diff --git a/3rdparty/SoundTouch/3dnow_win.cpp b/3rdparty/SoundTouch/3dnow_win.cpp index 2e369904ec..01e6dab8a7 100644 --- a/3rdparty/SoundTouch/3dnow_win.cpp +++ b/3rdparty/SoundTouch/3dnow_win.cpp @@ -1,350 +1,350 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Win32 version of the AMD 3DNow! optimized routines for AMD K6-2/Athlon -/// processors. All 3DNow! optimized functions have been gathered into this -/// single source code file, regardless to their class or original source code -/// file, in order to ease porting the library to other compiler and processor -/// platforms. -/// -/// By the way; the performance gain depends heavily on the CPU generation: On -/// K6-2 these routines provided speed-up of even 2.4 times, while on Athlon the -/// difference to the original routines stayed at unremarkable 8%! Such a small -/// improvement on Athlon is due to 3DNow can perform only two operations in -/// parallel, and obviously also the Athlon FPU is doing a very good job with -/// the standard C floating point routines! Here these routines are anyway, -/// although it might not be worth the effort to convert these to GCC platform, -/// for Athlon CPU at least. The situation is different regarding the SSE -/// optimizations though, thanks to the four parallel operations of SSE that -/// already make a difference. -/// -/// This file is to be compiled in Windows platform with Microsoft Visual C++ -/// Compiler. Please see '3dnow_gcc.cpp' for the gcc compiler version for all -/// GNU platforms (if file supplied). -/// -/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ -/// 6.0 processor pack" update to support 3DNow! instruction set. The update is -/// available for download at Microsoft Developers Network, see here: -/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx -/// -/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and -/// perform a search with keywords "processor pack". -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.10 $ -// -// $Id: 3dnow_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include "cpu_detect.h" -#include "STTypes.h" - -#ifndef _WIN32 -#error "wrong platform - this source code file is exclusively for Win32 platform" -#endif - -using namespace soundtouch; - -#ifdef ALLOW_3DNOW -// 3DNow! routines available only with float sample type - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of 3DNow! optimized functions of class 'TDStretch3DNow' -// -////////////////////////////////////////////////////////////////////////////// - -#include "TDStretch.h" -#include - -// these are declared in 'TDStretch.cpp' -extern int scanOffsets[4][24]; - - -// Calculates cross correlation of two buffers -double TDStretch3DNow::calcCrossCorrStereo(const float *pV1, const float *pV2) const -{ - uint overlapLengthLocal = overlapLength; - float corr; - - // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors - /* - c-pseudocode: - - corr = 0; - for (i = 0; i < overlapLength / 4; i ++) - { - corr += pV1[0] * pV2[0]; - pV1[1] * pV2[1]; - pV1[2] * pV2[2]; - pV1[3] * pV2[3]; - pV1[4] * pV2[4]; - pV1[5] * pV2[5]; - pV1[6] * pV2[6]; - pV1[7] * pV2[7]; - - pV1 += 8; - pV2 += 8; - } - */ - - _asm - { - // give prefetch hints to CPU of what data are to be needed soonish. - // give more aggressive hints on pV1 as that changes more between different calls - // while pV2 stays the same. - prefetch [pV1] - prefetch [pV2] - prefetch [pV1 + 32] - - mov eax, dword ptr pV2 - mov ebx, dword ptr pV1 - - pxor mm0, mm0 - - mov ecx, overlapLengthLocal - shr ecx, 2 // div by four - - loop1: - movq mm1, [eax] - prefetch [eax + 32] // give a prefetch hint to CPU what data are to be needed soonish - pfmul mm1, [ebx] - prefetch [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish - - movq mm2, [eax + 8] - pfadd mm0, mm1 - pfmul mm2, [ebx + 8] - - movq mm3, [eax + 16] - pfadd mm0, mm2 - pfmul mm3, [ebx + 16] - - movq mm4, [eax + 24] - pfadd mm0, mm3 - pfmul mm4, [ebx + 24] - - add eax, 32 - pfadd mm0, mm4 - add ebx, 32 - - dec ecx - jnz loop1 - - // add halfs of mm0 together and return the result. - // note: mm1 is used as a dummy parameter only, we actually don't care about it's value - pfacc mm0, mm1 - movd corr, mm0 - femms - } - - return corr; -} - - - - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of 3DNow! optimized functions of class 'FIRFilter' -// -////////////////////////////////////////////////////////////////////////////// - -#include "FIRFilter.h" - -FIRFilter3DNow::FIRFilter3DNow() : FIRFilter() -{ - filterCoeffsUnalign = NULL; -} - - -FIRFilter3DNow::~FIRFilter3DNow() -{ - delete[] filterCoeffsUnalign; -} - - -// (overloaded) Calculates filter coefficients for 3DNow! routine -void FIRFilter3DNow::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) -{ - uint i; - float fDivider; - - FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); - - // Scale the filter coefficients so that it won't be necessary to scale the filtering result - // also rearrange coefficients suitably for 3DNow! - // Ensure that filter coeffs array is aligned to 16-byte boundary - delete[] filterCoeffsUnalign; - filterCoeffsUnalign = new float[2 * newLength + 4]; - filterCoeffsAlign = (float *)(((uint)filterCoeffsUnalign + 15) & -16); - - fDivider = (float)resultDivider; - - // rearrange the filter coefficients for mmx routines - for (i = 0; i < newLength; i ++) - { - filterCoeffsAlign[2 * i + 0] = - filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; - } -} - - -// 3DNow!-optimized version of the filter routine for stereo sound -uint FIRFilter3DNow::evaluateFilterStereo(float *dest, const float *src, const uint numSamples) const -{ - float *filterCoeffsLocal = filterCoeffsAlign; - uint count = (numSamples - length) & -2; - uint lengthLocal = length / 4; - - assert(length != 0); - assert(count % 2 == 0); - - /* original code: - - double suml1, suml2; - double sumr1, sumr2; - uint i, j; - - for (j = 0; j < count; j += 2) - { - const float *ptr; - - suml1 = sumr1 = 0.0; - suml2 = sumr2 = 0.0; - ptr = src; - filterCoeffsLocal = filterCoeffs; - for (i = 0; i < lengthLocal; i ++) - { - // unroll loop for efficiency. - - suml1 += ptr[0] * filterCoeffsLocal[0] + - ptr[2] * filterCoeffsLocal[2] + - ptr[4] * filterCoeffsLocal[4] + - ptr[6] * filterCoeffsLocal[6]; - - sumr1 += ptr[1] * filterCoeffsLocal[1] + - ptr[3] * filterCoeffsLocal[3] + - ptr[5] * filterCoeffsLocal[5] + - ptr[7] * filterCoeffsLocal[7]; - - suml2 += ptr[8] * filterCoeffsLocal[0] + - ptr[10] * filterCoeffsLocal[2] + - ptr[12] * filterCoeffsLocal[4] + - ptr[14] * filterCoeffsLocal[6]; - - sumr2 += ptr[9] * filterCoeffsLocal[1] + - ptr[11] * filterCoeffsLocal[3] + - ptr[13] * filterCoeffsLocal[5] + - ptr[15] * filterCoeffsLocal[7]; - - ptr += 16; - filterCoeffsLocal += 8; - } - dest[0] = (float)suml1; - dest[1] = (float)sumr1; - dest[2] = (float)suml2; - dest[3] = (float)sumr2; - - src += 4; - dest += 4; - } - - */ - _asm - { - mov eax, dword ptr dest - mov ebx, dword ptr src - mov edx, count - shr edx, 1 - - loop1: - // "outer loop" : during each round 2*2 output samples are calculated - prefetch [ebx] // give a prefetch hint to CPU what data are to be needed soonish - prefetch [filterCoeffsLocal] // give a prefetch hint to CPU what data are to be needed soonish - - mov esi, ebx - mov edi, filterCoeffsLocal - pxor mm0, mm0 - pxor mm1, mm1 - mov ecx, lengthLocal - - loop2: - // "inner loop" : during each round four FIR filter taps are evaluated for 2*2 output samples - movq mm2, [edi] - movq mm3, mm2 - prefetch [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish - pfmul mm2, [esi] - prefetch [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish - pfmul mm3, [esi + 8] - - movq mm4, [edi + 8] - movq mm5, mm4 - pfadd mm0, mm2 - pfmul mm4, [esi + 8] - pfadd mm1, mm3 - pfmul mm5, [esi + 16] - - movq mm2, [edi + 16] - movq mm6, mm2 - pfadd mm0, mm4 - pfmul mm2, [esi + 16] - pfadd mm1, mm5 - pfmul mm6, [esi + 24] - - movq mm3, [edi + 24] - movq mm7, mm3 - pfadd mm0, mm2 - pfmul mm3, [esi + 24] - pfadd mm1, mm6 - pfmul mm7, [esi + 32] - add esi, 32 - pfadd mm0, mm3 - add edi, 32 - pfadd mm1, mm7 - - dec ecx - jnz loop2 - - movq [eax], mm0 - add ebx, 16 - movq [eax + 8], mm1 - add eax, 16 - - dec edx - jnz loop1 - - femms - } - - return count; -} - - -#endif // ALLOW_3DNOW +//////////////////////////////////////////////////////////////////////////////// +/// +/// Win32 version of the AMD 3DNow! optimized routines for AMD K6-2/Athlon +/// processors. All 3DNow! optimized functions have been gathered into this +/// single source code file, regardless to their class or original source code +/// file, in order to ease porting the library to other compiler and processor +/// platforms. +/// +/// By the way; the performance gain depends heavily on the CPU generation: On +/// K6-2 these routines provided speed-up of even 2.4 times, while on Athlon the +/// difference to the original routines stayed at unremarkable 8%! Such a small +/// improvement on Athlon is due to 3DNow can perform only two operations in +/// parallel, and obviously also the Athlon FPU is doing a very good job with +/// the standard C floating point routines! Here these routines are anyway, +/// although it might not be worth the effort to convert these to GCC platform, +/// for Athlon CPU at least. The situation is different regarding the SSE +/// optimizations though, thanks to the four parallel operations of SSE that +/// already make a difference. +/// +/// This file is to be compiled in Windows platform with Microsoft Visual C++ +/// Compiler. Please see '3dnow_gcc.cpp' for the gcc compiler version for all +/// GNU platforms (if file supplied). +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support 3DNow! instruction set. The update is +/// available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx +/// +/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and +/// perform a search with keywords "processor pack". +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: 3dnow_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" +#include "STTypes.h" + +#ifndef _WIN32 +#error "wrong platform - this source code file is exclusively for Win32 platform" +#endif + +using namespace soundtouch; + +#ifdef ALLOW_3DNOW +// 3DNow! routines available only with float sample type + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of 3DNow! optimized functions of class 'TDStretch3DNow' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include + +// these are declared in 'TDStretch.cpp' +extern int scanOffsets[4][24]; + + +// Calculates cross correlation of two buffers +double TDStretch3DNow::calcCrossCorrStereo(const float *pV1, const float *pV2) const +{ + uint overlapLengthLocal = overlapLength; + float corr; + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + /* + c-pseudocode: + + corr = 0; + for (i = 0; i < overlapLength / 4; i ++) + { + corr += pV1[0] * pV2[0]; + pV1[1] * pV2[1]; + pV1[2] * pV2[2]; + pV1[3] * pV2[3]; + pV1[4] * pV2[4]; + pV1[5] * pV2[5]; + pV1[6] * pV2[6]; + pV1[7] * pV2[7]; + + pV1 += 8; + pV2 += 8; + } + */ + + _asm + { + // give prefetch hints to CPU of what data are to be needed soonish. + // give more aggressive hints on pV1 as that changes more between different calls + // while pV2 stays the same. + prefetch [pV1] + prefetch [pV2] + prefetch [pV1 + 32] + + mov eax, dword ptr pV2 + mov ebx, dword ptr pV1 + + pxor mm0, mm0 + + mov ecx, overlapLengthLocal + shr ecx, 2 // div by four + + loop1: + movq mm1, [eax] + prefetch [eax + 32] // give a prefetch hint to CPU what data are to be needed soonish + pfmul mm1, [ebx] + prefetch [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish + + movq mm2, [eax + 8] + pfadd mm0, mm1 + pfmul mm2, [ebx + 8] + + movq mm3, [eax + 16] + pfadd mm0, mm2 + pfmul mm3, [ebx + 16] + + movq mm4, [eax + 24] + pfadd mm0, mm3 + pfmul mm4, [ebx + 24] + + add eax, 32 + pfadd mm0, mm4 + add ebx, 32 + + dec ecx + jnz loop1 + + // add halfs of mm0 together and return the result. + // note: mm1 is used as a dummy parameter only, we actually don't care about it's value + pfacc mm0, mm1 + movd corr, mm0 + femms + } + + return corr; +} + + + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of 3DNow! optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + +FIRFilter3DNow::FIRFilter3DNow() : FIRFilter() +{ + filterCoeffsUnalign = NULL; +} + + +FIRFilter3DNow::~FIRFilter3DNow() +{ + delete[] filterCoeffsUnalign; +} + + +// (overloaded) Calculates filter coefficients for 3DNow! routine +void FIRFilter3DNow::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + float fDivider; + + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Scale the filter coefficients so that it won't be necessary to scale the filtering result + // also rearrange coefficients suitably for 3DNow! + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new float[2 * newLength + 4]; + filterCoeffsAlign = (float *)(((uint)filterCoeffsUnalign + 15) & -16); + + fDivider = (float)resultDivider; + + // rearrange the filter coefficients for mmx routines + for (i = 0; i < newLength; i ++) + { + filterCoeffsAlign[2 * i + 0] = + filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; + } +} + + +// 3DNow!-optimized version of the filter routine for stereo sound +uint FIRFilter3DNow::evaluateFilterStereo(float *dest, const float *src, const uint numSamples) const +{ + float *filterCoeffsLocal = filterCoeffsAlign; + uint count = (numSamples - length) & -2; + uint lengthLocal = length / 4; + + assert(length != 0); + assert(count % 2 == 0); + + /* original code: + + double suml1, suml2; + double sumr1, sumr2; + uint i, j; + + for (j = 0; j < count; j += 2) + { + const float *ptr; + + suml1 = sumr1 = 0.0; + suml2 = sumr2 = 0.0; + ptr = src; + filterCoeffsLocal = filterCoeffs; + for (i = 0; i < lengthLocal; i ++) + { + // unroll loop for efficiency. + + suml1 += ptr[0] * filterCoeffsLocal[0] + + ptr[2] * filterCoeffsLocal[2] + + ptr[4] * filterCoeffsLocal[4] + + ptr[6] * filterCoeffsLocal[6]; + + sumr1 += ptr[1] * filterCoeffsLocal[1] + + ptr[3] * filterCoeffsLocal[3] + + ptr[5] * filterCoeffsLocal[5] + + ptr[7] * filterCoeffsLocal[7]; + + suml2 += ptr[8] * filterCoeffsLocal[0] + + ptr[10] * filterCoeffsLocal[2] + + ptr[12] * filterCoeffsLocal[4] + + ptr[14] * filterCoeffsLocal[6]; + + sumr2 += ptr[9] * filterCoeffsLocal[1] + + ptr[11] * filterCoeffsLocal[3] + + ptr[13] * filterCoeffsLocal[5] + + ptr[15] * filterCoeffsLocal[7]; + + ptr += 16; + filterCoeffsLocal += 8; + } + dest[0] = (float)suml1; + dest[1] = (float)sumr1; + dest[2] = (float)suml2; + dest[3] = (float)sumr2; + + src += 4; + dest += 4; + } + + */ + _asm + { + mov eax, dword ptr dest + mov ebx, dword ptr src + mov edx, count + shr edx, 1 + + loop1: + // "outer loop" : during each round 2*2 output samples are calculated + prefetch [ebx] // give a prefetch hint to CPU what data are to be needed soonish + prefetch [filterCoeffsLocal] // give a prefetch hint to CPU what data are to be needed soonish + + mov esi, ebx + mov edi, filterCoeffsLocal + pxor mm0, mm0 + pxor mm1, mm1 + mov ecx, lengthLocal + + loop2: + // "inner loop" : during each round four FIR filter taps are evaluated for 2*2 output samples + movq mm2, [edi] + movq mm3, mm2 + prefetch [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish + pfmul mm2, [esi] + prefetch [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish + pfmul mm3, [esi + 8] + + movq mm4, [edi + 8] + movq mm5, mm4 + pfadd mm0, mm2 + pfmul mm4, [esi + 8] + pfadd mm1, mm3 + pfmul mm5, [esi + 16] + + movq mm2, [edi + 16] + movq mm6, mm2 + pfadd mm0, mm4 + pfmul mm2, [esi + 16] + pfadd mm1, mm5 + pfmul mm6, [esi + 24] + + movq mm3, [edi + 24] + movq mm7, mm3 + pfadd mm0, mm2 + pfmul mm3, [esi + 24] + pfadd mm1, mm6 + pfmul mm7, [esi + 32] + add esi, 32 + pfadd mm0, mm3 + add edi, 32 + pfadd mm1, mm7 + + dec ecx + jnz loop2 + + movq [eax], mm0 + add ebx, 16 + movq [eax + 8], mm1 + add eax, 16 + + dec edx + jnz loop1 + + femms + } + + return count; +} + + +#endif // ALLOW_3DNOW diff --git a/3rdparty/SoundTouch/AAFilter.cpp b/3rdparty/SoundTouch/AAFilter.cpp index 9a5cf539c0..6bf529ccec 100644 --- a/3rdparty/SoundTouch/AAFilter.cpp +++ b/3rdparty/SoundTouch/AAFilter.cpp @@ -1,184 +1,184 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// FIR low-pass (anti-alias) filter with filter coefficient design routine and -/// MMX optimization. -/// -/// Anti-alias filter is used to prevent folding of high frequencies when -/// transposing the sample rate with interpolation. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.9 $ -// -// $Id: AAFilter.cpp,v 1.9 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include "AAFilter.h" -#include "FIRFilter.h" - -using namespace soundtouch; - -#define PI 3.141592655357989 -#define TWOPI (2 * PI) - -/***************************************************************************** - * - * Implementation of the class 'AAFilter' - * - *****************************************************************************/ - -AAFilter::AAFilter(const uint length) -{ - pFIR = FIRFilter::newInstance(); - cutoffFreq = 0.5; - setLength(length); -} - - - -AAFilter::~AAFilter() -{ - delete pFIR; -} - - - -// Sets new anti-alias filter cut-off edge frequency, scaled to -// sampling frequency (nyquist frequency = 0.5). -// The filter will cut frequencies higher than the given frequency. -void AAFilter::setCutoffFreq(const double newCutoffFreq) -{ - cutoffFreq = newCutoffFreq; - calculateCoeffs(); -} - - - -// Sets number of FIR filter taps -void AAFilter::setLength(const uint newLength) -{ - length = newLength; - calculateCoeffs(); -} - - - -// Calculates coefficients for a low-pass FIR filter using Hamming window -void AAFilter::calculateCoeffs() -{ - uint i; - double cntTemp, temp, tempCoeff,h, w; - double fc2, wc; - double scaleCoeff, sum; - double *work; - SAMPLETYPE *coeffs; - - assert(length > 0); - assert(length % 4 == 0); - assert(cutoffFreq >= 0); - assert(cutoffFreq <= 0.5); - - work = new double[length]; - coeffs = new SAMPLETYPE[length]; - - fc2 = 2.0 * cutoffFreq; - wc = PI * fc2; - tempCoeff = TWOPI / (double)length; - - sum = 0; - for (i = 0; i < length; i ++) - { - cntTemp = (double)i - (double)(length / 2); - - temp = cntTemp * wc; - if (temp != 0) - { - h = fc2 * sin(temp) / temp; // sinc function - } - else - { - h = 1.0; - } - w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window - - temp = w * h; - work[i] = temp; - - // calc net sum of coefficients - sum += temp; - } - - // ensure the sum of coefficients is larger than zero - assert(sum > 0); - - // ensure we've really designed a lowpass filter... - assert(work[length/2] > 0); - assert(work[length/2 + 1] > -1e-6); - assert(work[length/2 - 1] > -1e-6); - - // Calculate a scaling coefficient in such a way that the result can be - // divided by 16384 - scaleCoeff = 16384.0f / sum; - - for (i = 0; i < length; i ++) - { - // scale & round to nearest integer - temp = work[i] * scaleCoeff; - temp += (temp >= 0) ? 0.5 : -0.5; - // ensure no overfloods - assert(temp >= -32768 && temp <= 32767); - coeffs[i] = (SAMPLETYPE)temp; - } - - // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384 - pFIR->setCoefficients(coeffs, length, 14); - - delete[] work; - delete[] coeffs; -} - - -// Applies the filter to the given sequence of samples. -// Note : The amount of outputted samples is by value of 'filter length' -// smaller than the amount of input samples. -uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const -{ - return pFIR->evaluate(dest, src, numSamples, numChannels); -} - - -uint AAFilter::getLength() const -{ - return pFIR->getLength(); -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// FIR low-pass (anti-alias) filter with filter coefficient design routine and +/// MMX optimization. +/// +/// Anti-alias filter is used to prevent folding of high frequencies when +/// transposing the sample rate with interpolation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.9 $ +// +// $Id: AAFilter.cpp,v 1.9 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include "AAFilter.h" +#include "FIRFilter.h" + +using namespace soundtouch; + +#define PI 3.141592655357989 +#define TWOPI (2 * PI) + +/***************************************************************************** + * + * Implementation of the class 'AAFilter' + * + *****************************************************************************/ + +AAFilter::AAFilter(const uint length) +{ + pFIR = FIRFilter::newInstance(); + cutoffFreq = 0.5; + setLength(length); +} + + + +AAFilter::~AAFilter() +{ + delete pFIR; +} + + + +// Sets new anti-alias filter cut-off edge frequency, scaled to +// sampling frequency (nyquist frequency = 0.5). +// The filter will cut frequencies higher than the given frequency. +void AAFilter::setCutoffFreq(const double newCutoffFreq) +{ + cutoffFreq = newCutoffFreq; + calculateCoeffs(); +} + + + +// Sets number of FIR filter taps +void AAFilter::setLength(const uint newLength) +{ + length = newLength; + calculateCoeffs(); +} + + + +// Calculates coefficients for a low-pass FIR filter using Hamming window +void AAFilter::calculateCoeffs() +{ + uint i; + double cntTemp, temp, tempCoeff,h, w; + double fc2, wc; + double scaleCoeff, sum; + double *work; + SAMPLETYPE *coeffs; + + assert(length > 0); + assert(length % 4 == 0); + assert(cutoffFreq >= 0); + assert(cutoffFreq <= 0.5); + + work = new double[length]; + coeffs = new SAMPLETYPE[length]; + + fc2 = 2.0 * cutoffFreq; + wc = PI * fc2; + tempCoeff = TWOPI / (double)length; + + sum = 0; + for (i = 0; i < length; i ++) + { + cntTemp = (double)i - (double)(length / 2); + + temp = cntTemp * wc; + if (temp != 0) + { + h = fc2 * sin(temp) / temp; // sinc function + } + else + { + h = 1.0; + } + w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window + + temp = w * h; + work[i] = temp; + + // calc net sum of coefficients + sum += temp; + } + + // ensure the sum of coefficients is larger than zero + assert(sum > 0); + + // ensure we've really designed a lowpass filter... + assert(work[length/2] > 0); + assert(work[length/2 + 1] > -1e-6); + assert(work[length/2 - 1] > -1e-6); + + // Calculate a scaling coefficient in such a way that the result can be + // divided by 16384 + scaleCoeff = 16384.0f / sum; + + for (i = 0; i < length; i ++) + { + // scale & round to nearest integer + temp = work[i] * scaleCoeff; + temp += (temp >= 0) ? 0.5 : -0.5; + // ensure no overfloods + assert(temp >= -32768 && temp <= 32767); + coeffs[i] = (SAMPLETYPE)temp; + } + + // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384 + pFIR->setCoefficients(coeffs, length, 14); + + delete[] work; + delete[] coeffs; +} + + +// Applies the filter to the given sequence of samples. +// Note : The amount of outputted samples is by value of 'filter length' +// smaller than the amount of input samples. +uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const +{ + return pFIR->evaluate(dest, src, numSamples, numChannels); +} + + +uint AAFilter::getLength() const +{ + return pFIR->getLength(); +} diff --git a/3rdparty/SoundTouch/AAFilter.h b/3rdparty/SoundTouch/AAFilter.h index 4c85dcdbe7..68eb50d27f 100644 --- a/3rdparty/SoundTouch/AAFilter.h +++ b/3rdparty/SoundTouch/AAFilter.h @@ -1,91 +1,91 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo -/// while maintaining the original pitch by using a time domain WSOLA-like method -/// with several performance-increasing tweaks. -/// -/// Anti-alias filter is used to prevent folding of high frequencies when -/// transposing the sample rate with interpolation. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.10 $ -// -// $Id: AAFilter.h,v 1.10 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef AAFilter_H -#define AAFilter_H - -#include "STTypes.h" - -namespace soundtouch -{ - -class AAFilter -{ -protected: - class FIRFilter *pFIR; - - /// Low-pass filter cut-off frequency, negative = invalid - double cutoffFreq; - - /// num of filter taps - uint length; - - /// Calculate the FIR coefficients realizing the given cutoff-frequency - void calculateCoeffs(); -public: - AAFilter(uint length); - - ~AAFilter(); - - /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling - /// frequency (nyquist frequency = 0.5). The filter will cut off the - /// frequencies than that. - void setCutoffFreq(double newCutoffFreq); - - /// Sets number of FIR filter taps, i.e. ~filter complexity - void setLength(uint newLength); - - uint getLength() const; - - /// Applies the filter to the given sequence of samples. - /// Note : The amount of outputted samples is by value of 'filter length' - /// smaller than the amount of input samples. - uint evaluate(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples, - uint numChannels) const; -}; - -} - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like method +/// with several performance-increasing tweaks. +/// +/// Anti-alias filter is used to prevent folding of high frequencies when +/// transposing the sample rate with interpolation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: AAFilter.h,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef AAFilter_H +#define AAFilter_H + +#include "STTypes.h" + +namespace soundtouch +{ + +class AAFilter +{ +protected: + class FIRFilter *pFIR; + + /// Low-pass filter cut-off frequency, negative = invalid + double cutoffFreq; + + /// num of filter taps + uint length; + + /// Calculate the FIR coefficients realizing the given cutoff-frequency + void calculateCoeffs(); +public: + AAFilter(uint length); + + ~AAFilter(); + + /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling + /// frequency (nyquist frequency = 0.5). The filter will cut off the + /// frequencies than that. + void setCutoffFreq(double newCutoffFreq); + + /// Sets number of FIR filter taps, i.e. ~filter complexity + void setLength(uint newLength); + + uint getLength() const; + + /// Applies the filter to the given sequence of samples. + /// Note : The amount of outputted samples is by value of 'filter length' + /// smaller than the amount of input samples. + uint evaluate(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples, + uint numChannels) const; +}; + +} + +#endif diff --git a/3rdparty/SoundTouch/BPMDetect.h b/3rdparty/SoundTouch/BPMDetect.h index ac616e7e2b..b5e393979d 100644 --- a/3rdparty/SoundTouch/BPMDetect.h +++ b/3rdparty/SoundTouch/BPMDetect.h @@ -1,159 +1,159 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Beats-per-minute (BPM) detection routine. -/// -/// The beat detection algorithm works as follows: -/// - Use function 'inputSamples' to input a chunks of samples to the class for -/// analysis. It's a good idea to enter a large sound file or stream in smallish -/// chunks of around few kilosamples in order not to extinguish too much RAM memory. -/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden, -/// which is basically ok as low (bass) frequencies mostly determine the beat rate. -/// Simple averaging is used for anti-alias filtering because the resulting signal -/// quality isn't of that high importance. -/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by -/// taking absolute value that's smoothed by sliding average. Signal levels that -/// are below a couple of times the general RMS amplitude level are cut away to -/// leave only notable peaks there. -/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term -/// autocorrelation function of the enveloped signal. -/// - After whole sound data file has been analyzed as above, the bpm level is -/// detected by function 'getBpm' that finds the highest peak of the autocorrelation -/// function, calculates it's precise location and converts this reading to bpm's. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.5 $ -// -// $Id: BPMDetect.h,v 1.5 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef _BPMDetect_H_ -#define _BPMDetect_H_ - -#include "STTypes.h" -#include "FIFOSampleBuffer.h" - -/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit. -#define MIN_BPM 45 - -/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit. -#define MAX_BPM 230 - - -/// Class for calculating BPM rate for audio data. -class BPMDetect -{ -protected: - /// Auto-correlation accumulator bins. - float *xcorr; - - /// Amplitude envelope sliding average approximation level accumulator - float envelopeAccu; - - /// RMS volume sliding average approximation level accumulator - float RMSVolumeAccu; - - /// Sample average counter. - int decimateCount; - - /// Sample average accumulator for FIFO-like decimation. - soundtouch::LONG_SAMPLETYPE decimateSum; - - /// Decimate sound by this coefficient to reach approx. 500 Hz. - int decimateBy; - - /// Auto-correlation window length - int windowLen; - - /// Number of channels (1 = mono, 2 = stereo) - int channels; - - /// sample rate - int sampleRate; - - /// Beginning of auto-correlation window: Autocorrelation isn't being updated for - /// the first these many correlation bins. - int windowStart; - - /// FIFO-buffer for decimated processing samples. - soundtouch::FIFOSampleBuffer *buffer; - - /// Initialize the class for processing. - void init(int numChannels, int sampleRate); - - /// Updates auto-correlation function for given number of decimated samples that - /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe - /// though). - void updateXCorr(int process_samples /// How many samples are processed. - ); - - /// Decimates samples to approx. 500 Hz. - /// - /// \return Number of output samples. - int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer - const soundtouch::SAMPLETYPE *src, ///< Source sample buffer - int numsamples ///< Number of source samples. - ); - - /// Calculates amplitude envelope for the buffer of samples. - /// Result is output to 'samples'. - void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer - int numsamples ///< Number of samples in buffer - ); - -public: - /// Constructor. - BPMDetect(int numChannels, ///< Number of channels in sample data. - int sampleRate ///< Sample rate in Hz. - ); - - /// Destructor. - virtual ~BPMDetect(); - - /// Inputs a block of samples for analyzing: Envelopes the samples and then - /// updates the autocorrelation estimation. When whole song data has been input - /// in smaller blocks using this function, read the resulting bpm with 'getBpm' - /// function. - /// - /// Notice that data in 'samples' array can be disrupted in processing. - void inputSamples(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer - int numSamples ///< Number of samples in buffer - ); - - - /// Analyzes the results and returns the BPM rate. Use this function to read result - /// after whole song data has been input to the class by consecutive calls of - /// 'inputSamples' function. - /// - /// \return Beats-per-minute rate, or zero if detection failed. - float getBpm(); -}; - -#endif // _BPMDetect_H_ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Beats-per-minute (BPM) detection routine. +/// +/// The beat detection algorithm works as follows: +/// - Use function 'inputSamples' to input a chunks of samples to the class for +/// analysis. It's a good idea to enter a large sound file or stream in smallish +/// chunks of around few kilosamples in order not to extinguish too much RAM memory. +/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden, +/// which is basically ok as low (bass) frequencies mostly determine the beat rate. +/// Simple averaging is used for anti-alias filtering because the resulting signal +/// quality isn't of that high importance. +/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by +/// taking absolute value that's smoothed by sliding average. Signal levels that +/// are below a couple of times the general RMS amplitude level are cut away to +/// leave only notable peaks there. +/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term +/// autocorrelation function of the enveloped signal. +/// - After whole sound data file has been analyzed as above, the bpm level is +/// detected by function 'getBpm' that finds the highest peak of the autocorrelation +/// function, calculates it's precise location and converts this reading to bpm's. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.5 $ +// +// $Id: BPMDetect.h,v 1.5 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _BPMDetect_H_ +#define _BPMDetect_H_ + +#include "STTypes.h" +#include "FIFOSampleBuffer.h" + +/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit. +#define MIN_BPM 45 + +/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit. +#define MAX_BPM 230 + + +/// Class for calculating BPM rate for audio data. +class BPMDetect +{ +protected: + /// Auto-correlation accumulator bins. + float *xcorr; + + /// Amplitude envelope sliding average approximation level accumulator + float envelopeAccu; + + /// RMS volume sliding average approximation level accumulator + float RMSVolumeAccu; + + /// Sample average counter. + int decimateCount; + + /// Sample average accumulator for FIFO-like decimation. + soundtouch::LONG_SAMPLETYPE decimateSum; + + /// Decimate sound by this coefficient to reach approx. 500 Hz. + int decimateBy; + + /// Auto-correlation window length + int windowLen; + + /// Number of channels (1 = mono, 2 = stereo) + int channels; + + /// sample rate + int sampleRate; + + /// Beginning of auto-correlation window: Autocorrelation isn't being updated for + /// the first these many correlation bins. + int windowStart; + + /// FIFO-buffer for decimated processing samples. + soundtouch::FIFOSampleBuffer *buffer; + + /// Initialize the class for processing. + void init(int numChannels, int sampleRate); + + /// Updates auto-correlation function for given number of decimated samples that + /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe + /// though). + void updateXCorr(int process_samples /// How many samples are processed. + ); + + /// Decimates samples to approx. 500 Hz. + /// + /// \return Number of output samples. + int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer + const soundtouch::SAMPLETYPE *src, ///< Source sample buffer + int numsamples ///< Number of source samples. + ); + + /// Calculates amplitude envelope for the buffer of samples. + /// Result is output to 'samples'. + void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer + int numsamples ///< Number of samples in buffer + ); + +public: + /// Constructor. + BPMDetect(int numChannels, ///< Number of channels in sample data. + int sampleRate ///< Sample rate in Hz. + ); + + /// Destructor. + virtual ~BPMDetect(); + + /// Inputs a block of samples for analyzing: Envelopes the samples and then + /// updates the autocorrelation estimation. When whole song data has been input + /// in smaller blocks using this function, read the resulting bpm with 'getBpm' + /// function. + /// + /// Notice that data in 'samples' array can be disrupted in processing. + void inputSamples(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer + int numSamples ///< Number of samples in buffer + ); + + + /// Analyzes the results and returns the BPM rate. Use this function to read result + /// after whole song data has been input to the class by consecutive calls of + /// 'inputSamples' function. + /// + /// \return Beats-per-minute rate, or zero if detection failed. + float getBpm(); +}; + +#endif // _BPMDetect_H_ diff --git a/3rdparty/SoundTouch/FIFOSampleBuffer.cpp b/3rdparty/SoundTouch/FIFOSampleBuffer.cpp index 2bf965b763..a8918a8133 100644 --- a/3rdparty/SoundTouch/FIFOSampleBuffer.cpp +++ b/3rdparty/SoundTouch/FIFOSampleBuffer.cpp @@ -1,252 +1,252 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// A buffer class for temporarily storaging sound samples, operates as a -/// first-in-first-out pipe. -/// -/// Samples are added to the end of the sample buffer with the 'putSamples' -/// function, and are received from the beginning of the buffer by calling -/// the 'receiveSamples' function. The class automatically removes the -/// outputted samples from the buffer, as well as grows the buffer size -/// whenever necessary. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.11 $ -// -// $Id: FIFOSampleBuffer.cpp,v 1.11 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include - -#include "FIFOSampleBuffer.h" - -using namespace soundtouch; - -// Constructor -FIFOSampleBuffer::FIFOSampleBuffer(uint numChannels) -{ - sizeInBytes = 0; // reasonable initial value - buffer = NULL; //new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE)]; - bufferUnaligned = NULL; - samplesInBuffer = 0; - bufferPos = 0; - channels = numChannels; -} - - -// destructor -FIFOSampleBuffer::~FIFOSampleBuffer() -{ - delete[] bufferUnaligned; -} - - -// Sets number of channels, 1 = mono, 2 = stereo -void FIFOSampleBuffer::setChannels(const uint numChannels) -{ - uint usedBytes; - - usedBytes = channels * samplesInBuffer; - channels = numChannels; - samplesInBuffer = usedBytes / channels; -} - - -// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and -// zeroes this pointer by copying samples from the 'bufferPos' pointer -// location on to the beginning of the buffer. -void FIFOSampleBuffer::rewind() -{ - if (bufferPos) - { - memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer); - bufferPos = 0; - } -} - - -// Adds 'numSamples' pcs of samples from the 'samples' memory position to -// the sample buffer. -void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint numSamples) -{ - memcpy(ptrEnd(numSamples), samples, sizeof(SAMPLETYPE) * numSamples * channels); - samplesInBuffer += numSamples; -} - - -// Increases the number of samples in the buffer without copying any actual -// samples. -// -// This function is used to update the number of samples in the sample buffer -// when accessing the buffer directly with 'ptrEnd' function. Please be -// careful though! -void FIFOSampleBuffer::putSamples(uint numSamples) -{ - uint req; - - req = samplesInBuffer + numSamples; - ensureCapacity(req); - samplesInBuffer += numSamples; -} - - -// Returns a pointer to the end of the used part of the sample buffer (i.e. -// where the new samples are to be inserted). This function may be used for -// inserting new samples into the sample buffer directly. Please be careful! -// -// Parameter 'slackCapacity' tells the function how much free capacity (in -// terms of samples) there _at least_ should be, in order to the caller to -// succesfully insert all the required samples to the buffer. When necessary, -// the function grows the buffer size to comply with this requirement. -// -// When using this function as means for inserting new samples, also remember -// to increase the sample count afterwards, by calling the -// 'putSamples(numSamples)' function. -SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity) -{ - ensureCapacity(samplesInBuffer + slackCapacity); - return buffer + samplesInBuffer * channels; -} - - -// Returns a pointer to the beginning of the currently non-outputted samples. -// This function is provided for accessing the output samples directly. -// Please be careful! -// -// When using this function to output samples, also remember to 'remove' the -// outputted samples from the buffer by calling the -// 'receiveSamples(numSamples)' function -SAMPLETYPE *FIFOSampleBuffer::ptrBegin() const -{ - return buffer + bufferPos * channels; -} - - -// Ensures that the buffer has enought capacity, i.e. space for _at least_ -// 'capacityRequirement' number of samples. The buffer is grown in steps of -// 4 kilobytes to eliminate the need for frequently growing up the buffer, -// as well as to round the buffer size up to the virtual memory page size. -void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement) -{ - SAMPLETYPE *tempUnaligned, *temp; - - if (capacityRequirement > getCapacity()) - { - // enlarge the buffer in 4kbyte steps (round up to next 4k boundary) - sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & -4096; - assert(sizeInBytes % 2 == 0); - tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; - if (tempUnaligned == NULL) - { - throw std::runtime_error("Couldn't allocate memory!\n"); - } - temp = (SAMPLETYPE *)(((ulongptr)tempUnaligned + 15) & -16); - memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE)); - delete[] bufferUnaligned; - buffer = temp; - bufferUnaligned = tempUnaligned; - bufferPos = 0; - } - else - { - // simply rewind the buffer (if necessary) - rewind(); - } -} - - -// Returns the current buffer capacity in terms of samples -uint FIFOSampleBuffer::getCapacity() const -{ - return sizeInBytes / (channels * sizeof(SAMPLETYPE)); -} - - -// Returns the number of samples currently in the buffer -uint FIFOSampleBuffer::numSamples() const -{ - return samplesInBuffer; -} - - -// Output samples from beginning of the sample buffer. Copies demanded number -// of samples to output and removes them from the sample buffer. If there -// are less than 'numsample' samples in the buffer, returns all available. -// -// Returns number of samples copied. -uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples) -{ - uint num; - - num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples; - - memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num); - return receiveSamples(num); -} - - -// Removes samples from the beginning of the sample buffer without copying them -// anywhere. Used to reduce the number of samples in the buffer, when accessing -// the sample buffer with the 'ptrBegin' function. -uint FIFOSampleBuffer::receiveSamples(uint maxSamples) -{ - if (maxSamples >= samplesInBuffer) - { - uint temp; - - temp = samplesInBuffer; - samplesInBuffer = 0; - return temp; - } - - samplesInBuffer -= maxSamples; - bufferPos += maxSamples; - - return maxSamples; -} - - -// Returns nonzero if the sample buffer is empty -int FIFOSampleBuffer::isEmpty() const -{ - return (samplesInBuffer == 0) ? 1 : 0; -} - - -// Clears the sample buffer -void FIFOSampleBuffer::clear() -{ - samplesInBuffer = 0; - bufferPos = 0; -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// A buffer class for temporarily storaging sound samples, operates as a +/// first-in-first-out pipe. +/// +/// Samples are added to the end of the sample buffer with the 'putSamples' +/// function, and are received from the beginning of the buffer by calling +/// the 'receiveSamples' function. The class automatically removes the +/// outputted samples from the buffer, as well as grows the buffer size +/// whenever necessary. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.11 $ +// +// $Id: FIFOSampleBuffer.cpp,v 1.11 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include "FIFOSampleBuffer.h" + +using namespace soundtouch; + +// Constructor +FIFOSampleBuffer::FIFOSampleBuffer(uint numChannels) +{ + sizeInBytes = 0; // reasonable initial value + buffer = NULL; //new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE)]; + bufferUnaligned = NULL; + samplesInBuffer = 0; + bufferPos = 0; + channels = numChannels; +} + + +// destructor +FIFOSampleBuffer::~FIFOSampleBuffer() +{ + delete[] bufferUnaligned; +} + + +// Sets number of channels, 1 = mono, 2 = stereo +void FIFOSampleBuffer::setChannels(const uint numChannels) +{ + uint usedBytes; + + usedBytes = channels * samplesInBuffer; + channels = numChannels; + samplesInBuffer = usedBytes / channels; +} + + +// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and +// zeroes this pointer by copying samples from the 'bufferPos' pointer +// location on to the beginning of the buffer. +void FIFOSampleBuffer::rewind() +{ + if (bufferPos) + { + memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer); + bufferPos = 0; + } +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position to +// the sample buffer. +void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + memcpy(ptrEnd(numSamples), samples, sizeof(SAMPLETYPE) * numSamples * channels); + samplesInBuffer += numSamples; +} + + +// Increases the number of samples in the buffer without copying any actual +// samples. +// +// This function is used to update the number of samples in the sample buffer +// when accessing the buffer directly with 'ptrEnd' function. Please be +// careful though! +void FIFOSampleBuffer::putSamples(uint numSamples) +{ + uint req; + + req = samplesInBuffer + numSamples; + ensureCapacity(req); + samplesInBuffer += numSamples; +} + + +// Returns a pointer to the end of the used part of the sample buffer (i.e. +// where the new samples are to be inserted). This function may be used for +// inserting new samples into the sample buffer directly. Please be careful! +// +// Parameter 'slackCapacity' tells the function how much free capacity (in +// terms of samples) there _at least_ should be, in order to the caller to +// succesfully insert all the required samples to the buffer. When necessary, +// the function grows the buffer size to comply with this requirement. +// +// When using this function as means for inserting new samples, also remember +// to increase the sample count afterwards, by calling the +// 'putSamples(numSamples)' function. +SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity) +{ + ensureCapacity(samplesInBuffer + slackCapacity); + return buffer + samplesInBuffer * channels; +} + + +// Returns a pointer to the beginning of the currently non-outputted samples. +// This function is provided for accessing the output samples directly. +// Please be careful! +// +// When using this function to output samples, also remember to 'remove' the +// outputted samples from the buffer by calling the +// 'receiveSamples(numSamples)' function +SAMPLETYPE *FIFOSampleBuffer::ptrBegin() const +{ + return buffer + bufferPos * channels; +} + + +// Ensures that the buffer has enought capacity, i.e. space for _at least_ +// 'capacityRequirement' number of samples. The buffer is grown in steps of +// 4 kilobytes to eliminate the need for frequently growing up the buffer, +// as well as to round the buffer size up to the virtual memory page size. +void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement) +{ + SAMPLETYPE *tempUnaligned, *temp; + + if (capacityRequirement > getCapacity()) + { + // enlarge the buffer in 4kbyte steps (round up to next 4k boundary) + sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & -4096; + assert(sizeInBytes % 2 == 0); + tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; + if (tempUnaligned == NULL) + { + throw std::runtime_error("Couldn't allocate memory!\n"); + } + temp = (SAMPLETYPE *)(((ulongptr)tempUnaligned + 15) & -16); + memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE)); + delete[] bufferUnaligned; + buffer = temp; + bufferUnaligned = tempUnaligned; + bufferPos = 0; + } + else + { + // simply rewind the buffer (if necessary) + rewind(); + } +} + + +// Returns the current buffer capacity in terms of samples +uint FIFOSampleBuffer::getCapacity() const +{ + return sizeInBytes / (channels * sizeof(SAMPLETYPE)); +} + + +// Returns the number of samples currently in the buffer +uint FIFOSampleBuffer::numSamples() const +{ + return samplesInBuffer; +} + + +// Output samples from beginning of the sample buffer. Copies demanded number +// of samples to output and removes them from the sample buffer. If there +// are less than 'numsample' samples in the buffer, returns all available. +// +// Returns number of samples copied. +uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples) +{ + uint num; + + num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples; + + memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num); + return receiveSamples(num); +} + + +// Removes samples from the beginning of the sample buffer without copying them +// anywhere. Used to reduce the number of samples in the buffer, when accessing +// the sample buffer with the 'ptrBegin' function. +uint FIFOSampleBuffer::receiveSamples(uint maxSamples) +{ + if (maxSamples >= samplesInBuffer) + { + uint temp; + + temp = samplesInBuffer; + samplesInBuffer = 0; + return temp; + } + + samplesInBuffer -= maxSamples; + bufferPos += maxSamples; + + return maxSamples; +} + + +// Returns nonzero if the sample buffer is empty +int FIFOSampleBuffer::isEmpty() const +{ + return (samplesInBuffer == 0) ? 1 : 0; +} + + +// Clears the sample buffer +void FIFOSampleBuffer::clear() +{ + samplesInBuffer = 0; + bufferPos = 0; +} diff --git a/3rdparty/SoundTouch/FIFOSampleBuffer.h b/3rdparty/SoundTouch/FIFOSampleBuffer.h index 09f74c9a65..bcbfb59d4e 100644 --- a/3rdparty/SoundTouch/FIFOSampleBuffer.h +++ b/3rdparty/SoundTouch/FIFOSampleBuffer.h @@ -1,174 +1,174 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// A buffer class for temporarily storaging sound samples, operates as a -/// first-in-first-out pipe. -/// -/// Samples are added to the end of the sample buffer with the 'putSamples' -/// function, and are received from the beginning of the buffer by calling -/// the 'receiveSamples' function. The class automatically removes the -/// output samples from the buffer as well as grows the storage size -/// whenever necessary. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.9 $ -// -// $Id: FIFOSampleBuffer.h,v 1.9 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef FIFOSampleBuffer_H -#define FIFOSampleBuffer_H - -#include "FIFOSamplePipe.h" - -namespace soundtouch -{ - -/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes -/// care of storage size adjustment and data moving during input/output operations. -/// -/// Notice that in case of stereo audio, one sample is considered to consist of -/// both channel data. -class FIFOSampleBuffer : public FIFOSamplePipe -{ -private: - /// Sample buffer. - SAMPLETYPE *buffer; - - // Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first - // 16-byte aligned location of this buffer - SAMPLETYPE *bufferUnaligned; - - /// Sample buffer size in bytes - uint sizeInBytes; - - /// How many samples are currently in buffer. - uint samplesInBuffer; - - /// Channels, 1=mono, 2=stereo. - uint channels; - - /// Current position pointer to the buffer. This pointer is increased when samples are - /// removed from the pipe so that it's necessary to actually rewind buffer (move data) - /// only new data when is put to the pipe. - uint bufferPos; - - /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real - /// beginning of the buffer. - void rewind(); - - /// Ensures that the buffer has capacity for at least this many samples. - void ensureCapacity(const uint capacityRequirement); - - /// Returns current capacity. - uint getCapacity() const; - -public: - - /// Constructor - FIFOSampleBuffer(uint numChannels = 2 ///< Number of channels, 1=mono, 2=stereo. - ///< Default is stereo. - ); - - /// destructor - ~FIFOSampleBuffer(); - - /// Returns a pointer to the beginning of the output samples. - /// This function is provided for accessing the output samples directly. - /// Please be careful for not to corrupt the book-keeping! - /// - /// When using this function to output samples, also remember to 'remove' the - /// output samples from the buffer by calling the - /// 'receiveSamples(numSamples)' function - virtual SAMPLETYPE *ptrBegin() const; - - /// Returns a pointer to the end of the used part of the sample buffer (i.e. - /// where the new samples are to be inserted). This function may be used for - /// inserting new samples into the sample buffer directly. Please be careful - /// not corrupt the book-keeping! - /// - /// When using this function as means for inserting new samples, also remember - /// to increase the sample count afterwards, by calling the - /// 'putSamples(numSamples)' function. - SAMPLETYPE *ptrEnd( - uint slackCapacity ///< How much free capacity (in samples) there _at least_ - ///< should be so that the caller can succesfully insert the - ///< desired samples to the buffer. If necessary, the function - ///< grows the buffer size to comply with this requirement. - ); - - /// Adds 'numSamples' pcs of samples from the 'samples' memory position to - /// the sample buffer. - virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. - uint numSamples ///< Number of samples to insert. - ); - - /// Adjusts the book-keeping to increase number of samples in the buffer without - /// copying any actual samples. - /// - /// This function is used to update the number of samples in the sample buffer - /// when accessing the buffer directly with 'ptrEnd' function. Please be - /// careful though! - virtual void putSamples(uint numSamples ///< Number of samples been inserted. - ); - - /// Output samples from beginning of the sample buffer. Copies requested samples to - /// output buffer and removes them from the sample buffer. If there are less than - /// 'numsample' samples in the buffer, returns all that available. - /// - /// \return Number of samples returned. - virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. - uint maxSamples ///< How many samples to receive at max. - ); - - /// Adjusts book-keeping so that given number of samples are removed from beginning of the - /// sample buffer without copying them anywhere. - /// - /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly - /// with 'ptrBegin' function. - virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. - ); - - /// Returns number of samples currently available. - virtual uint numSamples() const; - - /// Sets number of channels, 1 = mono, 2 = stereo. - void setChannels(uint numChannels); - - /// Returns nonzero if there aren't any samples available for outputting. - virtual int isEmpty() const; - - /// Clears all the samples. - virtual void clear(); -}; - -} - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// A buffer class for temporarily storaging sound samples, operates as a +/// first-in-first-out pipe. +/// +/// Samples are added to the end of the sample buffer with the 'putSamples' +/// function, and are received from the beginning of the buffer by calling +/// the 'receiveSamples' function. The class automatically removes the +/// output samples from the buffer as well as grows the storage size +/// whenever necessary. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.9 $ +// +// $Id: FIFOSampleBuffer.h,v 1.9 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIFOSampleBuffer_H +#define FIFOSampleBuffer_H + +#include "FIFOSamplePipe.h" + +namespace soundtouch +{ + +/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes +/// care of storage size adjustment and data moving during input/output operations. +/// +/// Notice that in case of stereo audio, one sample is considered to consist of +/// both channel data. +class FIFOSampleBuffer : public FIFOSamplePipe +{ +private: + /// Sample buffer. + SAMPLETYPE *buffer; + + // Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first + // 16-byte aligned location of this buffer + SAMPLETYPE *bufferUnaligned; + + /// Sample buffer size in bytes + uint sizeInBytes; + + /// How many samples are currently in buffer. + uint samplesInBuffer; + + /// Channels, 1=mono, 2=stereo. + uint channels; + + /// Current position pointer to the buffer. This pointer is increased when samples are + /// removed from the pipe so that it's necessary to actually rewind buffer (move data) + /// only new data when is put to the pipe. + uint bufferPos; + + /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real + /// beginning of the buffer. + void rewind(); + + /// Ensures that the buffer has capacity for at least this many samples. + void ensureCapacity(const uint capacityRequirement); + + /// Returns current capacity. + uint getCapacity() const; + +public: + + /// Constructor + FIFOSampleBuffer(uint numChannels = 2 ///< Number of channels, 1=mono, 2=stereo. + ///< Default is stereo. + ); + + /// destructor + ~FIFOSampleBuffer(); + + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const; + + /// Returns a pointer to the end of the used part of the sample buffer (i.e. + /// where the new samples are to be inserted). This function may be used for + /// inserting new samples into the sample buffer directly. Please be careful + /// not corrupt the book-keeping! + /// + /// When using this function as means for inserting new samples, also remember + /// to increase the sample count afterwards, by calling the + /// 'putSamples(numSamples)' function. + SAMPLETYPE *ptrEnd( + uint slackCapacity ///< How much free capacity (in samples) there _at least_ + ///< should be so that the caller can succesfully insert the + ///< desired samples to the buffer. If necessary, the function + ///< grows the buffer size to comply with this requirement. + ); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position to + /// the sample buffer. + virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. + uint numSamples ///< Number of samples to insert. + ); + + /// Adjusts the book-keeping to increase number of samples in the buffer without + /// copying any actual samples. + /// + /// This function is used to update the number of samples in the sample buffer + /// when accessing the buffer directly with 'ptrEnd' function. Please be + /// careful though! + virtual void putSamples(uint numSamples ///< Number of samples been inserted. + ); + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ); + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ); + + /// Returns number of samples currently available. + virtual uint numSamples() const; + + /// Sets number of channels, 1 = mono, 2 = stereo. + void setChannels(uint numChannels); + + /// Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const; + + /// Clears all the samples. + virtual void clear(); +}; + +} + +#endif diff --git a/3rdparty/SoundTouch/FIFOSamplePipe.h b/3rdparty/SoundTouch/FIFOSamplePipe.h index 33e33c7e36..e10b8b26c8 100644 --- a/3rdparty/SoundTouch/FIFOSamplePipe.h +++ b/3rdparty/SoundTouch/FIFOSamplePipe.h @@ -1,217 +1,217 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound -/// samples by operating like a first-in-first-out pipe: New samples are fed -/// into one end of the pipe with the 'putSamples' function, and the processed -/// samples are received from the other end with the 'receiveSamples' function. -/// -/// 'FIFOProcessor' : A base class for classes the do signal processing with -/// the samples while operating like a first-in-first-out pipe. When samples -/// are input with the 'putSamples' function, the class processes them -/// and moves the processed samples to the given 'output' pipe object, which -/// may be either another processing stage, or a fifo sample buffer object. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.8 $ -// -// $Id: FIFOSamplePipe.h,v 1.8 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef FIFOSamplePipe_H -#define FIFOSamplePipe_H - -#include -#include -#include "STTypes.h" - -namespace soundtouch -{ - -/// Abstract base class for FIFO (first-in-first-out) sample processing classes. -class FIFOSamplePipe -{ -public: - /// Returns a pointer to the beginning of the output samples. - /// This function is provided for accessing the output samples directly. - /// Please be careful for not to corrupt the book-keeping! - /// - /// When using this function to output samples, also remember to 'remove' the - /// output samples from the buffer by calling the - /// 'receiveSamples(numSamples)' function - virtual SAMPLETYPE *ptrBegin() const = 0; - - /// Adds 'numSamples' pcs of samples from the 'samples' memory position to - /// the sample buffer. - virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. - uint numSamples ///< Number of samples to insert. - ) = 0; - - - // Moves samples from the 'other' pipe instance to this instance. - void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data. - ) - { - int oNumSamples = other.numSamples(); - - putSamples(other.ptrBegin(), oNumSamples); - other.receiveSamples(oNumSamples); - }; - - /// Output samples from beginning of the sample buffer. Copies requested samples to - /// output buffer and removes them from the sample buffer. If there are less than - /// 'numsample' samples in the buffer, returns all that available. - /// - /// \return Number of samples returned. - virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. - uint maxSamples ///< How many samples to receive at max. - ) = 0; - - /// Adjusts book-keeping so that given number of samples are removed from beginning of the - /// sample buffer without copying them anywhere. - /// - /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly - /// with 'ptrBegin' function. - virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. - ) = 0; - - /// Returns number of samples currently available. - virtual uint numSamples() const = 0; - - // Returns nonzero if there aren't any samples available for outputting. - virtual int isEmpty() const = 0; - - /// Clears all the samples. - virtual void clear() = 0; -}; - - - -/// Base-class for sound processing routines working in FIFO principle. With this base -/// class it's easy to implement sound processing stages that can be chained together, -/// so that samples that are fed into beginning of the pipe automatically go through -/// all the processing stages. -/// -/// When samples are input to this class, they're first processed and then put to -/// the FIFO pipe that's defined as output of this class. This output pipe can be -/// either other processing stage or a FIFO sample buffer. -class FIFOProcessor :public FIFOSamplePipe -{ -protected: - /// Internal pipe where processed samples are put. - FIFOSamplePipe *output; - - /// Sets output pipe. - void setOutPipe(FIFOSamplePipe *pOutput) - { - assert(output == NULL); - assert(pOutput != NULL); - output = pOutput; - } - - - /// Constructor. Doesn't define output pipe; it has to be set be - /// 'setOutPipe' function. - FIFOProcessor() - { - output = NULL; - } - - - /// Constructor. Configures output pipe. - FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe. - ) - { - output = pOutput; - } - - - /// Destructor. - virtual ~FIFOProcessor() - { - } - - - /// Returns a pointer to the beginning of the output samples. - /// This function is provided for accessing the output samples directly. - /// Please be careful for not to corrupt the book-keeping! - /// - /// When using this function to output samples, also remember to 'remove' the - /// output samples from the buffer by calling the - /// 'receiveSamples(numSamples)' function - virtual SAMPLETYPE *ptrBegin() const - { - return output->ptrBegin(); - } - -public: - - /// Output samples from beginning of the sample buffer. Copies requested samples to - /// output buffer and removes them from the sample buffer. If there are less than - /// 'numsample' samples in the buffer, returns all that available. - /// - /// \return Number of samples returned. - virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples. - uint maxSamples ///< How many samples to receive at max. - ) - { - return output->receiveSamples(outBuffer, maxSamples); - } - - - /// Adjusts book-keeping so that given number of samples are removed from beginning of the - /// sample buffer without copying them anywhere. - /// - /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly - /// with 'ptrBegin' function. - virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. - ) - { - return output->receiveSamples(maxSamples); - } - - - /// Returns number of samples currently available. - virtual uint numSamples() const - { - return output->numSamples(); - } - - - /// Returns nonzero if there aren't any samples available for outputting. - virtual int isEmpty() const - { - return output->isEmpty(); - } -}; - -} - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound +/// samples by operating like a first-in-first-out pipe: New samples are fed +/// into one end of the pipe with the 'putSamples' function, and the processed +/// samples are received from the other end with the 'receiveSamples' function. +/// +/// 'FIFOProcessor' : A base class for classes the do signal processing with +/// the samples while operating like a first-in-first-out pipe. When samples +/// are input with the 'putSamples' function, the class processes them +/// and moves the processed samples to the given 'output' pipe object, which +/// may be either another processing stage, or a fifo sample buffer object. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.8 $ +// +// $Id: FIFOSamplePipe.h,v 1.8 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIFOSamplePipe_H +#define FIFOSamplePipe_H + +#include +#include +#include "STTypes.h" + +namespace soundtouch +{ + +/// Abstract base class for FIFO (first-in-first-out) sample processing classes. +class FIFOSamplePipe +{ +public: + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const = 0; + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position to + /// the sample buffer. + virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. + uint numSamples ///< Number of samples to insert. + ) = 0; + + + // Moves samples from the 'other' pipe instance to this instance. + void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data. + ) + { + int oNumSamples = other.numSamples(); + + putSamples(other.ptrBegin(), oNumSamples); + other.receiveSamples(oNumSamples); + }; + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ) = 0; + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ) = 0; + + /// Returns number of samples currently available. + virtual uint numSamples() const = 0; + + // Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const = 0; + + /// Clears all the samples. + virtual void clear() = 0; +}; + + + +/// Base-class for sound processing routines working in FIFO principle. With this base +/// class it's easy to implement sound processing stages that can be chained together, +/// so that samples that are fed into beginning of the pipe automatically go through +/// all the processing stages. +/// +/// When samples are input to this class, they're first processed and then put to +/// the FIFO pipe that's defined as output of this class. This output pipe can be +/// either other processing stage or a FIFO sample buffer. +class FIFOProcessor :public FIFOSamplePipe +{ +protected: + /// Internal pipe where processed samples are put. + FIFOSamplePipe *output; + + /// Sets output pipe. + void setOutPipe(FIFOSamplePipe *pOutput) + { + assert(output == NULL); + assert(pOutput != NULL); + output = pOutput; + } + + + /// Constructor. Doesn't define output pipe; it has to be set be + /// 'setOutPipe' function. + FIFOProcessor() + { + output = NULL; + } + + + /// Constructor. Configures output pipe. + FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe. + ) + { + output = pOutput; + } + + + /// Destructor. + virtual ~FIFOProcessor() + { + } + + + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const + { + return output->ptrBegin(); + } + +public: + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ) + { + return output->receiveSamples(outBuffer, maxSamples); + } + + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ) + { + return output->receiveSamples(maxSamples); + } + + + /// Returns number of samples currently available. + virtual uint numSamples() const + { + return output->numSamples(); + } + + + /// Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const + { + return output->isEmpty(); + } +}; + +} + +#endif diff --git a/3rdparty/SoundTouch/FIRFilter.cpp b/3rdparty/SoundTouch/FIRFilter.cpp index ac57335a18..10a0bb0299 100644 --- a/3rdparty/SoundTouch/FIRFilter.cpp +++ b/3rdparty/SoundTouch/FIRFilter.cpp @@ -1,272 +1,272 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// General FIR digital filter routines with MMX optimization. -/// -/// Note : MMX optimized functions reside in a separate, platform-specific file, -/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.16 $ -// -// $Id: FIRFilter.cpp,v 1.16 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include "FIRFilter.h" -#include "cpu_detect.h" - -using namespace soundtouch; - -/***************************************************************************** - * - * Implementation of the class 'FIRFilter' - * - *****************************************************************************/ - -FIRFilter::FIRFilter() -{ - resultDivFactor = 0; - length = 0; - lengthDiv8 = 0; - filterCoeffs = NULL; -} - - -FIRFilter::~FIRFilter() -{ - delete[] filterCoeffs; -} - -// Usual C-version of the filter routine for stereo sound -uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const -{ - uint i, j, end; - LONG_SAMPLETYPE suml, sumr; -#ifdef FLOAT_SAMPLES - // when using floating point samples, use a scaler instead of a divider - // because division is much slower operation than multiplying. - double dScaler = 1.0 / (double)resultDivider; -#endif - - assert(length != 0); - - end = 2 * (numSamples - length); - - for (j = 0; j < end; j += 2) - { - const SAMPLETYPE *ptr; - - suml = sumr = 0; - ptr = src + j; - - for (i = 0; i < length; i += 4) - { - // loop is unrolled by factor of 4 here for efficiency - suml += ptr[2 * i + 0] * filterCoeffs[i + 0] + - ptr[2 * i + 2] * filterCoeffs[i + 1] + - ptr[2 * i + 4] * filterCoeffs[i + 2] + - ptr[2 * i + 6] * filterCoeffs[i + 3]; - sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] + - ptr[2 * i + 3] * filterCoeffs[i + 1] + - ptr[2 * i + 5] * filterCoeffs[i + 2] + - ptr[2 * i + 7] * filterCoeffs[i + 3]; - } - -#ifdef INTEGER_SAMPLES - suml >>= resultDivFactor; - sumr >>= resultDivFactor; - // saturate to 16 bit integer limits - suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml; - // saturate to 16 bit integer limits - sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr; -#else - suml *= dScaler; - sumr *= dScaler; -#endif // INTEGER_SAMPLES - dest[j] = (SAMPLETYPE)suml; - dest[j + 1] = (SAMPLETYPE)sumr; - } - return numSamples - length; -} - - - - -// Usual C-version of the filter routine for mono sound -uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const -{ - uint i, j, end; - LONG_SAMPLETYPE sum; -#ifdef FLOAT_SAMPLES - // when using floating point samples, use a scaler instead of a divider - // because division is much slower operation than multiplying. - double dScaler = 1.0 / (double)resultDivider; -#endif - - - assert(length != 0); - - end = numSamples - length; - for (j = 0; j < end; j ++) - { - sum = 0; - for (i = 0; i < length; i += 4) - { - // loop is unrolled by factor of 4 here for efficiency - sum += src[i + 0] * filterCoeffs[i + 0] + - src[i + 1] * filterCoeffs[i + 1] + - src[i + 2] * filterCoeffs[i + 2] + - src[i + 3] * filterCoeffs[i + 3]; - } -#ifdef INTEGER_SAMPLES - sum >>= resultDivFactor; - // saturate to 16 bit integer limits - sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum; -#else - sum *= dScaler; -#endif // INTEGER_SAMPLES - dest[j] = (SAMPLETYPE)sum; - src ++; - } - return end; -} - - -// Set filter coeffiecients and length. -// -// Throws an exception if filter length isn't divisible by 8 -void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor) -{ - assert(newLength > 0); - if (newLength % 8) throw std::runtime_error("FIR filter length not divisible by 8"); - - lengthDiv8 = newLength / 8; - length = lengthDiv8 * 8; - assert(length == newLength); - - resultDivFactor = uResultDivFactor; -#ifdef INTEGER_SAMPLES - resultDivider = (SAMPLETYPE)(1< 0); - assert(lengthDiv8 * 8 == length); - if (numSamples < length) return 0; - assert(resultDivFactor >= 0); - if (numChannels == 2) - { - return evaluateFilterStereo(dest, src, numSamples); - } else { - return evaluateFilterMono(dest, src, numSamples); - } -} - - - -// Operator 'new' is overloaded so that it automatically creates a suitable instance -// depending on if we've a MMX-capable CPU available or not. -void * FIRFilter::operator new(size_t s) -{ - // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! - throw std::runtime_error("Don't use 'new FIRFilter', use 'newInstance' member instead!"); - return NULL; -} - - -FIRFilter * FIRFilter::newInstance() -{ - uint uExtensions = 0; - -#if !defined(_MSC_VER) || !defined(__x86_64__) - uExtensions = detectCPUextensions(); -#endif - - // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU - -#ifdef ALLOW_MMX - // MMX routines available only with integer sample types - if (uExtensions & SUPPORT_MMX) - { - return ::new FIRFilterMMX; - } - else -#endif // ALLOW_MMX - -#ifdef ALLOW_SSE - if (uExtensions & SUPPORT_SSE) - { - // SSE support - return ::new FIRFilterSSE; - } - else -#endif // ALLOW_SSE - -#ifdef ALLOW_3DNOW - if (uExtensions & SUPPORT_3DNOW) - { - // 3DNow! support - return ::new FIRFilter3DNow; - } - else -#endif // ALLOW_3DNOW - - { - // ISA optimizations not supported, use plain C version - return ::new FIRFilter; - } -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// General FIR digital filter routines with MMX optimization. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.16 $ +// +// $Id: FIRFilter.cpp,v 1.16 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include "FIRFilter.h" +#include "cpu_detect.h" + +using namespace soundtouch; + +/***************************************************************************** + * + * Implementation of the class 'FIRFilter' + * + *****************************************************************************/ + +FIRFilter::FIRFilter() +{ + resultDivFactor = 0; + length = 0; + lengthDiv8 = 0; + filterCoeffs = NULL; +} + + +FIRFilter::~FIRFilter() +{ + delete[] filterCoeffs; +} + +// Usual C-version of the filter routine for stereo sound +uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const +{ + uint i, j, end; + LONG_SAMPLETYPE suml, sumr; +#ifdef FLOAT_SAMPLES + // when using floating point samples, use a scaler instead of a divider + // because division is much slower operation than multiplying. + double dScaler = 1.0 / (double)resultDivider; +#endif + + assert(length != 0); + + end = 2 * (numSamples - length); + + for (j = 0; j < end; j += 2) + { + const SAMPLETYPE *ptr; + + suml = sumr = 0; + ptr = src + j; + + for (i = 0; i < length; i += 4) + { + // loop is unrolled by factor of 4 here for efficiency + suml += ptr[2 * i + 0] * filterCoeffs[i + 0] + + ptr[2 * i + 2] * filterCoeffs[i + 1] + + ptr[2 * i + 4] * filterCoeffs[i + 2] + + ptr[2 * i + 6] * filterCoeffs[i + 3]; + sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] + + ptr[2 * i + 3] * filterCoeffs[i + 1] + + ptr[2 * i + 5] * filterCoeffs[i + 2] + + ptr[2 * i + 7] * filterCoeffs[i + 3]; + } + +#ifdef INTEGER_SAMPLES + suml >>= resultDivFactor; + sumr >>= resultDivFactor; + // saturate to 16 bit integer limits + suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml; + // saturate to 16 bit integer limits + sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr; +#else + suml *= dScaler; + sumr *= dScaler; +#endif // INTEGER_SAMPLES + dest[j] = (SAMPLETYPE)suml; + dest[j + 1] = (SAMPLETYPE)sumr; + } + return numSamples - length; +} + + + + +// Usual C-version of the filter routine for mono sound +uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const +{ + uint i, j, end; + LONG_SAMPLETYPE sum; +#ifdef FLOAT_SAMPLES + // when using floating point samples, use a scaler instead of a divider + // because division is much slower operation than multiplying. + double dScaler = 1.0 / (double)resultDivider; +#endif + + + assert(length != 0); + + end = numSamples - length; + for (j = 0; j < end; j ++) + { + sum = 0; + for (i = 0; i < length; i += 4) + { + // loop is unrolled by factor of 4 here for efficiency + sum += src[i + 0] * filterCoeffs[i + 0] + + src[i + 1] * filterCoeffs[i + 1] + + src[i + 2] * filterCoeffs[i + 2] + + src[i + 3] * filterCoeffs[i + 3]; + } +#ifdef INTEGER_SAMPLES + sum >>= resultDivFactor; + // saturate to 16 bit integer limits + sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum; +#else + sum *= dScaler; +#endif // INTEGER_SAMPLES + dest[j] = (SAMPLETYPE)sum; + src ++; + } + return end; +} + + +// Set filter coeffiecients and length. +// +// Throws an exception if filter length isn't divisible by 8 +void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor) +{ + assert(newLength > 0); + if (newLength % 8) throw std::runtime_error("FIR filter length not divisible by 8"); + + lengthDiv8 = newLength / 8; + length = lengthDiv8 * 8; + assert(length == newLength); + + resultDivFactor = uResultDivFactor; +#ifdef INTEGER_SAMPLES + resultDivider = (SAMPLETYPE)(1< 0); + assert(lengthDiv8 * 8 == length); + if (numSamples < length) return 0; + assert(resultDivFactor >= 0); + if (numChannels == 2) + { + return evaluateFilterStereo(dest, src, numSamples); + } else { + return evaluateFilterMono(dest, src, numSamples); + } +} + + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX-capable CPU available or not. +void * FIRFilter::operator new(size_t s) +{ + // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! + throw std::runtime_error("Don't use 'new FIRFilter', use 'newInstance' member instead!"); + return NULL; +} + + +FIRFilter * FIRFilter::newInstance() +{ + uint uExtensions = 0; + +#if !defined(_MSC_VER) || !defined(__x86_64__) + uExtensions = detectCPUextensions(); +#endif + + // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU + +#ifdef ALLOW_MMX + // MMX routines available only with integer sample types + if (uExtensions & SUPPORT_MMX) + { + return ::new FIRFilterMMX; + } + else +#endif // ALLOW_MMX + +#ifdef ALLOW_SSE + if (uExtensions & SUPPORT_SSE) + { + // SSE support + return ::new FIRFilterSSE; + } + else +#endif // ALLOW_SSE + +#ifdef ALLOW_3DNOW + if (uExtensions & SUPPORT_3DNOW) + { + // 3DNow! support + return ::new FIRFilter3DNow; + } + else +#endif // ALLOW_3DNOW + + { + // ISA optimizations not supported, use plain C version + return ::new FIRFilter; + } +} diff --git a/3rdparty/SoundTouch/FIRFilter.h b/3rdparty/SoundTouch/FIRFilter.h index be5cdd2943..5e9b3410f8 100644 --- a/3rdparty/SoundTouch/FIRFilter.h +++ b/3rdparty/SoundTouch/FIRFilter.h @@ -1,163 +1,163 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// General FIR digital filter routines with MMX optimization. -/// -/// Note : MMX optimized functions reside in a separate, platform-specific file, -/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.17 $ -// -// $Id: FIRFilter.h,v 1.17 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef FIRFilter_H -#define FIRFilter_H - -#include "STTypes.h" - -namespace soundtouch -{ - -class FIRFilter -{ -protected: - // Number of FIR filter taps - uint length; - // Number of FIR filter taps divided by 8 - uint lengthDiv8; - - // Result divider factor in 2^k format - uint resultDivFactor; - - // Result divider value. - SAMPLETYPE resultDivider; - - // Memory for filter coefficients - SAMPLETYPE *filterCoeffs; - - virtual uint evaluateFilterStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples) const; - virtual uint evaluateFilterMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples) const; - -public: - FIRFilter(); - virtual ~FIRFilter(); - - /// Operator 'new' is overloaded so that it automatically creates a suitable instance - /// depending on if we've a MMX-capable CPU available or not. - void * operator new(size_t s); - - static FIRFilter *newInstance(); - - /// Applies the filter to the given sequence of samples. - /// Note : The amount of outputted samples is by value of 'filter_length' - /// smaller than the amount of input samples. - /// - /// \return Number of samples copied to 'dest'. - uint evaluate(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples, - uint numChannels) const; - - uint getLength() const; - - virtual void setCoefficients(const SAMPLETYPE *coeffs, - uint newLength, - uint uResultDivFactor); -}; - - -// Optional subclasses that implement CPU-specific optimizations: - -#ifdef ALLOW_MMX - - /// Class that implements MMX optimized functions exclusive for 16bit integer samples type. - class FIRFilterMMX : public FIRFilter - { - protected: - short *filterCoeffsUnalign; - short *filterCoeffsAlign; - - virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const; - public: - FIRFilterMMX(); - ~FIRFilterMMX(); - - virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor); - }; - -#endif // ALLOW_MMX - - -#ifdef ALLOW_3DNOW - - /// Class that implements 3DNow! optimized functions exclusive for floating point samples type. - class FIRFilter3DNow : public FIRFilter - { - protected: - float *filterCoeffsUnalign; - float *filterCoeffsAlign; - - virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; - public: - FIRFilter3DNow(); - ~FIRFilter3DNow(); - virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); - }; - -#endif // ALLOW_3DNOW - - -#ifdef ALLOW_SSE - /// Class that implements SSE optimized functions exclusive for floating point samples type. - class FIRFilterSSE : public FIRFilter - { - protected: - float *filterCoeffsUnalign; - float *filterCoeffsAlign; - - virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; - public: - FIRFilterSSE(); - ~FIRFilterSSE(); - - virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); - }; - -#endif // ALLOW_SSE - -} - -#endif // FIRFilter_H +//////////////////////////////////////////////////////////////////////////////// +/// +/// General FIR digital filter routines with MMX optimization. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.17 $ +// +// $Id: FIRFilter.h,v 1.17 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIRFilter_H +#define FIRFilter_H + +#include "STTypes.h" + +namespace soundtouch +{ + +class FIRFilter +{ +protected: + // Number of FIR filter taps + uint length; + // Number of FIR filter taps divided by 8 + uint lengthDiv8; + + // Result divider factor in 2^k format + uint resultDivFactor; + + // Result divider value. + SAMPLETYPE resultDivider; + + // Memory for filter coefficients + SAMPLETYPE *filterCoeffs; + + virtual uint evaluateFilterStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) const; + virtual uint evaluateFilterMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) const; + +public: + FIRFilter(); + virtual ~FIRFilter(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we've a MMX-capable CPU available or not. + void * operator new(size_t s); + + static FIRFilter *newInstance(); + + /// Applies the filter to the given sequence of samples. + /// Note : The amount of outputted samples is by value of 'filter_length' + /// smaller than the amount of input samples. + /// + /// \return Number of samples copied to 'dest'. + uint evaluate(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples, + uint numChannels) const; + + uint getLength() const; + + virtual void setCoefficients(const SAMPLETYPE *coeffs, + uint newLength, + uint uResultDivFactor); +}; + + +// Optional subclasses that implement CPU-specific optimizations: + +#ifdef ALLOW_MMX + + /// Class that implements MMX optimized functions exclusive for 16bit integer samples type. + class FIRFilterMMX : public FIRFilter + { + protected: + short *filterCoeffsUnalign; + short *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const; + public: + FIRFilterMMX(); + ~FIRFilterMMX(); + + virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // ALLOW_MMX + + +#ifdef ALLOW_3DNOW + + /// Class that implements 3DNow! optimized functions exclusive for floating point samples type. + class FIRFilter3DNow : public FIRFilter + { + protected: + float *filterCoeffsUnalign; + float *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; + public: + FIRFilter3DNow(); + ~FIRFilter3DNow(); + virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // ALLOW_3DNOW + + +#ifdef ALLOW_SSE + /// Class that implements SSE optimized functions exclusive for floating point samples type. + class FIRFilterSSE : public FIRFilter + { + protected: + float *filterCoeffsUnalign; + float *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; + public: + FIRFilterSSE(); + ~FIRFilterSSE(); + + virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // ALLOW_SSE + +} + +#endif // FIRFilter_H diff --git a/3rdparty/SoundTouch/Makefile.am b/3rdparty/SoundTouch/Makefile.am index a09ae5f081..8e1d6d4bbf 100644 --- a/3rdparty/SoundTouch/Makefile.am +++ b/3rdparty/SoundTouch/Makefile.am @@ -1,46 +1,46 @@ -## Process this file with automake to create Makefile.in -## -## $Id: Makefile.am,v 1.3 2006/02/05 18:33:34 Olli Exp $ -## -## Copyright (C) 2003 - David W. Durham -## -## This file is part of SoundTouch, an audio processing library for pitch/time adjustments -## -## SoundTouch 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. -## -## SoundTouch 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 - -AUTOMAKE_OPTIONS = foreign - -noinst_HEADERS=AAFilter.h cpu_detect.h FIRFilter.h RateTransposer.h TDStretch.h cpu_detect_x86_gcc.cpp -noinst_LIBRARIES = libSoundTouch.a - -if X86_64 -libSoundTouch_a_CXXFLAGS = -fPIC -libSoundTouch_a_CFLAGS = -fPIC -else -libSoundTouch_a_CXXFLAGS = -msse -mmmx -libSoundTouch_a_CFLAGS = -msse -mmmx -endif - -#lib_LTLIBRARIES=libSoundTouch.la -# the mmx_gcc.cpp and cpu_detect_x86_gcc.cpp may need to be conditionally included here from things discovered in configure.ac -libSoundTouch_a_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp mmx_optimized.cpp sse_optimized.cpp \ -RateTransposer.cpp SoundTouch.cpp TDStretch.cpp WavFile.cpp cpu_detect_x86_gcc.cpp - -# ??? test for -fcheck-new in configure.ac -# other compiler flags to add -AM_CXXFLAGS=-O3 -msse -fcheck-new -I../../include - -# other linking flags to add -#libSoundTouch_la_LIBADD= - +## Process this file with automake to create Makefile.in +## +## $Id: Makefile.am,v 1.3 2006/02/05 18:33:34 Olli Exp $ +## +## Copyright (C) 2003 - David W. Durham +## +## This file is part of SoundTouch, an audio processing library for pitch/time adjustments +## +## SoundTouch 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. +## +## SoundTouch 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 + +AUTOMAKE_OPTIONS = foreign + +noinst_HEADERS=AAFilter.h cpu_detect.h FIRFilter.h RateTransposer.h TDStretch.h cpu_detect_x86_gcc.cpp +noinst_LIBRARIES = libSoundTouch.a + +if X86_64 +libSoundTouch_a_CXXFLAGS = -fPIC +libSoundTouch_a_CFLAGS = -fPIC +else +libSoundTouch_a_CXXFLAGS = -msse -mmmx +libSoundTouch_a_CFLAGS = -msse -mmmx +endif + +#lib_LTLIBRARIES=libSoundTouch.la +# the mmx_gcc.cpp and cpu_detect_x86_gcc.cpp may need to be conditionally included here from things discovered in configure.ac +libSoundTouch_a_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp mmx_optimized.cpp sse_optimized.cpp \ +RateTransposer.cpp SoundTouch.cpp TDStretch.cpp WavFile.cpp cpu_detect_x86_gcc.cpp + +# ??? test for -fcheck-new in configure.ac +# other compiler flags to add +AM_CXXFLAGS=-O3 -msse -fcheck-new -I../../include + +# other linking flags to add +#libSoundTouch_la_LIBADD= + diff --git a/3rdparty/SoundTouch/RateTransposer.cpp b/3rdparty/SoundTouch/RateTransposer.cpp index b7414b90a6..9e5c962d13 100644 --- a/3rdparty/SoundTouch/RateTransposer.cpp +++ b/3rdparty/SoundTouch/RateTransposer.cpp @@ -1,626 +1,626 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sample rate transposer. Changes sample rate by using linear interpolation -/// together with anti-alias filtering (first order interpolation with anti- -/// alias filtering should be quite adequate for this application) -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/03/19 10:05:49 $ -// File revision : $Revision: 1.13 $ -// -// $Id: RateTransposer.cpp,v 1.13 2006/03/19 10:05:49 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include "RateTransposer.h" -#include "AAFilter.h" - -using namespace soundtouch; - - -/// A linear samplerate transposer class that uses integer arithmetics. -/// for the transposing. -class RateTransposerInteger : public RateTransposer -{ -protected: - int iSlopeCount; - uint uRate; - SAMPLETYPE sPrevSampleL, sPrevSampleR; - - virtual void resetRegisters(); - - virtual uint transposeStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - virtual uint transposeMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - -public: - RateTransposerInteger(); - virtual ~RateTransposerInteger(); - - /// Sets new target rate. Normal rate = 1.0, smaller values represent slower - /// rate, larger faster rates. - virtual void setRate(float newRate); - -}; - - -/// A linear samplerate transposer class that uses floating point arithmetics -/// for the transposing. -class RateTransposerFloat : public RateTransposer -{ -protected: - float fSlopeCount; - float fRateStep; - SAMPLETYPE sPrevSampleL, sPrevSampleR; - - virtual void resetRegisters(); - - virtual uint transposeStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - virtual uint transposeMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - -public: - RateTransposerFloat(); - virtual ~RateTransposerFloat(); -}; - - - -#ifndef min -#define min(a,b) ((a > b) ? b : a) -#define max(a,b) ((a < b) ? b : a) -#endif - - -// Operator 'new' is overloaded so that it automatically creates a suitable instance -// depending on if we've a MMX/SSE/etc-capable CPU available or not. -void * RateTransposer::operator new(size_t s) -{ - // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! - assert(FALSE); - return NULL; -} - - -RateTransposer *RateTransposer::newInstance() -{ -#ifdef INTEGER_SAMPLES - return ::new RateTransposerInteger; -#else - return ::new RateTransposerFloat; -#endif -} - - -// Constructor -RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer) -{ - uChannels = 2; - bUseAAFilter = TRUE; - - // Instantiates the anti-alias filter with default tap length - // of 32 - pAAFilter = new AAFilter(32); -} - - - -RateTransposer::~RateTransposer() -{ - delete pAAFilter; -} - - - -/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable -void RateTransposer::enableAAFilter(const BOOL newMode) -{ - bUseAAFilter = newMode; -} - - -/// Returns nonzero if anti-alias filter is enabled. -BOOL RateTransposer::isAAFilterEnabled() const -{ - return bUseAAFilter; -} - - -AAFilter *RateTransposer::getAAFilter() const -{ - return pAAFilter; -} - - - -// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower -// uRate, larger faster uRates. -void RateTransposer::setRate(float newRate) -{ - float fCutoff; - - fRate = newRate; - - // design a new anti-alias filter - if (newRate > 1.0f) - { - fCutoff = 0.5f / newRate; - } - else - { - fCutoff = 0.5f * newRate; - } - pAAFilter->setCutoffFreq(fCutoff); -} - - -// Outputs as many samples of the 'outputBuffer' as possible, and if there's -// any room left, outputs also as many of the incoming samples as possible. -// The goal is to drive the outputBuffer empty. -// -// It's allowed for 'output' and 'input' parameters to point to the same -// memory position. -void RateTransposer::flushStoreBuffer() -{ - if (storeBuffer.isEmpty()) return; - - outputBuffer.moveSamples(storeBuffer); -} - - -// Adds 'numSamples' pcs of samples from the 'samples' memory position into -// the input of the object. -void RateTransposer::putSamples(const SAMPLETYPE *samples, uint numSamples) -{ - processSamples(samples, numSamples); -} - - - -// Transposes up the sample rate, causing the observed playback 'rate' of the -// sound to decrease -void RateTransposer::upsample(const SAMPLETYPE *src, uint numSamples) -{ - int count, sizeTemp, num; - - // If the parameter 'uRate' value is smaller than 'SCALE', first transpose - // the samples and then apply the anti-alias filter to remove aliasing. - - // First check that there's enough room in 'storeBuffer' - // (+16 is to reserve some slack in the destination buffer) - sizeTemp = (int)((float)numSamples / fRate + 16.0f); - - // Transpose the samples, store the result into the end of "storeBuffer" - count = transpose(storeBuffer.ptrEnd(sizeTemp), src, numSamples); - storeBuffer.putSamples(count); - - // Apply the anti-alias filter to samples in "store output", output the - // result to "dest" - num = storeBuffer.numSamples(); - count = pAAFilter->evaluate(outputBuffer.ptrEnd(num), - storeBuffer.ptrBegin(), num, uChannels); - outputBuffer.putSamples(count); - - // Remove the processed samples from "storeBuffer" - storeBuffer.receiveSamples(count); -} - - -// Transposes down the sample rate, causing the observed playback 'rate' of the -// sound to increase -void RateTransposer::downsample(const SAMPLETYPE *src, uint numSamples) -{ - int count, sizeTemp; - - // If the parameter 'uRate' value is larger than 'SCALE', first apply the - // anti-alias filter to remove high frequencies (prevent them from folding - // over the lover frequencies), then transpose. */ - - // Add the new samples to the end of the storeBuffer */ - storeBuffer.putSamples(src, numSamples); - - // Anti-alias filter the samples to prevent folding and output the filtered - // data to tempBuffer. Note : because of the FIR filter length, the - // filtering routine takes in 'filter_length' more samples than it outputs. - assert(tempBuffer.isEmpty()); - sizeTemp = storeBuffer.numSamples(); - - count = pAAFilter->evaluate(tempBuffer.ptrEnd(sizeTemp), - storeBuffer.ptrBegin(), sizeTemp, uChannels); - - // Remove the filtered samples from 'storeBuffer' - storeBuffer.receiveSamples(count); - - // Transpose the samples (+16 is to reserve some slack in the destination buffer) - sizeTemp = (int)((float)numSamples / fRate + 16.0f); - count = transpose(outputBuffer.ptrEnd(sizeTemp), tempBuffer.ptrBegin(), count); - outputBuffer.putSamples(count); -} - - -// Transposes sample rate by applying anti-alias filter to prevent folding. -// Returns amount of samples returned in the "dest" buffer. -// The maximum amount of samples that can be returned at a time is set by -// the 'set_returnBuffer_size' function. -void RateTransposer::processSamples(const SAMPLETYPE *src, uint numSamples) -{ - uint count; - uint sizeReq; - - if (numSamples == 0) return; - assert(pAAFilter); - - // If anti-alias filter is turned off, simply transpose without applying - // the filter - if (bUseAAFilter == FALSE) - { - sizeReq = (int)((float)numSamples / fRate + 1.0f); - count = transpose(outputBuffer.ptrEnd(sizeReq), src, numSamples); - outputBuffer.putSamples(count); - return; - } - - // Transpose with anti-alias filter - if (fRate < 1.0f) - { - upsample(src, numSamples); - } - else - { - downsample(src, numSamples); - } -} - - -// Transposes the sample rate of the given samples using linear interpolation. -// Returns the number of samples returned in the "dest" buffer -inline uint RateTransposer::transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) -{ - if (uChannels == 2) - { - return transposeStereo(dest, src, numSamples); - } - else - { - return transposeMono(dest, src, numSamples); - } -} - - -// Sets the number of channels, 1 = mono, 2 = stereo -void RateTransposer::setChannels(const uint numchannels) -{ - if (uChannels == numchannels) return; - - assert(numchannels == 1 || numchannels == 2); - uChannels = numchannels; - - storeBuffer.setChannels(uChannels); - tempBuffer.setChannels(uChannels); - outputBuffer.setChannels(uChannels); - - // Inits the linear interpolation registers - resetRegisters(); -} - - -// Clears all the samples in the object -void RateTransposer::clear() -{ - outputBuffer.clear(); - storeBuffer.clear(); -} - - -// Returns nonzero if there aren't any samples available for outputting. -uint RateTransposer::isEmpty() -{ - int res; - - res = FIFOProcessor::isEmpty(); - if (res == 0) return 0; - return storeBuffer.isEmpty(); -} - - -////////////////////////////////////////////////////////////////////////////// -// -// RateTransposerInteger - integer arithmetic implementation -// - -/// fixed-point interpolation routine precision -#define SCALE 65536 - -// Constructor -RateTransposerInteger::RateTransposerInteger() : RateTransposer() -{ - // call these here as these are virtual functions; calling these - // from the base class constructor wouldn't execute the overloaded - // versions (peculiar C++ can be). - resetRegisters(); - setRate(1.0f); -} - - -RateTransposerInteger::~RateTransposerInteger() -{ -} - - -void RateTransposerInteger::resetRegisters() -{ - iSlopeCount = 0; - sPrevSampleL = - sPrevSampleR = 0; -} - - - -// Transposes the sample rate of the given samples using linear interpolation. -// 'Mono' version of the routine. Returns the number of samples returned in -// the "dest" buffer -uint RateTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) -{ - unsigned int i, used; - LONG_SAMPLETYPE temp, vol1; - - used = 0; - i = 0; - - // Process the last sample saved from the previous call first... - while (iSlopeCount <= SCALE) - { - vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); - temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; - dest[i] = (SAMPLETYPE)(temp / SCALE); - i++; - iSlopeCount += uRate; - } - // now always (iSlopeCount > SCALE) - iSlopeCount -= SCALE; - - while (1) - { - while (iSlopeCount > SCALE) - { - iSlopeCount -= SCALE; - used ++; - if (used >= numSamples - 1) goto end; - } - vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); - temp = src[used] * vol1 + iSlopeCount * src[used + 1]; - dest[i] = (SAMPLETYPE)(temp / SCALE); - - i++; - iSlopeCount += uRate; - } -end: - // Store the last sample for the next round - sPrevSampleL = src[numSamples - 1]; - - return i; -} - - -// Transposes the sample rate of the given samples using linear interpolation. -// 'Stereo' version of the routine. Returns the number of samples returned in -// the "dest" buffer -uint RateTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) -{ - unsigned int srcPos, i, used; - LONG_SAMPLETYPE temp, vol1; - - if (numSamples == 0) return 0; // no samples, no work - - used = 0; - i = 0; - - // Process the last sample saved from the sPrevSampleLious call first... - while (iSlopeCount <= SCALE) - { - vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); - temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; - dest[2 * i] = (SAMPLETYPE)(temp / SCALE); - temp = vol1 * sPrevSampleR + iSlopeCount * src[1]; - dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); - i++; - iSlopeCount += uRate; - } - // now always (iSlopeCount > SCALE) - iSlopeCount -= SCALE; - - while (1) - { - while (iSlopeCount > SCALE) - { - iSlopeCount -= SCALE; - used ++; - if (used >= numSamples - 1) goto end; - } - srcPos = 2 * used; - vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); - temp = src[srcPos] * vol1 + iSlopeCount * src[srcPos + 2]; - dest[2 * i] = (SAMPLETYPE)(temp / SCALE); - temp = src[srcPos + 1] * vol1 + iSlopeCount * src[srcPos + 3]; - dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); - - i++; - iSlopeCount += uRate; - } -end: - // Store the last sample for the next round - sPrevSampleL = src[2 * numSamples - 2]; - sPrevSampleR = src[2 * numSamples - 1]; - - return i; -} - - -// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower -// uRate, larger faster uRates. -void RateTransposerInteger::setRate(float newRate) -{ - uRate = (int)(newRate * SCALE + 0.5f); - RateTransposer::setRate(newRate); -} - - -////////////////////////////////////////////////////////////////////////////// -// -// RateTransposerFloat - floating point arithmetic implementation -// -////////////////////////////////////////////////////////////////////////////// - -// Constructor -RateTransposerFloat::RateTransposerFloat() : RateTransposer() -{ - // call these here as these are virtual functions; calling these - // from the base class constructor wouldn't execute the overloaded - // versions (peculiar C++ can be). - resetRegisters(); - setRate(1.0f); -} - - -RateTransposerFloat::~RateTransposerFloat() -{ -} - - -void RateTransposerFloat::resetRegisters() -{ - fSlopeCount = 0; - sPrevSampleL = - sPrevSampleR = 0; -} - - - -// Transposes the sample rate of the given samples using linear interpolation. -// 'Mono' version of the routine. Returns the number of samples returned in -// the "dest" buffer -uint RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) -{ - unsigned int i, used; - - used = 0; - i = 0; - - // Process the last sample saved from the previous call first... - while (fSlopeCount <= 1.0f) - { - dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); - i++; - fSlopeCount += fRate; - } - fSlopeCount -= 1.0f; - - if (numSamples == 1) goto end; - - while (1) - { - while (fSlopeCount > 1.0f) - { - fSlopeCount -= 1.0f; - used ++; - if (used >= numSamples - 1) goto end; - } - dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[used] + fSlopeCount * src[used + 1]); - i++; - fSlopeCount += fRate; - } -end: - // Store the last sample for the next round - sPrevSampleL = src[numSamples - 1]; - - return i; -} - - -// Transposes the sample rate of the given samples using linear interpolation. -// 'Mono' version of the routine. Returns the number of samples returned in -// the "dest" buffer -uint RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) -{ - unsigned int srcPos, i, used; - - if (numSamples == 0) return 0; // no samples, no work - - used = 0; - i = 0; - - // Process the last sample saved from the sPrevSampleLious call first... - while (fSlopeCount <= 1.0f) - { - dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); - dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleR + fSlopeCount * src[1]); - i++; - fSlopeCount += fRate; - } - // now always (iSlopeCount > 1.0f) - fSlopeCount -= 1.0f; - - if (numSamples == 1) goto end; - - while (1) - { - while (fSlopeCount > 1.0f) - { - fSlopeCount -= 1.0f; - used ++; - if (used >= numSamples - 1) goto end; - } - srcPos = 2 * used; - - dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos] - + fSlopeCount * src[srcPos + 2]); - dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos + 1] - + fSlopeCount * src[srcPos + 3]); - - i++; - fSlopeCount += fRate; - } -end: - // Store the last sample for the next round - sPrevSampleL = src[2 * numSamples - 2]; - sPrevSampleR = src[2 * numSamples - 1]; - - return i; -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sample rate transposer. Changes sample rate by using linear interpolation +/// together with anti-alias filtering (first order interpolation with anti- +/// alias filtering should be quite adequate for this application) +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/03/19 10:05:49 $ +// File revision : $Revision: 1.13 $ +// +// $Id: RateTransposer.cpp,v 1.13 2006/03/19 10:05:49 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include "RateTransposer.h" +#include "AAFilter.h" + +using namespace soundtouch; + + +/// A linear samplerate transposer class that uses integer arithmetics. +/// for the transposing. +class RateTransposerInteger : public RateTransposer +{ +protected: + int iSlopeCount; + uint uRate; + SAMPLETYPE sPrevSampleL, sPrevSampleR; + + virtual void resetRegisters(); + + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + +public: + RateTransposerInteger(); + virtual ~RateTransposerInteger(); + + /// Sets new target rate. Normal rate = 1.0, smaller values represent slower + /// rate, larger faster rates. + virtual void setRate(float newRate); + +}; + + +/// A linear samplerate transposer class that uses floating point arithmetics +/// for the transposing. +class RateTransposerFloat : public RateTransposer +{ +protected: + float fSlopeCount; + float fRateStep; + SAMPLETYPE sPrevSampleL, sPrevSampleR; + + virtual void resetRegisters(); + + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + +public: + RateTransposerFloat(); + virtual ~RateTransposerFloat(); +}; + + + +#ifndef min +#define min(a,b) ((a > b) ? b : a) +#define max(a,b) ((a < b) ? b : a) +#endif + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX/SSE/etc-capable CPU available or not. +void * RateTransposer::operator new(size_t s) +{ + // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! + assert(FALSE); + return NULL; +} + + +RateTransposer *RateTransposer::newInstance() +{ +#ifdef INTEGER_SAMPLES + return ::new RateTransposerInteger; +#else + return ::new RateTransposerFloat; +#endif +} + + +// Constructor +RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer) +{ + uChannels = 2; + bUseAAFilter = TRUE; + + // Instantiates the anti-alias filter with default tap length + // of 32 + pAAFilter = new AAFilter(32); +} + + + +RateTransposer::~RateTransposer() +{ + delete pAAFilter; +} + + + +/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable +void RateTransposer::enableAAFilter(const BOOL newMode) +{ + bUseAAFilter = newMode; +} + + +/// Returns nonzero if anti-alias filter is enabled. +BOOL RateTransposer::isAAFilterEnabled() const +{ + return bUseAAFilter; +} + + +AAFilter *RateTransposer::getAAFilter() const +{ + return pAAFilter; +} + + + +// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower +// uRate, larger faster uRates. +void RateTransposer::setRate(float newRate) +{ + float fCutoff; + + fRate = newRate; + + // design a new anti-alias filter + if (newRate > 1.0f) + { + fCutoff = 0.5f / newRate; + } + else + { + fCutoff = 0.5f * newRate; + } + pAAFilter->setCutoffFreq(fCutoff); +} + + +// Outputs as many samples of the 'outputBuffer' as possible, and if there's +// any room left, outputs also as many of the incoming samples as possible. +// The goal is to drive the outputBuffer empty. +// +// It's allowed for 'output' and 'input' parameters to point to the same +// memory position. +void RateTransposer::flushStoreBuffer() +{ + if (storeBuffer.isEmpty()) return; + + outputBuffer.moveSamples(storeBuffer); +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void RateTransposer::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + processSamples(samples, numSamples); +} + + + +// Transposes up the sample rate, causing the observed playback 'rate' of the +// sound to decrease +void RateTransposer::upsample(const SAMPLETYPE *src, uint numSamples) +{ + int count, sizeTemp, num; + + // If the parameter 'uRate' value is smaller than 'SCALE', first transpose + // the samples and then apply the anti-alias filter to remove aliasing. + + // First check that there's enough room in 'storeBuffer' + // (+16 is to reserve some slack in the destination buffer) + sizeTemp = (int)((float)numSamples / fRate + 16.0f); + + // Transpose the samples, store the result into the end of "storeBuffer" + count = transpose(storeBuffer.ptrEnd(sizeTemp), src, numSamples); + storeBuffer.putSamples(count); + + // Apply the anti-alias filter to samples in "store output", output the + // result to "dest" + num = storeBuffer.numSamples(); + count = pAAFilter->evaluate(outputBuffer.ptrEnd(num), + storeBuffer.ptrBegin(), num, uChannels); + outputBuffer.putSamples(count); + + // Remove the processed samples from "storeBuffer" + storeBuffer.receiveSamples(count); +} + + +// Transposes down the sample rate, causing the observed playback 'rate' of the +// sound to increase +void RateTransposer::downsample(const SAMPLETYPE *src, uint numSamples) +{ + int count, sizeTemp; + + // If the parameter 'uRate' value is larger than 'SCALE', first apply the + // anti-alias filter to remove high frequencies (prevent them from folding + // over the lover frequencies), then transpose. */ + + // Add the new samples to the end of the storeBuffer */ + storeBuffer.putSamples(src, numSamples); + + // Anti-alias filter the samples to prevent folding and output the filtered + // data to tempBuffer. Note : because of the FIR filter length, the + // filtering routine takes in 'filter_length' more samples than it outputs. + assert(tempBuffer.isEmpty()); + sizeTemp = storeBuffer.numSamples(); + + count = pAAFilter->evaluate(tempBuffer.ptrEnd(sizeTemp), + storeBuffer.ptrBegin(), sizeTemp, uChannels); + + // Remove the filtered samples from 'storeBuffer' + storeBuffer.receiveSamples(count); + + // Transpose the samples (+16 is to reserve some slack in the destination buffer) + sizeTemp = (int)((float)numSamples / fRate + 16.0f); + count = transpose(outputBuffer.ptrEnd(sizeTemp), tempBuffer.ptrBegin(), count); + outputBuffer.putSamples(count); +} + + +// Transposes sample rate by applying anti-alias filter to prevent folding. +// Returns amount of samples returned in the "dest" buffer. +// The maximum amount of samples that can be returned at a time is set by +// the 'set_returnBuffer_size' function. +void RateTransposer::processSamples(const SAMPLETYPE *src, uint numSamples) +{ + uint count; + uint sizeReq; + + if (numSamples == 0) return; + assert(pAAFilter); + + // If anti-alias filter is turned off, simply transpose without applying + // the filter + if (bUseAAFilter == FALSE) + { + sizeReq = (int)((float)numSamples / fRate + 1.0f); + count = transpose(outputBuffer.ptrEnd(sizeReq), src, numSamples); + outputBuffer.putSamples(count); + return; + } + + // Transpose with anti-alias filter + if (fRate < 1.0f) + { + upsample(src, numSamples); + } + else + { + downsample(src, numSamples); + } +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// Returns the number of samples returned in the "dest" buffer +inline uint RateTransposer::transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + if (uChannels == 2) + { + return transposeStereo(dest, src, numSamples); + } + else + { + return transposeMono(dest, src, numSamples); + } +} + + +// Sets the number of channels, 1 = mono, 2 = stereo +void RateTransposer::setChannels(const uint numchannels) +{ + if (uChannels == numchannels) return; + + assert(numchannels == 1 || numchannels == 2); + uChannels = numchannels; + + storeBuffer.setChannels(uChannels); + tempBuffer.setChannels(uChannels); + outputBuffer.setChannels(uChannels); + + // Inits the linear interpolation registers + resetRegisters(); +} + + +// Clears all the samples in the object +void RateTransposer::clear() +{ + outputBuffer.clear(); + storeBuffer.clear(); +} + + +// Returns nonzero if there aren't any samples available for outputting. +uint RateTransposer::isEmpty() +{ + int res; + + res = FIFOProcessor::isEmpty(); + if (res == 0) return 0; + return storeBuffer.isEmpty(); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// RateTransposerInteger - integer arithmetic implementation +// + +/// fixed-point interpolation routine precision +#define SCALE 65536 + +// Constructor +RateTransposerInteger::RateTransposerInteger() : RateTransposer() +{ + // call these here as these are virtual functions; calling these + // from the base class constructor wouldn't execute the overloaded + // versions (peculiar C++ can be). + resetRegisters(); + setRate(1.0f); +} + + +RateTransposerInteger::~RateTransposerInteger() +{ +} + + +void RateTransposerInteger::resetRegisters() +{ + iSlopeCount = 0; + sPrevSampleL = + sPrevSampleR = 0; +} + + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int i, used; + LONG_SAMPLETYPE temp, vol1; + + used = 0; + i = 0; + + // Process the last sample saved from the previous call first... + while (iSlopeCount <= SCALE) + { + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; + dest[i] = (SAMPLETYPE)(temp / SCALE); + i++; + iSlopeCount += uRate; + } + // now always (iSlopeCount > SCALE) + iSlopeCount -= SCALE; + + while (1) + { + while (iSlopeCount > SCALE) + { + iSlopeCount -= SCALE; + used ++; + if (used >= numSamples - 1) goto end; + } + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = src[used] * vol1 + iSlopeCount * src[used + 1]; + dest[i] = (SAMPLETYPE)(temp / SCALE); + + i++; + iSlopeCount += uRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[numSamples - 1]; + + return i; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Stereo' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int srcPos, i, used; + LONG_SAMPLETYPE temp, vol1; + + if (numSamples == 0) return 0; // no samples, no work + + used = 0; + i = 0; + + // Process the last sample saved from the sPrevSampleLious call first... + while (iSlopeCount <= SCALE) + { + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; + dest[2 * i] = (SAMPLETYPE)(temp / SCALE); + temp = vol1 * sPrevSampleR + iSlopeCount * src[1]; + dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); + i++; + iSlopeCount += uRate; + } + // now always (iSlopeCount > SCALE) + iSlopeCount -= SCALE; + + while (1) + { + while (iSlopeCount > SCALE) + { + iSlopeCount -= SCALE; + used ++; + if (used >= numSamples - 1) goto end; + } + srcPos = 2 * used; + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = src[srcPos] * vol1 + iSlopeCount * src[srcPos + 2]; + dest[2 * i] = (SAMPLETYPE)(temp / SCALE); + temp = src[srcPos + 1] * vol1 + iSlopeCount * src[srcPos + 3]; + dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); + + i++; + iSlopeCount += uRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[2 * numSamples - 2]; + sPrevSampleR = src[2 * numSamples - 1]; + + return i; +} + + +// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower +// uRate, larger faster uRates. +void RateTransposerInteger::setRate(float newRate) +{ + uRate = (int)(newRate * SCALE + 0.5f); + RateTransposer::setRate(newRate); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// RateTransposerFloat - floating point arithmetic implementation +// +////////////////////////////////////////////////////////////////////////////// + +// Constructor +RateTransposerFloat::RateTransposerFloat() : RateTransposer() +{ + // call these here as these are virtual functions; calling these + // from the base class constructor wouldn't execute the overloaded + // versions (peculiar C++ can be). + resetRegisters(); + setRate(1.0f); +} + + +RateTransposerFloat::~RateTransposerFloat() +{ +} + + +void RateTransposerFloat::resetRegisters() +{ + fSlopeCount = 0; + sPrevSampleL = + sPrevSampleR = 0; +} + + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int i, used; + + used = 0; + i = 0; + + // Process the last sample saved from the previous call first... + while (fSlopeCount <= 1.0f) + { + dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); + i++; + fSlopeCount += fRate; + } + fSlopeCount -= 1.0f; + + if (numSamples == 1) goto end; + + while (1) + { + while (fSlopeCount > 1.0f) + { + fSlopeCount -= 1.0f; + used ++; + if (used >= numSamples - 1) goto end; + } + dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[used] + fSlopeCount * src[used + 1]); + i++; + fSlopeCount += fRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[numSamples - 1]; + + return i; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int srcPos, i, used; + + if (numSamples == 0) return 0; // no samples, no work + + used = 0; + i = 0; + + // Process the last sample saved from the sPrevSampleLious call first... + while (fSlopeCount <= 1.0f) + { + dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); + dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleR + fSlopeCount * src[1]); + i++; + fSlopeCount += fRate; + } + // now always (iSlopeCount > 1.0f) + fSlopeCount -= 1.0f; + + if (numSamples == 1) goto end; + + while (1) + { + while (fSlopeCount > 1.0f) + { + fSlopeCount -= 1.0f; + used ++; + if (used >= numSamples - 1) goto end; + } + srcPos = 2 * used; + + dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos] + + fSlopeCount * src[srcPos + 2]); + dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos + 1] + + fSlopeCount * src[srcPos + 3]); + + i++; + fSlopeCount += fRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[2 * numSamples - 2]; + sPrevSampleR = src[2 * numSamples - 1]; + + return i; +} diff --git a/3rdparty/SoundTouch/RateTransposer.h b/3rdparty/SoundTouch/RateTransposer.h index f73978e639..1cd6e9026d 100644 --- a/3rdparty/SoundTouch/RateTransposer.h +++ b/3rdparty/SoundTouch/RateTransposer.h @@ -1,162 +1,162 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sample rate transposer. Changes sample rate by using linear interpolation -/// together with anti-alias filtering (first order interpolation with anti- -/// alias filtering should be quite adequate for this application). -/// -/// Use either of the derived classes of 'RateTransposerInteger' or -/// 'RateTransposerFloat' for corresponding integer/floating point tranposing -/// algorithm implementation. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.10 $ -// -// $Id: RateTransposer.h,v 1.10 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef RateTransposer_H -#define RateTransposer_H - -#include "AAFilter.h" -#include "FIFOSamplePipe.h" -#include "FIFOSampleBuffer.h" - -#include "STTypes.h" - -namespace soundtouch -{ - -/// A common linear samplerate transposer class. -/// -/// Note: Use function "RateTransposer::newInstance()" to create a new class -/// instance instead of the "new" operator; that function automatically -/// chooses a correct implementation depending on if integer or floating -/// arithmetics are to be used. -class RateTransposer : public FIFOProcessor -{ -protected: - /// Anti-alias filter object - AAFilter *pAAFilter; - - float fRate; - - uint uChannels; - - /// Buffer for collecting samples to feed the anti-alias filter between - /// two batches - FIFOSampleBuffer storeBuffer; - - /// Buffer for keeping samples between transposing & anti-alias filter - FIFOSampleBuffer tempBuffer; - - /// Output sample buffer - FIFOSampleBuffer outputBuffer; - - BOOL bUseAAFilter; - - void init(); - - virtual void resetRegisters() = 0; - - virtual uint transposeStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples) = 0; - virtual uint transposeMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples) = 0; - uint transpose(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - - void flushStoreBuffer(); - - void downsample(const SAMPLETYPE *src, - uint numSamples); - void upsample(const SAMPLETYPE *src, - uint numSamples); - - /// Transposes sample rate by applying anti-alias filter to prevent folding. - /// Returns amount of samples returned in the "dest" buffer. - /// The maximum amount of samples that can be returned at a time is set by - /// the 'set_returnBuffer_size' function. - void processSamples(const SAMPLETYPE *src, - uint numSamples); - - -public: - RateTransposer(); - virtual ~RateTransposer(); - - /// Operator 'new' is overloaded so that it automatically creates a suitable instance - /// depending on if we're to use integer or floating point arithmetics. - void *operator new(size_t s); - - /// Use this function instead of "new" operator to create a new instance of this class. - /// This function automatically chooses a correct implementation, depending on if - /// integer ot floating point arithmetics are to be used. - static RateTransposer *newInstance(); - - /// Returns the output buffer object - FIFOSamplePipe *getOutput() { return &outputBuffer; }; - - /// Returns the store buffer object - FIFOSamplePipe *getStore() { return &storeBuffer; }; - - /// Return anti-alias filter object - AAFilter *getAAFilter() const; - - /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable - void enableAAFilter(BOOL newMode); - - /// Returns nonzero if anti-alias filter is enabled. - BOOL isAAFilterEnabled() const; - - /// Sets new target rate. Normal rate = 1.0, smaller values represent slower - /// rate, larger faster rates. - virtual void setRate(float newRate); - - /// Sets the number of channels, 1 = mono, 2 = stereo - void setChannels(uint channels); - - /// Adds 'numSamples' pcs of samples from the 'samples' memory position into - /// the input of the object. - void putSamples(const SAMPLETYPE *samples, uint numSamples); - - /// Clears all the samples in the object - void clear(); - - /// Returns nonzero if there aren't any samples available for outputting. - uint isEmpty(); -}; - -} - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sample rate transposer. Changes sample rate by using linear interpolation +/// together with anti-alias filtering (first order interpolation with anti- +/// alias filtering should be quite adequate for this application). +/// +/// Use either of the derived classes of 'RateTransposerInteger' or +/// 'RateTransposerFloat' for corresponding integer/floating point tranposing +/// algorithm implementation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: RateTransposer.h,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef RateTransposer_H +#define RateTransposer_H + +#include "AAFilter.h" +#include "FIFOSamplePipe.h" +#include "FIFOSampleBuffer.h" + +#include "STTypes.h" + +namespace soundtouch +{ + +/// A common linear samplerate transposer class. +/// +/// Note: Use function "RateTransposer::newInstance()" to create a new class +/// instance instead of the "new" operator; that function automatically +/// chooses a correct implementation depending on if integer or floating +/// arithmetics are to be used. +class RateTransposer : public FIFOProcessor +{ +protected: + /// Anti-alias filter object + AAFilter *pAAFilter; + + float fRate; + + uint uChannels; + + /// Buffer for collecting samples to feed the anti-alias filter between + /// two batches + FIFOSampleBuffer storeBuffer; + + /// Buffer for keeping samples between transposing & anti-alias filter + FIFOSampleBuffer tempBuffer; + + /// Output sample buffer + FIFOSampleBuffer outputBuffer; + + BOOL bUseAAFilter; + + void init(); + + virtual void resetRegisters() = 0; + + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) = 0; + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) = 0; + uint transpose(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + + void flushStoreBuffer(); + + void downsample(const SAMPLETYPE *src, + uint numSamples); + void upsample(const SAMPLETYPE *src, + uint numSamples); + + /// Transposes sample rate by applying anti-alias filter to prevent folding. + /// Returns amount of samples returned in the "dest" buffer. + /// The maximum amount of samples that can be returned at a time is set by + /// the 'set_returnBuffer_size' function. + void processSamples(const SAMPLETYPE *src, + uint numSamples); + + +public: + RateTransposer(); + virtual ~RateTransposer(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we're to use integer or floating point arithmetics. + void *operator new(size_t s); + + /// Use this function instead of "new" operator to create a new instance of this class. + /// This function automatically chooses a correct implementation, depending on if + /// integer ot floating point arithmetics are to be used. + static RateTransposer *newInstance(); + + /// Returns the output buffer object + FIFOSamplePipe *getOutput() { return &outputBuffer; }; + + /// Returns the store buffer object + FIFOSamplePipe *getStore() { return &storeBuffer; }; + + /// Return anti-alias filter object + AAFilter *getAAFilter() const; + + /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable + void enableAAFilter(BOOL newMode); + + /// Returns nonzero if anti-alias filter is enabled. + BOOL isAAFilterEnabled() const; + + /// Sets new target rate. Normal rate = 1.0, smaller values represent slower + /// rate, larger faster rates. + virtual void setRate(float newRate); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint channels); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position into + /// the input of the object. + void putSamples(const SAMPLETYPE *samples, uint numSamples); + + /// Clears all the samples in the object + void clear(); + + /// Returns nonzero if there aren't any samples available for outputting. + uint isEmpty(); +}; + +} + +#endif diff --git a/3rdparty/SoundTouch/STTypes.h b/3rdparty/SoundTouch/STTypes.h index f3a6a5d5c0..d0969ec1c9 100644 --- a/3rdparty/SoundTouch/STTypes.h +++ b/3rdparty/SoundTouch/STTypes.h @@ -1,202 +1,202 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Common type definitions for SoundTouch audio processing library. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.16 $ -// -// $Id: STTypes.h,v 1.16 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef STTypes_H -#define STTypes_H - -//#define INTEGER_SAMPLES 1 - -typedef unsigned int uint; -typedef unsigned long ulong; - -#ifdef __x86_64__ -typedef unsigned long long ulongptr; -#else -typedef unsigned long ulongptr; -#endif - - -#ifdef __GNUC__ - // In GCC, include soundtouch_config.h made by config scritps -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the `m' library (-lm). */ -#define HAVE_LIBM 1 - -/* Define to 1 if your system has a GNU libc compatible `malloc' function, and - to 0 otherwise. */ -#define HAVE_MALLOC 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Use Integer as Sample type */ -//#define INTEGER_SAMPLES 1 - -/* Define as the return type of signal handlers (`int' or `void'). */ -#define RETSIGTYPE void - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -#endif - -#ifndef _WINDEF_ - // if these aren't defined already by Windows headers, define now - - typedef int BOOL; - -#ifndef FALSE - #define FALSE 0 -#endif - -#ifndef TRUE - #define TRUE 1 -#endif - -#endif // _WINDEF_ - - -namespace soundtouch -{ -/// Activate these undef's to overrule the possible sampletype -/// setting inherited from some other header file: -//#undef INTEGER_SAMPLES -//#undef FLOAT_SAMPLES - -#if !(INTEGER_SAMPLES || FLOAT_SAMPLES) - - /// Choose either 32bit floating point or 16bit integer sampletype - /// by choosing one of the following defines, unless this selection - /// has already been done in some other file. - //// - /// Notes: - /// - In Windows environment, choose the sample format with the - /// following defines. - /// - In GNU environment, the floating point samples are used by - /// default, but integer samples can be chosen by giving the - /// following switch to the configure script: - /// ./configure --enable-integer-samples - /// However, if you still prefer to select the sample format here - /// also in GNU environment, then please #undef the INTEGER_SAMPLE - /// and FLOAT_SAMPLE defines first as in comments above. - //#define INTEGER_SAMPLES 1 //< 16bit integer samples - #define FLOAT_SAMPLES 1 //< 32bit float samples - - #endif - - /// Define this to allow CPU-specific assembler optimizations. Notice that - /// having this enabled on non-x86 platforms doesn't matter; the compiler can - /// drop unsupported extensions on different platforms automatically. - /// However, if you're having difficulties getting the optimized routines - /// compiled with your compler (e.g. some gcc compiler versions may be picky), - /// you may wish to disable the optimizations to make the library compile. - #if !defined(_MSC_VER) || !defined(__x86_64__) - #define ALLOW_OPTIMIZATIONS 1 - #define ALLOW_NONEXACT_SIMD_OPTIMIZATION 1 - #endif - - - // If defined, allows the SIMD-optimized routines to take minor shortcuts - // for improved performance. Undefine to require faithfully similar SIMD - // calculations as in normal C implementation. - - - - #ifdef INTEGER_SAMPLES - // 16bit integer sample type - typedef short SAMPLETYPE; - // data type for sample accumulation: Use 32bit integer to prevent overflows - typedef long LONG_SAMPLETYPE; - - #ifdef FLOAT_SAMPLES - // check that only one sample type is defined - #error "conflicting sample types defined" - #endif // FLOAT_SAMPLES - - #ifdef ALLOW_OPTIMIZATIONS - #if (_WIN32 || __i386__ || __x86_64__) - // Allow MMX optimizations - #define ALLOW_MMX 1 - #endif - #endif - - #else - - // floating point samples - typedef float SAMPLETYPE; - // data type for sample accumulation: Use double to utilize full precision. - typedef double LONG_SAMPLETYPE; - - #ifdef ALLOW_OPTIMIZATIONS - // Allow 3DNow! and SSE optimizations - #if _WIN32 - // #define ALLOW_3DNOW 1 - #endif - - #if (_WIN32 || __i386__ || __x86_64__) - #define ALLOW_SSE 1 - #endif - #endif - - #endif // INTEGER_SAMPLES -}; - +//////////////////////////////////////////////////////////////////////////////// +/// +/// Common type definitions for SoundTouch audio processing library. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.16 $ +// +// $Id: STTypes.h,v 1.16 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef STTypes_H +#define STTypes_H + +//#define INTEGER_SAMPLES 1 + +typedef unsigned int uint; +typedef unsigned long ulong; + +#ifdef __x86_64__ +typedef unsigned long long ulongptr; +#else +typedef unsigned long ulongptr; +#endif + + +#ifdef __GNUC__ + // In GCC, include soundtouch_config.h made by config scritps +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `m' library (-lm). */ +#define HAVE_LIBM 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Use Integer as Sample type */ +//#define INTEGER_SAMPLES 1 + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +#endif + +#ifndef _WINDEF_ + // if these aren't defined already by Windows headers, define now + + typedef int BOOL; + +#ifndef FALSE + #define FALSE 0 +#endif + +#ifndef TRUE + #define TRUE 1 +#endif + +#endif // _WINDEF_ + + +namespace soundtouch +{ +/// Activate these undef's to overrule the possible sampletype +/// setting inherited from some other header file: +//#undef INTEGER_SAMPLES +//#undef FLOAT_SAMPLES + +#if !(INTEGER_SAMPLES || FLOAT_SAMPLES) + + /// Choose either 32bit floating point or 16bit integer sampletype + /// by choosing one of the following defines, unless this selection + /// has already been done in some other file. + //// + /// Notes: + /// - In Windows environment, choose the sample format with the + /// following defines. + /// - In GNU environment, the floating point samples are used by + /// default, but integer samples can be chosen by giving the + /// following switch to the configure script: + /// ./configure --enable-integer-samples + /// However, if you still prefer to select the sample format here + /// also in GNU environment, then please #undef the INTEGER_SAMPLE + /// and FLOAT_SAMPLE defines first as in comments above. + //#define INTEGER_SAMPLES 1 //< 16bit integer samples + #define FLOAT_SAMPLES 1 //< 32bit float samples + + #endif + + /// Define this to allow CPU-specific assembler optimizations. Notice that + /// having this enabled on non-x86 platforms doesn't matter; the compiler can + /// drop unsupported extensions on different platforms automatically. + /// However, if you're having difficulties getting the optimized routines + /// compiled with your compler (e.g. some gcc compiler versions may be picky), + /// you may wish to disable the optimizations to make the library compile. + #if !defined(_MSC_VER) || !defined(__x86_64__) + #define ALLOW_OPTIMIZATIONS 1 + #define ALLOW_NONEXACT_SIMD_OPTIMIZATION 1 + #endif + + + // If defined, allows the SIMD-optimized routines to take minor shortcuts + // for improved performance. Undefine to require faithfully similar SIMD + // calculations as in normal C implementation. + + + + #ifdef INTEGER_SAMPLES + // 16bit integer sample type + typedef short SAMPLETYPE; + // data type for sample accumulation: Use 32bit integer to prevent overflows + typedef long LONG_SAMPLETYPE; + + #ifdef FLOAT_SAMPLES + // check that only one sample type is defined + #error "conflicting sample types defined" + #endif // FLOAT_SAMPLES + + #ifdef ALLOW_OPTIMIZATIONS + #if (_WIN32 || __i386__ || __x86_64__) + // Allow MMX optimizations + #define ALLOW_MMX 1 + #endif + #endif + + #else + + // floating point samples + typedef float SAMPLETYPE; + // data type for sample accumulation: Use double to utilize full precision. + typedef double LONG_SAMPLETYPE; + + #ifdef ALLOW_OPTIMIZATIONS + // Allow 3DNow! and SSE optimizations + #if _WIN32 + // #define ALLOW_3DNOW 1 + #endif + + #if (_WIN32 || __i386__ || __x86_64__) + #define ALLOW_SSE 1 + #endif + #endif + + #endif // INTEGER_SAMPLES +}; + #endif \ No newline at end of file diff --git a/3rdparty/SoundTouch/SoundTouch.cpp b/3rdparty/SoundTouch/SoundTouch.cpp index d20fd326ba..381c517162 100644 --- a/3rdparty/SoundTouch/SoundTouch.cpp +++ b/3rdparty/SoundTouch/SoundTouch.cpp @@ -1,474 +1,474 @@ -////////////////////////////////////////////////////////////////////////////// -/// -/// SoundTouch - main class for tempo/pitch/rate adjusting routines. -/// -/// Notes: -/// - Initialize the SoundTouch object instance by setting up the sound stream -/// parameters with functions 'setSampleRate' and 'setChannels', then set -/// desired tempo/pitch/rate settings with the corresponding functions. -/// -/// - The SoundTouch class behaves like a first-in-first-out pipeline: The -/// samples that are to be processed are fed into one of the pipe by calling -/// function 'putSamples', while the ready processed samples can be read -/// from the other end of the pipeline with function 'receiveSamples'. -/// -/// - The SoundTouch processing classes require certain sized 'batches' of -/// samples in order to process the sound. For this reason the classes buffer -/// incoming samples until there are enough of samples available for -/// processing, then they carry out the processing step and consequently -/// make the processed samples available for outputting. -/// -/// - For the above reason, the processing routines introduce a certain -/// 'latency' between the input and output, so that the samples input to -/// SoundTouch may not be immediately available in the output, and neither -/// the amount of outputtable samples may not immediately be in direct -/// relationship with the amount of previously input samples. -/// -/// - The tempo/pitch/rate control parameters can be altered during processing. -/// Please notice though that they aren't currently protected by semaphores, -/// so in multi-thread application external semaphore protection may be -/// required. -/// -/// - This class utilizes classes 'TDStretch' for tempo change (without modifying -/// pitch) and 'RateTransposer' for changing the playback rate (that is, both -/// tempo and pitch in the same ratio) of the sound. The third available control -/// 'pitch' (change pitch but maintain tempo) is produced by a combination of -/// combining the two other controls. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.13 $ -// -// $Id: SoundTouch.cpp,v 1.13 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include - -#include "SoundTouch.h" -#include "TDStretch.h" -#include "RateTransposer.h" -#include "cpu_detect.h" - -using namespace soundtouch; - -/// Print library version string -extern "C" void soundtouch_ac_test() -{ - printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION); -} - - -SoundTouch::SoundTouch() -{ - // Initialize rate transposer and tempo changer instances - - pRateTransposer = RateTransposer::newInstance(); - pTDStretch = TDStretch::newInstance(); - - setOutPipe(pTDStretch); - - rate = tempo = 0; - - virtualPitch = - virtualRate = - virtualTempo = 1.0; - - calcEffectiveRateAndTempo(); - - channels = 0; - bSrateSet = FALSE; -} - - - -SoundTouch::~SoundTouch() -{ - delete pRateTransposer; - delete pTDStretch; -} - - - -/// Get SoundTouch library version string -const char *SoundTouch::getVersionString() -{ - static const char *_version = SOUNDTOUCH_VERSION; - - return _version; -} - - -/// Get SoundTouch library version Id -uint SoundTouch::getVersionId() -{ - return SOUNDTOUCH_VERSION_ID; -} - - -// Sets the number of channels, 1 = mono, 2 = stereo -void SoundTouch::setChannels(uint numChannels) -{ - if (numChannels != 1 && numChannels != 2) - { - throw std::runtime_error("Illegal number of channels"); - } - channels = numChannels; - pRateTransposer->setChannels(numChannels); - pTDStretch->setChannels(numChannels); -} - - - -// Sets new rate control value. Normal rate = 1.0, smaller values -// represent slower rate, larger faster rates. -void SoundTouch::setRate(float newRate) -{ - virtualRate = newRate; - calcEffectiveRateAndTempo(); -} - - - -// Sets new rate control value as a difference in percents compared -// to the original rate (-50 .. +100 %) -void SoundTouch::setRateChange(float newRate) -{ - virtualRate = 1.0f + 0.01f * newRate; - calcEffectiveRateAndTempo(); -} - - - -// Sets new tempo control value. Normal tempo = 1.0, smaller values -// represent slower tempo, larger faster tempo. -void SoundTouch::setTempo(float newTempo) -{ - virtualTempo = newTempo; - calcEffectiveRateAndTempo(); -} - - - -// Sets new tempo control value as a difference in percents compared -// to the original tempo (-50 .. +100 %) -void SoundTouch::setTempoChange(float newTempo) -{ - virtualTempo = 1.0f + 0.01f * newTempo; - calcEffectiveRateAndTempo(); -} - - - -// Sets new pitch control value. Original pitch = 1.0, smaller values -// represent lower pitches, larger values higher pitch. -void SoundTouch::setPitch(float newPitch) -{ - virtualPitch = newPitch; - calcEffectiveRateAndTempo(); -} - - - -// Sets pitch change in octaves compared to the original pitch -// (-1.00 .. +1.00) -void SoundTouch::setPitchOctaves(float newPitch) -{ - virtualPitch = (float)exp(0.69314718056f * newPitch); - calcEffectiveRateAndTempo(); -} - - - -// Sets pitch change in semi-tones compared to the original pitch -// (-12 .. +12) -void SoundTouch::setPitchSemiTones(int newPitch) -{ - setPitchOctaves((float)newPitch / 12.0f); -} - - - -void SoundTouch::setPitchSemiTones(float newPitch) -{ - setPitchOctaves(newPitch / 12.0f); -} - - -// Calculates 'effective' rate and tempo values from the -// nominal control values. -void SoundTouch::calcEffectiveRateAndTempo() -{ - float oldTempo = tempo; - float oldRate = rate; - - tempo = virtualTempo / virtualPitch; - rate = virtualPitch * virtualRate; - - if (rate != oldRate) pRateTransposer->setRate(rate); - if (tempo != oldTempo) pTDStretch->setTempo(tempo); - - if (rate > 1.0f) - { - if (output != pRateTransposer) - { - FIFOSamplePipe *transOut; - - assert(output == pTDStretch); - // move samples in the current output buffer to the output of pRateTransposer - transOut = pRateTransposer->getOutput(); - transOut->moveSamples(*output); - // move samples in tempo changer's input to pitch transposer's input - pRateTransposer->moveSamples(*pTDStretch->getInput()); - - output = pRateTransposer; - } - } - else - { - if (output != pTDStretch) - { - FIFOSamplePipe *tempoOut; - - assert(output == pRateTransposer); - // move samples in the current output buffer to the output of pTDStretch - tempoOut = pTDStretch->getOutput(); - tempoOut->moveSamples(*output); - // move samples in pitch transposer's store buffer to tempo changer's input - pTDStretch->moveSamples(*pRateTransposer->getStore()); - - output = pTDStretch; - - } - } -} - - -// Sets sample rate. -void SoundTouch::setSampleRate(uint srate) -{ - bSrateSet = TRUE; - // set sample rate, leave other tempo changer parameters as they are. - pTDStretch->setParameters(srate); -} - - -// Adds 'numSamples' pcs of samples from the 'samples' memory position into -// the input of the object. -void SoundTouch::putSamples(const SAMPLETYPE *samples, uint numSamples) -{ - if (bSrateSet == FALSE) - { - throw std::runtime_error("SoundTouch : Sample rate not defined"); - } - else if (channels == 0) - { - throw std::runtime_error("SoundTouch : Number of channels not defined"); - } - - // Transpose the rate of the new samples if necessary - /* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value... - if (rate == 1.0f) - { - // The rate value is same as the original, simply evaluate the tempo changer. - assert(output == pTDStretch); - if (pRateTransposer->isEmpty() == 0) - { - // yet flush the last samples in the pitch transposer buffer - // (may happen if 'rate' changes from a non-zero value to zero) - pTDStretch->moveSamples(*pRateTransposer); - } - pTDStretch->putSamples(samples, numSamples); - } - */ - else if (rate <= 1.0f) - { - // transpose the rate down, output the transposed sound to tempo changer buffer - assert(output == pTDStretch); - pRateTransposer->putSamples(samples, numSamples); - pTDStretch->moveSamples(*pRateTransposer); - } - else - { - assert(rate > 1.0f); - // evaluate the tempo changer, then transpose the rate up, - assert(output == pRateTransposer); - pTDStretch->putSamples(samples, numSamples); - pRateTransposer->moveSamples(*pTDStretch); - } -} - - -// Flushes the last samples from the processing pipeline to the output. -// Clears also the internal processing buffers. -// -// Note: This function is meant for extracting the last samples of a sound -// stream. This function may introduce additional blank samples in the end -// of the sound stream, and thus it's not recommended to call this function -// in the middle of a sound stream. -void SoundTouch::flush() -{ - int i; - uint nOut; - SAMPLETYPE buff[128]; - - nOut = numSamples(); - - memset(buff, 0, 128 * sizeof(SAMPLETYPE)); - // "Push" the last active samples out from the processing pipeline by - // feeding blank samples into the processing pipeline until new, - // processed samples appear in the output (not however, more than - // 8ksamples in any case) - for (i = 0; i < 128; i ++) - { - putSamples(buff, 64); - if (numSamples() != nOut) break; // new samples have appeared in the output! - } - - // Clear working buffers - pRateTransposer->clear(); - pTDStretch->clearInput(); - // yet leave the 'tempoChanger' output intouched as that's where the - // flushed samples are! -} - - -// Changes a setting controlling the processing system behaviour. See the -// 'SETTING_...' defines for available setting ID's. -BOOL SoundTouch::setSetting(uint settingId, uint value) -{ - uint sampleRate, sequenceMs, seekWindowMs, overlapMs; - - // read current tdstretch routine parameters - pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs); - - switch (settingId) - { - case SETTING_USE_AA_FILTER : - // enables / disabless anti-alias filter - pRateTransposer->enableAAFilter((value != 0) ? TRUE : FALSE); - return TRUE; - - case SETTING_AA_FILTER_LENGTH : - // sets anti-alias filter length - pRateTransposer->getAAFilter()->setLength(value); - return TRUE; - - case SETTING_USE_QUICKSEEK : - // enables / disables tempo routine quick seeking algorithm - pTDStretch->enableQuickSeek((value != 0) ? TRUE : FALSE); - return TRUE; - - case SETTING_SEQUENCE_MS: - // change time-stretch sequence duration parameter - pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs); - return TRUE; - - case SETTING_SEEKWINDOW_MS: - // change time-stretch seek window length parameter - pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs); - return TRUE; - - case SETTING_OVERLAP_MS: - // change time-stretch overlap length parameter - pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value); - return TRUE; - - default : - return FALSE; - } -} - - -// Reads a setting controlling the processing system behaviour. See the -// 'SETTING_...' defines for available setting ID's. -// -// Returns the setting value. -uint SoundTouch::getSetting(uint settingId) const -{ - uint temp; - - switch (settingId) - { - case SETTING_USE_AA_FILTER : - return pRateTransposer->isAAFilterEnabled(); - - case SETTING_AA_FILTER_LENGTH : - return pRateTransposer->getAAFilter()->getLength(); - - case SETTING_USE_QUICKSEEK : - return pTDStretch->isQuickSeekEnabled(); - - case SETTING_SEQUENCE_MS: - pTDStretch->getParameters(NULL, &temp, NULL, NULL); - return temp; - - case SETTING_SEEKWINDOW_MS: - pTDStretch->getParameters(NULL, NULL, &temp, NULL); - return temp; - - case SETTING_OVERLAP_MS: - pTDStretch->getParameters(NULL, NULL, NULL, &temp); - return temp; - - default : - return 0; - } -} - - -// Clears all the samples in the object's output and internal processing -// buffers. -void SoundTouch::clear() -{ - pRateTransposer->clear(); - pTDStretch->clear(); -} - - - -/// Returns number of samples currently unprocessed. -uint SoundTouch::numUnprocessedSamples() const -{ - FIFOSamplePipe * psp; - if (pTDStretch) - { - psp = pTDStretch->getInput(); - if (psp) - { - return psp->numSamples(); - } - } - return 0; -} +////////////////////////////////////////////////////////////////////////////// +/// +/// SoundTouch - main class for tempo/pitch/rate adjusting routines. +/// +/// Notes: +/// - Initialize the SoundTouch object instance by setting up the sound stream +/// parameters with functions 'setSampleRate' and 'setChannels', then set +/// desired tempo/pitch/rate settings with the corresponding functions. +/// +/// - The SoundTouch class behaves like a first-in-first-out pipeline: The +/// samples that are to be processed are fed into one of the pipe by calling +/// function 'putSamples', while the ready processed samples can be read +/// from the other end of the pipeline with function 'receiveSamples'. +/// +/// - The SoundTouch processing classes require certain sized 'batches' of +/// samples in order to process the sound. For this reason the classes buffer +/// incoming samples until there are enough of samples available for +/// processing, then they carry out the processing step and consequently +/// make the processed samples available for outputting. +/// +/// - For the above reason, the processing routines introduce a certain +/// 'latency' between the input and output, so that the samples input to +/// SoundTouch may not be immediately available in the output, and neither +/// the amount of outputtable samples may not immediately be in direct +/// relationship with the amount of previously input samples. +/// +/// - The tempo/pitch/rate control parameters can be altered during processing. +/// Please notice though that they aren't currently protected by semaphores, +/// so in multi-thread application external semaphore protection may be +/// required. +/// +/// - This class utilizes classes 'TDStretch' for tempo change (without modifying +/// pitch) and 'RateTransposer' for changing the playback rate (that is, both +/// tempo and pitch in the same ratio) of the sound. The third available control +/// 'pitch' (change pitch but maintain tempo) is produced by a combination of +/// combining the two other controls. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.13 $ +// +// $Id: SoundTouch.cpp,v 1.13 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include "SoundTouch.h" +#include "TDStretch.h" +#include "RateTransposer.h" +#include "cpu_detect.h" + +using namespace soundtouch; + +/// Print library version string +extern "C" void soundtouch_ac_test() +{ + printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION); +} + + +SoundTouch::SoundTouch() +{ + // Initialize rate transposer and tempo changer instances + + pRateTransposer = RateTransposer::newInstance(); + pTDStretch = TDStretch::newInstance(); + + setOutPipe(pTDStretch); + + rate = tempo = 0; + + virtualPitch = + virtualRate = + virtualTempo = 1.0; + + calcEffectiveRateAndTempo(); + + channels = 0; + bSrateSet = FALSE; +} + + + +SoundTouch::~SoundTouch() +{ + delete pRateTransposer; + delete pTDStretch; +} + + + +/// Get SoundTouch library version string +const char *SoundTouch::getVersionString() +{ + static const char *_version = SOUNDTOUCH_VERSION; + + return _version; +} + + +/// Get SoundTouch library version Id +uint SoundTouch::getVersionId() +{ + return SOUNDTOUCH_VERSION_ID; +} + + +// Sets the number of channels, 1 = mono, 2 = stereo +void SoundTouch::setChannels(uint numChannels) +{ + if (numChannels != 1 && numChannels != 2) + { + throw std::runtime_error("Illegal number of channels"); + } + channels = numChannels; + pRateTransposer->setChannels(numChannels); + pTDStretch->setChannels(numChannels); +} + + + +// Sets new rate control value. Normal rate = 1.0, smaller values +// represent slower rate, larger faster rates. +void SoundTouch::setRate(float newRate) +{ + virtualRate = newRate; + calcEffectiveRateAndTempo(); +} + + + +// Sets new rate control value as a difference in percents compared +// to the original rate (-50 .. +100 %) +void SoundTouch::setRateChange(float newRate) +{ + virtualRate = 1.0f + 0.01f * newRate; + calcEffectiveRateAndTempo(); +} + + + +// Sets new tempo control value. Normal tempo = 1.0, smaller values +// represent slower tempo, larger faster tempo. +void SoundTouch::setTempo(float newTempo) +{ + virtualTempo = newTempo; + calcEffectiveRateAndTempo(); +} + + + +// Sets new tempo control value as a difference in percents compared +// to the original tempo (-50 .. +100 %) +void SoundTouch::setTempoChange(float newTempo) +{ + virtualTempo = 1.0f + 0.01f * newTempo; + calcEffectiveRateAndTempo(); +} + + + +// Sets new pitch control value. Original pitch = 1.0, smaller values +// represent lower pitches, larger values higher pitch. +void SoundTouch::setPitch(float newPitch) +{ + virtualPitch = newPitch; + calcEffectiveRateAndTempo(); +} + + + +// Sets pitch change in octaves compared to the original pitch +// (-1.00 .. +1.00) +void SoundTouch::setPitchOctaves(float newPitch) +{ + virtualPitch = (float)exp(0.69314718056f * newPitch); + calcEffectiveRateAndTempo(); +} + + + +// Sets pitch change in semi-tones compared to the original pitch +// (-12 .. +12) +void SoundTouch::setPitchSemiTones(int newPitch) +{ + setPitchOctaves((float)newPitch / 12.0f); +} + + + +void SoundTouch::setPitchSemiTones(float newPitch) +{ + setPitchOctaves(newPitch / 12.0f); +} + + +// Calculates 'effective' rate and tempo values from the +// nominal control values. +void SoundTouch::calcEffectiveRateAndTempo() +{ + float oldTempo = tempo; + float oldRate = rate; + + tempo = virtualTempo / virtualPitch; + rate = virtualPitch * virtualRate; + + if (rate != oldRate) pRateTransposer->setRate(rate); + if (tempo != oldTempo) pTDStretch->setTempo(tempo); + + if (rate > 1.0f) + { + if (output != pRateTransposer) + { + FIFOSamplePipe *transOut; + + assert(output == pTDStretch); + // move samples in the current output buffer to the output of pRateTransposer + transOut = pRateTransposer->getOutput(); + transOut->moveSamples(*output); + // move samples in tempo changer's input to pitch transposer's input + pRateTransposer->moveSamples(*pTDStretch->getInput()); + + output = pRateTransposer; + } + } + else + { + if (output != pTDStretch) + { + FIFOSamplePipe *tempoOut; + + assert(output == pRateTransposer); + // move samples in the current output buffer to the output of pTDStretch + tempoOut = pTDStretch->getOutput(); + tempoOut->moveSamples(*output); + // move samples in pitch transposer's store buffer to tempo changer's input + pTDStretch->moveSamples(*pRateTransposer->getStore()); + + output = pTDStretch; + + } + } +} + + +// Sets sample rate. +void SoundTouch::setSampleRate(uint srate) +{ + bSrateSet = TRUE; + // set sample rate, leave other tempo changer parameters as they are. + pTDStretch->setParameters(srate); +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void SoundTouch::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + if (bSrateSet == FALSE) + { + throw std::runtime_error("SoundTouch : Sample rate not defined"); + } + else if (channels == 0) + { + throw std::runtime_error("SoundTouch : Number of channels not defined"); + } + + // Transpose the rate of the new samples if necessary + /* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value... + if (rate == 1.0f) + { + // The rate value is same as the original, simply evaluate the tempo changer. + assert(output == pTDStretch); + if (pRateTransposer->isEmpty() == 0) + { + // yet flush the last samples in the pitch transposer buffer + // (may happen if 'rate' changes from a non-zero value to zero) + pTDStretch->moveSamples(*pRateTransposer); + } + pTDStretch->putSamples(samples, numSamples); + } + */ + else if (rate <= 1.0f) + { + // transpose the rate down, output the transposed sound to tempo changer buffer + assert(output == pTDStretch); + pRateTransposer->putSamples(samples, numSamples); + pTDStretch->moveSamples(*pRateTransposer); + } + else + { + assert(rate > 1.0f); + // evaluate the tempo changer, then transpose the rate up, + assert(output == pRateTransposer); + pTDStretch->putSamples(samples, numSamples); + pRateTransposer->moveSamples(*pTDStretch); + } +} + + +// Flushes the last samples from the processing pipeline to the output. +// Clears also the internal processing buffers. +// +// Note: This function is meant for extracting the last samples of a sound +// stream. This function may introduce additional blank samples in the end +// of the sound stream, and thus it's not recommended to call this function +// in the middle of a sound stream. +void SoundTouch::flush() +{ + int i; + uint nOut; + SAMPLETYPE buff[128]; + + nOut = numSamples(); + + memset(buff, 0, 128 * sizeof(SAMPLETYPE)); + // "Push" the last active samples out from the processing pipeline by + // feeding blank samples into the processing pipeline until new, + // processed samples appear in the output (not however, more than + // 8ksamples in any case) + for (i = 0; i < 128; i ++) + { + putSamples(buff, 64); + if (numSamples() != nOut) break; // new samples have appeared in the output! + } + + // Clear working buffers + pRateTransposer->clear(); + pTDStretch->clearInput(); + // yet leave the 'tempoChanger' output intouched as that's where the + // flushed samples are! +} + + +// Changes a setting controlling the processing system behaviour. See the +// 'SETTING_...' defines for available setting ID's. +BOOL SoundTouch::setSetting(uint settingId, uint value) +{ + uint sampleRate, sequenceMs, seekWindowMs, overlapMs; + + // read current tdstretch routine parameters + pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs); + + switch (settingId) + { + case SETTING_USE_AA_FILTER : + // enables / disabless anti-alias filter + pRateTransposer->enableAAFilter((value != 0) ? TRUE : FALSE); + return TRUE; + + case SETTING_AA_FILTER_LENGTH : + // sets anti-alias filter length + pRateTransposer->getAAFilter()->setLength(value); + return TRUE; + + case SETTING_USE_QUICKSEEK : + // enables / disables tempo routine quick seeking algorithm + pTDStretch->enableQuickSeek((value != 0) ? TRUE : FALSE); + return TRUE; + + case SETTING_SEQUENCE_MS: + // change time-stretch sequence duration parameter + pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs); + return TRUE; + + case SETTING_SEEKWINDOW_MS: + // change time-stretch seek window length parameter + pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs); + return TRUE; + + case SETTING_OVERLAP_MS: + // change time-stretch overlap length parameter + pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value); + return TRUE; + + default : + return FALSE; + } +} + + +// Reads a setting controlling the processing system behaviour. See the +// 'SETTING_...' defines for available setting ID's. +// +// Returns the setting value. +uint SoundTouch::getSetting(uint settingId) const +{ + uint temp; + + switch (settingId) + { + case SETTING_USE_AA_FILTER : + return pRateTransposer->isAAFilterEnabled(); + + case SETTING_AA_FILTER_LENGTH : + return pRateTransposer->getAAFilter()->getLength(); + + case SETTING_USE_QUICKSEEK : + return pTDStretch->isQuickSeekEnabled(); + + case SETTING_SEQUENCE_MS: + pTDStretch->getParameters(NULL, &temp, NULL, NULL); + return temp; + + case SETTING_SEEKWINDOW_MS: + pTDStretch->getParameters(NULL, NULL, &temp, NULL); + return temp; + + case SETTING_OVERLAP_MS: + pTDStretch->getParameters(NULL, NULL, NULL, &temp); + return temp; + + default : + return 0; + } +} + + +// Clears all the samples in the object's output and internal processing +// buffers. +void SoundTouch::clear() +{ + pRateTransposer->clear(); + pTDStretch->clear(); +} + + + +/// Returns number of samples currently unprocessed. +uint SoundTouch::numUnprocessedSamples() const +{ + FIFOSamplePipe * psp; + if (pTDStretch) + { + psp = pTDStretch->getInput(); + if (psp) + { + return psp->numSamples(); + } + } + return 0; +} diff --git a/3rdparty/SoundTouch/SoundTouch.h b/3rdparty/SoundTouch/SoundTouch.h index fab3bb9845..9f3a152f26 100644 --- a/3rdparty/SoundTouch/SoundTouch.h +++ b/3rdparty/SoundTouch/SoundTouch.h @@ -1,252 +1,252 @@ -////////////////////////////////////////////////////////////////////////////// -/// -/// SoundTouch - main class for tempo/pitch/rate adjusting routines. -/// -/// Notes: -/// - Initialize the SoundTouch object instance by setting up the sound stream -/// parameters with functions 'setSampleRate' and 'setChannels', then set -/// desired tempo/pitch/rate settings with the corresponding functions. -/// -/// - The SoundTouch class behaves like a first-in-first-out pipeline: The -/// samples that are to be processed are fed into one of the pipe by calling -/// function 'putSamples', while the ready processed samples can be read -/// from the other end of the pipeline with function 'receiveSamples'. -/// -/// - The SoundTouch processing classes require certain sized 'batches' of -/// samples in order to process the sound. For this reason the classes buffer -/// incoming samples until there are enough of samples available for -/// processing, then they carry out the processing step and consequently -/// make the processed samples available for outputting. -/// -/// - For the above reason, the processing routines introduce a certain -/// 'latency' between the input and output, so that the samples input to -/// SoundTouch may not be immediately available in the output, and neither -/// the amount of outputtable samples may not immediately be in direct -/// relationship with the amount of previously input samples. -/// -/// - The tempo/pitch/rate control parameters can be altered during processing. -/// Please notice though that they aren't currently protected by semaphores, -/// so in multi-thread application external semaphore protection may be -/// required. -/// -/// - This class utilizes classes 'TDStretch' for tempo change (without modifying -/// pitch) and 'RateTransposer' for changing the playback rate (that is, both -/// tempo and pitch in the same ratio) of the sound. The third available control -/// 'pitch' (change pitch but maintain tempo) is produced by a combination of -/// combining the two other controls. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.14 $ -// -// $Id: SoundTouch.h,v 1.14 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef SoundTouch_H -#define SoundTouch_H - -#include "FIFOSamplePipe.h" -#include "STTypes.h" - -namespace soundtouch -{ - -/// Soundtouch library version string -#define SOUNDTOUCH_VERSION "1.3.1" - -/// SoundTouch library version id -#define SOUNDTOUCH_VERSION_ID 010301 - -// -// Available setting IDs for the 'setSetting' & 'get_setting' functions: - -/// Enable/disable anti-alias filter in pitch transposer (0 = disable) -#define SETTING_USE_AA_FILTER 0 - -/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32) -#define SETTING_AA_FILTER_LENGTH 1 - -/// Enable/disable quick seeking algorithm in tempo changer routine -/// (enabling quick seeking lowers CPU utilization but causes a minor sound -/// quality compromising) -#define SETTING_USE_QUICKSEEK 2 - -/// Time-stretch algorithm single processing sequence length in milliseconds. This determines -/// to how long sequences the original sound is chopped in the time-stretch algorithm. -/// See "STTypes.h" or README for more information. -#define SETTING_SEQUENCE_MS 3 - -/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the -/// best possible overlapping location. This determines from how wide window the algorithm -/// may look for an optimal joining location when mixing the sound sequences back together. -/// See "STTypes.h" or README for more information. -#define SETTING_SEEKWINDOW_MS 4 - -/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences -/// are mixed back together, to form a continuous sound stream, this parameter defines over -/// how long period the two consecutive sequences are let to overlap each other. -/// See "STTypes.h" or README for more information. -#define SETTING_OVERLAP_MS 5 - - -class SoundTouch : public FIFOProcessor -{ -private: - /// Rate transposer class instance - class RateTransposer *pRateTransposer; - - /// Time-stretch class instance - class TDStretch *pTDStretch; - - /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. - float virtualRate; - - /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. - float virtualTempo; - - /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. - float virtualPitch; - - /// Flag: Has sample rate been set? - BOOL bSrateSet; - - /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and - /// 'virtualPitch' parameters. - void calcEffectiveRateAndTempo(); - -protected : - /// Number of channels - uint channels; - - /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' - float rate; - - /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' - float tempo; - -public: - SoundTouch(); - virtual ~SoundTouch(); - - /// Get SoundTouch library version string - static const char *getVersionString(); - - /// Get SoundTouch library version Id - static uint getVersionId(); - - /// Sets new rate control value. Normal rate = 1.0, smaller values - /// represent slower rate, larger faster rates. - void setRate(float newRate); - - /// Sets new tempo control value. Normal tempo = 1.0, smaller values - /// represent slower tempo, larger faster tempo. - void setTempo(float newTempo); - - /// Sets new rate control value as a difference in percents compared - /// to the original rate (-50 .. +100 %) - void setRateChange(float newRate); - - /// Sets new tempo control value as a difference in percents compared - /// to the original tempo (-50 .. +100 %) - void setTempoChange(float newTempo); - - /// Sets new pitch control value. Original pitch = 1.0, smaller values - /// represent lower pitches, larger values higher pitch. - void setPitch(float newPitch); - - /// Sets pitch change in octaves compared to the original pitch - /// (-1.00 .. +1.00) - void setPitchOctaves(float newPitch); - - /// Sets pitch change in semi-tones compared to the original pitch - /// (-12 .. +12) - void setPitchSemiTones(int newPitch); - void setPitchSemiTones(float newPitch); - - /// Sets the number of channels, 1 = mono, 2 = stereo - void setChannels(uint numChannels); - - /// Sets sample rate. - void setSampleRate(uint srate); - - /// Flushes the last samples from the processing pipeline to the output. - /// Clears also the internal processing buffers. - // - /// Note: This function is meant for extracting the last samples of a sound - /// stream. This function may introduce additional blank samples in the end - /// of the sound stream, and thus it's not recommended to call this function - /// in the middle of a sound stream. - void flush(); - - /// Adds 'numSamples' pcs of samples from the 'samples' memory position into - /// the input of the object. Notice that sample rate _has_to_ be set before - /// calling this function, otherwise throws a runtime_error exception. - virtual void putSamples( - const SAMPLETYPE *samples, ///< Pointer to sample buffer. - uint numSamples ///< Number of samples in buffer. Notice - ///< that in case of stereo-sound a single sample - ///< contains data for both channels. - ); - - /// Clears all the samples in the object's output and internal processing - /// buffers. - virtual void clear(); - - /// Changes a setting controlling the processing system behaviour. See the - /// 'SETTING_...' defines for available setting ID's. - /// - /// \return 'TRUE' if the setting was succesfully changed - BOOL setSetting(uint settingId, ///< Setting ID number. see SETTING_... defines. - uint value ///< New setting value. - ); - - /// Reads a setting controlling the processing system behaviour. See the - /// 'SETTING_...' defines for available setting ID's. - /// - /// \return the setting value. - uint getSetting(uint settingId ///< Setting ID number, see SETTING_... defines. - ) const; - - /// Returns number of samples currently unprocessed. - virtual uint numUnprocessedSamples() const; - - - /// Other handy functions that are implemented in the ancestor classes (see - /// classes 'FIFOProcessor' and 'FIFOSamplePipe') - /// - /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch. - /// - numSamples() : Get number of 'ready' samples that can be received with - /// function 'receiveSamples()' - /// - isEmpty() : Returns nonzero if there aren't any 'ready' samples. - /// - clear() : Clears all samples from ready/processing buffers. -}; - -} -#endif +////////////////////////////////////////////////////////////////////////////// +/// +/// SoundTouch - main class for tempo/pitch/rate adjusting routines. +/// +/// Notes: +/// - Initialize the SoundTouch object instance by setting up the sound stream +/// parameters with functions 'setSampleRate' and 'setChannels', then set +/// desired tempo/pitch/rate settings with the corresponding functions. +/// +/// - The SoundTouch class behaves like a first-in-first-out pipeline: The +/// samples that are to be processed are fed into one of the pipe by calling +/// function 'putSamples', while the ready processed samples can be read +/// from the other end of the pipeline with function 'receiveSamples'. +/// +/// - The SoundTouch processing classes require certain sized 'batches' of +/// samples in order to process the sound. For this reason the classes buffer +/// incoming samples until there are enough of samples available for +/// processing, then they carry out the processing step and consequently +/// make the processed samples available for outputting. +/// +/// - For the above reason, the processing routines introduce a certain +/// 'latency' between the input and output, so that the samples input to +/// SoundTouch may not be immediately available in the output, and neither +/// the amount of outputtable samples may not immediately be in direct +/// relationship with the amount of previously input samples. +/// +/// - The tempo/pitch/rate control parameters can be altered during processing. +/// Please notice though that they aren't currently protected by semaphores, +/// so in multi-thread application external semaphore protection may be +/// required. +/// +/// - This class utilizes classes 'TDStretch' for tempo change (without modifying +/// pitch) and 'RateTransposer' for changing the playback rate (that is, both +/// tempo and pitch in the same ratio) of the sound. The third available control +/// 'pitch' (change pitch but maintain tempo) is produced by a combination of +/// combining the two other controls. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.14 $ +// +// $Id: SoundTouch.h,v 1.14 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef SoundTouch_H +#define SoundTouch_H + +#include "FIFOSamplePipe.h" +#include "STTypes.h" + +namespace soundtouch +{ + +/// Soundtouch library version string +#define SOUNDTOUCH_VERSION "1.3.1" + +/// SoundTouch library version id +#define SOUNDTOUCH_VERSION_ID 010301 + +// +// Available setting IDs for the 'setSetting' & 'get_setting' functions: + +/// Enable/disable anti-alias filter in pitch transposer (0 = disable) +#define SETTING_USE_AA_FILTER 0 + +/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32) +#define SETTING_AA_FILTER_LENGTH 1 + +/// Enable/disable quick seeking algorithm in tempo changer routine +/// (enabling quick seeking lowers CPU utilization but causes a minor sound +/// quality compromising) +#define SETTING_USE_QUICKSEEK 2 + +/// Time-stretch algorithm single processing sequence length in milliseconds. This determines +/// to how long sequences the original sound is chopped in the time-stretch algorithm. +/// See "STTypes.h" or README for more information. +#define SETTING_SEQUENCE_MS 3 + +/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the +/// best possible overlapping location. This determines from how wide window the algorithm +/// may look for an optimal joining location when mixing the sound sequences back together. +/// See "STTypes.h" or README for more information. +#define SETTING_SEEKWINDOW_MS 4 + +/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences +/// are mixed back together, to form a continuous sound stream, this parameter defines over +/// how long period the two consecutive sequences are let to overlap each other. +/// See "STTypes.h" or README for more information. +#define SETTING_OVERLAP_MS 5 + + +class SoundTouch : public FIFOProcessor +{ +private: + /// Rate transposer class instance + class RateTransposer *pRateTransposer; + + /// Time-stretch class instance + class TDStretch *pTDStretch; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualRate; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualTempo; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualPitch; + + /// Flag: Has sample rate been set? + BOOL bSrateSet; + + /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and + /// 'virtualPitch' parameters. + void calcEffectiveRateAndTempo(); + +protected : + /// Number of channels + uint channels; + + /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' + float rate; + + /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' + float tempo; + +public: + SoundTouch(); + virtual ~SoundTouch(); + + /// Get SoundTouch library version string + static const char *getVersionString(); + + /// Get SoundTouch library version Id + static uint getVersionId(); + + /// Sets new rate control value. Normal rate = 1.0, smaller values + /// represent slower rate, larger faster rates. + void setRate(float newRate); + + /// Sets new tempo control value. Normal tempo = 1.0, smaller values + /// represent slower tempo, larger faster tempo. + void setTempo(float newTempo); + + /// Sets new rate control value as a difference in percents compared + /// to the original rate (-50 .. +100 %) + void setRateChange(float newRate); + + /// Sets new tempo control value as a difference in percents compared + /// to the original tempo (-50 .. +100 %) + void setTempoChange(float newTempo); + + /// Sets new pitch control value. Original pitch = 1.0, smaller values + /// represent lower pitches, larger values higher pitch. + void setPitch(float newPitch); + + /// Sets pitch change in octaves compared to the original pitch + /// (-1.00 .. +1.00) + void setPitchOctaves(float newPitch); + + /// Sets pitch change in semi-tones compared to the original pitch + /// (-12 .. +12) + void setPitchSemiTones(int newPitch); + void setPitchSemiTones(float newPitch); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint numChannels); + + /// Sets sample rate. + void setSampleRate(uint srate); + + /// Flushes the last samples from the processing pipeline to the output. + /// Clears also the internal processing buffers. + // + /// Note: This function is meant for extracting the last samples of a sound + /// stream. This function may introduce additional blank samples in the end + /// of the sound stream, and thus it's not recommended to call this function + /// in the middle of a sound stream. + void flush(); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position into + /// the input of the object. Notice that sample rate _has_to_ be set before + /// calling this function, otherwise throws a runtime_error exception. + virtual void putSamples( + const SAMPLETYPE *samples, ///< Pointer to sample buffer. + uint numSamples ///< Number of samples in buffer. Notice + ///< that in case of stereo-sound a single sample + ///< contains data for both channels. + ); + + /// Clears all the samples in the object's output and internal processing + /// buffers. + virtual void clear(); + + /// Changes a setting controlling the processing system behaviour. See the + /// 'SETTING_...' defines for available setting ID's. + /// + /// \return 'TRUE' if the setting was succesfully changed + BOOL setSetting(uint settingId, ///< Setting ID number. see SETTING_... defines. + uint value ///< New setting value. + ); + + /// Reads a setting controlling the processing system behaviour. See the + /// 'SETTING_...' defines for available setting ID's. + /// + /// \return the setting value. + uint getSetting(uint settingId ///< Setting ID number, see SETTING_... defines. + ) const; + + /// Returns number of samples currently unprocessed. + virtual uint numUnprocessedSamples() const; + + + /// Other handy functions that are implemented in the ancestor classes (see + /// classes 'FIFOProcessor' and 'FIFOSamplePipe') + /// + /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch. + /// - numSamples() : Get number of 'ready' samples that can be received with + /// function 'receiveSamples()' + /// - isEmpty() : Returns nonzero if there aren't any 'ready' samples. + /// - clear() : Clears all samples from ready/processing buffers. +}; + +} +#endif diff --git a/3rdparty/SoundTouch/TDStretch.cpp b/3rdparty/SoundTouch/TDStretch.cpp index d809623689..339c7378fb 100644 --- a/3rdparty/SoundTouch/TDStretch.cpp +++ b/3rdparty/SoundTouch/TDStretch.cpp @@ -1,940 +1,940 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo -/// while maintaining the original pitch by using a time domain WSOLA-like -/// method with several performance-increasing tweaks. -/// -/// Note : MMX optimized functions reside in a separate, platform-specific -/// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.24 $ -// -// $Id: TDStretch.cpp,v 1.24 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include - -#include "STTypes.h" -#include "cpu_detect.h" -#include "TDStretch.h" - -using namespace soundtouch; - -#ifndef min -#define min(a,b) ((a > b) ? b : a) -#define max(a,b) ((a < b) ? b : a) -#endif - - - -/***************************************************************************** - * - * Constant definitions - * - *****************************************************************************/ - - -// Table for the hierarchical mixing position seeking algorithm -int scanOffsets[4][24]={ - { 124, 186, 248, 310, 372, 434, 496, 558, 620, 682, 744, 806, - 868, 930, 992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488, 0}, - {-100, -75, -50, -25, 25, 50, 75, 100, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { -20, -15, -10, -5, 5, 10, 15, 20, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { -4, -3, -2, -1, 1, 2, 3, 4, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; - -/***************************************************************************** - * - * Implementation of the class 'TDStretch' - * - *****************************************************************************/ - - -TDStretch::TDStretch() : FIFOProcessor(&outputBuffer) -{ - bQuickseek = FALSE; - channels = 2; - bMidBufferDirty = FALSE; - - pMidBuffer = NULL; - pRefMidBufferUnaligned = NULL; - overlapLength = 0; - - setParameters(48000, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS); - - setTempo(1.0f); -} - - - - -TDStretch::~TDStretch() -{ - delete[] pMidBuffer; - delete[] pRefMidBufferUnaligned; -} - - - -// Calculates the x having the closest 2^x value for the given value -static int _getClosest2Power(double value) -{ - return (int)(log(value) / log(2.0) + 0.5); -} - - - -// Sets routine control parameters. These control are certain time constants -// defining how the sound is stretched to the desired duration. -// -// 'sampleRate' = sample rate of the sound -// 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms) -// 'seekwindowMS' = seeking window length for scanning the best overlapping -// position (default = 28 ms) -// 'overlapMS' = overlapping length (default = 12 ms) - -void TDStretch::setParameters(uint aSampleRate, uint aSequenceMS, - uint aSeekWindowMS, uint aOverlapMS) -{ - this->sampleRate = aSampleRate; - this->sequenceMs = aSequenceMS; - this->seekWindowMs = aSeekWindowMS; - this->overlapMs = aOverlapMS; - - seekLength = (sampleRate * seekWindowMs) / 1000; - seekWindowLength = (sampleRate * sequenceMs) / 1000; - - maxOffset = seekLength; - - calculateOverlapLength(overlapMs); - - // set tempo to recalculate 'sampleReq' - setTempo(tempo); - -} - - - -/// Get routine control parameters, see setParameters() function. -/// Any of the parameters to this function can be NULL, in such case corresponding parameter -/// value isn't returned. -void TDStretch::getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs) -{ - if (pSampleRate) - { - *pSampleRate = sampleRate; - } - - if (pSequenceMs) - { - *pSequenceMs = sequenceMs; - } - - if (pSeekWindowMs) - { - *pSeekWindowMs = seekWindowMs; - } - - if (pOverlapMs) - { - *pOverlapMs = overlapMs; - } -} - - -// Overlaps samples in 'midBuffer' with the samples in 'input' -void TDStretch::overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const -{ - int i, itemp; - - for (i = 0; i < (int)overlapLength ; i ++) - { - itemp = overlapLength - i; - output[i] = (input[i] * i + pMidBuffer[i] * itemp ) / overlapLength; // >> overlapDividerBits; - } -} - - - -void TDStretch::clearMidBuffer() -{ - if (bMidBufferDirty) - { - memset(pMidBuffer, 0, 2 * sizeof(SAMPLETYPE) * overlapLength); - bMidBufferDirty = FALSE; - } -} - - -void TDStretch::clearInput() -{ - inputBuffer.clear(); - clearMidBuffer(); -} - - -// Clears the sample buffers -void TDStretch::clear() -{ - outputBuffer.clear(); - inputBuffer.clear(); - clearMidBuffer(); -} - - - -// Enables/disables the quick position seeking algorithm. Zero to disable, nonzero -// to enable -void TDStretch::enableQuickSeek(BOOL enable) -{ - bQuickseek = enable; -} - - -// Returns nonzero if the quick seeking algorithm is enabled. -BOOL TDStretch::isQuickSeekEnabled() const -{ - return bQuickseek; -} - - -// Seeks for the optimal overlap-mixing position. -uint TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos) -{ - if (channels == 2) - { - // stereo sound - if (bQuickseek) - { - return seekBestOverlapPositionStereoQuick(refPos); - } - else - { - return seekBestOverlapPositionStereo(refPos); - } - } - else - { - // mono sound - if (bQuickseek) - { - return seekBestOverlapPositionMonoQuick(refPos); - } - else - { - return seekBestOverlapPositionMono(refPos); - } - } -} - - - - -// Overlaps samples in 'midBuffer' with the samples in 'inputBuffer' at position -// of 'ovlPos'. -inline void TDStretch::overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const -{ - if (channels == 2) - { - // stereo sound - overlapStereo(output, input + 2 * ovlPos); - } else { - // mono sound. - overlapMono(output, input + ovlPos); - } -} - - - - -// Seeks for the optimal overlap-mixing position. The 'stereo' version of the -// routine -// -// The best position is determined as the position where the two overlapped -// sample sequences are 'most alike', in terms of the highest cross-correlation -// value over the overlapping period -uint TDStretch::seekBestOverlapPositionStereo(const SAMPLETYPE *refPos) -{ - uint bestOffs; - LONG_SAMPLETYPE bestCorr, corr; - uint i; - - // Slopes the amplitudes of the 'midBuffer' samples - precalcCorrReferenceStereo(); - - bestCorr = INT_MIN; - bestOffs = 0; - - // Scans for the best correlation value by testing each possible position - // over the permitted range. - for (i = 0; i < seekLength; i ++) - { - // Calculates correlation value for the mixing position corresponding - // to 'i' - corr = calcCrossCorrStereo(refPos + 2 * i, pRefMidBuffer); - - // Checks for the highest correlation value - if (corr > bestCorr) - { - bestCorr = corr; - bestOffs = i; - } - } - // clear cross correlation routine state if necessary (is so e.g. in MMX routines). - clearCrossCorrState(); - - return bestOffs; -} - - -// Seeks for the optimal overlap-mixing position. The 'stereo' version of the -// routine -// -// The best position is determined as the position where the two overlapped -// sample sequences are 'most alike', in terms of the highest cross-correlation -// value over the overlapping period -uint TDStretch::seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos) -{ - uint j; - uint bestOffs; - LONG_SAMPLETYPE bestCorr, corr; - uint scanCount, corrOffset, tempOffset; - - // Slopes the amplitude of the 'midBuffer' samples - precalcCorrReferenceStereo(); - - bestCorr = INT_MIN; - bestOffs = 0; - corrOffset = 0; - tempOffset = 0; - - // Scans for the best correlation value using four-pass hierarchical search. - // - // The look-up table 'scans' has hierarchical position adjusting steps. - // In first pass the routine searhes for the highest correlation with - // relatively coarse steps, then rescans the neighbourhood of the highest - // correlation with better resolution and so on. - for (scanCount = 0;scanCount < 4; scanCount ++) - { - j = 0; - while (scanOffsets[scanCount][j]) - { - tempOffset = corrOffset + scanOffsets[scanCount][j]; - if (tempOffset >= seekLength) break; - - // Calculates correlation value for the mixing position corresponding - // to 'tempOffset' - corr = calcCrossCorrStereo(refPos + 2 * tempOffset, pRefMidBuffer); - - // Checks for the highest correlation value - if (corr > bestCorr) - { - bestCorr = corr; - bestOffs = tempOffset; - } - j ++; - } - corrOffset = bestOffs; - } - // clear cross correlation routine state if necessary (is so e.g. in MMX routines). - clearCrossCorrState(); - - return bestOffs; -} - - - -// Seeks for the optimal overlap-mixing position. The 'mono' version of the -// routine -// -// The best position is determined as the position where the two overlapped -// sample sequences are 'most alike', in terms of the highest cross-correlation -// value over the overlapping period -uint TDStretch::seekBestOverlapPositionMono(const SAMPLETYPE *refPos) -{ - uint bestOffs; - LONG_SAMPLETYPE bestCorr, corr; - uint tempOffset; - const SAMPLETYPE *compare; - - // Slopes the amplitude of the 'midBuffer' samples - precalcCorrReferenceMono(); - - bestCorr = INT_MIN; - bestOffs = 0; - - // Scans for the best correlation value by testing each possible position - // over the permitted range. - for (tempOffset = 0; tempOffset < seekLength; tempOffset ++) - { - compare = refPos + tempOffset; - - // Calculates correlation value for the mixing position corresponding - // to 'tempOffset' - corr = calcCrossCorrMono(pRefMidBuffer, compare); - - // Checks for the highest correlation value - if (corr > bestCorr) - { - bestCorr = corr; - bestOffs = tempOffset; - } - } - // clear cross correlation routine state if necessary (is so e.g. in MMX routines). - clearCrossCorrState(); - - return bestOffs; -} - - -// Seeks for the optimal overlap-mixing position. The 'mono' version of the -// routine -// -// The best position is determined as the position where the two overlapped -// sample sequences are 'most alike', in terms of the highest cross-correlation -// value over the overlapping period -uint TDStretch::seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos) -{ - uint j; - uint bestOffs; - LONG_SAMPLETYPE bestCorr, corr; - uint scanCount, corrOffset, tempOffset; - - // Slopes the amplitude of the 'midBuffer' samples - precalcCorrReferenceMono(); - - bestCorr = INT_MIN; - bestOffs = 0; - corrOffset = 0; - tempOffset = 0; - - // Scans for the best correlation value using four-pass hierarchical search. - // - // The look-up table 'scans' has hierarchical position adjusting steps. - // In first pass the routine searhes for the highest correlation with - // relatively coarse steps, then rescans the neighbourhood of the highest - // correlation with better resolution and so on. - for (scanCount = 0;scanCount < 4; scanCount ++) - { - j = 0; - while (scanOffsets[scanCount][j]) - { - tempOffset = corrOffset + scanOffsets[scanCount][j]; - if (tempOffset >= seekLength) break; - - // Calculates correlation value for the mixing position corresponding - // to 'tempOffset' - corr = calcCrossCorrMono(refPos + tempOffset, pRefMidBuffer); - - // Checks for the highest correlation value - if (corr > bestCorr) - { - bestCorr = corr; - bestOffs = tempOffset; - } - j ++; - } - corrOffset = bestOffs; - } - // clear cross correlation routine state if necessary (is so e.g. in MMX routines). - clearCrossCorrState(); - - return bestOffs; -} - - -/// clear cross correlation routine state if necessary -void TDStretch::clearCrossCorrState() -{ - // default implementation is empty. -} - - -// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower -// tempo, larger faster tempo. -void TDStretch::setTempo(float newTempo) -{ - uint intskip; - - tempo = newTempo; - - // Calculate ideal skip length (according to tempo value) - nominalSkip = tempo * (seekWindowLength - overlapLength); - skipFract = 0; - intskip = (int)(nominalSkip + 0.5f); - - // Calculate how many samples are needed in the 'inputBuffer' to - // process another batch of samples - sampleReq = max(intskip + overlapLength, seekWindowLength) + maxOffset; -} - - - -// Sets the number of channels, 1 = mono, 2 = stereo -void TDStretch::setChannels(uint numChannels) -{ - if (channels == numChannels) return; - assert(numChannels == 1 || numChannels == 2); - - channels = numChannels; - inputBuffer.setChannels(channels); - outputBuffer.setChannels(channels); -} - - -// nominal tempo, no need for processing, just pass the samples through -// to outputBuffer -void TDStretch::processNominalTempo() -{ - assert(tempo == 1.0f); - - if (bMidBufferDirty) - { - // If there are samples in pMidBuffer waiting for overlapping, - // do a single sliding overlapping with them in order to prevent a - // clicking distortion in the output sound - if (inputBuffer.numSamples() < overlapLength) - { - // wait until we've got overlapLength input samples - return; - } - // Mix the samples in the beginning of 'inputBuffer' with the - // samples in 'midBuffer' using sliding overlapping - overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0); - outputBuffer.putSamples(overlapLength); - inputBuffer.receiveSamples(overlapLength); - clearMidBuffer(); - // now we've caught the nominal sample flow and may switch to - // bypass mode - } - - // Simply bypass samples from input to output - outputBuffer.moveSamples(inputBuffer); -} - - -// Processes as many processing frames of the samples 'inputBuffer', store -// the result into 'outputBuffer' -void TDStretch::processSamples() -{ - uint ovlSkip, offset; - int temp; - - /* Removed this small optimization - can introduce a click to sound when tempo setting - crosses the nominal value - if (tempo == 1.0f) - { - // tempo not changed from the original, so bypass the processing - processNominalTempo(); - return; - } - */ - - if (bMidBufferDirty == FALSE) - { - // if midBuffer is empty, move the first samples of the input stream - // into it - if (inputBuffer.numSamples() < overlapLength) - { - // wait until we've got overlapLength samples - return; - } - memcpy(pMidBuffer, inputBuffer.ptrBegin(), channels * overlapLength * sizeof(SAMPLETYPE)); - inputBuffer.receiveSamples(overlapLength); - bMidBufferDirty = TRUE; - } - - // Process samples as long as there are enough samples in 'inputBuffer' - // to form a processing frame. - while (inputBuffer.numSamples() >= sampleReq) - { - // If tempo differs from the normal ('SCALE'), scan for the best overlapping - // position - offset = seekBestOverlapPosition(inputBuffer.ptrBegin()); - - // Mix the samples in the 'inputBuffer' at position of 'offset' with the - // samples in 'midBuffer' using sliding overlapping - // ... first partially overlap with the end of the previous sequence - // (that's in 'midBuffer') - overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), offset); - outputBuffer.putSamples(overlapLength); - - // ... then copy sequence samples from 'inputBuffer' to output - temp = (seekWindowLength - 2 * overlapLength);// & 0xfffffffe; - if (temp > 0) - { - outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * (offset + overlapLength), temp); - } - - // Copies the end of the current sequence from 'inputBuffer' to - // 'midBuffer' for being mixed with the beginning of the next - // processing sequence and so on - assert(offset + seekWindowLength <= inputBuffer.numSamples()); - memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + seekWindowLength - overlapLength), - channels * sizeof(SAMPLETYPE) * overlapLength); - bMidBufferDirty = TRUE; - - // Remove the processed samples from the input buffer. Update - // the difference between integer & nominal skip step to 'skipFract' - // in order to prevent the error from accumulating over time. - skipFract += nominalSkip; // real skip size - ovlSkip = (int)skipFract; // rounded to integer skip - skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip - inputBuffer.receiveSamples(ovlSkip); - } -} - - -// Adds 'numsamples' pcs of samples from the 'samples' memory position into -// the input of the object. -void TDStretch::putSamples(const SAMPLETYPE *samples, uint numSamples) -{ - // Add the samples into the input buffer - inputBuffer.putSamples(samples, numSamples); - // Process the samples in input buffer - processSamples(); -} - - - -/// Set new overlap length parameter & reallocate RefMidBuffer if necessary. -void TDStretch::acceptNewOverlapLength(uint newOverlapLength) -{ - uint prevOvl; - - prevOvl = overlapLength; - overlapLength = newOverlapLength; - - if (overlapLength > prevOvl) - { - delete[] pMidBuffer; - delete[] pRefMidBufferUnaligned; - - pMidBuffer = new SAMPLETYPE[overlapLength * 2]; - bMidBufferDirty = TRUE; - clearMidBuffer(); - - pRefMidBufferUnaligned = new SAMPLETYPE[2 * overlapLength + 16 / sizeof(SAMPLETYPE)]; - // ensure that 'pRefMidBuffer' is aligned to 16 byte boundary for efficiency - pRefMidBuffer = (SAMPLETYPE *)((((ulongptr)pRefMidBufferUnaligned) + 15) & -16); - } -} - - -// Operator 'new' is overloaded so that it automatically creates a suitable instance -// depending on if we've a MMX/SSE/etc-capable CPU available or not. -void * TDStretch::operator new(size_t s) -{ - // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! - assert(FALSE); - return NULL; -} - - -TDStretch * TDStretch::newInstance() -{ - uint uExtensions = 0; - -#if !defined(_MSC_VER) || !defined(__x86_64__) - uExtensions = detectCPUextensions(); -#endif - - // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU - -#ifdef ALLOW_MMX - // MMX routines available only with integer sample types - if (uExtensions & SUPPORT_MMX) - { - return ::new TDStretchMMX; - } - else -#endif // ALLOW_MMX - - -#ifdef ALLOW_SSE - if (uExtensions & SUPPORT_SSE) - { - // SSE support - return ::new TDStretchSSE; - } - else -#endif // ALLOW_SSE - - -#ifdef ALLOW_3DNOW - if (uExtensions & SUPPORT_3DNOW) - { - // 3DNow! support - return ::new TDStretch3DNow; - } - else -#endif // ALLOW_3DNOW - - { - // ISA optimizations not supported, use plain C version - return ::new TDStretch; - } -} - - -////////////////////////////////////////////////////////////////////////////// -// -// Integer arithmetics specific algorithm implementations. -// -////////////////////////////////////////////////////////////////////////////// - -#ifdef INTEGER_SAMPLES - -// Slopes the amplitude of the 'midBuffer' samples so that cross correlation -// is faster to calculate -void TDStretch::precalcCorrReferenceStereo() -{ - int i, cnt2; - int temp, temp2; - - for (i=0 ; i < (int)overlapLength ;i ++) - { - temp = i * (overlapLength - i); - cnt2 = i * 2; - - temp2 = (pMidBuffer[cnt2] * temp) / slopingDivider; - pRefMidBuffer[cnt2] = (short)(temp2); - temp2 = (pMidBuffer[cnt2 + 1] * temp) / slopingDivider; - pRefMidBuffer[cnt2 + 1] = (short)(temp2); - } -} - - -// Slopes the amplitude of the 'midBuffer' samples so that cross correlation -// is faster to calculate -void TDStretch::precalcCorrReferenceMono() -{ - int i; - long temp; - long temp2; - - for (i=0 ; i < (int)overlapLength ;i ++) - { - temp = i * (overlapLength - i); - temp2 = (pMidBuffer[i] * temp) / slopingDivider; - pRefMidBuffer[i] = (short)temp2; - } -} - - -// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo' -// version of the routine. -void TDStretch::overlapStereo(short *output, const short *input) const -{ - int i; - short temp; - uint cnt2; - - for (i = 0; i < (int)overlapLength ; i ++) - { - temp = (short)(overlapLength - i); - cnt2 = 2 * i; - output[cnt2] = (input[cnt2] * i + pMidBuffer[cnt2] * temp ) / overlapLength; - output[cnt2 + 1] = (input[cnt2 + 1] * i + pMidBuffer[cnt2 + 1] * temp ) / overlapLength; - } -} - - -/// Calculates overlap period length in samples. -/// Integer version rounds overlap length to closest power of 2 -/// for a divide scaling operation. -void TDStretch::calculateOverlapLength(uint overlapMs) -{ - uint newOvl; - - overlapDividerBits = _getClosest2Power((sampleRate * overlapMs) / 1000.0); - if (overlapDividerBits > 9) overlapDividerBits = 9; - if (overlapDividerBits < 4) overlapDividerBits = 4; - newOvl = 1<> overlapDividerBits; - } - - return corr; -} - - -long TDStretch::calcCrossCorrStereo(const short *mixingPos, const short *compare) const -{ - long corr; - uint i; - - corr = 0; - for (i = 2; i < 2 * overlapLength; i += 2) - { - corr += (mixingPos[i] * compare[i] + - mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBits; - } - - return corr; -} - -#endif // INTEGER_SAMPLES - -////////////////////////////////////////////////////////////////////////////// -// -// Floating point arithmetics specific algorithm implementations. -// - -#ifdef FLOAT_SAMPLES - - -// Slopes the amplitude of the 'midBuffer' samples so that cross correlation -// is faster to calculate -void TDStretch::precalcCorrReferenceStereo() -{ - int i, cnt2; - float temp; - - for (i=0 ; i < (int)overlapLength ;i ++) - { - temp = (float)i * (float)(overlapLength - i); - cnt2 = i * 2; - pRefMidBuffer[cnt2] = (float)(pMidBuffer[cnt2] * temp); - pRefMidBuffer[cnt2 + 1] = (float)(pMidBuffer[cnt2 + 1] * temp); - } -} - - -// Slopes the amplitude of the 'midBuffer' samples so that cross correlation -// is faster to calculate -void TDStretch::precalcCorrReferenceMono() -{ - int i; - float temp; - - for (i=0 ; i < (int)overlapLength ;i ++) - { - temp = (float)i * (float)(overlapLength - i); - pRefMidBuffer[i] = (float)(pMidBuffer[i] * temp); - } -} - - -// SSE-optimized version of the function overlapStereo -void TDStretch::overlapStereo(float *output, const float *input) const -{ - int i; - uint cnt2; - float fTemp; - float fScale; - float fi; - - fScale = 1.0f / (float)overlapLength; - - for (i = 0; i < (int)overlapLength ; i ++) - { - fTemp = (float)(overlapLength - i) * fScale; - fi = (float)i * fScale; - cnt2 = 2 * i; - output[cnt2 + 0] = input[cnt2 + 0] * fi + pMidBuffer[cnt2 + 0] * fTemp; - output[cnt2 + 1] = input[cnt2 + 1] * fi + pMidBuffer[cnt2 + 1] * fTemp; - } -} - - -/// Calculates overlap period length in samples. -void TDStretch::calculateOverlapLength(uint overlapMs) -{ - uint newOvl; - - newOvl = (sampleRate * overlapMs) / 1000; - if (newOvl < 16) newOvl = 16; - - // must be divisible by 8 - newOvl -= newOvl % 8; - - acceptNewOverlapLength(newOvl); -} - - - -double TDStretch::calcCrossCorrMono(const float *mixingPos, const float *compare) const -{ - double corr; - uint i; - - corr = 0; - for (i = 1; i < overlapLength; i ++) - { - corr += mixingPos[i] * compare[i]; - } - - return corr; -} - - -double TDStretch::calcCrossCorrStereo(const float *mixingPos, const float *compare) const -{ - double corr; - uint i; - - corr = 0; - for (i = 2; i < 2 * overlapLength; i += 2) - { - corr += mixingPos[i] * compare[i] + - mixingPos[i + 1] * compare[i + 1]; - } - - return corr; -} - -#endif // FLOAT_SAMPLES +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like +/// method with several performance-increasing tweaks. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific +/// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.24 $ +// +// $Id: TDStretch.cpp,v 1.24 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include "STTypes.h" +#include "cpu_detect.h" +#include "TDStretch.h" + +using namespace soundtouch; + +#ifndef min +#define min(a,b) ((a > b) ? b : a) +#define max(a,b) ((a < b) ? b : a) +#endif + + + +/***************************************************************************** + * + * Constant definitions + * + *****************************************************************************/ + + +// Table for the hierarchical mixing position seeking algorithm +int scanOffsets[4][24]={ + { 124, 186, 248, 310, 372, 434, 496, 558, 620, 682, 744, 806, + 868, 930, 992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488, 0}, + {-100, -75, -50, -25, 25, 50, 75, 100, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { -20, -15, -10, -5, 5, 10, 15, 20, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { -4, -3, -2, -1, 1, 2, 3, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; + +/***************************************************************************** + * + * Implementation of the class 'TDStretch' + * + *****************************************************************************/ + + +TDStretch::TDStretch() : FIFOProcessor(&outputBuffer) +{ + bQuickseek = FALSE; + channels = 2; + bMidBufferDirty = FALSE; + + pMidBuffer = NULL; + pRefMidBufferUnaligned = NULL; + overlapLength = 0; + + setParameters(48000, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS); + + setTempo(1.0f); +} + + + + +TDStretch::~TDStretch() +{ + delete[] pMidBuffer; + delete[] pRefMidBufferUnaligned; +} + + + +// Calculates the x having the closest 2^x value for the given value +static int _getClosest2Power(double value) +{ + return (int)(log(value) / log(2.0) + 0.5); +} + + + +// Sets routine control parameters. These control are certain time constants +// defining how the sound is stretched to the desired duration. +// +// 'sampleRate' = sample rate of the sound +// 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms) +// 'seekwindowMS' = seeking window length for scanning the best overlapping +// position (default = 28 ms) +// 'overlapMS' = overlapping length (default = 12 ms) + +void TDStretch::setParameters(uint aSampleRate, uint aSequenceMS, + uint aSeekWindowMS, uint aOverlapMS) +{ + this->sampleRate = aSampleRate; + this->sequenceMs = aSequenceMS; + this->seekWindowMs = aSeekWindowMS; + this->overlapMs = aOverlapMS; + + seekLength = (sampleRate * seekWindowMs) / 1000; + seekWindowLength = (sampleRate * sequenceMs) / 1000; + + maxOffset = seekLength; + + calculateOverlapLength(overlapMs); + + // set tempo to recalculate 'sampleReq' + setTempo(tempo); + +} + + + +/// Get routine control parameters, see setParameters() function. +/// Any of the parameters to this function can be NULL, in such case corresponding parameter +/// value isn't returned. +void TDStretch::getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs) +{ + if (pSampleRate) + { + *pSampleRate = sampleRate; + } + + if (pSequenceMs) + { + *pSequenceMs = sequenceMs; + } + + if (pSeekWindowMs) + { + *pSeekWindowMs = seekWindowMs; + } + + if (pOverlapMs) + { + *pOverlapMs = overlapMs; + } +} + + +// Overlaps samples in 'midBuffer' with the samples in 'input' +void TDStretch::overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const +{ + int i, itemp; + + for (i = 0; i < (int)overlapLength ; i ++) + { + itemp = overlapLength - i; + output[i] = (input[i] * i + pMidBuffer[i] * itemp ) / overlapLength; // >> overlapDividerBits; + } +} + + + +void TDStretch::clearMidBuffer() +{ + if (bMidBufferDirty) + { + memset(pMidBuffer, 0, 2 * sizeof(SAMPLETYPE) * overlapLength); + bMidBufferDirty = FALSE; + } +} + + +void TDStretch::clearInput() +{ + inputBuffer.clear(); + clearMidBuffer(); +} + + +// Clears the sample buffers +void TDStretch::clear() +{ + outputBuffer.clear(); + inputBuffer.clear(); + clearMidBuffer(); +} + + + +// Enables/disables the quick position seeking algorithm. Zero to disable, nonzero +// to enable +void TDStretch::enableQuickSeek(BOOL enable) +{ + bQuickseek = enable; +} + + +// Returns nonzero if the quick seeking algorithm is enabled. +BOOL TDStretch::isQuickSeekEnabled() const +{ + return bQuickseek; +} + + +// Seeks for the optimal overlap-mixing position. +uint TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos) +{ + if (channels == 2) + { + // stereo sound + if (bQuickseek) + { + return seekBestOverlapPositionStereoQuick(refPos); + } + else + { + return seekBestOverlapPositionStereo(refPos); + } + } + else + { + // mono sound + if (bQuickseek) + { + return seekBestOverlapPositionMonoQuick(refPos); + } + else + { + return seekBestOverlapPositionMono(refPos); + } + } +} + + + + +// Overlaps samples in 'midBuffer' with the samples in 'inputBuffer' at position +// of 'ovlPos'. +inline void TDStretch::overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const +{ + if (channels == 2) + { + // stereo sound + overlapStereo(output, input + 2 * ovlPos); + } else { + // mono sound. + overlapMono(output, input + ovlPos); + } +} + + + + +// Seeks for the optimal overlap-mixing position. The 'stereo' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionStereo(const SAMPLETYPE *refPos) +{ + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint i; + + // Slopes the amplitudes of the 'midBuffer' samples + precalcCorrReferenceStereo(); + + bestCorr = INT_MIN; + bestOffs = 0; + + // Scans for the best correlation value by testing each possible position + // over the permitted range. + for (i = 0; i < seekLength; i ++) + { + // Calculates correlation value for the mixing position corresponding + // to 'i' + corr = calcCrossCorrStereo(refPos + 2 * i, pRefMidBuffer); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = i; + } + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + +// Seeks for the optimal overlap-mixing position. The 'stereo' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos) +{ + uint j; + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint scanCount, corrOffset, tempOffset; + + // Slopes the amplitude of the 'midBuffer' samples + precalcCorrReferenceStereo(); + + bestCorr = INT_MIN; + bestOffs = 0; + corrOffset = 0; + tempOffset = 0; + + // Scans for the best correlation value using four-pass hierarchical search. + // + // The look-up table 'scans' has hierarchical position adjusting steps. + // In first pass the routine searhes for the highest correlation with + // relatively coarse steps, then rescans the neighbourhood of the highest + // correlation with better resolution and so on. + for (scanCount = 0;scanCount < 4; scanCount ++) + { + j = 0; + while (scanOffsets[scanCount][j]) + { + tempOffset = corrOffset + scanOffsets[scanCount][j]; + if (tempOffset >= seekLength) break; + + // Calculates correlation value for the mixing position corresponding + // to 'tempOffset' + corr = calcCrossCorrStereo(refPos + 2 * tempOffset, pRefMidBuffer); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = tempOffset; + } + j ++; + } + corrOffset = bestOffs; + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + + +// Seeks for the optimal overlap-mixing position. The 'mono' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionMono(const SAMPLETYPE *refPos) +{ + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint tempOffset; + const SAMPLETYPE *compare; + + // Slopes the amplitude of the 'midBuffer' samples + precalcCorrReferenceMono(); + + bestCorr = INT_MIN; + bestOffs = 0; + + // Scans for the best correlation value by testing each possible position + // over the permitted range. + for (tempOffset = 0; tempOffset < seekLength; tempOffset ++) + { + compare = refPos + tempOffset; + + // Calculates correlation value for the mixing position corresponding + // to 'tempOffset' + corr = calcCrossCorrMono(pRefMidBuffer, compare); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = tempOffset; + } + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + +// Seeks for the optimal overlap-mixing position. The 'mono' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos) +{ + uint j; + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint scanCount, corrOffset, tempOffset; + + // Slopes the amplitude of the 'midBuffer' samples + precalcCorrReferenceMono(); + + bestCorr = INT_MIN; + bestOffs = 0; + corrOffset = 0; + tempOffset = 0; + + // Scans for the best correlation value using four-pass hierarchical search. + // + // The look-up table 'scans' has hierarchical position adjusting steps. + // In first pass the routine searhes for the highest correlation with + // relatively coarse steps, then rescans the neighbourhood of the highest + // correlation with better resolution and so on. + for (scanCount = 0;scanCount < 4; scanCount ++) + { + j = 0; + while (scanOffsets[scanCount][j]) + { + tempOffset = corrOffset + scanOffsets[scanCount][j]; + if (tempOffset >= seekLength) break; + + // Calculates correlation value for the mixing position corresponding + // to 'tempOffset' + corr = calcCrossCorrMono(refPos + tempOffset, pRefMidBuffer); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = tempOffset; + } + j ++; + } + corrOffset = bestOffs; + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + +/// clear cross correlation routine state if necessary +void TDStretch::clearCrossCorrState() +{ + // default implementation is empty. +} + + +// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower +// tempo, larger faster tempo. +void TDStretch::setTempo(float newTempo) +{ + uint intskip; + + tempo = newTempo; + + // Calculate ideal skip length (according to tempo value) + nominalSkip = tempo * (seekWindowLength - overlapLength); + skipFract = 0; + intskip = (int)(nominalSkip + 0.5f); + + // Calculate how many samples are needed in the 'inputBuffer' to + // process another batch of samples + sampleReq = max(intskip + overlapLength, seekWindowLength) + maxOffset; +} + + + +// Sets the number of channels, 1 = mono, 2 = stereo +void TDStretch::setChannels(uint numChannels) +{ + if (channels == numChannels) return; + assert(numChannels == 1 || numChannels == 2); + + channels = numChannels; + inputBuffer.setChannels(channels); + outputBuffer.setChannels(channels); +} + + +// nominal tempo, no need for processing, just pass the samples through +// to outputBuffer +void TDStretch::processNominalTempo() +{ + assert(tempo == 1.0f); + + if (bMidBufferDirty) + { + // If there are samples in pMidBuffer waiting for overlapping, + // do a single sliding overlapping with them in order to prevent a + // clicking distortion in the output sound + if (inputBuffer.numSamples() < overlapLength) + { + // wait until we've got overlapLength input samples + return; + } + // Mix the samples in the beginning of 'inputBuffer' with the + // samples in 'midBuffer' using sliding overlapping + overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0); + outputBuffer.putSamples(overlapLength); + inputBuffer.receiveSamples(overlapLength); + clearMidBuffer(); + // now we've caught the nominal sample flow and may switch to + // bypass mode + } + + // Simply bypass samples from input to output + outputBuffer.moveSamples(inputBuffer); +} + + +// Processes as many processing frames of the samples 'inputBuffer', store +// the result into 'outputBuffer' +void TDStretch::processSamples() +{ + uint ovlSkip, offset; + int temp; + + /* Removed this small optimization - can introduce a click to sound when tempo setting + crosses the nominal value + if (tempo == 1.0f) + { + // tempo not changed from the original, so bypass the processing + processNominalTempo(); + return; + } + */ + + if (bMidBufferDirty == FALSE) + { + // if midBuffer is empty, move the first samples of the input stream + // into it + if (inputBuffer.numSamples() < overlapLength) + { + // wait until we've got overlapLength samples + return; + } + memcpy(pMidBuffer, inputBuffer.ptrBegin(), channels * overlapLength * sizeof(SAMPLETYPE)); + inputBuffer.receiveSamples(overlapLength); + bMidBufferDirty = TRUE; + } + + // Process samples as long as there are enough samples in 'inputBuffer' + // to form a processing frame. + while (inputBuffer.numSamples() >= sampleReq) + { + // If tempo differs from the normal ('SCALE'), scan for the best overlapping + // position + offset = seekBestOverlapPosition(inputBuffer.ptrBegin()); + + // Mix the samples in the 'inputBuffer' at position of 'offset' with the + // samples in 'midBuffer' using sliding overlapping + // ... first partially overlap with the end of the previous sequence + // (that's in 'midBuffer') + overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), offset); + outputBuffer.putSamples(overlapLength); + + // ... then copy sequence samples from 'inputBuffer' to output + temp = (seekWindowLength - 2 * overlapLength);// & 0xfffffffe; + if (temp > 0) + { + outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * (offset + overlapLength), temp); + } + + // Copies the end of the current sequence from 'inputBuffer' to + // 'midBuffer' for being mixed with the beginning of the next + // processing sequence and so on + assert(offset + seekWindowLength <= inputBuffer.numSamples()); + memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + seekWindowLength - overlapLength), + channels * sizeof(SAMPLETYPE) * overlapLength); + bMidBufferDirty = TRUE; + + // Remove the processed samples from the input buffer. Update + // the difference between integer & nominal skip step to 'skipFract' + // in order to prevent the error from accumulating over time. + skipFract += nominalSkip; // real skip size + ovlSkip = (int)skipFract; // rounded to integer skip + skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip + inputBuffer.receiveSamples(ovlSkip); + } +} + + +// Adds 'numsamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void TDStretch::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + // Add the samples into the input buffer + inputBuffer.putSamples(samples, numSamples); + // Process the samples in input buffer + processSamples(); +} + + + +/// Set new overlap length parameter & reallocate RefMidBuffer if necessary. +void TDStretch::acceptNewOverlapLength(uint newOverlapLength) +{ + uint prevOvl; + + prevOvl = overlapLength; + overlapLength = newOverlapLength; + + if (overlapLength > prevOvl) + { + delete[] pMidBuffer; + delete[] pRefMidBufferUnaligned; + + pMidBuffer = new SAMPLETYPE[overlapLength * 2]; + bMidBufferDirty = TRUE; + clearMidBuffer(); + + pRefMidBufferUnaligned = new SAMPLETYPE[2 * overlapLength + 16 / sizeof(SAMPLETYPE)]; + // ensure that 'pRefMidBuffer' is aligned to 16 byte boundary for efficiency + pRefMidBuffer = (SAMPLETYPE *)((((ulongptr)pRefMidBufferUnaligned) + 15) & -16); + } +} + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX/SSE/etc-capable CPU available or not. +void * TDStretch::operator new(size_t s) +{ + // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! + assert(FALSE); + return NULL; +} + + +TDStretch * TDStretch::newInstance() +{ + uint uExtensions = 0; + +#if !defined(_MSC_VER) || !defined(__x86_64__) + uExtensions = detectCPUextensions(); +#endif + + // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU + +#ifdef ALLOW_MMX + // MMX routines available only with integer sample types + if (uExtensions & SUPPORT_MMX) + { + return ::new TDStretchMMX; + } + else +#endif // ALLOW_MMX + + +#ifdef ALLOW_SSE + if (uExtensions & SUPPORT_SSE) + { + // SSE support + return ::new TDStretchSSE; + } + else +#endif // ALLOW_SSE + + +#ifdef ALLOW_3DNOW + if (uExtensions & SUPPORT_3DNOW) + { + // 3DNow! support + return ::new TDStretch3DNow; + } + else +#endif // ALLOW_3DNOW + + { + // ISA optimizations not supported, use plain C version + return ::new TDStretch; + } +} + + +////////////////////////////////////////////////////////////////////////////// +// +// Integer arithmetics specific algorithm implementations. +// +////////////////////////////////////////////////////////////////////////////// + +#ifdef INTEGER_SAMPLES + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceStereo() +{ + int i, cnt2; + int temp, temp2; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = i * (overlapLength - i); + cnt2 = i * 2; + + temp2 = (pMidBuffer[cnt2] * temp) / slopingDivider; + pRefMidBuffer[cnt2] = (short)(temp2); + temp2 = (pMidBuffer[cnt2 + 1] * temp) / slopingDivider; + pRefMidBuffer[cnt2 + 1] = (short)(temp2); + } +} + + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceMono() +{ + int i; + long temp; + long temp2; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = i * (overlapLength - i); + temp2 = (pMidBuffer[i] * temp) / slopingDivider; + pRefMidBuffer[i] = (short)temp2; + } +} + + +// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo' +// version of the routine. +void TDStretch::overlapStereo(short *output, const short *input) const +{ + int i; + short temp; + uint cnt2; + + for (i = 0; i < (int)overlapLength ; i ++) + { + temp = (short)(overlapLength - i); + cnt2 = 2 * i; + output[cnt2] = (input[cnt2] * i + pMidBuffer[cnt2] * temp ) / overlapLength; + output[cnt2 + 1] = (input[cnt2 + 1] * i + pMidBuffer[cnt2 + 1] * temp ) / overlapLength; + } +} + + +/// Calculates overlap period length in samples. +/// Integer version rounds overlap length to closest power of 2 +/// for a divide scaling operation. +void TDStretch::calculateOverlapLength(uint overlapMs) +{ + uint newOvl; + + overlapDividerBits = _getClosest2Power((sampleRate * overlapMs) / 1000.0); + if (overlapDividerBits > 9) overlapDividerBits = 9; + if (overlapDividerBits < 4) overlapDividerBits = 4; + newOvl = 1<> overlapDividerBits; + } + + return corr; +} + + +long TDStretch::calcCrossCorrStereo(const short *mixingPos, const short *compare) const +{ + long corr; + uint i; + + corr = 0; + for (i = 2; i < 2 * overlapLength; i += 2) + { + corr += (mixingPos[i] * compare[i] + + mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBits; + } + + return corr; +} + +#endif // INTEGER_SAMPLES + +////////////////////////////////////////////////////////////////////////////// +// +// Floating point arithmetics specific algorithm implementations. +// + +#ifdef FLOAT_SAMPLES + + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceStereo() +{ + int i, cnt2; + float temp; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = (float)i * (float)(overlapLength - i); + cnt2 = i * 2; + pRefMidBuffer[cnt2] = (float)(pMidBuffer[cnt2] * temp); + pRefMidBuffer[cnt2 + 1] = (float)(pMidBuffer[cnt2 + 1] * temp); + } +} + + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceMono() +{ + int i; + float temp; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = (float)i * (float)(overlapLength - i); + pRefMidBuffer[i] = (float)(pMidBuffer[i] * temp); + } +} + + +// SSE-optimized version of the function overlapStereo +void TDStretch::overlapStereo(float *output, const float *input) const +{ + int i; + uint cnt2; + float fTemp; + float fScale; + float fi; + + fScale = 1.0f / (float)overlapLength; + + for (i = 0; i < (int)overlapLength ; i ++) + { + fTemp = (float)(overlapLength - i) * fScale; + fi = (float)i * fScale; + cnt2 = 2 * i; + output[cnt2 + 0] = input[cnt2 + 0] * fi + pMidBuffer[cnt2 + 0] * fTemp; + output[cnt2 + 1] = input[cnt2 + 1] * fi + pMidBuffer[cnt2 + 1] * fTemp; + } +} + + +/// Calculates overlap period length in samples. +void TDStretch::calculateOverlapLength(uint overlapMs) +{ + uint newOvl; + + newOvl = (sampleRate * overlapMs) / 1000; + if (newOvl < 16) newOvl = 16; + + // must be divisible by 8 + newOvl -= newOvl % 8; + + acceptNewOverlapLength(newOvl); +} + + + +double TDStretch::calcCrossCorrMono(const float *mixingPos, const float *compare) const +{ + double corr; + uint i; + + corr = 0; + for (i = 1; i < overlapLength; i ++) + { + corr += mixingPos[i] * compare[i]; + } + + return corr; +} + + +double TDStretch::calcCrossCorrStereo(const float *mixingPos, const float *compare) const +{ + double corr; + uint i; + + corr = 0; + for (i = 2; i < 2 * overlapLength; i += 2) + { + corr += mixingPos[i] * compare[i] + + mixingPos[i + 1] * compare[i + 1]; + } + + return corr; +} + +#endif // FLOAT_SAMPLES diff --git a/3rdparty/SoundTouch/TDStretch.h b/3rdparty/SoundTouch/TDStretch.h index a05a7072fc..133c227d49 100644 --- a/3rdparty/SoundTouch/TDStretch.h +++ b/3rdparty/SoundTouch/TDStretch.h @@ -1,236 +1,236 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo -/// while maintaining the original pitch by using a time domain WSOLA-like method -/// with several performance-increasing tweaks. -/// -/// Note : MMX optimized functions reside in a separate, platform-specific file, -/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.16 $ -// -// $Id: TDStretch.h,v 1.16 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef TDStretch_H -#define TDStretch_H - -#include "STTypes.h" -#include "RateTransposer.h" -#include "FIFOSamplePipe.h" - -namespace soundtouch -{ - -// Default values for sound processing parameters: - -/// Default length of a single processing sequence, in milliseconds. This determines to how -/// long sequences the original sound is chopped in the time-stretch algorithm. -/// -/// The larger this value is, the lesser sequences are used in processing. In principle -/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo -/// and vice versa. -/// -/// Increasing this value reduces computational burden & vice versa. -#define DEFAULT_SEQUENCE_MS 61 - -#define DEFAULT_SEEKWINDOW_MS 18 - -#define DEFAULT_OVERLAP_MS 7 - - -/// Class that does the time-stretch (tempo change) effect for the processed -/// sound. -class TDStretch : public FIFOProcessor -{ -protected: - uint channels; - uint sampleReq; - float tempo; - - SAMPLETYPE *pMidBuffer; - SAMPLETYPE *pRefMidBuffer; - SAMPLETYPE *pRefMidBufferUnaligned; - uint overlapLength; - uint overlapDividerBits; - uint slopingDivider; - uint seekLength; - uint seekWindowLength; - uint maxOffset; - float nominalSkip; - float skipFract; - FIFOSampleBuffer outputBuffer; - FIFOSampleBuffer inputBuffer; - BOOL bQuickseek; - BOOL bMidBufferDirty; - - uint sampleRate; - uint sequenceMs; - uint seekWindowMs; - uint overlapMs; - - void acceptNewOverlapLength(uint newOverlapLength); - - virtual void clearCrossCorrState(); - void calculateOverlapLength(uint overlapMs); - - virtual LONG_SAMPLETYPE calcCrossCorrStereo(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; - virtual LONG_SAMPLETYPE calcCrossCorrMono(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; - - virtual uint seekBestOverlapPositionStereo(const SAMPLETYPE *refPos); - virtual uint seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos); - virtual uint seekBestOverlapPositionMono(const SAMPLETYPE *refPos); - virtual uint seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos); - uint seekBestOverlapPosition(const SAMPLETYPE *refPos); - - virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const; - virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const; - - void clearMidBuffer(); - void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const; - - void precalcCorrReferenceMono(); - void precalcCorrReferenceStereo(); - - void processNominalTempo(); - - /// Changes the tempo of the given sound samples. - /// Returns amount of samples returned in the "output" buffer. - /// The maximum amount of samples that can be returned at a time is set by - /// the 'set_returnBuffer_size' function. - void processSamples(); - -public: - TDStretch(); - virtual ~TDStretch(); - - /// Operator 'new' is overloaded so that it automatically creates a suitable instance - /// depending on if we've a MMX/SSE/etc-capable CPU available or not. - void *operator new(size_t s); - - /// Use this function instead of "new" operator to create a new instance of this class. - /// This function automatically chooses a correct feature set depending on if the CPU - /// supports MMX/SSE/etc extensions. - static TDStretch *newInstance(); - - /// Returns the output buffer object - FIFOSamplePipe *getOutput() { return &outputBuffer; }; - - /// Returns the input buffer object - FIFOSamplePipe *getInput() { return &inputBuffer; }; - - /// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower - /// tempo, larger faster tempo. - void setTempo(float newTempo); - - /// Returns nonzero if there aren't any samples available for outputting. - virtual void clear(); - - /// Clears the input buffer - void clearInput(); - - /// Sets the number of channels, 1 = mono, 2 = stereo - void setChannels(uint numChannels); - - /// Enables/disables the quick position seeking algorithm. Zero to disable, - /// nonzero to enable - void enableQuickSeek(BOOL enable); - - /// Returns nonzero if the quick seeking algorithm is enabled. - BOOL isQuickSeekEnabled() const; - - /// Sets routine control parameters. These control are certain time constants - /// defining how the sound is stretched to the desired duration. - // - /// 'sampleRate' = sample rate of the sound - /// 'sequenceMS' = one processing sequence length in milliseconds - /// 'seekwindowMS' = seeking window length for scanning the best overlapping - /// position - /// 'overlapMS' = overlapping length - void setParameters(uint sampleRate, ///< Samplerate of sound being processed (Hz) - uint sequenceMS = DEFAULT_SEQUENCE_MS, ///< Single processing sequence length (ms) - uint seekwindowMS = DEFAULT_SEEKWINDOW_MS, ///< Offset seeking window length (ms) - uint overlapMS = DEFAULT_OVERLAP_MS ///< Sequence overlapping length (ms) - ); - - /// Get routine control parameters, see setParameters() function. - /// Any of the parameters to this function can be NULL, in such case corresponding parameter - /// value isn't returned. - void getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs); - - /// Adds 'numsamples' pcs of samples from the 'samples' memory position into - /// the input of the object. - virtual void putSamples( - const SAMPLETYPE *samples, ///< Input sample data - uint numSamples ///< Number of samples in 'samples' so that one sample - ///< contains both channels if stereo - ); -}; - - - -// Implementation-specific class declarations: - -//#ifdef ALLOW_MMX -// /// Class that implements MMX optimized routines for 16bit integer samples type. -// class TDStretchMMX : public TDStretch -// { -// protected: -// long calcCrossCorrStereo(const short *mixingPos, const short *compare) const; -// virtual void overlapStereo(short *output, const short *input) const; -// virtual void clearCrossCorrState(); -// }; -//#endif /// ALLOW_MMX -// -// -//#ifdef ALLOW_3DNOW -// /// Class that implements 3DNow! optimized routines for floating point samples type. -// class TDStretch3DNow : public TDStretch -// { -// protected: -// double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; -// }; -//#endif /// ALLOW_3DNOW - - -#ifdef ALLOW_SSE - /// Class that implements SSE optimized routines for floating point samples type. - class TDStretchSSE : public TDStretch - { - protected: - double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; - }; - -#endif /// ALLOW_SSE - -} -#endif /// TDStretch_H +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like method +/// with several performance-increasing tweaks. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.16 $ +// +// $Id: TDStretch.h,v 1.16 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef TDStretch_H +#define TDStretch_H + +#include "STTypes.h" +#include "RateTransposer.h" +#include "FIFOSamplePipe.h" + +namespace soundtouch +{ + +// Default values for sound processing parameters: + +/// Default length of a single processing sequence, in milliseconds. This determines to how +/// long sequences the original sound is chopped in the time-stretch algorithm. +/// +/// The larger this value is, the lesser sequences are used in processing. In principle +/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo +/// and vice versa. +/// +/// Increasing this value reduces computational burden & vice versa. +#define DEFAULT_SEQUENCE_MS 61 + +#define DEFAULT_SEEKWINDOW_MS 18 + +#define DEFAULT_OVERLAP_MS 7 + + +/// Class that does the time-stretch (tempo change) effect for the processed +/// sound. +class TDStretch : public FIFOProcessor +{ +protected: + uint channels; + uint sampleReq; + float tempo; + + SAMPLETYPE *pMidBuffer; + SAMPLETYPE *pRefMidBuffer; + SAMPLETYPE *pRefMidBufferUnaligned; + uint overlapLength; + uint overlapDividerBits; + uint slopingDivider; + uint seekLength; + uint seekWindowLength; + uint maxOffset; + float nominalSkip; + float skipFract; + FIFOSampleBuffer outputBuffer; + FIFOSampleBuffer inputBuffer; + BOOL bQuickseek; + BOOL bMidBufferDirty; + + uint sampleRate; + uint sequenceMs; + uint seekWindowMs; + uint overlapMs; + + void acceptNewOverlapLength(uint newOverlapLength); + + virtual void clearCrossCorrState(); + void calculateOverlapLength(uint overlapMs); + + virtual LONG_SAMPLETYPE calcCrossCorrStereo(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; + virtual LONG_SAMPLETYPE calcCrossCorrMono(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; + + virtual uint seekBestOverlapPositionStereo(const SAMPLETYPE *refPos); + virtual uint seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos); + virtual uint seekBestOverlapPositionMono(const SAMPLETYPE *refPos); + virtual uint seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos); + uint seekBestOverlapPosition(const SAMPLETYPE *refPos); + + virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const; + virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const; + + void clearMidBuffer(); + void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const; + + void precalcCorrReferenceMono(); + void precalcCorrReferenceStereo(); + + void processNominalTempo(); + + /// Changes the tempo of the given sound samples. + /// Returns amount of samples returned in the "output" buffer. + /// The maximum amount of samples that can be returned at a time is set by + /// the 'set_returnBuffer_size' function. + void processSamples(); + +public: + TDStretch(); + virtual ~TDStretch(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we've a MMX/SSE/etc-capable CPU available or not. + void *operator new(size_t s); + + /// Use this function instead of "new" operator to create a new instance of this class. + /// This function automatically chooses a correct feature set depending on if the CPU + /// supports MMX/SSE/etc extensions. + static TDStretch *newInstance(); + + /// Returns the output buffer object + FIFOSamplePipe *getOutput() { return &outputBuffer; }; + + /// Returns the input buffer object + FIFOSamplePipe *getInput() { return &inputBuffer; }; + + /// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower + /// tempo, larger faster tempo. + void setTempo(float newTempo); + + /// Returns nonzero if there aren't any samples available for outputting. + virtual void clear(); + + /// Clears the input buffer + void clearInput(); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint numChannels); + + /// Enables/disables the quick position seeking algorithm. Zero to disable, + /// nonzero to enable + void enableQuickSeek(BOOL enable); + + /// Returns nonzero if the quick seeking algorithm is enabled. + BOOL isQuickSeekEnabled() const; + + /// Sets routine control parameters. These control are certain time constants + /// defining how the sound is stretched to the desired duration. + // + /// 'sampleRate' = sample rate of the sound + /// 'sequenceMS' = one processing sequence length in milliseconds + /// 'seekwindowMS' = seeking window length for scanning the best overlapping + /// position + /// 'overlapMS' = overlapping length + void setParameters(uint sampleRate, ///< Samplerate of sound being processed (Hz) + uint sequenceMS = DEFAULT_SEQUENCE_MS, ///< Single processing sequence length (ms) + uint seekwindowMS = DEFAULT_SEEKWINDOW_MS, ///< Offset seeking window length (ms) + uint overlapMS = DEFAULT_OVERLAP_MS ///< Sequence overlapping length (ms) + ); + + /// Get routine control parameters, see setParameters() function. + /// Any of the parameters to this function can be NULL, in such case corresponding parameter + /// value isn't returned. + void getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs); + + /// Adds 'numsamples' pcs of samples from the 'samples' memory position into + /// the input of the object. + virtual void putSamples( + const SAMPLETYPE *samples, ///< Input sample data + uint numSamples ///< Number of samples in 'samples' so that one sample + ///< contains both channels if stereo + ); +}; + + + +// Implementation-specific class declarations: + +//#ifdef ALLOW_MMX +// /// Class that implements MMX optimized routines for 16bit integer samples type. +// class TDStretchMMX : public TDStretch +// { +// protected: +// long calcCrossCorrStereo(const short *mixingPos, const short *compare) const; +// virtual void overlapStereo(short *output, const short *input) const; +// virtual void clearCrossCorrState(); +// }; +//#endif /// ALLOW_MMX +// +// +//#ifdef ALLOW_3DNOW +// /// Class that implements 3DNow! optimized routines for floating point samples type. +// class TDStretch3DNow : public TDStretch +// { +// protected: +// double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; +// }; +//#endif /// ALLOW_3DNOW + + +#ifdef ALLOW_SSE + /// Class that implements SSE optimized routines for floating point samples type. + class TDStretchSSE : public TDStretch + { + protected: + double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; + }; + +#endif /// ALLOW_SSE + +} +#endif /// TDStretch_H diff --git a/3rdparty/SoundTouch/WavFile.cpp b/3rdparty/SoundTouch/WavFile.cpp index 77db8cc431..15a679871c 100644 --- a/3rdparty/SoundTouch/WavFile.cpp +++ b/3rdparty/SoundTouch/WavFile.cpp @@ -1,714 +1,714 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Classes for easy reading & writing of WAV sound files. -/// -/// For big-endian CPU, define _BIG_ENDIAN_ during compile-time to correctly -/// parse the WAV files with such processors. -/// -/// Admittingly, more complete WAV reader routines may exist in public domain, -/// but the reason for 'yet another' one is that those generic WAV reader -/// libraries are exhaustingly large and cumbersome! Wanted to have something -/// simpler here, i.e. something that's not already larger than rest of the -/// SoundTouch/SoundStretch program... -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.15 $ -// -// $Id: WavFile.cpp,v 1.15 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include - -#include -#include - -#include "WavFile.h" - -using namespace std; - -const static char riffStr[] = "RIFF"; -const static char waveStr[] = "WAVE"; -const static char fmtStr[] = "fmt "; -const static char dataStr[] = "data"; - - -////////////////////////////////////////////////////////////////////////////// -// -// Helper functions for swapping byte order to correctly read/write WAV files -// with big-endian CPU's: Define compile-time definition _BIG_ENDIAN_ to -// turn-on the conversion if it appears necessary. -// -// For example, Intel x86 is little-endian and doesn't require conversion, -// while PowerPC of Mac's and many other RISC cpu's are big-endian. - -#ifdef BYTE_ORDER - // In gcc compiler detect the byte order automatically - #if BYTE_ORDER == BIG_ENDIAN - // big-endian platform. - #define _BIG_ENDIAN_ - #endif -#endif - -#ifdef _BIG_ENDIAN_ - // big-endian CPU, swap bytes in 16 & 32 bit words - - // helper-function to swap byte-order of 32bit integer - static inline void _swap32(unsigned int &dwData) - { - dwData = ((dwData >> 24) & 0x000000FF) | - ((dwData >> 8) & 0x0000FF00) | - ((dwData << 8) & 0x00FF0000) | - ((dwData << 24) & 0xFF000000); - } - - // helper-function to swap byte-order of 16bit integer - static inline void _swap16(unsigned short &wData) - { - wData = ((wData >> 8) & 0x00FF) | - ((wData << 8) & 0xFF00); - } - - // helper-function to swap byte-order of buffer of 16bit integers - static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumWords) - { - unsigned long i; - - for (i = 0; i < dwNumWords; i ++) - { - _swap16(pData[i]); - } - } - -#else // BIG_ENDIAN - // little-endian CPU, WAV file is ok as such - - // dummy helper-function - static inline void _swap32(unsigned int &dwData) - { - // do nothing - } - - // dummy helper-function - static inline void _swap16(unsigned short &wData) - { - // do nothing - } - - // dummy helper-function - static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumBytes) - { - // do nothing - } - -#endif // BIG_ENDIAN - - -////////////////////////////////////////////////////////////////////////////// -// -// Class WavInFile -// - -WavInFile::WavInFile(const char *fileName) -{ - int hdrsOk; - - // Try to open the file for reading - fptr = fopen(fileName, "rb"); - if (fptr == NULL) - { - // didn't succeed - string msg = "Error : Unable to open file \""; - msg += fileName; - msg += "\" for reading."; - throw runtime_error(msg); - } - - // Read the file headers - hdrsOk = readWavHeaders(); - if (hdrsOk != 0) - { - // Something didn't match in the wav file headers - string msg = "File \""; - msg += fileName; - msg += "\" is corrupt or not a WAV file"; - throw runtime_error(msg); - } - - if (header.format.fixed != 1) - { - string msg = "File \""; - msg += fileName; - msg += "\" uses unsupported encoding."; - throw runtime_error(msg); - } - - dataRead = 0; -} - - - -WavInFile::~WavInFile() -{ - close(); -} - - - -void WavInFile::rewind() -{ - int hdrsOk; - - fseek(fptr, 0, SEEK_SET); - hdrsOk = readWavHeaders(); - assert(hdrsOk == 0); - dataRead = 0; -} - - -int WavInFile::checkCharTags() -{ - // header.format.fmt should equal to 'fmt ' - if (memcmp(fmtStr, header.format.fmt, 4) != 0) return -1; - // header.data.data_field should equal to 'data' - if (memcmp(dataStr, header.data.data_field, 4) != 0) return -1; - - return 0; -} - - -int WavInFile::read(char *buffer, int maxElems) -{ - int numBytes; - uint afterDataRead; - - // ensure it's 8 bit format - if (header.format.bits_per_sample != 8) - { - throw runtime_error("Error: WavInFile::read(char*, int) works only with 8bit samples."); - } - assert(sizeof(char) == 1); - - numBytes = maxElems; - afterDataRead = dataRead + numBytes; - if (afterDataRead > header.data.data_len) - { - // Don't read more samples than are marked available in header - numBytes = header.data.data_len - dataRead; - assert(numBytes >= 0); - } - - numBytes = fread(buffer, 1, numBytes, fptr); - dataRead += numBytes; - - return numBytes; -} - - -int WavInFile::read(short *buffer, int maxElems) -{ - unsigned int afterDataRead; - int numBytes; - int numElems; - - if (header.format.bits_per_sample == 8) - { - // 8 bit format - char *temp = new char[maxElems]; - int i; - - numElems = read(temp, maxElems); - // convert from 8 to 16 bit - for (i = 0; i < numElems; i ++) - { - buffer[i] = temp[i] << 8; - } - delete[] temp; - } - else - { - // 16 bit format - assert(header.format.bits_per_sample == 16); - assert(sizeof(short) == 2); - - numBytes = maxElems * 2; - afterDataRead = dataRead + numBytes; - if (afterDataRead > header.data.data_len) - { - // Don't read more samples than are marked available in header - numBytes = header.data.data_len - dataRead; - assert(numBytes >= 0); - } - - numBytes = fread(buffer, 1, numBytes, fptr); - dataRead += numBytes; - numElems = numBytes / 2; - - // 16bit samples, swap byte order if necessary - _swap16Buffer((unsigned short *)buffer, numElems); - } - - return numElems; -} - - - -int WavInFile::read(float *buffer, int maxElems) -{ - short *temp = new short[maxElems]; - int num; - int i; - double fscale; - - num = read(temp, maxElems); - - fscale = 1.0 / 32768.0; - // convert to floats, scale to range [-1..+1[ - for (i = 0; i < num; i ++) - { - buffer[i] = (float)(fscale * (double)temp[i]); - } - - delete[] temp; - - return num; -} - - -int WavInFile::eof() const -{ - // return true if all data has been read or file eof has reached - return (dataRead == header.data.data_len || feof(fptr)); -} - - -void WavInFile::close() -{ - fclose(fptr); - fptr = NULL; -} - - - -// test if character code is between a white space ' ' and little 'z' -static int isAlpha(char c) -{ - return (c >= ' ' && c <= 'z') ? 1 : 0; -} - - -// test if all characters are between a white space ' ' and little 'z' -static int isAlphaStr(char *str) -{ - int c; - - c = str[0]; - while (c) - { - if (isAlpha(c) == 0) return 0; - str ++; - c = str[0]; - } - - return 1; -} - - -int WavInFile::readRIFFBlock() -{ - fread(&(header.riff), sizeof(WavRiff), 1, fptr); - - // swap 32bit data byte order if necessary - _swap32((unsigned int &)header.riff.package_len); - - // header.riff.riff_char should equal to 'RIFF'); - if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1; - // header.riff.wave should equal to 'WAVE' - if (memcmp(waveStr, header.riff.wave, 4) != 0) return -1; - - return 0; -} - - - - -int WavInFile::readHeaderBlock() -{ - char label[5]; - string sLabel; - - // lead label string - fread(label, 1, 4, fptr); - label[4] = 0; - - if (isAlphaStr(label) == 0) return -1; // not a valid label - - // Decode blocks according to their label - if (strcmp(label, fmtStr) == 0) - { - int nLen, nDump; - - // 'fmt ' block - memcpy(header.format.fmt, fmtStr, 4); - - // read length of the format field - fread(&nLen, sizeof(int), 1, fptr); - // swap byte order if necessary - _swap32((unsigned int &)nLen); // int format_len; - header.format.format_len = nLen; - - // calculate how much length differs from expected - nDump = nLen - (sizeof(header.format) - 8); - - // if format_len is larger than expected, read only as much data as we've space for - if (nDump > 0) - { - nLen = sizeof(header.format) - 8; - } - - // read data - fread(&(header.format.fixed), nLen, 1, fptr); - - // swap byte order if necessary - _swap16((unsigned short &)header.format.fixed); // short int fixed; - _swap16((unsigned short &)header.format.channel_number); // short int channel_number; - _swap32((unsigned int &)header.format.sample_rate); // int sample_rate; - _swap32((unsigned int &)header.format.byte_rate); // int byte_rate; - _swap16((unsigned short &)header.format.byte_per_sample); // short int byte_per_sample; - _swap16((unsigned short &)header.format.bits_per_sample); // short int bits_per_sample; - - // if format_len is larger than expected, skip the extra data - if (nDump > 0) - { - fseek(fptr, nDump, SEEK_CUR); - } - - return 0; - } - else if (strcmp(label, dataStr) == 0) - { - // 'data' block - memcpy(header.data.data_field, dataStr, 4); - fread(&(header.data.data_len), sizeof(uint), 1, fptr); - - // swap byte order if necessary - _swap32((unsigned int &)header.data.data_len); - - return 1; - } - else - { - uint len, i; - uint temp; - // unknown block - - // read length - fread(&len, sizeof(len), 1, fptr); - // scan through the block - for (i = 0; i < len; i ++) - { - fread(&temp, 1, 1, fptr); - if (feof(fptr)) return -1; // unexpected eof - } - } - return 0; -} - - -int WavInFile::readWavHeaders() -{ - int res; - - memset(&header, 0, sizeof(header)); - - res = readRIFFBlock(); - if (res) return 1; - // read header blocks until data block is found - do - { - // read header blocks - res = readHeaderBlock(); - if (res < 0) return 1; // error in file structure - } while (res == 0); - // check that all required tags are legal - return checkCharTags(); -} - - -uint WavInFile::getNumChannels() const -{ - return header.format.channel_number; -} - - -uint WavInFile::getNumBits() const -{ - return header.format.bits_per_sample; -} - - -uint WavInFile::getBytesPerSample() const -{ - return getNumChannels() * getNumBits() / 8; -} - - -uint WavInFile::getSampleRate() const -{ - return header.format.sample_rate; -} - - - -uint WavInFile::getDataSizeInBytes() const -{ - return header.data.data_len; -} - - -uint WavInFile::getNumSamples() const -{ - return header.data.data_len / header.format.byte_per_sample; -} - - -uint WavInFile::getLengthMS() const -{ - uint numSamples; - uint sampleRate; - - numSamples = getNumSamples(); - sampleRate = getSampleRate(); - - assert(numSamples < UINT_MAX / 1000); - return (1000 * numSamples / sampleRate); -} - - -////////////////////////////////////////////////////////////////////////////// -// -// Class WavOutFile -// - -WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels) -{ - bytesWritten = 0; - fptr = fopen(fileName, "wb"); - if (fptr == NULL) - { - string msg = "Error : Unable to open file \""; - msg += fileName; - msg += "\" for writing."; - //pmsg = msg.c_str; - throw runtime_error(msg); - } - - fillInHeader(sampleRate, bits, channels); - writeHeader(); -} - - - -WavOutFile::~WavOutFile() -{ - close(); -} - - - -void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels) -{ - // fill in the 'riff' part.. - - // copy string 'RIFF' to riff_char - memcpy(&(header.riff.riff_char), riffStr, 4); - // package_len unknown so far - header.riff.package_len = 0; - // copy string 'WAVE' to wave - memcpy(&(header.riff.wave), waveStr, 4); - - - // fill in the 'format' part.. - - // copy string 'fmt ' to fmt - memcpy(&(header.format.fmt), fmtStr, 4); - - header.format.format_len = 0x10; - header.format.fixed = 1; - header.format.channel_number = (short)channels; - header.format.sample_rate = sampleRate; - header.format.bits_per_sample = (short)bits; - header.format.byte_per_sample = (short)(bits * channels / 8); - header.format.byte_rate = header.format.byte_per_sample * sampleRate; - header.format.sample_rate = sampleRate; - - // fill in the 'data' part.. - - // copy string 'data' to data_field - memcpy(&(header.data.data_field), dataStr, 4); - // data_len unknown so far - header.data.data_len = 0; -} - - -void WavOutFile::finishHeader() -{ - // supplement the file length into the header structure - header.riff.package_len = bytesWritten + 36; - header.data.data_len = bytesWritten; - - writeHeader(); -} - - - -void WavOutFile::writeHeader() -{ - WavHeader hdrTemp; - - // swap byte order if necessary - hdrTemp = header; - _swap32((unsigned int &)hdrTemp.riff.package_len); - _swap32((unsigned int &)hdrTemp.format.format_len); - _swap16((unsigned short &)hdrTemp.format.fixed); - _swap16((unsigned short &)hdrTemp.format.channel_number); - _swap32((unsigned int &)hdrTemp.format.sample_rate); - _swap32((unsigned int &)hdrTemp.format.byte_rate); - _swap16((unsigned short &)hdrTemp.format.byte_per_sample); - _swap16((unsigned short &)hdrTemp.format.bits_per_sample); - _swap32((unsigned int &)hdrTemp.data.data_len); - - // write the supplemented header in the beginning of the file - fseek(fptr, 0, SEEK_SET); - fwrite(&hdrTemp, sizeof(hdrTemp), 1, fptr); - // jump back to the end of the file - fseek(fptr, 0, SEEK_END); -} - - - -void WavOutFile::close() -{ - finishHeader(); - fclose(fptr); - fptr = NULL; -} - - -void WavOutFile::write(const char *buffer, int numElems) -{ - int res; - - if (header.format.bits_per_sample != 8) - { - throw runtime_error("Error: WavOutFile::write(const char*, int) accepts only 8bit samples."); - } - assert(sizeof(char) == 1); - - res = fwrite(buffer, 1, numElems, fptr); - if (res != numElems) - { - throw runtime_error("Error while writing to a wav file."); - } - - bytesWritten += numElems; -} - - -void WavOutFile::write(const short *buffer, int numElems) -{ - int res; - - // 16 bit samples - if (numElems < 1) return; // nothing to do - - if (header.format.bits_per_sample == 8) - { - int i; - char *temp = new char[numElems]; - // convert from 16bit format to 8bit format - for (i = 0; i < numElems; i ++) - { - temp[i] = buffer[i] >> 8; - } - // write in 8bit format - write(temp, numElems); - delete[] temp; - } - else - { - // 16bit format - unsigned short *pTemp = new unsigned short[numElems]; - - assert(header.format.bits_per_sample == 16); - - // allocate temp buffer to swap byte order if necessary - memcpy(pTemp, buffer, numElems * 2); - _swap16Buffer(pTemp, numElems); - - res = fwrite(pTemp, 2, numElems, fptr); - - delete[] pTemp; - - if (res != numElems) - { - throw runtime_error("Error while writing to a wav file."); - } - bytesWritten += 2 * numElems; - } -} - - -void WavOutFile::write(const float *buffer, int numElems) -{ - int i; - short *temp = new short[numElems]; - int iTemp; - - // convert to 16 bit integer - for (i = 0; i < numElems; i ++) - { - // convert to integer - iTemp = (int)(32768.0f * buffer[i]); - - // saturate - if (iTemp < -32768) iTemp = -32768; - if (iTemp > 32767) iTemp = 32767; - temp[i] = (short)iTemp; - } - - write(temp, numElems); - - delete[] temp; -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// Classes for easy reading & writing of WAV sound files. +/// +/// For big-endian CPU, define _BIG_ENDIAN_ during compile-time to correctly +/// parse the WAV files with such processors. +/// +/// Admittingly, more complete WAV reader routines may exist in public domain, +/// but the reason for 'yet another' one is that those generic WAV reader +/// libraries are exhaustingly large and cumbersome! Wanted to have something +/// simpler here, i.e. something that's not already larger than rest of the +/// SoundTouch/SoundStretch program... +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.15 $ +// +// $Id: WavFile.cpp,v 1.15 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include +#include + +#include "WavFile.h" + +using namespace std; + +const static char riffStr[] = "RIFF"; +const static char waveStr[] = "WAVE"; +const static char fmtStr[] = "fmt "; +const static char dataStr[] = "data"; + + +////////////////////////////////////////////////////////////////////////////// +// +// Helper functions for swapping byte order to correctly read/write WAV files +// with big-endian CPU's: Define compile-time definition _BIG_ENDIAN_ to +// turn-on the conversion if it appears necessary. +// +// For example, Intel x86 is little-endian and doesn't require conversion, +// while PowerPC of Mac's and many other RISC cpu's are big-endian. + +#ifdef BYTE_ORDER + // In gcc compiler detect the byte order automatically + #if BYTE_ORDER == BIG_ENDIAN + // big-endian platform. + #define _BIG_ENDIAN_ + #endif +#endif + +#ifdef _BIG_ENDIAN_ + // big-endian CPU, swap bytes in 16 & 32 bit words + + // helper-function to swap byte-order of 32bit integer + static inline void _swap32(unsigned int &dwData) + { + dwData = ((dwData >> 24) & 0x000000FF) | + ((dwData >> 8) & 0x0000FF00) | + ((dwData << 8) & 0x00FF0000) | + ((dwData << 24) & 0xFF000000); + } + + // helper-function to swap byte-order of 16bit integer + static inline void _swap16(unsigned short &wData) + { + wData = ((wData >> 8) & 0x00FF) | + ((wData << 8) & 0xFF00); + } + + // helper-function to swap byte-order of buffer of 16bit integers + static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumWords) + { + unsigned long i; + + for (i = 0; i < dwNumWords; i ++) + { + _swap16(pData[i]); + } + } + +#else // BIG_ENDIAN + // little-endian CPU, WAV file is ok as such + + // dummy helper-function + static inline void _swap32(unsigned int &dwData) + { + // do nothing + } + + // dummy helper-function + static inline void _swap16(unsigned short &wData) + { + // do nothing + } + + // dummy helper-function + static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumBytes) + { + // do nothing + } + +#endif // BIG_ENDIAN + + +////////////////////////////////////////////////////////////////////////////// +// +// Class WavInFile +// + +WavInFile::WavInFile(const char *fileName) +{ + int hdrsOk; + + // Try to open the file for reading + fptr = fopen(fileName, "rb"); + if (fptr == NULL) + { + // didn't succeed + string msg = "Error : Unable to open file \""; + msg += fileName; + msg += "\" for reading."; + throw runtime_error(msg); + } + + // Read the file headers + hdrsOk = readWavHeaders(); + if (hdrsOk != 0) + { + // Something didn't match in the wav file headers + string msg = "File \""; + msg += fileName; + msg += "\" is corrupt or not a WAV file"; + throw runtime_error(msg); + } + + if (header.format.fixed != 1) + { + string msg = "File \""; + msg += fileName; + msg += "\" uses unsupported encoding."; + throw runtime_error(msg); + } + + dataRead = 0; +} + + + +WavInFile::~WavInFile() +{ + close(); +} + + + +void WavInFile::rewind() +{ + int hdrsOk; + + fseek(fptr, 0, SEEK_SET); + hdrsOk = readWavHeaders(); + assert(hdrsOk == 0); + dataRead = 0; +} + + +int WavInFile::checkCharTags() +{ + // header.format.fmt should equal to 'fmt ' + if (memcmp(fmtStr, header.format.fmt, 4) != 0) return -1; + // header.data.data_field should equal to 'data' + if (memcmp(dataStr, header.data.data_field, 4) != 0) return -1; + + return 0; +} + + +int WavInFile::read(char *buffer, int maxElems) +{ + int numBytes; + uint afterDataRead; + + // ensure it's 8 bit format + if (header.format.bits_per_sample != 8) + { + throw runtime_error("Error: WavInFile::read(char*, int) works only with 8bit samples."); + } + assert(sizeof(char) == 1); + + numBytes = maxElems; + afterDataRead = dataRead + numBytes; + if (afterDataRead > header.data.data_len) + { + // Don't read more samples than are marked available in header + numBytes = header.data.data_len - dataRead; + assert(numBytes >= 0); + } + + numBytes = fread(buffer, 1, numBytes, fptr); + dataRead += numBytes; + + return numBytes; +} + + +int WavInFile::read(short *buffer, int maxElems) +{ + unsigned int afterDataRead; + int numBytes; + int numElems; + + if (header.format.bits_per_sample == 8) + { + // 8 bit format + char *temp = new char[maxElems]; + int i; + + numElems = read(temp, maxElems); + // convert from 8 to 16 bit + for (i = 0; i < numElems; i ++) + { + buffer[i] = temp[i] << 8; + } + delete[] temp; + } + else + { + // 16 bit format + assert(header.format.bits_per_sample == 16); + assert(sizeof(short) == 2); + + numBytes = maxElems * 2; + afterDataRead = dataRead + numBytes; + if (afterDataRead > header.data.data_len) + { + // Don't read more samples than are marked available in header + numBytes = header.data.data_len - dataRead; + assert(numBytes >= 0); + } + + numBytes = fread(buffer, 1, numBytes, fptr); + dataRead += numBytes; + numElems = numBytes / 2; + + // 16bit samples, swap byte order if necessary + _swap16Buffer((unsigned short *)buffer, numElems); + } + + return numElems; +} + + + +int WavInFile::read(float *buffer, int maxElems) +{ + short *temp = new short[maxElems]; + int num; + int i; + double fscale; + + num = read(temp, maxElems); + + fscale = 1.0 / 32768.0; + // convert to floats, scale to range [-1..+1[ + for (i = 0; i < num; i ++) + { + buffer[i] = (float)(fscale * (double)temp[i]); + } + + delete[] temp; + + return num; +} + + +int WavInFile::eof() const +{ + // return true if all data has been read or file eof has reached + return (dataRead == header.data.data_len || feof(fptr)); +} + + +void WavInFile::close() +{ + fclose(fptr); + fptr = NULL; +} + + + +// test if character code is between a white space ' ' and little 'z' +static int isAlpha(char c) +{ + return (c >= ' ' && c <= 'z') ? 1 : 0; +} + + +// test if all characters are between a white space ' ' and little 'z' +static int isAlphaStr(char *str) +{ + int c; + + c = str[0]; + while (c) + { + if (isAlpha(c) == 0) return 0; + str ++; + c = str[0]; + } + + return 1; +} + + +int WavInFile::readRIFFBlock() +{ + fread(&(header.riff), sizeof(WavRiff), 1, fptr); + + // swap 32bit data byte order if necessary + _swap32((unsigned int &)header.riff.package_len); + + // header.riff.riff_char should equal to 'RIFF'); + if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1; + // header.riff.wave should equal to 'WAVE' + if (memcmp(waveStr, header.riff.wave, 4) != 0) return -1; + + return 0; +} + + + + +int WavInFile::readHeaderBlock() +{ + char label[5]; + string sLabel; + + // lead label string + fread(label, 1, 4, fptr); + label[4] = 0; + + if (isAlphaStr(label) == 0) return -1; // not a valid label + + // Decode blocks according to their label + if (strcmp(label, fmtStr) == 0) + { + int nLen, nDump; + + // 'fmt ' block + memcpy(header.format.fmt, fmtStr, 4); + + // read length of the format field + fread(&nLen, sizeof(int), 1, fptr); + // swap byte order if necessary + _swap32((unsigned int &)nLen); // int format_len; + header.format.format_len = nLen; + + // calculate how much length differs from expected + nDump = nLen - (sizeof(header.format) - 8); + + // if format_len is larger than expected, read only as much data as we've space for + if (nDump > 0) + { + nLen = sizeof(header.format) - 8; + } + + // read data + fread(&(header.format.fixed), nLen, 1, fptr); + + // swap byte order if necessary + _swap16((unsigned short &)header.format.fixed); // short int fixed; + _swap16((unsigned short &)header.format.channel_number); // short int channel_number; + _swap32((unsigned int &)header.format.sample_rate); // int sample_rate; + _swap32((unsigned int &)header.format.byte_rate); // int byte_rate; + _swap16((unsigned short &)header.format.byte_per_sample); // short int byte_per_sample; + _swap16((unsigned short &)header.format.bits_per_sample); // short int bits_per_sample; + + // if format_len is larger than expected, skip the extra data + if (nDump > 0) + { + fseek(fptr, nDump, SEEK_CUR); + } + + return 0; + } + else if (strcmp(label, dataStr) == 0) + { + // 'data' block + memcpy(header.data.data_field, dataStr, 4); + fread(&(header.data.data_len), sizeof(uint), 1, fptr); + + // swap byte order if necessary + _swap32((unsigned int &)header.data.data_len); + + return 1; + } + else + { + uint len, i; + uint temp; + // unknown block + + // read length + fread(&len, sizeof(len), 1, fptr); + // scan through the block + for (i = 0; i < len; i ++) + { + fread(&temp, 1, 1, fptr); + if (feof(fptr)) return -1; // unexpected eof + } + } + return 0; +} + + +int WavInFile::readWavHeaders() +{ + int res; + + memset(&header, 0, sizeof(header)); + + res = readRIFFBlock(); + if (res) return 1; + // read header blocks until data block is found + do + { + // read header blocks + res = readHeaderBlock(); + if (res < 0) return 1; // error in file structure + } while (res == 0); + // check that all required tags are legal + return checkCharTags(); +} + + +uint WavInFile::getNumChannels() const +{ + return header.format.channel_number; +} + + +uint WavInFile::getNumBits() const +{ + return header.format.bits_per_sample; +} + + +uint WavInFile::getBytesPerSample() const +{ + return getNumChannels() * getNumBits() / 8; +} + + +uint WavInFile::getSampleRate() const +{ + return header.format.sample_rate; +} + + + +uint WavInFile::getDataSizeInBytes() const +{ + return header.data.data_len; +} + + +uint WavInFile::getNumSamples() const +{ + return header.data.data_len / header.format.byte_per_sample; +} + + +uint WavInFile::getLengthMS() const +{ + uint numSamples; + uint sampleRate; + + numSamples = getNumSamples(); + sampleRate = getSampleRate(); + + assert(numSamples < UINT_MAX / 1000); + return (1000 * numSamples / sampleRate); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// Class WavOutFile +// + +WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels) +{ + bytesWritten = 0; + fptr = fopen(fileName, "wb"); + if (fptr == NULL) + { + string msg = "Error : Unable to open file \""; + msg += fileName; + msg += "\" for writing."; + //pmsg = msg.c_str; + throw runtime_error(msg); + } + + fillInHeader(sampleRate, bits, channels); + writeHeader(); +} + + + +WavOutFile::~WavOutFile() +{ + close(); +} + + + +void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels) +{ + // fill in the 'riff' part.. + + // copy string 'RIFF' to riff_char + memcpy(&(header.riff.riff_char), riffStr, 4); + // package_len unknown so far + header.riff.package_len = 0; + // copy string 'WAVE' to wave + memcpy(&(header.riff.wave), waveStr, 4); + + + // fill in the 'format' part.. + + // copy string 'fmt ' to fmt + memcpy(&(header.format.fmt), fmtStr, 4); + + header.format.format_len = 0x10; + header.format.fixed = 1; + header.format.channel_number = (short)channels; + header.format.sample_rate = sampleRate; + header.format.bits_per_sample = (short)bits; + header.format.byte_per_sample = (short)(bits * channels / 8); + header.format.byte_rate = header.format.byte_per_sample * sampleRate; + header.format.sample_rate = sampleRate; + + // fill in the 'data' part.. + + // copy string 'data' to data_field + memcpy(&(header.data.data_field), dataStr, 4); + // data_len unknown so far + header.data.data_len = 0; +} + + +void WavOutFile::finishHeader() +{ + // supplement the file length into the header structure + header.riff.package_len = bytesWritten + 36; + header.data.data_len = bytesWritten; + + writeHeader(); +} + + + +void WavOutFile::writeHeader() +{ + WavHeader hdrTemp; + + // swap byte order if necessary + hdrTemp = header; + _swap32((unsigned int &)hdrTemp.riff.package_len); + _swap32((unsigned int &)hdrTemp.format.format_len); + _swap16((unsigned short &)hdrTemp.format.fixed); + _swap16((unsigned short &)hdrTemp.format.channel_number); + _swap32((unsigned int &)hdrTemp.format.sample_rate); + _swap32((unsigned int &)hdrTemp.format.byte_rate); + _swap16((unsigned short &)hdrTemp.format.byte_per_sample); + _swap16((unsigned short &)hdrTemp.format.bits_per_sample); + _swap32((unsigned int &)hdrTemp.data.data_len); + + // write the supplemented header in the beginning of the file + fseek(fptr, 0, SEEK_SET); + fwrite(&hdrTemp, sizeof(hdrTemp), 1, fptr); + // jump back to the end of the file + fseek(fptr, 0, SEEK_END); +} + + + +void WavOutFile::close() +{ + finishHeader(); + fclose(fptr); + fptr = NULL; +} + + +void WavOutFile::write(const char *buffer, int numElems) +{ + int res; + + if (header.format.bits_per_sample != 8) + { + throw runtime_error("Error: WavOutFile::write(const char*, int) accepts only 8bit samples."); + } + assert(sizeof(char) == 1); + + res = fwrite(buffer, 1, numElems, fptr); + if (res != numElems) + { + throw runtime_error("Error while writing to a wav file."); + } + + bytesWritten += numElems; +} + + +void WavOutFile::write(const short *buffer, int numElems) +{ + int res; + + // 16 bit samples + if (numElems < 1) return; // nothing to do + + if (header.format.bits_per_sample == 8) + { + int i; + char *temp = new char[numElems]; + // convert from 16bit format to 8bit format + for (i = 0; i < numElems; i ++) + { + temp[i] = buffer[i] >> 8; + } + // write in 8bit format + write(temp, numElems); + delete[] temp; + } + else + { + // 16bit format + unsigned short *pTemp = new unsigned short[numElems]; + + assert(header.format.bits_per_sample == 16); + + // allocate temp buffer to swap byte order if necessary + memcpy(pTemp, buffer, numElems * 2); + _swap16Buffer(pTemp, numElems); + + res = fwrite(pTemp, 2, numElems, fptr); + + delete[] pTemp; + + if (res != numElems) + { + throw runtime_error("Error while writing to a wav file."); + } + bytesWritten += 2 * numElems; + } +} + + +void WavOutFile::write(const float *buffer, int numElems) +{ + int i; + short *temp = new short[numElems]; + int iTemp; + + // convert to 16 bit integer + for (i = 0; i < numElems; i ++) + { + // convert to integer + iTemp = (int)(32768.0f * buffer[i]); + + // saturate + if (iTemp < -32768) iTemp = -32768; + if (iTemp > 32767) iTemp = 32767; + temp[i] = (short)iTemp; + } + + write(temp, numElems); + + delete[] temp; +} diff --git a/3rdparty/SoundTouch/WavFile.h b/3rdparty/SoundTouch/WavFile.h index dd239034d2..331ef4d3e9 100644 --- a/3rdparty/SoundTouch/WavFile.h +++ b/3rdparty/SoundTouch/WavFile.h @@ -1,253 +1,253 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Classes for easy reading & writing of WAV sound files. -/// -/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly -/// parse the WAV files with such processors. -/// -/// Admittingly, more complete WAV reader routines may exist in public domain, but -/// the reason for 'yet another' one is that those generic WAV reader libraries are -/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e. -/// something that's not already larger than rest of the SoundTouch/SoundStretch program... -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.7 $ -// -// $Id: WavFile.h,v 1.7 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef WAVFILE_H -#define WAVFILE_H - -#include - -#ifndef uint -typedef unsigned int uint; -#endif - - -/// WAV audio file 'riff' section header -typedef struct -{ - char riff_char[4]; - int package_len; - char wave[4]; -} WavRiff; - -/// WAV audio file 'format' section header -typedef struct -{ - char fmt[4]; - int format_len; - short fixed; - short channel_number; - int sample_rate; - int byte_rate; - short byte_per_sample; - short bits_per_sample; -} WavFormat; - -/// WAV audio file 'data' section header -typedef struct -{ - char data_field[4]; - uint data_len; -} WavData; - - -/// WAV audio file header -typedef struct -{ - WavRiff riff; - WavFormat format; - WavData data; -} WavHeader; - - -/// Class for reading WAV audio files. -class WavInFile -{ -private: - /// File pointer. - FILE *fptr; - - /// Counter of how many bytes of sample data have been read from the file. - uint dataRead; - - /// WAV header information - WavHeader header; - - /// Read WAV file headers. - /// \return zero if all ok, nonzero if file format is invalid. - int readWavHeaders(); - - /// Checks WAV file header tags. - /// \return zero if all ok, nonzero if file format is invalid. - int checkCharTags(); - - /// Reads a single WAV file header block. - /// \return zero if all ok, nonzero if file format is invalid. - int readHeaderBlock(); - - /// Reads WAV file 'riff' block - int readRIFFBlock(); - -public: - /// Constructor: Opens the given WAV file. If the file can't be opened, - /// throws 'runtime_error' exception. - WavInFile(const char *filename); - - /// Destructor: Closes the file. - ~WavInFile(); - - /// Close the file. Notice that file is automatically closed also when the - /// class instance is deleted. - void close(); - - /// Rewind to beginning of the file - void rewind(); - - /// Get sample rate. - uint getSampleRate() const; - - /// Get number of bits per sample, i.e. 8 or 16. - uint getNumBits() const; - - /// Get sample data size in bytes. Ahem, this should return same information as - /// 'getBytesPerSample'... - uint getDataSizeInBytes() const; - - /// Get total number of samples in file. - uint getNumSamples() const; - - /// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample) - uint getBytesPerSample() const; - - /// Get number of audio channels in the file (1=mono, 2=stereo) - uint getNumChannels() const; - - /// Get the audio file length in milliseconds - uint getLengthMS() const; - - /// Reads audio samples from the WAV file. This routine works only for 8 bit samples. - /// Reads given number of elements from the file or if end-of-file reached, as many - /// elements as are left in the file. - /// - /// \return Number of 8-bit integers read from the file. - int read(char *buffer, int maxElems); - - /// Reads audio samples from the WAV file to 16 bit integer format. Reads given number - /// of elements from the file or if end-of-file reached, as many elements as are - /// left in the file. - /// - /// \return Number of 16-bit integers read from the file. - int read(short *buffer, ///< Pointer to buffer where to read data. - int maxElems ///< Size of 'buffer' array (number of array elements). - ); - - /// Reads audio samples from the WAV file to floating point format, converting - /// sample values to range [-1,1[. Reads given number of elements from the file - /// or if end-of-file reached, as many elements as are left in the file. - /// - /// \return Number of elements read from the file. - int read(float *buffer, ///< Pointer to buffer where to read data. - int maxElems ///< Size of 'buffer' array (number of array elements). - ); - - /// Check end-of-file. - /// - /// \return Nonzero if end-of-file reached. - int eof() const; -}; - - - -/// Class for writing WAV audio files. -class WavOutFile -{ -private: - /// Pointer to the WAV file - FILE *fptr; - - /// WAV file header data. - WavHeader header; - - /// Counter of how many bytes have been written to the file so far. - int bytesWritten; - - /// Fills in WAV file header information. - void fillInHeader(const uint sampleRate, const uint bits, const uint channels); - - /// Finishes the WAV file header by supplementing information of amount of - /// data written to file etc - void finishHeader(); - - /// Writes the WAV file header. - void writeHeader(); - -public: - /// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception - /// if file creation fails. - WavOutFile(const char *fileName, ///< Filename - int sampleRate, ///< Sample rate (e.g. 44100 etc) - int bits, ///< Bits per sample (8 or 16 bits) - int channels ///< Number of channels (1=mono, 2=stereo) - ); - - /// Destructor: Finalizes & closes the WAV file. - ~WavOutFile(); - - /// Write data to WAV file. This function works only with 8bit samples. - /// Throws a 'runtime_error' exception if writing to file fails. - void write(const char *buffer, ///< Pointer to sample data buffer. - int numElems ///< How many array items are to be written to file. - ); - - /// Write data to WAV file. Throws a 'runtime_error' exception if writing to - /// file fails. - void write(const short *buffer, ///< Pointer to sample data buffer. - int numElems ///< How many array items are to be written to file. - ); - - /// Write data to WAV file in floating point format, saturating sample values to range - /// [-1..+1[. Throws a 'runtime_error' exception if writing to file fails. - void write(const float *buffer, ///< Pointer to sample data buffer. - int numElems ///< How many array items are to be written to file. - ); - - /// Finalize & close the WAV file. Automatically supplements the WAV file header - /// information according to written data etc. - /// - /// Notice that file is automatically closed also when the class instance is deleted. - void close(); -}; - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// Classes for easy reading & writing of WAV sound files. +/// +/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly +/// parse the WAV files with such processors. +/// +/// Admittingly, more complete WAV reader routines may exist in public domain, but +/// the reason for 'yet another' one is that those generic WAV reader libraries are +/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e. +/// something that's not already larger than rest of the SoundTouch/SoundStretch program... +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.7 $ +// +// $Id: WavFile.h,v 1.7 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef WAVFILE_H +#define WAVFILE_H + +#include + +#ifndef uint +typedef unsigned int uint; +#endif + + +/// WAV audio file 'riff' section header +typedef struct +{ + char riff_char[4]; + int package_len; + char wave[4]; +} WavRiff; + +/// WAV audio file 'format' section header +typedef struct +{ + char fmt[4]; + int format_len; + short fixed; + short channel_number; + int sample_rate; + int byte_rate; + short byte_per_sample; + short bits_per_sample; +} WavFormat; + +/// WAV audio file 'data' section header +typedef struct +{ + char data_field[4]; + uint data_len; +} WavData; + + +/// WAV audio file header +typedef struct +{ + WavRiff riff; + WavFormat format; + WavData data; +} WavHeader; + + +/// Class for reading WAV audio files. +class WavInFile +{ +private: + /// File pointer. + FILE *fptr; + + /// Counter of how many bytes of sample data have been read from the file. + uint dataRead; + + /// WAV header information + WavHeader header; + + /// Read WAV file headers. + /// \return zero if all ok, nonzero if file format is invalid. + int readWavHeaders(); + + /// Checks WAV file header tags. + /// \return zero if all ok, nonzero if file format is invalid. + int checkCharTags(); + + /// Reads a single WAV file header block. + /// \return zero if all ok, nonzero if file format is invalid. + int readHeaderBlock(); + + /// Reads WAV file 'riff' block + int readRIFFBlock(); + +public: + /// Constructor: Opens the given WAV file. If the file can't be opened, + /// throws 'runtime_error' exception. + WavInFile(const char *filename); + + /// Destructor: Closes the file. + ~WavInFile(); + + /// Close the file. Notice that file is automatically closed also when the + /// class instance is deleted. + void close(); + + /// Rewind to beginning of the file + void rewind(); + + /// Get sample rate. + uint getSampleRate() const; + + /// Get number of bits per sample, i.e. 8 or 16. + uint getNumBits() const; + + /// Get sample data size in bytes. Ahem, this should return same information as + /// 'getBytesPerSample'... + uint getDataSizeInBytes() const; + + /// Get total number of samples in file. + uint getNumSamples() const; + + /// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample) + uint getBytesPerSample() const; + + /// Get number of audio channels in the file (1=mono, 2=stereo) + uint getNumChannels() const; + + /// Get the audio file length in milliseconds + uint getLengthMS() const; + + /// Reads audio samples from the WAV file. This routine works only for 8 bit samples. + /// Reads given number of elements from the file or if end-of-file reached, as many + /// elements as are left in the file. + /// + /// \return Number of 8-bit integers read from the file. + int read(char *buffer, int maxElems); + + /// Reads audio samples from the WAV file to 16 bit integer format. Reads given number + /// of elements from the file or if end-of-file reached, as many elements as are + /// left in the file. + /// + /// \return Number of 16-bit integers read from the file. + int read(short *buffer, ///< Pointer to buffer where to read data. + int maxElems ///< Size of 'buffer' array (number of array elements). + ); + + /// Reads audio samples from the WAV file to floating point format, converting + /// sample values to range [-1,1[. Reads given number of elements from the file + /// or if end-of-file reached, as many elements as are left in the file. + /// + /// \return Number of elements read from the file. + int read(float *buffer, ///< Pointer to buffer where to read data. + int maxElems ///< Size of 'buffer' array (number of array elements). + ); + + /// Check end-of-file. + /// + /// \return Nonzero if end-of-file reached. + int eof() const; +}; + + + +/// Class for writing WAV audio files. +class WavOutFile +{ +private: + /// Pointer to the WAV file + FILE *fptr; + + /// WAV file header data. + WavHeader header; + + /// Counter of how many bytes have been written to the file so far. + int bytesWritten; + + /// Fills in WAV file header information. + void fillInHeader(const uint sampleRate, const uint bits, const uint channels); + + /// Finishes the WAV file header by supplementing information of amount of + /// data written to file etc + void finishHeader(); + + /// Writes the WAV file header. + void writeHeader(); + +public: + /// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception + /// if file creation fails. + WavOutFile(const char *fileName, ///< Filename + int sampleRate, ///< Sample rate (e.g. 44100 etc) + int bits, ///< Bits per sample (8 or 16 bits) + int channels ///< Number of channels (1=mono, 2=stereo) + ); + + /// Destructor: Finalizes & closes the WAV file. + ~WavOutFile(); + + /// Write data to WAV file. This function works only with 8bit samples. + /// Throws a 'runtime_error' exception if writing to file fails. + void write(const char *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Write data to WAV file. Throws a 'runtime_error' exception if writing to + /// file fails. + void write(const short *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Write data to WAV file in floating point format, saturating sample values to range + /// [-1..+1[. Throws a 'runtime_error' exception if writing to file fails. + void write(const float *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Finalize & close the WAV file. Automatically supplements the WAV file header + /// information according to written data etc. + /// + /// Notice that file is automatically closed also when the class instance is deleted. + void close(); +}; + +#endif diff --git a/3rdparty/SoundTouch/cpu_detect.h b/3rdparty/SoundTouch/cpu_detect.h index 568817f17b..69892102c9 100644 --- a/3rdparty/SoundTouch/cpu_detect.h +++ b/3rdparty/SoundTouch/cpu_detect.h @@ -1,62 +1,62 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// A header file for detecting the Intel MMX instructions set extension. -/// -/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the -/// routine implementations for x86 Windows, x86 gnu version and non-x86 -/// platforms, respectively. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.4 $ -// -// $Id: cpu_detect.h,v 1.4 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef _CPU_DETECT_H_ -#define _CPU_DETECT_H_ - -#include "STTypes.h" - -#define SUPPORT_MMX 0x0001 -#define SUPPORT_3DNOW 0x0002 -#define SUPPORT_ALTIVEC 0x0004 -#define SUPPORT_SSE 0x0008 -#define SUPPORT_SSE2 0x0010 - -/// Checks which instruction set extensions are supported by the CPU. -/// -/// \return A bitmask of supported extensions, see SUPPORT_... defines. -uint detectCPUextensions(void); - -/// Disables given set of instruction extensions. See SUPPORT_... defines. -void disableExtensions(uint wDisableMask); - -#endif // _CPU_DETECT_H_ +//////////////////////////////////////////////////////////////////////////////// +/// +/// A header file for detecting the Intel MMX instructions set extension. +/// +/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the +/// routine implementations for x86 Windows, x86 gnu version and non-x86 +/// platforms, respectively. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.4 $ +// +// $Id: cpu_detect.h,v 1.4 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _CPU_DETECT_H_ +#define _CPU_DETECT_H_ + +#include "STTypes.h" + +#define SUPPORT_MMX 0x0001 +#define SUPPORT_3DNOW 0x0002 +#define SUPPORT_ALTIVEC 0x0004 +#define SUPPORT_SSE 0x0008 +#define SUPPORT_SSE2 0x0010 + +/// Checks which instruction set extensions are supported by the CPU. +/// +/// \return A bitmask of supported extensions, see SUPPORT_... defines. +uint detectCPUextensions(void); + +/// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint wDisableMask); + +#endif // _CPU_DETECT_H_ diff --git a/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp b/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp index 75bd771099..68423c3a0e 100644 --- a/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp +++ b/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp @@ -1,138 +1,138 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// gcc version of the x86 CPU detect routine. -/// -/// This file is to be compiled on any platform with the GNU C compiler. -/// Compiler. Please see 'cpu_detect_x86_win.cpp' for the x86 Windows version -/// of this file. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.6 $ -// -// $Id: cpu_detect_x86_gcc.cpp,v 1.6 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include "cpu_detect.h" - -#ifndef __GNUC__ -#error wrong platform - this source code file is for the GNU C compiler. -#endif - -using namespace std; - -#include -////////////////////////////////////////////////////////////////////////////// -// -// processor instructions extension detection routines -// -////////////////////////////////////////////////////////////////////////////// - - -// Flag variable indicating whick ISA extensions are disabled (for debugging) -static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions - -// Disables given set of instruction extensions. See SUPPORT_... defines. -void disableExtensions(uint dwDisableMask) -{ - _dwDisabledISA = dwDisableMask; -} - - - -/// Checks which instruction set extensions are supported by the CPU. -uint detectCPUextensions(void) -{ -#ifndef __i386__ - return 0; // always disable extensions on non-x86 platforms. -#else - uint res = 0; - - if (_dwDisabledISA == 0xffffffff) return 0; - - asm volatile( - "\n\txor %%esi, %%esi" // clear %%esi = result register - // check if 'cpuid' instructions is available by toggling eflags bit 21 - - "\n\tpushf" // save eflags to stack - "\n\tpop %%eax" // load eax from stack (with eflags) - "\n\tmovl %%eax, %%ecx" // save the original eflags values to ecx - "\n\txor $0x00200000, %%eax" // toggle bit 21 - "\n\tpush %%eax" // store toggled eflags to stack - "\n\tpopf" // load eflags from stack - "\n\tpushf" // save updated eflags to stack - "\n\tpop %%eax" // load from stack - "\n\txor %%edx, %%edx" // clear edx for defaulting no mmx - "\n\tcmp %%ecx, %%eax" // compare to original eflags values - "\n\tjz end" // jumps to 'end' if cpuid not present - - // cpuid instruction available, test for presence of mmx instructions - - "\n\tmovl $1, %%eax" - "\n\tcpuid" -// movl $0x00800000, %edx // force enable MMX - "\n\ttest $0x00800000, %%edx" - "\n\tjz end" // branch if MMX not available - - "\n\tor $0x01, %%esi" // otherwise add MMX support bit - - "\n\ttest $0x02000000, %%edx" - "\n\tjz test3DNow" // branch if SSE not available - - "\n\tor $0x08, %%esi" // otherwise add SSE support bit - - "\n\ttest3DNow:" - // test for precense of AMD extensions - "\n\tmov $0x80000000, %%eax" - "\n\tcpuid" - "\n\tcmp $0x80000000, %%eax" - "\n\tjbe end" // branch if no AMD extensions detected - - // test for precense of 3DNow! extension - "\n\tmov $0x80000001, %%eax" - "\n\tcpuid" - "\n\ttest $0x80000000, %%edx" - "\n\tjz end" // branch if 3DNow! not detected - - "\n\tor $0x02, %%esi" // otherwise add 3DNow support bit - - "\n\tend:" - - "\n\tmov %%esi, %0" - - : "=r" (res) - : /* no inputs */ - : "%edx", "%eax", "%ecx", "%esi" ); - - return res & ~_dwDisabledISA; -#endif -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// gcc version of the x86 CPU detect routine. +/// +/// This file is to be compiled on any platform with the GNU C compiler. +/// Compiler. Please see 'cpu_detect_x86_win.cpp' for the x86 Windows version +/// of this file. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.6 $ +// +// $Id: cpu_detect_x86_gcc.cpp,v 1.6 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "cpu_detect.h" + +#ifndef __GNUC__ +#error wrong platform - this source code file is for the GNU C compiler. +#endif + +using namespace std; + +#include +////////////////////////////////////////////////////////////////////////////// +// +// processor instructions extension detection routines +// +////////////////////////////////////////////////////////////////////////////// + + +// Flag variable indicating whick ISA extensions are disabled (for debugging) +static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions + +// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint dwDisableMask) +{ + _dwDisabledISA = dwDisableMask; +} + + + +/// Checks which instruction set extensions are supported by the CPU. +uint detectCPUextensions(void) +{ +#ifndef __i386__ + return 0; // always disable extensions on non-x86 platforms. +#else + uint res = 0; + + if (_dwDisabledISA == 0xffffffff) return 0; + + asm volatile( + "\n\txor %%esi, %%esi" // clear %%esi = result register + // check if 'cpuid' instructions is available by toggling eflags bit 21 + + "\n\tpushf" // save eflags to stack + "\n\tpop %%eax" // load eax from stack (with eflags) + "\n\tmovl %%eax, %%ecx" // save the original eflags values to ecx + "\n\txor $0x00200000, %%eax" // toggle bit 21 + "\n\tpush %%eax" // store toggled eflags to stack + "\n\tpopf" // load eflags from stack + "\n\tpushf" // save updated eflags to stack + "\n\tpop %%eax" // load from stack + "\n\txor %%edx, %%edx" // clear edx for defaulting no mmx + "\n\tcmp %%ecx, %%eax" // compare to original eflags values + "\n\tjz end" // jumps to 'end' if cpuid not present + + // cpuid instruction available, test for presence of mmx instructions + + "\n\tmovl $1, %%eax" + "\n\tcpuid" +// movl $0x00800000, %edx // force enable MMX + "\n\ttest $0x00800000, %%edx" + "\n\tjz end" // branch if MMX not available + + "\n\tor $0x01, %%esi" // otherwise add MMX support bit + + "\n\ttest $0x02000000, %%edx" + "\n\tjz test3DNow" // branch if SSE not available + + "\n\tor $0x08, %%esi" // otherwise add SSE support bit + + "\n\ttest3DNow:" + // test for precense of AMD extensions + "\n\tmov $0x80000000, %%eax" + "\n\tcpuid" + "\n\tcmp $0x80000000, %%eax" + "\n\tjbe end" // branch if no AMD extensions detected + + // test for precense of 3DNow! extension + "\n\tmov $0x80000001, %%eax" + "\n\tcpuid" + "\n\ttest $0x80000000, %%edx" + "\n\tjz end" // branch if 3DNow! not detected + + "\n\tor $0x02, %%esi" // otherwise add 3DNow support bit + + "\n\tend:" + + "\n\tmov %%esi, %0" + + : "=r" (res) + : /* no inputs */ + : "%edx", "%eax", "%ecx", "%esi" ); + + return res & ~_dwDisabledISA; +#endif +} diff --git a/3rdparty/SoundTouch/cpu_detect_x86_win.cpp b/3rdparty/SoundTouch/cpu_detect_x86_win.cpp index d8f9e58dd0..ee3acf69f7 100644 --- a/3rdparty/SoundTouch/cpu_detect_x86_win.cpp +++ b/3rdparty/SoundTouch/cpu_detect_x86_win.cpp @@ -1,126 +1,126 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Win32 version of the x86 CPU detect routine. -/// -/// This file is to be compiled in Windows platform with Microsoft Visual C++ -/// Compiler. Please see 'cpu_detect_x86_gcc.cpp' for the gcc compiler version -/// for all GNU platforms. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.10 $ -// -// $Id: cpu_detect_x86_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include "cpu_detect.h" - -#ifndef _WIN32 -#error wrong platform - this source code file is exclusively for Win32 platform -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// processor instructions extension detection routines -// -////////////////////////////////////////////////////////////////////////////// - -// Flag variable indicating whick ISA extensions are disabled (for debugging) -static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions - - -// Disables given set of instruction extensions. See SUPPORT_... defines. -void disableExtensions(uint dwDisableMask) -{ - _dwDisabledISA = dwDisableMask; -} - - - -/// Checks which instruction set extensions are supported by the CPU. -uint detectCPUextensions(void) -{ - uint res = 0; - - if (_dwDisabledISA == 0xffffffff) return 0; - - _asm - { - ; check if 'cpuid' instructions is available by toggling eflags bit 21 - ; - xor esi, esi ; clear esi = result register - - pushfd ; save eflags to stack - pop eax ; load eax from stack (with eflags) - mov ecx, eax ; save the original eflags values to ecx - xor eax, 0x00200000 ; toggle bit 21 - push eax ; store toggled eflags to stack - popfd ; load eflags from stack - pushfd ; save updated eflags to stack - pop eax ; load from stack - xor edx, edx ; clear edx for defaulting no mmx - cmp eax, ecx ; compare to original eflags values - jz end ; jumps to 'end' if cpuid not present - - ; cpuid instruction available, test for presence of mmx instructions - mov eax, 1 - cpuid - test edx, 0x00800000 - jz end ; branch if MMX not available - - or esi, SUPPORT_MMX ; otherwise add MMX support bit - - test edx, 0x02000000 - jz test3DNow ; branch if SSE not available - - or esi, SUPPORT_SSE ; otherwise add SSE support bit - - test3DNow: - ; test for precense of AMD extensions - mov eax, 0x80000000 - cpuid - cmp eax, 0x80000000 - jbe end ; branch if no AMD extensions detected - - ; test for precense of 3DNow! extension - mov eax, 0x80000001 - cpuid - test edx, 0x80000000 - jz end ; branch if 3DNow! not detected - - or esi, SUPPORT_3DNOW ; otherwise add 3DNow support bit - - end: - - mov res, esi - } - - return res & ~_dwDisabledISA; -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// Win32 version of the x86 CPU detect routine. +/// +/// This file is to be compiled in Windows platform with Microsoft Visual C++ +/// Compiler. Please see 'cpu_detect_x86_gcc.cpp' for the gcc compiler version +/// for all GNU platforms. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: cpu_detect_x86_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" + +#ifndef _WIN32 +#error wrong platform - this source code file is exclusively for Win32 platform +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// processor instructions extension detection routines +// +////////////////////////////////////////////////////////////////////////////// + +// Flag variable indicating whick ISA extensions are disabled (for debugging) +static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions + + +// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint dwDisableMask) +{ + _dwDisabledISA = dwDisableMask; +} + + + +/// Checks which instruction set extensions are supported by the CPU. +uint detectCPUextensions(void) +{ + uint res = 0; + + if (_dwDisabledISA == 0xffffffff) return 0; + + _asm + { + ; check if 'cpuid' instructions is available by toggling eflags bit 21 + ; + xor esi, esi ; clear esi = result register + + pushfd ; save eflags to stack + pop eax ; load eax from stack (with eflags) + mov ecx, eax ; save the original eflags values to ecx + xor eax, 0x00200000 ; toggle bit 21 + push eax ; store toggled eflags to stack + popfd ; load eflags from stack + pushfd ; save updated eflags to stack + pop eax ; load from stack + xor edx, edx ; clear edx for defaulting no mmx + cmp eax, ecx ; compare to original eflags values + jz end ; jumps to 'end' if cpuid not present + + ; cpuid instruction available, test for presence of mmx instructions + mov eax, 1 + cpuid + test edx, 0x00800000 + jz end ; branch if MMX not available + + or esi, SUPPORT_MMX ; otherwise add MMX support bit + + test edx, 0x02000000 + jz test3DNow ; branch if SSE not available + + or esi, SUPPORT_SSE ; otherwise add SSE support bit + + test3DNow: + ; test for precense of AMD extensions + mov eax, 0x80000000 + cpuid + cmp eax, 0x80000000 + jbe end ; branch if no AMD extensions detected + + ; test for precense of 3DNow! extension + mov eax, 0x80000001 + cpuid + test edx, 0x80000000 + jz end ; branch if 3DNow! not detected + + or esi, SUPPORT_3DNOW ; otherwise add 3DNow support bit + + end: + + mov res, esi + } + + return res & ~_dwDisabledISA; +} diff --git a/3rdparty/SoundTouch/mmx_optimized.cpp b/3rdparty/SoundTouch/mmx_optimized.cpp index f5afb595a5..b49584b694 100644 --- a/3rdparty/SoundTouch/mmx_optimized.cpp +++ b/3rdparty/SoundTouch/mmx_optimized.cpp @@ -1,305 +1,305 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// MMX optimized routines. All MMX optimized functions have been gathered into -/// this single source code file, regardless to their class or original source -/// code file, in order to ease porting the library to other compiler and -/// processor platforms. -/// -/// The MMX-optimizations are programmed using MMX compiler intrinsics that -/// are supported both by Microsoft Visual C++ and GCC compilers, so this file -/// should compile with both toolsets. -/// -/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ -/// 6.0 processor pack" update to support compiler intrinsic syntax. The update -/// is available for download at Microsoft Developers Network, see here: -/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/06 18:52:43 $ -// File revision : $Revision: 1.1 $ -// -// $Id: mmx_optimized.cpp,v 1.1 2006/02/06 18:52:43 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include "STTypes.h" - -#ifdef ALLOW_MMX -// MMX routines available only with integer sample type - -#if !(_WIN32 || __i386__ || __x86_64__) -#error "wrong platform - this source code file is exclusively for x86 platforms" -#endif - -using namespace soundtouch; - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of MMX optimized functions of class 'TDStretchMMX' -// -////////////////////////////////////////////////////////////////////////////// - -#include "TDStretch.h" -#include -#include - - -// Calculates cross correlation of two buffers -long TDStretchMMX::calcCrossCorrStereo(const short *pV1, const short *pV2) const -{ - const __m64 *pVec1, *pVec2; - __m64 shifter; - __m64 accu; - long corr; - uint i; - - pVec1 = (__m64*)pV1; - pVec2 = (__m64*)pV2; - - shifter = _m_from_int(overlapDividerBits); - accu = _mm_setzero_si64(); - - // Process 4 parallel sets of 2 * stereo samples each during each - // round to improve CPU-level parallellization. - for (i = 0; i < overlapLength / 8; i ++) - { - __m64 temp; - - // dictionary of instructions: - // _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3] - // _mm_add_pi32 : 2*32bit add - // _m_psrad : 32bit right-shift - - temp = _mm_add_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), - _mm_madd_pi16(pVec1[1], pVec2[1])); - accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); - - temp = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), - _mm_madd_pi16(pVec1[3], pVec2[3])); - accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); - - pVec1 += 4; - pVec2 += 4; - } - - // copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1 - // and finally store the result into the variable "corr" - - accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32)); - corr = _m_to_int(accu); - - // Clear MMS state - _m_empty(); - - return corr; - // Note: Warning about the missing EMMS instruction is harmless - // as it'll be called elsewhere. -} - - - -void TDStretchMMX::clearCrossCorrState() -{ - // Clear MMS state - _m_empty(); - //_asm EMMS; -} - - - -// MMX-optimized version of the function overlapStereo -void TDStretchMMX::overlapStereo(short *output, const short *input) const -{ - const __m64 *pVinput, *pVMidBuf; - __m64 *pVdest; - __m64 mix1, mix2, adder, shifter; - uint i; - - pVinput = (const __m64*)input; - pVMidBuf = (const __m64*)pMidBuffer; - pVdest = (__m64*)output; - - // mix1 = mixer values for 1st stereo sample - // mix1 = mixer values for 2nd stereo sample - // adder = adder for updating mixer values after each round - - mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength); - adder = _mm_set_pi16(1, -1, 1, -1); - mix2 = _mm_add_pi16(mix1, adder); - adder = _mm_add_pi16(adder, adder); - - shifter = _m_from_int(overlapDividerBits); - - for (i = 0; i < overlapLength / 4; i ++) - { - __m64 temp1, temp2; - - // load & shuffle data so that input & mixbuffer data samples are paired - temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r - temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r - - // temp = (temp .* mix) >> shifter - temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); - temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); - pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit - - // update mix += adder - mix1 = _mm_add_pi16(mix1, adder); - mix2 = _mm_add_pi16(mix2, adder); - - // --- second round begins here --- - - // load & shuffle data so that input & mixbuffer data samples are paired - temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]); // = i2l m2l i2r m2r - temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]); // = i3l m3l i3r m3r - - // temp = (temp .* mix) >> shifter - temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); - temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); - pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit - - // update mix += adder - mix1 = _mm_add_pi16(mix1, adder); - mix2 = _mm_add_pi16(mix2, adder); - - pVinput += 2; - pVMidBuf += 2; - pVdest += 2; - } - - _m_empty(); // clear MMS state -} - - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of MMX optimized functions of class 'FIRFilter' -// -////////////////////////////////////////////////////////////////////////////// - -#include "FIRFilter.h" - - -FIRFilterMMX::FIRFilterMMX() : FIRFilter() -{ - filterCoeffsUnalign = NULL; -} - - -FIRFilterMMX::~FIRFilterMMX() -{ - delete[] filterCoeffsUnalign; -} - - -// (overloaded) Calculates filter coefficients for MMX routine -void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor) -{ - uint i; - FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); - - // Ensure that filter coeffs array is aligned to 16-byte boundary - delete[] filterCoeffsUnalign; - filterCoeffsUnalign = new short[2 * newLength + 8]; - filterCoeffsAlign = (short *)(((ulongptr)filterCoeffsUnalign + 15) & -16); - - // rearrange the filter coefficients for mmx routines - for (i = 0;i < length; i += 4) - { - filterCoeffsAlign[2 * i + 0] = coeffs[i + 0]; - filterCoeffsAlign[2 * i + 1] = coeffs[i + 2]; - filterCoeffsAlign[2 * i + 2] = coeffs[i + 0]; - filterCoeffsAlign[2 * i + 3] = coeffs[i + 2]; - - filterCoeffsAlign[2 * i + 4] = coeffs[i + 1]; - filterCoeffsAlign[2 * i + 5] = coeffs[i + 3]; - filterCoeffsAlign[2 * i + 6] = coeffs[i + 1]; - filterCoeffsAlign[2 * i + 7] = coeffs[i + 3]; - } -} - - - -// mmx-optimized version of the filter routine for stereo sound -uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, const uint numSamples) const -{ - // Create stack copies of the needed member variables for asm routines : - uint i, j; - __m64 *pVdest = (__m64*)dest; - - if (length < 2) return 0; - - for (i = 0; i < numSamples / 2; i ++) - { - __m64 accu1; - __m64 accu2; - const __m64 *pVsrc = (const __m64*)src; - const __m64 *pVfilter = (const __m64*)filterCoeffsAlign; - - accu1 = accu2 = _mm_setzero_si64(); - for (j = 0; j < lengthDiv8 * 2; j ++) - { - __m64 temp1, temp2; - - temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]); // = l2 l0 r2 r0 - temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]); // = l3 l1 r3 r1 - - accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0])); // += l2*f2+l0*f0 r2*f2+r0*f0 - accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1])); // += l3*f3+l1*f1 r3*f3+r1*f1 - - temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]); // = l4 l2 r4 r2 - - accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0])); // += l3*f2+l1*f0 r3*f2+r1*f0 - accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1])); // += l4*f3+l2*f1 r4*f3+r2*f1 - - // accu1 += l2*f2+l0*f0 r2*f2+r0*f0 - // += l3*f3+l1*f1 r3*f3+r1*f1 - - // accu2 += l3*f2+l1*f0 r3*f2+r1*f0 - // l4*f3+l2*f1 r4*f3+r2*f1 - - pVfilter += 2; - pVsrc += 2; - } - // accu >>= resultDivFactor - accu1 = _mm_srai_pi32(accu1, resultDivFactor); - accu2 = _mm_srai_pi32(accu2, resultDivFactor); - - // pack 2*2*32bits => 4*16 bits - pVdest[0] = _mm_packs_pi32(accu1, accu2); - src += 4; - pVdest ++; - } - - _m_empty(); // clear emms state - - return (numSamples & 0xfffffffe) - length; -} - -#endif // ALLOW_MMX +//////////////////////////////////////////////////////////////////////////////// +/// +/// MMX optimized routines. All MMX optimized functions have been gathered into +/// this single source code file, regardless to their class or original source +/// code file, in order to ease porting the library to other compiler and +/// processor platforms. +/// +/// The MMX-optimizations are programmed using MMX compiler intrinsics that +/// are supported both by Microsoft Visual C++ and GCC compilers, so this file +/// should compile with both toolsets. +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support compiler intrinsic syntax. The update +/// is available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/06 18:52:43 $ +// File revision : $Revision: 1.1 $ +// +// $Id: mmx_optimized.cpp,v 1.1 2006/02/06 18:52:43 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "STTypes.h" + +#ifdef ALLOW_MMX +// MMX routines available only with integer sample type + +#if !(_WIN32 || __i386__ || __x86_64__) +#error "wrong platform - this source code file is exclusively for x86 platforms" +#endif + +using namespace soundtouch; + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of MMX optimized functions of class 'TDStretchMMX' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include +#include + + +// Calculates cross correlation of two buffers +long TDStretchMMX::calcCrossCorrStereo(const short *pV1, const short *pV2) const +{ + const __m64 *pVec1, *pVec2; + __m64 shifter; + __m64 accu; + long corr; + uint i; + + pVec1 = (__m64*)pV1; + pVec2 = (__m64*)pV2; + + shifter = _m_from_int(overlapDividerBits); + accu = _mm_setzero_si64(); + + // Process 4 parallel sets of 2 * stereo samples each during each + // round to improve CPU-level parallellization. + for (i = 0; i < overlapLength / 8; i ++) + { + __m64 temp; + + // dictionary of instructions: + // _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3] + // _mm_add_pi32 : 2*32bit add + // _m_psrad : 32bit right-shift + + temp = _mm_add_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), + _mm_madd_pi16(pVec1[1], pVec2[1])); + accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); + + temp = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), + _mm_madd_pi16(pVec1[3], pVec2[3])); + accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); + + pVec1 += 4; + pVec2 += 4; + } + + // copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1 + // and finally store the result into the variable "corr" + + accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32)); + corr = _m_to_int(accu); + + // Clear MMS state + _m_empty(); + + return corr; + // Note: Warning about the missing EMMS instruction is harmless + // as it'll be called elsewhere. +} + + + +void TDStretchMMX::clearCrossCorrState() +{ + // Clear MMS state + _m_empty(); + //_asm EMMS; +} + + + +// MMX-optimized version of the function overlapStereo +void TDStretchMMX::overlapStereo(short *output, const short *input) const +{ + const __m64 *pVinput, *pVMidBuf; + __m64 *pVdest; + __m64 mix1, mix2, adder, shifter; + uint i; + + pVinput = (const __m64*)input; + pVMidBuf = (const __m64*)pMidBuffer; + pVdest = (__m64*)output; + + // mix1 = mixer values for 1st stereo sample + // mix1 = mixer values for 2nd stereo sample + // adder = adder for updating mixer values after each round + + mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength); + adder = _mm_set_pi16(1, -1, 1, -1); + mix2 = _mm_add_pi16(mix1, adder); + adder = _mm_add_pi16(adder, adder); + + shifter = _m_from_int(overlapDividerBits); + + for (i = 0; i < overlapLength / 4; i ++) + { + __m64 temp1, temp2; + + // load & shuffle data so that input & mixbuffer data samples are paired + temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r + temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r + + // temp = (temp .* mix) >> shifter + temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); + temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); + pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit + + // update mix += adder + mix1 = _mm_add_pi16(mix1, adder); + mix2 = _mm_add_pi16(mix2, adder); + + // --- second round begins here --- + + // load & shuffle data so that input & mixbuffer data samples are paired + temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]); // = i2l m2l i2r m2r + temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]); // = i3l m3l i3r m3r + + // temp = (temp .* mix) >> shifter + temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); + temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); + pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit + + // update mix += adder + mix1 = _mm_add_pi16(mix1, adder); + mix2 = _mm_add_pi16(mix2, adder); + + pVinput += 2; + pVMidBuf += 2; + pVdest += 2; + } + + _m_empty(); // clear MMS state +} + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of MMX optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + + +FIRFilterMMX::FIRFilterMMX() : FIRFilter() +{ + filterCoeffsUnalign = NULL; +} + + +FIRFilterMMX::~FIRFilterMMX() +{ + delete[] filterCoeffsUnalign; +} + + +// (overloaded) Calculates filter coefficients for MMX routine +void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new short[2 * newLength + 8]; + filterCoeffsAlign = (short *)(((ulongptr)filterCoeffsUnalign + 15) & -16); + + // rearrange the filter coefficients for mmx routines + for (i = 0;i < length; i += 4) + { + filterCoeffsAlign[2 * i + 0] = coeffs[i + 0]; + filterCoeffsAlign[2 * i + 1] = coeffs[i + 2]; + filterCoeffsAlign[2 * i + 2] = coeffs[i + 0]; + filterCoeffsAlign[2 * i + 3] = coeffs[i + 2]; + + filterCoeffsAlign[2 * i + 4] = coeffs[i + 1]; + filterCoeffsAlign[2 * i + 5] = coeffs[i + 3]; + filterCoeffsAlign[2 * i + 6] = coeffs[i + 1]; + filterCoeffsAlign[2 * i + 7] = coeffs[i + 3]; + } +} + + + +// mmx-optimized version of the filter routine for stereo sound +uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, const uint numSamples) const +{ + // Create stack copies of the needed member variables for asm routines : + uint i, j; + __m64 *pVdest = (__m64*)dest; + + if (length < 2) return 0; + + for (i = 0; i < numSamples / 2; i ++) + { + __m64 accu1; + __m64 accu2; + const __m64 *pVsrc = (const __m64*)src; + const __m64 *pVfilter = (const __m64*)filterCoeffsAlign; + + accu1 = accu2 = _mm_setzero_si64(); + for (j = 0; j < lengthDiv8 * 2; j ++) + { + __m64 temp1, temp2; + + temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]); // = l2 l0 r2 r0 + temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]); // = l3 l1 r3 r1 + + accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0])); // += l2*f2+l0*f0 r2*f2+r0*f0 + accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1])); // += l3*f3+l1*f1 r3*f3+r1*f1 + + temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]); // = l4 l2 r4 r2 + + accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0])); // += l3*f2+l1*f0 r3*f2+r1*f0 + accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1])); // += l4*f3+l2*f1 r4*f3+r2*f1 + + // accu1 += l2*f2+l0*f0 r2*f2+r0*f0 + // += l3*f3+l1*f1 r3*f3+r1*f1 + + // accu2 += l3*f2+l1*f0 r3*f2+r1*f0 + // l4*f3+l2*f1 r4*f3+r2*f1 + + pVfilter += 2; + pVsrc += 2; + } + // accu >>= resultDivFactor + accu1 = _mm_srai_pi32(accu1, resultDivFactor); + accu2 = _mm_srai_pi32(accu2, resultDivFactor); + + // pack 2*2*32bits => 4*16 bits + pVdest[0] = _mm_packs_pi32(accu1, accu2); + src += 4; + pVdest ++; + } + + _m_empty(); // clear emms state + + return (numSamples & 0xfffffffe) - length; +} + +#endif // ALLOW_MMX diff --git a/3rdparty/SoundTouch/sse_optimized.cpp b/3rdparty/SoundTouch/sse_optimized.cpp index 57598d78d7..1e70da6608 100644 --- a/3rdparty/SoundTouch/sse_optimized.cpp +++ b/3rdparty/SoundTouch/sse_optimized.cpp @@ -1,484 +1,484 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE -/// optimized functions have been gathered into this single source -/// code file, regardless to their class or original source code file, in order -/// to ease porting the library to other compiler and processor platforms. -/// -/// The SSE-optimizations are programmed using SSE compiler intrinsics that -/// are supported both by Microsoft Visual C++ and GCC compilers, so this file -/// should compile with both toolsets. -/// -/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ -/// 6.0 processor pack" update to support SSE instruction set. The update is -/// available for download at Microsoft Developers Network, see here: -/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx -/// -/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and -/// perform a search with keywords "processor pack". -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.2 $ -// -// $Id: sse_optimized.cpp,v 1.2 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include "cpu_detect.h" -#include "STTypes.h" - -using namespace soundtouch; - -#ifdef ALLOW_SSE - -// SSE routines available only with float sample type - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of SSE optimized functions of class 'TDStretchSSE' -// -////////////////////////////////////////////////////////////////////////////// - -#include "TDStretch.h" -#include - -// Calculates cross correlation of two buffers -double TDStretchSSE::calcCrossCorrStereo(const float *pV1, const float *pV2) const -{ - uint i; - __m128 vSum, *pVec2; - - // Note. It means a major slow-down if the routine needs to tolerate - // unaligned __m128 memory accesses. It's way faster if we can skip - // unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps. - // This can mean up to ~ 10-fold difference (incl. part of which is - // due to skipping every second round for stereo sound though). - // - // Compile-time define ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided - // for choosing if this little cheating is allowed. - -#ifdef ALLOW_NONEXACT_SIMD_OPTIMIZATION - // Little cheating allowed, return valid correlation only for - // aligned locations, meaning every second round for stereo sound. - - #define _MM_LOAD _mm_load_ps - - if (((ulong)pV1) & 15) return -1e50; // skip unaligned locations - -#else - // No cheating allowed, use unaligned load & take the resulting - // performance hit. - #define _MM_LOAD _mm_loadu_ps -#endif - - // ensure overlapLength is divisible by 8 - assert((overlapLength % 8) == 0); - - // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors - // Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not. - pVec2 = (__m128*)pV2; - vSum = _mm_setzero_ps(); - - // Unroll the loop by factor of 4 * 4 operations - for (i = 0; i < overlapLength / 8; i ++) - { - // vSum += pV1[0..3] * pV2[0..3] - vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1),pVec2[0])); - - // vSum += pV1[4..7] * pV2[4..7] - vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 4), pVec2[1])); - - // vSum += pV1[8..11] * pV2[8..11] - vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 8), pVec2[2])); - - // vSum += pV1[12..15] * pV2[12..15] - vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 12), pVec2[3])); - - pV1 += 16; - pVec2 += 4; - } - - // return value = vSum[0] + vSum[1] + vSum[2] + vSum[3] - float *pvSum = (float*)&vSum; - return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]); - - /* This is approximately corresponding routine in C-language: - double corr; - uint i; - - // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors - corr = 0.0; - for (i = 0; i < overlapLength / 8; i ++) - { - corr += pV1[0] * pV2[0] + - pV1[1] * pV2[1] + - pV1[2] * pV2[2] + - pV1[3] * pV2[3] + - pV1[4] * pV2[4] + - pV1[5] * pV2[5] + - pV1[6] * pV2[6] + - pV1[7] * pV2[7] + - pV1[8] * pV2[8] + - pV1[9] * pV2[9] + - pV1[10] * pV2[10] + - pV1[11] * pV2[11] + - pV1[12] * pV2[12] + - pV1[13] * pV2[13] + - pV1[14] * pV2[14] + - pV1[15] * pV2[15]; - - pV1 += 16; - pV2 += 16; - } - */ - - /* This is corresponding routine in assembler. This may be teeny-weeny bit faster - than intrinsic version, but more difficult to maintain & get compiled on multiple - platforms. - - uint overlapLengthLocal = overlapLength; - float corr; - - _asm - { - // Very important note: data in 'pV2' _must_ be aligned to - // 16-byte boundary! - - // give prefetch hints to CPU of what data are to be needed soonish - // give more aggressive hints on pV1 as that changes while pV2 stays - // same between runs - prefetcht0 [pV1] - prefetcht0 [pV2] - prefetcht0 [pV1 + 32] - - mov eax, dword ptr pV1 - mov ebx, dword ptr pV2 - - xorps xmm0, xmm0 - - mov ecx, overlapLengthLocal - shr ecx, 3 // div by eight - - loop1: - prefetcht0 [eax + 64] // give a prefetch hint to CPU what data are to be needed soonish - prefetcht0 [ebx + 32] // give a prefetch hint to CPU what data are to be needed soonish - movups xmm1, [eax] - mulps xmm1, [ebx] - addps xmm0, xmm1 - - movups xmm2, [eax + 16] - mulps xmm2, [ebx + 16] - addps xmm0, xmm2 - - prefetcht0 [eax + 96] // give a prefetch hint to CPU what data are to be needed soonish - prefetcht0 [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish - - movups xmm3, [eax + 32] - mulps xmm3, [ebx + 32] - addps xmm0, xmm3 - - movups xmm4, [eax + 48] - mulps xmm4, [ebx + 48] - addps xmm0, xmm4 - - add eax, 64 - add ebx, 64 - - dec ecx - jnz loop1 - - // add the four floats of xmm0 together and return the result. - - movhlps xmm1, xmm0 // move 3 & 4 of xmm0 to 1 & 2 of xmm1 - addps xmm1, xmm0 - movaps xmm2, xmm1 - shufps xmm2, xmm2, 0x01 // move 2 of xmm2 as 1 of xmm2 - addss xmm2, xmm1 - movss corr, xmm2 - } - - return (double)corr; - */ -} - - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of SSE optimized functions of class 'FIRFilter' -// -////////////////////////////////////////////////////////////////////////////// - -#include "FIRFilter.h" - -FIRFilterSSE::FIRFilterSSE() : FIRFilter() -{ - filterCoeffsUnalign = NULL; -} - - -FIRFilterSSE::~FIRFilterSSE() -{ - delete[] filterCoeffsUnalign; -} - - -// (overloaded) Calculates filter coefficients for SSE routine -void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) -{ - uint i; - float fDivider; - - FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); - - // Scale the filter coefficients so that it won't be necessary to scale the filtering result - // also rearrange coefficients suitably for 3DNow! - // Ensure that filter coeffs array is aligned to 16-byte boundary - delete[] filterCoeffsUnalign; - filterCoeffsUnalign = new float[2 * newLength + 4]; - filterCoeffsAlign = (float *)(((unsigned long)filterCoeffsUnalign + 15) & -16); - - fDivider = (float)resultDivider; - - // rearrange the filter coefficients for mmx routines - for (i = 0; i < newLength; i ++) - { - filterCoeffsAlign[2 * i + 0] = - filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; - } -} - - - -// SSE-optimized version of the filter routine for stereo sound -uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const -{ - int count = (numSamples - length) & -2; - int j; - - assert(count % 2 == 0); - - if (count < 2) return 0; - - assert((length % 8) == 0); - assert(((unsigned long)filterCoeffsAlign) % 16 == 0); - - // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2' - for (j = 0; j < count; j += 2) - { - const float *pSrc; - const __m128 *pFil; - __m128 sum1, sum2; - uint i; - - pSrc = source; // source audio data - pFil = (__m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients - // are aligned to 16-byte boundary - sum1 = sum2 = _mm_setzero_ps(); - - for (i = 0; i < length / 8; i ++) - { - // Unroll loop for efficiency & calculate filter for 2*2 stereo samples - // at each pass - - // sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset - // sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset. - - sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc) , pFil[0])); - sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0])); - - sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1])); - sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1])); - - sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) , pFil[2])); - sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2])); - - sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3])); - sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3])); - - pSrc += 16; - pFil += 4; - } - - // Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need - // to sum the two hi- and lo-floats of these registers together. - - // post-shuffle & add the filtered values and store to dest. - _mm_storeu_ps(dest, _mm_add_ps( - _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2 - _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0 - )); - source += 4; - dest += 4; - } - - // Ideas for further improvement: - // 1. If it could be guaranteed that 'source' were always aligned to 16-byte - // boundary, a faster aligned '_mm_load_ps' instruction could be used. - // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte - // boundary, a faster '_mm_store_ps' instruction could be used. - - return (uint)count; - - /* original routine in C-language. please notice the C-version has differently - organized coefficients though. - double suml1, suml2; - double sumr1, sumr2; - uint i, j; - - for (j = 0; j < count; j += 2) - { - const float *ptr; - const float *pFil; - - suml1 = sumr1 = 0.0; - suml2 = sumr2 = 0.0; - ptr = src; - pFil = filterCoeffs; - for (i = 0; i < lengthLocal; i ++) - { - // unroll loop for efficiency. - - suml1 += ptr[0] * pFil[0] + - ptr[2] * pFil[2] + - ptr[4] * pFil[4] + - ptr[6] * pFil[6]; - - sumr1 += ptr[1] * pFil[1] + - ptr[3] * pFil[3] + - ptr[5] * pFil[5] + - ptr[7] * pFil[7]; - - suml2 += ptr[8] * pFil[0] + - ptr[10] * pFil[2] + - ptr[12] * pFil[4] + - ptr[14] * pFil[6]; - - sumr2 += ptr[9] * pFil[1] + - ptr[11] * pFil[3] + - ptr[13] * pFil[5] + - ptr[15] * pFil[7]; - - ptr += 16; - pFil += 8; - } - dest[0] = (float)suml1; - dest[1] = (float)sumr1; - dest[2] = (float)suml2; - dest[3] = (float)sumr2; - - src += 4; - dest += 4; - } - */ - - - /* Similar routine in assembly, again obsoleted due to maintainability - _asm - { - // Very important note: data in 'src' _must_ be aligned to - // 16-byte boundary! - mov edx, count - mov ebx, dword ptr src - mov eax, dword ptr dest - shr edx, 1 - - loop1: - // "outer loop" : during each round 2*2 output samples are calculated - - // give prefetch hints to CPU of what data are to be needed soonish - prefetcht0 [ebx] - prefetcht0 [filterCoeffsLocal] - - mov esi, ebx - mov edi, filterCoeffsLocal - xorps xmm0, xmm0 - xorps xmm1, xmm1 - mov ecx, lengthLocal - - loop2: - // "inner loop" : during each round eight FIR filter taps are evaluated for 2*2 samples - prefetcht0 [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish - prefetcht0 [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish - - movups xmm2, [esi] // possibly unaligned load - movups xmm3, [esi + 8] // possibly unaligned load - mulps xmm2, [edi] - mulps xmm3, [edi] - addps xmm0, xmm2 - addps xmm1, xmm3 - - movups xmm4, [esi + 16] // possibly unaligned load - movups xmm5, [esi + 24] // possibly unaligned load - mulps xmm4, [edi + 16] - mulps xmm5, [edi + 16] - addps xmm0, xmm4 - addps xmm1, xmm5 - - prefetcht0 [esi + 64] // give a prefetch hint to CPU what data are to be needed soonish - prefetcht0 [edi + 64] // give a prefetch hint to CPU what data are to be needed soonish - - movups xmm6, [esi + 32] // possibly unaligned load - movups xmm7, [esi + 40] // possibly unaligned load - mulps xmm6, [edi + 32] - mulps xmm7, [edi + 32] - addps xmm0, xmm6 - addps xmm1, xmm7 - - movups xmm4, [esi + 48] // possibly unaligned load - movups xmm5, [esi + 56] // possibly unaligned load - mulps xmm4, [edi + 48] - mulps xmm5, [edi + 48] - addps xmm0, xmm4 - addps xmm1, xmm5 - - add esi, 64 - add edi, 64 - dec ecx - jnz loop2 - - // Now xmm0 and xmm1 both have a filtered 2-channel sample each, but we still need - // to sum the two hi- and lo-floats of these registers together. - - movhlps xmm2, xmm0 // xmm2 = xmm2_3 xmm2_2 xmm0_3 xmm0_2 - movlhps xmm2, xmm1 // xmm2 = xmm1_1 xmm1_0 xmm0_3 xmm0_2 - shufps xmm0, xmm1, 0xe4 // xmm0 = xmm1_3 xmm1_2 xmm0_1 xmm0_0 - addps xmm0, xmm2 - - movaps [eax], xmm0 - add ebx, 16 - add eax, 16 - - dec edx - jnz loop1 - } - */ -} - -#endif // ALLOW_SSE +//////////////////////////////////////////////////////////////////////////////// +/// +/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE +/// optimized functions have been gathered into this single source +/// code file, regardless to their class or original source code file, in order +/// to ease porting the library to other compiler and processor platforms. +/// +/// The SSE-optimizations are programmed using SSE compiler intrinsics that +/// are supported both by Microsoft Visual C++ and GCC compilers, so this file +/// should compile with both toolsets. +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support SSE instruction set. The update is +/// available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx +/// +/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and +/// perform a search with keywords "processor pack". +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.2 $ +// +// $Id: sse_optimized.cpp,v 1.2 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" +#include "STTypes.h" + +using namespace soundtouch; + +#ifdef ALLOW_SSE + +// SSE routines available only with float sample type + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of SSE optimized functions of class 'TDStretchSSE' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include + +// Calculates cross correlation of two buffers +double TDStretchSSE::calcCrossCorrStereo(const float *pV1, const float *pV2) const +{ + uint i; + __m128 vSum, *pVec2; + + // Note. It means a major slow-down if the routine needs to tolerate + // unaligned __m128 memory accesses. It's way faster if we can skip + // unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps. + // This can mean up to ~ 10-fold difference (incl. part of which is + // due to skipping every second round for stereo sound though). + // + // Compile-time define ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided + // for choosing if this little cheating is allowed. + +#ifdef ALLOW_NONEXACT_SIMD_OPTIMIZATION + // Little cheating allowed, return valid correlation only for + // aligned locations, meaning every second round for stereo sound. + + #define _MM_LOAD _mm_load_ps + + if (((ulong)pV1) & 15) return -1e50; // skip unaligned locations + +#else + // No cheating allowed, use unaligned load & take the resulting + // performance hit. + #define _MM_LOAD _mm_loadu_ps +#endif + + // ensure overlapLength is divisible by 8 + assert((overlapLength % 8) == 0); + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + // Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not. + pVec2 = (__m128*)pV2; + vSum = _mm_setzero_ps(); + + // Unroll the loop by factor of 4 * 4 operations + for (i = 0; i < overlapLength / 8; i ++) + { + // vSum += pV1[0..3] * pV2[0..3] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1),pVec2[0])); + + // vSum += pV1[4..7] * pV2[4..7] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 4), pVec2[1])); + + // vSum += pV1[8..11] * pV2[8..11] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 8), pVec2[2])); + + // vSum += pV1[12..15] * pV2[12..15] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 12), pVec2[3])); + + pV1 += 16; + pVec2 += 4; + } + + // return value = vSum[0] + vSum[1] + vSum[2] + vSum[3] + float *pvSum = (float*)&vSum; + return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]); + + /* This is approximately corresponding routine in C-language: + double corr; + uint i; + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + corr = 0.0; + for (i = 0; i < overlapLength / 8; i ++) + { + corr += pV1[0] * pV2[0] + + pV1[1] * pV2[1] + + pV1[2] * pV2[2] + + pV1[3] * pV2[3] + + pV1[4] * pV2[4] + + pV1[5] * pV2[5] + + pV1[6] * pV2[6] + + pV1[7] * pV2[7] + + pV1[8] * pV2[8] + + pV1[9] * pV2[9] + + pV1[10] * pV2[10] + + pV1[11] * pV2[11] + + pV1[12] * pV2[12] + + pV1[13] * pV2[13] + + pV1[14] * pV2[14] + + pV1[15] * pV2[15]; + + pV1 += 16; + pV2 += 16; + } + */ + + /* This is corresponding routine in assembler. This may be teeny-weeny bit faster + than intrinsic version, but more difficult to maintain & get compiled on multiple + platforms. + + uint overlapLengthLocal = overlapLength; + float corr; + + _asm + { + // Very important note: data in 'pV2' _must_ be aligned to + // 16-byte boundary! + + // give prefetch hints to CPU of what data are to be needed soonish + // give more aggressive hints on pV1 as that changes while pV2 stays + // same between runs + prefetcht0 [pV1] + prefetcht0 [pV2] + prefetcht0 [pV1 + 32] + + mov eax, dword ptr pV1 + mov ebx, dword ptr pV2 + + xorps xmm0, xmm0 + + mov ecx, overlapLengthLocal + shr ecx, 3 // div by eight + + loop1: + prefetcht0 [eax + 64] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [ebx + 32] // give a prefetch hint to CPU what data are to be needed soonish + movups xmm1, [eax] + mulps xmm1, [ebx] + addps xmm0, xmm1 + + movups xmm2, [eax + 16] + mulps xmm2, [ebx + 16] + addps xmm0, xmm2 + + prefetcht0 [eax + 96] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish + + movups xmm3, [eax + 32] + mulps xmm3, [ebx + 32] + addps xmm0, xmm3 + + movups xmm4, [eax + 48] + mulps xmm4, [ebx + 48] + addps xmm0, xmm4 + + add eax, 64 + add ebx, 64 + + dec ecx + jnz loop1 + + // add the four floats of xmm0 together and return the result. + + movhlps xmm1, xmm0 // move 3 & 4 of xmm0 to 1 & 2 of xmm1 + addps xmm1, xmm0 + movaps xmm2, xmm1 + shufps xmm2, xmm2, 0x01 // move 2 of xmm2 as 1 of xmm2 + addss xmm2, xmm1 + movss corr, xmm2 + } + + return (double)corr; + */ +} + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of SSE optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + +FIRFilterSSE::FIRFilterSSE() : FIRFilter() +{ + filterCoeffsUnalign = NULL; +} + + +FIRFilterSSE::~FIRFilterSSE() +{ + delete[] filterCoeffsUnalign; +} + + +// (overloaded) Calculates filter coefficients for SSE routine +void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + float fDivider; + + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Scale the filter coefficients so that it won't be necessary to scale the filtering result + // also rearrange coefficients suitably for 3DNow! + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new float[2 * newLength + 4]; + filterCoeffsAlign = (float *)(((unsigned long)filterCoeffsUnalign + 15) & -16); + + fDivider = (float)resultDivider; + + // rearrange the filter coefficients for mmx routines + for (i = 0; i < newLength; i ++) + { + filterCoeffsAlign[2 * i + 0] = + filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; + } +} + + + +// SSE-optimized version of the filter routine for stereo sound +uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const +{ + int count = (numSamples - length) & -2; + int j; + + assert(count % 2 == 0); + + if (count < 2) return 0; + + assert((length % 8) == 0); + assert(((unsigned long)filterCoeffsAlign) % 16 == 0); + + // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2' + for (j = 0; j < count; j += 2) + { + const float *pSrc; + const __m128 *pFil; + __m128 sum1, sum2; + uint i; + + pSrc = source; // source audio data + pFil = (__m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients + // are aligned to 16-byte boundary + sum1 = sum2 = _mm_setzero_ps(); + + for (i = 0; i < length / 8; i ++) + { + // Unroll loop for efficiency & calculate filter for 2*2 stereo samples + // at each pass + + // sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset + // sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset. + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc) , pFil[0])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) , pFil[2])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3])); + + pSrc += 16; + pFil += 4; + } + + // Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need + // to sum the two hi- and lo-floats of these registers together. + + // post-shuffle & add the filtered values and store to dest. + _mm_storeu_ps(dest, _mm_add_ps( + _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2 + _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0 + )); + source += 4; + dest += 4; + } + + // Ideas for further improvement: + // 1. If it could be guaranteed that 'source' were always aligned to 16-byte + // boundary, a faster aligned '_mm_load_ps' instruction could be used. + // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte + // boundary, a faster '_mm_store_ps' instruction could be used. + + return (uint)count; + + /* original routine in C-language. please notice the C-version has differently + organized coefficients though. + double suml1, suml2; + double sumr1, sumr2; + uint i, j; + + for (j = 0; j < count; j += 2) + { + const float *ptr; + const float *pFil; + + suml1 = sumr1 = 0.0; + suml2 = sumr2 = 0.0; + ptr = src; + pFil = filterCoeffs; + for (i = 0; i < lengthLocal; i ++) + { + // unroll loop for efficiency. + + suml1 += ptr[0] * pFil[0] + + ptr[2] * pFil[2] + + ptr[4] * pFil[4] + + ptr[6] * pFil[6]; + + sumr1 += ptr[1] * pFil[1] + + ptr[3] * pFil[3] + + ptr[5] * pFil[5] + + ptr[7] * pFil[7]; + + suml2 += ptr[8] * pFil[0] + + ptr[10] * pFil[2] + + ptr[12] * pFil[4] + + ptr[14] * pFil[6]; + + sumr2 += ptr[9] * pFil[1] + + ptr[11] * pFil[3] + + ptr[13] * pFil[5] + + ptr[15] * pFil[7]; + + ptr += 16; + pFil += 8; + } + dest[0] = (float)suml1; + dest[1] = (float)sumr1; + dest[2] = (float)suml2; + dest[3] = (float)sumr2; + + src += 4; + dest += 4; + } + */ + + + /* Similar routine in assembly, again obsoleted due to maintainability + _asm + { + // Very important note: data in 'src' _must_ be aligned to + // 16-byte boundary! + mov edx, count + mov ebx, dword ptr src + mov eax, dword ptr dest + shr edx, 1 + + loop1: + // "outer loop" : during each round 2*2 output samples are calculated + + // give prefetch hints to CPU of what data are to be needed soonish + prefetcht0 [ebx] + prefetcht0 [filterCoeffsLocal] + + mov esi, ebx + mov edi, filterCoeffsLocal + xorps xmm0, xmm0 + xorps xmm1, xmm1 + mov ecx, lengthLocal + + loop2: + // "inner loop" : during each round eight FIR filter taps are evaluated for 2*2 samples + prefetcht0 [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish + + movups xmm2, [esi] // possibly unaligned load + movups xmm3, [esi + 8] // possibly unaligned load + mulps xmm2, [edi] + mulps xmm3, [edi] + addps xmm0, xmm2 + addps xmm1, xmm3 + + movups xmm4, [esi + 16] // possibly unaligned load + movups xmm5, [esi + 24] // possibly unaligned load + mulps xmm4, [edi + 16] + mulps xmm5, [edi + 16] + addps xmm0, xmm4 + addps xmm1, xmm5 + + prefetcht0 [esi + 64] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [edi + 64] // give a prefetch hint to CPU what data are to be needed soonish + + movups xmm6, [esi + 32] // possibly unaligned load + movups xmm7, [esi + 40] // possibly unaligned load + mulps xmm6, [edi + 32] + mulps xmm7, [edi + 32] + addps xmm0, xmm6 + addps xmm1, xmm7 + + movups xmm4, [esi + 48] // possibly unaligned load + movups xmm5, [esi + 56] // possibly unaligned load + mulps xmm4, [edi + 48] + mulps xmm5, [edi + 48] + addps xmm0, xmm4 + addps xmm1, xmm5 + + add esi, 64 + add edi, 64 + dec ecx + jnz loop2 + + // Now xmm0 and xmm1 both have a filtered 2-channel sample each, but we still need + // to sum the two hi- and lo-floats of these registers together. + + movhlps xmm2, xmm0 // xmm2 = xmm2_3 xmm2_2 xmm0_3 xmm0_2 + movlhps xmm2, xmm1 // xmm2 = xmm1_1 xmm1_0 xmm0_3 xmm0_2 + shufps xmm0, xmm1, 0xe4 // xmm0 = xmm1_3 xmm1_2 xmm0_1 xmm0_0 + addps xmm0, xmm2 + + movaps [eax], xmm0 + add ebx, 16 + add eax, 16 + + dec edx + jnz loop1 + } + */ +} + +#endif // ALLOW_SSE diff --git a/3rdparty/bzip2/blocksort.c b/3rdparty/bzip2/blocksort.c index aceb5e9508..8535c93c8d 100644 --- a/3rdparty/bzip2/blocksort.c +++ b/3rdparty/bzip2/blocksort.c @@ -1,1094 +1,1094 @@ - -/*-------------------------------------------------------------*/ -/*--- Block sorting machinery ---*/ -/*--- blocksort.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.4 of 20 December 2006 - Copyright (C) 1996-2006 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - -/*---------------------------------------------*/ -/*--- Fallback O(N log(N)^2) sorting ---*/ -/*--- algorithm, for repetitive blocks ---*/ -/*---------------------------------------------*/ - -/*---------------------------------------------*/ -static -__inline__ -void fallbackSimpleSort ( UInt32* fmap, - UInt32* eclass, - Int32 lo, - Int32 hi ) -{ - Int32 i, j, tmp; - UInt32 ec_tmp; - - if (lo == hi) return; - - if (hi - lo > 3) { - for ( i = hi-4; i >= lo; i-- ) { - tmp = fmap[i]; - ec_tmp = eclass[tmp]; - for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 ) - fmap[j-4] = fmap[j]; - fmap[j-4] = tmp; - } - } - - for ( i = hi-1; i >= lo; i-- ) { - tmp = fmap[i]; - ec_tmp = eclass[tmp]; - for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ ) - fmap[j-1] = fmap[j]; - fmap[j-1] = tmp; - } -} - - -/*---------------------------------------------*/ -#define fswap(zz1, zz2) \ - { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } - -#define fvswap(zzp1, zzp2, zzn) \ -{ \ - Int32 yyp1 = (zzp1); \ - Int32 yyp2 = (zzp2); \ - Int32 yyn = (zzn); \ - while (yyn > 0) { \ - fswap(fmap[yyp1], fmap[yyp2]); \ - yyp1++; yyp2++; yyn--; \ - } \ -} - - -#define fmin(a,b) ((a) < (b)) ? (a) : (b) - -#define fpush(lz,hz) { stackLo[sp] = lz; \ - stackHi[sp] = hz; \ - sp++; } - -#define fpop(lz,hz) { sp--; \ - lz = stackLo[sp]; \ - hz = stackHi[sp]; } - -#define FALLBACK_QSORT_SMALL_THRESH 10 -#define FALLBACK_QSORT_STACK_SIZE 100 - - -static -void fallbackQSort3 ( UInt32* fmap, - UInt32* eclass, - Int32 loSt, - Int32 hiSt ) -{ - Int32 unLo, unHi, ltLo, gtHi, n, m; - Int32 sp, lo, hi; - UInt32 med, r, r3; - Int32 stackLo[FALLBACK_QSORT_STACK_SIZE]; - Int32 stackHi[FALLBACK_QSORT_STACK_SIZE]; - - r = 0; - - sp = 0; - fpush ( loSt, hiSt ); - - while (sp > 0) { - - AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 ); - - fpop ( lo, hi ); - if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { - fallbackSimpleSort ( fmap, eclass, lo, hi ); - continue; - } - - /* Random partitioning. Median of 3 sometimes fails to - avoid bad cases. Median of 9 seems to help but - looks rather expensive. This too seems to work but - is cheaper. Guidance for the magic constants - 7621 and 32768 is taken from Sedgewick's algorithms - book, chapter 35. - */ - r = ((r * 7621) + 1) % 32768; - r3 = r % 3; - if (r3 == 0) med = eclass[fmap[lo]]; else - if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else - med = eclass[fmap[hi]]; - - unLo = ltLo = lo; - unHi = gtHi = hi; - - while (1) { - while (1) { - if (unLo > unHi) break; - n = (Int32)eclass[fmap[unLo]] - (Int32)med; - if (n == 0) { - fswap(fmap[unLo], fmap[ltLo]); - ltLo++; unLo++; - continue; - }; - if (n > 0) break; - unLo++; - } - while (1) { - if (unLo > unHi) break; - n = (Int32)eclass[fmap[unHi]] - (Int32)med; - if (n == 0) { - fswap(fmap[unHi], fmap[gtHi]); - gtHi--; unHi--; - continue; - }; - if (n < 0) break; - unHi--; - } - if (unLo > unHi) break; - fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; - } - - AssertD ( unHi == unLo-1, "fallbackQSort3(2)" ); - - if (gtHi < ltLo) continue; - - n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n); - m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m); - - n = lo + unLo - ltLo - 1; - m = hi - (gtHi - unHi) + 1; - - if (n - lo > hi - m) { - fpush ( lo, n ); - fpush ( m, hi ); - } else { - fpush ( m, hi ); - fpush ( lo, n ); - } - } -} - -#undef fmin -#undef fpush -#undef fpop -#undef fswap -#undef fvswap -#undef FALLBACK_QSORT_SMALL_THRESH -#undef FALLBACK_QSORT_STACK_SIZE - - -/*---------------------------------------------*/ -/* Pre: - nblock > 0 - eclass exists for [0 .. nblock-1] - ((UChar*)eclass) [0 .. nblock-1] holds block - ptr exists for [0 .. nblock-1] - - Post: - ((UChar*)eclass) [0 .. nblock-1] holds block - All other areas of eclass destroyed - fmap [0 .. nblock-1] holds sorted order - bhtab [ 0 .. 2+(nblock/32) ] destroyed -*/ - -#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) -#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) -#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) -#define WORD_BH(zz) bhtab[(zz) >> 5] -#define UNALIGNED_BH(zz) ((zz) & 0x01f) - -static -void fallbackSort ( UInt32* fmap, - UInt32* eclass, - UInt32* bhtab, - Int32 nblock, - Int32 verb ) -{ - Int32 ftab[257]; - Int32 ftabCopy[256]; - Int32 H, i, j, k, l, r, cc, cc1; - Int32 nNotDone; - Int32 nBhtab; - UChar* eclass8 = (UChar*)eclass; - - /*-- - Initial 1-char radix sort to generate - initial fmap and initial BH bits. - --*/ - if (verb >= 4) - VPrintf0 ( " bucket sorting ...\n" ); - for (i = 0; i < 257; i++) ftab[i] = 0; - for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; - for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; - for (i = 1; i < 257; i++) ftab[i] += ftab[i-1]; - - for (i = 0; i < nblock; i++) { - j = eclass8[i]; - k = ftab[j] - 1; - ftab[j] = k; - fmap[k] = i; - } - - nBhtab = 2 + (nblock / 32); - for (i = 0; i < nBhtab; i++) bhtab[i] = 0; - for (i = 0; i < 256; i++) SET_BH(ftab[i]); - - /*-- - Inductively refine the buckets. Kind-of an - "exponential radix sort" (!), inspired by the - Manber-Myers suffix array construction algorithm. - --*/ - - /*-- set sentinel bits for block-end detection --*/ - for (i = 0; i < 32; i++) { - SET_BH(nblock + 2*i); - CLEAR_BH(nblock + 2*i + 1); - } - - /*-- the log(N) loop --*/ - H = 1; - while (1) { - - if (verb >= 4) - VPrintf1 ( " depth %6d has ", H ); - - j = 0; - for (i = 0; i < nblock; i++) { - if (ISSET_BH(i)) j = i; - k = fmap[i] - H; if (k < 0) k += nblock; - eclass[k] = j; - } - - nNotDone = 0; - r = -1; - while (1) { - - /*-- find the next non-singleton bucket --*/ - k = r + 1; - while (ISSET_BH(k) && UNALIGNED_BH(k)) k++; - if (ISSET_BH(k)) { - while (WORD_BH(k) == 0xffffffff) k += 32; - while (ISSET_BH(k)) k++; - } - l = k - 1; - if (l >= nblock) break; - while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++; - if (!ISSET_BH(k)) { - while (WORD_BH(k) == 0x00000000) k += 32; - while (!ISSET_BH(k)) k++; - } - r = k - 1; - if (r >= nblock) break; - - /*-- now [l, r] bracket current bucket --*/ - if (r > l) { - nNotDone += (r - l + 1); - fallbackQSort3 ( fmap, eclass, l, r ); - - /*-- scan bucket and generate header bits-- */ - cc = -1; - for (i = l; i <= r; i++) { - cc1 = eclass[fmap[i]]; - if (cc != cc1) { SET_BH(i); cc = cc1; }; - } - } - } - - if (verb >= 4) - VPrintf1 ( "%6d unresolved strings\n", nNotDone ); - - H *= 2; - if (H > nblock || nNotDone == 0) break; - } - - /*-- - Reconstruct the original block in - eclass8 [0 .. nblock-1], since the - previous phase destroyed it. - --*/ - if (verb >= 4) - VPrintf0 ( " reconstructing block ...\n" ); - j = 0; - for (i = 0; i < nblock; i++) { - while (ftabCopy[j] == 0) j++; - ftabCopy[j]--; - eclass8[fmap[i]] = (UChar)j; - } - AssertH ( j < 256, 1005 ); -} - -#undef SET_BH -#undef CLEAR_BH -#undef ISSET_BH -#undef WORD_BH -#undef UNALIGNED_BH - - -/*---------------------------------------------*/ -/*--- The main, O(N^2 log(N)) sorting ---*/ -/*--- algorithm. Faster for "normal" ---*/ -/*--- non-repetitive blocks. ---*/ -/*---------------------------------------------*/ - -/*---------------------------------------------*/ -static -__inline__ -Bool mainGtU ( UInt32 i1, - UInt32 i2, - UChar* block, - UInt16* quadrant, - UInt32 nblock, - Int32* budget ) -{ - Int32 k; - UChar c1, c2; - UInt16 s1, s2; - - AssertD ( i1 != i2, "mainGtU" ); - /* 1 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 2 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 3 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 4 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 5 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 6 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 7 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 8 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 9 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 10 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 11 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 12 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - - k = nblock + 8; - - do { - /* 1 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 2 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 3 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 4 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 5 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 6 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 7 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 8 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - - if (i1 >= nblock) i1 -= nblock; - if (i2 >= nblock) i2 -= nblock; - - k -= 8; - (*budget)--; - } - while (k >= 0); - - return False; -} - - -/*---------------------------------------------*/ -/*-- - Knuth's increments seem to work better - than Incerpi-Sedgewick here. Possibly - because the number of elems to sort is - usually small, typically <= 20. ---*/ -static -Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, - 9841, 29524, 88573, 265720, - 797161, 2391484 }; - -static -void mainSimpleSort ( UInt32* ptr, - UChar* block, - UInt16* quadrant, - Int32 nblock, - Int32 lo, - Int32 hi, - Int32 d, - Int32* budget ) -{ - Int32 i, j, h, bigN, hp; - UInt32 v; - - bigN = hi - lo + 1; - if (bigN < 2) return; - - hp = 0; - while (incs[hp] < bigN) hp++; - hp--; - - for (; hp >= 0; hp--) { - h = incs[hp]; - - i = lo + h; - while (True) { - - /*-- copy 1 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while ( mainGtU ( - ptr[j-h]+d, v+d, block, quadrant, nblock, budget - ) ) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - - /*-- copy 2 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while ( mainGtU ( - ptr[j-h]+d, v+d, block, quadrant, nblock, budget - ) ) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - - /*-- copy 3 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while ( mainGtU ( - ptr[j-h]+d, v+d, block, quadrant, nblock, budget - ) ) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - - if (*budget < 0) return; - } - } -} - - -/*---------------------------------------------*/ -/*-- - The following is an implementation of - an elegant 3-way quicksort for strings, - described in a paper "Fast Algorithms for - Sorting and Searching Strings", by Robert - Sedgewick and Jon L. Bentley. ---*/ - -#define mswap(zz1, zz2) \ - { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } - -#define mvswap(zzp1, zzp2, zzn) \ -{ \ - Int32 yyp1 = (zzp1); \ - Int32 yyp2 = (zzp2); \ - Int32 yyn = (zzn); \ - while (yyn > 0) { \ - mswap(ptr[yyp1], ptr[yyp2]); \ - yyp1++; yyp2++; yyn--; \ - } \ -} - -static -__inline__ -UChar mmed3 ( UChar a, UChar b, UChar c ) -{ - UChar t; - if (a > b) { t = a; a = b; b = t; }; - if (b > c) { - b = c; - if (a > b) b = a; - } - return b; -} - -#define mmin(a,b) ((a) < (b)) ? (a) : (b) - -#define mpush(lz,hz,dz) { stackLo[sp] = lz; \ - stackHi[sp] = hz; \ - stackD [sp] = dz; \ - sp++; } - -#define mpop(lz,hz,dz) { sp--; \ - lz = stackLo[sp]; \ - hz = stackHi[sp]; \ - dz = stackD [sp]; } - - -#define mnextsize(az) (nextHi[az]-nextLo[az]) - -#define mnextswap(az,bz) \ - { Int32 tz; \ - tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ - tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ - tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; } - - -#define MAIN_QSORT_SMALL_THRESH 20 -#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) -#define MAIN_QSORT_STACK_SIZE 100 - -static -void mainQSort3 ( UInt32* ptr, - UChar* block, - UInt16* quadrant, - Int32 nblock, - Int32 loSt, - Int32 hiSt, - Int32 dSt, - Int32* budget ) -{ - Int32 unLo, unHi, ltLo, gtHi, n, m, med; - Int32 sp, lo, hi, d; - - Int32 stackLo[MAIN_QSORT_STACK_SIZE]; - Int32 stackHi[MAIN_QSORT_STACK_SIZE]; - Int32 stackD [MAIN_QSORT_STACK_SIZE]; - - Int32 nextLo[3]; - Int32 nextHi[3]; - Int32 nextD [3]; - - sp = 0; - mpush ( loSt, hiSt, dSt ); - - while (sp > 0) { - - AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 ); - - mpop ( lo, hi, d ); - if (hi - lo < MAIN_QSORT_SMALL_THRESH || - d > MAIN_QSORT_DEPTH_THRESH) { - mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget ); - if (*budget < 0) return; - continue; - } - - med = (Int32) - mmed3 ( block[ptr[ lo ]+d], - block[ptr[ hi ]+d], - block[ptr[ (lo+hi)>>1 ]+d] ); - - unLo = ltLo = lo; - unHi = gtHi = hi; - - while (True) { - while (True) { - if (unLo > unHi) break; - n = ((Int32)block[ptr[unLo]+d]) - med; - if (n == 0) { - mswap(ptr[unLo], ptr[ltLo]); - ltLo++; unLo++; continue; - }; - if (n > 0) break; - unLo++; - } - while (True) { - if (unLo > unHi) break; - n = ((Int32)block[ptr[unHi]+d]) - med; - if (n == 0) { - mswap(ptr[unHi], ptr[gtHi]); - gtHi--; unHi--; continue; - }; - if (n < 0) break; - unHi--; - } - if (unLo > unHi) break; - mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--; - } - - AssertD ( unHi == unLo-1, "mainQSort3(2)" ); - - if (gtHi < ltLo) { - mpush(lo, hi, d+1 ); - continue; - } - - n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n); - m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m); - - n = lo + unLo - ltLo - 1; - m = hi - (gtHi - unHi) + 1; - - nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; - nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; - nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; - - if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); - if (mnextsize(1) < mnextsize(2)) mnextswap(1,2); - if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); - - AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" ); - AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" ); - - mpush (nextLo[0], nextHi[0], nextD[0]); - mpush (nextLo[1], nextHi[1], nextD[1]); - mpush (nextLo[2], nextHi[2], nextD[2]); - } -} - -#undef mswap -#undef mvswap -#undef mpush -#undef mpop -#undef mmin -#undef mnextsize -#undef mnextswap -#undef MAIN_QSORT_SMALL_THRESH -#undef MAIN_QSORT_DEPTH_THRESH -#undef MAIN_QSORT_STACK_SIZE - - -/*---------------------------------------------*/ -/* Pre: - nblock > N_OVERSHOOT - block32 exists for [0 .. nblock-1 +N_OVERSHOOT] - ((UChar*)block32) [0 .. nblock-1] holds block - ptr exists for [0 .. nblock-1] - - Post: - ((UChar*)block32) [0 .. nblock-1] holds block - All other areas of block32 destroyed - ftab [0 .. 65536 ] destroyed - ptr [0 .. nblock-1] holds sorted order - if (*budget < 0), sorting was abandoned -*/ - -#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) -#define SETMASK (1 << 21) -#define CLEARMASK (~(SETMASK)) - -static -void mainSort ( UInt32* ptr, - UChar* block, - UInt16* quadrant, - UInt32* ftab, - Int32 nblock, - Int32 verb, - Int32* budget ) -{ - Int32 i, j, k, ss, sb; - Int32 runningOrder[256]; - Bool bigDone[256]; - Int32 copyStart[256]; - Int32 copyEnd [256]; - UChar c1; - Int32 numQSorted; - UInt16 s; - if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" ); - - /*-- set up the 2-byte frequency table --*/ - for (i = 65536; i >= 0; i--) ftab[i] = 0; - - j = block[0] << 8; - i = nblock-1; - for (; i >= 3; i -= 4) { - quadrant[i] = 0; - j = (j >> 8) | ( ((UInt16)block[i]) << 8); - ftab[j]++; - quadrant[i-1] = 0; - j = (j >> 8) | ( ((UInt16)block[i-1]) << 8); - ftab[j]++; - quadrant[i-2] = 0; - j = (j >> 8) | ( ((UInt16)block[i-2]) << 8); - ftab[j]++; - quadrant[i-3] = 0; - j = (j >> 8) | ( ((UInt16)block[i-3]) << 8); - ftab[j]++; - } - for (; i >= 0; i--) { - quadrant[i] = 0; - j = (j >> 8) | ( ((UInt16)block[i]) << 8); - ftab[j]++; - } - - /*-- (emphasises close relationship of block & quadrant) --*/ - for (i = 0; i < BZ_N_OVERSHOOT; i++) { - block [nblock+i] = block[i]; - quadrant[nblock+i] = 0; - } - - if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" ); - - /*-- Complete the initial radix sort --*/ - for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1]; - - s = block[0] << 8; - i = nblock-1; - for (; i >= 3; i -= 4) { - s = (s >> 8) | (block[i] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i; - s = (s >> 8) | (block[i-1] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i-1; - s = (s >> 8) | (block[i-2] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i-2; - s = (s >> 8) | (block[i-3] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i-3; - } - for (; i >= 0; i--) { - s = (s >> 8) | (block[i] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i; - } - - /*-- - Now ftab contains the first loc of every small bucket. - Calculate the running order, from smallest to largest - big bucket. - --*/ - for (i = 0; i <= 255; i++) { - bigDone [i] = False; - runningOrder[i] = i; - } - - { - Int32 vv; - Int32 h = 1; - do h = 3 * h + 1; while (h <= 256); - do { - h = h / 3; - for (i = h; i <= 255; i++) { - vv = runningOrder[i]; - j = i; - while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) { - runningOrder[j] = runningOrder[j-h]; - j = j - h; - if (j <= (h - 1)) goto zero; - } - zero: - runningOrder[j] = vv; - } - } while (h != 1); - } - - /*-- - The main sorting loop. - --*/ - - numQSorted = 0; - - for (i = 0; i <= 255; i++) { - - /*-- - Process big buckets, starting with the least full. - Basically this is a 3-step process in which we call - mainQSort3 to sort the small buckets [ss, j], but - also make a big effort to avoid the calls if we can. - --*/ - ss = runningOrder[i]; - - /*-- - Step 1: - Complete the big bucket [ss] by quicksorting - any unsorted small buckets [ss, j], for j != ss. - Hopefully previous pointer-scanning phases have already - completed many of the small buckets [ss, j], so - we don't have to sort them at all. - --*/ - for (j = 0; j <= 255; j++) { - if (j != ss) { - sb = (ss << 8) + j; - if ( ! (ftab[sb] & SETMASK) ) { - Int32 lo = ftab[sb] & CLEARMASK; - Int32 hi = (ftab[sb+1] & CLEARMASK) - 1; - if (hi > lo) { - if (verb >= 4) - VPrintf4 ( " qsort [0x%x, 0x%x] " - "done %d this %d\n", - ss, j, numQSorted, hi - lo + 1 ); - mainQSort3 ( - ptr, block, quadrant, nblock, - lo, hi, BZ_N_RADIX, budget - ); - numQSorted += (hi - lo + 1); - if (*budget < 0) return; - } - } - ftab[sb] |= SETMASK; - } - } - - AssertH ( !bigDone[ss], 1006 ); - - /*-- - Step 2: - Now scan this big bucket [ss] so as to synthesise the - sorted order for small buckets [t, ss] for all t, - including, magically, the bucket [ss,ss] too. - This will avoid doing Real Work in subsequent Step 1's. - --*/ - { - for (j = 0; j <= 255; j++) { - copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; - copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; - } - for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { - k = ptr[j]-1; if (k < 0) k += nblock; - c1 = block[k]; - if (!bigDone[c1]) - ptr[ copyStart[c1]++ ] = k; - } - for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { - k = ptr[j]-1; if (k < 0) k += nblock; - c1 = block[k]; - if (!bigDone[c1]) - ptr[ copyEnd[c1]-- ] = k; - } - } - - AssertH ( (copyStart[ss]-1 == copyEnd[ss]) - || - /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. - Necessity for this case is demonstrated by compressing - a sequence of approximately 48.5 million of character - 251; 1.0.0/1.0.1 will then die here. */ - (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), - 1007 ) - - for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK; - - /*-- - Step 3: - The [ss] big bucket is now done. Record this fact, - and update the quadrant descriptors. Remember to - update quadrants in the overshoot area too, if - necessary. The "if (i < 255)" test merely skips - this updating for the last bucket processed, since - updating for the last bucket is pointless. - - The quadrant array provides a way to incrementally - cache sort orderings, as they appear, so as to - make subsequent comparisons in fullGtU() complete - faster. For repetitive blocks this makes a big - difference (but not big enough to be able to avoid - the fallback sorting mechanism, exponential radix sort). - - The precise meaning is: at all times: - - for 0 <= i < nblock and 0 <= j <= nblock - - if block[i] != block[j], - - then the relative values of quadrant[i] and - quadrant[j] are meaningless. - - else { - if quadrant[i] < quadrant[j] - then the string starting at i lexicographically - precedes the string starting at j - - else if quadrant[i] > quadrant[j] - then the string starting at j lexicographically - precedes the string starting at i - - else - the relative ordering of the strings starting - at i and j has not yet been determined. - } - --*/ - bigDone[ss] = True; - - if (i < 255) { - Int32 bbStart = ftab[ss << 8] & CLEARMASK; - Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; - Int32 shifts = 0; - - while ((bbSize >> shifts) > 65534) shifts++; - - for (j = bbSize-1; j >= 0; j--) { - Int32 a2update = ptr[bbStart + j]; - UInt16 qVal = (UInt16)(j >> shifts); - quadrant[a2update] = qVal; - if (a2update < BZ_N_OVERSHOOT) - quadrant[a2update + nblock] = qVal; - } - AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 ); - } - - } - - if (verb >= 4) - VPrintf3 ( " %d pointers, %d sorted, %d scanned\n", - nblock, numQSorted, nblock - numQSorted ); -} - -#undef BIGFREQ -#undef SETMASK -#undef CLEARMASK - - -/*---------------------------------------------*/ -/* Pre: - nblock > 0 - arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] - ((UChar*)arr2) [0 .. nblock-1] holds block - arr1 exists for [0 .. nblock-1] - - Post: - ((UChar*)arr2) [0 .. nblock-1] holds block - All other areas of block destroyed - ftab [ 0 .. 65536 ] destroyed - arr1 [0 .. nblock-1] holds sorted order -*/ -void BZ2_blockSort ( EState* s ) -{ - UInt32* ptr = s->ptr; - UChar* block = s->block; - UInt32* ftab = s->ftab; - Int32 nblock = s->nblock; - Int32 verb = s->verbosity; - Int32 wfact = s->workFactor; - UInt16* quadrant; - Int32 budget; - Int32 budgetInit; - Int32 i; - - if (nblock < 10000) { - fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); - } else { - /* Calculate the location for quadrant, remembering to get - the alignment right. Assumes that &(block[0]) is at least - 2-byte aligned -- this should be ok since block is really - the first section of arr2. - */ - i = nblock+BZ_N_OVERSHOOT; - if (i & 1) i++; - quadrant = (UInt16*)(&(block[i])); - - /* (wfact-1) / 3 puts the default-factor-30 - transition point at very roughly the same place as - with v0.1 and v0.9.0. - Not that it particularly matters any more, since the - resulting compressed stream is now the same regardless - of whether or not we use the main sort or fallback sort. - */ - if (wfact < 1 ) wfact = 1; - if (wfact > 100) wfact = 100; - budgetInit = nblock * ((wfact-1) / 3); - budget = budgetInit; - - mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget ); - if (verb >= 3) - VPrintf3 ( " %d work, %d block, ratio %5.2f\n", - budgetInit - budget, - nblock, - (float)(budgetInit - budget) / - (float)(nblock==0 ? 1 : nblock) ); - if (budget < 0) { - if (verb >= 2) - VPrintf0 ( " too repetitive; using fallback" - " sorting algorithm\n" ); - fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); - } - } - - s->origPtr = -1; - for (i = 0; i < s->nblock; i++) - if (ptr[i] == 0) - { s->origPtr = i; break; }; - - AssertH( s->origPtr != -1, 1003 ); -} - - -/*-------------------------------------------------------------*/ -/*--- end blocksort.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Block sorting machinery ---*/ +/*--- blocksort.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*---------------------------------------------*/ +/*--- Fallback O(N log(N)^2) sorting ---*/ +/*--- algorithm, for repetitive blocks ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +void fallbackSimpleSort ( UInt32* fmap, + UInt32* eclass, + Int32 lo, + Int32 hi ) +{ + Int32 i, j, tmp; + UInt32 ec_tmp; + + if (lo == hi) return; + + if (hi - lo > 3) { + for ( i = hi-4; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 ) + fmap[j-4] = fmap[j]; + fmap[j-4] = tmp; + } + } + + for ( i = hi-1; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ ) + fmap[j-1] = fmap[j]; + fmap[j-1] = tmp; + } +} + + +/*---------------------------------------------*/ +#define fswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define fvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + fswap(fmap[yyp1], fmap[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + + +#define fmin(a,b) ((a) < (b)) ? (a) : (b) + +#define fpush(lz,hz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + sp++; } + +#define fpop(lz,hz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; } + +#define FALLBACK_QSORT_SMALL_THRESH 10 +#define FALLBACK_QSORT_STACK_SIZE 100 + + +static +void fallbackQSort3 ( UInt32* fmap, + UInt32* eclass, + Int32 loSt, + Int32 hiSt ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m; + Int32 sp, lo, hi; + UInt32 med, r, r3; + Int32 stackLo[FALLBACK_QSORT_STACK_SIZE]; + Int32 stackHi[FALLBACK_QSORT_STACK_SIZE]; + + r = 0; + + sp = 0; + fpush ( loSt, hiSt ); + + while (sp > 0) { + + AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 ); + + fpop ( lo, hi ); + if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { + fallbackSimpleSort ( fmap, eclass, lo, hi ); + continue; + } + + /* Random partitioning. Median of 3 sometimes fails to + avoid bad cases. Median of 9 seems to help but + looks rather expensive. This too seems to work but + is cheaper. Guidance for the magic constants + 7621 and 32768 is taken from Sedgewick's algorithms + book, chapter 35. + */ + r = ((r * 7621) + 1) % 32768; + r3 = r % 3; + if (r3 == 0) med = eclass[fmap[lo]]; else + if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else + med = eclass[fmap[hi]]; + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (1) { + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unLo]] - (Int32)med; + if (n == 0) { + fswap(fmap[unLo], fmap[ltLo]); + ltLo++; unLo++; + continue; + }; + if (n > 0) break; + unLo++; + } + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unHi]] - (Int32)med; + if (n == 0) { + fswap(fmap[unHi], fmap[gtHi]); + gtHi--; unHi--; + continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "fallbackQSort3(2)" ); + + if (gtHi < ltLo) continue; + + n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n); + m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + if (n - lo > hi - m) { + fpush ( lo, n ); + fpush ( m, hi ); + } else { + fpush ( m, hi ); + fpush ( lo, n ); + } + } +} + +#undef fmin +#undef fpush +#undef fpop +#undef fswap +#undef fvswap +#undef FALLBACK_QSORT_SMALL_THRESH +#undef FALLBACK_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + eclass exists for [0 .. nblock-1] + ((UChar*)eclass) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)eclass) [0 .. nblock-1] holds block + All other areas of eclass destroyed + fmap [0 .. nblock-1] holds sorted order + bhtab [ 0 .. 2+(nblock/32) ] destroyed +*/ + +#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) +#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) +#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) +#define WORD_BH(zz) bhtab[(zz) >> 5] +#define UNALIGNED_BH(zz) ((zz) & 0x01f) + +static +void fallbackSort ( UInt32* fmap, + UInt32* eclass, + UInt32* bhtab, + Int32 nblock, + Int32 verb ) +{ + Int32 ftab[257]; + Int32 ftabCopy[256]; + Int32 H, i, j, k, l, r, cc, cc1; + Int32 nNotDone; + Int32 nBhtab; + UChar* eclass8 = (UChar*)eclass; + + /*-- + Initial 1-char radix sort to generate + initial fmap and initial BH bits. + --*/ + if (verb >= 4) + VPrintf0 ( " bucket sorting ...\n" ); + for (i = 0; i < 257; i++) ftab[i] = 0; + for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; + for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; + for (i = 1; i < 257; i++) ftab[i] += ftab[i-1]; + + for (i = 0; i < nblock; i++) { + j = eclass8[i]; + k = ftab[j] - 1; + ftab[j] = k; + fmap[k] = i; + } + + nBhtab = 2 + (nblock / 32); + for (i = 0; i < nBhtab; i++) bhtab[i] = 0; + for (i = 0; i < 256; i++) SET_BH(ftab[i]); + + /*-- + Inductively refine the buckets. Kind-of an + "exponential radix sort" (!), inspired by the + Manber-Myers suffix array construction algorithm. + --*/ + + /*-- set sentinel bits for block-end detection --*/ + for (i = 0; i < 32; i++) { + SET_BH(nblock + 2*i); + CLEAR_BH(nblock + 2*i + 1); + } + + /*-- the log(N) loop --*/ + H = 1; + while (1) { + + if (verb >= 4) + VPrintf1 ( " depth %6d has ", H ); + + j = 0; + for (i = 0; i < nblock; i++) { + if (ISSET_BH(i)) j = i; + k = fmap[i] - H; if (k < 0) k += nblock; + eclass[k] = j; + } + + nNotDone = 0; + r = -1; + while (1) { + + /*-- find the next non-singleton bucket --*/ + k = r + 1; + while (ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (ISSET_BH(k)) { + while (WORD_BH(k) == 0xffffffff) k += 32; + while (ISSET_BH(k)) k++; + } + l = k - 1; + if (l >= nblock) break; + while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (!ISSET_BH(k)) { + while (WORD_BH(k) == 0x00000000) k += 32; + while (!ISSET_BH(k)) k++; + } + r = k - 1; + if (r >= nblock) break; + + /*-- now [l, r] bracket current bucket --*/ + if (r > l) { + nNotDone += (r - l + 1); + fallbackQSort3 ( fmap, eclass, l, r ); + + /*-- scan bucket and generate header bits-- */ + cc = -1; + for (i = l; i <= r; i++) { + cc1 = eclass[fmap[i]]; + if (cc != cc1) { SET_BH(i); cc = cc1; }; + } + } + } + + if (verb >= 4) + VPrintf1 ( "%6d unresolved strings\n", nNotDone ); + + H *= 2; + if (H > nblock || nNotDone == 0) break; + } + + /*-- + Reconstruct the original block in + eclass8 [0 .. nblock-1], since the + previous phase destroyed it. + --*/ + if (verb >= 4) + VPrintf0 ( " reconstructing block ...\n" ); + j = 0; + for (i = 0; i < nblock; i++) { + while (ftabCopy[j] == 0) j++; + ftabCopy[j]--; + eclass8[fmap[i]] = (UChar)j; + } + AssertH ( j < 256, 1005 ); +} + +#undef SET_BH +#undef CLEAR_BH +#undef ISSET_BH +#undef WORD_BH +#undef UNALIGNED_BH + + +/*---------------------------------------------*/ +/*--- The main, O(N^2 log(N)) sorting ---*/ +/*--- algorithm. Faster for "normal" ---*/ +/*--- non-repetitive blocks. ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +Bool mainGtU ( UInt32 i1, + UInt32 i2, + UChar* block, + UInt16* quadrant, + UInt32 nblock, + Int32* budget ) +{ + Int32 k; + UChar c1, c2; + UInt16 s1, s2; + + AssertD ( i1 != i2, "mainGtU" ); + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 9 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 10 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 11 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 12 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + + k = nblock + 8; + + do { + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + + if (i1 >= nblock) i1 -= nblock; + if (i2 >= nblock) i2 -= nblock; + + k -= 8; + (*budget)--; + } + while (k >= 0); + + return False; +} + + +/*---------------------------------------------*/ +/*-- + Knuth's increments seem to work better + than Incerpi-Sedgewick here. Possibly + because the number of elems to sort is + usually small, typically <= 20. +--*/ +static +Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, + 9841, 29524, 88573, 265720, + 797161, 2391484 }; + +static +void mainSimpleSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 lo, + Int32 hi, + Int32 d, + Int32* budget ) +{ + Int32 i, j, h, bigN, hp; + UInt32 v; + + bigN = hi - lo + 1; + if (bigN < 2) return; + + hp = 0; + while (incs[hp] < bigN) hp++; + hp--; + + for (; hp >= 0; hp--) { + h = incs[hp]; + + i = lo + h; + while (True) { + + /*-- copy 1 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 2 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 3 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + if (*budget < 0) return; + } + } +} + + +/*---------------------------------------------*/ +/*-- + The following is an implementation of + an elegant 3-way quicksort for strings, + described in a paper "Fast Algorithms for + Sorting and Searching Strings", by Robert + Sedgewick and Jon L. Bentley. +--*/ + +#define mswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define mvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + mswap(ptr[yyp1], ptr[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + +static +__inline__ +UChar mmed3 ( UChar a, UChar b, UChar c ) +{ + UChar t; + if (a > b) { t = a; a = b; b = t; }; + if (b > c) { + b = c; + if (a > b) b = a; + } + return b; +} + +#define mmin(a,b) ((a) < (b)) ? (a) : (b) + +#define mpush(lz,hz,dz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + stackD [sp] = dz; \ + sp++; } + +#define mpop(lz,hz,dz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; \ + dz = stackD [sp]; } + + +#define mnextsize(az) (nextHi[az]-nextLo[az]) + +#define mnextswap(az,bz) \ + { Int32 tz; \ + tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ + tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ + tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; } + + +#define MAIN_QSORT_SMALL_THRESH 20 +#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) +#define MAIN_QSORT_STACK_SIZE 100 + +static +void mainQSort3 ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 loSt, + Int32 hiSt, + Int32 dSt, + Int32* budget ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m, med; + Int32 sp, lo, hi, d; + + Int32 stackLo[MAIN_QSORT_STACK_SIZE]; + Int32 stackHi[MAIN_QSORT_STACK_SIZE]; + Int32 stackD [MAIN_QSORT_STACK_SIZE]; + + Int32 nextLo[3]; + Int32 nextHi[3]; + Int32 nextD [3]; + + sp = 0; + mpush ( loSt, hiSt, dSt ); + + while (sp > 0) { + + AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 ); + + mpop ( lo, hi, d ); + if (hi - lo < MAIN_QSORT_SMALL_THRESH || + d > MAIN_QSORT_DEPTH_THRESH) { + mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget ); + if (*budget < 0) return; + continue; + } + + med = (Int32) + mmed3 ( block[ptr[ lo ]+d], + block[ptr[ hi ]+d], + block[ptr[ (lo+hi)>>1 ]+d] ); + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (True) { + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unLo]+d]) - med; + if (n == 0) { + mswap(ptr[unLo], ptr[ltLo]); + ltLo++; unLo++; continue; + }; + if (n > 0) break; + unLo++; + } + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unHi]+d]) - med; + if (n == 0) { + mswap(ptr[unHi], ptr[gtHi]); + gtHi--; unHi--; continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "mainQSort3(2)" ); + + if (gtHi < ltLo) { + mpush(lo, hi, d+1 ); + continue; + } + + n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n); + m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; + nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; + nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; + + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + if (mnextsize(1) < mnextsize(2)) mnextswap(1,2); + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + + AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" ); + AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" ); + + mpush (nextLo[0], nextHi[0], nextD[0]); + mpush (nextLo[1], nextHi[1], nextD[1]); + mpush (nextLo[2], nextHi[2], nextD[2]); + } +} + +#undef mswap +#undef mvswap +#undef mpush +#undef mpop +#undef mmin +#undef mnextsize +#undef mnextswap +#undef MAIN_QSORT_SMALL_THRESH +#undef MAIN_QSORT_DEPTH_THRESH +#undef MAIN_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > N_OVERSHOOT + block32 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)block32) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)block32) [0 .. nblock-1] holds block + All other areas of block32 destroyed + ftab [0 .. 65536 ] destroyed + ptr [0 .. nblock-1] holds sorted order + if (*budget < 0), sorting was abandoned +*/ + +#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) +#define SETMASK (1 << 21) +#define CLEARMASK (~(SETMASK)) + +static +void mainSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + UInt32* ftab, + Int32 nblock, + Int32 verb, + Int32* budget ) +{ + Int32 i, j, k, ss, sb; + Int32 runningOrder[256]; + Bool bigDone[256]; + Int32 copyStart[256]; + Int32 copyEnd [256]; + UChar c1; + Int32 numQSorted; + UInt16 s; + if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" ); + + /*-- set up the 2-byte frequency table --*/ + for (i = 65536; i >= 0; i--) ftab[i] = 0; + + j = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + quadrant[i-1] = 0; + j = (j >> 8) | ( ((UInt16)block[i-1]) << 8); + ftab[j]++; + quadrant[i-2] = 0; + j = (j >> 8) | ( ((UInt16)block[i-2]) << 8); + ftab[j]++; + quadrant[i-3] = 0; + j = (j >> 8) | ( ((UInt16)block[i-3]) << 8); + ftab[j]++; + } + for (; i >= 0; i--) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + } + + /*-- (emphasises close relationship of block & quadrant) --*/ + for (i = 0; i < BZ_N_OVERSHOOT; i++) { + block [nblock+i] = block[i]; + quadrant[nblock+i] = 0; + } + + if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" ); + + /*-- Complete the initial radix sort --*/ + for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1]; + + s = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + s = (s >> 8) | (block[i-1] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-1; + s = (s >> 8) | (block[i-2] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-2; + s = (s >> 8) | (block[i-3] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-3; + } + for (; i >= 0; i--) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + } + + /*-- + Now ftab contains the first loc of every small bucket. + Calculate the running order, from smallest to largest + big bucket. + --*/ + for (i = 0; i <= 255; i++) { + bigDone [i] = False; + runningOrder[i] = i; + } + + { + Int32 vv; + Int32 h = 1; + do h = 3 * h + 1; while (h <= 256); + do { + h = h / 3; + for (i = h; i <= 255; i++) { + vv = runningOrder[i]; + j = i; + while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) { + runningOrder[j] = runningOrder[j-h]; + j = j - h; + if (j <= (h - 1)) goto zero; + } + zero: + runningOrder[j] = vv; + } + } while (h != 1); + } + + /*-- + The main sorting loop. + --*/ + + numQSorted = 0; + + for (i = 0; i <= 255; i++) { + + /*-- + Process big buckets, starting with the least full. + Basically this is a 3-step process in which we call + mainQSort3 to sort the small buckets [ss, j], but + also make a big effort to avoid the calls if we can. + --*/ + ss = runningOrder[i]; + + /*-- + Step 1: + Complete the big bucket [ss] by quicksorting + any unsorted small buckets [ss, j], for j != ss. + Hopefully previous pointer-scanning phases have already + completed many of the small buckets [ss, j], so + we don't have to sort them at all. + --*/ + for (j = 0; j <= 255; j++) { + if (j != ss) { + sb = (ss << 8) + j; + if ( ! (ftab[sb] & SETMASK) ) { + Int32 lo = ftab[sb] & CLEARMASK; + Int32 hi = (ftab[sb+1] & CLEARMASK) - 1; + if (hi > lo) { + if (verb >= 4) + VPrintf4 ( " qsort [0x%x, 0x%x] " + "done %d this %d\n", + ss, j, numQSorted, hi - lo + 1 ); + mainQSort3 ( + ptr, block, quadrant, nblock, + lo, hi, BZ_N_RADIX, budget + ); + numQSorted += (hi - lo + 1); + if (*budget < 0) return; + } + } + ftab[sb] |= SETMASK; + } + } + + AssertH ( !bigDone[ss], 1006 ); + + /*-- + Step 2: + Now scan this big bucket [ss] so as to synthesise the + sorted order for small buckets [t, ss] for all t, + including, magically, the bucket [ss,ss] too. + This will avoid doing Real Work in subsequent Step 1's. + --*/ + { + for (j = 0; j <= 255; j++) { + copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; + copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; + } + for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyStart[c1]++ ] = k; + } + for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyEnd[c1]-- ] = k; + } + } + + AssertH ( (copyStart[ss]-1 == copyEnd[ss]) + || + /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. + Necessity for this case is demonstrated by compressing + a sequence of approximately 48.5 million of character + 251; 1.0.0/1.0.1 will then die here. */ + (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), + 1007 ) + + for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK; + + /*-- + Step 3: + The [ss] big bucket is now done. Record this fact, + and update the quadrant descriptors. Remember to + update quadrants in the overshoot area too, if + necessary. The "if (i < 255)" test merely skips + this updating for the last bucket processed, since + updating for the last bucket is pointless. + + The quadrant array provides a way to incrementally + cache sort orderings, as they appear, so as to + make subsequent comparisons in fullGtU() complete + faster. For repetitive blocks this makes a big + difference (but not big enough to be able to avoid + the fallback sorting mechanism, exponential radix sort). + + The precise meaning is: at all times: + + for 0 <= i < nblock and 0 <= j <= nblock + + if block[i] != block[j], + + then the relative values of quadrant[i] and + quadrant[j] are meaningless. + + else { + if quadrant[i] < quadrant[j] + then the string starting at i lexicographically + precedes the string starting at j + + else if quadrant[i] > quadrant[j] + then the string starting at j lexicographically + precedes the string starting at i + + else + the relative ordering of the strings starting + at i and j has not yet been determined. + } + --*/ + bigDone[ss] = True; + + if (i < 255) { + Int32 bbStart = ftab[ss << 8] & CLEARMASK; + Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; + Int32 shifts = 0; + + while ((bbSize >> shifts) > 65534) shifts++; + + for (j = bbSize-1; j >= 0; j--) { + Int32 a2update = ptr[bbStart + j]; + UInt16 qVal = (UInt16)(j >> shifts); + quadrant[a2update] = qVal; + if (a2update < BZ_N_OVERSHOOT) + quadrant[a2update + nblock] = qVal; + } + AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 ); + } + + } + + if (verb >= 4) + VPrintf3 ( " %d pointers, %d sorted, %d scanned\n", + nblock, numQSorted, nblock - numQSorted ); +} + +#undef BIGFREQ +#undef SETMASK +#undef CLEARMASK + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)arr2) [0 .. nblock-1] holds block + arr1 exists for [0 .. nblock-1] + + Post: + ((UChar*)arr2) [0 .. nblock-1] holds block + All other areas of block destroyed + ftab [ 0 .. 65536 ] destroyed + arr1 [0 .. nblock-1] holds sorted order +*/ +void BZ2_blockSort ( EState* s ) +{ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt32* ftab = s->ftab; + Int32 nblock = s->nblock; + Int32 verb = s->verbosity; + Int32 wfact = s->workFactor; + UInt16* quadrant; + Int32 budget; + Int32 budgetInit; + Int32 i; + + if (nblock < 10000) { + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } else { + /* Calculate the location for quadrant, remembering to get + the alignment right. Assumes that &(block[0]) is at least + 2-byte aligned -- this should be ok since block is really + the first section of arr2. + */ + i = nblock+BZ_N_OVERSHOOT; + if (i & 1) i++; + quadrant = (UInt16*)(&(block[i])); + + /* (wfact-1) / 3 puts the default-factor-30 + transition point at very roughly the same place as + with v0.1 and v0.9.0. + Not that it particularly matters any more, since the + resulting compressed stream is now the same regardless + of whether or not we use the main sort or fallback sort. + */ + if (wfact < 1 ) wfact = 1; + if (wfact > 100) wfact = 100; + budgetInit = nblock * ((wfact-1) / 3); + budget = budgetInit; + + mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget ); + if (verb >= 3) + VPrintf3 ( " %d work, %d block, ratio %5.2f\n", + budgetInit - budget, + nblock, + (float)(budgetInit - budget) / + (float)(nblock==0 ? 1 : nblock) ); + if (budget < 0) { + if (verb >= 2) + VPrintf0 ( " too repetitive; using fallback" + " sorting algorithm\n" ); + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } + } + + s->origPtr = -1; + for (i = 0; i < s->nblock; i++) + if (ptr[i] == 0) + { s->origPtr = i; break; }; + + AssertH( s->origPtr != -1, 1003 ); +} + + +/*-------------------------------------------------------------*/ +/*--- end blocksort.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/3rdparty/bzip2/bzlib.c b/3rdparty/bzip2/bzlib.c index 5b70a84bbc..3afc812f75 100644 --- a/3rdparty/bzip2/bzlib.c +++ b/3rdparty/bzip2/bzlib.c @@ -1,1571 +1,1571 @@ - -/*-------------------------------------------------------------*/ -/*--- Library top-level functions. ---*/ -/*--- bzlib.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.4 of 20 December 2006 - Copyright (C) 1996-2006 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - -/* CHANGES - 0.9.0 -- original version. - 0.9.0a/b -- no changes in this file. - 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). - fixed bzWrite/bzRead to ignore zero-length requests. - fixed bzread to correctly handle read requests after EOF. - wrong parameter order in call to bzDecompressInit in - bzBuffToBuffDecompress. Fixed. -*/ - -#include "bzlib_private.h" - - -/*---------------------------------------------------*/ -/*--- Compression stuff ---*/ -/*---------------------------------------------------*/ - - -/*---------------------------------------------------*/ -#ifndef BZ_NO_STDIO -void BZ2_bz__AssertH__fail ( int errcode ) -{ - fprintf(stderr, - "\n\nbzip2/libbzip2: internal error number %d.\n" - "This is a bug in bzip2/libbzip2, %s.\n" - "Please report it to me at: jseward@bzip.org. If this happened\n" - "when you were using some program which uses libbzip2 as a\n" - "component, you should also report this bug to the author(s)\n" - "of that program. Please make an effort to report this bug;\n" - "timely and accurate bug reports eventually lead to higher\n" - "quality software. Thanks. Julian Seward, 15 February 2005.\n\n", - errcode, - BZ2_bzlibVersion() - ); - - if (errcode == 1007) { - fprintf(stderr, - "\n*** A special note about internal error number 1007 ***\n" - "\n" - "Experience suggests that a common cause of i.e. 1007\n" - "is unreliable memory or other hardware. The 1007 assertion\n" - "just happens to cross-check the results of huge numbers of\n" - "memory reads/writes, and so acts (unintendedly) as a stress\n" - "test of your memory system.\n" - "\n" - "I suggest the following: try compressing the file again,\n" - "possibly monitoring progress in detail with the -vv flag.\n" - "\n" - "* If the error cannot be reproduced, and/or happens at different\n" - " points in compression, you may have a flaky memory system.\n" - " Try a memory-test program. I have used Memtest86\n" - " (www.memtest86.com). At the time of writing it is free (GPLd).\n" - " Memtest86 tests memory much more thorougly than your BIOSs\n" - " power-on test, and may find failures that the BIOS doesn't.\n" - "\n" - "* If the error can be repeatably reproduced, this is a bug in\n" - " bzip2, and I would very much like to hear about it. Please\n" - " let me know, and, ideally, save a copy of the file causing the\n" - " problem -- without which I will be unable to investigate it.\n" - "\n" - ); - } - - exit(3); -} -#endif - - -/*---------------------------------------------------*/ -static -int bz_config_ok ( void ) -{ - if (sizeof(int) != 4) return 0; - if (sizeof(short) != 2) return 0; - if (sizeof(char) != 1) return 0; - return 1; -} - - -/*---------------------------------------------------*/ -static -void* default_bzalloc ( void* opaque, Int32 items, Int32 size ) -{ - void* v = malloc ( items * size ); - return v; -} - -static -void default_bzfree ( void* opaque, void* addr ) -{ - if (addr != NULL) free ( addr ); -} - - -/*---------------------------------------------------*/ -static -void prepare_new_block ( EState* s ) -{ - Int32 i; - s->nblock = 0; - s->numZ = 0; - s->state_out_pos = 0; - BZ_INITIALISE_CRC ( s->blockCRC ); - for (i = 0; i < 256; i++) s->inUse[i] = False; - s->blockNo++; -} - - -/*---------------------------------------------------*/ -static -void init_RL ( EState* s ) -{ - s->state_in_ch = 256; - s->state_in_len = 0; -} - - -static -Bool isempty_RL ( EState* s ) -{ - if (s->state_in_ch < 256 && s->state_in_len > 0) - return False; else - return True; -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzCompressInit) - ( bz_stream* strm, - int blockSize100k, - int verbosity, - int workFactor ) -{ - Int32 n; - EState* s; - - if (!bz_config_ok()) return BZ_CONFIG_ERROR; - - if (strm == NULL || - blockSize100k < 1 || blockSize100k > 9 || - workFactor < 0 || workFactor > 250) - return BZ_PARAM_ERROR; - - if (workFactor == 0) workFactor = 30; - if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; - if (strm->bzfree == NULL) strm->bzfree = default_bzfree; - - s = BZALLOC( sizeof(EState) ); - if (s == NULL) return BZ_MEM_ERROR; - s->strm = strm; - - s->arr1 = NULL; - s->arr2 = NULL; - s->ftab = NULL; - - n = 100000 * blockSize100k; - s->arr1 = BZALLOC( n * sizeof(UInt32) ); - s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) ); - s->ftab = BZALLOC( 65537 * sizeof(UInt32) ); - - if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) { - if (s->arr1 != NULL) BZFREE(s->arr1); - if (s->arr2 != NULL) BZFREE(s->arr2); - if (s->ftab != NULL) BZFREE(s->ftab); - if (s != NULL) BZFREE(s); - return BZ_MEM_ERROR; - } - - s->blockNo = 0; - s->state = BZ_S_INPUT; - s->mode = BZ_M_RUNNING; - s->combinedCRC = 0; - s->blockSize100k = blockSize100k; - s->nblockMAX = 100000 * blockSize100k - 19; - s->verbosity = verbosity; - s->workFactor = workFactor; - - s->block = (UChar*)s->arr2; - s->mtfv = (UInt16*)s->arr1; - s->zbits = NULL; - s->ptr = (UInt32*)s->arr1; - - strm->state = s; - strm->total_in_lo32 = 0; - strm->total_in_hi32 = 0; - strm->total_out_lo32 = 0; - strm->total_out_hi32 = 0; - init_RL ( s ); - prepare_new_block ( s ); - return BZ_OK; -} - - -/*---------------------------------------------------*/ -static -void add_pair_to_block ( EState* s ) -{ - Int32 i; - UChar ch = (UChar)(s->state_in_ch); - for (i = 0; i < s->state_in_len; i++) { - BZ_UPDATE_CRC( s->blockCRC, ch ); - } - s->inUse[s->state_in_ch] = True; - switch (s->state_in_len) { - case 1: - s->block[s->nblock] = (UChar)ch; s->nblock++; - break; - case 2: - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - break; - case 3: - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - break; - default: - s->inUse[s->state_in_len-4] = True; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = ((UChar)(s->state_in_len-4)); - s->nblock++; - break; - } -} - - -/*---------------------------------------------------*/ -static -void flush_RL ( EState* s ) -{ - if (s->state_in_ch < 256) add_pair_to_block ( s ); - init_RL ( s ); -} - - -/*---------------------------------------------------*/ -#define ADD_CHAR_TO_BLOCK(zs,zchh0) \ -{ \ - UInt32 zchh = (UInt32)(zchh0); \ - /*-- fast track the common case --*/ \ - if (zchh != zs->state_in_ch && \ - zs->state_in_len == 1) { \ - UChar ch = (UChar)(zs->state_in_ch); \ - BZ_UPDATE_CRC( zs->blockCRC, ch ); \ - zs->inUse[zs->state_in_ch] = True; \ - zs->block[zs->nblock] = (UChar)ch; \ - zs->nblock++; \ - zs->state_in_ch = zchh; \ - } \ - else \ - /*-- general, uncommon cases --*/ \ - if (zchh != zs->state_in_ch || \ - zs->state_in_len == 255) { \ - if (zs->state_in_ch < 256) \ - add_pair_to_block ( zs ); \ - zs->state_in_ch = zchh; \ - zs->state_in_len = 1; \ - } else { \ - zs->state_in_len++; \ - } \ -} - - -/*---------------------------------------------------*/ -static -Bool copy_input_until_stop ( EState* s ) -{ - Bool progress_in = False; - - if (s->mode == BZ_M_RUNNING) { - - /*-- fast track the common case --*/ - while (True) { - /*-- block full? --*/ - if (s->nblock >= s->nblockMAX) break; - /*-- no input? --*/ - if (s->strm->avail_in == 0) break; - progress_in = True; - ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); - s->strm->next_in++; - s->strm->avail_in--; - s->strm->total_in_lo32++; - if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; - } - - } else { - - /*-- general, uncommon case --*/ - while (True) { - /*-- block full? --*/ - if (s->nblock >= s->nblockMAX) break; - /*-- no input? --*/ - if (s->strm->avail_in == 0) break; - /*-- flush/finish end? --*/ - if (s->avail_in_expect == 0) break; - progress_in = True; - ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); - s->strm->next_in++; - s->strm->avail_in--; - s->strm->total_in_lo32++; - if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; - s->avail_in_expect--; - } - } - return progress_in; -} - - -/*---------------------------------------------------*/ -static -Bool copy_output_until_stop ( EState* s ) -{ - Bool progress_out = False; - - while (True) { - - /*-- no output space? --*/ - if (s->strm->avail_out == 0) break; - - /*-- block done? --*/ - if (s->state_out_pos >= s->numZ) break; - - progress_out = True; - *(s->strm->next_out) = s->zbits[s->state_out_pos]; - s->state_out_pos++; - s->strm->avail_out--; - s->strm->next_out++; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - return progress_out; -} - - -/*---------------------------------------------------*/ -static -Bool handle_compress ( bz_stream* strm ) -{ - Bool progress_in = False; - Bool progress_out = False; - EState* s = strm->state; - - while (True) { - - if (s->state == BZ_S_OUTPUT) { - progress_out |= copy_output_until_stop ( s ); - if (s->state_out_pos < s->numZ) break; - if (s->mode == BZ_M_FINISHING && - s->avail_in_expect == 0 && - isempty_RL(s)) break; - prepare_new_block ( s ); - s->state = BZ_S_INPUT; - if (s->mode == BZ_M_FLUSHING && - s->avail_in_expect == 0 && - isempty_RL(s)) break; - } - - if (s->state == BZ_S_INPUT) { - progress_in |= copy_input_until_stop ( s ); - if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { - flush_RL ( s ); - BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) ); - s->state = BZ_S_OUTPUT; - } - else - if (s->nblock >= s->nblockMAX) { - BZ2_compressBlock ( s, False ); - s->state = BZ_S_OUTPUT; - } - else - if (s->strm->avail_in == 0) { - break; - } - } - - } - - return progress_in || progress_out; -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action ) -{ - Bool progress; - EState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - preswitch: - switch (s->mode) { - - case BZ_M_IDLE: - return BZ_SEQUENCE_ERROR; - - case BZ_M_RUNNING: - if (action == BZ_RUN) { - progress = handle_compress ( strm ); - return progress ? BZ_RUN_OK : BZ_PARAM_ERROR; - } - else - if (action == BZ_FLUSH) { - s->avail_in_expect = strm->avail_in; - s->mode = BZ_M_FLUSHING; - goto preswitch; - } - else - if (action == BZ_FINISH) { - s->avail_in_expect = strm->avail_in; - s->mode = BZ_M_FINISHING; - goto preswitch; - } - else - return BZ_PARAM_ERROR; - - case BZ_M_FLUSHING: - if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR; - if (s->avail_in_expect != s->strm->avail_in) - return BZ_SEQUENCE_ERROR; - progress = handle_compress ( strm ); - if (s->avail_in_expect > 0 || !isempty_RL(s) || - s->state_out_pos < s->numZ) return BZ_FLUSH_OK; - s->mode = BZ_M_RUNNING; - return BZ_RUN_OK; - - case BZ_M_FINISHING: - if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR; - if (s->avail_in_expect != s->strm->avail_in) - return BZ_SEQUENCE_ERROR; - progress = handle_compress ( strm ); - if (!progress) return BZ_SEQUENCE_ERROR; - if (s->avail_in_expect > 0 || !isempty_RL(s) || - s->state_out_pos < s->numZ) return BZ_FINISH_OK; - s->mode = BZ_M_IDLE; - return BZ_STREAM_END; - } - return BZ_OK; /*--not reached--*/ -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm ) -{ - EState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - if (s->arr1 != NULL) BZFREE(s->arr1); - if (s->arr2 != NULL) BZFREE(s->arr2); - if (s->ftab != NULL) BZFREE(s->ftab); - BZFREE(strm->state); - - strm->state = NULL; - - return BZ_OK; -} - - -/*---------------------------------------------------*/ -/*--- Decompression stuff ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzDecompressInit) - ( bz_stream* strm, - int verbosity, - int small ) -{ - DState* s; - - if (!bz_config_ok()) return BZ_CONFIG_ERROR; - - if (strm == NULL) return BZ_PARAM_ERROR; - if (small != 0 && small != 1) return BZ_PARAM_ERROR; - if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; - - if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; - if (strm->bzfree == NULL) strm->bzfree = default_bzfree; - - s = BZALLOC( sizeof(DState) ); - if (s == NULL) return BZ_MEM_ERROR; - s->strm = strm; - strm->state = s; - s->state = BZ_X_MAGIC_1; - s->bsLive = 0; - s->bsBuff = 0; - s->calculatedCombinedCRC = 0; - strm->total_in_lo32 = 0; - strm->total_in_hi32 = 0; - strm->total_out_lo32 = 0; - strm->total_out_hi32 = 0; - s->smallDecompress = (Bool)small; - s->ll4 = NULL; - s->ll16 = NULL; - s->tt = NULL; - s->currBlockNo = 0; - s->verbosity = verbosity; - - return BZ_OK; -} - - -/*---------------------------------------------------*/ -/* Return True iff data corruption is discovered. - Returns False if there is no problem. -*/ -static -Bool unRLE_obuf_to_output_FAST ( DState* s ) -{ - UChar k1; - - if (s->blockRandomised) { - - while (True) { - /* try to finish existing run */ - while (True) { - if (s->strm->avail_out == 0) return False; - if (s->state_out_len == 0) break; - *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; - BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); - s->state_out_len--; - s->strm->next_out++; - s->strm->avail_out--; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - /* can a new run be started? */ - if (s->nblock_used == s->save_nblock+1) return False; - - /* Only caused by corrupt data stream? */ - if (s->nblock_used > s->save_nblock+1) - return True; - - s->state_out_len = 1; - s->state_out_ch = s->k0; - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 2; - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 3; - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - s->state_out_len = ((Int32)k1) + 4; - BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; - s->k0 ^= BZ_RAND_MASK; s->nblock_used++; - } - - } else { - - /* restore */ - UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; - UChar c_state_out_ch = s->state_out_ch; - Int32 c_state_out_len = s->state_out_len; - Int32 c_nblock_used = s->nblock_used; - Int32 c_k0 = s->k0; - UInt32* c_tt = s->tt; - UInt32 c_tPos = s->tPos; - char* cs_next_out = s->strm->next_out; - unsigned int cs_avail_out = s->strm->avail_out; - /* end restore */ - - UInt32 avail_out_INIT = cs_avail_out; - Int32 s_save_nblockPP = s->save_nblock+1; - unsigned int total_out_lo32_old; - - while (True) { - - /* try to finish existing run */ - if (c_state_out_len > 0) { - while (True) { - if (cs_avail_out == 0) goto return_notr; - if (c_state_out_len == 1) break; - *( (UChar*)(cs_next_out) ) = c_state_out_ch; - BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); - c_state_out_len--; - cs_next_out++; - cs_avail_out--; - } - s_state_out_len_eq_one: - { - if (cs_avail_out == 0) { - c_state_out_len = 1; goto return_notr; - }; - *( (UChar*)(cs_next_out) ) = c_state_out_ch; - BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); - cs_next_out++; - cs_avail_out--; - } - } - /* Only caused by corrupt data stream? */ - if (c_nblock_used > s_save_nblockPP) - return True; - - /* can a new run be started? */ - if (c_nblock_used == s_save_nblockPP) { - c_state_out_len = 0; goto return_notr; - }; - c_state_out_ch = c_k0; - BZ_GET_FAST_C(k1); c_nblock_used++; - if (k1 != c_k0) { - c_k0 = k1; goto s_state_out_len_eq_one; - }; - if (c_nblock_used == s_save_nblockPP) - goto s_state_out_len_eq_one; - - c_state_out_len = 2; - BZ_GET_FAST_C(k1); c_nblock_used++; - if (c_nblock_used == s_save_nblockPP) continue; - if (k1 != c_k0) { c_k0 = k1; continue; }; - - c_state_out_len = 3; - BZ_GET_FAST_C(k1); c_nblock_used++; - if (c_nblock_used == s_save_nblockPP) continue; - if (k1 != c_k0) { c_k0 = k1; continue; }; - - BZ_GET_FAST_C(k1); c_nblock_used++; - c_state_out_len = ((Int32)k1) + 4; - BZ_GET_FAST_C(c_k0); c_nblock_used++; - } - - return_notr: - total_out_lo32_old = s->strm->total_out_lo32; - s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); - if (s->strm->total_out_lo32 < total_out_lo32_old) - s->strm->total_out_hi32++; - - /* save */ - s->calculatedBlockCRC = c_calculatedBlockCRC; - s->state_out_ch = c_state_out_ch; - s->state_out_len = c_state_out_len; - s->nblock_used = c_nblock_used; - s->k0 = c_k0; - s->tt = c_tt; - s->tPos = c_tPos; - s->strm->next_out = cs_next_out; - s->strm->avail_out = cs_avail_out; - /* end save */ - } - return False; -} - - - -/*---------------------------------------------------*/ -__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) -{ - Int32 nb, na, mid; - nb = 0; - na = 256; - do { - mid = (nb + na) >> 1; - if (indx >= cftab[mid]) nb = mid; else na = mid; - } - while (na - nb != 1); - return nb; -} - - -/*---------------------------------------------------*/ -/* Return True iff data corruption is discovered. - Returns False if there is no problem. -*/ -static -Bool unRLE_obuf_to_output_SMALL ( DState* s ) -{ - UChar k1; - - if (s->blockRandomised) { - - while (True) { - /* try to finish existing run */ - while (True) { - if (s->strm->avail_out == 0) return False; - if (s->state_out_len == 0) break; - *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; - BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); - s->state_out_len--; - s->strm->next_out++; - s->strm->avail_out--; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - /* can a new run be started? */ - if (s->nblock_used == s->save_nblock+1) return False; - - /* Only caused by corrupt data stream? */ - if (s->nblock_used > s->save_nblock+1) - return True; - - s->state_out_len = 1; - s->state_out_ch = s->k0; - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 2; - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 3; - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - s->state_out_len = ((Int32)k1) + 4; - BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; - s->k0 ^= BZ_RAND_MASK; s->nblock_used++; - } - - } else { - - while (True) { - /* try to finish existing run */ - while (True) { - if (s->strm->avail_out == 0) return False; - if (s->state_out_len == 0) break; - *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; - BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); - s->state_out_len--; - s->strm->next_out++; - s->strm->avail_out--; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - /* can a new run be started? */ - if (s->nblock_used == s->save_nblock+1) return False; - - /* Only caused by corrupt data stream? */ - if (s->nblock_used > s->save_nblock+1) - return True; - - s->state_out_len = 1; - s->state_out_ch = s->k0; - BZ_GET_SMALL(k1); s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 2; - BZ_GET_SMALL(k1); s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 3; - BZ_GET_SMALL(k1); s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - BZ_GET_SMALL(k1); s->nblock_used++; - s->state_out_len = ((Int32)k1) + 4; - BZ_GET_SMALL(s->k0); s->nblock_used++; - } - - } -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) -{ - Bool corrupt; - DState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - while (True) { - if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; - if (s->state == BZ_X_OUTPUT) { - if (s->smallDecompress) - corrupt = unRLE_obuf_to_output_SMALL ( s ); else - corrupt = unRLE_obuf_to_output_FAST ( s ); - if (corrupt) return BZ_DATA_ERROR; - if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { - BZ_FINALISE_CRC ( s->calculatedBlockCRC ); - if (s->verbosity >= 3) - VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, - s->calculatedBlockCRC ); - if (s->verbosity >= 2) VPrintf0 ( "]" ); - if (s->calculatedBlockCRC != s->storedBlockCRC) - return BZ_DATA_ERROR; - s->calculatedCombinedCRC - = (s->calculatedCombinedCRC << 1) | - (s->calculatedCombinedCRC >> 31); - s->calculatedCombinedCRC ^= s->calculatedBlockCRC; - s->state = BZ_X_BLKHDR_1; - } else { - return BZ_OK; - } - } - if (s->state >= BZ_X_MAGIC_1) { - Int32 r = BZ2_decompress ( s ); - if (r == BZ_STREAM_END) { - if (s->verbosity >= 3) - VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x", - s->storedCombinedCRC, s->calculatedCombinedCRC ); - if (s->calculatedCombinedCRC != s->storedCombinedCRC) - return BZ_DATA_ERROR; - return r; - } - if (s->state != BZ_X_OUTPUT) return r; - } - } - - AssertH ( 0, 6001 ); - - return 0; /*NOTREACHED*/ -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) -{ - DState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - if (s->tt != NULL) BZFREE(s->tt); - if (s->ll16 != NULL) BZFREE(s->ll16); - if (s->ll4 != NULL) BZFREE(s->ll4); - - BZFREE(strm->state); - strm->state = NULL; - - return BZ_OK; -} - - -#ifndef BZ_NO_STDIO -/*---------------------------------------------------*/ -/*--- File I/O stuff ---*/ -/*---------------------------------------------------*/ - -#define BZ_SETERR(eee) \ -{ \ - if (bzerror != NULL) *bzerror = eee; \ - if (bzf != NULL) bzf->lastErr = eee; \ -} - -typedef - struct { - FILE* handle; - Char buf[BZ_MAX_UNUSED]; - Int32 bufN; - Bool writing; - bz_stream strm; - Int32 lastErr; - Bool initialisedOk; - } - bzFile; - - -/*---------------------------------------------*/ -static Bool myfeof ( FILE* f ) -{ - Int32 c = fgetc ( f ); - if (c == EOF) return True; - ungetc ( c, f ); - return False; -} - - -/*---------------------------------------------------*/ -BZFILE* BZ_API(BZ2_bzWriteOpen) - ( int* bzerror, - FILE* f, - int blockSize100k, - int verbosity, - int workFactor ) -{ - Int32 ret; - bzFile* bzf = NULL; - - BZ_SETERR(BZ_OK); - - if (f == NULL || - (blockSize100k < 1 || blockSize100k > 9) || - (workFactor < 0 || workFactor > 250) || - (verbosity < 0 || verbosity > 4)) - { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; - - if (ferror(f)) - { BZ_SETERR(BZ_IO_ERROR); return NULL; }; - - bzf = malloc ( sizeof(bzFile) ); - if (bzf == NULL) - { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; - - BZ_SETERR(BZ_OK); - bzf->initialisedOk = False; - bzf->bufN = 0; - bzf->handle = f; - bzf->writing = True; - bzf->strm.bzalloc = NULL; - bzf->strm.bzfree = NULL; - bzf->strm.opaque = NULL; - - if (workFactor == 0) workFactor = 30; - ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, - verbosity, workFactor ); - if (ret != BZ_OK) - { BZ_SETERR(ret); free(bzf); return NULL; }; - - bzf->strm.avail_in = 0; - bzf->initialisedOk = True; - return bzf; -} - - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzWrite) - ( int* bzerror, - BZFILE* b, - void* buf, - int len ) -{ - Int32 n, n2, ret; - bzFile* bzf = (bzFile*)b; - - BZ_SETERR(BZ_OK); - if (bzf == NULL || buf == NULL || len < 0) - { BZ_SETERR(BZ_PARAM_ERROR); return; }; - if (!(bzf->writing)) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - - if (len == 0) - { BZ_SETERR(BZ_OK); return; }; - - bzf->strm.avail_in = len; - bzf->strm.next_in = buf; - - while (True) { - bzf->strm.avail_out = BZ_MAX_UNUSED; - bzf->strm.next_out = bzf->buf; - ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN ); - if (ret != BZ_RUN_OK) - { BZ_SETERR(ret); return; }; - - if (bzf->strm.avail_out < BZ_MAX_UNUSED) { - n = BZ_MAX_UNUSED - bzf->strm.avail_out; - n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), - n, bzf->handle ); - if (n != n2 || ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - } - - if (bzf->strm.avail_in == 0) - { BZ_SETERR(BZ_OK); return; }; - } -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzWriteClose) - ( int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in, - unsigned int* nbytes_out ) -{ - BZ2_bzWriteClose64 ( bzerror, b, abandon, - nbytes_in, NULL, nbytes_out, NULL ); -} - - -void BZ_API(BZ2_bzWriteClose64) - ( int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in_lo32, - unsigned int* nbytes_in_hi32, - unsigned int* nbytes_out_lo32, - unsigned int* nbytes_out_hi32 ) -{ - Int32 n, n2, ret; - bzFile* bzf = (bzFile*)b; - - if (bzf == NULL) - { BZ_SETERR(BZ_OK); return; }; - if (!(bzf->writing)) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - - if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0; - if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0; - if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0; - if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0; - - if ((!abandon) && bzf->lastErr == BZ_OK) { - while (True) { - bzf->strm.avail_out = BZ_MAX_UNUSED; - bzf->strm.next_out = bzf->buf; - ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH ); - if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) - { BZ_SETERR(ret); return; }; - - if (bzf->strm.avail_out < BZ_MAX_UNUSED) { - n = BZ_MAX_UNUSED - bzf->strm.avail_out; - n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), - n, bzf->handle ); - if (n != n2 || ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - } - - if (ret == BZ_STREAM_END) break; - } - } - - if ( !abandon && !ferror ( bzf->handle ) ) { - fflush ( bzf->handle ); - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - } - - if (nbytes_in_lo32 != NULL) - *nbytes_in_lo32 = bzf->strm.total_in_lo32; - if (nbytes_in_hi32 != NULL) - *nbytes_in_hi32 = bzf->strm.total_in_hi32; - if (nbytes_out_lo32 != NULL) - *nbytes_out_lo32 = bzf->strm.total_out_lo32; - if (nbytes_out_hi32 != NULL) - *nbytes_out_hi32 = bzf->strm.total_out_hi32; - - BZ_SETERR(BZ_OK); - BZ2_bzCompressEnd ( &(bzf->strm) ); - free ( bzf ); -} - - -/*---------------------------------------------------*/ -BZFILE* BZ_API(BZ2_bzReadOpen) - ( int* bzerror, - FILE* f, - int verbosity, - int small, - void* unused, - int nUnused ) -{ - bzFile* bzf = NULL; - int ret; - - BZ_SETERR(BZ_OK); - - if (f == NULL || - (small != 0 && small != 1) || - (verbosity < 0 || verbosity > 4) || - (unused == NULL && nUnused != 0) || - (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) - { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; - - if (ferror(f)) - { BZ_SETERR(BZ_IO_ERROR); return NULL; }; - - bzf = malloc ( sizeof(bzFile) ); - if (bzf == NULL) - { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; - - BZ_SETERR(BZ_OK); - - bzf->initialisedOk = False; - bzf->handle = f; - bzf->bufN = 0; - bzf->writing = False; - bzf->strm.bzalloc = NULL; - bzf->strm.bzfree = NULL; - bzf->strm.opaque = NULL; - - while (nUnused > 0) { - bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; - unused = ((void*)( 1 + ((UChar*)(unused)) )); - nUnused--; - } - - ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); - if (ret != BZ_OK) - { BZ_SETERR(ret); free(bzf); return NULL; }; - - bzf->strm.avail_in = bzf->bufN; - bzf->strm.next_in = bzf->buf; - - bzf->initialisedOk = True; - return bzf; -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) -{ - bzFile* bzf = (bzFile*)b; - - BZ_SETERR(BZ_OK); - if (bzf == NULL) - { BZ_SETERR(BZ_OK); return; }; - - if (bzf->writing) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - - if (bzf->initialisedOk) - (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); - free ( bzf ); -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzRead) - ( int* bzerror, - BZFILE* b, - void* buf, - int len ) -{ - Int32 n, ret; - bzFile* bzf = (bzFile*)b; - - BZ_SETERR(BZ_OK); - - if (bzf == NULL || buf == NULL || len < 0) - { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; - - if (bzf->writing) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; - - if (len == 0) - { BZ_SETERR(BZ_OK); return 0; }; - - bzf->strm.avail_out = len; - bzf->strm.next_out = buf; - - while (True) { - - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return 0; }; - - if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { - n = fread ( bzf->buf, sizeof(UChar), - BZ_MAX_UNUSED, bzf->handle ); - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return 0; }; - bzf->bufN = n; - bzf->strm.avail_in = bzf->bufN; - bzf->strm.next_in = bzf->buf; - } - - ret = BZ2_bzDecompress ( &(bzf->strm) ); - - if (ret != BZ_OK && ret != BZ_STREAM_END) - { BZ_SETERR(ret); return 0; }; - - if (ret == BZ_OK && myfeof(bzf->handle) && - bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) - { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; - - if (ret == BZ_STREAM_END) - { BZ_SETERR(BZ_STREAM_END); - return len - bzf->strm.avail_out; }; - if (bzf->strm.avail_out == 0) - { BZ_SETERR(BZ_OK); return len; }; - - } - - return 0; /*not reached*/ -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzReadGetUnused) - ( int* bzerror, - BZFILE* b, - void** unused, - int* nUnused ) -{ - bzFile* bzf = (bzFile*)b; - if (bzf == NULL) - { BZ_SETERR(BZ_PARAM_ERROR); return; }; - if (bzf->lastErr != BZ_STREAM_END) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - if (unused == NULL || nUnused == NULL) - { BZ_SETERR(BZ_PARAM_ERROR); return; }; - - BZ_SETERR(BZ_OK); - *nUnused = bzf->strm.avail_in; - *unused = bzf->strm.next_in; -} -#endif - - -/*---------------------------------------------------*/ -/*--- Misc convenience stuff ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzBuffToBuffCompress) - ( char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int blockSize100k, - int verbosity, - int workFactor ) -{ - bz_stream strm; - int ret; - - if (dest == NULL || destLen == NULL || - source == NULL || - blockSize100k < 1 || blockSize100k > 9 || - verbosity < 0 || verbosity > 4 || - workFactor < 0 || workFactor > 250) - return BZ_PARAM_ERROR; - - if (workFactor == 0) workFactor = 30; - strm.bzalloc = NULL; - strm.bzfree = NULL; - strm.opaque = NULL; - ret = BZ2_bzCompressInit ( &strm, blockSize100k, - verbosity, workFactor ); - if (ret != BZ_OK) return ret; - - strm.next_in = source; - strm.next_out = dest; - strm.avail_in = sourceLen; - strm.avail_out = *destLen; - - ret = BZ2_bzCompress ( &strm, BZ_FINISH ); - if (ret == BZ_FINISH_OK) goto output_overflow; - if (ret != BZ_STREAM_END) goto errhandler; - - /* normal termination */ - *destLen -= strm.avail_out; - BZ2_bzCompressEnd ( &strm ); - return BZ_OK; - - output_overflow: - BZ2_bzCompressEnd ( &strm ); - return BZ_OUTBUFF_FULL; - - errhandler: - BZ2_bzCompressEnd ( &strm ); - return ret; -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzBuffToBuffDecompress) - ( char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int small, - int verbosity ) -{ - bz_stream strm; - int ret; - - if (dest == NULL || destLen == NULL || - source == NULL || - (small != 0 && small != 1) || - verbosity < 0 || verbosity > 4) - return BZ_PARAM_ERROR; - - strm.bzalloc = NULL; - strm.bzfree = NULL; - strm.opaque = NULL; - ret = BZ2_bzDecompressInit ( &strm, verbosity, small ); - if (ret != BZ_OK) return ret; - - strm.next_in = source; - strm.next_out = dest; - strm.avail_in = sourceLen; - strm.avail_out = *destLen; - - ret = BZ2_bzDecompress ( &strm ); - if (ret == BZ_OK) goto output_overflow_or_eof; - if (ret != BZ_STREAM_END) goto errhandler; - - /* normal termination */ - *destLen -= strm.avail_out; - BZ2_bzDecompressEnd ( &strm ); - return BZ_OK; - - output_overflow_or_eof: - if (strm.avail_out > 0) { - BZ2_bzDecompressEnd ( &strm ); - return BZ_UNEXPECTED_EOF; - } else { - BZ2_bzDecompressEnd ( &strm ); - return BZ_OUTBUFF_FULL; - }; - - errhandler: - BZ2_bzDecompressEnd ( &strm ); - return ret; -} - - -/*---------------------------------------------------*/ -/*-- - Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) - to support better zlib compatibility. - This code is not _officially_ part of libbzip2 (yet); - I haven't tested it, documented it, or considered the - threading-safeness of it. - If this code breaks, please contact both Yoshioka and me. ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -/*-- - return version like "0.9.5d, 4-Sept-1999". ---*/ -const char * BZ_API(BZ2_bzlibVersion)(void) -{ - return BZ_VERSION; -} - - -#ifndef BZ_NO_STDIO -/*---------------------------------------------------*/ - -#if defined(_WIN32) || defined(OS2) || defined(MSDOS) -# include -# include -# define SET_BINARY_MODE(file) _setmode(_fileno(file),O_BINARY) -#else -# define SET_BINARY_MODE(file) -#endif -static -BZFILE * bzopen_or_bzdopen - ( const char *path, /* no use when bzdopen */ - int fd, /* no use when bzdopen */ - const char *mode, - int open_mode) /* bzopen: 0, bzdopen:1 */ -{ - int bzerr; - char unused[BZ_MAX_UNUSED]; - int blockSize100k = 9; - int writing = 0; - char mode2[10] = ""; - FILE *fp = NULL; - BZFILE *bzfp = NULL; - int verbosity = 0; - int workFactor = 30; - int smallMode = 0; - int nUnused = 0; - - if (mode == NULL) return NULL; - while (*mode) { - switch (*mode) { - case 'r': - writing = 0; break; - case 'w': - writing = 1; break; - case 's': - smallMode = 1; break; - default: - if (isdigit((int)(*mode))) { - blockSize100k = *mode-BZ_HDR_0; - } - } - mode++; - } - strcat(mode2, writing ? "w" : "r" ); - strcat(mode2,"b"); /* binary mode */ - - if (open_mode==0) { - if (path==NULL || strcmp(path,"")==0) { - fp = (writing ? stdout : stdin); - SET_BINARY_MODE(fp); - } else { - fp = fopen(path,mode2); - } - } else { -#ifdef BZ_STRICT_ANSI - fp = NULL; -#else - fp = _fdopen(fd,mode2); -#endif - } - if (fp == NULL) return NULL; - - if (writing) { - /* Guard against total chaos and anarchy -- JRS */ - if (blockSize100k < 1) blockSize100k = 1; - if (blockSize100k > 9) blockSize100k = 9; - bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k, - verbosity,workFactor); - } else { - bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode, - unused,nUnused); - } - if (bzfp == NULL) { - if (fp != stdin && fp != stdout) fclose(fp); - return NULL; - } - return bzfp; -} - - -/*---------------------------------------------------*/ -/*-- - open file for read or write. - ex) bzopen("file","w9") - case path="" or NULL => use stdin or stdout. ---*/ -BZFILE * BZ_API(BZ2_bzopen) - ( const char *path, - const char *mode ) -{ - return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0); -} - - -/*---------------------------------------------------*/ -BZFILE * BZ_API(BZ2_bzdopen) - ( int fd, - const char *mode ) -{ - return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1); -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len ) -{ - int bzerr, nread; - if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0; - nread = BZ2_bzRead(&bzerr,b,buf,len); - if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) { - return nread; - } else { - return -1; - } -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len ) -{ - int bzerr; - - BZ2_bzWrite(&bzerr,b,buf,len); - if(bzerr == BZ_OK){ - return len; - }else{ - return -1; - } -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzflush) (BZFILE *b) -{ - /* do nothing now... */ - return 0; -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzclose) (BZFILE* b) -{ - int bzerr; - FILE *fp; - - if (b==NULL) {return;} - fp = ((bzFile *)b)->handle; - if(((bzFile*)b)->writing){ - BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); - if(bzerr != BZ_OK){ - BZ2_bzWriteClose(NULL,b,1,NULL,NULL); - } - }else{ - BZ2_bzReadClose(&bzerr,b); - } - if(fp!=stdin && fp!=stdout){ - fclose(fp); - } -} - - -/*---------------------------------------------------*/ -/*-- - return last error code ---*/ -static const char *bzerrorstrings[] = { - "OK" - ,"SEQUENCE_ERROR" - ,"PARAM_ERROR" - ,"MEM_ERROR" - ,"DATA_ERROR" - ,"DATA_ERROR_MAGIC" - ,"IO_ERROR" - ,"UNEXPECTED_EOF" - ,"OUTBUFF_FULL" - ,"CONFIG_ERROR" - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ -}; - - -const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum) -{ - int err = ((bzFile *)b)->lastErr; - - if(err>0) err = 0; - *errnum = err; - return bzerrorstrings[err*-1]; -} -#endif - - -/*-------------------------------------------------------------*/ -/*--- end bzlib.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Library top-level functions. ---*/ +/*--- bzlib.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + +/* CHANGES + 0.9.0 -- original version. + 0.9.0a/b -- no changes in this file. + 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). + fixed bzWrite/bzRead to ignore zero-length requests. + fixed bzread to correctly handle read requests after EOF. + wrong parameter order in call to bzDecompressInit in + bzBuffToBuffDecompress. Fixed. +*/ + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Compression stuff ---*/ +/*---------------------------------------------------*/ + + +/*---------------------------------------------------*/ +#ifndef BZ_NO_STDIO +void BZ2_bz__AssertH__fail ( int errcode ) +{ + fprintf(stderr, + "\n\nbzip2/libbzip2: internal error number %d.\n" + "This is a bug in bzip2/libbzip2, %s.\n" + "Please report it to me at: jseward@bzip.org. If this happened\n" + "when you were using some program which uses libbzip2 as a\n" + "component, you should also report this bug to the author(s)\n" + "of that program. Please make an effort to report this bug;\n" + "timely and accurate bug reports eventually lead to higher\n" + "quality software. Thanks. Julian Seward, 15 February 2005.\n\n", + errcode, + BZ2_bzlibVersion() + ); + + if (errcode == 1007) { + fprintf(stderr, + "\n*** A special note about internal error number 1007 ***\n" + "\n" + "Experience suggests that a common cause of i.e. 1007\n" + "is unreliable memory or other hardware. The 1007 assertion\n" + "just happens to cross-check the results of huge numbers of\n" + "memory reads/writes, and so acts (unintendedly) as a stress\n" + "test of your memory system.\n" + "\n" + "I suggest the following: try compressing the file again,\n" + "possibly monitoring progress in detail with the -vv flag.\n" + "\n" + "* If the error cannot be reproduced, and/or happens at different\n" + " points in compression, you may have a flaky memory system.\n" + " Try a memory-test program. I have used Memtest86\n" + " (www.memtest86.com). At the time of writing it is free (GPLd).\n" + " Memtest86 tests memory much more thorougly than your BIOSs\n" + " power-on test, and may find failures that the BIOS doesn't.\n" + "\n" + "* If the error can be repeatably reproduced, this is a bug in\n" + " bzip2, and I would very much like to hear about it. Please\n" + " let me know, and, ideally, save a copy of the file causing the\n" + " problem -- without which I will be unable to investigate it.\n" + "\n" + ); + } + + exit(3); +} +#endif + + +/*---------------------------------------------------*/ +static +int bz_config_ok ( void ) +{ + if (sizeof(int) != 4) return 0; + if (sizeof(short) != 2) return 0; + if (sizeof(char) != 1) return 0; + return 1; +} + + +/*---------------------------------------------------*/ +static +void* default_bzalloc ( void* opaque, Int32 items, Int32 size ) +{ + void* v = malloc ( items * size ); + return v; +} + +static +void default_bzfree ( void* opaque, void* addr ) +{ + if (addr != NULL) free ( addr ); +} + + +/*---------------------------------------------------*/ +static +void prepare_new_block ( EState* s ) +{ + Int32 i; + s->nblock = 0; + s->numZ = 0; + s->state_out_pos = 0; + BZ_INITIALISE_CRC ( s->blockCRC ); + for (i = 0; i < 256; i++) s->inUse[i] = False; + s->blockNo++; +} + + +/*---------------------------------------------------*/ +static +void init_RL ( EState* s ) +{ + s->state_in_ch = 256; + s->state_in_len = 0; +} + + +static +Bool isempty_RL ( EState* s ) +{ + if (s->state_in_ch < 256 && s->state_in_len > 0) + return False; else + return True; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressInit) + ( bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 n; + EState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL || + blockSize100k < 1 || blockSize100k > 9 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(EState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + + s->arr1 = NULL; + s->arr2 = NULL; + s->ftab = NULL; + + n = 100000 * blockSize100k; + s->arr1 = BZALLOC( n * sizeof(UInt32) ); + s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) ); + s->ftab = BZALLOC( 65537 * sizeof(UInt32) ); + + if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) { + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + if (s != NULL) BZFREE(s); + return BZ_MEM_ERROR; + } + + s->blockNo = 0; + s->state = BZ_S_INPUT; + s->mode = BZ_M_RUNNING; + s->combinedCRC = 0; + s->blockSize100k = blockSize100k; + s->nblockMAX = 100000 * blockSize100k - 19; + s->verbosity = verbosity; + s->workFactor = workFactor; + + s->block = (UChar*)s->arr2; + s->mtfv = (UInt16*)s->arr1; + s->zbits = NULL; + s->ptr = (UInt32*)s->arr1; + + strm->state = s; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + init_RL ( s ); + prepare_new_block ( s ); + return BZ_OK; +} + + +/*---------------------------------------------------*/ +static +void add_pair_to_block ( EState* s ) +{ + Int32 i; + UChar ch = (UChar)(s->state_in_ch); + for (i = 0; i < s->state_in_len; i++) { + BZ_UPDATE_CRC( s->blockCRC, ch ); + } + s->inUse[s->state_in_ch] = True; + switch (s->state_in_len) { + case 1: + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 2: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 3: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + default: + s->inUse[s->state_in_len-4] = True; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = ((UChar)(s->state_in_len-4)); + s->nblock++; + break; + } +} + + +/*---------------------------------------------------*/ +static +void flush_RL ( EState* s ) +{ + if (s->state_in_ch < 256) add_pair_to_block ( s ); + init_RL ( s ); +} + + +/*---------------------------------------------------*/ +#define ADD_CHAR_TO_BLOCK(zs,zchh0) \ +{ \ + UInt32 zchh = (UInt32)(zchh0); \ + /*-- fast track the common case --*/ \ + if (zchh != zs->state_in_ch && \ + zs->state_in_len == 1) { \ + UChar ch = (UChar)(zs->state_in_ch); \ + BZ_UPDATE_CRC( zs->blockCRC, ch ); \ + zs->inUse[zs->state_in_ch] = True; \ + zs->block[zs->nblock] = (UChar)ch; \ + zs->nblock++; \ + zs->state_in_ch = zchh; \ + } \ + else \ + /*-- general, uncommon cases --*/ \ + if (zchh != zs->state_in_ch || \ + zs->state_in_len == 255) { \ + if (zs->state_in_ch < 256) \ + add_pair_to_block ( zs ); \ + zs->state_in_ch = zchh; \ + zs->state_in_len = 1; \ + } else { \ + zs->state_in_len++; \ + } \ +} + + +/*---------------------------------------------------*/ +static +Bool copy_input_until_stop ( EState* s ) +{ + Bool progress_in = False; + + if (s->mode == BZ_M_RUNNING) { + + /*-- fast track the common case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + } + + } else { + + /*-- general, uncommon case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + /*-- flush/finish end? --*/ + if (s->avail_in_expect == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + s->avail_in_expect--; + } + } + return progress_in; +} + + +/*---------------------------------------------------*/ +static +Bool copy_output_until_stop ( EState* s ) +{ + Bool progress_out = False; + + while (True) { + + /*-- no output space? --*/ + if (s->strm->avail_out == 0) break; + + /*-- block done? --*/ + if (s->state_out_pos >= s->numZ) break; + + progress_out = True; + *(s->strm->next_out) = s->zbits[s->state_out_pos]; + s->state_out_pos++; + s->strm->avail_out--; + s->strm->next_out++; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + return progress_out; +} + + +/*---------------------------------------------------*/ +static +Bool handle_compress ( bz_stream* strm ) +{ + Bool progress_in = False; + Bool progress_out = False; + EState* s = strm->state; + + while (True) { + + if (s->state == BZ_S_OUTPUT) { + progress_out |= copy_output_until_stop ( s ); + if (s->state_out_pos < s->numZ) break; + if (s->mode == BZ_M_FINISHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + prepare_new_block ( s ); + s->state = BZ_S_INPUT; + if (s->mode == BZ_M_FLUSHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + } + + if (s->state == BZ_S_INPUT) { + progress_in |= copy_input_until_stop ( s ); + if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { + flush_RL ( s ); + BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) ); + s->state = BZ_S_OUTPUT; + } + else + if (s->nblock >= s->nblockMAX) { + BZ2_compressBlock ( s, False ); + s->state = BZ_S_OUTPUT; + } + else + if (s->strm->avail_in == 0) { + break; + } + } + + } + + return progress_in || progress_out; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action ) +{ + Bool progress; + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + preswitch: + switch (s->mode) { + + case BZ_M_IDLE: + return BZ_SEQUENCE_ERROR; + + case BZ_M_RUNNING: + if (action == BZ_RUN) { + progress = handle_compress ( strm ); + return progress ? BZ_RUN_OK : BZ_PARAM_ERROR; + } + else + if (action == BZ_FLUSH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FLUSHING; + goto preswitch; + } + else + if (action == BZ_FINISH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FINISHING; + goto preswitch; + } + else + return BZ_PARAM_ERROR; + + case BZ_M_FLUSHING: + if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FLUSH_OK; + s->mode = BZ_M_RUNNING; + return BZ_RUN_OK; + + case BZ_M_FINISHING: + if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (!progress) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FINISH_OK; + s->mode = BZ_M_IDLE; + return BZ_STREAM_END; + } + return BZ_OK; /*--not reached--*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm ) +{ + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + BZFREE(strm->state); + + strm->state = NULL; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/*--- Decompression stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressInit) + ( bz_stream* strm, + int verbosity, + int small ) +{ + DState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL) return BZ_PARAM_ERROR; + if (small != 0 && small != 1) return BZ_PARAM_ERROR; + if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; + + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(DState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + strm->state = s; + s->state = BZ_X_MAGIC_1; + s->bsLive = 0; + s->bsBuff = 0; + s->calculatedCombinedCRC = 0; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + s->smallDecompress = (Bool)small; + s->ll4 = NULL; + s->ll16 = NULL; + s->tt = NULL; + s->currBlockNo = 0; + s->verbosity = verbosity; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_FAST ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + /* restore */ + UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; + UChar c_state_out_ch = s->state_out_ch; + Int32 c_state_out_len = s->state_out_len; + Int32 c_nblock_used = s->nblock_used; + Int32 c_k0 = s->k0; + UInt32* c_tt = s->tt; + UInt32 c_tPos = s->tPos; + char* cs_next_out = s->strm->next_out; + unsigned int cs_avail_out = s->strm->avail_out; + /* end restore */ + + UInt32 avail_out_INIT = cs_avail_out; + Int32 s_save_nblockPP = s->save_nblock+1; + unsigned int total_out_lo32_old; + + while (True) { + + /* try to finish existing run */ + if (c_state_out_len > 0) { + while (True) { + if (cs_avail_out == 0) goto return_notr; + if (c_state_out_len == 1) break; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + c_state_out_len--; + cs_next_out++; + cs_avail_out--; + } + s_state_out_len_eq_one: + { + if (cs_avail_out == 0) { + c_state_out_len = 1; goto return_notr; + }; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + cs_next_out++; + cs_avail_out--; + } + } + /* Only caused by corrupt data stream? */ + if (c_nblock_used > s_save_nblockPP) + return True; + + /* can a new run be started? */ + if (c_nblock_used == s_save_nblockPP) { + c_state_out_len = 0; goto return_notr; + }; + c_state_out_ch = c_k0; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (k1 != c_k0) { + c_k0 = k1; goto s_state_out_len_eq_one; + }; + if (c_nblock_used == s_save_nblockPP) + goto s_state_out_len_eq_one; + + c_state_out_len = 2; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + c_state_out_len = 3; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + BZ_GET_FAST_C(k1); c_nblock_used++; + c_state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST_C(c_k0); c_nblock_used++; + } + + return_notr: + total_out_lo32_old = s->strm->total_out_lo32; + s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); + if (s->strm->total_out_lo32 < total_out_lo32_old) + s->strm->total_out_hi32++; + + /* save */ + s->calculatedBlockCRC = c_calculatedBlockCRC; + s->state_out_ch = c_state_out_ch; + s->state_out_len = c_state_out_len; + s->nblock_used = c_nblock_used; + s->k0 = c_k0; + s->tt = c_tt; + s->tPos = c_tPos; + s->strm->next_out = cs_next_out; + s->strm->avail_out = cs_avail_out; + /* end save */ + } + return False; +} + + + +/*---------------------------------------------------*/ +__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) +{ + Int32 nb, na, mid; + nb = 0; + na = 256; + do { + mid = (nb + na) >> 1; + if (indx >= cftab[mid]) nb = mid; else na = mid; + } + while (na - nb != 1); + return nb; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_SMALL ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) +{ + Bool corrupt; + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + while (True) { + if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; + if (s->state == BZ_X_OUTPUT) { + if (s->smallDecompress) + corrupt = unRLE_obuf_to_output_SMALL ( s ); else + corrupt = unRLE_obuf_to_output_FAST ( s ); + if (corrupt) return BZ_DATA_ERROR; + if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { + BZ_FINALISE_CRC ( s->calculatedBlockCRC ); + if (s->verbosity >= 3) + VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, + s->calculatedBlockCRC ); + if (s->verbosity >= 2) VPrintf0 ( "]" ); + if (s->calculatedBlockCRC != s->storedBlockCRC) + return BZ_DATA_ERROR; + s->calculatedCombinedCRC + = (s->calculatedCombinedCRC << 1) | + (s->calculatedCombinedCRC >> 31); + s->calculatedCombinedCRC ^= s->calculatedBlockCRC; + s->state = BZ_X_BLKHDR_1; + } else { + return BZ_OK; + } + } + if (s->state >= BZ_X_MAGIC_1) { + Int32 r = BZ2_decompress ( s ); + if (r == BZ_STREAM_END) { + if (s->verbosity >= 3) + VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x", + s->storedCombinedCRC, s->calculatedCombinedCRC ); + if (s->calculatedCombinedCRC != s->storedCombinedCRC) + return BZ_DATA_ERROR; + return r; + } + if (s->state != BZ_X_OUTPUT) return r; + } + } + + AssertH ( 0, 6001 ); + + return 0; /*NOTREACHED*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) +{ + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->tt != NULL) BZFREE(s->tt); + if (s->ll16 != NULL) BZFREE(s->ll16); + if (s->ll4 != NULL) BZFREE(s->ll4); + + BZFREE(strm->state); + strm->state = NULL; + + return BZ_OK; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ +/*--- File I/O stuff ---*/ +/*---------------------------------------------------*/ + +#define BZ_SETERR(eee) \ +{ \ + if (bzerror != NULL) *bzerror = eee; \ + if (bzf != NULL) bzf->lastErr = eee; \ +} + +typedef + struct { + FILE* handle; + Char buf[BZ_MAX_UNUSED]; + Int32 bufN; + Bool writing; + bz_stream strm; + Int32 lastErr; + Bool initialisedOk; + } + bzFile; + + +/*---------------------------------------------*/ +static Bool myfeof ( FILE* f ) +{ + Int32 c = fgetc ( f ); + if (c == EOF) return True; + ungetc ( c, f ); + return False; +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzWriteOpen) + ( int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 ret; + bzFile* bzf = NULL; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (blockSize100k < 1 || blockSize100k > 9) || + (workFactor < 0 || workFactor > 250) || + (verbosity < 0 || verbosity > 4)) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + bzf->initialisedOk = False; + bzf->bufN = 0; + bzf->handle = f; + bzf->writing = True; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + if (workFactor == 0) workFactor = 30; + ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = 0; + bzf->initialisedOk = True; + return bzf; +} + + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWrite) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return; }; + + bzf->strm.avail_in = len; + bzf->strm.next_in = buf; + + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN ); + if (ret != BZ_RUN_OK) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (bzf->strm.avail_in == 0) + { BZ_SETERR(BZ_OK); return; }; + } +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWriteClose) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out ) +{ + BZ2_bzWriteClose64 ( bzerror, b, abandon, + nbytes_in, NULL, nbytes_out, NULL ); +} + + +void BZ_API(BZ2_bzWriteClose64) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0; + if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0; + if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0; + if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0; + + if ((!abandon) && bzf->lastErr == BZ_OK) { + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH ); + if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (ret == BZ_STREAM_END) break; + } + } + + if ( !abandon && !ferror ( bzf->handle ) ) { + fflush ( bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (nbytes_in_lo32 != NULL) + *nbytes_in_lo32 = bzf->strm.total_in_lo32; + if (nbytes_in_hi32 != NULL) + *nbytes_in_hi32 = bzf->strm.total_in_hi32; + if (nbytes_out_lo32 != NULL) + *nbytes_out_lo32 = bzf->strm.total_out_lo32; + if (nbytes_out_hi32 != NULL) + *nbytes_out_hi32 = bzf->strm.total_out_hi32; + + BZ_SETERR(BZ_OK); + BZ2_bzCompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzReadOpen) + ( int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused ) +{ + bzFile* bzf = NULL; + int ret; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (small != 0 && small != 1) || + (verbosity < 0 || verbosity > 4) || + (unused == NULL && nUnused != 0) || + (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + + bzf->initialisedOk = False; + bzf->handle = f; + bzf->bufN = 0; + bzf->writing = False; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + while (nUnused > 0) { + bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; + unused = ((void*)( 1 + ((UChar*)(unused)) )); + nUnused--; + } + + ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + + bzf->initialisedOk = True; + return bzf; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) +{ + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + + if (bzf->initialisedOk) + (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzRead) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return 0; }; + + bzf->strm.avail_out = len; + bzf->strm.next_out = buf; + + while (True) { + + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + + if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { + n = fread ( bzf->buf, sizeof(UChar), + BZ_MAX_UNUSED, bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + bzf->bufN = n; + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + } + + ret = BZ2_bzDecompress ( &(bzf->strm) ); + + if (ret != BZ_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return 0; }; + + if (ret == BZ_OK && myfeof(bzf->handle) && + bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) + { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; + + if (ret == BZ_STREAM_END) + { BZ_SETERR(BZ_STREAM_END); + return len - bzf->strm.avail_out; }; + if (bzf->strm.avail_out == 0) + { BZ_SETERR(BZ_OK); return len; }; + + } + + return 0; /*not reached*/ +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadGetUnused) + ( int* bzerror, + BZFILE* b, + void** unused, + int* nUnused ) +{ + bzFile* bzf = (bzFile*)b; + if (bzf == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (bzf->lastErr != BZ_STREAM_END) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (unused == NULL || nUnused == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + + BZ_SETERR(BZ_OK); + *nUnused = bzf->strm.avail_in; + *unused = bzf->strm.next_in; +} +#endif + + +/*---------------------------------------------------*/ +/*--- Misc convenience stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffCompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + blockSize100k < 1 || blockSize100k > 9 || + verbosity < 0 || verbosity > 4 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzCompressInit ( &strm, blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzCompress ( &strm, BZ_FINISH ); + if (ret == BZ_FINISH_OK) goto output_overflow; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzCompressEnd ( &strm ); + return BZ_OK; + + output_overflow: + BZ2_bzCompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + + errhandler: + BZ2_bzCompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffDecompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + (small != 0 && small != 1) || + verbosity < 0 || verbosity > 4) + return BZ_PARAM_ERROR; + + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzDecompressInit ( &strm, verbosity, small ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzDecompress ( &strm ); + if (ret == BZ_OK) goto output_overflow_or_eof; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzDecompressEnd ( &strm ); + return BZ_OK; + + output_overflow_or_eof: + if (strm.avail_out > 0) { + BZ2_bzDecompressEnd ( &strm ); + return BZ_UNEXPECTED_EOF; + } else { + BZ2_bzDecompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + }; + + errhandler: + BZ2_bzDecompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +/*-- + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +/*-- + return version like "0.9.5d, 4-Sept-1999". +--*/ +const char * BZ_API(BZ2_bzlibVersion)(void) +{ + return BZ_VERSION; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ + +#if defined(_WIN32) || defined(OS2) || defined(MSDOS) +# include +# include +# define SET_BINARY_MODE(file) _setmode(_fileno(file),O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif +static +BZFILE * bzopen_or_bzdopen + ( const char *path, /* no use when bzdopen */ + int fd, /* no use when bzdopen */ + const char *mode, + int open_mode) /* bzopen: 0, bzdopen:1 */ +{ + int bzerr; + char unused[BZ_MAX_UNUSED]; + int blockSize100k = 9; + int writing = 0; + char mode2[10] = ""; + FILE *fp = NULL; + BZFILE *bzfp = NULL; + int verbosity = 0; + int workFactor = 30; + int smallMode = 0; + int nUnused = 0; + + if (mode == NULL) return NULL; + while (*mode) { + switch (*mode) { + case 'r': + writing = 0; break; + case 'w': + writing = 1; break; + case 's': + smallMode = 1; break; + default: + if (isdigit((int)(*mode))) { + blockSize100k = *mode-BZ_HDR_0; + } + } + mode++; + } + strcat(mode2, writing ? "w" : "r" ); + strcat(mode2,"b"); /* binary mode */ + + if (open_mode==0) { + if (path==NULL || strcmp(path,"")==0) { + fp = (writing ? stdout : stdin); + SET_BINARY_MODE(fp); + } else { + fp = fopen(path,mode2); + } + } else { +#ifdef BZ_STRICT_ANSI + fp = NULL; +#else + fp = _fdopen(fd,mode2); +#endif + } + if (fp == NULL) return NULL; + + if (writing) { + /* Guard against total chaos and anarchy -- JRS */ + if (blockSize100k < 1) blockSize100k = 1; + if (blockSize100k > 9) blockSize100k = 9; + bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k, + verbosity,workFactor); + } else { + bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode, + unused,nUnused); + } + if (bzfp == NULL) { + if (fp != stdin && fp != stdout) fclose(fp); + return NULL; + } + return bzfp; +} + + +/*---------------------------------------------------*/ +/*-- + open file for read or write. + ex) bzopen("file","w9") + case path="" or NULL => use stdin or stdout. +--*/ +BZFILE * BZ_API(BZ2_bzopen) + ( const char *path, + const char *mode ) +{ + return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0); +} + + +/*---------------------------------------------------*/ +BZFILE * BZ_API(BZ2_bzdopen) + ( int fd, + const char *mode ) +{ + return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len ) +{ + int bzerr, nread; + if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0; + nread = BZ2_bzRead(&bzerr,b,buf,len); + if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) { + return nread; + } else { + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len ) +{ + int bzerr; + + BZ2_bzWrite(&bzerr,b,buf,len); + if(bzerr == BZ_OK){ + return len; + }else{ + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzflush) (BZFILE *b) +{ + /* do nothing now... */ + return 0; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzclose) (BZFILE* b) +{ + int bzerr; + FILE *fp; + + if (b==NULL) {return;} + fp = ((bzFile *)b)->handle; + if(((bzFile*)b)->writing){ + BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); + if(bzerr != BZ_OK){ + BZ2_bzWriteClose(NULL,b,1,NULL,NULL); + } + }else{ + BZ2_bzReadClose(&bzerr,b); + } + if(fp!=stdin && fp!=stdout){ + fclose(fp); + } +} + + +/*---------------------------------------------------*/ +/*-- + return last error code +--*/ +static const char *bzerrorstrings[] = { + "OK" + ,"SEQUENCE_ERROR" + ,"PARAM_ERROR" + ,"MEM_ERROR" + ,"DATA_ERROR" + ,"DATA_ERROR_MAGIC" + ,"IO_ERROR" + ,"UNEXPECTED_EOF" + ,"OUTBUFF_FULL" + ,"CONFIG_ERROR" + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ +}; + + +const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum) +{ + int err = ((bzFile *)b)->lastErr; + + if(err>0) err = 0; + *errnum = err; + return bzerrorstrings[err*-1]; +} +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/3rdparty/bzip2/bzlib.h b/3rdparty/bzip2/bzlib.h index 941c9c5908..fdb0dbe7b0 100644 --- a/3rdparty/bzip2/bzlib.h +++ b/3rdparty/bzip2/bzlib.h @@ -1,282 +1,282 @@ - -/*-------------------------------------------------------------*/ -/*--- Public header file for the library. ---*/ -/*--- bzlib.h ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.4 of 20 December 2006 - Copyright (C) 1996-2006 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#ifndef _BZLIB_H -#define _BZLIB_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define BZ_RUN 0 -#define BZ_FLUSH 1 -#define BZ_FINISH 2 - -#define BZ_OK 0 -#define BZ_RUN_OK 1 -#define BZ_FLUSH_OK 2 -#define BZ_FINISH_OK 3 -#define BZ_STREAM_END 4 -#define BZ_SEQUENCE_ERROR (-1) -#define BZ_PARAM_ERROR (-2) -#define BZ_MEM_ERROR (-3) -#define BZ_DATA_ERROR (-4) -#define BZ_DATA_ERROR_MAGIC (-5) -#define BZ_IO_ERROR (-6) -#define BZ_UNEXPECTED_EOF (-7) -#define BZ_OUTBUFF_FULL (-8) -#define BZ_CONFIG_ERROR (-9) - -typedef - struct { - char *next_in; - unsigned int avail_in; - unsigned int total_in_lo32; - unsigned int total_in_hi32; - - char *next_out; - unsigned int avail_out; - unsigned int total_out_lo32; - unsigned int total_out_hi32; - - void *state; - - void *(*bzalloc)(void *,int,int); - void (*bzfree)(void *,void *); - void *opaque; - } - bz_stream; - - -#ifndef BZ_IMPORT -#define BZ_EXPORT -#endif - -#ifndef BZ_NO_STDIO -/* Need a definitition for FILE */ -#include -#endif - -#ifdef _WIN32 -# include -# ifdef small - /* windows.h define small to char */ -# undef small -# endif -# ifdef BZ_EXPORT -# define BZ_API(func) WINAPI func -# define BZ_EXTERN extern -# else - /* import windows dll dynamically */ -# define BZ_API(func) (WINAPI * func) -# define BZ_EXTERN -# endif -#else -# define BZ_API(func) func -# define BZ_EXTERN extern -#endif - - -/*-- Core (low-level) library functions --*/ - -BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( - bz_stream* strm, - int blockSize100k, - int verbosity, - int workFactor - ); - -BZ_EXTERN int BZ_API(BZ2_bzCompress) ( - bz_stream* strm, - int action - ); - -BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( - bz_stream* strm - ); - -BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( - bz_stream *strm, - int verbosity, - int small - ); - -BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( - bz_stream* strm - ); - -BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( - bz_stream *strm - ); - - - -/*-- High(er) level library functions --*/ - -#ifndef BZ_NO_STDIO -#define BZ_MAX_UNUSED 5000 - -typedef void BZFILE; - -BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( - int* bzerror, - FILE* f, - int verbosity, - int small, - void* unused, - int nUnused - ); - -BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( - int* bzerror, - BZFILE* b - ); - -BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( - int* bzerror, - BZFILE* b, - void** unused, - int* nUnused - ); - -BZ_EXTERN int BZ_API(BZ2_bzRead) ( - int* bzerror, - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( - int* bzerror, - FILE* f, - int blockSize100k, - int verbosity, - int workFactor - ); - -BZ_EXTERN void BZ_API(BZ2_bzWrite) ( - int* bzerror, - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( - int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in, - unsigned int* nbytes_out - ); - -BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( - int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in_lo32, - unsigned int* nbytes_in_hi32, - unsigned int* nbytes_out_lo32, - unsigned int* nbytes_out_hi32 - ); -#endif - - -/*-- Utility functions --*/ - -BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( - char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int blockSize100k, - int verbosity, - int workFactor - ); - -BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( - char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int small, - int verbosity - ); - - -/*-- - Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) - to support better zlib compatibility. - This code is not _officially_ part of libbzip2 (yet); - I haven't tested it, documented it, or considered the - threading-safeness of it. - If this code breaks, please contact both Yoshioka and me. ---*/ - -BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) ( - void - ); - -#ifndef BZ_NO_STDIO -BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) ( - const char *path, - const char *mode - ); - -BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) ( - int fd, - const char *mode - ); - -BZ_EXTERN int BZ_API(BZ2_bzread) ( - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN int BZ_API(BZ2_bzwrite) ( - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN int BZ_API(BZ2_bzflush) ( - BZFILE* b - ); - -BZ_EXTERN void BZ_API(BZ2_bzclose) ( - BZFILE* b - ); - -BZ_EXTERN const char * BZ_API(BZ2_bzerror) ( - BZFILE *b, - int *errnum - ); -#endif - -#ifdef __cplusplus -} -#endif - -#endif - -/*-------------------------------------------------------------*/ -/*--- end bzlib.h ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Public header file for the library. ---*/ +/*--- bzlib.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#ifndef _BZLIB_H +#define _BZLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define BZ_RUN 0 +#define BZ_FLUSH 1 +#define BZ_FINISH 2 + +#define BZ_OK 0 +#define BZ_RUN_OK 1 +#define BZ_FLUSH_OK 2 +#define BZ_FINISH_OK 3 +#define BZ_STREAM_END 4 +#define BZ_SEQUENCE_ERROR (-1) +#define BZ_PARAM_ERROR (-2) +#define BZ_MEM_ERROR (-3) +#define BZ_DATA_ERROR (-4) +#define BZ_DATA_ERROR_MAGIC (-5) +#define BZ_IO_ERROR (-6) +#define BZ_UNEXPECTED_EOF (-7) +#define BZ_OUTBUFF_FULL (-8) +#define BZ_CONFIG_ERROR (-9) + +typedef + struct { + char *next_in; + unsigned int avail_in; + unsigned int total_in_lo32; + unsigned int total_in_hi32; + + char *next_out; + unsigned int avail_out; + unsigned int total_out_lo32; + unsigned int total_out_hi32; + + void *state; + + void *(*bzalloc)(void *,int,int); + void (*bzfree)(void *,void *); + void *opaque; + } + bz_stream; + + +#ifndef BZ_IMPORT +#define BZ_EXPORT +#endif + +#ifndef BZ_NO_STDIO +/* Need a definitition for FILE */ +#include +#endif + +#ifdef _WIN32 +# include +# ifdef small + /* windows.h define small to char */ +# undef small +# endif +# ifdef BZ_EXPORT +# define BZ_API(func) WINAPI func +# define BZ_EXTERN extern +# else + /* import windows dll dynamically */ +# define BZ_API(func) (WINAPI * func) +# define BZ_EXTERN +# endif +#else +# define BZ_API(func) func +# define BZ_EXTERN extern +#endif + + +/*-- Core (low-level) library functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( + bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompress) ( + bz_stream* strm, + int action + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( + bz_stream *strm, + int verbosity, + int small + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( + bz_stream *strm + ); + + + +/*-- High(er) level library functions --*/ + +#ifndef BZ_NO_STDIO +#define BZ_MAX_UNUSED 5000 + +typedef void BZFILE; + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( + int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( + int* bzerror, + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( + int* bzerror, + BZFILE* b, + void** unused, + int* nUnused + ); + +BZ_EXTERN int BZ_API(BZ2_bzRead) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( + int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN void BZ_API(BZ2_bzWrite) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 + ); +#endif + + +/*-- Utility functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity + ); + + +/*-- + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ + +BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) ( + void + ); + +#ifndef BZ_NO_STDIO +BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) ( + const char *path, + const char *mode + ); + +BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) ( + int fd, + const char *mode + ); + +BZ_EXTERN int BZ_API(BZ2_bzread) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzwrite) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzflush) ( + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzclose) ( + BZFILE* b + ); + +BZ_EXTERN const char * BZ_API(BZ2_bzerror) ( + BZFILE *b, + int *errnum + ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +/*-------------------------------------------------------------*/ +/*--- end bzlib.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/3rdparty/bzip2/bzlib_private.h b/3rdparty/bzip2/bzlib_private.h index df7a22dd31..d0a05546ef 100644 --- a/3rdparty/bzip2/bzlib_private.h +++ b/3rdparty/bzip2/bzlib_private.h @@ -1,503 +1,503 @@ - -/*-------------------------------------------------------------*/ -/*--- Private header file for the library. ---*/ -/*--- bzlib_private.h ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.4 of 20 December 2006 - Copyright (C) 1996-2006 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#ifndef _BZLIB_PRIVATE_H -#define _BZLIB_PRIVATE_H - -#include - -#ifndef BZ_NO_STDIO -#include -#include -#include -#endif - -#include "bzlib.h" - - - -/*-- General stuff. --*/ - -#define BZ_VERSION "1.0.4, 20-Dec-2006" - -typedef char Char; -typedef unsigned char Bool; -typedef unsigned char UChar; -typedef int Int32; -typedef unsigned int UInt32; -typedef short Int16; -typedef unsigned short UInt16; - -#define True ((Bool)1) -#define False ((Bool)0) - -#ifndef __GNUC__ -#define __inline__ /* */ -#endif - -#ifndef BZ_NO_STDIO - -extern void BZ2_bz__AssertH__fail ( int errcode ); -#define AssertH(cond,errcode) \ - { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); } - -#if BZ_DEBUG -#define AssertD(cond,msg) \ - { if (!(cond)) { \ - fprintf ( stderr, \ - "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\ - exit(1); \ - }} -#else -#define AssertD(cond,msg) /* */ -#endif - -#define VPrintf0(zf) \ - fprintf(stderr,zf) -#define VPrintf1(zf,za1) \ - fprintf(stderr,zf,za1) -#define VPrintf2(zf,za1,za2) \ - fprintf(stderr,zf,za1,za2) -#define VPrintf3(zf,za1,za2,za3) \ - fprintf(stderr,zf,za1,za2,za3) -#define VPrintf4(zf,za1,za2,za3,za4) \ - fprintf(stderr,zf,za1,za2,za3,za4) -#define VPrintf5(zf,za1,za2,za3,za4,za5) \ - fprintf(stderr,zf,za1,za2,za3,za4,za5) - -#else - -extern void bz_internal_error ( int errcode ); -#define AssertH(cond,errcode) \ - { if (!(cond)) bz_internal_error ( errcode ); } -#define AssertD(cond,msg) do { } while (0) -#define VPrintf0(zf) do { } while (0) -#define VPrintf1(zf,za1) do { } while (0) -#define VPrintf2(zf,za1,za2) do { } while (0) -#define VPrintf3(zf,za1,za2,za3) do { } while (0) -#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0) -#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0) - -#endif - - -#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1) -#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp)) - - -/*-- Header bytes. --*/ - -#define BZ_HDR_B 0x42 /* 'B' */ -#define BZ_HDR_Z 0x5a /* 'Z' */ -#define BZ_HDR_h 0x68 /* 'h' */ -#define BZ_HDR_0 0x30 /* '0' */ - -/*-- Constants for the back end. --*/ - -#define BZ_MAX_ALPHA_SIZE 258 -#define BZ_MAX_CODE_LEN 23 - -#define BZ_RUNA 0 -#define BZ_RUNB 1 - -#define BZ_N_GROUPS 6 -#define BZ_G_SIZE 50 -#define BZ_N_ITERS 4 - -#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) - - - -/*-- Stuff for randomising repetitive blocks. --*/ - -extern Int32 BZ2_rNums[512]; - -#define BZ_RAND_DECLS \ - Int32 rNToGo; \ - Int32 rTPos \ - -#define BZ_RAND_INIT_MASK \ - s->rNToGo = 0; \ - s->rTPos = 0 \ - -#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0) - -#define BZ_RAND_UPD_MASK \ - if (s->rNToGo == 0) { \ - s->rNToGo = BZ2_rNums[s->rTPos]; \ - s->rTPos++; \ - if (s->rTPos == 512) s->rTPos = 0; \ - } \ - s->rNToGo--; - - - -/*-- Stuff for doing CRCs. --*/ - -extern UInt32 BZ2_crc32Table[256]; - -#define BZ_INITIALISE_CRC(crcVar) \ -{ \ - crcVar = 0xffffffffL; \ -} - -#define BZ_FINALISE_CRC(crcVar) \ -{ \ - crcVar = ~(crcVar); \ -} - -#define BZ_UPDATE_CRC(crcVar,cha) \ -{ \ - crcVar = (crcVar << 8) ^ \ - BZ2_crc32Table[(crcVar >> 24) ^ \ - ((UChar)cha)]; \ -} - - - -/*-- States and modes for compression. --*/ - -#define BZ_M_IDLE 1 -#define BZ_M_RUNNING 2 -#define BZ_M_FLUSHING 3 -#define BZ_M_FINISHING 4 - -#define BZ_S_OUTPUT 1 -#define BZ_S_INPUT 2 - -#define BZ_N_RADIX 2 -#define BZ_N_QSORT 12 -#define BZ_N_SHELL 18 -#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) - - - - -/*-- Structure holding all the compression-side stuff. --*/ - -typedef - struct { - /* pointer back to the struct bz_stream */ - bz_stream* strm; - - /* mode this stream is in, and whether inputting */ - /* or outputting data */ - Int32 mode; - Int32 state; - - /* remembers avail_in when flush/finish requested */ - UInt32 avail_in_expect; - - /* for doing the block sorting */ - UInt32* arr1; - UInt32* arr2; - UInt32* ftab; - Int32 origPtr; - - /* aliases for arr1 and arr2 */ - UInt32* ptr; - UChar* block; - UInt16* mtfv; - UChar* zbits; - - /* for deciding when to use the fallback sorting algorithm */ - Int32 workFactor; - - /* run-length-encoding of the input */ - UInt32 state_in_ch; - Int32 state_in_len; - BZ_RAND_DECLS; - - /* input and output limits and current posns */ - Int32 nblock; - Int32 nblockMAX; - Int32 numZ; - Int32 state_out_pos; - - /* map of bytes used in block */ - Int32 nInUse; - Bool inUse[256]; - UChar unseqToSeq[256]; - - /* the buffer for bit stream creation */ - UInt32 bsBuff; - Int32 bsLive; - - /* block and combined CRCs */ - UInt32 blockCRC; - UInt32 combinedCRC; - - /* misc administratium */ - Int32 verbosity; - Int32 blockNo; - Int32 blockSize100k; - - /* stuff for coding the MTF values */ - Int32 nMTF; - Int32 mtfFreq [BZ_MAX_ALPHA_SIZE]; - UChar selector [BZ_MAX_SELECTORS]; - UChar selectorMtf[BZ_MAX_SELECTORS]; - - UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - /* second dimension: only 3 needed; 4 makes index calculations faster */ - UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4]; - - } - EState; - - - -/*-- externs for compression. --*/ - -extern void -BZ2_blockSort ( EState* ); - -extern void -BZ2_compressBlock ( EState*, Bool ); - -extern void -BZ2_bsInitWrite ( EState* ); - -extern void -BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 ); - -extern void -BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 ); - - - -/*-- states for decompression. --*/ - -#define BZ_X_IDLE 1 -#define BZ_X_OUTPUT 2 - -#define BZ_X_MAGIC_1 10 -#define BZ_X_MAGIC_2 11 -#define BZ_X_MAGIC_3 12 -#define BZ_X_MAGIC_4 13 -#define BZ_X_BLKHDR_1 14 -#define BZ_X_BLKHDR_2 15 -#define BZ_X_BLKHDR_3 16 -#define BZ_X_BLKHDR_4 17 -#define BZ_X_BLKHDR_5 18 -#define BZ_X_BLKHDR_6 19 -#define BZ_X_BCRC_1 20 -#define BZ_X_BCRC_2 21 -#define BZ_X_BCRC_3 22 -#define BZ_X_BCRC_4 23 -#define BZ_X_RANDBIT 24 -#define BZ_X_ORIGPTR_1 25 -#define BZ_X_ORIGPTR_2 26 -#define BZ_X_ORIGPTR_3 27 -#define BZ_X_MAPPING_1 28 -#define BZ_X_MAPPING_2 29 -#define BZ_X_SELECTOR_1 30 -#define BZ_X_SELECTOR_2 31 -#define BZ_X_SELECTOR_3 32 -#define BZ_X_CODING_1 33 -#define BZ_X_CODING_2 34 -#define BZ_X_CODING_3 35 -#define BZ_X_MTF_1 36 -#define BZ_X_MTF_2 37 -#define BZ_X_MTF_3 38 -#define BZ_X_MTF_4 39 -#define BZ_X_MTF_5 40 -#define BZ_X_MTF_6 41 -#define BZ_X_ENDHDR_2 42 -#define BZ_X_ENDHDR_3 43 -#define BZ_X_ENDHDR_4 44 -#define BZ_X_ENDHDR_5 45 -#define BZ_X_ENDHDR_6 46 -#define BZ_X_CCRC_1 47 -#define BZ_X_CCRC_2 48 -#define BZ_X_CCRC_3 49 -#define BZ_X_CCRC_4 50 - - - -/*-- Constants for the fast MTF decoder. --*/ - -#define MTFA_SIZE 4096 -#define MTFL_SIZE 16 - - - -/*-- Structure holding all the decompression-side stuff. --*/ - -typedef - struct { - /* pointer back to the struct bz_stream */ - bz_stream* strm; - - /* state indicator for this stream */ - Int32 state; - - /* for doing the final run-length decoding */ - UChar state_out_ch; - Int32 state_out_len; - Bool blockRandomised; - BZ_RAND_DECLS; - - /* the buffer for bit stream reading */ - UInt32 bsBuff; - Int32 bsLive; - - /* misc administratium */ - Int32 blockSize100k; - Bool smallDecompress; - Int32 currBlockNo; - Int32 verbosity; - - /* for undoing the Burrows-Wheeler transform */ - Int32 origPtr; - UInt32 tPos; - Int32 k0; - Int32 unzftab[256]; - Int32 nblock_used; - Int32 cftab[257]; - Int32 cftabCopy[257]; - - /* for undoing the Burrows-Wheeler transform (FAST) */ - UInt32 *tt; - - /* for undoing the Burrows-Wheeler transform (SMALL) */ - UInt16 *ll16; - UChar *ll4; - - /* stored and calculated CRCs */ - UInt32 storedBlockCRC; - UInt32 storedCombinedCRC; - UInt32 calculatedBlockCRC; - UInt32 calculatedCombinedCRC; - - /* map of bytes used in block */ - Int32 nInUse; - Bool inUse[256]; - Bool inUse16[16]; - UChar seqToUnseq[256]; - - /* for decoding the MTF values */ - UChar mtfa [MTFA_SIZE]; - Int32 mtfbase[256 / MTFL_SIZE]; - UChar selector [BZ_MAX_SELECTORS]; - UChar selectorMtf[BZ_MAX_SELECTORS]; - UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - - Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 minLens[BZ_N_GROUPS]; - - /* save area for scalars in the main decompress code */ - Int32 save_i; - Int32 save_j; - Int32 save_t; - Int32 save_alphaSize; - Int32 save_nGroups; - Int32 save_nSelectors; - Int32 save_EOB; - Int32 save_groupNo; - Int32 save_groupPos; - Int32 save_nextSym; - Int32 save_nblockMAX; - Int32 save_nblock; - Int32 save_es; - Int32 save_N; - Int32 save_curr; - Int32 save_zt; - Int32 save_zn; - Int32 save_zvec; - Int32 save_zj; - Int32 save_gSel; - Int32 save_gMinlen; - Int32* save_gLimit; - Int32* save_gBase; - Int32* save_gPerm; - - } - DState; - - - -/*-- Macros for decompression. --*/ - -#define BZ_GET_FAST(cccc) \ - s->tPos = s->tt[s->tPos]; \ - cccc = (UChar)(s->tPos & 0xff); \ - s->tPos >>= 8; - -#define BZ_GET_FAST_C(cccc) \ - c_tPos = c_tt[c_tPos]; \ - cccc = (UChar)(c_tPos & 0xff); \ - c_tPos >>= 8; - -#define SET_LL4(i,n) \ - { if (((i) & 0x1) == 0) \ - s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \ - s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ - } - -#define GET_LL4(i) \ - ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF) - -#define SET_LL(i,n) \ - { s->ll16[i] = (UInt16)(n & 0x0000ffff); \ - SET_LL4(i, n >> 16); \ - } - -#define GET_LL(i) \ - (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16)) - -#define BZ_GET_SMALL(cccc) \ - cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ - s->tPos = GET_LL(s->tPos); - - -/*-- externs for decompression. --*/ - -extern Int32 -BZ2_indexIntoF ( Int32, Int32* ); - -extern Int32 -BZ2_decompress ( DState* ); - -extern void -BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*, - Int32, Int32, Int32 ); - - -#endif - - -/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/ - -#ifdef BZ_NO_STDIO -#ifndef NULL -#define NULL 0 -#endif -#endif - - -/*-------------------------------------------------------------*/ -/*--- end bzlib_private.h ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Private header file for the library. ---*/ +/*--- bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#ifndef _BZLIB_PRIVATE_H +#define _BZLIB_PRIVATE_H + +#include + +#ifndef BZ_NO_STDIO +#include +#include +#include +#endif + +#include "bzlib.h" + + + +/*-- General stuff. --*/ + +#define BZ_VERSION "1.0.4, 20-Dec-2006" + +typedef char Char; +typedef unsigned char Bool; +typedef unsigned char UChar; +typedef int Int32; +typedef unsigned int UInt32; +typedef short Int16; +typedef unsigned short UInt16; + +#define True ((Bool)1) +#define False ((Bool)0) + +#ifndef __GNUC__ +#define __inline__ /* */ +#endif + +#ifndef BZ_NO_STDIO + +extern void BZ2_bz__AssertH__fail ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); } + +#if BZ_DEBUG +#define AssertD(cond,msg) \ + { if (!(cond)) { \ + fprintf ( stderr, \ + "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\ + exit(1); \ + }} +#else +#define AssertD(cond,msg) /* */ +#endif + +#define VPrintf0(zf) \ + fprintf(stderr,zf) +#define VPrintf1(zf,za1) \ + fprintf(stderr,zf,za1) +#define VPrintf2(zf,za1,za2) \ + fprintf(stderr,zf,za1,za2) +#define VPrintf3(zf,za1,za2,za3) \ + fprintf(stderr,zf,za1,za2,za3) +#define VPrintf4(zf,za1,za2,za3,za4) \ + fprintf(stderr,zf,za1,za2,za3,za4) +#define VPrintf5(zf,za1,za2,za3,za4,za5) \ + fprintf(stderr,zf,za1,za2,za3,za4,za5) + +#else + +extern void bz_internal_error ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) bz_internal_error ( errcode ); } +#define AssertD(cond,msg) do { } while (0) +#define VPrintf0(zf) do { } while (0) +#define VPrintf1(zf,za1) do { } while (0) +#define VPrintf2(zf,za1,za2) do { } while (0) +#define VPrintf3(zf,za1,za2,za3) do { } while (0) +#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0) +#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0) + +#endif + + +#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1) +#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp)) + + +/*-- Header bytes. --*/ + +#define BZ_HDR_B 0x42 /* 'B' */ +#define BZ_HDR_Z 0x5a /* 'Z' */ +#define BZ_HDR_h 0x68 /* 'h' */ +#define BZ_HDR_0 0x30 /* '0' */ + +/*-- Constants for the back end. --*/ + +#define BZ_MAX_ALPHA_SIZE 258 +#define BZ_MAX_CODE_LEN 23 + +#define BZ_RUNA 0 +#define BZ_RUNB 1 + +#define BZ_N_GROUPS 6 +#define BZ_G_SIZE 50 +#define BZ_N_ITERS 4 + +#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) + + + +/*-- Stuff for randomising repetitive blocks. --*/ + +extern Int32 BZ2_rNums[512]; + +#define BZ_RAND_DECLS \ + Int32 rNToGo; \ + Int32 rTPos \ + +#define BZ_RAND_INIT_MASK \ + s->rNToGo = 0; \ + s->rTPos = 0 \ + +#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0) + +#define BZ_RAND_UPD_MASK \ + if (s->rNToGo == 0) { \ + s->rNToGo = BZ2_rNums[s->rTPos]; \ + s->rTPos++; \ + if (s->rTPos == 512) s->rTPos = 0; \ + } \ + s->rNToGo--; + + + +/*-- Stuff for doing CRCs. --*/ + +extern UInt32 BZ2_crc32Table[256]; + +#define BZ_INITIALISE_CRC(crcVar) \ +{ \ + crcVar = 0xffffffffL; \ +} + +#define BZ_FINALISE_CRC(crcVar) \ +{ \ + crcVar = ~(crcVar); \ +} + +#define BZ_UPDATE_CRC(crcVar,cha) \ +{ \ + crcVar = (crcVar << 8) ^ \ + BZ2_crc32Table[(crcVar >> 24) ^ \ + ((UChar)cha)]; \ +} + + + +/*-- States and modes for compression. --*/ + +#define BZ_M_IDLE 1 +#define BZ_M_RUNNING 2 +#define BZ_M_FLUSHING 3 +#define BZ_M_FINISHING 4 + +#define BZ_S_OUTPUT 1 +#define BZ_S_INPUT 2 + +#define BZ_N_RADIX 2 +#define BZ_N_QSORT 12 +#define BZ_N_SHELL 18 +#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) + + + + +/*-- Structure holding all the compression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* mode this stream is in, and whether inputting */ + /* or outputting data */ + Int32 mode; + Int32 state; + + /* remembers avail_in when flush/finish requested */ + UInt32 avail_in_expect; + + /* for doing the block sorting */ + UInt32* arr1; + UInt32* arr2; + UInt32* ftab; + Int32 origPtr; + + /* aliases for arr1 and arr2 */ + UInt32* ptr; + UChar* block; + UInt16* mtfv; + UChar* zbits; + + /* for deciding when to use the fallback sorting algorithm */ + Int32 workFactor; + + /* run-length-encoding of the input */ + UInt32 state_in_ch; + Int32 state_in_len; + BZ_RAND_DECLS; + + /* input and output limits and current posns */ + Int32 nblock; + Int32 nblockMAX; + Int32 numZ; + Int32 state_out_pos; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + UChar unseqToSeq[256]; + + /* the buffer for bit stream creation */ + UInt32 bsBuff; + Int32 bsLive; + + /* block and combined CRCs */ + UInt32 blockCRC; + UInt32 combinedCRC; + + /* misc administratium */ + Int32 verbosity; + Int32 blockNo; + Int32 blockSize100k; + + /* stuff for coding the MTF values */ + Int32 nMTF; + Int32 mtfFreq [BZ_MAX_ALPHA_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + /* second dimension: only 3 needed; 4 makes index calculations faster */ + UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4]; + + } + EState; + + + +/*-- externs for compression. --*/ + +extern void +BZ2_blockSort ( EState* ); + +extern void +BZ2_compressBlock ( EState*, Bool ); + +extern void +BZ2_bsInitWrite ( EState* ); + +extern void +BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 ); + +extern void +BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 ); + + + +/*-- states for decompression. --*/ + +#define BZ_X_IDLE 1 +#define BZ_X_OUTPUT 2 + +#define BZ_X_MAGIC_1 10 +#define BZ_X_MAGIC_2 11 +#define BZ_X_MAGIC_3 12 +#define BZ_X_MAGIC_4 13 +#define BZ_X_BLKHDR_1 14 +#define BZ_X_BLKHDR_2 15 +#define BZ_X_BLKHDR_3 16 +#define BZ_X_BLKHDR_4 17 +#define BZ_X_BLKHDR_5 18 +#define BZ_X_BLKHDR_6 19 +#define BZ_X_BCRC_1 20 +#define BZ_X_BCRC_2 21 +#define BZ_X_BCRC_3 22 +#define BZ_X_BCRC_4 23 +#define BZ_X_RANDBIT 24 +#define BZ_X_ORIGPTR_1 25 +#define BZ_X_ORIGPTR_2 26 +#define BZ_X_ORIGPTR_3 27 +#define BZ_X_MAPPING_1 28 +#define BZ_X_MAPPING_2 29 +#define BZ_X_SELECTOR_1 30 +#define BZ_X_SELECTOR_2 31 +#define BZ_X_SELECTOR_3 32 +#define BZ_X_CODING_1 33 +#define BZ_X_CODING_2 34 +#define BZ_X_CODING_3 35 +#define BZ_X_MTF_1 36 +#define BZ_X_MTF_2 37 +#define BZ_X_MTF_3 38 +#define BZ_X_MTF_4 39 +#define BZ_X_MTF_5 40 +#define BZ_X_MTF_6 41 +#define BZ_X_ENDHDR_2 42 +#define BZ_X_ENDHDR_3 43 +#define BZ_X_ENDHDR_4 44 +#define BZ_X_ENDHDR_5 45 +#define BZ_X_ENDHDR_6 46 +#define BZ_X_CCRC_1 47 +#define BZ_X_CCRC_2 48 +#define BZ_X_CCRC_3 49 +#define BZ_X_CCRC_4 50 + + + +/*-- Constants for the fast MTF decoder. --*/ + +#define MTFA_SIZE 4096 +#define MTFL_SIZE 16 + + + +/*-- Structure holding all the decompression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* state indicator for this stream */ + Int32 state; + + /* for doing the final run-length decoding */ + UChar state_out_ch; + Int32 state_out_len; + Bool blockRandomised; + BZ_RAND_DECLS; + + /* the buffer for bit stream reading */ + UInt32 bsBuff; + Int32 bsLive; + + /* misc administratium */ + Int32 blockSize100k; + Bool smallDecompress; + Int32 currBlockNo; + Int32 verbosity; + + /* for undoing the Burrows-Wheeler transform */ + Int32 origPtr; + UInt32 tPos; + Int32 k0; + Int32 unzftab[256]; + Int32 nblock_used; + Int32 cftab[257]; + Int32 cftabCopy[257]; + + /* for undoing the Burrows-Wheeler transform (FAST) */ + UInt32 *tt; + + /* for undoing the Burrows-Wheeler transform (SMALL) */ + UInt16 *ll16; + UChar *ll4; + + /* stored and calculated CRCs */ + UInt32 storedBlockCRC; + UInt32 storedCombinedCRC; + UInt32 calculatedBlockCRC; + UInt32 calculatedCombinedCRC; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + Bool inUse16[16]; + UChar seqToUnseq[256]; + + /* for decoding the MTF values */ + UChar mtfa [MTFA_SIZE]; + Int32 mtfbase[256 / MTFL_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + + Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 minLens[BZ_N_GROUPS]; + + /* save area for scalars in the main decompress code */ + Int32 save_i; + Int32 save_j; + Int32 save_t; + Int32 save_alphaSize; + Int32 save_nGroups; + Int32 save_nSelectors; + Int32 save_EOB; + Int32 save_groupNo; + Int32 save_groupPos; + Int32 save_nextSym; + Int32 save_nblockMAX; + Int32 save_nblock; + Int32 save_es; + Int32 save_N; + Int32 save_curr; + Int32 save_zt; + Int32 save_zn; + Int32 save_zvec; + Int32 save_zj; + Int32 save_gSel; + Int32 save_gMinlen; + Int32* save_gLimit; + Int32* save_gBase; + Int32* save_gPerm; + + } + DState; + + + +/*-- Macros for decompression. --*/ + +#define BZ_GET_FAST(cccc) \ + s->tPos = s->tt[s->tPos]; \ + cccc = (UChar)(s->tPos & 0xff); \ + s->tPos >>= 8; + +#define BZ_GET_FAST_C(cccc) \ + c_tPos = c_tt[c_tPos]; \ + cccc = (UChar)(c_tPos & 0xff); \ + c_tPos >>= 8; + +#define SET_LL4(i,n) \ + { if (((i) & 0x1) == 0) \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ + } + +#define GET_LL4(i) \ + ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF) + +#define SET_LL(i,n) \ + { s->ll16[i] = (UInt16)(n & 0x0000ffff); \ + SET_LL4(i, n >> 16); \ + } + +#define GET_LL(i) \ + (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16)) + +#define BZ_GET_SMALL(cccc) \ + cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ + s->tPos = GET_LL(s->tPos); + + +/*-- externs for decompression. --*/ + +extern Int32 +BZ2_indexIntoF ( Int32, Int32* ); + +extern Int32 +BZ2_decompress ( DState* ); + +extern void +BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*, + Int32, Int32, Int32 ); + + +#endif + + +/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/ + +#ifdef BZ_NO_STDIO +#ifndef NULL +#define NULL 0 +#endif +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/3rdparty/bzip2/compress.c b/3rdparty/bzip2/compress.c index 7be1976f69..d98d5c0bd8 100644 --- a/3rdparty/bzip2/compress.c +++ b/3rdparty/bzip2/compress.c @@ -1,672 +1,672 @@ - -/*-------------------------------------------------------------*/ -/*--- Compression machinery (not incl block sorting) ---*/ -/*--- compress.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.4 of 20 December 2006 - Copyright (C) 1996-2006 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -/* CHANGES - 0.9.0 -- original version. - 0.9.0a/b -- no changes in this file. - 0.9.0c -- changed setting of nGroups in sendMTFValues() - so as to do a bit better on small files -*/ - -#include "bzlib_private.h" - - -/*---------------------------------------------------*/ -/*--- Bit stream I/O ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -void BZ2_bsInitWrite ( EState* s ) -{ - s->bsLive = 0; - s->bsBuff = 0; -} - - -/*---------------------------------------------------*/ -static -void bsFinishWrite ( EState* s ) -{ - while (s->bsLive > 0) { - s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24); - s->numZ++; - s->bsBuff <<= 8; - s->bsLive -= 8; - } -} - - -/*---------------------------------------------------*/ -#define bsNEEDW(nz) \ -{ \ - while (s->bsLive >= 8) { \ - s->zbits[s->numZ] \ - = (UChar)(s->bsBuff >> 24); \ - s->numZ++; \ - s->bsBuff <<= 8; \ - s->bsLive -= 8; \ - } \ -} - - -/*---------------------------------------------------*/ -static -__inline__ -void bsW ( EState* s, Int32 n, UInt32 v ) -{ - bsNEEDW ( n ); - s->bsBuff |= (v << (32 - s->bsLive - n)); - s->bsLive += n; -} - - -/*---------------------------------------------------*/ -static -void bsPutUInt32 ( EState* s, UInt32 u ) -{ - bsW ( s, 8, (u >> 24) & 0xffL ); - bsW ( s, 8, (u >> 16) & 0xffL ); - bsW ( s, 8, (u >> 8) & 0xffL ); - bsW ( s, 8, u & 0xffL ); -} - - -/*---------------------------------------------------*/ -static -void bsPutUChar ( EState* s, UChar c ) -{ - bsW( s, 8, (UInt32)c ); -} - - -/*---------------------------------------------------*/ -/*--- The back end proper ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -static -void makeMaps_e ( EState* s ) -{ - Int32 i; - s->nInUse = 0; - for (i = 0; i < 256; i++) - if (s->inUse[i]) { - s->unseqToSeq[i] = s->nInUse; - s->nInUse++; - } -} - - -/*---------------------------------------------------*/ -static -void generateMTFValues ( EState* s ) -{ - UChar yy[256]; - Int32 i, j; - Int32 zPend; - Int32 wr; - Int32 EOB; - - /* - After sorting (eg, here), - s->arr1 [ 0 .. s->nblock-1 ] holds sorted order, - and - ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] - holds the original block data. - - The first thing to do is generate the MTF values, - and put them in - ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ]. - Because there are strictly fewer or equal MTF values - than block values, ptr values in this area are overwritten - with MTF values only when they are no longer needed. - - The final compressed bitstream is generated into the - area starting at - (UChar*) (&((UChar*)s->arr2)[s->nblock]) - - These storage aliases are set up in bzCompressInit(), - except for the last one, which is arranged in - compressBlock(). - */ - UInt32* ptr = s->ptr; - UChar* block = s->block; - UInt16* mtfv = s->mtfv; - - makeMaps_e ( s ); - EOB = s->nInUse+1; - - for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0; - - wr = 0; - zPend = 0; - for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i; - - for (i = 0; i < s->nblock; i++) { - UChar ll_i; - AssertD ( wr <= i, "generateMTFValues(1)" ); - j = ptr[i]-1; if (j < 0) j += s->nblock; - ll_i = s->unseqToSeq[block[j]]; - AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" ); - - if (yy[0] == ll_i) { - zPend++; - } else { - - if (zPend > 0) { - zPend--; - while (True) { - if (zPend & 1) { - mtfv[wr] = BZ_RUNB; wr++; - s->mtfFreq[BZ_RUNB]++; - } else { - mtfv[wr] = BZ_RUNA; wr++; - s->mtfFreq[BZ_RUNA]++; - } - if (zPend < 2) break; - zPend = (zPend - 2) / 2; - }; - zPend = 0; - } - { - register UChar rtmp; - register UChar* ryy_j; - register UChar rll_i; - rtmp = yy[1]; - yy[1] = yy[0]; - ryy_j = &(yy[1]); - rll_i = ll_i; - while ( rll_i != rtmp ) { - register UChar rtmp2; - ryy_j++; - rtmp2 = rtmp; - rtmp = *ryy_j; - *ryy_j = rtmp2; - }; - yy[0] = rtmp; - j = ryy_j - &(yy[0]); - mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++; - } - - } - } - - if (zPend > 0) { - zPend--; - while (True) { - if (zPend & 1) { - mtfv[wr] = BZ_RUNB; wr++; - s->mtfFreq[BZ_RUNB]++; - } else { - mtfv[wr] = BZ_RUNA; wr++; - s->mtfFreq[BZ_RUNA]++; - } - if (zPend < 2) break; - zPend = (zPend - 2) / 2; - }; - zPend = 0; - } - - mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++; - - s->nMTF = wr; -} - - -/*---------------------------------------------------*/ -#define BZ_LESSER_ICOST 0 -#define BZ_GREATER_ICOST 15 - -static -void sendMTFValues ( EState* s ) -{ - Int32 v, t, i, j, gs, ge, totc, bt, bc, iter; - Int32 nSelectors, alphaSize, minLen, maxLen, selCtr; - Int32 nGroups, nBytes; - - /*-- - UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - is a global since the decoder also needs it. - - Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - are also globals only used in this proc. - Made global to keep stack frame size small. - --*/ - - - UInt16 cost[BZ_N_GROUPS]; - Int32 fave[BZ_N_GROUPS]; - - UInt16* mtfv = s->mtfv; - - if (s->verbosity >= 3) - VPrintf3( " %d in block, %d after MTF & 1-2 coding, " - "%d+2 syms in use\n", - s->nblock, s->nMTF, s->nInUse ); - - alphaSize = s->nInUse+2; - for (t = 0; t < BZ_N_GROUPS; t++) - for (v = 0; v < alphaSize; v++) - s->len[t][v] = BZ_GREATER_ICOST; - - /*--- Decide how many coding tables to use ---*/ - AssertH ( s->nMTF > 0, 3001 ); - if (s->nMTF < 200) nGroups = 2; else - if (s->nMTF < 600) nGroups = 3; else - if (s->nMTF < 1200) nGroups = 4; else - if (s->nMTF < 2400) nGroups = 5; else - nGroups = 6; - - /*--- Generate an initial set of coding tables ---*/ - { - Int32 nPart, remF, tFreq, aFreq; - - nPart = nGroups; - remF = s->nMTF; - gs = 0; - while (nPart > 0) { - tFreq = remF / nPart; - ge = gs-1; - aFreq = 0; - while (aFreq < tFreq && ge < alphaSize-1) { - ge++; - aFreq += s->mtfFreq[ge]; - } - - if (ge > gs - && nPart != nGroups && nPart != 1 - && ((nGroups-nPart) % 2 == 1)) { - aFreq -= s->mtfFreq[ge]; - ge--; - } - - if (s->verbosity >= 3) - VPrintf5( " initial group %d, [%d .. %d], " - "has %d syms (%4.1f%%)\n", - nPart, gs, ge, aFreq, - (100.0 * (float)aFreq) / (float)(s->nMTF) ); - - for (v = 0; v < alphaSize; v++) - if (v >= gs && v <= ge) - s->len[nPart-1][v] = BZ_LESSER_ICOST; else - s->len[nPart-1][v] = BZ_GREATER_ICOST; - - nPart--; - gs = ge+1; - remF -= aFreq; - } - } - - /*--- - Iterate up to BZ_N_ITERS times to improve the tables. - ---*/ - for (iter = 0; iter < BZ_N_ITERS; iter++) { - - for (t = 0; t < nGroups; t++) fave[t] = 0; - - for (t = 0; t < nGroups; t++) - for (v = 0; v < alphaSize; v++) - s->rfreq[t][v] = 0; - - /*--- - Set up an auxiliary length table which is used to fast-track - the common case (nGroups == 6). - ---*/ - if (nGroups == 6) { - for (v = 0; v < alphaSize; v++) { - s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; - s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; - s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; - } - } - - nSelectors = 0; - totc = 0; - gs = 0; - while (True) { - - /*--- Set group start & end marks. --*/ - if (gs >= s->nMTF) break; - ge = gs + BZ_G_SIZE - 1; - if (ge >= s->nMTF) ge = s->nMTF-1; - - /*-- - Calculate the cost of this group as coded - by each of the coding tables. - --*/ - for (t = 0; t < nGroups; t++) cost[t] = 0; - - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - register UInt32 cost01, cost23, cost45; - register UInt16 icv; - cost01 = cost23 = cost45 = 0; - -# define BZ_ITER(nn) \ - icv = mtfv[gs+(nn)]; \ - cost01 += s->len_pack[icv][0]; \ - cost23 += s->len_pack[icv][1]; \ - cost45 += s->len_pack[icv][2]; \ - - BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); - BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); - BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); - BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); - BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); - BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); - BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); - BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); - BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); - BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); - -# undef BZ_ITER - - cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; - cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; - cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; - - } else { - /*--- slow version which correctly handles all situations ---*/ - for (i = gs; i <= ge; i++) { - UInt16 icv = mtfv[i]; - for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv]; - } - } - - /*-- - Find the coding table which is best for this group, - and record its identity in the selector table. - --*/ - bc = 999999999; bt = -1; - for (t = 0; t < nGroups; t++) - if (cost[t] < bc) { bc = cost[t]; bt = t; }; - totc += bc; - fave[bt]++; - s->selector[nSelectors] = bt; - nSelectors++; - - /*-- - Increment the symbol frequencies for the selected table. - --*/ - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - -# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++ - - BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); - BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); - BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); - BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); - BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); - BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); - BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); - BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); - BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); - BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); - -# undef BZ_ITUR - - } else { - /*--- slow version which correctly handles all situations ---*/ - for (i = gs; i <= ge; i++) - s->rfreq[bt][ mtfv[i] ]++; - } - - gs = ge+1; - } - if (s->verbosity >= 3) { - VPrintf2 ( " pass %d: size is %d, grp uses are ", - iter+1, totc/8 ); - for (t = 0; t < nGroups; t++) - VPrintf1 ( "%d ", fave[t] ); - VPrintf0 ( "\n" ); - } - - /*-- - Recompute the tables based on the accumulated frequencies. - --*/ - /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See - comment in huffman.c for details. */ - for (t = 0; t < nGroups; t++) - BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), - alphaSize, 17 /*20*/ ); - } - - - AssertH( nGroups < 8, 3002 ); - AssertH( nSelectors < 32768 && - nSelectors <= (2 + (900000 / BZ_G_SIZE)), - 3003 ); - - - /*--- Compute MTF values for the selectors. ---*/ - { - UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp; - for (i = 0; i < nGroups; i++) pos[i] = i; - for (i = 0; i < nSelectors; i++) { - ll_i = s->selector[i]; - j = 0; - tmp = pos[j]; - while ( ll_i != tmp ) { - j++; - tmp2 = tmp; - tmp = pos[j]; - pos[j] = tmp2; - }; - pos[0] = tmp; - s->selectorMtf[i] = j; - } - }; - - /*--- Assign actual codes for the tables. --*/ - for (t = 0; t < nGroups; t++) { - minLen = 32; - maxLen = 0; - for (i = 0; i < alphaSize; i++) { - if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; - if (s->len[t][i] < minLen) minLen = s->len[t][i]; - } - AssertH ( !(maxLen > 17 /*20*/ ), 3004 ); - AssertH ( !(minLen < 1), 3005 ); - BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), - minLen, maxLen, alphaSize ); - } - - /*--- Transmit the mapping table. ---*/ - { - Bool inUse16[16]; - for (i = 0; i < 16; i++) { - inUse16[i] = False; - for (j = 0; j < 16; j++) - if (s->inUse[i * 16 + j]) inUse16[i] = True; - } - - nBytes = s->numZ; - for (i = 0; i < 16; i++) - if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0); - - for (i = 0; i < 16; i++) - if (inUse16[i]) - for (j = 0; j < 16; j++) { - if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0); - } - - if (s->verbosity >= 3) - VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes ); - } - - /*--- Now the selectors. ---*/ - nBytes = s->numZ; - bsW ( s, 3, nGroups ); - bsW ( s, 15, nSelectors ); - for (i = 0; i < nSelectors; i++) { - for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1); - bsW(s,1,0); - } - if (s->verbosity >= 3) - VPrintf1( "selectors %d, ", s->numZ-nBytes ); - - /*--- Now the coding tables. ---*/ - nBytes = s->numZ; - - for (t = 0; t < nGroups; t++) { - Int32 curr = s->len[t][0]; - bsW ( s, 5, curr ); - for (i = 0; i < alphaSize; i++) { - while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ }; - while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ }; - bsW ( s, 1, 0 ); - } - } - - if (s->verbosity >= 3) - VPrintf1 ( "code lengths %d, ", s->numZ-nBytes ); - - /*--- And finally, the block data proper ---*/ - nBytes = s->numZ; - selCtr = 0; - gs = 0; - while (True) { - if (gs >= s->nMTF) break; - ge = gs + BZ_G_SIZE - 1; - if (ge >= s->nMTF) ge = s->nMTF-1; - AssertH ( s->selector[selCtr] < nGroups, 3006 ); - - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - UInt16 mtfv_i; - UChar* s_len_sel_selCtr - = &(s->len[s->selector[selCtr]][0]); - Int32* s_code_sel_selCtr - = &(s->code[s->selector[selCtr]][0]); - -# define BZ_ITAH(nn) \ - mtfv_i = mtfv[gs+(nn)]; \ - bsW ( s, \ - s_len_sel_selCtr[mtfv_i], \ - s_code_sel_selCtr[mtfv_i] ) - - BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); - BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); - BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); - BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); - BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); - BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); - BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); - BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); - BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); - BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); - -# undef BZ_ITAH - - } else { - /*--- slow version which correctly handles all situations ---*/ - for (i = gs; i <= ge; i++) { - bsW ( s, - s->len [s->selector[selCtr]] [mtfv[i]], - s->code [s->selector[selCtr]] [mtfv[i]] ); - } - } - - - gs = ge+1; - selCtr++; - } - AssertH( selCtr == nSelectors, 3007 ); - - if (s->verbosity >= 3) - VPrintf1( "codes %d\n", s->numZ-nBytes ); -} - - -/*---------------------------------------------------*/ -void BZ2_compressBlock ( EState* s, Bool is_last_block ) -{ - if (s->nblock > 0) { - - BZ_FINALISE_CRC ( s->blockCRC ); - s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); - s->combinedCRC ^= s->blockCRC; - if (s->blockNo > 1) s->numZ = 0; - - if (s->verbosity >= 2) - VPrintf4( " block %d: crc = 0x%08x, " - "combined CRC = 0x%08x, size = %d\n", - s->blockNo, s->blockCRC, s->combinedCRC, s->nblock ); - - BZ2_blockSort ( s ); - } - - s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]); - - /*-- If this is the first block, create the stream header. --*/ - if (s->blockNo == 1) { - BZ2_bsInitWrite ( s ); - bsPutUChar ( s, BZ_HDR_B ); - bsPutUChar ( s, BZ_HDR_Z ); - bsPutUChar ( s, BZ_HDR_h ); - bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) ); - } - - if (s->nblock > 0) { - - bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 ); - bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 ); - bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 ); - - /*-- Now the block's CRC, so it is in a known place. --*/ - bsPutUInt32 ( s, s->blockCRC ); - - /*-- - Now a single bit indicating (non-)randomisation. - As of version 0.9.5, we use a better sorting algorithm - which makes randomisation unnecessary. So always set - the randomised bit to 'no'. Of course, the decoder - still needs to be able to handle randomised blocks - so as to maintain backwards compatibility with - older versions of bzip2. - --*/ - bsW(s,1,0); - - bsW ( s, 24, s->origPtr ); - generateMTFValues ( s ); - sendMTFValues ( s ); - } - - - /*-- If this is the last block, add the stream trailer. --*/ - if (is_last_block) { - - bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 ); - bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 ); - bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 ); - bsPutUInt32 ( s, s->combinedCRC ); - if (s->verbosity >= 2) - VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC ); - bsFinishWrite ( s ); - } -} - - -/*-------------------------------------------------------------*/ -/*--- end compress.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Compression machinery (not incl block sorting) ---*/ +/*--- compress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +/* CHANGES + 0.9.0 -- original version. + 0.9.0a/b -- no changes in this file. + 0.9.0c -- changed setting of nGroups in sendMTFValues() + so as to do a bit better on small files +*/ + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Bit stream I/O ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +void BZ2_bsInitWrite ( EState* s ) +{ + s->bsLive = 0; + s->bsBuff = 0; +} + + +/*---------------------------------------------------*/ +static +void bsFinishWrite ( EState* s ) +{ + while (s->bsLive > 0) { + s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24); + s->numZ++; + s->bsBuff <<= 8; + s->bsLive -= 8; + } +} + + +/*---------------------------------------------------*/ +#define bsNEEDW(nz) \ +{ \ + while (s->bsLive >= 8) { \ + s->zbits[s->numZ] \ + = (UChar)(s->bsBuff >> 24); \ + s->numZ++; \ + s->bsBuff <<= 8; \ + s->bsLive -= 8; \ + } \ +} + + +/*---------------------------------------------------*/ +static +__inline__ +void bsW ( EState* s, Int32 n, UInt32 v ) +{ + bsNEEDW ( n ); + s->bsBuff |= (v << (32 - s->bsLive - n)); + s->bsLive += n; +} + + +/*---------------------------------------------------*/ +static +void bsPutUInt32 ( EState* s, UInt32 u ) +{ + bsW ( s, 8, (u >> 24) & 0xffL ); + bsW ( s, 8, (u >> 16) & 0xffL ); + bsW ( s, 8, (u >> 8) & 0xffL ); + bsW ( s, 8, u & 0xffL ); +} + + +/*---------------------------------------------------*/ +static +void bsPutUChar ( EState* s, UChar c ) +{ + bsW( s, 8, (UInt32)c ); +} + + +/*---------------------------------------------------*/ +/*--- The back end proper ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +static +void makeMaps_e ( EState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->unseqToSeq[i] = s->nInUse; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +static +void generateMTFValues ( EState* s ) +{ + UChar yy[256]; + Int32 i, j; + Int32 zPend; + Int32 wr; + Int32 EOB; + + /* + After sorting (eg, here), + s->arr1 [ 0 .. s->nblock-1 ] holds sorted order, + and + ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] + holds the original block data. + + The first thing to do is generate the MTF values, + and put them in + ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ]. + Because there are strictly fewer or equal MTF values + than block values, ptr values in this area are overwritten + with MTF values only when they are no longer needed. + + The final compressed bitstream is generated into the + area starting at + (UChar*) (&((UChar*)s->arr2)[s->nblock]) + + These storage aliases are set up in bzCompressInit(), + except for the last one, which is arranged in + compressBlock(). + */ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt16* mtfv = s->mtfv; + + makeMaps_e ( s ); + EOB = s->nInUse+1; + + for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0; + + wr = 0; + zPend = 0; + for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i; + + for (i = 0; i < s->nblock; i++) { + UChar ll_i; + AssertD ( wr <= i, "generateMTFValues(1)" ); + j = ptr[i]-1; if (j < 0) j += s->nblock; + ll_i = s->unseqToSeq[block[j]]; + AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" ); + + if (yy[0] == ll_i) { + zPend++; + } else { + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + { + register UChar rtmp; + register UChar* ryy_j; + register UChar rll_i; + rtmp = yy[1]; + yy[1] = yy[0]; + ryy_j = &(yy[1]); + rll_i = ll_i; + while ( rll_i != rtmp ) { + register UChar rtmp2; + ryy_j++; + rtmp2 = rtmp; + rtmp = *ryy_j; + *ryy_j = rtmp2; + }; + yy[0] = rtmp; + j = ryy_j - &(yy[0]); + mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++; + } + + } + } + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + + mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++; + + s->nMTF = wr; +} + + +/*---------------------------------------------------*/ +#define BZ_LESSER_ICOST 0 +#define BZ_GREATER_ICOST 15 + +static +void sendMTFValues ( EState* s ) +{ + Int32 v, t, i, j, gs, ge, totc, bt, bc, iter; + Int32 nSelectors, alphaSize, minLen, maxLen, selCtr; + Int32 nGroups, nBytes; + + /*-- + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + is a global since the decoder also needs it. + + Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + are also globals only used in this proc. + Made global to keep stack frame size small. + --*/ + + + UInt16 cost[BZ_N_GROUPS]; + Int32 fave[BZ_N_GROUPS]; + + UInt16* mtfv = s->mtfv; + + if (s->verbosity >= 3) + VPrintf3( " %d in block, %d after MTF & 1-2 coding, " + "%d+2 syms in use\n", + s->nblock, s->nMTF, s->nInUse ); + + alphaSize = s->nInUse+2; + for (t = 0; t < BZ_N_GROUPS; t++) + for (v = 0; v < alphaSize; v++) + s->len[t][v] = BZ_GREATER_ICOST; + + /*--- Decide how many coding tables to use ---*/ + AssertH ( s->nMTF > 0, 3001 ); + if (s->nMTF < 200) nGroups = 2; else + if (s->nMTF < 600) nGroups = 3; else + if (s->nMTF < 1200) nGroups = 4; else + if (s->nMTF < 2400) nGroups = 5; else + nGroups = 6; + + /*--- Generate an initial set of coding tables ---*/ + { + Int32 nPart, remF, tFreq, aFreq; + + nPart = nGroups; + remF = s->nMTF; + gs = 0; + while (nPart > 0) { + tFreq = remF / nPart; + ge = gs-1; + aFreq = 0; + while (aFreq < tFreq && ge < alphaSize-1) { + ge++; + aFreq += s->mtfFreq[ge]; + } + + if (ge > gs + && nPart != nGroups && nPart != 1 + && ((nGroups-nPart) % 2 == 1)) { + aFreq -= s->mtfFreq[ge]; + ge--; + } + + if (s->verbosity >= 3) + VPrintf5( " initial group %d, [%d .. %d], " + "has %d syms (%4.1f%%)\n", + nPart, gs, ge, aFreq, + (100.0 * (float)aFreq) / (float)(s->nMTF) ); + + for (v = 0; v < alphaSize; v++) + if (v >= gs && v <= ge) + s->len[nPart-1][v] = BZ_LESSER_ICOST; else + s->len[nPart-1][v] = BZ_GREATER_ICOST; + + nPart--; + gs = ge+1; + remF -= aFreq; + } + } + + /*--- + Iterate up to BZ_N_ITERS times to improve the tables. + ---*/ + for (iter = 0; iter < BZ_N_ITERS; iter++) { + + for (t = 0; t < nGroups; t++) fave[t] = 0; + + for (t = 0; t < nGroups; t++) + for (v = 0; v < alphaSize; v++) + s->rfreq[t][v] = 0; + + /*--- + Set up an auxiliary length table which is used to fast-track + the common case (nGroups == 6). + ---*/ + if (nGroups == 6) { + for (v = 0; v < alphaSize; v++) { + s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; + s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; + s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; + } + } + + nSelectors = 0; + totc = 0; + gs = 0; + while (True) { + + /*--- Set group start & end marks. --*/ + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + + /*-- + Calculate the cost of this group as coded + by each of the coding tables. + --*/ + for (t = 0; t < nGroups; t++) cost[t] = 0; + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + register UInt32 cost01, cost23, cost45; + register UInt16 icv; + cost01 = cost23 = cost45 = 0; + +# define BZ_ITER(nn) \ + icv = mtfv[gs+(nn)]; \ + cost01 += s->len_pack[icv][0]; \ + cost23 += s->len_pack[icv][1]; \ + cost45 += s->len_pack[icv][2]; \ + + BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); + BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); + BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); + BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); + BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); + BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); + BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); + BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); + BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); + BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); + +# undef BZ_ITER + + cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; + cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; + cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + UInt16 icv = mtfv[i]; + for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv]; + } + } + + /*-- + Find the coding table which is best for this group, + and record its identity in the selector table. + --*/ + bc = 999999999; bt = -1; + for (t = 0; t < nGroups; t++) + if (cost[t] < bc) { bc = cost[t]; bt = t; }; + totc += bc; + fave[bt]++; + s->selector[nSelectors] = bt; + nSelectors++; + + /*-- + Increment the symbol frequencies for the selected table. + --*/ + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + +# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++ + + BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); + BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); + BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); + BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); + BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); + BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); + BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); + BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); + BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); + BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); + +# undef BZ_ITUR + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) + s->rfreq[bt][ mtfv[i] ]++; + } + + gs = ge+1; + } + if (s->verbosity >= 3) { + VPrintf2 ( " pass %d: size is %d, grp uses are ", + iter+1, totc/8 ); + for (t = 0; t < nGroups; t++) + VPrintf1 ( "%d ", fave[t] ); + VPrintf0 ( "\n" ); + } + + /*-- + Recompute the tables based on the accumulated frequencies. + --*/ + /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See + comment in huffman.c for details. */ + for (t = 0; t < nGroups; t++) + BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), + alphaSize, 17 /*20*/ ); + } + + + AssertH( nGroups < 8, 3002 ); + AssertH( nSelectors < 32768 && + nSelectors <= (2 + (900000 / BZ_G_SIZE)), + 3003 ); + + + /*--- Compute MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp; + for (i = 0; i < nGroups; i++) pos[i] = i; + for (i = 0; i < nSelectors; i++) { + ll_i = s->selector[i]; + j = 0; + tmp = pos[j]; + while ( ll_i != tmp ) { + j++; + tmp2 = tmp; + tmp = pos[j]; + pos[j] = tmp2; + }; + pos[0] = tmp; + s->selectorMtf[i] = j; + } + }; + + /*--- Assign actual codes for the tables. --*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + AssertH ( !(maxLen > 17 /*20*/ ), 3004 ); + AssertH ( !(minLen < 1), 3005 ); + BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), + minLen, maxLen, alphaSize ); + } + + /*--- Transmit the mapping table. ---*/ + { + Bool inUse16[16]; + for (i = 0; i < 16; i++) { + inUse16[i] = False; + for (j = 0; j < 16; j++) + if (s->inUse[i * 16 + j]) inUse16[i] = True; + } + + nBytes = s->numZ; + for (i = 0; i < 16; i++) + if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0); + + for (i = 0; i < 16; i++) + if (inUse16[i]) + for (j = 0; j < 16; j++) { + if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0); + } + + if (s->verbosity >= 3) + VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes ); + } + + /*--- Now the selectors. ---*/ + nBytes = s->numZ; + bsW ( s, 3, nGroups ); + bsW ( s, 15, nSelectors ); + for (i = 0; i < nSelectors; i++) { + for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1); + bsW(s,1,0); + } + if (s->verbosity >= 3) + VPrintf1( "selectors %d, ", s->numZ-nBytes ); + + /*--- Now the coding tables. ---*/ + nBytes = s->numZ; + + for (t = 0; t < nGroups; t++) { + Int32 curr = s->len[t][0]; + bsW ( s, 5, curr ); + for (i = 0; i < alphaSize; i++) { + while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ }; + while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ }; + bsW ( s, 1, 0 ); + } + } + + if (s->verbosity >= 3) + VPrintf1 ( "code lengths %d, ", s->numZ-nBytes ); + + /*--- And finally, the block data proper ---*/ + nBytes = s->numZ; + selCtr = 0; + gs = 0; + while (True) { + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + AssertH ( s->selector[selCtr] < nGroups, 3006 ); + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + UInt16 mtfv_i; + UChar* s_len_sel_selCtr + = &(s->len[s->selector[selCtr]][0]); + Int32* s_code_sel_selCtr + = &(s->code[s->selector[selCtr]][0]); + +# define BZ_ITAH(nn) \ + mtfv_i = mtfv[gs+(nn)]; \ + bsW ( s, \ + s_len_sel_selCtr[mtfv_i], \ + s_code_sel_selCtr[mtfv_i] ) + + BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); + BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); + BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); + BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); + BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); + BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); + BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); + BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); + BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); + BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); + +# undef BZ_ITAH + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + bsW ( s, + s->len [s->selector[selCtr]] [mtfv[i]], + s->code [s->selector[selCtr]] [mtfv[i]] ); + } + } + + + gs = ge+1; + selCtr++; + } + AssertH( selCtr == nSelectors, 3007 ); + + if (s->verbosity >= 3) + VPrintf1( "codes %d\n", s->numZ-nBytes ); +} + + +/*---------------------------------------------------*/ +void BZ2_compressBlock ( EState* s, Bool is_last_block ) +{ + if (s->nblock > 0) { + + BZ_FINALISE_CRC ( s->blockCRC ); + s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); + s->combinedCRC ^= s->blockCRC; + if (s->blockNo > 1) s->numZ = 0; + + if (s->verbosity >= 2) + VPrintf4( " block %d: crc = 0x%08x, " + "combined CRC = 0x%08x, size = %d\n", + s->blockNo, s->blockCRC, s->combinedCRC, s->nblock ); + + BZ2_blockSort ( s ); + } + + s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]); + + /*-- If this is the first block, create the stream header. --*/ + if (s->blockNo == 1) { + BZ2_bsInitWrite ( s ); + bsPutUChar ( s, BZ_HDR_B ); + bsPutUChar ( s, BZ_HDR_Z ); + bsPutUChar ( s, BZ_HDR_h ); + bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) ); + } + + if (s->nblock > 0) { + + bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 ); + bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 ); + bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 ); + + /*-- Now the block's CRC, so it is in a known place. --*/ + bsPutUInt32 ( s, s->blockCRC ); + + /*-- + Now a single bit indicating (non-)randomisation. + As of version 0.9.5, we use a better sorting algorithm + which makes randomisation unnecessary. So always set + the randomised bit to 'no'. Of course, the decoder + still needs to be able to handle randomised blocks + so as to maintain backwards compatibility with + older versions of bzip2. + --*/ + bsW(s,1,0); + + bsW ( s, 24, s->origPtr ); + generateMTFValues ( s ); + sendMTFValues ( s ); + } + + + /*-- If this is the last block, add the stream trailer. --*/ + if (is_last_block) { + + bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 ); + bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 ); + bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 ); + bsPutUInt32 ( s, s->combinedCRC ); + if (s->verbosity >= 2) + VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC ); + bsFinishWrite ( s ); + } +} + + +/*-------------------------------------------------------------*/ +/*--- end compress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/3rdparty/bzip2/crctable.c b/3rdparty/bzip2/crctable.c index 5fd7cf6506..bc7e2ae39d 100644 --- a/3rdparty/bzip2/crctable.c +++ b/3rdparty/bzip2/crctable.c @@ -1,104 +1,104 @@ - -/*-------------------------------------------------------------*/ -/*--- Table for doing CRCs ---*/ -/*--- crctable.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.4 of 20 December 2006 - Copyright (C) 1996-2006 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - -/*-- - I think this is an implementation of the AUTODIN-II, - Ethernet & FDDI 32-bit CRC standard. Vaguely derived - from code by Rob Warnock, in Section 51 of the - comp.compression FAQ. ---*/ - -UInt32 BZ2_crc32Table[256] = { - - /*-- Ugly, innit? --*/ - - 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, - 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, - 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, - 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, - 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, - 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, - 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, - 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, - 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, - 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, - 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, - 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, - 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, - 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, - 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, - 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, - 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, - 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, - 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, - 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, - 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, - 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, - 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, - 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, - 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, - 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, - 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, - 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, - 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, - 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, - 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, - 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, - 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, - 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, - 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, - 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, - 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, - 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, - 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, - 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, - 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, - 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, - 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, - 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, - 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, - 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, - 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, - 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, - 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, - 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, - 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, - 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, - 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, - 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, - 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, - 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, - 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, - 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, - 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, - 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, - 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, - 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, - 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, - 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L -}; - - -/*-------------------------------------------------------------*/ -/*--- end crctable.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Table for doing CRCs ---*/ +/*--- crctable.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*-- + I think this is an implementation of the AUTODIN-II, + Ethernet & FDDI 32-bit CRC standard. Vaguely derived + from code by Rob Warnock, in Section 51 of the + comp.compression FAQ. +--*/ + +UInt32 BZ2_crc32Table[256] = { + + /*-- Ugly, innit? --*/ + + 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, + 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, + 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, + 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, + 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, + 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, + 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, + 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, + 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, + 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, + 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, + 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, + 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, + 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, + 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, + 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, + 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, + 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, + 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, + 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, + 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, + 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, + 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, + 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, + 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, + 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, + 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, + 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, + 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, + 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, + 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, + 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, + 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, + 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, + 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, + 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, + 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, + 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, + 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, + 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, + 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, + 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, + 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, + 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, + 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, + 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, + 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, + 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, + 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, + 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, + 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, + 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, + 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, + 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, + 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, + 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, + 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, + 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, + 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, + 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, + 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, + 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, + 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, + 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L +}; + + +/*-------------------------------------------------------------*/ +/*--- end crctable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/3rdparty/bzip2/decompress.c b/3rdparty/bzip2/decompress.c index 4aa7f53c0c..124cc8ddc7 100644 --- a/3rdparty/bzip2/decompress.c +++ b/3rdparty/bzip2/decompress.c @@ -1,626 +1,626 @@ - -/*-------------------------------------------------------------*/ -/*--- Decompression machinery ---*/ -/*--- decompress.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.4 of 20 December 2006 - Copyright (C) 1996-2006 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - - -/*---------------------------------------------------*/ -static -void makeMaps_d ( DState* s ) -{ - Int32 i; - s->nInUse = 0; - for (i = 0; i < 256; i++) - if (s->inUse[i]) { - s->seqToUnseq[s->nInUse] = i; - s->nInUse++; - } -} - - -/*---------------------------------------------------*/ -#define RETURN(rrr) \ - { retVal = rrr; goto save_state_and_return; }; - -#define GET_BITS(lll,vvv,nnn) \ - case lll: s->state = lll; \ - while (True) { \ - if (s->bsLive >= nnn) { \ - UInt32 v; \ - v = (s->bsBuff >> \ - (s->bsLive-nnn)) & ((1 << nnn)-1); \ - s->bsLive -= nnn; \ - vvv = v; \ - break; \ - } \ - if (s->strm->avail_in == 0) RETURN(BZ_OK); \ - s->bsBuff \ - = (s->bsBuff << 8) | \ - ((UInt32) \ - (*((UChar*)(s->strm->next_in)))); \ - s->bsLive += 8; \ - s->strm->next_in++; \ - s->strm->avail_in--; \ - s->strm->total_in_lo32++; \ - if (s->strm->total_in_lo32 == 0) \ - s->strm->total_in_hi32++; \ - } - -#define GET_UCHAR(lll,uuu) \ - GET_BITS(lll,uuu,8) - -#define GET_BIT(lll,uuu) \ - GET_BITS(lll,uuu,1) - -/*---------------------------------------------------*/ -#define GET_MTF_VAL(label1,label2,lval) \ -{ \ - if (groupPos == 0) { \ - groupNo++; \ - if (groupNo >= nSelectors) \ - RETURN(BZ_DATA_ERROR); \ - groupPos = BZ_G_SIZE; \ - gSel = s->selector[groupNo]; \ - gMinlen = s->minLens[gSel]; \ - gLimit = &(s->limit[gSel][0]); \ - gPerm = &(s->perm[gSel][0]); \ - gBase = &(s->base[gSel][0]); \ - } \ - groupPos--; \ - zn = gMinlen; \ - GET_BITS(label1, zvec, zn); \ - while (1) { \ - if (zn > 20 /* the longest code */) \ - RETURN(BZ_DATA_ERROR); \ - if (zvec <= gLimit[zn]) break; \ - zn++; \ - GET_BIT(label2, zj); \ - zvec = (zvec << 1) | zj; \ - }; \ - if (zvec - gBase[zn] < 0 \ - || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \ - RETURN(BZ_DATA_ERROR); \ - lval = gPerm[zvec - gBase[zn]]; \ -} - - -/*---------------------------------------------------*/ -Int32 BZ2_decompress ( DState* s ) -{ - UChar uc; - Int32 retVal; - Int32 minLen, maxLen; - bz_stream* strm = s->strm; - - /* stuff that needs to be saved/restored */ - Int32 i; - Int32 j; - Int32 t; - Int32 alphaSize; - Int32 nGroups; - Int32 nSelectors; - Int32 EOB; - Int32 groupNo; - Int32 groupPos; - Int32 nextSym; - Int32 nblockMAX; - Int32 nblock; - Int32 es; - Int32 N; - Int32 curr; - Int32 zt; - Int32 zn; - Int32 zvec; - Int32 zj; - Int32 gSel; - Int32 gMinlen; - Int32* gLimit; - Int32* gBase; - Int32* gPerm; - - if (s->state == BZ_X_MAGIC_1) { - /*initialise the save area*/ - s->save_i = 0; - s->save_j = 0; - s->save_t = 0; - s->save_alphaSize = 0; - s->save_nGroups = 0; - s->save_nSelectors = 0; - s->save_EOB = 0; - s->save_groupNo = 0; - s->save_groupPos = 0; - s->save_nextSym = 0; - s->save_nblockMAX = 0; - s->save_nblock = 0; - s->save_es = 0; - s->save_N = 0; - s->save_curr = 0; - s->save_zt = 0; - s->save_zn = 0; - s->save_zvec = 0; - s->save_zj = 0; - s->save_gSel = 0; - s->save_gMinlen = 0; - s->save_gLimit = NULL; - s->save_gBase = NULL; - s->save_gPerm = NULL; - } - - /*restore from the save area*/ - i = s->save_i; - j = s->save_j; - t = s->save_t; - alphaSize = s->save_alphaSize; - nGroups = s->save_nGroups; - nSelectors = s->save_nSelectors; - EOB = s->save_EOB; - groupNo = s->save_groupNo; - groupPos = s->save_groupPos; - nextSym = s->save_nextSym; - nblockMAX = s->save_nblockMAX; - nblock = s->save_nblock; - es = s->save_es; - N = s->save_N; - curr = s->save_curr; - zt = s->save_zt; - zn = s->save_zn; - zvec = s->save_zvec; - zj = s->save_zj; - gSel = s->save_gSel; - gMinlen = s->save_gMinlen; - gLimit = s->save_gLimit; - gBase = s->save_gBase; - gPerm = s->save_gPerm; - - retVal = BZ_OK; - - switch (s->state) { - - GET_UCHAR(BZ_X_MAGIC_1, uc); - if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC); - - GET_UCHAR(BZ_X_MAGIC_2, uc); - if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC); - - GET_UCHAR(BZ_X_MAGIC_3, uc) - if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC); - - GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8) - if (s->blockSize100k < (BZ_HDR_0 + 1) || - s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC); - s->blockSize100k -= BZ_HDR_0; - - if (s->smallDecompress) { - s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) ); - s->ll4 = BZALLOC( - ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) - ); - if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR); - } else { - s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) ); - if (s->tt == NULL) RETURN(BZ_MEM_ERROR); - } - - GET_UCHAR(BZ_X_BLKHDR_1, uc); - - if (uc == 0x17) goto endhdr_2; - if (uc != 0x31) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_2, uc); - if (uc != 0x41) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_3, uc); - if (uc != 0x59) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_4, uc); - if (uc != 0x26) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_5, uc); - if (uc != 0x53) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_6, uc); - if (uc != 0x59) RETURN(BZ_DATA_ERROR); - - s->currBlockNo++; - if (s->verbosity >= 2) - VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo ); - - s->storedBlockCRC = 0; - GET_UCHAR(BZ_X_BCRC_1, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_BCRC_2, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_BCRC_3, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_BCRC_4, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - - GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1); - - s->origPtr = 0; - GET_UCHAR(BZ_X_ORIGPTR_1, uc); - s->origPtr = (s->origPtr << 8) | ((Int32)uc); - GET_UCHAR(BZ_X_ORIGPTR_2, uc); - s->origPtr = (s->origPtr << 8) | ((Int32)uc); - GET_UCHAR(BZ_X_ORIGPTR_3, uc); - s->origPtr = (s->origPtr << 8) | ((Int32)uc); - - if (s->origPtr < 0) - RETURN(BZ_DATA_ERROR); - if (s->origPtr > 10 + 100000*s->blockSize100k) - RETURN(BZ_DATA_ERROR); - - /*--- Receive the mapping table ---*/ - for (i = 0; i < 16; i++) { - GET_BIT(BZ_X_MAPPING_1, uc); - if (uc == 1) - s->inUse16[i] = True; else - s->inUse16[i] = False; - } - - for (i = 0; i < 256; i++) s->inUse[i] = False; - - for (i = 0; i < 16; i++) - if (s->inUse16[i]) - for (j = 0; j < 16; j++) { - GET_BIT(BZ_X_MAPPING_2, uc); - if (uc == 1) s->inUse[i * 16 + j] = True; - } - makeMaps_d ( s ); - if (s->nInUse == 0) RETURN(BZ_DATA_ERROR); - alphaSize = s->nInUse+2; - - /*--- Now the selectors ---*/ - GET_BITS(BZ_X_SELECTOR_1, nGroups, 3); - if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR); - GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15); - if (nSelectors < 1) RETURN(BZ_DATA_ERROR); - for (i = 0; i < nSelectors; i++) { - j = 0; - while (True) { - GET_BIT(BZ_X_SELECTOR_3, uc); - if (uc == 0) break; - j++; - if (j >= nGroups) RETURN(BZ_DATA_ERROR); - } - s->selectorMtf[i] = j; - } - - /*--- Undo the MTF values for the selectors. ---*/ - { - UChar pos[BZ_N_GROUPS], tmp, v; - for (v = 0; v < nGroups; v++) pos[v] = v; - - for (i = 0; i < nSelectors; i++) { - v = s->selectorMtf[i]; - tmp = pos[v]; - while (v > 0) { pos[v] = pos[v-1]; v--; } - pos[0] = tmp; - s->selector[i] = tmp; - } - } - - /*--- Now the coding tables ---*/ - for (t = 0; t < nGroups; t++) { - GET_BITS(BZ_X_CODING_1, curr, 5); - for (i = 0; i < alphaSize; i++) { - while (True) { - if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR); - GET_BIT(BZ_X_CODING_2, uc); - if (uc == 0) break; - GET_BIT(BZ_X_CODING_3, uc); - if (uc == 0) curr++; else curr--; - } - s->len[t][i] = curr; - } - } - - /*--- Create the Huffman decoding tables ---*/ - for (t = 0; t < nGroups; t++) { - minLen = 32; - maxLen = 0; - for (i = 0; i < alphaSize; i++) { - if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; - if (s->len[t][i] < minLen) minLen = s->len[t][i]; - } - BZ2_hbCreateDecodeTables ( - &(s->limit[t][0]), - &(s->base[t][0]), - &(s->perm[t][0]), - &(s->len[t][0]), - minLen, maxLen, alphaSize - ); - s->minLens[t] = minLen; - } - - /*--- Now the MTF values ---*/ - - EOB = s->nInUse+1; - nblockMAX = 100000 * s->blockSize100k; - groupNo = -1; - groupPos = 0; - - for (i = 0; i <= 255; i++) s->unzftab[i] = 0; - - /*-- MTF init --*/ - { - Int32 ii, jj, kk; - kk = MTFA_SIZE-1; - for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) { - for (jj = MTFL_SIZE-1; jj >= 0; jj--) { - s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj); - kk--; - } - s->mtfbase[ii] = kk + 1; - } - } - /*-- end MTF init --*/ - - nblock = 0; - GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym); - - while (True) { - - if (nextSym == EOB) break; - - if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) { - - es = -1; - N = 1; - do { - if (nextSym == BZ_RUNA) es = es + (0+1) * N; else - if (nextSym == BZ_RUNB) es = es + (1+1) * N; - N = N * 2; - GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym); - } - while (nextSym == BZ_RUNA || nextSym == BZ_RUNB); - - es++; - uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ]; - s->unzftab[uc] += es; - - if (s->smallDecompress) - while (es > 0) { - if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); - s->ll16[nblock] = (UInt16)uc; - nblock++; - es--; - } - else - while (es > 0) { - if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); - s->tt[nblock] = (UInt32)uc; - nblock++; - es--; - }; - - continue; - - } else { - - if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); - - /*-- uc = MTF ( nextSym-1 ) --*/ - { - Int32 ii, jj, kk, pp, lno, off; - UInt32 nn; - nn = (UInt32)(nextSym - 1); - - if (nn < MTFL_SIZE) { - /* avoid general-case expense */ - pp = s->mtfbase[0]; - uc = s->mtfa[pp+nn]; - while (nn > 3) { - Int32 z = pp+nn; - s->mtfa[(z) ] = s->mtfa[(z)-1]; - s->mtfa[(z)-1] = s->mtfa[(z)-2]; - s->mtfa[(z)-2] = s->mtfa[(z)-3]; - s->mtfa[(z)-3] = s->mtfa[(z)-4]; - nn -= 4; - } - while (nn > 0) { - s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; - }; - s->mtfa[pp] = uc; - } else { - /* general case */ - lno = nn / MTFL_SIZE; - off = nn % MTFL_SIZE; - pp = s->mtfbase[lno] + off; - uc = s->mtfa[pp]; - while (pp > s->mtfbase[lno]) { - s->mtfa[pp] = s->mtfa[pp-1]; pp--; - }; - s->mtfbase[lno]++; - while (lno > 0) { - s->mtfbase[lno]--; - s->mtfa[s->mtfbase[lno]] - = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1]; - lno--; - } - s->mtfbase[0]--; - s->mtfa[s->mtfbase[0]] = uc; - if (s->mtfbase[0] == 0) { - kk = MTFA_SIZE-1; - for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) { - for (jj = MTFL_SIZE-1; jj >= 0; jj--) { - s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj]; - kk--; - } - s->mtfbase[ii] = kk + 1; - } - } - } - } - /*-- end uc = MTF ( nextSym-1 ) --*/ - - s->unzftab[s->seqToUnseq[uc]]++; - if (s->smallDecompress) - s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else - s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]); - nblock++; - - GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym); - continue; - } - } - - /* Now we know what nblock is, we can do a better sanity - check on s->origPtr. - */ - if (s->origPtr < 0 || s->origPtr >= nblock) - RETURN(BZ_DATA_ERROR); - - /*-- Set up cftab to facilitate generation of T^(-1) --*/ - s->cftab[0] = 0; - for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1]; - for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1]; - for (i = 0; i <= 256; i++) { - if (s->cftab[i] < 0 || s->cftab[i] > nblock) { - /* s->cftab[i] can legitimately be == nblock */ - RETURN(BZ_DATA_ERROR); - } - } - - s->state_out_len = 0; - s->state_out_ch = 0; - BZ_INITIALISE_CRC ( s->calculatedBlockCRC ); - s->state = BZ_X_OUTPUT; - if (s->verbosity >= 2) VPrintf0 ( "rt+rld" ); - - if (s->smallDecompress) { - - /*-- Make a copy of cftab, used in generation of T --*/ - for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i]; - - /*-- compute the T vector --*/ - for (i = 0; i < nblock; i++) { - uc = (UChar)(s->ll16[i]); - SET_LL(i, s->cftabCopy[uc]); - s->cftabCopy[uc]++; - } - - /*-- Compute T^(-1) by pointer reversal on T --*/ - i = s->origPtr; - j = GET_LL(i); - do { - Int32 tmp = GET_LL(j); - SET_LL(j, i); - i = j; - j = tmp; - } - while (i != s->origPtr); - - s->tPos = s->origPtr; - s->nblock_used = 0; - if (s->blockRandomised) { - BZ_RAND_INIT_MASK; - BZ_GET_SMALL(s->k0); s->nblock_used++; - BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; - } else { - BZ_GET_SMALL(s->k0); s->nblock_used++; - } - - } else { - - /*-- compute the T^(-1) vector --*/ - for (i = 0; i < nblock; i++) { - uc = (UChar)(s->tt[i] & 0xff); - s->tt[s->cftab[uc]] |= (i << 8); - s->cftab[uc]++; - } - - s->tPos = s->tt[s->origPtr] >> 8; - s->nblock_used = 0; - if (s->blockRandomised) { - BZ_RAND_INIT_MASK; - BZ_GET_FAST(s->k0); s->nblock_used++; - BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; - } else { - BZ_GET_FAST(s->k0); s->nblock_used++; - } - - } - - RETURN(BZ_OK); - - - - endhdr_2: - - GET_UCHAR(BZ_X_ENDHDR_2, uc); - if (uc != 0x72) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_3, uc); - if (uc != 0x45) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_4, uc); - if (uc != 0x38) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_5, uc); - if (uc != 0x50) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_6, uc); - if (uc != 0x90) RETURN(BZ_DATA_ERROR); - - s->storedCombinedCRC = 0; - GET_UCHAR(BZ_X_CCRC_1, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_CCRC_2, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_CCRC_3, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_CCRC_4, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - - s->state = BZ_X_IDLE; - RETURN(BZ_STREAM_END); - - default: AssertH ( False, 4001 ); - } - - AssertH ( False, 4002 ); - - save_state_and_return: - - s->save_i = i; - s->save_j = j; - s->save_t = t; - s->save_alphaSize = alphaSize; - s->save_nGroups = nGroups; - s->save_nSelectors = nSelectors; - s->save_EOB = EOB; - s->save_groupNo = groupNo; - s->save_groupPos = groupPos; - s->save_nextSym = nextSym; - s->save_nblockMAX = nblockMAX; - s->save_nblock = nblock; - s->save_es = es; - s->save_N = N; - s->save_curr = curr; - s->save_zt = zt; - s->save_zn = zn; - s->save_zvec = zvec; - s->save_zj = zj; - s->save_gSel = gSel; - s->save_gMinlen = gMinlen; - s->save_gLimit = gLimit; - s->save_gBase = gBase; - s->save_gPerm = gPerm; - - return retVal; -} - - -/*-------------------------------------------------------------*/ -/*--- end decompress.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Decompression machinery ---*/ +/*--- decompress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +static +void makeMaps_d ( DState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->seqToUnseq[s->nInUse] = i; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +#define RETURN(rrr) \ + { retVal = rrr; goto save_state_and_return; }; + +#define GET_BITS(lll,vvv,nnn) \ + case lll: s->state = lll; \ + while (True) { \ + if (s->bsLive >= nnn) { \ + UInt32 v; \ + v = (s->bsBuff >> \ + (s->bsLive-nnn)) & ((1 << nnn)-1); \ + s->bsLive -= nnn; \ + vvv = v; \ + break; \ + } \ + if (s->strm->avail_in == 0) RETURN(BZ_OK); \ + s->bsBuff \ + = (s->bsBuff << 8) | \ + ((UInt32) \ + (*((UChar*)(s->strm->next_in)))); \ + s->bsLive += 8; \ + s->strm->next_in++; \ + s->strm->avail_in--; \ + s->strm->total_in_lo32++; \ + if (s->strm->total_in_lo32 == 0) \ + s->strm->total_in_hi32++; \ + } + +#define GET_UCHAR(lll,uuu) \ + GET_BITS(lll,uuu,8) + +#define GET_BIT(lll,uuu) \ + GET_BITS(lll,uuu,1) + +/*---------------------------------------------------*/ +#define GET_MTF_VAL(label1,label2,lval) \ +{ \ + if (groupPos == 0) { \ + groupNo++; \ + if (groupNo >= nSelectors) \ + RETURN(BZ_DATA_ERROR); \ + groupPos = BZ_G_SIZE; \ + gSel = s->selector[groupNo]; \ + gMinlen = s->minLens[gSel]; \ + gLimit = &(s->limit[gSel][0]); \ + gPerm = &(s->perm[gSel][0]); \ + gBase = &(s->base[gSel][0]); \ + } \ + groupPos--; \ + zn = gMinlen; \ + GET_BITS(label1, zvec, zn); \ + while (1) { \ + if (zn > 20 /* the longest code */) \ + RETURN(BZ_DATA_ERROR); \ + if (zvec <= gLimit[zn]) break; \ + zn++; \ + GET_BIT(label2, zj); \ + zvec = (zvec << 1) | zj; \ + }; \ + if (zvec - gBase[zn] < 0 \ + || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \ + RETURN(BZ_DATA_ERROR); \ + lval = gPerm[zvec - gBase[zn]]; \ +} + + +/*---------------------------------------------------*/ +Int32 BZ2_decompress ( DState* s ) +{ + UChar uc; + Int32 retVal; + Int32 minLen, maxLen; + bz_stream* strm = s->strm; + + /* stuff that needs to be saved/restored */ + Int32 i; + Int32 j; + Int32 t; + Int32 alphaSize; + Int32 nGroups; + Int32 nSelectors; + Int32 EOB; + Int32 groupNo; + Int32 groupPos; + Int32 nextSym; + Int32 nblockMAX; + Int32 nblock; + Int32 es; + Int32 N; + Int32 curr; + Int32 zt; + Int32 zn; + Int32 zvec; + Int32 zj; + Int32 gSel; + Int32 gMinlen; + Int32* gLimit; + Int32* gBase; + Int32* gPerm; + + if (s->state == BZ_X_MAGIC_1) { + /*initialise the save area*/ + s->save_i = 0; + s->save_j = 0; + s->save_t = 0; + s->save_alphaSize = 0; + s->save_nGroups = 0; + s->save_nSelectors = 0; + s->save_EOB = 0; + s->save_groupNo = 0; + s->save_groupPos = 0; + s->save_nextSym = 0; + s->save_nblockMAX = 0; + s->save_nblock = 0; + s->save_es = 0; + s->save_N = 0; + s->save_curr = 0; + s->save_zt = 0; + s->save_zn = 0; + s->save_zvec = 0; + s->save_zj = 0; + s->save_gSel = 0; + s->save_gMinlen = 0; + s->save_gLimit = NULL; + s->save_gBase = NULL; + s->save_gPerm = NULL; + } + + /*restore from the save area*/ + i = s->save_i; + j = s->save_j; + t = s->save_t; + alphaSize = s->save_alphaSize; + nGroups = s->save_nGroups; + nSelectors = s->save_nSelectors; + EOB = s->save_EOB; + groupNo = s->save_groupNo; + groupPos = s->save_groupPos; + nextSym = s->save_nextSym; + nblockMAX = s->save_nblockMAX; + nblock = s->save_nblock; + es = s->save_es; + N = s->save_N; + curr = s->save_curr; + zt = s->save_zt; + zn = s->save_zn; + zvec = s->save_zvec; + zj = s->save_zj; + gSel = s->save_gSel; + gMinlen = s->save_gMinlen; + gLimit = s->save_gLimit; + gBase = s->save_gBase; + gPerm = s->save_gPerm; + + retVal = BZ_OK; + + switch (s->state) { + + GET_UCHAR(BZ_X_MAGIC_1, uc); + if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_2, uc); + if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_3, uc) + if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8) + if (s->blockSize100k < (BZ_HDR_0 + 1) || + s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC); + s->blockSize100k -= BZ_HDR_0; + + if (s->smallDecompress) { + s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) ); + s->ll4 = BZALLOC( + ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) + ); + if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR); + } else { + s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) ); + if (s->tt == NULL) RETURN(BZ_MEM_ERROR); + } + + GET_UCHAR(BZ_X_BLKHDR_1, uc); + + if (uc == 0x17) goto endhdr_2; + if (uc != 0x31) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_2, uc); + if (uc != 0x41) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_3, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_4, uc); + if (uc != 0x26) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_5, uc); + if (uc != 0x53) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_6, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + + s->currBlockNo++; + if (s->verbosity >= 2) + VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo ); + + s->storedBlockCRC = 0; + GET_UCHAR(BZ_X_BCRC_1, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_2, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_3, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_4, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + + GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1); + + s->origPtr = 0; + GET_UCHAR(BZ_X_ORIGPTR_1, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_2, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_3, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + + if (s->origPtr < 0) + RETURN(BZ_DATA_ERROR); + if (s->origPtr > 10 + 100000*s->blockSize100k) + RETURN(BZ_DATA_ERROR); + + /*--- Receive the mapping table ---*/ + for (i = 0; i < 16; i++) { + GET_BIT(BZ_X_MAPPING_1, uc); + if (uc == 1) + s->inUse16[i] = True; else + s->inUse16[i] = False; + } + + for (i = 0; i < 256; i++) s->inUse[i] = False; + + for (i = 0; i < 16; i++) + if (s->inUse16[i]) + for (j = 0; j < 16; j++) { + GET_BIT(BZ_X_MAPPING_2, uc); + if (uc == 1) s->inUse[i * 16 + j] = True; + } + makeMaps_d ( s ); + if (s->nInUse == 0) RETURN(BZ_DATA_ERROR); + alphaSize = s->nInUse+2; + + /*--- Now the selectors ---*/ + GET_BITS(BZ_X_SELECTOR_1, nGroups, 3); + if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR); + GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15); + if (nSelectors < 1) RETURN(BZ_DATA_ERROR); + for (i = 0; i < nSelectors; i++) { + j = 0; + while (True) { + GET_BIT(BZ_X_SELECTOR_3, uc); + if (uc == 0) break; + j++; + if (j >= nGroups) RETURN(BZ_DATA_ERROR); + } + s->selectorMtf[i] = j; + } + + /*--- Undo the MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], tmp, v; + for (v = 0; v < nGroups; v++) pos[v] = v; + + for (i = 0; i < nSelectors; i++) { + v = s->selectorMtf[i]; + tmp = pos[v]; + while (v > 0) { pos[v] = pos[v-1]; v--; } + pos[0] = tmp; + s->selector[i] = tmp; + } + } + + /*--- Now the coding tables ---*/ + for (t = 0; t < nGroups; t++) { + GET_BITS(BZ_X_CODING_1, curr, 5); + for (i = 0; i < alphaSize; i++) { + while (True) { + if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR); + GET_BIT(BZ_X_CODING_2, uc); + if (uc == 0) break; + GET_BIT(BZ_X_CODING_3, uc); + if (uc == 0) curr++; else curr--; + } + s->len[t][i] = curr; + } + } + + /*--- Create the Huffman decoding tables ---*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + BZ2_hbCreateDecodeTables ( + &(s->limit[t][0]), + &(s->base[t][0]), + &(s->perm[t][0]), + &(s->len[t][0]), + minLen, maxLen, alphaSize + ); + s->minLens[t] = minLen; + } + + /*--- Now the MTF values ---*/ + + EOB = s->nInUse+1; + nblockMAX = 100000 * s->blockSize100k; + groupNo = -1; + groupPos = 0; + + for (i = 0; i <= 255; i++) s->unzftab[i] = 0; + + /*-- MTF init --*/ + { + Int32 ii, jj, kk; + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj); + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + /*-- end MTF init --*/ + + nblock = 0; + GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym); + + while (True) { + + if (nextSym == EOB) break; + + if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) { + + es = -1; + N = 1; + do { + if (nextSym == BZ_RUNA) es = es + (0+1) * N; else + if (nextSym == BZ_RUNB) es = es + (1+1) * N; + N = N * 2; + GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym); + } + while (nextSym == BZ_RUNA || nextSym == BZ_RUNB); + + es++; + uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ]; + s->unzftab[uc] += es; + + if (s->smallDecompress) + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->ll16[nblock] = (UInt16)uc; + nblock++; + es--; + } + else + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->tt[nblock] = (UInt32)uc; + nblock++; + es--; + }; + + continue; + + } else { + + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + + /*-- uc = MTF ( nextSym-1 ) --*/ + { + Int32 ii, jj, kk, pp, lno, off; + UInt32 nn; + nn = (UInt32)(nextSym - 1); + + if (nn < MTFL_SIZE) { + /* avoid general-case expense */ + pp = s->mtfbase[0]; + uc = s->mtfa[pp+nn]; + while (nn > 3) { + Int32 z = pp+nn; + s->mtfa[(z) ] = s->mtfa[(z)-1]; + s->mtfa[(z)-1] = s->mtfa[(z)-2]; + s->mtfa[(z)-2] = s->mtfa[(z)-3]; + s->mtfa[(z)-3] = s->mtfa[(z)-4]; + nn -= 4; + } + while (nn > 0) { + s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; + }; + s->mtfa[pp] = uc; + } else { + /* general case */ + lno = nn / MTFL_SIZE; + off = nn % MTFL_SIZE; + pp = s->mtfbase[lno] + off; + uc = s->mtfa[pp]; + while (pp > s->mtfbase[lno]) { + s->mtfa[pp] = s->mtfa[pp-1]; pp--; + }; + s->mtfbase[lno]++; + while (lno > 0) { + s->mtfbase[lno]--; + s->mtfa[s->mtfbase[lno]] + = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1]; + lno--; + } + s->mtfbase[0]--; + s->mtfa[s->mtfbase[0]] = uc; + if (s->mtfbase[0] == 0) { + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj]; + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + } + } + /*-- end uc = MTF ( nextSym-1 ) --*/ + + s->unzftab[s->seqToUnseq[uc]]++; + if (s->smallDecompress) + s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else + s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]); + nblock++; + + GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym); + continue; + } + } + + /* Now we know what nblock is, we can do a better sanity + check on s->origPtr. + */ + if (s->origPtr < 0 || s->origPtr >= nblock) + RETURN(BZ_DATA_ERROR); + + /*-- Set up cftab to facilitate generation of T^(-1) --*/ + s->cftab[0] = 0; + for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1]; + for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1]; + for (i = 0; i <= 256; i++) { + if (s->cftab[i] < 0 || s->cftab[i] > nblock) { + /* s->cftab[i] can legitimately be == nblock */ + RETURN(BZ_DATA_ERROR); + } + } + + s->state_out_len = 0; + s->state_out_ch = 0; + BZ_INITIALISE_CRC ( s->calculatedBlockCRC ); + s->state = BZ_X_OUTPUT; + if (s->verbosity >= 2) VPrintf0 ( "rt+rld" ); + + if (s->smallDecompress) { + + /*-- Make a copy of cftab, used in generation of T --*/ + for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i]; + + /*-- compute the T vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->ll16[i]); + SET_LL(i, s->cftabCopy[uc]); + s->cftabCopy[uc]++; + } + + /*-- Compute T^(-1) by pointer reversal on T --*/ + i = s->origPtr; + j = GET_LL(i); + do { + Int32 tmp = GET_LL(j); + SET_LL(j, i); + i = j; + j = tmp; + } + while (i != s->origPtr); + + s->tPos = s->origPtr; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_SMALL(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } else { + + /*-- compute the T^(-1) vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->tt[i] & 0xff); + s->tt[s->cftab[uc]] |= (i << 8); + s->cftab[uc]++; + } + + s->tPos = s->tt[s->origPtr] >> 8; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_FAST(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_FAST(s->k0); s->nblock_used++; + } + + } + + RETURN(BZ_OK); + + + + endhdr_2: + + GET_UCHAR(BZ_X_ENDHDR_2, uc); + if (uc != 0x72) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_3, uc); + if (uc != 0x45) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_4, uc); + if (uc != 0x38) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_5, uc); + if (uc != 0x50) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_6, uc); + if (uc != 0x90) RETURN(BZ_DATA_ERROR); + + s->storedCombinedCRC = 0; + GET_UCHAR(BZ_X_CCRC_1, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_2, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_3, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_4, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + + s->state = BZ_X_IDLE; + RETURN(BZ_STREAM_END); + + default: AssertH ( False, 4001 ); + } + + AssertH ( False, 4002 ); + + save_state_and_return: + + s->save_i = i; + s->save_j = j; + s->save_t = t; + s->save_alphaSize = alphaSize; + s->save_nGroups = nGroups; + s->save_nSelectors = nSelectors; + s->save_EOB = EOB; + s->save_groupNo = groupNo; + s->save_groupPos = groupPos; + s->save_nextSym = nextSym; + s->save_nblockMAX = nblockMAX; + s->save_nblock = nblock; + s->save_es = es; + s->save_N = N; + s->save_curr = curr; + s->save_zt = zt; + s->save_zn = zn; + s->save_zvec = zvec; + s->save_zj = zj; + s->save_gSel = gSel; + s->save_gMinlen = gMinlen; + s->save_gLimit = gLimit; + s->save_gBase = gBase; + s->save_gPerm = gPerm; + + return retVal; +} + + +/*-------------------------------------------------------------*/ +/*--- end decompress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/3rdparty/bzip2/huffman.c b/3rdparty/bzip2/huffman.c index 00066bd0ab..be4dc024dc 100644 --- a/3rdparty/bzip2/huffman.c +++ b/3rdparty/bzip2/huffman.c @@ -1,205 +1,205 @@ - -/*-------------------------------------------------------------*/ -/*--- Huffman coding low-level stuff ---*/ -/*--- huffman.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.4 of 20 December 2006 - Copyright (C) 1996-2006 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - -/*---------------------------------------------------*/ -#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) -#define DEPTHOF(zz1) ((zz1) & 0x000000ff) -#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) - -#define ADDWEIGHTS(zw1,zw2) \ - (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ - (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) - -#define UPHEAP(z) \ -{ \ - Int32 zz, tmp; \ - zz = z; tmp = heap[zz]; \ - while (weight[tmp] < weight[heap[zz >> 1]]) { \ - heap[zz] = heap[zz >> 1]; \ - zz >>= 1; \ - } \ - heap[zz] = tmp; \ -} - -#define DOWNHEAP(z) \ -{ \ - Int32 zz, yy, tmp; \ - zz = z; tmp = heap[zz]; \ - while (True) { \ - yy = zz << 1; \ - if (yy > nHeap) break; \ - if (yy < nHeap && \ - weight[heap[yy+1]] < weight[heap[yy]]) \ - yy++; \ - if (weight[tmp] < weight[heap[yy]]) break; \ - heap[zz] = heap[yy]; \ - zz = yy; \ - } \ - heap[zz] = tmp; \ -} - - -/*---------------------------------------------------*/ -void BZ2_hbMakeCodeLengths ( UChar *len, - Int32 *freq, - Int32 alphaSize, - Int32 maxLen ) -{ - /*-- - Nodes and heap entries run from 1. Entry 0 - for both the heap and nodes is a sentinel. - --*/ - Int32 nNodes, nHeap, n1, n2, i, j, k; - Bool tooLong; - - Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ]; - Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ]; - Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; - - for (i = 0; i < alphaSize; i++) - weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; - - while (True) { - - nNodes = alphaSize; - nHeap = 0; - - heap[0] = 0; - weight[0] = 0; - parent[0] = -2; - - for (i = 1; i <= alphaSize; i++) { - parent[i] = -1; - nHeap++; - heap[nHeap] = i; - UPHEAP(nHeap); - } - - AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 ); - - while (nHeap > 1) { - n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); - n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); - nNodes++; - parent[n1] = parent[n2] = nNodes; - weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); - parent[nNodes] = -1; - nHeap++; - heap[nHeap] = nNodes; - UPHEAP(nHeap); - } - - AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 ); - - tooLong = False; - for (i = 1; i <= alphaSize; i++) { - j = 0; - k = i; - while (parent[k] >= 0) { k = parent[k]; j++; } - len[i-1] = j; - if (j > maxLen) tooLong = True; - } - - if (! tooLong) break; - - /* 17 Oct 04: keep-going condition for the following loop used - to be 'i < alphaSize', which missed the last element, - theoretically leading to the possibility of the compressor - looping. However, this count-scaling step is only needed if - one of the generated Huffman code words is longer than - maxLen, which up to and including version 1.0.2 was 20 bits, - which is extremely unlikely. In version 1.0.3 maxLen was - changed to 17 bits, which has minimal effect on compression - ratio, but does mean this scaling step is used from time to - time, enough to verify that it works. - - This means that bzip2-1.0.3 and later will only produce - Huffman codes with a maximum length of 17 bits. However, in - order to preserve backwards compatibility with bitstreams - produced by versions pre-1.0.3, the decompressor must still - handle lengths of up to 20. */ - - for (i = 1; i <= alphaSize; i++) { - j = weight[i] >> 8; - j = 1 + (j / 2); - weight[i] = j << 8; - } - } -} - - -/*---------------------------------------------------*/ -void BZ2_hbAssignCodes ( Int32 *code, - UChar *length, - Int32 minLen, - Int32 maxLen, - Int32 alphaSize ) -{ - Int32 n, vec, i; - - vec = 0; - for (n = minLen; n <= maxLen; n++) { - for (i = 0; i < alphaSize; i++) - if (length[i] == n) { code[i] = vec; vec++; }; - vec <<= 1; - } -} - - -/*---------------------------------------------------*/ -void BZ2_hbCreateDecodeTables ( Int32 *limit, - Int32 *base, - Int32 *perm, - UChar *length, - Int32 minLen, - Int32 maxLen, - Int32 alphaSize ) -{ - Int32 pp, i, j, vec; - - pp = 0; - for (i = minLen; i <= maxLen; i++) - for (j = 0; j < alphaSize; j++) - if (length[j] == i) { perm[pp] = j; pp++; }; - - for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0; - for (i = 0; i < alphaSize; i++) base[length[i]+1]++; - - for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1]; - - for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0; - vec = 0; - - for (i = minLen; i <= maxLen; i++) { - vec += (base[i+1] - base[i]); - limit[i] = vec-1; - vec <<= 1; - } - for (i = minLen + 1; i <= maxLen; i++) - base[i] = ((limit[i-1] + 1) << 1) - base[i]; -} - - -/*-------------------------------------------------------------*/ -/*--- end huffman.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Huffman coding low-level stuff ---*/ +/*--- huffman.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*---------------------------------------------------*/ +#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) +#define DEPTHOF(zz1) ((zz1) & 0x000000ff) +#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) + +#define ADDWEIGHTS(zw1,zw2) \ + (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ + (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) + +#define UPHEAP(z) \ +{ \ + Int32 zz, tmp; \ + zz = z; tmp = heap[zz]; \ + while (weight[tmp] < weight[heap[zz >> 1]]) { \ + heap[zz] = heap[zz >> 1]; \ + zz >>= 1; \ + } \ + heap[zz] = tmp; \ +} + +#define DOWNHEAP(z) \ +{ \ + Int32 zz, yy, tmp; \ + zz = z; tmp = heap[zz]; \ + while (True) { \ + yy = zz << 1; \ + if (yy > nHeap) break; \ + if (yy < nHeap && \ + weight[heap[yy+1]] < weight[heap[yy]]) \ + yy++; \ + if (weight[tmp] < weight[heap[yy]]) break; \ + heap[zz] = heap[yy]; \ + zz = yy; \ + } \ + heap[zz] = tmp; \ +} + + +/*---------------------------------------------------*/ +void BZ2_hbMakeCodeLengths ( UChar *len, + Int32 *freq, + Int32 alphaSize, + Int32 maxLen ) +{ + /*-- + Nodes and heap entries run from 1. Entry 0 + for both the heap and nodes is a sentinel. + --*/ + Int32 nNodes, nHeap, n1, n2, i, j, k; + Bool tooLong; + + Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ]; + Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ]; + Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; + + for (i = 0; i < alphaSize; i++) + weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; + + while (True) { + + nNodes = alphaSize; + nHeap = 0; + + heap[0] = 0; + weight[0] = 0; + parent[0] = -2; + + for (i = 1; i <= alphaSize; i++) { + parent[i] = -1; + nHeap++; + heap[nHeap] = i; + UPHEAP(nHeap); + } + + AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 ); + + while (nHeap > 1) { + n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + nNodes++; + parent[n1] = parent[n2] = nNodes; + weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); + parent[nNodes] = -1; + nHeap++; + heap[nHeap] = nNodes; + UPHEAP(nHeap); + } + + AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 ); + + tooLong = False; + for (i = 1; i <= alphaSize; i++) { + j = 0; + k = i; + while (parent[k] >= 0) { k = parent[k]; j++; } + len[i-1] = j; + if (j > maxLen) tooLong = True; + } + + if (! tooLong) break; + + /* 17 Oct 04: keep-going condition for the following loop used + to be 'i < alphaSize', which missed the last element, + theoretically leading to the possibility of the compressor + looping. However, this count-scaling step is only needed if + one of the generated Huffman code words is longer than + maxLen, which up to and including version 1.0.2 was 20 bits, + which is extremely unlikely. In version 1.0.3 maxLen was + changed to 17 bits, which has minimal effect on compression + ratio, but does mean this scaling step is used from time to + time, enough to verify that it works. + + This means that bzip2-1.0.3 and later will only produce + Huffman codes with a maximum length of 17 bits. However, in + order to preserve backwards compatibility with bitstreams + produced by versions pre-1.0.3, the decompressor must still + handle lengths of up to 20. */ + + for (i = 1; i <= alphaSize; i++) { + j = weight[i] >> 8; + j = 1 + (j / 2); + weight[i] = j << 8; + } + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbAssignCodes ( Int32 *code, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 n, vec, i; + + vec = 0; + for (n = minLen; n <= maxLen; n++) { + for (i = 0; i < alphaSize; i++) + if (length[i] == n) { code[i] = vec; vec++; }; + vec <<= 1; + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbCreateDecodeTables ( Int32 *limit, + Int32 *base, + Int32 *perm, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 pp, i, j, vec; + + pp = 0; + for (i = minLen; i <= maxLen; i++) + for (j = 0; j < alphaSize; j++) + if (length[j] == i) { perm[pp] = j; pp++; }; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0; + for (i = 0; i < alphaSize; i++) base[length[i]+1]++; + + for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1]; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0; + vec = 0; + + for (i = minLen; i <= maxLen; i++) { + vec += (base[i+1] - base[i]); + limit[i] = vec-1; + vec <<= 1; + } + for (i = minLen + 1; i <= maxLen; i++) + base[i] = ((limit[i-1] + 1) << 1) - base[i]; +} + + +/*-------------------------------------------------------------*/ +/*--- end huffman.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/3rdparty/bzip2/randtable.c b/3rdparty/bzip2/randtable.c index 87a2f05012..d186335e0e 100644 --- a/3rdparty/bzip2/randtable.c +++ b/3rdparty/bzip2/randtable.c @@ -1,84 +1,84 @@ - -/*-------------------------------------------------------------*/ -/*--- Table for randomising repetitive blocks ---*/ -/*--- randtable.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.4 of 20 December 2006 - Copyright (C) 1996-2006 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - - -/*---------------------------------------------*/ -Int32 BZ2_rNums[512] = { - 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, - 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, - 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, - 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, - 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, - 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, - 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, - 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, - 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, - 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, - 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, - 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, - 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, - 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, - 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, - 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, - 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, - 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, - 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, - 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, - 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, - 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, - 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, - 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, - 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, - 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, - 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, - 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, - 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, - 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, - 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, - 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, - 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, - 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, - 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, - 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, - 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, - 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, - 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, - 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, - 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, - 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, - 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, - 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, - 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, - 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, - 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, - 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, - 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, - 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, - 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, - 936, 638 -}; - - -/*-------------------------------------------------------------*/ -/*--- end randtable.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Table for randomising repetitive blocks ---*/ +/*--- randtable.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + + +/*---------------------------------------------*/ +Int32 BZ2_rNums[512] = { + 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, + 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, + 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, + 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, + 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, + 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, + 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, + 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, + 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, + 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, + 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, + 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, + 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, + 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, + 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, + 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, + 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, + 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, + 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, + 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, + 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, + 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, + 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, + 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, + 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, + 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, + 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, + 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, + 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, + 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, + 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, + 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, + 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, + 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, + 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, + 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, + 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, + 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, + 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, + 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, + 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, + 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, + 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, + 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, + 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, + 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, + 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, + 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, + 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, + 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, + 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, + 936, 638 +}; + + +/*-------------------------------------------------------------*/ +/*--- end randtable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/3rdparty/zlib/adler32.c b/3rdparty/zlib/adler32.c index f201d6701e..007ba26277 100644 --- a/3rdparty/zlib/adler32.c +++ b/3rdparty/zlib/adler32.c @@ -1,149 +1,149 @@ -/* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2004 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -#define BASE 65521UL /* largest prime smaller than 65536 */ -#define NMAX 5552 -/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ - -#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} -#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); -#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); -#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); -#define DO16(buf) DO8(buf,0); DO8(buf,8); - -/* use NO_DIVIDE if your processor does not do division in hardware */ -#ifdef NO_DIVIDE -# define MOD(a) \ - do { \ - if (a >= (BASE << 16)) a -= (BASE << 16); \ - if (a >= (BASE << 15)) a -= (BASE << 15); \ - if (a >= (BASE << 14)) a -= (BASE << 14); \ - if (a >= (BASE << 13)) a -= (BASE << 13); \ - if (a >= (BASE << 12)) a -= (BASE << 12); \ - if (a >= (BASE << 11)) a -= (BASE << 11); \ - if (a >= (BASE << 10)) a -= (BASE << 10); \ - if (a >= (BASE << 9)) a -= (BASE << 9); \ - if (a >= (BASE << 8)) a -= (BASE << 8); \ - if (a >= (BASE << 7)) a -= (BASE << 7); \ - if (a >= (BASE << 6)) a -= (BASE << 6); \ - if (a >= (BASE << 5)) a -= (BASE << 5); \ - if (a >= (BASE << 4)) a -= (BASE << 4); \ - if (a >= (BASE << 3)) a -= (BASE << 3); \ - if (a >= (BASE << 2)) a -= (BASE << 2); \ - if (a >= (BASE << 1)) a -= (BASE << 1); \ - if (a >= BASE) a -= BASE; \ - } while (0) -# define MOD4(a) \ - do { \ - if (a >= (BASE << 4)) a -= (BASE << 4); \ - if (a >= (BASE << 3)) a -= (BASE << 3); \ - if (a >= (BASE << 2)) a -= (BASE << 2); \ - if (a >= (BASE << 1)) a -= (BASE << 1); \ - if (a >= BASE) a -= BASE; \ - } while (0) -#else -# define MOD(a) a %= BASE -# define MOD4(a) a %= BASE -#endif - -/* ========================================================================= */ -uLong ZEXPORT adler32(adler, buf, len) - uLong adler; - const Bytef *buf; - uInt len; -{ - unsigned long sum2; - unsigned n; - - /* split Adler-32 into component sums */ - sum2 = (adler >> 16) & 0xffff; - adler &= 0xffff; - - /* in case user likes doing a byte at a time, keep it fast */ - if (len == 1) { - adler += buf[0]; - if (adler >= BASE) - adler -= BASE; - sum2 += adler; - if (sum2 >= BASE) - sum2 -= BASE; - return adler | (sum2 << 16); - } - - /* initial Adler-32 value (deferred check for len == 1 speed) */ - if (buf == Z_NULL) - return 1L; - - /* in case short lengths are provided, keep it somewhat fast */ - if (len < 16) { - while (len--) { - adler += *buf++; - sum2 += adler; - } - if (adler >= BASE) - adler -= BASE; - MOD4(sum2); /* only added so many BASE's */ - return adler | (sum2 << 16); - } - - /* do length NMAX blocks -- requires just one modulo operation */ - while (len >= NMAX) { - len -= NMAX; - n = NMAX / 16; /* NMAX is divisible by 16 */ - do { - DO16(buf); /* 16 sums unrolled */ - buf += 16; - } while (--n); - MOD(adler); - MOD(sum2); - } - - /* do remaining bytes (less than NMAX, still just one modulo) */ - if (len) { /* avoid modulos if none remaining */ - while (len >= 16) { - len -= 16; - DO16(buf); - buf += 16; - } - while (len--) { - adler += *buf++; - sum2 += adler; - } - MOD(adler); - MOD(sum2); - } - - /* return recombined sums */ - return adler | (sum2 << 16); -} - -/* ========================================================================= */ -uLong ZEXPORT adler32_combine(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off_t len2; -{ - unsigned long sum1; - unsigned long sum2; - unsigned rem; - - /* the derivation of this formula is left as an exercise for the reader */ - rem = (unsigned)(len2 % BASE); - sum1 = adler1 & 0xffff; - sum2 = rem * sum1; - MOD(sum2); - sum1 += (adler2 & 0xffff) + BASE - 1; - sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; - if (sum1 > BASE) sum1 -= BASE; - if (sum1 > BASE) sum1 -= BASE; - if (sum2 > (BASE << 1)) sum2 -= (BASE << 1); - if (sum2 > BASE) sum2 -= BASE; - return sum1 | (sum2 << 16); -} +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware */ +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD4(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD4(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* the derivation of this formula is left as an exercise for the reader */ + rem = (unsigned)(len2 % BASE); + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 > BASE) sum1 -= BASE; + if (sum1 > BASE) sum1 -= BASE; + if (sum2 > (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 > BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} diff --git a/3rdparty/zlib/compress.c b/3rdparty/zlib/compress.c index d37e84f5e3..df04f0148e 100644 --- a/3rdparty/zlib/compress.c +++ b/3rdparty/zlib/compress.c @@ -1,79 +1,79 @@ -/* compress.c -- compress a memory buffer - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -/* =========================================================================== - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least 0.1% larger than sourceLen plus - 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ -int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; - int level; -{ - z_stream stream; - int err; - - stream.next_in = (Bytef*)source; - stream.avail_in = (uInt)sourceLen; -#ifdef MAXSEG_64K - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; -#endif - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; - - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - stream.opaque = (voidpf)0; - - err = deflateInit(&stream, level); - if (err != Z_OK) return err; - - err = deflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - deflateEnd(&stream); - return err == Z_OK ? Z_BUF_ERROR : err; - } - *destLen = stream.total_out; - - err = deflateEnd(&stream); - return err; -} - -/* =========================================================================== - */ -int ZEXPORT compress (dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ - return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); -} - -/* =========================================================================== - If the default memLevel or windowBits for deflateInit() is changed, then - this function needs to be updated. - */ -uLong ZEXPORT compressBound (sourceLen) - uLong sourceLen; -{ - return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; -} +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/3rdparty/zlib/crc32.c b/3rdparty/zlib/crc32.c index 32814c20c8..f658a9ef55 100644 --- a/3rdparty/zlib/crc32.c +++ b/3rdparty/zlib/crc32.c @@ -1,423 +1,423 @@ -/* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Thanks to Rodney Brown for his contribution of faster - * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing - * tables for updating the shift register in one step with three exclusive-ors - * instead of four steps with four exclusive-ors. This results in about a - * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. - */ - -/* @(#) $Id$ */ - -/* - Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore - protection on the static variables used to control the first-use generation - of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should - first call get_crc_table() to initialize the tables before allowing more than - one thread to use crc32(). - */ - -#ifdef MAKECRCH -# include -# ifndef DYNAMIC_CRC_TABLE -# define DYNAMIC_CRC_TABLE -# endif /* !DYNAMIC_CRC_TABLE */ -#endif /* MAKECRCH */ - -#include "zutil.h" /* for STDC and FAR definitions */ - -#define local static - -/* Find a four-byte integer type for crc32_little() and crc32_big(). */ -#ifndef NOBYFOUR -# ifdef STDC /* need ANSI C limits.h to determine sizes */ -# include -# define BYFOUR -# if (UINT_MAX == 0xffffffffUL) - typedef unsigned int u4; -# else -# if (ULONG_MAX == 0xffffffffUL) - typedef unsigned long u4; -# else -# if (USHRT_MAX == 0xffffffffUL) - typedef unsigned short u4; -# else -# undef BYFOUR /* can't find a four-byte integer type! */ -# endif -# endif -# endif -# endif /* STDC */ -#endif /* !NOBYFOUR */ - -/* Definitions for doing the crc four data bytes at a time. */ -#ifdef BYFOUR -# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ - (((w)&0xff00)<<8)+(((w)&0xff)<<24)) - local unsigned long crc32_little OF((unsigned long, - const unsigned char FAR *, unsigned)); - local unsigned long crc32_big OF((unsigned long, - const unsigned char FAR *, unsigned)); -# define TBLS 8 -#else -# define TBLS 1 -#endif /* BYFOUR */ - -/* Local functions for crc concatenation */ -local unsigned long gf2_matrix_times OF((unsigned long *mat, - unsigned long vec)); -local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); - -#ifdef DYNAMIC_CRC_TABLE - -local volatile int crc_table_empty = 1; -local unsigned long FAR crc_table[TBLS][256]; -local void make_crc_table OF((void)); -#ifdef MAKECRCH - local void write_table OF((FILE *, const unsigned long FAR *)); -#endif /* MAKECRCH */ -/* - Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: - x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. - - Polynomials over GF(2) are represented in binary, one bit per coefficient, - with the lowest powers in the most significant bit. Then adding polynomials - is just exclusive-or, and multiplying a polynomial by x is a right shift by - one. If we call the above polynomial p, and represent a byte as the - polynomial q, also with the lowest power in the most significant bit (so the - byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, - where a mod b means the remainder after dividing a by b. - - This calculation is done using the shift-register method of multiplying and - taking the remainder. The register is initialized to zero, and for each - incoming bit, x^32 is added mod p to the register if the bit is a one (where - x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by - x (which is shifting right by one and adding x^32 mod p if the bit shifted - out is a one). We start with the highest power (least significant bit) of - q and repeat for all eight bits of q. - - The first table is simply the CRC of all possible eight bit values. This is - all the information needed to generate CRCs on data a byte at a time for all - combinations of CRC register values and incoming bytes. The remaining tables - allow for word-at-a-time CRC calculation for both big-endian and little- - endian machines, where a word is four bytes. -*/ -local void make_crc_table() -{ - unsigned long c; - int n, k; - unsigned long poly; /* polynomial exclusive-or pattern */ - /* terms of polynomial defining this crc (except x^32): */ - static volatile int first = 1; /* flag to limit concurrent making */ - static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - /* See if another task is already doing this (not thread-safe, but better - than nothing -- significantly reduces duration of vulnerability in - case the advice about DYNAMIC_CRC_TABLE is ignored) */ - if (first) { - first = 0; - - /* make exclusive-or pattern from polynomial (0xedb88320UL) */ - poly = 0UL; - for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) - poly |= 1UL << (31 - p[n]); - - /* generate a crc for every 8-bit value */ - for (n = 0; n < 256; n++) { - c = (unsigned long)n; - for (k = 0; k < 8; k++) - c = c & 1 ? poly ^ (c >> 1) : c >> 1; - crc_table[0][n] = c; - } - -#ifdef BYFOUR - /* generate crc for each value followed by one, two, and three zeros, - and then the byte reversal of those as well as the first table */ - for (n = 0; n < 256; n++) { - c = crc_table[0][n]; - crc_table[4][n] = REV(c); - for (k = 1; k < 4; k++) { - c = crc_table[0][c & 0xff] ^ (c >> 8); - crc_table[k][n] = c; - crc_table[k + 4][n] = REV(c); - } - } -#endif /* BYFOUR */ - - crc_table_empty = 0; - } - else { /* not first */ - /* wait for the other guy to finish (not efficient, but rare) */ - while (crc_table_empty) - ; - } - -#ifdef MAKECRCH - /* write out CRC tables to crc32.h */ - { - FILE *out; - - out = fopen("crc32.h", "w"); - if (out == NULL) return; - fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); - fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); - fprintf(out, "local const unsigned long FAR "); - fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); - write_table(out, crc_table[0]); -# ifdef BYFOUR - fprintf(out, "#ifdef BYFOUR\n"); - for (k = 1; k < 8; k++) { - fprintf(out, " },\n {\n"); - write_table(out, crc_table[k]); - } - fprintf(out, "#endif\n"); -# endif /* BYFOUR */ - fprintf(out, " }\n};\n"); - fclose(out); - } -#endif /* MAKECRCH */ -} - -#ifdef MAKECRCH -local void write_table(out, table) - FILE *out; - const unsigned long FAR *table; -{ - int n; - - for (n = 0; n < 256; n++) - fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], - n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); -} -#endif /* MAKECRCH */ - -#else /* !DYNAMIC_CRC_TABLE */ -/* ======================================================================== - * Tables of CRC-32s of all single-byte values, made by make_crc_table(). - */ -#include "crc32.h" -#endif /* DYNAMIC_CRC_TABLE */ - -/* ========================================================================= - * This function can be used by asm versions of crc32() - */ -const unsigned long FAR * ZEXPORT get_crc_table() -{ -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); -#endif /* DYNAMIC_CRC_TABLE */ - return (const unsigned long FAR *)crc_table; -} - -/* ========================================================================= */ -#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) -#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 - -/* ========================================================================= */ -unsigned long ZEXPORT crc32(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - if (buf == Z_NULL) return 0UL; - -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); -#endif /* DYNAMIC_CRC_TABLE */ - -#ifdef BYFOUR - if (sizeof(void *) == sizeof(ptrdiff_t)) { - u4 endian; - - endian = 1; - if (*((unsigned char *)(&endian))) - return crc32_little(crc, buf, len); - else - return crc32_big(crc, buf, len); - } -#endif /* BYFOUR */ - crc = crc ^ 0xffffffffUL; - while (len >= 8) { - DO8; - len -= 8; - } - if (len) do { - DO1; - } while (--len); - return crc ^ 0xffffffffUL; -} - -#ifdef BYFOUR - -/* ========================================================================= */ -#define DOLIT4 c ^= *buf4++; \ - c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ - crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] -#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 - -/* ========================================================================= */ -local unsigned long crc32_little(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - register u4 c; - register const u4 FAR *buf4; - - c = (u4)crc; - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - len--; - } - - buf4 = (const u4 FAR *)(const void FAR *)buf; - while (len >= 32) { - DOLIT32; - len -= 32; - } - while (len >= 4) { - DOLIT4; - len -= 4; - } - buf = (const unsigned char FAR *)buf4; - - if (len) do { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - } while (--len); - c = ~c; - return (unsigned long)c; -} - -/* ========================================================================= */ -#define DOBIG4 c ^= *++buf4; \ - c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ - crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] -#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 - -/* ========================================================================= */ -local unsigned long crc32_big(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - register u4 c; - register const u4 FAR *buf4; - - c = REV((u4)crc); - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - len--; - } - - buf4 = (const u4 FAR *)(const void FAR *)buf; - buf4--; - while (len >= 32) { - DOBIG32; - len -= 32; - } - while (len >= 4) { - DOBIG4; - len -= 4; - } - buf4++; - buf = (const unsigned char FAR *)buf4; - - if (len) do { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - } while (--len); - c = ~c; - return (unsigned long)(REV(c)); -} - -#endif /* BYFOUR */ - -#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ - -/* ========================================================================= */ -local unsigned long gf2_matrix_times(mat, vec) - unsigned long *mat; - unsigned long vec; -{ - unsigned long sum; - - sum = 0; - while (vec) { - if (vec & 1) - sum ^= *mat; - vec >>= 1; - mat++; - } - return sum; -} - -/* ========================================================================= */ -local void gf2_matrix_square(square, mat) - unsigned long *square; - unsigned long *mat; -{ - int n; - - for (n = 0; n < GF2_DIM; n++) - square[n] = gf2_matrix_times(mat, mat[n]); -} - -/* ========================================================================= */ -uLong ZEXPORT crc32_combine(crc1, crc2, len2) - uLong crc1; - uLong crc2; - z_off_t len2; -{ - int n; - unsigned long row; - unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ - unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ - - /* degenerate case */ - if (len2 == 0) - return crc1; - - /* put operator for one zero bit in odd */ - odd[0] = 0xedb88320L; /* CRC-32 polynomial */ - row = 1; - for (n = 1; n < GF2_DIM; n++) { - odd[n] = row; - row <<= 1; - } - - /* put operator for two zero bits in even */ - gf2_matrix_square(even, odd); - - /* put operator for four zero bits in odd */ - gf2_matrix_square(odd, even); - - /* apply len2 zeros to crc1 (first square will put the operator for one - zero byte, eight zero bits, in even) */ - do { - /* apply zeros operator for this bit of len2 */ - gf2_matrix_square(even, odd); - if (len2 & 1) - crc1 = gf2_matrix_times(even, crc1); - len2 >>= 1; - - /* if no more bits set, then done */ - if (len2 == 0) - break; - - /* another iteration of the loop with odd and even swapped */ - gf2_matrix_square(odd, even); - if (len2 & 1) - crc1 = gf2_matrix_times(odd, crc1); - len2 >>= 1; - - /* if no more bits set, then done */ - } while (len2 != 0); - - /* return combined crc */ - crc1 ^= crc2; - return crc1; -} +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case */ + if (len2 == 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320L; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} diff --git a/3rdparty/zlib/crc32.h b/3rdparty/zlib/crc32.h index 5de49bc978..8053b6117c 100644 --- a/3rdparty/zlib/crc32.h +++ b/3rdparty/zlib/crc32.h @@ -1,441 +1,441 @@ -/* crc32.h -- tables for rapid CRC calculation - * Generated automatically by crc32.c - */ - -local const unsigned long FAR crc_table[TBLS][256] = -{ - { - 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, - 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, - 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, - 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, - 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, - 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, - 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, - 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, - 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, - 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, - 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, - 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, - 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, - 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, - 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, - 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, - 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, - 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, - 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, - 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, - 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, - 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, - 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, - 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, - 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, - 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, - 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, - 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, - 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, - 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, - 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, - 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, - 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, - 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, - 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, - 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, - 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, - 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, - 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, - 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, - 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, - 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, - 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, - 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, - 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, - 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, - 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, - 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, - 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, - 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, - 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, - 0x2d02ef8dUL -#ifdef BYFOUR - }, - { - 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, - 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, - 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, - 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, - 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, - 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, - 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, - 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, - 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, - 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, - 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, - 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, - 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, - 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, - 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, - 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, - 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, - 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, - 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, - 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, - 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, - 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, - 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, - 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, - 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, - 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, - 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, - 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, - 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, - 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, - 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, - 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, - 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, - 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, - 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, - 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, - 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, - 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, - 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, - 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, - 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, - 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, - 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, - 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, - 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, - 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, - 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, - 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, - 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, - 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, - 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, - 0x9324fd72UL - }, - { - 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, - 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, - 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, - 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, - 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, - 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, - 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, - 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, - 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, - 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, - 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, - 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, - 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, - 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, - 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, - 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, - 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, - 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, - 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, - 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, - 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, - 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, - 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, - 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, - 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, - 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, - 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, - 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, - 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, - 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, - 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, - 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, - 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, - 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, - 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, - 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, - 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, - 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, - 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, - 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, - 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, - 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, - 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, - 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, - 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, - 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, - 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, - 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, - 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, - 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, - 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, - 0xbe9834edUL - }, - { - 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, - 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, - 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, - 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, - 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, - 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, - 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, - 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, - 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, - 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, - 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, - 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, - 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, - 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, - 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, - 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, - 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, - 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, - 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, - 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, - 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, - 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, - 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, - 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, - 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, - 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, - 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, - 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, - 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, - 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, - 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, - 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, - 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, - 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, - 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, - 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, - 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, - 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, - 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, - 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, - 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, - 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, - 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, - 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, - 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, - 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, - 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, - 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, - 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, - 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, - 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, - 0xde0506f1UL - }, - { - 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, - 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, - 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, - 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, - 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, - 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, - 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, - 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, - 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, - 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, - 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, - 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, - 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, - 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, - 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, - 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, - 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, - 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, - 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, - 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, - 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, - 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, - 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, - 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, - 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, - 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, - 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, - 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, - 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, - 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, - 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, - 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, - 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, - 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, - 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, - 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, - 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, - 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, - 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, - 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, - 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, - 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, - 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, - 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, - 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, - 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, - 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, - 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, - 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, - 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, - 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, - 0x8def022dUL - }, - { - 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, - 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, - 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, - 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, - 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, - 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, - 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, - 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, - 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, - 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, - 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, - 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, - 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, - 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, - 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, - 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, - 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, - 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, - 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, - 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, - 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, - 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, - 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, - 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, - 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, - 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, - 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, - 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, - 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, - 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, - 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, - 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, - 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, - 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, - 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, - 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, - 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, - 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, - 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, - 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, - 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, - 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, - 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, - 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, - 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, - 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, - 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, - 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, - 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, - 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, - 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, - 0x72fd2493UL - }, - { - 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, - 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, - 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, - 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, - 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, - 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, - 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, - 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, - 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, - 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, - 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, - 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, - 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, - 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, - 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, - 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, - 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, - 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, - 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, - 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, - 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, - 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, - 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, - 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, - 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, - 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, - 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, - 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, - 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, - 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, - 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, - 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, - 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, - 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, - 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, - 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, - 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, - 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, - 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, - 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, - 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, - 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, - 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, - 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, - 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, - 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, - 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, - 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, - 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, - 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, - 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, - 0xed3498beUL - }, - { - 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, - 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, - 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, - 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, - 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, - 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, - 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, - 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, - 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, - 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, - 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, - 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, - 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, - 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, - 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, - 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, - 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, - 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, - 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, - 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, - 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, - 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, - 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, - 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, - 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, - 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, - 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, - 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, - 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, - 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, - 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, - 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, - 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, - 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, - 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, - 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, - 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, - 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, - 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, - 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, - 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, - 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, - 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, - 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, - 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, - 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, - 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, - 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, - 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, - 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, - 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, - 0xf10605deUL -#endif - } -}; +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/3rdparty/zlib/deflate.c b/3rdparty/zlib/deflate.c index 529f716b7a..29ce1f64a5 100644 --- a/3rdparty/zlib/deflate.c +++ b/3rdparty/zlib/deflate.c @@ -1,1736 +1,1736 @@ -/* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process depends on being able to identify portions - * of the input text which are identical to earlier input (within a - * sliding window trailing behind the input currently being processed). - * - * The most straightforward technique turns out to be the fastest for - * most input files: try all possible matches and select the longest. - * The key feature of this algorithm is that insertions into the string - * dictionary are very simple and thus fast, and deletions are avoided - * completely. Insertions are performed at each input character, whereas - * string matches are performed only when the previous match ends. So it - * is preferable to spend more time in matches to allow very fast string - * insertions and avoid deletions. The matching algorithm for small - * strings is inspired from that of Rabin & Karp. A brute force approach - * is used to find longer strings when a small match has been found. - * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze - * (by Leonid Broukhis). - * A previous version of this file used a more sophisticated algorithm - * (by Fiala and Greene) which is guaranteed to run in linear amortized - * time, but has a larger average cost, uses more memory and is patented. - * However the F&G algorithm may be faster for some highly redundant - * files if the parameter max_chain_length (described below) is too large. - * - * ACKNOWLEDGEMENTS - * - * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and - * I found it in 'freeze' written by Leonid Broukhis. - * Thanks to many people for bug reports and testing. - * - * REFERENCES - * - * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". - * Available in http://www.ietf.org/rfc/rfc1951.txt - * - * A description of the Rabin and Karp algorithm is given in the book - * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. - * - * Fiala,E.R., and Greene,D.H. - * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 - * - */ - -/* @(#) $Id$ */ - -#include "deflate.h" - -const char deflate_copyright[] = - " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* =========================================================================== - * Function prototypes. - */ -typedef enum { - need_more, /* block not completed, need more input or more output */ - block_done, /* block flush performed */ - finish_started, /* finish started, need only more output at next deflate */ - finish_done /* finish done, accept no more input or output */ -} block_state; - -typedef block_state (*compress_func) OF((deflate_state *s, int flush)); -/* Compression function. Returns the block state after the call. */ - -local void fill_window OF((deflate_state *s)); -local block_state deflate_stored OF((deflate_state *s, int flush)); -local block_state deflate_fast OF((deflate_state *s, int flush)); -#ifndef FASTEST -local block_state deflate_slow OF((deflate_state *s, int flush)); -#endif -local void lm_init OF((deflate_state *s)); -local void putShortMSB OF((deflate_state *s, uInt b)); -local void flush_pending OF((z_streamp strm)); -local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); -#ifndef FASTEST -#ifdef ASMV - void match_init OF((void)); /* asm code initialization */ - uInt longest_match OF((deflate_state *s, IPos cur_match)); -#else -local uInt longest_match OF((deflate_state *s, IPos cur_match)); -#endif -#endif -local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); - -#ifdef DEBUG -local void check_match OF((deflate_state *s, IPos start, IPos match, - int length)); -#endif - -/* =========================================================================== - * Local data - */ - -#define NIL 0 -/* Tail of hash chains */ - -#ifndef TOO_FAR -# define TOO_FAR 4096 -#endif -/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -/* Values for max_lazy_match, good_match and max_chain_length, depending on - * the desired pack level (0..9). The values given below have been tuned to - * exclude worst case performance for pathological files. Better values may be - * found for specific files. - */ -typedef struct config_s { - ush good_length; /* reduce lazy search above this match length */ - ush max_lazy; /* do not perform lazy search above this match length */ - ush nice_length; /* quit search above this match length */ - ush max_chain; - compress_func func; -} config; - -#ifdef FASTEST -local const config configuration_table[2] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ -#else -local const config configuration_table[10] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ -/* 2 */ {4, 5, 16, 8, deflate_fast}, -/* 3 */ {4, 6, 32, 32, deflate_fast}, - -/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ -/* 5 */ {8, 16, 32, 32, deflate_slow}, -/* 6 */ {8, 16, 128, 128, deflate_slow}, -/* 7 */ {8, 32, 128, 256, deflate_slow}, -/* 8 */ {32, 128, 258, 1024, deflate_slow}, -/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ -#endif - -/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 - * For deflate_fast() (levels <= 3) good is ignored and lazy has a different - * meaning. - */ - -#define EQUAL 0 -/* result of memcmp for equal strings */ - -#ifndef NO_DUMMY_DECL -struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ -#endif - -/* =========================================================================== - * Update a hash value with the given input byte - * IN assertion: all calls to to UPDATE_HASH are made with consecutive - * input characters, so that a running hash key can be computed from the - * previous key instead of complete recalculation each time. - */ -#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) - - -/* =========================================================================== - * Insert string str in the dictionary and set match_head to the previous head - * of the hash chain (the most recent string with same hash key). Return - * the previous length of the hash chain. - * If this file is compiled with -DFASTEST, the compression level is forced - * to 1, and no hash chains are maintained. - * IN assertion: all calls to to INSERT_STRING are made with consecutive - * input characters and the first MIN_MATCH bytes of str are valid - * (except for the last MIN_MATCH-1 bytes of the input file). - */ -#ifdef FASTEST -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - match_head = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) -#else -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) -#endif - -/* =========================================================================== - * Initialize the hash table (avoiding 64K overflow for 16 bit systems). - * prev[] will be initialized on the fly. - */ -#define CLEAR_HASH(s) \ - s->head[s->hash_size-1] = NIL; \ - zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); - -/* ========================================================================= */ -int ZEXPORT deflateInit_(strm, level, version, stream_size) - z_streamp strm; - int level; - const char *version; - int stream_size; -{ - return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, version, stream_size); - /* To do: ignore strm->next_in if we use it as window */ -} - -/* ========================================================================= */ -int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, - version, stream_size) - z_streamp strm; - int level; - int method; - int windowBits; - int memLevel; - int strategy; - const char *version; - int stream_size; -{ - deflate_state *s; - int wrap = 1; - static const char my_version[] = ZLIB_VERSION; - - ushf *overlay; - /* We overlay pending_buf and d_buf+l_buf. This works since the average - * output size for (length,distance) codes is <= 24 bits. - */ - - if (version == Z_NULL || version[0] != my_version[0] || - stream_size != sizeof(z_stream)) { - return Z_VERSION_ERROR; - } - if (strm == Z_NULL) return Z_STREAM_ERROR; - - strm->msg = Z_NULL; - if (strm->zalloc == (alloc_func)0) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; - -#ifdef FASTEST - if (level != 0) level = 1; -#else - if (level == Z_DEFAULT_COMPRESSION) level = 6; -#endif - - if (windowBits < 0) { /* suppress zlib wrapper */ - wrap = 0; - windowBits = -windowBits; - } -#ifdef GZIP - else if (windowBits > 15) { - wrap = 2; /* write gzip wrapper instead */ - windowBits -= 16; - } -#endif - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || - windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_FIXED) { - return Z_STREAM_ERROR; - } - if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ - s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); - if (s == Z_NULL) return Z_MEM_ERROR; - strm->state = (struct internal_state FAR *)s; - s->strm = strm; - - s->wrap = wrap; - s->gzhead = Z_NULL; - s->w_bits = windowBits; - s->w_size = 1 << s->w_bits; - s->w_mask = s->w_size - 1; - - s->hash_bits = memLevel + 7; - s->hash_size = 1 << s->hash_bits; - s->hash_mask = s->hash_size - 1; - s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); - - s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); - s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); - s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); - - s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ - - overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); - s->pending_buf = (uchf *) overlay; - s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); - - if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || - s->pending_buf == Z_NULL) { - s->status = FINISH_STATE; - strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); - deflateEnd (strm); - return Z_MEM_ERROR; - } - s->d_buf = overlay + s->lit_bufsize/sizeof(ush); - s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; - - s->level = level; - s->strategy = strategy; - s->method = (Byte)method; - - return deflateReset(strm); -} - -/* ========================================================================= */ -int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) - z_streamp strm; - const Bytef *dictionary; - uInt dictLength; -{ - deflate_state *s; - uInt length = dictLength; - uInt n; - IPos hash_head = 0; - - if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || - strm->state->wrap == 2 || - (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) - return Z_STREAM_ERROR; - - s = strm->state; - if (s->wrap) - strm->adler = adler32(strm->adler, dictionary, dictLength); - - if (length < MIN_MATCH) return Z_OK; - if (length > MAX_DIST(s)) { - length = MAX_DIST(s); - dictionary += dictLength - length; /* use the tail of the dictionary */ - } - zmemcpy(s->window, dictionary, length); - s->strstart = length; - s->block_start = (long)length; - - /* Insert all strings in the hash table (except for the last two bytes). - * s->lookahead stays null, so s->ins_h will be recomputed at the next - * call of fill_window. - */ - s->ins_h = s->window[0]; - UPDATE_HASH(s, s->ins_h, s->window[1]); - for (n = 0; n <= length - MIN_MATCH; n++) { - INSERT_STRING(s, n, hash_head); - } - if (hash_head) hash_head = 0; /* to make compiler happy */ - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateReset (strm) - z_streamp strm; -{ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL || - strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { - return Z_STREAM_ERROR; - } - - strm->total_in = strm->total_out = 0; - strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ - strm->data_type = Z_UNKNOWN; - - s = (deflate_state *)strm->state; - s->pending = 0; - s->pending_out = s->pending_buf; - - if (s->wrap < 0) { - s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ - } - s->status = s->wrap ? INIT_STATE : BUSY_STATE; - strm->adler = -#ifdef GZIP - s->wrap == 2 ? crc32(0L, Z_NULL, 0) : -#endif - adler32(0L, Z_NULL, 0); - s->last_flush = Z_NO_FLUSH; - - _tr_init(s); - lm_init(s); - - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateSetHeader (strm, head) - z_streamp strm; - gz_headerp head; -{ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - if (strm->state->wrap != 2) return Z_STREAM_ERROR; - strm->state->gzhead = head; - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflatePrime (strm, bits, value) - z_streamp strm; - int bits; - int value; -{ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - strm->state->bi_valid = bits; - strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateParams(strm, level, strategy) - z_streamp strm; - int level; - int strategy; -{ - deflate_state *s; - compress_func func; - int err = Z_OK; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - s = strm->state; - -#ifdef FASTEST - if (level != 0) level = 1; -#else - if (level == Z_DEFAULT_COMPRESSION) level = 6; -#endif - if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { - return Z_STREAM_ERROR; - } - func = configuration_table[s->level].func; - - if (func != configuration_table[level].func && strm->total_in != 0) { - /* Flush the last buffer: */ - err = deflate(strm, Z_PARTIAL_FLUSH); - } - if (s->level != level) { - s->level = level; - s->max_lazy_match = configuration_table[level].max_lazy; - s->good_match = configuration_table[level].good_length; - s->nice_match = configuration_table[level].nice_length; - s->max_chain_length = configuration_table[level].max_chain; - } - s->strategy = strategy; - return err; -} - -/* ========================================================================= */ -int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) - z_streamp strm; - int good_length; - int max_lazy; - int nice_length; - int max_chain; -{ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - s = strm->state; - s->good_match = good_length; - s->max_lazy_match = max_lazy; - s->nice_match = nice_length; - s->max_chain_length = max_chain; - return Z_OK; -} - -/* ========================================================================= - * For the default windowBits of 15 and memLevel of 8, this function returns - * a close to exact, as well as small, upper bound on the compressed size. - * They are coded as constants here for a reason--if the #define's are - * changed, then this function needs to be changed as well. The return - * value for 15 and 8 only works for those exact settings. - * - * For any setting other than those defaults for windowBits and memLevel, - * the value returned is a conservative worst case for the maximum expansion - * resulting from using fixed blocks instead of stored blocks, which deflate - * can emit on compressed data for some combinations of the parameters. - * - * This function could be more sophisticated to provide closer upper bounds - * for every combination of windowBits and memLevel, as well as wrap. - * But even the conservative upper bound of about 14% expansion does not - * seem onerous for output buffer allocation. - */ -uLong ZEXPORT deflateBound(strm, sourceLen) - z_streamp strm; - uLong sourceLen; -{ - deflate_state *s; - uLong destLen; - - /* conservative upper bound */ - destLen = sourceLen + - ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; - - /* if can't get parameters, return conservative bound */ - if (strm == Z_NULL || strm->state == Z_NULL) - return destLen; - - /* if not default parameters, return conservative bound */ - s = strm->state; - if (s->w_bits != 15 || s->hash_bits != 8 + 7) - return destLen; - - /* default settings: return tight bound for that case */ - return compressBound(sourceLen); -} - -/* ========================================================================= - * Put a short in the pending buffer. The 16-bit value is put in MSB order. - * IN assertion: the stream state is correct and there is enough room in - * pending_buf. - */ -local void putShortMSB (s, b) - deflate_state *s; - uInt b; -{ - put_byte(s, (Byte)(b >> 8)); - put_byte(s, (Byte)(b & 0xff)); -} - -/* ========================================================================= - * Flush as much pending output as possible. All deflate() output goes - * through this function so some applications may wish to modify it - * to avoid allocating a large strm->next_out buffer and copying into it. - * (See also read_buf()). - */ -local void flush_pending(strm) - z_streamp strm; -{ - unsigned len = strm->state->pending; - - if (len > strm->avail_out) len = strm->avail_out; - if (len == 0) return; - - zmemcpy(strm->next_out, strm->state->pending_out, len); - strm->next_out += len; - strm->state->pending_out += len; - strm->total_out += len; - strm->avail_out -= len; - strm->state->pending -= len; - if (strm->state->pending == 0) { - strm->state->pending_out = strm->state->pending_buf; - } -} - -/* ========================================================================= */ -int ZEXPORT deflate (strm, flush) - z_streamp strm; - int flush; -{ - int old_flush; /* value of flush param for previous deflate call */ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL || - flush > Z_FINISH || flush < 0) { - return Z_STREAM_ERROR; - } - s = strm->state; - - if (strm->next_out == Z_NULL || - (strm->next_in == Z_NULL && strm->avail_in != 0) || - (s->status == FINISH_STATE && flush != Z_FINISH)) { - ERR_RETURN(strm, Z_STREAM_ERROR); - } - if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); - - s->strm = strm; /* just in case */ - old_flush = s->last_flush; - s->last_flush = flush; - - /* Write the header */ - if (s->status == INIT_STATE) { -#ifdef GZIP - if (s->wrap == 2) { - strm->adler = crc32(0L, Z_NULL, 0); - put_byte(s, 31); - put_byte(s, 139); - put_byte(s, 8); - if (s->gzhead == NULL) { - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, OS_CODE); - s->status = BUSY_STATE; - } - else { - put_byte(s, (s->gzhead->text ? 1 : 0) + - (s->gzhead->hcrc ? 2 : 0) + - (s->gzhead->extra == Z_NULL ? 0 : 4) + - (s->gzhead->name == Z_NULL ? 0 : 8) + - (s->gzhead->comment == Z_NULL ? 0 : 16) - ); - put_byte(s, (Byte)(s->gzhead->time & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, s->gzhead->os & 0xff); - if (s->gzhead->extra != NULL) { - put_byte(s, s->gzhead->extra_len & 0xff); - put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); - } - if (s->gzhead->hcrc) - strm->adler = crc32(strm->adler, s->pending_buf, - s->pending); - s->gzindex = 0; - s->status = EXTRA_STATE; - } - } - else -#endif - { - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; - uInt level_flags; - - if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) - level_flags = 0; - else if (s->level < 6) - level_flags = 1; - else if (s->level == 6) - level_flags = 2; - else - level_flags = 3; - header |= (level_flags << 6); - if (s->strstart != 0) header |= PRESET_DICT; - header += 31 - (header % 31); - - s->status = BUSY_STATE; - putShortMSB(s, header); - - /* Save the adler32 of the preset dictionary: */ - if (s->strstart != 0) { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - strm->adler = adler32(0L, Z_NULL, 0); - } - } -#ifdef GZIP - if (s->status == EXTRA_STATE) { - if (s->gzhead->extra != NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - - while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) - break; - } - put_byte(s, s->gzhead->extra[s->gzindex]); - s->gzindex++; - } - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (s->gzindex == s->gzhead->extra_len) { - s->gzindex = 0; - s->status = NAME_STATE; - } - } - else - s->status = NAME_STATE; - } - if (s->status == NAME_STATE) { - if (s->gzhead->name != NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - int val; - - do { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) { - val = 1; - break; - } - } - val = s->gzhead->name[s->gzindex++]; - put_byte(s, val); - } while (val != 0); - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (val == 0) { - s->gzindex = 0; - s->status = COMMENT_STATE; - } - } - else - s->status = COMMENT_STATE; - } - if (s->status == COMMENT_STATE) { - if (s->gzhead->comment != NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - int val; - - do { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) { - val = 1; - break; - } - } - val = s->gzhead->comment[s->gzindex++]; - put_byte(s, val); - } while (val != 0); - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (val == 0) - s->status = HCRC_STATE; - } - else - s->status = HCRC_STATE; - } - if (s->status == HCRC_STATE) { - if (s->gzhead->hcrc) { - if (s->pending + 2 > s->pending_buf_size) - flush_pending(strm); - if (s->pending + 2 <= s->pending_buf_size) { - put_byte(s, (Byte)(strm->adler & 0xff)); - put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); - strm->adler = crc32(0L, Z_NULL, 0); - s->status = BUSY_STATE; - } - } - else - s->status = BUSY_STATE; - } -#endif - - /* Flush as much pending output as possible */ - if (s->pending != 0) { - flush_pending(strm); - if (strm->avail_out == 0) { - /* Since avail_out is 0, deflate will be called again with - * more output space, but possibly with both pending and - * avail_in equal to zero. There won't be anything to do, - * but this is not an error situation so make sure we - * return OK instead of BUF_ERROR at next call of deflate: - */ - s->last_flush = -1; - return Z_OK; - } - - /* Make sure there is something to do and avoid duplicate consecutive - * flushes. For repeated and useless calls with Z_FINISH, we keep - * returning Z_STREAM_END instead of Z_BUF_ERROR. - */ - } else if (strm->avail_in == 0 && flush <= old_flush && - flush != Z_FINISH) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* User must not provide more input after the first FINISH: */ - if (s->status == FINISH_STATE && strm->avail_in != 0) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* Start a new block or continue the current one. - */ - if (strm->avail_in != 0 || s->lookahead != 0 || - (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { - block_state bstate; - - bstate = (*(configuration_table[s->level].func))(s, flush); - - if (bstate == finish_started || bstate == finish_done) { - s->status = FINISH_STATE; - } - if (bstate == need_more || bstate == finish_started) { - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ - } - return Z_OK; - /* If flush != Z_NO_FLUSH && avail_out == 0, the next call - * of deflate should use the same flush parameter to make sure - * that the flush is complete. So we don't have to output an - * empty block here, this will be done at next call. This also - * ensures that for a very small output buffer, we emit at most - * one empty block. - */ - } - if (bstate == block_done) { - if (flush == Z_PARTIAL_FLUSH) { - _tr_align(s); - } else { /* FULL_FLUSH or SYNC_FLUSH */ - _tr_stored_block(s, (char*)0, 0L, 0); - /* For a full flush, this empty block will be recognized - * as a special marker by inflate_sync(). - */ - if (flush == Z_FULL_FLUSH) { - CLEAR_HASH(s); /* forget history */ - } - } - flush_pending(strm); - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ - return Z_OK; - } - } - } - Assert(strm->avail_out > 0, "bug2"); - - if (flush != Z_FINISH) return Z_OK; - if (s->wrap <= 0) return Z_STREAM_END; - - /* Write the trailer */ -#ifdef GZIP - if (s->wrap == 2) { - put_byte(s, (Byte)(strm->adler & 0xff)); - put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); - put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); - put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); - put_byte(s, (Byte)(strm->total_in & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); - } - else -#endif - { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - flush_pending(strm); - /* If avail_out is zero, the application will call deflate again - * to flush the rest. - */ - if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ - return s->pending != 0 ? Z_OK : Z_STREAM_END; -} - -/* ========================================================================= */ -int ZEXPORT deflateEnd (strm) - z_streamp strm; -{ - int status; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - - status = strm->state->status; - if (status != INIT_STATE && - status != EXTRA_STATE && - status != NAME_STATE && - status != COMMENT_STATE && - status != HCRC_STATE && - status != BUSY_STATE && - status != FINISH_STATE) { - return Z_STREAM_ERROR; - } - - /* Deallocate in reverse order of allocations: */ - TRY_FREE(strm, strm->state->pending_buf); - TRY_FREE(strm, strm->state->head); - TRY_FREE(strm, strm->state->prev); - TRY_FREE(strm, strm->state->window); - - ZFREE(strm, strm->state); - strm->state = Z_NULL; - - return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; -} - -/* ========================================================================= - * Copy the source state to the destination state. - * To simplify the source, this is not supported for 16-bit MSDOS (which - * doesn't have enough memory anyway to duplicate compression states). - */ -int ZEXPORT deflateCopy (dest, source) - z_streamp dest; - z_streamp source; -{ -#ifdef MAXSEG_64K - return Z_STREAM_ERROR; -#else - deflate_state *ds; - deflate_state *ss; - ushf *overlay; - - - if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { - return Z_STREAM_ERROR; - } - - ss = source->state; - - zmemcpy(dest, source, sizeof(z_stream)); - - ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); - if (ds == Z_NULL) return Z_MEM_ERROR; - dest->state = (struct internal_state FAR *) ds; - zmemcpy(ds, ss, sizeof(deflate_state)); - ds->strm = dest; - - ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); - ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); - ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); - overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); - ds->pending_buf = (uchf *) overlay; - - if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || - ds->pending_buf == Z_NULL) { - deflateEnd (dest); - return Z_MEM_ERROR; - } - /* following zmemcpy do not work for 16-bit MSDOS */ - zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); - zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); - zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); - zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); - - ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); - ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); - ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; - - ds->l_desc.dyn_tree = ds->dyn_ltree; - ds->d_desc.dyn_tree = ds->dyn_dtree; - ds->bl_desc.dyn_tree = ds->bl_tree; - - return Z_OK; -#endif /* MAXSEG_64K */ -} - -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->next_in buffer and copying from it. - * (See also flush_pending()). - */ -local int read_buf(strm, buf, size) - z_streamp strm; - Bytef *buf; - unsigned size; -{ - unsigned len = strm->avail_in; - - if (len > size) len = size; - if (len == 0) return 0; - - strm->avail_in -= len; - - if (strm->state->wrap == 1) { - strm->adler = adler32(strm->adler, strm->next_in, len); - } -#ifdef GZIP - else if (strm->state->wrap == 2) { - strm->adler = crc32(strm->adler, strm->next_in, len); - } -#endif - zmemcpy(buf, strm->next_in, len); - strm->next_in += len; - strm->total_in += len; - - return (int)len; -} - -/* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ -local void lm_init (s) - deflate_state *s; -{ - s->window_size = (ulg)2L*s->w_size; - - CLEAR_HASH(s); - - /* Set the default configuration parameters: - */ - s->max_lazy_match = configuration_table[s->level].max_lazy; - s->good_match = configuration_table[s->level].good_length; - s->nice_match = configuration_table[s->level].nice_length; - s->max_chain_length = configuration_table[s->level].max_chain; - - s->strstart = 0; - s->block_start = 0L; - s->lookahead = 0; - s->match_length = s->prev_length = MIN_MATCH-1; - s->match_available = 0; - s->ins_h = 0; -#ifndef FASTEST -#ifdef ASMV - match_init(); /* initialize the asm code */ -#endif -#endif -} - -#ifndef FASTEST -/* =========================================================================== - * Set match_start to the longest match starting at the given string and - * return its length. Matches shorter or equal to prev_length are discarded, - * in which case the result is equal to prev_length and match_start is - * garbage. - * IN assertions: cur_match is the head of the hash chain for the current - * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 - * OUT assertion: the match length is not greater than s->lookahead. - */ -#ifndef ASMV -/* For 80x86 and 680x0, an optimized version will be provided in match.asm or - * match.S. The code will be functionally equivalent. - */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - unsigned chain_length = s->max_chain_length;/* max hash chain length */ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - int best_len = s->prev_length; /* best match length so far */ - int nice_match = s->nice_match; /* stop if match long enough */ - IPos limit = s->strstart > (IPos)MAX_DIST(s) ? - s->strstart - (IPos)MAX_DIST(s) : NIL; - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0. - */ - Posf *prev = s->prev; - uInt wmask = s->w_mask; - -#ifdef UNALIGNED_OK - /* Compare two bytes at a time. Note: this is not always beneficial. - * Try with and without -DUNALIGNED_OK to check. - */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; - register ush scan_start = *(ushf*)scan; - register ush scan_end = *(ushf*)(scan+best_len-1); -#else - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - register Byte scan_end1 = scan[best_len-1]; - register Byte scan_end = scan[best_len]; -#endif - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - /* Do not waste too much time if we already have a good match: */ - if (s->prev_length >= s->good_match) { - chain_length >>= 2; - } - /* Do not look for matches beyond the end of the input. This is necessary - * to make deflate deterministic. - */ - if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - do { - Assert(cur_match < s->strstart, "no future"); - match = s->window + cur_match; - - /* Skip to next match if the match length cannot increase - * or if the match length is less than 2. Note that the checks below - * for insufficient lookahead only occur occasionally for performance - * reasons. Therefore uninitialized memory will be accessed, and - * conditional jumps will be made that depend on those values. - * However the length of the match is limited to the lookahead, so - * the output of deflate is not affected by the uninitialized values. - */ -#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) - /* This code assumes sizeof(unsigned short) == 2. Do not use - * UNALIGNED_OK if your compiler uses a different size. - */ - if (*(ushf*)(match+best_len-1) != scan_end || - *(ushf*)match != scan_start) continue; - - /* It is not necessary to compare scan[2] and match[2] since they are - * always equal when the other bytes match, given that the hash keys - * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at - * strstart+3, +5, ... up to strstart+257. We check for insufficient - * lookahead only every 4th comparison; the 128th check will be made - * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is - * necessary to put more guard bytes at the end of the window, or - * to check more often for insufficient lookahead. - */ - Assert(scan[2] == match[2], "scan[2]?"); - scan++, match++; - do { - } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - scan < strend); - /* The funny "do {}" generates better code on most compilers */ - - /* Here, scan <= window+strstart+257 */ - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - if (*scan == *match) scan++; - - len = (MAX_MATCH - 1) - (int)(strend-scan); - scan = strend - (MAX_MATCH-1); - -#else /* UNALIGNED_OK */ - - if (match[best_len] != scan_end || - match[best_len-1] != scan_end1 || - *match != *scan || - *++match != scan[1]) continue; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match++; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - scan = strend - MAX_MATCH; - -#endif /* UNALIGNED_OK */ - - if (len > best_len) { - s->match_start = cur_match; - best_len = len; - if (len >= nice_match) break; -#ifdef UNALIGNED_OK - scan_end = *(ushf*)(scan+best_len-1); -#else - scan_end1 = scan[best_len-1]; - scan_end = scan[best_len]; -#endif - } - } while ((cur_match = prev[cur_match & wmask]) > limit - && --chain_length != 0); - - if ((uInt)best_len <= s->lookahead) return (uInt)best_len; - return s->lookahead; -} -#endif /* ASMV */ -#endif /* FASTEST */ - -/* --------------------------------------------------------------------------- - * Optimized version for level == 1 or strategy == Z_RLE only - */ -local uInt longest_match_fast(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - Assert(cur_match < s->strstart, "no future"); - - match = s->window + cur_match; - - /* Return failure if the match length is less than 2: - */ - if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match += 2; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - - if (len < MIN_MATCH) return MIN_MATCH - 1; - - s->match_start = cur_match; - return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; -} - -#ifdef DEBUG -/* =========================================================================== - * Check that the match at match_start is indeed a match. - */ -local void check_match(s, start, match, length) - deflate_state *s; - IPos start, match; - int length; -{ - /* check that the match is indeed a match */ - if (zmemcmp(s->window + match, - s->window + start, length) != EQUAL) { - fprintf(stderr, " start %u, match %u, length %d\n", - start, match, length); - do { - fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); - } while (--length != 0); - z_error("invalid match"); - } - if (z_verbose > 1) { - fprintf(stderr,"\\[%d,%d]", start-match, length); - do { putc(s->window[start++], stderr); } while (--length != 0); - } -} -#else -# define check_match(s, start, match, length) -#endif /* DEBUG */ - -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ -local void fill_window(s) - deflate_state *s; -{ - register unsigned n, m; - register Posf *p; - unsigned more; /* Amount of free space at the end of the window. */ - uInt wsize = s->w_size; - - do { - more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); - - /* Deal with !@#$% 64K limit: */ - if (sizeof(int) <= 2) { - if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - more = wsize; - - } else if (more == (unsigned)(-1)) { - /* Very unlikely, but possible on 16 bit machine if - * strstart == 0 && lookahead == 1 (input done a byte at time) - */ - more--; - } - } - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (s->strstart >= wsize+MAX_DIST(s)) { - - zmemcpy(s->window, s->window+wsize, (unsigned)wsize); - s->match_start -= wsize; - s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ - s->block_start -= (long) wsize; - - /* Slide the hash table (could be avoided with 32 bit values - at the expense of memory usage). We slide even when level == 0 - to keep the hash table consistent if we switch back to level > 0 - later. (Using level 0 permanently is not an optimal usage of - zlib, so we don't care about this pathological case.) - */ - /* %%% avoid this when Z_RLE */ - n = s->hash_size; - p = &s->head[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - } while (--n); - - n = wsize; -#ifndef FASTEST - p = &s->prev[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); -#endif - more += wsize; - } - if (s->strm->avail_in == 0) return; - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - Assert(more >= 2, "more < 2"); - - n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); - s->lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s->lookahead >= MIN_MATCH) { - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ - - } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); -} - -/* =========================================================================== - * Flush the current block, with given end-of-file flag. - * IN assertion: strstart is set to the end of the current match. - */ -#define FLUSH_BLOCK_ONLY(s, eof) { \ - _tr_flush_block(s, (s->block_start >= 0L ? \ - (charf *)&s->window[(unsigned)s->block_start] : \ - (charf *)Z_NULL), \ - (ulg)((long)s->strstart - s->block_start), \ - (eof)); \ - s->block_start = s->strstart; \ - flush_pending(s->strm); \ - Tracev((stderr,"[FLUSH]")); \ -} - -/* Same but force premature exit if necessary. */ -#define FLUSH_BLOCK(s, eof) { \ - FLUSH_BLOCK_ONLY(s, eof); \ - if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ -} - -/* =========================================================================== - * Copy without compression as much as possible from the input stream, return - * the current block state. - * This function does not insert new strings in the dictionary since - * uncompressible data is probably not useful. This function is used - * only for the level=0 compression option. - * NOTE: this function should be optimized to avoid extra copying from - * window to pending_buf. - */ -local block_state deflate_stored(s, flush) - deflate_state *s; - int flush; -{ - /* Stored blocks are limited to 0xffff bytes, pending_buf is limited - * to pending_buf_size, and each stored block has a 5 byte header: - */ - ulg max_block_size = 0xffff; - ulg max_start; - - if (max_block_size > s->pending_buf_size - 5) { - max_block_size = s->pending_buf_size - 5; - } - - /* Copy as much as possible from input to output: */ - for (;;) { - /* Fill the window as much as possible: */ - if (s->lookahead <= 1) { - - Assert(s->strstart < s->w_size+MAX_DIST(s) || - s->block_start >= (long)s->w_size, "slide too late"); - - fill_window(s); - if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; - - if (s->lookahead == 0) break; /* flush the current block */ - } - Assert(s->block_start >= 0L, "block gone"); - - s->strstart += s->lookahead; - s->lookahead = 0; - - /* Emit a stored block if pending_buf will be full: */ - max_start = s->block_start + max_block_size; - if (s->strstart == 0 || (ulg)s->strstart >= max_start) { - /* strstart == 0 is possible when wraparound on 16-bit machine */ - s->lookahead = (uInt)(s->strstart - max_start); - s->strstart = (uInt)max_start; - FLUSH_BLOCK(s, 0); - } - /* Flush if we may have to slide, otherwise block_start may become - * negative and the data will be gone: - */ - if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { - FLUSH_BLOCK(s, 0); - } - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} - -/* =========================================================================== - * Compress as much as possible from the input stream, return the current - * block state. - * This function does not perform lazy evaluation of matches and inserts - * new strings in the dictionary only for unmatched strings or for short - * matches. It is used only for the fast compression options. - */ -local block_state deflate_fast(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head = NIL; /* head of the hash chain */ - int bflush; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - * At this point we have always match_length < MIN_MATCH - */ - if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ -#ifdef FASTEST - if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || - (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { - s->match_length = longest_match_fast (s, hash_head); - } -#else - if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { - s->match_length = longest_match (s, hash_head); - } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { - s->match_length = longest_match_fast (s, hash_head); - } -#endif - /* longest_match() or longest_match_fast() sets match_start */ - } - if (s->match_length >= MIN_MATCH) { - check_match(s, s->strstart, s->match_start, s->match_length); - - _tr_tally_dist(s, s->strstart - s->match_start, - s->match_length - MIN_MATCH, bflush); - - s->lookahead -= s->match_length; - - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ -#ifndef FASTEST - if (s->match_length <= s->max_insert_length && - s->lookahead >= MIN_MATCH) { - s->match_length--; /* string at strstart already in table */ - do { - s->strstart++; - INSERT_STRING(s, s->strstart, hash_head); - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. - */ - } while (--s->match_length != 0); - s->strstart++; - } else -#endif - { - s->strstart += s->match_length; - s->match_length = 0; - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not - * matter since it will be recomputed at next deflate call. - */ - } - } else { - /* No match, output a literal byte */ - Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - } - if (bflush) FLUSH_BLOCK(s, 0); - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} - -#ifndef FASTEST -/* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ -local block_state deflate_slow(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head = NIL; /* head of hash chain */ - int bflush; /* set if current block must be flushed */ - - /* Process the input block. */ - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - */ - s->prev_length = s->match_length, s->prev_match = s->match_start; - s->match_length = MIN_MATCH-1; - - if (hash_head != NIL && s->prev_length < s->max_lazy_match && - s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { - s->match_length = longest_match (s, hash_head); - } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { - s->match_length = longest_match_fast (s, hash_head); - } - /* longest_match() or longest_match_fast() sets match_start */ - - if (s->match_length <= 5 && (s->strategy == Z_FILTERED -#if TOO_FAR <= 32767 - || (s->match_length == MIN_MATCH && - s->strstart - s->match_start > TOO_FAR) -#endif - )) { - - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - s->match_length = MIN_MATCH-1; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { - uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; - /* Do not insert strings in hash table beyond this. */ - - check_match(s, s->strstart-1, s->prev_match, s->prev_length); - - _tr_tally_dist(s, s->strstart -1 - s->prev_match, - s->prev_length - MIN_MATCH, bflush); - - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not - * enough lookahead, the last two strings are not inserted in - * the hash table. - */ - s->lookahead -= s->prev_length-1; - s->prev_length -= 2; - do { - if (++s->strstart <= max_insert) { - INSERT_STRING(s, s->strstart, hash_head); - } - } while (--s->prev_length != 0); - s->match_available = 0; - s->match_length = MIN_MATCH-1; - s->strstart++; - - if (bflush) FLUSH_BLOCK(s, 0); - - } else if (s->match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - if (bflush) { - FLUSH_BLOCK_ONLY(s, 0); - } - s->strstart++; - s->lookahead--; - if (s->strm->avail_out == 0) return need_more; - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - s->match_available = 1; - s->strstart++; - s->lookahead--; - } - } - Assert (flush != Z_NO_FLUSH, "no flush?"); - if (s->match_available) { - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - s->match_available = 0; - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} -#endif /* FASTEST */ - -#if 0 -/* =========================================================================== - * For Z_RLE, simply look for runs of bytes, generate matches only of distance - * one. Do not maintain a hash table. (It will be regenerated if this run of - * deflate switches away from Z_RLE.) - */ -local block_state deflate_rle(s, flush) - deflate_state *s; - int flush; -{ - int bflush; /* set if current block must be flushed */ - uInt run; /* length of run */ - uInt max; /* maximum length of run */ - uInt prev; /* byte at distance one to match */ - Bytef *scan; /* scan for end of run */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the longest encodable run. - */ - if (s->lookahead < MAX_MATCH) { - fill_window(s); - if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* See how many times the previous byte repeats */ - run = 0; - if (s->strstart > 0) { /* if there is a previous byte, that is */ - max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; - scan = s->window + s->strstart - 1; - prev = *scan++; - do { - if (*scan++ != prev) - break; - } while (++run < max); - } - - /* Emit match if have run of MIN_MATCH or longer, else emit literal */ - if (run >= MIN_MATCH) { - check_match(s, s->strstart, s->strstart - 1, run); - _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); - s->lookahead -= run; - s->strstart += run; - } else { - /* No match, output a literal byte */ - Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - } - if (bflush) FLUSH_BLOCK(s, 0); - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} -#endif +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); + dictionary += dictLength - length; /* use the tail of the dictionary */ + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy(dest, source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy(ds, ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + /* %%% avoid this when Z_RLE */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ + +#if 0 +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt run; /* length of run */ + uInt max; /* maximum length of run */ + uInt prev; /* byte at distance one to match */ + Bytef *scan; /* scan for end of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest encodable run. + */ + if (s->lookahead < MAX_MATCH) { + fill_window(s); + if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + run = 0; + if (s->strstart > 0) { /* if there is a previous byte, that is */ + max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; + scan = s->window + s->strstart - 1; + prev = *scan++; + do { + if (*scan++ != prev) + break; + } while (++run < max); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (run >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, run); + _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); + s->lookahead -= run; + s->strstart += run; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif diff --git a/3rdparty/zlib/deflate.h b/3rdparty/zlib/deflate.h index 222c53e043..05a5ab3a2c 100644 --- a/3rdparty/zlib/deflate.h +++ b/3rdparty/zlib/deflate.h @@ -1,331 +1,331 @@ -/* deflate.h -- internal compression state - * Copyright (C) 1995-2004 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id$ */ - -#ifndef DEFLATE_H -#define DEFLATE_H - -#include "zutil.h" - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer creation by deflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip encoding - should be left enabled. */ -#ifndef NO_GZIP -# define GZIP -#endif - -/* =========================================================================== - * Internal compression state. - */ - -#define LENGTH_CODES 29 -/* number of length codes, not counting the special END_BLOCK code */ - -#define LITERALS 256 -/* number of literal bytes 0..255 */ - -#define L_CODES (LITERALS+1+LENGTH_CODES) -/* number of Literal or Length codes, including the END_BLOCK code */ - -#define D_CODES 30 -/* number of distance codes */ - -#define BL_CODES 19 -/* number of codes used to transfer the bit lengths */ - -#define HEAP_SIZE (2*L_CODES+1) -/* maximum heap size */ - -#define MAX_BITS 15 -/* All codes must not exceed MAX_BITS bits */ - -#define INIT_STATE 42 -#define EXTRA_STATE 69 -#define NAME_STATE 73 -#define COMMENT_STATE 91 -#define HCRC_STATE 103 -#define BUSY_STATE 113 -#define FINISH_STATE 666 -/* Stream status */ - - -/* Data structure describing a single value and its code string. */ -typedef struct ct_data_s { - union { - ush freq; /* frequency count */ - ush code; /* bit string */ - } fc; - union { - ush dad; /* father node in Huffman tree */ - ush len; /* length of bit string */ - } dl; -} FAR ct_data; - -#define Freq fc.freq -#define Code fc.code -#define Dad dl.dad -#define Len dl.len - -typedef struct static_tree_desc_s static_tree_desc; - -typedef struct tree_desc_s { - ct_data *dyn_tree; /* the dynamic tree */ - int max_code; /* largest code with non zero frequency */ - static_tree_desc *stat_desc; /* the corresponding static tree */ -} FAR tree_desc; - -typedef ush Pos; -typedef Pos FAR Posf; -typedef unsigned IPos; - -/* A Pos is an index in the character window. We use short instead of int to - * save space in the various tables. IPos is used only for parameter passing. - */ - -typedef struct internal_state { - z_streamp strm; /* pointer back to this zlib stream */ - int status; /* as the name implies */ - Bytef *pending_buf; /* output still pending */ - ulg pending_buf_size; /* size of pending_buf */ - Bytef *pending_out; /* next pending byte to output to the stream */ - uInt pending; /* nb of bytes in the pending buffer */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - gz_headerp gzhead; /* gzip header information to write */ - uInt gzindex; /* where in extra, name, or comment */ - Byte method; /* STORED (for zip only) or DEFLATED */ - int last_flush; /* value of flush param for previous deflate call */ - - /* used by deflate.c: */ - - uInt w_size; /* LZ77 window size (32K by default) */ - uInt w_bits; /* log2(w_size) (8..16) */ - uInt w_mask; /* w_size - 1 */ - - Bytef *window; - /* Sliding window. Input bytes are read into the second half of the window, - * and move to the first half later to keep a dictionary of at least wSize - * bytes. With this organization, matches are limited to a distance of - * wSize-MAX_MATCH bytes, but this ensures that IO is always - * performed with a length multiple of the block size. Also, it limits - * the window size to 64K, which is quite useful on MSDOS. - * To do: use the user input buffer as sliding window. - */ - - ulg window_size; - /* Actual size of window: 2*wSize, except when the user input buffer - * is directly used as sliding window. - */ - - Posf *prev; - /* Link to older string with same hash index. To limit the size of this - * array to 64K, this link is maintained only for the last 32K strings. - * An index in this array is thus a window index modulo 32K. - */ - - Posf *head; /* Heads of the hash chains or NIL. */ - - uInt ins_h; /* hash index of string to be inserted */ - uInt hash_size; /* number of elements in hash table */ - uInt hash_bits; /* log2(hash_size) */ - uInt hash_mask; /* hash_size-1 */ - - uInt hash_shift; - /* Number of bits by which ins_h must be shifted at each input - * step. It must be such that after MIN_MATCH steps, the oldest - * byte no longer takes part in the hash key, that is: - * hash_shift * MIN_MATCH >= hash_bits - */ - - long block_start; - /* Window position at the beginning of the current output block. Gets - * negative when the window is moved backwards. - */ - - uInt match_length; /* length of best match */ - IPos prev_match; /* previous match */ - int match_available; /* set if previous match exists */ - uInt strstart; /* start of string to insert */ - uInt match_start; /* start of matching string */ - uInt lookahead; /* number of valid bytes ahead in window */ - - uInt prev_length; - /* Length of the best match at previous step. Matches not greater than this - * are discarded. This is used in the lazy match evaluation. - */ - - uInt max_chain_length; - /* To speed up deflation, hash chains are never searched beyond this - * length. A higher limit improves compression ratio but degrades the - * speed. - */ - - uInt max_lazy_match; - /* Attempt to find a better match only when the current match is strictly - * smaller than this value. This mechanism is used only for compression - * levels >= 4. - */ -# define max_insert_length max_lazy_match - /* Insert new strings in the hash table only if the match length is not - * greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 3. - */ - - int level; /* compression level (1..9) */ - int strategy; /* favor or force Huffman coding*/ - - uInt good_match; - /* Use a faster search when the previous match is longer than this */ - - int nice_match; /* Stop searching when current match exceeds this */ - - /* used by trees.c: */ - /* Didn't use ct_data typedef below to supress compiler warning */ - struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ - struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ - struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ - - struct tree_desc_s l_desc; /* desc. for literal tree */ - struct tree_desc_s d_desc; /* desc. for distance tree */ - struct tree_desc_s bl_desc; /* desc. for bit length tree */ - - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ - int heap_len; /* number of elements in the heap */ - int heap_max; /* element of largest frequency */ - /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - * The same heap array is used to build all trees. - */ - - uch depth[2*L_CODES+1]; - /* Depth of each subtree used as tie breaker for trees of equal frequency - */ - - uchf *l_buf; /* buffer for literals or lengths */ - - uInt lit_bufsize; - /* Size of match buffer for literals/lengths. There are 4 reasons for - * limiting lit_bufsize to 64K: - * - frequencies can be kept in 16 bit counters - * - if compression is not successful for the first block, all input - * data is still in the window so we can still emit a stored block even - * when input comes from standard input. (This can also be done for - * all blocks if lit_bufsize is not greater than 32K.) - * - if compression is not successful for a file smaller than 64K, we can - * even emit a stored file instead of a stored block (saving 5 bytes). - * This is applicable only for zip (not gzip or zlib). - * - creating new Huffman trees less frequently may not provide fast - * adaptation to changes in the input data statistics. (Take for - * example a binary file with poorly compressible code followed by - * a highly compressible string table.) Smaller buffer sizes give - * fast adaptation but have of course the overhead of transmitting - * trees more frequently. - * - I can't count above 4 - */ - - uInt last_lit; /* running index in l_buf */ - - ushf *d_buf; - /* Buffer for distances. To simplify the code, d_buf and l_buf have - * the same number of elements. To use different lengths, an extra flag - * array would be necessary. - */ - - ulg opt_len; /* bit length of current block with optimal trees */ - ulg static_len; /* bit length of current block with static trees */ - uInt matches; /* number of string matches in current block */ - int last_eob_len; /* bit length of EOB code for last block */ - -#ifdef DEBUG - ulg compressed_len; /* total bit length of compressed file mod 2^32 */ - ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ -#endif - - ush bi_buf; - /* Output buffer. bits are inserted starting at the bottom (least - * significant bits). - */ - int bi_valid; - /* Number of valid bits in bi_buf. All bits above the last valid bit - * are always zero. - */ - -} FAR deflate_state; - -/* Output a byte on the stream. - * IN assertion: there is enough room in pending_buf. - */ -#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} - - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) -/* In order to simplify the code, particularly on 16 bit machines, match - * distances are limited to MAX_DIST instead of WSIZE. - */ - - /* in trees.c */ -void _tr_init OF((deflate_state *s)); -int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); -void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); -void _tr_align OF((deflate_state *s)); -void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); - -#define d_code(dist) \ - ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) -/* Mapping from a distance to a distance code. dist is the distance - 1 and - * must not have side effects. _dist_code[256] and _dist_code[257] are never - * used. - */ - -#ifndef DEBUG -/* Inline versions of _tr_tally for speed: */ - -#if defined(GEN_TREES_H) || !defined(STDC) - extern uch _length_code[]; - extern uch _dist_code[]; -#else - extern const uch _length_code[]; - extern const uch _dist_code[]; -#endif - -# define _tr_tally_lit(s, c, flush) \ - { uch cc = (c); \ - s->d_buf[s->last_lit] = 0; \ - s->l_buf[s->last_lit++] = cc; \ - s->dyn_ltree[cc].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -# define _tr_tally_dist(s, distance, length, flush) \ - { uch len = (length); \ - ush dist = (distance); \ - s->d_buf[s->last_lit] = dist; \ - s->l_buf[s->last_lit++] = len; \ - dist--; \ - s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ - s->dyn_dtree[d_code(dist)].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -#else -# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) -# define _tr_tally_dist(s, distance, length, flush) \ - flush = _tr_tally(s, distance, length) -#endif - -#endif /* DEFLATE_H */ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2004 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/3rdparty/zlib/gzio.c b/3rdparty/zlib/gzio.c index 2de9a36441..b3c59ecd4c 100644 --- a/3rdparty/zlib/gzio.c +++ b/3rdparty/zlib/gzio.c @@ -1,1026 +1,1026 @@ -/* gzio.c -- IO on .gz files - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. - */ - -/* @(#) $Id$ */ - -#include - -#include "zutil.h" - -#ifdef NO_DEFLATE /* for compatibility with old definition */ -# define NO_GZCOMPRESS -#endif - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -#ifndef Z_BUFSIZE -# ifdef MAXSEG_64K -# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ -# else -# define Z_BUFSIZE 16384 -# endif -#endif -#ifndef Z_PRINTF_BUFSIZE -# define Z_PRINTF_BUFSIZE 4096 -#endif - -#ifdef __MVS__ -# pragma map (fdopen , "\174\174FDOPEN") - FILE *fdopen(int, const char *); -#endif - -#ifndef STDC -extern voidp malloc OF((uInt size)); -extern void free OF((voidpf ptr)); -#endif - -#define ALLOC(size) malloc(size) -#define TRYFREE(p) {if (p) free(p);} - -static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ - -/* gzip flag byte */ -#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ -#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ -#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ -#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ -#define COMMENT 0x10 /* bit 4 set: file comment present */ -#define RESERVED 0xE0 /* bits 5..7: reserved */ - -typedef struct gz_stream { - z_stream stream; - int z_err; /* error code for last stream operation */ - int z_eof; /* set if end of input file */ - FILE *file; /* .gz file */ - Byte *inbuf; /* input buffer */ - Byte *outbuf; /* output buffer */ - uLong crc; /* crc32 of uncompressed data */ - char *msg; /* error message */ - char *path; /* path name for debugging only */ - int transparent; /* 1 if input file is not a .gz file */ - char mode; /* 'w' or 'r' */ - z_off_t start; /* start of compressed data in file (header skipped) */ - z_off_t in; /* bytes into deflate or inflate */ - z_off_t out; /* bytes out of deflate or inflate */ - int back; /* one character push-back */ - int last; /* true if push-back is last character */ -} gz_stream; - - -local gzFile gz_open OF((const char *path, const char *mode, int fd)); -local int do_flush OF((gzFile file, int flush)); -local int get_byte OF((gz_stream *s)); -local void check_header OF((gz_stream *s)); -local int destroy OF((gz_stream *s)); -local void putLong OF((FILE *file, uLong x)); -local uLong getLong OF((gz_stream *s)); - -/* =========================================================================== - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb"). The file is given either by file descriptor - or path name (if fd == -1). - gz_open returns NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). -*/ -local gzFile gz_open (path, mode, fd) - const char *path; - const char *mode; - int fd; -{ - int err; - int level = Z_BEST_SPEED; /* compression level */ - int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ - char *p = (char*)mode; - gz_stream *s; - char fmode[80]; /* copy of mode, without the compression level */ - char *m = fmode; - - if (!path || !mode) return Z_NULL; - - s = (gz_stream *)ALLOC(sizeof(gz_stream)); - if (!s) return Z_NULL; - - s->stream.zalloc = (alloc_func)0; - s->stream.zfree = (free_func)0; - s->stream.opaque = (voidpf)0; - s->stream.next_in = s->inbuf = Z_NULL; - s->stream.next_out = s->outbuf = Z_NULL; - s->stream.avail_in = s->stream.avail_out = 0; - s->file = NULL; - s->z_err = Z_OK; - s->z_eof = 0; - s->in = 0; - s->out = 0; - s->back = EOF; - s->crc = crc32(0L, Z_NULL, 0); - s->msg = NULL; - s->transparent = 0; - - s->path = (char*)ALLOC(strlen(path)+1); - if (s->path == NULL) { - return destroy(s), (gzFile)Z_NULL; - } - strcpy(s->path, path); /* do this early for debugging */ - - s->mode = '\0'; - do { - if (*p == 'r') s->mode = 'r'; - if (*p == 'w' || *p == 'a') s->mode = 'w'; - if (*p >= '0' && *p <= '9') { - level = *p - '0'; - } else if (*p == 'f') { - strategy = Z_FILTERED; - } else if (*p == 'h') { - strategy = Z_HUFFMAN_ONLY; - } else if (*p == 'R') { - strategy = Z_RLE; - } else { - *m++ = *p; /* copy the mode */ - } - } while (*p++ && m != fmode + sizeof(fmode)); - if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - err = Z_STREAM_ERROR; -#else - err = deflateInit2(&(s->stream), level, - Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); - /* windowBits is passed < 0 to suppress zlib header */ - - s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); -#endif - if (err != Z_OK || s->outbuf == Z_NULL) { - return destroy(s), (gzFile)Z_NULL; - } - } else { - s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); - - err = inflateInit2(&(s->stream), -MAX_WBITS); - /* windowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are - * present after the compressed stream. - */ - if (err != Z_OK || s->inbuf == Z_NULL) { - return destroy(s), (gzFile)Z_NULL; - } - } - s->stream.avail_out = Z_BUFSIZE; - - errno = 0; - s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); - - if (s->file == NULL) { - return destroy(s), (gzFile)Z_NULL; - } - if (s->mode == 'w') { - /* Write a very simple .gz header: - */ - fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], - Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); - s->start = 10L; - /* We use 10L instead of ftell(s->file) to because ftell causes an - * fflush on some systems. This version of the library doesn't use - * start anyway in write mode, so this initialization is not - * necessary. - */ - } else { - check_header(s); /* skip the .gz header */ - s->start = ftell(s->file) - s->stream.avail_in; - } - - return (gzFile)s; -} - -/* =========================================================================== - Opens a gzip (.gz) file for reading or writing. -*/ -gzFile ZEXPORT gzopen (path, mode) - const char *path; - const char *mode; -{ - return gz_open (path, mode, -1); -} - -/* =========================================================================== - Associate a gzFile with the file descriptor fd. fd is not dup'ed here - to mimic the behavio(u)r of fdopen. -*/ -gzFile ZEXPORT gzdopen (fd, mode) - int fd; - const char *mode; -{ - char name[46]; /* allow for up to 128-bit integers */ - - if (fd < 0) return (gzFile)Z_NULL; - sprintf(name, "", fd); /* for debugging */ - - return gz_open (name, mode, fd); -} - -/* =========================================================================== - * Update the compression level and strategy - */ -int ZEXPORT gzsetparams (file, level, strategy) - gzFile file; - int level; - int strategy; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - /* Make room to allow flushing */ - if (s->stream.avail_out == 0) { - - s->stream.next_out = s->outbuf; - if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { - s->z_err = Z_ERRNO; - } - s->stream.avail_out = Z_BUFSIZE; - } - - return deflateParams (&(s->stream), level, strategy); -} - -/* =========================================================================== - Read a byte from a gz_stream; update next_in and avail_in. Return EOF - for end of file. - IN assertion: the stream s has been sucessfully opened for reading. -*/ -local int get_byte(s) - gz_stream *s; -{ - if (s->z_eof) return EOF; - if (s->stream.avail_in == 0) { - errno = 0; - s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); - if (s->stream.avail_in == 0) { - s->z_eof = 1; - if (ferror(s->file)) s->z_err = Z_ERRNO; - return EOF; - } - s->stream.next_in = s->inbuf; - } - s->stream.avail_in--; - return *(s->stream.next_in)++; -} - -/* =========================================================================== - Check the gzip header of a gz_stream opened for reading. Set the stream - mode to transparent if the gzip magic header is not present; set s->err - to Z_DATA_ERROR if the magic header is present but the rest of the header - is incorrect. - IN assertion: the stream s has already been created sucessfully; - s->stream.avail_in is zero for the first time, but may be non-zero - for concatenated .gz files. -*/ -local void check_header(s) - gz_stream *s; -{ - int method; /* method byte */ - int flags; /* flags byte */ - uInt len; - int c; - - /* Assure two bytes in the buffer so we can peek ahead -- handle case - where first byte of header is at the end of the buffer after the last - gzip segment */ - len = s->stream.avail_in; - if (len < 2) { - if (len) s->inbuf[0] = s->stream.next_in[0]; - errno = 0; - len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); - if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; - s->stream.avail_in += len; - s->stream.next_in = s->inbuf; - if (s->stream.avail_in < 2) { - s->transparent = s->stream.avail_in; - return; - } - } - - /* Peek ahead to check the gzip magic header */ - if (s->stream.next_in[0] != gz_magic[0] || - s->stream.next_in[1] != gz_magic[1]) { - s->transparent = 1; - return; - } - s->stream.avail_in -= 2; - s->stream.next_in += 2; - - /* Check the rest of the gzip header */ - method = get_byte(s); - flags = get_byte(s); - if (method != Z_DEFLATED || (flags & RESERVED) != 0) { - s->z_err = Z_DATA_ERROR; - return; - } - - /* Discard time, xflags and OS code: */ - for (len = 0; len < 6; len++) (void)get_byte(s); - - if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ - len = (uInt)get_byte(s); - len += ((uInt)get_byte(s))<<8; - /* len is garbage if EOF but the loop below will quit anyway */ - while (len-- != 0 && get_byte(s) != EOF) ; - } - if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ - while ((c = get_byte(s)) != 0 && c != EOF) ; - } - if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ - while ((c = get_byte(s)) != 0 && c != EOF) ; - } - if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ - for (len = 0; len < 2; len++) (void)get_byte(s); - } - s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; -} - - /* =========================================================================== - * Cleanup then free the given gz_stream. Return a zlib error code. - Try freeing in the reverse order of allocations. - */ -local int destroy (s) - gz_stream *s; -{ - int err = Z_OK; - - if (!s) return Z_STREAM_ERROR; - - TRYFREE(s->msg); - - if (s->stream.state != NULL) { - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - err = Z_STREAM_ERROR; -#else - err = deflateEnd(&(s->stream)); -#endif - } else if (s->mode == 'r') { - err = inflateEnd(&(s->stream)); - } - } - if (s->file != NULL && fclose(s->file)) { -#ifdef ESPIPE - if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ -#endif - err = Z_ERRNO; - } - if (s->z_err < 0) err = s->z_err; - - TRYFREE(s->inbuf); - TRYFREE(s->outbuf); - TRYFREE(s->path); - TRYFREE(s); - return err; -} - -/* =========================================================================== - Reads the given number of uncompressed bytes from the compressed file. - gzread returns the number of bytes actually read (0 for end of file). -*/ -int ZEXPORT gzread (file, buf, len) - gzFile file; - voidp buf; - unsigned len; -{ - gz_stream *s = (gz_stream*)file; - Bytef *start = (Bytef*)buf; /* starting point for crc computation */ - Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ - - if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; - - if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; - if (s->z_err == Z_STREAM_END) return 0; /* EOF */ - - next_out = (Byte*)buf; - s->stream.next_out = (Bytef*)buf; - s->stream.avail_out = len; - - if (s->stream.avail_out && s->back != EOF) { - *next_out++ = s->back; - s->stream.next_out++; - s->stream.avail_out--; - s->back = EOF; - s->out++; - start++; - if (s->last) { - s->z_err = Z_STREAM_END; - return 1; - } - } - - while (s->stream.avail_out != 0) { - - if (s->transparent) { - /* Copy first the lookahead bytes: */ - uInt n = s->stream.avail_in; - if (n > s->stream.avail_out) n = s->stream.avail_out; - if (n > 0) { - zmemcpy(s->stream.next_out, s->stream.next_in, n); - next_out += n; - s->stream.next_out = next_out; - s->stream.next_in += n; - s->stream.avail_out -= n; - s->stream.avail_in -= n; - } - if (s->stream.avail_out > 0) { - s->stream.avail_out -= - (uInt)fread(next_out, 1, s->stream.avail_out, s->file); - } - len -= s->stream.avail_out; - s->in += len; - s->out += len; - if (len == 0) s->z_eof = 1; - return (int)len; - } - if (s->stream.avail_in == 0 && !s->z_eof) { - - errno = 0; - s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); - if (s->stream.avail_in == 0) { - s->z_eof = 1; - if (ferror(s->file)) { - s->z_err = Z_ERRNO; - break; - } - } - s->stream.next_in = s->inbuf; - } - s->in += s->stream.avail_in; - s->out += s->stream.avail_out; - s->z_err = inflate(&(s->stream), Z_NO_FLUSH); - s->in -= s->stream.avail_in; - s->out -= s->stream.avail_out; - - if (s->z_err == Z_STREAM_END) { - /* Check CRC and original size */ - s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); - start = s->stream.next_out; - - if (getLong(s) != s->crc) { - s->z_err = Z_DATA_ERROR; - } else { - (void)getLong(s); - /* The uncompressed length returned by above getlong() may be - * different from s->out in case of concatenated .gz files. - * Check for such files: - */ - check_header(s); - if (s->z_err == Z_OK) { - inflateReset(&(s->stream)); - s->crc = crc32(0L, Z_NULL, 0); - } - } - } - if (s->z_err != Z_OK || s->z_eof) break; - } - s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); - - if (len == s->stream.avail_out && - (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) - return -1; - return (int)(len - s->stream.avail_out); -} - - -/* =========================================================================== - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. -*/ -int ZEXPORT gzgetc(file) - gzFile file; -{ - unsigned char c; - - return gzread(file, &c, 1) == 1 ? c : -1; -} - - -/* =========================================================================== - Push one byte back onto the stream. -*/ -int ZEXPORT gzungetc(c, file) - int c; - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; - s->back = c; - s->out--; - s->last = (s->z_err == Z_STREAM_END); - if (s->last) s->z_err = Z_OK; - s->z_eof = 0; - return c; -} - - -/* =========================================================================== - Reads bytes from the compressed file until len-1 characters are - read, or a newline character is read and transferred to buf, or an - end-of-file condition is encountered. The string is then terminated - with a null character. - gzgets returns buf, or Z_NULL in case of error. - - The current implementation is not optimized at all. -*/ -char * ZEXPORT gzgets(file, buf, len) - gzFile file; - char *buf; - int len; -{ - char *b = buf; - if (buf == Z_NULL || len <= 0) return Z_NULL; - - while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; - *buf = '\0'; - return b == buf && len > 0 ? Z_NULL : b; -} - - -#ifndef NO_GZCOMPRESS -/* =========================================================================== - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of bytes actually written (0 in case of error). -*/ -int ZEXPORT gzwrite (file, buf, len) - gzFile file; - voidpc buf; - unsigned len; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - s->stream.next_in = (Bytef*)buf; - s->stream.avail_in = len; - - while (s->stream.avail_in != 0) { - - if (s->stream.avail_out == 0) { - - s->stream.next_out = s->outbuf; - if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { - s->z_err = Z_ERRNO; - break; - } - s->stream.avail_out = Z_BUFSIZE; - } - s->in += s->stream.avail_in; - s->out += s->stream.avail_out; - s->z_err = deflate(&(s->stream), Z_NO_FLUSH); - s->in -= s->stream.avail_in; - s->out -= s->stream.avail_out; - if (s->z_err != Z_OK) break; - } - s->crc = crc32(s->crc, (const Bytef *)buf, len); - - return (int)(len - s->stream.avail_in); -} - - -/* =========================================================================== - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). -*/ -#ifdef STDC -#include - -int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) -{ - char buf[Z_PRINTF_BUFSIZE]; - va_list va; - int len; - - buf[sizeof(buf) - 1] = 0; - va_start(va, format); -#ifdef NO_vsnprintf -# ifdef HAS_vsprintf_void - (void)vsprintf(buf, format, va); - va_end(va); - for (len = 0; len < sizeof(buf); len++) - if (buf[len] == 0) break; -# else - len = vsprintf(buf, format, va); - va_end(va); -# endif -#else -# ifdef HAS_vsnprintf_void - (void)vsnprintf(buf, sizeof(buf), format, va); - va_end(va); - len = strlen(buf); -# else - len = vsnprintf(buf, sizeof(buf), format, va); - va_end(va); -# endif -#endif - if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) - return 0; - return gzwrite(file, buf, (unsigned)len); -} -#else /* not ANSI C */ - -int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) - gzFile file; - const char *format; - int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; -{ - char buf[Z_PRINTF_BUFSIZE]; - int len; - - buf[sizeof(buf) - 1] = 0; -#ifdef NO_snprintf -# ifdef HAS_sprintf_void - sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); - for (len = 0; len < sizeof(buf); len++) - if (buf[len] == 0) break; -# else - len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); -# endif -#else -# ifdef HAS_snprintf_void - snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); - len = strlen(buf); -# else - len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); -# endif -#endif - if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) - return 0; - return gzwrite(file, buf, len); -} -#endif - -/* =========================================================================== - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. -*/ -int ZEXPORT gzputc(file, c) - gzFile file; - int c; -{ - unsigned char cc = (unsigned char) c; /* required for big endian systems */ - - return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; -} - - -/* =========================================================================== - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. -*/ -int ZEXPORT gzputs(file, s) - gzFile file; - const char *s; -{ - return gzwrite(file, (char*)s, (unsigned)strlen(s)); -} - - -/* =========================================================================== - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. -*/ -local int do_flush (file, flush) - gzFile file; - int flush; -{ - uInt len; - int done = 0; - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - s->stream.avail_in = 0; /* should be zero already anyway */ - - for (;;) { - len = Z_BUFSIZE - s->stream.avail_out; - - if (len != 0) { - if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { - s->z_err = Z_ERRNO; - return Z_ERRNO; - } - s->stream.next_out = s->outbuf; - s->stream.avail_out = Z_BUFSIZE; - } - if (done) break; - s->out += s->stream.avail_out; - s->z_err = deflate(&(s->stream), flush); - s->out -= s->stream.avail_out; - - /* Ignore the second of two consecutive flushes: */ - if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; - - /* deflate has finished flushing only when it hasn't used up - * all the available space in the output buffer: - */ - done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); - - if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; - } - return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; -} - -int ZEXPORT gzflush (file, flush) - gzFile file; - int flush; -{ - gz_stream *s = (gz_stream*)file; - int err = do_flush (file, flush); - - if (err) return err; - fflush(s->file); - return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; -} -#endif /* NO_GZCOMPRESS */ - -/* =========================================================================== - Sets the starting position for the next gzread or gzwrite on the given - compressed file. The offset represents a number of bytes in the - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error. - SEEK_END is not implemented, returns error. - In this version of the library, gzseek can be extremely slow. -*/ -z_off_t ZEXPORT gzseek (file, offset, whence) - gzFile file; - z_off_t offset; - int whence; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || whence == SEEK_END || - s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { - return -1L; - } - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - return -1L; -#else - if (whence == SEEK_SET) { - offset -= s->in; - } - if (offset < 0) return -1L; - - /* At this point, offset is the number of zero bytes to write. */ - if (s->inbuf == Z_NULL) { - s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ - if (s->inbuf == Z_NULL) return -1L; - zmemzero(s->inbuf, Z_BUFSIZE); - } - while (offset > 0) { - uInt size = Z_BUFSIZE; - if (offset < Z_BUFSIZE) size = (uInt)offset; - - size = gzwrite(file, s->inbuf, size); - if (size == 0) return -1L; - - offset -= size; - } - return s->in; -#endif - } - /* Rest of function is for reading only */ - - /* compute absolute position */ - if (whence == SEEK_CUR) { - offset += s->out; - } - if (offset < 0) return -1L; - - if (s->transparent) { - /* map to fseek */ - s->back = EOF; - s->stream.avail_in = 0; - s->stream.next_in = s->inbuf; - if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; - - s->in = s->out = offset; - return offset; - } - - /* For a negative seek, rewind and use positive seek */ - if (offset >= s->out) { - offset -= s->out; - } else if (gzrewind(file) < 0) { - return -1L; - } - /* offset is now the number of bytes to skip. */ - - if (offset != 0 && s->outbuf == Z_NULL) { - s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); - if (s->outbuf == Z_NULL) return -1L; - } - if (offset && s->back != EOF) { - s->back = EOF; - s->out++; - offset--; - if (s->last) s->z_err = Z_STREAM_END; - } - while (offset > 0) { - int size = Z_BUFSIZE; - if (offset < Z_BUFSIZE) size = (int)offset; - - size = gzread(file, s->outbuf, (uInt)size); - if (size <= 0) return -1L; - offset -= size; - } - return s->out; -} - -/* =========================================================================== - Rewinds input file. -*/ -int ZEXPORT gzrewind (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'r') return -1; - - s->z_err = Z_OK; - s->z_eof = 0; - s->back = EOF; - s->stream.avail_in = 0; - s->stream.next_in = s->inbuf; - s->crc = crc32(0L, Z_NULL, 0); - if (!s->transparent) (void)inflateReset(&s->stream); - s->in = 0; - s->out = 0; - return fseek(s->file, s->start, SEEK_SET); -} - -/* =========================================================================== - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. -*/ -z_off_t ZEXPORT gztell (file) - gzFile file; -{ - return gzseek(file, 0L, SEEK_CUR); -} - -/* =========================================================================== - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. -*/ -int ZEXPORT gzeof (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - /* With concatenated compressed files that can have embedded - * crc trailers, z_eof is no longer the only/best indicator of EOF - * on a gz_stream. Handle end-of-stream error explicitly here. - */ - if (s == NULL || s->mode != 'r') return 0; - if (s->z_eof) return 1; - return s->z_err == Z_STREAM_END; -} - -/* =========================================================================== - Returns 1 if reading and doing so transparently, otherwise zero. -*/ -int ZEXPORT gzdirect (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'r') return 0; - return s->transparent; -} - -/* =========================================================================== - Outputs a long in LSB order to the given file -*/ -local void putLong (file, x) - FILE *file; - uLong x; -{ - int n; - for (n = 0; n < 4; n++) { - fputc((int)(x & 0xff), file); - x >>= 8; - } -} - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets z_err in case - of error. -*/ -local uLong getLong (s) - gz_stream *s; -{ - uLong x = (uLong)get_byte(s); - int c; - - x += ((uLong)get_byte(s))<<8; - x += ((uLong)get_byte(s))<<16; - c = get_byte(s); - if (c == EOF) s->z_err = Z_DATA_ERROR; - x += ((uLong)c)<<24; - return x; -} - -/* =========================================================================== - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. -*/ -int ZEXPORT gzclose (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL) return Z_STREAM_ERROR; - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - return Z_STREAM_ERROR; -#else - if (do_flush (file, Z_FINISH) != Z_OK) - return destroy((gz_stream*)file); - - putLong (s->file, s->crc); - putLong (s->file, (uLong)(s->in & 0xffffffff)); -#endif - } - return destroy((gz_stream*)file); -} - -#ifdef STDC -# define zstrerror(errnum) strerror(errnum) -#else -# define zstrerror(errnum) "" -#endif - -/* =========================================================================== - Returns the error message for the last error which occurred on the - given compressed file. errnum is set to zlib error number. If an - error occurred in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. -*/ -const char * ZEXPORT gzerror (file, errnum) - gzFile file; - int *errnum; -{ - char *m; - gz_stream *s = (gz_stream*)file; - - if (s == NULL) { - *errnum = Z_STREAM_ERROR; - return (const char*)ERR_MSG(Z_STREAM_ERROR); - } - *errnum = s->z_err; - if (*errnum == Z_OK) return (const char*)""; - - m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); - - if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); - - TRYFREE(s->msg); - s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); - if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); - strcpy(s->msg, s->path); - strcat(s->msg, ": "); - strcat(s->msg, m); - return (const char*)s->msg; -} - -/* =========================================================================== - Clear the error and end-of-file flags, and do the same for the real file. -*/ -void ZEXPORT gzclearerr (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL) return; - if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; - s->z_eof = 0; - clearerr(s->file); -} +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id$ */ + +#include + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_BEST_SPEED; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[46]; /* allow for up to 128-bit integers */ + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + start++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= + (uInt)fread(next_out, 1, s->stream.avail_out, s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + if (len == s->stream.avail_out && + (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) + return -1; + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Returns 1 if reading and doing so transparently, otherwise zero. +*/ +int ZEXPORT gzdirect (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return 0; + return s->transparent; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + if (do_flush (file, Z_FINISH) != Z_OK) + return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +#ifdef STDC +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +/* =========================================================================== + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/3rdparty/zlib/infback.c b/3rdparty/zlib/infback.c index 1e03e1bab0..455dbc9ee8 100644 --- a/3rdparty/zlib/infback.c +++ b/3rdparty/zlib/infback.c @@ -1,623 +1,623 @@ -/* infback.c -- inflate using a call-back interface - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - This code is largely copied from inflate.c. Normally either infback.o or - inflate.o would be linked into an application--not both. The interface - with inffast.c is retained so that optimized assembler-coded versions of - inflate_fast() can be used with either inflate.c or infback.c. - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -/* function prototypes */ -local void fixedtables OF((struct inflate_state FAR *state)); - -/* - strm provides memory allocation functions in zalloc and zfree, or - Z_NULL to use the library memory allocation functions. - - windowBits is in the range 8..15, and window is a user-supplied - window and output buffer that is 2**windowBits bytes. - */ -int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) -z_streamp strm; -int windowBits; -unsigned char FAR *window; -const char *version; -int stream_size; -{ - struct inflate_state FAR *state; - - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != (int)(sizeof(z_stream))) - return Z_VERSION_ERROR; - if (strm == Z_NULL || window == Z_NULL || - windowBits < 8 || windowBits > 15) - return Z_STREAM_ERROR; - strm->msg = Z_NULL; /* in case we return an error */ - if (strm->zalloc == (alloc_func)0) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; - state = (struct inflate_state FAR *)ZALLOC(strm, 1, - sizeof(struct inflate_state)); - if (state == Z_NULL) return Z_MEM_ERROR; - Tracev((stderr, "inflate: allocated\n")); - strm->state = (struct internal_state FAR *)state; - state->dmax = 32768U; - state->wbits = windowBits; - state->wsize = 1U << windowBits; - state->window = window; - state->write = 0; - state->whave = 0; - return Z_OK; -} - -/* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ -#ifdef BUILDFIXED - static int virgin = 1; - static code *lenfix, *distfix; - static code fixed[544]; - - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - unsigned sym, bits; - static code *next; - - /* literal/length table */ - sym = 0; - while (sym < 144) state->lens[sym++] = 8; - while (sym < 256) state->lens[sym++] = 9; - while (sym < 280) state->lens[sym++] = 7; - while (sym < 288) state->lens[sym++] = 8; - next = fixed; - lenfix = next; - bits = 9; - inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); - - /* distance table */ - sym = 0; - while (sym < 32) state->lens[sym++] = 5; - distfix = next; - bits = 5; - inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); - - /* do this just once */ - virgin = 0; - } -#else /* !BUILDFIXED */ -# include "inffixed.h" -#endif /* BUILDFIXED */ - state->lencode = lenfix; - state->lenbits = 9; - state->distcode = distfix; - state->distbits = 5; -} - -/* Macros for inflateBack(): */ - -/* Load returned state from inflate_fast() */ -#define LOAD() \ - do { \ - put = strm->next_out; \ - left = strm->avail_out; \ - next = strm->next_in; \ - have = strm->avail_in; \ - hold = state->hold; \ - bits = state->bits; \ - } while (0) - -/* Set state from registers for inflate_fast() */ -#define RESTORE() \ - do { \ - strm->next_out = put; \ - strm->avail_out = left; \ - strm->next_in = next; \ - strm->avail_in = have; \ - state->hold = hold; \ - state->bits = bits; \ - } while (0) - -/* Clear the input bit accumulator */ -#define INITBITS() \ - do { \ - hold = 0; \ - bits = 0; \ - } while (0) - -/* Assure that some input is available. If input is requested, but denied, - then return a Z_BUF_ERROR from inflateBack(). */ -#define PULL() \ - do { \ - if (have == 0) { \ - have = in(in_desc, &next); \ - if (have == 0) { \ - next = Z_NULL; \ - ret = Z_BUF_ERROR; \ - goto inf_leave; \ - } \ - } \ - } while (0) - -/* Get a byte of input into the bit accumulator, or return from inflateBack() - with an error if there is no input available. */ -#define PULLBYTE() \ - do { \ - PULL(); \ - have--; \ - hold += (unsigned long)(*next++) << bits; \ - bits += 8; \ - } while (0) - -/* Assure that there are at least n bits in the bit accumulator. If there is - not enough available input to do that, then return from inflateBack() with - an error. */ -#define NEEDBITS(n) \ - do { \ - while (bits < (unsigned)(n)) \ - PULLBYTE(); \ - } while (0) - -/* Return the low n bits of the bit accumulator (n < 16) */ -#define BITS(n) \ - ((unsigned)hold & ((1U << (n)) - 1)) - -/* Remove n bits from the bit accumulator */ -#define DROPBITS(n) \ - do { \ - hold >>= (n); \ - bits -= (unsigned)(n); \ - } while (0) - -/* Remove zero to seven bits as needed to go to a byte boundary */ -#define BYTEBITS() \ - do { \ - hold >>= bits & 7; \ - bits -= bits & 7; \ - } while (0) - -/* Assure that some output space is available, by writing out the window - if it's full. If the write fails, return from inflateBack() with a - Z_BUF_ERROR. */ -#define ROOM() \ - do { \ - if (left == 0) { \ - put = state->window; \ - left = state->wsize; \ - state->whave = left; \ - if (out(out_desc, put, left)) { \ - ret = Z_BUF_ERROR; \ - goto inf_leave; \ - } \ - } \ - } while (0) - -/* - strm provides the memory allocation functions and window buffer on input, - and provides information on the unused input on return. For Z_DATA_ERROR - returns, strm will also provide an error message. - - in() and out() are the call-back input and output functions. When - inflateBack() needs more input, it calls in(). When inflateBack() has - filled the window with output, or when it completes with data in the - window, it calls out() to write out the data. The application must not - change the provided input until in() is called again or inflateBack() - returns. The application must not change the window/output buffer until - inflateBack() returns. - - in() and out() are called with a descriptor parameter provided in the - inflateBack() call. This parameter can be a structure that provides the - information required to do the read or write, as well as accumulated - information on the input and output such as totals and check values. - - in() should return zero on failure. out() should return non-zero on - failure. If either in() or out() fails, than inflateBack() returns a - Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it - was in() or out() that caused in the error. Otherwise, inflateBack() - returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format - error, or Z_MEM_ERROR if it could not allocate memory for the state. - inflateBack() can also return Z_STREAM_ERROR if the input parameters - are not correct, i.e. strm is Z_NULL or the state was not initialized. - */ -int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) -z_streamp strm; -in_func in; -void FAR *in_desc; -out_func out; -void FAR *out_desc; -{ - struct inflate_state FAR *state; - unsigned char FAR *next; /* next input */ - unsigned char FAR *put; /* next output */ - unsigned have, left; /* available input and output */ - unsigned long hold; /* bit buffer */ - unsigned bits; /* bits in bit buffer */ - unsigned copy; /* number of stored or match bytes to copy */ - unsigned char FAR *from; /* where to copy match bytes from */ - code this; /* current decoding table entry */ - code last; /* parent table entry */ - unsigned len; /* length to copy for repeats, bits to drop */ - int ret; /* return code */ - static const unsigned short order[19] = /* permutation of code lengths */ - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - /* Check that the strm exists and that the state was initialized */ - if (strm == Z_NULL || strm->state == Z_NULL) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - - /* Reset the state */ - strm->msg = Z_NULL; - state->mode = TYPE; - state->last = 0; - state->whave = 0; - next = strm->next_in; - have = next != Z_NULL ? strm->avail_in : 0; - hold = 0; - bits = 0; - put = state->window; - left = state->wsize; - - /* Inflate until end of block marked as last */ - for (;;) - switch (state->mode) { - case TYPE: - /* determine and dispatch block type */ - if (state->last) { - BYTEBITS(); - state->mode = DONE; - break; - } - NEEDBITS(3); - state->last = BITS(1); - DROPBITS(1); - switch (BITS(2)) { - case 0: /* stored block */ - Tracev((stderr, "inflate: stored block%s\n", - state->last ? " (last)" : "")); - state->mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - Tracev((stderr, "inflate: fixed codes block%s\n", - state->last ? " (last)" : "")); - state->mode = LEN; /* decode codes */ - break; - case 2: /* dynamic block */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - state->last ? " (last)" : "")); - state->mode = TABLE; - break; - case 3: - strm->msg = (char *)"invalid block type"; - state->mode = BAD; - } - DROPBITS(2); - break; - - case STORED: - /* get and verify stored block length */ - BYTEBITS(); /* go to byte boundary */ - NEEDBITS(32); - if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - strm->msg = (char *)"invalid stored block lengths"; - state->mode = BAD; - break; - } - state->length = (unsigned)hold & 0xffff; - Tracev((stderr, "inflate: stored length %u\n", - state->length)); - INITBITS(); - - /* copy stored block from input to output */ - while (state->length != 0) { - copy = state->length; - PULL(); - ROOM(); - if (copy > have) copy = have; - if (copy > left) copy = left; - zmemcpy(put, next, copy); - have -= copy; - next += copy; - left -= copy; - put += copy; - state->length -= copy; - } - Tracev((stderr, "inflate: stored end\n")); - state->mode = TYPE; - break; - - case TABLE: - /* get dynamic table entries descriptor */ - NEEDBITS(14); - state->nlen = BITS(5) + 257; - DROPBITS(5); - state->ndist = BITS(5) + 1; - DROPBITS(5); - state->ncode = BITS(4) + 4; - DROPBITS(4); -#ifndef PKZIP_BUG_WORKAROUND - if (state->nlen > 286 || state->ndist > 30) { - strm->msg = (char *)"too many length or distance symbols"; - state->mode = BAD; - break; - } -#endif - Tracev((stderr, "inflate: table sizes ok\n")); - - /* get code length code lengths (not a typo) */ - state->have = 0; - while (state->have < state->ncode) { - NEEDBITS(3); - state->lens[order[state->have++]] = (unsigned short)BITS(3); - DROPBITS(3); - } - while (state->have < 19) - state->lens[order[state->have++]] = 0; - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 7; - ret = inflate_table(CODES, state->lens, 19, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid code lengths set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: code lengths ok\n")); - - /* get length and distance code code lengths */ - state->have = 0; - while (state->have < state->nlen + state->ndist) { - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.val < 16) { - NEEDBITS(this.bits); - DROPBITS(this.bits); - state->lens[state->have++] = this.val; - } - else { - if (this.val == 16) { - NEEDBITS(this.bits + 2); - DROPBITS(this.bits); - if (state->have == 0) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - len = (unsigned)(state->lens[state->have - 1]); - copy = 3 + BITS(2); - DROPBITS(2); - } - else if (this.val == 17) { - NEEDBITS(this.bits + 3); - DROPBITS(this.bits); - len = 0; - copy = 3 + BITS(3); - DROPBITS(3); - } - else { - NEEDBITS(this.bits + 7); - DROPBITS(this.bits); - len = 0; - copy = 11 + BITS(7); - DROPBITS(7); - } - if (state->have + copy > state->nlen + state->ndist) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - while (copy--) - state->lens[state->have++] = (unsigned short)len; - } - } - - /* handle error breaks in while */ - if (state->mode == BAD) break; - - /* build code tables */ - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 9; - ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid literal/lengths set"; - state->mode = BAD; - break; - } - state->distcode = (code const FAR *)(state->next); - state->distbits = 6; - ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, - &(state->next), &(state->distbits), state->work); - if (ret) { - strm->msg = (char *)"invalid distances set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: codes ok\n")); - state->mode = LEN; - - case LEN: - /* use inflate_fast() if we have enough input and output */ - if (have >= 6 && left >= 258) { - RESTORE(); - if (state->whave < state->wsize) - state->whave = state->wsize - left; - inflate_fast(strm, state->wsize); - LOAD(); - break; - } - - /* get a literal, length, or end-of-block code */ - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.op && (this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->lencode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - state->length = (unsigned)this.val; - - /* process literal */ - if (this.op == 0) { - Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", this.val)); - ROOM(); - *put++ = (unsigned char)(state->length); - left--; - state->mode = LEN; - break; - } - - /* process end of block */ - if (this.op & 32) { - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - - /* invalid code */ - if (this.op & 64) { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - - /* length code -- get extra bits, if any */ - state->extra = (unsigned)(this.op) & 15; - if (state->extra != 0) { - NEEDBITS(state->extra); - state->length += BITS(state->extra); - DROPBITS(state->extra); - } - Tracevv((stderr, "inflate: length %u\n", state->length)); - - /* get distance code */ - for (;;) { - this = state->distcode[BITS(state->distbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if ((this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->distcode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - if (this.op & 64) { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - state->offset = (unsigned)this.val; - - /* get distance extra bits, if any */ - state->extra = (unsigned)(this.op) & 15; - if (state->extra != 0) { - NEEDBITS(state->extra); - state->offset += BITS(state->extra); - DROPBITS(state->extra); - } - if (state->offset > state->wsize - (state->whave < state->wsize ? - left : 0)) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - Tracevv((stderr, "inflate: distance %u\n", state->offset)); - - /* copy match from window to output */ - do { - ROOM(); - copy = state->wsize - state->offset; - if (copy < left) { - from = put + copy; - copy = left - copy; - } - else { - from = put - state->offset; - copy = left; - } - if (copy > state->length) copy = state->length; - state->length -= copy; - left -= copy; - do { - *put++ = *from++; - } while (--copy); - } while (state->length != 0); - break; - - case DONE: - /* inflate stream terminated properly -- write leftover output */ - ret = Z_STREAM_END; - if (left < state->wsize) { - if (out(out_desc, state->window, state->wsize - left)) - ret = Z_BUF_ERROR; - } - goto inf_leave; - - case BAD: - ret = Z_DATA_ERROR; - goto inf_leave; - - default: /* can't happen, but makes compilers happy */ - ret = Z_STREAM_ERROR; - goto inf_leave; - } - - /* Return unused input */ - inf_leave: - strm->next_in = next; - strm->avail_in = have; - return ret; -} - -int ZEXPORT inflateBackEnd(strm) -z_streamp strm; -{ - if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) - return Z_STREAM_ERROR; - ZFREE(strm, strm->state); - strm->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; -} +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/3rdparty/zlib/inffast.c b/3rdparty/zlib/inffast.c index fa31cad905..bbee92ed1e 100644 --- a/3rdparty/zlib/inffast.c +++ b/3rdparty/zlib/inffast.c @@ -1,318 +1,318 @@ -/* inffast.c -- fast decoding - * Copyright (C) 1995-2004 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -#ifndef ASMINF - -/* Allow machine dependent optimization for post-increment or pre-increment. - Based on testing to date, - Pre-increment preferred for: - - PowerPC G3 (Adler) - - MIPS R5000 (Randers-Pehrson) - Post-increment preferred for: - - none - No measurable difference: - - Pentium III (Anderson) - - M68060 (Nikl) - */ -#ifdef POSTINC -# define OFF 0 -# define PUP(a) *(a)++ -#else -# define OFF 1 -# define PUP(a) *++(a) -#endif - -/* - Decode literal, length, and distance codes and write out the resulting - literal and match bytes until either not enough input or output is - available, an end-of-block is encountered, or a data error is encountered. - When large enough input and output buffers are supplied to inflate(), for - example, a 16K input buffer and a 64K output buffer, more than 95% of the - inflate execution time is spent in this routine. - - Entry assumptions: - - state->mode == LEN - strm->avail_in >= 6 - strm->avail_out >= 258 - start >= strm->avail_out - state->bits < 8 - - On return, state->mode is one of: - - LEN -- ran out of enough output space or enough available input - TYPE -- reached end of block code, inflate() to interpret next block - BAD -- error in block data - - Notes: - - - The maximum input bits used by a length/distance pair is 15 bits for the - length code, 5 bits for the length extra, 15 bits for the distance code, - and 13 bits for the distance extra. This totals 48 bits, or six bytes. - Therefore if strm->avail_in >= 6, then there is enough input to avoid - checking for available input while decoding. - - - The maximum bytes that a single length/distance pair can output is 258 - bytes, which is the maximum length that can be coded. inflate_fast() - requires strm->avail_out >= 258 for each loop to avoid checking for - output space. - */ -void inflate_fast(strm, start) -z_streamp strm; -unsigned start; /* inflate()'s starting value for strm->avail_out */ -{ - struct inflate_state FAR *state; - unsigned char FAR *in; /* local strm->next_in */ - unsigned char FAR *last; /* while in < last, enough input available */ - unsigned char FAR *out; /* local strm->next_out */ - unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ - unsigned char FAR *end; /* while out < end, enough space available */ -#ifdef INFLATE_STRICT - unsigned dmax; /* maximum distance from zlib header */ -#endif - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned write; /* window write index */ - unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ - unsigned long hold; /* local strm->hold */ - unsigned bits; /* local strm->bits */ - code const FAR *lcode; /* local strm->lencode */ - code const FAR *dcode; /* local strm->distcode */ - unsigned lmask; /* mask for first level of length codes */ - unsigned dmask; /* mask for first level of distance codes */ - code this; /* retrieved table entry */ - unsigned op; /* code bits, operation, extra bits, or */ - /* window position, window bytes to copy */ - unsigned len; /* match length, unused bytes */ - unsigned dist; /* match distance */ - unsigned char FAR *from; /* where to copy match from */ - - /* copy state to local variables */ - state = (struct inflate_state FAR *)strm->state; - in = strm->next_in - OFF; - last = in + (strm->avail_in - 5); - out = strm->next_out - OFF; - beg = out - (start - strm->avail_out); - end = out + (strm->avail_out - 257); -#ifdef INFLATE_STRICT - dmax = state->dmax; -#endif - wsize = state->wsize; - whave = state->whave; - write = state->write; - window = state->window; - hold = state->hold; - bits = state->bits; - lcode = state->lencode; - dcode = state->distcode; - lmask = (1U << state->lenbits) - 1; - dmask = (1U << state->distbits) - 1; - - /* decode literals and length/distances until end-of-block or not enough - input data or output space */ - do { - if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - this = lcode[hold & lmask]; - dolen: - op = (unsigned)(this.bits); - hold >>= op; - bits -= op; - op = (unsigned)(this.op); - if (op == 0) { /* literal */ - Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", this.val)); - PUP(out) = (unsigned char)(this.val); - } - else if (op & 16) { /* length base */ - len = (unsigned)(this.val); - op &= 15; /* number of extra bits */ - if (op) { - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - len += (unsigned)hold & ((1U << op) - 1); - hold >>= op; - bits -= op; - } - Tracevv((stderr, "inflate: length %u\n", len)); - if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - this = dcode[hold & dmask]; - dodist: - op = (unsigned)(this.bits); - hold >>= op; - bits -= op; - op = (unsigned)(this.op); - if (op & 16) { /* distance base */ - dist = (unsigned)(this.val); - op &= 15; /* number of extra bits */ - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - } - dist += (unsigned)hold & ((1U << op) - 1); -#ifdef INFLATE_STRICT - if (dist > dmax) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#endif - hold >>= op; - bits -= op; - Tracevv((stderr, "inflate: distance %u\n", dist)); - op = (unsigned)(out - beg); /* max distance in output */ - if (dist > op) { /* see if copy from window */ - op = dist - op; /* distance back in window */ - if (op > whave) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - from = window - OFF; - if (write == 0) { /* very common case */ - from += wsize - op; - if (op < len) { /* some from window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - else if (write < op) { /* wrap around window */ - from += wsize + write - op; - op -= write; - if (op < len) { /* some from end of window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = window - OFF; - if (write < len) { /* some from start of window */ - op = write; - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - } - else { /* contiguous in window */ - from += write - op; - if (op < len) { /* some from window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - while (len > 2) { - PUP(out) = PUP(from); - PUP(out) = PUP(from); - PUP(out) = PUP(from); - len -= 3; - } - if (len) { - PUP(out) = PUP(from); - if (len > 1) - PUP(out) = PUP(from); - } - } - else { - from = out - dist; /* copy direct from output */ - do { /* minimum length is three */ - PUP(out) = PUP(from); - PUP(out) = PUP(from); - PUP(out) = PUP(from); - len -= 3; - } while (len > 2); - if (len) { - PUP(out) = PUP(from); - if (len > 1) - PUP(out) = PUP(from); - } - } - } - else if ((op & 64) == 0) { /* 2nd level distance code */ - this = dcode[this.val + (hold & ((1U << op) - 1))]; - goto dodist; - } - else { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - } - else if ((op & 64) == 0) { /* 2nd level length code */ - this = lcode[this.val + (hold & ((1U << op) - 1))]; - goto dolen; - } - else if (op & 32) { /* end-of-block */ - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - else { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - } while (in < last && out < end); - - /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ - len = bits >> 3; - in -= len; - bits -= len << 3; - hold &= (1U << bits) - 1; - - /* update state and return */ - strm->next_in = in + OFF; - strm->next_out = out + OFF; - strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); - strm->avail_out = (unsigned)(out < end ? - 257 + (end - out) : 257 - (out - end)); - state->hold = hold; - state->bits = bits; - return; -} - -/* - inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - - Using bit fields for code structure - - Different op definition to avoid & for extra bits (do & for table bits) - - Three separate decoding do-loops for direct, window, and write == 0 - - Special case for distance > 1 copies to do overlapped load and store copy - - Explicit branch predictions (based on measured branch probabilities) - - Deferring match copy and interspersed it with decoding subsequent codes - - Swapping literal/length else - - Swapping window/direct else - - Larger unrolled copy loops (three is about right) - - Moving len -= 3 statement into middle of loop - */ - -#endif /* !ASMINF */ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - M68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/3rdparty/zlib/inffast.h b/3rdparty/zlib/inffast.h index 614fa7877d..1e88d2d97b 100644 --- a/3rdparty/zlib/inffast.h +++ b/3rdparty/zlib/inffast.h @@ -1,11 +1,11 @@ -/* inffast.h -- header to use inffast.c - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -void inflate_fast OF((z_streamp strm, unsigned start)); +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/3rdparty/zlib/inffixed.h b/3rdparty/zlib/inffixed.h index 423d5c5b50..75ed4b5978 100644 --- a/3rdparty/zlib/inffixed.h +++ b/3rdparty/zlib/inffixed.h @@ -1,94 +1,94 @@ - /* inffixed.h -- table for decoding fixed codes - * Generated automatically by makefixed(). - */ - - /* WARNING: this file should *not* be used by applications. It - is part of the implementation of the compression library and - is subject to change. Applications should only use zlib.h. - */ - - static const code lenfix[512] = { - {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, - {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, - {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, - {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, - {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, - {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, - {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, - {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, - {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, - {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, - {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, - {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, - {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, - {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, - {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, - {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, - {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, - {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, - {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, - {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, - {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, - {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, - {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, - {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, - {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, - {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, - {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, - {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, - {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, - {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, - {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, - {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, - {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, - {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, - {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, - {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, - {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, - {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, - {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, - {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, - {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, - {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, - {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, - {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, - {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, - {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, - {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, - {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, - {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, - {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, - {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, - {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, - {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, - {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, - {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, - {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, - {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, - {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, - {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, - {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, - {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, - {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, - {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, - {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, - {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, - {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, - {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, - {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, - {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, - {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, - {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, - {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, - {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, - {0,9,255} - }; - - static const code distfix[32] = { - {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, - {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, - {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, - {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, - {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, - {22,5,193},{64,5,0} - }; + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/3rdparty/zlib/inflate.c b/3rdparty/zlib/inflate.c index 33ea902928..792fdee8e9 100644 --- a/3rdparty/zlib/inflate.c +++ b/3rdparty/zlib/inflate.c @@ -1,1368 +1,1368 @@ -/* inflate.c -- zlib decompression - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * Change history: - * - * 1.2.beta0 24 Nov 2002 - * - First version -- complete rewrite of inflate to simplify code, avoid - * creation of window when not needed, minimize use of window when it is - * needed, make inffast.c even faster, implement gzip decoding, and to - * improve code readability and style over the previous zlib inflate code - * - * 1.2.beta1 25 Nov 2002 - * - Use pointers for available input and output checking in inffast.c - * - Remove input and output counters in inffast.c - * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 - * - Remove unnecessary second byte pull from length extra in inffast.c - * - Unroll direct copy to three copies per loop in inffast.c - * - * 1.2.beta2 4 Dec 2002 - * - Change external routine names to reduce potential conflicts - * - Correct filename to inffixed.h for fixed tables in inflate.c - * - Make hbuf[] unsigned char to match parameter type in inflate.c - * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) - * to avoid negation problem on Alphas (64 bit) in inflate.c - * - * 1.2.beta3 22 Dec 2002 - * - Add comments on state->bits assertion in inffast.c - * - Add comments on op field in inftrees.h - * - Fix bug in reuse of allocated window after inflateReset() - * - Remove bit fields--back to byte structure for speed - * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths - * - Change post-increments to pre-increments in inflate_fast(), PPC biased? - * - Add compile time option, POSTINC, to use post-increments instead (Intel?) - * - Make MATCH copy in inflate() much faster for when inflate_fast() not used - * - Use local copies of stream next and avail values, as well as local bit - * buffer and bit count in inflate()--for speed when inflate_fast() not used - * - * 1.2.beta4 1 Jan 2003 - * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings - * - Move a comment on output buffer sizes from inffast.c to inflate.c - * - Add comments in inffast.c to introduce the inflate_fast() routine - * - Rearrange window copies in inflate_fast() for speed and simplification - * - Unroll last copy for window match in inflate_fast() - * - Use local copies of window variables in inflate_fast() for speed - * - Pull out common write == 0 case for speed in inflate_fast() - * - Make op and len in inflate_fast() unsigned for consistency - * - Add FAR to lcode and dcode declarations in inflate_fast() - * - Simplified bad distance check in inflate_fast() - * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new - * source file infback.c to provide a call-back interface to inflate for - * programs like gzip and unzip -- uses window as output buffer to avoid - * window copying - * - * 1.2.beta5 1 Jan 2003 - * - Improved inflateBack() interface to allow the caller to provide initial - * input in strm. - * - Fixed stored blocks bug in inflateBack() - * - * 1.2.beta6 4 Jan 2003 - * - Added comments in inffast.c on effectiveness of POSTINC - * - Typecasting all around to reduce compiler warnings - * - Changed loops from while (1) or do {} while (1) to for (;;), again to - * make compilers happy - * - Changed type of window in inflateBackInit() to unsigned char * - * - * 1.2.beta7 27 Jan 2003 - * - Changed many types to unsigned or unsigned short to avoid warnings - * - Added inflateCopy() function - * - * 1.2.0 9 Mar 2003 - * - Changed inflateBack() interface to provide separate opaque descriptors - * for the in() and out() functions - * - Changed inflateBack() argument and in_func typedef to swap the length - * and buffer address return values for the input function - * - Check next_in and next_out for Z_NULL on entry to inflate() - * - * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -#ifdef MAKEFIXED -# ifndef BUILDFIXED -# define BUILDFIXED -# endif -#endif - -/* function prototypes */ -local void fixedtables OF((struct inflate_state FAR *state)); -local int updatewindow OF((z_streamp strm, unsigned out)); -#ifdef BUILDFIXED - void makefixed OF((void)); -#endif -local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, - unsigned len)); - -int ZEXPORT inflateReset(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - strm->total_in = strm->total_out = state->total = 0; - strm->msg = Z_NULL; - strm->adler = 1; /* to support ill-conceived Java test suite */ - state->mode = HEAD; - state->last = 0; - state->havedict = 0; - state->dmax = 32768U; - state->head = Z_NULL; - state->wsize = 0; - state->whave = 0; - state->write = 0; - state->hold = 0; - state->bits = 0; - state->lencode = state->distcode = state->next = state->codes; - Tracev((stderr, "inflate: reset\n")); - return Z_OK; -} - -int ZEXPORT inflatePrime(strm, bits, value) -z_streamp strm; -int bits; -int value; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; - value &= (1L << bits) - 1; - state->hold += value << state->bits; - state->bits += bits; - return Z_OK; -} - -int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) -z_streamp strm; -int windowBits; -const char *version; -int stream_size; -{ - struct inflate_state FAR *state; - - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != (int)(sizeof(z_stream))) - return Z_VERSION_ERROR; - if (strm == Z_NULL) return Z_STREAM_ERROR; - strm->msg = Z_NULL; /* in case we return an error */ - if (strm->zalloc == (alloc_func)0) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; - state = (struct inflate_state FAR *) - ZALLOC(strm, 1, sizeof(struct inflate_state)); - if (state == Z_NULL) return Z_MEM_ERROR; - Tracev((stderr, "inflate: allocated\n")); - strm->state = (struct internal_state FAR *)state; - if (windowBits < 0) { - state->wrap = 0; - windowBits = -windowBits; - } - else { - state->wrap = (windowBits >> 4) + 1; -#ifdef GUNZIP - if (windowBits < 48) windowBits &= 15; -#endif - } - if (windowBits < 8 || windowBits > 15) { - ZFREE(strm, state); - strm->state = Z_NULL; - return Z_STREAM_ERROR; - } - state->wbits = (unsigned)windowBits; - state->window = Z_NULL; - return inflateReset(strm); -} - -int ZEXPORT inflateInit_(strm, version, stream_size) -z_streamp strm; -const char *version; -int stream_size; -{ - return inflateInit2_(strm, DEF_WBITS, version, stream_size); -} - -/* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ -#ifdef BUILDFIXED - static int virgin = 1; - static code *lenfix, *distfix; - static code fixed[544]; - - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - unsigned sym, bits; - static code *next; - - /* literal/length table */ - sym = 0; - while (sym < 144) state->lens[sym++] = 8; - while (sym < 256) state->lens[sym++] = 9; - while (sym < 280) state->lens[sym++] = 7; - while (sym < 288) state->lens[sym++] = 8; - next = fixed; - lenfix = next; - bits = 9; - inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); - - /* distance table */ - sym = 0; - while (sym < 32) state->lens[sym++] = 5; - distfix = next; - bits = 5; - inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); - - /* do this just once */ - virgin = 0; - } -#else /* !BUILDFIXED */ -# include "inffixed.h" -#endif /* BUILDFIXED */ - state->lencode = lenfix; - state->lenbits = 9; - state->distcode = distfix; - state->distbits = 5; -} - -#ifdef MAKEFIXED -#include - -/* - Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also - defines BUILDFIXED, so the tables are built on the fly. makefixed() writes - those tables to stdout, which would be piped to inffixed.h. A small program - can simply call makefixed to do this: - - void makefixed(void); - - int main(void) - { - makefixed(); - return 0; - } - - Then that can be linked with zlib built with MAKEFIXED defined and run: - - a.out > inffixed.h - */ -void makefixed() -{ - unsigned low, size; - struct inflate_state state; - - fixedtables(&state); - puts(" /* inffixed.h -- table for decoding fixed codes"); - puts(" * Generated automatically by makefixed()."); - puts(" */"); - puts(""); - puts(" /* WARNING: this file should *not* be used by applications."); - puts(" It is part of the implementation of this library and is"); - puts(" subject to change. Applications should only use zlib.h."); - puts(" */"); - puts(""); - size = 1U << 9; - printf(" static const code lenfix[%u] = {", size); - low = 0; - for (;;) { - if ((low % 7) == 0) printf("\n "); - printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, - state.lencode[low].val); - if (++low == size) break; - putchar(','); - } - puts("\n };"); - size = 1U << 5; - printf("\n static const code distfix[%u] = {", size); - low = 0; - for (;;) { - if ((low % 6) == 0) printf("\n "); - printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, - state.distcode[low].val); - if (++low == size) break; - putchar(','); - } - puts("\n };"); -} -#endif /* MAKEFIXED */ - -/* - Update the window with the last wsize (normally 32K) bytes written before - returning. If window does not exist yet, create it. This is only called - when a window is already in use, or when output has been written during this - inflate call, but the end of the deflate stream has not been reached yet. - It is also called to create a window for dictionary data when a dictionary - is loaded. - - Providing output buffers larger than 32K to inflate() should provide a speed - advantage, since only the last 32K of output is copied to the sliding window - upon return from inflate(), and since all distances after the first 32K of - output will fall in the output data, making match copies simpler and faster. - The advantage may be dependent on the size of the processor's data caches. - */ -local int updatewindow(strm, out) -z_streamp strm; -unsigned out; -{ - struct inflate_state FAR *state; - unsigned copy, dist; - - state = (struct inflate_state FAR *)strm->state; - - /* if it hasn't been done already, allocate space for the window */ - if (state->window == Z_NULL) { - state->window = (unsigned char FAR *) - ZALLOC(strm, 1U << state->wbits, - sizeof(unsigned char)); - if (state->window == Z_NULL) return 1; - } - - /* if window not in use yet, initialize */ - if (state->wsize == 0) { - state->wsize = 1U << state->wbits; - state->write = 0; - state->whave = 0; - } - - /* copy state->wsize or less output bytes into the circular window */ - copy = out - strm->avail_out; - if (copy >= state->wsize) { - zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); - state->write = 0; - state->whave = state->wsize; - } - else { - dist = state->wsize - state->write; - if (dist > copy) dist = copy; - zmemcpy(state->window + state->write, strm->next_out - copy, dist); - copy -= dist; - if (copy) { - zmemcpy(state->window, strm->next_out - copy, copy); - state->write = copy; - state->whave = state->wsize; - } - else { - state->write += dist; - if (state->write == state->wsize) state->write = 0; - if (state->whave < state->wsize) state->whave += dist; - } - } - return 0; -} - -/* Macros for inflate(): */ - -/* check function to use adler32() for zlib or crc32() for gzip */ -#ifdef GUNZIP -# define UPDATE(check, buf, len) \ - (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) -#else -# define UPDATE(check, buf, len) adler32(check, buf, len) -#endif - -/* check macros for header crc */ -#ifdef GUNZIP -# define CRC2(check, word) \ - do { \ - hbuf[0] = (unsigned char)(word); \ - hbuf[1] = (unsigned char)((word) >> 8); \ - check = crc32(check, hbuf, 2); \ - } while (0) - -# define CRC4(check, word) \ - do { \ - hbuf[0] = (unsigned char)(word); \ - hbuf[1] = (unsigned char)((word) >> 8); \ - hbuf[2] = (unsigned char)((word) >> 16); \ - hbuf[3] = (unsigned char)((word) >> 24); \ - check = crc32(check, hbuf, 4); \ - } while (0) -#endif - -/* Load registers with state in inflate() for speed */ -#define LOAD() \ - do { \ - put = strm->next_out; \ - left = strm->avail_out; \ - next = strm->next_in; \ - have = strm->avail_in; \ - hold = state->hold; \ - bits = state->bits; \ - } while (0) - -/* Restore state from registers in inflate() */ -#define RESTORE() \ - do { \ - strm->next_out = put; \ - strm->avail_out = left; \ - strm->next_in = next; \ - strm->avail_in = have; \ - state->hold = hold; \ - state->bits = bits; \ - } while (0) - -/* Clear the input bit accumulator */ -#define INITBITS() \ - do { \ - hold = 0; \ - bits = 0; \ - } while (0) - -/* Get a byte of input into the bit accumulator, or return from inflate() - if there is no input available. */ -#define PULLBYTE() \ - do { \ - if (have == 0) goto inf_leave; \ - have--; \ - hold += (unsigned long)(*next++) << bits; \ - bits += 8; \ - } while (0) - -/* Assure that there are at least n bits in the bit accumulator. If there is - not enough available input to do that, then return from inflate(). */ -#define NEEDBITS(n) \ - do { \ - while (bits < (unsigned)(n)) \ - PULLBYTE(); \ - } while (0) - -/* Return the low n bits of the bit accumulator (n < 16) */ -#define BITS(n) \ - ((unsigned)hold & ((1U << (n)) - 1)) - -/* Remove n bits from the bit accumulator */ -#define DROPBITS(n) \ - do { \ - hold >>= (n); \ - bits -= (unsigned)(n); \ - } while (0) - -/* Remove zero to seven bits as needed to go to a byte boundary */ -#define BYTEBITS() \ - do { \ - hold >>= bits & 7; \ - bits -= bits & 7; \ - } while (0) - -/* Reverse the bytes in a 32-bit value */ -#define REVERSE(q) \ - ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ - (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) - -/* - inflate() uses a state machine to process as much input data and generate as - much output data as possible before returning. The state machine is - structured roughly as follows: - - for (;;) switch (state) { - ... - case STATEn: - if (not enough input data or output space to make progress) - return; - ... make progress ... - state = STATEm; - break; - ... - } - - so when inflate() is called again, the same case is attempted again, and - if the appropriate resources are provided, the machine proceeds to the - next state. The NEEDBITS() macro is usually the way the state evaluates - whether it can proceed or should return. NEEDBITS() does the return if - the requested bits are not available. The typical use of the BITS macros - is: - - NEEDBITS(n); - ... do something with BITS(n) ... - DROPBITS(n); - - where NEEDBITS(n) either returns from inflate() if there isn't enough - input left to load n bits into the accumulator, or it continues. BITS(n) - gives the low n bits in the accumulator. When done, DROPBITS(n) drops - the low n bits off the accumulator. INITBITS() clears the accumulator - and sets the number of available bits to zero. BYTEBITS() discards just - enough bits to put the accumulator on a byte boundary. After BYTEBITS() - and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. - - NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return - if there is no input available. The decoding of variable length codes uses - PULLBYTE() directly in order to pull just enough bytes to decode the next - code, and no more. - - Some states loop until they get enough input, making sure that enough - state information is maintained to continue the loop where it left off - if NEEDBITS() returns in the loop. For example, want, need, and keep - would all have to actually be part of the saved state in case NEEDBITS() - returns: - - case STATEw: - while (want < need) { - NEEDBITS(n); - keep[want++] = BITS(n); - DROPBITS(n); - } - state = STATEx; - case STATEx: - - As shown above, if the next state is also the next case, then the break - is omitted. - - A state may also return if there is not enough output space available to - complete that state. Those states are copying stored data, writing a - literal byte, and copying a matching string. - - When returning, a "goto inf_leave" is used to update the total counters, - update the check value, and determine whether any progress has been made - during that inflate() call in order to return the proper return code. - Progress is defined as a change in either strm->avail_in or strm->avail_out. - When there is a window, goto inf_leave will update the window with the last - output written. If a goto inf_leave occurs in the middle of decompression - and there is no window currently, goto inf_leave will create one and copy - output to the window for the next call of inflate(). - - In this implementation, the flush parameter of inflate() only affects the - return code (per zlib.h). inflate() always writes as much as possible to - strm->next_out, given the space available and the provided input--the effect - documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers - the allocation of and copying into a sliding window until necessary, which - provides the effect documented in zlib.h for Z_FINISH when the entire input - stream available. So the only thing the flush parameter actually does is: - when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it - will return Z_BUF_ERROR if it has not reached the end of the stream. - */ - -int ZEXPORT inflate(strm, flush) -z_streamp strm; -int flush; -{ - struct inflate_state FAR *state; - unsigned char FAR *next; /* next input */ - unsigned char FAR *put; /* next output */ - unsigned have, left; /* available input and output */ - unsigned long hold; /* bit buffer */ - unsigned bits; /* bits in bit buffer */ - unsigned in, out; /* save starting available input and output */ - unsigned copy; /* number of stored or match bytes to copy */ - unsigned char FAR *from; /* where to copy match bytes from */ - code this; /* current decoding table entry */ - code last; /* parent table entry */ - unsigned len; /* length to copy for repeats, bits to drop */ - int ret; /* return code */ -#ifdef GUNZIP - unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ -#endif - static const unsigned short order[19] = /* permutation of code lengths */ - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || - (strm->next_in == Z_NULL && strm->avail_in != 0)) - return Z_STREAM_ERROR; - - state = (struct inflate_state FAR *)strm->state; - if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ - LOAD(); - in = have; - out = left; - ret = Z_OK; - for (;;) - switch (state->mode) { - case HEAD: - if (state->wrap == 0) { - state->mode = TYPEDO; - break; - } - NEEDBITS(16); -#ifdef GUNZIP - if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ - state->check = crc32(0L, Z_NULL, 0); - CRC2(state->check, hold); - INITBITS(); - state->mode = FLAGS; - break; - } - state->flags = 0; /* expect zlib header */ - if (state->head != Z_NULL) - state->head->done = -1; - if (!(state->wrap & 1) || /* check if zlib header allowed */ -#else - if ( -#endif - ((BITS(8) << 8) + (hold >> 8)) % 31) { - strm->msg = (char *)"incorrect header check"; - state->mode = BAD; - break; - } - if (BITS(4) != Z_DEFLATED) { - strm->msg = (char *)"unknown compression method"; - state->mode = BAD; - break; - } - DROPBITS(4); - len = BITS(4) + 8; - if (len > state->wbits) { - strm->msg = (char *)"invalid window size"; - state->mode = BAD; - break; - } - state->dmax = 1U << len; - Tracev((stderr, "inflate: zlib header ok\n")); - strm->adler = state->check = adler32(0L, Z_NULL, 0); - state->mode = hold & 0x200 ? DICTID : TYPE; - INITBITS(); - break; -#ifdef GUNZIP - case FLAGS: - NEEDBITS(16); - state->flags = (int)(hold); - if ((state->flags & 0xff) != Z_DEFLATED) { - strm->msg = (char *)"unknown compression method"; - state->mode = BAD; - break; - } - if (state->flags & 0xe000) { - strm->msg = (char *)"unknown header flags set"; - state->mode = BAD; - break; - } - if (state->head != Z_NULL) - state->head->text = (int)((hold >> 8) & 1); - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - state->mode = TIME; - case TIME: - NEEDBITS(32); - if (state->head != Z_NULL) - state->head->time = hold; - if (state->flags & 0x0200) CRC4(state->check, hold); - INITBITS(); - state->mode = OS; - case OS: - NEEDBITS(16); - if (state->head != Z_NULL) { - state->head->xflags = (int)(hold & 0xff); - state->head->os = (int)(hold >> 8); - } - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - state->mode = EXLEN; - case EXLEN: - if (state->flags & 0x0400) { - NEEDBITS(16); - state->length = (unsigned)(hold); - if (state->head != Z_NULL) - state->head->extra_len = (unsigned)hold; - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - } - else if (state->head != Z_NULL) - state->head->extra = Z_NULL; - state->mode = EXTRA; - case EXTRA: - if (state->flags & 0x0400) { - copy = state->length; - if (copy > have) copy = have; - if (copy) { - if (state->head != Z_NULL && - state->head->extra != Z_NULL) { - len = state->head->extra_len - state->length; - zmemcpy(state->head->extra + len, next, - len + copy > state->head->extra_max ? - state->head->extra_max - len : copy); - } - if (state->flags & 0x0200) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - state->length -= copy; - } - if (state->length) goto inf_leave; - } - state->length = 0; - state->mode = NAME; - case NAME: - if (state->flags & 0x0800) { - if (have == 0) goto inf_leave; - copy = 0; - do { - len = (unsigned)(next[copy++]); - if (state->head != Z_NULL && - state->head->name != Z_NULL && - state->length < state->head->name_max) - state->head->name[state->length++] = len; - } while (len && copy < have); - if (state->flags & 0x0200) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - if (len) goto inf_leave; - } - else if (state->head != Z_NULL) - state->head->name = Z_NULL; - state->length = 0; - state->mode = COMMENT; - case COMMENT: - if (state->flags & 0x1000) { - if (have == 0) goto inf_leave; - copy = 0; - do { - len = (unsigned)(next[copy++]); - if (state->head != Z_NULL && - state->head->comment != Z_NULL && - state->length < state->head->comm_max) - state->head->comment[state->length++] = len; - } while (len && copy < have); - if (state->flags & 0x0200) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - if (len) goto inf_leave; - } - else if (state->head != Z_NULL) - state->head->comment = Z_NULL; - state->mode = HCRC; - case HCRC: - if (state->flags & 0x0200) { - NEEDBITS(16); - if (hold != (state->check & 0xffff)) { - strm->msg = (char *)"header crc mismatch"; - state->mode = BAD; - break; - } - INITBITS(); - } - if (state->head != Z_NULL) { - state->head->hcrc = (int)((state->flags >> 9) & 1); - state->head->done = 1; - } - strm->adler = state->check = crc32(0L, Z_NULL, 0); - state->mode = TYPE; - break; -#endif - case DICTID: - NEEDBITS(32); - strm->adler = state->check = REVERSE(hold); - INITBITS(); - state->mode = DICT; - case DICT: - if (state->havedict == 0) { - RESTORE(); - return Z_NEED_DICT; - } - strm->adler = state->check = adler32(0L, Z_NULL, 0); - state->mode = TYPE; - case TYPE: - if (flush == Z_BLOCK) goto inf_leave; - case TYPEDO: - if (state->last) { - BYTEBITS(); - state->mode = CHECK; - break; - } - NEEDBITS(3); - state->last = BITS(1); - DROPBITS(1); - switch (BITS(2)) { - case 0: /* stored block */ - Tracev((stderr, "inflate: stored block%s\n", - state->last ? " (last)" : "")); - state->mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - Tracev((stderr, "inflate: fixed codes block%s\n", - state->last ? " (last)" : "")); - state->mode = LEN; /* decode codes */ - break; - case 2: /* dynamic block */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - state->last ? " (last)" : "")); - state->mode = TABLE; - break; - case 3: - strm->msg = (char *)"invalid block type"; - state->mode = BAD; - } - DROPBITS(2); - break; - case STORED: - BYTEBITS(); /* go to byte boundary */ - NEEDBITS(32); - if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - strm->msg = (char *)"invalid stored block lengths"; - state->mode = BAD; - break; - } - state->length = (unsigned)hold & 0xffff; - Tracev((stderr, "inflate: stored length %u\n", - state->length)); - INITBITS(); - state->mode = COPY; - case COPY: - copy = state->length; - if (copy) { - if (copy > have) copy = have; - if (copy > left) copy = left; - if (copy == 0) goto inf_leave; - zmemcpy(put, next, copy); - have -= copy; - next += copy; - left -= copy; - put += copy; - state->length -= copy; - break; - } - Tracev((stderr, "inflate: stored end\n")); - state->mode = TYPE; - break; - case TABLE: - NEEDBITS(14); - state->nlen = BITS(5) + 257; - DROPBITS(5); - state->ndist = BITS(5) + 1; - DROPBITS(5); - state->ncode = BITS(4) + 4; - DROPBITS(4); -#ifndef PKZIP_BUG_WORKAROUND - if (state->nlen > 286 || state->ndist > 30) { - strm->msg = (char *)"too many length or distance symbols"; - state->mode = BAD; - break; - } -#endif - Tracev((stderr, "inflate: table sizes ok\n")); - state->have = 0; - state->mode = LENLENS; - case LENLENS: - while (state->have < state->ncode) { - NEEDBITS(3); - state->lens[order[state->have++]] = (unsigned short)BITS(3); - DROPBITS(3); - } - while (state->have < 19) - state->lens[order[state->have++]] = 0; - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 7; - ret = inflate_table(CODES, state->lens, 19, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid code lengths set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: code lengths ok\n")); - state->have = 0; - state->mode = CODELENS; - case CODELENS: - while (state->have < state->nlen + state->ndist) { - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.val < 16) { - NEEDBITS(this.bits); - DROPBITS(this.bits); - state->lens[state->have++] = this.val; - } - else { - if (this.val == 16) { - NEEDBITS(this.bits + 2); - DROPBITS(this.bits); - if (state->have == 0) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - len = state->lens[state->have - 1]; - copy = 3 + BITS(2); - DROPBITS(2); - } - else if (this.val == 17) { - NEEDBITS(this.bits + 3); - DROPBITS(this.bits); - len = 0; - copy = 3 + BITS(3); - DROPBITS(3); - } - else { - NEEDBITS(this.bits + 7); - DROPBITS(this.bits); - len = 0; - copy = 11 + BITS(7); - DROPBITS(7); - } - if (state->have + copy > state->nlen + state->ndist) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - while (copy--) - state->lens[state->have++] = (unsigned short)len; - } - } - - /* handle error breaks in while */ - if (state->mode == BAD) break; - - /* build code tables */ - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 9; - ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid literal/lengths set"; - state->mode = BAD; - break; - } - state->distcode = (code const FAR *)(state->next); - state->distbits = 6; - ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, - &(state->next), &(state->distbits), state->work); - if (ret) { - strm->msg = (char *)"invalid distances set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: codes ok\n")); - state->mode = LEN; - case LEN: - if (have >= 6 && left >= 258) { - RESTORE(); - inflate_fast(strm, out); - LOAD(); - break; - } - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.op && (this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->lencode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - state->length = (unsigned)this.val; - if ((int)(this.op) == 0) { - Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", this.val)); - state->mode = LIT; - break; - } - if (this.op & 32) { - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - if (this.op & 64) { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - state->extra = (unsigned)(this.op) & 15; - state->mode = LENEXT; - case LENEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->length += BITS(state->extra); - DROPBITS(state->extra); - } - Tracevv((stderr, "inflate: length %u\n", state->length)); - state->mode = DIST; - case DIST: - for (;;) { - this = state->distcode[BITS(state->distbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if ((this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->distcode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - if (this.op & 64) { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - state->offset = (unsigned)this.val; - state->extra = (unsigned)(this.op) & 15; - state->mode = DISTEXT; - case DISTEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->offset += BITS(state->extra); - DROPBITS(state->extra); - } -#ifdef INFLATE_STRICT - if (state->offset > state->dmax) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#endif - if (state->offset > state->whave + out - left) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - Tracevv((stderr, "inflate: distance %u\n", state->offset)); - state->mode = MATCH; - case MATCH: - if (left == 0) goto inf_leave; - copy = out - left; - if (state->offset > copy) { /* copy from window */ - copy = state->offset - copy; - if (copy > state->write) { - copy -= state->write; - from = state->window + (state->wsize - copy); - } - else - from = state->window + (state->write - copy); - if (copy > state->length) copy = state->length; - } - else { /* copy from output */ - from = put - state->offset; - copy = state->length; - } - if (copy > left) copy = left; - left -= copy; - state->length -= copy; - do { - *put++ = *from++; - } while (--copy); - if (state->length == 0) state->mode = LEN; - break; - case LIT: - if (left == 0) goto inf_leave; - *put++ = (unsigned char)(state->length); - left--; - state->mode = LEN; - break; - case CHECK: - if (state->wrap) { - NEEDBITS(32); - out -= left; - strm->total_out += out; - state->total += out; - if (out) - strm->adler = state->check = - UPDATE(state->check, put - out, out); - out = left; - if (( -#ifdef GUNZIP - state->flags ? hold : -#endif - REVERSE(hold)) != state->check) { - strm->msg = (char *)"incorrect data check"; - state->mode = BAD; - break; - } - INITBITS(); - Tracev((stderr, "inflate: check matches trailer\n")); - } -#ifdef GUNZIP - state->mode = LENGTH; - case LENGTH: - if (state->wrap && state->flags) { - NEEDBITS(32); - if (hold != (state->total & 0xffffffffUL)) { - strm->msg = (char *)"incorrect length check"; - state->mode = BAD; - break; - } - INITBITS(); - Tracev((stderr, "inflate: length matches trailer\n")); - } -#endif - state->mode = DONE; - case DONE: - ret = Z_STREAM_END; - goto inf_leave; - case BAD: - ret = Z_DATA_ERROR; - goto inf_leave; - case MEM: - return Z_MEM_ERROR; - case SYNC: - default: - return Z_STREAM_ERROR; - } - - /* - Return from inflate(), updating the total counts and the check value. - If there was no progress during the inflate() call, return a buffer - error. Call updatewindow() to create and/or update the window state. - Note: a memory error from inflate() is non-recoverable. - */ - inf_leave: - RESTORE(); - if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) - if (updatewindow(strm, out)) { - state->mode = MEM; - return Z_MEM_ERROR; - } - in -= strm->avail_in; - out -= strm->avail_out; - strm->total_in += in; - strm->total_out += out; - state->total += out; - if (state->wrap && out) - strm->adler = state->check = - UPDATE(state->check, strm->next_out - out, out); - strm->data_type = state->bits + (state->last ? 64 : 0) + - (state->mode == TYPE ? 128 : 0); - if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) - ret = Z_BUF_ERROR; - return ret; -} - -int ZEXPORT inflateEnd(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (state->window != Z_NULL) ZFREE(strm, state->window); - ZFREE(strm, strm->state); - strm->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; -} - -int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) -z_streamp strm; -const Bytef *dictionary; -uInt dictLength; -{ - struct inflate_state FAR *state; - unsigned long id; - - /* check state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (state->wrap != 0 && state->mode != DICT) - return Z_STREAM_ERROR; - - /* check for correct dictionary id */ - if (state->mode == DICT) { - id = adler32(0L, Z_NULL, 0); - id = adler32(id, dictionary, dictLength); - if (id != state->check) - return Z_DATA_ERROR; - } - - /* copy dictionary to window */ - if (updatewindow(strm, strm->avail_out)) { - state->mode = MEM; - return Z_MEM_ERROR; - } - if (dictLength > state->wsize) { - zmemcpy(state->window, dictionary + dictLength - state->wsize, - state->wsize); - state->whave = state->wsize; - } - else { - zmemcpy(state->window + state->wsize - dictLength, dictionary, - dictLength); - state->whave = dictLength; - } - state->havedict = 1; - Tracev((stderr, "inflate: dictionary set\n")); - return Z_OK; -} - -int ZEXPORT inflateGetHeader(strm, head) -z_streamp strm; -gz_headerp head; -{ - struct inflate_state FAR *state; - - /* check state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; - - /* save header structure */ - state->head = head; - head->done = 0; - return Z_OK; -} - -/* - Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found - or when out of input. When called, *have is the number of pattern bytes - found in order so far, in 0..3. On return *have is updated to the new - state. If on return *have equals four, then the pattern was found and the - return value is how many bytes were read including the last byte of the - pattern. If *have is less than four, then the pattern has not been found - yet and the return value is len. In the latter case, syncsearch() can be - called again with more data and the *have state. *have is initialized to - zero for the first call. - */ -local unsigned syncsearch(have, buf, len) -unsigned FAR *have; -unsigned char FAR *buf; -unsigned len; -{ - unsigned got; - unsigned next; - - got = *have; - next = 0; - while (next < len && got < 4) { - if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) - got++; - else if (buf[next]) - got = 0; - else - got = 4 - got; - next++; - } - *have = got; - return next; -} - -int ZEXPORT inflateSync(strm) -z_streamp strm; -{ - unsigned len; /* number of bytes to look at or looked at */ - unsigned long in, out; /* temporary to save total_in and total_out */ - unsigned char buf[4]; /* to restore bit buffer to byte string */ - struct inflate_state FAR *state; - - /* check parameters */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; - - /* if first time, start search in bit buffer */ - if (state->mode != SYNC) { - state->mode = SYNC; - state->hold <<= state->bits & 7; - state->bits -= state->bits & 7; - len = 0; - while (state->bits >= 8) { - buf[len++] = (unsigned char)(state->hold); - state->hold >>= 8; - state->bits -= 8; - } - state->have = 0; - syncsearch(&(state->have), buf, len); - } - - /* search available input */ - len = syncsearch(&(state->have), strm->next_in, strm->avail_in); - strm->avail_in -= len; - strm->next_in += len; - strm->total_in += len; - - /* return no joy or set up to restart inflate() on a new block */ - if (state->have != 4) return Z_DATA_ERROR; - in = strm->total_in; out = strm->total_out; - inflateReset(strm); - strm->total_in = in; strm->total_out = out; - state->mode = TYPE; - return Z_OK; -} - -/* - Returns true if inflate is currently at the end of a block generated by - Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP - implementation to provide an additional safety check. PPP uses - Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored - block. When decompressing, PPP checks that at the end of input packet, - inflate is waiting for these length bytes. - */ -int ZEXPORT inflateSyncPoint(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - return state->mode == STORED && state->bits == 0; -} - -int ZEXPORT inflateCopy(dest, source) -z_streamp dest; -z_streamp source; -{ - struct inflate_state FAR *state; - struct inflate_state FAR *copy; - unsigned char FAR *window; - unsigned wsize; - - /* check input */ - if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || - source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)source->state; - - /* allocate space */ - copy = (struct inflate_state FAR *) - ZALLOC(source, 1, sizeof(struct inflate_state)); - if (copy == Z_NULL) return Z_MEM_ERROR; - window = Z_NULL; - if (state->window != Z_NULL) { - window = (unsigned char FAR *) - ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); - if (window == Z_NULL) { - ZFREE(source, copy); - return Z_MEM_ERROR; - } - } - - /* copy state */ - zmemcpy(dest, source, sizeof(z_stream)); - zmemcpy(copy, state, sizeof(struct inflate_state)); - if (state->lencode >= state->codes && - state->lencode <= state->codes + ENOUGH - 1) { - copy->lencode = copy->codes + (state->lencode - state->codes); - copy->distcode = copy->codes + (state->distcode - state->codes); - } - copy->next = copy->codes + (state->next - state->codes); - if (window != Z_NULL) { - wsize = 1U << state->wbits; - zmemcpy(window, state->window, wsize); - } - copy->window = window; - dest->state = (struct internal_state FAR *)copy; - return Z_OK; -} +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + strm->adler = 1; /* to support ill-conceived Java test suite */ + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->wsize = 0; + state->whave = 0; + state->write = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + if (state->mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy(dest, source, sizeof(z_stream)); + zmemcpy(copy, state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} diff --git a/3rdparty/zlib/inflate.h b/3rdparty/zlib/inflate.h index fbbc871432..07bd3e78a7 100644 --- a/3rdparty/zlib/inflate.h +++ b/3rdparty/zlib/inflate.h @@ -1,115 +1,115 @@ -/* inflate.h -- internal inflate state definition - * Copyright (C) 1995-2004 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer decoding by inflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip decoding - should be left enabled. */ -#ifndef NO_GZIP -# define GUNZIP -#endif - -/* Possible inflate modes between inflate() calls */ -typedef enum { - HEAD, /* i: waiting for magic header */ - FLAGS, /* i: waiting for method and flags (gzip) */ - TIME, /* i: waiting for modification time (gzip) */ - OS, /* i: waiting for extra flags and operating system (gzip) */ - EXLEN, /* i: waiting for extra length (gzip) */ - EXTRA, /* i: waiting for extra bytes (gzip) */ - NAME, /* i: waiting for end of file name (gzip) */ - COMMENT, /* i: waiting for end of comment (gzip) */ - HCRC, /* i: waiting for header crc (gzip) */ - DICTID, /* i: waiting for dictionary check value */ - DICT, /* waiting for inflateSetDictionary() call */ - TYPE, /* i: waiting for type bits, including last-flag bit */ - TYPEDO, /* i: same, but skip check to exit inflate on new block */ - STORED, /* i: waiting for stored size (length and complement) */ - COPY, /* i/o: waiting for input or output to copy stored block */ - TABLE, /* i: waiting for dynamic block table lengths */ - LENLENS, /* i: waiting for code length code lengths */ - CODELENS, /* i: waiting for length/lit and distance code lengths */ - LEN, /* i: waiting for length/lit code */ - LENEXT, /* i: waiting for length extra bits */ - DIST, /* i: waiting for distance code */ - DISTEXT, /* i: waiting for distance extra bits */ - MATCH, /* o: waiting for output space to copy string */ - LIT, /* o: waiting for output space to write literal */ - CHECK, /* i: waiting for 32-bit check value */ - LENGTH, /* i: waiting for 32-bit length (gzip) */ - DONE, /* finished check, done -- remain here until reset */ - BAD, /* got a data error -- remain here until reset */ - MEM, /* got an inflate() memory error -- remain here until reset */ - SYNC /* looking for synchronization bytes to restart inflate() */ -} inflate_mode; - -/* - State transitions between above modes - - - (most modes can go to the BAD or MEM mode -- not shown for clarity) - - Process header: - HEAD -> (gzip) or (zlib) - (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME - NAME -> COMMENT -> HCRC -> TYPE - (zlib) -> DICTID or TYPE - DICTID -> DICT -> TYPE - Read deflate blocks: - TYPE -> STORED or TABLE or LEN or CHECK - STORED -> COPY -> TYPE - TABLE -> LENLENS -> CODELENS -> LEN - Read deflate codes: - LEN -> LENEXT or LIT or TYPE - LENEXT -> DIST -> DISTEXT -> MATCH -> LEN - LIT -> LEN - Process trailer: - CHECK -> LENGTH -> DONE - */ - -/* state maintained between inflate() calls. Approximately 7K bytes. */ -struct inflate_state { - inflate_mode mode; /* current inflate mode */ - int last; /* true if processing last block */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - int havedict; /* true if dictionary provided */ - int flags; /* gzip header method and flags (0 if zlib) */ - unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ - unsigned long check; /* protected copy of check value */ - unsigned long total; /* protected copy of output count */ - gz_headerp head; /* where to save gzip header information */ - /* sliding window */ - unsigned wbits; /* log base 2 of requested window size */ - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned write; /* window write index */ - unsigned char FAR *window; /* allocated sliding window, if needed */ - /* bit accumulator */ - unsigned long hold; /* input bit accumulator */ - unsigned bits; /* number of bits in "in" */ - /* for string and stored block copying */ - unsigned length; /* literal or length of data to copy */ - unsigned offset; /* distance back to copy string from */ - /* for table and code decoding */ - unsigned extra; /* extra bits needed */ - /* fixed and dynamic code tables */ - code const FAR *lencode; /* starting table for length/literal codes */ - code const FAR *distcode; /* starting table for distance codes */ - unsigned lenbits; /* index bits for lencode */ - unsigned distbits; /* index bits for distcode */ - /* dynamic table building */ - unsigned ncode; /* number of code length code lengths */ - unsigned nlen; /* number of length code lengths */ - unsigned ndist; /* number of distance code lengths */ - unsigned have; /* number of code lengths in lens[] */ - code FAR *next; /* next available space in codes[] */ - unsigned short lens[320]; /* temporary storage for code lengths */ - unsigned short work[288]; /* work area for code table building */ - code codes[ENOUGH]; /* space for code tables */ -}; +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/3rdparty/zlib/inftrees.c b/3rdparty/zlib/inftrees.c index 38ded81c36..8a9c13ff03 100644 --- a/3rdparty/zlib/inftrees.c +++ b/3rdparty/zlib/inftrees.c @@ -1,329 +1,329 @@ -/* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" - -#define MAXBITS 15 - -const char inflate_copyright[] = - " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* - Build a set of tables to decode the provided canonical Huffman code. - The code lengths are lens[0..codes-1]. The result starts at *table, - whose indices are 0..2^bits-1. work is a writable array of at least - lens shorts, which is used as a work area. type is the type of code - to be generated, CODES, LENS, or DISTS. On return, zero is success, - -1 is an invalid code, and +1 means that ENOUGH isn't enough. table - on return points to the next available entry's address. bits is the - requested root table index bits, and on return it is the actual root - table index bits. It will differ if the request is greater than the - longest code or if it is less than the shortest code. - */ -int inflate_table(type, lens, codes, table, bits, work) -codetype type; -unsigned short FAR *lens; -unsigned codes; -code FAR * FAR *table; -unsigned FAR *bits; -unsigned short FAR *work; -{ - unsigned len; /* a code's length in bits */ - unsigned sym; /* index of code symbols */ - unsigned min, max; /* minimum and maximum code lengths */ - unsigned root; /* number of index bits for root table */ - unsigned curr; /* number of index bits for current table */ - unsigned drop; /* code bits to drop for sub-table */ - int left; /* number of prefix codes available */ - unsigned used; /* code entries in table used */ - unsigned huff; /* Huffman code */ - unsigned incr; /* for incrementing code, index */ - unsigned fill; /* index for replicating entries */ - unsigned low; /* low bits for current root entry */ - unsigned mask; /* mask for low root bits */ - code this; /* table entry for duplication */ - code FAR *next; /* next available space in table */ - const unsigned short FAR *base; /* base value table to use */ - const unsigned short FAR *extra; /* extra bits table to use */ - int end; /* use base and extra for symbol > end */ - unsigned short count[MAXBITS+1]; /* number of codes of each length */ - unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ - static const unsigned short lbase[31] = { /* Length codes 257..285 base */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - static const unsigned short lext[31] = { /* Length codes 257..285 extra */ - 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; - static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577, 0, 0}; - static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ - 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, - 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, - 28, 28, 29, 29, 64, 64}; - - /* - Process a set of code lengths to create a canonical Huffman code. The - code lengths are lens[0..codes-1]. Each length corresponds to the - symbols 0..codes-1. The Huffman code is generated by first sorting the - symbols by length from short to long, and retaining the symbol order - for codes with equal lengths. Then the code starts with all zero bits - for the first code of the shortest length, and the codes are integer - increments for the same length, and zeros are appended as the length - increases. For the deflate format, these bits are stored backwards - from their more natural integer increment ordering, and so when the - decoding tables are built in the large loop below, the integer codes - are incremented backwards. - - This routine assumes, but does not check, that all of the entries in - lens[] are in the range 0..MAXBITS. The caller must assure this. - 1..MAXBITS is interpreted as that code length. zero means that that - symbol does not occur in this code. - - The codes are sorted by computing a count of codes for each length, - creating from that a table of starting indices for each length in the - sorted table, and then entering the symbols in order in the sorted - table. The sorted table is work[], with that space being provided by - the caller. - - The length counts are used for other purposes as well, i.e. finding - the minimum and maximum length codes, determining if there are any - codes at all, checking for a valid set of lengths, and looking ahead - at length counts to determine sub-table sizes when building the - decoding tables. - */ - - /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ - for (len = 0; len <= MAXBITS; len++) - count[len] = 0; - for (sym = 0; sym < codes; sym++) - count[lens[sym]]++; - - /* bound code lengths, force root to be within code lengths */ - root = *bits; - for (max = MAXBITS; max >= 1; max--) - if (count[max] != 0) break; - if (root > max) root = max; - if (max == 0) { /* no symbols to code at all */ - this.op = (unsigned char)64; /* invalid code marker */ - this.bits = (unsigned char)1; - this.val = (unsigned short)0; - *(*table)++ = this; /* make a table to force an error */ - *(*table)++ = this; - *bits = 1; - return 0; /* no symbols, but wait for decoding to report error */ - } - for (min = 1; min <= MAXBITS; min++) - if (count[min] != 0) break; - if (root < min) root = min; - - /* check for an over-subscribed or incomplete set of lengths */ - left = 1; - for (len = 1; len <= MAXBITS; len++) { - left <<= 1; - left -= count[len]; - if (left < 0) return -1; /* over-subscribed */ - } - if (left > 0 && (type == CODES || max != 1)) - return -1; /* incomplete set */ - - /* generate offsets into symbol table for each length for sorting */ - offs[1] = 0; - for (len = 1; len < MAXBITS; len++) - offs[len + 1] = offs[len] + count[len]; - - /* sort symbols by length, by symbol order within each length */ - for (sym = 0; sym < codes; sym++) - if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; - - /* - Create and fill in decoding tables. In this loop, the table being - filled is at next and has curr index bits. The code being used is huff - with length len. That code is converted to an index by dropping drop - bits off of the bottom. For codes where len is less than drop + curr, - those top drop + curr - len bits are incremented through all values to - fill the table with replicated entries. - - root is the number of index bits for the root table. When len exceeds - root, sub-tables are created pointed to by the root entry with an index - of the low root bits of huff. This is saved in low to check for when a - new sub-table should be started. drop is zero when the root table is - being filled, and drop is root when sub-tables are being filled. - - When a new sub-table is needed, it is necessary to look ahead in the - code lengths to determine what size sub-table is needed. The length - counts are used for this, and so count[] is decremented as codes are - entered in the tables. - - used keeps track of how many table entries have been allocated from the - provided *table space. It is checked when a LENS table is being made - against the space in *table, ENOUGH, minus the maximum space needed by - the worst case distance code, MAXD. This should never happen, but the - sufficiency of ENOUGH has not been proven exhaustively, hence the check. - This assumes that when type == LENS, bits == 9. - - sym increments through all symbols, and the loop terminates when - all codes of length max, i.e. all codes, have been processed. This - routine permits incomplete codes, so another loop after this one fills - in the rest of the decoding tables with invalid code markers. - */ - - /* set up for code type */ - switch (type) { - case CODES: - base = extra = work; /* dummy value--not used */ - end = 19; - break; - case LENS: - base = lbase; - base -= 257; - extra = lext; - extra -= 257; - end = 256; - break; - default: /* DISTS */ - base = dbase; - extra = dext; - end = -1; - } - - /* initialize state for loop */ - huff = 0; /* starting code */ - sym = 0; /* starting code symbol */ - len = min; /* starting code length */ - next = *table; /* current table to fill in */ - curr = root; /* current table index bits */ - drop = 0; /* current bits to drop from code for index */ - low = (unsigned)(-1); /* trigger new sub-table when len > root */ - used = 1U << root; /* use root table entries */ - mask = used - 1; /* mask for comparing low */ - - /* check available table space */ - if (type == LENS && used >= ENOUGH - MAXD) - return 1; - - /* process all codes and make table entries */ - for (;;) { - /* create table entry */ - this.bits = (unsigned char)(len - drop); - if ((int)(work[sym]) < end) { - this.op = (unsigned char)0; - this.val = work[sym]; - } - else if ((int)(work[sym]) > end) { - this.op = (unsigned char)(extra[work[sym]]); - this.val = base[work[sym]]; - } - else { - this.op = (unsigned char)(32 + 64); /* end of block */ - this.val = 0; - } - - /* replicate for those indices with low len bits equal to huff */ - incr = 1U << (len - drop); - fill = 1U << curr; - min = fill; /* save offset to next table */ - do { - fill -= incr; - next[(huff >> drop) + fill] = this; - } while (fill != 0); - - /* backwards increment the len-bit code huff */ - incr = 1U << (len - 1); - while (huff & incr) - incr >>= 1; - if (incr != 0) { - huff &= incr - 1; - huff += incr; - } - else - huff = 0; - - /* go to next symbol, update count, len */ - sym++; - if (--(count[len]) == 0) { - if (len == max) break; - len = lens[work[sym]]; - } - - /* create new sub-table if needed */ - if (len > root && (huff & mask) != low) { - /* if first time, transition to sub-tables */ - if (drop == 0) - drop = root; - - /* increment past last table */ - next += min; /* here min is 1 << curr */ - - /* determine length of next table */ - curr = len - drop; - left = (int)(1 << curr); - while (curr + drop < max) { - left -= count[curr + drop]; - if (left <= 0) break; - curr++; - left <<= 1; - } - - /* check for enough space */ - used += 1U << curr; - if (type == LENS && used >= ENOUGH - MAXD) - return 1; - - /* point entry in root table to sub-table */ - low = huff & mask; - (*table)[low].op = (unsigned char)curr; - (*table)[low].bits = (unsigned char)root; - (*table)[low].val = (unsigned short)(next - *table); - } - } - - /* - Fill in rest of table for incomplete codes. This loop is similar to the - loop above in incrementing huff for table indices. It is assumed that - len is equal to curr + drop, so there is no loop needed to increment - through high index bits. When the current sub-table is filled, the loop - drops back to the root table to fill in any remaining entries there. - */ - this.op = (unsigned char)64; /* invalid code marker */ - this.bits = (unsigned char)(len - drop); - this.val = (unsigned short)0; - while (huff != 0) { - /* when done with sub-table, drop back to root table */ - if (drop != 0 && (huff & mask) != low) { - drop = 0; - len = root; - next = *table; - this.bits = (unsigned char)len; - } - - /* put invalid code marker in table */ - next[huff >> drop] = this; - - /* backwards increment the len-bit code huff */ - incr = 1U << (len - 1); - while (huff & incr) - incr >>= 1; - if (incr != 0) { - huff &= incr - 1; - huff += incr; - } - else - huff = 0; - } - - /* set return parameters */ - *table += used; - *bits = root; - return 0; -} +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)1; + this.val = (unsigned short)0; + *(*table)++ = this; /* make a table to force an error */ + *(*table)++ = this; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/3rdparty/zlib/inftrees.h b/3rdparty/zlib/inftrees.h index dc0fd567ea..b1104c87e7 100644 --- a/3rdparty/zlib/inftrees.h +++ b/3rdparty/zlib/inftrees.h @@ -1,55 +1,55 @@ -/* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* Structure for decoding tables. Each entry provides either the - information needed to do the operation requested by the code that - indexed that table entry, or it provides a pointer to another - table that indexes more bits of the code. op indicates whether - the entry is a pointer to another table, a literal, a length or - distance, an end-of-block, or an invalid code. For a table - pointer, the low four bits of op is the number of index bits of - that table. For a length or distance, the low four bits of op - is the number of extra bits to get after the code. bits is - the number of bits in this code or part of the code to drop off - of the bit buffer. val is the actual byte to output in the case - of a literal, the base length or distance, or the offset from - the current table to the next table. Each entry is four bytes. */ -typedef struct { - unsigned char op; /* operation, extra bits, table bits */ - unsigned char bits; /* bits in this part of the code */ - unsigned short val; /* offset in table or code value */ -} code; - -/* op values as set by inflate_table(): - 00000000 - literal - 0000tttt - table link, tttt != 0 is the number of table index bits - 0001eeee - length or distance, eeee is the number of extra bits - 01100000 - end of block - 01000000 - invalid code - */ - -/* Maximum size of dynamic tree. The maximum found in a long but non- - exhaustive search was 1444 code structures (852 for length/literals - and 592 for distances, the latter actually the result of an - exhaustive search). The true maximum is not known, but the value - below is more than safe. */ -#define ENOUGH 2048 -#define MAXD 592 - -/* Type of code to build for inftable() */ -typedef enum { - CODES, - LENS, - DISTS -} codetype; - -extern int inflate_table OF((codetype type, unsigned short FAR *lens, - unsigned codes, code FAR * FAR *table, - unsigned FAR *bits, unsigned short FAR *work)); +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1444 code structures (852 for length/literals + and 592 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 2048 +#define MAXD 592 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/3rdparty/zlib/trees.c b/3rdparty/zlib/trees.c index 7a04802862..395e4e1681 100644 --- a/3rdparty/zlib/trees.c +++ b/3rdparty/zlib/trees.c @@ -1,1219 +1,1219 @@ -/* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2005 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process uses several Huffman trees. The more - * common source values are represented by shorter bit sequences. - * - * Each code tree is stored in a compressed form which is itself - * a Huffman encoding of the lengths of all the code strings (in - * ascending order by source values). The actual code strings are - * reconstructed from the lengths in the inflate process, as described - * in the deflate specification. - * - * REFERENCES - * - * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". - * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc - * - * Storer, James A. - * Data Compression: Methods and Theory, pp. 49-50. - * Computer Science Press, 1988. ISBN 0-7167-8156-5. - * - * Sedgewick, R. - * Algorithms, p290. - * Addison-Wesley, 1983. ISBN 0-201-06672-6. - */ - -/* @(#) $Id$ */ - -/* #define GEN_TREES_H */ - -#include "deflate.h" - -#ifdef DEBUG -# include -#endif - -/* =========================================================================== - * Constants - */ - -#define MAX_BL_BITS 7 -/* Bit length codes must not exceed MAX_BL_BITS bits */ - -#define END_BLOCK 256 -/* end of block literal code */ - -#define REP_3_6 16 -/* repeat previous bit length 3-6 times (2 bits of repeat count) */ - -#define REPZ_3_10 17 -/* repeat a zero length 3-10 times (3 bits of repeat count) */ - -#define REPZ_11_138 18 -/* repeat a zero length 11-138 times (7 bits of repeat count) */ - -local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ - = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; - -local const int extra_dbits[D_CODES] /* extra bits for each distance code */ - = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ - = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; - -local const uch bl_order[BL_CODES] - = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; -/* The lengths of the bit length codes are sent in order of decreasing - * probability, to avoid transmitting the lengths for unused bit length codes. - */ - -#define Buf_size (8 * 2*sizeof(char)) -/* Number of bits used within bi_buf. (bi_buf might be implemented on - * more than 16 bits on some systems.) - */ - -/* =========================================================================== - * Local data. These are initialized only once. - */ - -#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ - -#if defined(GEN_TREES_H) || !defined(STDC) -/* non ANSI compilers may not accept trees.h */ - -local ct_data static_ltree[L_CODES+2]; -/* The static literal tree. Since the bit lengths are imposed, there is no - * need for the L_CODES extra codes used during heap construction. However - * The codes 286 and 287 are needed to build a canonical tree (see _tr_init - * below). - */ - -local ct_data static_dtree[D_CODES]; -/* The static distance tree. (Actually a trivial tree since all codes use - * 5 bits.) - */ - -uch _dist_code[DIST_CODE_LEN]; -/* Distance codes. The first 256 values correspond to the distances - * 3 .. 258, the last 256 values correspond to the top 8 bits of - * the 15 bit distances. - */ - -uch _length_code[MAX_MATCH-MIN_MATCH+1]; -/* length code for each normalized match length (0 == MIN_MATCH) */ - -local int base_length[LENGTH_CODES]; -/* First normalized length for each code (0 = MIN_MATCH) */ - -local int base_dist[D_CODES]; -/* First normalized distance for each code (0 = distance of 1) */ - -#else -# include "trees.h" -#endif /* GEN_TREES_H */ - -struct static_tree_desc_s { - const ct_data *static_tree; /* static tree or NULL */ - const intf *extra_bits; /* extra bits for each code or NULL */ - int extra_base; /* base index for extra_bits */ - int elems; /* max number of elements in the tree */ - int max_length; /* max bit length for the codes */ -}; - -local static_tree_desc static_l_desc = -{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; - -local static_tree_desc static_d_desc = -{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; - -local static_tree_desc static_bl_desc = -{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; - -/* =========================================================================== - * Local (static) routines in this file. - */ - -local void tr_static_init OF((void)); -local void init_block OF((deflate_state *s)); -local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); -local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); -local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); -local void build_tree OF((deflate_state *s, tree_desc *desc)); -local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local int build_bl_tree OF((deflate_state *s)); -local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, - int blcodes)); -local void compress_block OF((deflate_state *s, ct_data *ltree, - ct_data *dtree)); -local void set_data_type OF((deflate_state *s)); -local unsigned bi_reverse OF((unsigned value, int length)); -local void bi_windup OF((deflate_state *s)); -local void bi_flush OF((deflate_state *s)); -local void copy_block OF((deflate_state *s, charf *buf, unsigned len, - int header)); - -#ifdef GEN_TREES_H -local void gen_trees_header OF((void)); -#endif - -#ifndef DEBUG -# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) - /* Send a code of the given tree. c and tree must not have side effects */ - -#else /* DEBUG */ -# define send_code(s, c, tree) \ - { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ - send_bits(s, tree[c].Code, tree[c].Len); } -#endif - -/* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ -#define put_short(s, w) { \ - put_byte(s, (uch)((w) & 0xff)); \ - put_byte(s, (uch)((ush)(w) >> 8)); \ -} - -/* =========================================================================== - * Send a value on a given number of bits. - * IN assertion: length <= 16 and value fits in length bits. - */ -#ifdef DEBUG -local void send_bits OF((deflate_state *s, int value, int length)); - -local void send_bits(s, value, length) - deflate_state *s; - int value; /* value to send */ - int length; /* number of bits */ -{ - Tracevv((stderr," l %2d v %4x ", length, value)); - Assert(length > 0 && length <= 15, "invalid length"); - s->bits_sent += (ulg)length; - - /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) - * unused bits in value. - */ - if (s->bi_valid > (int)Buf_size - length) { - s->bi_buf |= (value << s->bi_valid); - put_short(s, s->bi_buf); - s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); - s->bi_valid += length - Buf_size; - } else { - s->bi_buf |= value << s->bi_valid; - s->bi_valid += length; - } -} -#else /* !DEBUG */ - -#define send_bits(s, value, length) \ -{ int len = length;\ - if (s->bi_valid > (int)Buf_size - len) {\ - int val = value;\ - s->bi_buf |= (val << s->bi_valid);\ - put_short(s, s->bi_buf);\ - s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ - s->bi_valid += len - Buf_size;\ - } else {\ - s->bi_buf |= (value) << s->bi_valid;\ - s->bi_valid += len;\ - }\ -} -#endif /* DEBUG */ - - -/* the arguments must not have side effects */ - -/* =========================================================================== - * Initialize the various 'constant' tables. - */ -local void tr_static_init() -{ -#if defined(GEN_TREES_H) || !defined(STDC) - static int static_init_done = 0; - int n; /* iterates over tree elements */ - int bits; /* bit counter */ - int length; /* length value */ - int code; /* code value */ - int dist; /* distance index */ - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - if (static_init_done) return; - - /* For some embedded targets, global variables are not initialized: */ - static_l_desc.static_tree = static_ltree; - static_l_desc.extra_bits = extra_lbits; - static_d_desc.static_tree = static_dtree; - static_d_desc.extra_bits = extra_dbits; - static_bl_desc.extra_bits = extra_blbits; - - /* Initialize the mapping length (0..255) -> length code (0..28) */ - length = 0; - for (code = 0; code < LENGTH_CODES-1; code++) { - base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ - dist = 0; - for (code = 0 ; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ - for ( ; code < D_CODES; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { - _dist_code[256 + dist++] = (uch)code; - } - } - Assert (dist == 256, "tr_static_init: 256+dist != 512"); - - /* Construct the codes of the static literal tree */ - for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; - n = 0; - while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; - while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; - while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; - while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; - /* Codes 286 and 287 do not exist, but we must include them in the - * tree construction to get a canonical Huffman tree (longest code - * all ones) - */ - gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); - - /* The static distance tree is trivial: */ - for (n = 0; n < D_CODES; n++) { - static_dtree[n].Len = 5; - static_dtree[n].Code = bi_reverse((unsigned)n, 5); - } - static_init_done = 1; - -# ifdef GEN_TREES_H - gen_trees_header(); -# endif -#endif /* defined(GEN_TREES_H) || !defined(STDC) */ -} - -/* =========================================================================== - * Genererate the file trees.h describing the static trees. - */ -#ifdef GEN_TREES_H -# ifndef DEBUG -# include -# endif - -# define SEPARATOR(i, last, width) \ - ((i) == (last)? "\n};\n\n" : \ - ((i) % (width) == (width)-1 ? ",\n" : ", ")) - -void gen_trees_header() -{ - FILE *header = fopen("trees.h", "w"); - int i; - - Assert (header != NULL, "Can't open trees.h"); - fprintf(header, - "/* header created automatically with -DGEN_TREES_H */\n\n"); - - fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); - for (i = 0; i < L_CODES+2; i++) { - fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, - static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); - } - - fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); - for (i = 0; i < D_CODES; i++) { - fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, - static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); - } - - fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); - for (i = 0; i < DIST_CODE_LEN; i++) { - fprintf(header, "%2u%s", _dist_code[i], - SEPARATOR(i, DIST_CODE_LEN-1, 20)); - } - - fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); - for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { - fprintf(header, "%2u%s", _length_code[i], - SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); - } - - fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); - for (i = 0; i < LENGTH_CODES; i++) { - fprintf(header, "%1u%s", base_length[i], - SEPARATOR(i, LENGTH_CODES-1, 20)); - } - - fprintf(header, "local const int base_dist[D_CODES] = {\n"); - for (i = 0; i < D_CODES; i++) { - fprintf(header, "%5u%s", base_dist[i], - SEPARATOR(i, D_CODES-1, 10)); - } - - fclose(header); -} -#endif /* GEN_TREES_H */ - -/* =========================================================================== - * Initialize the tree data structures for a new zlib stream. - */ -void _tr_init(s) - deflate_state *s; -{ - tr_static_init(); - - s->l_desc.dyn_tree = s->dyn_ltree; - s->l_desc.stat_desc = &static_l_desc; - - s->d_desc.dyn_tree = s->dyn_dtree; - s->d_desc.stat_desc = &static_d_desc; - - s->bl_desc.dyn_tree = s->bl_tree; - s->bl_desc.stat_desc = &static_bl_desc; - - s->bi_buf = 0; - s->bi_valid = 0; - s->last_eob_len = 8; /* enough lookahead for inflate */ -#ifdef DEBUG - s->compressed_len = 0L; - s->bits_sent = 0L; -#endif - - /* Initialize the first block of the first file: */ - init_block(s); -} - -/* =========================================================================== - * Initialize a new block. - */ -local void init_block(s) - deflate_state *s; -{ - int n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; - for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; - for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; - - s->dyn_ltree[END_BLOCK].Freq = 1; - s->opt_len = s->static_len = 0L; - s->last_lit = s->matches = 0; -} - -#define SMALLEST 1 -/* Index within the heap array of least frequent node in the Huffman tree */ - - -/* =========================================================================== - * Remove the smallest element from the heap and recreate the heap with - * one less element. Updates heap and heap_len. - */ -#define pqremove(s, tree, top) \ -{\ - top = s->heap[SMALLEST]; \ - s->heap[SMALLEST] = s->heap[s->heap_len--]; \ - pqdownheap(s, tree, SMALLEST); \ -} - -/* =========================================================================== - * Compares to subtrees, using the tree depth as tie breaker when - * the subtrees have equal frequency. This minimizes the worst case length. - */ -#define smaller(tree, n, m, depth) \ - (tree[n].Freq < tree[m].Freq || \ - (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) - -/* =========================================================================== - * Restore the heap property by moving down the tree starting at node k, - * exchanging a node with the smallest of its two sons if necessary, stopping - * when the heap property is re-established (each father smaller than its - * two sons). - */ -local void pqdownheap(s, tree, k) - deflate_state *s; - ct_data *tree; /* the tree to restore */ - int k; /* node to move down */ -{ - int v = s->heap[k]; - int j = k << 1; /* left son of k */ - while (j <= s->heap_len) { - /* Set j to the smallest of the two sons: */ - if (j < s->heap_len && - smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { - j++; - } - /* Exit if v is smaller than both sons */ - if (smaller(tree, v, s->heap[j], s->depth)) break; - - /* Exchange v with the smallest son */ - s->heap[k] = s->heap[j]; k = j; - - /* And continue down the tree, setting j to the left son of k */ - j <<= 1; - } - s->heap[k] = v; -} - -/* =========================================================================== - * Compute the optimal bit lengths for a tree and update the total bit length - * for the current block. - * IN assertion: the fields freq and dad are set, heap[heap_max] and - * above are the tree nodes sorted by increasing frequency. - * OUT assertions: the field len is set to the optimal bit length, the - * array bl_count contains the frequencies for each bit length. - * The length opt_len is updated; static_len is also updated if stree is - * not null. - */ -local void gen_bitlen(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ -{ - ct_data *tree = desc->dyn_tree; - int max_code = desc->max_code; - const ct_data *stree = desc->stat_desc->static_tree; - const intf *extra = desc->stat_desc->extra_bits; - int base = desc->stat_desc->extra_base; - int max_length = desc->stat_desc->max_length; - int h; /* heap index */ - int n, m; /* iterate over the tree elements */ - int bits; /* bit length */ - int xbits; /* extra bits */ - ush f; /* frequency */ - int overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; - - /* In a first pass, compute the optimal bit lengths (which may - * overflow in the case of the bit length tree). - */ - tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - - for (h = s->heap_max+1; h < HEAP_SIZE; h++) { - n = s->heap[h]; - bits = tree[tree[n].Dad].Len + 1; - if (bits > max_length) bits = max_length, overflow++; - tree[n].Len = (ush)bits; - /* We overwrite tree[n].Dad which is no longer needed */ - - if (n > max_code) continue; /* not a leaf node */ - - s->bl_count[bits]++; - xbits = 0; - if (n >= base) xbits = extra[n-base]; - f = tree[n].Freq; - s->opt_len += (ulg)f * (bits + xbits); - if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); - } - if (overflow == 0) return; - - Trace((stderr,"\nbit length overflow\n")); - /* This happens for example on obj2 and pic of the Calgary corpus */ - - /* Find the first bit length which could increase: */ - do { - bits = max_length-1; - while (s->bl_count[bits] == 0) bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ - s->bl_count[max_length]--; - /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] - */ - overflow -= 2; - } while (overflow > 0); - - /* Now recompute all bit lengths, scanning in increasing frequency. - * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - * lengths instead of fixing only the wrong ones. This idea is taken - * from 'ar' written by Haruhiko Okumura.) - */ - for (bits = max_length; bits != 0; bits--) { - n = s->bl_count[bits]; - while (n != 0) { - m = s->heap[--h]; - if (m > max_code) continue; - if ((unsigned) tree[m].Len != (unsigned) bits) { - Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); - s->opt_len += ((long)bits - (long)tree[m].Len) - *(long)tree[m].Freq; - tree[m].Len = (ush)bits; - } - n--; - } - } -} - -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -local void gen_codes (tree, max_code, bl_count) - ct_data *tree; /* the tree to decorate */ - int max_code; /* largest code with non zero frequency */ - ushf *bl_count; /* number of codes at each bit length */ -{ - ush next_code[MAX_BITS+1]; /* next code value for each bit length */ - ush code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (code + bl_count[bits-1]) << 1; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; - const ct_data *stree = desc->stat_desc->static_tree; - int elems = desc->stat_desc->elems; - int n, m; /* iterate over heap elements */ - int max_code = -1; /* largest code with non zero frequency */ - int node; /* new node being created */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - s->heap_len = 0, s->heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) { - if (tree[n].Freq != 0) { - s->heap[++(s->heap_len)] = max_code = n; - s->depth[n] = 0; - } else { - tree[n].Len = 0; - } - } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (s->heap_len < 2) { - node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); - tree[node].Freq = 1; - s->depth[node] = 0; - s->opt_len--; if (stree) s->static_len -= stree[node].Len; - /* node is 0 or 1 so it does not have extra bits */ - } - desc->max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - node = elems; /* next internal node of the tree */ - do { - pqremove(s, tree, n); /* n = node of least frequency */ - m = s->heap[SMALLEST]; /* m = node of next least frequency */ - - s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ - s->heap[--(s->heap_max)] = m; - - /* Create a new node father of n and m */ - tree[node].Freq = tree[n].Freq + tree[m].Freq; - s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? - s->depth[n] : s->depth[m]) + 1); - tree[n].Dad = tree[m].Dad = (ush)node; -#ifdef DUMP_BL_TREE - if (tree == s->bl_tree) { - fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", - node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); - } -#endif - /* and insert the new node in the heap */ - s->heap[SMALLEST] = node++; - pqdownheap(s, tree, SMALLEST); - - } while (s->heap_len >= 2); - - s->heap[--(s->heap_max)] = s->heap[SMALLEST]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen(s, (tree_desc *)desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes ((ct_data *)tree, max_code, s->bl_count); -} - -/* =========================================================================== - * Scan a literal or distance tree to determine the frequencies of the codes - * in the bit length tree. - */ -local void scan_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].Len = (ush)0xffff; /* guard */ - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - s->bl_tree[curlen].Freq += count; - } else if (curlen != 0) { - if (curlen != prevlen) s->bl_tree[curlen].Freq++; - s->bl_tree[REP_3_6].Freq++; - } else if (count <= 10) { - s->bl_tree[REPZ_3_10].Freq++; - } else { - s->bl_tree[REPZ_11_138].Freq++; - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Send a literal or distance tree in compressed form, using the codes in - * bl_tree. - */ -local void send_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - /* tree[max_code+1].Len = -1; */ /* guard already set */ - if (nextlen == 0) max_count = 138, min_count = 3; - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - do { send_code(s, curlen, s->bl_tree); } while (--count != 0); - - } else if (curlen != 0) { - if (curlen != prevlen) { - send_code(s, curlen, s->bl_tree); count--; - } - Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); - - } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); - - } else { - send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Construct the Huffman tree for the bit lengths and return the index in - * bl_order of the last bit length code to send. - */ -local int build_bl_tree(s) - deflate_state *s; -{ - int max_blindex; /* index of last bit length code of non zero freq */ - - /* Determine the bit length frequencies for literal and distance trees */ - scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); - scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); - - /* Build the bit length tree: */ - build_tree(s, (tree_desc *)(&(s->bl_desc))); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - */ - - /* Determine the number of bit length codes to send. The pkzip format - * requires that at least 4 bit length codes be sent. (appnote.txt says - * 3 but the actual value used is 4.) - */ - for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { - if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; - } - /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*(max_blindex+1) + 5+5+4; - Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", - s->opt_len, s->static_len)); - - return max_blindex; -} - -/* =========================================================================== - * Send the header for a block using dynamic Huffman trees: the counts, the - * lengths of the bit length codes, the literal tree and the distance tree. - * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - */ -local void send_all_trees(s, lcodes, dcodes, blcodes) - deflate_state *s; - int lcodes, dcodes, blcodes; /* number of codes for each tree */ -{ - int rank; /* index in bl_order */ - - Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); - Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, - "too many codes"); - Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ - for (rank = 0; rank < blcodes; rank++) { - Tracev((stderr, "\nbl code %2d ", bl_order[rank])); - send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); - } - Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ - Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ - Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); -} - -/* =========================================================================== - * Send a stored block - */ -void _tr_stored_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ -{ - send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ -#ifdef DEBUG - s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; - s->compressed_len += (stored_len + 4) << 3; -#endif - copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ -} - -/* =========================================================================== - * Send one empty static block to give enough lookahead for inflate. - * This takes 10 bits, of which 7 may remain in the bit buffer. - * The current inflate code requires 9 bits of lookahead. If the - * last two codes for the previous block (real code plus EOB) were coded - * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode - * the last real code. In this case we send two empty static blocks instead - * of one. (There are no problems if the previous block is stored or fixed.) - * To simplify the code, we assume the worst case of last real code encoded - * on one bit only. - */ -void _tr_align(s) - deflate_state *s; -{ - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); -#ifdef DEBUG - s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ -#endif - bi_flush(s); - /* Of the 10 bits for the empty block, we have already sent - * (10 - bi_valid) bits. The lookahead for the last real code (before - * the EOB of the previous block) was thus at least one plus the length - * of the EOB plus what we have just sent of the empty static block. - */ - if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); -#ifdef DEBUG - s->compressed_len += 10L; -#endif - bi_flush(s); - } - s->last_eob_len = 7; -} - -/* =========================================================================== - * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. - */ -void _tr_flush_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block, or NULL if too old */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ -{ - ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ - int max_blindex = 0; /* index of last bit length code of non zero freq */ - - /* Build the Huffman trees unless a stored block is forced */ - if (s->level > 0) { - - /* Check if the file is binary or text */ - if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) - set_data_type(s); - - /* Construct the literal and distance trees */ - build_tree(s, (tree_desc *)(&(s->l_desc))); - Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - - build_tree(s, (tree_desc *)(&(s->d_desc))); - Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ - - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(s); - - /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; - - Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", - opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - s->last_lit)); - - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; - - } else { - Assert(buf != (char*)0, "lost buf"); - opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ - } - -#ifdef FORCE_STORED - if (buf != (char*)0) { /* force stored block */ -#else - if (stored_len+4 <= opt_lenb && buf != (char*)0) { - /* 4: two words for the lengths */ -#endif - /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - * Otherwise we can't have processed more than WSIZE input bytes since - * the last block flush, because compression would have been - * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - * transform a block into a stored block. - */ - _tr_stored_block(s, buf, stored_len, eof); - -#ifdef FORCE_STATIC - } else if (static_lenb >= 0) { /* force static trees */ -#else - } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { -#endif - send_bits(s, (STATIC_TREES<<1)+eof, 3); - compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); -#ifdef DEBUG - s->compressed_len += 3 + s->static_len; -#endif - } else { - send_bits(s, (DYN_TREES<<1)+eof, 3); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, - max_blindex+1); - compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); -#ifdef DEBUG - s->compressed_len += 3 + s->opt_len; -#endif - } - Assert (s->compressed_len == s->bits_sent, "bad compressed size"); - /* The above check is made mod 2^32, for files larger than 512 MB - * and uLong implemented on 32 bits. - */ - init_block(s); - - if (eof) { - bi_windup(s); -#ifdef DEBUG - s->compressed_len += 7; /* align on byte boundary */ -#endif - } - Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - s->compressed_len-7*eof)); -} - -/* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ -int _tr_tally (s, dist, lc) - deflate_state *s; - unsigned dist; /* distance of matched string */ - unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ -{ - s->d_buf[s->last_lit] = (ush)dist; - s->l_buf[s->last_lit++] = (uch)lc; - if (dist == 0) { - /* lc is the unmatched char */ - s->dyn_ltree[lc].Freq++; - } else { - s->matches++; - /* Here, lc is the match length - MIN_MATCH */ - dist--; /* dist = match distance - 1 */ - Assert((ush)dist < (ush)MAX_DIST(s) && - (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && - (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - - s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; - s->dyn_dtree[d_code(dist)].Freq++; - } - -#ifdef TRUNCATE_BLOCK - /* Try to guess if it is profitable to stop the current block here */ - if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { - /* Compute an upper bound for the compressed length */ - ulg out_length = (ulg)s->last_lit*8L; - ulg in_length = (ulg)((long)s->strstart - s->block_start); - int dcode; - for (dcode = 0; dcode < D_CODES; dcode++) { - out_length += (ulg)s->dyn_dtree[dcode].Freq * - (5L+extra_dbits[dcode]); - } - out_length >>= 3; - Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", - s->last_lit, in_length, out_length, - 100L - out_length*100L/in_length)); - if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; - } -#endif - return (s->last_lit == s->lit_bufsize-1); - /* We avoid equality with lit_bufsize because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ -} - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -local void compress_block(s, ltree, dtree) - deflate_state *s; - ct_data *ltree; /* literal tree */ - ct_data *dtree; /* distance tree */ -{ - unsigned dist; /* distance of matched string */ - int lc; /* match length or unmatched char (if dist == 0) */ - unsigned lx = 0; /* running index in l_buf */ - unsigned code; /* the code to send */ - int extra; /* number of extra bits to send */ - - if (s->last_lit != 0) do { - dist = s->d_buf[lx]; - lc = s->l_buf[lx++]; - if (dist == 0) { - send_code(s, lc, ltree); /* send a literal byte */ - Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = _length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra != 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra != 0) { - dist -= base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ - Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, - "pendingBuf overflow"); - - } while (lx < s->last_lit); - - send_code(s, END_BLOCK, ltree); - s->last_eob_len = ltree[END_BLOCK].Len; -} - -/* =========================================================================== - * Set the data type to BINARY or TEXT, using a crude approximation: - * set it to Z_TEXT if all symbols are either printable characters (33 to 255) - * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. - * IN assertion: the fields Freq of dyn_ltree are set. - */ -local void set_data_type(s) - deflate_state *s; -{ - int n; - - for (n = 0; n < 9; n++) - if (s->dyn_ltree[n].Freq != 0) - break; - if (n == 9) - for (n = 14; n < 32; n++) - if (s->dyn_ltree[n].Freq != 0) - break; - s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; -} - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -local unsigned bi_reverse(code, len) - unsigned code; /* the value to invert */ - int len; /* its bit length */ -{ - register unsigned res = 0; - do { - res |= code & 1; - code >>= 1, res <<= 1; - } while (--len > 0); - return res >> 1; -} - -/* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ -local void bi_flush(s) - deflate_state *s; -{ - if (s->bi_valid == 16) { - put_short(s, s->bi_buf); - s->bi_buf = 0; - s->bi_valid = 0; - } else if (s->bi_valid >= 8) { - put_byte(s, (Byte)s->bi_buf); - s->bi_buf >>= 8; - s->bi_valid -= 8; - } -} - -/* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ -local void bi_windup(s) - deflate_state *s; -{ - if (s->bi_valid > 8) { - put_short(s, s->bi_buf); - } else if (s->bi_valid > 0) { - put_byte(s, (Byte)s->bi_buf); - } - s->bi_buf = 0; - s->bi_valid = 0; -#ifdef DEBUG - s->bits_sent = (s->bits_sent+7) & ~7; -#endif -} - -/* =========================================================================== - * Copy a stored block, storing first the length and its - * one's complement if requested. - */ -local void copy_block(s, buf, len, header) - deflate_state *s; - charf *buf; /* the input data */ - unsigned len; /* its length */ - int header; /* true if block header must be written */ -{ - bi_windup(s); /* align on byte boundary */ - s->last_eob_len = 8; /* enough lookahead for inflate */ - - if (header) { - put_short(s, (ush)len); - put_short(s, (ush)~len); -#ifdef DEBUG - s->bits_sent += 2*16; -#endif - } -#ifdef DEBUG - s->bits_sent += (ulg)len<<3; -#endif - while (len--) { - put_byte(s, *buf++); - } -} +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2005 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) + set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to BINARY or TEXT, using a crude approximation: + * set it to Z_TEXT if all symbols are either printable characters (33 to 255) + * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local void set_data_type(s) + deflate_state *s; +{ + int n; + + for (n = 0; n < 9; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + if (n == 9) + for (n = 14; n < 32; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/3rdparty/zlib/trees.h b/3rdparty/zlib/trees.h index 1ca868b848..72facf900f 100644 --- a/3rdparty/zlib/trees.h +++ b/3rdparty/zlib/trees.h @@ -1,128 +1,128 @@ -/* header created automatically with -DGEN_TREES_H */ - -local const ct_data static_ltree[L_CODES+2] = { -{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, -{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, -{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, -{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, -{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, -{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, -{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, -{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, -{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, -{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, -{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, -{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, -{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, -{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, -{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, -{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, -{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, -{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, -{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, -{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, -{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, -{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, -{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, -{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, -{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, -{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, -{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, -{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, -{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, -{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, -{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, -{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, -{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, -{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, -{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, -{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, -{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, -{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, -{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, -{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, -{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, -{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, -{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, -{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, -{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, -{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, -{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, -{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, -{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, -{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, -{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, -{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, -{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, -{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, -{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, -{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, -{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, -{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} -}; - -local const ct_data static_dtree[D_CODES] = { -{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, -{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, -{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, -{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, -{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, -{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} -}; - -const uch _dist_code[DIST_CODE_LEN] = { - 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, - 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, -10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, -11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, -12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, -18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 -}; - -const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, -13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, -17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, -19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, -21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, -22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 -}; - -local const int base_length[LENGTH_CODES] = { -0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, -64, 80, 96, 112, 128, 160, 192, 224, 0 -}; - -local const int base_dist[D_CODES] = { - 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, - 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, - 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 -}; - +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/3rdparty/zlib/uncompr.c b/3rdparty/zlib/uncompr.c index ad6db0a67c..b59e3d0def 100644 --- a/3rdparty/zlib/uncompr.c +++ b/3rdparty/zlib/uncompr.c @@ -1,61 +1,61 @@ -/* uncompr.c -- decompress a memory buffer - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -/* =========================================================================== - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted. -*/ -int ZEXPORT uncompress (dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ - z_stream stream; - int err; - - stream.next_in = (Bytef*)source; - stream.avail_in = (uInt)sourceLen; - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; - - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; - - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - - err = inflateInit(&stream); - if (err != Z_OK) return err; - - err = inflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - inflateEnd(&stream); - if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) - return Z_DATA_ERROR; - return err; - } - *destLen = stream.total_out; - - err = inflateEnd(&stream); - return err; -} +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/3rdparty/zlib/zconf.h b/3rdparty/zlib/zconf.h index e3b0c962e3..03a9431c8b 100644 --- a/3rdparty/zlib/zconf.h +++ b/3rdparty/zlib/zconf.h @@ -1,332 +1,332 @@ -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#ifndef ZCONF_H -#define ZCONF_H - -/* - * If you *really* need a unique prefix for all types and library functions, - * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. - */ -#ifdef Z_PREFIX -# define deflateInit_ z_deflateInit_ -# define deflate z_deflate -# define deflateEnd z_deflateEnd -# define inflateInit_ z_inflateInit_ -# define inflate z_inflate -# define inflateEnd z_inflateEnd -# define deflateInit2_ z_deflateInit2_ -# define deflateSetDictionary z_deflateSetDictionary -# define deflateCopy z_deflateCopy -# define deflateReset z_deflateReset -# define deflateParams z_deflateParams -# define deflateBound z_deflateBound -# define deflatePrime z_deflatePrime -# define inflateInit2_ z_inflateInit2_ -# define inflateSetDictionary z_inflateSetDictionary -# define inflateSync z_inflateSync -# define inflateSyncPoint z_inflateSyncPoint -# define inflateCopy z_inflateCopy -# define inflateReset z_inflateReset -# define inflateBack z_inflateBack -# define inflateBackEnd z_inflateBackEnd -# define compress z_compress -# define compress2 z_compress2 -# define compressBound z_compressBound -# define uncompress z_uncompress -# define adler32 z_adler32 -# define crc32 z_crc32 -# define get_crc_table z_get_crc_table -# define zError z_zError - -# define alloc_func z_alloc_func -# define free_func z_free_func -# define in_func z_in_func -# define out_func z_out_func -# define Byte z_Byte -# define uInt z_uInt -# define uLong z_uLong -# define Bytef z_Bytef -# define charf z_charf -# define intf z_intf -# define uIntf z_uIntf -# define uLongf z_uLongf -# define voidpf z_voidpf -# define voidp z_voidp -#endif - -#if defined(__MSDOS__) && !defined(MSDOS) -# define MSDOS -#endif -#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) -# define OS2 -#endif -#if defined(_WINDOWS) && !defined(WINDOWS) -# define WINDOWS -#endif -#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) -# ifndef WIN32 -# define WIN32 -# endif -#endif -#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) -# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) -# ifndef SYS16BIT -# define SYS16BIT -# endif -# endif -#endif - -/* - * Compile with -DMAXSEG_64K if the alloc function cannot allocate more - * than 64k bytes at a time (needed on systems with 16-bit int). - */ -#ifdef SYS16BIT -# define MAXSEG_64K -#endif -#ifdef MSDOS -# define UNALIGNED_OK -#endif - -#ifdef __STDC_VERSION__ -# ifndef STDC -# define STDC -# endif -# if __STDC_VERSION__ >= 199901L -# ifndef STDC99 -# define STDC99 -# endif -# endif -#endif -#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) -# define STDC -#endif -#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) -# define STDC -#endif -#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) -# define STDC -#endif -#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) -# define STDC -#endif - -#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ -# define STDC -#endif - -#ifndef STDC -# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ -# define const /* note: need a more gentle solution here */ -# endif -#endif - -/* Some Mac compilers merge all .h files incorrectly: */ -#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) -# define NO_DUMMY_DECL -#endif - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# ifdef MAXSEG_64K -# define MAX_MEM_LEVEL 8 -# else -# define MAX_MEM_LEVEL 9 -# endif -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2. - * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files - * created by gzip. (Files created by minigzip can still be extracted by - * gzip.) - */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - (1 << (windowBits+2)) + (1 << (memLevel+9)) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects. -*/ - - /* Type declarations */ - -#ifndef OF /* function prototypes */ -# ifdef STDC -# define OF(args) args -# else -# define OF(args) () -# endif -#endif - -/* The following definitions for FAR are needed only for MSDOS mixed - * model programming (small or medium model with some far allocations). - * This was tested only with MSC; for other MSDOS compilers you may have - * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, - * just define FAR to be empty. - */ -#ifdef SYS16BIT -# if defined(M_I86SM) || defined(M_I86MM) - /* MSC small or medium model */ -# define SMALL_MEDIUM -# ifdef _MSC_VER -# define FAR _far -# else -# define FAR far -# endif -# endif -# if (defined(__SMALL__) || defined(__MEDIUM__)) - /* Turbo C small or medium model */ -# define SMALL_MEDIUM -# ifdef __BORLANDC__ -# define FAR _far -# else -# define FAR far -# endif -# endif -#endif - -#if defined(WINDOWS) || defined(WIN32) - /* If building or using zlib as a DLL, define ZLIB_DLL. - * This is not mandatory, but it offers a little performance increase. - */ -# ifdef ZLIB_DLL -# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) -# ifdef ZLIB_INTERNAL -# define ZEXTERN extern __declspec(dllexport) -# else -# define ZEXTERN extern __declspec(dllimport) -# endif -# endif -# endif /* ZLIB_DLL */ - /* If building or using zlib with the WINAPI/WINAPIV calling convention, - * define ZLIB_WINAPI. - * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. - */ -# ifdef ZLIB_WINAPI -# ifdef FAR -# undef FAR -# endif -# include - /* No need for _export, use ZLIB.DEF instead. */ - /* For complete Windows compatibility, use WINAPI, not __stdcall. */ -# define ZEXPORT WINAPI -# ifdef WIN32 -# define ZEXPORTVA WINAPIV -# else -# define ZEXPORTVA FAR CDECL -# endif -# endif -#endif - -#if defined (__BEOS__) -# ifdef ZLIB_DLL -# ifdef ZLIB_INTERNAL -# define ZEXPORT __declspec(dllexport) -# define ZEXPORTVA __declspec(dllexport) -# else -# define ZEXPORT __declspec(dllimport) -# define ZEXPORTVA __declspec(dllimport) -# endif -# endif -#endif - -#ifndef ZEXTERN -# define ZEXTERN extern -#endif -#ifndef ZEXPORT -# define ZEXPORT -#endif -#ifndef ZEXPORTVA -# define ZEXPORTVA -#endif - -#ifndef FAR -# define FAR -#endif - -#if !defined(__MACTYPES__) -typedef unsigned char Byte; /* 8 bits */ -#endif -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ - -#ifdef SMALL_MEDIUM - /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ -# define Bytef Byte FAR -#else - typedef Byte FAR Bytef; -#endif -typedef char FAR charf; -typedef int FAR intf; -typedef uInt FAR uIntf; -typedef uLong FAR uLongf; - -#ifdef STDC - typedef void const *voidpc; - typedef void FAR *voidpf; - typedef void *voidp; -#else - typedef Byte const *voidpc; - typedef Byte FAR *voidpf; - typedef Byte *voidp; -#endif - -#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ -# include /* for off_t */ -# include /* for SEEK_* and off_t */ -# ifdef VMS -# include /* for off_t */ -# endif -# define z_off_t off_t -#endif -#ifndef SEEK_SET -# define SEEK_SET 0 /* Seek from beginning of file. */ -# define SEEK_CUR 1 /* Seek from current position. */ -# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ -#endif -#ifndef z_off_t -# define z_off_t long -#endif - -#if defined(__OS400__) -# define NO_vsnprintf -#endif - -#if defined(__MVS__) -# define NO_vsnprintf -# ifdef FAR -# undef FAR -# endif -#endif - -/* MVS linker does not support external names larger than 8 bytes */ -#if defined(__MVS__) -# pragma map(deflateInit_,"DEIN") -# pragma map(deflateInit2_,"DEIN2") -# pragma map(deflateEnd,"DEEND") -# pragma map(deflateBound,"DEBND") -# pragma map(inflateInit_,"ININ") -# pragma map(inflateInit2_,"ININ2") -# pragma map(inflateEnd,"INEND") -# pragma map(inflateSync,"INSY") -# pragma map(inflateSetDictionary,"INSEDI") -# pragma map(compressBound,"CMBND") -# pragma map(inflate_table,"INTABL") -# pragma map(inflate_fast,"INFA") -# pragma map(inflate_copyright,"INCOPY") -#endif - -#endif /* ZCONF_H */ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/3rdparty/zlib/zlib.h b/3rdparty/zlib/zlib.h index 62d0e4675b..022817927c 100644 --- a/3rdparty/zlib/zlib.h +++ b/3rdparty/zlib/zlib.h @@ -1,1357 +1,1357 @@ -/* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.3, July 18th, 2005 - - Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - - - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). -*/ - -#ifndef ZLIB_H -#define ZLIB_H - -#include "zconf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define ZLIB_VERSION "1.2.3" -#define ZLIB_VERNUM 0x1230 - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed - data. This version of the library supports only one compression method - (deflation) but other algorithms will be added later and will have the same - stream interface. - - Compression can be done in a single step if the buffers are large - enough (for example if an input file is mmap'ed), or can be done by - repeated calls of the compression function. In the latter case, the - application must provide more input and/or consume the output - (providing more output space) before each call. - - The compressed data format used by default by the in-memory functions is - the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped - around a deflate stream, which is itself documented in RFC 1951. - - The library also supports reading and writing files in gzip (.gz) format - with an interface similar to that of stdio using the functions that start - with "gz". The gzip format is different from the zlib format. gzip is a - gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. - - This library can optionally read and write gzip streams in memory as well. - - The zlib format was designed to be compact and fast for use in memory - and on communications channels. The gzip format was designed for single- - file compression on file systems, has a larger header than zlib to maintain - directory information, and uses a different, slower check method than zlib. - - The library does not install any signal handler. The decoder checks - the consistency of the compressed data, so the library should never - crash even in case of corrupted input. -*/ - -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address)); - -struct internal_state; - -typedef struct z_stream_s { - Bytef *next_in; /* next input byte */ - uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total nb of input bytes read so far */ - - Bytef *next_out; /* next output byte should be put there */ - uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total nb of bytes output so far */ - - char *msg; /* last error message, NULL if no error */ - struct internal_state FAR *state; /* not visible by applications */ - - alloc_func zalloc; /* used to allocate the internal state */ - free_func zfree; /* used to free the internal state */ - voidpf opaque; /* private data object passed to zalloc and zfree */ - - int data_type; /* best guess about the data type: binary or text */ - uLong adler; /* adler32 value of the uncompressed data */ - uLong reserved; /* reserved for future use */ -} z_stream; - -typedef z_stream FAR *z_streamp; - -/* - gzip header information passed to and from zlib routines. See RFC 1952 - for more details on the meanings of these fields. -*/ -typedef struct gz_header_s { - int text; /* true if compressed data believed to be text */ - uLong time; /* modification time */ - int xflags; /* extra flags (not used when writing a gzip file) */ - int os; /* operating system */ - Bytef *extra; /* pointer to extra field or Z_NULL if none */ - uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ - uInt extra_max; /* space at extra (only when reading header) */ - Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ - uInt name_max; /* space at name (only when reading header) */ - Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ - uInt comm_max; /* space at comment (only when reading header) */ - int hcrc; /* true if there was or will be a header crc */ - int done; /* true when done reading gzip header (not used - when writing a gzip file) */ -} gz_header; - -typedef gz_header FAR *gz_headerp; - -/* - The application must update next_in and avail_in when avail_in has - dropped to zero. It must update next_out and avail_out when avail_out - has dropped to zero. The application must initialize zalloc, zfree and - opaque before calling the init function. All other fields are set by the - compression library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - If zlib is used in a multi-threaded application, zalloc and zfree must be - thread safe. - - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this - if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, - pointers returned by zalloc for objects of exactly 65536 bytes *must* - have their offset normalized to zero. The default allocation function - provided by this library ensures this (see zutil.c). To reduce memory - requirements and avoid any allocation of 64K objects, at the expense of - compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or - progress reports. After compression, total_in holds the total size of - the uncompressed data and may be saved for use in the decompressor - (particularly if the decompressor wants to decompress everything in - a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ -#define Z_SYNC_FLUSH 2 -#define Z_FULL_FLUSH 3 -#define Z_FINISH 4 -#define Z_BLOCK 5 -/* Allowed flush values; see deflate() and inflate() below for details */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_NEED_DICT 2 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -#define Z_VERSION_ERROR (-6) -/* Return codes for the compression/decompression functions. Negative - * values are errors, positive values are used for special but normal events. - */ - -#define Z_NO_COMPRESSION 0 -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_RLE 3 -#define Z_FIXED 4 -#define Z_DEFAULT_STRATEGY 0 -/* compression strategy; see deflateInit2() below for details */ - -#define Z_BINARY 0 -#define Z_TEXT 1 -#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ -#define Z_UNKNOWN 2 -/* Possible values of the data_type field (though see inflate()) */ - -#define Z_DEFLATED 8 -/* The deflate compression method (the only one supported in this version) */ - -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - -#define zlib_version zlibVersion() -/* for compatibility with versions < 1.0.2 */ - - /* basic functions */ - -ZEXTERN const char * ZEXPORT zlibVersion OF((void)); -/* The application can compare zlibVersion and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is - not compatible with the zlib.h header file used by the application. - This check is automatically made by deflateInit and inflateInit. - */ - -/* -ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); - - Initializes the internal stream state for compression. The fields - zalloc, zfree and opaque must be initialized before by the caller. - If zalloc and zfree are set to Z_NULL, deflateInit updates them to - use default allocation functions. - - The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: - 1 gives best speed, 9 gives best compression, 0 gives no compression at - all (the input data is simply copied a block at a time). - Z_DEFAULT_COMPRESSION requests a default compromise between speed and - compression (currently equivalent to level 6). - - deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if level is not a valid compression level, - Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible - with the version assumed by the caller (ZLIB_VERSION). - msg is set to null if there is no error message. deflateInit does not - perform any compression: this will be done by deflate(). -*/ - - -ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); -/* - deflate compresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce some - output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. deflate performs one or both of the - following actions: - - - Compress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in and avail_in are updated and - processing will resume at this point for the next call of deflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. This action is forced if the parameter flush is non zero. - Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary (in interactive applications). - Some output may be provided even if flush is not set. - - Before the call of deflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating avail_in or avail_out accordingly; avail_out - should never be zero before the call. The application can consume the - compressed output when it wants, for example when the output buffer is full - (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK - and with zero avail_out, it must be called again after making room in the - output buffer because there might be more output pending. - - Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to - decide how much data to accumualte before producing output, in order to - maximize compression. - - If the parameter flush is set to Z_SYNC_FLUSH, all pending output is - flushed to the output buffer and the output is aligned on a byte boundary, so - that the decompressor can get all input data available so far. (In particular - avail_in is zero after the call if enough output space has been provided - before the call.) Flushing may degrade compression for some compression - algorithms and so it should be used only when necessary. - - If flush is set to Z_FULL_FLUSH, all output is flushed as with - Z_SYNC_FLUSH, and the compression state is reset so that decompression can - restart from this point if previous compressed data has been damaged or if - random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - compression. - - If deflate returns with avail_out == 0, this function must be called again - with the same value of the flush parameter and more output space (updated - avail_out), until the flush is complete (deflate returns with non-zero - avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that - avail_out is greater than six to avoid repeated flush markers due to - avail_out == 0 on return. - - If the parameter flush is set to Z_FINISH, pending input is processed, - pending output is flushed and deflate returns with Z_STREAM_END if there - was enough output space; if deflate returns with Z_OK, this function must be - called again with Z_FINISH and more output space (updated avail_out) but no - more input data, until it returns with Z_STREAM_END or an error. After - deflate has returned Z_STREAM_END, the only possible operations on the - stream are deflateReset or deflateEnd. - - Z_FINISH can be used immediately after deflateInit if all the compression - is to be done in a single step. In this case, avail_out must be at least - the value returned by deflateBound (see below). If deflate does not return - Z_STREAM_END, then it must be called again as described above. - - deflate() sets strm->adler to the adler32 checksum of all input read - so far (that is, total_in bytes). - - deflate() may update strm->data_type if it can make a good guess about - the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered - binary. This field is only for information purposes and does not affect - the compression algorithm in any manner. - - deflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if all input has been - consumed and all output has been produced (only when flush is set to - Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible - (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not - fatal, and deflate() can be called again with more input and more output - space to continue compressing. -*/ - - -ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the - stream state was inconsistent, Z_DATA_ERROR if the stream was freed - prematurely (some input or output was discarded). In the error case, - msg may be set but then points to a static string (which must not be - deallocated). -*/ - - -/* -ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); - - Initializes the internal stream state for decompression. The fields - next_in, avail_in, zalloc, zfree and opaque must be initialized before by - the caller. If next_in is not Z_NULL and avail_in is large enough (the exact - value depends on the compression method), inflateInit determines the - compression method from the zlib header and allocates all data structures - accordingly; otherwise the allocation will be deferred to the first call of - inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to - use default allocation functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller. msg is set to null if there is no error - message. inflateInit does not perform any decompression apart from reading - the zlib header if present: this will be done by inflate(). (So next_in and - avail_in may be modified, but next_out and avail_out are unchanged.) -*/ - - -ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); -/* - inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce - some output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. inflate performs one or both of the - following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing - will resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() provides as much output as possible, until there - is no more input data or no more space in the output buffer (see below - about the flush parameter). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating the next_* and avail_* values accordingly. - The application can consume the uncompressed output when it wants, for - example when the output buffer is full (avail_out == 0), or after each - call of inflate(). If inflate returns Z_OK and with zero avail_out, it - must be called again after making room in the output buffer because there - might be more output pending. - - The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, - Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much - output as possible to the output buffer. Z_BLOCK requests that inflate() stop - if and when it gets to the next deflate block boundary. When decoding the - zlib or gzip format, this will cause inflate() to return immediately after - the header and before the first block. When doing a raw inflate, inflate() - will go ahead and process the first block, and will return when it gets to - the end of that block, or when it runs out of data. - - The Z_BLOCK option assists in appending to or combining deflate streams. - Also to assist in this, on return inflate() will set strm->data_type to the - number of unused bits in the last byte taken from strm->next_in, plus 64 - if inflate() is currently decoding the last block in the deflate stream, - plus 128 if inflate() returned immediately after decoding an end-of-block - code or decoding the complete header up to just before the first byte of the - deflate stream. The end-of-block will not be indicated until all of the - uncompressed data from that block has been written to strm->next_out. The - number of unused bits may in general be greater than seven, except when - bit 7 of data_type is set, in which case the number of unused bits will be - less than eight. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step - (a single call of inflate), the parameter flush should be set to - Z_FINISH. In this case all pending input is processed and all pending - output is flushed; avail_out must be large enough to hold all the - uncompressed data. (The size of the uncompressed data may have been saved - by the compressor for this purpose.) The next operation on this stream must - be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster approach - may be used for the single inflate() call. - - In this implementation, inflate() always flushes as much output as - possible to the output buffer, and always uses the faster approach on the - first call. So the only effect of the flush parameter in this implementation - is on the return value of inflate(), as noted below, or when it returns early - because Z_BLOCK is used. - - If a preset dictionary is needed after this call (see inflateSetDictionary - below), inflate sets strm->adler to the adler32 checksum of the dictionary - chosen by the compressor and returns Z_NEED_DICT; otherwise it sets - strm->adler to the adler32 checksum of all output produced so far (that is, - total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described - below. At the end of the stream, inflate() checks that its computed adler32 - checksum is equal to that saved by the compressor and returns Z_STREAM_END - only if the checksum is correct. - - inflate() will decompress and check either zlib-wrapped or gzip-wrapped - deflate data. The header type is detected automatically. Any information - contained in the gzip header is not retained, so applications that need that - information should instead use raw inflate, see inflateInit2() below, or - inflateBack() and perform their own processing of the gzip header and - trailer. - - inflate() returns Z_OK if some progress has been made (more input processed - or more output produced), Z_STREAM_END if the end of the compressed data has - been reached and all uncompressed output has been produced, Z_NEED_DICT if a - preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect check - value), Z_STREAM_ERROR if the stream structure was inconsistent (for example - if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, - Z_BUF_ERROR if no progress is possible or if there was not enough room in the - output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and - inflate() can be called again with more input and more output space to - continue decompressing. If Z_DATA_ERROR is returned, the application may then - call inflateSync() to look for a good compression block if a partial recovery - of the data is desired. -*/ - - -ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). -*/ - - /* Advanced functions */ - -/* - The following functions are needed only in some special applications. -*/ - -/* -ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); - - This is another version of deflateInit with more compression options. The - fields next_in, zalloc, zfree and opaque must be initialized before by - the caller. - - The method parameter is the compression method. It must be Z_DEFLATED in - this version of the library. - - The windowBits parameter is the base two logarithm of the window size - (the size of the history buffer). It should be in the range 8..15 for this - version of the library. Larger values of this parameter result in better - compression at the expense of memory usage. The default value is 15 if - deflateInit is used instead. - - windowBits can also be -8..-15 for raw deflate. In this case, -windowBits - determines the window size. deflate() will then generate raw deflate data - with no zlib header or trailer, and will not compute an adler32 check value. - - windowBits can also be greater than 15 for optional gzip encoding. Add - 16 to windowBits to write a simple gzip header and trailer around the - compressed data instead of a zlib wrapper. The gzip header will have no - file name, no extra data, no comment, no modification time (set to zero), - no header crc, and the operating system will be set to 255 (unknown). If a - gzip stream is being written, strm->adler is a crc32 instead of an adler32. - - The memLevel parameter specifies how much memory should be allocated - for the internal compression state. memLevel=1 uses minimum memory but - is slow and reduces compression ratio; memLevel=9 uses maximum memory - for optimal speed. The default value is 8. See zconf.h for total memory - usage as a function of windowBits and memLevel. - - The strategy parameter is used to tune the compression algorithm. Use the - value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match), or Z_RLE to limit match distances to one (run-length - encoding). Filtered data consists mostly of small values with a somewhat - random distribution. In this case, the compression algorithm is tuned to - compress them better. The effect of Z_FILTERED is to force more Huffman - coding and less string matching; it is somewhat intermediate between - Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as - Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy - parameter only affects the compression ratio but not the correctness of the - compressed output even if it is not set appropriately. Z_FIXED prevents the - use of dynamic Huffman codes, allowing for a simpler decoder for special - applications. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid - method). msg is set to null if there is no error message. deflateInit2 does - not perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the compression dictionary from the given byte sequence - without producing any compressed output. This function must be called - immediately after deflateInit, deflateInit2 or deflateReset, before any - call of deflate. The compressor and decompressor must use exactly the same - dictionary (see inflateSetDictionary). - - The dictionary should consist of strings (byte sequences) that are likely - to be encountered later in the data to be compressed, with the most commonly - used strings preferably put towards the end of the dictionary. Using a - dictionary is most useful when the data to be compressed is short and can be - predicted with good accuracy; the data can then be compressed better than - with the default empty dictionary. - - Depending on the size of the compression data structures selected by - deflateInit or deflateInit2, a part of the dictionary may in effect be - discarded, for example if the dictionary is larger than the window size in - deflate or deflate2. Thus the strings most likely to be useful should be - put at the end of the dictionary, not at the front. In addition, the - current implementation of deflate will use at most the window size minus - 262 bytes of the provided dictionary. - - Upon return of this function, strm->adler is set to the adler32 value - of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The adler32 value - applies to the whole dictionary even if only a subset of the dictionary is - actually used by the compressor.) If a raw deflate was requested, then the - adler32 value is not computed and strm->adler is not set. - - deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent (for example if deflate has already been called for this stream - or if the compression method is bsort). deflateSetDictionary does not - perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when several compression strategies will be - tried, for example when there are several ways of pre-processing the input - data with a filter. The streams that will be discarded should then be freed - by calling deflateEnd. Note that deflateCopy duplicates the internal - compression state which can be quite large, so this strategy is slow and - can consume lots of memory. - - deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); -/* - This function is equivalent to deflateEnd followed by deflateInit, - but does not free and reallocate all the internal compression state. - The stream will keep the same compression level and any other attributes - that may have been set by deflateInit2. - - deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, - int level, - int strategy)); -/* - Dynamically update the compression level and compression strategy. The - interpretation of level and strategy is as in deflateInit2. This can be - used to switch between compression and straight copy of the input data, or - to switch to a different kind of input data requiring a different - strategy. If the compression level is changed, the input available so far - is compressed with the old level (and may be flushed); the new level will - take effect only at the next call of deflate(). - - Before the call of deflateParams, the stream state must be set as for - a call of deflate(), since the currently available input may have to - be compressed and flushed. In particular, strm->avail_out must be non-zero. - - deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source - stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR - if strm->avail_out was zero. -*/ - -ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, - int good_length, - int max_lazy, - int nice_length, - int max_chain)); -/* - Fine tune deflate's internal compression parameters. This should only be - used by someone who understands the algorithm used by zlib's deflate for - searching for the best matching string, and even then only by the most - fanatic optimizer trying to squeeze out the last compressed bit for their - specific input data. Read the deflate.c source code for the meaning of the - max_lazy, good_length, nice_length, and max_chain parameters. - - deflateTune() can be called after deflateInit() or deflateInit2(), and - returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. - */ - -ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, - uLong sourceLen)); -/* - deflateBound() returns an upper bound on the compressed size after - deflation of sourceLen bytes. It must be called after deflateInit() - or deflateInit2(). This would be used to allocate an output buffer - for deflation in a single pass, and so would be called before deflate(). -*/ - -ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - deflatePrime() inserts bits in the deflate output stream. The intent - is that this function is used to start off the deflate output with the - bits leftover from a previous deflate stream when appending to it. As such, - this function can only be used for raw deflate, and must be used before the - first deflate() call after a deflateInit2() or deflateReset(). bits must be - less than or equal to 16, and that many of the least significant bits of - value will be inserted in the output. - - deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, - gz_headerp head)); -/* - deflateSetHeader() provides gzip header information for when a gzip - stream is requested by deflateInit2(). deflateSetHeader() may be called - after deflateInit2() or deflateReset() and before the first call of - deflate(). The text, time, os, extra field, name, and comment information - in the provided gz_header structure are written to the gzip header (xflag is - ignored -- the extra flags are set according to the compression level). The - caller must assure that, if not Z_NULL, name and comment are terminated with - a zero byte, and that if extra is not Z_NULL, that extra_len bytes are - available there. If hcrc is true, a gzip header crc is included. Note that - the current versions of the command-line version of gzip (up through version - 1.3.x) do not support header crc's, and will report that it is a "multi-part - gzip file" and give up. - - If deflateSetHeader is not used, the default gzip header has text false, - the time set to zero, and os set to 255, with no extra, name, or comment - fields. The gzip header is returned to the default state by deflateReset(). - - deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, - int windowBits)); - - This is another version of inflateInit with an extra parameter. The - fields next_in, avail_in, zalloc, zfree and opaque must be initialized - before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library. The default value is 15 if inflateInit is used - instead. windowBits must be greater than or equal to the windowBits value - provided to deflateInit2() while compressing, or it must be equal to 15 if - deflateInit2() was not used. If a compressed stream with a larger window - size is given as input, inflate() will return with the error code - Z_DATA_ERROR instead of trying to allocate a larger window. - - windowBits can also be -8..-15 for raw inflate. In this case, -windowBits - determines the window size. inflate() will then process raw deflate data, - not looking for a zlib or gzip header, not generating a check value, and not - looking for any check values for comparison at the end of the stream. This - is for use with other formats that use the deflate compressed data format - such as zip. Those formats provide their own check values. If a custom - format is developed using the raw deflate format for compressed data, it is - recommended that a check value such as an adler32 or a crc32 be applied to - the uncompressed data as is done in the zlib, gzip, and zip formats. For - most applications, the zlib format should be used as is. Note that comments - above on the use in deflateInit2() applies to the magnitude of windowBits. - - windowBits can also be greater than 15 for optional gzip decoding. Add - 32 to windowBits to enable zlib and gzip decoding with automatic header - detection, or add 16 to decode only the gzip format (the zlib format will - return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is - a crc32 instead of an adler32. - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg - is set to null if there is no error message. inflateInit2 does not perform - any decompression apart from reading the zlib header if present: this will - be done by inflate(). (So next_in and avail_in may be modified, but next_out - and avail_out are unchanged.) -*/ - -ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate, - if that call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the adler32 value returned by that call of inflate. - The compressor and decompressor must use exactly the same dictionary (see - deflateSetDictionary). For raw inflate, this function can be called - immediately after inflateInit2() or inflateReset() and before any call of - inflate() to set the dictionary. The application must insure that the - dictionary that was used for compression is provided. - - inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect adler32 value). inflateSetDictionary does not - perform any decompression: this will be done by subsequent calls of - inflate(). -*/ - -ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); -/* - Skips invalid compressed data until a full flush point (see above the - description of deflate with Z_FULL_FLUSH) can be found, or until all - available input is skipped. No output is provided. - - inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR - if no more input was provided, Z_DATA_ERROR if no flush point has been found, - or Z_STREAM_ERROR if the stream structure was inconsistent. In the success - case, the application may save the current current value of total_in which - indicates where valid compressed data was found. In the error case, the - application may repeatedly call inflateSync, providing more input each time, - until success or end of the input data. -*/ - -ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when randomly accessing a large stream. The - first pass through the stream can periodically record the inflate state, - allowing restarting inflate at those points when randomly accessing the - stream. - - inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); -/* - This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate all the internal decompression state. - The stream will keep attributes that may have been set by inflateInit2. - - inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - This function inserts bits in the inflate input stream. The intent is - that this function is used to start inflating at a bit position in the - middle of a byte. The provided bits will be used before any bytes are used - from next_in. This function should only be used with raw inflate, and - should be used before the first inflate() call after inflateInit2() or - inflateReset(). bits must be less than or equal to 16, and that many of the - least significant bits of value will be inserted in the input. - - inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, - gz_headerp head)); -/* - inflateGetHeader() requests that gzip header information be stored in the - provided gz_header structure. inflateGetHeader() may be called after - inflateInit2() or inflateReset(), and before the first call of inflate(). - As inflate() processes the gzip stream, head->done is zero until the header - is completed, at which time head->done is set to one. If a zlib stream is - being decoded, then head->done is set to -1 to indicate that there will be - no gzip header information forthcoming. Note that Z_BLOCK can be used to - force inflate() to return immediately after header processing is complete - and before any actual data is decompressed. - - The text, time, xflags, and os fields are filled in with the gzip header - contents. hcrc is set to true if there is a header CRC. (The header CRC - was valid if done is set to one.) If extra is not Z_NULL, then extra_max - contains the maximum number of bytes to write to extra. Once done is true, - extra_len contains the actual extra field length, and extra contains the - extra field, or that field truncated if extra_max is less than extra_len. - If name is not Z_NULL, then up to name_max characters are written there, - terminated with a zero unless the length is greater than name_max. If - comment is not Z_NULL, then up to comm_max characters are written there, - terminated with a zero unless the length is greater than comm_max. When - any of extra, name, or comment are not Z_NULL and the respective field is - not present in the header, then that field is set to Z_NULL to signal its - absence. This allows the use of deflateSetHeader() with the returned - structure to duplicate the header. However if those fields are set to - allocated memory, then the application will need to save those pointers - elsewhere so that they can be eventually freed. - - If inflateGetHeader is not used, then the header information is simply - discarded. The header is always checked for validity, including the header - CRC if present. inflateReset() will reset the process to discard the header - information. The application would need to call inflateGetHeader() again to - retrieve the header from the next gzip stream. - - inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, - unsigned char FAR *window)); - - Initialize the internal stream state for decompression using inflateBack() - calls. The fields zalloc, zfree and opaque in strm must be initialized - before the call. If zalloc and zfree are Z_NULL, then the default library- - derived memory allocation routines are used. windowBits is the base two - logarithm of the window size, in the range 8..15. window is a caller - supplied buffer of that size. Except for special applications where it is - assured that deflate was used with small window sizes, windowBits must be 15 - and a 32K byte window must be supplied to be able to decompress general - deflate streams. - - See inflateBack() for the usage of these routines. - - inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of - the paramaters are invalid, Z_MEM_ERROR if the internal state could not - be allocated, or Z_VERSION_ERROR if the version of the library does not - match the version of the header file. -*/ - -typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); -typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); - -ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, - in_func in, void FAR *in_desc, - out_func out, void FAR *out_desc)); -/* - inflateBack() does a raw inflate with a single call using a call-back - interface for input and output. This is more efficient than inflate() for - file i/o applications in that it avoids copying between the output and the - sliding window by simply making the window itself the output buffer. This - function trusts the application to not change the output buffer passed by - the output function, at least until inflateBack() returns. - - inflateBackInit() must be called first to allocate the internal state - and to initialize the state with the user-provided window buffer. - inflateBack() may then be used multiple times to inflate a complete, raw - deflate stream with each call. inflateBackEnd() is then called to free - the allocated state. - - A raw deflate stream is one with no zlib or gzip header or trailer. - This routine would normally be used in a utility that reads zip or gzip - files and writes out uncompressed files. The utility would decode the - header and process the trailer on its own, hence this routine expects - only the raw deflate stream to decompress. This is different from the - normal behavior of inflate(), which expects either a zlib or gzip header and - trailer around the deflate stream. - - inflateBack() uses two subroutines supplied by the caller that are then - called by inflateBack() for input and output. inflateBack() calls those - routines until it reads a complete deflate stream and writes out all of the - uncompressed data, or until it encounters an error. The function's - parameters and return types are defined above in the in_func and out_func - typedefs. inflateBack() will call in(in_desc, &buf) which should return the - number of bytes of provided input, and a pointer to that input in buf. If - there is no input available, in() must return zero--buf is ignored in that - case--and inflateBack() will return a buffer error. inflateBack() will call - out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() - should return zero on success, or non-zero on failure. If out() returns - non-zero, inflateBack() will return with an error. Neither in() nor out() - are permitted to change the contents of the window provided to - inflateBackInit(), which is also the buffer that out() uses to write from. - The length written by out() will be at most the window size. Any non-zero - amount of input may be provided by in(). - - For convenience, inflateBack() can be provided input on the first call by - setting strm->next_in and strm->avail_in. If that input is exhausted, then - in() will be called. Therefore strm->next_in must be initialized before - calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called - immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in - must also be initialized, and then if strm->avail_in is not zero, input will - initially be taken from strm->next_in[0 .. strm->avail_in - 1]. - - The in_desc and out_desc parameters of inflateBack() is passed as the - first parameter of in() and out() respectively when they are called. These - descriptors can be optionally used to pass any information that the caller- - supplied in() and out() functions need to do their job. - - On return, inflateBack() will set strm->next_in and strm->avail_in to - pass back any unused input that was provided by the last in() call. The - return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR - if in() or out() returned an error, Z_DATA_ERROR if there was a format - error in the deflate stream (in which case strm->msg is set to indicate the - nature of the error), or Z_STREAM_ERROR if the stream was not properly - initialized. In the case of Z_BUF_ERROR, an input or output error can be - distinguished using strm->next_in which will be Z_NULL only if in() returned - an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to - out() returning non-zero. (in() will always be called before out(), so - strm->next_in is assured to be defined if out() returns non-zero.) Note - that inflateBack() cannot return Z_OK. -*/ - -ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); -/* - All memory allocated by inflateBackInit() is freed. - - inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream - state was inconsistent. -*/ - -ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); -/* Return flags indicating compile-time options. - - Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: - 1.0: size of uInt - 3.2: size of uLong - 5.4: size of voidpf (pointer) - 7.6: size of z_off_t - - Compiler, assembler, and debug options: - 8: DEBUG - 9: ASMV or ASMINF -- use ASM code - 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention - 11: 0 (reserved) - - One-time table building (smaller code, but not thread-safe if true): - 12: BUILDFIXED -- build static block decoding tables when needed - 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed - 14,15: 0 (reserved) - - Library content (indicates missing functionality): - 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking - deflate code when not needed) - 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect - and decode gzip streams (to avoid linking crc code) - 18-19: 0 (reserved) - - Operation variations (changes in library functionality): - 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate - 21: FASTEST -- deflate algorithm with only one, lowest compression level - 22,23: 0 (reserved) - - The sprintf variant used by gzprintf (zero is best): - 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format - 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! - 26: 0 = returns value, 1 = void -- 1 means inferred string length returned - - Remainder: - 27-31: 0 (reserved) - */ - - - /* utility functions */ - -/* - The following utility functions are implemented on top of the - basic stream-oriented functions. To simplify the interface, some - default options are assumed (compression level and memory usage, - standard memory allocation functions). The source code of these - utility functions can easily be modified if you need special options. -*/ - -ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Compresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be at least the value returned - by compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - This function can be used to compress a whole file at once if the - input file is mmap'ed. - compress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer. -*/ - -ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen, - int level)); -/* - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least the value returned by - compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ - -ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); -/* - compressBound() returns an upper bound on the compressed size after - compress() or compress2() on sourceLen bytes. It would be used before - a compress() or compress2() call to allocate the destination buffer. -*/ - -ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. -*/ - - -typedef voidp gzFile; - -ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); -/* - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb") but can also include a compression level - ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for - Huffman only compression as in "wb1h", or 'R' for run-length encoding - as in "wb1R". (See the description of deflateInit2 for more information - about the strategy parameter.) - - gzopen can be used to read a file which is not in gzip format; in this - case gzread will directly read from the file without decompression. - - gzopen returns NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). */ - -ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); -/* - gzdopen() associates a gzFile with the file descriptor fd. File - descriptors are obtained from calls like open, dup, creat, pipe or - fileno (in the file has been previously opened with fopen). - The mode parameter is as in gzopen. - The next call of gzclose on the returned gzFile will also close the - file descriptor fd, just like fclose(fdopen(fd), mode) closes the file - descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). - gzdopen returns NULL if there was insufficient memory to allocate - the (de)compression state. -*/ - -ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); -/* - Dynamically update the compression level or strategy. See the description - of deflateInit2 for the meaning of these parameters. - gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not - opened for writing. -*/ - -ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); -/* - Reads the given number of uncompressed bytes from the compressed file. - If the input file was not in gzip format, gzread copies the given number - of bytes into the buffer. - gzread returns the number of uncompressed bytes actually read (0 for - end of file, -1 for error). */ - -ZEXTERN int ZEXPORT gzwrite OF((gzFile file, - voidpc buf, unsigned len)); -/* - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of uncompressed bytes actually written - (0 in case of error). -*/ - -ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); -/* - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). The number of - uncompressed bytes written is limited to 4095. The caller should assure that - this limit is not exceeded. If it is exceeded, then gzprintf() will return - return an error (0) with nothing written. In this case, there may also be a - buffer overflow with unpredictable consequences, which is possible only if - zlib was compiled with the insecure functions sprintf() or vsprintf() - because the secure snprintf() or vsnprintf() functions were not available. -*/ - -ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); -/* - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. -*/ - -ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); -/* - Reads bytes from the compressed file until len-1 characters are read, or - a newline character is read and transferred to buf, or an end-of-file - condition is encountered. The string is then terminated with a null - character. - gzgets returns buf, or Z_NULL in case of error. -*/ - -ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); -/* - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. -*/ - -ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); -/* - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. -*/ - -ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); -/* - Push one character back onto the stream to be read again later. - Only one character of push-back is allowed. gzungetc() returns the - character pushed, or -1 on failure. gzungetc() will fail if a - character has been pushed but not read yet, or if c is -1. The pushed - character will be discarded if the stream is repositioned with gzseek() - or gzrewind(). -*/ - -ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); -/* - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. The return value is the zlib - error number (see function gzerror below). gzflush returns Z_OK if - the flush parameter is Z_FINISH and all output could be flushed. - gzflush should be called only when strictly necessary because it can - degrade compression. -*/ - -ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, - z_off_t offset, int whence)); -/* - Sets the starting position for the next gzread or gzwrite on the - given compressed file. The offset represents a number of bytes in the - uncompressed data stream. The whence parameter is defined as in lseek(2); - the value SEEK_END is not supported. - If the file is opened for reading, this function is emulated but can be - extremely slow. If the file is opened for writing, only forward seeks are - supported; gzseek then compresses a sequence of zeroes up to the new - starting position. - - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error, in - particular if the file is opened for writing and the new starting position - would be before the current position. -*/ - -ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); -/* - Rewinds the given file. This function is supported only for reading. - - gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) -*/ - -ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); -/* - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. - - gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) -*/ - -ZEXTERN int ZEXPORT gzeof OF((gzFile file)); -/* - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. -*/ - -ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); -/* - Returns 1 if file is being read directly without decompression, otherwise - zero. -*/ - -ZEXTERN int ZEXPORT gzclose OF((gzFile file)); -/* - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. The return value is the zlib - error number (see function gzerror below). -*/ - -ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); -/* - Returns the error message for the last error which occurred on the - given compressed file. errnum is set to zlib error number. If an - error occurred in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. -*/ - -ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); -/* - Clears the error and end-of-file flags for file. This is analogous to the - clearerr() function in stdio. This is useful for continuing to read a gzip - file that is being written concurrently. -*/ - - /* checksum functions */ - -/* - These functions are not related to compression but are exported - anyway because they might be useful in applications using the - compression library. -*/ - -ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); -/* - Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. If buf is NULL, this function returns - the required initial value for the checksum. - An Adler-32 checksum is almost as reliable as a CRC32 but can be computed - much faster. Usage example: - - uLong adler = adler32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - adler = adler32(adler, buffer, length); - } - if (adler != original_adler) error(); -*/ - -ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, - z_off_t len2)); -/* - Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 - and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for - each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of - seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. -*/ - -ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); -/* - Update a running CRC-32 with the bytes buf[0..len-1] and return the - updated CRC-32. If buf is NULL, this function returns the required initial - value for the for the crc. Pre- and post-conditioning (one's complement) is - performed within this function so it shouldn't be done by the application. - Usage example: - - uLong crc = crc32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - crc = crc32(crc, buffer, length); - } - if (crc != original_crc) error(); -*/ - -ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); - -/* - Combine two CRC-32 check values into one. For two sequences of bytes, - seq1 and seq2 with lengths len1 and len2, CRC-32 check values were - calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 - check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and - len2. -*/ - - - /* various hacks, don't look :) */ - -/* deflateInit and inflateInit are macros to allow checking the zlib version - * and the compiler's view of z_stream: - */ -ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy, const char *version, - int stream_size)); -ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, - unsigned char FAR *window, - const char *version, - int stream_size)); -#define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) -#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) -#define inflateBackInit(strm, windowBits, window) \ - inflateBackInit_((strm), (windowBits), (window), \ - ZLIB_VERSION, sizeof(z_stream)) - - -#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) - struct internal_state {int dummy;}; /* hack for buggy compilers */ -#endif - -ZEXTERN const char * ZEXPORT zError OF((int)); -ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); -ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); - -#ifdef __cplusplus -} -#endif - -#endif /* ZLIB_H */ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/3rdparty/zlib/zutil.c b/3rdparty/zlib/zutil.c index 0f4bd7871d..d55f5948a3 100644 --- a/3rdparty/zlib/zutil.c +++ b/3rdparty/zlib/zutil.c @@ -1,318 +1,318 @@ -/* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#include "zutil.h" - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -const char * const z_errmsg[10] = { -"need dictionary", /* Z_NEED_DICT 2 */ -"stream end", /* Z_STREAM_END 1 */ -"", /* Z_OK 0 */ -"file error", /* Z_ERRNO (-1) */ -"stream error", /* Z_STREAM_ERROR (-2) */ -"data error", /* Z_DATA_ERROR (-3) */ -"insufficient memory", /* Z_MEM_ERROR (-4) */ -"buffer error", /* Z_BUF_ERROR (-5) */ -"incompatible version",/* Z_VERSION_ERROR (-6) */ -""}; - - -const char * ZEXPORT zlibVersion() -{ - return ZLIB_VERSION; -} - -uLong ZEXPORT zlibCompileFlags() -{ - uLong flags; - - flags = 0; - switch (sizeof(uInt)) { - case 2: break; - case 4: flags += 1; break; - case 8: flags += 2; break; - default: flags += 3; - } - switch (sizeof(uLong)) { - case 2: break; - case 4: flags += 1 << 2; break; - case 8: flags += 2 << 2; break; - default: flags += 3 << 2; - } - switch (sizeof(voidpf)) { - case 2: break; - case 4: flags += 1 << 4; break; - case 8: flags += 2 << 4; break; - default: flags += 3 << 4; - } - switch (sizeof(z_off_t)) { - case 2: break; - case 4: flags += 1 << 6; break; - case 8: flags += 2 << 6; break; - default: flags += 3 << 6; - } -#ifdef DEBUG - flags += 1 << 8; -#endif -#if defined(ASMV) || defined(ASMINF) - flags += 1 << 9; -#endif -#ifdef ZLIB_WINAPI - flags += 1 << 10; -#endif -#ifdef BUILDFIXED - flags += 1 << 12; -#endif -#ifdef DYNAMIC_CRC_TABLE - flags += 1 << 13; -#endif -#ifdef NO_GZCOMPRESS - flags += 1L << 16; -#endif -#ifdef NO_GZIP - flags += 1L << 17; -#endif -#ifdef PKZIP_BUG_WORKAROUND - flags += 1L << 20; -#endif -#ifdef FASTEST - flags += 1L << 21; -#endif -#ifdef STDC -# ifdef NO_vsnprintf - flags += 1L << 25; -# ifdef HAS_vsprintf_void - flags += 1L << 26; -# endif -# else -# ifdef HAS_vsnprintf_void - flags += 1L << 26; -# endif -# endif -#else - flags += 1L << 24; -# ifdef NO_snprintf - flags += 1L << 25; -# ifdef HAS_sprintf_void - flags += 1L << 26; -# endif -# else -# ifdef HAS_snprintf_void - flags += 1L << 26; -# endif -# endif -#endif - return flags; -} - -#ifdef DEBUG - -# ifndef verbose -# define verbose 0 -# endif -int z_verbose = verbose; - -void z_error (m) - char *m; -{ - fprintf(stderr, "%s\n", m); - exit(1); -} -#endif - -/* exported to allow conversion of error code to string for compress() and - * uncompress() - */ -const char * ZEXPORT zError(err) - int err; -{ - return ERR_MSG(err); -} - -#if defined(_WIN32_WCE) - /* The Microsoft C Run-Time Library for Windows CE doesn't have - * errno. We define it as a global variable to simplify porting. - * Its value is always 0 and should not be used. - */ - int errno = 0; -#endif - -#ifndef HAVE_MEMCPY - -void zmemcpy(dest, source, len) - Bytef* dest; - const Bytef* source; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = *source++; /* ??? to be unrolled */ - } while (--len != 0); -} - -int zmemcmp(s1, s2, len) - const Bytef* s1; - const Bytef* s2; - uInt len; -{ - uInt j; - - for (j = 0; j < len; j++) { - if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; - } - return 0; -} - -void zmemzero(dest, len) - Bytef* dest; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = 0; /* ??? to be unrolled */ - } while (--len != 0); -} -#endif - - -#ifdef SYS16BIT - -#ifdef __TURBOC__ -/* Turbo C in 16-bit mode */ - -# define MY_ZCALLOC - -/* Turbo C malloc() does not allow dynamic allocation of 64K bytes - * and farmalloc(64K) returns a pointer with an offset of 8, so we - * must fix the pointer. Warning: the pointer must be put back to its - * original form in order to free it, use zcfree(). - */ - -#define MAX_PTR 10 -/* 10*64K = 640K */ - -local int next_ptr = 0; - -typedef struct ptr_table_s { - voidpf org_ptr; - voidpf new_ptr; -} ptr_table; - -local ptr_table table[MAX_PTR]; -/* This table is used to remember the original form of pointers - * to large buffers (64K). Such pointers are normalized with a zero offset. - * Since MSDOS is not a preemptive multitasking OS, this table is not - * protected from concurrent access. This hack doesn't work anyway on - * a protected system like OS/2. Use Microsoft C instead. - */ - -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - voidpf buf = opaque; /* just to make some compilers happy */ - ulg bsize = (ulg)items*size; - - /* If we allocate less than 65520 bytes, we assume that farmalloc - * will return a usable pointer which doesn't have to be normalized. - */ - if (bsize < 65520L) { - buf = farmalloc(bsize); - if (*(ush*)&buf != 0) return buf; - } else { - buf = farmalloc(bsize + 16L); - } - if (buf == NULL || next_ptr >= MAX_PTR) return NULL; - table[next_ptr].org_ptr = buf; - - /* Normalize the pointer to seg:0 */ - *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; - *(ush*)&buf = 0; - table[next_ptr++].new_ptr = buf; - return buf; -} - -void zcfree (voidpf opaque, voidpf ptr) -{ - int n; - if (*(ush*)&ptr != 0) { /* object < 64K */ - farfree(ptr); - return; - } - /* Find the original pointer */ - for (n = 0; n < next_ptr; n++) { - if (ptr != table[n].new_ptr) continue; - - farfree(table[n].org_ptr); - while (++n < next_ptr) { - table[n-1] = table[n]; - } - next_ptr--; - return; - } - ptr = opaque; /* just to make some compilers happy */ - Assert(0, "zcfree: ptr not found"); -} - -#endif /* __TURBOC__ */ - - -#ifdef M_I86 -/* Microsoft C in 16-bit mode */ - -# define MY_ZCALLOC - -#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) -# define _halloc halloc -# define _hfree hfree -#endif - -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - if (opaque) opaque = 0; /* to make compiler happy */ - return _halloc((long)items, size); -} - -void zcfree (voidpf opaque, voidpf ptr) -{ - if (opaque) opaque = 0; /* to make compiler happy */ - _hfree(ptr); -} - -#endif /* M_I86 */ - -#endif /* SYS16BIT */ - - -#ifndef MY_ZCALLOC /* Any system without a special alloc function */ - -#ifndef STDC -extern voidp malloc OF((uInt size)); -extern voidp calloc OF((uInt items, uInt size)); -extern void free OF((voidpf ptr)); -#endif - -voidpf zcalloc (opaque, items, size) - voidpf opaque; - unsigned items; - unsigned size; -{ - if (opaque) items += size - size; /* make compiler happy */ - return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : - (voidpf)calloc(items, size); -} - -void zcfree (opaque, ptr) - voidpf opaque; - voidpf ptr; -{ - free(ptr); - if (opaque) return; /* make compiler happy */ -} - -#endif /* MY_ZCALLOC */ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/3rdparty/zlib/zutil.h b/3rdparty/zlib/zutil.h index 0e3a9a0638..532fc7084a 100644 --- a/3rdparty/zlib/zutil.h +++ b/3rdparty/zlib/zutil.h @@ -1,269 +1,269 @@ -/* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id$ */ - -#ifndef ZUTIL_H -#define ZUTIL_H - -#define ZLIB_INTERNAL -#include "zlib.h" - -#ifdef STDC -# ifndef _WIN32_WCE -# include -# endif -# include -# include -#endif -#ifdef NO_ERRNO_H -# ifdef _WIN32_WCE - /* The Microsoft C Run-Time Library for Windows CE doesn't have - * errno. We define it as a global variable to simplify porting. - * Its value is always 0 and should not be used. We rename it to - * avoid conflict with other libraries that use the same workaround. - */ -# define errno z_errno -# endif - extern int errno; -#else -# ifndef _WIN32_WCE -# include -# endif -#endif - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -typedef unsigned char uch; -typedef uch FAR uchf; -typedef unsigned short ush; -typedef ush FAR ushf; -typedef unsigned long ulg; - -extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ -/* (size given to avoid silly warnings with Visual C++) */ - -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] - -#define ERR_RETURN(strm,err) \ - return (strm->msg = (char*)ERR_MSG(err), (err)) -/* To be used only when the state is known to be valid */ - - /* common constants */ - -#ifndef DEF_WBITS -# define DEF_WBITS MAX_WBITS -#endif -/* default windowBits for decompression. MAX_WBITS is for compression only */ - -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 9 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -/* default memLevel */ - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - -#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ - - /* target dependencies */ - -#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) -# define OS_CODE 0x00 -# if defined(__TURBOC__) || defined(__BORLANDC__) -# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) - /* Allow compilation with ANSI keywords only enabled */ - void _Cdecl farfree( void *block ); - void *_Cdecl farmalloc( unsigned long nbytes ); -# else -# include -# endif -# else /* MSC or DJGPP */ -# include -# endif -#endif - -#ifdef AMIGA -# define OS_CODE 0x01 -#endif - -#if defined(VAXC) || defined(VMS) -# define OS_CODE 0x02 -# define F_OPEN(name, mode) \ - fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") -#endif - -#if defined(ATARI) || defined(atarist) -# define OS_CODE 0x05 -#endif - -#ifdef OS2 -# define OS_CODE 0x06 -# ifdef M_I86 - #include -# endif -#endif - -#if defined(MACOS) || defined(TARGET_OS_MAC) -# define OS_CODE 0x07 -# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os -# include /* for fdopen */ -# else -# ifndef fdopen -# define fdopen(fd,mode) NULL /* No fdopen() */ -# endif -# endif -#endif - -#ifdef TOPS20 -# define OS_CODE 0x0a -#endif - -#ifdef WIN32 -# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ -# define OS_CODE 0x0b -# endif -#endif - -#ifdef __50SERIES /* Prime/PRIMOS */ -# define OS_CODE 0x0f -#endif - -#if defined(_BEOS_) || defined(RISCOS) -# define fdopen(fd,mode) NULL /* No fdopen() */ -#endif - -#if (defined(_MSC_VER) && (_MSC_VER > 600)) -# if defined(_WIN32_WCE) -# define fdopen(fd,mode) NULL /* No fdopen() */ -# ifndef _PTRDIFF_T_DEFINED - typedef int ptrdiff_t; -# define _PTRDIFF_T_DEFINED -# endif -# else -# define fdopen(fd,type) _fdopen(fd,type) -# endif -#endif - - /* common defaults */ - -#ifndef OS_CODE -# define OS_CODE 0x03 /* assume Unix */ -#endif - -#ifndef F_OPEN -# define F_OPEN(name, mode) fopen((name), (mode)) -#endif - - /* functions */ - -#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif -#if defined(__CYGWIN__) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif -#ifndef HAVE_VSNPRINTF -# ifdef MSDOS - /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), - but for now we just assume it doesn't. */ -# define NO_vsnprintf -# endif -# ifdef __TURBOC__ -# define NO_vsnprintf -# endif -# ifdef WIN32 - /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ -# if !defined(vsnprintf) && !defined(NO_vsnprintf) -# define vsnprintf _vsnprintf -# endif -# endif -# ifdef __SASC -# define NO_vsnprintf -# endif -#endif -#ifdef VMS -# define NO_vsnprintf -#endif - -#if defined(pyr) -# define NO_MEMCPY -#endif -#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) - /* Use our own functions for small and medium model with MSC <= 5.0. - * You may have to use the same strategy for Borland C (untested). - * The __SC__ check is for Symantec. - */ -# define NO_MEMCPY -#endif -#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) -# define HAVE_MEMCPY -#endif -#ifdef HAVE_MEMCPY -# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ -# define zmemcpy _fmemcpy -# define zmemcmp _fmemcmp -# define zmemzero(dest, len) _fmemset(dest, 0, len) -# else -# define zmemcpy memcpy -# define zmemcmp memcmp -# define zmemzero(dest, len) memset(dest, 0, len) -# endif -#else - extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); - extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); - extern void zmemzero OF((Bytef* dest, uInt len)); -#endif - -/* Diagnostic functions */ -#ifdef DEBUG -# include - extern int z_verbose; - extern void z_error OF((char *m)); -# define Assert(cond,msg) {if(!(cond)) z_error(msg);} -# define Trace(x) {if (z_verbose>=0) fprintf x ;} -# define Tracev(x) {if (z_verbose>0) fprintf x ;} -# define Tracevv(x) {if (z_verbose>1) fprintf x ;} -# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} -# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - - -voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); -void zcfree OF((voidpf opaque, voidpf ptr)); - -#define ZALLOC(strm, items, size) \ - (*((strm)->zalloc))((strm)->opaque, (items), (size)) -#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) -#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} - -#endif /* ZUTIL_H */ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# ifndef _WIN32_WCE +# include +# endif +# include +# include +#endif +#ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif + extern int errno; +#else +# ifndef _WIN32_WCE +# include +# endif +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 9 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 + #include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/common/includes/PS2Edefs.h b/common/includes/PS2Edefs.h index 1f65fc02b9..49b16e16d5 100644 --- a/common/includes/PS2Edefs.h +++ b/common/includes/PS2Edefs.h @@ -1,885 +1,885 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef __PS2EDEFS_H__ -#define __PS2EDEFS_H__ - -/* - * PS2E Definitions v0.6.2 (beta) - * - * Author: linuzappz@hotmail.com - * shadowpcsx2@yahoo.gr - * florinsasu@hotmail.com - */ - -/* - Notes: - * Since this is still beta things may change. - - * OSflags: - __LINUX__ (linux OS) - _WIN32 (win32 OS) - - * common return values (for ie. GSinit): - 0 - success - -1 - error - - * reserved keys: - F1 to F10 are reserved for the emulator - - * plugins should NOT change the current - working directory. - (on win32, add flag OFN_NOCHANGEDIR for - GetOpenFileName) - -*/ - -#include "PS2Etypes.h" - - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ - defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ - defined(USBdefs) || defined(FWdefs) -#define COMMONdefs -#endif - -// PS2EgetLibType returns (may be OR'd) -#define PS2E_LT_GS 0x01 -#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- -#define PS2E_LT_SPU2 0x04 -#define PS2E_LT_CDVD 0x08 -#define PS2E_LT_DEV9 0x10 -#define PS2E_LT_USB 0x20 -#define PS2E_LT_FW 0x40 -#define PS2E_LT_SIO 0x80 - -// PS2EgetLibVersion2 (high 16 bits) -#define PS2E_GS_VERSION 0x0006 -#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- -#define PS2E_SPU2_VERSION 0x0005 -#define PS2E_CDVD_VERSION 0x0005 -#define PS2E_DEV9_VERSION 0x0003 -#define PS2E_USB_VERSION 0x0003 -#define PS2E_FW_VERSION 0x0002 -#define PS2E_SIO_VERSION 0x0001 -#ifdef COMMONdefs - -u32 CALLBACK PS2EgetLibType(void); -u32 CALLBACK PS2EgetLibVersion2(u32 type); -char* CALLBACK PS2EgetLibName(void); - -#endif - -// key values: -/* key values must be OS dependant: - win32: the VK_XXX will be used (WinUser) - linux: the XK_XXX will be used (XFree86) -*/ - -// event values: -#define KEYPRESS 1 -#define KEYRELEASE 2 - -typedef struct _keyEvent { - u32 key; - u32 evt; -} keyEvent; - -// for 64bit compilers -typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; - -// plugin types -#define SIO_TYPE_PAD 0x00000001 -#define SIO_TYPE_MTAP 0x00000004 -#define SIO_TYPE_RM 0x00000040 -#define SIO_TYPE_MC 0x00000100 - -typedef int (CALLBACK * SIOchangeSlotCB)(int slot); - -typedef struct _cdvdSubQ { - u8 ctrl:4; // control and mode bits - u8 mode:4; // control and mode bits - u8 trackNum; // current track number (1 to 99) - u8 trackIndex; // current index within track (0 to 99) - u8 trackM; // current minute location on the disc (BCD encoded) - u8 trackS; // current sector location on the disc (BCD encoded) - u8 trackF; // current frame location on the disc (BCD encoded) - u8 pad; // unused - u8 discM; // current minute offset from first track (BCD encoded) - u8 discS; // current sector offset from first track (BCD encoded) - u8 discF; // current frame offset from first track (BCD encoded) -} cdvdSubQ; - -typedef struct _cdvdTD { // NOT bcd coded - u32 lsn; - u8 type; -} cdvdTD; - -typedef struct _cdvdTN { - u8 strack; //number of the first track (usually 1) - u8 etrack; //number of the last track -} cdvdTN; - -// CDVDreadTrack mode values: -#define CDVD_MODE_2352 0 // full 2352 bytes -#define CDVD_MODE_2340 1 // skip sync (12) bytes -#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq - -// CDVDgetDiskType returns: -#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc -#define CDVD_TYPE_DVDV 0xfe // DVD Video -#define CDVD_TYPE_CDDA 0xfd // Audio CD -#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD -#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) -#define CDVD_TYPE_PS2CD 0x12 // PS2 CD -#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) -#define CDVD_TYPE_PSCD 0x10 // PS CD -#define CDVD_TYPE_UNKNOWN 0x05 // Unknown -#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided -#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided -#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd -#define CDVD_TYPE_DETCT 0x01 // Detecting -#define CDVD_TYPE_NODISC 0x00 // No Disc - -// CDVDgetTrayStatus returns: -#define CDVD_TRAY_CLOSE 0x00 -#define CDVD_TRAY_OPEN 0x01 - -// cdvdTD.type (track types for cds) -#define CDVD_AUDIO_TRACK 0x01 -#define CDVD_MODE1_TRACK 0x41 -#define CDVD_MODE2_TRACK 0x61 - -#define CDVD_AUDIO_MASK 0x00 -#define CDVD_DATA_MASK 0x40 -// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) - -typedef void (*DEV9callback)(int cycles); -typedef int (*DEV9handler)(void); - -typedef void (*USBcallback)(int cycles); -typedef int (*USBhandler)(void); - -// freeze modes: -#define FREEZE_LOAD 0 -#define FREEZE_SAVE 1 -#define FREEZE_SIZE 2 - -typedef struct _GSdriverInfo { - char name[8]; - void *common; -} GSdriverInfo; - -#ifdef _WINDOWS_ -typedef struct _winInfo { // unsupported values must be set to zero - HWND hWnd; - HMENU hMenu; - HWND hStatusWnd; -} winInfo; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* GS plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef GSdefs - -// basic funcs - -s32 CALLBACK GSinit(); -s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); -void CALLBACK GSclose(); -void CALLBACK GSshutdown(); -void CALLBACK GSvsync(int field); -void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); -void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); -void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); -void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) -void CALLBACK GSgifSoftReset(u32 mask); -void CALLBACK GSreadFIFO(u64 *mem); -void CALLBACK GSreadFIFO2(u64 *mem, int qwc); - -// extended funcs - -// GSkeyEvent gets called when there is a keyEvent from the PAD plugin -void CALLBACK GSkeyEvent(keyEvent *ev); -void CALLBACK GSchangeSaveState(int, const char* filename); -void CALLBACK GSmakeSnapshot(char *path); -void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); -void CALLBACK GSirqCallback(void (*callback)()); -void CALLBACK GSprintf(int timeout, char *fmt, ...); -void CALLBACK GSsetBaseMem(void*); -void CALLBACK GSsetGameCRC(int crc, int gameoptions); - -// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done -void CALLBACK GSsetFrameSkip(int frameskip); - -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK GSsetupRecording(int start, void* pData); - -void CALLBACK GSreset(); -void CALLBACK GSwriteCSR(u32 value); -void CALLBACK GSgetDriverInfo(GSdriverInfo *info); -#ifdef _WIN32 -s32 CALLBACK GSsetWindowInfo(winInfo *info); -#endif -s32 CALLBACK GSfreeze(int mode, freezeData *data); -void CALLBACK GSconfigure(); -void CALLBACK GSabout(); -s32 CALLBACK GStest(); - -#endif - -/* PAD plugin API -=[ OBSOLETE ]=- */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef PADdefs - -// basic funcs - -s32 CALLBACK PADinit(u32 flags); -s32 CALLBACK PADopen(void *pDsp); -void CALLBACK PADclose(); -void CALLBACK PADshutdown(); -// PADkeyEvent is called every vsync (return NULL if no event) -keyEvent* CALLBACK PADkeyEvent(); -u8 CALLBACK PADstartPoll(int pad); -u8 CALLBACK PADpoll(u8 value); -// returns: 1 if supported pad1 -// 2 if supported pad2 -// 3 if both are supported -u32 CALLBACK PADquery(); - -// call to give a hint to the PAD plugin to query for the keyboard state. A -// good plugin will query the OS for keyboard state ONLY in this function. -// This function is necessary when multithreading because otherwise -// the PAD plugin can get into deadlocks with the thread that really owns -// the window (and input). Note that PADupdate can be called from a different -// thread than the other functions, so mutex or other multithreading primitives -// have to be added to maintain data integrity. -void CALLBACK PADupdate(int pad); - -// extended funcs - -void CALLBACK PADgsDriverInfo(GSdriverInfo *info); -void CALLBACK PADconfigure(); -void CALLBACK PADabout(); -s32 CALLBACK PADtest(); - -#endif - -/* SIO plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SIOdefs - -// basic funcs - -s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); -s32 CALLBACK SIOopen(void *pDsp); -void CALLBACK SIOclose(); -void CALLBACK SIOshutdown(); -u8 CALLBACK SIOstartPoll(u8 value); -u8 CALLBACK SIOpoll(u8 value); -// returns: SIO_TYPE_{PAD,MTAP,RM,MC} -u32 CALLBACK SIOquery(); - -// extended funcs - -void CALLBACK SIOconfigure(); -void CALLBACK SIOabout(); -s32 CALLBACK SIOtest(); - -#endif - -/* SPU2 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SPU2defs - -// basic funcs - -s32 CALLBACK SPU2init(); -s32 CALLBACK SPU2open(void *pDsp); -void CALLBACK SPU2close(); -void CALLBACK SPU2shutdown(); -void CALLBACK SPU2write(u32 mem, u16 value); -u16 CALLBACK SPU2read(u32 mem); -void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA4(); -void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); -void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); - -// all addresses passed by dma will be pointers to the array starting at baseaddr -// This function is necessary to successfully save and reload the spu2 state -void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); - -void CALLBACK SPU2interruptDMA7(); -u32 CALLBACK SPU2ReadMemAddr(int core); -void CALLBACK SPU2WriteMemAddr(int core,u32 value); -void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); - -// extended funcs -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK SPU2setupRecording(int start, void* pData); - -void CALLBACK SPU2setClockPtr(u32* ptr); -void CALLBACK SPU2setTimeStretcher(short int enable); - -void CALLBACK SPU2async(u32 cycles); -s32 CALLBACK SPU2freeze(int mode, freezeData *data); -void CALLBACK SPU2configure(); -void CALLBACK SPU2about(); -s32 CALLBACK SPU2test(); - -#endif - -/* CDVD plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef CDVDdefs - -// basic funcs - -s32 CALLBACK CDVDinit(); -s32 CALLBACK CDVDopen(const char* pTitleFilename); -void CALLBACK CDVDclose(); -void CALLBACK CDVDshutdown(); -s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); - -// return can be NULL (for async modes) -u8* CALLBACK CDVDgetBuffer(); - -s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) -s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information -s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type -s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc -s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx -s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx -s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray -s32 CALLBACK CDVDctrlTrayClose(); //close disc tray - -// extended funcs - -void CALLBACK CDVDconfigure(); -void CALLBACK CDVDabout(); -s32 CALLBACK CDVDtest(); -void CALLBACK CDVDnewDiskCB(void (*callback)()); - -#endif - -/* DEV9 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef DEV9defs - -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK DEV9init(); -s32 CALLBACK DEV9open(void *pDsp); -void CALLBACK DEV9close(); -void CALLBACK DEV9shutdown(); -u8 CALLBACK DEV9read8(u32 addr); -u16 CALLBACK DEV9read16(u32 addr); -u32 CALLBACK DEV9read32(u32 addr); -void CALLBACK DEV9write8(u32 addr, u8 value); -void CALLBACK DEV9write16(u32 addr, u16 value); -void CALLBACK DEV9write32(u32 addr, u32 value); -void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); -void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK DEV9irqCallback(DEV9callback callback); -DEV9handler CALLBACK DEV9irqHandler(void); - -// extended funcs - -s32 CALLBACK DEV9freeze(int mode, freezeData *data); -void CALLBACK DEV9configure(); -void CALLBACK DEV9about(); -s32 CALLBACK DEV9test(); - -#endif - -/* USB plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef USBdefs - -// basic funcs - -s32 CALLBACK USBinit(); -s32 CALLBACK USBopen(void *pDsp); -void CALLBACK USBclose(); -void CALLBACK USBshutdown(); -u8 CALLBACK USBread8(u32 addr); -u16 CALLBACK USBread16(u32 addr); -u32 CALLBACK USBread32(u32 addr); -void CALLBACK USBwrite8(u32 addr, u8 value); -void CALLBACK USBwrite16(u32 addr, u16 value); -void CALLBACK USBwrite32(u32 addr, u32 value); -void CALLBACK USBasync(u32 cycles); - -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK USBirqCallback(USBcallback callback); -USBhandler CALLBACK USBirqHandler(void); -void CALLBACK USBsetRAM(void *mem); - -// extended funcs - -s32 CALLBACK USBfreeze(int mode, freezeData *data); -void CALLBACK USBconfigure(); -void CALLBACK USBabout(); -s32 CALLBACK USBtest(); - -#endif - -/* FW plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef FWdefs -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK FWinit(); -s32 CALLBACK FWopen(void *pDsp); -void CALLBACK FWclose(); -void CALLBACK FWshutdown(); -u32 CALLBACK FWread32(u32 addr); -void CALLBACK FWwrite32(u32 addr, u32 value); -void CALLBACK FWirqCallback(void (*callback)()); - -// extended funcs - -s32 CALLBACK FWfreeze(int mode, freezeData *data); -void CALLBACK FWconfigure(); -void CALLBACK FWabout(); -s32 CALLBACK FWtest(); -#endif - -// might be useful for emulators -#ifdef PLUGINtypedefs - -typedef u32 (CALLBACK* _PS2EgetLibType)(void); -typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); -typedef char*(CALLBACK* _PS2EgetLibName)(void); - -// GS -// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _GSinit)(); -typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); -typedef void (CALLBACK* _GSclose)(); -typedef void (CALLBACK* _GSshutdown)(); -typedef void (CALLBACK* _GSvsync)(int field); -typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); -typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) -typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); -typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); -typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); - -typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); -typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); -typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); -typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); -typedef void (CALLBACK* _GSsetBaseMem)(void*); -typedef void (CALLBACK* _GSsetGameCRC)(int, int); -typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); -typedef int (CALLBACK* _GSsetupRecording)(int, void*); -typedef void (CALLBACK* _GSreset)(); -typedef void (CALLBACK* _GSwriteCSR)(u32 value); -typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); -#ifdef _WINDOWS_ -typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); -#endif -typedef void (CALLBACK* _GSmakeSnapshot)(const char *path); -typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); -typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _GSconfigure)(); -typedef s32 (CALLBACK* _GStest)(); -typedef void (CALLBACK* _GSabout)(); - -// PAD -typedef s32 (CALLBACK* _PADinit)(u32 flags); -typedef s32 (CALLBACK* _PADopen)(void *pDsp); -typedef void (CALLBACK* _PADclose)(); -typedef void (CALLBACK* _PADshutdown)(); -typedef keyEvent* (CALLBACK* _PADkeyEvent)(); -typedef u8 (CALLBACK* _PADstartPoll)(int pad); -typedef u8 (CALLBACK* _PADpoll)(u8 value); -typedef u32 (CALLBACK* _PADquery)(); -typedef void (CALLBACK* _PADupdate)(int pad); - -typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); -typedef void (CALLBACK* _PADconfigure)(); -typedef s32 (CALLBACK* _PADtest)(); -typedef void (CALLBACK* _PADabout)(); - -// SIO -typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); -typedef s32 (CALLBACK* _SIOopen)(void *pDsp); -typedef void (CALLBACK* _SIOclose)(); -typedef void (CALLBACK* _SIOshutdown)(); -typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); -typedef u8 (CALLBACK* _SIOpoll)(u8 value); -typedef u32 (CALLBACK* _SIOquery)(); - -typedef void (CALLBACK* _SIOconfigure)(); -typedef s32 (CALLBACK* _SIOtest)(); -typedef void (CALLBACK* _SIOabout)(); - -// SPU2 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _SPU2init)(); -typedef s32 (CALLBACK* _SPU2open)(void *pDsp); -typedef void (CALLBACK* _SPU2close)(); -typedef void (CALLBACK* _SPU2shutdown)(); -typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); -typedef u16 (CALLBACK* _SPU2read)(u32 mem); -typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA4)(); -typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); -typedef void (CALLBACK* _SPU2interruptDMA7)(); -typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); -typedef int (CALLBACK* _SPU2setupRecording)(int, void*); - -typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); -typedef void (CALLBACK* _SPU2setTimeStretcher)(short int enable); - -typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); -typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); -typedef void (CALLBACK* _SPU2async)(u32 cycles); -typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _SPU2configure)(); -typedef s32 (CALLBACK* _SPU2test)(); -typedef void (CALLBACK* _SPU2about)(); - - -// CDVD -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _CDVDinit)(); -typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); -typedef void (CALLBACK* _CDVDclose)(); -typedef void (CALLBACK* _CDVDshutdown)(); -typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); -typedef u8* (CALLBACK* _CDVDgetBuffer)(); -typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); -typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); -typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); -typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); -typedef s32 (CALLBACK* _CDVDgetDiskType)(); -typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); -typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); -typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); - -typedef void (CALLBACK* _CDVDconfigure)(); -typedef s32 (CALLBACK* _CDVDtest)(); -typedef void (CALLBACK* _CDVDabout)(); -typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); - -// DEV9 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _DEV9init)(); -typedef s32 (CALLBACK* _DEV9open)(void *pDsp); -typedef void (CALLBACK* _DEV9close)(); -typedef void (CALLBACK* _DEV9shutdown)(); -typedef u8 (CALLBACK* _DEV9read8)(u32 mem); -typedef u16 (CALLBACK* _DEV9read16)(u32 mem); -typedef u32 (CALLBACK* _DEV9read32)(u32 mem); -typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); -typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); -typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); -typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); -typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); - -typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _DEV9configure)(); -typedef s32 (CALLBACK* _DEV9test)(); -typedef void (CALLBACK* _DEV9about)(); - -// USB -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _USBinit)(); -typedef s32 (CALLBACK* _USBopen)(void *pDsp); -typedef void (CALLBACK* _USBclose)(); -typedef void (CALLBACK* _USBshutdown)(); -typedef u8 (CALLBACK* _USBread8)(u32 mem); -typedef u16 (CALLBACK* _USBread16)(u32 mem); -typedef u32 (CALLBACK* _USBread32)(u32 mem); -typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); -typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); -typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _USBasync)(u32 cycles); - - -typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); -typedef USBhandler (CALLBACK* _USBirqHandler)(void); -typedef void (CALLBACK* _USBsetRAM)(void *mem); - -typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _USBconfigure)(); -typedef s32 (CALLBACK* _USBtest)(); -typedef void (CALLBACK* _USBabout)(); - -//FW -typedef s32 (CALLBACK* _FWinit)(); -typedef s32 (CALLBACK* _FWopen)(void *pDsp); -typedef void (CALLBACK* _FWclose)(); -typedef void (CALLBACK* _FWshutdown)(); -typedef u32 (CALLBACK* _FWread32)(u32 mem); -typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); - -typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _FWconfigure)(); -typedef s32 (CALLBACK* _FWtest)(); -typedef void (CALLBACK* _FWabout)(); - -#endif - -#ifdef PLUGINfuncs - -// GS -extern _GSinit GSinit; -extern _GSopen GSopen; -extern _GSclose GSclose; -extern _GSshutdown GSshutdown; -extern _GSvsync GSvsync; -extern _GSgifTransfer1 GSgifTransfer1; -extern _GSgifTransfer2 GSgifTransfer2; -extern _GSgifTransfer3 GSgifTransfer3; -extern _GSgetLastTag GSgetLastTag; -extern _GSgifSoftReset GSgifSoftReset; -extern _GSreadFIFO GSreadFIFO; -extern _GSreadFIFO2 GSreadFIFO2; - -extern _GSkeyEvent GSkeyEvent; -extern _GSchangeSaveState GSchangeSaveState; -extern _GSmakeSnapshot GSmakeSnapshot; -extern _GSmakeSnapshot2 GSmakeSnapshot2; -extern _GSirqCallback GSirqCallback; -extern _GSprintf GSprintf; -extern _GSsetBaseMem GSsetBaseMem; -extern _GSsetGameCRC GSsetGameCRC; -extern _GSsetFrameSkip GSsetFrameSkip; -extern _GSsetupRecording GSsetupRecording; -extern _GSreset GSreset; -extern _GSwriteCSR GSwriteCSR; -extern _GSgetDriverInfo GSgetDriverInfo; -#ifdef _WINDOWS_ -extern _GSsetWindowInfo GSsetWindowInfo; -#endif -extern _GSfreeze GSfreeze; -extern _GSconfigure GSconfigure; -extern _GStest GStest; -extern _GSabout GSabout; - -// PAD1 -extern _PADinit PAD1init; -extern _PADopen PAD1open; -extern _PADclose PAD1close; -extern _PADshutdown PAD1shutdown; -extern _PADkeyEvent PAD1keyEvent; -extern _PADstartPoll PAD1startPoll; -extern _PADpoll PAD1poll; -extern _PADquery PAD1query; -extern _PADupdate PAD1update; - -extern _PADgsDriverInfo PAD1gsDriverInfo; -extern _PADconfigure PAD1configure; -extern _PADtest PAD1test; -extern _PADabout PAD1about; - -// PAD2 -extern _PADinit PAD2init; -extern _PADopen PAD2open; -extern _PADclose PAD2close; -extern _PADshutdown PAD2shutdown; -extern _PADkeyEvent PAD2keyEvent; -extern _PADstartPoll PAD2startPoll; -extern _PADpoll PAD2poll; -extern _PADquery PAD2query; -extern _PADupdate PAD2update; - -extern _PADgsDriverInfo PAD2gsDriverInfo; -extern _PADconfigure PAD2configure; -extern _PADtest PAD2test; -extern _PADabout PAD2about; - -// SIO[2] -extern _SIOinit SIOinit[2][9]; -extern _SIOopen SIOopen[2][9]; -extern _SIOclose SIOclose[2][9]; -extern _SIOshutdown SIOshutdown[2][9]; -extern _SIOstartPoll SIOstartPoll[2][9]; -extern _SIOpoll SIOpoll[2][9]; -extern _SIOquery SIOquery[2][9]; - -extern _SIOconfigure SIOconfigure[2][9]; -extern _SIOtest SIOtest[2][9]; -extern _SIOabout SIOabout[2][9]; - -// SPU2 -extern _SPU2init SPU2init; -extern _SPU2open SPU2open; -extern _SPU2close SPU2close; -extern _SPU2shutdown SPU2shutdown; -extern _SPU2write SPU2write; -extern _SPU2read SPU2read; -extern _SPU2readDMA4Mem SPU2readDMA4Mem; -extern _SPU2writeDMA4Mem SPU2writeDMA4Mem; -extern _SPU2interruptDMA4 SPU2interruptDMA4; -extern _SPU2readDMA7Mem SPU2readDMA7Mem; -extern _SPU2writeDMA7Mem SPU2writeDMA7Mem; -extern _SPU2setDMABaseAddr SPU2setDMABaseAddr; -extern _SPU2interruptDMA7 SPU2interruptDMA7; -extern _SPU2ReadMemAddr SPU2ReadMemAddr; -extern _SPU2setupRecording SPU2setupRecording; -extern _SPU2WriteMemAddr SPU2WriteMemAddr; -extern _SPU2irqCallback SPU2irqCallback; - -extern _SPU2setClockPtr SPU2setClockPtr; -extern _SPU2setTimeStretcher SPU2setTimeStretcher; - -extern _SPU2async SPU2async; -extern _SPU2freeze SPU2freeze; -extern _SPU2configure SPU2configure; -extern _SPU2test SPU2test; -extern _SPU2about SPU2about; - -// CDVD -extern _CDVDinit CDVDinit; -extern _CDVDopen CDVDopen; -extern _CDVDclose CDVDclose; -extern _CDVDshutdown CDVDshutdown; -extern _CDVDreadTrack CDVDreadTrack; -extern _CDVDgetBuffer CDVDgetBuffer; -extern _CDVDreadSubQ CDVDreadSubQ; -extern _CDVDgetTN CDVDgetTN; -extern _CDVDgetTD CDVDgetTD; -extern _CDVDgetTOC CDVDgetTOC; -extern _CDVDgetDiskType CDVDgetDiskType; -extern _CDVDgetTrayStatus CDVDgetTrayStatus; -extern _CDVDctrlTrayOpen CDVDctrlTrayOpen; -extern _CDVDctrlTrayClose CDVDctrlTrayClose; - -extern _CDVDconfigure CDVDconfigure; -extern _CDVDtest CDVDtest; -extern _CDVDabout CDVDabout; -extern _CDVDnewDiskCB CDVDnewDiskCB; - -// DEV9 -extern _DEV9init DEV9init; -extern _DEV9open DEV9open; -extern _DEV9close DEV9close; -extern _DEV9shutdown DEV9shutdown; -extern _DEV9read8 DEV9read8; -extern _DEV9read16 DEV9read16; -extern _DEV9read32 DEV9read32; -extern _DEV9write8 DEV9write8; -extern _DEV9write16 DEV9write16; -extern _DEV9write32 DEV9write32; -extern _DEV9readDMA8Mem DEV9readDMA8Mem; -extern _DEV9writeDMA8Mem DEV9writeDMA8Mem; -extern _DEV9irqCallback DEV9irqCallback; -extern _DEV9irqHandler DEV9irqHandler; - -extern _DEV9configure DEV9configure; -extern _DEV9freeze DEV9freeze; -extern _DEV9test DEV9test; -extern _DEV9about DEV9about; - -// USB -extern _USBinit USBinit; -extern _USBopen USBopen; -extern _USBclose USBclose; -extern _USBshutdown USBshutdown; -extern _USBread8 USBread8; -extern _USBread16 USBread16; -extern _USBread32 USBread32; -extern _USBwrite8 USBwrite8; -extern _USBwrite16 USBwrite16; -extern _USBwrite32 USBwrite32; -extern _USBasync USBasync; - -extern _USBirqCallback USBirqCallback; -extern _USBirqHandler USBirqHandler; -extern _USBsetRAM USBsetRAM; - -extern _USBconfigure USBconfigure; -extern _USBfreeze USBfreeze; -extern _USBtest USBtest; -extern _USBabout USBabout; - -// FW -extern _FWinit FWinit; -extern _FWopen FWopen; -extern _FWclose FWclose; -extern _FWshutdown FWshutdown; -extern _FWread32 FWread32; -extern _FWwrite32 FWwrite32; -extern _FWirqCallback FWirqCallback; - -extern _FWconfigure FWconfigure; -extern _FWfreeze FWfreeze; -extern _FWtest FWtest; -extern _FWabout FWabout; -#endif - -#ifdef __cplusplus -} // End extern "C" -#endif - -#endif /* __PS2EDEFS_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct _keyEvent { + u32 key; + u32 evt; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct _cdvdSubQ { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct _cdvdTD { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct _cdvdTN { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct _GSdriverInfo { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WINDOWS_ +typedef struct _winInfo { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2setClockPtr(u32* ptr); +void CALLBACK SPU2setTimeStretcher(short int enable); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +void CALLBACK USBasync(u32 cycles); + +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WINDOWS_ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(const char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); + +typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); +typedef void (CALLBACK* _SPU2setTimeStretcher)(short int enable); + +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBasync)(u32 cycles); + + +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +extern _GSinit GSinit; +extern _GSopen GSopen; +extern _GSclose GSclose; +extern _GSshutdown GSshutdown; +extern _GSvsync GSvsync; +extern _GSgifTransfer1 GSgifTransfer1; +extern _GSgifTransfer2 GSgifTransfer2; +extern _GSgifTransfer3 GSgifTransfer3; +extern _GSgetLastTag GSgetLastTag; +extern _GSgifSoftReset GSgifSoftReset; +extern _GSreadFIFO GSreadFIFO; +extern _GSreadFIFO2 GSreadFIFO2; + +extern _GSkeyEvent GSkeyEvent; +extern _GSchangeSaveState GSchangeSaveState; +extern _GSmakeSnapshot GSmakeSnapshot; +extern _GSmakeSnapshot2 GSmakeSnapshot2; +extern _GSirqCallback GSirqCallback; +extern _GSprintf GSprintf; +extern _GSsetBaseMem GSsetBaseMem; +extern _GSsetGameCRC GSsetGameCRC; +extern _GSsetFrameSkip GSsetFrameSkip; +extern _GSsetupRecording GSsetupRecording; +extern _GSreset GSreset; +extern _GSwriteCSR GSwriteCSR; +extern _GSgetDriverInfo GSgetDriverInfo; +#ifdef _WINDOWS_ +extern _GSsetWindowInfo GSsetWindowInfo; +#endif +extern _GSfreeze GSfreeze; +extern _GSconfigure GSconfigure; +extern _GStest GStest; +extern _GSabout GSabout; + +// PAD1 +extern _PADinit PAD1init; +extern _PADopen PAD1open; +extern _PADclose PAD1close; +extern _PADshutdown PAD1shutdown; +extern _PADkeyEvent PAD1keyEvent; +extern _PADstartPoll PAD1startPoll; +extern _PADpoll PAD1poll; +extern _PADquery PAD1query; +extern _PADupdate PAD1update; + +extern _PADgsDriverInfo PAD1gsDriverInfo; +extern _PADconfigure PAD1configure; +extern _PADtest PAD1test; +extern _PADabout PAD1about; + +// PAD2 +extern _PADinit PAD2init; +extern _PADopen PAD2open; +extern _PADclose PAD2close; +extern _PADshutdown PAD2shutdown; +extern _PADkeyEvent PAD2keyEvent; +extern _PADstartPoll PAD2startPoll; +extern _PADpoll PAD2poll; +extern _PADquery PAD2query; +extern _PADupdate PAD2update; + +extern _PADgsDriverInfo PAD2gsDriverInfo; +extern _PADconfigure PAD2configure; +extern _PADtest PAD2test; +extern _PADabout PAD2about; + +// SIO[2] +extern _SIOinit SIOinit[2][9]; +extern _SIOopen SIOopen[2][9]; +extern _SIOclose SIOclose[2][9]; +extern _SIOshutdown SIOshutdown[2][9]; +extern _SIOstartPoll SIOstartPoll[2][9]; +extern _SIOpoll SIOpoll[2][9]; +extern _SIOquery SIOquery[2][9]; + +extern _SIOconfigure SIOconfigure[2][9]; +extern _SIOtest SIOtest[2][9]; +extern _SIOabout SIOabout[2][9]; + +// SPU2 +extern _SPU2init SPU2init; +extern _SPU2open SPU2open; +extern _SPU2close SPU2close; +extern _SPU2shutdown SPU2shutdown; +extern _SPU2write SPU2write; +extern _SPU2read SPU2read; +extern _SPU2readDMA4Mem SPU2readDMA4Mem; +extern _SPU2writeDMA4Mem SPU2writeDMA4Mem; +extern _SPU2interruptDMA4 SPU2interruptDMA4; +extern _SPU2readDMA7Mem SPU2readDMA7Mem; +extern _SPU2writeDMA7Mem SPU2writeDMA7Mem; +extern _SPU2setDMABaseAddr SPU2setDMABaseAddr; +extern _SPU2interruptDMA7 SPU2interruptDMA7; +extern _SPU2ReadMemAddr SPU2ReadMemAddr; +extern _SPU2setupRecording SPU2setupRecording; +extern _SPU2WriteMemAddr SPU2WriteMemAddr; +extern _SPU2irqCallback SPU2irqCallback; + +extern _SPU2setClockPtr SPU2setClockPtr; +extern _SPU2setTimeStretcher SPU2setTimeStretcher; + +extern _SPU2async SPU2async; +extern _SPU2freeze SPU2freeze; +extern _SPU2configure SPU2configure; +extern _SPU2test SPU2test; +extern _SPU2about SPU2about; + +// CDVD +extern _CDVDinit CDVDinit; +extern _CDVDopen CDVDopen; +extern _CDVDclose CDVDclose; +extern _CDVDshutdown CDVDshutdown; +extern _CDVDreadTrack CDVDreadTrack; +extern _CDVDgetBuffer CDVDgetBuffer; +extern _CDVDreadSubQ CDVDreadSubQ; +extern _CDVDgetTN CDVDgetTN; +extern _CDVDgetTD CDVDgetTD; +extern _CDVDgetTOC CDVDgetTOC; +extern _CDVDgetDiskType CDVDgetDiskType; +extern _CDVDgetTrayStatus CDVDgetTrayStatus; +extern _CDVDctrlTrayOpen CDVDctrlTrayOpen; +extern _CDVDctrlTrayClose CDVDctrlTrayClose; + +extern _CDVDconfigure CDVDconfigure; +extern _CDVDtest CDVDtest; +extern _CDVDabout CDVDabout; +extern _CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +extern _DEV9init DEV9init; +extern _DEV9open DEV9open; +extern _DEV9close DEV9close; +extern _DEV9shutdown DEV9shutdown; +extern _DEV9read8 DEV9read8; +extern _DEV9read16 DEV9read16; +extern _DEV9read32 DEV9read32; +extern _DEV9write8 DEV9write8; +extern _DEV9write16 DEV9write16; +extern _DEV9write32 DEV9write32; +extern _DEV9readDMA8Mem DEV9readDMA8Mem; +extern _DEV9writeDMA8Mem DEV9writeDMA8Mem; +extern _DEV9irqCallback DEV9irqCallback; +extern _DEV9irqHandler DEV9irqHandler; + +extern _DEV9configure DEV9configure; +extern _DEV9freeze DEV9freeze; +extern _DEV9test DEV9test; +extern _DEV9about DEV9about; + +// USB +extern _USBinit USBinit; +extern _USBopen USBopen; +extern _USBclose USBclose; +extern _USBshutdown USBshutdown; +extern _USBread8 USBread8; +extern _USBread16 USBread16; +extern _USBread32 USBread32; +extern _USBwrite8 USBwrite8; +extern _USBwrite16 USBwrite16; +extern _USBwrite32 USBwrite32; +extern _USBasync USBasync; + +extern _USBirqCallback USBirqCallback; +extern _USBirqHandler USBirqHandler; +extern _USBsetRAM USBsetRAM; + +extern _USBconfigure USBconfigure; +extern _USBfreeze USBfreeze; +extern _USBtest USBtest; +extern _USBabout USBabout; + +// FW +extern _FWinit FWinit; +extern _FWopen FWopen; +extern _FWclose FWclose; +extern _FWshutdown FWshutdown; +extern _FWread32 FWread32; +extern _FWwrite32 FWwrite32; +extern _FWirqCallback FWirqCallback; + +extern _FWconfigure FWconfigure; +extern _FWfreeze FWfreeze; +extern _FWtest FWtest; +extern _FWabout FWabout; +#endif + +#ifdef __cplusplus +} // End extern "C" +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/common/includes/PS2Etypes.h b/common/includes/PS2Etypes.h index 59be1c3de4..4c62b47f0f 100644 --- a/common/includes/PS2Etypes.h +++ b/common/includes/PS2Etypes.h @@ -1,219 +1,219 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef __PS2ETYPES_H__ -#define __PS2ETYPES_H__ - -#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case -#define __LINUX__ -#endif - -#ifdef __CYGWIN__ -#define __LINUX__ -#endif - -#ifndef ARRAYSIZE -#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) -#endif - -#ifdef __LINUX__ -#define CALLBACK -#else -#define CALLBACK __stdcall -#endif - - -// jASSUME - give hints to the optimizer -// This is primarily useful for the default case switch optimizer, which enables VC to -// generate more compact switches. - -#ifdef NDEBUG -# define jBREAKPOINT() ((void) 0) -# ifdef _MSC_VER -# define jASSUME(exp) (__assume(exp)) -# else -# define jASSUME(exp) ((void) sizeof(exp)) -# endif -#else -# if defined(_MSC_VER) -# define jBREAKPOINT() do { __asm int 3 } while(0) -# else -# define jBREAKPOINT() ((void) *(volatile char *) 0) -# endif -# define jASSUME(exp) if(exp) ; else jBREAKPOINT() -#endif - -// disable the default case in a switch -#define jNO_DEFAULT \ -{ \ - break; \ - \ -default: \ - jASSUME(0); \ - break; \ -} - - -// Basic types -#if defined(_MSC_VER) - -typedef __int8 s8; -typedef __int16 s16; -typedef __int32 s32; -typedef __int64 s64; - -typedef unsigned __int8 u8; -typedef unsigned __int16 u16; -typedef unsigned __int32 u32; -typedef unsigned __int64 u64; - -typedef unsigned int uint; - -#define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x -#define PCSX2_ALIGNED16(x) __declspec(align(16)) x -#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x - -#define __naked __declspec(naked) - -#else // _MSC_VER - -#ifdef __LINUX__ - -#ifdef HAVE_STDINT_H -#include "stdint.h" - -typedef int8_t s8; -typedef int16_t s16; -typedef int32_t s32; -typedef int64_t s64; - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -typedef uintptr_t uptr; -typedef intptr_t sptr; - -#else // HAVE_STDINT_H - -typedef char s8; -typedef short s16; -typedef int s32; -typedef long long s64; - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long long u64; - -#endif // HAVE_STDINT_H - -typedef unsigned int uint; - -#define LONG long -typedef union _LARGE_INTEGER -{ - long long QuadPart; -} LARGE_INTEGER; - -#define __fastcall __attribute__((fastcall)) -#define __unused __attribute__((unused)) -#define _inline __inline__ __attribute__((unused)) -#define __forceinline __attribute__((always_inline,unused)) -#define __naked // GCC lacks the naked specifier - -#endif // __LINUX__ - -#define PCSX2_ALIGNED(alig,x) x __attribute((aligned(alig))) -#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) - -#define PCSX2_ALIGNED16_DECL(x) x - -#endif // _MSC_VER - -#if !defined(__LINUX__) || !defined(HAVE_STDINT_H) -#if defined(__x86_64__) -typedef u64 uptr; -typedef s64 sptr; -#else -typedef u32 uptr; -typedef s32 sptr; -#endif -#endif - -// A rough-and-ready cross platform 128-bit datatype, Non-SSE style. -#ifdef __cplusplus -struct u128 -{ - u64 lo; - u64 hi; - - // Implicit conversion from u64 - u128( u64 src ) : - lo( src ) - , hi( 0 ) {} - - // Implicit conversion from u32 - u128( u32 src ) : - lo( src ) - , hi( 0 ) {} -}; - -struct s128 -{ - s64 lo; - s64 hi; - - // Implicit conversion from u64 - s128( s64 src ) : - lo( src ) - , hi( 0 ) {} - - // Implicit conversion from u32 - s128( s32 src ) : - lo( src ) - , hi( 0 ) {} -}; - -#else - -typedef union _u128_t -{ - u64 lo; - u64 hi; -} u128; - -typedef union _s128_t -{ - s64 lo; - s64 hi; -} s128; - -#endif - -typedef struct { - int size; - s8 *data; -} freezeData; - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#endif /* __PS2ETYPES_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +#ifdef __CYGWIN__ +#define __LINUX__ +#endif + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#ifdef __LINUX__ +#define CALLBACK +#else +#define CALLBACK __stdcall +#endif + + +// jASSUME - give hints to the optimizer +// This is primarily useful for the default case switch optimizer, which enables VC to +// generate more compact switches. + +#ifdef NDEBUG +# define jBREAKPOINT() ((void) 0) +# ifdef _MSC_VER +# define jASSUME(exp) (__assume(exp)) +# else +# define jASSUME(exp) ((void) sizeof(exp)) +# endif +#else +# if defined(_MSC_VER) +# define jBREAKPOINT() do { __asm int 3 } while(0) +# else +# define jBREAKPOINT() ((void) *(volatile char *) 0) +# endif +# define jASSUME(exp) if(exp) ; else jBREAKPOINT() +#endif + +// disable the default case in a switch +#define jNO_DEFAULT \ +{ \ + break; \ + \ +default: \ + jASSUME(0); \ + break; \ +} + + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +typedef unsigned int uint; + +#define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x + +#define __naked __declspec(naked) + +#else // _MSC_VER + +#ifdef __LINUX__ + +#ifdef HAVE_STDINT_H +#include "stdint.h" + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef uintptr_t uptr; +typedef intptr_t sptr; + +#else // HAVE_STDINT_H + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#endif // HAVE_STDINT_H + +typedef unsigned int uint; + +#define LONG long +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; + +#define __fastcall __attribute__((fastcall)) +#define __unused __attribute__((unused)) +#define _inline __inline__ __attribute__((unused)) +#define __forceinline __attribute__((always_inline,unused)) +#define __naked // GCC lacks the naked specifier + +#endif // __LINUX__ + +#define PCSX2_ALIGNED(alig,x) x __attribute((aligned(alig))) +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) + +#define PCSX2_ALIGNED16_DECL(x) x + +#endif // _MSC_VER + +#if !defined(__LINUX__) || !defined(HAVE_STDINT_H) +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif +#endif + +// A rough-and-ready cross platform 128-bit datatype, Non-SSE style. +#ifdef __cplusplus +struct u128 +{ + u64 lo; + u64 hi; + + // Implicit conversion from u64 + u128( u64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + u128( u32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +struct s128 +{ + s64 lo; + s64 hi; + + // Implicit conversion from u64 + s128( s64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + s128( s32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +#else + +typedef union _u128_t +{ + u64 lo; + u64 hi; +} u128; + +typedef union _s128_t +{ + s64 lo; + s64 hi; +} s128; + +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/common/tsvnrev/svnrev_template.h b/common/tsvnrev/svnrev_template.h index 50327f3f30..a67a4629bd 100644 --- a/common/tsvnrev/svnrev_template.h +++ b/common/tsvnrev/svnrev_template.h @@ -1,18 +1,18 @@ -// svnrev_template.h --> svnrev.h -// -// This file acts as a template for the automatic SVN revision/version tag. -// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for -// whichever project is being compiled (as indicated by command line options -// passed to SubWCRev.exe during the project's pre-build step). -// -// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs -// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN -// installed on your system. If you do not have it installed, a generic template -// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not -// necessary. If you do not have it installed, everything will still compile -// fine except without the SVN revision tagged to the application/dll version. -// -// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org - -#define SVN_REV $WCREV$ +// svnrev_template.h --> svnrev.h +// +// This file acts as a template for the automatic SVN revision/version tag. +// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for +// whichever project is being compiled (as indicated by command line options +// passed to SubWCRev.exe during the project's pre-build step). +// +// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs +// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN +// installed on your system. If you do not have it installed, a generic template +// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not +// necessary. If you do not have it installed, everything will still compile +// fine except without the SVN revision tagged to the application/dll version. +// +// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV $WCREV$ #define SVN_MODS $WCMODS?1:0$ \ No newline at end of file diff --git a/common/tsvnrev/svnrev_unknown.h b/common/tsvnrev/svnrev_unknown.h index a2a3703186..4872e23b20 100644 --- a/common/tsvnrev/svnrev_unknown.h +++ b/common/tsvnrev/svnrev_unknown.h @@ -1,23 +1,23 @@ -// svnrev_genric.h --> svnrev.h -// -// This file acts as a placebo for people who do not have TortoiseSVN installed. -// It provides "empty" revision information to the Pcsx2 Playground projects in -// the absence of real revisions derived from the repository being built. -// -// This file does not affect application/dll builds in any significant manner, -// other than the lack of automatic revision tags inserted into the app (which -// is very convenient but hardly necessary). -// -// See svn_template.h for more information on how the process of revision -// templating works. -// -// If you would like to enable automatic revisin tagging, TortoiseSVN can be -// downloaded from http://tortoisesvn.tigris.org - -#define SVN_REV_UNKNOWN - -// The following defines are included so that code will still compile even if it -// doesn't check for the SVN_REV_UNKNOWN define. - -#define SVN_REV 0 +// svnrev_genric.h --> svnrev.h +// +// This file acts as a placebo for people who do not have TortoiseSVN installed. +// It provides "empty" revision information to the Pcsx2 Playground projects in +// the absence of real revisions derived from the repository being built. +// +// This file does not affect application/dll builds in any significant manner, +// other than the lack of automatic revision tags inserted into the app (which +// is very convenient but hardly necessary). +// +// See svn_template.h for more information on how the process of revision +// templating works. +// +// If you would like to enable automatic revisin tagging, TortoiseSVN can be +// downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV_UNKNOWN + +// The following defines are included so that code will still compile even if it +// doesn't check for the SVN_REV_UNKNOWN define. + +#define SVN_REV 0 #define SVN_MODS "" \ No newline at end of file diff --git a/fps2bios/Makefile b/fps2bios/Makefile index ce6478f8fa..d591c80da7 100644 --- a/fps2bios/Makefile +++ b/fps2bios/Makefile @@ -1,57 +1,57 @@ -# -# - -all: ps2romgen_exe romdir_exe romver_exe fps2bios - -VERSION = 0 -BUILD = 1 - -CC = gcc -RM = rm -f -STRIP = strip - -OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -CFLAGS = -Wall ${OPTIMIZE} -I. -DIRS = kernel intro loader -FILES = RESET ROMDIR EXTINFO ROMVER IOPBOOT EELOAD \ - SYSMEM LOADCORE EXCEPMAN INTRMAN SSBUSC DMACMAN \ - TIMRMAN SYSCLIB HEAPLIB THREADMAN VBLANK STDIO \ - SIFMAN SIFCMD SIO2MAN LOADER INTRO IOPBTCONF FP2BLOGO \ - IOMAN MODLOAD ROMDRV IGREETING REBOOT LOADFILE CDVDMAN \ - CDVDFSV SIFINIT FILEIO SECRMAN EESYNC - -ps2romgen_exe: ps2romgen.o - ${CC} ${CFLAGS} ps2romgen.o -o build/ps2romgen_exe - -romdir_exe: romdir.o - ${CC} ${CFLAGS} romdir.o -o build/romdir_exe - -romver_exe: romver.o - ${CC} ${CFLAGS} romver.o -o build/romver_exe - -fps2bios: - for i in $(DIRS); do \ - (cd $$i; make; cd ..) \ - done; - cp -f used/* build - cp -f FP2BLOGO build - cp -f IOPBTCONF build/ - (cd build; \ - ./romver_exe $(VERSION) $(BUILD); \ - ./romdir_exe $(FILES); \ - ./ps2romgen_exe fps2bios; \ - cd ..) - cp build/fps2bios ../bin/bios - -.PHONY: clean ps2romgen_exe romdir_exe fps2bios - -clean: - ${RM} *.o build/* - for i in $(DIRS); do \ - (cd $$i; make clean; cd ..) \ - done; - -%.o: %.c - ${CC} ${CFLAGS} -c -o $@ $< - - +# +# + +all: ps2romgen_exe romdir_exe romver_exe fps2bios + +VERSION = 0 +BUILD = 1 + +CC = gcc +RM = rm -f +STRIP = strip + +OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math +CFLAGS = -Wall ${OPTIMIZE} -I. +DIRS = kernel intro loader +FILES = RESET ROMDIR EXTINFO ROMVER IOPBOOT EELOAD \ + SYSMEM LOADCORE EXCEPMAN INTRMAN SSBUSC DMACMAN \ + TIMRMAN SYSCLIB HEAPLIB THREADMAN VBLANK STDIO \ + SIFMAN SIFCMD SIO2MAN LOADER INTRO IOPBTCONF FP2BLOGO \ + IOMAN MODLOAD ROMDRV IGREETING REBOOT LOADFILE CDVDMAN \ + CDVDFSV SIFINIT FILEIO SECRMAN EESYNC + +ps2romgen_exe: ps2romgen.o + ${CC} ${CFLAGS} ps2romgen.o -o build/ps2romgen_exe + +romdir_exe: romdir.o + ${CC} ${CFLAGS} romdir.o -o build/romdir_exe + +romver_exe: romver.o + ${CC} ${CFLAGS} romver.o -o build/romver_exe + +fps2bios: + for i in $(DIRS); do \ + (cd $$i; make; cd ..) \ + done; + cp -f used/* build + cp -f FP2BLOGO build + cp -f IOPBTCONF build/ + (cd build; \ + ./romver_exe $(VERSION) $(BUILD); \ + ./romdir_exe $(FILES); \ + ./ps2romgen_exe fps2bios; \ + cd ..) + cp build/fps2bios ../bin/bios + +.PHONY: clean ps2romgen_exe romdir_exe fps2bios + +clean: + ${RM} *.o build/* + for i in $(DIRS); do \ + (cd $$i; make clean; cd ..) \ + done; + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< + + diff --git a/fps2bios/intro/Makefile b/fps2bios/intro/Makefile index b02228b3d8..7ebb188850 100644 --- a/fps2bios/intro/Makefile +++ b/fps2bios/intro/Makefile @@ -1,57 +1,57 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -G0 -D_EE -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: intro - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -L$(PS2LIB)/ee/lib -LDADD = -lmc -lpad -lc -lkernel -lm -OBJECTS = intro.o eedebug.o crt0.o romdir.o -DEST = ../build/INTRO - -intro: $(OBJECTS) - $(EELD) -T linkfile $(EECFLAGS) $(OBJECTS) $(LDFLAGS) $(LDADD) -o $(DEST) - -%.o: %.c - $(EECC) $(EEINCLUDES) $(EECFLAGS) -o $@ -c $< - -%.o: %.s - $(EECC) $(EEINCLUDES) $(EECFLAGS) -o $@ -c $< - - -clean: - rm -f $(OBJECTS) $(DEST) - - - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -G0 -D_EE +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: intro + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/ee/lib +LDADD = -lmc -lpad -lc -lkernel -lm +OBJECTS = intro.o eedebug.o crt0.o romdir.o +DEST = ../build/INTRO + +intro: $(OBJECTS) + $(EELD) -T linkfile $(EECFLAGS) $(OBJECTS) $(LDFLAGS) $(LDADD) -o $(DEST) + +%.o: %.c + $(EECC) $(EEINCLUDES) $(EECFLAGS) -o $@ -c $< + +%.o: %.s + $(EECC) $(EEINCLUDES) $(EECFLAGS) -o $@ -c $< + + +clean: + rm -f $(OBJECTS) $(DEST) + + + diff --git a/fps2bios/intro/eedebug.c b/fps2bios/intro/eedebug.c index 6fa7c8e108..f7cc8a1807 100644 --- a/fps2bios/intro/eedebug.c +++ b/fps2bios/intro/eedebug.c @@ -1,31 +1,31 @@ - -#include -#include -#include - - -void __putc(u8 c) { - while (*((u32*)0x1000f130) & 0x8000) { __asm__ ("nop\nnop\nnop\n"); } - - *((u8*)0x1000f180) = c; -} - -void __puts(u8 *s) { - while (*s != 0) { - __putc(*s++); - } -} - -int __printf(const char *format, ...) { - char buf[4096]; - va_list args; - int ret; - - va_start(args, format); - ret = vsnprintf(buf, 4096, format, args); - va_end(args); - - __puts((u8*)buf); - return ret; -} - + +#include +#include +#include + + +void __putc(u8 c) { + while (*((u32*)0x1000f130) & 0x8000) { __asm__ ("nop\nnop\nnop\n"); } + + *((u8*)0x1000f180) = c; +} + +void __puts(u8 *s) { + while (*s != 0) { + __putc(*s++); + } +} + +int __printf(const char *format, ...) { + char buf[4096]; + va_list args; + int ret; + + va_start(args, format); + ret = vsnprintf(buf, 4096, format, args); + va_end(args); + + __puts((u8*)buf); + return ret; +} + diff --git a/fps2bios/intro/include/eedebug.h b/fps2bios/intro/include/eedebug.h index dfe853c609..503f65e062 100644 --- a/fps2bios/intro/include/eedebug.h +++ b/fps2bios/intro/include/eedebug.h @@ -1,12 +1,12 @@ -#ifndef __EEDEBUG_H__ -#define __EEDEBUG_H__ - -#include -#include - - -void __putc(u8 c); -void __puts(u8 *s); -int __printf(const char *format, ...); - -#endif /* __EEDEBUG_H__ */ +#ifndef __EEDEBUG_H__ +#define __EEDEBUG_H__ + +#include +#include + + +void __putc(u8 c); +void __puts(u8 *s); +int __printf(const char *format, ...); + +#endif /* __EEDEBUG_H__ */ diff --git a/fps2bios/intro/include/romdir.h b/fps2bios/intro/include/romdir.h index 8249989e78..ef03a3223d 100644 --- a/fps2bios/intro/include/romdir.h +++ b/fps2bios/intro/include/romdir.h @@ -1,20 +1,20 @@ -#ifndef __ROMDIR_H__ -#define __ROMDIR_H__ - -#include - -struct romdir { - /*following variable must place in designed order*/ - u8 fileName[10]; - u16 extInfoSize; - u32 fileSize; -} __attribute__ ((packed)); - -struct rominfo { - u32 fileOffset; - u32 fileSize; -}; - -struct rominfo *romdirGetFile(char *name, struct rominfo *ri); - -#endif /* __ROMDIR_H__ */ +#ifndef __ROMDIR_H__ +#define __ROMDIR_H__ + +#include + +struct romdir { + /*following variable must place in designed order*/ + u8 fileName[10]; + u16 extInfoSize; + u32 fileSize; +} __attribute__ ((packed)); + +struct rominfo { + u32 fileOffset; + u32 fileSize; +}; + +struct rominfo *romdirGetFile(char *name, struct rominfo *ri); + +#endif /* __ROMDIR_H__ */ diff --git a/fps2bios/intro/intro.c b/fps2bios/intro/intro.c index a9d54ca3d5..7972a8ed28 100644 --- a/fps2bios/intro/intro.c +++ b/fps2bios/intro/intro.c @@ -1,19 +1,19 @@ - -#include -#include -#include -#include - -#include "eedebug.h" -#include "romdir.h" - - -int main() { - - __printf("INTRO start\n"); - - __printf("INTRO end\n"); - - return 0; -} - + +#include +#include +#include +#include + +#include "eedebug.h" +#include "romdir.h" + + +int main() { + + __printf("INTRO start\n"); + + __printf("INTRO end\n"); + + return 0; +} + diff --git a/fps2bios/intro/romdir.c b/fps2bios/intro/romdir.c index 2487288f0f..b23a5b2722 100644 --- a/fps2bios/intro/romdir.c +++ b/fps2bios/intro/romdir.c @@ -1,43 +1,43 @@ -/*************************************************************** -* romdir.c, based over Alex Lau (http://alexlau.8k.com) RomDir * -****************************************************************/ -#include "romdir.h" - -struct romdir *romdirInit() { - u8 *mem; - - for (mem=(u8*)0xbfc00000; (u32)mem<0xbfc01000; mem++) { - if (mem[0] == 'R' && mem[1] == 'E' && - mem[2] == 'S' && mem[3] == 'E' && - mem[4] == 'T') - break; - } - if ((u32)mem == 0xbfc01000) return NULL; - - return (struct romdir*)mem; -} - -struct rominfo *romdirGetFile(char *name, struct rominfo *ri) { - struct romdir *rd; - struct romdir *base; - int i; - - base = romdirInit(); - if (base == NULL) return NULL; - - ri->fileOffset = 0; - for (rd = base; rd->fileName[0] != 0; rd++) { - for (i=0; i<10 && name[i] != 0; i++) { - if (rd->fileName[i] != name[i]) break; - } - if (rd->fileName[i] != name[i]) { - ri->fileOffset+= (rd->fileSize + 15) & ~0xF; - continue; - } - - ri->fileSize = rd->fileSize; - return ri; - } - - return NULL; -} +/*************************************************************** +* romdir.c, based over Alex Lau (http://alexlau.8k.com) RomDir * +****************************************************************/ +#include "romdir.h" + +struct romdir *romdirInit() { + u8 *mem; + + for (mem=(u8*)0xbfc00000; (u32)mem<0xbfc01000; mem++) { + if (mem[0] == 'R' && mem[1] == 'E' && + mem[2] == 'S' && mem[3] == 'E' && + mem[4] == 'T') + break; + } + if ((u32)mem == 0xbfc01000) return NULL; + + return (struct romdir*)mem; +} + +struct rominfo *romdirGetFile(char *name, struct rominfo *ri) { + struct romdir *rd; + struct romdir *base; + int i; + + base = romdirInit(); + if (base == NULL) return NULL; + + ri->fileOffset = 0; + for (rd = base; rd->fileName[0] != 0; rd++) { + for (i=0; i<10 && name[i] != 0; i++) { + if (rd->fileName[i] != name[i]) break; + } + if (rd->fileName[i] != name[i]) { + ri->fileOffset+= (rd->fileSize + 15) & ~0xF; + continue; + } + + ri->fileSize = rd->fileSize; + return ri; + } + + return NULL; +} diff --git a/fps2bios/kernel/Makefile b/fps2bios/kernel/Makefile index 566a5dee9f..8644706e9d 100644 --- a/fps2bios/kernel/Makefile +++ b/fps2bios/kernel/Makefile @@ -1,73 +1,73 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -G0 -EEINCLUDES = -I. -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include - -IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 -IOPINCLUDES = -I. -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include -IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -IOPLINK = $(IOPLD) -dc - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: start - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -OBJS = eestart.o iopstart.o start.o romdir.o -DIRS = eeload iopload - -start: $(OBJS) - for i in $(DIRS); do \ - (cd $$i; make; cd ..) \ - done; - $(EELD) -Wl,--oformat,binary -T linkfile $(EECFLAGS) $(OBJS) -o ../build/RESET - -iopstart.o: iopstart.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - -eestart.o: eestart.c - $(EECC) $(EEINCLUDES) $(EECFLAGS) -o $@ -c $< - -romdir.o: romdir.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - -start.o: start.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - - - -clean: - for i in $(DIRS); do \ - (cd $$i; make clean; cd ..) \ - done; - rm -f $(OBJS) start - - - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -G0 +EEINCLUDES = -I. -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: start + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +OBJS = eestart.o iopstart.o start.o romdir.o +DIRS = eeload iopload + +start: $(OBJS) + for i in $(DIRS); do \ + (cd $$i; make; cd ..) \ + done; + $(EELD) -Wl,--oformat,binary -T linkfile $(EECFLAGS) $(OBJS) -o ../build/RESET + +iopstart.o: iopstart.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +eestart.o: eestart.c + $(EECC) $(EEINCLUDES) $(EECFLAGS) -o $@ -c $< + +romdir.o: romdir.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +start.o: start.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + + + +clean: + for i in $(DIRS); do \ + (cd $$i; make clean; cd ..) \ + done; + rm -f $(OBJS) start + + + diff --git a/fps2bios/kernel/eeload/Makefile b/fps2bios/kernel/eeload/Makefile index c836b90d7d..9076329965 100644 --- a/fps2bios/kernel/eeload/Makefile +++ b/fps2bios/kernel/eeload/Makefile @@ -1,61 +1,61 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -G0 -D_EE --save-temps -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include - -IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -IOPINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include -IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -IOPLINK = $(IOPLD) -dc - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: eeload - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -L$(PS2LIB)/ee/lib -LDADD = -lmc -lpad -lc -lkernel -OBJECTS = eeirq.o eedata.o eekernel.o eeinit.o eeload.o eeelf.o eedebug.o romdir.o - -eeload: $(OBJECTS) - $(EELD) -Wl,--oformat,binary,--Map,eeload.map -T linkfile $(EECFLAGS) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../build/EELOAD - -# restrict all but the kernel registers -eeirq.o: eeirq.c - $(EECC) $(EEINCLUDES) $(EECFLAGS) -ffixed-2 -ffixed-3 -ffixed-4 -ffixed-5 -ffixed-6 -ffixed-7 -ffixed-8 -ffixed-9 -ffixed-10 -ffixed-11 -ffixed-12 -ffixed-13 -ffixed-14 -ffixed-15 -ffixed-16 -ffixed-17 -ffixed-18 -ffixed-19 -ffixed-20 -ffixed-21 -ffixed-22 -ffixed-23 -ffixed-24 -ffixed-25 -fcall-used-26 -fcall-used-27 -ffixed-30 -o $@ -c $< -%.o: %.c - $(EECC) $(EEINCLUDES) $(EECFLAGS) -o $@ -c $< - - -clean: - rm -f $(OBJECTS) eeload - - - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -G0 -D_EE --save-temps +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles +IOPINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: eeload + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/ee/lib +LDADD = -lmc -lpad -lc -lkernel +OBJECTS = eeirq.o eedata.o eekernel.o eeinit.o eeload.o eeelf.o eedebug.o romdir.o + +eeload: $(OBJECTS) + $(EELD) -Wl,--oformat,binary,--Map,eeload.map -T linkfile $(EECFLAGS) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../build/EELOAD + +# restrict all but the kernel registers +eeirq.o: eeirq.c + $(EECC) $(EEINCLUDES) $(EECFLAGS) -ffixed-2 -ffixed-3 -ffixed-4 -ffixed-5 -ffixed-6 -ffixed-7 -ffixed-8 -ffixed-9 -ffixed-10 -ffixed-11 -ffixed-12 -ffixed-13 -ffixed-14 -ffixed-15 -ffixed-16 -ffixed-17 -ffixed-18 -ffixed-19 -ffixed-20 -ffixed-21 -ffixed-22 -ffixed-23 -ffixed-24 -ffixed-25 -fcall-used-26 -fcall-used-27 -ffixed-30 -o $@ -c $< +%.o: %.c + $(EECC) $(EEINCLUDES) $(EECFLAGS) -o $@ -c $< + + +clean: + rm -f $(OBJECTS) eeload + + + diff --git a/fps2bios/kernel/eeload/eedata.c b/fps2bios/kernel/eeload/eedata.c index 9343330287..5b6f25bd57 100644 --- a/fps2bios/kernel/eeload/eedata.c +++ b/fps2bios/kernel/eeload/eedata.c @@ -1,198 +1,198 @@ -// eedata.c - needed in order to assure -// that some of the kernel variables are as close to 0x80000000 as possible -// (ie, look in saveContext2) -//[made by] [RO]man, zerofrog - -#include -#include -#include - -#include "eekernel.h" -#include "eeirq.h" - -eeRegs SavedRegs __attribute((aligned(256))); -u128 SavedSP __attribute((aligned(16))); -u128 SavedRA __attribute((aligned(16))); -u128 SavedAT __attribute((aligned(16))); -u64 SavedT9 __attribute((aligned(16))); - -u32 _CpuConfig_0(u32); -u32 _CpuConfig_1(u32); -u32 _CpuConfig_2(u32); -u32 _CpuConfig_3(u32); -u32 _CpuConfig_4(u32); -u32 _CpuConfig_5(u32); -u32 (*table_CpuConfig[6])(u32) = {_CpuConfig_0, _CpuConfig_1, _CpuConfig_2, - _CpuConfig_3, _CpuConfig_4, _CpuConfig_5}; - -u32 dmac_CHCR[10] = { - 0xB0008000, - 0xB0009000, - 0xB000A000, - 0xB000B000, - 0xB000B400, - 0xB000C000, - 0xB000C400, - 0xB000C800, - 0xB000D000, - 0xB000D400, -}; - -void (*VCRTable[14])() = { - 0, 0, 0, 0, - 0, 0, 0, 0, - SyscException, 0, 0, 0, - 0, 0 -}; - -void (*VIntTable[8])() = { - 0, 0, DMACException, INTCException, - 0, 0, 0, TIMERException, -}; - -void _DummyINTCHandler(int); -void _DummyDMACHandler(int); - -void (*INTCTable[16])(int) = { - _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, - _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, - _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, - _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler }; - -void (*DMACTable[16])(int) = { - _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, - _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, - _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, - _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler }; - - -void (*table_SYSCALL[0x80])() = { - (void (*))_RFU___, // 0x00 - (void (*))_ResetEE, - (void (*))_SetGsCrt, - (void (*))_RFU___, - (void (*))_Exit, // 0x04 - (void (*))_RFU005, - (void (*))_LoadPS2Exe, - (void (*))_ExecPS2, - (void (*))_RFU___, // 0x08 - (void (*))_TlbWriteRandom, - (void (*))_AddSbusIntcHandler, - (void (*))_RemoveSbusIntcHandler, - (void (*))_Interrupt2Iop, // 0x0C - (void (*))_SetVTLBRefillHandler, - (void (*))_SetVCommonHandler, - (void (*))_SetVInterruptHandler, - (void (*))_AddIntcHandler, // 0x10 - (void (*))_RemoveIntcHandler, - (void (*))_AddDmacHandler, - (void (*))_RemoveDmacHandler, - (void (*))__EnableIntc, // 0x14 - (void (*))__DisableIntc, - (void (*))__EnableDmac, - (void (*))__DisableDmac, - (void (*))_SetAlarm, // 0x18 - (void (*))_ReleaseAlarm, - (void (*))__EnableIntc, - (void (*))__DisableIntc, - (void (*))__EnableDmac, // 0x1C - (void (*))__DisableDmac, - (void (*))_SetAlarm, - (void (*))_ReleaseAlarm, - (void (*))_CreateThread, // 0x20 - (void (*))_DeleteThread, - (void (*))_StartThread, - (void (*))_ExitThread, - (void (*))_ExitDeleteThread, // 0x24 - (void (*))_TerminateThread, - (void (*))_iTerminateThread, - (void (*))_DisableDispatchThread, - (void (*))_EnableDispatchThread, // 0x28 - (void (*))_ChangeThreadPriority, - (void (*))_iChangeThreadPriority, - (void (*))_RotateThreadReadyQueue, - (void (*))_iRotateThreadReadyQueue, // 0x2C - (void (*))_ReleaseWaitThread, - (void (*))_iReleaseWaitThread, - (void (*))_GetThreadId, - (void (*))_ReferThreadStatus, // 0x30 - (void (*))_ReferThreadStatus, - (void (*))_SleepThread, - (void (*))_WakeupThread, - (void (*))_iWakeupThread, - (void (*))_CancelWakeupThread, - (void (*))_CancelWakeupThread, - (void (*))_SuspendThread, - (void (*))_SuspendThread, - (void (*))_ResumeThread, - (void (*))_iResumeThread, - (void (*))_JoinThread, - (void (*))_InitializeMainThread, - (void (*))_InitializeHeapArea, - (void (*))_EndOfHeap, - (void (*))_RFU___, - (void (*))_CreateSema, // 0x40 - (void (*))_DeleteSema, - (void (*))_SignalSema, - (void (*))_iSignalSema, - (void (*))_WaitSema, - (void (*))_PollSema, - (void (*))_PollSema, - (void (*))_ReferSemaStatus, - (void (*))_ReferSemaStatus, - (void (*))_iDeleteSema, - (void (*))_SetOsdConfigParam, - (void (*))_GetOsdConfigParam, - (void (*))_GetGsHParam, - (void (*))_GetGsVParam, - (void (*))_SetGsHParam, - (void (*))_SetGsVParam, - (void (*))_CreateEventFlag, // 0x50 - (void (*))_DeleteEventFlag, - (void (*))_SetEventFlag, - (void (*))_iSetEventFlag, - (void (*))_RFU___, - (void (*))_RFU___, - (void (*))_RFU___, - (void (*))_RFU___, - (void (*))_RFU___, - (void (*))_RFU___, - (void (*))_RFU___, - (void (*))_RFU___, - (void (*))_EnableIntcHandler, - (void (*))_DisableIntcHandler, - (void (*))_EnableDmacHandler, - (void (*))_DisableDmacHandler, - (void (*))_KSeg0, // 0x60 - (void (*))_EnableCache, - (void (*))_DisableCache, - (void (*))_GetCop0, - (void (*))_FlushCache, - (void (*))_105, - (void (*))_CpuConfig, - (void (*))_GetCop0, - (void (*))_FlushCache, - (void (*))_105, - (void (*))_CpuConfig, - (void (*))_SifStopDma, //_sceSifStopDma, - (void (*))_SetCPUTimerHandler, - (void (*))_SetCPUTimer, - (void (*))0,//_SetOsdConfigParam2, - (void (*))0,//_GetOsdConfigParam2, - (void (*))_GsGetIMR, // 0x70 - (void (*))_GsPutIMR, - (void (*))_SetPgifHandler, - (void (*))_SetVSyncFlag, - (void (*))_SetSYSCALL, - (void (*))_print, - (void (*))_SifDmaStat, - (void (*))_SifSetDma, - (void (*))_SifSetDChain, - (void (*))_SifSetReg, - (void (*))_SifGetReg, - (void (*))_ExecOSD, - (void (*))_RFU___, - (void (*))_PSMode, - (void (*))_MachineType, - (void (*))_GetMemorySize -}; +// eedata.c - needed in order to assure +// that some of the kernel variables are as close to 0x80000000 as possible +// (ie, look in saveContext2) +//[made by] [RO]man, zerofrog + +#include +#include +#include + +#include "eekernel.h" +#include "eeirq.h" + +eeRegs SavedRegs __attribute((aligned(256))); +u128 SavedSP __attribute((aligned(16))); +u128 SavedRA __attribute((aligned(16))); +u128 SavedAT __attribute((aligned(16))); +u64 SavedT9 __attribute((aligned(16))); + +u32 _CpuConfig_0(u32); +u32 _CpuConfig_1(u32); +u32 _CpuConfig_2(u32); +u32 _CpuConfig_3(u32); +u32 _CpuConfig_4(u32); +u32 _CpuConfig_5(u32); +u32 (*table_CpuConfig[6])(u32) = {_CpuConfig_0, _CpuConfig_1, _CpuConfig_2, + _CpuConfig_3, _CpuConfig_4, _CpuConfig_5}; + +u32 dmac_CHCR[10] = { + 0xB0008000, + 0xB0009000, + 0xB000A000, + 0xB000B000, + 0xB000B400, + 0xB000C000, + 0xB000C400, + 0xB000C800, + 0xB000D000, + 0xB000D400, +}; + +void (*VCRTable[14])() = { + 0, 0, 0, 0, + 0, 0, 0, 0, + SyscException, 0, 0, 0, + 0, 0 +}; + +void (*VIntTable[8])() = { + 0, 0, DMACException, INTCException, + 0, 0, 0, TIMERException, +}; + +void _DummyINTCHandler(int); +void _DummyDMACHandler(int); + +void (*INTCTable[16])(int) = { + _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, + _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, + _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, + _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler, _DummyINTCHandler }; + +void (*DMACTable[16])(int) = { + _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, + _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, + _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, + _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler, _DummyDMACHandler }; + + +void (*table_SYSCALL[0x80])() = { + (void (*))_RFU___, // 0x00 + (void (*))_ResetEE, + (void (*))_SetGsCrt, + (void (*))_RFU___, + (void (*))_Exit, // 0x04 + (void (*))_RFU005, + (void (*))_LoadPS2Exe, + (void (*))_ExecPS2, + (void (*))_RFU___, // 0x08 + (void (*))_TlbWriteRandom, + (void (*))_AddSbusIntcHandler, + (void (*))_RemoveSbusIntcHandler, + (void (*))_Interrupt2Iop, // 0x0C + (void (*))_SetVTLBRefillHandler, + (void (*))_SetVCommonHandler, + (void (*))_SetVInterruptHandler, + (void (*))_AddIntcHandler, // 0x10 + (void (*))_RemoveIntcHandler, + (void (*))_AddDmacHandler, + (void (*))_RemoveDmacHandler, + (void (*))__EnableIntc, // 0x14 + (void (*))__DisableIntc, + (void (*))__EnableDmac, + (void (*))__DisableDmac, + (void (*))_SetAlarm, // 0x18 + (void (*))_ReleaseAlarm, + (void (*))__EnableIntc, + (void (*))__DisableIntc, + (void (*))__EnableDmac, // 0x1C + (void (*))__DisableDmac, + (void (*))_SetAlarm, + (void (*))_ReleaseAlarm, + (void (*))_CreateThread, // 0x20 + (void (*))_DeleteThread, + (void (*))_StartThread, + (void (*))_ExitThread, + (void (*))_ExitDeleteThread, // 0x24 + (void (*))_TerminateThread, + (void (*))_iTerminateThread, + (void (*))_DisableDispatchThread, + (void (*))_EnableDispatchThread, // 0x28 + (void (*))_ChangeThreadPriority, + (void (*))_iChangeThreadPriority, + (void (*))_RotateThreadReadyQueue, + (void (*))_iRotateThreadReadyQueue, // 0x2C + (void (*))_ReleaseWaitThread, + (void (*))_iReleaseWaitThread, + (void (*))_GetThreadId, + (void (*))_ReferThreadStatus, // 0x30 + (void (*))_ReferThreadStatus, + (void (*))_SleepThread, + (void (*))_WakeupThread, + (void (*))_iWakeupThread, + (void (*))_CancelWakeupThread, + (void (*))_CancelWakeupThread, + (void (*))_SuspendThread, + (void (*))_SuspendThread, + (void (*))_ResumeThread, + (void (*))_iResumeThread, + (void (*))_JoinThread, + (void (*))_InitializeMainThread, + (void (*))_InitializeHeapArea, + (void (*))_EndOfHeap, + (void (*))_RFU___, + (void (*))_CreateSema, // 0x40 + (void (*))_DeleteSema, + (void (*))_SignalSema, + (void (*))_iSignalSema, + (void (*))_WaitSema, + (void (*))_PollSema, + (void (*))_PollSema, + (void (*))_ReferSemaStatus, + (void (*))_ReferSemaStatus, + (void (*))_iDeleteSema, + (void (*))_SetOsdConfigParam, + (void (*))_GetOsdConfigParam, + (void (*))_GetGsHParam, + (void (*))_GetGsVParam, + (void (*))_SetGsHParam, + (void (*))_SetGsVParam, + (void (*))_CreateEventFlag, // 0x50 + (void (*))_DeleteEventFlag, + (void (*))_SetEventFlag, + (void (*))_iSetEventFlag, + (void (*))_RFU___, + (void (*))_RFU___, + (void (*))_RFU___, + (void (*))_RFU___, + (void (*))_RFU___, + (void (*))_RFU___, + (void (*))_RFU___, + (void (*))_RFU___, + (void (*))_EnableIntcHandler, + (void (*))_DisableIntcHandler, + (void (*))_EnableDmacHandler, + (void (*))_DisableDmacHandler, + (void (*))_KSeg0, // 0x60 + (void (*))_EnableCache, + (void (*))_DisableCache, + (void (*))_GetCop0, + (void (*))_FlushCache, + (void (*))_105, + (void (*))_CpuConfig, + (void (*))_GetCop0, + (void (*))_FlushCache, + (void (*))_105, + (void (*))_CpuConfig, + (void (*))_SifStopDma, //_sceSifStopDma, + (void (*))_SetCPUTimerHandler, + (void (*))_SetCPUTimer, + (void (*))0,//_SetOsdConfigParam2, + (void (*))0,//_GetOsdConfigParam2, + (void (*))_GsGetIMR, // 0x70 + (void (*))_GsPutIMR, + (void (*))_SetPgifHandler, + (void (*))_SetVSyncFlag, + (void (*))_SetSYSCALL, + (void (*))_print, + (void (*))_SifDmaStat, + (void (*))_SifSetDma, + (void (*))_SifSetDChain, + (void (*))_SifSetReg, + (void (*))_SifGetReg, + (void (*))_ExecOSD, + (void (*))_RFU___, + (void (*))_PSMode, + (void (*))_MachineType, + (void (*))_GetMemorySize +}; diff --git a/fps2bios/kernel/eeload/eedebug.c b/fps2bios/kernel/eeload/eedebug.c index 24bc361406..8be3c068b8 100644 --- a/fps2bios/kernel/eeload/eedebug.c +++ b/fps2bios/kernel/eeload/eedebug.c @@ -1,31 +1,31 @@ - -#include -#include -#include - - -void __putc(u8 c) { - while (*((u32*)0x1000f130) & 0x8000) { __asm__ ("nop\nnop\nnop\n"); } - - *((u8*)0x1000f180) = c; -} - -void __puts(u8 *s) { - while (*s != 0) { - __putc(*s++); - } -} - -int __printf(const char *format, ...) { - char buf[4096]; - va_list args; - int ret; - - va_start(args, format); - ret = vsnprintf(buf, 4096, format, args); - va_end(args); - - __puts(buf); - return ret; -} - + +#include +#include +#include + + +void __putc(u8 c) { + while (*((u32*)0x1000f130) & 0x8000) { __asm__ ("nop\nnop\nnop\n"); } + + *((u8*)0x1000f180) = c; +} + +void __puts(u8 *s) { + while (*s != 0) { + __putc(*s++); + } +} + +int __printf(const char *format, ...) { + char buf[4096]; + va_list args; + int ret; + + va_start(args, format); + ret = vsnprintf(buf, 4096, format, args); + va_end(args); + + __puts(buf); + return ret; +} + diff --git a/fps2bios/kernel/eeload/eeelf.c b/fps2bios/kernel/eeload/eeelf.c index 52dce53963..221126caa7 100644 --- a/fps2bios/kernel/eeload/eeelf.c +++ b/fps2bios/kernel/eeload/eeelf.c @@ -1,423 +1,423 @@ -#include "romdir.h" -#include "eedebug.h" - -typedef struct { - u8 e_ident[16]; //0x7f,"ELF" (ELF file identifier) - u16 e_type; //ELF type: 0=NONE, 1=REL, 2=EXEC, 3=SHARED, 4=CORE - u16 e_machine; //Processor: 8=MIPS R3000 - u32 e_version; //Version: 1=current - u32 e_entry; //Entry point address - u32 e_phoff; //Start of program headers (offset from file start) - u32 e_shoff; //Start of section headers (offset from file start) - u32 e_flags; //Processor specific flags = 0x20924001 noreorder, mips - u16 e_ehsize; //ELF header size (0x34 = 52 bytes) - u16 e_phentsize; //Program headers entry size - u16 e_phnum; //Number of program headers - u16 e_shentsize; //Section headers entry size - u16 e_shnum; //Number of section headers - u16 e_shstrndx; //Section header stringtable index -} ELF_HEADER; - -typedef struct { - u32 p_type; //see notes1 - u32 p_offset; //Offset from file start to program segment. - u32 p_vaddr; //Virtual address of the segment - u32 p_paddr; //Physical address of the segment - u32 p_filesz; //Number of bytes in the file image of the segment - u32 p_memsz; //Number of bytes in the memory image of the segment - u32 p_flags; //Flags for segment - u32 p_align; //Alignment. The address of 0x08 and 0x0C must fit this alignment. 0=no alignment -} ELF_PHR; - -/* -notes1 ------- -0=Inactive -1=Load the segment into memory, no. of bytes specified by 0x10 and 0x14 -2=Dynamic linking -3=Interpreter. The array element must specify a path name -4=Note. The array element must specify the location and size of aux. info -5=reserved -6=The array element must specify location and size of the program header table. -*/ - -typedef struct { - u32 sh_name; //No. to the index of the Section header stringtable index - u32 sh_type; //See notes2 - u32 sh_flags; //see notes3 - u32 sh_addr; //Section start address - u32 sh_offset; //Offset from start of file to section - u32 sh_size; //Size of section - u32 sh_link; //Section header table index link - u32 sh_info; //Info - u32 sh_addralign; //Alignment. The adress of 0x0C must fit this alignment. 0=no alignment. - u32 sh_entsize; //Fixed size entries. -} ELF_SHR; -/* -notes 2 -------- -Type: -0=Inactive -1=PROGBITS -2=SYMTAB symbol table -3=STRTAB string table -4=RELA relocation entries -5=HASH hash table -6=DYNAMIC dynamic linking information -7=NOTE -8=NOBITS -9=REL relocation entries -10=SHLIB -0x70000000=LOPROC processor specifc -0x7fffffff=HIPROC -0x80000000=LOUSER lower bound -0xffffffff=HIUSER upper bound - -notes 3 -------- -Section Flags: (1 bit, you may combine them like 3 = alloc & write permission) -1=Write section contains data the is be writeable during execution. -2=Alloc section occupies memory during execution -4=Exec section contains executable instructions -0xf0000000=Mask bits processor-specific -*/ - -typedef struct { - u32 st_name; - u32 st_value; - u32 st_size; - u8 st_info; - u8 st_other; - u16 st_shndx; -} Elf32_Sym; - -#define ELF32_ST_TYPE(i) ((i)&0xf) - -typedef struct { - u32 r_offset; - u32 r_info; -} Elf32_Rel; - -char *sections_names; - -ELF_HEADER *elfHeader; -ELF_PHR *elfProgH; -ELF_SHR *elfSectH; -u8 *elfdata; -int elfsize; - - -static void __memcpy(void *dest, const void *src, int n) { - const u8 *s = (u8*)src; - u8 *d = (u8*)dest; - - while (n) { - *d++ = *s++; n--; - } -} - - -int loadHeaders() { - elfHeader = (ELF_HEADER*)elfdata; - - if ((elfHeader->e_shentsize != sizeof(ELF_SHR)) && (elfHeader->e_shnum > 0)) { - return -1; - } - -#ifdef ELF_LOG - ELF_LOG( "type: " ); -#endif - switch( elfHeader->e_type ) - { - default: -#ifdef ELF_LOG - ELF_LOG( "unknown %x", elfHeader->e_type ); -#endif - break; - - case 0x0: -#ifdef ELF_LOG - ELF_LOG( "no file type" ); -#endif - break; - - case 0x1: -#ifdef ELF_LOG - ELF_LOG( "relocatable" ); -#endif - break; - - case 0x2: -#ifdef ELF_LOG - ELF_LOG( "executable" ); -#endif - break; - } -#ifdef ELF_LOG - ELF_LOG( "\n" ); - ELF_LOG( "machine: " ); -#endif - switch ( elfHeader->e_machine ) - { - default: -#ifdef ELF_LOG - ELF_LOG( "unknown" ); -#endif - break; - - case 0x8: -#ifdef ELF_LOG - ELF_LOG( "mips_rs3000" ); -#endif - break; - } -#ifdef ELF_LOG - ELF_LOG("\n"); - ELF_LOG("version: %d\n",elfHeader->e_version); - ELF_LOG("entry: %08x\n",elfHeader->e_entry); - ELF_LOG("flags: %08x\n",elfHeader->e_flags); - ELF_LOG("eh size: %08x\n",elfHeader->e_ehsize); - ELF_LOG("ph off: %08x\n",elfHeader->e_phoff); - ELF_LOG("ph entsiz: %08x\n",elfHeader->e_phentsize); - ELF_LOG("ph num: %08x\n",elfHeader->e_phnum); - ELF_LOG("sh off: %08x\n",elfHeader->e_shoff); - ELF_LOG("sh entsiz: %08x\n",elfHeader->e_shentsize); - ELF_LOG("sh num: %08x\n",elfHeader->e_shnum); - ELF_LOG("sh strndx: %08x\n",elfHeader->e_shstrndx); - - ELF_LOG("\n"); -#endif - - return 0; -} - - -int loadProgramHeaders() { - int i; - - if (elfHeader->e_phnum == 0) { - return 0; - } - - if (elfHeader->e_phentsize != sizeof(ELF_PHR)) { - return -1; - } - - elfProgH = (ELF_PHR*)&elfdata[elfHeader->e_phoff]; - - for ( i = 0 ; i < elfHeader->e_phnum ; i++ ) - { -#ifdef ELF_LOG - ELF_LOG( "Elf32 Program Header\n" ); - ELF_LOG( "type: " ); -#endif - switch ( elfProgH[ i ].p_type ) - { - default: -#ifdef ELF_LOG - ELF_LOG( "unknown %x", (int)elfProgH[ i ].p_type ); -#endif - break; - - case 0x1: -#ifdef ELF_LOG - ELF_LOG("load"); -#endif -/* if ( elfHeader->e_shnum == 0 ) {*/ - if (elfProgH[ i ].p_offset < elfsize) { - int size; - - if ((elfProgH[ i ].p_filesz + elfProgH[ i ].p_offset) > elfsize) { - size = elfsize - elfProgH[ i ].p_offset; - } else { - size = elfProgH[ i ].p_filesz; - } -// __printf("loading program to %x\n", elfProgH[ i ].p_paddr + elfbase); - __memcpy(elfProgH[ i ].p_paddr, - &elfdata[elfProgH[ i ].p_offset], - size); - } -#ifdef ELF_LOG - ELF_LOG("\t*LOADED*"); -#endif -// } - break; - } -#ifdef ELF_LOG - ELF_LOG("\n"); - ELF_LOG("offset: %08x\n",(int)elfProgH[i].p_offset); - ELF_LOG("vaddr: %08x\n",(int)elfProgH[i].p_vaddr); - ELF_LOG("paddr: %08x\n",elfProgH[i].p_paddr); - ELF_LOG("file size: %08x\n",elfProgH[i].p_filesz); - ELF_LOG("mem size: %08x\n",elfProgH[i].p_memsz); - ELF_LOG("flags: %08x\n",elfProgH[i].p_flags); - ELF_LOG("palign: %08x\n",elfProgH[i].p_align); - ELF_LOG("\n"); -#endif - } - - return 0; -} - -int loadSectionHeaders() { - int i; - int i_st = -1; - int i_dt = -1; - - if (elfHeader->e_shnum == 0) { - return -1; - } - - elfSectH = (ELF_SHR*)&elfdata[elfHeader->e_shoff]; - - if ( elfHeader->e_shstrndx < elfHeader->e_shnum ) { - sections_names = (char *)&elfdata[elfSectH[ elfHeader->e_shstrndx ].sh_offset]; - } - - for ( i = 0 ; i < elfHeader->e_shnum ; i++ ) - { -#ifdef ELF_LOG - ELF_LOG( "Elf32 Section Header [%x] %s", i, §ions_names[ elfSectH[ i ].sh_name ] ); -#endif -/* if ( elfSectH[i].sh_flags & 0x2 ) { - if (elfSectH[i].sh_offset < elfsize) { - int size; - - if ((elfSectH[i].sh_size + elfSectH[i].sh_offset) > elfsize) { - size = elfsize - elfSectH[i].sh_offset; - } else { - size = elfSectH[i].sh_size; - } - memcpy(&psM[ elfSectH[ i ].sh_addr &0x1ffffff ], - &elfdata[elfSectH[i].sh_offset], - size); - } -#ifdef ELF_LOG - ELF_LOG( "\t*LOADED*" ); -#endif - }*/ -#ifdef ELF_LOG - ELF_LOG("\n"); - ELF_LOG("type: "); -#endif - switch ( elfSectH[ i ].sh_type ) - { - default: -#ifdef ELF_LOG - ELF_LOG("unknown %08x",elfSectH[i].sh_type); -#endif - break; - - case 0x0: -#ifdef ELF_LOG - ELF_LOG("null"); -#endif - break; - - case 0x1: -#ifdef ELF_LOG - ELF_LOG("progbits"); -#endif - break; - - case 0x2: -#ifdef ELF_LOG - ELF_LOG("symtab"); -#endif - break; - - case 0x3: -#ifdef ELF_LOG - ELF_LOG("strtab"); -#endif - break; - - case 0x4: -#ifdef ELF_LOG - ELF_LOG("rela"); -#endif - break; - - case 0x8: -#ifdef ELF_LOG - ELF_LOG("no bits"); -#endif - break; - - case 0x9: -#ifdef ELF_LOG - ELF_LOG("rel"); -#endif - break; - } -#ifdef ELF_LOG - ELF_LOG("\n"); - ELF_LOG("flags: %08x\n", elfSectH[i].sh_flags); - ELF_LOG("addr: %08x\n", elfSectH[i].sh_addr); - ELF_LOG("offset: %08x\n", elfSectH[i].sh_offset); - ELF_LOG("size: %08x\n", elfSectH[i].sh_size); - ELF_LOG("link: %08x\n", elfSectH[i].sh_link); - ELF_LOG("info: %08x\n", elfSectH[i].sh_info); - ELF_LOG("addralign: %08x\n", elfSectH[i].sh_addralign); - ELF_LOG("entsize: %08x\n", elfSectH[i].sh_entsize); -#endif - // dump symbol table - - if (elfSectH[i].sh_type == 0x02) { - i_st = i; i_dt = elfSectH[i].sh_link; - } -/* - if (elfSectH[i].sh_type == 0x01) { - int size = elfSectH[i].sh_size / 4; - u32 *ptr = (u32*)&psxM[(elfSectH[i].sh_addr + irx_addr) & 0x1fffff]; - - while (size) { - - if (*ptr == 0x41e00000) { // import func - int ret = iopSetImportFunc(ptr+1); - size-= ret; ptr+= ret; - } - - if (*ptr == 0x41c00000) { // export func - int ret = iopSetExportFunc(ptr+1); - size-= ret; ptr+= ret; - } - - size--; ptr++; - } - } -*/ -/* if (!strcmp(".data", §ions_names[elfSectH[i].sh_name])) { - // seems so.. - - psxRegs.GPR.n.gp = 0x8000 + irx_addr + elfSectH[i].sh_addr; - }*/ - } - - return 0; -} - - -u32 loadElfFile(char *filename, struct elfinfo *info) { - struct rominfo ri; - char str[256]; - char str2[256]; - int i; - - __printf("loadElfFile: %s\n", filename); - - if (romdirGetFile(filename, &ri) == NULL) { - __printf("file %s not found!!\n", filename); - return -1; - } - elfdata = (u8*)(0xbfc00000 + ri.fileOffset); - elfsize = ri.fileSize; - - loadHeaders(); - loadProgramHeaders(); - loadSectionHeaders(); - -// __printf("loadElfFile: e_entry=%x\n", elfHeader->e_entry); - return elfHeader->e_entry; -} - +#include "romdir.h" +#include "eedebug.h" + +typedef struct { + u8 e_ident[16]; //0x7f,"ELF" (ELF file identifier) + u16 e_type; //ELF type: 0=NONE, 1=REL, 2=EXEC, 3=SHARED, 4=CORE + u16 e_machine; //Processor: 8=MIPS R3000 + u32 e_version; //Version: 1=current + u32 e_entry; //Entry point address + u32 e_phoff; //Start of program headers (offset from file start) + u32 e_shoff; //Start of section headers (offset from file start) + u32 e_flags; //Processor specific flags = 0x20924001 noreorder, mips + u16 e_ehsize; //ELF header size (0x34 = 52 bytes) + u16 e_phentsize; //Program headers entry size + u16 e_phnum; //Number of program headers + u16 e_shentsize; //Section headers entry size + u16 e_shnum; //Number of section headers + u16 e_shstrndx; //Section header stringtable index +} ELF_HEADER; + +typedef struct { + u32 p_type; //see notes1 + u32 p_offset; //Offset from file start to program segment. + u32 p_vaddr; //Virtual address of the segment + u32 p_paddr; //Physical address of the segment + u32 p_filesz; //Number of bytes in the file image of the segment + u32 p_memsz; //Number of bytes in the memory image of the segment + u32 p_flags; //Flags for segment + u32 p_align; //Alignment. The address of 0x08 and 0x0C must fit this alignment. 0=no alignment +} ELF_PHR; + +/* +notes1 +------ +0=Inactive +1=Load the segment into memory, no. of bytes specified by 0x10 and 0x14 +2=Dynamic linking +3=Interpreter. The array element must specify a path name +4=Note. The array element must specify the location and size of aux. info +5=reserved +6=The array element must specify location and size of the program header table. +*/ + +typedef struct { + u32 sh_name; //No. to the index of the Section header stringtable index + u32 sh_type; //See notes2 + u32 sh_flags; //see notes3 + u32 sh_addr; //Section start address + u32 sh_offset; //Offset from start of file to section + u32 sh_size; //Size of section + u32 sh_link; //Section header table index link + u32 sh_info; //Info + u32 sh_addralign; //Alignment. The adress of 0x0C must fit this alignment. 0=no alignment. + u32 sh_entsize; //Fixed size entries. +} ELF_SHR; +/* +notes 2 +------- +Type: +0=Inactive +1=PROGBITS +2=SYMTAB symbol table +3=STRTAB string table +4=RELA relocation entries +5=HASH hash table +6=DYNAMIC dynamic linking information +7=NOTE +8=NOBITS +9=REL relocation entries +10=SHLIB +0x70000000=LOPROC processor specifc +0x7fffffff=HIPROC +0x80000000=LOUSER lower bound +0xffffffff=HIUSER upper bound + +notes 3 +------- +Section Flags: (1 bit, you may combine them like 3 = alloc & write permission) +1=Write section contains data the is be writeable during execution. +2=Alloc section occupies memory during execution +4=Exec section contains executable instructions +0xf0000000=Mask bits processor-specific +*/ + +typedef struct { + u32 st_name; + u32 st_value; + u32 st_size; + u8 st_info; + u8 st_other; + u16 st_shndx; +} Elf32_Sym; + +#define ELF32_ST_TYPE(i) ((i)&0xf) + +typedef struct { + u32 r_offset; + u32 r_info; +} Elf32_Rel; + +char *sections_names; + +ELF_HEADER *elfHeader; +ELF_PHR *elfProgH; +ELF_SHR *elfSectH; +u8 *elfdata; +int elfsize; + + +static void __memcpy(void *dest, const void *src, int n) { + const u8 *s = (u8*)src; + u8 *d = (u8*)dest; + + while (n) { + *d++ = *s++; n--; + } +} + + +int loadHeaders() { + elfHeader = (ELF_HEADER*)elfdata; + + if ((elfHeader->e_shentsize != sizeof(ELF_SHR)) && (elfHeader->e_shnum > 0)) { + return -1; + } + +#ifdef ELF_LOG + ELF_LOG( "type: " ); +#endif + switch( elfHeader->e_type ) + { + default: +#ifdef ELF_LOG + ELF_LOG( "unknown %x", elfHeader->e_type ); +#endif + break; + + case 0x0: +#ifdef ELF_LOG + ELF_LOG( "no file type" ); +#endif + break; + + case 0x1: +#ifdef ELF_LOG + ELF_LOG( "relocatable" ); +#endif + break; + + case 0x2: +#ifdef ELF_LOG + ELF_LOG( "executable" ); +#endif + break; + } +#ifdef ELF_LOG + ELF_LOG( "\n" ); + ELF_LOG( "machine: " ); +#endif + switch ( elfHeader->e_machine ) + { + default: +#ifdef ELF_LOG + ELF_LOG( "unknown" ); +#endif + break; + + case 0x8: +#ifdef ELF_LOG + ELF_LOG( "mips_rs3000" ); +#endif + break; + } +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("version: %d\n",elfHeader->e_version); + ELF_LOG("entry: %08x\n",elfHeader->e_entry); + ELF_LOG("flags: %08x\n",elfHeader->e_flags); + ELF_LOG("eh size: %08x\n",elfHeader->e_ehsize); + ELF_LOG("ph off: %08x\n",elfHeader->e_phoff); + ELF_LOG("ph entsiz: %08x\n",elfHeader->e_phentsize); + ELF_LOG("ph num: %08x\n",elfHeader->e_phnum); + ELF_LOG("sh off: %08x\n",elfHeader->e_shoff); + ELF_LOG("sh entsiz: %08x\n",elfHeader->e_shentsize); + ELF_LOG("sh num: %08x\n",elfHeader->e_shnum); + ELF_LOG("sh strndx: %08x\n",elfHeader->e_shstrndx); + + ELF_LOG("\n"); +#endif + + return 0; +} + + +int loadProgramHeaders() { + int i; + + if (elfHeader->e_phnum == 0) { + return 0; + } + + if (elfHeader->e_phentsize != sizeof(ELF_PHR)) { + return -1; + } + + elfProgH = (ELF_PHR*)&elfdata[elfHeader->e_phoff]; + + for ( i = 0 ; i < elfHeader->e_phnum ; i++ ) + { +#ifdef ELF_LOG + ELF_LOG( "Elf32 Program Header\n" ); + ELF_LOG( "type: " ); +#endif + switch ( elfProgH[ i ].p_type ) + { + default: +#ifdef ELF_LOG + ELF_LOG( "unknown %x", (int)elfProgH[ i ].p_type ); +#endif + break; + + case 0x1: +#ifdef ELF_LOG + ELF_LOG("load"); +#endif +/* if ( elfHeader->e_shnum == 0 ) {*/ + if (elfProgH[ i ].p_offset < elfsize) { + int size; + + if ((elfProgH[ i ].p_filesz + elfProgH[ i ].p_offset) > elfsize) { + size = elfsize - elfProgH[ i ].p_offset; + } else { + size = elfProgH[ i ].p_filesz; + } +// __printf("loading program to %x\n", elfProgH[ i ].p_paddr + elfbase); + __memcpy(elfProgH[ i ].p_paddr, + &elfdata[elfProgH[ i ].p_offset], + size); + } +#ifdef ELF_LOG + ELF_LOG("\t*LOADED*"); +#endif +// } + break; + } +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("offset: %08x\n",(int)elfProgH[i].p_offset); + ELF_LOG("vaddr: %08x\n",(int)elfProgH[i].p_vaddr); + ELF_LOG("paddr: %08x\n",elfProgH[i].p_paddr); + ELF_LOG("file size: %08x\n",elfProgH[i].p_filesz); + ELF_LOG("mem size: %08x\n",elfProgH[i].p_memsz); + ELF_LOG("flags: %08x\n",elfProgH[i].p_flags); + ELF_LOG("palign: %08x\n",elfProgH[i].p_align); + ELF_LOG("\n"); +#endif + } + + return 0; +} + +int loadSectionHeaders() { + int i; + int i_st = -1; + int i_dt = -1; + + if (elfHeader->e_shnum == 0) { + return -1; + } + + elfSectH = (ELF_SHR*)&elfdata[elfHeader->e_shoff]; + + if ( elfHeader->e_shstrndx < elfHeader->e_shnum ) { + sections_names = (char *)&elfdata[elfSectH[ elfHeader->e_shstrndx ].sh_offset]; + } + + for ( i = 0 ; i < elfHeader->e_shnum ; i++ ) + { +#ifdef ELF_LOG + ELF_LOG( "Elf32 Section Header [%x] %s", i, §ions_names[ elfSectH[ i ].sh_name ] ); +#endif +/* if ( elfSectH[i].sh_flags & 0x2 ) { + if (elfSectH[i].sh_offset < elfsize) { + int size; + + if ((elfSectH[i].sh_size + elfSectH[i].sh_offset) > elfsize) { + size = elfsize - elfSectH[i].sh_offset; + } else { + size = elfSectH[i].sh_size; + } + memcpy(&psM[ elfSectH[ i ].sh_addr &0x1ffffff ], + &elfdata[elfSectH[i].sh_offset], + size); + } +#ifdef ELF_LOG + ELF_LOG( "\t*LOADED*" ); +#endif + }*/ +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("type: "); +#endif + switch ( elfSectH[ i ].sh_type ) + { + default: +#ifdef ELF_LOG + ELF_LOG("unknown %08x",elfSectH[i].sh_type); +#endif + break; + + case 0x0: +#ifdef ELF_LOG + ELF_LOG("null"); +#endif + break; + + case 0x1: +#ifdef ELF_LOG + ELF_LOG("progbits"); +#endif + break; + + case 0x2: +#ifdef ELF_LOG + ELF_LOG("symtab"); +#endif + break; + + case 0x3: +#ifdef ELF_LOG + ELF_LOG("strtab"); +#endif + break; + + case 0x4: +#ifdef ELF_LOG + ELF_LOG("rela"); +#endif + break; + + case 0x8: +#ifdef ELF_LOG + ELF_LOG("no bits"); +#endif + break; + + case 0x9: +#ifdef ELF_LOG + ELF_LOG("rel"); +#endif + break; + } +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("flags: %08x\n", elfSectH[i].sh_flags); + ELF_LOG("addr: %08x\n", elfSectH[i].sh_addr); + ELF_LOG("offset: %08x\n", elfSectH[i].sh_offset); + ELF_LOG("size: %08x\n", elfSectH[i].sh_size); + ELF_LOG("link: %08x\n", elfSectH[i].sh_link); + ELF_LOG("info: %08x\n", elfSectH[i].sh_info); + ELF_LOG("addralign: %08x\n", elfSectH[i].sh_addralign); + ELF_LOG("entsize: %08x\n", elfSectH[i].sh_entsize); +#endif + // dump symbol table + + if (elfSectH[i].sh_type == 0x02) { + i_st = i; i_dt = elfSectH[i].sh_link; + } +/* + if (elfSectH[i].sh_type == 0x01) { + int size = elfSectH[i].sh_size / 4; + u32 *ptr = (u32*)&psxM[(elfSectH[i].sh_addr + irx_addr) & 0x1fffff]; + + while (size) { + + if (*ptr == 0x41e00000) { // import func + int ret = iopSetImportFunc(ptr+1); + size-= ret; ptr+= ret; + } + + if (*ptr == 0x41c00000) { // export func + int ret = iopSetExportFunc(ptr+1); + size-= ret; ptr+= ret; + } + + size--; ptr++; + } + } +*/ +/* if (!strcmp(".data", §ions_names[elfSectH[i].sh_name])) { + // seems so.. + + psxRegs.GPR.n.gp = 0x8000 + irx_addr + elfSectH[i].sh_addr; + }*/ + } + + return 0; +} + + +u32 loadElfFile(char *filename, struct elfinfo *info) { + struct rominfo ri; + char str[256]; + char str2[256]; + int i; + + __printf("loadElfFile: %s\n", filename); + + if (romdirGetFile(filename, &ri) == NULL) { + __printf("file %s not found!!\n", filename); + return -1; + } + elfdata = (u8*)(0xbfc00000 + ri.fileOffset); + elfsize = ri.fileSize; + + loadHeaders(); + loadProgramHeaders(); + loadSectionHeaders(); + +// __printf("loadElfFile: e_entry=%x\n", elfHeader->e_entry); + return elfHeader->e_entry; +} + diff --git a/fps2bios/kernel/eeload/eeinit.c b/fps2bios/kernel/eeload/eeinit.c index c26a421edf..01ef01a34e 100644 --- a/fps2bios/kernel/eeload/eeinit.c +++ b/fps2bios/kernel/eeload/eeinit.c @@ -1,511 +1,511 @@ -// EE initialization functions -// [made by] [RO]man, zerofrog -#include -#include - -#include "eekernel.h" -#include "eeirq.h" - -void InitializeGS(); -void InitializeGIF(); -void InitializeDMAC(int code); -void InitializeVU1(); -void InitializeVIF1(); -void InitializeIPU(); -void InitializeVIF0(); -void InitializeVU0(); -void InitializeFPU(); -void InitializeScratchPad(); -void InitializeUserMemory(u32 base); -void InitializeINTC(int a); -void InitializeTIMER(); - -//////////////////////////////////////////////////////////////////// -//8000AA60 -//////////////////////////////////////////////////////////////////// -void InitializeGS() -{ -} - -//////////////////////////////////////////////////////////////////// -//8000AB98 -//////////////////////////////////////////////////////////////////// -void InitializeGIF() -{ - GIF_CTRL = 1; - __asm__ ("sync\n"); - GIF_FIFO = 0; -} - -//////////////////////////////////////////////////////////////////// -//8000AD68 SYSCALL 001 ResetEE -//////////////////////////////////////////////////////////////////// -int _ResetEE(int init) -{ - if (init & 0x01) { __printf("# Initialize DMAC ...\n"); InitializeDMAC(0x31F); } - if (init & 0x02) { __printf("# Initialize VU1 ...\n"); InitializeVU1(); } - if (init & 0x04) { __printf("# Initialize VIF1 ...\n"); InitializeVIF1(); } - if (init & 0x08) { __printf("# Initialize GIF ...\n"); InitializeGIF(); } - if (init & 0x10) { __printf("# Initialize VU0 ...\n"); InitializeVU0(); } - if (init & 0x04) { __printf("# Initialize VIF0 ...\n"); InitializeVIF0(); } - if (init & 0x40) { __printf("# Initialize IPU ...\n"); InitializeIPU(); } - - InitializeINTC(0xC); -// return (*(int*)0x1000F410 &= 0xFFFBFFFF); code never reached :) -} - -//////////////////////////////////////////////////////////////////// -//8000AE88 -//////////////////////////////////////////////////////////////////// -int Initialize() -{ - __printf("# Initialize Start.\n"); - __printf("# Initialize GS ..."); - - InitializeGS(); - _SetGsCrt(1, 2, 1); - __printf("\n"); - - __printf("# Initialize INTC ...\n"); - InitializeINTC(0xFFFF); - - __printf("# Initialize TIMER ...\n"); - InitializeTIMER(); - - ResetEE(0x7F); - - __printf("# Initialize FPU ...\n"); - InitializeFPU(); - - __printf("# Initialize User Memory ...\n"); - InitializeUserMemory(0x80000); - - __printf("# Initialize Scratch Pad ...\n"); - InitializeScratchPad(); - - __printf("# Initialize Done.\n"); -} - -//////////////////////////////////////////////////////////////////// -//8000AF50 -//////////////////////////////////////////////////////////////////// -int Restart() -{ - __printf("# Restart.\n"); - __printf("# Initialize GS ..."); - - INTC_STAT = 4; - while (INTC_STAT & 4) { __asm__ ("nop\nnop\nnop\n"); } - INTC_STAT = 4; - - InitializeGS(); - _SetGsCrt(1, 2, 1); - __printf("\n"); - - __printf("# Initialize INTC ...\n"); - InitializeINTC(0xDFFD); - - __printf("# Initialize TIMER ...\n"); - InitializeTIMER(); - - ResetEE(0x7F); - - __printf("# Initialize FPU ...\n"); - InitializeFPU(); - - __printf("# Initialize User Memory ...\n"); - InitializeUserMemory(0x82000); - - __printf("# Initialize Scratch Pad ...\n"); - InitializeScratchPad(); - - __printf("# Restart Done.\n"); - - //wait for syncing IOP - while (SBUS_SMFLG & SBFLG_IOPSYNC) { __asm__ ("nop\nnop\nnop\n"); } - - SBUS_SMFLG=SBFLG_IOPSYNC; -} - -//////////////////////////////////////////////////////////////////// -//8000B0A0 -//////////////////////////////////////////////////////////////////// -void InitializeDMAC(int code) -{ - int i; - int *addr; - - for (i=0; i<10; i++) { - if (!(code & (1< 48) { - __printf("# TLB over flow (1)\n"); - } - - ptr = (u32*)(tlb_config[4] + 0x10); - for (i=1; i 48) { - __printf("# TLB over flow (2)\n"); - } - - if (tlb_config[1]) { - ptr = (u32*)(tlb_config[5]); - for (; i 48) { - __printf("# TLB over flow (3)\n"); - } - - ptr = (u32*)(tlb_config[6]); - for (; i +#include + +#include "eekernel.h" +#include "eeirq.h" + +void InitializeGS(); +void InitializeGIF(); +void InitializeDMAC(int code); +void InitializeVU1(); +void InitializeVIF1(); +void InitializeIPU(); +void InitializeVIF0(); +void InitializeVU0(); +void InitializeFPU(); +void InitializeScratchPad(); +void InitializeUserMemory(u32 base); +void InitializeINTC(int a); +void InitializeTIMER(); + +//////////////////////////////////////////////////////////////////// +//8000AA60 +//////////////////////////////////////////////////////////////////// +void InitializeGS() +{ +} + +//////////////////////////////////////////////////////////////////// +//8000AB98 +//////////////////////////////////////////////////////////////////// +void InitializeGIF() +{ + GIF_CTRL = 1; + __asm__ ("sync\n"); + GIF_FIFO = 0; +} + +//////////////////////////////////////////////////////////////////// +//8000AD68 SYSCALL 001 ResetEE +//////////////////////////////////////////////////////////////////// +int _ResetEE(int init) +{ + if (init & 0x01) { __printf("# Initialize DMAC ...\n"); InitializeDMAC(0x31F); } + if (init & 0x02) { __printf("# Initialize VU1 ...\n"); InitializeVU1(); } + if (init & 0x04) { __printf("# Initialize VIF1 ...\n"); InitializeVIF1(); } + if (init & 0x08) { __printf("# Initialize GIF ...\n"); InitializeGIF(); } + if (init & 0x10) { __printf("# Initialize VU0 ...\n"); InitializeVU0(); } + if (init & 0x04) { __printf("# Initialize VIF0 ...\n"); InitializeVIF0(); } + if (init & 0x40) { __printf("# Initialize IPU ...\n"); InitializeIPU(); } + + InitializeINTC(0xC); +// return (*(int*)0x1000F410 &= 0xFFFBFFFF); code never reached :) +} + +//////////////////////////////////////////////////////////////////// +//8000AE88 +//////////////////////////////////////////////////////////////////// +int Initialize() +{ + __printf("# Initialize Start.\n"); + __printf("# Initialize GS ..."); + + InitializeGS(); + _SetGsCrt(1, 2, 1); + __printf("\n"); + + __printf("# Initialize INTC ...\n"); + InitializeINTC(0xFFFF); + + __printf("# Initialize TIMER ...\n"); + InitializeTIMER(); + + ResetEE(0x7F); + + __printf("# Initialize FPU ...\n"); + InitializeFPU(); + + __printf("# Initialize User Memory ...\n"); + InitializeUserMemory(0x80000); + + __printf("# Initialize Scratch Pad ...\n"); + InitializeScratchPad(); + + __printf("# Initialize Done.\n"); +} + +//////////////////////////////////////////////////////////////////// +//8000AF50 +//////////////////////////////////////////////////////////////////// +int Restart() +{ + __printf("# Restart.\n"); + __printf("# Initialize GS ..."); + + INTC_STAT = 4; + while (INTC_STAT & 4) { __asm__ ("nop\nnop\nnop\n"); } + INTC_STAT = 4; + + InitializeGS(); + _SetGsCrt(1, 2, 1); + __printf("\n"); + + __printf("# Initialize INTC ...\n"); + InitializeINTC(0xDFFD); + + __printf("# Initialize TIMER ...\n"); + InitializeTIMER(); + + ResetEE(0x7F); + + __printf("# Initialize FPU ...\n"); + InitializeFPU(); + + __printf("# Initialize User Memory ...\n"); + InitializeUserMemory(0x82000); + + __printf("# Initialize Scratch Pad ...\n"); + InitializeScratchPad(); + + __printf("# Restart Done.\n"); + + //wait for syncing IOP + while (SBUS_SMFLG & SBFLG_IOPSYNC) { __asm__ ("nop\nnop\nnop\n"); } + + SBUS_SMFLG=SBFLG_IOPSYNC; +} + +//////////////////////////////////////////////////////////////////// +//8000B0A0 +//////////////////////////////////////////////////////////////////// +void InitializeDMAC(int code) +{ + int i; + int *addr; + + for (i=0; i<10; i++) { + if (!(code & (1< 48) { + __printf("# TLB over flow (1)\n"); + } + + ptr = (u32*)(tlb_config[4] + 0x10); + for (i=1; i 48) { + __printf("# TLB over flow (2)\n"); + } + + if (tlb_config[1]) { + ptr = (u32*)(tlb_config[5]); + for (; i 48) { + __printf("# TLB over flow (3)\n"); + } + + ptr = (u32*)(tlb_config[6]); + for (; i> 16) | 0x8000; - code&= DMAC_STAT & 0xFFFF; - if (code & 0x80) { - //__printf("%s: code & 0x80\n", __FUNCTION__); - __asm__( - ".set noat\n" - "lui $26, %hi(SavedAT)\n" - "lq $1, %lo(SavedAT)($26)\n" - ".set at\n"); - __exception1(); - } - __asm__ ( - "mfc0 $26, $14\n" - "li $27, 0xFFFFFFE4\n" - "and $26, $27\n" - "mtc0 $26, $14\n" - "sync\n" - - LOAD_KERNELSTACK - "addiu $sp, -0x10\n" - "mfc0 $26, $14\n" - "sw $26, 0($sp)\n" - ); - saveContext2(); - - __asm__ ( - "plzcw %0, %1" - : "=r"(temp) : "r"(code) - ); - temp = 0x1e - (temp & 0xff); - DMAC_STAT = 1 << temp; - threadStatus = 0; - - DMACTable[temp](temp); - - restoreContext2(); - - __asm__ ( - ".set noat\n" - "lw $26, 0($sp)\n" - "mtc0 $26, $14\n" - "lui $26, %hi(SavedSP)\n" - "lq $sp, %lo(SavedSP)($26)\n" - "lui $26, %hi(SavedRA)\n" - "lq $31, %lo(SavedRA)($26)\n" - "lui $26, %hi(SavedAT)\n" - "lq $1, %lo(SavedAT)($26)\n" - ".set at\n" - ); - - if (!threadStatus) { - __asm__ ( - "mfc0 $26, $12\n" - "ori $26, 0x13\n" - "mtc0 $26, $12\n" - "sync\n" - "eret\n" - ); - } - __asm__(LOAD_KERNELSTACK); - threadStatus = 0; - - __ThreadHandler(); -} - -//////////////////////////////////////////////////////////////////// -//80000600 -//////////////////////////////////////////////////////////////////// -void TIMERException() -{ - -} - -//////////////////////////////////////////////////////////////////// -//80000700 -//////////////////////////////////////////////////////////////////// -void setINTCHandler(int n, void (*phandler)(int)) -{ - INTCTable[n] = phandler; -} - -//////////////////////////////////////////////////////////////////// -//80000780 -//////////////////////////////////////////////////////////////////// -void setDMACHandler(int n, void (*phandler)(int)) -{ - DMACTable[n] = phandler; -} +// EE core interrupt and exception handlers +// most functions here can only use $at, $k0, and $k1 +// [made by] [RO]man, zerofrog + +#include "eekernel.h" +#include "eeirq.h" + + +#define LOAD_KERNELSTACK \ + "lui $sp, %hi(g_kernelstackend)\n" \ + "addiu $sp, %lo(g_kernelstackend)\n" + +__asm__(".org 0x0000"); + +__asm__(".set noreorder"); +void CpuException0() { + __asm__ ( + "lui $26, %hi(SavedT9)\n" + "sd $25, %lo(SavedT9)($26)\n" + + "mfc0 $25, $13\n" + "andi $25, 0x7C\n" + "lui $26, %hi(VCRTable)\n" + "addu $26, $25\n" + "lw $26, %lo(VCRTable)($26)\n" + + "lui $25, %hi(SavedT9)\n" + "jr $26\n" + "ld $25, %lo(SavedT9)($25)\n" + ); +} + +__asm__(".org 0x0180"); + +__asm__(".set noreorder"); +void CpuException() { + __asm__ ( + "lui $26, %hi(SavedT9)\n" + "sd $25, %lo(SavedT9)($26)\n" + + "mfc0 $25, $13\n" + "andi $25, 0x7C\n" + "lui $26, %hi(VCRTable)\n" + "addu $26, $25\n" + "lw $26, %lo(VCRTable)($26)\n" + + "lui $25, %hi(SavedT9)\n" + "jr $26\n" + "ld $25, %lo(SavedT9)($25)\n" + ); +} + +__asm__(".org 0x0200"); + +__asm__(".set noreorder"); +__asm__(".set noat"); +void CpuException2() { + __asm__ ( + "lui $26, %hi(SavedSP)\n" + "sq $sp, %lo(SavedSP)($26)\n" + "lui $26, %hi(SavedRA)\n" + "sq $31, %lo(SavedRA)($26)\n" + "lui $26, %hi(SavedAT)\n" + "sq $1, %lo(SavedAT)($26)\n" + + "mfc0 $1, $13\n" + "mfc0 $26, $14\n" + "and $1, $26\n" + "srl $1, 8\n" + "andi $1, 0xFF\n" + + "plzcw $26, $1\n" + "andi $26, 0xFF\n" + "ori $1, $0, 0x1E\n" + "subu $1, $26\n" + "sll $1, 2\n" + "lui $26, %hi(VIntTable)\n" + "addu $26, $25\n" + "lw $26, %lo(VIntTable)($26)\n" + "jr $26\n" + "nop\n" + ); +} + +extern char call_used_regs[]; +extern char fixed_regs[]; + +__asm__(".org 0x0280"); +__asm__(".set noreorder"); + +void SyscException() +{ + const register int code __asm__("$3"); // $v1 + + if (code < 0) { + __asm__( + "addiu $sp, -0x10\n" + "sw $31, 0($sp)\n" + "mfc0 $26, $14\n" + "addiu $26, 4\n" + "sw $26, 4($sp)\n" + "mtc0 $26, $14\n" + "sync\n"); + + table_SYSCALL[-code](); + + __asm__( + "lw $26, 4($sp)\n" + "lw $31, 0($sp)\n" + "addiu $sp, 0x10\n" + "mtc0 $26, $14\n" + "sync\n" + "eret\n" + "nop\n"); + } + + if (code == 0x7c) { + _Deci2Call(); + return; + } + + __asm__( + "lui $26, %hi(SavedSP)\n" + "sq $sp, %lo(SavedSP)($26)\n" + "lui $26, %hi(SavedRA)\n" + "sq $31, %lo(SavedRA)($26)\n" + "lui $26, %hi(SavedAT)\n" + "sq $1, %lo(SavedAT)($26)\n" + + "mfc0 $1, $12\n" + "addiu $26, $0, 0xFFE4\n" + "and $1, $26\n" + "mtc0 $1, $12\n" + "sync\n" + + "move $26, $sp\n" + LOAD_KERNELSTACK + "addiu $sp, -0x10\n" + "sw $31, 0($sp)\n" + "sw $26, 4($sp)\n" + "mfc0 $26, $14\n" + "addiu $26, 4\n" + "sw $26, 8($sp)\n" + "mtc0 $26, $14\n" + "sync\n"); + + table_SYSCALL[code](); + + __asm__( + "lw $26, 8($sp)\n" + "lw $31, 0($sp)\n" + "lw $sp, 4($sp)\n" + "mtc0 $26, $14\n" + "sync\n" + + "mfc0 $26, $12\n" + "ori $26, 0x13\n" + "mtc0 $26, $12\n" + "sync\n" + "eret\n" + "nop\n"); +} + +void _Deci2Call() { + __puts("_Deci2Call called\n"); +} + +void __ThreadHandler(); + +void INTCException() { + u32 code; + u32 temp; + + code = INTC_STAT & INTC_MASK; + if (code & 0xC0) { + int VpuStat; + + __asm__("cfc2 %0, $29\n" : "=r"(VpuStat) : ); + if (VpuStat & 0x202) { + __asm__( + ".set noat\n" + "lui $26, %hi(SavedAT)\n" + "lq $1, %lo(SavedAT)($26)\n" + ".set at\n"); + __exception(); + } + } + __asm__ ( + "mfc0 $26, $14\n" + "li $27, 0xFFFFFFE4\n" + "and $26, $27\n" + "mtc0 $26, $14\n" + "sync\n" + + LOAD_KERNELSTACK + "addiu $sp, -0x10\n" + "mfc0 $26, $14\n" + "sw $26, 0($sp)\n" + ); + saveContext2(); + + __asm__ ( + "plzcw %0, %1" + : "=r"(temp) : "r"(code) + ); + temp = 0x1e - (temp & 0xff); + INTC_STAT = 1 << temp; + threadStatus = 0; + + INTCTable[temp](temp); + + restoreContext2(); + + __asm__ ( + ".set noat\n" + "lw $26, 0($sp)\n" + "mtc0 $26, $14\n" + "lui $26, %hi(SavedSP)\n" + "lq $sp, %lo(SavedSP)($26)\n" + "lui $26, %hi(SavedRA)\n" + "lq $31, %lo(SavedRA)($26)\n" + "lui $26, %hi(SavedAT)\n" + "lq $1, %lo(SavedAT)($26)\n" + ".set at\n" + ); + + if (!threadStatus) { + __asm__ ( + "mfc0 $26, $12\n" + "ori $26, 0x13\n" + "mtc0 $26, $12\n" + "sync\n" + "eret\n" + ); + } + __asm__(LOAD_KERNELSTACK); + threadStatus = 0; + + __ThreadHandler(); +} + +//////////////////////////////////////////////////////////////////// +//800004C0 +//////////////////////////////////////////////////////////////////// +void DMACException() { + unsigned int code; + unsigned int temp; + + code = (DMAC_STAT >> 16) | 0x8000; + code&= DMAC_STAT & 0xFFFF; + if (code & 0x80) { + //__printf("%s: code & 0x80\n", __FUNCTION__); + __asm__( + ".set noat\n" + "lui $26, %hi(SavedAT)\n" + "lq $1, %lo(SavedAT)($26)\n" + ".set at\n"); + __exception1(); + } + __asm__ ( + "mfc0 $26, $14\n" + "li $27, 0xFFFFFFE4\n" + "and $26, $27\n" + "mtc0 $26, $14\n" + "sync\n" + + LOAD_KERNELSTACK + "addiu $sp, -0x10\n" + "mfc0 $26, $14\n" + "sw $26, 0($sp)\n" + ); + saveContext2(); + + __asm__ ( + "plzcw %0, %1" + : "=r"(temp) : "r"(code) + ); + temp = 0x1e - (temp & 0xff); + DMAC_STAT = 1 << temp; + threadStatus = 0; + + DMACTable[temp](temp); + + restoreContext2(); + + __asm__ ( + ".set noat\n" + "lw $26, 0($sp)\n" + "mtc0 $26, $14\n" + "lui $26, %hi(SavedSP)\n" + "lq $sp, %lo(SavedSP)($26)\n" + "lui $26, %hi(SavedRA)\n" + "lq $31, %lo(SavedRA)($26)\n" + "lui $26, %hi(SavedAT)\n" + "lq $1, %lo(SavedAT)($26)\n" + ".set at\n" + ); + + if (!threadStatus) { + __asm__ ( + "mfc0 $26, $12\n" + "ori $26, 0x13\n" + "mtc0 $26, $12\n" + "sync\n" + "eret\n" + ); + } + __asm__(LOAD_KERNELSTACK); + threadStatus = 0; + + __ThreadHandler(); +} + +//////////////////////////////////////////////////////////////////// +//80000600 +//////////////////////////////////////////////////////////////////// +void TIMERException() +{ + +} + +//////////////////////////////////////////////////////////////////// +//80000700 +//////////////////////////////////////////////////////////////////// +void setINTCHandler(int n, void (*phandler)(int)) +{ + INTCTable[n] = phandler; +} + +//////////////////////////////////////////////////////////////////// +//80000780 +//////////////////////////////////////////////////////////////////// +void setDMACHandler(int n, void (*phandler)(int)) +{ + DMACTable[n] = phandler; +} diff --git a/fps2bios/kernel/eeload/eeload.c b/fps2bios/kernel/eeload/eeload.c index 1af03d441e..efacfe9cd2 100644 --- a/fps2bios/kernel/eeload/eeload.c +++ b/fps2bios/kernel/eeload/eeload.c @@ -1,34 +1,34 @@ - -#include -#include - -#include "eeload.h" -#include "eeinit.h" -#include "eedebug.h" - -void __attribute__((noreturn)) eeload_start() { - void (*entry)(); - __puts("EELOAD start\n"); - - __printf("about to SifInitRpc(0)\n"); - SifInitRpc(0); - __printf("done rpc\n"); - - entry = (void (*)())loadElfFile("INTRO"); - entry(); - - entry = (void (*)())loadElfFile("LOADER"); - entry(); - - for (;;); -} - -void Kmemcpy(void *dest, const void *src, int n) { - const u8 *s = (u8*)src; - u8 *d = (u8*)dest; - - while (n) { - *d++ = *s++; n--; - } -} - + +#include +#include + +#include "eeload.h" +#include "eeinit.h" +#include "eedebug.h" + +void __attribute__((noreturn)) eeload_start() { + void (*entry)(); + __puts("EELOAD start\n"); + + __printf("about to SifInitRpc(0)\n"); + SifInitRpc(0); + __printf("done rpc\n"); + + entry = (void (*)())loadElfFile("INTRO"); + entry(); + + entry = (void (*)())loadElfFile("LOADER"); + entry(); + + for (;;); +} + +void Kmemcpy(void *dest, const void *src, int n) { + const u8 *s = (u8*)src; + u8 *d = (u8*)dest; + + while (n) { + *d++ = *s++; n--; + } +} + diff --git a/fps2bios/kernel/eeload/include/eedebug.h b/fps2bios/kernel/eeload/include/eedebug.h index dfe853c609..503f65e062 100644 --- a/fps2bios/kernel/eeload/include/eedebug.h +++ b/fps2bios/kernel/eeload/include/eedebug.h @@ -1,12 +1,12 @@ -#ifndef __EEDEBUG_H__ -#define __EEDEBUG_H__ - -#include -#include - - -void __putc(u8 c); -void __puts(u8 *s); -int __printf(const char *format, ...); - -#endif /* __EEDEBUG_H__ */ +#ifndef __EEDEBUG_H__ +#define __EEDEBUG_H__ + +#include +#include + + +void __putc(u8 c); +void __puts(u8 *s); +int __printf(const char *format, ...); + +#endif /* __EEDEBUG_H__ */ diff --git a/fps2bios/kernel/eeload/include/eeelf.h b/fps2bios/kernel/eeload/include/eeelf.h index 8f5019bc4b..16c344006e 100644 --- a/fps2bios/kernel/eeload/include/eeelf.h +++ b/fps2bios/kernel/eeload/include/eeelf.h @@ -1,6 +1,6 @@ -#ifndef __EEELF_H__ -#define __EEELF_H__ - -u32 loadElfFile(char *filename); - -#endif +#ifndef __EEELF_H__ +#define __EEELF_H__ + +u32 loadElfFile(char *filename); + +#endif diff --git a/fps2bios/kernel/eeload/include/eeinit.h b/fps2bios/kernel/eeload/include/eeinit.h index 19789ca566..d7e267c72a 100644 --- a/fps2bios/kernel/eeload/include/eeinit.h +++ b/fps2bios/kernel/eeload/include/eeinit.h @@ -1,8 +1,8 @@ -#ifndef __EEINIT_H__ -#define __EEINIT_H__ - -#include - -void TlbInit(); - -#endif /* __EEINIT_H__ */ +#ifndef __EEINIT_H__ +#define __EEINIT_H__ + +#include + +void TlbInit(); + +#endif /* __EEINIT_H__ */ diff --git a/fps2bios/kernel/eeload/include/eeirq.h b/fps2bios/kernel/eeload/include/eeirq.h index 9fbccc0a0f..958744e827 100644 --- a/fps2bios/kernel/eeload/include/eeirq.h +++ b/fps2bios/kernel/eeload/include/eeirq.h @@ -1,17 +1,17 @@ -#ifndef __EEIRQ_H__ -#define __EEIRQ_H__ - -#include - -void CpuException0(); -void CpuException(); -void CpuException2(); -void SyscException(); -void _Deci2Call(); -void INTCException(); -void DMACException(); -void TIMERException(); -void setINTCHandler(int n, void (*phandler)(int)); -void setDMACHandler(int n, void (*phandler)(int)); - -#endif /* __EEIRQ_H__ */ +#ifndef __EEIRQ_H__ +#define __EEIRQ_H__ + +#include + +void CpuException0(); +void CpuException(); +void CpuException2(); +void SyscException(); +void _Deci2Call(); +void INTCException(); +void DMACException(); +void TIMERException(); +void setINTCHandler(int n, void (*phandler)(int)); +void setDMACHandler(int n, void (*phandler)(int)); + +#endif /* __EEIRQ_H__ */ diff --git a/fps2bios/kernel/eeload/include/eekernel.h b/fps2bios/kernel/eeload/include/eekernel.h index aedd830883..90f5f20fc8 100644 --- a/fps2bios/kernel/eeload/include/eekernel.h +++ b/fps2bios/kernel/eeload/include/eekernel.h @@ -1,447 +1,447 @@ -#ifndef __EEKERNEL_H__ -#define __EEKERNEL_H__ - -#include -#include - - -#define RCNT0_COUNT *(volatile int*)0xB0000000 -#define RCNT0_MODE *(volatile int*)0xB0000010 -#define RCNT0_TARGET *(volatile int*)0xB0000020 -#define RCNT0_HOLD *(volatile int*)0xB0000030 - -#define RCNT1_COUNT *(volatile int*)0xB0000800 -#define RCNT1_MODE *(volatile int*)0xB0000810 -#define RCNT1_TARGET *(volatile int*)0xB0000820 -#define RCNT1_HOLD *(volatile int*)0xB0000830 - -#define RCNT2_COUNT *(volatile int*)0xB0001000 -#define RCNT2_MODE *(volatile int*)0xB0001010 -#define RCNT2_TARGET *(volatile int*)0xB0001020 - -#define RCNT3_COUNT *(volatile int*)0xB0001800 -#define RCNT3_MODE *(volatile int*)0xB0001810 -#define RCNT3_TARGET *(volatile int*)0xB0001820 - -#define GIF_CTRL *(volatile int*)0xB0003000 - -#define GIF_FIFO *(volatile u128*)0xB0006000 - -//SIF0 -#define D5_CHCR *(volatile int*)0xB000C000 -#define D5_MADR *(volatile int*)0xB000C010 -#define D5_QWC *(volatile int*)0xB000C020 - -//SIF1 -#define D6_CHCR *(volatile int*)0xB000C400 -#define D6_MADR *(volatile int*)0xB000C410 -#define D6_QWC *(volatile int*)0xB000C420 -#define D6_TAG *(volatile int*)0xB000C430 - -#define DMAC_CTRL *(volatile int*)0xB000E000 -#define DMAC_STAT *(volatile int*)0xB000E010 -#define DMAC_PCR *(volatile int*)0xB000E020 -#define DMAC_SQWC *(volatile int*)0xB000E030 -#define DMAC_RBSR *(volatile int*)0xB000E040 -#define DMAC_RBOR *(volatile int*)0xB000E050 -#define DMAC_STADR *(volatile int*)0xB000E060 - -#define INTC_STAT *(volatile int*)0xB000F000 -#define INTC_MASK *(volatile int*)0xB000F010 - -#define SBUS_MSFLG *(volatile int*)0xB000F220 -#define SBUS_SMFLG *(volatile int*)0xB000F230 -#define SBUS_F240 *(volatile int*)0xB000F240 - -#define DMAC_ENABLER *(volatile int*)0xB000F520 -#define DMAC_ENABLEW *(volatile int*)0xB000F590 - -#define SBFLG_IOPALIVE 0x10000 -#define SBFLG_IOPSYNC 0x40000 - -#define GS_PMODE *(volatile u64*)0xB2000000 -#define GS_SMODE1 *(volatile u64*)0xB2000010 -#define GS_SMODE2 *(volatile u64*)0xB2000020 -#define GS_SRFSH *(volatile u64*)0xB2000030 -#define GS_SYNCH1 *(volatile u64*)0xB2000040 -#define GS_SYNCH2 *(volatile u64*)0xB2000050 -#define GS_SYNCV *(volatile u64*)0xB2000060 -#define GS_DISPFB1 *(volatile u64*)0xB2000070 -#define GS_DISPLAY1 *(volatile u64*)0xB2000080 -#define GS_DISPFB2 *(volatile u64*)0xB2000090 -#define GS_DISPLAY2 *(volatile u64*)0xB20000A0 -#define GS_EXTBUF *(volatile u64*)0xB20000B0 -#define GS_EXTDATA *(volatile u64*)0xB20000C0 -#define GS_EXTWRITE *(volatile u64*)0xB20000D0 -#define GS_BGCOLOR *(volatile u64*)0xB20000E0 -#define GS_CSR *(volatile u64*)0xB2001000 -#define GS_IMR *(volatile u64*)0xB2001010 -#define GS_BUSDIR *(volatile u64*)0xB2001040 -#define GS_SIGLBLID *(volatile u64*)0xB2001080 - -#define INTC_GS 0 -#define INTC_SBUS 1 -#define INTC_VBLANK_S 2 -#define INTC_VBLANK_E 3 -#define INTC_VIF0 4 -#define INTC_VIF1 5 -#define INTC_VU0 6 -#define INTC_VU1 7 -#define INTC_IPU 8 -#define INTC_TIM0 9 -#define INTC_TIM1 10 -#define INTC_TIM2 11 -#define INTC_TIM3 12 //threads -//#define INTC_13 13 //not used -//#define INTC_14 14 //not used - -#define DMAC_VIF0 0 -#define DMAC_VIF1 1 -#define DMAC_GIF 2 -#define DMAC_FROM_IPU 3 -#define DMAC_TO_IPU 4 -#define DMAC_SIF0 5 -#define DMAC_SIF1 6 -#define DMAC_SIF2 7 -#define DMAC_FROM_SPR 8 -#define DMAC_TO_SPR 9 -//#define DMAC_10 10 //not used -//#define DMAC_11 11 //not used -//#define DMAC_12 12 //not used -//#define DMAC_13 13 //not used -//#define DMAC_14 14 //not used -#define DMAC_ERROR 15 - - /////////////////////// - // DMA TAG REGISTERS // - /////////////////////// - #define DMA_TAG_REFE 0x00 - #define DMA_TAG_CNT 0x01 - #define DMA_TAG_NEXT 0x02 - #define DMA_TAG_REF 0x03 - #define DMA_TAG_REFS 0x04 - #define DMA_TAG_CALL 0x05 - #define DMA_TAG_RET 0x06 - #define DMA_TAG_END 0x07 - -// Modes for DMA transfers -#define SIF_DMA_FROM_IOP 0x0 -#define SIF_DMA_TO_IOP 0x1 -#define SIF_DMA_FROM_EE 0x0 -#define SIF_DMA_TO_EE 0x1 - -#define SIF_DMA_INT_I 0x2 -#define SIF_DMA_INT_O 0x4 -#define SIF_DMA_SPR 0x8 -#define SIF_DMA_BSN 0x10 /* ? what is this? */ -#define SIF_DMA_TAG 0x20 -#define SIF_DMA_ERT 0x40 -#define DMA_TAG_IRQ 0x80000000 -#define DMA_TAG_PCE 0x0C000000 - -#define KSEG1_ADDR(x) (((u32)(x))|0xA0000000) -#define KUSEG_ADDR(x) (((u32)(x))&0x1FFFFFFF) - -#define MAX_SEMAS 256 -#define STACK_RES 0x2A0 - -//? -#define SRInitVal 0x70030C13 -#define ConfigInitVal 0x73003 - -enum { - THS_RUN = 0x01, - THS_READY = 0x02, - THS_WAIT = 0x04, - THS_SUSPEND = 0x08, - THS_DORMANT = 0x10, -}; - -typedef struct { - u128 gpr[24]; // v0-t9 (skip r0,at,k0-ra) - u128 gp; - u128 fp; - u128 hi; - u128 lo; - u32 sa; -} eeRegs; - -struct ThreadParam { - int status; - void (*entry)(void*); - void *stack; - int stackSize; - void *gpReg; - int initPriority; - int currentPriority; - u32 attr; - u32 option; - int waitSema; // waitType? - int waitId; - int wakeupCount; -}; - -struct TCB { //internal struct - struct TCB *next; //+00 - struct TCB *prev; //+04 - int status;//+08 - void (*entry)(void*); //+0C - void *stack_res; //+10 initial $sp - void *gpReg; //+14 - short currentPriority; //+18 - short initPriority; //+1A - int waitSema, //+1C waitType? - semaId, //+20 - wakeupCount, //+24 - attr, //+28 - option; //+2C - void (*entry_)(void*); //+30 - int argc; //+34 - char *argstring;//+38 - void *stack;//+3C - int stackSize; //+40 - int (*root)(); //+44 - void* heap_base; //+48 -}; - -struct threadCtx { - u128 gpr[25]; // at-t9, (skip r0,k0-ra) - u128 gp; //+190 - u128 sp; //+1A0 - u128 fp; //+1B0 - u128 ra; //+1C0 - u128 hi; //+1D0 - u128 lo; //+1E0 - u32 sa; //+1F0 - u32 cf31;//+1F4 - u32 acc; //+1F8 - u32 res; //+1FC - u32 fpr[32];//+200 -}; - -typedef struct tag_ARGS{ - int argc; - char *argv[16]; - char args[256]; -} ARGS; - -struct SemaParam { - int count; - int max_count; - int init_count; - int wait_threads; - int attr; - u32 option; -}; - -struct kSema { // internal struct - struct kSema *free;//+00 - int count;//+04 - int max_count;//+08 - int attr;//+0C - int option;//+10 - int wait_threads;//+14 - struct TCB *wait_next,//+18 - *wait_prev;//+1C -}; - -struct ll { struct ll *next, *prev; }; //linked list - -//internal struct -struct IDhandl { //intc dmac handler - struct ll *next, //+00 - *prev; //+04 - int (*handler)(int); //+08 - u32 gp; //+0C - void *arg; //+10 - int flag; //+14 -}; - -//internal struct -struct HCinfo{ //handler cause info - int count; - struct ll l; -}; - -extern u128 SavedSP; -extern u128 SavedRA; -extern u128 SavedAT; -extern u64 SavedT9; - -extern eeRegs SavedRegs; - -extern u32 excepRA; -extern u32 excepSP; - -extern u32 (*table_CpuConfig[6])(u32); -extern void (*table_SYSCALL[0x80])(); - -extern void (*VCRTable[14])(); -extern void (*VIntTable[8])(); -extern void (*INTCTable[16])(int); -extern void (*DMACTable[16])(int); - -extern int threadId; -extern int threadPrio; -extern int threadStatus; - -extern u64 hvParam; - -extern u32 machineType; -extern u64 gsIMR; -extern u32 memorySize; - -extern u32 g_kernelstackend; - -extern u32 dmac_CHCR[10]; - -extern int VSyncFlag0; -extern int VSyncFlag1; - -extern int _HandlersCount; -extern struct ll handler_ll_free, *ihandlers_last, *ihandlers_first; -extern struct HCinfo intcs_array[14]; -extern struct ll *dhandlers_last, *dhandlers_first; -extern struct HCinfo dmacs_array[15]; -extern struct IDhandl pgifhandlers_array[161]; -extern void (*sbus_handlers[32])(int ca); - -extern int rcnt3Code; -extern int rcnt3TargetTable[0x142]; -extern u8 rcnt3TargetNum[0x40]; -extern int threads_count; -extern struct ll thread_ll_free; -extern struct ll thread_ll_priorities[128]; -extern int semas_count; -extern struct kSema* semas_last; - -extern struct TCB threads_array[256]; -extern struct kSema semas_array[256]; - -extern char tagindex; -extern short transferscount; -extern struct TAG{ - int id_qwc; - int addr; - int unk[2]; -} tadrptr[31]; -extern int extrastorage[(16/4) * 8][31]; - -extern int osdConfigParam; - -// syscalls -// Every syscall is officially prefixed with _ (to avoid clashing with ps2sdk) -void _SetSYSCALL(int num, int address); -int __EnableIntc(int ch); -int __DisableIntc(int ch); -int __EnableDmac(int ch); -int __DisableDmac(int ch); -void *_SetVTLBRefillHandler(int cause, void (*handler)()); -void *_SetVCommonHandler(int cause, void (*handler)()); -void *_SetVInterruptHandler(int cause, void (*handler)()); -void _PSMode(); -u32 _MachineType(); -u32 _SetMemorySize(u32 size); -u32 _GetMemorySize(); -u64 _GsGetIMR(); -u64 _GsPutIMR(u64 val); -int _Exit(); // 3 -void _RFU___(); // 0 -void _SetVSyncFlag(int flag0, int flag1); -int _AddIntcHandler(int cause, int (*handler)(int), int next, void *arg); -int _AddIntcHandler2(int cause, int (*handler)(int), int next, void *arg); -int _RemoveIntcHandler(int cause, int hid); -int _AddDmacHandler(int cause, int (*handler)(int), int next, void *arg); -int _AddDmacHandler2(int cause, int (*handler)(int), int next, void *arg); -int _RemoveDmacHandler(int code, int hid); -int _AddSbusIntcHandler(int cause, void (*handler)(int ca)); -int _RemoveSbusIntcHandler(int cause); -int _Interrupt2Iop(int cause); -void _RFU005(); -int _GetCop0(int reg); -int _ExecPS2(void *, void *, int, char **); -int _DeleteThread(int tid); -int _StartThread(int tid, void *arg); -int _ExitThread(); -int _ExitDeleteThread(); -int _SleepThread(); -int _WakeupThread(int tid); -int _WaitSema(int sid); -void _ChangeThreadPriority(int tid, int prio); -int _CreateThread(struct ThreadParam *param); -int _iChangeThreadPriority(int tid, int prio); -int _GetThreadId(); -int _ReferThreadStatus(int tid, struct ThreadParam *info); -int _iWakeupThread(int tid); -int _SuspendThread(int thid); -int _iResumeThread(int tid); -int _CancelWakeupThread(int tid); -int _CreateEventFlag(); -int _CreateSema(struct SemaParam *sema); -int _RFU073(int sid); -int _iSignalSema(int sid); -int _PollSema(int sid); -int _ReferSemaStatus(int sid, struct SemaParam *sema); -int _DeleteEventFlag(); -void*_InitializeMainThread(u32 gp, void *stack, int stack_size, - char *args, int root); -void *_InitializeHeapArea(void *heap_base, int heap_size); -void *_EndOfHeap(); -int _LoadPS2Exe(char *filename, int argc, char **argv); -int _ExecOSD(int argc, char **argv); -void _SifSetDChain(); -void _SifStopDma(); -u32 _SifSetDma(SifDmaTransfer_t *sdd, int len); -void _SetGsCrt(short arg0, short arg1, short arg2); // 2 -void _GetGsHParam(int *p0, int *p1, int *p2, int *p3); -int _GetGsVParam(); -void _SetGsVParam(int VParam); -void _GetOsdConfigParam(int *result); -void _SetOsdConfigParam(int *param); -int _ResetEE(int init); // 1 -int _TlbWriteRandom(u32 PageMask, u32 EntryHi, u32 EntryLo0, u32 EntryLo1); -int _SetAlarm(short a0, int a1, int a2); -void _ReleaseAlarm(); -int _TerminateThread(int tid); -void _RotateThreadReadyQueue(int prio); -int _iTerminateThread(int tid); -int _DisableDispatchThread(); -int _EnableDispatchThread(); -int _iRotateThreadReadyQueue(int prio); -void _ReleaseWaitThread(int tid); -int _iReleaseWaitThread(int tid); -int _ResumeThread(int tid); -int _iResumeThread(int tid); -void _JoinThread(); -int _DeleteSema(int sid); -int _iDeleteSema(int sid); -void _SignalSema(int sid); -void _SetGsHParam(int a0, int a1, int a2, int a3); -int _SetEventFlag(int ef, u32 bits); // bits is EF_X -int _iSetEventFlag(int ef, u32 bits); -void _EnableIntcHandler(u32 id); -void _DisableIntcHandler(u32 id); -void _EnableDmacHandler(u32 id); -void _DisableDmacHandler(u32 id); -void _KSeg0(u32 arg); -int _EnableCache(int cache); -int _DisableCache(int cache); -void _FlushCache(int op); -void _105(int op1, int op2); -u32 _CpuConfig(u32 op); -void _SetCPUTimerHandler(void (*handler)()); -void _SetCPUTimer(int compval); -void _SetPgifHandler(void (*handler)(int)); -void _print(); -int _SifDmaStat(int id); - -int _SifGetReg(int reg); -int _SifSetReg(int reg, u32 val); - -//////////////////////////////////////////////////////////////////// -// KERNEL BSS // -//////////////////////////////////////////////////////////////////// - - -#endif - +#ifndef __EEKERNEL_H__ +#define __EEKERNEL_H__ + +#include +#include + + +#define RCNT0_COUNT *(volatile int*)0xB0000000 +#define RCNT0_MODE *(volatile int*)0xB0000010 +#define RCNT0_TARGET *(volatile int*)0xB0000020 +#define RCNT0_HOLD *(volatile int*)0xB0000030 + +#define RCNT1_COUNT *(volatile int*)0xB0000800 +#define RCNT1_MODE *(volatile int*)0xB0000810 +#define RCNT1_TARGET *(volatile int*)0xB0000820 +#define RCNT1_HOLD *(volatile int*)0xB0000830 + +#define RCNT2_COUNT *(volatile int*)0xB0001000 +#define RCNT2_MODE *(volatile int*)0xB0001010 +#define RCNT2_TARGET *(volatile int*)0xB0001020 + +#define RCNT3_COUNT *(volatile int*)0xB0001800 +#define RCNT3_MODE *(volatile int*)0xB0001810 +#define RCNT3_TARGET *(volatile int*)0xB0001820 + +#define GIF_CTRL *(volatile int*)0xB0003000 + +#define GIF_FIFO *(volatile u128*)0xB0006000 + +//SIF0 +#define D5_CHCR *(volatile int*)0xB000C000 +#define D5_MADR *(volatile int*)0xB000C010 +#define D5_QWC *(volatile int*)0xB000C020 + +//SIF1 +#define D6_CHCR *(volatile int*)0xB000C400 +#define D6_MADR *(volatile int*)0xB000C410 +#define D6_QWC *(volatile int*)0xB000C420 +#define D6_TAG *(volatile int*)0xB000C430 + +#define DMAC_CTRL *(volatile int*)0xB000E000 +#define DMAC_STAT *(volatile int*)0xB000E010 +#define DMAC_PCR *(volatile int*)0xB000E020 +#define DMAC_SQWC *(volatile int*)0xB000E030 +#define DMAC_RBSR *(volatile int*)0xB000E040 +#define DMAC_RBOR *(volatile int*)0xB000E050 +#define DMAC_STADR *(volatile int*)0xB000E060 + +#define INTC_STAT *(volatile int*)0xB000F000 +#define INTC_MASK *(volatile int*)0xB000F010 + +#define SBUS_MSFLG *(volatile int*)0xB000F220 +#define SBUS_SMFLG *(volatile int*)0xB000F230 +#define SBUS_F240 *(volatile int*)0xB000F240 + +#define DMAC_ENABLER *(volatile int*)0xB000F520 +#define DMAC_ENABLEW *(volatile int*)0xB000F590 + +#define SBFLG_IOPALIVE 0x10000 +#define SBFLG_IOPSYNC 0x40000 + +#define GS_PMODE *(volatile u64*)0xB2000000 +#define GS_SMODE1 *(volatile u64*)0xB2000010 +#define GS_SMODE2 *(volatile u64*)0xB2000020 +#define GS_SRFSH *(volatile u64*)0xB2000030 +#define GS_SYNCH1 *(volatile u64*)0xB2000040 +#define GS_SYNCH2 *(volatile u64*)0xB2000050 +#define GS_SYNCV *(volatile u64*)0xB2000060 +#define GS_DISPFB1 *(volatile u64*)0xB2000070 +#define GS_DISPLAY1 *(volatile u64*)0xB2000080 +#define GS_DISPFB2 *(volatile u64*)0xB2000090 +#define GS_DISPLAY2 *(volatile u64*)0xB20000A0 +#define GS_EXTBUF *(volatile u64*)0xB20000B0 +#define GS_EXTDATA *(volatile u64*)0xB20000C0 +#define GS_EXTWRITE *(volatile u64*)0xB20000D0 +#define GS_BGCOLOR *(volatile u64*)0xB20000E0 +#define GS_CSR *(volatile u64*)0xB2001000 +#define GS_IMR *(volatile u64*)0xB2001010 +#define GS_BUSDIR *(volatile u64*)0xB2001040 +#define GS_SIGLBLID *(volatile u64*)0xB2001080 + +#define INTC_GS 0 +#define INTC_SBUS 1 +#define INTC_VBLANK_S 2 +#define INTC_VBLANK_E 3 +#define INTC_VIF0 4 +#define INTC_VIF1 5 +#define INTC_VU0 6 +#define INTC_VU1 7 +#define INTC_IPU 8 +#define INTC_TIM0 9 +#define INTC_TIM1 10 +#define INTC_TIM2 11 +#define INTC_TIM3 12 //threads +//#define INTC_13 13 //not used +//#define INTC_14 14 //not used + +#define DMAC_VIF0 0 +#define DMAC_VIF1 1 +#define DMAC_GIF 2 +#define DMAC_FROM_IPU 3 +#define DMAC_TO_IPU 4 +#define DMAC_SIF0 5 +#define DMAC_SIF1 6 +#define DMAC_SIF2 7 +#define DMAC_FROM_SPR 8 +#define DMAC_TO_SPR 9 +//#define DMAC_10 10 //not used +//#define DMAC_11 11 //not used +//#define DMAC_12 12 //not used +//#define DMAC_13 13 //not used +//#define DMAC_14 14 //not used +#define DMAC_ERROR 15 + + /////////////////////// + // DMA TAG REGISTERS // + /////////////////////// + #define DMA_TAG_REFE 0x00 + #define DMA_TAG_CNT 0x01 + #define DMA_TAG_NEXT 0x02 + #define DMA_TAG_REF 0x03 + #define DMA_TAG_REFS 0x04 + #define DMA_TAG_CALL 0x05 + #define DMA_TAG_RET 0x06 + #define DMA_TAG_END 0x07 + +// Modes for DMA transfers +#define SIF_DMA_FROM_IOP 0x0 +#define SIF_DMA_TO_IOP 0x1 +#define SIF_DMA_FROM_EE 0x0 +#define SIF_DMA_TO_EE 0x1 + +#define SIF_DMA_INT_I 0x2 +#define SIF_DMA_INT_O 0x4 +#define SIF_DMA_SPR 0x8 +#define SIF_DMA_BSN 0x10 /* ? what is this? */ +#define SIF_DMA_TAG 0x20 +#define SIF_DMA_ERT 0x40 +#define DMA_TAG_IRQ 0x80000000 +#define DMA_TAG_PCE 0x0C000000 + +#define KSEG1_ADDR(x) (((u32)(x))|0xA0000000) +#define KUSEG_ADDR(x) (((u32)(x))&0x1FFFFFFF) + +#define MAX_SEMAS 256 +#define STACK_RES 0x2A0 + +//? +#define SRInitVal 0x70030C13 +#define ConfigInitVal 0x73003 + +enum { + THS_RUN = 0x01, + THS_READY = 0x02, + THS_WAIT = 0x04, + THS_SUSPEND = 0x08, + THS_DORMANT = 0x10, +}; + +typedef struct { + u128 gpr[24]; // v0-t9 (skip r0,at,k0-ra) + u128 gp; + u128 fp; + u128 hi; + u128 lo; + u32 sa; +} eeRegs; + +struct ThreadParam { + int status; + void (*entry)(void*); + void *stack; + int stackSize; + void *gpReg; + int initPriority; + int currentPriority; + u32 attr; + u32 option; + int waitSema; // waitType? + int waitId; + int wakeupCount; +}; + +struct TCB { //internal struct + struct TCB *next; //+00 + struct TCB *prev; //+04 + int status;//+08 + void (*entry)(void*); //+0C + void *stack_res; //+10 initial $sp + void *gpReg; //+14 + short currentPriority; //+18 + short initPriority; //+1A + int waitSema, //+1C waitType? + semaId, //+20 + wakeupCount, //+24 + attr, //+28 + option; //+2C + void (*entry_)(void*); //+30 + int argc; //+34 + char *argstring;//+38 + void *stack;//+3C + int stackSize; //+40 + int (*root)(); //+44 + void* heap_base; //+48 +}; + +struct threadCtx { + u128 gpr[25]; // at-t9, (skip r0,k0-ra) + u128 gp; //+190 + u128 sp; //+1A0 + u128 fp; //+1B0 + u128 ra; //+1C0 + u128 hi; //+1D0 + u128 lo; //+1E0 + u32 sa; //+1F0 + u32 cf31;//+1F4 + u32 acc; //+1F8 + u32 res; //+1FC + u32 fpr[32];//+200 +}; + +typedef struct tag_ARGS{ + int argc; + char *argv[16]; + char args[256]; +} ARGS; + +struct SemaParam { + int count; + int max_count; + int init_count; + int wait_threads; + int attr; + u32 option; +}; + +struct kSema { // internal struct + struct kSema *free;//+00 + int count;//+04 + int max_count;//+08 + int attr;//+0C + int option;//+10 + int wait_threads;//+14 + struct TCB *wait_next,//+18 + *wait_prev;//+1C +}; + +struct ll { struct ll *next, *prev; }; //linked list + +//internal struct +struct IDhandl { //intc dmac handler + struct ll *next, //+00 + *prev; //+04 + int (*handler)(int); //+08 + u32 gp; //+0C + void *arg; //+10 + int flag; //+14 +}; + +//internal struct +struct HCinfo{ //handler cause info + int count; + struct ll l; +}; + +extern u128 SavedSP; +extern u128 SavedRA; +extern u128 SavedAT; +extern u64 SavedT9; + +extern eeRegs SavedRegs; + +extern u32 excepRA; +extern u32 excepSP; + +extern u32 (*table_CpuConfig[6])(u32); +extern void (*table_SYSCALL[0x80])(); + +extern void (*VCRTable[14])(); +extern void (*VIntTable[8])(); +extern void (*INTCTable[16])(int); +extern void (*DMACTable[16])(int); + +extern int threadId; +extern int threadPrio; +extern int threadStatus; + +extern u64 hvParam; + +extern u32 machineType; +extern u64 gsIMR; +extern u32 memorySize; + +extern u32 g_kernelstackend; + +extern u32 dmac_CHCR[10]; + +extern int VSyncFlag0; +extern int VSyncFlag1; + +extern int _HandlersCount; +extern struct ll handler_ll_free, *ihandlers_last, *ihandlers_first; +extern struct HCinfo intcs_array[14]; +extern struct ll *dhandlers_last, *dhandlers_first; +extern struct HCinfo dmacs_array[15]; +extern struct IDhandl pgifhandlers_array[161]; +extern void (*sbus_handlers[32])(int ca); + +extern int rcnt3Code; +extern int rcnt3TargetTable[0x142]; +extern u8 rcnt3TargetNum[0x40]; +extern int threads_count; +extern struct ll thread_ll_free; +extern struct ll thread_ll_priorities[128]; +extern int semas_count; +extern struct kSema* semas_last; + +extern struct TCB threads_array[256]; +extern struct kSema semas_array[256]; + +extern char tagindex; +extern short transferscount; +extern struct TAG{ + int id_qwc; + int addr; + int unk[2]; +} tadrptr[31]; +extern int extrastorage[(16/4) * 8][31]; + +extern int osdConfigParam; + +// syscalls +// Every syscall is officially prefixed with _ (to avoid clashing with ps2sdk) +void _SetSYSCALL(int num, int address); +int __EnableIntc(int ch); +int __DisableIntc(int ch); +int __EnableDmac(int ch); +int __DisableDmac(int ch); +void *_SetVTLBRefillHandler(int cause, void (*handler)()); +void *_SetVCommonHandler(int cause, void (*handler)()); +void *_SetVInterruptHandler(int cause, void (*handler)()); +void _PSMode(); +u32 _MachineType(); +u32 _SetMemorySize(u32 size); +u32 _GetMemorySize(); +u64 _GsGetIMR(); +u64 _GsPutIMR(u64 val); +int _Exit(); // 3 +void _RFU___(); // 0 +void _SetVSyncFlag(int flag0, int flag1); +int _AddIntcHandler(int cause, int (*handler)(int), int next, void *arg); +int _AddIntcHandler2(int cause, int (*handler)(int), int next, void *arg); +int _RemoveIntcHandler(int cause, int hid); +int _AddDmacHandler(int cause, int (*handler)(int), int next, void *arg); +int _AddDmacHandler2(int cause, int (*handler)(int), int next, void *arg); +int _RemoveDmacHandler(int code, int hid); +int _AddSbusIntcHandler(int cause, void (*handler)(int ca)); +int _RemoveSbusIntcHandler(int cause); +int _Interrupt2Iop(int cause); +void _RFU005(); +int _GetCop0(int reg); +int _ExecPS2(void *, void *, int, char **); +int _DeleteThread(int tid); +int _StartThread(int tid, void *arg); +int _ExitThread(); +int _ExitDeleteThread(); +int _SleepThread(); +int _WakeupThread(int tid); +int _WaitSema(int sid); +void _ChangeThreadPriority(int tid, int prio); +int _CreateThread(struct ThreadParam *param); +int _iChangeThreadPriority(int tid, int prio); +int _GetThreadId(); +int _ReferThreadStatus(int tid, struct ThreadParam *info); +int _iWakeupThread(int tid); +int _SuspendThread(int thid); +int _iResumeThread(int tid); +int _CancelWakeupThread(int tid); +int _CreateEventFlag(); +int _CreateSema(struct SemaParam *sema); +int _RFU073(int sid); +int _iSignalSema(int sid); +int _PollSema(int sid); +int _ReferSemaStatus(int sid, struct SemaParam *sema); +int _DeleteEventFlag(); +void*_InitializeMainThread(u32 gp, void *stack, int stack_size, + char *args, int root); +void *_InitializeHeapArea(void *heap_base, int heap_size); +void *_EndOfHeap(); +int _LoadPS2Exe(char *filename, int argc, char **argv); +int _ExecOSD(int argc, char **argv); +void _SifSetDChain(); +void _SifStopDma(); +u32 _SifSetDma(SifDmaTransfer_t *sdd, int len); +void _SetGsCrt(short arg0, short arg1, short arg2); // 2 +void _GetGsHParam(int *p0, int *p1, int *p2, int *p3); +int _GetGsVParam(); +void _SetGsVParam(int VParam); +void _GetOsdConfigParam(int *result); +void _SetOsdConfigParam(int *param); +int _ResetEE(int init); // 1 +int _TlbWriteRandom(u32 PageMask, u32 EntryHi, u32 EntryLo0, u32 EntryLo1); +int _SetAlarm(short a0, int a1, int a2); +void _ReleaseAlarm(); +int _TerminateThread(int tid); +void _RotateThreadReadyQueue(int prio); +int _iTerminateThread(int tid); +int _DisableDispatchThread(); +int _EnableDispatchThread(); +int _iRotateThreadReadyQueue(int prio); +void _ReleaseWaitThread(int tid); +int _iReleaseWaitThread(int tid); +int _ResumeThread(int tid); +int _iResumeThread(int tid); +void _JoinThread(); +int _DeleteSema(int sid); +int _iDeleteSema(int sid); +void _SignalSema(int sid); +void _SetGsHParam(int a0, int a1, int a2, int a3); +int _SetEventFlag(int ef, u32 bits); // bits is EF_X +int _iSetEventFlag(int ef, u32 bits); +void _EnableIntcHandler(u32 id); +void _DisableIntcHandler(u32 id); +void _EnableDmacHandler(u32 id); +void _DisableDmacHandler(u32 id); +void _KSeg0(u32 arg); +int _EnableCache(int cache); +int _DisableCache(int cache); +void _FlushCache(int op); +void _105(int op1, int op2); +u32 _CpuConfig(u32 op); +void _SetCPUTimerHandler(void (*handler)()); +void _SetCPUTimer(int compval); +void _SetPgifHandler(void (*handler)(int)); +void _print(); +int _SifDmaStat(int id); + +int _SifGetReg(int reg); +int _SifSetReg(int reg, u32 val); + +//////////////////////////////////////////////////////////////////// +// KERNEL BSS // +//////////////////////////////////////////////////////////////////// + + +#endif + diff --git a/fps2bios/kernel/eeload/include/eeload.h b/fps2bios/kernel/eeload/include/eeload.h index ba6af54200..0dda55ba2b 100644 --- a/fps2bios/kernel/eeload/include/eeload.h +++ b/fps2bios/kernel/eeload/include/eeload.h @@ -1,4 +1,4 @@ -#ifndef __EELOAD_H__ -#define __EELOAD_H__ - -#endif /* __EELOAD_H__ */ +#ifndef __EELOAD_H__ +#define __EELOAD_H__ + +#endif /* __EELOAD_H__ */ diff --git a/fps2bios/kernel/eeload/include/romdir.h b/fps2bios/kernel/eeload/include/romdir.h index 8249989e78..ef03a3223d 100644 --- a/fps2bios/kernel/eeload/include/romdir.h +++ b/fps2bios/kernel/eeload/include/romdir.h @@ -1,20 +1,20 @@ -#ifndef __ROMDIR_H__ -#define __ROMDIR_H__ - -#include - -struct romdir { - /*following variable must place in designed order*/ - u8 fileName[10]; - u16 extInfoSize; - u32 fileSize; -} __attribute__ ((packed)); - -struct rominfo { - u32 fileOffset; - u32 fileSize; -}; - -struct rominfo *romdirGetFile(char *name, struct rominfo *ri); - -#endif /* __ROMDIR_H__ */ +#ifndef __ROMDIR_H__ +#define __ROMDIR_H__ + +#include + +struct romdir { + /*following variable must place in designed order*/ + u8 fileName[10]; + u16 extInfoSize; + u32 fileSize; +} __attribute__ ((packed)); + +struct rominfo { + u32 fileOffset; + u32 fileSize; +}; + +struct rominfo *romdirGetFile(char *name, struct rominfo *ri); + +#endif /* __ROMDIR_H__ */ diff --git a/fps2bios/kernel/eeload/romdir.c b/fps2bios/kernel/eeload/romdir.c index 3494074eda..a9915f7f41 100644 --- a/fps2bios/kernel/eeload/romdir.c +++ b/fps2bios/kernel/eeload/romdir.c @@ -1,47 +1,47 @@ -/*************************************************************** -* romdir.c, based over Alex Lau (http://alexlau.8k.com) RomDir * -****************************************************************/ -#include "romdir.h" - -struct romdir *base = NULL; - -struct romdir *romdirInit() { - u8 *mem; - - for (mem=(u8*)0xbfc00000; (u32)mem<0xbfc01000; mem++) { - if (mem[0] == 'R' && mem[1] == 'E' && - mem[2] == 'S' && mem[3] == 'E' && - mem[4] == 'T') - break; - } - if ((u32)mem == 0xbfc01000) return NULL; - - return (struct romdir*)mem; -} - -struct rominfo *romdirGetFile(char *name, struct rominfo *ri) { - struct romdir *rd; -// struct romdir *base; - int i; - - if (base == NULL) { - base = romdirInit(); - if (base == NULL) return NULL; - } - - ri->fileOffset = 0; - for (rd = base; rd->fileName[0] != 0; rd++) { - for (i=0; i<10 && name[i] != 0; i++) { - if (rd->fileName[i] != name[i]) break; - } - if (rd->fileName[i] != name[i]) { - ri->fileOffset+= (rd->fileSize + 15) & ~0xF; - continue; - } - - ri->fileSize = rd->fileSize; - return ri; - } - - return NULL; -} +/*************************************************************** +* romdir.c, based over Alex Lau (http://alexlau.8k.com) RomDir * +****************************************************************/ +#include "romdir.h" + +struct romdir *base = NULL; + +struct romdir *romdirInit() { + u8 *mem; + + for (mem=(u8*)0xbfc00000; (u32)mem<0xbfc01000; mem++) { + if (mem[0] == 'R' && mem[1] == 'E' && + mem[2] == 'S' && mem[3] == 'E' && + mem[4] == 'T') + break; + } + if ((u32)mem == 0xbfc01000) return NULL; + + return (struct romdir*)mem; +} + +struct rominfo *romdirGetFile(char *name, struct rominfo *ri) { + struct romdir *rd; +// struct romdir *base; + int i; + + if (base == NULL) { + base = romdirInit(); + if (base == NULL) return NULL; + } + + ri->fileOffset = 0; + for (rd = base; rd->fileName[0] != 0; rd++) { + for (i=0; i<10 && name[i] != 0; i++) { + if (rd->fileName[i] != name[i]) break; + } + if (rd->fileName[i] != name[i]) { + ri->fileOffset+= (rd->fileSize + 15) & ~0xF; + continue; + } + + ri->fileSize = rd->fileSize; + return ri; + } + + return NULL; +} diff --git a/fps2bios/kernel/eestart.c b/fps2bios/kernel/eestart.c index edb1b6f5b5..9a8562e25c 100644 --- a/fps2bios/kernel/eestart.c +++ b/fps2bios/kernel/eestart.c @@ -1,50 +1,50 @@ -#include -#include "romdir.h" - -static void Kputc(u8 c) { - *((u8*)0x1000f180) = c; -} - -static void Kputs(u8 *s) { - while (*s != 0) { - Kputc(*s++); - } -} - -static void Kmemcpy(void *dest, const void *src, int n) { - const u8 *s = (u8*)src; - u8 *d = (u8*)dest; - - while (n > 0) { - *d++ = *s++; n--; - } -} - -void _eestart() { - struct rominfo ri; - u8 *str; - - romdirGetFile("ROMVER", &ri); - str = (u8*)(0xbfc00000 + ri.fileOffset); - Kputs("fps2bios v"); - Kputc(str[1]); Kputc('.'); Kputc(str[3]); Kputc('\n'); - - romdirGetFile("EELOAD", &ri); - - Kputs("loading EELOAD to 0x80000000\n"); - - Kmemcpy((void*)0x80000000, (void*)(0xbfc00000 + ri.fileOffset), ri.fileSize); - - __asm__ ( - "li $26, 0x80001000\n" - "jr $26\n"); - for (;;); -} - -__asm__ ( - ".global eestart\n" - "eestart:\n" - "li $sp, 0x80010000\n" - "j _eestart\n"); - - +#include +#include "romdir.h" + +static void Kputc(u8 c) { + *((u8*)0x1000f180) = c; +} + +static void Kputs(u8 *s) { + while (*s != 0) { + Kputc(*s++); + } +} + +static void Kmemcpy(void *dest, const void *src, int n) { + const u8 *s = (u8*)src; + u8 *d = (u8*)dest; + + while (n > 0) { + *d++ = *s++; n--; + } +} + +void _eestart() { + struct rominfo ri; + u8 *str; + + romdirGetFile("ROMVER", &ri); + str = (u8*)(0xbfc00000 + ri.fileOffset); + Kputs("fps2bios v"); + Kputc(str[1]); Kputc('.'); Kputc(str[3]); Kputc('\n'); + + romdirGetFile("EELOAD", &ri); + + Kputs("loading EELOAD to 0x80000000\n"); + + Kmemcpy((void*)0x80000000, (void*)(0xbfc00000 + ri.fileOffset), ri.fileSize); + + __asm__ ( + "li $26, 0x80001000\n" + "jr $26\n"); + for (;;); +} + +__asm__ ( + ".global eestart\n" + "eestart:\n" + "li $sp, 0x80010000\n" + "j _eestart\n"); + + diff --git a/fps2bios/kernel/iopload/Makefile b/fps2bios/kernel/iopload/Makefile index 614a3983a3..38697f5906 100644 --- a/fps2bios/kernel/iopload/Makefile +++ b/fps2bios/kernel/iopload/Makefile @@ -1,67 +1,67 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include - -IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 -IOPINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include -IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -IOPLINK = $(IOPLD) -dc - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: iopload - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -nostartfiles -L$(PS2LIB)/iop/lib -LDADD = -OBJECTS = romdir.o iopelf.o iopdebug.o -DIRS = iopboot sysmem loadcore excepman intrman stdio timrman \ - dmacman sifman sifcmd ssbusc sysclib heaplib \ - vblank threadman sio2man - -iopload: $(OBJECTS) - for i in $(DIRS); do \ - (cd $$i; make; cd ..) \ - done; - - -%.o: %.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - - -clean: - for i in $(DIRS); do \ - (cd $$i; make clean; cd ..) \ - done; - rm -f $(OBJECTS) - - - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: iopload + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -nostartfiles -L$(PS2LIB)/iop/lib +LDADD = +OBJECTS = romdir.o iopelf.o iopdebug.o +DIRS = iopboot sysmem loadcore excepman intrman stdio timrman \ + dmacman sifman sifcmd ssbusc sysclib heaplib \ + vblank threadman sio2man + +iopload: $(OBJECTS) + for i in $(DIRS); do \ + (cd $$i; make; cd ..) \ + done; + + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + + +clean: + for i in $(DIRS); do \ + (cd $$i; make clean; cd ..) \ + done; + rm -f $(OBJECTS) + + + diff --git a/fps2bios/kernel/iopload/dmacman/Makefile b/fps2bios/kernel/iopload/dmacman/Makefile index 51769e589a..81855565c3 100644 --- a/fps2bios/kernel/iopload/dmacman/Makefile +++ b/fps2bios/kernel/iopload/dmacman/Makefile @@ -1,60 +1,60 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include - -IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 -IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include -IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -IOPLINK = $(IOPLD) -dc -IOPASFLAGS := -EL -G0 - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: dmacman - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib -LDADD = -OBJECTS = dmacman.o ../iopdebug.o ../libkernel/iop_loadcore.o \ - ../libkernel/iop_intrman.o ../libkernel/iop_sysmem.o - -dmacman: $(OBJECTS) - $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/DMACMAN - -%.o: %.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - -%.o : %.s - $(IOPAS) $(IOPASFLAGS) $< -o $@ - -clean: - rm -f $(OBJECTS) - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: dmacman + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib +LDADD = +OBJECTS = dmacman.o ../iopdebug.o ../libkernel/iop_loadcore.o \ + ../libkernel/iop_intrman.o ../libkernel/iop_sysmem.o + +dmacman: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/DMACMAN + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/dmacman/dmacman.c b/fps2bios/kernel/iopload/dmacman/dmacman.c index db60e3acfe..4cd46ea1d1 100644 --- a/fps2bios/kernel/iopload/dmacman/dmacman.c +++ b/fps2bios/kernel/iopload/dmacman/dmacman.c @@ -1,923 +1,923 @@ -//[module] DMACMAN -//[processor] IOP -//[type] ELF-IRX -//[name] dmacman -//[version] 0x101 -//[memory map] 0xBF801080,0xBF801084,0xBF801088, 00 mdec in -// 0xBF801090,0xBF801094,0xBF801098, 01 mdec out -// 0xBF8010A0,0xBF8010A4,0xBF8010A8, 02 gpu -// 0xBF8010B0,0xBF8010B4,0xBF8010B8, 03 cdrom/dvd -// 0xBF8010C0,0xBF8010C4,0xBF8010C8, 0xBF8010CC, 04 spu -// 0xBF8010D0,0xBF8010D4,0xBF8010D8, 05 pio -// 0xBF8010E0,0xBF8010E4,0xBF8010E8, 06 gpu otc -// -// 0xBF8010F0,0xBF8010F4, -// -// 0xBF801500,0xBF801504,0xBF801508, 07 SPU2 -// 0xBF801510,0xBF801514,0xBF801518, 08 -// 0xBF801520,0xBF801524,0xBF801528, 0xBF80152C, 09 SIF0 -// 0xBF801530,0xBF801534,0xBF801538, 10 SIF1 -// 0xBF801540,0xBF801544,0xBF801548, 11 SIO2in -// 0xBF801550,0xBF801554,0xBF801558, 12 SIO2out -// -// 0xBF801560,0xBF801564,0xBF801568, //sifman -// sif0 sif1 spu -// -// 0xBF801570, 0xBF801574,0xBF801578,0xBF80157C, //sifman -// 0xBF8015F0 -//[handlers] - -//[entry point] dmacman_start, dmacman_stub -//[made by] [RO]man (roman_ps2dev@hotmail.com) - -#include - -#include "kloadcore.h" -#include "kintrman.h" -#include "kdmacman.h" - - -int _start(int argc, char* argv[]); - -/////////////////////////////////////////////////////////////////////// -void _setBF801080(unsigned int ch, int value){ - *(int*)0xBF801080=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801090(unsigned int ch, int value){ - *(int*)0xBF801090=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF8010A0(unsigned int ch, int value){ - *(int*)0xBF8010A0=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF8010B0(unsigned int ch, int value){ - *(int*)0xBF8010B0=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF8010C0(unsigned int ch, int value){ - *(int*)0xBF8010C0=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF8010D0(unsigned int ch, int value){ - *(int*)0xBF8010D0=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF8010E0(unsigned int ch, int value){ - *(int*)0xBF8010E0=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801500(unsigned int ch, int value){ - *(int*)0xBF801500=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801510(unsigned int ch, int value){ - *(int*)0xBF801510=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801520(unsigned int ch, int value){ - *(int*)0xBF801520=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801530(unsigned int ch, int value){ - *(int*)0xBF801530=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801540(unsigned int ch, int value){ - *(int*)0xBF801540=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801550(unsigned int ch, int value){ - *(int*)0xBF801550=value; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801080(unsigned int ch){ - return *(int*)0xBF801080; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801090(unsigned int ch){ - return *(int*)0xBF801090; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF8010A0(unsigned int ch){ - return *(int*)0xBF8010A0; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF8010B0(unsigned int ch){ - return *(int*)0xBF8010B0; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF8010C0(unsigned int ch){ - return *(int*)0xBF8010C0; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF8010D0(unsigned int ch){ - return *(int*)0xBF8010D0; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF8010E0(unsigned int ch){ - return *(int*)0xBF8010E0; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801500(unsigned int ch){ - return *(int*)0xBF801500; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801510(unsigned int ch){ - return *(int*)0xBF801510; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801520(unsigned int ch){ - return *(int*)0xBF801520; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801530(unsigned int ch){ - return *(int*)0xBF801530; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801540(unsigned int ch){ - return *(int*)0xBF801540; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801550(unsigned int ch){ - return *(int*)0xBF801550; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801084(unsigned int ch, int value){ - *(int*)0xBF801084=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801094(unsigned int ch, int value){ - *(int*)0xBF801094=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF8010A4(unsigned int ch, int value){ - *(int*)0xBF8010A4=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF8010B4(unsigned int ch, int value){ - *(int*)0xBF8010B4=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF8010C4(unsigned int ch, int value){ - *(int*)0xBF8010C4=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF8010D4(unsigned int ch, int value){ - *(int*)0xBF8010D4=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF8010E4(unsigned int ch, int value){ - *(int*)0xBF8010E4=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801504(unsigned int ch, int value){ - *(int*)0xBF801504=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801514(unsigned int ch, int value){ - *(int*)0xBF801514=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801524(unsigned int ch, int value){ - *(int*)0xBF801524=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801534(unsigned int ch, int value){ - *(int*)0xBF801534=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801544(unsigned int ch, int value){ - *(int*)0xBF801544=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801554(unsigned int ch, int value){ - *(int*)0xBF801554=value; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801084(unsigned int ch){ - return *(int*)0xBF801084; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801094(unsigned int ch){ - return *(int*)0xBF801094; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF8010A4(unsigned int ch){ - return *(int*)0xBF8010A4; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF8010B4(unsigned int ch){ - return *(int*)0xBF8010B4; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF8010C4(unsigned int ch){ - return *(int*)0xBF8010C4; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF8010D4(unsigned int ch){ - return *(int*)0xBF8010D4; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF8010E4(unsigned int ch){ - return *(int*)0xBF8010E4; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801504(unsigned int ch){ - return *(int*)0xBF801504; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801514(unsigned int ch){ - return *(int*)0xBF801514; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801524(unsigned int ch){ - return *(int*)0xBF801524; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801534(unsigned int ch){ - return *(int*)0xBF801534; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801544(unsigned int ch){ - return *(int*)0xBF801544; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801554(unsigned int ch){ - return *(int*)0xBF801554; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801088(unsigned int ch, int value){ - *(int*)0xBF801088=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801098(unsigned int ch, int value){ - *(int*)0xBF801098=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF8010A8(unsigned int ch, int value){ - *(int*)0xBF8010A8=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF8010B8(unsigned int ch, int value){ - *(int*)0xBF8010B8=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF8010C8(unsigned int ch, int value){ - *(int*)0xBF8010C8=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF8010D8(unsigned int ch, int value){ - *(int*)0xBF8010D8=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF8010E8(unsigned int ch, int value){ - *(int*)0xBF8010E8=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801508(unsigned int ch, int value){ - *(int*)0xBF801508=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801518(unsigned int ch, int value){ - *(int*)0xBF801518=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801528(unsigned int ch, int value){ - *(int*)0xBF801528=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801538(unsigned int ch, int value){ - *(int*)0xBF801538=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801548(unsigned int ch, int value){ - *(int*)0xBF801548=value; -} - -/////////////////////////////////////////////////////////////////////// -void _setBF801558(unsigned int ch, int value){ - *(int*)0xBF801558=value; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801088(unsigned int ch){ - return *(int*)0xBF801088; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801098(unsigned int ch){ - return *(int*)0xBF801098; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF8010A8(unsigned int ch){ - return *(int*)0xBF8010A8; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF8010B8(unsigned int ch){ - return *(int*)0xBF8010B8; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF8010C8(unsigned int ch){ - return *(int*)0xBF8010C8; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF8010D8(unsigned int ch){ - return *(int*)0xBF8010D8; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF8010E8(unsigned int ch){ - return *(int*)0xBF8010E8; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801508(unsigned int ch){ - return *(int*)0xBF801508; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801518(unsigned int ch){ - return *(int*)0xBF801518; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801528(unsigned int ch){ - return *(int*)0xBF801528; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801538(unsigned int ch){ - return *(int*)0xBF801538; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801548(unsigned int ch){ - return *(int*)0xBF801548; -} - -/////////////////////////////////////////////////////////////////////// -int _getBF801558(unsigned int ch){ - return *(int*)0xBF801558; -} - -/////////////////////////////////////////////////////////////////////// -void dmacSetD_TADR(unsigned int ch, int value){ - if (ch==DMAch_SPU) - *(int*)0xBF8010CC=value; else - if (ch==DMAch_SIF0) - *(int*)0xBF80152C=value; -} - -/////////////////////////////////////////////////////////////////////// -int dmacGetD_TADR(unsigned int ch){ - if (ch==DMAch_SPU) - return *(int*)0xBF8010CC; - if (ch==DMAch_SIF0) - return *(int*)0xBF80152C; - return 0; -} - -/////////////////////////////////////////////////////////////////////// -void dmacSet_4_9_A(unsigned int ch, int value){ - if (ch==DMAch_SPU) - *(int*)0xBF801568=value; else - if (ch==DMAch_SIF0) - *(int*)0xBF801560=value; else - if (ch==DMAch_SIF1) - *(int*)0xBF801564=value; -} - -/////////////////////////////////////////////////////////////////////// -int dmacGet_4_9_A(unsigned int ch){ - if (ch==DMAch_SPU) - return *(int*)0xBF801568; - if (ch==DMAch_SIF0) - return *(int*)0xBF801560; - if (ch==DMAch_SIF1) - return *(int*)0xBF801564; - return 0; -} - -/////////////////////////////////////////////////////////////////////// -void dmacSetDPCR(int value){ - *(int*)0xBF8010F0=value; -} - -/////////////////////////////////////////////////////////////////////// -int dmacGetDPCR(){ - return *(int*)0xBF8010F0; -} - -/////////////////////////////////////////////////////////////////////// -void dmacSetDPCR2(int value){ - *(int*)0xBF801570=value; -} - -/////////////////////////////////////////////////////////////////////// -int dmacGetDPCR2(){ - return *(int*)0xBF801570; -} - -/////////////////////////////////////////////////////////////////////// -void dmacSetDPCR3(int value){ - *(int*)0xBF8015F0=value; -} - -/////////////////////////////////////////////////////////////////////// -int dmacGetDPCR3(){ - return *(int*)0xBF8015F0; -} - -/////////////////////////////////////////////////////////////////////// -void dmacSetDICR(int value){ - *(int*)0xBF8010F4=value; -} - -/////////////////////////////////////////////////////////////////////// -int dmacGetDICR(){ - return *(int*)0xBF8010F4; -} - -/////////////////////////////////////////////////////////////////////// -void dmacSetDICR2(int value){ - *(int*)0xBF801574=value; -} - -/////////////////////////////////////////////////////////////////////// -int dmacGetDICR2(){ - return *(int*)0xBF801574; -} - -/////////////////////////////////////////////////////////////////////// -void dmacSetBF80157C(int value){ - *(int*)0xBF80157C=value; -} - -/////////////////////////////////////////////////////////////////////// -int dmacGetBF80157C(){ - return *(int*)0xBF80157C; -} - -/////////////////////////////////////////////////////////////////////// -void dmacSetBF801578(int value){ - *(int*)0xBF801578=value; -} - -/////////////////////////////////////////////////////////////////////// -int dmacGetBF801578(){ - return *(int*)0xBF801578; -} - -func setD_MADR[]={ - (func)_setBF801080, (func)_setBF801090, (func)_setBF8010A0, (func)_setBF8010B0, - (func)_setBF8010C0, (func)_setBF8010D0, (func)_setBF8010E0, - (func)_setBF801500, (func)_setBF801510, (func)_setBF801520, - (func)_setBF801530, (func)_setBF801540, (func)_setBF801550, 0 -}; - -func getD_MADR[]={ - (func)_getBF801080, (func)_getBF801090, (func)_getBF8010A0, (func)_getBF8010B0, - (func)_getBF8010C0, (func)_getBF8010D0, (func)_getBF8010E0, - (func)_getBF801500, (func)_getBF801510, (func)_getBF801520, - (func)_getBF801530, (func)_getBF801540, (func)_getBF801550, 0 -}; - -func setD_BCR[]={ - (func)_setBF801084, (func)_setBF801094, (func)_setBF8010A4, (func)_setBF8010B4, - (func)_setBF8010C4, (func)_setBF8010D4, (func)_setBF8010E4, - (func)_setBF801504, (func)_setBF801514, (func)_setBF801524, - (func)_setBF801534, (func)_setBF801544, (func)_setBF801554, 0 -}; - -func getD_BCR[]={ - (func)_getBF801084, (func)_getBF801094, (func)_getBF8010A4, (func)_getBF8010B4, - (func)_getBF8010C4, (func)_getBF8010D4, (func)_getBF8010E4, - (func)_getBF801504, (func)_getBF801514, (func)_getBF801524, - (func)_getBF801534, (func)_getBF801544, (func)_getBF801554, 0 -}; - -func setD_CHCR[]={ - (func)_setBF801088, (func)_setBF801098, (func)_setBF8010A8, (func)_setBF8010B8, - (func)_setBF8010C8, (func)_setBF8010D8, (func)_setBF8010E8, - (func)_setBF801508, (func)_setBF801518, (func)_setBF801528, - (func)_setBF801538, (func)_setBF801548, (func)_setBF801558, 0 -}; - -func getD_CHCR[]={ - (func)_getBF801088, (func)_getBF801098, (func)_getBF8010A8, (func)_getBF8010B8, - (func)_getBF8010C8, (func)_getBF8010D8, (func)_getBF8010E8, - (func)_getBF801508, (func)_getBF801518, (func)_getBF801528, - (func)_getBF801538, (func)_getBF801548, (func)_getBF801558, 0 -}; - -/////////////////////////////////////////////////////////////////////// -void dmacSetD_MADR(unsigned int ch, int value){ - if (ch<13) - setD_MADR[ch](ch, value); //function call -} - -/////////////////////////////////////////////////////////////////////// -int dmacGetD_MADR(unsigned int ch){ - if (ch<13) - return getD_MADR[ch](ch); //function call - return 0; -} - -/////////////////////////////////////////////////////////////////////// -void dmacSetD_BCR(unsigned int ch, int value){ - if (ch<13) - setD_BCR[ch](ch, value); //function call -} - -/////////////////////////////////////////////////////////////////////// -int dmacGetD_BCR(unsigned int ch){ - if (ch<13) - return getD_BCR[ch](ch); //function call - return 0; -} - -/////////////////////////////////////////////////////////////////////// -void dmacSetD_CHCR(unsigned int ch, int value){ - if (ch<13) - setD_CHCR[ch](ch, value); //function call -} - -/////////////////////////////////////////////////////////////////////// -int dmacGetD_CHCR(unsigned int ch){ - if (ch<13) - return getD_CHCR[ch](ch); //function call - return 0; -} - - - - -/////////////////////////////////////////////////////////////////////// -int dmacDeinit(){ - int x; - register int ch, value; - - CpuSuspendIntr(&x); //intrman - - dmacSetBF801578(0); - for (ch=0; ch<13; ch++){ - value=dmacGetD_CHCR(ch); - if (value & DMAf_TR) //sysmem - Kprintf("WARNING:DMA %dch has been continued until shutdown\n", ch); - dmacSetD_CHCR(ch, value & 0xFEFFFFFF); - } - - CpuResumeIntr(x); //intrman - return 1; -} - -/////////////////////////////////////////////////////////////////////// -int dmacSetDMA(int ch, int address, int size, int count, int dir){ - if (ch<13 && ch != DMAch_GPUotc){ - dmacSetD_MADR(ch, 0x00FFFFFF & address); - dmacSetD_BCR (ch, (count << 16) | (size & 0xFFFF)); - dmacSetD_CHCR(ch, (dir & DMAf_DR) | DMAf_CO | - (dir == 0 ? DMAf_30 : 0)); - return 1; - } - return 0; -} - -/////////////////////////////////////////////////////////////////////// -int dmacSetDMA_chainedSPU_SIF0(int ch, int size, int tadr){ - if (ch != DMAch_SPU && ch != DMAch_SIF0) - return 0; - dmacSetD_BCR (ch, size & 0x0000FFFF); - dmacSetD_CHCR(ch, DMAf_LI | DMAf_CO | DMAf_DR); //0x601 - dmacSetD_TADR (ch, tadr & 0x00FFFFFF); - return 1; -} - -/////////////////////////////////////////////////////////////////////// -int dmacSetDMA_SIF0(int ch, int size, int tadr){ - if (ch != DMAch_SIF0) - return 0; - dmacSetD_BCR ( DMAch_SIF0, size & 0x0000FFFF); - dmacSetD_CHCR( DMAch_SIF0, DMAf_LI | DMAf_CO | DMAf_08 | DMAf_DR); //0x701 - dmacSetD_TADR ( DMAch_SIF0, tadr & 0x00FFFFFF); - return 1; -} - -/////////////////////////////////////////////////////////////////////// -int dmacSetDMA_SIF1(int ch, int size){ - if (ch != DMAch_SIF1) - return 0; - dmacSetD_BCR (DMAch_SIF1, size & 0x0000FFFF); - dmacSetD_CHCR(DMAch_SIF1, DMAf_30 | DMAf_CO | DMAf_08); //0x40000300 - return 1; -} - -/////////////////////////////////////////////////////////////////////// -void dmacStartTransfer(int ch){ - if (ch < 15) - dmacSetD_CHCR(ch, DMAf_TR | dmacGetD_CHCR(ch)); -} - -/////////////////////////////////////////////////////////////////////// -// set 3-bit value of channel -void dmacSetVal(int ch, int value){ - int x; - CpuSuspendIntr(&x); //intrman - - switch (ch){ - case DMAch_MDECin: dmacSetDPCR( - (dmacGetDPCR() & 0xFFFFFFF8) | - ( value & 7)); break; - case DMAch_MDECout:dmacSetDPCR( - (dmacGetDPCR() & 0xFFFFFF8F) | - (( value & 7) << 4)); break; - case DMAch_GPU: dmacSetDPCR( - (dmacGetDPCR() & 0xFFFFF8FF) | - (( value & 7) << 8)); break; - case DMAch_CD: dmacSetDPCR( - (dmacGetDPCR() & 0xFFFF8FFF) | - (( value & 7) << 12)); break; - case DMAch_SPU: dmacSetDPCR( - (dmacGetDPCR() & 0xFFF8FFFF) | - (( value & 7) << 16)); break; - case DMAch_PIO: dmacSetDPCR( - (dmacGetDPCR() & 0xFF8FFFFF) | - (( value & 7) << 20)); break; - case DMAch_GPUotc:dmacSetDPCR( - (dmacGetDPCR() & 0xF8FFFFFF) | - (( value & 7) << 24)); break; - case DMAch_SPU2:dmacSetDPCR2( - (dmacGetDPCR2() & 0xFFFFFFF8) | - ( value & 7)); break; - case DMAch_8: dmacSetDPCR2( - (dmacGetDPCR2() & 0xFFFFFF8F) | - (( value & 7) << 4)); break; - case DMAch_SIF0: dmacSetDPCR2( - (dmacGetDPCR2() & 0xFFFFF8FF) | - (( value & 7) << 8)); break; - case DMAch_SIF1: dmacSetDPCR2( - (dmacGetDPCR2() & 0xFFFF8FFF) | - (( value & 7) << 12)); break; - case DMAch_SIO2in: dmacSetDPCR2( - (dmacGetDPCR2() & 0xFFF8FFFF) | - (( value & 7) << 16)); break; - case DMAch_SIO2out:dmacSetDPCR2( - (dmacGetDPCR2() & 0xFF8FFFFF) | - (( value & 7) << 20)); break; - case DMAch_13: dmacSetDPCR3( - (dmacGetDPCR3() & 0xFFFFFFF8) | - ( value & 7)); break; - case DMAch_14: dmacSetDPCR3( - (dmacGetDPCR3() & 0xFFFFFF8F) | - (( value & 7) << 4)); break; - case DMAch_15: dmacSetDPCR3( - (dmacGetDPCR3() & 0xFFFFF8FF) | - (( value & 7) << 8)); break; - case DMAch_67: dmacSetDPCR( - (dmacGetDPCR() & 0x8FFFFFFF) | - (( value & 7) << 28)); break; - case DMAch_85: dmacSetDPCR2( - (dmacGetDPCR2() & 0xF8FFFFFF) | - (( value & 7) << 24)); break; - } - - CpuResumeIntr(x); //intrman -} - -/////////////////////////////////////////////////////////////////////// -// set 4th bit of channel -void dmacEnableDMAch(int ch){ - int x; - CpuSuspendIntr(&x); //intrman - - switch (ch){ - case DMAch_MDECin: dmacSetDPCR( - (dmacGetDPCR() | 0x00000008)); break; - case DMAch_MDECout:dmacSetDPCR( - (dmacGetDPCR() | 0x00000080)); break; - case DMAch_GPU: dmacSetDPCR( - (dmacGetDPCR() | 0x00000800)); break; - case DMAch_CD: dmacSetDPCR( - (dmacGetDPCR() | 0x00008000)); break; - case DMAch_SPU: dmacSetDPCR( - (dmacGetDPCR() | 0x00080000)); break; - case DMAch_PIO: dmacSetDPCR( - (dmacGetDPCR() | 0x00800000)); break; - case DMAch_GPUotc:dmacSetDPCR( - (dmacGetDPCR() | 0x08000000)); break; - case DMAch_SPU2: dmacSetDPCR2( - (dmacGetDPCR2() | 0x00000008)); break; - case DMAch_8: dmacSetDPCR2( - (dmacGetDPCR2() | 0x00000080)); break; - case DMAch_SIF0: dmacSetDPCR2( - (dmacGetDPCR2() | 0x00000800)); break; - case DMAch_SIF1: dmacSetDPCR2( - (dmacGetDPCR2() | 0x00008000)); break; - case DMAch_SIO2in:dmacSetDPCR2( - (dmacGetDPCR2() | 0x00080000)); break; - case DMAch_SIO2out:dmacSetDPCR2( - (dmacGetDPCR2() | 0x00800000)); break; - case DMAch_13: dmacSetDPCR3( - (dmacGetDPCR3() | 0x00000008)); break; - case DMAch_14: dmacSetDPCR3( - (dmacGetDPCR3() | 0x00000080)); break; - case DMAch_15: dmacSetDPCR3( - (dmacGetDPCR3() | 0x00000800)); break; - case DMAch_85: dmacSetDPCR2( - (dmacGetDPCR2() | 0x08000000)); break; - } - - CpuResumeIntr(x); //intrman -} - -/////////////////////////////////////////////////////////////////////// -// reset 4th bit of channel -void dmacDisableDMAch(int ch){ - int x; - CpuSuspendIntr(&x); //intrman - - switch (ch){ - case DMAch_MDECin: dmacSetDPCR( - (dmacGetDPCR() & 0xFFFFFFF7)); break; - case DMAch_MDECout:dmacSetDPCR( - (dmacGetDPCR() & 0xFFFFFF7F)); break; - case DMAch_GPU: dmacSetDPCR( - (dmacGetDPCR() & 0xFFFFF7FF)); break; - case DMAch_CD: dmacSetDPCR( - (dmacGetDPCR() & 0xFFFF7FFF)); break; - case DMAch_SPU: dmacSetDPCR( - (dmacGetDPCR() & 0xFFF7FFFF)); break; - case DMAch_PIO: dmacSetDPCR( - (dmacGetDPCR() & 0xFF7FFFFF)); break; - case DMAch_GPUotc:dmacSetDPCR( - (dmacGetDPCR() & 0xF7FFFFFF)); break; - case DMAch_SPU2: dmacSetDPCR2( - (dmacGetDPCR2() & 0xFFFFFFF7)); break; - case DMAch_8: dmacSetDPCR2( - (dmacGetDPCR2() & 0xFFFFFF7F)); break; - case DMAch_SIF0: dmacSetDPCR2( - (dmacGetDPCR2() & 0xFFFFF7FF)); break; - case DMAch_SIF1: dmacSetDPCR2( - (dmacGetDPCR2() & 0xFFFF7FFF)); break; - case DMAch_SIO2in:dmacSetDPCR2( - (dmacGetDPCR2() & 0xFFF7FFFF)); break; - case DMAch_SIO2out:dmacSetDPCR2( - (dmacGetDPCR2() & 0xFF7FFFFF)); break; - case DMAch_13: dmacSetDPCR3( - (dmacGetDPCR3() & 0xFFFFFFF7)); break; - case DMAch_14: dmacSetDPCR3( - (dmacGetDPCR3() & 0xFFFFFF7F)); break; - case DMAch_15: dmacSetDPCR3( - (dmacGetDPCR3() & 0xFFFFF7FF)); break; - case DMAch_85: dmacSetDPCR2( - (dmacGetDPCR2() & 0xF7FFFFFF)); break; - } - - CpuResumeIntr(x); //intrman -} - -void _retonly(){} - -//////////////////////////////entrypoint/////////////////////////////// -struct export dmacman_stub={ - 0x41C00000, - 0, - VER(1, 2), // 1.2 => 0x102 - 0, - "dmacman", - (func)_start, // entrypoint - (func)_retonly, - (func)dmacDeinit, - (func)_retonly, - (func)dmacSetD_MADR, - (func)dmacGetD_MADR, - (func)dmacSetD_BCR, - (func)dmacGetD_BCR, - (func)dmacSetD_CHCR, - (func)dmacGetD_CHCR, - (func)dmacSetD_TADR, - (func)dmacGetD_TADR, - (func)dmacSet_4_9_A, - (func)dmacGet_4_9_A, - (func)dmacSetDPCR, - (func)dmacGetDPCR, - (func)dmacSetDPCR2, - (func)dmacGetDPCR2, - (func)dmacSetDPCR3, - (func)dmacGetDPCR3, - (func)dmacSetDICR, - (func)dmacGetDICR, - (func)dmacSetDICR2, - (func)dmacGetDICR2, - (func)dmacSetBF80157C, - (func)dmacGetBF80157C, - (func)dmacSetBF801578, - (func)dmacGetBF801578, - (func)dmacSetDMA, - (func)dmacSetDMA_chainedSPU_SIF0, - (func)dmacSetDMA_SIF0, - (func)dmacSetDMA_SIF1, - (func)dmacStartTransfer, - (func)dmacSetVal, - (func)dmacEnableDMAch, - (func)dmacDisableDMAch, - 0 -}; - -//////////////////////////////entrypoint/////////////////////////////// -int _start(int argc, char* argv[]){ - int x; - register int ch; - - if (RegisterLibraryEntries(&dmacman_stub)) //loadcore - return 1; - - CpuSuspendIntr(&x); //intrman - - dmacSetDPCR(0x07777777); - dmacSetDPCR2(0x07777777); - dmacSetDPCR3(0x00000777); - for (ch=0; ch<13; ch++){ - dmacSetD_MADR(ch, 0); - dmacSetD_BCR (ch, 0); - dmacSetD_CHCR(ch, 0); - } - dmacSetD_TADR( DMAch_SPU, 0); - dmacSetD_TADR( DMAch_SIF0,0); - dmacSet_4_9_A( DMAch_SPU, 0); - dmacSet_4_9_A( DMAch_SIF0,0); - dmacSet_4_9_A( DMAch_SIF1,0); - dmacSetBF801578(1); - - CpuResumeIntr(x); //intrman - return 0; -} - +//[module] DMACMAN +//[processor] IOP +//[type] ELF-IRX +//[name] dmacman +//[version] 0x101 +//[memory map] 0xBF801080,0xBF801084,0xBF801088, 00 mdec in +// 0xBF801090,0xBF801094,0xBF801098, 01 mdec out +// 0xBF8010A0,0xBF8010A4,0xBF8010A8, 02 gpu +// 0xBF8010B0,0xBF8010B4,0xBF8010B8, 03 cdrom/dvd +// 0xBF8010C0,0xBF8010C4,0xBF8010C8, 0xBF8010CC, 04 spu +// 0xBF8010D0,0xBF8010D4,0xBF8010D8, 05 pio +// 0xBF8010E0,0xBF8010E4,0xBF8010E8, 06 gpu otc +// +// 0xBF8010F0,0xBF8010F4, +// +// 0xBF801500,0xBF801504,0xBF801508, 07 SPU2 +// 0xBF801510,0xBF801514,0xBF801518, 08 +// 0xBF801520,0xBF801524,0xBF801528, 0xBF80152C, 09 SIF0 +// 0xBF801530,0xBF801534,0xBF801538, 10 SIF1 +// 0xBF801540,0xBF801544,0xBF801548, 11 SIO2in +// 0xBF801550,0xBF801554,0xBF801558, 12 SIO2out +// +// 0xBF801560,0xBF801564,0xBF801568, //sifman +// sif0 sif1 spu +// +// 0xBF801570, 0xBF801574,0xBF801578,0xBF80157C, //sifman +// 0xBF8015F0 +//[handlers] - +//[entry point] dmacman_start, dmacman_stub +//[made by] [RO]man (roman_ps2dev@hotmail.com) + +#include + +#include "kloadcore.h" +#include "kintrman.h" +#include "kdmacman.h" + + +int _start(int argc, char* argv[]); + +/////////////////////////////////////////////////////////////////////// +void _setBF801080(unsigned int ch, int value){ + *(int*)0xBF801080=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801090(unsigned int ch, int value){ + *(int*)0xBF801090=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010A0(unsigned int ch, int value){ + *(int*)0xBF8010A0=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010B0(unsigned int ch, int value){ + *(int*)0xBF8010B0=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010C0(unsigned int ch, int value){ + *(int*)0xBF8010C0=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010D0(unsigned int ch, int value){ + *(int*)0xBF8010D0=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010E0(unsigned int ch, int value){ + *(int*)0xBF8010E0=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801500(unsigned int ch, int value){ + *(int*)0xBF801500=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801510(unsigned int ch, int value){ + *(int*)0xBF801510=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801520(unsigned int ch, int value){ + *(int*)0xBF801520=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801530(unsigned int ch, int value){ + *(int*)0xBF801530=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801540(unsigned int ch, int value){ + *(int*)0xBF801540=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801550(unsigned int ch, int value){ + *(int*)0xBF801550=value; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801080(unsigned int ch){ + return *(int*)0xBF801080; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801090(unsigned int ch){ + return *(int*)0xBF801090; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010A0(unsigned int ch){ + return *(int*)0xBF8010A0; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010B0(unsigned int ch){ + return *(int*)0xBF8010B0; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010C0(unsigned int ch){ + return *(int*)0xBF8010C0; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010D0(unsigned int ch){ + return *(int*)0xBF8010D0; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010E0(unsigned int ch){ + return *(int*)0xBF8010E0; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801500(unsigned int ch){ + return *(int*)0xBF801500; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801510(unsigned int ch){ + return *(int*)0xBF801510; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801520(unsigned int ch){ + return *(int*)0xBF801520; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801530(unsigned int ch){ + return *(int*)0xBF801530; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801540(unsigned int ch){ + return *(int*)0xBF801540; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801550(unsigned int ch){ + return *(int*)0xBF801550; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801084(unsigned int ch, int value){ + *(int*)0xBF801084=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801094(unsigned int ch, int value){ + *(int*)0xBF801094=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010A4(unsigned int ch, int value){ + *(int*)0xBF8010A4=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010B4(unsigned int ch, int value){ + *(int*)0xBF8010B4=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010C4(unsigned int ch, int value){ + *(int*)0xBF8010C4=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010D4(unsigned int ch, int value){ + *(int*)0xBF8010D4=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010E4(unsigned int ch, int value){ + *(int*)0xBF8010E4=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801504(unsigned int ch, int value){ + *(int*)0xBF801504=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801514(unsigned int ch, int value){ + *(int*)0xBF801514=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801524(unsigned int ch, int value){ + *(int*)0xBF801524=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801534(unsigned int ch, int value){ + *(int*)0xBF801534=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801544(unsigned int ch, int value){ + *(int*)0xBF801544=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801554(unsigned int ch, int value){ + *(int*)0xBF801554=value; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801084(unsigned int ch){ + return *(int*)0xBF801084; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801094(unsigned int ch){ + return *(int*)0xBF801094; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010A4(unsigned int ch){ + return *(int*)0xBF8010A4; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010B4(unsigned int ch){ + return *(int*)0xBF8010B4; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010C4(unsigned int ch){ + return *(int*)0xBF8010C4; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010D4(unsigned int ch){ + return *(int*)0xBF8010D4; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010E4(unsigned int ch){ + return *(int*)0xBF8010E4; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801504(unsigned int ch){ + return *(int*)0xBF801504; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801514(unsigned int ch){ + return *(int*)0xBF801514; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801524(unsigned int ch){ + return *(int*)0xBF801524; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801534(unsigned int ch){ + return *(int*)0xBF801534; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801544(unsigned int ch){ + return *(int*)0xBF801544; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801554(unsigned int ch){ + return *(int*)0xBF801554; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801088(unsigned int ch, int value){ + *(int*)0xBF801088=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801098(unsigned int ch, int value){ + *(int*)0xBF801098=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010A8(unsigned int ch, int value){ + *(int*)0xBF8010A8=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010B8(unsigned int ch, int value){ + *(int*)0xBF8010B8=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010C8(unsigned int ch, int value){ + *(int*)0xBF8010C8=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010D8(unsigned int ch, int value){ + *(int*)0xBF8010D8=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF8010E8(unsigned int ch, int value){ + *(int*)0xBF8010E8=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801508(unsigned int ch, int value){ + *(int*)0xBF801508=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801518(unsigned int ch, int value){ + *(int*)0xBF801518=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801528(unsigned int ch, int value){ + *(int*)0xBF801528=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801538(unsigned int ch, int value){ + *(int*)0xBF801538=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801548(unsigned int ch, int value){ + *(int*)0xBF801548=value; +} + +/////////////////////////////////////////////////////////////////////// +void _setBF801558(unsigned int ch, int value){ + *(int*)0xBF801558=value; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801088(unsigned int ch){ + return *(int*)0xBF801088; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801098(unsigned int ch){ + return *(int*)0xBF801098; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010A8(unsigned int ch){ + return *(int*)0xBF8010A8; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010B8(unsigned int ch){ + return *(int*)0xBF8010B8; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010C8(unsigned int ch){ + return *(int*)0xBF8010C8; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010D8(unsigned int ch){ + return *(int*)0xBF8010D8; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF8010E8(unsigned int ch){ + return *(int*)0xBF8010E8; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801508(unsigned int ch){ + return *(int*)0xBF801508; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801518(unsigned int ch){ + return *(int*)0xBF801518; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801528(unsigned int ch){ + return *(int*)0xBF801528; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801538(unsigned int ch){ + return *(int*)0xBF801538; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801548(unsigned int ch){ + return *(int*)0xBF801548; +} + +/////////////////////////////////////////////////////////////////////// +int _getBF801558(unsigned int ch){ + return *(int*)0xBF801558; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetD_TADR(unsigned int ch, int value){ + if (ch==DMAch_SPU) + *(int*)0xBF8010CC=value; else + if (ch==DMAch_SIF0) + *(int*)0xBF80152C=value; +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetD_TADR(unsigned int ch){ + if (ch==DMAch_SPU) + return *(int*)0xBF8010CC; + if (ch==DMAch_SIF0) + return *(int*)0xBF80152C; + return 0; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSet_4_9_A(unsigned int ch, int value){ + if (ch==DMAch_SPU) + *(int*)0xBF801568=value; else + if (ch==DMAch_SIF0) + *(int*)0xBF801560=value; else + if (ch==DMAch_SIF1) + *(int*)0xBF801564=value; +} + +/////////////////////////////////////////////////////////////////////// +int dmacGet_4_9_A(unsigned int ch){ + if (ch==DMAch_SPU) + return *(int*)0xBF801568; + if (ch==DMAch_SIF0) + return *(int*)0xBF801560; + if (ch==DMAch_SIF1) + return *(int*)0xBF801564; + return 0; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetDPCR(int value){ + *(int*)0xBF8010F0=value; +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetDPCR(){ + return *(int*)0xBF8010F0; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetDPCR2(int value){ + *(int*)0xBF801570=value; +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetDPCR2(){ + return *(int*)0xBF801570; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetDPCR3(int value){ + *(int*)0xBF8015F0=value; +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetDPCR3(){ + return *(int*)0xBF8015F0; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetDICR(int value){ + *(int*)0xBF8010F4=value; +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetDICR(){ + return *(int*)0xBF8010F4; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetDICR2(int value){ + *(int*)0xBF801574=value; +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetDICR2(){ + return *(int*)0xBF801574; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetBF80157C(int value){ + *(int*)0xBF80157C=value; +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetBF80157C(){ + return *(int*)0xBF80157C; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetBF801578(int value){ + *(int*)0xBF801578=value; +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetBF801578(){ + return *(int*)0xBF801578; +} + +func setD_MADR[]={ + (func)_setBF801080, (func)_setBF801090, (func)_setBF8010A0, (func)_setBF8010B0, + (func)_setBF8010C0, (func)_setBF8010D0, (func)_setBF8010E0, + (func)_setBF801500, (func)_setBF801510, (func)_setBF801520, + (func)_setBF801530, (func)_setBF801540, (func)_setBF801550, 0 +}; + +func getD_MADR[]={ + (func)_getBF801080, (func)_getBF801090, (func)_getBF8010A0, (func)_getBF8010B0, + (func)_getBF8010C0, (func)_getBF8010D0, (func)_getBF8010E0, + (func)_getBF801500, (func)_getBF801510, (func)_getBF801520, + (func)_getBF801530, (func)_getBF801540, (func)_getBF801550, 0 +}; + +func setD_BCR[]={ + (func)_setBF801084, (func)_setBF801094, (func)_setBF8010A4, (func)_setBF8010B4, + (func)_setBF8010C4, (func)_setBF8010D4, (func)_setBF8010E4, + (func)_setBF801504, (func)_setBF801514, (func)_setBF801524, + (func)_setBF801534, (func)_setBF801544, (func)_setBF801554, 0 +}; + +func getD_BCR[]={ + (func)_getBF801084, (func)_getBF801094, (func)_getBF8010A4, (func)_getBF8010B4, + (func)_getBF8010C4, (func)_getBF8010D4, (func)_getBF8010E4, + (func)_getBF801504, (func)_getBF801514, (func)_getBF801524, + (func)_getBF801534, (func)_getBF801544, (func)_getBF801554, 0 +}; + +func setD_CHCR[]={ + (func)_setBF801088, (func)_setBF801098, (func)_setBF8010A8, (func)_setBF8010B8, + (func)_setBF8010C8, (func)_setBF8010D8, (func)_setBF8010E8, + (func)_setBF801508, (func)_setBF801518, (func)_setBF801528, + (func)_setBF801538, (func)_setBF801548, (func)_setBF801558, 0 +}; + +func getD_CHCR[]={ + (func)_getBF801088, (func)_getBF801098, (func)_getBF8010A8, (func)_getBF8010B8, + (func)_getBF8010C8, (func)_getBF8010D8, (func)_getBF8010E8, + (func)_getBF801508, (func)_getBF801518, (func)_getBF801528, + (func)_getBF801538, (func)_getBF801548, (func)_getBF801558, 0 +}; + +/////////////////////////////////////////////////////////////////////// +void dmacSetD_MADR(unsigned int ch, int value){ + if (ch<13) + setD_MADR[ch](ch, value); //function call +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetD_MADR(unsigned int ch){ + if (ch<13) + return getD_MADR[ch](ch); //function call + return 0; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetD_BCR(unsigned int ch, int value){ + if (ch<13) + setD_BCR[ch](ch, value); //function call +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetD_BCR(unsigned int ch){ + if (ch<13) + return getD_BCR[ch](ch); //function call + return 0; +} + +/////////////////////////////////////////////////////////////////////// +void dmacSetD_CHCR(unsigned int ch, int value){ + if (ch<13) + setD_CHCR[ch](ch, value); //function call +} + +/////////////////////////////////////////////////////////////////////// +int dmacGetD_CHCR(unsigned int ch){ + if (ch<13) + return getD_CHCR[ch](ch); //function call + return 0; +} + + + + +/////////////////////////////////////////////////////////////////////// +int dmacDeinit(){ + int x; + register int ch, value; + + CpuSuspendIntr(&x); //intrman + + dmacSetBF801578(0); + for (ch=0; ch<13; ch++){ + value=dmacGetD_CHCR(ch); + if (value & DMAf_TR) //sysmem + Kprintf("WARNING:DMA %dch has been continued until shutdown\n", ch); + dmacSetD_CHCR(ch, value & 0xFEFFFFFF); + } + + CpuResumeIntr(x); //intrman + return 1; +} + +/////////////////////////////////////////////////////////////////////// +int dmacSetDMA(int ch, int address, int size, int count, int dir){ + if (ch<13 && ch != DMAch_GPUotc){ + dmacSetD_MADR(ch, 0x00FFFFFF & address); + dmacSetD_BCR (ch, (count << 16) | (size & 0xFFFF)); + dmacSetD_CHCR(ch, (dir & DMAf_DR) | DMAf_CO | + (dir == 0 ? DMAf_30 : 0)); + return 1; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int dmacSetDMA_chainedSPU_SIF0(int ch, int size, int tadr){ + if (ch != DMAch_SPU && ch != DMAch_SIF0) + return 0; + dmacSetD_BCR (ch, size & 0x0000FFFF); + dmacSetD_CHCR(ch, DMAf_LI | DMAf_CO | DMAf_DR); //0x601 + dmacSetD_TADR (ch, tadr & 0x00FFFFFF); + return 1; +} + +/////////////////////////////////////////////////////////////////////// +int dmacSetDMA_SIF0(int ch, int size, int tadr){ + if (ch != DMAch_SIF0) + return 0; + dmacSetD_BCR ( DMAch_SIF0, size & 0x0000FFFF); + dmacSetD_CHCR( DMAch_SIF0, DMAf_LI | DMAf_CO | DMAf_08 | DMAf_DR); //0x701 + dmacSetD_TADR ( DMAch_SIF0, tadr & 0x00FFFFFF); + return 1; +} + +/////////////////////////////////////////////////////////////////////// +int dmacSetDMA_SIF1(int ch, int size){ + if (ch != DMAch_SIF1) + return 0; + dmacSetD_BCR (DMAch_SIF1, size & 0x0000FFFF); + dmacSetD_CHCR(DMAch_SIF1, DMAf_30 | DMAf_CO | DMAf_08); //0x40000300 + return 1; +} + +/////////////////////////////////////////////////////////////////////// +void dmacStartTransfer(int ch){ + if (ch < 15) + dmacSetD_CHCR(ch, DMAf_TR | dmacGetD_CHCR(ch)); +} + +/////////////////////////////////////////////////////////////////////// +// set 3-bit value of channel +void dmacSetVal(int ch, int value){ + int x; + CpuSuspendIntr(&x); //intrman + + switch (ch){ + case DMAch_MDECin: dmacSetDPCR( + (dmacGetDPCR() & 0xFFFFFFF8) | + ( value & 7)); break; + case DMAch_MDECout:dmacSetDPCR( + (dmacGetDPCR() & 0xFFFFFF8F) | + (( value & 7) << 4)); break; + case DMAch_GPU: dmacSetDPCR( + (dmacGetDPCR() & 0xFFFFF8FF) | + (( value & 7) << 8)); break; + case DMAch_CD: dmacSetDPCR( + (dmacGetDPCR() & 0xFFFF8FFF) | + (( value & 7) << 12)); break; + case DMAch_SPU: dmacSetDPCR( + (dmacGetDPCR() & 0xFFF8FFFF) | + (( value & 7) << 16)); break; + case DMAch_PIO: dmacSetDPCR( + (dmacGetDPCR() & 0xFF8FFFFF) | + (( value & 7) << 20)); break; + case DMAch_GPUotc:dmacSetDPCR( + (dmacGetDPCR() & 0xF8FFFFFF) | + (( value & 7) << 24)); break; + case DMAch_SPU2:dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFFFFFF8) | + ( value & 7)); break; + case DMAch_8: dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFFFFF8F) | + (( value & 7) << 4)); break; + case DMAch_SIF0: dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFFFF8FF) | + (( value & 7) << 8)); break; + case DMAch_SIF1: dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFFF8FFF) | + (( value & 7) << 12)); break; + case DMAch_SIO2in: dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFF8FFFF) | + (( value & 7) << 16)); break; + case DMAch_SIO2out:dmacSetDPCR2( + (dmacGetDPCR2() & 0xFF8FFFFF) | + (( value & 7) << 20)); break; + case DMAch_13: dmacSetDPCR3( + (dmacGetDPCR3() & 0xFFFFFFF8) | + ( value & 7)); break; + case DMAch_14: dmacSetDPCR3( + (dmacGetDPCR3() & 0xFFFFFF8F) | + (( value & 7) << 4)); break; + case DMAch_15: dmacSetDPCR3( + (dmacGetDPCR3() & 0xFFFFF8FF) | + (( value & 7) << 8)); break; + case DMAch_67: dmacSetDPCR( + (dmacGetDPCR() & 0x8FFFFFFF) | + (( value & 7) << 28)); break; + case DMAch_85: dmacSetDPCR2( + (dmacGetDPCR2() & 0xF8FFFFFF) | + (( value & 7) << 24)); break; + } + + CpuResumeIntr(x); //intrman +} + +/////////////////////////////////////////////////////////////////////// +// set 4th bit of channel +void dmacEnableDMAch(int ch){ + int x; + CpuSuspendIntr(&x); //intrman + + switch (ch){ + case DMAch_MDECin: dmacSetDPCR( + (dmacGetDPCR() | 0x00000008)); break; + case DMAch_MDECout:dmacSetDPCR( + (dmacGetDPCR() | 0x00000080)); break; + case DMAch_GPU: dmacSetDPCR( + (dmacGetDPCR() | 0x00000800)); break; + case DMAch_CD: dmacSetDPCR( + (dmacGetDPCR() | 0x00008000)); break; + case DMAch_SPU: dmacSetDPCR( + (dmacGetDPCR() | 0x00080000)); break; + case DMAch_PIO: dmacSetDPCR( + (dmacGetDPCR() | 0x00800000)); break; + case DMAch_GPUotc:dmacSetDPCR( + (dmacGetDPCR() | 0x08000000)); break; + case DMAch_SPU2: dmacSetDPCR2( + (dmacGetDPCR2() | 0x00000008)); break; + case DMAch_8: dmacSetDPCR2( + (dmacGetDPCR2() | 0x00000080)); break; + case DMAch_SIF0: dmacSetDPCR2( + (dmacGetDPCR2() | 0x00000800)); break; + case DMAch_SIF1: dmacSetDPCR2( + (dmacGetDPCR2() | 0x00008000)); break; + case DMAch_SIO2in:dmacSetDPCR2( + (dmacGetDPCR2() | 0x00080000)); break; + case DMAch_SIO2out:dmacSetDPCR2( + (dmacGetDPCR2() | 0x00800000)); break; + case DMAch_13: dmacSetDPCR3( + (dmacGetDPCR3() | 0x00000008)); break; + case DMAch_14: dmacSetDPCR3( + (dmacGetDPCR3() | 0x00000080)); break; + case DMAch_15: dmacSetDPCR3( + (dmacGetDPCR3() | 0x00000800)); break; + case DMAch_85: dmacSetDPCR2( + (dmacGetDPCR2() | 0x08000000)); break; + } + + CpuResumeIntr(x); //intrman +} + +/////////////////////////////////////////////////////////////////////// +// reset 4th bit of channel +void dmacDisableDMAch(int ch){ + int x; + CpuSuspendIntr(&x); //intrman + + switch (ch){ + case DMAch_MDECin: dmacSetDPCR( + (dmacGetDPCR() & 0xFFFFFFF7)); break; + case DMAch_MDECout:dmacSetDPCR( + (dmacGetDPCR() & 0xFFFFFF7F)); break; + case DMAch_GPU: dmacSetDPCR( + (dmacGetDPCR() & 0xFFFFF7FF)); break; + case DMAch_CD: dmacSetDPCR( + (dmacGetDPCR() & 0xFFFF7FFF)); break; + case DMAch_SPU: dmacSetDPCR( + (dmacGetDPCR() & 0xFFF7FFFF)); break; + case DMAch_PIO: dmacSetDPCR( + (dmacGetDPCR() & 0xFF7FFFFF)); break; + case DMAch_GPUotc:dmacSetDPCR( + (dmacGetDPCR() & 0xF7FFFFFF)); break; + case DMAch_SPU2: dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFFFFFF7)); break; + case DMAch_8: dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFFFFF7F)); break; + case DMAch_SIF0: dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFFFF7FF)); break; + case DMAch_SIF1: dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFFF7FFF)); break; + case DMAch_SIO2in:dmacSetDPCR2( + (dmacGetDPCR2() & 0xFFF7FFFF)); break; + case DMAch_SIO2out:dmacSetDPCR2( + (dmacGetDPCR2() & 0xFF7FFFFF)); break; + case DMAch_13: dmacSetDPCR3( + (dmacGetDPCR3() & 0xFFFFFFF7)); break; + case DMAch_14: dmacSetDPCR3( + (dmacGetDPCR3() & 0xFFFFFF7F)); break; + case DMAch_15: dmacSetDPCR3( + (dmacGetDPCR3() & 0xFFFFF7FF)); break; + case DMAch_85: dmacSetDPCR2( + (dmacGetDPCR2() & 0xF7FFFFFF)); break; + } + + CpuResumeIntr(x); //intrman +} + +void _retonly(){} + +//////////////////////////////entrypoint/////////////////////////////// +struct export dmacman_stub={ + 0x41C00000, + 0, + VER(1, 2), // 1.2 => 0x102 + 0, + "dmacman", + (func)_start, // entrypoint + (func)_retonly, + (func)dmacDeinit, + (func)_retonly, + (func)dmacSetD_MADR, + (func)dmacGetD_MADR, + (func)dmacSetD_BCR, + (func)dmacGetD_BCR, + (func)dmacSetD_CHCR, + (func)dmacGetD_CHCR, + (func)dmacSetD_TADR, + (func)dmacGetD_TADR, + (func)dmacSet_4_9_A, + (func)dmacGet_4_9_A, + (func)dmacSetDPCR, + (func)dmacGetDPCR, + (func)dmacSetDPCR2, + (func)dmacGetDPCR2, + (func)dmacSetDPCR3, + (func)dmacGetDPCR3, + (func)dmacSetDICR, + (func)dmacGetDICR, + (func)dmacSetDICR2, + (func)dmacGetDICR2, + (func)dmacSetBF80157C, + (func)dmacGetBF80157C, + (func)dmacSetBF801578, + (func)dmacGetBF801578, + (func)dmacSetDMA, + (func)dmacSetDMA_chainedSPU_SIF0, + (func)dmacSetDMA_SIF0, + (func)dmacSetDMA_SIF1, + (func)dmacStartTransfer, + (func)dmacSetVal, + (func)dmacEnableDMAch, + (func)dmacDisableDMAch, + 0 +}; + +//////////////////////////////entrypoint/////////////////////////////// +int _start(int argc, char* argv[]){ + int x; + register int ch; + + if (RegisterLibraryEntries(&dmacman_stub)) //loadcore + return 1; + + CpuSuspendIntr(&x); //intrman + + dmacSetDPCR(0x07777777); + dmacSetDPCR2(0x07777777); + dmacSetDPCR3(0x00000777); + for (ch=0; ch<13; ch++){ + dmacSetD_MADR(ch, 0); + dmacSetD_BCR (ch, 0); + dmacSetD_CHCR(ch, 0); + } + dmacSetD_TADR( DMAch_SPU, 0); + dmacSetD_TADR( DMAch_SIF0,0); + dmacSet_4_9_A( DMAch_SPU, 0); + dmacSet_4_9_A( DMAch_SIF0,0); + dmacSet_4_9_A( DMAch_SIF1,0); + dmacSetBF801578(1); + + CpuResumeIntr(x); //intrman + return 0; +} + diff --git a/fps2bios/kernel/iopload/excepman/Makefile b/fps2bios/kernel/iopload/excepman/Makefile index acc273fd9a..cc7d7bceb2 100644 --- a/fps2bios/kernel/iopload/excepman/Makefile +++ b/fps2bios/kernel/iopload/excepman/Makefile @@ -1,60 +1,60 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include - -IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 -IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -IOPLINK = $(IOPLD) -dc -nostartfiles - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: excepman - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -LDADD = -OBJECTS = excepman.o ../libkernel/iop_loadcore.o ex_handler.o ../iopdebug.o - -excepman: $(OBJECTS) - $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/EXCEPMAN - -%.o: %.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - -%.o : %.s - $(IOPAS) $(IOPASFLAGS) $< -o $@ - -clean: - rm -f $(OBJECTS) - - - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc -nostartfiles + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: excepman + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = +LDADD = +OBJECTS = excepman.o ../libkernel/iop_loadcore.o ex_handler.o ../iopdebug.o + +excepman: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/EXCEPMAN + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + + + diff --git a/fps2bios/kernel/iopload/heaplib/Makefile b/fps2bios/kernel/iopload/heaplib/Makefile index 9af0f48679..eea0164316 100644 --- a/fps2bios/kernel/iopload/heaplib/Makefile +++ b/fps2bios/kernel/iopload/heaplib/Makefile @@ -1,59 +1,59 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include - -IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 -IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include -IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -IOPLINK = $(IOPLD) -dc -IOPASFLAGS := -EL -G0 - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: heaplib - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib -LDADD = -OBJECTS = heaplib.o ../iopdebug.o ../libkernel/iop_loadcore.o ../libkernel/iop_sysmem.o - -heaplib: $(OBJECTS) - $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/HEAPLIB - -%.o: %.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - -%.o : %.s - $(IOPAS) $(IOPASFLAGS) $< -o $@ - -clean: - rm -f $(OBJECTS) - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: heaplib + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib +LDADD = +OBJECTS = heaplib.o ../iopdebug.o ../libkernel/iop_loadcore.o ../libkernel/iop_sysmem.o + +heaplib: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/HEAPLIB + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/heaplib/heaplib.c b/fps2bios/kernel/iopload/heaplib/heaplib.c index 14793752b3..c66da7c93e 100644 --- a/fps2bios/kernel/iopload/heaplib/heaplib.c +++ b/fps2bios/kernel/iopload/heaplib/heaplib.c @@ -1,206 +1,206 @@ -//[module] HEAPLIB -//[processor] IOP -//[type] ELF-IRX -//[name] Heap_lib -//[version] 0x101 -//[memory map] - -//[handlers] - -//[entry point] heaplib_start, heaplib_stub -//[made by] [RO]man (roman_ps2dev@hotmail.com) 26 January 2003 - -#include "sysmem.h" -#include "kloadcore.h" -#include "kheaplib.h" -#include "iopdebug.h" - -static int debug=1; - -#define _dprintf(fmt, args...) \ - if (debug > 0) __printf("\033[0;32m" "heaplib: " "\033[0m" fmt, ## args) - -int _start(int argc, char* argv[]); - -/////////////////////////////////////////////////////////////////////// -void ll_reset(struct ll *l){ - l->prev=l->next=l; -} - -/////////////////////////////////////////////////////////////////////// -int ll_one(struct ll *l){ - return (l == l->next); -// return (l ^ l->next) < 1; //l==l->next -} - -/////////////////////////////////////////////////////////////////////// -void ll_remove(struct ll *l){ - l->next->prev=l->prev; - l->prev->next=l->next; -} - -/////////////////////////////////////////////////////////////////////// -/*int ll_one_two(struct ll *l){ - return (l->prev ^ l->next) < 1; //l->prev==l->next -}*/ - -/////////////////////////////////////////////////////////////////////// -void ll_add(struct ll *l, struct ll *n){ - n->next=l; - n->prev=l->prev; - l->prev=n; - n->prev->next=n; -} - -void HeapPrepare(void *mem, int size) { - struct Chunk *_chunk = (struct Chunk*)mem; - - if (mem == NULL || size < 41) return; - - _chunk->_mem=(long)mem-1; - _chunk->freesize=size; - _chunk->usedsize=0; - _chunk->mem_16 = (u32)mem+16; - _chunk->unk5=((size-16)>>3)-1; - _chunk->unk4=(long)_chunk+8+((size-16)&~7); - ((struct ll*)_chunk->unk4)->next=(void*)_chunk->mem_16; - ((struct ll*)_chunk->unk4)->prev=0; -} - -int HeapChunkSize(void *chunk) { -// int size = (chunk[1] - 16) >> 3; -// return ((size - chunk[2]) - 1) << 3; -} - -/////////////////////////////////////////////////////////////////////// -void* CreateHeap(int chunkSize, int memoryType){ - struct Heap *_heap; - - _dprintf("%s\n", __FUNCTION__); - chunkSize = (chunkSize+3) & ~3; - _heap = AllocSysMemory(memoryType & 2 ? ALLOC_LAST : ALLOC_FIRST, chunkSize, NULL); - if (_heap == NULL) return NULL; - - _heap->plus_one=(long)_heap + 1; - if (memoryType & 1) _heap->size2free=chunkSize; - else _heap->size2free=0; - _heap->size2free |= ((memoryType>>1) & 1); - ll_reset(&_heap->l); - - HeapPrepare(&_heap->mem, chunkSize-4*sizeof(int)); - return (void*)_heap; -} - -/////////////////////////////////////////////////////////////////////// -int DestroyHeap(void *heap){ - register struct ll *tmp, *p; - struct Heap *_heap = (struct Heap*)heap; - - if (_heap->plus_one != (long)_heap+1) return (long)_heap+1; - _heap->plus_one=0; - - for (p=&_heap->l; p != &_heap->l; p=tmp){ - tmp=p->next; - ((int*)p)[2]=0; //p->mem - FreeSysMemory(p); - } - _heap->mem=0; - return FreeSysMemory(_heap); -} - -/////////////////////////////////////////////////////////////////////// -void* HeapMalloc(void *heap, int size) { -#if 0 - struct Heap *_heap = (struct Heap*)heap; - void *p; - - if (_heap->plus_one != (long)_heap+1) return NULL; - - for (;;) { - p = HeapChunk13((u32)_heap->l.next+8, size); - if (p != NULL) return p; - - if (_heap->l.next->next == _heap->l.next) break; - } -#endif -} - -int HeapFree(void *heap, void *mem) { - struct Heap *_heap = (struct Heap*)heap; - struct Heap *h; - - if (heap == NULL || - _heap->plus_one != (long)_heap+1) return -4; - - for (h = (struct Heap*)_heap->l.next; h != &_heap->l; h = (struct Heap*)h->l.next) { - if (HeapChunk14(h->l, mem) != NULL) continue; - - break; - } - - if ((struct ll*)h == &_heap->l) return 0; - if (HeapChunk12() == 0) return 0; - ll_one(h); - h->l.next = 0; - FreeSysMemory(h); - - return 0; -} - -int HeapSize(void *heap) { - struct Heap *_heap = (struct Heap*)heap; - - if (heap == NULL || - _heap->plus_one != (long)_heap+1) return -4; - - for (;; _heap = _heap->plus_one) { - if (_heap->l.next == &_heap->l) - break; - } - - return HeapChunkSize(_heap->l.next+8); -} - -void HeapChunk12() { -} - -void HeapChunk13() { -} - -void HeapChunk14() { -} - -/////////////////////////////////////////////////////////////////////// -void _retonly(){} - -struct export heaplib_stub={ - 0x41C00000, - 0, - VER(1, 1), // 1.1 => 0x101 - 0, - "heaplib", - (func)_start, // entrypoint - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)CreateHeap, - (func)DestroyHeap, - (func)HeapMalloc, - (func)HeapFree, - (func)HeapSize, - (func)_retonly, - (func)_retonly, - (func)HeapPrepare, - (func)HeapChunk12, - (func)HeapChunk13, - (func)HeapChunk14, - (func)HeapChunkSize, - (func)_retonly, - (func)_retonly, - 0 -}; - - -//////////////////////////////entrypoint/////////////////////////////// -int _start(int argc, char* argv[]){ - return RegisterLibraryEntries(&heaplib_stub); -} - +//[module] HEAPLIB +//[processor] IOP +//[type] ELF-IRX +//[name] Heap_lib +//[version] 0x101 +//[memory map] - +//[handlers] - +//[entry point] heaplib_start, heaplib_stub +//[made by] [RO]man (roman_ps2dev@hotmail.com) 26 January 2003 + +#include "sysmem.h" +#include "kloadcore.h" +#include "kheaplib.h" +#include "iopdebug.h" + +static int debug=1; + +#define _dprintf(fmt, args...) \ + if (debug > 0) __printf("\033[0;32m" "heaplib: " "\033[0m" fmt, ## args) + +int _start(int argc, char* argv[]); + +/////////////////////////////////////////////////////////////////////// +void ll_reset(struct ll *l){ + l->prev=l->next=l; +} + +/////////////////////////////////////////////////////////////////////// +int ll_one(struct ll *l){ + return (l == l->next); +// return (l ^ l->next) < 1; //l==l->next +} + +/////////////////////////////////////////////////////////////////////// +void ll_remove(struct ll *l){ + l->next->prev=l->prev; + l->prev->next=l->next; +} + +/////////////////////////////////////////////////////////////////////// +/*int ll_one_two(struct ll *l){ + return (l->prev ^ l->next) < 1; //l->prev==l->next +}*/ + +/////////////////////////////////////////////////////////////////////// +void ll_add(struct ll *l, struct ll *n){ + n->next=l; + n->prev=l->prev; + l->prev=n; + n->prev->next=n; +} + +void HeapPrepare(void *mem, int size) { + struct Chunk *_chunk = (struct Chunk*)mem; + + if (mem == NULL || size < 41) return; + + _chunk->_mem=(long)mem-1; + _chunk->freesize=size; + _chunk->usedsize=0; + _chunk->mem_16 = (u32)mem+16; + _chunk->unk5=((size-16)>>3)-1; + _chunk->unk4=(long)_chunk+8+((size-16)&~7); + ((struct ll*)_chunk->unk4)->next=(void*)_chunk->mem_16; + ((struct ll*)_chunk->unk4)->prev=0; +} + +int HeapChunkSize(void *chunk) { +// int size = (chunk[1] - 16) >> 3; +// return ((size - chunk[2]) - 1) << 3; +} + +/////////////////////////////////////////////////////////////////////// +void* CreateHeap(int chunkSize, int memoryType){ + struct Heap *_heap; + + _dprintf("%s\n", __FUNCTION__); + chunkSize = (chunkSize+3) & ~3; + _heap = AllocSysMemory(memoryType & 2 ? ALLOC_LAST : ALLOC_FIRST, chunkSize, NULL); + if (_heap == NULL) return NULL; + + _heap->plus_one=(long)_heap + 1; + if (memoryType & 1) _heap->size2free=chunkSize; + else _heap->size2free=0; + _heap->size2free |= ((memoryType>>1) & 1); + ll_reset(&_heap->l); + + HeapPrepare(&_heap->mem, chunkSize-4*sizeof(int)); + return (void*)_heap; +} + +/////////////////////////////////////////////////////////////////////// +int DestroyHeap(void *heap){ + register struct ll *tmp, *p; + struct Heap *_heap = (struct Heap*)heap; + + if (_heap->plus_one != (long)_heap+1) return (long)_heap+1; + _heap->plus_one=0; + + for (p=&_heap->l; p != &_heap->l; p=tmp){ + tmp=p->next; + ((int*)p)[2]=0; //p->mem + FreeSysMemory(p); + } + _heap->mem=0; + return FreeSysMemory(_heap); +} + +/////////////////////////////////////////////////////////////////////// +void* HeapMalloc(void *heap, int size) { +#if 0 + struct Heap *_heap = (struct Heap*)heap; + void *p; + + if (_heap->plus_one != (long)_heap+1) return NULL; + + for (;;) { + p = HeapChunk13((u32)_heap->l.next+8, size); + if (p != NULL) return p; + + if (_heap->l.next->next == _heap->l.next) break; + } +#endif +} + +int HeapFree(void *heap, void *mem) { + struct Heap *_heap = (struct Heap*)heap; + struct Heap *h; + + if (heap == NULL || + _heap->plus_one != (long)_heap+1) return -4; + + for (h = (struct Heap*)_heap->l.next; h != &_heap->l; h = (struct Heap*)h->l.next) { + if (HeapChunk14(h->l, mem) != NULL) continue; + + break; + } + + if ((struct ll*)h == &_heap->l) return 0; + if (HeapChunk12() == 0) return 0; + ll_one(h); + h->l.next = 0; + FreeSysMemory(h); + + return 0; +} + +int HeapSize(void *heap) { + struct Heap *_heap = (struct Heap*)heap; + + if (heap == NULL || + _heap->plus_one != (long)_heap+1) return -4; + + for (;; _heap = _heap->plus_one) { + if (_heap->l.next == &_heap->l) + break; + } + + return HeapChunkSize(_heap->l.next+8); +} + +void HeapChunk12() { +} + +void HeapChunk13() { +} + +void HeapChunk14() { +} + +/////////////////////////////////////////////////////////////////////// +void _retonly(){} + +struct export heaplib_stub={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "heaplib", + (func)_start, // entrypoint + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)CreateHeap, + (func)DestroyHeap, + (func)HeapMalloc, + (func)HeapFree, + (func)HeapSize, + (func)_retonly, + (func)_retonly, + (func)HeapPrepare, + (func)HeapChunk12, + (func)HeapChunk13, + (func)HeapChunk14, + (func)HeapChunkSize, + (func)_retonly, + (func)_retonly, + 0 +}; + + +//////////////////////////////entrypoint/////////////////////////////// +int _start(int argc, char* argv[]){ + return RegisterLibraryEntries(&heaplib_stub); +} + diff --git a/fps2bios/kernel/iopload/include/err.h b/fps2bios/kernel/iopload/include/err.h index c93784ee98..a8f3ef59e1 100644 --- a/fps2bios/kernel/iopload/include/err.h +++ b/fps2bios/kernel/iopload/include/err.h @@ -1,30 +1,30 @@ -#ifndef __ERR_H__ -#define __ERR_H__ - -//#define ERR_VER 0x - -#define ERROR_OK 0 -#define ERROR_UNK -1 -//bad exception code -#define ERROR_BAD_EXCODE -50 - -//no exception handler for that code -#define ERROR_EXCODE_NOTFOUND -51 - -//already used -#define ERROR_USED_EXCODE -52 -#define ERROR_INTR_CONTEXT -100 -#define ERROR_DOES_EXIST -104 -#define ERROR_DOESNOT_EXIST -105 -#define ERROR_NO_TIMER -150 -#define ERROR_NOT_IRX -201 -#define ERROR_FILE_NOT_FOUND -203 -#define ERROR_FILE_ERROR -204 -#define ERROR_NO_MEM -400 -#define ERROR_SEMACOUNT_ZERO -400 - -// what should these be? Used in intrman.c -#define ERROR_ILLEGAL_INTRCODE ERROR_UNK -#define ERROR_CPUDI ERROR_UNK - -#endif//__ERR_H__ +#ifndef __ERR_H__ +#define __ERR_H__ + +//#define ERR_VER 0x + +#define ERROR_OK 0 +#define ERROR_UNK -1 +//bad exception code +#define ERROR_BAD_EXCODE -50 + +//no exception handler for that code +#define ERROR_EXCODE_NOTFOUND -51 + +//already used +#define ERROR_USED_EXCODE -52 +#define ERROR_INTR_CONTEXT -100 +#define ERROR_DOES_EXIST -104 +#define ERROR_DOESNOT_EXIST -105 +#define ERROR_NO_TIMER -150 +#define ERROR_NOT_IRX -201 +#define ERROR_FILE_NOT_FOUND -203 +#define ERROR_FILE_ERROR -204 +#define ERROR_NO_MEM -400 +#define ERROR_SEMACOUNT_ZERO -400 + +// what should these be? Used in intrman.c +#define ERROR_ILLEGAL_INTRCODE ERROR_UNK +#define ERROR_CPUDI ERROR_UNK + +#endif//__ERR_H__ diff --git a/fps2bios/kernel/iopload/include/errno.h b/fps2bios/kernel/iopload/include/errno.h index fa069caf3c..c8f33f9436 100644 --- a/fps2bios/kernel/iopload/include/errno.h +++ b/fps2bios/kernel/iopload/include/errno.h @@ -1,143 +1,143 @@ -/* errno is not a global variable, because that would make using it - non-reentrant. Instead, its address is returned by the function - __errno. */ - -#ifndef _SYS_ERRNO_H_ -#ifdef __cplusplus -extern "C" { -#endif -#define _SYS_ERRNO_H_ - - -#define EPERM 1 /* Not super-user */ -#define ENOENT 2 /* No such file or directory */ -#define ESRCH 3 /* No such process */ -#define EINTR 4 /* Interrupted system call */ -#define EIO 5 /* I/O error */ -#define ENXIO 6 /* No such device or address */ -#define E2BIG 7 /* Arg list too long */ -#define ENOEXEC 8 /* Exec format error */ -#define EBADF 9 /* Bad file number */ -#define ECHILD 10 /* No children */ -#define EAGAIN 11 /* No more processes */ -#define ENOMEM 12 /* Not enough core */ -#define EACCES 13 /* Permission denied */ -#define EFAULT 14 /* Bad address */ -#define ENOTBLK 15 /* Block device required */ -#define EBUSY 16 /* Mount device busy */ -#define EEXIST 17 /* File exists */ -#define EXDEV 18 /* Cross-device link */ -#define ENODEV 19 /* No such device */ -#define ENOTDIR 20 /* Not a directory */ -#define EISDIR 21 /* Is a directory */ -#define EINVAL 22 /* Invalid argument */ -#define ENFILE 23 /* Too many open files in system */ -#define EMFILE 24 /* Too many open files */ -#define ENOTTY 25 /* Not a typewriter */ -#define ETXTBSY 26 /* Text file busy */ -#define EFBIG 27 /* File too large */ -#define ENOSPC 28 /* No space left on device */ -#define ESPIPE 29 /* Illegal seek */ -#define EROFS 30 /* Read only file system */ -#define EMLINK 31 /* Too many links */ -#define EPIPE 32 /* Broken pipe */ -#define EDOM 33 /* Math arg out of domain of func */ -#define ERANGE 34 /* Math result not representable */ -#define ENOMSG 35 /* No message of desired type */ -#define EIDRM 36 /* Identifier removed */ -#define ECHRNG 37 /* Channel number out of range */ -#define EL2NSYNC 38 /* Level 2 not synchronized */ -#define EL3HLT 39 /* Level 3 halted */ -#define EL3RST 40 /* Level 3 reset */ -#define ELNRNG 41 /* Link number out of range */ -#define EUNATCH 42 /* Protocol driver not attached */ -#define ENOCSI 43 /* No CSI structure available */ -#define EL2HLT 44 /* Level 2 halted */ -#define EDEADLK 45 /* Deadlock condition */ -#define ENOLCK 46 /* No record locks available */ -#define EBADE 50 /* Invalid exchange */ -#define EBADR 51 /* Invalid request descriptor */ -#define EXFULL 52 /* Exchange full */ -#define ENOANO 53 /* No anode */ -#define EBADRQC 54 /* Invalid request code */ -#define EBADSLT 55 /* Invalid slot */ -#define EDEADLOCK 56 /* File locking deadlock error */ -#define EBFONT 57 /* Bad font file fmt */ -#define ENOSTR 60 /* Device not a stream */ -#define ENODATA 61 /* No data (for no delay io) */ -#define ETIME 62 /* Timer expired */ -#define ENOSR 63 /* Out of streams resources */ -#define ENONET 64 /* Machine is not on the network */ -#define ENOPKG 65 /* Package not installed */ -#define EREMOTE 66 /* The object is remote */ -#define ENOLINK 67 /* The link has been severed */ -#define EADV 68 /* Advertise error */ -#define ESRMNT 69 /* Srmount error */ -#define ECOMM 70 /* Communication error on send */ -#define EPROTO 71 /* Protocol error */ -#define EMULTIHOP 74 /* Multihop attempted */ -#define ELBIN 75 /* Inode is remote (not really error) */ -#define EDOTDOT 76 /* Cross mount point (not really error) */ -#define EBADMSG 77 /* Trying to read unreadable message */ -#define EFTYPE 79 /* Inappropriate file type or format */ -#define ENOTUNIQ 80 /* Given log. name not unique */ -#define EBADFD 81 /* f.d. invalid for this operation */ -#define EREMCHG 82 /* Remote address changed */ -#define ELIBACC 83 /* Can't access a needed shared lib */ -#define ELIBBAD 84 /* Accessing a corrupted shared lib */ -#define ELIBSCN 85 /* .lib section in a.out corrupted */ -#define ELIBMAX 86 /* Attempting to link in too many libs */ -#define ELIBEXEC 87 /* Attempting to exec a shared library */ -#define ENOSYS 88 /* Function not implemented */ -#define ENMFILE 89 /* No more files */ -#define ENOTEMPTY 90 /* Directory not empty */ -#define ENAMETOOLONG 91 /* File or path name too long */ -#define ELOOP 92 /* Too many symbolic links */ -#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ -#define EPFNOSUPPORT 96 /* Protocol family not supported */ -#define ECONNRESET 104 /* Connection reset by peer */ -#define ENOBUFS 105 /* No buffer space available */ -#define EAFNOSUPPORT 106 /* Address family not supported by protocol family */ -#define EPROTOTYPE 107 /* Protocol wrong type for socket */ -#define ENOTSOCK 108 /* Socket operation on non-socket */ -#define ENOPROTOOPT 109 /* Protocol not available */ -#define ESHUTDOWN 110 /* Can't send after socket shutdown */ -#define ECONNREFUSED 111 /* Connection refused */ -#define EADDRINUSE 112 /* Address already in use */ -#define ECONNABORTED 113 /* Connection aborted */ -#define ENETUNREACH 114 /* Network is unreachable */ -#define ENETDOWN 115 /* Network interface is not configured */ -#define ETIMEDOUT 116 /* Connection timed out */ -#define EHOSTDOWN 117 /* Host is down */ -#define EHOSTUNREACH 118 /* Host is unreachable */ -#define EINPROGRESS 119 /* Connection already in progress */ -#define EALREADY 120 /* Socket already connected */ -#define EDESTADDRREQ 121 /* Destination address required */ -#define EMSGSIZE 122 /* Message too long */ -#define EPROTONOSUPPORT 123 /* Unknown protocol */ -#define ESOCKTNOSUPPORT 124 /* Socket type not supported */ -#define EADDRNOTAVAIL 125 /* Address not available */ -#define ENETRESET 126 -#define EISCONN 127 /* Socket is already connected */ -#define ENOTCONN 128 /* Socket is not connected */ -#define ETOOMANYREFS 129 -#define EPROCLIM 130 -#define EUSERS 131 -#define EDQUOT 132 -#define ESTALE 133 -#define ENOTSUP 134 /* Not supported */ -#define ENOMEDIUM 135 /* No medium (in tape drive) */ -#define ENOSHARE 136 /* No such host or network path */ -#define ECASECLASH 137 /* Filename exists with different case */ -#define EILSEQ 138 -#define EOVERFLOW 139 /* Value too large for defined data type */ - -/* From cygwin32. */ -#define EWOULDBLOCK EAGAIN /* Operation would block */ - -#define __ELASTERROR 2000 /* Users can add values starting here */ - -#ifdef __cplusplus -} -#endif -#endif /* _SYS_ERRNO_H */ +/* errno is not a global variable, because that would make using it + non-reentrant. Instead, its address is returned by the function + __errno. */ + +#ifndef _SYS_ERRNO_H_ +#ifdef __cplusplus +extern "C" { +#endif +#define _SYS_ERRNO_H_ + + +#define EPERM 1 /* Not super-user */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No children */ +#define EAGAIN 11 /* No more processes */ +#define ENOMEM 12 /* Not enough core */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Mount device busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* Too many open files in system */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math arg out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define ENOMSG 35 /* No message of desired type */ +#define EIDRM 36 /* Identifier removed */ +#define ECHRNG 37 /* Channel number out of range */ +#define EL2NSYNC 38 /* Level 2 not synchronized */ +#define EL3HLT 39 /* Level 3 halted */ +#define EL3RST 40 /* Level 3 reset */ +#define ELNRNG 41 /* Link number out of range */ +#define EUNATCH 42 /* Protocol driver not attached */ +#define ENOCSI 43 /* No CSI structure available */ +#define EL2HLT 44 /* Level 2 halted */ +#define EDEADLK 45 /* Deadlock condition */ +#define ENOLCK 46 /* No record locks available */ +#define EBADE 50 /* Invalid exchange */ +#define EBADR 51 /* Invalid request descriptor */ +#define EXFULL 52 /* Exchange full */ +#define ENOANO 53 /* No anode */ +#define EBADRQC 54 /* Invalid request code */ +#define EBADSLT 55 /* Invalid slot */ +#define EDEADLOCK 56 /* File locking deadlock error */ +#define EBFONT 57 /* Bad font file fmt */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data (for no delay io) */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* The object is remote */ +#define ENOLINK 67 /* The link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 74 /* Multihop attempted */ +#define ELBIN 75 /* Inode is remote (not really error) */ +#define EDOTDOT 76 /* Cross mount point (not really error) */ +#define EBADMSG 77 /* Trying to read unreadable message */ +#define EFTYPE 79 /* Inappropriate file type or format */ +#define ENOTUNIQ 80 /* Given log. name not unique */ +#define EBADFD 81 /* f.d. invalid for this operation */ +#define EREMCHG 82 /* Remote address changed */ +#define ELIBACC 83 /* Can't access a needed shared lib */ +#define ELIBBAD 84 /* Accessing a corrupted shared lib */ +#define ELIBSCN 85 /* .lib section in a.out corrupted */ +#define ELIBMAX 86 /* Attempting to link in too many libs */ +#define ELIBEXEC 87 /* Attempting to exec a shared library */ +#define ENOSYS 88 /* Function not implemented */ +#define ENMFILE 89 /* No more files */ +#define ENOTEMPTY 90 /* Directory not empty */ +#define ENAMETOOLONG 91 /* File or path name too long */ +#define ELOOP 92 /* Too many symbolic links */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EAFNOSUPPORT 106 /* Address family not supported by protocol family */ +#define EPROTOTYPE 107 /* Protocol wrong type for socket */ +#define ENOTSOCK 108 /* Socket operation on non-socket */ +#define ENOPROTOOPT 109 /* Protocol not available */ +#define ESHUTDOWN 110 /* Can't send after socket shutdown */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EADDRINUSE 112 /* Address already in use */ +#define ECONNABORTED 113 /* Connection aborted */ +#define ENETUNREACH 114 /* Network is unreachable */ +#define ENETDOWN 115 /* Network interface is not configured */ +#define ETIMEDOUT 116 /* Connection timed out */ +#define EHOSTDOWN 117 /* Host is down */ +#define EHOSTUNREACH 118 /* Host is unreachable */ +#define EINPROGRESS 119 /* Connection already in progress */ +#define EALREADY 120 /* Socket already connected */ +#define EDESTADDRREQ 121 /* Destination address required */ +#define EMSGSIZE 122 /* Message too long */ +#define EPROTONOSUPPORT 123 /* Unknown protocol */ +#define ESOCKTNOSUPPORT 124 /* Socket type not supported */ +#define EADDRNOTAVAIL 125 /* Address not available */ +#define ENETRESET 126 +#define EISCONN 127 /* Socket is already connected */ +#define ENOTCONN 128 /* Socket is not connected */ +#define ETOOMANYREFS 129 +#define EPROCLIM 130 +#define EUSERS 131 +#define EDQUOT 132 +#define ESTALE 133 +#define ENOTSUP 134 /* Not supported */ +#define ENOMEDIUM 135 /* No medium (in tape drive) */ +#define ENOSHARE 136 /* No such host or network path */ +#define ECASECLASH 137 /* Filename exists with different case */ +#define EILSEQ 138 +#define EOVERFLOW 139 /* Value too large for defined data type */ + +/* From cygwin32. */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ + +#define __ELASTERROR 2000 /* Users can add values starting here */ + +#ifdef __cplusplus +} +#endif +#endif /* _SYS_ERRNO_H */ diff --git a/fps2bios/kernel/iopload/include/iopdebug.h b/fps2bios/kernel/iopload/include/iopdebug.h index c52e672334..20c4585194 100644 --- a/fps2bios/kernel/iopload/include/iopdebug.h +++ b/fps2bios/kernel/iopload/include/iopdebug.h @@ -1,11 +1,11 @@ -#ifndef __IOPDEBUG_H__ -#define __IOPDEBUG_H__ - -#include - -void __putc(u8 c); -void __puts(u8 *s); -void __printf(char *fmt, ...); - - -#endif /* __IOPDEBUG_H__ */ +#ifndef __IOPDEBUG_H__ +#define __IOPDEBUG_H__ + +#include + +void __putc(u8 c); +void __puts(u8 *s); +void __printf(char *fmt, ...); + + +#endif /* __IOPDEBUG_H__ */ diff --git a/fps2bios/kernel/iopload/include/iopelf.h b/fps2bios/kernel/iopload/include/iopelf.h index 2f8933a1f6..fbed795412 100644 --- a/fps2bios/kernel/iopload/include/iopelf.h +++ b/fps2bios/kernel/iopload/include/iopelf.h @@ -1,226 +1,226 @@ -#ifndef __IOPELF_H__ -#define __IOPELF_H__ - -#include "romdir.h" - -#define MOD_TYPE_REL 1 -#define MOD_TYPE_2 2 -#define MOD_TYPE_DYN 3 -#define MOD_TYPE_CORE 4 - -typedef struct { - char *name; - short version; -} moduleInfo; - -// info about a module file -typedef struct module_info { - int type; // module type (MOD_TYPE_*) - int (*entry)(void*);// module entry point address - int gpValue; // module gp value - int progVAddr; // programs virtual address - int textSize; // size of text section - int dataSize; // size of data section - int bssSize; // size of bss section - int progMemSize; // size of program memory - int moduleInfo; // info about module ? -} MODULE_INFO; - -typedef struct { - u32 ei_magic; - u8 ei_class; - u8 ei_data; - u8 ei_version; - u8 ei_pad[9]; -} E_IDENT; - -typedef struct { - u8 e_ident[16]; //+00 0x7f,"ELF" (ELF file identifier), E_IDENT* - u16 e_type; //+10 ELF type: 0=NONE, 1=REL, 2=EXEC, 3=SHARED, 4=CORE - u16 e_machine; //+12 Processor: 8=MIPS R3000 - u32 e_version; //+14 Version: 1=current - u32 e_entry; //+18 Entry point address - u32 e_phoff; //+1C Start of program headers (offset from file start) - u32 e_shoff; //+20 Start of section headers (offset from file start) - u32 e_flags; //+24 Processor specific flags = 0x20924001 noreorder, mips - u16 e_ehsize; //+28 ELF header size (0x34 = 52 bytes) - u16 e_phentsize; //+2A Program headers entry size - u16 e_phnum; //+2C Number of program headers - u16 e_shentsize; //+2E Section headers entry size - u16 e_shnum; //+30 Number of section headers - u16 e_shstrndx; //+32 Section header stringtable index -} ELF_HEADER; //+34=sizeof -#define ET_SCE_IOPRELEXEC 0xFF80 -#define PT_SCE_IOPMOD 0x70000080 -#define SHT_REL 9 -#define EM_MIPS 8 - -typedef struct tag_COFF_AOUTHDR { - short magic; //+00 - short vstamp; //+02 - int tsize; //+04 - int dsize; //+08 - int bsize; //+0C - int entry; //+10 - int text_start; //+14 - int data_start; //+18 - int bss_start; //+1C - int field_20; //+20 - int field_24; //+24 - int field_28; //+28 - int field_2C; //+2C - int moduleinfo; //+30 - int gp_value; //+34 -} COFF_AOUTHDR, COHDR; //=38 - -typedef struct tag_CHDR{ - short f_magic; //+00 - short f_nscns; //+02 - int f_timdat; //+04 - int f_symptr; //+08 - int f_nsyms; //+0C - short f_opthdr; //+10 - short f_flags; //+12 -} CHDR; //=14 - -typedef struct tag_COFF_HEADER{ //same header as above - short f_magic; //+00 - short f_nscns; //+02 - int f_timdat; //+04 - int f_symptr; //+08 - int f_nsyms; //+0C - short f_opthdr; //+10 - short f_flags; //+12 - COFF_AOUTHDR opthdr; //+14 -} COFF_HEADER; //=4C - -typedef struct tag_COFF_scnhdr -{ - char s_name[8]; //+00 - int s_paddr; //+08 - int s_vaddr; //+0C - int s_size; //+10 - int s_scnptr; //+14 - int s_relptr; //+18 - int s_lnnoptr; //+1C - short s_nreloc; //+20 - short s_nlnno; //+22 - int s_flags; //+24 -} COFF_scnhdr, SHDR; //=28 - -typedef struct _fileInfo -{ - u32 type, //+00 - entry, //+04 - gp_value, //+08 - p1_vaddr, //+0C - text_size, //+10 - data_size, //+14 - bss_size, //+18 - p1_memsz; //+1C - moduleInfo *moduleinfo; //+20 -} fileInfo; - -typedef struct { - u32 p_type; //+00 see notes1 - u32 p_offset; //+04 Offset from file start to program segment. - u32 p_vaddr; //+08 Virtual address of the segment - u32 p_paddr; //+0C Physical address of the segment - u32 p_filesz; //+10 Number of bytes in the file image of the segment - u32 p_memsz; //+14 Number of bytes in the memory image of the segment - u32 p_flags; //+18 Flags for segment - u32 p_align; //+1C Alignment. The address of 0x08 and 0x0C must fit this alignment. 0=no alignment -} ELF_PHR; - -//notes1 -//------ -//0=Inactive -//1=Load the segment into memory, no. of bytes specified by 0x10 and 0x14 -//2=Dynamic linking -//3=Interpreter. The array element must specify a path name -//4=Note. The array element must specify the location and size of aux. info -//5=reserved -//6=The array element must specify location and size of the program header table. - -typedef struct { - u32 r_offset; - u32 r_info; -} ELF_REL; - -typedef struct { - char* moduleinfo; - u32 entry; //+04 - u32 gp_value; //+08 - u32 text_size; //+0C - u32 data_size; //+10 - u32 bss_size;//+14 - short moduleversion;//+18 - char* modulename; //+1A -} ELF_IOPMOD; - -typedef struct { - u32 sh_name; //+00 No. to the index of the Section header stringtable index - u32 sh_type; //+04 See notes2 - u32 sh_flags; //+08 see notes3 - u32 sh_addr; //+0C Section start address - u32 sh_offset; //+10 Offset from start of file to section - u32 sh_size; //+14 Size of section - u32 sh_link; //+18 Section header table index link - u32 sh_info; //+1C Info - u32 sh_addralign; //+20 Alignment. The adress of 0x0C must fit this alignment. 0=no alignment. - u32 sh_entsize; //+24 Fixed size entries. -} ELF_SHR; - -//notes 2 -//------- -//Type: -//0=Inactive -//1=PROGBITS -//2=SYMTAB symbol table -//3=STRTAB string table -//4=RELA relocation entries -//5=HASH hash table -//6=DYNAMIC dynamic linking information -//7=NOTE -//8=NOBITS -//9=REL relocation entries -//10=SHLIB -//0x70000000=LOPROC processor specifc -//0x7fffffff=HIPROC -//0x80000000=LOUSER lower bound -//0xffffffff=HIUSER upper bound -// -//notes 3 -//------- -//Section Flags: (1 bit, you may combine them like 3 = alloc & write permission) -//1=Write section contains data the is be writeable during execution. -//2=Alloc section occupies memory during execution -//4=Exec section contains executable instructions -//0xf0000000=Mask bits processor-specific - - -#define ELF32_ST_TYPE(i) ((i)&0xf) - -// special header for every iop module? -typedef struct { - u32 next; //+00 - char *name; //+04 - short version, //+08 - flags, //+0A - modid, //+0C - HE; //+0E - u32 entry, //+10 - gp_value, //+14 - p1_vaddr, //+18 - text_size, //+1C - data_size, //+20 - bss_size, //+24 - H28, //+28 - H2C; //+2C -} imageInfo; - -// pass in the memory to load the elf file from -// elfoffset - offset to load elf file to -void* loadElfFile(ROMFILE_INFO* ri, u32 elfoffset); - -#endif +#ifndef __IOPELF_H__ +#define __IOPELF_H__ + +#include "romdir.h" + +#define MOD_TYPE_REL 1 +#define MOD_TYPE_2 2 +#define MOD_TYPE_DYN 3 +#define MOD_TYPE_CORE 4 + +typedef struct { + char *name; + short version; +} moduleInfo; + +// info about a module file +typedef struct module_info { + int type; // module type (MOD_TYPE_*) + int (*entry)(void*);// module entry point address + int gpValue; // module gp value + int progVAddr; // programs virtual address + int textSize; // size of text section + int dataSize; // size of data section + int bssSize; // size of bss section + int progMemSize; // size of program memory + int moduleInfo; // info about module ? +} MODULE_INFO; + +typedef struct { + u32 ei_magic; + u8 ei_class; + u8 ei_data; + u8 ei_version; + u8 ei_pad[9]; +} E_IDENT; + +typedef struct { + u8 e_ident[16]; //+00 0x7f,"ELF" (ELF file identifier), E_IDENT* + u16 e_type; //+10 ELF type: 0=NONE, 1=REL, 2=EXEC, 3=SHARED, 4=CORE + u16 e_machine; //+12 Processor: 8=MIPS R3000 + u32 e_version; //+14 Version: 1=current + u32 e_entry; //+18 Entry point address + u32 e_phoff; //+1C Start of program headers (offset from file start) + u32 e_shoff; //+20 Start of section headers (offset from file start) + u32 e_flags; //+24 Processor specific flags = 0x20924001 noreorder, mips + u16 e_ehsize; //+28 ELF header size (0x34 = 52 bytes) + u16 e_phentsize; //+2A Program headers entry size + u16 e_phnum; //+2C Number of program headers + u16 e_shentsize; //+2E Section headers entry size + u16 e_shnum; //+30 Number of section headers + u16 e_shstrndx; //+32 Section header stringtable index +} ELF_HEADER; //+34=sizeof +#define ET_SCE_IOPRELEXEC 0xFF80 +#define PT_SCE_IOPMOD 0x70000080 +#define SHT_REL 9 +#define EM_MIPS 8 + +typedef struct tag_COFF_AOUTHDR { + short magic; //+00 + short vstamp; //+02 + int tsize; //+04 + int dsize; //+08 + int bsize; //+0C + int entry; //+10 + int text_start; //+14 + int data_start; //+18 + int bss_start; //+1C + int field_20; //+20 + int field_24; //+24 + int field_28; //+28 + int field_2C; //+2C + int moduleinfo; //+30 + int gp_value; //+34 +} COFF_AOUTHDR, COHDR; //=38 + +typedef struct tag_CHDR{ + short f_magic; //+00 + short f_nscns; //+02 + int f_timdat; //+04 + int f_symptr; //+08 + int f_nsyms; //+0C + short f_opthdr; //+10 + short f_flags; //+12 +} CHDR; //=14 + +typedef struct tag_COFF_HEADER{ //same header as above + short f_magic; //+00 + short f_nscns; //+02 + int f_timdat; //+04 + int f_symptr; //+08 + int f_nsyms; //+0C + short f_opthdr; //+10 + short f_flags; //+12 + COFF_AOUTHDR opthdr; //+14 +} COFF_HEADER; //=4C + +typedef struct tag_COFF_scnhdr +{ + char s_name[8]; //+00 + int s_paddr; //+08 + int s_vaddr; //+0C + int s_size; //+10 + int s_scnptr; //+14 + int s_relptr; //+18 + int s_lnnoptr; //+1C + short s_nreloc; //+20 + short s_nlnno; //+22 + int s_flags; //+24 +} COFF_scnhdr, SHDR; //=28 + +typedef struct _fileInfo +{ + u32 type, //+00 + entry, //+04 + gp_value, //+08 + p1_vaddr, //+0C + text_size, //+10 + data_size, //+14 + bss_size, //+18 + p1_memsz; //+1C + moduleInfo *moduleinfo; //+20 +} fileInfo; + +typedef struct { + u32 p_type; //+00 see notes1 + u32 p_offset; //+04 Offset from file start to program segment. + u32 p_vaddr; //+08 Virtual address of the segment + u32 p_paddr; //+0C Physical address of the segment + u32 p_filesz; //+10 Number of bytes in the file image of the segment + u32 p_memsz; //+14 Number of bytes in the memory image of the segment + u32 p_flags; //+18 Flags for segment + u32 p_align; //+1C Alignment. The address of 0x08 and 0x0C must fit this alignment. 0=no alignment +} ELF_PHR; + +//notes1 +//------ +//0=Inactive +//1=Load the segment into memory, no. of bytes specified by 0x10 and 0x14 +//2=Dynamic linking +//3=Interpreter. The array element must specify a path name +//4=Note. The array element must specify the location and size of aux. info +//5=reserved +//6=The array element must specify location and size of the program header table. + +typedef struct { + u32 r_offset; + u32 r_info; +} ELF_REL; + +typedef struct { + char* moduleinfo; + u32 entry; //+04 + u32 gp_value; //+08 + u32 text_size; //+0C + u32 data_size; //+10 + u32 bss_size;//+14 + short moduleversion;//+18 + char* modulename; //+1A +} ELF_IOPMOD; + +typedef struct { + u32 sh_name; //+00 No. to the index of the Section header stringtable index + u32 sh_type; //+04 See notes2 + u32 sh_flags; //+08 see notes3 + u32 sh_addr; //+0C Section start address + u32 sh_offset; //+10 Offset from start of file to section + u32 sh_size; //+14 Size of section + u32 sh_link; //+18 Section header table index link + u32 sh_info; //+1C Info + u32 sh_addralign; //+20 Alignment. The adress of 0x0C must fit this alignment. 0=no alignment. + u32 sh_entsize; //+24 Fixed size entries. +} ELF_SHR; + +//notes 2 +//------- +//Type: +//0=Inactive +//1=PROGBITS +//2=SYMTAB symbol table +//3=STRTAB string table +//4=RELA relocation entries +//5=HASH hash table +//6=DYNAMIC dynamic linking information +//7=NOTE +//8=NOBITS +//9=REL relocation entries +//10=SHLIB +//0x70000000=LOPROC processor specifc +//0x7fffffff=HIPROC +//0x80000000=LOUSER lower bound +//0xffffffff=HIUSER upper bound +// +//notes 3 +//------- +//Section Flags: (1 bit, you may combine them like 3 = alloc & write permission) +//1=Write section contains data the is be writeable during execution. +//2=Alloc section occupies memory during execution +//4=Exec section contains executable instructions +//0xf0000000=Mask bits processor-specific + + +#define ELF32_ST_TYPE(i) ((i)&0xf) + +// special header for every iop module? +typedef struct { + u32 next; //+00 + char *name; //+04 + short version, //+08 + flags, //+0A + modid, //+0C + HE; //+0E + u32 entry, //+10 + gp_value, //+14 + p1_vaddr, //+18 + text_size, //+1C + data_size, //+20 + bss_size, //+24 + H28, //+28 + H2C; //+2C +} imageInfo; + +// pass in the memory to load the elf file from +// elfoffset - offset to load elf file to +void* loadElfFile(ROMFILE_INFO* ri, u32 elfoffset); + +#endif diff --git a/fps2bios/kernel/iopload/include/iopload.h b/fps2bios/kernel/iopload/include/iopload.h index 42a2815153..ad20f1778e 100644 --- a/fps2bios/kernel/iopload/include/iopload.h +++ b/fps2bios/kernel/iopload/include/iopload.h @@ -1,18 +1,18 @@ -#ifndef __IOPLOAD_H__ -#define __IOPLOAD_H__ - -#include - -extern char *iopModules[32]; - -void Kmemcpy(void *dest, const void *src, int n); - -#define SBUS_MSFLG *(volatile int*)0xBD00F220 -#define SBUS_SMFLG *(volatile int*)0xBD00F230 -#define SBUS_F240 *(volatile int*)0xBD00F240 - -#define SBFLG_IOPALIVE 0x10000 -#define SBFLG_IOPSYNC 0x40000 - - -#endif /* __IOPLOAD_H__ */ +#ifndef __IOPLOAD_H__ +#define __IOPLOAD_H__ + +#include + +extern char *iopModules[32]; + +void Kmemcpy(void *dest, const void *src, int n); + +#define SBUS_MSFLG *(volatile int*)0xBD00F220 +#define SBUS_SMFLG *(volatile int*)0xBD00F230 +#define SBUS_F240 *(volatile int*)0xBD00F240 + +#define SBFLG_IOPALIVE 0x10000 +#define SBFLG_IOPSYNC 0x40000 + + +#endif /* __IOPLOAD_H__ */ diff --git a/fps2bios/kernel/iopload/include/kdmacman.h b/fps2bios/kernel/iopload/include/kdmacman.h index efcf40bf8e..cabd0529e1 100644 --- a/fps2bios/kernel/iopload/include/kdmacman.h +++ b/fps2bios/kernel/iopload/include/kdmacman.h @@ -1,116 +1,116 @@ -#ifndef __DMACMAN_H__ -#define __DMACMAN_H__ - -#define DMACMAN_VER 0x101 - -////////////////////////////// D_CHCR - DMA Channel Control Register -#define DMAf_30 0x40000000 // unknown; set on 'to' direction -#define DMAf_TR 0x01000000 // DMA transfer -#define DMAf_LI 0x00000400 // Linked list GPU; also SPU & SIF0 -#define DMAf_CO 0x00000200 // Continuous stream -#define DMAf_08 0x00000100 // unknown -#define DMAf_DR 0x00000001 // Direction to=0/from=1 -// 31 24 23 16 15 8 7 0 -// ÖÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ· -// º ³?³ ³ ³ ³ ³ ³Tº ³ ³ ³ ³ ³ ³ ³ º ³ ³ ³ ³ ³L³C³?º ³ ³ ³ ³ ³ ³ ³Dº -// º ³?³ ³ ³ ³ ³ ³Rº ³ ³ ³ ³ ³ ³ ³ º ³ ³ ³ ³ ³I³O³?º ³ ³ ³ ³ ³ ³ ³Rº -// ÓÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁĽ -// 30 24 10 9 8 0 - -////////////////////////////// DPCR - DMA Primary Control Register -// ÖÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ· -// º 67 ³ DMA 6 º DMA 5 ³ DMA 4 º DMA 3 ³ DMA 2 º DMA 1 ³ DMA 0 º 0xBF8010F0 DPCR -// ÓÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁĽ -// ÖÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ· -// º ³ DMA85 º DMA12 ³ DMA11 º DMA10 ³ DMA 9 º DMA 8 ³ DMA 7 º 0xBF801570 DPCR_ -// ÓÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁĽ -// ÖÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ· -// º ³ º ³ º ³ DMA15 º DMA14 ³ DMA13 º 0xBF8015F0 DPCR__ -// ÓÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁĽ - -////////// DPCR -#define DMAch_MDECin 0 -#define DMAch_MDECout 1 -#define DMAch_GPU 2 // SIF2 both directions -#define DMAch_CD 3 -#define DMAch_SPU 4 -#define DMAch_PIO 5 -#define DMAch_GPUotc 6 - -#define DMAch_67 67 // strange - -////////// DPCR_ -#define DMAch_SPU2 7 -#define DMAch_8 8 -#define DMAch_SIF0 9 // SIFout IOP->EE -#define DMAch_SIF1 10 // SIFin EE->IOP -#define DMAch_SIO2in 11 -#define DMAch_SIO2out 12 - -#define DMAch_85 85 // stange, very strange - -////////// DPCR__ -#define DMAch_13 13 -#define DMAch_14 14 -#define DMAch_15 15 - -int dmacman_start(int argc, char* argv[]); // 0 -int dmacman_deinit(); // 2 - -void dmacman_call4_SetD_MADR(unsigned int ch, int value); // 4 -int dmacman_call5_GetD_MADR(unsigned int ch); // 5 -void dmacman_call6_SetD_BCR(unsigned int ch, int value); // 6 -int dmacman_call7_GetD_BCR(unsigned int ch); // 7 -void dmacman_call8_SetD_CHCR(unsigned int ch, int value); // 8 -int dmacman_call9_GetD_CHCR(unsigned int ch); // 9 -void dmacman_call10_SetD_TADR(unsigned int ch, int value); //10 -int dmacman_call11_GetD_TADR(unsigned int ch); //11 -void dmacman_call12_Set_4_9_A(unsigned int ch, int value); //12 -int dmacman_call13_Get_4_9_A(unsigned int ch); //13 -void dmacman_call14_SetDPCR(int value); //14 -int dmacman_call15_GetDPCR(); //15 -void dmacman_call16_SetDPCR2(int value); //16 -int dmacman_call17_GetDPCR2(); //17 -void dmacman_call18_SetDPCR3(int value); //18 -int dmacman_call19_GetDPCR3(); //19 -void dmacman_call20_SetDICR(int value); //20 -int dmacman_call21_GetDICR(); //21 -void dmacman_call22_SetDICR2(int value); //22 -int dmacman_call23_GetDICR2(); //23 -void dmacman_call24_setBF80157C(int value); //24 -int dmacman_call25_getBF80157C(); //25 -void dmacman_call26_setBF801578(int value); //26 -int dmacman_call27_getBF801578(); //27 -int dmacman_call28_SetDMA(int ch, int address, int size, int count, int dir); //28 -int dmacman_call29_SetDMA_chainedSPU_SIF0(int ch, int size, int c);//29 -int dmacman_call30_SetDMA_SIF0(int ch, int size, int c); //30 -int dmacman_call31_SetDMA_SIF1(int ch, int size); //31 -void dmacman_call32_StartTransfer(int ch); //32 -void dmacman_call33_SetVal(int ch, int value); //33 -void dmacman_call34_EnableDMAch(int ch); //34 -void dmacman_call35_DisableDMAch(int ch); //35 - -//SIF2 DMA ch 2 (GPU) -#define DMAch_SIF2_MADR (*(volatile int*)0xBF8010A0) -#define DMAch_SIF2_BCR (*(volatile int*)0xBF8010A4) -#define DMAch_SIF2_BCR_size (*(volatile short*)0xBF8010A4) -#define DMAch_SIF2_BCR_count (*(volatile short*)0xBF8010A6) -#define DMAch_SIF2_CHCR (*(volatile int*)0xBF8010A8) -//SIF0 DMA ch 9 -#define DMAch_SIF9_MADR (*(volatile int*)0xBF801520) -#define DMAch_SIF9_BCR (*(volatile int*)0xBF801524) -#define DMAch_SIF9_BCR_size (*(volatile short*)0xBF801524) -#define DMAch_SIF9_BCR_count (*(volatile short*)0xBF801526) -#define DMAch_SIF9_CHCR (*(volatile int*)0xBF801528) -#define DMAch_SIF9_TADR (*(volatile int*)0xBF80152C) -//SIF1 DMA ch 10 (0xA) -#define DMAch_SIFA_MADR (*(volatile int*)0xBF801530) -#define DMAch_SIFA_BCR (*(volatile int*)0xBF801534) -#define DMAch_SIFA_BCR_size (*(volatile short*)0xBF801534) -#define DMAch_SIFA_BCR_count (*(volatile short*)0xBF801536) -#define DMAch_SIFA_CHCR (*(volatile int*)0xBF801538) - -#define DMAch_DPCR (*(volatile int*)0xBF8010F0) -#define DMAch_DPCR2 (*(volatile int*)0xBF801570) - -#endif//__DMACMAN_H__ +#ifndef __DMACMAN_H__ +#define __DMACMAN_H__ + +#define DMACMAN_VER 0x101 + +////////////////////////////// D_CHCR - DMA Channel Control Register +#define DMAf_30 0x40000000 // unknown; set on 'to' direction +#define DMAf_TR 0x01000000 // DMA transfer +#define DMAf_LI 0x00000400 // Linked list GPU; also SPU & SIF0 +#define DMAf_CO 0x00000200 // Continuous stream +#define DMAf_08 0x00000100 // unknown +#define DMAf_DR 0x00000001 // Direction to=0/from=1 +// 31 24 23 16 15 8 7 0 +// ÖÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ· +// º ³?³ ³ ³ ³ ³ ³Tº ³ ³ ³ ³ ³ ³ ³ º ³ ³ ³ ³ ³L³C³?º ³ ³ ³ ³ ³ ³ ³Dº +// º ³?³ ³ ³ ³ ³ ³Rº ³ ³ ³ ³ ³ ³ ³ º ³ ³ ³ ³ ³I³O³?º ³ ³ ³ ³ ³ ³ ³Rº +// ÓÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁĽ +// 30 24 10 9 8 0 + +////////////////////////////// DPCR - DMA Primary Control Register +// ÖÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ· +// º 67 ³ DMA 6 º DMA 5 ³ DMA 4 º DMA 3 ³ DMA 2 º DMA 1 ³ DMA 0 º 0xBF8010F0 DPCR +// ÓÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁĽ +// ÖÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ· +// º ³ DMA85 º DMA12 ³ DMA11 º DMA10 ³ DMA 9 º DMA 8 ³ DMA 7 º 0xBF801570 DPCR_ +// ÓÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁĽ +// ÖÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄÒÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ· +// º ³ º ³ º ³ DMA15 º DMA14 ³ DMA13 º 0xBF8015F0 DPCR__ +// ÓÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÐÄÁÄÁÄÁÄÁÄÁÄÁÄÁĽ + +////////// DPCR +#define DMAch_MDECin 0 +#define DMAch_MDECout 1 +#define DMAch_GPU 2 // SIF2 both directions +#define DMAch_CD 3 +#define DMAch_SPU 4 +#define DMAch_PIO 5 +#define DMAch_GPUotc 6 + +#define DMAch_67 67 // strange + +////////// DPCR_ +#define DMAch_SPU2 7 +#define DMAch_8 8 +#define DMAch_SIF0 9 // SIFout IOP->EE +#define DMAch_SIF1 10 // SIFin EE->IOP +#define DMAch_SIO2in 11 +#define DMAch_SIO2out 12 + +#define DMAch_85 85 // stange, very strange + +////////// DPCR__ +#define DMAch_13 13 +#define DMAch_14 14 +#define DMAch_15 15 + +int dmacman_start(int argc, char* argv[]); // 0 +int dmacman_deinit(); // 2 + +void dmacman_call4_SetD_MADR(unsigned int ch, int value); // 4 +int dmacman_call5_GetD_MADR(unsigned int ch); // 5 +void dmacman_call6_SetD_BCR(unsigned int ch, int value); // 6 +int dmacman_call7_GetD_BCR(unsigned int ch); // 7 +void dmacman_call8_SetD_CHCR(unsigned int ch, int value); // 8 +int dmacman_call9_GetD_CHCR(unsigned int ch); // 9 +void dmacman_call10_SetD_TADR(unsigned int ch, int value); //10 +int dmacman_call11_GetD_TADR(unsigned int ch); //11 +void dmacman_call12_Set_4_9_A(unsigned int ch, int value); //12 +int dmacman_call13_Get_4_9_A(unsigned int ch); //13 +void dmacman_call14_SetDPCR(int value); //14 +int dmacman_call15_GetDPCR(); //15 +void dmacman_call16_SetDPCR2(int value); //16 +int dmacman_call17_GetDPCR2(); //17 +void dmacman_call18_SetDPCR3(int value); //18 +int dmacman_call19_GetDPCR3(); //19 +void dmacman_call20_SetDICR(int value); //20 +int dmacman_call21_GetDICR(); //21 +void dmacman_call22_SetDICR2(int value); //22 +int dmacman_call23_GetDICR2(); //23 +void dmacman_call24_setBF80157C(int value); //24 +int dmacman_call25_getBF80157C(); //25 +void dmacman_call26_setBF801578(int value); //26 +int dmacman_call27_getBF801578(); //27 +int dmacman_call28_SetDMA(int ch, int address, int size, int count, int dir); //28 +int dmacman_call29_SetDMA_chainedSPU_SIF0(int ch, int size, int c);//29 +int dmacman_call30_SetDMA_SIF0(int ch, int size, int c); //30 +int dmacman_call31_SetDMA_SIF1(int ch, int size); //31 +void dmacman_call32_StartTransfer(int ch); //32 +void dmacman_call33_SetVal(int ch, int value); //33 +void dmacman_call34_EnableDMAch(int ch); //34 +void dmacman_call35_DisableDMAch(int ch); //35 + +//SIF2 DMA ch 2 (GPU) +#define DMAch_SIF2_MADR (*(volatile int*)0xBF8010A0) +#define DMAch_SIF2_BCR (*(volatile int*)0xBF8010A4) +#define DMAch_SIF2_BCR_size (*(volatile short*)0xBF8010A4) +#define DMAch_SIF2_BCR_count (*(volatile short*)0xBF8010A6) +#define DMAch_SIF2_CHCR (*(volatile int*)0xBF8010A8) +//SIF0 DMA ch 9 +#define DMAch_SIF9_MADR (*(volatile int*)0xBF801520) +#define DMAch_SIF9_BCR (*(volatile int*)0xBF801524) +#define DMAch_SIF9_BCR_size (*(volatile short*)0xBF801524) +#define DMAch_SIF9_BCR_count (*(volatile short*)0xBF801526) +#define DMAch_SIF9_CHCR (*(volatile int*)0xBF801528) +#define DMAch_SIF9_TADR (*(volatile int*)0xBF80152C) +//SIF1 DMA ch 10 (0xA) +#define DMAch_SIFA_MADR (*(volatile int*)0xBF801530) +#define DMAch_SIFA_BCR (*(volatile int*)0xBF801534) +#define DMAch_SIFA_BCR_size (*(volatile short*)0xBF801534) +#define DMAch_SIFA_BCR_count (*(volatile short*)0xBF801536) +#define DMAch_SIFA_CHCR (*(volatile int*)0xBF801538) + +#define DMAch_DPCR (*(volatile int*)0xBF8010F0) +#define DMAch_DPCR2 (*(volatile int*)0xBF801570) + +#endif//__DMACMAN_H__ diff --git a/fps2bios/kernel/iopload/include/kexcepman.h b/fps2bios/kernel/iopload/include/kexcepman.h index a29909c8b0..45a1137726 100644 --- a/fps2bios/kernel/iopload/include/kexcepman.h +++ b/fps2bios/kernel/iopload/include/kexcepman.h @@ -1,23 +1,23 @@ -#ifndef __EXCEPMAN_H__ -#define __EXCEPMAN_H__ - -#define EXCEPMAN_VER 0x101 - -#define EXCEP_MAX 16 - -struct exHandler { - void *next; // next points to the next funccode :/ - int info; - u32 funccode[0]; -}; - -void *GetExHandlersTable(); // 3 - -int RegisterExceptionHandler(int code, struct exHandler *handler); // 4 -int RegisterPriorityExceptionHandler(int code, int priority, - struct exHandler *handler); // 5 -int RegisterDefaultExceptionHandler(struct exHandler *handler); // 6 -int ReleaseExceptionHandler(int excode, struct exHandler *handler); // 7 -int ReleaseDefaultExceptionHandler(struct exHandler *handler); // 8 - -#endif//__EXCEPMAN_H__ +#ifndef __EXCEPMAN_H__ +#define __EXCEPMAN_H__ + +#define EXCEPMAN_VER 0x101 + +#define EXCEP_MAX 16 + +struct exHandler { + void *next; // next points to the next funccode :/ + int info; + u32 funccode[0]; +}; + +void *GetExHandlersTable(); // 3 + +int RegisterExceptionHandler(int code, struct exHandler *handler); // 4 +int RegisterPriorityExceptionHandler(int code, int priority, + struct exHandler *handler); // 5 +int RegisterDefaultExceptionHandler(struct exHandler *handler); // 6 +int ReleaseExceptionHandler(int excode, struct exHandler *handler); // 7 +int ReleaseDefaultExceptionHandler(struct exHandler *handler); // 8 + +#endif//__EXCEPMAN_H__ diff --git a/fps2bios/kernel/iopload/include/kheaplib.h b/fps2bios/kernel/iopload/include/kheaplib.h index 618cebd16b..3bfd61268d 100644 --- a/fps2bios/kernel/iopload/include/kheaplib.h +++ b/fps2bios/kernel/iopload/include/kheaplib.h @@ -1,30 +1,30 @@ -#ifndef __HEAPLIB_H__ -#define __HEAPLIB_H__ - -struct ll{ struct ll *next, *prev; }; //linked list - - -struct Heap { - long plus_one; - int size2free; - struct ll l; - void *mem; -}; - -struct Chunk { - u32 _mem; - int freesize; - int usedsize; - u32 mem_16; - u32 unk4; - u32 unk5; -}; - -void *CreateHeap(int chunkSize, int memoryType ); -int DestroyHeap(void *heap); - -void *HeapMalloc(void *heap, int size); -int HeapFree(void *heap, void * mem); -int HeapSize(void *heap); - -#endif /* __HEAPLIB_H__ */ +#ifndef __HEAPLIB_H__ +#define __HEAPLIB_H__ + +struct ll{ struct ll *next, *prev; }; //linked list + + +struct Heap { + long plus_one; + int size2free; + struct ll l; + void *mem; +}; + +struct Chunk { + u32 _mem; + int freesize; + int usedsize; + u32 mem_16; + u32 unk4; + u32 unk5; +}; + +void *CreateHeap(int chunkSize, int memoryType ); +int DestroyHeap(void *heap); + +void *HeapMalloc(void *heap, int size); +int HeapFree(void *heap, void * mem); +int HeapSize(void *heap); + +#endif /* __HEAPLIB_H__ */ diff --git a/fps2bios/kernel/iopload/include/kintrman.h b/fps2bios/kernel/iopload/include/kintrman.h index d12407c33b..b291ed64de 100644 --- a/fps2bios/kernel/iopload/include/kintrman.h +++ b/fps2bios/kernel/iopload/include/kintrman.h @@ -1,38 +1,38 @@ -#ifndef __INTRMAN_H__ -#define __INTRMAN_H__ - -#define INTRMAN_VER 0x102 - -#define INT_VBLANK 0x00 - -#define INT_CDROM 0x02 - -#define INT_RTC0 0x04 -#define INT_RTC1 0x05 -#define INT_RTC2 0x06 - -#define INT_EVBLANK 0x0B - -#define INT_RTC3 0x0E -#define INT_RTC4 0x0F -#define INT_RTC5 0x10 - -#define INT_DMA9 0x2A //sif0 -#define INT_DMA10 0x2B //sif1 - -#define IMODE_DMA_IRM 0x100 -#define IMODE_DMA_IQE 0x200 - -typedef int (*intrh_func)(void*); - -int RegisterIntrHandler(int interrupt, int, intrh_func intrh, void*); - //4 (13,18) -int ReleaseIntrHandler(int interrupt); //5 (18) -int EnableIntr(int interrupt); //6 (13,18) -int DisableIntr(int interrupt, int *oldstat); //7 (18) -int CpuEnableIntr(); //9 (18,21,26) -int CpuSuspendIntr(u32* ictrl); //17(05,06,07,13,14,18,26) -int CpuResumeIntr(u32 ictrl); //18(05,06,07,13,14,18,26) -int QueryIntrContext(); //23(07,13) - -#endif//__INTRMAN_H__ +#ifndef __INTRMAN_H__ +#define __INTRMAN_H__ + +#define INTRMAN_VER 0x102 + +#define INT_VBLANK 0x00 + +#define INT_CDROM 0x02 + +#define INT_RTC0 0x04 +#define INT_RTC1 0x05 +#define INT_RTC2 0x06 + +#define INT_EVBLANK 0x0B + +#define INT_RTC3 0x0E +#define INT_RTC4 0x0F +#define INT_RTC5 0x10 + +#define INT_DMA9 0x2A //sif0 +#define INT_DMA10 0x2B //sif1 + +#define IMODE_DMA_IRM 0x100 +#define IMODE_DMA_IQE 0x200 + +typedef int (*intrh_func)(void*); + +int RegisterIntrHandler(int interrupt, int, intrh_func intrh, void*); + //4 (13,18) +int ReleaseIntrHandler(int interrupt); //5 (18) +int EnableIntr(int interrupt); //6 (13,18) +int DisableIntr(int interrupt, int *oldstat); //7 (18) +int CpuEnableIntr(); //9 (18,21,26) +int CpuSuspendIntr(u32* ictrl); //17(05,06,07,13,14,18,26) +int CpuResumeIntr(u32 ictrl); //18(05,06,07,13,14,18,26) +int QueryIntrContext(); //23(07,13) + +#endif//__INTRMAN_H__ diff --git a/fps2bios/kernel/iopload/include/kioman.h b/fps2bios/kernel/iopload/include/kioman.h index 26cecd687e..df8f4690d7 100644 --- a/fps2bios/kernel/iopload/include/kioman.h +++ b/fps2bios/kernel/iopload/include/kioman.h @@ -1,56 +1,56 @@ -#ifndef __IOMAN_H__ -#define __IOMAN_H__ - -#define IOMAN_VER 0x102 - -#define STDIN 0 -#define STDOUT 1 - -struct ioman_FUNCS{ - int init(struct ioman_DRV *drv); //00 - void term(struct ioman_DRV *drv); //01 - int format(char *filename); //02 - int open(int fd, char *filename, int flag); //03 - int close(int fd); //04 - int read(int fd, void *buf, int nbyte); //05 - int write(int fd, void *buf, int nbyte); //06 - int lseek(int fd, int offset, int whence); //07 - int ioctl(int fd, int request, int arg); //08 - int remove(char *filename); //09 - int mkdir(char *filename); //10 - int rmdir(char *filename); //11 - int dopen(char *filename); //12 - int dclose(int fd); //13 - int dread(int fd, void *buf); //14 - int getstat(char *filename, void *buf); //15 - int chstat(char *filename, void *buf, unsigned int mask); //16 -}; - -struct ioman_DRV{ //struct fileio_driver from ps2lib - char *driver; //+00 - int unk1; //+04 - int version; //+08 - char *description; //+0C - struct ioman_FUNCS *f_list; //+10 -}; //=14 - -int open(char *filename, int flag); // 4(26) -int close(int fd); // 5(26) -int read(int fd, void *buf, long count); // 6(17,26) -int write(int fd, void *buf, long count); // 7(17,26) -int lseek(int fd, int offset, int whence); // 8(26) -int ioctl(int fd, int request, int arg); // 9(26) -int remove(char *filename); //10(26) -int mkdir(char *filename); //11(26) -int rmdir(char *filename); //12(26) -int dopen(char *filename); //13(26) -int dclose(int fd); //14(26) -int dread(int fd, void *buf); //15(26) -int getstat(char *filename, void *buf); //16(26) -int chstat(char *filename, void *buf, unsigned int mask); //17(26) -int format(char *filename); //18(26) -int AddDrv(struct ioman_DRV *drv); //20(26) -int DelDrv(char *device); //21(26) - -#endif//__IOMAN_H__ - +#ifndef __IOMAN_H__ +#define __IOMAN_H__ + +#define IOMAN_VER 0x102 + +#define STDIN 0 +#define STDOUT 1 + +struct ioman_FUNCS{ + int init(struct ioman_DRV *drv); //00 + void term(struct ioman_DRV *drv); //01 + int format(char *filename); //02 + int open(int fd, char *filename, int flag); //03 + int close(int fd); //04 + int read(int fd, void *buf, int nbyte); //05 + int write(int fd, void *buf, int nbyte); //06 + int lseek(int fd, int offset, int whence); //07 + int ioctl(int fd, int request, int arg); //08 + int remove(char *filename); //09 + int mkdir(char *filename); //10 + int rmdir(char *filename); //11 + int dopen(char *filename); //12 + int dclose(int fd); //13 + int dread(int fd, void *buf); //14 + int getstat(char *filename, void *buf); //15 + int chstat(char *filename, void *buf, unsigned int mask); //16 +}; + +struct ioman_DRV{ //struct fileio_driver from ps2lib + char *driver; //+00 + int unk1; //+04 + int version; //+08 + char *description; //+0C + struct ioman_FUNCS *f_list; //+10 +}; //=14 + +int open(char *filename, int flag); // 4(26) +int close(int fd); // 5(26) +int read(int fd, void *buf, long count); // 6(17,26) +int write(int fd, void *buf, long count); // 7(17,26) +int lseek(int fd, int offset, int whence); // 8(26) +int ioctl(int fd, int request, int arg); // 9(26) +int remove(char *filename); //10(26) +int mkdir(char *filename); //11(26) +int rmdir(char *filename); //12(26) +int dopen(char *filename); //13(26) +int dclose(int fd); //14(26) +int dread(int fd, void *buf); //15(26) +int getstat(char *filename, void *buf); //16(26) +int chstat(char *filename, void *buf, unsigned int mask); //17(26) +int format(char *filename); //18(26) +int AddDrv(struct ioman_DRV *drv); //20(26) +int DelDrv(char *device); //21(26) + +#endif//__IOMAN_H__ + diff --git a/fps2bios/kernel/iopload/include/kloadcore.h b/fps2bios/kernel/iopload/include/kloadcore.h index bac1206320..8454919e76 100644 --- a/fps2bios/kernel/iopload/include/kloadcore.h +++ b/fps2bios/kernel/iopload/include/kloadcore.h @@ -1,89 +1,89 @@ -#ifndef __LOADCORE_H__ -#define __LOADCORE_H__ - -#include - -#define LOADCORE_VER 0x101 - -typedef int (*func)(); - -#define VER(major, minor) ((((major) & 0xFF)<<8) + ((minor) & 0xFF)) - -#define MODULE_RESIDENT_END 0 -#define MODULE_NO_RESIDENT_END 1 - -struct func_stub { - int jr_ra; //jump instruction - int addiu0; //addiu zero, number -}; - -// defined by irx.h in the sdk -//#define IMPORT_MAGIC 0x41E00000 -//#define EXPORT_MAGIC 0x41C00000 - -#define FLAG_EXPORT_QUEUED 1 -#define FLAG_IMPORT_QUEUED 2 - -#define FLAG_NO_AUTO_LINK 1 - -#define INS_JR 2 -#define INS_ADDIU 9 -#define INS_JR_RA 0x03E00008 -#define INS_J 0x08000000 - -enum tag_BOOTUPCB_PRIO{ - BOOTUPCB_FIRST = 0, - BOOTUPCB_RUN_UDNL = 1, - BOOTUPCB_NORMAL = 2, - BOOTUPCB_LAST = 3, - BOOTUPCB_PRIORITIES -} BOOTUPCB_PRIO; - -struct import { - u32 magic; //0x41E00000 - struct import *next; - short version; //mjmi (mj=major, mi=minor version numbers) - short flags; //=0 - char name[8]; - struct func_stub func[0]; //the last one is 0, 0 (i.e. nop, nop) -}; - -struct export { - u32 magic_link; //0x41C00000, prev - struct export *next; - short version; //mjmi (mj=major, mi=minor version numbers) - short flags; //=0 - char name[8]; - func func[45]; //usually module entry point (allways?) -// func1 -// func2 -// func3 -// funcs // more functions: the services provided my module -}; - -struct bootmode { - short unk0; - char id; - char len; - int data[0]; -}; - -typedef struct boot_params { - int ramMBSize; //+00/0 size of iop ram in megabytes (2 or 8) - int bootInfo; //+04/1 ==QueryBootMode(KEY_IOPbootinfo) - char* udnlString; //+08/2 points to the undl reboot string, NULL if no string - u32 firstModuleAddr;//+0C/3 the load address of the first module (sysmem) - int pos; //+10/4 - int size; //+14/5 - int numConfLines; //+18/6 number of lines in IOPBTCONF - u32** moduleAddrs; //+1C/7 pointer to an array of addresses to load modules from -} BOOT_PARAMS; //=20 - -void FlushIcache(); //4 (14) -void FlushDcache(); //5 (14,21,26) -int RegisterLibraryEntries(struct export*); //6 (05,06,07,13,14,17,18,28) -u32* QueryBootMode(int code); //12(11,21,25,26,28) -int loadcore_call20_registerFunc(int (*function)(int *, int), int a1, int *result); - //20(28) - -#endif//__LOADCORE_H__ +#ifndef __LOADCORE_H__ +#define __LOADCORE_H__ + +#include + +#define LOADCORE_VER 0x101 + +typedef int (*func)(); + +#define VER(major, minor) ((((major) & 0xFF)<<8) + ((minor) & 0xFF)) + +#define MODULE_RESIDENT_END 0 +#define MODULE_NO_RESIDENT_END 1 + +struct func_stub { + int jr_ra; //jump instruction + int addiu0; //addiu zero, number +}; + +// defined by irx.h in the sdk +//#define IMPORT_MAGIC 0x41E00000 +//#define EXPORT_MAGIC 0x41C00000 + +#define FLAG_EXPORT_QUEUED 1 +#define FLAG_IMPORT_QUEUED 2 + +#define FLAG_NO_AUTO_LINK 1 + +#define INS_JR 2 +#define INS_ADDIU 9 +#define INS_JR_RA 0x03E00008 +#define INS_J 0x08000000 + +enum tag_BOOTUPCB_PRIO{ + BOOTUPCB_FIRST = 0, + BOOTUPCB_RUN_UDNL = 1, + BOOTUPCB_NORMAL = 2, + BOOTUPCB_LAST = 3, + BOOTUPCB_PRIORITIES +} BOOTUPCB_PRIO; + +struct import { + u32 magic; //0x41E00000 + struct import *next; + short version; //mjmi (mj=major, mi=minor version numbers) + short flags; //=0 + char name[8]; + struct func_stub func[0]; //the last one is 0, 0 (i.e. nop, nop) +}; + +struct export { + u32 magic_link; //0x41C00000, prev + struct export *next; + short version; //mjmi (mj=major, mi=minor version numbers) + short flags; //=0 + char name[8]; + func func[45]; //usually module entry point (allways?) +// func1 +// func2 +// func3 +// funcs // more functions: the services provided my module +}; + +struct bootmode { + short unk0; + char id; + char len; + int data[0]; +}; + +typedef struct boot_params { + int ramMBSize; //+00/0 size of iop ram in megabytes (2 or 8) + int bootInfo; //+04/1 ==QueryBootMode(KEY_IOPbootinfo) + char* udnlString; //+08/2 points to the undl reboot string, NULL if no string + u32 firstModuleAddr;//+0C/3 the load address of the first module (sysmem) + int pos; //+10/4 + int size; //+14/5 + int numConfLines; //+18/6 number of lines in IOPBTCONF + u32** moduleAddrs; //+1C/7 pointer to an array of addresses to load modules from +} BOOT_PARAMS; //=20 + +void FlushIcache(); //4 (14) +void FlushDcache(); //5 (14,21,26) +int RegisterLibraryEntries(struct export*); //6 (05,06,07,13,14,17,18,28) +u32* QueryBootMode(int code); //12(11,21,25,26,28) +int loadcore_call20_registerFunc(int (*function)(int *, int), int a1, int *result); + //20(28) + +#endif//__LOADCORE_H__ diff --git a/fps2bios/kernel/iopload/include/ksifcmd.h b/fps2bios/kernel/iopload/include/ksifcmd.h index 710a1385ba..166673d61b 100644 --- a/fps2bios/kernel/iopload/include/ksifcmd.h +++ b/fps2bios/kernel/iopload/include/ksifcmd.h @@ -1,162 +1,162 @@ -#ifndef __SIFCMD_H__ -#define __SIFCMD_H__ - -#define SIFCMD_VER 0x101 - -#define SIF_CMDI_SYSTEM 0x80000000 // system function call -#define SIF_CMDC_CHANGE_SADDR ( SIF_CMDI_SYSTEM | 0x00000000) -#define SIF_CMDC_SET_SREG ( SIF_CMDI_SYSTEM | 0x00000001) -#define SIF_CMDC_INIT_CMD ( SIF_CMDI_SYSTEM | 0x00000002) -#define SIF_CMDC_RESET_CMD ( SIF_CMDI_SYSTEM | 0x00000003) - -#define SIF_CMDC_RPC_END ( SIF_CMDI_SYSTEM | 0x00000008) -#define SIF_CMDC_RPC_BIND ( SIF_CMDI_SYSTEM | 0x00000009) -#define SIF_CMDC_RPC_CALL ( SIF_CMDI_SYSTEM | 0x0000000A) -#define SIF_CMDC_RPC_RDATA ( SIF_CMDI_SYSTEM | 0x0000000C) - -typedef struct { - unsigned int psize:8; // packet size [16->112] - unsigned int dsize:24;// extra data size - unsigned int daddr; // extra data address - unsigned int fcode; // function code - unsigned int opt; // optional user parameter -} SifCmdHdr; - -typedef int (*cmdh_func) (SifCmdHdr*, void*); -typedef void *(*rpch_func)(u32 code, void *param1, int param2); - -typedef struct { - SifCmdHdr hdr; - void *newaddr; -} SifCmdCSData; - -typedef struct { - SifCmdHdr chdr; - int rno; - unsigned int value; -} SifCmdSRData; - -typedef struct { - SifCmdHdr chdr; - int size; - int flag; - char arg[80]; -} SifCmdResetData; - -struct sifcmd_RPC_SERVER_DATA{ //t_rpc_server_data - int command; /* 04 00 */ - - rpch_func func; /* 05 01 */ - void *buff; /* 06 02 */ - int size; /* 07 03 */ - - rpch_func cfunc; /* 08 04 */ - void *cbuff; /* 09 05 */ - int csize; /* 10 06 */ - - struct sifcmd_RPC_CLIENT_DATA*client; /* 11 07 */ - void *pkt_addr; /* 12 08 */ - int fno; /* 13 09 */ - - void *receive; /* 14 10 */ - int rsize; /* 15 11 */ - int rmode; /* 16 12 */ - int rid; /* 17 13 */ - - struct sifcmd_RPC_SERVER_DATA*link; /* 18 14 */ - struct sifcmd_RPC_SERVER_DATA*next; /* 19 15 */ - struct sifcmd_RPC_DATA_QUEUE *base; /* 20 16 */ -}; - - -struct sifcmd_RPC_HEADER{ //t_rpc_header - void *pkt_addr; /* 04 00 */ - u32 rpc_id; /* 05 01 */ - int tid; /* 06 02 */ - u32 mode; /* 07 03 */ -}; - - -struct sifcmd_RPC_CLIENT_DATA{ //t_rpc_client_data - struct sifcmd_RPC_HEADER hdr; - u32 command; /* 04 08 */ - void *buff, /* 05 09 */ - *cbuff; /* 06 10 */ - void (*func)(void*); /* 07 11 */ - void *param; /* 08 12*/ - struct sifcmd_RPC_SERVER_DATA*server; /* 09 13 */ -}; - -struct sifcmd_RPC_RECEIVE_DATA{ //t_rpc_receive_data - struct sifcmd_RPC_HEADER hdr; - void *src, /* 04 */ - *dest; /* 05 */ - int size; /* 06 */ -}; - -struct sifcmd_RPC_DATA_QUEUE{ //t_rpc_data_queue - int key, /* 00 */ - active; /* 01 */ - struct sifcmd_RPC_SERVER_DATA*link, /* 02 */ - *start, /* 03 */ - *end; /* 04 */ - struct sifcmd_RPC_DATA_QUEUE *next; /* 05 */ -}; - -typedef struct { - SifCmdHdr hdr; - u32 rec_id; - void *paddr; - u32 pid; -} RPC_PACKET; - -typedef struct { - RPC_PACKET packet; - struct sifcmd_RPC_CLIENT_DATA *client; - u32 command; - struct sifcmd_RPC_SERVER_DATA *server; - void *buff, *cbuff; -} RPC_PACKET_END; - -typedef struct { - RPC_PACKET packet; - struct sifcmd_RPC_CLIENT_DATA *client; - u32 fno; -} RPC_PACKET_BIND; - -typedef struct { - RPC_PACKET_BIND packet; - u32 size; - void *receive; - u32 rsize; - u32 rmode; - struct sifcmd_RPC_SERVER_DATA *server; -} RPC_PACKET_CALL; - -typedef struct { - RPC_PACKET packet; - struct sifcmd_RPC_CLIENT_DATA *client; - void *src; - void *dst; - u32 size; -} RPC_PACKET_RDATA; - - -typedef struct { - cmdh_func func; - void *data; -} SifCmdData; - -void SifInitCmd(); //4 (21) -void SifAddCmdHandler(int pos, cmdh_func func, void *data); //10(21) -void SifInitRpc(int mode); //14(26) -void SifRegisterRpc(struct sifcmd_RPC_SERVER_DATA *sd, u32 cmd, - rpch_func func, void *buff, - rpch_func cfunc, void *cbuff, - struct sifcmd_RPC_DATA_QUEUE *dq); //17(26) -void SifSetRpcQueue(struct sifcmd_RPC_DATA_QUEUE* dq, int thid); //19(26) -void SifRpcLoop(struct sifcmd_RPC_DATA_QUEUE* dq); //22(26) -int SifGetOtherData(struct sifcmd_RPC_RECEIVE_DATA *rd, - void *src, void *dst, int size, int mode); //23(26) - -#endif//__SIFCMD_H__ +#ifndef __SIFCMD_H__ +#define __SIFCMD_H__ + +#define SIFCMD_VER 0x101 + +#define SIF_CMDI_SYSTEM 0x80000000 // system function call +#define SIF_CMDC_CHANGE_SADDR ( SIF_CMDI_SYSTEM | 0x00000000) +#define SIF_CMDC_SET_SREG ( SIF_CMDI_SYSTEM | 0x00000001) +#define SIF_CMDC_INIT_CMD ( SIF_CMDI_SYSTEM | 0x00000002) +#define SIF_CMDC_RESET_CMD ( SIF_CMDI_SYSTEM | 0x00000003) + +#define SIF_CMDC_RPC_END ( SIF_CMDI_SYSTEM | 0x00000008) +#define SIF_CMDC_RPC_BIND ( SIF_CMDI_SYSTEM | 0x00000009) +#define SIF_CMDC_RPC_CALL ( SIF_CMDI_SYSTEM | 0x0000000A) +#define SIF_CMDC_RPC_RDATA ( SIF_CMDI_SYSTEM | 0x0000000C) + +typedef struct { + unsigned int psize:8; // packet size [16->112] + unsigned int dsize:24;// extra data size + unsigned int daddr; // extra data address + unsigned int fcode; // function code + unsigned int opt; // optional user parameter +} SifCmdHdr; + +typedef int (*cmdh_func) (SifCmdHdr*, void*); +typedef void *(*rpch_func)(u32 code, void *param1, int param2); + +typedef struct { + SifCmdHdr hdr; + void *newaddr; +} SifCmdCSData; + +typedef struct { + SifCmdHdr chdr; + int rno; + unsigned int value; +} SifCmdSRData; + +typedef struct { + SifCmdHdr chdr; + int size; + int flag; + char arg[80]; +} SifCmdResetData; + +struct sifcmd_RPC_SERVER_DATA{ //t_rpc_server_data + int command; /* 04 00 */ + + rpch_func func; /* 05 01 */ + void *buff; /* 06 02 */ + int size; /* 07 03 */ + + rpch_func cfunc; /* 08 04 */ + void *cbuff; /* 09 05 */ + int csize; /* 10 06 */ + + struct sifcmd_RPC_CLIENT_DATA*client; /* 11 07 */ + void *pkt_addr; /* 12 08 */ + int fno; /* 13 09 */ + + void *receive; /* 14 10 */ + int rsize; /* 15 11 */ + int rmode; /* 16 12 */ + int rid; /* 17 13 */ + + struct sifcmd_RPC_SERVER_DATA*link; /* 18 14 */ + struct sifcmd_RPC_SERVER_DATA*next; /* 19 15 */ + struct sifcmd_RPC_DATA_QUEUE *base; /* 20 16 */ +}; + + +struct sifcmd_RPC_HEADER{ //t_rpc_header + void *pkt_addr; /* 04 00 */ + u32 rpc_id; /* 05 01 */ + int tid; /* 06 02 */ + u32 mode; /* 07 03 */ +}; + + +struct sifcmd_RPC_CLIENT_DATA{ //t_rpc_client_data + struct sifcmd_RPC_HEADER hdr; + u32 command; /* 04 08 */ + void *buff, /* 05 09 */ + *cbuff; /* 06 10 */ + void (*func)(void*); /* 07 11 */ + void *param; /* 08 12*/ + struct sifcmd_RPC_SERVER_DATA*server; /* 09 13 */ +}; + +struct sifcmd_RPC_RECEIVE_DATA{ //t_rpc_receive_data + struct sifcmd_RPC_HEADER hdr; + void *src, /* 04 */ + *dest; /* 05 */ + int size; /* 06 */ +}; + +struct sifcmd_RPC_DATA_QUEUE{ //t_rpc_data_queue + int key, /* 00 */ + active; /* 01 */ + struct sifcmd_RPC_SERVER_DATA*link, /* 02 */ + *start, /* 03 */ + *end; /* 04 */ + struct sifcmd_RPC_DATA_QUEUE *next; /* 05 */ +}; + +typedef struct { + SifCmdHdr hdr; + u32 rec_id; + void *paddr; + u32 pid; +} RPC_PACKET; + +typedef struct { + RPC_PACKET packet; + struct sifcmd_RPC_CLIENT_DATA *client; + u32 command; + struct sifcmd_RPC_SERVER_DATA *server; + void *buff, *cbuff; +} RPC_PACKET_END; + +typedef struct { + RPC_PACKET packet; + struct sifcmd_RPC_CLIENT_DATA *client; + u32 fno; +} RPC_PACKET_BIND; + +typedef struct { + RPC_PACKET_BIND packet; + u32 size; + void *receive; + u32 rsize; + u32 rmode; + struct sifcmd_RPC_SERVER_DATA *server; +} RPC_PACKET_CALL; + +typedef struct { + RPC_PACKET packet; + struct sifcmd_RPC_CLIENT_DATA *client; + void *src; + void *dst; + u32 size; +} RPC_PACKET_RDATA; + + +typedef struct { + cmdh_func func; + void *data; +} SifCmdData; + +void SifInitCmd(); //4 (21) +void SifAddCmdHandler(int pos, cmdh_func func, void *data); //10(21) +void SifInitRpc(int mode); //14(26) +void SifRegisterRpc(struct sifcmd_RPC_SERVER_DATA *sd, u32 cmd, + rpch_func func, void *buff, + rpch_func cfunc, void *cbuff, + struct sifcmd_RPC_DATA_QUEUE *dq); //17(26) +void SifSetRpcQueue(struct sifcmd_RPC_DATA_QUEUE* dq, int thid); //19(26) +void SifRpcLoop(struct sifcmd_RPC_DATA_QUEUE* dq); //22(26) +int SifGetOtherData(struct sifcmd_RPC_RECEIVE_DATA *rd, + void *src, void *dst, int size, int mode); //23(26) + +#endif//__SIFCMD_H__ diff --git a/fps2bios/kernel/iopload/include/ksifman.h b/fps2bios/kernel/iopload/include/ksifman.h index 89840cbb58..94434545c6 100644 --- a/fps2bios/kernel/iopload/include/ksifman.h +++ b/fps2bios/kernel/iopload/include/ksifman.h @@ -1,57 +1,57 @@ -#ifndef __SIFMAN_H__ -#define __SIFMAN_H__ - -#include - -#define SIFMAN_VER 0x101 - -#define SIF_FROM_IOP 0x0 -#define SIF_TO_IOP 0x1 -#define SIF_FROM_EE 0x0 -#define SIF_TO_EE 0x1 - -#define SIF_DMA_INT_I 0x2 -#define SIF_DMA_INT_O 0x4 -#define SIF_DMA_SPR 0x8 -#define SIF_DMA_BSN 0x10 -#define SIF_DMA_TAG 0x20 - -struct sifman_DMA { //t_sif_dma_transfer - void *data; - void *addr; - int size; - int attr; -}; - -void SifDeinit(); //2 - -void SifSIF2Init(); //4 -void SifInit(); //5 (21,25,26) -void SifSetDChain(); //6 -u32 SifSetDma(struct sifman_DMA* psd, int len); //7 (26) -int SifDmaStat(u32 id); //8 (26) -void SifSend(struct sifman_DMA sd); //9 -void SifSendSync(); //10 -int SifIsSending(); //11 -void SifSetSIF0DMA(void *data, int size, int attr); //12 -void SifSendSync0(); //13 -int SifIsSending0(); //14 -void SifSetSIF1DMA(void *data, int size, int attr); //15 -void SifSendSync1(); //16 -int SifIsSending1(); //17 -void SifSetSIF2DMA(void *data, int size, int attr); //18 -void SifSendSync2(); //19 -int SifIsSending2(); //20 -int SifGetEEIOPflags(); //21 -int SifSetEEIOPflags(int val); //22(21) -int SifGetIOPEEflags(); //23 -int SifSetIOPEEflags(int val); //24(28) -int SifGetEErcvaddr(); //25 -int SifGetIOPrcvaddr(); //26 -int SifSetIOPrcvaddr(int val); //27 -void SifSet1450_2(); //28 -int SifCheckInit(); //29(21,26) -void SifSet0CB(int (*_function)(int), int _param);//30 -void SifReset0CB(); //31 - -#endif /* __SIFMAN_H__ */ +#ifndef __SIFMAN_H__ +#define __SIFMAN_H__ + +#include + +#define SIFMAN_VER 0x101 + +#define SIF_FROM_IOP 0x0 +#define SIF_TO_IOP 0x1 +#define SIF_FROM_EE 0x0 +#define SIF_TO_EE 0x1 + +#define SIF_DMA_INT_I 0x2 +#define SIF_DMA_INT_O 0x4 +#define SIF_DMA_SPR 0x8 +#define SIF_DMA_BSN 0x10 +#define SIF_DMA_TAG 0x20 + +struct sifman_DMA { //t_sif_dma_transfer + void *data; + void *addr; + int size; + int attr; +}; + +void SifDeinit(); //2 + +void SifSIF2Init(); //4 +void SifInit(); //5 (21,25,26) +void SifSetDChain(); //6 +u32 SifSetDma(struct sifman_DMA* psd, int len); //7 (26) +int SifDmaStat(u32 id); //8 (26) +void SifSend(struct sifman_DMA sd); //9 +void SifSendSync(); //10 +int SifIsSending(); //11 +void SifSetSIF0DMA(void *data, int size, int attr); //12 +void SifSendSync0(); //13 +int SifIsSending0(); //14 +void SifSetSIF1DMA(void *data, int size, int attr); //15 +void SifSendSync1(); //16 +int SifIsSending1(); //17 +void SifSetSIF2DMA(void *data, int size, int attr); //18 +void SifSendSync2(); //19 +int SifIsSending2(); //20 +int SifGetEEIOPflags(); //21 +int SifSetEEIOPflags(int val); //22(21) +int SifGetIOPEEflags(); //23 +int SifSetIOPEEflags(int val); //24(28) +int SifGetEErcvaddr(); //25 +int SifGetIOPrcvaddr(); //26 +int SifSetIOPrcvaddr(int val); //27 +void SifSet1450_2(); //28 +int SifCheckInit(); //29(21,26) +void SifSet0CB(int (*_function)(int), int _param);//30 +void SifReset0CB(); //31 + +#endif /* __SIFMAN_H__ */ diff --git a/fps2bios/kernel/iopload/include/kstdio.h b/fps2bios/kernel/iopload/include/kstdio.h index 0c392e3c77..8877f32ccc 100644 --- a/fps2bios/kernel/iopload/include/kstdio.h +++ b/fps2bios/kernel/iopload/include/kstdio.h @@ -1,21 +1,21 @@ -#ifndef __STDIO_H__ -#define __STDIO_H__ - -#define STDIO_VER 0x102 - -#define TAB 0x9 //\t -#define LF 0x10 //\n -#define CR 0x13 //\r - -void printf(const char *format, ...); // 4(21,25,26) -int getchar(); // 5 -//int putchar(int c); // 6 -int puts(char *s); // 7 -char *gets(char *s); // 8 -int fdprintf(int fd, const char *format, ...); // 9 -int fdgetc(int fd); //10 -int fdputc(int c, int fd); //11 -int fdputs(char *s, int fd); //12 -char *fdgets(char *buf, int fd); //13 - -#endif//__STDIO_H__ +#ifndef __STDIO_H__ +#define __STDIO_H__ + +#define STDIO_VER 0x102 + +#define TAB 0x9 //\t +#define LF 0x10 //\n +#define CR 0x13 //\r + +void printf(const char *format, ...); // 4(21,25,26) +int getchar(); // 5 +//int putchar(int c); // 6 +int puts(char *s); // 7 +char *gets(char *s); // 8 +int fdprintf(int fd, const char *format, ...); // 9 +int fdgetc(int fd); //10 +int fdputc(int c, int fd); //11 +int fdputs(char *s, int fd); //12 +char *fdgets(char *buf, int fd); //13 + +#endif//__STDIO_H__ diff --git a/fps2bios/kernel/iopload/include/ksysclib.h b/fps2bios/kernel/iopload/include/ksysclib.h index bf7213cfdb..d73f83d662 100644 --- a/fps2bios/kernel/iopload/include/ksysclib.h +++ b/fps2bios/kernel/iopload/include/ksysclib.h @@ -1,46 +1,46 @@ -#ifndef __SYSCLIB_H__ -#define __SYSCLIB_H__ - -#define SYSCLIB_VER 0x101 - -#include - -#define _U 01 -#define _L 02 -#define _N 04 -#define _S 010 -#define _P 020 -#define _C 040 -#define _X 0100 -#define _B 0200 - -extern const char _ctype_[]; - -#ifndef __cplusplus -#define isalpha(c) ((_ctype_+1)[(unsigned)(c)]&(_U|_L)) -#define isupper(c) ((_ctype_+1)[(unsigned)(c)]&_U) -#define islower(c) ((_ctype_+1)[(unsigned)(c)]&_L) -#define isdigit(c) ((_ctype_+1)[(unsigned)(c)]&_N) -#define isxdigit(c) ((_ctype_+1)[(unsigned)(c)]&(_X|_N)) -#define isspace(c) ((_ctype_+1)[(unsigned)(c)]&_S) -#define ispunct(c) ((_ctype_+1)[(unsigned)(c)]&_P) -#define isalnum(c) ((_ctype_+1)[(unsigned)(c)]&(_U|_L|_N)) -#define isprint(c) ((_ctype_+1)[(unsigned)(c)]&(_P|_U|_L|_N|_B)) -#define isgraph(c) ((_ctype_+1)[(unsigned)(c)]&(_P|_U|_L|_N)) -#define iscntrl(c) ((_ctype_+1)[(unsigned)(c)]&_C) -#endif /* !__cplusplus */ - -#define isascii(c) ((unsigned)(c)<=0177) -#define toascii(c) ((c)&0177) - -unsigned char look_ctype_table(int pos); -void* memset(void *s, int c, size_t n); -void bzero(void *s, size_t n); -int strcmp (const char *, const char *); -char* index (const char *s, int c); -int strlen (const char *); -char* strncpy(char *dest, const char *src, size_t n); -long int strtol(const char *nptr, char **endptr, int base); -//int prnt(void (*func)(void*, int), int *v, const char *format, ...); //18(17) - -#endif//__SYSCLIB_H__ +#ifndef __SYSCLIB_H__ +#define __SYSCLIB_H__ + +#define SYSCLIB_VER 0x101 + +#include + +#define _U 01 +#define _L 02 +#define _N 04 +#define _S 010 +#define _P 020 +#define _C 040 +#define _X 0100 +#define _B 0200 + +extern const char _ctype_[]; + +#ifndef __cplusplus +#define isalpha(c) ((_ctype_+1)[(unsigned)(c)]&(_U|_L)) +#define isupper(c) ((_ctype_+1)[(unsigned)(c)]&_U) +#define islower(c) ((_ctype_+1)[(unsigned)(c)]&_L) +#define isdigit(c) ((_ctype_+1)[(unsigned)(c)]&_N) +#define isxdigit(c) ((_ctype_+1)[(unsigned)(c)]&(_X|_N)) +#define isspace(c) ((_ctype_+1)[(unsigned)(c)]&_S) +#define ispunct(c) ((_ctype_+1)[(unsigned)(c)]&_P) +#define isalnum(c) ((_ctype_+1)[(unsigned)(c)]&(_U|_L|_N)) +#define isprint(c) ((_ctype_+1)[(unsigned)(c)]&(_P|_U|_L|_N|_B)) +#define isgraph(c) ((_ctype_+1)[(unsigned)(c)]&(_P|_U|_L|_N)) +#define iscntrl(c) ((_ctype_+1)[(unsigned)(c)]&_C) +#endif /* !__cplusplus */ + +#define isascii(c) ((unsigned)(c)<=0177) +#define toascii(c) ((c)&0177) + +unsigned char look_ctype_table(int pos); +void* memset(void *s, int c, size_t n); +void bzero(void *s, size_t n); +int strcmp (const char *, const char *); +char* index (const char *s, int c); +int strlen (const char *); +char* strncpy(char *dest, const char *src, size_t n); +long int strtol(const char *nptr, char **endptr, int base); +//int prnt(void (*func)(void*, int), int *v, const char *format, ...); //18(17) + +#endif//__SYSCLIB_H__ diff --git a/fps2bios/kernel/iopload/include/ksysmem.h b/fps2bios/kernel/iopload/include/ksysmem.h index d6de342ac9..97234350c6 100644 --- a/fps2bios/kernel/iopload/include/ksysmem.h +++ b/fps2bios/kernel/iopload/include/ksysmem.h @@ -1,27 +1,27 @@ -#ifndef __SYSMEM_H__ -#define __SYSMEM_H__ - -#include - -#define SYSMEM_VER 0x101 - -//allocation strategies -#define ALLOC_FIRST 0 -#define ALLOC_LAST 1 -#define ALLOC_LATER 2 - -// see QueryBlockTopAddress, QueryBlockSize -#define USED 0x00000000 -#define FREE 0x80000000 - -void *AllocSysMemory(int flags, int size, void *mem);//4 (11,26) -int FreeSysMemory(void *mem); //5 (26) -unsigned int QueryMemSize(); -unsigned int QueryMaxFreeMemSize(); -unsigned int QueryTotalFreeMemSize(); -void *QueryBlockTopAddress(void *address); -int QueryBlockSize(void *address); -char *Kprintf(const char *format,...); //14(06,14,26) -void sysmem_call15_set_Kprintf(char* (*newKprintf)(unsigned int unk, const char*, ...), unsigned int newunk); - -#endif //__SYSMEM_H__ +#ifndef __SYSMEM_H__ +#define __SYSMEM_H__ + +#include + +#define SYSMEM_VER 0x101 + +//allocation strategies +#define ALLOC_FIRST 0 +#define ALLOC_LAST 1 +#define ALLOC_LATER 2 + +// see QueryBlockTopAddress, QueryBlockSize +#define USED 0x00000000 +#define FREE 0x80000000 + +void *AllocSysMemory(int flags, int size, void *mem);//4 (11,26) +int FreeSysMemory(void *mem); //5 (26) +unsigned int QueryMemSize(); +unsigned int QueryMaxFreeMemSize(); +unsigned int QueryTotalFreeMemSize(); +void *QueryBlockTopAddress(void *address); +int QueryBlockSize(void *address); +char *Kprintf(const char *format,...); //14(06,14,26) +void sysmem_call15_set_Kprintf(char* (*newKprintf)(unsigned int unk, const char*, ...), unsigned int newunk); + +#endif //__SYSMEM_H__ diff --git a/fps2bios/kernel/iopload/include/kthbase.h b/fps2bios/kernel/iopload/include/kthbase.h index 3b4000881b..818096ebe0 100644 --- a/fps2bios/kernel/iopload/include/kthbase.h +++ b/fps2bios/kernel/iopload/include/kthbase.h @@ -1,19 +1,19 @@ -#ifndef __THBASE_H__ -#define __THBASE_H__ - -#define THBASE_VER 0x101 - -struct thbase_thread{ - unsigned int attr; - unsigned int option; - int (*entry)(); - unsigned int stackSize; - unsigned int initPriority; -}; - -int CreateThread(struct thbase_thread*); //4 (21,26) //returns thid -void StartThread(int thid, int); //6 (21,26) -int GetThreadId(); //20(26) //returns thid? -int GetSystemStatusFlag(); //41(13,21) - -#endif//__THBASE_H__ +#ifndef __THBASE_H__ +#define __THBASE_H__ + +#define THBASE_VER 0x101 + +struct thbase_thread{ + unsigned int attr; + unsigned int option; + int (*entry)(); + unsigned int stackSize; + unsigned int initPriority; +}; + +int CreateThread(struct thbase_thread*); //4 (21,26) //returns thid +void StartThread(int thid, int); //6 (21,26) +int GetThreadId(); //20(26) //returns thid? +int GetSystemStatusFlag(); //41(13,21) + +#endif//__THBASE_H__ diff --git a/fps2bios/kernel/iopload/include/kthsemap.h b/fps2bios/kernel/iopload/include/kthsemap.h index b89eed2b21..2a8718cc81 100644 --- a/fps2bios/kernel/iopload/include/kthsemap.h +++ b/fps2bios/kernel/iopload/include/kthsemap.h @@ -1,17 +1,17 @@ -#ifndef __THSEMAP_H__ -#define __THSEMAP_H__ - -#define THSEMAP_VER 0x101 - -struct thsema_sema{ - unsigned int attr; - unsigned int option; - int initCount; - int maxCount; -}; - -int CreateSema(struct thsema_sema* sema); // 4(15) -int SignalSema(int semaid); // 6(15) -int WaitSema(int semaid); // 8(15) - -#endif//__THSEMAP_H__ +#ifndef __THSEMAP_H__ +#define __THSEMAP_H__ + +#define THSEMAP_VER 0x101 + +struct thsema_sema{ + unsigned int attr; + unsigned int option; + int initCount; + int maxCount; +}; + +int CreateSema(struct thsema_sema* sema); // 4(15) +int SignalSema(int semaid); // 6(15) +int WaitSema(int semaid); // 8(15) + +#endif//__THSEMAP_H__ diff --git a/fps2bios/kernel/iopload/include/ktimrman.h b/fps2bios/kernel/iopload/include/ktimrman.h index 7a3b4a5ca5..5a34bdca28 100644 --- a/fps2bios/kernel/iopload/include/ktimrman.h +++ b/fps2bios/kernel/iopload/include/ktimrman.h @@ -1,48 +1,48 @@ -#ifndef __TIMEMAN_H__ -#define __TIMEMAN_H__ - -#define TIMEMAN_VER 0x101 - -//timids << 2; use AllocHardTimer or ReferHardTimer to get one -#define RTC0 0xBF801100 -#define RTC1 0xBF801110 -#define RTC2 0xBF801120 - -#define RTC3 0xBF801480 -#define RTC4 0xBF801490 -#define RTC5 0xBF8014A0 - -#define RTC_HOLDREGS 0xBF8014B0 -#define RTC_HOLDMODE (*(volatile unsigned int*)0xBF8014C0) - -//source -#define TC_SYSCLOCK 1 -#define TC_PIXEL 2 -#define TC_HLINE 4 -#define TC_HOLD 8 - -//size -#define TIMER_SIZE_16 16 -#define TIMER_SIZE_32 32 - -//prescale -#define TIMER_PRESCALE_1 1 -#define TIMER_PRESCALE_8 8 -#define TIMER_PRESCALE_16 16 -#define TIMER_PRESCALE_256 256 - -int AllocHardTimer(int source, int size, int prescale); //4 -int ReferHardTimer(int source, int size, int mode, int modemask);//5 -int FreeHardTimer(int timid); //6 -void SetTimerMode(int timid, int mode); //7 -unsigned int GetTimerStatus(int timid); //8 -void SetTimerCounter(int timid, unsigned int count); //9 -unsigned int GetTimerCounter(int timid); //10 -void SetTimerCompare(int timid, unsigned int compare); //11 -unsigned int GetTimerCompare(int timid); //12 -void SetHoldMode(int holdnum, int mode); //13 -unsigned long GetHoldMode(int holdnum); //14 -unsigned long GetHoldReg(int holdnum); //15 -int GetHardTimerIntrCode(int timid); //16 - +#ifndef __TIMEMAN_H__ +#define __TIMEMAN_H__ + +#define TIMEMAN_VER 0x101 + +//timids << 2; use AllocHardTimer or ReferHardTimer to get one +#define RTC0 0xBF801100 +#define RTC1 0xBF801110 +#define RTC2 0xBF801120 + +#define RTC3 0xBF801480 +#define RTC4 0xBF801490 +#define RTC5 0xBF8014A0 + +#define RTC_HOLDREGS 0xBF8014B0 +#define RTC_HOLDMODE (*(volatile unsigned int*)0xBF8014C0) + +//source +#define TC_SYSCLOCK 1 +#define TC_PIXEL 2 +#define TC_HLINE 4 +#define TC_HOLD 8 + +//size +#define TIMER_SIZE_16 16 +#define TIMER_SIZE_32 32 + +//prescale +#define TIMER_PRESCALE_1 1 +#define TIMER_PRESCALE_8 8 +#define TIMER_PRESCALE_16 16 +#define TIMER_PRESCALE_256 256 + +int AllocHardTimer(int source, int size, int prescale); //4 +int ReferHardTimer(int source, int size, int mode, int modemask);//5 +int FreeHardTimer(int timid); //6 +void SetTimerMode(int timid, int mode); //7 +unsigned int GetTimerStatus(int timid); //8 +void SetTimerCounter(int timid, unsigned int count); //9 +unsigned int GetTimerCounter(int timid); //10 +void SetTimerCompare(int timid, unsigned int compare); //11 +unsigned int GetTimerCompare(int timid); //12 +void SetHoldMode(int holdnum, int mode); //13 +unsigned long GetHoldMode(int holdnum); //14 +unsigned long GetHoldReg(int holdnum); //15 +int GetHardTimerIntrCode(int timid); //16 + #endif//__TIMEMAN_H__ \ No newline at end of file diff --git a/fps2bios/kernel/iopload/include/romdir.h b/fps2bios/kernel/iopload/include/romdir.h index e01eb98342..abbc3b429c 100644 --- a/fps2bios/kernel/iopload/include/romdir.h +++ b/fps2bios/kernel/iopload/include/romdir.h @@ -1,115 +1,115 @@ -#ifndef __ROMDIR_H__ -#define __ROMDIR_H__ - -#include - -// an entry in a romdir table. a romdir table is an array of these. -// gets filled in by searchRomDir() -typedef struct romdir_entry { - char name[10]; //+00 - short extSize; //+0A - int fileSize; //+0C -} __attribute__ ((packed)) ROMDIR_ENTRY; - - -// info about a file in a romdir -// gets filled in by searchFileInRom() -typedef struct { - ROMDIR_ENTRY* entry; // pointer to the file's ROMDIR_ENTRY - u32 fileData; // address of file contents - u32 extData; // address of file's ext info -} ROMFILE_INFO; - -// info about the location of a romdir table -typedef struct { - u32 romPtr; //+00 - ROMDIR_ENTRY* romdirPtr;//+04 - u32 extinfoPtr; //+08 -} ROMDIR_INFO; - -typedef struct romfs { - char* filename; //+00 - int fd; //+04 - int size; //+08 - ROMDIR_INFO romdirInfo; //+0C -} ROMFS; - -// rounds off a value to the next multiple -#define ROUND_UP(num, multiple) (((num)+multiple-1) & (~(multiple-1))) - -// searches between beginning and end addresses for a romdir structure. -// if found it returns info about it in romDirInfo. -// -// args: address to start searching from -// address to stop searching at -// gets filled in with info if found -// returns: a pointer to the filled in romDirInfo if successful -// NULL if error -extern ROMDIR_INFO* searchRomDir(const u32* searchStartAddr, const u32* searchEndAddr, ROMDIR_INFO* romDirInfo); - -// find a file in the romdir table and return info about it -// -// args: info about romdir to search through -// filename to search for -// structure to get info about file into -// returns: a pointer to fileinfo if successful -// NULL otherwise -extern ROMFILE_INFO* searchFileInRom(const ROMDIR_INFO* romdirInfo, const char* filename, ROMFILE_INFO* fileinfo); - -// gets a hex number from *addr and updates the pointer -// -// args: pointer to string buffer containing a hex number -// returns: the value of the hex number -extern u32 getHexNumber(char** addr); - -/* -IOPBTCONF file format -===================== -each line is one of this: - -1. loading address of IOP kernel -Format: @ -Example: @800 -Default: 0 -Description: starting with (or 0 if not specified) the loader will - place modules in memory on 256 boundaries at +0x30 (the first 48 bytes are - reserved for info about the following module) - -2. address of function to be called while loading of IOP kernel -Format: !addr -Description: the code indicated by will be run on kernel loading - -3. name of (parent) included IOPBTCONF -Format: !include -Description: allow to have another file with same format to be loaded - recursively; support for this is limited because of the BUGGY parsing; -Note: you can have such option only at the begining of IOPBTCONF and the - inclusion can be made without getting stucked in recursion like this: - -ioprp1.img contains IOPBTCONF1 (!include IOPBTCON2) and IOPBTCONF11 -ioprp2.img contains IOPBTCONF2 (!include IOPBTCONF1) -ioprp.img contains IOPBTCONF (!include IOPBTCONF2!include IOPBTCONF11) -rom0 contains IOPBTCONF and IOPBTCON2 - -udnl cdrom0:ioprp1.img cdrom0:ioprp2.img cdrom0:ioprp.img - -the starting of the chain can be named IOPBTCONF only -also you can include only from the previous romz - -4. comment -Format: # -Example: #APPLOAD -Description: you can have comments on a line that starts with # - -5. modules that have to be loaded after a reset -Format: -Example: SYSMEM -Description: each line of IOPBTCONF usualy have a module name; the order the - modules appear in the list is the order they are loaded as IOP kernel --------------------------------- -Notes: - - each line ends with , that is 0x0A - - in the final loading list the first 2 positions must be SYSMEM and LOADCORE -*/ - -#endif /* __ROMDIR_H__ */ +#ifndef __ROMDIR_H__ +#define __ROMDIR_H__ + +#include + +// an entry in a romdir table. a romdir table is an array of these. +// gets filled in by searchRomDir() +typedef struct romdir_entry { + char name[10]; //+00 + short extSize; //+0A + int fileSize; //+0C +} __attribute__ ((packed)) ROMDIR_ENTRY; + + +// info about a file in a romdir +// gets filled in by searchFileInRom() +typedef struct { + ROMDIR_ENTRY* entry; // pointer to the file's ROMDIR_ENTRY + u32 fileData; // address of file contents + u32 extData; // address of file's ext info +} ROMFILE_INFO; + +// info about the location of a romdir table +typedef struct { + u32 romPtr; //+00 + ROMDIR_ENTRY* romdirPtr;//+04 + u32 extinfoPtr; //+08 +} ROMDIR_INFO; + +typedef struct romfs { + char* filename; //+00 + int fd; //+04 + int size; //+08 + ROMDIR_INFO romdirInfo; //+0C +} ROMFS; + +// rounds off a value to the next multiple +#define ROUND_UP(num, multiple) (((num)+multiple-1) & (~(multiple-1))) + +// searches between beginning and end addresses for a romdir structure. +// if found it returns info about it in romDirInfo. +// +// args: address to start searching from +// address to stop searching at +// gets filled in with info if found +// returns: a pointer to the filled in romDirInfo if successful +// NULL if error +extern ROMDIR_INFO* searchRomDir(const u32* searchStartAddr, const u32* searchEndAddr, ROMDIR_INFO* romDirInfo); + +// find a file in the romdir table and return info about it +// +// args: info about romdir to search through +// filename to search for +// structure to get info about file into +// returns: a pointer to fileinfo if successful +// NULL otherwise +extern ROMFILE_INFO* searchFileInRom(const ROMDIR_INFO* romdirInfo, const char* filename, ROMFILE_INFO* fileinfo); + +// gets a hex number from *addr and updates the pointer +// +// args: pointer to string buffer containing a hex number +// returns: the value of the hex number +extern u32 getHexNumber(char** addr); + +/* +IOPBTCONF file format +===================== +each line is one of this: + +1. loading address of IOP kernel +Format: @ +Example: @800 +Default: 0 +Description: starting with (or 0 if not specified) the loader will + place modules in memory on 256 boundaries at +0x30 (the first 48 bytes are + reserved for info about the following module) + +2. address of function to be called while loading of IOP kernel +Format: !addr +Description: the code indicated by will be run on kernel loading + +3. name of (parent) included IOPBTCONF +Format: !include +Description: allow to have another file with same format to be loaded + recursively; support for this is limited because of the BUGGY parsing; +Note: you can have such option only at the begining of IOPBTCONF and the + inclusion can be made without getting stucked in recursion like this: + +ioprp1.img contains IOPBTCONF1 (!include IOPBTCON2) and IOPBTCONF11 +ioprp2.img contains IOPBTCONF2 (!include IOPBTCONF1) +ioprp.img contains IOPBTCONF (!include IOPBTCONF2!include IOPBTCONF11) +rom0 contains IOPBTCONF and IOPBTCON2 + +udnl cdrom0:ioprp1.img cdrom0:ioprp2.img cdrom0:ioprp.img + +the starting of the chain can be named IOPBTCONF only +also you can include only from the previous romz + +4. comment +Format: # +Example: #APPLOAD +Description: you can have comments on a line that starts with # + +5. modules that have to be loaded after a reset +Format: +Example: SYSMEM +Description: each line of IOPBTCONF usualy have a module name; the order the + modules appear in the list is the order they are loaded as IOP kernel +-------------------------------- +Notes: + - each line ends with , that is 0x0A + - in the final loading list the first 2 positions must be SYSMEM and LOADCORE +*/ + +#endif /* __ROMDIR_H__ */ diff --git a/fps2bios/kernel/iopload/intrman/Makefile b/fps2bios/kernel/iopload/intrman/Makefile index 2e84af2bd7..0811b161ca 100644 --- a/fps2bios/kernel/iopload/intrman/Makefile +++ b/fps2bios/kernel/iopload/intrman/Makefile @@ -1,61 +1,61 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include - -IOPCFLAGS = -O0 -g -fomit-frame-pointer -nostartfiles -G0 --save-temps -IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include -IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -IOPLINK = $(IOPLD) -dc -IOPASFLAGS := -EL -G0 - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: intrman - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib -LDADD = -OBJECTS = int_handler.o intrman.o ../iopdebug.o ../libkernel/iop_loadcore.o ../libkernel/iop_excepman.o - -intrman: $(OBJECTS) - $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/INTRMAN - -%.o: %.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - -%.o : %.S - $(IOPAS) $(IOPASFLAGS) $< -o $@ -%.o : %.s - $(IOPAS) $(IOPASFLAGS) $< -o $@ - -clean: - rm -f $(OBJECTS) - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O0 -g -fomit-frame-pointer -nostartfiles -G0 --save-temps +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: intrman + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib +LDADD = +OBJECTS = int_handler.o intrman.o ../iopdebug.o ../libkernel/iop_loadcore.o ../libkernel/iop_excepman.o + +intrman: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/INTRMAN + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.S + $(IOPAS) $(IOPASFLAGS) $< -o $@ +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/iopboot/Makefile b/fps2bios/kernel/iopload/iopboot/Makefile index 8450079bb4..e9cc754b2b 100644 --- a/fps2bios/kernel/iopload/iopboot/Makefile +++ b/fps2bios/kernel/iopload/iopboot/Makefile @@ -1,59 +1,59 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include - -IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 -IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include -IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -IOPLINK = $(IOPLD) -dc -IOPASFLAGS := -EL -G0 - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: iopboot - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -nostartfiles -L$(PS2LIB)/iop/lib -LDADD = -OBJECTS = iopboot.o ../iopdebug.o ../iopelf.o ../romdir.o - -iopboot: $(OBJECTS) - $(EELD) -Wl,--oformat,binary,--Map,iopboot.map -T linkfile $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/IOPBOOT - -%.o: %.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - -%.o : %.s - $(IOPAS) $(IOPASFLAGS) $< -o $@ - -clean: - rm -f $(OBJECTS) - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: iopboot + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -nostartfiles -L$(PS2LIB)/iop/lib +LDADD = +OBJECTS = iopboot.o ../iopdebug.o ../iopelf.o ../romdir.o + +iopboot: $(OBJECTS) + $(EELD) -Wl,--oformat,binary,--Map,iopboot.map -T linkfile $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/IOPBOOT + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/iopboot/iopboot.c b/fps2bios/kernel/iopload/iopboot/iopboot.c index 481755eb9b..edd3da1909 100644 --- a/fps2bios/kernel/iopload/iopboot/iopboot.c +++ b/fps2bios/kernel/iopload/iopboot/iopboot.c @@ -1,252 +1,252 @@ -// -// iopboot.c -// -// this is the c code for the iopboot file in the ps2 rom. -// this file is located at 0xBFC4A000 in the ps2 bios rom0. -// modload.irx also from the ps2 bios executes this direct from the rom -// (no loading to ram first) -// -// this is based on florin's disasm and converted to c code by xorloser and zerofrog -// - -#include -#include - -#include "iopload.h" -#include "iopdebug.h" -#include "iopelf.h" -#include "romdir.h" -#include "kloadcore.h" - -static void kstrcpy(char* dst, const char* src); -static int kstrlen(const char* src); - -//BOOT_PARAMS boot_params; -//u32* next_free_address[0x40]; // up to 64 modules - - -// this is the start point of execution at 0xBFC4A000 -// -// it loads the IOPBTCONF module list from rom0 and compiles a -// list of modules and their addresses. -// -// this list is then passed to loadcore as it is executed in order -// to then load the rest of the modules -// -// args: total size of IOP ram in MegaBytes -// bootinfo flags -// string containing the reboot image filepath -// ? doesnt seem to be used -void _start(int ramMBSize, int bootInfo, char* udnlString, int unk) -{ - ROMFS ri; - void *(*sysmem_entry)(u32 iopmemsize); - void (*loadcore_entry)(BOOT_PARAMS *init); - int i; - ROMDIR_INFO romdir_info; - ROMFILE_INFO romfile_info; - char conf_filename[10]; - int ram_byte_size, num_lines; - u32 module_load_addr; - u32** modules_ptr; - char* file_data_ptr, *file_data_end; - void* psysmemstart; - BOOT_PARAMS* boot_params; - - if( ramMBSize <= 2 ) - ram_byte_size = 2; - else - ram_byte_size = ramMBSize; - ram_byte_size <<= 20; - - // compile module list to send to loadcore - boot_params = (BOOT_PARAMS*)0x30000; // random address, has to be clear before loadcore call - boot_params->ramMBSize = ramMBSize; - boot_params->bootInfo = bootInfo; - boot_params->udnlString = NULL; - boot_params->moduleAddrs = (u32**)((u32)boot_params + sizeof(BOOT_PARAMS)); // right after - - // if a undl string is specified, get a copy of it and store a pointer to it - if(udnlString) - { - boot_params->udnlString = (char*)boot_params->moduleAddrs; - kstrcpy(boot_params->udnlString, udnlString); - boot_params->moduleAddrs = (u32**)((u32)boot_params->udnlString + ROUND_UP(kstrlen(udnlString) + 8, 4)); - } - - // find the romdir table in the rom - if( searchRomDir((u32*)0xBFC00000, (u32*)0xBFC10000, &romdir_info) == NULL ) - { - __printf("IOPBOOT: failed to find start of rom!\n"); - // error - cant find romdir! - while(1) *(u8*)0x80000000 = 0; - } - - // find the bootconf file in the romdir table - kstrcpy(conf_filename, "IOPBTCONF"); - conf_filename[8] = '0' + bootInfo; - if( !searchFileInRom(&romdir_info, conf_filename, &romfile_info) ) - { - kstrcpy(conf_filename, "IOPBTCONF"); - if( !searchFileInRom(&romdir_info, conf_filename, &romfile_info) ) - { - __printf("IOPBTCONF file not found!\n"); - // error - cant find conf file! - while(1) *(u8*)0x80000000 = 1; - } - } - - // count the number of lines in conf file - file_data_ptr = (char*)romfile_info.fileData; - file_data_end = (char*)romfile_info.fileData + romfile_info.entry->fileSize; - { - num_lines = 0; - while( file_data_ptr < file_data_end ) { - // loop until a "newline" charcter is found - while(file_data_ptr < file_data_end) { - if(*file_data_ptr++ < ' ') - break; - } - - // loop until a "non-newline" charcter is found - while(file_data_ptr < file_data_end) { - if(*file_data_ptr++ >= ' ') - break; - } - - num_lines++; - } - num_lines++; - } - - // get the addresses of each module - { - module_load_addr = 0; - boot_params->numConfLines = num_lines-1; - modules_ptr = boot_params->moduleAddrs; - char* file_data_ptr = (char*)romfile_info.fileData; - while( file_data_ptr < file_data_end ) { - if(*file_data_ptr == '@') { - file_data_ptr++; - module_load_addr = getHexNumber(&file_data_ptr); - } - else if(*file_data_ptr == '!') { - if( file_data_ptr[1] == 'a' && - file_data_ptr[2] == 'd' && - file_data_ptr[3] == 'd' && - file_data_ptr[4] == 'r' && - file_data_ptr[5] == ' ' ) { - file_data_ptr += 6; - *modules_ptr++ = (u32*)(getHexNumber(&file_data_ptr) * 4 + 1); - *modules_ptr++ = 0; - } - } - else if(*file_data_ptr != '#') { - // 'file_data_ptr' should be pointing to a filename - // this finds the address of that file in the rom - ROMFILE_INFO module_fileinfo; - char strmodule[16]; - for(i = 0; i < 16; ++i) { - if( file_data_ptr[i] < ' ' ) - break; - strmodule[i] = file_data_ptr[i]; - } - strmodule[i] = 0; - - if( searchFileInRom(&romdir_info, strmodule, &module_fileinfo) == NULL ) { - __printf("IOPBOOT: failed to find %s module\n", strmodule); - return; - } - - //__printf("mod: %s:%x\n", strmodule, module_fileinfo.fileData); - - *modules_ptr++ = (u32*)module_fileinfo.fileData; - *modules_ptr = 0; // don't increment - } - - // loop until a "newline" charcter is found - while(file_data_ptr < file_data_end) { - if(*file_data_ptr++ < ' ') - break; - } - - // loop until a "non-newline" charcter is found - while(file_data_ptr < file_data_end) { - if(*file_data_ptr >= ' ') - break; - file_data_ptr++; - } - } - } - - if( searchFileInRom(&romdir_info, "IOPBOOT", &romfile_info) == NULL ) { - __printf("loadElfFile: failed to find IOPBOOT module\n"); - return; - } - - // load sysmem module to memory and execute it - if( searchFileInRom(&romdir_info, "SYSMEM", &romfile_info) == NULL ) { - __printf("loadElfFile: failed to find SYSMEM module\n"); - return; - } - sysmem_entry = (void *(*)(u32))loadElfFile(&romfile_info, module_load_addr); - if( sysmem_entry == 0 ) - return; - - psysmemstart = sysmem_entry(ram_byte_size); - //FlushIcache(); - if( psysmemstart == 0 ) { - __printf("IOPBOOT: sysmem failed\n"); - return; - } - - __printf("SYSMEM success, start addr: %x, alloc start: %x\n", module_load_addr, psysmemstart); - - if( searchFileInRom(&romdir_info, "LOADCORE", &romfile_info) == NULL ) { - __printf("loadElfFile: failed to find SYSMEM module\n"); - return; - } - loadcore_entry = (void (*)())loadElfFile(&romfile_info, (u32)psysmemstart); - if( loadcore_entry == 0 ) - return; - - boot_params->firstModuleAddr = (u32)module_load_addr + 0x30; // skip elf? - if(0x1FC10000 < ram_byte_size) { - boot_params->pos = 0x1FC00000; - boot_params->size = 0x10100; - } - else { - boot_params->pos = 0; - boot_params->size = 0; - } - - __printf("executing LOADCORE entry at %p\n", loadcore_entry); - loadcore_entry(boot_params); - - __printf("iopboot error\n"); - - // error - loadcore shouldnt ever return - while(1) *(u8*)0x80000000 = 2; -} - -void Kmemcpy(void *dest, const void *src, int n) { - const u8 *s = (u8*)src; - u8 *d = (u8*)dest; - - while (n) { - *d++ = *s++; n--; - } -} - -static void kstrcpy(char* dst, const char* src) -{ - while(*src) *dst++ = *src++; - *dst = 0; -} - -static int kstrlen(const char* src) -{ - int len = 0; - while(*src++) len++; - return len; -} +// +// iopboot.c +// +// this is the c code for the iopboot file in the ps2 rom. +// this file is located at 0xBFC4A000 in the ps2 bios rom0. +// modload.irx also from the ps2 bios executes this direct from the rom +// (no loading to ram first) +// +// this is based on florin's disasm and converted to c code by xorloser and zerofrog +// + +#include +#include + +#include "iopload.h" +#include "iopdebug.h" +#include "iopelf.h" +#include "romdir.h" +#include "kloadcore.h" + +static void kstrcpy(char* dst, const char* src); +static int kstrlen(const char* src); + +//BOOT_PARAMS boot_params; +//u32* next_free_address[0x40]; // up to 64 modules + + +// this is the start point of execution at 0xBFC4A000 +// +// it loads the IOPBTCONF module list from rom0 and compiles a +// list of modules and their addresses. +// +// this list is then passed to loadcore as it is executed in order +// to then load the rest of the modules +// +// args: total size of IOP ram in MegaBytes +// bootinfo flags +// string containing the reboot image filepath +// ? doesnt seem to be used +void _start(int ramMBSize, int bootInfo, char* udnlString, int unk) +{ + ROMFS ri; + void *(*sysmem_entry)(u32 iopmemsize); + void (*loadcore_entry)(BOOT_PARAMS *init); + int i; + ROMDIR_INFO romdir_info; + ROMFILE_INFO romfile_info; + char conf_filename[10]; + int ram_byte_size, num_lines; + u32 module_load_addr; + u32** modules_ptr; + char* file_data_ptr, *file_data_end; + void* psysmemstart; + BOOT_PARAMS* boot_params; + + if( ramMBSize <= 2 ) + ram_byte_size = 2; + else + ram_byte_size = ramMBSize; + ram_byte_size <<= 20; + + // compile module list to send to loadcore + boot_params = (BOOT_PARAMS*)0x30000; // random address, has to be clear before loadcore call + boot_params->ramMBSize = ramMBSize; + boot_params->bootInfo = bootInfo; + boot_params->udnlString = NULL; + boot_params->moduleAddrs = (u32**)((u32)boot_params + sizeof(BOOT_PARAMS)); // right after + + // if a undl string is specified, get a copy of it and store a pointer to it + if(udnlString) + { + boot_params->udnlString = (char*)boot_params->moduleAddrs; + kstrcpy(boot_params->udnlString, udnlString); + boot_params->moduleAddrs = (u32**)((u32)boot_params->udnlString + ROUND_UP(kstrlen(udnlString) + 8, 4)); + } + + // find the romdir table in the rom + if( searchRomDir((u32*)0xBFC00000, (u32*)0xBFC10000, &romdir_info) == NULL ) + { + __printf("IOPBOOT: failed to find start of rom!\n"); + // error - cant find romdir! + while(1) *(u8*)0x80000000 = 0; + } + + // find the bootconf file in the romdir table + kstrcpy(conf_filename, "IOPBTCONF"); + conf_filename[8] = '0' + bootInfo; + if( !searchFileInRom(&romdir_info, conf_filename, &romfile_info) ) + { + kstrcpy(conf_filename, "IOPBTCONF"); + if( !searchFileInRom(&romdir_info, conf_filename, &romfile_info) ) + { + __printf("IOPBTCONF file not found!\n"); + // error - cant find conf file! + while(1) *(u8*)0x80000000 = 1; + } + } + + // count the number of lines in conf file + file_data_ptr = (char*)romfile_info.fileData; + file_data_end = (char*)romfile_info.fileData + romfile_info.entry->fileSize; + { + num_lines = 0; + while( file_data_ptr < file_data_end ) { + // loop until a "newline" charcter is found + while(file_data_ptr < file_data_end) { + if(*file_data_ptr++ < ' ') + break; + } + + // loop until a "non-newline" charcter is found + while(file_data_ptr < file_data_end) { + if(*file_data_ptr++ >= ' ') + break; + } + + num_lines++; + } + num_lines++; + } + + // get the addresses of each module + { + module_load_addr = 0; + boot_params->numConfLines = num_lines-1; + modules_ptr = boot_params->moduleAddrs; + char* file_data_ptr = (char*)romfile_info.fileData; + while( file_data_ptr < file_data_end ) { + if(*file_data_ptr == '@') { + file_data_ptr++; + module_load_addr = getHexNumber(&file_data_ptr); + } + else if(*file_data_ptr == '!') { + if( file_data_ptr[1] == 'a' && + file_data_ptr[2] == 'd' && + file_data_ptr[3] == 'd' && + file_data_ptr[4] == 'r' && + file_data_ptr[5] == ' ' ) { + file_data_ptr += 6; + *modules_ptr++ = (u32*)(getHexNumber(&file_data_ptr) * 4 + 1); + *modules_ptr++ = 0; + } + } + else if(*file_data_ptr != '#') { + // 'file_data_ptr' should be pointing to a filename + // this finds the address of that file in the rom + ROMFILE_INFO module_fileinfo; + char strmodule[16]; + for(i = 0; i < 16; ++i) { + if( file_data_ptr[i] < ' ' ) + break; + strmodule[i] = file_data_ptr[i]; + } + strmodule[i] = 0; + + if( searchFileInRom(&romdir_info, strmodule, &module_fileinfo) == NULL ) { + __printf("IOPBOOT: failed to find %s module\n", strmodule); + return; + } + + //__printf("mod: %s:%x\n", strmodule, module_fileinfo.fileData); + + *modules_ptr++ = (u32*)module_fileinfo.fileData; + *modules_ptr = 0; // don't increment + } + + // loop until a "newline" charcter is found + while(file_data_ptr < file_data_end) { + if(*file_data_ptr++ < ' ') + break; + } + + // loop until a "non-newline" charcter is found + while(file_data_ptr < file_data_end) { + if(*file_data_ptr >= ' ') + break; + file_data_ptr++; + } + } + } + + if( searchFileInRom(&romdir_info, "IOPBOOT", &romfile_info) == NULL ) { + __printf("loadElfFile: failed to find IOPBOOT module\n"); + return; + } + + // load sysmem module to memory and execute it + if( searchFileInRom(&romdir_info, "SYSMEM", &romfile_info) == NULL ) { + __printf("loadElfFile: failed to find SYSMEM module\n"); + return; + } + sysmem_entry = (void *(*)(u32))loadElfFile(&romfile_info, module_load_addr); + if( sysmem_entry == 0 ) + return; + + psysmemstart = sysmem_entry(ram_byte_size); + //FlushIcache(); + if( psysmemstart == 0 ) { + __printf("IOPBOOT: sysmem failed\n"); + return; + } + + __printf("SYSMEM success, start addr: %x, alloc start: %x\n", module_load_addr, psysmemstart); + + if( searchFileInRom(&romdir_info, "LOADCORE", &romfile_info) == NULL ) { + __printf("loadElfFile: failed to find SYSMEM module\n"); + return; + } + loadcore_entry = (void (*)())loadElfFile(&romfile_info, (u32)psysmemstart); + if( loadcore_entry == 0 ) + return; + + boot_params->firstModuleAddr = (u32)module_load_addr + 0x30; // skip elf? + if(0x1FC10000 < ram_byte_size) { + boot_params->pos = 0x1FC00000; + boot_params->size = 0x10100; + } + else { + boot_params->pos = 0; + boot_params->size = 0; + } + + __printf("executing LOADCORE entry at %p\n", loadcore_entry); + loadcore_entry(boot_params); + + __printf("iopboot error\n"); + + // error - loadcore shouldnt ever return + while(1) *(u8*)0x80000000 = 2; +} + +void Kmemcpy(void *dest, const void *src, int n) { + const u8 *s = (u8*)src; + u8 *d = (u8*)dest; + + while (n) { + *d++ = *s++; n--; + } +} + +static void kstrcpy(char* dst, const char* src) +{ + while(*src) *dst++ = *src++; + *dst = 0; +} + +static int kstrlen(const char* src) +{ + int len = 0; + while(*src++) len++; + return len; +} diff --git a/fps2bios/kernel/iopload/iopboot/iopirq.c b/fps2bios/kernel/iopload/iopboot/iopirq.c index 853d0b223f..36565b88da 100644 --- a/fps2bios/kernel/iopload/iopboot/iopirq.c +++ b/fps2bios/kernel/iopload/iopboot/iopirq.c @@ -1,17 +1,17 @@ - - -// Boiler plate exception handlers used at boot time. -// EXCEPMAN replaces these with something more useful. - -__asm__(".org 0x0000"); - -__asm__(".set noreorder"); -void CpuException0() { -} - -__asm__(".org 0x0080"); - -__asm__(".set noreorder"); -void CpuException() { -} - + + +// Boiler plate exception handlers used at boot time. +// EXCEPMAN replaces these with something more useful. + +__asm__(".org 0x0000"); + +__asm__(".set noreorder"); +void CpuException0() { +} + +__asm__(".org 0x0080"); + +__asm__(".set noreorder"); +void CpuException() { +} + diff --git a/fps2bios/kernel/iopload/iopdebug.c b/fps2bios/kernel/iopload/iopdebug.c index a5551a46e5..2b69b8f5bc 100644 --- a/fps2bios/kernel/iopload/iopdebug.c +++ b/fps2bios/kernel/iopload/iopdebug.c @@ -1,279 +1,279 @@ -/* Debugging printf, for debugging the library itself. - - We don't assume stdio is working. - We do assume _write_r is working. -*/ - -#include "iopload.h" -#include "iopdebug.h" - -#ifdef __STDC__ -#include "stdarg.h" -#else -#include "varargs.h" -#endif - -static char *parse_number (); -static long get_number (); -static void print_number (); -static void write_char (char c); -static void write_string (char* s); - -/* Non-zero for big-endian systems. */ -static int big_endian_p; - -/* For now hardcode 2 (stderr) as the console file descriptor. - May wish to let the caller pass in a file descriptor or some such but - this is only for debugging purposes anyway. */ -#define CONSOLE_FD 2 - -/* Standalone printf routine. - - The format string has been enhanced so that multiple values can be dumped - without having to have a %-field for each one (say if you want to dump - 20 words at a certain address). A modifier of `N' says the next argument - is a count, and the one after that is a pointer. - - Example: __dprintf (stderr, "%Nx\n", 20, p); /-* print 20 ints at `p' *-/ - - Supported formats are: c d u x s p. - - All ints are retrieved a byte at a time so alignment issues are not - a problem. - - This routine is used in situations where the only debugging capability - is console output and was written to aid debugging newlib itself. We don't - use printf ourselves as we may be debugging it. We do assume _write_r is - working. -*/ - -void -#ifdef __STDC__ -__printf (char *fmt, ...) -#else -__printf (fmt, va_alist) - char *fmt; - va_dcl -#endif -{ - va_list args; - - /* Which endian are we? */ - { - short tmp = 1; - big_endian_p = *(char *) &tmp == 0; - } - -#ifdef __STDC__ - va_start (args, fmt); -#else - va_start (args); -#endif - - while (*fmt) - { - char c, *p; - int count; - long l; - - if (*fmt != '%' || *++fmt == '%') - { - write_char (*fmt++); - continue; - } - - if (*fmt == 'N') - { - count = va_arg (args, int); - p = va_arg (args, char *); - ++fmt; - c = *fmt++; - - while (--count >= 0) - { - switch (c) - { -// case 'c' : -// write_string (unctrl (*p++)); -// break; - case 'p' : - print_number (16, 1, get_number (p, sizeof (char *), 1)); - p += sizeof (char *); - break; - case 'd' : - case 'u' : - case 'x' : - print_number (c == 'x' ? 16 : 10, c != 'd', - get_number (p, sizeof (int), c != 'd')); - p += sizeof (int); - break; - case 's' : - write_string (*(char **) p); - p += sizeof (char *); - break; - } - if (count > 0) - write_char (' '); - } - } - else - { - switch (c = *fmt++) - { -// case 'c' : -// c = va_arg (args, int); -// write_string (unctrl (c)); -// break; - case 'p' : - l = (void *) va_arg (args, char *); - print_number (16, 1, l); - break; - case 'd' : - case 'u' : - case 'x' : - l = va_arg (args, int); - print_number (c == 'x' ? 16 : 10, c != 'd', l); - break; - case 's' : - p = va_arg (args, char *); - write_string (p); - break; - } - } - } - - va_end (args); -} - -static int isdigit(int c) { - if (c >= '0' && c <= '9') return 1; - return 0; -} - -/* Parse a positive decimal integer at S. - FIXME: Was used in earlier version, but not currently used. - Keep for now. */ - -static char * -parse_number (s, p) - char *s; - long *p; -{ - long x = 0; - - while (isdigit (*s)) - { - x = (x * 10) + (*s - '0'); - ++s; - } - - *p = x; - return s; -} - -/* Fetch the number at S of SIZE bytes. */ - -static long -get_number (s, size, unsigned_p) - char *s; - long size; - int unsigned_p; -{ - long x; - unsigned char *p = (unsigned char *) s; - - switch (size) - { - case 1 : - x = *p; - if (!unsigned_p) - x = (x ^ 0x80) - 0x80; - return x; - case 2 : - if (big_endian_p) - x = (p[0] << 8) | p[1]; - else - x = (p[1] << 8) | p[0]; - if (!unsigned_p) - x = (x ^ 0x8000) - 0x8000; - return x; - case 4 : - if (big_endian_p) - x = ((long)p[0] << 24) | ((long)p[1] << 16) | (p[2] << 8) | p[3]; - else - x = ((long)p[3] << 24) | ((long)p[2] << 16) | (p[1] << 8) | p[0]; - if (!unsigned_p) - x = (x ^ 0x80000000L) - 0x80000000L; - return x; -#if 0 /* FIXME: Is there a standard mechanism for knowing if - long longs exist? */ - case 8 : -#endif - default : - return 0; - } -} - -/* Print X in base BASE. */ - -static void -print_number (base, unsigned_p, n) - int base; - int unsigned_p; - long n; -{ - static char chars[16] = "0123456789abcdef"; - char *p, buf[32]; - unsigned long x; - - if (!unsigned_p && n < 0) - { - write_char ('-'); - x = -n; - } - else - x = n; - - p = buf + sizeof (buf); - *--p = '\0'; - do - { - *--p = chars[x % base]; - x /= base; - } - while (x != 0); - - write_string (p); -} - -/* Write C to the console. - We go through the file descriptor directly because we can't assume - stdio is working. */ - -static void -write_char (char c) -{ - __putc(c); -} - -/* Write S to the console. - We go through the file descriptor directly because we can't assume - stdio is working. */ - -static void -write_string (char *s) -{ - __puts(s); -} - - -void __putc(u8 c) { - *((u8*)0x1f80380c) = c; -} - -void __puts(u8 *s) { - while (*s != 0) { - __putc(*s++); - } -} - +/* Debugging printf, for debugging the library itself. + + We don't assume stdio is working. + We do assume _write_r is working. +*/ + +#include "iopload.h" +#include "iopdebug.h" + +#ifdef __STDC__ +#include "stdarg.h" +#else +#include "varargs.h" +#endif + +static char *parse_number (); +static long get_number (); +static void print_number (); +static void write_char (char c); +static void write_string (char* s); + +/* Non-zero for big-endian systems. */ +static int big_endian_p; + +/* For now hardcode 2 (stderr) as the console file descriptor. + May wish to let the caller pass in a file descriptor or some such but + this is only for debugging purposes anyway. */ +#define CONSOLE_FD 2 + +/* Standalone printf routine. + + The format string has been enhanced so that multiple values can be dumped + without having to have a %-field for each one (say if you want to dump + 20 words at a certain address). A modifier of `N' says the next argument + is a count, and the one after that is a pointer. + + Example: __dprintf (stderr, "%Nx\n", 20, p); /-* print 20 ints at `p' *-/ + + Supported formats are: c d u x s p. + + All ints are retrieved a byte at a time so alignment issues are not + a problem. + + This routine is used in situations where the only debugging capability + is console output and was written to aid debugging newlib itself. We don't + use printf ourselves as we may be debugging it. We do assume _write_r is + working. +*/ + +void +#ifdef __STDC__ +__printf (char *fmt, ...) +#else +__printf (fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list args; + + /* Which endian are we? */ + { + short tmp = 1; + big_endian_p = *(char *) &tmp == 0; + } + +#ifdef __STDC__ + va_start (args, fmt); +#else + va_start (args); +#endif + + while (*fmt) + { + char c, *p; + int count; + long l; + + if (*fmt != '%' || *++fmt == '%') + { + write_char (*fmt++); + continue; + } + + if (*fmt == 'N') + { + count = va_arg (args, int); + p = va_arg (args, char *); + ++fmt; + c = *fmt++; + + while (--count >= 0) + { + switch (c) + { +// case 'c' : +// write_string (unctrl (*p++)); +// break; + case 'p' : + print_number (16, 1, get_number (p, sizeof (char *), 1)); + p += sizeof (char *); + break; + case 'd' : + case 'u' : + case 'x' : + print_number (c == 'x' ? 16 : 10, c != 'd', + get_number (p, sizeof (int), c != 'd')); + p += sizeof (int); + break; + case 's' : + write_string (*(char **) p); + p += sizeof (char *); + break; + } + if (count > 0) + write_char (' '); + } + } + else + { + switch (c = *fmt++) + { +// case 'c' : +// c = va_arg (args, int); +// write_string (unctrl (c)); +// break; + case 'p' : + l = (void *) va_arg (args, char *); + print_number (16, 1, l); + break; + case 'd' : + case 'u' : + case 'x' : + l = va_arg (args, int); + print_number (c == 'x' ? 16 : 10, c != 'd', l); + break; + case 's' : + p = va_arg (args, char *); + write_string (p); + break; + } + } + } + + va_end (args); +} + +static int isdigit(int c) { + if (c >= '0' && c <= '9') return 1; + return 0; +} + +/* Parse a positive decimal integer at S. + FIXME: Was used in earlier version, but not currently used. + Keep for now. */ + +static char * +parse_number (s, p) + char *s; + long *p; +{ + long x = 0; + + while (isdigit (*s)) + { + x = (x * 10) + (*s - '0'); + ++s; + } + + *p = x; + return s; +} + +/* Fetch the number at S of SIZE bytes. */ + +static long +get_number (s, size, unsigned_p) + char *s; + long size; + int unsigned_p; +{ + long x; + unsigned char *p = (unsigned char *) s; + + switch (size) + { + case 1 : + x = *p; + if (!unsigned_p) + x = (x ^ 0x80) - 0x80; + return x; + case 2 : + if (big_endian_p) + x = (p[0] << 8) | p[1]; + else + x = (p[1] << 8) | p[0]; + if (!unsigned_p) + x = (x ^ 0x8000) - 0x8000; + return x; + case 4 : + if (big_endian_p) + x = ((long)p[0] << 24) | ((long)p[1] << 16) | (p[2] << 8) | p[3]; + else + x = ((long)p[3] << 24) | ((long)p[2] << 16) | (p[1] << 8) | p[0]; + if (!unsigned_p) + x = (x ^ 0x80000000L) - 0x80000000L; + return x; +#if 0 /* FIXME: Is there a standard mechanism for knowing if + long longs exist? */ + case 8 : +#endif + default : + return 0; + } +} + +/* Print X in base BASE. */ + +static void +print_number (base, unsigned_p, n) + int base; + int unsigned_p; + long n; +{ + static char chars[16] = "0123456789abcdef"; + char *p, buf[32]; + unsigned long x; + + if (!unsigned_p && n < 0) + { + write_char ('-'); + x = -n; + } + else + x = n; + + p = buf + sizeof (buf); + *--p = '\0'; + do + { + *--p = chars[x % base]; + x /= base; + } + while (x != 0); + + write_string (p); +} + +/* Write C to the console. + We go through the file descriptor directly because we can't assume + stdio is working. */ + +static void +write_char (char c) +{ + __putc(c); +} + +/* Write S to the console. + We go through the file descriptor directly because we can't assume + stdio is working. */ + +static void +write_string (char *s) +{ + __puts(s); +} + + +void __putc(u8 c) { + *((u8*)0x1f80380c) = c; +} + +void __puts(u8 *s) { + while (*s != 0) { + __putc(*s++); + } +} + diff --git a/fps2bios/kernel/iopload/iopelf.c b/fps2bios/kernel/iopload/iopelf.c index c277b2afad..3bba367f0a 100644 --- a/fps2bios/kernel/iopload/iopelf.c +++ b/fps2bios/kernel/iopload/iopelf.c @@ -1,428 +1,428 @@ -#include "romdir.h" -#include "iopelf.h" - -typedef struct { - u32 st_name; - u32 st_value; - u32 st_size; - u8 st_info; - u8 st_other; - u16 st_shndx; -} Elf32_Sym; - -char *sections_names; - -ELF_HEADER *elfHeader; -ELF_PHR *elfProgH; -ELF_SHR *elfSectH; -u8 *elfdata; -int elfsize; -u32 elfbase; -static int debug=1; - -#define _dprintf(fmt, args...) \ - if (debug > 0) __printf("iopelf: " fmt, ## args) - -static void __memcpy(void *dest, const void *src, int n) { - const u8 *s = (u8*)src; - u8 *d = (u8*)dest; - - while (n) { - *d++ = *s++; n--; - } -} - - -int loadHeaders() { - elfHeader = (ELF_HEADER*)elfdata; - - if ((elfHeader->e_shentsize != sizeof(ELF_SHR)) && (elfHeader->e_shnum > 0)) { - return -1; - } - -#ifdef ELF_LOG - ELF_LOG( "type: " ); -#endif - switch( elfHeader->e_type ) - { - default: -#ifdef ELF_LOG - ELF_LOG( "unknown %x", elfHeader->e_type ); -#endif - break; - - case 0x0: -#ifdef ELF_LOG - ELF_LOG( "no file type" ); -#endif - break; - - case 0x1: -#ifdef ELF_LOG - ELF_LOG( "relocatable" ); -#endif - break; - - case 0x2: -#ifdef ELF_LOG - ELF_LOG( "executable" ); -#endif - break; - } -#ifdef ELF_LOG - ELF_LOG( "\n" ); - ELF_LOG( "machine: " ); -#endif - switch ( elfHeader->e_machine ) - { - default: -#ifdef ELF_LOG - ELF_LOG( "unknown" ); -#endif - break; - - case 0x8: -#ifdef ELF_LOG - ELF_LOG( "mips_rs3000" ); -#endif - break; - } -#ifdef ELF_LOG - ELF_LOG("\n"); - ELF_LOG("version: %d\n",elfHeader->e_version); - ELF_LOG("entry: %08x\n",elfHeader->e_entry); - ELF_LOG("flags: %08x\n",elfHeader->e_flags); - ELF_LOG("eh size: %08x\n",elfHeader->e_ehsize); - ELF_LOG("ph off: %08x\n",elfHeader->e_phoff); - ELF_LOG("ph entsiz: %08x\n",elfHeader->e_phentsize); - ELF_LOG("ph num: %08x\n",elfHeader->e_phnum); - ELF_LOG("sh off: %08x\n",elfHeader->e_shoff); - ELF_LOG("sh entsiz: %08x\n",elfHeader->e_shentsize); - ELF_LOG("sh num: %08x\n",elfHeader->e_shnum); - ELF_LOG("sh strndx: %08x\n",elfHeader->e_shstrndx); - - ELF_LOG("\n"); -#endif - - return 0; -} - - -int loadProgramHeaders() { - int i; - - if (elfHeader->e_phnum == 0) { - return 0; - } - - if (elfHeader->e_phentsize != sizeof(ELF_PHR)) { - return -1; - } - - elfProgH = (ELF_PHR*)&elfdata[elfHeader->e_phoff]; - - for ( i = 0 ; i < elfHeader->e_phnum ; i++ ) - { -#ifdef ELF_LOG - ELF_LOG( "Elf32 Program Header\n" ); - ELF_LOG( "type: " ); -#endif - switch ( elfProgH[ i ].p_type ) - { - default: -#ifdef ELF_LOG - ELF_LOG( "unknown %x", (int)elfProgH[ i ].p_type ); -#endif - break; - - case 0x1: -#ifdef ELF_LOG - ELF_LOG("load"); -#endif -/* if ( elfHeader->e_shnum == 0 ) {*/ - if (elfProgH[ i ].p_offset < elfsize) { - int size; - - if ((elfProgH[ i ].p_filesz + elfProgH[ i ].p_offset) > elfsize) { - size = elfsize - elfProgH[ i ].p_offset; - } else { - size = elfProgH[ i ].p_filesz; - } - _dprintf("loading program at %x, size=%x\n", elfProgH[ i ].p_paddr + elfbase, size); - __memcpy((void*)(elfProgH[ i ].p_paddr + elfbase), - &elfdata[elfProgH[ i ].p_offset], - size); - } -#ifdef ELF_LOG - ELF_LOG("\t*LOADED*"); -#endif -// } - break; - } -#ifdef ELF_LOG - ELF_LOG("\n"); - ELF_LOG("offset: %08x\n",(int)elfProgH[i].p_offset); - ELF_LOG("vaddr: %08x\n",(int)elfProgH[i].p_vaddr); - ELF_LOG("paddr: %08x\n",elfProgH[i].p_paddr); - ELF_LOG("file size: %08x\n",elfProgH[i].p_filesz); - ELF_LOG("mem size: %08x\n",elfProgH[i].p_memsz); - ELF_LOG("flags: %08x\n",elfProgH[i].p_flags); - ELF_LOG("palign: %08x\n",elfProgH[i].p_align); - ELF_LOG("\n"); -#endif - } - - return 0; -} - -void _relocateElfSection(int i) { - ELF_REL *rel; - int size = elfSectH[i].sh_size / 4; - int r = 0; - u32 *ptr, *tmp; - ELF_SHR *rsec = &elfSectH[elfSectH[i].sh_info]; - u8 *mem = (u8*)(elfSectH[i].sh_addr + elfbase); - u32 imm; - int j; - - ptr = (u32*)(elfdata+elfSectH[i].sh_offset); - -// _dprintf("relocating section %s\n", §ions_names[rsec->sh_name]); -// __printf("sh_addr %x\n", elfSectH[i].sh_addr); - - while (size > 0) { - rel = (ELF_REL*)&ptr[r]; -// __printf("rel size=%x: offset=%x, info=%x\n", size, rel->r_offset, rel->r_info); - - tmp = (u32*)&mem[rel->r_offset]; - switch ((u8)rel->r_info) { - case 2: // R_MIPS_32 - *tmp+= elfbase; break; - - case 4: // R_MIPS_26 - *tmp = (*tmp & 0xfc000000) | - (((*tmp & 0x03ffffff) + (elfbase >> 2)) & 0x03ffffff); - break; - - case 5: // R_MIPS_HI16 - imm = (((*tmp & 0xffff) + (elfbase >> 16)) & 0xffff); - for (j=(r+2)/2; jr_info == 6) - break; -// if ((rel->r_info >> 8) == (((ELF_REL*)&ptr[j*2])->r_info >> 8)) -// break; - } - -/* if (j != elfSectH[i].sh_size / 4)*/ { - u32 *p; - - rel = (ELF_REL*)&ptr[j*2]; -// __printf("HI16: found match: %x\n", rel->r_offset); - p = (u32*)&mem[rel->r_offset]; -// __printf("%x + %x = %x\n", *p, elfbase, (*p & 0xffff) + (elfbase & 0xffff)); - if (((*p & 0xffff) + (elfbase & 0xffff)) & 0x8000) { -// __printf("found\n"); - imm++; - } - } - *tmp = (*tmp & 0xffff0000) | imm; - break; - - case 6: // R_MIPS_LO16 - *tmp = (*tmp & 0xffff0000) | - (((*tmp & 0xffff) + (elfbase & 0xffff)) & 0xffff); - break; - - default: - __printf("UNKNOWN R_MIPS REL!!\n"); - break; - } - - size-= 2; r+= 2; - } -} - -int loadSectionHeaders() { - int i; - int i_st = -1; - int i_dt = -1; - - if (elfHeader->e_shnum == 0) { - return -1; - } - - elfSectH = (ELF_SHR*)&elfdata[elfHeader->e_shoff]; - - if ( elfHeader->e_shstrndx < elfHeader->e_shnum ) { - sections_names = (char *)&elfdata[elfSectH[ elfHeader->e_shstrndx ].sh_offset]; - } - - for ( i = 0 ; i < elfHeader->e_shnum ; i++ ) - { -#ifdef ELF_LOG - ELF_LOG( "Elf32 Section Header [%x] %s", i, §ions_names[ elfSectH[ i ].sh_name ] ); -#endif -/* if ( elfSectH[i].sh_flags & 0x2 ) { - if (elfSectH[i].sh_offset < elfsize) { - int size; - - if ((elfSectH[i].sh_size + elfSectH[i].sh_offset) > elfsize) { - size = elfsize - elfSectH[i].sh_offset; - } else { - size = elfSectH[i].sh_size; - } - memcpy(&psM[ elfSectH[ i ].sh_addr &0x1ffffff ], - &elfdata[elfSectH[i].sh_offset], - size); - } -#ifdef ELF_LOG - ELF_LOG( "\t*LOADED*" ); -#endif - }*/ -#ifdef ELF_LOG - ELF_LOG("\n"); - ELF_LOG("type: "); -#endif - switch ( elfSectH[ i ].sh_type ) - { - default: -#ifdef ELF_LOG - ELF_LOG("unknown %08x",elfSectH[i].sh_type); -#endif - break; - - case 0x0: -#ifdef ELF_LOG - ELF_LOG("null"); -#endif - break; - - case 0x1: -#ifdef ELF_LOG - ELF_LOG("progbits"); -#endif - break; - - case 0x2: -#ifdef ELF_LOG - ELF_LOG("symtab"); -#endif - break; - - case 0x3: -#ifdef ELF_LOG - ELF_LOG("strtab"); -#endif - break; - - case 0x4: -#ifdef ELF_LOG - ELF_LOG("rela"); -#endif - break; - - case 0x8: -#ifdef ELF_LOG - ELF_LOG("no bits"); -#endif - break; - - case 0x9: -#ifdef ELF_LOG - ELF_LOG("rel"); -#endif - break; - } -#ifdef ELF_LOG - ELF_LOG("\n"); - ELF_LOG("flags: %08x\n", elfSectH[i].sh_flags); - ELF_LOG("addr: %08x\n", elfSectH[i].sh_addr); - ELF_LOG("offset: %08x\n", elfSectH[i].sh_offset); - ELF_LOG("size: %08x\n", elfSectH[i].sh_size); - ELF_LOG("link: %08x\n", elfSectH[i].sh_link); - ELF_LOG("info: %08x\n", elfSectH[i].sh_info); - ELF_LOG("addralign: %08x\n", elfSectH[i].sh_addralign); - ELF_LOG("entsize: %08x\n", elfSectH[i].sh_entsize); -#endif - // dump symbol table - - if (elfSectH[i].sh_type == 0x02) { - i_st = i; i_dt = elfSectH[i].sh_link; - } - } - - - // now that we have all the stuff loaded, relocate it - for (i = 0 ; i < elfHeader->e_shnum ; i++) { - if (elfSectH[i].sh_type == 0x09) { // relocations - _relocateElfSection(i); - } - } - - return 0; -} - -void* loadElfFile(ROMFILE_INFO* ri, u32 offset) -{ - imageInfo* ii; - ELF_PHR* ph; - ELF_IOPMOD* im; - - __printf("loadElfFile: base=%x, size=%x\n", ri->fileData, ri->entry->fileSize); - elfdata = (u8*)(ri->fileData); - elfsize = ri->entry->fileSize; - elfbase = offset+0x30; - - loadHeaders(); - - // fill the image info header - ph= (ELF_PHR*)((char*)elfHeader +elfHeader->e_phoff); - im= (ELF_IOPMOD*)((char*)elfHeader + ph[0].p_offset); - ii = (imageInfo*)offset; - - if( *(u16*)(elfHeader->e_ident+4) != 0x101 ) - return NULL; - if (elfHeader->e_machine != EM_MIPS) - return NULL; - if (elfHeader->e_phentsize != sizeof(ELF_PHR)) - return NULL; - if (elfHeader->e_phnum != 2) - return NULL; - if (ph[0].p_type != PT_SCE_IOPMOD) - return NULL; - if (elfHeader->e_type != ET_SCE_IOPRELEXEC){ - if (elfHeader->e_type != elfHeader->e_phnum )//ET_EXEC) - return NULL; - //result->type=3; - } - //else result->type=4; - - ii->next =0; - ii->name =NULL; - ii->version =0; - ii->flags =0; - ii->modid =0; - if ((int)im->moduleinfo != -1) { - moduleInfo* minfo = (moduleInfo*)(im->moduleinfo+ph[1].p_vaddr); // probably wrong - ii->name = minfo->name; - ii->version = minfo->version; - } - else { - ii->name = NULL; - ii->version = 0; - } - ii->entry = im->entry; - ii->gp_value = im->gp_value; - ii->p1_vaddr = ph[1].p_vaddr; - ii->text_size = im->text_size; - ii->data_size = im->data_size; - ii->bss_size = im->bss_size; - - loadProgramHeaders(); - loadSectionHeaders(); - - _dprintf("loadElfFile: e_entry=%x, hdr=%x\n", elfHeader->e_entry, elfHeader); - return (void*)(elfbase+elfHeader->e_entry); -} - +#include "romdir.h" +#include "iopelf.h" + +typedef struct { + u32 st_name; + u32 st_value; + u32 st_size; + u8 st_info; + u8 st_other; + u16 st_shndx; +} Elf32_Sym; + +char *sections_names; + +ELF_HEADER *elfHeader; +ELF_PHR *elfProgH; +ELF_SHR *elfSectH; +u8 *elfdata; +int elfsize; +u32 elfbase; +static int debug=1; + +#define _dprintf(fmt, args...) \ + if (debug > 0) __printf("iopelf: " fmt, ## args) + +static void __memcpy(void *dest, const void *src, int n) { + const u8 *s = (u8*)src; + u8 *d = (u8*)dest; + + while (n) { + *d++ = *s++; n--; + } +} + + +int loadHeaders() { + elfHeader = (ELF_HEADER*)elfdata; + + if ((elfHeader->e_shentsize != sizeof(ELF_SHR)) && (elfHeader->e_shnum > 0)) { + return -1; + } + +#ifdef ELF_LOG + ELF_LOG( "type: " ); +#endif + switch( elfHeader->e_type ) + { + default: +#ifdef ELF_LOG + ELF_LOG( "unknown %x", elfHeader->e_type ); +#endif + break; + + case 0x0: +#ifdef ELF_LOG + ELF_LOG( "no file type" ); +#endif + break; + + case 0x1: +#ifdef ELF_LOG + ELF_LOG( "relocatable" ); +#endif + break; + + case 0x2: +#ifdef ELF_LOG + ELF_LOG( "executable" ); +#endif + break; + } +#ifdef ELF_LOG + ELF_LOG( "\n" ); + ELF_LOG( "machine: " ); +#endif + switch ( elfHeader->e_machine ) + { + default: +#ifdef ELF_LOG + ELF_LOG( "unknown" ); +#endif + break; + + case 0x8: +#ifdef ELF_LOG + ELF_LOG( "mips_rs3000" ); +#endif + break; + } +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("version: %d\n",elfHeader->e_version); + ELF_LOG("entry: %08x\n",elfHeader->e_entry); + ELF_LOG("flags: %08x\n",elfHeader->e_flags); + ELF_LOG("eh size: %08x\n",elfHeader->e_ehsize); + ELF_LOG("ph off: %08x\n",elfHeader->e_phoff); + ELF_LOG("ph entsiz: %08x\n",elfHeader->e_phentsize); + ELF_LOG("ph num: %08x\n",elfHeader->e_phnum); + ELF_LOG("sh off: %08x\n",elfHeader->e_shoff); + ELF_LOG("sh entsiz: %08x\n",elfHeader->e_shentsize); + ELF_LOG("sh num: %08x\n",elfHeader->e_shnum); + ELF_LOG("sh strndx: %08x\n",elfHeader->e_shstrndx); + + ELF_LOG("\n"); +#endif + + return 0; +} + + +int loadProgramHeaders() { + int i; + + if (elfHeader->e_phnum == 0) { + return 0; + } + + if (elfHeader->e_phentsize != sizeof(ELF_PHR)) { + return -1; + } + + elfProgH = (ELF_PHR*)&elfdata[elfHeader->e_phoff]; + + for ( i = 0 ; i < elfHeader->e_phnum ; i++ ) + { +#ifdef ELF_LOG + ELF_LOG( "Elf32 Program Header\n" ); + ELF_LOG( "type: " ); +#endif + switch ( elfProgH[ i ].p_type ) + { + default: +#ifdef ELF_LOG + ELF_LOG( "unknown %x", (int)elfProgH[ i ].p_type ); +#endif + break; + + case 0x1: +#ifdef ELF_LOG + ELF_LOG("load"); +#endif +/* if ( elfHeader->e_shnum == 0 ) {*/ + if (elfProgH[ i ].p_offset < elfsize) { + int size; + + if ((elfProgH[ i ].p_filesz + elfProgH[ i ].p_offset) > elfsize) { + size = elfsize - elfProgH[ i ].p_offset; + } else { + size = elfProgH[ i ].p_filesz; + } + _dprintf("loading program at %x, size=%x\n", elfProgH[ i ].p_paddr + elfbase, size); + __memcpy((void*)(elfProgH[ i ].p_paddr + elfbase), + &elfdata[elfProgH[ i ].p_offset], + size); + } +#ifdef ELF_LOG + ELF_LOG("\t*LOADED*"); +#endif +// } + break; + } +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("offset: %08x\n",(int)elfProgH[i].p_offset); + ELF_LOG("vaddr: %08x\n",(int)elfProgH[i].p_vaddr); + ELF_LOG("paddr: %08x\n",elfProgH[i].p_paddr); + ELF_LOG("file size: %08x\n",elfProgH[i].p_filesz); + ELF_LOG("mem size: %08x\n",elfProgH[i].p_memsz); + ELF_LOG("flags: %08x\n",elfProgH[i].p_flags); + ELF_LOG("palign: %08x\n",elfProgH[i].p_align); + ELF_LOG("\n"); +#endif + } + + return 0; +} + +void _relocateElfSection(int i) { + ELF_REL *rel; + int size = elfSectH[i].sh_size / 4; + int r = 0; + u32 *ptr, *tmp; + ELF_SHR *rsec = &elfSectH[elfSectH[i].sh_info]; + u8 *mem = (u8*)(elfSectH[i].sh_addr + elfbase); + u32 imm; + int j; + + ptr = (u32*)(elfdata+elfSectH[i].sh_offset); + +// _dprintf("relocating section %s\n", §ions_names[rsec->sh_name]); +// __printf("sh_addr %x\n", elfSectH[i].sh_addr); + + while (size > 0) { + rel = (ELF_REL*)&ptr[r]; +// __printf("rel size=%x: offset=%x, info=%x\n", size, rel->r_offset, rel->r_info); + + tmp = (u32*)&mem[rel->r_offset]; + switch ((u8)rel->r_info) { + case 2: // R_MIPS_32 + *tmp+= elfbase; break; + + case 4: // R_MIPS_26 + *tmp = (*tmp & 0xfc000000) | + (((*tmp & 0x03ffffff) + (elfbase >> 2)) & 0x03ffffff); + break; + + case 5: // R_MIPS_HI16 + imm = (((*tmp & 0xffff) + (elfbase >> 16)) & 0xffff); + for (j=(r+2)/2; jr_info == 6) + break; +// if ((rel->r_info >> 8) == (((ELF_REL*)&ptr[j*2])->r_info >> 8)) +// break; + } + +/* if (j != elfSectH[i].sh_size / 4)*/ { + u32 *p; + + rel = (ELF_REL*)&ptr[j*2]; +// __printf("HI16: found match: %x\n", rel->r_offset); + p = (u32*)&mem[rel->r_offset]; +// __printf("%x + %x = %x\n", *p, elfbase, (*p & 0xffff) + (elfbase & 0xffff)); + if (((*p & 0xffff) + (elfbase & 0xffff)) & 0x8000) { +// __printf("found\n"); + imm++; + } + } + *tmp = (*tmp & 0xffff0000) | imm; + break; + + case 6: // R_MIPS_LO16 + *tmp = (*tmp & 0xffff0000) | + (((*tmp & 0xffff) + (elfbase & 0xffff)) & 0xffff); + break; + + default: + __printf("UNKNOWN R_MIPS REL!!\n"); + break; + } + + size-= 2; r+= 2; + } +} + +int loadSectionHeaders() { + int i; + int i_st = -1; + int i_dt = -1; + + if (elfHeader->e_shnum == 0) { + return -1; + } + + elfSectH = (ELF_SHR*)&elfdata[elfHeader->e_shoff]; + + if ( elfHeader->e_shstrndx < elfHeader->e_shnum ) { + sections_names = (char *)&elfdata[elfSectH[ elfHeader->e_shstrndx ].sh_offset]; + } + + for ( i = 0 ; i < elfHeader->e_shnum ; i++ ) + { +#ifdef ELF_LOG + ELF_LOG( "Elf32 Section Header [%x] %s", i, §ions_names[ elfSectH[ i ].sh_name ] ); +#endif +/* if ( elfSectH[i].sh_flags & 0x2 ) { + if (elfSectH[i].sh_offset < elfsize) { + int size; + + if ((elfSectH[i].sh_size + elfSectH[i].sh_offset) > elfsize) { + size = elfsize - elfSectH[i].sh_offset; + } else { + size = elfSectH[i].sh_size; + } + memcpy(&psM[ elfSectH[ i ].sh_addr &0x1ffffff ], + &elfdata[elfSectH[i].sh_offset], + size); + } +#ifdef ELF_LOG + ELF_LOG( "\t*LOADED*" ); +#endif + }*/ +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("type: "); +#endif + switch ( elfSectH[ i ].sh_type ) + { + default: +#ifdef ELF_LOG + ELF_LOG("unknown %08x",elfSectH[i].sh_type); +#endif + break; + + case 0x0: +#ifdef ELF_LOG + ELF_LOG("null"); +#endif + break; + + case 0x1: +#ifdef ELF_LOG + ELF_LOG("progbits"); +#endif + break; + + case 0x2: +#ifdef ELF_LOG + ELF_LOG("symtab"); +#endif + break; + + case 0x3: +#ifdef ELF_LOG + ELF_LOG("strtab"); +#endif + break; + + case 0x4: +#ifdef ELF_LOG + ELF_LOG("rela"); +#endif + break; + + case 0x8: +#ifdef ELF_LOG + ELF_LOG("no bits"); +#endif + break; + + case 0x9: +#ifdef ELF_LOG + ELF_LOG("rel"); +#endif + break; + } +#ifdef ELF_LOG + ELF_LOG("\n"); + ELF_LOG("flags: %08x\n", elfSectH[i].sh_flags); + ELF_LOG("addr: %08x\n", elfSectH[i].sh_addr); + ELF_LOG("offset: %08x\n", elfSectH[i].sh_offset); + ELF_LOG("size: %08x\n", elfSectH[i].sh_size); + ELF_LOG("link: %08x\n", elfSectH[i].sh_link); + ELF_LOG("info: %08x\n", elfSectH[i].sh_info); + ELF_LOG("addralign: %08x\n", elfSectH[i].sh_addralign); + ELF_LOG("entsize: %08x\n", elfSectH[i].sh_entsize); +#endif + // dump symbol table + + if (elfSectH[i].sh_type == 0x02) { + i_st = i; i_dt = elfSectH[i].sh_link; + } + } + + + // now that we have all the stuff loaded, relocate it + for (i = 0 ; i < elfHeader->e_shnum ; i++) { + if (elfSectH[i].sh_type == 0x09) { // relocations + _relocateElfSection(i); + } + } + + return 0; +} + +void* loadElfFile(ROMFILE_INFO* ri, u32 offset) +{ + imageInfo* ii; + ELF_PHR* ph; + ELF_IOPMOD* im; + + __printf("loadElfFile: base=%x, size=%x\n", ri->fileData, ri->entry->fileSize); + elfdata = (u8*)(ri->fileData); + elfsize = ri->entry->fileSize; + elfbase = offset+0x30; + + loadHeaders(); + + // fill the image info header + ph= (ELF_PHR*)((char*)elfHeader +elfHeader->e_phoff); + im= (ELF_IOPMOD*)((char*)elfHeader + ph[0].p_offset); + ii = (imageInfo*)offset; + + if( *(u16*)(elfHeader->e_ident+4) != 0x101 ) + return NULL; + if (elfHeader->e_machine != EM_MIPS) + return NULL; + if (elfHeader->e_phentsize != sizeof(ELF_PHR)) + return NULL; + if (elfHeader->e_phnum != 2) + return NULL; + if (ph[0].p_type != PT_SCE_IOPMOD) + return NULL; + if (elfHeader->e_type != ET_SCE_IOPRELEXEC){ + if (elfHeader->e_type != elfHeader->e_phnum )//ET_EXEC) + return NULL; + //result->type=3; + } + //else result->type=4; + + ii->next =0; + ii->name =NULL; + ii->version =0; + ii->flags =0; + ii->modid =0; + if ((int)im->moduleinfo != -1) { + moduleInfo* minfo = (moduleInfo*)(im->moduleinfo+ph[1].p_vaddr); // probably wrong + ii->name = minfo->name; + ii->version = minfo->version; + } + else { + ii->name = NULL; + ii->version = 0; + } + ii->entry = im->entry; + ii->gp_value = im->gp_value; + ii->p1_vaddr = ph[1].p_vaddr; + ii->text_size = im->text_size; + ii->data_size = im->data_size; + ii->bss_size = im->bss_size; + + loadProgramHeaders(); + loadSectionHeaders(); + + _dprintf("loadElfFile: e_entry=%x, hdr=%x\n", elfHeader->e_entry, elfHeader); + return (void*)(elfbase+elfHeader->e_entry); +} + diff --git a/fps2bios/kernel/iopload/loadcore/Makefile b/fps2bios/kernel/iopload/loadcore/Makefile index b7d1a95cbf..df12e727f3 100644 --- a/fps2bios/kernel/iopload/loadcore/Makefile +++ b/fps2bios/kernel/iopload/loadcore/Makefile @@ -1,59 +1,59 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include - -IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 -IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include -IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -IOPLINK = $(IOPLD) -dc -IOPASFLAGS := -EL -G0 - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: loadcore - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -L$(PS2LIB)/iop/lib -LDADD = -OBJECTS = loadcore.o ../iopdebug.o ../iopelf.o ../romdir.o ../libkernel/iop_sysmem.o - -loadcore: $(OBJECTS) - $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/LOADCORE - -%.o: %.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - -%.o : %.s - $(IOPAS) $(IOPASFLAGS) $< -o $@ - -clean: - rm -f $(OBJECTS) - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: loadcore + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib +LDADD = +OBJECTS = loadcore.o ../iopdebug.o ../iopelf.o ../romdir.o ../libkernel/iop_sysmem.o + +loadcore: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/LOADCORE + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/loadcore/loadcore.c b/fps2bios/kernel/iopload/loadcore/loadcore.c index 690215da08..14233bf4b6 100644 --- a/fps2bios/kernel/iopload/loadcore/loadcore.c +++ b/fps2bios/kernel/iopload/loadcore/loadcore.c @@ -1,1044 +1,1044 @@ - -#include - -#include "ksysmem.h" -#include "kloadcore.h" -#include "iopdebug.h" -#include "iopelf.h" -#include "romdir.h" -#include "irx.h" // ps2sdk file for IMPORT_MAGIC - -#define BOOTMODE_START *((volatile u32**)0x3F0) -#define BOOTMODE_END *((volatile u32**)0x3F4) - -void _start(BOOT_PARAMS *init); // has to be declared first! - -struct tag_LC_internals { - struct export* let_next, *let_prev; - struct export* mda_next, *mda_prev;//.prev==free - imageInfo *image_info; // 0x800?0x830? - int module_count; - int module_index; -} lc_internals; - -u32 free; -u32 sysmem_00; -u32 modules_count; -u32 module_index; -u32 *place; // addr of 8 * 31 = 8 * linesInIopbtconf //place[2][31] -u32 bootmodes[17]; // was 16? -u32 bootmodes_size; -int debug=0; - -u32 bm_end; - -#define _dprintf(fmt, args...) \ - if (debug > 0) __printf("loadcore:%d: " fmt, __LINE__, ## args) - -void retonly(); -struct tag_LC_internals* GetLibraryEntryTable(); -void FlushIcache(); -void FlushDcache(); -int RegisterLibraryEntries(struct export *es); -int ReleaseLibraryEntries(struct export *e); -int _LinkImports(u32 *addr, int size); -int _UnlinkImports(void *addr, int size); -int RegisterNonAutoLinkEntries(struct export *e); -int QueryLibraryEntryTable(struct export *e); -u32 *QueryBootMode(int id); -void RegisterBootMode(struct bootmode *b); -int SetNonAutoLinkFlag(struct export *e); -int UnsetNonAutoLinkFlag(struct export *e); -void _LinkModule(imageInfo *ii); -void _UnlinkModule(imageInfo *ii); -int _RegisterBootupCBFunc(int (*function)(int *, int), int priority, int *result); -void _SetCacheCtrl(u32 val); -int _ReadModuleHeader(void *image, fileInfo *result); -int _LoadModule(void *image, fileInfo *fi); -u32 _FindImageInfo(void *addr); - -struct export loadcore_stub __attribute__((section(".text"))) ={ - EXPORT_MAGIC, - 0, - VER(1, 1), // 1.1 => 0x101 - 0, - "loadcore", - (func)_start, // entrypoint - (func)retonly, - (func)retonly, - (func)GetLibraryEntryTable, - (func)FlushIcache, - (func)FlushDcache, - (func)RegisterLibraryEntries, - (func)ReleaseLibraryEntries, - (func)_LinkImports, - (func)_UnlinkImports, - (func)RegisterNonAutoLinkEntries, - (func)QueryLibraryEntryTable, - (func)QueryBootMode, - (func)RegisterBootMode, - (func)SetNonAutoLinkFlag, - (func)UnsetNonAutoLinkFlag, - (func)_LinkModule, - (func)_UnlinkModule, - (func)retonly, - (func)retonly, - (func)_RegisterBootupCBFunc, - (func)_SetCacheCtrl, - (func)_ReadModuleHeader, - (func)_LoadModule, - (func)_FindImageInfo, - 0 -}; - -/////////////////////////////////////////////////////////////////////// -void retonly(){} - -/////////////////////////////////////////////////////////////////////// -void RegisterBootMode(struct bootmode *b) { - int i; - - _dprintf("%s\n", __FUNCTION__); - if (((b->len + 1) * 4) < (16-bootmodes_size)) { - u32 *p = &bootmodes[bootmodes_size]; - for (i=0; ilen + 1; i++) p[i]=((u32*)b)[i]; - p[i]=0; - bootmodes_size+= b->len + 1; - } -} - -/////////////////////////////////////////////////////////////////////// -u32 *QueryBootMode(int id) { - u32 *b; - - for (b = (u32*)&bootmodes[0]; *b; b += ((struct bootmode*)b)->len + 1) - if (id == ((struct bootmode*)b)->id) - return b; - return NULL; -} - -/////////////////////////////////////////////////////////////////////// -int match_name(struct export *src, struct export *dst){ - return (*(int*)(src->name+0) == *(int*)(dst->name+0)) && - (*(int*)(src->name+4) == *(int*)(dst->name+4)); -} - -/////////////////////////////////////////////////////////////////////// -int match_version_major(struct export *src, struct export *dst){ - return ((src->version>>8) - (dst->version>>8)); -} - -/////////////////////////////////////////////////////////////////////// -int match_version_minor(struct export *src, struct export *dst){ - return ((unsigned char)src->version - (unsigned char)dst->version); -} - -/////////////////////////////////////////////////////////////////////// -int fix_imports(struct import *imp, struct export *exp){ - func *ef; - struct func_stub *fs; - int count=0, ordinal; - - for (ef=exp->func; *ef; ef++){ - count++; //count number of exported functions - } - _dprintf("%s (%d functions)\n", __FUNCTION__, count); - - for (fs=imp->func; fs->jr_ra; fs++) { - if ((fs->addiu0 >> 26) != INS_ADDIU) break; - - ordinal = fs->addiu0 & 0xFFFF; - if (ordinal < count) { -// _dprintf("%s linking ordinal %d to %x\n", __FUNCTION__, ordinal, exp->func[ordinal]); - fs->jr_ra=(((u32)exp->func[ordinal]>>2) & 0x3FFFFFF) | INS_J; - } else { - fs->jr_ra=INS_JR_RA; - } - } - - imp->flags |=FLAG_IMPORT_QUEUED; - return 0; -} - -/////////////////////////////////////////////////////////////////////// -// Check the structure of the import table. -// Return 0 if a bad or empty import table is detected. -// Return a non-zero value if a valid import table is detected. -// -int check_import_table(struct import* imp){ - struct func_stub *f; - - if (imp->magic != IMPORT_MAGIC) - return 0; - for (f=imp->func; f->jr_ra; f++){ - if (f->addiu0 >> 26 != INS_ADDIU) - return 0; - if ((f->jr_ra!=INS_JR_RA) && (f->jr_ra>26!=INS_JR)) - return 0; - } - if (f->addiu0) - return 0; - return (imp->func < f); -} - -///////////////////////////////////////////////////////////////////////[OK] - -// Return 0 if successful -int link_client(struct import *imp){ - struct export *e; - -// _dprintf("%s\n", __FUNCTION__); - for (e=lc_internals.let_next; e; e=(struct export*)e->magic_link) { - if (debug > 0){ - // Zero terminate the name before printing it - char ename[9], iname[9]; - *(int*)ename = *(int*)e->name; *(int*)(ename+4) = *(int*)(e->name+4); ename[8] = 0; - *(int*)iname = *(int*)imp->name; *(int*)(iname+4) = *(int*)(imp->name+4);iname[8] = 0; - - //__printf("loadcore: %s: %s, %s\n", __FUNCTION__, ename, iname); - } - - if (!(e->flags & FLAG_NO_AUTO_LINK)){ - if ( match_name(e, (struct export*)imp)){ - if (match_version_major(e, (struct export*)imp)==0) { - fix_imports(imp, e); - imp->next=(struct import*)e->next; - e->next=(struct export*)imp; - FlushIcache(); - return 0; - } else { -// _dprintf("%s: version does not match\n", __FUNCTION__); - } - } else { -// _dprintf("%s: name does not match\n", __FUNCTION__); - } - } else { -// _dprintf("%s: e->flags bit 0 is 0\n", __FUNCTION__); - } - } - _dprintf("%s: FAILED to find a match\n", __FUNCTION__); - return -1; -} - -///////////////////////////////////////////////////////////////////////[OK] -int _LinkImports(u32 *addr, int size) -{ - struct import *p; - int i; - - _dprintf("%s: %x, %d\n", __FUNCTION__, addr, size); - for (i=0; imagic == IMPORT_MAGIC) && - check_import_table(p) && - ((p->flags & 7) == 0) && - link_client(p)) { - _UnlinkImports(p, size); - return -1; - } - } - return 0; -} - -///////////////////////////////////////////////////////////////////////[OK] -int unlink_client(struct import *i1, struct import *i2){ - struct import *i, *tmp; - - if (i1->next == i2){ - i1->next=i2->next; - return 0; - } - for (i = i1->next; i->next;) { - tmp=i->next; - if (tmp==i2) { - i->next=tmp->next; - tmp->next=NULL; - return 0; - } - i=tmp; - } - return -1; -} - -///////////////////////////////////////////////////////////////////////[OK] -void restore_imports(struct import* imp){ - struct func_stub *f; - - for (f=imp->func; (f->jr_ra) && ((f->addiu0 >> 26) == INS_ADDIU); f++) - f->jr_ra=INS_JR_RA; -} - -///////////////////////////////////////////////////////////////////////[OK] -int _UnlinkImports(void *addr, int size) -{ - struct export *e; - struct export *i; - struct export *tmp; - void *limit = addr + (size & ~0x3); - - for (e = (struct export*)lc_internals.let_next; e; e=(struct export*)e->magic_link){ - for (i = e->next; i; i=i->next) { - if (((u32)i >= (u32)addr) && ((u32)i < (u32)limit)) { - if (unlink_client((struct import*)e, (struct import*)i)) - return -1; - i->flags &= ~0x7; - restore_imports((struct import*)i); - } - } - if (((u32)e >= (u32)addr) && ((u32)e < (u32)limit)) - ReleaseLibraryEntries(e); - } -/* - for (i=let.mda; i->next; ) - if ((i->next >= addr) && (i->next < limit)){ - i->next->flags &= ~0x7; - restore_imports(i->next); - tmp = i->next->next; - i->next->next=NULL; - i->next=tmp; - }else - i=i->next; -*/ - return 0; -} - -/////////////////////////////////////////////////////////////////////// -int SetNonAutoLinkFlag(struct export *e) -{ - return (e->flags |= FLAG_NO_AUTO_LINK); -} - -/////////////////////////////////////////////////////////////////////// -int UnsetNonAutoLinkFlag(struct export *e) -{ - return (e->flags &= ~FLAG_NO_AUTO_LINK); -} - -/////////////////////////////////////////////////////////////////////// -int _RegisterBootupCBFunc(int (*function)(int *, int), int priority, int *result) -{ - int x; - register int r; - if (place==NULL){ - x=1; - r=function(&x, 0); - if (result) *result=r; - return 0; - } - - __asm__("move %0, $gp\n" : "=r"(x) : ); - - place[0]=(u32)function + (priority & 3); - place[1]=x; - place[2]=0; - place+=2; - return 1; -} - -/////////////////////////////////////////////////////////////////////// -void _LinkModule(imageInfo *ii) -{ - imageInfo* p; - for (p=lc_internals.image_info; p->next && (p->next < (u32)ii); p=(imageInfo*)p->next); - - ii->next=p->next; - p->next=(u32)ii; - - ii->modid=module_index++; - modules_count++; -} - -/////////////////////////////////////////////////////////////////////// -void _UnlinkModule(imageInfo *ii) -{ - imageInfo *p; - if (ii) - for (p=lc_internals.image_info; p->next; p=(imageInfo*)p->next) - if (p->next == (u32)ii){ - p->next=((imageInfo*)p->next)->next; - modules_count--; - return; - } -} - -u32 _FindImageInfo(void *addr) -{ - register imageInfo *ii; - for (ii=lc_internals.image_info; ii; ii=(imageInfo*)ii->next) - if(((u32)addr>=ii->p1_vaddr) && - ((u32)addr p1_vaddr + ii->text_size + ii->data_size + ii->bss_size)) - return (u32)ii; - return 0; -} - -/////////////////////////////////////////////////////////////////////// -int RegisterLibraryEntries(struct export *es){ - struct export *p; - struct export *plast; - struct export *pnext; - struct export *tmp; - struct export *snext; - - if ((es == NULL) || (es->magic_link != EXPORT_MAGIC)) - return -1; - - if (debug > 0){ - // Zero terminate the name before printing it - char ename[9]; - *(int*)ename = *(int*)es->name; - *(int*)(ename+4) = *(int*)(es->name+4); - ename[8] = 0; - - __printf("loadcore: %s (%x): %s, %x\n", __FUNCTION__, es, es->name, es->version); - } - - - plast=NULL; - for (p=(struct export*)lc_internals.let_next; p; p=(struct export*)p->magic_link) { - if (match_name(es, p) == 0 || - match_version_major(es, p) == 0) continue; - - if (match_version_minor(es, p) == 0) - return -1; - _dprintf("%s: found match\n", __FUNCTION__); - pnext = p->next; - p->next = NULL; - - for (tmp = pnext; tmp; ) { - if (tmp->flags & FLAG_NO_AUTO_LINK) { - pnext->magic_link = (u32)tmp; - pnext = tmp->next; - tmp->next = NULL; - } else { - tmp->next=plast; - plast=tmp; - } - tmp=tmp->next; - } - } - - if( lc_internals.mda_next ) { - for (tmp = lc_internals.mda_next; tmp->next; tmp=tmp->next) { //free - if ((match_name(es, tmp->next)) && - (match_version_major(es, tmp->next)==0)){ - _dprintf("%s: freeing module\n", __FUNCTION__); - snext=tmp->next->next; - tmp->next->next=plast; - plast=tmp->next; - tmp->next=snext; - } else tmp=tmp->next; - } - } - - es->next=0; - while (plast) { - snext=plast->next; - fix_imports((struct import*)plast, es); - plast->next=es->next; - es->next=plast; - plast=snext; - } - es->flags &= ~FLAG_NO_AUTO_LINK; - es->magic_link=(u32)lc_internals.let_next; - lc_internals.let_next=es; - FlushIcache(); - - return 0; -} - -/////////////////////////////////////////////////////////////////////// -int ReleaseLibraryEntries(struct export *e) -{ - register struct export *n, *p, *next, *prev; - - p = lc_internals.let_next; - while ((p) && (p!=e)){ - prev=p; - p=(struct export*)prev->magic_link; - } - if (p != e) // if (0 != e) - return -1; //japanese BUG for e==p==0 - - n =e->next; - e ->next =0; - - prev->magic_link=e->magic_link; - e ->magic_link=0x41C00000; - - while(n) { - next = n->next; - if (link_client((struct import*)n)){ - restore_imports((struct import*)n); - n->flags=(n->flags & ~2) | 4; - n->next = lc_internals.mda_prev; - lc_internals.mda_prev=n; - } - n=next; - } - - return 0; -} - -/////////////////////////////////////////////////////////////////////// -int RegisterNonAutoLinkEntries(struct export *e) -{ - if ((e == NULL) || (e->magic_link != EXPORT_MAGIC)){ - return -1; - } - e->flags |= FLAG_NO_AUTO_LINK; - e->magic_link = (u32)lc_internals.let_next; // --add as first - lc_internals.let_next = e; // / - FlushIcache(); - - return 0; -} - -/////////////////////////////////////////////////////////////////////// -int QueryLibraryEntryTable(struct export *e) -{ - struct export *p = lc_internals.let_next; - while (p){ - if ((match_name(p, e)) && (match_version_major(p, e)==0)){ - return (int)p->func; - } - p=(struct export*)p->magic_link; - } - return 0; -} - -/////////////////////////////////////////////////////////////////////// -struct tag_LC_internals* GetLibraryEntryTable(){ - return &lc_internals; -} - -/////////////////////////////////////////////////////////////////////// -void _FlushIcache() { - u32 status; - u32 s1450; - u32 s1578; - u32 icache; - u32 *p; - - __asm__ ("mfc0 %0, $12\n" : "=r"(status) : ); - - __asm__ ("mtc0 %0, $12\n" :: "r"(0)); - - s1450 = *(int*)0xBF801450; - *(int*)0xBF801450&= ~1; - *(int*)0xBF801450; - - s1578 = *(int*)0xBF801578; - *(int*)0xBF801578 = 0; - *(int*)0xBF801578; - - icache = *(int*)0xFFFE0130; - *(int*)0xFFFE0130 = 0xC04; - *(int*)0xFFFE0130; - - __asm__ ("mtc0 %0, $12\n" :: "r"(0x10000)); - - for (p=0; p<(u32*)0x400; p+=4) // 4KB instruction cache - *p=0; - - __asm__ ("mtc0 %0, $12\n" :: "r"(0)); - - *(int*)0xFFFE0130 = icache; - *(int*)0xFFFE0130; - *(int*)0xBF801578 = s1578; - *(int*)0xBF801578; - *(int*)0xBF801450 = s1450; - *(int*)0xBF801450; - - __asm__ ("mtc0 %0, $12\n" : : "r"(status) ); -} - -void FlushIcache() { - __asm__ ( - "la $26, %0\n" - "lui $27, 0xA000\n" - "or $26, $27\n" - "jr $26\n" - "nop\n" - : : "i"(_FlushIcache) - ); -} - -/////////////////////////////////////////////////////////////////////// -void _FlushDcache() { - u32 status; - u32 s1450; - u32 s1578; - u32 icache; - u32 *p; - - __asm__ ("mfc0 %0, $12\n" : "=r"(status) : ); - - __asm__ ("mtc0 %0, $12\n" :: "r"(0)); - - s1450 = *(int*)0xBF801450; - *(int*)0xBF801450&= ~1; - *(int*)0xBF801450; - - s1578 = *(int*)0xBF801578; - *(int*)0xBF801578 = 0; - *(int*)0xBF801578; - - icache = *(int*)0xFFFE0130; - *(int*)0xFFFE0130 = 0xC4; - *(int*)0xFFFE0130; - - __asm__ ("mtc0 %0, $12\n" :: "r"(0x10000)); - - for (p=0; p<(u32*)0x100; p+=4) // 1KB data cache - *p=0; - - __asm__ ("mtc0 %0, $12\n" :: "r"(0)); - - *(int*)0xFFFE0130 = icache; - *(int*)0xFFFE0130; - *(int*)0xBF801578 = s1578; - *(int*)0xBF801578; - *(int*)0xBF801450 = s1450; - *(int*)0xBF801450; - - __asm__ ("mtc0 %0, $12\n" : : "r"(status) ); -} - -void FlushDcache(){ - __asm__ ( - "la $26, %0\n" - "lui $27, 0xA000\n" - "or $26, $27\n" - "jr $26\n" - "nop\n" - : : "i"(_FlushDcache) - ); -} - -/////////////////////////////////////////////////////////////////////// -void _SetIcache(u32 val) { - u32 status; - - __asm__ ("mfc0 %0, $12\n" : "=r"(status) : ); - - __asm__ ("mtc0 %0, $12\n" :: "r"(0)); - - *(int*)0xFFFE0130 = val; - *(int*)0xFFFE0130; - - __asm__ ("mtc0 %0, $12\n" : : "r"(status) ); -} - -void _SetCacheCtrl(u32 val) -{ - __asm__ ( - "la $26, %0\n" - "lui $27, 0xA000\n" - "or $26, $27\n" - "jr $26\n" - "nop\n" - : : "i"(_SetIcache) - ); -} - -/////////////////////////////////////////////////////////////////////// -int _ReadModuleHeader(void *image, fileInfo *result) -{ - COFF_HEADER *coffhdr = image; - COFF_scnhdr *section = (COFF_scnhdr*)((char*)image+sizeof(COFF_HEADER));//0x4C - - if ((coffhdr->f_magic==0x162) && //COFF loading - (coffhdr->opthdr.magic == 0x107) && - (coffhdr->f_nscns < 32) && - ((coffhdr->f_opthdr & 0x2FFFF) == 0x20038) && - (section->s_paddr == coffhdr->opthdr.text_start)){ - - if (coffhdr->opthdr.vstamp == 0x7001) - return -1; - result->type =1; - result->entry =coffhdr->opthdr.entry; - result->gp_value =coffhdr->opthdr.gp_value; - result->p1_vaddr =coffhdr->opthdr.text_start; - result->text_size =coffhdr->opthdr.tsize; - result->data_size =coffhdr->opthdr.dsize; - result->bss_size =coffhdr->opthdr.bsize; - result->p1_memsz =coffhdr->opthdr.bss_start+coffhdr->opthdr.bsize-coffhdr->opthdr.text_start; - result->moduleinfo =(moduleInfo*)coffhdr->opthdr.moduleinfo; - return result->type; - }else{ - ELF_HEADER* eh = (ELF_HEADER*)image; - ELF_PHR* ph= (ELF_PHR*)((char*)eh +eh->e_phoff); - //if ((eh->e_ident[EI_CLASS] != ELFCLASS32) || - //(eh->e_ident[EI_DATA]) != ELFDATA2LSB)) return -1;//break - if( *(u16*)(eh->e_ident+4) != 0x101 ) - return -1; - if (eh->e_machine != EM_MIPS) - return -1;//break - if (eh->e_phentsize != sizeof(ELF_PHR)) - return -1;//break - if (eh->e_phnum != 2) - return -1;//break - if (ph[0].p_type != PT_SCE_IOPMOD) - return -1;//break - if (eh->e_type != ET_SCE_IOPRELEXEC){ - if (eh->e_type != eh->e_phnum )//ET_EXEC) - return -1;//only - result->type=3; - }else - result->type=4; - ELF_IOPMOD* im= (ELF_IOPMOD*)((char*)image + ph[0].p_offset); - result->entry =im->entry; - result->gp_value=im->gp_value; - result->p1_vaddr=ph[1].p_vaddr; - result->text_size=im->text_size; - result->data_size=im->data_size; - result->bss_size=im->bss_size; - result->p1_memsz=ph[1].p_memsz; - result->moduleinfo=( moduleInfo*)im->moduleinfo; - return result->type; - } - return result->type=-1; -} - -#define MODULE_TYPE_COFF 1 -#define MODULE_TYPE_2 2 -#define MODULE_TYPE_EXEC 3 -#define MODULE_TYPE_IOPRELEXEC 4 - -/////////////////////////////////////////////////////////////////////// -void setImageInfo(fileInfo *fi, imageInfo *ii) -{ - ii->next =0; - ii->name =NULL; - ii->version =0; - ii->flags =0; - ii->modid =0; - if ((int)fi->moduleinfo != -1){ - ii->name =fi->moduleinfo->name; - ii->version =fi->moduleinfo->version; - } - ii->entry =fi->entry; - ii->gp_value =fi->gp_value; - ii->p1_vaddr =fi->p1_vaddr; - ii->text_size =fi->text_size; - ii->data_size =fi->data_size; - ii->bss_size =fi->bss_size; -} - -/////////////////////////////////////////////////////////////////////// -void load_type_1(COFF_HEADER *image){ - SHDR* s0=(SHDR*)( (char*)image + *(int*)((char*)image+0x60) ); - lc_memcpy(s0, image->opthdr.text_start, image->opthdr.tsize); - lc_memcpy((char*)s0+image->opthdr.tsize, image->opthdr.data_start, image->opthdr.dsize); - if (image->opthdr.bss_start && image->opthdr.bsize) - lc_zeromem((void*)image->opthdr.bss_start, image->opthdr.bsize/4); -} - -/////////////////////////////////////////////////////////////////////// -void load_type_3(void *image){ - ELF_PHR *ph=(ELF_PHR*)((char*)image+((ELF_HEADER*)image)->e_phoff); - lc_memcpy(image+ph[1].p_offset, ph[1].p_vaddr, ph[1].p_filesz); - if (ph[1].p_filesz < ph[1].p_memsz) - lc_zeromem(ph[1].p_vaddr+ph[1].p_filesz, - (ph[1].p_memsz-ph[1].p_filesz)/4); -} - -/////////////////////////////////////////////////////////////////////// -#define R_MIPS_32 2 -#define R_MIPS_26 4 -#define R_MIPS_HI16 5 -#define R_MIPS_LO16 6 - -void load_type_4(ELF_HEADER *image, fileInfo *fi) -{ - ELF_PHR *ph=(ELF_PHR*)((char*)image+image->e_phoff); - ELF_SHR* sh = (ELF_SHR*)((char*)image+image->e_shoff); - ELF_REL* rel; - int i,j,scount; - u32* b, *b2, tmp; - - //ph[0] - .iopmod, skip - fi->entry += fi->p1_vaddr; - fi->gp_value += fi->p1_vaddr; - if ((int)fi->moduleinfo != -1) - fi->moduleinfo = (moduleInfo*)((int)fi->moduleinfo + fi->p1_vaddr); - lc_memcpy((char*)image+ph[1].p_offset, fi->p1_vaddr, ph[1].p_filesz); - - if (ph[1].p_filesz < ph[1].p_memsz) { - lc_zeromem(ph[1].p_vaddr+ph[1].p_filesz+fi->p1_vaddr, (ph[1].p_memsz-ph[1].p_filesz)); - } - - for (i=1; ie_shnum; i++) { - if (sh[i].sh_type==SHT_REL) { - ELF_REL* rel =(ELF_REL*)(sh[i].sh_offset + (char*)image); - scount=sh[i].sh_size / sh[i].sh_entsize; - for (j=0; jp1_vaddr + rel[j].r_offset); - switch((u8)rel[j].r_info){ - case R_MIPS_LO16: - *b=(*b & 0xFFFF0000) | (((*b & 0x0000FFFF) + fi->p1_vaddr) & 0xFFFF); - break; - case R_MIPS_32: - *b+=fi->p1_vaddr; - break; - case R_MIPS_26: - *b = (*b & 0xfc000000) | (((*b & 0x03ffffff) + (fi->p1_vaddr >> 2)) & 0x03ffffff); - break; - case R_MIPS_HI16: - b2 =(u32*)(rel[j+1].r_offset + fi->p1_vaddr); - ++j; - - tmp = (*b << 16) + (int)(*(s16*)b2) + fi->p1_vaddr; - *b = (*b&0xffff0000) | ((((tmp>>15)+1)>>1)&0xffff); - *b2 = (*b2&0xffff0000) | (tmp&0xffff); - break; - } - } - } - } -} - -int _LoadModule(void *image, fileInfo *fi) -{ - u32* ptr; - int i; - switch (fi->type){ - case MODULE_TYPE_COFF: load_type_1(image); break; - case MODULE_TYPE_EXEC: load_type_3(image); break; - case MODULE_TYPE_IOPRELEXEC: load_type_4(image, fi); break; - default: return -1; - } - - setImageInfo(fi, (imageInfo*)(fi->p1_vaddr-0x30)); - - return 0; -} - -///////////////////////////////////////////////////////////////////////[OK] -int lc_memcpy(void *src,void *dest,int len){ - char* _src = (char*)src; - char* _dst = (char*)dest; - for (len=len; len>0; len--) - *_dst++=*_src++; -} - -///////////////////////////////////////////////////////////////////////[OK] -int lc_zeromem(void *addr,int len){ - for (; len>0; len--) *(char*)addr++=0; -} - -int lc_strlen(char *s) -{ - int len; - if (s==NULL) return 0; - for (len=0; *s++; len++); - return len; -} - -int recursive_set_a2(int* start, int* end, int val) -{ - *start++ = val; - if( start < end ) - return recursive_set_a2(start, end, val); - return 0; -} - -void* lc_memcpy_overlapping(char *dst,char *src,int len){ - if (dst==NULL) return 0; - - if (dst>=src) - while(--len>=0) - *(dst+len)=*(src+len); - else - while (len-->0) - *dst++=*src++; - - return dst; -} - -//////////////////////////////entrypoint/////////////////////////////// -void _start(BOOT_PARAMS *init) { - *(int*)0xFFFE0130 = 0x1e988; - __asm__ ( - "addiu $26, $0, 0\n" - "mtc0 $26, $12\n"); - //"move $fp, %0\n" - //"move $sp, %0\n" - //: : "r"((init->ramMBSize << 20) - 0x40)); - __asm__ ( - "j loadcore_start\n" - ); -} - -extern void* _ftext, *_etext, *_end; -typedef int (*IopEntryFn)(u32,void*,void*,void*); - -void loadcore_start(BOOT_PARAMS *pInitParams) -{ - fileInfo fi; - void (*entry)(); - u32 offset; - u32 status = 0x401; - int bm; - int i; - void** s0; // pointer in module list to current module? - BOOT_PARAMS params; - u32 s1, s2, s3, sp, a2; - - _dprintf("%s\n", __FUNCTION__); - - // Write 0x401 into the co-processor status register? - // This enables interrupts generally, and disables (masks) them all except hardware interrupt 0? - - lc_memcpy(pInitParams,¶ms,sizeof(BOOT_PARAMS)); - BOOTMODE_END = BOOTMODE_START = bootmodes; - - //_dprintf("module: %x\n", params.firstModuleAddr); - - lc_internals.let_next = (struct export*)params.firstModuleAddr; - lc_internals.let_prev = (struct export*)params.firstModuleAddr; - lc_internals.let_next->next = 0; - lc_internals.module_count = 2; // SYSMEM + LOADCORE - lc_internals.mda_prev = lc_internals.mda_next = NULL; - lc_internals.module_index = 3; // next available index - - for (i=0; i<17; i++){ - bootmodes[i]=0; - } - bootmodes_size=0; - - bm = params.bootInfo | 0x00040000; - RegisterBootMode((struct bootmode*)&bm); - - lc_internals.image_info = (imageInfo*)((u32)lc_internals.let_prev - 0x30); - lc_internals.image_info->modid = 1; // SYSMEM is the first module - lc_internals.image_info->next = (u32)&_ftext - 0x30; - ((imageInfo*)lc_internals.image_info->next)->modid = 2; // LOADCORE is the second module - - // find & fix LOADCORE imports (to SYSMEM) - _LinkImports((u32*)&_ftext, (u32)&_etext - (u32)&_ftext); - - RegisterLibraryEntries(&loadcore_stub); - - // reserve LOADCORE memory - AllocSysMemory(2, (u32)((u32)&_end - (((u32)&_ftext - 0x30) >> 8 << 8)), (void*)((((u32)&_ftext - 0x30) >> 8 << 8) & 0x1FFFFFFF)); - - if (params.pos) - params.pos = (u32)AllocSysMemory(2, params.size, (void*)params.pos); - - sp=(u32)alloca(0x10); - s0 = (void**)((sp - 0xDF0) & 0x1FFFFF00);//=0x001ff100 - recursive_set_a2((int*)s0, (void*)(sp+0x10), 0x11111111); - if ((u32)s0 < QueryMemSize()) - AllocSysMemory(2, QueryMemSize() - (u32)s0, s0); - - if (params.udnlString){ - int v0 = lc_strlen(params.udnlString); - int* v1 = (int*)alloca((v0 + 8 + 8) >> 3 << 3); - lc_memcpy_overlapping((char*)&v1[6], params.udnlString, v0+1); - params.udnlString = (char*)&v1[6]; - v1[4] = 0x01050000; - v1[5] = (int)&v1[6]; - RegisterBootMode((struct bootmode*)&v1[4]); // BTUPDATER bootmode 5 - } - - a2 = (params.numConfLines+1) * 4; - s0 = alloca((a2 + 7) >> 3 << 3) + 0x10; - lc_memcpy_overlapping((char*)s0, (char*)params.moduleAddrs, a2); //0x30020 - - s1 = 0; - params.moduleAddrs = (u32**)s0; - s2 = (u32)alloca(params.numConfLines << 3) + 0x10; - place = (u32*)s2; - *place = 0; - i = -1; - s3 = 1; - - _dprintf("loading modules: %d\n", params.numConfLines); - s0 += 2; // skip first two: SYSMEM, LOADCORE - for (; *s0; s0+=1) { - if ((u32)*s0 & 1){ - if (((u32)*s0 & 0xF) == s3) - s1 = (u32)*s0>>2; - }else{ - i += 1; - i &= 0xF; - - _dprintf("load module from %x\n", *s0); - switch(_ReadModuleHeader(*s0, &fi)){ - case MODULE_TYPE_COFF: - case MODULE_TYPE_EXEC: - a2 = ((fi.p1_vaddr - 0x30) >> 8 << 8) & 0x1FFFFFFF; - if (NULL == AllocSysMemory(2, fi.p1_memsz + fi.p1_vaddr - a2, (void*)a2)) - goto HALT; - break; - - case MODULE_TYPE_2: - case MODULE_TYPE_IOPRELEXEC: - if (fi.p1_vaddr = (u32)((s1 == 0) ? - AllocSysMemory(0, fi.p1_memsz+0x30, 0) : - AllocSysMemory(2, fi.p1_memsz+0x30, (void*)s1)) ) - fi.p1_vaddr += 0x30; - else - goto HALT; - break; - - default: - _dprintf("could not find module at %x\n", *s0); - goto HALT; - } - - _LoadModule(*s0, &fi); - _dprintf("loading module %s: at offset %x, memsz=%x, type=%x, entry=%x\n", fi.moduleinfo->name, fi.p1_vaddr, fi.p1_memsz, fi.type, fi.entry); - - if (0 == _LinkImports((u32*)fi.p1_vaddr, fi.text_size)) { - - FlushIcache(); - __asm__("move $gp, %0\n" : : "r"(fi.gp_value)); - // call the entry point - s1 = ((IopEntryFn)fi.entry)(0, NULL, s0, NULL); - - if ((s1 & 3) == 0){ - _LinkModule((imageInfo*)(fi.p1_vaddr - 0x30)); - if (s1 & ~3) - _RegisterBootupCBFunc((int (*)(int *, int))(s1 & ~3), BOOTUPCB_NORMAL, 0); - }else{ - _UnlinkImports((void*)fi.p1_vaddr, fi.text_size); - FreeSysMemory((void*)((fi.p1_vaddr - 0x30) >> 8 << 8)); - } - }else { - FreeSysMemory((void*)((fi.p1_vaddr - 0x30) >> 8 << 8)); - } - - s1 = 0; - } - } - - if (params.pos) - FreeSysMemory((void*)params.pos); - - for (i=BOOTUPCB_FIRST; i + +#include "ksysmem.h" +#include "kloadcore.h" +#include "iopdebug.h" +#include "iopelf.h" +#include "romdir.h" +#include "irx.h" // ps2sdk file for IMPORT_MAGIC + +#define BOOTMODE_START *((volatile u32**)0x3F0) +#define BOOTMODE_END *((volatile u32**)0x3F4) + +void _start(BOOT_PARAMS *init); // has to be declared first! + +struct tag_LC_internals { + struct export* let_next, *let_prev; + struct export* mda_next, *mda_prev;//.prev==free + imageInfo *image_info; // 0x800?0x830? + int module_count; + int module_index; +} lc_internals; + +u32 free; +u32 sysmem_00; +u32 modules_count; +u32 module_index; +u32 *place; // addr of 8 * 31 = 8 * linesInIopbtconf //place[2][31] +u32 bootmodes[17]; // was 16? +u32 bootmodes_size; +int debug=0; + +u32 bm_end; + +#define _dprintf(fmt, args...) \ + if (debug > 0) __printf("loadcore:%d: " fmt, __LINE__, ## args) + +void retonly(); +struct tag_LC_internals* GetLibraryEntryTable(); +void FlushIcache(); +void FlushDcache(); +int RegisterLibraryEntries(struct export *es); +int ReleaseLibraryEntries(struct export *e); +int _LinkImports(u32 *addr, int size); +int _UnlinkImports(void *addr, int size); +int RegisterNonAutoLinkEntries(struct export *e); +int QueryLibraryEntryTable(struct export *e); +u32 *QueryBootMode(int id); +void RegisterBootMode(struct bootmode *b); +int SetNonAutoLinkFlag(struct export *e); +int UnsetNonAutoLinkFlag(struct export *e); +void _LinkModule(imageInfo *ii); +void _UnlinkModule(imageInfo *ii); +int _RegisterBootupCBFunc(int (*function)(int *, int), int priority, int *result); +void _SetCacheCtrl(u32 val); +int _ReadModuleHeader(void *image, fileInfo *result); +int _LoadModule(void *image, fileInfo *fi); +u32 _FindImageInfo(void *addr); + +struct export loadcore_stub __attribute__((section(".text"))) ={ + EXPORT_MAGIC, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "loadcore", + (func)_start, // entrypoint + (func)retonly, + (func)retonly, + (func)GetLibraryEntryTable, + (func)FlushIcache, + (func)FlushDcache, + (func)RegisterLibraryEntries, + (func)ReleaseLibraryEntries, + (func)_LinkImports, + (func)_UnlinkImports, + (func)RegisterNonAutoLinkEntries, + (func)QueryLibraryEntryTable, + (func)QueryBootMode, + (func)RegisterBootMode, + (func)SetNonAutoLinkFlag, + (func)UnsetNonAutoLinkFlag, + (func)_LinkModule, + (func)_UnlinkModule, + (func)retonly, + (func)retonly, + (func)_RegisterBootupCBFunc, + (func)_SetCacheCtrl, + (func)_ReadModuleHeader, + (func)_LoadModule, + (func)_FindImageInfo, + 0 +}; + +/////////////////////////////////////////////////////////////////////// +void retonly(){} + +/////////////////////////////////////////////////////////////////////// +void RegisterBootMode(struct bootmode *b) { + int i; + + _dprintf("%s\n", __FUNCTION__); + if (((b->len + 1) * 4) < (16-bootmodes_size)) { + u32 *p = &bootmodes[bootmodes_size]; + for (i=0; ilen + 1; i++) p[i]=((u32*)b)[i]; + p[i]=0; + bootmodes_size+= b->len + 1; + } +} + +/////////////////////////////////////////////////////////////////////// +u32 *QueryBootMode(int id) { + u32 *b; + + for (b = (u32*)&bootmodes[0]; *b; b += ((struct bootmode*)b)->len + 1) + if (id == ((struct bootmode*)b)->id) + return b; + return NULL; +} + +/////////////////////////////////////////////////////////////////////// +int match_name(struct export *src, struct export *dst){ + return (*(int*)(src->name+0) == *(int*)(dst->name+0)) && + (*(int*)(src->name+4) == *(int*)(dst->name+4)); +} + +/////////////////////////////////////////////////////////////////////// +int match_version_major(struct export *src, struct export *dst){ + return ((src->version>>8) - (dst->version>>8)); +} + +/////////////////////////////////////////////////////////////////////// +int match_version_minor(struct export *src, struct export *dst){ + return ((unsigned char)src->version - (unsigned char)dst->version); +} + +/////////////////////////////////////////////////////////////////////// +int fix_imports(struct import *imp, struct export *exp){ + func *ef; + struct func_stub *fs; + int count=0, ordinal; + + for (ef=exp->func; *ef; ef++){ + count++; //count number of exported functions + } + _dprintf("%s (%d functions)\n", __FUNCTION__, count); + + for (fs=imp->func; fs->jr_ra; fs++) { + if ((fs->addiu0 >> 26) != INS_ADDIU) break; + + ordinal = fs->addiu0 & 0xFFFF; + if (ordinal < count) { +// _dprintf("%s linking ordinal %d to %x\n", __FUNCTION__, ordinal, exp->func[ordinal]); + fs->jr_ra=(((u32)exp->func[ordinal]>>2) & 0x3FFFFFF) | INS_J; + } else { + fs->jr_ra=INS_JR_RA; + } + } + + imp->flags |=FLAG_IMPORT_QUEUED; + return 0; +} + +/////////////////////////////////////////////////////////////////////// +// Check the structure of the import table. +// Return 0 if a bad or empty import table is detected. +// Return a non-zero value if a valid import table is detected. +// +int check_import_table(struct import* imp){ + struct func_stub *f; + + if (imp->magic != IMPORT_MAGIC) + return 0; + for (f=imp->func; f->jr_ra; f++){ + if (f->addiu0 >> 26 != INS_ADDIU) + return 0; + if ((f->jr_ra!=INS_JR_RA) && (f->jr_ra>26!=INS_JR)) + return 0; + } + if (f->addiu0) + return 0; + return (imp->func < f); +} + +///////////////////////////////////////////////////////////////////////[OK] + +// Return 0 if successful +int link_client(struct import *imp){ + struct export *e; + +// _dprintf("%s\n", __FUNCTION__); + for (e=lc_internals.let_next; e; e=(struct export*)e->magic_link) { + if (debug > 0){ + // Zero terminate the name before printing it + char ename[9], iname[9]; + *(int*)ename = *(int*)e->name; *(int*)(ename+4) = *(int*)(e->name+4); ename[8] = 0; + *(int*)iname = *(int*)imp->name; *(int*)(iname+4) = *(int*)(imp->name+4);iname[8] = 0; + + //__printf("loadcore: %s: %s, %s\n", __FUNCTION__, ename, iname); + } + + if (!(e->flags & FLAG_NO_AUTO_LINK)){ + if ( match_name(e, (struct export*)imp)){ + if (match_version_major(e, (struct export*)imp)==0) { + fix_imports(imp, e); + imp->next=(struct import*)e->next; + e->next=(struct export*)imp; + FlushIcache(); + return 0; + } else { +// _dprintf("%s: version does not match\n", __FUNCTION__); + } + } else { +// _dprintf("%s: name does not match\n", __FUNCTION__); + } + } else { +// _dprintf("%s: e->flags bit 0 is 0\n", __FUNCTION__); + } + } + _dprintf("%s: FAILED to find a match\n", __FUNCTION__); + return -1; +} + +///////////////////////////////////////////////////////////////////////[OK] +int _LinkImports(u32 *addr, int size) +{ + struct import *p; + int i; + + _dprintf("%s: %x, %d\n", __FUNCTION__, addr, size); + for (i=0; imagic == IMPORT_MAGIC) && + check_import_table(p) && + ((p->flags & 7) == 0) && + link_client(p)) { + _UnlinkImports(p, size); + return -1; + } + } + return 0; +} + +///////////////////////////////////////////////////////////////////////[OK] +int unlink_client(struct import *i1, struct import *i2){ + struct import *i, *tmp; + + if (i1->next == i2){ + i1->next=i2->next; + return 0; + } + for (i = i1->next; i->next;) { + tmp=i->next; + if (tmp==i2) { + i->next=tmp->next; + tmp->next=NULL; + return 0; + } + i=tmp; + } + return -1; +} + +///////////////////////////////////////////////////////////////////////[OK] +void restore_imports(struct import* imp){ + struct func_stub *f; + + for (f=imp->func; (f->jr_ra) && ((f->addiu0 >> 26) == INS_ADDIU); f++) + f->jr_ra=INS_JR_RA; +} + +///////////////////////////////////////////////////////////////////////[OK] +int _UnlinkImports(void *addr, int size) +{ + struct export *e; + struct export *i; + struct export *tmp; + void *limit = addr + (size & ~0x3); + + for (e = (struct export*)lc_internals.let_next; e; e=(struct export*)e->magic_link){ + for (i = e->next; i; i=i->next) { + if (((u32)i >= (u32)addr) && ((u32)i < (u32)limit)) { + if (unlink_client((struct import*)e, (struct import*)i)) + return -1; + i->flags &= ~0x7; + restore_imports((struct import*)i); + } + } + if (((u32)e >= (u32)addr) && ((u32)e < (u32)limit)) + ReleaseLibraryEntries(e); + } +/* + for (i=let.mda; i->next; ) + if ((i->next >= addr) && (i->next < limit)){ + i->next->flags &= ~0x7; + restore_imports(i->next); + tmp = i->next->next; + i->next->next=NULL; + i->next=tmp; + }else + i=i->next; +*/ + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int SetNonAutoLinkFlag(struct export *e) +{ + return (e->flags |= FLAG_NO_AUTO_LINK); +} + +/////////////////////////////////////////////////////////////////////// +int UnsetNonAutoLinkFlag(struct export *e) +{ + return (e->flags &= ~FLAG_NO_AUTO_LINK); +} + +/////////////////////////////////////////////////////////////////////// +int _RegisterBootupCBFunc(int (*function)(int *, int), int priority, int *result) +{ + int x; + register int r; + if (place==NULL){ + x=1; + r=function(&x, 0); + if (result) *result=r; + return 0; + } + + __asm__("move %0, $gp\n" : "=r"(x) : ); + + place[0]=(u32)function + (priority & 3); + place[1]=x; + place[2]=0; + place+=2; + return 1; +} + +/////////////////////////////////////////////////////////////////////// +void _LinkModule(imageInfo *ii) +{ + imageInfo* p; + for (p=lc_internals.image_info; p->next && (p->next < (u32)ii); p=(imageInfo*)p->next); + + ii->next=p->next; + p->next=(u32)ii; + + ii->modid=module_index++; + modules_count++; +} + +/////////////////////////////////////////////////////////////////////// +void _UnlinkModule(imageInfo *ii) +{ + imageInfo *p; + if (ii) + for (p=lc_internals.image_info; p->next; p=(imageInfo*)p->next) + if (p->next == (u32)ii){ + p->next=((imageInfo*)p->next)->next; + modules_count--; + return; + } +} + +u32 _FindImageInfo(void *addr) +{ + register imageInfo *ii; + for (ii=lc_internals.image_info; ii; ii=(imageInfo*)ii->next) + if(((u32)addr>=ii->p1_vaddr) && + ((u32)addr p1_vaddr + ii->text_size + ii->data_size + ii->bss_size)) + return (u32)ii; + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int RegisterLibraryEntries(struct export *es){ + struct export *p; + struct export *plast; + struct export *pnext; + struct export *tmp; + struct export *snext; + + if ((es == NULL) || (es->magic_link != EXPORT_MAGIC)) + return -1; + + if (debug > 0){ + // Zero terminate the name before printing it + char ename[9]; + *(int*)ename = *(int*)es->name; + *(int*)(ename+4) = *(int*)(es->name+4); + ename[8] = 0; + + __printf("loadcore: %s (%x): %s, %x\n", __FUNCTION__, es, es->name, es->version); + } + + + plast=NULL; + for (p=(struct export*)lc_internals.let_next; p; p=(struct export*)p->magic_link) { + if (match_name(es, p) == 0 || + match_version_major(es, p) == 0) continue; + + if (match_version_minor(es, p) == 0) + return -1; + _dprintf("%s: found match\n", __FUNCTION__); + pnext = p->next; + p->next = NULL; + + for (tmp = pnext; tmp; ) { + if (tmp->flags & FLAG_NO_AUTO_LINK) { + pnext->magic_link = (u32)tmp; + pnext = tmp->next; + tmp->next = NULL; + } else { + tmp->next=plast; + plast=tmp; + } + tmp=tmp->next; + } + } + + if( lc_internals.mda_next ) { + for (tmp = lc_internals.mda_next; tmp->next; tmp=tmp->next) { //free + if ((match_name(es, tmp->next)) && + (match_version_major(es, tmp->next)==0)){ + _dprintf("%s: freeing module\n", __FUNCTION__); + snext=tmp->next->next; + tmp->next->next=plast; + plast=tmp->next; + tmp->next=snext; + } else tmp=tmp->next; + } + } + + es->next=0; + while (plast) { + snext=plast->next; + fix_imports((struct import*)plast, es); + plast->next=es->next; + es->next=plast; + plast=snext; + } + es->flags &= ~FLAG_NO_AUTO_LINK; + es->magic_link=(u32)lc_internals.let_next; + lc_internals.let_next=es; + FlushIcache(); + + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int ReleaseLibraryEntries(struct export *e) +{ + register struct export *n, *p, *next, *prev; + + p = lc_internals.let_next; + while ((p) && (p!=e)){ + prev=p; + p=(struct export*)prev->magic_link; + } + if (p != e) // if (0 != e) + return -1; //japanese BUG for e==p==0 + + n =e->next; + e ->next =0; + + prev->magic_link=e->magic_link; + e ->magic_link=0x41C00000; + + while(n) { + next = n->next; + if (link_client((struct import*)n)){ + restore_imports((struct import*)n); + n->flags=(n->flags & ~2) | 4; + n->next = lc_internals.mda_prev; + lc_internals.mda_prev=n; + } + n=next; + } + + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int RegisterNonAutoLinkEntries(struct export *e) +{ + if ((e == NULL) || (e->magic_link != EXPORT_MAGIC)){ + return -1; + } + e->flags |= FLAG_NO_AUTO_LINK; + e->magic_link = (u32)lc_internals.let_next; // --add as first + lc_internals.let_next = e; // / + FlushIcache(); + + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int QueryLibraryEntryTable(struct export *e) +{ + struct export *p = lc_internals.let_next; + while (p){ + if ((match_name(p, e)) && (match_version_major(p, e)==0)){ + return (int)p->func; + } + p=(struct export*)p->magic_link; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////// +struct tag_LC_internals* GetLibraryEntryTable(){ + return &lc_internals; +} + +/////////////////////////////////////////////////////////////////////// +void _FlushIcache() { + u32 status; + u32 s1450; + u32 s1578; + u32 icache; + u32 *p; + + __asm__ ("mfc0 %0, $12\n" : "=r"(status) : ); + + __asm__ ("mtc0 %0, $12\n" :: "r"(0)); + + s1450 = *(int*)0xBF801450; + *(int*)0xBF801450&= ~1; + *(int*)0xBF801450; + + s1578 = *(int*)0xBF801578; + *(int*)0xBF801578 = 0; + *(int*)0xBF801578; + + icache = *(int*)0xFFFE0130; + *(int*)0xFFFE0130 = 0xC04; + *(int*)0xFFFE0130; + + __asm__ ("mtc0 %0, $12\n" :: "r"(0x10000)); + + for (p=0; p<(u32*)0x400; p+=4) // 4KB instruction cache + *p=0; + + __asm__ ("mtc0 %0, $12\n" :: "r"(0)); + + *(int*)0xFFFE0130 = icache; + *(int*)0xFFFE0130; + *(int*)0xBF801578 = s1578; + *(int*)0xBF801578; + *(int*)0xBF801450 = s1450; + *(int*)0xBF801450; + + __asm__ ("mtc0 %0, $12\n" : : "r"(status) ); +} + +void FlushIcache() { + __asm__ ( + "la $26, %0\n" + "lui $27, 0xA000\n" + "or $26, $27\n" + "jr $26\n" + "nop\n" + : : "i"(_FlushIcache) + ); +} + +/////////////////////////////////////////////////////////////////////// +void _FlushDcache() { + u32 status; + u32 s1450; + u32 s1578; + u32 icache; + u32 *p; + + __asm__ ("mfc0 %0, $12\n" : "=r"(status) : ); + + __asm__ ("mtc0 %0, $12\n" :: "r"(0)); + + s1450 = *(int*)0xBF801450; + *(int*)0xBF801450&= ~1; + *(int*)0xBF801450; + + s1578 = *(int*)0xBF801578; + *(int*)0xBF801578 = 0; + *(int*)0xBF801578; + + icache = *(int*)0xFFFE0130; + *(int*)0xFFFE0130 = 0xC4; + *(int*)0xFFFE0130; + + __asm__ ("mtc0 %0, $12\n" :: "r"(0x10000)); + + for (p=0; p<(u32*)0x100; p+=4) // 1KB data cache + *p=0; + + __asm__ ("mtc0 %0, $12\n" :: "r"(0)); + + *(int*)0xFFFE0130 = icache; + *(int*)0xFFFE0130; + *(int*)0xBF801578 = s1578; + *(int*)0xBF801578; + *(int*)0xBF801450 = s1450; + *(int*)0xBF801450; + + __asm__ ("mtc0 %0, $12\n" : : "r"(status) ); +} + +void FlushDcache(){ + __asm__ ( + "la $26, %0\n" + "lui $27, 0xA000\n" + "or $26, $27\n" + "jr $26\n" + "nop\n" + : : "i"(_FlushDcache) + ); +} + +/////////////////////////////////////////////////////////////////////// +void _SetIcache(u32 val) { + u32 status; + + __asm__ ("mfc0 %0, $12\n" : "=r"(status) : ); + + __asm__ ("mtc0 %0, $12\n" :: "r"(0)); + + *(int*)0xFFFE0130 = val; + *(int*)0xFFFE0130; + + __asm__ ("mtc0 %0, $12\n" : : "r"(status) ); +} + +void _SetCacheCtrl(u32 val) +{ + __asm__ ( + "la $26, %0\n" + "lui $27, 0xA000\n" + "or $26, $27\n" + "jr $26\n" + "nop\n" + : : "i"(_SetIcache) + ); +} + +/////////////////////////////////////////////////////////////////////// +int _ReadModuleHeader(void *image, fileInfo *result) +{ + COFF_HEADER *coffhdr = image; + COFF_scnhdr *section = (COFF_scnhdr*)((char*)image+sizeof(COFF_HEADER));//0x4C + + if ((coffhdr->f_magic==0x162) && //COFF loading + (coffhdr->opthdr.magic == 0x107) && + (coffhdr->f_nscns < 32) && + ((coffhdr->f_opthdr & 0x2FFFF) == 0x20038) && + (section->s_paddr == coffhdr->opthdr.text_start)){ + + if (coffhdr->opthdr.vstamp == 0x7001) + return -1; + result->type =1; + result->entry =coffhdr->opthdr.entry; + result->gp_value =coffhdr->opthdr.gp_value; + result->p1_vaddr =coffhdr->opthdr.text_start; + result->text_size =coffhdr->opthdr.tsize; + result->data_size =coffhdr->opthdr.dsize; + result->bss_size =coffhdr->opthdr.bsize; + result->p1_memsz =coffhdr->opthdr.bss_start+coffhdr->opthdr.bsize-coffhdr->opthdr.text_start; + result->moduleinfo =(moduleInfo*)coffhdr->opthdr.moduleinfo; + return result->type; + }else{ + ELF_HEADER* eh = (ELF_HEADER*)image; + ELF_PHR* ph= (ELF_PHR*)((char*)eh +eh->e_phoff); + //if ((eh->e_ident[EI_CLASS] != ELFCLASS32) || + //(eh->e_ident[EI_DATA]) != ELFDATA2LSB)) return -1;//break + if( *(u16*)(eh->e_ident+4) != 0x101 ) + return -1; + if (eh->e_machine != EM_MIPS) + return -1;//break + if (eh->e_phentsize != sizeof(ELF_PHR)) + return -1;//break + if (eh->e_phnum != 2) + return -1;//break + if (ph[0].p_type != PT_SCE_IOPMOD) + return -1;//break + if (eh->e_type != ET_SCE_IOPRELEXEC){ + if (eh->e_type != eh->e_phnum )//ET_EXEC) + return -1;//only + result->type=3; + }else + result->type=4; + ELF_IOPMOD* im= (ELF_IOPMOD*)((char*)image + ph[0].p_offset); + result->entry =im->entry; + result->gp_value=im->gp_value; + result->p1_vaddr=ph[1].p_vaddr; + result->text_size=im->text_size; + result->data_size=im->data_size; + result->bss_size=im->bss_size; + result->p1_memsz=ph[1].p_memsz; + result->moduleinfo=( moduleInfo*)im->moduleinfo; + return result->type; + } + return result->type=-1; +} + +#define MODULE_TYPE_COFF 1 +#define MODULE_TYPE_2 2 +#define MODULE_TYPE_EXEC 3 +#define MODULE_TYPE_IOPRELEXEC 4 + +/////////////////////////////////////////////////////////////////////// +void setImageInfo(fileInfo *fi, imageInfo *ii) +{ + ii->next =0; + ii->name =NULL; + ii->version =0; + ii->flags =0; + ii->modid =0; + if ((int)fi->moduleinfo != -1){ + ii->name =fi->moduleinfo->name; + ii->version =fi->moduleinfo->version; + } + ii->entry =fi->entry; + ii->gp_value =fi->gp_value; + ii->p1_vaddr =fi->p1_vaddr; + ii->text_size =fi->text_size; + ii->data_size =fi->data_size; + ii->bss_size =fi->bss_size; +} + +/////////////////////////////////////////////////////////////////////// +void load_type_1(COFF_HEADER *image){ + SHDR* s0=(SHDR*)( (char*)image + *(int*)((char*)image+0x60) ); + lc_memcpy(s0, image->opthdr.text_start, image->opthdr.tsize); + lc_memcpy((char*)s0+image->opthdr.tsize, image->opthdr.data_start, image->opthdr.dsize); + if (image->opthdr.bss_start && image->opthdr.bsize) + lc_zeromem((void*)image->opthdr.bss_start, image->opthdr.bsize/4); +} + +/////////////////////////////////////////////////////////////////////// +void load_type_3(void *image){ + ELF_PHR *ph=(ELF_PHR*)((char*)image+((ELF_HEADER*)image)->e_phoff); + lc_memcpy(image+ph[1].p_offset, ph[1].p_vaddr, ph[1].p_filesz); + if (ph[1].p_filesz < ph[1].p_memsz) + lc_zeromem(ph[1].p_vaddr+ph[1].p_filesz, + (ph[1].p_memsz-ph[1].p_filesz)/4); +} + +/////////////////////////////////////////////////////////////////////// +#define R_MIPS_32 2 +#define R_MIPS_26 4 +#define R_MIPS_HI16 5 +#define R_MIPS_LO16 6 + +void load_type_4(ELF_HEADER *image, fileInfo *fi) +{ + ELF_PHR *ph=(ELF_PHR*)((char*)image+image->e_phoff); + ELF_SHR* sh = (ELF_SHR*)((char*)image+image->e_shoff); + ELF_REL* rel; + int i,j,scount; + u32* b, *b2, tmp; + + //ph[0] - .iopmod, skip + fi->entry += fi->p1_vaddr; + fi->gp_value += fi->p1_vaddr; + if ((int)fi->moduleinfo != -1) + fi->moduleinfo = (moduleInfo*)((int)fi->moduleinfo + fi->p1_vaddr); + lc_memcpy((char*)image+ph[1].p_offset, fi->p1_vaddr, ph[1].p_filesz); + + if (ph[1].p_filesz < ph[1].p_memsz) { + lc_zeromem(ph[1].p_vaddr+ph[1].p_filesz+fi->p1_vaddr, (ph[1].p_memsz-ph[1].p_filesz)); + } + + for (i=1; ie_shnum; i++) { + if (sh[i].sh_type==SHT_REL) { + ELF_REL* rel =(ELF_REL*)(sh[i].sh_offset + (char*)image); + scount=sh[i].sh_size / sh[i].sh_entsize; + for (j=0; jp1_vaddr + rel[j].r_offset); + switch((u8)rel[j].r_info){ + case R_MIPS_LO16: + *b=(*b & 0xFFFF0000) | (((*b & 0x0000FFFF) + fi->p1_vaddr) & 0xFFFF); + break; + case R_MIPS_32: + *b+=fi->p1_vaddr; + break; + case R_MIPS_26: + *b = (*b & 0xfc000000) | (((*b & 0x03ffffff) + (fi->p1_vaddr >> 2)) & 0x03ffffff); + break; + case R_MIPS_HI16: + b2 =(u32*)(rel[j+1].r_offset + fi->p1_vaddr); + ++j; + + tmp = (*b << 16) + (int)(*(s16*)b2) + fi->p1_vaddr; + *b = (*b&0xffff0000) | ((((tmp>>15)+1)>>1)&0xffff); + *b2 = (*b2&0xffff0000) | (tmp&0xffff); + break; + } + } + } + } +} + +int _LoadModule(void *image, fileInfo *fi) +{ + u32* ptr; + int i; + switch (fi->type){ + case MODULE_TYPE_COFF: load_type_1(image); break; + case MODULE_TYPE_EXEC: load_type_3(image); break; + case MODULE_TYPE_IOPRELEXEC: load_type_4(image, fi); break; + default: return -1; + } + + setImageInfo(fi, (imageInfo*)(fi->p1_vaddr-0x30)); + + return 0; +} + +///////////////////////////////////////////////////////////////////////[OK] +int lc_memcpy(void *src,void *dest,int len){ + char* _src = (char*)src; + char* _dst = (char*)dest; + for (len=len; len>0; len--) + *_dst++=*_src++; +} + +///////////////////////////////////////////////////////////////////////[OK] +int lc_zeromem(void *addr,int len){ + for (; len>0; len--) *(char*)addr++=0; +} + +int lc_strlen(char *s) +{ + int len; + if (s==NULL) return 0; + for (len=0; *s++; len++); + return len; +} + +int recursive_set_a2(int* start, int* end, int val) +{ + *start++ = val; + if( start < end ) + return recursive_set_a2(start, end, val); + return 0; +} + +void* lc_memcpy_overlapping(char *dst,char *src,int len){ + if (dst==NULL) return 0; + + if (dst>=src) + while(--len>=0) + *(dst+len)=*(src+len); + else + while (len-->0) + *dst++=*src++; + + return dst; +} + +//////////////////////////////entrypoint/////////////////////////////// +void _start(BOOT_PARAMS *init) { + *(int*)0xFFFE0130 = 0x1e988; + __asm__ ( + "addiu $26, $0, 0\n" + "mtc0 $26, $12\n"); + //"move $fp, %0\n" + //"move $sp, %0\n" + //: : "r"((init->ramMBSize << 20) - 0x40)); + __asm__ ( + "j loadcore_start\n" + ); +} + +extern void* _ftext, *_etext, *_end; +typedef int (*IopEntryFn)(u32,void*,void*,void*); + +void loadcore_start(BOOT_PARAMS *pInitParams) +{ + fileInfo fi; + void (*entry)(); + u32 offset; + u32 status = 0x401; + int bm; + int i; + void** s0; // pointer in module list to current module? + BOOT_PARAMS params; + u32 s1, s2, s3, sp, a2; + + _dprintf("%s\n", __FUNCTION__); + + // Write 0x401 into the co-processor status register? + // This enables interrupts generally, and disables (masks) them all except hardware interrupt 0? + + lc_memcpy(pInitParams,¶ms,sizeof(BOOT_PARAMS)); + BOOTMODE_END = BOOTMODE_START = bootmodes; + + //_dprintf("module: %x\n", params.firstModuleAddr); + + lc_internals.let_next = (struct export*)params.firstModuleAddr; + lc_internals.let_prev = (struct export*)params.firstModuleAddr; + lc_internals.let_next->next = 0; + lc_internals.module_count = 2; // SYSMEM + LOADCORE + lc_internals.mda_prev = lc_internals.mda_next = NULL; + lc_internals.module_index = 3; // next available index + + for (i=0; i<17; i++){ + bootmodes[i]=0; + } + bootmodes_size=0; + + bm = params.bootInfo | 0x00040000; + RegisterBootMode((struct bootmode*)&bm); + + lc_internals.image_info = (imageInfo*)((u32)lc_internals.let_prev - 0x30); + lc_internals.image_info->modid = 1; // SYSMEM is the first module + lc_internals.image_info->next = (u32)&_ftext - 0x30; + ((imageInfo*)lc_internals.image_info->next)->modid = 2; // LOADCORE is the second module + + // find & fix LOADCORE imports (to SYSMEM) + _LinkImports((u32*)&_ftext, (u32)&_etext - (u32)&_ftext); + + RegisterLibraryEntries(&loadcore_stub); + + // reserve LOADCORE memory + AllocSysMemory(2, (u32)((u32)&_end - (((u32)&_ftext - 0x30) >> 8 << 8)), (void*)((((u32)&_ftext - 0x30) >> 8 << 8) & 0x1FFFFFFF)); + + if (params.pos) + params.pos = (u32)AllocSysMemory(2, params.size, (void*)params.pos); + + sp=(u32)alloca(0x10); + s0 = (void**)((sp - 0xDF0) & 0x1FFFFF00);//=0x001ff100 + recursive_set_a2((int*)s0, (void*)(sp+0x10), 0x11111111); + if ((u32)s0 < QueryMemSize()) + AllocSysMemory(2, QueryMemSize() - (u32)s0, s0); + + if (params.udnlString){ + int v0 = lc_strlen(params.udnlString); + int* v1 = (int*)alloca((v0 + 8 + 8) >> 3 << 3); + lc_memcpy_overlapping((char*)&v1[6], params.udnlString, v0+1); + params.udnlString = (char*)&v1[6]; + v1[4] = 0x01050000; + v1[5] = (int)&v1[6]; + RegisterBootMode((struct bootmode*)&v1[4]); // BTUPDATER bootmode 5 + } + + a2 = (params.numConfLines+1) * 4; + s0 = alloca((a2 + 7) >> 3 << 3) + 0x10; + lc_memcpy_overlapping((char*)s0, (char*)params.moduleAddrs, a2); //0x30020 + + s1 = 0; + params.moduleAddrs = (u32**)s0; + s2 = (u32)alloca(params.numConfLines << 3) + 0x10; + place = (u32*)s2; + *place = 0; + i = -1; + s3 = 1; + + _dprintf("loading modules: %d\n", params.numConfLines); + s0 += 2; // skip first two: SYSMEM, LOADCORE + for (; *s0; s0+=1) { + if ((u32)*s0 & 1){ + if (((u32)*s0 & 0xF) == s3) + s1 = (u32)*s0>>2; + }else{ + i += 1; + i &= 0xF; + + _dprintf("load module from %x\n", *s0); + switch(_ReadModuleHeader(*s0, &fi)){ + case MODULE_TYPE_COFF: + case MODULE_TYPE_EXEC: + a2 = ((fi.p1_vaddr - 0x30) >> 8 << 8) & 0x1FFFFFFF; + if (NULL == AllocSysMemory(2, fi.p1_memsz + fi.p1_vaddr - a2, (void*)a2)) + goto HALT; + break; + + case MODULE_TYPE_2: + case MODULE_TYPE_IOPRELEXEC: + if (fi.p1_vaddr = (u32)((s1 == 0) ? + AllocSysMemory(0, fi.p1_memsz+0x30, 0) : + AllocSysMemory(2, fi.p1_memsz+0x30, (void*)s1)) ) + fi.p1_vaddr += 0x30; + else + goto HALT; + break; + + default: + _dprintf("could not find module at %x\n", *s0); + goto HALT; + } + + _LoadModule(*s0, &fi); + _dprintf("loading module %s: at offset %x, memsz=%x, type=%x, entry=%x\n", fi.moduleinfo->name, fi.p1_vaddr, fi.p1_memsz, fi.type, fi.entry); + + if (0 == _LinkImports((u32*)fi.p1_vaddr, fi.text_size)) { + + FlushIcache(); + __asm__("move $gp, %0\n" : : "r"(fi.gp_value)); + // call the entry point + s1 = ((IopEntryFn)fi.entry)(0, NULL, s0, NULL); + + if ((s1 & 3) == 0){ + _LinkModule((imageInfo*)(fi.p1_vaddr - 0x30)); + if (s1 & ~3) + _RegisterBootupCBFunc((int (*)(int *, int))(s1 & ~3), BOOTUPCB_NORMAL, 0); + }else{ + _UnlinkImports((void*)fi.p1_vaddr, fi.text_size); + FreeSysMemory((void*)((fi.p1_vaddr - 0x30) >> 8 << 8)); + } + }else { + FreeSysMemory((void*)((fi.p1_vaddr - 0x30) >> 8 << 8)); + } + + s1 = 0; + } + } + + if (params.pos) + FreeSysMemory((void*)params.pos); + + for (i=BOOTUPCB_FIRST; iname[0] == 'R' && - dir_entry->name[1] == 'E' && - dir_entry->name[2] == 'S' && - dir_entry->name[3] == 'E' && - dir_entry->name[4] == 'T' && - dir_entry->name[5] == 0 && - (ROUND_UP(dir_entry->fileSize,16) == offset) ) - { - romDirInfo->romPtr = (u32)searchStartAddr; // start of rom - romDirInfo->romdirPtr = dir_entry; // start of romdir structure - romDirInfo->extinfoPtr = (u32)dir_entry + dir_entry[1].fileSize; // start of extinfo - return romDirInfo; - } - - dir_entry++; - offset += sizeof(ROMDIR_ENTRY); - } - - // not found - romDirInfo->romdirPtr = NULL; - return NULL; -} - -// find a file in the romdir table and return info about it -// -// args: info about romdir to search through -// filename to search for -// structure to get info about file into -// returns: a pointer to fileinfo if successful -// NULL otherwise -ROMFILE_INFO* searchFileInRom(const ROMDIR_INFO* romdirInfo, const char* filename, ROMFILE_INFO* fileinfo) -{ - register ROMDIR_ENTRY* dir_entry; - register ext_offset=0, file_offset=0; - int i; - - for (dir_entry = romdirInfo->romdirPtr; dir_entry->name[0]; dir_entry++) { - - for(i = 0; i < 10; ++i) { - if( filename[i] == 0 ) - break; - if( dir_entry->name[i] != filename[i] ) { - i = -1; - break; - } - } - - if (i > 0 ) { - fileinfo->entry = dir_entry; - fileinfo->fileData = file_offset + romdirInfo->romPtr; // address of file in rom - fileinfo->extData = (u32)NULL; // address of extinfo in rom - - if (dir_entry->extSize) - fileinfo->extData = ext_offset + romdirInfo->extinfoPtr; // address of extinfo in rom - return fileinfo; - } - - file_offset += ROUND_UP(dir_entry->fileSize,16); - ext_offset += dir_entry->extSize; - } - - // error - file not found - return NULL; -} - -// gets a hex number from *addr and updates the pointer -// -// args: pointer to string buffer containing a hex number -// returns: the value of the hex number -u32 getHexNumber(char** addr) -{ - register char *p; //a1 - register u32 h = 0; //a2; - - for (p=*addr; *p >= '0'; p++) - { - int num; - if(*p <= '9') num = *p - '0'; - else if(*p >= 'a') num = *p - 'a' + 10; - else num = *p - 'A' + 10; - - h = h*16 + num; - } - - *addr = p; - return h; -} +/*************************************************************** +* romdir.c, based over Alex Lau (http://alexlau.8k.com) RomDir * +****************************************************************/ +#include "romdir.h" + +// searches between beginning and end addresses for a romdir structure. +// if found it returns info about it in romDirInfo. +// +// args: address to start searching from +// address to stop searching at +// gets filled in with info if found +// returns: a pointer to the filled in romDirInfo if successful +// NULL if error +ROMDIR_INFO* searchRomDir(const u32* searchStartAddr, const u32* searchEndAddr, ROMDIR_INFO* romDirInfo) +{ + int offset = 0; + ROMDIR_ENTRY* dir_entry = (ROMDIR_ENTRY*)searchStartAddr; + while (dir_entry < (ROMDIR_ENTRY*)searchEndAddr) + { + if(dir_entry->name[0] == 'R' && + dir_entry->name[1] == 'E' && + dir_entry->name[2] == 'S' && + dir_entry->name[3] == 'E' && + dir_entry->name[4] == 'T' && + dir_entry->name[5] == 0 && + (ROUND_UP(dir_entry->fileSize,16) == offset) ) + { + romDirInfo->romPtr = (u32)searchStartAddr; // start of rom + romDirInfo->romdirPtr = dir_entry; // start of romdir structure + romDirInfo->extinfoPtr = (u32)dir_entry + dir_entry[1].fileSize; // start of extinfo + return romDirInfo; + } + + dir_entry++; + offset += sizeof(ROMDIR_ENTRY); + } + + // not found + romDirInfo->romdirPtr = NULL; + return NULL; +} + +// find a file in the romdir table and return info about it +// +// args: info about romdir to search through +// filename to search for +// structure to get info about file into +// returns: a pointer to fileinfo if successful +// NULL otherwise +ROMFILE_INFO* searchFileInRom(const ROMDIR_INFO* romdirInfo, const char* filename, ROMFILE_INFO* fileinfo) +{ + register ROMDIR_ENTRY* dir_entry; + register ext_offset=0, file_offset=0; + int i; + + for (dir_entry = romdirInfo->romdirPtr; dir_entry->name[0]; dir_entry++) { + + for(i = 0; i < 10; ++i) { + if( filename[i] == 0 ) + break; + if( dir_entry->name[i] != filename[i] ) { + i = -1; + break; + } + } + + if (i > 0 ) { + fileinfo->entry = dir_entry; + fileinfo->fileData = file_offset + romdirInfo->romPtr; // address of file in rom + fileinfo->extData = (u32)NULL; // address of extinfo in rom + + if (dir_entry->extSize) + fileinfo->extData = ext_offset + romdirInfo->extinfoPtr; // address of extinfo in rom + return fileinfo; + } + + file_offset += ROUND_UP(dir_entry->fileSize,16); + ext_offset += dir_entry->extSize; + } + + // error - file not found + return NULL; +} + +// gets a hex number from *addr and updates the pointer +// +// args: pointer to string buffer containing a hex number +// returns: the value of the hex number +u32 getHexNumber(char** addr) +{ + register char *p; //a1 + register u32 h = 0; //a2; + + for (p=*addr; *p >= '0'; p++) + { + int num; + if(*p <= '9') num = *p - '0'; + else if(*p >= 'a') num = *p - 'a' + 10; + else num = *p - 'A' + 10; + + h = h*16 + num; + } + + *addr = p; + return h; +} diff --git a/fps2bios/kernel/iopload/sifcmd/Makefile b/fps2bios/kernel/iopload/sifcmd/Makefile index 2874d2ae4e..c5b26d5d66 100644 --- a/fps2bios/kernel/iopload/sifcmd/Makefile +++ b/fps2bios/kernel/iopload/sifcmd/Makefile @@ -1,62 +1,62 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include - -IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 -IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include -IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -IOPLINK = $(IOPLD) -dc -IOPASFLAGS := -EL -G0 - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: sifcmd - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib -LDADD = -OBJECTS = sifcmd.o ../iopdebug.o ../libkernel/iop_loadcore.o \ - ../libkernel/iop_intrman.o ../libkernel/iop_sifman.o \ - ../libkernel/iop_thbase.o ../libkernel/iop_thevent.o \ - ../libkernel/iop_stdio.o - -sifcmd: $(OBJECTS) - $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/SIFCMD - -%.o: %.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - -%.o : %.s - $(IOPAS) $(IOPASFLAGS) $< -o $@ - -clean: - rm -f $(OBJECTS) - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: sifcmd + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib +LDADD = +OBJECTS = sifcmd.o ../iopdebug.o ../libkernel/iop_loadcore.o \ + ../libkernel/iop_intrman.o ../libkernel/iop_sifman.o \ + ../libkernel/iop_thbase.o ../libkernel/iop_thevent.o \ + ../libkernel/iop_stdio.o + +sifcmd: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/SIFCMD + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/sifcmd/sifcmd.c b/fps2bios/kernel/iopload/sifcmd/sifcmd.c index d944b51223..6b6568d249 100644 --- a/fps2bios/kernel/iopload/sifcmd/sifcmd.c +++ b/fps2bios/kernel/iopload/sifcmd/sifcmd.c @@ -1,798 +1,798 @@ -//[module] SIFCMD -//[processor] IOP -//[type] ELF-IRX -//[name] IOP_SIF_rpc_interface -//[version] 0x101 -//[memory map] -//[handlers] -//[entry point] sifcmd_start, sifcmd_stub -//[made by] [RO]man (roman_ps2dev@hotmail.com) - -#include "kloadcore.h" -#include "kintrman.h" -#include "ksifman.h" -#include "kthbase.h" -#include "ksifcmd.h" -#include "ksifman.h" - -#define _dprintf(fmt, args...) \ - __printf("sifcmd: " fmt, ## args) - -int sifInitRpc=0; - -// CMD data -char sif1_rcvBuffer[8*16]; //8 qwords -char b[4*16]; //not used -struct tag_cmd_common { - char *sif1_rcvBuffer, //+00 - *b, //+04 - *saddr; //+08 - SifCmdData *sysCmdBuffer; //+0C - int sysCmdBufferSize; //+10 - SifCmdData *cmdBuffer; //+14 - int cmdBufferSize, //+18 - *Sreg, //+1C - systemStatusFlag; //+20 - void (*func)(int); //+24 - int param, //+28 - _pad; //+2C -} cmd_common; //=30 -SifCmdData sysCmds[32]; -int Sreg[32]; - -// RPC data -int bufx[512], bufy[512]; -struct tag_rpc_common{ - int pid; - RPC_PACKET *paddr; - int size; - RPC_PACKET *paddr2; - int size2; - void *next; - int count; - int base; - void *queue; - int _pad0, - _pad1, - _pad2; -} rpc_common; - - -int _start(); - -/////////////////////////////////////////////////////////////////////// -//////////////////////////// CMD ////////////////////////////////////// -/////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////// -void cmd80000001_SET_SREG(SifCmdSRData *packet, struct tag_cmd_common *common) { - common->Sreg[packet->rno]=packet->value; -} - -/////////////////////////////////////////////////////////////////////// -void cmd80000000_CHANGE_SADDR(SifCmdCSData *packet, struct tag_cmd_common *common) { - common->saddr=packet->newaddr; -} - -///////////////////////////////////////////////////////////////////////[06] -int SifGetSreg(int index){ - return Sreg[index]; -} - -///////////////////////////////////////////////////////////////////////[07] -int SifSetSreg(int index, unsigned int value){ - return Sreg[index]=value; -} - -/////////////////////////////////////////////////////////////////////// -void *getCmdCommon(){ - return &cmd_common; -} - -/////////////////////////////////////////////////////////////////////// -void cmd80000002_INIT_CMD(SifCmdCSData *packet, struct tag_cmd_common *common){ - __printf("cmd80000002_INIT_CMD\n"); - if (packet->hdr.opt==0){ - iSetEventFlag(common->systemStatusFlag, 0x100); - SifSetEEIOPflags(0x20000); - common->saddr=packet->newaddr; - }else - iSetEventFlag(common->systemStatusFlag, 0x800); -} - -///////////////////////////////////////////////////////////////////////[02] -int SifDeinitCmd(){ - int x; - DisableIntr(INT_DMA10, &x); - ReleaseIntrHandler(INT_DMA10); - SifDeinit(); - return 0; -} - -///////////////////////////////////////////////////////////////////////[04] -void SifInitCmd(){ - __printf("iopSifInitCmd\n"); - SifSetIOPEEflags(0x20000); - WaitEventFlag(cmd_common.systemStatusFlag, 0x100, 0, 0); -} - -///////////////////////////////////////////////////////////////////////[05] -void SifExitCmd(){ - int x; - DisableIntr(INT_DMA10, &x); - ReleaseIntrHandler(INT_DMA10); -} - -///////////////////////////////////////////////////////////////////////[08] -SifCmdData *SifSetCmdBuffer(SifCmdData *cmdBuffer, int size){ - register SifCmdData *old; - old=cmd_common.cmdBuffer; - cmd_common.cmdBuffer=cmdBuffer; - cmd_common.cmdBufferSize=size; - return old; -} - -///////////////////////////////////////////////////////////////////////[09] -SifCmdData *SifSetSysCmdBuffer(SifCmdData *sysCmdBuffer, int size){ - register SifCmdData *old; - old=cmd_common.sysCmdBuffer; - cmd_common.sysCmdBuffer=sysCmdBuffer; - cmd_common.sysCmdBufferSize=size; - return old; -} - -///////////////////////////////////////////////////////////////////////[0A] -void SifAddCmdHandler(int pos, cmdh_func f, void *data){ - if (pos<0){ - cmd_common.sysCmdBuffer[pos & 0x1FFFFFFF].func=f; - cmd_common.sysCmdBuffer[pos & 0x1FFFFFFF].data=data; - }else{ - cmd_common.cmdBuffer [pos & 0x1FFFFFFF].func=f; - cmd_common.cmdBuffer [pos & 0x1FFFFFFF].data=data; - } -} - -///////////////////////////////////////////////////////////////////////[0B] -void SifRemoveCmdHandler(unsigned int pos){ - if (pos<0) - cmd_common.sysCmdBuffer[pos & 0x1FFFFFFF].func=0; - else - cmd_common.cmdBuffer [pos & 0x1FFFFFFF].func=0; -} - -/////////////////////////////////////////////////////////////////////// -unsigned int sendCmd(unsigned int pos, int mode, SifCmdHdr *cp, int ps, void *src, void *dst, int size){ - u32 x; - struct sifman_DMA dma[2]; - register int count, y; - - if (ps<16 || ps>112) return 0; - - count=0; - if (size>0){ - count=1; - dma[0].addr=dst; - dma[0].size=size; - dma[0].attr=0; - dma[0].data=src; - cp->daddr=(u32)dst; - cp->dsize=size; - }else{ - cp->daddr=0; - cp->dsize=0; - } - count++; - cp->psize=ps; - cp->fcode=pos; - dma[count-1].data=cp; - dma[count-1].attr=SIF_DMA_INT_O; //calls SIF0 handler - dma[count-1].size=ps; //on EE side after transfer;) - dma[count-1].addr=cmd_common.saddr; - if (mode & 1) //interrupt mode - return SifSetDma(dma, count); - else{ - CpuSuspendIntr(&x); - y=SifSetDma(dma, count); - CpuResumeIntr(x); - return y; - } -} - -///////////////////////////////////////////////////////////////////////[0C] -unsigned int SifSendCmd(unsigned int pos, void *cp, int ps, void *src, void *dst, int size){ - return sendCmd(pos, 0, cp, ps, src, dst, size); -} - -///////////////////////////////////////////////////////////////////////[0D] -unsigned int iSifSendCmd(unsigned int pos, void *cp, int ps, void *src, void *dst, int size){ - return sendCmd(pos, 1, cp, ps, src, dst, size); -} - -///////////////////////////////////////////////////////////////////////[1A] -void SifSet1CB(void *func, int param){ - cmd_common.func =func; - cmd_common.param=param; -} - -///////////////////////////////////////////////////////////////////////[1B] -void SifReset1CB(){ - cmd_common.func =0; - cmd_common.param=0; -} - -/////////////////////////////////////////////////////////////////////// -int SIF1_handler(void *common){ - int buf[112/4]; - register int i, ps; - register SifCmdData *scd; - SifCmdHdr *packet; - struct tag_cmd_common *c = (struct tag_cmd_common *)common; - - if (c->func) - c->func(c->param); - - packet=(SifCmdHdr*)c->sif1_rcvBuffer; - - if ((ps=packet->psize & 0xFF)==0){ - SifSetDChain(); - return 1; - } - packet->psize=0; - - ps=(ps+3<0 ? ps+6 : ps+3)/4; - for (i=0; ifcode<0){ - if (packet->fcode & 0x7FFFFFFF>=c->sysCmdBufferSize) - return 1; - scd=&c->sysCmdBuffer[packet->fcode & 0x7FFFFFFF]; - }else{ - if (packet->fcode>=c->cmdBufferSize) - return 1; - scd=&c->cmdBuffer[packet->fcode]; - } - if (scd->func) - scd->func(packet, scd->data); - - return 1; -} - -/////////////////////////////////////////////////////////////////////// -//////////////////////////// RPC ////////////////////////////////////// -/////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////// -RPC_PACKET *rpc_get_packet(struct tag_rpc_common *common){ - u32 x; - register int pid, i; - RPC_PACKET *packet; - - CpuSuspendIntr(&x); - - for (i=0, packet=common->paddr; isize; i++) - if (packet[i].rec_id & 2==0) goto found; - for (i=0, packet=common->paddr2; isize2; i++) - if (packet[i].rec_id & 2==0) goto found; - - CpuResumeIntr(x); - return 0; - -found: - packet[i].rec_id |= 2; - pid=++common->pid; - if (pid == 1) - common->pid++; - packet[i].pid=pid; - packet[i].paddr=&packet[i]; - CpuResumeIntr(x); - return &packet[i]; -} - -/////////////////////////////////////////////////////////////////////// -void rpc_free_packet(RPC_PACKET *packet){ - packet->pid = 0; - packet->rec_id &= 0xFFFFFFFD; //~2 -} - -/////////////////////////////////////////////////////////////////////// -RPC_PACKET *rpc_get_fpacket(struct tag_rpc_common *common){ - register int i; - - i=common->base % common->count; - common->base=i+1; - return (RPC_PACKET*)(((u8*)common->next)+i*64); -} - -/////////////////////////////////////////////////////////////////////// -void cmd80000008_END(RPC_PACKET_END *packet, struct tag_rpc_common *common){ - if (packet->command==0x8000000A){ - if (packet->client->func) - packet->client->func(packet->client->param); - }else - if (packet->command==0x80000009){ - packet->client->server=packet->server; - packet->client->buff =packet->buff; - packet->client->cbuff =packet->cbuff; - } - - if (packet->client->hdr.tid>=0) - iWakeupThread(packet->client->hdr.tid); - - rpc_free_packet(packet->client->hdr.pkt_addr); - packet->client->hdr.pkt_addr=0; -} - -/////////////////////////////////////////////////////////////////////// -void cmd8000000C_RDATA(RPC_PACKET_RDATA *packet, struct tag_rpc_common *common){ - RPC_PACKET_END *epacket; - - epacket = (RPC_PACKET_END *)rpc_get_fpacket(common); - - epacket->packet.paddr = packet->packet.paddr; - epacket->command = 0x8000000C; - epacket->client = packet->client; - - iSifSendCmd(0x80000008, epacket, 0x40, packet->src, packet->dst, packet->size); -} - -///////////////////////////////////////////////////////////////////////[17] -int SifGetOtherData(struct sifcmd_RPC_RECEIVE_DATA *rd, void *src, void *dst, int size, int mode){ - RPC_PACKET_RDATA *packet; - - if ((packet=(RPC_PACKET_RDATA *)rpc_get_packet(&rpc_common))==0) - return -1; - - rd->hdr.pkt_addr=packet; - rd->hdr.rpc_id =packet->packet.pid; - packet->packet.paddr=packet; - packet->client=(struct sifcmd_RPC_CLIENT_DATA*)rd; - packet->src=src; - packet->dst=dst; - packet->size=size; - - if (mode & 1==0){ - rd->hdr.tid=GetThreadId(); - if (SifSendCmd(0x8000000C, packet, 0x40, 0, 0, 0)==0) - return -2; - SleepThread(); - }else{ //async - rd->hdr.tid=-1; - if (SifSendCmd(0x8000000C, packet, 0x40, 0, 0, 0)==0) - return -2; - } - return 0; -} - -/////////////////////////////////////////////////////////////////////// -struct sifcmd_RPC_SERVER_DATA *search_svdata(u32 command, struct tag_rpc_common *common){ - struct sifcmd_RPC_SERVER_DATA *q; - struct sifcmd_RPC_SERVER_DATA *s; - - for (q=common->queue; q; q=q->next) { - for (s=q->link; s; s=s->link) { - if (s->command==command) - return s; - } - } - return 0; -} - -/////////////////////////////////////////////////////////////////////// -void cmd80000009_BIND(RPC_PACKET_BIND *packet, struct tag_rpc_common *common){ - RPC_PACKET_END *epacket; - struct sifcmd_RPC_SERVER_DATA *s; - - epacket = (RPC_PACKET_END *)rpc_get_fpacket(common); - - epacket->packet.paddr=packet->packet.paddr; - epacket->command=0x80000009; - epacket->client=packet->client; - - s = search_svdata(packet->fno, common); - if (s == NULL){ - epacket->server=0; - epacket->buff =0; - epacket->cbuff =0; - }else{ - epacket->server=s; - epacket->buff =s->buff; - epacket->cbuff =s->cbuff; - } - iSifSendCmd(0x80000008, epacket, 0x40, 0, 0, 0); -} - -///////////////////////////////////////////////////////////////////////[0F] -int SifBindRpc(struct sifcmd_RPC_CLIENT_DATA *client, unsigned int number, unsigned int mode) { - RPC_PACKET_BIND *packet; - - client->command=0; - client->server=0; - - packet = (RPC_PACKET_BIND *)rpc_get_packet(&rpc_common); - if (packet==NULL) return -1; - - client->hdr.pkt_addr = packet; - client->hdr.rpc_id = packet->packet.pid; - packet->packet.paddr = packet; - packet->client = client; - packet->fno = number; - - if (mode & 1==0){ - client->hdr.tid=GetThreadId(); - if (SifSendCmd(0x80000009, packet, 0x40, 0, 0, 0)==0) - return -2; - SleepThread(); - }else{ //async - client->hdr.tid=-1; - if (SifSendCmd(0x80000009, packet, 0x40, 0, 0, 0)==0) - return -2; - } - return 0; -} - -/////////////////////////////////////////////////////////////////////// -void cmd8000000A_CALL(RPC_PACKET_CALL *packet, struct tag_rpc_common *common){ - struct sifcmd_RPC_DATA_QUEUE *qd; - - qd = packet->server->base; - if (qd->start==0) qd->start=packet->server; - else qd->end->link=packet->server; - qd->end=packet->server; - packet->server->pkt_addr=packet->packet.packet.paddr; - packet->server->client=packet->packet.client; - packet->server->fno=packet->packet.fno; - packet->server->size=packet->size; - packet->server->receive=packet->receive; - packet->server->rsize=packet->rsize; - packet->server->rmode=packet->rmode; - if ((qd->key>=0) && (qd->active==0)) - iWakeupThread(qd->key); -} - -///////////////////////////////////////////////////////////////////////[10] -int SifCallRpc(struct sifcmd_RPC_CLIENT_DATA *client, unsigned int fno, unsigned int mode, void *send, int ssize, void *receive, int rsize, void (*end_func)(void*), void *end_para){ - RPC_PACKET_CALL *packet; - - if ((packet=(RPC_PACKET_CALL *)rpc_get_packet(&rpc_common))==0) - return -1; - client->hdr.pkt_addr=(void*)packet; - client->func = end_func; - client->param = end_para; - client->hdr.rpc_id= packet->packet.packet.pid; - - packet->packet.packet.paddr = packet; - packet->packet.client = client; - packet->packet.fno = fno; - packet->size = ssize; - packet->receive= receive; - packet->rsize = rsize; - packet->server = client->server; - - if (mode & 1){ - packet->rmode=(end_func!=0); - client->hdr.tid=-1; - if (SifSendCmd(0x8000000A, packet, 0x40, send, client->buff, ssize)) - return 0; - return -2; - }else{ - packet->rmode=1; - client->hdr.tid=GetThreadId(); - if (SifSendCmd(0x8000000A, packet, 0x40, send, client->buff, ssize)==0) - return -2; - SleepThread(); - return 0; - } -} - -///////////////////////////////////////////////////////////////////////[12] -int SifCheckStatRpc(struct sifcmd_RPC_HEADER *rd){ - RPC_PACKET *packet = (RPC_PACKET*)rd->pkt_addr; - return (rd->pkt_addr && - (rd->rpc_id==packet->pid) && - (packet->rec_id & 2)); -} - -///////////////////////////////////////////////////////////////////////[13] -void SifSetRpcQueue(struct sifcmd_RPC_DATA_QUEUE *qd, int key){ - u32 x; - register struct sifcmd_RPC_DATA_QUEUE *q, *i; - - CpuSuspendIntr(&x); - qd->key=key; - qd->active=0; - qd->link=0; - qd->start=0; - qd->end=0; - qd->next=0; - q = (struct sifcmd_RPC_DATA_QUEUE *)&rpc_common.queue; - if (q) { - for (i=q->next; i; i=q->next) q=q->next; - } - rpc_common.queue = qd; - CpuResumeIntr(x); -} - -///////////////////////////////////////////////////////////////////////[11] -void SifRegisterRpc(struct sifcmd_RPC_SERVER_DATA *sd, u32 command, - rpch_func func, void *buff, - rpch_func cfunc, void *cbuff, - struct sifcmd_RPC_DATA_QUEUE *qd) { - u32 x; - register struct sifcmd_RPC_DATA_QUEUE *q, *i; - - CpuSuspendIntr(&x); - sd->command=command; - sd->func=func; - sd->buff=buff; - sd->next=0; - sd->link=0; - sd->cfunc=cfunc; - sd->cbuff=cbuff; - sd->base=qd; - - if (qd->link==0) - qd->link=sd; - else{ - for (q=qd->link, i=q->link; i; i=q->link) - q=q->link; - q->link=sd; - } - CpuResumeIntr(x); -} - -///////////////////////////////////////////////////////////////////////[18] -struct sifcmd_RPC_SERVER_DATA *SifRemoveRpc(struct sifcmd_RPC_SERVER_DATA *sd, struct sifcmd_RPC_DATA_QUEUE *qd){ - u32 x; - register struct sifcmd_RPC_SERVER_DATA *s; - - CpuSuspendIntr(&x); - - if ((s=qd->link)==sd) - qd->link=s->link; - else - for ( ; s; s=s->link) - if (s->link==sd){ - s->link=s->link->link; - break; - } - CpuResumeIntr(x); - return s; -} - -///////////////////////////////////////////////////////////////////////[19] -struct sifcmd_RPC_DATA_QUEUE *SifRemoveRpcQueue(struct sifcmd_RPC_DATA_QUEUE *qd){ - u32 x; - register struct sifcmd_RPC_DATA_QUEUE *q; - - CpuSuspendIntr(&x); - - q=rpc_common.queue; - if (q==qd) { - rpc_common.queue=q->next; - } else { - for (; q; q=q->next) { - if (q->next==qd){ - q->next=q->next->next; - break; - } - } - } - CpuResumeIntr(x); - return q; -} - -///////////////////////////////////////////////////////////////////////[14] -struct sifcmd_RPC_SERVER_DATA *SifGetNextRequest(struct sifcmd_RPC_DATA_QUEUE *qd){ - u32 x; - register struct sifcmd_RPC_SERVER_DATA *s; - - CpuSuspendIntr(&x); - - if ((s=qd->start)==0) - qd->active=0; - else{ - qd->active=1; - qd->start=qd->start->next; - } - - CpuResumeIntr(x); - return s; -} - -///////////////////////////////////////////////////////////////////////[15] -void SifExecRequest(struct sifcmd_RPC_SERVER_DATA *sd){ - u32 x; - register int size, id, count, i; - register void *buff; - RPC_PACKET_END *epacket; - struct sifman_DMA dma[2]; - - size=0; - if (buff=sd->func(sd->fno, sd->buff, sd->size)) - size=sd->rsize; - - CpuSuspendIntr(&x); - epacket=(RPC_PACKET_END *)rpc_get_fpacket(&rpc_common); - CpuResumeIntr(x); - - epacket->command=0x8000000A; - epacket->client=sd->client; - count=0; - if (sd->rmode){ - while (SifSendCmd(0x80000008, epacket, 0x40, buff, sd->receive, size)==0); - return; - }else{ - epacket->packet.pid=0; - epacket->packet.rec_id=0; - if (size>0){ - count=1; - dma[count-1].data=buff; - dma[count-1].size=size; - dma[count-1].attr=0; - dma[count-1].addr=sd->receive; - } - count++; - dma[count-1].data=epacket; - dma[count-1].size=0x40; - dma[count-1].attr=0; - dma[count-1].addr=sd->pkt_addr; - do{ - CpuSuspendIntr(&x); - id=SifSetDma(dma, count); - CpuResumeIntr(x); - if (id) break; - i=0xFFFF; do --i; while (i!=-1); - } while (id==0); - } -} - -///////////////////////////////////////////////////////////////////////[16] -void SifRpcLoop(struct sifcmd_RPC_DATA_QUEUE *qd){ - register struct sifcmd_RPC_SERVER_DATA *s; - - do{ - if (s=SifGetNextRequest(qd)) - SifExecRequest(s); - else - SleepThread(); - } while (1); -} - -///////////////////////////////////////////////////////////////////////[0E] -void SifInitRpc(int mode){ - u32 x; - _dprintf("%s\n", __FUNCTION__); - - SifInitCmd(); - CpuSuspendIntr(&x); - - if (sifInitRpc){ - CpuResumeIntr(x); - }else{ - sifInitRpc=1; - rpc_common.paddr=(RPC_PACKET*)bufx; - rpc_common.size=32; - rpc_common.paddr2=0; - rpc_common.size2=0; - rpc_common.next=(RPC_PACKET*)bufy; - rpc_common.count=32; - rpc_common.base=0; - rpc_common.pid=1; - - SifAddCmdHandler(0x80000008, (cmdh_func)cmd80000008_END, &rpc_common); - SifAddCmdHandler(0x80000009, (cmdh_func)cmd80000009_BIND, &rpc_common); - SifAddCmdHandler(0x8000000A, (cmdh_func)cmd8000000A_CALL, &rpc_common); - SifAddCmdHandler(0x8000000C, (cmdh_func)cmd8000000C_RDATA, &rpc_common); - - CpuResumeIntr(x); - - ((SifCmdSRData*)bufx)->rno =0; - ((SifCmdSRData*)bufx)->value=1; - SifSendCmd(0x80000001, (void*)bufx, sizeof(SifCmdSRData), 0, 0, 0); - } - WaitEventFlag(GetSystemStatusFlag(), 0x800, 0, 0); -} - -void _retonly() {} - -struct export sifcmd_stub={ - 0x41C00000, - 0, - VER(1, 1), // 1.1 => 0x101 - 0, - "sifcmd", - (func)_start, // entrypoint - (func)_retonly, - (func)SifDeinitCmd, - (func)_retonly, - (func)SifInitCmd, - (func)SifExitCmd, - (func)SifGetSreg, - (func)SifSetSreg, - (func)SifSetCmdBuffer, - (func)SifSetSysCmdBuffer, - (func)SifAddCmdHandler, - (func)SifRemoveCmdHandler, - (func)SifSendCmd, - (func)iSifSendCmd, - (func)SifInitRpc, - (func)SifBindRpc, - (func)SifCallRpc, - (func)SifRegisterRpc, - (func)SifCheckStatRpc, - (func)SifSetRpcQueue, - (func)SifGetNextRequest, - (func)SifExecRequest, - (func)SifRpcLoop, - (func)SifGetOtherData, - (func)SifRemoveRpc, - (func)SifRemoveRpcQueue, - (func)SifSet1CB, - (func)SifReset1CB, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - 0 -}; - -//////////////////////////////entrypoint///////////////////////////////[00] -int _start(){ - register int *v, i; - - _dprintf("%s\n", __FUNCTION__); - if (v=QueryBootMode(3)){ - _dprintf("bootmode: %x\n", v[1]); - if (v[1] & 1){ printf("%s No SIF service(sifcmd)\n", __FUNCTION__);return 1;} - if (v[1] & 2){ printf("%s No SIFCMD/RPC service\n", __FUNCTION__); return 1;} - } - - if (SifCheckInit()==0) - SifInit(); - - if (RegisterLibraryEntries(&sifcmd_stub)) return 1; - - cmd_common.sif1_rcvBuffer=sif1_rcvBuffer; - cmd_common.b=b; - cmd_common.sysCmdBuffer=sysCmds; - cmd_common.sysCmdBufferSize=32; - cmd_common.saddr=0; - cmd_common.cmdBuffer=0; - cmd_common.cmdBufferSize=0; - cmd_common.Sreg=Sreg; - cmd_common.func=0; - cmd_common.param=0; - - for (i=0; i<32; i++) { - sysCmds[i].func=0; - sysCmds[i].data=0; - } - for (i=0; i<32; i++) { - Sreg[i]=0; - } - - sysCmds[0].func=(cmdh_func)cmd80000000_CHANGE_SADDR; - sysCmds[0].data=&cmd_common; - - sysCmds[1].func=(cmdh_func)cmd80000001_SET_SREG; - sysCmds[1].data=&cmd_common; - - cmd_common.systemStatusFlag=GetSystemStatusFlag(); - - sysCmds[2].func=(cmdh_func)cmd80000002_INIT_CMD; - sysCmds[2].data=&cmd_common; - - RegisterIntrHandler(INT_DMA10, 1, SIF1_handler, (void*)&cmd_common); - EnableIntr(INT_DMA10 | IMODE_DMA_IQE); - - SifSetIOPrcvaddr((u32)sif1_rcvBuffer); - - return 0; -} - - - - +//[module] SIFCMD +//[processor] IOP +//[type] ELF-IRX +//[name] IOP_SIF_rpc_interface +//[version] 0x101 +//[memory map] +//[handlers] +//[entry point] sifcmd_start, sifcmd_stub +//[made by] [RO]man (roman_ps2dev@hotmail.com) + +#include "kloadcore.h" +#include "kintrman.h" +#include "ksifman.h" +#include "kthbase.h" +#include "ksifcmd.h" +#include "ksifman.h" + +#define _dprintf(fmt, args...) \ + __printf("sifcmd: " fmt, ## args) + +int sifInitRpc=0; + +// CMD data +char sif1_rcvBuffer[8*16]; //8 qwords +char b[4*16]; //not used +struct tag_cmd_common { + char *sif1_rcvBuffer, //+00 + *b, //+04 + *saddr; //+08 + SifCmdData *sysCmdBuffer; //+0C + int sysCmdBufferSize; //+10 + SifCmdData *cmdBuffer; //+14 + int cmdBufferSize, //+18 + *Sreg, //+1C + systemStatusFlag; //+20 + void (*func)(int); //+24 + int param, //+28 + _pad; //+2C +} cmd_common; //=30 +SifCmdData sysCmds[32]; +int Sreg[32]; + +// RPC data +int bufx[512], bufy[512]; +struct tag_rpc_common{ + int pid; + RPC_PACKET *paddr; + int size; + RPC_PACKET *paddr2; + int size2; + void *next; + int count; + int base; + void *queue; + int _pad0, + _pad1, + _pad2; +} rpc_common; + + +int _start(); + +/////////////////////////////////////////////////////////////////////// +//////////////////////////// CMD ////////////////////////////////////// +/////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////// +void cmd80000001_SET_SREG(SifCmdSRData *packet, struct tag_cmd_common *common) { + common->Sreg[packet->rno]=packet->value; +} + +/////////////////////////////////////////////////////////////////////// +void cmd80000000_CHANGE_SADDR(SifCmdCSData *packet, struct tag_cmd_common *common) { + common->saddr=packet->newaddr; +} + +///////////////////////////////////////////////////////////////////////[06] +int SifGetSreg(int index){ + return Sreg[index]; +} + +///////////////////////////////////////////////////////////////////////[07] +int SifSetSreg(int index, unsigned int value){ + return Sreg[index]=value; +} + +/////////////////////////////////////////////////////////////////////// +void *getCmdCommon(){ + return &cmd_common; +} + +/////////////////////////////////////////////////////////////////////// +void cmd80000002_INIT_CMD(SifCmdCSData *packet, struct tag_cmd_common *common){ + __printf("cmd80000002_INIT_CMD\n"); + if (packet->hdr.opt==0){ + iSetEventFlag(common->systemStatusFlag, 0x100); + SifSetEEIOPflags(0x20000); + common->saddr=packet->newaddr; + }else + iSetEventFlag(common->systemStatusFlag, 0x800); +} + +///////////////////////////////////////////////////////////////////////[02] +int SifDeinitCmd(){ + int x; + DisableIntr(INT_DMA10, &x); + ReleaseIntrHandler(INT_DMA10); + SifDeinit(); + return 0; +} + +///////////////////////////////////////////////////////////////////////[04] +void SifInitCmd(){ + __printf("iopSifInitCmd\n"); + SifSetIOPEEflags(0x20000); + WaitEventFlag(cmd_common.systemStatusFlag, 0x100, 0, 0); +} + +///////////////////////////////////////////////////////////////////////[05] +void SifExitCmd(){ + int x; + DisableIntr(INT_DMA10, &x); + ReleaseIntrHandler(INT_DMA10); +} + +///////////////////////////////////////////////////////////////////////[08] +SifCmdData *SifSetCmdBuffer(SifCmdData *cmdBuffer, int size){ + register SifCmdData *old; + old=cmd_common.cmdBuffer; + cmd_common.cmdBuffer=cmdBuffer; + cmd_common.cmdBufferSize=size; + return old; +} + +///////////////////////////////////////////////////////////////////////[09] +SifCmdData *SifSetSysCmdBuffer(SifCmdData *sysCmdBuffer, int size){ + register SifCmdData *old; + old=cmd_common.sysCmdBuffer; + cmd_common.sysCmdBuffer=sysCmdBuffer; + cmd_common.sysCmdBufferSize=size; + return old; +} + +///////////////////////////////////////////////////////////////////////[0A] +void SifAddCmdHandler(int pos, cmdh_func f, void *data){ + if (pos<0){ + cmd_common.sysCmdBuffer[pos & 0x1FFFFFFF].func=f; + cmd_common.sysCmdBuffer[pos & 0x1FFFFFFF].data=data; + }else{ + cmd_common.cmdBuffer [pos & 0x1FFFFFFF].func=f; + cmd_common.cmdBuffer [pos & 0x1FFFFFFF].data=data; + } +} + +///////////////////////////////////////////////////////////////////////[0B] +void SifRemoveCmdHandler(unsigned int pos){ + if (pos<0) + cmd_common.sysCmdBuffer[pos & 0x1FFFFFFF].func=0; + else + cmd_common.cmdBuffer [pos & 0x1FFFFFFF].func=0; +} + +/////////////////////////////////////////////////////////////////////// +unsigned int sendCmd(unsigned int pos, int mode, SifCmdHdr *cp, int ps, void *src, void *dst, int size){ + u32 x; + struct sifman_DMA dma[2]; + register int count, y; + + if (ps<16 || ps>112) return 0; + + count=0; + if (size>0){ + count=1; + dma[0].addr=dst; + dma[0].size=size; + dma[0].attr=0; + dma[0].data=src; + cp->daddr=(u32)dst; + cp->dsize=size; + }else{ + cp->daddr=0; + cp->dsize=0; + } + count++; + cp->psize=ps; + cp->fcode=pos; + dma[count-1].data=cp; + dma[count-1].attr=SIF_DMA_INT_O; //calls SIF0 handler + dma[count-1].size=ps; //on EE side after transfer;) + dma[count-1].addr=cmd_common.saddr; + if (mode & 1) //interrupt mode + return SifSetDma(dma, count); + else{ + CpuSuspendIntr(&x); + y=SifSetDma(dma, count); + CpuResumeIntr(x); + return y; + } +} + +///////////////////////////////////////////////////////////////////////[0C] +unsigned int SifSendCmd(unsigned int pos, void *cp, int ps, void *src, void *dst, int size){ + return sendCmd(pos, 0, cp, ps, src, dst, size); +} + +///////////////////////////////////////////////////////////////////////[0D] +unsigned int iSifSendCmd(unsigned int pos, void *cp, int ps, void *src, void *dst, int size){ + return sendCmd(pos, 1, cp, ps, src, dst, size); +} + +///////////////////////////////////////////////////////////////////////[1A] +void SifSet1CB(void *func, int param){ + cmd_common.func =func; + cmd_common.param=param; +} + +///////////////////////////////////////////////////////////////////////[1B] +void SifReset1CB(){ + cmd_common.func =0; + cmd_common.param=0; +} + +/////////////////////////////////////////////////////////////////////// +int SIF1_handler(void *common){ + int buf[112/4]; + register int i, ps; + register SifCmdData *scd; + SifCmdHdr *packet; + struct tag_cmd_common *c = (struct tag_cmd_common *)common; + + if (c->func) + c->func(c->param); + + packet=(SifCmdHdr*)c->sif1_rcvBuffer; + + if ((ps=packet->psize & 0xFF)==0){ + SifSetDChain(); + return 1; + } + packet->psize=0; + + ps=(ps+3<0 ? ps+6 : ps+3)/4; + for (i=0; ifcode<0){ + if (packet->fcode & 0x7FFFFFFF>=c->sysCmdBufferSize) + return 1; + scd=&c->sysCmdBuffer[packet->fcode & 0x7FFFFFFF]; + }else{ + if (packet->fcode>=c->cmdBufferSize) + return 1; + scd=&c->cmdBuffer[packet->fcode]; + } + if (scd->func) + scd->func(packet, scd->data); + + return 1; +} + +/////////////////////////////////////////////////////////////////////// +//////////////////////////// RPC ////////////////////////////////////// +/////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////// +RPC_PACKET *rpc_get_packet(struct tag_rpc_common *common){ + u32 x; + register int pid, i; + RPC_PACKET *packet; + + CpuSuspendIntr(&x); + + for (i=0, packet=common->paddr; isize; i++) + if (packet[i].rec_id & 2==0) goto found; + for (i=0, packet=common->paddr2; isize2; i++) + if (packet[i].rec_id & 2==0) goto found; + + CpuResumeIntr(x); + return 0; + +found: + packet[i].rec_id |= 2; + pid=++common->pid; + if (pid == 1) + common->pid++; + packet[i].pid=pid; + packet[i].paddr=&packet[i]; + CpuResumeIntr(x); + return &packet[i]; +} + +/////////////////////////////////////////////////////////////////////// +void rpc_free_packet(RPC_PACKET *packet){ + packet->pid = 0; + packet->rec_id &= 0xFFFFFFFD; //~2 +} + +/////////////////////////////////////////////////////////////////////// +RPC_PACKET *rpc_get_fpacket(struct tag_rpc_common *common){ + register int i; + + i=common->base % common->count; + common->base=i+1; + return (RPC_PACKET*)(((u8*)common->next)+i*64); +} + +/////////////////////////////////////////////////////////////////////// +void cmd80000008_END(RPC_PACKET_END *packet, struct tag_rpc_common *common){ + if (packet->command==0x8000000A){ + if (packet->client->func) + packet->client->func(packet->client->param); + }else + if (packet->command==0x80000009){ + packet->client->server=packet->server; + packet->client->buff =packet->buff; + packet->client->cbuff =packet->cbuff; + } + + if (packet->client->hdr.tid>=0) + iWakeupThread(packet->client->hdr.tid); + + rpc_free_packet(packet->client->hdr.pkt_addr); + packet->client->hdr.pkt_addr=0; +} + +/////////////////////////////////////////////////////////////////////// +void cmd8000000C_RDATA(RPC_PACKET_RDATA *packet, struct tag_rpc_common *common){ + RPC_PACKET_END *epacket; + + epacket = (RPC_PACKET_END *)rpc_get_fpacket(common); + + epacket->packet.paddr = packet->packet.paddr; + epacket->command = 0x8000000C; + epacket->client = packet->client; + + iSifSendCmd(0x80000008, epacket, 0x40, packet->src, packet->dst, packet->size); +} + +///////////////////////////////////////////////////////////////////////[17] +int SifGetOtherData(struct sifcmd_RPC_RECEIVE_DATA *rd, void *src, void *dst, int size, int mode){ + RPC_PACKET_RDATA *packet; + + if ((packet=(RPC_PACKET_RDATA *)rpc_get_packet(&rpc_common))==0) + return -1; + + rd->hdr.pkt_addr=packet; + rd->hdr.rpc_id =packet->packet.pid; + packet->packet.paddr=packet; + packet->client=(struct sifcmd_RPC_CLIENT_DATA*)rd; + packet->src=src; + packet->dst=dst; + packet->size=size; + + if (mode & 1==0){ + rd->hdr.tid=GetThreadId(); + if (SifSendCmd(0x8000000C, packet, 0x40, 0, 0, 0)==0) + return -2; + SleepThread(); + }else{ //async + rd->hdr.tid=-1; + if (SifSendCmd(0x8000000C, packet, 0x40, 0, 0, 0)==0) + return -2; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////// +struct sifcmd_RPC_SERVER_DATA *search_svdata(u32 command, struct tag_rpc_common *common){ + struct sifcmd_RPC_SERVER_DATA *q; + struct sifcmd_RPC_SERVER_DATA *s; + + for (q=common->queue; q; q=q->next) { + for (s=q->link; s; s=s->link) { + if (s->command==command) + return s; + } + } + return 0; +} + +/////////////////////////////////////////////////////////////////////// +void cmd80000009_BIND(RPC_PACKET_BIND *packet, struct tag_rpc_common *common){ + RPC_PACKET_END *epacket; + struct sifcmd_RPC_SERVER_DATA *s; + + epacket = (RPC_PACKET_END *)rpc_get_fpacket(common); + + epacket->packet.paddr=packet->packet.paddr; + epacket->command=0x80000009; + epacket->client=packet->client; + + s = search_svdata(packet->fno, common); + if (s == NULL){ + epacket->server=0; + epacket->buff =0; + epacket->cbuff =0; + }else{ + epacket->server=s; + epacket->buff =s->buff; + epacket->cbuff =s->cbuff; + } + iSifSendCmd(0x80000008, epacket, 0x40, 0, 0, 0); +} + +///////////////////////////////////////////////////////////////////////[0F] +int SifBindRpc(struct sifcmd_RPC_CLIENT_DATA *client, unsigned int number, unsigned int mode) { + RPC_PACKET_BIND *packet; + + client->command=0; + client->server=0; + + packet = (RPC_PACKET_BIND *)rpc_get_packet(&rpc_common); + if (packet==NULL) return -1; + + client->hdr.pkt_addr = packet; + client->hdr.rpc_id = packet->packet.pid; + packet->packet.paddr = packet; + packet->client = client; + packet->fno = number; + + if (mode & 1==0){ + client->hdr.tid=GetThreadId(); + if (SifSendCmd(0x80000009, packet, 0x40, 0, 0, 0)==0) + return -2; + SleepThread(); + }else{ //async + client->hdr.tid=-1; + if (SifSendCmd(0x80000009, packet, 0x40, 0, 0, 0)==0) + return -2; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////// +void cmd8000000A_CALL(RPC_PACKET_CALL *packet, struct tag_rpc_common *common){ + struct sifcmd_RPC_DATA_QUEUE *qd; + + qd = packet->server->base; + if (qd->start==0) qd->start=packet->server; + else qd->end->link=packet->server; + qd->end=packet->server; + packet->server->pkt_addr=packet->packet.packet.paddr; + packet->server->client=packet->packet.client; + packet->server->fno=packet->packet.fno; + packet->server->size=packet->size; + packet->server->receive=packet->receive; + packet->server->rsize=packet->rsize; + packet->server->rmode=packet->rmode; + if ((qd->key>=0) && (qd->active==0)) + iWakeupThread(qd->key); +} + +///////////////////////////////////////////////////////////////////////[10] +int SifCallRpc(struct sifcmd_RPC_CLIENT_DATA *client, unsigned int fno, unsigned int mode, void *send, int ssize, void *receive, int rsize, void (*end_func)(void*), void *end_para){ + RPC_PACKET_CALL *packet; + + if ((packet=(RPC_PACKET_CALL *)rpc_get_packet(&rpc_common))==0) + return -1; + client->hdr.pkt_addr=(void*)packet; + client->func = end_func; + client->param = end_para; + client->hdr.rpc_id= packet->packet.packet.pid; + + packet->packet.packet.paddr = packet; + packet->packet.client = client; + packet->packet.fno = fno; + packet->size = ssize; + packet->receive= receive; + packet->rsize = rsize; + packet->server = client->server; + + if (mode & 1){ + packet->rmode=(end_func!=0); + client->hdr.tid=-1; + if (SifSendCmd(0x8000000A, packet, 0x40, send, client->buff, ssize)) + return 0; + return -2; + }else{ + packet->rmode=1; + client->hdr.tid=GetThreadId(); + if (SifSendCmd(0x8000000A, packet, 0x40, send, client->buff, ssize)==0) + return -2; + SleepThread(); + return 0; + } +} + +///////////////////////////////////////////////////////////////////////[12] +int SifCheckStatRpc(struct sifcmd_RPC_HEADER *rd){ + RPC_PACKET *packet = (RPC_PACKET*)rd->pkt_addr; + return (rd->pkt_addr && + (rd->rpc_id==packet->pid) && + (packet->rec_id & 2)); +} + +///////////////////////////////////////////////////////////////////////[13] +void SifSetRpcQueue(struct sifcmd_RPC_DATA_QUEUE *qd, int key){ + u32 x; + register struct sifcmd_RPC_DATA_QUEUE *q, *i; + + CpuSuspendIntr(&x); + qd->key=key; + qd->active=0; + qd->link=0; + qd->start=0; + qd->end=0; + qd->next=0; + q = (struct sifcmd_RPC_DATA_QUEUE *)&rpc_common.queue; + if (q) { + for (i=q->next; i; i=q->next) q=q->next; + } + rpc_common.queue = qd; + CpuResumeIntr(x); +} + +///////////////////////////////////////////////////////////////////////[11] +void SifRegisterRpc(struct sifcmd_RPC_SERVER_DATA *sd, u32 command, + rpch_func func, void *buff, + rpch_func cfunc, void *cbuff, + struct sifcmd_RPC_DATA_QUEUE *qd) { + u32 x; + register struct sifcmd_RPC_DATA_QUEUE *q, *i; + + CpuSuspendIntr(&x); + sd->command=command; + sd->func=func; + sd->buff=buff; + sd->next=0; + sd->link=0; + sd->cfunc=cfunc; + sd->cbuff=cbuff; + sd->base=qd; + + if (qd->link==0) + qd->link=sd; + else{ + for (q=qd->link, i=q->link; i; i=q->link) + q=q->link; + q->link=sd; + } + CpuResumeIntr(x); +} + +///////////////////////////////////////////////////////////////////////[18] +struct sifcmd_RPC_SERVER_DATA *SifRemoveRpc(struct sifcmd_RPC_SERVER_DATA *sd, struct sifcmd_RPC_DATA_QUEUE *qd){ + u32 x; + register struct sifcmd_RPC_SERVER_DATA *s; + + CpuSuspendIntr(&x); + + if ((s=qd->link)==sd) + qd->link=s->link; + else + for ( ; s; s=s->link) + if (s->link==sd){ + s->link=s->link->link; + break; + } + CpuResumeIntr(x); + return s; +} + +///////////////////////////////////////////////////////////////////////[19] +struct sifcmd_RPC_DATA_QUEUE *SifRemoveRpcQueue(struct sifcmd_RPC_DATA_QUEUE *qd){ + u32 x; + register struct sifcmd_RPC_DATA_QUEUE *q; + + CpuSuspendIntr(&x); + + q=rpc_common.queue; + if (q==qd) { + rpc_common.queue=q->next; + } else { + for (; q; q=q->next) { + if (q->next==qd){ + q->next=q->next->next; + break; + } + } + } + CpuResumeIntr(x); + return q; +} + +///////////////////////////////////////////////////////////////////////[14] +struct sifcmd_RPC_SERVER_DATA *SifGetNextRequest(struct sifcmd_RPC_DATA_QUEUE *qd){ + u32 x; + register struct sifcmd_RPC_SERVER_DATA *s; + + CpuSuspendIntr(&x); + + if ((s=qd->start)==0) + qd->active=0; + else{ + qd->active=1; + qd->start=qd->start->next; + } + + CpuResumeIntr(x); + return s; +} + +///////////////////////////////////////////////////////////////////////[15] +void SifExecRequest(struct sifcmd_RPC_SERVER_DATA *sd){ + u32 x; + register int size, id, count, i; + register void *buff; + RPC_PACKET_END *epacket; + struct sifman_DMA dma[2]; + + size=0; + if (buff=sd->func(sd->fno, sd->buff, sd->size)) + size=sd->rsize; + + CpuSuspendIntr(&x); + epacket=(RPC_PACKET_END *)rpc_get_fpacket(&rpc_common); + CpuResumeIntr(x); + + epacket->command=0x8000000A; + epacket->client=sd->client; + count=0; + if (sd->rmode){ + while (SifSendCmd(0x80000008, epacket, 0x40, buff, sd->receive, size)==0); + return; + }else{ + epacket->packet.pid=0; + epacket->packet.rec_id=0; + if (size>0){ + count=1; + dma[count-1].data=buff; + dma[count-1].size=size; + dma[count-1].attr=0; + dma[count-1].addr=sd->receive; + } + count++; + dma[count-1].data=epacket; + dma[count-1].size=0x40; + dma[count-1].attr=0; + dma[count-1].addr=sd->pkt_addr; + do{ + CpuSuspendIntr(&x); + id=SifSetDma(dma, count); + CpuResumeIntr(x); + if (id) break; + i=0xFFFF; do --i; while (i!=-1); + } while (id==0); + } +} + +///////////////////////////////////////////////////////////////////////[16] +void SifRpcLoop(struct sifcmd_RPC_DATA_QUEUE *qd){ + register struct sifcmd_RPC_SERVER_DATA *s; + + do{ + if (s=SifGetNextRequest(qd)) + SifExecRequest(s); + else + SleepThread(); + } while (1); +} + +///////////////////////////////////////////////////////////////////////[0E] +void SifInitRpc(int mode){ + u32 x; + _dprintf("%s\n", __FUNCTION__); + + SifInitCmd(); + CpuSuspendIntr(&x); + + if (sifInitRpc){ + CpuResumeIntr(x); + }else{ + sifInitRpc=1; + rpc_common.paddr=(RPC_PACKET*)bufx; + rpc_common.size=32; + rpc_common.paddr2=0; + rpc_common.size2=0; + rpc_common.next=(RPC_PACKET*)bufy; + rpc_common.count=32; + rpc_common.base=0; + rpc_common.pid=1; + + SifAddCmdHandler(0x80000008, (cmdh_func)cmd80000008_END, &rpc_common); + SifAddCmdHandler(0x80000009, (cmdh_func)cmd80000009_BIND, &rpc_common); + SifAddCmdHandler(0x8000000A, (cmdh_func)cmd8000000A_CALL, &rpc_common); + SifAddCmdHandler(0x8000000C, (cmdh_func)cmd8000000C_RDATA, &rpc_common); + + CpuResumeIntr(x); + + ((SifCmdSRData*)bufx)->rno =0; + ((SifCmdSRData*)bufx)->value=1; + SifSendCmd(0x80000001, (void*)bufx, sizeof(SifCmdSRData), 0, 0, 0); + } + WaitEventFlag(GetSystemStatusFlag(), 0x800, 0, 0); +} + +void _retonly() {} + +struct export sifcmd_stub={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "sifcmd", + (func)_start, // entrypoint + (func)_retonly, + (func)SifDeinitCmd, + (func)_retonly, + (func)SifInitCmd, + (func)SifExitCmd, + (func)SifGetSreg, + (func)SifSetSreg, + (func)SifSetCmdBuffer, + (func)SifSetSysCmdBuffer, + (func)SifAddCmdHandler, + (func)SifRemoveCmdHandler, + (func)SifSendCmd, + (func)iSifSendCmd, + (func)SifInitRpc, + (func)SifBindRpc, + (func)SifCallRpc, + (func)SifRegisterRpc, + (func)SifCheckStatRpc, + (func)SifSetRpcQueue, + (func)SifGetNextRequest, + (func)SifExecRequest, + (func)SifRpcLoop, + (func)SifGetOtherData, + (func)SifRemoveRpc, + (func)SifRemoveRpcQueue, + (func)SifSet1CB, + (func)SifReset1CB, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + 0 +}; + +//////////////////////////////entrypoint///////////////////////////////[00] +int _start(){ + register int *v, i; + + _dprintf("%s\n", __FUNCTION__); + if (v=QueryBootMode(3)){ + _dprintf("bootmode: %x\n", v[1]); + if (v[1] & 1){ printf("%s No SIF service(sifcmd)\n", __FUNCTION__);return 1;} + if (v[1] & 2){ printf("%s No SIFCMD/RPC service\n", __FUNCTION__); return 1;} + } + + if (SifCheckInit()==0) + SifInit(); + + if (RegisterLibraryEntries(&sifcmd_stub)) return 1; + + cmd_common.sif1_rcvBuffer=sif1_rcvBuffer; + cmd_common.b=b; + cmd_common.sysCmdBuffer=sysCmds; + cmd_common.sysCmdBufferSize=32; + cmd_common.saddr=0; + cmd_common.cmdBuffer=0; + cmd_common.cmdBufferSize=0; + cmd_common.Sreg=Sreg; + cmd_common.func=0; + cmd_common.param=0; + + for (i=0; i<32; i++) { + sysCmds[i].func=0; + sysCmds[i].data=0; + } + for (i=0; i<32; i++) { + Sreg[i]=0; + } + + sysCmds[0].func=(cmdh_func)cmd80000000_CHANGE_SADDR; + sysCmds[0].data=&cmd_common; + + sysCmds[1].func=(cmdh_func)cmd80000001_SET_SREG; + sysCmds[1].data=&cmd_common; + + cmd_common.systemStatusFlag=GetSystemStatusFlag(); + + sysCmds[2].func=(cmdh_func)cmd80000002_INIT_CMD; + sysCmds[2].data=&cmd_common; + + RegisterIntrHandler(INT_DMA10, 1, SIF1_handler, (void*)&cmd_common); + EnableIntr(INT_DMA10 | IMODE_DMA_IQE); + + SifSetIOPrcvaddr((u32)sif1_rcvBuffer); + + return 0; +} + + + + diff --git a/fps2bios/kernel/iopload/sifman/Makefile b/fps2bios/kernel/iopload/sifman/Makefile index 8b5f90731c..b7f86ca1eb 100644 --- a/fps2bios/kernel/iopload/sifman/Makefile +++ b/fps2bios/kernel/iopload/sifman/Makefile @@ -1,59 +1,59 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include - -IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 -IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include -IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -IOPLINK = $(IOPLD) -dc -IOPASFLAGS := -EL -G0 - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: sifman - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib -LDADD = -OBJECTS = sifman.o ../iopdebug.o ../libkernel/iop_loadcore.o ../libkernel/iop_intrman.o - -sifman: $(OBJECTS) - $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/SIFMAN - -%.o: %.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - -%.o : %.s - $(IOPAS) $(IOPASFLAGS) $< -o $@ - -clean: - rm -f $(OBJECTS) - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: sifman + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib +LDADD = +OBJECTS = sifman.o ../iopdebug.o ../libkernel/iop_loadcore.o ../libkernel/iop_intrman.o + +sifman: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/SIFMAN + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/sifman/sifman.c b/fps2bios/kernel/iopload/sifman/sifman.c index 5ff46af2c4..dd2898a3c9 100644 --- a/fps2bios/kernel/iopload/sifman/sifman.c +++ b/fps2bios/kernel/iopload/sifman/sifman.c @@ -1,467 +1,467 @@ - -#include "kloadcore.h" -#include "kintrman.h" -#include "kdmacman.h" -#include "ksifman.h" - -#define min(a, b) ((a)<(b)?(a):(b)) -#define max(a, b) ((a)>(b)?(a):(b)) - -#define CONFIG_1450 (*(volatile int*)0xBF801450) - -#define BD0 (*(volatile int*)0xBD000000) //mscom -#define BD1 (*(volatile int*)0xBD000010) //smcom -#define BD2 (*(volatile int*)0xBD000020) //msflag -#define BD3 (*(volatile int*)0xBD000030) //smflag -#define BD4 (*(volatile int*)0xBD000040) -#define BD5 (*(volatile int*)0xBD000050) -#define BD6 (*(volatile int*)0xBD000060) -#define BD7 (*(volatile int*)0xBD000070) - - -int debug=1; - -#define _dprintf(fmt, args...) \ - if (debug > 0) __printf("sifman: " fmt, ## args) - - -struct sifData{ - int data, - words, - count, - addr; -}; - -int sifSIF2Init =0, - sifInit =0; - -struct sm_internal{ - short id, //+000 some id...?!? - res1; //+002 not used - int index; //+004 current position in dma buffer - struct sifData *crtbuf; //+008 address of current used buffer - struct sifData buf1[32]; //+00C first buffer - struct sifData buf2[32]; //+20C second buffer - int (*function)(int);//+40C a function ?!? - int param; //+410 a parameter for function - int res2; //+414 not used -} vars; - -struct sifData one; -int res3, res4; - -int _start(int argc, char* argv); -void RegisterSif0Handler(); - - -/////////////////////////////////////////////////////////////////////// -int getBD2_loopchanging(){ - register int a, b; - a=BD2; - b=BD2; - while (a!=b) { - a=b; - b=BD2; - } - return a; -} - -/////////////////////////////////////////////////////////////////////// -int getBD3_loopchanging(){ - register int a, b; - a=BD3; - b=BD3; - while (a!=b) { - a=b; - b=BD3; - } - return a; -} - -///////////////////////////////////////////////////////////////////////[04] -void SifSIF2Init(){ - if (sifSIF2Init!=0) return; - - DMAch_SIF2_CHCR = 0; //reset ch. 2 - DMAch_DPCR|= 0x800; //enable dma ch. 2 - DMAch_DPCR; - sifSIF2Init =1; -} - -///////////////////////////////////////////////////////////////////////[05] -void SifInit(){ - u32 x, y; - u32 msflag; - - _dprintf("%s: sifInit=%d\n", __FUNCTION__, sifInit); - if (sifInit!=0) return; - - DMAch_DPCR2 |=0x8800; //enable dma ch. 9 and 10 - DMAch_SIF9_CHCR = 0; - DMAch_SIFA_CHCR = 0; - SifSIF2Init(); - - if (CONFIG_1450 & 0x10) - CONFIG_1450 |= 0x10; - CONFIG_1450 |= 0x1; - - RegisterSif0Handler(); - - CpuSuspendIntr(&x); //intrman - CpuEnableIntr(); //intrman - - _dprintf("%s: waiting EE...\n", __FUNCTION__); - do { //EE kernel sif ready - CpuSuspendIntr(&y); //intrman - msflag = getBD2_loopchanging(); - CpuResumeIntr(y); //intrman - } while(!(msflag & 0x10000)); - - _dprintf("%s: EE ready\n", __FUNCTION__); - CpuResumeIntr(x); //intrman - SifSetDChain(); - SifSetIOPrcvaddr(0); //sif1 receive buffer - BD3 = 0x10000; //IOPEE_sifman_init - BD3; - sifInit =1; - _dprintf("%s ok\n", __FUNCTION__); -} - -///////////////////////////////////////////////////////////////////////[02] -void SifDeinit(){ - int x; - - DisableIntr(INT_DMA9, &x); - ReleaseIntrHandler(INT_DMA9); - DMAch_SIF9_CHCR=0; - DMAch_SIFA_CHCR=0; - if (CONFIG_1450 & 0x10) - CONFIG_1450 |= 0x10; -} - -///////////////////////////////////////////////////////////////////////[29] -int SifCheckInit(){ - return sifInit; -} - -///////////////////////////////////////////////////////////////////////[06] -void SifSetDChain(){ - if ((BD4 & 0x40) == 0) BD4=0x40; - DMAch_SIFA_CHCR =0; - DMAch_SIFA_BCR_size =32; - DMAch_SIFA_CHCR =DMAf_08|DMAf_CO|DMAf_TR|DMAf_30;//EE->IOP (to memory) -} - -///////////////////////////////////////////////////////////////////////[30] -void SifSet0CB(int (*_function)(int), int _param){ - vars.function=_function; - vars.param=_param; -} - -///////////////////////////////////////////////////////////////////////[31] -void SifReset0CB(){ - vars.function=NULL; - vars.param=0; -} - -/////////////////////////////////////////////////////////////////////// -int Sif0Handler(void *common) { - struct sm_internal *vars = (struct sm_internal *)common; - int var_10; - if (vars->function) - vars->function(vars->param); - - if ((DMAch_SIF9_CHCR & DMAf_TR == 0) && (vars->index>0)) { - DMAch_SIF9_CHCR =0; - DMAch_SIF9_TADR =(int)vars->crtbuf; - DMAch_SIF9_BCR =32; - if (BD4 & 0x20 == 0) BD4 = 0x20; - vars->id++; - if (vars->crtbuf == vars->buf1){ - vars->index=0; - vars->crtbuf=vars->buf2; - }else - vars->crtbuf=vars->buf1; - DMAch_SIF9_CHCR = DMAf_DR|DMAf_08|DMAf_CO|DMAf_LI|DMAf_TR;//IOP->EE (from memory) - var_10=DMAch_SIF9_CHCR; - } - return 1; -} - -/////////////////////////////////////////////////////////////////////// -void RegisterSif0Handler(){ - u32 x; - vars.index=0; - vars.crtbuf=vars.buf1; - vars.function=NULL; - vars.param=0; - CpuSuspendIntr(&x); //intrman - RegisterIntrHandler(INT_DMA9, 1, Sif0Handler, &vars); //intrman - EnableIntr(INT_DMA9); //intrman - CpuResumeIntr(x); //intrman -} - -/////////////////////////////////////////////////////////////////////// -void enqueue(struct sifman_DMA *psd){ - vars.crtbuf[vars.index].data=(u32)psd->data & 0xFFFFFF; //16MB addressability - if (psd->attr & SIF_DMA_INT_I) - vars.crtbuf[vars.index].data |= 0x40000000; - vars.crtbuf[vars.index].words=(psd->size + 3)/4 & 0xFFFFFF; - vars.crtbuf[vars.index].count = ((psd->size + 3)/16 + (((psd->size + 3)/4) & 3)) - | 0x10000000; - if (psd->attr & SIF_DMA_INT_O) - vars.crtbuf[vars.index].count |=0x80000000; - vars.crtbuf[vars.index].addr = (u32)psd->addr & 0x1FFFFFFF; //512MB addresability - vars.index++; -} - -///////////////////////////////////////////////////////////////////////[07] -u32 SifSetDma(struct sifman_DMA *psd, int len){ - int var_20; - register unsigned int ret; - int i; - - if (32-vars.index < len) return 0; //no place - - ret = vars.id; - ret = (ret << 16) | ((vars.index & 0xFF) << 8) | (len & 0xFF); - - if (vars.index) - vars.crtbuf[vars.index-1].data &= 0x7FFFFFFF; - for (i=0; iEE - var_20=DMAch_SIF9_CHCR; //?!? - } - return ret; -} - -///////////////////////////////////////////////////////////////////////[08] -int SifDmaStat(u32 id){ - if (DMAch_SIF9_CHCR & DMAf_TR){ - if (id>>16 == vars.id) return 1; //waiting in queue - if (id>>16+1 == vars.id) return 0; //running - } - return -1; //terminated -} - -///////////////////////////////////////////////////////////////////////[09] -void SifSend(struct sifman_DMA sd){ - sd.size = sd.size /4 + ((sd.size & 3) > 0); - one.data = ((u32)sd.data & 0xFFFFFF) | 0x80000000; - one.words= sd.size & 0xFFFFFF; - if (sd.attr & SIF_DMA_INT_I) one.data |= 0x40000000; - one.count = (sd.size/4 + ((sd.size & 3)>0)) | 0x10000000; - if (sd.attr & SIF_DMA_INT_O) one.count|= 0x80000000; - one.addr = (u32)sd.addr & 0xFFFFFFF; - - if (BD4 & 0x20 == 0) BD4=0x20; - - DMAch_SIF9_CHCR=0; - DMAch_SIF9_TADR=(u32)&one; - DMAch_SIF9_BCR_size=32; - DMAch_SIF9_CHCR=DMAf_DR|DMAf_08|DMAf_CO|DMAf_LI|DMAf_TR; //IOP->EE - DMAch_SIF9_CHCR; -} - -///////////////////////////////////////////////////////////////////////[10] -void SifSendSync(){ - while (DMAch_SIF9_CHCR & DMAf_TR); -} - -///////////////////////////////////////////////////////////////////////[11] -int SifIsSending(){ - return (DMAch_SIF9_CHCR & DMAf_TR); -} - -///////////////////////////////////////////////////////////////////////[12] -void SifSetSIF0DMA(void *data, int size, int attr){ - size=size/4 + ((size & 3)>0); - - if (BD4 & 0x20 == 0) BD4=0x20; - - DMAch_SIF9_CHCR=0; - DMAch_SIF9_MADR=(u32)data & 0xFFFFFF; - DMAch_SIF9_BCR_size=32; - DMAch_SIF9_BCR_count=size/32 + ((size & 0x1F)>0); - DMAch_SIF9_CHCR=DMAf_DR|DMAf_CO|DMAf_TR; - DMAch_SIF9_CHCR; -} - -///////////////////////////////////////////////////////////////////////[13] -void SifSendSync0(){ - while (DMAch_SIF9_CHCR & DMAf_TR); -} - -///////////////////////////////////////////////////////////////////////[14] -int SifIsSending0(){ - return (DMAch_SIF9_CHCR & DMAf_TR); -} - -///////////////////////////////////////////////////////////////////////[15] -void SifSetSIF1DMA(void *data, int size, int attr){ - size=size/4 + ((size & 3)>0); - - if (BD4 & 0x40 == 0) BD4=0x40; - - DMAch_SIFA_CHCR=0; - DMAch_SIFA_MADR=(u32)data & 0xFFFFFF; - DMAch_SIFA_BCR_size=32; - DMAch_SIFA_BCR_count=size/32 + ((size & 0x1F)>0); - DMAch_SIFA_CHCR=DMAf_CO|DMAf_TR| - (attr & SIF_DMA_BSN?DMAf_30:0); - DMAch_SIFA_CHCR; -} - -///////////////////////////////////////////////////////////////////////[16] -void SifSendSync1(){ - while (DMAch_SIFA_CHCR & DMAf_TR); -} - -///////////////////////////////////////////////////////////////////////[17] -int SifIsSending1(){ - return (DMAch_SIFA_CHCR & DMAf_TR); -} - -///////////////////////////////////////////////////////////////////////[18] -void SifSetSIF2DMA(void *data, int size, int attr){ - size=size/4 + ((size & 3)>0); - - if (BD4 & 0x80 == 0) BD4=0x80; - - DMAch_SIF2_CHCR=0; - DMAch_SIF2_MADR=(u32)data & 0xFFFFFF; - DMAch_SIF2_BCR_size=min(size, 32); - DMAch_SIF2_BCR_count=size/32 + ((size & 0x1F)>0); - DMAch_SIF2_CHCR=DMAf_CO |DMAf_TR| - ((attr & SIF_TO_EE ?DMAf_DR: - (attr & SIF_DMA_BSN?DMAf_30:0))); - DMAch_SIF2_CHCR; -} - -///////////////////////////////////////////////////////////////////////[19] -void SifSendSync2(){ - while (DMAch_SIF2_CHCR & DMAf_TR); -} - -///////////////////////////////////////////////////////////////////////[20] -int SifIsSending2(){ - return (DMAch_SIF2_CHCR & DMAf_TR); -} - -///////////////////////////////////////////////////////////////////////[21] -int SifGetEEIOPflags(){ - return getBD2_loopchanging(); -} - -///////////////////////////////////////////////////////////////////////[22] -int SifSetEEIOPflags(int val){ - BD2=val; - return getBD2_loopchanging(); -} - -///////////////////////////////////////////////////////////////////////[23] -int SifGetIOPEEflags(){ - return getBD3_loopchanging(); -} - -///////////////////////////////////////////////////////////////////////[24] -int SifSetIOPEEflags(int val){ - BD3=val; - return getBD3_loopchanging(); -} - -///////////////////////////////////////////////////////////////////////[25] -int SifGetEErcvaddr(){ - return BD0; -} - -///////////////////////////////////////////////////////////////////////[26] -int SifGetIOPrcvaddr(){ - return BD1; -} - -///////////////////////////////////////////////////////////////////////[27] -int SifSetIOPrcvaddr(int val){ - BD1=val; - return BD1; -} - -///////////////////////////////////////////////////////////////////////[28] -void SifSet1450_2(){ - CONFIG_1450 |= 2; - CONFIG_1450 &= ~2; - CONFIG_1450; -} - -///////////////////////////////////////////////////////////////////////[01,03,32,33,34,35] -void _retonly(){} - -//////////////////////////////entrypoint/////////////////////////////// -struct export sifman_stub={ - 0x41C00000, - 0, - VER(1, 1), // 1.1 => 0x101 - 0, - "sifman", - (func)_start, // entrypoint - (func)_retonly, - (func)SifDeinit, - (func)_retonly, - (func)SifSIF2Init, - (func)SifInit, - (func)SifSetDChain, - (func)SifSetDma, - (func)SifDmaStat, - (func)SifSend, - (func)SifSendSync, - (func)SifIsSending, - (func)SifSetSIF0DMA, - (func)SifSendSync0, - (func)SifIsSending0, - (func)SifSetSIF1DMA, - (func)SifSendSync1, - (func)SifIsSending1, - (func)SifSetSIF2DMA, - (func)SifSendSync2, - (func)SifIsSending2, - (func)SifGetEEIOPflags, - (func)SifSetEEIOPflags, - (func)SifGetIOPEEflags, - (func)SifSetIOPEEflags, - (func)SifGetEErcvaddr, - (func)SifGetIOPrcvaddr, - (func)SifSetIOPrcvaddr, - (func)SifSet1450_2, - (func)SifCheckInit, - (func)SifSet0CB, - (func)SifReset0CB, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - 0 -}; - -//////////////////////////////entrypoint///////////////////////////////[00] -int _start(int argc, char* argv){ - - return RegisterLibraryEntries(&sifman_stub) > 0; - -} - + +#include "kloadcore.h" +#include "kintrman.h" +#include "kdmacman.h" +#include "ksifman.h" + +#define min(a, b) ((a)<(b)?(a):(b)) +#define max(a, b) ((a)>(b)?(a):(b)) + +#define CONFIG_1450 (*(volatile int*)0xBF801450) + +#define BD0 (*(volatile int*)0xBD000000) //mscom +#define BD1 (*(volatile int*)0xBD000010) //smcom +#define BD2 (*(volatile int*)0xBD000020) //msflag +#define BD3 (*(volatile int*)0xBD000030) //smflag +#define BD4 (*(volatile int*)0xBD000040) +#define BD5 (*(volatile int*)0xBD000050) +#define BD6 (*(volatile int*)0xBD000060) +#define BD7 (*(volatile int*)0xBD000070) + + +int debug=1; + +#define _dprintf(fmt, args...) \ + if (debug > 0) __printf("sifman: " fmt, ## args) + + +struct sifData{ + int data, + words, + count, + addr; +}; + +int sifSIF2Init =0, + sifInit =0; + +struct sm_internal{ + short id, //+000 some id...?!? + res1; //+002 not used + int index; //+004 current position in dma buffer + struct sifData *crtbuf; //+008 address of current used buffer + struct sifData buf1[32]; //+00C first buffer + struct sifData buf2[32]; //+20C second buffer + int (*function)(int);//+40C a function ?!? + int param; //+410 a parameter for function + int res2; //+414 not used +} vars; + +struct sifData one; +int res3, res4; + +int _start(int argc, char* argv); +void RegisterSif0Handler(); + + +/////////////////////////////////////////////////////////////////////// +int getBD2_loopchanging(){ + register int a, b; + a=BD2; + b=BD2; + while (a!=b) { + a=b; + b=BD2; + } + return a; +} + +/////////////////////////////////////////////////////////////////////// +int getBD3_loopchanging(){ + register int a, b; + a=BD3; + b=BD3; + while (a!=b) { + a=b; + b=BD3; + } + return a; +} + +///////////////////////////////////////////////////////////////////////[04] +void SifSIF2Init(){ + if (sifSIF2Init!=0) return; + + DMAch_SIF2_CHCR = 0; //reset ch. 2 + DMAch_DPCR|= 0x800; //enable dma ch. 2 + DMAch_DPCR; + sifSIF2Init =1; +} + +///////////////////////////////////////////////////////////////////////[05] +void SifInit(){ + u32 x, y; + u32 msflag; + + _dprintf("%s: sifInit=%d\n", __FUNCTION__, sifInit); + if (sifInit!=0) return; + + DMAch_DPCR2 |=0x8800; //enable dma ch. 9 and 10 + DMAch_SIF9_CHCR = 0; + DMAch_SIFA_CHCR = 0; + SifSIF2Init(); + + if (CONFIG_1450 & 0x10) + CONFIG_1450 |= 0x10; + CONFIG_1450 |= 0x1; + + RegisterSif0Handler(); + + CpuSuspendIntr(&x); //intrman + CpuEnableIntr(); //intrman + + _dprintf("%s: waiting EE...\n", __FUNCTION__); + do { //EE kernel sif ready + CpuSuspendIntr(&y); //intrman + msflag = getBD2_loopchanging(); + CpuResumeIntr(y); //intrman + } while(!(msflag & 0x10000)); + + _dprintf("%s: EE ready\n", __FUNCTION__); + CpuResumeIntr(x); //intrman + SifSetDChain(); + SifSetIOPrcvaddr(0); //sif1 receive buffer + BD3 = 0x10000; //IOPEE_sifman_init + BD3; + sifInit =1; + _dprintf("%s ok\n", __FUNCTION__); +} + +///////////////////////////////////////////////////////////////////////[02] +void SifDeinit(){ + int x; + + DisableIntr(INT_DMA9, &x); + ReleaseIntrHandler(INT_DMA9); + DMAch_SIF9_CHCR=0; + DMAch_SIFA_CHCR=0; + if (CONFIG_1450 & 0x10) + CONFIG_1450 |= 0x10; +} + +///////////////////////////////////////////////////////////////////////[29] +int SifCheckInit(){ + return sifInit; +} + +///////////////////////////////////////////////////////////////////////[06] +void SifSetDChain(){ + if ((BD4 & 0x40) == 0) BD4=0x40; + DMAch_SIFA_CHCR =0; + DMAch_SIFA_BCR_size =32; + DMAch_SIFA_CHCR =DMAf_08|DMAf_CO|DMAf_TR|DMAf_30;//EE->IOP (to memory) +} + +///////////////////////////////////////////////////////////////////////[30] +void SifSet0CB(int (*_function)(int), int _param){ + vars.function=_function; + vars.param=_param; +} + +///////////////////////////////////////////////////////////////////////[31] +void SifReset0CB(){ + vars.function=NULL; + vars.param=0; +} + +/////////////////////////////////////////////////////////////////////// +int Sif0Handler(void *common) { + struct sm_internal *vars = (struct sm_internal *)common; + int var_10; + if (vars->function) + vars->function(vars->param); + + if ((DMAch_SIF9_CHCR & DMAf_TR == 0) && (vars->index>0)) { + DMAch_SIF9_CHCR =0; + DMAch_SIF9_TADR =(int)vars->crtbuf; + DMAch_SIF9_BCR =32; + if (BD4 & 0x20 == 0) BD4 = 0x20; + vars->id++; + if (vars->crtbuf == vars->buf1){ + vars->index=0; + vars->crtbuf=vars->buf2; + }else + vars->crtbuf=vars->buf1; + DMAch_SIF9_CHCR = DMAf_DR|DMAf_08|DMAf_CO|DMAf_LI|DMAf_TR;//IOP->EE (from memory) + var_10=DMAch_SIF9_CHCR; + } + return 1; +} + +/////////////////////////////////////////////////////////////////////// +void RegisterSif0Handler(){ + u32 x; + vars.index=0; + vars.crtbuf=vars.buf1; + vars.function=NULL; + vars.param=0; + CpuSuspendIntr(&x); //intrman + RegisterIntrHandler(INT_DMA9, 1, Sif0Handler, &vars); //intrman + EnableIntr(INT_DMA9); //intrman + CpuResumeIntr(x); //intrman +} + +/////////////////////////////////////////////////////////////////////// +void enqueue(struct sifman_DMA *psd){ + vars.crtbuf[vars.index].data=(u32)psd->data & 0xFFFFFF; //16MB addressability + if (psd->attr & SIF_DMA_INT_I) + vars.crtbuf[vars.index].data |= 0x40000000; + vars.crtbuf[vars.index].words=(psd->size + 3)/4 & 0xFFFFFF; + vars.crtbuf[vars.index].count = ((psd->size + 3)/16 + (((psd->size + 3)/4) & 3)) + | 0x10000000; + if (psd->attr & SIF_DMA_INT_O) + vars.crtbuf[vars.index].count |=0x80000000; + vars.crtbuf[vars.index].addr = (u32)psd->addr & 0x1FFFFFFF; //512MB addresability + vars.index++; +} + +///////////////////////////////////////////////////////////////////////[07] +u32 SifSetDma(struct sifman_DMA *psd, int len){ + int var_20; + register unsigned int ret; + int i; + + if (32-vars.index < len) return 0; //no place + + ret = vars.id; + ret = (ret << 16) | ((vars.index & 0xFF) << 8) | (len & 0xFF); + + if (vars.index) + vars.crtbuf[vars.index-1].data &= 0x7FFFFFFF; + for (i=0; iEE + var_20=DMAch_SIF9_CHCR; //?!? + } + return ret; +} + +///////////////////////////////////////////////////////////////////////[08] +int SifDmaStat(u32 id){ + if (DMAch_SIF9_CHCR & DMAf_TR){ + if (id>>16 == vars.id) return 1; //waiting in queue + if (id>>16+1 == vars.id) return 0; //running + } + return -1; //terminated +} + +///////////////////////////////////////////////////////////////////////[09] +void SifSend(struct sifman_DMA sd){ + sd.size = sd.size /4 + ((sd.size & 3) > 0); + one.data = ((u32)sd.data & 0xFFFFFF) | 0x80000000; + one.words= sd.size & 0xFFFFFF; + if (sd.attr & SIF_DMA_INT_I) one.data |= 0x40000000; + one.count = (sd.size/4 + ((sd.size & 3)>0)) | 0x10000000; + if (sd.attr & SIF_DMA_INT_O) one.count|= 0x80000000; + one.addr = (u32)sd.addr & 0xFFFFFFF; + + if (BD4 & 0x20 == 0) BD4=0x20; + + DMAch_SIF9_CHCR=0; + DMAch_SIF9_TADR=(u32)&one; + DMAch_SIF9_BCR_size=32; + DMAch_SIF9_CHCR=DMAf_DR|DMAf_08|DMAf_CO|DMAf_LI|DMAf_TR; //IOP->EE + DMAch_SIF9_CHCR; +} + +///////////////////////////////////////////////////////////////////////[10] +void SifSendSync(){ + while (DMAch_SIF9_CHCR & DMAf_TR); +} + +///////////////////////////////////////////////////////////////////////[11] +int SifIsSending(){ + return (DMAch_SIF9_CHCR & DMAf_TR); +} + +///////////////////////////////////////////////////////////////////////[12] +void SifSetSIF0DMA(void *data, int size, int attr){ + size=size/4 + ((size & 3)>0); + + if (BD4 & 0x20 == 0) BD4=0x20; + + DMAch_SIF9_CHCR=0; + DMAch_SIF9_MADR=(u32)data & 0xFFFFFF; + DMAch_SIF9_BCR_size=32; + DMAch_SIF9_BCR_count=size/32 + ((size & 0x1F)>0); + DMAch_SIF9_CHCR=DMAf_DR|DMAf_CO|DMAf_TR; + DMAch_SIF9_CHCR; +} + +///////////////////////////////////////////////////////////////////////[13] +void SifSendSync0(){ + while (DMAch_SIF9_CHCR & DMAf_TR); +} + +///////////////////////////////////////////////////////////////////////[14] +int SifIsSending0(){ + return (DMAch_SIF9_CHCR & DMAf_TR); +} + +///////////////////////////////////////////////////////////////////////[15] +void SifSetSIF1DMA(void *data, int size, int attr){ + size=size/4 + ((size & 3)>0); + + if (BD4 & 0x40 == 0) BD4=0x40; + + DMAch_SIFA_CHCR=0; + DMAch_SIFA_MADR=(u32)data & 0xFFFFFF; + DMAch_SIFA_BCR_size=32; + DMAch_SIFA_BCR_count=size/32 + ((size & 0x1F)>0); + DMAch_SIFA_CHCR=DMAf_CO|DMAf_TR| + (attr & SIF_DMA_BSN?DMAf_30:0); + DMAch_SIFA_CHCR; +} + +///////////////////////////////////////////////////////////////////////[16] +void SifSendSync1(){ + while (DMAch_SIFA_CHCR & DMAf_TR); +} + +///////////////////////////////////////////////////////////////////////[17] +int SifIsSending1(){ + return (DMAch_SIFA_CHCR & DMAf_TR); +} + +///////////////////////////////////////////////////////////////////////[18] +void SifSetSIF2DMA(void *data, int size, int attr){ + size=size/4 + ((size & 3)>0); + + if (BD4 & 0x80 == 0) BD4=0x80; + + DMAch_SIF2_CHCR=0; + DMAch_SIF2_MADR=(u32)data & 0xFFFFFF; + DMAch_SIF2_BCR_size=min(size, 32); + DMAch_SIF2_BCR_count=size/32 + ((size & 0x1F)>0); + DMAch_SIF2_CHCR=DMAf_CO |DMAf_TR| + ((attr & SIF_TO_EE ?DMAf_DR: + (attr & SIF_DMA_BSN?DMAf_30:0))); + DMAch_SIF2_CHCR; +} + +///////////////////////////////////////////////////////////////////////[19] +void SifSendSync2(){ + while (DMAch_SIF2_CHCR & DMAf_TR); +} + +///////////////////////////////////////////////////////////////////////[20] +int SifIsSending2(){ + return (DMAch_SIF2_CHCR & DMAf_TR); +} + +///////////////////////////////////////////////////////////////////////[21] +int SifGetEEIOPflags(){ + return getBD2_loopchanging(); +} + +///////////////////////////////////////////////////////////////////////[22] +int SifSetEEIOPflags(int val){ + BD2=val; + return getBD2_loopchanging(); +} + +///////////////////////////////////////////////////////////////////////[23] +int SifGetIOPEEflags(){ + return getBD3_loopchanging(); +} + +///////////////////////////////////////////////////////////////////////[24] +int SifSetIOPEEflags(int val){ + BD3=val; + return getBD3_loopchanging(); +} + +///////////////////////////////////////////////////////////////////////[25] +int SifGetEErcvaddr(){ + return BD0; +} + +///////////////////////////////////////////////////////////////////////[26] +int SifGetIOPrcvaddr(){ + return BD1; +} + +///////////////////////////////////////////////////////////////////////[27] +int SifSetIOPrcvaddr(int val){ + BD1=val; + return BD1; +} + +///////////////////////////////////////////////////////////////////////[28] +void SifSet1450_2(){ + CONFIG_1450 |= 2; + CONFIG_1450 &= ~2; + CONFIG_1450; +} + +///////////////////////////////////////////////////////////////////////[01,03,32,33,34,35] +void _retonly(){} + +//////////////////////////////entrypoint/////////////////////////////// +struct export sifman_stub={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "sifman", + (func)_start, // entrypoint + (func)_retonly, + (func)SifDeinit, + (func)_retonly, + (func)SifSIF2Init, + (func)SifInit, + (func)SifSetDChain, + (func)SifSetDma, + (func)SifDmaStat, + (func)SifSend, + (func)SifSendSync, + (func)SifIsSending, + (func)SifSetSIF0DMA, + (func)SifSendSync0, + (func)SifIsSending0, + (func)SifSetSIF1DMA, + (func)SifSendSync1, + (func)SifIsSending1, + (func)SifSetSIF2DMA, + (func)SifSendSync2, + (func)SifIsSending2, + (func)SifGetEEIOPflags, + (func)SifSetEEIOPflags, + (func)SifGetIOPEEflags, + (func)SifSetIOPEEflags, + (func)SifGetEErcvaddr, + (func)SifGetIOPrcvaddr, + (func)SifSetIOPrcvaddr, + (func)SifSet1450_2, + (func)SifCheckInit, + (func)SifSet0CB, + (func)SifReset0CB, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + 0 +}; + +//////////////////////////////entrypoint///////////////////////////////[00] +int _start(int argc, char* argv){ + + return RegisterLibraryEntries(&sifman_stub) > 0; + +} + diff --git a/fps2bios/kernel/iopload/sio2man/Makefile b/fps2bios/kernel/iopload/sio2man/Makefile index 593c41abc3..b797dd1667 100644 --- a/fps2bios/kernel/iopload/sio2man/Makefile +++ b/fps2bios/kernel/iopload/sio2man/Makefile @@ -1,63 +1,63 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include - -IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 -IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include -IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -IOPLINK = $(IOPLD) -dc -nostartfiles -IOPASFLAGS := -EL -G0 - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: sio2man - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib -LDADD = -OBJECTS = sio2man.o ../iopdebug.o \ - ../libkernel/iop_loadcore.o ../libkernel/iop_intrman.o \ - ../libkernel/iop_dmacman.o ../libkernel/iop_thbase.o \ - ../libkernel/iop_thevent.o ../libkernel/iop_stdio.o \ - ../libkernel/iop_sysclib.o - -sio2man: $(OBJECTS) - $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/SIO2MAN - -%.o: %.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - -%.o : %.s - $(IOPAS) $(IOPASFLAGS) $< -o $@ - -clean: - rm -f $(OBJECTS) - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc -nostartfiles +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: sio2man + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib +LDADD = +OBJECTS = sio2man.o ../iopdebug.o \ + ../libkernel/iop_loadcore.o ../libkernel/iop_intrman.o \ + ../libkernel/iop_dmacman.o ../libkernel/iop_thbase.o \ + ../libkernel/iop_thevent.o ../libkernel/iop_stdio.o \ + ../libkernel/iop_sysclib.o + +sio2man: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/SIO2MAN + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/sio2man/sio2man.c b/fps2bios/kernel/iopload/sio2man/sio2man.c index 11a5220dbc..73f423f75f 100644 --- a/fps2bios/kernel/iopload/sio2man/sio2man.c +++ b/fps2bios/kernel/iopload/sio2man/sio2man.c @@ -1,508 +1,508 @@ -//[module] SIO2MAN -//[processor] IOP -//[type] ELF-IRX -//[size] ?(0x?) -//[bios] ?(0x?-0x?) -//[iopboot2] 21 -//[loaded @] ? -//[name] sio2man -//[version] 0x101 -//[memory map] 0xBF808200,0xBF808204,0xBF808208,0xBF80820C, -// 0xBF808210,0xBF808214,0xBF808218,0xBF80821C, 16 entries -// 0xBF808220,0xBF808224,0xBF808228,0xBF80822C, array -// 0xBF808230,0xBF808234,0xBF808238,0xBF80823C, -// 0xBF808240,0xBF808244,0xBF808248,0xBF80824C, -// 0xBF808250,0xBF808254,0xBF808258,0xBF80825C, -// 0xBF808260, 0xBF808268,0xBF80826C, -// 0xBF808270,0xBF808274,0xBF808278,0xBF80827C, -// 0xBF808280 -//[handlers] - -//[entry point] _start, (export_stub) -//[made by] Herben - -#include -#include - -#include "kdmacman.h" -#include "kloadcore.h" -#include "kintrman.h" -#include -#include - -struct sio2_packet { - u32 recvVal1; // 0x00 - u32 sendArray1[4]; // 0x04-0x10 - u32 sendArray2[4]; // 0x14-0x20 - - u32 recvVal2; // 0x24 - - u32 sendArray3[16]; // 0x28-0x64 - - u32 recvVal3; // 0x68 - - int sendSize; // 0x6C - int recvSize; // 0x70 - - u8 *sendBuf; // 0x74 - u8 *recvBuf; // 0x78 - - u32 dmacAddress1; - u32 dmacSize1; - u32 dmacCount1; - u32 dmacAddress2; - u32 dmacSize2; - u32 dmacCount2; -}; - -struct sio2common { - int evid; - int thid; -}; - -struct sio2common common; -int sio2_initialized = 0; -struct sio2_packet *packetAddr; -int debug = 1; - -#define _dprintf(fmt, args...) if (debug > 0) printf(fmt, ## args) - -// if (debug > 0) printf("\033[0;32m" "sio2man: " "\033[0m" fmt, ## args) - -int _start(void); -void nullSub(void); -int sio2_init(void); -void sio2_deInit(void); -void sio2_setCtrl(u32 arg0); -u32 sio2_getCtrl(void); -u32 sio2_getRecv1(void); -void sio2_setSend1(int entryNum, u32 val); -u32 sio2_getSend1(int entryNum); -void sio2_setSend2(int entryNum, u32 val); -u32 sio2_getSend2(int entryNum); -u32 sio2_getRecv2(void); -void sio2_setSend3(int entryNum, u32 val); -u32 sio2_getSend3(int entryNum); -u32 sio2_getRecv3(void); -void sio2_set8278(u32 arg0); -u32 sio2_get8278(void); -void sio2_set827C(u32 arg0); -u32 sio2_get827C(void); -void sio2_datain(u8 arg0); -u8 sio2_dataout(void); -void sio2_setIntr(u32 arg0); -u32 sio2_getIntr(void); -void sio2_signalExchange1(void); -void sio2_signalExchange2(void); -int sio2_packetExchange(struct sio2_packet *packet); - -struct export sio2man_stub={ - 0x41C00000, - 0, - VER(1, 2), // 1.2 => 0x102 - 0, - "sio2man", - (func)_start, // 0 - (func)nullSub, - (func)sio2_deInit, - (func)nullSub, - (func)sio2_setCtrl, // 4 - (func)sio2_getCtrl, - (func)sio2_getRecv1, - (func)sio2_setSend1, - (func)sio2_getSend1, // 8 - (func)sio2_setSend2, - (func)sio2_getSend2, - (func)sio2_getRecv2, - (func)sio2_setSend3, // 12 - (func)sio2_getSend3, - (func)sio2_getRecv3, - (func)sio2_set8278, - (func)sio2_get8278, // 16 - (func)sio2_set827C, - (func)sio2_get827C, - (func)sio2_datain, - (func)sio2_dataout, // 20 - (func)sio2_setIntr, - (func)sio2_getIntr, - (func)sio2_signalExchange1, - (func)sio2_signalExchange2, // 24 - (func)sio2_packetExchange, - 0 -}; - -#define INUM_sio2 17 -#define HTYPE_C 1 - - -int _start(void) { - return sio2_init(); -} - -void nullSub(void) { return; } - -void sio2_setCtrl(u32 arg0) { - *(u32 *) (0xBF808268) = arg0; -} - -u32 sio2_getCtrl(void) { - return(*(u32 *) (0xBF808268)); -} - -u32 sio2_getRecv1(void) { - return(*(u32 *) (0xBF80826C)); -} - -void sio2_setSend1(int entryNum, u32 val) { - switch(entryNum) { - case 0: - *(u32 *) (0xBF808240) = val; - break; - case 1: - *(u32 *) (0xBF808248) = val; - break; - case 2: - *(u32 *) (0xBF808250) = val; - break; - case 3: - *(u32 *) (0xBF808258) = val; - break; - } -} - -u32 sio2_getSend1(int entryNum) { - switch(entryNum) { - case 0: - return(*(u32 *) (0xBF808240)); - case 1: - return(*(u32 *) (0xBF808248)); - case 2: - return(*(u32 *) (0xBF808250)); - case 3: - return(*(u32 *) (0xBF808258)); - } - - return(0); -} - -void sio2_setSend2(int entryNum, u32 val) { - switch(entryNum) { - case 0: - *(u32 *) (0xBF808244) = val; - break; - case 1: - *(u32 *) (0xBF80824C) = val; - break; - case 2: - *(u32 *) (0xBF808254) = val; - break; - case 3: - *(u32 *) (0xBF80825C) = val; - break; - } -} - -u32 sio2_getSend2(int entryNum) { - switch(entryNum) { - case 0: - return(*(u32 *) (0xBF808244)); - case 1: - return(*(u32 *) (0xBF80824C)); - case 2: - return(*(u32 *) (0xBF808254)); - case 3: - return(*(u32 *) (0xBF80825C)); - } - - return(0); -} - -u32 sio2_getRecv2(void) { - return(*(u32 *) (0xBF808270)); -} - -void sio2_setSend3(int entryNum, u32 val) { - if(entryNum < 16) - *(u32 *) (0xBF808200 + (entryNum * 4)) = val; -} - -u32 sio2_getSend3(int entryNum) { - if(entryNum < 16) - return(*(u32 *) (0xBF808200 + (entryNum * 4))); - - return(-1); -} - -u32 sio2_getRecv3(void) { - return(*(u32 *) (0xBF808274)); -} - -void sio2_set8278(u32 arg0) { - *(u32 *) (0xBF808278) = arg0; -} - -u32 sio2_get8278(void) { - return(*(u32 *) (0xBF808278)); -} - -void sio2_set827C(u32 arg0) { - *(u32 *) (0xBF80827C) = arg0; -} - -u32 sio2_get827C(void) { - return(*(u32 *) (0xBF80827C)); -} - -void sio2_datain(u8 arg0) { - *(u8 *) (0xBF808260) = arg0; -} - -u8 sio2_dataout(void) { - return(*(u8 *) (0xBF808264)); -} - -void sio2_setIntr(u32 arg0) { - *(u32 *) (0xBF808280) = arg0; -} - -u32 sio2_getIntr(void) { - return(*(u32 *) (0xBF808280)); -} - -int sio2_createEventFlag(void) { - iop_event_t param; - - param.attr = 2; - param.option = 0; - param.bits = 0; - return(CreateEventFlag(¶m)); -} - -void dumpbuf(u8 *buf, int size) { -/* char str[1024]; - char tmp[256]; - int i; - - str[0] = 0; - for(i = 0; i < size; i++) { - sprintf(tmp, "%x, ", buf[i]); - strcat(str, tmp); - } - printf("%s\n", str); - */ -} - -void sio2_sendPacket(struct sio2_packet *p) { - int i; - -// _dprintf("%s: sendSize=%d\n", __FUNCTION__, p->sendSize); - - for(i = 0; i < 4; i++) { - sio2_setSend1(i, p->sendArray1[i]); - sio2_setSend2(i, p->sendArray2[i]); - } - - for(i = 0; i < 16; i++) - sio2_setSend3(i, p->sendArray3[i]); - - if (p->sendSize) { - _dprintf("sendBuf: "); - dumpbuf(p->sendBuf, p->sendSize); - - for(i = 0; i < p->sendSize; i++) { - *(u8 *) (0xBF808260) = p->sendBuf[i]; - } - } - - if(p->dmacAddress1 != 0) { - _dprintf("dmaAddress1=%x, dmacSize1=%x, dmacCount1=%x\n", p->dmacAddress1, p->dmacSize1, p->dmacCount1); - dumpbuf((u8*)p->dmacAddress1, p->dmacSize1*p->dmacCount1); - dmacSetDMA(DMAch_SIO2in, p->dmacAddress1, p->dmacSize1, p->dmacCount1, 1); // from memory - dmacStartTransfer(DMAch_SIO2in); - } - - if(p->dmacAddress2 != 0) { - dmacSetDMA(DMAch_SIO2out, p->dmacAddress2, p->dmacSize2, p->dmacCount2, 0); // to memory - dmacStartTransfer(DMAch_SIO2out); - } -} - -void sio2_recvPacket(struct sio2_packet *p) { - int i; - -// _dprintf("%s: recvSize=%d\n", __FUNCTION__, p->recvSize); - - p->recvVal1 = *(u32 *) (0xBF80826C); - p->recvVal2 = *(u32 *) (0xBF808270); - p->recvVal3 = *(u32 *) (0xBF808274); - - if (p->recvSize) { - _dprintf("recvBuf: "); - for(i = 0; i < p->recvSize; i++) { - p->recvBuf[i] = *(u8 *) (0xBF808264); - printf("%x, ", p->recvBuf[i]); - } - // printf("\n"); - } - - if (p->dmacAddress2 != 0) { - dumpbuf((u8*)p->dmacAddress2, p->dmacSize2*p->dmacCount2); - } -} - -void sio2_basicThread(void* data) { - unsigned long result[4]; - - //_dprintf("%s\n", __FUNCTION__); - - while(1) { - WaitEventFlag(common.evid, 0x5, 0x01, result); - - if (result[0] & 0x01) { - ClearEventFlag(common.evid, ~0x1); - SetEventFlag(common.evid, 0x02); - } else - if (result[0] & 0x04) { - ClearEventFlag(common.evid, ~0x4); - SetEventFlag(common.evid, 0x08); - } else { - printf("sio2MAN: Woke up for unknown event(%08X)!\n", result[0]); - return; - } - -// Wait for application to call our export 25 - WaitEventFlag(common.evid, 0x10, 0, NULL); - ClearEventFlag(common.evid, ~0x10); - - *(u32 *) (0xBF808268) = (*(u32 *) (0xBF808268)) | 0x0C; - sio2_sendPacket(packetAddr); - *(u32 *) (0xBF808268) = (*(u32 *) (0xBF808268)) | 0x01; - -// Wait for the sio2 interrupt to occur - WaitEventFlag(common.evid, 0x80, 0, NULL); - ClearEventFlag(common.evid, ~0x80); - -// Recieve the reply packet - sio2_recvPacket(packetAddr); - - SetEventFlag(common.evid, 0x20); - - WaitEventFlag(common.evid, 0x40, 0, NULL); - ClearEventFlag(common.evid, ~0x40); - } -} - -int sio2_createBasicThread(void) { - iop_thread_t param; - - param.attr = TH_C; - param.option = 0; - param.thread = &sio2_basicThread; - param.stacksize = 0x2000; - param.priority = 0x18; - - return(CreateThread(¶m)); -} - - -int sio2_interruptHandler(struct sio2common *c) { - sio2_setIntr(sio2_getIntr()); - - iSetEventFlag(c->evid, 0x80); - - return(1); -} - -// Export 0 -int sio2_init(void) { - u32 oldStat; - -// _dprintf("%s\n", __FUNCTION__); - - if(RegisterLibraryEntries(&sio2man_stub) != 0) { - //printf("sio2MAN: Unable to register library entries!\n"); - return(MODULE_NO_RESIDENT_END);//==1 - } - - if(sio2_initialized != 0) { - //printf("sio2MAN: Already initialized!\n"); - return(MODULE_NO_RESIDENT_END); - } - - sio2_initialized = 1; - - *(u32 *) (0xBF808268) = 0x3BC; - - common.evid = sio2_createEventFlag(); - common.thid = sio2_createBasicThread(); - - CpuSuspendIntr(&oldStat); - - RegisterIntrHandler(INUM_sio2, HTYPE_C, &sio2_interruptHandler, &common); - EnableIntr(INUM_sio2); - - CpuResumeIntr(oldStat); - - dmacSetVal(DMAch_SIO2in, 0x03); - dmacSetVal(DMAch_SIO2out, 0x03); - dmacEnableDMAch(DMAch_SIO2in); - dmacEnableDMAch(DMAch_SIO2out); - - StartThread(common.thid, 0); // Start the "basicThread" - - return MODULE_RESIDENT_END; -} - -void sio2_deInit(void) { - u32 oldStat; - -// _dprintf("%s\n", __FUNCTION__); - - CpuSuspendIntr(&oldStat); - - DisableIntr(INUM_sio2, 0); - ReleaseIntrHandler(INUM_sio2); - - CpuResumeIntr(oldStat); - - dmacDisableDMAch(DMAch_SIO2in); - dmacDisableDMAch(DMAch_SIO2out); -} - -void sio2_signalExchange1(void) { -// _dprintf("%s\n", __FUNCTION__); - -// Signal the basic thread to let it know we want to do an exchange. - SetEventFlag(common.evid, 0x01); -// Wait for basic thread to acknowledge then clear the flag. - WaitEventFlag(common.evid, 0x02, 0, NULL); - ClearEventFlag(common.evid, ~0x2); -} - -void sio2_signalExchange2(void) { -// _dprintf("%s\n", __FUNCTION__); - -// Signal the basic thread to let it know we want to do an exchange. - SetEventFlag(common.evid, 0x04); -// Wait for basic thread to acknowledge then clear the flag. - WaitEventFlag(common.evid, 0x08, 0, NULL); - ClearEventFlag(common.evid, ~0x8); -} - -int sio2_packetExchange(struct sio2_packet *packet) { -// _dprintf("%s: %x\n", __FUNCTION__, packet); - -// Set the address of the packet. - packetAddr = packet; - -// Let the basic thread know we have the address set for the exchange. - SetEventFlag(common.evid, 0x10); - -// Wait for the basic thread to finish it's stuff. - WaitEventFlag(common.evid, 0x20, 0, NULL); - ClearEventFlag(common.evid, ~0x20); - - SetEventFlag(common.evid, 0x40); - - return 1; -} - +//[module] SIO2MAN +//[processor] IOP +//[type] ELF-IRX +//[size] ?(0x?) +//[bios] ?(0x?-0x?) +//[iopboot2] 21 +//[loaded @] ? +//[name] sio2man +//[version] 0x101 +//[memory map] 0xBF808200,0xBF808204,0xBF808208,0xBF80820C, +// 0xBF808210,0xBF808214,0xBF808218,0xBF80821C, 16 entries +// 0xBF808220,0xBF808224,0xBF808228,0xBF80822C, array +// 0xBF808230,0xBF808234,0xBF808238,0xBF80823C, +// 0xBF808240,0xBF808244,0xBF808248,0xBF80824C, +// 0xBF808250,0xBF808254,0xBF808258,0xBF80825C, +// 0xBF808260, 0xBF808268,0xBF80826C, +// 0xBF808270,0xBF808274,0xBF808278,0xBF80827C, +// 0xBF808280 +//[handlers] - +//[entry point] _start, (export_stub) +//[made by] Herben + +#include +#include + +#include "kdmacman.h" +#include "kloadcore.h" +#include "kintrman.h" +#include +#include + +struct sio2_packet { + u32 recvVal1; // 0x00 + u32 sendArray1[4]; // 0x04-0x10 + u32 sendArray2[4]; // 0x14-0x20 + + u32 recvVal2; // 0x24 + + u32 sendArray3[16]; // 0x28-0x64 + + u32 recvVal3; // 0x68 + + int sendSize; // 0x6C + int recvSize; // 0x70 + + u8 *sendBuf; // 0x74 + u8 *recvBuf; // 0x78 + + u32 dmacAddress1; + u32 dmacSize1; + u32 dmacCount1; + u32 dmacAddress2; + u32 dmacSize2; + u32 dmacCount2; +}; + +struct sio2common { + int evid; + int thid; +}; + +struct sio2common common; +int sio2_initialized = 0; +struct sio2_packet *packetAddr; +int debug = 1; + +#define _dprintf(fmt, args...) if (debug > 0) printf(fmt, ## args) + +// if (debug > 0) printf("\033[0;32m" "sio2man: " "\033[0m" fmt, ## args) + +int _start(void); +void nullSub(void); +int sio2_init(void); +void sio2_deInit(void); +void sio2_setCtrl(u32 arg0); +u32 sio2_getCtrl(void); +u32 sio2_getRecv1(void); +void sio2_setSend1(int entryNum, u32 val); +u32 sio2_getSend1(int entryNum); +void sio2_setSend2(int entryNum, u32 val); +u32 sio2_getSend2(int entryNum); +u32 sio2_getRecv2(void); +void sio2_setSend3(int entryNum, u32 val); +u32 sio2_getSend3(int entryNum); +u32 sio2_getRecv3(void); +void sio2_set8278(u32 arg0); +u32 sio2_get8278(void); +void sio2_set827C(u32 arg0); +u32 sio2_get827C(void); +void sio2_datain(u8 arg0); +u8 sio2_dataout(void); +void sio2_setIntr(u32 arg0); +u32 sio2_getIntr(void); +void sio2_signalExchange1(void); +void sio2_signalExchange2(void); +int sio2_packetExchange(struct sio2_packet *packet); + +struct export sio2man_stub={ + 0x41C00000, + 0, + VER(1, 2), // 1.2 => 0x102 + 0, + "sio2man", + (func)_start, // 0 + (func)nullSub, + (func)sio2_deInit, + (func)nullSub, + (func)sio2_setCtrl, // 4 + (func)sio2_getCtrl, + (func)sio2_getRecv1, + (func)sio2_setSend1, + (func)sio2_getSend1, // 8 + (func)sio2_setSend2, + (func)sio2_getSend2, + (func)sio2_getRecv2, + (func)sio2_setSend3, // 12 + (func)sio2_getSend3, + (func)sio2_getRecv3, + (func)sio2_set8278, + (func)sio2_get8278, // 16 + (func)sio2_set827C, + (func)sio2_get827C, + (func)sio2_datain, + (func)sio2_dataout, // 20 + (func)sio2_setIntr, + (func)sio2_getIntr, + (func)sio2_signalExchange1, + (func)sio2_signalExchange2, // 24 + (func)sio2_packetExchange, + 0 +}; + +#define INUM_sio2 17 +#define HTYPE_C 1 + + +int _start(void) { + return sio2_init(); +} + +void nullSub(void) { return; } + +void sio2_setCtrl(u32 arg0) { + *(u32 *) (0xBF808268) = arg0; +} + +u32 sio2_getCtrl(void) { + return(*(u32 *) (0xBF808268)); +} + +u32 sio2_getRecv1(void) { + return(*(u32 *) (0xBF80826C)); +} + +void sio2_setSend1(int entryNum, u32 val) { + switch(entryNum) { + case 0: + *(u32 *) (0xBF808240) = val; + break; + case 1: + *(u32 *) (0xBF808248) = val; + break; + case 2: + *(u32 *) (0xBF808250) = val; + break; + case 3: + *(u32 *) (0xBF808258) = val; + break; + } +} + +u32 sio2_getSend1(int entryNum) { + switch(entryNum) { + case 0: + return(*(u32 *) (0xBF808240)); + case 1: + return(*(u32 *) (0xBF808248)); + case 2: + return(*(u32 *) (0xBF808250)); + case 3: + return(*(u32 *) (0xBF808258)); + } + + return(0); +} + +void sio2_setSend2(int entryNum, u32 val) { + switch(entryNum) { + case 0: + *(u32 *) (0xBF808244) = val; + break; + case 1: + *(u32 *) (0xBF80824C) = val; + break; + case 2: + *(u32 *) (0xBF808254) = val; + break; + case 3: + *(u32 *) (0xBF80825C) = val; + break; + } +} + +u32 sio2_getSend2(int entryNum) { + switch(entryNum) { + case 0: + return(*(u32 *) (0xBF808244)); + case 1: + return(*(u32 *) (0xBF80824C)); + case 2: + return(*(u32 *) (0xBF808254)); + case 3: + return(*(u32 *) (0xBF80825C)); + } + + return(0); +} + +u32 sio2_getRecv2(void) { + return(*(u32 *) (0xBF808270)); +} + +void sio2_setSend3(int entryNum, u32 val) { + if(entryNum < 16) + *(u32 *) (0xBF808200 + (entryNum * 4)) = val; +} + +u32 sio2_getSend3(int entryNum) { + if(entryNum < 16) + return(*(u32 *) (0xBF808200 + (entryNum * 4))); + + return(-1); +} + +u32 sio2_getRecv3(void) { + return(*(u32 *) (0xBF808274)); +} + +void sio2_set8278(u32 arg0) { + *(u32 *) (0xBF808278) = arg0; +} + +u32 sio2_get8278(void) { + return(*(u32 *) (0xBF808278)); +} + +void sio2_set827C(u32 arg0) { + *(u32 *) (0xBF80827C) = arg0; +} + +u32 sio2_get827C(void) { + return(*(u32 *) (0xBF80827C)); +} + +void sio2_datain(u8 arg0) { + *(u8 *) (0xBF808260) = arg0; +} + +u8 sio2_dataout(void) { + return(*(u8 *) (0xBF808264)); +} + +void sio2_setIntr(u32 arg0) { + *(u32 *) (0xBF808280) = arg0; +} + +u32 sio2_getIntr(void) { + return(*(u32 *) (0xBF808280)); +} + +int sio2_createEventFlag(void) { + iop_event_t param; + + param.attr = 2; + param.option = 0; + param.bits = 0; + return(CreateEventFlag(¶m)); +} + +void dumpbuf(u8 *buf, int size) { +/* char str[1024]; + char tmp[256]; + int i; + + str[0] = 0; + for(i = 0; i < size; i++) { + sprintf(tmp, "%x, ", buf[i]); + strcat(str, tmp); + } + printf("%s\n", str); + */ +} + +void sio2_sendPacket(struct sio2_packet *p) { + int i; + +// _dprintf("%s: sendSize=%d\n", __FUNCTION__, p->sendSize); + + for(i = 0; i < 4; i++) { + sio2_setSend1(i, p->sendArray1[i]); + sio2_setSend2(i, p->sendArray2[i]); + } + + for(i = 0; i < 16; i++) + sio2_setSend3(i, p->sendArray3[i]); + + if (p->sendSize) { + _dprintf("sendBuf: "); + dumpbuf(p->sendBuf, p->sendSize); + + for(i = 0; i < p->sendSize; i++) { + *(u8 *) (0xBF808260) = p->sendBuf[i]; + } + } + + if(p->dmacAddress1 != 0) { + _dprintf("dmaAddress1=%x, dmacSize1=%x, dmacCount1=%x\n", p->dmacAddress1, p->dmacSize1, p->dmacCount1); + dumpbuf((u8*)p->dmacAddress1, p->dmacSize1*p->dmacCount1); + dmacSetDMA(DMAch_SIO2in, p->dmacAddress1, p->dmacSize1, p->dmacCount1, 1); // from memory + dmacStartTransfer(DMAch_SIO2in); + } + + if(p->dmacAddress2 != 0) { + dmacSetDMA(DMAch_SIO2out, p->dmacAddress2, p->dmacSize2, p->dmacCount2, 0); // to memory + dmacStartTransfer(DMAch_SIO2out); + } +} + +void sio2_recvPacket(struct sio2_packet *p) { + int i; + +// _dprintf("%s: recvSize=%d\n", __FUNCTION__, p->recvSize); + + p->recvVal1 = *(u32 *) (0xBF80826C); + p->recvVal2 = *(u32 *) (0xBF808270); + p->recvVal3 = *(u32 *) (0xBF808274); + + if (p->recvSize) { + _dprintf("recvBuf: "); + for(i = 0; i < p->recvSize; i++) { + p->recvBuf[i] = *(u8 *) (0xBF808264); + printf("%x, ", p->recvBuf[i]); + } + // printf("\n"); + } + + if (p->dmacAddress2 != 0) { + dumpbuf((u8*)p->dmacAddress2, p->dmacSize2*p->dmacCount2); + } +} + +void sio2_basicThread(void* data) { + unsigned long result[4]; + + //_dprintf("%s\n", __FUNCTION__); + + while(1) { + WaitEventFlag(common.evid, 0x5, 0x01, result); + + if (result[0] & 0x01) { + ClearEventFlag(common.evid, ~0x1); + SetEventFlag(common.evid, 0x02); + } else + if (result[0] & 0x04) { + ClearEventFlag(common.evid, ~0x4); + SetEventFlag(common.evid, 0x08); + } else { + printf("sio2MAN: Woke up for unknown event(%08X)!\n", result[0]); + return; + } + +// Wait for application to call our export 25 + WaitEventFlag(common.evid, 0x10, 0, NULL); + ClearEventFlag(common.evid, ~0x10); + + *(u32 *) (0xBF808268) = (*(u32 *) (0xBF808268)) | 0x0C; + sio2_sendPacket(packetAddr); + *(u32 *) (0xBF808268) = (*(u32 *) (0xBF808268)) | 0x01; + +// Wait for the sio2 interrupt to occur + WaitEventFlag(common.evid, 0x80, 0, NULL); + ClearEventFlag(common.evid, ~0x80); + +// Recieve the reply packet + sio2_recvPacket(packetAddr); + + SetEventFlag(common.evid, 0x20); + + WaitEventFlag(common.evid, 0x40, 0, NULL); + ClearEventFlag(common.evid, ~0x40); + } +} + +int sio2_createBasicThread(void) { + iop_thread_t param; + + param.attr = TH_C; + param.option = 0; + param.thread = &sio2_basicThread; + param.stacksize = 0x2000; + param.priority = 0x18; + + return(CreateThread(¶m)); +} + + +int sio2_interruptHandler(struct sio2common *c) { + sio2_setIntr(sio2_getIntr()); + + iSetEventFlag(c->evid, 0x80); + + return(1); +} + +// Export 0 +int sio2_init(void) { + u32 oldStat; + +// _dprintf("%s\n", __FUNCTION__); + + if(RegisterLibraryEntries(&sio2man_stub) != 0) { + //printf("sio2MAN: Unable to register library entries!\n"); + return(MODULE_NO_RESIDENT_END);//==1 + } + + if(sio2_initialized != 0) { + //printf("sio2MAN: Already initialized!\n"); + return(MODULE_NO_RESIDENT_END); + } + + sio2_initialized = 1; + + *(u32 *) (0xBF808268) = 0x3BC; + + common.evid = sio2_createEventFlag(); + common.thid = sio2_createBasicThread(); + + CpuSuspendIntr(&oldStat); + + RegisterIntrHandler(INUM_sio2, HTYPE_C, &sio2_interruptHandler, &common); + EnableIntr(INUM_sio2); + + CpuResumeIntr(oldStat); + + dmacSetVal(DMAch_SIO2in, 0x03); + dmacSetVal(DMAch_SIO2out, 0x03); + dmacEnableDMAch(DMAch_SIO2in); + dmacEnableDMAch(DMAch_SIO2out); + + StartThread(common.thid, 0); // Start the "basicThread" + + return MODULE_RESIDENT_END; +} + +void sio2_deInit(void) { + u32 oldStat; + +// _dprintf("%s\n", __FUNCTION__); + + CpuSuspendIntr(&oldStat); + + DisableIntr(INUM_sio2, 0); + ReleaseIntrHandler(INUM_sio2); + + CpuResumeIntr(oldStat); + + dmacDisableDMAch(DMAch_SIO2in); + dmacDisableDMAch(DMAch_SIO2out); +} + +void sio2_signalExchange1(void) { +// _dprintf("%s\n", __FUNCTION__); + +// Signal the basic thread to let it know we want to do an exchange. + SetEventFlag(common.evid, 0x01); +// Wait for basic thread to acknowledge then clear the flag. + WaitEventFlag(common.evid, 0x02, 0, NULL); + ClearEventFlag(common.evid, ~0x2); +} + +void sio2_signalExchange2(void) { +// _dprintf("%s\n", __FUNCTION__); + +// Signal the basic thread to let it know we want to do an exchange. + SetEventFlag(common.evid, 0x04); +// Wait for basic thread to acknowledge then clear the flag. + WaitEventFlag(common.evid, 0x08, 0, NULL); + ClearEventFlag(common.evid, ~0x8); +} + +int sio2_packetExchange(struct sio2_packet *packet) { +// _dprintf("%s: %x\n", __FUNCTION__, packet); + +// Set the address of the packet. + packetAddr = packet; + +// Let the basic thread know we have the address set for the exchange. + SetEventFlag(common.evid, 0x10); + +// Wait for the basic thread to finish it's stuff. + WaitEventFlag(common.evid, 0x20, 0, NULL); + ClearEventFlag(common.evid, ~0x20); + + SetEventFlag(common.evid, 0x40); + + return 1; +} + diff --git a/fps2bios/kernel/iopload/ssbusc/Makefile b/fps2bios/kernel/iopload/ssbusc/Makefile index 831351ae84..8622149571 100644 --- a/fps2bios/kernel/iopload/ssbusc/Makefile +++ b/fps2bios/kernel/iopload/ssbusc/Makefile @@ -1,59 +1,59 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include - -IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 -IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include -IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -IOPLINK = $(IOPLD) -dc -IOPASFLAGS := -EL -G0 - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: ssbusc - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -L$(PS2LIB)/iop/lib -LDADD = -OBJECTS = ssbusc.o ../iopdebug.o ../libkernel/iop_loadcore.o ../libkernel/iop_intrman.o - -ssbusc: $(OBJECTS) - $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/SSBUSC - -%.o: %.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - -%.o : %.s - $(IOPAS) $(IOPASFLAGS) $< -o $@ - -clean: - rm -f $(OBJECTS) - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: ssbusc + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib +LDADD = +OBJECTS = ssbusc.o ../iopdebug.o ../libkernel/iop_loadcore.o ../libkernel/iop_intrman.o + +ssbusc: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/SSBUSC + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/ssbusc/ssbusc.c b/fps2bios/kernel/iopload/ssbusc/ssbusc.c index 98ebfd0f5f..81d5964501 100644 --- a/fps2bios/kernel/iopload/ssbusc/ssbusc.c +++ b/fps2bios/kernel/iopload/ssbusc/ssbusc.c @@ -1,178 +1,178 @@ -//[module] SSBUSC -//[processor] IOP -//[type] ELF-IRX -//[name] ssbus_service -//[version] 0x101 -//[memory map] 0xBF801000,0xBF801004,0xBF801008,0xBF80100C, (r/w) -// MDECin(T2),8(T2) ,MDECin(T1),MDECout(T1), -// -// 0xBF801010,0xBF801014,0xBF801018,0xBF80101C,0xBF801020 (r/w) -// GPU(SIF2)(T1),SPU(T1)spu_delay,PIO(T1),8(T1),SSBUSCconfig -// -// 0xBF801400,0xBF801404,0xBF801408,0xBF80140C, (r/w) -// MDECout(T2),SPU(T2) ,PIO(T2) ,SIF0(T2), -// -// 0xBF801410,0xBF801414,0xBF801418,0xBF80141C,0xBF801420 (r/w) -// SIO2in(T2),SIF0(T1) ,SIF1(T1) ,SIO2in(T1),SIO2out(T1) -// -//[handlers] - -//[entry point] start, export_stub -//[made by] [RO]man (roman_ps2dev@hotmail.com) - -#include "kloadcore.h" -#include "kintrman.h" - -int memmap_table[]={ - 0xBF801008, 0xBF80100C, 0xBF801010, 0, 0xBF801014,//spu_delay - 0xBF801018, 0, 0, 0xBF80101C, 0xBF801414, - 0xBF801418, 0xBF80141C, 0xBF801420 -}; - -int memmap_table_2[]={ - 0xBF801000, 0xBF801400, 0, 0, 0xBF801404, - 0xBF801408, 0, 0, 0xBF801004, 0xBF80140C, - 0, 0xBF801410, 0 -}; - -int _start(); - -/////////////////////////////////////////////////////////////////////// -int return_0(){ - return 0; -} - -/////////////////////////////////////////////////////////////////////// -int SSBUSsetTable1(int code, int value){ //set - int *v; - if ((code < 13) && (v=(int*)memmap_table[code])) - return *v=value; - return -1; -} - -/////////////////////////////////////////////////////////////////////// -int SSBUSgetTable1(int code){ //get - int *v; - if ((code < 13) && (v=(int*)memmap_table[code])) - return *v; - return -1; -} - -/////////////////////////////////////////////////////////////////////// -int SSBUSsetTable2(int code, int value){ //set - int *v; - if ((code < 13) && (v=(int*)memmap_table_2[code])) - return *v=value; - return -1; -} - -/////////////////////////////////////////////////////////////////////// -int SSBUSgetTable2(int code){ //get - int *v; - if ((code < 13) && (v=(int*)memmap_table_2[code])) - return *v; - return -1; -} - -/////////////////////////////////////////////////////////////////////// -int SSBUSsetCOM_DELAY_1st(int a){ //set lowest nibble - return *(int*)(0xBF801020) = - (*(int*)(0xBF801020) & 0xFFFFFFF0) | - ( a & 0xF); -} - -/////////////////////////////////////////////////////////////////////// -int SSBUSgetCOM_DELAY_1st(){ //get lowest nibble - return *(int*)(0xBF801020) & 0xF; -} - -/////////////////////////////////////////////////////////////////////// -int SSBUSsetCOM_DELAY_2nd(int a){ //set - return *(int*)(0xBF801020) = - (*(int*)(0xBF801020) & 0xFFFFFF0F) | - ( (a << 4) & 0xF0); -} - -/////////////////////////////////////////////////////////////////////// -int SSBUSgetCOM_DELAY_2nd(){ //get - return *(unsigned char*)(0xBF801020) >> 4; -} - -/////////////////////////////////////////////////////////////////////// -int SSBUSsetCOM_DELAY_3rd(int a){ //set - return *(int*)(0xBF801020) = - (*(int*)(0xBF801020) & 0xFFFFF0FF) | - ( (a << 8) & 0xF00); -} - -/////////////////////////////////////////////////////////////////////// -int SSBUSgetCOM_DELAY_3rd(){ //get - return (*(int*)(0xBF801020) >> 8) & 0xF; -} - -/////////////////////////////////////////////////////////////////////// -int SSBUSsetCOM_DELAY_4th(int a){ //set - return *(int*)(0xBF801020) = - (*(int*)(0xBF801020) & 0xFFFF0FFF) | - ( (a << 12) & 0xF000); -} - -/////////////////////////////////////////////////////////////////////// -int SSBUSgetCOM_DELAY_4th(){ //get - return (*(int*)(0xBF801020) >> 12) & 0xF; -} - -/////////////////////////////////////////////////////////////////////// -int SSBUSsetCOM_DELAY(int a){ //set - return *(int*)(0xBF801020) = a; -} - -/////////////////////////////////////////////////////////////////////// -int SSBUSgetCOM_DELAY(){ //get - return *(int*)(0xBF801020); -} - -/////////////////////////////////////////////////////////////////////// -void retonly(){} - -//////////////////////////////entrypoint/////////////////////////////// -struct export export_stub={ - 0x41C00000, - 0, - VER(1, 1), // 1.1 => 0x101 - 0, - "ssbusc", - (func)_start, // entrypoint - (func)retonly, - (func)return_0, - (func)retonly, - (func)SSBUSsetTable1, - (func)SSBUSgetTable1, - (func)SSBUSsetTable2, - (func)SSBUSgetTable2, - (func)SSBUSsetCOM_DELAY_1st, - (func)SSBUSgetCOM_DELAY_1st, - (func)SSBUSsetCOM_DELAY_2nd, - (func)SSBUSgetCOM_DELAY_2nd, - (func)SSBUSsetCOM_DELAY_3rd, - (func)SSBUSgetCOM_DELAY_3rd, - (func)SSBUSsetCOM_DELAY_4th, - (func)SSBUSgetCOM_DELAY_4th, - (func)SSBUSsetCOM_DELAY, - (func)SSBUSgetCOM_DELAY, - 0 // end of list -}; - -//////////////////////////////entrypoint/////////////////////////////// -int _start(int argc, char* argv[]){ - int x; - - CpuSuspendIntr(&x); - if (RegisterLibraryEntries(&export_stub)==0) { - CpuResumeIntr(x); - return 0; - } - - CpuResumeIntr(x); - return 1; -} - +//[module] SSBUSC +//[processor] IOP +//[type] ELF-IRX +//[name] ssbus_service +//[version] 0x101 +//[memory map] 0xBF801000,0xBF801004,0xBF801008,0xBF80100C, (r/w) +// MDECin(T2),8(T2) ,MDECin(T1),MDECout(T1), +// +// 0xBF801010,0xBF801014,0xBF801018,0xBF80101C,0xBF801020 (r/w) +// GPU(SIF2)(T1),SPU(T1)spu_delay,PIO(T1),8(T1),SSBUSCconfig +// +// 0xBF801400,0xBF801404,0xBF801408,0xBF80140C, (r/w) +// MDECout(T2),SPU(T2) ,PIO(T2) ,SIF0(T2), +// +// 0xBF801410,0xBF801414,0xBF801418,0xBF80141C,0xBF801420 (r/w) +// SIO2in(T2),SIF0(T1) ,SIF1(T1) ,SIO2in(T1),SIO2out(T1) +// +//[handlers] - +//[entry point] start, export_stub +//[made by] [RO]man (roman_ps2dev@hotmail.com) + +#include "kloadcore.h" +#include "kintrman.h" + +int memmap_table[]={ + 0xBF801008, 0xBF80100C, 0xBF801010, 0, 0xBF801014,//spu_delay + 0xBF801018, 0, 0, 0xBF80101C, 0xBF801414, + 0xBF801418, 0xBF80141C, 0xBF801420 +}; + +int memmap_table_2[]={ + 0xBF801000, 0xBF801400, 0, 0, 0xBF801404, + 0xBF801408, 0, 0, 0xBF801004, 0xBF80140C, + 0, 0xBF801410, 0 +}; + +int _start(); + +/////////////////////////////////////////////////////////////////////// +int return_0(){ + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSsetTable1(int code, int value){ //set + int *v; + if ((code < 13) && (v=(int*)memmap_table[code])) + return *v=value; + return -1; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSgetTable1(int code){ //get + int *v; + if ((code < 13) && (v=(int*)memmap_table[code])) + return *v; + return -1; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSsetTable2(int code, int value){ //set + int *v; + if ((code < 13) && (v=(int*)memmap_table_2[code])) + return *v=value; + return -1; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSgetTable2(int code){ //get + int *v; + if ((code < 13) && (v=(int*)memmap_table_2[code])) + return *v; + return -1; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSsetCOM_DELAY_1st(int a){ //set lowest nibble + return *(int*)(0xBF801020) = + (*(int*)(0xBF801020) & 0xFFFFFFF0) | + ( a & 0xF); +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSgetCOM_DELAY_1st(){ //get lowest nibble + return *(int*)(0xBF801020) & 0xF; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSsetCOM_DELAY_2nd(int a){ //set + return *(int*)(0xBF801020) = + (*(int*)(0xBF801020) & 0xFFFFFF0F) | + ( (a << 4) & 0xF0); +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSgetCOM_DELAY_2nd(){ //get + return *(unsigned char*)(0xBF801020) >> 4; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSsetCOM_DELAY_3rd(int a){ //set + return *(int*)(0xBF801020) = + (*(int*)(0xBF801020) & 0xFFFFF0FF) | + ( (a << 8) & 0xF00); +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSgetCOM_DELAY_3rd(){ //get + return (*(int*)(0xBF801020) >> 8) & 0xF; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSsetCOM_DELAY_4th(int a){ //set + return *(int*)(0xBF801020) = + (*(int*)(0xBF801020) & 0xFFFF0FFF) | + ( (a << 12) & 0xF000); +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSgetCOM_DELAY_4th(){ //get + return (*(int*)(0xBF801020) >> 12) & 0xF; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSsetCOM_DELAY(int a){ //set + return *(int*)(0xBF801020) = a; +} + +/////////////////////////////////////////////////////////////////////// +int SSBUSgetCOM_DELAY(){ //get + return *(int*)(0xBF801020); +} + +/////////////////////////////////////////////////////////////////////// +void retonly(){} + +//////////////////////////////entrypoint/////////////////////////////// +struct export export_stub={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "ssbusc", + (func)_start, // entrypoint + (func)retonly, + (func)return_0, + (func)retonly, + (func)SSBUSsetTable1, + (func)SSBUSgetTable1, + (func)SSBUSsetTable2, + (func)SSBUSgetTable2, + (func)SSBUSsetCOM_DELAY_1st, + (func)SSBUSgetCOM_DELAY_1st, + (func)SSBUSsetCOM_DELAY_2nd, + (func)SSBUSgetCOM_DELAY_2nd, + (func)SSBUSsetCOM_DELAY_3rd, + (func)SSBUSgetCOM_DELAY_3rd, + (func)SSBUSsetCOM_DELAY_4th, + (func)SSBUSgetCOM_DELAY_4th, + (func)SSBUSsetCOM_DELAY, + (func)SSBUSgetCOM_DELAY, + 0 // end of list +}; + +//////////////////////////////entrypoint/////////////////////////////// +int _start(int argc, char* argv[]){ + int x; + + CpuSuspendIntr(&x); + if (RegisterLibraryEntries(&export_stub)==0) { + CpuResumeIntr(x); + return 0; + } + + CpuResumeIntr(x); + return 1; +} + diff --git a/fps2bios/kernel/iopload/stdio/Makefile b/fps2bios/kernel/iopload/stdio/Makefile index d457ca18af..bc64e5b8ac 100644 --- a/fps2bios/kernel/iopload/stdio/Makefile +++ b/fps2bios/kernel/iopload/stdio/Makefile @@ -1,58 +1,58 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include - -IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 -IOPINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(NEWLIB)/include #-I$(PS2LIB)/iop/include -IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -IOPLINK = $(IOPLD) -dc -nostartfiles - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: stdio - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib -LDADD = -OBJECTS = stdio.o - -stdio: $(OBJECTS) - $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/STDIO - -%.o: %.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - - -clean: - rm -f $(OBJECTS) - - - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(NEWLIB)/include #-I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc -nostartfiles + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: stdio + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib +LDADD = +OBJECTS = stdio.o + +stdio: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/STDIO + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + + +clean: + rm -f $(OBJECTS) + + + diff --git a/fps2bios/kernel/iopload/stdio/stdio.c b/fps2bios/kernel/iopload/stdio/stdio.c index dcbc7a9f20..36feefe9cb 100644 --- a/fps2bios/kernel/iopload/stdio/stdio.c +++ b/fps2bios/kernel/iopload/stdio/stdio.c @@ -1,40 +1,40 @@ - -#include -//#include - -void Kputc(u8 c) { - *((u8*)0x1f80380c) = c; -} - -void Kputs(u8 *s) { - while (*s != 0) { - Kputc(*s++); - } -} - -void Kmemcpy(void *dest, const void *src, int n) { - const u8 *s = (u8*)src; - u8 *d = (u8*)dest; - - while (n) { - *d++ = *s++; n--; - } -} -/* -int Kprintf(const char *format, ...) { - char buf[4096]; - va_list args; - int ret; - - va_start(args, format); - ret = vsnprintf(buf, 4096, format, args); - va_end(args); - - Kputs(buf); - return ret; -} -*/ -void _start() { - Kputs("STDIO start\n"); -} - + +#include +//#include + +void Kputc(u8 c) { + *((u8*)0x1f80380c) = c; +} + +void Kputs(u8 *s) { + while (*s != 0) { + Kputc(*s++); + } +} + +void Kmemcpy(void *dest, const void *src, int n) { + const u8 *s = (u8*)src; + u8 *d = (u8*)dest; + + while (n) { + *d++ = *s++; n--; + } +} +/* +int Kprintf(const char *format, ...) { + char buf[4096]; + va_list args; + int ret; + + va_start(args, format); + ret = vsnprintf(buf, 4096, format, args); + va_end(args); + + Kputs(buf); + return ret; +} +*/ +void _start() { + Kputs("STDIO start\n"); +} + diff --git a/fps2bios/kernel/iopload/sysclib/Makefile b/fps2bios/kernel/iopload/sysclib/Makefile index 2b9a33b90a..7c8591eb35 100644 --- a/fps2bios/kernel/iopload/sysclib/Makefile +++ b/fps2bios/kernel/iopload/sysclib/Makefile @@ -1,59 +1,59 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include - -IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 -IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include -IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -IOPLINK = $(IOPLD) -dc -IOPASFLAGS := -EL -G0 - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: sysclib - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -L$(PS2LIB)/iop/lib -LDADD = -OBJECTS = sysclib.o ../iopdebug.o ../libkernel/iop_loadcore.o - -sysclib: $(OBJECTS) - $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/SYSCLIB - -%.o: %.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - -%.o : %.s - $(IOPAS) $(IOPASFLAGS) $< -o $@ - -clean: - rm -f $(OBJECTS) - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: sysclib + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib +LDADD = +OBJECTS = sysclib.o ../iopdebug.o ../libkernel/iop_loadcore.o + +sysclib: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/SYSCLIB + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/sysclib/sysclib.c b/fps2bios/kernel/iopload/sysclib/sysclib.c index 75df9819df..91b6bbb741 100644 --- a/fps2bios/kernel/iopload/sysclib/sysclib.c +++ b/fps2bios/kernel/iopload/sysclib/sysclib.c @@ -1,583 +1,583 @@ -#include -#include -#include -#include - -#include "kloadcore.h" -#include "stdarg.h" -#include "ksysclib.h" - - -typedef struct _jmp_buf{ - int ra, - sp, - fp, - s0, - s1, - s2, - s3, - s4, - s5, - s6, - s7, - gp; -} *jmp_buf; - -int _start(int argc, char* argv[]); - - -unsigned char ctype_table[128]={ - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x08, 0x08, 0x08, 0x08, 0x08, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - - 0x18, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - - 0x10, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x10, 0x10, 0x10, 0x10, 0x10, - - 0x10, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x10, 0x10, 0x10, 0x10, 0x20 -}; - -int setjmp (jmp_buf jb){ - asm __volatile__( - "sw $31, 0($4)\n" //$ra, JUMP_BUFFER.ra($a0) - "sw $28, 4($4)\n" //$gp, JUMP_BUFFER.gp($a0) - "sw $29, 8($4)\n" //$sp, JUMP_BUFFER.sp($a0) - "sw $30, 12($4)\n" //$fp, JUMP_BUFFER.fp($a0) - "sw $16, 16($4)\n" //$s0, JUMP_BUFFER.s0($a0) - "sw $17, 20($4)\n" //$s1, JUMP_BUFFER.s1($a0) - "sw $18, 24($4)\n" //$s2, JUMP_BUFFER.s2($a0) - "sw $19, 28($4)\n" //$s3, JUMP_BUFFER.s3($a0) - "sw $20, 32($4)\n" //$s4, JUMP_BUFFER.s4($a0) - "sw $21, 36($4)\n" //$s5, JUMP_BUFFER.s5($a0) - "sw $22, 40($4)\n" //$s6, JUMP_BUFFER.s6($a0) - "sw $23, 44($4)\n" //$s7, JUMP_BUFFER.s7($a0) - ); - return 0; -} - -int longjmp(void *jb, int u){ - asm __volatile__( - "lw $31, 0($4)\n" //$ra, JUMP_BUFFER.ra($a0) - "lw $28, 4($4)\n" //$gp, JUMP_BUFFER.gp($a0) - "lw $29, 8($4)\n" //$sp, JUMP_BUFFER.sp($a0) - "lw $30, 12($4)\n" //$fp, JUMP_BUFFER.fp($a0) - "lw $16, 16($4)\n" //$s0, JUMP_BUFFER.s0($a0) - "lw $17, 20($4)\n" //$s1, JUMP_BUFFER.s1($a0) - "lw $18, 24($4)\n" //$s2, JUMP_BUFFER.s2($a0) - "lw $19, 28($4)\n" //$s3, JUMP_BUFFER.s3($a0) - "lw $20, 32($4)\n" //$s4, JUMP_BUFFER.s4($a0) - "lw $21, 36($4)\n" //$s5, JUMP_BUFFER.s5($a0) - "lw $22, 40($4)\n" //$s6, JUMP_BUFFER.s6($a0) - "lw $23, 44($4)\n" //$s7, JUMP_BUFFER.s7($a0) - ); - return u; -} - -#define CHAR(a) (((a)<<24)>>24) -unsigned char look_ctype_table(int); - -int toupper (int ch){ - if (look_ctype_table(CHAR(ch)) & 0x0002) - return CHAR(ch-32); - return CHAR(ch); -} - -int tolower (int ch){ - if (look_ctype_table(CHAR(ch)) & 0x0001) - return CHAR(ch+32); - return CHAR(ch); -} - -unsigned char look_ctype_table(int pos){ - return ctype_table[pos]; -} - -void* get_ctype_table(){ - return ctype_table; -} - -void* memchr(void *s, int ch, int len){ - if (s && len>0) { - ch &= 0xFF; - do { - if (*(unsigned char*)s == ch) - return s; - } while(s++, --len>0); - - } - return NULL; -} - -int memcmp(const void *a, const void *b, size_t len){ - if (len == 0) return 0; - - do { - if (*(unsigned char*)a != *(unsigned char*)b) { - if (*(unsigned char*)a < *(unsigned char*)b) return 1; - else return -1; - } - } while (a++, b++, --len>0); - - return 0; -} - -void* memcpy(void *dest, const void *src, size_t len){ - void *temp; - - if (dest == NULL) return NULL; - -// if (((int)dest | (int)src | len) & 3 == 0) -// return wmemcopy(dest, src, len); - for(temp=dest; len>0; len--) - *(unsigned char*)temp++ = *(unsigned char*)src++; - return dest; -} - -void *memmove (void *dest, const void *src, size_t len){ - void *temp; - - if (dest==NULL) return NULL; - - temp=dest; - if (dest>=src) - for (len--; len>=0; len--) - *(unsigned char*)(temp+len)=*(unsigned char*)(src+len); - else - for ( ; len>0; len--) - *(unsigned char*)temp++ =*(unsigned char*)src++; - return dest; -} - -void *memset (void *dest, int ch, size_t len){ - void *temp; - - if (dest == NULL) return NULL; - -/* if ((ch==0) && (((int)dest | len) & 3 == 0)) - return wmemset(dest, 0, len); - else -*/ for (temp=dest; len>0; len--) - *(unsigned char*)temp++ = ch; - return dest; -} - -int bcmp (const void *a, const void *b, size_t len){ - return memcmp(a, b, len); -} - -void bcopy (const void *src, void *dest, size_t len){ - memmove(dest, src, len); -} - -void bzero (void *dest, size_t len){ - memset(dest, 0, len); -} - -char *strcat(char *dest, const char *src) { - char *s = dest; - - while (*dest) dest++; - while (*dest++ = *src++); - - return s; -} - -char *strncat(char *dest, const char *src, size_t n) { - char *s = dest; - - while (*dest) dest++; - while (n-- > 0 && (*dest++ = *src++)); - *dest = '\0'; - - return s; -} - -char *strchr(const char *s, int c) { - unsigned char _c = (unsigned int)c; - - while (*s && *s != c) s++; - if (*s != c) s = NULL; - - return (char *)s; -} - -char *strrchr(const char *s, int c) { - const char *last = NULL; - - if (c) { - while (s = strchr(s, c)) { - last = s++; - } - } else { - last = strchr(s, c); - } - - return (char *)last; -} - -int strcmp(const char *s1, const char *s2) { - while (*s1 != '\0' && *s1 == *s2) { - s1++; s2++; - } - - return (*(unsigned char *)s1) - (*(unsigned char *)s2); -} - -int strncmp(const char *s1, const char *s2, size_t n) { - if (n == 0) return 0; - - while (n-- != 0 && *s1 == *s2) { - if (n == 0 || *s1 == '\0') break; - s1++; s2++; - } - - return (*(unsigned char *)s1) - (*(unsigned char *)s2); -} - -char *strcpy(char *dest, const char *src) { - char *s = dest; - - while (*dest++ = *src++); - - return s; -} - -char *strncpy(char *dest, const char *src, size_t n) { - char *s = dest; - - while (*dest++ = *src++); - - return s; -} - -size_t strspn(const char *s, const char *accept) { - const char *_s = s; - const char *c; - - while (*s) { - for (c = accept; *c; c++) { - if (*s == *c) break; - } - if (*c == '\0') break; - s++; - } - - return s - _s; -} - -size_t strcspn(const char *s, const char *reject) { - const char *_s = s; - const char *c; - - while (*s) { - for (c = reject; *c; c++) { - if (*s == *c) break; - } - if (*c) break; - s++; - } - - return s - _s; -} - -char *index(const char *s, int c) { - return strchr(s, c); -} - -char *rindex(const char *s, int c) { - return strrchr(s, c); -} - -size_t strlen(const char *s) { - const char *start = s; - - while (*s) s++; - - return s - start; -} - -char *strpbrk(const char *s, const char *accept) { - const char *c = accept; - - if (!*s) return NULL; - - while (*s) { - for (c = accept; *c; c++) { - if (*s == *c) break; - } - if (*c) break; - s++; - } - - if (*c == '\0') s = NULL; - - return (char *)s; -} - -char *strstr(const char *haystack, const char *needle) { - if (*haystack == 0) { - if (*needle) return (char *) NULL; - return (char *) haystack; - } - - while (*haystack) { - size_t i; - i = 0; - - for (;;) { - if (needle[i] == 0) { - return (char *) haystack; - } - - if (needle[i] != haystack[i]) break; - i++; - } - haystack++; - } - - return (char *) NULL; -} - -#define _CTYPE_DATA_0_127 \ - _C, _C, _C, _C, _C, _C, _C, _C, \ - _C, _C|_S, _C|_S, _C|_S, _C|_S, _C|_S, _C, _C, \ - _C, _C, _C, _C, _C, _C, _C, _C, \ - _C, _C, _C, _C, _C, _C, _C, _C, \ - _S|_B, _P, _P, _P, _P, _P, _P, _P, \ - _P, _P, _P, _P, _P, _P, _P, _P, \ - _N, _N, _N, _N, _N, _N, _N, _N, \ - _N, _N, _P, _P, _P, _P, _P, _P, \ - _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U, \ - _U, _U, _U, _U, _U, _U, _U, _U, \ - _U, _U, _U, _U, _U, _U, _U, _U, \ - _U, _U, _U, _P, _P, _P, _P, _P, \ - _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L, \ - _L, _L, _L, _L, _L, _L, _L, _L, \ - _L, _L, _L, _L, _L, _L, _L, _L, \ - _L, _L, _L, _P, _P, _P, _P, _C - -#define _CTYPE_DATA_128_256 \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0 - - -const char _ctype_[1 + 256] = { - 0, - _CTYPE_DATA_0_127, - _CTYPE_DATA_128_256 -}; - -char *strtok(char *s, const char *delim) { -} - -long _strtol_r(const char *nptr, char **endptr, int base) { - register const char *s = nptr; - register unsigned long acc; - register int c; - register unsigned long cutoff; - register int neg = 0, any, cutlim; - - /* - * Skip white space and pick up leading +/- sign if any. - * If base is 0, allow 0x for hex and 0 for octal, else - * assume decimal; if base is already 16, allow 0x. - */ - do { - c = *s++; - } while (isspace(c)); - if (c == '-') { - neg = 1; - c = *s++; - } else if (c == '+') - c = *s++; - if ((base == 0 || base == 16) && - c == '0' && (*s == 'x' || *s == 'X')) { - c = s[1]; - s += 2; - base = 16; - } - if (base == 0) - base = c == '0' ? 8 : 10; - - /* - * Compute the cutoff value between legal numbers and illegal - * numbers. That is the largest legal value, divided by the - * base. An input number that is greater than this value, if - * followed by a legal input character, is too big. One that - * is equal to this value may be valid or not; the limit - * between valid and invalid numbers is then based on the last - * digit. For instance, if the range for longs is - * [-2147483648..2147483647] and the input base is 10, - * cutoff will be set to 214748364 and cutlim to either - * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated - * a value > 214748364, or equal but the next digit is > 7 (or 8), - * the number is too big, and we will return a range error. - * - * Set any if any `digits' consumed; make it negative to indicate - * overflow. - */ - cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; - cutlim = cutoff % (unsigned long)base; - cutoff /= (unsigned long)base; - for (acc = 0, any = 0;; c = *s++) { - if (isdigit(c)) - c -= '0'; - else if (isalpha(c)) - c -= isupper(c) ? 'A' - 10 : 'a' - 10; - else - break; - if (c >= base) - break; - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - any = -1; - else { - any = 1; - acc *= base; - acc += c; - } - } - if (any < 0) { - acc = neg ? LONG_MIN : LONG_MAX; -// rptr->_errno = ERANGE; - } else if (neg) - acc = -acc; - if (endptr != 0) - *endptr = (char *) (any ? s - 1 : nptr); - return (acc); -} - -long int strtol(const char *nptr, char **endptr, int base) { - return _strtol_r (nptr, endptr, base); -} - -unsigned long int strtoul(const char *nptr, char **endptr, int base) { -} - -void atob() { -} - -wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, size_t n) { -} - -wchar_t *wmemset(wchar_t *wcs, wchar_t wc, size_t n) { -} - -void prnt() { -} - -int sprintf(char *str, const char *format, ...) { -} - -int vsprintf(char *str, const char *format, va_list ap) { -} - - - - -/////////////////////////////////////////////////////////////////////// -void _retonly(){} - -struct export sysclib_stub={ - 0x41C00000, - 0, - VER(1, 1), // 1.1 => 0x101 - 0, - "sysclib", - (func)_start, // entrypoint - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)setjmp, - (func)longjmp, - (func)toupper, - (func)tolower, - (func)look_ctype_table, - (func)get_ctype_table, - (func)memchr, - (func)memcmp, - (func)memcpy, - (func)memmove, - (func)memset, - (func)bcmp, - (func)bcopy, - (func)bzero, - (func)prnt, - (func)sprintf, - (func)strcat, - (func)strchr, - (func)strcmp, - (func)strcpy, - (func)strcspn, - (func)index, - (func)rindex, - (func)strlen, - (func)strncat, - (func)strncmp, - (func)strncpy, - (func)strpbrk, - (func)strrchr, - (func)strspn, - (func)strstr, - (func)strtok, - (func)strtol, - (func)atob, - (func)strtoul, - (func)wmemcpy, - (func)wmemset, - (func)vsprintf, - 0 -}; - -struct export stdio_stub={ - 0x41C00000, - 0, - VER(1, 2), // 1.2 => 0x102 - 0, - "stdio", - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, -}; - -//////////////////////////////entrypoint/////////////////////////////// -int _start(int argc, char* argv[]){ - int ret = RegisterLibraryEntries(&sysclib_stub); - return RegisterLibraryEntries(&stdio_stub) + ret; -} - +#include +#include +#include +#include + +#include "kloadcore.h" +#include "stdarg.h" +#include "ksysclib.h" + + +typedef struct _jmp_buf{ + int ra, + sp, + fp, + s0, + s1, + s2, + s3, + s4, + s5, + s6, + s7, + gp; +} *jmp_buf; + +int _start(int argc, char* argv[]); + + +unsigned char ctype_table[128]={ + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x08, 0x08, 0x08, 0x08, 0x08, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + + 0x18, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + + 0x10, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x10, 0x10, 0x10, 0x10, 0x10, + + 0x10, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x10, 0x10, 0x10, 0x10, 0x20 +}; + +int setjmp (jmp_buf jb){ + asm __volatile__( + "sw $31, 0($4)\n" //$ra, JUMP_BUFFER.ra($a0) + "sw $28, 4($4)\n" //$gp, JUMP_BUFFER.gp($a0) + "sw $29, 8($4)\n" //$sp, JUMP_BUFFER.sp($a0) + "sw $30, 12($4)\n" //$fp, JUMP_BUFFER.fp($a0) + "sw $16, 16($4)\n" //$s0, JUMP_BUFFER.s0($a0) + "sw $17, 20($4)\n" //$s1, JUMP_BUFFER.s1($a0) + "sw $18, 24($4)\n" //$s2, JUMP_BUFFER.s2($a0) + "sw $19, 28($4)\n" //$s3, JUMP_BUFFER.s3($a0) + "sw $20, 32($4)\n" //$s4, JUMP_BUFFER.s4($a0) + "sw $21, 36($4)\n" //$s5, JUMP_BUFFER.s5($a0) + "sw $22, 40($4)\n" //$s6, JUMP_BUFFER.s6($a0) + "sw $23, 44($4)\n" //$s7, JUMP_BUFFER.s7($a0) + ); + return 0; +} + +int longjmp(void *jb, int u){ + asm __volatile__( + "lw $31, 0($4)\n" //$ra, JUMP_BUFFER.ra($a0) + "lw $28, 4($4)\n" //$gp, JUMP_BUFFER.gp($a0) + "lw $29, 8($4)\n" //$sp, JUMP_BUFFER.sp($a0) + "lw $30, 12($4)\n" //$fp, JUMP_BUFFER.fp($a0) + "lw $16, 16($4)\n" //$s0, JUMP_BUFFER.s0($a0) + "lw $17, 20($4)\n" //$s1, JUMP_BUFFER.s1($a0) + "lw $18, 24($4)\n" //$s2, JUMP_BUFFER.s2($a0) + "lw $19, 28($4)\n" //$s3, JUMP_BUFFER.s3($a0) + "lw $20, 32($4)\n" //$s4, JUMP_BUFFER.s4($a0) + "lw $21, 36($4)\n" //$s5, JUMP_BUFFER.s5($a0) + "lw $22, 40($4)\n" //$s6, JUMP_BUFFER.s6($a0) + "lw $23, 44($4)\n" //$s7, JUMP_BUFFER.s7($a0) + ); + return u; +} + +#define CHAR(a) (((a)<<24)>>24) +unsigned char look_ctype_table(int); + +int toupper (int ch){ + if (look_ctype_table(CHAR(ch)) & 0x0002) + return CHAR(ch-32); + return CHAR(ch); +} + +int tolower (int ch){ + if (look_ctype_table(CHAR(ch)) & 0x0001) + return CHAR(ch+32); + return CHAR(ch); +} + +unsigned char look_ctype_table(int pos){ + return ctype_table[pos]; +} + +void* get_ctype_table(){ + return ctype_table; +} + +void* memchr(void *s, int ch, int len){ + if (s && len>0) { + ch &= 0xFF; + do { + if (*(unsigned char*)s == ch) + return s; + } while(s++, --len>0); + + } + return NULL; +} + +int memcmp(const void *a, const void *b, size_t len){ + if (len == 0) return 0; + + do { + if (*(unsigned char*)a != *(unsigned char*)b) { + if (*(unsigned char*)a < *(unsigned char*)b) return 1; + else return -1; + } + } while (a++, b++, --len>0); + + return 0; +} + +void* memcpy(void *dest, const void *src, size_t len){ + void *temp; + + if (dest == NULL) return NULL; + +// if (((int)dest | (int)src | len) & 3 == 0) +// return wmemcopy(dest, src, len); + for(temp=dest; len>0; len--) + *(unsigned char*)temp++ = *(unsigned char*)src++; + return dest; +} + +void *memmove (void *dest, const void *src, size_t len){ + void *temp; + + if (dest==NULL) return NULL; + + temp=dest; + if (dest>=src) + for (len--; len>=0; len--) + *(unsigned char*)(temp+len)=*(unsigned char*)(src+len); + else + for ( ; len>0; len--) + *(unsigned char*)temp++ =*(unsigned char*)src++; + return dest; +} + +void *memset (void *dest, int ch, size_t len){ + void *temp; + + if (dest == NULL) return NULL; + +/* if ((ch==0) && (((int)dest | len) & 3 == 0)) + return wmemset(dest, 0, len); + else +*/ for (temp=dest; len>0; len--) + *(unsigned char*)temp++ = ch; + return dest; +} + +int bcmp (const void *a, const void *b, size_t len){ + return memcmp(a, b, len); +} + +void bcopy (const void *src, void *dest, size_t len){ + memmove(dest, src, len); +} + +void bzero (void *dest, size_t len){ + memset(dest, 0, len); +} + +char *strcat(char *dest, const char *src) { + char *s = dest; + + while (*dest) dest++; + while (*dest++ = *src++); + + return s; +} + +char *strncat(char *dest, const char *src, size_t n) { + char *s = dest; + + while (*dest) dest++; + while (n-- > 0 && (*dest++ = *src++)); + *dest = '\0'; + + return s; +} + +char *strchr(const char *s, int c) { + unsigned char _c = (unsigned int)c; + + while (*s && *s != c) s++; + if (*s != c) s = NULL; + + return (char *)s; +} + +char *strrchr(const char *s, int c) { + const char *last = NULL; + + if (c) { + while (s = strchr(s, c)) { + last = s++; + } + } else { + last = strchr(s, c); + } + + return (char *)last; +} + +int strcmp(const char *s1, const char *s2) { + while (*s1 != '\0' && *s1 == *s2) { + s1++; s2++; + } + + return (*(unsigned char *)s1) - (*(unsigned char *)s2); +} + +int strncmp(const char *s1, const char *s2, size_t n) { + if (n == 0) return 0; + + while (n-- != 0 && *s1 == *s2) { + if (n == 0 || *s1 == '\0') break; + s1++; s2++; + } + + return (*(unsigned char *)s1) - (*(unsigned char *)s2); +} + +char *strcpy(char *dest, const char *src) { + char *s = dest; + + while (*dest++ = *src++); + + return s; +} + +char *strncpy(char *dest, const char *src, size_t n) { + char *s = dest; + + while (*dest++ = *src++); + + return s; +} + +size_t strspn(const char *s, const char *accept) { + const char *_s = s; + const char *c; + + while (*s) { + for (c = accept; *c; c++) { + if (*s == *c) break; + } + if (*c == '\0') break; + s++; + } + + return s - _s; +} + +size_t strcspn(const char *s, const char *reject) { + const char *_s = s; + const char *c; + + while (*s) { + for (c = reject; *c; c++) { + if (*s == *c) break; + } + if (*c) break; + s++; + } + + return s - _s; +} + +char *index(const char *s, int c) { + return strchr(s, c); +} + +char *rindex(const char *s, int c) { + return strrchr(s, c); +} + +size_t strlen(const char *s) { + const char *start = s; + + while (*s) s++; + + return s - start; +} + +char *strpbrk(const char *s, const char *accept) { + const char *c = accept; + + if (!*s) return NULL; + + while (*s) { + for (c = accept; *c; c++) { + if (*s == *c) break; + } + if (*c) break; + s++; + } + + if (*c == '\0') s = NULL; + + return (char *)s; +} + +char *strstr(const char *haystack, const char *needle) { + if (*haystack == 0) { + if (*needle) return (char *) NULL; + return (char *) haystack; + } + + while (*haystack) { + size_t i; + i = 0; + + for (;;) { + if (needle[i] == 0) { + return (char *) haystack; + } + + if (needle[i] != haystack[i]) break; + i++; + } + haystack++; + } + + return (char *) NULL; +} + +#define _CTYPE_DATA_0_127 \ + _C, _C, _C, _C, _C, _C, _C, _C, \ + _C, _C|_S, _C|_S, _C|_S, _C|_S, _C|_S, _C, _C, \ + _C, _C, _C, _C, _C, _C, _C, _C, \ + _C, _C, _C, _C, _C, _C, _C, _C, \ + _S|_B, _P, _P, _P, _P, _P, _P, _P, \ + _P, _P, _P, _P, _P, _P, _P, _P, \ + _N, _N, _N, _N, _N, _N, _N, _N, \ + _N, _N, _P, _P, _P, _P, _P, _P, \ + _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U, \ + _U, _U, _U, _U, _U, _U, _U, _U, \ + _U, _U, _U, _U, _U, _U, _U, _U, \ + _U, _U, _U, _P, _P, _P, _P, _P, \ + _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L, \ + _L, _L, _L, _L, _L, _L, _L, _L, \ + _L, _L, _L, _L, _L, _L, _L, _L, \ + _L, _L, _L, _P, _P, _P, _P, _C + +#define _CTYPE_DATA_128_256 \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0 + + +const char _ctype_[1 + 256] = { + 0, + _CTYPE_DATA_0_127, + _CTYPE_DATA_128_256 +}; + +char *strtok(char *s, const char *delim) { +} + +long _strtol_r(const char *nptr, char **endptr, int base) { + register const char *s = nptr; + register unsigned long acc; + register int c; + register unsigned long cutoff; + register int neg = 0, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for longs is + * [-2147483648..2147483647] and the input base is 10, + * cutoff will be set to 214748364 and cutlim to either + * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated + * a value > 214748364, or equal but the next digit is > 7 (or 8), + * the number is too big, and we will return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; + cutlim = cutoff % (unsigned long)base; + cutoff /= (unsigned long)base; + for (acc = 0, any = 0;; c = *s++) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = neg ? LONG_MIN : LONG_MAX; +// rptr->_errno = ERANGE; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} + +long int strtol(const char *nptr, char **endptr, int base) { + return _strtol_r (nptr, endptr, base); +} + +unsigned long int strtoul(const char *nptr, char **endptr, int base) { +} + +void atob() { +} + +wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, size_t n) { +} + +wchar_t *wmemset(wchar_t *wcs, wchar_t wc, size_t n) { +} + +void prnt() { +} + +int sprintf(char *str, const char *format, ...) { +} + +int vsprintf(char *str, const char *format, va_list ap) { +} + + + + +/////////////////////////////////////////////////////////////////////// +void _retonly(){} + +struct export sysclib_stub={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "sysclib", + (func)_start, // entrypoint + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)setjmp, + (func)longjmp, + (func)toupper, + (func)tolower, + (func)look_ctype_table, + (func)get_ctype_table, + (func)memchr, + (func)memcmp, + (func)memcpy, + (func)memmove, + (func)memset, + (func)bcmp, + (func)bcopy, + (func)bzero, + (func)prnt, + (func)sprintf, + (func)strcat, + (func)strchr, + (func)strcmp, + (func)strcpy, + (func)strcspn, + (func)index, + (func)rindex, + (func)strlen, + (func)strncat, + (func)strncmp, + (func)strncpy, + (func)strpbrk, + (func)strrchr, + (func)strspn, + (func)strstr, + (func)strtok, + (func)strtol, + (func)atob, + (func)strtoul, + (func)wmemcpy, + (func)wmemset, + (func)vsprintf, + 0 +}; + +struct export stdio_stub={ + 0x41C00000, + 0, + VER(1, 2), // 1.2 => 0x102 + 0, + "stdio", + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, +}; + +//////////////////////////////entrypoint/////////////////////////////// +int _start(int argc, char* argv[]){ + int ret = RegisterLibraryEntries(&sysclib_stub); + return RegisterLibraryEntries(&stdio_stub) + ret; +} + diff --git a/fps2bios/kernel/iopload/sysmem/Makefile b/fps2bios/kernel/iopload/sysmem/Makefile index 03e3dd2b45..2040891a20 100644 --- a/fps2bios/kernel/iopload/sysmem/Makefile +++ b/fps2bios/kernel/iopload/sysmem/Makefile @@ -1,57 +1,57 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include - -IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 -IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include -IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -IOPLINK = $(IOPLD) -dc - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: sysmem - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -L$(PS2LIB)/iop/lib -LDADD = -OBJECTS = sysmem.o - -sysmem: $(OBJECTS) - $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/SYSMEM - -%.o: %.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - - -clean: - rm -f $(OBJECTS) - - - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: sysmem + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib +LDADD = +OBJECTS = sysmem.o + +sysmem: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/SYSMEM + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + + +clean: + rm -f $(OBJECTS) + + + diff --git a/fps2bios/kernel/iopload/sysmem/sysmem.c b/fps2bios/kernel/iopload/sysmem/sysmem.c index 0aca682d45..29f6fe9aea 100644 --- a/fps2bios/kernel/iopload/sysmem/sysmem.c +++ b/fps2bios/kernel/iopload/sysmem/sysmem.c @@ -1,529 +1,529 @@ -//[module] SYSMEM -//[processor] IOP -//[type] ELF-IRX -//[name] System_Memory_Manager -//[version] 0x101 -//[memory map] 0x00001500(0x000015C3) in RAM -//[handlers] see fileio/80000003 -//[entry point] sysmem_start, sysmem_stub(it is handeled specialy by loadcore) -//[made by] [RO]man (roman_ps2dev@hotmail.com) september 2002 - -#define min(a, b) ((a)<(b)?(a):(b)) -#define max(a, b) ((a)>(b)?(a):(b)) - -#include - -#include "ksysmem.h" -#include "kloadcore.h" -#include "iopdebug.h" - -#define EIGHTMEGSm256 (8*1024*1024-256) //0x007FFF00 -#define ALIGN256 0xFFFFFF00 - -#define mALLOCATED(info) (info & 1) -#define mADDRESS(info) ((info >> 1) & 0x7FFF) -#define mSIZE(info) (info >> 17) -//[000000000000000 0 000000000000000 1] -//[ size of block |?|address of block|a]located -//upper 15bits are the size of block in 256bytes units [8MB addressability] -//unknown 1 bit -//15bits for address of block in 256bytes units [8MB addressability; 15+8 bits] -//the lower bit means that block is allocated or not (1/0) - -struct allocELEM{ //sizeof()=8 - struct allocELEM *next; -/* unsigned int size :15, - unknown :1, // info could be declared this way - addr :15, - allocated:1; */ - unsigned int info; // here is stored data about - // an allocable memory chunk -}; - -#define smFIRST 0 -#define smFIRSTF 2 //first one that can be freed -#define smCHECK 27 -#define smLAST 30 -#define smMAX (smLAST+1) //max number of elements = 31 - -struct allocTABLE{ //sizeof()=256=0x100 - struct allocTABLE *next; //+00 - struct allocELEM list[31]; //+04 8 * 31 = 248 = 0xF8; - int dummy; -}; - -char* (*_Kprintf)(unsigned int, ...); -unsigned int unk; - -/////////////////////////////////////////////////////////////////////// -unsigned int memsize; - -void *_start(u32 iopmemsize); -void *sysmem_init_memory(); -void sysmem_retonly(); -unsigned int *sysmem_return_addr_of_memsize(); - -//////////////////////////////entrypoint/////////////////////////////// -struct export sysmem_stub __attribute__((section(".text"))) = { - 0x41C00000, - 0, - VER(1, 1), // 1.1 => 0x101 - 0, - "sysmem", - (func)_start, // entrypoint - (func)sysmem_init_memory, - (func)sysmem_retonly, - (func)sysmem_return_addr_of_memsize, - (func)AllocSysMemory, - (func)FreeSysMemory, - (func)QueryMemSize, - (func)QueryMaxFreeMemSize, - (func)QueryTotalFreeMemSize, - (func)QueryBlockTopAddress, - (func)QueryBlockSize, - (func)sysmem_retonly, - (func)sysmem_retonly, - (func)sysmem_retonly, - (func)Kprintf, - (func)sysmem_call15_set_Kprintf, - 0 -}; - -struct allocTABLE *alloclist; -char _alloclist[0x200]; // temp buffer -//struct allocTABLE _alloclist; // has to be last!, also temp! - -void Kputc(u8 c) { - *((u8*)0x1f80380c) = c; -} - -void Kputs(u8 *s) { - while (*s != 0) { - Kputc(*s++); - } -} - -void Kprintnum(unsigned int n) -{ - char chars[16] = "0123456789abcdef"; - int i = 0; - while(i < 8) { - Kputc(chars[n>>28]); - n <<= 4; - ++i; - } -} - - -///////////////////////////////////////////////////////////////////////[OK] -void sysmem_retonly(){} - -//////////////////////////////entrypoint///////////////////////////////[OK] -void *_start(u32 iopmemsize) -{ - iopmemsize=min(EIGHTMEGSm256, iopmemsize); - - alloclist = (struct allocTABLE*)(((u32)&_alloclist + 255) & 0xFFFFFF00); // round up - memsize = iopmemsize & 0xFFFFFF00; - - //__printf("sysmem_start: %x, %x\n", memsize, ((u32)alloclist+sizeof(struct allocTABLE))); - //Kprintnum((int)alloclist); Kputs(" alloclist\n"); - //Kprintnum((int)&alloclist); Kputs(" &alloclist\n"); - - if (memsize >= ((u32)alloclist+sizeof(struct allocTABLE))) //alloctable must fit memory - return sysmem_init_memory(); - alloclist = NULL; - return NULL; -} - -/////////////////////////////////////////////////////////////////////// -extern void* _end; -void *sysmem_init_memory(){ //mark all mem as not allocated, available - unsigned int i; - struct allocELEM *p; - - //__printf("system_init_memory\n"); - - if (alloclist == NULL) return NULL; - - alloclist->next=NULL; - for (i=smFIRST; ilist[i].next=&alloclist->list[i+1]; - alloclist->list[i].info=0; - } - alloclist->list[smLAST].next=NULL; - - alloclist->list[smFIRST].info &= 0x0001FFFF; - alloclist->list[smFIRST].info |= (((memsize<0 ? - memsize+255:memsize) >> 8) << 17); - - // _end ~= alloclist + sizeof(struct alocTABLE); - - //this is not NULL! but the starting address of the first 0x1500 bytes allocated - if ( AllocSysMemory(ALLOC_FIRST, (int)alloclist, NULL)==0) { - if (alloclist==AllocSysMemory(ALLOC_FIRST, sizeof(struct allocTABLE)-4, NULL)){ //alloc allocated allocation table;-) - for (p=alloclist->list; p; p=p->next) { - if (!mALLOCATED(p->info)) { - return (void*)((mADDRESS(p->info))<<8);//next free block address - } - } - return NULL; - } - } - alloclist=NULL; - return NULL; -} - -///////////////////////////////////////////////////////////////////////[OK] -unsigned int QueryMemSize(){ - if (alloclist) - return memsize;//2*1024*1024-256=0x001FFF00 - return 0; -} - -///////////////////////////////////////////////////////////////////////[OK] -unsigned int QueryMaxFreeMemSize(){ - unsigned int maxfree=0; - struct allocELEM *p; - - if (alloclist) - for (p=alloclist->list; p; p=p->next) - if (!mALLOCATED(p->info)) - maxfree = max(maxfree, mSIZE(p->info)); - return maxfree<<8; // => 256bytes allocation units -} - -///////////////////////////////////////////////////////////////////////[OK] -unsigned int QueryTotalFreeMemSize(){ - unsigned int freesize=0; - struct allocELEM *p; - - if (alloclist) - for (p=alloclist->list; p; p=p->next) - if (!mALLOCATED(p->info)) - freesize+=mSIZE(p->info); - return freesize<<8; // => 256bytes allocation units -} - -void *alloc(int flags, int size, void *mem); -void maintain(); -///////////////////////////////////////////////////////////////////////[OK] -void *AllocSysMemory(int flags, int size, void *mem){ - if (alloclist && (flags<3)){ - void *r=alloc(flags, size, mem); - maintain(); - //Kprintnum((int)r); Kputs("\n"); - return (void*)r; - } - return NULL; -} - -int free(void *mem); -///////////////////////////////////////////////////////////////////////[OK] -int FreeSysMemory(void *mem){ - struct allocTABLE *table; - int r; - - for (table=alloclist; table; table=table->next) //must not be among - if (mem==table) //the allocation tables - return -1; - if (r=free(mem)) - return r; - maintain(); - return r; //r==0 ;-) -} - -struct allocELEM *findblock(void *a); -///////////////////////////////////////////////////////////////////////[OK] -void *QueryBlockTopAddress(void *address){ - struct allocELEM *p; - - if (p=findblock(address)) - return (void*)((mADDRESS(p->info) << 8) + - (mALLOCATED(p->info) ? USED : FREE)); - return (void*)-1; -} - -///////////////////////////////////////////////////////////////////////[OK] -int QueryBlockSize(void *address){ - struct allocELEM *p; - - if (p=findblock(address)) - return (mSIZE(p->info) << 8) | - (mALLOCATED(p->info) ? USED : FREE); - return -1; -} - -///////////////////////////////////////////////////////////////////////[OK] -unsigned int *sysmem_return_addr_of_memsize(){ - return &memsize; -} - -/////////////////////////////////////////////////////////////////////// -void *alloc(int flags, int size, void *mem){ - struct allocELEM *a, *last, *k; - unsigned int bsize, //block size in 256bytes units - baddress, //block address in 256bytes units - i, tmp; - void *address; - - bsize = (size+255) >> 8; // round to upper - if (bsize==0) return NULL; - - switch (flags){ - case ALLOC_FIRST: - for (a = alloclist->list; a; a=a->next) - if ((!mALLOCATED(a->info))) - if (mSIZE(a->info) >= bsize) - break; - if (a==NULL) return NULL; - - if (mSIZE(a->info) == bsize){ - a->info|=1; //alloc it - return (void*)(mADDRESS(a->info) << 8); //all done, how quick! - } - - address = (void*)(mADDRESS(a->info) << 8); - i = a->info; - - a->info=((a->info | 1) & 0x1FFFF) | //alloc block - (bsize << 17); //of wanted size - - i = (i & 0xFFFF0001) | (((mADDRESS(i) + bsize) & 0x7FFF) << 1); - i = (i & 0x1FFFF) | ((mSIZE(i) - bsize) << 17); - - a=a->next; - while (mSIZE(i)>0){ - tmp=a->info; - a->info=i; - i=tmp; - a = a->next; - } - return address; - - case ALLOC_LAST: - last=NULL; - for (a = alloclist->list; a; a=a->next) - if ((!mALLOCATED(a->info))) - if (mSIZE(a->info) >= bsize) - last=a; //use last one suitable - a = last; - if (a==0) return NULL; - - if (mSIZE(a->info) == bsize){ - a->info|=1; //alloc it - return (void*)(mADDRESS(a->info) << 8); - } - - a->info = (a->info & 0x0001FFFF) | - ((mSIZE(a->info) - bsize) << 17); //put rest of block - - i = (((i & 0xFFFF0001)//this line has no use; this is stupid - | ((mADDRESS(a->info) + mSIZE(a->info)) & 0x7FFF) << 1) //calculate address of block to use - & 0x0001FFFF) //keep only address (and alloc' state) - | (bsize << 17) //put size - | 1; //mark as allocated - a=a->next; - - address = (void*)(mADDRESS(i) << 8); //address in bytes - while (mSIZE(i)>0){ - tmp=a->info; - a->info=i; - i=tmp; - a = a->next; - } - return address; - - case ALLOC_LATER: - if ((unsigned int)mem & 0xFF) return NULL; - baddress = (unsigned int)mem >> 8; //addr in 256bytes units - for (a = alloclist->list; a ; a=a->next){ - if (baddress < mADDRESS(a->info)) return NULL;//cannot realloc - if ((!mALLOCATED(a->info)) && - (mSIZE(a->info) + mADDRESS(a->info) >= baddress + bsize)) - break; - } - if (a==0) return NULL; - - if (mADDRESS(a->info) < baddress){ - tmp = mADDRESS(a->info) + mSIZE(a->info) - baddress; - a->info= (a->info & 0x1FFFF) | - ((mSIZE(a->info) - tmp) << 17); - - i =(((i & 0xFFFF0001) | //stupid compiler - ((mADDRESS(a->info) + mSIZE(a->info)) & 0x7FFF) << 1) - & 0x1FFFE) - | (tmp << 17); - - k = a = a->next; - while (mSIZE(i)>0){ - tmp=a->info; - a->info=i; - i=tmp; - a=a->next; - } - a = k; - } - - if (mSIZE(a->info)==bsize){ - a->info|=1; //alloc it - return (void*)(mADDRESS(a->info) << 8); - } - - address = (void*)(mADDRESS(a->info) << 8); - i = a->info; - - a->info=((a->info | 1) & 0x1FFFF) | //alloc block - (bsize << 17); - - i = (i & 0xFFFF0001) | (((mADDRESS(i) + bsize) & 0x7FFF) << 1); - i = (i & 0x1FFFF) | ((mSIZE(i) - bsize) << 17); - - a=a->next; - while (mSIZE(i)>0){ - tmp=a->info; - a->info=i; - i=tmp; - a = a->next; - } - return address; - - } - - return NULL; -} -/***original while (mSIZE(i)>0){ - x=a->next; //stupid, n'est ce pas? - tmp=a->info; - a->next=z; //stupid, n'est ce pas? - a->info=i; - a->next=x; //stupid, n'est ce pas? - z=x; //stupid, n'est ce pas? - i=tmp; - a = a->next; - } ***/ - -///////////////////////////////////////////////////////////////////////[OK] -int free(void *mem){ - int skip; // counter (0,1,2) of elements to remove - struct allocELEM *a, // an element - *p, // prev - *n; // next - - if ((unsigned int)mem & 0xFF) return -1; // only 256byte multiple - - for (a=&alloclist->list[smFIRSTF], p=NULL; a; a=a->next){ - if ((mSIZE(a->info) && (mADDRESS(a->info)== - ((unsigned int)mem >> 8)))) // convert to 256byte units - break; - p=a; - } - - if (a==NULL) return -1; //block not found - - if (!mALLOCATED(a->info))return -1; //cannot free a freed block - - n=NULL; - skip=0; - - a->info&=0xFFFFFFFE; //free block - - if ((a->next) && (!mALLOCATED(a->next->info))){//bind with next free block - n = a->next; - skip = 1; - a->info = (a->info & 0x1FFFE) | - ((mSIZE(a->info) + mSIZE(a->next->info)) << 17); - } - - if (p && (!mALLOCATED(p->info))){ //bind with previous free block - n=a; - skip++; // or skip=2; - p->info=(p->info & 0x1FFFF) | - ((mSIZE(p->info) + mSIZE(a->info)) << 17); - } - - if (skip){ - a=n; - while (--skip!=-1) - a=a->next; - while (a){ - n->info=a->info; - a=a->next; - n=n->next; - } - } - return 0; -} -/***original while (a){ - t1=n->next; - t2=a->next; - t3=a->info; - n->next=t2; //stupid compiler, see above - n->info=t3; - n->next=t1; - a=a->next; - n=t1; - }***/ - -///////////////////////////////////////////////////////////////////////[OK] -void maintain(){ - struct allocTABLE *table, *new; - int i; - - for (table=alloclist; table->next; table = table->next) //+0x00 - ; //move to last non-NULL - if (mSIZE(table->list[smCHECK].info)>0) //+0xE0 //27 (i.e.28th) - // a new table is needed; alloc it - if (new=(struct allocTABLE*)alloc(0, sizeof(struct allocTABLE), 0)){ - table->next=new; // link it - table->list[smLAST].next=&new->list[smFIRST];// link it's table elements - table=table->next; // move to it - table->next=NULL; // mark as end of tables - for (i=0; ilist[i].next=&table->list[i+1]; - table->list[i].info=0; - } - table->list[smLAST].next=NULL; - } - - table=alloclist; - if (table->next){ - while (table->next->next) - table=table->next; - if (table->next) //redundant check - if (mSIZE(table->list[smCHECK].info)==0){ - struct allocTABLE *t=table->next; - table->list[smLAST].next=NULL; - table->next =NULL; - free(t); - } - } -} - -///////////////////////////////////////////////////////////////////////[OK] -struct allocELEM *findblock(void *a){ // it finds the block for a given address - struct allocELEM *p; - for (p = alloclist->list; p; p=p->next) - if (((unsigned int)a >= (mADDRESS(p->info) << 8)) && - ((unsigned int)a < (mADDRESS(p->info) << 8) + mSIZE(p->info))) - break; - return p; -} - -///////////////////////////////////////////////////////////////////////[OK] -char *Kprintf(const char *format,...){ - if (_Kprintf) - return _Kprintf(unk, format, (void*)(format+4));//it is not accurate since mips - // have the 2nd, 3rd & 4th parameters - // in regs and not in stack, - // but you got the idea - return NULL; -} - -///////////////////////////////////////////////////////////////////////[OK] -void sysmem_call15_set_Kprintf(char* (*newKprintf)(unsigned int, const char*, ...), unsigned int newunk){ - if (_Kprintf && newKprintf) - newKprintf(newunk, _Kprintf(0)); - unk = newunk; - _Kprintf = newKprintf; -} +//[module] SYSMEM +//[processor] IOP +//[type] ELF-IRX +//[name] System_Memory_Manager +//[version] 0x101 +//[memory map] 0x00001500(0x000015C3) in RAM +//[handlers] see fileio/80000003 +//[entry point] sysmem_start, sysmem_stub(it is handeled specialy by loadcore) +//[made by] [RO]man (roman_ps2dev@hotmail.com) september 2002 + +#define min(a, b) ((a)<(b)?(a):(b)) +#define max(a, b) ((a)>(b)?(a):(b)) + +#include + +#include "ksysmem.h" +#include "kloadcore.h" +#include "iopdebug.h" + +#define EIGHTMEGSm256 (8*1024*1024-256) //0x007FFF00 +#define ALIGN256 0xFFFFFF00 + +#define mALLOCATED(info) (info & 1) +#define mADDRESS(info) ((info >> 1) & 0x7FFF) +#define mSIZE(info) (info >> 17) +//[000000000000000 0 000000000000000 1] +//[ size of block |?|address of block|a]located +//upper 15bits are the size of block in 256bytes units [8MB addressability] +//unknown 1 bit +//15bits for address of block in 256bytes units [8MB addressability; 15+8 bits] +//the lower bit means that block is allocated or not (1/0) + +struct allocELEM{ //sizeof()=8 + struct allocELEM *next; +/* unsigned int size :15, + unknown :1, // info could be declared this way + addr :15, + allocated:1; */ + unsigned int info; // here is stored data about + // an allocable memory chunk +}; + +#define smFIRST 0 +#define smFIRSTF 2 //first one that can be freed +#define smCHECK 27 +#define smLAST 30 +#define smMAX (smLAST+1) //max number of elements = 31 + +struct allocTABLE{ //sizeof()=256=0x100 + struct allocTABLE *next; //+00 + struct allocELEM list[31]; //+04 8 * 31 = 248 = 0xF8; + int dummy; +}; + +char* (*_Kprintf)(unsigned int, ...); +unsigned int unk; + +/////////////////////////////////////////////////////////////////////// +unsigned int memsize; + +void *_start(u32 iopmemsize); +void *sysmem_init_memory(); +void sysmem_retonly(); +unsigned int *sysmem_return_addr_of_memsize(); + +//////////////////////////////entrypoint/////////////////////////////// +struct export sysmem_stub __attribute__((section(".text"))) = { + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "sysmem", + (func)_start, // entrypoint + (func)sysmem_init_memory, + (func)sysmem_retonly, + (func)sysmem_return_addr_of_memsize, + (func)AllocSysMemory, + (func)FreeSysMemory, + (func)QueryMemSize, + (func)QueryMaxFreeMemSize, + (func)QueryTotalFreeMemSize, + (func)QueryBlockTopAddress, + (func)QueryBlockSize, + (func)sysmem_retonly, + (func)sysmem_retonly, + (func)sysmem_retonly, + (func)Kprintf, + (func)sysmem_call15_set_Kprintf, + 0 +}; + +struct allocTABLE *alloclist; +char _alloclist[0x200]; // temp buffer +//struct allocTABLE _alloclist; // has to be last!, also temp! + +void Kputc(u8 c) { + *((u8*)0x1f80380c) = c; +} + +void Kputs(u8 *s) { + while (*s != 0) { + Kputc(*s++); + } +} + +void Kprintnum(unsigned int n) +{ + char chars[16] = "0123456789abcdef"; + int i = 0; + while(i < 8) { + Kputc(chars[n>>28]); + n <<= 4; + ++i; + } +} + + +///////////////////////////////////////////////////////////////////////[OK] +void sysmem_retonly(){} + +//////////////////////////////entrypoint///////////////////////////////[OK] +void *_start(u32 iopmemsize) +{ + iopmemsize=min(EIGHTMEGSm256, iopmemsize); + + alloclist = (struct allocTABLE*)(((u32)&_alloclist + 255) & 0xFFFFFF00); // round up + memsize = iopmemsize & 0xFFFFFF00; + + //__printf("sysmem_start: %x, %x\n", memsize, ((u32)alloclist+sizeof(struct allocTABLE))); + //Kprintnum((int)alloclist); Kputs(" alloclist\n"); + //Kprintnum((int)&alloclist); Kputs(" &alloclist\n"); + + if (memsize >= ((u32)alloclist+sizeof(struct allocTABLE))) //alloctable must fit memory + return sysmem_init_memory(); + alloclist = NULL; + return NULL; +} + +/////////////////////////////////////////////////////////////////////// +extern void* _end; +void *sysmem_init_memory(){ //mark all mem as not allocated, available + unsigned int i; + struct allocELEM *p; + + //__printf("system_init_memory\n"); + + if (alloclist == NULL) return NULL; + + alloclist->next=NULL; + for (i=smFIRST; ilist[i].next=&alloclist->list[i+1]; + alloclist->list[i].info=0; + } + alloclist->list[smLAST].next=NULL; + + alloclist->list[smFIRST].info &= 0x0001FFFF; + alloclist->list[smFIRST].info |= (((memsize<0 ? + memsize+255:memsize) >> 8) << 17); + + // _end ~= alloclist + sizeof(struct alocTABLE); + + //this is not NULL! but the starting address of the first 0x1500 bytes allocated + if ( AllocSysMemory(ALLOC_FIRST, (int)alloclist, NULL)==0) { + if (alloclist==AllocSysMemory(ALLOC_FIRST, sizeof(struct allocTABLE)-4, NULL)){ //alloc allocated allocation table;-) + for (p=alloclist->list; p; p=p->next) { + if (!mALLOCATED(p->info)) { + return (void*)((mADDRESS(p->info))<<8);//next free block address + } + } + return NULL; + } + } + alloclist=NULL; + return NULL; +} + +///////////////////////////////////////////////////////////////////////[OK] +unsigned int QueryMemSize(){ + if (alloclist) + return memsize;//2*1024*1024-256=0x001FFF00 + return 0; +} + +///////////////////////////////////////////////////////////////////////[OK] +unsigned int QueryMaxFreeMemSize(){ + unsigned int maxfree=0; + struct allocELEM *p; + + if (alloclist) + for (p=alloclist->list; p; p=p->next) + if (!mALLOCATED(p->info)) + maxfree = max(maxfree, mSIZE(p->info)); + return maxfree<<8; // => 256bytes allocation units +} + +///////////////////////////////////////////////////////////////////////[OK] +unsigned int QueryTotalFreeMemSize(){ + unsigned int freesize=0; + struct allocELEM *p; + + if (alloclist) + for (p=alloclist->list; p; p=p->next) + if (!mALLOCATED(p->info)) + freesize+=mSIZE(p->info); + return freesize<<8; // => 256bytes allocation units +} + +void *alloc(int flags, int size, void *mem); +void maintain(); +///////////////////////////////////////////////////////////////////////[OK] +void *AllocSysMemory(int flags, int size, void *mem){ + if (alloclist && (flags<3)){ + void *r=alloc(flags, size, mem); + maintain(); + //Kprintnum((int)r); Kputs("\n"); + return (void*)r; + } + return NULL; +} + +int free(void *mem); +///////////////////////////////////////////////////////////////////////[OK] +int FreeSysMemory(void *mem){ + struct allocTABLE *table; + int r; + + for (table=alloclist; table; table=table->next) //must not be among + if (mem==table) //the allocation tables + return -1; + if (r=free(mem)) + return r; + maintain(); + return r; //r==0 ;-) +} + +struct allocELEM *findblock(void *a); +///////////////////////////////////////////////////////////////////////[OK] +void *QueryBlockTopAddress(void *address){ + struct allocELEM *p; + + if (p=findblock(address)) + return (void*)((mADDRESS(p->info) << 8) + + (mALLOCATED(p->info) ? USED : FREE)); + return (void*)-1; +} + +///////////////////////////////////////////////////////////////////////[OK] +int QueryBlockSize(void *address){ + struct allocELEM *p; + + if (p=findblock(address)) + return (mSIZE(p->info) << 8) | + (mALLOCATED(p->info) ? USED : FREE); + return -1; +} + +///////////////////////////////////////////////////////////////////////[OK] +unsigned int *sysmem_return_addr_of_memsize(){ + return &memsize; +} + +/////////////////////////////////////////////////////////////////////// +void *alloc(int flags, int size, void *mem){ + struct allocELEM *a, *last, *k; + unsigned int bsize, //block size in 256bytes units + baddress, //block address in 256bytes units + i, tmp; + void *address; + + bsize = (size+255) >> 8; // round to upper + if (bsize==0) return NULL; + + switch (flags){ + case ALLOC_FIRST: + for (a = alloclist->list; a; a=a->next) + if ((!mALLOCATED(a->info))) + if (mSIZE(a->info) >= bsize) + break; + if (a==NULL) return NULL; + + if (mSIZE(a->info) == bsize){ + a->info|=1; //alloc it + return (void*)(mADDRESS(a->info) << 8); //all done, how quick! + } + + address = (void*)(mADDRESS(a->info) << 8); + i = a->info; + + a->info=((a->info | 1) & 0x1FFFF) | //alloc block + (bsize << 17); //of wanted size + + i = (i & 0xFFFF0001) | (((mADDRESS(i) + bsize) & 0x7FFF) << 1); + i = (i & 0x1FFFF) | ((mSIZE(i) - bsize) << 17); + + a=a->next; + while (mSIZE(i)>0){ + tmp=a->info; + a->info=i; + i=tmp; + a = a->next; + } + return address; + + case ALLOC_LAST: + last=NULL; + for (a = alloclist->list; a; a=a->next) + if ((!mALLOCATED(a->info))) + if (mSIZE(a->info) >= bsize) + last=a; //use last one suitable + a = last; + if (a==0) return NULL; + + if (mSIZE(a->info) == bsize){ + a->info|=1; //alloc it + return (void*)(mADDRESS(a->info) << 8); + } + + a->info = (a->info & 0x0001FFFF) | + ((mSIZE(a->info) - bsize) << 17); //put rest of block + + i = (((i & 0xFFFF0001)//this line has no use; this is stupid + | ((mADDRESS(a->info) + mSIZE(a->info)) & 0x7FFF) << 1) //calculate address of block to use + & 0x0001FFFF) //keep only address (and alloc' state) + | (bsize << 17) //put size + | 1; //mark as allocated + a=a->next; + + address = (void*)(mADDRESS(i) << 8); //address in bytes + while (mSIZE(i)>0){ + tmp=a->info; + a->info=i; + i=tmp; + a = a->next; + } + return address; + + case ALLOC_LATER: + if ((unsigned int)mem & 0xFF) return NULL; + baddress = (unsigned int)mem >> 8; //addr in 256bytes units + for (a = alloclist->list; a ; a=a->next){ + if (baddress < mADDRESS(a->info)) return NULL;//cannot realloc + if ((!mALLOCATED(a->info)) && + (mSIZE(a->info) + mADDRESS(a->info) >= baddress + bsize)) + break; + } + if (a==0) return NULL; + + if (mADDRESS(a->info) < baddress){ + tmp = mADDRESS(a->info) + mSIZE(a->info) - baddress; + a->info= (a->info & 0x1FFFF) | + ((mSIZE(a->info) - tmp) << 17); + + i =(((i & 0xFFFF0001) | //stupid compiler + ((mADDRESS(a->info) + mSIZE(a->info)) & 0x7FFF) << 1) + & 0x1FFFE) + | (tmp << 17); + + k = a = a->next; + while (mSIZE(i)>0){ + tmp=a->info; + a->info=i; + i=tmp; + a=a->next; + } + a = k; + } + + if (mSIZE(a->info)==bsize){ + a->info|=1; //alloc it + return (void*)(mADDRESS(a->info) << 8); + } + + address = (void*)(mADDRESS(a->info) << 8); + i = a->info; + + a->info=((a->info | 1) & 0x1FFFF) | //alloc block + (bsize << 17); + + i = (i & 0xFFFF0001) | (((mADDRESS(i) + bsize) & 0x7FFF) << 1); + i = (i & 0x1FFFF) | ((mSIZE(i) - bsize) << 17); + + a=a->next; + while (mSIZE(i)>0){ + tmp=a->info; + a->info=i; + i=tmp; + a = a->next; + } + return address; + + } + + return NULL; +} +/***original while (mSIZE(i)>0){ + x=a->next; //stupid, n'est ce pas? + tmp=a->info; + a->next=z; //stupid, n'est ce pas? + a->info=i; + a->next=x; //stupid, n'est ce pas? + z=x; //stupid, n'est ce pas? + i=tmp; + a = a->next; + } ***/ + +///////////////////////////////////////////////////////////////////////[OK] +int free(void *mem){ + int skip; // counter (0,1,2) of elements to remove + struct allocELEM *a, // an element + *p, // prev + *n; // next + + if ((unsigned int)mem & 0xFF) return -1; // only 256byte multiple + + for (a=&alloclist->list[smFIRSTF], p=NULL; a; a=a->next){ + if ((mSIZE(a->info) && (mADDRESS(a->info)== + ((unsigned int)mem >> 8)))) // convert to 256byte units + break; + p=a; + } + + if (a==NULL) return -1; //block not found + + if (!mALLOCATED(a->info))return -1; //cannot free a freed block + + n=NULL; + skip=0; + + a->info&=0xFFFFFFFE; //free block + + if ((a->next) && (!mALLOCATED(a->next->info))){//bind with next free block + n = a->next; + skip = 1; + a->info = (a->info & 0x1FFFE) | + ((mSIZE(a->info) + mSIZE(a->next->info)) << 17); + } + + if (p && (!mALLOCATED(p->info))){ //bind with previous free block + n=a; + skip++; // or skip=2; + p->info=(p->info & 0x1FFFF) | + ((mSIZE(p->info) + mSIZE(a->info)) << 17); + } + + if (skip){ + a=n; + while (--skip!=-1) + a=a->next; + while (a){ + n->info=a->info; + a=a->next; + n=n->next; + } + } + return 0; +} +/***original while (a){ + t1=n->next; + t2=a->next; + t3=a->info; + n->next=t2; //stupid compiler, see above + n->info=t3; + n->next=t1; + a=a->next; + n=t1; + }***/ + +///////////////////////////////////////////////////////////////////////[OK] +void maintain(){ + struct allocTABLE *table, *new; + int i; + + for (table=alloclist; table->next; table = table->next) //+0x00 + ; //move to last non-NULL + if (mSIZE(table->list[smCHECK].info)>0) //+0xE0 //27 (i.e.28th) + // a new table is needed; alloc it + if (new=(struct allocTABLE*)alloc(0, sizeof(struct allocTABLE), 0)){ + table->next=new; // link it + table->list[smLAST].next=&new->list[smFIRST];// link it's table elements + table=table->next; // move to it + table->next=NULL; // mark as end of tables + for (i=0; ilist[i].next=&table->list[i+1]; + table->list[i].info=0; + } + table->list[smLAST].next=NULL; + } + + table=alloclist; + if (table->next){ + while (table->next->next) + table=table->next; + if (table->next) //redundant check + if (mSIZE(table->list[smCHECK].info)==0){ + struct allocTABLE *t=table->next; + table->list[smLAST].next=NULL; + table->next =NULL; + free(t); + } + } +} + +///////////////////////////////////////////////////////////////////////[OK] +struct allocELEM *findblock(void *a){ // it finds the block for a given address + struct allocELEM *p; + for (p = alloclist->list; p; p=p->next) + if (((unsigned int)a >= (mADDRESS(p->info) << 8)) && + ((unsigned int)a < (mADDRESS(p->info) << 8) + mSIZE(p->info))) + break; + return p; +} + +///////////////////////////////////////////////////////////////////////[OK] +char *Kprintf(const char *format,...){ + if (_Kprintf) + return _Kprintf(unk, format, (void*)(format+4));//it is not accurate since mips + // have the 2nd, 3rd & 4th parameters + // in regs and not in stack, + // but you got the idea + return NULL; +} + +///////////////////////////////////////////////////////////////////////[OK] +void sysmem_call15_set_Kprintf(char* (*newKprintf)(unsigned int, const char*, ...), unsigned int newunk){ + if (_Kprintf && newKprintf) + newKprintf(newunk, _Kprintf(0)); + unk = newunk; + _Kprintf = newKprintf; +} diff --git a/fps2bios/kernel/iopload/threadman/Makefile b/fps2bios/kernel/iopload/threadman/Makefile index 825a93d649..590345af01 100644 --- a/fps2bios/kernel/iopload/threadman/Makefile +++ b/fps2bios/kernel/iopload/threadman/Makefile @@ -1,59 +1,59 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include - -IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 -IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include -IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -IOPLINK = $(IOPLD) -dc -IOPASFLAGS := -EL -G0 - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: threadman - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib -LDADD = -OBJECTS = threadman.o ../iopdebug.o ../libkernel/iop_loadcore.o ../libkernel/iop_intrman.o - -threadman: $(OBJECTS) - $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/THREADMAN - -%.o: %.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - -%.o : %.s - $(IOPAS) $(IOPASFLAGS) $< -o $@ - -clean: - rm -f $(OBJECTS) - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: threadman + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib +LDADD = +OBJECTS = threadman.o ../iopdebug.o ../libkernel/iop_loadcore.o ../libkernel/iop_intrman.o + +threadman: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/THREADMAN + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/threadman/threadman.c b/fps2bios/kernel/iopload/threadman/threadman.c index d964bad648..f0b6d1558c 100644 --- a/fps2bios/kernel/iopload/threadman/threadman.c +++ b/fps2bios/kernel/iopload/threadman/threadman.c @@ -1,654 +1,654 @@ -//[module] THREADMAN -//[processor] IOP -//[type] ELF-IRX -//[name] Multi_Thread_Manager -//[version] 0x101 -//[memory map] 0xBF802070 -//[handlers] - -//[entry point] start, thbase_stub, thevent_stub, thsemap_stub, -// thmsgbx_stub, thfpool_stub, thvpool_stub, thrdman_stub -//[made by] [RO]man (roman_ps2dev@hotmail.com) november 2002 - january 2003 - -#include "err.h" -#include "ksysmem.h" -#include "kloadcore.h" -#include "kintrman.h" -#include "kstdio.h" -#include "ksysclib.h" -#include "ktimrman.h" -#include "kheaplib.h" -#include "iopdebug.h" -#include "kthbase.h" - -int debug=1; - -#define _dprintf(fmt, args...) \ - if (debug > 0) __printf("threadman:" fmt, ## args) - -int _start(); - - -void _retonly() {} - -struct export thbase_stub={ - 0x41C00000, - 0, - VER(1, 1), // 1.1 => 0x101 - 0, - "thbase", - (func)_start, // entrypoint - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, // 0x08 - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, // 0x10 - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, // 0x18 - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, // 0x20 - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, // 0x28 - (func)_retonly, - 0 -}; - -struct export thevent_stub={ - 0x41C00000, - 0, - VER(1, 1), // 1.1 => 0x101 - 0, - "thevent", - (func)_start, // entrypoint - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, // 0x08 - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - 0 -}; - -struct export thsemap_stub={ - 0x41C00000, - 0, - VER(1, 1), // 1.1 => 0x101 - 0, - "thsemap", - (func)_start, // entrypoint - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, // 0x08 - (func)_retonly, - (func)_retonly, - (func)_retonly, - (func)_retonly, - 0 -}; - - -int _start() { - int x; - - _dprintf("_start\n"); - -// if (RegisterNonAutoLinkEntries(&thrdman_stub)) return 1; - if (RegisterLibraryEntries(&thbase_stub)) return 1; - - CpuSuspendIntr(&x); - - RegisterLibraryEntries(&thevent_stub); - RegisterLibraryEntries(&thsemap_stub); -// RegisterLibraryEntries(&thmsgbx_stub); -// RegisterLibraryEntries(&thfpool_stub); -// RegisterLibraryEntries(&thvpool_stub); - - CpuEnableIntr(); -} - -#if 0 -unsigned int ready; -unsigned int _263; -unsigned int _14; - -/////////////////////////////////////////////////////////////////////// -unsigned int *threadman_callx(){ - return &ready; -} - -/////////////////////////////////////////////////////////////////////// -int thbase_start(int argc, char* argv[]){ - int x; - - if (RegisterNonAutoLinkEntries(&thrdman_stub)) return 1; - if (RegisterLibraryEntries(&thbase_stub)) return 1; - - CpuSuspendIntr(&x); - - RegisterLibraryEntries(&thevent_stub); - RegisterLibraryEntries(&thsemap_stub); - RegisterLibraryEntries(&thmsgbx_stub); - RegisterLibraryEntries(&thfpool_stub); - RegisterLibraryEntries(&thvpool_stub); - - memset(&ready, 0, 1220); //305 x 4 => zero all bss - - _unk3=8; - _2=NULL; - LL_reset(&a); - LL_reset(&b); - LL_reset(&c); - LL_reset(&d); - LL_reset(&e); - LL_reset(&f); - LL_reset(&g); - LL_reset(&h); - LL_reset(&i); - LL_reset(&threads_list); - - for (j=0; j<128; j++) - LL_reset(&prio_lists[j]); - hp=CreateHeap(0x800, 1); //s3=&hp - th=allocheap(0x7F01, sizeof(struct TCB)); - th->id=++ids;//short - th->thp_stackSize=512; - th->stack=AllocSysMemory(ALLOC_LAST, 512, 0); - th->prio=th->thp_priority=127;//LOWEST_PRIORITY+1 - th->thp_attr=TH_C; - th->status=THS_READY; - th->gp=gp; - th->thp_entry=infinite_call; - th->area=th->stack + ((th->thp_stackSize >> 2) << 2) - 0xB8; - memset(th->area, 0, 0xB8); - th->area->field_00=0xFFFFFFFE; - th->area->H78=th->area->H74==&th->area->regs; - th->area->ExitThread=ExitThread; - th->area->gp=th->gp; - th->area->attr=(th->attr & TH_COP) | 0x404; - th->area->attr|=th->attr & TH_UMODE; - th->area->entry=th->thp_entry; - th->area->ei=1; - _2.next=th; - _2.prev=th; - enqueue(th); - - th=allocheap(0x7F01, sizeof(struct TCB)); - th->id=++ids;//short - th->thp_stackSize=QueryBlockSize(&j); - th->stack=QueryBlockTopAddress(&j); - th->thp_priority=8; //MODULE_INIT_PRIORITY - th->prio=1; //HIGHEST_PRIORITY - th->thp_attr=0x2000000; - th->status=THS_RUN; - th->gp=gp; - th->next_2=_2.next; - _2.next=th; - ready.prev=ready.next=th; - th->next=NULL; - th->prev=NULL; - SetCtxSwitchHandler(handler1_switchcontexts); - SetCtxSwitchReqHandler(handler2_morethan1ready); - sub_50A0(); - - efp.attr=2; - efp.initPattern=0; - efp.option=0; - systemStatusFlag=CreateEventFlag(&efp); - - if (v0=QueryBootMode(4)) - SetEventFlag(systemStatusFlag, 1<<(v0->H0 & 3));//H0 short - - loadcore_call20_registerFunc(&lc20_2, 2, 0); - loadcore_call20_registerFunc(&lc20_3, 3, 0); - CpuEnableIntr(); - return 0; -} - -/////////////////////////////////////////////////////////////////////// -int lc20_2(){ - CpuEnableIntr(); - - return 0; -} - -/////////////////////////////////////////////////////////////////////// -int lc20_3(int a){ - _dprintf("%s\n", __FUNCTION__); - CpuEnableIntr(); - - ChangeThreadPriority(0, 126);//LOWEST_PRIORIT - if (a->H0 == 0) { - for (;;) { - DelayThread(1000000); //never exit - } - } - return 0; -} - -/////////////////////////////////////////////////////////////////////// -void infinite_call(){ - infinite_call(); -} - -/////////////////////////////////////////////////////////////////////// -void syscall_32(){ - li $v0, 0x20 - syscall #0 -} - -/////////////////////////////////////////////////////////////////////// -void enqueue(struct TCB *th){ - flags[th->prio>>5] |= 1 << (th->prio & 0x1F); - LL_add_before(&prio_lists[th->prio], th); -} - -///////////////////////////////////////////////////////////////////////clone? -void enqueue2(struct TCB *th){ - flags[th->prio>>5] |= 1 << (th->prio & 0x1F); - LL_add_before(&prio_lists[th->prio], th); -} - -/////////////////////////////////////////////////////////////////////// -void unqueue(ll, prio){ - if (LL_0_1_elements(ll) - flags[prio>>5] &= ~(1 << (prio & 0x1F)) - LL_remove(ll); -} - -/////////////////////////////////////////////////////////////////////// -int run(struct TCB *th, int x){ - if (th->prio >= ready.next->prio){ - th->status=THS_READY; - enqueue(th); - CpuResumeIntr(x); - return KE_OK; - }else{ - ready.next->status=THS_READY; - enqueue2(ready.next); - th->status=THS_RUN; - ready->prev=th; - return syscall_32(0, 0, x, 0); - } -} - -/////////////////////////////////////////////////////////////////////// -int getHighestUsed(){ - int i; - for (i=0; i<4; i++) - if (flags[i]) - return (i<<5)+getHighestUsed_32(flags[i]); - return 128; //LOWEST_PRIORITY+2 -} - -/////////////////////////////////////////////////////////////////////// -void switch(){ - int hp; - - ready.prev=ready.next; - if (ready.next->status != THS_RUN){ - if (unk3 & 4) - Kprintf(" not THS_RUN "); - hp=getHighestUsed(); - if (hp<128){ - if (unk3 & 4) - Kprintf(" readyq = %x, newrun = %x:%d, prio = %d", - &prio_lists[hp], prio_lists[hp].next, prio_lists[hp].next->id, hp); - unqueue(prio_lists[hp].next, hp); - prio_lists[hp].next->status=THS_RUN; - ready.prev=prio_lists[hp].next; - }else - Kprintf("Panic: not found executable Thread\n"); - }else - if ((hp=getHighestUsed())<128){ - if (unk3 & 4) - Kprintf(" THS_RUN cp=%d : hp=%d ", ready.next->prio, hp); - if (hpprio){ - if (unk3 & 4) - Kprintf(" readyq = %x, newrun = %x:%d, prio = %d", - &prio_list[hp], prio_list[hp].next, prio_list[hp].next->id, hp); - unqueue(prio_list[hp].next, hp); - prio_list[hp].next->status=ready.next->status; - ready.prev=prio_lists[hp].next; - ready.next->status=THS_READY; - enqueue2(ready.next); - } - }else - Kprintf("Panic: not found ready Thread\n"); - if (unk3 & 4) - Kprintf("\n"); -} - -/////////////////////////////////////////////////////////////////////// -void stack_overflow(struct TCB *th){ - register ImageInfo ii; - register char *name; - Kprintf("\nThread (thid=%x, #%d) stack overflow\n Stack = %x, Stack size = %x, SP=%x\n", - (th<<5) | ((th->id & 0x3F) << 1) | 1, th->id & 0xFFFF, th->stack, th->thp_stackSize, th->area); - if ((ii=loadcore_call24_findImageInfo(th->thp_entry)) && - (name=ii->H04)) - Kprintf(" Module Name = %s\n", name); - __asm break #0x400 -); - -/////////////////////////////////////////////////////////////////////// -struct TCB *handler1_switchcontexts(struct AREA *area){ - s0=&unk4; - unk4++; - if (unk3 & 3){ - if (1==unk3 & 3) - Kprintf("[%3d->", ready.next->id); - if (2==unk3 & 3) - Kprintf("switch_context(%x:%x,pc=%x,ei=%x =>%x:%d)\n", - area, area->field_00, area->entry, area->ei, ready.next, ready.next->id); - } - ready.next->area=area; - if (area < ready.next->stack) - stack_overflow(ready.next); - if (ready.prev->next==NULL) - switch(); - if (ready.prev != ready.next){ - s0=GetTimerCounter(timid); - ready.next->field_30=moveregs(0, s0-www.prev, ready.next->field_30); - www.prev=s0; - } - if (unk3 & 3){ - if (unk3 & 3 == 1) - Kprintf("%3d]", ready.prev->id); - if (unk3 & 3 == 2) - Kprintf(" switch_context --> %x:%x,pc=%x,ei=%x =>%x:%d\n" - ready.prev->area, ready.prev->area->field_00, ready.prev->area->entry, - ready.prev->area->ei, ready.prev, ready.prev->id); - } - if (unk3 & 0x20){ - 0xBF802070=~(1 << ((ready.prev->id-1) & 7)); - } - return ready.prev; -} - -/////////////////////////////////////////////////////////////////////// -int handler2_morethan1ready(){ - return (0 < (ready.prev^ready.next)); - //return (ready.prev!=ready.next); -} - -/////////////////////////////////////////////////////////////////////// -void queue_on_prio(struct TCB *th, void *fld, int prio){ - register struct TCB *p; - - LL_remove(th); - for (p=fld->H14; p !=&fld->H14 && prio>=p->prio; p=p->next); - LL_add_before(p, th); -} - -///////////////////////////////////////////////////////////////////////[04] -int CreateThread(struct ThreadParam *param){ - int x; - register struct TCB *th; - - if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; - if (param->attr & 0x1CFFFFF7) return KE_ILLEGAL_ATTR; - if (param->initPriority-1>=126) return KE_ILLEGAL_PRIORITY; - if (param->entry & 3) return KE_ILLEGAL_ENTRY; - if (param->stackSize<0x130) return KE_ILLEGAL_STACK_SIZE; - - CpuSuspendIntr(&x); - if (th=allocheap(0x7F01, sizeof(struct TCB))){ //0x50 - param->stackSize = (param->stackSize+0xFF) & 0xFFFFFF00; - stack=AllocSysMemory(ALLOC_LAST, param->stackSize, NULL); - if (!stack) - freeheap(th); - } - if (!th || !stack){ - CpuResumeIntr(x); - return KE_NO_MEMORY; - } - th->id=++ids; - th->thp_entry=param->entry; - th->stack=stack; - th->thp_stackSize; - th->thp_priority=param->initPriority; - th->thp_attr=attr; - th->status=THS_DORMANT; - th->thp_option=param->option; - th->gp=$gp; - th->next_2=&_2; - _2.next=th; - LL_add_before(threads_list, th); - if (!(th->thp_attr & TH_NO_FILLSTACK)) - memset(th->stack, 0xFF, th->thp_stackSize-48); - CpuResumeIntr(x); - return ((int)th<<5) | ((th->id & 0x3F) << 1) | 1; -} - -///////////////////////////////////////////////////////////////////////[05] -int DeleteThread(int thid){ - int x; - register struct TCB *th, *p; - - if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; - if (thid==0) return KE_ILLEGAL_THID; - - CpuSuspendIntr(&x); - th=(struct TCB *)(thid>>7<<2); - if ((th->_7F01 != 0x7F01) || - (((thid>>1) & 0x3F) != (th->id & 0x3F)) || - (_2.prev == th)){ - CpuResumeIntr(x); - return KE_UNKNOWN_THID; - } - if (th->status != THS_DORMANT){ - CpuResumeIntr(x); - return KE_NOT_DORMANT; - } - FreeSysMemory(th->stack); - LL_remove(th); - - if (_2.next==th) - _2.next=th->next_2; - else - for (p=_2.next; p->next_2; p=p->next_2) - if (p->next_2==th){ - p->next_2=th->next_2; - break; - } - - freeheap(th); - CpuResumeIntr(x); - return KE_OK; -} - -/////////////////////////////////////////////////////////////////////// -int startThread(struct TCB *th,int x){ - th->field_1C=0; - th->field_20=0; - th->field_1E=0; - th->prio=thp_priority; - th->area->field_00=0xFFFFFFFE; - th->area->field_78=th->area->field_74=&th->area->regs; - th->area->ExitThread=ExitThread; - th->area->gp=th->gp; - th->area->attr=(th->attr & TH_COP) | 0x404; - th->area->attr|=th->attr & TH_UMODE; - th->area->entry->th->thp_entry; - th->ei=1; - LL_remove(th); - return run(th, x); -} - -///////////////////////////////////////////////////////////////////////[06] -int StartThread(int thid,u_long arg){ - int x; - register struct TCB *th, *p; - - if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; - if (thid==0) return KE_ILLEGAL_THID; - - CpuSuspendIntr(&x); - th=(struct TCB *)(thid>>7<<2); - if ((th->_7F01 != 0x7F01) || - (((thid>>1) & 0x3F) != (th->id & 0x3F))){ - CpuResumeIntr(x); - return KE_UNKNOWN_THID; - } - if (th->status != THS_DORMANT){ - CpuResumeIntr(x); - return KE_NOT_DORMANT; - } - th->area = th->stack + ((th->thp_stackSize >> 2) << 2) - 0xB8; - memset(th->area, 0, 0xB8); - th->area->arg=arg; - return startThread(th, x); -} - -///////////////////////////////////////////////////////////////////////[07] -int StartThreadArgs(int thid,int args,void *argp){ - int x; - register struct TCB *th, *p; - register void *_argp; - - if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; - if (thid==0) return KE_ILLEGAL_THID; - - CpuSuspendIntr(&x); - th=(struct TCB *)(thid>>7<<2); - if ((th->_7F01 != 0x7F01) || - (((thid>>1) & 0x3F) != (th->id & 0x3F))){ - CpuResumeIntr(x); - return KE_UNKNOWN_THID; - } - if (th->status != THS_DORMANT){ - CpuResumeIntr(x); - return KE_NOT_DORMANT; - } - - _argp=th->stack + ((th->thp_stackSize >> 2) - ((args+3) >> 2)) << 2 - if (args>0 && argp) - memcpy(_argp, argp, args); - - memset(th->area, 0, 0xB8); //BUG: these instructions should be switched! - th->area = th->stack + ((th->thp_stackSize >> 2) << 2) - 0xB8; - - th->area->arg =args; - th->area->argp=_argp; - return startThread(th, x); -} - -///////////////////////////////////////////////////////////////////////[08] -int ExitThread(){ - th=ready->next; - if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT - CpuSuspendIntr(&x); - th->status=THS_DORMANT; - LL_add_before(&threads_list, th); - a0=0; - do{ - ready.prev=0; - syscall_32(0, 0, x, 0); - Kprintf("panic ! Thread DORMANT !\n"); - __asm break #0x400 - while(1); -} - -///////////////////////////////////////////////////////////////////////[09] -int ExitDeleteThread(){ - return KE_ERROR; -} - -///////////////////////////////////////////////////////////////////////[10] -int TerminateThread(int thid){ - int x; - register struct TCB *th, *p; - - if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; - if (thid==0) return KE_ILLEGAL_THID; - - CpuSuspendIntr(&x); - th=(struct TCB *)(thid>>7<<2); - if (ready.next==th){ - CpuResumeIntr(x); - return KE_ILLEGAL_THID; - } - if ((th->_7F01 != 0x7F01) || - (((thid>>1) & 0x3F) != (th->id & 0x3F))){ - CpuResumeIntr(x); - return KE_UNKNOWN_THID; - } - if (th->status == THS_DORMANT){ - CpuResumeIntr(x); - return KE_DORMANT; - } - LL_remove(th); - if (th->status==THS_WAIT) - if (th->field_1C==2) - CancelAlarm(alarmhandler, th); - else - if (th->field_1C>=2) && (th->field_1C<8) - th->field_20->H10--; - th->status=THS_DORMANT; - LL_add_before(&threads_list, th); - - CpuResumeIntr(x); - return KE_OK; -} - -/////////////////////////////////////////////////////////////////////// -void LL_add_before(struct ll *list, struct ll *new){ - new->next=list; - new->prev=list->prev; - list->prev=new; - new->prev->next=new; -} - -///////////////////////////////////////////////////////////////////////:) -int getHighestUsed_32(int flags_32){ - v=-4; - do{ - i=flags_32<<28; - flags_32>>=4; - v+=4; - }while(i==0); - return v + ((0x1020103 >> ((i>>26) & 0x1C)) & 0xF); -} - -#endif +//[module] THREADMAN +//[processor] IOP +//[type] ELF-IRX +//[name] Multi_Thread_Manager +//[version] 0x101 +//[memory map] 0xBF802070 +//[handlers] - +//[entry point] start, thbase_stub, thevent_stub, thsemap_stub, +// thmsgbx_stub, thfpool_stub, thvpool_stub, thrdman_stub +//[made by] [RO]man (roman_ps2dev@hotmail.com) november 2002 - january 2003 + +#include "err.h" +#include "ksysmem.h" +#include "kloadcore.h" +#include "kintrman.h" +#include "kstdio.h" +#include "ksysclib.h" +#include "ktimrman.h" +#include "kheaplib.h" +#include "iopdebug.h" +#include "kthbase.h" + +int debug=1; + +#define _dprintf(fmt, args...) \ + if (debug > 0) __printf("threadman:" fmt, ## args) + +int _start(); + + +void _retonly() {} + +struct export thbase_stub={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "thbase", + (func)_start, // entrypoint + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, // 0x08 + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, // 0x10 + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, // 0x18 + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, // 0x20 + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, // 0x28 + (func)_retonly, + 0 +}; + +struct export thevent_stub={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "thevent", + (func)_start, // entrypoint + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, // 0x08 + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + 0 +}; + +struct export thsemap_stub={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "thsemap", + (func)_start, // entrypoint + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, // 0x08 + (func)_retonly, + (func)_retonly, + (func)_retonly, + (func)_retonly, + 0 +}; + + +int _start() { + int x; + + _dprintf("_start\n"); + +// if (RegisterNonAutoLinkEntries(&thrdman_stub)) return 1; + if (RegisterLibraryEntries(&thbase_stub)) return 1; + + CpuSuspendIntr(&x); + + RegisterLibraryEntries(&thevent_stub); + RegisterLibraryEntries(&thsemap_stub); +// RegisterLibraryEntries(&thmsgbx_stub); +// RegisterLibraryEntries(&thfpool_stub); +// RegisterLibraryEntries(&thvpool_stub); + + CpuEnableIntr(); +} + +#if 0 +unsigned int ready; +unsigned int _263; +unsigned int _14; + +/////////////////////////////////////////////////////////////////////// +unsigned int *threadman_callx(){ + return &ready; +} + +/////////////////////////////////////////////////////////////////////// +int thbase_start(int argc, char* argv[]){ + int x; + + if (RegisterNonAutoLinkEntries(&thrdman_stub)) return 1; + if (RegisterLibraryEntries(&thbase_stub)) return 1; + + CpuSuspendIntr(&x); + + RegisterLibraryEntries(&thevent_stub); + RegisterLibraryEntries(&thsemap_stub); + RegisterLibraryEntries(&thmsgbx_stub); + RegisterLibraryEntries(&thfpool_stub); + RegisterLibraryEntries(&thvpool_stub); + + memset(&ready, 0, 1220); //305 x 4 => zero all bss + + _unk3=8; + _2=NULL; + LL_reset(&a); + LL_reset(&b); + LL_reset(&c); + LL_reset(&d); + LL_reset(&e); + LL_reset(&f); + LL_reset(&g); + LL_reset(&h); + LL_reset(&i); + LL_reset(&threads_list); + + for (j=0; j<128; j++) + LL_reset(&prio_lists[j]); + hp=CreateHeap(0x800, 1); //s3=&hp + th=allocheap(0x7F01, sizeof(struct TCB)); + th->id=++ids;//short + th->thp_stackSize=512; + th->stack=AllocSysMemory(ALLOC_LAST, 512, 0); + th->prio=th->thp_priority=127;//LOWEST_PRIORITY+1 + th->thp_attr=TH_C; + th->status=THS_READY; + th->gp=gp; + th->thp_entry=infinite_call; + th->area=th->stack + ((th->thp_stackSize >> 2) << 2) - 0xB8; + memset(th->area, 0, 0xB8); + th->area->field_00=0xFFFFFFFE; + th->area->H78=th->area->H74==&th->area->regs; + th->area->ExitThread=ExitThread; + th->area->gp=th->gp; + th->area->attr=(th->attr & TH_COP) | 0x404; + th->area->attr|=th->attr & TH_UMODE; + th->area->entry=th->thp_entry; + th->area->ei=1; + _2.next=th; + _2.prev=th; + enqueue(th); + + th=allocheap(0x7F01, sizeof(struct TCB)); + th->id=++ids;//short + th->thp_stackSize=QueryBlockSize(&j); + th->stack=QueryBlockTopAddress(&j); + th->thp_priority=8; //MODULE_INIT_PRIORITY + th->prio=1; //HIGHEST_PRIORITY + th->thp_attr=0x2000000; + th->status=THS_RUN; + th->gp=gp; + th->next_2=_2.next; + _2.next=th; + ready.prev=ready.next=th; + th->next=NULL; + th->prev=NULL; + SetCtxSwitchHandler(handler1_switchcontexts); + SetCtxSwitchReqHandler(handler2_morethan1ready); + sub_50A0(); + + efp.attr=2; + efp.initPattern=0; + efp.option=0; + systemStatusFlag=CreateEventFlag(&efp); + + if (v0=QueryBootMode(4)) + SetEventFlag(systemStatusFlag, 1<<(v0->H0 & 3));//H0 short + + loadcore_call20_registerFunc(&lc20_2, 2, 0); + loadcore_call20_registerFunc(&lc20_3, 3, 0); + CpuEnableIntr(); + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int lc20_2(){ + CpuEnableIntr(); + + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int lc20_3(int a){ + _dprintf("%s\n", __FUNCTION__); + CpuEnableIntr(); + + ChangeThreadPriority(0, 126);//LOWEST_PRIORIT + if (a->H0 == 0) { + for (;;) { + DelayThread(1000000); //never exit + } + } + return 0; +} + +/////////////////////////////////////////////////////////////////////// +void infinite_call(){ + infinite_call(); +} + +/////////////////////////////////////////////////////////////////////// +void syscall_32(){ + li $v0, 0x20 + syscall #0 +} + +/////////////////////////////////////////////////////////////////////// +void enqueue(struct TCB *th){ + flags[th->prio>>5] |= 1 << (th->prio & 0x1F); + LL_add_before(&prio_lists[th->prio], th); +} + +///////////////////////////////////////////////////////////////////////clone? +void enqueue2(struct TCB *th){ + flags[th->prio>>5] |= 1 << (th->prio & 0x1F); + LL_add_before(&prio_lists[th->prio], th); +} + +/////////////////////////////////////////////////////////////////////// +void unqueue(ll, prio){ + if (LL_0_1_elements(ll) + flags[prio>>5] &= ~(1 << (prio & 0x1F)) + LL_remove(ll); +} + +/////////////////////////////////////////////////////////////////////// +int run(struct TCB *th, int x){ + if (th->prio >= ready.next->prio){ + th->status=THS_READY; + enqueue(th); + CpuResumeIntr(x); + return KE_OK; + }else{ + ready.next->status=THS_READY; + enqueue2(ready.next); + th->status=THS_RUN; + ready->prev=th; + return syscall_32(0, 0, x, 0); + } +} + +/////////////////////////////////////////////////////////////////////// +int getHighestUsed(){ + int i; + for (i=0; i<4; i++) + if (flags[i]) + return (i<<5)+getHighestUsed_32(flags[i]); + return 128; //LOWEST_PRIORITY+2 +} + +/////////////////////////////////////////////////////////////////////// +void switch(){ + int hp; + + ready.prev=ready.next; + if (ready.next->status != THS_RUN){ + if (unk3 & 4) + Kprintf(" not THS_RUN "); + hp=getHighestUsed(); + if (hp<128){ + if (unk3 & 4) + Kprintf(" readyq = %x, newrun = %x:%d, prio = %d", + &prio_lists[hp], prio_lists[hp].next, prio_lists[hp].next->id, hp); + unqueue(prio_lists[hp].next, hp); + prio_lists[hp].next->status=THS_RUN; + ready.prev=prio_lists[hp].next; + }else + Kprintf("Panic: not found executable Thread\n"); + }else + if ((hp=getHighestUsed())<128){ + if (unk3 & 4) + Kprintf(" THS_RUN cp=%d : hp=%d ", ready.next->prio, hp); + if (hpprio){ + if (unk3 & 4) + Kprintf(" readyq = %x, newrun = %x:%d, prio = %d", + &prio_list[hp], prio_list[hp].next, prio_list[hp].next->id, hp); + unqueue(prio_list[hp].next, hp); + prio_list[hp].next->status=ready.next->status; + ready.prev=prio_lists[hp].next; + ready.next->status=THS_READY; + enqueue2(ready.next); + } + }else + Kprintf("Panic: not found ready Thread\n"); + if (unk3 & 4) + Kprintf("\n"); +} + +/////////////////////////////////////////////////////////////////////// +void stack_overflow(struct TCB *th){ + register ImageInfo ii; + register char *name; + Kprintf("\nThread (thid=%x, #%d) stack overflow\n Stack = %x, Stack size = %x, SP=%x\n", + (th<<5) | ((th->id & 0x3F) << 1) | 1, th->id & 0xFFFF, th->stack, th->thp_stackSize, th->area); + if ((ii=loadcore_call24_findImageInfo(th->thp_entry)) && + (name=ii->H04)) + Kprintf(" Module Name = %s\n", name); + __asm break #0x400 +); + +/////////////////////////////////////////////////////////////////////// +struct TCB *handler1_switchcontexts(struct AREA *area){ + s0=&unk4; + unk4++; + if (unk3 & 3){ + if (1==unk3 & 3) + Kprintf("[%3d->", ready.next->id); + if (2==unk3 & 3) + Kprintf("switch_context(%x:%x,pc=%x,ei=%x =>%x:%d)\n", + area, area->field_00, area->entry, area->ei, ready.next, ready.next->id); + } + ready.next->area=area; + if (area < ready.next->stack) + stack_overflow(ready.next); + if (ready.prev->next==NULL) + switch(); + if (ready.prev != ready.next){ + s0=GetTimerCounter(timid); + ready.next->field_30=moveregs(0, s0-www.prev, ready.next->field_30); + www.prev=s0; + } + if (unk3 & 3){ + if (unk3 & 3 == 1) + Kprintf("%3d]", ready.prev->id); + if (unk3 & 3 == 2) + Kprintf(" switch_context --> %x:%x,pc=%x,ei=%x =>%x:%d\n" + ready.prev->area, ready.prev->area->field_00, ready.prev->area->entry, + ready.prev->area->ei, ready.prev, ready.prev->id); + } + if (unk3 & 0x20){ + 0xBF802070=~(1 << ((ready.prev->id-1) & 7)); + } + return ready.prev; +} + +/////////////////////////////////////////////////////////////////////// +int handler2_morethan1ready(){ + return (0 < (ready.prev^ready.next)); + //return (ready.prev!=ready.next); +} + +/////////////////////////////////////////////////////////////////////// +void queue_on_prio(struct TCB *th, void *fld, int prio){ + register struct TCB *p; + + LL_remove(th); + for (p=fld->H14; p !=&fld->H14 && prio>=p->prio; p=p->next); + LL_add_before(p, th); +} + +///////////////////////////////////////////////////////////////////////[04] +int CreateThread(struct ThreadParam *param){ + int x; + register struct TCB *th; + + if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; + if (param->attr & 0x1CFFFFF7) return KE_ILLEGAL_ATTR; + if (param->initPriority-1>=126) return KE_ILLEGAL_PRIORITY; + if (param->entry & 3) return KE_ILLEGAL_ENTRY; + if (param->stackSize<0x130) return KE_ILLEGAL_STACK_SIZE; + + CpuSuspendIntr(&x); + if (th=allocheap(0x7F01, sizeof(struct TCB))){ //0x50 + param->stackSize = (param->stackSize+0xFF) & 0xFFFFFF00; + stack=AllocSysMemory(ALLOC_LAST, param->stackSize, NULL); + if (!stack) + freeheap(th); + } + if (!th || !stack){ + CpuResumeIntr(x); + return KE_NO_MEMORY; + } + th->id=++ids; + th->thp_entry=param->entry; + th->stack=stack; + th->thp_stackSize; + th->thp_priority=param->initPriority; + th->thp_attr=attr; + th->status=THS_DORMANT; + th->thp_option=param->option; + th->gp=$gp; + th->next_2=&_2; + _2.next=th; + LL_add_before(threads_list, th); + if (!(th->thp_attr & TH_NO_FILLSTACK)) + memset(th->stack, 0xFF, th->thp_stackSize-48); + CpuResumeIntr(x); + return ((int)th<<5) | ((th->id & 0x3F) << 1) | 1; +} + +///////////////////////////////////////////////////////////////////////[05] +int DeleteThread(int thid){ + int x; + register struct TCB *th, *p; + + if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; + if (thid==0) return KE_ILLEGAL_THID; + + CpuSuspendIntr(&x); + th=(struct TCB *)(thid>>7<<2); + if ((th->_7F01 != 0x7F01) || + (((thid>>1) & 0x3F) != (th->id & 0x3F)) || + (_2.prev == th)){ + CpuResumeIntr(x); + return KE_UNKNOWN_THID; + } + if (th->status != THS_DORMANT){ + CpuResumeIntr(x); + return KE_NOT_DORMANT; + } + FreeSysMemory(th->stack); + LL_remove(th); + + if (_2.next==th) + _2.next=th->next_2; + else + for (p=_2.next; p->next_2; p=p->next_2) + if (p->next_2==th){ + p->next_2=th->next_2; + break; + } + + freeheap(th); + CpuResumeIntr(x); + return KE_OK; +} + +/////////////////////////////////////////////////////////////////////// +int startThread(struct TCB *th,int x){ + th->field_1C=0; + th->field_20=0; + th->field_1E=0; + th->prio=thp_priority; + th->area->field_00=0xFFFFFFFE; + th->area->field_78=th->area->field_74=&th->area->regs; + th->area->ExitThread=ExitThread; + th->area->gp=th->gp; + th->area->attr=(th->attr & TH_COP) | 0x404; + th->area->attr|=th->attr & TH_UMODE; + th->area->entry->th->thp_entry; + th->ei=1; + LL_remove(th); + return run(th, x); +} + +///////////////////////////////////////////////////////////////////////[06] +int StartThread(int thid,u_long arg){ + int x; + register struct TCB *th, *p; + + if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; + if (thid==0) return KE_ILLEGAL_THID; + + CpuSuspendIntr(&x); + th=(struct TCB *)(thid>>7<<2); + if ((th->_7F01 != 0x7F01) || + (((thid>>1) & 0x3F) != (th->id & 0x3F))){ + CpuResumeIntr(x); + return KE_UNKNOWN_THID; + } + if (th->status != THS_DORMANT){ + CpuResumeIntr(x); + return KE_NOT_DORMANT; + } + th->area = th->stack + ((th->thp_stackSize >> 2) << 2) - 0xB8; + memset(th->area, 0, 0xB8); + th->area->arg=arg; + return startThread(th, x); +} + +///////////////////////////////////////////////////////////////////////[07] +int StartThreadArgs(int thid,int args,void *argp){ + int x; + register struct TCB *th, *p; + register void *_argp; + + if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; + if (thid==0) return KE_ILLEGAL_THID; + + CpuSuspendIntr(&x); + th=(struct TCB *)(thid>>7<<2); + if ((th->_7F01 != 0x7F01) || + (((thid>>1) & 0x3F) != (th->id & 0x3F))){ + CpuResumeIntr(x); + return KE_UNKNOWN_THID; + } + if (th->status != THS_DORMANT){ + CpuResumeIntr(x); + return KE_NOT_DORMANT; + } + + _argp=th->stack + ((th->thp_stackSize >> 2) - ((args+3) >> 2)) << 2 + if (args>0 && argp) + memcpy(_argp, argp, args); + + memset(th->area, 0, 0xB8); //BUG: these instructions should be switched! + th->area = th->stack + ((th->thp_stackSize >> 2) << 2) - 0xB8; + + th->area->arg =args; + th->area->argp=_argp; + return startThread(th, x); +} + +///////////////////////////////////////////////////////////////////////[08] +int ExitThread(){ + th=ready->next; + if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT + CpuSuspendIntr(&x); + th->status=THS_DORMANT; + LL_add_before(&threads_list, th); + a0=0; + do{ + ready.prev=0; + syscall_32(0, 0, x, 0); + Kprintf("panic ! Thread DORMANT !\n"); + __asm break #0x400 + while(1); +} + +///////////////////////////////////////////////////////////////////////[09] +int ExitDeleteThread(){ + return KE_ERROR; +} + +///////////////////////////////////////////////////////////////////////[10] +int TerminateThread(int thid){ + int x; + register struct TCB *th, *p; + + if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; + if (thid==0) return KE_ILLEGAL_THID; + + CpuSuspendIntr(&x); + th=(struct TCB *)(thid>>7<<2); + if (ready.next==th){ + CpuResumeIntr(x); + return KE_ILLEGAL_THID; + } + if ((th->_7F01 != 0x7F01) || + (((thid>>1) & 0x3F) != (th->id & 0x3F))){ + CpuResumeIntr(x); + return KE_UNKNOWN_THID; + } + if (th->status == THS_DORMANT){ + CpuResumeIntr(x); + return KE_DORMANT; + } + LL_remove(th); + if (th->status==THS_WAIT) + if (th->field_1C==2) + CancelAlarm(alarmhandler, th); + else + if (th->field_1C>=2) && (th->field_1C<8) + th->field_20->H10--; + th->status=THS_DORMANT; + LL_add_before(&threads_list, th); + + CpuResumeIntr(x); + return KE_OK; +} + +/////////////////////////////////////////////////////////////////////// +void LL_add_before(struct ll *list, struct ll *new){ + new->next=list; + new->prev=list->prev; + list->prev=new; + new->prev->next=new; +} + +///////////////////////////////////////////////////////////////////////:) +int getHighestUsed_32(int flags_32){ + v=-4; + do{ + i=flags_32<<28; + flags_32>>=4; + v+=4; + }while(i==0); + return v + ((0x1020103 >> ((i>>26) & 0x1C)) & 0xF); +} + +#endif diff --git a/fps2bios/kernel/iopload/timrman/Makefile b/fps2bios/kernel/iopload/timrman/Makefile index 1113b6c434..1a1d073863 100644 --- a/fps2bios/kernel/iopload/timrman/Makefile +++ b/fps2bios/kernel/iopload/timrman/Makefile @@ -1,59 +1,59 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include - -IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 -IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include -IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -IOPLINK = $(IOPLD) -dc -IOPASFLAGS := -EL -G0 - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: timrman - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib -LDADD = -OBJECTS = timrman.o ../iopdebug.o ../libkernel/iop_loadcore.o ../libkernel/iop_intrman.o - -timrman: $(OBJECTS) - $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/TIMRMAN - -%.o: %.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - -%.o : %.s - $(IOPAS) $(IOPASFLAGS) $< -o $@ - -clean: - rm -f $(OBJECTS) - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: timrman + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/iop/lib -L$(NEWLIB)/lib +LDADD = +OBJECTS = timrman.o ../iopdebug.o ../libkernel/iop_loadcore.o ../libkernel/iop_intrman.o + +timrman: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/TIMRMAN + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopload/timrman/timrman.c b/fps2bios/kernel/iopload/timrman/timrman.c index 63e0f23140..572aa1597b 100644 --- a/fps2bios/kernel/iopload/timrman/timrman.c +++ b/fps2bios/kernel/iopload/timrman/timrman.c @@ -1,234 +1,234 @@ -//[module] TIMEMANI -//[processor] IOP -//[type] ELF-IRX -//[name] Timer_Manager -//[version] 0x101 -//[memory map] 0xBF801100, 0xBF801110, 0xBF801120, -// 0xBF801450 -// 0xBF801480, 0xBF801490, 0xBF8014A0, -// 0xBF8014B0, 0xBF8014C0 -//[handlers] - -//[entry point] timrman_start, timrman_stub -//[made by] [RO]man (roman_ps2dev@hotmail.com) 13 October 2002 - -#include - -#include "iopdebug.h" -#include "kloadcore.h" -#include "kintrman.h" - -#include "err.h" -#include "ktimrman.h" - -#define CONFIG_1450 (*(volatile int*)0xBF801450) - -struct TIMRMAN{ - int hwreg; - char source, size; - short prescale; - int allocated; -} t[6]={ -{RTC2, TC_SYSCLOCK, TIMER_SIZE_16, TIMER_PRESCALE_8, 0}, -{RTC5, TC_SYSCLOCK, TIMER_SIZE_32, TIMER_PRESCALE_256, 0}, -{RTC4, TC_SYSCLOCK, TIMER_SIZE_32, TIMER_PRESCALE_256, 0}, -{RTC3, TC_SYSCLOCK|TC_HLINE, TIMER_SIZE_32, TIMER_PRESCALE_1, 0}, -{RTC0, TC_SYSCLOCK|TC_PIXEL|TC_HOLD, TIMER_SIZE_16, TIMER_PRESCALE_1, 0}, -{RTC1, TC_SYSCLOCK|TC_HLINE|TC_HOLD, TIMER_SIZE_16, TIMER_PRESCALE_1, 0} -}; - -int _start(int argc, char* argv[]); - -///////////////////////////////////////////////////////////////////////[03] -void *GetTimersTable(){ - return t; //address of the array -} - -///////////////////////////////////////////////////////////////////////[04] -int AllocHardTimer(int source, int size, int prescale){ - register int i; - int x; - - if (QueryIntrContext()) return ERROR_INTR_CONTEXT; //intrman - - CpuSuspendIntr(&x); //intrman - - for (i=0; i<6; i++) - if (!t[i].allocated && (t[i].source & source) && - (t[i].size==size) && (t[i].prescale>=prescale)){ - t[i].allocated++; //u8 - CpuResumeIntr(x); //intrman - return t[i].hwreg>>2; - } - - CpuResumeIntr(x); //intrman - return ERROR_NO_TIMER; -} - -///////////////////////////////////////////////////////////////////////[05] -int ReferHardTimer(int source, int size, int mode, int modemask){ - register int i; - int x; - - if (QueryIntrContext()) return ERROR_INTR_CONTEXT; //intrman - - CpuSuspendIntr(&x); //intrman - - for (i=0; i<6; i++) - if (t[i].allocated && (t[i].source & source) && (t[i].size==size) && - (int)(GetTimerStatus(t[i].hwreg>>2) & modemask)==mode){ - t[i].allocated++; //u8 - CpuResumeIntr(x); //intrman - return t[i].hwreg>>2; - } - - CpuResumeIntr(x); //intrman - return ERROR_NO_TIMER; -} - -///////////////////////////////////////////////////////////////////////[10] -int GetHardTimerIntrCode(int timid){ - switch(timid<<2){ - case RTC2: return INT_RTC2; - case RTC0: return INT_RTC0; - case RTC1: return INT_RTC1; - - case RTC4: return INT_RTC4; - case RTC3: return INT_RTC3; - case RTC5: return INT_RTC5; - } - return ERROR_UNK; -} - -///////////////////////////////////////////////////////////////////////[06] -int FreeHardTimer(int timid){ - register int i; - int x; - - if (QueryIntrContext()) return ERROR_INTR_CONTEXT; //intrman - - for (i=0; i<6; i++) - if (t[i].hwreg==(timid<<2)) - break; - - if ((i<6) && (t[i].allocated)){ - CpuSuspendIntr(&x); //intrman - t[i].allocated--; - CpuResumeIntr(x); //intrman - return ERROR_OK; - } - return ERROR_NO_TIMER; - -} - -///////////////////////////////////////////////////////////////////////[07] -void SetTimerMode(int timid, int mode){ - *(volatile short*)((timid<<2)+4) = mode; -} - -///////////////////////////////////////////////////////////////////////[08] -unsigned int GetTimerStatus(int timid){ - return *(volatile unsigned short*)((timid<<2)+4); -} - -///////////////////////////////////////////////////////////////////////[09] -void SetTimerCounter(int timid, unsigned int count){ - if ((timid<<2) < RTC3) - *(volatile short*)((timid<<2)+0)=count; - else - *(volatile int*)((timid<<2)+0)=count; -} - -///////////////////////////////////////////////////////////////////////[0A] -unsigned int GetTimerCounter(int timid){ - if ((timid<<2) < RTC3) - return *(volatile short*)((timid<<2)+0); - else - return *(volatile int*)((timid<<2)+0); -} - -///////////////////////////////////////////////////////////////////////[0B] -void SetTimerCompare(int timid, unsigned int compare){ - if ((timid<<2)+8 < RTC3) - *(volatile short*)((timid<<2)+8)=compare; - else - *(volatile int*)((timid<<2)+8)=compare; -} - -///////////////////////////////////////////////////////////////////////[0C] -unsigned int GetTimerCompare(int timid){ - if ((timid<<2)+8 < RTC3) - return *(volatile short*)((timid<<2)+8); - else - return *(volatile int*)((timid<<2)+8); -} - -///////////////////////////////////////////////////////////////////////[0D] -void SetHoldMode(int holdnum, int mode){ - RTC_HOLDMODE=(RTC_HOLDMODE & - ( ~(0xF << (holdnum*4)))) | - ((mode & 0xF) << (holdnum*4)); -} - -///////////////////////////////////////////////////////////////////////[0E] -unsigned long GetHoldMode(int holdnum){ - return (RTC_HOLDMODE >> (holdnum*4)) & 0xF; -} - -///////////////////////////////////////////////////////////////////////[0F] -unsigned long GetHoldReg(int holdnum){ - return *(volatile unsigned int*)(RTC_HOLDREGS + (holdnum*4)); -} - -///////////////////////////////////////////////////////////////////////[01,02] -void _retonly(){} - -//////////////////////////////entrypoint/////////////////////////////// -struct export timrman_stub={ - 0x41C00000, - 0, - VER(1, 1), // 1.1 => 0x101 - 0, - "timrman", - (func)_start, // entrypoint - (func)_retonly, - (func)_retonly, - (func)GetTimersTable, - (func)AllocHardTimer, - (func)ReferHardTimer, - (func)FreeHardTimer, - (func)SetTimerMode, - (func)GetTimerStatus, - (func)SetTimerCounter, - (func)GetTimerCounter, - (func)SetTimerCompare, - (func)GetTimerCompare, - (func)SetHoldMode, - (func)GetHoldMode, - (func)GetHoldReg, - (func)GetHardTimerIntrCode, - 0 -}; - -//////////////////////////////entrypoint///////////////////////////////[00] -int _start(int argc, char* argv[]){ - int i; - u32 PRid; - - __asm__ ( - "mfc0 %0, $15\n" - : "=r"(PRid) : - ); - - - if ((PRid<0x10) || (CONFIG_1450 & 8)) return 1; - - for (i=5; i>=0; i--) t[i].allocated=0; - - if( RegisterLibraryEntries(&timrman_stub) > 0 ) - return 1; - - EnableIntr(INT_RTC5); - - return 0; //loadcore -} - +//[module] TIMEMANI +//[processor] IOP +//[type] ELF-IRX +//[name] Timer_Manager +//[version] 0x101 +//[memory map] 0xBF801100, 0xBF801110, 0xBF801120, +// 0xBF801450 +// 0xBF801480, 0xBF801490, 0xBF8014A0, +// 0xBF8014B0, 0xBF8014C0 +//[handlers] - +//[entry point] timrman_start, timrman_stub +//[made by] [RO]man (roman_ps2dev@hotmail.com) 13 October 2002 + +#include + +#include "iopdebug.h" +#include "kloadcore.h" +#include "kintrman.h" + +#include "err.h" +#include "ktimrman.h" + +#define CONFIG_1450 (*(volatile int*)0xBF801450) + +struct TIMRMAN{ + int hwreg; + char source, size; + short prescale; + int allocated; +} t[6]={ +{RTC2, TC_SYSCLOCK, TIMER_SIZE_16, TIMER_PRESCALE_8, 0}, +{RTC5, TC_SYSCLOCK, TIMER_SIZE_32, TIMER_PRESCALE_256, 0}, +{RTC4, TC_SYSCLOCK, TIMER_SIZE_32, TIMER_PRESCALE_256, 0}, +{RTC3, TC_SYSCLOCK|TC_HLINE, TIMER_SIZE_32, TIMER_PRESCALE_1, 0}, +{RTC0, TC_SYSCLOCK|TC_PIXEL|TC_HOLD, TIMER_SIZE_16, TIMER_PRESCALE_1, 0}, +{RTC1, TC_SYSCLOCK|TC_HLINE|TC_HOLD, TIMER_SIZE_16, TIMER_PRESCALE_1, 0} +}; + +int _start(int argc, char* argv[]); + +///////////////////////////////////////////////////////////////////////[03] +void *GetTimersTable(){ + return t; //address of the array +} + +///////////////////////////////////////////////////////////////////////[04] +int AllocHardTimer(int source, int size, int prescale){ + register int i; + int x; + + if (QueryIntrContext()) return ERROR_INTR_CONTEXT; //intrman + + CpuSuspendIntr(&x); //intrman + + for (i=0; i<6; i++) + if (!t[i].allocated && (t[i].source & source) && + (t[i].size==size) && (t[i].prescale>=prescale)){ + t[i].allocated++; //u8 + CpuResumeIntr(x); //intrman + return t[i].hwreg>>2; + } + + CpuResumeIntr(x); //intrman + return ERROR_NO_TIMER; +} + +///////////////////////////////////////////////////////////////////////[05] +int ReferHardTimer(int source, int size, int mode, int modemask){ + register int i; + int x; + + if (QueryIntrContext()) return ERROR_INTR_CONTEXT; //intrman + + CpuSuspendIntr(&x); //intrman + + for (i=0; i<6; i++) + if (t[i].allocated && (t[i].source & source) && (t[i].size==size) && + (int)(GetTimerStatus(t[i].hwreg>>2) & modemask)==mode){ + t[i].allocated++; //u8 + CpuResumeIntr(x); //intrman + return t[i].hwreg>>2; + } + + CpuResumeIntr(x); //intrman + return ERROR_NO_TIMER; +} + +///////////////////////////////////////////////////////////////////////[10] +int GetHardTimerIntrCode(int timid){ + switch(timid<<2){ + case RTC2: return INT_RTC2; + case RTC0: return INT_RTC0; + case RTC1: return INT_RTC1; + + case RTC4: return INT_RTC4; + case RTC3: return INT_RTC3; + case RTC5: return INT_RTC5; + } + return ERROR_UNK; +} + +///////////////////////////////////////////////////////////////////////[06] +int FreeHardTimer(int timid){ + register int i; + int x; + + if (QueryIntrContext()) return ERROR_INTR_CONTEXT; //intrman + + for (i=0; i<6; i++) + if (t[i].hwreg==(timid<<2)) + break; + + if ((i<6) && (t[i].allocated)){ + CpuSuspendIntr(&x); //intrman + t[i].allocated--; + CpuResumeIntr(x); //intrman + return ERROR_OK; + } + return ERROR_NO_TIMER; + +} + +///////////////////////////////////////////////////////////////////////[07] +void SetTimerMode(int timid, int mode){ + *(volatile short*)((timid<<2)+4) = mode; +} + +///////////////////////////////////////////////////////////////////////[08] +unsigned int GetTimerStatus(int timid){ + return *(volatile unsigned short*)((timid<<2)+4); +} + +///////////////////////////////////////////////////////////////////////[09] +void SetTimerCounter(int timid, unsigned int count){ + if ((timid<<2) < RTC3) + *(volatile short*)((timid<<2)+0)=count; + else + *(volatile int*)((timid<<2)+0)=count; +} + +///////////////////////////////////////////////////////////////////////[0A] +unsigned int GetTimerCounter(int timid){ + if ((timid<<2) < RTC3) + return *(volatile short*)((timid<<2)+0); + else + return *(volatile int*)((timid<<2)+0); +} + +///////////////////////////////////////////////////////////////////////[0B] +void SetTimerCompare(int timid, unsigned int compare){ + if ((timid<<2)+8 < RTC3) + *(volatile short*)((timid<<2)+8)=compare; + else + *(volatile int*)((timid<<2)+8)=compare; +} + +///////////////////////////////////////////////////////////////////////[0C] +unsigned int GetTimerCompare(int timid){ + if ((timid<<2)+8 < RTC3) + return *(volatile short*)((timid<<2)+8); + else + return *(volatile int*)((timid<<2)+8); +} + +///////////////////////////////////////////////////////////////////////[0D] +void SetHoldMode(int holdnum, int mode){ + RTC_HOLDMODE=(RTC_HOLDMODE & + ( ~(0xF << (holdnum*4)))) | + ((mode & 0xF) << (holdnum*4)); +} + +///////////////////////////////////////////////////////////////////////[0E] +unsigned long GetHoldMode(int holdnum){ + return (RTC_HOLDMODE >> (holdnum*4)) & 0xF; +} + +///////////////////////////////////////////////////////////////////////[0F] +unsigned long GetHoldReg(int holdnum){ + return *(volatile unsigned int*)(RTC_HOLDREGS + (holdnum*4)); +} + +///////////////////////////////////////////////////////////////////////[01,02] +void _retonly(){} + +//////////////////////////////entrypoint/////////////////////////////// +struct export timrman_stub={ + 0x41C00000, + 0, + VER(1, 1), // 1.1 => 0x101 + 0, + "timrman", + (func)_start, // entrypoint + (func)_retonly, + (func)_retonly, + (func)GetTimersTable, + (func)AllocHardTimer, + (func)ReferHardTimer, + (func)FreeHardTimer, + (func)SetTimerMode, + (func)GetTimerStatus, + (func)SetTimerCounter, + (func)GetTimerCounter, + (func)SetTimerCompare, + (func)GetTimerCompare, + (func)SetHoldMode, + (func)GetHoldMode, + (func)GetHoldReg, + (func)GetHardTimerIntrCode, + 0 +}; + +//////////////////////////////entrypoint///////////////////////////////[00] +int _start(int argc, char* argv[]){ + int i; + u32 PRid; + + __asm__ ( + "mfc0 %0, $15\n" + : "=r"(PRid) : + ); + + + if ((PRid<0x10) || (CONFIG_1450 & 8)) return 1; + + for (i=5; i>=0; i--) t[i].allocated=0; + + if( RegisterLibraryEntries(&timrman_stub) > 0 ) + return 1; + + EnableIntr(INT_RTC5); + + return 0; //loadcore +} + diff --git a/fps2bios/kernel/iopload/vblank/Makefile b/fps2bios/kernel/iopload/vblank/Makefile index e947fc5dc3..07853940e4 100644 --- a/fps2bios/kernel/iopload/vblank/Makefile +++ b/fps2bios/kernel/iopload/vblank/Makefile @@ -1,61 +1,61 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include - -IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 -IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include -IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -IOPLINK = $(IOPLD) -dc -IOPASFLAGS := -EL -G0 - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: vblank - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -LDADD = -OBJECTS = vblank.o ../iopdebug.o ../libkernel/iop_loadcore.o \ - ../libkernel/iop_intrman.o ../libkernel/iop_sysclib.o \ - ../libkernel/iop_thbase.o ../libkernel/iop_thevent.o - -vblank: $(OBJECTS) - $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/VBLANK - -%.o: %.c - $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< - -%.o : %.s - $(IOPAS) $(IOPASFLAGS) $< -o $@ - -clean: - rm -f $(OBJECTS) - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include + +IOPCFLAGS = -O2 -fomit-frame-pointer -nostartfiles -G0 +IOPINCLUDES = -I. -I../include -I$(PS2LIB)/common/include -I$(PS2LIB)/iop/include +IOPCOMPILE = $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) +IOPLINK = $(IOPLD) -dc +IOPASFLAGS := -EL -G0 + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: vblank + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = +LDADD = +OBJECTS = vblank.o ../iopdebug.o ../libkernel/iop_loadcore.o \ + ../libkernel/iop_intrman.o ../libkernel/iop_sysclib.o \ + ../libkernel/iop_thbase.o ../libkernel/iop_thevent.o + +vblank: $(OBJECTS) + $(IOPLINK) $(OBJECTS) $(LDFLAGS) $(LDADD) -o ../../../build/VBLANK + +%.o: %.c + $(IOPCC) $(IOPINCLUDES) $(IOPCFLAGS) -o $@ -c $< + +%.o : %.s + $(IOPAS) $(IOPASFLAGS) $< -o $@ + +clean: + rm -f $(OBJECTS) + diff --git a/fps2bios/kernel/iopstart.c b/fps2bios/kernel/iopstart.c index 3b3da90522..f872ab81aa 100644 --- a/fps2bios/kernel/iopstart.c +++ b/fps2bios/kernel/iopstart.c @@ -1,66 +1,66 @@ -#include -#include "romdir.h" - -static void Kputc(u8 c) { - *((u8*)0x1f80380c) = c; -} - -static void Kputs(u8 *s) { - while (*s != 0) { - Kputc(*s++); - } -} - -static void Kmemcpy(void *dest, const void *src, int n) { - const u8 *s = (u8*)src; - u8 *d = (u8*)dest; - - while (n) { - *d++ = *s++; n--; - } -} - -static void _iopstart() { - struct rominfo ri; - u8 *str; - - // setup iop - *(char*)0xbf802070 = 9; - *(int*)0xfffe0130 = 0xcc4; - *(int*)0xfffe0130 = 0xcc0; - if( (*(int*)0xbf801450) & 8 ) - *(int*)0xfffe0130 = 0x1e988; - else - *(int*)0xfffe0130 = 0x1edd8; - - romdirGetFile("ROMVER", &ri); - str = (u8*)(0xbfc00000 + ri.fileOffset); - Kputs("iopstart: fps2bios v"); - Kputc(str[1]); Kputc('.'); Kputc(str[3]); Kputc('\n'); - - // note, IOPBOOT has to be linked at location ri.fileOffset=0x600!! - romdirGetFile("IOPBOOT", &ri); - - Kputs("_iopstart: loading IOPBOOT to 0xbfc0a180\n"); - //Kmemcpy((void*)0x80000000, (void*)(0xbfc00000 + ri.fileOffset), ri.fileSize); - - __asm__ ( - "li $a0, 2\n" // 2Mb - "move $a1, $0\n" - "move $a2, $0\n" - "move $a3, $0\n" - "move $26, %0\n" - "jr $26\n" - "nop\n" : : "r"(0xbfc00000+ri.fileOffset)); - for (;;); -} - -__asm__ ( - ".global iopstart\n" - "iopstart:\n" - "li $sp, 0x001fffc0\n" // (2<<20)-0x40 - "move $fp, $sp\n" - "j _iopstart\n" - "nop\n"); - - +#include +#include "romdir.h" + +static void Kputc(u8 c) { + *((u8*)0x1f80380c) = c; +} + +static void Kputs(u8 *s) { + while (*s != 0) { + Kputc(*s++); + } +} + +static void Kmemcpy(void *dest, const void *src, int n) { + const u8 *s = (u8*)src; + u8 *d = (u8*)dest; + + while (n) { + *d++ = *s++; n--; + } +} + +static void _iopstart() { + struct rominfo ri; + u8 *str; + + // setup iop + *(char*)0xbf802070 = 9; + *(int*)0xfffe0130 = 0xcc4; + *(int*)0xfffe0130 = 0xcc0; + if( (*(int*)0xbf801450) & 8 ) + *(int*)0xfffe0130 = 0x1e988; + else + *(int*)0xfffe0130 = 0x1edd8; + + romdirGetFile("ROMVER", &ri); + str = (u8*)(0xbfc00000 + ri.fileOffset); + Kputs("iopstart: fps2bios v"); + Kputc(str[1]); Kputc('.'); Kputc(str[3]); Kputc('\n'); + + // note, IOPBOOT has to be linked at location ri.fileOffset=0x600!! + romdirGetFile("IOPBOOT", &ri); + + Kputs("_iopstart: loading IOPBOOT to 0xbfc0a180\n"); + //Kmemcpy((void*)0x80000000, (void*)(0xbfc00000 + ri.fileOffset), ri.fileSize); + + __asm__ ( + "li $a0, 2\n" // 2Mb + "move $a1, $0\n" + "move $a2, $0\n" + "move $a3, $0\n" + "move $26, %0\n" + "jr $26\n" + "nop\n" : : "r"(0xbfc00000+ri.fileOffset)); + for (;;); +} + +__asm__ ( + ".global iopstart\n" + "iopstart:\n" + "li $sp, 0x001fffc0\n" // (2<<20)-0x40 + "move $fp, $sp\n" + "j _iopstart\n" + "nop\n"); + + diff --git a/fps2bios/kernel/romdir.c b/fps2bios/kernel/romdir.c index 2487288f0f..b23a5b2722 100644 --- a/fps2bios/kernel/romdir.c +++ b/fps2bios/kernel/romdir.c @@ -1,43 +1,43 @@ -/*************************************************************** -* romdir.c, based over Alex Lau (http://alexlau.8k.com) RomDir * -****************************************************************/ -#include "romdir.h" - -struct romdir *romdirInit() { - u8 *mem; - - for (mem=(u8*)0xbfc00000; (u32)mem<0xbfc01000; mem++) { - if (mem[0] == 'R' && mem[1] == 'E' && - mem[2] == 'S' && mem[3] == 'E' && - mem[4] == 'T') - break; - } - if ((u32)mem == 0xbfc01000) return NULL; - - return (struct romdir*)mem; -} - -struct rominfo *romdirGetFile(char *name, struct rominfo *ri) { - struct romdir *rd; - struct romdir *base; - int i; - - base = romdirInit(); - if (base == NULL) return NULL; - - ri->fileOffset = 0; - for (rd = base; rd->fileName[0] != 0; rd++) { - for (i=0; i<10 && name[i] != 0; i++) { - if (rd->fileName[i] != name[i]) break; - } - if (rd->fileName[i] != name[i]) { - ri->fileOffset+= (rd->fileSize + 15) & ~0xF; - continue; - } - - ri->fileSize = rd->fileSize; - return ri; - } - - return NULL; -} +/*************************************************************** +* romdir.c, based over Alex Lau (http://alexlau.8k.com) RomDir * +****************************************************************/ +#include "romdir.h" + +struct romdir *romdirInit() { + u8 *mem; + + for (mem=(u8*)0xbfc00000; (u32)mem<0xbfc01000; mem++) { + if (mem[0] == 'R' && mem[1] == 'E' && + mem[2] == 'S' && mem[3] == 'E' && + mem[4] == 'T') + break; + } + if ((u32)mem == 0xbfc01000) return NULL; + + return (struct romdir*)mem; +} + +struct rominfo *romdirGetFile(char *name, struct rominfo *ri) { + struct romdir *rd; + struct romdir *base; + int i; + + base = romdirInit(); + if (base == NULL) return NULL; + + ri->fileOffset = 0; + for (rd = base; rd->fileName[0] != 0; rd++) { + for (i=0; i<10 && name[i] != 0; i++) { + if (rd->fileName[i] != name[i]) break; + } + if (rd->fileName[i] != name[i]) { + ri->fileOffset+= (rd->fileSize + 15) & ~0xF; + continue; + } + + ri->fileSize = rd->fileSize; + return ri; + } + + return NULL; +} diff --git a/fps2bios/kernel/romdir.h b/fps2bios/kernel/romdir.h index 8249989e78..ef03a3223d 100644 --- a/fps2bios/kernel/romdir.h +++ b/fps2bios/kernel/romdir.h @@ -1,20 +1,20 @@ -#ifndef __ROMDIR_H__ -#define __ROMDIR_H__ - -#include - -struct romdir { - /*following variable must place in designed order*/ - u8 fileName[10]; - u16 extInfoSize; - u32 fileSize; -} __attribute__ ((packed)); - -struct rominfo { - u32 fileOffset; - u32 fileSize; -}; - -struct rominfo *romdirGetFile(char *name, struct rominfo *ri); - -#endif /* __ROMDIR_H__ */ +#ifndef __ROMDIR_H__ +#define __ROMDIR_H__ + +#include + +struct romdir { + /*following variable must place in designed order*/ + u8 fileName[10]; + u16 extInfoSize; + u32 fileSize; +} __attribute__ ((packed)); + +struct rominfo { + u32 fileOffset; + u32 fileSize; +}; + +struct rominfo *romdirGetFile(char *name, struct rominfo *ri); + +#endif /* __ROMDIR_H__ */ diff --git a/fps2bios/kernel/start.c b/fps2bios/kernel/start.c index 81277910f8..33481cb496 100644 --- a/fps2bios/kernel/start.c +++ b/fps2bios/kernel/start.c @@ -1,30 +1,30 @@ -#include -void eestart() __attribute__ ((noreturn)); -void iopstart() __attribute__ ((noreturn)); - -__asm__ ( - ".org 0\n" - ".set noat\n" - - ".global _start\n" - "_start:\n" - "mfc0 $at, $15\n" - "sltiu $at, 0x59\n" - "bne $at, $0, __iopstart\n" - "j eestart\n" - "nop\n" - "__iopstart:\n" - "j iopstart\n" - "nop\n"); - - -/* -void _start() __attribute__ ((noreturn)); -void _start() { - register unsigned long PRid; - - __asm__ ("mfc0 %0, $15" : "=r"(PRid) : ); - if (PRid >= 0x59) eestart(); - else iopstart(); -}*/ - +#include +void eestart() __attribute__ ((noreturn)); +void iopstart() __attribute__ ((noreturn)); + +__asm__ ( + ".org 0\n" + ".set noat\n" + + ".global _start\n" + "_start:\n" + "mfc0 $at, $15\n" + "sltiu $at, 0x59\n" + "bne $at, $0, __iopstart\n" + "j eestart\n" + "nop\n" + "__iopstart:\n" + "j iopstart\n" + "nop\n"); + + +/* +void _start() __attribute__ ((noreturn)); +void _start() { + register unsigned long PRid; + + __asm__ ("mfc0 %0, $15" : "=r"(PRid) : ); + if (PRid >= 0x59) eestart(); + else iopstart(); +}*/ + diff --git a/fps2bios/loader/Makefile b/fps2bios/loader/Makefile index 6aab6f23dc..c441a5ba21 100644 --- a/fps2bios/loader/Makefile +++ b/fps2bios/loader/Makefile @@ -1,57 +1,57 @@ -# _____ ___ ____ -# ____| | ____| PSX2 OpenSource Project -# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) -# ------------------------------------------------------------------------ - -# Generated automatically from Makefile.in by configure. -#.SUFFIXES: .S .c .o .s .elf .irx - -# ------------------------------------------------------------------------ -# COMPILERS - -IOPCC = iop-gcc -IOPAR = iop-ar -IOPLD = iop-ld -IOPAS = iop-as -EECC = ee-gcc -EEAR = ee-ar -EELD = ee-gcc - - -# ------------------------------------------------------------------------ -# DIRECTORY PATHS & FLAGS - - -EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -G0 -D_EE -EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include - - -# ------------------------------------------------------------------------ -# PROJECTS TO BUILD - -all: loader - - -# ------------------------------------------------------------------------ -# KERNEL BUILD INSTRUCTIONS - -LDFLAGS = -L$(PS2LIB)/ee/lib -L$(NEWLIB)/lib -L$(LIBITO)/lib -LDADD = -lkernel -lmc -lkernel -lpad -lc -lkernel -OBJECTS = loader.o menu.o eedebug.o crt0.o romdir.o -DEST = ../build/LOADER - -loader: $(OBJECTS) - $(EELD) -T linkfile $(EECFLAGS) $(OBJECTS) $(LDFLAGS) $(LDADD) -o $(DEST) - -%.o: %.c - $(EECC) $(EEINCLUDES) $(EECFLAGS) -o $@ -c $< - -%.o: %.s - $(EECC) $(EEINCLUDES) $(EECFLAGS) -o $@ -c $< - - -clean: - rm -f $(OBJECTS) $(DEST) - - - +# _____ ___ ____ +# ____| | ____| PSX2 OpenSource Project +# | ___| |____ (C)2002, David Ryan ( Oobles@hotmail.com ) +# ------------------------------------------------------------------------ + +# Generated automatically from Makefile.in by configure. +#.SUFFIXES: .S .c .o .s .elf .irx + +# ------------------------------------------------------------------------ +# COMPILERS + +IOPCC = iop-gcc +IOPAR = iop-ar +IOPLD = iop-ld +IOPAS = iop-as +EECC = ee-gcc +EEAR = ee-ar +EELD = ee-gcc + + +# ------------------------------------------------------------------------ +# DIRECTORY PATHS & FLAGS + + +EECFLAGS = -O2 -fomit-frame-pointer -mips3 -EL -nostartfiles -G0 -D_EE +EEINCLUDES = -I. -Iinclude -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I$(NEWLIB)/include + + +# ------------------------------------------------------------------------ +# PROJECTS TO BUILD + +all: loader + + +# ------------------------------------------------------------------------ +# KERNEL BUILD INSTRUCTIONS + +LDFLAGS = -L$(PS2LIB)/ee/lib -L$(NEWLIB)/lib -L$(LIBITO)/lib +LDADD = -lkernel -lmc -lkernel -lpad -lc -lkernel +OBJECTS = loader.o menu.o eedebug.o crt0.o romdir.o +DEST = ../build/LOADER + +loader: $(OBJECTS) + $(EELD) -T linkfile $(EECFLAGS) $(OBJECTS) $(LDFLAGS) $(LDADD) -o $(DEST) + +%.o: %.c + $(EECC) $(EEINCLUDES) $(EECFLAGS) -o $@ -c $< + +%.o: %.s + $(EECC) $(EEINCLUDES) $(EECFLAGS) -o $@ -c $< + + +clean: + rm -f $(OBJECTS) $(DEST) + + + diff --git a/fps2bios/loader/eedebug.c b/fps2bios/loader/eedebug.c index 24bc361406..8be3c068b8 100644 --- a/fps2bios/loader/eedebug.c +++ b/fps2bios/loader/eedebug.c @@ -1,31 +1,31 @@ - -#include -#include -#include - - -void __putc(u8 c) { - while (*((u32*)0x1000f130) & 0x8000) { __asm__ ("nop\nnop\nnop\n"); } - - *((u8*)0x1000f180) = c; -} - -void __puts(u8 *s) { - while (*s != 0) { - __putc(*s++); - } -} - -int __printf(const char *format, ...) { - char buf[4096]; - va_list args; - int ret; - - va_start(args, format); - ret = vsnprintf(buf, 4096, format, args); - va_end(args); - - __puts(buf); - return ret; -} - + +#include +#include +#include + + +void __putc(u8 c) { + while (*((u32*)0x1000f130) & 0x8000) { __asm__ ("nop\nnop\nnop\n"); } + + *((u8*)0x1000f180) = c; +} + +void __puts(u8 *s) { + while (*s != 0) { + __putc(*s++); + } +} + +int __printf(const char *format, ...) { + char buf[4096]; + va_list args; + int ret; + + va_start(args, format); + ret = vsnprintf(buf, 4096, format, args); + va_end(args); + + __puts(buf); + return ret; +} + diff --git a/fps2bios/loader/include/eedebug.h b/fps2bios/loader/include/eedebug.h index dfe853c609..503f65e062 100644 --- a/fps2bios/loader/include/eedebug.h +++ b/fps2bios/loader/include/eedebug.h @@ -1,12 +1,12 @@ -#ifndef __EEDEBUG_H__ -#define __EEDEBUG_H__ - -#include -#include - - -void __putc(u8 c); -void __puts(u8 *s); -int __printf(const char *format, ...); - -#endif /* __EEDEBUG_H__ */ +#ifndef __EEDEBUG_H__ +#define __EEDEBUG_H__ + +#include +#include + + +void __putc(u8 c); +void __puts(u8 *s); +int __printf(const char *format, ...); + +#endif /* __EEDEBUG_H__ */ diff --git a/fps2bios/loader/include/menu.h b/fps2bios/loader/include/menu.h index 3e2d2e8848..6c08f4bdfd 100644 --- a/fps2bios/loader/include/menu.h +++ b/fps2bios/loader/include/menu.h @@ -1,8 +1,8 @@ -#ifndef __MENU_H__ -#define __MENU_H__ - -#include - -int menuStart(); - -#endif /* __MENU_H__ */ +#ifndef __MENU_H__ +#define __MENU_H__ + +#include + +int menuStart(); + +#endif /* __MENU_H__ */ diff --git a/fps2bios/loader/include/romdir.h b/fps2bios/loader/include/romdir.h index 8249989e78..ef03a3223d 100644 --- a/fps2bios/loader/include/romdir.h +++ b/fps2bios/loader/include/romdir.h @@ -1,20 +1,20 @@ -#ifndef __ROMDIR_H__ -#define __ROMDIR_H__ - -#include - -struct romdir { - /*following variable must place in designed order*/ - u8 fileName[10]; - u16 extInfoSize; - u32 fileSize; -} __attribute__ ((packed)); - -struct rominfo { - u32 fileOffset; - u32 fileSize; -}; - -struct rominfo *romdirGetFile(char *name, struct rominfo *ri); - -#endif /* __ROMDIR_H__ */ +#ifndef __ROMDIR_H__ +#define __ROMDIR_H__ + +#include + +struct romdir { + /*following variable must place in designed order*/ + u8 fileName[10]; + u16 extInfoSize; + u32 fileSize; +} __attribute__ ((packed)); + +struct rominfo { + u32 fileOffset; + u32 fileSize; +}; + +struct rominfo *romdirGetFile(char *name, struct rominfo *ri); + +#endif /* __ROMDIR_H__ */ diff --git a/fps2bios/loader/loader.c b/fps2bios/loader/loader.c index 45e9a47e4a..7445006800 100644 --- a/fps2bios/loader/loader.c +++ b/fps2bios/loader/loader.c @@ -1,14 +1,14 @@ - -#include -#include -#include - -#include "eedebug.h" - - -void main() { - __printf("LOADER start\n"); - - menuStart(); -} - + +#include +#include +#include + +#include "eedebug.h" + + +void main() { + __printf("LOADER start\n"); + + menuStart(); +} + diff --git a/fps2bios/loader/menu.c b/fps2bios/loader/menu.c index 00b336c274..bba7cf322b 100644 --- a/fps2bios/loader/menu.c +++ b/fps2bios/loader/menu.c @@ -1,20 +1,20 @@ - -#include -#include -#include -#include - -#include "eedebug.h" -#include "romdir.h" - - -int menuStart() { - - - __printf("%s\n", __FUNCTION__); - - - - return 0; -} - + +#include +#include +#include +#include + +#include "eedebug.h" +#include "romdir.h" + + +int menuStart() { + + + __printf("%s\n", __FUNCTION__); + + + + return 0; +} + diff --git a/fps2bios/loader/romdir.c b/fps2bios/loader/romdir.c index 3494074eda..a9915f7f41 100644 --- a/fps2bios/loader/romdir.c +++ b/fps2bios/loader/romdir.c @@ -1,47 +1,47 @@ -/*************************************************************** -* romdir.c, based over Alex Lau (http://alexlau.8k.com) RomDir * -****************************************************************/ -#include "romdir.h" - -struct romdir *base = NULL; - -struct romdir *romdirInit() { - u8 *mem; - - for (mem=(u8*)0xbfc00000; (u32)mem<0xbfc01000; mem++) { - if (mem[0] == 'R' && mem[1] == 'E' && - mem[2] == 'S' && mem[3] == 'E' && - mem[4] == 'T') - break; - } - if ((u32)mem == 0xbfc01000) return NULL; - - return (struct romdir*)mem; -} - -struct rominfo *romdirGetFile(char *name, struct rominfo *ri) { - struct romdir *rd; -// struct romdir *base; - int i; - - if (base == NULL) { - base = romdirInit(); - if (base == NULL) return NULL; - } - - ri->fileOffset = 0; - for (rd = base; rd->fileName[0] != 0; rd++) { - for (i=0; i<10 && name[i] != 0; i++) { - if (rd->fileName[i] != name[i]) break; - } - if (rd->fileName[i] != name[i]) { - ri->fileOffset+= (rd->fileSize + 15) & ~0xF; - continue; - } - - ri->fileSize = rd->fileSize; - return ri; - } - - return NULL; -} +/*************************************************************** +* romdir.c, based over Alex Lau (http://alexlau.8k.com) RomDir * +****************************************************************/ +#include "romdir.h" + +struct romdir *base = NULL; + +struct romdir *romdirInit() { + u8 *mem; + + for (mem=(u8*)0xbfc00000; (u32)mem<0xbfc01000; mem++) { + if (mem[0] == 'R' && mem[1] == 'E' && + mem[2] == 'S' && mem[3] == 'E' && + mem[4] == 'T') + break; + } + if ((u32)mem == 0xbfc01000) return NULL; + + return (struct romdir*)mem; +} + +struct rominfo *romdirGetFile(char *name, struct rominfo *ri) { + struct romdir *rd; +// struct romdir *base; + int i; + + if (base == NULL) { + base = romdirInit(); + if (base == NULL) return NULL; + } + + ri->fileOffset = 0; + for (rd = base; rd->fileName[0] != 0; rd++) { + for (i=0; i<10 && name[i] != 0; i++) { + if (rd->fileName[i] != name[i]) break; + } + if (rd->fileName[i] != name[i]) { + ri->fileOffset+= (rd->fileSize + 15) & ~0xF; + continue; + } + + ri->fileSize = rd->fileSize; + return ri; + } + + return NULL; +} diff --git a/fps2bios/ps2romgen.c b/fps2bios/ps2romgen.c index 30c78b0f87..36481e1596 100644 --- a/fps2bios/ps2romgen.c +++ b/fps2bios/ps2romgen.c @@ -1,80 +1,80 @@ -// little prog for bios image repack by Florin Sasu 2002-10-03 - -#include -#include - -struct romdir{ - char name[10]; - short ext; - int size; -} rd[200]; //increase the number if needed; 200 is enough - -char buffer[10000]; - -#define min(a,b) (a0){ - fwrite(buffer, 1, min(size, 10000), f); - size-=10000; - } -} - -void writefile(FILE *f, char *name, int offset, int size){ - FILE *fi=fopen(name, "rb"); - if (fi) fseek(fi, 0, SEEK_END); - if ((!fi) || (ftell(fi)!=size)){ - printf("Could not find a file %s of %d bytes\n", name, size); - if (fi) fclose(fi); - return; - } - - printf("%10s\t%8X\t%8X\n", name, offset, size); - fillfile(f, offset-ftell(f), 0); - fseek(fi, 0, SEEK_SET); - while (size>0){ - fread(buffer, 1, min(10000, size), fi); - fwrite(buffer, 1, min(10000, size), f); - size-=10000; - } - - fclose(fi); -} - -int main(int argc, char* argv[]){ - int i, n, offset; - FILE *f; -////////////////////////////////// - printf("PS2 ROMGEN v0.1 Florin Sasu 2002-10-03 (florinsasu@yahoo.com) no padding\n"); - if (argc<2){ - printf("Usage: ps2biosgen \n\tfilename=name of the biosfile to create\n"); - printf("\n\tPut in the same directory with ps2romgen all the files from bios\n"); - return 1; - } -////////////////////////////////// - f=fopen("ROMDIR", "rb"); - if (!f){ - printf("Could not find the ROMDIR file\n"); - return 1; - } - - for (n=0; !feof(f) && (fread(&rd[n], 16, 1, f)==1) && rd[n].name[0]; n++); - - fclose(f); -////////////////////////////////// - printf("\n Name Offset(hex) Size(hex)" - "\n----------------------------------------\n"); - f=fopen(argv[1], "wb"); - - for (i=0, offset=0; i +#include + +struct romdir{ + char name[10]; + short ext; + int size; +} rd[200]; //increase the number if needed; 200 is enough + +char buffer[10000]; + +#define min(a,b) (a0){ + fwrite(buffer, 1, min(size, 10000), f); + size-=10000; + } +} + +void writefile(FILE *f, char *name, int offset, int size){ + FILE *fi=fopen(name, "rb"); + if (fi) fseek(fi, 0, SEEK_END); + if ((!fi) || (ftell(fi)!=size)){ + printf("Could not find a file %s of %d bytes\n", name, size); + if (fi) fclose(fi); + return; + } + + printf("%10s\t%8X\t%8X\n", name, offset, size); + fillfile(f, offset-ftell(f), 0); + fseek(fi, 0, SEEK_SET); + while (size>0){ + fread(buffer, 1, min(10000, size), fi); + fwrite(buffer, 1, min(10000, size), f); + size-=10000; + } + + fclose(fi); +} + +int main(int argc, char* argv[]){ + int i, n, offset; + FILE *f; +////////////////////////////////// + printf("PS2 ROMGEN v0.1 Florin Sasu 2002-10-03 (florinsasu@yahoo.com) no padding\n"); + if (argc<2){ + printf("Usage: ps2biosgen \n\tfilename=name of the biosfile to create\n"); + printf("\n\tPut in the same directory with ps2romgen all the files from bios\n"); + return 1; + } +////////////////////////////////// + f=fopen("ROMDIR", "rb"); + if (!f){ + printf("Could not find the ROMDIR file\n"); + return 1; + } + + for (n=0; !feof(f) && (fread(&rd[n], 16, 1, f)==1) && rd[n].name[0]; n++); + + fclose(f); +////////////////////////////////// + printf("\n Name Offset(hex) Size(hex)" + "\n----------------------------------------\n"); + f=fopen(argv[1], "wb"); + + for (i=0, offset=0; i -#include -#include -#include -#include - -#define MAXFILES 200 -#define DIRENTRY_SIZE 16 -#define BUFFSIZE 16384 - -struct __attribute__ ((__packed__)) romdir { - /*following variable must place in designed order*/ - char fileName[10]; - unsigned short extInfoSize; - unsigned long fileSize; -} rd; - -int main(int argc, char *argv[]) { - struct stat buf; - FILE *romdir; - FILE *extinfo; - int i, j; - - printf("fps2bios romdir generator\n"); - if (argc < 2){ - printf("usage: %s infile1 [infile2...]\n", argv[0]); - return 1; - } - - romdir = fopen("ROMDIR", "wb"); - if (romdir == NULL) { - printf("failed to create ROMDIR\n"); - return 1; - } - - extinfo = fopen("EXTINFO", "wb"); - if (extinfo == NULL) { - printf("failed to create EXTINFO\n"); - return 1; - } - - for (i=1; i +#include +#include +#include +#include + +#define MAXFILES 200 +#define DIRENTRY_SIZE 16 +#define BUFFSIZE 16384 + +struct __attribute__ ((__packed__)) romdir { + /*following variable must place in designed order*/ + char fileName[10]; + unsigned short extInfoSize; + unsigned long fileSize; +} rd; + +int main(int argc, char *argv[]) { + struct stat buf; + FILE *romdir; + FILE *extinfo; + int i, j; + + printf("fps2bios romdir generator\n"); + if (argc < 2){ + printf("usage: %s infile1 [infile2...]\n", argv[0]); + return 1; + } + + romdir = fopen("ROMDIR", "wb"); + if (romdir == NULL) { + printf("failed to create ROMDIR\n"); + return 1; + } + + extinfo = fopen("EXTINFO", "wb"); + if (extinfo == NULL) { + printf("failed to create EXTINFO\n"); + return 1; + } + + for (i=1; i -#include -#include -#include -#include -#include -#include - -int main(int argc, char *argv[]) { - char str[256]; - FILE *f; - time_t t; - int version; - int build; - - printf("fps2bios romver generator\n"); - if (argc < 3){ - printf("usage: %s version build\n", argv[0]); - return 1; - } - f = fopen("ROMVER", "wb"); - if (f == NULL) { - printf("failed to create ROMVER\n"); - return 1; - } - - t = time(NULL); - strftime(str, 256, "%Y%m%d", localtime(&t)); - version = strtol(argv[1], (char**)NULL, 0); - build = strtol(argv[2], (char**)NULL, 0); - fprintf(f, "%2.2d%2.2dPD%s\n", version, build, str); - fputc(0, f); - - fclose(f); - - return 0; -} +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + char str[256]; + FILE *f; + time_t t; + int version; + int build; + + printf("fps2bios romver generator\n"); + if (argc < 3){ + printf("usage: %s version build\n", argv[0]); + return 1; + } + f = fopen("ROMVER", "wb"); + if (f == NULL) { + printf("failed to create ROMVER\n"); + return 1; + } + + t = time(NULL); + strftime(str, 256, "%Y%m%d", localtime(&t)); + version = strtol(argv[1], (char**)NULL, 0); + build = strtol(argv[2], (char**)NULL, 0); + fprintf(f, "%2.2d%2.2dPD%s\n", version, build, str); + fputc(0, f); + + fclose(f); + + return 0; +} diff --git a/pcsx2/3rdparty/zlib/adler32.c b/pcsx2/3rdparty/zlib/adler32.c index f201d6701e..007ba26277 100644 --- a/pcsx2/3rdparty/zlib/adler32.c +++ b/pcsx2/3rdparty/zlib/adler32.c @@ -1,149 +1,149 @@ -/* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2004 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -#define BASE 65521UL /* largest prime smaller than 65536 */ -#define NMAX 5552 -/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ - -#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} -#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); -#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); -#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); -#define DO16(buf) DO8(buf,0); DO8(buf,8); - -/* use NO_DIVIDE if your processor does not do division in hardware */ -#ifdef NO_DIVIDE -# define MOD(a) \ - do { \ - if (a >= (BASE << 16)) a -= (BASE << 16); \ - if (a >= (BASE << 15)) a -= (BASE << 15); \ - if (a >= (BASE << 14)) a -= (BASE << 14); \ - if (a >= (BASE << 13)) a -= (BASE << 13); \ - if (a >= (BASE << 12)) a -= (BASE << 12); \ - if (a >= (BASE << 11)) a -= (BASE << 11); \ - if (a >= (BASE << 10)) a -= (BASE << 10); \ - if (a >= (BASE << 9)) a -= (BASE << 9); \ - if (a >= (BASE << 8)) a -= (BASE << 8); \ - if (a >= (BASE << 7)) a -= (BASE << 7); \ - if (a >= (BASE << 6)) a -= (BASE << 6); \ - if (a >= (BASE << 5)) a -= (BASE << 5); \ - if (a >= (BASE << 4)) a -= (BASE << 4); \ - if (a >= (BASE << 3)) a -= (BASE << 3); \ - if (a >= (BASE << 2)) a -= (BASE << 2); \ - if (a >= (BASE << 1)) a -= (BASE << 1); \ - if (a >= BASE) a -= BASE; \ - } while (0) -# define MOD4(a) \ - do { \ - if (a >= (BASE << 4)) a -= (BASE << 4); \ - if (a >= (BASE << 3)) a -= (BASE << 3); \ - if (a >= (BASE << 2)) a -= (BASE << 2); \ - if (a >= (BASE << 1)) a -= (BASE << 1); \ - if (a >= BASE) a -= BASE; \ - } while (0) -#else -# define MOD(a) a %= BASE -# define MOD4(a) a %= BASE -#endif - -/* ========================================================================= */ -uLong ZEXPORT adler32(adler, buf, len) - uLong adler; - const Bytef *buf; - uInt len; -{ - unsigned long sum2; - unsigned n; - - /* split Adler-32 into component sums */ - sum2 = (adler >> 16) & 0xffff; - adler &= 0xffff; - - /* in case user likes doing a byte at a time, keep it fast */ - if (len == 1) { - adler += buf[0]; - if (adler >= BASE) - adler -= BASE; - sum2 += adler; - if (sum2 >= BASE) - sum2 -= BASE; - return adler | (sum2 << 16); - } - - /* initial Adler-32 value (deferred check for len == 1 speed) */ - if (buf == Z_NULL) - return 1L; - - /* in case short lengths are provided, keep it somewhat fast */ - if (len < 16) { - while (len--) { - adler += *buf++; - sum2 += adler; - } - if (adler >= BASE) - adler -= BASE; - MOD4(sum2); /* only added so many BASE's */ - return adler | (sum2 << 16); - } - - /* do length NMAX blocks -- requires just one modulo operation */ - while (len >= NMAX) { - len -= NMAX; - n = NMAX / 16; /* NMAX is divisible by 16 */ - do { - DO16(buf); /* 16 sums unrolled */ - buf += 16; - } while (--n); - MOD(adler); - MOD(sum2); - } - - /* do remaining bytes (less than NMAX, still just one modulo) */ - if (len) { /* avoid modulos if none remaining */ - while (len >= 16) { - len -= 16; - DO16(buf); - buf += 16; - } - while (len--) { - adler += *buf++; - sum2 += adler; - } - MOD(adler); - MOD(sum2); - } - - /* return recombined sums */ - return adler | (sum2 << 16); -} - -/* ========================================================================= */ -uLong ZEXPORT adler32_combine(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off_t len2; -{ - unsigned long sum1; - unsigned long sum2; - unsigned rem; - - /* the derivation of this formula is left as an exercise for the reader */ - rem = (unsigned)(len2 % BASE); - sum1 = adler1 & 0xffff; - sum2 = rem * sum1; - MOD(sum2); - sum1 += (adler2 & 0xffff) + BASE - 1; - sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; - if (sum1 > BASE) sum1 -= BASE; - if (sum1 > BASE) sum1 -= BASE; - if (sum2 > (BASE << 1)) sum2 -= (BASE << 1); - if (sum2 > BASE) sum2 -= BASE; - return sum1 | (sum2 << 16); -} +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware */ +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD4(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD4(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* the derivation of this formula is left as an exercise for the reader */ + rem = (unsigned)(len2 % BASE); + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 > BASE) sum1 -= BASE; + if (sum1 > BASE) sum1 -= BASE; + if (sum2 > (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 > BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} diff --git a/pcsx2/3rdparty/zlib/compress.c b/pcsx2/3rdparty/zlib/compress.c index d37e84f5e3..df04f0148e 100644 --- a/pcsx2/3rdparty/zlib/compress.c +++ b/pcsx2/3rdparty/zlib/compress.c @@ -1,79 +1,79 @@ -/* compress.c -- compress a memory buffer - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -/* =========================================================================== - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least 0.1% larger than sourceLen plus - 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ -int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; - int level; -{ - z_stream stream; - int err; - - stream.next_in = (Bytef*)source; - stream.avail_in = (uInt)sourceLen; -#ifdef MAXSEG_64K - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; -#endif - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; - - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - stream.opaque = (voidpf)0; - - err = deflateInit(&stream, level); - if (err != Z_OK) return err; - - err = deflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - deflateEnd(&stream); - return err == Z_OK ? Z_BUF_ERROR : err; - } - *destLen = stream.total_out; - - err = deflateEnd(&stream); - return err; -} - -/* =========================================================================== - */ -int ZEXPORT compress (dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ - return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); -} - -/* =========================================================================== - If the default memLevel or windowBits for deflateInit() is changed, then - this function needs to be updated. - */ -uLong ZEXPORT compressBound (sourceLen) - uLong sourceLen; -{ - return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; -} +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/pcsx2/3rdparty/zlib/crc32.c b/pcsx2/3rdparty/zlib/crc32.c index 32814c20c8..f658a9ef55 100644 --- a/pcsx2/3rdparty/zlib/crc32.c +++ b/pcsx2/3rdparty/zlib/crc32.c @@ -1,423 +1,423 @@ -/* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Thanks to Rodney Brown for his contribution of faster - * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing - * tables for updating the shift register in one step with three exclusive-ors - * instead of four steps with four exclusive-ors. This results in about a - * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. - */ - -/* @(#) $Id$ */ - -/* - Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore - protection on the static variables used to control the first-use generation - of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should - first call get_crc_table() to initialize the tables before allowing more than - one thread to use crc32(). - */ - -#ifdef MAKECRCH -# include -# ifndef DYNAMIC_CRC_TABLE -# define DYNAMIC_CRC_TABLE -# endif /* !DYNAMIC_CRC_TABLE */ -#endif /* MAKECRCH */ - -#include "zutil.h" /* for STDC and FAR definitions */ - -#define local static - -/* Find a four-byte integer type for crc32_little() and crc32_big(). */ -#ifndef NOBYFOUR -# ifdef STDC /* need ANSI C limits.h to determine sizes */ -# include -# define BYFOUR -# if (UINT_MAX == 0xffffffffUL) - typedef unsigned int u4; -# else -# if (ULONG_MAX == 0xffffffffUL) - typedef unsigned long u4; -# else -# if (USHRT_MAX == 0xffffffffUL) - typedef unsigned short u4; -# else -# undef BYFOUR /* can't find a four-byte integer type! */ -# endif -# endif -# endif -# endif /* STDC */ -#endif /* !NOBYFOUR */ - -/* Definitions for doing the crc four data bytes at a time. */ -#ifdef BYFOUR -# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ - (((w)&0xff00)<<8)+(((w)&0xff)<<24)) - local unsigned long crc32_little OF((unsigned long, - const unsigned char FAR *, unsigned)); - local unsigned long crc32_big OF((unsigned long, - const unsigned char FAR *, unsigned)); -# define TBLS 8 -#else -# define TBLS 1 -#endif /* BYFOUR */ - -/* Local functions for crc concatenation */ -local unsigned long gf2_matrix_times OF((unsigned long *mat, - unsigned long vec)); -local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); - -#ifdef DYNAMIC_CRC_TABLE - -local volatile int crc_table_empty = 1; -local unsigned long FAR crc_table[TBLS][256]; -local void make_crc_table OF((void)); -#ifdef MAKECRCH - local void write_table OF((FILE *, const unsigned long FAR *)); -#endif /* MAKECRCH */ -/* - Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: - x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. - - Polynomials over GF(2) are represented in binary, one bit per coefficient, - with the lowest powers in the most significant bit. Then adding polynomials - is just exclusive-or, and multiplying a polynomial by x is a right shift by - one. If we call the above polynomial p, and represent a byte as the - polynomial q, also with the lowest power in the most significant bit (so the - byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, - where a mod b means the remainder after dividing a by b. - - This calculation is done using the shift-register method of multiplying and - taking the remainder. The register is initialized to zero, and for each - incoming bit, x^32 is added mod p to the register if the bit is a one (where - x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by - x (which is shifting right by one and adding x^32 mod p if the bit shifted - out is a one). We start with the highest power (least significant bit) of - q and repeat for all eight bits of q. - - The first table is simply the CRC of all possible eight bit values. This is - all the information needed to generate CRCs on data a byte at a time for all - combinations of CRC register values and incoming bytes. The remaining tables - allow for word-at-a-time CRC calculation for both big-endian and little- - endian machines, where a word is four bytes. -*/ -local void make_crc_table() -{ - unsigned long c; - int n, k; - unsigned long poly; /* polynomial exclusive-or pattern */ - /* terms of polynomial defining this crc (except x^32): */ - static volatile int first = 1; /* flag to limit concurrent making */ - static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - /* See if another task is already doing this (not thread-safe, but better - than nothing -- significantly reduces duration of vulnerability in - case the advice about DYNAMIC_CRC_TABLE is ignored) */ - if (first) { - first = 0; - - /* make exclusive-or pattern from polynomial (0xedb88320UL) */ - poly = 0UL; - for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) - poly |= 1UL << (31 - p[n]); - - /* generate a crc for every 8-bit value */ - for (n = 0; n < 256; n++) { - c = (unsigned long)n; - for (k = 0; k < 8; k++) - c = c & 1 ? poly ^ (c >> 1) : c >> 1; - crc_table[0][n] = c; - } - -#ifdef BYFOUR - /* generate crc for each value followed by one, two, and three zeros, - and then the byte reversal of those as well as the first table */ - for (n = 0; n < 256; n++) { - c = crc_table[0][n]; - crc_table[4][n] = REV(c); - for (k = 1; k < 4; k++) { - c = crc_table[0][c & 0xff] ^ (c >> 8); - crc_table[k][n] = c; - crc_table[k + 4][n] = REV(c); - } - } -#endif /* BYFOUR */ - - crc_table_empty = 0; - } - else { /* not first */ - /* wait for the other guy to finish (not efficient, but rare) */ - while (crc_table_empty) - ; - } - -#ifdef MAKECRCH - /* write out CRC tables to crc32.h */ - { - FILE *out; - - out = fopen("crc32.h", "w"); - if (out == NULL) return; - fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); - fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); - fprintf(out, "local const unsigned long FAR "); - fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); - write_table(out, crc_table[0]); -# ifdef BYFOUR - fprintf(out, "#ifdef BYFOUR\n"); - for (k = 1; k < 8; k++) { - fprintf(out, " },\n {\n"); - write_table(out, crc_table[k]); - } - fprintf(out, "#endif\n"); -# endif /* BYFOUR */ - fprintf(out, " }\n};\n"); - fclose(out); - } -#endif /* MAKECRCH */ -} - -#ifdef MAKECRCH -local void write_table(out, table) - FILE *out; - const unsigned long FAR *table; -{ - int n; - - for (n = 0; n < 256; n++) - fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], - n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); -} -#endif /* MAKECRCH */ - -#else /* !DYNAMIC_CRC_TABLE */ -/* ======================================================================== - * Tables of CRC-32s of all single-byte values, made by make_crc_table(). - */ -#include "crc32.h" -#endif /* DYNAMIC_CRC_TABLE */ - -/* ========================================================================= - * This function can be used by asm versions of crc32() - */ -const unsigned long FAR * ZEXPORT get_crc_table() -{ -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); -#endif /* DYNAMIC_CRC_TABLE */ - return (const unsigned long FAR *)crc_table; -} - -/* ========================================================================= */ -#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) -#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 - -/* ========================================================================= */ -unsigned long ZEXPORT crc32(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - if (buf == Z_NULL) return 0UL; - -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); -#endif /* DYNAMIC_CRC_TABLE */ - -#ifdef BYFOUR - if (sizeof(void *) == sizeof(ptrdiff_t)) { - u4 endian; - - endian = 1; - if (*((unsigned char *)(&endian))) - return crc32_little(crc, buf, len); - else - return crc32_big(crc, buf, len); - } -#endif /* BYFOUR */ - crc = crc ^ 0xffffffffUL; - while (len >= 8) { - DO8; - len -= 8; - } - if (len) do { - DO1; - } while (--len); - return crc ^ 0xffffffffUL; -} - -#ifdef BYFOUR - -/* ========================================================================= */ -#define DOLIT4 c ^= *buf4++; \ - c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ - crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] -#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 - -/* ========================================================================= */ -local unsigned long crc32_little(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - register u4 c; - register const u4 FAR *buf4; - - c = (u4)crc; - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - len--; - } - - buf4 = (const u4 FAR *)(const void FAR *)buf; - while (len >= 32) { - DOLIT32; - len -= 32; - } - while (len >= 4) { - DOLIT4; - len -= 4; - } - buf = (const unsigned char FAR *)buf4; - - if (len) do { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - } while (--len); - c = ~c; - return (unsigned long)c; -} - -/* ========================================================================= */ -#define DOBIG4 c ^= *++buf4; \ - c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ - crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] -#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 - -/* ========================================================================= */ -local unsigned long crc32_big(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - register u4 c; - register const u4 FAR *buf4; - - c = REV((u4)crc); - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - len--; - } - - buf4 = (const u4 FAR *)(const void FAR *)buf; - buf4--; - while (len >= 32) { - DOBIG32; - len -= 32; - } - while (len >= 4) { - DOBIG4; - len -= 4; - } - buf4++; - buf = (const unsigned char FAR *)buf4; - - if (len) do { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - } while (--len); - c = ~c; - return (unsigned long)(REV(c)); -} - -#endif /* BYFOUR */ - -#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ - -/* ========================================================================= */ -local unsigned long gf2_matrix_times(mat, vec) - unsigned long *mat; - unsigned long vec; -{ - unsigned long sum; - - sum = 0; - while (vec) { - if (vec & 1) - sum ^= *mat; - vec >>= 1; - mat++; - } - return sum; -} - -/* ========================================================================= */ -local void gf2_matrix_square(square, mat) - unsigned long *square; - unsigned long *mat; -{ - int n; - - for (n = 0; n < GF2_DIM; n++) - square[n] = gf2_matrix_times(mat, mat[n]); -} - -/* ========================================================================= */ -uLong ZEXPORT crc32_combine(crc1, crc2, len2) - uLong crc1; - uLong crc2; - z_off_t len2; -{ - int n; - unsigned long row; - unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ - unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ - - /* degenerate case */ - if (len2 == 0) - return crc1; - - /* put operator for one zero bit in odd */ - odd[0] = 0xedb88320L; /* CRC-32 polynomial */ - row = 1; - for (n = 1; n < GF2_DIM; n++) { - odd[n] = row; - row <<= 1; - } - - /* put operator for two zero bits in even */ - gf2_matrix_square(even, odd); - - /* put operator for four zero bits in odd */ - gf2_matrix_square(odd, even); - - /* apply len2 zeros to crc1 (first square will put the operator for one - zero byte, eight zero bits, in even) */ - do { - /* apply zeros operator for this bit of len2 */ - gf2_matrix_square(even, odd); - if (len2 & 1) - crc1 = gf2_matrix_times(even, crc1); - len2 >>= 1; - - /* if no more bits set, then done */ - if (len2 == 0) - break; - - /* another iteration of the loop with odd and even swapped */ - gf2_matrix_square(odd, even); - if (len2 & 1) - crc1 = gf2_matrix_times(odd, crc1); - len2 >>= 1; - - /* if no more bits set, then done */ - } while (len2 != 0); - - /* return combined crc */ - crc1 ^= crc2; - return crc1; -} +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case */ + if (len2 == 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320L; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} diff --git a/pcsx2/3rdparty/zlib/crc32.h b/pcsx2/3rdparty/zlib/crc32.h index 5de49bc978..8053b6117c 100644 --- a/pcsx2/3rdparty/zlib/crc32.h +++ b/pcsx2/3rdparty/zlib/crc32.h @@ -1,441 +1,441 @@ -/* crc32.h -- tables for rapid CRC calculation - * Generated automatically by crc32.c - */ - -local const unsigned long FAR crc_table[TBLS][256] = -{ - { - 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, - 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, - 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, - 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, - 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, - 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, - 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, - 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, - 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, - 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, - 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, - 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, - 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, - 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, - 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, - 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, - 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, - 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, - 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, - 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, - 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, - 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, - 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, - 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, - 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, - 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, - 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, - 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, - 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, - 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, - 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, - 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, - 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, - 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, - 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, - 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, - 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, - 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, - 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, - 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, - 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, - 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, - 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, - 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, - 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, - 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, - 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, - 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, - 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, - 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, - 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, - 0x2d02ef8dUL -#ifdef BYFOUR - }, - { - 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, - 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, - 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, - 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, - 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, - 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, - 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, - 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, - 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, - 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, - 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, - 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, - 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, - 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, - 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, - 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, - 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, - 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, - 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, - 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, - 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, - 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, - 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, - 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, - 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, - 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, - 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, - 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, - 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, - 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, - 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, - 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, - 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, - 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, - 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, - 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, - 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, - 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, - 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, - 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, - 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, - 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, - 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, - 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, - 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, - 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, - 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, - 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, - 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, - 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, - 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, - 0x9324fd72UL - }, - { - 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, - 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, - 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, - 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, - 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, - 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, - 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, - 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, - 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, - 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, - 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, - 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, - 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, - 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, - 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, - 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, - 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, - 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, - 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, - 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, - 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, - 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, - 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, - 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, - 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, - 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, - 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, - 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, - 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, - 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, - 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, - 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, - 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, - 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, - 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, - 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, - 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, - 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, - 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, - 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, - 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, - 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, - 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, - 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, - 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, - 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, - 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, - 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, - 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, - 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, - 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, - 0xbe9834edUL - }, - { - 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, - 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, - 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, - 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, - 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, - 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, - 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, - 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, - 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, - 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, - 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, - 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, - 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, - 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, - 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, - 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, - 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, - 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, - 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, - 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, - 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, - 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, - 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, - 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, - 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, - 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, - 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, - 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, - 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, - 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, - 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, - 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, - 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, - 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, - 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, - 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, - 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, - 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, - 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, - 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, - 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, - 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, - 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, - 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, - 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, - 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, - 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, - 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, - 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, - 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, - 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, - 0xde0506f1UL - }, - { - 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, - 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, - 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, - 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, - 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, - 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, - 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, - 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, - 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, - 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, - 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, - 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, - 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, - 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, - 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, - 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, - 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, - 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, - 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, - 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, - 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, - 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, - 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, - 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, - 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, - 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, - 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, - 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, - 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, - 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, - 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, - 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, - 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, - 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, - 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, - 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, - 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, - 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, - 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, - 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, - 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, - 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, - 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, - 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, - 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, - 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, - 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, - 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, - 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, - 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, - 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, - 0x8def022dUL - }, - { - 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, - 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, - 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, - 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, - 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, - 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, - 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, - 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, - 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, - 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, - 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, - 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, - 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, - 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, - 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, - 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, - 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, - 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, - 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, - 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, - 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, - 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, - 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, - 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, - 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, - 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, - 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, - 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, - 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, - 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, - 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, - 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, - 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, - 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, - 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, - 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, - 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, - 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, - 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, - 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, - 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, - 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, - 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, - 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, - 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, - 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, - 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, - 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, - 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, - 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, - 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, - 0x72fd2493UL - }, - { - 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, - 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, - 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, - 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, - 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, - 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, - 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, - 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, - 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, - 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, - 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, - 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, - 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, - 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, - 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, - 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, - 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, - 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, - 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, - 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, - 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, - 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, - 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, - 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, - 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, - 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, - 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, - 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, - 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, - 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, - 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, - 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, - 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, - 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, - 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, - 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, - 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, - 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, - 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, - 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, - 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, - 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, - 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, - 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, - 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, - 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, - 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, - 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, - 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, - 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, - 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, - 0xed3498beUL - }, - { - 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, - 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, - 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, - 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, - 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, - 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, - 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, - 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, - 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, - 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, - 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, - 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, - 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, - 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, - 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, - 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, - 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, - 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, - 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, - 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, - 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, - 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, - 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, - 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, - 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, - 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, - 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, - 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, - 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, - 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, - 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, - 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, - 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, - 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, - 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, - 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, - 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, - 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, - 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, - 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, - 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, - 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, - 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, - 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, - 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, - 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, - 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, - 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, - 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, - 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, - 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, - 0xf10605deUL -#endif - } -}; +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/pcsx2/3rdparty/zlib/deflate.c b/pcsx2/3rdparty/zlib/deflate.c index 529f716b7a..29ce1f64a5 100644 --- a/pcsx2/3rdparty/zlib/deflate.c +++ b/pcsx2/3rdparty/zlib/deflate.c @@ -1,1736 +1,1736 @@ -/* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process depends on being able to identify portions - * of the input text which are identical to earlier input (within a - * sliding window trailing behind the input currently being processed). - * - * The most straightforward technique turns out to be the fastest for - * most input files: try all possible matches and select the longest. - * The key feature of this algorithm is that insertions into the string - * dictionary are very simple and thus fast, and deletions are avoided - * completely. Insertions are performed at each input character, whereas - * string matches are performed only when the previous match ends. So it - * is preferable to spend more time in matches to allow very fast string - * insertions and avoid deletions. The matching algorithm for small - * strings is inspired from that of Rabin & Karp. A brute force approach - * is used to find longer strings when a small match has been found. - * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze - * (by Leonid Broukhis). - * A previous version of this file used a more sophisticated algorithm - * (by Fiala and Greene) which is guaranteed to run in linear amortized - * time, but has a larger average cost, uses more memory and is patented. - * However the F&G algorithm may be faster for some highly redundant - * files if the parameter max_chain_length (described below) is too large. - * - * ACKNOWLEDGEMENTS - * - * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and - * I found it in 'freeze' written by Leonid Broukhis. - * Thanks to many people for bug reports and testing. - * - * REFERENCES - * - * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". - * Available in http://www.ietf.org/rfc/rfc1951.txt - * - * A description of the Rabin and Karp algorithm is given in the book - * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. - * - * Fiala,E.R., and Greene,D.H. - * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 - * - */ - -/* @(#) $Id$ */ - -#include "deflate.h" - -const char deflate_copyright[] = - " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* =========================================================================== - * Function prototypes. - */ -typedef enum { - need_more, /* block not completed, need more input or more output */ - block_done, /* block flush performed */ - finish_started, /* finish started, need only more output at next deflate */ - finish_done /* finish done, accept no more input or output */ -} block_state; - -typedef block_state (*compress_func) OF((deflate_state *s, int flush)); -/* Compression function. Returns the block state after the call. */ - -local void fill_window OF((deflate_state *s)); -local block_state deflate_stored OF((deflate_state *s, int flush)); -local block_state deflate_fast OF((deflate_state *s, int flush)); -#ifndef FASTEST -local block_state deflate_slow OF((deflate_state *s, int flush)); -#endif -local void lm_init OF((deflate_state *s)); -local void putShortMSB OF((deflate_state *s, uInt b)); -local void flush_pending OF((z_streamp strm)); -local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); -#ifndef FASTEST -#ifdef ASMV - void match_init OF((void)); /* asm code initialization */ - uInt longest_match OF((deflate_state *s, IPos cur_match)); -#else -local uInt longest_match OF((deflate_state *s, IPos cur_match)); -#endif -#endif -local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); - -#ifdef DEBUG -local void check_match OF((deflate_state *s, IPos start, IPos match, - int length)); -#endif - -/* =========================================================================== - * Local data - */ - -#define NIL 0 -/* Tail of hash chains */ - -#ifndef TOO_FAR -# define TOO_FAR 4096 -#endif -/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -/* Values for max_lazy_match, good_match and max_chain_length, depending on - * the desired pack level (0..9). The values given below have been tuned to - * exclude worst case performance for pathological files. Better values may be - * found for specific files. - */ -typedef struct config_s { - ush good_length; /* reduce lazy search above this match length */ - ush max_lazy; /* do not perform lazy search above this match length */ - ush nice_length; /* quit search above this match length */ - ush max_chain; - compress_func func; -} config; - -#ifdef FASTEST -local const config configuration_table[2] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ -#else -local const config configuration_table[10] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ -/* 2 */ {4, 5, 16, 8, deflate_fast}, -/* 3 */ {4, 6, 32, 32, deflate_fast}, - -/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ -/* 5 */ {8, 16, 32, 32, deflate_slow}, -/* 6 */ {8, 16, 128, 128, deflate_slow}, -/* 7 */ {8, 32, 128, 256, deflate_slow}, -/* 8 */ {32, 128, 258, 1024, deflate_slow}, -/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ -#endif - -/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 - * For deflate_fast() (levels <= 3) good is ignored and lazy has a different - * meaning. - */ - -#define EQUAL 0 -/* result of memcmp for equal strings */ - -#ifndef NO_DUMMY_DECL -struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ -#endif - -/* =========================================================================== - * Update a hash value with the given input byte - * IN assertion: all calls to to UPDATE_HASH are made with consecutive - * input characters, so that a running hash key can be computed from the - * previous key instead of complete recalculation each time. - */ -#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) - - -/* =========================================================================== - * Insert string str in the dictionary and set match_head to the previous head - * of the hash chain (the most recent string with same hash key). Return - * the previous length of the hash chain. - * If this file is compiled with -DFASTEST, the compression level is forced - * to 1, and no hash chains are maintained. - * IN assertion: all calls to to INSERT_STRING are made with consecutive - * input characters and the first MIN_MATCH bytes of str are valid - * (except for the last MIN_MATCH-1 bytes of the input file). - */ -#ifdef FASTEST -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - match_head = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) -#else -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) -#endif - -/* =========================================================================== - * Initialize the hash table (avoiding 64K overflow for 16 bit systems). - * prev[] will be initialized on the fly. - */ -#define CLEAR_HASH(s) \ - s->head[s->hash_size-1] = NIL; \ - zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); - -/* ========================================================================= */ -int ZEXPORT deflateInit_(strm, level, version, stream_size) - z_streamp strm; - int level; - const char *version; - int stream_size; -{ - return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, version, stream_size); - /* To do: ignore strm->next_in if we use it as window */ -} - -/* ========================================================================= */ -int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, - version, stream_size) - z_streamp strm; - int level; - int method; - int windowBits; - int memLevel; - int strategy; - const char *version; - int stream_size; -{ - deflate_state *s; - int wrap = 1; - static const char my_version[] = ZLIB_VERSION; - - ushf *overlay; - /* We overlay pending_buf and d_buf+l_buf. This works since the average - * output size for (length,distance) codes is <= 24 bits. - */ - - if (version == Z_NULL || version[0] != my_version[0] || - stream_size != sizeof(z_stream)) { - return Z_VERSION_ERROR; - } - if (strm == Z_NULL) return Z_STREAM_ERROR; - - strm->msg = Z_NULL; - if (strm->zalloc == (alloc_func)0) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; - -#ifdef FASTEST - if (level != 0) level = 1; -#else - if (level == Z_DEFAULT_COMPRESSION) level = 6; -#endif - - if (windowBits < 0) { /* suppress zlib wrapper */ - wrap = 0; - windowBits = -windowBits; - } -#ifdef GZIP - else if (windowBits > 15) { - wrap = 2; /* write gzip wrapper instead */ - windowBits -= 16; - } -#endif - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || - windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_FIXED) { - return Z_STREAM_ERROR; - } - if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ - s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); - if (s == Z_NULL) return Z_MEM_ERROR; - strm->state = (struct internal_state FAR *)s; - s->strm = strm; - - s->wrap = wrap; - s->gzhead = Z_NULL; - s->w_bits = windowBits; - s->w_size = 1 << s->w_bits; - s->w_mask = s->w_size - 1; - - s->hash_bits = memLevel + 7; - s->hash_size = 1 << s->hash_bits; - s->hash_mask = s->hash_size - 1; - s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); - - s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); - s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); - s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); - - s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ - - overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); - s->pending_buf = (uchf *) overlay; - s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); - - if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || - s->pending_buf == Z_NULL) { - s->status = FINISH_STATE; - strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); - deflateEnd (strm); - return Z_MEM_ERROR; - } - s->d_buf = overlay + s->lit_bufsize/sizeof(ush); - s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; - - s->level = level; - s->strategy = strategy; - s->method = (Byte)method; - - return deflateReset(strm); -} - -/* ========================================================================= */ -int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) - z_streamp strm; - const Bytef *dictionary; - uInt dictLength; -{ - deflate_state *s; - uInt length = dictLength; - uInt n; - IPos hash_head = 0; - - if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || - strm->state->wrap == 2 || - (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) - return Z_STREAM_ERROR; - - s = strm->state; - if (s->wrap) - strm->adler = adler32(strm->adler, dictionary, dictLength); - - if (length < MIN_MATCH) return Z_OK; - if (length > MAX_DIST(s)) { - length = MAX_DIST(s); - dictionary += dictLength - length; /* use the tail of the dictionary */ - } - zmemcpy(s->window, dictionary, length); - s->strstart = length; - s->block_start = (long)length; - - /* Insert all strings in the hash table (except for the last two bytes). - * s->lookahead stays null, so s->ins_h will be recomputed at the next - * call of fill_window. - */ - s->ins_h = s->window[0]; - UPDATE_HASH(s, s->ins_h, s->window[1]); - for (n = 0; n <= length - MIN_MATCH; n++) { - INSERT_STRING(s, n, hash_head); - } - if (hash_head) hash_head = 0; /* to make compiler happy */ - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateReset (strm) - z_streamp strm; -{ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL || - strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { - return Z_STREAM_ERROR; - } - - strm->total_in = strm->total_out = 0; - strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ - strm->data_type = Z_UNKNOWN; - - s = (deflate_state *)strm->state; - s->pending = 0; - s->pending_out = s->pending_buf; - - if (s->wrap < 0) { - s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ - } - s->status = s->wrap ? INIT_STATE : BUSY_STATE; - strm->adler = -#ifdef GZIP - s->wrap == 2 ? crc32(0L, Z_NULL, 0) : -#endif - adler32(0L, Z_NULL, 0); - s->last_flush = Z_NO_FLUSH; - - _tr_init(s); - lm_init(s); - - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateSetHeader (strm, head) - z_streamp strm; - gz_headerp head; -{ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - if (strm->state->wrap != 2) return Z_STREAM_ERROR; - strm->state->gzhead = head; - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflatePrime (strm, bits, value) - z_streamp strm; - int bits; - int value; -{ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - strm->state->bi_valid = bits; - strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateParams(strm, level, strategy) - z_streamp strm; - int level; - int strategy; -{ - deflate_state *s; - compress_func func; - int err = Z_OK; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - s = strm->state; - -#ifdef FASTEST - if (level != 0) level = 1; -#else - if (level == Z_DEFAULT_COMPRESSION) level = 6; -#endif - if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { - return Z_STREAM_ERROR; - } - func = configuration_table[s->level].func; - - if (func != configuration_table[level].func && strm->total_in != 0) { - /* Flush the last buffer: */ - err = deflate(strm, Z_PARTIAL_FLUSH); - } - if (s->level != level) { - s->level = level; - s->max_lazy_match = configuration_table[level].max_lazy; - s->good_match = configuration_table[level].good_length; - s->nice_match = configuration_table[level].nice_length; - s->max_chain_length = configuration_table[level].max_chain; - } - s->strategy = strategy; - return err; -} - -/* ========================================================================= */ -int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) - z_streamp strm; - int good_length; - int max_lazy; - int nice_length; - int max_chain; -{ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - s = strm->state; - s->good_match = good_length; - s->max_lazy_match = max_lazy; - s->nice_match = nice_length; - s->max_chain_length = max_chain; - return Z_OK; -} - -/* ========================================================================= - * For the default windowBits of 15 and memLevel of 8, this function returns - * a close to exact, as well as small, upper bound on the compressed size. - * They are coded as constants here for a reason--if the #define's are - * changed, then this function needs to be changed as well. The return - * value for 15 and 8 only works for those exact settings. - * - * For any setting other than those defaults for windowBits and memLevel, - * the value returned is a conservative worst case for the maximum expansion - * resulting from using fixed blocks instead of stored blocks, which deflate - * can emit on compressed data for some combinations of the parameters. - * - * This function could be more sophisticated to provide closer upper bounds - * for every combination of windowBits and memLevel, as well as wrap. - * But even the conservative upper bound of about 14% expansion does not - * seem onerous for output buffer allocation. - */ -uLong ZEXPORT deflateBound(strm, sourceLen) - z_streamp strm; - uLong sourceLen; -{ - deflate_state *s; - uLong destLen; - - /* conservative upper bound */ - destLen = sourceLen + - ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; - - /* if can't get parameters, return conservative bound */ - if (strm == Z_NULL || strm->state == Z_NULL) - return destLen; - - /* if not default parameters, return conservative bound */ - s = strm->state; - if (s->w_bits != 15 || s->hash_bits != 8 + 7) - return destLen; - - /* default settings: return tight bound for that case */ - return compressBound(sourceLen); -} - -/* ========================================================================= - * Put a short in the pending buffer. The 16-bit value is put in MSB order. - * IN assertion: the stream state is correct and there is enough room in - * pending_buf. - */ -local void putShortMSB (s, b) - deflate_state *s; - uInt b; -{ - put_byte(s, (Byte)(b >> 8)); - put_byte(s, (Byte)(b & 0xff)); -} - -/* ========================================================================= - * Flush as much pending output as possible. All deflate() output goes - * through this function so some applications may wish to modify it - * to avoid allocating a large strm->next_out buffer and copying into it. - * (See also read_buf()). - */ -local void flush_pending(strm) - z_streamp strm; -{ - unsigned len = strm->state->pending; - - if (len > strm->avail_out) len = strm->avail_out; - if (len == 0) return; - - zmemcpy(strm->next_out, strm->state->pending_out, len); - strm->next_out += len; - strm->state->pending_out += len; - strm->total_out += len; - strm->avail_out -= len; - strm->state->pending -= len; - if (strm->state->pending == 0) { - strm->state->pending_out = strm->state->pending_buf; - } -} - -/* ========================================================================= */ -int ZEXPORT deflate (strm, flush) - z_streamp strm; - int flush; -{ - int old_flush; /* value of flush param for previous deflate call */ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL || - flush > Z_FINISH || flush < 0) { - return Z_STREAM_ERROR; - } - s = strm->state; - - if (strm->next_out == Z_NULL || - (strm->next_in == Z_NULL && strm->avail_in != 0) || - (s->status == FINISH_STATE && flush != Z_FINISH)) { - ERR_RETURN(strm, Z_STREAM_ERROR); - } - if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); - - s->strm = strm; /* just in case */ - old_flush = s->last_flush; - s->last_flush = flush; - - /* Write the header */ - if (s->status == INIT_STATE) { -#ifdef GZIP - if (s->wrap == 2) { - strm->adler = crc32(0L, Z_NULL, 0); - put_byte(s, 31); - put_byte(s, 139); - put_byte(s, 8); - if (s->gzhead == NULL) { - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, OS_CODE); - s->status = BUSY_STATE; - } - else { - put_byte(s, (s->gzhead->text ? 1 : 0) + - (s->gzhead->hcrc ? 2 : 0) + - (s->gzhead->extra == Z_NULL ? 0 : 4) + - (s->gzhead->name == Z_NULL ? 0 : 8) + - (s->gzhead->comment == Z_NULL ? 0 : 16) - ); - put_byte(s, (Byte)(s->gzhead->time & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, s->gzhead->os & 0xff); - if (s->gzhead->extra != NULL) { - put_byte(s, s->gzhead->extra_len & 0xff); - put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); - } - if (s->gzhead->hcrc) - strm->adler = crc32(strm->adler, s->pending_buf, - s->pending); - s->gzindex = 0; - s->status = EXTRA_STATE; - } - } - else -#endif - { - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; - uInt level_flags; - - if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) - level_flags = 0; - else if (s->level < 6) - level_flags = 1; - else if (s->level == 6) - level_flags = 2; - else - level_flags = 3; - header |= (level_flags << 6); - if (s->strstart != 0) header |= PRESET_DICT; - header += 31 - (header % 31); - - s->status = BUSY_STATE; - putShortMSB(s, header); - - /* Save the adler32 of the preset dictionary: */ - if (s->strstart != 0) { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - strm->adler = adler32(0L, Z_NULL, 0); - } - } -#ifdef GZIP - if (s->status == EXTRA_STATE) { - if (s->gzhead->extra != NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - - while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) - break; - } - put_byte(s, s->gzhead->extra[s->gzindex]); - s->gzindex++; - } - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (s->gzindex == s->gzhead->extra_len) { - s->gzindex = 0; - s->status = NAME_STATE; - } - } - else - s->status = NAME_STATE; - } - if (s->status == NAME_STATE) { - if (s->gzhead->name != NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - int val; - - do { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) { - val = 1; - break; - } - } - val = s->gzhead->name[s->gzindex++]; - put_byte(s, val); - } while (val != 0); - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (val == 0) { - s->gzindex = 0; - s->status = COMMENT_STATE; - } - } - else - s->status = COMMENT_STATE; - } - if (s->status == COMMENT_STATE) { - if (s->gzhead->comment != NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - int val; - - do { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) { - val = 1; - break; - } - } - val = s->gzhead->comment[s->gzindex++]; - put_byte(s, val); - } while (val != 0); - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (val == 0) - s->status = HCRC_STATE; - } - else - s->status = HCRC_STATE; - } - if (s->status == HCRC_STATE) { - if (s->gzhead->hcrc) { - if (s->pending + 2 > s->pending_buf_size) - flush_pending(strm); - if (s->pending + 2 <= s->pending_buf_size) { - put_byte(s, (Byte)(strm->adler & 0xff)); - put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); - strm->adler = crc32(0L, Z_NULL, 0); - s->status = BUSY_STATE; - } - } - else - s->status = BUSY_STATE; - } -#endif - - /* Flush as much pending output as possible */ - if (s->pending != 0) { - flush_pending(strm); - if (strm->avail_out == 0) { - /* Since avail_out is 0, deflate will be called again with - * more output space, but possibly with both pending and - * avail_in equal to zero. There won't be anything to do, - * but this is not an error situation so make sure we - * return OK instead of BUF_ERROR at next call of deflate: - */ - s->last_flush = -1; - return Z_OK; - } - - /* Make sure there is something to do and avoid duplicate consecutive - * flushes. For repeated and useless calls with Z_FINISH, we keep - * returning Z_STREAM_END instead of Z_BUF_ERROR. - */ - } else if (strm->avail_in == 0 && flush <= old_flush && - flush != Z_FINISH) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* User must not provide more input after the first FINISH: */ - if (s->status == FINISH_STATE && strm->avail_in != 0) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* Start a new block or continue the current one. - */ - if (strm->avail_in != 0 || s->lookahead != 0 || - (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { - block_state bstate; - - bstate = (*(configuration_table[s->level].func))(s, flush); - - if (bstate == finish_started || bstate == finish_done) { - s->status = FINISH_STATE; - } - if (bstate == need_more || bstate == finish_started) { - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ - } - return Z_OK; - /* If flush != Z_NO_FLUSH && avail_out == 0, the next call - * of deflate should use the same flush parameter to make sure - * that the flush is complete. So we don't have to output an - * empty block here, this will be done at next call. This also - * ensures that for a very small output buffer, we emit at most - * one empty block. - */ - } - if (bstate == block_done) { - if (flush == Z_PARTIAL_FLUSH) { - _tr_align(s); - } else { /* FULL_FLUSH or SYNC_FLUSH */ - _tr_stored_block(s, (char*)0, 0L, 0); - /* For a full flush, this empty block will be recognized - * as a special marker by inflate_sync(). - */ - if (flush == Z_FULL_FLUSH) { - CLEAR_HASH(s); /* forget history */ - } - } - flush_pending(strm); - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ - return Z_OK; - } - } - } - Assert(strm->avail_out > 0, "bug2"); - - if (flush != Z_FINISH) return Z_OK; - if (s->wrap <= 0) return Z_STREAM_END; - - /* Write the trailer */ -#ifdef GZIP - if (s->wrap == 2) { - put_byte(s, (Byte)(strm->adler & 0xff)); - put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); - put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); - put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); - put_byte(s, (Byte)(strm->total_in & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); - } - else -#endif - { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - flush_pending(strm); - /* If avail_out is zero, the application will call deflate again - * to flush the rest. - */ - if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ - return s->pending != 0 ? Z_OK : Z_STREAM_END; -} - -/* ========================================================================= */ -int ZEXPORT deflateEnd (strm) - z_streamp strm; -{ - int status; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - - status = strm->state->status; - if (status != INIT_STATE && - status != EXTRA_STATE && - status != NAME_STATE && - status != COMMENT_STATE && - status != HCRC_STATE && - status != BUSY_STATE && - status != FINISH_STATE) { - return Z_STREAM_ERROR; - } - - /* Deallocate in reverse order of allocations: */ - TRY_FREE(strm, strm->state->pending_buf); - TRY_FREE(strm, strm->state->head); - TRY_FREE(strm, strm->state->prev); - TRY_FREE(strm, strm->state->window); - - ZFREE(strm, strm->state); - strm->state = Z_NULL; - - return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; -} - -/* ========================================================================= - * Copy the source state to the destination state. - * To simplify the source, this is not supported for 16-bit MSDOS (which - * doesn't have enough memory anyway to duplicate compression states). - */ -int ZEXPORT deflateCopy (dest, source) - z_streamp dest; - z_streamp source; -{ -#ifdef MAXSEG_64K - return Z_STREAM_ERROR; -#else - deflate_state *ds; - deflate_state *ss; - ushf *overlay; - - - if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { - return Z_STREAM_ERROR; - } - - ss = source->state; - - zmemcpy(dest, source, sizeof(z_stream)); - - ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); - if (ds == Z_NULL) return Z_MEM_ERROR; - dest->state = (struct internal_state FAR *) ds; - zmemcpy(ds, ss, sizeof(deflate_state)); - ds->strm = dest; - - ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); - ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); - ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); - overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); - ds->pending_buf = (uchf *) overlay; - - if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || - ds->pending_buf == Z_NULL) { - deflateEnd (dest); - return Z_MEM_ERROR; - } - /* following zmemcpy do not work for 16-bit MSDOS */ - zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); - zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); - zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); - zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); - - ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); - ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); - ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; - - ds->l_desc.dyn_tree = ds->dyn_ltree; - ds->d_desc.dyn_tree = ds->dyn_dtree; - ds->bl_desc.dyn_tree = ds->bl_tree; - - return Z_OK; -#endif /* MAXSEG_64K */ -} - -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->next_in buffer and copying from it. - * (See also flush_pending()). - */ -local int read_buf(strm, buf, size) - z_streamp strm; - Bytef *buf; - unsigned size; -{ - unsigned len = strm->avail_in; - - if (len > size) len = size; - if (len == 0) return 0; - - strm->avail_in -= len; - - if (strm->state->wrap == 1) { - strm->adler = adler32(strm->adler, strm->next_in, len); - } -#ifdef GZIP - else if (strm->state->wrap == 2) { - strm->adler = crc32(strm->adler, strm->next_in, len); - } -#endif - zmemcpy(buf, strm->next_in, len); - strm->next_in += len; - strm->total_in += len; - - return (int)len; -} - -/* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ -local void lm_init (s) - deflate_state *s; -{ - s->window_size = (ulg)2L*s->w_size; - - CLEAR_HASH(s); - - /* Set the default configuration parameters: - */ - s->max_lazy_match = configuration_table[s->level].max_lazy; - s->good_match = configuration_table[s->level].good_length; - s->nice_match = configuration_table[s->level].nice_length; - s->max_chain_length = configuration_table[s->level].max_chain; - - s->strstart = 0; - s->block_start = 0L; - s->lookahead = 0; - s->match_length = s->prev_length = MIN_MATCH-1; - s->match_available = 0; - s->ins_h = 0; -#ifndef FASTEST -#ifdef ASMV - match_init(); /* initialize the asm code */ -#endif -#endif -} - -#ifndef FASTEST -/* =========================================================================== - * Set match_start to the longest match starting at the given string and - * return its length. Matches shorter or equal to prev_length are discarded, - * in which case the result is equal to prev_length and match_start is - * garbage. - * IN assertions: cur_match is the head of the hash chain for the current - * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 - * OUT assertion: the match length is not greater than s->lookahead. - */ -#ifndef ASMV -/* For 80x86 and 680x0, an optimized version will be provided in match.asm or - * match.S. The code will be functionally equivalent. - */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - unsigned chain_length = s->max_chain_length;/* max hash chain length */ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - int best_len = s->prev_length; /* best match length so far */ - int nice_match = s->nice_match; /* stop if match long enough */ - IPos limit = s->strstart > (IPos)MAX_DIST(s) ? - s->strstart - (IPos)MAX_DIST(s) : NIL; - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0. - */ - Posf *prev = s->prev; - uInt wmask = s->w_mask; - -#ifdef UNALIGNED_OK - /* Compare two bytes at a time. Note: this is not always beneficial. - * Try with and without -DUNALIGNED_OK to check. - */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; - register ush scan_start = *(ushf*)scan; - register ush scan_end = *(ushf*)(scan+best_len-1); -#else - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - register Byte scan_end1 = scan[best_len-1]; - register Byte scan_end = scan[best_len]; -#endif - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - /* Do not waste too much time if we already have a good match: */ - if (s->prev_length >= s->good_match) { - chain_length >>= 2; - } - /* Do not look for matches beyond the end of the input. This is necessary - * to make deflate deterministic. - */ - if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - do { - Assert(cur_match < s->strstart, "no future"); - match = s->window + cur_match; - - /* Skip to next match if the match length cannot increase - * or if the match length is less than 2. Note that the checks below - * for insufficient lookahead only occur occasionally for performance - * reasons. Therefore uninitialized memory will be accessed, and - * conditional jumps will be made that depend on those values. - * However the length of the match is limited to the lookahead, so - * the output of deflate is not affected by the uninitialized values. - */ -#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) - /* This code assumes sizeof(unsigned short) == 2. Do not use - * UNALIGNED_OK if your compiler uses a different size. - */ - if (*(ushf*)(match+best_len-1) != scan_end || - *(ushf*)match != scan_start) continue; - - /* It is not necessary to compare scan[2] and match[2] since they are - * always equal when the other bytes match, given that the hash keys - * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at - * strstart+3, +5, ... up to strstart+257. We check for insufficient - * lookahead only every 4th comparison; the 128th check will be made - * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is - * necessary to put more guard bytes at the end of the window, or - * to check more often for insufficient lookahead. - */ - Assert(scan[2] == match[2], "scan[2]?"); - scan++, match++; - do { - } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - scan < strend); - /* The funny "do {}" generates better code on most compilers */ - - /* Here, scan <= window+strstart+257 */ - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - if (*scan == *match) scan++; - - len = (MAX_MATCH - 1) - (int)(strend-scan); - scan = strend - (MAX_MATCH-1); - -#else /* UNALIGNED_OK */ - - if (match[best_len] != scan_end || - match[best_len-1] != scan_end1 || - *match != *scan || - *++match != scan[1]) continue; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match++; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - scan = strend - MAX_MATCH; - -#endif /* UNALIGNED_OK */ - - if (len > best_len) { - s->match_start = cur_match; - best_len = len; - if (len >= nice_match) break; -#ifdef UNALIGNED_OK - scan_end = *(ushf*)(scan+best_len-1); -#else - scan_end1 = scan[best_len-1]; - scan_end = scan[best_len]; -#endif - } - } while ((cur_match = prev[cur_match & wmask]) > limit - && --chain_length != 0); - - if ((uInt)best_len <= s->lookahead) return (uInt)best_len; - return s->lookahead; -} -#endif /* ASMV */ -#endif /* FASTEST */ - -/* --------------------------------------------------------------------------- - * Optimized version for level == 1 or strategy == Z_RLE only - */ -local uInt longest_match_fast(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - Assert(cur_match < s->strstart, "no future"); - - match = s->window + cur_match; - - /* Return failure if the match length is less than 2: - */ - if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match += 2; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - - if (len < MIN_MATCH) return MIN_MATCH - 1; - - s->match_start = cur_match; - return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; -} - -#ifdef DEBUG -/* =========================================================================== - * Check that the match at match_start is indeed a match. - */ -local void check_match(s, start, match, length) - deflate_state *s; - IPos start, match; - int length; -{ - /* check that the match is indeed a match */ - if (zmemcmp(s->window + match, - s->window + start, length) != EQUAL) { - fprintf(stderr, " start %u, match %u, length %d\n", - start, match, length); - do { - fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); - } while (--length != 0); - z_error("invalid match"); - } - if (z_verbose > 1) { - fprintf(stderr,"\\[%d,%d]", start-match, length); - do { putc(s->window[start++], stderr); } while (--length != 0); - } -} -#else -# define check_match(s, start, match, length) -#endif /* DEBUG */ - -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ -local void fill_window(s) - deflate_state *s; -{ - register unsigned n, m; - register Posf *p; - unsigned more; /* Amount of free space at the end of the window. */ - uInt wsize = s->w_size; - - do { - more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); - - /* Deal with !@#$% 64K limit: */ - if (sizeof(int) <= 2) { - if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - more = wsize; - - } else if (more == (unsigned)(-1)) { - /* Very unlikely, but possible on 16 bit machine if - * strstart == 0 && lookahead == 1 (input done a byte at time) - */ - more--; - } - } - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (s->strstart >= wsize+MAX_DIST(s)) { - - zmemcpy(s->window, s->window+wsize, (unsigned)wsize); - s->match_start -= wsize; - s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ - s->block_start -= (long) wsize; - - /* Slide the hash table (could be avoided with 32 bit values - at the expense of memory usage). We slide even when level == 0 - to keep the hash table consistent if we switch back to level > 0 - later. (Using level 0 permanently is not an optimal usage of - zlib, so we don't care about this pathological case.) - */ - /* %%% avoid this when Z_RLE */ - n = s->hash_size; - p = &s->head[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - } while (--n); - - n = wsize; -#ifndef FASTEST - p = &s->prev[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); -#endif - more += wsize; - } - if (s->strm->avail_in == 0) return; - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - Assert(more >= 2, "more < 2"); - - n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); - s->lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s->lookahead >= MIN_MATCH) { - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ - - } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); -} - -/* =========================================================================== - * Flush the current block, with given end-of-file flag. - * IN assertion: strstart is set to the end of the current match. - */ -#define FLUSH_BLOCK_ONLY(s, eof) { \ - _tr_flush_block(s, (s->block_start >= 0L ? \ - (charf *)&s->window[(unsigned)s->block_start] : \ - (charf *)Z_NULL), \ - (ulg)((long)s->strstart - s->block_start), \ - (eof)); \ - s->block_start = s->strstart; \ - flush_pending(s->strm); \ - Tracev((stderr,"[FLUSH]")); \ -} - -/* Same but force premature exit if necessary. */ -#define FLUSH_BLOCK(s, eof) { \ - FLUSH_BLOCK_ONLY(s, eof); \ - if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ -} - -/* =========================================================================== - * Copy without compression as much as possible from the input stream, return - * the current block state. - * This function does not insert new strings in the dictionary since - * uncompressible data is probably not useful. This function is used - * only for the level=0 compression option. - * NOTE: this function should be optimized to avoid extra copying from - * window to pending_buf. - */ -local block_state deflate_stored(s, flush) - deflate_state *s; - int flush; -{ - /* Stored blocks are limited to 0xffff bytes, pending_buf is limited - * to pending_buf_size, and each stored block has a 5 byte header: - */ - ulg max_block_size = 0xffff; - ulg max_start; - - if (max_block_size > s->pending_buf_size - 5) { - max_block_size = s->pending_buf_size - 5; - } - - /* Copy as much as possible from input to output: */ - for (;;) { - /* Fill the window as much as possible: */ - if (s->lookahead <= 1) { - - Assert(s->strstart < s->w_size+MAX_DIST(s) || - s->block_start >= (long)s->w_size, "slide too late"); - - fill_window(s); - if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; - - if (s->lookahead == 0) break; /* flush the current block */ - } - Assert(s->block_start >= 0L, "block gone"); - - s->strstart += s->lookahead; - s->lookahead = 0; - - /* Emit a stored block if pending_buf will be full: */ - max_start = s->block_start + max_block_size; - if (s->strstart == 0 || (ulg)s->strstart >= max_start) { - /* strstart == 0 is possible when wraparound on 16-bit machine */ - s->lookahead = (uInt)(s->strstart - max_start); - s->strstart = (uInt)max_start; - FLUSH_BLOCK(s, 0); - } - /* Flush if we may have to slide, otherwise block_start may become - * negative and the data will be gone: - */ - if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { - FLUSH_BLOCK(s, 0); - } - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} - -/* =========================================================================== - * Compress as much as possible from the input stream, return the current - * block state. - * This function does not perform lazy evaluation of matches and inserts - * new strings in the dictionary only for unmatched strings or for short - * matches. It is used only for the fast compression options. - */ -local block_state deflate_fast(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head = NIL; /* head of the hash chain */ - int bflush; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - * At this point we have always match_length < MIN_MATCH - */ - if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ -#ifdef FASTEST - if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || - (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { - s->match_length = longest_match_fast (s, hash_head); - } -#else - if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { - s->match_length = longest_match (s, hash_head); - } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { - s->match_length = longest_match_fast (s, hash_head); - } -#endif - /* longest_match() or longest_match_fast() sets match_start */ - } - if (s->match_length >= MIN_MATCH) { - check_match(s, s->strstart, s->match_start, s->match_length); - - _tr_tally_dist(s, s->strstart - s->match_start, - s->match_length - MIN_MATCH, bflush); - - s->lookahead -= s->match_length; - - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ -#ifndef FASTEST - if (s->match_length <= s->max_insert_length && - s->lookahead >= MIN_MATCH) { - s->match_length--; /* string at strstart already in table */ - do { - s->strstart++; - INSERT_STRING(s, s->strstart, hash_head); - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. - */ - } while (--s->match_length != 0); - s->strstart++; - } else -#endif - { - s->strstart += s->match_length; - s->match_length = 0; - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not - * matter since it will be recomputed at next deflate call. - */ - } - } else { - /* No match, output a literal byte */ - Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - } - if (bflush) FLUSH_BLOCK(s, 0); - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} - -#ifndef FASTEST -/* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ -local block_state deflate_slow(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head = NIL; /* head of hash chain */ - int bflush; /* set if current block must be flushed */ - - /* Process the input block. */ - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - */ - s->prev_length = s->match_length, s->prev_match = s->match_start; - s->match_length = MIN_MATCH-1; - - if (hash_head != NIL && s->prev_length < s->max_lazy_match && - s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { - s->match_length = longest_match (s, hash_head); - } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { - s->match_length = longest_match_fast (s, hash_head); - } - /* longest_match() or longest_match_fast() sets match_start */ - - if (s->match_length <= 5 && (s->strategy == Z_FILTERED -#if TOO_FAR <= 32767 - || (s->match_length == MIN_MATCH && - s->strstart - s->match_start > TOO_FAR) -#endif - )) { - - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - s->match_length = MIN_MATCH-1; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { - uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; - /* Do not insert strings in hash table beyond this. */ - - check_match(s, s->strstart-1, s->prev_match, s->prev_length); - - _tr_tally_dist(s, s->strstart -1 - s->prev_match, - s->prev_length - MIN_MATCH, bflush); - - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not - * enough lookahead, the last two strings are not inserted in - * the hash table. - */ - s->lookahead -= s->prev_length-1; - s->prev_length -= 2; - do { - if (++s->strstart <= max_insert) { - INSERT_STRING(s, s->strstart, hash_head); - } - } while (--s->prev_length != 0); - s->match_available = 0; - s->match_length = MIN_MATCH-1; - s->strstart++; - - if (bflush) FLUSH_BLOCK(s, 0); - - } else if (s->match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - if (bflush) { - FLUSH_BLOCK_ONLY(s, 0); - } - s->strstart++; - s->lookahead--; - if (s->strm->avail_out == 0) return need_more; - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - s->match_available = 1; - s->strstart++; - s->lookahead--; - } - } - Assert (flush != Z_NO_FLUSH, "no flush?"); - if (s->match_available) { - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - s->match_available = 0; - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} -#endif /* FASTEST */ - -#if 0 -/* =========================================================================== - * For Z_RLE, simply look for runs of bytes, generate matches only of distance - * one. Do not maintain a hash table. (It will be regenerated if this run of - * deflate switches away from Z_RLE.) - */ -local block_state deflate_rle(s, flush) - deflate_state *s; - int flush; -{ - int bflush; /* set if current block must be flushed */ - uInt run; /* length of run */ - uInt max; /* maximum length of run */ - uInt prev; /* byte at distance one to match */ - Bytef *scan; /* scan for end of run */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the longest encodable run. - */ - if (s->lookahead < MAX_MATCH) { - fill_window(s); - if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* See how many times the previous byte repeats */ - run = 0; - if (s->strstart > 0) { /* if there is a previous byte, that is */ - max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; - scan = s->window + s->strstart - 1; - prev = *scan++; - do { - if (*scan++ != prev) - break; - } while (++run < max); - } - - /* Emit match if have run of MIN_MATCH or longer, else emit literal */ - if (run >= MIN_MATCH) { - check_match(s, s->strstart, s->strstart - 1, run); - _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); - s->lookahead -= run; - s->strstart += run; - } else { - /* No match, output a literal byte */ - Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - } - if (bflush) FLUSH_BLOCK(s, 0); - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} -#endif +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); + dictionary += dictLength - length; /* use the tail of the dictionary */ + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy(dest, source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy(ds, ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + /* %%% avoid this when Z_RLE */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ + +#if 0 +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt run; /* length of run */ + uInt max; /* maximum length of run */ + uInt prev; /* byte at distance one to match */ + Bytef *scan; /* scan for end of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest encodable run. + */ + if (s->lookahead < MAX_MATCH) { + fill_window(s); + if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + run = 0; + if (s->strstart > 0) { /* if there is a previous byte, that is */ + max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; + scan = s->window + s->strstart - 1; + prev = *scan++; + do { + if (*scan++ != prev) + break; + } while (++run < max); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (run >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, run); + _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); + s->lookahead -= run; + s->strstart += run; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif diff --git a/pcsx2/3rdparty/zlib/deflate.h b/pcsx2/3rdparty/zlib/deflate.h index 222c53e043..05a5ab3a2c 100644 --- a/pcsx2/3rdparty/zlib/deflate.h +++ b/pcsx2/3rdparty/zlib/deflate.h @@ -1,331 +1,331 @@ -/* deflate.h -- internal compression state - * Copyright (C) 1995-2004 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id$ */ - -#ifndef DEFLATE_H -#define DEFLATE_H - -#include "zutil.h" - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer creation by deflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip encoding - should be left enabled. */ -#ifndef NO_GZIP -# define GZIP -#endif - -/* =========================================================================== - * Internal compression state. - */ - -#define LENGTH_CODES 29 -/* number of length codes, not counting the special END_BLOCK code */ - -#define LITERALS 256 -/* number of literal bytes 0..255 */ - -#define L_CODES (LITERALS+1+LENGTH_CODES) -/* number of Literal or Length codes, including the END_BLOCK code */ - -#define D_CODES 30 -/* number of distance codes */ - -#define BL_CODES 19 -/* number of codes used to transfer the bit lengths */ - -#define HEAP_SIZE (2*L_CODES+1) -/* maximum heap size */ - -#define MAX_BITS 15 -/* All codes must not exceed MAX_BITS bits */ - -#define INIT_STATE 42 -#define EXTRA_STATE 69 -#define NAME_STATE 73 -#define COMMENT_STATE 91 -#define HCRC_STATE 103 -#define BUSY_STATE 113 -#define FINISH_STATE 666 -/* Stream status */ - - -/* Data structure describing a single value and its code string. */ -typedef struct ct_data_s { - union { - ush freq; /* frequency count */ - ush code; /* bit string */ - } fc; - union { - ush dad; /* father node in Huffman tree */ - ush len; /* length of bit string */ - } dl; -} FAR ct_data; - -#define Freq fc.freq -#define Code fc.code -#define Dad dl.dad -#define Len dl.len - -typedef struct static_tree_desc_s static_tree_desc; - -typedef struct tree_desc_s { - ct_data *dyn_tree; /* the dynamic tree */ - int max_code; /* largest code with non zero frequency */ - static_tree_desc *stat_desc; /* the corresponding static tree */ -} FAR tree_desc; - -typedef ush Pos; -typedef Pos FAR Posf; -typedef unsigned IPos; - -/* A Pos is an index in the character window. We use short instead of int to - * save space in the various tables. IPos is used only for parameter passing. - */ - -typedef struct internal_state { - z_streamp strm; /* pointer back to this zlib stream */ - int status; /* as the name implies */ - Bytef *pending_buf; /* output still pending */ - ulg pending_buf_size; /* size of pending_buf */ - Bytef *pending_out; /* next pending byte to output to the stream */ - uInt pending; /* nb of bytes in the pending buffer */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - gz_headerp gzhead; /* gzip header information to write */ - uInt gzindex; /* where in extra, name, or comment */ - Byte method; /* STORED (for zip only) or DEFLATED */ - int last_flush; /* value of flush param for previous deflate call */ - - /* used by deflate.c: */ - - uInt w_size; /* LZ77 window size (32K by default) */ - uInt w_bits; /* log2(w_size) (8..16) */ - uInt w_mask; /* w_size - 1 */ - - Bytef *window; - /* Sliding window. Input bytes are read into the second half of the window, - * and move to the first half later to keep a dictionary of at least wSize - * bytes. With this organization, matches are limited to a distance of - * wSize-MAX_MATCH bytes, but this ensures that IO is always - * performed with a length multiple of the block size. Also, it limits - * the window size to 64K, which is quite useful on MSDOS. - * To do: use the user input buffer as sliding window. - */ - - ulg window_size; - /* Actual size of window: 2*wSize, except when the user input buffer - * is directly used as sliding window. - */ - - Posf *prev; - /* Link to older string with same hash index. To limit the size of this - * array to 64K, this link is maintained only for the last 32K strings. - * An index in this array is thus a window index modulo 32K. - */ - - Posf *head; /* Heads of the hash chains or NIL. */ - - uInt ins_h; /* hash index of string to be inserted */ - uInt hash_size; /* number of elements in hash table */ - uInt hash_bits; /* log2(hash_size) */ - uInt hash_mask; /* hash_size-1 */ - - uInt hash_shift; - /* Number of bits by which ins_h must be shifted at each input - * step. It must be such that after MIN_MATCH steps, the oldest - * byte no longer takes part in the hash key, that is: - * hash_shift * MIN_MATCH >= hash_bits - */ - - long block_start; - /* Window position at the beginning of the current output block. Gets - * negative when the window is moved backwards. - */ - - uInt match_length; /* length of best match */ - IPos prev_match; /* previous match */ - int match_available; /* set if previous match exists */ - uInt strstart; /* start of string to insert */ - uInt match_start; /* start of matching string */ - uInt lookahead; /* number of valid bytes ahead in window */ - - uInt prev_length; - /* Length of the best match at previous step. Matches not greater than this - * are discarded. This is used in the lazy match evaluation. - */ - - uInt max_chain_length; - /* To speed up deflation, hash chains are never searched beyond this - * length. A higher limit improves compression ratio but degrades the - * speed. - */ - - uInt max_lazy_match; - /* Attempt to find a better match only when the current match is strictly - * smaller than this value. This mechanism is used only for compression - * levels >= 4. - */ -# define max_insert_length max_lazy_match - /* Insert new strings in the hash table only if the match length is not - * greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 3. - */ - - int level; /* compression level (1..9) */ - int strategy; /* favor or force Huffman coding*/ - - uInt good_match; - /* Use a faster search when the previous match is longer than this */ - - int nice_match; /* Stop searching when current match exceeds this */ - - /* used by trees.c: */ - /* Didn't use ct_data typedef below to supress compiler warning */ - struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ - struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ - struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ - - struct tree_desc_s l_desc; /* desc. for literal tree */ - struct tree_desc_s d_desc; /* desc. for distance tree */ - struct tree_desc_s bl_desc; /* desc. for bit length tree */ - - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ - int heap_len; /* number of elements in the heap */ - int heap_max; /* element of largest frequency */ - /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - * The same heap array is used to build all trees. - */ - - uch depth[2*L_CODES+1]; - /* Depth of each subtree used as tie breaker for trees of equal frequency - */ - - uchf *l_buf; /* buffer for literals or lengths */ - - uInt lit_bufsize; - /* Size of match buffer for literals/lengths. There are 4 reasons for - * limiting lit_bufsize to 64K: - * - frequencies can be kept in 16 bit counters - * - if compression is not successful for the first block, all input - * data is still in the window so we can still emit a stored block even - * when input comes from standard input. (This can also be done for - * all blocks if lit_bufsize is not greater than 32K.) - * - if compression is not successful for a file smaller than 64K, we can - * even emit a stored file instead of a stored block (saving 5 bytes). - * This is applicable only for zip (not gzip or zlib). - * - creating new Huffman trees less frequently may not provide fast - * adaptation to changes in the input data statistics. (Take for - * example a binary file with poorly compressible code followed by - * a highly compressible string table.) Smaller buffer sizes give - * fast adaptation but have of course the overhead of transmitting - * trees more frequently. - * - I can't count above 4 - */ - - uInt last_lit; /* running index in l_buf */ - - ushf *d_buf; - /* Buffer for distances. To simplify the code, d_buf and l_buf have - * the same number of elements. To use different lengths, an extra flag - * array would be necessary. - */ - - ulg opt_len; /* bit length of current block with optimal trees */ - ulg static_len; /* bit length of current block with static trees */ - uInt matches; /* number of string matches in current block */ - int last_eob_len; /* bit length of EOB code for last block */ - -#ifdef DEBUG - ulg compressed_len; /* total bit length of compressed file mod 2^32 */ - ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ -#endif - - ush bi_buf; - /* Output buffer. bits are inserted starting at the bottom (least - * significant bits). - */ - int bi_valid; - /* Number of valid bits in bi_buf. All bits above the last valid bit - * are always zero. - */ - -} FAR deflate_state; - -/* Output a byte on the stream. - * IN assertion: there is enough room in pending_buf. - */ -#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} - - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) -/* In order to simplify the code, particularly on 16 bit machines, match - * distances are limited to MAX_DIST instead of WSIZE. - */ - - /* in trees.c */ -void _tr_init OF((deflate_state *s)); -int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); -void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); -void _tr_align OF((deflate_state *s)); -void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); - -#define d_code(dist) \ - ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) -/* Mapping from a distance to a distance code. dist is the distance - 1 and - * must not have side effects. _dist_code[256] and _dist_code[257] are never - * used. - */ - -#ifndef DEBUG -/* Inline versions of _tr_tally for speed: */ - -#if defined(GEN_TREES_H) || !defined(STDC) - extern uch _length_code[]; - extern uch _dist_code[]; -#else - extern const uch _length_code[]; - extern const uch _dist_code[]; -#endif - -# define _tr_tally_lit(s, c, flush) \ - { uch cc = (c); \ - s->d_buf[s->last_lit] = 0; \ - s->l_buf[s->last_lit++] = cc; \ - s->dyn_ltree[cc].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -# define _tr_tally_dist(s, distance, length, flush) \ - { uch len = (length); \ - ush dist = (distance); \ - s->d_buf[s->last_lit] = dist; \ - s->l_buf[s->last_lit++] = len; \ - dist--; \ - s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ - s->dyn_dtree[d_code(dist)].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -#else -# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) -# define _tr_tally_dist(s, distance, length, flush) \ - flush = _tr_tally(s, distance, length) -#endif - -#endif /* DEFLATE_H */ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2004 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/pcsx2/3rdparty/zlib/gzio.c b/pcsx2/3rdparty/zlib/gzio.c index 2de9a36441..b3c59ecd4c 100644 --- a/pcsx2/3rdparty/zlib/gzio.c +++ b/pcsx2/3rdparty/zlib/gzio.c @@ -1,1026 +1,1026 @@ -/* gzio.c -- IO on .gz files - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. - */ - -/* @(#) $Id$ */ - -#include - -#include "zutil.h" - -#ifdef NO_DEFLATE /* for compatibility with old definition */ -# define NO_GZCOMPRESS -#endif - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -#ifndef Z_BUFSIZE -# ifdef MAXSEG_64K -# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ -# else -# define Z_BUFSIZE 16384 -# endif -#endif -#ifndef Z_PRINTF_BUFSIZE -# define Z_PRINTF_BUFSIZE 4096 -#endif - -#ifdef __MVS__ -# pragma map (fdopen , "\174\174FDOPEN") - FILE *fdopen(int, const char *); -#endif - -#ifndef STDC -extern voidp malloc OF((uInt size)); -extern void free OF((voidpf ptr)); -#endif - -#define ALLOC(size) malloc(size) -#define TRYFREE(p) {if (p) free(p);} - -static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ - -/* gzip flag byte */ -#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ -#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ -#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ -#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ -#define COMMENT 0x10 /* bit 4 set: file comment present */ -#define RESERVED 0xE0 /* bits 5..7: reserved */ - -typedef struct gz_stream { - z_stream stream; - int z_err; /* error code for last stream operation */ - int z_eof; /* set if end of input file */ - FILE *file; /* .gz file */ - Byte *inbuf; /* input buffer */ - Byte *outbuf; /* output buffer */ - uLong crc; /* crc32 of uncompressed data */ - char *msg; /* error message */ - char *path; /* path name for debugging only */ - int transparent; /* 1 if input file is not a .gz file */ - char mode; /* 'w' or 'r' */ - z_off_t start; /* start of compressed data in file (header skipped) */ - z_off_t in; /* bytes into deflate or inflate */ - z_off_t out; /* bytes out of deflate or inflate */ - int back; /* one character push-back */ - int last; /* true if push-back is last character */ -} gz_stream; - - -local gzFile gz_open OF((const char *path, const char *mode, int fd)); -local int do_flush OF((gzFile file, int flush)); -local int get_byte OF((gz_stream *s)); -local void check_header OF((gz_stream *s)); -local int destroy OF((gz_stream *s)); -local void putLong OF((FILE *file, uLong x)); -local uLong getLong OF((gz_stream *s)); - -/* =========================================================================== - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb"). The file is given either by file descriptor - or path name (if fd == -1). - gz_open returns NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). -*/ -local gzFile gz_open (path, mode, fd) - const char *path; - const char *mode; - int fd; -{ - int err; - int level = Z_BEST_SPEED; /* compression level */ - int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ - char *p = (char*)mode; - gz_stream *s; - char fmode[80]; /* copy of mode, without the compression level */ - char *m = fmode; - - if (!path || !mode) return Z_NULL; - - s = (gz_stream *)ALLOC(sizeof(gz_stream)); - if (!s) return Z_NULL; - - s->stream.zalloc = (alloc_func)0; - s->stream.zfree = (free_func)0; - s->stream.opaque = (voidpf)0; - s->stream.next_in = s->inbuf = Z_NULL; - s->stream.next_out = s->outbuf = Z_NULL; - s->stream.avail_in = s->stream.avail_out = 0; - s->file = NULL; - s->z_err = Z_OK; - s->z_eof = 0; - s->in = 0; - s->out = 0; - s->back = EOF; - s->crc = crc32(0L, Z_NULL, 0); - s->msg = NULL; - s->transparent = 0; - - s->path = (char*)ALLOC(strlen(path)+1); - if (s->path == NULL) { - return destroy(s), (gzFile)Z_NULL; - } - strcpy(s->path, path); /* do this early for debugging */ - - s->mode = '\0'; - do { - if (*p == 'r') s->mode = 'r'; - if (*p == 'w' || *p == 'a') s->mode = 'w'; - if (*p >= '0' && *p <= '9') { - level = *p - '0'; - } else if (*p == 'f') { - strategy = Z_FILTERED; - } else if (*p == 'h') { - strategy = Z_HUFFMAN_ONLY; - } else if (*p == 'R') { - strategy = Z_RLE; - } else { - *m++ = *p; /* copy the mode */ - } - } while (*p++ && m != fmode + sizeof(fmode)); - if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - err = Z_STREAM_ERROR; -#else - err = deflateInit2(&(s->stream), level, - Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); - /* windowBits is passed < 0 to suppress zlib header */ - - s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); -#endif - if (err != Z_OK || s->outbuf == Z_NULL) { - return destroy(s), (gzFile)Z_NULL; - } - } else { - s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); - - err = inflateInit2(&(s->stream), -MAX_WBITS); - /* windowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are - * present after the compressed stream. - */ - if (err != Z_OK || s->inbuf == Z_NULL) { - return destroy(s), (gzFile)Z_NULL; - } - } - s->stream.avail_out = Z_BUFSIZE; - - errno = 0; - s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); - - if (s->file == NULL) { - return destroy(s), (gzFile)Z_NULL; - } - if (s->mode == 'w') { - /* Write a very simple .gz header: - */ - fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], - Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); - s->start = 10L; - /* We use 10L instead of ftell(s->file) to because ftell causes an - * fflush on some systems. This version of the library doesn't use - * start anyway in write mode, so this initialization is not - * necessary. - */ - } else { - check_header(s); /* skip the .gz header */ - s->start = ftell(s->file) - s->stream.avail_in; - } - - return (gzFile)s; -} - -/* =========================================================================== - Opens a gzip (.gz) file for reading or writing. -*/ -gzFile ZEXPORT gzopen (path, mode) - const char *path; - const char *mode; -{ - return gz_open (path, mode, -1); -} - -/* =========================================================================== - Associate a gzFile with the file descriptor fd. fd is not dup'ed here - to mimic the behavio(u)r of fdopen. -*/ -gzFile ZEXPORT gzdopen (fd, mode) - int fd; - const char *mode; -{ - char name[46]; /* allow for up to 128-bit integers */ - - if (fd < 0) return (gzFile)Z_NULL; - sprintf(name, "", fd); /* for debugging */ - - return gz_open (name, mode, fd); -} - -/* =========================================================================== - * Update the compression level and strategy - */ -int ZEXPORT gzsetparams (file, level, strategy) - gzFile file; - int level; - int strategy; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - /* Make room to allow flushing */ - if (s->stream.avail_out == 0) { - - s->stream.next_out = s->outbuf; - if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { - s->z_err = Z_ERRNO; - } - s->stream.avail_out = Z_BUFSIZE; - } - - return deflateParams (&(s->stream), level, strategy); -} - -/* =========================================================================== - Read a byte from a gz_stream; update next_in and avail_in. Return EOF - for end of file. - IN assertion: the stream s has been sucessfully opened for reading. -*/ -local int get_byte(s) - gz_stream *s; -{ - if (s->z_eof) return EOF; - if (s->stream.avail_in == 0) { - errno = 0; - s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); - if (s->stream.avail_in == 0) { - s->z_eof = 1; - if (ferror(s->file)) s->z_err = Z_ERRNO; - return EOF; - } - s->stream.next_in = s->inbuf; - } - s->stream.avail_in--; - return *(s->stream.next_in)++; -} - -/* =========================================================================== - Check the gzip header of a gz_stream opened for reading. Set the stream - mode to transparent if the gzip magic header is not present; set s->err - to Z_DATA_ERROR if the magic header is present but the rest of the header - is incorrect. - IN assertion: the stream s has already been created sucessfully; - s->stream.avail_in is zero for the first time, but may be non-zero - for concatenated .gz files. -*/ -local void check_header(s) - gz_stream *s; -{ - int method; /* method byte */ - int flags; /* flags byte */ - uInt len; - int c; - - /* Assure two bytes in the buffer so we can peek ahead -- handle case - where first byte of header is at the end of the buffer after the last - gzip segment */ - len = s->stream.avail_in; - if (len < 2) { - if (len) s->inbuf[0] = s->stream.next_in[0]; - errno = 0; - len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); - if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; - s->stream.avail_in += len; - s->stream.next_in = s->inbuf; - if (s->stream.avail_in < 2) { - s->transparent = s->stream.avail_in; - return; - } - } - - /* Peek ahead to check the gzip magic header */ - if (s->stream.next_in[0] != gz_magic[0] || - s->stream.next_in[1] != gz_magic[1]) { - s->transparent = 1; - return; - } - s->stream.avail_in -= 2; - s->stream.next_in += 2; - - /* Check the rest of the gzip header */ - method = get_byte(s); - flags = get_byte(s); - if (method != Z_DEFLATED || (flags & RESERVED) != 0) { - s->z_err = Z_DATA_ERROR; - return; - } - - /* Discard time, xflags and OS code: */ - for (len = 0; len < 6; len++) (void)get_byte(s); - - if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ - len = (uInt)get_byte(s); - len += ((uInt)get_byte(s))<<8; - /* len is garbage if EOF but the loop below will quit anyway */ - while (len-- != 0 && get_byte(s) != EOF) ; - } - if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ - while ((c = get_byte(s)) != 0 && c != EOF) ; - } - if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ - while ((c = get_byte(s)) != 0 && c != EOF) ; - } - if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ - for (len = 0; len < 2; len++) (void)get_byte(s); - } - s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; -} - - /* =========================================================================== - * Cleanup then free the given gz_stream. Return a zlib error code. - Try freeing in the reverse order of allocations. - */ -local int destroy (s) - gz_stream *s; -{ - int err = Z_OK; - - if (!s) return Z_STREAM_ERROR; - - TRYFREE(s->msg); - - if (s->stream.state != NULL) { - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - err = Z_STREAM_ERROR; -#else - err = deflateEnd(&(s->stream)); -#endif - } else if (s->mode == 'r') { - err = inflateEnd(&(s->stream)); - } - } - if (s->file != NULL && fclose(s->file)) { -#ifdef ESPIPE - if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ -#endif - err = Z_ERRNO; - } - if (s->z_err < 0) err = s->z_err; - - TRYFREE(s->inbuf); - TRYFREE(s->outbuf); - TRYFREE(s->path); - TRYFREE(s); - return err; -} - -/* =========================================================================== - Reads the given number of uncompressed bytes from the compressed file. - gzread returns the number of bytes actually read (0 for end of file). -*/ -int ZEXPORT gzread (file, buf, len) - gzFile file; - voidp buf; - unsigned len; -{ - gz_stream *s = (gz_stream*)file; - Bytef *start = (Bytef*)buf; /* starting point for crc computation */ - Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ - - if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; - - if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; - if (s->z_err == Z_STREAM_END) return 0; /* EOF */ - - next_out = (Byte*)buf; - s->stream.next_out = (Bytef*)buf; - s->stream.avail_out = len; - - if (s->stream.avail_out && s->back != EOF) { - *next_out++ = s->back; - s->stream.next_out++; - s->stream.avail_out--; - s->back = EOF; - s->out++; - start++; - if (s->last) { - s->z_err = Z_STREAM_END; - return 1; - } - } - - while (s->stream.avail_out != 0) { - - if (s->transparent) { - /* Copy first the lookahead bytes: */ - uInt n = s->stream.avail_in; - if (n > s->stream.avail_out) n = s->stream.avail_out; - if (n > 0) { - zmemcpy(s->stream.next_out, s->stream.next_in, n); - next_out += n; - s->stream.next_out = next_out; - s->stream.next_in += n; - s->stream.avail_out -= n; - s->stream.avail_in -= n; - } - if (s->stream.avail_out > 0) { - s->stream.avail_out -= - (uInt)fread(next_out, 1, s->stream.avail_out, s->file); - } - len -= s->stream.avail_out; - s->in += len; - s->out += len; - if (len == 0) s->z_eof = 1; - return (int)len; - } - if (s->stream.avail_in == 0 && !s->z_eof) { - - errno = 0; - s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); - if (s->stream.avail_in == 0) { - s->z_eof = 1; - if (ferror(s->file)) { - s->z_err = Z_ERRNO; - break; - } - } - s->stream.next_in = s->inbuf; - } - s->in += s->stream.avail_in; - s->out += s->stream.avail_out; - s->z_err = inflate(&(s->stream), Z_NO_FLUSH); - s->in -= s->stream.avail_in; - s->out -= s->stream.avail_out; - - if (s->z_err == Z_STREAM_END) { - /* Check CRC and original size */ - s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); - start = s->stream.next_out; - - if (getLong(s) != s->crc) { - s->z_err = Z_DATA_ERROR; - } else { - (void)getLong(s); - /* The uncompressed length returned by above getlong() may be - * different from s->out in case of concatenated .gz files. - * Check for such files: - */ - check_header(s); - if (s->z_err == Z_OK) { - inflateReset(&(s->stream)); - s->crc = crc32(0L, Z_NULL, 0); - } - } - } - if (s->z_err != Z_OK || s->z_eof) break; - } - s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); - - if (len == s->stream.avail_out && - (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) - return -1; - return (int)(len - s->stream.avail_out); -} - - -/* =========================================================================== - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. -*/ -int ZEXPORT gzgetc(file) - gzFile file; -{ - unsigned char c; - - return gzread(file, &c, 1) == 1 ? c : -1; -} - - -/* =========================================================================== - Push one byte back onto the stream. -*/ -int ZEXPORT gzungetc(c, file) - int c; - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; - s->back = c; - s->out--; - s->last = (s->z_err == Z_STREAM_END); - if (s->last) s->z_err = Z_OK; - s->z_eof = 0; - return c; -} - - -/* =========================================================================== - Reads bytes from the compressed file until len-1 characters are - read, or a newline character is read and transferred to buf, or an - end-of-file condition is encountered. The string is then terminated - with a null character. - gzgets returns buf, or Z_NULL in case of error. - - The current implementation is not optimized at all. -*/ -char * ZEXPORT gzgets(file, buf, len) - gzFile file; - char *buf; - int len; -{ - char *b = buf; - if (buf == Z_NULL || len <= 0) return Z_NULL; - - while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; - *buf = '\0'; - return b == buf && len > 0 ? Z_NULL : b; -} - - -#ifndef NO_GZCOMPRESS -/* =========================================================================== - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of bytes actually written (0 in case of error). -*/ -int ZEXPORT gzwrite (file, buf, len) - gzFile file; - voidpc buf; - unsigned len; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - s->stream.next_in = (Bytef*)buf; - s->stream.avail_in = len; - - while (s->stream.avail_in != 0) { - - if (s->stream.avail_out == 0) { - - s->stream.next_out = s->outbuf; - if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { - s->z_err = Z_ERRNO; - break; - } - s->stream.avail_out = Z_BUFSIZE; - } - s->in += s->stream.avail_in; - s->out += s->stream.avail_out; - s->z_err = deflate(&(s->stream), Z_NO_FLUSH); - s->in -= s->stream.avail_in; - s->out -= s->stream.avail_out; - if (s->z_err != Z_OK) break; - } - s->crc = crc32(s->crc, (const Bytef *)buf, len); - - return (int)(len - s->stream.avail_in); -} - - -/* =========================================================================== - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). -*/ -#ifdef STDC -#include - -int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) -{ - char buf[Z_PRINTF_BUFSIZE]; - va_list va; - int len; - - buf[sizeof(buf) - 1] = 0; - va_start(va, format); -#ifdef NO_vsnprintf -# ifdef HAS_vsprintf_void - (void)vsprintf(buf, format, va); - va_end(va); - for (len = 0; len < sizeof(buf); len++) - if (buf[len] == 0) break; -# else - len = vsprintf(buf, format, va); - va_end(va); -# endif -#else -# ifdef HAS_vsnprintf_void - (void)vsnprintf(buf, sizeof(buf), format, va); - va_end(va); - len = strlen(buf); -# else - len = vsnprintf(buf, sizeof(buf), format, va); - va_end(va); -# endif -#endif - if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) - return 0; - return gzwrite(file, buf, (unsigned)len); -} -#else /* not ANSI C */ - -int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) - gzFile file; - const char *format; - int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; -{ - char buf[Z_PRINTF_BUFSIZE]; - int len; - - buf[sizeof(buf) - 1] = 0; -#ifdef NO_snprintf -# ifdef HAS_sprintf_void - sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); - for (len = 0; len < sizeof(buf); len++) - if (buf[len] == 0) break; -# else - len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); -# endif -#else -# ifdef HAS_snprintf_void - snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); - len = strlen(buf); -# else - len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); -# endif -#endif - if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) - return 0; - return gzwrite(file, buf, len); -} -#endif - -/* =========================================================================== - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. -*/ -int ZEXPORT gzputc(file, c) - gzFile file; - int c; -{ - unsigned char cc = (unsigned char) c; /* required for big endian systems */ - - return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; -} - - -/* =========================================================================== - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. -*/ -int ZEXPORT gzputs(file, s) - gzFile file; - const char *s; -{ - return gzwrite(file, (char*)s, (unsigned)strlen(s)); -} - - -/* =========================================================================== - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. -*/ -local int do_flush (file, flush) - gzFile file; - int flush; -{ - uInt len; - int done = 0; - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - s->stream.avail_in = 0; /* should be zero already anyway */ - - for (;;) { - len = Z_BUFSIZE - s->stream.avail_out; - - if (len != 0) { - if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { - s->z_err = Z_ERRNO; - return Z_ERRNO; - } - s->stream.next_out = s->outbuf; - s->stream.avail_out = Z_BUFSIZE; - } - if (done) break; - s->out += s->stream.avail_out; - s->z_err = deflate(&(s->stream), flush); - s->out -= s->stream.avail_out; - - /* Ignore the second of two consecutive flushes: */ - if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; - - /* deflate has finished flushing only when it hasn't used up - * all the available space in the output buffer: - */ - done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); - - if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; - } - return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; -} - -int ZEXPORT gzflush (file, flush) - gzFile file; - int flush; -{ - gz_stream *s = (gz_stream*)file; - int err = do_flush (file, flush); - - if (err) return err; - fflush(s->file); - return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; -} -#endif /* NO_GZCOMPRESS */ - -/* =========================================================================== - Sets the starting position for the next gzread or gzwrite on the given - compressed file. The offset represents a number of bytes in the - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error. - SEEK_END is not implemented, returns error. - In this version of the library, gzseek can be extremely slow. -*/ -z_off_t ZEXPORT gzseek (file, offset, whence) - gzFile file; - z_off_t offset; - int whence; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || whence == SEEK_END || - s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { - return -1L; - } - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - return -1L; -#else - if (whence == SEEK_SET) { - offset -= s->in; - } - if (offset < 0) return -1L; - - /* At this point, offset is the number of zero bytes to write. */ - if (s->inbuf == Z_NULL) { - s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ - if (s->inbuf == Z_NULL) return -1L; - zmemzero(s->inbuf, Z_BUFSIZE); - } - while (offset > 0) { - uInt size = Z_BUFSIZE; - if (offset < Z_BUFSIZE) size = (uInt)offset; - - size = gzwrite(file, s->inbuf, size); - if (size == 0) return -1L; - - offset -= size; - } - return s->in; -#endif - } - /* Rest of function is for reading only */ - - /* compute absolute position */ - if (whence == SEEK_CUR) { - offset += s->out; - } - if (offset < 0) return -1L; - - if (s->transparent) { - /* map to fseek */ - s->back = EOF; - s->stream.avail_in = 0; - s->stream.next_in = s->inbuf; - if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; - - s->in = s->out = offset; - return offset; - } - - /* For a negative seek, rewind and use positive seek */ - if (offset >= s->out) { - offset -= s->out; - } else if (gzrewind(file) < 0) { - return -1L; - } - /* offset is now the number of bytes to skip. */ - - if (offset != 0 && s->outbuf == Z_NULL) { - s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); - if (s->outbuf == Z_NULL) return -1L; - } - if (offset && s->back != EOF) { - s->back = EOF; - s->out++; - offset--; - if (s->last) s->z_err = Z_STREAM_END; - } - while (offset > 0) { - int size = Z_BUFSIZE; - if (offset < Z_BUFSIZE) size = (int)offset; - - size = gzread(file, s->outbuf, (uInt)size); - if (size <= 0) return -1L; - offset -= size; - } - return s->out; -} - -/* =========================================================================== - Rewinds input file. -*/ -int ZEXPORT gzrewind (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'r') return -1; - - s->z_err = Z_OK; - s->z_eof = 0; - s->back = EOF; - s->stream.avail_in = 0; - s->stream.next_in = s->inbuf; - s->crc = crc32(0L, Z_NULL, 0); - if (!s->transparent) (void)inflateReset(&s->stream); - s->in = 0; - s->out = 0; - return fseek(s->file, s->start, SEEK_SET); -} - -/* =========================================================================== - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. -*/ -z_off_t ZEXPORT gztell (file) - gzFile file; -{ - return gzseek(file, 0L, SEEK_CUR); -} - -/* =========================================================================== - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. -*/ -int ZEXPORT gzeof (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - /* With concatenated compressed files that can have embedded - * crc trailers, z_eof is no longer the only/best indicator of EOF - * on a gz_stream. Handle end-of-stream error explicitly here. - */ - if (s == NULL || s->mode != 'r') return 0; - if (s->z_eof) return 1; - return s->z_err == Z_STREAM_END; -} - -/* =========================================================================== - Returns 1 if reading and doing so transparently, otherwise zero. -*/ -int ZEXPORT gzdirect (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'r') return 0; - return s->transparent; -} - -/* =========================================================================== - Outputs a long in LSB order to the given file -*/ -local void putLong (file, x) - FILE *file; - uLong x; -{ - int n; - for (n = 0; n < 4; n++) { - fputc((int)(x & 0xff), file); - x >>= 8; - } -} - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets z_err in case - of error. -*/ -local uLong getLong (s) - gz_stream *s; -{ - uLong x = (uLong)get_byte(s); - int c; - - x += ((uLong)get_byte(s))<<8; - x += ((uLong)get_byte(s))<<16; - c = get_byte(s); - if (c == EOF) s->z_err = Z_DATA_ERROR; - x += ((uLong)c)<<24; - return x; -} - -/* =========================================================================== - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. -*/ -int ZEXPORT gzclose (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL) return Z_STREAM_ERROR; - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - return Z_STREAM_ERROR; -#else - if (do_flush (file, Z_FINISH) != Z_OK) - return destroy((gz_stream*)file); - - putLong (s->file, s->crc); - putLong (s->file, (uLong)(s->in & 0xffffffff)); -#endif - } - return destroy((gz_stream*)file); -} - -#ifdef STDC -# define zstrerror(errnum) strerror(errnum) -#else -# define zstrerror(errnum) "" -#endif - -/* =========================================================================== - Returns the error message for the last error which occurred on the - given compressed file. errnum is set to zlib error number. If an - error occurred in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. -*/ -const char * ZEXPORT gzerror (file, errnum) - gzFile file; - int *errnum; -{ - char *m; - gz_stream *s = (gz_stream*)file; - - if (s == NULL) { - *errnum = Z_STREAM_ERROR; - return (const char*)ERR_MSG(Z_STREAM_ERROR); - } - *errnum = s->z_err; - if (*errnum == Z_OK) return (const char*)""; - - m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); - - if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); - - TRYFREE(s->msg); - s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); - if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); - strcpy(s->msg, s->path); - strcat(s->msg, ": "); - strcat(s->msg, m); - return (const char*)s->msg; -} - -/* =========================================================================== - Clear the error and end-of-file flags, and do the same for the real file. -*/ -void ZEXPORT gzclearerr (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL) return; - if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; - s->z_eof = 0; - clearerr(s->file); -} +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id$ */ + +#include + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_BEST_SPEED; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[46]; /* allow for up to 128-bit integers */ + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + start++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= + (uInt)fread(next_out, 1, s->stream.avail_out, s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + if (len == s->stream.avail_out && + (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) + return -1; + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Returns 1 if reading and doing so transparently, otherwise zero. +*/ +int ZEXPORT gzdirect (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return 0; + return s->transparent; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + if (do_flush (file, Z_FINISH) != Z_OK) + return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +#ifdef STDC +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +/* =========================================================================== + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/pcsx2/3rdparty/zlib/infback.c b/pcsx2/3rdparty/zlib/infback.c index 1e03e1bab0..455dbc9ee8 100644 --- a/pcsx2/3rdparty/zlib/infback.c +++ b/pcsx2/3rdparty/zlib/infback.c @@ -1,623 +1,623 @@ -/* infback.c -- inflate using a call-back interface - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - This code is largely copied from inflate.c. Normally either infback.o or - inflate.o would be linked into an application--not both. The interface - with inffast.c is retained so that optimized assembler-coded versions of - inflate_fast() can be used with either inflate.c or infback.c. - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -/* function prototypes */ -local void fixedtables OF((struct inflate_state FAR *state)); - -/* - strm provides memory allocation functions in zalloc and zfree, or - Z_NULL to use the library memory allocation functions. - - windowBits is in the range 8..15, and window is a user-supplied - window and output buffer that is 2**windowBits bytes. - */ -int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) -z_streamp strm; -int windowBits; -unsigned char FAR *window; -const char *version; -int stream_size; -{ - struct inflate_state FAR *state; - - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != (int)(sizeof(z_stream))) - return Z_VERSION_ERROR; - if (strm == Z_NULL || window == Z_NULL || - windowBits < 8 || windowBits > 15) - return Z_STREAM_ERROR; - strm->msg = Z_NULL; /* in case we return an error */ - if (strm->zalloc == (alloc_func)0) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; - state = (struct inflate_state FAR *)ZALLOC(strm, 1, - sizeof(struct inflate_state)); - if (state == Z_NULL) return Z_MEM_ERROR; - Tracev((stderr, "inflate: allocated\n")); - strm->state = (struct internal_state FAR *)state; - state->dmax = 32768U; - state->wbits = windowBits; - state->wsize = 1U << windowBits; - state->window = window; - state->write = 0; - state->whave = 0; - return Z_OK; -} - -/* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ -#ifdef BUILDFIXED - static int virgin = 1; - static code *lenfix, *distfix; - static code fixed[544]; - - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - unsigned sym, bits; - static code *next; - - /* literal/length table */ - sym = 0; - while (sym < 144) state->lens[sym++] = 8; - while (sym < 256) state->lens[sym++] = 9; - while (sym < 280) state->lens[sym++] = 7; - while (sym < 288) state->lens[sym++] = 8; - next = fixed; - lenfix = next; - bits = 9; - inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); - - /* distance table */ - sym = 0; - while (sym < 32) state->lens[sym++] = 5; - distfix = next; - bits = 5; - inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); - - /* do this just once */ - virgin = 0; - } -#else /* !BUILDFIXED */ -# include "inffixed.h" -#endif /* BUILDFIXED */ - state->lencode = lenfix; - state->lenbits = 9; - state->distcode = distfix; - state->distbits = 5; -} - -/* Macros for inflateBack(): */ - -/* Load returned state from inflate_fast() */ -#define LOAD() \ - do { \ - put = strm->next_out; \ - left = strm->avail_out; \ - next = strm->next_in; \ - have = strm->avail_in; \ - hold = state->hold; \ - bits = state->bits; \ - } while (0) - -/* Set state from registers for inflate_fast() */ -#define RESTORE() \ - do { \ - strm->next_out = put; \ - strm->avail_out = left; \ - strm->next_in = next; \ - strm->avail_in = have; \ - state->hold = hold; \ - state->bits = bits; \ - } while (0) - -/* Clear the input bit accumulator */ -#define INITBITS() \ - do { \ - hold = 0; \ - bits = 0; \ - } while (0) - -/* Assure that some input is available. If input is requested, but denied, - then return a Z_BUF_ERROR from inflateBack(). */ -#define PULL() \ - do { \ - if (have == 0) { \ - have = in(in_desc, &next); \ - if (have == 0) { \ - next = Z_NULL; \ - ret = Z_BUF_ERROR; \ - goto inf_leave; \ - } \ - } \ - } while (0) - -/* Get a byte of input into the bit accumulator, or return from inflateBack() - with an error if there is no input available. */ -#define PULLBYTE() \ - do { \ - PULL(); \ - have--; \ - hold += (unsigned long)(*next++) << bits; \ - bits += 8; \ - } while (0) - -/* Assure that there are at least n bits in the bit accumulator. If there is - not enough available input to do that, then return from inflateBack() with - an error. */ -#define NEEDBITS(n) \ - do { \ - while (bits < (unsigned)(n)) \ - PULLBYTE(); \ - } while (0) - -/* Return the low n bits of the bit accumulator (n < 16) */ -#define BITS(n) \ - ((unsigned)hold & ((1U << (n)) - 1)) - -/* Remove n bits from the bit accumulator */ -#define DROPBITS(n) \ - do { \ - hold >>= (n); \ - bits -= (unsigned)(n); \ - } while (0) - -/* Remove zero to seven bits as needed to go to a byte boundary */ -#define BYTEBITS() \ - do { \ - hold >>= bits & 7; \ - bits -= bits & 7; \ - } while (0) - -/* Assure that some output space is available, by writing out the window - if it's full. If the write fails, return from inflateBack() with a - Z_BUF_ERROR. */ -#define ROOM() \ - do { \ - if (left == 0) { \ - put = state->window; \ - left = state->wsize; \ - state->whave = left; \ - if (out(out_desc, put, left)) { \ - ret = Z_BUF_ERROR; \ - goto inf_leave; \ - } \ - } \ - } while (0) - -/* - strm provides the memory allocation functions and window buffer on input, - and provides information on the unused input on return. For Z_DATA_ERROR - returns, strm will also provide an error message. - - in() and out() are the call-back input and output functions. When - inflateBack() needs more input, it calls in(). When inflateBack() has - filled the window with output, or when it completes with data in the - window, it calls out() to write out the data. The application must not - change the provided input until in() is called again or inflateBack() - returns. The application must not change the window/output buffer until - inflateBack() returns. - - in() and out() are called with a descriptor parameter provided in the - inflateBack() call. This parameter can be a structure that provides the - information required to do the read or write, as well as accumulated - information on the input and output such as totals and check values. - - in() should return zero on failure. out() should return non-zero on - failure. If either in() or out() fails, than inflateBack() returns a - Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it - was in() or out() that caused in the error. Otherwise, inflateBack() - returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format - error, or Z_MEM_ERROR if it could not allocate memory for the state. - inflateBack() can also return Z_STREAM_ERROR if the input parameters - are not correct, i.e. strm is Z_NULL or the state was not initialized. - */ -int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) -z_streamp strm; -in_func in; -void FAR *in_desc; -out_func out; -void FAR *out_desc; -{ - struct inflate_state FAR *state; - unsigned char FAR *next; /* next input */ - unsigned char FAR *put; /* next output */ - unsigned have, left; /* available input and output */ - unsigned long hold; /* bit buffer */ - unsigned bits; /* bits in bit buffer */ - unsigned copy; /* number of stored or match bytes to copy */ - unsigned char FAR *from; /* where to copy match bytes from */ - code this; /* current decoding table entry */ - code last; /* parent table entry */ - unsigned len; /* length to copy for repeats, bits to drop */ - int ret; /* return code */ - static const unsigned short order[19] = /* permutation of code lengths */ - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - /* Check that the strm exists and that the state was initialized */ - if (strm == Z_NULL || strm->state == Z_NULL) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - - /* Reset the state */ - strm->msg = Z_NULL; - state->mode = TYPE; - state->last = 0; - state->whave = 0; - next = strm->next_in; - have = next != Z_NULL ? strm->avail_in : 0; - hold = 0; - bits = 0; - put = state->window; - left = state->wsize; - - /* Inflate until end of block marked as last */ - for (;;) - switch (state->mode) { - case TYPE: - /* determine and dispatch block type */ - if (state->last) { - BYTEBITS(); - state->mode = DONE; - break; - } - NEEDBITS(3); - state->last = BITS(1); - DROPBITS(1); - switch (BITS(2)) { - case 0: /* stored block */ - Tracev((stderr, "inflate: stored block%s\n", - state->last ? " (last)" : "")); - state->mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - Tracev((stderr, "inflate: fixed codes block%s\n", - state->last ? " (last)" : "")); - state->mode = LEN; /* decode codes */ - break; - case 2: /* dynamic block */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - state->last ? " (last)" : "")); - state->mode = TABLE; - break; - case 3: - strm->msg = (char *)"invalid block type"; - state->mode = BAD; - } - DROPBITS(2); - break; - - case STORED: - /* get and verify stored block length */ - BYTEBITS(); /* go to byte boundary */ - NEEDBITS(32); - if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - strm->msg = (char *)"invalid stored block lengths"; - state->mode = BAD; - break; - } - state->length = (unsigned)hold & 0xffff; - Tracev((stderr, "inflate: stored length %u\n", - state->length)); - INITBITS(); - - /* copy stored block from input to output */ - while (state->length != 0) { - copy = state->length; - PULL(); - ROOM(); - if (copy > have) copy = have; - if (copy > left) copy = left; - zmemcpy(put, next, copy); - have -= copy; - next += copy; - left -= copy; - put += copy; - state->length -= copy; - } - Tracev((stderr, "inflate: stored end\n")); - state->mode = TYPE; - break; - - case TABLE: - /* get dynamic table entries descriptor */ - NEEDBITS(14); - state->nlen = BITS(5) + 257; - DROPBITS(5); - state->ndist = BITS(5) + 1; - DROPBITS(5); - state->ncode = BITS(4) + 4; - DROPBITS(4); -#ifndef PKZIP_BUG_WORKAROUND - if (state->nlen > 286 || state->ndist > 30) { - strm->msg = (char *)"too many length or distance symbols"; - state->mode = BAD; - break; - } -#endif - Tracev((stderr, "inflate: table sizes ok\n")); - - /* get code length code lengths (not a typo) */ - state->have = 0; - while (state->have < state->ncode) { - NEEDBITS(3); - state->lens[order[state->have++]] = (unsigned short)BITS(3); - DROPBITS(3); - } - while (state->have < 19) - state->lens[order[state->have++]] = 0; - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 7; - ret = inflate_table(CODES, state->lens, 19, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid code lengths set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: code lengths ok\n")); - - /* get length and distance code code lengths */ - state->have = 0; - while (state->have < state->nlen + state->ndist) { - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.val < 16) { - NEEDBITS(this.bits); - DROPBITS(this.bits); - state->lens[state->have++] = this.val; - } - else { - if (this.val == 16) { - NEEDBITS(this.bits + 2); - DROPBITS(this.bits); - if (state->have == 0) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - len = (unsigned)(state->lens[state->have - 1]); - copy = 3 + BITS(2); - DROPBITS(2); - } - else if (this.val == 17) { - NEEDBITS(this.bits + 3); - DROPBITS(this.bits); - len = 0; - copy = 3 + BITS(3); - DROPBITS(3); - } - else { - NEEDBITS(this.bits + 7); - DROPBITS(this.bits); - len = 0; - copy = 11 + BITS(7); - DROPBITS(7); - } - if (state->have + copy > state->nlen + state->ndist) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - while (copy--) - state->lens[state->have++] = (unsigned short)len; - } - } - - /* handle error breaks in while */ - if (state->mode == BAD) break; - - /* build code tables */ - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 9; - ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid literal/lengths set"; - state->mode = BAD; - break; - } - state->distcode = (code const FAR *)(state->next); - state->distbits = 6; - ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, - &(state->next), &(state->distbits), state->work); - if (ret) { - strm->msg = (char *)"invalid distances set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: codes ok\n")); - state->mode = LEN; - - case LEN: - /* use inflate_fast() if we have enough input and output */ - if (have >= 6 && left >= 258) { - RESTORE(); - if (state->whave < state->wsize) - state->whave = state->wsize - left; - inflate_fast(strm, state->wsize); - LOAD(); - break; - } - - /* get a literal, length, or end-of-block code */ - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.op && (this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->lencode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - state->length = (unsigned)this.val; - - /* process literal */ - if (this.op == 0) { - Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", this.val)); - ROOM(); - *put++ = (unsigned char)(state->length); - left--; - state->mode = LEN; - break; - } - - /* process end of block */ - if (this.op & 32) { - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - - /* invalid code */ - if (this.op & 64) { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - - /* length code -- get extra bits, if any */ - state->extra = (unsigned)(this.op) & 15; - if (state->extra != 0) { - NEEDBITS(state->extra); - state->length += BITS(state->extra); - DROPBITS(state->extra); - } - Tracevv((stderr, "inflate: length %u\n", state->length)); - - /* get distance code */ - for (;;) { - this = state->distcode[BITS(state->distbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if ((this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->distcode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - if (this.op & 64) { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - state->offset = (unsigned)this.val; - - /* get distance extra bits, if any */ - state->extra = (unsigned)(this.op) & 15; - if (state->extra != 0) { - NEEDBITS(state->extra); - state->offset += BITS(state->extra); - DROPBITS(state->extra); - } - if (state->offset > state->wsize - (state->whave < state->wsize ? - left : 0)) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - Tracevv((stderr, "inflate: distance %u\n", state->offset)); - - /* copy match from window to output */ - do { - ROOM(); - copy = state->wsize - state->offset; - if (copy < left) { - from = put + copy; - copy = left - copy; - } - else { - from = put - state->offset; - copy = left; - } - if (copy > state->length) copy = state->length; - state->length -= copy; - left -= copy; - do { - *put++ = *from++; - } while (--copy); - } while (state->length != 0); - break; - - case DONE: - /* inflate stream terminated properly -- write leftover output */ - ret = Z_STREAM_END; - if (left < state->wsize) { - if (out(out_desc, state->window, state->wsize - left)) - ret = Z_BUF_ERROR; - } - goto inf_leave; - - case BAD: - ret = Z_DATA_ERROR; - goto inf_leave; - - default: /* can't happen, but makes compilers happy */ - ret = Z_STREAM_ERROR; - goto inf_leave; - } - - /* Return unused input */ - inf_leave: - strm->next_in = next; - strm->avail_in = have; - return ret; -} - -int ZEXPORT inflateBackEnd(strm) -z_streamp strm; -{ - if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) - return Z_STREAM_ERROR; - ZFREE(strm, strm->state); - strm->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; -} +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/pcsx2/3rdparty/zlib/inffast.c b/pcsx2/3rdparty/zlib/inffast.c index fa31cad905..bbee92ed1e 100644 --- a/pcsx2/3rdparty/zlib/inffast.c +++ b/pcsx2/3rdparty/zlib/inffast.c @@ -1,318 +1,318 @@ -/* inffast.c -- fast decoding - * Copyright (C) 1995-2004 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -#ifndef ASMINF - -/* Allow machine dependent optimization for post-increment or pre-increment. - Based on testing to date, - Pre-increment preferred for: - - PowerPC G3 (Adler) - - MIPS R5000 (Randers-Pehrson) - Post-increment preferred for: - - none - No measurable difference: - - Pentium III (Anderson) - - M68060 (Nikl) - */ -#ifdef POSTINC -# define OFF 0 -# define PUP(a) *(a)++ -#else -# define OFF 1 -# define PUP(a) *++(a) -#endif - -/* - Decode literal, length, and distance codes and write out the resulting - literal and match bytes until either not enough input or output is - available, an end-of-block is encountered, or a data error is encountered. - When large enough input and output buffers are supplied to inflate(), for - example, a 16K input buffer and a 64K output buffer, more than 95% of the - inflate execution time is spent in this routine. - - Entry assumptions: - - state->mode == LEN - strm->avail_in >= 6 - strm->avail_out >= 258 - start >= strm->avail_out - state->bits < 8 - - On return, state->mode is one of: - - LEN -- ran out of enough output space or enough available input - TYPE -- reached end of block code, inflate() to interpret next block - BAD -- error in block data - - Notes: - - - The maximum input bits used by a length/distance pair is 15 bits for the - length code, 5 bits for the length extra, 15 bits for the distance code, - and 13 bits for the distance extra. This totals 48 bits, or six bytes. - Therefore if strm->avail_in >= 6, then there is enough input to avoid - checking for available input while decoding. - - - The maximum bytes that a single length/distance pair can output is 258 - bytes, which is the maximum length that can be coded. inflate_fast() - requires strm->avail_out >= 258 for each loop to avoid checking for - output space. - */ -void inflate_fast(strm, start) -z_streamp strm; -unsigned start; /* inflate()'s starting value for strm->avail_out */ -{ - struct inflate_state FAR *state; - unsigned char FAR *in; /* local strm->next_in */ - unsigned char FAR *last; /* while in < last, enough input available */ - unsigned char FAR *out; /* local strm->next_out */ - unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ - unsigned char FAR *end; /* while out < end, enough space available */ -#ifdef INFLATE_STRICT - unsigned dmax; /* maximum distance from zlib header */ -#endif - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned write; /* window write index */ - unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ - unsigned long hold; /* local strm->hold */ - unsigned bits; /* local strm->bits */ - code const FAR *lcode; /* local strm->lencode */ - code const FAR *dcode; /* local strm->distcode */ - unsigned lmask; /* mask for first level of length codes */ - unsigned dmask; /* mask for first level of distance codes */ - code this; /* retrieved table entry */ - unsigned op; /* code bits, operation, extra bits, or */ - /* window position, window bytes to copy */ - unsigned len; /* match length, unused bytes */ - unsigned dist; /* match distance */ - unsigned char FAR *from; /* where to copy match from */ - - /* copy state to local variables */ - state = (struct inflate_state FAR *)strm->state; - in = strm->next_in - OFF; - last = in + (strm->avail_in - 5); - out = strm->next_out - OFF; - beg = out - (start - strm->avail_out); - end = out + (strm->avail_out - 257); -#ifdef INFLATE_STRICT - dmax = state->dmax; -#endif - wsize = state->wsize; - whave = state->whave; - write = state->write; - window = state->window; - hold = state->hold; - bits = state->bits; - lcode = state->lencode; - dcode = state->distcode; - lmask = (1U << state->lenbits) - 1; - dmask = (1U << state->distbits) - 1; - - /* decode literals and length/distances until end-of-block or not enough - input data or output space */ - do { - if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - this = lcode[hold & lmask]; - dolen: - op = (unsigned)(this.bits); - hold >>= op; - bits -= op; - op = (unsigned)(this.op); - if (op == 0) { /* literal */ - Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", this.val)); - PUP(out) = (unsigned char)(this.val); - } - else if (op & 16) { /* length base */ - len = (unsigned)(this.val); - op &= 15; /* number of extra bits */ - if (op) { - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - len += (unsigned)hold & ((1U << op) - 1); - hold >>= op; - bits -= op; - } - Tracevv((stderr, "inflate: length %u\n", len)); - if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - this = dcode[hold & dmask]; - dodist: - op = (unsigned)(this.bits); - hold >>= op; - bits -= op; - op = (unsigned)(this.op); - if (op & 16) { /* distance base */ - dist = (unsigned)(this.val); - op &= 15; /* number of extra bits */ - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - } - dist += (unsigned)hold & ((1U << op) - 1); -#ifdef INFLATE_STRICT - if (dist > dmax) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#endif - hold >>= op; - bits -= op; - Tracevv((stderr, "inflate: distance %u\n", dist)); - op = (unsigned)(out - beg); /* max distance in output */ - if (dist > op) { /* see if copy from window */ - op = dist - op; /* distance back in window */ - if (op > whave) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - from = window - OFF; - if (write == 0) { /* very common case */ - from += wsize - op; - if (op < len) { /* some from window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - else if (write < op) { /* wrap around window */ - from += wsize + write - op; - op -= write; - if (op < len) { /* some from end of window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = window - OFF; - if (write < len) { /* some from start of window */ - op = write; - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - } - else { /* contiguous in window */ - from += write - op; - if (op < len) { /* some from window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - while (len > 2) { - PUP(out) = PUP(from); - PUP(out) = PUP(from); - PUP(out) = PUP(from); - len -= 3; - } - if (len) { - PUP(out) = PUP(from); - if (len > 1) - PUP(out) = PUP(from); - } - } - else { - from = out - dist; /* copy direct from output */ - do { /* minimum length is three */ - PUP(out) = PUP(from); - PUP(out) = PUP(from); - PUP(out) = PUP(from); - len -= 3; - } while (len > 2); - if (len) { - PUP(out) = PUP(from); - if (len > 1) - PUP(out) = PUP(from); - } - } - } - else if ((op & 64) == 0) { /* 2nd level distance code */ - this = dcode[this.val + (hold & ((1U << op) - 1))]; - goto dodist; - } - else { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - } - else if ((op & 64) == 0) { /* 2nd level length code */ - this = lcode[this.val + (hold & ((1U << op) - 1))]; - goto dolen; - } - else if (op & 32) { /* end-of-block */ - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - else { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - } while (in < last && out < end); - - /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ - len = bits >> 3; - in -= len; - bits -= len << 3; - hold &= (1U << bits) - 1; - - /* update state and return */ - strm->next_in = in + OFF; - strm->next_out = out + OFF; - strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); - strm->avail_out = (unsigned)(out < end ? - 257 + (end - out) : 257 - (out - end)); - state->hold = hold; - state->bits = bits; - return; -} - -/* - inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - - Using bit fields for code structure - - Different op definition to avoid & for extra bits (do & for table bits) - - Three separate decoding do-loops for direct, window, and write == 0 - - Special case for distance > 1 copies to do overlapped load and store copy - - Explicit branch predictions (based on measured branch probabilities) - - Deferring match copy and interspersed it with decoding subsequent codes - - Swapping literal/length else - - Swapping window/direct else - - Larger unrolled copy loops (three is about right) - - Moving len -= 3 statement into middle of loop - */ - -#endif /* !ASMINF */ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - M68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/pcsx2/3rdparty/zlib/inffast.h b/pcsx2/3rdparty/zlib/inffast.h index 614fa7877d..1e88d2d97b 100644 --- a/pcsx2/3rdparty/zlib/inffast.h +++ b/pcsx2/3rdparty/zlib/inffast.h @@ -1,11 +1,11 @@ -/* inffast.h -- header to use inffast.c - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -void inflate_fast OF((z_streamp strm, unsigned start)); +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/pcsx2/3rdparty/zlib/inffixed.h b/pcsx2/3rdparty/zlib/inffixed.h index 423d5c5b50..75ed4b5978 100644 --- a/pcsx2/3rdparty/zlib/inffixed.h +++ b/pcsx2/3rdparty/zlib/inffixed.h @@ -1,94 +1,94 @@ - /* inffixed.h -- table for decoding fixed codes - * Generated automatically by makefixed(). - */ - - /* WARNING: this file should *not* be used by applications. It - is part of the implementation of the compression library and - is subject to change. Applications should only use zlib.h. - */ - - static const code lenfix[512] = { - {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, - {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, - {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, - {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, - {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, - {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, - {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, - {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, - {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, - {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, - {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, - {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, - {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, - {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, - {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, - {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, - {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, - {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, - {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, - {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, - {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, - {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, - {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, - {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, - {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, - {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, - {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, - {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, - {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, - {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, - {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, - {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, - {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, - {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, - {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, - {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, - {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, - {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, - {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, - {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, - {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, - {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, - {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, - {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, - {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, - {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, - {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, - {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, - {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, - {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, - {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, - {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, - {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, - {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, - {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, - {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, - {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, - {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, - {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, - {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, - {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, - {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, - {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, - {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, - {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, - {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, - {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, - {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, - {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, - {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, - {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, - {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, - {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, - {0,9,255} - }; - - static const code distfix[32] = { - {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, - {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, - {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, - {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, - {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, - {22,5,193},{64,5,0} - }; + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/pcsx2/3rdparty/zlib/inflate.c b/pcsx2/3rdparty/zlib/inflate.c index 33ea902928..792fdee8e9 100644 --- a/pcsx2/3rdparty/zlib/inflate.c +++ b/pcsx2/3rdparty/zlib/inflate.c @@ -1,1368 +1,1368 @@ -/* inflate.c -- zlib decompression - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * Change history: - * - * 1.2.beta0 24 Nov 2002 - * - First version -- complete rewrite of inflate to simplify code, avoid - * creation of window when not needed, minimize use of window when it is - * needed, make inffast.c even faster, implement gzip decoding, and to - * improve code readability and style over the previous zlib inflate code - * - * 1.2.beta1 25 Nov 2002 - * - Use pointers for available input and output checking in inffast.c - * - Remove input and output counters in inffast.c - * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 - * - Remove unnecessary second byte pull from length extra in inffast.c - * - Unroll direct copy to three copies per loop in inffast.c - * - * 1.2.beta2 4 Dec 2002 - * - Change external routine names to reduce potential conflicts - * - Correct filename to inffixed.h for fixed tables in inflate.c - * - Make hbuf[] unsigned char to match parameter type in inflate.c - * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) - * to avoid negation problem on Alphas (64 bit) in inflate.c - * - * 1.2.beta3 22 Dec 2002 - * - Add comments on state->bits assertion in inffast.c - * - Add comments on op field in inftrees.h - * - Fix bug in reuse of allocated window after inflateReset() - * - Remove bit fields--back to byte structure for speed - * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths - * - Change post-increments to pre-increments in inflate_fast(), PPC biased? - * - Add compile time option, POSTINC, to use post-increments instead (Intel?) - * - Make MATCH copy in inflate() much faster for when inflate_fast() not used - * - Use local copies of stream next and avail values, as well as local bit - * buffer and bit count in inflate()--for speed when inflate_fast() not used - * - * 1.2.beta4 1 Jan 2003 - * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings - * - Move a comment on output buffer sizes from inffast.c to inflate.c - * - Add comments in inffast.c to introduce the inflate_fast() routine - * - Rearrange window copies in inflate_fast() for speed and simplification - * - Unroll last copy for window match in inflate_fast() - * - Use local copies of window variables in inflate_fast() for speed - * - Pull out common write == 0 case for speed in inflate_fast() - * - Make op and len in inflate_fast() unsigned for consistency - * - Add FAR to lcode and dcode declarations in inflate_fast() - * - Simplified bad distance check in inflate_fast() - * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new - * source file infback.c to provide a call-back interface to inflate for - * programs like gzip and unzip -- uses window as output buffer to avoid - * window copying - * - * 1.2.beta5 1 Jan 2003 - * - Improved inflateBack() interface to allow the caller to provide initial - * input in strm. - * - Fixed stored blocks bug in inflateBack() - * - * 1.2.beta6 4 Jan 2003 - * - Added comments in inffast.c on effectiveness of POSTINC - * - Typecasting all around to reduce compiler warnings - * - Changed loops from while (1) or do {} while (1) to for (;;), again to - * make compilers happy - * - Changed type of window in inflateBackInit() to unsigned char * - * - * 1.2.beta7 27 Jan 2003 - * - Changed many types to unsigned or unsigned short to avoid warnings - * - Added inflateCopy() function - * - * 1.2.0 9 Mar 2003 - * - Changed inflateBack() interface to provide separate opaque descriptors - * for the in() and out() functions - * - Changed inflateBack() argument and in_func typedef to swap the length - * and buffer address return values for the input function - * - Check next_in and next_out for Z_NULL on entry to inflate() - * - * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -#ifdef MAKEFIXED -# ifndef BUILDFIXED -# define BUILDFIXED -# endif -#endif - -/* function prototypes */ -local void fixedtables OF((struct inflate_state FAR *state)); -local int updatewindow OF((z_streamp strm, unsigned out)); -#ifdef BUILDFIXED - void makefixed OF((void)); -#endif -local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, - unsigned len)); - -int ZEXPORT inflateReset(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - strm->total_in = strm->total_out = state->total = 0; - strm->msg = Z_NULL; - strm->adler = 1; /* to support ill-conceived Java test suite */ - state->mode = HEAD; - state->last = 0; - state->havedict = 0; - state->dmax = 32768U; - state->head = Z_NULL; - state->wsize = 0; - state->whave = 0; - state->write = 0; - state->hold = 0; - state->bits = 0; - state->lencode = state->distcode = state->next = state->codes; - Tracev((stderr, "inflate: reset\n")); - return Z_OK; -} - -int ZEXPORT inflatePrime(strm, bits, value) -z_streamp strm; -int bits; -int value; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; - value &= (1L << bits) - 1; - state->hold += value << state->bits; - state->bits += bits; - return Z_OK; -} - -int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) -z_streamp strm; -int windowBits; -const char *version; -int stream_size; -{ - struct inflate_state FAR *state; - - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != (int)(sizeof(z_stream))) - return Z_VERSION_ERROR; - if (strm == Z_NULL) return Z_STREAM_ERROR; - strm->msg = Z_NULL; /* in case we return an error */ - if (strm->zalloc == (alloc_func)0) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; - state = (struct inflate_state FAR *) - ZALLOC(strm, 1, sizeof(struct inflate_state)); - if (state == Z_NULL) return Z_MEM_ERROR; - Tracev((stderr, "inflate: allocated\n")); - strm->state = (struct internal_state FAR *)state; - if (windowBits < 0) { - state->wrap = 0; - windowBits = -windowBits; - } - else { - state->wrap = (windowBits >> 4) + 1; -#ifdef GUNZIP - if (windowBits < 48) windowBits &= 15; -#endif - } - if (windowBits < 8 || windowBits > 15) { - ZFREE(strm, state); - strm->state = Z_NULL; - return Z_STREAM_ERROR; - } - state->wbits = (unsigned)windowBits; - state->window = Z_NULL; - return inflateReset(strm); -} - -int ZEXPORT inflateInit_(strm, version, stream_size) -z_streamp strm; -const char *version; -int stream_size; -{ - return inflateInit2_(strm, DEF_WBITS, version, stream_size); -} - -/* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ -#ifdef BUILDFIXED - static int virgin = 1; - static code *lenfix, *distfix; - static code fixed[544]; - - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - unsigned sym, bits; - static code *next; - - /* literal/length table */ - sym = 0; - while (sym < 144) state->lens[sym++] = 8; - while (sym < 256) state->lens[sym++] = 9; - while (sym < 280) state->lens[sym++] = 7; - while (sym < 288) state->lens[sym++] = 8; - next = fixed; - lenfix = next; - bits = 9; - inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); - - /* distance table */ - sym = 0; - while (sym < 32) state->lens[sym++] = 5; - distfix = next; - bits = 5; - inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); - - /* do this just once */ - virgin = 0; - } -#else /* !BUILDFIXED */ -# include "inffixed.h" -#endif /* BUILDFIXED */ - state->lencode = lenfix; - state->lenbits = 9; - state->distcode = distfix; - state->distbits = 5; -} - -#ifdef MAKEFIXED -#include - -/* - Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also - defines BUILDFIXED, so the tables are built on the fly. makefixed() writes - those tables to stdout, which would be piped to inffixed.h. A small program - can simply call makefixed to do this: - - void makefixed(void); - - int main(void) - { - makefixed(); - return 0; - } - - Then that can be linked with zlib built with MAKEFIXED defined and run: - - a.out > inffixed.h - */ -void makefixed() -{ - unsigned low, size; - struct inflate_state state; - - fixedtables(&state); - puts(" /* inffixed.h -- table for decoding fixed codes"); - puts(" * Generated automatically by makefixed()."); - puts(" */"); - puts(""); - puts(" /* WARNING: this file should *not* be used by applications."); - puts(" It is part of the implementation of this library and is"); - puts(" subject to change. Applications should only use zlib.h."); - puts(" */"); - puts(""); - size = 1U << 9; - printf(" static const code lenfix[%u] = {", size); - low = 0; - for (;;) { - if ((low % 7) == 0) printf("\n "); - printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, - state.lencode[low].val); - if (++low == size) break; - putchar(','); - } - puts("\n };"); - size = 1U << 5; - printf("\n static const code distfix[%u] = {", size); - low = 0; - for (;;) { - if ((low % 6) == 0) printf("\n "); - printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, - state.distcode[low].val); - if (++low == size) break; - putchar(','); - } - puts("\n };"); -} -#endif /* MAKEFIXED */ - -/* - Update the window with the last wsize (normally 32K) bytes written before - returning. If window does not exist yet, create it. This is only called - when a window is already in use, or when output has been written during this - inflate call, but the end of the deflate stream has not been reached yet. - It is also called to create a window for dictionary data when a dictionary - is loaded. - - Providing output buffers larger than 32K to inflate() should provide a speed - advantage, since only the last 32K of output is copied to the sliding window - upon return from inflate(), and since all distances after the first 32K of - output will fall in the output data, making match copies simpler and faster. - The advantage may be dependent on the size of the processor's data caches. - */ -local int updatewindow(strm, out) -z_streamp strm; -unsigned out; -{ - struct inflate_state FAR *state; - unsigned copy, dist; - - state = (struct inflate_state FAR *)strm->state; - - /* if it hasn't been done already, allocate space for the window */ - if (state->window == Z_NULL) { - state->window = (unsigned char FAR *) - ZALLOC(strm, 1U << state->wbits, - sizeof(unsigned char)); - if (state->window == Z_NULL) return 1; - } - - /* if window not in use yet, initialize */ - if (state->wsize == 0) { - state->wsize = 1U << state->wbits; - state->write = 0; - state->whave = 0; - } - - /* copy state->wsize or less output bytes into the circular window */ - copy = out - strm->avail_out; - if (copy >= state->wsize) { - zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); - state->write = 0; - state->whave = state->wsize; - } - else { - dist = state->wsize - state->write; - if (dist > copy) dist = copy; - zmemcpy(state->window + state->write, strm->next_out - copy, dist); - copy -= dist; - if (copy) { - zmemcpy(state->window, strm->next_out - copy, copy); - state->write = copy; - state->whave = state->wsize; - } - else { - state->write += dist; - if (state->write == state->wsize) state->write = 0; - if (state->whave < state->wsize) state->whave += dist; - } - } - return 0; -} - -/* Macros for inflate(): */ - -/* check function to use adler32() for zlib or crc32() for gzip */ -#ifdef GUNZIP -# define UPDATE(check, buf, len) \ - (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) -#else -# define UPDATE(check, buf, len) adler32(check, buf, len) -#endif - -/* check macros for header crc */ -#ifdef GUNZIP -# define CRC2(check, word) \ - do { \ - hbuf[0] = (unsigned char)(word); \ - hbuf[1] = (unsigned char)((word) >> 8); \ - check = crc32(check, hbuf, 2); \ - } while (0) - -# define CRC4(check, word) \ - do { \ - hbuf[0] = (unsigned char)(word); \ - hbuf[1] = (unsigned char)((word) >> 8); \ - hbuf[2] = (unsigned char)((word) >> 16); \ - hbuf[3] = (unsigned char)((word) >> 24); \ - check = crc32(check, hbuf, 4); \ - } while (0) -#endif - -/* Load registers with state in inflate() for speed */ -#define LOAD() \ - do { \ - put = strm->next_out; \ - left = strm->avail_out; \ - next = strm->next_in; \ - have = strm->avail_in; \ - hold = state->hold; \ - bits = state->bits; \ - } while (0) - -/* Restore state from registers in inflate() */ -#define RESTORE() \ - do { \ - strm->next_out = put; \ - strm->avail_out = left; \ - strm->next_in = next; \ - strm->avail_in = have; \ - state->hold = hold; \ - state->bits = bits; \ - } while (0) - -/* Clear the input bit accumulator */ -#define INITBITS() \ - do { \ - hold = 0; \ - bits = 0; \ - } while (0) - -/* Get a byte of input into the bit accumulator, or return from inflate() - if there is no input available. */ -#define PULLBYTE() \ - do { \ - if (have == 0) goto inf_leave; \ - have--; \ - hold += (unsigned long)(*next++) << bits; \ - bits += 8; \ - } while (0) - -/* Assure that there are at least n bits in the bit accumulator. If there is - not enough available input to do that, then return from inflate(). */ -#define NEEDBITS(n) \ - do { \ - while (bits < (unsigned)(n)) \ - PULLBYTE(); \ - } while (0) - -/* Return the low n bits of the bit accumulator (n < 16) */ -#define BITS(n) \ - ((unsigned)hold & ((1U << (n)) - 1)) - -/* Remove n bits from the bit accumulator */ -#define DROPBITS(n) \ - do { \ - hold >>= (n); \ - bits -= (unsigned)(n); \ - } while (0) - -/* Remove zero to seven bits as needed to go to a byte boundary */ -#define BYTEBITS() \ - do { \ - hold >>= bits & 7; \ - bits -= bits & 7; \ - } while (0) - -/* Reverse the bytes in a 32-bit value */ -#define REVERSE(q) \ - ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ - (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) - -/* - inflate() uses a state machine to process as much input data and generate as - much output data as possible before returning. The state machine is - structured roughly as follows: - - for (;;) switch (state) { - ... - case STATEn: - if (not enough input data or output space to make progress) - return; - ... make progress ... - state = STATEm; - break; - ... - } - - so when inflate() is called again, the same case is attempted again, and - if the appropriate resources are provided, the machine proceeds to the - next state. The NEEDBITS() macro is usually the way the state evaluates - whether it can proceed or should return. NEEDBITS() does the return if - the requested bits are not available. The typical use of the BITS macros - is: - - NEEDBITS(n); - ... do something with BITS(n) ... - DROPBITS(n); - - where NEEDBITS(n) either returns from inflate() if there isn't enough - input left to load n bits into the accumulator, or it continues. BITS(n) - gives the low n bits in the accumulator. When done, DROPBITS(n) drops - the low n bits off the accumulator. INITBITS() clears the accumulator - and sets the number of available bits to zero. BYTEBITS() discards just - enough bits to put the accumulator on a byte boundary. After BYTEBITS() - and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. - - NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return - if there is no input available. The decoding of variable length codes uses - PULLBYTE() directly in order to pull just enough bytes to decode the next - code, and no more. - - Some states loop until they get enough input, making sure that enough - state information is maintained to continue the loop where it left off - if NEEDBITS() returns in the loop. For example, want, need, and keep - would all have to actually be part of the saved state in case NEEDBITS() - returns: - - case STATEw: - while (want < need) { - NEEDBITS(n); - keep[want++] = BITS(n); - DROPBITS(n); - } - state = STATEx; - case STATEx: - - As shown above, if the next state is also the next case, then the break - is omitted. - - A state may also return if there is not enough output space available to - complete that state. Those states are copying stored data, writing a - literal byte, and copying a matching string. - - When returning, a "goto inf_leave" is used to update the total counters, - update the check value, and determine whether any progress has been made - during that inflate() call in order to return the proper return code. - Progress is defined as a change in either strm->avail_in or strm->avail_out. - When there is a window, goto inf_leave will update the window with the last - output written. If a goto inf_leave occurs in the middle of decompression - and there is no window currently, goto inf_leave will create one and copy - output to the window for the next call of inflate(). - - In this implementation, the flush parameter of inflate() only affects the - return code (per zlib.h). inflate() always writes as much as possible to - strm->next_out, given the space available and the provided input--the effect - documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers - the allocation of and copying into a sliding window until necessary, which - provides the effect documented in zlib.h for Z_FINISH when the entire input - stream available. So the only thing the flush parameter actually does is: - when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it - will return Z_BUF_ERROR if it has not reached the end of the stream. - */ - -int ZEXPORT inflate(strm, flush) -z_streamp strm; -int flush; -{ - struct inflate_state FAR *state; - unsigned char FAR *next; /* next input */ - unsigned char FAR *put; /* next output */ - unsigned have, left; /* available input and output */ - unsigned long hold; /* bit buffer */ - unsigned bits; /* bits in bit buffer */ - unsigned in, out; /* save starting available input and output */ - unsigned copy; /* number of stored or match bytes to copy */ - unsigned char FAR *from; /* where to copy match bytes from */ - code this; /* current decoding table entry */ - code last; /* parent table entry */ - unsigned len; /* length to copy for repeats, bits to drop */ - int ret; /* return code */ -#ifdef GUNZIP - unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ -#endif - static const unsigned short order[19] = /* permutation of code lengths */ - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || - (strm->next_in == Z_NULL && strm->avail_in != 0)) - return Z_STREAM_ERROR; - - state = (struct inflate_state FAR *)strm->state; - if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ - LOAD(); - in = have; - out = left; - ret = Z_OK; - for (;;) - switch (state->mode) { - case HEAD: - if (state->wrap == 0) { - state->mode = TYPEDO; - break; - } - NEEDBITS(16); -#ifdef GUNZIP - if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ - state->check = crc32(0L, Z_NULL, 0); - CRC2(state->check, hold); - INITBITS(); - state->mode = FLAGS; - break; - } - state->flags = 0; /* expect zlib header */ - if (state->head != Z_NULL) - state->head->done = -1; - if (!(state->wrap & 1) || /* check if zlib header allowed */ -#else - if ( -#endif - ((BITS(8) << 8) + (hold >> 8)) % 31) { - strm->msg = (char *)"incorrect header check"; - state->mode = BAD; - break; - } - if (BITS(4) != Z_DEFLATED) { - strm->msg = (char *)"unknown compression method"; - state->mode = BAD; - break; - } - DROPBITS(4); - len = BITS(4) + 8; - if (len > state->wbits) { - strm->msg = (char *)"invalid window size"; - state->mode = BAD; - break; - } - state->dmax = 1U << len; - Tracev((stderr, "inflate: zlib header ok\n")); - strm->adler = state->check = adler32(0L, Z_NULL, 0); - state->mode = hold & 0x200 ? DICTID : TYPE; - INITBITS(); - break; -#ifdef GUNZIP - case FLAGS: - NEEDBITS(16); - state->flags = (int)(hold); - if ((state->flags & 0xff) != Z_DEFLATED) { - strm->msg = (char *)"unknown compression method"; - state->mode = BAD; - break; - } - if (state->flags & 0xe000) { - strm->msg = (char *)"unknown header flags set"; - state->mode = BAD; - break; - } - if (state->head != Z_NULL) - state->head->text = (int)((hold >> 8) & 1); - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - state->mode = TIME; - case TIME: - NEEDBITS(32); - if (state->head != Z_NULL) - state->head->time = hold; - if (state->flags & 0x0200) CRC4(state->check, hold); - INITBITS(); - state->mode = OS; - case OS: - NEEDBITS(16); - if (state->head != Z_NULL) { - state->head->xflags = (int)(hold & 0xff); - state->head->os = (int)(hold >> 8); - } - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - state->mode = EXLEN; - case EXLEN: - if (state->flags & 0x0400) { - NEEDBITS(16); - state->length = (unsigned)(hold); - if (state->head != Z_NULL) - state->head->extra_len = (unsigned)hold; - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - } - else if (state->head != Z_NULL) - state->head->extra = Z_NULL; - state->mode = EXTRA; - case EXTRA: - if (state->flags & 0x0400) { - copy = state->length; - if (copy > have) copy = have; - if (copy) { - if (state->head != Z_NULL && - state->head->extra != Z_NULL) { - len = state->head->extra_len - state->length; - zmemcpy(state->head->extra + len, next, - len + copy > state->head->extra_max ? - state->head->extra_max - len : copy); - } - if (state->flags & 0x0200) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - state->length -= copy; - } - if (state->length) goto inf_leave; - } - state->length = 0; - state->mode = NAME; - case NAME: - if (state->flags & 0x0800) { - if (have == 0) goto inf_leave; - copy = 0; - do { - len = (unsigned)(next[copy++]); - if (state->head != Z_NULL && - state->head->name != Z_NULL && - state->length < state->head->name_max) - state->head->name[state->length++] = len; - } while (len && copy < have); - if (state->flags & 0x0200) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - if (len) goto inf_leave; - } - else if (state->head != Z_NULL) - state->head->name = Z_NULL; - state->length = 0; - state->mode = COMMENT; - case COMMENT: - if (state->flags & 0x1000) { - if (have == 0) goto inf_leave; - copy = 0; - do { - len = (unsigned)(next[copy++]); - if (state->head != Z_NULL && - state->head->comment != Z_NULL && - state->length < state->head->comm_max) - state->head->comment[state->length++] = len; - } while (len && copy < have); - if (state->flags & 0x0200) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - if (len) goto inf_leave; - } - else if (state->head != Z_NULL) - state->head->comment = Z_NULL; - state->mode = HCRC; - case HCRC: - if (state->flags & 0x0200) { - NEEDBITS(16); - if (hold != (state->check & 0xffff)) { - strm->msg = (char *)"header crc mismatch"; - state->mode = BAD; - break; - } - INITBITS(); - } - if (state->head != Z_NULL) { - state->head->hcrc = (int)((state->flags >> 9) & 1); - state->head->done = 1; - } - strm->adler = state->check = crc32(0L, Z_NULL, 0); - state->mode = TYPE; - break; -#endif - case DICTID: - NEEDBITS(32); - strm->adler = state->check = REVERSE(hold); - INITBITS(); - state->mode = DICT; - case DICT: - if (state->havedict == 0) { - RESTORE(); - return Z_NEED_DICT; - } - strm->adler = state->check = adler32(0L, Z_NULL, 0); - state->mode = TYPE; - case TYPE: - if (flush == Z_BLOCK) goto inf_leave; - case TYPEDO: - if (state->last) { - BYTEBITS(); - state->mode = CHECK; - break; - } - NEEDBITS(3); - state->last = BITS(1); - DROPBITS(1); - switch (BITS(2)) { - case 0: /* stored block */ - Tracev((stderr, "inflate: stored block%s\n", - state->last ? " (last)" : "")); - state->mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - Tracev((stderr, "inflate: fixed codes block%s\n", - state->last ? " (last)" : "")); - state->mode = LEN; /* decode codes */ - break; - case 2: /* dynamic block */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - state->last ? " (last)" : "")); - state->mode = TABLE; - break; - case 3: - strm->msg = (char *)"invalid block type"; - state->mode = BAD; - } - DROPBITS(2); - break; - case STORED: - BYTEBITS(); /* go to byte boundary */ - NEEDBITS(32); - if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - strm->msg = (char *)"invalid stored block lengths"; - state->mode = BAD; - break; - } - state->length = (unsigned)hold & 0xffff; - Tracev((stderr, "inflate: stored length %u\n", - state->length)); - INITBITS(); - state->mode = COPY; - case COPY: - copy = state->length; - if (copy) { - if (copy > have) copy = have; - if (copy > left) copy = left; - if (copy == 0) goto inf_leave; - zmemcpy(put, next, copy); - have -= copy; - next += copy; - left -= copy; - put += copy; - state->length -= copy; - break; - } - Tracev((stderr, "inflate: stored end\n")); - state->mode = TYPE; - break; - case TABLE: - NEEDBITS(14); - state->nlen = BITS(5) + 257; - DROPBITS(5); - state->ndist = BITS(5) + 1; - DROPBITS(5); - state->ncode = BITS(4) + 4; - DROPBITS(4); -#ifndef PKZIP_BUG_WORKAROUND - if (state->nlen > 286 || state->ndist > 30) { - strm->msg = (char *)"too many length or distance symbols"; - state->mode = BAD; - break; - } -#endif - Tracev((stderr, "inflate: table sizes ok\n")); - state->have = 0; - state->mode = LENLENS; - case LENLENS: - while (state->have < state->ncode) { - NEEDBITS(3); - state->lens[order[state->have++]] = (unsigned short)BITS(3); - DROPBITS(3); - } - while (state->have < 19) - state->lens[order[state->have++]] = 0; - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 7; - ret = inflate_table(CODES, state->lens, 19, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid code lengths set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: code lengths ok\n")); - state->have = 0; - state->mode = CODELENS; - case CODELENS: - while (state->have < state->nlen + state->ndist) { - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.val < 16) { - NEEDBITS(this.bits); - DROPBITS(this.bits); - state->lens[state->have++] = this.val; - } - else { - if (this.val == 16) { - NEEDBITS(this.bits + 2); - DROPBITS(this.bits); - if (state->have == 0) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - len = state->lens[state->have - 1]; - copy = 3 + BITS(2); - DROPBITS(2); - } - else if (this.val == 17) { - NEEDBITS(this.bits + 3); - DROPBITS(this.bits); - len = 0; - copy = 3 + BITS(3); - DROPBITS(3); - } - else { - NEEDBITS(this.bits + 7); - DROPBITS(this.bits); - len = 0; - copy = 11 + BITS(7); - DROPBITS(7); - } - if (state->have + copy > state->nlen + state->ndist) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - while (copy--) - state->lens[state->have++] = (unsigned short)len; - } - } - - /* handle error breaks in while */ - if (state->mode == BAD) break; - - /* build code tables */ - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 9; - ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid literal/lengths set"; - state->mode = BAD; - break; - } - state->distcode = (code const FAR *)(state->next); - state->distbits = 6; - ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, - &(state->next), &(state->distbits), state->work); - if (ret) { - strm->msg = (char *)"invalid distances set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: codes ok\n")); - state->mode = LEN; - case LEN: - if (have >= 6 && left >= 258) { - RESTORE(); - inflate_fast(strm, out); - LOAD(); - break; - } - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.op && (this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->lencode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - state->length = (unsigned)this.val; - if ((int)(this.op) == 0) { - Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", this.val)); - state->mode = LIT; - break; - } - if (this.op & 32) { - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - if (this.op & 64) { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - state->extra = (unsigned)(this.op) & 15; - state->mode = LENEXT; - case LENEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->length += BITS(state->extra); - DROPBITS(state->extra); - } - Tracevv((stderr, "inflate: length %u\n", state->length)); - state->mode = DIST; - case DIST: - for (;;) { - this = state->distcode[BITS(state->distbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if ((this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->distcode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - if (this.op & 64) { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - state->offset = (unsigned)this.val; - state->extra = (unsigned)(this.op) & 15; - state->mode = DISTEXT; - case DISTEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->offset += BITS(state->extra); - DROPBITS(state->extra); - } -#ifdef INFLATE_STRICT - if (state->offset > state->dmax) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#endif - if (state->offset > state->whave + out - left) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - Tracevv((stderr, "inflate: distance %u\n", state->offset)); - state->mode = MATCH; - case MATCH: - if (left == 0) goto inf_leave; - copy = out - left; - if (state->offset > copy) { /* copy from window */ - copy = state->offset - copy; - if (copy > state->write) { - copy -= state->write; - from = state->window + (state->wsize - copy); - } - else - from = state->window + (state->write - copy); - if (copy > state->length) copy = state->length; - } - else { /* copy from output */ - from = put - state->offset; - copy = state->length; - } - if (copy > left) copy = left; - left -= copy; - state->length -= copy; - do { - *put++ = *from++; - } while (--copy); - if (state->length == 0) state->mode = LEN; - break; - case LIT: - if (left == 0) goto inf_leave; - *put++ = (unsigned char)(state->length); - left--; - state->mode = LEN; - break; - case CHECK: - if (state->wrap) { - NEEDBITS(32); - out -= left; - strm->total_out += out; - state->total += out; - if (out) - strm->adler = state->check = - UPDATE(state->check, put - out, out); - out = left; - if (( -#ifdef GUNZIP - state->flags ? hold : -#endif - REVERSE(hold)) != state->check) { - strm->msg = (char *)"incorrect data check"; - state->mode = BAD; - break; - } - INITBITS(); - Tracev((stderr, "inflate: check matches trailer\n")); - } -#ifdef GUNZIP - state->mode = LENGTH; - case LENGTH: - if (state->wrap && state->flags) { - NEEDBITS(32); - if (hold != (state->total & 0xffffffffUL)) { - strm->msg = (char *)"incorrect length check"; - state->mode = BAD; - break; - } - INITBITS(); - Tracev((stderr, "inflate: length matches trailer\n")); - } -#endif - state->mode = DONE; - case DONE: - ret = Z_STREAM_END; - goto inf_leave; - case BAD: - ret = Z_DATA_ERROR; - goto inf_leave; - case MEM: - return Z_MEM_ERROR; - case SYNC: - default: - return Z_STREAM_ERROR; - } - - /* - Return from inflate(), updating the total counts and the check value. - If there was no progress during the inflate() call, return a buffer - error. Call updatewindow() to create and/or update the window state. - Note: a memory error from inflate() is non-recoverable. - */ - inf_leave: - RESTORE(); - if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) - if (updatewindow(strm, out)) { - state->mode = MEM; - return Z_MEM_ERROR; - } - in -= strm->avail_in; - out -= strm->avail_out; - strm->total_in += in; - strm->total_out += out; - state->total += out; - if (state->wrap && out) - strm->adler = state->check = - UPDATE(state->check, strm->next_out - out, out); - strm->data_type = state->bits + (state->last ? 64 : 0) + - (state->mode == TYPE ? 128 : 0); - if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) - ret = Z_BUF_ERROR; - return ret; -} - -int ZEXPORT inflateEnd(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (state->window != Z_NULL) ZFREE(strm, state->window); - ZFREE(strm, strm->state); - strm->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; -} - -int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) -z_streamp strm; -const Bytef *dictionary; -uInt dictLength; -{ - struct inflate_state FAR *state; - unsigned long id; - - /* check state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (state->wrap != 0 && state->mode != DICT) - return Z_STREAM_ERROR; - - /* check for correct dictionary id */ - if (state->mode == DICT) { - id = adler32(0L, Z_NULL, 0); - id = adler32(id, dictionary, dictLength); - if (id != state->check) - return Z_DATA_ERROR; - } - - /* copy dictionary to window */ - if (updatewindow(strm, strm->avail_out)) { - state->mode = MEM; - return Z_MEM_ERROR; - } - if (dictLength > state->wsize) { - zmemcpy(state->window, dictionary + dictLength - state->wsize, - state->wsize); - state->whave = state->wsize; - } - else { - zmemcpy(state->window + state->wsize - dictLength, dictionary, - dictLength); - state->whave = dictLength; - } - state->havedict = 1; - Tracev((stderr, "inflate: dictionary set\n")); - return Z_OK; -} - -int ZEXPORT inflateGetHeader(strm, head) -z_streamp strm; -gz_headerp head; -{ - struct inflate_state FAR *state; - - /* check state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; - - /* save header structure */ - state->head = head; - head->done = 0; - return Z_OK; -} - -/* - Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found - or when out of input. When called, *have is the number of pattern bytes - found in order so far, in 0..3. On return *have is updated to the new - state. If on return *have equals four, then the pattern was found and the - return value is how many bytes were read including the last byte of the - pattern. If *have is less than four, then the pattern has not been found - yet and the return value is len. In the latter case, syncsearch() can be - called again with more data and the *have state. *have is initialized to - zero for the first call. - */ -local unsigned syncsearch(have, buf, len) -unsigned FAR *have; -unsigned char FAR *buf; -unsigned len; -{ - unsigned got; - unsigned next; - - got = *have; - next = 0; - while (next < len && got < 4) { - if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) - got++; - else if (buf[next]) - got = 0; - else - got = 4 - got; - next++; - } - *have = got; - return next; -} - -int ZEXPORT inflateSync(strm) -z_streamp strm; -{ - unsigned len; /* number of bytes to look at or looked at */ - unsigned long in, out; /* temporary to save total_in and total_out */ - unsigned char buf[4]; /* to restore bit buffer to byte string */ - struct inflate_state FAR *state; - - /* check parameters */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; - - /* if first time, start search in bit buffer */ - if (state->mode != SYNC) { - state->mode = SYNC; - state->hold <<= state->bits & 7; - state->bits -= state->bits & 7; - len = 0; - while (state->bits >= 8) { - buf[len++] = (unsigned char)(state->hold); - state->hold >>= 8; - state->bits -= 8; - } - state->have = 0; - syncsearch(&(state->have), buf, len); - } - - /* search available input */ - len = syncsearch(&(state->have), strm->next_in, strm->avail_in); - strm->avail_in -= len; - strm->next_in += len; - strm->total_in += len; - - /* return no joy or set up to restart inflate() on a new block */ - if (state->have != 4) return Z_DATA_ERROR; - in = strm->total_in; out = strm->total_out; - inflateReset(strm); - strm->total_in = in; strm->total_out = out; - state->mode = TYPE; - return Z_OK; -} - -/* - Returns true if inflate is currently at the end of a block generated by - Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP - implementation to provide an additional safety check. PPP uses - Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored - block. When decompressing, PPP checks that at the end of input packet, - inflate is waiting for these length bytes. - */ -int ZEXPORT inflateSyncPoint(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - return state->mode == STORED && state->bits == 0; -} - -int ZEXPORT inflateCopy(dest, source) -z_streamp dest; -z_streamp source; -{ - struct inflate_state FAR *state; - struct inflate_state FAR *copy; - unsigned char FAR *window; - unsigned wsize; - - /* check input */ - if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || - source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)source->state; - - /* allocate space */ - copy = (struct inflate_state FAR *) - ZALLOC(source, 1, sizeof(struct inflate_state)); - if (copy == Z_NULL) return Z_MEM_ERROR; - window = Z_NULL; - if (state->window != Z_NULL) { - window = (unsigned char FAR *) - ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); - if (window == Z_NULL) { - ZFREE(source, copy); - return Z_MEM_ERROR; - } - } - - /* copy state */ - zmemcpy(dest, source, sizeof(z_stream)); - zmemcpy(copy, state, sizeof(struct inflate_state)); - if (state->lencode >= state->codes && - state->lencode <= state->codes + ENOUGH - 1) { - copy->lencode = copy->codes + (state->lencode - state->codes); - copy->distcode = copy->codes + (state->distcode - state->codes); - } - copy->next = copy->codes + (state->next - state->codes); - if (window != Z_NULL) { - wsize = 1U << state->wbits; - zmemcpy(window, state->window, wsize); - } - copy->window = window; - dest->state = (struct internal_state FAR *)copy; - return Z_OK; -} +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + strm->adler = 1; /* to support ill-conceived Java test suite */ + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->wsize = 0; + state->whave = 0; + state->write = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + if (state->mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy(dest, source, sizeof(z_stream)); + zmemcpy(copy, state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} diff --git a/pcsx2/3rdparty/zlib/inflate.h b/pcsx2/3rdparty/zlib/inflate.h index fbbc871432..07bd3e78a7 100644 --- a/pcsx2/3rdparty/zlib/inflate.h +++ b/pcsx2/3rdparty/zlib/inflate.h @@ -1,115 +1,115 @@ -/* inflate.h -- internal inflate state definition - * Copyright (C) 1995-2004 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer decoding by inflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip decoding - should be left enabled. */ -#ifndef NO_GZIP -# define GUNZIP -#endif - -/* Possible inflate modes between inflate() calls */ -typedef enum { - HEAD, /* i: waiting for magic header */ - FLAGS, /* i: waiting for method and flags (gzip) */ - TIME, /* i: waiting for modification time (gzip) */ - OS, /* i: waiting for extra flags and operating system (gzip) */ - EXLEN, /* i: waiting for extra length (gzip) */ - EXTRA, /* i: waiting for extra bytes (gzip) */ - NAME, /* i: waiting for end of file name (gzip) */ - COMMENT, /* i: waiting for end of comment (gzip) */ - HCRC, /* i: waiting for header crc (gzip) */ - DICTID, /* i: waiting for dictionary check value */ - DICT, /* waiting for inflateSetDictionary() call */ - TYPE, /* i: waiting for type bits, including last-flag bit */ - TYPEDO, /* i: same, but skip check to exit inflate on new block */ - STORED, /* i: waiting for stored size (length and complement) */ - COPY, /* i/o: waiting for input or output to copy stored block */ - TABLE, /* i: waiting for dynamic block table lengths */ - LENLENS, /* i: waiting for code length code lengths */ - CODELENS, /* i: waiting for length/lit and distance code lengths */ - LEN, /* i: waiting for length/lit code */ - LENEXT, /* i: waiting for length extra bits */ - DIST, /* i: waiting for distance code */ - DISTEXT, /* i: waiting for distance extra bits */ - MATCH, /* o: waiting for output space to copy string */ - LIT, /* o: waiting for output space to write literal */ - CHECK, /* i: waiting for 32-bit check value */ - LENGTH, /* i: waiting for 32-bit length (gzip) */ - DONE, /* finished check, done -- remain here until reset */ - BAD, /* got a data error -- remain here until reset */ - MEM, /* got an inflate() memory error -- remain here until reset */ - SYNC /* looking for synchronization bytes to restart inflate() */ -} inflate_mode; - -/* - State transitions between above modes - - - (most modes can go to the BAD or MEM mode -- not shown for clarity) - - Process header: - HEAD -> (gzip) or (zlib) - (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME - NAME -> COMMENT -> HCRC -> TYPE - (zlib) -> DICTID or TYPE - DICTID -> DICT -> TYPE - Read deflate blocks: - TYPE -> STORED or TABLE or LEN or CHECK - STORED -> COPY -> TYPE - TABLE -> LENLENS -> CODELENS -> LEN - Read deflate codes: - LEN -> LENEXT or LIT or TYPE - LENEXT -> DIST -> DISTEXT -> MATCH -> LEN - LIT -> LEN - Process trailer: - CHECK -> LENGTH -> DONE - */ - -/* state maintained between inflate() calls. Approximately 7K bytes. */ -struct inflate_state { - inflate_mode mode; /* current inflate mode */ - int last; /* true if processing last block */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - int havedict; /* true if dictionary provided */ - int flags; /* gzip header method and flags (0 if zlib) */ - unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ - unsigned long check; /* protected copy of check value */ - unsigned long total; /* protected copy of output count */ - gz_headerp head; /* where to save gzip header information */ - /* sliding window */ - unsigned wbits; /* log base 2 of requested window size */ - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned write; /* window write index */ - unsigned char FAR *window; /* allocated sliding window, if needed */ - /* bit accumulator */ - unsigned long hold; /* input bit accumulator */ - unsigned bits; /* number of bits in "in" */ - /* for string and stored block copying */ - unsigned length; /* literal or length of data to copy */ - unsigned offset; /* distance back to copy string from */ - /* for table and code decoding */ - unsigned extra; /* extra bits needed */ - /* fixed and dynamic code tables */ - code const FAR *lencode; /* starting table for length/literal codes */ - code const FAR *distcode; /* starting table for distance codes */ - unsigned lenbits; /* index bits for lencode */ - unsigned distbits; /* index bits for distcode */ - /* dynamic table building */ - unsigned ncode; /* number of code length code lengths */ - unsigned nlen; /* number of length code lengths */ - unsigned ndist; /* number of distance code lengths */ - unsigned have; /* number of code lengths in lens[] */ - code FAR *next; /* next available space in codes[] */ - unsigned short lens[320]; /* temporary storage for code lengths */ - unsigned short work[288]; /* work area for code table building */ - code codes[ENOUGH]; /* space for code tables */ -}; +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/pcsx2/3rdparty/zlib/inftrees.c b/pcsx2/3rdparty/zlib/inftrees.c index 38ded81c36..8a9c13ff03 100644 --- a/pcsx2/3rdparty/zlib/inftrees.c +++ b/pcsx2/3rdparty/zlib/inftrees.c @@ -1,329 +1,329 @@ -/* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" - -#define MAXBITS 15 - -const char inflate_copyright[] = - " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* - Build a set of tables to decode the provided canonical Huffman code. - The code lengths are lens[0..codes-1]. The result starts at *table, - whose indices are 0..2^bits-1. work is a writable array of at least - lens shorts, which is used as a work area. type is the type of code - to be generated, CODES, LENS, or DISTS. On return, zero is success, - -1 is an invalid code, and +1 means that ENOUGH isn't enough. table - on return points to the next available entry's address. bits is the - requested root table index bits, and on return it is the actual root - table index bits. It will differ if the request is greater than the - longest code or if it is less than the shortest code. - */ -int inflate_table(type, lens, codes, table, bits, work) -codetype type; -unsigned short FAR *lens; -unsigned codes; -code FAR * FAR *table; -unsigned FAR *bits; -unsigned short FAR *work; -{ - unsigned len; /* a code's length in bits */ - unsigned sym; /* index of code symbols */ - unsigned min, max; /* minimum and maximum code lengths */ - unsigned root; /* number of index bits for root table */ - unsigned curr; /* number of index bits for current table */ - unsigned drop; /* code bits to drop for sub-table */ - int left; /* number of prefix codes available */ - unsigned used; /* code entries in table used */ - unsigned huff; /* Huffman code */ - unsigned incr; /* for incrementing code, index */ - unsigned fill; /* index for replicating entries */ - unsigned low; /* low bits for current root entry */ - unsigned mask; /* mask for low root bits */ - code this; /* table entry for duplication */ - code FAR *next; /* next available space in table */ - const unsigned short FAR *base; /* base value table to use */ - const unsigned short FAR *extra; /* extra bits table to use */ - int end; /* use base and extra for symbol > end */ - unsigned short count[MAXBITS+1]; /* number of codes of each length */ - unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ - static const unsigned short lbase[31] = { /* Length codes 257..285 base */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - static const unsigned short lext[31] = { /* Length codes 257..285 extra */ - 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; - static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577, 0, 0}; - static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ - 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, - 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, - 28, 28, 29, 29, 64, 64}; - - /* - Process a set of code lengths to create a canonical Huffman code. The - code lengths are lens[0..codes-1]. Each length corresponds to the - symbols 0..codes-1. The Huffman code is generated by first sorting the - symbols by length from short to long, and retaining the symbol order - for codes with equal lengths. Then the code starts with all zero bits - for the first code of the shortest length, and the codes are integer - increments for the same length, and zeros are appended as the length - increases. For the deflate format, these bits are stored backwards - from their more natural integer increment ordering, and so when the - decoding tables are built in the large loop below, the integer codes - are incremented backwards. - - This routine assumes, but does not check, that all of the entries in - lens[] are in the range 0..MAXBITS. The caller must assure this. - 1..MAXBITS is interpreted as that code length. zero means that that - symbol does not occur in this code. - - The codes are sorted by computing a count of codes for each length, - creating from that a table of starting indices for each length in the - sorted table, and then entering the symbols in order in the sorted - table. The sorted table is work[], with that space being provided by - the caller. - - The length counts are used for other purposes as well, i.e. finding - the minimum and maximum length codes, determining if there are any - codes at all, checking for a valid set of lengths, and looking ahead - at length counts to determine sub-table sizes when building the - decoding tables. - */ - - /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ - for (len = 0; len <= MAXBITS; len++) - count[len] = 0; - for (sym = 0; sym < codes; sym++) - count[lens[sym]]++; - - /* bound code lengths, force root to be within code lengths */ - root = *bits; - for (max = MAXBITS; max >= 1; max--) - if (count[max] != 0) break; - if (root > max) root = max; - if (max == 0) { /* no symbols to code at all */ - this.op = (unsigned char)64; /* invalid code marker */ - this.bits = (unsigned char)1; - this.val = (unsigned short)0; - *(*table)++ = this; /* make a table to force an error */ - *(*table)++ = this; - *bits = 1; - return 0; /* no symbols, but wait for decoding to report error */ - } - for (min = 1; min <= MAXBITS; min++) - if (count[min] != 0) break; - if (root < min) root = min; - - /* check for an over-subscribed or incomplete set of lengths */ - left = 1; - for (len = 1; len <= MAXBITS; len++) { - left <<= 1; - left -= count[len]; - if (left < 0) return -1; /* over-subscribed */ - } - if (left > 0 && (type == CODES || max != 1)) - return -1; /* incomplete set */ - - /* generate offsets into symbol table for each length for sorting */ - offs[1] = 0; - for (len = 1; len < MAXBITS; len++) - offs[len + 1] = offs[len] + count[len]; - - /* sort symbols by length, by symbol order within each length */ - for (sym = 0; sym < codes; sym++) - if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; - - /* - Create and fill in decoding tables. In this loop, the table being - filled is at next and has curr index bits. The code being used is huff - with length len. That code is converted to an index by dropping drop - bits off of the bottom. For codes where len is less than drop + curr, - those top drop + curr - len bits are incremented through all values to - fill the table with replicated entries. - - root is the number of index bits for the root table. When len exceeds - root, sub-tables are created pointed to by the root entry with an index - of the low root bits of huff. This is saved in low to check for when a - new sub-table should be started. drop is zero when the root table is - being filled, and drop is root when sub-tables are being filled. - - When a new sub-table is needed, it is necessary to look ahead in the - code lengths to determine what size sub-table is needed. The length - counts are used for this, and so count[] is decremented as codes are - entered in the tables. - - used keeps track of how many table entries have been allocated from the - provided *table space. It is checked when a LENS table is being made - against the space in *table, ENOUGH, minus the maximum space needed by - the worst case distance code, MAXD. This should never happen, but the - sufficiency of ENOUGH has not been proven exhaustively, hence the check. - This assumes that when type == LENS, bits == 9. - - sym increments through all symbols, and the loop terminates when - all codes of length max, i.e. all codes, have been processed. This - routine permits incomplete codes, so another loop after this one fills - in the rest of the decoding tables with invalid code markers. - */ - - /* set up for code type */ - switch (type) { - case CODES: - base = extra = work; /* dummy value--not used */ - end = 19; - break; - case LENS: - base = lbase; - base -= 257; - extra = lext; - extra -= 257; - end = 256; - break; - default: /* DISTS */ - base = dbase; - extra = dext; - end = -1; - } - - /* initialize state for loop */ - huff = 0; /* starting code */ - sym = 0; /* starting code symbol */ - len = min; /* starting code length */ - next = *table; /* current table to fill in */ - curr = root; /* current table index bits */ - drop = 0; /* current bits to drop from code for index */ - low = (unsigned)(-1); /* trigger new sub-table when len > root */ - used = 1U << root; /* use root table entries */ - mask = used - 1; /* mask for comparing low */ - - /* check available table space */ - if (type == LENS && used >= ENOUGH - MAXD) - return 1; - - /* process all codes and make table entries */ - for (;;) { - /* create table entry */ - this.bits = (unsigned char)(len - drop); - if ((int)(work[sym]) < end) { - this.op = (unsigned char)0; - this.val = work[sym]; - } - else if ((int)(work[sym]) > end) { - this.op = (unsigned char)(extra[work[sym]]); - this.val = base[work[sym]]; - } - else { - this.op = (unsigned char)(32 + 64); /* end of block */ - this.val = 0; - } - - /* replicate for those indices with low len bits equal to huff */ - incr = 1U << (len - drop); - fill = 1U << curr; - min = fill; /* save offset to next table */ - do { - fill -= incr; - next[(huff >> drop) + fill] = this; - } while (fill != 0); - - /* backwards increment the len-bit code huff */ - incr = 1U << (len - 1); - while (huff & incr) - incr >>= 1; - if (incr != 0) { - huff &= incr - 1; - huff += incr; - } - else - huff = 0; - - /* go to next symbol, update count, len */ - sym++; - if (--(count[len]) == 0) { - if (len == max) break; - len = lens[work[sym]]; - } - - /* create new sub-table if needed */ - if (len > root && (huff & mask) != low) { - /* if first time, transition to sub-tables */ - if (drop == 0) - drop = root; - - /* increment past last table */ - next += min; /* here min is 1 << curr */ - - /* determine length of next table */ - curr = len - drop; - left = (int)(1 << curr); - while (curr + drop < max) { - left -= count[curr + drop]; - if (left <= 0) break; - curr++; - left <<= 1; - } - - /* check for enough space */ - used += 1U << curr; - if (type == LENS && used >= ENOUGH - MAXD) - return 1; - - /* point entry in root table to sub-table */ - low = huff & mask; - (*table)[low].op = (unsigned char)curr; - (*table)[low].bits = (unsigned char)root; - (*table)[low].val = (unsigned short)(next - *table); - } - } - - /* - Fill in rest of table for incomplete codes. This loop is similar to the - loop above in incrementing huff for table indices. It is assumed that - len is equal to curr + drop, so there is no loop needed to increment - through high index bits. When the current sub-table is filled, the loop - drops back to the root table to fill in any remaining entries there. - */ - this.op = (unsigned char)64; /* invalid code marker */ - this.bits = (unsigned char)(len - drop); - this.val = (unsigned short)0; - while (huff != 0) { - /* when done with sub-table, drop back to root table */ - if (drop != 0 && (huff & mask) != low) { - drop = 0; - len = root; - next = *table; - this.bits = (unsigned char)len; - } - - /* put invalid code marker in table */ - next[huff >> drop] = this; - - /* backwards increment the len-bit code huff */ - incr = 1U << (len - 1); - while (huff & incr) - incr >>= 1; - if (incr != 0) { - huff &= incr - 1; - huff += incr; - } - else - huff = 0; - } - - /* set return parameters */ - *table += used; - *bits = root; - return 0; -} +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)1; + this.val = (unsigned short)0; + *(*table)++ = this; /* make a table to force an error */ + *(*table)++ = this; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/pcsx2/3rdparty/zlib/inftrees.h b/pcsx2/3rdparty/zlib/inftrees.h index dc0fd567ea..b1104c87e7 100644 --- a/pcsx2/3rdparty/zlib/inftrees.h +++ b/pcsx2/3rdparty/zlib/inftrees.h @@ -1,55 +1,55 @@ -/* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* Structure for decoding tables. Each entry provides either the - information needed to do the operation requested by the code that - indexed that table entry, or it provides a pointer to another - table that indexes more bits of the code. op indicates whether - the entry is a pointer to another table, a literal, a length or - distance, an end-of-block, or an invalid code. For a table - pointer, the low four bits of op is the number of index bits of - that table. For a length or distance, the low four bits of op - is the number of extra bits to get after the code. bits is - the number of bits in this code or part of the code to drop off - of the bit buffer. val is the actual byte to output in the case - of a literal, the base length or distance, or the offset from - the current table to the next table. Each entry is four bytes. */ -typedef struct { - unsigned char op; /* operation, extra bits, table bits */ - unsigned char bits; /* bits in this part of the code */ - unsigned short val; /* offset in table or code value */ -} code; - -/* op values as set by inflate_table(): - 00000000 - literal - 0000tttt - table link, tttt != 0 is the number of table index bits - 0001eeee - length or distance, eeee is the number of extra bits - 01100000 - end of block - 01000000 - invalid code - */ - -/* Maximum size of dynamic tree. The maximum found in a long but non- - exhaustive search was 1444 code structures (852 for length/literals - and 592 for distances, the latter actually the result of an - exhaustive search). The true maximum is not known, but the value - below is more than safe. */ -#define ENOUGH 2048 -#define MAXD 592 - -/* Type of code to build for inftable() */ -typedef enum { - CODES, - LENS, - DISTS -} codetype; - -extern int inflate_table OF((codetype type, unsigned short FAR *lens, - unsigned codes, code FAR * FAR *table, - unsigned FAR *bits, unsigned short FAR *work)); +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1444 code structures (852 for length/literals + and 592 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 2048 +#define MAXD 592 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/pcsx2/3rdparty/zlib/trees.c b/pcsx2/3rdparty/zlib/trees.c index 7a04802862..395e4e1681 100644 --- a/pcsx2/3rdparty/zlib/trees.c +++ b/pcsx2/3rdparty/zlib/trees.c @@ -1,1219 +1,1219 @@ -/* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2005 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process uses several Huffman trees. The more - * common source values are represented by shorter bit sequences. - * - * Each code tree is stored in a compressed form which is itself - * a Huffman encoding of the lengths of all the code strings (in - * ascending order by source values). The actual code strings are - * reconstructed from the lengths in the inflate process, as described - * in the deflate specification. - * - * REFERENCES - * - * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". - * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc - * - * Storer, James A. - * Data Compression: Methods and Theory, pp. 49-50. - * Computer Science Press, 1988. ISBN 0-7167-8156-5. - * - * Sedgewick, R. - * Algorithms, p290. - * Addison-Wesley, 1983. ISBN 0-201-06672-6. - */ - -/* @(#) $Id$ */ - -/* #define GEN_TREES_H */ - -#include "deflate.h" - -#ifdef DEBUG -# include -#endif - -/* =========================================================================== - * Constants - */ - -#define MAX_BL_BITS 7 -/* Bit length codes must not exceed MAX_BL_BITS bits */ - -#define END_BLOCK 256 -/* end of block literal code */ - -#define REP_3_6 16 -/* repeat previous bit length 3-6 times (2 bits of repeat count) */ - -#define REPZ_3_10 17 -/* repeat a zero length 3-10 times (3 bits of repeat count) */ - -#define REPZ_11_138 18 -/* repeat a zero length 11-138 times (7 bits of repeat count) */ - -local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ - = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; - -local const int extra_dbits[D_CODES] /* extra bits for each distance code */ - = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ - = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; - -local const uch bl_order[BL_CODES] - = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; -/* The lengths of the bit length codes are sent in order of decreasing - * probability, to avoid transmitting the lengths for unused bit length codes. - */ - -#define Buf_size (8 * 2*sizeof(char)) -/* Number of bits used within bi_buf. (bi_buf might be implemented on - * more than 16 bits on some systems.) - */ - -/* =========================================================================== - * Local data. These are initialized only once. - */ - -#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ - -#if defined(GEN_TREES_H) || !defined(STDC) -/* non ANSI compilers may not accept trees.h */ - -local ct_data static_ltree[L_CODES+2]; -/* The static literal tree. Since the bit lengths are imposed, there is no - * need for the L_CODES extra codes used during heap construction. However - * The codes 286 and 287 are needed to build a canonical tree (see _tr_init - * below). - */ - -local ct_data static_dtree[D_CODES]; -/* The static distance tree. (Actually a trivial tree since all codes use - * 5 bits.) - */ - -uch _dist_code[DIST_CODE_LEN]; -/* Distance codes. The first 256 values correspond to the distances - * 3 .. 258, the last 256 values correspond to the top 8 bits of - * the 15 bit distances. - */ - -uch _length_code[MAX_MATCH-MIN_MATCH+1]; -/* length code for each normalized match length (0 == MIN_MATCH) */ - -local int base_length[LENGTH_CODES]; -/* First normalized length for each code (0 = MIN_MATCH) */ - -local int base_dist[D_CODES]; -/* First normalized distance for each code (0 = distance of 1) */ - -#else -# include "trees.h" -#endif /* GEN_TREES_H */ - -struct static_tree_desc_s { - const ct_data *static_tree; /* static tree or NULL */ - const intf *extra_bits; /* extra bits for each code or NULL */ - int extra_base; /* base index for extra_bits */ - int elems; /* max number of elements in the tree */ - int max_length; /* max bit length for the codes */ -}; - -local static_tree_desc static_l_desc = -{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; - -local static_tree_desc static_d_desc = -{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; - -local static_tree_desc static_bl_desc = -{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; - -/* =========================================================================== - * Local (static) routines in this file. - */ - -local void tr_static_init OF((void)); -local void init_block OF((deflate_state *s)); -local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); -local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); -local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); -local void build_tree OF((deflate_state *s, tree_desc *desc)); -local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local int build_bl_tree OF((deflate_state *s)); -local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, - int blcodes)); -local void compress_block OF((deflate_state *s, ct_data *ltree, - ct_data *dtree)); -local void set_data_type OF((deflate_state *s)); -local unsigned bi_reverse OF((unsigned value, int length)); -local void bi_windup OF((deflate_state *s)); -local void bi_flush OF((deflate_state *s)); -local void copy_block OF((deflate_state *s, charf *buf, unsigned len, - int header)); - -#ifdef GEN_TREES_H -local void gen_trees_header OF((void)); -#endif - -#ifndef DEBUG -# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) - /* Send a code of the given tree. c and tree must not have side effects */ - -#else /* DEBUG */ -# define send_code(s, c, tree) \ - { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ - send_bits(s, tree[c].Code, tree[c].Len); } -#endif - -/* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ -#define put_short(s, w) { \ - put_byte(s, (uch)((w) & 0xff)); \ - put_byte(s, (uch)((ush)(w) >> 8)); \ -} - -/* =========================================================================== - * Send a value on a given number of bits. - * IN assertion: length <= 16 and value fits in length bits. - */ -#ifdef DEBUG -local void send_bits OF((deflate_state *s, int value, int length)); - -local void send_bits(s, value, length) - deflate_state *s; - int value; /* value to send */ - int length; /* number of bits */ -{ - Tracevv((stderr," l %2d v %4x ", length, value)); - Assert(length > 0 && length <= 15, "invalid length"); - s->bits_sent += (ulg)length; - - /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) - * unused bits in value. - */ - if (s->bi_valid > (int)Buf_size - length) { - s->bi_buf |= (value << s->bi_valid); - put_short(s, s->bi_buf); - s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); - s->bi_valid += length - Buf_size; - } else { - s->bi_buf |= value << s->bi_valid; - s->bi_valid += length; - } -} -#else /* !DEBUG */ - -#define send_bits(s, value, length) \ -{ int len = length;\ - if (s->bi_valid > (int)Buf_size - len) {\ - int val = value;\ - s->bi_buf |= (val << s->bi_valid);\ - put_short(s, s->bi_buf);\ - s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ - s->bi_valid += len - Buf_size;\ - } else {\ - s->bi_buf |= (value) << s->bi_valid;\ - s->bi_valid += len;\ - }\ -} -#endif /* DEBUG */ - - -/* the arguments must not have side effects */ - -/* =========================================================================== - * Initialize the various 'constant' tables. - */ -local void tr_static_init() -{ -#if defined(GEN_TREES_H) || !defined(STDC) - static int static_init_done = 0; - int n; /* iterates over tree elements */ - int bits; /* bit counter */ - int length; /* length value */ - int code; /* code value */ - int dist; /* distance index */ - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - if (static_init_done) return; - - /* For some embedded targets, global variables are not initialized: */ - static_l_desc.static_tree = static_ltree; - static_l_desc.extra_bits = extra_lbits; - static_d_desc.static_tree = static_dtree; - static_d_desc.extra_bits = extra_dbits; - static_bl_desc.extra_bits = extra_blbits; - - /* Initialize the mapping length (0..255) -> length code (0..28) */ - length = 0; - for (code = 0; code < LENGTH_CODES-1; code++) { - base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ - dist = 0; - for (code = 0 ; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ - for ( ; code < D_CODES; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { - _dist_code[256 + dist++] = (uch)code; - } - } - Assert (dist == 256, "tr_static_init: 256+dist != 512"); - - /* Construct the codes of the static literal tree */ - for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; - n = 0; - while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; - while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; - while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; - while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; - /* Codes 286 and 287 do not exist, but we must include them in the - * tree construction to get a canonical Huffman tree (longest code - * all ones) - */ - gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); - - /* The static distance tree is trivial: */ - for (n = 0; n < D_CODES; n++) { - static_dtree[n].Len = 5; - static_dtree[n].Code = bi_reverse((unsigned)n, 5); - } - static_init_done = 1; - -# ifdef GEN_TREES_H - gen_trees_header(); -# endif -#endif /* defined(GEN_TREES_H) || !defined(STDC) */ -} - -/* =========================================================================== - * Genererate the file trees.h describing the static trees. - */ -#ifdef GEN_TREES_H -# ifndef DEBUG -# include -# endif - -# define SEPARATOR(i, last, width) \ - ((i) == (last)? "\n};\n\n" : \ - ((i) % (width) == (width)-1 ? ",\n" : ", ")) - -void gen_trees_header() -{ - FILE *header = fopen("trees.h", "w"); - int i; - - Assert (header != NULL, "Can't open trees.h"); - fprintf(header, - "/* header created automatically with -DGEN_TREES_H */\n\n"); - - fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); - for (i = 0; i < L_CODES+2; i++) { - fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, - static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); - } - - fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); - for (i = 0; i < D_CODES; i++) { - fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, - static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); - } - - fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); - for (i = 0; i < DIST_CODE_LEN; i++) { - fprintf(header, "%2u%s", _dist_code[i], - SEPARATOR(i, DIST_CODE_LEN-1, 20)); - } - - fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); - for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { - fprintf(header, "%2u%s", _length_code[i], - SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); - } - - fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); - for (i = 0; i < LENGTH_CODES; i++) { - fprintf(header, "%1u%s", base_length[i], - SEPARATOR(i, LENGTH_CODES-1, 20)); - } - - fprintf(header, "local const int base_dist[D_CODES] = {\n"); - for (i = 0; i < D_CODES; i++) { - fprintf(header, "%5u%s", base_dist[i], - SEPARATOR(i, D_CODES-1, 10)); - } - - fclose(header); -} -#endif /* GEN_TREES_H */ - -/* =========================================================================== - * Initialize the tree data structures for a new zlib stream. - */ -void _tr_init(s) - deflate_state *s; -{ - tr_static_init(); - - s->l_desc.dyn_tree = s->dyn_ltree; - s->l_desc.stat_desc = &static_l_desc; - - s->d_desc.dyn_tree = s->dyn_dtree; - s->d_desc.stat_desc = &static_d_desc; - - s->bl_desc.dyn_tree = s->bl_tree; - s->bl_desc.stat_desc = &static_bl_desc; - - s->bi_buf = 0; - s->bi_valid = 0; - s->last_eob_len = 8; /* enough lookahead for inflate */ -#ifdef DEBUG - s->compressed_len = 0L; - s->bits_sent = 0L; -#endif - - /* Initialize the first block of the first file: */ - init_block(s); -} - -/* =========================================================================== - * Initialize a new block. - */ -local void init_block(s) - deflate_state *s; -{ - int n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; - for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; - for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; - - s->dyn_ltree[END_BLOCK].Freq = 1; - s->opt_len = s->static_len = 0L; - s->last_lit = s->matches = 0; -} - -#define SMALLEST 1 -/* Index within the heap array of least frequent node in the Huffman tree */ - - -/* =========================================================================== - * Remove the smallest element from the heap and recreate the heap with - * one less element. Updates heap and heap_len. - */ -#define pqremove(s, tree, top) \ -{\ - top = s->heap[SMALLEST]; \ - s->heap[SMALLEST] = s->heap[s->heap_len--]; \ - pqdownheap(s, tree, SMALLEST); \ -} - -/* =========================================================================== - * Compares to subtrees, using the tree depth as tie breaker when - * the subtrees have equal frequency. This minimizes the worst case length. - */ -#define smaller(tree, n, m, depth) \ - (tree[n].Freq < tree[m].Freq || \ - (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) - -/* =========================================================================== - * Restore the heap property by moving down the tree starting at node k, - * exchanging a node with the smallest of its two sons if necessary, stopping - * when the heap property is re-established (each father smaller than its - * two sons). - */ -local void pqdownheap(s, tree, k) - deflate_state *s; - ct_data *tree; /* the tree to restore */ - int k; /* node to move down */ -{ - int v = s->heap[k]; - int j = k << 1; /* left son of k */ - while (j <= s->heap_len) { - /* Set j to the smallest of the two sons: */ - if (j < s->heap_len && - smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { - j++; - } - /* Exit if v is smaller than both sons */ - if (smaller(tree, v, s->heap[j], s->depth)) break; - - /* Exchange v with the smallest son */ - s->heap[k] = s->heap[j]; k = j; - - /* And continue down the tree, setting j to the left son of k */ - j <<= 1; - } - s->heap[k] = v; -} - -/* =========================================================================== - * Compute the optimal bit lengths for a tree and update the total bit length - * for the current block. - * IN assertion: the fields freq and dad are set, heap[heap_max] and - * above are the tree nodes sorted by increasing frequency. - * OUT assertions: the field len is set to the optimal bit length, the - * array bl_count contains the frequencies for each bit length. - * The length opt_len is updated; static_len is also updated if stree is - * not null. - */ -local void gen_bitlen(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ -{ - ct_data *tree = desc->dyn_tree; - int max_code = desc->max_code; - const ct_data *stree = desc->stat_desc->static_tree; - const intf *extra = desc->stat_desc->extra_bits; - int base = desc->stat_desc->extra_base; - int max_length = desc->stat_desc->max_length; - int h; /* heap index */ - int n, m; /* iterate over the tree elements */ - int bits; /* bit length */ - int xbits; /* extra bits */ - ush f; /* frequency */ - int overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; - - /* In a first pass, compute the optimal bit lengths (which may - * overflow in the case of the bit length tree). - */ - tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - - for (h = s->heap_max+1; h < HEAP_SIZE; h++) { - n = s->heap[h]; - bits = tree[tree[n].Dad].Len + 1; - if (bits > max_length) bits = max_length, overflow++; - tree[n].Len = (ush)bits; - /* We overwrite tree[n].Dad which is no longer needed */ - - if (n > max_code) continue; /* not a leaf node */ - - s->bl_count[bits]++; - xbits = 0; - if (n >= base) xbits = extra[n-base]; - f = tree[n].Freq; - s->opt_len += (ulg)f * (bits + xbits); - if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); - } - if (overflow == 0) return; - - Trace((stderr,"\nbit length overflow\n")); - /* This happens for example on obj2 and pic of the Calgary corpus */ - - /* Find the first bit length which could increase: */ - do { - bits = max_length-1; - while (s->bl_count[bits] == 0) bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ - s->bl_count[max_length]--; - /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] - */ - overflow -= 2; - } while (overflow > 0); - - /* Now recompute all bit lengths, scanning in increasing frequency. - * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - * lengths instead of fixing only the wrong ones. This idea is taken - * from 'ar' written by Haruhiko Okumura.) - */ - for (bits = max_length; bits != 0; bits--) { - n = s->bl_count[bits]; - while (n != 0) { - m = s->heap[--h]; - if (m > max_code) continue; - if ((unsigned) tree[m].Len != (unsigned) bits) { - Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); - s->opt_len += ((long)bits - (long)tree[m].Len) - *(long)tree[m].Freq; - tree[m].Len = (ush)bits; - } - n--; - } - } -} - -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -local void gen_codes (tree, max_code, bl_count) - ct_data *tree; /* the tree to decorate */ - int max_code; /* largest code with non zero frequency */ - ushf *bl_count; /* number of codes at each bit length */ -{ - ush next_code[MAX_BITS+1]; /* next code value for each bit length */ - ush code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (code + bl_count[bits-1]) << 1; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; - const ct_data *stree = desc->stat_desc->static_tree; - int elems = desc->stat_desc->elems; - int n, m; /* iterate over heap elements */ - int max_code = -1; /* largest code with non zero frequency */ - int node; /* new node being created */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - s->heap_len = 0, s->heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) { - if (tree[n].Freq != 0) { - s->heap[++(s->heap_len)] = max_code = n; - s->depth[n] = 0; - } else { - tree[n].Len = 0; - } - } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (s->heap_len < 2) { - node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); - tree[node].Freq = 1; - s->depth[node] = 0; - s->opt_len--; if (stree) s->static_len -= stree[node].Len; - /* node is 0 or 1 so it does not have extra bits */ - } - desc->max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - node = elems; /* next internal node of the tree */ - do { - pqremove(s, tree, n); /* n = node of least frequency */ - m = s->heap[SMALLEST]; /* m = node of next least frequency */ - - s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ - s->heap[--(s->heap_max)] = m; - - /* Create a new node father of n and m */ - tree[node].Freq = tree[n].Freq + tree[m].Freq; - s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? - s->depth[n] : s->depth[m]) + 1); - tree[n].Dad = tree[m].Dad = (ush)node; -#ifdef DUMP_BL_TREE - if (tree == s->bl_tree) { - fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", - node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); - } -#endif - /* and insert the new node in the heap */ - s->heap[SMALLEST] = node++; - pqdownheap(s, tree, SMALLEST); - - } while (s->heap_len >= 2); - - s->heap[--(s->heap_max)] = s->heap[SMALLEST]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen(s, (tree_desc *)desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes ((ct_data *)tree, max_code, s->bl_count); -} - -/* =========================================================================== - * Scan a literal or distance tree to determine the frequencies of the codes - * in the bit length tree. - */ -local void scan_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].Len = (ush)0xffff; /* guard */ - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - s->bl_tree[curlen].Freq += count; - } else if (curlen != 0) { - if (curlen != prevlen) s->bl_tree[curlen].Freq++; - s->bl_tree[REP_3_6].Freq++; - } else if (count <= 10) { - s->bl_tree[REPZ_3_10].Freq++; - } else { - s->bl_tree[REPZ_11_138].Freq++; - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Send a literal or distance tree in compressed form, using the codes in - * bl_tree. - */ -local void send_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - /* tree[max_code+1].Len = -1; */ /* guard already set */ - if (nextlen == 0) max_count = 138, min_count = 3; - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - do { send_code(s, curlen, s->bl_tree); } while (--count != 0); - - } else if (curlen != 0) { - if (curlen != prevlen) { - send_code(s, curlen, s->bl_tree); count--; - } - Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); - - } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); - - } else { - send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Construct the Huffman tree for the bit lengths and return the index in - * bl_order of the last bit length code to send. - */ -local int build_bl_tree(s) - deflate_state *s; -{ - int max_blindex; /* index of last bit length code of non zero freq */ - - /* Determine the bit length frequencies for literal and distance trees */ - scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); - scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); - - /* Build the bit length tree: */ - build_tree(s, (tree_desc *)(&(s->bl_desc))); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - */ - - /* Determine the number of bit length codes to send. The pkzip format - * requires that at least 4 bit length codes be sent. (appnote.txt says - * 3 but the actual value used is 4.) - */ - for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { - if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; - } - /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*(max_blindex+1) + 5+5+4; - Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", - s->opt_len, s->static_len)); - - return max_blindex; -} - -/* =========================================================================== - * Send the header for a block using dynamic Huffman trees: the counts, the - * lengths of the bit length codes, the literal tree and the distance tree. - * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - */ -local void send_all_trees(s, lcodes, dcodes, blcodes) - deflate_state *s; - int lcodes, dcodes, blcodes; /* number of codes for each tree */ -{ - int rank; /* index in bl_order */ - - Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); - Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, - "too many codes"); - Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ - for (rank = 0; rank < blcodes; rank++) { - Tracev((stderr, "\nbl code %2d ", bl_order[rank])); - send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); - } - Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ - Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ - Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); -} - -/* =========================================================================== - * Send a stored block - */ -void _tr_stored_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ -{ - send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ -#ifdef DEBUG - s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; - s->compressed_len += (stored_len + 4) << 3; -#endif - copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ -} - -/* =========================================================================== - * Send one empty static block to give enough lookahead for inflate. - * This takes 10 bits, of which 7 may remain in the bit buffer. - * The current inflate code requires 9 bits of lookahead. If the - * last two codes for the previous block (real code plus EOB) were coded - * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode - * the last real code. In this case we send two empty static blocks instead - * of one. (There are no problems if the previous block is stored or fixed.) - * To simplify the code, we assume the worst case of last real code encoded - * on one bit only. - */ -void _tr_align(s) - deflate_state *s; -{ - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); -#ifdef DEBUG - s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ -#endif - bi_flush(s); - /* Of the 10 bits for the empty block, we have already sent - * (10 - bi_valid) bits. The lookahead for the last real code (before - * the EOB of the previous block) was thus at least one plus the length - * of the EOB plus what we have just sent of the empty static block. - */ - if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); -#ifdef DEBUG - s->compressed_len += 10L; -#endif - bi_flush(s); - } - s->last_eob_len = 7; -} - -/* =========================================================================== - * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. - */ -void _tr_flush_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block, or NULL if too old */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ -{ - ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ - int max_blindex = 0; /* index of last bit length code of non zero freq */ - - /* Build the Huffman trees unless a stored block is forced */ - if (s->level > 0) { - - /* Check if the file is binary or text */ - if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) - set_data_type(s); - - /* Construct the literal and distance trees */ - build_tree(s, (tree_desc *)(&(s->l_desc))); - Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - - build_tree(s, (tree_desc *)(&(s->d_desc))); - Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ - - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(s); - - /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; - - Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", - opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - s->last_lit)); - - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; - - } else { - Assert(buf != (char*)0, "lost buf"); - opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ - } - -#ifdef FORCE_STORED - if (buf != (char*)0) { /* force stored block */ -#else - if (stored_len+4 <= opt_lenb && buf != (char*)0) { - /* 4: two words for the lengths */ -#endif - /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - * Otherwise we can't have processed more than WSIZE input bytes since - * the last block flush, because compression would have been - * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - * transform a block into a stored block. - */ - _tr_stored_block(s, buf, stored_len, eof); - -#ifdef FORCE_STATIC - } else if (static_lenb >= 0) { /* force static trees */ -#else - } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { -#endif - send_bits(s, (STATIC_TREES<<1)+eof, 3); - compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); -#ifdef DEBUG - s->compressed_len += 3 + s->static_len; -#endif - } else { - send_bits(s, (DYN_TREES<<1)+eof, 3); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, - max_blindex+1); - compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); -#ifdef DEBUG - s->compressed_len += 3 + s->opt_len; -#endif - } - Assert (s->compressed_len == s->bits_sent, "bad compressed size"); - /* The above check is made mod 2^32, for files larger than 512 MB - * and uLong implemented on 32 bits. - */ - init_block(s); - - if (eof) { - bi_windup(s); -#ifdef DEBUG - s->compressed_len += 7; /* align on byte boundary */ -#endif - } - Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - s->compressed_len-7*eof)); -} - -/* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ -int _tr_tally (s, dist, lc) - deflate_state *s; - unsigned dist; /* distance of matched string */ - unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ -{ - s->d_buf[s->last_lit] = (ush)dist; - s->l_buf[s->last_lit++] = (uch)lc; - if (dist == 0) { - /* lc is the unmatched char */ - s->dyn_ltree[lc].Freq++; - } else { - s->matches++; - /* Here, lc is the match length - MIN_MATCH */ - dist--; /* dist = match distance - 1 */ - Assert((ush)dist < (ush)MAX_DIST(s) && - (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && - (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - - s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; - s->dyn_dtree[d_code(dist)].Freq++; - } - -#ifdef TRUNCATE_BLOCK - /* Try to guess if it is profitable to stop the current block here */ - if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { - /* Compute an upper bound for the compressed length */ - ulg out_length = (ulg)s->last_lit*8L; - ulg in_length = (ulg)((long)s->strstart - s->block_start); - int dcode; - for (dcode = 0; dcode < D_CODES; dcode++) { - out_length += (ulg)s->dyn_dtree[dcode].Freq * - (5L+extra_dbits[dcode]); - } - out_length >>= 3; - Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", - s->last_lit, in_length, out_length, - 100L - out_length*100L/in_length)); - if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; - } -#endif - return (s->last_lit == s->lit_bufsize-1); - /* We avoid equality with lit_bufsize because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ -} - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -local void compress_block(s, ltree, dtree) - deflate_state *s; - ct_data *ltree; /* literal tree */ - ct_data *dtree; /* distance tree */ -{ - unsigned dist; /* distance of matched string */ - int lc; /* match length or unmatched char (if dist == 0) */ - unsigned lx = 0; /* running index in l_buf */ - unsigned code; /* the code to send */ - int extra; /* number of extra bits to send */ - - if (s->last_lit != 0) do { - dist = s->d_buf[lx]; - lc = s->l_buf[lx++]; - if (dist == 0) { - send_code(s, lc, ltree); /* send a literal byte */ - Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = _length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra != 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra != 0) { - dist -= base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ - Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, - "pendingBuf overflow"); - - } while (lx < s->last_lit); - - send_code(s, END_BLOCK, ltree); - s->last_eob_len = ltree[END_BLOCK].Len; -} - -/* =========================================================================== - * Set the data type to BINARY or TEXT, using a crude approximation: - * set it to Z_TEXT if all symbols are either printable characters (33 to 255) - * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. - * IN assertion: the fields Freq of dyn_ltree are set. - */ -local void set_data_type(s) - deflate_state *s; -{ - int n; - - for (n = 0; n < 9; n++) - if (s->dyn_ltree[n].Freq != 0) - break; - if (n == 9) - for (n = 14; n < 32; n++) - if (s->dyn_ltree[n].Freq != 0) - break; - s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; -} - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -local unsigned bi_reverse(code, len) - unsigned code; /* the value to invert */ - int len; /* its bit length */ -{ - register unsigned res = 0; - do { - res |= code & 1; - code >>= 1, res <<= 1; - } while (--len > 0); - return res >> 1; -} - -/* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ -local void bi_flush(s) - deflate_state *s; -{ - if (s->bi_valid == 16) { - put_short(s, s->bi_buf); - s->bi_buf = 0; - s->bi_valid = 0; - } else if (s->bi_valid >= 8) { - put_byte(s, (Byte)s->bi_buf); - s->bi_buf >>= 8; - s->bi_valid -= 8; - } -} - -/* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ -local void bi_windup(s) - deflate_state *s; -{ - if (s->bi_valid > 8) { - put_short(s, s->bi_buf); - } else if (s->bi_valid > 0) { - put_byte(s, (Byte)s->bi_buf); - } - s->bi_buf = 0; - s->bi_valid = 0; -#ifdef DEBUG - s->bits_sent = (s->bits_sent+7) & ~7; -#endif -} - -/* =========================================================================== - * Copy a stored block, storing first the length and its - * one's complement if requested. - */ -local void copy_block(s, buf, len, header) - deflate_state *s; - charf *buf; /* the input data */ - unsigned len; /* its length */ - int header; /* true if block header must be written */ -{ - bi_windup(s); /* align on byte boundary */ - s->last_eob_len = 8; /* enough lookahead for inflate */ - - if (header) { - put_short(s, (ush)len); - put_short(s, (ush)~len); -#ifdef DEBUG - s->bits_sent += 2*16; -#endif - } -#ifdef DEBUG - s->bits_sent += (ulg)len<<3; -#endif - while (len--) { - put_byte(s, *buf++); - } -} +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2005 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) + set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to BINARY or TEXT, using a crude approximation: + * set it to Z_TEXT if all symbols are either printable characters (33 to 255) + * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local void set_data_type(s) + deflate_state *s; +{ + int n; + + for (n = 0; n < 9; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + if (n == 9) + for (n = 14; n < 32; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/pcsx2/3rdparty/zlib/trees.h b/pcsx2/3rdparty/zlib/trees.h index 1ca868b848..72facf900f 100644 --- a/pcsx2/3rdparty/zlib/trees.h +++ b/pcsx2/3rdparty/zlib/trees.h @@ -1,128 +1,128 @@ -/* header created automatically with -DGEN_TREES_H */ - -local const ct_data static_ltree[L_CODES+2] = { -{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, -{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, -{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, -{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, -{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, -{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, -{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, -{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, -{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, -{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, -{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, -{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, -{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, -{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, -{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, -{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, -{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, -{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, -{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, -{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, -{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, -{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, -{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, -{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, -{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, -{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, -{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, -{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, -{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, -{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, -{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, -{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, -{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, -{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, -{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, -{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, -{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, -{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, -{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, -{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, -{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, -{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, -{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, -{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, -{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, -{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, -{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, -{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, -{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, -{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, -{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, -{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, -{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, -{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, -{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, -{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, -{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, -{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} -}; - -local const ct_data static_dtree[D_CODES] = { -{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, -{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, -{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, -{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, -{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, -{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} -}; - -const uch _dist_code[DIST_CODE_LEN] = { - 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, - 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, -10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, -11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, -12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, -18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 -}; - -const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, -13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, -17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, -19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, -21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, -22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 -}; - -local const int base_length[LENGTH_CODES] = { -0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, -64, 80, 96, 112, 128, 160, 192, 224, 0 -}; - -local const int base_dist[D_CODES] = { - 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, - 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, - 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 -}; - +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/pcsx2/3rdparty/zlib/uncompr.c b/pcsx2/3rdparty/zlib/uncompr.c index ad6db0a67c..b59e3d0def 100644 --- a/pcsx2/3rdparty/zlib/uncompr.c +++ b/pcsx2/3rdparty/zlib/uncompr.c @@ -1,61 +1,61 @@ -/* uncompr.c -- decompress a memory buffer - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -/* =========================================================================== - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted. -*/ -int ZEXPORT uncompress (dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ - z_stream stream; - int err; - - stream.next_in = (Bytef*)source; - stream.avail_in = (uInt)sourceLen; - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; - - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; - - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - - err = inflateInit(&stream); - if (err != Z_OK) return err; - - err = inflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - inflateEnd(&stream); - if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) - return Z_DATA_ERROR; - return err; - } - *destLen = stream.total_out; - - err = inflateEnd(&stream); - return err; -} +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/pcsx2/3rdparty/zlib/zconf.h b/pcsx2/3rdparty/zlib/zconf.h index e3b0c962e3..03a9431c8b 100644 --- a/pcsx2/3rdparty/zlib/zconf.h +++ b/pcsx2/3rdparty/zlib/zconf.h @@ -1,332 +1,332 @@ -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#ifndef ZCONF_H -#define ZCONF_H - -/* - * If you *really* need a unique prefix for all types and library functions, - * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. - */ -#ifdef Z_PREFIX -# define deflateInit_ z_deflateInit_ -# define deflate z_deflate -# define deflateEnd z_deflateEnd -# define inflateInit_ z_inflateInit_ -# define inflate z_inflate -# define inflateEnd z_inflateEnd -# define deflateInit2_ z_deflateInit2_ -# define deflateSetDictionary z_deflateSetDictionary -# define deflateCopy z_deflateCopy -# define deflateReset z_deflateReset -# define deflateParams z_deflateParams -# define deflateBound z_deflateBound -# define deflatePrime z_deflatePrime -# define inflateInit2_ z_inflateInit2_ -# define inflateSetDictionary z_inflateSetDictionary -# define inflateSync z_inflateSync -# define inflateSyncPoint z_inflateSyncPoint -# define inflateCopy z_inflateCopy -# define inflateReset z_inflateReset -# define inflateBack z_inflateBack -# define inflateBackEnd z_inflateBackEnd -# define compress z_compress -# define compress2 z_compress2 -# define compressBound z_compressBound -# define uncompress z_uncompress -# define adler32 z_adler32 -# define crc32 z_crc32 -# define get_crc_table z_get_crc_table -# define zError z_zError - -# define alloc_func z_alloc_func -# define free_func z_free_func -# define in_func z_in_func -# define out_func z_out_func -# define Byte z_Byte -# define uInt z_uInt -# define uLong z_uLong -# define Bytef z_Bytef -# define charf z_charf -# define intf z_intf -# define uIntf z_uIntf -# define uLongf z_uLongf -# define voidpf z_voidpf -# define voidp z_voidp -#endif - -#if defined(__MSDOS__) && !defined(MSDOS) -# define MSDOS -#endif -#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) -# define OS2 -#endif -#if defined(_WINDOWS) && !defined(WINDOWS) -# define WINDOWS -#endif -#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) -# ifndef WIN32 -# define WIN32 -# endif -#endif -#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) -# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) -# ifndef SYS16BIT -# define SYS16BIT -# endif -# endif -#endif - -/* - * Compile with -DMAXSEG_64K if the alloc function cannot allocate more - * than 64k bytes at a time (needed on systems with 16-bit int). - */ -#ifdef SYS16BIT -# define MAXSEG_64K -#endif -#ifdef MSDOS -# define UNALIGNED_OK -#endif - -#ifdef __STDC_VERSION__ -# ifndef STDC -# define STDC -# endif -# if __STDC_VERSION__ >= 199901L -# ifndef STDC99 -# define STDC99 -# endif -# endif -#endif -#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) -# define STDC -#endif -#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) -# define STDC -#endif -#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) -# define STDC -#endif -#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) -# define STDC -#endif - -#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ -# define STDC -#endif - -#ifndef STDC -# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ -# define const /* note: need a more gentle solution here */ -# endif -#endif - -/* Some Mac compilers merge all .h files incorrectly: */ -#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) -# define NO_DUMMY_DECL -#endif - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# ifdef MAXSEG_64K -# define MAX_MEM_LEVEL 8 -# else -# define MAX_MEM_LEVEL 9 -# endif -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2. - * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files - * created by gzip. (Files created by minigzip can still be extracted by - * gzip.) - */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - (1 << (windowBits+2)) + (1 << (memLevel+9)) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects. -*/ - - /* Type declarations */ - -#ifndef OF /* function prototypes */ -# ifdef STDC -# define OF(args) args -# else -# define OF(args) () -# endif -#endif - -/* The following definitions for FAR are needed only for MSDOS mixed - * model programming (small or medium model with some far allocations). - * This was tested only with MSC; for other MSDOS compilers you may have - * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, - * just define FAR to be empty. - */ -#ifdef SYS16BIT -# if defined(M_I86SM) || defined(M_I86MM) - /* MSC small or medium model */ -# define SMALL_MEDIUM -# ifdef _MSC_VER -# define FAR _far -# else -# define FAR far -# endif -# endif -# if (defined(__SMALL__) || defined(__MEDIUM__)) - /* Turbo C small or medium model */ -# define SMALL_MEDIUM -# ifdef __BORLANDC__ -# define FAR _far -# else -# define FAR far -# endif -# endif -#endif - -#if defined(WINDOWS) || defined(WIN32) - /* If building or using zlib as a DLL, define ZLIB_DLL. - * This is not mandatory, but it offers a little performance increase. - */ -# ifdef ZLIB_DLL -# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) -# ifdef ZLIB_INTERNAL -# define ZEXTERN extern __declspec(dllexport) -# else -# define ZEXTERN extern __declspec(dllimport) -# endif -# endif -# endif /* ZLIB_DLL */ - /* If building or using zlib with the WINAPI/WINAPIV calling convention, - * define ZLIB_WINAPI. - * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. - */ -# ifdef ZLIB_WINAPI -# ifdef FAR -# undef FAR -# endif -# include - /* No need for _export, use ZLIB.DEF instead. */ - /* For complete Windows compatibility, use WINAPI, not __stdcall. */ -# define ZEXPORT WINAPI -# ifdef WIN32 -# define ZEXPORTVA WINAPIV -# else -# define ZEXPORTVA FAR CDECL -# endif -# endif -#endif - -#if defined (__BEOS__) -# ifdef ZLIB_DLL -# ifdef ZLIB_INTERNAL -# define ZEXPORT __declspec(dllexport) -# define ZEXPORTVA __declspec(dllexport) -# else -# define ZEXPORT __declspec(dllimport) -# define ZEXPORTVA __declspec(dllimport) -# endif -# endif -#endif - -#ifndef ZEXTERN -# define ZEXTERN extern -#endif -#ifndef ZEXPORT -# define ZEXPORT -#endif -#ifndef ZEXPORTVA -# define ZEXPORTVA -#endif - -#ifndef FAR -# define FAR -#endif - -#if !defined(__MACTYPES__) -typedef unsigned char Byte; /* 8 bits */ -#endif -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ - -#ifdef SMALL_MEDIUM - /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ -# define Bytef Byte FAR -#else - typedef Byte FAR Bytef; -#endif -typedef char FAR charf; -typedef int FAR intf; -typedef uInt FAR uIntf; -typedef uLong FAR uLongf; - -#ifdef STDC - typedef void const *voidpc; - typedef void FAR *voidpf; - typedef void *voidp; -#else - typedef Byte const *voidpc; - typedef Byte FAR *voidpf; - typedef Byte *voidp; -#endif - -#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ -# include /* for off_t */ -# include /* for SEEK_* and off_t */ -# ifdef VMS -# include /* for off_t */ -# endif -# define z_off_t off_t -#endif -#ifndef SEEK_SET -# define SEEK_SET 0 /* Seek from beginning of file. */ -# define SEEK_CUR 1 /* Seek from current position. */ -# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ -#endif -#ifndef z_off_t -# define z_off_t long -#endif - -#if defined(__OS400__) -# define NO_vsnprintf -#endif - -#if defined(__MVS__) -# define NO_vsnprintf -# ifdef FAR -# undef FAR -# endif -#endif - -/* MVS linker does not support external names larger than 8 bytes */ -#if defined(__MVS__) -# pragma map(deflateInit_,"DEIN") -# pragma map(deflateInit2_,"DEIN2") -# pragma map(deflateEnd,"DEEND") -# pragma map(deflateBound,"DEBND") -# pragma map(inflateInit_,"ININ") -# pragma map(inflateInit2_,"ININ2") -# pragma map(inflateEnd,"INEND") -# pragma map(inflateSync,"INSY") -# pragma map(inflateSetDictionary,"INSEDI") -# pragma map(compressBound,"CMBND") -# pragma map(inflate_table,"INTABL") -# pragma map(inflate_fast,"INFA") -# pragma map(inflate_copyright,"INCOPY") -#endif - -#endif /* ZCONF_H */ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/pcsx2/3rdparty/zlib/zlib.h b/pcsx2/3rdparty/zlib/zlib.h index 62d0e4675b..022817927c 100644 --- a/pcsx2/3rdparty/zlib/zlib.h +++ b/pcsx2/3rdparty/zlib/zlib.h @@ -1,1357 +1,1357 @@ -/* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.3, July 18th, 2005 - - Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - - - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). -*/ - -#ifndef ZLIB_H -#define ZLIB_H - -#include "zconf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define ZLIB_VERSION "1.2.3" -#define ZLIB_VERNUM 0x1230 - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed - data. This version of the library supports only one compression method - (deflation) but other algorithms will be added later and will have the same - stream interface. - - Compression can be done in a single step if the buffers are large - enough (for example if an input file is mmap'ed), or can be done by - repeated calls of the compression function. In the latter case, the - application must provide more input and/or consume the output - (providing more output space) before each call. - - The compressed data format used by default by the in-memory functions is - the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped - around a deflate stream, which is itself documented in RFC 1951. - - The library also supports reading and writing files in gzip (.gz) format - with an interface similar to that of stdio using the functions that start - with "gz". The gzip format is different from the zlib format. gzip is a - gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. - - This library can optionally read and write gzip streams in memory as well. - - The zlib format was designed to be compact and fast for use in memory - and on communications channels. The gzip format was designed for single- - file compression on file systems, has a larger header than zlib to maintain - directory information, and uses a different, slower check method than zlib. - - The library does not install any signal handler. The decoder checks - the consistency of the compressed data, so the library should never - crash even in case of corrupted input. -*/ - -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address)); - -struct internal_state; - -typedef struct z_stream_s { - Bytef *next_in; /* next input byte */ - uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total nb of input bytes read so far */ - - Bytef *next_out; /* next output byte should be put there */ - uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total nb of bytes output so far */ - - char *msg; /* last error message, NULL if no error */ - struct internal_state FAR *state; /* not visible by applications */ - - alloc_func zalloc; /* used to allocate the internal state */ - free_func zfree; /* used to free the internal state */ - voidpf opaque; /* private data object passed to zalloc and zfree */ - - int data_type; /* best guess about the data type: binary or text */ - uLong adler; /* adler32 value of the uncompressed data */ - uLong reserved; /* reserved for future use */ -} z_stream; - -typedef z_stream FAR *z_streamp; - -/* - gzip header information passed to and from zlib routines. See RFC 1952 - for more details on the meanings of these fields. -*/ -typedef struct gz_header_s { - int text; /* true if compressed data believed to be text */ - uLong time; /* modification time */ - int xflags; /* extra flags (not used when writing a gzip file) */ - int os; /* operating system */ - Bytef *extra; /* pointer to extra field or Z_NULL if none */ - uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ - uInt extra_max; /* space at extra (only when reading header) */ - Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ - uInt name_max; /* space at name (only when reading header) */ - Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ - uInt comm_max; /* space at comment (only when reading header) */ - int hcrc; /* true if there was or will be a header crc */ - int done; /* true when done reading gzip header (not used - when writing a gzip file) */ -} gz_header; - -typedef gz_header FAR *gz_headerp; - -/* - The application must update next_in and avail_in when avail_in has - dropped to zero. It must update next_out and avail_out when avail_out - has dropped to zero. The application must initialize zalloc, zfree and - opaque before calling the init function. All other fields are set by the - compression library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - If zlib is used in a multi-threaded application, zalloc and zfree must be - thread safe. - - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this - if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, - pointers returned by zalloc for objects of exactly 65536 bytes *must* - have their offset normalized to zero. The default allocation function - provided by this library ensures this (see zutil.c). To reduce memory - requirements and avoid any allocation of 64K objects, at the expense of - compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or - progress reports. After compression, total_in holds the total size of - the uncompressed data and may be saved for use in the decompressor - (particularly if the decompressor wants to decompress everything in - a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ -#define Z_SYNC_FLUSH 2 -#define Z_FULL_FLUSH 3 -#define Z_FINISH 4 -#define Z_BLOCK 5 -/* Allowed flush values; see deflate() and inflate() below for details */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_NEED_DICT 2 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -#define Z_VERSION_ERROR (-6) -/* Return codes for the compression/decompression functions. Negative - * values are errors, positive values are used for special but normal events. - */ - -#define Z_NO_COMPRESSION 0 -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_RLE 3 -#define Z_FIXED 4 -#define Z_DEFAULT_STRATEGY 0 -/* compression strategy; see deflateInit2() below for details */ - -#define Z_BINARY 0 -#define Z_TEXT 1 -#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ -#define Z_UNKNOWN 2 -/* Possible values of the data_type field (though see inflate()) */ - -#define Z_DEFLATED 8 -/* The deflate compression method (the only one supported in this version) */ - -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - -#define zlib_version zlibVersion() -/* for compatibility with versions < 1.0.2 */ - - /* basic functions */ - -ZEXTERN const char * ZEXPORT zlibVersion OF((void)); -/* The application can compare zlibVersion and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is - not compatible with the zlib.h header file used by the application. - This check is automatically made by deflateInit and inflateInit. - */ - -/* -ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); - - Initializes the internal stream state for compression. The fields - zalloc, zfree and opaque must be initialized before by the caller. - If zalloc and zfree are set to Z_NULL, deflateInit updates them to - use default allocation functions. - - The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: - 1 gives best speed, 9 gives best compression, 0 gives no compression at - all (the input data is simply copied a block at a time). - Z_DEFAULT_COMPRESSION requests a default compromise between speed and - compression (currently equivalent to level 6). - - deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if level is not a valid compression level, - Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible - with the version assumed by the caller (ZLIB_VERSION). - msg is set to null if there is no error message. deflateInit does not - perform any compression: this will be done by deflate(). -*/ - - -ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); -/* - deflate compresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce some - output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. deflate performs one or both of the - following actions: - - - Compress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in and avail_in are updated and - processing will resume at this point for the next call of deflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. This action is forced if the parameter flush is non zero. - Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary (in interactive applications). - Some output may be provided even if flush is not set. - - Before the call of deflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating avail_in or avail_out accordingly; avail_out - should never be zero before the call. The application can consume the - compressed output when it wants, for example when the output buffer is full - (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK - and with zero avail_out, it must be called again after making room in the - output buffer because there might be more output pending. - - Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to - decide how much data to accumualte before producing output, in order to - maximize compression. - - If the parameter flush is set to Z_SYNC_FLUSH, all pending output is - flushed to the output buffer and the output is aligned on a byte boundary, so - that the decompressor can get all input data available so far. (In particular - avail_in is zero after the call if enough output space has been provided - before the call.) Flushing may degrade compression for some compression - algorithms and so it should be used only when necessary. - - If flush is set to Z_FULL_FLUSH, all output is flushed as with - Z_SYNC_FLUSH, and the compression state is reset so that decompression can - restart from this point if previous compressed data has been damaged or if - random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - compression. - - If deflate returns with avail_out == 0, this function must be called again - with the same value of the flush parameter and more output space (updated - avail_out), until the flush is complete (deflate returns with non-zero - avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that - avail_out is greater than six to avoid repeated flush markers due to - avail_out == 0 on return. - - If the parameter flush is set to Z_FINISH, pending input is processed, - pending output is flushed and deflate returns with Z_STREAM_END if there - was enough output space; if deflate returns with Z_OK, this function must be - called again with Z_FINISH and more output space (updated avail_out) but no - more input data, until it returns with Z_STREAM_END or an error. After - deflate has returned Z_STREAM_END, the only possible operations on the - stream are deflateReset or deflateEnd. - - Z_FINISH can be used immediately after deflateInit if all the compression - is to be done in a single step. In this case, avail_out must be at least - the value returned by deflateBound (see below). If deflate does not return - Z_STREAM_END, then it must be called again as described above. - - deflate() sets strm->adler to the adler32 checksum of all input read - so far (that is, total_in bytes). - - deflate() may update strm->data_type if it can make a good guess about - the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered - binary. This field is only for information purposes and does not affect - the compression algorithm in any manner. - - deflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if all input has been - consumed and all output has been produced (only when flush is set to - Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible - (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not - fatal, and deflate() can be called again with more input and more output - space to continue compressing. -*/ - - -ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the - stream state was inconsistent, Z_DATA_ERROR if the stream was freed - prematurely (some input or output was discarded). In the error case, - msg may be set but then points to a static string (which must not be - deallocated). -*/ - - -/* -ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); - - Initializes the internal stream state for decompression. The fields - next_in, avail_in, zalloc, zfree and opaque must be initialized before by - the caller. If next_in is not Z_NULL and avail_in is large enough (the exact - value depends on the compression method), inflateInit determines the - compression method from the zlib header and allocates all data structures - accordingly; otherwise the allocation will be deferred to the first call of - inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to - use default allocation functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller. msg is set to null if there is no error - message. inflateInit does not perform any decompression apart from reading - the zlib header if present: this will be done by inflate(). (So next_in and - avail_in may be modified, but next_out and avail_out are unchanged.) -*/ - - -ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); -/* - inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce - some output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. inflate performs one or both of the - following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing - will resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() provides as much output as possible, until there - is no more input data or no more space in the output buffer (see below - about the flush parameter). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating the next_* and avail_* values accordingly. - The application can consume the uncompressed output when it wants, for - example when the output buffer is full (avail_out == 0), or after each - call of inflate(). If inflate returns Z_OK and with zero avail_out, it - must be called again after making room in the output buffer because there - might be more output pending. - - The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, - Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much - output as possible to the output buffer. Z_BLOCK requests that inflate() stop - if and when it gets to the next deflate block boundary. When decoding the - zlib or gzip format, this will cause inflate() to return immediately after - the header and before the first block. When doing a raw inflate, inflate() - will go ahead and process the first block, and will return when it gets to - the end of that block, or when it runs out of data. - - The Z_BLOCK option assists in appending to or combining deflate streams. - Also to assist in this, on return inflate() will set strm->data_type to the - number of unused bits in the last byte taken from strm->next_in, plus 64 - if inflate() is currently decoding the last block in the deflate stream, - plus 128 if inflate() returned immediately after decoding an end-of-block - code or decoding the complete header up to just before the first byte of the - deflate stream. The end-of-block will not be indicated until all of the - uncompressed data from that block has been written to strm->next_out. The - number of unused bits may in general be greater than seven, except when - bit 7 of data_type is set, in which case the number of unused bits will be - less than eight. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step - (a single call of inflate), the parameter flush should be set to - Z_FINISH. In this case all pending input is processed and all pending - output is flushed; avail_out must be large enough to hold all the - uncompressed data. (The size of the uncompressed data may have been saved - by the compressor for this purpose.) The next operation on this stream must - be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster approach - may be used for the single inflate() call. - - In this implementation, inflate() always flushes as much output as - possible to the output buffer, and always uses the faster approach on the - first call. So the only effect of the flush parameter in this implementation - is on the return value of inflate(), as noted below, or when it returns early - because Z_BLOCK is used. - - If a preset dictionary is needed after this call (see inflateSetDictionary - below), inflate sets strm->adler to the adler32 checksum of the dictionary - chosen by the compressor and returns Z_NEED_DICT; otherwise it sets - strm->adler to the adler32 checksum of all output produced so far (that is, - total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described - below. At the end of the stream, inflate() checks that its computed adler32 - checksum is equal to that saved by the compressor and returns Z_STREAM_END - only if the checksum is correct. - - inflate() will decompress and check either zlib-wrapped or gzip-wrapped - deflate data. The header type is detected automatically. Any information - contained in the gzip header is not retained, so applications that need that - information should instead use raw inflate, see inflateInit2() below, or - inflateBack() and perform their own processing of the gzip header and - trailer. - - inflate() returns Z_OK if some progress has been made (more input processed - or more output produced), Z_STREAM_END if the end of the compressed data has - been reached and all uncompressed output has been produced, Z_NEED_DICT if a - preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect check - value), Z_STREAM_ERROR if the stream structure was inconsistent (for example - if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, - Z_BUF_ERROR if no progress is possible or if there was not enough room in the - output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and - inflate() can be called again with more input and more output space to - continue decompressing. If Z_DATA_ERROR is returned, the application may then - call inflateSync() to look for a good compression block if a partial recovery - of the data is desired. -*/ - - -ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). -*/ - - /* Advanced functions */ - -/* - The following functions are needed only in some special applications. -*/ - -/* -ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); - - This is another version of deflateInit with more compression options. The - fields next_in, zalloc, zfree and opaque must be initialized before by - the caller. - - The method parameter is the compression method. It must be Z_DEFLATED in - this version of the library. - - The windowBits parameter is the base two logarithm of the window size - (the size of the history buffer). It should be in the range 8..15 for this - version of the library. Larger values of this parameter result in better - compression at the expense of memory usage. The default value is 15 if - deflateInit is used instead. - - windowBits can also be -8..-15 for raw deflate. In this case, -windowBits - determines the window size. deflate() will then generate raw deflate data - with no zlib header or trailer, and will not compute an adler32 check value. - - windowBits can also be greater than 15 for optional gzip encoding. Add - 16 to windowBits to write a simple gzip header and trailer around the - compressed data instead of a zlib wrapper. The gzip header will have no - file name, no extra data, no comment, no modification time (set to zero), - no header crc, and the operating system will be set to 255 (unknown). If a - gzip stream is being written, strm->adler is a crc32 instead of an adler32. - - The memLevel parameter specifies how much memory should be allocated - for the internal compression state. memLevel=1 uses minimum memory but - is slow and reduces compression ratio; memLevel=9 uses maximum memory - for optimal speed. The default value is 8. See zconf.h for total memory - usage as a function of windowBits and memLevel. - - The strategy parameter is used to tune the compression algorithm. Use the - value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match), or Z_RLE to limit match distances to one (run-length - encoding). Filtered data consists mostly of small values with a somewhat - random distribution. In this case, the compression algorithm is tuned to - compress them better. The effect of Z_FILTERED is to force more Huffman - coding and less string matching; it is somewhat intermediate between - Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as - Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy - parameter only affects the compression ratio but not the correctness of the - compressed output even if it is not set appropriately. Z_FIXED prevents the - use of dynamic Huffman codes, allowing for a simpler decoder for special - applications. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid - method). msg is set to null if there is no error message. deflateInit2 does - not perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the compression dictionary from the given byte sequence - without producing any compressed output. This function must be called - immediately after deflateInit, deflateInit2 or deflateReset, before any - call of deflate. The compressor and decompressor must use exactly the same - dictionary (see inflateSetDictionary). - - The dictionary should consist of strings (byte sequences) that are likely - to be encountered later in the data to be compressed, with the most commonly - used strings preferably put towards the end of the dictionary. Using a - dictionary is most useful when the data to be compressed is short and can be - predicted with good accuracy; the data can then be compressed better than - with the default empty dictionary. - - Depending on the size of the compression data structures selected by - deflateInit or deflateInit2, a part of the dictionary may in effect be - discarded, for example if the dictionary is larger than the window size in - deflate or deflate2. Thus the strings most likely to be useful should be - put at the end of the dictionary, not at the front. In addition, the - current implementation of deflate will use at most the window size minus - 262 bytes of the provided dictionary. - - Upon return of this function, strm->adler is set to the adler32 value - of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The adler32 value - applies to the whole dictionary even if only a subset of the dictionary is - actually used by the compressor.) If a raw deflate was requested, then the - adler32 value is not computed and strm->adler is not set. - - deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent (for example if deflate has already been called for this stream - or if the compression method is bsort). deflateSetDictionary does not - perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when several compression strategies will be - tried, for example when there are several ways of pre-processing the input - data with a filter. The streams that will be discarded should then be freed - by calling deflateEnd. Note that deflateCopy duplicates the internal - compression state which can be quite large, so this strategy is slow and - can consume lots of memory. - - deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); -/* - This function is equivalent to deflateEnd followed by deflateInit, - but does not free and reallocate all the internal compression state. - The stream will keep the same compression level and any other attributes - that may have been set by deflateInit2. - - deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, - int level, - int strategy)); -/* - Dynamically update the compression level and compression strategy. The - interpretation of level and strategy is as in deflateInit2. This can be - used to switch between compression and straight copy of the input data, or - to switch to a different kind of input data requiring a different - strategy. If the compression level is changed, the input available so far - is compressed with the old level (and may be flushed); the new level will - take effect only at the next call of deflate(). - - Before the call of deflateParams, the stream state must be set as for - a call of deflate(), since the currently available input may have to - be compressed and flushed. In particular, strm->avail_out must be non-zero. - - deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source - stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR - if strm->avail_out was zero. -*/ - -ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, - int good_length, - int max_lazy, - int nice_length, - int max_chain)); -/* - Fine tune deflate's internal compression parameters. This should only be - used by someone who understands the algorithm used by zlib's deflate for - searching for the best matching string, and even then only by the most - fanatic optimizer trying to squeeze out the last compressed bit for their - specific input data. Read the deflate.c source code for the meaning of the - max_lazy, good_length, nice_length, and max_chain parameters. - - deflateTune() can be called after deflateInit() or deflateInit2(), and - returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. - */ - -ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, - uLong sourceLen)); -/* - deflateBound() returns an upper bound on the compressed size after - deflation of sourceLen bytes. It must be called after deflateInit() - or deflateInit2(). This would be used to allocate an output buffer - for deflation in a single pass, and so would be called before deflate(). -*/ - -ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - deflatePrime() inserts bits in the deflate output stream. The intent - is that this function is used to start off the deflate output with the - bits leftover from a previous deflate stream when appending to it. As such, - this function can only be used for raw deflate, and must be used before the - first deflate() call after a deflateInit2() or deflateReset(). bits must be - less than or equal to 16, and that many of the least significant bits of - value will be inserted in the output. - - deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, - gz_headerp head)); -/* - deflateSetHeader() provides gzip header information for when a gzip - stream is requested by deflateInit2(). deflateSetHeader() may be called - after deflateInit2() or deflateReset() and before the first call of - deflate(). The text, time, os, extra field, name, and comment information - in the provided gz_header structure are written to the gzip header (xflag is - ignored -- the extra flags are set according to the compression level). The - caller must assure that, if not Z_NULL, name and comment are terminated with - a zero byte, and that if extra is not Z_NULL, that extra_len bytes are - available there. If hcrc is true, a gzip header crc is included. Note that - the current versions of the command-line version of gzip (up through version - 1.3.x) do not support header crc's, and will report that it is a "multi-part - gzip file" and give up. - - If deflateSetHeader is not used, the default gzip header has text false, - the time set to zero, and os set to 255, with no extra, name, or comment - fields. The gzip header is returned to the default state by deflateReset(). - - deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, - int windowBits)); - - This is another version of inflateInit with an extra parameter. The - fields next_in, avail_in, zalloc, zfree and opaque must be initialized - before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library. The default value is 15 if inflateInit is used - instead. windowBits must be greater than or equal to the windowBits value - provided to deflateInit2() while compressing, or it must be equal to 15 if - deflateInit2() was not used. If a compressed stream with a larger window - size is given as input, inflate() will return with the error code - Z_DATA_ERROR instead of trying to allocate a larger window. - - windowBits can also be -8..-15 for raw inflate. In this case, -windowBits - determines the window size. inflate() will then process raw deflate data, - not looking for a zlib or gzip header, not generating a check value, and not - looking for any check values for comparison at the end of the stream. This - is for use with other formats that use the deflate compressed data format - such as zip. Those formats provide their own check values. If a custom - format is developed using the raw deflate format for compressed data, it is - recommended that a check value such as an adler32 or a crc32 be applied to - the uncompressed data as is done in the zlib, gzip, and zip formats. For - most applications, the zlib format should be used as is. Note that comments - above on the use in deflateInit2() applies to the magnitude of windowBits. - - windowBits can also be greater than 15 for optional gzip decoding. Add - 32 to windowBits to enable zlib and gzip decoding with automatic header - detection, or add 16 to decode only the gzip format (the zlib format will - return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is - a crc32 instead of an adler32. - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg - is set to null if there is no error message. inflateInit2 does not perform - any decompression apart from reading the zlib header if present: this will - be done by inflate(). (So next_in and avail_in may be modified, but next_out - and avail_out are unchanged.) -*/ - -ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate, - if that call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the adler32 value returned by that call of inflate. - The compressor and decompressor must use exactly the same dictionary (see - deflateSetDictionary). For raw inflate, this function can be called - immediately after inflateInit2() or inflateReset() and before any call of - inflate() to set the dictionary. The application must insure that the - dictionary that was used for compression is provided. - - inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect adler32 value). inflateSetDictionary does not - perform any decompression: this will be done by subsequent calls of - inflate(). -*/ - -ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); -/* - Skips invalid compressed data until a full flush point (see above the - description of deflate with Z_FULL_FLUSH) can be found, or until all - available input is skipped. No output is provided. - - inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR - if no more input was provided, Z_DATA_ERROR if no flush point has been found, - or Z_STREAM_ERROR if the stream structure was inconsistent. In the success - case, the application may save the current current value of total_in which - indicates where valid compressed data was found. In the error case, the - application may repeatedly call inflateSync, providing more input each time, - until success or end of the input data. -*/ - -ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when randomly accessing a large stream. The - first pass through the stream can periodically record the inflate state, - allowing restarting inflate at those points when randomly accessing the - stream. - - inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); -/* - This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate all the internal decompression state. - The stream will keep attributes that may have been set by inflateInit2. - - inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - This function inserts bits in the inflate input stream. The intent is - that this function is used to start inflating at a bit position in the - middle of a byte. The provided bits will be used before any bytes are used - from next_in. This function should only be used with raw inflate, and - should be used before the first inflate() call after inflateInit2() or - inflateReset(). bits must be less than or equal to 16, and that many of the - least significant bits of value will be inserted in the input. - - inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, - gz_headerp head)); -/* - inflateGetHeader() requests that gzip header information be stored in the - provided gz_header structure. inflateGetHeader() may be called after - inflateInit2() or inflateReset(), and before the first call of inflate(). - As inflate() processes the gzip stream, head->done is zero until the header - is completed, at which time head->done is set to one. If a zlib stream is - being decoded, then head->done is set to -1 to indicate that there will be - no gzip header information forthcoming. Note that Z_BLOCK can be used to - force inflate() to return immediately after header processing is complete - and before any actual data is decompressed. - - The text, time, xflags, and os fields are filled in with the gzip header - contents. hcrc is set to true if there is a header CRC. (The header CRC - was valid if done is set to one.) If extra is not Z_NULL, then extra_max - contains the maximum number of bytes to write to extra. Once done is true, - extra_len contains the actual extra field length, and extra contains the - extra field, or that field truncated if extra_max is less than extra_len. - If name is not Z_NULL, then up to name_max characters are written there, - terminated with a zero unless the length is greater than name_max. If - comment is not Z_NULL, then up to comm_max characters are written there, - terminated with a zero unless the length is greater than comm_max. When - any of extra, name, or comment are not Z_NULL and the respective field is - not present in the header, then that field is set to Z_NULL to signal its - absence. This allows the use of deflateSetHeader() with the returned - structure to duplicate the header. However if those fields are set to - allocated memory, then the application will need to save those pointers - elsewhere so that they can be eventually freed. - - If inflateGetHeader is not used, then the header information is simply - discarded. The header is always checked for validity, including the header - CRC if present. inflateReset() will reset the process to discard the header - information. The application would need to call inflateGetHeader() again to - retrieve the header from the next gzip stream. - - inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, - unsigned char FAR *window)); - - Initialize the internal stream state for decompression using inflateBack() - calls. The fields zalloc, zfree and opaque in strm must be initialized - before the call. If zalloc and zfree are Z_NULL, then the default library- - derived memory allocation routines are used. windowBits is the base two - logarithm of the window size, in the range 8..15. window is a caller - supplied buffer of that size. Except for special applications where it is - assured that deflate was used with small window sizes, windowBits must be 15 - and a 32K byte window must be supplied to be able to decompress general - deflate streams. - - See inflateBack() for the usage of these routines. - - inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of - the paramaters are invalid, Z_MEM_ERROR if the internal state could not - be allocated, or Z_VERSION_ERROR if the version of the library does not - match the version of the header file. -*/ - -typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); -typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); - -ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, - in_func in, void FAR *in_desc, - out_func out, void FAR *out_desc)); -/* - inflateBack() does a raw inflate with a single call using a call-back - interface for input and output. This is more efficient than inflate() for - file i/o applications in that it avoids copying between the output and the - sliding window by simply making the window itself the output buffer. This - function trusts the application to not change the output buffer passed by - the output function, at least until inflateBack() returns. - - inflateBackInit() must be called first to allocate the internal state - and to initialize the state with the user-provided window buffer. - inflateBack() may then be used multiple times to inflate a complete, raw - deflate stream with each call. inflateBackEnd() is then called to free - the allocated state. - - A raw deflate stream is one with no zlib or gzip header or trailer. - This routine would normally be used in a utility that reads zip or gzip - files and writes out uncompressed files. The utility would decode the - header and process the trailer on its own, hence this routine expects - only the raw deflate stream to decompress. This is different from the - normal behavior of inflate(), which expects either a zlib or gzip header and - trailer around the deflate stream. - - inflateBack() uses two subroutines supplied by the caller that are then - called by inflateBack() for input and output. inflateBack() calls those - routines until it reads a complete deflate stream and writes out all of the - uncompressed data, or until it encounters an error. The function's - parameters and return types are defined above in the in_func and out_func - typedefs. inflateBack() will call in(in_desc, &buf) which should return the - number of bytes of provided input, and a pointer to that input in buf. If - there is no input available, in() must return zero--buf is ignored in that - case--and inflateBack() will return a buffer error. inflateBack() will call - out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() - should return zero on success, or non-zero on failure. If out() returns - non-zero, inflateBack() will return with an error. Neither in() nor out() - are permitted to change the contents of the window provided to - inflateBackInit(), which is also the buffer that out() uses to write from. - The length written by out() will be at most the window size. Any non-zero - amount of input may be provided by in(). - - For convenience, inflateBack() can be provided input on the first call by - setting strm->next_in and strm->avail_in. If that input is exhausted, then - in() will be called. Therefore strm->next_in must be initialized before - calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called - immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in - must also be initialized, and then if strm->avail_in is not zero, input will - initially be taken from strm->next_in[0 .. strm->avail_in - 1]. - - The in_desc and out_desc parameters of inflateBack() is passed as the - first parameter of in() and out() respectively when they are called. These - descriptors can be optionally used to pass any information that the caller- - supplied in() and out() functions need to do their job. - - On return, inflateBack() will set strm->next_in and strm->avail_in to - pass back any unused input that was provided by the last in() call. The - return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR - if in() or out() returned an error, Z_DATA_ERROR if there was a format - error in the deflate stream (in which case strm->msg is set to indicate the - nature of the error), or Z_STREAM_ERROR if the stream was not properly - initialized. In the case of Z_BUF_ERROR, an input or output error can be - distinguished using strm->next_in which will be Z_NULL only if in() returned - an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to - out() returning non-zero. (in() will always be called before out(), so - strm->next_in is assured to be defined if out() returns non-zero.) Note - that inflateBack() cannot return Z_OK. -*/ - -ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); -/* - All memory allocated by inflateBackInit() is freed. - - inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream - state was inconsistent. -*/ - -ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); -/* Return flags indicating compile-time options. - - Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: - 1.0: size of uInt - 3.2: size of uLong - 5.4: size of voidpf (pointer) - 7.6: size of z_off_t - - Compiler, assembler, and debug options: - 8: DEBUG - 9: ASMV or ASMINF -- use ASM code - 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention - 11: 0 (reserved) - - One-time table building (smaller code, but not thread-safe if true): - 12: BUILDFIXED -- build static block decoding tables when needed - 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed - 14,15: 0 (reserved) - - Library content (indicates missing functionality): - 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking - deflate code when not needed) - 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect - and decode gzip streams (to avoid linking crc code) - 18-19: 0 (reserved) - - Operation variations (changes in library functionality): - 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate - 21: FASTEST -- deflate algorithm with only one, lowest compression level - 22,23: 0 (reserved) - - The sprintf variant used by gzprintf (zero is best): - 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format - 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! - 26: 0 = returns value, 1 = void -- 1 means inferred string length returned - - Remainder: - 27-31: 0 (reserved) - */ - - - /* utility functions */ - -/* - The following utility functions are implemented on top of the - basic stream-oriented functions. To simplify the interface, some - default options are assumed (compression level and memory usage, - standard memory allocation functions). The source code of these - utility functions can easily be modified if you need special options. -*/ - -ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Compresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be at least the value returned - by compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - This function can be used to compress a whole file at once if the - input file is mmap'ed. - compress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer. -*/ - -ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen, - int level)); -/* - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least the value returned by - compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ - -ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); -/* - compressBound() returns an upper bound on the compressed size after - compress() or compress2() on sourceLen bytes. It would be used before - a compress() or compress2() call to allocate the destination buffer. -*/ - -ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. -*/ - - -typedef voidp gzFile; - -ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); -/* - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb") but can also include a compression level - ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for - Huffman only compression as in "wb1h", or 'R' for run-length encoding - as in "wb1R". (See the description of deflateInit2 for more information - about the strategy parameter.) - - gzopen can be used to read a file which is not in gzip format; in this - case gzread will directly read from the file without decompression. - - gzopen returns NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). */ - -ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); -/* - gzdopen() associates a gzFile with the file descriptor fd. File - descriptors are obtained from calls like open, dup, creat, pipe or - fileno (in the file has been previously opened with fopen). - The mode parameter is as in gzopen. - The next call of gzclose on the returned gzFile will also close the - file descriptor fd, just like fclose(fdopen(fd), mode) closes the file - descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). - gzdopen returns NULL if there was insufficient memory to allocate - the (de)compression state. -*/ - -ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); -/* - Dynamically update the compression level or strategy. See the description - of deflateInit2 for the meaning of these parameters. - gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not - opened for writing. -*/ - -ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); -/* - Reads the given number of uncompressed bytes from the compressed file. - If the input file was not in gzip format, gzread copies the given number - of bytes into the buffer. - gzread returns the number of uncompressed bytes actually read (0 for - end of file, -1 for error). */ - -ZEXTERN int ZEXPORT gzwrite OF((gzFile file, - voidpc buf, unsigned len)); -/* - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of uncompressed bytes actually written - (0 in case of error). -*/ - -ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); -/* - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). The number of - uncompressed bytes written is limited to 4095. The caller should assure that - this limit is not exceeded. If it is exceeded, then gzprintf() will return - return an error (0) with nothing written. In this case, there may also be a - buffer overflow with unpredictable consequences, which is possible only if - zlib was compiled with the insecure functions sprintf() or vsprintf() - because the secure snprintf() or vsnprintf() functions were not available. -*/ - -ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); -/* - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. -*/ - -ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); -/* - Reads bytes from the compressed file until len-1 characters are read, or - a newline character is read and transferred to buf, or an end-of-file - condition is encountered. The string is then terminated with a null - character. - gzgets returns buf, or Z_NULL in case of error. -*/ - -ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); -/* - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. -*/ - -ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); -/* - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. -*/ - -ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); -/* - Push one character back onto the stream to be read again later. - Only one character of push-back is allowed. gzungetc() returns the - character pushed, or -1 on failure. gzungetc() will fail if a - character has been pushed but not read yet, or if c is -1. The pushed - character will be discarded if the stream is repositioned with gzseek() - or gzrewind(). -*/ - -ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); -/* - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. The return value is the zlib - error number (see function gzerror below). gzflush returns Z_OK if - the flush parameter is Z_FINISH and all output could be flushed. - gzflush should be called only when strictly necessary because it can - degrade compression. -*/ - -ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, - z_off_t offset, int whence)); -/* - Sets the starting position for the next gzread or gzwrite on the - given compressed file. The offset represents a number of bytes in the - uncompressed data stream. The whence parameter is defined as in lseek(2); - the value SEEK_END is not supported. - If the file is opened for reading, this function is emulated but can be - extremely slow. If the file is opened for writing, only forward seeks are - supported; gzseek then compresses a sequence of zeroes up to the new - starting position. - - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error, in - particular if the file is opened for writing and the new starting position - would be before the current position. -*/ - -ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); -/* - Rewinds the given file. This function is supported only for reading. - - gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) -*/ - -ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); -/* - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. - - gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) -*/ - -ZEXTERN int ZEXPORT gzeof OF((gzFile file)); -/* - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. -*/ - -ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); -/* - Returns 1 if file is being read directly without decompression, otherwise - zero. -*/ - -ZEXTERN int ZEXPORT gzclose OF((gzFile file)); -/* - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. The return value is the zlib - error number (see function gzerror below). -*/ - -ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); -/* - Returns the error message for the last error which occurred on the - given compressed file. errnum is set to zlib error number. If an - error occurred in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. -*/ - -ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); -/* - Clears the error and end-of-file flags for file. This is analogous to the - clearerr() function in stdio. This is useful for continuing to read a gzip - file that is being written concurrently. -*/ - - /* checksum functions */ - -/* - These functions are not related to compression but are exported - anyway because they might be useful in applications using the - compression library. -*/ - -ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); -/* - Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. If buf is NULL, this function returns - the required initial value for the checksum. - An Adler-32 checksum is almost as reliable as a CRC32 but can be computed - much faster. Usage example: - - uLong adler = adler32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - adler = adler32(adler, buffer, length); - } - if (adler != original_adler) error(); -*/ - -ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, - z_off_t len2)); -/* - Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 - and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for - each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of - seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. -*/ - -ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); -/* - Update a running CRC-32 with the bytes buf[0..len-1] and return the - updated CRC-32. If buf is NULL, this function returns the required initial - value for the for the crc. Pre- and post-conditioning (one's complement) is - performed within this function so it shouldn't be done by the application. - Usage example: - - uLong crc = crc32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - crc = crc32(crc, buffer, length); - } - if (crc != original_crc) error(); -*/ - -ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); - -/* - Combine two CRC-32 check values into one. For two sequences of bytes, - seq1 and seq2 with lengths len1 and len2, CRC-32 check values were - calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 - check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and - len2. -*/ - - - /* various hacks, don't look :) */ - -/* deflateInit and inflateInit are macros to allow checking the zlib version - * and the compiler's view of z_stream: - */ -ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy, const char *version, - int stream_size)); -ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, - unsigned char FAR *window, - const char *version, - int stream_size)); -#define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) -#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) -#define inflateBackInit(strm, windowBits, window) \ - inflateBackInit_((strm), (windowBits), (window), \ - ZLIB_VERSION, sizeof(z_stream)) - - -#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) - struct internal_state {int dummy;}; /* hack for buggy compilers */ -#endif - -ZEXTERN const char * ZEXPORT zError OF((int)); -ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); -ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); - -#ifdef __cplusplus -} -#endif - -#endif /* ZLIB_H */ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/pcsx2/3rdparty/zlib/zutil.c b/pcsx2/3rdparty/zlib/zutil.c index 0f4bd7871d..d55f5948a3 100644 --- a/pcsx2/3rdparty/zlib/zutil.c +++ b/pcsx2/3rdparty/zlib/zutil.c @@ -1,318 +1,318 @@ -/* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#include "zutil.h" - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -const char * const z_errmsg[10] = { -"need dictionary", /* Z_NEED_DICT 2 */ -"stream end", /* Z_STREAM_END 1 */ -"", /* Z_OK 0 */ -"file error", /* Z_ERRNO (-1) */ -"stream error", /* Z_STREAM_ERROR (-2) */ -"data error", /* Z_DATA_ERROR (-3) */ -"insufficient memory", /* Z_MEM_ERROR (-4) */ -"buffer error", /* Z_BUF_ERROR (-5) */ -"incompatible version",/* Z_VERSION_ERROR (-6) */ -""}; - - -const char * ZEXPORT zlibVersion() -{ - return ZLIB_VERSION; -} - -uLong ZEXPORT zlibCompileFlags() -{ - uLong flags; - - flags = 0; - switch (sizeof(uInt)) { - case 2: break; - case 4: flags += 1; break; - case 8: flags += 2; break; - default: flags += 3; - } - switch (sizeof(uLong)) { - case 2: break; - case 4: flags += 1 << 2; break; - case 8: flags += 2 << 2; break; - default: flags += 3 << 2; - } - switch (sizeof(voidpf)) { - case 2: break; - case 4: flags += 1 << 4; break; - case 8: flags += 2 << 4; break; - default: flags += 3 << 4; - } - switch (sizeof(z_off_t)) { - case 2: break; - case 4: flags += 1 << 6; break; - case 8: flags += 2 << 6; break; - default: flags += 3 << 6; - } -#ifdef DEBUG - flags += 1 << 8; -#endif -#if defined(ASMV) || defined(ASMINF) - flags += 1 << 9; -#endif -#ifdef ZLIB_WINAPI - flags += 1 << 10; -#endif -#ifdef BUILDFIXED - flags += 1 << 12; -#endif -#ifdef DYNAMIC_CRC_TABLE - flags += 1 << 13; -#endif -#ifdef NO_GZCOMPRESS - flags += 1L << 16; -#endif -#ifdef NO_GZIP - flags += 1L << 17; -#endif -#ifdef PKZIP_BUG_WORKAROUND - flags += 1L << 20; -#endif -#ifdef FASTEST - flags += 1L << 21; -#endif -#ifdef STDC -# ifdef NO_vsnprintf - flags += 1L << 25; -# ifdef HAS_vsprintf_void - flags += 1L << 26; -# endif -# else -# ifdef HAS_vsnprintf_void - flags += 1L << 26; -# endif -# endif -#else - flags += 1L << 24; -# ifdef NO_snprintf - flags += 1L << 25; -# ifdef HAS_sprintf_void - flags += 1L << 26; -# endif -# else -# ifdef HAS_snprintf_void - flags += 1L << 26; -# endif -# endif -#endif - return flags; -} - -#ifdef DEBUG - -# ifndef verbose -# define verbose 0 -# endif -int z_verbose = verbose; - -void z_error (m) - char *m; -{ - fprintf(stderr, "%s\n", m); - exit(1); -} -#endif - -/* exported to allow conversion of error code to string for compress() and - * uncompress() - */ -const char * ZEXPORT zError(err) - int err; -{ - return ERR_MSG(err); -} - -#if defined(_WIN32_WCE) - /* The Microsoft C Run-Time Library for Windows CE doesn't have - * errno. We define it as a global variable to simplify porting. - * Its value is always 0 and should not be used. - */ - int errno = 0; -#endif - -#ifndef HAVE_MEMCPY - -void zmemcpy(dest, source, len) - Bytef* dest; - const Bytef* source; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = *source++; /* ??? to be unrolled */ - } while (--len != 0); -} - -int zmemcmp(s1, s2, len) - const Bytef* s1; - const Bytef* s2; - uInt len; -{ - uInt j; - - for (j = 0; j < len; j++) { - if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; - } - return 0; -} - -void zmemzero(dest, len) - Bytef* dest; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = 0; /* ??? to be unrolled */ - } while (--len != 0); -} -#endif - - -#ifdef SYS16BIT - -#ifdef __TURBOC__ -/* Turbo C in 16-bit mode */ - -# define MY_ZCALLOC - -/* Turbo C malloc() does not allow dynamic allocation of 64K bytes - * and farmalloc(64K) returns a pointer with an offset of 8, so we - * must fix the pointer. Warning: the pointer must be put back to its - * original form in order to free it, use zcfree(). - */ - -#define MAX_PTR 10 -/* 10*64K = 640K */ - -local int next_ptr = 0; - -typedef struct ptr_table_s { - voidpf org_ptr; - voidpf new_ptr; -} ptr_table; - -local ptr_table table[MAX_PTR]; -/* This table is used to remember the original form of pointers - * to large buffers (64K). Such pointers are normalized with a zero offset. - * Since MSDOS is not a preemptive multitasking OS, this table is not - * protected from concurrent access. This hack doesn't work anyway on - * a protected system like OS/2. Use Microsoft C instead. - */ - -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - voidpf buf = opaque; /* just to make some compilers happy */ - ulg bsize = (ulg)items*size; - - /* If we allocate less than 65520 bytes, we assume that farmalloc - * will return a usable pointer which doesn't have to be normalized. - */ - if (bsize < 65520L) { - buf = farmalloc(bsize); - if (*(ush*)&buf != 0) return buf; - } else { - buf = farmalloc(bsize + 16L); - } - if (buf == NULL || next_ptr >= MAX_PTR) return NULL; - table[next_ptr].org_ptr = buf; - - /* Normalize the pointer to seg:0 */ - *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; - *(ush*)&buf = 0; - table[next_ptr++].new_ptr = buf; - return buf; -} - -void zcfree (voidpf opaque, voidpf ptr) -{ - int n; - if (*(ush*)&ptr != 0) { /* object < 64K */ - farfree(ptr); - return; - } - /* Find the original pointer */ - for (n = 0; n < next_ptr; n++) { - if (ptr != table[n].new_ptr) continue; - - farfree(table[n].org_ptr); - while (++n < next_ptr) { - table[n-1] = table[n]; - } - next_ptr--; - return; - } - ptr = opaque; /* just to make some compilers happy */ - Assert(0, "zcfree: ptr not found"); -} - -#endif /* __TURBOC__ */ - - -#ifdef M_I86 -/* Microsoft C in 16-bit mode */ - -# define MY_ZCALLOC - -#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) -# define _halloc halloc -# define _hfree hfree -#endif - -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - if (opaque) opaque = 0; /* to make compiler happy */ - return _halloc((long)items, size); -} - -void zcfree (voidpf opaque, voidpf ptr) -{ - if (opaque) opaque = 0; /* to make compiler happy */ - _hfree(ptr); -} - -#endif /* M_I86 */ - -#endif /* SYS16BIT */ - - -#ifndef MY_ZCALLOC /* Any system without a special alloc function */ - -#ifndef STDC -extern voidp malloc OF((uInt size)); -extern voidp calloc OF((uInt items, uInt size)); -extern void free OF((voidpf ptr)); -#endif - -voidpf zcalloc (opaque, items, size) - voidpf opaque; - unsigned items; - unsigned size; -{ - if (opaque) items += size - size; /* make compiler happy */ - return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : - (voidpf)calloc(items, size); -} - -void zcfree (opaque, ptr) - voidpf opaque; - voidpf ptr; -{ - free(ptr); - if (opaque) return; /* make compiler happy */ -} - -#endif /* MY_ZCALLOC */ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/pcsx2/3rdparty/zlib/zutil.h b/pcsx2/3rdparty/zlib/zutil.h index 0e3a9a0638..532fc7084a 100644 --- a/pcsx2/3rdparty/zlib/zutil.h +++ b/pcsx2/3rdparty/zlib/zutil.h @@ -1,269 +1,269 @@ -/* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id$ */ - -#ifndef ZUTIL_H -#define ZUTIL_H - -#define ZLIB_INTERNAL -#include "zlib.h" - -#ifdef STDC -# ifndef _WIN32_WCE -# include -# endif -# include -# include -#endif -#ifdef NO_ERRNO_H -# ifdef _WIN32_WCE - /* The Microsoft C Run-Time Library for Windows CE doesn't have - * errno. We define it as a global variable to simplify porting. - * Its value is always 0 and should not be used. We rename it to - * avoid conflict with other libraries that use the same workaround. - */ -# define errno z_errno -# endif - extern int errno; -#else -# ifndef _WIN32_WCE -# include -# endif -#endif - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -typedef unsigned char uch; -typedef uch FAR uchf; -typedef unsigned short ush; -typedef ush FAR ushf; -typedef unsigned long ulg; - -extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ -/* (size given to avoid silly warnings with Visual C++) */ - -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] - -#define ERR_RETURN(strm,err) \ - return (strm->msg = (char*)ERR_MSG(err), (err)) -/* To be used only when the state is known to be valid */ - - /* common constants */ - -#ifndef DEF_WBITS -# define DEF_WBITS MAX_WBITS -#endif -/* default windowBits for decompression. MAX_WBITS is for compression only */ - -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 9 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -/* default memLevel */ - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - -#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ - - /* target dependencies */ - -#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) -# define OS_CODE 0x00 -# if defined(__TURBOC__) || defined(__BORLANDC__) -# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) - /* Allow compilation with ANSI keywords only enabled */ - void _Cdecl farfree( void *block ); - void *_Cdecl farmalloc( unsigned long nbytes ); -# else -# include -# endif -# else /* MSC or DJGPP */ -# include -# endif -#endif - -#ifdef AMIGA -# define OS_CODE 0x01 -#endif - -#if defined(VAXC) || defined(VMS) -# define OS_CODE 0x02 -# define F_OPEN(name, mode) \ - fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") -#endif - -#if defined(ATARI) || defined(atarist) -# define OS_CODE 0x05 -#endif - -#ifdef OS2 -# define OS_CODE 0x06 -# ifdef M_I86 - #include -# endif -#endif - -#if defined(MACOS) || defined(TARGET_OS_MAC) -# define OS_CODE 0x07 -# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os -# include /* for fdopen */ -# else -# ifndef fdopen -# define fdopen(fd,mode) NULL /* No fdopen() */ -# endif -# endif -#endif - -#ifdef TOPS20 -# define OS_CODE 0x0a -#endif - -#ifdef WIN32 -# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ -# define OS_CODE 0x0b -# endif -#endif - -#ifdef __50SERIES /* Prime/PRIMOS */ -# define OS_CODE 0x0f -#endif - -#if defined(_BEOS_) || defined(RISCOS) -# define fdopen(fd,mode) NULL /* No fdopen() */ -#endif - -#if (defined(_MSC_VER) && (_MSC_VER > 600)) -# if defined(_WIN32_WCE) -# define fdopen(fd,mode) NULL /* No fdopen() */ -# ifndef _PTRDIFF_T_DEFINED - typedef int ptrdiff_t; -# define _PTRDIFF_T_DEFINED -# endif -# else -# define fdopen(fd,type) _fdopen(fd,type) -# endif -#endif - - /* common defaults */ - -#ifndef OS_CODE -# define OS_CODE 0x03 /* assume Unix */ -#endif - -#ifndef F_OPEN -# define F_OPEN(name, mode) fopen((name), (mode)) -#endif - - /* functions */ - -#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif -#if defined(__CYGWIN__) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif -#ifndef HAVE_VSNPRINTF -# ifdef MSDOS - /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), - but for now we just assume it doesn't. */ -# define NO_vsnprintf -# endif -# ifdef __TURBOC__ -# define NO_vsnprintf -# endif -# ifdef WIN32 - /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ -# if !defined(vsnprintf) && !defined(NO_vsnprintf) -# define vsnprintf _vsnprintf -# endif -# endif -# ifdef __SASC -# define NO_vsnprintf -# endif -#endif -#ifdef VMS -# define NO_vsnprintf -#endif - -#if defined(pyr) -# define NO_MEMCPY -#endif -#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) - /* Use our own functions for small and medium model with MSC <= 5.0. - * You may have to use the same strategy for Borland C (untested). - * The __SC__ check is for Symantec. - */ -# define NO_MEMCPY -#endif -#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) -# define HAVE_MEMCPY -#endif -#ifdef HAVE_MEMCPY -# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ -# define zmemcpy _fmemcpy -# define zmemcmp _fmemcmp -# define zmemzero(dest, len) _fmemset(dest, 0, len) -# else -# define zmemcpy memcpy -# define zmemcmp memcmp -# define zmemzero(dest, len) memset(dest, 0, len) -# endif -#else - extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); - extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); - extern void zmemzero OF((Bytef* dest, uInt len)); -#endif - -/* Diagnostic functions */ -#ifdef DEBUG -# include - extern int z_verbose; - extern void z_error OF((char *m)); -# define Assert(cond,msg) {if(!(cond)) z_error(msg);} -# define Trace(x) {if (z_verbose>=0) fprintf x ;} -# define Tracev(x) {if (z_verbose>0) fprintf x ;} -# define Tracevv(x) {if (z_verbose>1) fprintf x ;} -# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} -# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - - -voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); -void zcfree OF((voidpf opaque, voidpf ptr)); - -#define ZALLOC(strm, items, size) \ - (*((strm)->zalloc))((strm)->opaque, (items), (size)) -#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) -#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} - -#endif /* ZUTIL_H */ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# ifndef _WIN32_WCE +# include +# endif +# include +# include +#endif +#ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif + extern int errno; +#else +# ifndef _WIN32_WCE +# include +# endif +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 9 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 + #include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/pcsx2/AlignedMalloc.cpp b/pcsx2/AlignedMalloc.cpp index 7ab8ca4e98..bc8c37dd3a 100644 --- a/pcsx2/AlignedMalloc.cpp +++ b/pcsx2/AlignedMalloc.cpp @@ -1,72 +1,72 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -// This module contains implementations of _aligned_malloc for platforms that don't have -// it built into their CRT/libc. - -#include "PrecompiledHeader.h" -#include "System.h" - - -struct AlignedMallocHeader -{ - u32 size; // size of the allocated buffer (minus alignment and header) - void* baseptr; // offset of the original allocated pointer -}; - -static const uint headsize = sizeof(AlignedMallocHeader); - -void* __fastcall pcsx2_aligned_malloc(size_t size, size_t align) -{ - jASSUME( align < 0x10000 ); - - u8* p = (u8*)malloc(size+align+headsize); - - // start alignment calculations from past the header. - uptr pasthead = (uptr)(p+headsize); - uptr aligned = (pasthead + align-1) & ~(align-1); - - AlignedMallocHeader* header = (AlignedMallocHeader*)(aligned-headsize); - jASSUME( (uptr)header >= (uptr)p ); - - header->baseptr = p; - header->size = size; - - return (void*)aligned; -} - -void* __fastcall pcsx2_aligned_realloc(void* handle, size_t size, size_t align) -{ - if( handle == NULL ) return NULL; - jASSUME( align < 0x10000 ); - - AlignedMallocHeader* header = (AlignedMallocHeader*)((uptr)handle - headsize); - - void* newbuf = pcsx2_aligned_malloc( size, align ); - memcpy_fast( newbuf, handle, std::min( size, header->size ) ); - - free( header->baseptr ); - return newbuf; -} - -__forceinline void pcsx2_aligned_free(void* pmem) -{ - if( pmem == NULL ) return; - AlignedMallocHeader* header = (AlignedMallocHeader*)((uptr)pmem - headsize); - free( header->baseptr ); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +// This module contains implementations of _aligned_malloc for platforms that don't have +// it built into their CRT/libc. + +#include "PrecompiledHeader.h" +#include "System.h" + + +struct AlignedMallocHeader +{ + u32 size; // size of the allocated buffer (minus alignment and header) + void* baseptr; // offset of the original allocated pointer +}; + +static const uint headsize = sizeof(AlignedMallocHeader); + +void* __fastcall pcsx2_aligned_malloc(size_t size, size_t align) +{ + jASSUME( align < 0x10000 ); + + u8* p = (u8*)malloc(size+align+headsize); + + // start alignment calculations from past the header. + uptr pasthead = (uptr)(p+headsize); + uptr aligned = (pasthead + align-1) & ~(align-1); + + AlignedMallocHeader* header = (AlignedMallocHeader*)(aligned-headsize); + jASSUME( (uptr)header >= (uptr)p ); + + header->baseptr = p; + header->size = size; + + return (void*)aligned; +} + +void* __fastcall pcsx2_aligned_realloc(void* handle, size_t size, size_t align) +{ + if( handle == NULL ) return NULL; + jASSUME( align < 0x10000 ); + + AlignedMallocHeader* header = (AlignedMallocHeader*)((uptr)handle - headsize); + + void* newbuf = pcsx2_aligned_malloc( size, align ); + memcpy_fast( newbuf, handle, std::min( size, header->size ) ); + + free( header->baseptr ); + return newbuf; +} + +__forceinline void pcsx2_aligned_free(void* pmem) +{ + if( pmem == NULL ) return; + AlignedMallocHeader* header = (AlignedMallocHeader*)((uptr)pmem - headsize); + free( header->baseptr ); +} diff --git a/pcsx2/CDVD.cpp b/pcsx2/CDVD.cpp index fa06c19367..b6d92d3704 100644 --- a/pcsx2/CDVD.cpp +++ b/pcsx2/CDVD.cpp @@ -1,2171 +1,2171 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include -#include - -#ifndef _WIN32 -#include -#endif - -#include "PsxCommon.h" -#include "CDVDiso.h" - -static cdvdStruct cdvd; -static int cdCaseopen; - -/* -Interrupts - values are flag bits. - -0x00 No interrupt -0x01 Data Ready -0x02 Command Complete -0x03 Acknowledge (reserved) -0x04 End of Data Detected -0x05 Error Detected -0x06 Drive Not Ready - -In limited experimentation I found that PS2 apps respond actively to use of the -'Data Ready' flag -- in that they'll almost immediately initiate a DMA transfer -after receiving an Irq with that as the cause. But the question is, of course, -*when* to use it. Adding it into some locations of CDVD reading only slowed -games down and broke things. - -Using Drive Not Ready also invokes basic error handling from the Iop Bios, but -without proper emulation of the cdvd status flag it also tends to break things. - -*/ - -enum CdvdIrqId -{ - Irq_None = 0 -, Irq_DataReady = 0 -, Irq_CommandComplete -, Irq_Acknowledge -, Irq_EndOfData -, Irq_Error -, Irq_NotReady - -}; - -/* is cdvd.Status only for NCMDS? (linuzappz) */ -enum cdvdStatus -{ - CDVD_STATUS_NONE = 0x00, // not sure ;) - CDVD_STATUS_SEEK_COMPLETE = 0x0A, -}; - -// Cdvd actions tell the emulator how and when to respond to certain requests. -// Actions are handled by the cdvdInterrupt() -enum cdvdActions -{ - cdvdAction_None = 0 -, cdvdAction_Seek -, cdvdAction_Standby -, cdvdAction_Stop -, cdvdAction_Break -, cdvdAction_Read // note: not used yet. -}; - -////////////////////////////////////////////////////////////////////////// -// -- Cdvd Block Read Cycle Timings -- -// These timings are based on a median average block read speed. In theory the read -// speeds differ based on the location of the sector being read (outer rings have -// a different read speed from inner rings). But for our purposes an average is good -// enough, since all of Pcsx2's instruction cycle counting is hardly accurate anyway. - -// Morale of the story: don't get too caught up micro-managing your cycle timings. :) - -// Note: DVD read times are modified to be faster, because games seem to be a lot more -// concerned with accurate(ish) seek delays and less concerned with actual block read speeds. - -static const uint PSX_CD_READSPEED = 153600; // 1 Byte Time @ x1 (150KB = cd x 1) -static const uint PSX_DVD_READSPEED = 1382400 + 256000; // normal is 1 Byte Time @ x1 (1350KB = dvd x 1). - -enum CDVD_MODE_TYPE -{ - MODE_DVDROM, - MODE_CDROM -}; - -// if a seek is within this many blocks, read instead of seek. -// I picked 9 as an arbitrary value. Not sure what the real PS2 uses. -static const int Cdvd_Contigious_Seek = 9; -static const uint Cdvd_Avg_SeekCycles = (PSXCLK*40) / 1000; // average number of cycles per seek (40ms) - - - -static const char *mg_zones[8] = {"Japan", "USA", "Europe", "Oceania", "Asia", "Russia", "China", "Mexico"}; - -static const char *nCmdName[0x100]= { - "CdSync", "CdNop", "CdStandby", "CdStop", - "CdPause", "CdSeek", "CdRead", "CdReadCDDA", - "CdReadDVDV", "CdGetToc", "", "NCMD_B", - "CdReadKey", "", "sceCdReadXCDDA", "sceCdChgSpdlCtrl", -}; - -static const char *sCmdName[0x100]= { - "", "sceCdGetDiscType", "sceCdReadSubQ", "subcommands",//sceCdGetMecaconVersion, read/write console id, read renewal date - "", "sceCdTrayState", "sceCdTrayCtrl", "", - "sceCdReadClock", "sceCdWriteClock", "sceCdReadNVM", "sceCdWriteNVM", - "sceCdSetHDMode", "", "", "sceCdPowerOff", - "", "", "sceCdReadILinkID", "sceCdWriteILinkID", /*10*/ - "sceAudioDigitalOut", "sceForbidDVDP", "sceAutoAdjustCtrl", "sceCdReadModelNumber", - "sceWriteModelNumber", "sceCdForbidCD", "sceCdBootCertify", "sceCdCancelPOffRdy", - "sceCdBlueLEDCtl", "", "sceRm2Read", "sceRemote2_7",//Rm2PortGetConnection? - "sceRemote2_6", "sceCdWriteWakeUpTime", "sceCdReadWakeUpTime", "", /*20*/ - "sceCdRcBypassCtl", "", "", "", - "", "sceCdNoticeGameStart", "", "", - "sceCdXBSPowerCtl", "sceCdXLEDCtl", "sceCdBuzzerCtl", "", - "", "sceCdSetMediumRemoval", "sceCdGetMediumRemoval", "sceCdXDVRPReset", /*30*/ - "", "", "__sceCdReadRegionParams", "__sceCdReadMAC", - "__sceCdWriteMAC", "", "", "", - "", "", "__sceCdWriteRegionParams", "", - "sceCdOpenConfig", "sceCdReadConfig", "sceCdWriteConfig", "sceCdCloseConfig", /*40*/ - "", "", "", "", - "", "", "", "", - "", "", "", "", - "", "", "", "", /*50*/ - "", "", "", "", - "", "", "", "", - "", "", "", "", - "", "", "", "", /*60*/ - "", "", "", "", - "", "", "", "", - "", "", "", "", - "", "", "", "", /*70*/ - "", "", "", "", - "", "", "", "", - "", "", "", "", - "mechacon_auth_0x80", "mechacon_auth_0x81", "mechacon_auth_0x82", "mechacon_auth_0x83", /*80*/ - "mechacon_auth_0x84", "mechacon_auth_0x85", "mechacon_auth_0x86", "mechacon_auth_0x87", - "mechacon_auth_0x88", "", "", "", - "", "sceMgWriteData", "sceMgReadData", "mechacon_auth_0x8F", - "sceMgWriteHeaderStart", "sceMgReadBITLength", "sceMgWriteDatainLength", "sceMgWriteDataoutLength", /*90*/ - "sceMgReadKbit", "sceMgReadKbit2", "sceMgReadKcon", "sceMgReadKcon2", - "sceMgReadIcvPs2", "", "", "", - "", "", "", "", - /*A0, no sCmds above?*/ -}; - -// NVM (eeprom) layout info -struct NVMLayout { - u32 biosVer; // bios version that this eeprom layout is for - s32 config0; // offset of 1st config block - s32 config1; // offset of 2nd config block - s32 config2; // offset of 3rd config block - s32 consoleId; // offset of console id (?) - s32 ilinkId; // offset of ilink id (ilink mac address) - s32 modelNum; // offset of ps2 model number (eg "SCPH-70002") - s32 regparams; // offset of RegionParams for PStwo - s32 mac; // offset of the value written to 0xFFFE0188 and 0xFFFE018C on PStwo -}; - -#define NVM_FORMAT_MAX 2 -NVMLayout nvmlayouts[NVM_FORMAT_MAX] = -{ - {0x000, 0x280, 0x300, 0x200, 0x1C8, 0x1C0, 0x1A0, 0x180, 0x198}, // eeproms from bios v0.00 and up - {0x146, 0x270, 0x2B0, 0x200, 0x1C8, 0x1E0, 0x1B0, 0x180, 0x198}, // eeproms from bios v1.70 and up -}; - -#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ -#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ - -#define SetResultSize(size) \ - cdvd.ResultC = size; cdvd.ResultP = 0; \ - cdvd.sDataIn&=~0x40; - -#define CDVDREAD_INT(eCycle) PSX_INT(IopEvt_CdvdRead, eCycle) -static void CDVD_INT(int eCycle) -{ - if( eCycle == 0 ) - cdvdActionInterrupt(); - else - PSX_INT(IopEvt_Cdvd, eCycle); -} - -// Sets the cdvd IRQ and the reason for the IRQ, and signals the IOP for a branch -// test (which will cause the exception to be handled). -static void cdvdSetIrq( uint id = (1< 0) { if (ptr[i] == '.') break; i--; } - ptr[i+1] = '\0'; - strcat(file, "MEC"); - - // if file doesnt exist, create empty one - fd = fopen(file, "r+b"); - if (fd == NULL) { - SysPrintf("MEC File Not Found , Creating Blank File\n"); - fd = fopen(file, "wb"); - if (fd == NULL) { - Msgbox::Alert("_cdvdOpenMechaVer: Error creating %s", params file); - exit(1); - } - fputc(0x03, fd); - fputc(0x06, fd); - fputc(0x02, fd); - fputc(0x00, fd); - } - return fd; -} - -s32 cdvdGetMechaVer(u8* ver) -{ - FILE* fd = _cdvdOpenMechaVer(); - if (fd == NULL) return 1; - fseek(fd, 0, SEEK_SET); - fread(ver, 1, 4, fd); - fclose(fd); - return 0; -} - -FILE *_cdvdOpenNVM() { - char *ptr; - int i; - string Bios; - char file[g_MaxPath]; - FILE* fd; - - // get the name of the bios file - Path::Combine( Bios, Config.BiosDir, Config.Bios ); - - // use the bios filename to get the name of the nvm file - // [TODO] : Upgrade this to use std::string! - - strcpy( file, Bios.c_str() ); - ptr = file; i = (int)strlen(file); - while (i > 0) { if (ptr[i] == '.') break; i--; } - ptr[i+1] = '\0'; - strcat(file, "NVM"); - - // if file doesnt exist, create empty one - fd = fopen(file, "r+b"); - if (fd == NULL) { - SysPrintf("NVM File Not Found , Creating Blank File\n"); - fd = fopen(file, "wb"); - if (fd == NULL) { - Msgbox::Alert("_cdvdOpenNVM: Error creating %s", params file); - exit(1); - } - for (i=0; i<1024; i++) fputc(0, fd); - } - return fd; -} - -// -// the following 'cdvd' functions all return 0 if successful -// - -s32 cdvdReadNVM(u8 *dst, int offset, int bytes) { - FILE* fd = _cdvdOpenNVM(); - if (fd == NULL) return 1; - fseek(fd, offset, SEEK_SET); - fread(dst, 1, bytes, fd); - fclose(fd); - return 0; -} -s32 cdvdWriteNVM(const u8 *src, int offset, int bytes) { - FILE* fd = _cdvdOpenNVM(); - if (fd == NULL) return 1; - fseek(fd, offset, SEEK_SET); - fwrite(src, 1, bytes, fd); - fclose(fd); - return 0; -} - -#define GET_NVM_DATA(buff, offset, size, fmtOffset) getNvmData(buff, offset, size, BiosVersion, offsetof(NVMLayout, fmtOffset)) -#define SET_NVM_DATA(buff, offset, size, fmtOffset) setNvmData(buff, offset, size, BiosVersion, offsetof(NVMLayout, fmtOffset)) - -s32 getNvmData(u8* buffer, s32 offset, s32 size, u32 biosVersion, s32 fmtOffset) -{ - // find the correct bios version - NVMLayout* nvmLayout = NULL; - s32 nvmIdx; - for(nvmIdx=0; nvmIdx= cdvd.CNumBlocks) - return 1; - else if( - ((cdvd.COffset == 0) && (cdvd.CBlockIndex >= 4))|| - ((cdvd.COffset == 1) && (cdvd.CBlockIndex >= 2))|| - ((cdvd.COffset == 2) && (cdvd.CBlockIndex >= 7)) - ) - { - memzero_ptr<16>(config); - return 0; - } - - // get config data - if(cdvd.COffset == 0) - return GET_NVM_DATA(config, (cdvd.CBlockIndex++)*16, 16, config0); else - if(cdvd.COffset == 2) - return GET_NVM_DATA(config, (cdvd.CBlockIndex++)*16, 16, config2); - else - return GET_NVM_DATA(config, (cdvd.CBlockIndex++)*16, 16, config1); -} -s32 cdvdWriteConfig(const u8* config) -{ - // make sure its in write mode - if(cdvd.CReadWrite != 1) - return 1; - // check if block index is in bounds - else if(cdvd.CBlockIndex >= cdvd.CNumBlocks) - return 1; - else if( - ((cdvd.COffset == 0) && (cdvd.CBlockIndex >= 4))|| - ((cdvd.COffset == 1) && (cdvd.CBlockIndex >= 2))|| - ((cdvd.COffset == 2) && (cdvd.CBlockIndex >= 7)) - ) - return 0; - - // get config data - if(cdvd.COffset == 0) - return SET_NVM_DATA(config, (cdvd.CBlockIndex++)*16, 16, config0); else - if(cdvd.COffset == 2) - return SET_NVM_DATA(config, (cdvd.CBlockIndex++)*16, 16, config2); - else - return SET_NVM_DATA(config, (cdvd.CBlockIndex++)*16, 16, config1); -} - - -void cdvdReadKey(u8 arg0, u16 arg1, u32 arg2, u8* key) { - char str[g_MaxPath]; - int numbers; - int letters; - unsigned int key_0_3; - unsigned char key_4; - unsigned char key_14; - char exeName[12]; - - // get main elf name - GetPS2ElfName(str); - sprintf(exeName, "%c%c%c%c%c%c%c%c%c%c%c",str[8],str[9],str[10],str[11],str[12],str[13],str[14],str[15],str[16],str[17],str[18]); - DevCon::Notice("exeName = %s", params &str[8]); - - // convert the number characters to a real 32bit number - numbers = ((((exeName[5] - '0'))*10000) + - (((exeName[ 6] - '0'))*1000) + - (((exeName[ 7] - '0'))*100) + - (((exeName[ 9] - '0'))*10) + - (((exeName[10] - '0'))*1) ); - - // combine the lower 7 bits of each char - // to make the 4 letters fit into a single u32 - letters = (int)((exeName[3]&0x7F)<< 0) | - (int)((exeName[2]&0x7F)<< 7) | - (int)((exeName[1]&0x7F)<<14) | - (int)((exeName[0]&0x7F)<<21); - - // calculate magic numbers - key_0_3 = ((numbers & 0x1FC00) >> 10) | ((0x01FFFFFF & letters) << 7); // numbers = 7F letters = FFFFFF80 - key_4 = ((numbers & 0x0001F) << 3) | ((0x0E000000 & letters) >> 25); // numbers = F8 letters = 07 - key_14 = ((numbers & 0x003E0) >> 2) | 0x04; // numbers = F8 extra = 04 unused = 03 - - // clear key values - memzero_ptr<16>(key); - - // store key values - key[ 0] = (key_0_3&0x000000FF)>> 0; - key[ 1] = (key_0_3&0x0000FF00)>> 8; - key[ 2] = (key_0_3&0x00FF0000)>>16; - key[ 3] = (key_0_3&0xFF000000)>>24; - key[ 4] = key_4; - - if(arg2 == 75) - { - key[14] = key_14; - key[15] = 0x05; - } - else if(arg2 == 3075) - { - key[15] = 0x01; - } - else if(arg2 == 4246) - { - // 0x0001F2F707 = sector 0x0001F2F7 dec 0x07 - key[ 0] = 0x07; - key[ 1] = 0xF7; - key[ 2] = 0xF2; - key[ 3] = 0x01; - key[ 4] = 0x00; - key[15] = 0x01; - } - else - { - key[15] = 0x01; - } - - Console::WriteLn( "CDVD.KEY = %02X,%02X,%02X,%02X,%02X,%02X,%02X", params - cdvd.Key[0],cdvd.Key[1],cdvd.Key[2],cdvd.Key[3],cdvd.Key[4],cdvd.Key[14],cdvd.Key[15] ); - - // Now's a good time to reload the ELF info... - if( ElfCRC == 0 ) - { - ElfCRC = loadElfCRC( str ); - ElfApplyPatches(); - LoadGameSpecificSettings(); - } -} - -s32 cdvdGetToc(void* toc) -{ - s32 ret = CDVDgetTOC(toc); - if(ret == -1) ret = 0x80; - return ret; -/* - cdvdTN diskInfo; - cdvdTD trackInfo; - u8 _time[3]; - u32 type; - int i, err; - - //Param[0] is 0 for CdGetToc and any value for cdvdman_call19 - //the code below handles only CdGetToc! - //if(cdvd.Param[0]==0x01) - //{ - SysPrintf("CDGetToc Param[0]=%d, Param[1]=%d\n",cdvd.Param[0],cdvd.Param[1]); - //} - type = CDVDgetDiskType(); - if (CDVDgetTN(&diskInfo) == -1) { diskInfo.etrack = 0;diskInfo.strack = 1; } - if (CDVDgetTD(0, &trackInfo) == -1) trackInfo.lsn = 0; - - if (type == CDVD_TYPE_CDDA) { - PSXMu8(HW_DMA3_MADR+ 0) = 0x01; - } else - if (type == CDVD_TYPE_PS2DVD) { - if (trackInfo.lsn >= (2048*1024)) { // dual sided - PSXMu8(HW_DMA3_MADR+ 0) = 0x24; - } else { - PSXMu8(HW_DMA3_MADR+ 0) = 0x04; - } - } else - if (type == CDVD_TYPE_PS2CD) { - PSXMu8(HW_DMA3_MADR+ 0) = 0x41; - } - - if (PSXMu8(HW_DMA3_MADR+ 0) & 0x04) { - PSXMu8(HW_DMA3_MADR+ 1) = 0x02; - PSXMu8(HW_DMA3_MADR+ 2) = 0xF2; - PSXMu8(HW_DMA3_MADR+ 3) = 0x00; - - if (PSXMu8(HW_DMA3_MADR+ 0) & 0x20) { - PSXMu8(HW_DMA3_MADR+ 4) = 0x41; - PSXMu8(HW_DMA3_MADR+ 5) = 0x95; - } else { - PSXMu8(HW_DMA3_MADR+ 4) = 0x86; - PSXMu8(HW_DMA3_MADR+ 5) = 0x72; - } - PSXMu8(HW_DMA3_MADR+ 6) = 0x00; - PSXMu8(HW_DMA3_MADR+ 7) = 0x00; - PSXMu8(HW_DMA3_MADR+ 8) = 0x00; - PSXMu8(HW_DMA3_MADR+ 9) = 0x00; - PSXMu8(HW_DMA3_MADR+10) = 0x00; - PSXMu8(HW_DMA3_MADR+11) = 0x00; - - PSXMu8(HW_DMA3_MADR+12) = 0x00; - PSXMu8(HW_DMA3_MADR+13) = 0x00; - PSXMu8(HW_DMA3_MADR+14) = 0x00; - PSXMu8(HW_DMA3_MADR+15) = 0x00; - - PSXMu8(HW_DMA3_MADR+16) = 0x00; - PSXMu8(HW_DMA3_MADR+17) = 0x03; - PSXMu8(HW_DMA3_MADR+18) = 0x00; - PSXMu8(HW_DMA3_MADR+19) = 0x00; - - } else { - PSXMu8(HW_DMA3_MADR+ 1) = 0x00; - PSXMu8(HW_DMA3_MADR+ 2) = 0xA0; - PSXMu8(HW_DMA3_MADR+ 7) = itob(diskInfo.strack);//Number of FirstTrack - - PSXMu8(HW_DMA3_MADR+12) = 0xA1; - PSXMu8(HW_DMA3_MADR+17) = itob(diskInfo.etrack);//Number of LastTrack - - PSXMu8(HW_DMA3_MADR+22) = 0xA2;//DiskLength - LSNtoMSF(_time, trackInfo.lsn); - PSXMu8(HW_DMA3_MADR+27) = itob(_time[2]); - PSXMu8(HW_DMA3_MADR+28) = itob(_time[1]); - - for (i=diskInfo.strack; i<=diskInfo.etrack; i++) { - err=CDVDgetTD(i, &trackInfo); - LSNtoMSF(_time, trackInfo.lsn); - PSXMu8(HW_DMA3_MADR+i*10+30) = trackInfo.type; - PSXMu8(HW_DMA3_MADR+i*10+32) = err == -1 ? 0 : itob(i); //number - PSXMu8(HW_DMA3_MADR+i*10+37) = itob(_time[2]); - PSXMu8(HW_DMA3_MADR+i*10+38) = itob(_time[1]); - PSXMu8(HW_DMA3_MADR+i*10+39) = itob(_time[0]); - } - } -*/ -} - -s32 cdvdReadSubQ(s32 lsn, cdvdSubQ* subq) -{ - s32 ret = CDVDreadSubQ(lsn, subq); - if(ret == -1) ret = 0x80; - return ret; -} - -s32 cdvdCtrlTrayOpen() -{ - s32 ret = CDVDctrlTrayOpen(); - if(ret == -1) ret = 0x80; - return ret; -} - -s32 cdvdCtrlTrayClose() -{ - s32 ret = CDVDctrlTrayClose(); - if(ret == -1) ret = 0x80; - return ret; -} - -// Modified by (efp) - 16/01/2006 -// checks if tray was opened since last call to this func -s32 cdvdGetTrayStatus() -{ - s32 ret = CDVDgetTrayStatus(); - // get current tray state - if (cdCaseopen) return(CDVD_TRAY_OPEN); - - - if (ret == -1) return(CDVD_TRAY_CLOSE); - return(ret); -} - -// Note: Is tray status being kept as a var here somewhere? -// cdvdNewDiskCB() can update it's status as well... - -// Modified by (efp) - 16/01/2006 -__forceinline void cdvdGetDiskType() -{ - // defs 0.9.0 - if(CDVDnewDiskCB || cdvd.Type != CDVD_TYPE_NODISC) return; - - // defs.0.8.1 - if(cdvdGetTrayStatus() == CDVD_TRAY_OPEN) - { - cdvd.Type = CDVD_TYPE_NODISC; - return; - } - - cdvd.Type = CDVDgetDiskType(); - if (cdvd.Type == CDVD_TYPE_PS2CD) // && needReset == 1) - { - char str[g_MaxPath]; - if (GetPS2ElfName(str) == 1) - { - cdvd.Type = CDVD_TYPE_PSCD; - } // ENDIF- Does the SYSTEM.CNF file only say "BOOT="? PS1 CD then. - } // ENDIF- Is the type listed as a PS2 CD? -} // END cdvdGetDiskType() - - -// check whether disc is single or dual layer -// if its dual layer, check what the disctype is and what sector number -// layer1 starts at -// -// args: gets value for dvd type (0=single layer, 1=ptp, 2=otp) -// gets value for start lsn of layer1 -// returns: 1 if on dual layer disc -// 0 if not on dual layer disc -s32 cdvdReadDvdDualInfo(s32* dualType, u32* layer1Start) -{ - u8 toc[2064]; - *dualType = 0; - *layer1Start = 0; - - // if error getting toc, settle for single layer disc ;) - if(cdvdGetToc(toc)) - return 0; - if(toc[14] & 0x60) - { - if(toc[14] & 0x10) - { - // otp dvd - *dualType = 2; - *layer1Start = (toc[25]<<16) + (toc[26]<<8) + (toc[27]) - 0x30000 + 1; - } - else - { - // ptp dvd - *dualType = 1; - *layer1Start = (toc[21]<<16) + (toc[22]<<8) + (toc[23]) - 0x30000 + 1; - } - } - else - { - // single layer dvd - *dualType = 0; - *layer1Start = (toc[21]<<16) + (toc[22]<<8) + (toc[23]) - 0x30000 + 1; - } - - return 1; -} - - -#include - -static uint cdvdBlockReadTime( CDVD_MODE_TYPE mode ) -{ - return (PSXCLK * cdvd.BlockSize) / (((mode==MODE_CDROM) ? PSX_CD_READSPEED : PSX_DVD_READSPEED) * cdvd.Speed); -} - -void cdvdReset() -{ -#ifdef _WIN32 - SYSTEMTIME st; - //Get and set the internal clock to time - GetSystemTime(&st); -#else - time_t traw; - struct tm* ptlocal; - time(&traw); - ptlocal = localtime(&traw); -#endif - - memzero_obj(cdvd); - - cdvd.Type = CDVD_TYPE_NODISC; - cdvd.Spinning = false; - - cdvd.sDataIn = 0x40; - cdvd.Ready = 0x4e; - cdCaseopen = 0; - cdvd.Speed = 4; - cdvd.BlockSize = 2064; - cdvd.Action = cdvdAction_None; - cdvd.ReadTime = cdvdBlockReadTime( MODE_DVDROM ); - - // any random valid date will do - cdvd.RTC.hour = 1; - cdvd.RTC.day = 25; - cdvd.RTC.month = 5; - cdvd.RTC.year = 7; //2007 - -#ifndef _DEBUG -#ifdef _WIN32 - cdvd.RTC.second = (u8)(st.wSecond); - cdvd.RTC.minute = (u8)(st.wMinute); - cdvd.RTC.hour = (u8)(st.wHour+1)%24; - cdvd.RTC.day = (u8)(st.wDay); - cdvd.RTC.month = (u8)(st.wMonth); - cdvd.RTC.year = (u8)(st.wYear - 2000); -#else - cdvd.RTC.second = ptlocal->tm_sec; - cdvd.RTC.minute = ptlocal->tm_min; - cdvd.RTC.hour = ptlocal->tm_hour; - cdvd.RTC.day = ptlocal->tm_mday; - cdvd.RTC.month = ptlocal->tm_mon; - cdvd.RTC.year = ptlocal->tm_year; -#endif -#endif - -} - -struct Freeze_v10Compat -{ - u8 Action; - u32 SeekToSector; - u32 ReadTime; - bool Spinning; -}; - -void SaveState::cdvdFreeze() -{ - if( GetVersion() <= 0x10 ) - { - // the old cdvd struct didn't save the last few items. - FreezeLegacy( cdvd, sizeof(Freeze_v10Compat) ); - cdvd.SeekToSector = cdvd.Sector; - cdvd.Action = cdvdAction_None; - cdvd.ReadTime = cdvdBlockReadTime( MODE_DVDROM ); - cdvd.Spinning = true; - } - else - Freeze( cdvd ); - - if( IsLoading() ) - { - // Make sure the Cdvd plugin has the expected track loaded into the buffer. - // If cdvd.Readed is cleared it means we need to load the SeekToSector (ie, a - // seek is in progress!) - - if( cdvd.Reading ) - cdvd.RErr = CDVDreadTrack( cdvd.Readed ? cdvd.Sector : cdvd.SeekToSector, cdvd.ReadMode); - } -} - -// Modified by (efp) - 16/01/2006 -void cdvdNewDiskCB() -{ - cdvd.Type = CDVDgetDiskType(); - if(cdvd.Type == CDVD_TYPE_PS2CD) { - char str[g_MaxPath]; - if(GetPS2ElfName(str) == 1) { - cdvd.Type = CDVD_TYPE_PSCD; - } // ENDIF- Does the SYSTEM.CNF file only say "BOOT="? PS1 CD then. - } -} - -void mechaDecryptBytes(unsigned char* buffer, int size) -{ - int i; - - int shiftAmount = (cdvd.decSet>>4) & 7; - int doXor = (cdvd.decSet) & 1; - int doShift = (cdvd.decSet) & 2; - - for (i=0; i>shiftAmount) | (buffer[i]<<(8-shiftAmount)); - } -} - -int cdvdReadSector() { - s32 bcr; - - CDR_LOG("SECTOR %d (BCR %x;%x)\n", cdvd.Sector, HW_DMA3_BCR_H16, HW_DMA3_BCR_L16); - - bcr = (HW_DMA3_BCR_H16 * HW_DMA3_BCR_L16) *4; - if (bcr < cdvd.BlockSize) { - CDR_LOG( "READBLOCK: bcr < cdvd.BlockSize; %x < %x\n", bcr, cdvd.BlockSize ); - if (HW_DMA3_CHCR & 0x01000000) { - HW_DMA3_CHCR &= ~0x01000000; - psxDmaInterrupt(3); - } - return -1; - } - - const u32 madr = HW_DMA3_MADR; - - // if raw dvd sector 'fill in the blanks' - if (cdvd.BlockSize == 2064) { - // get info on dvd type and layer1 start - u32 layer1Start; - s32 dualType; - s32 layerNum; - u32 lsn = cdvd.Sector; - - cdvdReadDvdDualInfo(&dualType, &layer1Start); - - if((dualType == 1) && (lsn >= layer1Start)) { - // dual layer ptp disc - layerNum = 1; - lsn = lsn-layer1Start + 0x30000; - } else if((dualType == 2) && (lsn >= layer1Start)) { - // dual layer otp disc - layerNum = 1; - lsn = ~(layer1Start+0x30000 - 1); - } else { - // single layer disc - // or on first layer of dual layer disc - layerNum = 0; - lsn += 0x30000; - } // ENDLONGIF- Assumed the other dualType is 0. - - PSXMu8(madr+0) = 0x20 | layerNum; - PSXMu8(madr+1) = (u8)(lsn >> 16); - PSXMu8(madr+2) = (u8)(lsn >> 8); - PSXMu8(madr+3) = (u8)(lsn ); - - // sector IED (not calculated at present) - PSXMu8(madr+4) = 0; - PSXMu8(madr+5) = 0; - - // sector CPR_MAI (not calculated at present) - PSXMu8(madr+ 6) = 0; - PSXMu8(madr+ 7) = 0; - PSXMu8(madr+ 8) = 0; - PSXMu8(madr+ 9) = 0; - PSXMu8(madr+10) = 0; - PSXMu8(madr+11) = 0; - - // normal 2048 bytes of sector data - memcpy_fast(PSXM(madr+12), cdr.pTransfer, 2048); - - // 4 bytes of edc (not calculated at present) - PSXMu8(madr+2060) = 0; - PSXMu8(madr+2061) = 0; - PSXMu8(madr+2062) = 0; - PSXMu8(madr+2063) = 0; - } else { - // normal read - memcpy_fast((u8*)PSXM(madr), cdr.pTransfer, cdvd.BlockSize); - } - // decrypt sector's bytes - if(cdvd.decSet) - mechaDecryptBytes((u8*)PSXM(madr), cdvd.BlockSize); - - // Added a clear after memory write .. never seemed to be necessary before but *should* - // be more correct. (air) - psxCpu->Clear( madr, cdvd.BlockSize/4); - -// SysPrintf("sector %x;%x;%x\n", PSXMu8(madr+0), PSXMu8(madr+1), PSXMu8(madr+2)); - - HW_DMA3_BCR_H16-= (cdvd.BlockSize / (HW_DMA3_BCR_L16*4)); - HW_DMA3_MADR+= cdvd.BlockSize; - - return 0; -} - -// inlined due to being referenced in only one place. -__forceinline void cdvdActionInterrupt() -{ - switch( cdvd.Action ) - { - case cdvdAction_Seek: - case cdvdAction_Standby: - cdvd.Spinning = true; - cdvd.Ready = 0x40; - cdvd.Sector = cdvd.SeekToSector; - cdvd.Status = CDVD_STATUS_SEEK_COMPLETE; - break; - - case cdvdAction_Stop: - cdvd.Spinning = false; - cdvd.Ready = 0x40; - cdvd.Sector = 0; - cdvd.Status = 0; - break; - - case cdvdAction_Break: - // Make sure the cdvd action state is pretty well cleared: - cdvd.Reading = 0; - cdvd.Readed = 0; - cdvd.Ready = 0x4e; // should be 0x40 or something else? - cdvd.Status = 0; - cdvd.RErr = 0; - cdvd.nCommand = 0; - break; - } - cdvd.Action = cdvdAction_None; - - cdvd.PwOff |= 1< Scheduling block read interrupt at iopcycle=%8.8x.\n", - psxRegs.cycle + cdvd.ReadTime ); - - CDVDREAD_INT(cdvd.ReadTime); - return; - } - - if (cdvd.Reading == 1) { - if (cdvd.RErr == 0) { - cdr.pTransfer = CDVDgetBuffer(); - } else cdr.pTransfer = NULL; - if (cdr.pTransfer == NULL) { - cdvd.RetryCntP++; - Console::Error("CDVD READ ERROR, sector=%d", params cdvd.Sector); - if (cdvd.RetryCntP <= cdvd.RetryCnt) { - cdvd.RErr = CDVDreadTrack(cdvd.Sector, cdvd.ReadMode); - CDVDREAD_INT(cdvd.ReadTime); - return; - } - } - cdvd.Reading = 0; - } - - if (cdvdReadSector() == -1) { - assert( (int)cdvd.ReadTime > 0 ); - CDVDREAD_INT(cdvd.ReadTime); - return; - } - - cdvd.Sector++; - - if (--cdvd.nSectors <= 0) - { - cdvd.PwOff |= 1<= cdvd.ResultC) cdvd.sDataIn|= 0x40; - ret = cdvd.Result[cdvd.ResultP-1]; - } - } - CDR_LOG("cdvdRead18(SDataOut) %x (ResultC=%d, ResultP=%d)\n", ret, cdvd.ResultC, cdvd.ResultP); - return ret; -} - -u8 cdvdRead20(void) { - CDR_LOG("cdvdRead20(Key0) %x\n", cdvd.Key[0]); - - return cdvd.Key[0]; -} - -u8 cdvdRead21(void) { - CDR_LOG("cdvdRead21(Key1) %x\n", cdvd.Key[1]); - - return cdvd.Key[1]; -} - -u8 cdvdRead22(void) { - CDR_LOG("cdvdRead22(Key2) %x\n", cdvd.Key[2]); - - return cdvd.Key[2]; -} - -u8 cdvdRead23(void) { - CDR_LOG("cdvdRead23(Key3) %x\n", cdvd.Key[3]); - - return cdvd.Key[3]; -} - -u8 cdvdRead24(void) { - CDR_LOG("cdvdRead24(Key4) %x\n", cdvd.Key[4]); - - return cdvd.Key[4]; -} - -u8 cdvdRead28(void) { - CDR_LOG("cdvdRead28(Key5) %x\n", cdvd.Key[5]); - - return cdvd.Key[5]; -} - -u8 cdvdRead29(void) { - CDR_LOG("cdvdRead29(Key6) %x\n", cdvd.Key[6]); - - return cdvd.Key[6]; -} - -u8 cdvdRead2A(void) { - CDR_LOG("cdvdRead2A(Key7) %x\n", cdvd.Key[7]); - - return cdvd.Key[7]; -} - -u8 cdvdRead2B(void) { - CDR_LOG("cdvdRead2B(Key8) %x\n", cdvd.Key[8]); - - return cdvd.Key[8]; -} - -u8 cdvdRead2C(void) { - CDR_LOG("cdvdRead2C(Key9) %x\n", cdvd.Key[9]); - - return cdvd.Key[9]; -} - -u8 cdvdRead30(void) { - CDR_LOG("cdvdRead30(Key10) %x\n", cdvd.Key[10]); - - return cdvd.Key[10]; -} - -u8 cdvdRead31(void) { - CDR_LOG("cdvdRead31(Key11) %x\n", cdvd.Key[11]); - - return cdvd.Key[11]; -} - -u8 cdvdRead32(void) { - CDR_LOG("cdvdRead32(Key12) %x\n", cdvd.Key[12]); - - return cdvd.Key[12]; -} - -u8 cdvdRead33(void) { - CDR_LOG("cdvdRead33(Key13) %x\n", cdvd.Key[13]); - - return cdvd.Key[13]; -} - -u8 cdvdRead34(void) { - CDR_LOG("cdvdRead34(Key14) %x\n", cdvd.Key[14]); - - return cdvd.Key[14]; -} - -u8 cdvdRead38(void) { // valid parts of key data (first and last are valid) - CDR_LOG("cdvdRead38(KeysValid) %x\n", cdvd.Key[15]); - - return cdvd.Key[15]; -} - -u8 cdvdRead39(void) { // KEY-XOR - CDR_LOG("cdvdRead39(KeyXor) %x\n", cdvd.KeyXor); - - return cdvd.KeyXor; -} - -u8 cdvdRead3A(void) { // DEC_SET - CDR_LOG("cdvdRead3A(DecSet) %x\n", cdvd.decSet); - - SysPrintf("DecSet Read: %02X\n", cdvd.decSet); - return cdvd.decSet; -} - - -// Returns the number of IOP cycles until the event completes. -static uint cdvdStartSeek( uint newsector ) -{ - cdvd.SeekToSector = newsector; - - uint delta = abs(cdvd.SeekToSector - cdvd.Sector); - uint seektime; - - cdvd.Ready = 0; - cdvd.Reading = 0; - cdvd.Readed = 0; - cdvd.Status = 0; - - if( !cdvd.Spinning ) - { - CDR_LOG( "CdSpinUp > Simulating CdRom Spinup Time, and seek to sector %d\n", cdvd.SeekToSector ); - seektime = PSXCLK / 3; // 333ms delay - cdvd.Spinning = true; - } - else if( (Cdvd_Contigious_Seek >= 0) && (delta >= Cdvd_Contigious_Seek) ) - { - CDR_LOG( "CdSeek Begin > to sector %d, from %d - delta=%d\n", cdvd.SeekToSector, cdvd.Sector, delta ); - seektime = Cdvd_Avg_SeekCycles; - } - else - { - CDR_LOG( "CdSeek Begin > Contigious block without seek - delta=%d sectors\n", delta ); - - // seektime is the time it takes to read to the destination block: - seektime = delta * cdvd.ReadTime; - - if( delta == 0 ) - { - cdvd.Status = CDVD_STATUS_SEEK_COMPLETE; - cdvd.Readed = 1; - cdvd.RetryCntP = 0; - - // setting Readed to zero skips the seek logic, which means the next call to - // cdvdReadInterrupt will load a block. So make sure it's properly scheduled - // based on sector read speeds: - seektime = cdvd.ReadTime; - } - } - - return seektime; -} - -void cdvdWrite04(u8 rt) { // NCOMMAND - CDR_LOG("cdvdWrite04: NCMD %s (%x) (ParamP = %x)\n", nCmdName[rt], rt, cdvd.ParamP); - - cdvd.nCommand = rt; - cdvd.Status = CDVD_STATUS_NONE; - cdvd.PwOff = Irq_None; // good or bad? - - switch (rt) { - case 0x00: // CdSync - case 0x01: // CdNop_ - cdvdSetIrq(); - break; - - case 0x02: // CdStandby - - // Seek to sector zero. The cdvdStartSeek function will simulate - // spinup times if needed. - - DevCon::Notice( "CdStandby : %d", params rt ); - cdvd.Action = cdvdAction_Standby; - cdvd.ReadTime = cdvdBlockReadTime( MODE_DVDROM ); - CDVD_INT( cdvdStartSeek( 0 ) ); - break; - - case 0x03: // CdStop - DevCon::Notice( "CdStop : %d", params rt ); - cdvd.Action = cdvdAction_Stop; - CDVD_INT( PSXCLK / 6 ); // 166ms delay? - break; - - // from an emulation point of view there is not much need to do anything for this one - case 0x04: // CdPause - cdvdSetIrq(); - break; - - case 0x05: // CdSeek - cdvd.Action = cdvdAction_Seek; - cdvd.ReadTime = cdvdBlockReadTime( MODE_DVDROM ); - CDVD_INT( cdvdStartSeek( *(uint*)(cdvd.Param+0) ) ); - break; - - case 0x06: // CdRead - cdvd.SeekToSector = *(uint*)(cdvd.Param+0); - cdvd.nSectors = *(int*)(cdvd.Param+4); - cdvd.RetryCnt = (cdvd.Param[8] == 0) ? 0x100 : cdvd.Param[8]; - cdvd.SpindlCtrl = cdvd.Param[9]; - cdvd.Speed = 24; - switch (cdvd.Param[10]) { - case 2: cdvd.ReadMode = CDVD_MODE_2340; cdvd.BlockSize = 2340; break; - case 1: cdvd.ReadMode = CDVD_MODE_2328; cdvd.BlockSize = 2328; break; - case 0: default: cdvd.ReadMode = CDVD_MODE_2048; cdvd.BlockSize = 2048; break; - } - - CDR_LOG( "CdRead > startSector=%d, nSectors=%d, RetryCnt=%x, Speed=%x(%x), ReadMode=%x(%x) (1074=%x)\n", - cdvd.Sector, cdvd.nSectors, cdvd.RetryCnt, cdvd.Speed, cdvd.Param[9], cdvd.ReadMode, cdvd.Param[10], psxHu32(0x1074)); - - if (Config.cdvdPrint) SysPrintf("CdRead: Reading Sector %d(%d Blocks of Size %d) at Speed=%dx\n", cdvd.Sector, cdvd.nSectors,cdvd.BlockSize,cdvd.Speed); - - cdvd.ReadTime = cdvdBlockReadTime( MODE_CDROM ); - CDVDREAD_INT( cdvdStartSeek( cdvd.SeekToSector ) ); - - // Read-ahead by telling the plugin about the track now. - // This helps improve performance on actual from-cd emulation - // (ie, not using the hard drive) - cdvd.RErr = CDVDreadTrack( cdvd.SeekToSector, cdvd.ReadMode ); - - // Set the reading block flag. If a seek is pending then Readed will - // take priority in the handler anyway. If the read is contigeous then - // this'll skip the seek delay. - cdvd.Reading = 1; - break; - - case 0x07: // CdReadCDDA - case 0x0E: // CdReadXCDDA - cdvd.SeekToSector = *(int*)(cdvd.Param+0); - cdvd.nSectors = *(int*)(cdvd.Param+4); - if (cdvd.Param[8] == 0) cdvd.RetryCnt = 0x100; - else cdvd.RetryCnt = cdvd.Param[8]; - cdvd.SpindlCtrl = cdvd.Param[9]; - switch (cdvd.Param[9]) { - case 0x01: cdvd.Speed = 1; break; - case 0x02: cdvd.Speed = 2; break; - case 0x03: cdvd.Speed = 4; break; - case 0x04: cdvd.Speed = 12; break; - default: cdvd.Speed = 24; break; - } - switch (cdvd.Param[10]) { - case 1: cdvd.ReadMode = CDVD_MODE_2368; cdvd.BlockSize = 2368; break; - case 2: - case 0: cdvd.ReadMode = CDVD_MODE_2352; cdvd.BlockSize = 2352; break; - } - - CDR_LOG( "CdReadCDDA > startSector=%d, nSectors=%d, RetryCnt=%x, Speed=%xx(%x), ReadMode=%x(%x) (1074=%x)\n", - cdvd.Sector, cdvd.nSectors, cdvd.RetryCnt, cdvd.Speed, cdvd.Param[9], cdvd.ReadMode, cdvd.Param[10], psxHu32(0x1074)); - - if (Config.cdvdPrint) SysPrintf("CdAudioRead: Reading Sector %d(%d Blocks of Size %d) at Speed=%dx\n", cdvd.Sector, cdvd.nSectors,cdvd.BlockSize,cdvd.Speed); - - cdvd.ReadTime = cdvdBlockReadTime( MODE_CDROM ); - CDVDREAD_INT( cdvdStartSeek( cdvd.SeekToSector ) ); - - // Read-ahead by telling the plugin about the track now. - // This helps improve performance on actual from-cd emulation - // (ie, not using the hard drive) - cdvd.RErr = CDVDreadTrack( cdvd.SeekToSector, cdvd.ReadMode ); - - // Set the reading block flag. If a seek is pending then Readed will - // take priority in the handler anyway. If the read is contigeous then - // this'll skip the seek delay. - cdvd.Reading = 1; - break; - - case 0x08: // DvdRead - cdvd.SeekToSector = *(int*)(cdvd.Param+0); - cdvd.nSectors = *(int*)(cdvd.Param+4); - if (cdvd.Param[8] == 0) cdvd.RetryCnt = 0x100; - else cdvd.RetryCnt = cdvd.Param[8]; - cdvd.SpindlCtrl = cdvd.Param[9]; - cdvd.Speed = 4; - cdvd.ReadMode = CDVD_MODE_2048; - cdvd.BlockSize = 2064; // Why oh why was it 2064 - - CDR_LOG( "DvdRead > startSector=%d, nSectors=%d, RetryCnt=%x, Speed=%x(%x), ReadMode=%x(%x) (1074=%x)\n", - cdvd.Sector, cdvd.nSectors, cdvd.RetryCnt, cdvd.Speed, cdvd.Param[9], cdvd.ReadMode, cdvd.Param[10], psxHu32(0x1074)); - - if (Config.cdvdPrint) SysPrintf("DvdRead: Reading Sector %d(%d Blocks of Size %d) at Speed=%dx\n", cdvd.Sector, cdvd.nSectors,cdvd.BlockSize,cdvd.Speed); - - cdvd.ReadTime = cdvdBlockReadTime( MODE_DVDROM ); - CDVDREAD_INT( cdvdStartSeek( cdvd.SeekToSector ) ); - - // Read-ahead by telling the plugin about the track now. - // This helps improve performance on actual from-cd emulation - // (ie, not using the hard drive) - cdvd.RErr = CDVDreadTrack( cdvd.SeekToSector, cdvd.ReadMode ); - - // Set the reading block flag. If a seek is pending then Readed will - // take priority in the handler anyway. If the read is contigeous then - // this'll skip the seek delay. - cdvd.Reading = 1; - break; - - case 0x09: // CdGetToc & cdvdman_call19 - //Param[0] is 0 for CdGetToc and any value for cdvdman_call19 - //the code below handles only CdGetToc! - //if(cdvd.Param[0]==0x01) - //{ - DevCon::WriteLn("CDGetToc Param[0]=%d, Param[1]=%d", params cdvd.Param[0],cdvd.Param[1]); - //} - cdvdGetToc( PSXM( HW_DMA3_MADR ) ); - cdvdSetIrq( (1< remote key code - SetResultSize(5); - cdvd.Result[0] = 0x00; - cdvd.Result[1] = 0x14; - cdvd.Result[2] = 0x00; - cdvd.Result[3] = 0x00; - cdvd.Result[4] = 0x00; - break; - -// case 0x1F: // sceRemote2_7 (2:1) - cdvdman_call117 -// break; - - case 0x20: // sceRemote2_6 (0:3) // 00 01 00 - SetResultSize(3); - cdvd.Result[0] = 0x00; - cdvd.Result[1] = 0x01; - cdvd.Result[2] = 0x00; - break; - -// case 0x21: // sceCdWriteWakeUpTime (8:1) -// break; - - case 0x22: // sceCdReadWakeUpTime (0:10) - SetResultSize(10); - cdvd.Result[0] = 0; - cdvd.Result[1] = 0; - cdvd.Result[2] = 0; - cdvd.Result[3] = 0; - cdvd.Result[4] = 0; - cdvd.Result[5] = 0; - cdvd.Result[6] = 0; - cdvd.Result[7] = 0; - cdvd.Result[8] = 0; - cdvd.Result[9] = 0; - break; - - case 0x24: // sceCdRCBypassCtrl (1:1) - In V10 Bios - // FIXME: because PRId<0x23, the bit 0 of sio2 don't get updated 0xBF808284 - SetResultSize(1); - cdvd.Result[0] = 0; - break; - -// case 0x25: // cdvdman_call120 (1:1) - In V10 Bios -// break; - -// case 0x26: // cdvdman_call128 (0,3) - In V10 Bios -// break; - -// case 0x27: // cdvdman_call148 (0:13) - In V10 Bios -// break; - -// case 0x28: // cdvdman_call150 (1:1) - In V10 Bios -// break; - - case 0x29: //sceCdNoticeGameStart (1:1) - SetResultSize(1); - cdvd.Result[0] = 0; - break; - -// case 0x2C: //sceCdXBSPowerCtl (2:2) -// break; - -// case 0x2D: //sceCdXLEDCtl (2:2) -// break; - -// case 0x2E: //sceCdBuzzerCtl (0:1) -// break; - -// case 0x2F: //cdvdman_call167 (16:1) -// break; - -// case 0x30: //cdvdman_call169 (1:9) -// break; - - case 0x31: //sceCdSetMediumRemoval (1:1) - SetResultSize(1); - cdvd.Result[0] = 0; - break; - - case 0x32: //sceCdGetMediumRemoval (0:2) - SetResultSize(2); - cdvd.Result[0] = 0; - cdvd.Result[0] = 0; - break; - -// case 0x33: //sceCdXDVRPReset (1:1) -// break; - - case 0x36: //cdvdman_call189 [__sceCdReadRegionParams - made up name] (0:15) i think it is 16, not 15 - SetResultSize(15); - cdvdGetMechaVer(&cdvd.Result[1]); - cdvd.Result[0] = cdvdReadRegionParams(&cdvd.Result[3]);//size==8 - SysPrintf("REGION PARAMS = %s %s\n", mg_zones[cdvd.Result[1]], &cdvd.Result[3]); - cdvd.Result[1] = 1 << cdvd.Result[1]; //encryption zone; see offset 0x1C in encrypted headers - ////////////////////////////////////////// - cdvd.Result[2] = 0; //?? -// cdvd.Result[3] == ROMVER[4] == *0xBFC7FF04 -// cdvd.Result[4] == OSDVER[4] == CAP Jjpn, Aeng, Eeng, Heng, Reng, Csch, Kkor? -// cdvd.Result[5] == OSDVER[5] == small -// cdvd.Result[6] == OSDVER[6] == small -// cdvd.Result[7] == OSDVER[7] == small -// cdvd.Result[8] == VERSTR[0x22] == *0xBFC7FF52 -// cdvd.Result[9] == DVDID J U O E A R C M -// cdvd.Result[10]== 0; //?? - cdvd.Result[11] = 0; //?? - cdvd.Result[12] = 0; //?? - ////////////////////////////////////////// - cdvd.Result[13] = 0; //0xFF - 77001 - cdvd.Result[14] = 0; //?? - break; - - case 0x37: //called from EECONF [sceCdReadMAC - made up name] (0:9) - SetResultSize(9); - cdvd.Result[0] = cdvdReadMAC(&cdvd.Result[1]); - break; - - case 0x38: //used to fix the MAC back after accidentally trashed it :D [sceCdWriteMAC - made up name] (8:1) - SetResultSize(1); - cdvd.Result[0] = cdvdWriteMAC(&cdvd.Param[0]); - break; - - case 0x3E: //[__sceCdWriteRegionParams - made up name] (15:1) [Florin: hum, i was expecting 14:1] - SetResultSize(1); - cdvd.Result[0] = cdvdWriteRegionParams(&cdvd.Param[2]); - break; - - case 0x40: // CdOpenConfig (3:1) - cdvd.CReadWrite = cdvd.Param[0]; - cdvd.COffset = cdvd.Param[1]; - cdvd.CNumBlocks = cdvd.Param[2]; - cdvd.CBlockIndex= 0; - SetResultSize(1); - cdvd.Result[0] = 0; - break; - - case 0x41: // CdReadConfig (0:16) - SetResultSize(16); - cdvdReadConfig(&cdvd.Result[0]); - break; - - case 0x42: // CdWriteConfig (16:1) - SetResultSize(1); - cdvd.Result[0] = cdvdWriteConfig(&cdvd.Param[0]); - break; - - case 0x43: // CdCloseConfig (0:1) - cdvd.CReadWrite = 0; - cdvd.COffset = 0; - cdvd.CNumBlocks = 0; - cdvd.CBlockIndex= 0; - SetResultSize(1); - cdvd.Result[0] = 0; - break; - - case 0x80: // secrman: __mechacon_auth_0x80 - cdvd.mg_datatype = 0;//data - SetResultSize(1);//in:1 - cdvd.Result[0] = 0; - break; - - case 0x81: // secrman: __mechacon_auth_0x81 - cdvd.mg_datatype = 0;//data - SetResultSize(1);//in:1 - cdvd.Result[0] = 0; - break; - - case 0x82: // secrman: __mechacon_auth_0x82 - SetResultSize(1);//in:16 - cdvd.Result[0] = 0; - break; - - case 0x83: // secrman: __mechacon_auth_0x83 - SetResultSize(1);//in:8 - cdvd.Result[0] = 0; - break; - - case 0x84: // secrman: __mechacon_auth_0x84 - SetResultSize(1+8+4);//in:0 - cdvd.Result[0] = 0; - - cdvd.Result[1] = 0x21; - cdvd.Result[2] = 0xdc; - cdvd.Result[3] = 0x31; - cdvd.Result[4] = 0x96; - cdvd.Result[5] = 0xce; - cdvd.Result[6] = 0x72; - cdvd.Result[7] = 0xe0; - cdvd.Result[8] = 0xc8; - - cdvd.Result[9] = 0x69; - cdvd.Result[10] = 0xda; - cdvd.Result[11] = 0x34; - cdvd.Result[12] = 0x9b; - break; - - case 0x85: // secrman: __mechacon_auth_0x85 - SetResultSize(1+4+8);//in:0 - cdvd.Result[0] = 0; - - cdvd.Result[1] = 0xeb; - cdvd.Result[2] = 0x01; - cdvd.Result[3] = 0xc7; - cdvd.Result[4] = 0xa9; - - cdvd.Result[ 5] = 0x3f; - cdvd.Result[ 6] = 0x9c; - cdvd.Result[ 7] = 0x5b; - cdvd.Result[ 8] = 0x19; - cdvd.Result[ 9] = 0x31; - cdvd.Result[10] = 0xa0; - cdvd.Result[11] = 0xb3; - cdvd.Result[12] = 0xa3; - break; - - case 0x86: // secrman: __mechacon_auth_0x86 - SetResultSize(1);//in:16 - cdvd.Result[0] = 0; - break; - - case 0x87: // secrman: __mechacon_auth_0x87 - SetResultSize(1);//in:8 - cdvd.Result[0] = 0; - break; - - case 0x8D: // sceMgWriteData - SetResultSize(1);//in:length<=16 - if (cdvd.mg_size + cdvd.ParamC > cdvd.mg_maxsize) - cdvd.Result[0] = 0x80; - else{ - memcpy_fast(cdvd.mg_buffer + cdvd.mg_size, cdvd.Param, cdvd.ParamC); - cdvd.mg_size += cdvd.ParamC; - cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error - } - break; - - case 0x8E: // sceMgReadData - SetResultSize( std::min(16, cdvd.mg_size) ); - memcpy_fast(cdvd.Result, cdvd.mg_buffer, cdvd.ResultC); - cdvd.mg_size -= cdvd.ResultC; - memcpy_fast(cdvd.mg_buffer, cdvd.mg_buffer+cdvd.ResultC, cdvd.mg_size); - break; - - case 0x88: // secrman: __mechacon_auth_0x88 //for now it is the same; so, fall;) - case 0x8F: // secrman: __mechacon_auth_0x8F - SetResultSize(1);//in:0 - if (cdvd.mg_datatype == 1){// header data - u64* psrc, *pdst; - int bit_ofs, i; - - if (cdvd.mg_maxsize != cdvd.mg_size) goto fail_pol_cal; - if (cdvd.mg_size < 0x20) goto fail_pol_cal; - if (cdvd.mg_size != *(u16*)&cdvd.mg_buffer[0x14]) goto fail_pol_cal; - SysPrintf("[MG] ELF_size=0x%X Hdr_size=0x%X unk=0x%X flags=0x%X count=%d zones=", - *(u32*)&cdvd.mg_buffer[0x10], *(u16*)&cdvd.mg_buffer[0x14], *(u16*)&cdvd.mg_buffer[0x16], - *(u16*)&cdvd.mg_buffer[0x18], *(u16*)&cdvd.mg_buffer[0x1A]); - for (i=0; i<8; i++) - if (cdvd.mg_buffer[0x1C] & (1<> 0) & 0xFF; - cdvd.Result[2] = (cdvd.mg_size >> 8) & 0xFF; - break; - - case 0x92: // sceMgWriteDatainLength - cdvd.mg_size = 0; - cdvd.mg_datatype = 0;//data (encrypted) - cdvd.mg_maxsize = cdvd.Param[0] | (((int)cdvd.Param[1])<<8); - SetResultSize(1);//in:2 - cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error - break; - - case 0x93: // sceMgWriteDataoutLength - SetResultSize(1);//in:2 - if (((cdvd.Param[0] | (((int)cdvd.Param[1])<<8)) == cdvd.mg_size) && (cdvd.mg_datatype == 0)){ - cdvd.mg_maxsize = 0; // don't allow any write - cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error - }else - cdvd.Result[0] = 0x80; - break; - - case 0x94: // sceMgReadKbit - read first half of BIT key - SetResultSize(1+8);//in:0 - cdvd.Result[0] = 0; - - ((int*)(cdvd.Result+1))[0] = ((int*)cdvd.mg_kbit)[0]; - ((int*)(cdvd.Result+1))[1] = ((int*)cdvd.mg_kbit)[1];//memcpy(cdvd.Result+1, cdvd.mg_kbit, 8); - break; - - case 0x95: // sceMgReadKbit2 - read second half of BIT key - SetResultSize(1+8);//in:0 - cdvd.Result[0] = 0; - ((int*)(cdvd.Result+1))[0] = ((int*)(cdvd.mg_kbit+8))[0]; - ((int*)(cdvd.Result+1))[1] = ((int*)(cdvd.mg_kbit+8))[1];//memcpy(cdvd.Result+1, cdvd.mg_kbit+8, 8); - break; - - case 0x96: // sceMgReadKcon - read first half of content key - SetResultSize(1+8);//in:0 - cdvd.Result[0] = 0; - ((int*)(cdvd.Result+1))[0] = ((int*)cdvd.mg_kcon)[0]; - ((int*)(cdvd.Result+1))[1] = ((int*)cdvd.mg_kcon)[1];//memcpy(cdvd.Result+1, cdvd.mg_kcon, 8); - break; - - case 0x97: // sceMgReadKcon2 - read second half of content key - SetResultSize(1+8);//in:0 - cdvd.Result[0] = 0; - ((int*)(cdvd.Result+1))[0] = ((int*)(cdvd.mg_kcon+8))[0]; - ((int*)(cdvd.Result+1))[1] = ((int*)(cdvd.mg_kcon+8))[1];//memcpy(cdvd.Result+1, cdvd.mg_kcon+8, 8); - break; - - default: - // fake a 'correct' command - SysPrintf("SCMD Unknown %x\n", rt); - SetResultSize(1); //in:0 - cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error - break; - } - //SysPrintf("SCMD - %x\n", rt); - cdvd.ParamP = 0; cdvd.ParamC = 0; -} - -void cdvdWrite17(u8 rt) { // SDATAIN - CDR_LOG("cdvdWrite17(SDataIn) %x\n", rt); - - if (cdvd.ParamP < 32) { - cdvd.Param[cdvd.ParamP++] = rt; - cdvd.ParamC++; - } -} - -void cdvdWrite18(u8 rt) { // SDATAOUT - CDR_LOG("cdvdWrite18(SDataOut) %x\n", rt); - SysPrintf("*PCSX2* SDATAOUT\n"); -} - -void cdvdWrite3A(u8 rt) { // DEC-SET - CDR_LOG("cdvdWrite3A(DecSet) %x\n", rt); - cdvd.decSet = rt; - SysPrintf("DecSet Write: %02X\n", cdvd.decSet); +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include +#include + +#ifndef _WIN32 +#include +#endif + +#include "PsxCommon.h" +#include "CDVDiso.h" + +static cdvdStruct cdvd; +static int cdCaseopen; + +/* +Interrupts - values are flag bits. + +0x00 No interrupt +0x01 Data Ready +0x02 Command Complete +0x03 Acknowledge (reserved) +0x04 End of Data Detected +0x05 Error Detected +0x06 Drive Not Ready + +In limited experimentation I found that PS2 apps respond actively to use of the +'Data Ready' flag -- in that they'll almost immediately initiate a DMA transfer +after receiving an Irq with that as the cause. But the question is, of course, +*when* to use it. Adding it into some locations of CDVD reading only slowed +games down and broke things. + +Using Drive Not Ready also invokes basic error handling from the Iop Bios, but +without proper emulation of the cdvd status flag it also tends to break things. + +*/ + +enum CdvdIrqId +{ + Irq_None = 0 +, Irq_DataReady = 0 +, Irq_CommandComplete +, Irq_Acknowledge +, Irq_EndOfData +, Irq_Error +, Irq_NotReady + +}; + +/* is cdvd.Status only for NCMDS? (linuzappz) */ +enum cdvdStatus +{ + CDVD_STATUS_NONE = 0x00, // not sure ;) + CDVD_STATUS_SEEK_COMPLETE = 0x0A, +}; + +// Cdvd actions tell the emulator how and when to respond to certain requests. +// Actions are handled by the cdvdInterrupt() +enum cdvdActions +{ + cdvdAction_None = 0 +, cdvdAction_Seek +, cdvdAction_Standby +, cdvdAction_Stop +, cdvdAction_Break +, cdvdAction_Read // note: not used yet. +}; + +////////////////////////////////////////////////////////////////////////// +// -- Cdvd Block Read Cycle Timings -- +// These timings are based on a median average block read speed. In theory the read +// speeds differ based on the location of the sector being read (outer rings have +// a different read speed from inner rings). But for our purposes an average is good +// enough, since all of Pcsx2's instruction cycle counting is hardly accurate anyway. + +// Morale of the story: don't get too caught up micro-managing your cycle timings. :) + +// Note: DVD read times are modified to be faster, because games seem to be a lot more +// concerned with accurate(ish) seek delays and less concerned with actual block read speeds. + +static const uint PSX_CD_READSPEED = 153600; // 1 Byte Time @ x1 (150KB = cd x 1) +static const uint PSX_DVD_READSPEED = 1382400 + 256000; // normal is 1 Byte Time @ x1 (1350KB = dvd x 1). + +enum CDVD_MODE_TYPE +{ + MODE_DVDROM, + MODE_CDROM +}; + +// if a seek is within this many blocks, read instead of seek. +// I picked 9 as an arbitrary value. Not sure what the real PS2 uses. +static const int Cdvd_Contigious_Seek = 9; +static const uint Cdvd_Avg_SeekCycles = (PSXCLK*40) / 1000; // average number of cycles per seek (40ms) + + + +static const char *mg_zones[8] = {"Japan", "USA", "Europe", "Oceania", "Asia", "Russia", "China", "Mexico"}; + +static const char *nCmdName[0x100]= { + "CdSync", "CdNop", "CdStandby", "CdStop", + "CdPause", "CdSeek", "CdRead", "CdReadCDDA", + "CdReadDVDV", "CdGetToc", "", "NCMD_B", + "CdReadKey", "", "sceCdReadXCDDA", "sceCdChgSpdlCtrl", +}; + +static const char *sCmdName[0x100]= { + "", "sceCdGetDiscType", "sceCdReadSubQ", "subcommands",//sceCdGetMecaconVersion, read/write console id, read renewal date + "", "sceCdTrayState", "sceCdTrayCtrl", "", + "sceCdReadClock", "sceCdWriteClock", "sceCdReadNVM", "sceCdWriteNVM", + "sceCdSetHDMode", "", "", "sceCdPowerOff", + "", "", "sceCdReadILinkID", "sceCdWriteILinkID", /*10*/ + "sceAudioDigitalOut", "sceForbidDVDP", "sceAutoAdjustCtrl", "sceCdReadModelNumber", + "sceWriteModelNumber", "sceCdForbidCD", "sceCdBootCertify", "sceCdCancelPOffRdy", + "sceCdBlueLEDCtl", "", "sceRm2Read", "sceRemote2_7",//Rm2PortGetConnection? + "sceRemote2_6", "sceCdWriteWakeUpTime", "sceCdReadWakeUpTime", "", /*20*/ + "sceCdRcBypassCtl", "", "", "", + "", "sceCdNoticeGameStart", "", "", + "sceCdXBSPowerCtl", "sceCdXLEDCtl", "sceCdBuzzerCtl", "", + "", "sceCdSetMediumRemoval", "sceCdGetMediumRemoval", "sceCdXDVRPReset", /*30*/ + "", "", "__sceCdReadRegionParams", "__sceCdReadMAC", + "__sceCdWriteMAC", "", "", "", + "", "", "__sceCdWriteRegionParams", "", + "sceCdOpenConfig", "sceCdReadConfig", "sceCdWriteConfig", "sceCdCloseConfig", /*40*/ + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", /*50*/ + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", /*60*/ + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", /*70*/ + "", "", "", "", + "", "", "", "", + "", "", "", "", + "mechacon_auth_0x80", "mechacon_auth_0x81", "mechacon_auth_0x82", "mechacon_auth_0x83", /*80*/ + "mechacon_auth_0x84", "mechacon_auth_0x85", "mechacon_auth_0x86", "mechacon_auth_0x87", + "mechacon_auth_0x88", "", "", "", + "", "sceMgWriteData", "sceMgReadData", "mechacon_auth_0x8F", + "sceMgWriteHeaderStart", "sceMgReadBITLength", "sceMgWriteDatainLength", "sceMgWriteDataoutLength", /*90*/ + "sceMgReadKbit", "sceMgReadKbit2", "sceMgReadKcon", "sceMgReadKcon2", + "sceMgReadIcvPs2", "", "", "", + "", "", "", "", + /*A0, no sCmds above?*/ +}; + +// NVM (eeprom) layout info +struct NVMLayout { + u32 biosVer; // bios version that this eeprom layout is for + s32 config0; // offset of 1st config block + s32 config1; // offset of 2nd config block + s32 config2; // offset of 3rd config block + s32 consoleId; // offset of console id (?) + s32 ilinkId; // offset of ilink id (ilink mac address) + s32 modelNum; // offset of ps2 model number (eg "SCPH-70002") + s32 regparams; // offset of RegionParams for PStwo + s32 mac; // offset of the value written to 0xFFFE0188 and 0xFFFE018C on PStwo +}; + +#define NVM_FORMAT_MAX 2 +NVMLayout nvmlayouts[NVM_FORMAT_MAX] = +{ + {0x000, 0x280, 0x300, 0x200, 0x1C8, 0x1C0, 0x1A0, 0x180, 0x198}, // eeproms from bios v0.00 and up + {0x146, 0x270, 0x2B0, 0x200, 0x1C8, 0x1E0, 0x1B0, 0x180, 0x198}, // eeproms from bios v1.70 and up +}; + +#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ +#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ + +#define SetResultSize(size) \ + cdvd.ResultC = size; cdvd.ResultP = 0; \ + cdvd.sDataIn&=~0x40; + +#define CDVDREAD_INT(eCycle) PSX_INT(IopEvt_CdvdRead, eCycle) +static void CDVD_INT(int eCycle) +{ + if( eCycle == 0 ) + cdvdActionInterrupt(); + else + PSX_INT(IopEvt_Cdvd, eCycle); +} + +// Sets the cdvd IRQ and the reason for the IRQ, and signals the IOP for a branch +// test (which will cause the exception to be handled). +static void cdvdSetIrq( uint id = (1< 0) { if (ptr[i] == '.') break; i--; } + ptr[i+1] = '\0'; + strcat(file, "MEC"); + + // if file doesnt exist, create empty one + fd = fopen(file, "r+b"); + if (fd == NULL) { + SysPrintf("MEC File Not Found , Creating Blank File\n"); + fd = fopen(file, "wb"); + if (fd == NULL) { + Msgbox::Alert("_cdvdOpenMechaVer: Error creating %s", params file); + exit(1); + } + fputc(0x03, fd); + fputc(0x06, fd); + fputc(0x02, fd); + fputc(0x00, fd); + } + return fd; +} + +s32 cdvdGetMechaVer(u8* ver) +{ + FILE* fd = _cdvdOpenMechaVer(); + if (fd == NULL) return 1; + fseek(fd, 0, SEEK_SET); + fread(ver, 1, 4, fd); + fclose(fd); + return 0; +} + +FILE *_cdvdOpenNVM() { + char *ptr; + int i; + string Bios; + char file[g_MaxPath]; + FILE* fd; + + // get the name of the bios file + Path::Combine( Bios, Config.BiosDir, Config.Bios ); + + // use the bios filename to get the name of the nvm file + // [TODO] : Upgrade this to use std::string! + + strcpy( file, Bios.c_str() ); + ptr = file; i = (int)strlen(file); + while (i > 0) { if (ptr[i] == '.') break; i--; } + ptr[i+1] = '\0'; + strcat(file, "NVM"); + + // if file doesnt exist, create empty one + fd = fopen(file, "r+b"); + if (fd == NULL) { + SysPrintf("NVM File Not Found , Creating Blank File\n"); + fd = fopen(file, "wb"); + if (fd == NULL) { + Msgbox::Alert("_cdvdOpenNVM: Error creating %s", params file); + exit(1); + } + for (i=0; i<1024; i++) fputc(0, fd); + } + return fd; +} + +// +// the following 'cdvd' functions all return 0 if successful +// + +s32 cdvdReadNVM(u8 *dst, int offset, int bytes) { + FILE* fd = _cdvdOpenNVM(); + if (fd == NULL) return 1; + fseek(fd, offset, SEEK_SET); + fread(dst, 1, bytes, fd); + fclose(fd); + return 0; +} +s32 cdvdWriteNVM(const u8 *src, int offset, int bytes) { + FILE* fd = _cdvdOpenNVM(); + if (fd == NULL) return 1; + fseek(fd, offset, SEEK_SET); + fwrite(src, 1, bytes, fd); + fclose(fd); + return 0; +} + +#define GET_NVM_DATA(buff, offset, size, fmtOffset) getNvmData(buff, offset, size, BiosVersion, offsetof(NVMLayout, fmtOffset)) +#define SET_NVM_DATA(buff, offset, size, fmtOffset) setNvmData(buff, offset, size, BiosVersion, offsetof(NVMLayout, fmtOffset)) + +s32 getNvmData(u8* buffer, s32 offset, s32 size, u32 biosVersion, s32 fmtOffset) +{ + // find the correct bios version + NVMLayout* nvmLayout = NULL; + s32 nvmIdx; + for(nvmIdx=0; nvmIdx= cdvd.CNumBlocks) + return 1; + else if( + ((cdvd.COffset == 0) && (cdvd.CBlockIndex >= 4))|| + ((cdvd.COffset == 1) && (cdvd.CBlockIndex >= 2))|| + ((cdvd.COffset == 2) && (cdvd.CBlockIndex >= 7)) + ) + { + memzero_ptr<16>(config); + return 0; + } + + // get config data + if(cdvd.COffset == 0) + return GET_NVM_DATA(config, (cdvd.CBlockIndex++)*16, 16, config0); else + if(cdvd.COffset == 2) + return GET_NVM_DATA(config, (cdvd.CBlockIndex++)*16, 16, config2); + else + return GET_NVM_DATA(config, (cdvd.CBlockIndex++)*16, 16, config1); +} +s32 cdvdWriteConfig(const u8* config) +{ + // make sure its in write mode + if(cdvd.CReadWrite != 1) + return 1; + // check if block index is in bounds + else if(cdvd.CBlockIndex >= cdvd.CNumBlocks) + return 1; + else if( + ((cdvd.COffset == 0) && (cdvd.CBlockIndex >= 4))|| + ((cdvd.COffset == 1) && (cdvd.CBlockIndex >= 2))|| + ((cdvd.COffset == 2) && (cdvd.CBlockIndex >= 7)) + ) + return 0; + + // get config data + if(cdvd.COffset == 0) + return SET_NVM_DATA(config, (cdvd.CBlockIndex++)*16, 16, config0); else + if(cdvd.COffset == 2) + return SET_NVM_DATA(config, (cdvd.CBlockIndex++)*16, 16, config2); + else + return SET_NVM_DATA(config, (cdvd.CBlockIndex++)*16, 16, config1); +} + + +void cdvdReadKey(u8 arg0, u16 arg1, u32 arg2, u8* key) { + char str[g_MaxPath]; + int numbers; + int letters; + unsigned int key_0_3; + unsigned char key_4; + unsigned char key_14; + char exeName[12]; + + // get main elf name + GetPS2ElfName(str); + sprintf(exeName, "%c%c%c%c%c%c%c%c%c%c%c",str[8],str[9],str[10],str[11],str[12],str[13],str[14],str[15],str[16],str[17],str[18]); + DevCon::Notice("exeName = %s", params &str[8]); + + // convert the number characters to a real 32bit number + numbers = ((((exeName[5] - '0'))*10000) + + (((exeName[ 6] - '0'))*1000) + + (((exeName[ 7] - '0'))*100) + + (((exeName[ 9] - '0'))*10) + + (((exeName[10] - '0'))*1) ); + + // combine the lower 7 bits of each char + // to make the 4 letters fit into a single u32 + letters = (int)((exeName[3]&0x7F)<< 0) | + (int)((exeName[2]&0x7F)<< 7) | + (int)((exeName[1]&0x7F)<<14) | + (int)((exeName[0]&0x7F)<<21); + + // calculate magic numbers + key_0_3 = ((numbers & 0x1FC00) >> 10) | ((0x01FFFFFF & letters) << 7); // numbers = 7F letters = FFFFFF80 + key_4 = ((numbers & 0x0001F) << 3) | ((0x0E000000 & letters) >> 25); // numbers = F8 letters = 07 + key_14 = ((numbers & 0x003E0) >> 2) | 0x04; // numbers = F8 extra = 04 unused = 03 + + // clear key values + memzero_ptr<16>(key); + + // store key values + key[ 0] = (key_0_3&0x000000FF)>> 0; + key[ 1] = (key_0_3&0x0000FF00)>> 8; + key[ 2] = (key_0_3&0x00FF0000)>>16; + key[ 3] = (key_0_3&0xFF000000)>>24; + key[ 4] = key_4; + + if(arg2 == 75) + { + key[14] = key_14; + key[15] = 0x05; + } + else if(arg2 == 3075) + { + key[15] = 0x01; + } + else if(arg2 == 4246) + { + // 0x0001F2F707 = sector 0x0001F2F7 dec 0x07 + key[ 0] = 0x07; + key[ 1] = 0xF7; + key[ 2] = 0xF2; + key[ 3] = 0x01; + key[ 4] = 0x00; + key[15] = 0x01; + } + else + { + key[15] = 0x01; + } + + Console::WriteLn( "CDVD.KEY = %02X,%02X,%02X,%02X,%02X,%02X,%02X", params + cdvd.Key[0],cdvd.Key[1],cdvd.Key[2],cdvd.Key[3],cdvd.Key[4],cdvd.Key[14],cdvd.Key[15] ); + + // Now's a good time to reload the ELF info... + if( ElfCRC == 0 ) + { + ElfCRC = loadElfCRC( str ); + ElfApplyPatches(); + LoadGameSpecificSettings(); + } +} + +s32 cdvdGetToc(void* toc) +{ + s32 ret = CDVDgetTOC(toc); + if(ret == -1) ret = 0x80; + return ret; +/* + cdvdTN diskInfo; + cdvdTD trackInfo; + u8 _time[3]; + u32 type; + int i, err; + + //Param[0] is 0 for CdGetToc and any value for cdvdman_call19 + //the code below handles only CdGetToc! + //if(cdvd.Param[0]==0x01) + //{ + SysPrintf("CDGetToc Param[0]=%d, Param[1]=%d\n",cdvd.Param[0],cdvd.Param[1]); + //} + type = CDVDgetDiskType(); + if (CDVDgetTN(&diskInfo) == -1) { diskInfo.etrack = 0;diskInfo.strack = 1; } + if (CDVDgetTD(0, &trackInfo) == -1) trackInfo.lsn = 0; + + if (type == CDVD_TYPE_CDDA) { + PSXMu8(HW_DMA3_MADR+ 0) = 0x01; + } else + if (type == CDVD_TYPE_PS2DVD) { + if (trackInfo.lsn >= (2048*1024)) { // dual sided + PSXMu8(HW_DMA3_MADR+ 0) = 0x24; + } else { + PSXMu8(HW_DMA3_MADR+ 0) = 0x04; + } + } else + if (type == CDVD_TYPE_PS2CD) { + PSXMu8(HW_DMA3_MADR+ 0) = 0x41; + } + + if (PSXMu8(HW_DMA3_MADR+ 0) & 0x04) { + PSXMu8(HW_DMA3_MADR+ 1) = 0x02; + PSXMu8(HW_DMA3_MADR+ 2) = 0xF2; + PSXMu8(HW_DMA3_MADR+ 3) = 0x00; + + if (PSXMu8(HW_DMA3_MADR+ 0) & 0x20) { + PSXMu8(HW_DMA3_MADR+ 4) = 0x41; + PSXMu8(HW_DMA3_MADR+ 5) = 0x95; + } else { + PSXMu8(HW_DMA3_MADR+ 4) = 0x86; + PSXMu8(HW_DMA3_MADR+ 5) = 0x72; + } + PSXMu8(HW_DMA3_MADR+ 6) = 0x00; + PSXMu8(HW_DMA3_MADR+ 7) = 0x00; + PSXMu8(HW_DMA3_MADR+ 8) = 0x00; + PSXMu8(HW_DMA3_MADR+ 9) = 0x00; + PSXMu8(HW_DMA3_MADR+10) = 0x00; + PSXMu8(HW_DMA3_MADR+11) = 0x00; + + PSXMu8(HW_DMA3_MADR+12) = 0x00; + PSXMu8(HW_DMA3_MADR+13) = 0x00; + PSXMu8(HW_DMA3_MADR+14) = 0x00; + PSXMu8(HW_DMA3_MADR+15) = 0x00; + + PSXMu8(HW_DMA3_MADR+16) = 0x00; + PSXMu8(HW_DMA3_MADR+17) = 0x03; + PSXMu8(HW_DMA3_MADR+18) = 0x00; + PSXMu8(HW_DMA3_MADR+19) = 0x00; + + } else { + PSXMu8(HW_DMA3_MADR+ 1) = 0x00; + PSXMu8(HW_DMA3_MADR+ 2) = 0xA0; + PSXMu8(HW_DMA3_MADR+ 7) = itob(diskInfo.strack);//Number of FirstTrack + + PSXMu8(HW_DMA3_MADR+12) = 0xA1; + PSXMu8(HW_DMA3_MADR+17) = itob(diskInfo.etrack);//Number of LastTrack + + PSXMu8(HW_DMA3_MADR+22) = 0xA2;//DiskLength + LSNtoMSF(_time, trackInfo.lsn); + PSXMu8(HW_DMA3_MADR+27) = itob(_time[2]); + PSXMu8(HW_DMA3_MADR+28) = itob(_time[1]); + + for (i=diskInfo.strack; i<=diskInfo.etrack; i++) { + err=CDVDgetTD(i, &trackInfo); + LSNtoMSF(_time, trackInfo.lsn); + PSXMu8(HW_DMA3_MADR+i*10+30) = trackInfo.type; + PSXMu8(HW_DMA3_MADR+i*10+32) = err == -1 ? 0 : itob(i); //number + PSXMu8(HW_DMA3_MADR+i*10+37) = itob(_time[2]); + PSXMu8(HW_DMA3_MADR+i*10+38) = itob(_time[1]); + PSXMu8(HW_DMA3_MADR+i*10+39) = itob(_time[0]); + } + } +*/ +} + +s32 cdvdReadSubQ(s32 lsn, cdvdSubQ* subq) +{ + s32 ret = CDVDreadSubQ(lsn, subq); + if(ret == -1) ret = 0x80; + return ret; +} + +s32 cdvdCtrlTrayOpen() +{ + s32 ret = CDVDctrlTrayOpen(); + if(ret == -1) ret = 0x80; + return ret; +} + +s32 cdvdCtrlTrayClose() +{ + s32 ret = CDVDctrlTrayClose(); + if(ret == -1) ret = 0x80; + return ret; +} + +// Modified by (efp) - 16/01/2006 +// checks if tray was opened since last call to this func +s32 cdvdGetTrayStatus() +{ + s32 ret = CDVDgetTrayStatus(); + // get current tray state + if (cdCaseopen) return(CDVD_TRAY_OPEN); + + + if (ret == -1) return(CDVD_TRAY_CLOSE); + return(ret); +} + +// Note: Is tray status being kept as a var here somewhere? +// cdvdNewDiskCB() can update it's status as well... + +// Modified by (efp) - 16/01/2006 +__forceinline void cdvdGetDiskType() +{ + // defs 0.9.0 + if(CDVDnewDiskCB || cdvd.Type != CDVD_TYPE_NODISC) return; + + // defs.0.8.1 + if(cdvdGetTrayStatus() == CDVD_TRAY_OPEN) + { + cdvd.Type = CDVD_TYPE_NODISC; + return; + } + + cdvd.Type = CDVDgetDiskType(); + if (cdvd.Type == CDVD_TYPE_PS2CD) // && needReset == 1) + { + char str[g_MaxPath]; + if (GetPS2ElfName(str) == 1) + { + cdvd.Type = CDVD_TYPE_PSCD; + } // ENDIF- Does the SYSTEM.CNF file only say "BOOT="? PS1 CD then. + } // ENDIF- Is the type listed as a PS2 CD? +} // END cdvdGetDiskType() + + +// check whether disc is single or dual layer +// if its dual layer, check what the disctype is and what sector number +// layer1 starts at +// +// args: gets value for dvd type (0=single layer, 1=ptp, 2=otp) +// gets value for start lsn of layer1 +// returns: 1 if on dual layer disc +// 0 if not on dual layer disc +s32 cdvdReadDvdDualInfo(s32* dualType, u32* layer1Start) +{ + u8 toc[2064]; + *dualType = 0; + *layer1Start = 0; + + // if error getting toc, settle for single layer disc ;) + if(cdvdGetToc(toc)) + return 0; + if(toc[14] & 0x60) + { + if(toc[14] & 0x10) + { + // otp dvd + *dualType = 2; + *layer1Start = (toc[25]<<16) + (toc[26]<<8) + (toc[27]) - 0x30000 + 1; + } + else + { + // ptp dvd + *dualType = 1; + *layer1Start = (toc[21]<<16) + (toc[22]<<8) + (toc[23]) - 0x30000 + 1; + } + } + else + { + // single layer dvd + *dualType = 0; + *layer1Start = (toc[21]<<16) + (toc[22]<<8) + (toc[23]) - 0x30000 + 1; + } + + return 1; +} + + +#include + +static uint cdvdBlockReadTime( CDVD_MODE_TYPE mode ) +{ + return (PSXCLK * cdvd.BlockSize) / (((mode==MODE_CDROM) ? PSX_CD_READSPEED : PSX_DVD_READSPEED) * cdvd.Speed); +} + +void cdvdReset() +{ +#ifdef _WIN32 + SYSTEMTIME st; + //Get and set the internal clock to time + GetSystemTime(&st); +#else + time_t traw; + struct tm* ptlocal; + time(&traw); + ptlocal = localtime(&traw); +#endif + + memzero_obj(cdvd); + + cdvd.Type = CDVD_TYPE_NODISC; + cdvd.Spinning = false; + + cdvd.sDataIn = 0x40; + cdvd.Ready = 0x4e; + cdCaseopen = 0; + cdvd.Speed = 4; + cdvd.BlockSize = 2064; + cdvd.Action = cdvdAction_None; + cdvd.ReadTime = cdvdBlockReadTime( MODE_DVDROM ); + + // any random valid date will do + cdvd.RTC.hour = 1; + cdvd.RTC.day = 25; + cdvd.RTC.month = 5; + cdvd.RTC.year = 7; //2007 + +#ifndef _DEBUG +#ifdef _WIN32 + cdvd.RTC.second = (u8)(st.wSecond); + cdvd.RTC.minute = (u8)(st.wMinute); + cdvd.RTC.hour = (u8)(st.wHour+1)%24; + cdvd.RTC.day = (u8)(st.wDay); + cdvd.RTC.month = (u8)(st.wMonth); + cdvd.RTC.year = (u8)(st.wYear - 2000); +#else + cdvd.RTC.second = ptlocal->tm_sec; + cdvd.RTC.minute = ptlocal->tm_min; + cdvd.RTC.hour = ptlocal->tm_hour; + cdvd.RTC.day = ptlocal->tm_mday; + cdvd.RTC.month = ptlocal->tm_mon; + cdvd.RTC.year = ptlocal->tm_year; +#endif +#endif + +} + +struct Freeze_v10Compat +{ + u8 Action; + u32 SeekToSector; + u32 ReadTime; + bool Spinning; +}; + +void SaveState::cdvdFreeze() +{ + if( GetVersion() <= 0x10 ) + { + // the old cdvd struct didn't save the last few items. + FreezeLegacy( cdvd, sizeof(Freeze_v10Compat) ); + cdvd.SeekToSector = cdvd.Sector; + cdvd.Action = cdvdAction_None; + cdvd.ReadTime = cdvdBlockReadTime( MODE_DVDROM ); + cdvd.Spinning = true; + } + else + Freeze( cdvd ); + + if( IsLoading() ) + { + // Make sure the Cdvd plugin has the expected track loaded into the buffer. + // If cdvd.Readed is cleared it means we need to load the SeekToSector (ie, a + // seek is in progress!) + + if( cdvd.Reading ) + cdvd.RErr = CDVDreadTrack( cdvd.Readed ? cdvd.Sector : cdvd.SeekToSector, cdvd.ReadMode); + } +} + +// Modified by (efp) - 16/01/2006 +void cdvdNewDiskCB() +{ + cdvd.Type = CDVDgetDiskType(); + if(cdvd.Type == CDVD_TYPE_PS2CD) { + char str[g_MaxPath]; + if(GetPS2ElfName(str) == 1) { + cdvd.Type = CDVD_TYPE_PSCD; + } // ENDIF- Does the SYSTEM.CNF file only say "BOOT="? PS1 CD then. + } +} + +void mechaDecryptBytes(unsigned char* buffer, int size) +{ + int i; + + int shiftAmount = (cdvd.decSet>>4) & 7; + int doXor = (cdvd.decSet) & 1; + int doShift = (cdvd.decSet) & 2; + + for (i=0; i>shiftAmount) | (buffer[i]<<(8-shiftAmount)); + } +} + +int cdvdReadSector() { + s32 bcr; + + CDR_LOG("SECTOR %d (BCR %x;%x)\n", cdvd.Sector, HW_DMA3_BCR_H16, HW_DMA3_BCR_L16); + + bcr = (HW_DMA3_BCR_H16 * HW_DMA3_BCR_L16) *4; + if (bcr < cdvd.BlockSize) { + CDR_LOG( "READBLOCK: bcr < cdvd.BlockSize; %x < %x\n", bcr, cdvd.BlockSize ); + if (HW_DMA3_CHCR & 0x01000000) { + HW_DMA3_CHCR &= ~0x01000000; + psxDmaInterrupt(3); + } + return -1; + } + + const u32 madr = HW_DMA3_MADR; + + // if raw dvd sector 'fill in the blanks' + if (cdvd.BlockSize == 2064) { + // get info on dvd type and layer1 start + u32 layer1Start; + s32 dualType; + s32 layerNum; + u32 lsn = cdvd.Sector; + + cdvdReadDvdDualInfo(&dualType, &layer1Start); + + if((dualType == 1) && (lsn >= layer1Start)) { + // dual layer ptp disc + layerNum = 1; + lsn = lsn-layer1Start + 0x30000; + } else if((dualType == 2) && (lsn >= layer1Start)) { + // dual layer otp disc + layerNum = 1; + lsn = ~(layer1Start+0x30000 - 1); + } else { + // single layer disc + // or on first layer of dual layer disc + layerNum = 0; + lsn += 0x30000; + } // ENDLONGIF- Assumed the other dualType is 0. + + PSXMu8(madr+0) = 0x20 | layerNum; + PSXMu8(madr+1) = (u8)(lsn >> 16); + PSXMu8(madr+2) = (u8)(lsn >> 8); + PSXMu8(madr+3) = (u8)(lsn ); + + // sector IED (not calculated at present) + PSXMu8(madr+4) = 0; + PSXMu8(madr+5) = 0; + + // sector CPR_MAI (not calculated at present) + PSXMu8(madr+ 6) = 0; + PSXMu8(madr+ 7) = 0; + PSXMu8(madr+ 8) = 0; + PSXMu8(madr+ 9) = 0; + PSXMu8(madr+10) = 0; + PSXMu8(madr+11) = 0; + + // normal 2048 bytes of sector data + memcpy_fast(PSXM(madr+12), cdr.pTransfer, 2048); + + // 4 bytes of edc (not calculated at present) + PSXMu8(madr+2060) = 0; + PSXMu8(madr+2061) = 0; + PSXMu8(madr+2062) = 0; + PSXMu8(madr+2063) = 0; + } else { + // normal read + memcpy_fast((u8*)PSXM(madr), cdr.pTransfer, cdvd.BlockSize); + } + // decrypt sector's bytes + if(cdvd.decSet) + mechaDecryptBytes((u8*)PSXM(madr), cdvd.BlockSize); + + // Added a clear after memory write .. never seemed to be necessary before but *should* + // be more correct. (air) + psxCpu->Clear( madr, cdvd.BlockSize/4); + +// SysPrintf("sector %x;%x;%x\n", PSXMu8(madr+0), PSXMu8(madr+1), PSXMu8(madr+2)); + + HW_DMA3_BCR_H16-= (cdvd.BlockSize / (HW_DMA3_BCR_L16*4)); + HW_DMA3_MADR+= cdvd.BlockSize; + + return 0; +} + +// inlined due to being referenced in only one place. +__forceinline void cdvdActionInterrupt() +{ + switch( cdvd.Action ) + { + case cdvdAction_Seek: + case cdvdAction_Standby: + cdvd.Spinning = true; + cdvd.Ready = 0x40; + cdvd.Sector = cdvd.SeekToSector; + cdvd.Status = CDVD_STATUS_SEEK_COMPLETE; + break; + + case cdvdAction_Stop: + cdvd.Spinning = false; + cdvd.Ready = 0x40; + cdvd.Sector = 0; + cdvd.Status = 0; + break; + + case cdvdAction_Break: + // Make sure the cdvd action state is pretty well cleared: + cdvd.Reading = 0; + cdvd.Readed = 0; + cdvd.Ready = 0x4e; // should be 0x40 or something else? + cdvd.Status = 0; + cdvd.RErr = 0; + cdvd.nCommand = 0; + break; + } + cdvd.Action = cdvdAction_None; + + cdvd.PwOff |= 1< Scheduling block read interrupt at iopcycle=%8.8x.\n", + psxRegs.cycle + cdvd.ReadTime ); + + CDVDREAD_INT(cdvd.ReadTime); + return; + } + + if (cdvd.Reading == 1) { + if (cdvd.RErr == 0) { + cdr.pTransfer = CDVDgetBuffer(); + } else cdr.pTransfer = NULL; + if (cdr.pTransfer == NULL) { + cdvd.RetryCntP++; + Console::Error("CDVD READ ERROR, sector=%d", params cdvd.Sector); + if (cdvd.RetryCntP <= cdvd.RetryCnt) { + cdvd.RErr = CDVDreadTrack(cdvd.Sector, cdvd.ReadMode); + CDVDREAD_INT(cdvd.ReadTime); + return; + } + } + cdvd.Reading = 0; + } + + if (cdvdReadSector() == -1) { + assert( (int)cdvd.ReadTime > 0 ); + CDVDREAD_INT(cdvd.ReadTime); + return; + } + + cdvd.Sector++; + + if (--cdvd.nSectors <= 0) + { + cdvd.PwOff |= 1<= cdvd.ResultC) cdvd.sDataIn|= 0x40; + ret = cdvd.Result[cdvd.ResultP-1]; + } + } + CDR_LOG("cdvdRead18(SDataOut) %x (ResultC=%d, ResultP=%d)\n", ret, cdvd.ResultC, cdvd.ResultP); + return ret; +} + +u8 cdvdRead20(void) { + CDR_LOG("cdvdRead20(Key0) %x\n", cdvd.Key[0]); + + return cdvd.Key[0]; +} + +u8 cdvdRead21(void) { + CDR_LOG("cdvdRead21(Key1) %x\n", cdvd.Key[1]); + + return cdvd.Key[1]; +} + +u8 cdvdRead22(void) { + CDR_LOG("cdvdRead22(Key2) %x\n", cdvd.Key[2]); + + return cdvd.Key[2]; +} + +u8 cdvdRead23(void) { + CDR_LOG("cdvdRead23(Key3) %x\n", cdvd.Key[3]); + + return cdvd.Key[3]; +} + +u8 cdvdRead24(void) { + CDR_LOG("cdvdRead24(Key4) %x\n", cdvd.Key[4]); + + return cdvd.Key[4]; +} + +u8 cdvdRead28(void) { + CDR_LOG("cdvdRead28(Key5) %x\n", cdvd.Key[5]); + + return cdvd.Key[5]; +} + +u8 cdvdRead29(void) { + CDR_LOG("cdvdRead29(Key6) %x\n", cdvd.Key[6]); + + return cdvd.Key[6]; +} + +u8 cdvdRead2A(void) { + CDR_LOG("cdvdRead2A(Key7) %x\n", cdvd.Key[7]); + + return cdvd.Key[7]; +} + +u8 cdvdRead2B(void) { + CDR_LOG("cdvdRead2B(Key8) %x\n", cdvd.Key[8]); + + return cdvd.Key[8]; +} + +u8 cdvdRead2C(void) { + CDR_LOG("cdvdRead2C(Key9) %x\n", cdvd.Key[9]); + + return cdvd.Key[9]; +} + +u8 cdvdRead30(void) { + CDR_LOG("cdvdRead30(Key10) %x\n", cdvd.Key[10]); + + return cdvd.Key[10]; +} + +u8 cdvdRead31(void) { + CDR_LOG("cdvdRead31(Key11) %x\n", cdvd.Key[11]); + + return cdvd.Key[11]; +} + +u8 cdvdRead32(void) { + CDR_LOG("cdvdRead32(Key12) %x\n", cdvd.Key[12]); + + return cdvd.Key[12]; +} + +u8 cdvdRead33(void) { + CDR_LOG("cdvdRead33(Key13) %x\n", cdvd.Key[13]); + + return cdvd.Key[13]; +} + +u8 cdvdRead34(void) { + CDR_LOG("cdvdRead34(Key14) %x\n", cdvd.Key[14]); + + return cdvd.Key[14]; +} + +u8 cdvdRead38(void) { // valid parts of key data (first and last are valid) + CDR_LOG("cdvdRead38(KeysValid) %x\n", cdvd.Key[15]); + + return cdvd.Key[15]; +} + +u8 cdvdRead39(void) { // KEY-XOR + CDR_LOG("cdvdRead39(KeyXor) %x\n", cdvd.KeyXor); + + return cdvd.KeyXor; +} + +u8 cdvdRead3A(void) { // DEC_SET + CDR_LOG("cdvdRead3A(DecSet) %x\n", cdvd.decSet); + + SysPrintf("DecSet Read: %02X\n", cdvd.decSet); + return cdvd.decSet; +} + + +// Returns the number of IOP cycles until the event completes. +static uint cdvdStartSeek( uint newsector ) +{ + cdvd.SeekToSector = newsector; + + uint delta = abs(cdvd.SeekToSector - cdvd.Sector); + uint seektime; + + cdvd.Ready = 0; + cdvd.Reading = 0; + cdvd.Readed = 0; + cdvd.Status = 0; + + if( !cdvd.Spinning ) + { + CDR_LOG( "CdSpinUp > Simulating CdRom Spinup Time, and seek to sector %d\n", cdvd.SeekToSector ); + seektime = PSXCLK / 3; // 333ms delay + cdvd.Spinning = true; + } + else if( (Cdvd_Contigious_Seek >= 0) && (delta >= Cdvd_Contigious_Seek) ) + { + CDR_LOG( "CdSeek Begin > to sector %d, from %d - delta=%d\n", cdvd.SeekToSector, cdvd.Sector, delta ); + seektime = Cdvd_Avg_SeekCycles; + } + else + { + CDR_LOG( "CdSeek Begin > Contigious block without seek - delta=%d sectors\n", delta ); + + // seektime is the time it takes to read to the destination block: + seektime = delta * cdvd.ReadTime; + + if( delta == 0 ) + { + cdvd.Status = CDVD_STATUS_SEEK_COMPLETE; + cdvd.Readed = 1; + cdvd.RetryCntP = 0; + + // setting Readed to zero skips the seek logic, which means the next call to + // cdvdReadInterrupt will load a block. So make sure it's properly scheduled + // based on sector read speeds: + seektime = cdvd.ReadTime; + } + } + + return seektime; +} + +void cdvdWrite04(u8 rt) { // NCOMMAND + CDR_LOG("cdvdWrite04: NCMD %s (%x) (ParamP = %x)\n", nCmdName[rt], rt, cdvd.ParamP); + + cdvd.nCommand = rt; + cdvd.Status = CDVD_STATUS_NONE; + cdvd.PwOff = Irq_None; // good or bad? + + switch (rt) { + case 0x00: // CdSync + case 0x01: // CdNop_ + cdvdSetIrq(); + break; + + case 0x02: // CdStandby + + // Seek to sector zero. The cdvdStartSeek function will simulate + // spinup times if needed. + + DevCon::Notice( "CdStandby : %d", params rt ); + cdvd.Action = cdvdAction_Standby; + cdvd.ReadTime = cdvdBlockReadTime( MODE_DVDROM ); + CDVD_INT( cdvdStartSeek( 0 ) ); + break; + + case 0x03: // CdStop + DevCon::Notice( "CdStop : %d", params rt ); + cdvd.Action = cdvdAction_Stop; + CDVD_INT( PSXCLK / 6 ); // 166ms delay? + break; + + // from an emulation point of view there is not much need to do anything for this one + case 0x04: // CdPause + cdvdSetIrq(); + break; + + case 0x05: // CdSeek + cdvd.Action = cdvdAction_Seek; + cdvd.ReadTime = cdvdBlockReadTime( MODE_DVDROM ); + CDVD_INT( cdvdStartSeek( *(uint*)(cdvd.Param+0) ) ); + break; + + case 0x06: // CdRead + cdvd.SeekToSector = *(uint*)(cdvd.Param+0); + cdvd.nSectors = *(int*)(cdvd.Param+4); + cdvd.RetryCnt = (cdvd.Param[8] == 0) ? 0x100 : cdvd.Param[8]; + cdvd.SpindlCtrl = cdvd.Param[9]; + cdvd.Speed = 24; + switch (cdvd.Param[10]) { + case 2: cdvd.ReadMode = CDVD_MODE_2340; cdvd.BlockSize = 2340; break; + case 1: cdvd.ReadMode = CDVD_MODE_2328; cdvd.BlockSize = 2328; break; + case 0: default: cdvd.ReadMode = CDVD_MODE_2048; cdvd.BlockSize = 2048; break; + } + + CDR_LOG( "CdRead > startSector=%d, nSectors=%d, RetryCnt=%x, Speed=%x(%x), ReadMode=%x(%x) (1074=%x)\n", + cdvd.Sector, cdvd.nSectors, cdvd.RetryCnt, cdvd.Speed, cdvd.Param[9], cdvd.ReadMode, cdvd.Param[10], psxHu32(0x1074)); + + if (Config.cdvdPrint) SysPrintf("CdRead: Reading Sector %d(%d Blocks of Size %d) at Speed=%dx\n", cdvd.Sector, cdvd.nSectors,cdvd.BlockSize,cdvd.Speed); + + cdvd.ReadTime = cdvdBlockReadTime( MODE_CDROM ); + CDVDREAD_INT( cdvdStartSeek( cdvd.SeekToSector ) ); + + // Read-ahead by telling the plugin about the track now. + // This helps improve performance on actual from-cd emulation + // (ie, not using the hard drive) + cdvd.RErr = CDVDreadTrack( cdvd.SeekToSector, cdvd.ReadMode ); + + // Set the reading block flag. If a seek is pending then Readed will + // take priority in the handler anyway. If the read is contigeous then + // this'll skip the seek delay. + cdvd.Reading = 1; + break; + + case 0x07: // CdReadCDDA + case 0x0E: // CdReadXCDDA + cdvd.SeekToSector = *(int*)(cdvd.Param+0); + cdvd.nSectors = *(int*)(cdvd.Param+4); + if (cdvd.Param[8] == 0) cdvd.RetryCnt = 0x100; + else cdvd.RetryCnt = cdvd.Param[8]; + cdvd.SpindlCtrl = cdvd.Param[9]; + switch (cdvd.Param[9]) { + case 0x01: cdvd.Speed = 1; break; + case 0x02: cdvd.Speed = 2; break; + case 0x03: cdvd.Speed = 4; break; + case 0x04: cdvd.Speed = 12; break; + default: cdvd.Speed = 24; break; + } + switch (cdvd.Param[10]) { + case 1: cdvd.ReadMode = CDVD_MODE_2368; cdvd.BlockSize = 2368; break; + case 2: + case 0: cdvd.ReadMode = CDVD_MODE_2352; cdvd.BlockSize = 2352; break; + } + + CDR_LOG( "CdReadCDDA > startSector=%d, nSectors=%d, RetryCnt=%x, Speed=%xx(%x), ReadMode=%x(%x) (1074=%x)\n", + cdvd.Sector, cdvd.nSectors, cdvd.RetryCnt, cdvd.Speed, cdvd.Param[9], cdvd.ReadMode, cdvd.Param[10], psxHu32(0x1074)); + + if (Config.cdvdPrint) SysPrintf("CdAudioRead: Reading Sector %d(%d Blocks of Size %d) at Speed=%dx\n", cdvd.Sector, cdvd.nSectors,cdvd.BlockSize,cdvd.Speed); + + cdvd.ReadTime = cdvdBlockReadTime( MODE_CDROM ); + CDVDREAD_INT( cdvdStartSeek( cdvd.SeekToSector ) ); + + // Read-ahead by telling the plugin about the track now. + // This helps improve performance on actual from-cd emulation + // (ie, not using the hard drive) + cdvd.RErr = CDVDreadTrack( cdvd.SeekToSector, cdvd.ReadMode ); + + // Set the reading block flag. If a seek is pending then Readed will + // take priority in the handler anyway. If the read is contigeous then + // this'll skip the seek delay. + cdvd.Reading = 1; + break; + + case 0x08: // DvdRead + cdvd.SeekToSector = *(int*)(cdvd.Param+0); + cdvd.nSectors = *(int*)(cdvd.Param+4); + if (cdvd.Param[8] == 0) cdvd.RetryCnt = 0x100; + else cdvd.RetryCnt = cdvd.Param[8]; + cdvd.SpindlCtrl = cdvd.Param[9]; + cdvd.Speed = 4; + cdvd.ReadMode = CDVD_MODE_2048; + cdvd.BlockSize = 2064; // Why oh why was it 2064 + + CDR_LOG( "DvdRead > startSector=%d, nSectors=%d, RetryCnt=%x, Speed=%x(%x), ReadMode=%x(%x) (1074=%x)\n", + cdvd.Sector, cdvd.nSectors, cdvd.RetryCnt, cdvd.Speed, cdvd.Param[9], cdvd.ReadMode, cdvd.Param[10], psxHu32(0x1074)); + + if (Config.cdvdPrint) SysPrintf("DvdRead: Reading Sector %d(%d Blocks of Size %d) at Speed=%dx\n", cdvd.Sector, cdvd.nSectors,cdvd.BlockSize,cdvd.Speed); + + cdvd.ReadTime = cdvdBlockReadTime( MODE_DVDROM ); + CDVDREAD_INT( cdvdStartSeek( cdvd.SeekToSector ) ); + + // Read-ahead by telling the plugin about the track now. + // This helps improve performance on actual from-cd emulation + // (ie, not using the hard drive) + cdvd.RErr = CDVDreadTrack( cdvd.SeekToSector, cdvd.ReadMode ); + + // Set the reading block flag. If a seek is pending then Readed will + // take priority in the handler anyway. If the read is contigeous then + // this'll skip the seek delay. + cdvd.Reading = 1; + break; + + case 0x09: // CdGetToc & cdvdman_call19 + //Param[0] is 0 for CdGetToc and any value for cdvdman_call19 + //the code below handles only CdGetToc! + //if(cdvd.Param[0]==0x01) + //{ + DevCon::WriteLn("CDGetToc Param[0]=%d, Param[1]=%d", params cdvd.Param[0],cdvd.Param[1]); + //} + cdvdGetToc( PSXM( HW_DMA3_MADR ) ); + cdvdSetIrq( (1< remote key code + SetResultSize(5); + cdvd.Result[0] = 0x00; + cdvd.Result[1] = 0x14; + cdvd.Result[2] = 0x00; + cdvd.Result[3] = 0x00; + cdvd.Result[4] = 0x00; + break; + +// case 0x1F: // sceRemote2_7 (2:1) - cdvdman_call117 +// break; + + case 0x20: // sceRemote2_6 (0:3) // 00 01 00 + SetResultSize(3); + cdvd.Result[0] = 0x00; + cdvd.Result[1] = 0x01; + cdvd.Result[2] = 0x00; + break; + +// case 0x21: // sceCdWriteWakeUpTime (8:1) +// break; + + case 0x22: // sceCdReadWakeUpTime (0:10) + SetResultSize(10); + cdvd.Result[0] = 0; + cdvd.Result[1] = 0; + cdvd.Result[2] = 0; + cdvd.Result[3] = 0; + cdvd.Result[4] = 0; + cdvd.Result[5] = 0; + cdvd.Result[6] = 0; + cdvd.Result[7] = 0; + cdvd.Result[8] = 0; + cdvd.Result[9] = 0; + break; + + case 0x24: // sceCdRCBypassCtrl (1:1) - In V10 Bios + // FIXME: because PRId<0x23, the bit 0 of sio2 don't get updated 0xBF808284 + SetResultSize(1); + cdvd.Result[0] = 0; + break; + +// case 0x25: // cdvdman_call120 (1:1) - In V10 Bios +// break; + +// case 0x26: // cdvdman_call128 (0,3) - In V10 Bios +// break; + +// case 0x27: // cdvdman_call148 (0:13) - In V10 Bios +// break; + +// case 0x28: // cdvdman_call150 (1:1) - In V10 Bios +// break; + + case 0x29: //sceCdNoticeGameStart (1:1) + SetResultSize(1); + cdvd.Result[0] = 0; + break; + +// case 0x2C: //sceCdXBSPowerCtl (2:2) +// break; + +// case 0x2D: //sceCdXLEDCtl (2:2) +// break; + +// case 0x2E: //sceCdBuzzerCtl (0:1) +// break; + +// case 0x2F: //cdvdman_call167 (16:1) +// break; + +// case 0x30: //cdvdman_call169 (1:9) +// break; + + case 0x31: //sceCdSetMediumRemoval (1:1) + SetResultSize(1); + cdvd.Result[0] = 0; + break; + + case 0x32: //sceCdGetMediumRemoval (0:2) + SetResultSize(2); + cdvd.Result[0] = 0; + cdvd.Result[0] = 0; + break; + +// case 0x33: //sceCdXDVRPReset (1:1) +// break; + + case 0x36: //cdvdman_call189 [__sceCdReadRegionParams - made up name] (0:15) i think it is 16, not 15 + SetResultSize(15); + cdvdGetMechaVer(&cdvd.Result[1]); + cdvd.Result[0] = cdvdReadRegionParams(&cdvd.Result[3]);//size==8 + SysPrintf("REGION PARAMS = %s %s\n", mg_zones[cdvd.Result[1]], &cdvd.Result[3]); + cdvd.Result[1] = 1 << cdvd.Result[1]; //encryption zone; see offset 0x1C in encrypted headers + ////////////////////////////////////////// + cdvd.Result[2] = 0; //?? +// cdvd.Result[3] == ROMVER[4] == *0xBFC7FF04 +// cdvd.Result[4] == OSDVER[4] == CAP Jjpn, Aeng, Eeng, Heng, Reng, Csch, Kkor? +// cdvd.Result[5] == OSDVER[5] == small +// cdvd.Result[6] == OSDVER[6] == small +// cdvd.Result[7] == OSDVER[7] == small +// cdvd.Result[8] == VERSTR[0x22] == *0xBFC7FF52 +// cdvd.Result[9] == DVDID J U O E A R C M +// cdvd.Result[10]== 0; //?? + cdvd.Result[11] = 0; //?? + cdvd.Result[12] = 0; //?? + ////////////////////////////////////////// + cdvd.Result[13] = 0; //0xFF - 77001 + cdvd.Result[14] = 0; //?? + break; + + case 0x37: //called from EECONF [sceCdReadMAC - made up name] (0:9) + SetResultSize(9); + cdvd.Result[0] = cdvdReadMAC(&cdvd.Result[1]); + break; + + case 0x38: //used to fix the MAC back after accidentally trashed it :D [sceCdWriteMAC - made up name] (8:1) + SetResultSize(1); + cdvd.Result[0] = cdvdWriteMAC(&cdvd.Param[0]); + break; + + case 0x3E: //[__sceCdWriteRegionParams - made up name] (15:1) [Florin: hum, i was expecting 14:1] + SetResultSize(1); + cdvd.Result[0] = cdvdWriteRegionParams(&cdvd.Param[2]); + break; + + case 0x40: // CdOpenConfig (3:1) + cdvd.CReadWrite = cdvd.Param[0]; + cdvd.COffset = cdvd.Param[1]; + cdvd.CNumBlocks = cdvd.Param[2]; + cdvd.CBlockIndex= 0; + SetResultSize(1); + cdvd.Result[0] = 0; + break; + + case 0x41: // CdReadConfig (0:16) + SetResultSize(16); + cdvdReadConfig(&cdvd.Result[0]); + break; + + case 0x42: // CdWriteConfig (16:1) + SetResultSize(1); + cdvd.Result[0] = cdvdWriteConfig(&cdvd.Param[0]); + break; + + case 0x43: // CdCloseConfig (0:1) + cdvd.CReadWrite = 0; + cdvd.COffset = 0; + cdvd.CNumBlocks = 0; + cdvd.CBlockIndex= 0; + SetResultSize(1); + cdvd.Result[0] = 0; + break; + + case 0x80: // secrman: __mechacon_auth_0x80 + cdvd.mg_datatype = 0;//data + SetResultSize(1);//in:1 + cdvd.Result[0] = 0; + break; + + case 0x81: // secrman: __mechacon_auth_0x81 + cdvd.mg_datatype = 0;//data + SetResultSize(1);//in:1 + cdvd.Result[0] = 0; + break; + + case 0x82: // secrman: __mechacon_auth_0x82 + SetResultSize(1);//in:16 + cdvd.Result[0] = 0; + break; + + case 0x83: // secrman: __mechacon_auth_0x83 + SetResultSize(1);//in:8 + cdvd.Result[0] = 0; + break; + + case 0x84: // secrman: __mechacon_auth_0x84 + SetResultSize(1+8+4);//in:0 + cdvd.Result[0] = 0; + + cdvd.Result[1] = 0x21; + cdvd.Result[2] = 0xdc; + cdvd.Result[3] = 0x31; + cdvd.Result[4] = 0x96; + cdvd.Result[5] = 0xce; + cdvd.Result[6] = 0x72; + cdvd.Result[7] = 0xe0; + cdvd.Result[8] = 0xc8; + + cdvd.Result[9] = 0x69; + cdvd.Result[10] = 0xda; + cdvd.Result[11] = 0x34; + cdvd.Result[12] = 0x9b; + break; + + case 0x85: // secrman: __mechacon_auth_0x85 + SetResultSize(1+4+8);//in:0 + cdvd.Result[0] = 0; + + cdvd.Result[1] = 0xeb; + cdvd.Result[2] = 0x01; + cdvd.Result[3] = 0xc7; + cdvd.Result[4] = 0xa9; + + cdvd.Result[ 5] = 0x3f; + cdvd.Result[ 6] = 0x9c; + cdvd.Result[ 7] = 0x5b; + cdvd.Result[ 8] = 0x19; + cdvd.Result[ 9] = 0x31; + cdvd.Result[10] = 0xa0; + cdvd.Result[11] = 0xb3; + cdvd.Result[12] = 0xa3; + break; + + case 0x86: // secrman: __mechacon_auth_0x86 + SetResultSize(1);//in:16 + cdvd.Result[0] = 0; + break; + + case 0x87: // secrman: __mechacon_auth_0x87 + SetResultSize(1);//in:8 + cdvd.Result[0] = 0; + break; + + case 0x8D: // sceMgWriteData + SetResultSize(1);//in:length<=16 + if (cdvd.mg_size + cdvd.ParamC > cdvd.mg_maxsize) + cdvd.Result[0] = 0x80; + else{ + memcpy_fast(cdvd.mg_buffer + cdvd.mg_size, cdvd.Param, cdvd.ParamC); + cdvd.mg_size += cdvd.ParamC; + cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error + } + break; + + case 0x8E: // sceMgReadData + SetResultSize( std::min(16, cdvd.mg_size) ); + memcpy_fast(cdvd.Result, cdvd.mg_buffer, cdvd.ResultC); + cdvd.mg_size -= cdvd.ResultC; + memcpy_fast(cdvd.mg_buffer, cdvd.mg_buffer+cdvd.ResultC, cdvd.mg_size); + break; + + case 0x88: // secrman: __mechacon_auth_0x88 //for now it is the same; so, fall;) + case 0x8F: // secrman: __mechacon_auth_0x8F + SetResultSize(1);//in:0 + if (cdvd.mg_datatype == 1){// header data + u64* psrc, *pdst; + int bit_ofs, i; + + if (cdvd.mg_maxsize != cdvd.mg_size) goto fail_pol_cal; + if (cdvd.mg_size < 0x20) goto fail_pol_cal; + if (cdvd.mg_size != *(u16*)&cdvd.mg_buffer[0x14]) goto fail_pol_cal; + SysPrintf("[MG] ELF_size=0x%X Hdr_size=0x%X unk=0x%X flags=0x%X count=%d zones=", + *(u32*)&cdvd.mg_buffer[0x10], *(u16*)&cdvd.mg_buffer[0x14], *(u16*)&cdvd.mg_buffer[0x16], + *(u16*)&cdvd.mg_buffer[0x18], *(u16*)&cdvd.mg_buffer[0x1A]); + for (i=0; i<8; i++) + if (cdvd.mg_buffer[0x1C] & (1<> 0) & 0xFF; + cdvd.Result[2] = (cdvd.mg_size >> 8) & 0xFF; + break; + + case 0x92: // sceMgWriteDatainLength + cdvd.mg_size = 0; + cdvd.mg_datatype = 0;//data (encrypted) + cdvd.mg_maxsize = cdvd.Param[0] | (((int)cdvd.Param[1])<<8); + SetResultSize(1);//in:2 + cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error + break; + + case 0x93: // sceMgWriteDataoutLength + SetResultSize(1);//in:2 + if (((cdvd.Param[0] | (((int)cdvd.Param[1])<<8)) == cdvd.mg_size) && (cdvd.mg_datatype == 0)){ + cdvd.mg_maxsize = 0; // don't allow any write + cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error + }else + cdvd.Result[0] = 0x80; + break; + + case 0x94: // sceMgReadKbit - read first half of BIT key + SetResultSize(1+8);//in:0 + cdvd.Result[0] = 0; + + ((int*)(cdvd.Result+1))[0] = ((int*)cdvd.mg_kbit)[0]; + ((int*)(cdvd.Result+1))[1] = ((int*)cdvd.mg_kbit)[1];//memcpy(cdvd.Result+1, cdvd.mg_kbit, 8); + break; + + case 0x95: // sceMgReadKbit2 - read second half of BIT key + SetResultSize(1+8);//in:0 + cdvd.Result[0] = 0; + ((int*)(cdvd.Result+1))[0] = ((int*)(cdvd.mg_kbit+8))[0]; + ((int*)(cdvd.Result+1))[1] = ((int*)(cdvd.mg_kbit+8))[1];//memcpy(cdvd.Result+1, cdvd.mg_kbit+8, 8); + break; + + case 0x96: // sceMgReadKcon - read first half of content key + SetResultSize(1+8);//in:0 + cdvd.Result[0] = 0; + ((int*)(cdvd.Result+1))[0] = ((int*)cdvd.mg_kcon)[0]; + ((int*)(cdvd.Result+1))[1] = ((int*)cdvd.mg_kcon)[1];//memcpy(cdvd.Result+1, cdvd.mg_kcon, 8); + break; + + case 0x97: // sceMgReadKcon2 - read second half of content key + SetResultSize(1+8);//in:0 + cdvd.Result[0] = 0; + ((int*)(cdvd.Result+1))[0] = ((int*)(cdvd.mg_kcon+8))[0]; + ((int*)(cdvd.Result+1))[1] = ((int*)(cdvd.mg_kcon+8))[1];//memcpy(cdvd.Result+1, cdvd.mg_kcon+8, 8); + break; + + default: + // fake a 'correct' command + SysPrintf("SCMD Unknown %x\n", rt); + SetResultSize(1); //in:0 + cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error + break; + } + //SysPrintf("SCMD - %x\n", rt); + cdvd.ParamP = 0; cdvd.ParamC = 0; +} + +void cdvdWrite17(u8 rt) { // SDATAIN + CDR_LOG("cdvdWrite17(SDataIn) %x\n", rt); + + if (cdvd.ParamP < 32) { + cdvd.Param[cdvd.ParamP++] = rt; + cdvd.ParamC++; + } +} + +void cdvdWrite18(u8 rt) { // SDATAOUT + CDR_LOG("cdvdWrite18(SDataOut) %x\n", rt); + SysPrintf("*PCSX2* SDATAOUT\n"); +} + +void cdvdWrite3A(u8 rt) { // DEC-SET + CDR_LOG("cdvdWrite3A(DecSet) %x\n", rt); + cdvd.decSet = rt; + SysPrintf("DecSet Write: %02X\n", cdvd.decSet); } \ No newline at end of file diff --git a/pcsx2/CDVD.h b/pcsx2/CDVD.h index aabbc52b69..cb0b8bc2c0 100644 --- a/pcsx2/CDVD.h +++ b/pcsx2/CDVD.h @@ -1,144 +1,144 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __CDVD_H__ -#define __CDVD_H__ - -#include "PsxCommon.h" - -struct cdvdRTC { - u8 status; - u8 second; - u8 minute; - u8 hour; - u8 pad; - u8 day; - u8 month; - u8 year; -}; - -struct cdvdStruct { - u8 nCommand; - u8 Ready; - u8 Error; - u8 PwOff; - u8 Status; - u8 Type; - u8 sCommand; - u8 sDataIn; - u8 sDataOut; - u8 HowTo; - - u8 Param[32]; - u8 Result[32]; - - u8 ParamC; - u8 ParamP; - u8 ResultC; - u8 ResultP; - - u8 CBlockIndex; - u8 COffset; - u8 CReadWrite; - u8 CNumBlocks; - - int RTCcount; - cdvdRTC RTC; - - u32 Sector; - int nSectors; - int Readed; - int Reading; - int ReadMode; - int BlockSize; // Total bytes transfered at 1x speed - int Speed; - int RetryCnt; - int RetryCntP; - int RErr; - int SpindlCtrl; - - u8 Key[16]; - u8 KeyXor; - u8 decSet; - - u8 mg_buffer[65536]; - int mg_size; - int mg_maxsize; - int mg_datatype;//0-data(encrypted); 1-header - u8 mg_kbit[16];//last BIT key 'seen' - u8 mg_kcon[16];//last content key 'seen' - - u8 Action; // the currently scheduled emulated action - u32 SeekToSector; // Holds the destination sector during seek operations. - u32 ReadTime; // Avg. time to read one block of data (in Iop cycles) - bool Spinning; // indicates if the Cdvd is spinning or needs a spinup delay -}; - -void cdvdReset(); -void cdvdVsync(); -extern void cdvdActionInterrupt(); -extern void cdvdReadInterrupt(); -void cdvdNewDiskCB(); -u8 cdvdRead04(void); -u8 cdvdRead05(void); -u8 cdvdRead06(void); -u8 cdvdRead07(void); -u8 cdvdRead08(void); -u8 cdvdRead0A(void); -u8 cdvdRead0B(void); -u8 cdvdRead0C(void); -u8 cdvdRead0D(void); -u8 cdvdRead0E(void); -u8 cdvdRead0F(void); -u8 cdvdRead13(void); -u8 cdvdRead15(void); -u8 cdvdRead16(void); -u8 cdvdRead17(void); -u8 cdvdRead18(void); -u8 cdvdRead20(void); -u8 cdvdRead21(void); -u8 cdvdRead22(void); -u8 cdvdRead23(void); -u8 cdvdRead24(void); -u8 cdvdRead28(void); -u8 cdvdRead29(void); -u8 cdvdRead2A(void); -u8 cdvdRead2B(void); -u8 cdvdRead2C(void); -u8 cdvdRead30(void); -u8 cdvdRead31(void); -u8 cdvdRead32(void); -u8 cdvdRead33(void); -u8 cdvdRead34(void); -u8 cdvdRead38(void); -u8 cdvdRead39(void); -u8 cdvdRead3A(void); -void cdvdWrite04(u8 rt); -void cdvdWrite05(u8 rt); -void cdvdWrite06(u8 rt); -void cdvdWrite07(u8 rt); -void cdvdWrite08(u8 rt); -void cdvdWrite0A(u8 rt); -void cdvdWrite0F(u8 rt); -void cdvdWrite14(u8 rt); -void cdvdWrite16(u8 rt); -void cdvdWrite17(u8 rt); -void cdvdWrite18(u8 rt); -void cdvdWrite3A(u8 rt); - -#endif /* __CDVD_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __CDVD_H__ +#define __CDVD_H__ + +#include "PsxCommon.h" + +struct cdvdRTC { + u8 status; + u8 second; + u8 minute; + u8 hour; + u8 pad; + u8 day; + u8 month; + u8 year; +}; + +struct cdvdStruct { + u8 nCommand; + u8 Ready; + u8 Error; + u8 PwOff; + u8 Status; + u8 Type; + u8 sCommand; + u8 sDataIn; + u8 sDataOut; + u8 HowTo; + + u8 Param[32]; + u8 Result[32]; + + u8 ParamC; + u8 ParamP; + u8 ResultC; + u8 ResultP; + + u8 CBlockIndex; + u8 COffset; + u8 CReadWrite; + u8 CNumBlocks; + + int RTCcount; + cdvdRTC RTC; + + u32 Sector; + int nSectors; + int Readed; + int Reading; + int ReadMode; + int BlockSize; // Total bytes transfered at 1x speed + int Speed; + int RetryCnt; + int RetryCntP; + int RErr; + int SpindlCtrl; + + u8 Key[16]; + u8 KeyXor; + u8 decSet; + + u8 mg_buffer[65536]; + int mg_size; + int mg_maxsize; + int mg_datatype;//0-data(encrypted); 1-header + u8 mg_kbit[16];//last BIT key 'seen' + u8 mg_kcon[16];//last content key 'seen' + + u8 Action; // the currently scheduled emulated action + u32 SeekToSector; // Holds the destination sector during seek operations. + u32 ReadTime; // Avg. time to read one block of data (in Iop cycles) + bool Spinning; // indicates if the Cdvd is spinning or needs a spinup delay +}; + +void cdvdReset(); +void cdvdVsync(); +extern void cdvdActionInterrupt(); +extern void cdvdReadInterrupt(); +void cdvdNewDiskCB(); +u8 cdvdRead04(void); +u8 cdvdRead05(void); +u8 cdvdRead06(void); +u8 cdvdRead07(void); +u8 cdvdRead08(void); +u8 cdvdRead0A(void); +u8 cdvdRead0B(void); +u8 cdvdRead0C(void); +u8 cdvdRead0D(void); +u8 cdvdRead0E(void); +u8 cdvdRead0F(void); +u8 cdvdRead13(void); +u8 cdvdRead15(void); +u8 cdvdRead16(void); +u8 cdvdRead17(void); +u8 cdvdRead18(void); +u8 cdvdRead20(void); +u8 cdvdRead21(void); +u8 cdvdRead22(void); +u8 cdvdRead23(void); +u8 cdvdRead24(void); +u8 cdvdRead28(void); +u8 cdvdRead29(void); +u8 cdvdRead2A(void); +u8 cdvdRead2B(void); +u8 cdvdRead2C(void); +u8 cdvdRead30(void); +u8 cdvdRead31(void); +u8 cdvdRead32(void); +u8 cdvdRead33(void); +u8 cdvdRead34(void); +u8 cdvdRead38(void); +u8 cdvdRead39(void); +u8 cdvdRead3A(void); +void cdvdWrite04(u8 rt); +void cdvdWrite05(u8 rt); +void cdvdWrite06(u8 rt); +void cdvdWrite07(u8 rt); +void cdvdWrite08(u8 rt); +void cdvdWrite0A(u8 rt); +void cdvdWrite0F(u8 rt); +void cdvdWrite14(u8 rt); +void cdvdWrite16(u8 rt); +void cdvdWrite17(u8 rt); +void cdvdWrite18(u8 rt); +void cdvdWrite3A(u8 rt); + +#endif /* __CDVD_H__ */ diff --git a/pcsx2/CDVDiso.cpp b/pcsx2/CDVDiso.cpp index 17bb7383b9..5b26848f50 100644 --- a/pcsx2/CDVDiso.cpp +++ b/pcsx2/CDVDiso.cpp @@ -1,818 +1,818 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -/* - * Original code from libcdvd by Hiryu & Sjeep (C) 2002 - * Modified by Florin for PCSX2 emu - * Fixed CdRead by linuzappz - */ -#include "PrecompiledHeader.h" - -#include - -#include "CDVDiso.h" -#include "CDVDisodrv.h" - -struct dir_toc_data -{ - u32 start_LBA; - u32 num_sectors; - u32 num_entries; - u32 current_entry; - u32 current_sector; - u32 current_sector_offset; - u32 inc_dirs; - char extension_list[128+1]; -}; - -//static u8 cdVolDescriptor[2048]; -static dir_toc_data getDirTocData; -static cdVolDesc CDVolDesc; - -static const int JolietMaxPath = 1024; - -void _splitpath2(const char *constpath, char *dir, char *fname){ - // 255 char max path-length is an ISO9660 restriction - // we must change this for Joliet or relaxed iso restriction support - char pathcopy[JolietMaxPath+1]; - - char* slash; - - strncpy(pathcopy, constpath, 1024); - - slash = strrchr (pathcopy, '/'); - - // if the path doesn't contain a '/' then look for a '\' - if (!slash) - slash = strrchr (pathcopy, (int)'\\'); - - // if a slash was found - if (slash != NULL) - { - // null terminate the path - slash[0] = 0; - // and copy the path into 'dir' - strncpy(dir, pathcopy, 1024); - dir[255]=0; - - // copy the filename into 'fname' - strncpy(fname, slash+1, 128); - fname[128]=0; - } - else - { - dir[0] = 0; - - strncpy(fname, pathcopy, 128); - fname[128]=0; - } - -} - -// Used in findfile -//int tolower(int c); -int strcasecmp(const char *s1, const char *s2){ - while (*s1 != '\0' && tolower(*s1) == tolower(*s2)) - { - s1++; - s2++; - } - - return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2); -} - -// Copy a TOC Entry from the CD native format to our tidier format -void TocEntryCopy(TocEntry* tocEntry, const dirTocEntry* internalTocEntry){ - int i; - int filenamelen; - - tocEntry->fileSize = internalTocEntry->fileSize; - tocEntry->fileLBA = internalTocEntry->fileLBA; - tocEntry->fileProperties = internalTocEntry->fileProperties; - memcpy(tocEntry->date, internalTocEntry->dateStamp, 7); //TODO: Buffer read overrun, dateStamp is 6 bytes - - if (CDVolDesc.filesystemType == 2){ - // This is a Joliet Filesystem, so use Unicode to ISO string copy - - filenamelen = internalTocEntry->filenameLength/2; - - if (!(tocEntry->fileProperties & 0x02)){ - // strip the ;1 from the filename -// filenamelen -= 2;//(Florin) nah, do not strip ;1 - } - - for (i=0; i < filenamelen; i++) - tocEntry->filename[i] = internalTocEntry->filename[(i<<1)+1]; - - tocEntry->filename[filenamelen] = 0; - } - else{ - filenamelen = internalTocEntry->filenameLength; - - if (!(tocEntry->fileProperties & 0x02)){ - // strip the ;1 from the filename -// filenamelen -= 2;//(Florin) nah, do not strip ;1 - } - - // use normal string copy - strncpy(tocEntry->filename,internalTocEntry->filename,128); - tocEntry->filename[filenamelen] = 0; - } -} - -// Check if a TOC Entry matches our extension list -int TocEntryCompare(char* filename, char* extensions){ - static char ext_list[129]; - - char* token; - - char* ext_point; - - strncpy(ext_list,extensions,128); - ext_list[128]=0; - - token = strtok( ext_list, " ," ); - while( token != NULL ) - { - // if 'token' matches extension of 'filename' - // then return a match - ext_point = strrchr(filename,'.'); - - if (strnicmp(ext_point, token, strlen(token)) == 0) - return (TRUE); - - /* Get next token: */ - token = strtok( NULL, " ," ); - } - - // If not match found then return FALSE - return (FALSE); - -} - -#define CD_SECS 60 /* seconds per minute */ -#define CD_FRAMES 75 /* frames per second */ -#define CD_MSF_OFFSET 150 /* MSF numbering offset of first frame */ - -int CdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode){ - u32 i; - u8* buff; - int rmode; - - switch (mode->datapattern) { - case CdSecS2048: - rmode = CDVD_MODE_2048; break; - case CdSecS2328: - rmode = CDVD_MODE_2328; break; - case CdSecS2340: - rmode = CDVD_MODE_2340; break; - default: - return 0; - } - - for (i=0; idatapattern){ - case CdSecS2048: - memcpy_fast((void*)((uptr)buf+2048*i), buff, 2048);break;//only data - case CdSecS2328: - memcpy_fast((void*)((uptr)buf+2328*i), buff, 2328);break;//without sync & head & sub - case CdSecS2340: - memcpy_fast((void*)((uptr)buf+2340*i), buff, 2340);break;//without sync - } - } - return 1; -} - -int DvdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode){ - u32 i; - u8* buff; - - for (i=lsn; i<(lsn+sectors); i++){ - if (CDVDreadTrack(i, CDVD_MODE_2048)==-1) - return 0; - buff = CDVDgetBuffer(); - if (buff==NULL) return 0; - -// switch (mode->datapattern){ -// case CdSecS2064: - ((u32*)buf)[0] = i + 0x30000; - memcpy_fast((u8*)buf+12, buff, 2048); - buf = (char*)buf + 2064; break; -// default: -// return 0; -// } - } - - return 1; -} - -/************************************************************** -* The functions below are not exported for normal file-system * -* operations, but are used by the file-system operations, and * -* may also be exported for use via RPC * -**************************************************************/ - -int CDVD_GetVolumeDescriptor(void){ - // Read until we find the last valid Volume Descriptor - int volDescSector; - - cdVolDesc localVolDesc; - - DbgCon::WriteLn("CDVD_GetVolumeDescriptor called"); - - for (volDescSector = 16; volDescSector<20; volDescSector++) - { - CdRead(volDescSector,1,&localVolDesc,&cdReadMode); -// CdSync(0x00); - - // If this is still a volume Descriptor - if (strncmp((char*)localVolDesc.volID, "CD001", 5) == 0) - { - if ((localVolDesc.filesystemType == 1) || - (localVolDesc.filesystemType == 2)) - { - memcpy_fast(&CDVolDesc, &localVolDesc, sizeof(cdVolDesc)); - } - } - else - break; - } - - if (CDVolDesc.filesystemType == 1) - DbgCon::WriteLn( Color_Green, "CD FileSystem is ISO9660" ); - else if (CDVolDesc.filesystemType == 2) - DbgCon::WriteLn( Color_Green, "CD FileSystem is Joliet"); - else DbgCon::Notice("Could not detect CD FileSystem type"); - - // CdStop(); - - return TRUE; -} - -int CDVD_findfile(const char* fname, TocEntry* tocEntry){ - char filename[g_MaxPath+1]; - char pathname[JolietMaxPath+1]; - char toc[2048]; - char* dirname; - - TocEntry localTocEntry; // used for internal checking only - - int found_dir; - - int num_dir_sectors; - int current_sector; - - int dir_lba; - - dirTocEntry* tocEntryPointer; - - DbgCon::WriteLn("CDVD_findfile called"); - - //make sure we have good cdReadMode - cdReadMode.trycount = 0; - cdReadMode.spindlctrl = CdSpinStm; - cdReadMode.datapattern = CdSecS2048; - - _splitpath2(fname, pathname, filename); - - // Find the TOC for a specific directory - if (CDVD_GetVolumeDescriptor() != TRUE){ - RPC_LOG("Could not get CD Volume Descriptor\n"); - return -1; - } - - // Read the TOC of the root directory - if (CdRead(CDVolDesc.rootToc.tocLBA,1,toc,&cdReadMode) != TRUE){ - RPC_LOG("Couldn't Read from CD !\n"); - return -1; - } - //CdSync(0x00); - - // point the tocEntryPointer at the first real toc entry - tocEntryPointer = (dirTocEntry*)toc; - - num_dir_sectors = (tocEntryPointer->fileSize+2047) >> 11; //round up fix - current_sector = tocEntryPointer->fileLBA; - - tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); - tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); - - - localTocEntry.fileLBA = CDVolDesc.rootToc.tocLBA; - // while (there are more dir names in the path) - dirname = strtok( pathname, "\\/" ); - - while( dirname != NULL ) - { - found_dir = FALSE; -/* - while(tocEntryPointer->length > 0) - { - // while there are still more directory entries then search through - // for the one we want - - if (tocEntryPointer->fileProperties & 0x02) - { - // Copy the CD format TOC Entry to our format - TocEntryCopy(&localTocEntry, tocEntryPointer); - - // If this TOC Entry is a directory, - // then see if it has the right name - if (strcasecmp(dirname,localTocEntry.filename) == 0) - { - // if the name matches then we've found the directory - found_dir = TRUE; - break; - } - } - - // point to the next entry - (char*)tocEntryPointer += tocEntryPointer->length; - } -*/ - while(1) - { - if ((tocEntryPointer->length == 0) || (((char*)tocEntryPointer-toc)>=2048)) - { - num_dir_sectors--; - - if (num_dir_sectors > 0) - { - // If we've run out of entries, but arent on the last sector - // then load another sector - - current_sector++; - if (CdRead(current_sector,1,toc,&cdReadMode) != TRUE) - { - SysPrintf("Couldn't Read from CD !\n"); - return -1; - } -// CdSync(0x00); - - tocEntryPointer = (dirTocEntry*)toc; - } - else - { - // Couldnt find the directory, and got to end of directory - return -1; - } - } - - - if (tocEntryPointer->fileProperties & 0x02) - { - TocEntryCopy(&localTocEntry, tocEntryPointer); - - // If this TOC Entry is a directory, - // then see if it has the right name - if (strcmp(dirname,localTocEntry.filename) == 0) - { - // if the name matches then we've found the directory - found_dir = TRUE; - break; - } - } - - // point to the next entry - tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); - } - - // If we havent found the directory name we wanted then fail - if (found_dir != TRUE) - { - Console::Notice( "CDVD_findfile: could not find dir" ); - return -1; - } - - // Get next directory name - dirname = strtok( NULL, "\\/" ); - - // Read the TOC of the found subdirectory - if (CdRead(localTocEntry.fileLBA,1,toc,&cdReadMode) != TRUE) - { - Console::Error("Couldn't Read from CD !"); - return -1; - } -// CdSync(0x00); - - num_dir_sectors = (localTocEntry.fileSize+2047) >> 11; //round up fix - current_sector = localTocEntry.fileLBA; - - // and point the tocEntryPointer at the first real toc entry - tocEntryPointer = (dirTocEntry*)toc; - tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); - tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); - } - - RPC_LOG("[RPC:cdvd] findfile: found dir, now looking for file\n"); - - tocEntryPointer = (dirTocEntry*)toc; - - num_dir_sectors = (tocEntryPointer->fileSize+2047) >> 11; //round up fix - dir_lba = tocEntryPointer->fileLBA; - - tocEntryPointer = (dirTocEntry*)toc; - tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); - tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); - - while (num_dir_sectors > 0) - { - while(tocEntryPointer->length != 0) - { - // Copy the CD format TOC Entry to our format - TocEntryCopy(&localTocEntry, tocEntryPointer); - - if ((strnicmp(localTocEntry.filename, filename, strlen(filename)) == 0) || - ((filename[strlen(filename)-2] == ';') && - (localTocEntry.filename[strlen(localTocEntry.filename)-2] == ';') && - (strnicmp(localTocEntry.filename, filename, strlen(filename)-2) == 0))) - { - // if the filename matches then copy the toc Entry - tocEntry->fileLBA = localTocEntry.fileLBA; - tocEntry->fileProperties = localTocEntry.fileProperties; - tocEntry->fileSize = localTocEntry.fileSize; - - strcpy(tocEntry->filename, localTocEntry.filename); - memcpy(tocEntry->date, localTocEntry.date, 7); - - DbgCon::WriteLn("CDVD_findfile: found file"); - - return TRUE; - } - - tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); - } - - num_dir_sectors--; - - if (num_dir_sectors > 0) - { - dir_lba++; - - if (CdRead(dir_lba,1,toc,&cdReadMode) != TRUE){ - Console::Error("Couldn't Read from CD !"); - return -1; - } -// CdSync(0x00); - - tocEntryPointer = (dirTocEntry*)toc; - } - } - - DbgCon::Notice("CDVD_findfile: could not find file"); - - return FALSE; -} - -// This is the RPC-ready function which takes the request to start the tocEntry retrieval -int CDVD_GetDir_RPC_request(char* pathname, char* extensions, unsigned int inc_dirs){ -// int dir_depth = 1; - char toc[2048]; - char* dirname; - int found_dir; - int num_dir_sectors; - unsigned int toc_entry_num; - dirTocEntry* tocEntryPointer; - TocEntry localTocEntry; - int current_sector; - - // store the extension list statically for the retrieve function - strncpy(getDirTocData.extension_list, extensions, 128); - getDirTocData.extension_list[128]=0; - - getDirTocData.inc_dirs = inc_dirs; - - // Find the TOC for a specific directory - if (CDVD_GetVolumeDescriptor() != TRUE){ - RPC_LOG("[RPC:cdvd] Could not get CD Volume Descriptor\n"); - return -1; - } - - RPC_LOG("[RPC:cdvd] Getting Directory Listing for: \"%s\"\n", pathname); - - // Read the TOC of the root directory - if (CdRead(CDVolDesc.rootToc.tocLBA,1,toc,&cdReadMode) != TRUE){ - RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); - return -1; - } - //CdSync(0x00); - - // point the tocEntryPointer at the first real toc entry - tocEntryPointer = (dirTocEntry*)toc; - - num_dir_sectors = (tocEntryPointer->fileSize+2047) >> 11; - current_sector = tocEntryPointer->fileLBA; - - tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); - tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); - - // use strtok to get the next dir name - - // if there isnt one, then assume we want the LBA - // for the current one, and exit the while loop - - // if there is another dir name then increment dir_depth - // and look through dir table entries until we find the right name - // if we dont find the right name - // before finding an entry at a higher level (lower num), then return nothing - - localTocEntry.fileLBA = CDVolDesc.rootToc.tocLBA; - - // while (there are more dir names in the path) - dirname = strtok( pathname, "\\/" ); - while( dirname != NULL ){ - found_dir = FALSE; - - while(1){ - if ((tocEntryPointer->length == 0) || (((char*)tocEntryPointer-toc)>=2048)) { - num_dir_sectors--; - - if (num_dir_sectors > 0){ - // If we've run out of entries, but arent on the last sector - // then load another sector - - current_sector++; - if (CdRead(current_sector,1,toc,&cdReadMode) != TRUE){ - RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); - - return -1; - } - //CdSync(0x00); - - tocEntryPointer = (dirTocEntry*)toc; - } - else{ - // Couldnt find the directory, and got to end of directory - return -1; - } - } - - if (tocEntryPointer->fileProperties & 0x02){ - TocEntryCopy(&localTocEntry, tocEntryPointer); - - // If this TOC Entry is a directory, - // then see if it has the right name - if (strcmp(dirname,localTocEntry.filename) == 0){ - // if the name matches then we've found the directory - found_dir = TRUE; - RPC_LOG("[RPC: ] Found directory %s in subdir at sector %d\n",dirname,current_sector); - RPC_LOG("[RPC: ] LBA of found subdirectory = %d\n",localTocEntry.fileLBA); - - break; - } - } - - // point to the next entry - tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); - } - - // If we havent found the directory name we wanted then fail - if (found_dir != TRUE) - return -1; - - // Get next directory name - dirname = strtok( NULL, "\\/" ); - - // Read the TOC of the found subdirectory - if (CdRead(localTocEntry.fileLBA,1,toc,&cdReadMode) != TRUE){ - RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); - return -1; - } - //CdSync(0x00); - - num_dir_sectors = (localTocEntry.fileSize+2047) >> 11; - current_sector = localTocEntry.fileLBA; - - // and point the tocEntryPointer at the first real toc entry - tocEntryPointer = (dirTocEntry*)toc; - tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); - tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); - } - - // We know how much data we need to read in from the DirTocHeader - // but we need to read in at least 1 sector before we can get this value - - // Now we need to COUNT the number of entries (dont do anything with info at this point) - // so set the tocEntryPointer to point to the first actual file entry - - // This is a bit of a waste of reads since we're not actually copying the data out yet, - // but we dont know how big this TOC might be, so we cant allocate a specific size - - tocEntryPointer = (dirTocEntry*)toc; - - // Need to STORE the start LBA and number of Sectors, for use by the retrieve func. - getDirTocData.start_LBA = localTocEntry.fileLBA; - getDirTocData.num_sectors = (tocEntryPointer->fileSize+2047) >> 11; - getDirTocData.num_entries = 0; - getDirTocData.current_entry = 0; - getDirTocData.current_sector = getDirTocData.start_LBA; - getDirTocData.current_sector_offset = 0; - - num_dir_sectors = getDirTocData.num_sectors; - - tocEntryPointer = (dirTocEntry*)toc; - tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); - tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); - - toc_entry_num=0; - - while(1){ - if ((tocEntryPointer->length == 0) || (((char*)tocEntryPointer-toc)>=2048)){ - // decrease the number of dirs remaining - num_dir_sectors--; - - if (num_dir_sectors > 0){ - // If we've run out of entries, but arent on the last sector - // then load another sector - getDirTocData.current_sector++; - - if (CdRead(getDirTocData.current_sector,1,toc,&cdReadMode) != TRUE){ - RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); - return -1; - } - //CdSync(0x00); - - tocEntryPointer = (dirTocEntry*)toc; - -// continue; - } - else{ - getDirTocData.num_entries = toc_entry_num; - getDirTocData.current_sector = getDirTocData.start_LBA; - return (toc_entry_num); - } - } - - // We've found a file/dir in this directory - // now check if it matches our extension list (if there is one) - TocEntryCopy(&localTocEntry, tocEntryPointer); - - if (localTocEntry.fileProperties & 0x02){ - // If this is a subdir, then check if we want to include subdirs - if (getDirTocData.inc_dirs){ - toc_entry_num++; - } - } - else{ - if (strlen(getDirTocData.extension_list) > 0){ - if (TocEntryCompare(localTocEntry.filename, getDirTocData.extension_list) == TRUE){ - // increment the number of matching entries counter - toc_entry_num++; - } - } - else{ - toc_entry_num++; - } - } - - tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); - } - - - // THIS SHOULD BE UNREACHABLE - - // since we are trying to count ALL matching entries, rather than upto a limit - - - // STORE total number of TOC entries - getDirTocData.num_entries = toc_entry_num; - getDirTocData.current_sector = getDirTocData.start_LBA; - - - // we've reached the toc entry limit, so return how many we've done - return (toc_entry_num); - -} - -// This function can be called repeatedly after CDVD_GetDir_RPC_request to get the actual entries -// buffer (tocEntry) must be 18KB in size, and this will be filled with a maximum of 128 entries in one go -int CDVD_GetDir_RPC_get_entries(TocEntry tocEntry[], int req_entries){ - char toc[2048]; - int toc_entry_num; - - dirTocEntry* tocEntryPointer; - - if (CdRead(getDirTocData.current_sector,1,toc,&cdReadMode) != TRUE){ - RPC_LOG("[RPC:cdvd] Couldn't Read from CD !\n"); - return -1; - } - //CdSync(0x00); - - if (getDirTocData.current_entry == 0){ - // if this is the first read then make sure we point to the first real entry - tocEntryPointer = (dirTocEntry*)toc; - tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); - tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); - - getDirTocData.current_sector_offset = (char*)tocEntryPointer - toc; - } - else{ - tocEntryPointer = (dirTocEntry*)(toc + getDirTocData.current_sector_offset); - } - - if (req_entries > 128) - req_entries = 128; - - for (toc_entry_num=0; toc_entry_num < req_entries;){ - if ((tocEntryPointer->length == 0) || (getDirTocData.current_sector_offset >= 2048)){ - // decrease the number of dirs remaining - getDirTocData.num_sectors--; - - if (getDirTocData.num_sectors > 0){ - // If we've run out of entries, but arent on the last sector - // then load another sector - getDirTocData.current_sector++; - - if (CdRead(getDirTocData.current_sector,1,toc,&cdReadMode) != TRUE){ - RPC_LOG("[RPC:cdvd] Couldn't Read from CD !\n"); - return -1; - } - //CdSync(0x00); - - getDirTocData.current_sector_offset = 0; - tocEntryPointer = (dirTocEntry*)(toc + getDirTocData.current_sector_offset); - -// continue; - } - else{ - return (toc_entry_num); - } - } - - // This must be incremented even if the filename doesnt match extension list - getDirTocData.current_entry++; - - // We've found a file in this directory - // now check if it matches our extension list (if there is one) - - // Copy the entry regardless, as it makes the comparison easier - // if it doesn't match then it will just be overwritten - TocEntryCopy(&tocEntry[toc_entry_num], tocEntryPointer); - - if (tocEntry[toc_entry_num].fileProperties & 0x02){ - // If this is a subdir, then check if we want to include subdirs - if (getDirTocData.inc_dirs) { - toc_entry_num++; - } - - getDirTocData.current_sector_offset += tocEntryPointer->length; - tocEntryPointer = (dirTocEntry*)(toc + getDirTocData.current_sector_offset); - } - else{ - if (strlen(getDirTocData.extension_list) > 0){ - if (TocEntryCompare(tocEntry[toc_entry_num].filename, getDirTocData.extension_list) == TRUE){ - // increment the number of matching entries counter - toc_entry_num++; - } - - getDirTocData.current_sector_offset += tocEntryPointer->length; - tocEntryPointer = (dirTocEntry*)(toc + getDirTocData.current_sector_offset); - - } - else{ - toc_entry_num++; - getDirTocData.current_sector_offset += tocEntryPointer->length; - tocEntryPointer = (dirTocEntry*)(toc + getDirTocData.current_sector_offset); - } - } -/* - if (strlen(getDirTocData.extension_list) > 0) - { - if (TocEntryCompare(tocEntry[toc_entry_num].filename, getDirTocData.extension_list) == TRUE) - { - - // increment this here, rather than in the main for loop - // since this should count the number of matching entries - toc_entry_num++; - } - - getDirTocData.current_sector_offset += tocEntryPointer->length; - (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; - } - else - { - toc_entry_num++; - getDirTocData.current_sector_offset += tocEntryPointer->length; - (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; - } -*/ - } - return (toc_entry_num); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Modified by Florin for PCSX2 emu + * Fixed CdRead by linuzappz + */ +#include "PrecompiledHeader.h" + +#include + +#include "CDVDiso.h" +#include "CDVDisodrv.h" + +struct dir_toc_data +{ + u32 start_LBA; + u32 num_sectors; + u32 num_entries; + u32 current_entry; + u32 current_sector; + u32 current_sector_offset; + u32 inc_dirs; + char extension_list[128+1]; +}; + +//static u8 cdVolDescriptor[2048]; +static dir_toc_data getDirTocData; +static cdVolDesc CDVolDesc; + +static const int JolietMaxPath = 1024; + +void _splitpath2(const char *constpath, char *dir, char *fname){ + // 255 char max path-length is an ISO9660 restriction + // we must change this for Joliet or relaxed iso restriction support + char pathcopy[JolietMaxPath+1]; + + char* slash; + + strncpy(pathcopy, constpath, 1024); + + slash = strrchr (pathcopy, '/'); + + // if the path doesn't contain a '/' then look for a '\' + if (!slash) + slash = strrchr (pathcopy, (int)'\\'); + + // if a slash was found + if (slash != NULL) + { + // null terminate the path + slash[0] = 0; + // and copy the path into 'dir' + strncpy(dir, pathcopy, 1024); + dir[255]=0; + + // copy the filename into 'fname' + strncpy(fname, slash+1, 128); + fname[128]=0; + } + else + { + dir[0] = 0; + + strncpy(fname, pathcopy, 128); + fname[128]=0; + } + +} + +// Used in findfile +//int tolower(int c); +int strcasecmp(const char *s1, const char *s2){ + while (*s1 != '\0' && tolower(*s1) == tolower(*s2)) + { + s1++; + s2++; + } + + return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2); +} + +// Copy a TOC Entry from the CD native format to our tidier format +void TocEntryCopy(TocEntry* tocEntry, const dirTocEntry* internalTocEntry){ + int i; + int filenamelen; + + tocEntry->fileSize = internalTocEntry->fileSize; + tocEntry->fileLBA = internalTocEntry->fileLBA; + tocEntry->fileProperties = internalTocEntry->fileProperties; + memcpy(tocEntry->date, internalTocEntry->dateStamp, 7); //TODO: Buffer read overrun, dateStamp is 6 bytes + + if (CDVolDesc.filesystemType == 2){ + // This is a Joliet Filesystem, so use Unicode to ISO string copy + + filenamelen = internalTocEntry->filenameLength/2; + + if (!(tocEntry->fileProperties & 0x02)){ + // strip the ;1 from the filename +// filenamelen -= 2;//(Florin) nah, do not strip ;1 + } + + for (i=0; i < filenamelen; i++) + tocEntry->filename[i] = internalTocEntry->filename[(i<<1)+1]; + + tocEntry->filename[filenamelen] = 0; + } + else{ + filenamelen = internalTocEntry->filenameLength; + + if (!(tocEntry->fileProperties & 0x02)){ + // strip the ;1 from the filename +// filenamelen -= 2;//(Florin) nah, do not strip ;1 + } + + // use normal string copy + strncpy(tocEntry->filename,internalTocEntry->filename,128); + tocEntry->filename[filenamelen] = 0; + } +} + +// Check if a TOC Entry matches our extension list +int TocEntryCompare(char* filename, char* extensions){ + static char ext_list[129]; + + char* token; + + char* ext_point; + + strncpy(ext_list,extensions,128); + ext_list[128]=0; + + token = strtok( ext_list, " ," ); + while( token != NULL ) + { + // if 'token' matches extension of 'filename' + // then return a match + ext_point = strrchr(filename,'.'); + + if (strnicmp(ext_point, token, strlen(token)) == 0) + return (TRUE); + + /* Get next token: */ + token = strtok( NULL, " ," ); + } + + // If not match found then return FALSE + return (FALSE); + +} + +#define CD_SECS 60 /* seconds per minute */ +#define CD_FRAMES 75 /* frames per second */ +#define CD_MSF_OFFSET 150 /* MSF numbering offset of first frame */ + +int CdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode){ + u32 i; + u8* buff; + int rmode; + + switch (mode->datapattern) { + case CdSecS2048: + rmode = CDVD_MODE_2048; break; + case CdSecS2328: + rmode = CDVD_MODE_2328; break; + case CdSecS2340: + rmode = CDVD_MODE_2340; break; + default: + return 0; + } + + for (i=0; idatapattern){ + case CdSecS2048: + memcpy_fast((void*)((uptr)buf+2048*i), buff, 2048);break;//only data + case CdSecS2328: + memcpy_fast((void*)((uptr)buf+2328*i), buff, 2328);break;//without sync & head & sub + case CdSecS2340: + memcpy_fast((void*)((uptr)buf+2340*i), buff, 2340);break;//without sync + } + } + return 1; +} + +int DvdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode){ + u32 i; + u8* buff; + + for (i=lsn; i<(lsn+sectors); i++){ + if (CDVDreadTrack(i, CDVD_MODE_2048)==-1) + return 0; + buff = CDVDgetBuffer(); + if (buff==NULL) return 0; + +// switch (mode->datapattern){ +// case CdSecS2064: + ((u32*)buf)[0] = i + 0x30000; + memcpy_fast((u8*)buf+12, buff, 2048); + buf = (char*)buf + 2064; break; +// default: +// return 0; +// } + } + + return 1; +} + +/************************************************************** +* The functions below are not exported for normal file-system * +* operations, but are used by the file-system operations, and * +* may also be exported for use via RPC * +**************************************************************/ + +int CDVD_GetVolumeDescriptor(void){ + // Read until we find the last valid Volume Descriptor + int volDescSector; + + cdVolDesc localVolDesc; + + DbgCon::WriteLn("CDVD_GetVolumeDescriptor called"); + + for (volDescSector = 16; volDescSector<20; volDescSector++) + { + CdRead(volDescSector,1,&localVolDesc,&cdReadMode); +// CdSync(0x00); + + // If this is still a volume Descriptor + if (strncmp((char*)localVolDesc.volID, "CD001", 5) == 0) + { + if ((localVolDesc.filesystemType == 1) || + (localVolDesc.filesystemType == 2)) + { + memcpy_fast(&CDVolDesc, &localVolDesc, sizeof(cdVolDesc)); + } + } + else + break; + } + + if (CDVolDesc.filesystemType == 1) + DbgCon::WriteLn( Color_Green, "CD FileSystem is ISO9660" ); + else if (CDVolDesc.filesystemType == 2) + DbgCon::WriteLn( Color_Green, "CD FileSystem is Joliet"); + else DbgCon::Notice("Could not detect CD FileSystem type"); + + // CdStop(); + + return TRUE; +} + +int CDVD_findfile(const char* fname, TocEntry* tocEntry){ + char filename[g_MaxPath+1]; + char pathname[JolietMaxPath+1]; + char toc[2048]; + char* dirname; + + TocEntry localTocEntry; // used for internal checking only + + int found_dir; + + int num_dir_sectors; + int current_sector; + + int dir_lba; + + dirTocEntry* tocEntryPointer; + + DbgCon::WriteLn("CDVD_findfile called"); + + //make sure we have good cdReadMode + cdReadMode.trycount = 0; + cdReadMode.spindlctrl = CdSpinStm; + cdReadMode.datapattern = CdSecS2048; + + _splitpath2(fname, pathname, filename); + + // Find the TOC for a specific directory + if (CDVD_GetVolumeDescriptor() != TRUE){ + RPC_LOG("Could not get CD Volume Descriptor\n"); + return -1; + } + + // Read the TOC of the root directory + if (CdRead(CDVolDesc.rootToc.tocLBA,1,toc,&cdReadMode) != TRUE){ + RPC_LOG("Couldn't Read from CD !\n"); + return -1; + } + //CdSync(0x00); + + // point the tocEntryPointer at the first real toc entry + tocEntryPointer = (dirTocEntry*)toc; + + num_dir_sectors = (tocEntryPointer->fileSize+2047) >> 11; //round up fix + current_sector = tocEntryPointer->fileLBA; + + tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + + + localTocEntry.fileLBA = CDVolDesc.rootToc.tocLBA; + // while (there are more dir names in the path) + dirname = strtok( pathname, "\\/" ); + + while( dirname != NULL ) + { + found_dir = FALSE; +/* + while(tocEntryPointer->length > 0) + { + // while there are still more directory entries then search through + // for the one we want + + if (tocEntryPointer->fileProperties & 0x02) + { + // Copy the CD format TOC Entry to our format + TocEntryCopy(&localTocEntry, tocEntryPointer); + + // If this TOC Entry is a directory, + // then see if it has the right name + if (strcasecmp(dirname,localTocEntry.filename) == 0) + { + // if the name matches then we've found the directory + found_dir = TRUE; + break; + } + } + + // point to the next entry + (char*)tocEntryPointer += tocEntryPointer->length; + } +*/ + while(1) + { + if ((tocEntryPointer->length == 0) || (((char*)tocEntryPointer-toc)>=2048)) + { + num_dir_sectors--; + + if (num_dir_sectors > 0) + { + // If we've run out of entries, but arent on the last sector + // then load another sector + + current_sector++; + if (CdRead(current_sector,1,toc,&cdReadMode) != TRUE) + { + SysPrintf("Couldn't Read from CD !\n"); + return -1; + } +// CdSync(0x00); + + tocEntryPointer = (dirTocEntry*)toc; + } + else + { + // Couldnt find the directory, and got to end of directory + return -1; + } + } + + + if (tocEntryPointer->fileProperties & 0x02) + { + TocEntryCopy(&localTocEntry, tocEntryPointer); + + // If this TOC Entry is a directory, + // then see if it has the right name + if (strcmp(dirname,localTocEntry.filename) == 0) + { + // if the name matches then we've found the directory + found_dir = TRUE; + break; + } + } + + // point to the next entry + tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + } + + // If we havent found the directory name we wanted then fail + if (found_dir != TRUE) + { + Console::Notice( "CDVD_findfile: could not find dir" ); + return -1; + } + + // Get next directory name + dirname = strtok( NULL, "\\/" ); + + // Read the TOC of the found subdirectory + if (CdRead(localTocEntry.fileLBA,1,toc,&cdReadMode) != TRUE) + { + Console::Error("Couldn't Read from CD !"); + return -1; + } +// CdSync(0x00); + + num_dir_sectors = (localTocEntry.fileSize+2047) >> 11; //round up fix + current_sector = localTocEntry.fileLBA; + + // and point the tocEntryPointer at the first real toc entry + tocEntryPointer = (dirTocEntry*)toc; + tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + } + + RPC_LOG("[RPC:cdvd] findfile: found dir, now looking for file\n"); + + tocEntryPointer = (dirTocEntry*)toc; + + num_dir_sectors = (tocEntryPointer->fileSize+2047) >> 11; //round up fix + dir_lba = tocEntryPointer->fileLBA; + + tocEntryPointer = (dirTocEntry*)toc; + tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + + while (num_dir_sectors > 0) + { + while(tocEntryPointer->length != 0) + { + // Copy the CD format TOC Entry to our format + TocEntryCopy(&localTocEntry, tocEntryPointer); + + if ((strnicmp(localTocEntry.filename, filename, strlen(filename)) == 0) || + ((filename[strlen(filename)-2] == ';') && + (localTocEntry.filename[strlen(localTocEntry.filename)-2] == ';') && + (strnicmp(localTocEntry.filename, filename, strlen(filename)-2) == 0))) + { + // if the filename matches then copy the toc Entry + tocEntry->fileLBA = localTocEntry.fileLBA; + tocEntry->fileProperties = localTocEntry.fileProperties; + tocEntry->fileSize = localTocEntry.fileSize; + + strcpy(tocEntry->filename, localTocEntry.filename); + memcpy(tocEntry->date, localTocEntry.date, 7); + + DbgCon::WriteLn("CDVD_findfile: found file"); + + return TRUE; + } + + tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + } + + num_dir_sectors--; + + if (num_dir_sectors > 0) + { + dir_lba++; + + if (CdRead(dir_lba,1,toc,&cdReadMode) != TRUE){ + Console::Error("Couldn't Read from CD !"); + return -1; + } +// CdSync(0x00); + + tocEntryPointer = (dirTocEntry*)toc; + } + } + + DbgCon::Notice("CDVD_findfile: could not find file"); + + return FALSE; +} + +// This is the RPC-ready function which takes the request to start the tocEntry retrieval +int CDVD_GetDir_RPC_request(char* pathname, char* extensions, unsigned int inc_dirs){ +// int dir_depth = 1; + char toc[2048]; + char* dirname; + int found_dir; + int num_dir_sectors; + unsigned int toc_entry_num; + dirTocEntry* tocEntryPointer; + TocEntry localTocEntry; + int current_sector; + + // store the extension list statically for the retrieve function + strncpy(getDirTocData.extension_list, extensions, 128); + getDirTocData.extension_list[128]=0; + + getDirTocData.inc_dirs = inc_dirs; + + // Find the TOC for a specific directory + if (CDVD_GetVolumeDescriptor() != TRUE){ + RPC_LOG("[RPC:cdvd] Could not get CD Volume Descriptor\n"); + return -1; + } + + RPC_LOG("[RPC:cdvd] Getting Directory Listing for: \"%s\"\n", pathname); + + // Read the TOC of the root directory + if (CdRead(CDVolDesc.rootToc.tocLBA,1,toc,&cdReadMode) != TRUE){ + RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); + return -1; + } + //CdSync(0x00); + + // point the tocEntryPointer at the first real toc entry + tocEntryPointer = (dirTocEntry*)toc; + + num_dir_sectors = (tocEntryPointer->fileSize+2047) >> 11; + current_sector = tocEntryPointer->fileLBA; + + tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + + // use strtok to get the next dir name + + // if there isnt one, then assume we want the LBA + // for the current one, and exit the while loop + + // if there is another dir name then increment dir_depth + // and look through dir table entries until we find the right name + // if we dont find the right name + // before finding an entry at a higher level (lower num), then return nothing + + localTocEntry.fileLBA = CDVolDesc.rootToc.tocLBA; + + // while (there are more dir names in the path) + dirname = strtok( pathname, "\\/" ); + while( dirname != NULL ){ + found_dir = FALSE; + + while(1){ + if ((tocEntryPointer->length == 0) || (((char*)tocEntryPointer-toc)>=2048)) { + num_dir_sectors--; + + if (num_dir_sectors > 0){ + // If we've run out of entries, but arent on the last sector + // then load another sector + + current_sector++; + if (CdRead(current_sector,1,toc,&cdReadMode) != TRUE){ + RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); + + return -1; + } + //CdSync(0x00); + + tocEntryPointer = (dirTocEntry*)toc; + } + else{ + // Couldnt find the directory, and got to end of directory + return -1; + } + } + + if (tocEntryPointer->fileProperties & 0x02){ + TocEntryCopy(&localTocEntry, tocEntryPointer); + + // If this TOC Entry is a directory, + // then see if it has the right name + if (strcmp(dirname,localTocEntry.filename) == 0){ + // if the name matches then we've found the directory + found_dir = TRUE; + RPC_LOG("[RPC: ] Found directory %s in subdir at sector %d\n",dirname,current_sector); + RPC_LOG("[RPC: ] LBA of found subdirectory = %d\n",localTocEntry.fileLBA); + + break; + } + } + + // point to the next entry + tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + } + + // If we havent found the directory name we wanted then fail + if (found_dir != TRUE) + return -1; + + // Get next directory name + dirname = strtok( NULL, "\\/" ); + + // Read the TOC of the found subdirectory + if (CdRead(localTocEntry.fileLBA,1,toc,&cdReadMode) != TRUE){ + RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); + return -1; + } + //CdSync(0x00); + + num_dir_sectors = (localTocEntry.fileSize+2047) >> 11; + current_sector = localTocEntry.fileLBA; + + // and point the tocEntryPointer at the first real toc entry + tocEntryPointer = (dirTocEntry*)toc; + tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + } + + // We know how much data we need to read in from the DirTocHeader + // but we need to read in at least 1 sector before we can get this value + + // Now we need to COUNT the number of entries (dont do anything with info at this point) + // so set the tocEntryPointer to point to the first actual file entry + + // This is a bit of a waste of reads since we're not actually copying the data out yet, + // but we dont know how big this TOC might be, so we cant allocate a specific size + + tocEntryPointer = (dirTocEntry*)toc; + + // Need to STORE the start LBA and number of Sectors, for use by the retrieve func. + getDirTocData.start_LBA = localTocEntry.fileLBA; + getDirTocData.num_sectors = (tocEntryPointer->fileSize+2047) >> 11; + getDirTocData.num_entries = 0; + getDirTocData.current_entry = 0; + getDirTocData.current_sector = getDirTocData.start_LBA; + getDirTocData.current_sector_offset = 0; + + num_dir_sectors = getDirTocData.num_sectors; + + tocEntryPointer = (dirTocEntry*)toc; + tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + + toc_entry_num=0; + + while(1){ + if ((tocEntryPointer->length == 0) || (((char*)tocEntryPointer-toc)>=2048)){ + // decrease the number of dirs remaining + num_dir_sectors--; + + if (num_dir_sectors > 0){ + // If we've run out of entries, but arent on the last sector + // then load another sector + getDirTocData.current_sector++; + + if (CdRead(getDirTocData.current_sector,1,toc,&cdReadMode) != TRUE){ + RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); + return -1; + } + //CdSync(0x00); + + tocEntryPointer = (dirTocEntry*)toc; + +// continue; + } + else{ + getDirTocData.num_entries = toc_entry_num; + getDirTocData.current_sector = getDirTocData.start_LBA; + return (toc_entry_num); + } + } + + // We've found a file/dir in this directory + // now check if it matches our extension list (if there is one) + TocEntryCopy(&localTocEntry, tocEntryPointer); + + if (localTocEntry.fileProperties & 0x02){ + // If this is a subdir, then check if we want to include subdirs + if (getDirTocData.inc_dirs){ + toc_entry_num++; + } + } + else{ + if (strlen(getDirTocData.extension_list) > 0){ + if (TocEntryCompare(localTocEntry.filename, getDirTocData.extension_list) == TRUE){ + // increment the number of matching entries counter + toc_entry_num++; + } + } + else{ + toc_entry_num++; + } + } + + tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + } + + + // THIS SHOULD BE UNREACHABLE - + // since we are trying to count ALL matching entries, rather than upto a limit + + + // STORE total number of TOC entries + getDirTocData.num_entries = toc_entry_num; + getDirTocData.current_sector = getDirTocData.start_LBA; + + + // we've reached the toc entry limit, so return how many we've done + return (toc_entry_num); + +} + +// This function can be called repeatedly after CDVD_GetDir_RPC_request to get the actual entries +// buffer (tocEntry) must be 18KB in size, and this will be filled with a maximum of 128 entries in one go +int CDVD_GetDir_RPC_get_entries(TocEntry tocEntry[], int req_entries){ + char toc[2048]; + int toc_entry_num; + + dirTocEntry* tocEntryPointer; + + if (CdRead(getDirTocData.current_sector,1,toc,&cdReadMode) != TRUE){ + RPC_LOG("[RPC:cdvd] Couldn't Read from CD !\n"); + return -1; + } + //CdSync(0x00); + + if (getDirTocData.current_entry == 0){ + // if this is the first read then make sure we point to the first real entry + tocEntryPointer = (dirTocEntry*)toc; + tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + tocEntryPointer = (dirTocEntry*)((char*)tocEntryPointer + tocEntryPointer->length); + + getDirTocData.current_sector_offset = (char*)tocEntryPointer - toc; + } + else{ + tocEntryPointer = (dirTocEntry*)(toc + getDirTocData.current_sector_offset); + } + + if (req_entries > 128) + req_entries = 128; + + for (toc_entry_num=0; toc_entry_num < req_entries;){ + if ((tocEntryPointer->length == 0) || (getDirTocData.current_sector_offset >= 2048)){ + // decrease the number of dirs remaining + getDirTocData.num_sectors--; + + if (getDirTocData.num_sectors > 0){ + // If we've run out of entries, but arent on the last sector + // then load another sector + getDirTocData.current_sector++; + + if (CdRead(getDirTocData.current_sector,1,toc,&cdReadMode) != TRUE){ + RPC_LOG("[RPC:cdvd] Couldn't Read from CD !\n"); + return -1; + } + //CdSync(0x00); + + getDirTocData.current_sector_offset = 0; + tocEntryPointer = (dirTocEntry*)(toc + getDirTocData.current_sector_offset); + +// continue; + } + else{ + return (toc_entry_num); + } + } + + // This must be incremented even if the filename doesnt match extension list + getDirTocData.current_entry++; + + // We've found a file in this directory + // now check if it matches our extension list (if there is one) + + // Copy the entry regardless, as it makes the comparison easier + // if it doesn't match then it will just be overwritten + TocEntryCopy(&tocEntry[toc_entry_num], tocEntryPointer); + + if (tocEntry[toc_entry_num].fileProperties & 0x02){ + // If this is a subdir, then check if we want to include subdirs + if (getDirTocData.inc_dirs) { + toc_entry_num++; + } + + getDirTocData.current_sector_offset += tocEntryPointer->length; + tocEntryPointer = (dirTocEntry*)(toc + getDirTocData.current_sector_offset); + } + else{ + if (strlen(getDirTocData.extension_list) > 0){ + if (TocEntryCompare(tocEntry[toc_entry_num].filename, getDirTocData.extension_list) == TRUE){ + // increment the number of matching entries counter + toc_entry_num++; + } + + getDirTocData.current_sector_offset += tocEntryPointer->length; + tocEntryPointer = (dirTocEntry*)(toc + getDirTocData.current_sector_offset); + + } + else{ + toc_entry_num++; + getDirTocData.current_sector_offset += tocEntryPointer->length; + tocEntryPointer = (dirTocEntry*)(toc + getDirTocData.current_sector_offset); + } + } +/* + if (strlen(getDirTocData.extension_list) > 0) + { + if (TocEntryCompare(tocEntry[toc_entry_num].filename, getDirTocData.extension_list) == TRUE) + { + + // increment this here, rather than in the main for loop + // since this should count the number of matching entries + toc_entry_num++; + } + + getDirTocData.current_sector_offset += tocEntryPointer->length; + (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; + } + else + { + toc_entry_num++; + getDirTocData.current_sector_offset += tocEntryPointer->length; + (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; + } +*/ + } + return (toc_entry_num); +} diff --git a/pcsx2/CDVDiso.h b/pcsx2/CDVDiso.h index e68d85eb82..e0ebae0201 100644 --- a/pcsx2/CDVDiso.h +++ b/pcsx2/CDVDiso.h @@ -1,149 +1,149 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -/* - * Original code from libcdvd by Hiryu & Sjeep (C) 2002 - * Modified by Florin for PCSX2 emu - */ - -#ifndef __CDVDISO_H__ -#define __CDVDISO_H__ - -#include "CDVDlib.h" - -int CDVD_findfile(const char* fname, TocEntry* tocEntry); -int CDVD_GetDir_RPC_request(char* pathname, char* extensions, unsigned int inc_dirs); -int CDVD_GetDir_RPC_get_entries(TocEntry tocEntry[], int req_entries); - -#if defined(_MSC_VER) -#pragma pack(1) -#pragma warning(disable:4996) //ignore the stricmp deprecated warning -#endif - -struct rootDirTocHeader -{ - u16 length; //+00 - u32 tocLBA; //+02 - u32 tocLBA_bigend; //+06 - u32 tocSize; //+0A - u32 tocSize_bigend; //+0E - u8 dateStamp[8]; //+12 - u8 reserved[6]; //+1A - u8 reserved2; //+20 - u8 reserved3; //+21 -#if defined(_MSC_VER) -}; //+22 -#else -} __attribute__((packed)); -#endif - -struct asciiDate -{ - char year[4]; - char month[2]; - char day[2]; - char hours[2]; - char minutes[2]; - char seconds[2]; - char hundreths[2]; - char terminator[1]; -#if defined(_MSC_VER) -}; -#else -} __attribute__((packed)); -#endif - -struct cdVolDesc -{ - u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL - u8 volID[5]; // "CD001" - u8 reserved2; - u8 reserved3; - u8 sysIdName[32]; - u8 volName[32]; // The ISO9660 Volume Name - u8 reserved5[8]; - u32 volSize; // Volume Size - u32 volSizeBig; // Volume Size Big-Endian - u8 reserved6[32]; - u32 unknown1; - u32 unknown1_bigend; - u16 volDescSize; //+80 - u16 volDescSize_bigend; //+82 - u32 unknown3; //+84 - u32 unknown3_bigend; //+88 - u32 priDirTableLBA; // LBA of Primary Dir Table //+8C - u32 reserved7; //+90 - u32 secDirTableLBA; // LBA of Secondary Dir Table //+94 - u32 reserved8; //+98 - struct rootDirTocHeader rootToc; - s8 volSetName[128]; - s8 publisherName[128]; - s8 preparerName[128]; - s8 applicationName[128]; - s8 copyrightFileName[37]; - s8 abstractFileName[37]; - s8 bibliographyFileName[37]; - struct asciiDate creationDate; - struct asciiDate modificationDate; - struct asciiDate effectiveDate; - struct asciiDate expirationDate; - u8 reserved10; - u8 reserved11[1166]; -#if defined(_MSC_VER) -}; -#else -} __attribute__((packed)); -#endif - -struct dirTableEntry -{ - u8 dirNameLength; - u8 reserved; - u32 dirTOCLBA; - u16 dirDepth; - u8 dirName[32]; -#if defined(_MSC_VER) -}; -#else -} __attribute__((packed)); -#endif - -struct dirTocEntry -{ - short length; - u32 fileLBA; - u32 fileLBA_bigend; - u32 fileSize; - u32 fileSize_bigend; - u8 dateStamp[6]; - u8 reserved1; - u8 fileProperties; - u8 reserved2[6]; - u8 filenameLength; - char filename[128]; -#if defined(_MSC_VER) -}; -#else -} __attribute__((packed)); -#endif // This is the internal format on the CD -// TocEntry structure contains only the important stuff needed for export - -#if defined(_MSC_VER) -#pragma pack() -#endif - -#endif//__CDVDISO_H__ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Modified by Florin for PCSX2 emu + */ + +#ifndef __CDVDISO_H__ +#define __CDVDISO_H__ + +#include "CDVDlib.h" + +int CDVD_findfile(const char* fname, TocEntry* tocEntry); +int CDVD_GetDir_RPC_request(char* pathname, char* extensions, unsigned int inc_dirs); +int CDVD_GetDir_RPC_get_entries(TocEntry tocEntry[], int req_entries); + +#if defined(_MSC_VER) +#pragma pack(1) +#pragma warning(disable:4996) //ignore the stricmp deprecated warning +#endif + +struct rootDirTocHeader +{ + u16 length; //+00 + u32 tocLBA; //+02 + u32 tocLBA_bigend; //+06 + u32 tocSize; //+0A + u32 tocSize_bigend; //+0E + u8 dateStamp[8]; //+12 + u8 reserved[6]; //+1A + u8 reserved2; //+20 + u8 reserved3; //+21 +#if defined(_MSC_VER) +}; //+22 +#else +} __attribute__((packed)); +#endif + +struct asciiDate +{ + char year[4]; + char month[2]; + char day[2]; + char hours[2]; + char minutes[2]; + char seconds[2]; + char hundreths[2]; + char terminator[1]; +#if defined(_MSC_VER) +}; +#else +} __attribute__((packed)); +#endif + +struct cdVolDesc +{ + u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL + u8 volID[5]; // "CD001" + u8 reserved2; + u8 reserved3; + u8 sysIdName[32]; + u8 volName[32]; // The ISO9660 Volume Name + u8 reserved5[8]; + u32 volSize; // Volume Size + u32 volSizeBig; // Volume Size Big-Endian + u8 reserved6[32]; + u32 unknown1; + u32 unknown1_bigend; + u16 volDescSize; //+80 + u16 volDescSize_bigend; //+82 + u32 unknown3; //+84 + u32 unknown3_bigend; //+88 + u32 priDirTableLBA; // LBA of Primary Dir Table //+8C + u32 reserved7; //+90 + u32 secDirTableLBA; // LBA of Secondary Dir Table //+94 + u32 reserved8; //+98 + struct rootDirTocHeader rootToc; + s8 volSetName[128]; + s8 publisherName[128]; + s8 preparerName[128]; + s8 applicationName[128]; + s8 copyrightFileName[37]; + s8 abstractFileName[37]; + s8 bibliographyFileName[37]; + struct asciiDate creationDate; + struct asciiDate modificationDate; + struct asciiDate effectiveDate; + struct asciiDate expirationDate; + u8 reserved10; + u8 reserved11[1166]; +#if defined(_MSC_VER) +}; +#else +} __attribute__((packed)); +#endif + +struct dirTableEntry +{ + u8 dirNameLength; + u8 reserved; + u32 dirTOCLBA; + u16 dirDepth; + u8 dirName[32]; +#if defined(_MSC_VER) +}; +#else +} __attribute__((packed)); +#endif + +struct dirTocEntry +{ + short length; + u32 fileLBA; + u32 fileLBA_bigend; + u32 fileSize; + u32 fileSize_bigend; + u8 dateStamp[6]; + u8 reserved1; + u8 fileProperties; + u8 reserved2[6]; + u8 filenameLength; + char filename[128]; +#if defined(_MSC_VER) +}; +#else +} __attribute__((packed)); +#endif // This is the internal format on the CD +// TocEntry structure contains only the important stuff needed for export + +#if defined(_MSC_VER) +#pragma pack() +#endif + +#endif//__CDVDISO_H__ diff --git a/pcsx2/CDVDisodrv.cpp b/pcsx2/CDVDisodrv.cpp index 4b33baaec0..6f699e857a 100644 --- a/pcsx2/CDVDisodrv.cpp +++ b/pcsx2/CDVDisodrv.cpp @@ -1,254 +1,254 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -/* - * Original code from libcdvd by Hiryu & Sjeep (C) 2002 - * Modified by Florin for PCSX2 emu - */ - -#include "PrecompiledHeader.h" - -#include "CDVDiso.h" -#include "CDVDisodrv.h" - -CdRMode cdReadMode; - -struct fdtable{ -//int fd; - int fileSize; - int LBA; - int filePos; -}; - -static struct fdtable fd_table[16]; -static int fd_used[16]; -static int files_open=0; -static int inited=FALSE; - -/************************************************************* -* The functions below are the normal file-system operations, * -* used to provide a standard filesystem interface * -*************************************************************/ - -////////////////////////////////////////////////////////////////////// -// CDVDFS_init -// called by 80000592 sceCdInit() -////////////////////////////////////////////////////////////////////// -void CDVDFS_init(){ - - if (inited) return;//might change in the future as a param; forceInit/Reset - - RPC_LOG("[CDVDisodrv:init] CDVD Filesystem v1.00\n"); - RPC_LOG("[CDVDisodrv ] \tby A.Lee (aka Hiryu) & Nicholas Van Veen (aka Sjeep)\n"); - RPC_LOG("[CDVDisodrv ] Initializing '%s' file driver.\n", "cdfs"); - - //CdInit(0); already called by plugin loading system ;) - - cdReadMode.trycount = 0; - cdReadMode.spindlctrl = CdSpinStm; - cdReadMode.datapattern = CdSecS2048; //isofs driver only needs - //2KB sectors - - memzero_obj( fd_table ); - memzero_obj( fd_used ); - - inited = TRUE; - - return; -} - -////////////////////////////////////////////////////////////////////// -// CDVDFS_open -// called by 80000001 fileio_open for devices: "cdrom:", "cdrom0:" -////////////////////////////////////////////////////////////////////// -int CDVDFS_open(const char *name, int mode){ - int j; - static struct TocEntry tocEntry; - - // check if the file exists - if (CDVD_findfile(name, &tocEntry) != TRUE) - return -1; - - if(mode != 1) return -2; //SCE_RDONLY - - // set up a new file descriptor - for(j=0; j < 16; j++) if(fd_used[j] == 0) break; - if(j >= 16) return -3; - - fd_used[j] = 1; - files_open++; - - RPC_LOG("[CDVDisodrv:open] internal fd=%d\n", j); - - fd_table[j].fileSize = tocEntry.fileSize; - fd_table[j].LBA = tocEntry.fileLBA; - fd_table[j].filePos = 0; - - RPC_LOG("[CDVDisodrv ] tocEntry.fileSize = %d\n",tocEntry.fileSize); - return j; -} - -////////////////////////////////////////////////////////////////////// -// CDVDFS_lseek -// called by 80000001 fileio_lseek for devices: "cdrom:", "cdrom0:" -////////////////////////////////////////////////////////////////////// -int CDVDFS_lseek(int fd, int offset, int whence){ - - if ((fd >= 16) || (fd_used[fd]==0)){ - RPC_LOG("[CDVDisodrv:lseek] ERROR: File does not appear to be open!\n"); - return -1; - } - - switch(whence){ - case SEEK_SET: - fd_table[fd].filePos = offset; - break; - - case SEEK_CUR: - fd_table[fd].filePos += offset; - break; - - case SEEK_END: - fd_table[fd].filePos = fd_table[fd].fileSize + offset; - break; - - default: - return -1; - } - - if (fd_table[fd].filePos < 0) - fd_table[fd].filePos = 0; - - if (fd_table[fd].filePos > fd_table[fd].fileSize) - fd_table[fd].filePos = fd_table[fd].fileSize; - - return fd_table[fd].filePos; -} - -////////////////////////////////////////////////////////////////////// -// CDVDFS_read -// called by 80000001 fileio_read for devices: "cdrom:", "cdrom0:", "cdfs:" -////////////////////////////////////////////////////////////////////// -int CDVDFS_read( int fd, char *buffer, int size ){ -// int start_sector; - int off_sector; -// int num_sectors; - - //static char local_buffer[2024*2048]; //4MB - static char lb[2048]; //2KB - //Start, Aligned, End - int ssector, asector, esector; - int ssize=0, asize, esize; - - if ((fd >= 16) || (fd_used[fd]==0)){ - RPC_LOG("[CDVDisodrv:read] ERROR: File does not appear to be open!\n"); - return -1; - } - - // A few sanity checks - if (fd_table[fd].filePos > fd_table[fd].fileSize){ - // We cant start reading from past the beginning of the file - return 0; // File exists but we couldnt read anything from it - } - - if ((fd_table[fd].filePos + size) > fd_table[fd].fileSize) - size = fd_table[fd].fileSize - fd_table[fd].filePos; - - // Now work out where we want to start reading from - asector = ssector = fd_table[fd].LBA + (fd_table[fd].filePos >> 11); - off_sector = (fd_table[fd].filePos & 0x7FF); - if (off_sector){ - ssize = std::min(2048 - off_sector, size); - size -= ssize; - asector++; - } - asize = size & 0xFFFFF800; - esize = size & 0x000007FF; - esector=asector + (asize >> 11); - size += ssize; - - RPC_LOG("[CDVDisodrv:read] read sectors 0x%08X to 0x%08X\n", ssector, esector-(esize==0)); - - if (ssize){ - if (CdRead(ssector, 1, lb, &cdReadMode) != TRUE){ - RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); - return 0; - } - memcpy_fast(buffer, lb + off_sector, ssize); - } - if (asize) if (CdRead(asector, asize >> 11, buffer+ssize, &cdReadMode) != TRUE){ - RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); - return 0; - } - if (esize){ - if (CdRead(esector, 1, lb, &cdReadMode) != TRUE){ - RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); - return 0; - } - memcpy_fast(buffer+ssize+asize, lb, esize); - } -/*********************** - // Now work out where we want to start reading from - start_sector = fd_table[fd].LBA + (fd_table[fd].filePos >> 11); - off_sector = (fd_table[fd].filePos & 0x7FF); - num_sectors = ((off_sector + size) >> 11) + 1; - - RPC_LOG("[CDVDisodrv:read] read sectors 0x%08X to 0x%08X\n",start_sector,start_sector+num_sectors); - - // Read the data (we only ever get 16KB max request at once) - if (CdRead(start_sector, num_sectors, local_buffer, &cdReadMode) != TRUE){ - - //RPC_LOG("sector = %d, start sector = %d\n",sector,start_sector); - RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); - return 0; - } - //CdSync(0); hm, a wait function maybe... - - memcpy_fast(buffer,local_buffer+off_sector,size); -**************************/ - fd_table[fd].filePos += size; - - return (size); -} - -////////////////////////////////////////////////////////////////////// -// CDVDFS_write -// called by 80000001 fileio_write for devices: "cdrom:", "cdrom0:" -// hehe, this ain't a CD writing option :D -////////////////////////////////////////////////////////////////////// -int CDVDFS_write( int fd, char * buffer, int size ){ - if(size == 0) return 0; - else return -1; -} - -////////////////////////////////////////////////////////////////////// -// CDVDFS_close -// called by 80000001 fileio_close for devices: "cdrom:", "cdrom0:" -////////////////////////////////////////////////////////////////////// -int CDVDFS_close( int fd){ - - if ((fd >= 16) || (fd_used[fd]==0)){ - RPC_LOG("[CDVDisodrv:close] ERROR: File does not appear to be open!\n"); - return -1; - } - RPC_LOG("[CDVDisodrv:close] internal fd %d\n", fd); - fd_used[fd] = 0; - files_open--; - - return 0; -} - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Modified by Florin for PCSX2 emu + */ + +#include "PrecompiledHeader.h" + +#include "CDVDiso.h" +#include "CDVDisodrv.h" + +CdRMode cdReadMode; + +struct fdtable{ +//int fd; + int fileSize; + int LBA; + int filePos; +}; + +static struct fdtable fd_table[16]; +static int fd_used[16]; +static int files_open=0; +static int inited=FALSE; + +/************************************************************* +* The functions below are the normal file-system operations, * +* used to provide a standard filesystem interface * +*************************************************************/ + +////////////////////////////////////////////////////////////////////// +// CDVDFS_init +// called by 80000592 sceCdInit() +////////////////////////////////////////////////////////////////////// +void CDVDFS_init(){ + + if (inited) return;//might change in the future as a param; forceInit/Reset + + RPC_LOG("[CDVDisodrv:init] CDVD Filesystem v1.00\n"); + RPC_LOG("[CDVDisodrv ] \tby A.Lee (aka Hiryu) & Nicholas Van Veen (aka Sjeep)\n"); + RPC_LOG("[CDVDisodrv ] Initializing '%s' file driver.\n", "cdfs"); + + //CdInit(0); already called by plugin loading system ;) + + cdReadMode.trycount = 0; + cdReadMode.spindlctrl = CdSpinStm; + cdReadMode.datapattern = CdSecS2048; //isofs driver only needs + //2KB sectors + + memzero_obj( fd_table ); + memzero_obj( fd_used ); + + inited = TRUE; + + return; +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_open +// called by 80000001 fileio_open for devices: "cdrom:", "cdrom0:" +////////////////////////////////////////////////////////////////////// +int CDVDFS_open(const char *name, int mode){ + int j; + static struct TocEntry tocEntry; + + // check if the file exists + if (CDVD_findfile(name, &tocEntry) != TRUE) + return -1; + + if(mode != 1) return -2; //SCE_RDONLY + + // set up a new file descriptor + for(j=0; j < 16; j++) if(fd_used[j] == 0) break; + if(j >= 16) return -3; + + fd_used[j] = 1; + files_open++; + + RPC_LOG("[CDVDisodrv:open] internal fd=%d\n", j); + + fd_table[j].fileSize = tocEntry.fileSize; + fd_table[j].LBA = tocEntry.fileLBA; + fd_table[j].filePos = 0; + + RPC_LOG("[CDVDisodrv ] tocEntry.fileSize = %d\n",tocEntry.fileSize); + return j; +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_lseek +// called by 80000001 fileio_lseek for devices: "cdrom:", "cdrom0:" +////////////////////////////////////////////////////////////////////// +int CDVDFS_lseek(int fd, int offset, int whence){ + + if ((fd >= 16) || (fd_used[fd]==0)){ + RPC_LOG("[CDVDisodrv:lseek] ERROR: File does not appear to be open!\n"); + return -1; + } + + switch(whence){ + case SEEK_SET: + fd_table[fd].filePos = offset; + break; + + case SEEK_CUR: + fd_table[fd].filePos += offset; + break; + + case SEEK_END: + fd_table[fd].filePos = fd_table[fd].fileSize + offset; + break; + + default: + return -1; + } + + if (fd_table[fd].filePos < 0) + fd_table[fd].filePos = 0; + + if (fd_table[fd].filePos > fd_table[fd].fileSize) + fd_table[fd].filePos = fd_table[fd].fileSize; + + return fd_table[fd].filePos; +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_read +// called by 80000001 fileio_read for devices: "cdrom:", "cdrom0:", "cdfs:" +////////////////////////////////////////////////////////////////////// +int CDVDFS_read( int fd, char *buffer, int size ){ +// int start_sector; + int off_sector; +// int num_sectors; + + //static char local_buffer[2024*2048]; //4MB + static char lb[2048]; //2KB + //Start, Aligned, End + int ssector, asector, esector; + int ssize=0, asize, esize; + + if ((fd >= 16) || (fd_used[fd]==0)){ + RPC_LOG("[CDVDisodrv:read] ERROR: File does not appear to be open!\n"); + return -1; + } + + // A few sanity checks + if (fd_table[fd].filePos > fd_table[fd].fileSize){ + // We cant start reading from past the beginning of the file + return 0; // File exists but we couldnt read anything from it + } + + if ((fd_table[fd].filePos + size) > fd_table[fd].fileSize) + size = fd_table[fd].fileSize - fd_table[fd].filePos; + + // Now work out where we want to start reading from + asector = ssector = fd_table[fd].LBA + (fd_table[fd].filePos >> 11); + off_sector = (fd_table[fd].filePos & 0x7FF); + if (off_sector){ + ssize = std::min(2048 - off_sector, size); + size -= ssize; + asector++; + } + asize = size & 0xFFFFF800; + esize = size & 0x000007FF; + esector=asector + (asize >> 11); + size += ssize; + + RPC_LOG("[CDVDisodrv:read] read sectors 0x%08X to 0x%08X\n", ssector, esector-(esize==0)); + + if (ssize){ + if (CdRead(ssector, 1, lb, &cdReadMode) != TRUE){ + RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); + return 0; + } + memcpy_fast(buffer, lb + off_sector, ssize); + } + if (asize) if (CdRead(asector, asize >> 11, buffer+ssize, &cdReadMode) != TRUE){ + RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); + return 0; + } + if (esize){ + if (CdRead(esector, 1, lb, &cdReadMode) != TRUE){ + RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); + return 0; + } + memcpy_fast(buffer+ssize+asize, lb, esize); + } +/*********************** + // Now work out where we want to start reading from + start_sector = fd_table[fd].LBA + (fd_table[fd].filePos >> 11); + off_sector = (fd_table[fd].filePos & 0x7FF); + num_sectors = ((off_sector + size) >> 11) + 1; + + RPC_LOG("[CDVDisodrv:read] read sectors 0x%08X to 0x%08X\n",start_sector,start_sector+num_sectors); + + // Read the data (we only ever get 16KB max request at once) + if (CdRead(start_sector, num_sectors, local_buffer, &cdReadMode) != TRUE){ + + //RPC_LOG("sector = %d, start sector = %d\n",sector,start_sector); + RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); + return 0; + } + //CdSync(0); hm, a wait function maybe... + + memcpy_fast(buffer,local_buffer+off_sector,size); +**************************/ + fd_table[fd].filePos += size; + + return (size); +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_write +// called by 80000001 fileio_write for devices: "cdrom:", "cdrom0:" +// hehe, this ain't a CD writing option :D +////////////////////////////////////////////////////////////////////// +int CDVDFS_write( int fd, char * buffer, int size ){ + if(size == 0) return 0; + else return -1; +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_close +// called by 80000001 fileio_close for devices: "cdrom:", "cdrom0:" +////////////////////////////////////////////////////////////////////// +int CDVDFS_close( int fd){ + + if ((fd >= 16) || (fd_used[fd]==0)){ + RPC_LOG("[CDVDisodrv:close] ERROR: File does not appear to be open!\n"); + return -1; + } + RPC_LOG("[CDVDisodrv:close] internal fd %d\n", fd); + fd_used[fd] = 0; + files_open--; + + return 0; +} + diff --git a/pcsx2/CDVDisodrv.h b/pcsx2/CDVDisodrv.h index 65ed7387bc..e17928797e 100644 --- a/pcsx2/CDVDisodrv.h +++ b/pcsx2/CDVDisodrv.h @@ -1,38 +1,38 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -/* - * Original code from libcdvd by Hiryu & Sjeep (C) 2002 - * Modified by Florin for PCSX2 emu - */ - -#ifndef __CDVDISODRV_H__ -#define __CDVDISODRV_H__ - -#include "CDVDlib.h" - -extern CdRMode cdReadMode; - -/* Filing-system exported functions */ -void CDVDFS_init(); -int CDVDFS_open(const char *name, int mode); -int CDVDFS_lseek(int fd, int offset, int whence); -int CDVDFS_read( int fd, char * buffer, int size ); -int CDVDFS_write( int fd, char * buffer, int size ); -int CDVDFS_close( int fd); - -#endif//__CDVDISODRV_H__ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Modified by Florin for PCSX2 emu + */ + +#ifndef __CDVDISODRV_H__ +#define __CDVDISODRV_H__ + +#include "CDVDlib.h" + +extern CdRMode cdReadMode; + +/* Filing-system exported functions */ +void CDVDFS_init(); +int CDVDFS_open(const char *name, int mode); +int CDVDFS_lseek(int fd, int offset, int whence); +int CDVDFS_read( int fd, char * buffer, int size ); +int CDVDFS_write( int fd, char * buffer, int size ); +int CDVDFS_close( int fd); + +#endif//__CDVDISODRV_H__ diff --git a/pcsx2/CDVDlib.h b/pcsx2/CDVDlib.h index 72aa44d9c9..9e74fb8d6d 100644 --- a/pcsx2/CDVDlib.h +++ b/pcsx2/CDVDlib.h @@ -1,171 +1,171 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -/* - * Original code from libcdvd by Hiryu & Sjeep (C) 2002 - * Linux kernel headers - * Modified by Florin for PCSX2 emu - */ - -#ifndef _CDVDLIB_H -#define _CDVDLIB_H - -#include "Common.h" - -// Macros for READ Data pattan -#define CdSecS2048 0 // sector size 2048 -#define CdSecS2328 1 // sector size 2328 -#define CdSecS2340 2 // sector size 2340 - -//#define CD_FRAMESIZE_RAW1 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE) /*2340*/ -//#define CD_FRAMESIZE_RAW0 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE-CD_HEAD_SIZE) /*2336*/ -//#define CD_HEAD_SIZE 4 /* header (address) bytes per raw data frame */ -//#define CD_SUBHEAD_SIZE 8 /* subheader bytes per raw XA data frame */ -//#define CD_XA_HEAD (CD_HEAD_SIZE+CD_SUBHEAD_SIZE) /* "before data" part of raw XA frame */ - -/* - * A CD-ROM physical sector size is 2048, 2052, 2056, 2324, 2332, 2336, - * 2340, or 2352 bytes long. - * Sector types of the standard CD-ROM data formats: - * - * format sector type user data size (bytes) - * ----------------------------------------------------------------------------- - * 1 (Red Book) CD-DA 2352 (CD_FRAMESIZE_RAW) - * 2 (Yellow Book) Mode1 Form1 2048 (CD_FRAMESIZE) - * 3 (Yellow Book) Mode1 Form2 2336 (CD_FRAMESIZE_RAW0) - * 4 (Green Book) Mode2 Form1 2048 (CD_FRAMESIZE) - * 5 (Green Book) Mode2 Form2 2328 (2324+4 spare bytes) - * - * - * The layout of the standard CD-ROM data formats: - * ----------------------------------------------------------------------------- - * - audio (red): | audio_sample_bytes | - * | 2352 | - * - * - data (yellow, mode1): | sync - head - data - EDC - zero - ECC | - * | 12 - 4 - 2048 - 4 - 8 - 276 | - * - * - data (yellow, mode2): | sync - head - data | - * | 12 - 4 - 2336 | - * - * - XA data (green, mode2 form1): | sync - head - sub - data - EDC - ECC | - * | 12 - 4 - 8 - 2048 - 4 - 276 | - * - * - XA data (green, mode2 form2): | sync - head - sub - data - Spare | - * | 12 - 4 - 8 - 2324 - 4 | - * - */ - -// Macros for Spindle control -#define CdSpinMax 0 -#define CdSpinNom 1 // Starts reading data at maximum rotational velocity and if a read error occurs, the rotational velocity is reduced. -#define CdSpinStm 0 // Recommended stream rotation speed. - -// Macros for TrayReq -#define CdTrayOpen 0 -#define CdTrayClose 1 -#define CdTrayCheck 2 - -/* - * Macros for sceCdGetDiskType() //comments translated from japanese;) - */ - -#define SCECdIllgalMedia 0xff // ILIMEDIA (Illegal Media) A non-PS / non-PS2 Disc. -#define SCECdDVDV 0xfe // DVDV (DVD Video) A non-PS / non-PS2 Disc, but a DVD Video Disc -#define SCECdCDDA 0xfd // CDDA (CD DA) A non-PS / non-PS2 Disc that include a DA track -#define SCECdPS2DVD 0x14 // PS2DVD PS2 consumer DVD. -#define SCECdPS2CDDA 0x13 // PS2CDDA PS2 consumer CD that includes a DA track -#define SCECdPS2CD 0x12 // PS2CD PS2 consumer CD that does not include a DA track -#define SCECdPSCDDA 0x11 // PSCDDA PS CD that includes a DA track -#define SCECdPSCD 0x10 // PSCD PS CD that does not include a DA track -#define SCECdDETCT 0x01 // DETCT (Detecting) Disc distinction action -#define SCECdNODISC 0x00 // NODISC (No disc) No disc entered - - -/* - * Media mode - */ -#define SCECdCD 1 -#define SCECdDVD 2 - -typedef struct { - u8 stat; // 0: normal. Any other: error - u8 second; // second (BCD value) - u8 minute; // minute (BCD value) - u8 hour; // hour (BCD value) - u8 week; // week (BCD value) - u8 day; // day (BCD value) - u8 month; // month (BCD value) - u8 year; // year (BCD value) -} CdCLOCK; - -typedef struct { - u32 lsn; // Logical sector number of file - u32 size; // File size (in bytes) - char name[16]; // Filename - u8 date[8]; // 1th: Seconds - // 2th: Minutes - // 3th: Hours - // 4th: Date - // 5th: Month - // 6th 7th: Year (4 digits) -} CdlFILE; - -typedef struct { - u8 minute; // Minutes - u8 second; // Seconds - u8 sector; // Sector - u8 track; // Track number -} CdlLOCCD; - -typedef struct { - u8 trycount; // Read try count (No. of error retries + 1) (0 - 255) - u8 spindlctrl; // SCECdSpinStm: Recommended stream rotation speed. - // SCECdSpinNom: Starts reading data at maximum rotational velocity and if a read error occurs, the rotational velocity is reduced. - u8 datapattern; // SCECdSecS2048: Data size 2048 bytes - // SCECdSecS2328: 2328 bytes - // SCECdSecS2340: 2340 bytes - u8 pad; // Padding data produced by alignment. -} CdRMode; - -#if defined(_MSC_VER) -#pragma pack(1) -#endif - -struct TocEntry -{ - u32 fileLBA; - u32 fileSize; - u8 fileProperties; - u8 padding1[3]; - char filename[128+1]; - u8 date[7]; -#if defined(_MSC_VER) -}; -#else -} __attribute__((packed)); -#endif - -#if defined(_MSC_VER) -#pragma pack() -#endif - -int CDVD_findfile(const char* fname, struct TocEntry* tocEntry); -int CdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode); -int DvdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode); - -#endif // _CDVDLIB_H +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Linux kernel headers + * Modified by Florin for PCSX2 emu + */ + +#ifndef _CDVDLIB_H +#define _CDVDLIB_H + +#include "Common.h" + +// Macros for READ Data pattan +#define CdSecS2048 0 // sector size 2048 +#define CdSecS2328 1 // sector size 2328 +#define CdSecS2340 2 // sector size 2340 + +//#define CD_FRAMESIZE_RAW1 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE) /*2340*/ +//#define CD_FRAMESIZE_RAW0 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE-CD_HEAD_SIZE) /*2336*/ +//#define CD_HEAD_SIZE 4 /* header (address) bytes per raw data frame */ +//#define CD_SUBHEAD_SIZE 8 /* subheader bytes per raw XA data frame */ +//#define CD_XA_HEAD (CD_HEAD_SIZE+CD_SUBHEAD_SIZE) /* "before data" part of raw XA frame */ + +/* + * A CD-ROM physical sector size is 2048, 2052, 2056, 2324, 2332, 2336, + * 2340, or 2352 bytes long. + * Sector types of the standard CD-ROM data formats: + * + * format sector type user data size (bytes) + * ----------------------------------------------------------------------------- + * 1 (Red Book) CD-DA 2352 (CD_FRAMESIZE_RAW) + * 2 (Yellow Book) Mode1 Form1 2048 (CD_FRAMESIZE) + * 3 (Yellow Book) Mode1 Form2 2336 (CD_FRAMESIZE_RAW0) + * 4 (Green Book) Mode2 Form1 2048 (CD_FRAMESIZE) + * 5 (Green Book) Mode2 Form2 2328 (2324+4 spare bytes) + * + * + * The layout of the standard CD-ROM data formats: + * ----------------------------------------------------------------------------- + * - audio (red): | audio_sample_bytes | + * | 2352 | + * + * - data (yellow, mode1): | sync - head - data - EDC - zero - ECC | + * | 12 - 4 - 2048 - 4 - 8 - 276 | + * + * - data (yellow, mode2): | sync - head - data | + * | 12 - 4 - 2336 | + * + * - XA data (green, mode2 form1): | sync - head - sub - data - EDC - ECC | + * | 12 - 4 - 8 - 2048 - 4 - 276 | + * + * - XA data (green, mode2 form2): | sync - head - sub - data - Spare | + * | 12 - 4 - 8 - 2324 - 4 | + * + */ + +// Macros for Spindle control +#define CdSpinMax 0 +#define CdSpinNom 1 // Starts reading data at maximum rotational velocity and if a read error occurs, the rotational velocity is reduced. +#define CdSpinStm 0 // Recommended stream rotation speed. + +// Macros for TrayReq +#define CdTrayOpen 0 +#define CdTrayClose 1 +#define CdTrayCheck 2 + +/* + * Macros for sceCdGetDiskType() //comments translated from japanese;) + */ + +#define SCECdIllgalMedia 0xff // ILIMEDIA (Illegal Media) A non-PS / non-PS2 Disc. +#define SCECdDVDV 0xfe // DVDV (DVD Video) A non-PS / non-PS2 Disc, but a DVD Video Disc +#define SCECdCDDA 0xfd // CDDA (CD DA) A non-PS / non-PS2 Disc that include a DA track +#define SCECdPS2DVD 0x14 // PS2DVD PS2 consumer DVD. +#define SCECdPS2CDDA 0x13 // PS2CDDA PS2 consumer CD that includes a DA track +#define SCECdPS2CD 0x12 // PS2CD PS2 consumer CD that does not include a DA track +#define SCECdPSCDDA 0x11 // PSCDDA PS CD that includes a DA track +#define SCECdPSCD 0x10 // PSCD PS CD that does not include a DA track +#define SCECdDETCT 0x01 // DETCT (Detecting) Disc distinction action +#define SCECdNODISC 0x00 // NODISC (No disc) No disc entered + + +/* + * Media mode + */ +#define SCECdCD 1 +#define SCECdDVD 2 + +typedef struct { + u8 stat; // 0: normal. Any other: error + u8 second; // second (BCD value) + u8 minute; // minute (BCD value) + u8 hour; // hour (BCD value) + u8 week; // week (BCD value) + u8 day; // day (BCD value) + u8 month; // month (BCD value) + u8 year; // year (BCD value) +} CdCLOCK; + +typedef struct { + u32 lsn; // Logical sector number of file + u32 size; // File size (in bytes) + char name[16]; // Filename + u8 date[8]; // 1th: Seconds + // 2th: Minutes + // 3th: Hours + // 4th: Date + // 5th: Month + // 6th 7th: Year (4 digits) +} CdlFILE; + +typedef struct { + u8 minute; // Minutes + u8 second; // Seconds + u8 sector; // Sector + u8 track; // Track number +} CdlLOCCD; + +typedef struct { + u8 trycount; // Read try count (No. of error retries + 1) (0 - 255) + u8 spindlctrl; // SCECdSpinStm: Recommended stream rotation speed. + // SCECdSpinNom: Starts reading data at maximum rotational velocity and if a read error occurs, the rotational velocity is reduced. + u8 datapattern; // SCECdSecS2048: Data size 2048 bytes + // SCECdSecS2328: 2328 bytes + // SCECdSecS2340: 2340 bytes + u8 pad; // Padding data produced by alignment. +} CdRMode; + +#if defined(_MSC_VER) +#pragma pack(1) +#endif + +struct TocEntry +{ + u32 fileLBA; + u32 fileSize; + u8 fileProperties; + u8 padding1[3]; + char filename[128+1]; + u8 date[7]; +#if defined(_MSC_VER) +}; +#else +} __attribute__((packed)); +#endif + +#if defined(_MSC_VER) +#pragma pack() +#endif + +int CDVD_findfile(const char* fname, struct TocEntry* tocEntry); +int CdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode); +int DvdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode); + +#endif // _CDVDLIB_H diff --git a/pcsx2/COP0.cpp b/pcsx2/COP0.cpp index 41a4ab03be..7258ae0a63 100644 --- a/pcsx2/COP0.cpp +++ b/pcsx2/COP0.cpp @@ -1,357 +1,357 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "R5900.h" -#include "R5900OpcodeTables.h" - -u32 s_iLastCOP0Cycle = 0; -u32 s_iLastPERFCycle[2] = { 0, 0 }; - -void UpdateCP0Status() { - u32 value = cpuRegs.CP0.n.Status.val; - - if (value & 0x06 || - (value & 0x18) == 0) { // Kernel Mode (KSU = 0 | EXL = 1 | ERL = 1)*/ - memSetKernelMode(); // Kernel memory always - } else { // User Mode - memSetUserMode(); - } - cpuTestHwInts(); -} - -void WriteCP0Status(u32 value) { - cpuRegs.CP0.n.Status.val = value; - UpdateCP0Status(); -} - -void MapTLB(int i) -{ - u32 mask, addr; - u32 saddr, eaddr; - - DevCon::WriteLn("MAP TLB %d: %08x-> [%08x %08x] S=%d G=%d ASID=%d Mask= %03X", params - i,tlb[i].VPN2,tlb[i].PFN0,tlb[i].PFN1,tlb[i].S,tlb[i].G,tlb[i].ASID,tlb[i].Mask); - - if (tlb[i].S) - { - DevCon::WriteLn("OMG SPRAM MAPPING %08X %08X\n",params tlb[i].VPN2,tlb[i].Mask); - vtlb_VMapBuffer(tlb[i].VPN2,psS,0x4000); - } - - if (tlb[i].VPN2 == 0x70000000) return; //uh uhh right ... - - if (tlb[i].EntryLo0 & 0x2) { - mask = ((~tlb[i].Mask) << 1) & 0xfffff; - saddr = tlb[i].VPN2 >> 12; - eaddr = saddr + tlb[i].Mask + 1; - - for (addr=saddr; addr> 12) & mask)) { //match - memSetPageAddr(addr << 12, tlb[i].PFN0 + ((addr - saddr) << 12)); - Cpu->Clear(addr << 12, 1); - } - } - } - - if (tlb[i].EntryLo1 & 0x2) { - mask = ((~tlb[i].Mask) << 1) & 0xfffff; - saddr = (tlb[i].VPN2 >> 12) + tlb[i].Mask + 1; - eaddr = saddr + tlb[i].Mask + 1; - - for (addr=saddr; addr> 12) & mask)) { //match - memSetPageAddr(addr << 12, tlb[i].PFN1 + ((addr - saddr) << 12)); - Cpu->Clear(addr << 12, 1); - } - } - } -} - -void UnmapTLB(int i) -{ - //SysPrintf("Clear TLB %d: %08x-> [%08x %08x] S=%d G=%d ASID=%d Mask= %03X\n",i,tlb[i].VPN2,tlb[i].PFN0,tlb[i].PFN1,tlb[i].S,tlb[i].G,tlb[i].ASID,tlb[i].Mask); - u32 mask, addr; - u32 saddr, eaddr; - - if (tlb[i].S) - { - vtlb_VMapUnmap(tlb[i].VPN2,0x4000); - return; - } - - if (tlb[i].EntryLo0 & 0x2) - { - mask = ((~tlb[i].Mask) << 1) & 0xfffff; - saddr = tlb[i].VPN2 >> 12; - eaddr = saddr + tlb[i].Mask + 1; - // SysPrintf("Clear TLB: %08x ~ %08x\n",saddr,eaddr-1); - for (addr=saddr; addr> 12) & mask)) { //match - memClearPageAddr(addr << 12); - Cpu->Clear(addr << 12, 1); - } - } - } - - if (tlb[i].EntryLo1 & 0x2) { - mask = ((~tlb[i].Mask) << 1) & 0xfffff; - saddr = (tlb[i].VPN2 >> 12) + tlb[i].Mask + 1; - eaddr = saddr + tlb[i].Mask + 1; - // SysPrintf("Clear TLB: %08x ~ %08x\n",saddr,eaddr-1); - for (addr=saddr; addr> 12) & mask)) { //match - memClearPageAddr(addr << 12); - Cpu->Clear(addr << 12, 1); - } - } - } -} - -void WriteTLB(int i) -{ - tlb[i].PageMask = cpuRegs.CP0.n.PageMask; - tlb[i].EntryHi = cpuRegs.CP0.n.EntryHi; - tlb[i].EntryLo0 = cpuRegs.CP0.n.EntryLo0; - tlb[i].EntryLo1 = cpuRegs.CP0.n.EntryLo1; - - tlb[i].Mask = (cpuRegs.CP0.n.PageMask >> 13) & 0xfff; - tlb[i].nMask = (~tlb[i].Mask) & 0xfff; - tlb[i].VPN2 = ((cpuRegs.CP0.n.EntryHi >> 13) & (~tlb[i].Mask)) << 13; - tlb[i].ASID = cpuRegs.CP0.n.EntryHi & 0xfff; - tlb[i].G = cpuRegs.CP0.n.EntryLo0 & cpuRegs.CP0.n.EntryLo1 & 0x1; - tlb[i].PFN0 = (((cpuRegs.CP0.n.EntryLo0 >> 6) & 0xFFFFF) & (~tlb[i].Mask)) << 12; - tlb[i].PFN1 = (((cpuRegs.CP0.n.EntryLo1 >> 6) & 0xFFFFF) & (~tlb[i].Mask)) << 12; - tlb[i].S = cpuRegs.CP0.n.EntryLo0&0x80000000; - - MapTLB(i); -} - -namespace R5900 { -namespace Interpreter { -namespace OpcodeImpl { -namespace COP0 { - -void MFC0() { - if (!_Rt_) return; - if (_Rd_ != 9) { COP0_LOG("%s\n", disR5900Current.getCString() ); } - - //if(bExecBIOS == FALSE && _Rd_ == 25) SysPrintf("MFC0 _Rd_ %x = %x\n", _Rd_, cpuRegs.CP0.r[_Rd_]); - switch (_Rd_) { - - case 12: cpuRegs.GPR.r[_Rt_].UD[0] = (s64)(cpuRegs.CP0.r[_Rd_] & 0xf0c79c1f); break; - case 25: - switch(_Imm_ & 0x3F){ - case 0: cpuRegs.GPR.r[_Rt_].UD[0] = (s64)cpuRegs.PERF.n.pccr; break; - case 1: - if((cpuRegs.PERF.n.pccr & 0x800003E0) == 0x80000020) { - cpuRegs.PERF.n.pcr0 += cpuRegs.cycle-s_iLastPERFCycle[0]; - s_iLastPERFCycle[0] = cpuRegs.cycle; - } - - cpuRegs.GPR.r[_Rt_].UD[0] = (s64)cpuRegs.PERF.n.pcr0; - break; - case 3: - if((cpuRegs.PERF.n.pccr & 0x800F8000) == 0x80008000) { - cpuRegs.PERF.n.pcr1 += cpuRegs.cycle-s_iLastPERFCycle[1]; - s_iLastPERFCycle[1] = cpuRegs.cycle; - } - cpuRegs.GPR.r[_Rt_].UD[0] = (s64)cpuRegs.PERF.n.pcr1; - break; - } - /*SysPrintf("MFC0 PCCR = %x PCR0 = %x PCR1 = %x IMM= %x\n", - cpuRegs.PERF.n.pccr, cpuRegs.PERF.n.pcr0, cpuRegs.PERF.n.pcr1, _Imm_ & 0x3F);*/ - break; - case 24: - SysPrintf("MFC0 Breakpoint debug Registers code = %x\n", cpuRegs.code & 0x3FF); - break; - case 9: - // update - cpuRegs.CP0.n.Count += cpuRegs.cycle-s_iLastCOP0Cycle; - s_iLastCOP0Cycle = cpuRegs.cycle; - default: cpuRegs.GPR.r[_Rt_].UD[0] = (s64)cpuRegs.CP0.r[_Rd_]; - } -} - -void MTC0() { - COP0_LOG("%s\n", disR5900Current.getCString()); - //if(bExecBIOS == FALSE && _Rd_ == 25) SysPrintf("MTC0 _Rd_ %x = %x\n", _Rd_, cpuRegs.CP0.r[_Rd_]); - switch (_Rd_) { - case 25: - /*if(bExecBIOS == FALSE && _Rd_ == 25) SysPrintf("MTC0 PCCR = %x PCR0 = %x PCR1 = %x IMM= %x\n", - cpuRegs.PERF.n.pccr, cpuRegs.PERF.n.pcr0, cpuRegs.PERF.n.pcr1, _Imm_ & 0x3F);*/ - switch(_Imm_ & 0x3F){ - case 0: - if((cpuRegs.PERF.n.pccr & 0x800003E0) == 0x80000020) - cpuRegs.PERF.n.pcr0 += cpuRegs.cycle-s_iLastPERFCycle[0]; - if((cpuRegs.PERF.n.pccr & 0x800F8000) == 0x80008000) - cpuRegs.PERF.n.pcr1 += cpuRegs.cycle-s_iLastPERFCycle[1]; - cpuRegs.PERF.n.pccr = cpuRegs.GPR.r[_Rt_].UL[0]; - s_iLastPERFCycle[0] = cpuRegs.cycle; - s_iLastPERFCycle[1] = cpuRegs.cycle; - break; - case 1: cpuRegs.PERF.n.pcr0 = cpuRegs.GPR.r[_Rt_].UL[0]; s_iLastPERFCycle[0] = cpuRegs.cycle; break; - case 3: cpuRegs.PERF.n.pcr1 = cpuRegs.GPR.r[_Rt_].UL[0]; s_iLastPERFCycle[1] = cpuRegs.cycle; break; - } - break; - case 24: - SysPrintf("MTC0 Breakpoint debug Registers code = %x\n", cpuRegs.code & 0x3FF); - break; - case 12: WriteCP0Status(cpuRegs.GPR.r[_Rt_].UL[0]); break; - case 9: s_iLastCOP0Cycle = cpuRegs.cycle; cpuRegs.CP0.r[9] = cpuRegs.GPR.r[_Rt_].UL[0]; break; - default: cpuRegs.CP0.r[_Rd_] = cpuRegs.GPR.r[_Rt_].UL[0]; break; - } -} - -int CPCOND0() { - return (((psHu16(DMAC_STAT) & psHu16(DMAC_PCR)) & 0x3ff) == (psHu16(DMAC_PCR) & 0x3ff)); -} - -//#define CPCOND0 1 - -#define BC0(cond) \ - if (CPCOND0() cond) { \ - intDoBranch(_BranchTarget_); \ - } - -void BC0F() { - BC0(== 0); - COP0_LOG( "COP0 > BC0F\n" ); -} - -void BC0T() { - BC0(== 1); - COP0_LOG( "COP0 > BC0T\n" ); -} - -#define BC0L(cond) \ - if (CPCOND0() cond) { \ - intDoBranch(_BranchTarget_); \ - } else cpuRegs.pc+= 4; - -void BC0FL() { - BC0L(== 0); - COP0_LOG( "COP0 > BC0FL\n" ); -} - -void BC0TL() { - BC0L(== 1); - COP0_LOG( "COP0 > BCOTL\n" ); -} - -void TLBR() { -/* CPU_LOG("COP0_TLBR %d:%x,%x,%x,%x\n", - cpuRegs.CP0.n.Random, cpuRegs.CP0.n.PageMask, cpuRegs.CP0.n.EntryHi, - cpuRegs.CP0.n.EntryLo0, cpuRegs.CP0.n.EntryLo1);*/ - - int i = cpuRegs.CP0.n.Index&0x1f; - - COP0_LOG("COP0 > TLBR\n"); - cpuRegs.CP0.n.PageMask = tlb[i].PageMask; - cpuRegs.CP0.n.EntryHi = tlb[i].EntryHi&~(tlb[i].PageMask|0x1f00); - cpuRegs.CP0.n.EntryLo0 = (tlb[i].EntryLo0&~1)|((tlb[i].EntryHi>>12)&1); - cpuRegs.CP0.n.EntryLo1 =(tlb[i].EntryLo1&~1)|((tlb[i].EntryHi>>12)&1); -} - -void TLBWI() { - int j = cpuRegs.CP0.n.Index & 0x3f; - - if (j > 48) return; - -/* CPU_LOG("COP0_TLBWI %d:%x,%x,%x,%x\n", - cpuRegs.CP0.n.Index, cpuRegs.CP0.n.PageMask, cpuRegs.CP0.n.EntryHi, - cpuRegs.CP0.n.EntryLo0, cpuRegs.CP0.n.EntryLo1);*/ - - UnmapTLB(j); - WriteTLB(j); -} - -void TLBWR() { - int j = cpuRegs.CP0.n.Random & 0x3f; - - if (j > 48) return; - -/* CPU_LOG("COP0_TLBWR %d:%x,%x,%x,%x\n", - cpuRegs.CP0.n.Random, cpuRegs.CP0.n.PageMask, cpuRegs.CP0.n.EntryHi, - cpuRegs.CP0.n.EntryLo0, cpuRegs.CP0.n.EntryLo1);*/ - -// if( !bExecBIOS ) -// __Log("TLBWR %d\n", j); - - UnmapTLB(j); - WriteTLB(j); -} - -void TLBP() { - int i; - - - union { - struct { - u32 VPN2:19; - u32 VPN2X:2; - u32 G:3; - u32 ASID:8; - } s; - u32 u; - } EntryHi32; - - EntryHi32.u=cpuRegs.CP0.n.EntryHi; - - cpuRegs.CP0.n.Index=0xFFFFFFFF; - for(i=0;i<48;i++){ - if(tlb[i].VPN2==((~tlb[i].Mask)&(EntryHi32.s.VPN2)) - &&((tlb[i].G&1)||((tlb[i].ASID & 0xff) == EntryHi32.s.ASID))) { - cpuRegs.CP0.n.Index=i; - break; - } - } - if(cpuRegs.CP0.n.Index == 0xFFFFFFFF) cpuRegs.CP0.n.Index = 0x80000000; -} - -void ERET() { - if (cpuRegs.CP0.n.Status.b.ERL) { - cpuRegs.pc = cpuRegs.CP0.n.ErrorEPC; - cpuRegs.CP0.n.Status.b.ERL = 0; - } else { - cpuRegs.pc = cpuRegs.CP0.n.EPC; - cpuRegs.CP0.n.Status.b.EXL = 0; - } - UpdateCP0Status(); - intSetBranch(); -} - -void DI() { - if (cpuRegs.CP0.n.Status.b._EDI || cpuRegs.CP0.n.Status.b.EXL || - cpuRegs.CP0.n.Status.b.ERL || (cpuRegs.CP0.n.Status.b.KSU == 0)) { - cpuRegs.CP0.n.Status.b.EIE = 0; - //UpdateCP0Status(); // ints are disabled so checking for them is kinda silly... - } -} - -void EI() { - if (cpuRegs.CP0.n.Status.b._EDI || cpuRegs.CP0.n.Status.b.EXL || - cpuRegs.CP0.n.Status.b.ERL || (cpuRegs.CP0.n.Status.b.KSU == 0)) { - cpuRegs.CP0.n.Status.b.EIE = 1; - UpdateCP0Status(); - } -} - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "R5900.h" +#include "R5900OpcodeTables.h" + +u32 s_iLastCOP0Cycle = 0; +u32 s_iLastPERFCycle[2] = { 0, 0 }; + +void UpdateCP0Status() { + u32 value = cpuRegs.CP0.n.Status.val; + + if (value & 0x06 || + (value & 0x18) == 0) { // Kernel Mode (KSU = 0 | EXL = 1 | ERL = 1)*/ + memSetKernelMode(); // Kernel memory always + } else { // User Mode + memSetUserMode(); + } + cpuTestHwInts(); +} + +void WriteCP0Status(u32 value) { + cpuRegs.CP0.n.Status.val = value; + UpdateCP0Status(); +} + +void MapTLB(int i) +{ + u32 mask, addr; + u32 saddr, eaddr; + + DevCon::WriteLn("MAP TLB %d: %08x-> [%08x %08x] S=%d G=%d ASID=%d Mask= %03X", params + i,tlb[i].VPN2,tlb[i].PFN0,tlb[i].PFN1,tlb[i].S,tlb[i].G,tlb[i].ASID,tlb[i].Mask); + + if (tlb[i].S) + { + DevCon::WriteLn("OMG SPRAM MAPPING %08X %08X\n",params tlb[i].VPN2,tlb[i].Mask); + vtlb_VMapBuffer(tlb[i].VPN2,psS,0x4000); + } + + if (tlb[i].VPN2 == 0x70000000) return; //uh uhh right ... + + if (tlb[i].EntryLo0 & 0x2) { + mask = ((~tlb[i].Mask) << 1) & 0xfffff; + saddr = tlb[i].VPN2 >> 12; + eaddr = saddr + tlb[i].Mask + 1; + + for (addr=saddr; addr> 12) & mask)) { //match + memSetPageAddr(addr << 12, tlb[i].PFN0 + ((addr - saddr) << 12)); + Cpu->Clear(addr << 12, 1); + } + } + } + + if (tlb[i].EntryLo1 & 0x2) { + mask = ((~tlb[i].Mask) << 1) & 0xfffff; + saddr = (tlb[i].VPN2 >> 12) + tlb[i].Mask + 1; + eaddr = saddr + tlb[i].Mask + 1; + + for (addr=saddr; addr> 12) & mask)) { //match + memSetPageAddr(addr << 12, tlb[i].PFN1 + ((addr - saddr) << 12)); + Cpu->Clear(addr << 12, 1); + } + } + } +} + +void UnmapTLB(int i) +{ + //SysPrintf("Clear TLB %d: %08x-> [%08x %08x] S=%d G=%d ASID=%d Mask= %03X\n",i,tlb[i].VPN2,tlb[i].PFN0,tlb[i].PFN1,tlb[i].S,tlb[i].G,tlb[i].ASID,tlb[i].Mask); + u32 mask, addr; + u32 saddr, eaddr; + + if (tlb[i].S) + { + vtlb_VMapUnmap(tlb[i].VPN2,0x4000); + return; + } + + if (tlb[i].EntryLo0 & 0x2) + { + mask = ((~tlb[i].Mask) << 1) & 0xfffff; + saddr = tlb[i].VPN2 >> 12; + eaddr = saddr + tlb[i].Mask + 1; + // SysPrintf("Clear TLB: %08x ~ %08x\n",saddr,eaddr-1); + for (addr=saddr; addr> 12) & mask)) { //match + memClearPageAddr(addr << 12); + Cpu->Clear(addr << 12, 1); + } + } + } + + if (tlb[i].EntryLo1 & 0x2) { + mask = ((~tlb[i].Mask) << 1) & 0xfffff; + saddr = (tlb[i].VPN2 >> 12) + tlb[i].Mask + 1; + eaddr = saddr + tlb[i].Mask + 1; + // SysPrintf("Clear TLB: %08x ~ %08x\n",saddr,eaddr-1); + for (addr=saddr; addr> 12) & mask)) { //match + memClearPageAddr(addr << 12); + Cpu->Clear(addr << 12, 1); + } + } + } +} + +void WriteTLB(int i) +{ + tlb[i].PageMask = cpuRegs.CP0.n.PageMask; + tlb[i].EntryHi = cpuRegs.CP0.n.EntryHi; + tlb[i].EntryLo0 = cpuRegs.CP0.n.EntryLo0; + tlb[i].EntryLo1 = cpuRegs.CP0.n.EntryLo1; + + tlb[i].Mask = (cpuRegs.CP0.n.PageMask >> 13) & 0xfff; + tlb[i].nMask = (~tlb[i].Mask) & 0xfff; + tlb[i].VPN2 = ((cpuRegs.CP0.n.EntryHi >> 13) & (~tlb[i].Mask)) << 13; + tlb[i].ASID = cpuRegs.CP0.n.EntryHi & 0xfff; + tlb[i].G = cpuRegs.CP0.n.EntryLo0 & cpuRegs.CP0.n.EntryLo1 & 0x1; + tlb[i].PFN0 = (((cpuRegs.CP0.n.EntryLo0 >> 6) & 0xFFFFF) & (~tlb[i].Mask)) << 12; + tlb[i].PFN1 = (((cpuRegs.CP0.n.EntryLo1 >> 6) & 0xFFFFF) & (~tlb[i].Mask)) << 12; + tlb[i].S = cpuRegs.CP0.n.EntryLo0&0x80000000; + + MapTLB(i); +} + +namespace R5900 { +namespace Interpreter { +namespace OpcodeImpl { +namespace COP0 { + +void MFC0() { + if (!_Rt_) return; + if (_Rd_ != 9) { COP0_LOG("%s\n", disR5900Current.getCString() ); } + + //if(bExecBIOS == FALSE && _Rd_ == 25) SysPrintf("MFC0 _Rd_ %x = %x\n", _Rd_, cpuRegs.CP0.r[_Rd_]); + switch (_Rd_) { + + case 12: cpuRegs.GPR.r[_Rt_].UD[0] = (s64)(cpuRegs.CP0.r[_Rd_] & 0xf0c79c1f); break; + case 25: + switch(_Imm_ & 0x3F){ + case 0: cpuRegs.GPR.r[_Rt_].UD[0] = (s64)cpuRegs.PERF.n.pccr; break; + case 1: + if((cpuRegs.PERF.n.pccr & 0x800003E0) == 0x80000020) { + cpuRegs.PERF.n.pcr0 += cpuRegs.cycle-s_iLastPERFCycle[0]; + s_iLastPERFCycle[0] = cpuRegs.cycle; + } + + cpuRegs.GPR.r[_Rt_].UD[0] = (s64)cpuRegs.PERF.n.pcr0; + break; + case 3: + if((cpuRegs.PERF.n.pccr & 0x800F8000) == 0x80008000) { + cpuRegs.PERF.n.pcr1 += cpuRegs.cycle-s_iLastPERFCycle[1]; + s_iLastPERFCycle[1] = cpuRegs.cycle; + } + cpuRegs.GPR.r[_Rt_].UD[0] = (s64)cpuRegs.PERF.n.pcr1; + break; + } + /*SysPrintf("MFC0 PCCR = %x PCR0 = %x PCR1 = %x IMM= %x\n", + cpuRegs.PERF.n.pccr, cpuRegs.PERF.n.pcr0, cpuRegs.PERF.n.pcr1, _Imm_ & 0x3F);*/ + break; + case 24: + SysPrintf("MFC0 Breakpoint debug Registers code = %x\n", cpuRegs.code & 0x3FF); + break; + case 9: + // update + cpuRegs.CP0.n.Count += cpuRegs.cycle-s_iLastCOP0Cycle; + s_iLastCOP0Cycle = cpuRegs.cycle; + default: cpuRegs.GPR.r[_Rt_].UD[0] = (s64)cpuRegs.CP0.r[_Rd_]; + } +} + +void MTC0() { + COP0_LOG("%s\n", disR5900Current.getCString()); + //if(bExecBIOS == FALSE && _Rd_ == 25) SysPrintf("MTC0 _Rd_ %x = %x\n", _Rd_, cpuRegs.CP0.r[_Rd_]); + switch (_Rd_) { + case 25: + /*if(bExecBIOS == FALSE && _Rd_ == 25) SysPrintf("MTC0 PCCR = %x PCR0 = %x PCR1 = %x IMM= %x\n", + cpuRegs.PERF.n.pccr, cpuRegs.PERF.n.pcr0, cpuRegs.PERF.n.pcr1, _Imm_ & 0x3F);*/ + switch(_Imm_ & 0x3F){ + case 0: + if((cpuRegs.PERF.n.pccr & 0x800003E0) == 0x80000020) + cpuRegs.PERF.n.pcr0 += cpuRegs.cycle-s_iLastPERFCycle[0]; + if((cpuRegs.PERF.n.pccr & 0x800F8000) == 0x80008000) + cpuRegs.PERF.n.pcr1 += cpuRegs.cycle-s_iLastPERFCycle[1]; + cpuRegs.PERF.n.pccr = cpuRegs.GPR.r[_Rt_].UL[0]; + s_iLastPERFCycle[0] = cpuRegs.cycle; + s_iLastPERFCycle[1] = cpuRegs.cycle; + break; + case 1: cpuRegs.PERF.n.pcr0 = cpuRegs.GPR.r[_Rt_].UL[0]; s_iLastPERFCycle[0] = cpuRegs.cycle; break; + case 3: cpuRegs.PERF.n.pcr1 = cpuRegs.GPR.r[_Rt_].UL[0]; s_iLastPERFCycle[1] = cpuRegs.cycle; break; + } + break; + case 24: + SysPrintf("MTC0 Breakpoint debug Registers code = %x\n", cpuRegs.code & 0x3FF); + break; + case 12: WriteCP0Status(cpuRegs.GPR.r[_Rt_].UL[0]); break; + case 9: s_iLastCOP0Cycle = cpuRegs.cycle; cpuRegs.CP0.r[9] = cpuRegs.GPR.r[_Rt_].UL[0]; break; + default: cpuRegs.CP0.r[_Rd_] = cpuRegs.GPR.r[_Rt_].UL[0]; break; + } +} + +int CPCOND0() { + return (((psHu16(DMAC_STAT) & psHu16(DMAC_PCR)) & 0x3ff) == (psHu16(DMAC_PCR) & 0x3ff)); +} + +//#define CPCOND0 1 + +#define BC0(cond) \ + if (CPCOND0() cond) { \ + intDoBranch(_BranchTarget_); \ + } + +void BC0F() { + BC0(== 0); + COP0_LOG( "COP0 > BC0F\n" ); +} + +void BC0T() { + BC0(== 1); + COP0_LOG( "COP0 > BC0T\n" ); +} + +#define BC0L(cond) \ + if (CPCOND0() cond) { \ + intDoBranch(_BranchTarget_); \ + } else cpuRegs.pc+= 4; + +void BC0FL() { + BC0L(== 0); + COP0_LOG( "COP0 > BC0FL\n" ); +} + +void BC0TL() { + BC0L(== 1); + COP0_LOG( "COP0 > BCOTL\n" ); +} + +void TLBR() { +/* CPU_LOG("COP0_TLBR %d:%x,%x,%x,%x\n", + cpuRegs.CP0.n.Random, cpuRegs.CP0.n.PageMask, cpuRegs.CP0.n.EntryHi, + cpuRegs.CP0.n.EntryLo0, cpuRegs.CP0.n.EntryLo1);*/ + + int i = cpuRegs.CP0.n.Index&0x1f; + + COP0_LOG("COP0 > TLBR\n"); + cpuRegs.CP0.n.PageMask = tlb[i].PageMask; + cpuRegs.CP0.n.EntryHi = tlb[i].EntryHi&~(tlb[i].PageMask|0x1f00); + cpuRegs.CP0.n.EntryLo0 = (tlb[i].EntryLo0&~1)|((tlb[i].EntryHi>>12)&1); + cpuRegs.CP0.n.EntryLo1 =(tlb[i].EntryLo1&~1)|((tlb[i].EntryHi>>12)&1); +} + +void TLBWI() { + int j = cpuRegs.CP0.n.Index & 0x3f; + + if (j > 48) return; + +/* CPU_LOG("COP0_TLBWI %d:%x,%x,%x,%x\n", + cpuRegs.CP0.n.Index, cpuRegs.CP0.n.PageMask, cpuRegs.CP0.n.EntryHi, + cpuRegs.CP0.n.EntryLo0, cpuRegs.CP0.n.EntryLo1);*/ + + UnmapTLB(j); + WriteTLB(j); +} + +void TLBWR() { + int j = cpuRegs.CP0.n.Random & 0x3f; + + if (j > 48) return; + +/* CPU_LOG("COP0_TLBWR %d:%x,%x,%x,%x\n", + cpuRegs.CP0.n.Random, cpuRegs.CP0.n.PageMask, cpuRegs.CP0.n.EntryHi, + cpuRegs.CP0.n.EntryLo0, cpuRegs.CP0.n.EntryLo1);*/ + +// if( !bExecBIOS ) +// __Log("TLBWR %d\n", j); + + UnmapTLB(j); + WriteTLB(j); +} + +void TLBP() { + int i; + + + union { + struct { + u32 VPN2:19; + u32 VPN2X:2; + u32 G:3; + u32 ASID:8; + } s; + u32 u; + } EntryHi32; + + EntryHi32.u=cpuRegs.CP0.n.EntryHi; + + cpuRegs.CP0.n.Index=0xFFFFFFFF; + for(i=0;i<48;i++){ + if(tlb[i].VPN2==((~tlb[i].Mask)&(EntryHi32.s.VPN2)) + &&((tlb[i].G&1)||((tlb[i].ASID & 0xff) == EntryHi32.s.ASID))) { + cpuRegs.CP0.n.Index=i; + break; + } + } + if(cpuRegs.CP0.n.Index == 0xFFFFFFFF) cpuRegs.CP0.n.Index = 0x80000000; +} + +void ERET() { + if (cpuRegs.CP0.n.Status.b.ERL) { + cpuRegs.pc = cpuRegs.CP0.n.ErrorEPC; + cpuRegs.CP0.n.Status.b.ERL = 0; + } else { + cpuRegs.pc = cpuRegs.CP0.n.EPC; + cpuRegs.CP0.n.Status.b.EXL = 0; + } + UpdateCP0Status(); + intSetBranch(); +} + +void DI() { + if (cpuRegs.CP0.n.Status.b._EDI || cpuRegs.CP0.n.Status.b.EXL || + cpuRegs.CP0.n.Status.b.ERL || (cpuRegs.CP0.n.Status.b.KSU == 0)) { + cpuRegs.CP0.n.Status.b.EIE = 0; + //UpdateCP0Status(); // ints are disabled so checking for them is kinda silly... + } +} + +void EI() { + if (cpuRegs.CP0.n.Status.b._EDI || cpuRegs.CP0.n.Status.b.EXL || + cpuRegs.CP0.n.Status.b.ERL || (cpuRegs.CP0.n.Status.b.KSU == 0)) { + cpuRegs.CP0.n.Status.b.EIE = 1; + UpdateCP0Status(); + } +} + } } } } // end namespace R5900::Interpreter::OpcodeImpl \ No newline at end of file diff --git a/pcsx2/COP0.h b/pcsx2/COP0.h index 1945532fa4..6fb2a200d0 100644 --- a/pcsx2/COP0.h +++ b/pcsx2/COP0.h @@ -1,28 +1,28 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __COP0_H__ -#define __COP0_H__ - -void WriteCP0Status(u32 value); -void UpdateCP0Status(); -void WriteTLB(int i); -void UnmapTLB(int i); -void MapTLB(int i); - -#endif /* __COP0_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __COP0_H__ +#define __COP0_H__ + +void WriteCP0Status(u32 value); +void UpdateCP0Status(); +void WriteTLB(int i); +void UnmapTLB(int i); +void MapTLB(int i); + +#endif /* __COP0_H__ */ diff --git a/pcsx2/COP2.cpp b/pcsx2/COP2.cpp index d52f32cdea..372a520718 100644 --- a/pcsx2/COP2.cpp +++ b/pcsx2/COP2.cpp @@ -1,89 +1,89 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "DebugTools/Debug.h" -#include "R5900.h" -#include "R5900OpcodeTables.h" -#include "VUops.h" -#include "VUmicro.h" - -//namespace R5900 { -//namespace Interpreter { -//namespace OpcodeImpl{ - -using namespace R5900; -using namespace R5900::Interpreter; - -#define CP2COND (((VU0.VI[REG_VPU_STAT].US[0] >> 8) & 1)) - -void VCALLMS() { - vu0Finish(); - vu0ExecMicro(((cpuRegs.code >> 6) & 0x7FFF) * 8); -} - -void VCALLMSR() { - vu0Finish(); - vu0ExecMicro(VU0.VI[REG_CMSAR0].US[0] * 8); -} - -void BC2F() -{ - if (CP2COND == 0) - { - SysPrintf("VU0 Macro Branch \n"); - intDoBranch(_BranchTarget_); - } -} -void BC2T() -{ - if (CP2COND == 1) - { - SysPrintf("VU0 Macro Branch \n"); - intDoBranch(_BranchTarget_); - } -} - -void BC2FL() -{ - if (CP2COND == 0) - { - SysPrintf("VU0 Macro Branch \n"); - intDoBranch(_BranchTarget_); - } - else - { - cpuRegs.pc+= 4; - } -} -void BC2TL() -{ - if (CP2COND == 1) - { - SysPrintf("VU0 Macro Branch \n"); - intDoBranch(_BranchTarget_); - } - else - { - cpuRegs.pc+= 4; - } -} - -//}}} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "DebugTools/Debug.h" +#include "R5900.h" +#include "R5900OpcodeTables.h" +#include "VUops.h" +#include "VUmicro.h" + +//namespace R5900 { +//namespace Interpreter { +//namespace OpcodeImpl{ + +using namespace R5900; +using namespace R5900::Interpreter; + +#define CP2COND (((VU0.VI[REG_VPU_STAT].US[0] >> 8) & 1)) + +void VCALLMS() { + vu0Finish(); + vu0ExecMicro(((cpuRegs.code >> 6) & 0x7FFF) * 8); +} + +void VCALLMSR() { + vu0Finish(); + vu0ExecMicro(VU0.VI[REG_CMSAR0].US[0] * 8); +} + +void BC2F() +{ + if (CP2COND == 0) + { + SysPrintf("VU0 Macro Branch \n"); + intDoBranch(_BranchTarget_); + } +} +void BC2T() +{ + if (CP2COND == 1) + { + SysPrintf("VU0 Macro Branch \n"); + intDoBranch(_BranchTarget_); + } +} + +void BC2FL() +{ + if (CP2COND == 0) + { + SysPrintf("VU0 Macro Branch \n"); + intDoBranch(_BranchTarget_); + } + else + { + cpuRegs.pc+= 4; + } +} +void BC2TL() +{ + if (CP2COND == 1) + { + SysPrintf("VU0 Macro Branch \n"); + intDoBranch(_BranchTarget_); + } + else + { + cpuRegs.pc+= 4; + } +} + +//}}} diff --git a/pcsx2/Cache.cpp b/pcsx2/Cache.cpp index 2ded259fed..d1c86c7daa 100644 --- a/pcsx2/Cache.cpp +++ b/pcsx2/Cache.cpp @@ -1,400 +1,400 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "Cache.h" - -_cacheS pCache[64]; - -namespace R5900{ -namespace Interpreter -{ - -#ifdef PCSX2_CACHE_EMU_MEM -int getFreeCache(u32 mem, int mode, int * way) { - u8 * out; - u32 paddr; - u32 taddr[2]; - u8 * t; - int number; - int i = (mem >> 6) & 0x3F; - - paddr = memLUTR[mem >> 12]; - taddr[0] = memLUTW[pCache[i].tag[0]>>12]; - taddr[1] = memLUTW[pCache[i].tag[1]>>12]; - - if (taddr[0] == paddr && (pCache[i].tag[0] & 0x20)) - { - *way = 0; - return i; - }else if(taddr[1] == paddr && (pCache[i].tag[1] & 0x20)) - { - *way = 1; - return i; - } - - number = ((pCache[i].tag[0]>>4) & 1) ^ ((pCache[i].tag[1]>>4) & 1); - - if(pCache[i].tag[number] & 0x60) // Valid Dirty - { - t = (u8*)(taddr[number]); - out = (u8*)(t + (mem & 0xFC0)); - ((u64*)out)[0] = ((u64*)pCache[i].data[number][0].b8._8)[0]; - ((u64*)out)[1] = ((u64*)pCache[i].data[number][0].b8._8)[1]; - ((u64*)out)[2] = ((u64*)pCache[i].data[number][1].b8._8)[0]; - ((u64*)out)[3] = ((u64*)pCache[i].data[number][1].b8._8)[1]; - ((u64*)out)[4] = ((u64*)pCache[i].data[number][2].b8._8)[0]; - ((u64*)out)[5] = ((u64*)pCache[i].data[number][2].b8._8)[1]; - ((u64*)out)[6] = ((u64*)pCache[i].data[number][3].b8._8)[0]; - ((u64*)out)[7] = ((u64*)pCache[i].data[number][3].b8._8)[1]; - } - - - - if(mode == 1) - { - pCache[i].tag[number] |= 0x40; // Set Dirty Bit if mode == write - } - - pCache[i].tag[number] &= ~(0xFFFFF000); - pCache[i].tag[number] |= ((mem>>12) & 0xFFFFF) << 12; - - - t = (u8 *)paddr; - out= (u8*)(t + (mem & 0xFC0)); - ((u64*)pCache[i].data[number][0].b8._8)[0] = ((u64*)out)[0]; - ((u64*)pCache[i].data[number][0].b8._8)[1] = ((u64*)out)[1]; - ((u64*)pCache[i].data[number][1].b8._8)[0] = ((u64*)out)[2]; - ((u64*)pCache[i].data[number][1].b8._8)[1] = ((u64*)out)[3]; - ((u64*)pCache[i].data[number][2].b8._8)[0] = ((u64*)out)[4]; - ((u64*)pCache[i].data[number][2].b8._8)[1] = ((u64*)out)[5]; - ((u64*)pCache[i].data[number][3].b8._8)[0] = ((u64*)out)[6]; - ((u64*)pCache[i].data[number][3].b8._8)[1] = ((u64*)out)[7]; - - if(pCache[i].tag[number] & 0x10) pCache[i].tag[number] &= ~(0x10); - else pCache[i].tag[number] |= 0x10; - - pCache[i].tag[number] |= 0x20; - *way = number; - return i; -} - -void writeCache8(u32 mem, u8 value) { - int i, number; - - i = getFreeCache(mem,1,&number); -// CACHE_LOG("writeCache8 %8.8x adding to %d, way %d, value %x\n", mem, i,number,value); - - pCache[i].data[number][(mem>>4) & 0x3].b8._8[(mem&0xf)] = value; -} - -void writeCache16(u32 mem, u16 value) { - int i, number; - - i = getFreeCache(mem,1,&number); -// CACHE_LOG("writeCache16 %8.8x adding to %d, way %d, value %x\n", mem, i,number,value); - - *(u16*)(&pCache[i].data[number][(mem>>4) & 0x3].b8._8[(mem&0xf)]) = value; -} - -void writeCache32(u32 mem, u32 value) { - int i, number; - - i = getFreeCache(mem,1,&number); -// CACHE_LOG("writeCache32 %8.8x adding to %d, way %d, value %x\n", mem, i,number,value); - *(u32*)(&pCache[i].data[number][(mem>>4) & 0x3].b8._8[(mem&0xf)]) = value; -} - -void writeCache64(u32 mem, u64 value) { - int i, number; - - i = getFreeCache(mem,1,&number); -// CACHE_LOG("writeCache64 %8.8x adding to %d, way %d, value %x\n", mem, i,number,value); - *(u64*)(&pCache[i].data[number][(mem>>4) & 0x3].b8._8[(mem&0xf)]) = value; -} - -void writeCache128(u32 mem, u64 *value) { - int i, number; - - i = getFreeCache(mem,1,&number); -// CACHE_LOG("writeCache128 %8.8x adding to %d\n", mem, i); - ((u64*)pCache[i].data[number][(mem>>4) & 0x3].b8._8)[0] = value[0]; - ((u64*)pCache[i].data[number][(mem>>4) & 0x3].b8._8)[1] = value[1]; -} - -u8 *readCache(u32 mem) { - int i, number; - - i = getFreeCache(mem,0,&number); -// CACHE_LOG("readCache %8.8x from %d, way %d\n", mem, i,number); - - return pCache[i].data[number][(mem>>4) & 0x3].b8._8; -} - -namespace OpcodeImpl -{ - -extern int Dcache; -void CACHE() { - u32 addr; - //if(Dcache == 0) return; - addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - switch (_Rt_) { - case 0x1a: - { - int index = (addr >> 6) & 0x3F; - u32 paddr[2]; - int way; - u32 taddr = memLUTR[addr >> 12]; - paddr[0] = memLUTW[pCache[index].tag[0] >> 12]; - paddr[1] = memLUTW[pCache[index].tag[1] >> 12]; - - if(paddr[0] == taddr && (pCache[index].tag[0] & 0x20)) - { - way = 0; - } - else if(paddr[1] == taddr && (pCache[index].tag[1] & 0x20)) - { - way = 1; - } - else - { - return; - } - - CACHE_LOG("CACHE DHIN addr %x, index %d, way %d, Flags %x\n",addr,index,way,pCache[index].tag[way] & 0x78); - - pCache[index].tag[way] &= ~(0x6F); - ((u64*)pCache[index].data[way][0].b8._8)[0] = 0; - ((u64*)pCache[index].data[way][0].b8._8)[1] = 0; - ((u64*)pCache[index].data[way][1].b8._8)[0] = 0; - ((u64*)pCache[index].data[way][1].b8._8)[1] = 0; - ((u64*)pCache[index].data[way][2].b8._8)[0] = 0; - ((u64*)pCache[index].data[way][2].b8._8)[1] = 0; - ((u64*)pCache[index].data[way][3].b8._8)[0] = 0; - ((u64*)pCache[index].data[way][3].b8._8)[1] = 0; - break; - } - case 0x18: - { - u8 * out; - int index = (addr >> 6) & 0x3F; - u32 paddr[2]; - int way; - u32 taddr = memLUTW[addr >> 12]; - paddr[0] = memLUTW[pCache[index].tag[0] >> 12]; - paddr[1] = memLUTW[pCache[index].tag[1] >> 12]; - - if(paddr[0] == taddr && (pCache[index].tag[0] & 0x20)) - { - way = 0; - } - else if(paddr[1] == taddr && (pCache[index].tag[1] & 0x20)) - { - way = 1; - } - else - { - return; - } - - CACHE_LOG("CACHE DHWBIN addr %x, index %d, way %d, Flags %x\n",addr,index,way,pCache[index].tag[way] & 0x78); - - if(pCache[index].tag[way] & 0x60) // Valid Dirty - { - char * t = (char *)(taddr);//paddr[way]); - out = (u8*)(t + (addr & 0xFC0)); - ((u64*)out)[0] = ((u64*)pCache[index].data[way][0].b8._8)[0]; - ((u64*)out)[1] = ((u64*)pCache[index].data[way][0].b8._8)[1]; - ((u64*)out)[2] = ((u64*)pCache[index].data[way][1].b8._8)[0]; - ((u64*)out)[3] = ((u64*)pCache[index].data[way][1].b8._8)[1]; - ((u64*)out)[4] = ((u64*)pCache[index].data[way][2].b8._8)[0]; - ((u64*)out)[5] = ((u64*)pCache[index].data[way][2].b8._8)[1]; - ((u64*)out)[6] = ((u64*)pCache[index].data[way][3].b8._8)[0]; - ((u64*)out)[7] = ((u64*)pCache[index].data[way][3].b8._8)[1]; - } - - pCache[index].tag[way] &= ~(0x6F); - ((u64*)pCache[index].data[way][0].b8._8)[0] = 0; - ((u64*)pCache[index].data[way][0].b8._8)[1] = 0; - ((u64*)pCache[index].data[way][1].b8._8)[0] = 0; - ((u64*)pCache[index].data[way][1].b8._8)[1] = 0; - ((u64*)pCache[index].data[way][2].b8._8)[0] = 0; - ((u64*)pCache[index].data[way][2].b8._8)[1] = 0; - ((u64*)pCache[index].data[way][3].b8._8)[0] = 0; - ((u64*)pCache[index].data[way][3].b8._8)[1] = 0; - - break; - } - case 0x1c: - { - u8 * out; - int index = (addr >> 6) & 0x3F; - u32 paddr[2]; - int way; - u32 taddr = memLUTW[addr >> 12]; - paddr[0] = memLUTW[pCache[index].tag[0] >> 12]; - paddr[1] = memLUTW[pCache[index].tag[1] >> 12]; - - if(paddr[0] == taddr && (pCache[index].tag[0] & 0x20)) - { - way = 0; - } - else if(paddr[1] == taddr && (pCache[index].tag[1] & 0x20)) - { - way = 1; - } - else - { - return; - } - CACHE_LOG("CACHE DHWOIN addr %x, index %d, way %d, Flags %x\n",addr,index,way,pCache[index].tag[way] & 0x78); - - if(pCache[index].tag[way] & 0x60) // Valid Dirty - { - char * t = (char *)(taddr); - out = (u8*)(t + (addr & 0xFC0)); - ((u64*)out)[0] = ((u64*)pCache[index].data[way][0].b8._8)[0]; - ((u64*)out)[1] = ((u64*)pCache[index].data[way][0].b8._8)[1]; - ((u64*)out)[2] = ((u64*)pCache[index].data[way][1].b8._8)[0]; - ((u64*)out)[3] = ((u64*)pCache[index].data[way][1].b8._8)[1]; - ((u64*)out)[4] = ((u64*)pCache[index].data[way][2].b8._8)[0]; - ((u64*)out)[5] = ((u64*)pCache[index].data[way][2].b8._8)[1]; - ((u64*)out)[6] = ((u64*)pCache[index].data[way][3].b8._8)[0]; - ((u64*)out)[7] = ((u64*)pCache[index].data[way][3].b8._8)[1]; - } - - pCache[index].tag[way] &= ~(0x40); - break; - } - case 0x16: - { - int index = (addr >> 6) & 0x3F; - int way = addr & 0x1; - - CACHE_LOG("CACHE DXIN addr %x, index %d, way %d, flag %x\n",addr,index,way,pCache[index].tag[way] & 0x78); - - pCache[index].tag[way] &= ~(0x6F); - - ((u64*)pCache[index].data[way][0].b8._8)[0] = 0; - ((u64*)pCache[index].data[way][0].b8._8)[1] = 0; - ((u64*)pCache[index].data[way][1].b8._8)[0] = 0; - ((u64*)pCache[index].data[way][1].b8._8)[1] = 0; - ((u64*)pCache[index].data[way][2].b8._8)[0] = 0; - ((u64*)pCache[index].data[way][2].b8._8)[1] = 0; - ((u64*)pCache[index].data[way][3].b8._8)[0] = 0; - ((u64*)pCache[index].data[way][3].b8._8)[1] = 0; - break; - } - case 0x11: - { - int index = (addr >> 6) & 0x3F; - int way = addr & 0x1; - u8 * out = pCache[index].data[way][(addr>>4) & 0x3].b8._8; - cpuRegs.CP0.r[28] = *(u32 *)(out+(addr&0xf)); - - CACHE_LOG("CACHE DXLDT addr %x, index %d, way %d, DATA %x\n",addr,index,way,cpuRegs.CP0.r[28]); - - break; - } - case 0x10: - { - int index = (addr >> 6) & 0x3F; - int way = addr & 0x1; - - cpuRegs.CP0.r[28] = 0; - cpuRegs.CP0.r[28] = pCache[index].tag[way]; - - CACHE_LOG("CACHE DXLTG addr %x, index %d, way %d, DATA %x\n",addr,index,way,cpuRegs.CP0.r[28]); - - break; - } - case 0x13: - { - int index = (addr >> 6) & 0x3F; - int way = addr & 0x1; - //u8 * out = pCache[index].data[way][(addr>>4) & 0x3].b8._8; - *(u32*)(&pCache[index].data[way][(addr>>4) & 0x3].b8._8[(addr&0xf)]) = cpuRegs.CP0.r[28]; - - CACHE_LOG("CACHE DXSDT addr %x, index %d, way %d, DATA %x\n",addr,index,way,cpuRegs.CP0.r[28]); - - break; - } - case 0x12: - { - int index = (addr >> 6) & 0x3F; - int way = addr & 0x1; - pCache[index].tag[way] = cpuRegs.CP0.r[28]; - - CACHE_LOG("CACHE DXSTG addr %x, index %d, way %d, DATA %x\n",addr,index,way,cpuRegs.CP0.r[28] & 0x6F); - - break; - } - case 0x14: - { - - u8 * out; - int index = (addr >> 6) & 0x3F; - int way = addr & 0x1; - - - CACHE_LOG("CACHE DXWBIN addr %x, index %d, way %d, Flags %x\n",addr,index,way,pCache[index].tag[way] & 0x78); - - if(pCache[index].tag[way] & 0x60) // Dirty - { - u32 paddr = memLUTW[pCache[index].tag[way] >> 12]; - char * t = (char *)(paddr); - out = (u8*)(t + (addr & 0xFC0)); - ((u64*)out)[0] = ((u64*)pCache[index].data[way][0].b8._8)[0]; - ((u64*)out)[1] = ((u64*)pCache[index].data[way][0].b8._8)[1]; - ((u64*)out)[2] = ((u64*)pCache[index].data[way][1].b8._8)[0]; - ((u64*)out)[3] = ((u64*)pCache[index].data[way][1].b8._8)[1]; - ((u64*)out)[4] = ((u64*)pCache[index].data[way][2].b8._8)[0]; - ((u64*)out)[5] = ((u64*)pCache[index].data[way][2].b8._8)[1]; - ((u64*)out)[6] = ((u64*)pCache[index].data[way][3].b8._8)[0]; - ((u64*)out)[7] = ((u64*)pCache[index].data[way][3].b8._8)[1]; - } - - pCache[index].tag[way] &= ~(0x6F); - ((u64*)pCache[index].data[way][0].b8._8)[0] = 0; - ((u64*)pCache[index].data[way][0].b8._8)[1] = 0; - ((u64*)pCache[index].data[way][1].b8._8)[0] = 0; - ((u64*)pCache[index].data[way][1].b8._8)[1] = 0; - ((u64*)pCache[index].data[way][2].b8._8)[0] = 0; - ((u64*)pCache[index].data[way][2].b8._8)[1] = 0; - ((u64*)pCache[index].data[way][3].b8._8)[0] = 0; - ((u64*)pCache[index].data[way][3].b8._8)[1] = 0; - break; - } - } -} -} // end namespace OpcodeImpl -#else - -namespace OpcodeImpl -{ - -void CACHE() { -} -} - -#endif - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "Cache.h" + +_cacheS pCache[64]; + +namespace R5900{ +namespace Interpreter +{ + +#ifdef PCSX2_CACHE_EMU_MEM +int getFreeCache(u32 mem, int mode, int * way) { + u8 * out; + u32 paddr; + u32 taddr[2]; + u8 * t; + int number; + int i = (mem >> 6) & 0x3F; + + paddr = memLUTR[mem >> 12]; + taddr[0] = memLUTW[pCache[i].tag[0]>>12]; + taddr[1] = memLUTW[pCache[i].tag[1]>>12]; + + if (taddr[0] == paddr && (pCache[i].tag[0] & 0x20)) + { + *way = 0; + return i; + }else if(taddr[1] == paddr && (pCache[i].tag[1] & 0x20)) + { + *way = 1; + return i; + } + + number = ((pCache[i].tag[0]>>4) & 1) ^ ((pCache[i].tag[1]>>4) & 1); + + if(pCache[i].tag[number] & 0x60) // Valid Dirty + { + t = (u8*)(taddr[number]); + out = (u8*)(t + (mem & 0xFC0)); + ((u64*)out)[0] = ((u64*)pCache[i].data[number][0].b8._8)[0]; + ((u64*)out)[1] = ((u64*)pCache[i].data[number][0].b8._8)[1]; + ((u64*)out)[2] = ((u64*)pCache[i].data[number][1].b8._8)[0]; + ((u64*)out)[3] = ((u64*)pCache[i].data[number][1].b8._8)[1]; + ((u64*)out)[4] = ((u64*)pCache[i].data[number][2].b8._8)[0]; + ((u64*)out)[5] = ((u64*)pCache[i].data[number][2].b8._8)[1]; + ((u64*)out)[6] = ((u64*)pCache[i].data[number][3].b8._8)[0]; + ((u64*)out)[7] = ((u64*)pCache[i].data[number][3].b8._8)[1]; + } + + + + if(mode == 1) + { + pCache[i].tag[number] |= 0x40; // Set Dirty Bit if mode == write + } + + pCache[i].tag[number] &= ~(0xFFFFF000); + pCache[i].tag[number] |= ((mem>>12) & 0xFFFFF) << 12; + + + t = (u8 *)paddr; + out= (u8*)(t + (mem & 0xFC0)); + ((u64*)pCache[i].data[number][0].b8._8)[0] = ((u64*)out)[0]; + ((u64*)pCache[i].data[number][0].b8._8)[1] = ((u64*)out)[1]; + ((u64*)pCache[i].data[number][1].b8._8)[0] = ((u64*)out)[2]; + ((u64*)pCache[i].data[number][1].b8._8)[1] = ((u64*)out)[3]; + ((u64*)pCache[i].data[number][2].b8._8)[0] = ((u64*)out)[4]; + ((u64*)pCache[i].data[number][2].b8._8)[1] = ((u64*)out)[5]; + ((u64*)pCache[i].data[number][3].b8._8)[0] = ((u64*)out)[6]; + ((u64*)pCache[i].data[number][3].b8._8)[1] = ((u64*)out)[7]; + + if(pCache[i].tag[number] & 0x10) pCache[i].tag[number] &= ~(0x10); + else pCache[i].tag[number] |= 0x10; + + pCache[i].tag[number] |= 0x20; + *way = number; + return i; +} + +void writeCache8(u32 mem, u8 value) { + int i, number; + + i = getFreeCache(mem,1,&number); +// CACHE_LOG("writeCache8 %8.8x adding to %d, way %d, value %x\n", mem, i,number,value); + + pCache[i].data[number][(mem>>4) & 0x3].b8._8[(mem&0xf)] = value; +} + +void writeCache16(u32 mem, u16 value) { + int i, number; + + i = getFreeCache(mem,1,&number); +// CACHE_LOG("writeCache16 %8.8x adding to %d, way %d, value %x\n", mem, i,number,value); + + *(u16*)(&pCache[i].data[number][(mem>>4) & 0x3].b8._8[(mem&0xf)]) = value; +} + +void writeCache32(u32 mem, u32 value) { + int i, number; + + i = getFreeCache(mem,1,&number); +// CACHE_LOG("writeCache32 %8.8x adding to %d, way %d, value %x\n", mem, i,number,value); + *(u32*)(&pCache[i].data[number][(mem>>4) & 0x3].b8._8[(mem&0xf)]) = value; +} + +void writeCache64(u32 mem, u64 value) { + int i, number; + + i = getFreeCache(mem,1,&number); +// CACHE_LOG("writeCache64 %8.8x adding to %d, way %d, value %x\n", mem, i,number,value); + *(u64*)(&pCache[i].data[number][(mem>>4) & 0x3].b8._8[(mem&0xf)]) = value; +} + +void writeCache128(u32 mem, u64 *value) { + int i, number; + + i = getFreeCache(mem,1,&number); +// CACHE_LOG("writeCache128 %8.8x adding to %d\n", mem, i); + ((u64*)pCache[i].data[number][(mem>>4) & 0x3].b8._8)[0] = value[0]; + ((u64*)pCache[i].data[number][(mem>>4) & 0x3].b8._8)[1] = value[1]; +} + +u8 *readCache(u32 mem) { + int i, number; + + i = getFreeCache(mem,0,&number); +// CACHE_LOG("readCache %8.8x from %d, way %d\n", mem, i,number); + + return pCache[i].data[number][(mem>>4) & 0x3].b8._8; +} + +namespace OpcodeImpl +{ + +extern int Dcache; +void CACHE() { + u32 addr; + //if(Dcache == 0) return; + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + switch (_Rt_) { + case 0x1a: + { + int index = (addr >> 6) & 0x3F; + u32 paddr[2]; + int way; + u32 taddr = memLUTR[addr >> 12]; + paddr[0] = memLUTW[pCache[index].tag[0] >> 12]; + paddr[1] = memLUTW[pCache[index].tag[1] >> 12]; + + if(paddr[0] == taddr && (pCache[index].tag[0] & 0x20)) + { + way = 0; + } + else if(paddr[1] == taddr && (pCache[index].tag[1] & 0x20)) + { + way = 1; + } + else + { + return; + } + + CACHE_LOG("CACHE DHIN addr %x, index %d, way %d, Flags %x\n",addr,index,way,pCache[index].tag[way] & 0x78); + + pCache[index].tag[way] &= ~(0x6F); + ((u64*)pCache[index].data[way][0].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][0].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][1].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][1].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][2].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][2].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][3].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][3].b8._8)[1] = 0; + break; + } + case 0x18: + { + u8 * out; + int index = (addr >> 6) & 0x3F; + u32 paddr[2]; + int way; + u32 taddr = memLUTW[addr >> 12]; + paddr[0] = memLUTW[pCache[index].tag[0] >> 12]; + paddr[1] = memLUTW[pCache[index].tag[1] >> 12]; + + if(paddr[0] == taddr && (pCache[index].tag[0] & 0x20)) + { + way = 0; + } + else if(paddr[1] == taddr && (pCache[index].tag[1] & 0x20)) + { + way = 1; + } + else + { + return; + } + + CACHE_LOG("CACHE DHWBIN addr %x, index %d, way %d, Flags %x\n",addr,index,way,pCache[index].tag[way] & 0x78); + + if(pCache[index].tag[way] & 0x60) // Valid Dirty + { + char * t = (char *)(taddr);//paddr[way]); + out = (u8*)(t + (addr & 0xFC0)); + ((u64*)out)[0] = ((u64*)pCache[index].data[way][0].b8._8)[0]; + ((u64*)out)[1] = ((u64*)pCache[index].data[way][0].b8._8)[1]; + ((u64*)out)[2] = ((u64*)pCache[index].data[way][1].b8._8)[0]; + ((u64*)out)[3] = ((u64*)pCache[index].data[way][1].b8._8)[1]; + ((u64*)out)[4] = ((u64*)pCache[index].data[way][2].b8._8)[0]; + ((u64*)out)[5] = ((u64*)pCache[index].data[way][2].b8._8)[1]; + ((u64*)out)[6] = ((u64*)pCache[index].data[way][3].b8._8)[0]; + ((u64*)out)[7] = ((u64*)pCache[index].data[way][3].b8._8)[1]; + } + + pCache[index].tag[way] &= ~(0x6F); + ((u64*)pCache[index].data[way][0].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][0].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][1].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][1].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][2].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][2].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][3].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][3].b8._8)[1] = 0; + + break; + } + case 0x1c: + { + u8 * out; + int index = (addr >> 6) & 0x3F; + u32 paddr[2]; + int way; + u32 taddr = memLUTW[addr >> 12]; + paddr[0] = memLUTW[pCache[index].tag[0] >> 12]; + paddr[1] = memLUTW[pCache[index].tag[1] >> 12]; + + if(paddr[0] == taddr && (pCache[index].tag[0] & 0x20)) + { + way = 0; + } + else if(paddr[1] == taddr && (pCache[index].tag[1] & 0x20)) + { + way = 1; + } + else + { + return; + } + CACHE_LOG("CACHE DHWOIN addr %x, index %d, way %d, Flags %x\n",addr,index,way,pCache[index].tag[way] & 0x78); + + if(pCache[index].tag[way] & 0x60) // Valid Dirty + { + char * t = (char *)(taddr); + out = (u8*)(t + (addr & 0xFC0)); + ((u64*)out)[0] = ((u64*)pCache[index].data[way][0].b8._8)[0]; + ((u64*)out)[1] = ((u64*)pCache[index].data[way][0].b8._8)[1]; + ((u64*)out)[2] = ((u64*)pCache[index].data[way][1].b8._8)[0]; + ((u64*)out)[3] = ((u64*)pCache[index].data[way][1].b8._8)[1]; + ((u64*)out)[4] = ((u64*)pCache[index].data[way][2].b8._8)[0]; + ((u64*)out)[5] = ((u64*)pCache[index].data[way][2].b8._8)[1]; + ((u64*)out)[6] = ((u64*)pCache[index].data[way][3].b8._8)[0]; + ((u64*)out)[7] = ((u64*)pCache[index].data[way][3].b8._8)[1]; + } + + pCache[index].tag[way] &= ~(0x40); + break; + } + case 0x16: + { + int index = (addr >> 6) & 0x3F; + int way = addr & 0x1; + + CACHE_LOG("CACHE DXIN addr %x, index %d, way %d, flag %x\n",addr,index,way,pCache[index].tag[way] & 0x78); + + pCache[index].tag[way] &= ~(0x6F); + + ((u64*)pCache[index].data[way][0].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][0].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][1].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][1].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][2].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][2].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][3].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][3].b8._8)[1] = 0; + break; + } + case 0x11: + { + int index = (addr >> 6) & 0x3F; + int way = addr & 0x1; + u8 * out = pCache[index].data[way][(addr>>4) & 0x3].b8._8; + cpuRegs.CP0.r[28] = *(u32 *)(out+(addr&0xf)); + + CACHE_LOG("CACHE DXLDT addr %x, index %d, way %d, DATA %x\n",addr,index,way,cpuRegs.CP0.r[28]); + + break; + } + case 0x10: + { + int index = (addr >> 6) & 0x3F; + int way = addr & 0x1; + + cpuRegs.CP0.r[28] = 0; + cpuRegs.CP0.r[28] = pCache[index].tag[way]; + + CACHE_LOG("CACHE DXLTG addr %x, index %d, way %d, DATA %x\n",addr,index,way,cpuRegs.CP0.r[28]); + + break; + } + case 0x13: + { + int index = (addr >> 6) & 0x3F; + int way = addr & 0x1; + //u8 * out = pCache[index].data[way][(addr>>4) & 0x3].b8._8; + *(u32*)(&pCache[index].data[way][(addr>>4) & 0x3].b8._8[(addr&0xf)]) = cpuRegs.CP0.r[28]; + + CACHE_LOG("CACHE DXSDT addr %x, index %d, way %d, DATA %x\n",addr,index,way,cpuRegs.CP0.r[28]); + + break; + } + case 0x12: + { + int index = (addr >> 6) & 0x3F; + int way = addr & 0x1; + pCache[index].tag[way] = cpuRegs.CP0.r[28]; + + CACHE_LOG("CACHE DXSTG addr %x, index %d, way %d, DATA %x\n",addr,index,way,cpuRegs.CP0.r[28] & 0x6F); + + break; + } + case 0x14: + { + + u8 * out; + int index = (addr >> 6) & 0x3F; + int way = addr & 0x1; + + + CACHE_LOG("CACHE DXWBIN addr %x, index %d, way %d, Flags %x\n",addr,index,way,pCache[index].tag[way] & 0x78); + + if(pCache[index].tag[way] & 0x60) // Dirty + { + u32 paddr = memLUTW[pCache[index].tag[way] >> 12]; + char * t = (char *)(paddr); + out = (u8*)(t + (addr & 0xFC0)); + ((u64*)out)[0] = ((u64*)pCache[index].data[way][0].b8._8)[0]; + ((u64*)out)[1] = ((u64*)pCache[index].data[way][0].b8._8)[1]; + ((u64*)out)[2] = ((u64*)pCache[index].data[way][1].b8._8)[0]; + ((u64*)out)[3] = ((u64*)pCache[index].data[way][1].b8._8)[1]; + ((u64*)out)[4] = ((u64*)pCache[index].data[way][2].b8._8)[0]; + ((u64*)out)[5] = ((u64*)pCache[index].data[way][2].b8._8)[1]; + ((u64*)out)[6] = ((u64*)pCache[index].data[way][3].b8._8)[0]; + ((u64*)out)[7] = ((u64*)pCache[index].data[way][3].b8._8)[1]; + } + + pCache[index].tag[way] &= ~(0x6F); + ((u64*)pCache[index].data[way][0].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][0].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][1].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][1].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][2].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][2].b8._8)[1] = 0; + ((u64*)pCache[index].data[way][3].b8._8)[0] = 0; + ((u64*)pCache[index].data[way][3].b8._8)[1] = 0; + break; + } + } +} +} // end namespace OpcodeImpl +#else + +namespace OpcodeImpl +{ + +void CACHE() { +} +} + +#endif + }} \ No newline at end of file diff --git a/pcsx2/Cache.h b/pcsx2/Cache.h index 1a5ebf80f6..62d513430a 100644 --- a/pcsx2/Cache.h +++ b/pcsx2/Cache.h @@ -1,48 +1,48 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __CACHE_H__ -#define __CACHE_H__ - -#include "Common.h" - -struct _u8bit_128 { - u8 _8[16]; - -}; - -struct u8bit_128 { - _u8bit_128 b8; - -}; - -struct _cacheS { - u32 tag[2]; - u8bit_128 data[2][4]; -}; - -extern _cacheS pCache[64]; - -void writeCache8(u32 mem, u8 value); -void writeCache16(u32 mem, u16 value); -void writeCache32(u32 mem, u32 value); -void writeCache64(u32 mem, u64 value); -void writeCache128(u32 mem, u64 *value); -u8 *readCache(u32 mem); - -#endif /* __CACHE_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __CACHE_H__ +#define __CACHE_H__ + +#include "Common.h" + +struct _u8bit_128 { + u8 _8[16]; + +}; + +struct u8bit_128 { + _u8bit_128 b8; + +}; + +struct _cacheS { + u32 tag[2]; + u8bit_128 data[2][4]; +}; + +extern _cacheS pCache[64]; + +void writeCache8(u32 mem, u8 value); +void writeCache16(u32 mem, u16 value); +void writeCache32(u32 mem, u32 value); +void writeCache64(u32 mem, u64 value); +void writeCache128(u32 mem, u64 *value); +u8 *readCache(u32 mem); + +#endif /* __CACHE_H__ */ diff --git a/pcsx2/CdRom.cpp b/pcsx2/CdRom.cpp index 44465d7226..583cb15e1d 100644 --- a/pcsx2/CdRom.cpp +++ b/pcsx2/CdRom.cpp @@ -1,959 +1,959 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "PsxCommon.h" - -//THIS ALL IS FOR THE CDROM REGISTERS HANDLING - -#define CdlSync 0 -#define CdlNop 1 -#define CdlSetloc 2 -#define CdlPlay 3 -#define CdlForward 4 -#define CdlBackward 5 -#define CdlReadN 6 -#define CdlStandby 7 -#define CdlStop 8 -#define CdlPause 9 -#define CdlInit 10 -#define CdlMute 11 -#define CdlDemute 12 -#define CdlSetfilter 13 -#define CdlSetmode 14 -#define CdlGetmode 15 -#define CdlGetlocL 16 -#define CdlGetlocP 17 -#define Cdl18 18 -#define CdlGetTN 19 -#define CdlGetTD 20 -#define CdlSeekL 21 -#define CdlSeekP 22 -#define CdlTest 25 -#define CdlID 26 -#define CdlReadS 27 -#define CdlReset 28 -#define CdlReadToc 30 - -#define AUTOPAUSE 249 -#define READ_ACK 250 -#define READ 251 -#define REPPLAY_ACK 252 -#define REPPLAY 253 -#define ASYNC 254 -/* don't set 255, it's reserved */ - -const char *CmdName[0x100]= { - "CdlSync", "CdlNop", "CdlSetloc", "CdlPlay", - "CdlForward", "CdlBackward", "CdlReadN", "CdlStandby", - "CdlStop", "CdlPause", "CdlInit", "CdlMute", - "CdlDemute", "CdlSetfilter", "CdlSetmode", "CdlGetmode", - "CdlGetlocL", "CdlGetlocP", "Cdl18", "CdlGetTN", - "CdlGetTD", "CdlSeekL", "CdlSeekP", NULL, - NULL, "CdlTest", "CdlID", "CdlReadS", - "CdlReset", NULL, "CDlReadToc", NULL -}; - -cdrStruct cdr; -long LoadCdBios; -int cdOpenCase; - -u8 Test04[] = { 0 }; -u8 Test05[] = { 0 }; -u8 Test20[] = { 0x98, 0x06, 0x10, 0xC3 }; -u8 Test22[] = { 0x66, 0x6F, 0x72, 0x20, 0x45, 0x75, 0x72, 0x6F }; -u8 Test23[] = { 0x43, 0x58, 0x44, 0x32, 0x39 ,0x34, 0x30, 0x51 }; - -// 1x = 75 sectors per second -// PSXCLK = 1 sec in the ps -// so (PSXCLK / 75) / BIAS = cdr read time (linuzappz) -//#define cdReadTime ((PSXCLK / 75) / BIAS) -unsigned long cdReadTime;// = ((PSXCLK / 75) / BIAS); - -#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ -#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ - -#define CDR_INT(eCycle) PSX_INT(IopEvt_Cdrom, eCycle) -#define CDREAD_INT(eCycle) PSX_INT(IopEvt_CdromRead, eCycle) - -static __forceinline void StartReading(unsigned long type) { - cdr.Reading = type; - cdr.FirstSector = 1; - cdr.Readed = 0xff; - AddIrqQueue(READ_ACK, 0x800); -} - -static __forceinline void StopReading() { - if (cdr.Reading) { - cdr.Reading = 0; - psxRegs.interrupt &= ~(1<(cdr.Transfer); - cdr.Stat = DiskError; - cdr.Result[0]|= 0x01; - ReadTrack(); - CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime); - return; - } - memcpy_fast(cdr.Transfer, buf+12, 2340); - cdr.Stat = DataReady; - - CDR_LOG(" %x:%x:%x\n", cdr.Transfer[0], cdr.Transfer[1], cdr.Transfer[2]); - - cdr.SetSector[2]++; - - if (cdr.SetSector[2] == 75) { - cdr.SetSector[2] = 0; - cdr.SetSector[1]++; - if (cdr.SetSector[1] == 60) { - cdr.SetSector[1] = 0; - cdr.SetSector[0]++; - } - } - - cdr.Readed = 0; - - if ((cdr.Transfer[4+2] & 0x80) && (cdr.Mode & 0x2)) { // EOF - CDR_LOG("AutoPausing Read\n"); - AddIrqQueue(CdlPause, 0x800); - } - else { - ReadTrack(); - CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime); - } - - psxHu32(0x1070)|= 0x4; - return; -} - -/* -cdrRead0: - bit 0 - 0 REG1 command send / 1 REG1 data read - bit 1 - 0 data transfer finish / 1 data transfer ready/in progress - bit 2 - unknown - bit 3 - unknown - bit 4 - unknown - bit 5 - 1 result ready - bit 6 - 1 dma ready - bit 7 - 1 command being processed -*/ - -u8 cdrRead0(void) { - if (cdr.ResultReady) - cdr.Ctrl |= 0x20; - else - cdr.Ctrl &= ~0x20; - - if (cdr.OCUP) - cdr.Ctrl |= 0x40; - else - cdr.Ctrl &= ~0x40; - - // what means the 0x10 and the 0x08 bits? i only saw it used by the bios - cdr.Ctrl|=0x18; - - CDR_LOG("CD0 Read: %x\n", cdr.Ctrl); - return psxHu8(0x1800) = cdr.Ctrl; -} - -/* -cdrWrite0: - 0 - to send a command / 1 - to get the result -*/ - -void cdrWrite0(u8 rt) { - CDR_LOG("CD0 write: %x\n", rt); - - cdr.Ctrl = rt | (cdr.Ctrl & ~0x3); - - if (rt == 0) { - cdr.ParamP = 0; - cdr.ParamC = 0; - cdr.ResultReady = 0; - } -} - -u8 cdrRead1(void) { - if (cdr.ResultReady && cdr.Ctrl & 0x1) { - psxHu8(0x1801) = cdr.Result[cdr.ResultP++]; - if (cdr.ResultP == cdr.ResultC) cdr.ResultReady = 0; - } - else - psxHu8(0x1801) = 0; - - CDR_LOG("CD1 Read: %x\n", psxHu8(0x1801)); - return psxHu8(0x1801); -} - -void cdrWrite1(u8 rt) { - int i; - - CDR_LOG("CD1 write: %x (%s)\n", rt, CmdName[rt]); - cdr.Cmd = rt; - cdr.OCUP = 0; - -#ifdef CDRCMD_DEBUG - SysPrintf("CD1 write: %x (%s)", rt, CmdName[rt]); - if (cdr.ParamC) { - SysPrintf(" Param[%d] = {", cdr.ParamC); - for (i=0;i 1) cdr.CurTrack--; - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x800); - break; - - case CdlReadN: - cdr.Irq = 0; - StopReading(); - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - StartReading(1); - break; - - case CdlStandby: - StopCdda(); - StopReading(); - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x800); - break; - - case CdlStop: - StopCdda(); - StopReading(); - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x800); - break; - - case CdlPause: - StopCdda(); - StopReading(); - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x40000); - break; - - case CdlReset: - case CdlInit: - StopCdda(); - StopReading(); - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x800); - break; - - case CdlMute: - cdr.Muted = 0; - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x800); - break; - - case CdlDemute: - cdr.Muted = 1; - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x800); - break; - - case CdlSetfilter: - cdr.File = cdr.Param[0]; - cdr.Channel = cdr.Param[1]; - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x800); - break; - - case CdlSetmode: - CDR_LOG("Setmode %x\n", cdr.Param[0]); - - cdr.Mode = cdr.Param[0]; - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x800); - break; - - case CdlGetmode: - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x800); - break; - - case CdlGetlocL: - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x800); - break; - - case CdlGetlocP: - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x800); - break; - - case CdlGetTN: - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x800); - break; - - case CdlGetTD: - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x800); - break; - - case CdlSeekL: - ((unsigned long *)cdr.SetSectorSeek)[0] = ((unsigned long *)cdr.SetSector)[0]; - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x800); - break; - - case CdlSeekP: - ((unsigned long *)cdr.SetSectorSeek)[0] = ((unsigned long *)cdr.SetSector)[0]; - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x800); - break; - - case CdlTest: - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x800); - break; - - case CdlID: - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x800); - break; - - case CdlReadS: - cdr.Irq = 0; - StopReading(); - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - StartReading(2); - break; - - case CdlReadToc: - cdr.Ctrl|= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(cdr.Cmd, 0x800); - break; - - default: - CDR_LOG("Unknown Cmd: %x\n", cdr.Cmd); - return; - } - if (cdr.Stat != NoIntr) - iopIntcIrq( 2 ); -} - -u8 cdrRead2(void) { - u8 ret; - - if (cdr.Readed == 0) { - ret = 0; - } else { - ret = *cdr.pTransfer++; - } - - CDR_LOG("CD2 Read: %x\n", ret); - return ret; -} - -void cdrWrite2(u8 rt) { - CDR_LOG("CD2 write: %x\n", rt); - - if (cdr.Ctrl & 0x1) { - switch (rt) { - case 0x07: - cdr.ParamP = 0; - cdr.ParamC = 0; - cdr.ResultReady = 0; - cdr.Ctrl = 0; - break; - - default: - cdr.Reg2 = rt; - break; - } - } - else - { - if (!(cdr.Ctrl & 0x1) && cdr.ParamP < 8) { - cdr.Param[cdr.ParamP++] = rt; - cdr.ParamC++; - } - } -} - -u8 cdrRead3(void) { - if (cdr.Stat) { - if (cdr.Ctrl & 0x1) - psxHu8(0x1803) = cdr.Stat | 0xE0; - else - psxHu8(0x1803) = 0xff; - } else psxHu8(0x1803) = 0; - - CDR_LOG("CD3 Read: %x\n", psxHu8(0x1803)); - return psxHu8(0x1803); -} - -void cdrWrite3(u8 rt) { - CDR_LOG("CD3 write: %x\n", rt); - - if (rt == 0x07 && cdr.Ctrl & 0x1) { - cdr.Stat = 0; - - if (cdr.Irq == 0xff) { cdr.Irq = 0; return; } - if (cdr.Irq) { - CDR_INT(cdr.eCycle); - } - return; - } - - if (rt == 0x80 && !(cdr.Ctrl & 0x1) && cdr.Readed == 0) { - cdr.Readed = 1; - cdr.pTransfer = cdr.Transfer; - - switch (cdr.Mode&0x30) { - case 0x10: - case 0x00: cdr.pTransfer+=12; break; - default: break; - } - } -} - -void psxDma3(u32 madr, u32 bcr, u32 chcr) { - u32 cdsize; - - CDR_LOG("*** DMA 3 *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); - - switch (chcr) { - case 0x11000000: - case 0x11400100: - if (cdr.Readed == 0) { - CDR_LOG("*** DMA 3 *** NOT READY\n"); - return; - } - - cdsize = (bcr & 0xffff) * 4; - memcpy_fast((u8*)PSXM(madr), cdr.pTransfer, cdsize); - psxCpu->Clear(madr, cdsize/4); - cdr.pTransfer+=cdsize; - - break; - case 0x41000200: - //SysPrintf("unhandled cdrom dma3: madr: %x, bcr: %x, chcr %x\n", madr, bcr, chcr); - return; - - default: - CDR_LOG("Unknown cddma %lx\n", chcr); - break; - } - HW_DMA3_CHCR &= ~0x01000000; - psxDmaInterrupt(3); -} - -void cdrReset() { - memzero_obj(cdr); - cdr.CurTrack=1; - cdr.File=1; cdr.Channel=1; - cdReadTime = (PSXCLK / 1757) * BIAS; -} - -void SaveState::cdrFreeze() { - Freeze(cdr); - - // Alrighty! This code used to, for some reason, recalculate the pTransfer value - // even though it's being saved as part of the cdr struct. Probably a backwards - // compat fix with an earlier save version. - - int tmp; // = (int)(cdr.pTransfer - cdr.Transfer); - Freeze(tmp); - //if (Mode == 0) cdr.pTransfer = cdr.Transfer + tmp; -} - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "PsxCommon.h" + +//THIS ALL IS FOR THE CDROM REGISTERS HANDLING + +#define CdlSync 0 +#define CdlNop 1 +#define CdlSetloc 2 +#define CdlPlay 3 +#define CdlForward 4 +#define CdlBackward 5 +#define CdlReadN 6 +#define CdlStandby 7 +#define CdlStop 8 +#define CdlPause 9 +#define CdlInit 10 +#define CdlMute 11 +#define CdlDemute 12 +#define CdlSetfilter 13 +#define CdlSetmode 14 +#define CdlGetmode 15 +#define CdlGetlocL 16 +#define CdlGetlocP 17 +#define Cdl18 18 +#define CdlGetTN 19 +#define CdlGetTD 20 +#define CdlSeekL 21 +#define CdlSeekP 22 +#define CdlTest 25 +#define CdlID 26 +#define CdlReadS 27 +#define CdlReset 28 +#define CdlReadToc 30 + +#define AUTOPAUSE 249 +#define READ_ACK 250 +#define READ 251 +#define REPPLAY_ACK 252 +#define REPPLAY 253 +#define ASYNC 254 +/* don't set 255, it's reserved */ + +const char *CmdName[0x100]= { + "CdlSync", "CdlNop", "CdlSetloc", "CdlPlay", + "CdlForward", "CdlBackward", "CdlReadN", "CdlStandby", + "CdlStop", "CdlPause", "CdlInit", "CdlMute", + "CdlDemute", "CdlSetfilter", "CdlSetmode", "CdlGetmode", + "CdlGetlocL", "CdlGetlocP", "Cdl18", "CdlGetTN", + "CdlGetTD", "CdlSeekL", "CdlSeekP", NULL, + NULL, "CdlTest", "CdlID", "CdlReadS", + "CdlReset", NULL, "CDlReadToc", NULL +}; + +cdrStruct cdr; +long LoadCdBios; +int cdOpenCase; + +u8 Test04[] = { 0 }; +u8 Test05[] = { 0 }; +u8 Test20[] = { 0x98, 0x06, 0x10, 0xC3 }; +u8 Test22[] = { 0x66, 0x6F, 0x72, 0x20, 0x45, 0x75, 0x72, 0x6F }; +u8 Test23[] = { 0x43, 0x58, 0x44, 0x32, 0x39 ,0x34, 0x30, 0x51 }; + +// 1x = 75 sectors per second +// PSXCLK = 1 sec in the ps +// so (PSXCLK / 75) / BIAS = cdr read time (linuzappz) +//#define cdReadTime ((PSXCLK / 75) / BIAS) +unsigned long cdReadTime;// = ((PSXCLK / 75) / BIAS); + +#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ +#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ + +#define CDR_INT(eCycle) PSX_INT(IopEvt_Cdrom, eCycle) +#define CDREAD_INT(eCycle) PSX_INT(IopEvt_CdromRead, eCycle) + +static __forceinline void StartReading(unsigned long type) { + cdr.Reading = type; + cdr.FirstSector = 1; + cdr.Readed = 0xff; + AddIrqQueue(READ_ACK, 0x800); +} + +static __forceinline void StopReading() { + if (cdr.Reading) { + cdr.Reading = 0; + psxRegs.interrupt &= ~(1<(cdr.Transfer); + cdr.Stat = DiskError; + cdr.Result[0]|= 0x01; + ReadTrack(); + CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime); + return; + } + memcpy_fast(cdr.Transfer, buf+12, 2340); + cdr.Stat = DataReady; + + CDR_LOG(" %x:%x:%x\n", cdr.Transfer[0], cdr.Transfer[1], cdr.Transfer[2]); + + cdr.SetSector[2]++; + + if (cdr.SetSector[2] == 75) { + cdr.SetSector[2] = 0; + cdr.SetSector[1]++; + if (cdr.SetSector[1] == 60) { + cdr.SetSector[1] = 0; + cdr.SetSector[0]++; + } + } + + cdr.Readed = 0; + + if ((cdr.Transfer[4+2] & 0x80) && (cdr.Mode & 0x2)) { // EOF + CDR_LOG("AutoPausing Read\n"); + AddIrqQueue(CdlPause, 0x800); + } + else { + ReadTrack(); + CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime); + } + + psxHu32(0x1070)|= 0x4; + return; +} + +/* +cdrRead0: + bit 0 - 0 REG1 command send / 1 REG1 data read + bit 1 - 0 data transfer finish / 1 data transfer ready/in progress + bit 2 - unknown + bit 3 - unknown + bit 4 - unknown + bit 5 - 1 result ready + bit 6 - 1 dma ready + bit 7 - 1 command being processed +*/ + +u8 cdrRead0(void) { + if (cdr.ResultReady) + cdr.Ctrl |= 0x20; + else + cdr.Ctrl &= ~0x20; + + if (cdr.OCUP) + cdr.Ctrl |= 0x40; + else + cdr.Ctrl &= ~0x40; + + // what means the 0x10 and the 0x08 bits? i only saw it used by the bios + cdr.Ctrl|=0x18; + + CDR_LOG("CD0 Read: %x\n", cdr.Ctrl); + return psxHu8(0x1800) = cdr.Ctrl; +} + +/* +cdrWrite0: + 0 - to send a command / 1 - to get the result +*/ + +void cdrWrite0(u8 rt) { + CDR_LOG("CD0 write: %x\n", rt); + + cdr.Ctrl = rt | (cdr.Ctrl & ~0x3); + + if (rt == 0) { + cdr.ParamP = 0; + cdr.ParamC = 0; + cdr.ResultReady = 0; + } +} + +u8 cdrRead1(void) { + if (cdr.ResultReady && cdr.Ctrl & 0x1) { + psxHu8(0x1801) = cdr.Result[cdr.ResultP++]; + if (cdr.ResultP == cdr.ResultC) cdr.ResultReady = 0; + } + else + psxHu8(0x1801) = 0; + + CDR_LOG("CD1 Read: %x\n", psxHu8(0x1801)); + return psxHu8(0x1801); +} + +void cdrWrite1(u8 rt) { + int i; + + CDR_LOG("CD1 write: %x (%s)\n", rt, CmdName[rt]); + cdr.Cmd = rt; + cdr.OCUP = 0; + +#ifdef CDRCMD_DEBUG + SysPrintf("CD1 write: %x (%s)", rt, CmdName[rt]); + if (cdr.ParamC) { + SysPrintf(" Param[%d] = {", cdr.ParamC); + for (i=0;i 1) cdr.CurTrack--; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlReadN: + cdr.Irq = 0; + StopReading(); + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + StartReading(1); + break; + + case CdlStandby: + StopCdda(); + StopReading(); + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlStop: + StopCdda(); + StopReading(); + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlPause: + StopCdda(); + StopReading(); + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x40000); + break; + + case CdlReset: + case CdlInit: + StopCdda(); + StopReading(); + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlMute: + cdr.Muted = 0; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlDemute: + cdr.Muted = 1; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlSetfilter: + cdr.File = cdr.Param[0]; + cdr.Channel = cdr.Param[1]; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlSetmode: + CDR_LOG("Setmode %x\n", cdr.Param[0]); + + cdr.Mode = cdr.Param[0]; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlGetmode: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlGetlocL: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlGetlocP: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlGetTN: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlGetTD: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlSeekL: + ((unsigned long *)cdr.SetSectorSeek)[0] = ((unsigned long *)cdr.SetSector)[0]; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlSeekP: + ((unsigned long *)cdr.SetSectorSeek)[0] = ((unsigned long *)cdr.SetSector)[0]; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlTest: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlID: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlReadS: + cdr.Irq = 0; + StopReading(); + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + StartReading(2); + break; + + case CdlReadToc: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + default: + CDR_LOG("Unknown Cmd: %x\n", cdr.Cmd); + return; + } + if (cdr.Stat != NoIntr) + iopIntcIrq( 2 ); +} + +u8 cdrRead2(void) { + u8 ret; + + if (cdr.Readed == 0) { + ret = 0; + } else { + ret = *cdr.pTransfer++; + } + + CDR_LOG("CD2 Read: %x\n", ret); + return ret; +} + +void cdrWrite2(u8 rt) { + CDR_LOG("CD2 write: %x\n", rt); + + if (cdr.Ctrl & 0x1) { + switch (rt) { + case 0x07: + cdr.ParamP = 0; + cdr.ParamC = 0; + cdr.ResultReady = 0; + cdr.Ctrl = 0; + break; + + default: + cdr.Reg2 = rt; + break; + } + } + else + { + if (!(cdr.Ctrl & 0x1) && cdr.ParamP < 8) { + cdr.Param[cdr.ParamP++] = rt; + cdr.ParamC++; + } + } +} + +u8 cdrRead3(void) { + if (cdr.Stat) { + if (cdr.Ctrl & 0x1) + psxHu8(0x1803) = cdr.Stat | 0xE0; + else + psxHu8(0x1803) = 0xff; + } else psxHu8(0x1803) = 0; + + CDR_LOG("CD3 Read: %x\n", psxHu8(0x1803)); + return psxHu8(0x1803); +} + +void cdrWrite3(u8 rt) { + CDR_LOG("CD3 write: %x\n", rt); + + if (rt == 0x07 && cdr.Ctrl & 0x1) { + cdr.Stat = 0; + + if (cdr.Irq == 0xff) { cdr.Irq = 0; return; } + if (cdr.Irq) { + CDR_INT(cdr.eCycle); + } + return; + } + + if (rt == 0x80 && !(cdr.Ctrl & 0x1) && cdr.Readed == 0) { + cdr.Readed = 1; + cdr.pTransfer = cdr.Transfer; + + switch (cdr.Mode&0x30) { + case 0x10: + case 0x00: cdr.pTransfer+=12; break; + default: break; + } + } +} + +void psxDma3(u32 madr, u32 bcr, u32 chcr) { + u32 cdsize; + + CDR_LOG("*** DMA 3 *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); + + switch (chcr) { + case 0x11000000: + case 0x11400100: + if (cdr.Readed == 0) { + CDR_LOG("*** DMA 3 *** NOT READY\n"); + return; + } + + cdsize = (bcr & 0xffff) * 4; + memcpy_fast((u8*)PSXM(madr), cdr.pTransfer, cdsize); + psxCpu->Clear(madr, cdsize/4); + cdr.pTransfer+=cdsize; + + break; + case 0x41000200: + //SysPrintf("unhandled cdrom dma3: madr: %x, bcr: %x, chcr %x\n", madr, bcr, chcr); + return; + + default: + CDR_LOG("Unknown cddma %lx\n", chcr); + break; + } + HW_DMA3_CHCR &= ~0x01000000; + psxDmaInterrupt(3); +} + +void cdrReset() { + memzero_obj(cdr); + cdr.CurTrack=1; + cdr.File=1; cdr.Channel=1; + cdReadTime = (PSXCLK / 1757) * BIAS; +} + +void SaveState::cdrFreeze() { + Freeze(cdr); + + // Alrighty! This code used to, for some reason, recalculate the pTransfer value + // even though it's being saved as part of the cdr struct. Probably a backwards + // compat fix with an earlier save version. + + int tmp; // = (int)(cdr.pTransfer - cdr.Transfer); + Freeze(tmp); + //if (Mode == 0) cdr.pTransfer = cdr.Transfer + tmp; +} + diff --git a/pcsx2/CdRom.h b/pcsx2/CdRom.h index d8bd02873f..ebb4290c44 100644 --- a/pcsx2/CdRom.h +++ b/pcsx2/CdRom.h @@ -1,93 +1,93 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __CDROM_H__ -#define __CDROM_H__ - -#include "PsxCommon.h" -#include "Decode_XA.h" -#include "PS2Edefs.h" - -struct cdrStruct -{ - u8 OCUP; - u8 Reg1Mode; - u8 Reg2; - u8 CmdProcess; - u8 Ctrl; - u8 Stat; - - u8 StatP; - - u8 Transfer[2352]; - u8 *pTransfer; - - u8 Prev[4]; - u8 Param[8]; - u8 Result[8]; - - u8 ParamC; - u8 ParamP; - u8 ResultC; - u8 ResultP; - u8 ResultReady; - u8 Cmd; - u8 Readed; - unsigned long Reading; - - cdvdTN ResultTN; - u8 ResultTD[4]; - u8 SetSector[4]; - u8 SetSectorSeek[4]; - u8 Track; - int Play; - int CurTrack; - int Mode, File, Channel, Muted; - int Reset; - int RErr; - int FirstSector; - - xa_decode_t Xa; - - int Init; - - u8 Irq; - unsigned long eCycle; - - char Unused[4087]; -}; - -extern cdrStruct cdr; - -s32 MSFtoLSN(u8 *Time); -void LSNtoMSF(u8 *Time, s32 lsn); -void AddIrqQueue(u8 irq, unsigned long ecycle); - -void cdrReset(); -void cdrInterrupt(); -void cdrReadInterrupt(); -u8 cdrRead0(void); -u8 cdrRead1(void); -u8 cdrRead2(void); -u8 cdrRead3(void); -void cdrWrite0(u8 rt); -void cdrWrite1(u8 rt); -void cdrWrite2(u8 rt); -void cdrWrite3(u8 rt); - -#endif /* __CDROM_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __CDROM_H__ +#define __CDROM_H__ + +#include "PsxCommon.h" +#include "Decode_XA.h" +#include "PS2Edefs.h" + +struct cdrStruct +{ + u8 OCUP; + u8 Reg1Mode; + u8 Reg2; + u8 CmdProcess; + u8 Ctrl; + u8 Stat; + + u8 StatP; + + u8 Transfer[2352]; + u8 *pTransfer; + + u8 Prev[4]; + u8 Param[8]; + u8 Result[8]; + + u8 ParamC; + u8 ParamP; + u8 ResultC; + u8 ResultP; + u8 ResultReady; + u8 Cmd; + u8 Readed; + unsigned long Reading; + + cdvdTN ResultTN; + u8 ResultTD[4]; + u8 SetSector[4]; + u8 SetSectorSeek[4]; + u8 Track; + int Play; + int CurTrack; + int Mode, File, Channel, Muted; + int Reset; + int RErr; + int FirstSector; + + xa_decode_t Xa; + + int Init; + + u8 Irq; + unsigned long eCycle; + + char Unused[4087]; +}; + +extern cdrStruct cdr; + +s32 MSFtoLSN(u8 *Time); +void LSNtoMSF(u8 *Time, s32 lsn); +void AddIrqQueue(u8 irq, unsigned long ecycle); + +void cdrReset(); +void cdrInterrupt(); +void cdrReadInterrupt(); +u8 cdrRead0(void); +u8 cdrRead1(void); +u8 cdrRead2(void); +u8 cdrRead3(void); +void cdrWrite0(u8 rt); +void cdrWrite1(u8 rt); +void cdrWrite2(u8 rt); +void cdrWrite3(u8 rt); + +#endif /* __CDROM_H__ */ diff --git a/pcsx2/Common.h b/pcsx2/Common.h index 410ee9c15e..838ec24734 100644 --- a/pcsx2/Common.h +++ b/pcsx2/Common.h @@ -1,79 +1,79 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __COMMON_H__ -#define __COMMON_H__ - -#include "PS2Etypes.h" - -struct TESTRUNARGS -{ - u8 enabled; - u8 jpgcapture; - - int frame; // if < 0, frame is unlimited (run until crash). - int numimages; - int curimage; - u32 autopad; // mask for auto buttons - bool efile; - int snapdone; - - const char* ptitle; - const char* pimagename; - const char* plogname; - const char* pgsdll, *pcdvddll, *pspudll; - -}; - -extern TESTRUNARGS g_TestRun; - -#define BIAS 2 // Bus is half of the actual ps2 speed -//#define PS2CLK 36864000 /* 294.912 mhz */ -//#define PSXCLK 9216000 /* 36.864 Mhz */ -//#define PSXCLK 186864000 /* 36.864 Mhz */ -#define PS2CLK 294912000 //hz /* 294.912 mhz */ - - -/* Config.PsxType == 1: PAL: - VBlank interlaced 50.00 Hz - VBlank non-interlaced 49.76 Hz - HBlank 15.625 KHz - Config.PsxType == 0: NSTC - VBlank interlaced 59.94 Hz - VBlank non-interlaced 59.82 Hz - HBlank 15.73426573 KHz */ - -//Misc Clocks -#define PSXPIXEL ((int)(PSXCLK / 13500000)) -#define PSXSOUNDCLK ((int)(48000)) - -#include "Plugins.h" -#include "Misc.h" -#include "SaveState.h" -#include "DebugTools/Debug.h" -#include "R5900.h" -#include "Memory.h" -#include "Elfheader.h" -#include "Hw.h" -// Moving this before one of the other includes causes compilation issues. -//#include "Misc.h" -#include "Patch.h" - -#define PCSX2_VERSION "(beta)" - -#endif /* __COMMON_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __COMMON_H__ +#define __COMMON_H__ + +#include "PS2Etypes.h" + +struct TESTRUNARGS +{ + u8 enabled; + u8 jpgcapture; + + int frame; // if < 0, frame is unlimited (run until crash). + int numimages; + int curimage; + u32 autopad; // mask for auto buttons + bool efile; + int snapdone; + + const char* ptitle; + const char* pimagename; + const char* plogname; + const char* pgsdll, *pcdvddll, *pspudll; + +}; + +extern TESTRUNARGS g_TestRun; + +#define BIAS 2 // Bus is half of the actual ps2 speed +//#define PS2CLK 36864000 /* 294.912 mhz */ +//#define PSXCLK 9216000 /* 36.864 Mhz */ +//#define PSXCLK 186864000 /* 36.864 Mhz */ +#define PS2CLK 294912000 //hz /* 294.912 mhz */ + + +/* Config.PsxType == 1: PAL: + VBlank interlaced 50.00 Hz + VBlank non-interlaced 49.76 Hz + HBlank 15.625 KHz + Config.PsxType == 0: NSTC + VBlank interlaced 59.94 Hz + VBlank non-interlaced 59.82 Hz + HBlank 15.73426573 KHz */ + +//Misc Clocks +#define PSXPIXEL ((int)(PSXCLK / 13500000)) +#define PSXSOUNDCLK ((int)(48000)) + +#include "Plugins.h" +#include "Misc.h" +#include "SaveState.h" +#include "DebugTools/Debug.h" +#include "R5900.h" +#include "Memory.h" +#include "Elfheader.h" +#include "Hw.h" +// Moving this before one of the other includes causes compilation issues. +//#include "Misc.h" +#include "Patch.h" + +#define PCSX2_VERSION "(beta)" + +#endif /* __COMMON_H__ */ diff --git a/pcsx2/Console.cpp b/pcsx2/Console.cpp index a7f97121bb..156df72190 100644 --- a/pcsx2/Console.cpp +++ b/pcsx2/Console.cpp @@ -1,179 +1,179 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "System.h" -#include "DebugTools/Debug.h" - -using namespace std; - -const _VARG_PARAM va_arg_dummy = { 0 }; - -// Methods of the Console namespace not defined here are to be found in the platform -// dependent implementations in WinConsole.cpp and LnxConsole.cpp. - -namespace Console -{ - __forceinline void __fastcall _WriteLn( Colors color, const char* fmt, va_list args ) - { - SetColor( color ); - WriteLn( vfmt_string( fmt, args ).c_str() ); - ClearColor(); - } - - bool Write( const char* fmt, VARG_PARAM dummy, ... ) - { - varg_assert(); - - va_list list; - va_start(list,dummy); - WriteLn( vfmt_string( fmt, list ).c_str() ); - va_end(list); - - return false; - } - - bool Write( Colors color, const char* fmt ) - { - SetColor( color ); - Write( fmt ); - ClearColor(); - return false; - } - - bool Write( Colors color, const char* fmt, VARG_PARAM dummy, ... ) - { - varg_assert(); - - va_list list; - va_start(list,dummy); - Write( vfmt_string( fmt, list ).c_str() ); - va_end(list); - - return false; - } - - bool WriteLn( const char* fmt, VARG_PARAM dummy, ... ) - { - varg_assert(); - - va_list list; - va_start(list,dummy); - WriteLn( vfmt_string( fmt, list).c_str() ); - va_end(list); - - return false; - } - - // Writes an unformatted string of text to the console (fast!) - // A newline is automatically appended. - __forceinline bool __fastcall WriteLn( const char* fmt ) - { - Write( fmt ); - Newline(); - return false; - } - - // Writes an unformatted string of text to the console (fast!) - // A newline is automatically appended. - __forceinline bool __fastcall WriteLn( Colors color, const char* fmt ) - { - Write( color, fmt ); - Newline(); - return false; - } - - // Writes a line of colored text to the console, with automatic newline appendage. - bool WriteLn( Colors color, const char* fmt, VARG_PARAM dummy, ... ) - { - varg_assert(); - - va_list list; - va_start(list,dummy); - _WriteLn( Color_White, fmt, list ); - va_end(list); - return false; - } - - // Displays a message in the console with red emphasis. - // Newline is automatically appended. - bool Error( const char* fmt, VARG_PARAM dummy, ... ) - { - varg_assert(); - - va_list list; - va_start(list,dummy); - _WriteLn( Color_Red, fmt, list ); - va_end(list); - return false; - } - - // Displays a message in the console with yellow emphasis. - // Newline is automatically appended. - bool Notice( const char* fmt, VARG_PARAM dummy, ... ) - { - varg_assert(); - - va_list list; - - va_start(list,dummy); - _WriteLn( Color_Yellow, fmt, list ); - va_end(list); - return false; - } - - // Displays a message in the console with green emphasis. - // Newline is automatically appended. - bool Status( const char* fmt, VARG_PARAM dummy, ... ) - { - varg_assert(); - - va_list list; - va_start(list,dummy); - _WriteLn( Color_Green, fmt, list ); - va_end(list); - return false; - } - - // Displays a message in the console with red emphasis. - // Newline is automatically appended. - bool Error( const char* fmt ) - { - WriteLn( Color_Red, fmt ); - return false; - } - - // Displays a message in the console with yellow emphasis. - // Newline is automatically appended. - bool Notice( const char* fmt ) - { - WriteLn( Color_Yellow, fmt ); - return false; - } - - // Displays a message in the console with green emphasis. - // Newline is automatically appended. - bool Status( const char* fmt ) - { - WriteLn( Color_Green, fmt ); - return false; - } - -} - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "System.h" +#include "DebugTools/Debug.h" + +using namespace std; + +const _VARG_PARAM va_arg_dummy = { 0 }; + +// Methods of the Console namespace not defined here are to be found in the platform +// dependent implementations in WinConsole.cpp and LnxConsole.cpp. + +namespace Console +{ + __forceinline void __fastcall _WriteLn( Colors color, const char* fmt, va_list args ) + { + SetColor( color ); + WriteLn( vfmt_string( fmt, args ).c_str() ); + ClearColor(); + } + + bool Write( const char* fmt, VARG_PARAM dummy, ... ) + { + varg_assert(); + + va_list list; + va_start(list,dummy); + WriteLn( vfmt_string( fmt, list ).c_str() ); + va_end(list); + + return false; + } + + bool Write( Colors color, const char* fmt ) + { + SetColor( color ); + Write( fmt ); + ClearColor(); + return false; + } + + bool Write( Colors color, const char* fmt, VARG_PARAM dummy, ... ) + { + varg_assert(); + + va_list list; + va_start(list,dummy); + Write( vfmt_string( fmt, list ).c_str() ); + va_end(list); + + return false; + } + + bool WriteLn( const char* fmt, VARG_PARAM dummy, ... ) + { + varg_assert(); + + va_list list; + va_start(list,dummy); + WriteLn( vfmt_string( fmt, list).c_str() ); + va_end(list); + + return false; + } + + // Writes an unformatted string of text to the console (fast!) + // A newline is automatically appended. + __forceinline bool __fastcall WriteLn( const char* fmt ) + { + Write( fmt ); + Newline(); + return false; + } + + // Writes an unformatted string of text to the console (fast!) + // A newline is automatically appended. + __forceinline bool __fastcall WriteLn( Colors color, const char* fmt ) + { + Write( color, fmt ); + Newline(); + return false; + } + + // Writes a line of colored text to the console, with automatic newline appendage. + bool WriteLn( Colors color, const char* fmt, VARG_PARAM dummy, ... ) + { + varg_assert(); + + va_list list; + va_start(list,dummy); + _WriteLn( Color_White, fmt, list ); + va_end(list); + return false; + } + + // Displays a message in the console with red emphasis. + // Newline is automatically appended. + bool Error( const char* fmt, VARG_PARAM dummy, ... ) + { + varg_assert(); + + va_list list; + va_start(list,dummy); + _WriteLn( Color_Red, fmt, list ); + va_end(list); + return false; + } + + // Displays a message in the console with yellow emphasis. + // Newline is automatically appended. + bool Notice( const char* fmt, VARG_PARAM dummy, ... ) + { + varg_assert(); + + va_list list; + + va_start(list,dummy); + _WriteLn( Color_Yellow, fmt, list ); + va_end(list); + return false; + } + + // Displays a message in the console with green emphasis. + // Newline is automatically appended. + bool Status( const char* fmt, VARG_PARAM dummy, ... ) + { + varg_assert(); + + va_list list; + va_start(list,dummy); + _WriteLn( Color_Green, fmt, list ); + va_end(list); + return false; + } + + // Displays a message in the console with red emphasis. + // Newline is automatically appended. + bool Error( const char* fmt ) + { + WriteLn( Color_Red, fmt ); + return false; + } + + // Displays a message in the console with yellow emphasis. + // Newline is automatically appended. + bool Notice( const char* fmt ) + { + WriteLn( Color_Yellow, fmt ); + return false; + } + + // Displays a message in the console with green emphasis. + // Newline is automatically appended. + bool Status( const char* fmt ) + { + WriteLn( Color_Green, fmt ); + return false; + } + +} + diff --git a/pcsx2/Counters.cpp b/pcsx2/Counters.cpp index 6900a6f214..adc0e5970c 100644 --- a/pcsx2/Counters.cpp +++ b/pcsx2/Counters.cpp @@ -1,863 +1,863 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include -#include -#include "Common.h" -#include "Counters.h" - -#include "R3000A.h" -#include "IopCounters.h" - -#include "GS.h" -#include "VUmicro.h" - -using namespace Threading; - -extern u8 psxhblankgate; -u32 g_vu1SkipCount; // number of frames to disable/skip VU1 - -static const uint EECNT_FUTURE_TARGET = 0x10000000; - -u64 profile_starttick = 0; -u64 profile_totalticks = 0; - -int gates = 0; - -// Counter 4 takes care of scanlines - hSync/hBlanks -// Counter 5 takes care of vSync/vBlanks -Counter counters[6]; - -u32 nextsCounter; // records the cpuRegs.cycle value of the last call to rcntUpdate() -s32 nextCounter; // delta from nextsCounter, in cycles, until the next rcntUpdate() - -// VUSkip Locals and Globals - -void rcntReset(int index) { - counters[index].count = 0; - counters[index].sCycleT = cpuRegs.cycle; -} - -// Updates the state of the nextCounter value (if needed) to serve -// any pending events for the given counter. -// Call this method after any modifications to the state of a counter. -static __forceinline void _rcntSet( int cntidx ) -{ - s32 c; - jASSUME( cntidx <= 4 ); // rcntSet isn't valid for h/vsync counters. - - const Counter& counter = counters[cntidx]; - - // Stopped or special hsync gate? - if (!counter.mode.IsCounting || (counter.mode.ClockSource == 0x3) ) return; - - // check for special cases where the overflow or target has just passed - // (we probably missed it because we're doing/checking other things) - if( counter.count > 0x10000 || counter.count > counter.target ) - { - nextCounter = 4; - return; - } - - // nextCounter is relative to the cpuRegs.cycle when rcntUpdate() was last called. - // However, the current _rcntSet could be called at any cycle count, so we need to take - // that into account. Adding the difference from that cycle count to the current one - // will do the trick! - - c = ((0x10000 - counter.count) * counter.rate) - (cpuRegs.cycle - counter.sCycleT); - c += cpuRegs.cycle - nextsCounter; // adjust for time passed since last rcntUpdate(); - if (c < nextCounter) nextCounter = c; - - // Ignore target diff if target is currently disabled. - // (the overflow is all we care about since it goes first, and then the - // target will be turned on afterward). - - if( counter.target & EECNT_FUTURE_TARGET ) return; - c = ((counter.target - counter.count) * counter.rate) - (cpuRegs.cycle - counter.sCycleT); - c += cpuRegs.cycle - nextsCounter; // adjust for time passed since last rcntUpdate(); - if (c < nextCounter) nextCounter = c; -} - - -static __forceinline void cpuRcntSet() -{ - int i; - - nextsCounter = cpuRegs.cycle; - nextCounter = (counters[5].sCycle + counters[5].CycleT) - cpuRegs.cycle; - - for (i = 0; i < 4; i++) - _rcntSet( i ); - - // sanity check! - if( nextCounter < 0 ) nextCounter = 0; -} - -void rcntInit() { - int i; - - memzero_obj(counters); - - for (i=0; i<4; i++) { - counters[i].rate = 2; - counters[i].target = 0xffff; - } - counters[0].interrupt = 9; - counters[1].interrupt = 10; - counters[2].interrupt = 11; - counters[3].interrupt = 12; - - counters[4].modeval = MODE_HRENDER; - counters[4].sCycle = cpuRegs.cycle; - counters[5].modeval = MODE_VRENDER; - counters[5].sCycle = cpuRegs.cycle; - - UpdateVSyncRate(); - - for (i=0; i<4; i++) rcntReset(i); - cpuRcntSet(); -} - -// debug code, used for stats -int g_nCounters[4]; -static int iFrame = 0; - -#ifndef _WIN32 -#include -#endif - -static s64 m_iTicks=0; -static u64 m_iStart=0; - -struct vSyncTimingInfo -{ - u32 Framerate; // frames per second * 100 (so 2500 for PAL and 2997 for NTSC) - u32 Render; // time from vblank end to vblank start (cycles) - u32 Blank; // time from vblank start to vblank end (cycles) - - u32 hSyncError; // rounding error after the duration of a rendered frame (cycles) - u32 hRender; // time from hblank end to hblank start (cycles) - u32 hBlank; // time from hblank start to hblank end (cycles) - u32 hScanlinesPerFrame; // number of scanlines per frame (525/625 for NTSC/PAL) -}; - - -static vSyncTimingInfo vSyncInfo; - - -static __forceinline void vSyncInfoCalc( vSyncTimingInfo* info, u32 framesPerSecond, u32 scansPerFrame ) -{ - // Important: Cannot use floats or doubles here. The emulator changes rounding modes - // depending on user-set speedhack options, and it can break float/double code - // (as in returning infinities and junk) - - // NOTE: mgs3 likes a /4 vsync, but many games prefer /2. This seems to indicate a - // problem in the counters vsync gates somewhere. - - u64 Frame = ((u64)PS2CLK * 1000000ULL) / framesPerSecond; - u64 HalfFrame = Frame / 2; - u64 Blank = HalfFrame / 2; // two blanks and renders per frame - u64 Render = HalfFrame - Blank; // so use the half-frame value for these... - - // Important! The hRender/hBlank timers should be 50/50 for best results. - // In theory a 70%/30% ratio would be more correct but in practice it runs - // like crap and totally screws audio synchronization and other things. - - u64 Scanline = Frame / scansPerFrame; - u64 hBlank = Scanline / 2; - u64 hRender = Scanline - hBlank; - - info->Framerate = framesPerSecond; - info->Render = (u32)(Render/10000); - info->Blank = (u32)(Blank/10000); - - info->hRender = (u32)(hRender/10000); - info->hBlank = (u32)(hBlank/10000); - info->hScanlinesPerFrame = scansPerFrame; - - // Apply rounding: - if( ( Render - info->Render ) >= 5000 ) info->Render++; - else if( ( Blank - info->Blank ) >= 5000 ) info->Blank++; - - if( ( hRender - info->hRender ) >= 5000 ) info->hRender++; - else if( ( hBlank - info->hBlank ) >= 5000 ) info->hBlank++; - - // Calculate accumulative hSync rounding error per half-frame: - { - u32 hSyncCycles = ((info->hRender + info->hBlank) * scansPerFrame) / 2; - u32 vSyncCycles = (info->Render + info->Blank); - info->hSyncError = vSyncCycles - hSyncCycles; - } - - // Note: In NTSC modes there is some small rounding error in the vsync too, - // however it would take thousands of frames for it to amount to anything and - // is thus not worth the effort at this time. -} - - -u32 UpdateVSyncRate() -{ - const char *limiterMsg = "Framelimiter rate updated (UpdateVSyncRate): %d.%d fps"; - - // fixme - According to some docs, progressive-scan modes actually refresh slower than - // interlaced modes. But I can't fathom how, since the refresh rate is a function of - // the television and all the docs I found on TVs made no indication that they ever - // run anything except their native refresh rate. - - //#define VBLANK_NTSC ((Config.PsxType & 2) ? 59.94 : 59.82) //59.94 is more precise - //#define VBLANK_PAL ((Config.PsxType & 2) ? 50.00 : 49.76) - - if(Config.PsxType & 1) - { - if( vSyncInfo.Framerate != FRAMERATE_PAL ) - vSyncInfoCalc( &vSyncInfo, FRAMERATE_PAL, SCANLINES_TOTAL_PAL ); - } - else - { - if( vSyncInfo.Framerate != FRAMERATE_NTSC ) - vSyncInfoCalc( &vSyncInfo, FRAMERATE_NTSC, SCANLINES_TOTAL_NTSC ); - } - - counters[4].CycleT = vSyncInfo.hRender; // Amount of cycles before the counter will be updated - counters[5].CycleT = vSyncInfo.Render; // Amount of cycles before the counter will be updated - - if (Config.CustomFps > 0) - { - s64 ticks = GetTickFrequency() / Config.CustomFps; - if( m_iTicks != ticks ) - { - m_iTicks = ticks; - gsOnModeChanged( vSyncInfo.Framerate, m_iTicks ); - Console::Status( limiterMsg, params Config.CustomFps, 0 ); - } - } - else - { - s64 ticks = (GetTickFrequency() * 50) / vSyncInfo.Framerate; - if( m_iTicks != ticks ) - { - m_iTicks = ticks; - gsOnModeChanged( vSyncInfo.Framerate, m_iTicks ); - Console::Status( limiterMsg, params vSyncInfo.Framerate/50, (vSyncInfo.Framerate*2)%100 ); - } - } - - m_iStart = GetCPUTicks(); - cpuRcntSet(); - - // Initialize VU Skip Stuff... - g_vu1SkipCount = 0; - - return (u32)m_iTicks; -} - -extern u32 vu0time; - - -void vSyncDebugStuff() { - -#ifdef PCSX2_DEVBUILD - if( g_TestRun.enabled && g_TestRun.frame > 0 ) { - if( iFrame > g_TestRun.frame ) { - // take a snapshot - if( g_TestRun.pimagename != NULL && GSmakeSnapshot2 != NULL ) { - if( g_TestRun.snapdone ) { - g_TestRun.curimage++; - g_TestRun.snapdone = 0; - g_TestRun.frame += 20; - if( g_TestRun.curimage >= g_TestRun.numimages ) { - // exit - SysClose(); - exit(0); - } - } - else { - // query for the image - GSmakeSnapshot2(g_TestRun.pimagename, &g_TestRun.snapdone, g_TestRun.jpgcapture); - } - } - else { - // exit - SysClose(); - exit(0); - } - } - } - - GSVSYNC(); - - if( g_SaveGSStream == 1 ) { - freezeData fP; - - g_SaveGSStream = 2; - g_fGSSave->gsFreeze(); - - if (GSfreeze(FREEZE_SIZE, &fP) == -1) { - safe_delete( g_fGSSave ); - g_SaveGSStream = 0; - } - else { - fP.data = (s8*)malloc(fP.size); - if (fP.data == NULL) { - safe_delete( g_fGSSave ); - g_SaveGSStream = 0; - } - else { - if (GSfreeze(FREEZE_SAVE, &fP) == -1) { - safe_delete( g_fGSSave ); - g_SaveGSStream = 0; - } - else { - g_fGSSave->Freeze( fP.size ); - if (fP.size) { - g_fGSSave->FreezeMem( fP.data, fP.size ); - free(fP.data); - } - } - } - } - } - else if( g_SaveGSStream == 2 ) { - - if( --g_nLeftGSFrames <= 0 ) { - safe_delete( g_fGSSave ); - g_SaveGSStream = 0; - Console::WriteLn("Done saving GS stream"); - } - } -#endif -} - -void frameLimitReset() -{ - m_iStart = GetCPUTicks(); -} - -// Framelimiter - Measures the delta time between calls and stalls until a -// certain amount of time passes if such time hasn't passed yet. -// See the GS FrameSkip function for details on why this is here and not in the GS. -static __forceinline void frameLimit() -{ - s64 sDeltaTime; - u64 uExpectedEnd; - u64 iEnd; - - if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_NORMAL ) return; - if( Config.CustomFps >= 999 ) return; // means the user would rather just have framelimiting turned off... - - uExpectedEnd = m_iStart + m_iTicks; - iEnd = GetCPUTicks(); - - sDeltaTime = iEnd - uExpectedEnd; - - // If the framerate drops too low, reset the expected value. This avoids - // excessive amounts of "fast forward" syndrome which would occur if we - // tried to catch up too much. - - if( sDeltaTime > m_iTicks*8 ) - { - m_iStart = iEnd - m_iTicks; - - // Let the GS Skipper know we lost time. - // Keeps the GS skipper from trying to catch up to a framerate - // that the limiter already gave up on. - - gsSyncLimiterLostTime( (s32)(m_iStart - uExpectedEnd) ); - return; - } - - // use the expected frame completion time as our starting point. - // improves smoothness by making the framelimiter more adaptive to the - // imperfect TIMESLICE() wait, and allows it to speed up a wee bit after - // slow frames to "catch up." - - m_iStart = uExpectedEnd; - - while( sDeltaTime < 0 ) - { - Timeslice(); - iEnd = GetCPUTicks(); - sDeltaTime = iEnd - uExpectedEnd; - } -} - -static __forceinline void VSyncStart(u32 sCycle) -{ - EECNT_LOG( "///////// EE COUNTER VSYNC START \\\\\\\\\\ (frame: %d)\n", iFrame ); - vSyncDebugStuff(); // EE Profiling and Debug code - - if ((CSRw & 0x8)) GSCSRr|= 0x8; - if (!(GSIMR&0x800)) gsIrq(); - - hwIntcIrq(2); - psxVBlankStart(); - - if (gates) rcntStartGate(0x8, sCycle); // Counters Start Gate code - if (Config.Patch) applypatch(1); // Apply patches (ToDo: clean up patch code) - - // INTC - VB Blank Start Hack -- - // Hack fix! This corrects a freezeup in Granda 2 where it decides to spin - // on the INTC_STAT register after the exception handler has already cleared - // it. But be warned! Set the value to larger than 4 and it breaks Dark - // Cloud and other games. -_- - - // How it works: Normally the INTC raises exceptions immediately at the end of the - // current branch test. But in the case of Grandia 2, the game's code is spinning - // on the INTC status, and the exception handler (for some reason?) clears the INTC - // before returning *and* returns to a location other than EPC. So the game never - // gets to the point where it sees the INTC Irq set true. - - // (I haven't investigated why Dark Cloud freezes on larger values) - // (all testing done using the recompiler -- dunno how the ints respond yet) - - cpuRegs.eCycle[30] = 2; -} - -static __forceinline void VSyncEnd(u32 sCycle) -{ - EECNT_LOG( "///////// EE COUNTER VSYNC END \\\\\\\\\\ (frame: %d)\n", iFrame ); - - iFrame++; - - if( g_vu1SkipCount > 0 ) - { - gsPostVsyncEnd( false ); - AtomicDecrement( g_vu1SkipCount ); - vu1MicroEnableSkip(); - } - else - { - gsPostVsyncEnd( true ); - vu1MicroDisableSkip(); - } - - hwIntcIrq(3); // HW Irq - psxVBlankEnd(); // psxCounters vBlank End - if (gates) rcntEndGate(0x8, sCycle); // Counters End Gate Code - frameLimit(); // limit FPS - - // This doesn't seem to be needed here. Games only seem to break with regard to the - // vsyncstart irq. - //cpuRegs.eCycle[30] = 2; -} - -//#define VSYNC_DEBUG // Uncomment this to enable some vSync Timer debugging features. -#ifdef VSYNC_DEBUG -static u32 hsc=0; -static int vblankinc = 0; -#endif - -__forceinline void rcntUpdate_hScanline() -{ - if( !cpuTestCycle( counters[4].sCycle, counters[4].CycleT ) ) return; - - //iopBranchAction = 1; - if (counters[4].modeval & MODE_HBLANK) { //HBLANK Start - rcntStartGate(0, counters[4].sCycle); - psxCheckStartGate16(0); - - // Setup the hRender's start and end cycle information: - counters[4].sCycle += vSyncInfo.hBlank; // start (absolute cycle value) - counters[4].CycleT = vSyncInfo.hRender; // endpoint (delta from start value) - counters[4].modeval = MODE_HRENDER; - } - else { //HBLANK END / HRENDER Begin - if (CSRw & 0x4) GSCSRr |= 4; // signal - if (!(GSIMR&0x400)) gsIrq(); - if (gates) rcntEndGate(0, counters[4].sCycle); - if (psxhblankgate) psxCheckEndGate16(0); - - // set up the hblank's start and end cycle information: - counters[4].sCycle += vSyncInfo.hRender; // start (absolute cycle value) - counters[4].CycleT = vSyncInfo.hBlank; // endpoint (delta from start value) - counters[4].modeval = MODE_HBLANK; - -# ifdef VSYNC_DEBUG - hsc++; -# endif - } -} - -__forceinline bool rcntUpdate_vSync() -{ - s32 diff = (cpuRegs.cycle - counters[5].sCycle); - if( diff < counters[5].CycleT ) return false; - - //iopBranchAction = 1; - if (counters[5].modeval == MODE_VSYNC) - { - VSyncEnd(counters[5].sCycle); - - counters[5].sCycle += vSyncInfo.Blank; - counters[5].CycleT = vSyncInfo.Render; - counters[5].modeval = MODE_VRENDER; - - return true; -// SysUpdate(); // check for and handle keyevents - } - else // VSYNC end / VRENDER begin - { - VSyncStart(counters[5].sCycle); - - counters[5].sCycle += vSyncInfo.Render; - counters[5].CycleT = vSyncInfo.Blank; - counters[5].modeval = MODE_VSYNC; - - // Accumulate hsync rounding errors: - counters[4].sCycle += vSyncInfo.hSyncError; - -# ifdef VSYNC_DEBUG - vblankinc++; - if( vblankinc > 1 ) - { - if( hsc != vSyncInfo.hScanlinesPerFrame ) - SysPrintf( " ** vSync > Abnormal Scanline Count: %d\n", hsc ); - hsc = 0; - vblankinc = 0; - } -# endif - } - return false; -} - -static __forceinline void __fastcall _cpuTestTarget( int i ) -{ - if (counters[i].count < counters[i].target) return; - - if(counters[i].mode.TargetInterrupt) { - - EECNT_LOG("EE Counter[%d] TARGET reached - mode=%x, count=%x, target=%x\n", i, counters[i].mode, counters[i].count, counters[i].target); - counters[i].mode.TargetReached = 1; - hwIntcIrq(counters[i].interrupt); - - // The PS2 only resets if the interrupt is enabled - Tested on PS2 - if (counters[i].mode.ZeroReturn) - counters[i].count -= counters[i].target; // Reset on target - else - counters[i].target |= EECNT_FUTURE_TARGET; - } - else counters[i].target |= EECNT_FUTURE_TARGET; -} - -static __forceinline void _cpuTestOverflow( int i ) -{ - if (counters[i].count <= 0xffff) return; - - if (counters[i].mode.OverflowInterrupt) { - EECNT_LOG("EE Counter[%d] OVERFLOW - mode=%x, count=%x\n", i, counters[i].mode, counters[i].count); - counters[i].mode.OverflowReached = 1; - hwIntcIrq(counters[i].interrupt); - } - - // wrap counter back around zero, and enable the future target: - counters[i].count -= 0x10000; - counters[i].target &= 0xffff; -} - - -// forceinline note: this method is called from two locations, but one -// of them is the interpreter, which doesn't count. ;) So might as -// well forceinline it! -__forceinline bool rcntUpdate() -{ - bool retval = rcntUpdate_vSync(); - - // Update counters so that we can perform overflow and target tests. - - for (int i=0; i<=3; i++) { - - // We want to count gated counters (except the hblank which exclude below, and are - // counted by the hblank timer instead) - - //if ( gates & (1< 0 ) - { - counters[index].count += change / counters[index].rate; - change -= (change / counters[index].rate) * counters[index].rate; - counters[index].sCycleT = cpuRegs.cycle - change; - } - } - } - else counters[index].sCycleT = cpuRegs.cycle; - - counters[index].modeval &= ~(value & 0xc00); //Clear status flags, the ps2 only clears what is given in the value - counters[index].modeval = (counters[index].modeval & 0xc00) | (value & 0x3ff); - EECNT_LOG("EE Counter[%d] writeMode = %x passed value=%x\n", index, counters[index].modeval, value ); - - switch (counters[index].mode.ClockSource) { //Clock rate divisers *2, they use BUSCLK speed not PS2CLK - case 0: counters[index].rate = 2; break; - case 1: counters[index].rate = 32; break; - case 2: counters[index].rate = 512; break; - case 3: counters[index].rate = vSyncInfo.hBlank+vSyncInfo.hRender; break; - } - - _rcntSetGate( index ); - _rcntSet( index ); -} - -void __fastcall rcntWcount(int index, u32 value) -{ - EECNT_LOG("EE Counter[%d] writeCount = %x, oldcount=%x, target=%x\n", index, value, counters[index].count, counters[index].target ); - - counters[index].count = value & 0xffff; - - // reset the target, and make sure we don't get a premature target. - counters[index].target &= 0xffff; - if( counters[index].count > counters[index].target ) - counters[index].target |= EECNT_FUTURE_TARGET; - - // re-calculate the start cycle of the counter based on elapsed time since the last counter update: - if(counters[index].mode.IsCounting) { - if(counters[index].mode.ClockSource != 0x3) { - s32 change = cpuRegs.cycle - counters[index].sCycleT; - if( change > 0 ) { - change -= (change / counters[index].rate) * counters[index].rate; - counters[index].sCycleT = cpuRegs.cycle - change; - } - } - } - else counters[index].sCycleT = cpuRegs.cycle; - - _rcntSet( index ); -} - -void __fastcall rcntWtarget(int index, u32 value) -{ - EECNT_LOG("EE Counter[%d] writeTarget = %x\n", index, value); - - counters[index].target = value & 0xffff; - - // guard against premature (instant) targeting. - // If the target is behind the current count, set it up so that the counter must - // overflow first before the target fires: - - if( counters[index].target <= rcntCycle(index) ) - counters[index].target |= EECNT_FUTURE_TARGET; - - _rcntSet( index ); -} - -void __fastcall rcntWhold(int index, u32 value) -{ - EECNT_LOG("EE Counter[%d] Hold Write = %x\n", index, value); - counters[index].hold = value; -} - -u32 __fastcall rcntRcount(int index) -{ - u32 ret; - - // only count if the counter is turned on (0x80) and is not an hsync gate (!0x03) - if (counters[index].mode.IsCounting && (counters[index].mode.ClockSource != 0x3)) - ret = counters[index].count + ((cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate); - else - ret = counters[index].count; - - EECNT_LOG("EE Counter[%d] readCount32 = %x\n", index, ret); - return ret; -} - -u32 __fastcall rcntCycle(int index) -{ - if (counters[index].mode.IsCounting && (counters[index].mode.ClockSource != 0x3)) - return counters[index].count + ((cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate); - else - return counters[index].count; -} - -void SaveState::rcntFreeze() -{ - Freeze(counters); - Freeze(nextCounter); - Freeze(nextsCounter); - - // New in version 11 -- save the PAL/NTSC info! - if( GetVersion() > 0x10 ) - { - Freeze( Config.PsxType ); - } - - if( IsLoading() ) - { - UpdateVSyncRate(); - - // make sure the gate flags are set based on the counter modes... - for( int i=0; i<4; i++ ) - _rcntSetGate( i ); - - iopBranchAction = 1; // probably not needed but won't hurt anything either. - } -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include +#include +#include "Common.h" +#include "Counters.h" + +#include "R3000A.h" +#include "IopCounters.h" + +#include "GS.h" +#include "VUmicro.h" + +using namespace Threading; + +extern u8 psxhblankgate; +u32 g_vu1SkipCount; // number of frames to disable/skip VU1 + +static const uint EECNT_FUTURE_TARGET = 0x10000000; + +u64 profile_starttick = 0; +u64 profile_totalticks = 0; + +int gates = 0; + +// Counter 4 takes care of scanlines - hSync/hBlanks +// Counter 5 takes care of vSync/vBlanks +Counter counters[6]; + +u32 nextsCounter; // records the cpuRegs.cycle value of the last call to rcntUpdate() +s32 nextCounter; // delta from nextsCounter, in cycles, until the next rcntUpdate() + +// VUSkip Locals and Globals + +void rcntReset(int index) { + counters[index].count = 0; + counters[index].sCycleT = cpuRegs.cycle; +} + +// Updates the state of the nextCounter value (if needed) to serve +// any pending events for the given counter. +// Call this method after any modifications to the state of a counter. +static __forceinline void _rcntSet( int cntidx ) +{ + s32 c; + jASSUME( cntidx <= 4 ); // rcntSet isn't valid for h/vsync counters. + + const Counter& counter = counters[cntidx]; + + // Stopped or special hsync gate? + if (!counter.mode.IsCounting || (counter.mode.ClockSource == 0x3) ) return; + + // check for special cases where the overflow or target has just passed + // (we probably missed it because we're doing/checking other things) + if( counter.count > 0x10000 || counter.count > counter.target ) + { + nextCounter = 4; + return; + } + + // nextCounter is relative to the cpuRegs.cycle when rcntUpdate() was last called. + // However, the current _rcntSet could be called at any cycle count, so we need to take + // that into account. Adding the difference from that cycle count to the current one + // will do the trick! + + c = ((0x10000 - counter.count) * counter.rate) - (cpuRegs.cycle - counter.sCycleT); + c += cpuRegs.cycle - nextsCounter; // adjust for time passed since last rcntUpdate(); + if (c < nextCounter) nextCounter = c; + + // Ignore target diff if target is currently disabled. + // (the overflow is all we care about since it goes first, and then the + // target will be turned on afterward). + + if( counter.target & EECNT_FUTURE_TARGET ) return; + c = ((counter.target - counter.count) * counter.rate) - (cpuRegs.cycle - counter.sCycleT); + c += cpuRegs.cycle - nextsCounter; // adjust for time passed since last rcntUpdate(); + if (c < nextCounter) nextCounter = c; +} + + +static __forceinline void cpuRcntSet() +{ + int i; + + nextsCounter = cpuRegs.cycle; + nextCounter = (counters[5].sCycle + counters[5].CycleT) - cpuRegs.cycle; + + for (i = 0; i < 4; i++) + _rcntSet( i ); + + // sanity check! + if( nextCounter < 0 ) nextCounter = 0; +} + +void rcntInit() { + int i; + + memzero_obj(counters); + + for (i=0; i<4; i++) { + counters[i].rate = 2; + counters[i].target = 0xffff; + } + counters[0].interrupt = 9; + counters[1].interrupt = 10; + counters[2].interrupt = 11; + counters[3].interrupt = 12; + + counters[4].modeval = MODE_HRENDER; + counters[4].sCycle = cpuRegs.cycle; + counters[5].modeval = MODE_VRENDER; + counters[5].sCycle = cpuRegs.cycle; + + UpdateVSyncRate(); + + for (i=0; i<4; i++) rcntReset(i); + cpuRcntSet(); +} + +// debug code, used for stats +int g_nCounters[4]; +static int iFrame = 0; + +#ifndef _WIN32 +#include +#endif + +static s64 m_iTicks=0; +static u64 m_iStart=0; + +struct vSyncTimingInfo +{ + u32 Framerate; // frames per second * 100 (so 2500 for PAL and 2997 for NTSC) + u32 Render; // time from vblank end to vblank start (cycles) + u32 Blank; // time from vblank start to vblank end (cycles) + + u32 hSyncError; // rounding error after the duration of a rendered frame (cycles) + u32 hRender; // time from hblank end to hblank start (cycles) + u32 hBlank; // time from hblank start to hblank end (cycles) + u32 hScanlinesPerFrame; // number of scanlines per frame (525/625 for NTSC/PAL) +}; + + +static vSyncTimingInfo vSyncInfo; + + +static __forceinline void vSyncInfoCalc( vSyncTimingInfo* info, u32 framesPerSecond, u32 scansPerFrame ) +{ + // Important: Cannot use floats or doubles here. The emulator changes rounding modes + // depending on user-set speedhack options, and it can break float/double code + // (as in returning infinities and junk) + + // NOTE: mgs3 likes a /4 vsync, but many games prefer /2. This seems to indicate a + // problem in the counters vsync gates somewhere. + + u64 Frame = ((u64)PS2CLK * 1000000ULL) / framesPerSecond; + u64 HalfFrame = Frame / 2; + u64 Blank = HalfFrame / 2; // two blanks and renders per frame + u64 Render = HalfFrame - Blank; // so use the half-frame value for these... + + // Important! The hRender/hBlank timers should be 50/50 for best results. + // In theory a 70%/30% ratio would be more correct but in practice it runs + // like crap and totally screws audio synchronization and other things. + + u64 Scanline = Frame / scansPerFrame; + u64 hBlank = Scanline / 2; + u64 hRender = Scanline - hBlank; + + info->Framerate = framesPerSecond; + info->Render = (u32)(Render/10000); + info->Blank = (u32)(Blank/10000); + + info->hRender = (u32)(hRender/10000); + info->hBlank = (u32)(hBlank/10000); + info->hScanlinesPerFrame = scansPerFrame; + + // Apply rounding: + if( ( Render - info->Render ) >= 5000 ) info->Render++; + else if( ( Blank - info->Blank ) >= 5000 ) info->Blank++; + + if( ( hRender - info->hRender ) >= 5000 ) info->hRender++; + else if( ( hBlank - info->hBlank ) >= 5000 ) info->hBlank++; + + // Calculate accumulative hSync rounding error per half-frame: + { + u32 hSyncCycles = ((info->hRender + info->hBlank) * scansPerFrame) / 2; + u32 vSyncCycles = (info->Render + info->Blank); + info->hSyncError = vSyncCycles - hSyncCycles; + } + + // Note: In NTSC modes there is some small rounding error in the vsync too, + // however it would take thousands of frames for it to amount to anything and + // is thus not worth the effort at this time. +} + + +u32 UpdateVSyncRate() +{ + const char *limiterMsg = "Framelimiter rate updated (UpdateVSyncRate): %d.%d fps"; + + // fixme - According to some docs, progressive-scan modes actually refresh slower than + // interlaced modes. But I can't fathom how, since the refresh rate is a function of + // the television and all the docs I found on TVs made no indication that they ever + // run anything except their native refresh rate. + + //#define VBLANK_NTSC ((Config.PsxType & 2) ? 59.94 : 59.82) //59.94 is more precise + //#define VBLANK_PAL ((Config.PsxType & 2) ? 50.00 : 49.76) + + if(Config.PsxType & 1) + { + if( vSyncInfo.Framerate != FRAMERATE_PAL ) + vSyncInfoCalc( &vSyncInfo, FRAMERATE_PAL, SCANLINES_TOTAL_PAL ); + } + else + { + if( vSyncInfo.Framerate != FRAMERATE_NTSC ) + vSyncInfoCalc( &vSyncInfo, FRAMERATE_NTSC, SCANLINES_TOTAL_NTSC ); + } + + counters[4].CycleT = vSyncInfo.hRender; // Amount of cycles before the counter will be updated + counters[5].CycleT = vSyncInfo.Render; // Amount of cycles before the counter will be updated + + if (Config.CustomFps > 0) + { + s64 ticks = GetTickFrequency() / Config.CustomFps; + if( m_iTicks != ticks ) + { + m_iTicks = ticks; + gsOnModeChanged( vSyncInfo.Framerate, m_iTicks ); + Console::Status( limiterMsg, params Config.CustomFps, 0 ); + } + } + else + { + s64 ticks = (GetTickFrequency() * 50) / vSyncInfo.Framerate; + if( m_iTicks != ticks ) + { + m_iTicks = ticks; + gsOnModeChanged( vSyncInfo.Framerate, m_iTicks ); + Console::Status( limiterMsg, params vSyncInfo.Framerate/50, (vSyncInfo.Framerate*2)%100 ); + } + } + + m_iStart = GetCPUTicks(); + cpuRcntSet(); + + // Initialize VU Skip Stuff... + g_vu1SkipCount = 0; + + return (u32)m_iTicks; +} + +extern u32 vu0time; + + +void vSyncDebugStuff() { + +#ifdef PCSX2_DEVBUILD + if( g_TestRun.enabled && g_TestRun.frame > 0 ) { + if( iFrame > g_TestRun.frame ) { + // take a snapshot + if( g_TestRun.pimagename != NULL && GSmakeSnapshot2 != NULL ) { + if( g_TestRun.snapdone ) { + g_TestRun.curimage++; + g_TestRun.snapdone = 0; + g_TestRun.frame += 20; + if( g_TestRun.curimage >= g_TestRun.numimages ) { + // exit + SysClose(); + exit(0); + } + } + else { + // query for the image + GSmakeSnapshot2(g_TestRun.pimagename, &g_TestRun.snapdone, g_TestRun.jpgcapture); + } + } + else { + // exit + SysClose(); + exit(0); + } + } + } + + GSVSYNC(); + + if( g_SaveGSStream == 1 ) { + freezeData fP; + + g_SaveGSStream = 2; + g_fGSSave->gsFreeze(); + + if (GSfreeze(FREEZE_SIZE, &fP) == -1) { + safe_delete( g_fGSSave ); + g_SaveGSStream = 0; + } + else { + fP.data = (s8*)malloc(fP.size); + if (fP.data == NULL) { + safe_delete( g_fGSSave ); + g_SaveGSStream = 0; + } + else { + if (GSfreeze(FREEZE_SAVE, &fP) == -1) { + safe_delete( g_fGSSave ); + g_SaveGSStream = 0; + } + else { + g_fGSSave->Freeze( fP.size ); + if (fP.size) { + g_fGSSave->FreezeMem( fP.data, fP.size ); + free(fP.data); + } + } + } + } + } + else if( g_SaveGSStream == 2 ) { + + if( --g_nLeftGSFrames <= 0 ) { + safe_delete( g_fGSSave ); + g_SaveGSStream = 0; + Console::WriteLn("Done saving GS stream"); + } + } +#endif +} + +void frameLimitReset() +{ + m_iStart = GetCPUTicks(); +} + +// Framelimiter - Measures the delta time between calls and stalls until a +// certain amount of time passes if such time hasn't passed yet. +// See the GS FrameSkip function for details on why this is here and not in the GS. +static __forceinline void frameLimit() +{ + s64 sDeltaTime; + u64 uExpectedEnd; + u64 iEnd; + + if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_NORMAL ) return; + if( Config.CustomFps >= 999 ) return; // means the user would rather just have framelimiting turned off... + + uExpectedEnd = m_iStart + m_iTicks; + iEnd = GetCPUTicks(); + + sDeltaTime = iEnd - uExpectedEnd; + + // If the framerate drops too low, reset the expected value. This avoids + // excessive amounts of "fast forward" syndrome which would occur if we + // tried to catch up too much. + + if( sDeltaTime > m_iTicks*8 ) + { + m_iStart = iEnd - m_iTicks; + + // Let the GS Skipper know we lost time. + // Keeps the GS skipper from trying to catch up to a framerate + // that the limiter already gave up on. + + gsSyncLimiterLostTime( (s32)(m_iStart - uExpectedEnd) ); + return; + } + + // use the expected frame completion time as our starting point. + // improves smoothness by making the framelimiter more adaptive to the + // imperfect TIMESLICE() wait, and allows it to speed up a wee bit after + // slow frames to "catch up." + + m_iStart = uExpectedEnd; + + while( sDeltaTime < 0 ) + { + Timeslice(); + iEnd = GetCPUTicks(); + sDeltaTime = iEnd - uExpectedEnd; + } +} + +static __forceinline void VSyncStart(u32 sCycle) +{ + EECNT_LOG( "///////// EE COUNTER VSYNC START \\\\\\\\\\ (frame: %d)\n", iFrame ); + vSyncDebugStuff(); // EE Profiling and Debug code + + if ((CSRw & 0x8)) GSCSRr|= 0x8; + if (!(GSIMR&0x800)) gsIrq(); + + hwIntcIrq(2); + psxVBlankStart(); + + if (gates) rcntStartGate(0x8, sCycle); // Counters Start Gate code + if (Config.Patch) applypatch(1); // Apply patches (ToDo: clean up patch code) + + // INTC - VB Blank Start Hack -- + // Hack fix! This corrects a freezeup in Granda 2 where it decides to spin + // on the INTC_STAT register after the exception handler has already cleared + // it. But be warned! Set the value to larger than 4 and it breaks Dark + // Cloud and other games. -_- + + // How it works: Normally the INTC raises exceptions immediately at the end of the + // current branch test. But in the case of Grandia 2, the game's code is spinning + // on the INTC status, and the exception handler (for some reason?) clears the INTC + // before returning *and* returns to a location other than EPC. So the game never + // gets to the point where it sees the INTC Irq set true. + + // (I haven't investigated why Dark Cloud freezes on larger values) + // (all testing done using the recompiler -- dunno how the ints respond yet) + + cpuRegs.eCycle[30] = 2; +} + +static __forceinline void VSyncEnd(u32 sCycle) +{ + EECNT_LOG( "///////// EE COUNTER VSYNC END \\\\\\\\\\ (frame: %d)\n", iFrame ); + + iFrame++; + + if( g_vu1SkipCount > 0 ) + { + gsPostVsyncEnd( false ); + AtomicDecrement( g_vu1SkipCount ); + vu1MicroEnableSkip(); + } + else + { + gsPostVsyncEnd( true ); + vu1MicroDisableSkip(); + } + + hwIntcIrq(3); // HW Irq + psxVBlankEnd(); // psxCounters vBlank End + if (gates) rcntEndGate(0x8, sCycle); // Counters End Gate Code + frameLimit(); // limit FPS + + // This doesn't seem to be needed here. Games only seem to break with regard to the + // vsyncstart irq. + //cpuRegs.eCycle[30] = 2; +} + +//#define VSYNC_DEBUG // Uncomment this to enable some vSync Timer debugging features. +#ifdef VSYNC_DEBUG +static u32 hsc=0; +static int vblankinc = 0; +#endif + +__forceinline void rcntUpdate_hScanline() +{ + if( !cpuTestCycle( counters[4].sCycle, counters[4].CycleT ) ) return; + + //iopBranchAction = 1; + if (counters[4].modeval & MODE_HBLANK) { //HBLANK Start + rcntStartGate(0, counters[4].sCycle); + psxCheckStartGate16(0); + + // Setup the hRender's start and end cycle information: + counters[4].sCycle += vSyncInfo.hBlank; // start (absolute cycle value) + counters[4].CycleT = vSyncInfo.hRender; // endpoint (delta from start value) + counters[4].modeval = MODE_HRENDER; + } + else { //HBLANK END / HRENDER Begin + if (CSRw & 0x4) GSCSRr |= 4; // signal + if (!(GSIMR&0x400)) gsIrq(); + if (gates) rcntEndGate(0, counters[4].sCycle); + if (psxhblankgate) psxCheckEndGate16(0); + + // set up the hblank's start and end cycle information: + counters[4].sCycle += vSyncInfo.hRender; // start (absolute cycle value) + counters[4].CycleT = vSyncInfo.hBlank; // endpoint (delta from start value) + counters[4].modeval = MODE_HBLANK; + +# ifdef VSYNC_DEBUG + hsc++; +# endif + } +} + +__forceinline bool rcntUpdate_vSync() +{ + s32 diff = (cpuRegs.cycle - counters[5].sCycle); + if( diff < counters[5].CycleT ) return false; + + //iopBranchAction = 1; + if (counters[5].modeval == MODE_VSYNC) + { + VSyncEnd(counters[5].sCycle); + + counters[5].sCycle += vSyncInfo.Blank; + counters[5].CycleT = vSyncInfo.Render; + counters[5].modeval = MODE_VRENDER; + + return true; +// SysUpdate(); // check for and handle keyevents + } + else // VSYNC end / VRENDER begin + { + VSyncStart(counters[5].sCycle); + + counters[5].sCycle += vSyncInfo.Render; + counters[5].CycleT = vSyncInfo.Blank; + counters[5].modeval = MODE_VSYNC; + + // Accumulate hsync rounding errors: + counters[4].sCycle += vSyncInfo.hSyncError; + +# ifdef VSYNC_DEBUG + vblankinc++; + if( vblankinc > 1 ) + { + if( hsc != vSyncInfo.hScanlinesPerFrame ) + SysPrintf( " ** vSync > Abnormal Scanline Count: %d\n", hsc ); + hsc = 0; + vblankinc = 0; + } +# endif + } + return false; +} + +static __forceinline void __fastcall _cpuTestTarget( int i ) +{ + if (counters[i].count < counters[i].target) return; + + if(counters[i].mode.TargetInterrupt) { + + EECNT_LOG("EE Counter[%d] TARGET reached - mode=%x, count=%x, target=%x\n", i, counters[i].mode, counters[i].count, counters[i].target); + counters[i].mode.TargetReached = 1; + hwIntcIrq(counters[i].interrupt); + + // The PS2 only resets if the interrupt is enabled - Tested on PS2 + if (counters[i].mode.ZeroReturn) + counters[i].count -= counters[i].target; // Reset on target + else + counters[i].target |= EECNT_FUTURE_TARGET; + } + else counters[i].target |= EECNT_FUTURE_TARGET; +} + +static __forceinline void _cpuTestOverflow( int i ) +{ + if (counters[i].count <= 0xffff) return; + + if (counters[i].mode.OverflowInterrupt) { + EECNT_LOG("EE Counter[%d] OVERFLOW - mode=%x, count=%x\n", i, counters[i].mode, counters[i].count); + counters[i].mode.OverflowReached = 1; + hwIntcIrq(counters[i].interrupt); + } + + // wrap counter back around zero, and enable the future target: + counters[i].count -= 0x10000; + counters[i].target &= 0xffff; +} + + +// forceinline note: this method is called from two locations, but one +// of them is the interpreter, which doesn't count. ;) So might as +// well forceinline it! +__forceinline bool rcntUpdate() +{ + bool retval = rcntUpdate_vSync(); + + // Update counters so that we can perform overflow and target tests. + + for (int i=0; i<=3; i++) { + + // We want to count gated counters (except the hblank which exclude below, and are + // counted by the hblank timer instead) + + //if ( gates & (1< 0 ) + { + counters[index].count += change / counters[index].rate; + change -= (change / counters[index].rate) * counters[index].rate; + counters[index].sCycleT = cpuRegs.cycle - change; + } + } + } + else counters[index].sCycleT = cpuRegs.cycle; + + counters[index].modeval &= ~(value & 0xc00); //Clear status flags, the ps2 only clears what is given in the value + counters[index].modeval = (counters[index].modeval & 0xc00) | (value & 0x3ff); + EECNT_LOG("EE Counter[%d] writeMode = %x passed value=%x\n", index, counters[index].modeval, value ); + + switch (counters[index].mode.ClockSource) { //Clock rate divisers *2, they use BUSCLK speed not PS2CLK + case 0: counters[index].rate = 2; break; + case 1: counters[index].rate = 32; break; + case 2: counters[index].rate = 512; break; + case 3: counters[index].rate = vSyncInfo.hBlank+vSyncInfo.hRender; break; + } + + _rcntSetGate( index ); + _rcntSet( index ); +} + +void __fastcall rcntWcount(int index, u32 value) +{ + EECNT_LOG("EE Counter[%d] writeCount = %x, oldcount=%x, target=%x\n", index, value, counters[index].count, counters[index].target ); + + counters[index].count = value & 0xffff; + + // reset the target, and make sure we don't get a premature target. + counters[index].target &= 0xffff; + if( counters[index].count > counters[index].target ) + counters[index].target |= EECNT_FUTURE_TARGET; + + // re-calculate the start cycle of the counter based on elapsed time since the last counter update: + if(counters[index].mode.IsCounting) { + if(counters[index].mode.ClockSource != 0x3) { + s32 change = cpuRegs.cycle - counters[index].sCycleT; + if( change > 0 ) { + change -= (change / counters[index].rate) * counters[index].rate; + counters[index].sCycleT = cpuRegs.cycle - change; + } + } + } + else counters[index].sCycleT = cpuRegs.cycle; + + _rcntSet( index ); +} + +void __fastcall rcntWtarget(int index, u32 value) +{ + EECNT_LOG("EE Counter[%d] writeTarget = %x\n", index, value); + + counters[index].target = value & 0xffff; + + // guard against premature (instant) targeting. + // If the target is behind the current count, set it up so that the counter must + // overflow first before the target fires: + + if( counters[index].target <= rcntCycle(index) ) + counters[index].target |= EECNT_FUTURE_TARGET; + + _rcntSet( index ); +} + +void __fastcall rcntWhold(int index, u32 value) +{ + EECNT_LOG("EE Counter[%d] Hold Write = %x\n", index, value); + counters[index].hold = value; +} + +u32 __fastcall rcntRcount(int index) +{ + u32 ret; + + // only count if the counter is turned on (0x80) and is not an hsync gate (!0x03) + if (counters[index].mode.IsCounting && (counters[index].mode.ClockSource != 0x3)) + ret = counters[index].count + ((cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate); + else + ret = counters[index].count; + + EECNT_LOG("EE Counter[%d] readCount32 = %x\n", index, ret); + return ret; +} + +u32 __fastcall rcntCycle(int index) +{ + if (counters[index].mode.IsCounting && (counters[index].mode.ClockSource != 0x3)) + return counters[index].count + ((cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate); + else + return counters[index].count; +} + +void SaveState::rcntFreeze() +{ + Freeze(counters); + Freeze(nextCounter); + Freeze(nextsCounter); + + // New in version 11 -- save the PAL/NTSC info! + if( GetVersion() > 0x10 ) + { + Freeze( Config.PsxType ); + } + + if( IsLoading() ) + { + UpdateVSyncRate(); + + // make sure the gate flags are set based on the counter modes... + for( int i=0; i<4; i++ ) + _rcntSetGate( i ); + + iopBranchAction = 1; // probably not needed but won't hurt anything either. + } +} diff --git a/pcsx2/Counters.h b/pcsx2/Counters.h index c058fd6587..2b9b815d9c 100644 --- a/pcsx2/Counters.h +++ b/pcsx2/Counters.h @@ -1,148 +1,148 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __COUNTERS_H__ -#define __COUNTERS_H__ - -struct EECNT_MODE -{ - // 0 - BUSCLK - // 1 - 1/16th of BUSCLK - // 2 - 1/256th of BUSCLK - // 3 - External Clock (hblank!) - u32 ClockSource:2; - - // Enables the counter gate (turns counter on/off as according to the - // h/v blank type set in GateType). - u32 EnableGate:1; - - // 0 - hblank! 1 - vblank! - // Note: the hblank source type is disabled when ClockSel = 3 - u32 GateSource:1; - - // 0 - count when the gate signal is low - // 1 - reset and start counting at the signal's rising edge (h/v blank end) - // 2 - reset and start counting at the signal's falling edge (h/v blank start) - // 3 - reset and start counting at both signal edges - u32 GateMode:2; - - // Counter cleared to zero when target reached. - // The PS2 only resets if the TargetInterrupt is enabled - Tested on PS2 - u32 ZeroReturn:1; - - // General count enable/status. If 0, no counting happens. - // This flag is set/unset by the gates. - u32 IsCounting:1; - - // Enables target interrupts. - u32 TargetInterrupt:1; - - // Enables overflow interrupts. - u32 OverflowInterrupt:1; - - // Set to true by the counter when the target is reached. - // Flag is set only when TargetInterrupt is enabled. - u32 TargetReached:1; - - // Set to true by the counter when the target has overflowed. - // Flag is set only when OverflowInterrupt is enabled. - u32 OverflowReached:1; -}; - -// fixme: Cycle and sCycleT members are unused. -// But they can't be removed without making a new savestate version. -struct Counter { - u32 count; - union - { - u32 modeval; // the mode as a 32 bit int (for optimized combination masks) - EECNT_MODE mode; - }; - u32 target, hold; - u32 rate, interrupt; - u32 Cycle; - u32 sCycle; // start cycle of timer - s32 CycleT; - u32 sCycleT; // delta values should be signed. -}; - -//------------------------------------------------------------------ -// SPEED HACKS!!! (1 is normal) (They have inverse affects, only set 1 at a time) -//------------------------------------------------------------------ -#define HBLANK_COUNTER_SPEED 1 //Set to '3' to double the speed of games like KHII -//#define HBLANK_TIMER_SLOWDOWN 1 //Set to '2' to increase the speed of games like God of War (FPS will be less, but game will be faster) - -//------------------------------------------------------------------ -// NTSC Timing Information!!! (some scanline info is guessed) -//------------------------------------------------------------------ -#define FRAMERATE_NTSC 2997// frames per second * 100 (29.97) - -#define SCANLINES_TOTAL_NTSC 525 // total number of scanlines -#define SCANLINES_VSYNC_NTSC 3 // scanlines that are used for syncing every half-frame -#define SCANLINES_VRENDER_NTSC 240 // scanlines in a half-frame (because of interlacing) -#define SCANLINES_VBLANK1_NTSC 19 // scanlines used for vblank1 (even interlace) -#define SCANLINES_VBLANK2_NTSC 20 // scanlines used for vblank2 (odd interlace) - -#define HSYNC_ERROR_NTSC ((s32)VSYNC_NTSC - (s32)(((HRENDER_TIME_NTSC+HBLANK_TIME_NTSC) * SCANLINES_TOTAL_NTSC)/2) ) - -//------------------------------------------------------------------ -// PAL Timing Information!!! (some scanline info is guessed) -//------------------------------------------------------------------ -#define FRAMERATE_PAL 2500// frames per second * 100 (25) - -#define SCANLINES_TOTAL_PAL 625 // total number of scanlines per frame -#define SCANLINES_VSYNC_PAL 5 // scanlines that are used for syncing every half-frame -#define SCANLINES_VRENDER_PAL 288 // scanlines in a half-frame (because of interlacing) -#define SCANLINES_VBLANK1_PAL 19 // scanlines used for vblank1 (even interlace) -#define SCANLINES_VBLANK2_PAL 20 // scanlines used for vblank2 (odd interlace) - -//------------------------------------------------------------------ -// vSync and hBlank Timing Modes -//------------------------------------------------------------------ -#define MODE_VRENDER 0x0 //Set during the Render/Frame Scanlines -#define MODE_VBLANK 0x1 //Set during the Blanking Scanlines -#define MODE_VSYNC 0x3 //Set during the Syncing Scanlines -#define MODE_VBLANK1 0x0 //Set during the Blanking Scanlines (half-frame 1) -#define MODE_VBLANK2 0x1 //Set during the Blanking Scanlines (half-frame 2) - -#define MODE_HRENDER 0x0 //Set for ~5/6 of 1 Scanline -#define MODE_HBLANK 0x1 //Set for the remaining ~1/6 of 1 Scanline - - -extern Counter counters[6]; -extern s32 nextCounter; // delta until the next counter event (must be signed) -extern u32 nextsCounter; - -extern void rcntUpdate_hScanline(); -extern bool rcntUpdate_vSync(); -extern bool rcntUpdate(); - -extern void rcntInit(); -extern void __fastcall rcntStartGate(unsigned int mode, u32 sCycle); -extern void __fastcall rcntEndGate(unsigned int mode, u32 sCycle); -extern void __fastcall rcntWcount(int index, u32 value); -extern void __fastcall rcntWmode(int index, u32 value); -extern void __fastcall rcntWtarget(int index, u32 value); -extern void __fastcall rcntWhold(int index, u32 value); -extern u32 __fastcall rcntRcount(int index); -extern u32 __fastcall rcntCycle(int index); - -u32 UpdateVSyncRate(); -void frameLimitReset(); - -#endif /* __COUNTERS_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __COUNTERS_H__ +#define __COUNTERS_H__ + +struct EECNT_MODE +{ + // 0 - BUSCLK + // 1 - 1/16th of BUSCLK + // 2 - 1/256th of BUSCLK + // 3 - External Clock (hblank!) + u32 ClockSource:2; + + // Enables the counter gate (turns counter on/off as according to the + // h/v blank type set in GateType). + u32 EnableGate:1; + + // 0 - hblank! 1 - vblank! + // Note: the hblank source type is disabled when ClockSel = 3 + u32 GateSource:1; + + // 0 - count when the gate signal is low + // 1 - reset and start counting at the signal's rising edge (h/v blank end) + // 2 - reset and start counting at the signal's falling edge (h/v blank start) + // 3 - reset and start counting at both signal edges + u32 GateMode:2; + + // Counter cleared to zero when target reached. + // The PS2 only resets if the TargetInterrupt is enabled - Tested on PS2 + u32 ZeroReturn:1; + + // General count enable/status. If 0, no counting happens. + // This flag is set/unset by the gates. + u32 IsCounting:1; + + // Enables target interrupts. + u32 TargetInterrupt:1; + + // Enables overflow interrupts. + u32 OverflowInterrupt:1; + + // Set to true by the counter when the target is reached. + // Flag is set only when TargetInterrupt is enabled. + u32 TargetReached:1; + + // Set to true by the counter when the target has overflowed. + // Flag is set only when OverflowInterrupt is enabled. + u32 OverflowReached:1; +}; + +// fixme: Cycle and sCycleT members are unused. +// But they can't be removed without making a new savestate version. +struct Counter { + u32 count; + union + { + u32 modeval; // the mode as a 32 bit int (for optimized combination masks) + EECNT_MODE mode; + }; + u32 target, hold; + u32 rate, interrupt; + u32 Cycle; + u32 sCycle; // start cycle of timer + s32 CycleT; + u32 sCycleT; // delta values should be signed. +}; + +//------------------------------------------------------------------ +// SPEED HACKS!!! (1 is normal) (They have inverse affects, only set 1 at a time) +//------------------------------------------------------------------ +#define HBLANK_COUNTER_SPEED 1 //Set to '3' to double the speed of games like KHII +//#define HBLANK_TIMER_SLOWDOWN 1 //Set to '2' to increase the speed of games like God of War (FPS will be less, but game will be faster) + +//------------------------------------------------------------------ +// NTSC Timing Information!!! (some scanline info is guessed) +//------------------------------------------------------------------ +#define FRAMERATE_NTSC 2997// frames per second * 100 (29.97) + +#define SCANLINES_TOTAL_NTSC 525 // total number of scanlines +#define SCANLINES_VSYNC_NTSC 3 // scanlines that are used for syncing every half-frame +#define SCANLINES_VRENDER_NTSC 240 // scanlines in a half-frame (because of interlacing) +#define SCANLINES_VBLANK1_NTSC 19 // scanlines used for vblank1 (even interlace) +#define SCANLINES_VBLANK2_NTSC 20 // scanlines used for vblank2 (odd interlace) + +#define HSYNC_ERROR_NTSC ((s32)VSYNC_NTSC - (s32)(((HRENDER_TIME_NTSC+HBLANK_TIME_NTSC) * SCANLINES_TOTAL_NTSC)/2) ) + +//------------------------------------------------------------------ +// PAL Timing Information!!! (some scanline info is guessed) +//------------------------------------------------------------------ +#define FRAMERATE_PAL 2500// frames per second * 100 (25) + +#define SCANLINES_TOTAL_PAL 625 // total number of scanlines per frame +#define SCANLINES_VSYNC_PAL 5 // scanlines that are used for syncing every half-frame +#define SCANLINES_VRENDER_PAL 288 // scanlines in a half-frame (because of interlacing) +#define SCANLINES_VBLANK1_PAL 19 // scanlines used for vblank1 (even interlace) +#define SCANLINES_VBLANK2_PAL 20 // scanlines used for vblank2 (odd interlace) + +//------------------------------------------------------------------ +// vSync and hBlank Timing Modes +//------------------------------------------------------------------ +#define MODE_VRENDER 0x0 //Set during the Render/Frame Scanlines +#define MODE_VBLANK 0x1 //Set during the Blanking Scanlines +#define MODE_VSYNC 0x3 //Set during the Syncing Scanlines +#define MODE_VBLANK1 0x0 //Set during the Blanking Scanlines (half-frame 1) +#define MODE_VBLANK2 0x1 //Set during the Blanking Scanlines (half-frame 2) + +#define MODE_HRENDER 0x0 //Set for ~5/6 of 1 Scanline +#define MODE_HBLANK 0x1 //Set for the remaining ~1/6 of 1 Scanline + + +extern Counter counters[6]; +extern s32 nextCounter; // delta until the next counter event (must be signed) +extern u32 nextsCounter; + +extern void rcntUpdate_hScanline(); +extern bool rcntUpdate_vSync(); +extern bool rcntUpdate(); + +extern void rcntInit(); +extern void __fastcall rcntStartGate(unsigned int mode, u32 sCycle); +extern void __fastcall rcntEndGate(unsigned int mode, u32 sCycle); +extern void __fastcall rcntWcount(int index, u32 value); +extern void __fastcall rcntWmode(int index, u32 value); +extern void __fastcall rcntWtarget(int index, u32 value); +extern void __fastcall rcntWhold(int index, u32 value); +extern u32 __fastcall rcntRcount(int index); +extern u32 __fastcall rcntCycle(int index); + +u32 UpdateVSyncRate(); +void frameLimitReset(); + +#endif /* __COUNTERS_H__ */ diff --git a/pcsx2/DebugTools/Debug.h b/pcsx2/DebugTools/Debug.h index 5e0c0d03e7..188e2f017c 100644 --- a/pcsx2/DebugTools/Debug.h +++ b/pcsx2/DebugTools/Debug.h @@ -1,197 +1,197 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - - -#ifndef __DEBUG_H__ -#define __DEBUG_H__ - -#include "Misc.h" - -extern FILE *emuLog; - -extern char* disVU0MicroUF(u32 code, u32 pc); -extern char* disVU0MicroLF(u32 code, u32 pc); -extern char* disVU1MicroUF(u32 code, u32 pc); -extern char* disVU1MicroLF(u32 code, u32 pc); - -extern const char * const CP2VFnames[]; -extern const char * const disRNameCP2f[]; -extern const char * const disRNameCP2i[]; - -namespace R5900 -{ - // [TODO] : These function names can be de-obfuscated with the help of a little namespace love. - - void disR5900F( std::string& output, u32 code ); - void disR5900Fasm( std::string& output, u32 code, u32 pc); - void disR5900AddSym(u32 addr, const char *name); - const char* disR5900GetSym(u32 addr); - const char* disR5900GetUpperSym(u32 addr); - void disR5900FreeSyms(); - void dFindSym( std::string& output, u32 addr ); - - extern const char * const disRNameGPR[]; - - // A helper class for getting a quick and efficient string representation of the - // R5900's current instruction. This class is *not* thread safe! - class DisR5900CurrentState - { - protected: - std::string result; - - public: - const std::string& getString(); - const char* getCString(); - }; - - extern DisR5900CurrentState disR5900Current; -} - -namespace R3000A -{ - extern void (*IOP_DEBUG_BSC[64])(char *buf); - - extern const char * const disRNameGPR[]; - extern char* disR3000Fasm(u32 code, u32 pc); - extern char* disR3000AF(u32 code, u32 pc); -} - -#ifdef PCSX2_DEVBUILD - -extern u32 varLog; - -void SourceLog( u16 protocol, u8 source, u32 cpuPc, u32 cpuCycle, const char *fmt, ...); -void __Log( const char* fmt, ... ); - -extern void SrcLog_CPU( const char* fmt, ... ); -extern void SrcLog_COP0( const char* fmt, ... ); -extern void SrcLog_FPU( const char* fmt, ... ); -extern void SrcLog_MMI( const char* fmt, ... ); - -extern void SrcLog_MEM( const char* fmt, ... ); -extern void SrcLog_HW( const char* fmt, ... ); -extern void SrcLog_DMA( const char* fmt, ... ); -extern void SrcLog_BIOS( const char* fmt, ... ); -extern void SrcLog_ELF( const char* fmt, ... ); -extern void SrcLog_VU0( const char* fmt, ... ); - -extern void SrcLog_VIF( const char* fmt, ... ); -extern void SrcLog_SPR( const char* fmt, ... ); -extern void SrcLog_GIF( const char* fmt, ... ); -extern void SrcLog_SIF( const char* fmt, ... ); -extern void SrcLog_IPU( const char* fmt, ... ); -extern void SrcLog_VUM( const char* fmt, ... ); -extern void SrcLog_RPC( const char* fmt, ... ); -extern void SrcLog_EECNT( const char* fmt, ... ); - -extern void SrcLog_PSXCPU( const char* fmt, ... ); -extern void SrcLog_PSXMEM( const char* fmt, ... ); -extern void SrcLog_PSXHW( const char* fmt, ... ); -extern void SrcLog_PSXBIOS( const char* fmt, ... ); -extern void SrcLog_PSXDMA( const char* fmt, ... ); -extern void SrcLog_PSXCNT( const char* fmt, ... ); - -extern void SrcLog_MEMCARDS( const char* fmt, ... ); -extern void SrcLog_PAD( const char* fmt, ... ); -extern void SrcLog_GTE( const char* fmt, ... ); -extern void SrcLog_CDR( const char* fmt, ... ); -extern void SrcLog_GPU( const char* fmt, ... ); - -#define CPU_LOG if (varLog & 0x00000001) SrcLog_CPU -#define MEM_LOG if (varLog & 0x00000002) SrcLog_MEM -#define HW_LOG if (varLog & 0x00000004) SrcLog_HW -#define DMA_LOG if (varLog & 0x00000008) SrcLog_DMA -#define BIOS_LOG if (varLog & 0x00000010) SrcLog_BIOS -#define ELF_LOG if (varLog & 0x00000020) SrcLog_ELF -#define FPU_LOG if (varLog & 0x00000040) SrcLog_FPU -#define MMI_LOG if (varLog & 0x00000080) SrcLog_MMI -#define VU0_LOG if (varLog & 0x00000100) SrcLog_VU0 -#define COP0_LOG if (varLog & 0x00000200) SrcLog_COP0 -#define VIF_LOG if (varLog & 0x00000400) SrcLog_VIF -#define SPR_LOG if (varLog & 0x00000800) SrcLog_SPR -#define GIF_LOG if (varLog & 0x00001000) SrcLog_GIF -#define SIF_LOG if (varLog & 0x00002000) SrcLog_SIF -#define IPU_LOG if (varLog & 0x00004000) SrcLog_IPU -#define VUM_LOG if (varLog & 0x00008000) SrcLog_VUM -#define RPC_LOG if (varLog & 0x00010000) SrcLog_RPC -#define EECNT_LOG if (varLog & 0x40000000) SrcLog_EECNT - -#define PSXCPU_LOG if (varLog & 0x00100000) SrcLog_PSXCPU -#define PSXMEM_LOG if (varLog & 0x00200000) SrcLog_PSXMEM -#define PSXHW_LOG if (varLog & 0x00400000) SrcLog_PSXHW -#define PSXBIOS_LOG if (varLog & 0x00800000) SrcLog_PSXBIOS -#define PSXDMA_LOG if (varLog & 0x01000000) SrcLog_PSXDMA -#define PSXCNT_LOG if (varLog & 0x20000000) SrcLog_PSXCNT - -//memcard has the same number as PAD_LOG for now -#define MEMCARDS_LOG if (varLog & 0x02000000) SrcLog_MEMCARDS -#define PAD_LOG if (varLog & 0x02000000) SrcLog_PAD -#define GTE_LOG if (varLog & 0x04000000) SrcLog_GTE -#define CDR_LOG if (varLog & 0x08000000) SrcLog_CDR -#define GPU_LOG if (varLog & 0x10000000) SrcLog_GPU - -// fixme - currently we don't log cache -#define CACHE_LOG 0&& - -#else // PCSX2_DEVBUILD - -#define varLog 0 - -#define CPU_LOG 0&& -#define MEM_LOG 0&& -#define HW_LOG 0&& -#define DMA_LOG 0&& -#define BIOS_LOG 0&& -#define ELF_LOG 0&& -#define FPU_LOG 0&& -#define MMI_LOG 0&& -#define VU0_LOG 0&& -#define COP0_LOG 0&& -#define VIF_LOG 0&& -#define SPR_LOG 0&& -#define GIF_LOG 0&& -#define SIF_LOG 0&& -#define IPU_LOG 0&& -#define VUM_LOG 0&& -#define RPC_LOG 0&& - -#define PSXCPU_LOG 0&& -#define PSXMEM_LOG 0&& -#define PSXHW_LOG 0&& -#define PSXBIOS_LOG 0&& -#define PSXDMA_LOG 0&& - -#define PAD_LOG 0&& -#define GTE_LOG 0&& -#define CDR_LOG 0&& -#define GPU_LOG 0&& -#define PSXCNT_LOG 0&& -#define EECNT_LOG 0&& - -#define EMU_LOG 0&& -#define CACHE_LOG 0&& -#define MEMCARDS_LOG 0&& -#endif - -#ifdef VIFUNPACKDEBUG -#define VIFUNPACK_LOG VIF_LOG -#else -#define VIFUNPACK_LOG 0&& -#endif - -#endif /* __DEBUG_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + + +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#include "Misc.h" + +extern FILE *emuLog; + +extern char* disVU0MicroUF(u32 code, u32 pc); +extern char* disVU0MicroLF(u32 code, u32 pc); +extern char* disVU1MicroUF(u32 code, u32 pc); +extern char* disVU1MicroLF(u32 code, u32 pc); + +extern const char * const CP2VFnames[]; +extern const char * const disRNameCP2f[]; +extern const char * const disRNameCP2i[]; + +namespace R5900 +{ + // [TODO] : These function names can be de-obfuscated with the help of a little namespace love. + + void disR5900F( std::string& output, u32 code ); + void disR5900Fasm( std::string& output, u32 code, u32 pc); + void disR5900AddSym(u32 addr, const char *name); + const char* disR5900GetSym(u32 addr); + const char* disR5900GetUpperSym(u32 addr); + void disR5900FreeSyms(); + void dFindSym( std::string& output, u32 addr ); + + extern const char * const disRNameGPR[]; + + // A helper class for getting a quick and efficient string representation of the + // R5900's current instruction. This class is *not* thread safe! + class DisR5900CurrentState + { + protected: + std::string result; + + public: + const std::string& getString(); + const char* getCString(); + }; + + extern DisR5900CurrentState disR5900Current; +} + +namespace R3000A +{ + extern void (*IOP_DEBUG_BSC[64])(char *buf); + + extern const char * const disRNameGPR[]; + extern char* disR3000Fasm(u32 code, u32 pc); + extern char* disR3000AF(u32 code, u32 pc); +} + +#ifdef PCSX2_DEVBUILD + +extern u32 varLog; + +void SourceLog( u16 protocol, u8 source, u32 cpuPc, u32 cpuCycle, const char *fmt, ...); +void __Log( const char* fmt, ... ); + +extern void SrcLog_CPU( const char* fmt, ... ); +extern void SrcLog_COP0( const char* fmt, ... ); +extern void SrcLog_FPU( const char* fmt, ... ); +extern void SrcLog_MMI( const char* fmt, ... ); + +extern void SrcLog_MEM( const char* fmt, ... ); +extern void SrcLog_HW( const char* fmt, ... ); +extern void SrcLog_DMA( const char* fmt, ... ); +extern void SrcLog_BIOS( const char* fmt, ... ); +extern void SrcLog_ELF( const char* fmt, ... ); +extern void SrcLog_VU0( const char* fmt, ... ); + +extern void SrcLog_VIF( const char* fmt, ... ); +extern void SrcLog_SPR( const char* fmt, ... ); +extern void SrcLog_GIF( const char* fmt, ... ); +extern void SrcLog_SIF( const char* fmt, ... ); +extern void SrcLog_IPU( const char* fmt, ... ); +extern void SrcLog_VUM( const char* fmt, ... ); +extern void SrcLog_RPC( const char* fmt, ... ); +extern void SrcLog_EECNT( const char* fmt, ... ); + +extern void SrcLog_PSXCPU( const char* fmt, ... ); +extern void SrcLog_PSXMEM( const char* fmt, ... ); +extern void SrcLog_PSXHW( const char* fmt, ... ); +extern void SrcLog_PSXBIOS( const char* fmt, ... ); +extern void SrcLog_PSXDMA( const char* fmt, ... ); +extern void SrcLog_PSXCNT( const char* fmt, ... ); + +extern void SrcLog_MEMCARDS( const char* fmt, ... ); +extern void SrcLog_PAD( const char* fmt, ... ); +extern void SrcLog_GTE( const char* fmt, ... ); +extern void SrcLog_CDR( const char* fmt, ... ); +extern void SrcLog_GPU( const char* fmt, ... ); + +#define CPU_LOG if (varLog & 0x00000001) SrcLog_CPU +#define MEM_LOG if (varLog & 0x00000002) SrcLog_MEM +#define HW_LOG if (varLog & 0x00000004) SrcLog_HW +#define DMA_LOG if (varLog & 0x00000008) SrcLog_DMA +#define BIOS_LOG if (varLog & 0x00000010) SrcLog_BIOS +#define ELF_LOG if (varLog & 0x00000020) SrcLog_ELF +#define FPU_LOG if (varLog & 0x00000040) SrcLog_FPU +#define MMI_LOG if (varLog & 0x00000080) SrcLog_MMI +#define VU0_LOG if (varLog & 0x00000100) SrcLog_VU0 +#define COP0_LOG if (varLog & 0x00000200) SrcLog_COP0 +#define VIF_LOG if (varLog & 0x00000400) SrcLog_VIF +#define SPR_LOG if (varLog & 0x00000800) SrcLog_SPR +#define GIF_LOG if (varLog & 0x00001000) SrcLog_GIF +#define SIF_LOG if (varLog & 0x00002000) SrcLog_SIF +#define IPU_LOG if (varLog & 0x00004000) SrcLog_IPU +#define VUM_LOG if (varLog & 0x00008000) SrcLog_VUM +#define RPC_LOG if (varLog & 0x00010000) SrcLog_RPC +#define EECNT_LOG if (varLog & 0x40000000) SrcLog_EECNT + +#define PSXCPU_LOG if (varLog & 0x00100000) SrcLog_PSXCPU +#define PSXMEM_LOG if (varLog & 0x00200000) SrcLog_PSXMEM +#define PSXHW_LOG if (varLog & 0x00400000) SrcLog_PSXHW +#define PSXBIOS_LOG if (varLog & 0x00800000) SrcLog_PSXBIOS +#define PSXDMA_LOG if (varLog & 0x01000000) SrcLog_PSXDMA +#define PSXCNT_LOG if (varLog & 0x20000000) SrcLog_PSXCNT + +//memcard has the same number as PAD_LOG for now +#define MEMCARDS_LOG if (varLog & 0x02000000) SrcLog_MEMCARDS +#define PAD_LOG if (varLog & 0x02000000) SrcLog_PAD +#define GTE_LOG if (varLog & 0x04000000) SrcLog_GTE +#define CDR_LOG if (varLog & 0x08000000) SrcLog_CDR +#define GPU_LOG if (varLog & 0x10000000) SrcLog_GPU + +// fixme - currently we don't log cache +#define CACHE_LOG 0&& + +#else // PCSX2_DEVBUILD + +#define varLog 0 + +#define CPU_LOG 0&& +#define MEM_LOG 0&& +#define HW_LOG 0&& +#define DMA_LOG 0&& +#define BIOS_LOG 0&& +#define ELF_LOG 0&& +#define FPU_LOG 0&& +#define MMI_LOG 0&& +#define VU0_LOG 0&& +#define COP0_LOG 0&& +#define VIF_LOG 0&& +#define SPR_LOG 0&& +#define GIF_LOG 0&& +#define SIF_LOG 0&& +#define IPU_LOG 0&& +#define VUM_LOG 0&& +#define RPC_LOG 0&& + +#define PSXCPU_LOG 0&& +#define PSXMEM_LOG 0&& +#define PSXHW_LOG 0&& +#define PSXBIOS_LOG 0&& +#define PSXDMA_LOG 0&& + +#define PAD_LOG 0&& +#define GTE_LOG 0&& +#define CDR_LOG 0&& +#define GPU_LOG 0&& +#define PSXCNT_LOG 0&& +#define EECNT_LOG 0&& + +#define EMU_LOG 0&& +#define CACHE_LOG 0&& +#define MEMCARDS_LOG 0&& +#endif + +#ifdef VIFUNPACKDEBUG +#define VIFUNPACK_LOG VIF_LOG +#else +#define VIFUNPACK_LOG 0&& +#endif + +#endif /* __DEBUG_H__ */ diff --git a/pcsx2/DebugTools/DisASM.h b/pcsx2/DebugTools/DisASM.h index 1147df12a7..a5e5bd1204 100644 --- a/pcsx2/DebugTools/DisASM.h +++ b/pcsx2/DebugTools/DisASM.h @@ -1,52 +1,52 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 -#include - -//DECODE PROCUDURES - -//cop0 -#define DECODE_FS (DECODE_RD) -#define DECODE_FT (DECODE_RT) -#define DECODE_FD (DECODE_SA) -///******** - -#define DECODE_FUNCTION ((cpuRegs.code) & 0x3F) -#define DECODE_RD ((cpuRegs.code >> 11) & 0x1F) // The rd part of the instruction register -#define DECODE_RT ((cpuRegs.code >> 16) & 0x1F) // The rt part of the instruction register -#define DECODE_RS ((cpuRegs.code >> 21) & 0x1F) // The rs part of the instruction register -#define DECODE_SA ((cpuRegs.code >> 6) & 0x1F) // The sa part of the instruction register -#define DECODE_IMMED ( cpuRegs.code & 0xFFFF) // The immediate part of the instruction register -#define DECODE_OFFSET ((((short)DECODE_IMMED * 4) + opcode_addr + 4)) -#define DECODE_JUMP (opcode_addr & 0xf0000000)|((cpuRegs.code&0x3ffffff)<<2) -#define DECODE_SYSCALL ((opcode_addr & 0x03FFFFFF) >> 6) -#define DECODE_BREAK (DECODE_SYSCALL) -#define DECODE_C0BC ((cpuRegs.code >> 16) & 0x03) -#define DECODE_C1BC ((cpuRegs.code >> 16) & 0x03) -#define DECODE_C2BC ((cpuRegs.code >> 16) & 0x03) - -//IOP - -#define DECODE_RD_IOP ((psxRegs.code >> 11) & 0x1F) -#define DECODE_RT_IOP ((psxRegs.code >> 16) & 0x1F) -#define DECODE_RS_IOP ((psxRegs.code >> 21) & 0x1F) -#define DECODE_IMMED_IOP ( psxRegs.code & 0xFFFF) -#define DECODE_SA_IOP ((psxRegs.code >> 6) & 0x1F) -#define DECODE_FS_IOP (DECODE_RD_IOP) - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 +#include + +//DECODE PROCUDURES + +//cop0 +#define DECODE_FS (DECODE_RD) +#define DECODE_FT (DECODE_RT) +#define DECODE_FD (DECODE_SA) +///******** + +#define DECODE_FUNCTION ((cpuRegs.code) & 0x3F) +#define DECODE_RD ((cpuRegs.code >> 11) & 0x1F) // The rd part of the instruction register +#define DECODE_RT ((cpuRegs.code >> 16) & 0x1F) // The rt part of the instruction register +#define DECODE_RS ((cpuRegs.code >> 21) & 0x1F) // The rs part of the instruction register +#define DECODE_SA ((cpuRegs.code >> 6) & 0x1F) // The sa part of the instruction register +#define DECODE_IMMED ( cpuRegs.code & 0xFFFF) // The immediate part of the instruction register +#define DECODE_OFFSET ((((short)DECODE_IMMED * 4) + opcode_addr + 4)) +#define DECODE_JUMP (opcode_addr & 0xf0000000)|((cpuRegs.code&0x3ffffff)<<2) +#define DECODE_SYSCALL ((opcode_addr & 0x03FFFFFF) >> 6) +#define DECODE_BREAK (DECODE_SYSCALL) +#define DECODE_C0BC ((cpuRegs.code >> 16) & 0x03) +#define DECODE_C1BC ((cpuRegs.code >> 16) & 0x03) +#define DECODE_C2BC ((cpuRegs.code >> 16) & 0x03) + +//IOP + +#define DECODE_RD_IOP ((psxRegs.code >> 11) & 0x1F) +#define DECODE_RT_IOP ((psxRegs.code >> 16) & 0x1F) +#define DECODE_RS_IOP ((psxRegs.code >> 21) & 0x1F) +#define DECODE_IMMED_IOP ( psxRegs.code & 0xFFFF) +#define DECODE_SA_IOP ((psxRegs.code >> 6) & 0x1F) +#define DECODE_FS_IOP (DECODE_RD_IOP) + diff --git a/pcsx2/DebugTools/DisR3000A.cpp b/pcsx2/DebugTools/DisR3000A.cpp index 3bd08d9de2..b122021b8f 100644 --- a/pcsx2/DebugTools/DisR3000A.cpp +++ b/pcsx2/DebugTools/DisR3000A.cpp @@ -1,322 +1,322 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "R3000A.h" -#include "Debug.h" - -namespace R3000A -{ - static char ostr[1024]; - -// Names of registers - const char * const disRNameGPR[] = { - "r0", "at", "v0", "v1", "a0", "a1","a2", "a3", - "t0", "t1", "t2", "t3", "t4", "t5","t6", "t7", - "s0", "s1", "s2", "s3", "s4", "s5","s6", "s7", - "t8", "t9", "k0", "k1", "gp", "sp","fp", "ra"}; - - const char * const disRNameCP0[] = { - "Index" , "Random" , "EntryLo0", "EntryLo1", "Context" , "PageMask" , "Wired" , "*Check me*", - "BadVAddr" , "Count" , "EntryHi" , "Compare" , "Status" , "Cause" , "ExceptPC" , "PRevID" , - "Config" , "LLAddr" , "WatchLo" , "WatchHi" , "XContext", "*RES*" , "*RES*" , "*RES*" , - "*RES*" , "*RES* " , "PErr" , "CacheErr", "TagLo" , "TagHi" , "ErrorEPC" , "*RES*" }; - -// Type definition of our functions - -typedef char* (*TdisR3000AF)(u32 code, u32 pc); - -// These macros are used to assemble the disassembler functions -#define MakeDisFg(fn, b) char* fn(u32 code, u32 pc) { b; return ostr; } -#define MakeDisF(fn, b) \ - static char* fn(u32 code, u32 pc) { \ - sprintf (ostr, "%8.8lx %8.8lx:", pc, code); \ - b; /*ostr[(strlen(ostr) - 1)] = 0;*/ return ostr; \ - } - - -#undef _Funct_ -#undef _Rd_ -#undef _Rt_ -#undef _Rs_ -#undef _Sa_ -#undef _Im_ -#undef _Target_ - -#define _Funct_ ((code ) & 0x3F) // The funct part of the instruction register -#define _Rd_ ((code >> 11) & 0x1F) // The rd part of the instruction register -#define _Rt_ ((code >> 16) & 0x1F) // The rt part of the instruction register -#define _Rs_ ((code >> 21) & 0x1F) // The rs part of the instruction register -#define _Sa_ ((code >> 6) & 0x1F) // The sa part of the instruction register -#define _Im_ ( code & 0xFFFF) // The immediate part of the instruction register - -#define _Target_ ((pc & 0xf0000000) + ((code & 0x03ffffff) * 4)) -#define _Branch_ (pc + 4 + ((short)_Im_ * 4)) -#define _OfB_ _Im_, _nRs_ - -#define dName(i) sprintf(ostr, "%s %-7s,", ostr, i) -#define dGPR(i) sprintf(ostr, "%s %8.8lx (%s),", ostr, psxRegs.GPR.r[i], disRNameGPR[i]) -#define dCP0(i) sprintf(ostr, "%s %8.8lx (%s),", ostr, psxRegs.CP0.r[i], disRNameCP0[i]) -#define dHI() sprintf(ostr, "%s %8.8lx (%s),", ostr, psxRegs.GPR.n.hi, "hi") -#define dLO() sprintf(ostr, "%s %8.8lx (%s),", ostr, psxRegs.GPR.n.lo, "lo") -#define dImm() sprintf(ostr, "%s %4.4lx (%ld),", ostr, _Im_, _Im_) -#define dTarget() sprintf(ostr, "%s %8.8lx,", ostr, _Target_) -#define dSa() sprintf(ostr, "%s %2.2lx (%ld),", ostr, _Sa_, _Sa_) -#define dOfB() sprintf(ostr, "%s %4.4lx (%8.8lx (%s)),", ostr, _Im_, psxRegs.GPR.r[_Rs_], disRNameGPR[_Rs_]) -#define dOffset() sprintf(ostr, "%s %8.8lx,", ostr, _Branch_) -#define dCode() sprintf(ostr, "%s %8.8lx,", ostr, (code >> 6) & 0xffffff) - -/********************************************************* -* Arithmetic with immediate operand * -* Format: OP rt, rs, immediate * -*********************************************************/ -MakeDisF(disADDI, dName("ADDI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) -MakeDisF(disADDIU, dName("ADDIU"); dGPR(_Rt_); dGPR(_Rs_); dImm();) -MakeDisF(disANDI, dName("ANDI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) -MakeDisF(disORI, dName("ORI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) -MakeDisF(disSLTI, dName("SLTI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) -MakeDisF(disSLTIU, dName("SLTIU"); dGPR(_Rt_); dGPR(_Rs_); dImm();) -MakeDisF(disXORI, dName("XORI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) - -/********************************************************* -* Register arithmetic * -* Format: OP rd, rs, rt * -*********************************************************/ -MakeDisF(disADD, dName("ADD"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) -MakeDisF(disADDU, dName("ADDU"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) -MakeDisF(disAND, dName("AND"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) -MakeDisF(disNOR, dName("NOR"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) -MakeDisF(disOR, dName("OR"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) -MakeDisF(disSLT, dName("SLT"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) -MakeDisF(disSLTU, dName("SLTU"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) -MakeDisF(disSUB, dName("SUB"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) -MakeDisF(disSUBU, dName("SUBU"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) -MakeDisF(disXOR, dName("XOR"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) - -/********************************************************* -* Register arithmetic & Register trap logic * -* Format: OP rs, rt * -*********************************************************/ -MakeDisF(disDIV, dName("DIV"); dGPR(_Rs_); dGPR(_Rt_);) -MakeDisF(disDIVU, dName("DIVU"); dGPR(_Rs_); dGPR(_Rt_);) -MakeDisF(disMULT, dName("MULT"); dGPR(_Rs_); dGPR(_Rt_);) -MakeDisF(disMULTU, dName("MULTU"); dGPR(_Rs_); dGPR(_Rt_);) - -/********************************************************* -* Register branch logic * -* Format: OP rs, offset * -*********************************************************/ -MakeDisF(disBGEZ, dName("BGEZ"); dGPR(_Rs_); dOffset();) -MakeDisF(disBGEZAL, dName("BGEZAL"); dGPR(_Rs_); dOffset();) -MakeDisF(disBGTZ, dName("BGTZ"); dGPR(_Rs_); dOffset();) -MakeDisF(disBLEZ, dName("BLEZ"); dGPR(_Rs_); dOffset();) -MakeDisF(disBLTZ, dName("BLTZ"); dGPR(_Rs_); dOffset();) -MakeDisF(disBLTZAL, dName("BLTZAL"); dGPR(_Rs_); dOffset();) - -/********************************************************* -* Shift arithmetic with constant shift * -* Format: OP rd, rt, sa * -*********************************************************/ -MakeDisF(disSLL, if (code) { dName("SLL"); dGPR(_Rd_); dGPR(_Rt_); dSa(); } else { dName("NOP"); }) -MakeDisF(disSRA, dName("SRA"); dGPR(_Rd_); dGPR(_Rt_); dSa();) -MakeDisF(disSRL, dName("SRL"); dGPR(_Rd_); dGPR(_Rt_); dSa();) - -/********************************************************* -* Shift arithmetic with variant register shift * -* Format: OP rd, rt, rs * -*********************************************************/ -MakeDisF(disSLLV, dName("SLLV"); dGPR(_Rd_); dGPR(_Rt_); dGPR(_Rs_);) -MakeDisF(disSRAV, dName("SRAV"); dGPR(_Rd_); dGPR(_Rt_); dGPR(_Rs_);) -MakeDisF(disSRLV, dName("SRLV"); dGPR(_Rd_); dGPR(_Rt_); dGPR(_Rs_);) - -/********************************************************* -* Load higher 16 bits of the first word in GPR with imm * -* Format: OP rt, immediate * -*********************************************************/ -MakeDisF(disLUI, dName("LUI"); dGPR(_Rt_); dImm();) - -/********************************************************* -* Move from HI/LO to GPR * -* Format: OP rd * -*********************************************************/ -MakeDisF(disMFHI, dName("MFHI"); dGPR(_Rd_); dHI();) -MakeDisF(disMFLO, dName("MFLO"); dGPR(_Rd_); dLO();) - -/********************************************************* -* Move from GPR to HI/LO * -* Format: OP rd * -*********************************************************/ -MakeDisF(disMTHI, dName("MTHI"); dHI(); dGPR(_Rs_);) -MakeDisF(disMTLO, dName("MTLO"); dLO(); dGPR(_Rs_);) - -/********************************************************* -* Special purpose instructions * -* Format: OP * -*********************************************************/ -MakeDisF(disBREAK, dName("BREAK")) -MakeDisF(disRFE, dName("RFE")) -MakeDisF(disSYSCALL, dName("SYSCALL")) - - - -MakeDisF(disRTPS, dName("RTPS")) -MakeDisF(disOP , dName("OP")) -MakeDisF(disNCLIP, dName("NCLIP")) -MakeDisF(disDPCS, dName("DPCS")) -MakeDisF(disINTPL, dName("INTPL")) -MakeDisF(disMVMVA, dName("MVMVA")) -MakeDisF(disNCDS , dName("NCDS")) -MakeDisF(disCDP , dName("CDP")) -MakeDisF(disNCDT , dName("NCDT")) -MakeDisF(disNCCS , dName("NCCS")) -MakeDisF(disCC , dName("CC")) -MakeDisF(disNCS , dName("NCS")) -MakeDisF(disNCT , dName("NCT")) -MakeDisF(disSQR , dName("SQR")) -MakeDisF(disDCPL , dName("DCPL")) -MakeDisF(disDPCT , dName("DPCT")) -MakeDisF(disAVSZ3, dName("AVSZ3")) -MakeDisF(disAVSZ4, dName("AVSZ4")) -MakeDisF(disRTPT , dName("RTPT")) -MakeDisF(disGPF , dName("GPF")) -MakeDisF(disGPL , dName("GPL")) -MakeDisF(disNCCT , dName("NCCT")) - -MakeDisF(disMFC2, dName("MFC2"); dGPR(_Rt_);) -MakeDisF(disCFC2, dName("CFC2"); dGPR(_Rt_);) -MakeDisF(disMTC2, dName("MTC2")) -MakeDisF(disCTC2, dName("CTC2")) - -/********************************************************* -* Register branch logic * -* Format: OP rs, rt, offset * -*********************************************************/ -MakeDisF(disBEQ, dName("BEQ"); dGPR(_Rs_); dGPR(_Rt_); dOffset();) -MakeDisF(disBNE, dName("BNE"); dGPR(_Rs_); dGPR(_Rt_); dOffset();) - -/********************************************************* -* Jump to target * -* Format: OP target * -*********************************************************/ -MakeDisF(disJ, dName("J"); dTarget();) -MakeDisF(disJAL, dName("JAL"); dTarget(); dGPR(31);) - -/********************************************************* -* Register jump * -* Format: OP rs, rd * -*********************************************************/ -MakeDisF(disJR, dName("JR"); dGPR(_Rs_);) -MakeDisF(disJALR, dName("JALR"); dGPR(_Rs_); dGPR(_Rd_)) - -/********************************************************* -* Load and store for GPR * -* Format: OP rt, offset(base) * -*********************************************************/ -MakeDisF(disLB, dName("LB"); dGPR(_Rt_); dOfB();) -MakeDisF(disLBU, dName("LBU"); dGPR(_Rt_); dOfB();) -MakeDisF(disLH, dName("LH"); dGPR(_Rt_); dOfB();) -MakeDisF(disLHU, dName("LHU"); dGPR(_Rt_); dOfB();) -MakeDisF(disLW, dName("LW"); dGPR(_Rt_); dOfB();) -MakeDisF(disLWL, dName("LWL"); dGPR(_Rt_); dOfB();) -MakeDisF(disLWR, dName("LWR"); dGPR(_Rt_); dOfB();) -MakeDisF(disLWC2, dName("LWC2"); dGPR(_Rt_); dOfB();) -MakeDisF(disSB, dName("SB"); dGPR(_Rt_); dOfB();) -MakeDisF(disSH, dName("SH"); dGPR(_Rt_); dOfB();) -MakeDisF(disSW, dName("SW"); dGPR(_Rt_); dOfB();) -MakeDisF(disSWL, dName("SWL"); dGPR(_Rt_); dOfB();) -MakeDisF(disSWR, dName("SWR"); dGPR(_Rt_); dOfB();) -MakeDisF(disSWC2, dName("SWC2"); dGPR(_Rt_); dOfB();) - -/********************************************************* -* Moves between GPR and COPx * -* Format: OP rt, fs * -*********************************************************/ -MakeDisF(disMFC0, dName("MFC0"); dGPR(_Rt_); dCP0(_Rd_);) -MakeDisF(disMTC0, dName("MTC0"); dCP0(_Rd_); dGPR(_Rt_);) -MakeDisF(disCFC0, dName("CFC0"); dGPR(_Rt_); dCP0(_Rd_);) -MakeDisF(disCTC0, dName("CTC0"); dCP0(_Rd_); dGPR(_Rt_);) - -/********************************************************* -* Unknow instruction (would generate an exception) * -* Format: ? * -*********************************************************/ -MakeDisF(disNULL, dName("*** Bad OP ***");) - - -TdisR3000AF disR3000A_SPECIAL[] = { // Subset of disSPECIAL - disSLL , disNULL , disSRL , disSRA , disSLLV , disNULL , disSRLV , disSRAV , - disJR , disJALR , disNULL, disNULL, disSYSCALL, disBREAK , disNULL , disNULL , - disMFHI, disMTHI , disMFLO, disMTLO, disNULL , disNULL , disNULL , disNULL , - disMULT, disMULTU, disDIV , disDIVU, disNULL , disNULL , disNULL , disNULL , - disADD , disADDU , disSUB , disSUBU, disAND , disOR , disXOR , disNOR , - disNULL, disNULL , disSLT , disSLTU, disNULL , disNULL , disNULL , disNULL , - disNULL, disNULL , disNULL, disNULL, disNULL , disNULL , disNULL , disNULL , - disNULL, disNULL , disNULL, disNULL, disNULL , disNULL , disNULL , disNULL}; - -MakeDisF(disSPECIAL, disR3000A_SPECIAL[_Funct_](code, pc)) - -TdisR3000AF disR3000A_BCOND[] = { // Subset of disBCOND - disBLTZ , disBGEZ , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disBLTZAL, disBGEZAL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; - -MakeDisF(disBCOND, disR3000A_BCOND[_Rt_](code, pc)) - -TdisR3000AF disR3000A_COP0[] = { // Subset of disCOP0 - disMFC0, disNULL, disCFC0, disNULL, disMTC0, disNULL, disCTC0, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disRFE , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; - -MakeDisF(disCOP0, disR3000A_COP0[_Rs_](code, pc)) - -TdisR3000AF disR3000A_BASIC[] = { // Subset of disBASIC (based on rs) - disMFC2, disNULL, disCFC2, disNULL, disMTC2, disNULL, disCTC2, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; - -MakeDisF(disBASIC, disR3000A_BASIC[_Rs_](code, pc)) - -TdisR3000AF disR3000A_COP2[] = { // Subset of disR3000F_COP2 (based on funct) - disBASIC, disRTPS , disNULL , disNULL , disNULL, disNULL , disNCLIP, disNULL, - disNULL , disNULL , disNULL , disNULL , disOP , disNULL , disNULL , disNULL, - disDPCS , disINTPL, disMVMVA, disNCDS , disCDP , disNULL , disNCDT , disNULL, - disNULL , disNULL , disNULL , disNCCS , disCC , disNULL , disNCS , disNULL, - disNCT , disNULL , disNULL , disNULL , disNULL, disNULL , disNULL , disNULL, - disSQR , disDCPL , disDPCT , disNULL , disNULL, disAVSZ3, disAVSZ4, disNULL, - disRTPT , disNULL , disNULL , disNULL , disNULL, disNULL , disNULL , disNULL, - disNULL , disNULL , disNULL , disNULL , disNULL, disGPF , disGPL , disNCCT }; - -MakeDisF(disCOP2, disR3000A_COP2[_Funct_](code, pc)) - -TdisR3000AF disR3000A[] = { - disSPECIAL , disBCOND , disJ , disJAL , disBEQ , disBNE , disBLEZ , disBGTZ , - disADDI , disADDIU , disSLTI , disSLTIU, disANDI, disORI , disXORI , disLUI , - disCOP0 , disNULL , disCOP2 , disNULL , disNULL, disNULL, disNULL , disNULL , - disNULL , disNULL , disNULL , disNULL , disNULL, disNULL, disNULL , disNULL , - disLB , disLH , disLWL , disLW , disLBU , disLHU , disLWR , disNULL , - disSB , disSH , disSWL , disSW , disNULL, disNULL, disSWR , disNULL , - disNULL , disNULL , disLWC2 , disNULL , disNULL, disNULL, disNULL , disNULL , - disNULL , disNULL , disSWC2 , disNULL , disNULL, disNULL, disNULL , disNULL }; - -MakeDisFg(disR3000AF, disR3000A[code >> 26](code, pc)) - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "R3000A.h" +#include "Debug.h" + +namespace R3000A +{ + static char ostr[1024]; + +// Names of registers + const char * const disRNameGPR[] = { + "r0", "at", "v0", "v1", "a0", "a1","a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5","t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5","s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp","fp", "ra"}; + + const char * const disRNameCP0[] = { + "Index" , "Random" , "EntryLo0", "EntryLo1", "Context" , "PageMask" , "Wired" , "*Check me*", + "BadVAddr" , "Count" , "EntryHi" , "Compare" , "Status" , "Cause" , "ExceptPC" , "PRevID" , + "Config" , "LLAddr" , "WatchLo" , "WatchHi" , "XContext", "*RES*" , "*RES*" , "*RES*" , + "*RES*" , "*RES* " , "PErr" , "CacheErr", "TagLo" , "TagHi" , "ErrorEPC" , "*RES*" }; + +// Type definition of our functions + +typedef char* (*TdisR3000AF)(u32 code, u32 pc); + +// These macros are used to assemble the disassembler functions +#define MakeDisFg(fn, b) char* fn(u32 code, u32 pc) { b; return ostr; } +#define MakeDisF(fn, b) \ + static char* fn(u32 code, u32 pc) { \ + sprintf (ostr, "%8.8lx %8.8lx:", pc, code); \ + b; /*ostr[(strlen(ostr) - 1)] = 0;*/ return ostr; \ + } + + +#undef _Funct_ +#undef _Rd_ +#undef _Rt_ +#undef _Rs_ +#undef _Sa_ +#undef _Im_ +#undef _Target_ + +#define _Funct_ ((code ) & 0x3F) // The funct part of the instruction register +#define _Rd_ ((code >> 11) & 0x1F) // The rd part of the instruction register +#define _Rt_ ((code >> 16) & 0x1F) // The rt part of the instruction register +#define _Rs_ ((code >> 21) & 0x1F) // The rs part of the instruction register +#define _Sa_ ((code >> 6) & 0x1F) // The sa part of the instruction register +#define _Im_ ( code & 0xFFFF) // The immediate part of the instruction register + +#define _Target_ ((pc & 0xf0000000) + ((code & 0x03ffffff) * 4)) +#define _Branch_ (pc + 4 + ((short)_Im_ * 4)) +#define _OfB_ _Im_, _nRs_ + +#define dName(i) sprintf(ostr, "%s %-7s,", ostr, i) +#define dGPR(i) sprintf(ostr, "%s %8.8lx (%s),", ostr, psxRegs.GPR.r[i], disRNameGPR[i]) +#define dCP0(i) sprintf(ostr, "%s %8.8lx (%s),", ostr, psxRegs.CP0.r[i], disRNameCP0[i]) +#define dHI() sprintf(ostr, "%s %8.8lx (%s),", ostr, psxRegs.GPR.n.hi, "hi") +#define dLO() sprintf(ostr, "%s %8.8lx (%s),", ostr, psxRegs.GPR.n.lo, "lo") +#define dImm() sprintf(ostr, "%s %4.4lx (%ld),", ostr, _Im_, _Im_) +#define dTarget() sprintf(ostr, "%s %8.8lx,", ostr, _Target_) +#define dSa() sprintf(ostr, "%s %2.2lx (%ld),", ostr, _Sa_, _Sa_) +#define dOfB() sprintf(ostr, "%s %4.4lx (%8.8lx (%s)),", ostr, _Im_, psxRegs.GPR.r[_Rs_], disRNameGPR[_Rs_]) +#define dOffset() sprintf(ostr, "%s %8.8lx,", ostr, _Branch_) +#define dCode() sprintf(ostr, "%s %8.8lx,", ostr, (code >> 6) & 0xffffff) + +/********************************************************* +* Arithmetic with immediate operand * +* Format: OP rt, rs, immediate * +*********************************************************/ +MakeDisF(disADDI, dName("ADDI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) +MakeDisF(disADDIU, dName("ADDIU"); dGPR(_Rt_); dGPR(_Rs_); dImm();) +MakeDisF(disANDI, dName("ANDI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) +MakeDisF(disORI, dName("ORI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) +MakeDisF(disSLTI, dName("SLTI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) +MakeDisF(disSLTIU, dName("SLTIU"); dGPR(_Rt_); dGPR(_Rs_); dImm();) +MakeDisF(disXORI, dName("XORI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) + +/********************************************************* +* Register arithmetic * +* Format: OP rd, rs, rt * +*********************************************************/ +MakeDisF(disADD, dName("ADD"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disADDU, dName("ADDU"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disAND, dName("AND"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disNOR, dName("NOR"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disOR, dName("OR"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disSLT, dName("SLT"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disSLTU, dName("SLTU"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disSUB, dName("SUB"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disSUBU, dName("SUBU"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disXOR, dName("XOR"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) + +/********************************************************* +* Register arithmetic & Register trap logic * +* Format: OP rs, rt * +*********************************************************/ +MakeDisF(disDIV, dName("DIV"); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disDIVU, dName("DIVU"); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disMULT, dName("MULT"); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disMULTU, dName("MULTU"); dGPR(_Rs_); dGPR(_Rt_);) + +/********************************************************* +* Register branch logic * +* Format: OP rs, offset * +*********************************************************/ +MakeDisF(disBGEZ, dName("BGEZ"); dGPR(_Rs_); dOffset();) +MakeDisF(disBGEZAL, dName("BGEZAL"); dGPR(_Rs_); dOffset();) +MakeDisF(disBGTZ, dName("BGTZ"); dGPR(_Rs_); dOffset();) +MakeDisF(disBLEZ, dName("BLEZ"); dGPR(_Rs_); dOffset();) +MakeDisF(disBLTZ, dName("BLTZ"); dGPR(_Rs_); dOffset();) +MakeDisF(disBLTZAL, dName("BLTZAL"); dGPR(_Rs_); dOffset();) + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ +MakeDisF(disSLL, if (code) { dName("SLL"); dGPR(_Rd_); dGPR(_Rt_); dSa(); } else { dName("NOP"); }) +MakeDisF(disSRA, dName("SRA"); dGPR(_Rd_); dGPR(_Rt_); dSa();) +MakeDisF(disSRL, dName("SRL"); dGPR(_Rd_); dGPR(_Rt_); dSa();) + +/********************************************************* +* Shift arithmetic with variant register shift * +* Format: OP rd, rt, rs * +*********************************************************/ +MakeDisF(disSLLV, dName("SLLV"); dGPR(_Rd_); dGPR(_Rt_); dGPR(_Rs_);) +MakeDisF(disSRAV, dName("SRAV"); dGPR(_Rd_); dGPR(_Rt_); dGPR(_Rs_);) +MakeDisF(disSRLV, dName("SRLV"); dGPR(_Rd_); dGPR(_Rt_); dGPR(_Rs_);) + +/********************************************************* +* Load higher 16 bits of the first word in GPR with imm * +* Format: OP rt, immediate * +*********************************************************/ +MakeDisF(disLUI, dName("LUI"); dGPR(_Rt_); dImm();) + +/********************************************************* +* Move from HI/LO to GPR * +* Format: OP rd * +*********************************************************/ +MakeDisF(disMFHI, dName("MFHI"); dGPR(_Rd_); dHI();) +MakeDisF(disMFLO, dName("MFLO"); dGPR(_Rd_); dLO();) + +/********************************************************* +* Move from GPR to HI/LO * +* Format: OP rd * +*********************************************************/ +MakeDisF(disMTHI, dName("MTHI"); dHI(); dGPR(_Rs_);) +MakeDisF(disMTLO, dName("MTLO"); dLO(); dGPR(_Rs_);) + +/********************************************************* +* Special purpose instructions * +* Format: OP * +*********************************************************/ +MakeDisF(disBREAK, dName("BREAK")) +MakeDisF(disRFE, dName("RFE")) +MakeDisF(disSYSCALL, dName("SYSCALL")) + + + +MakeDisF(disRTPS, dName("RTPS")) +MakeDisF(disOP , dName("OP")) +MakeDisF(disNCLIP, dName("NCLIP")) +MakeDisF(disDPCS, dName("DPCS")) +MakeDisF(disINTPL, dName("INTPL")) +MakeDisF(disMVMVA, dName("MVMVA")) +MakeDisF(disNCDS , dName("NCDS")) +MakeDisF(disCDP , dName("CDP")) +MakeDisF(disNCDT , dName("NCDT")) +MakeDisF(disNCCS , dName("NCCS")) +MakeDisF(disCC , dName("CC")) +MakeDisF(disNCS , dName("NCS")) +MakeDisF(disNCT , dName("NCT")) +MakeDisF(disSQR , dName("SQR")) +MakeDisF(disDCPL , dName("DCPL")) +MakeDisF(disDPCT , dName("DPCT")) +MakeDisF(disAVSZ3, dName("AVSZ3")) +MakeDisF(disAVSZ4, dName("AVSZ4")) +MakeDisF(disRTPT , dName("RTPT")) +MakeDisF(disGPF , dName("GPF")) +MakeDisF(disGPL , dName("GPL")) +MakeDisF(disNCCT , dName("NCCT")) + +MakeDisF(disMFC2, dName("MFC2"); dGPR(_Rt_);) +MakeDisF(disCFC2, dName("CFC2"); dGPR(_Rt_);) +MakeDisF(disMTC2, dName("MTC2")) +MakeDisF(disCTC2, dName("CTC2")) + +/********************************************************* +* Register branch logic * +* Format: OP rs, rt, offset * +*********************************************************/ +MakeDisF(disBEQ, dName("BEQ"); dGPR(_Rs_); dGPR(_Rt_); dOffset();) +MakeDisF(disBNE, dName("BNE"); dGPR(_Rs_); dGPR(_Rt_); dOffset();) + +/********************************************************* +* Jump to target * +* Format: OP target * +*********************************************************/ +MakeDisF(disJ, dName("J"); dTarget();) +MakeDisF(disJAL, dName("JAL"); dTarget(); dGPR(31);) + +/********************************************************* +* Register jump * +* Format: OP rs, rd * +*********************************************************/ +MakeDisF(disJR, dName("JR"); dGPR(_Rs_);) +MakeDisF(disJALR, dName("JALR"); dGPR(_Rs_); dGPR(_Rd_)) + +/********************************************************* +* Load and store for GPR * +* Format: OP rt, offset(base) * +*********************************************************/ +MakeDisF(disLB, dName("LB"); dGPR(_Rt_); dOfB();) +MakeDisF(disLBU, dName("LBU"); dGPR(_Rt_); dOfB();) +MakeDisF(disLH, dName("LH"); dGPR(_Rt_); dOfB();) +MakeDisF(disLHU, dName("LHU"); dGPR(_Rt_); dOfB();) +MakeDisF(disLW, dName("LW"); dGPR(_Rt_); dOfB();) +MakeDisF(disLWL, dName("LWL"); dGPR(_Rt_); dOfB();) +MakeDisF(disLWR, dName("LWR"); dGPR(_Rt_); dOfB();) +MakeDisF(disLWC2, dName("LWC2"); dGPR(_Rt_); dOfB();) +MakeDisF(disSB, dName("SB"); dGPR(_Rt_); dOfB();) +MakeDisF(disSH, dName("SH"); dGPR(_Rt_); dOfB();) +MakeDisF(disSW, dName("SW"); dGPR(_Rt_); dOfB();) +MakeDisF(disSWL, dName("SWL"); dGPR(_Rt_); dOfB();) +MakeDisF(disSWR, dName("SWR"); dGPR(_Rt_); dOfB();) +MakeDisF(disSWC2, dName("SWC2"); dGPR(_Rt_); dOfB();) + +/********************************************************* +* Moves between GPR and COPx * +* Format: OP rt, fs * +*********************************************************/ +MakeDisF(disMFC0, dName("MFC0"); dGPR(_Rt_); dCP0(_Rd_);) +MakeDisF(disMTC0, dName("MTC0"); dCP0(_Rd_); dGPR(_Rt_);) +MakeDisF(disCFC0, dName("CFC0"); dGPR(_Rt_); dCP0(_Rd_);) +MakeDisF(disCTC0, dName("CTC0"); dCP0(_Rd_); dGPR(_Rt_);) + +/********************************************************* +* Unknow instruction (would generate an exception) * +* Format: ? * +*********************************************************/ +MakeDisF(disNULL, dName("*** Bad OP ***");) + + +TdisR3000AF disR3000A_SPECIAL[] = { // Subset of disSPECIAL + disSLL , disNULL , disSRL , disSRA , disSLLV , disNULL , disSRLV , disSRAV , + disJR , disJALR , disNULL, disNULL, disSYSCALL, disBREAK , disNULL , disNULL , + disMFHI, disMTHI , disMFLO, disMTLO, disNULL , disNULL , disNULL , disNULL , + disMULT, disMULTU, disDIV , disDIVU, disNULL , disNULL , disNULL , disNULL , + disADD , disADDU , disSUB , disSUBU, disAND , disOR , disXOR , disNOR , + disNULL, disNULL , disSLT , disSLTU, disNULL , disNULL , disNULL , disNULL , + disNULL, disNULL , disNULL, disNULL, disNULL , disNULL , disNULL , disNULL , + disNULL, disNULL , disNULL, disNULL, disNULL , disNULL , disNULL , disNULL}; + +MakeDisF(disSPECIAL, disR3000A_SPECIAL[_Funct_](code, pc)) + +TdisR3000AF disR3000A_BCOND[] = { // Subset of disBCOND + disBLTZ , disBGEZ , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disBLTZAL, disBGEZAL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; + +MakeDisF(disBCOND, disR3000A_BCOND[_Rt_](code, pc)) + +TdisR3000AF disR3000A_COP0[] = { // Subset of disCOP0 + disMFC0, disNULL, disCFC0, disNULL, disMTC0, disNULL, disCTC0, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disRFE , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; + +MakeDisF(disCOP0, disR3000A_COP0[_Rs_](code, pc)) + +TdisR3000AF disR3000A_BASIC[] = { // Subset of disBASIC (based on rs) + disMFC2, disNULL, disCFC2, disNULL, disMTC2, disNULL, disCTC2, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; + +MakeDisF(disBASIC, disR3000A_BASIC[_Rs_](code, pc)) + +TdisR3000AF disR3000A_COP2[] = { // Subset of disR3000F_COP2 (based on funct) + disBASIC, disRTPS , disNULL , disNULL , disNULL, disNULL , disNCLIP, disNULL, + disNULL , disNULL , disNULL , disNULL , disOP , disNULL , disNULL , disNULL, + disDPCS , disINTPL, disMVMVA, disNCDS , disCDP , disNULL , disNCDT , disNULL, + disNULL , disNULL , disNULL , disNCCS , disCC , disNULL , disNCS , disNULL, + disNCT , disNULL , disNULL , disNULL , disNULL, disNULL , disNULL , disNULL, + disSQR , disDCPL , disDPCT , disNULL , disNULL, disAVSZ3, disAVSZ4, disNULL, + disRTPT , disNULL , disNULL , disNULL , disNULL, disNULL , disNULL , disNULL, + disNULL , disNULL , disNULL , disNULL , disNULL, disGPF , disGPL , disNCCT }; + +MakeDisF(disCOP2, disR3000A_COP2[_Funct_](code, pc)) + +TdisR3000AF disR3000A[] = { + disSPECIAL , disBCOND , disJ , disJAL , disBEQ , disBNE , disBLEZ , disBGTZ , + disADDI , disADDIU , disSLTI , disSLTIU, disANDI, disORI , disXORI , disLUI , + disCOP0 , disNULL , disCOP2 , disNULL , disNULL, disNULL, disNULL , disNULL , + disNULL , disNULL , disNULL , disNULL , disNULL, disNULL, disNULL , disNULL , + disLB , disLH , disLWL , disLW , disLBU , disLHU , disLWR , disNULL , + disSB , disSH , disSWL , disSW , disNULL, disNULL, disSWR , disNULL , + disNULL , disNULL , disLWC2 , disNULL , disNULL, disNULL, disNULL , disNULL , + disNULL , disNULL , disSWC2 , disNULL , disNULL, disNULL, disNULL , disNULL }; + +MakeDisFg(disR3000AF, disR3000A[code >> 26](code, pc)) + } \ No newline at end of file diff --git a/pcsx2/DebugTools/DisR3000asm.cpp b/pcsx2/DebugTools/DisR3000asm.cpp index b92db4532b..69d73a2aa9 100644 --- a/pcsx2/DebugTools/DisR3000asm.cpp +++ b/pcsx2/DebugTools/DisR3000asm.cpp @@ -1,363 +1,363 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Debug.h" -#include "R3000A.h" -#include "DisASM.h" - -namespace R3000A { - -unsigned long IOP_opcode_addr; - -const char *GPR_IOP_REG[32] = { - "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", - "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", - "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" -}; -const char *COP0_IOP_REG[32] ={ - "Index","Random","EntryLo0","EntryLo1","Context","PageMask", - "Wired","C0r7","BadVaddr","Count","EntryHi","Compare","Status", - "Cause","EPC","PRId","Config","C0r17","C0r18","C0r19","C0r20", - "C0r21","C0r22","C0r23","Debug","Perf","C0r26","C0r27","TagLo", - "TagHi","ErrorPC","C0r31" -}; -void IOPD_SPECIAL(char *buf); -void IOPD_REGIMM(char *buf); -void IOPD_J(char *buf); -void IOPD_JAL(char *buf); -void IOPD_BEQ(char *buf); -void IOPD_BNE(char *buf); -void IOPD_BLEZ(char *buf); -void IOPD_BGTZ(char *buf); -void IOPD_ADDI(char *buf); -void IOPD_ADDIU(char *buf); -void IOPD_SLTI(char *buf); -void IOPD_SLTIU(char *buf); -void IOPD_ANDI(char *buf); -void IOPD_ORI(char *buf); -void IOPD_XORI(char *buf); -void IOPD_LUI(char *buf); -void IOPD_COP0(char *buf); -void IOPD_COP2(char *buf); -void IOPD_LB(char *buf); -void IOPD_LH(char *buf); -void IOPD_LWL(char *buf); -void IOPD_LW(char *buf); -void IOPD_LBU(char *buf); -void IOPD_LHU(char *buf); -void IOPD_LWR(char *buf); -void IOPD_SB(char *buf); -void IOPD_SH(char *buf); -void IOPD_SWL(char *buf); -void IOPD_SW(char *buf); -void IOPD_SWR(char *buf); -void IOPD_LWC2(char *buf); -void IOPD_SWC2(char *buf); - -void IOPD_SLL(char *buf); -void IOPD_SRL(char *buf); -void IOPD_SRA(char *buf); -void IOPD_SLLV(char *buf); -void IOPD_SRLV(char *buf); -void IOPD_SRAV(char *buf); -void IOPD_JR(char *buf); -void IOPD_JALR(char *buf); -void IOPD_SYSCALL(char *buf); -void IOPD_BREAK(char *buf); -void IOPD_MFHI(char *buf); -void IOPD_MTHI(char *buf); -void IOPD_MFLO(char *buf); -void IOPD_MTLO(char *buf); -void IOPD_MULT(char *buf); -void IOPD_MULTU(char *buf); -void IOPD_DIV(char *buf); -void IOPD_DIVU(char *buf); -void IOPD_ADD(char *buf); -void IOPD_ADDU(char *buf); -void IOPD_SUB(char *buf); -void IOPD_SUBU(char *buf); -void IOPD_AND(char *buf); -void IOPD_OR(char *buf); -void IOPD_XOR(char *buf); -void IOPD_NOR(char *buf); -void IOPD_SLT(char *buf); -void IOPD_SLTU(char *buf); - - -void IOPD_BLTZ(char *buf); -void IOPD_BGEZ(char *buf); -void IOPD_BLTZAL(char *buf); -void IOPD_BGEZAL(char *buf); - - - -void IOPD_MFC0(char *buf); -void IOPD_CFC0(char *buf); -void IOPD_MTC0(char *buf); -void IOPD_CTC0(char *buf); -void IOPD_RFE(char *buf); - - - -void IOPD_BASIC(char *buf); -void IOPD_RTPS(char *buf); -void IOPD_NCLIP(char *buf); -void IOPD_OP(char *buf); -void IOPD_DPCS(char *buf); -void IOPD_INTPL(char *buf); -void IOPD_MVMVA(char *buf); -void IOPD_NCDS(char *buf); -void IOPD_CDP(char *buf); -void IOPD_NCDT(char *buf); -void IOPD_NCCS(char *buf); -void IOPD_CC(char *buf); -void IOPD_NCS(char *buf); -void IOPD_NCT(char *buf); -void IOPD_SQR(char *buf); -void IOPD_DCPL(char *buf); -void IOPD_DPCT(char *buf); -void IOPD_AVSZ3(char *buf); -void IOPD_AVSZ4(char *buf); -void IOPD_RTPT(char *buf); -void IOPD_GPF(char *buf); -void IOPD_GPL(char *buf); -void IOPD_NCCT(char *buf); - - - -void IOPD_MFC2(char *buf); -void IOPD_CFC2(char *buf); -void IOPD_MTC2(char *buf); -void IOPD_CTC2(char *buf); -void IOPD_NULL(char *buf); - - - - void (*IOP_DEBUG_BSC[64])(char *buf) = { - IOPD_SPECIAL, IOPD_REGIMM, IOPD_J , IOPD_JAL , IOPD_BEQ , IOPD_BNE , IOPD_BLEZ, IOPD_BGTZ, - IOPD_ADDI , IOPD_ADDIU , IOPD_SLTI, IOPD_SLTIU, IOPD_ANDI, IOPD_ORI , IOPD_XORI, IOPD_LUI , - IOPD_COP0 , IOPD_NULL , IOPD_COP2, IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, - IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, - IOPD_LB , IOPD_LH , IOPD_LWL , IOPD_LW , IOPD_LBU , IOPD_LHU , IOPD_LWR , IOPD_NULL, - IOPD_SB , IOPD_SH , IOPD_SWL , IOPD_SW , IOPD_NULL, IOPD_NULL, IOPD_SWR , IOPD_NULL, - IOPD_NULL , IOPD_NULL , IOPD_LWC2, IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, - IOPD_NULL , IOPD_NULL , IOPD_SWC2, IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL -}; - - -void (*IOP_DEBUG_SPC[64])(char *buf) = { - IOPD_SLL , IOPD_NULL , IOPD_SRL , IOPD_SRA , IOPD_SLLV , IOPD_NULL , IOPD_SRLV, IOPD_SRAV, - IOPD_JR , IOPD_JALR , IOPD_NULL, IOPD_NULL, IOPD_SYSCALL, IOPD_BREAK, IOPD_NULL, IOPD_NULL, - IOPD_MFHI, IOPD_MTHI , IOPD_MFLO, IOPD_MTLO, IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, - IOPD_MULT, IOPD_MULTU, IOPD_DIV , IOPD_DIVU, IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, - IOPD_ADD , IOPD_ADDU , IOPD_SUB , IOPD_SUBU, IOPD_AND , IOPD_OR , IOPD_XOR , IOPD_NOR , - IOPD_NULL, IOPD_NULL , IOPD_SLT , IOPD_SLTU, IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, - IOPD_NULL, IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, - IOPD_NULL, IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL -}; - -void (*IOP_DEBUG_REG[32])(char *buf) = { - IOPD_BLTZ , IOPD_BGEZ , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, - IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, - IOPD_BLTZAL, IOPD_BGEZAL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, - IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL -}; - -void (*IOP_DEBUG_CP0[32])(char *buf) = { - IOPD_MFC0, IOPD_NULL, IOPD_CFC0, IOPD_NULL, IOPD_MTC0, IOPD_NULL, IOPD_CTC0, IOPD_NULL, - IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, - IOPD_RFE , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, - IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL -}; - -void (*IOP_DEBUG_CP2[64])(char *buf) = { - IOPD_BASIC, IOPD_RTPS , IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL , IOPD_NCLIP, IOPD_NULL, - IOPD_NULL , IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_OP , IOPD_NULL , IOPD_NULL , IOPD_NULL, - IOPD_DPCS , IOPD_INTPL, IOPD_MVMVA, IOPD_NCDS, IOPD_CDP , IOPD_NULL , IOPD_NCDT , IOPD_NULL, - IOPD_NULL , IOPD_NULL , IOPD_NULL , IOPD_NCCS, IOPD_CC , IOPD_NULL , IOPD_NCS , IOPD_NULL, - IOPD_NCT , IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL , IOPD_NULL , IOPD_NULL, - IOPD_SQR , IOPD_DCPL , IOPD_DPCT , IOPD_NULL, IOPD_NULL, IOPD_AVSZ3, IOPD_AVSZ4, IOPD_NULL, - IOPD_RTPT , IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL , IOPD_NULL , IOPD_NULL, - IOPD_NULL , IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_GPF , IOPD_GPL , IOPD_NCCT -}; - -void (*IOP_DEBUG_CP2BSC[32])(char *buf) = { - IOPD_MFC2, IOPD_NULL, IOPD_CFC2, IOPD_NULL, IOPD_MTC2, IOPD_NULL, IOPD_CTC2, IOPD_NULL, - IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, - IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, - IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL -}; - -static char dbuf2[1024]; -static char obuf2[1024]; - -char *disR3000Fasm(u32 code, u32 pc) { - u32 scode = psxRegs.code; - IOP_opcode_addr = pc; - psxRegs.code = code; - IOP_DEBUG_BSC[(code) >> 26](dbuf2); - - sprintf(obuf2, "%08lX:\t%s", pc, dbuf2); - - psxRegs.code = scode; - return obuf2; -} -char *IOP_jump_decode(void) -{ - static char buf[256]; - unsigned long addr; - addr = (IOP_opcode_addr & 0xf0000000)|((psxRegs.code&0x3ffffff)<<2); - sprintf(buf, "0x%08lX", addr); - return buf; -} -char *IOP_offset_decode(void) -{ - static char buf[256]; - unsigned long addr; - addr = ((((short)( psxRegs.code & 0xFFFF) * 4) + IOP_opcode_addr + 4)); - sprintf(buf, "0x%08lX", addr); - return buf; -} -//basic table -void IOPD_SPECIAL(char *buf){IOP_DEBUG_SPC[((psxRegs.code) & 0x3F)](buf);} -void IOPD_REGIMM(char *buf){IOP_DEBUG_REG[DECODE_RT_IOP](buf);} -void IOPD_J(char *buf) { sprintf(buf, "j\t%s", IOP_jump_decode());} -void IOPD_JAL(char *buf){sprintf(buf, "jal\t%s", IOP_jump_decode());} -void IOPD_BEQ(char *buf){sprintf(buf, "beq\t%s, %s, %s", GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP], IOP_offset_decode()); } -void IOPD_BNE(char *buf){sprintf(buf, "bne\t%s, %s, %s", GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP], IOP_offset_decode()); } -void IOPD_BLEZ(char *buf){sprintf(buf, "blez\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], IOP_offset_decode()); } -void IOPD_BGTZ(char *buf){sprintf(buf, "bgtz\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], IOP_offset_decode()); } -void IOPD_ADDI(char *buf){sprintf(buf, "addi\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP);} -void IOPD_ADDIU(char *buf){sprintf(buf, "addiu\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP);} -void IOPD_SLTI(char *buf){sprintf(buf, "slti\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP);} -void IOPD_SLTIU(char *buf){sprintf(buf, "sltiu\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP);} -void IOPD_ANDI(char *buf){sprintf(buf, "andi\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP);} -void IOPD_ORI(char *buf){sprintf(buf, "ori\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP); } -void IOPD_XORI(char *buf){sprintf(buf, "xori\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP); } -void IOPD_LUI(char *buf){sprintf(buf, "lui\t%s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP); } -void IOPD_COP0(char *buf){IOP_DEBUG_CP0[DECODE_RS_IOP](buf);} -void IOPD_COP2(char *buf){IOP_DEBUG_CP2[((psxRegs.code) & 0x3F)](buf);} -void IOPD_LB(char *buf){sprintf(buf, "lb\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } -void IOPD_LH(char *buf){sprintf(buf, "lh\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } -void IOPD_LWL(char *buf){sprintf(buf, "lwl\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } -void IOPD_LW(char *buf){sprintf(buf, "lw\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } -void IOPD_LBU(char *buf){sprintf(buf, "lbu\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } -void IOPD_LHU(char *buf){sprintf(buf, "lhu\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } -void IOPD_LWR(char *buf){sprintf(buf, "lwr\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]);} -void IOPD_SB(char *buf){sprintf(buf, "sb\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]);} -void IOPD_SH(char *buf){sprintf(buf, "sh\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } -void IOPD_SWL(char *buf){sprintf(buf, "swl\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } -void IOPD_SW(char *buf){sprintf(buf, "sw\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } -void IOPD_SWR(char *buf){sprintf(buf, "swr\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]);} -void IOPD_LWC2(char *buf){strcpy(buf, "lwc2");} -void IOPD_SWC2(char *buf){strcpy(buf, "swc2");} -//special table -void IOPD_SLL(char *buf) -{ - if (psxRegs.code == 0x00000000) - strcpy(buf, "nop"); - else - sprintf(buf, "sll\t%s, %s, 0x%02lX", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RT_IOP], DECODE_SA_IOP); -} -void IOPD_SRL(char *buf){sprintf(buf, "srl\t%s, %s, 0x%02lX", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RT_IOP], DECODE_SA_IOP); } -void IOPD_SRA(char *buf){sprintf(buf, "sra\t%s, %s, 0x%02lX", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RT_IOP], DECODE_SA_IOP);} -void IOPD_SLLV(char *buf){sprintf(buf, "sllv\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP]); } -void IOPD_SRLV(char *buf){sprintf(buf, "srlv\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP]);} -void IOPD_SRAV(char *buf){sprintf(buf, "srav\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP]); } -void IOPD_JR(char *buf){sprintf(buf, "jr\t%s", GPR_IOP_REG[DECODE_RS_IOP]);} -void IOPD_JALR(char *buf) -{ - int rd = DECODE_RD_IOP; - - if (rd == 31) - sprintf(buf, "jalr\t%s", GPR_IOP_REG[DECODE_RS_IOP]); - else - sprintf(buf, "jalr\t%s, %s", GPR_IOP_REG[rd], GPR_IOP_REG[DECODE_RS_IOP]); -} - -void IOPD_SYSCALL(char *buf){strcpy(buf, "syscall");} -void IOPD_BREAK(char *buf){strcpy(buf, "break");} -void IOPD_MFHI(char *buf){sprintf(buf, "mfhi\t%s", GPR_IOP_REG[DECODE_RD_IOP]); } -void IOPD_MTHI(char *buf){sprintf(buf, "mthi\t%s", GPR_IOP_REG[DECODE_RS_IOP]); } -void IOPD_MFLO(char *buf){sprintf(buf, "mflo\t%s", GPR_IOP_REG[DECODE_RD_IOP]); } -void IOPD_MTLO(char *buf){sprintf(buf, "mtlo\t%s", GPR_IOP_REG[DECODE_RS_IOP]); } -void IOPD_MULT(char *buf){sprintf(buf, "mult\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]);} -void IOPD_MULTU(char *buf){sprintf(buf, "multu\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]);} -void IOPD_DIV(char *buf){sprintf(buf, "div\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]);} -void IOPD_DIVU(char *buf){sprintf(buf, "divu\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } - -void IOPD_ADD(char *buf) { sprintf(buf, "add\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } -void IOPD_ADDU(char *buf) { sprintf(buf, "addu\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } -void IOPD_SUB(char *buf) { sprintf(buf, "sub\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } -void IOPD_SUBU(char *buf) { sprintf(buf, "subu\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } -void IOPD_AND(char *buf) { sprintf(buf, "and\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } -void IOPD_OR(char *buf) { sprintf(buf, "or\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } -void IOPD_XOR(char *buf) { sprintf(buf, "xor\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } -void IOPD_NOR(char *buf) { sprintf(buf, "nor\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } -void IOPD_SLT(char *buf) { sprintf(buf, "slt\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } -void IOPD_SLTU(char *buf) { sprintf(buf, "sltu\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } -//regimm - -void IOPD_BLTZ(char *buf) { sprintf(buf, "bltz\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], IOP_offset_decode()); } -void IOPD_BGEZ(char *buf) { sprintf(buf, "bgez\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], IOP_offset_decode()); } -void IOPD_BLTZAL(char *buf) { sprintf(buf, "bltzal\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], IOP_offset_decode()); } -void IOPD_BGEZAL(char *buf) { sprintf(buf, "bgezal\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], IOP_offset_decode()); } - -//cop0 - -void IOPD_MFC0(char *buf){ sprintf(buf, "mfc0\t%s, %s", GPR_IOP_REG[DECODE_RT_IOP], COP0_IOP_REG[DECODE_FS_IOP]); } -void IOPD_MTC0(char *buf){ sprintf(buf, "mtc0\t%s, %s", GPR_IOP_REG[DECODE_RT_IOP], COP0_IOP_REG[DECODE_FS_IOP]); } -void IOPD_CFC0(char *buf){ sprintf(buf, "cfc0\t%s, %s", GPR_IOP_REG[DECODE_RT_IOP], COP0_IOP_REG[DECODE_FS_IOP]); } -void IOPD_CTC0(char *buf){ sprintf(buf, "ctc0\t%s, %s", GPR_IOP_REG[DECODE_RT_IOP], COP0_IOP_REG[DECODE_FS_IOP]); } -void IOPD_RFE(char *buf){strcpy(buf, "rfe");} -//cop2 -void IOPD_BASIC(char *buf){IOP_DEBUG_CP2BSC[DECODE_RS_IOP](buf);} -void IOPD_RTPS(char *buf){strcpy(buf, "rtps");} -void IOPD_NCLIP(char *buf){strcpy(buf, "nclip");} -void IOPD_OP(char *buf){strcpy(buf, "op");} -void IOPD_DPCS(char *buf){strcpy(buf, "dpcs");} -void IOPD_INTPL(char *buf){strcpy(buf, "intpl");} -void IOPD_MVMVA(char *buf){strcpy(buf, "mvmva");} -void IOPD_NCDS(char *buf){strcpy(buf, "ncds");} -void IOPD_CDP(char *buf){strcpy(buf, "cdp");} -void IOPD_NCDT(char *buf){strcpy(buf, "ncdt");} -void IOPD_NCCS(char *buf){strcpy(buf, "nccs");} -void IOPD_CC(char *buf){strcpy(buf, "cc");} -void IOPD_NCS(char *buf){strcpy(buf, "ncs");} -void IOPD_NCT(char *buf){strcpy(buf, "nct");} -void IOPD_SQR(char *buf){strcpy(buf, "sqr");} -void IOPD_DCPL(char *buf){strcpy(buf, "dcpl");} -void IOPD_DPCT(char *buf){strcpy(buf, "dpct");} -void IOPD_AVSZ3(char *buf){strcpy(buf, "avsz3");} -void IOPD_AVSZ4(char *buf){strcpy(buf, "avsz4");} -void IOPD_RTPT(char *buf){strcpy(buf, "rtpt");} -void IOPD_GPF(char *buf){strcpy(buf, "gpf");} -void IOPD_GPL(char *buf){strcpy(buf, "gpl");} -void IOPD_NCCT(char *buf){strcpy(buf, "ncct");} -//cop2 basic -void IOPD_MFC2(char *buf){strcpy(buf, "mfc2");} -void IOPD_CFC2(char *buf){strcpy(buf, "cfc2");} -void IOPD_MTC2(char *buf){strcpy(buf, "mtc2");} -void IOPD_CTC2(char *buf){strcpy(buf, "ctc2");} -//null -void IOPD_NULL(char *buf){strcpy(buf, "????");} - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Debug.h" +#include "R3000A.h" +#include "DisASM.h" + +namespace R3000A { + +unsigned long IOP_opcode_addr; + +const char *GPR_IOP_REG[32] = { + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" +}; +const char *COP0_IOP_REG[32] ={ + "Index","Random","EntryLo0","EntryLo1","Context","PageMask", + "Wired","C0r7","BadVaddr","Count","EntryHi","Compare","Status", + "Cause","EPC","PRId","Config","C0r17","C0r18","C0r19","C0r20", + "C0r21","C0r22","C0r23","Debug","Perf","C0r26","C0r27","TagLo", + "TagHi","ErrorPC","C0r31" +}; +void IOPD_SPECIAL(char *buf); +void IOPD_REGIMM(char *buf); +void IOPD_J(char *buf); +void IOPD_JAL(char *buf); +void IOPD_BEQ(char *buf); +void IOPD_BNE(char *buf); +void IOPD_BLEZ(char *buf); +void IOPD_BGTZ(char *buf); +void IOPD_ADDI(char *buf); +void IOPD_ADDIU(char *buf); +void IOPD_SLTI(char *buf); +void IOPD_SLTIU(char *buf); +void IOPD_ANDI(char *buf); +void IOPD_ORI(char *buf); +void IOPD_XORI(char *buf); +void IOPD_LUI(char *buf); +void IOPD_COP0(char *buf); +void IOPD_COP2(char *buf); +void IOPD_LB(char *buf); +void IOPD_LH(char *buf); +void IOPD_LWL(char *buf); +void IOPD_LW(char *buf); +void IOPD_LBU(char *buf); +void IOPD_LHU(char *buf); +void IOPD_LWR(char *buf); +void IOPD_SB(char *buf); +void IOPD_SH(char *buf); +void IOPD_SWL(char *buf); +void IOPD_SW(char *buf); +void IOPD_SWR(char *buf); +void IOPD_LWC2(char *buf); +void IOPD_SWC2(char *buf); + +void IOPD_SLL(char *buf); +void IOPD_SRL(char *buf); +void IOPD_SRA(char *buf); +void IOPD_SLLV(char *buf); +void IOPD_SRLV(char *buf); +void IOPD_SRAV(char *buf); +void IOPD_JR(char *buf); +void IOPD_JALR(char *buf); +void IOPD_SYSCALL(char *buf); +void IOPD_BREAK(char *buf); +void IOPD_MFHI(char *buf); +void IOPD_MTHI(char *buf); +void IOPD_MFLO(char *buf); +void IOPD_MTLO(char *buf); +void IOPD_MULT(char *buf); +void IOPD_MULTU(char *buf); +void IOPD_DIV(char *buf); +void IOPD_DIVU(char *buf); +void IOPD_ADD(char *buf); +void IOPD_ADDU(char *buf); +void IOPD_SUB(char *buf); +void IOPD_SUBU(char *buf); +void IOPD_AND(char *buf); +void IOPD_OR(char *buf); +void IOPD_XOR(char *buf); +void IOPD_NOR(char *buf); +void IOPD_SLT(char *buf); +void IOPD_SLTU(char *buf); + + +void IOPD_BLTZ(char *buf); +void IOPD_BGEZ(char *buf); +void IOPD_BLTZAL(char *buf); +void IOPD_BGEZAL(char *buf); + + + +void IOPD_MFC0(char *buf); +void IOPD_CFC0(char *buf); +void IOPD_MTC0(char *buf); +void IOPD_CTC0(char *buf); +void IOPD_RFE(char *buf); + + + +void IOPD_BASIC(char *buf); +void IOPD_RTPS(char *buf); +void IOPD_NCLIP(char *buf); +void IOPD_OP(char *buf); +void IOPD_DPCS(char *buf); +void IOPD_INTPL(char *buf); +void IOPD_MVMVA(char *buf); +void IOPD_NCDS(char *buf); +void IOPD_CDP(char *buf); +void IOPD_NCDT(char *buf); +void IOPD_NCCS(char *buf); +void IOPD_CC(char *buf); +void IOPD_NCS(char *buf); +void IOPD_NCT(char *buf); +void IOPD_SQR(char *buf); +void IOPD_DCPL(char *buf); +void IOPD_DPCT(char *buf); +void IOPD_AVSZ3(char *buf); +void IOPD_AVSZ4(char *buf); +void IOPD_RTPT(char *buf); +void IOPD_GPF(char *buf); +void IOPD_GPL(char *buf); +void IOPD_NCCT(char *buf); + + + +void IOPD_MFC2(char *buf); +void IOPD_CFC2(char *buf); +void IOPD_MTC2(char *buf); +void IOPD_CTC2(char *buf); +void IOPD_NULL(char *buf); + + + + void (*IOP_DEBUG_BSC[64])(char *buf) = { + IOPD_SPECIAL, IOPD_REGIMM, IOPD_J , IOPD_JAL , IOPD_BEQ , IOPD_BNE , IOPD_BLEZ, IOPD_BGTZ, + IOPD_ADDI , IOPD_ADDIU , IOPD_SLTI, IOPD_SLTIU, IOPD_ANDI, IOPD_ORI , IOPD_XORI, IOPD_LUI , + IOPD_COP0 , IOPD_NULL , IOPD_COP2, IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_LB , IOPD_LH , IOPD_LWL , IOPD_LW , IOPD_LBU , IOPD_LHU , IOPD_LWR , IOPD_NULL, + IOPD_SB , IOPD_SH , IOPD_SWL , IOPD_SW , IOPD_NULL, IOPD_NULL, IOPD_SWR , IOPD_NULL, + IOPD_NULL , IOPD_NULL , IOPD_LWC2, IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_NULL , IOPD_NULL , IOPD_SWC2, IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL +}; + + +void (*IOP_DEBUG_SPC[64])(char *buf) = { + IOPD_SLL , IOPD_NULL , IOPD_SRL , IOPD_SRA , IOPD_SLLV , IOPD_NULL , IOPD_SRLV, IOPD_SRAV, + IOPD_JR , IOPD_JALR , IOPD_NULL, IOPD_NULL, IOPD_SYSCALL, IOPD_BREAK, IOPD_NULL, IOPD_NULL, + IOPD_MFHI, IOPD_MTHI , IOPD_MFLO, IOPD_MTLO, IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, + IOPD_MULT, IOPD_MULTU, IOPD_DIV , IOPD_DIVU, IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, + IOPD_ADD , IOPD_ADDU , IOPD_SUB , IOPD_SUBU, IOPD_AND , IOPD_OR , IOPD_XOR , IOPD_NOR , + IOPD_NULL, IOPD_NULL , IOPD_SLT , IOPD_SLTU, IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, + IOPD_NULL, IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, + IOPD_NULL, IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL +}; + +void (*IOP_DEBUG_REG[32])(char *buf) = { + IOPD_BLTZ , IOPD_BGEZ , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_BLTZAL, IOPD_BGEZAL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL +}; + +void (*IOP_DEBUG_CP0[32])(char *buf) = { + IOPD_MFC0, IOPD_NULL, IOPD_CFC0, IOPD_NULL, IOPD_MTC0, IOPD_NULL, IOPD_CTC0, IOPD_NULL, + IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_RFE , IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL +}; + +void (*IOP_DEBUG_CP2[64])(char *buf) = { + IOPD_BASIC, IOPD_RTPS , IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL , IOPD_NCLIP, IOPD_NULL, + IOPD_NULL , IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_OP , IOPD_NULL , IOPD_NULL , IOPD_NULL, + IOPD_DPCS , IOPD_INTPL, IOPD_MVMVA, IOPD_NCDS, IOPD_CDP , IOPD_NULL , IOPD_NCDT , IOPD_NULL, + IOPD_NULL , IOPD_NULL , IOPD_NULL , IOPD_NCCS, IOPD_CC , IOPD_NULL , IOPD_NCS , IOPD_NULL, + IOPD_NCT , IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL , IOPD_NULL , IOPD_NULL, + IOPD_SQR , IOPD_DCPL , IOPD_DPCT , IOPD_NULL, IOPD_NULL, IOPD_AVSZ3, IOPD_AVSZ4, IOPD_NULL, + IOPD_RTPT , IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_NULL , IOPD_NULL , IOPD_NULL, + IOPD_NULL , IOPD_NULL , IOPD_NULL , IOPD_NULL, IOPD_NULL, IOPD_GPF , IOPD_GPL , IOPD_NCCT +}; + +void (*IOP_DEBUG_CP2BSC[32])(char *buf) = { + IOPD_MFC2, IOPD_NULL, IOPD_CFC2, IOPD_NULL, IOPD_MTC2, IOPD_NULL, IOPD_CTC2, IOPD_NULL, + IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, + IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL, IOPD_NULL +}; + +static char dbuf2[1024]; +static char obuf2[1024]; + +char *disR3000Fasm(u32 code, u32 pc) { + u32 scode = psxRegs.code; + IOP_opcode_addr = pc; + psxRegs.code = code; + IOP_DEBUG_BSC[(code) >> 26](dbuf2); + + sprintf(obuf2, "%08lX:\t%s", pc, dbuf2); + + psxRegs.code = scode; + return obuf2; +} +char *IOP_jump_decode(void) +{ + static char buf[256]; + unsigned long addr; + addr = (IOP_opcode_addr & 0xf0000000)|((psxRegs.code&0x3ffffff)<<2); + sprintf(buf, "0x%08lX", addr); + return buf; +} +char *IOP_offset_decode(void) +{ + static char buf[256]; + unsigned long addr; + addr = ((((short)( psxRegs.code & 0xFFFF) * 4) + IOP_opcode_addr + 4)); + sprintf(buf, "0x%08lX", addr); + return buf; +} +//basic table +void IOPD_SPECIAL(char *buf){IOP_DEBUG_SPC[((psxRegs.code) & 0x3F)](buf);} +void IOPD_REGIMM(char *buf){IOP_DEBUG_REG[DECODE_RT_IOP](buf);} +void IOPD_J(char *buf) { sprintf(buf, "j\t%s", IOP_jump_decode());} +void IOPD_JAL(char *buf){sprintf(buf, "jal\t%s", IOP_jump_decode());} +void IOPD_BEQ(char *buf){sprintf(buf, "beq\t%s, %s, %s", GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP], IOP_offset_decode()); } +void IOPD_BNE(char *buf){sprintf(buf, "bne\t%s, %s, %s", GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP], IOP_offset_decode()); } +void IOPD_BLEZ(char *buf){sprintf(buf, "blez\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], IOP_offset_decode()); } +void IOPD_BGTZ(char *buf){sprintf(buf, "bgtz\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], IOP_offset_decode()); } +void IOPD_ADDI(char *buf){sprintf(buf, "addi\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP);} +void IOPD_ADDIU(char *buf){sprintf(buf, "addiu\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP);} +void IOPD_SLTI(char *buf){sprintf(buf, "slti\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP);} +void IOPD_SLTIU(char *buf){sprintf(buf, "sltiu\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP);} +void IOPD_ANDI(char *buf){sprintf(buf, "andi\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP);} +void IOPD_ORI(char *buf){sprintf(buf, "ori\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP); } +void IOPD_XORI(char *buf){sprintf(buf, "xori\t%s, %s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP], DECODE_IMMED_IOP); } +void IOPD_LUI(char *buf){sprintf(buf, "lui\t%s, 0x%04lX", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP); } +void IOPD_COP0(char *buf){IOP_DEBUG_CP0[DECODE_RS_IOP](buf);} +void IOPD_COP2(char *buf){IOP_DEBUG_CP2[((psxRegs.code) & 0x3F)](buf);} +void IOPD_LB(char *buf){sprintf(buf, "lb\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_LH(char *buf){sprintf(buf, "lh\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_LWL(char *buf){sprintf(buf, "lwl\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_LW(char *buf){sprintf(buf, "lw\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_LBU(char *buf){sprintf(buf, "lbu\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_LHU(char *buf){sprintf(buf, "lhu\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_LWR(char *buf){sprintf(buf, "lwr\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]);} +void IOPD_SB(char *buf){sprintf(buf, "sb\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]);} +void IOPD_SH(char *buf){sprintf(buf, "sh\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_SWL(char *buf){sprintf(buf, "swl\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_SW(char *buf){sprintf(buf, "sw\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_SWR(char *buf){sprintf(buf, "swr\t%s, 0x%04lX(%s)", GPR_IOP_REG[DECODE_RT_IOP], DECODE_IMMED_IOP, GPR_IOP_REG[DECODE_RS_IOP]);} +void IOPD_LWC2(char *buf){strcpy(buf, "lwc2");} +void IOPD_SWC2(char *buf){strcpy(buf, "swc2");} +//special table +void IOPD_SLL(char *buf) +{ + if (psxRegs.code == 0x00000000) + strcpy(buf, "nop"); + else + sprintf(buf, "sll\t%s, %s, 0x%02lX", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RT_IOP], DECODE_SA_IOP); +} +void IOPD_SRL(char *buf){sprintf(buf, "srl\t%s, %s, 0x%02lX", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RT_IOP], DECODE_SA_IOP); } +void IOPD_SRA(char *buf){sprintf(buf, "sra\t%s, %s, 0x%02lX", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RT_IOP], DECODE_SA_IOP);} +void IOPD_SLLV(char *buf){sprintf(buf, "sllv\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_SRLV(char *buf){sprintf(buf, "srlv\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP]);} +void IOPD_SRAV(char *buf){sprintf(buf, "srav\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RT_IOP], GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_JR(char *buf){sprintf(buf, "jr\t%s", GPR_IOP_REG[DECODE_RS_IOP]);} +void IOPD_JALR(char *buf) +{ + int rd = DECODE_RD_IOP; + + if (rd == 31) + sprintf(buf, "jalr\t%s", GPR_IOP_REG[DECODE_RS_IOP]); + else + sprintf(buf, "jalr\t%s, %s", GPR_IOP_REG[rd], GPR_IOP_REG[DECODE_RS_IOP]); +} + +void IOPD_SYSCALL(char *buf){strcpy(buf, "syscall");} +void IOPD_BREAK(char *buf){strcpy(buf, "break");} +void IOPD_MFHI(char *buf){sprintf(buf, "mfhi\t%s", GPR_IOP_REG[DECODE_RD_IOP]); } +void IOPD_MTHI(char *buf){sprintf(buf, "mthi\t%s", GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_MFLO(char *buf){sprintf(buf, "mflo\t%s", GPR_IOP_REG[DECODE_RD_IOP]); } +void IOPD_MTLO(char *buf){sprintf(buf, "mtlo\t%s", GPR_IOP_REG[DECODE_RS_IOP]); } +void IOPD_MULT(char *buf){sprintf(buf, "mult\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]);} +void IOPD_MULTU(char *buf){sprintf(buf, "multu\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]);} +void IOPD_DIV(char *buf){sprintf(buf, "div\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]);} +void IOPD_DIVU(char *buf){sprintf(buf, "divu\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } + +void IOPD_ADD(char *buf) { sprintf(buf, "add\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +void IOPD_ADDU(char *buf) { sprintf(buf, "addu\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +void IOPD_SUB(char *buf) { sprintf(buf, "sub\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +void IOPD_SUBU(char *buf) { sprintf(buf, "subu\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +void IOPD_AND(char *buf) { sprintf(buf, "and\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +void IOPD_OR(char *buf) { sprintf(buf, "or\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +void IOPD_XOR(char *buf) { sprintf(buf, "xor\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +void IOPD_NOR(char *buf) { sprintf(buf, "nor\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +void IOPD_SLT(char *buf) { sprintf(buf, "slt\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +void IOPD_SLTU(char *buf) { sprintf(buf, "sltu\t%s, %s, %s", GPR_IOP_REG[DECODE_RD_IOP], GPR_IOP_REG[DECODE_RS_IOP], GPR_IOP_REG[DECODE_RT_IOP]); } +//regimm + +void IOPD_BLTZ(char *buf) { sprintf(buf, "bltz\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], IOP_offset_decode()); } +void IOPD_BGEZ(char *buf) { sprintf(buf, "bgez\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], IOP_offset_decode()); } +void IOPD_BLTZAL(char *buf) { sprintf(buf, "bltzal\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], IOP_offset_decode()); } +void IOPD_BGEZAL(char *buf) { sprintf(buf, "bgezal\t%s, %s", GPR_IOP_REG[DECODE_RS_IOP], IOP_offset_decode()); } + +//cop0 + +void IOPD_MFC0(char *buf){ sprintf(buf, "mfc0\t%s, %s", GPR_IOP_REG[DECODE_RT_IOP], COP0_IOP_REG[DECODE_FS_IOP]); } +void IOPD_MTC0(char *buf){ sprintf(buf, "mtc0\t%s, %s", GPR_IOP_REG[DECODE_RT_IOP], COP0_IOP_REG[DECODE_FS_IOP]); } +void IOPD_CFC0(char *buf){ sprintf(buf, "cfc0\t%s, %s", GPR_IOP_REG[DECODE_RT_IOP], COP0_IOP_REG[DECODE_FS_IOP]); } +void IOPD_CTC0(char *buf){ sprintf(buf, "ctc0\t%s, %s", GPR_IOP_REG[DECODE_RT_IOP], COP0_IOP_REG[DECODE_FS_IOP]); } +void IOPD_RFE(char *buf){strcpy(buf, "rfe");} +//cop2 +void IOPD_BASIC(char *buf){IOP_DEBUG_CP2BSC[DECODE_RS_IOP](buf);} +void IOPD_RTPS(char *buf){strcpy(buf, "rtps");} +void IOPD_NCLIP(char *buf){strcpy(buf, "nclip");} +void IOPD_OP(char *buf){strcpy(buf, "op");} +void IOPD_DPCS(char *buf){strcpy(buf, "dpcs");} +void IOPD_INTPL(char *buf){strcpy(buf, "intpl");} +void IOPD_MVMVA(char *buf){strcpy(buf, "mvmva");} +void IOPD_NCDS(char *buf){strcpy(buf, "ncds");} +void IOPD_CDP(char *buf){strcpy(buf, "cdp");} +void IOPD_NCDT(char *buf){strcpy(buf, "ncdt");} +void IOPD_NCCS(char *buf){strcpy(buf, "nccs");} +void IOPD_CC(char *buf){strcpy(buf, "cc");} +void IOPD_NCS(char *buf){strcpy(buf, "ncs");} +void IOPD_NCT(char *buf){strcpy(buf, "nct");} +void IOPD_SQR(char *buf){strcpy(buf, "sqr");} +void IOPD_DCPL(char *buf){strcpy(buf, "dcpl");} +void IOPD_DPCT(char *buf){strcpy(buf, "dpct");} +void IOPD_AVSZ3(char *buf){strcpy(buf, "avsz3");} +void IOPD_AVSZ4(char *buf){strcpy(buf, "avsz4");} +void IOPD_RTPT(char *buf){strcpy(buf, "rtpt");} +void IOPD_GPF(char *buf){strcpy(buf, "gpf");} +void IOPD_GPL(char *buf){strcpy(buf, "gpl");} +void IOPD_NCCT(char *buf){strcpy(buf, "ncct");} +//cop2 basic +void IOPD_MFC2(char *buf){strcpy(buf, "mfc2");} +void IOPD_CFC2(char *buf){strcpy(buf, "cfc2");} +void IOPD_MTC2(char *buf){strcpy(buf, "mtc2");} +void IOPD_CTC2(char *buf){strcpy(buf, "ctc2");} +//null +void IOPD_NULL(char *buf){strcpy(buf, "????");} + } // end Namespace R3000A \ No newline at end of file diff --git a/pcsx2/DebugTools/DisR5900.cpp b/pcsx2/DebugTools/DisR5900.cpp index fd2849c3f4..7b6d6964b9 100644 --- a/pcsx2/DebugTools/DisR5900.cpp +++ b/pcsx2/DebugTools/DisR5900.cpp @@ -1,1089 +1,1089 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -using namespace std; - -#include "Debug.h" -#include "R5900.h" -#include "VU.h" - -const char * const disRNameCP2f[] = { - "VF00", "VF01", "VF02", "VF03", "VF04", "VF05", "VF06", "VF07", - "VF08", "VF09", "VF10", "VF11", "VF12", "VF13", "VF14", "VF15", - "VF16", "VF17", "VF18", "VF19", "VF20", "VF21", "VF22", "VF23", - "VF24", "VF25", "VF26", "VF27", "VF28", "VF29", "VF30", "VF31"}; - -const char * const disRNameCP2i[] = { - "VI00", "VI01", "VI02", "VI03", "VI04", "VI05", "VI06", "VI07", - "VI08", "VI09", "VI10", "VI11", "VI12", "VI13", "VI14", "VI15", - "Status", "MAC", "Clip", "*RES*", "R", "I", "Q", "*RES*", - "*RES*", "*RES*", "TPC", "CMSAR0", "FBRST", "VPU-STAT", "*RES*", "CMSAR1"}; - -const char * const CP2VFnames[] = { "x", "y", "z", "w" }; - -namespace R5900 -{ - -// Names of registers -const char * const disRNameGPR[] = { - "r0", "at", "v0", "v1", "a0", "a1","a2", "a3", - "t0", "t1", "t2", "t3", "t4", "t5","t6", "t7", - "s0", "s1", "s2", "s3", "s4", "s5","s6", "s7", - "t8", "t9", "k0", "k1", "gp", "sp","fp", "ra", "hi", "lo"}; // lo,hi used in rec - -const char * const disRNameCP0[] = { - "Index" , "Random" , "EntryLo0" , "EntryLo1", "Context" , "PageMask" , "Wired" , "*RES*", - "BadVAddr" , "Count" , "EntryHi" , "Compare" , "Status" , "Cause" , "ExceptPC" , "PRevID", - "Config" , "LLAddr" , "WatchLo" , "WatchHi" , "*RES*" , "*RES*" , "*RES*" , "Debug", - "DEPC" , "PerfCnt" , "ErrCtl" , "CacheErr", "TagLo" , "TagHi" , "ErrorEPC" , "DESAVE"}; - -const char * const disRNameCP1[] = { - "FPR0" , "FPR1" , "FPR2" , "FPR3" , "FPR4" , "FPR5" , "FPR6" , "FPR7", - "FPR8" , "FPR9" , "FPR10", "FPR11", "FPR12", "FPR13", "FPR14", "FPR15", - "FPR16", "FPR17", "FPR18", "FPR19", "FPR20", "FPR21", "FPR22", "FPR23", - "FPR24", "FPR25", "FPR26", "FPR27", "FPR28", "FPR29", "FPR30", "FPR31"}; - -const char * const disRNameCP1c[] = { - "FRevID", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", - "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", - "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", - "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "FStatus"}; - -// Type definition of our functions -#define DisFInterface (string& output, u32 code) -#define DisFInterfaceT (string&, u32) -#define DisFInterfaceN (output, code) - -typedef void (*TdisR5900F)DisFInterface; - -// These macros are used to assemble the disassembler functions -#define MakeDisF(fn, b) \ - void fn DisFInterface { \ - ssprintf(output, "(%8.8x) ", code); \ - b; \ - } - -#undef _Target_ -#undef _Branch_ -#undef _Funct_ -#undef _Rd_ -#undef _Rt_ -#undef _Rs_ -#undef _Sa_ -#undef _Im_ - -#define _Funct_ ((code ) & 0x3F) // The funct part of the instruction register -#define _Rd_ ((code >> 11) & 0x1F) // The rd part of the instruction register -#define _Rt_ ((code >> 16) & 0x1F) // The rt part of the instruction register -#define _Rs_ ((code >> 21) & 0x1F) // The rs part of the instruction register -#define _Sa_ ((code >> 6) & 0x1F) // The sa part of the instruction register -#define _Im_ ( code & 0xFFFF) // The immediate part of the instruction register - - -#define _rRs_ cpuRegs.GPR.r[_Rs_].UL[1], cpuRegs.GPR.r[_Rs_].UL[0] // Rs register -#define _rRt_ cpuRegs.GPR.r[_Rt_].UL[1], cpuRegs.GPR.r[_Rt_].UL[0] // Rt register -#define _rRd_ cpuRegs.GPR.r[_Rd_].UL[1], cpuRegs.GPR.r[_Rd_].UL[0] // Rd register -#define _rSa_ cpuRegs.GPR.r[_Sa_].UL[1], cpuRegs.GPR.r[_Sa_].UL[0] // Sa register - -#define _rFs_ cpuRegs.CP0.r[_Rd_] // Fs register - -#define _rRs32_ cpuRegs.GPR.r[_Rs_].UL[0] // Rs register -#define _rRt32_ cpuRegs.GPR.r[_Rt_].UL[0] // Rt register -#define _rRd32_ cpuRegs.GPR.r[_Rd_].UL[0] // Rd register -#define _rSa32_ cpuRegs.GPR.r[_Sa_].UL[0] // Sa register - - -#define _nRs_ _rRs_, disRNameGPR[_Rs_] -#define _nRt_ _rRt_, disRNameGPR[_Rt_] -#define _nRd_ _rRd_, disRNameGPR[_Rd_] -#define _nSa_ _rSa_, disRNameGPR[_Sa_] -#define _nRd0_ _rFs_, disRNameCP0[_Rd_] - -#define _nRs32_ _rRs32_, disRNameGPR[_Rs_] -#define _nRt32_ _rRt32_, disRNameGPR[_Rt_] -#define _nRd32_ _rRd32_, disRNameGPR[_Rd_] -#define _nSa32_ _rSa32_, disRNameGPR[_Sa_] - -#define _I_ _Im_, _Im_ -#define _Target_ ((cpuRegs.pc & 0xf0000000) + ((code & 0x03ffffff) * 4)) -#define _Branch_ (cpuRegs.pc + 4 + ((short)_Im_ * 4)) -#define _OfB_ _Im_, _nRs_ - -#define _Fsf_ ((code >> 21) & 0x03) -#define _Ftf_ ((code >> 23) & 0x03) - -// sap! it stands for string append. It's not a friendly name but for now it makes -// the copy-paste marathon of code below more readable! -#define _sap( str ) ssappendf( output, str, params - -#define dName(i) _sap("%-7s\t") i); -#define dGPR128(i) _sap("%8.8x_%8.8x_%8.8x_%8.8x (%s),") cpuRegs.GPR.r[i].UL[3], cpuRegs.GPR.r[i].UL[2], cpuRegs.GPR.r[i].UL[1], cpuRegs.GPR.r[i].UL[0], disRNameGPR[i]) -#define dGPR64(i) _sap("%8.8x_%8.8x (%s),") cpuRegs.GPR.r[i].UL[1], cpuRegs.GPR.r[i].UL[0], disRNameGPR[i]) -#define dGPR64U(i) _sap("%8.8x_%8.8x (%s),") cpuRegs.GPR.r[i].UL[3], cpuRegs.GPR.r[i].UL[2], disRNameGPR[i]) -#define dGPR32(i) _sap("%8.8x (%s),") cpuRegs.GPR.r[i].UL[0], disRNameGPR[i]) - -#define dCP032(i) _sap("%8.8x (%s),") cpuRegs.CP0.r[i], disRNameCP0[i]) - -#define dCP132(i) _sap("%f (%s),") fpuRegs.fpr[i].f, disRNameCP1[i]) -#define dCP1c32(i) _sap("%8.8x (%s),") fpuRegs.fprc[i], disRNameCP1c[i]) -#define dCP1acc() _sap("%f (ACC),") fpuRegs.ACC.f) - -#define dCP2128f(i) _sap("w=%f z=%f y=%f x=%f (%s),") VU0.VF[i].f.w, VU0.VF[i].f.z, VU0.VF[i].f.y, VU0.VF[i].f.x, disRNameCP2f[i]) -#define dCP232x(i) _sap("x=%f (%s),") VU0.VF[i].f.x, disRNameCP2f[i]) -#define dCP232y(i) _sap("y=%f (%s),") VU0.VF[i].f.y, disRNameCP2f[i]) -#define dCP232z(i) _sap("z=%f (%s),") VU0.VF[i].f.z, disRNameCP2f[i]) -#define dCP232w(i) _sap("w=%f (%s),") VU0.VF[i].f.w, disRNameCP2f[i]) -#define dCP2ACCf() _sap("w=%f z=%f y=%f x=%f (ACC),") VU0.ACC.f.w, VU0.ACC.f.z, VU0.ACC.f.y, VU0.ACC.f.x) -#define dCP232i(i) _sap("%8.8x (%s),") VU0.VI[i].UL, disRNameCP2i[i]) -#define dCP232iF(i) _sap("%f (%s),") VU0.VI[i].F, disRNameCP2i[i]) -#define dCP232f(i, j) _sap("Q %s=%f (%s),") CP2VFnames[j], VU0.VF[i].F[j], disRNameCP2f[i]) - -#define dHI64() _sap("%8.8x_%8.8x (%s),") cpuRegs.HI.UL[1], cpuRegs.HI.UL[0], "hi") -#define dLO64() _sap("%8.8x_%8.8x (%s),") cpuRegs.LO.UL[1], cpuRegs.LO.UL[0], "lo") -#define dImm() _sap("%4.4x (%d),") _Im_, _Im_) -#define dTarget() _sap("%8.8x,") _Target_) -#define dSa() _sap("%2.2x (%d),") _Sa_, _Sa_) -#define dSa32() _sap("%2.2x (%d),") _Sa_+32, _Sa_+32) -#define dOfB() _sap("%4.4x (%8.8x (%s)),") _Im_, cpuRegs.GPR.r[_Rs_].UL[0], disRNameGPR[_Rs_]) -#define dOffset() _sap("%8.8x,") _Branch_) -#define dCode() _sap("%8.8x,") (code >> 6) & 0xffffff) -#define dSaR() _sap("%8.8x,") cpuRegs.sa) - -struct sSymbol { - u32 addr; - char name[32]; -}; - -static sSymbol *dSyms = NULL; -static int nSymAlloc = 0; -static int nSyms = 0; - -void disR5900AddSym(u32 addr, const char *name) { - - assert( strlen(name) < 32 ); - - if( nSyms+1 >= nSymAlloc ) - { - // Realloc by threshold block sizes. - nSymAlloc += 64 + (nSyms / 4); - dSyms = (sSymbol*)realloc(dSyms, sizeof(sSymbol) * (nSymAlloc)); - } - - if (dSyms == NULL) return; - dSyms[nSyms].addr = addr; - strncpy(dSyms[nSyms].name, name, 32); - nSyms++; -} - -void disR5900FreeSyms() { - if (dSyms != NULL) { free(dSyms); dSyms = NULL; } - nSymAlloc = 0; - nSyms = 0; -} - -const char *disR5900GetSym(u32 addr) { - int i; - - if (dSyms == NULL) return NULL; - for (i=0; i laddr) { - laddr = dSyms[i].addr; - j = i; - } - } - if (j == -1) return NULL; - return dSyms[j].name; -} - -void dFindSym( string& output, u32 addr ) -{ - const char* label = disR5900GetSym( addr ); - if( label != NULL ) - output.append( label ); -} - -#define dAppendSym(addr) dFindSym( output, addr ) - -/********************************************************* -* Arithmetic with immediate operand * -* Format: OP rt, rs, immediate * -*********************************************************/ -MakeDisF(disADDI, dName("ADDI"); dGPR64(_Rt_); dGPR32(_Rs_); dImm();) -MakeDisF(disADDIU, dName("ADDIU"); dGPR64(_Rt_); dGPR32(_Rs_); dImm();) -MakeDisF(disANDI, dName("ANDI"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) -MakeDisF(disORI, dName("ORI"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) -MakeDisF(disSLTI, dName("SLTI"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) -MakeDisF(disSLTIU, dName("SLTIU"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) -MakeDisF(disXORI, dName("XORI"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) -MakeDisF(disDADDI, dName("DADDI"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) -MakeDisF(disDADDIU, dName("DADDIU"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) - -/********************************************************* -* Register arithmetic * -* Format: OP rd, rs, rt * -*********************************************************/ -MakeDisF(disADD, dName("ADD"); dGPR64(_Rd_); dGPR32(_Rs_); dGPR32(_Rt_);) -MakeDisF(disADDU, dName("ADDU"); dGPR64(_Rd_); dGPR32(_Rs_); dGPR32(_Rt_);) -MakeDisF(disDADD, dName("DADD"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) -MakeDisF(disDADDU, dName("DADDU"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) -MakeDisF(disSUB, dName("SUB"); dGPR64(_Rd_); dGPR32(_Rs_); dGPR32(_Rt_);) -MakeDisF(disSUBU, dName("SUBU"); dGPR64(_Rd_); dGPR32(_Rs_); dGPR32(_Rt_);) -MakeDisF(disDSUB, dName("DSUB"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) -MakeDisF(disDSUBU, dName("DSDBU"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) -MakeDisF(disAND, dName("AND"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) -MakeDisF(disOR, dName("OR"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) -MakeDisF(disXOR, dName("XOR"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) -MakeDisF(disNOR, dName("NOR"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) -MakeDisF(disSLT, dName("SLT"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) -MakeDisF(disSLTU, dName("SLTU"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) - -/********************************************************* -* Jump to target * -* Format: OP target * -*********************************************************/ -MakeDisF(disJ, dName("J"); dTarget(); dAppendSym(_Target_);) -MakeDisF(disJAL, dName("JAL"); dTarget(); dGPR32(31); dAppendSym(_Target_);) - -/********************************************************* -* Register jump * -* Format: OP rs, rd * -*********************************************************/ -MakeDisF(disJR, dName("JR"); dGPR32(_Rs_); dAppendSym(cpuRegs.GPR.r[_Rs_].UL[0]);) -MakeDisF(disJALR, dName("JALR"); dGPR32(_Rs_); dGPR32(_Rd_); dAppendSym(cpuRegs.GPR.r[_Rs_].UL[0]);) - -/********************************************************* -* Register mult/div & Register trap logic * -* Format: OP rs, rt * -*********************************************************/ -MakeDisF(disDIV, dName("DIV"); dGPR32(_Rs_); dGPR32(_Rt_);) -MakeDisF(disDIVU, dName("DIVU"); dGPR32(_Rs_); dGPR32(_Rt_);) -MakeDisF(disMULT, dName("MULT"); dGPR32(_Rs_); dGPR32(_Rt_); dGPR32(_Rd_);) -MakeDisF(disMULTU, dName("MULTU"); dGPR32(_Rs_); dGPR32(_Rt_); dGPR32(_Rd_);) - -/********************************************************* -* Load higher 16 bits of the first word in GPR with imm * -* Format: OP rt, immediate * -*********************************************************/ -MakeDisF(disLUI, dName("LUI"); dGPR64(_Rt_); dImm();) - -/********************************************************* -* Move from HI/LO to GPR * -* Format: OP rd * -*********************************************************/ -MakeDisF(disMFHI, dName("MFHI"); dGPR64(_Rd_); dHI64();) -MakeDisF(disMFLO, dName("MFLO"); dGPR64(_Rd_); dLO64();) - -/********************************************************* -* Move to GPR to HI/LO & Register jump * -* Format: OP rs * -*********************************************************/ -MakeDisF(disMTHI, dName("MTHI"); dHI64(); dGPR64(_Rs_);) -MakeDisF(disMTLO, dName("MTLO"); dLO64(); dGPR64(_Rs_);) - -/********************************************************* -* Shift arithmetic with constant shift * -* Format: OP rd, rt, sa * -*********************************************************/ -MakeDisF(disSLL, if (code) { dName("SLL"); dGPR64(_Rd_); dGPR32(_Rt_); dSa(); } else { dName("NOP"); }) -MakeDisF(disDSLL, dName("DSLL"); dGPR64(_Rd_); dGPR64(_Rt_); dSa();) -MakeDisF(disDSLL32, dName("DSLL32"); dGPR64(_Rd_); dGPR64(_Rt_); dSa32();) -MakeDisF(disSRA, dName("SRA"); dGPR64(_Rd_); dGPR32(_Rt_); dSa();) -MakeDisF(disDSRA, dName("DSRA"); dGPR64(_Rd_); dGPR64(_Rt_); dSa();) -MakeDisF(disDSRA32, dName("DSRA32"); dGPR64(_Rd_); dGPR64(_Rt_); dSa32();) -MakeDisF(disSRL, dName("SRL"); dGPR64(_Rd_); dGPR32(_Rt_); dSa();) -MakeDisF(disDSRL, dName("DSRL"); dGPR64(_Rd_); dGPR64(_Rt_); dSa();) -MakeDisF(disDSRL32, dName("DSRL32"); dGPR64(_Rd_); dGPR64(_Rt_); dSa32();) - -/********************************************************* -* Shift arithmetic with variant register shift * -* Format: OP rd, rt, rs * -*********************************************************/ -MakeDisF(disSLLV, dName("SLLV"); dGPR64(_Rd_); dGPR32(_Rt_); dGPR32(_Rs_);) -MakeDisF(disDSLLV, dName("DSLLV"); dGPR64(_Rd_); dGPR64(_Rt_); dGPR32(_Rs_);) -MakeDisF(disSRAV, dName("SRAV"); dGPR64(_Rd_); dGPR32(_Rt_); dGPR32(_Rs_);) -MakeDisF(disDSRAV, dName("DSRAV"); dGPR64(_Rd_); dGPR64(_Rt_); dGPR32(_Rs_);) -MakeDisF(disSRLV, dName("SRLV"); dGPR64(_Rd_); dGPR32(_Rt_); dGPR32(_Rs_);) -MakeDisF(disDSRLV, dName("DSRLV"); dGPR64(_Rd_); dGPR64(_Rt_); dGPR32(_Rs_);) - -/********************************************************* -* Load and store for GPR * -* Format: OP rt, offset(base) * -*********************************************************/ -MakeDisF(disLB, dName("LB"); dGPR64(_Rt_); dOfB();) -MakeDisF(disLBU, dName("LBU"); dGPR64(_Rt_); dOfB();) -MakeDisF(disLH, dName("LH"); dGPR64(_Rt_); dOfB();) -MakeDisF(disLHU, dName("LHU"); dGPR64(_Rt_); dOfB();) -MakeDisF(disLW, dName("LW"); dGPR64(_Rt_); dOfB();) -MakeDisF(disLWU, dName("LWU"); dGPR64(_Rt_); dOfB();) -MakeDisF(disLWL, dName("LWL"); dGPR64(_Rt_); dOfB();) -MakeDisF(disLWR, dName("LWR"); dGPR64(_Rt_); dOfB();) -MakeDisF(disLD, dName("LD"); dGPR64(_Rt_); dOfB();) -MakeDisF(disLDL, dName("LDL"); dGPR64(_Rt_); dOfB();) -MakeDisF(disLDR, dName("LDR"); dGPR64(_Rt_); dOfB();) -MakeDisF(disLQ, dName("LQ"); dGPR128(_Rt_); dOfB();) -MakeDisF(disSB, dName("SB"); dGPR64(_Rt_); dOfB();) -MakeDisF(disSH, dName("SH"); dGPR64(_Rt_); dOfB();) -MakeDisF(disSW, dName("SW"); dGPR64(_Rt_); dOfB();) -MakeDisF(disSWL, dName("SWL"); dGPR64(_Rt_); dOfB();) -MakeDisF(disSWR, dName("SWR"); dGPR64(_Rt_); dOfB();) -MakeDisF(disSD, dName("SD"); dGPR64(_Rt_); dOfB();) -MakeDisF(disSDL, dName("SDL"); dGPR64(_Rt_); dOfB();) -MakeDisF(disSDR, dName("SDR"); dGPR64(_Rt_); dOfB();) -MakeDisF(disSQ, dName("SQ"); dGPR128(_Rt_); dOfB();) - -/********************************************************* -* Register branch logic * -* Format: OP rs, rt, offset * -*********************************************************/ -MakeDisF(disBEQ, dName("BEQ"); dGPR64(_Rs_); dGPR64(_Rt_); dOffset();) -MakeDisF(disBNE, dName("BNE"); dGPR64(_Rs_); dGPR64(_Rt_); dOffset();) - -/********************************************************* -* Moves between GPR and COPx * -* Format: OP rt, rd * -*********************************************************/ -MakeDisF(disMFC0, dName("MFC0"); dGPR32(_Rt_); dCP032(_Rd_);) -MakeDisF(disMTC0, dName("MTC0"); dCP032(_Rd_); dGPR32(_Rt_);) - -/********************************************************* -* Register branch logic * -* Format: OP rs, offset * -*********************************************************/ - -MakeDisF(disBGEZ, dName("BGEZ"); dGPR64(_Rs_); dOffset();) -MakeDisF(disBGEZAL, dName("BGEZAL"); dGPR64(_Rs_); dOffset();) -MakeDisF(disBGTZ, dName("BGTZ"); dGPR64(_Rs_); dOffset();) -MakeDisF(disBLEZ, dName("BLEZ"); dGPR64(_Rs_); dOffset();) -MakeDisF(disBLTZ, dName("BLTZ"); dGPR64(_Rs_); dOffset();) -MakeDisF(disBLTZAL, dName("BLTZAL"); dGPR64(_Rs_); dOffset();) - - -/********************************************************* -* Register branch logic Likely * -* Format: OP rs, offset * -*********************************************************/ - - -MakeDisF(disBEQL, dName("BEQL"); dGPR64(_Rs_); dGPR64(_Rt_); dOffset();) -MakeDisF(disBNEL, dName("BNEL"); dGPR64(_Rs_); dGPR64(_Rt_); dOffset();) -MakeDisF(disBLEZL, dName("BLEZL"); dGPR64(_Rs_); dOffset();) -MakeDisF(disBGTZL, dName("BGTZL"); dGPR64(_Rs_); dOffset();) -MakeDisF(disBLTZL, dName("BLTZL"); dGPR64(_Rs_); dOffset();) -MakeDisF(disBGEZL, dName("BGEZL"); dGPR64(_Rs_); dOffset();) -MakeDisF(disBLTZALL, dName("BLTZALL"); dGPR64(_Rs_); dOffset();) -MakeDisF(disBGEZALL, dName("BGEZALL"); dGPR64(_Rs_); dOffset();) - - -/********************************************************* -* COP0 opcodes * -* * -*********************************************************/ - -MakeDisF(disBC0F, dName("BC0F"); dOffset();) -MakeDisF(disBC0T, dName("BC0T"); dOffset();) -MakeDisF(disBC0FL, dName("BC0FL"); dOffset();) -MakeDisF(disBC0TL, dName("BC0TL"); dOffset();) - -MakeDisF(disTLBR, dName("TLBR");) -MakeDisF(disTLBWI, dName("TLBWI");) -MakeDisF(disTLBWR, dName("TLBWR");) -MakeDisF(disTLBP, dName("TLBP");) -MakeDisF(disERET, dName("ERET");) -MakeDisF(disEI, dName("EI");) -MakeDisF(disDI, dName("DI");) - -/********************************************************* -* COP1 opcodes * -* * -*********************************************************/ - -#define _Ft_ _Rt_ -#define _Fs_ _Rd_ -#define _Fd_ _Sa_ - -MakeDisF(disMFC1, dName("MFC1"); dGPR64(_Rt_); dCP132(_Fs_);) -MakeDisF(disCFC1, dName("CFC1"); dGPR64(_Rt_); dCP1c32(_Fs_);) -MakeDisF(disMTC1, dName("MTC1"); dCP132(_Fs_); dGPR64(_Rt_);) -MakeDisF(disCTC1, dName("CTC1"); dCP1c32(_Fs_); dGPR64(_Rt_);) - -MakeDisF(disBC1F, dName("BC1F");) -MakeDisF(disBC1T, dName("BC1T");) -MakeDisF(disBC1FL, dName("BC1FL");) -MakeDisF(disBC1TL, dName("BC1TL");) - -MakeDisF(disADDs, dName("ADDs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) -MakeDisF(disSUBs, dName("SUBs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) -MakeDisF(disMULs, dName("MULs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) -MakeDisF(disDIVs, dName("DIVs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) -MakeDisF(disSQRTs, dName("SQRTs"); dCP132(_Fd_); dCP132(_Ft_);) -MakeDisF(disABSs, dName("ABSs"); dCP132(_Fd_); dCP132(_Fs_);) -MakeDisF(disMOVs, dName("MOVs"); dCP132(_Fd_); dCP132(_Fs_);) -MakeDisF(disNEGs, dName("NEGs"); dCP132(_Fd_); dCP132(_Fs_);) -MakeDisF(disRSQRTs, dName("RSQRTs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) -MakeDisF(disADDAs, dName("ADDAs"); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) -MakeDisF(disSUBAs, dName("SUBAs"); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) -MakeDisF(disMULAs, dName("MULAs"); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) -MakeDisF(disMADDs, dName("MADDs"); dCP132(_Fd_); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) -MakeDisF(disMSUBs, dName("MSUBs"); dCP132(_Fd_); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) -MakeDisF(disMADDAs, dName("MADDAs"); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) -MakeDisF(disMSUBAs, dName("MSUBAs"); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) -MakeDisF(disCVTWs, dName("CVTWs"); dCP132(_Fd_); dCP132(_Fs_);) -MakeDisF(disMAXs, dName("MAXs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) -MakeDisF(disMINs, dName("MINs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) -MakeDisF(disCFs, dName("CFs"); dCP132(_Fs_); dCP132(_Ft_);) -MakeDisF(disCEQs, dName("CEQs"); dCP132(_Fs_); dCP132(_Ft_);) -MakeDisF(disCLTs, dName("CLTs"); dCP132(_Fs_); dCP132(_Ft_);) -MakeDisF(disCLEs, dName("CLEs"); dCP132(_Fs_); dCP132(_Ft_);) - -MakeDisF(disCVTSw, dName("CVTSw"); dCP132(_Fd_); dCP132(_Fs_);) - -/********************************************************* -* Load and store for COP1 * -* Format: OP rt, offset(base) * -*********************************************************/ - -MakeDisF(disLWC1, dName("LWC1"); dCP132(_Rt_); dOffset();) -MakeDisF(disSWC1, dName("SWC1"); dCP132(_Rt_); dOffset();) - -/********************************************************* -* Conditional Move * -* Format: OP rd, rs, rt * -*********************************************************/ - -MakeDisF(disMOVZ, dName("MOVZ"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) -MakeDisF(disMOVN, dName("MOVN"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) - -/********************************************************* -* MMI opcodes * -* * -*********************************************************/ - -MakeDisF(disMULT1, dName("MULT1");) -MakeDisF(disMULTU1, dName("MULTU1");) - -/********************************************************* -* MMI0 opcodes * -* * -*********************************************************/ - -MakeDisF(disPADDW, dName("PADDW");) -MakeDisF(disPADDH, dName("PADDH");) -MakeDisF(disPADDB, dName("PADDB");) - -MakeDisF(disPADDSW, dName("PADDSW");) -MakeDisF(disPADDSH, dName("PADDSH");) -MakeDisF(disPADDSB, dName("PADDSB");) - -MakeDisF(disPSUBW, dName("PSUBW");) -MakeDisF(disPSUBH, dName("PSUBH");) -MakeDisF(disPSUBB, dName("PSUBB");) - -MakeDisF(disPSUBSW, dName("PSUBSW");) -MakeDisF(disPSUBSH, dName("PSUBSH");) -MakeDisF(disPSUBSB, dName("PSUBSB");) - -MakeDisF(disPCGTW, dName("PCGTW");) -MakeDisF(disPCGTH, dName("PCGTH");) -MakeDisF(disPCGTB, dName("PCGTB");) - -MakeDisF(disPMAXW, dName("PMAXW");) -MakeDisF(disPMAXH, dName("PMAXH");) - -MakeDisF(disPEXTLW, dName("PEXTLW"); dGPR128(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) -MakeDisF(disPEXTLH, dName("PEXTLH"); dGPR128(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) -MakeDisF(disPEXTLB, dName("PEXTLB");) -MakeDisF(disPEXTS, dName("PEXTS");) - -MakeDisF(disPPACW, dName("PPACW");) -MakeDisF(disPPACH, dName("PPACH");) -MakeDisF(disPPACB, dName("PPACB");) -MakeDisF(disPPACS, dName("PPACS");) - -/********************************************************* -* MMI1 opcodes * -* * -*********************************************************/ - -MakeDisF(disPADSBH, dName("PADSBH");) - -MakeDisF(disPABSW, dName("PABSW");) -MakeDisF(disPABSH, dName("PABSH");) - -MakeDisF(disPCEQW, dName("PCEQW");) -MakeDisF(disPCEQH, dName("PCEQH");) -MakeDisF(disPCEQB, dName("PCEQB");) - -MakeDisF(disPMINW, dName("PMINW");) -MakeDisF(disPMINH, dName("PMINH");) - -MakeDisF(disPADDUW, dName("PADDUW");) -MakeDisF(disPADDUH, dName("PADDUH");) -MakeDisF(disPADDUB, dName("PADDUB");) - -MakeDisF(disPSUBUW, dName("PSUBUW");) -MakeDisF(disPSUBUH, dName("PSUBUH");) -MakeDisF(disPSUBUB, dName("PSUBUB");) - -MakeDisF(disPEXTUW, dName("PEXTUW"); dGPR128(_Rd_); dGPR64U(_Rs_); dGPR64U(_Rt_);) -MakeDisF(disPEXTUH, dName("PEXTUH"); dGPR128(_Rd_); dGPR64U(_Rs_); dGPR64U(_Rt_);) -MakeDisF(disPEXTUB, dName("PEXTUB");) - -MakeDisF(disQFSRV, dName("QFSRV");) - -/********************************************************* -* MMI2 opcodes * -* * -*********************************************************/ - -MakeDisF(disPMADDW, dName("PMADDW");) -MakeDisF(disPMADDH, dName("PMADDH");) - -MakeDisF(disPSLLVW, dName("PSLLVW");) -MakeDisF(disPSRLVW, dName("PSRLVW");) - -MakeDisF(disPMFHI, dName("PMFHI");) -MakeDisF(disPMFLO, dName("PMFLO");) - -MakeDisF(disPINTH, dName("PINTH");) - -MakeDisF(disPMULTW, dName("PMULTW");) -MakeDisF(disPMULTH, dName("PMULTH");) - -MakeDisF(disPDIVW, dName("PDIVW");) -MakeDisF(disPDIVH, dName("PDIVH");) - -MakeDisF(disPCPYLD, dName("PCPYLD"); dGPR128(_Rd_); dGPR128(_Rs_); dGPR128(_Rt_);) - -MakeDisF(disPAND, dName("PAND"); dGPR128(_Rd_); dGPR128(_Rs_); dGPR128(_Rt_);) -MakeDisF(disPXOR, dName("PXOR"); dGPR128(_Rd_); dGPR128(_Rs_); dGPR128(_Rt_);) - -MakeDisF(disPMSUBW, dName("PMSUBW");) -MakeDisF(disPMSUBH, dName("PMSUBH");) - -MakeDisF(disPHMADH, dName("PHMADH");) -MakeDisF(disPHMSBH, dName("PHMSBH");) - -MakeDisF(disPEXEW, dName("PEXEW");) -MakeDisF(disPEXEH, dName("PEXEH");) - -MakeDisF(disPREVH, dName("PREVH");) - -MakeDisF(disPDIVBW, dName("PDIVBW");) - -MakeDisF(disPROT3W, dName("PROT3W");) - -/********************************************************* -* MMI3 opcodes * -* * -*********************************************************/ - -MakeDisF(disPMADDUW, dName("PMADDUW");) - -MakeDisF(disPSRAVW, dName("PSRAVW");) - -MakeDisF(disPMTHI, dName("PMTHI");) -MakeDisF(disPMTLO, dName("PMTLO");) - -MakeDisF(disPINTEH, dName("PINTEH");) - -MakeDisF(disPMULTUW, dName("PMULTUW");) -MakeDisF(disPDIVUW, dName("PDIVUW");) - -MakeDisF(disPCPYUD, dName("PCPYUD"); dGPR128(_Rd_); dGPR128(_Rt_); dGPR128(_Rs_);) - -MakeDisF(disPOR, dName("POR"); dGPR128(_Rd_); dGPR128(_Rs_); dGPR128(_Rt_);) -MakeDisF(disPNOR, dName("PNOR"); dGPR128(_Rd_); dGPR128(_Rs_); dGPR128(_Rt_);) - -MakeDisF(disPEXCH, dName("PEXCH");) -MakeDisF(disPEXCW, dName("PEXCW");) - -MakeDisF(disPCPYH, dName("PCPYH"); dGPR128(_Rd_); dGPR128(_Rt_);) - -/********************************************************* -* COP2 opcodes * -* * -*********************************************************/ - -#define _Ft_ _Rt_ -#define _Fs_ _Rd_ -#define _Fd_ _Sa_ - -#define _X code>>24 -#define _Y code>>23 -#define _Z code>>22 -#define _W code>>21 - -MakeDisF(disLQC2, dName("LQC2"); dCP2128f(_Rt_); dOfB();) -MakeDisF(disSQC2, dName("SQC2"); dCP2128f(_Rt_); dOfB();) - -MakeDisF(disQMFC2, dName("QMFC2");) -MakeDisF(disQMTC2, dName("QMTC2");) -MakeDisF(disCFC2, dName("CFC2"); dGPR32(_Rt_); dCP232i(_Fs_);) -MakeDisF(disCTC2, dName("CTC2"); dCP232i(_Fs_); dGPR32(_Rt_);) - -MakeDisF(disBC2F, dName("BC2F");) -MakeDisF(disBC2T, dName("BC2T");) -MakeDisF(disBC2FL, dName("BC2FL");) -MakeDisF(disBC2TL, dName("BC2TL");) - -// SPEC1 -MakeDisF(disVADD, dName("VADD");) -MakeDisF(disVADDx, dName("VADDx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) -MakeDisF(disVADDy, dName("VADDy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) -MakeDisF(disVADDz, dName("VADDz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) -MakeDisF(disVADDw, dName("VADDw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) -MakeDisF(disVADDq, dName("VADDq"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_Q);) -MakeDisF(disVADDi, dName("VADDi"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_I);) -MakeDisF(disVSUB, dName("VSUB");) -MakeDisF(disVSUBx, dName("VSUBx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) -MakeDisF(disVSUBy, dName("VSUBy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) -MakeDisF(disVSUBz, dName("VSUBz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) -MakeDisF(disVSUBw, dName("VSUBw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) -MakeDisF(disVSUBq, dName("VSUBq");) -MakeDisF(disVSUBi, dName("VSUBi");) -MakeDisF(disVMADD, dName("VMADD");) -MakeDisF(disVMADDx, dName("VMADDx"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) -MakeDisF(disVMADDy, dName("VMADDy"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) -MakeDisF(disVMADDz, dName("VMADDz"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) -MakeDisF(disVMADDw, dName("VMADDw"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) -MakeDisF(disVMADDq, dName("VMADDq");) -MakeDisF(disVMADDi, dName("VMADDi");) -MakeDisF(disVMSUB, dName("VMSUB");) -MakeDisF(disVMSUBx, dName("VMSUBx");) -MakeDisF(disVMSUBy, dName("VMSUBy");) -MakeDisF(disVMSUBz, dName("VMSUBz");) -MakeDisF(disVMSUBw, dName("VMSUBw");) -MakeDisF(disVMSUBq, dName("VMSUBq");) -MakeDisF(disVMSUBi, dName("VMSUBi");) -MakeDisF(disVMAX, dName("VMAX");) -MakeDisF(disVMAXx, dName("VMAXx");) -MakeDisF(disVMAXy, dName("VMAXy");) -MakeDisF(disVMAXz, dName("VMAXz");) -MakeDisF(disVMAXw, dName("VMAXw");) -MakeDisF(disVMAXi, dName("VMAXi");) -MakeDisF(disVMINI, dName("VMINI");) -MakeDisF(disVMINIx, dName("VMINIx");) -MakeDisF(disVMINIy, dName("VMINIy");) -MakeDisF(disVMINIz, dName("VMINIz");) -MakeDisF(disVMINIw, dName("VMINIw");) -MakeDisF(disVMINIi, dName("VMINIi");) -MakeDisF(disVMUL, dName("VMUL");) -MakeDisF(disVMULx, dName("VMULx");) -MakeDisF(disVMULy, dName("VMULy");) -MakeDisF(disVMULz, dName("VMULz");) -MakeDisF(disVMULw, dName("VMULw");) -MakeDisF(disVMULq, dName("VMULq");) -MakeDisF(disVMULi, dName("VMULi");) -MakeDisF(disVIADD, dName("VIADD");) -MakeDisF(disVIADDI, dName("VIADDI");) -MakeDisF(disVISUB, dName("VISUB");) -MakeDisF(disVIAND, dName("VIAND");) -MakeDisF(disVIOR, dName("VIOR");) -MakeDisF(disVOPMSUB, dName("VOPMSUB");) -MakeDisF(disVCALLMS, dName("VCALLMS");) -MakeDisF(disVCALLMSR, dName("VCALLMSR");) - -// SPEC2 -MakeDisF(disVADDA, dName("VADDA");) -MakeDisF(disVADDAx, dName("VADDAx");) -MakeDisF(disVADDAy, dName("VADDAy");) -MakeDisF(disVADDAz, dName("VADDAz");) -MakeDisF(disVADDAw, dName("VADDAw");) -MakeDisF(disVADDAq, dName("VADDAq");) -MakeDisF(disVADDAi, dName("VADDAi");) -MakeDisF(disVMADDA, dName("VMADDA");) -MakeDisF(disVMADDAx, dName("VMADDAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) -MakeDisF(disVMADDAy, dName("VMADDAy"); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) -MakeDisF(disVMADDAz, dName("VMADDAz"); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) -MakeDisF(disVMADDAw, dName("VMADDAw"); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) -MakeDisF(disVMADDAq, dName("VMADDAq");) -MakeDisF(disVMADDAi, dName("VMADDAi");) -MakeDisF(disVSUBAx, dName("VSUBAx");) -MakeDisF(disVSUBAy, dName("VSUBAy");) -MakeDisF(disVSUBAz, dName("VSUBAz");) -MakeDisF(disVSUBAw, dName("VSUBAw");) -MakeDisF(disVMSUBAx, dName("VMSUBAx");) -MakeDisF(disVMSUBAy, dName("VMSUBAy");) -MakeDisF(disVMSUBAz, dName("VMSUBAz");) -MakeDisF(disVMSUBAw, dName("VMSUBAw");) -MakeDisF(disVITOF0, dName("VITOF0");) -MakeDisF(disVITOF4, dName("VITOF4");) -MakeDisF(disVITOF12, dName("VITOF12");) -MakeDisF(disVITOF15, dName("VITOF15");) -MakeDisF(disVFTOI0, dName("VFTOI0");) -MakeDisF(disVFTOI4, dName("VFTOI4");) -MakeDisF(disVFTOI12, dName("VFTOI12");) -MakeDisF(disVFTOI15, dName("VFTOI15");) -MakeDisF(disVMULA, dName("VMULA");) -MakeDisF(disVMULAx, dName("VMULAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) -MakeDisF(disVMULAy, dName("VMULAy");) -MakeDisF(disVMULAz, dName("VMULAz");) -MakeDisF(disVMULAw, dName("VMULAw");) -MakeDisF(disVMOVE, dName("VMOVE"); dCP2128f(_Ft_); dCP2128f(_Fs_);) -MakeDisF(disVMR32, dName("VMR32");) -MakeDisF(disVDIV, dName("VDIV");) -MakeDisF(disVSQRT, dName("VSQRT"); dCP232f(_Ft_, _Ftf_);) -MakeDisF(disVRSQRT, dName("VRSQRT");) -MakeDisF(disVRNEXT, dName("VRNEXT");) -MakeDisF(disVRGET, dName("VRGET");) -MakeDisF(disVRINIT, dName("VRINIT");) -MakeDisF(disVRXOR, dName("VRXOR");) -MakeDisF(disVWAITQ, dName("VWAITQ");) - -/********************************************************* -* Special purpose instructions * -* Format: OP * -*********************************************************/ - -MakeDisF(disSYNC, dName("SYNC");) -MakeDisF(disBREAK, dName("BREAK");) -MakeDisF(disSYSCALL, dName("SYSCALL"); dCode();) -MakeDisF(disCACHE, ssappendf(output, "%-7s, %x,", params "CACHE", _Rt_); dOfB();) -MakeDisF(disPREF, dName("PREF");) - -MakeDisF(disMFSA, dName("MFSA"); dGPR64(_Rd_); dSaR();) -MakeDisF(disMTSA, dName("MTSA"); dGPR64(_Rs_); dSaR();) - -MakeDisF(disMTSAB, dName("MTSAB");dGPR64(_Rs_); dImm();) -MakeDisF(disMTSAH, dName("MTSAH");dGPR64(_Rs_); dImm();) - -MakeDisF(disTGE, dName("TGE"); dGPR64(_Rs_); dGPR64(_Rt_);) -MakeDisF(disTGEU, dName("TGEU"); dGPR64(_Rs_); dGPR64(_Rt_);) -MakeDisF(disTLT, dName("TLT"); dGPR64(_Rs_); dGPR64(_Rt_);) -MakeDisF(disTLTU, dName("TLTU"); dGPR64(_Rs_); dGPR64(_Rt_);) -MakeDisF(disTEQ, dName("TEQ"); dGPR64(_Rs_); dGPR64(_Rt_);) -MakeDisF(disTNE, dName("TNE"); dGPR64(_Rs_); dGPR64(_Rt_);) - -MakeDisF(disTGEI, dName("TGEI"); dGPR64(_Rs_); dImm();) -MakeDisF(disTGEIU, dName("TGEIU"); dGPR64(_Rs_); dImm();) -MakeDisF(disTLTI, dName("TLTI"); dGPR64(_Rs_); dImm();) -MakeDisF(disTLTIU, dName("TLTIU"); dGPR64(_Rs_); dImm();) -MakeDisF(disTEQI, dName("TEQI"); dGPR64(_Rs_); dImm();) -MakeDisF(disTNEI, dName("TNEI"); dGPR64(_Rs_); dImm();) - -/********************************************************* -* Unknown instruction (would generate an exception) * -* Format: ? * -*********************************************************/ -static MakeDisF(disNULL, dName("*** Bad OP ***");) - -TdisR5900F disR5900_MMI0[] = { // Subset of disMMI0 - disPADDW, disPSUBW, disPCGTW, disPMAXW, - disPADDH, disPSUBH, disPCGTH, disPMAXH, - disPADDB, disPSUBB, disPCGTB, disNULL, - disNULL, disNULL, disNULL, disNULL, - disPADDSW, disPSUBSW, disPEXTLW, disPPACW, - disPADDSH, disPSUBSH, disPEXTLH, disPPACH, - disPADDSB, disPSUBSB, disPEXTLB, disPPACB, - disNULL, disNULL, disPEXTS, disPPACS}; - -static void disMMI0( string& output, u32 code ) -{ - disR5900_MMI0[_Sa_]( output, code ); -} - -TdisR5900F disR5900_MMI1[] = { // Subset of disMMI1 - disNULL, disPABSW, disPCEQW, disPMINW, - disPADSBH, disPABSH, disPCEQH, disPMINH, - disNULL, disNULL, disPCEQB, disNULL, - disNULL, disNULL, disNULL, disNULL, - disPADDUW, disPSUBUW, disPEXTUW, disNULL, - disPADDUH, disPSUBUH, disPEXTUH, disNULL, - disPADDUB, disPSUBUB, disPEXTUB, disQFSRV, - disNULL, disNULL, disNULL, disNULL}; - -static void disMMI1( string& output, u32 code ) -{ - disR5900_MMI1[_Sa_]( output, code ); -} - -TdisR5900F disR5900_MMI2[] = { // Subset of disMMI2 - disPMADDW, disNULL, disPSLLVW, disPSRLVW, - disPMSUBW, disNULL, disNULL, disNULL, - disPMFHI, disPMFLO, disPINTH, disNULL, - disPMULTW, disPDIVW, disPCPYLD, disNULL, - disPMADDH, disPHMADH, disPAND, disPXOR, - disPMSUBH, disPHMSBH, disNULL, disNULL, - disNULL, disNULL, disPEXEH, disPREVH, - disPMULTH, disPDIVBW, disPEXEW, disPROT3W}; - -static void disMMI2( string& output, u32 code ) -{ - disR5900_MMI2[_Sa_]( output, code ); -} - -TdisR5900F disR5900_MMI3[] = { // Subset of disMMI3 - disPMADDUW, disNULL, disNULL, disPSRAVW, - disNULL, disNULL, disNULL, disNULL, - disPMTHI, disPMTLO, disPINTEH, disNULL, - disPMULTUW, disPDIVUW, disPCPYUD, disNULL, - disNULL, disNULL, disPOR, disPNOR, - disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disPEXCH, disPCPYH, - disNULL, disNULL, disPEXCW, disNULL}; - -static void disMMI3( string& output, u32 code ) -{ - disR5900_MMI3[_Sa_]( output, code ); -} - -TdisR5900F disR5900_MMI[] = { // Subset of disMMI - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disMMI0, disMMI2, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disMULT1, disMULTU1, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disMMI1, disMMI3, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; - -static void disMMI( string& output, u32 code ) -{ - disR5900_MMI[_Funct_]( output, code ); -} - - -TdisR5900F disR5900_COP0_BC0[] = { //subset of disCOP0 BC - disBC0F, disBC0T, disBC0FL, disBC0TL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, -}; - -static void disCOP0_BC0( string& output, u32 code ) -{ - disR5900_COP0_BC0[_Rt_]( output, code ); -} - -TdisR5900F disR5900_COP0_Func[] = { //subset of disCOP0 Function - disNULL, disTLBR, disTLBWI, disNULL, disNULL, disNULL, disTLBWR, disNULL, - disTLBP, disNULL, disNULL , disNULL, disNULL, disNULL, disNULL , disNULL, - disNULL, disNULL, disNULL , disNULL, disNULL, disNULL, disNULL , disNULL, - disERET, disNULL, disNULL , disNULL, disNULL, disNULL, disNULL , disNULL, - disNULL, disNULL, disNULL , disNULL, disNULL, disNULL, disNULL , disNULL, - disNULL, disNULL, disNULL , disNULL, disNULL, disNULL, disNULL , disNULL, - disNULL, disNULL, disNULL , disNULL, disNULL, disNULL, disNULL , disNULL, - disEI , disDI , disNULL , disNULL, disNULL, disNULL, disNULL , disNULL -}; -static void disCOP0_Func( string& output, u32 code ) -{ - disR5900_COP0_Func[_Funct_]( output, code ); -} - -TdisR5900F disR5900_COP0[] = { // Subset of disCOP0 - disMFC0, disNULL, disNULL, disNULL, disMTC0, disNULL, disNULL, disNULL, - disCOP0_BC0, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disCOP0_Func, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; - -static void disCOP0( string& output, u32 code ) -{ - disR5900_COP0[_Rs_]( output, code ); -} - -TdisR5900F disR5900_COP1_S[] = { //subset of disCOP1 S - disADDs, disSUBs, disMULs, disDIVs, disSQRTs, disABSs, disMOVs, disNEGs, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disRSQRTs, disNULL, - disADDAs, disSUBAs, disMULAs, disNULL, disMADDs, disMSUBs, disMADDAs, disMSUBAs, - disNULL, disNULL, disNULL, disNULL, disCVTWs, disNULL, disNULL, disNULL, - disMINs, disMAXs, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disCFs, disNULL, disCEQs, disNULL, disCLTs, disNULL, disCLEs, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, -}; - -static void disCOP1_S( string& output, u32 code ) -{ - disR5900_COP1_S[_Funct_]( output, code ); -} - -TdisR5900F disR5900_COP1_W[] = { //subset of disCOP1 W - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disCVTSw, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, -}; - -static void disCOP1_W( string& output, u32 code ) -{ - disR5900_COP1_W[_Funct_]( output, code ); -} - -TdisR5900F disR5900_COP1_BC1[] = { //subset of disCOP1 BC - disBC1F, disBC1T, disBC1FL, disBC1TL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, -}; - -static void disCOP1_BC1( string& output, u32 code ) -{ - disR5900_COP1_BC1[_Rt_]( output, code ); -} - -TdisR5900F disR5900_COP1[] = { // Subset of disCOP1 - disMFC1, disNULL, disCFC1, disNULL, disMTC1, disNULL, disCTC1, disNULL, - disCOP1_BC1, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disCOP1_S, disNULL, disNULL, disNULL, disCOP1_W, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; - -static void disCOP1( string& output, u32 code ) -{ - disR5900_COP1[_Rs_]( output, code ); -} - -TdisR5900F disR5900_COP2_SPEC2[] = { //subset of disCOP2 SPEC2 - disVADDAx, disVADDAy, disVADDAz, disVADDAw, disVSUBAx, disVSUBAy, disVSUBAz, disVSUBAw, - disVMADDAx, disVMADDAy, disVMADDAz, disVMADDAw, disVMSUBAx, disVMSUBAy, disVMSUBAz, disVMSUBAw, - disVITOF0, disVITOF4, disVITOF12, disVITOF15, disVFTOI0, disVFTOI4, disVFTOI12, disVFTOI15, - disVMULAx, disVMULAy, disVMULAz, disVMULAw, disNULL, disNULL, disNULL, disNULL, - disVADDAq, disVMADDAq, disVADDAi, disVMADDAi, disNULL, disNULL, disNULL, disNULL, - disVADDA, disVMADDA, disVMULA, disNULL, disNULL, disNULL, disNULL, disNULL, - disVMOVE, disVMR32, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disVDIV, disVSQRT, disVRSQRT, disVWAITQ, disNULL, disNULL, disNULL, disNULL, - disVRNEXT, disVRGET, disVRINIT, disVRXOR, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, -}; - -static void disCOP2_SPEC2( string& output, u32 code ) -{ - disR5900_COP2_SPEC2[(code & 0x3) | ((code >> 4) & 0x7c)]( output, code ); -} - -TdisR5900F disR5900_COP2_SPEC1[] = { //subset of disCOP2 SPEC1 - disVADDx, disVADDy, disVADDz, disVADDw, disVSUBx, disVSUBy, disVSUBz, disVSUBw, - disVMADDx, disVMADDy, disVMADDz, disVMADDw, disVMSUBx, disVMSUBy, disVMSUBz, disVMSUBw, - disVMAXx, disVMAXy, disVMAXz, disVMAXw, disVMINIx, disVMINIy, disVMINIz, disVMINIw, - disVMULx, disVMULy, disVMULz, disVMULw, disVMULq, disVMAXi, disVMULi, disVMINIi, - disVADDq, disVMADDq, disVADDi, disVMADDi, disVSUBq, disVMSUBq, disVSUBi, disVMSUBi, - disVADD, disVMADD, disVMUL, disVMAX, disVSUB, disVMSUB, disVOPMSUB, disVMINI, - disVIADD, disVISUB, disVIADDI, disNULL, disVIAND, disVIOR, disNULL, disNULL, - disVCALLMS, disVCALLMSR, disNULL, disNULL, disCOP2_SPEC2, disCOP2_SPEC2, disCOP2_SPEC2, disCOP2_SPEC2, -}; - -static void disCOP2_SPEC1( string& output, u32 code ) -{ - disR5900_COP2_SPEC1[_Funct_]( output, code ); -} - -TdisR5900F disR5900_COP2_BC2[] = { //subset of disCOP2 BC - disBC2F, disBC2T, disBC2FL, disBC2TL, disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, - disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, -}; - -static void disCOP2_BC2( string& output, u32 code ) -{ - disR5900_COP2_BC2[_Rt_]( output, code ); -} - -TdisR5900F disR5900_COP2[] = { // Subset of disCOP2 - disNULL, disQMFC2, disCFC2, disNULL, disNULL, disQMTC2, disCTC2, disNULL, - disCOP2_BC2, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, - disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, - disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1}; - -static void disCOP2( string& output, u32 code ) -{ - disR5900_COP2[_Rs_]( output, code ); -} - -TdisR5900F disR5900_REGIMM[] = { // Subset of disREGIMM - disBLTZ, disBGEZ, disBLTZL, disBGEZL, disNULL, disNULL, disNULL, disNULL, - disTGEI, disTGEIU, disTLTI, disTLTIU, disTEQI, disNULL, disTNEI, disNULL, - disBLTZAL, disBGEZAL, disBLTZALL, disBGEZALL, disNULL, disNULL, disNULL, disNULL, - disMTSAB, disMTSAH , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; - -static void disREGIMM( string& output, u32 code ) -{ - disR5900_REGIMM[_Rt_]( output, code ); -} - -TdisR5900F disR5900_SPECIAL[] = { - disSLL, disNULL, disSRL, disSRA, disSLLV, disNULL, disSRLV, disSRAV, - disJR, disJALR, disMOVZ, disMOVN, disSYSCALL, disBREAK,disNULL, disSYNC, - disMFHI, disMTHI, disMFLO, disMTLO, disDSLLV, disNULL, disDSRLV, disDSRAV, - disMULT, disMULTU,disDIV, disDIVU, disNULL, disNULL, disNULL, disNULL, - disADD, disADDU, disSUB, disSUBU, disAND, disOR, disXOR, disNOR, - disMFSA , disMTSA, disSLT, disSLTU, disDADD, disDADDU,disDSUB, disDSUBU, - disTGE, disTGEU, disTLT, disTLTU, disTEQ, disNULL, disTNE, disNULL, - disDSLL, disNULL, disDSRL, disDSRA, disDSLL32, disNULL, disDSRL32,disDSRA32 }; - -static void disSPECIAL( string& output, u32 code ) -{ - disR5900_SPECIAL[_Funct_]( output, code ); -} - -TdisR5900F disR5900[] = { - disSPECIAL, disREGIMM, disJ , disJAL , disBEQ , disBNE , disBLEZ , disBGTZ , - disADDI , disADDIU , disSLTI, disSLTIU, disANDI, disORI , disXORI , disLUI , - disCOP0 , disCOP1 , disCOP2, disNULL , disBEQL, disBNEL, disBLEZL, disBGTZL, - disDADDI , disDADDIU, disLDL , disLDR , disMMI , disNULL, disLQ , disSQ , - disLB , disLH , disLWL , disLW , disLBU , disLHU , disLWR , disLWU , - disSB , disSH , disSWL , disSW , disSDL , disSDR , disSWR , disCACHE, - disNULL , disLWC1 , disNULL, disPREF , disNULL, disNULL, disLQC2 , disLD , - disNULL , disSWC1 , disNULL, disNULL , disNULL, disNULL, disSQC2 , disSD }; - -void disR5900F( string& output, u32 code ) -{ - disR5900[code >> 26]( output, code ); -} - -// returns a string representation of the cpuRegs current instruction. -// The return value of this method is *not* thread safe! -const string& DisR5900CurrentState::getString() -{ - result.clear(); - disR5900F( result, cpuRegs.code ); - return result; -} - -const char* DisR5900CurrentState::getCString() -{ - result.clear(); - disR5900F( result, cpuRegs.code ); - return result.c_str(); -} - -DisR5900CurrentState disR5900Current; - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +using namespace std; + +#include "Debug.h" +#include "R5900.h" +#include "VU.h" + +const char * const disRNameCP2f[] = { + "VF00", "VF01", "VF02", "VF03", "VF04", "VF05", "VF06", "VF07", + "VF08", "VF09", "VF10", "VF11", "VF12", "VF13", "VF14", "VF15", + "VF16", "VF17", "VF18", "VF19", "VF20", "VF21", "VF22", "VF23", + "VF24", "VF25", "VF26", "VF27", "VF28", "VF29", "VF30", "VF31"}; + +const char * const disRNameCP2i[] = { + "VI00", "VI01", "VI02", "VI03", "VI04", "VI05", "VI06", "VI07", + "VI08", "VI09", "VI10", "VI11", "VI12", "VI13", "VI14", "VI15", + "Status", "MAC", "Clip", "*RES*", "R", "I", "Q", "*RES*", + "*RES*", "*RES*", "TPC", "CMSAR0", "FBRST", "VPU-STAT", "*RES*", "CMSAR1"}; + +const char * const CP2VFnames[] = { "x", "y", "z", "w" }; + +namespace R5900 +{ + +// Names of registers +const char * const disRNameGPR[] = { + "r0", "at", "v0", "v1", "a0", "a1","a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5","t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5","s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp","fp", "ra", "hi", "lo"}; // lo,hi used in rec + +const char * const disRNameCP0[] = { + "Index" , "Random" , "EntryLo0" , "EntryLo1", "Context" , "PageMask" , "Wired" , "*RES*", + "BadVAddr" , "Count" , "EntryHi" , "Compare" , "Status" , "Cause" , "ExceptPC" , "PRevID", + "Config" , "LLAddr" , "WatchLo" , "WatchHi" , "*RES*" , "*RES*" , "*RES*" , "Debug", + "DEPC" , "PerfCnt" , "ErrCtl" , "CacheErr", "TagLo" , "TagHi" , "ErrorEPC" , "DESAVE"}; + +const char * const disRNameCP1[] = { + "FPR0" , "FPR1" , "FPR2" , "FPR3" , "FPR4" , "FPR5" , "FPR6" , "FPR7", + "FPR8" , "FPR9" , "FPR10", "FPR11", "FPR12", "FPR13", "FPR14", "FPR15", + "FPR16", "FPR17", "FPR18", "FPR19", "FPR20", "FPR21", "FPR22", "FPR23", + "FPR24", "FPR25", "FPR26", "FPR27", "FPR28", "FPR29", "FPR30", "FPR31"}; + +const char * const disRNameCP1c[] = { + "FRevID", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", + "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", + "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", + "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "*RES*", "FStatus"}; + +// Type definition of our functions +#define DisFInterface (string& output, u32 code) +#define DisFInterfaceT (string&, u32) +#define DisFInterfaceN (output, code) + +typedef void (*TdisR5900F)DisFInterface; + +// These macros are used to assemble the disassembler functions +#define MakeDisF(fn, b) \ + void fn DisFInterface { \ + ssprintf(output, "(%8.8x) ", code); \ + b; \ + } + +#undef _Target_ +#undef _Branch_ +#undef _Funct_ +#undef _Rd_ +#undef _Rt_ +#undef _Rs_ +#undef _Sa_ +#undef _Im_ + +#define _Funct_ ((code ) & 0x3F) // The funct part of the instruction register +#define _Rd_ ((code >> 11) & 0x1F) // The rd part of the instruction register +#define _Rt_ ((code >> 16) & 0x1F) // The rt part of the instruction register +#define _Rs_ ((code >> 21) & 0x1F) // The rs part of the instruction register +#define _Sa_ ((code >> 6) & 0x1F) // The sa part of the instruction register +#define _Im_ ( code & 0xFFFF) // The immediate part of the instruction register + + +#define _rRs_ cpuRegs.GPR.r[_Rs_].UL[1], cpuRegs.GPR.r[_Rs_].UL[0] // Rs register +#define _rRt_ cpuRegs.GPR.r[_Rt_].UL[1], cpuRegs.GPR.r[_Rt_].UL[0] // Rt register +#define _rRd_ cpuRegs.GPR.r[_Rd_].UL[1], cpuRegs.GPR.r[_Rd_].UL[0] // Rd register +#define _rSa_ cpuRegs.GPR.r[_Sa_].UL[1], cpuRegs.GPR.r[_Sa_].UL[0] // Sa register + +#define _rFs_ cpuRegs.CP0.r[_Rd_] // Fs register + +#define _rRs32_ cpuRegs.GPR.r[_Rs_].UL[0] // Rs register +#define _rRt32_ cpuRegs.GPR.r[_Rt_].UL[0] // Rt register +#define _rRd32_ cpuRegs.GPR.r[_Rd_].UL[0] // Rd register +#define _rSa32_ cpuRegs.GPR.r[_Sa_].UL[0] // Sa register + + +#define _nRs_ _rRs_, disRNameGPR[_Rs_] +#define _nRt_ _rRt_, disRNameGPR[_Rt_] +#define _nRd_ _rRd_, disRNameGPR[_Rd_] +#define _nSa_ _rSa_, disRNameGPR[_Sa_] +#define _nRd0_ _rFs_, disRNameCP0[_Rd_] + +#define _nRs32_ _rRs32_, disRNameGPR[_Rs_] +#define _nRt32_ _rRt32_, disRNameGPR[_Rt_] +#define _nRd32_ _rRd32_, disRNameGPR[_Rd_] +#define _nSa32_ _rSa32_, disRNameGPR[_Sa_] + +#define _I_ _Im_, _Im_ +#define _Target_ ((cpuRegs.pc & 0xf0000000) + ((code & 0x03ffffff) * 4)) +#define _Branch_ (cpuRegs.pc + 4 + ((short)_Im_ * 4)) +#define _OfB_ _Im_, _nRs_ + +#define _Fsf_ ((code >> 21) & 0x03) +#define _Ftf_ ((code >> 23) & 0x03) + +// sap! it stands for string append. It's not a friendly name but for now it makes +// the copy-paste marathon of code below more readable! +#define _sap( str ) ssappendf( output, str, params + +#define dName(i) _sap("%-7s\t") i); +#define dGPR128(i) _sap("%8.8x_%8.8x_%8.8x_%8.8x (%s),") cpuRegs.GPR.r[i].UL[3], cpuRegs.GPR.r[i].UL[2], cpuRegs.GPR.r[i].UL[1], cpuRegs.GPR.r[i].UL[0], disRNameGPR[i]) +#define dGPR64(i) _sap("%8.8x_%8.8x (%s),") cpuRegs.GPR.r[i].UL[1], cpuRegs.GPR.r[i].UL[0], disRNameGPR[i]) +#define dGPR64U(i) _sap("%8.8x_%8.8x (%s),") cpuRegs.GPR.r[i].UL[3], cpuRegs.GPR.r[i].UL[2], disRNameGPR[i]) +#define dGPR32(i) _sap("%8.8x (%s),") cpuRegs.GPR.r[i].UL[0], disRNameGPR[i]) + +#define dCP032(i) _sap("%8.8x (%s),") cpuRegs.CP0.r[i], disRNameCP0[i]) + +#define dCP132(i) _sap("%f (%s),") fpuRegs.fpr[i].f, disRNameCP1[i]) +#define dCP1c32(i) _sap("%8.8x (%s),") fpuRegs.fprc[i], disRNameCP1c[i]) +#define dCP1acc() _sap("%f (ACC),") fpuRegs.ACC.f) + +#define dCP2128f(i) _sap("w=%f z=%f y=%f x=%f (%s),") VU0.VF[i].f.w, VU0.VF[i].f.z, VU0.VF[i].f.y, VU0.VF[i].f.x, disRNameCP2f[i]) +#define dCP232x(i) _sap("x=%f (%s),") VU0.VF[i].f.x, disRNameCP2f[i]) +#define dCP232y(i) _sap("y=%f (%s),") VU0.VF[i].f.y, disRNameCP2f[i]) +#define dCP232z(i) _sap("z=%f (%s),") VU0.VF[i].f.z, disRNameCP2f[i]) +#define dCP232w(i) _sap("w=%f (%s),") VU0.VF[i].f.w, disRNameCP2f[i]) +#define dCP2ACCf() _sap("w=%f z=%f y=%f x=%f (ACC),") VU0.ACC.f.w, VU0.ACC.f.z, VU0.ACC.f.y, VU0.ACC.f.x) +#define dCP232i(i) _sap("%8.8x (%s),") VU0.VI[i].UL, disRNameCP2i[i]) +#define dCP232iF(i) _sap("%f (%s),") VU0.VI[i].F, disRNameCP2i[i]) +#define dCP232f(i, j) _sap("Q %s=%f (%s),") CP2VFnames[j], VU0.VF[i].F[j], disRNameCP2f[i]) + +#define dHI64() _sap("%8.8x_%8.8x (%s),") cpuRegs.HI.UL[1], cpuRegs.HI.UL[0], "hi") +#define dLO64() _sap("%8.8x_%8.8x (%s),") cpuRegs.LO.UL[1], cpuRegs.LO.UL[0], "lo") +#define dImm() _sap("%4.4x (%d),") _Im_, _Im_) +#define dTarget() _sap("%8.8x,") _Target_) +#define dSa() _sap("%2.2x (%d),") _Sa_, _Sa_) +#define dSa32() _sap("%2.2x (%d),") _Sa_+32, _Sa_+32) +#define dOfB() _sap("%4.4x (%8.8x (%s)),") _Im_, cpuRegs.GPR.r[_Rs_].UL[0], disRNameGPR[_Rs_]) +#define dOffset() _sap("%8.8x,") _Branch_) +#define dCode() _sap("%8.8x,") (code >> 6) & 0xffffff) +#define dSaR() _sap("%8.8x,") cpuRegs.sa) + +struct sSymbol { + u32 addr; + char name[32]; +}; + +static sSymbol *dSyms = NULL; +static int nSymAlloc = 0; +static int nSyms = 0; + +void disR5900AddSym(u32 addr, const char *name) { + + assert( strlen(name) < 32 ); + + if( nSyms+1 >= nSymAlloc ) + { + // Realloc by threshold block sizes. + nSymAlloc += 64 + (nSyms / 4); + dSyms = (sSymbol*)realloc(dSyms, sizeof(sSymbol) * (nSymAlloc)); + } + + if (dSyms == NULL) return; + dSyms[nSyms].addr = addr; + strncpy(dSyms[nSyms].name, name, 32); + nSyms++; +} + +void disR5900FreeSyms() { + if (dSyms != NULL) { free(dSyms); dSyms = NULL; } + nSymAlloc = 0; + nSyms = 0; +} + +const char *disR5900GetSym(u32 addr) { + int i; + + if (dSyms == NULL) return NULL; + for (i=0; i laddr) { + laddr = dSyms[i].addr; + j = i; + } + } + if (j == -1) return NULL; + return dSyms[j].name; +} + +void dFindSym( string& output, u32 addr ) +{ + const char* label = disR5900GetSym( addr ); + if( label != NULL ) + output.append( label ); +} + +#define dAppendSym(addr) dFindSym( output, addr ) + +/********************************************************* +* Arithmetic with immediate operand * +* Format: OP rt, rs, immediate * +*********************************************************/ +MakeDisF(disADDI, dName("ADDI"); dGPR64(_Rt_); dGPR32(_Rs_); dImm();) +MakeDisF(disADDIU, dName("ADDIU"); dGPR64(_Rt_); dGPR32(_Rs_); dImm();) +MakeDisF(disANDI, dName("ANDI"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) +MakeDisF(disORI, dName("ORI"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) +MakeDisF(disSLTI, dName("SLTI"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) +MakeDisF(disSLTIU, dName("SLTIU"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) +MakeDisF(disXORI, dName("XORI"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) +MakeDisF(disDADDI, dName("DADDI"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) +MakeDisF(disDADDIU, dName("DADDIU"); dGPR64(_Rt_); dGPR64(_Rs_); dImm();) + +/********************************************************* +* Register arithmetic * +* Format: OP rd, rs, rt * +*********************************************************/ +MakeDisF(disADD, dName("ADD"); dGPR64(_Rd_); dGPR32(_Rs_); dGPR32(_Rt_);) +MakeDisF(disADDU, dName("ADDU"); dGPR64(_Rd_); dGPR32(_Rs_); dGPR32(_Rt_);) +MakeDisF(disDADD, dName("DADD"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disDADDU, dName("DADDU"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disSUB, dName("SUB"); dGPR64(_Rd_); dGPR32(_Rs_); dGPR32(_Rt_);) +MakeDisF(disSUBU, dName("SUBU"); dGPR64(_Rd_); dGPR32(_Rs_); dGPR32(_Rt_);) +MakeDisF(disDSUB, dName("DSUB"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disDSUBU, dName("DSDBU"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disAND, dName("AND"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disOR, dName("OR"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disXOR, dName("XOR"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disNOR, dName("NOR"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disSLT, dName("SLT"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disSLTU, dName("SLTU"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) + +/********************************************************* +* Jump to target * +* Format: OP target * +*********************************************************/ +MakeDisF(disJ, dName("J"); dTarget(); dAppendSym(_Target_);) +MakeDisF(disJAL, dName("JAL"); dTarget(); dGPR32(31); dAppendSym(_Target_);) + +/********************************************************* +* Register jump * +* Format: OP rs, rd * +*********************************************************/ +MakeDisF(disJR, dName("JR"); dGPR32(_Rs_); dAppendSym(cpuRegs.GPR.r[_Rs_].UL[0]);) +MakeDisF(disJALR, dName("JALR"); dGPR32(_Rs_); dGPR32(_Rd_); dAppendSym(cpuRegs.GPR.r[_Rs_].UL[0]);) + +/********************************************************* +* Register mult/div & Register trap logic * +* Format: OP rs, rt * +*********************************************************/ +MakeDisF(disDIV, dName("DIV"); dGPR32(_Rs_); dGPR32(_Rt_);) +MakeDisF(disDIVU, dName("DIVU"); dGPR32(_Rs_); dGPR32(_Rt_);) +MakeDisF(disMULT, dName("MULT"); dGPR32(_Rs_); dGPR32(_Rt_); dGPR32(_Rd_);) +MakeDisF(disMULTU, dName("MULTU"); dGPR32(_Rs_); dGPR32(_Rt_); dGPR32(_Rd_);) + +/********************************************************* +* Load higher 16 bits of the first word in GPR with imm * +* Format: OP rt, immediate * +*********************************************************/ +MakeDisF(disLUI, dName("LUI"); dGPR64(_Rt_); dImm();) + +/********************************************************* +* Move from HI/LO to GPR * +* Format: OP rd * +*********************************************************/ +MakeDisF(disMFHI, dName("MFHI"); dGPR64(_Rd_); dHI64();) +MakeDisF(disMFLO, dName("MFLO"); dGPR64(_Rd_); dLO64();) + +/********************************************************* +* Move to GPR to HI/LO & Register jump * +* Format: OP rs * +*********************************************************/ +MakeDisF(disMTHI, dName("MTHI"); dHI64(); dGPR64(_Rs_);) +MakeDisF(disMTLO, dName("MTLO"); dLO64(); dGPR64(_Rs_);) + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ +MakeDisF(disSLL, if (code) { dName("SLL"); dGPR64(_Rd_); dGPR32(_Rt_); dSa(); } else { dName("NOP"); }) +MakeDisF(disDSLL, dName("DSLL"); dGPR64(_Rd_); dGPR64(_Rt_); dSa();) +MakeDisF(disDSLL32, dName("DSLL32"); dGPR64(_Rd_); dGPR64(_Rt_); dSa32();) +MakeDisF(disSRA, dName("SRA"); dGPR64(_Rd_); dGPR32(_Rt_); dSa();) +MakeDisF(disDSRA, dName("DSRA"); dGPR64(_Rd_); dGPR64(_Rt_); dSa();) +MakeDisF(disDSRA32, dName("DSRA32"); dGPR64(_Rd_); dGPR64(_Rt_); dSa32();) +MakeDisF(disSRL, dName("SRL"); dGPR64(_Rd_); dGPR32(_Rt_); dSa();) +MakeDisF(disDSRL, dName("DSRL"); dGPR64(_Rd_); dGPR64(_Rt_); dSa();) +MakeDisF(disDSRL32, dName("DSRL32"); dGPR64(_Rd_); dGPR64(_Rt_); dSa32();) + +/********************************************************* +* Shift arithmetic with variant register shift * +* Format: OP rd, rt, rs * +*********************************************************/ +MakeDisF(disSLLV, dName("SLLV"); dGPR64(_Rd_); dGPR32(_Rt_); dGPR32(_Rs_);) +MakeDisF(disDSLLV, dName("DSLLV"); dGPR64(_Rd_); dGPR64(_Rt_); dGPR32(_Rs_);) +MakeDisF(disSRAV, dName("SRAV"); dGPR64(_Rd_); dGPR32(_Rt_); dGPR32(_Rs_);) +MakeDisF(disDSRAV, dName("DSRAV"); dGPR64(_Rd_); dGPR64(_Rt_); dGPR32(_Rs_);) +MakeDisF(disSRLV, dName("SRLV"); dGPR64(_Rd_); dGPR32(_Rt_); dGPR32(_Rs_);) +MakeDisF(disDSRLV, dName("DSRLV"); dGPR64(_Rd_); dGPR64(_Rt_); dGPR32(_Rs_);) + +/********************************************************* +* Load and store for GPR * +* Format: OP rt, offset(base) * +*********************************************************/ +MakeDisF(disLB, dName("LB"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLBU, dName("LBU"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLH, dName("LH"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLHU, dName("LHU"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLW, dName("LW"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLWU, dName("LWU"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLWL, dName("LWL"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLWR, dName("LWR"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLD, dName("LD"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLDL, dName("LDL"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLDR, dName("LDR"); dGPR64(_Rt_); dOfB();) +MakeDisF(disLQ, dName("LQ"); dGPR128(_Rt_); dOfB();) +MakeDisF(disSB, dName("SB"); dGPR64(_Rt_); dOfB();) +MakeDisF(disSH, dName("SH"); dGPR64(_Rt_); dOfB();) +MakeDisF(disSW, dName("SW"); dGPR64(_Rt_); dOfB();) +MakeDisF(disSWL, dName("SWL"); dGPR64(_Rt_); dOfB();) +MakeDisF(disSWR, dName("SWR"); dGPR64(_Rt_); dOfB();) +MakeDisF(disSD, dName("SD"); dGPR64(_Rt_); dOfB();) +MakeDisF(disSDL, dName("SDL"); dGPR64(_Rt_); dOfB();) +MakeDisF(disSDR, dName("SDR"); dGPR64(_Rt_); dOfB();) +MakeDisF(disSQ, dName("SQ"); dGPR128(_Rt_); dOfB();) + +/********************************************************* +* Register branch logic * +* Format: OP rs, rt, offset * +*********************************************************/ +MakeDisF(disBEQ, dName("BEQ"); dGPR64(_Rs_); dGPR64(_Rt_); dOffset();) +MakeDisF(disBNE, dName("BNE"); dGPR64(_Rs_); dGPR64(_Rt_); dOffset();) + +/********************************************************* +* Moves between GPR and COPx * +* Format: OP rt, rd * +*********************************************************/ +MakeDisF(disMFC0, dName("MFC0"); dGPR32(_Rt_); dCP032(_Rd_);) +MakeDisF(disMTC0, dName("MTC0"); dCP032(_Rd_); dGPR32(_Rt_);) + +/********************************************************* +* Register branch logic * +* Format: OP rs, offset * +*********************************************************/ + +MakeDisF(disBGEZ, dName("BGEZ"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBGEZAL, dName("BGEZAL"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBGTZ, dName("BGTZ"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBLEZ, dName("BLEZ"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBLTZ, dName("BLTZ"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBLTZAL, dName("BLTZAL"); dGPR64(_Rs_); dOffset();) + + +/********************************************************* +* Register branch logic Likely * +* Format: OP rs, offset * +*********************************************************/ + + +MakeDisF(disBEQL, dName("BEQL"); dGPR64(_Rs_); dGPR64(_Rt_); dOffset();) +MakeDisF(disBNEL, dName("BNEL"); dGPR64(_Rs_); dGPR64(_Rt_); dOffset();) +MakeDisF(disBLEZL, dName("BLEZL"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBGTZL, dName("BGTZL"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBLTZL, dName("BLTZL"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBGEZL, dName("BGEZL"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBLTZALL, dName("BLTZALL"); dGPR64(_Rs_); dOffset();) +MakeDisF(disBGEZALL, dName("BGEZALL"); dGPR64(_Rs_); dOffset();) + + +/********************************************************* +* COP0 opcodes * +* * +*********************************************************/ + +MakeDisF(disBC0F, dName("BC0F"); dOffset();) +MakeDisF(disBC0T, dName("BC0T"); dOffset();) +MakeDisF(disBC0FL, dName("BC0FL"); dOffset();) +MakeDisF(disBC0TL, dName("BC0TL"); dOffset();) + +MakeDisF(disTLBR, dName("TLBR");) +MakeDisF(disTLBWI, dName("TLBWI");) +MakeDisF(disTLBWR, dName("TLBWR");) +MakeDisF(disTLBP, dName("TLBP");) +MakeDisF(disERET, dName("ERET");) +MakeDisF(disEI, dName("EI");) +MakeDisF(disDI, dName("DI");) + +/********************************************************* +* COP1 opcodes * +* * +*********************************************************/ + +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +MakeDisF(disMFC1, dName("MFC1"); dGPR64(_Rt_); dCP132(_Fs_);) +MakeDisF(disCFC1, dName("CFC1"); dGPR64(_Rt_); dCP1c32(_Fs_);) +MakeDisF(disMTC1, dName("MTC1"); dCP132(_Fs_); dGPR64(_Rt_);) +MakeDisF(disCTC1, dName("CTC1"); dCP1c32(_Fs_); dGPR64(_Rt_);) + +MakeDisF(disBC1F, dName("BC1F");) +MakeDisF(disBC1T, dName("BC1T");) +MakeDisF(disBC1FL, dName("BC1FL");) +MakeDisF(disBC1TL, dName("BC1TL");) + +MakeDisF(disADDs, dName("ADDs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disSUBs, dName("SUBs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disMULs, dName("MULs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disDIVs, dName("DIVs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disSQRTs, dName("SQRTs"); dCP132(_Fd_); dCP132(_Ft_);) +MakeDisF(disABSs, dName("ABSs"); dCP132(_Fd_); dCP132(_Fs_);) +MakeDisF(disMOVs, dName("MOVs"); dCP132(_Fd_); dCP132(_Fs_);) +MakeDisF(disNEGs, dName("NEGs"); dCP132(_Fd_); dCP132(_Fs_);) +MakeDisF(disRSQRTs, dName("RSQRTs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disADDAs, dName("ADDAs"); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disSUBAs, dName("SUBAs"); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disMULAs, dName("MULAs"); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disMADDs, dName("MADDs"); dCP132(_Fd_); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disMSUBs, dName("MSUBs"); dCP132(_Fd_); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disMADDAs, dName("MADDAs"); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disMSUBAs, dName("MSUBAs"); dCP1acc(); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disCVTWs, dName("CVTWs"); dCP132(_Fd_); dCP132(_Fs_);) +MakeDisF(disMAXs, dName("MAXs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disMINs, dName("MINs"); dCP132(_Fd_); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disCFs, dName("CFs"); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disCEQs, dName("CEQs"); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disCLTs, dName("CLTs"); dCP132(_Fs_); dCP132(_Ft_);) +MakeDisF(disCLEs, dName("CLEs"); dCP132(_Fs_); dCP132(_Ft_);) + +MakeDisF(disCVTSw, dName("CVTSw"); dCP132(_Fd_); dCP132(_Fs_);) + +/********************************************************* +* Load and store for COP1 * +* Format: OP rt, offset(base) * +*********************************************************/ + +MakeDisF(disLWC1, dName("LWC1"); dCP132(_Rt_); dOffset();) +MakeDisF(disSWC1, dName("SWC1"); dCP132(_Rt_); dOffset();) + +/********************************************************* +* Conditional Move * +* Format: OP rd, rs, rt * +*********************************************************/ + +MakeDisF(disMOVZ, dName("MOVZ"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disMOVN, dName("MOVN"); dGPR64(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) + +/********************************************************* +* MMI opcodes * +* * +*********************************************************/ + +MakeDisF(disMULT1, dName("MULT1");) +MakeDisF(disMULTU1, dName("MULTU1");) + +/********************************************************* +* MMI0 opcodes * +* * +*********************************************************/ + +MakeDisF(disPADDW, dName("PADDW");) +MakeDisF(disPADDH, dName("PADDH");) +MakeDisF(disPADDB, dName("PADDB");) + +MakeDisF(disPADDSW, dName("PADDSW");) +MakeDisF(disPADDSH, dName("PADDSH");) +MakeDisF(disPADDSB, dName("PADDSB");) + +MakeDisF(disPSUBW, dName("PSUBW");) +MakeDisF(disPSUBH, dName("PSUBH");) +MakeDisF(disPSUBB, dName("PSUBB");) + +MakeDisF(disPSUBSW, dName("PSUBSW");) +MakeDisF(disPSUBSH, dName("PSUBSH");) +MakeDisF(disPSUBSB, dName("PSUBSB");) + +MakeDisF(disPCGTW, dName("PCGTW");) +MakeDisF(disPCGTH, dName("PCGTH");) +MakeDisF(disPCGTB, dName("PCGTB");) + +MakeDisF(disPMAXW, dName("PMAXW");) +MakeDisF(disPMAXH, dName("PMAXH");) + +MakeDisF(disPEXTLW, dName("PEXTLW"); dGPR128(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disPEXTLH, dName("PEXTLH"); dGPR128(_Rd_); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disPEXTLB, dName("PEXTLB");) +MakeDisF(disPEXTS, dName("PEXTS");) + +MakeDisF(disPPACW, dName("PPACW");) +MakeDisF(disPPACH, dName("PPACH");) +MakeDisF(disPPACB, dName("PPACB");) +MakeDisF(disPPACS, dName("PPACS");) + +/********************************************************* +* MMI1 opcodes * +* * +*********************************************************/ + +MakeDisF(disPADSBH, dName("PADSBH");) + +MakeDisF(disPABSW, dName("PABSW");) +MakeDisF(disPABSH, dName("PABSH");) + +MakeDisF(disPCEQW, dName("PCEQW");) +MakeDisF(disPCEQH, dName("PCEQH");) +MakeDisF(disPCEQB, dName("PCEQB");) + +MakeDisF(disPMINW, dName("PMINW");) +MakeDisF(disPMINH, dName("PMINH");) + +MakeDisF(disPADDUW, dName("PADDUW");) +MakeDisF(disPADDUH, dName("PADDUH");) +MakeDisF(disPADDUB, dName("PADDUB");) + +MakeDisF(disPSUBUW, dName("PSUBUW");) +MakeDisF(disPSUBUH, dName("PSUBUH");) +MakeDisF(disPSUBUB, dName("PSUBUB");) + +MakeDisF(disPEXTUW, dName("PEXTUW"); dGPR128(_Rd_); dGPR64U(_Rs_); dGPR64U(_Rt_);) +MakeDisF(disPEXTUH, dName("PEXTUH"); dGPR128(_Rd_); dGPR64U(_Rs_); dGPR64U(_Rt_);) +MakeDisF(disPEXTUB, dName("PEXTUB");) + +MakeDisF(disQFSRV, dName("QFSRV");) + +/********************************************************* +* MMI2 opcodes * +* * +*********************************************************/ + +MakeDisF(disPMADDW, dName("PMADDW");) +MakeDisF(disPMADDH, dName("PMADDH");) + +MakeDisF(disPSLLVW, dName("PSLLVW");) +MakeDisF(disPSRLVW, dName("PSRLVW");) + +MakeDisF(disPMFHI, dName("PMFHI");) +MakeDisF(disPMFLO, dName("PMFLO");) + +MakeDisF(disPINTH, dName("PINTH");) + +MakeDisF(disPMULTW, dName("PMULTW");) +MakeDisF(disPMULTH, dName("PMULTH");) + +MakeDisF(disPDIVW, dName("PDIVW");) +MakeDisF(disPDIVH, dName("PDIVH");) + +MakeDisF(disPCPYLD, dName("PCPYLD"); dGPR128(_Rd_); dGPR128(_Rs_); dGPR128(_Rt_);) + +MakeDisF(disPAND, dName("PAND"); dGPR128(_Rd_); dGPR128(_Rs_); dGPR128(_Rt_);) +MakeDisF(disPXOR, dName("PXOR"); dGPR128(_Rd_); dGPR128(_Rs_); dGPR128(_Rt_);) + +MakeDisF(disPMSUBW, dName("PMSUBW");) +MakeDisF(disPMSUBH, dName("PMSUBH");) + +MakeDisF(disPHMADH, dName("PHMADH");) +MakeDisF(disPHMSBH, dName("PHMSBH");) + +MakeDisF(disPEXEW, dName("PEXEW");) +MakeDisF(disPEXEH, dName("PEXEH");) + +MakeDisF(disPREVH, dName("PREVH");) + +MakeDisF(disPDIVBW, dName("PDIVBW");) + +MakeDisF(disPROT3W, dName("PROT3W");) + +/********************************************************* +* MMI3 opcodes * +* * +*********************************************************/ + +MakeDisF(disPMADDUW, dName("PMADDUW");) + +MakeDisF(disPSRAVW, dName("PSRAVW");) + +MakeDisF(disPMTHI, dName("PMTHI");) +MakeDisF(disPMTLO, dName("PMTLO");) + +MakeDisF(disPINTEH, dName("PINTEH");) + +MakeDisF(disPMULTUW, dName("PMULTUW");) +MakeDisF(disPDIVUW, dName("PDIVUW");) + +MakeDisF(disPCPYUD, dName("PCPYUD"); dGPR128(_Rd_); dGPR128(_Rt_); dGPR128(_Rs_);) + +MakeDisF(disPOR, dName("POR"); dGPR128(_Rd_); dGPR128(_Rs_); dGPR128(_Rt_);) +MakeDisF(disPNOR, dName("PNOR"); dGPR128(_Rd_); dGPR128(_Rs_); dGPR128(_Rt_);) + +MakeDisF(disPEXCH, dName("PEXCH");) +MakeDisF(disPEXCW, dName("PEXCW");) + +MakeDisF(disPCPYH, dName("PCPYH"); dGPR128(_Rd_); dGPR128(_Rt_);) + +/********************************************************* +* COP2 opcodes * +* * +*********************************************************/ + +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +#define _X code>>24 +#define _Y code>>23 +#define _Z code>>22 +#define _W code>>21 + +MakeDisF(disLQC2, dName("LQC2"); dCP2128f(_Rt_); dOfB();) +MakeDisF(disSQC2, dName("SQC2"); dCP2128f(_Rt_); dOfB();) + +MakeDisF(disQMFC2, dName("QMFC2");) +MakeDisF(disQMTC2, dName("QMTC2");) +MakeDisF(disCFC2, dName("CFC2"); dGPR32(_Rt_); dCP232i(_Fs_);) +MakeDisF(disCTC2, dName("CTC2"); dCP232i(_Fs_); dGPR32(_Rt_);) + +MakeDisF(disBC2F, dName("BC2F");) +MakeDisF(disBC2T, dName("BC2T");) +MakeDisF(disBC2FL, dName("BC2FL");) +MakeDisF(disBC2TL, dName("BC2TL");) + +// SPEC1 +MakeDisF(disVADD, dName("VADD");) +MakeDisF(disVADDx, dName("VADDx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) +MakeDisF(disVADDy, dName("VADDy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) +MakeDisF(disVADDz, dName("VADDz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) +MakeDisF(disVADDw, dName("VADDw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) +MakeDisF(disVADDq, dName("VADDq"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_Q);) +MakeDisF(disVADDi, dName("VADDi"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_I);) +MakeDisF(disVSUB, dName("VSUB");) +MakeDisF(disVSUBx, dName("VSUBx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) +MakeDisF(disVSUBy, dName("VSUBy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) +MakeDisF(disVSUBz, dName("VSUBz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) +MakeDisF(disVSUBw, dName("VSUBw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) +MakeDisF(disVSUBq, dName("VSUBq");) +MakeDisF(disVSUBi, dName("VSUBi");) +MakeDisF(disVMADD, dName("VMADD");) +MakeDisF(disVMADDx, dName("VMADDx"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) +MakeDisF(disVMADDy, dName("VMADDy"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) +MakeDisF(disVMADDz, dName("VMADDz"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) +MakeDisF(disVMADDw, dName("VMADDw"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) +MakeDisF(disVMADDq, dName("VMADDq");) +MakeDisF(disVMADDi, dName("VMADDi");) +MakeDisF(disVMSUB, dName("VMSUB");) +MakeDisF(disVMSUBx, dName("VMSUBx");) +MakeDisF(disVMSUBy, dName("VMSUBy");) +MakeDisF(disVMSUBz, dName("VMSUBz");) +MakeDisF(disVMSUBw, dName("VMSUBw");) +MakeDisF(disVMSUBq, dName("VMSUBq");) +MakeDisF(disVMSUBi, dName("VMSUBi");) +MakeDisF(disVMAX, dName("VMAX");) +MakeDisF(disVMAXx, dName("VMAXx");) +MakeDisF(disVMAXy, dName("VMAXy");) +MakeDisF(disVMAXz, dName("VMAXz");) +MakeDisF(disVMAXw, dName("VMAXw");) +MakeDisF(disVMAXi, dName("VMAXi");) +MakeDisF(disVMINI, dName("VMINI");) +MakeDisF(disVMINIx, dName("VMINIx");) +MakeDisF(disVMINIy, dName("VMINIy");) +MakeDisF(disVMINIz, dName("VMINIz");) +MakeDisF(disVMINIw, dName("VMINIw");) +MakeDisF(disVMINIi, dName("VMINIi");) +MakeDisF(disVMUL, dName("VMUL");) +MakeDisF(disVMULx, dName("VMULx");) +MakeDisF(disVMULy, dName("VMULy");) +MakeDisF(disVMULz, dName("VMULz");) +MakeDisF(disVMULw, dName("VMULw");) +MakeDisF(disVMULq, dName("VMULq");) +MakeDisF(disVMULi, dName("VMULi");) +MakeDisF(disVIADD, dName("VIADD");) +MakeDisF(disVIADDI, dName("VIADDI");) +MakeDisF(disVISUB, dName("VISUB");) +MakeDisF(disVIAND, dName("VIAND");) +MakeDisF(disVIOR, dName("VIOR");) +MakeDisF(disVOPMSUB, dName("VOPMSUB");) +MakeDisF(disVCALLMS, dName("VCALLMS");) +MakeDisF(disVCALLMSR, dName("VCALLMSR");) + +// SPEC2 +MakeDisF(disVADDA, dName("VADDA");) +MakeDisF(disVADDAx, dName("VADDAx");) +MakeDisF(disVADDAy, dName("VADDAy");) +MakeDisF(disVADDAz, dName("VADDAz");) +MakeDisF(disVADDAw, dName("VADDAw");) +MakeDisF(disVADDAq, dName("VADDAq");) +MakeDisF(disVADDAi, dName("VADDAi");) +MakeDisF(disVMADDA, dName("VMADDA");) +MakeDisF(disVMADDAx, dName("VMADDAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) +MakeDisF(disVMADDAy, dName("VMADDAy"); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) +MakeDisF(disVMADDAz, dName("VMADDAz"); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) +MakeDisF(disVMADDAw, dName("VMADDAw"); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) +MakeDisF(disVMADDAq, dName("VMADDAq");) +MakeDisF(disVMADDAi, dName("VMADDAi");) +MakeDisF(disVSUBAx, dName("VSUBAx");) +MakeDisF(disVSUBAy, dName("VSUBAy");) +MakeDisF(disVSUBAz, dName("VSUBAz");) +MakeDisF(disVSUBAw, dName("VSUBAw");) +MakeDisF(disVMSUBAx, dName("VMSUBAx");) +MakeDisF(disVMSUBAy, dName("VMSUBAy");) +MakeDisF(disVMSUBAz, dName("VMSUBAz");) +MakeDisF(disVMSUBAw, dName("VMSUBAw");) +MakeDisF(disVITOF0, dName("VITOF0");) +MakeDisF(disVITOF4, dName("VITOF4");) +MakeDisF(disVITOF12, dName("VITOF12");) +MakeDisF(disVITOF15, dName("VITOF15");) +MakeDisF(disVFTOI0, dName("VFTOI0");) +MakeDisF(disVFTOI4, dName("VFTOI4");) +MakeDisF(disVFTOI12, dName("VFTOI12");) +MakeDisF(disVFTOI15, dName("VFTOI15");) +MakeDisF(disVMULA, dName("VMULA");) +MakeDisF(disVMULAx, dName("VMULAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) +MakeDisF(disVMULAy, dName("VMULAy");) +MakeDisF(disVMULAz, dName("VMULAz");) +MakeDisF(disVMULAw, dName("VMULAw");) +MakeDisF(disVMOVE, dName("VMOVE"); dCP2128f(_Ft_); dCP2128f(_Fs_);) +MakeDisF(disVMR32, dName("VMR32");) +MakeDisF(disVDIV, dName("VDIV");) +MakeDisF(disVSQRT, dName("VSQRT"); dCP232f(_Ft_, _Ftf_);) +MakeDisF(disVRSQRT, dName("VRSQRT");) +MakeDisF(disVRNEXT, dName("VRNEXT");) +MakeDisF(disVRGET, dName("VRGET");) +MakeDisF(disVRINIT, dName("VRINIT");) +MakeDisF(disVRXOR, dName("VRXOR");) +MakeDisF(disVWAITQ, dName("VWAITQ");) + +/********************************************************* +* Special purpose instructions * +* Format: OP * +*********************************************************/ + +MakeDisF(disSYNC, dName("SYNC");) +MakeDisF(disBREAK, dName("BREAK");) +MakeDisF(disSYSCALL, dName("SYSCALL"); dCode();) +MakeDisF(disCACHE, ssappendf(output, "%-7s, %x,", params "CACHE", _Rt_); dOfB();) +MakeDisF(disPREF, dName("PREF");) + +MakeDisF(disMFSA, dName("MFSA"); dGPR64(_Rd_); dSaR();) +MakeDisF(disMTSA, dName("MTSA"); dGPR64(_Rs_); dSaR();) + +MakeDisF(disMTSAB, dName("MTSAB");dGPR64(_Rs_); dImm();) +MakeDisF(disMTSAH, dName("MTSAH");dGPR64(_Rs_); dImm();) + +MakeDisF(disTGE, dName("TGE"); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disTGEU, dName("TGEU"); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disTLT, dName("TLT"); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disTLTU, dName("TLTU"); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disTEQ, dName("TEQ"); dGPR64(_Rs_); dGPR64(_Rt_);) +MakeDisF(disTNE, dName("TNE"); dGPR64(_Rs_); dGPR64(_Rt_);) + +MakeDisF(disTGEI, dName("TGEI"); dGPR64(_Rs_); dImm();) +MakeDisF(disTGEIU, dName("TGEIU"); dGPR64(_Rs_); dImm();) +MakeDisF(disTLTI, dName("TLTI"); dGPR64(_Rs_); dImm();) +MakeDisF(disTLTIU, dName("TLTIU"); dGPR64(_Rs_); dImm();) +MakeDisF(disTEQI, dName("TEQI"); dGPR64(_Rs_); dImm();) +MakeDisF(disTNEI, dName("TNEI"); dGPR64(_Rs_); dImm();) + +/********************************************************* +* Unknown instruction (would generate an exception) * +* Format: ? * +*********************************************************/ +static MakeDisF(disNULL, dName("*** Bad OP ***");) + +TdisR5900F disR5900_MMI0[] = { // Subset of disMMI0 + disPADDW, disPSUBW, disPCGTW, disPMAXW, + disPADDH, disPSUBH, disPCGTH, disPMAXH, + disPADDB, disPSUBB, disPCGTB, disNULL, + disNULL, disNULL, disNULL, disNULL, + disPADDSW, disPSUBSW, disPEXTLW, disPPACW, + disPADDSH, disPSUBSH, disPEXTLH, disPPACH, + disPADDSB, disPSUBSB, disPEXTLB, disPPACB, + disNULL, disNULL, disPEXTS, disPPACS}; + +static void disMMI0( string& output, u32 code ) +{ + disR5900_MMI0[_Sa_]( output, code ); +} + +TdisR5900F disR5900_MMI1[] = { // Subset of disMMI1 + disNULL, disPABSW, disPCEQW, disPMINW, + disPADSBH, disPABSH, disPCEQH, disPMINH, + disNULL, disNULL, disPCEQB, disNULL, + disNULL, disNULL, disNULL, disNULL, + disPADDUW, disPSUBUW, disPEXTUW, disNULL, + disPADDUH, disPSUBUH, disPEXTUH, disNULL, + disPADDUB, disPSUBUB, disPEXTUB, disQFSRV, + disNULL, disNULL, disNULL, disNULL}; + +static void disMMI1( string& output, u32 code ) +{ + disR5900_MMI1[_Sa_]( output, code ); +} + +TdisR5900F disR5900_MMI2[] = { // Subset of disMMI2 + disPMADDW, disNULL, disPSLLVW, disPSRLVW, + disPMSUBW, disNULL, disNULL, disNULL, + disPMFHI, disPMFLO, disPINTH, disNULL, + disPMULTW, disPDIVW, disPCPYLD, disNULL, + disPMADDH, disPHMADH, disPAND, disPXOR, + disPMSUBH, disPHMSBH, disNULL, disNULL, + disNULL, disNULL, disPEXEH, disPREVH, + disPMULTH, disPDIVBW, disPEXEW, disPROT3W}; + +static void disMMI2( string& output, u32 code ) +{ + disR5900_MMI2[_Sa_]( output, code ); +} + +TdisR5900F disR5900_MMI3[] = { // Subset of disMMI3 + disPMADDUW, disNULL, disNULL, disPSRAVW, + disNULL, disNULL, disNULL, disNULL, + disPMTHI, disPMTLO, disPINTEH, disNULL, + disPMULTUW, disPDIVUW, disPCPYUD, disNULL, + disNULL, disNULL, disPOR, disPNOR, + disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disPEXCH, disPCPYH, + disNULL, disNULL, disPEXCW, disNULL}; + +static void disMMI3( string& output, u32 code ) +{ + disR5900_MMI3[_Sa_]( output, code ); +} + +TdisR5900F disR5900_MMI[] = { // Subset of disMMI + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disMMI0, disMMI2, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disMULT1, disMULTU1, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disMMI1, disMMI3, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; + +static void disMMI( string& output, u32 code ) +{ + disR5900_MMI[_Funct_]( output, code ); +} + + +TdisR5900F disR5900_COP0_BC0[] = { //subset of disCOP0 BC + disBC0F, disBC0T, disBC0FL, disBC0TL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, +}; + +static void disCOP0_BC0( string& output, u32 code ) +{ + disR5900_COP0_BC0[_Rt_]( output, code ); +} + +TdisR5900F disR5900_COP0_Func[] = { //subset of disCOP0 Function + disNULL, disTLBR, disTLBWI, disNULL, disNULL, disNULL, disTLBWR, disNULL, + disTLBP, disNULL, disNULL , disNULL, disNULL, disNULL, disNULL , disNULL, + disNULL, disNULL, disNULL , disNULL, disNULL, disNULL, disNULL , disNULL, + disERET, disNULL, disNULL , disNULL, disNULL, disNULL, disNULL , disNULL, + disNULL, disNULL, disNULL , disNULL, disNULL, disNULL, disNULL , disNULL, + disNULL, disNULL, disNULL , disNULL, disNULL, disNULL, disNULL , disNULL, + disNULL, disNULL, disNULL , disNULL, disNULL, disNULL, disNULL , disNULL, + disEI , disDI , disNULL , disNULL, disNULL, disNULL, disNULL , disNULL +}; +static void disCOP0_Func( string& output, u32 code ) +{ + disR5900_COP0_Func[_Funct_]( output, code ); +} + +TdisR5900F disR5900_COP0[] = { // Subset of disCOP0 + disMFC0, disNULL, disNULL, disNULL, disMTC0, disNULL, disNULL, disNULL, + disCOP0_BC0, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disCOP0_Func, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; + +static void disCOP0( string& output, u32 code ) +{ + disR5900_COP0[_Rs_]( output, code ); +} + +TdisR5900F disR5900_COP1_S[] = { //subset of disCOP1 S + disADDs, disSUBs, disMULs, disDIVs, disSQRTs, disABSs, disMOVs, disNEGs, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disRSQRTs, disNULL, + disADDAs, disSUBAs, disMULAs, disNULL, disMADDs, disMSUBs, disMADDAs, disMSUBAs, + disNULL, disNULL, disNULL, disNULL, disCVTWs, disNULL, disNULL, disNULL, + disMINs, disMAXs, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disCFs, disNULL, disCEQs, disNULL, disCLTs, disNULL, disCLEs, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, +}; + +static void disCOP1_S( string& output, u32 code ) +{ + disR5900_COP1_S[_Funct_]( output, code ); +} + +TdisR5900F disR5900_COP1_W[] = { //subset of disCOP1 W + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disCVTSw, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, +}; + +static void disCOP1_W( string& output, u32 code ) +{ + disR5900_COP1_W[_Funct_]( output, code ); +} + +TdisR5900F disR5900_COP1_BC1[] = { //subset of disCOP1 BC + disBC1F, disBC1T, disBC1FL, disBC1TL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, +}; + +static void disCOP1_BC1( string& output, u32 code ) +{ + disR5900_COP1_BC1[_Rt_]( output, code ); +} + +TdisR5900F disR5900_COP1[] = { // Subset of disCOP1 + disMFC1, disNULL, disCFC1, disNULL, disMTC1, disNULL, disCTC1, disNULL, + disCOP1_BC1, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disCOP1_S, disNULL, disNULL, disNULL, disCOP1_W, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; + +static void disCOP1( string& output, u32 code ) +{ + disR5900_COP1[_Rs_]( output, code ); +} + +TdisR5900F disR5900_COP2_SPEC2[] = { //subset of disCOP2 SPEC2 + disVADDAx, disVADDAy, disVADDAz, disVADDAw, disVSUBAx, disVSUBAy, disVSUBAz, disVSUBAw, + disVMADDAx, disVMADDAy, disVMADDAz, disVMADDAw, disVMSUBAx, disVMSUBAy, disVMSUBAz, disVMSUBAw, + disVITOF0, disVITOF4, disVITOF12, disVITOF15, disVFTOI0, disVFTOI4, disVFTOI12, disVFTOI15, + disVMULAx, disVMULAy, disVMULAz, disVMULAw, disNULL, disNULL, disNULL, disNULL, + disVADDAq, disVMADDAq, disVADDAi, disVMADDAi, disNULL, disNULL, disNULL, disNULL, + disVADDA, disVMADDA, disVMULA, disNULL, disNULL, disNULL, disNULL, disNULL, + disVMOVE, disVMR32, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disVDIV, disVSQRT, disVRSQRT, disVWAITQ, disNULL, disNULL, disNULL, disNULL, + disVRNEXT, disVRGET, disVRINIT, disVRXOR, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, +}; + +static void disCOP2_SPEC2( string& output, u32 code ) +{ + disR5900_COP2_SPEC2[(code & 0x3) | ((code >> 4) & 0x7c)]( output, code ); +} + +TdisR5900F disR5900_COP2_SPEC1[] = { //subset of disCOP2 SPEC1 + disVADDx, disVADDy, disVADDz, disVADDw, disVSUBx, disVSUBy, disVSUBz, disVSUBw, + disVMADDx, disVMADDy, disVMADDz, disVMADDw, disVMSUBx, disVMSUBy, disVMSUBz, disVMSUBw, + disVMAXx, disVMAXy, disVMAXz, disVMAXw, disVMINIx, disVMINIy, disVMINIz, disVMINIw, + disVMULx, disVMULy, disVMULz, disVMULw, disVMULq, disVMAXi, disVMULi, disVMINIi, + disVADDq, disVMADDq, disVADDi, disVMADDi, disVSUBq, disVMSUBq, disVSUBi, disVMSUBi, + disVADD, disVMADD, disVMUL, disVMAX, disVSUB, disVMSUB, disVOPMSUB, disVMINI, + disVIADD, disVISUB, disVIADDI, disNULL, disVIAND, disVIOR, disNULL, disNULL, + disVCALLMS, disVCALLMSR, disNULL, disNULL, disCOP2_SPEC2, disCOP2_SPEC2, disCOP2_SPEC2, disCOP2_SPEC2, +}; + +static void disCOP2_SPEC1( string& output, u32 code ) +{ + disR5900_COP2_SPEC1[_Funct_]( output, code ); +} + +TdisR5900F disR5900_COP2_BC2[] = { //subset of disCOP2 BC + disBC2F, disBC2T, disBC2FL, disBC2TL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, +}; + +static void disCOP2_BC2( string& output, u32 code ) +{ + disR5900_COP2_BC2[_Rt_]( output, code ); +} + +TdisR5900F disR5900_COP2[] = { // Subset of disCOP2 + disNULL, disQMFC2, disCFC2, disNULL, disNULL, disQMTC2, disCTC2, disNULL, + disCOP2_BC2, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, + disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1, disCOP2_SPEC1}; + +static void disCOP2( string& output, u32 code ) +{ + disR5900_COP2[_Rs_]( output, code ); +} + +TdisR5900F disR5900_REGIMM[] = { // Subset of disREGIMM + disBLTZ, disBGEZ, disBLTZL, disBGEZL, disNULL, disNULL, disNULL, disNULL, + disTGEI, disTGEIU, disTLTI, disTLTIU, disTEQI, disNULL, disTNEI, disNULL, + disBLTZAL, disBGEZAL, disBLTZALL, disBGEZALL, disNULL, disNULL, disNULL, disNULL, + disMTSAB, disMTSAH , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; + +static void disREGIMM( string& output, u32 code ) +{ + disR5900_REGIMM[_Rt_]( output, code ); +} + +TdisR5900F disR5900_SPECIAL[] = { + disSLL, disNULL, disSRL, disSRA, disSLLV, disNULL, disSRLV, disSRAV, + disJR, disJALR, disMOVZ, disMOVN, disSYSCALL, disBREAK,disNULL, disSYNC, + disMFHI, disMTHI, disMFLO, disMTLO, disDSLLV, disNULL, disDSRLV, disDSRAV, + disMULT, disMULTU,disDIV, disDIVU, disNULL, disNULL, disNULL, disNULL, + disADD, disADDU, disSUB, disSUBU, disAND, disOR, disXOR, disNOR, + disMFSA , disMTSA, disSLT, disSLTU, disDADD, disDADDU,disDSUB, disDSUBU, + disTGE, disTGEU, disTLT, disTLTU, disTEQ, disNULL, disTNE, disNULL, + disDSLL, disNULL, disDSRL, disDSRA, disDSLL32, disNULL, disDSRL32,disDSRA32 }; + +static void disSPECIAL( string& output, u32 code ) +{ + disR5900_SPECIAL[_Funct_]( output, code ); +} + +TdisR5900F disR5900[] = { + disSPECIAL, disREGIMM, disJ , disJAL , disBEQ , disBNE , disBLEZ , disBGTZ , + disADDI , disADDIU , disSLTI, disSLTIU, disANDI, disORI , disXORI , disLUI , + disCOP0 , disCOP1 , disCOP2, disNULL , disBEQL, disBNEL, disBLEZL, disBGTZL, + disDADDI , disDADDIU, disLDL , disLDR , disMMI , disNULL, disLQ , disSQ , + disLB , disLH , disLWL , disLW , disLBU , disLHU , disLWR , disLWU , + disSB , disSH , disSWL , disSW , disSDL , disSDR , disSWR , disCACHE, + disNULL , disLWC1 , disNULL, disPREF , disNULL, disNULL, disLQC2 , disLD , + disNULL , disSWC1 , disNULL, disNULL , disNULL, disNULL, disSQC2 , disSD }; + +void disR5900F( string& output, u32 code ) +{ + disR5900[code >> 26]( output, code ); +} + +// returns a string representation of the cpuRegs current instruction. +// The return value of this method is *not* thread safe! +const string& DisR5900CurrentState::getString() +{ + result.clear(); + disR5900F( result, cpuRegs.code ); + return result; +} + +const char* DisR5900CurrentState::getCString() +{ + result.clear(); + disR5900F( result, cpuRegs.code ); + return result.c_str(); +} + +DisR5900CurrentState disR5900Current; + } \ No newline at end of file diff --git a/pcsx2/DebugTools/DisR5900asm.cpp b/pcsx2/DebugTools/DisR5900asm.cpp index 132ea554fc..a1d2f27ff0 100644 --- a/pcsx2/DebugTools/DisR5900asm.cpp +++ b/pcsx2/DebugTools/DisR5900asm.cpp @@ -1,1192 +1,1192 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#ifdef __LINUX__ -#include -#endif - -#include "Debug.h" -#include "R5900.h" -#include "DisASM.h" -#include "R5900OpcodeTables.h" - -unsigned long opcode_addr; - -using namespace std; - -namespace R5900 -{ - -/* -//DECODE PROCUDURES - -//cop0 -#define DECODE_FS (DECODE_RD) -#define DECODE_FT (DECODE_RT) -#define DECODE_FD (DECODE_SA) -/// ******** - -#define DECODE_FUNCTION ((cpuRegs.code) & 0x3F) -#define DECODE_RD ((cpuRegs.code >> 11) & 0x1F) // The rd part of the instruction register -#define DECODE_RT ((cpuRegs.code >> 16) & 0x1F) // The rt part of the instruction register -#define DECODE_RS ((cpuRegs.code >> 21) & 0x1F) // The rs part of the instruction register -#define DECODE_SA ((cpuRegs.code >> 6) & 0x1F) // The sa part of the instruction register -#define DECODE_IMMED ( cpuRegs.code & 0xFFFF) // The immediate part of the instruction register -#define DECODE_OFFSET ((((short)DECODE_IMMED * 4) + opcode_addr + 4)) -#define DECODE_JUMP (opcode_addr & 0xf0000000)|((cpuRegs.code&0x3ffffff)<<2) -#define DECODE_SYSCALL ((opcode_addr & 0x03FFFFFF) >> 6) -#define DECODE_BREAK (DECODE_SYSCALL) -#define DECODE_C0BC ((cpuRegs.code >> 16) & 0x03) -#define DECODE_C1BC ((cpuRegs.code >> 16) & 0x03) -#define DECODE_C2BC ((cpuRegs.code >> 16) & 0x03) -*/ -/*************************CPUS REGISTERS**************************/ -static const char * const GPR_REG[32] = { - "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", - "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", - "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" -}; -static const char * const COP0_REG[32] ={ - "Index","Random","EntryLo0","EntryLo1","Context","PageMask", - "Wired","C0r7","BadVaddr","Count","EntryHi","Compare","Status", - "Cause","EPC","PRId","Config","C0r17","C0r18","C0r19","C0r20", - "C0r21","C0r22","C0r23","Debug","Perf","C0r26","C0r27","TagLo", - "TagHi","ErrorPC","C0r31" -}; -//floating point cop1 Floating point reg -static const char * const COP1_REG_FP[32] ={ - "f00","f01","f02","f03","f04","f05","f06","f07", - "f08","f09","f10","f11","f12","f13","f14","f15", - "f16","f17","f18","f19","f20","f21","f21","f23", - "f24","f25","f26","f27","f28","f29","f30","f31" -}; -//floating point cop1 control registers -static const char * const COP1_REG_FCR[32] ={ - "fcr00","fcr01","fcr02","fcr03","fcr04","fcr05","fcr06","fcr07", - "fcr08","fcr09","fcr10","fcr11","fcr12","fcr13","fcr14","fcr15", - "fcr16","fcr17","fcr18","fcr19","fcr20","fcr21","fcr21","fcr23", - "fcr24","fcr25","fcr26","fcr27","fcr28","fcr29","fcr30","fcr31" -}; - -//floating point cop2 reg -static const char * const COP2_REG_FP[32] ={ - "vf00","vf01","vf02","vf03","vf04","vf05","vf06","vf07", - "vf08","vf09","vf10","vf11","vf12","vf13","vf14","vf15", - "vf16","vf17","vf18","vf19","vf20","vf21","vf21","vf23", - "vf24","vf25","vf26","vf27","vf28","vf29","vf30","vf31" -}; -//cop2 control registers - -static const char * const COP2_REG_CTL[32] ={ - "vi00","vi01","vi02","vi03","vi04","vi05","vi06","vi07", - "vi08","vi09","vi10","vi11","vi12","vi13","vi14","vi15", - "Status","MACflag","ClipFlag","c2c19","R","I","Q","c2c23", - "c2c24","c2c25","TPC","CMSAR0","FBRST","VPU-STAT","c2c30","CMSAR1" -}; - -void P_COP2_Unknown( string& output ); -void P_COP2_SPECIAL2( string& output ); -void P_COP2_SPECIAL( string& output ); -void P_COP2_BC2( string& output ); - -//**************************************************************************** -//** COP2 - (VU0) ** -//**************************************************************************** -void P_QMFC2( string& output ); -void P_CFC2( string& output ); -void P_QMTC2( string& output ); -void P_CTC2( string& output ); -void P_BC2F( string& output ); -void P_BC2T( string& output ); -void P_BC2FL( string& output ); -void P_BC2TL( string& output ); -//*****************SPECIAL 1 VUO TABLE******************************* -void P_VADDx( string& output ); -void P_VADDy( string& output ); -void P_VADDz( string& output ); -void P_VADDw( string& output ); -void P_VSUBx( string& output ); -void P_VSUBy( string& output ); -void P_VSUBz( string& output ); -void P_VSUBw( string& output ); -void P_VMADDx( string& output ); -void P_VMADDy( string& output ); -void P_VMADDz( string& output ); -void P_VMADDw( string& output ); -void P_VMSUBx( string& output ); -void P_VMSUBy( string& output ); -void P_VMSUBz( string& output ); -void P_VMSUBw( string& output ); -void P_VMAXx( string& output ); -void P_VMAXy( string& output ); -void P_VMAXz( string& output ); -void P_VMAXw( string& output ); -void P_VMINIx( string& output ); -void P_VMINIy( string& output ); -void P_VMINIz( string& output ); -void P_VMINIw( string& output ); -void P_VMULx( string& output ); -void P_VMULy( string& output ); -void P_VMULz( string& output ); -void P_VMULw( string& output ); -void P_VMULq( string& output ); -void P_VMAXi( string& output ); -void P_VMULi( string& output ); -void P_VMINIi( string& output ); -void P_VADDq( string& output ); -void P_VMADDq( string& output ); -void P_VADDi( string& output ); -void P_VMADDi( string& output ); -void P_VSUBq( string& output ); -void P_VMSUBq( string& output ); -void P_VSUbi( string& output ); -void P_VMSUBi( string& output ); -void P_VADD( string& output ); -void P_VMADD( string& output ); -void P_VMUL( string& output ); -void P_VMAX( string& output ); -void P_VSUB( string& output ); -void P_VMSUB( string& output ); -void P_VOPMSUB( string& output ); -void P_VMINI( string& output ); -void P_VIADD( string& output ); -void P_VISUB( string& output ); -void P_VIADDI( string& output ); -void P_VIAND( string& output ); -void P_VIOR( string& output ); -void P_VCALLMS( string& output ); -void P_CALLMSR( string& output ); -//***********************************END OF SPECIAL1 VU0 TABLE***************************** -//******************************SPECIAL2 VUO TABLE***************************************** -void P_VADDAx( string& output ); -void P_VADDAy( string& output ); -void P_VADDAz( string& output ); -void P_VADDAw( string& output ); -void P_VSUBAx( string& output ); -void P_VSUBAy( string& output ); -void P_VSUBAz( string& output ); -void P_VSUBAw( string& output ); -void P_VMADDAx( string& output ); -void P_VMADDAy( string& output ); -void P_VMADDAz( string& output ); -void P_VMADDAw( string& output ); -void P_VMSUBAx( string& output ); -void P_VMSUBAy( string& output ); -void P_VMSUBAz( string& output ); -void P_VMSUBAw( string& output ); -void P_VITOF0( string& output ); -void P_VITOF4( string& output ); -void P_VITOF12( string& output ); -void P_VITOF15( string& output ); -void P_VFTOI0( string& output ); -void P_VFTOI4( string& output ); -void P_VFTOI12( string& output ); -void P_VFTOI15( string& output ); -void P_VMULAx( string& output ); -void P_VMULAy( string& output ); -void P_VMULAz( string& output ); -void P_VMULAw( string& output ); -void P_VMULAq( string& output ); -void P_VABS( string& output ); -void P_VMULAi( string& output ); -void P_VCLIPw( string& output ); -void P_VADDAq( string& output ); -void P_VMADDAq( string& output ); -void P_VADDAi( string& output ); -void P_VMADDAi( string& output ); -void P_VSUBAq( string& output ); -void P_VMSUBAq( string& output ); -void P_VSUBAi( string& output ); -void P_VMSUBAi( string& output ); -void P_VADDA( string& output ); -void P_VMADDA( string& output ); -void P_VMULA( string& output ); -void P_VSUBA( string& output ); -void P_VMSUBA( string& output ); -void P_VOPMULA( string& output ); -void P_VNOP( string& output ); -void P_VMONE( string& output ); -void P_VMR32( string& output ); -void P_VLQI( string& output ); -void P_VSQI( string& output ); -void P_VLQD( string& output ); -void P_VSQD( string& output ); -void P_VDIV( string& output ); -void P_VSQRT( string& output ); -void P_VRSQRT( string& output ); -void P_VWAITQ( string& output ); -void P_VMTIR( string& output ); -void P_VMFIR( string& output ); -void P_VILWR( string& output ); -void P_VISWR( string& output ); -void P_VRNEXT( string& output ); -void P_VRGET( string& output ); -void P_VRINIT( string& output ); -void P_VRXOR( string& output ); -//************************************END OF SPECIAL2 VUO TABLE**************************** - - -/* - CPU: Instructions encoded by opcode field. - 31---------26---------------------------------------------------0 - | opcode | | - ------6---------------------------------------------------------- - |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo -000 | *1 | *2 | J | JAL | BEQ | BNE | BLEZ | BGTZ | -001 | ADDI | ADDIU | SLTI | SLTIU | ANDI | ORI | XORI | LUI | -010 | *3 | *4 | *5 | --- | BEQL | BNEL | BLEZL | BGTZL | -011 | DADDI |DADDIU | LDL | LDR | *6 | --- | LQ | SQ | -100 | LB | LH | LWL | LW | LBU | LHU | LWR | LWU | -101 | SB | SH | SWL | SW | SDL | SDR | SWR | CACHE | -110 | --- | LWC1 | --- | PREF | --- | --- | LQC2 | LD | -111 | --- | SWC1 | --- | --- | --- | --- | SQC2 | SD | - hi |-------|-------|-------|-------|-------|-------|-------|-------| - *1 = SPECIAL, see SPECIAL list *2 = REGIMM, see REGIMM list - *3 = COP0 *4 = COP1 - *5 = COP2 *6 = MMI table -*/ - -/* - SPECIAL: Instr. encoded by function field when opcode field = SPECIAL - 31---------26------------------------------------------5--------0 - | = SPECIAL | | function| - ------6----------------------------------------------------6----- - |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo -000 | SLL | --- | SRL | SRA | SLLV | --- | SRLV | SRAV | -001 | JR | JALR | MOVZ | MOVN |SYSCALL| BREAK | --- | SYNC | -010 | MFHI | MTHI | MFLO | MTLO | DSLLV | --- | DSRLV | DSRAV | -011 | MULT | MULTU | DIV | DIVU | ---- | --- | ---- | ----- | -100 | ADD | ADDU | SUB | SUBU | AND | OR | XOR | NOR | -101 | MFSA | MTSA | SLT | SLTU | DADD | DADDU | DSUB | DSUBU | -110 | TGE | TGEU | TLT | TLTU | TEQ | --- | TNE | --- | -111 | DSLL | --- | DSRL | DSRA |DSLL32 | --- |DSRL32 |DSRA32 | - hi |-------|-------|-------|-------|-------|-------|-------|-------| -*/ - -/* - REGIMM: Instructions encoded by the rt field when opcode field = REGIMM. - 31---------26----------20-------16------------------------------0 - | = REGIMM | | rt | | - ------6---------------------5------------------------------------ - |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo - 00 | BLTZ | BGEZ | BLTZL | BGEZL | --- | --- | --- | --- | - 01 | TGEI | TGEIU | TLTI | TLTIU | TEQI | --- | TNEI | --- | - 10 | BLTZAL| BGEZAL|BLTZALL|BGEZALL| --- | --- | --- | --- | - 11 | MTSAB | MTSAH | --- | --- | --- | --- | --- | --- | - hi |-------|-------|-------|-------|-------|-------|-------|-------| -*/ - -/* - MMI: Instr. encoded by function field when opcode field = MMI - 31---------26------------------------------------------5--------0 - | = MMI | | function| - ------6----------------------------------------------------6----- - |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo -000 | MADD | MADDU | --- | --- | PLZCW | --- | --- | --- | -001 | *1 | *2 | --- | --- | --- | --- | --- | --- | -010 | MFHI1 | MTHI1 | MFLO1 | MTLO1 | --- | --- | --- | --- | -011 | MULT1 | MULTU1| DIV1 | DIVU1 | --- | --- | --- | --- | -100 | MADD1 | MADDU1| --- | --- | --- | --- | --- | --- | -101 | *3 | *4 | --- | --- | --- | --- | --- | --- | -110 | PMFHL | PMTHL | --- | --- | PSLLH | --- | PSRLH | PSRAH | -111 | --- | --- | --- | --- | PSLLW | --- | PSRLW | PSRAW | - hi |-------|-------|-------|-------|-------|-------|-------|-------| - - *1 = see MMI0 table *2 = see MMI2 Table - *3 = see MMI1 table *4 = see MMI3 Table -*/ - -/* - MMI0: Instr. encoded by function field when opcode field = MMI & MMI0 - - 31---------26------------------------------10--------6-5--------0 - | | |function | MMI0 | - ------6----------------------------------------------------6----- - |--000--|--001--|--010--|--011--| lo -000 |PADDW | PSUBW | PCGTW | PMAXW | -001 |PADDH | PSUBH | PCGTH | PMAXH | -010 |PADDB | PSUBB | PCGTB | --- | -011 | --- | --- | --- | --- | -100 |PADDSW |PSUBSW |PEXTLW | PPACW | -101 |PADDSH |PSUBSH |PEXTLH | PPACH | -110 |PADDSB |PSUBSB |PEXTLB | PPACB | -111 | --- | --- | PEXT5 | PPAC5 | - hi |-------|-------|-------|-------| -*/ - -/* - MMI1: Instr. encoded by function field when opcode field = MMI & MMI1 - - 31---------26------------------------------------------5--------0 - | | |function | MMI1 | - ------6----------------------------------------------------6----- - |--000--|--001--|--010--|--011--| lo -000 | --- | PABSW | PCEQW | PMINW | -001 |PADSBH | PABSH | PCEQH | PMINH | -010 | --- | --- | PCEQB | --- | -011 | --- | --- | --- | --- | -100 |PADDUW |PSUBUW |PEXTUW | --- | -101 |PADDUH |PSUBUH |PEXTUH | --- | -110 |PADDUB |PSUBUB |PEXTUB | QFSRV | -111 | --- | --- | --- | --- | - hi |-------|-------|-------|-------| -*/ - -/* - MMI2: Instr. encoded by function field when opcode field = MMI & MMI2 - - 31---------26------------------------------------------5--------0 - | | |function | MMI2 | - ------6----------------------------------------------------6----- - |--000--|--001--|--010--|--011--| lo -000 |PMADDW | --- |PSLLVW |PSRLVW | -001 |PMSUBW | --- | --- | --- | -010 |PMFHI |PMFLO |PINTH | --- | -011 |PMULTW |PDIVW |PCPYLD | --- | -100 |PMADDH |PHMADH | PAND | PXOR | -101 |PMSUBH |PHMSBH | --- | --- | -110 | --- | --- | PEXEH | PREVH | -111 |PMULTH |PDIVBW | PEXEW |PROT3W | - hi |-------|-------|-------|-------| -*/ - -/* - MMI3: Instr. encoded by function field when opcode field = MMI & MMI3 - 31---------26------------------------------------------5--------0 - | | |function | MMI3 | - ------6----------------------------------------------------6----- - |--000--|--001--|--010--|--011--| lo -000 |PMADDUW| --- | --- |PSRAVW | -001 | --- | --- | --- | --- | -010 |PMTHI | PMTLO |PINTEH | --- | -011 |PMULTUW| PDIVUW|PCPYUD | --- | -100 | --- | --- | POR | PNOR | -101 | --- | --- | --- | --- | -110 | --- | --- | PEXCH | PCPYH | -111 | --- | --- | PEXCW | --- | - hi |-------|-------|-------|-------| - */ - -/* - COP0: Instructions encoded by the rs field when opcode = COP0. - 31--------26-25------21 ----------------------------------------0 - | = COP0 | fmt | | - ------6----------5----------------------------------------------- - |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo - 00 | MFC0 | --- | --- | --- | MTC0 | --- | --- | --- | - 01 | *1 | --- | --- | --- | --- | --- | --- | --- | - 10 | *2 | --- | --- | --- | --- | --- | --- | --- | - 11 | --- | --- | --- | --- | --- | --- | --- | --- | - hi |-------|-------|-------|-------|-------|-------|-------|-------| - *1=BC See BC0 list *2 = TLB instr, see TLB list -*/ -/* - BC0: Instructions encoded by the rt field when opcode = COP0 & rs field=BC0 - 31--------26-25------21 ----------------------------------------0 - | = COP0 | fmt | | - ------6----------5----------------------------------------------- - |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo - 00 | BC0F | BC0T | BC0FL | BC0TL | --- | --- | --- | --- | - 01 | --- | --- | --- | --- | --- | --- | --- | --- | - 10 | --- | --- | --- | --- | --- | --- | --- | --- | - 11 | --- | --- | --- | --- | --- | --- | --- | --- | - hi |-------|-------|-------|-------|-------|-------|-------|-------| -*/ -/* - C0=Instructions encode by function field when Opcode field=COP0 & rs field=C0 - 31---------26------------------------------------------5--------0 - | | | | - ------6----------------------------------------------------6----- - |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo -000 | --- | TLBR | TLBWI | --- | --- | --- | TLBWR | --- | -001 | TLBP | --- | --- | --- | --- | --- | --- | --- | -010 | --- | --- | --- | --- | --- | --- | --- | --- | -011 | ERET | --- | --- | --- | --- | --- | --- | --- | -100 | --- | --- | --- | --- | --- | --- | --- | --- | -101 | --- | --- | --- | --- | --- | --- | --- | --- | -110 | --- | --- | --- | --- | --- | --- | --- | --- | -111 | EI | DI | --- | --- | --- | --- | --- | --- | - hi |-------|-------|-------|-------|-------|-------|-------|-------| -*/ -/* - COP1: Instructions encoded by the fmt field when opcode = COP1. - 31--------26-25------21 ----------------------------------------0 - | = COP1 | fmt | | - ------6----------5----------------------------------------------- - |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo - 00 | MFC1 | --- | CFC1 | --- | MTC1 | --- | CTC1 | --- | - 01 | *1 | --- | --- | --- | --- | --- | --- | --- | - 10 | *2 | --- | --- | --- | *3 | --- | --- | --- | - 11 | --- | --- | --- | --- | --- | --- | --- | --- | - hi |-------|-------|-------|-------|-------|-------|-------|-------| - *1 = BC instructions, see BC1 list *2 = S instr, see FPU list - *3 = W instr, see FPU list -*/ -/* - BC1: Instructions encoded by the rt field when opcode = COP1 & rs field=BC1 - 31--------26-25------21 ----------------------------------------0 - | = COP1 | fmt | | - ------6----------5----------------------------------------------- - |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo - 00 | BC1F | BC1T | BC1FL | BC1TL | --- | --- | --- | --- | - 01 | --- | --- | --- | --- | --- | --- | --- | --- | - 10 | --- | --- | --- | --- | --- | --- | --- | --- | - 11 | --- | --- | --- | --- | --- | --- | --- | --- | - hi |-------|-------|-------|-------|-------|-------|-------|-------| -*/ -/* - FPU: Instructions encoded by the function field when opcode = COP1 - and rs = S - 31--------26-25------21 -------------------------------5--------0 - | = COP1 | = S | | function| - ------6----------5-----------------------------------------6----- - |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo -000 | ADD.S | SUB.S | MUL.S | DIV.S | SQRT.S| ABS.S | MOV.S | NEG.S | -001 | --- | --- | --- | --- | --- | --- | --- | --- | -010 | --- | --- | --- | --- | --- | --- |RSQRT.S| --- | -011 | ADDA.S| SUBA.S| MULA.S| --- | MADD.S| MSUB.S|MADDA.S|MSUBA.S| -100 | --- | --- | --- | --- | CVT.W | --- | --- | --- | -101 | MAX.S | MIN.S | --- | --- | --- | --- | --- | --- | -110 | C.F | --- | C.EQ | --- | C.LT | --- | C.LE | --- | -111 | --- | --- | --- | --- | --- | --- | --- | --- | - hi |-------|-------|-------|-------|-------|-------|-------|-------| -*/ -/* - FPU: Instructions encoded by the function field when opcode = COP1 - and rs = W - 31--------26-25------21 -------------------------------5--------0 - | = COP1 | = W | | function| - ------6----------5-----------------------------------------6----- - |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo -000 | --- | --- | --- | --- | --- | --- | --- | --- | -001 | --- | --- | --- | --- | --- | --- | --- | --- | -010 | --- | --- | --- | --- | --- | --- | --- | --- | -011 | --- | --- | --- | --- | --- | --- | --- | --- | -100 | CVT.S | --- | --- | --- | --- | --- | --- | --- | -101 | --- | --- | --- | --- | --- | --- | --- | --- | -110 | --- | --- | --- | --- | --- | --- | --- | --- | -111 | --- | --- | --- | --- | --- | --- | --- | --- | - hi |-------|-------|-------|-------|-------|-------|-------|-------| -*/ - -//************************************************************* -// COP2 TABLES :) [VU0 as a Co-Processor to the EE] -//************************************************************* -/* - COP2: Instructions encoded by the fmt field when opcode = COP2. - 31--------26-25------21 ----------------------------------------0 - | = COP2 | fmt | | - ------6----------5----------------------------------------------- - |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo - 00 | --- | QMFC2 | CFC2 | --- | --- | QMTC2 | CTC2 | --- | - 01 | *1 | --- | --- | --- | --- | --- | --- | --- | - 10 | *2 | *2 | *2 | *2 | *2 | *2 | *2 | *2 | - 11 | *2 | *2 | *2 | *2 | *2 | *2 | *2 | *2 | - hi |-------|-------|-------|-------|-------|-------|-------|-------| - *1 = BC instructions, see BC2 list *2 =see special1 table -*/ -void (*COP2PrintTable[32])( string& output ) = { - P_COP2_Unknown, P_QMFC2, P_CFC2, P_COP2_Unknown, P_COP2_Unknown, P_QMTC2, P_CTC2, P_COP2_Unknown, - P_COP2_BC2, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, - P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, - P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, - - -}; -/* - BC2: Instructions encoded by the rt field when opcode = COP2 & rs field=BC1 - 31--------26-25------21 ----------------------------------------0 - | = COP2 | rs=BC2| | - ------6----------5----------------------------------------------- - |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo - 00 | BC2F | BC2T | BC2FL | BC2TL | --- | --- | --- | --- | - 01 | --- | --- | --- | --- | --- | --- | --- | --- | - 10 | --- | --- | --- | --- | --- | --- | --- | --- | - 11 | --- | --- | --- | --- | --- | --- | --- | --- | - hi |-------|-------|-------|-------|-------|-------|-------|-------| - */ -void (*COP2BC2PrintTable[32])( string& output ) = { - P_BC2F, P_BC2T, P_BC2FL, P_BC2TL, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, - P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, - P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, - P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, -}; -/* - Special1 table : instructions encode by function field when opcode=COP2 & rs field=Special1 - 31---------26---------------------------------------------------0 - | =COP2 | rs=Special | - ------6---------------------------------------------------------- - |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo -000 |VADDx |VADDy |VADDz |VADDw |VSUBx |VSUBy |VSUBz |VSUBw | -001 |VMADDx |VMADDy |VMADDz |VMADDw |VMSUBx |VMSUBy |VMSUBz |VMSUBw | -010 |VMAXx |VMAXy |VMAXz |VMAXw |VMINIx |VMINIy |VMINIz |VMINIw | -011 |VMULx |VMULy |VMULz |VMULw |VMULq |VMAXi |VMULi |VMINIi | -100 |VADDq |VMADDq |VADDi |VMADDi |VSUBq |VMSUBq |VSUbi |VMSUBi | -101 |VADD |VMADD |VMUL |VMAX |VSUB |VMSUB |VOPMSUB|VMINI | -110 |VIADD |VISUB |VIADDI | --- |VIAND |VIOR | --- | --- | -111 |VCALLMS|CALLMSR| --- | --- | *1 | *1 | *1 | *1 | - hi |-------|-------|-------|-------|-------|-------|-------|-------| - *1=see special2 table -*/ -void (*COP2SPECIAL1PrintTable[64])( string& output ) = -{ - P_VADDx, P_VADDy, P_VADDz, P_VADDw, P_VSUBx, P_VSUBy, P_VSUBz, P_VSUBw, - P_VMADDx, P_VMADDy, P_VMADDz, P_VMADDw, P_VMSUBx, P_VMSUBy, P_VMSUBz, P_VMSUBw, - P_VMAXx, P_VMAXy, P_VMAXz, P_VMAXw, P_VMINIx, P_VMINIy, P_VMINIz, P_VMINIw, - P_VMULx, P_VMULy, P_VMULz, P_VMULw, P_VMULq, P_VMAXi, P_VMULi, P_VMINIi, - P_VADDq, P_VMADDq, P_VADDi, P_VMADDi, P_VSUBq, P_VMSUBq, P_VSUbi, P_VMSUBi, - P_VADD, P_VMADD, P_VMUL, P_VMAX, P_VSUB, P_VMSUB, P_VOPMSUB, P_VMINI, - P_VIADD, P_VISUB, P_VIADDI, P_COP2_Unknown,P_VIAND, P_VIOR, P_COP2_Unknown, P_COP2_Unknown, - P_VCALLMS, P_CALLMSR, P_COP2_Unknown,P_COP2_Unknown,P_COP2_SPECIAL2,P_COP2_SPECIAL2,P_COP2_SPECIAL2,P_COP2_SPECIAL2, - -}; -/* - Special2 table : instructions encode by function field when opcode=COp2 & rs field=Special2 - - 31---------26---------------------------------------------------0 - | =COP2 | rs=Special2 | - ------6---------------------------------------------------------- - |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo -0000 |VADDAx |VADDAy |VADDAz |VADDAw |VSUBAx |VSUBAy |VSUBAz |VSUBAw | -0001 |VMADDAx|VMADDAy|VMADDAz|VMADDAw|VMSUBAx|VMSUBAy|VMSUBAz|VMSUBAw| -0010 |VITOF0 |VITOF4 |VITOF12|VITOF15|VFTOI0 |VFTOI4 |VFTOI12|VFTOI15| -0011 |VMULAx |VMULAy |VMULAz |VMULAw |VMULAq |VABS |VMULAi |VCLIPw | -0100 |VADDAq |VMADDAq|VADDAi |VMADDAi|VSUBAq |VMSUBAq|VSUBAi |VMSUBAi| -0101 |VADDA |VMADDA |VMULA | --- |VSUBA |VMSUBA |VOPMULA|VNOP | -0110 |VMONE |VMR32 | --- | --- |VLQI |VSQI |VLQD |VSQD | -0111 |VDIV |VSQRT |VRSQRT |VWAITQ |VMTIR |VMFIR |VILWR |VISWR | -1000 |VRNEXT |VRGET |VRINIT |VRXOR | --- | --- | --- | --- | -1001 | --- | --- | --- | --- | --- | --- | --- | --- | -1010 | --- | --- | --- | --- | --- | --- | --- | --- | -1011 | --- | --- | --- | --- | --- | --- | --- | --- | -1100 | --- | --- | --- | --- | --- | --- | --- | --- | -1101 | --- | --- | --- | --- | --- | --- | --- | --- | -1110 | --- | --- | --- | --- | --- | --- | --- | --- | -1111 | --- | --- | --- | --- | --- | --- | --- | --- | - hi |-------|-------|-------|-------|-------|-------|-------|-------| -*/ -void (*COP2SPECIAL2PrintTable[128])( string& output ) = -{ - P_VADDAx ,P_VADDAy ,P_VADDAz ,P_VADDAw ,P_VSUBAx ,P_VSUBAy ,P_VSUBAz ,P_VSUBAw, - P_VMADDAx ,P_VMADDAy ,P_VMADDAz ,P_VMADDAw ,P_VMSUBAx ,P_VMSUBAy ,P_VMSUBAz ,P_VMSUBAw, - P_VITOF0 ,P_VITOF4 ,P_VITOF12 ,P_VITOF15 ,P_VFTOI0 ,P_VFTOI4 ,P_VFTOI12 ,P_VFTOI15, - P_VMULAx ,P_VMULAy ,P_VMULAz ,P_VMULAw ,P_VMULAq ,P_VABS ,P_VMULAi ,P_VCLIPw, - P_VADDAq ,P_VMADDAq ,P_VADDAi ,P_VMADDAi ,P_VSUBAq ,P_VMSUBAq ,P_VSUBAi ,P_VMSUBAi, - P_VADDA ,P_VMADDA ,P_VMULA ,P_COP2_Unknown,P_VSUBA ,P_VMSUBA ,P_VOPMULA ,P_VNOP, - P_VMONE ,P_VMR32 ,P_COP2_Unknown,P_COP2_Unknown,P_VLQI ,P_VSQI ,P_VLQD ,P_VSQD, - P_VDIV ,P_VSQRT ,P_VRSQRT ,P_VWAITQ ,P_VMTIR ,P_VMFIR ,P_VILWR ,P_VISWR, - P_VRNEXT ,P_VRGET ,P_VRINIT ,P_VRXOR ,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, - P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, - P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, - P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, - P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, - P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, - P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, - P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, -}; - -//**************************TABLES CALLS*********************** - - -void disR5900Fasm(string& output, u32 code, u32 pc) -{ - string dbuf; - char obuf[48]; - - const u32 scode = cpuRegs.code; - opcode_addr = pc; - cpuRegs.code = code; - - sprintf(obuf, "%08X:\t", pc ); - output.assign( obuf ); - GetCurrentInstruction().disasm( output ); - - cpuRegs.code = scode; -} - -//************************************************************* -//************************COP2********************************** -void P_COP2_BC2( string& output ) -{ - COP2BC2PrintTable[DECODE_C2BC]( output ); -} -void P_COP2_SPECIAL( string& output ) -{ - COP2SPECIAL1PrintTable[DECODE_FUNCTION ]( output ); -} -void P_COP2_SPECIAL2( string& output ) -{ - COP2SPECIAL2PrintTable[(cpuRegs.code & 0x3) | ((cpuRegs.code >> 4) & 0x7c)]( output ); -} - -//**************************UNKNOWN**************************** -void P_COP2_Unknown( string& output ) -{ - output += "COP2 ??"; -} - - -//************************************************************* - -//*****************SOME DECODE STUFF*************************** - -void label_decode( string& output, u32 addr ) -{ - string buf; - ssprintf(buf, "0x%08X", addr); - const char* label = disR5900GetSym( addr ); - - if( label != NULL ) - { - output += label; - output += ' '; - } - - output += buf; -} - -void jump_decode( string& output ) -{ - label_decode( output, DECODE_JUMP ); -} - -void offset_decode( string& output ) -{ - label_decode( output, DECODE_OFFSET ); -} - -//*********************END OF DECODE ROUTINES****************** - -namespace OpcodeDisasm -{ - -void COP2( string& output ) -{ - COP2PrintTable[DECODE_RS]( output ); -} - -// Unkown Opcode! -void Unknown( string& output ) -{ - output += "?????"; -} - -void MMI_Unknown( string& output ) -{ - output += "MMI ??"; -} - -void COP0_Unknown( string& output ) -{ - output += "COP0 ??"; -} - -void COP1_Unknown( string& output ) -{ - output += "FPU ??"; -} - -// sap! it stands for string append. It's not a friendly name but for now it makes -// the copy-paste marathon of code below more readable! -#define _sap( str ) ssappendf( output, str, - -//********************* Standard Opcodes*********************** -void J( string& output ) { output += "j\t"; jump_decode(output);} -void JAL( string& output ) { output += "jal\t"; jump_decode(output);} -void BEQ( string& output ) { _sap("beq\t%s, %s, ") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); offset_decode(output); } -void BNE( string& output ) { _sap("bne\t%s, %s, ") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); offset_decode(output); } -void BLEZ( string& output ) { _sap("blez\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } -void BGTZ( string& output ) { _sap("bgtz\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } -void ADDI( string& output ) { _sap("addi\t%s, %s, 0x%04X") GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED);} -void ADDIU( string& output ) { _sap("addiu\t%s, %s, 0x%04X") GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED);} -void SLTI( string& output ) { _sap("slti\t%s, %s, 0x%04X") GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED); } -void SLTIU( string& output ) { _sap("sltiu\t%s, %s, 0x%04X") GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED); } -void ANDI( string& output ) { _sap("andi\t%s, %s, 0x%04X") GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED);} -void ORI( string& output ) { _sap("ori\t%s, %s, 0x%04X") GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED); } -void XORI( string& output ) { _sap("xori\t%s, %s, 0x%04X") GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED); } -void LUI( string& output ) { _sap("lui\t%s, 0x%04X") GPR_REG[DECODE_RT], DECODE_IMMED); } -void BEQL( string& output ) { _sap("beql\t%s, %s, ") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); offset_decode(output); } -void BNEL( string& output ) { _sap("bnel\t%s, %s, ") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); offset_decode(output); } -void BLEZL( string& output ) { _sap("blezl\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } -void BGTZL( string& output ) { _sap("bgtzl\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } -void DADDI( string& output ) { _sap("daddi\t%s, %s, 0x%04X") GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED); } -void DADDIU( string& output ) { _sap("daddiu\t%s, %s, 0x%04X") GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED); } -void LDL( string& output ) { _sap("ldl\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void LDR( string& output ) { _sap("ldr\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void LB( string& output ) { _sap("lb\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void LH( string& output ) { _sap("lh\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void LWL( string& output ) { _sap("lwl\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void LW( string& output ) { _sap("lw\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void LBU( string& output ) { _sap("lbu\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void LHU( string& output ) { _sap("lhu\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void LWR( string& output ) { _sap("lwr\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void LWU( string& output ) { _sap("lwu\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void SB( string& output ) { _sap("sb\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void SH( string& output ) { _sap("sh\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void SWL( string& output ) { _sap("swl\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void SW( string& output ) { _sap("sw\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void SDL( string& output ) { _sap("sdl\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void SDR( string& output ) { _sap("sdr\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void SWR( string& output ) { _sap("swr\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void LD( string& output ) { _sap("ld\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void SD( string& output ) { _sap("sd\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void LQ( string& output ) { _sap("lq\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void SQ( string& output ) { _sap("sq\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void SWC1( string& output ) { _sap("swc1\t%s, 0x%04X(%s)") COP1_REG_FP[DECODE_FT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void SQC2( string& output ) { _sap("sqc2\t%s, 0x%04X(%s)") COP2_REG_FP[DECODE_FT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void PREF( string& output ) { output += "pref ---"; /*_sap("PREF\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[RS]); */} -void LWC1( string& output ) { _sap("lwc1\t%s, 0x%04X(%s)") COP1_REG_FP[DECODE_FT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -void LQC2( string& output ) { _sap("lqc2\t%s, 0x%04X(%s)") COP2_REG_FP[DECODE_FT], DECODE_IMMED, GPR_REG[DECODE_RS]); } -//********************END OF STANDARD OPCODES************************* - -void SLL( string& output ) -{ - if (cpuRegs.code == 0x00000000) - output += "nop"; - else - _sap("sll\t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); -} - -void SRL( string& output ) { _sap("srl\t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } -void SRA( string& output ) { _sap("sra\t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } -void SLLV( string& output ) { _sap("sllv\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } -void SRLV( string& output ) { _sap("srlv\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]);} -void SRAV( string& output ) { _sap("srav\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } -void JR( string& output ) { _sap("jr\t%s") GPR_REG[DECODE_RS]); } - -void JALR( string& output ) -{ - int rd = DECODE_RD; - - if (rd == 31) - _sap("jalr\t%s") GPR_REG[DECODE_RS]); - else - _sap("jalr\t%s, %s") GPR_REG[rd], GPR_REG[DECODE_RS]); -} - - -void SYNC( string& output ) { output += "SYNC"; } -void MFHI( string& output ) { _sap("mfhi\t%s") GPR_REG[DECODE_RD]); } -void MTHI( string& output ) { _sap("mthi\t%s") GPR_REG[DECODE_RS]); } -void MFLO( string& output ) { _sap("mflo\t%s") GPR_REG[DECODE_RD]); } -void MTLO( string& output ) { _sap("mtlo\t%s") GPR_REG[DECODE_RS]); } -void DSLLV( string& output ) { _sap("dsllv\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } -void DSRLV( string& output ) { _sap("dsrlv\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } -void DSRAV( string& output ) { _sap("dsrav\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } -void MULT( string& output ) { _sap("mult\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]);} -void MULTU( string& output ) { _sap("multu\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]);} -void DIV( string& output ) { _sap("div\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void DIVU( string& output ) { _sap("divu\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void ADD( string& output ) { _sap("add\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void ADDU( string& output ) { _sap("addu\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void SUB( string& output ) { _sap("sub\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void SUBU( string& output ) { _sap("subu\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void AND( string& output ) { _sap("and\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void OR( string& output ) { _sap("or\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void XOR( string& output ) { _sap("xor\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void NOR( string& output ) { _sap("nor\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void SLT( string& output ) { _sap("slt\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void SLTU( string& output ) { _sap("sltu\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void DADD( string& output ) { _sap("dadd\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void DADDU( string& output ) { _sap("daddu\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void DSUB( string& output ) { _sap("dsub\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void DSUBU( string& output ) { _sap("dsubu\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void TGE( string& output ) { _sap("tge\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void TGEU( string& output ) { _sap("tgeu\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void TLT( string& output ) { _sap("tlt\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void TLTU( string& output ) { _sap("tltu\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void TEQ( string& output ) { _sap("teq\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void TNE( string& output ) { _sap("tne\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void DSLL( string& output ) { _sap("dsll\t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } -void DSRL( string& output ) { _sap("dsrl\t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } -void DSRA( string& output ) { _sap("dsra\t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } -void DSLL32( string& output ) { _sap("dsll32\t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } -void DSRL32( string& output ) { _sap("dsrl32\t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } -void DSRA32( string& output ) { _sap("dsra32\t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } -void MOVZ( string& output ) { _sap("movz\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void MOVN( string& output ) { _sap("movn\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void MFSA( string& output ) { _sap("mfsa\t%s") GPR_REG[DECODE_RD]);} -void MTSA( string& output ) { _sap("mtsa\t%s") GPR_REG[DECODE_RS]);} -//*** unsupport (yet) cpu opcodes -void SYSCALL( string& output ) { output +="syscall ---";/*_sap("syscall\t0x%05X") DECODE_SYSCALL);*/} -void BREAK( string& output ) { output += "break ---";/*_sap("break\t0x%05X") DECODE_BREAK); */} -void CACHE( string& output ) { output += "cache ---";/*_sap("cache\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); */} -//************************REGIMM OPCODES*************************** -void BLTZ( string& output ) { _sap("bltz\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } -void BGEZ( string& output ) { _sap("bgez\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } -void BLTZL( string& output ) { _sap("bltzl\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } -void BGEZL( string& output ) { _sap("bgezl\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } -void TGEI( string& output ) { _sap("tgei\t%s, 0x%04X") GPR_REG[DECODE_RS], DECODE_IMMED); } -void TGEIU( string& output ) { _sap("tgeiu\t%s,0x%04X") GPR_REG[DECODE_RS], DECODE_IMMED); } -void TLTI( string& output ) { _sap("tlti\t%s, 0x%04X") GPR_REG[DECODE_RS], DECODE_IMMED); } -void TLTIU( string& output ) { _sap("tltiu\t%s,0x%04X") GPR_REG[DECODE_RS], DECODE_IMMED); } -void TEQI( string& output ) { _sap("teqi\t%s, 0x%04X") GPR_REG[DECODE_RS], DECODE_IMMED); } -void TNEI( string& output ) { _sap("tnei\t%s, 0x%04X") GPR_REG[DECODE_RS], DECODE_IMMED); } -void BLTZAL( string& output ) { _sap("bltzal\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } -void BGEZAL( string& output ) { _sap("bgezal\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } -void BLTZALL( string& output ) { _sap("bltzall\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } -void BGEZALL( string& output ) { _sap("bgezall\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } -void MTSAB( string& output ) { _sap("mtsab\t%s, 0x%04X") GPR_REG[DECODE_RS], DECODE_IMMED);} -void MTSAH( string& output ) { _sap("mtsah\t%s, 0x%04X") GPR_REG[DECODE_RS], DECODE_IMMED);} - - -//***************************SPECIAL 2 CPU OPCODES******************* -const char* pmfhl_sub[] = { "lw", "uw", "slw", "lh", "sh" }; - -void MADD( string& output ) { _sap("madd\t%s, %s %s") GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void MADDU( string& output ) { _sap("maddu\t%s, %s %s") GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]);} -void PLZCW( string& output ) { _sap("plzcw\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS]); } -void MADD1( string& output ) { _sap("madd1\t%s, %s %s") GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void MADDU1( string& output ) { _sap("maddu1\t%s, %s %s") GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void MFHI1( string& output ) { _sap("mfhi1\t%s") GPR_REG[DECODE_RD]); } -void MTHI1( string& output ) { _sap("mthi1\t%s") GPR_REG[DECODE_RS]); } -void MFLO1( string& output ) { _sap("mflo1\t%s") GPR_REG[DECODE_RD]); } -void MTLO1( string& output ) { _sap("mtlo1\t%s") GPR_REG[DECODE_RS]); } -void MULT1( string& output ) { _sap("mult1\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void MULTU1( string& output ) { _sap("multu1\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]);} -void DIV1( string& output ) { _sap("div1\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void DIVU1( string& output ) { _sap("divu1\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -//that have parametres that i haven't figure out how to display... -void PMFHL( string& output ) { _sap("pmfhl.%s \t%s") pmfhl_sub[DECODE_SA], GPR_REG[DECODE_RD]); } -void PMTHL( string& output ) { _sap("pmthl.%s \t%s") pmfhl_sub[DECODE_SA], GPR_REG[DECODE_RS]); } -void PSLLH( string& output ) { _sap("psllh \t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } -void PSRLH( string& output ) { _sap("psrlh \t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA);} -void PSRAH( string& output ) { _sap("psrah \t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA);} -void PSLLW( string& output ) { _sap( "psllw \t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA);} -void PSRLW( string& output ) { _sap( "psrlw \t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA);} -void PSRAW( string& output ) { _sap( "psraw \t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA);} -//***************************END OF SPECIAL OPCODES****************** -//*************************MMI0 OPCODES************************ - -void PADDW( string& output ){ _sap( "paddw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PSUBW( string& output ){ _sap( "psubw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PCGTW( string& output ){ _sap( "pcgtw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PMAXW( string& output ){ _sap( "pmaxw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PADDH( string& output ){ _sap( "paddh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PSUBH( string& output ){ _sap( "psubh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PCGTH( string& output ){ _sap( "pcgth\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PMAXH( string& output ){ _sap( "pmaxh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PADDB( string& output ){ _sap( "paddb\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PSUBB( string& output ){ _sap( "psubb\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PCGTB( string& output ){ _sap( "pcgtb\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PADDSW( string& output ){ _sap( "paddsw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PSUBSW( string& output ){ _sap( "psubsw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PEXTLW( string& output ){ _sap( "pextlw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PPACW( string& output ) { _sap( "ppacw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PADDSH( string& output ){ _sap( "paddsh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PSUBSH( string& output ){ _sap( "psubsh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PEXTLH( string& output ){ _sap( "pextlh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PPACH( string& output ) { _sap( "ppach\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PADDSB( string& output ){ _sap( "paddsb\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PSUBSB( string& output ){ _sap( "psubsb\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PEXTLB( string& output ){ _sap( "pextlb\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PPACB( string& output ) { _sap( "ppacb\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PEXT5( string& output ) { _sap( "pext5\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } -void PPAC5( string& output ) { _sap( "ppac5\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } -//**********END OF MMI0 OPCODES********************************* -//**********MMI1 OPCODES************************************** -void PABSW( string& output ){ _sap( "pabsw%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } -void PCEQW( string& output ){ _sap( "pceqw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PMINW( string& output ){ _sap( "pminw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PADSBH( string& output ){ _sap( "padsbh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PABSH( string& output ){ _sap( "pabsh%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } -void PCEQH( string& output ){ _sap( "pceqh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PMINH( string& output ){ _sap( "pminh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PCEQB( string& output ){ _sap( "pceqb\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PADDUW( string& output ){ _sap( "padduw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PSUBUW( string& output ){ _sap( "psubuw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PEXTUW( string& output ){ _sap( "pextuw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PADDUH( string& output ){ _sap( "padduh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PSUBUH( string& output ){ _sap( "psubuh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PEXTUH( string& output ){ _sap( "pextuh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PADDUB( string& output ){ _sap( "paddub\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PSUBUB( string& output ){ _sap( "psubub\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PEXTUB( string& output ){ _sap( "pextub\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void QFSRV( string& output ) { _sap( "qfsrv\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -//********END OF MMI1 OPCODES*********************************** -//*********MMI2 OPCODES*************************************** -void PMADDW( string& output ){ _sap( "pmaddw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PSLLVW( string& output ){ _sap( "psllvw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PSRLVW( string& output ){ _sap( "psrlvw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PMSUBW( string& output ){ _sap( "msubw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PMFHI( string& output ){ _sap( "pmfhi\t%s") GPR_REG[DECODE_RD]); } -void PMFLO( string& output ){ _sap( "pmflo\t%s") GPR_REG[DECODE_RD]); } -void PINTH( string& output ){ _sap( "pinth\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PMULTW( string& output ){ _sap( "pmultw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PDIVW( string& output ){ _sap( "pdivw\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PCPYLD( string& output ){ _sap( "pcpyld\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PMADDH( string& output ){ _sap( "pmaddh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PHMADH( string& output ){ _sap( "phmadh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PAND( string& output ){ _sap( "pand\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PXOR( string& output ){ _sap( "pxor\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PMSUBH( string& output ){ _sap( "pmsubh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PHMSBH( string& output ){ _sap( "phmsbh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PEXEH( string& output ){ _sap( "pexeh\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } -void PREVH( string& output ){ _sap( "prevh\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } -void PMULTH( string& output ){ _sap( "pmulth\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PDIVBW( string& output ){ _sap( "pdivbw\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PEXEW( string& output ){ _sap( "pexew\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } -void PROT3W( string& output ){ _sap( "prot3w\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } -//*****END OF MMI2 OPCODES*********************************** -//*************************MMI3 OPCODES************************ -void PMADDUW( string& output ){ _sap("pmadduw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } -void PSRAVW( string& output ){ _sap("psravw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } -void PMTHI( string& output ){ _sap("pmthi\t%s") GPR_REG[DECODE_RS]); } -void PMTLO( string& output ){ _sap("pmtlo\t%s") GPR_REG[DECODE_RS]); } -void PINTEH( string& output ){ _sap("pinteh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PMULTUW( string& output ){ _sap("pmultuw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PDIVUW( string& output ){ _sap("pdivuw\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PCPYUD( string& output ){ _sap("pcpyud\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void POR( string& output ){ _sap("por\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PNOR( string& output ){ _sap("pnor\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } -void PEXCH( string& output ){ _sap("pexch\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]);} -void PCPYH( string& output ){ _sap("pcpyh\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]);} -void PEXCW( string& output ){ _sap("pexcw\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]);} -//**********************END OF MMI3 OPCODES******************** - -//**************************************************************************** -//** COP0 ** -//**************************************************************************** -void MFC0( string& output ){ _sap("mfc0\t%s, %s") GPR_REG[DECODE_RT], COP0_REG[DECODE_FS]); } -void MTC0( string& output ){ _sap("mtc0\t%s, %s") GPR_REG[DECODE_RT], COP0_REG[DECODE_FS]); } -void BC0F( string& output ){ output += "bc0f\t"; offset_decode(output); } -void BC0T( string& output ){ output += "bc0t\t"; offset_decode(output); } -void BC0FL( string& output ){ output += "bc0fl\t"; offset_decode(output); } -void BC0TL( string& output ){ output += "bc0tl\t"; offset_decode(output); } -void TLBR( string& output ){ output += "tlbr";} -void TLBWI( string& output ){ output += "tlbwi";} -void TLBWR( string& output ){ output += "tlbwr";} -void TLBP( string& output ){ output += "tlbp";} -void ERET( string& output ){ output += "eret";} -void DI( string& output ){ output += "di";} -void EI( string& output ){ output += "ei";} -//**************************************************************************** -//** END OF COP0 ** -//**************************************************************************** -//**************************************************************************** -//** COP1 - Floating Point Unit (FPU) ** -//**************************************************************************** -void MFC1( string& output ){ _sap("mfc1\t%s, %s") GPR_REG[DECODE_RT], COP1_REG_FP[DECODE_FS]); } -void CFC1( string& output ){ _sap("cfc1\t%s, %s") GPR_REG[DECODE_RT], COP1_REG_FCR[DECODE_FS]); } -void MTC1( string& output ){ _sap("mtc1\t%s, %s") GPR_REG[DECODE_RT], COP1_REG_FP[DECODE_FS]); } -void CTC1( string& output ){ _sap("ctc1\t%s, %s") GPR_REG[DECODE_RT], COP1_REG_FCR[DECODE_FS]); } -void BC1F( string& output ){ output += "bc1f\t"; offset_decode(output); } -void BC1T( string& output ){ output += "bc1t\t"; offset_decode(output); } -void BC1FL( string& output ){ output += "bc1fl\t"; offset_decode(output); } -void BC1TL( string& output ){ output += "bc1tl\t"; offset_decode(output); } -void ADD_S( string& output ){ _sap("add.s\t%s, %s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]);} -void SUB_S( string& output ){ _sap("sub.s\t%s, %s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]);} -void MUL_S( string& output ){ _sap("mul.s\t%s, %s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]);} -void DIV_S( string& output ){ _sap("div.s\t%s, %s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } -void SQRT_S( string& output ){ _sap("sqrt.s\t%s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FT]); } -void ABS_S( string& output ){ _sap("abs.s\t%s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS]); } -void MOV_S( string& output ){ _sap("mov.s\t%s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS]); } -void NEG_S( string& output ){ _sap("neg.s\t%s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS]);} -void RSQRT_S( string& output ){_sap("rsqrt.s\t%s, %s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]);} -void ADDA_S( string& output ){ _sap("adda.s\t%s, %s") COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } -void SUBA_S( string& output ){ _sap("suba.s\t%s, %s") COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } -void MULA_S( string& output ){ _sap("mula.s\t%s, %s") COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } -void MADD_S( string& output ){ _sap("madd.s\t%s, %s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } -void MSUB_S( string& output ){ _sap("msub.s\t%s, %s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } -void MADDA_S( string& output ){_sap("madda.s\t%s, %s") COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } -void MSUBA_S( string& output ){_sap("msuba.s\t%s, %s") COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } -void CVT_W( string& output ){ _sap("cvt.w.s\t%s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS]); } -void MAX_S( string& output ){ _sap("max.s\t%s, %s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]);} -void MIN_S( string& output ){ _sap("min.s\t%s, %s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]);} -void C_F( string& output ){ _sap("c.f.s\t%s, %s") COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } -void C_EQ( string& output ){ _sap("c.eq.s\t%s, %s") COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } -void C_LT( string& output ){ _sap("c.lt.s\t%s, %s") COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } -void C_LE( string& output ){ _sap("c.le.s\t%s, %s") COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } -void CVT_S( string& output ){ _sap("cvt.s.w\t%s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS]); } -//**************************************************************************** -//** END OF COP1 ** -//**************************************************************************** - -} // End namespace R5900::OpcodeDisasm - -//**************************************************************************** -//** COP2 - (VU0) ** -//**************************************************************************** -void P_QMFC2( string& output ){ _sap("qmfc2\t%s, %s") GPR_REG[DECODE_RT], COP2_REG_FP[DECODE_FS]); } -void P_CFC2( string& output ){ _sap("cfc2\t%s, %s") GPR_REG[DECODE_RT], COP2_REG_CTL[DECODE_FS]); } -void P_QMTC2( string& output ){ _sap("qmtc2\t%s, %s") GPR_REG[DECODE_RT], COP2_REG_FP[DECODE_FS]); } -void P_CTC2( string& output ){ _sap("ctc2\t%s, %s") GPR_REG[DECODE_RT], COP2_REG_CTL[DECODE_FS]); } -void P_BC2F( string& output ){ output += "bc2f\t"; offset_decode(output); } -void P_BC2T( string& output ){ output += "bc2t\t"; offset_decode(output); } -void P_BC2FL( string& output ){ output += "bc2fl\t"; offset_decode(output); } -void P_BC2TL( string& output ){ output += "bc2tl\t"; offset_decode(output); } -//******************************SPECIAL 1 VUO TABLE**************************************** -#define _X ((cpuRegs.code>>24) & 1) -#define _Y ((cpuRegs.code>>23) & 1) -#define _Z ((cpuRegs.code>>22) & 1) -#define _W ((cpuRegs.code>>21) & 1) - -const char *dest_string(void) -{ - static char str[5]; - int i = 0; - - if(_X) str[i++] = 'x'; - if(_Y) str[i++] = 'y'; - if(_Z) str[i++] = 'z'; - if(_W) str[i++] = 'w'; - str[i++] = 0; - - return (const char *)str; -} - -char dest_fsf() -{ - const char arr[4] = { 'x', 'y', 'z', 'w' }; - return arr[(cpuRegs.code>>21)&3]; -} - -char dest_ftf() -{ - const char arr[4] = { 'x', 'y', 'z', 'w' }; - return arr[(cpuRegs.code>>23)&3]; -} - -void P_VADDx( string& output ){_sap("vaddx.%s %s, %s, %sx") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VADDy( string& output ){_sap("vaddy.%s %s, %s, %sy") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VADDz( string& output ){_sap("vaddz.%s %s, %s, %sz") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VADDw( string& output ){_sap("vaddw.%s %s, %s, %sw") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VSUBx( string& output ){_sap("vsubx.%s %s, %s, %sx") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VSUBy( string& output ){_sap("vsuby.%s %s, %s, %sy") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VSUBz( string& output ){_sap("vsubz.%s %s, %s, %sz") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VSUBw( string& output ){_sap("vsubw.%s %s, %s, %sw") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMADDx( string& output ){_sap("vmaddx.%s %s, %s, %sx") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMADDy( string& output ){_sap("vmaddy.%s %s, %s, %sy") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMADDz( string& output ){_sap("vmaddz.%s %s, %s, %sz") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMADDw( string& output ){_sap("vmaddw.%s %s, %s, %sw") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMSUBx( string& output ){_sap("vmsubx.%s %s, %s, %sx") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMSUBy( string& output ){_sap("vmsuby.%s %s, %s, %sy") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMSUBz( string& output ){_sap("vmsubz.%s %s, %s, %sz") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMSUBw( string& output ){_sap("vmsubw.%s %s, %s, %sw") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMAXx( string& output ){_sap("vmaxx.%s %s, %s, %sx") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMAXy( string& output ){_sap("vmaxy.%s %s, %s, %sy") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMAXz( string& output ){_sap("vmaxz.%s %s, %s, %sz") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMAXw( string& output ){_sap("vmaxw.%s %s, %s, %sw") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMINIx( string& output ){_sap("vminix.%s %s, %s, %sx") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMINIy( string& output ){_sap("vminiy.%s %s, %s, %sy") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); ;} -void P_VMINIz( string& output ){_sap("vminiz.%s %s, %s, %sz") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMINIw( string& output ){_sap("vminiw.%s %s, %s, %sw") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMULx( string& output ){_sap("vmulx.%s %s,%s,%sx") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMULy( string& output ){_sap("vmuly.%s %s,%s,%sy") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMULz( string& output ){_sap("vmulz.%s %s,%s,%sz") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMULw( string& output ){_sap("vmulw.%s %s,%s,%sw") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMULq( string& output ){_sap("vmulq.%s %s,%s,Q") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } -void P_VMAXi( string& output ){_sap("vmaxi.%s %s,%s,I") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } -void P_VMULi( string& output ){_sap("vmuli.%s %s,%s,I") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } -void P_VMINIi( string& output ){_sap("vminii.%s %s,%s,I") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } -void P_VADDq( string& output ){_sap("vaddq.%s %s,%s,Q") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } -void P_VMADDq( string& output ){_sap("vmaddq.%s %s,%s,Q") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } -void P_VADDi( string& output ){_sap("vaddi.%s %s,%s,I") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } -void P_VMADDi( string& output ){_sap("vmaddi.%s %s,%s,I") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } -void P_VSUBq( string& output ){_sap("vsubq.%s %s,%s,Q") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } -void P_VMSUBq( string& output ){_sap("vmsubq.%s %s,%s,Q") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } -void P_VSUbi( string& output ){_sap("vsubi.%s %s,%s,I") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } -void P_VMSUBi( string& output ){_sap("vmsubi.%s %s,%s,I") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } -void P_VADD( string& output ){_sap("vadd.%s %s, %s, %s") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMADD( string& output ){_sap("vmadd.%s %s, %s, %s") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMUL( string& output ){_sap("vmul.%s %s, %s, %s") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMAX( string& output ){_sap("vmax.%s %s, %s, %s") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VSUB( string& output ){_sap("vsub.%s %s, %s, %s") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMSUB( string& output ){_sap("vmsub.%s %s, %s, %s") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VOPMSUB( string& output ){_sap("vopmsub.xyz %s, %s, %s") COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMINI( string& output ){_sap("vmini.%s %s, %s, %s") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VIADD( string& output ){_sap("viadd %s, %s, %s") COP2_REG_CTL[DECODE_SA], COP2_REG_CTL[DECODE_FS], COP2_REG_CTL[DECODE_FT]);} -void P_VISUB( string& output ){_sap("visub %s, %s, %s") COP2_REG_CTL[DECODE_SA], COP2_REG_CTL[DECODE_FS], COP2_REG_CTL[DECODE_FT]);} -void P_VIADDI( string& output ){_sap("viaddi %s, %s, 0x%x") COP2_REG_CTL[DECODE_FT], COP2_REG_CTL[DECODE_FS], DECODE_SA);} -void P_VIAND( string& output ){_sap("viand %s, %s, %s") COP2_REG_CTL[DECODE_SA], COP2_REG_CTL[DECODE_FS], COP2_REG_CTL[DECODE_FT]);} -void P_VIOR( string& output ){_sap("vior %s, %s, %s") COP2_REG_CTL[DECODE_SA], COP2_REG_CTL[DECODE_FS], COP2_REG_CTL[DECODE_FT]);} -void P_VCALLMS( string& output ){output += "vcallms";} -void P_CALLMSR( string& output ){output += "callmsr";} -//***********************************END OF SPECIAL1 VU0 TABLE***************************** -//******************************SPECIAL2 VUO TABLE***************************************** -void P_VADDAx( string& output ){_sap("vaddax.%s ACC,%s,%sx") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VADDAy( string& output ){_sap("vadday.%s ACC,%s,%sy") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VADDAz( string& output ){_sap("vaddaz.%s ACC,%s,%sz") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VADDAw( string& output ){_sap("vaddaw.%s ACC,%s,%sw") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VSUBAx( string& output ){_sap("vsubax.%s ACC,%s,%sx") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VSUBAy( string& output ){_sap("vsubay.%s ACC,%s,%sy") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VSUBAz( string& output ){_sap("vsubaz.%s ACC,%s,%sz") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VSUBAw( string& output ){_sap("vsubaw.%s ACC,%s,%sw") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VMADDAx( string& output ){_sap("vmaddax.%s ACC,%s,%sx") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VMADDAy( string& output ){_sap("vmadday.%s ACC,%s,%sy") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VMADDAz( string& output ){_sap("vmaddaz.%s ACC,%s,%sz") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VMADDAw( string& output ){_sap("vmaddaw.%s ACC,%s,%sw") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VMSUBAx( string& output ){_sap("vmsubax.%s ACC,%s,%sx") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VMSUBAy( string& output ){_sap("vmsubay.%s ACC,%s,%sy") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VMSUBAz( string& output ){_sap("vmsubaz.%s ACC,%s,%sz") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VMSUBAw( string& output ){_sap("vmsubaw.%s ACC,%s,%sw") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VITOF0( string& output ){_sap("vitof0.%s %s, %s") dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } -void P_VITOF4( string& output ){_sap("vitof4.%s %s, %s") dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } -void P_VITOF12( string& output ){_sap("vitof12.%s %s, %s") dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } -void P_VITOF15( string& output ){_sap("vitof15.%s %s, %s") dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } -void P_VFTOI0( string& output ) {_sap("vftoi0.%s %s, %s") dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } -void P_VFTOI4( string& output ) {_sap("vftoi4.%s %s, %s") dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } -void P_VFTOI12( string& output ){_sap("vftoi12.%s %s, %s") dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } -void P_VFTOI15( string& output ){_sap("vftoi15.%s %s, %s") dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } -void P_VMULAx( string& output ){_sap("vmulax.%s ACC,%s,%sx") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VMULAy( string& output ){_sap("vmulay.%s ACC,%s,%sy") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VMULAz( string& output ){_sap("vmulaz.%s ACC,%s,%sz") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VMULAw( string& output ){_sap("vmulaw.%s ACC,%s,%sw") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} -void P_VMULAq( string& output ){_sap("vmulaq.%s ACC %s, Q") dest_string(), COP2_REG_FP[DECODE_FS]); } -void P_VABS( string& output ){_sap("vabs.%s %s, %s") dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]);} -void P_VMULAi( string& output ){_sap("vmulaq.%s ACC %s, I") dest_string(), COP2_REG_FP[DECODE_FS]); } -void P_VCLIPw( string& output ){_sap("vclip %sxyz, %sw") COP2_REG_FP[DECODE_FS], COP2_REG_FP[DECODE_FT]);} -void P_VADDAq( string& output ){_sap("vaddaq.%s ACC %s, Q") dest_string(), COP2_REG_FP[DECODE_FS]); } -void P_VMADDAq( string& output ){_sap("vmaddaq.%s ACC %s, Q") dest_string(), COP2_REG_FP[DECODE_FS]); } -void P_VADDAi( string& output ){_sap("vaddai.%s ACC %s, I") dest_string(), COP2_REG_FP[DECODE_FS]); } -void P_VMADDAi( string& output ){_sap("vmaddai.%s ACC %s, Q") dest_string(), COP2_REG_FP[DECODE_FS]); } -void P_VSUBAq( string& output ){_sap("vsubaq.%s ACC %s, Q") dest_string(), COP2_REG_FP[DECODE_FS]); } -void P_VMSUBAq( string& output ){_sap("vmsubaq.%s ACC %s, Q") dest_string(), COP2_REG_FP[DECODE_FS]); } -void P_VSUBAi( string& output ){_sap("vsubai.%s ACC %s, I") dest_string(), COP2_REG_FP[DECODE_FS]); } -void P_VMSUBAi( string& output ){_sap("vmsubai.%s ACC %s, I") dest_string(), COP2_REG_FP[DECODE_FS]); } -void P_VADDA( string& output ){_sap("vadda.%s ACC %s, %s") dest_string(), COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMADDA( string& output ){_sap("vmadda.%s ACC %s, %s") dest_string(), COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMULA( string& output ){_sap("vmula.%s ACC %s, %s") dest_string(), COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VSUBA( string& output ){_sap("vsuba.%s ACC %s, %s") dest_string(), COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VMSUBA( string& output ){_sap("vmsuba.%s ACC %s, %s") dest_string(), COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VOPMULA( string& output ){_sap("vopmula.xyz %sxyz, %sxyz") COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } -void P_VNOP( string& output ){output += "vnop";} -void P_VMONE( string& output ){_sap("vmove.%s, %s, %s") dest_string(), COP2_REG_FP[DECODE_FT],COP2_REG_FP[DECODE_FS]); } -void P_VMR32( string& output ){_sap("vmr32.%s, %s, %s") dest_string(), COP2_REG_FP[DECODE_FT],COP2_REG_FP[DECODE_FS]); } -void P_VLQI( string& output ){_sap("vlqi %s%s, (%s++)") COP2_REG_FP[DECODE_FT], dest_string(), COP2_REG_CTL[DECODE_FS]);} -void P_VSQI( string& output ){_sap("vsqi %s%s, (%s++)") COP2_REG_FP[DECODE_FS], dest_string(), COP2_REG_CTL[DECODE_FT]);} -void P_VLQD( string& output ){_sap("vlqd %s%s, (--%s)") COP2_REG_FP[DECODE_FT], dest_string(), COP2_REG_CTL[DECODE_FS]);} -void P_VSQD( string& output ){_sap("vsqd %s%s, (--%s)") COP2_REG_FP[DECODE_FS], dest_string(), COP2_REG_CTL[DECODE_FT]);} -void P_VDIV( string& output ){_sap("vdiv Q, %s%c, %s%c") COP2_REG_FP[DECODE_FS], dest_fsf(), COP2_REG_FP[DECODE_FT], dest_ftf());} -void P_VSQRT( string& output ){_sap("vsqrt Q, %s%c") COP2_REG_FP[DECODE_FT], dest_ftf());} -void P_VRSQRT( string& output ){_sap("vrsqrt Q, %s%c, %s%c") COP2_REG_FP[DECODE_FS], dest_fsf(), COP2_REG_FP[DECODE_FT], dest_ftf());} -void P_VWAITQ( string& output ){output += "vwaitq";} -void P_VMTIR( string& output ){_sap("vmtir %s, %s%c") COP2_REG_CTL[DECODE_FT], COP2_REG_FP[DECODE_FS], dest_fsf());} -void P_VMFIR( string& output ){_sap("vmfir %s%c, %s") COP2_REG_FP[DECODE_FT], dest_string(), COP2_REG_CTL[DECODE_FS]);} -void P_VILWR( string& output ){_sap("vilwr %s, (%s)%s") COP2_REG_CTL[DECODE_FT], COP2_REG_CTL[DECODE_FS], dest_string());} -void P_VISWR( string& output ){_sap("viswr %s, (%s)%s") COP2_REG_CTL[DECODE_FT], COP2_REG_CTL[DECODE_FS], dest_string());} -void P_VRNEXT( string& output ){_sap("vrnext %s%s, R") COP2_REG_CTL[DECODE_FT], dest_string());} -void P_VRGET( string& output ){_sap("vrget %s%s, R") COP2_REG_CTL[DECODE_FT], dest_string());} -void P_VRINIT( string& output ){_sap("vrinit R, %s%s") COP2_REG_CTL[DECODE_FS], dest_string());} -void P_VRXOR( string& output ){_sap("vrxor R, %s%s") COP2_REG_CTL[DECODE_FS], dest_string());} -//************************************END OF SPECIAL2 VUO TABLE**************************** - -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#ifdef __LINUX__ +#include +#endif + +#include "Debug.h" +#include "R5900.h" +#include "DisASM.h" +#include "R5900OpcodeTables.h" + +unsigned long opcode_addr; + +using namespace std; + +namespace R5900 +{ + +/* +//DECODE PROCUDURES + +//cop0 +#define DECODE_FS (DECODE_RD) +#define DECODE_FT (DECODE_RT) +#define DECODE_FD (DECODE_SA) +/// ******** + +#define DECODE_FUNCTION ((cpuRegs.code) & 0x3F) +#define DECODE_RD ((cpuRegs.code >> 11) & 0x1F) // The rd part of the instruction register +#define DECODE_RT ((cpuRegs.code >> 16) & 0x1F) // The rt part of the instruction register +#define DECODE_RS ((cpuRegs.code >> 21) & 0x1F) // The rs part of the instruction register +#define DECODE_SA ((cpuRegs.code >> 6) & 0x1F) // The sa part of the instruction register +#define DECODE_IMMED ( cpuRegs.code & 0xFFFF) // The immediate part of the instruction register +#define DECODE_OFFSET ((((short)DECODE_IMMED * 4) + opcode_addr + 4)) +#define DECODE_JUMP (opcode_addr & 0xf0000000)|((cpuRegs.code&0x3ffffff)<<2) +#define DECODE_SYSCALL ((opcode_addr & 0x03FFFFFF) >> 6) +#define DECODE_BREAK (DECODE_SYSCALL) +#define DECODE_C0BC ((cpuRegs.code >> 16) & 0x03) +#define DECODE_C1BC ((cpuRegs.code >> 16) & 0x03) +#define DECODE_C2BC ((cpuRegs.code >> 16) & 0x03) +*/ +/*************************CPUS REGISTERS**************************/ +static const char * const GPR_REG[32] = { + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" +}; +static const char * const COP0_REG[32] ={ + "Index","Random","EntryLo0","EntryLo1","Context","PageMask", + "Wired","C0r7","BadVaddr","Count","EntryHi","Compare","Status", + "Cause","EPC","PRId","Config","C0r17","C0r18","C0r19","C0r20", + "C0r21","C0r22","C0r23","Debug","Perf","C0r26","C0r27","TagLo", + "TagHi","ErrorPC","C0r31" +}; +//floating point cop1 Floating point reg +static const char * const COP1_REG_FP[32] ={ + "f00","f01","f02","f03","f04","f05","f06","f07", + "f08","f09","f10","f11","f12","f13","f14","f15", + "f16","f17","f18","f19","f20","f21","f21","f23", + "f24","f25","f26","f27","f28","f29","f30","f31" +}; +//floating point cop1 control registers +static const char * const COP1_REG_FCR[32] ={ + "fcr00","fcr01","fcr02","fcr03","fcr04","fcr05","fcr06","fcr07", + "fcr08","fcr09","fcr10","fcr11","fcr12","fcr13","fcr14","fcr15", + "fcr16","fcr17","fcr18","fcr19","fcr20","fcr21","fcr21","fcr23", + "fcr24","fcr25","fcr26","fcr27","fcr28","fcr29","fcr30","fcr31" +}; + +//floating point cop2 reg +static const char * const COP2_REG_FP[32] ={ + "vf00","vf01","vf02","vf03","vf04","vf05","vf06","vf07", + "vf08","vf09","vf10","vf11","vf12","vf13","vf14","vf15", + "vf16","vf17","vf18","vf19","vf20","vf21","vf21","vf23", + "vf24","vf25","vf26","vf27","vf28","vf29","vf30","vf31" +}; +//cop2 control registers + +static const char * const COP2_REG_CTL[32] ={ + "vi00","vi01","vi02","vi03","vi04","vi05","vi06","vi07", + "vi08","vi09","vi10","vi11","vi12","vi13","vi14","vi15", + "Status","MACflag","ClipFlag","c2c19","R","I","Q","c2c23", + "c2c24","c2c25","TPC","CMSAR0","FBRST","VPU-STAT","c2c30","CMSAR1" +}; + +void P_COP2_Unknown( string& output ); +void P_COP2_SPECIAL2( string& output ); +void P_COP2_SPECIAL( string& output ); +void P_COP2_BC2( string& output ); + +//**************************************************************************** +//** COP2 - (VU0) ** +//**************************************************************************** +void P_QMFC2( string& output ); +void P_CFC2( string& output ); +void P_QMTC2( string& output ); +void P_CTC2( string& output ); +void P_BC2F( string& output ); +void P_BC2T( string& output ); +void P_BC2FL( string& output ); +void P_BC2TL( string& output ); +//*****************SPECIAL 1 VUO TABLE******************************* +void P_VADDx( string& output ); +void P_VADDy( string& output ); +void P_VADDz( string& output ); +void P_VADDw( string& output ); +void P_VSUBx( string& output ); +void P_VSUBy( string& output ); +void P_VSUBz( string& output ); +void P_VSUBw( string& output ); +void P_VMADDx( string& output ); +void P_VMADDy( string& output ); +void P_VMADDz( string& output ); +void P_VMADDw( string& output ); +void P_VMSUBx( string& output ); +void P_VMSUBy( string& output ); +void P_VMSUBz( string& output ); +void P_VMSUBw( string& output ); +void P_VMAXx( string& output ); +void P_VMAXy( string& output ); +void P_VMAXz( string& output ); +void P_VMAXw( string& output ); +void P_VMINIx( string& output ); +void P_VMINIy( string& output ); +void P_VMINIz( string& output ); +void P_VMINIw( string& output ); +void P_VMULx( string& output ); +void P_VMULy( string& output ); +void P_VMULz( string& output ); +void P_VMULw( string& output ); +void P_VMULq( string& output ); +void P_VMAXi( string& output ); +void P_VMULi( string& output ); +void P_VMINIi( string& output ); +void P_VADDq( string& output ); +void P_VMADDq( string& output ); +void P_VADDi( string& output ); +void P_VMADDi( string& output ); +void P_VSUBq( string& output ); +void P_VMSUBq( string& output ); +void P_VSUbi( string& output ); +void P_VMSUBi( string& output ); +void P_VADD( string& output ); +void P_VMADD( string& output ); +void P_VMUL( string& output ); +void P_VMAX( string& output ); +void P_VSUB( string& output ); +void P_VMSUB( string& output ); +void P_VOPMSUB( string& output ); +void P_VMINI( string& output ); +void P_VIADD( string& output ); +void P_VISUB( string& output ); +void P_VIADDI( string& output ); +void P_VIAND( string& output ); +void P_VIOR( string& output ); +void P_VCALLMS( string& output ); +void P_CALLMSR( string& output ); +//***********************************END OF SPECIAL1 VU0 TABLE***************************** +//******************************SPECIAL2 VUO TABLE***************************************** +void P_VADDAx( string& output ); +void P_VADDAy( string& output ); +void P_VADDAz( string& output ); +void P_VADDAw( string& output ); +void P_VSUBAx( string& output ); +void P_VSUBAy( string& output ); +void P_VSUBAz( string& output ); +void P_VSUBAw( string& output ); +void P_VMADDAx( string& output ); +void P_VMADDAy( string& output ); +void P_VMADDAz( string& output ); +void P_VMADDAw( string& output ); +void P_VMSUBAx( string& output ); +void P_VMSUBAy( string& output ); +void P_VMSUBAz( string& output ); +void P_VMSUBAw( string& output ); +void P_VITOF0( string& output ); +void P_VITOF4( string& output ); +void P_VITOF12( string& output ); +void P_VITOF15( string& output ); +void P_VFTOI0( string& output ); +void P_VFTOI4( string& output ); +void P_VFTOI12( string& output ); +void P_VFTOI15( string& output ); +void P_VMULAx( string& output ); +void P_VMULAy( string& output ); +void P_VMULAz( string& output ); +void P_VMULAw( string& output ); +void P_VMULAq( string& output ); +void P_VABS( string& output ); +void P_VMULAi( string& output ); +void P_VCLIPw( string& output ); +void P_VADDAq( string& output ); +void P_VMADDAq( string& output ); +void P_VADDAi( string& output ); +void P_VMADDAi( string& output ); +void P_VSUBAq( string& output ); +void P_VMSUBAq( string& output ); +void P_VSUBAi( string& output ); +void P_VMSUBAi( string& output ); +void P_VADDA( string& output ); +void P_VMADDA( string& output ); +void P_VMULA( string& output ); +void P_VSUBA( string& output ); +void P_VMSUBA( string& output ); +void P_VOPMULA( string& output ); +void P_VNOP( string& output ); +void P_VMONE( string& output ); +void P_VMR32( string& output ); +void P_VLQI( string& output ); +void P_VSQI( string& output ); +void P_VLQD( string& output ); +void P_VSQD( string& output ); +void P_VDIV( string& output ); +void P_VSQRT( string& output ); +void P_VRSQRT( string& output ); +void P_VWAITQ( string& output ); +void P_VMTIR( string& output ); +void P_VMFIR( string& output ); +void P_VILWR( string& output ); +void P_VISWR( string& output ); +void P_VRNEXT( string& output ); +void P_VRGET( string& output ); +void P_VRINIT( string& output ); +void P_VRXOR( string& output ); +//************************************END OF SPECIAL2 VUO TABLE**************************** + + +/* + CPU: Instructions encoded by opcode field. + 31---------26---------------------------------------------------0 + | opcode | | + ------6---------------------------------------------------------- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo +000 | *1 | *2 | J | JAL | BEQ | BNE | BLEZ | BGTZ | +001 | ADDI | ADDIU | SLTI | SLTIU | ANDI | ORI | XORI | LUI | +010 | *3 | *4 | *5 | --- | BEQL | BNEL | BLEZL | BGTZL | +011 | DADDI |DADDIU | LDL | LDR | *6 | --- | LQ | SQ | +100 | LB | LH | LWL | LW | LBU | LHU | LWR | LWU | +101 | SB | SH | SWL | SW | SDL | SDR | SWR | CACHE | +110 | --- | LWC1 | --- | PREF | --- | --- | LQC2 | LD | +111 | --- | SWC1 | --- | --- | --- | --- | SQC2 | SD | + hi |-------|-------|-------|-------|-------|-------|-------|-------| + *1 = SPECIAL, see SPECIAL list *2 = REGIMM, see REGIMM list + *3 = COP0 *4 = COP1 + *5 = COP2 *6 = MMI table +*/ + +/* + SPECIAL: Instr. encoded by function field when opcode field = SPECIAL + 31---------26------------------------------------------5--------0 + | = SPECIAL | | function| + ------6----------------------------------------------------6----- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo +000 | SLL | --- | SRL | SRA | SLLV | --- | SRLV | SRAV | +001 | JR | JALR | MOVZ | MOVN |SYSCALL| BREAK | --- | SYNC | +010 | MFHI | MTHI | MFLO | MTLO | DSLLV | --- | DSRLV | DSRAV | +011 | MULT | MULTU | DIV | DIVU | ---- | --- | ---- | ----- | +100 | ADD | ADDU | SUB | SUBU | AND | OR | XOR | NOR | +101 | MFSA | MTSA | SLT | SLTU | DADD | DADDU | DSUB | DSUBU | +110 | TGE | TGEU | TLT | TLTU | TEQ | --- | TNE | --- | +111 | DSLL | --- | DSRL | DSRA |DSLL32 | --- |DSRL32 |DSRA32 | + hi |-------|-------|-------|-------|-------|-------|-------|-------| +*/ + +/* + REGIMM: Instructions encoded by the rt field when opcode field = REGIMM. + 31---------26----------20-------16------------------------------0 + | = REGIMM | | rt | | + ------6---------------------5------------------------------------ + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo + 00 | BLTZ | BGEZ | BLTZL | BGEZL | --- | --- | --- | --- | + 01 | TGEI | TGEIU | TLTI | TLTIU | TEQI | --- | TNEI | --- | + 10 | BLTZAL| BGEZAL|BLTZALL|BGEZALL| --- | --- | --- | --- | + 11 | MTSAB | MTSAH | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| +*/ + +/* + MMI: Instr. encoded by function field when opcode field = MMI + 31---------26------------------------------------------5--------0 + | = MMI | | function| + ------6----------------------------------------------------6----- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo +000 | MADD | MADDU | --- | --- | PLZCW | --- | --- | --- | +001 | *1 | *2 | --- | --- | --- | --- | --- | --- | +010 | MFHI1 | MTHI1 | MFLO1 | MTLO1 | --- | --- | --- | --- | +011 | MULT1 | MULTU1| DIV1 | DIVU1 | --- | --- | --- | --- | +100 | MADD1 | MADDU1| --- | --- | --- | --- | --- | --- | +101 | *3 | *4 | --- | --- | --- | --- | --- | --- | +110 | PMFHL | PMTHL | --- | --- | PSLLH | --- | PSRLH | PSRAH | +111 | --- | --- | --- | --- | PSLLW | --- | PSRLW | PSRAW | + hi |-------|-------|-------|-------|-------|-------|-------|-------| + + *1 = see MMI0 table *2 = see MMI2 Table + *3 = see MMI1 table *4 = see MMI3 Table +*/ + +/* + MMI0: Instr. encoded by function field when opcode field = MMI & MMI0 + + 31---------26------------------------------10--------6-5--------0 + | | |function | MMI0 | + ------6----------------------------------------------------6----- + |--000--|--001--|--010--|--011--| lo +000 |PADDW | PSUBW | PCGTW | PMAXW | +001 |PADDH | PSUBH | PCGTH | PMAXH | +010 |PADDB | PSUBB | PCGTB | --- | +011 | --- | --- | --- | --- | +100 |PADDSW |PSUBSW |PEXTLW | PPACW | +101 |PADDSH |PSUBSH |PEXTLH | PPACH | +110 |PADDSB |PSUBSB |PEXTLB | PPACB | +111 | --- | --- | PEXT5 | PPAC5 | + hi |-------|-------|-------|-------| +*/ + +/* + MMI1: Instr. encoded by function field when opcode field = MMI & MMI1 + + 31---------26------------------------------------------5--------0 + | | |function | MMI1 | + ------6----------------------------------------------------6----- + |--000--|--001--|--010--|--011--| lo +000 | --- | PABSW | PCEQW | PMINW | +001 |PADSBH | PABSH | PCEQH | PMINH | +010 | --- | --- | PCEQB | --- | +011 | --- | --- | --- | --- | +100 |PADDUW |PSUBUW |PEXTUW | --- | +101 |PADDUH |PSUBUH |PEXTUH | --- | +110 |PADDUB |PSUBUB |PEXTUB | QFSRV | +111 | --- | --- | --- | --- | + hi |-------|-------|-------|-------| +*/ + +/* + MMI2: Instr. encoded by function field when opcode field = MMI & MMI2 + + 31---------26------------------------------------------5--------0 + | | |function | MMI2 | + ------6----------------------------------------------------6----- + |--000--|--001--|--010--|--011--| lo +000 |PMADDW | --- |PSLLVW |PSRLVW | +001 |PMSUBW | --- | --- | --- | +010 |PMFHI |PMFLO |PINTH | --- | +011 |PMULTW |PDIVW |PCPYLD | --- | +100 |PMADDH |PHMADH | PAND | PXOR | +101 |PMSUBH |PHMSBH | --- | --- | +110 | --- | --- | PEXEH | PREVH | +111 |PMULTH |PDIVBW | PEXEW |PROT3W | + hi |-------|-------|-------|-------| +*/ + +/* + MMI3: Instr. encoded by function field when opcode field = MMI & MMI3 + 31---------26------------------------------------------5--------0 + | | |function | MMI3 | + ------6----------------------------------------------------6----- + |--000--|--001--|--010--|--011--| lo +000 |PMADDUW| --- | --- |PSRAVW | +001 | --- | --- | --- | --- | +010 |PMTHI | PMTLO |PINTEH | --- | +011 |PMULTUW| PDIVUW|PCPYUD | --- | +100 | --- | --- | POR | PNOR | +101 | --- | --- | --- | --- | +110 | --- | --- | PEXCH | PCPYH | +111 | --- | --- | PEXCW | --- | + hi |-------|-------|-------|-------| + */ + +/* + COP0: Instructions encoded by the rs field when opcode = COP0. + 31--------26-25------21 ----------------------------------------0 + | = COP0 | fmt | | + ------6----------5----------------------------------------------- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo + 00 | MFC0 | --- | --- | --- | MTC0 | --- | --- | --- | + 01 | *1 | --- | --- | --- | --- | --- | --- | --- | + 10 | *2 | --- | --- | --- | --- | --- | --- | --- | + 11 | --- | --- | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| + *1=BC See BC0 list *2 = TLB instr, see TLB list +*/ +/* + BC0: Instructions encoded by the rt field when opcode = COP0 & rs field=BC0 + 31--------26-25------21 ----------------------------------------0 + | = COP0 | fmt | | + ------6----------5----------------------------------------------- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo + 00 | BC0F | BC0T | BC0FL | BC0TL | --- | --- | --- | --- | + 01 | --- | --- | --- | --- | --- | --- | --- | --- | + 10 | --- | --- | --- | --- | --- | --- | --- | --- | + 11 | --- | --- | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| +*/ +/* + C0=Instructions encode by function field when Opcode field=COP0 & rs field=C0 + 31---------26------------------------------------------5--------0 + | | | | + ------6----------------------------------------------------6----- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo +000 | --- | TLBR | TLBWI | --- | --- | --- | TLBWR | --- | +001 | TLBP | --- | --- | --- | --- | --- | --- | --- | +010 | --- | --- | --- | --- | --- | --- | --- | --- | +011 | ERET | --- | --- | --- | --- | --- | --- | --- | +100 | --- | --- | --- | --- | --- | --- | --- | --- | +101 | --- | --- | --- | --- | --- | --- | --- | --- | +110 | --- | --- | --- | --- | --- | --- | --- | --- | +111 | EI | DI | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| +*/ +/* + COP1: Instructions encoded by the fmt field when opcode = COP1. + 31--------26-25------21 ----------------------------------------0 + | = COP1 | fmt | | + ------6----------5----------------------------------------------- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo + 00 | MFC1 | --- | CFC1 | --- | MTC1 | --- | CTC1 | --- | + 01 | *1 | --- | --- | --- | --- | --- | --- | --- | + 10 | *2 | --- | --- | --- | *3 | --- | --- | --- | + 11 | --- | --- | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| + *1 = BC instructions, see BC1 list *2 = S instr, see FPU list + *3 = W instr, see FPU list +*/ +/* + BC1: Instructions encoded by the rt field when opcode = COP1 & rs field=BC1 + 31--------26-25------21 ----------------------------------------0 + | = COP1 | fmt | | + ------6----------5----------------------------------------------- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo + 00 | BC1F | BC1T | BC1FL | BC1TL | --- | --- | --- | --- | + 01 | --- | --- | --- | --- | --- | --- | --- | --- | + 10 | --- | --- | --- | --- | --- | --- | --- | --- | + 11 | --- | --- | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| +*/ +/* + FPU: Instructions encoded by the function field when opcode = COP1 + and rs = S + 31--------26-25------21 -------------------------------5--------0 + | = COP1 | = S | | function| + ------6----------5-----------------------------------------6----- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo +000 | ADD.S | SUB.S | MUL.S | DIV.S | SQRT.S| ABS.S | MOV.S | NEG.S | +001 | --- | --- | --- | --- | --- | --- | --- | --- | +010 | --- | --- | --- | --- | --- | --- |RSQRT.S| --- | +011 | ADDA.S| SUBA.S| MULA.S| --- | MADD.S| MSUB.S|MADDA.S|MSUBA.S| +100 | --- | --- | --- | --- | CVT.W | --- | --- | --- | +101 | MAX.S | MIN.S | --- | --- | --- | --- | --- | --- | +110 | C.F | --- | C.EQ | --- | C.LT | --- | C.LE | --- | +111 | --- | --- | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| +*/ +/* + FPU: Instructions encoded by the function field when opcode = COP1 + and rs = W + 31--------26-25------21 -------------------------------5--------0 + | = COP1 | = W | | function| + ------6----------5-----------------------------------------6----- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo +000 | --- | --- | --- | --- | --- | --- | --- | --- | +001 | --- | --- | --- | --- | --- | --- | --- | --- | +010 | --- | --- | --- | --- | --- | --- | --- | --- | +011 | --- | --- | --- | --- | --- | --- | --- | --- | +100 | CVT.S | --- | --- | --- | --- | --- | --- | --- | +101 | --- | --- | --- | --- | --- | --- | --- | --- | +110 | --- | --- | --- | --- | --- | --- | --- | --- | +111 | --- | --- | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| +*/ + +//************************************************************* +// COP2 TABLES :) [VU0 as a Co-Processor to the EE] +//************************************************************* +/* + COP2: Instructions encoded by the fmt field when opcode = COP2. + 31--------26-25------21 ----------------------------------------0 + | = COP2 | fmt | | + ------6----------5----------------------------------------------- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo + 00 | --- | QMFC2 | CFC2 | --- | --- | QMTC2 | CTC2 | --- | + 01 | *1 | --- | --- | --- | --- | --- | --- | --- | + 10 | *2 | *2 | *2 | *2 | *2 | *2 | *2 | *2 | + 11 | *2 | *2 | *2 | *2 | *2 | *2 | *2 | *2 | + hi |-------|-------|-------|-------|-------|-------|-------|-------| + *1 = BC instructions, see BC2 list *2 =see special1 table +*/ +void (*COP2PrintTable[32])( string& output ) = { + P_COP2_Unknown, P_QMFC2, P_CFC2, P_COP2_Unknown, P_COP2_Unknown, P_QMTC2, P_CTC2, P_COP2_Unknown, + P_COP2_BC2, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, + P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, + P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, P_COP2_SPECIAL, + + +}; +/* + BC2: Instructions encoded by the rt field when opcode = COP2 & rs field=BC1 + 31--------26-25------21 ----------------------------------------0 + | = COP2 | rs=BC2| | + ------6----------5----------------------------------------------- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo + 00 | BC2F | BC2T | BC2FL | BC2TL | --- | --- | --- | --- | + 01 | --- | --- | --- | --- | --- | --- | --- | --- | + 10 | --- | --- | --- | --- | --- | --- | --- | --- | + 11 | --- | --- | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| + */ +void (*COP2BC2PrintTable[32])( string& output ) = { + P_BC2F, P_BC2T, P_BC2FL, P_BC2TL, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, + P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, + P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, + P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, P_COP2_Unknown, +}; +/* + Special1 table : instructions encode by function field when opcode=COP2 & rs field=Special1 + 31---------26---------------------------------------------------0 + | =COP2 | rs=Special | + ------6---------------------------------------------------------- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo +000 |VADDx |VADDy |VADDz |VADDw |VSUBx |VSUBy |VSUBz |VSUBw | +001 |VMADDx |VMADDy |VMADDz |VMADDw |VMSUBx |VMSUBy |VMSUBz |VMSUBw | +010 |VMAXx |VMAXy |VMAXz |VMAXw |VMINIx |VMINIy |VMINIz |VMINIw | +011 |VMULx |VMULy |VMULz |VMULw |VMULq |VMAXi |VMULi |VMINIi | +100 |VADDq |VMADDq |VADDi |VMADDi |VSUBq |VMSUBq |VSUbi |VMSUBi | +101 |VADD |VMADD |VMUL |VMAX |VSUB |VMSUB |VOPMSUB|VMINI | +110 |VIADD |VISUB |VIADDI | --- |VIAND |VIOR | --- | --- | +111 |VCALLMS|CALLMSR| --- | --- | *1 | *1 | *1 | *1 | + hi |-------|-------|-------|-------|-------|-------|-------|-------| + *1=see special2 table +*/ +void (*COP2SPECIAL1PrintTable[64])( string& output ) = +{ + P_VADDx, P_VADDy, P_VADDz, P_VADDw, P_VSUBx, P_VSUBy, P_VSUBz, P_VSUBw, + P_VMADDx, P_VMADDy, P_VMADDz, P_VMADDw, P_VMSUBx, P_VMSUBy, P_VMSUBz, P_VMSUBw, + P_VMAXx, P_VMAXy, P_VMAXz, P_VMAXw, P_VMINIx, P_VMINIy, P_VMINIz, P_VMINIw, + P_VMULx, P_VMULy, P_VMULz, P_VMULw, P_VMULq, P_VMAXi, P_VMULi, P_VMINIi, + P_VADDq, P_VMADDq, P_VADDi, P_VMADDi, P_VSUBq, P_VMSUBq, P_VSUbi, P_VMSUBi, + P_VADD, P_VMADD, P_VMUL, P_VMAX, P_VSUB, P_VMSUB, P_VOPMSUB, P_VMINI, + P_VIADD, P_VISUB, P_VIADDI, P_COP2_Unknown,P_VIAND, P_VIOR, P_COP2_Unknown, P_COP2_Unknown, + P_VCALLMS, P_CALLMSR, P_COP2_Unknown,P_COP2_Unknown,P_COP2_SPECIAL2,P_COP2_SPECIAL2,P_COP2_SPECIAL2,P_COP2_SPECIAL2, + +}; +/* + Special2 table : instructions encode by function field when opcode=COp2 & rs field=Special2 + + 31---------26---------------------------------------------------0 + | =COP2 | rs=Special2 | + ------6---------------------------------------------------------- + |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo +0000 |VADDAx |VADDAy |VADDAz |VADDAw |VSUBAx |VSUBAy |VSUBAz |VSUBAw | +0001 |VMADDAx|VMADDAy|VMADDAz|VMADDAw|VMSUBAx|VMSUBAy|VMSUBAz|VMSUBAw| +0010 |VITOF0 |VITOF4 |VITOF12|VITOF15|VFTOI0 |VFTOI4 |VFTOI12|VFTOI15| +0011 |VMULAx |VMULAy |VMULAz |VMULAw |VMULAq |VABS |VMULAi |VCLIPw | +0100 |VADDAq |VMADDAq|VADDAi |VMADDAi|VSUBAq |VMSUBAq|VSUBAi |VMSUBAi| +0101 |VADDA |VMADDA |VMULA | --- |VSUBA |VMSUBA |VOPMULA|VNOP | +0110 |VMONE |VMR32 | --- | --- |VLQI |VSQI |VLQD |VSQD | +0111 |VDIV |VSQRT |VRSQRT |VWAITQ |VMTIR |VMFIR |VILWR |VISWR | +1000 |VRNEXT |VRGET |VRINIT |VRXOR | --- | --- | --- | --- | +1001 | --- | --- | --- | --- | --- | --- | --- | --- | +1010 | --- | --- | --- | --- | --- | --- | --- | --- | +1011 | --- | --- | --- | --- | --- | --- | --- | --- | +1100 | --- | --- | --- | --- | --- | --- | --- | --- | +1101 | --- | --- | --- | --- | --- | --- | --- | --- | +1110 | --- | --- | --- | --- | --- | --- | --- | --- | +1111 | --- | --- | --- | --- | --- | --- | --- | --- | + hi |-------|-------|-------|-------|-------|-------|-------|-------| +*/ +void (*COP2SPECIAL2PrintTable[128])( string& output ) = +{ + P_VADDAx ,P_VADDAy ,P_VADDAz ,P_VADDAw ,P_VSUBAx ,P_VSUBAy ,P_VSUBAz ,P_VSUBAw, + P_VMADDAx ,P_VMADDAy ,P_VMADDAz ,P_VMADDAw ,P_VMSUBAx ,P_VMSUBAy ,P_VMSUBAz ,P_VMSUBAw, + P_VITOF0 ,P_VITOF4 ,P_VITOF12 ,P_VITOF15 ,P_VFTOI0 ,P_VFTOI4 ,P_VFTOI12 ,P_VFTOI15, + P_VMULAx ,P_VMULAy ,P_VMULAz ,P_VMULAw ,P_VMULAq ,P_VABS ,P_VMULAi ,P_VCLIPw, + P_VADDAq ,P_VMADDAq ,P_VADDAi ,P_VMADDAi ,P_VSUBAq ,P_VMSUBAq ,P_VSUBAi ,P_VMSUBAi, + P_VADDA ,P_VMADDA ,P_VMULA ,P_COP2_Unknown,P_VSUBA ,P_VMSUBA ,P_VOPMULA ,P_VNOP, + P_VMONE ,P_VMR32 ,P_COP2_Unknown,P_COP2_Unknown,P_VLQI ,P_VSQI ,P_VLQD ,P_VSQD, + P_VDIV ,P_VSQRT ,P_VRSQRT ,P_VWAITQ ,P_VMTIR ,P_VMFIR ,P_VILWR ,P_VISWR, + P_VRNEXT ,P_VRGET ,P_VRINIT ,P_VRXOR ,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, + P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, + P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, + P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, + P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, + P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, + P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, + P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown,P_COP2_Unknown, +}; + +//**************************TABLES CALLS*********************** + + +void disR5900Fasm(string& output, u32 code, u32 pc) +{ + string dbuf; + char obuf[48]; + + const u32 scode = cpuRegs.code; + opcode_addr = pc; + cpuRegs.code = code; + + sprintf(obuf, "%08X:\t", pc ); + output.assign( obuf ); + GetCurrentInstruction().disasm( output ); + + cpuRegs.code = scode; +} + +//************************************************************* +//************************COP2********************************** +void P_COP2_BC2( string& output ) +{ + COP2BC2PrintTable[DECODE_C2BC]( output ); +} +void P_COP2_SPECIAL( string& output ) +{ + COP2SPECIAL1PrintTable[DECODE_FUNCTION ]( output ); +} +void P_COP2_SPECIAL2( string& output ) +{ + COP2SPECIAL2PrintTable[(cpuRegs.code & 0x3) | ((cpuRegs.code >> 4) & 0x7c)]( output ); +} + +//**************************UNKNOWN**************************** +void P_COP2_Unknown( string& output ) +{ + output += "COP2 ??"; +} + + +//************************************************************* + +//*****************SOME DECODE STUFF*************************** + +void label_decode( string& output, u32 addr ) +{ + string buf; + ssprintf(buf, "0x%08X", addr); + const char* label = disR5900GetSym( addr ); + + if( label != NULL ) + { + output += label; + output += ' '; + } + + output += buf; +} + +void jump_decode( string& output ) +{ + label_decode( output, DECODE_JUMP ); +} + +void offset_decode( string& output ) +{ + label_decode( output, DECODE_OFFSET ); +} + +//*********************END OF DECODE ROUTINES****************** + +namespace OpcodeDisasm +{ + +void COP2( string& output ) +{ + COP2PrintTable[DECODE_RS]( output ); +} + +// Unkown Opcode! +void Unknown( string& output ) +{ + output += "?????"; +} + +void MMI_Unknown( string& output ) +{ + output += "MMI ??"; +} + +void COP0_Unknown( string& output ) +{ + output += "COP0 ??"; +} + +void COP1_Unknown( string& output ) +{ + output += "FPU ??"; +} + +// sap! it stands for string append. It's not a friendly name but for now it makes +// the copy-paste marathon of code below more readable! +#define _sap( str ) ssappendf( output, str, + +//********************* Standard Opcodes*********************** +void J( string& output ) { output += "j\t"; jump_decode(output);} +void JAL( string& output ) { output += "jal\t"; jump_decode(output);} +void BEQ( string& output ) { _sap("beq\t%s, %s, ") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); offset_decode(output); } +void BNE( string& output ) { _sap("bne\t%s, %s, ") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); offset_decode(output); } +void BLEZ( string& output ) { _sap("blez\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } +void BGTZ( string& output ) { _sap("bgtz\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } +void ADDI( string& output ) { _sap("addi\t%s, %s, 0x%04X") GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED);} +void ADDIU( string& output ) { _sap("addiu\t%s, %s, 0x%04X") GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED);} +void SLTI( string& output ) { _sap("slti\t%s, %s, 0x%04X") GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED); } +void SLTIU( string& output ) { _sap("sltiu\t%s, %s, 0x%04X") GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED); } +void ANDI( string& output ) { _sap("andi\t%s, %s, 0x%04X") GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED);} +void ORI( string& output ) { _sap("ori\t%s, %s, 0x%04X") GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED); } +void XORI( string& output ) { _sap("xori\t%s, %s, 0x%04X") GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED); } +void LUI( string& output ) { _sap("lui\t%s, 0x%04X") GPR_REG[DECODE_RT], DECODE_IMMED); } +void BEQL( string& output ) { _sap("beql\t%s, %s, ") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); offset_decode(output); } +void BNEL( string& output ) { _sap("bnel\t%s, %s, ") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); offset_decode(output); } +void BLEZL( string& output ) { _sap("blezl\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } +void BGTZL( string& output ) { _sap("bgtzl\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } +void DADDI( string& output ) { _sap("daddi\t%s, %s, 0x%04X") GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED); } +void DADDIU( string& output ) { _sap("daddiu\t%s, %s, 0x%04X") GPR_REG[DECODE_RT], GPR_REG[DECODE_RS], DECODE_IMMED); } +void LDL( string& output ) { _sap("ldl\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void LDR( string& output ) { _sap("ldr\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void LB( string& output ) { _sap("lb\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void LH( string& output ) { _sap("lh\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void LWL( string& output ) { _sap("lwl\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void LW( string& output ) { _sap("lw\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void LBU( string& output ) { _sap("lbu\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void LHU( string& output ) { _sap("lhu\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void LWR( string& output ) { _sap("lwr\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void LWU( string& output ) { _sap("lwu\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void SB( string& output ) { _sap("sb\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void SH( string& output ) { _sap("sh\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void SWL( string& output ) { _sap("swl\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void SW( string& output ) { _sap("sw\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void SDL( string& output ) { _sap("sdl\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void SDR( string& output ) { _sap("sdr\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void SWR( string& output ) { _sap("swr\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void LD( string& output ) { _sap("ld\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void SD( string& output ) { _sap("sd\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void LQ( string& output ) { _sap("lq\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void SQ( string& output ) { _sap("sq\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void SWC1( string& output ) { _sap("swc1\t%s, 0x%04X(%s)") COP1_REG_FP[DECODE_FT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void SQC2( string& output ) { _sap("sqc2\t%s, 0x%04X(%s)") COP2_REG_FP[DECODE_FT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void PREF( string& output ) { output += "pref ---"; /*_sap("PREF\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[RS]); */} +void LWC1( string& output ) { _sap("lwc1\t%s, 0x%04X(%s)") COP1_REG_FP[DECODE_FT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +void LQC2( string& output ) { _sap("lqc2\t%s, 0x%04X(%s)") COP2_REG_FP[DECODE_FT], DECODE_IMMED, GPR_REG[DECODE_RS]); } +//********************END OF STANDARD OPCODES************************* + +void SLL( string& output ) +{ + if (cpuRegs.code == 0x00000000) + output += "nop"; + else + _sap("sll\t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); +} + +void SRL( string& output ) { _sap("srl\t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } +void SRA( string& output ) { _sap("sra\t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } +void SLLV( string& output ) { _sap("sllv\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } +void SRLV( string& output ) { _sap("srlv\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]);} +void SRAV( string& output ) { _sap("srav\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } +void JR( string& output ) { _sap("jr\t%s") GPR_REG[DECODE_RS]); } + +void JALR( string& output ) +{ + int rd = DECODE_RD; + + if (rd == 31) + _sap("jalr\t%s") GPR_REG[DECODE_RS]); + else + _sap("jalr\t%s, %s") GPR_REG[rd], GPR_REG[DECODE_RS]); +} + + +void SYNC( string& output ) { output += "SYNC"; } +void MFHI( string& output ) { _sap("mfhi\t%s") GPR_REG[DECODE_RD]); } +void MTHI( string& output ) { _sap("mthi\t%s") GPR_REG[DECODE_RS]); } +void MFLO( string& output ) { _sap("mflo\t%s") GPR_REG[DECODE_RD]); } +void MTLO( string& output ) { _sap("mtlo\t%s") GPR_REG[DECODE_RS]); } +void DSLLV( string& output ) { _sap("dsllv\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } +void DSRLV( string& output ) { _sap("dsrlv\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } +void DSRAV( string& output ) { _sap("dsrav\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } +void MULT( string& output ) { _sap("mult\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]);} +void MULTU( string& output ) { _sap("multu\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]);} +void DIV( string& output ) { _sap("div\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void DIVU( string& output ) { _sap("divu\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void ADD( string& output ) { _sap("add\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void ADDU( string& output ) { _sap("addu\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void SUB( string& output ) { _sap("sub\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void SUBU( string& output ) { _sap("subu\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void AND( string& output ) { _sap("and\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void OR( string& output ) { _sap("or\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void XOR( string& output ) { _sap("xor\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void NOR( string& output ) { _sap("nor\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void SLT( string& output ) { _sap("slt\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void SLTU( string& output ) { _sap("sltu\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void DADD( string& output ) { _sap("dadd\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void DADDU( string& output ) { _sap("daddu\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void DSUB( string& output ) { _sap("dsub\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void DSUBU( string& output ) { _sap("dsubu\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void TGE( string& output ) { _sap("tge\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void TGEU( string& output ) { _sap("tgeu\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void TLT( string& output ) { _sap("tlt\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void TLTU( string& output ) { _sap("tltu\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void TEQ( string& output ) { _sap("teq\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void TNE( string& output ) { _sap("tne\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void DSLL( string& output ) { _sap("dsll\t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } +void DSRL( string& output ) { _sap("dsrl\t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } +void DSRA( string& output ) { _sap("dsra\t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } +void DSLL32( string& output ) { _sap("dsll32\t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } +void DSRL32( string& output ) { _sap("dsrl32\t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } +void DSRA32( string& output ) { _sap("dsra32\t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } +void MOVZ( string& output ) { _sap("movz\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void MOVN( string& output ) { _sap("movn\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void MFSA( string& output ) { _sap("mfsa\t%s") GPR_REG[DECODE_RD]);} +void MTSA( string& output ) { _sap("mtsa\t%s") GPR_REG[DECODE_RS]);} +//*** unsupport (yet) cpu opcodes +void SYSCALL( string& output ) { output +="syscall ---";/*_sap("syscall\t0x%05X") DECODE_SYSCALL);*/} +void BREAK( string& output ) { output += "break ---";/*_sap("break\t0x%05X") DECODE_BREAK); */} +void CACHE( string& output ) { output += "cache ---";/*_sap("cache\t%s, 0x%04X(%s)") GPR_REG[DECODE_RT], DECODE_IMMED, GPR_REG[DECODE_RS]); */} +//************************REGIMM OPCODES*************************** +void BLTZ( string& output ) { _sap("bltz\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } +void BGEZ( string& output ) { _sap("bgez\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } +void BLTZL( string& output ) { _sap("bltzl\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } +void BGEZL( string& output ) { _sap("bgezl\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } +void TGEI( string& output ) { _sap("tgei\t%s, 0x%04X") GPR_REG[DECODE_RS], DECODE_IMMED); } +void TGEIU( string& output ) { _sap("tgeiu\t%s,0x%04X") GPR_REG[DECODE_RS], DECODE_IMMED); } +void TLTI( string& output ) { _sap("tlti\t%s, 0x%04X") GPR_REG[DECODE_RS], DECODE_IMMED); } +void TLTIU( string& output ) { _sap("tltiu\t%s,0x%04X") GPR_REG[DECODE_RS], DECODE_IMMED); } +void TEQI( string& output ) { _sap("teqi\t%s, 0x%04X") GPR_REG[DECODE_RS], DECODE_IMMED); } +void TNEI( string& output ) { _sap("tnei\t%s, 0x%04X") GPR_REG[DECODE_RS], DECODE_IMMED); } +void BLTZAL( string& output ) { _sap("bltzal\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } +void BGEZAL( string& output ) { _sap("bgezal\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } +void BLTZALL( string& output ) { _sap("bltzall\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } +void BGEZALL( string& output ) { _sap("bgezall\t%s, ") GPR_REG[DECODE_RS]); offset_decode(output); } +void MTSAB( string& output ) { _sap("mtsab\t%s, 0x%04X") GPR_REG[DECODE_RS], DECODE_IMMED);} +void MTSAH( string& output ) { _sap("mtsah\t%s, 0x%04X") GPR_REG[DECODE_RS], DECODE_IMMED);} + + +//***************************SPECIAL 2 CPU OPCODES******************* +const char* pmfhl_sub[] = { "lw", "uw", "slw", "lh", "sh" }; + +void MADD( string& output ) { _sap("madd\t%s, %s %s") GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void MADDU( string& output ) { _sap("maddu\t%s, %s %s") GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]);} +void PLZCW( string& output ) { _sap("plzcw\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS]); } +void MADD1( string& output ) { _sap("madd1\t%s, %s %s") GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void MADDU1( string& output ) { _sap("maddu1\t%s, %s %s") GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void MFHI1( string& output ) { _sap("mfhi1\t%s") GPR_REG[DECODE_RD]); } +void MTHI1( string& output ) { _sap("mthi1\t%s") GPR_REG[DECODE_RS]); } +void MFLO1( string& output ) { _sap("mflo1\t%s") GPR_REG[DECODE_RD]); } +void MTLO1( string& output ) { _sap("mtlo1\t%s") GPR_REG[DECODE_RS]); } +void MULT1( string& output ) { _sap("mult1\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void MULTU1( string& output ) { _sap("multu1\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]);} +void DIV1( string& output ) { _sap("div1\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void DIVU1( string& output ) { _sap("divu1\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +//that have parametres that i haven't figure out how to display... +void PMFHL( string& output ) { _sap("pmfhl.%s \t%s") pmfhl_sub[DECODE_SA], GPR_REG[DECODE_RD]); } +void PMTHL( string& output ) { _sap("pmthl.%s \t%s") pmfhl_sub[DECODE_SA], GPR_REG[DECODE_RS]); } +void PSLLH( string& output ) { _sap("psllh \t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA); } +void PSRLH( string& output ) { _sap("psrlh \t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA);} +void PSRAH( string& output ) { _sap("psrah \t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA);} +void PSLLW( string& output ) { _sap( "psllw \t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA);} +void PSRLW( string& output ) { _sap( "psrlw \t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA);} +void PSRAW( string& output ) { _sap( "psraw \t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA);} +//***************************END OF SPECIAL OPCODES****************** +//*************************MMI0 OPCODES************************ + +void PADDW( string& output ){ _sap( "paddw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PSUBW( string& output ){ _sap( "psubw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PCGTW( string& output ){ _sap( "pcgtw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PMAXW( string& output ){ _sap( "pmaxw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PADDH( string& output ){ _sap( "paddh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PSUBH( string& output ){ _sap( "psubh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PCGTH( string& output ){ _sap( "pcgth\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PMAXH( string& output ){ _sap( "pmaxh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PADDB( string& output ){ _sap( "paddb\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PSUBB( string& output ){ _sap( "psubb\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PCGTB( string& output ){ _sap( "pcgtb\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PADDSW( string& output ){ _sap( "paddsw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PSUBSW( string& output ){ _sap( "psubsw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PEXTLW( string& output ){ _sap( "pextlw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PPACW( string& output ) { _sap( "ppacw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PADDSH( string& output ){ _sap( "paddsh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PSUBSH( string& output ){ _sap( "psubsh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PEXTLH( string& output ){ _sap( "pextlh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PPACH( string& output ) { _sap( "ppach\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PADDSB( string& output ){ _sap( "paddsb\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PSUBSB( string& output ){ _sap( "psubsb\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PEXTLB( string& output ){ _sap( "pextlb\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PPACB( string& output ) { _sap( "ppacb\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PEXT5( string& output ) { _sap( "pext5\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } +void PPAC5( string& output ) { _sap( "ppac5\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } +//**********END OF MMI0 OPCODES********************************* +//**********MMI1 OPCODES************************************** +void PABSW( string& output ){ _sap( "pabsw%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } +void PCEQW( string& output ){ _sap( "pceqw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PMINW( string& output ){ _sap( "pminw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PADSBH( string& output ){ _sap( "padsbh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PABSH( string& output ){ _sap( "pabsh%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } +void PCEQH( string& output ){ _sap( "pceqh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PMINH( string& output ){ _sap( "pminh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PCEQB( string& output ){ _sap( "pceqb\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PADDUW( string& output ){ _sap( "padduw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PSUBUW( string& output ){ _sap( "psubuw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PEXTUW( string& output ){ _sap( "pextuw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PADDUH( string& output ){ _sap( "padduh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PSUBUH( string& output ){ _sap( "psubuh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PEXTUH( string& output ){ _sap( "pextuh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PADDUB( string& output ){ _sap( "paddub\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PSUBUB( string& output ){ _sap( "psubub\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PEXTUB( string& output ){ _sap( "pextub\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void QFSRV( string& output ) { _sap( "qfsrv\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +//********END OF MMI1 OPCODES*********************************** +//*********MMI2 OPCODES*************************************** +void PMADDW( string& output ){ _sap( "pmaddw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PSLLVW( string& output ){ _sap( "psllvw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PSRLVW( string& output ){ _sap( "psrlvw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PMSUBW( string& output ){ _sap( "msubw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PMFHI( string& output ){ _sap( "pmfhi\t%s") GPR_REG[DECODE_RD]); } +void PMFLO( string& output ){ _sap( "pmflo\t%s") GPR_REG[DECODE_RD]); } +void PINTH( string& output ){ _sap( "pinth\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PMULTW( string& output ){ _sap( "pmultw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PDIVW( string& output ){ _sap( "pdivw\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PCPYLD( string& output ){ _sap( "pcpyld\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PMADDH( string& output ){ _sap( "pmaddh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PHMADH( string& output ){ _sap( "phmadh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PAND( string& output ){ _sap( "pand\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PXOR( string& output ){ _sap( "pxor\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PMSUBH( string& output ){ _sap( "pmsubh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PHMSBH( string& output ){ _sap( "phmsbh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PEXEH( string& output ){ _sap( "pexeh\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } +void PREVH( string& output ){ _sap( "prevh\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } +void PMULTH( string& output ){ _sap( "pmulth\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PDIVBW( string& output ){ _sap( "pdivbw\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PEXEW( string& output ){ _sap( "pexew\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } +void PROT3W( string& output ){ _sap( "prot3w\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); } +//*****END OF MMI2 OPCODES*********************************** +//*************************MMI3 OPCODES************************ +void PMADDUW( string& output ){ _sap("pmadduw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } +void PSRAVW( string& output ){ _sap("psravw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); } +void PMTHI( string& output ){ _sap("pmthi\t%s") GPR_REG[DECODE_RS]); } +void PMTLO( string& output ){ _sap("pmtlo\t%s") GPR_REG[DECODE_RS]); } +void PINTEH( string& output ){ _sap("pinteh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PMULTUW( string& output ){ _sap("pmultuw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PDIVUW( string& output ){ _sap("pdivuw\t%s, %s") GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PCPYUD( string& output ){ _sap("pcpyud\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void POR( string& output ){ _sap("por\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PNOR( string& output ){ _sap("pnor\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); } +void PEXCH( string& output ){ _sap("pexch\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]);} +void PCPYH( string& output ){ _sap("pcpyh\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]);} +void PEXCW( string& output ){ _sap("pexcw\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]);} +//**********************END OF MMI3 OPCODES******************** + +//**************************************************************************** +//** COP0 ** +//**************************************************************************** +void MFC0( string& output ){ _sap("mfc0\t%s, %s") GPR_REG[DECODE_RT], COP0_REG[DECODE_FS]); } +void MTC0( string& output ){ _sap("mtc0\t%s, %s") GPR_REG[DECODE_RT], COP0_REG[DECODE_FS]); } +void BC0F( string& output ){ output += "bc0f\t"; offset_decode(output); } +void BC0T( string& output ){ output += "bc0t\t"; offset_decode(output); } +void BC0FL( string& output ){ output += "bc0fl\t"; offset_decode(output); } +void BC0TL( string& output ){ output += "bc0tl\t"; offset_decode(output); } +void TLBR( string& output ){ output += "tlbr";} +void TLBWI( string& output ){ output += "tlbwi";} +void TLBWR( string& output ){ output += "tlbwr";} +void TLBP( string& output ){ output += "tlbp";} +void ERET( string& output ){ output += "eret";} +void DI( string& output ){ output += "di";} +void EI( string& output ){ output += "ei";} +//**************************************************************************** +//** END OF COP0 ** +//**************************************************************************** +//**************************************************************************** +//** COP1 - Floating Point Unit (FPU) ** +//**************************************************************************** +void MFC1( string& output ){ _sap("mfc1\t%s, %s") GPR_REG[DECODE_RT], COP1_REG_FP[DECODE_FS]); } +void CFC1( string& output ){ _sap("cfc1\t%s, %s") GPR_REG[DECODE_RT], COP1_REG_FCR[DECODE_FS]); } +void MTC1( string& output ){ _sap("mtc1\t%s, %s") GPR_REG[DECODE_RT], COP1_REG_FP[DECODE_FS]); } +void CTC1( string& output ){ _sap("ctc1\t%s, %s") GPR_REG[DECODE_RT], COP1_REG_FCR[DECODE_FS]); } +void BC1F( string& output ){ output += "bc1f\t"; offset_decode(output); } +void BC1T( string& output ){ output += "bc1t\t"; offset_decode(output); } +void BC1FL( string& output ){ output += "bc1fl\t"; offset_decode(output); } +void BC1TL( string& output ){ output += "bc1tl\t"; offset_decode(output); } +void ADD_S( string& output ){ _sap("add.s\t%s, %s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]);} +void SUB_S( string& output ){ _sap("sub.s\t%s, %s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]);} +void MUL_S( string& output ){ _sap("mul.s\t%s, %s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]);} +void DIV_S( string& output ){ _sap("div.s\t%s, %s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void SQRT_S( string& output ){ _sap("sqrt.s\t%s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FT]); } +void ABS_S( string& output ){ _sap("abs.s\t%s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS]); } +void MOV_S( string& output ){ _sap("mov.s\t%s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS]); } +void NEG_S( string& output ){ _sap("neg.s\t%s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS]);} +void RSQRT_S( string& output ){_sap("rsqrt.s\t%s, %s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]);} +void ADDA_S( string& output ){ _sap("adda.s\t%s, %s") COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void SUBA_S( string& output ){ _sap("suba.s\t%s, %s") COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void MULA_S( string& output ){ _sap("mula.s\t%s, %s") COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void MADD_S( string& output ){ _sap("madd.s\t%s, %s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void MSUB_S( string& output ){ _sap("msub.s\t%s, %s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void MADDA_S( string& output ){_sap("madda.s\t%s, %s") COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void MSUBA_S( string& output ){_sap("msuba.s\t%s, %s") COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void CVT_W( string& output ){ _sap("cvt.w.s\t%s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS]); } +void MAX_S( string& output ){ _sap("max.s\t%s, %s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]);} +void MIN_S( string& output ){ _sap("min.s\t%s, %s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]);} +void C_F( string& output ){ _sap("c.f.s\t%s, %s") COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void C_EQ( string& output ){ _sap("c.eq.s\t%s, %s") COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void C_LT( string& output ){ _sap("c.lt.s\t%s, %s") COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void C_LE( string& output ){ _sap("c.le.s\t%s, %s") COP1_REG_FP[DECODE_FS], COP1_REG_FP[DECODE_FT]); } +void CVT_S( string& output ){ _sap("cvt.s.w\t%s, %s") COP1_REG_FP[DECODE_FD], COP1_REG_FP[DECODE_FS]); } +//**************************************************************************** +//** END OF COP1 ** +//**************************************************************************** + +} // End namespace R5900::OpcodeDisasm + +//**************************************************************************** +//** COP2 - (VU0) ** +//**************************************************************************** +void P_QMFC2( string& output ){ _sap("qmfc2\t%s, %s") GPR_REG[DECODE_RT], COP2_REG_FP[DECODE_FS]); } +void P_CFC2( string& output ){ _sap("cfc2\t%s, %s") GPR_REG[DECODE_RT], COP2_REG_CTL[DECODE_FS]); } +void P_QMTC2( string& output ){ _sap("qmtc2\t%s, %s") GPR_REG[DECODE_RT], COP2_REG_FP[DECODE_FS]); } +void P_CTC2( string& output ){ _sap("ctc2\t%s, %s") GPR_REG[DECODE_RT], COP2_REG_CTL[DECODE_FS]); } +void P_BC2F( string& output ){ output += "bc2f\t"; offset_decode(output); } +void P_BC2T( string& output ){ output += "bc2t\t"; offset_decode(output); } +void P_BC2FL( string& output ){ output += "bc2fl\t"; offset_decode(output); } +void P_BC2TL( string& output ){ output += "bc2tl\t"; offset_decode(output); } +//******************************SPECIAL 1 VUO TABLE**************************************** +#define _X ((cpuRegs.code>>24) & 1) +#define _Y ((cpuRegs.code>>23) & 1) +#define _Z ((cpuRegs.code>>22) & 1) +#define _W ((cpuRegs.code>>21) & 1) + +const char *dest_string(void) +{ + static char str[5]; + int i = 0; + + if(_X) str[i++] = 'x'; + if(_Y) str[i++] = 'y'; + if(_Z) str[i++] = 'z'; + if(_W) str[i++] = 'w'; + str[i++] = 0; + + return (const char *)str; +} + +char dest_fsf() +{ + const char arr[4] = { 'x', 'y', 'z', 'w' }; + return arr[(cpuRegs.code>>21)&3]; +} + +char dest_ftf() +{ + const char arr[4] = { 'x', 'y', 'z', 'w' }; + return arr[(cpuRegs.code>>23)&3]; +} + +void P_VADDx( string& output ){_sap("vaddx.%s %s, %s, %sx") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VADDy( string& output ){_sap("vaddy.%s %s, %s, %sy") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VADDz( string& output ){_sap("vaddz.%s %s, %s, %sz") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VADDw( string& output ){_sap("vaddw.%s %s, %s, %sw") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VSUBx( string& output ){_sap("vsubx.%s %s, %s, %sx") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VSUBy( string& output ){_sap("vsuby.%s %s, %s, %sy") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VSUBz( string& output ){_sap("vsubz.%s %s, %s, %sz") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VSUBw( string& output ){_sap("vsubw.%s %s, %s, %sw") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMADDx( string& output ){_sap("vmaddx.%s %s, %s, %sx") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMADDy( string& output ){_sap("vmaddy.%s %s, %s, %sy") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMADDz( string& output ){_sap("vmaddz.%s %s, %s, %sz") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMADDw( string& output ){_sap("vmaddw.%s %s, %s, %sw") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMSUBx( string& output ){_sap("vmsubx.%s %s, %s, %sx") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMSUBy( string& output ){_sap("vmsuby.%s %s, %s, %sy") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMSUBz( string& output ){_sap("vmsubz.%s %s, %s, %sz") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMSUBw( string& output ){_sap("vmsubw.%s %s, %s, %sw") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMAXx( string& output ){_sap("vmaxx.%s %s, %s, %sx") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMAXy( string& output ){_sap("vmaxy.%s %s, %s, %sy") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMAXz( string& output ){_sap("vmaxz.%s %s, %s, %sz") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMAXw( string& output ){_sap("vmaxw.%s %s, %s, %sw") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMINIx( string& output ){_sap("vminix.%s %s, %s, %sx") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMINIy( string& output ){_sap("vminiy.%s %s, %s, %sy") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); ;} +void P_VMINIz( string& output ){_sap("vminiz.%s %s, %s, %sz") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMINIw( string& output ){_sap("vminiw.%s %s, %s, %sw") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMULx( string& output ){_sap("vmulx.%s %s,%s,%sx") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMULy( string& output ){_sap("vmuly.%s %s,%s,%sy") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMULz( string& output ){_sap("vmulz.%s %s,%s,%sz") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMULw( string& output ){_sap("vmulw.%s %s,%s,%sw") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMULq( string& output ){_sap("vmulq.%s %s,%s,Q") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VMAXi( string& output ){_sap("vmaxi.%s %s,%s,I") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VMULi( string& output ){_sap("vmuli.%s %s,%s,I") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VMINIi( string& output ){_sap("vminii.%s %s,%s,I") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VADDq( string& output ){_sap("vaddq.%s %s,%s,Q") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VMADDq( string& output ){_sap("vmaddq.%s %s,%s,Q") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VADDi( string& output ){_sap("vaddi.%s %s,%s,I") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VMADDi( string& output ){_sap("vmaddi.%s %s,%s,I") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VSUBq( string& output ){_sap("vsubq.%s %s,%s,Q") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VMSUBq( string& output ){_sap("vmsubq.%s %s,%s,Q") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VSUbi( string& output ){_sap("vsubi.%s %s,%s,I") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VMSUBi( string& output ){_sap("vmsubi.%s %s,%s,I") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS]); } +void P_VADD( string& output ){_sap("vadd.%s %s, %s, %s") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMADD( string& output ){_sap("vmadd.%s %s, %s, %s") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMUL( string& output ){_sap("vmul.%s %s, %s, %s") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMAX( string& output ){_sap("vmax.%s %s, %s, %s") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VSUB( string& output ){_sap("vsub.%s %s, %s, %s") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMSUB( string& output ){_sap("vmsub.%s %s, %s, %s") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VOPMSUB( string& output ){_sap("vopmsub.xyz %s, %s, %s") COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMINI( string& output ){_sap("vmini.%s %s, %s, %s") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VIADD( string& output ){_sap("viadd %s, %s, %s") COP2_REG_CTL[DECODE_SA], COP2_REG_CTL[DECODE_FS], COP2_REG_CTL[DECODE_FT]);} +void P_VISUB( string& output ){_sap("visub %s, %s, %s") COP2_REG_CTL[DECODE_SA], COP2_REG_CTL[DECODE_FS], COP2_REG_CTL[DECODE_FT]);} +void P_VIADDI( string& output ){_sap("viaddi %s, %s, 0x%x") COP2_REG_CTL[DECODE_FT], COP2_REG_CTL[DECODE_FS], DECODE_SA);} +void P_VIAND( string& output ){_sap("viand %s, %s, %s") COP2_REG_CTL[DECODE_SA], COP2_REG_CTL[DECODE_FS], COP2_REG_CTL[DECODE_FT]);} +void P_VIOR( string& output ){_sap("vior %s, %s, %s") COP2_REG_CTL[DECODE_SA], COP2_REG_CTL[DECODE_FS], COP2_REG_CTL[DECODE_FT]);} +void P_VCALLMS( string& output ){output += "vcallms";} +void P_CALLMSR( string& output ){output += "callmsr";} +//***********************************END OF SPECIAL1 VU0 TABLE***************************** +//******************************SPECIAL2 VUO TABLE***************************************** +void P_VADDAx( string& output ){_sap("vaddax.%s ACC,%s,%sx") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VADDAy( string& output ){_sap("vadday.%s ACC,%s,%sy") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VADDAz( string& output ){_sap("vaddaz.%s ACC,%s,%sz") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VADDAw( string& output ){_sap("vaddaw.%s ACC,%s,%sw") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VSUBAx( string& output ){_sap("vsubax.%s ACC,%s,%sx") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VSUBAy( string& output ){_sap("vsubay.%s ACC,%s,%sy") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VSUBAz( string& output ){_sap("vsubaz.%s ACC,%s,%sz") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VSUBAw( string& output ){_sap("vsubaw.%s ACC,%s,%sw") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMADDAx( string& output ){_sap("vmaddax.%s ACC,%s,%sx") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMADDAy( string& output ){_sap("vmadday.%s ACC,%s,%sy") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMADDAz( string& output ){_sap("vmaddaz.%s ACC,%s,%sz") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMADDAw( string& output ){_sap("vmaddaw.%s ACC,%s,%sw") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMSUBAx( string& output ){_sap("vmsubax.%s ACC,%s,%sx") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMSUBAy( string& output ){_sap("vmsubay.%s ACC,%s,%sy") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMSUBAz( string& output ){_sap("vmsubaz.%s ACC,%s,%sz") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMSUBAw( string& output ){_sap("vmsubaw.%s ACC,%s,%sw") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VITOF0( string& output ){_sap("vitof0.%s %s, %s") dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } +void P_VITOF4( string& output ){_sap("vitof4.%s %s, %s") dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } +void P_VITOF12( string& output ){_sap("vitof12.%s %s, %s") dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } +void P_VITOF15( string& output ){_sap("vitof15.%s %s, %s") dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } +void P_VFTOI0( string& output ) {_sap("vftoi0.%s %s, %s") dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } +void P_VFTOI4( string& output ) {_sap("vftoi4.%s %s, %s") dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } +void P_VFTOI12( string& output ){_sap("vftoi12.%s %s, %s") dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } +void P_VFTOI15( string& output ){_sap("vftoi15.%s %s, %s") dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]); } +void P_VMULAx( string& output ){_sap("vmulax.%s ACC,%s,%sx") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMULAy( string& output ){_sap("vmulay.%s ACC,%s,%sy") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMULAz( string& output ){_sap("vmulaz.%s ACC,%s,%sz") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMULAw( string& output ){_sap("vmulaw.%s ACC,%s,%sw") dest_string(),COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]);} +void P_VMULAq( string& output ){_sap("vmulaq.%s ACC %s, Q") dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VABS( string& output ){_sap("vabs.%s %s, %s") dest_string(),COP2_REG_FP[DECODE_FT], COP2_REG_FP[DECODE_FS]);} +void P_VMULAi( string& output ){_sap("vmulaq.%s ACC %s, I") dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VCLIPw( string& output ){_sap("vclip %sxyz, %sw") COP2_REG_FP[DECODE_FS], COP2_REG_FP[DECODE_FT]);} +void P_VADDAq( string& output ){_sap("vaddaq.%s ACC %s, Q") dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VMADDAq( string& output ){_sap("vmaddaq.%s ACC %s, Q") dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VADDAi( string& output ){_sap("vaddai.%s ACC %s, I") dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VMADDAi( string& output ){_sap("vmaddai.%s ACC %s, Q") dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VSUBAq( string& output ){_sap("vsubaq.%s ACC %s, Q") dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VMSUBAq( string& output ){_sap("vmsubaq.%s ACC %s, Q") dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VSUBAi( string& output ){_sap("vsubai.%s ACC %s, I") dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VMSUBAi( string& output ){_sap("vmsubai.%s ACC %s, I") dest_string(), COP2_REG_FP[DECODE_FS]); } +void P_VADDA( string& output ){_sap("vadda.%s ACC %s, %s") dest_string(), COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMADDA( string& output ){_sap("vmadda.%s ACC %s, %s") dest_string(), COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMULA( string& output ){_sap("vmula.%s ACC %s, %s") dest_string(), COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VSUBA( string& output ){_sap("vsuba.%s ACC %s, %s") dest_string(), COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VMSUBA( string& output ){_sap("vmsuba.%s ACC %s, %s") dest_string(), COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VOPMULA( string& output ){_sap("vopmula.xyz %sxyz, %sxyz") COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); } +void P_VNOP( string& output ){output += "vnop";} +void P_VMONE( string& output ){_sap("vmove.%s, %s, %s") dest_string(), COP2_REG_FP[DECODE_FT],COP2_REG_FP[DECODE_FS]); } +void P_VMR32( string& output ){_sap("vmr32.%s, %s, %s") dest_string(), COP2_REG_FP[DECODE_FT],COP2_REG_FP[DECODE_FS]); } +void P_VLQI( string& output ){_sap("vlqi %s%s, (%s++)") COP2_REG_FP[DECODE_FT], dest_string(), COP2_REG_CTL[DECODE_FS]);} +void P_VSQI( string& output ){_sap("vsqi %s%s, (%s++)") COP2_REG_FP[DECODE_FS], dest_string(), COP2_REG_CTL[DECODE_FT]);} +void P_VLQD( string& output ){_sap("vlqd %s%s, (--%s)") COP2_REG_FP[DECODE_FT], dest_string(), COP2_REG_CTL[DECODE_FS]);} +void P_VSQD( string& output ){_sap("vsqd %s%s, (--%s)") COP2_REG_FP[DECODE_FS], dest_string(), COP2_REG_CTL[DECODE_FT]);} +void P_VDIV( string& output ){_sap("vdiv Q, %s%c, %s%c") COP2_REG_FP[DECODE_FS], dest_fsf(), COP2_REG_FP[DECODE_FT], dest_ftf());} +void P_VSQRT( string& output ){_sap("vsqrt Q, %s%c") COP2_REG_FP[DECODE_FT], dest_ftf());} +void P_VRSQRT( string& output ){_sap("vrsqrt Q, %s%c, %s%c") COP2_REG_FP[DECODE_FS], dest_fsf(), COP2_REG_FP[DECODE_FT], dest_ftf());} +void P_VWAITQ( string& output ){output += "vwaitq";} +void P_VMTIR( string& output ){_sap("vmtir %s, %s%c") COP2_REG_CTL[DECODE_FT], COP2_REG_FP[DECODE_FS], dest_fsf());} +void P_VMFIR( string& output ){_sap("vmfir %s%c, %s") COP2_REG_FP[DECODE_FT], dest_string(), COP2_REG_CTL[DECODE_FS]);} +void P_VILWR( string& output ){_sap("vilwr %s, (%s)%s") COP2_REG_CTL[DECODE_FT], COP2_REG_CTL[DECODE_FS], dest_string());} +void P_VISWR( string& output ){_sap("viswr %s, (%s)%s") COP2_REG_CTL[DECODE_FT], COP2_REG_CTL[DECODE_FS], dest_string());} +void P_VRNEXT( string& output ){_sap("vrnext %s%s, R") COP2_REG_CTL[DECODE_FT], dest_string());} +void P_VRGET( string& output ){_sap("vrget %s%s, R") COP2_REG_CTL[DECODE_FT], dest_string());} +void P_VRINIT( string& output ){_sap("vrinit R, %s%s") COP2_REG_CTL[DECODE_FS], dest_string());} +void P_VRXOR( string& output ){_sap("vrxor R, %s%s") COP2_REG_CTL[DECODE_FS], dest_string());} +//************************************END OF SPECIAL2 VUO TABLE**************************** + +} diff --git a/pcsx2/DebugTools/DisVU0Micro.cpp b/pcsx2/DebugTools/DisVU0Micro.cpp index d348de6648..aef9a8b98e 100644 --- a/pcsx2/DebugTools/DisVU0Micro.cpp +++ b/pcsx2/DebugTools/DisVU0Micro.cpp @@ -1,83 +1,83 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Debug.h" - -static char ostr[1024]; - -// Type deffinition of our functions -#define DisFInterface (u32 code, u32 pc) -#define DisFInterfaceT (u32, u32) -#define DisFInterfaceN (code, pc) - -typedef char* (*TdisR5900F)DisFInterface; - -// These macros are used to assemble the disassembler functions -#define MakeDisF(fn, b) \ - char* fn DisFInterface { \ - sprintf (ostr, "%8.8x %8.8x:", pc, code); \ - b; /*ostr[(strlen(ostr) - 1)] = 0;*/ return ostr; \ - } - -//Lower/Upper instructions can use that.. -#define _Ft_ ((code >> 16) & 0x1F) // The rt part of the instruction register -#define _Fs_ ((code >> 11) & 0x1F) // The rd part of the instruction register -#define _Fd_ ((code >> 6) & 0x1F) // The sa part of the instruction register - -#define dName(i) sprintf(ostr, "%s %-7s,", ostr, i) -#define dNameU(i) { char op[256]; sprintf(op, "%s.%s%s%s%s", i, _X ? "x" : "", _Y ? "y" : "", _Z ? "z" : "", _W ? "w" : ""); sprintf(ostr, "%s %-7s,", ostr, op); } - - -#define dCP2128f(i) sprintf(ostr, "%s w=%f z=%f y=%f x=%f (%s),", ostr, VU0.VF[i].f.w, VU0.VF[i].f.z, VU0.VF[i].f.y, VU0.VF[i].f.x, disRNameCP2f[i]) -#define dCP232x(i) sprintf(ostr, "%s x=%f (%s),", ostr, VU0.VF[i].f.x, disRNameCP2f[i]) -#define dCP232y(i) sprintf(ostr, "%s y=%f (%s),", ostr, VU0.VF[i].f.y, disRNameCP2f[i]) -#define dCP232z(i) sprintf(ostr, "%s z=%f (%s),", ostr, VU0.VF[i].f.z, disRNameCP2f[i]) -#define dCP232w(i) sprintf(ostr, "%s w=%f (%s),", ostr, VU0.VF[i].f.w, disRNameCP2f[i]) -#define dCP2ACCf() sprintf(ostr, "%s w=%f z=%f y=%f x=%f (ACC),", ostr, VU0.ACC.f.w, VU0.ACC.f.z, VU0.ACC.f.y, VU0.ACC.f.x) -#define dCP232i(i) sprintf(ostr, "%s %8.8x (%s),", ostr, VU0.VI[i].UL, disRNameCP2i[i]) -#define dCP232iF(i) sprintf(ostr, "%s %f (%s),", ostr, VU0.VI[i].F, disRNameCP2i[i]) -#define dCP232f(i, j) sprintf(ostr, "%s Q %s=%f (%s),", ostr, CP2VFnames[j], VU0.VF[i].F[j], disRNameCP2f[i]) -#define dImm5() sprintf(ostr, "%s %d,", ostr, (code >> 6) & 0x1f) -#define dImm11() sprintf(ostr, "%s %d,", ostr, code & 0x7ff) -#define dImm15() sprintf(ostr, "%s %d,", ostr, ( ( code >> 10 ) & 0x7800 ) | ( code & 0x7ff )) - -#define _X ((code>>24) & 0x1) -#define _Y ((code>>23) & 0x1) -#define _Z ((code>>22) & 0x1) -#define _W ((code>>21) & 0x1) - -#define _Fsf_ ((code >> 21) & 0x03) -#define _Ftf_ ((code >> 23) & 0x03) - - -/********************************************************* -* Unknown instruction (would generate an exception) * -* Format: ? * -*********************************************************/ -//extern char* disNULL DisFInterface; -static MakeDisF(disNULL, dName("*** Bad OP ***");) - -#include "DisVUmicro.h" -#include "DisVUops.h" -#include "VU.h" - -_disVUOpcodes(VU0); -_disVUTables(VU0); - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Debug.h" + +static char ostr[1024]; + +// Type deffinition of our functions +#define DisFInterface (u32 code, u32 pc) +#define DisFInterfaceT (u32, u32) +#define DisFInterfaceN (code, pc) + +typedef char* (*TdisR5900F)DisFInterface; + +// These macros are used to assemble the disassembler functions +#define MakeDisF(fn, b) \ + char* fn DisFInterface { \ + sprintf (ostr, "%8.8x %8.8x:", pc, code); \ + b; /*ostr[(strlen(ostr) - 1)] = 0;*/ return ostr; \ + } + +//Lower/Upper instructions can use that.. +#define _Ft_ ((code >> 16) & 0x1F) // The rt part of the instruction register +#define _Fs_ ((code >> 11) & 0x1F) // The rd part of the instruction register +#define _Fd_ ((code >> 6) & 0x1F) // The sa part of the instruction register + +#define dName(i) sprintf(ostr, "%s %-7s,", ostr, i) +#define dNameU(i) { char op[256]; sprintf(op, "%s.%s%s%s%s", i, _X ? "x" : "", _Y ? "y" : "", _Z ? "z" : "", _W ? "w" : ""); sprintf(ostr, "%s %-7s,", ostr, op); } + + +#define dCP2128f(i) sprintf(ostr, "%s w=%f z=%f y=%f x=%f (%s),", ostr, VU0.VF[i].f.w, VU0.VF[i].f.z, VU0.VF[i].f.y, VU0.VF[i].f.x, disRNameCP2f[i]) +#define dCP232x(i) sprintf(ostr, "%s x=%f (%s),", ostr, VU0.VF[i].f.x, disRNameCP2f[i]) +#define dCP232y(i) sprintf(ostr, "%s y=%f (%s),", ostr, VU0.VF[i].f.y, disRNameCP2f[i]) +#define dCP232z(i) sprintf(ostr, "%s z=%f (%s),", ostr, VU0.VF[i].f.z, disRNameCP2f[i]) +#define dCP232w(i) sprintf(ostr, "%s w=%f (%s),", ostr, VU0.VF[i].f.w, disRNameCP2f[i]) +#define dCP2ACCf() sprintf(ostr, "%s w=%f z=%f y=%f x=%f (ACC),", ostr, VU0.ACC.f.w, VU0.ACC.f.z, VU0.ACC.f.y, VU0.ACC.f.x) +#define dCP232i(i) sprintf(ostr, "%s %8.8x (%s),", ostr, VU0.VI[i].UL, disRNameCP2i[i]) +#define dCP232iF(i) sprintf(ostr, "%s %f (%s),", ostr, VU0.VI[i].F, disRNameCP2i[i]) +#define dCP232f(i, j) sprintf(ostr, "%s Q %s=%f (%s),", ostr, CP2VFnames[j], VU0.VF[i].F[j], disRNameCP2f[i]) +#define dImm5() sprintf(ostr, "%s %d,", ostr, (code >> 6) & 0x1f) +#define dImm11() sprintf(ostr, "%s %d,", ostr, code & 0x7ff) +#define dImm15() sprintf(ostr, "%s %d,", ostr, ( ( code >> 10 ) & 0x7800 ) | ( code & 0x7ff )) + +#define _X ((code>>24) & 0x1) +#define _Y ((code>>23) & 0x1) +#define _Z ((code>>22) & 0x1) +#define _W ((code>>21) & 0x1) + +#define _Fsf_ ((code >> 21) & 0x03) +#define _Ftf_ ((code >> 23) & 0x03) + + +/********************************************************* +* Unknown instruction (would generate an exception) * +* Format: ? * +*********************************************************/ +//extern char* disNULL DisFInterface; +static MakeDisF(disNULL, dName("*** Bad OP ***");) + +#include "DisVUmicro.h" +#include "DisVUops.h" +#include "VU.h" + +_disVUOpcodes(VU0); +_disVUTables(VU0); + diff --git a/pcsx2/DebugTools/DisVU1Micro.cpp b/pcsx2/DebugTools/DisVU1Micro.cpp index 17721e3aee..51a6e4db38 100644 --- a/pcsx2/DebugTools/DisVU1Micro.cpp +++ b/pcsx2/DebugTools/DisVU1Micro.cpp @@ -1,122 +1,122 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Debug.h" -#include "VUmicro.h" - -static char ostr[1024]; - -// Type deffinition of our functions -#define DisFInterface (u32 code, u32 pc) -#define DisFInterfaceT (u32, u32) -#define DisFInterfaceN (code, pc) - -typedef char* (*TdisR5900F)DisFInterface; - -// These macros are used to assemble the disassembler functions -#define MakeDisF(fn, b) \ - char* fn DisFInterface { \ - if( !CHECK_VU1REC ) sprintf (ostr, "%8.8x %8.8x:", pc, code); \ - else ostr[0] = 0; \ - b; /*ostr[(strlen(ostr) - 1)] = 0;*/ return ostr; \ - } - -//Lower/Upper instructions can use that.. -#define _Ft_ ((code >> 16) & 0x1F) // The rt part of the instruction register -#define _Fs_ ((code >> 11) & 0x1F) // The rd part of the instruction register -#define _Fd_ ((code >> 6) & 0x1F) // The sa part of the instruction register - -#define dName(i) sprintf(ostr, "%s %-12s", ostr, i); \ - -#define dNameU(i) { \ - char op[256]; sprintf(op, "%s.%s%s%s%s", i, _X ? "x" : "", _Y ? "y" : "", _Z ? "z" : "", _W ? "w" : ""); \ - sprintf(ostr, "%s %-12s", ostr, op); \ -} - -#define dCP2128f(i) { \ - if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ - else sprintf(ostr, "%s w=%f (%8.8x) z=%f (%8.8x) y=%f (%8.8xl) x=%f (%8.8x) (%s),", ostr, VU1.VF[i].f.w, VU1.VF[i].UL[3], VU1.VF[i].f.z, VU1.VF[i].UL[2], VU1.VF[i].f.y, VU1.VF[i].UL[1], VU1.VF[i].f.x, VU1.VF[i].UL[0], disRNameCP2f[i]); \ -} \ - -#define dCP232x(i) { \ - if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ - else sprintf(ostr, "%s x=%f (%s),", ostr, VU1.VF[i].f.x, disRNameCP2f[i]); \ -} \ - -#define dCP232y(i) { \ - if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ - else sprintf(ostr, "%s y=%f (%s),", ostr, VU1.VF[i].f.y, disRNameCP2f[i]); \ -} \ - -#define dCP232z(i) { \ - if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ - else sprintf(ostr, "%s z=%f (%s),", ostr, VU1.VF[i].f.z, disRNameCP2f[i]); \ -} - -#define dCP232w(i) { \ - if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ - else sprintf(ostr, "%s w=%f (%s),", ostr, VU1.VF[i].f.w, disRNameCP2f[i]); \ -} - -#define dCP2ACCf() { \ - if( CHECK_VU1REC ) sprintf(ostr, "%s ACC,", ostr); \ - else sprintf(ostr, "%s w=%f z=%f y=%f x=%f (ACC),", ostr, VU1.ACC.f.w, VU1.ACC.f.z, VU1.ACC.f.y, VU1.ACC.f.x); \ -} \ - -#define dCP232i(i) { \ - if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2i[i]); \ - else sprintf(ostr, "%s %8.8x (%s),", ostr, VU1.VI[i].UL, disRNameCP2i[i]); \ -} - -#define dCP232iF(i) { \ - if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2i[i]); \ - else sprintf(ostr, "%s %f (%s),", ostr, VU1.VI[i].F, disRNameCP2i[i]); \ -} - -#define dCP232f(i, j) { \ - if( CHECK_VU1REC ) sprintf(ostr, "%s %s%s,", ostr, disRNameCP2f[i], CP2VFnames[j]); \ - else sprintf(ostr, "%s %s=%f (%s),", ostr, CP2VFnames[j], VU1.VF[i].F[j], disRNameCP2f[i]); \ -} - -#define dImm5() sprintf(ostr, "%s %d,", ostr, (s16)((code >> 6) & 0x10 ? 0xfff0 | ((code >> 6) & 0xf) : (code >> 6) & 0xf)) -#define dImm11() sprintf(ostr, "%s %d,", ostr, (s16)(code & 0x400 ? 0xfc00 | (code & 0x3ff) : code & 0x3ff)) -#define dImm15() sprintf(ostr, "%s %d,", ostr, ( ( code >> 10 ) & 0x7800 ) | ( code & 0x7ff )) - -#define _X ((code>>24) & 0x1) -#define _Y ((code>>23) & 0x1) -#define _Z ((code>>22) & 0x1) -#define _W ((code>>21) & 0x1) - -#define _Fsf_ ((code >> 21) & 0x03) -#define _Ftf_ ((code >> 23) & 0x03) - -/********************************************************* -* Unknown instruction (would generate an exception) * -* Format: ? * -*********************************************************/ -//extern char* disNULL DisFInterface; -static MakeDisF(disNULL, dName("*** Bad OP ***");) - -#include "DisVUmicro.h" -#include "DisVUops.h" - -_disVUOpcodes(VU1); -_disVUTables(VU1); - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Debug.h" +#include "VUmicro.h" + +static char ostr[1024]; + +// Type deffinition of our functions +#define DisFInterface (u32 code, u32 pc) +#define DisFInterfaceT (u32, u32) +#define DisFInterfaceN (code, pc) + +typedef char* (*TdisR5900F)DisFInterface; + +// These macros are used to assemble the disassembler functions +#define MakeDisF(fn, b) \ + char* fn DisFInterface { \ + if( !CHECK_VU1REC ) sprintf (ostr, "%8.8x %8.8x:", pc, code); \ + else ostr[0] = 0; \ + b; /*ostr[(strlen(ostr) - 1)] = 0;*/ return ostr; \ + } + +//Lower/Upper instructions can use that.. +#define _Ft_ ((code >> 16) & 0x1F) // The rt part of the instruction register +#define _Fs_ ((code >> 11) & 0x1F) // The rd part of the instruction register +#define _Fd_ ((code >> 6) & 0x1F) // The sa part of the instruction register + +#define dName(i) sprintf(ostr, "%s %-12s", ostr, i); \ + +#define dNameU(i) { \ + char op[256]; sprintf(op, "%s.%s%s%s%s", i, _X ? "x" : "", _Y ? "y" : "", _Z ? "z" : "", _W ? "w" : ""); \ + sprintf(ostr, "%s %-12s", ostr, op); \ +} + +#define dCP2128f(i) { \ + if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ + else sprintf(ostr, "%s w=%f (%8.8x) z=%f (%8.8x) y=%f (%8.8xl) x=%f (%8.8x) (%s),", ostr, VU1.VF[i].f.w, VU1.VF[i].UL[3], VU1.VF[i].f.z, VU1.VF[i].UL[2], VU1.VF[i].f.y, VU1.VF[i].UL[1], VU1.VF[i].f.x, VU1.VF[i].UL[0], disRNameCP2f[i]); \ +} \ + +#define dCP232x(i) { \ + if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ + else sprintf(ostr, "%s x=%f (%s),", ostr, VU1.VF[i].f.x, disRNameCP2f[i]); \ +} \ + +#define dCP232y(i) { \ + if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ + else sprintf(ostr, "%s y=%f (%s),", ostr, VU1.VF[i].f.y, disRNameCP2f[i]); \ +} \ + +#define dCP232z(i) { \ + if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ + else sprintf(ostr, "%s z=%f (%s),", ostr, VU1.VF[i].f.z, disRNameCP2f[i]); \ +} + +#define dCP232w(i) { \ + if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ + else sprintf(ostr, "%s w=%f (%s),", ostr, VU1.VF[i].f.w, disRNameCP2f[i]); \ +} + +#define dCP2ACCf() { \ + if( CHECK_VU1REC ) sprintf(ostr, "%s ACC,", ostr); \ + else sprintf(ostr, "%s w=%f z=%f y=%f x=%f (ACC),", ostr, VU1.ACC.f.w, VU1.ACC.f.z, VU1.ACC.f.y, VU1.ACC.f.x); \ +} \ + +#define dCP232i(i) { \ + if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2i[i]); \ + else sprintf(ostr, "%s %8.8x (%s),", ostr, VU1.VI[i].UL, disRNameCP2i[i]); \ +} + +#define dCP232iF(i) { \ + if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2i[i]); \ + else sprintf(ostr, "%s %f (%s),", ostr, VU1.VI[i].F, disRNameCP2i[i]); \ +} + +#define dCP232f(i, j) { \ + if( CHECK_VU1REC ) sprintf(ostr, "%s %s%s,", ostr, disRNameCP2f[i], CP2VFnames[j]); \ + else sprintf(ostr, "%s %s=%f (%s),", ostr, CP2VFnames[j], VU1.VF[i].F[j], disRNameCP2f[i]); \ +} + +#define dImm5() sprintf(ostr, "%s %d,", ostr, (s16)((code >> 6) & 0x10 ? 0xfff0 | ((code >> 6) & 0xf) : (code >> 6) & 0xf)) +#define dImm11() sprintf(ostr, "%s %d,", ostr, (s16)(code & 0x400 ? 0xfc00 | (code & 0x3ff) : code & 0x3ff)) +#define dImm15() sprintf(ostr, "%s %d,", ostr, ( ( code >> 10 ) & 0x7800 ) | ( code & 0x7ff )) + +#define _X ((code>>24) & 0x1) +#define _Y ((code>>23) & 0x1) +#define _Z ((code>>22) & 0x1) +#define _W ((code>>21) & 0x1) + +#define _Fsf_ ((code >> 21) & 0x03) +#define _Ftf_ ((code >> 23) & 0x03) + +/********************************************************* +* Unknown instruction (would generate an exception) * +* Format: ? * +*********************************************************/ +//extern char* disNULL DisFInterface; +static MakeDisF(disNULL, dName("*** Bad OP ***");) + +#include "DisVUmicro.h" +#include "DisVUops.h" + +_disVUOpcodes(VU1); +_disVUTables(VU1); + diff --git a/pcsx2/DebugTools/DisVUmicro.h b/pcsx2/DebugTools/DisVUmicro.h index 15caffe9ca..aef106828b 100644 --- a/pcsx2/DebugTools/DisVUmicro.h +++ b/pcsx2/DebugTools/DisVUmicro.h @@ -1,209 +1,209 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - - -#define _disVUTables(VU) \ - \ -/****************/ \ -/* LOWER TABLES */ \ -/****************/ \ - \ -TdisR5900F dis##VU##LowerOP_T3_00_OPCODE[32] = { \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - dis##VU##MI_MOVE , dis##VU##MI_LQI , dis##VU##MI_DIV , dis##VU##MI_MTIR, \ - dis##VU##MI_RNEXT , disNULL , disNULL , disNULL , /* 0x10 */ \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , dis##VU##MI_MFP , dis##VU##MI_XTOP , dis##VU##MI_XGKICK, \ - dis##VU##MI_ESADD , dis##VU##MI_EATANxy, dis##VU##MI_ESQRT, dis##VU##MI_ESIN, \ -}; \ - \ -TdisR5900F dis##VU##LowerOP_T3_01_OPCODE[32] = { \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - dis##VU##MI_MR32 , dis##VU##MI_SQI , dis##VU##MI_SQRT , dis##VU##MI_MFIR, \ - dis##VU##MI_RGET , disNULL , disNULL , disNULL , /* 0x10 */ \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , dis##VU##MI_XITOP, disNULL , \ - dis##VU##MI_ERSADD, dis##VU##MI_EATANxz, dis##VU##MI_ERSQRT, dis##VU##MI_EATAN, \ -}; \ - \ -TdisR5900F dis##VU##LowerOP_T3_10_OPCODE[32] = { \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , dis##VU##MI_LQD , dis##VU##MI_RSQRT, dis##VU##MI_ILWR, \ - dis##VU##MI_RINIT , disNULL , disNULL , disNULL , /* 0x10 */ \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - dis##VU##MI_ELENG , dis##VU##MI_ESUM , dis##VU##MI_ERCPR, dis##VU##MI_EEXP, \ -}; \ - \ -TdisR5900F dis##VU##LowerOP_T3_11_OPCODE[32] = { \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , dis##VU##MI_SQD , dis##VU##MI_WAITQ, dis##VU##MI_ISWR, \ - dis##VU##MI_RXOR , disNULL , disNULL , disNULL , /* 0x10 */ \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - dis##VU##MI_ERLENG, disNULL , dis##VU##MI_WAITP, disNULL , \ -}; \ - \ -MakeDisF(dis##VU##LowerOP_T3_00, dis##VU##LowerOP_T3_00_OPCODE[_Fd_] DisFInterfaceN) \ -MakeDisF(dis##VU##LowerOP_T3_01, dis##VU##LowerOP_T3_01_OPCODE[_Fd_] DisFInterfaceN) \ -MakeDisF(dis##VU##LowerOP_T3_10, dis##VU##LowerOP_T3_10_OPCODE[_Fd_] DisFInterfaceN) \ -MakeDisF(dis##VU##LowerOP_T3_11, dis##VU##LowerOP_T3_11_OPCODE[_Fd_] DisFInterfaceN) \ - \ -TdisR5900F dis##VU##LowerOP_OPCODE[64] = { \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , /* 0x10 */ \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , /* 0x20 */ \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - dis##VU##MI_IADD , dis##VU##MI_ISUB , dis##VU##MI_IADDI, disNULL , /* 0x30 */ \ - dis##VU##MI_IAND , dis##VU##MI_IOR , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - dis##VU##LowerOP_T3_00, dis##VU##LowerOP_T3_01, dis##VU##LowerOP_T3_10, dis##VU##LowerOP_T3_11, \ -}; \ - \ -MakeDisF(dis##VU##LowerOP, dis##VU##LowerOP_OPCODE[code & 0x3f] DisFInterfaceN) \ - \ -TdisR5900F dis##VU##MicroL[] = { \ - dis##VU##MI_LQ , dis##VU##MI_SQ , disNULL , disNULL, \ - dis##VU##MI_ILW , dis##VU##MI_ISW , disNULL , disNULL, \ - dis##VU##MI_IADDIU, dis##VU##MI_ISUBIU, disNULL , disNULL, \ - disNULL , disNULL , disNULL , disNULL, \ - dis##VU##MI_FCEQ , dis##VU##MI_FCSET , dis##VU##MI_FCAND, dis##VU##MI_FCOR, /* 0x10 */ \ - dis##VU##MI_FSEQ , dis##VU##MI_FSSET , dis##VU##MI_FSAND, dis##VU##MI_FSOR, \ - dis##VU##MI_FMEQ , disNULL , dis##VU##MI_FMAND, dis##VU##MI_FMOR, \ - dis##VU##MI_FCGET , disNULL , disNULL , disNULL, \ - dis##VU##MI_B , dis##VU##MI_BAL , disNULL , disNULL, /* 0x20 */ \ - dis##VU##MI_JR , dis##VU##MI_JALR , disNULL , disNULL, \ - dis##VU##MI_IBEQ , dis##VU##MI_IBNE , disNULL , disNULL, \ - dis##VU##MI_IBLTZ , dis##VU##MI_IBGTZ , dis##VU##MI_IBLEZ, dis##VU##MI_IBGEZ, \ - disNULL , disNULL , disNULL , disNULL, /* 0x30 */ \ - disNULL , disNULL , disNULL , disNULL, \ - disNULL , disNULL , disNULL , disNULL, \ - disNULL , disNULL , disNULL , disNULL, \ - dis##VU##LowerOP , disNULL , disNULL , disNULL, /* 0x40*/ \ - disNULL , disNULL , disNULL , disNULL, \ - disNULL , disNULL , disNULL , disNULL, \ - disNULL , disNULL , disNULL , disNULL, \ - disNULL , disNULL , disNULL , disNULL, /* 0x50 */ \ - disNULL , disNULL , disNULL , disNULL, \ - disNULL , disNULL , disNULL , disNULL, \ - disNULL , disNULL , disNULL , disNULL, \ - disNULL , disNULL , disNULL , disNULL, /* 0x60 */ \ - disNULL , disNULL , disNULL , disNULL, \ - disNULL , disNULL , disNULL , disNULL, \ - disNULL , disNULL , disNULL , disNULL, \ - disNULL , disNULL , disNULL , disNULL, /* 0x70 */ \ - disNULL , disNULL , disNULL , disNULL, \ - disNULL , disNULL , disNULL , disNULL, \ - disNULL , disNULL , disNULL , disNULL, \ -}; \ - \ - \ -MakeDisF(dis##VU##MicroLF, dis##VU##MicroL[code >> 25] DisFInterfaceN) \ - \ - \ -/****************/ \ -/* UPPER TABLES */ \ -/****************/ \ - \ -TdisR5900F dis##VU##_UPPER_FD_00_TABLE[32] = { \ - dis##VU##MI_ADDAx, dis##VU##MI_SUBx , dis##VU##MI_MADDAx, dis##VU##MI_MSUBAx, \ - dis##VU##MI_ITOF0, dis##VU##MI_FTOI0, dis##VU##MI_MULAx , dis##VU##MI_MULAq , \ - dis##VU##MI_ADDAq, dis##VU##MI_SUBAq, dis##VU##MI_ADDA , dis##VU##MI_SUBA , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ -}; \ - \ -TdisR5900F dis##VU##_UPPER_FD_01_TABLE[32] = { \ - dis##VU##MI_ADDAy , dis##VU##MI_SUBy , dis##VU##MI_MADDAy, dis##VU##MI_MSUBAy, \ - dis##VU##MI_ITOF4 , dis##VU##MI_FTOI4 , dis##VU##MI_MULAy , dis##VU##MI_ABS , \ - dis##VU##MI_MADDAq, dis##VU##MI_MSUBAq, dis##VU##MI_MADDA , dis##VU##MI_MSUBA , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ -}; \ - \ -TdisR5900F dis##VU##_UPPER_FD_10_TABLE[32] = { \ - dis##VU##MI_ADDAz , dis##VU##MI_SUBz , dis##VU##MI_MADDAz, dis##VU##MI_MSUBAz, \ - dis##VU##MI_ITOF12, dis##VU##MI_FTOI12, dis##VU##MI_MULAz , dis##VU##MI_MULAi , \ - dis##VU##MI_ADDAi, dis##VU##MI_SUBAi , dis##VU##MI_MULA , dis##VU##MI_OPMULA, \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ -}; \ - \ -TdisR5900F dis##VU##_UPPER_FD_11_TABLE[32] = { \ - dis##VU##MI_ADDAw , dis##VU##MI_SUBw , dis##VU##MI_MADDAw, dis##VU##MI_MSUBAw, \ - dis##VU##MI_ITOF15, dis##VU##MI_FTOI15, dis##VU##MI_MULAw , dis##VU##MI_CLIP , \ - dis##VU##MI_MADDAi, dis##VU##MI_MSUBAi, disNULL , dis##VU##MI_NOP , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ -}; \ - \ -MakeDisF(dis##VU##_UPPER_FD_00, dis##VU##_UPPER_FD_00_TABLE[_Fd_] DisFInterfaceN) \ -MakeDisF(dis##VU##_UPPER_FD_01, dis##VU##_UPPER_FD_01_TABLE[_Fd_] DisFInterfaceN) \ -MakeDisF(dis##VU##_UPPER_FD_10, dis##VU##_UPPER_FD_10_TABLE[_Fd_] DisFInterfaceN) \ -MakeDisF(dis##VU##_UPPER_FD_11, dis##VU##_UPPER_FD_11_TABLE[_Fd_] DisFInterfaceN) \ - \ -TdisR5900F dis##VU##MicroU[] = { \ - dis##VU##MI_ADDx , dis##VU##MI_ADDy , dis##VU##MI_ADDz , dis##VU##MI_ADDw, \ - dis##VU##MI_SUBx , dis##VU##MI_SUBy , dis##VU##MI_SUBz , dis##VU##MI_SUBw, \ - dis##VU##MI_MADDx , dis##VU##MI_MADDy , dis##VU##MI_MADDz , dis##VU##MI_MADDw, \ - dis##VU##MI_MSUBx , dis##VU##MI_MSUBy , dis##VU##MI_MSUBz , dis##VU##MI_MSUBw, \ - dis##VU##MI_MAXx , dis##VU##MI_MAXy , dis##VU##MI_MAXz , dis##VU##MI_MAXw, /* 0x10 */ \ - dis##VU##MI_MINIx , dis##VU##MI_MINIy , dis##VU##MI_MINIz , dis##VU##MI_MINIw, \ - dis##VU##MI_MULx , dis##VU##MI_MULy , dis##VU##MI_MULz , dis##VU##MI_MULw, \ - dis##VU##MI_MULq , dis##VU##MI_MAXi , dis##VU##MI_MULi , dis##VU##MI_MINIi, \ - dis##VU##MI_ADDq , dis##VU##MI_MADDq , dis##VU##MI_ADDi , dis##VU##MI_MADDi, /* 0x20 */ \ - dis##VU##MI_SUBq , dis##VU##MI_MSUBq , dis##VU##MI_SUBi , dis##VU##MI_MSUBi, \ - dis##VU##MI_ADD , dis##VU##MI_MADD , dis##VU##MI_MUL , dis##VU##MI_MAX, \ - dis##VU##MI_SUB , dis##VU##MI_MSUB , dis##VU##MI_OPMSUB, dis##VU##MI_MINI, \ - disNULL , disNULL , disNULL , disNULL , /* 0x30 */ \ - disNULL , disNULL , disNULL , disNULL , \ - disNULL , disNULL , disNULL , disNULL , \ - dis##VU##_UPPER_FD_00, dis##VU##_UPPER_FD_01, dis##VU##_UPPER_FD_10, dis##VU##_UPPER_FD_11, \ -}; \ - \ - \ -MakeDisF(dis##VU##MicroUF, dis##VU##MicroU[code & 0x3f] DisFInterfaceN) \ - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + + +#define _disVUTables(VU) \ + \ +/****************/ \ +/* LOWER TABLES */ \ +/****************/ \ + \ +TdisR5900F dis##VU##LowerOP_T3_00_OPCODE[32] = { \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + dis##VU##MI_MOVE , dis##VU##MI_LQI , dis##VU##MI_DIV , dis##VU##MI_MTIR, \ + dis##VU##MI_RNEXT , disNULL , disNULL , disNULL , /* 0x10 */ \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , dis##VU##MI_MFP , dis##VU##MI_XTOP , dis##VU##MI_XGKICK, \ + dis##VU##MI_ESADD , dis##VU##MI_EATANxy, dis##VU##MI_ESQRT, dis##VU##MI_ESIN, \ +}; \ + \ +TdisR5900F dis##VU##LowerOP_T3_01_OPCODE[32] = { \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + dis##VU##MI_MR32 , dis##VU##MI_SQI , dis##VU##MI_SQRT , dis##VU##MI_MFIR, \ + dis##VU##MI_RGET , disNULL , disNULL , disNULL , /* 0x10 */ \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , dis##VU##MI_XITOP, disNULL , \ + dis##VU##MI_ERSADD, dis##VU##MI_EATANxz, dis##VU##MI_ERSQRT, dis##VU##MI_EATAN, \ +}; \ + \ +TdisR5900F dis##VU##LowerOP_T3_10_OPCODE[32] = { \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , dis##VU##MI_LQD , dis##VU##MI_RSQRT, dis##VU##MI_ILWR, \ + dis##VU##MI_RINIT , disNULL , disNULL , disNULL , /* 0x10 */ \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + dis##VU##MI_ELENG , dis##VU##MI_ESUM , dis##VU##MI_ERCPR, dis##VU##MI_EEXP, \ +}; \ + \ +TdisR5900F dis##VU##LowerOP_T3_11_OPCODE[32] = { \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , dis##VU##MI_SQD , dis##VU##MI_WAITQ, dis##VU##MI_ISWR, \ + dis##VU##MI_RXOR , disNULL , disNULL , disNULL , /* 0x10 */ \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + dis##VU##MI_ERLENG, disNULL , dis##VU##MI_WAITP, disNULL , \ +}; \ + \ +MakeDisF(dis##VU##LowerOP_T3_00, dis##VU##LowerOP_T3_00_OPCODE[_Fd_] DisFInterfaceN) \ +MakeDisF(dis##VU##LowerOP_T3_01, dis##VU##LowerOP_T3_01_OPCODE[_Fd_] DisFInterfaceN) \ +MakeDisF(dis##VU##LowerOP_T3_10, dis##VU##LowerOP_T3_10_OPCODE[_Fd_] DisFInterfaceN) \ +MakeDisF(dis##VU##LowerOP_T3_11, dis##VU##LowerOP_T3_11_OPCODE[_Fd_] DisFInterfaceN) \ + \ +TdisR5900F dis##VU##LowerOP_OPCODE[64] = { \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , /* 0x10 */ \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , /* 0x20 */ \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + dis##VU##MI_IADD , dis##VU##MI_ISUB , dis##VU##MI_IADDI, disNULL , /* 0x30 */ \ + dis##VU##MI_IAND , dis##VU##MI_IOR , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + dis##VU##LowerOP_T3_00, dis##VU##LowerOP_T3_01, dis##VU##LowerOP_T3_10, dis##VU##LowerOP_T3_11, \ +}; \ + \ +MakeDisF(dis##VU##LowerOP, dis##VU##LowerOP_OPCODE[code & 0x3f] DisFInterfaceN) \ + \ +TdisR5900F dis##VU##MicroL[] = { \ + dis##VU##MI_LQ , dis##VU##MI_SQ , disNULL , disNULL, \ + dis##VU##MI_ILW , dis##VU##MI_ISW , disNULL , disNULL, \ + dis##VU##MI_IADDIU, dis##VU##MI_ISUBIU, disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + dis##VU##MI_FCEQ , dis##VU##MI_FCSET , dis##VU##MI_FCAND, dis##VU##MI_FCOR, /* 0x10 */ \ + dis##VU##MI_FSEQ , dis##VU##MI_FSSET , dis##VU##MI_FSAND, dis##VU##MI_FSOR, \ + dis##VU##MI_FMEQ , disNULL , dis##VU##MI_FMAND, dis##VU##MI_FMOR, \ + dis##VU##MI_FCGET , disNULL , disNULL , disNULL, \ + dis##VU##MI_B , dis##VU##MI_BAL , disNULL , disNULL, /* 0x20 */ \ + dis##VU##MI_JR , dis##VU##MI_JALR , disNULL , disNULL, \ + dis##VU##MI_IBEQ , dis##VU##MI_IBNE , disNULL , disNULL, \ + dis##VU##MI_IBLTZ , dis##VU##MI_IBGTZ , dis##VU##MI_IBLEZ, dis##VU##MI_IBGEZ, \ + disNULL , disNULL , disNULL , disNULL, /* 0x30 */ \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + dis##VU##LowerOP , disNULL , disNULL , disNULL, /* 0x40*/ \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, /* 0x50 */ \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, /* 0x60 */ \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, /* 0x70 */ \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ + disNULL , disNULL , disNULL , disNULL, \ +}; \ + \ + \ +MakeDisF(dis##VU##MicroLF, dis##VU##MicroL[code >> 25] DisFInterfaceN) \ + \ + \ +/****************/ \ +/* UPPER TABLES */ \ +/****************/ \ + \ +TdisR5900F dis##VU##_UPPER_FD_00_TABLE[32] = { \ + dis##VU##MI_ADDAx, dis##VU##MI_SUBx , dis##VU##MI_MADDAx, dis##VU##MI_MSUBAx, \ + dis##VU##MI_ITOF0, dis##VU##MI_FTOI0, dis##VU##MI_MULAx , dis##VU##MI_MULAq , \ + dis##VU##MI_ADDAq, dis##VU##MI_SUBAq, dis##VU##MI_ADDA , dis##VU##MI_SUBA , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ +}; \ + \ +TdisR5900F dis##VU##_UPPER_FD_01_TABLE[32] = { \ + dis##VU##MI_ADDAy , dis##VU##MI_SUBy , dis##VU##MI_MADDAy, dis##VU##MI_MSUBAy, \ + dis##VU##MI_ITOF4 , dis##VU##MI_FTOI4 , dis##VU##MI_MULAy , dis##VU##MI_ABS , \ + dis##VU##MI_MADDAq, dis##VU##MI_MSUBAq, dis##VU##MI_MADDA , dis##VU##MI_MSUBA , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ +}; \ + \ +TdisR5900F dis##VU##_UPPER_FD_10_TABLE[32] = { \ + dis##VU##MI_ADDAz , dis##VU##MI_SUBz , dis##VU##MI_MADDAz, dis##VU##MI_MSUBAz, \ + dis##VU##MI_ITOF12, dis##VU##MI_FTOI12, dis##VU##MI_MULAz , dis##VU##MI_MULAi , \ + dis##VU##MI_ADDAi, dis##VU##MI_SUBAi , dis##VU##MI_MULA , dis##VU##MI_OPMULA, \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ +}; \ + \ +TdisR5900F dis##VU##_UPPER_FD_11_TABLE[32] = { \ + dis##VU##MI_ADDAw , dis##VU##MI_SUBw , dis##VU##MI_MADDAw, dis##VU##MI_MSUBAw, \ + dis##VU##MI_ITOF15, dis##VU##MI_FTOI15, dis##VU##MI_MULAw , dis##VU##MI_CLIP , \ + dis##VU##MI_MADDAi, dis##VU##MI_MSUBAi, disNULL , dis##VU##MI_NOP , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ +}; \ + \ +MakeDisF(dis##VU##_UPPER_FD_00, dis##VU##_UPPER_FD_00_TABLE[_Fd_] DisFInterfaceN) \ +MakeDisF(dis##VU##_UPPER_FD_01, dis##VU##_UPPER_FD_01_TABLE[_Fd_] DisFInterfaceN) \ +MakeDisF(dis##VU##_UPPER_FD_10, dis##VU##_UPPER_FD_10_TABLE[_Fd_] DisFInterfaceN) \ +MakeDisF(dis##VU##_UPPER_FD_11, dis##VU##_UPPER_FD_11_TABLE[_Fd_] DisFInterfaceN) \ + \ +TdisR5900F dis##VU##MicroU[] = { \ + dis##VU##MI_ADDx , dis##VU##MI_ADDy , dis##VU##MI_ADDz , dis##VU##MI_ADDw, \ + dis##VU##MI_SUBx , dis##VU##MI_SUBy , dis##VU##MI_SUBz , dis##VU##MI_SUBw, \ + dis##VU##MI_MADDx , dis##VU##MI_MADDy , dis##VU##MI_MADDz , dis##VU##MI_MADDw, \ + dis##VU##MI_MSUBx , dis##VU##MI_MSUBy , dis##VU##MI_MSUBz , dis##VU##MI_MSUBw, \ + dis##VU##MI_MAXx , dis##VU##MI_MAXy , dis##VU##MI_MAXz , dis##VU##MI_MAXw, /* 0x10 */ \ + dis##VU##MI_MINIx , dis##VU##MI_MINIy , dis##VU##MI_MINIz , dis##VU##MI_MINIw, \ + dis##VU##MI_MULx , dis##VU##MI_MULy , dis##VU##MI_MULz , dis##VU##MI_MULw, \ + dis##VU##MI_MULq , dis##VU##MI_MAXi , dis##VU##MI_MULi , dis##VU##MI_MINIi, \ + dis##VU##MI_ADDq , dis##VU##MI_MADDq , dis##VU##MI_ADDi , dis##VU##MI_MADDi, /* 0x20 */ \ + dis##VU##MI_SUBq , dis##VU##MI_MSUBq , dis##VU##MI_SUBi , dis##VU##MI_MSUBi, \ + dis##VU##MI_ADD , dis##VU##MI_MADD , dis##VU##MI_MUL , dis##VU##MI_MAX, \ + dis##VU##MI_SUB , dis##VU##MI_MSUB , dis##VU##MI_OPMSUB, dis##VU##MI_MINI, \ + disNULL , disNULL , disNULL , disNULL , /* 0x30 */ \ + disNULL , disNULL , disNULL , disNULL , \ + disNULL , disNULL , disNULL , disNULL , \ + dis##VU##_UPPER_FD_00, dis##VU##_UPPER_FD_01, dis##VU##_UPPER_FD_10, dis##VU##_UPPER_FD_11, \ +}; \ + \ + \ +MakeDisF(dis##VU##MicroUF, dis##VU##MicroU[code & 0x3f] DisFInterfaceN) \ + diff --git a/pcsx2/DebugTools/DisVUops.h b/pcsx2/DebugTools/DisVUops.h index fb43a9d69a..53409e8121 100644 --- a/pcsx2/DebugTools/DisVUops.h +++ b/pcsx2/DebugTools/DisVUops.h @@ -1,197 +1,197 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - - -#define _disVUOpcodes(VU) \ - \ -/*****************/ \ -/* LOWER OPCODES */ \ -/*****************/ \ - \ -MakeDisF(dis##VU##MI_DIV, dName("DIV"); dCP232f(_Fs_, _Fsf_); dCP232f(_Ft_, _Ftf_);) \ -MakeDisF(dis##VU##MI_SQRT, dName("SQRT"); dCP232f(_Ft_, _Ftf_);) \ -MakeDisF(dis##VU##MI_RSQRT, dName("RSQRT"); dCP232f(_Fs_, _Fsf_); dCP232f(_Ft_, _Ftf_);) \ -MakeDisF(dis##VU##MI_IADDI, dName("IADDI"); dCP232i(_Ft_); dCP232i(_Fs_); dImm5();) \ -MakeDisF(dis##VU##MI_IADDIU, dName("IADDIU"); dCP232i(_Ft_); dCP232i(_Fs_); dImm15();) \ -MakeDisF(dis##VU##MI_IADD, dName("IADD"); dCP232i(_Fd_); dCP232i(_Fs_); dCP232i(_Ft_);) \ -MakeDisF(dis##VU##MI_IAND, dName("IAND"); dCP232i(_Fd_); dCP232i(_Fs_); dCP232i(_Ft_);) \ -MakeDisF(dis##VU##MI_IOR, dName("IOR"); dCP232i(_Fd_); dCP232i(_Fs_); dCP232i(_Ft_);) \ -MakeDisF(dis##VU##MI_ISUB, dName("ISUB"); dCP232i(_Fd_); dCP232i(_Fs_); dCP232i(_Ft_);) \ -MakeDisF(dis##VU##MI_ISUBIU, dName("ISUBIU"); dCP232i(_Ft_); dCP232i(_Fs_); dImm15();) \ -MakeDisF(dis##VU##MI_MOVE, if (_Fs_ == 0 && _Ft_ == 0) { dNameU("NOP"); } else { dNameU("MOVE"); dCP2128f(_Ft_); dCP2128f(_Fs_); }) \ -MakeDisF(dis##VU##MI_MFIR, dNameU("MFIR"); dCP2128f(_Ft_); dCP232i(_Fs_);) \ -MakeDisF(dis##VU##MI_MTIR, dNameU("MTIR"); dCP232i(_Ft_); dCP232f(_Fs_, _Fsf_);) \ -MakeDisF(dis##VU##MI_MR32, dNameU("MR32"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ -MakeDisF(dis##VU##MI_LQ, dNameU("LQ"); dCP2128f(_Ft_); dCP232i(_Fs_); dImm11();) \ -MakeDisF(dis##VU##MI_LQD, dNameU("LQD"); dCP2128f(_Ft_); dCP232i(_Fs_);) \ -MakeDisF(dis##VU##MI_LQI, dNameU("LQI"); dCP2128f(_Ft_); dCP232i(_Fs_);) \ -MakeDisF(dis##VU##MI_SQ, dNameU("SQ"); dCP2128f(_Fs_); dCP232i(_Ft_); dImm11(); ) \ -MakeDisF(dis##VU##MI_SQD, dNameU("SQD"); dCP2128f(_Fs_); dCP232i(_Ft_);) \ -MakeDisF(dis##VU##MI_SQI, dNameU("SQI"); dCP2128f(_Fs_); dCP232i(_Ft_);) \ -MakeDisF(dis##VU##MI_ILW, dNameU("ILW"); dCP232i(_Ft_); dImm11(); dCP232i(_Fs_);) \ -MakeDisF(dis##VU##MI_ISW, dNameU("ISW"); dCP232i(_Ft_); dImm11(); dCP232i(_Fs_);) \ -MakeDisF(dis##VU##MI_ILWR, dNameU("ILWR"); dCP232i(_Ft_); dCP232i(_Fs_);) \ -MakeDisF(dis##VU##MI_ISWR, dNameU("ISWR"); dCP232i(_Ft_); dCP232i(_Fs_);) \ -MakeDisF(dis##VU##MI_LOI, dName("LOI"); ) \ -MakeDisF(dis##VU##MI_RINIT, dNameU("RINIT"); dCP232i(REG_R); dCP232f(_Fs_, _Fsf_);) \ -MakeDisF(dis##VU##MI_RGET, dNameU("RGET"); dCP232i(REG_R); dCP2128f(_Ft_);) \ -MakeDisF(dis##VU##MI_RNEXT, dNameU("RNEXT"); dCP232i(REG_R); dCP2128f(_Ft_);) \ -MakeDisF(dis##VU##MI_RXOR, dNameU("RXOR"); dCP232i(REG_R); dCP232f(_Fs_, _Fsf_);) \ -MakeDisF(dis##VU##MI_WAITQ, dName("WAITQ"); ) \ -MakeDisF(dis##VU##MI_FSAND, dName("FSAND"); dCP232i(_Ft_); dCP232i(REG_STATUS_FLAG); sprintf(ostr, "%s %.3x,", ostr, code&0xfff); ) \ -MakeDisF(dis##VU##MI_FSEQ, dName("FSEQ"); dCP232i(_Ft_); dCP232i(REG_STATUS_FLAG); sprintf(ostr, "%s %.3x,", ostr, code&0xfff);) \ -MakeDisF(dis##VU##MI_FSOR, dName("FSOR"); dCP232i(_Ft_); dCP232i(REG_STATUS_FLAG); sprintf(ostr, "%s %.3x,", ostr, code&0xfff);) \ -MakeDisF(dis##VU##MI_FSSET, dName("FSSET"); dCP232i(REG_STATUS_FLAG);) \ -MakeDisF(dis##VU##MI_FMAND, dName("FMAND"); dCP232i(_Ft_); dCP232i(REG_MAC_FLAG); dCP232i(_Fs_);) \ -MakeDisF(dis##VU##MI_FMEQ, dName("FMEQ"); dCP232i(_Ft_); dCP232i(REG_MAC_FLAG); dCP232i(_Fs_);) \ -MakeDisF(dis##VU##MI_FMOR, dName("FMOR"); dCP232i(_Ft_); dCP232i(REG_MAC_FLAG); dCP232i(_Fs_);) \ -MakeDisF(dis##VU##MI_FCAND, dName("FCAND"); dCP232i(1); sprintf(ostr, "%s %8.8x,", ostr, code&0xffffff); ) \ -MakeDisF(dis##VU##MI_FCEQ, dName("FCEQ"); dCP232i(1); dCP232i(REG_CLIP_FLAG);) \ -MakeDisF(dis##VU##MI_FCOR, dName("FCOR"); dCP232i(1); dCP232i(REG_CLIP_FLAG);) \ -MakeDisF(dis##VU##MI_FCSET, dName("FCSET"); dCP232i(REG_CLIP_FLAG); sprintf(ostr, "%s %.6x,", ostr, code&0xffffff); ) \ -MakeDisF(dis##VU##MI_FCGET, dName("FCGET"); dCP232i(_Ft_); dCP232i(REG_CLIP_FLAG);) \ -MakeDisF(dis##VU##MI_IBEQ, dName("IBEQ"); dImm11(); dCP232i(_Ft_); dCP232i(_Fs_);) \ -MakeDisF(dis##VU##MI_IBGEZ, dName("IBEZ"); dImm11(); dCP232i(_Ft_); dCP232i(_Fs_);) \ -MakeDisF(dis##VU##MI_IBGTZ, dName("IBGTZ"); dImm11(); dCP232i(_Ft_); dCP232i(_Fs_);) \ -MakeDisF(dis##VU##MI_IBLEZ, dName("IBLEZ"); dImm11(); dCP232i(_Ft_); dCP232i(_Fs_);) \ -MakeDisF(dis##VU##MI_IBLTZ, dName("IBLTZ"); dImm11(); dCP232i(_Ft_); dCP232i(_Fs_);) \ -MakeDisF(dis##VU##MI_IBNE, dName("IBNE"); dImm11(); dCP232i(_Ft_); dCP232i(_Fs_);) \ -MakeDisF(dis##VU##MI_B, dName("B"); dImm11();) \ -MakeDisF(dis##VU##MI_BAL, dName("BAL"); dImm11(); dCP232i(_Ft_);) \ -MakeDisF(dis##VU##MI_JR, dName("JR"); dCP232i(_Fs_);) \ -MakeDisF(dis##VU##MI_JALR, dName("JALR"); dCP232i(_Ft_); dCP232i(_Fs_); ) \ -MakeDisF(dis##VU##MI_MFP, dNameU("MFP"); dCP2128f(_Ft_); dCP232i(REG_P);) \ -MakeDisF(dis##VU##MI_WAITP, dName("WAITP"); ) \ -MakeDisF(dis##VU##MI_ESADD, dName("ESADD"); dCP2128f(_Fs_);) \ -MakeDisF(dis##VU##MI_ERSADD, dName("ERSADD"); dCP2128f(_Fs_);) \ -MakeDisF(dis##VU##MI_ELENG, dName("ELENG"); dCP2128f(_Fs_); ) \ -MakeDisF(dis##VU##MI_ERLENG, dName("ERLENG"); dCP2128f(_Fs_); ) \ -MakeDisF(dis##VU##MI_EATANxy, dName("EATANxy"); dCP2128f(_Fs_);) \ -MakeDisF(dis##VU##MI_EATANxz, dName("EATANxz"); dCP2128f(_Fs_);) \ -MakeDisF(dis##VU##MI_ESUM, dName("ESUM"); dCP232i(_Fs_); ) \ -MakeDisF(dis##VU##MI_ERCPR, dName("ERCPR"); dCP232f(_Fs_, _Fsf_); ) \ -MakeDisF(dis##VU##MI_ESQRT, dName("ESQRT"); dCP232f(_Fs_, _Fsf_); ) \ -MakeDisF(dis##VU##MI_ERSQRT, dName("ERSQRT"); dCP232f(_Fs_, _Fsf_); ) \ -MakeDisF(dis##VU##MI_ESIN, dName("ESIN"); dCP232f(_Fs_, _Fsf_); ) \ -MakeDisF(dis##VU##MI_EATAN, dName("EATAN"); dCP232f(_Fs_, _Fsf_); ) \ -MakeDisF(dis##VU##MI_EEXP, dName("EEXP"); dCP232f(_Fs_, _Fsf_); ) \ -MakeDisF(dis##VU##MI_XITOP, dName("XITOP"); dCP232i(_Ft_);) \ -MakeDisF(dis##VU##MI_XGKICK, dName("XGKICK"); dCP232i(_Fs_);) \ -MakeDisF(dis##VU##MI_XTOP, dName("XTOP"); dCP232i(_Ft_);) \ - \ - \ -/*****************/ \ -/* UPPER OPCODES */ \ -/*****************/ \ - \ -MakeDisF(dis##VU##MI_ABS, dNameU("ABS"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ -MakeDisF(dis##VU##MI_ADD, dNameU("ADD"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ -MakeDisF(dis##VU##MI_ADDi, dNameU("ADDi"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_I);) \ -MakeDisF(dis##VU##MI_ADDq, dNameU("ADDq"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ -MakeDisF(dis##VU##MI_ADDx, dNameU("ADDx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232x(_Ft_);) \ -MakeDisF(dis##VU##MI_ADDy, dNameU("ADDy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232y(_Ft_);) \ -MakeDisF(dis##VU##MI_ADDz, dNameU("ADDz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232z(_Ft_);) \ -MakeDisF(dis##VU##MI_ADDw, dNameU("ADDw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232w(_Ft_);) \ -MakeDisF(dis##VU##MI_ADDA, dNameU("ADDA"); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ -MakeDisF(dis##VU##MI_ADDAi, dNameU("ADDAi"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ -MakeDisF(dis##VU##MI_ADDAq, dNameU("ADDAq"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ -MakeDisF(dis##VU##MI_ADDAx, dNameU("ADDAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ -MakeDisF(dis##VU##MI_ADDAy, dNameU("ADDAy"); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ -MakeDisF(dis##VU##MI_ADDAz, dNameU("ADDAz"); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ -MakeDisF(dis##VU##MI_ADDAw, dNameU("ADDAw"); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ -MakeDisF(dis##VU##MI_SUB, dNameU("SUB"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ -MakeDisF(dis##VU##MI_SUBi, dNameU("SUBi"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_I);) \ -MakeDisF(dis##VU##MI_SUBq, dNameU("SUBq"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ -MakeDisF(dis##VU##MI_SUBx, dNameU("SUBx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232x(_Ft_);) \ -MakeDisF(dis##VU##MI_SUBy, dNameU("SUBy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232y(_Ft_);) \ -MakeDisF(dis##VU##MI_SUBz, dNameU("SUBz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232z(_Ft_);) \ -MakeDisF(dis##VU##MI_SUBw, dNameU("SUBw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232w(_Ft_);) \ -MakeDisF(dis##VU##MI_SUBA, dNameU("SUBA"); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ -MakeDisF(dis##VU##MI_SUBAi, dNameU("SUBAi"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ -MakeDisF(dis##VU##MI_SUBAq, dNameU("SUBAq"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ -MakeDisF(dis##VU##MI_SUBAx, dNameU("SUBAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ -MakeDisF(dis##VU##MI_SUBAy, dNameU("SUBAy"); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ -MakeDisF(dis##VU##MI_SUBAz, dNameU("SUBAz"); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ -MakeDisF(dis##VU##MI_SUBAw, dNameU("SUBAw"); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ -MakeDisF(dis##VU##MI_MUL, dNameU("MUL"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ -MakeDisF(dis##VU##MI_MULi, dNameU("MULi"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_I);) \ -MakeDisF(dis##VU##MI_MULq, dNameU("MULq"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ -MakeDisF(dis##VU##MI_MULx, dNameU("MULx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232x(_Ft_);) \ -MakeDisF(dis##VU##MI_MULy, dNameU("MULy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232y(_Ft_);) \ -MakeDisF(dis##VU##MI_MULz, dNameU("MULz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232z(_Ft_);) \ -MakeDisF(dis##VU##MI_MULw, dNameU("MULw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232w(_Ft_);) \ -MakeDisF(dis##VU##MI_MULA, dNameU("MULA"); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ -MakeDisF(dis##VU##MI_MULAi, dNameU("MULAi"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ -MakeDisF(dis##VU##MI_MULAq, dNameU("MULAq"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ -MakeDisF(dis##VU##MI_MULAx, dNameU("MULAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ -MakeDisF(dis##VU##MI_MULAy, dNameU("MULAy"); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ -MakeDisF(dis##VU##MI_MULAz, dNameU("MULAz"); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ -MakeDisF(dis##VU##MI_MULAw, dNameU("MULAw"); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ -MakeDisF(dis##VU##MI_MADD, dNameU("MADD"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ -MakeDisF(dis##VU##MI_MADDi, dNameU("MADDi"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ -MakeDisF(dis##VU##MI_MADDq, dNameU("MADDq"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ -MakeDisF(dis##VU##MI_MADDx, dNameU("MADDx"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ -MakeDisF(dis##VU##MI_MADDy, dNameU("MADDy"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ -MakeDisF(dis##VU##MI_MADDz, dNameU("MADDz"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ -MakeDisF(dis##VU##MI_MADDw, dNameU("MADDw"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ -MakeDisF(dis##VU##MI_MADDA, dNameU("MADDA"); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ -MakeDisF(dis##VU##MI_MADDAi, dNameU("MADDAi"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ -MakeDisF(dis##VU##MI_MADDAq, dNameU("MADDAq"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ -MakeDisF(dis##VU##MI_MADDAx, dNameU("MADDAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ -MakeDisF(dis##VU##MI_MADDAy, dNameU("MADDAy"); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ -MakeDisF(dis##VU##MI_MADDAz, dNameU("MADDAz"); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ -MakeDisF(dis##VU##MI_MADDAw, dNameU("MADDAw"); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ -MakeDisF(dis##VU##MI_MSUB, dNameU("MSUB"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ -MakeDisF(dis##VU##MI_MSUBi, dNameU("MSUBi"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ -MakeDisF(dis##VU##MI_MSUBq, dNameU("MSUBq"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ -MakeDisF(dis##VU##MI_MSUBx, dNameU("MSUBx"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ -MakeDisF(dis##VU##MI_MSUBy, dNameU("MSUBy"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ -MakeDisF(dis##VU##MI_MSUBz, dNameU("MSUBz"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ -MakeDisF(dis##VU##MI_MSUBw, dNameU("MSUBw"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ -MakeDisF(dis##VU##MI_MSUBA, dNameU("MSUBA"); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ -MakeDisF(dis##VU##MI_MSUBAi, dNameU("MSUBAi"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ -MakeDisF(dis##VU##MI_MSUBAq, dNameU("MSUBAq"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ -MakeDisF(dis##VU##MI_MSUBAx, dNameU("MSUBAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ -MakeDisF(dis##VU##MI_MSUBAy, dNameU("MSUBAy"); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ -MakeDisF(dis##VU##MI_MSUBAz, dNameU("MSUBAz"); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ -MakeDisF(dis##VU##MI_MSUBAw, dNameU("MSUBAw"); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ -MakeDisF(dis##VU##MI_MAX, dNameU("MAX"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ -MakeDisF(dis##VU##MI_MAXi, dNameU("MAXi"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_I);) \ -MakeDisF(dis##VU##MI_MAXx, dNameU("MAXx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232x(_Ft_);) \ -MakeDisF(dis##VU##MI_MAXy, dNameU("MAXy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232y(_Ft_);) \ -MakeDisF(dis##VU##MI_MAXz, dNameU("MAXz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232z(_Ft_);) \ -MakeDisF(dis##VU##MI_MAXw, dNameU("MAXw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232w(_Ft_);) \ -MakeDisF(dis##VU##MI_MINI, dNameU("MINI"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ -MakeDisF(dis##VU##MI_MINIi, dNameU("MINIi"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_I);) \ -MakeDisF(dis##VU##MI_MINIx, dNameU("MINIx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232x(_Ft_);) \ -MakeDisF(dis##VU##MI_MINIy, dNameU("MINIy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232y(_Ft_);) \ -MakeDisF(dis##VU##MI_MINIz, dNameU("MINIz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232z(_Ft_);) \ -MakeDisF(dis##VU##MI_MINIw, dNameU("MINIw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232w(_Ft_);) \ -MakeDisF(dis##VU##MI_OPMULA, dNameU("OPMULA"); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ -MakeDisF(dis##VU##MI_OPMSUB, dNameU("OPMSUB"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ -MakeDisF(dis##VU##MI_NOP, dName("NOP");) \ -MakeDisF(dis##VU##MI_FTOI0, dNameU("FTOI0"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ -MakeDisF(dis##VU##MI_FTOI4, dNameU("FTOI4"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ -MakeDisF(dis##VU##MI_FTOI12, dNameU("FTOI12"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ -MakeDisF(dis##VU##MI_FTOI15, dNameU("FTOI15"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ -MakeDisF(dis##VU##MI_ITOF0, dNameU("ITOF0"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ -MakeDisF(dis##VU##MI_ITOF4, dNameU("ITOF4"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ -MakeDisF(dis##VU##MI_ITOF12, dNameU("ITOF12"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ -MakeDisF(dis##VU##MI_ITOF15, dNameU("ITOF15"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ -MakeDisF(dis##VU##MI_CLIP, dNameU("CLIP"); dCP2128f(_Fs_); dCP232w(_Ft_);) \ - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + + +#define _disVUOpcodes(VU) \ + \ +/*****************/ \ +/* LOWER OPCODES */ \ +/*****************/ \ + \ +MakeDisF(dis##VU##MI_DIV, dName("DIV"); dCP232f(_Fs_, _Fsf_); dCP232f(_Ft_, _Ftf_);) \ +MakeDisF(dis##VU##MI_SQRT, dName("SQRT"); dCP232f(_Ft_, _Ftf_);) \ +MakeDisF(dis##VU##MI_RSQRT, dName("RSQRT"); dCP232f(_Fs_, _Fsf_); dCP232f(_Ft_, _Ftf_);) \ +MakeDisF(dis##VU##MI_IADDI, dName("IADDI"); dCP232i(_Ft_); dCP232i(_Fs_); dImm5();) \ +MakeDisF(dis##VU##MI_IADDIU, dName("IADDIU"); dCP232i(_Ft_); dCP232i(_Fs_); dImm15();) \ +MakeDisF(dis##VU##MI_IADD, dName("IADD"); dCP232i(_Fd_); dCP232i(_Fs_); dCP232i(_Ft_);) \ +MakeDisF(dis##VU##MI_IAND, dName("IAND"); dCP232i(_Fd_); dCP232i(_Fs_); dCP232i(_Ft_);) \ +MakeDisF(dis##VU##MI_IOR, dName("IOR"); dCP232i(_Fd_); dCP232i(_Fs_); dCP232i(_Ft_);) \ +MakeDisF(dis##VU##MI_ISUB, dName("ISUB"); dCP232i(_Fd_); dCP232i(_Fs_); dCP232i(_Ft_);) \ +MakeDisF(dis##VU##MI_ISUBIU, dName("ISUBIU"); dCP232i(_Ft_); dCP232i(_Fs_); dImm15();) \ +MakeDisF(dis##VU##MI_MOVE, if (_Fs_ == 0 && _Ft_ == 0) { dNameU("NOP"); } else { dNameU("MOVE"); dCP2128f(_Ft_); dCP2128f(_Fs_); }) \ +MakeDisF(dis##VU##MI_MFIR, dNameU("MFIR"); dCP2128f(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_MTIR, dNameU("MTIR"); dCP232i(_Ft_); dCP232f(_Fs_, _Fsf_);) \ +MakeDisF(dis##VU##MI_MR32, dNameU("MR32"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_LQ, dNameU("LQ"); dCP2128f(_Ft_); dCP232i(_Fs_); dImm11();) \ +MakeDisF(dis##VU##MI_LQD, dNameU("LQD"); dCP2128f(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_LQI, dNameU("LQI"); dCP2128f(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_SQ, dNameU("SQ"); dCP2128f(_Fs_); dCP232i(_Ft_); dImm11(); ) \ +MakeDisF(dis##VU##MI_SQD, dNameU("SQD"); dCP2128f(_Fs_); dCP232i(_Ft_);) \ +MakeDisF(dis##VU##MI_SQI, dNameU("SQI"); dCP2128f(_Fs_); dCP232i(_Ft_);) \ +MakeDisF(dis##VU##MI_ILW, dNameU("ILW"); dCP232i(_Ft_); dImm11(); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_ISW, dNameU("ISW"); dCP232i(_Ft_); dImm11(); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_ILWR, dNameU("ILWR"); dCP232i(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_ISWR, dNameU("ISWR"); dCP232i(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_LOI, dName("LOI"); ) \ +MakeDisF(dis##VU##MI_RINIT, dNameU("RINIT"); dCP232i(REG_R); dCP232f(_Fs_, _Fsf_);) \ +MakeDisF(dis##VU##MI_RGET, dNameU("RGET"); dCP232i(REG_R); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_RNEXT, dNameU("RNEXT"); dCP232i(REG_R); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_RXOR, dNameU("RXOR"); dCP232i(REG_R); dCP232f(_Fs_, _Fsf_);) \ +MakeDisF(dis##VU##MI_WAITQ, dName("WAITQ"); ) \ +MakeDisF(dis##VU##MI_FSAND, dName("FSAND"); dCP232i(_Ft_); dCP232i(REG_STATUS_FLAG); sprintf(ostr, "%s %.3x,", ostr, code&0xfff); ) \ +MakeDisF(dis##VU##MI_FSEQ, dName("FSEQ"); dCP232i(_Ft_); dCP232i(REG_STATUS_FLAG); sprintf(ostr, "%s %.3x,", ostr, code&0xfff);) \ +MakeDisF(dis##VU##MI_FSOR, dName("FSOR"); dCP232i(_Ft_); dCP232i(REG_STATUS_FLAG); sprintf(ostr, "%s %.3x,", ostr, code&0xfff);) \ +MakeDisF(dis##VU##MI_FSSET, dName("FSSET"); dCP232i(REG_STATUS_FLAG);) \ +MakeDisF(dis##VU##MI_FMAND, dName("FMAND"); dCP232i(_Ft_); dCP232i(REG_MAC_FLAG); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_FMEQ, dName("FMEQ"); dCP232i(_Ft_); dCP232i(REG_MAC_FLAG); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_FMOR, dName("FMOR"); dCP232i(_Ft_); dCP232i(REG_MAC_FLAG); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_FCAND, dName("FCAND"); dCP232i(1); sprintf(ostr, "%s %8.8x,", ostr, code&0xffffff); ) \ +MakeDisF(dis##VU##MI_FCEQ, dName("FCEQ"); dCP232i(1); dCP232i(REG_CLIP_FLAG);) \ +MakeDisF(dis##VU##MI_FCOR, dName("FCOR"); dCP232i(1); dCP232i(REG_CLIP_FLAG);) \ +MakeDisF(dis##VU##MI_FCSET, dName("FCSET"); dCP232i(REG_CLIP_FLAG); sprintf(ostr, "%s %.6x,", ostr, code&0xffffff); ) \ +MakeDisF(dis##VU##MI_FCGET, dName("FCGET"); dCP232i(_Ft_); dCP232i(REG_CLIP_FLAG);) \ +MakeDisF(dis##VU##MI_IBEQ, dName("IBEQ"); dImm11(); dCP232i(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_IBGEZ, dName("IBEZ"); dImm11(); dCP232i(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_IBGTZ, dName("IBGTZ"); dImm11(); dCP232i(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_IBLEZ, dName("IBLEZ"); dImm11(); dCP232i(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_IBLTZ, dName("IBLTZ"); dImm11(); dCP232i(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_IBNE, dName("IBNE"); dImm11(); dCP232i(_Ft_); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_B, dName("B"); dImm11();) \ +MakeDisF(dis##VU##MI_BAL, dName("BAL"); dImm11(); dCP232i(_Ft_);) \ +MakeDisF(dis##VU##MI_JR, dName("JR"); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_JALR, dName("JALR"); dCP232i(_Ft_); dCP232i(_Fs_); ) \ +MakeDisF(dis##VU##MI_MFP, dNameU("MFP"); dCP2128f(_Ft_); dCP232i(REG_P);) \ +MakeDisF(dis##VU##MI_WAITP, dName("WAITP"); ) \ +MakeDisF(dis##VU##MI_ESADD, dName("ESADD"); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_ERSADD, dName("ERSADD"); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_ELENG, dName("ELENG"); dCP2128f(_Fs_); ) \ +MakeDisF(dis##VU##MI_ERLENG, dName("ERLENG"); dCP2128f(_Fs_); ) \ +MakeDisF(dis##VU##MI_EATANxy, dName("EATANxy"); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_EATANxz, dName("EATANxz"); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_ESUM, dName("ESUM"); dCP232i(_Fs_); ) \ +MakeDisF(dis##VU##MI_ERCPR, dName("ERCPR"); dCP232f(_Fs_, _Fsf_); ) \ +MakeDisF(dis##VU##MI_ESQRT, dName("ESQRT"); dCP232f(_Fs_, _Fsf_); ) \ +MakeDisF(dis##VU##MI_ERSQRT, dName("ERSQRT"); dCP232f(_Fs_, _Fsf_); ) \ +MakeDisF(dis##VU##MI_ESIN, dName("ESIN"); dCP232f(_Fs_, _Fsf_); ) \ +MakeDisF(dis##VU##MI_EATAN, dName("EATAN"); dCP232f(_Fs_, _Fsf_); ) \ +MakeDisF(dis##VU##MI_EEXP, dName("EEXP"); dCP232f(_Fs_, _Fsf_); ) \ +MakeDisF(dis##VU##MI_XITOP, dName("XITOP"); dCP232i(_Ft_);) \ +MakeDisF(dis##VU##MI_XGKICK, dName("XGKICK"); dCP232i(_Fs_);) \ +MakeDisF(dis##VU##MI_XTOP, dName("XTOP"); dCP232i(_Ft_);) \ + \ + \ +/*****************/ \ +/* UPPER OPCODES */ \ +/*****************/ \ + \ +MakeDisF(dis##VU##MI_ABS, dNameU("ABS"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_ADD, dNameU("ADD"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_ADDi, dNameU("ADDi"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_ADDq, dNameU("ADDq"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_ADDx, dNameU("ADDx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_ADDy, dNameU("ADDy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_ADDz, dNameU("ADDz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_ADDw, dNameU("ADDw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_ADDA, dNameU("ADDA"); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_ADDAi, dNameU("ADDAi"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_ADDAq, dNameU("ADDAq"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_ADDAx, dNameU("ADDAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_ADDAy, dNameU("ADDAy"); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_ADDAz, dNameU("ADDAz"); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_ADDAw, dNameU("ADDAw"); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_SUB, dNameU("SUB"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_SUBi, dNameU("SUBi"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_SUBq, dNameU("SUBq"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_SUBx, dNameU("SUBx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_SUBy, dNameU("SUBy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_SUBz, dNameU("SUBz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_SUBw, dNameU("SUBw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_SUBA, dNameU("SUBA"); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_SUBAi, dNameU("SUBAi"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_SUBAq, dNameU("SUBAq"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_SUBAx, dNameU("SUBAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_SUBAy, dNameU("SUBAy"); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_SUBAz, dNameU("SUBAz"); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_SUBAw, dNameU("SUBAw"); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_MUL, dNameU("MUL"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_MULi, dNameU("MULi"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_MULq, dNameU("MULq"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_MULx, dNameU("MULx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_MULy, dNameU("MULy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_MULz, dNameU("MULz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_MULw, dNameU("MULw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_MULA, dNameU("MULA"); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_MULAi, dNameU("MULAi"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_MULAq, dNameU("MULAq"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_MULAx, dNameU("MULAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_MULAy, dNameU("MULAy"); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_MULAz, dNameU("MULAz"); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_MULAw, dNameU("MULAw"); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_MADD, dNameU("MADD"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_MADDi, dNameU("MADDi"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_MADDq, dNameU("MADDq"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_MADDx, dNameU("MADDx"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_MADDy, dNameU("MADDy"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_MADDz, dNameU("MADDz"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_MADDw, dNameU("MADDw"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_MADDA, dNameU("MADDA"); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_MADDAi, dNameU("MADDAi"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_MADDAq, dNameU("MADDAq"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_MADDAx, dNameU("MADDAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_MADDAy, dNameU("MADDAy"); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_MADDAz, dNameU("MADDAz"); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_MADDAw, dNameU("MADDAw"); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUB, dNameU("MSUB"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUBi, dNameU("MSUBi"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_MSUBq, dNameU("MSUBq"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_MSUBx, dNameU("MSUBx"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUBy, dNameU("MSUBy"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUBz, dNameU("MSUBz"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUBw, dNameU("MSUBw"); dCP2128f(_Fd_); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUBA, dNameU("MSUBA"); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUBAi, dNameU("MSUBAi"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_MSUBAq, dNameU("MSUBAq"); dCP2ACCf(); dCP2128f(_Fs_); dCP232iF(REG_Q);) \ +MakeDisF(dis##VU##MI_MSUBAx, dNameU("MSUBAx"); dCP2ACCf(); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUBAy, dNameU("MSUBAy"); dCP2ACCf(); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUBAz, dNameU("MSUBAz"); dCP2ACCf(); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_MSUBAw, dNameU("MSUBAw"); dCP2ACCf(); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_MAX, dNameU("MAX"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_MAXi, dNameU("MAXi"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_MAXx, dNameU("MAXx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_MAXy, dNameU("MAXy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_MAXz, dNameU("MAXz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_MAXw, dNameU("MAXw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_MINI, dNameU("MINI"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_MINIi, dNameU("MINIi"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232iF(REG_I);) \ +MakeDisF(dis##VU##MI_MINIx, dNameU("MINIx"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232x(_Ft_);) \ +MakeDisF(dis##VU##MI_MINIy, dNameU("MINIy"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232y(_Ft_);) \ +MakeDisF(dis##VU##MI_MINIz, dNameU("MINIz"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232z(_Ft_);) \ +MakeDisF(dis##VU##MI_MINIw, dNameU("MINIw"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP232w(_Ft_);) \ +MakeDisF(dis##VU##MI_OPMULA, dNameU("OPMULA"); dCP2ACCf(); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_OPMSUB, dNameU("OPMSUB"); dCP2128f(_Fd_); dCP2128f(_Fs_); dCP2128f(_Ft_);) \ +MakeDisF(dis##VU##MI_NOP, dName("NOP");) \ +MakeDisF(dis##VU##MI_FTOI0, dNameU("FTOI0"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_FTOI4, dNameU("FTOI4"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_FTOI12, dNameU("FTOI12"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_FTOI15, dNameU("FTOI15"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_ITOF0, dNameU("ITOF0"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_ITOF4, dNameU("ITOF4"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_ITOF12, dNameU("ITOF12"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_ITOF15, dNameU("ITOF15"); dCP2128f(_Ft_); dCP2128f(_Fs_);) \ +MakeDisF(dis##VU##MI_CLIP, dNameU("CLIP"); dCP2128f(_Fs_); dCP232w(_Ft_);) \ + diff --git a/pcsx2/Decode_XA.cpp b/pcsx2/Decode_XA.cpp index 59bbb6faf0..51de78a58e 100644 --- a/pcsx2/Decode_XA.cpp +++ b/pcsx2/Decode_XA.cpp @@ -1,322 +1,322 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -//============================================ -//=== Audio XA decoding -//=== Kazzuya -//============================================ -//=== Modified by linuzappz -//============================================ - -#include - -#include "Decode_XA.h" - -#ifdef __WIN32__ -#pragma warning(disable:4244) -#endif - -typedef unsigned char U8; -typedef unsigned short U16; -typedef unsigned long U32; - -#define NOT(_X_) (!(_X_)) -#define CLAMP(_X_,_MI_,_MA_) {if(_X_<_MI_)_X_=_MI_;if(_X_>_MA_)_X_=_MA_;} - -//============================================ -//=== ADPCM DECODING ROUTINES -//============================================ - -static double K0[4] = { - 0.0, - 0.9375, - 1.796875, - 1.53125 -}; - -static double K1[4] = { - 0.0, - 0.0, - -0.8125, - -0.859375 -}; - -#define BLKSIZ 28 /* block size (32 - 4 nibbles) */ - -//=========================================== -void ADPCM_InitDecode( ADPCM_Decode_t *decp ) -{ - decp->y0 = 0; - decp->y1 = 0; -} - -//=========================================== -#define SH 4 -#define SHC 10 - -#define IK0(fid) ((int)((-K0[fid]) * (1<> 4) & 0x0f; - range = (filter_range >> 0) & 0x0f; - - fy0 = decp->y0; - fy1 = decp->y1; - - for (i = BLKSIZ/4; i; --i) { - long y; - long x0, x1, x2, x3; - - y = *blockp++; - x3 = (short)( y & 0xf000) >> range; x3 <<= SH; - x2 = (short)((y << 4) & 0xf000) >> range; x2 <<= SH; - x1 = (short)((y << 8) & 0xf000) >> range; x1 <<= SH; - x0 = (short)((y << 12) & 0xf000) >> range; x0 <<= SH; - - x0 -= (IK0(filterid) * fy0 + (IK1(filterid) * fy1)) >> SHC; fy1 = fy0; fy0 = x0; - x1 -= (IK0(filterid) * fy0 + (IK1(filterid) * fy1)) >> SHC; fy1 = fy0; fy0 = x1; - x2 -= (IK0(filterid) * fy0 + (IK1(filterid) * fy1)) >> SHC; fy1 = fy0; fy0 = x2; - x3 -= (IK0(filterid) * fy0 + (IK1(filterid) * fy1)) >> SHC; fy1 = fy0; fy0 = x3; - - CLAMP( x0, -32768<> SH; destp += inc; - CLAMP( x1, -32768<> SH; destp += inc; - CLAMP( x2, -32768<> SH; destp += inc; - CLAMP( x3, -32768<> SH; destp += inc; - } - decp->y0 = fy0; - decp->y1 = fy1; -} - -static int headtable[4] = {0,2,8,10}; - -//=========================================== -static void xa_decode_data( xa_decode_t *xdp, unsigned char *srcp ) { - const U8 *sound_groupsp; - const U8 *sound_datap, *sound_datap2; - int i, j, k, nbits; - U16 data[4096], *datap; - short *destp; - - destp = xdp->pcm; - nbits = xdp->nbits == 4 ? 4 : 2; - - if (xdp->stereo) { // stereo - for (j=0; j < 18; j++) { - sound_groupsp = srcp + j * 128; // sound groups header - sound_datap = sound_groupsp + 16; // sound data just after the header - - for (i=0; i < nbits; i++) { - datap = data; - sound_datap2 = sound_datap + i; - if ((xdp->nbits == 8) && (xdp->freq == 37800)) { // level A - for (k=0; k < 14; k++, sound_datap2 += 8) { - *(datap++) = (U16)sound_datap2[0] | - (U16)(sound_datap2[4] << 8); - } - } else { // level B/C - for (k=0; k < 7; k++, sound_datap2 += 16) { - *(datap++) = (U16)(sound_datap2[ 0] & 0x0f) | - ((U16)(sound_datap2[ 4] & 0x0f) << 4) | - ((U16)(sound_datap2[ 8] & 0x0f) << 8) | - ((U16)(sound_datap2[12] & 0x0f) << 12); - } - } - ADPCM_DecodeBlock16( &xdp->left, sound_groupsp[headtable[i]+0], data, - destp+0, 2 ); - - datap = data; - sound_datap2 = sound_datap + i; - if ((xdp->nbits == 8) && (xdp->freq == 37800)) { // level A - for (k=0; k < 14; k++, sound_datap2 += 8) { - *(datap++) = (U16)sound_datap2[0] | - (U16)(sound_datap2[4] << 8); - } - } else { // level B/C - for (k=0; k < 7; k++, sound_datap2 += 16) { - *(datap++) = (U16)(sound_datap2[ 0] >> 4) | - ((U16)(sound_datap2[ 4] >> 4) << 4) | - ((U16)(sound_datap2[ 8] >> 4) << 8) | - ((U16)(sound_datap2[12] >> 4) << 12); - } - } - ADPCM_DecodeBlock16( &xdp->right, sound_groupsp[headtable[i]+1], data, - destp+1, 2 ); - - destp += 28*2; - } - } - } - else { // mono - for (j=0; j < 18; j++) { - sound_groupsp = srcp + j * 128; // sound groups header - sound_datap = sound_groupsp + 16; // sound data just after the header - - for (i=0; i < nbits; i++) { - datap = data; - sound_datap2 = sound_datap + i; - if ((xdp->nbits == 8) && (xdp->freq == 37800)) { // level A - for (k=0; k < 14; k++, sound_datap2 += 8) { - *(datap++) = (U16)sound_datap2[0] | - (U16)(sound_datap2[4] << 8); - } - } else { // level B/C - for (k=0; k < 7; k++, sound_datap2 += 16) { - *(datap++) = (U16)(sound_datap2[ 0] & 0x0f) | - ((U16)(sound_datap2[ 4] & 0x0f) << 4) | - ((U16)(sound_datap2[ 8] & 0x0f) << 8) | - ((U16)(sound_datap2[12] & 0x0f) << 12); - } - } - ADPCM_DecodeBlock16( &xdp->left, sound_groupsp[headtable[i]+0], data, - destp, 1 ); - - destp += 28; - - datap = data; - sound_datap2 = sound_datap + i; - if ((xdp->nbits == 8) && (xdp->freq == 37800)) { // level A - for (k=0; k < 14; k++, sound_datap2 += 8) { - *(datap++) = (U16)sound_datap2[0] | - (U16)(sound_datap2[4] << 8); - } - } else { // level B/C - for (k=0; k < 7; k++, sound_datap2 += 16) { - *(datap++) = (U16)(sound_datap2[ 0] >> 4) | - ((U16)(sound_datap2[ 4] >> 4) << 4) | - ((U16)(sound_datap2[ 8] >> 4) << 8) | - ((U16)(sound_datap2[12] >> 4) << 12); - } - } - ADPCM_DecodeBlock16( &xdp->left, sound_groupsp[headtable[i]+1], data, - destp, 1 ); - - destp += 28; - } - } - } -} - -//============================================ -//=== XA SPECIFIC ROUTINES -//============================================ -typedef struct { -U8 filenum; -U8 channum; -U8 submode; -U8 coding; - -U8 filenum2; -U8 channum2; -U8 submode2; -U8 coding2; -} xa_subheader_t; - -#define SUB_SUB_EOF (1<<7) // end of file -#define SUB_SUB_RT (1<<6) // real-time sector -#define SUB_SUB_FORM (1<<5) // 0 form1 1 form2 -#define SUB_SUB_TRIGGER (1<<4) // used for interrupt -#define SUB_SUB_DATA (1<<3) // contains data -#define SUB_SUB_AUDIO (1<<2) // contains audio -#define SUB_SUB_VIDEO (1<<1) // contains video -#define SUB_SUB_EOR (1<<0) // end of record - -#define AUDIO_CODING_GET_STEREO(_X_) ( (_X_) & 3) -#define AUDIO_CODING_GET_FREQ(_X_) (((_X_) >> 2) & 3) -#define AUDIO_CODING_GET_BPS(_X_) (((_X_) >> 4) & 3) -#define AUDIO_CODING_GET_EMPHASIS(_X_) (((_X_) >> 6) & 1) - -#define SUB_UNKNOWN 0 -#define SUB_VIDEO 1 -#define SUB_AUDIO 2 - -//============================================ -static int parse_xa_audio_sector( xa_decode_t *xdp, - xa_subheader_t *subheadp, - unsigned char *sectorp, - int is_first_sector ) { - if ( is_first_sector ) { - switch ( AUDIO_CODING_GET_FREQ(subheadp->coding) ) { - case 0: xdp->freq = 37800; break; - case 1: xdp->freq = 18900; break; - default: xdp->freq = 0; break; - } - switch ( AUDIO_CODING_GET_BPS(subheadp->coding) ) { - case 0: xdp->nbits = 4; break; - case 1: xdp->nbits = 8; break; - default: xdp->nbits = 0; break; - } - switch ( AUDIO_CODING_GET_STEREO(subheadp->coding) ) { - case 0: xdp->stereo = 0; break; - case 1: xdp->stereo = 1; break; - default: xdp->stereo = 0; break; - } - - if ( xdp->freq == 0 ) - return -1; - - ADPCM_InitDecode( &xdp->left ); - ADPCM_InitDecode( &xdp->right ); - - xdp->nsamples = 18 * 28 * 8; - if (xdp->stereo == 1) xdp->nsamples /= 2; - } - xa_decode_data( xdp, sectorp ); - - return 0; -} - -//================================================================ -//=== THIS IS WHAT YOU HAVE TO CALL -//=== xdp - structure were all important data are returned -//=== sectorp - data in input -//=== pcmp - data in output -//=== is_first_sector - 1 if it's the 1st sector of the stream -//=== - 0 for any other successive sector -//=== return -1 if error -//================================================================ -long xa_decode_sector( xa_decode_t *xdp, - unsigned char *sectorp, int is_first_sector ) { - if (parse_xa_audio_sector(xdp, (xa_subheader_t *)sectorp, sectorp + sizeof(xa_subheader_t), is_first_sector)) - return -1; - - return 0; -} - -/* EXAMPLE: -"nsamples" is the number of 16 bit samples -every sample is 2 bytes in mono and 4 bytes in stereo - -xa_decode_t xa; - - sectorp = read_first_sector(); - xa_decode_sector( &xa, sectorp, 1 ); - play_wave( xa.pcm, xa.freq, xa.nsamples ); - - while ( --n_sectors ) - { - sectorp = read_next_sector(); - xa_decode_sector( &xa, sectorp, 0 ); - play_wave( xa.pcm, xa.freq, xa.nsamples ); - } -*/ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +//============================================ +//=== Audio XA decoding +//=== Kazzuya +//============================================ +//=== Modified by linuzappz +//============================================ + +#include + +#include "Decode_XA.h" + +#ifdef __WIN32__ +#pragma warning(disable:4244) +#endif + +typedef unsigned char U8; +typedef unsigned short U16; +typedef unsigned long U32; + +#define NOT(_X_) (!(_X_)) +#define CLAMP(_X_,_MI_,_MA_) {if(_X_<_MI_)_X_=_MI_;if(_X_>_MA_)_X_=_MA_;} + +//============================================ +//=== ADPCM DECODING ROUTINES +//============================================ + +static double K0[4] = { + 0.0, + 0.9375, + 1.796875, + 1.53125 +}; + +static double K1[4] = { + 0.0, + 0.0, + -0.8125, + -0.859375 +}; + +#define BLKSIZ 28 /* block size (32 - 4 nibbles) */ + +//=========================================== +void ADPCM_InitDecode( ADPCM_Decode_t *decp ) +{ + decp->y0 = 0; + decp->y1 = 0; +} + +//=========================================== +#define SH 4 +#define SHC 10 + +#define IK0(fid) ((int)((-K0[fid]) * (1<> 4) & 0x0f; + range = (filter_range >> 0) & 0x0f; + + fy0 = decp->y0; + fy1 = decp->y1; + + for (i = BLKSIZ/4; i; --i) { + long y; + long x0, x1, x2, x3; + + y = *blockp++; + x3 = (short)( y & 0xf000) >> range; x3 <<= SH; + x2 = (short)((y << 4) & 0xf000) >> range; x2 <<= SH; + x1 = (short)((y << 8) & 0xf000) >> range; x1 <<= SH; + x0 = (short)((y << 12) & 0xf000) >> range; x0 <<= SH; + + x0 -= (IK0(filterid) * fy0 + (IK1(filterid) * fy1)) >> SHC; fy1 = fy0; fy0 = x0; + x1 -= (IK0(filterid) * fy0 + (IK1(filterid) * fy1)) >> SHC; fy1 = fy0; fy0 = x1; + x2 -= (IK0(filterid) * fy0 + (IK1(filterid) * fy1)) >> SHC; fy1 = fy0; fy0 = x2; + x3 -= (IK0(filterid) * fy0 + (IK1(filterid) * fy1)) >> SHC; fy1 = fy0; fy0 = x3; + + CLAMP( x0, -32768<> SH; destp += inc; + CLAMP( x1, -32768<> SH; destp += inc; + CLAMP( x2, -32768<> SH; destp += inc; + CLAMP( x3, -32768<> SH; destp += inc; + } + decp->y0 = fy0; + decp->y1 = fy1; +} + +static int headtable[4] = {0,2,8,10}; + +//=========================================== +static void xa_decode_data( xa_decode_t *xdp, unsigned char *srcp ) { + const U8 *sound_groupsp; + const U8 *sound_datap, *sound_datap2; + int i, j, k, nbits; + U16 data[4096], *datap; + short *destp; + + destp = xdp->pcm; + nbits = xdp->nbits == 4 ? 4 : 2; + + if (xdp->stereo) { // stereo + for (j=0; j < 18; j++) { + sound_groupsp = srcp + j * 128; // sound groups header + sound_datap = sound_groupsp + 16; // sound data just after the header + + for (i=0; i < nbits; i++) { + datap = data; + sound_datap2 = sound_datap + i; + if ((xdp->nbits == 8) && (xdp->freq == 37800)) { // level A + for (k=0; k < 14; k++, sound_datap2 += 8) { + *(datap++) = (U16)sound_datap2[0] | + (U16)(sound_datap2[4] << 8); + } + } else { // level B/C + for (k=0; k < 7; k++, sound_datap2 += 16) { + *(datap++) = (U16)(sound_datap2[ 0] & 0x0f) | + ((U16)(sound_datap2[ 4] & 0x0f) << 4) | + ((U16)(sound_datap2[ 8] & 0x0f) << 8) | + ((U16)(sound_datap2[12] & 0x0f) << 12); + } + } + ADPCM_DecodeBlock16( &xdp->left, sound_groupsp[headtable[i]+0], data, + destp+0, 2 ); + + datap = data; + sound_datap2 = sound_datap + i; + if ((xdp->nbits == 8) && (xdp->freq == 37800)) { // level A + for (k=0; k < 14; k++, sound_datap2 += 8) { + *(datap++) = (U16)sound_datap2[0] | + (U16)(sound_datap2[4] << 8); + } + } else { // level B/C + for (k=0; k < 7; k++, sound_datap2 += 16) { + *(datap++) = (U16)(sound_datap2[ 0] >> 4) | + ((U16)(sound_datap2[ 4] >> 4) << 4) | + ((U16)(sound_datap2[ 8] >> 4) << 8) | + ((U16)(sound_datap2[12] >> 4) << 12); + } + } + ADPCM_DecodeBlock16( &xdp->right, sound_groupsp[headtable[i]+1], data, + destp+1, 2 ); + + destp += 28*2; + } + } + } + else { // mono + for (j=0; j < 18; j++) { + sound_groupsp = srcp + j * 128; // sound groups header + sound_datap = sound_groupsp + 16; // sound data just after the header + + for (i=0; i < nbits; i++) { + datap = data; + sound_datap2 = sound_datap + i; + if ((xdp->nbits == 8) && (xdp->freq == 37800)) { // level A + for (k=0; k < 14; k++, sound_datap2 += 8) { + *(datap++) = (U16)sound_datap2[0] | + (U16)(sound_datap2[4] << 8); + } + } else { // level B/C + for (k=0; k < 7; k++, sound_datap2 += 16) { + *(datap++) = (U16)(sound_datap2[ 0] & 0x0f) | + ((U16)(sound_datap2[ 4] & 0x0f) << 4) | + ((U16)(sound_datap2[ 8] & 0x0f) << 8) | + ((U16)(sound_datap2[12] & 0x0f) << 12); + } + } + ADPCM_DecodeBlock16( &xdp->left, sound_groupsp[headtable[i]+0], data, + destp, 1 ); + + destp += 28; + + datap = data; + sound_datap2 = sound_datap + i; + if ((xdp->nbits == 8) && (xdp->freq == 37800)) { // level A + for (k=0; k < 14; k++, sound_datap2 += 8) { + *(datap++) = (U16)sound_datap2[0] | + (U16)(sound_datap2[4] << 8); + } + } else { // level B/C + for (k=0; k < 7; k++, sound_datap2 += 16) { + *(datap++) = (U16)(sound_datap2[ 0] >> 4) | + ((U16)(sound_datap2[ 4] >> 4) << 4) | + ((U16)(sound_datap2[ 8] >> 4) << 8) | + ((U16)(sound_datap2[12] >> 4) << 12); + } + } + ADPCM_DecodeBlock16( &xdp->left, sound_groupsp[headtable[i]+1], data, + destp, 1 ); + + destp += 28; + } + } + } +} + +//============================================ +//=== XA SPECIFIC ROUTINES +//============================================ +typedef struct { +U8 filenum; +U8 channum; +U8 submode; +U8 coding; + +U8 filenum2; +U8 channum2; +U8 submode2; +U8 coding2; +} xa_subheader_t; + +#define SUB_SUB_EOF (1<<7) // end of file +#define SUB_SUB_RT (1<<6) // real-time sector +#define SUB_SUB_FORM (1<<5) // 0 form1 1 form2 +#define SUB_SUB_TRIGGER (1<<4) // used for interrupt +#define SUB_SUB_DATA (1<<3) // contains data +#define SUB_SUB_AUDIO (1<<2) // contains audio +#define SUB_SUB_VIDEO (1<<1) // contains video +#define SUB_SUB_EOR (1<<0) // end of record + +#define AUDIO_CODING_GET_STEREO(_X_) ( (_X_) & 3) +#define AUDIO_CODING_GET_FREQ(_X_) (((_X_) >> 2) & 3) +#define AUDIO_CODING_GET_BPS(_X_) (((_X_) >> 4) & 3) +#define AUDIO_CODING_GET_EMPHASIS(_X_) (((_X_) >> 6) & 1) + +#define SUB_UNKNOWN 0 +#define SUB_VIDEO 1 +#define SUB_AUDIO 2 + +//============================================ +static int parse_xa_audio_sector( xa_decode_t *xdp, + xa_subheader_t *subheadp, + unsigned char *sectorp, + int is_first_sector ) { + if ( is_first_sector ) { + switch ( AUDIO_CODING_GET_FREQ(subheadp->coding) ) { + case 0: xdp->freq = 37800; break; + case 1: xdp->freq = 18900; break; + default: xdp->freq = 0; break; + } + switch ( AUDIO_CODING_GET_BPS(subheadp->coding) ) { + case 0: xdp->nbits = 4; break; + case 1: xdp->nbits = 8; break; + default: xdp->nbits = 0; break; + } + switch ( AUDIO_CODING_GET_STEREO(subheadp->coding) ) { + case 0: xdp->stereo = 0; break; + case 1: xdp->stereo = 1; break; + default: xdp->stereo = 0; break; + } + + if ( xdp->freq == 0 ) + return -1; + + ADPCM_InitDecode( &xdp->left ); + ADPCM_InitDecode( &xdp->right ); + + xdp->nsamples = 18 * 28 * 8; + if (xdp->stereo == 1) xdp->nsamples /= 2; + } + xa_decode_data( xdp, sectorp ); + + return 0; +} + +//================================================================ +//=== THIS IS WHAT YOU HAVE TO CALL +//=== xdp - structure were all important data are returned +//=== sectorp - data in input +//=== pcmp - data in output +//=== is_first_sector - 1 if it's the 1st sector of the stream +//=== - 0 for any other successive sector +//=== return -1 if error +//================================================================ +long xa_decode_sector( xa_decode_t *xdp, + unsigned char *sectorp, int is_first_sector ) { + if (parse_xa_audio_sector(xdp, (xa_subheader_t *)sectorp, sectorp + sizeof(xa_subheader_t), is_first_sector)) + return -1; + + return 0; +} + +/* EXAMPLE: +"nsamples" is the number of 16 bit samples +every sample is 2 bytes in mono and 4 bytes in stereo + +xa_decode_t xa; + + sectorp = read_first_sector(); + xa_decode_sector( &xa, sectorp, 1 ); + play_wave( xa.pcm, xa.freq, xa.nsamples ); + + while ( --n_sectors ) + { + sectorp = read_next_sector(); + xa_decode_sector( &xa, sectorp, 0 ); + play_wave( xa.pcm, xa.freq, xa.nsamples ); + } +*/ diff --git a/pcsx2/Decode_XA.h b/pcsx2/Decode_XA.h index 40262f205d..0aeab19749 100644 --- a/pcsx2/Decode_XA.h +++ b/pcsx2/Decode_XA.h @@ -1,43 +1,43 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -//============================================ -//=== Audio XA decoding -//=== Kazzuya -//============================================ - -#ifndef DECODEXA_H -#define DECODEXA_H - -typedef struct { - long y0, y1; -} ADPCM_Decode_t; - -typedef struct { - int freq; - int nbits; - int stereo; - int nsamples; - ADPCM_Decode_t left, right; - short pcm[16384]; -} xa_decode_t; - -long xa_decode_sector( xa_decode_t *xdp, - unsigned char *sectorp, - int is_first_sector ); - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +//============================================ +//=== Audio XA decoding +//=== Kazzuya +//============================================ + +#ifndef DECODEXA_H +#define DECODEXA_H + +typedef struct { + long y0, y1; +} ADPCM_Decode_t; + +typedef struct { + int freq; + int nbits; + int stereo; + int nsamples; + ADPCM_Decode_t left, right; + short pcm[16384]; +} xa_decode_t; + +long xa_decode_sector( xa_decode_t *xdp, + unsigned char *sectorp, + int is_first_sector ); + +#endif diff --git a/pcsx2/EEregs.h b/pcsx2/EEregs.h index 2af2517334..3059309d1e 100644 --- a/pcsx2/EEregs.h +++ b/pcsx2/EEregs.h @@ -1,40 +1,40 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __EEREGS_H__ -#define __EEREGS_H__ - -#define at cpuRegs.GPR.n.at -#define k0 cpuRegs.GPR.n.k0 -#define k1 cpuRegs.GPR.n.k1 -#define v0 cpuRegs.GPR.n.v0 -#define v1 cpuRegs.GPR.n.v1 -#define a0 cpuRegs.GPR.n.a0 -#define a1 cpuRegs.GPR.n.a1 -#define a2 cpuRegs.GPR.n.a2 -#define a3 cpuRegs.GPR.n.a3 -#define t0 cpuRegs.GPR.n.t0 -#define s0 cpuRegs.GPR.n.s0 -#define gp cpuRegs.GPR.n.gp -#define fp cpuRegs.GPR.n.s8 -#define sp cpuRegs.GPR.n.sp -#define ra cpuRegs.GPR.n.ra - -#define pc0 cpuRegs.pc - -#endif /* __EEREGS_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __EEREGS_H__ +#define __EEREGS_H__ + +#define at cpuRegs.GPR.n.at +#define k0 cpuRegs.GPR.n.k0 +#define k1 cpuRegs.GPR.n.k1 +#define v0 cpuRegs.GPR.n.v0 +#define v1 cpuRegs.GPR.n.v1 +#define a0 cpuRegs.GPR.n.a0 +#define a1 cpuRegs.GPR.n.a1 +#define a2 cpuRegs.GPR.n.a2 +#define a3 cpuRegs.GPR.n.a3 +#define t0 cpuRegs.GPR.n.t0 +#define s0 cpuRegs.GPR.n.s0 +#define gp cpuRegs.GPR.n.gp +#define fp cpuRegs.GPR.n.s8 +#define sp cpuRegs.GPR.n.sp +#define ra cpuRegs.GPR.n.ra + +#define pc0 cpuRegs.pc + +#endif /* __EEREGS_H__ */ diff --git a/pcsx2/Elfheader.cpp b/pcsx2/Elfheader.cpp index 7e718e9868..c26d3b9143 100644 --- a/pcsx2/Elfheader.cpp +++ b/pcsx2/Elfheader.cpp @@ -1,662 +1,662 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "CDVDisodrv.h" - -using namespace std; - -#ifdef _MSC_VER -#pragma warning(disable:4996) //ignore the stricmp deprecated warning -#endif - -u32 ElfCRC; - -struct ELF_HEADER { - u8 e_ident[16]; //0x7f,"ELF" (ELF file identifier) - u16 e_type; //ELF type: 0=NONE, 1=REL, 2=EXEC, 3=SHARED, 4=CORE - u16 e_machine; //Processor: 8=MIPS R3000 - u32 e_version; //Version: 1=current - u32 e_entry; //Entry point address - u32 e_phoff; //Start of program headers (offset from file start) - u32 e_shoff; //Start of section headers (offset from file start) - u32 e_flags; //Processor specific flags = 0x20924001 noreorder, mips - u16 e_ehsize; //ELF header size (0x34 = 52 bytes) - u16 e_phentsize; //Program headers entry size - u16 e_phnum; //Number of program headers - u16 e_shentsize; //Section headers entry size - u16 e_shnum; //Number of section headers - u16 e_shstrndx; //Section header stringtable index -}; - -struct ELF_PHR { - u32 p_type; //see notes1 - u32 p_offset; //Offset from file start to program segment. - u32 p_vaddr; //Virtual address of the segment - u32 p_paddr; //Physical address of the segment - u32 p_filesz; //Number of bytes in the file image of the segment - u32 p_memsz; //Number of bytes in the memory image of the segment - u32 p_flags; //Flags for segment - u32 p_align; //Alignment. The address of 0x08 and 0x0C must fit this alignment. 0=no alignment -}; - -/* -notes1 ------- -0=Inactive -1=Load the segment into memory, no. of bytes specified by 0x10 and 0x14 -2=Dynamic linking -3=Interpreter. The array element must specify a path name -4=Note. The array element must specify the location and size of aux. info -5=reserved -6=The array element must specify location and size of the program header table. -*/ - -struct ELF_SHR { - u32 sh_name; //No. to the index of the Section header stringtable index - u32 sh_type; //See notes2 - u32 sh_flags; //see notes3 - u32 sh_addr; //Section start address - u32 sh_offset; //Offset from start of file to section - u32 sh_size; //Size of section - u32 sh_link; //Section header table index link - u32 sh_info; //Info - u32 sh_addralign; //Alignment. The adress of 0x0C must fit this alignment. 0=no alignment. - u32 sh_entsize; //Fixed size entries. -}; - -/* -notes 2 -------- -Type: -0=Inactive -1=PROGBITS -2=SYMTAB symbol table -3=STRTAB string table -4=RELA relocation entries -5=HASH hash table -6=DYNAMIC dynamic linking information -7=NOTE -8=NOBITS -9=REL relocation entries -10=SHLIB -0x70000000=LOPROC processor specifc -0x7fffffff=HIPROC -0x80000000=LOUSER lower bound -0xffffffff=HIUSER upper bound - -notes 3 -------- -Section Flags: (1 bit, you may combine them like 3 = alloc & write permission) -1=Write section contains data the is be writeable during execution. -2=Alloc section occupies memory during execution -4=Exec section contains executable instructions -0xf0000000=Mask bits processor-specific -*/ - -struct Elf32_Sym { - u32 st_name; - u32 st_value; - u32 st_size; - u8 st_info; - u8 st_other; - u16 st_shndx; -}; - -#define ELF32_ST_TYPE(i) ((i)&0xf) - -struct Elf32_Rel { - u32 r_offset; - u32 r_info; -}; - -//2002-09-19 (Florin) -char args[256]="ez.m2v"; //to be accessed by other files -uptr args_ptr; //a big value; in fact, it is an address - -//in a0 is passed the address of the command line args, -//i.e. a pointer to an area like this: -//+00 unknown/unused -//+04 argc; number of arguments -//+08 argv[0]; address of the first parameter - program name (char*) - -//+08 argv[1]; address of the second parameter (char*) | -//+0C argv[2]; and so on | -//........ | -//+08+4*argc the program name(first param) <-- -//+08+4*argc+strlen(argv[0]+1) the rest of params; i.e. a copy of 'args' -// see above 'char args[256];' -static uint parseCommandLine( const char *filename ) -{ - if ( ( args_ptr != 0xFFFFFFFF ) && ( args_ptr > 264 ) ) - { // 4 + 4 + 256 - const char * p; - int argc; - int i; - - args_ptr -= 256; - - args[ 255 ] = 0; - memcpy( &PS2MEM_BASE[ args_ptr ], args, 256 ); //params 1, 2, etc copied - memset( &PS2MEM_BASE[ args_ptr + strlen( args ) ], 0, 256 - strlen( args ) ); -#ifdef _WIN32 - p = strrchr( filename, '\\' ); -#else //linux - p = strrchr( filename, '/' ); - if( p == NULL ) - p = strchr(filename, '\\'); -#endif - if ( p ) - { - p++; - } - else - { - p = filename; - } - args_ptr -= strlen( p ) + 1; - /* if ( args_ptr < 0 ) // fixme- This is still impossible. - { - return 0; - }*/ - strcpy( (char*)&PS2MEM_BASE[ args_ptr ], p ); //fill param 0; i.e. name of the program - - for ( i = strlen( p ) + 1 + 256, argc = 0; i > 0; i-- ) - { - while ( i && ( ( PS2MEM_BASE[ args_ptr + i ] == 0 ) || ( PS2MEM_BASE[ args_ptr + i ] == 32 ) ) ) - { - i--; - } - if ( PS2MEM_BASE[ args_ptr + i + 1 ] == ' ' ) - { - PS2MEM_BASE[ args_ptr + i + 1 ] = 0; - } - while ( i && ( PS2MEM_BASE[ args_ptr + i ] != 0 ) && ( PS2MEM_BASE[ args_ptr + i] != 32 ) ) - { - i--; - } - if ( ( PS2MEM_BASE[ args_ptr + i ] != 0 ) && ( PS2MEM_BASE[ args_ptr + i ] != 32 ) ) - { //i==0 - argc++; - if ( args_ptr - 4 - 4 - argc * 4 < 0 ) // fixme - Should this be cast to a signed int? - { - return 0; - } - ((u32*)PS2MEM_BASE)[ args_ptr / 4 - argc ] = args_ptr + i; - } - else - { - if ( ( PS2MEM_BASE[ args_ptr + i + 1 ] != 0 ) && ( PS2MEM_BASE[ args_ptr + i + 1 ] != 32 ) ) - { - argc++; - if ( args_ptr - 4 - 4 - argc * 4 < 0 ) // fixme - Should this be cast to a signed int? - { - return 0; - } - ((u32*)PS2MEM_BASE)[ args_ptr / 4 - argc ] = args_ptr + i + 1; - } - } - } - ((u32*)PS2MEM_BASE)[ args_ptr /4 - argc - 1 ] = argc; //how many args - ((u32*)PS2MEM_BASE)[ args_ptr /4 - argc - 2 ] = ( argc > 0); //have args? //not used, cannot be filled at all - - return ( args_ptr - argc * 4 - 8 ); - } - - return 0; -} -//--------------- - -struct ElfObject -{ - string filename; - MemoryAlloc data; - ELF_HEADER& header; - ELF_PHR* proghead; - ELF_SHR* secthead; - - // Destructor! - // C++ does all the cleanup automagically for us. - ~ElfObject() { } - - ElfObject( const string& srcfile, uint hdrsize ) : - filename( srcfile ) - , data( hdrsize, "ELF headers" ) - , header( *(ELF_HEADER*)data.GetPtr() ) - , proghead( NULL ) - , secthead( NULL ) - { - readFile(); - proghead = (ELF_PHR*)&data[header.e_phoff]; - secthead = (ELF_SHR*)&data[header.e_shoff]; - - if ( ( header.e_shnum > 0 ) && ( header.e_shentsize != sizeof(ELF_SHR) ) ) - { - Console::Error( "ElfLoader Warning > Size of section headers is not standard" ); - } - - if ( ( header.e_phnum > 0 ) && ( header.e_phentsize != sizeof(ELF_PHR) ) ) - { - Console::Error( "ElfLoader Warning > Size of program headers is not standard" ); - } - - ELF_LOG( "type: " ); - switch( header.e_type ) - { - default: - ELF_LOG( "unknown %x", header.e_type ); - break; - - case 0x0: - ELF_LOG( "no file type" ); - break; - - case 0x1: - ELF_LOG( "relocatable" ); - break; - - case 0x2: - ELF_LOG( "executable" ); - break; - } - ELF_LOG( "\n" ); - ELF_LOG( "machine: " ); - - switch ( header.e_machine ) - { - default: - ELF_LOG( "unknown" ); - break; - - case 0x8: - ELF_LOG( "mips_rs3000" ); - break; - } - - ELF_LOG("\n"); - ELF_LOG("version: %d\n",header.e_version); - ELF_LOG("entry: %08x\n",header.e_entry); - ELF_LOG("flags: %08x\n",header.e_flags); - ELF_LOG("eh size: %08x\n",header.e_ehsize); - ELF_LOG("ph off: %08x\n",header.e_phoff); - ELF_LOG("ph entsiz: %08x\n",header.e_phentsize); - ELF_LOG("ph num: %08x\n",header.e_phnum); - ELF_LOG("sh off: %08x\n",header.e_shoff); - ELF_LOG("sh entsiz: %08x\n",header.e_shentsize); - ELF_LOG("sh num: %08x\n",header.e_shnum); - ELF_LOG("sh strndx: %08x\n",header.e_shstrndx); - - ELF_LOG("\n"); - } - - void readFile() - { - int rsize = 0; - if ((strnicmp( filename.c_str(), "cdrom0:", strlen("cdromN:")) == 0) || - (strnicmp( filename.c_str(), "cdrom1:", strlen("cdromN:")) == 0)) - { - int fi; - fi = CDVDFS_open(filename.c_str() + strlen("cdromN:"), 1);//RDONLY - if (fi < 0) - throw Exception::FileNotFound( filename ); - CDVDFS_lseek( fi, 0, SEEK_SET ); - rsize = CDVDFS_read( fi, (char*)data.GetPtr(), data.GetSizeInBytes() ); - CDVDFS_close( fi ); - } - else - { - FILE *f; - - f = fopen( filename.c_str(), "rb" ); - if( f == NULL ) - Exception::FileNotFound( filename ); - fseek( f, 0, SEEK_SET ); - rsize = fread( data.GetPtr(), 1, data.GetSizeInBytes(), f ); - fclose( f ); - } - - if( rsize < data.GetSizeInBytes() ) - throw Exception::EndOfStream( filename ); - } - - u32 GetCRC() const - { - u32 CRC = 0; - - const u32* srcdata = (u32*)data.GetPtr(); - for(u32 i=data.GetSizeInBytes()/4; i; --i, ++srcdata) - CRC ^= *srcdata; - - return CRC; - } - - - void loadProgramHeaders() - { - if ( header.e_phnum == 0 ) - return; - - for( int i = 0 ; i < header.e_phnum ; i++ ) - { - ELF_LOG( "Elf32 Program Header\n" ); - ELF_LOG( "type: " ); - - switch ( proghead[ i ].p_type ) { - default: - ELF_LOG( "unknown %x", (int)proghead[ i ].p_type ); - break; - - case 0x1: - { - ELF_LOG("load"); - const uint elfsize = data.GetLength(); - - if (proghead[ i ].p_offset < elfsize) { - int size; - - if ((proghead[ i ].p_filesz + proghead[ i ].p_offset) > elfsize) - size = elfsize - proghead[ i ].p_offset; - else - size = proghead[ i ].p_filesz; - - if( proghead[ i ].p_vaddr != proghead[ i ].p_paddr ) - Console::Notice( "ElfProgram different load addrs: paddr=0x%8.8x, vaddr=0x%8.8x", params - proghead[ i ].p_paddr, proghead[ i ].p_vaddr); - - // used to be paddr - memcpy( - &PS2MEM_BASE[proghead[ i ].p_vaddr & 0x1ffffff], - data.GetPtr(proghead[ i ].p_offset), size - ); - - ELF_LOG("\t*LOADED*"); - } - } - break; - } - - ELF_LOG("\n"); - ELF_LOG("offset: %08x\n",(int)proghead[i].p_offset); - ELF_LOG("vaddr: %08x\n",(int)proghead[i].p_vaddr); - ELF_LOG("paddr: %08x\n",proghead[i].p_paddr); - ELF_LOG("file size: %08x\n",proghead[i].p_filesz); - ELF_LOG("mem size: %08x\n",proghead[i].p_memsz); - ELF_LOG("flags: %08x\n",proghead[i].p_flags); - ELF_LOG("palign: %08x\n",proghead[i].p_align); - ELF_LOG("\n"); - - } - } - - - void loadSectionHeaders() - { - if( header.e_shnum == 0 || header.e_shoff > (u32)data.GetLength() ) - return; - - const u8* sections_names = data.GetPtr( secthead[ header.e_shstrndx ].sh_offset ); - - int i_st = -1; - int i_dt = -1; - - for( int i = 0 ; i < header.e_shnum ; i++ ) - { - ELF_LOG( "Elf32 Section Header [%x] %s", i, §ions_names[ secthead[ i ].sh_name ] ); - - if ( secthead[i].sh_flags & 0x2 ) - args_ptr = min( args_ptr, secthead[ i ].sh_addr & 0x1ffffff ); - -#ifdef PCSX2_DEVBULD - ELF_LOG("\n"); - ELF_LOG("type: "); - - switch ( secthead[ i ].sh_type ) - { - default: - ELF_LOG("unknown %08x",secthead[i].sh_type); - break; - - case 0x0: - ELF_LOG("null"); - break; - - case 0x1: - ELF_LOG("progbits"); - break; - - case 0x2: - ELF_LOG("symtab"); - break; - - case 0x3: - ELF_LOG("strtab"); - break; - - case 0x4: - ELF_LOG("rela"); - break; - - case 0x8: - ELF_LOG("no bits"); - break; - - case 0x9: - ELF_LOG("rel"); - break; - } - - ELF_LOG("\n"); - ELF_LOG("flags: %08x\n", secthead[i].sh_flags); - ELF_LOG("addr: %08x\n", secthead[i].sh_addr); - ELF_LOG("offset: %08x\n", secthead[i].sh_offset); - ELF_LOG("size: %08x\n", secthead[i].sh_size); - ELF_LOG("link: %08x\n", secthead[i].sh_link); - ELF_LOG("info: %08x\n", secthead[i].sh_info); - ELF_LOG("addralign: %08x\n", secthead[i].sh_addralign); - ELF_LOG("entsize: %08x\n", secthead[i].sh_entsize); - // dump symbol table - - if( secthead[ i ].sh_type == 0x02 ) - { - i_st = i; - i_dt = secthead[i].sh_link; - } -#endif - } - - if( ( i_st >= 0 ) && ( i_dt >= 0 ) ) - { - const char * SymNames; - Elf32_Sym * eS; - - SymNames = (char*)data.GetPtr( secthead[ i_dt ].sh_offset ); - eS = (Elf32_Sym*)data.GetPtr( secthead[ i_st ].sh_offset ); - Console::WriteLn("found %d symbols", params secthead[ i_st ].sh_size / sizeof( Elf32_Sym )); - - for( uint i = 1; i < ( secthead[ i_st ].sh_size / sizeof( Elf32_Sym ) ); i++ ) { - if ( ( eS[ i ].st_value != 0 ) && ( ELF32_ST_TYPE( eS[ i ].st_info ) == 2 ) ) { - R5900::disR5900AddSym( eS[i].st_value, &SymNames[ eS[ i ].st_name ] ); - } - } - } - } -}; - -void ElfApplyPatches() -{ - string filename; - ssprintf( filename, "%8.8x", ElfCRC ); - - // if patches found the following status msg will be overwritten - Console::SetTitle( fmt_string( "Game running [CRC=%hs]", &filename ) ); - - if( !Config.Patch ) return; - - if(LoadPatch( filename ) != 0) - { - Console::WriteLn("XML Loader returned an error. Trying to load a pnach..."); - inifile_read( filename.c_str() ); - } - else - Console::WriteLn("XML Loading success. Will not load from pnach..."); - - applypatch( 0 ); -} - -// Fetches the CRC of the game bound to the CDVD plugin. -u32 loadElfCRC( const char* filename ) -{ - TocEntry toc; - - CDVDFS_init( ); - if ( CDVD_findfile( filename + strlen( "cdromN:" ), &toc ) == -1 ) - return 0; - - DevCon::Status( "loadElfFile: %d bytes", params toc.fileSize ); - u32 crcval = ElfObject( filename, toc.fileSize ).GetCRC(); - Console::Status( "loadElfFile: %s; CRC = %8.8X", params filename, crcval ); - - return crcval; -} - -int loadElfFile(const char *filename) -{ - // Reset all recompilers prior to initiating a BIOS or new ELF. The cleaner the - // slate, the happier the recompiler! - - SysResetExecutionState(); - - if( filename == NULL || filename[0] == 0 ) - { - Console::Notice( "Running the PS2 BIOS..." ); - return -1; - } - - // We still need to run the BIOS stub, so that all the EE hardware gets initialized correctly. - cpuExecuteBios(); - - int elfsize; - - Console::Status("loadElfFile: %s", params filename); - if (strnicmp( filename, "cdrom0:", strlen( "cdromN:" ) ) && - strnicmp( filename, "cdrom1:", strlen( "cdromN:" ) ) ) - { - // Loading from a file (or non-cd image) - struct stat sbuf; - if ( stat( filename, &sbuf ) != 0 ) - return -1; - elfsize = sbuf.st_size; - } - else - { - // Loading from a CD rom or CD image. - TocEntry toc; - CDVDFS_init( ); - if ( CDVD_findfile( filename + strlen( "cdromN:" ), &toc ) == -1 ) - return -1; - elfsize = toc.fileSize; - } - - Console::Status( "loadElfFile: %d", params elfsize); - ElfObject elfobj( filename, elfsize ); - - //2002-09-19 (Florin) - args_ptr = 0xFFFFFFFF; //big value, searching for minimum - - elfobj.loadProgramHeaders(); - elfobj.loadSectionHeaders(); - - cpuRegs.pc = elfobj.header.e_entry; //set pc to proper place - ELF_LOG( "PC set to: %8.8lx\n", cpuRegs.pc ); - - cpuRegs.GPR.n.sp.UL[0] = 0x81f00000; - cpuRegs.GPR.n.gp.UL[0] = 0x81f80000; // might not be 100% ok - cpuRegs.GPR.n.a0.UL[0] = parseCommandLine( filename ); - - for ( uint i = 0; i < 0x100000; i++ ) { - if ( strcmp( "rom0:OSDSYS", (char*)PSM( i ) ) == 0 ) { - strcpy( (char*)PSM( i ), filename ); - DevCon::Status( "addr %x \"%s\" -> \"%s\"", params i, "rom0:OSDSYS", filename ); - } - } - - ElfCRC = elfobj.GetCRC(); - Console::Status( "loadElfFile: %s; CRC = %8.8X\n", params filename, ElfCRC); - - ElfApplyPatches(); - LoadGameSpecificSettings(); - return 0; -} - -#include "VU.h" -extern int g_FFXHack; -extern int path3hack; -int g_VUGameFixes = 0; - -// fixme - this should be moved to patches or eliminated -void LoadGameSpecificSettings() -{ - // default - g_VUGameFixes = 0; - g_FFXHack = 0; - - switch(ElfCRC) { - // The code involving VUFIX_SIGNEDZERO & VUFIX_EXTRAFLAGS - // is no longer in pcsx2. - - //case 0x0c414549: // spacefisherman, missing gfx - // g_VUGameFixes |= VUFIX_SIGNEDZERO; - // break; - //case 0x4C9EE7DF: // crazy taxi (u) - //case 0xC9C145BF: // crazy taxi, missing gfx - // g_VUGameFixes |= VUFIX_EXTRAFLAGS; - // break; - - case 0xb99379b7: // erementar gerad (discolored chars) - g_VUGameFixes |= VUFIX_XGKICKDELAY2; // Tested - still needed - arcum42 - break; - case 0xa08c4057: //Sprint Cars (SLUS) - case 0x8b0725d5: //Flinstones Bedrock Racing (SLES) - path3hack = 1; // We can move this to patch files right now - break; - - case 0x6a4efe60: // ffx(j) - case 0xA39517AB: // ffx(e) - case 0xBB3D833A: // ffx(u) - case 0x941bb7d9: // ffx(g) - case 0xD9FC6310: // ffx int(j) - case 0xa39517ae: // ffx(f) - case 0xa39517a9: // ffx(i) - case 0x658597e2: // ffx int - case 0x941BB7DE: // ffx(s) - case 0x3866CA7E: // ffx(asia) - case 0x48FE0C71: // ffx2 (u) - case 0x9aac530d: // ffx2 (g) - case 0x9AAC5309: // ffx2 (e) - case 0x8A6D7F14: // ffx2 (j) - case 0x9AAC530B: // ffx2 (i) - case 0x9AAC530A: // ffx2 (f) - case 0xe1fd9a2d: // ffx2 last mission (?) - case 0x93f9b89a: // ffx2 demo (g) - case 0x304C115C: // harvest moon - awl - case 0xF0A6D880: // harvest moon - sth - g_FFXHack = 1; - break; - } -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "CDVDisodrv.h" + +using namespace std; + +#ifdef _MSC_VER +#pragma warning(disable:4996) //ignore the stricmp deprecated warning +#endif + +u32 ElfCRC; + +struct ELF_HEADER { + u8 e_ident[16]; //0x7f,"ELF" (ELF file identifier) + u16 e_type; //ELF type: 0=NONE, 1=REL, 2=EXEC, 3=SHARED, 4=CORE + u16 e_machine; //Processor: 8=MIPS R3000 + u32 e_version; //Version: 1=current + u32 e_entry; //Entry point address + u32 e_phoff; //Start of program headers (offset from file start) + u32 e_shoff; //Start of section headers (offset from file start) + u32 e_flags; //Processor specific flags = 0x20924001 noreorder, mips + u16 e_ehsize; //ELF header size (0x34 = 52 bytes) + u16 e_phentsize; //Program headers entry size + u16 e_phnum; //Number of program headers + u16 e_shentsize; //Section headers entry size + u16 e_shnum; //Number of section headers + u16 e_shstrndx; //Section header stringtable index +}; + +struct ELF_PHR { + u32 p_type; //see notes1 + u32 p_offset; //Offset from file start to program segment. + u32 p_vaddr; //Virtual address of the segment + u32 p_paddr; //Physical address of the segment + u32 p_filesz; //Number of bytes in the file image of the segment + u32 p_memsz; //Number of bytes in the memory image of the segment + u32 p_flags; //Flags for segment + u32 p_align; //Alignment. The address of 0x08 and 0x0C must fit this alignment. 0=no alignment +}; + +/* +notes1 +------ +0=Inactive +1=Load the segment into memory, no. of bytes specified by 0x10 and 0x14 +2=Dynamic linking +3=Interpreter. The array element must specify a path name +4=Note. The array element must specify the location and size of aux. info +5=reserved +6=The array element must specify location and size of the program header table. +*/ + +struct ELF_SHR { + u32 sh_name; //No. to the index of the Section header stringtable index + u32 sh_type; //See notes2 + u32 sh_flags; //see notes3 + u32 sh_addr; //Section start address + u32 sh_offset; //Offset from start of file to section + u32 sh_size; //Size of section + u32 sh_link; //Section header table index link + u32 sh_info; //Info + u32 sh_addralign; //Alignment. The adress of 0x0C must fit this alignment. 0=no alignment. + u32 sh_entsize; //Fixed size entries. +}; + +/* +notes 2 +------- +Type: +0=Inactive +1=PROGBITS +2=SYMTAB symbol table +3=STRTAB string table +4=RELA relocation entries +5=HASH hash table +6=DYNAMIC dynamic linking information +7=NOTE +8=NOBITS +9=REL relocation entries +10=SHLIB +0x70000000=LOPROC processor specifc +0x7fffffff=HIPROC +0x80000000=LOUSER lower bound +0xffffffff=HIUSER upper bound + +notes 3 +------- +Section Flags: (1 bit, you may combine them like 3 = alloc & write permission) +1=Write section contains data the is be writeable during execution. +2=Alloc section occupies memory during execution +4=Exec section contains executable instructions +0xf0000000=Mask bits processor-specific +*/ + +struct Elf32_Sym { + u32 st_name; + u32 st_value; + u32 st_size; + u8 st_info; + u8 st_other; + u16 st_shndx; +}; + +#define ELF32_ST_TYPE(i) ((i)&0xf) + +struct Elf32_Rel { + u32 r_offset; + u32 r_info; +}; + +//2002-09-19 (Florin) +char args[256]="ez.m2v"; //to be accessed by other files +uptr args_ptr; //a big value; in fact, it is an address + +//in a0 is passed the address of the command line args, +//i.e. a pointer to an area like this: +//+00 unknown/unused +//+04 argc; number of arguments +//+08 argv[0]; address of the first parameter - program name (char*) - +//+08 argv[1]; address of the second parameter (char*) | +//+0C argv[2]; and so on | +//........ | +//+08+4*argc the program name(first param) <-- +//+08+4*argc+strlen(argv[0]+1) the rest of params; i.e. a copy of 'args' +// see above 'char args[256];' +static uint parseCommandLine( const char *filename ) +{ + if ( ( args_ptr != 0xFFFFFFFF ) && ( args_ptr > 264 ) ) + { // 4 + 4 + 256 + const char * p; + int argc; + int i; + + args_ptr -= 256; + + args[ 255 ] = 0; + memcpy( &PS2MEM_BASE[ args_ptr ], args, 256 ); //params 1, 2, etc copied + memset( &PS2MEM_BASE[ args_ptr + strlen( args ) ], 0, 256 - strlen( args ) ); +#ifdef _WIN32 + p = strrchr( filename, '\\' ); +#else //linux + p = strrchr( filename, '/' ); + if( p == NULL ) + p = strchr(filename, '\\'); +#endif + if ( p ) + { + p++; + } + else + { + p = filename; + } + args_ptr -= strlen( p ) + 1; + /* if ( args_ptr < 0 ) // fixme- This is still impossible. + { + return 0; + }*/ + strcpy( (char*)&PS2MEM_BASE[ args_ptr ], p ); //fill param 0; i.e. name of the program + + for ( i = strlen( p ) + 1 + 256, argc = 0; i > 0; i-- ) + { + while ( i && ( ( PS2MEM_BASE[ args_ptr + i ] == 0 ) || ( PS2MEM_BASE[ args_ptr + i ] == 32 ) ) ) + { + i--; + } + if ( PS2MEM_BASE[ args_ptr + i + 1 ] == ' ' ) + { + PS2MEM_BASE[ args_ptr + i + 1 ] = 0; + } + while ( i && ( PS2MEM_BASE[ args_ptr + i ] != 0 ) && ( PS2MEM_BASE[ args_ptr + i] != 32 ) ) + { + i--; + } + if ( ( PS2MEM_BASE[ args_ptr + i ] != 0 ) && ( PS2MEM_BASE[ args_ptr + i ] != 32 ) ) + { //i==0 + argc++; + if ( args_ptr - 4 - 4 - argc * 4 < 0 ) // fixme - Should this be cast to a signed int? + { + return 0; + } + ((u32*)PS2MEM_BASE)[ args_ptr / 4 - argc ] = args_ptr + i; + } + else + { + if ( ( PS2MEM_BASE[ args_ptr + i + 1 ] != 0 ) && ( PS2MEM_BASE[ args_ptr + i + 1 ] != 32 ) ) + { + argc++; + if ( args_ptr - 4 - 4 - argc * 4 < 0 ) // fixme - Should this be cast to a signed int? + { + return 0; + } + ((u32*)PS2MEM_BASE)[ args_ptr / 4 - argc ] = args_ptr + i + 1; + } + } + } + ((u32*)PS2MEM_BASE)[ args_ptr /4 - argc - 1 ] = argc; //how many args + ((u32*)PS2MEM_BASE)[ args_ptr /4 - argc - 2 ] = ( argc > 0); //have args? //not used, cannot be filled at all + + return ( args_ptr - argc * 4 - 8 ); + } + + return 0; +} +//--------------- + +struct ElfObject +{ + string filename; + MemoryAlloc data; + ELF_HEADER& header; + ELF_PHR* proghead; + ELF_SHR* secthead; + + // Destructor! + // C++ does all the cleanup automagically for us. + ~ElfObject() { } + + ElfObject( const string& srcfile, uint hdrsize ) : + filename( srcfile ) + , data( hdrsize, "ELF headers" ) + , header( *(ELF_HEADER*)data.GetPtr() ) + , proghead( NULL ) + , secthead( NULL ) + { + readFile(); + proghead = (ELF_PHR*)&data[header.e_phoff]; + secthead = (ELF_SHR*)&data[header.e_shoff]; + + if ( ( header.e_shnum > 0 ) && ( header.e_shentsize != sizeof(ELF_SHR) ) ) + { + Console::Error( "ElfLoader Warning > Size of section headers is not standard" ); + } + + if ( ( header.e_phnum > 0 ) && ( header.e_phentsize != sizeof(ELF_PHR) ) ) + { + Console::Error( "ElfLoader Warning > Size of program headers is not standard" ); + } + + ELF_LOG( "type: " ); + switch( header.e_type ) + { + default: + ELF_LOG( "unknown %x", header.e_type ); + break; + + case 0x0: + ELF_LOG( "no file type" ); + break; + + case 0x1: + ELF_LOG( "relocatable" ); + break; + + case 0x2: + ELF_LOG( "executable" ); + break; + } + ELF_LOG( "\n" ); + ELF_LOG( "machine: " ); + + switch ( header.e_machine ) + { + default: + ELF_LOG( "unknown" ); + break; + + case 0x8: + ELF_LOG( "mips_rs3000" ); + break; + } + + ELF_LOG("\n"); + ELF_LOG("version: %d\n",header.e_version); + ELF_LOG("entry: %08x\n",header.e_entry); + ELF_LOG("flags: %08x\n",header.e_flags); + ELF_LOG("eh size: %08x\n",header.e_ehsize); + ELF_LOG("ph off: %08x\n",header.e_phoff); + ELF_LOG("ph entsiz: %08x\n",header.e_phentsize); + ELF_LOG("ph num: %08x\n",header.e_phnum); + ELF_LOG("sh off: %08x\n",header.e_shoff); + ELF_LOG("sh entsiz: %08x\n",header.e_shentsize); + ELF_LOG("sh num: %08x\n",header.e_shnum); + ELF_LOG("sh strndx: %08x\n",header.e_shstrndx); + + ELF_LOG("\n"); + } + + void readFile() + { + int rsize = 0; + if ((strnicmp( filename.c_str(), "cdrom0:", strlen("cdromN:")) == 0) || + (strnicmp( filename.c_str(), "cdrom1:", strlen("cdromN:")) == 0)) + { + int fi; + fi = CDVDFS_open(filename.c_str() + strlen("cdromN:"), 1);//RDONLY + if (fi < 0) + throw Exception::FileNotFound( filename ); + CDVDFS_lseek( fi, 0, SEEK_SET ); + rsize = CDVDFS_read( fi, (char*)data.GetPtr(), data.GetSizeInBytes() ); + CDVDFS_close( fi ); + } + else + { + FILE *f; + + f = fopen( filename.c_str(), "rb" ); + if( f == NULL ) + Exception::FileNotFound( filename ); + fseek( f, 0, SEEK_SET ); + rsize = fread( data.GetPtr(), 1, data.GetSizeInBytes(), f ); + fclose( f ); + } + + if( rsize < data.GetSizeInBytes() ) + throw Exception::EndOfStream( filename ); + } + + u32 GetCRC() const + { + u32 CRC = 0; + + const u32* srcdata = (u32*)data.GetPtr(); + for(u32 i=data.GetSizeInBytes()/4; i; --i, ++srcdata) + CRC ^= *srcdata; + + return CRC; + } + + + void loadProgramHeaders() + { + if ( header.e_phnum == 0 ) + return; + + for( int i = 0 ; i < header.e_phnum ; i++ ) + { + ELF_LOG( "Elf32 Program Header\n" ); + ELF_LOG( "type: " ); + + switch ( proghead[ i ].p_type ) { + default: + ELF_LOG( "unknown %x", (int)proghead[ i ].p_type ); + break; + + case 0x1: + { + ELF_LOG("load"); + const uint elfsize = data.GetLength(); + + if (proghead[ i ].p_offset < elfsize) { + int size; + + if ((proghead[ i ].p_filesz + proghead[ i ].p_offset) > elfsize) + size = elfsize - proghead[ i ].p_offset; + else + size = proghead[ i ].p_filesz; + + if( proghead[ i ].p_vaddr != proghead[ i ].p_paddr ) + Console::Notice( "ElfProgram different load addrs: paddr=0x%8.8x, vaddr=0x%8.8x", params + proghead[ i ].p_paddr, proghead[ i ].p_vaddr); + + // used to be paddr + memcpy( + &PS2MEM_BASE[proghead[ i ].p_vaddr & 0x1ffffff], + data.GetPtr(proghead[ i ].p_offset), size + ); + + ELF_LOG("\t*LOADED*"); + } + } + break; + } + + ELF_LOG("\n"); + ELF_LOG("offset: %08x\n",(int)proghead[i].p_offset); + ELF_LOG("vaddr: %08x\n",(int)proghead[i].p_vaddr); + ELF_LOG("paddr: %08x\n",proghead[i].p_paddr); + ELF_LOG("file size: %08x\n",proghead[i].p_filesz); + ELF_LOG("mem size: %08x\n",proghead[i].p_memsz); + ELF_LOG("flags: %08x\n",proghead[i].p_flags); + ELF_LOG("palign: %08x\n",proghead[i].p_align); + ELF_LOG("\n"); + + } + } + + + void loadSectionHeaders() + { + if( header.e_shnum == 0 || header.e_shoff > (u32)data.GetLength() ) + return; + + const u8* sections_names = data.GetPtr( secthead[ header.e_shstrndx ].sh_offset ); + + int i_st = -1; + int i_dt = -1; + + for( int i = 0 ; i < header.e_shnum ; i++ ) + { + ELF_LOG( "Elf32 Section Header [%x] %s", i, §ions_names[ secthead[ i ].sh_name ] ); + + if ( secthead[i].sh_flags & 0x2 ) + args_ptr = min( args_ptr, secthead[ i ].sh_addr & 0x1ffffff ); + +#ifdef PCSX2_DEVBULD + ELF_LOG("\n"); + ELF_LOG("type: "); + + switch ( secthead[ i ].sh_type ) + { + default: + ELF_LOG("unknown %08x",secthead[i].sh_type); + break; + + case 0x0: + ELF_LOG("null"); + break; + + case 0x1: + ELF_LOG("progbits"); + break; + + case 0x2: + ELF_LOG("symtab"); + break; + + case 0x3: + ELF_LOG("strtab"); + break; + + case 0x4: + ELF_LOG("rela"); + break; + + case 0x8: + ELF_LOG("no bits"); + break; + + case 0x9: + ELF_LOG("rel"); + break; + } + + ELF_LOG("\n"); + ELF_LOG("flags: %08x\n", secthead[i].sh_flags); + ELF_LOG("addr: %08x\n", secthead[i].sh_addr); + ELF_LOG("offset: %08x\n", secthead[i].sh_offset); + ELF_LOG("size: %08x\n", secthead[i].sh_size); + ELF_LOG("link: %08x\n", secthead[i].sh_link); + ELF_LOG("info: %08x\n", secthead[i].sh_info); + ELF_LOG("addralign: %08x\n", secthead[i].sh_addralign); + ELF_LOG("entsize: %08x\n", secthead[i].sh_entsize); + // dump symbol table + + if( secthead[ i ].sh_type == 0x02 ) + { + i_st = i; + i_dt = secthead[i].sh_link; + } +#endif + } + + if( ( i_st >= 0 ) && ( i_dt >= 0 ) ) + { + const char * SymNames; + Elf32_Sym * eS; + + SymNames = (char*)data.GetPtr( secthead[ i_dt ].sh_offset ); + eS = (Elf32_Sym*)data.GetPtr( secthead[ i_st ].sh_offset ); + Console::WriteLn("found %d symbols", params secthead[ i_st ].sh_size / sizeof( Elf32_Sym )); + + for( uint i = 1; i < ( secthead[ i_st ].sh_size / sizeof( Elf32_Sym ) ); i++ ) { + if ( ( eS[ i ].st_value != 0 ) && ( ELF32_ST_TYPE( eS[ i ].st_info ) == 2 ) ) { + R5900::disR5900AddSym( eS[i].st_value, &SymNames[ eS[ i ].st_name ] ); + } + } + } + } +}; + +void ElfApplyPatches() +{ + string filename; + ssprintf( filename, "%8.8x", ElfCRC ); + + // if patches found the following status msg will be overwritten + Console::SetTitle( fmt_string( "Game running [CRC=%hs]", &filename ) ); + + if( !Config.Patch ) return; + + if(LoadPatch( filename ) != 0) + { + Console::WriteLn("XML Loader returned an error. Trying to load a pnach..."); + inifile_read( filename.c_str() ); + } + else + Console::WriteLn("XML Loading success. Will not load from pnach..."); + + applypatch( 0 ); +} + +// Fetches the CRC of the game bound to the CDVD plugin. +u32 loadElfCRC( const char* filename ) +{ + TocEntry toc; + + CDVDFS_init( ); + if ( CDVD_findfile( filename + strlen( "cdromN:" ), &toc ) == -1 ) + return 0; + + DevCon::Status( "loadElfFile: %d bytes", params toc.fileSize ); + u32 crcval = ElfObject( filename, toc.fileSize ).GetCRC(); + Console::Status( "loadElfFile: %s; CRC = %8.8X", params filename, crcval ); + + return crcval; +} + +int loadElfFile(const char *filename) +{ + // Reset all recompilers prior to initiating a BIOS or new ELF. The cleaner the + // slate, the happier the recompiler! + + SysResetExecutionState(); + + if( filename == NULL || filename[0] == 0 ) + { + Console::Notice( "Running the PS2 BIOS..." ); + return -1; + } + + // We still need to run the BIOS stub, so that all the EE hardware gets initialized correctly. + cpuExecuteBios(); + + int elfsize; + + Console::Status("loadElfFile: %s", params filename); + if (strnicmp( filename, "cdrom0:", strlen( "cdromN:" ) ) && + strnicmp( filename, "cdrom1:", strlen( "cdromN:" ) ) ) + { + // Loading from a file (or non-cd image) + struct stat sbuf; + if ( stat( filename, &sbuf ) != 0 ) + return -1; + elfsize = sbuf.st_size; + } + else + { + // Loading from a CD rom or CD image. + TocEntry toc; + CDVDFS_init( ); + if ( CDVD_findfile( filename + strlen( "cdromN:" ), &toc ) == -1 ) + return -1; + elfsize = toc.fileSize; + } + + Console::Status( "loadElfFile: %d", params elfsize); + ElfObject elfobj( filename, elfsize ); + + //2002-09-19 (Florin) + args_ptr = 0xFFFFFFFF; //big value, searching for minimum + + elfobj.loadProgramHeaders(); + elfobj.loadSectionHeaders(); + + cpuRegs.pc = elfobj.header.e_entry; //set pc to proper place + ELF_LOG( "PC set to: %8.8lx\n", cpuRegs.pc ); + + cpuRegs.GPR.n.sp.UL[0] = 0x81f00000; + cpuRegs.GPR.n.gp.UL[0] = 0x81f80000; // might not be 100% ok + cpuRegs.GPR.n.a0.UL[0] = parseCommandLine( filename ); + + for ( uint i = 0; i < 0x100000; i++ ) { + if ( strcmp( "rom0:OSDSYS", (char*)PSM( i ) ) == 0 ) { + strcpy( (char*)PSM( i ), filename ); + DevCon::Status( "addr %x \"%s\" -> \"%s\"", params i, "rom0:OSDSYS", filename ); + } + } + + ElfCRC = elfobj.GetCRC(); + Console::Status( "loadElfFile: %s; CRC = %8.8X\n", params filename, ElfCRC); + + ElfApplyPatches(); + LoadGameSpecificSettings(); + return 0; +} + +#include "VU.h" +extern int g_FFXHack; +extern int path3hack; +int g_VUGameFixes = 0; + +// fixme - this should be moved to patches or eliminated +void LoadGameSpecificSettings() +{ + // default + g_VUGameFixes = 0; + g_FFXHack = 0; + + switch(ElfCRC) { + // The code involving VUFIX_SIGNEDZERO & VUFIX_EXTRAFLAGS + // is no longer in pcsx2. + + //case 0x0c414549: // spacefisherman, missing gfx + // g_VUGameFixes |= VUFIX_SIGNEDZERO; + // break; + //case 0x4C9EE7DF: // crazy taxi (u) + //case 0xC9C145BF: // crazy taxi, missing gfx + // g_VUGameFixes |= VUFIX_EXTRAFLAGS; + // break; + + case 0xb99379b7: // erementar gerad (discolored chars) + g_VUGameFixes |= VUFIX_XGKICKDELAY2; // Tested - still needed - arcum42 + break; + case 0xa08c4057: //Sprint Cars (SLUS) + case 0x8b0725d5: //Flinstones Bedrock Racing (SLES) + path3hack = 1; // We can move this to patch files right now + break; + + case 0x6a4efe60: // ffx(j) + case 0xA39517AB: // ffx(e) + case 0xBB3D833A: // ffx(u) + case 0x941bb7d9: // ffx(g) + case 0xD9FC6310: // ffx int(j) + case 0xa39517ae: // ffx(f) + case 0xa39517a9: // ffx(i) + case 0x658597e2: // ffx int + case 0x941BB7DE: // ffx(s) + case 0x3866CA7E: // ffx(asia) + case 0x48FE0C71: // ffx2 (u) + case 0x9aac530d: // ffx2 (g) + case 0x9AAC5309: // ffx2 (e) + case 0x8A6D7F14: // ffx2 (j) + case 0x9AAC530B: // ffx2 (i) + case 0x9AAC530A: // ffx2 (f) + case 0xe1fd9a2d: // ffx2 last mission (?) + case 0x93f9b89a: // ffx2 demo (g) + case 0x304C115C: // harvest moon - awl + case 0xF0A6D880: // harvest moon - sth + g_FFXHack = 1; + break; + } +} diff --git a/pcsx2/Elfheader.h b/pcsx2/Elfheader.h index a3514fa333..35a9c036fa 100644 --- a/pcsx2/Elfheader.h +++ b/pcsx2/Elfheader.h @@ -1,34 +1,34 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __ELF_H__ -#define __ELF_H__ - -//2002-09-20 (Florin) -extern char args[256]; //to be filled by GUI -extern unsigned int args_ptr; - -//------------------- -int loadElfFile(const char *filename); -u32 loadElfCRC(const char *filename); -void LoadGameSpecificSettings(); -void ElfApplyPatches(); - -extern u32 ElfCRC; - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __ELF_H__ +#define __ELF_H__ + +//2002-09-20 (Florin) +extern char args[256]; //to be filled by GUI +extern unsigned int args_ptr; + +//------------------- +int loadElfFile(const char *filename); +u32 loadElfCRC(const char *filename); +void LoadGameSpecificSettings(); +void ElfApplyPatches(); + +extern u32 ElfCRC; + +#endif diff --git a/pcsx2/Exceptions.h b/pcsx2/Exceptions.h index 4c92d5780f..452d498cfb 100644 --- a/pcsx2/Exceptions.h +++ b/pcsx2/Exceptions.h @@ -1,349 +1,349 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef _PCSX2_EXCEPTIONS_H_ -#define _PCSX2_EXCEPTIONS_H_ - -#include -#include "StringUtils.h" - -// This class provides an easy and clean method for ensuring objects are not copyable. -class NoncopyableObject -{ -protected: - NoncopyableObject() {} - ~NoncopyableObject() {} - -// Programmer's note: -// No need to provide implementations for these methods since they should -// never be referenced anyway. No references? No Linker Errors! Noncopyable! -private: - // Copy me? I think not! - explicit NoncopyableObject( const NoncopyableObject& ); - // Assign me? I think not! - const NoncopyableObject& operator=( const NoncopyableObject& ); -}; - - -// Base class used to implement type-safe sealed classes. -// This class should never be used directly. Use the Sealed -// macro instead, which ensures all sealed classes derive from a unique BaseSealed -// (preventing them from accidentally cirumventing sealing by inheriting from -// multiple sealed classes. -template < int T > -class __BaseSealed -{ -protected: - __BaseSealed() - { - } -}; - -// Use this macro/class as a base to seal a class from being derrived from. -// This macro works by providing a unique base class with a protected constructor -// for every class that derives from it. -#define Sealed private virtual __BaseSealed<__COUNTER__> - -namespace Exception -{ - // std::exception sucks, so I made a replacement. - // Note, this class is "abstract" which means you shouldn't use it directly like, ever. - // Use Exception::RuntimeError or Exception::LogicError instead. - class BaseException - { - protected: - const std::string m_message; // a "detailed" message of what disasterous thing has occured! - - public: - virtual ~BaseException() throw()=0; // the =0; syntax forces this class into "abstract" mode. - explicit BaseException( const std::string& msg="Unhandled exception." ) : - m_message( msg ) - {} - - const std::string& Message() const { return m_message; } - const char* cMessage() const { return m_message.c_str(); } - }; - - class RuntimeError : public BaseException - { - public: - virtual ~RuntimeError() throw() {} - explicit RuntimeError( const std::string& msg="An unhandled runtime error has occurred, somewhere in the depths of Pcsx2's cluttered brain-matter." ) : - BaseException( msg ) - {} - }; - - class LogicError : public BaseException - { - public: - virtual ~LogicError() throw() {} - explicit LogicError( const std::string& msg="An unhandled logic error has occured." ) : - BaseException( msg ) - {} - }; - - class OutOfMemory : public RuntimeError - { - public: - explicit OutOfMemory( const std::string& msg="Out of memory!" ) : - RuntimeError( msg ) {} - }; - - // This exception thrown any time an operation is attempted when an object - // is in an uninitialized state. - class InvalidOperation : public LogicError - { - public: - virtual ~InvalidOperation() throw() {} - explicit InvalidOperation( const std::string& msg="Attempted method call is invalid for the current object or program state." ) : - LogicError( msg ) {} - }; - - // This exception thrown any time an operation is attempted when an object - // is in an uninitialized state. - class InvalidArgument : public LogicError - { - public: - virtual ~InvalidArgument() throw() {} - explicit InvalidArgument( const std::string& msg="Invalid argument passed to a function." ) : - LogicError( msg ) {} - }; - - // Keep those array indexers in bounds when using the SafeArray type, or you'll be - // seeing these. - class IndexBoundsFault : public LogicError - { - public: - virtual ~IndexBoundsFault() throw() {} - explicit IndexBoundsFault( const std::string& msg="Array index is outsides the bounds of an array." ) : - LogicError( msg ) {} - }; - - class HardwareDeficiency : public RuntimeError - { - public: - explicit HardwareDeficiency( const std::string& msg="Your machine's hardware is incapable of running Pcsx2. Sorry dood." ) : - RuntimeError( msg ) {} - }; - - // This exception is thrown by the PS2 emulation (R5900, etc) when bad things happen - // that force the emulation state to terminate. The GUI should handle them by returning - // the user to the GUI. - class CpuStateShutdown : public RuntimeError - { - public: - virtual ~CpuStateShutdown() throw() {} - explicit CpuStateShutdown( const std::string& msg="The PS2 emulated state was shut down unexpectedly." ) : - RuntimeError( msg ) {} - }; - - class PluginFailure : public RuntimeError - { - public: - std::string plugin_name; // name of the plugin - - virtual ~PluginFailure() throw() {} - explicit PluginFailure( const std::string& plugin, const std::string& msg = "A plugin encountered a critical error." ) : - RuntimeError( msg ) - , plugin_name( plugin ) {} - }; - - class ThreadCreationError : public RuntimeError - { - public: - virtual ~ThreadCreationError() throw() {} - explicit ThreadCreationError( const std::string& msg="Thread could not be created." ) : - RuntimeError( msg ) {} - }; - - // This is a "special" exception that's primarily included for safe functioning in the - // Win32's ASCII API (ie, the non-Unicode one). Many of the old Win32 APIs don't support - // paths over 256 characters. - class PathTooLong : public RuntimeError - { - public: - virtual ~PathTooLong() throw() {} - explicit PathTooLong( const std::string& msg= - "A Pcsx2 pathname was too long for the system. Please move or reinstall Pcsx2 to\n" - "a location on your hard drive that has a shorter path." ) : - RuntimeError( msg ) {} - }; - - /////////////////////////////////////////////////////////////////////// - // STREAMING EXCEPTIONS - - // Generic stream error. Contains the name of the stream and a message. - // This exception is usually thrown via derrived classes, except in the (rare) case of a generic / unknown error. - class Stream : public RuntimeError - { - public: - std::string stream_name; // name of the stream (if applicable) - - virtual ~Stream() throw() {} - - // copy construct! - Stream( const Stream& src ) : - RuntimeError( src.Message() ) - , stream_name( src.stream_name ) {} - - explicit Stream( - const std::string& objname=std::string(), - const std::string& msg="Invalid stream object" ) : - RuntimeError( msg + "\n\tFilename: " + objname ) - , stream_name( objname ) {} - }; - - // A generic base error class for bad streams -- corrupted data, sudden closures, loss of - // connection, or anything else that would indicate a failure to read the data after the - // stream was successfully opened. - class BadStream : public Stream - { - public: - virtual ~BadStream() throw() {} - explicit BadStream( - const std::string& objname=std::string(), - const std::string& msg="Stream data is corrupted or incomplete, or the stream connection closed unexpectedly" ) : - Stream( objname, msg ) {} - }; - - // A generic exception for odd-ball stream creation errors. - class CreateStream : public Stream - { - public: - virtual ~CreateStream() throw() {} - explicit CreateStream( - const std::string& objname=std::string(), - const std::string& msg="Stream could not be created or opened" ) : - Stream( objname, msg ) {} - }; - - // Exception thrown when an attempt to open a non-existent file is made. - // (this exception can also mean file permissions are invalid) - class FileNotFound : public CreateStream - { - public: - virtual ~FileNotFound() throw() {} - explicit FileNotFound( - const std::string& objname=std::string(), - const std::string& msg="File not found" ) : - CreateStream( objname, msg ) {} - }; - - class AccessDenied : public CreateStream - { - public: - virtual ~AccessDenied() throw() {} - explicit AccessDenied( - const std::string& objname=std::string(), - const std::string& msg="Permission denied to file or stream" ) : - CreateStream( objname, msg ) {} - }; - - // Generic End of Stream exception (sometimes an error, and sometimes just used as a - // shortcut for manual feof checks). - class EndOfStream : public Stream - { - public: - virtual ~EndOfStream() throw() {} - explicit EndOfStream( const std::string& objname=std::string(), const std::string& msg="End of stream was encountered" ) : - Stream( objname, msg ) {} - }; - - ////////////////////////////////////////////////////////////////////////// - // SAVESTATE EXCEPTIONS - - // Exception thrown when a corrupted or truncated savestate is encountered. - class BadSavedState : public BadStream - { - public: - virtual ~BadSavedState() throw() {} - explicit BadSavedState( - const std::string& objname=std::string(), - const std::string& msg="Savestate data is corrupted or incomplete" ) : - BadStream( objname, msg ) {} - }; - - // Exception thrown by SaveState class when a critical plugin or gzread - class FreezePluginFailure : public RuntimeError - { - public: - std::string plugin_name; // name of the plugin - std::string freeze_action; - - virtual ~FreezePluginFailure() throw() {} - explicit FreezePluginFailure( const std::string& plugin, const std::string& action ) : - RuntimeError( plugin + " plugin returned an error while " + action + " the state." ) - , plugin_name( plugin ) - , freeze_action( action ){} - }; - - // The savestate code throws Recoverable errors when it fails prior to actually modifying - // the current emulation state. Recoverable errors are always thrown from the SaveState - // object construction (and never from Freeze methods). - class StateLoadError_Recoverable : public RuntimeError - { - public: - virtual ~StateLoadError_Recoverable() throw() {} - explicit StateLoadError_Recoverable( const std::string& msg="Recoverable error while loading savestate (existing emulation state is still intact)." ) : - RuntimeError( msg ) {} - }; - - // A recoverable exception thrown when the savestate being loaded isn't supported. - class UnsupportedStateVersion : public StateLoadError_Recoverable - { - public: - u32 Version; // version number of the unsupported state. - - public: - virtual ~UnsupportedStateVersion() throw() {} - explicit UnsupportedStateVersion( int version ) : - StateLoadError_Recoverable( fmt_string( "Unknown or unsupported savestate version: 0x%x", version ) ) - {} - - explicit UnsupportedStateVersion( int version, const std::string& msg ) : - StateLoadError_Recoverable( msg ) {} - }; - - // A recoverable exception thrown when the CRC of the savestate does not match the - // CRC returned by the Cdvd driver. - class StateCrcMismatch : public StateLoadError_Recoverable - { - public: - u32 Crc_Savestate; - u32 Crc_Cdvd; - - public: - virtual ~StateCrcMismatch() throw() {} - explicit StateCrcMismatch( u32 crc_save, u32 crc_cdvd ) - : StateLoadError_Recoverable( fmt_string( - "Game/CDVD does not match the savestate CRC.\n" - "\tCdvd CRC: 0x%X\n\tGame CRC: 0x%X\n", params crc_save, crc_cdvd - ) ) - , Crc_Savestate( crc_save ) - , Crc_Cdvd( crc_cdvd ) - {} - - explicit StateCrcMismatch( u32 crc_save, u32 crc_cdvd, const std::string& msg ) - : StateLoadError_Recoverable( msg ) - , Crc_Savestate( crc_save ) - , Crc_Cdvd( crc_cdvd ) - {} - }; -} - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef _PCSX2_EXCEPTIONS_H_ +#define _PCSX2_EXCEPTIONS_H_ + +#include +#include "StringUtils.h" + +// This class provides an easy and clean method for ensuring objects are not copyable. +class NoncopyableObject +{ +protected: + NoncopyableObject() {} + ~NoncopyableObject() {} + +// Programmer's note: +// No need to provide implementations for these methods since they should +// never be referenced anyway. No references? No Linker Errors! Noncopyable! +private: + // Copy me? I think not! + explicit NoncopyableObject( const NoncopyableObject& ); + // Assign me? I think not! + const NoncopyableObject& operator=( const NoncopyableObject& ); +}; + + +// Base class used to implement type-safe sealed classes. +// This class should never be used directly. Use the Sealed +// macro instead, which ensures all sealed classes derive from a unique BaseSealed +// (preventing them from accidentally cirumventing sealing by inheriting from +// multiple sealed classes. +template < int T > +class __BaseSealed +{ +protected: + __BaseSealed() + { + } +}; + +// Use this macro/class as a base to seal a class from being derrived from. +// This macro works by providing a unique base class with a protected constructor +// for every class that derives from it. +#define Sealed private virtual __BaseSealed<__COUNTER__> + +namespace Exception +{ + // std::exception sucks, so I made a replacement. + // Note, this class is "abstract" which means you shouldn't use it directly like, ever. + // Use Exception::RuntimeError or Exception::LogicError instead. + class BaseException + { + protected: + const std::string m_message; // a "detailed" message of what disasterous thing has occured! + + public: + virtual ~BaseException() throw()=0; // the =0; syntax forces this class into "abstract" mode. + explicit BaseException( const std::string& msg="Unhandled exception." ) : + m_message( msg ) + {} + + const std::string& Message() const { return m_message; } + const char* cMessage() const { return m_message.c_str(); } + }; + + class RuntimeError : public BaseException + { + public: + virtual ~RuntimeError() throw() {} + explicit RuntimeError( const std::string& msg="An unhandled runtime error has occurred, somewhere in the depths of Pcsx2's cluttered brain-matter." ) : + BaseException( msg ) + {} + }; + + class LogicError : public BaseException + { + public: + virtual ~LogicError() throw() {} + explicit LogicError( const std::string& msg="An unhandled logic error has occured." ) : + BaseException( msg ) + {} + }; + + class OutOfMemory : public RuntimeError + { + public: + explicit OutOfMemory( const std::string& msg="Out of memory!" ) : + RuntimeError( msg ) {} + }; + + // This exception thrown any time an operation is attempted when an object + // is in an uninitialized state. + class InvalidOperation : public LogicError + { + public: + virtual ~InvalidOperation() throw() {} + explicit InvalidOperation( const std::string& msg="Attempted method call is invalid for the current object or program state." ) : + LogicError( msg ) {} + }; + + // This exception thrown any time an operation is attempted when an object + // is in an uninitialized state. + class InvalidArgument : public LogicError + { + public: + virtual ~InvalidArgument() throw() {} + explicit InvalidArgument( const std::string& msg="Invalid argument passed to a function." ) : + LogicError( msg ) {} + }; + + // Keep those array indexers in bounds when using the SafeArray type, or you'll be + // seeing these. + class IndexBoundsFault : public LogicError + { + public: + virtual ~IndexBoundsFault() throw() {} + explicit IndexBoundsFault( const std::string& msg="Array index is outsides the bounds of an array." ) : + LogicError( msg ) {} + }; + + class HardwareDeficiency : public RuntimeError + { + public: + explicit HardwareDeficiency( const std::string& msg="Your machine's hardware is incapable of running Pcsx2. Sorry dood." ) : + RuntimeError( msg ) {} + }; + + // This exception is thrown by the PS2 emulation (R5900, etc) when bad things happen + // that force the emulation state to terminate. The GUI should handle them by returning + // the user to the GUI. + class CpuStateShutdown : public RuntimeError + { + public: + virtual ~CpuStateShutdown() throw() {} + explicit CpuStateShutdown( const std::string& msg="The PS2 emulated state was shut down unexpectedly." ) : + RuntimeError( msg ) {} + }; + + class PluginFailure : public RuntimeError + { + public: + std::string plugin_name; // name of the plugin + + virtual ~PluginFailure() throw() {} + explicit PluginFailure( const std::string& plugin, const std::string& msg = "A plugin encountered a critical error." ) : + RuntimeError( msg ) + , plugin_name( plugin ) {} + }; + + class ThreadCreationError : public RuntimeError + { + public: + virtual ~ThreadCreationError() throw() {} + explicit ThreadCreationError( const std::string& msg="Thread could not be created." ) : + RuntimeError( msg ) {} + }; + + // This is a "special" exception that's primarily included for safe functioning in the + // Win32's ASCII API (ie, the non-Unicode one). Many of the old Win32 APIs don't support + // paths over 256 characters. + class PathTooLong : public RuntimeError + { + public: + virtual ~PathTooLong() throw() {} + explicit PathTooLong( const std::string& msg= + "A Pcsx2 pathname was too long for the system. Please move or reinstall Pcsx2 to\n" + "a location on your hard drive that has a shorter path." ) : + RuntimeError( msg ) {} + }; + + /////////////////////////////////////////////////////////////////////// + // STREAMING EXCEPTIONS + + // Generic stream error. Contains the name of the stream and a message. + // This exception is usually thrown via derrived classes, except in the (rare) case of a generic / unknown error. + class Stream : public RuntimeError + { + public: + std::string stream_name; // name of the stream (if applicable) + + virtual ~Stream() throw() {} + + // copy construct! + Stream( const Stream& src ) : + RuntimeError( src.Message() ) + , stream_name( src.stream_name ) {} + + explicit Stream( + const std::string& objname=std::string(), + const std::string& msg="Invalid stream object" ) : + RuntimeError( msg + "\n\tFilename: " + objname ) + , stream_name( objname ) {} + }; + + // A generic base error class for bad streams -- corrupted data, sudden closures, loss of + // connection, or anything else that would indicate a failure to read the data after the + // stream was successfully opened. + class BadStream : public Stream + { + public: + virtual ~BadStream() throw() {} + explicit BadStream( + const std::string& objname=std::string(), + const std::string& msg="Stream data is corrupted or incomplete, or the stream connection closed unexpectedly" ) : + Stream( objname, msg ) {} + }; + + // A generic exception for odd-ball stream creation errors. + class CreateStream : public Stream + { + public: + virtual ~CreateStream() throw() {} + explicit CreateStream( + const std::string& objname=std::string(), + const std::string& msg="Stream could not be created or opened" ) : + Stream( objname, msg ) {} + }; + + // Exception thrown when an attempt to open a non-existent file is made. + // (this exception can also mean file permissions are invalid) + class FileNotFound : public CreateStream + { + public: + virtual ~FileNotFound() throw() {} + explicit FileNotFound( + const std::string& objname=std::string(), + const std::string& msg="File not found" ) : + CreateStream( objname, msg ) {} + }; + + class AccessDenied : public CreateStream + { + public: + virtual ~AccessDenied() throw() {} + explicit AccessDenied( + const std::string& objname=std::string(), + const std::string& msg="Permission denied to file or stream" ) : + CreateStream( objname, msg ) {} + }; + + // Generic End of Stream exception (sometimes an error, and sometimes just used as a + // shortcut for manual feof checks). + class EndOfStream : public Stream + { + public: + virtual ~EndOfStream() throw() {} + explicit EndOfStream( const std::string& objname=std::string(), const std::string& msg="End of stream was encountered" ) : + Stream( objname, msg ) {} + }; + + ////////////////////////////////////////////////////////////////////////// + // SAVESTATE EXCEPTIONS + + // Exception thrown when a corrupted or truncated savestate is encountered. + class BadSavedState : public BadStream + { + public: + virtual ~BadSavedState() throw() {} + explicit BadSavedState( + const std::string& objname=std::string(), + const std::string& msg="Savestate data is corrupted or incomplete" ) : + BadStream( objname, msg ) {} + }; + + // Exception thrown by SaveState class when a critical plugin or gzread + class FreezePluginFailure : public RuntimeError + { + public: + std::string plugin_name; // name of the plugin + std::string freeze_action; + + virtual ~FreezePluginFailure() throw() {} + explicit FreezePluginFailure( const std::string& plugin, const std::string& action ) : + RuntimeError( plugin + " plugin returned an error while " + action + " the state." ) + , plugin_name( plugin ) + , freeze_action( action ){} + }; + + // The savestate code throws Recoverable errors when it fails prior to actually modifying + // the current emulation state. Recoverable errors are always thrown from the SaveState + // object construction (and never from Freeze methods). + class StateLoadError_Recoverable : public RuntimeError + { + public: + virtual ~StateLoadError_Recoverable() throw() {} + explicit StateLoadError_Recoverable( const std::string& msg="Recoverable error while loading savestate (existing emulation state is still intact)." ) : + RuntimeError( msg ) {} + }; + + // A recoverable exception thrown when the savestate being loaded isn't supported. + class UnsupportedStateVersion : public StateLoadError_Recoverable + { + public: + u32 Version; // version number of the unsupported state. + + public: + virtual ~UnsupportedStateVersion() throw() {} + explicit UnsupportedStateVersion( int version ) : + StateLoadError_Recoverable( fmt_string( "Unknown or unsupported savestate version: 0x%x", version ) ) + {} + + explicit UnsupportedStateVersion( int version, const std::string& msg ) : + StateLoadError_Recoverable( msg ) {} + }; + + // A recoverable exception thrown when the CRC of the savestate does not match the + // CRC returned by the Cdvd driver. + class StateCrcMismatch : public StateLoadError_Recoverable + { + public: + u32 Crc_Savestate; + u32 Crc_Cdvd; + + public: + virtual ~StateCrcMismatch() throw() {} + explicit StateCrcMismatch( u32 crc_save, u32 crc_cdvd ) + : StateLoadError_Recoverable( fmt_string( + "Game/CDVD does not match the savestate CRC.\n" + "\tCdvd CRC: 0x%X\n\tGame CRC: 0x%X\n", params crc_save, crc_cdvd + ) ) + , Crc_Savestate( crc_save ) + , Crc_Cdvd( crc_cdvd ) + {} + + explicit StateCrcMismatch( u32 crc_save, u32 crc_cdvd, const std::string& msg ) + : StateLoadError_Recoverable( msg ) + , Crc_Savestate( crc_save ) + , Crc_Cdvd( crc_cdvd ) + {} + }; +} + +#endif diff --git a/pcsx2/FPU.cpp b/pcsx2/FPU.cpp index cc92316ec4..eebe2e57b5 100644 --- a/pcsx2/FPU.cpp +++ b/pcsx2/FPU.cpp @@ -1,388 +1,388 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include -#include "Common.h" -#include "R5900.h" -#include "R5900OpcodeTables.h" - -using namespace std; // for min / max - -// Helper Macros -//**************************************************************** - -// IEEE 754 Values -#define PosInfinity 0x7f800000 -#define NegInfinity 0xff800000 -#define posFmax 0x7F7FFFFF -#define negFmax 0xFF7FFFFF - - -/* Used in compare function to compensate for differences between IEEE 754 and the FPU. - Setting it to ~0x00000000 = Compares Exact Value. (comment out this macro for faster Exact Compare method) - Setting it to ~0x00000001 = Discards the least significant bit when comparing. - Setting it to ~0x00000003 = Discards the least 2 significant bits when comparing... etc.. */ -//#define comparePrecision ~0x00000001 - -// Operands -#define _Ft_ ( ( cpuRegs.code >> 16 ) & 0x1F ) -#define _Fs_ ( ( cpuRegs.code >> 11 ) & 0x1F ) -#define _Fd_ ( ( cpuRegs.code >> 6 ) & 0x1F ) - -// Floats -#define _FtValf_ fpuRegs.fpr[ _Ft_ ].f -#define _FsValf_ fpuRegs.fpr[ _Fs_ ].f -#define _FdValf_ fpuRegs.fpr[ _Fd_ ].f -#define _FAValf_ fpuRegs.ACC.f - -// U32's -#define _FtValUl_ fpuRegs.fpr[ _Ft_ ].UL -#define _FsValUl_ fpuRegs.fpr[ _Fs_ ].UL -#define _FdValUl_ fpuRegs.fpr[ _Fd_ ].UL -#define _FAValUl_ fpuRegs.ACC.UL - -// FPU Control Reg (FCR31) -#define _ContVal_ fpuRegs.fprc[ 31 ] - -// FCR31 Flags -#define FPUflagC 0X00800000 -#define FPUflagI 0X00020000 -#define FPUflagD 0X00010000 -#define FPUflagO 0X00008000 -#define FPUflagU 0X00004000 -#define FPUflagSI 0X00000040 -#define FPUflagSD 0X00000020 -#define FPUflagSO 0X00000010 -#define FPUflagSU 0X00000008 - -//**************************************************************** - -// If we have an infinity value, then Overflow has occured. -#define checkOverflow(xReg, cFlagsToSet, shouldReturn) { \ - if ( ( xReg & ~0x80000000 ) == PosInfinity ) { \ - /*SysPrintf( "FPU OVERFLOW!: Changing to +/-Fmax!!!!!!!!!!!!\n" );*/ \ - xReg = ( xReg & 0x80000000 ) | posFmax; \ - _ContVal_ |= cFlagsToSet; \ - if ( shouldReturn ) { return; } \ - } \ -} - -// If we have a denormal value, then Underflow has occured. -#define checkUnderflow(xReg, cFlagsToSet, shouldReturn) { \ - if ( ( ( xReg & 0x7F800000 ) == 0 ) && ( ( xReg & 0x007FFFFF ) != 0 ) ) { \ - /*SysPrintf( "FPU UNDERFLOW!: Changing to +/-0!!!!!!!!!!!!\n" );*/ \ - xReg &= 0x80000000; \ - _ContVal_ |= cFlagsToSet; \ - if ( shouldReturn ) { return; } \ - } \ -} - -/* Checks if Divide by Zero will occur. (z/y = x) - cFlagsToSet1 = Flags to set if (z != 0) - cFlagsToSet2 = Flags to set if (z == 0) - ( Denormals are counted as "0" ) -*/ -#define checkDivideByZero(xReg, yDivisorReg, zDividendReg, cFlagsToSet1, cFlagsToSet2, shouldReturn) { \ - if ( ( yDivisorReg & 0x7F800000 ) == 0 ) { \ - _ContVal_ |= ( ( zDividendReg & 0x7F800000 ) == 0 ) ? cFlagsToSet2 : cFlagsToSet1; \ - xReg = ( ( yDivisorReg ^ zDividendReg ) & 0x80000000 ) | posFmax; \ - if ( shouldReturn ) { return; } \ - } \ -} - -/* Clears the "Cause Flags" of the Control/Status Reg - The "EE Core Users Manual" implies that all the Cause flags are cleared every instruction... - But, the "EE Core Instruction Set Manual" says that only certain Cause Flags are cleared - for specific instructions... I'm just setting them to clear when the Instruction Set Manual - says to... (cottonvibes) -*/ -#define clearFPUFlags(cFlags) { \ - _ContVal_ &= ~( cFlags ) ; \ -} - -#ifdef comparePrecision -// This compare discards the least-significant bit(s) in order to solve some rounding issues. - #define C_cond_S(cond) { \ - FPRreg tempA, tempB; \ - tempA.UL = _FsValUl_ & comparePrecision; \ - tempB.UL = _FtValUl_ & comparePrecision; \ - _ContVal_ = ( ( tempA.f ) cond ( tempB.f ) ) ? \ - ( _ContVal_ | FPUflagC ) : \ - ( _ContVal_ & ~FPUflagC ); \ - } -#else -// Used for Comparing; This compares if the floats are exactly the same. - #define C_cond_S(cond) { \ - _ContVal_ = ( _FsValf_ cond _FtValf_ ) ? \ - ( _ContVal_ | FPUflagC ) : \ - ( _ContVal_ & ~FPUflagC ); \ - } -#endif - -// Conditional Branch -#define BC1(cond) \ - if ( ( _ContVal_ & FPUflagC ) cond 0 ) { \ - intDoBranch( _BranchTarget_ ); \ - } - -// Conditional Branch -#define BC1L(cond) \ - if ( ( _ContVal_ & FPUflagC ) cond 0 ) { \ - intDoBranch( _BranchTarget_ ); \ - } else cpuRegs.pc += 4; - -namespace R5900 { -namespace Interpreter { -namespace OpcodeImpl { -namespace COP1 { - -//**************************************************************** -// FPU Opcodes -//**************************************************************** - -float fpuDouble(u32 f) -{ - switch(f & 0x7f800000){ - case 0x0: - f &= 0x80000000; - return *(float*)&f; - break; - case 0x7f800000: - f = (f & 0x80000000)|0x7f7fffff; - return *(float*)&f; - break; - default: - return *(float*)&f; - break; - } -} - -void ABS_S() { - _FdValUl_ = _FsValUl_ & 0x7fffffff; - clearFPUFlags( FPUflagO | FPUflagU ); -} - -void ADD_S() { - _FdValf_ = fpuDouble( _FsValUl_ ) + fpuDouble( _FtValUl_ ); - checkOverflow( _FdValUl_, FPUflagO | FPUflagSO, 1 ); - checkUnderflow( _FdValUl_, FPUflagU | FPUflagSU, 1 ); -} - -void ADDA_S() { - _FAValf_ = fpuDouble( _FsValUl_ ) + fpuDouble( _FtValUl_ ); - checkOverflow( _FAValUl_, FPUflagO | FPUflagSO, 1 ); - checkUnderflow( _FAValUl_, FPUflagU | FPUflagSU, 1 ); -} - -void BC1F() { - BC1(==); -} - -void BC1FL() { - BC1L(==); // Equal to 0 -} - -void BC1T() { - BC1(!=); -} - -void BC1TL() { - BC1L(!=); // different from 0 -} - -void C_EQ() { - C_cond_S(==); -} - -void C_F() { - clearFPUFlags( FPUflagC ); //clears C regardless -} - -void C_LE() { - C_cond_S(<=); -} - -void C_LT() { - C_cond_S(<); -} - -void CFC1() { - if ( !_Rt_ || ( (_Fs_ != 0) && (_Fs_ != 31) ) ) return; - cpuRegs.GPR.r[_Rt_].SD[0] = (s64)fpuRegs.fprc[_Fs_]; -} - -void CTC1() { - if ( _Fs_ != 31 ) return; - fpuRegs.fprc[_Fs_] = cpuRegs.GPR.r[_Rt_].UL[0]; -} - -void CVT_S() { - _FdValf_ = (float)(*(s32*)&_FsValUl_); - _FdValf_ = fpuDouble( _FdValUl_ ); -} - -void CVT_W() { - if ( ( _FsValUl_ & 0x7F800000 ) <= 0x4E800000 ) { _FdValUl_ = (s32)_FsValf_; } - else if ( ( _FsValUl_ & 0x80000000 ) == 0 ) { _FdValUl_ = 0x7fffffff; } - else { _FdValUl_ = 0x80000000; } -} - -void DIV_S() { - checkDivideByZero( _FdValUl_, _FtValUl_, _FsValUl_, FPUflagD | FPUflagSD, FPUflagI | FPUflagSI, 1 ); - _FdValf_ = fpuDouble( _FsValUl_ ) / fpuDouble( _FtValUl_ ); - checkOverflow( _FdValUl_, 0, 1); - checkUnderflow( _FdValUl_, 0, 1 ); -} - -/* The Instruction Set manual has an overly complicated way of - determining the flags that are set. Hopefully this shorter - method provides a similar outcome and is faster. (cottonvibes) -*/ -void MADD_S() { - FPRreg temp; - temp.f = fpuDouble( _FsValUl_ ) * fpuDouble( _FtValUl_ ); - _FdValf_ = fpuDouble( _FAValUl_ ) + fpuDouble( temp.UL ); - checkOverflow( _FdValUl_, FPUflagO | FPUflagSO, 1 ); - checkUnderflow( _FdValUl_, FPUflagU | FPUflagSU, 1 ); -} - -void MADDA_S() { - _FAValf_ += fpuDouble( _FsValUl_ ) * fpuDouble( _FtValUl_ ); - checkOverflow( _FAValUl_, FPUflagO | FPUflagSO, 1 ); - checkUnderflow( _FAValUl_, FPUflagU | FPUflagSU, 1 ); -} - -void MAX_S() { - _FdValf_ = max( _FsValf_, _FtValf_ ); - clearFPUFlags( FPUflagO | FPUflagU ); -} - -void MFC1() { - if ( !_Rt_ ) return; - cpuRegs.GPR.r[_Rt_].SD[0] = (s64)_FsValUl_; -} - -void MIN_S() { - _FdValf_ = min( _FsValf_, _FtValf_ ); - clearFPUFlags( FPUflagO | FPUflagU ); -} - -void MOV_S() { - _FdValUl_ = _FsValUl_; -} - -void MSUB_S() { - FPRreg temp; - temp.f = fpuDouble( _FsValUl_ ) * fpuDouble( _FtValUl_ ); - _FdValf_ = fpuDouble( _FAValUl_ ) - fpuDouble( temp.UL ); - checkOverflow( _FdValUl_, FPUflagO | FPUflagSO, 1 ); - checkUnderflow( _FdValUl_, FPUflagU | FPUflagSU, 1 ); -} - -void MSUBA_S() { - _FAValf_ -= fpuDouble( _FsValUl_ ) * fpuDouble( _FtValUl_ ); - checkOverflow( _FAValUl_, FPUflagO | FPUflagSO, 1 ); - checkUnderflow( _FAValUl_, FPUflagU | FPUflagSU, 1 ); -} - -void MTC1() { - _FsValUl_ = cpuRegs.GPR.r[_Rt_].UL[0]; -} - -void MUL_S() { - _FdValf_ = fpuDouble( _FsValUl_ ) * fpuDouble( _FtValUl_ ); - checkOverflow( _FdValUl_, FPUflagO | FPUflagSO, 1 ); - checkUnderflow( _FdValUl_, FPUflagU | FPUflagSU, 1 ); -} - -void MULA_S() { - _FAValf_ = fpuDouble( _FsValUl_ ) * fpuDouble( _FtValUl_ ); - checkOverflow( _FAValUl_, FPUflagO | FPUflagSO, 1 ); - checkUnderflow( _FAValUl_, FPUflagU | FPUflagSU, 1 ); -} - -void NEG_S() { - _FdValUl_ = (_FsValUl_ ^ 0x80000000); - clearFPUFlags( FPUflagO | FPUflagU ); -} - -void RSQRT_S() { - FPRreg temp; - if ( ( _FtValUl_ & 0x7F800000 ) == 0 ) { // Ft is zero (Denormals are Zero) - _ContVal_ |= FPUflagD | FPUflagSD; - _FdValUl_ = ( ( _FsValUl_ ^ _FtValUl_ ) & 0x80000000 ) | posFmax; - return; - } - else if ( _FtValUl_ & 0x80000000 ) { // Ft is negative - _ContVal_ |= FPUflagI | FPUflagSI; - temp.f = sqrt( fabs( fpuDouble( _FtValUl_ ) ) ); - _FdValf_ = fpuDouble( _FsValUl_ ) / fpuDouble( temp.UL ); - } - else { _FdValf_ = fpuDouble( _FsValUl_ ) / sqrt( fpuDouble( _FtValUl_ ) ); } // Ft is positive and not zero - - checkOverflow( _FdValUl_, 0, 1 ); - checkUnderflow( _FdValUl_, 0, 1 ); -} - -void SQRT_S() { - if ( ( _FtValUl_ & 0xFF800000 ) == 0x80000000 ) { _FdValUl_ = 0x80000000; } // If Ft = -0 - else if ( _FtValUl_ & 0x80000000 ) { // If Ft is Negative - _ContVal_ |= FPUflagI | FPUflagSI; - _FdValf_ = sqrt( fabs( fpuDouble( _FtValUl_ ) ) ); - } - else { _FdValf_ = sqrt( fpuDouble( _FtValUl_ ) ); } // If Ft is Positive - clearFPUFlags( FPUflagD ); -} - -void SUB_S() { - _FdValf_ = fpuDouble( _FsValUl_ ) - fpuDouble( _FtValUl_ ); - checkOverflow( _FdValUl_, FPUflagO | FPUflagSO, 1 ); - checkUnderflow( _FdValUl_, FPUflagU | FPUflagSU, 1 ); -} - -void SUBA_S() { - _FAValf_ = fpuDouble( _FsValUl_ ) - fpuDouble( _FtValUl_ ); - checkOverflow( _FAValUl_, FPUflagO | FPUflagSO, 1 ); - checkUnderflow( _FAValUl_, FPUflagU | FPUflagSU, 1 ); -} - -} // End Namespace COP1 - -///////////////////////////////////////////////////////////////////// -// COP1 (FPU) Load/Store Instructions - -// These are actually EE opcodes but since they're related to FPU registers and such they -// seem more appropriately located here. - -void LWC1() { - u32 addr; - addr = cpuRegs.GPR.r[_Rs_].UL[0] + (s32)(s16)(cpuRegs.code & 0xffff); - if (addr & 0x00000003) { Console::Error( "FPU (LWC1 Opcode): Invalid Memory Address" ); return; } // Should signal an exception? - memRead32(addr, &fpuRegs.fpr[_Rt_].UL); -} - -void SWC1() { - u32 addr; - addr = cpuRegs.GPR.r[_Rs_].UL[0] + (s32)(s16)(cpuRegs.code & 0xffff); - if (addr & 0x00000003) { Console::Error( "FPU (SWC1 Opcode): Invalid Memory Address" ); return; } // Should signal an exception? - memWrite32(addr, fpuRegs.fpr[_Rt_].UL); -} - -} } } +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include +#include "Common.h" +#include "R5900.h" +#include "R5900OpcodeTables.h" + +using namespace std; // for min / max + +// Helper Macros +//**************************************************************** + +// IEEE 754 Values +#define PosInfinity 0x7f800000 +#define NegInfinity 0xff800000 +#define posFmax 0x7F7FFFFF +#define negFmax 0xFF7FFFFF + + +/* Used in compare function to compensate for differences between IEEE 754 and the FPU. + Setting it to ~0x00000000 = Compares Exact Value. (comment out this macro for faster Exact Compare method) + Setting it to ~0x00000001 = Discards the least significant bit when comparing. + Setting it to ~0x00000003 = Discards the least 2 significant bits when comparing... etc.. */ +//#define comparePrecision ~0x00000001 + +// Operands +#define _Ft_ ( ( cpuRegs.code >> 16 ) & 0x1F ) +#define _Fs_ ( ( cpuRegs.code >> 11 ) & 0x1F ) +#define _Fd_ ( ( cpuRegs.code >> 6 ) & 0x1F ) + +// Floats +#define _FtValf_ fpuRegs.fpr[ _Ft_ ].f +#define _FsValf_ fpuRegs.fpr[ _Fs_ ].f +#define _FdValf_ fpuRegs.fpr[ _Fd_ ].f +#define _FAValf_ fpuRegs.ACC.f + +// U32's +#define _FtValUl_ fpuRegs.fpr[ _Ft_ ].UL +#define _FsValUl_ fpuRegs.fpr[ _Fs_ ].UL +#define _FdValUl_ fpuRegs.fpr[ _Fd_ ].UL +#define _FAValUl_ fpuRegs.ACC.UL + +// FPU Control Reg (FCR31) +#define _ContVal_ fpuRegs.fprc[ 31 ] + +// FCR31 Flags +#define FPUflagC 0X00800000 +#define FPUflagI 0X00020000 +#define FPUflagD 0X00010000 +#define FPUflagO 0X00008000 +#define FPUflagU 0X00004000 +#define FPUflagSI 0X00000040 +#define FPUflagSD 0X00000020 +#define FPUflagSO 0X00000010 +#define FPUflagSU 0X00000008 + +//**************************************************************** + +// If we have an infinity value, then Overflow has occured. +#define checkOverflow(xReg, cFlagsToSet, shouldReturn) { \ + if ( ( xReg & ~0x80000000 ) == PosInfinity ) { \ + /*SysPrintf( "FPU OVERFLOW!: Changing to +/-Fmax!!!!!!!!!!!!\n" );*/ \ + xReg = ( xReg & 0x80000000 ) | posFmax; \ + _ContVal_ |= cFlagsToSet; \ + if ( shouldReturn ) { return; } \ + } \ +} + +// If we have a denormal value, then Underflow has occured. +#define checkUnderflow(xReg, cFlagsToSet, shouldReturn) { \ + if ( ( ( xReg & 0x7F800000 ) == 0 ) && ( ( xReg & 0x007FFFFF ) != 0 ) ) { \ + /*SysPrintf( "FPU UNDERFLOW!: Changing to +/-0!!!!!!!!!!!!\n" );*/ \ + xReg &= 0x80000000; \ + _ContVal_ |= cFlagsToSet; \ + if ( shouldReturn ) { return; } \ + } \ +} + +/* Checks if Divide by Zero will occur. (z/y = x) + cFlagsToSet1 = Flags to set if (z != 0) + cFlagsToSet2 = Flags to set if (z == 0) + ( Denormals are counted as "0" ) +*/ +#define checkDivideByZero(xReg, yDivisorReg, zDividendReg, cFlagsToSet1, cFlagsToSet2, shouldReturn) { \ + if ( ( yDivisorReg & 0x7F800000 ) == 0 ) { \ + _ContVal_ |= ( ( zDividendReg & 0x7F800000 ) == 0 ) ? cFlagsToSet2 : cFlagsToSet1; \ + xReg = ( ( yDivisorReg ^ zDividendReg ) & 0x80000000 ) | posFmax; \ + if ( shouldReturn ) { return; } \ + } \ +} + +/* Clears the "Cause Flags" of the Control/Status Reg + The "EE Core Users Manual" implies that all the Cause flags are cleared every instruction... + But, the "EE Core Instruction Set Manual" says that only certain Cause Flags are cleared + for specific instructions... I'm just setting them to clear when the Instruction Set Manual + says to... (cottonvibes) +*/ +#define clearFPUFlags(cFlags) { \ + _ContVal_ &= ~( cFlags ) ; \ +} + +#ifdef comparePrecision +// This compare discards the least-significant bit(s) in order to solve some rounding issues. + #define C_cond_S(cond) { \ + FPRreg tempA, tempB; \ + tempA.UL = _FsValUl_ & comparePrecision; \ + tempB.UL = _FtValUl_ & comparePrecision; \ + _ContVal_ = ( ( tempA.f ) cond ( tempB.f ) ) ? \ + ( _ContVal_ | FPUflagC ) : \ + ( _ContVal_ & ~FPUflagC ); \ + } +#else +// Used for Comparing; This compares if the floats are exactly the same. + #define C_cond_S(cond) { \ + _ContVal_ = ( _FsValf_ cond _FtValf_ ) ? \ + ( _ContVal_ | FPUflagC ) : \ + ( _ContVal_ & ~FPUflagC ); \ + } +#endif + +// Conditional Branch +#define BC1(cond) \ + if ( ( _ContVal_ & FPUflagC ) cond 0 ) { \ + intDoBranch( _BranchTarget_ ); \ + } + +// Conditional Branch +#define BC1L(cond) \ + if ( ( _ContVal_ & FPUflagC ) cond 0 ) { \ + intDoBranch( _BranchTarget_ ); \ + } else cpuRegs.pc += 4; + +namespace R5900 { +namespace Interpreter { +namespace OpcodeImpl { +namespace COP1 { + +//**************************************************************** +// FPU Opcodes +//**************************************************************** + +float fpuDouble(u32 f) +{ + switch(f & 0x7f800000){ + case 0x0: + f &= 0x80000000; + return *(float*)&f; + break; + case 0x7f800000: + f = (f & 0x80000000)|0x7f7fffff; + return *(float*)&f; + break; + default: + return *(float*)&f; + break; + } +} + +void ABS_S() { + _FdValUl_ = _FsValUl_ & 0x7fffffff; + clearFPUFlags( FPUflagO | FPUflagU ); +} + +void ADD_S() { + _FdValf_ = fpuDouble( _FsValUl_ ) + fpuDouble( _FtValUl_ ); + checkOverflow( _FdValUl_, FPUflagO | FPUflagSO, 1 ); + checkUnderflow( _FdValUl_, FPUflagU | FPUflagSU, 1 ); +} + +void ADDA_S() { + _FAValf_ = fpuDouble( _FsValUl_ ) + fpuDouble( _FtValUl_ ); + checkOverflow( _FAValUl_, FPUflagO | FPUflagSO, 1 ); + checkUnderflow( _FAValUl_, FPUflagU | FPUflagSU, 1 ); +} + +void BC1F() { + BC1(==); +} + +void BC1FL() { + BC1L(==); // Equal to 0 +} + +void BC1T() { + BC1(!=); +} + +void BC1TL() { + BC1L(!=); // different from 0 +} + +void C_EQ() { + C_cond_S(==); +} + +void C_F() { + clearFPUFlags( FPUflagC ); //clears C regardless +} + +void C_LE() { + C_cond_S(<=); +} + +void C_LT() { + C_cond_S(<); +} + +void CFC1() { + if ( !_Rt_ || ( (_Fs_ != 0) && (_Fs_ != 31) ) ) return; + cpuRegs.GPR.r[_Rt_].SD[0] = (s64)fpuRegs.fprc[_Fs_]; +} + +void CTC1() { + if ( _Fs_ != 31 ) return; + fpuRegs.fprc[_Fs_] = cpuRegs.GPR.r[_Rt_].UL[0]; +} + +void CVT_S() { + _FdValf_ = (float)(*(s32*)&_FsValUl_); + _FdValf_ = fpuDouble( _FdValUl_ ); +} + +void CVT_W() { + if ( ( _FsValUl_ & 0x7F800000 ) <= 0x4E800000 ) { _FdValUl_ = (s32)_FsValf_; } + else if ( ( _FsValUl_ & 0x80000000 ) == 0 ) { _FdValUl_ = 0x7fffffff; } + else { _FdValUl_ = 0x80000000; } +} + +void DIV_S() { + checkDivideByZero( _FdValUl_, _FtValUl_, _FsValUl_, FPUflagD | FPUflagSD, FPUflagI | FPUflagSI, 1 ); + _FdValf_ = fpuDouble( _FsValUl_ ) / fpuDouble( _FtValUl_ ); + checkOverflow( _FdValUl_, 0, 1); + checkUnderflow( _FdValUl_, 0, 1 ); +} + +/* The Instruction Set manual has an overly complicated way of + determining the flags that are set. Hopefully this shorter + method provides a similar outcome and is faster. (cottonvibes) +*/ +void MADD_S() { + FPRreg temp; + temp.f = fpuDouble( _FsValUl_ ) * fpuDouble( _FtValUl_ ); + _FdValf_ = fpuDouble( _FAValUl_ ) + fpuDouble( temp.UL ); + checkOverflow( _FdValUl_, FPUflagO | FPUflagSO, 1 ); + checkUnderflow( _FdValUl_, FPUflagU | FPUflagSU, 1 ); +} + +void MADDA_S() { + _FAValf_ += fpuDouble( _FsValUl_ ) * fpuDouble( _FtValUl_ ); + checkOverflow( _FAValUl_, FPUflagO | FPUflagSO, 1 ); + checkUnderflow( _FAValUl_, FPUflagU | FPUflagSU, 1 ); +} + +void MAX_S() { + _FdValf_ = max( _FsValf_, _FtValf_ ); + clearFPUFlags( FPUflagO | FPUflagU ); +} + +void MFC1() { + if ( !_Rt_ ) return; + cpuRegs.GPR.r[_Rt_].SD[0] = (s64)_FsValUl_; +} + +void MIN_S() { + _FdValf_ = min( _FsValf_, _FtValf_ ); + clearFPUFlags( FPUflagO | FPUflagU ); +} + +void MOV_S() { + _FdValUl_ = _FsValUl_; +} + +void MSUB_S() { + FPRreg temp; + temp.f = fpuDouble( _FsValUl_ ) * fpuDouble( _FtValUl_ ); + _FdValf_ = fpuDouble( _FAValUl_ ) - fpuDouble( temp.UL ); + checkOverflow( _FdValUl_, FPUflagO | FPUflagSO, 1 ); + checkUnderflow( _FdValUl_, FPUflagU | FPUflagSU, 1 ); +} + +void MSUBA_S() { + _FAValf_ -= fpuDouble( _FsValUl_ ) * fpuDouble( _FtValUl_ ); + checkOverflow( _FAValUl_, FPUflagO | FPUflagSO, 1 ); + checkUnderflow( _FAValUl_, FPUflagU | FPUflagSU, 1 ); +} + +void MTC1() { + _FsValUl_ = cpuRegs.GPR.r[_Rt_].UL[0]; +} + +void MUL_S() { + _FdValf_ = fpuDouble( _FsValUl_ ) * fpuDouble( _FtValUl_ ); + checkOverflow( _FdValUl_, FPUflagO | FPUflagSO, 1 ); + checkUnderflow( _FdValUl_, FPUflagU | FPUflagSU, 1 ); +} + +void MULA_S() { + _FAValf_ = fpuDouble( _FsValUl_ ) * fpuDouble( _FtValUl_ ); + checkOverflow( _FAValUl_, FPUflagO | FPUflagSO, 1 ); + checkUnderflow( _FAValUl_, FPUflagU | FPUflagSU, 1 ); +} + +void NEG_S() { + _FdValUl_ = (_FsValUl_ ^ 0x80000000); + clearFPUFlags( FPUflagO | FPUflagU ); +} + +void RSQRT_S() { + FPRreg temp; + if ( ( _FtValUl_ & 0x7F800000 ) == 0 ) { // Ft is zero (Denormals are Zero) + _ContVal_ |= FPUflagD | FPUflagSD; + _FdValUl_ = ( ( _FsValUl_ ^ _FtValUl_ ) & 0x80000000 ) | posFmax; + return; + } + else if ( _FtValUl_ & 0x80000000 ) { // Ft is negative + _ContVal_ |= FPUflagI | FPUflagSI; + temp.f = sqrt( fabs( fpuDouble( _FtValUl_ ) ) ); + _FdValf_ = fpuDouble( _FsValUl_ ) / fpuDouble( temp.UL ); + } + else { _FdValf_ = fpuDouble( _FsValUl_ ) / sqrt( fpuDouble( _FtValUl_ ) ); } // Ft is positive and not zero + + checkOverflow( _FdValUl_, 0, 1 ); + checkUnderflow( _FdValUl_, 0, 1 ); +} + +void SQRT_S() { + if ( ( _FtValUl_ & 0xFF800000 ) == 0x80000000 ) { _FdValUl_ = 0x80000000; } // If Ft = -0 + else if ( _FtValUl_ & 0x80000000 ) { // If Ft is Negative + _ContVal_ |= FPUflagI | FPUflagSI; + _FdValf_ = sqrt( fabs( fpuDouble( _FtValUl_ ) ) ); + } + else { _FdValf_ = sqrt( fpuDouble( _FtValUl_ ) ); } // If Ft is Positive + clearFPUFlags( FPUflagD ); +} + +void SUB_S() { + _FdValf_ = fpuDouble( _FsValUl_ ) - fpuDouble( _FtValUl_ ); + checkOverflow( _FdValUl_, FPUflagO | FPUflagSO, 1 ); + checkUnderflow( _FdValUl_, FPUflagU | FPUflagSU, 1 ); +} + +void SUBA_S() { + _FAValf_ = fpuDouble( _FsValUl_ ) - fpuDouble( _FtValUl_ ); + checkOverflow( _FAValUl_, FPUflagO | FPUflagSO, 1 ); + checkUnderflow( _FAValUl_, FPUflagU | FPUflagSU, 1 ); +} + +} // End Namespace COP1 + +///////////////////////////////////////////////////////////////////// +// COP1 (FPU) Load/Store Instructions + +// These are actually EE opcodes but since they're related to FPU registers and such they +// seem more appropriately located here. + +void LWC1() { + u32 addr; + addr = cpuRegs.GPR.r[_Rs_].UL[0] + (s32)(s16)(cpuRegs.code & 0xffff); + if (addr & 0x00000003) { Console::Error( "FPU (LWC1 Opcode): Invalid Memory Address" ); return; } // Should signal an exception? + memRead32(addr, &fpuRegs.fpr[_Rt_].UL); +} + +void SWC1() { + u32 addr; + addr = cpuRegs.GPR.r[_Rs_].UL[0] + (s32)(s16)(cpuRegs.code & 0xffff); + if (addr & 0x00000003) { Console::Error( "FPU (SWC1 Opcode): Invalid Memory Address" ); return; } // Should signal an exception? + memWrite32(addr, fpuRegs.fpr[_Rt_].UL); +} + +} } } diff --git a/pcsx2/FPU2.cpp b/pcsx2/FPU2.cpp index 3ff56385a9..744e40f062 100644 --- a/pcsx2/FPU2.cpp +++ b/pcsx2/FPU2.cpp @@ -1,42 +1,42 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - -// sqrtf only defined in C++ -extern "C" { - -float (*fpusqrtf)(float fval) = 0; -float (*fpufabsf)(float fval) = 0; -float (*fpusinf)(float fval) = 0; -float (*fpucosf)(float fval) = 0; -float (*fpuexpf)(float fval) = 0; -float (*fpuatanf)(float fval) = 0; -float (*fpuatan2f)(float fvalx, float fvaly) = 0; - -void InitFPUOps() -{ - fpusqrtf = sqrtf; - fpufabsf = fabsf; - fpusinf = sinf; - fpucosf = cosf; - fpuexpf = expf; - fpuatanf = atanf; - fpuatan2f = atan2f; -} - -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + +// sqrtf only defined in C++ +extern "C" { + +float (*fpusqrtf)(float fval) = 0; +float (*fpufabsf)(float fval) = 0; +float (*fpusinf)(float fval) = 0; +float (*fpucosf)(float fval) = 0; +float (*fpuexpf)(float fval) = 0; +float (*fpuatanf)(float fval) = 0; +float (*fpuatan2f)(float fvalx, float fvaly) = 0; + +void InitFPUOps() +{ + fpusqrtf = sqrtf; + fpufabsf = fabsf; + fpusinf = sinf; + fpucosf = cosf; + fpuexpf = expf; + fpuatanf = atanf; + fpuatan2f = atan2f; +} + +} diff --git a/pcsx2/FiFo.cpp b/pcsx2/FiFo.cpp index 100b45f5da..5492d3b76c 100644 --- a/pcsx2/FiFo.cpp +++ b/pcsx2/FiFo.cpp @@ -1,221 +1,221 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "Hw.h" -#include "GS.h" - -#include "Vif.h" -#include "VifDma.h" - -////////////////////////////////////////////////////////////////////////// -/////////////////////////// Quick & dirty FIFO :D //////////////////////// -////////////////////////////////////////////////////////////////////////// - -// ** NOTE: cannot use XMM/MMX regs ** - -// Notes on FIFO implementation -// -// The FIFO consists of four separate pages of HW register memory, each mapped to a -// PS2 device. They are listed as follows: -// -// 0x4000 - 0x5000 : VIF0 (all registers map to 0x4000) -// 0x5000 - 0x6000 : VIF1 (all registers map to 0x5000) -// 0x6000 - 0x7000 : GS (all registers map to 0x6000) -// 0x7000 - 0x8000 : IPU (registers map to 0x7000 and 0x7010, respectively) - -extern int FIFOto_write(u32* pMem, int size); -extern void FIFOfrom_readsingle(void *value); - -extern int g_nIPU0Data; -extern u8* g_pIPU0Pointer; -extern int FOreadpos; - -////////////////////////////////////////////////////////////////////////// -// ReadFIFO Pages - -void __fastcall ReadFIFO_page_4(u32 mem, u64 *out) -{ - jASSUME( (mem >= 0x10004000) && (mem < 0x10005000) ); - - VIF_LOG("ReadFIFO/VIF0 0x%08X\n", mem); - //out[0] = psHu64(mem ); - //out[1] = psHu64(mem+8); - - out[0] = psHu64(0x4000); - out[1] = psHu64(0x4008); -} - -void __fastcall ReadFIFO_page_5(u32 mem, u64 *out) -{ - jASSUME( (mem >= 0x10005000) && (mem < 0x10006000) ); - - VIF_LOG("ReadFIFO/VIF1, addr=0x%08X\n", mem); - - if( vif1Regs->stat & (VIF1_STAT_INT|VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS) ) - DevCon::Notice( "Reading from vif1 fifo when stalled" ); - - if (vif1Regs->stat & 0x800000) - { - if (--psHu32(D1_QWC) == 0) - vif1Regs->stat&= ~0x1f000000; - } - - //out[0] = psHu64(mem ); - //out[1] = psHu64(mem+8); - - out[0] = psHu64(0x5000); - out[1] = psHu64(0x5008); -} - -void __fastcall ReadFIFO_page_6(u32 mem, u64 *out) -{ - jASSUME( (mem >= 0x10006000) && (mem < 0x10007000) ); - - DevCon::Notice( "ReadFIFO/GIF, addr=0x%x", params mem ); - - //out[0] = psHu64(mem ); - //out[1] = psHu64(mem+8); - - out[0] = psHu64(0x6000); - out[1] = psHu64(0x6008); -} - -void __fastcall ReadFIFO_page_7(u32 mem, u64 *out) -{ - jASSUME( (mem >= 0x10007000) && (mem < 0x10008000) ); - - // All addresses in this page map to 0x7000 and 0x7010: - mem &= 0x10; - - if( mem == 0 ) - { - if( g_nIPU0Data > 0 ) - { - out[0] = *(u64*)(g_pIPU0Pointer); - out[1] = *(u64*)(g_pIPU0Pointer+8); - FOreadpos = (FOreadpos + 4) & 31; - g_nIPU0Data--; - g_pIPU0Pointer += 16; - } - } - else - FIFOfrom_readsingle((void*)out); -} - -////////////////////////////////////////////////////////////////////////// -// WriteFIFO Pages - -void __fastcall WriteFIFO_page_4(u32 mem, const mem128_t *value) -{ - jASSUME( (mem >= 0x10004000) && (mem < 0x10005000) ); - - VIF_LOG("WriteFIFO/VIF0, addr=0x%08X\n", mem); - - //psHu64(mem ) = value[0]; - //psHu64(mem+8) = value[1]; - - psHu64(0x4000) = value[0]; - psHu64(0x4008) = value[1]; - - vif0ch->qwc += 1; - int ret = VIF0transfer((u32*)value, 4, 0); - assert( ret == 0 ); // vif stall code not implemented -} - -void __fastcall WriteFIFO_page_5(u32 mem, const mem128_t *value) -{ - jASSUME( (mem >= 0x10005000) && (mem < 0x10006000) ); - - VIF_LOG("WriteFIFO/VIF1, addr=0x%08X\n", mem); - - //psHu64(mem ) = value[0]; - //psHu64(mem+8) = value[1]; - - psHu64(0x5000) = value[0]; - psHu64(0x5008) = value[1]; - - if(vif1Regs->stat & VIF1_STAT_FDR) - DevCon::Notice("writing to fifo when fdr is set!"); - if( vif1Regs->stat & (VIF1_STAT_INT|VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS) ) - DevCon::Notice("writing to vif1 fifo when stalled"); - - vif1ch->qwc += 1; - int ret = VIF1transfer((u32*)value, 4, 0); - assert( ret == 0 ); // vif stall code not implemented -} - -void __fastcall WriteFIFO_page_6(u32 mem, const mem128_t *value) -{ - jASSUME( (mem >= 0x10006000) && (mem < 0x10007000) ); - GIF_LOG("WriteFIFO/GIF, addr=0x%08X\n", mem); - - //psHu64(mem ) = value[0]; - //psHu64(mem+8) = value[1]; - - psHu64(0x6000) = value[0]; - psHu64(0x6008) = value[1]; - - if( mtgsThread != NULL ) - { - const uint count = mtgsThread->PrepDataPacket( GIF_PATH_3, value, 1 ); - jASSUME( count == 1 ); - u64* data = (u64*)mtgsThread->GetDataPacketPtr(); - data[0] = value[0]; - data[1] = value[1]; - mtgsThread->SendDataPacket(); - } - else - { - FreezeXMMRegs(1); - FreezeMMXRegs(1); - GSGIFTRANSFER3((u32*)value, 1); - FreezeMMXRegs(0); - FreezeXMMRegs(0); - } -} - -void __fastcall WriteFIFO_page_7(u32 mem, const mem128_t *value) -{ - jASSUME( (mem >= 0x10007000) && (mem < 0x10008000) ); - - // All addresses in this page map to 0x7000 and 0x7010: - mem &= 0x10; - - IPU_LOG( "WriteFIFO/IPU, addr=0x%x", params mem ); - - if( mem == 0 ) - { - // Should this raise a PS2 exception or just ignore silently? - Console::Notice( "WriteFIFO/IPUout (ignored)" ); - } - else - { - IPU_LOG("WriteFIFO IPU_in[%d] <- %8.8X_%8.8X_%8.8X_%8.8X\n", - mem/16, ((u32*)value)[3], ((u32*)value)[2], ((u32*)value)[1], ((u32*)value)[0]); - - //committing every 16 bytes - while( FIFOto_write((u32*)value, 1) == 0 ) - { - Console::WriteLn("IPU sleeping"); - Threading::Timeslice(); - } - } -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "Hw.h" +#include "GS.h" + +#include "Vif.h" +#include "VifDma.h" + +////////////////////////////////////////////////////////////////////////// +/////////////////////////// Quick & dirty FIFO :D //////////////////////// +////////////////////////////////////////////////////////////////////////// + +// ** NOTE: cannot use XMM/MMX regs ** + +// Notes on FIFO implementation +// +// The FIFO consists of four separate pages of HW register memory, each mapped to a +// PS2 device. They are listed as follows: +// +// 0x4000 - 0x5000 : VIF0 (all registers map to 0x4000) +// 0x5000 - 0x6000 : VIF1 (all registers map to 0x5000) +// 0x6000 - 0x7000 : GS (all registers map to 0x6000) +// 0x7000 - 0x8000 : IPU (registers map to 0x7000 and 0x7010, respectively) + +extern int FIFOto_write(u32* pMem, int size); +extern void FIFOfrom_readsingle(void *value); + +extern int g_nIPU0Data; +extern u8* g_pIPU0Pointer; +extern int FOreadpos; + +////////////////////////////////////////////////////////////////////////// +// ReadFIFO Pages + +void __fastcall ReadFIFO_page_4(u32 mem, u64 *out) +{ + jASSUME( (mem >= 0x10004000) && (mem < 0x10005000) ); + + VIF_LOG("ReadFIFO/VIF0 0x%08X\n", mem); + //out[0] = psHu64(mem ); + //out[1] = psHu64(mem+8); + + out[0] = psHu64(0x4000); + out[1] = psHu64(0x4008); +} + +void __fastcall ReadFIFO_page_5(u32 mem, u64 *out) +{ + jASSUME( (mem >= 0x10005000) && (mem < 0x10006000) ); + + VIF_LOG("ReadFIFO/VIF1, addr=0x%08X\n", mem); + + if( vif1Regs->stat & (VIF1_STAT_INT|VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS) ) + DevCon::Notice( "Reading from vif1 fifo when stalled" ); + + if (vif1Regs->stat & 0x800000) + { + if (--psHu32(D1_QWC) == 0) + vif1Regs->stat&= ~0x1f000000; + } + + //out[0] = psHu64(mem ); + //out[1] = psHu64(mem+8); + + out[0] = psHu64(0x5000); + out[1] = psHu64(0x5008); +} + +void __fastcall ReadFIFO_page_6(u32 mem, u64 *out) +{ + jASSUME( (mem >= 0x10006000) && (mem < 0x10007000) ); + + DevCon::Notice( "ReadFIFO/GIF, addr=0x%x", params mem ); + + //out[0] = psHu64(mem ); + //out[1] = psHu64(mem+8); + + out[0] = psHu64(0x6000); + out[1] = psHu64(0x6008); +} + +void __fastcall ReadFIFO_page_7(u32 mem, u64 *out) +{ + jASSUME( (mem >= 0x10007000) && (mem < 0x10008000) ); + + // All addresses in this page map to 0x7000 and 0x7010: + mem &= 0x10; + + if( mem == 0 ) + { + if( g_nIPU0Data > 0 ) + { + out[0] = *(u64*)(g_pIPU0Pointer); + out[1] = *(u64*)(g_pIPU0Pointer+8); + FOreadpos = (FOreadpos + 4) & 31; + g_nIPU0Data--; + g_pIPU0Pointer += 16; + } + } + else + FIFOfrom_readsingle((void*)out); +} + +////////////////////////////////////////////////////////////////////////// +// WriteFIFO Pages + +void __fastcall WriteFIFO_page_4(u32 mem, const mem128_t *value) +{ + jASSUME( (mem >= 0x10004000) && (mem < 0x10005000) ); + + VIF_LOG("WriteFIFO/VIF0, addr=0x%08X\n", mem); + + //psHu64(mem ) = value[0]; + //psHu64(mem+8) = value[1]; + + psHu64(0x4000) = value[0]; + psHu64(0x4008) = value[1]; + + vif0ch->qwc += 1; + int ret = VIF0transfer((u32*)value, 4, 0); + assert( ret == 0 ); // vif stall code not implemented +} + +void __fastcall WriteFIFO_page_5(u32 mem, const mem128_t *value) +{ + jASSUME( (mem >= 0x10005000) && (mem < 0x10006000) ); + + VIF_LOG("WriteFIFO/VIF1, addr=0x%08X\n", mem); + + //psHu64(mem ) = value[0]; + //psHu64(mem+8) = value[1]; + + psHu64(0x5000) = value[0]; + psHu64(0x5008) = value[1]; + + if(vif1Regs->stat & VIF1_STAT_FDR) + DevCon::Notice("writing to fifo when fdr is set!"); + if( vif1Regs->stat & (VIF1_STAT_INT|VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS) ) + DevCon::Notice("writing to vif1 fifo when stalled"); + + vif1ch->qwc += 1; + int ret = VIF1transfer((u32*)value, 4, 0); + assert( ret == 0 ); // vif stall code not implemented +} + +void __fastcall WriteFIFO_page_6(u32 mem, const mem128_t *value) +{ + jASSUME( (mem >= 0x10006000) && (mem < 0x10007000) ); + GIF_LOG("WriteFIFO/GIF, addr=0x%08X\n", mem); + + //psHu64(mem ) = value[0]; + //psHu64(mem+8) = value[1]; + + psHu64(0x6000) = value[0]; + psHu64(0x6008) = value[1]; + + if( mtgsThread != NULL ) + { + const uint count = mtgsThread->PrepDataPacket( GIF_PATH_3, value, 1 ); + jASSUME( count == 1 ); + u64* data = (u64*)mtgsThread->GetDataPacketPtr(); + data[0] = value[0]; + data[1] = value[1]; + mtgsThread->SendDataPacket(); + } + else + { + FreezeXMMRegs(1); + FreezeMMXRegs(1); + GSGIFTRANSFER3((u32*)value, 1); + FreezeMMXRegs(0); + FreezeXMMRegs(0); + } +} + +void __fastcall WriteFIFO_page_7(u32 mem, const mem128_t *value) +{ + jASSUME( (mem >= 0x10007000) && (mem < 0x10008000) ); + + // All addresses in this page map to 0x7000 and 0x7010: + mem &= 0x10; + + IPU_LOG( "WriteFIFO/IPU, addr=0x%x", params mem ); + + if( mem == 0 ) + { + // Should this raise a PS2 exception or just ignore silently? + Console::Notice( "WriteFIFO/IPUout (ignored)" ); + } + else + { + IPU_LOG("WriteFIFO IPU_in[%d] <- %8.8X_%8.8X_%8.8X_%8.8X\n", + mem/16, ((u32*)value)[3], ((u32*)value)[2], ((u32*)value)[1], ((u32*)value)[0]); + + //committing every 16 bytes + while( FIFOto_write((u32*)value, 1) == 0 ) + { + Console::WriteLn("IPU sleeping"); + Threading::Timeslice(); + } + } +} diff --git a/pcsx2/GS.cpp b/pcsx2/GS.cpp index a9fadacf97..a7a78cfb01 100644 --- a/pcsx2/GS.cpp +++ b/pcsx2/GS.cpp @@ -1,895 +1,895 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include - -#include "Common.h" -#include "GS.h" -#include "iR5900.h" -#include "Counters.h" - -#include "VifDma.h" - -using namespace Threading; -using namespace std; - -using namespace R5900; - -#ifdef DEBUG -#define MTGS_LOG SysPrintf -#else -#define MTGS_LOG 0&& -#endif - -static bool m_gsOpened = false; - -int g_FFXHack=0; - -#ifdef PCSX2_DEVBUILD - -// GS Playback -int g_SaveGSStream = 0; // save GS stream; 1 - prepare, 2 - save -int g_nLeftGSFrames = 0; // when saving, number of frames left -gzSavingState* g_fGSSave; - -void GSGIFTRANSFER1(u32 *pMem, u32 addr) { - if( g_SaveGSStream == 2) { - u32 type = GSRUN_TRANS1; - u32 size = (0x4000-(addr))/16; - g_fGSSave->Freeze( type ); - g_fGSSave->Freeze( size ); - g_fGSSave->FreezeMem( ((u8*)pMem)+(addr), size*16 ); - } - GSgifTransfer1(pMem, addr); -} - -void GSGIFTRANSFER2(u32 *pMem, u32 size) { - if( g_SaveGSStream == 2) { - u32 type = GSRUN_TRANS2; - u32 _size = size; - g_fGSSave->Freeze( type ); - g_fGSSave->Freeze( size ); - g_fGSSave->FreezeMem( pMem, _size*16 ); - } - GSgifTransfer2(pMem, size); -} - -void GSGIFTRANSFER3(u32 *pMem, u32 size) { - if( g_SaveGSStream == 2 ) { - u32 type = GSRUN_TRANS3; - u32 _size = size; - g_fGSSave->Freeze( type ); - g_fGSSave->Freeze( size ); - g_fGSSave->FreezeMem( pMem, _size*16 ); - } - GSgifTransfer3(pMem, size); -} - -__forceinline void GSVSYNC(void) { - if( g_SaveGSStream == 2 ) { - u32 type = GSRUN_VSYNC; - g_fGSSave->Freeze( type ); - } -} -#else - -__forceinline void GSGIFTRANSFER1(u32 *pMem, u32 addr) { - GSgifTransfer1(pMem, addr); -} - -__forceinline void GSGIFTRANSFER2(u32 *pMem, u32 size) { - GSgifTransfer2(pMem, size); -} - -__forceinline void GSGIFTRANSFER3(u32 *pMem, u32 size) { - GSgifTransfer3(pMem, size); -} - -__forceinline void GSVSYNC(void) { -} -#endif - -u32 CSRw; - -PCSX2_ALIGNED16( u8 g_RealGSMem[0x2000] ); -#define PS2GS_BASE(mem) (g_RealGSMem+(mem&0x13ff)) - -extern int m_nCounters[]; - -// FrameSkipping Stuff -// Yuck, iSlowStart is needed by the MTGS, so can't make it static yet. - -u64 m_iSlowStart=0; -static s64 m_iSlowTicks=0; -static bool m_justSkipped = false; -static bool m_StrictSkipping = false; - -void _gs_ChangeTimings( u32 framerate, u32 iTicks ) -{ - m_iSlowStart = GetCPUTicks(); - - u32 frameSkipThreshold = Config.CustomFrameSkip*50; - if( Config.CustomFrameSkip == 0) - { - // default: load the frameSkipThreshold with a value roughly 90% of our current framerate - frameSkipThreshold = ( framerate * 242 ) / 256; - } - - m_iSlowTicks = ( GetTickFrequency() * 50 ) / frameSkipThreshold; - - // sanity check against users who set a "minimum" frame that's higher - // than the maximum framerate. Also, if framerates are within 1/3300th - // of a second of each other, assume strict skipping (it's too close, - // and could cause excessive skipping). - - if( m_iSlowTicks <= (iTicks + ((s64)GetTickFrequency()/3300)) ) - { - m_iSlowTicks = iTicks; - m_StrictSkipping = true; - } -} - -void gsOnModeChanged( u32 framerate, u32 newTickrate ) -{ - if( mtgsThread != NULL ) - mtgsThread->SendSimplePacket( GS_RINGTYPE_MODECHANGE, framerate, newTickrate, 0 ); - else - _gs_ChangeTimings( framerate, newTickrate ); -} - -void gsSetVideoRegionType( u32 isPal ) -{ - if( isPal ) - { - if( Config.PsxType & 1 ) return; - Console::WriteLn( "PAL Display Mode Initialized." ); - Config.PsxType |= 1; - } - else - { - if( !(Config.PsxType & 1 ) ) return; - Console::WriteLn( "NTSC Display Mode Initialized." ); - Config.PsxType &= ~1; - } - - // If we made it this far it means the refresh rate changed, so update the vsync timers: - UpdateVSyncRate(); -} - - -// Make sure framelimiter options are in sync with the plugin's capabilities. -void gsInit() -{ - switch(CHECK_FRAMELIMIT) - { - case PCSX2_FRAMELIMIT_SKIP: - case PCSX2_FRAMELIMIT_VUSKIP: - if( GSsetFrameSkip == NULL ) - { - Config.Options &= ~PCSX2_FRAMELIMIT_MASK; - Console::WriteLn("Notice: Disabling frameskip -- GS plugin does not support it."); - } - break; - } -} - -// Opens the gsRingbuffer thread. -s32 gsOpen() -{ - if( m_gsOpened ) return 0; - - // mtgs overrides these as necessary... - GSsetBaseMem( PS2MEM_GS ); - GSirqCallback( gsIrq ); - - //video - // Only bind the gsIrq if we're not running the MTGS. - // The MTGS simulates its own gsIrq in order to maintain proper sync. - - m_gsOpened = mtgsOpen(); - if( !m_gsOpened ) - { - // MTGS failed to init or is disabled. Try the GS instead! - // ... and set the memptr again just in case (for switching between GS/MTGS on the fly) - - m_gsOpened = !GSopen((void *)&pDsp, "PCSX2", 0); - } - - /*if( m_gsOpened ) - { - gsOnModeChanged( - (Config.PsxType & 1) ? FRAMERATE_PAL : FRAMERATE_NTSC, - UpdateVSyncRate() - ); - }*/ - return !m_gsOpened; -} - -void gsClose() -{ - if( !m_gsOpened ) return; - m_gsOpened = false; - - // Throw an assert if our multigs setting and mtgsThread status - // aren't synched. It shouldn't break the code anyway but it's a - // bad coding habit that we should catch and fix early. - assert( !!CHECK_MULTIGS == (mtgsThread != NULL ) ); - - if( mtgsThread != NULL ) - { - mtgsThread->Close(); - safe_delete( mtgsThread ); - } - else - GSclose(); -} - -void gsReset() -{ - // Sanity check in case the plugin hasn't been initialized... - if( !m_gsOpened ) return; - - if( mtgsThread != NULL ) - mtgsThread->Reset(); - else - { - Console::Notice( "GIF reset" ); - GSreset(); - GSsetFrameSkip(0); - } - - gsOnModeChanged( - (Config.PsxType & 1) ? FRAMERATE_PAL : FRAMERATE_NTSC, - UpdateVSyncRate() - ); - - memzero_obj(g_RealGSMem); - - Path3transfer = 0; - - GSCSRr = 0x551B400F; // Set the FINISH bit to 1 for now - GSIMR = 0x7f00; - psHu32(GIF_STAT) = 0; - psHu32(GIF_CTRL) = 0; - psHu32(GIF_MODE) = 0; -} - -bool gsGIFSoftReset( int mask ) -{ - if( GSgifSoftReset == NULL ) - { - static bool warned = false; - if( !warned ) - { - Console::Notice( "GIF Warning > Soft reset requested, but the GS plugin doesn't support it!" ); - //warned = true; - } - return false; - } - - if( mtgsThread != NULL ) - mtgsThread->GIFSoftReset( mask ); - else - GSgifSoftReset( mask ); - - return true; -} - -void gsGIFReset() -{ - // fixme - should this be here? (air) - //memzero_obj(g_RealGSMem); - - // perform a soft reset (but do not do a full reset if the soft reset API is unavailable) - gsGIFSoftReset( 7 ); - - GSCSRr = 0x551B400F; // Set the FINISH bit to 1 for now - GSIMR = 0x7f00; - psHu32(GIF_STAT) = 0; - psHu32(GIF_CTRL) = 0; - psHu32(GIF_MODE) = 0; -} - -void gsCSRwrite(u32 value) -{ - CSRw |= value & ~0x60; - - if( mtgsThread != NULL ) - mtgsThread->SendSimplePacket( GS_RINGTYPE_WRITECSR, CSRw, 0, 0 ); - else - GSwriteCSR(CSRw); - - GSCSRr = ((GSCSRr&~value)&0x1f)|(GSCSRr&~0x1f); - - // Our emulated GS has no FIFO... - /*if( value & 0x100 ) { // FLUSH - //SysPrintf("GS_CSR FLUSH GS fifo: %x (CSRr=%x)\n", value, GSCSRr); - }*/ - - if (value & 0x200) { // resetGS - - // perform a soft reset -- and fall back to doing a full reset if the plugin doesn't - // support soft resets. - - if( !gsGIFSoftReset( 7 ) ) - { - if( mtgsThread != NULL ) - mtgsThread->SendSimplePacket( GS_RINGTYPE_RESET, 0, 0, 0 ); - else - GSreset(); - } - - GSCSRr = 0x551B400F; // Set the FINISH bit to 1 - GS is always at a finish state as we don't have a FIFO(saqib) - GSIMR = 0x7F00; //This is bits 14-8 thats all that should be 1 - } -} - -static void IMRwrite(u32 value) -{ - GSIMR = (value & 0x1f00)|0x6000; - - // don't update mtgs mem -} - -__forceinline void gsWrite8(u32 mem, u8 value) -{ - switch (mem) - { - case 0x12001000: // GS_CSR - gsCSRwrite((CSRw & ~0x000000ff) | value); break; - case 0x12001001: // GS_CSR - gsCSRwrite((CSRw & ~0x0000ff00) | (value << 8)); break; - case 0x12001002: // GS_CSR - gsCSRwrite((CSRw & ~0x00ff0000) | (value << 16)); break; - case 0x12001003: // GS_CSR - gsCSRwrite((CSRw & ~0xff000000) | (value << 24)); break; - default: - *PS2GS_BASE(mem) = value; - - if( mtgsThread != NULL ) - mtgsThread->SendSimplePacket(GS_RINGTYPE_MEMWRITE8, mem&0x13ff, value, 0); - } - GIF_LOG("GS write 8 at %8.8lx with data %8.8lx\n", mem, value); -} - -__forceinline void _gsSMODEwrite( u32 mem, u32 value ) -{ - switch (mem) - { - case GS_SMODE1: - gsSetVideoRegionType( (value & 0x6000) == 0x6000 ); - break; - - case GS_SMODE2: - if(value & 0x1) - Config.PsxType |= 2; // Interlaced - else - Config.PsxType &= ~2; // Non-Interlaced - break; - } -} - -////////////////////////////////////////////////////////////////////////// -// GS Write 16 bit - -__forceinline void gsWrite16(u32 mem, u16 value) -{ - GIF_LOG("GS write 16 at %8.8lx with data %8.8lx\n", mem, value); - - _gsSMODEwrite( mem, value ); - - switch (mem) - { - case GS_CSR: - gsCSRwrite( (CSRw&0xffff0000) | value); - return; // do not write to MTGS memory - - case GS_CSR+2: - gsCSRwrite( (CSRw&0xffff) | ((u32)value<<16)); - return; // do not write to MTGS memory - - case GS_IMR: - IMRwrite(value); - return; // do not write to MTGS memory - } - - *(u16*)PS2GS_BASE(mem) = value; - - if( mtgsThread != NULL ) - mtgsThread->SendSimplePacket(GS_RINGTYPE_MEMWRITE16, mem&0x13ff, value, 0); -} - -////////////////////////////////////////////////////////////////////////// -// GS Write 32 bit - -__forceinline void gsWrite32(u32 mem, u32 value) -{ - jASSUME( (mem & 3) == 0 ); - GIF_LOG("GS write 32 at %8.8lx with data %8.8lx\n", mem, value); - - _gsSMODEwrite( mem, value ); - - switch (mem) - { - case GS_CSR: - gsCSRwrite(value); - return; - - case GS_IMR: - IMRwrite(value); - return; - } - - *(u32*)PS2GS_BASE(mem) = value; - - if( mtgsThread != NULL ) - mtgsThread->SendSimplePacket(GS_RINGTYPE_MEMWRITE32, mem&0x13ff, value, 0); -} - -////////////////////////////////////////////////////////////////////////// -// GS Write 64 bit - -void __fastcall gsWrite64_page_00( u32 mem, const mem64_t* value ) -{ - gsWrite64_generic( mem, value ); - _gsSMODEwrite( mem, (u32)value[0] ); -} - -void __fastcall gsWrite64_page_01( u32 mem, const mem64_t* value ) -{ - switch( mem ) - { - case GS_CSR: - gsCSRwrite((u32)value[0]); - return; - - case GS_IMR: - IMRwrite((u32)value[0]); - return; - } - - gsWrite64_generic( mem, value ); -} - -void __fastcall gsWrite64_generic( u32 mem, const mem64_t* value ) -{ - const u32* const srcval32 = (u32*)value; - GIF_LOG("GS Write64 at %8.8lx with data %8.8x_%8.8x\n", mem, srcval32[1], srcval32[0]); - - *(u64*)PS2GS_BASE(mem) = *value; - - if( mtgsThread != NULL ) - mtgsThread->SendSimplePacket(GS_RINGTYPE_MEMWRITE64, mem&0x13ff, srcval32[0], srcval32[1]); -} - -////////////////////////////////////////////////////////////////////////// -// GS Write 128 bit - -void __fastcall gsWrite128_page_00( u32 mem, const mem128_t* value ) -{ - gsWrite128_generic( mem, value ); - _gsSMODEwrite( mem, (u32)value[0] ); -} - -void __fastcall gsWrite128_page_01( u32 mem, const mem128_t* value ) -{ - switch( mem ) - { - case GS_CSR: - gsCSRwrite((u32)value[0]); - return; - - case GS_IMR: - IMRwrite((u32)value[0]); - return; - } - - gsWrite128_generic( mem, value ); -} - -void __fastcall gsWrite128_generic( u32 mem, const mem128_t* value ) -{ - const u32* const srcval32 = (u32*)value; - - GIF_LOG("GS Write64 at %8.8lx with data %8.8x_%8.8x_%8.8x_%8.8x \n", mem, - srcval32[3], srcval32[2], srcval32[1], srcval32[0]); - - const uint masked_mem = mem & 0x13ff; - u64* writeTo = (u64*)(&g_RealGSMem[masked_mem]); - - writeTo[0] = value[0]; - writeTo[1] = value[1]; - - if( mtgsThread != NULL ) - { - mtgsThread->SendSimplePacket(GS_RINGTYPE_MEMWRITE64, masked_mem, srcval32[0], srcval32[1]); - mtgsThread->SendSimplePacket(GS_RINGTYPE_MEMWRITE64, masked_mem+8, srcval32[2], srcval32[3]); - } -} - -#if 0 -// This function is left in for now for debugging/reference purposes. -__forceinline void gsWrite64(u32 mem, u64 value) -{ - GIF_LOG("GS write 64 at %8.8lx with data %8.8lx_%8.8lx\n", mem, ((u32*)&value)[1], (u32)value); - - switch (mem) - { - case 0x12000010: // GS_SMODE1 - gsSetVideoRegionType( (value & 0x6000) == 0x6000 ); - break; - - case 0x12000020: // GS_SMODE2 - if(value & 0x1) Config.PsxType |= 2; // Interlaced - else Config.PsxType &= ~2; // Non-Interlaced - break; - - case 0x12001000: // GS_CSR - gsCSRwrite((u32)value); - return; - - case 0x12001010: // GS_IMR - IMRwrite((u32)value); - return; - } - - *(u64*)PS2GS_BASE(mem) = value; - - if( mtgsThread != NULL ) - mtgsThread->SendSimplePacket(GS_RINGTYPE_MEMWRITE64, mem&0x13ff, (u32)value, (u32)(value>>32)); -} -#endif - -__forceinline u8 gsRead8(u32 mem) -{ - GIF_LOG("GS read 8 from %8.8lx value: %8.8lx\n", mem, *(u8*)PS2GS_BASE(mem)); - return *(u8*)PS2GS_BASE(mem); -} - -__forceinline u16 gsRead16(u32 mem) -{ - GIF_LOG("GS read 16 from %8.8lx value: %8.8lx\n", mem, *(u16*)PS2GS_BASE(mem)); - return *(u16*)PS2GS_BASE(mem); -} - -__forceinline u32 gsRead32(u32 mem) -{ - GIF_LOG("GS read 32 from %8.8lx value: %8.8lx\n", mem, *(u32*)PS2GS_BASE(mem)); - return *(u32*)PS2GS_BASE(mem); -} - -__forceinline u64 gsRead64(u32 mem) -{ - GIF_LOG("GS read 64 from %8.8lx value: %8.8lx_%8.8lx\n", mem, *(u32*)PS2GS_BASE(mem+4), *(u32*)PS2GS_BASE(mem) ); - return *(u64*)PS2GS_BASE(mem); -} - -void gsIrq() { - hwIntcIrq(0); -} - -void gsSyncLimiterLostTime( s32 deltaTime ) -{ - // This sync issue applies only to configs that are trying to maintain - // a perfect "specific" framerate (where both min and max fps are the same) - // any other config will eventually equalize out. - - if( !m_StrictSkipping ) return; - - //SysPrintf("LostTime on the EE!\n"); - - if( mtgsThread != NULL ) - { - mtgsThread->SendSimplePacket( - GS_RINGTYPE_STARTTIME, - deltaTime, - 0, - 0 - ); - } - else - { - m_iSlowStart += deltaTime; - //m_justSkipped = false; - } -} - -// FrameSkipper - Measures delta time between calls and issues frameskips -// it the time is too long. Also regulates the status of the EE's framelimiter. - -// This function does not regulate frame limiting, meaning it does no stalling. -// Stalling functions are performed by the EE: If the MTGS were throtted and not -// the EE, the EE would fill the ringbuffer while the MTGS regulated frames -- -// fine for most situations but could result in literally dozens of frames queued -// up in the ringbuffer durimg some game menu screens; which in turn would result -// in a half-second lag of keystroke actions becoming visible to the user (bad!). - -// Alternative: Instead of this, I could have everything regulated here, and then -// put a framecount limit on the MTGS ringbuffer. But that seems no less complicated -// and would also mean that aforementioned menus would still be laggy by whatever -// frame count threshold. This method is more responsive. - -__forceinline void gsFrameSkip( bool forceskip ) -{ - static u8 FramesToRender = 0; - static u8 FramesToSkip = 0; - - if( CHECK_FRAMELIMIT != PCSX2_FRAMELIMIT_SKIP && - CHECK_FRAMELIMIT != PCSX2_FRAMELIMIT_VUSKIP ) return; - - // FrameSkip and VU-Skip Magic! - // Skips a sequence of consecutive frames after a sequence of rendered frames - - // This is the least number of consecutive frames we will render w/o skipping - const int noSkipFrames = ((Config.CustomConsecutiveFrames>0) ? Config.CustomConsecutiveFrames : 1); - // This is the number of consecutive frames we will skip - const int yesSkipFrames = ((Config.CustomConsecutiveSkip>0) ? Config.CustomConsecutiveSkip : 1); - - const u64 iEnd = GetCPUTicks(); - const s64 uSlowExpectedEnd = m_iSlowStart + m_iSlowTicks; - const s64 sSlowDeltaTime = iEnd - uSlowExpectedEnd; - - m_iSlowStart = uSlowExpectedEnd; - - if( forceskip ) - { - if( !FramesToSkip ) - { - //Console::Status( "- Skipping some VUs!" ); - - GSsetFrameSkip( 1 ); - FramesToRender = noSkipFrames; - FramesToSkip = 1; // just set to 1 - - // We're already skipping, so FramesToSkip==1 will just restore the gsFrameSkip - // setting and reset our delta times as needed. - } - return; - } - - // if we've already given the EE a skipcount assignment then don't do anything more. - // Otherwise we could start compounding the issue and skips would be too long. - if( g_vu1SkipCount > 0 ) - { - //Console::Status("- Already Assigned a Skipcount.. %d", params g_vu1SkipCount ); - return; - } - - if( FramesToRender == 0 ) - { - // -- Standard operation section -- - // Means neither skipping frames nor force-rendering consecutive frames. - - if( sSlowDeltaTime > 0 ) - { - // The game is running below the minimum framerate. - // But don't start skipping yet! That would be too sensitive. - // So the skipping code is only engaged if the SlowDeltaTime falls behind by - // a full frame, or if we're already skipping (in which case we don't care - // to avoid errant skips). - - // Note: The MTGS can go out of phase from the EE, which means that the - // variance for a "nominal" framerate can range from 0 to m_iSlowTicks. - // We also check for that here. - - if( (m_justSkipped && (sSlowDeltaTime > m_iSlowTicks)) || - (sSlowDeltaTime > m_iSlowTicks*2) ) - { - //Console::Status( "Frameskip Initiated! Lateness: %d", params (int)( (sSlowDeltaTime*100) / m_iSlowTicks ) ); - - if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_VUSKIP ) - { - // For best results we have to wait for the EE to - // tell us when to skip, so that VU skips are synched with GS skips. - AtomicExchangeAdd( g_vu1SkipCount, yesSkipFrames+1 ); - } - else - { - GSsetFrameSkip(1); - FramesToRender = noSkipFrames+1; - FramesToSkip = yesSkipFrames; - } - } - } - else - { - // Running at or above full speed, so reset the StartTime since the Limiter - // will muck things up. (special case: if skip and limit fps are equal then - // we don't reset starttime since it would cause desyncing. We let the EE - // regulate it via calls to gsSyncLimiterStartTime). - - if( !m_StrictSkipping ) - m_iSlowStart = iEnd; - } - m_justSkipped = false; - return; - } - else if( FramesToSkip > 0 ) - { - // -- Frames-a-Skippin' Section -- - - FramesToSkip--; - - if( FramesToSkip == 0 ) - { - // Skipped our last frame, so restore non-skip behavior - - GSsetFrameSkip(0); - - // Note: If we lag behind by 250ms then it's time to give up on the idea - // of catching up. Force the game to slow down by resetting iStart to - // something closer to iEnd. - - if( sSlowDeltaTime > (m_iSlowTicks + ((s64)GetTickFrequency() / 4)) ) - { - //Console::Status( "Frameskip couldn't skip enough -- had to lose some time!" ); - m_iSlowStart = iEnd - m_iSlowTicks; - } - - m_justSkipped = true; - } - else - return; - } - - //SysPrintf( "Consecutive Frames -- Lateness: %d\n", (int)( sSlowDeltaTime / m_iSlowTicks ) ); - - // -- Consecutive frames section -- - // Force-render consecutive frames without skipping. - - FramesToRender--; - - if( sSlowDeltaTime < 0 ) - { - m_iSlowStart = iEnd; - } -} - -// updategs - if FALSE the gs will skip the frame. -void gsPostVsyncEnd( bool updategs ) -{ - *(u32*)(PS2MEM_GS+0x1000) ^= 0x2000; // swap the vsync field - - if( mtgsThread != NULL ) - { - mtgsThread->SendSimplePacket( GS_RINGTYPE_VSYNC, - (*(u32*)(PS2MEM_GS+0x1000)&0x2000), updategs, 0); - - // No need to freeze MMX/XMM registers here since this - // code is always called from the context of a BranchTest. - mtgsThread->SetEvent(); - } - else - { - GSvsync((*(u32*)(PS2MEM_GS+0x1000)&0x2000)); - - // update here on single thread mode *OBSOLETE* - if( PAD1update != NULL ) PAD1update(0); - if( PAD2update != NULL ) PAD2update(1); - - gsFrameSkip( !updategs ); - } -} - -void _gs_ResetFrameskip() -{ - g_vu1SkipCount = 0; // set to 0 so that EE will re-enable the VU at the next vblank. - GSsetFrameSkip( 0 ); -} - -// Disables the GS Frameskip at runtime without any racy mess... -void gsResetFrameSkip() -{ - if( mtgsThread != NULL ) - mtgsThread->SendSimplePacket(GS_RINGTYPE_FRAMESKIP, 0, 0, 0); - else - _gs_ResetFrameskip(); -} - -void gsDynamicSkipEnable() -{ - if( !m_StrictSkipping ) return; - - mtgsWaitGS(); - m_iSlowStart = GetCPUTicks(); - frameLimitReset(); -} - -void SaveState::gsFreeze() -{ - FreezeMem(PS2MEM_GS, 0x2000); - Freeze(CSRw); - mtgsFreeze(); -} - -#ifdef PCSX2_DEVBUILD - -struct GSStatePacket -{ - u32 type; - vector mem; -}; - -// runs the GS -void RunGSState( gzLoadingState& f ) -{ - u32 newfield; - list< GSStatePacket > packets; - - while( !f.Finished() ) - { - int type, size; - f.Freeze( type ); - - if( type != GSRUN_VSYNC ) f.Freeze( size ); - - packets.push_back(GSStatePacket()); - GSStatePacket& p = packets.back(); - - p.type = type; - - if( type != GSRUN_VSYNC ) { - p.mem.resize(size*16); - f.FreezeMem( &p.mem[0], size*16 ); - } - } - - list::iterator it = packets.begin(); - g_SaveGSStream = 3; - - int skipfirst = 1; - - // first extract the data - while(1) { - - switch(it->type) { - case GSRUN_TRANS1: - GSgifTransfer1((u32*)&it->mem[0], 0); - break; - case GSRUN_TRANS2: - GSgifTransfer2((u32*)&it->mem[0], it->mem.size()/16); - break; - case GSRUN_TRANS3: - GSgifTransfer3((u32*)&it->mem[0], it->mem.size()/16); - break; - case GSRUN_VSYNC: - // flip - newfield = (*(u32*)(PS2MEM_GS+0x1000)&0x2000) ? 0 : 0x2000; - *(u32*)(PS2MEM_GS+0x1000) = (*(u32*)(PS2MEM_GS+0x1000) & ~(1<<13)) | newfield; - - GSvsync(newfield); - SysUpdate(); - - if( g_SaveGSStream != 3 ) - return; - break; - - jNO_DEFAULT - } - - ++it; - if( it == packets.end() ) - it = packets.begin(); - } -} - -#endif - -#undef GIFchain +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include + +#include "Common.h" +#include "GS.h" +#include "iR5900.h" +#include "Counters.h" + +#include "VifDma.h" + +using namespace Threading; +using namespace std; + +using namespace R5900; + +#ifdef DEBUG +#define MTGS_LOG SysPrintf +#else +#define MTGS_LOG 0&& +#endif + +static bool m_gsOpened = false; + +int g_FFXHack=0; + +#ifdef PCSX2_DEVBUILD + +// GS Playback +int g_SaveGSStream = 0; // save GS stream; 1 - prepare, 2 - save +int g_nLeftGSFrames = 0; // when saving, number of frames left +gzSavingState* g_fGSSave; + +void GSGIFTRANSFER1(u32 *pMem, u32 addr) { + if( g_SaveGSStream == 2) { + u32 type = GSRUN_TRANS1; + u32 size = (0x4000-(addr))/16; + g_fGSSave->Freeze( type ); + g_fGSSave->Freeze( size ); + g_fGSSave->FreezeMem( ((u8*)pMem)+(addr), size*16 ); + } + GSgifTransfer1(pMem, addr); +} + +void GSGIFTRANSFER2(u32 *pMem, u32 size) { + if( g_SaveGSStream == 2) { + u32 type = GSRUN_TRANS2; + u32 _size = size; + g_fGSSave->Freeze( type ); + g_fGSSave->Freeze( size ); + g_fGSSave->FreezeMem( pMem, _size*16 ); + } + GSgifTransfer2(pMem, size); +} + +void GSGIFTRANSFER3(u32 *pMem, u32 size) { + if( g_SaveGSStream == 2 ) { + u32 type = GSRUN_TRANS3; + u32 _size = size; + g_fGSSave->Freeze( type ); + g_fGSSave->Freeze( size ); + g_fGSSave->FreezeMem( pMem, _size*16 ); + } + GSgifTransfer3(pMem, size); +} + +__forceinline void GSVSYNC(void) { + if( g_SaveGSStream == 2 ) { + u32 type = GSRUN_VSYNC; + g_fGSSave->Freeze( type ); + } +} +#else + +__forceinline void GSGIFTRANSFER1(u32 *pMem, u32 addr) { + GSgifTransfer1(pMem, addr); +} + +__forceinline void GSGIFTRANSFER2(u32 *pMem, u32 size) { + GSgifTransfer2(pMem, size); +} + +__forceinline void GSGIFTRANSFER3(u32 *pMem, u32 size) { + GSgifTransfer3(pMem, size); +} + +__forceinline void GSVSYNC(void) { +} +#endif + +u32 CSRw; + +PCSX2_ALIGNED16( u8 g_RealGSMem[0x2000] ); +#define PS2GS_BASE(mem) (g_RealGSMem+(mem&0x13ff)) + +extern int m_nCounters[]; + +// FrameSkipping Stuff +// Yuck, iSlowStart is needed by the MTGS, so can't make it static yet. + +u64 m_iSlowStart=0; +static s64 m_iSlowTicks=0; +static bool m_justSkipped = false; +static bool m_StrictSkipping = false; + +void _gs_ChangeTimings( u32 framerate, u32 iTicks ) +{ + m_iSlowStart = GetCPUTicks(); + + u32 frameSkipThreshold = Config.CustomFrameSkip*50; + if( Config.CustomFrameSkip == 0) + { + // default: load the frameSkipThreshold with a value roughly 90% of our current framerate + frameSkipThreshold = ( framerate * 242 ) / 256; + } + + m_iSlowTicks = ( GetTickFrequency() * 50 ) / frameSkipThreshold; + + // sanity check against users who set a "minimum" frame that's higher + // than the maximum framerate. Also, if framerates are within 1/3300th + // of a second of each other, assume strict skipping (it's too close, + // and could cause excessive skipping). + + if( m_iSlowTicks <= (iTicks + ((s64)GetTickFrequency()/3300)) ) + { + m_iSlowTicks = iTicks; + m_StrictSkipping = true; + } +} + +void gsOnModeChanged( u32 framerate, u32 newTickrate ) +{ + if( mtgsThread != NULL ) + mtgsThread->SendSimplePacket( GS_RINGTYPE_MODECHANGE, framerate, newTickrate, 0 ); + else + _gs_ChangeTimings( framerate, newTickrate ); +} + +void gsSetVideoRegionType( u32 isPal ) +{ + if( isPal ) + { + if( Config.PsxType & 1 ) return; + Console::WriteLn( "PAL Display Mode Initialized." ); + Config.PsxType |= 1; + } + else + { + if( !(Config.PsxType & 1 ) ) return; + Console::WriteLn( "NTSC Display Mode Initialized." ); + Config.PsxType &= ~1; + } + + // If we made it this far it means the refresh rate changed, so update the vsync timers: + UpdateVSyncRate(); +} + + +// Make sure framelimiter options are in sync with the plugin's capabilities. +void gsInit() +{ + switch(CHECK_FRAMELIMIT) + { + case PCSX2_FRAMELIMIT_SKIP: + case PCSX2_FRAMELIMIT_VUSKIP: + if( GSsetFrameSkip == NULL ) + { + Config.Options &= ~PCSX2_FRAMELIMIT_MASK; + Console::WriteLn("Notice: Disabling frameskip -- GS plugin does not support it."); + } + break; + } +} + +// Opens the gsRingbuffer thread. +s32 gsOpen() +{ + if( m_gsOpened ) return 0; + + // mtgs overrides these as necessary... + GSsetBaseMem( PS2MEM_GS ); + GSirqCallback( gsIrq ); + + //video + // Only bind the gsIrq if we're not running the MTGS. + // The MTGS simulates its own gsIrq in order to maintain proper sync. + + m_gsOpened = mtgsOpen(); + if( !m_gsOpened ) + { + // MTGS failed to init or is disabled. Try the GS instead! + // ... and set the memptr again just in case (for switching between GS/MTGS on the fly) + + m_gsOpened = !GSopen((void *)&pDsp, "PCSX2", 0); + } + + /*if( m_gsOpened ) + { + gsOnModeChanged( + (Config.PsxType & 1) ? FRAMERATE_PAL : FRAMERATE_NTSC, + UpdateVSyncRate() + ); + }*/ + return !m_gsOpened; +} + +void gsClose() +{ + if( !m_gsOpened ) return; + m_gsOpened = false; + + // Throw an assert if our multigs setting and mtgsThread status + // aren't synched. It shouldn't break the code anyway but it's a + // bad coding habit that we should catch and fix early. + assert( !!CHECK_MULTIGS == (mtgsThread != NULL ) ); + + if( mtgsThread != NULL ) + { + mtgsThread->Close(); + safe_delete( mtgsThread ); + } + else + GSclose(); +} + +void gsReset() +{ + // Sanity check in case the plugin hasn't been initialized... + if( !m_gsOpened ) return; + + if( mtgsThread != NULL ) + mtgsThread->Reset(); + else + { + Console::Notice( "GIF reset" ); + GSreset(); + GSsetFrameSkip(0); + } + + gsOnModeChanged( + (Config.PsxType & 1) ? FRAMERATE_PAL : FRAMERATE_NTSC, + UpdateVSyncRate() + ); + + memzero_obj(g_RealGSMem); + + Path3transfer = 0; + + GSCSRr = 0x551B400F; // Set the FINISH bit to 1 for now + GSIMR = 0x7f00; + psHu32(GIF_STAT) = 0; + psHu32(GIF_CTRL) = 0; + psHu32(GIF_MODE) = 0; +} + +bool gsGIFSoftReset( int mask ) +{ + if( GSgifSoftReset == NULL ) + { + static bool warned = false; + if( !warned ) + { + Console::Notice( "GIF Warning > Soft reset requested, but the GS plugin doesn't support it!" ); + //warned = true; + } + return false; + } + + if( mtgsThread != NULL ) + mtgsThread->GIFSoftReset( mask ); + else + GSgifSoftReset( mask ); + + return true; +} + +void gsGIFReset() +{ + // fixme - should this be here? (air) + //memzero_obj(g_RealGSMem); + + // perform a soft reset (but do not do a full reset if the soft reset API is unavailable) + gsGIFSoftReset( 7 ); + + GSCSRr = 0x551B400F; // Set the FINISH bit to 1 for now + GSIMR = 0x7f00; + psHu32(GIF_STAT) = 0; + psHu32(GIF_CTRL) = 0; + psHu32(GIF_MODE) = 0; +} + +void gsCSRwrite(u32 value) +{ + CSRw |= value & ~0x60; + + if( mtgsThread != NULL ) + mtgsThread->SendSimplePacket( GS_RINGTYPE_WRITECSR, CSRw, 0, 0 ); + else + GSwriteCSR(CSRw); + + GSCSRr = ((GSCSRr&~value)&0x1f)|(GSCSRr&~0x1f); + + // Our emulated GS has no FIFO... + /*if( value & 0x100 ) { // FLUSH + //SysPrintf("GS_CSR FLUSH GS fifo: %x (CSRr=%x)\n", value, GSCSRr); + }*/ + + if (value & 0x200) { // resetGS + + // perform a soft reset -- and fall back to doing a full reset if the plugin doesn't + // support soft resets. + + if( !gsGIFSoftReset( 7 ) ) + { + if( mtgsThread != NULL ) + mtgsThread->SendSimplePacket( GS_RINGTYPE_RESET, 0, 0, 0 ); + else + GSreset(); + } + + GSCSRr = 0x551B400F; // Set the FINISH bit to 1 - GS is always at a finish state as we don't have a FIFO(saqib) + GSIMR = 0x7F00; //This is bits 14-8 thats all that should be 1 + } +} + +static void IMRwrite(u32 value) +{ + GSIMR = (value & 0x1f00)|0x6000; + + // don't update mtgs mem +} + +__forceinline void gsWrite8(u32 mem, u8 value) +{ + switch (mem) + { + case 0x12001000: // GS_CSR + gsCSRwrite((CSRw & ~0x000000ff) | value); break; + case 0x12001001: // GS_CSR + gsCSRwrite((CSRw & ~0x0000ff00) | (value << 8)); break; + case 0x12001002: // GS_CSR + gsCSRwrite((CSRw & ~0x00ff0000) | (value << 16)); break; + case 0x12001003: // GS_CSR + gsCSRwrite((CSRw & ~0xff000000) | (value << 24)); break; + default: + *PS2GS_BASE(mem) = value; + + if( mtgsThread != NULL ) + mtgsThread->SendSimplePacket(GS_RINGTYPE_MEMWRITE8, mem&0x13ff, value, 0); + } + GIF_LOG("GS write 8 at %8.8lx with data %8.8lx\n", mem, value); +} + +__forceinline void _gsSMODEwrite( u32 mem, u32 value ) +{ + switch (mem) + { + case GS_SMODE1: + gsSetVideoRegionType( (value & 0x6000) == 0x6000 ); + break; + + case GS_SMODE2: + if(value & 0x1) + Config.PsxType |= 2; // Interlaced + else + Config.PsxType &= ~2; // Non-Interlaced + break; + } +} + +////////////////////////////////////////////////////////////////////////// +// GS Write 16 bit + +__forceinline void gsWrite16(u32 mem, u16 value) +{ + GIF_LOG("GS write 16 at %8.8lx with data %8.8lx\n", mem, value); + + _gsSMODEwrite( mem, value ); + + switch (mem) + { + case GS_CSR: + gsCSRwrite( (CSRw&0xffff0000) | value); + return; // do not write to MTGS memory + + case GS_CSR+2: + gsCSRwrite( (CSRw&0xffff) | ((u32)value<<16)); + return; // do not write to MTGS memory + + case GS_IMR: + IMRwrite(value); + return; // do not write to MTGS memory + } + + *(u16*)PS2GS_BASE(mem) = value; + + if( mtgsThread != NULL ) + mtgsThread->SendSimplePacket(GS_RINGTYPE_MEMWRITE16, mem&0x13ff, value, 0); +} + +////////////////////////////////////////////////////////////////////////// +// GS Write 32 bit + +__forceinline void gsWrite32(u32 mem, u32 value) +{ + jASSUME( (mem & 3) == 0 ); + GIF_LOG("GS write 32 at %8.8lx with data %8.8lx\n", mem, value); + + _gsSMODEwrite( mem, value ); + + switch (mem) + { + case GS_CSR: + gsCSRwrite(value); + return; + + case GS_IMR: + IMRwrite(value); + return; + } + + *(u32*)PS2GS_BASE(mem) = value; + + if( mtgsThread != NULL ) + mtgsThread->SendSimplePacket(GS_RINGTYPE_MEMWRITE32, mem&0x13ff, value, 0); +} + +////////////////////////////////////////////////////////////////////////// +// GS Write 64 bit + +void __fastcall gsWrite64_page_00( u32 mem, const mem64_t* value ) +{ + gsWrite64_generic( mem, value ); + _gsSMODEwrite( mem, (u32)value[0] ); +} + +void __fastcall gsWrite64_page_01( u32 mem, const mem64_t* value ) +{ + switch( mem ) + { + case GS_CSR: + gsCSRwrite((u32)value[0]); + return; + + case GS_IMR: + IMRwrite((u32)value[0]); + return; + } + + gsWrite64_generic( mem, value ); +} + +void __fastcall gsWrite64_generic( u32 mem, const mem64_t* value ) +{ + const u32* const srcval32 = (u32*)value; + GIF_LOG("GS Write64 at %8.8lx with data %8.8x_%8.8x\n", mem, srcval32[1], srcval32[0]); + + *(u64*)PS2GS_BASE(mem) = *value; + + if( mtgsThread != NULL ) + mtgsThread->SendSimplePacket(GS_RINGTYPE_MEMWRITE64, mem&0x13ff, srcval32[0], srcval32[1]); +} + +////////////////////////////////////////////////////////////////////////// +// GS Write 128 bit + +void __fastcall gsWrite128_page_00( u32 mem, const mem128_t* value ) +{ + gsWrite128_generic( mem, value ); + _gsSMODEwrite( mem, (u32)value[0] ); +} + +void __fastcall gsWrite128_page_01( u32 mem, const mem128_t* value ) +{ + switch( mem ) + { + case GS_CSR: + gsCSRwrite((u32)value[0]); + return; + + case GS_IMR: + IMRwrite((u32)value[0]); + return; + } + + gsWrite128_generic( mem, value ); +} + +void __fastcall gsWrite128_generic( u32 mem, const mem128_t* value ) +{ + const u32* const srcval32 = (u32*)value; + + GIF_LOG("GS Write64 at %8.8lx with data %8.8x_%8.8x_%8.8x_%8.8x \n", mem, + srcval32[3], srcval32[2], srcval32[1], srcval32[0]); + + const uint masked_mem = mem & 0x13ff; + u64* writeTo = (u64*)(&g_RealGSMem[masked_mem]); + + writeTo[0] = value[0]; + writeTo[1] = value[1]; + + if( mtgsThread != NULL ) + { + mtgsThread->SendSimplePacket(GS_RINGTYPE_MEMWRITE64, masked_mem, srcval32[0], srcval32[1]); + mtgsThread->SendSimplePacket(GS_RINGTYPE_MEMWRITE64, masked_mem+8, srcval32[2], srcval32[3]); + } +} + +#if 0 +// This function is left in for now for debugging/reference purposes. +__forceinline void gsWrite64(u32 mem, u64 value) +{ + GIF_LOG("GS write 64 at %8.8lx with data %8.8lx_%8.8lx\n", mem, ((u32*)&value)[1], (u32)value); + + switch (mem) + { + case 0x12000010: // GS_SMODE1 + gsSetVideoRegionType( (value & 0x6000) == 0x6000 ); + break; + + case 0x12000020: // GS_SMODE2 + if(value & 0x1) Config.PsxType |= 2; // Interlaced + else Config.PsxType &= ~2; // Non-Interlaced + break; + + case 0x12001000: // GS_CSR + gsCSRwrite((u32)value); + return; + + case 0x12001010: // GS_IMR + IMRwrite((u32)value); + return; + } + + *(u64*)PS2GS_BASE(mem) = value; + + if( mtgsThread != NULL ) + mtgsThread->SendSimplePacket(GS_RINGTYPE_MEMWRITE64, mem&0x13ff, (u32)value, (u32)(value>>32)); +} +#endif + +__forceinline u8 gsRead8(u32 mem) +{ + GIF_LOG("GS read 8 from %8.8lx value: %8.8lx\n", mem, *(u8*)PS2GS_BASE(mem)); + return *(u8*)PS2GS_BASE(mem); +} + +__forceinline u16 gsRead16(u32 mem) +{ + GIF_LOG("GS read 16 from %8.8lx value: %8.8lx\n", mem, *(u16*)PS2GS_BASE(mem)); + return *(u16*)PS2GS_BASE(mem); +} + +__forceinline u32 gsRead32(u32 mem) +{ + GIF_LOG("GS read 32 from %8.8lx value: %8.8lx\n", mem, *(u32*)PS2GS_BASE(mem)); + return *(u32*)PS2GS_BASE(mem); +} + +__forceinline u64 gsRead64(u32 mem) +{ + GIF_LOG("GS read 64 from %8.8lx value: %8.8lx_%8.8lx\n", mem, *(u32*)PS2GS_BASE(mem+4), *(u32*)PS2GS_BASE(mem) ); + return *(u64*)PS2GS_BASE(mem); +} + +void gsIrq() { + hwIntcIrq(0); +} + +void gsSyncLimiterLostTime( s32 deltaTime ) +{ + // This sync issue applies only to configs that are trying to maintain + // a perfect "specific" framerate (where both min and max fps are the same) + // any other config will eventually equalize out. + + if( !m_StrictSkipping ) return; + + //SysPrintf("LostTime on the EE!\n"); + + if( mtgsThread != NULL ) + { + mtgsThread->SendSimplePacket( + GS_RINGTYPE_STARTTIME, + deltaTime, + 0, + 0 + ); + } + else + { + m_iSlowStart += deltaTime; + //m_justSkipped = false; + } +} + +// FrameSkipper - Measures delta time between calls and issues frameskips +// it the time is too long. Also regulates the status of the EE's framelimiter. + +// This function does not regulate frame limiting, meaning it does no stalling. +// Stalling functions are performed by the EE: If the MTGS were throtted and not +// the EE, the EE would fill the ringbuffer while the MTGS regulated frames -- +// fine for most situations but could result in literally dozens of frames queued +// up in the ringbuffer durimg some game menu screens; which in turn would result +// in a half-second lag of keystroke actions becoming visible to the user (bad!). + +// Alternative: Instead of this, I could have everything regulated here, and then +// put a framecount limit on the MTGS ringbuffer. But that seems no less complicated +// and would also mean that aforementioned menus would still be laggy by whatever +// frame count threshold. This method is more responsive. + +__forceinline void gsFrameSkip( bool forceskip ) +{ + static u8 FramesToRender = 0; + static u8 FramesToSkip = 0; + + if( CHECK_FRAMELIMIT != PCSX2_FRAMELIMIT_SKIP && + CHECK_FRAMELIMIT != PCSX2_FRAMELIMIT_VUSKIP ) return; + + // FrameSkip and VU-Skip Magic! + // Skips a sequence of consecutive frames after a sequence of rendered frames + + // This is the least number of consecutive frames we will render w/o skipping + const int noSkipFrames = ((Config.CustomConsecutiveFrames>0) ? Config.CustomConsecutiveFrames : 1); + // This is the number of consecutive frames we will skip + const int yesSkipFrames = ((Config.CustomConsecutiveSkip>0) ? Config.CustomConsecutiveSkip : 1); + + const u64 iEnd = GetCPUTicks(); + const s64 uSlowExpectedEnd = m_iSlowStart + m_iSlowTicks; + const s64 sSlowDeltaTime = iEnd - uSlowExpectedEnd; + + m_iSlowStart = uSlowExpectedEnd; + + if( forceskip ) + { + if( !FramesToSkip ) + { + //Console::Status( "- Skipping some VUs!" ); + + GSsetFrameSkip( 1 ); + FramesToRender = noSkipFrames; + FramesToSkip = 1; // just set to 1 + + // We're already skipping, so FramesToSkip==1 will just restore the gsFrameSkip + // setting and reset our delta times as needed. + } + return; + } + + // if we've already given the EE a skipcount assignment then don't do anything more. + // Otherwise we could start compounding the issue and skips would be too long. + if( g_vu1SkipCount > 0 ) + { + //Console::Status("- Already Assigned a Skipcount.. %d", params g_vu1SkipCount ); + return; + } + + if( FramesToRender == 0 ) + { + // -- Standard operation section -- + // Means neither skipping frames nor force-rendering consecutive frames. + + if( sSlowDeltaTime > 0 ) + { + // The game is running below the minimum framerate. + // But don't start skipping yet! That would be too sensitive. + // So the skipping code is only engaged if the SlowDeltaTime falls behind by + // a full frame, or if we're already skipping (in which case we don't care + // to avoid errant skips). + + // Note: The MTGS can go out of phase from the EE, which means that the + // variance for a "nominal" framerate can range from 0 to m_iSlowTicks. + // We also check for that here. + + if( (m_justSkipped && (sSlowDeltaTime > m_iSlowTicks)) || + (sSlowDeltaTime > m_iSlowTicks*2) ) + { + //Console::Status( "Frameskip Initiated! Lateness: %d", params (int)( (sSlowDeltaTime*100) / m_iSlowTicks ) ); + + if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_VUSKIP ) + { + // For best results we have to wait for the EE to + // tell us when to skip, so that VU skips are synched with GS skips. + AtomicExchangeAdd( g_vu1SkipCount, yesSkipFrames+1 ); + } + else + { + GSsetFrameSkip(1); + FramesToRender = noSkipFrames+1; + FramesToSkip = yesSkipFrames; + } + } + } + else + { + // Running at or above full speed, so reset the StartTime since the Limiter + // will muck things up. (special case: if skip and limit fps are equal then + // we don't reset starttime since it would cause desyncing. We let the EE + // regulate it via calls to gsSyncLimiterStartTime). + + if( !m_StrictSkipping ) + m_iSlowStart = iEnd; + } + m_justSkipped = false; + return; + } + else if( FramesToSkip > 0 ) + { + // -- Frames-a-Skippin' Section -- + + FramesToSkip--; + + if( FramesToSkip == 0 ) + { + // Skipped our last frame, so restore non-skip behavior + + GSsetFrameSkip(0); + + // Note: If we lag behind by 250ms then it's time to give up on the idea + // of catching up. Force the game to slow down by resetting iStart to + // something closer to iEnd. + + if( sSlowDeltaTime > (m_iSlowTicks + ((s64)GetTickFrequency() / 4)) ) + { + //Console::Status( "Frameskip couldn't skip enough -- had to lose some time!" ); + m_iSlowStart = iEnd - m_iSlowTicks; + } + + m_justSkipped = true; + } + else + return; + } + + //SysPrintf( "Consecutive Frames -- Lateness: %d\n", (int)( sSlowDeltaTime / m_iSlowTicks ) ); + + // -- Consecutive frames section -- + // Force-render consecutive frames without skipping. + + FramesToRender--; + + if( sSlowDeltaTime < 0 ) + { + m_iSlowStart = iEnd; + } +} + +// updategs - if FALSE the gs will skip the frame. +void gsPostVsyncEnd( bool updategs ) +{ + *(u32*)(PS2MEM_GS+0x1000) ^= 0x2000; // swap the vsync field + + if( mtgsThread != NULL ) + { + mtgsThread->SendSimplePacket( GS_RINGTYPE_VSYNC, + (*(u32*)(PS2MEM_GS+0x1000)&0x2000), updategs, 0); + + // No need to freeze MMX/XMM registers here since this + // code is always called from the context of a BranchTest. + mtgsThread->SetEvent(); + } + else + { + GSvsync((*(u32*)(PS2MEM_GS+0x1000)&0x2000)); + + // update here on single thread mode *OBSOLETE* + if( PAD1update != NULL ) PAD1update(0); + if( PAD2update != NULL ) PAD2update(1); + + gsFrameSkip( !updategs ); + } +} + +void _gs_ResetFrameskip() +{ + g_vu1SkipCount = 0; // set to 0 so that EE will re-enable the VU at the next vblank. + GSsetFrameSkip( 0 ); +} + +// Disables the GS Frameskip at runtime without any racy mess... +void gsResetFrameSkip() +{ + if( mtgsThread != NULL ) + mtgsThread->SendSimplePacket(GS_RINGTYPE_FRAMESKIP, 0, 0, 0); + else + _gs_ResetFrameskip(); +} + +void gsDynamicSkipEnable() +{ + if( !m_StrictSkipping ) return; + + mtgsWaitGS(); + m_iSlowStart = GetCPUTicks(); + frameLimitReset(); +} + +void SaveState::gsFreeze() +{ + FreezeMem(PS2MEM_GS, 0x2000); + Freeze(CSRw); + mtgsFreeze(); +} + +#ifdef PCSX2_DEVBUILD + +struct GSStatePacket +{ + u32 type; + vector mem; +}; + +// runs the GS +void RunGSState( gzLoadingState& f ) +{ + u32 newfield; + list< GSStatePacket > packets; + + while( !f.Finished() ) + { + int type, size; + f.Freeze( type ); + + if( type != GSRUN_VSYNC ) f.Freeze( size ); + + packets.push_back(GSStatePacket()); + GSStatePacket& p = packets.back(); + + p.type = type; + + if( type != GSRUN_VSYNC ) { + p.mem.resize(size*16); + f.FreezeMem( &p.mem[0], size*16 ); + } + } + + list::iterator it = packets.begin(); + g_SaveGSStream = 3; + + int skipfirst = 1; + + // first extract the data + while(1) { + + switch(it->type) { + case GSRUN_TRANS1: + GSgifTransfer1((u32*)&it->mem[0], 0); + break; + case GSRUN_TRANS2: + GSgifTransfer2((u32*)&it->mem[0], it->mem.size()/16); + break; + case GSRUN_TRANS3: + GSgifTransfer3((u32*)&it->mem[0], it->mem.size()/16); + break; + case GSRUN_VSYNC: + // flip + newfield = (*(u32*)(PS2MEM_GS+0x1000)&0x2000) ? 0 : 0x2000; + *(u32*)(PS2MEM_GS+0x1000) = (*(u32*)(PS2MEM_GS+0x1000) & ~(1<<13)) | newfield; + + GSvsync(newfield); + SysUpdate(); + + if( g_SaveGSStream != 3 ) + return; + break; + + jNO_DEFAULT + } + + ++it; + if( it == packets.end() ) + it = packets.begin(); + } +} + +#endif + +#undef GIFchain diff --git a/pcsx2/GS.h b/pcsx2/GS.h index 8f8e05aedd..46f6c0c1d7 100644 --- a/pcsx2/GS.h +++ b/pcsx2/GS.h @@ -1,345 +1,345 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __GS_H__ -#define __GS_H__ - -// GCC needs these includes -#include -#include -#include - -#include "Common.h" -#include "Threading.h" -#include "zlib.h" - -#define GSPATH3FIX - -PCSX2_ALIGNED16( extern u8 g_RealGSMem[0x2000] ); -#define GSCSRr *((u64*)(g_RealGSMem+0x1000)) -#define GSIMR *((u32*)(g_RealGSMem+0x1010)) -#define GSSIGLBLID ((GSRegSIGBLID*)(g_RealGSMem+0x1080)) - -///////////////////////////////////////////////////////////////////////////// -// MTGS GIFtag Parser - Declaration -// -// The MTGS needs a dummy "GS plugin" for processing SIGNAL, FINISH, and LABEL -// commands. These commands trigger gsIRQs, which need to be handled accurately -// in synch with the EE (which can be running several frames ahead of the MTGS) -// -// Yeah, it's a lot of work, but the performance gains are huge, even on HT cpus. - -struct GSRegSIGBLID -{ - u32 SIGID; - u32 LBLID; -}; - -enum GIF_FLG -{ - GIF_FLG_PACKED = 0, - GIF_FLG_REGLIST = 1, - GIF_FLG_IMAGE = 2, - GIF_FLG_IMAGE2 = 3 -}; - -enum GIF_REG -{ - GIF_REG_PRIM = 0x00, - GIF_REG_RGBA = 0x01, - GIF_REG_STQ = 0x02, - GIF_REG_UV = 0x03, - GIF_REG_XYZF2 = 0x04, - GIF_REG_XYZ2 = 0x05, - GIF_REG_TEX0_1 = 0x06, - GIF_REG_TEX0_2 = 0x07, - GIF_REG_CLAMP_1 = 0x08, - GIF_REG_CLAMP_2 = 0x09, - GIF_REG_FOG = 0x0a, - GIF_REG_XYZF3 = 0x0c, - GIF_REG_XYZ3 = 0x0d, - GIF_REG_A_D = 0x0e, - GIF_REG_NOP = 0x0f, -}; - -struct GIFTAG -{ - u32 nloop : 15; - u32 eop : 1; - u32 dummy0 : 16; - u32 dummy1 : 14; - u32 pre : 1; - u32 prim : 11; - u32 flg : 2; - u32 nreg : 4; - u32 regs[2]; -}; - -struct GIFPath -{ - GIFTAG tag; - u32 curreg; - u32 _pad[3]; - u8 regs[16]; - - __forceinline void PrepRegs(); - void SetTag(const void* mem); - u32 GetReg(); -}; - - -///////////////////////////////////////////////////////////////////////////// -// MTGS Threaded Class Declaration - -// Uncomment this to enable the MTGS debug stack, which tracks to ensure reads -// and writes stay synchronized. Warning: the debug stack is VERY slow. -//#define RINGBUF_DEBUG_STACK - -enum GIF_PATH -{ - GIF_PATH_1 = 0, - GIF_PATH_2, - GIF_PATH_3, -}; - - -enum GS_RINGTYPE -{ - GS_RINGTYPE_RESTART = 0 -, GS_RINGTYPE_P1 -, GS_RINGTYPE_P2 -, GS_RINGTYPE_P3 -, GS_RINGTYPE_VSYNC -, GS_RINGTYPE_FRAMESKIP -, GS_RINGTYPE_MEMWRITE8 -, GS_RINGTYPE_MEMWRITE16 -, GS_RINGTYPE_MEMWRITE32 -, GS_RINGTYPE_MEMWRITE64 -, GS_RINGTYPE_FREEZE -, GS_RINGTYPE_RECORD -, GS_RINGTYPE_RESET // issues a GSreset() command. -, GS_RINGTYPE_SOFTRESET // issues a soft reset for the GIF -, GS_RINGTYPE_WRITECSR -, GS_RINGTYPE_MODECHANGE // for issued mode changes. -, GS_RINGTYPE_STARTTIME // special case for min==max fps frameskip settings -, GS_RINGTYPE_QUIT -}; - -class mtgsThreadObject : public Threading::Thread -{ - friend class SaveState; - -protected: - // Size of the ringbuffer as a power of 2 -- size is a multiple of simd128s. - // (actual size is 1< m_RingBuffer; - - // mtgs needs its own memory space separate from the PS2. The PS2 memory is in - // synch with the EE while this stays in sync with the GS (ie, it lags behind) - u8* const m_gsMem; - -public: - mtgsThreadObject(); - virtual ~mtgsThreadObject(); - - void Close(); - void Reset(); - void GIFSoftReset( int mask ); - - // Waits for the GS to empty out the entire ring buffer contents. - // Used primarily for plugin startup/shutdown. - void WaitGS(); - - int PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 size ); - int PrepDataPacket( GIF_PATH pathidx, const u32* srcdata, u32 size ); - int PrepDataPacket( GIF_PATH pathidx, const u64* srcdata, u32 size ); - void SendDataPacket(); - - void SendSimplePacket( GS_RINGTYPE type, int data0, int data1, int data2 ); - void SendPointerPacket( GS_RINGTYPE type, u32 data0, void* data1 ); - - u8* GetDataPacketPtr() const; - void Freeze( SaveState& state ); - void SetEvent(); - - uptr FnPtr_SimplePacket() const - { -#ifndef __LINUX__ - __asm mov eax, SendSimplePacket -#else - __asm ("mov %eax, SendSimplePacket"); -#endif - //return (uptr)&SendSimplePacket; - } - -protected: - // Saves MMX/XMM regs, posts an event to the mtgsThread flag and releases a timeslice. - // For use in surrounding loops that wait on the mtgs. - void PrepEventWait(); - - // Restores MMX/XMM regs. For use in surrounding loops that wait on the mtgs. - void PostEventWait() const; - - // Processes a GIFtag & packet, and throws out some gsIRQs as needed. - // Used to keep interrupts in sync with the EE, while the GS itself - // runs potentially several frames behind. - u32 _gifTransferDummy( GIF_PATH pathidx, const u8 *pMem, u32 size ); - - // Used internally by SendSimplePacket type functions - uint _PrepForSimplePacket(); - void _FinishSimplePacket( uint future_writepos ); - - int Callback(); -}; - -extern mtgsThreadObject* mtgsThread; - -void mtgsWaitGS(); -bool mtgsOpen(); -void mtgsRingBufSimplePacket( s32 command, u32 data0, u32 data1, u32 data2 ); - -///////////////////////////////////////////////////////////////////////////// -// Generalized GS Functions and Stuff - -extern void gsInit(); -extern s32 gsOpen(); -extern void gsClose(); -extern void gsReset(); -extern void gsOnModeChanged( u32 framerate, u32 newTickrate ); -extern void gsSetVideoRegionType( u32 isPal ); -extern void gsResetFrameSkip(); -extern void gsSyncLimiterLostTime( s32 deltaTime ); -extern void gsDynamicSkipEnable(); -extern void gsPostVsyncEnd( bool updategs ); -extern void gsFrameSkip( bool forceskip ); - -// Some functions shared by both the GS and MTGS -extern void _gs_ResetFrameskip(); -extern void _gs_ChangeTimings( u32 framerate, u32 iTicks ); - - -// used for resetting GIF fifo -bool gsGIFSoftReset( int mask ); -void gsGIFReset(); -void gsCSRwrite(u32 value); - -extern void gsWrite8(u32 mem, u8 value); -extern void gsWrite16(u32 mem, u16 value); -extern void gsWrite32(u32 mem, u32 value); - -extern void __fastcall gsWrite64_page_00( u32 mem, const mem64_t* value ); -extern void __fastcall gsWrite64_page_01( u32 mem, const mem64_t* value ); -extern void __fastcall gsWrite64_generic( u32 mem, const mem64_t* value ); - -extern void __fastcall gsWrite128_page_00( u32 mem, const mem128_t* value ); -extern void __fastcall gsWrite128_page_01( u32 mem, const mem128_t* value ); -extern void __fastcall gsWrite128_generic( u32 mem, const mem128_t* value ); - -extern u8 gsRead8(u32 mem); -extern u16 gsRead16(u32 mem); -extern u32 gsRead32(u32 mem); -extern u64 gsRead64(u32 mem); - - -//extern void gsWrite64(u32 mem, u64 value); - - -void gsConstWrite8(u32 mem, int mmreg); -void gsConstWrite16(u32 mem, int mmreg); -void gsConstWrite32(u32 mem, int mmreg); -void gsConstWrite64(u32 mem, int mmreg); -void gsConstWrite128(u32 mem, int mmreg); - -int gsConstRead8(u32 x86reg, u32 mem, u32 sign); -int gsConstRead16(u32 x86reg, u32 mem, u32 sign); -int gsConstRead32(u32 x86reg, u32 mem); -void gsConstRead64(u32 mem, int mmreg); -void gsConstRead128(u32 mem, int xmmreg); - -void gsIrq(); -extern void gsInterrupt(); -void dmaGIF(); -void GIFdma(); -void mfifoGIFtransfer(int qwc); -int _GIFchain(); -void gifMFIFOInterrupt(); - -extern u32 g_vu1SkipCount; -extern u32 CSRw; -extern u64 m_iSlowStart; - -// GS Playback -#define GSRUN_TRANS1 1 -#define GSRUN_TRANS2 2 -#define GSRUN_TRANS3 3 -#define GSRUN_VSYNC 4 - -#ifdef PCSX2_DEVBUILD - -extern int g_SaveGSStream; -extern int g_nLeftGSFrames; -extern gzSavingState* g_fGSSave; - -#endif - -void RunGSState(gzLoadingState& f); - -extern void GSGIFTRANSFER1(u32 *pMem, u32 addr); -extern void GSGIFTRANSFER2(u32 *pMem, u32 addr); -extern void GSGIFTRANSFER3(u32 *pMem, u32 addr); -extern void GSVSYNC(); - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __GS_H__ +#define __GS_H__ + +// GCC needs these includes +#include +#include +#include + +#include "Common.h" +#include "Threading.h" +#include "zlib.h" + +#define GSPATH3FIX + +PCSX2_ALIGNED16( extern u8 g_RealGSMem[0x2000] ); +#define GSCSRr *((u64*)(g_RealGSMem+0x1000)) +#define GSIMR *((u32*)(g_RealGSMem+0x1010)) +#define GSSIGLBLID ((GSRegSIGBLID*)(g_RealGSMem+0x1080)) + +///////////////////////////////////////////////////////////////////////////// +// MTGS GIFtag Parser - Declaration +// +// The MTGS needs a dummy "GS plugin" for processing SIGNAL, FINISH, and LABEL +// commands. These commands trigger gsIRQs, which need to be handled accurately +// in synch with the EE (which can be running several frames ahead of the MTGS) +// +// Yeah, it's a lot of work, but the performance gains are huge, even on HT cpus. + +struct GSRegSIGBLID +{ + u32 SIGID; + u32 LBLID; +}; + +enum GIF_FLG +{ + GIF_FLG_PACKED = 0, + GIF_FLG_REGLIST = 1, + GIF_FLG_IMAGE = 2, + GIF_FLG_IMAGE2 = 3 +}; + +enum GIF_REG +{ + GIF_REG_PRIM = 0x00, + GIF_REG_RGBA = 0x01, + GIF_REG_STQ = 0x02, + GIF_REG_UV = 0x03, + GIF_REG_XYZF2 = 0x04, + GIF_REG_XYZ2 = 0x05, + GIF_REG_TEX0_1 = 0x06, + GIF_REG_TEX0_2 = 0x07, + GIF_REG_CLAMP_1 = 0x08, + GIF_REG_CLAMP_2 = 0x09, + GIF_REG_FOG = 0x0a, + GIF_REG_XYZF3 = 0x0c, + GIF_REG_XYZ3 = 0x0d, + GIF_REG_A_D = 0x0e, + GIF_REG_NOP = 0x0f, +}; + +struct GIFTAG +{ + u32 nloop : 15; + u32 eop : 1; + u32 dummy0 : 16; + u32 dummy1 : 14; + u32 pre : 1; + u32 prim : 11; + u32 flg : 2; + u32 nreg : 4; + u32 regs[2]; +}; + +struct GIFPath +{ + GIFTAG tag; + u32 curreg; + u32 _pad[3]; + u8 regs[16]; + + __forceinline void PrepRegs(); + void SetTag(const void* mem); + u32 GetReg(); +}; + + +///////////////////////////////////////////////////////////////////////////// +// MTGS Threaded Class Declaration + +// Uncomment this to enable the MTGS debug stack, which tracks to ensure reads +// and writes stay synchronized. Warning: the debug stack is VERY slow. +//#define RINGBUF_DEBUG_STACK + +enum GIF_PATH +{ + GIF_PATH_1 = 0, + GIF_PATH_2, + GIF_PATH_3, +}; + + +enum GS_RINGTYPE +{ + GS_RINGTYPE_RESTART = 0 +, GS_RINGTYPE_P1 +, GS_RINGTYPE_P2 +, GS_RINGTYPE_P3 +, GS_RINGTYPE_VSYNC +, GS_RINGTYPE_FRAMESKIP +, GS_RINGTYPE_MEMWRITE8 +, GS_RINGTYPE_MEMWRITE16 +, GS_RINGTYPE_MEMWRITE32 +, GS_RINGTYPE_MEMWRITE64 +, GS_RINGTYPE_FREEZE +, GS_RINGTYPE_RECORD +, GS_RINGTYPE_RESET // issues a GSreset() command. +, GS_RINGTYPE_SOFTRESET // issues a soft reset for the GIF +, GS_RINGTYPE_WRITECSR +, GS_RINGTYPE_MODECHANGE // for issued mode changes. +, GS_RINGTYPE_STARTTIME // special case for min==max fps frameskip settings +, GS_RINGTYPE_QUIT +}; + +class mtgsThreadObject : public Threading::Thread +{ + friend class SaveState; + +protected: + // Size of the ringbuffer as a power of 2 -- size is a multiple of simd128s. + // (actual size is 1< m_RingBuffer; + + // mtgs needs its own memory space separate from the PS2. The PS2 memory is in + // synch with the EE while this stays in sync with the GS (ie, it lags behind) + u8* const m_gsMem; + +public: + mtgsThreadObject(); + virtual ~mtgsThreadObject(); + + void Close(); + void Reset(); + void GIFSoftReset( int mask ); + + // Waits for the GS to empty out the entire ring buffer contents. + // Used primarily for plugin startup/shutdown. + void WaitGS(); + + int PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 size ); + int PrepDataPacket( GIF_PATH pathidx, const u32* srcdata, u32 size ); + int PrepDataPacket( GIF_PATH pathidx, const u64* srcdata, u32 size ); + void SendDataPacket(); + + void SendSimplePacket( GS_RINGTYPE type, int data0, int data1, int data2 ); + void SendPointerPacket( GS_RINGTYPE type, u32 data0, void* data1 ); + + u8* GetDataPacketPtr() const; + void Freeze( SaveState& state ); + void SetEvent(); + + uptr FnPtr_SimplePacket() const + { +#ifndef __LINUX__ + __asm mov eax, SendSimplePacket +#else + __asm ("mov %eax, SendSimplePacket"); +#endif + //return (uptr)&SendSimplePacket; + } + +protected: + // Saves MMX/XMM regs, posts an event to the mtgsThread flag and releases a timeslice. + // For use in surrounding loops that wait on the mtgs. + void PrepEventWait(); + + // Restores MMX/XMM regs. For use in surrounding loops that wait on the mtgs. + void PostEventWait() const; + + // Processes a GIFtag & packet, and throws out some gsIRQs as needed. + // Used to keep interrupts in sync with the EE, while the GS itself + // runs potentially several frames behind. + u32 _gifTransferDummy( GIF_PATH pathidx, const u8 *pMem, u32 size ); + + // Used internally by SendSimplePacket type functions + uint _PrepForSimplePacket(); + void _FinishSimplePacket( uint future_writepos ); + + int Callback(); +}; + +extern mtgsThreadObject* mtgsThread; + +void mtgsWaitGS(); +bool mtgsOpen(); +void mtgsRingBufSimplePacket( s32 command, u32 data0, u32 data1, u32 data2 ); + +///////////////////////////////////////////////////////////////////////////// +// Generalized GS Functions and Stuff + +extern void gsInit(); +extern s32 gsOpen(); +extern void gsClose(); +extern void gsReset(); +extern void gsOnModeChanged( u32 framerate, u32 newTickrate ); +extern void gsSetVideoRegionType( u32 isPal ); +extern void gsResetFrameSkip(); +extern void gsSyncLimiterLostTime( s32 deltaTime ); +extern void gsDynamicSkipEnable(); +extern void gsPostVsyncEnd( bool updategs ); +extern void gsFrameSkip( bool forceskip ); + +// Some functions shared by both the GS and MTGS +extern void _gs_ResetFrameskip(); +extern void _gs_ChangeTimings( u32 framerate, u32 iTicks ); + + +// used for resetting GIF fifo +bool gsGIFSoftReset( int mask ); +void gsGIFReset(); +void gsCSRwrite(u32 value); + +extern void gsWrite8(u32 mem, u8 value); +extern void gsWrite16(u32 mem, u16 value); +extern void gsWrite32(u32 mem, u32 value); + +extern void __fastcall gsWrite64_page_00( u32 mem, const mem64_t* value ); +extern void __fastcall gsWrite64_page_01( u32 mem, const mem64_t* value ); +extern void __fastcall gsWrite64_generic( u32 mem, const mem64_t* value ); + +extern void __fastcall gsWrite128_page_00( u32 mem, const mem128_t* value ); +extern void __fastcall gsWrite128_page_01( u32 mem, const mem128_t* value ); +extern void __fastcall gsWrite128_generic( u32 mem, const mem128_t* value ); + +extern u8 gsRead8(u32 mem); +extern u16 gsRead16(u32 mem); +extern u32 gsRead32(u32 mem); +extern u64 gsRead64(u32 mem); + + +//extern void gsWrite64(u32 mem, u64 value); + + +void gsConstWrite8(u32 mem, int mmreg); +void gsConstWrite16(u32 mem, int mmreg); +void gsConstWrite32(u32 mem, int mmreg); +void gsConstWrite64(u32 mem, int mmreg); +void gsConstWrite128(u32 mem, int mmreg); + +int gsConstRead8(u32 x86reg, u32 mem, u32 sign); +int gsConstRead16(u32 x86reg, u32 mem, u32 sign); +int gsConstRead32(u32 x86reg, u32 mem); +void gsConstRead64(u32 mem, int mmreg); +void gsConstRead128(u32 mem, int xmmreg); + +void gsIrq(); +extern void gsInterrupt(); +void dmaGIF(); +void GIFdma(); +void mfifoGIFtransfer(int qwc); +int _GIFchain(); +void gifMFIFOInterrupt(); + +extern u32 g_vu1SkipCount; +extern u32 CSRw; +extern u64 m_iSlowStart; + +// GS Playback +#define GSRUN_TRANS1 1 +#define GSRUN_TRANS2 2 +#define GSRUN_TRANS3 3 +#define GSRUN_VSYNC 4 + +#ifdef PCSX2_DEVBUILD + +extern int g_SaveGSStream; +extern int g_nLeftGSFrames; +extern gzSavingState* g_fGSSave; + +#endif + +void RunGSState(gzLoadingState& f); + +extern void GSGIFTRANSFER1(u32 *pMem, u32 addr); +extern void GSGIFTRANSFER2(u32 *pMem, u32 addr); +extern void GSGIFTRANSFER3(u32 *pMem, u32 addr); +extern void GSVSYNC(); + +#endif diff --git a/pcsx2/Gif.cpp b/pcsx2/Gif.cpp index 82230f5f0b..3401b3c8b3 100644 --- a/pcsx2/Gif.cpp +++ b/pcsx2/Gif.cpp @@ -1,533 +1,533 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "VU.h" -#include "GS.h" -#include "iR5900.h" -#include "Counters.h" - -#include "VifDma.h" - -using std::min; - - -#define gif ((DMACh*)&psH[0xA000]) - -static u64 s_gstag=0; // used for querying the last tag -static int gspath3done=0; -static int gscycles = 0; - -__forceinline void gsInterrupt() { - GIF_LOG("gsInterrupt: %8.8x\n", cpuRegs.cycle); - - if((gif->chcr & 0x100) == 0){ - //SysPrintf("Eh? why are you still interrupting! chcr %x, qwc %x, done = %x\n", gif->chcr, gif->qwc, done); - return; - } - if(gif->qwc > 0 || gspath3done == 0) { - if( !(psHu32(DMAC_CTRL) & 0x1) ) { - Console::Notice("gs dma masked, re-scheduling..."); - // re-raise the int shortly in the future - CPU_INT( 2, 64 ); - return; - } - - GIFdma(); -#ifdef GSPATH3FIX - // re-reaise the IRQ as part of the mysterious Path3fix. - // fixme - this hack *should* have the gs_irq raised from the VIF, I think. It would be - // more efficient and more correct. (air) - if (!(vif1Regs->mskpath3 && (vif1ch->chcr & 0x100)) || (psHu32(GIF_MODE) & 0x1)) - CPU_INT( 2, 64 ); -#endif - return; - } - - gspath3done = 0; - gscycles = 0; - Path3transfer = 0; - gif->chcr &= ~0x100; - GSCSRr &= ~0xC000; //Clear FIFO stuff - GSCSRr |= 0x4000; //FIFO empty - //psHu32(GIF_MODE)&= ~0x4; - psHu32(GIF_STAT)&= ~0xE00; // OPH=0 | APATH=0 - psHu32(GIF_STAT)&= ~0x1F000000; // QFC=0 - hwDmacIrq(DMAC_GIF); - -} - -static void WRITERING_DMA(u32 *pMem, u32 qwc) -{ - psHu32(GIF_STAT) |= 0xE00; - - // Path3 transfer will be set to zero by the GIFtag handler. - Path3transfer = 1; - - if( mtgsThread != NULL ) - { - int sizetoread = (qwc)<<4; - sizetoread = mtgsThread->PrepDataPacket( GIF_PATH_3, pMem, qwc ); - u8* pgsmem = mtgsThread->GetDataPacketPtr(); - - /* check if page of endmem is valid (dark cloud2) */ - // fixme: this hack makes no sense, because the giftagDummy will - // process the full length of bytes regardess of how much we copy. - // So you'd think if we're truncating the copy to prevent DEPs, we - // should truncate the gif packet size too.. (air) - - // fixed? PrepDataPacket now returns the actual size of the packet. - // VIF handles scratchpad wrapping also, so this code shouldn't be needed anymore. - - memcpy_aligned(pgsmem, pMem, sizetoread<<4); - - mtgsThread->SendDataPacket(); - } - else - { - GSGIFTRANSFER3(pMem, qwc); - if( GSgetLastTag != NULL ) - { - GSgetLastTag(&s_gstag); - if( s_gstag == 1 ) - Path3transfer = 0; /* fixes SRS and others */ - } - } -} - -int _GIFchain() { -#ifdef GSPATH3FIX - u32 qwc = (psHu32(GIF_MODE) & 0x4 && vif1Regs->mskpath3) ? min(8, (int)gif->qwc) : gif->qwc; -#else - u32 qwc = gif->qwc; -#endif - u32 *pMem; - - //if (gif->qwc == 0) return 0; - - pMem = (u32*)dmaGetAddr(gif->madr); - if (pMem == NULL) { - // reset path3, fixes dark cloud 2 - - gsGIFSoftReset(4); - - //must increment madr and clear qwc, else it loops - gif->madr+= gif->qwc*16; - gif->qwc = 0; - Console::Notice( "Hackfix - NULL GIFchain" ); - return -1; - } - WRITERING_DMA(pMem, qwc); - - //if((psHu32(GIF_MODE) & 0x4)) amount -= qwc; - gif->madr+= qwc*16; - gif->qwc -= qwc; - return (qwc)*2; -} - -#define GIFchain() \ - if (gif->qwc) { \ - gscycles+= _GIFchain(); /* guessing */ \ - } - -int gscount = 0; -static int prevcycles = 0; -static u32* prevtag = NULL; - -void GIFdma() -{ - u32 *ptag; - u32 id; - - gscycles= prevcycles ? prevcycles: gscycles; - - if( (psHu32(GIF_CTRL) & 8) ) { // temporarily stop - SysPrintf("Gif dma temp paused?\n"); - return; - } - - GIF_LOG("dmaGIFstart chcr = %lx, madr = %lx, qwc = %lx\n tadr = %lx, asr0 = %lx, asr1 = %lx\n", gif->chcr, gif->madr, gif->qwc, gif->tadr, gif->asr0, gif->asr1); - -#ifndef GSPATH3FIX - if ( !(psHu32(GIF_MODE) & 0x4) ) { - if (vif1Regs->mskpath3 || psHu32(GIF_MODE) & 0x1) { - gif->chcr &= ~0x100; - psHu32(GIF_STAT)&= ~0xE00; // OPH=0 | APATH=0 - hwDmacIrq(2); - return; - } - } -#endif - - if ((psHu32(DMAC_CTRL) & 0xC0) == 0x80 && prevcycles != 0) { // STD == GIF - SysPrintf("GS Stall Control Source = %x, Drain = %x\n MADR = %x, STADR = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3, gif->madr, psHu32(DMAC_STADR)); - - if( gif->madr + (gif->qwc * 16) > psHu32(DMAC_STADR) ) { - CPU_INT(2, gscycles); - gscycles = 0; - return; - } - prevcycles = 0; - gif->qwc = 0; - } - - GSCSRr &= ~0xC000; //Clear FIFO stuff - GSCSRr |= 0x8000; //FIFO full - //psHu32(GIF_STAT)|= 0xE00; // OPH=1 | APATH=3 - psHu32(GIF_STAT)|= 0x10000000; // FQC=31, hack ;) - -#ifdef GSPATH3FIX - if (vif1Regs->mskpath3 || psHu32(GIF_MODE) & 0x1) { - if(gif->qwc == 0) { - if((gif->chcr & 0x10e) == 0x104) { - ptag = (u32*)dmaGetAddr(gif->tadr); //Set memory pointer to TADR - - if (ptag == NULL) { //Is ptag empty? - psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register - return; - } - gscycles += 2; - gif->chcr = ( gif->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 - id = (ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag - gif->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag - gif->madr = ptag[1]; //MADR = ADDR field - gspath3done = hwDmacSrcChainWithStack(gif, id); - GIF_LOG("PTH3 MASK gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx\n", ptag[1], ptag[0], gif->qwc, id, gif->madr); - - if ((gif->chcr & 0x80) && ptag[0] >> 31) { //Check TIE bit of CHCR and IRQ bit of tag - GIF_LOG("PATH3 MSK dmaIrq Set\n"); - SysPrintf("GIF TIE\n"); - gspath3done |= 1; - } - } - } - // When MTGS is enabled, Gifchain calls WRITERING_DMA, which calls GSRINGBUF_DONECOPY, which freezes - // the registers inside of the FreezeXMMRegs calls here and in the other two below.. - // I'm not really sure that is intentional. --arcum42 - FreezeXMMRegs(1); - FreezeMMXRegs(1); - GIFchain(); - FreezeXMMRegs(0); // Theres a comment below that says not to unfreeze the xmm regs, so not sure about this. - FreezeMMXRegs(0); - - if((gspath3done == 1 || (gif->chcr & 0xc) == 0) && gif->qwc == 0){ - if(gif->qwc > 0) SysPrintf("Horray\n"); - gspath3done = 0; - gif->chcr &= ~0x100; - //psHu32(GIF_MODE)&= ~0x4; - GSCSRr &= ~0xC000; - GSCSRr |= 0x4000; - Path3transfer = 0; - psHu32(GIF_STAT)&= ~0x1F000E00; // OPH=0 | APATH=0 | QFC=0 - hwDmacIrq(DMAC_GIF); - } - //Dont unfreeze xmm regs here, Masked PATH3 can only be called by VIF, which is already handling it. - return; - } -#endif - //gscycles = 0; - // Transfer Dn_QWC from Dn_MADR to GIF - if ((gif->chcr & 0xc) == 0 || gif->qwc > 0) { // Normal Mode - //gscount++; - if ((psHu32(DMAC_CTRL) & 0xC0) == 0x80 && (gif->chcr & 0xc) == 0) { - SysPrintf("DMA Stall Control on GIF normal\n"); - } - FreezeXMMRegs(1); - FreezeMMXRegs(1); - GIFchain(); //Transfers the data set by the switch - FreezeXMMRegs(0); - FreezeMMXRegs(0); - if(gif->qwc == 0 && (gif->chcr & 0xc) == 0) gspath3done = 1; - } - else { - // Chain Mode - while (gspath3done == 0 && gif->qwc == 0) { //Loop if the transfers aren't intermittent - ptag = (u32*)dmaGetAddr(gif->tadr); //Set memory pointer to TADR - if (ptag == NULL) { //Is ptag empty? - psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register - return; - } - gscycles+=2; // Add 1 cycles from the QW read for the tag - - // Transfer dma tag if tte is set - if (gif->chcr & 0x40) { - //u32 temptag[4] = {0}; - //SysPrintf("GIF TTE: %x_%x\n", ptag[3], ptag[2]); - - //temptag[0] = ptag[2]; - //temptag[1] = ptag[3]; - //GSGIFTRANSFER3(ptag, 1); - } - - gif->chcr = ( gif->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 - - id = (ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag - gif->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag - gif->madr = ptag[1]; //MADR = ADDR field - - gspath3done = hwDmacSrcChainWithStack(gif, id); - GIF_LOG("gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx\n", ptag[1], ptag[0], gif->qwc, id, gif->madr); - - if ((psHu32(DMAC_CTRL) & 0xC0) == 0x80) { // STD == GIF - // there are still bugs, need to also check if gif->madr +16*qwc >= stadr, if not, stall - if(!gspath3done && gif->madr + (gif->qwc * 16) > psHu32(DMAC_STADR) && id == 4) { - // stalled - SysPrintf("GS Stall Control Source = %x, Drain = %x\n MADR = %x, STADR = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3,gif->madr, psHu32(DMAC_STADR)); - prevcycles = gscycles; - gif->tadr -= 16; - hwDmacIrq(13); - CPU_INT(2, gscycles); - gscycles = 0; - return; - } - } - - FreezeXMMRegs(1); - FreezeMMXRegs(1); - GIFchain(); //Transfers the data set by the switch - FreezeXMMRegs(0); - FreezeMMXRegs(0); - - if ((gif->chcr & 0x80) && ptag[0] >> 31) { //Check TIE bit of CHCR and IRQ bit of tag - GIF_LOG("dmaIrq Set\n"); - gspath3done = 1; - //gif->qwc = 0; - } - } - } - prevtag = NULL; - prevcycles = 0; - if (!(vif1Regs->mskpath3 || (psHu32(GIF_MODE) & 0x1))) { - CPU_INT(2, gscycles); - gscycles = 0; - } -} - -void dmaGIF() { - //if(vif1Regs->mskpath3 || (psHu32(GIF_MODE) & 0x1)){ - // CPU_INT(2, 48); //Wait time for the buffer to fill, fixes some timing problems in path 3 masking - //} //It takes the time of 24 QW for the BUS to become ready - The Punisher, And1 Streetball - //else - gspath3done = 0; // For some reason this doesnt clear? So when the system starts the thread, we will clear it :) - - if(gif->qwc > 0 && (gif->chcr & 0x4) == 0x4) - gspath3done = 1; //Halflife sets a QWC amount in chain mode, no tadr set. - - if ((psHu32(DMAC_CTRL) & 0xC) == 0xC ) { // GIF MFIFO - //SysPrintf("GIF MFIFO\n"); - gifMFIFOInterrupt(); - return; - } - - GIFdma(); -} - -#define spr0 ((DMACh*)&PS2MEM_HW[0xD000]) - -static unsigned int mfifocycles; -static unsigned int gifqwc = 0; -static unsigned int gifdone = 0; - -// called from only one location, so forceinline it: -static __forceinline int mfifoGIFrbTransfer() { - u32 qwc = (psHu32(GIF_MODE) & 0x4 && vif1Regs->mskpath3) ? min(8, (int)gif->qwc) : gif->qwc; - int mfifoqwc = min(gifqwc, qwc); - u32 *src; - - - /* Check if the transfer should wrap around the ring buffer */ - if ((gif->madr+mfifoqwc*16) > (psHu32(DMAC_RBOR) + psHu32(DMAC_RBSR)+16)) { - int s1 = ((psHu32(DMAC_RBOR) + psHu32(DMAC_RBSR)+16) - gif->madr) >> 4; - - // fixme - I don't think these should use WRITERING_DMA, since our source - // isn't the DmaGetAddr(gif->madr) address that WRITERING_DMA expects. - - /* it does, so first copy 's1' bytes from 'addr' to 'data' */ - src = (u32*)PSM(gif->madr); - if (src == NULL) return -1; - WRITERING_DMA(src, s1); - - /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */ - src = (u32*)PSM(psHu32(DMAC_RBOR)); - if (src == NULL) return -1; - WRITERING_DMA(src, (mfifoqwc - s1)); - - } else { - /* it doesn't, so just transfer 'qwc*16' words - from 'gif->madr' to GS */ - src = (u32*)PSM(gif->madr); - if (src == NULL) return -1; - - WRITERING_DMA(src, mfifoqwc); - gif->madr = psHu32(DMAC_RBOR) + (gif->madr & psHu32(DMAC_RBSR)); - } - - gifqwc -= mfifoqwc; - gif->qwc -= mfifoqwc; - gif->madr+= mfifoqwc*16; - mfifocycles+= (mfifoqwc) * 2; /* guessing */ - - - return 0; -} - -// called from only one location, so forceinline it: -static __forceinline int mfifoGIFchain() { - /* Is QWC = 0? if so there is nothing to transfer */ - - if (gif->qwc == 0) return 0; - - if (gif->madr >= psHu32(DMAC_RBOR) && - gif->madr <= (psHu32(DMAC_RBOR)+psHu32(DMAC_RBSR))) { - if (mfifoGIFrbTransfer() == -1) return -1; - } else { - int mfifoqwc = (psHu32(GIF_MODE) & 0x4 && vif1Regs->mskpath3) ? min(8, (int)gif->qwc) : gif->qwc; - u32 *pMem = (u32*)dmaGetAddr(gif->madr); - if (pMem == NULL) return -1; - - WRITERING_DMA(pMem, mfifoqwc); - gif->madr+= mfifoqwc*16; - gif->qwc -= mfifoqwc; - mfifocycles+= (mfifoqwc) * 2; /* guessing */ - } - - return 0; -} - - -void mfifoGIFtransfer(int qwc) { - u32 *ptag; - int id; - u32 temp = 0; - mfifocycles = 0; - - if(qwc > 0 ) { - gifqwc += qwc; - if(!(gif->chcr & 0x100))return; - } - SPR_LOG("mfifoGIFtransfer %x madr %x, tadr %x\n", gif->chcr, gif->madr, gif->tadr); - - if(gif->qwc == 0){ - if(gif->tadr == spr0->madr) { - #ifdef PCSX2_DEVBUILD - /*if( gifqwc > 1 ) - SysPrintf("gif mfifo tadr==madr but qwc = %d\n", gifqwc);*/ - #endif - //hwDmacIrq(14); - - return; - } - gif->tadr = psHu32(DMAC_RBOR) + (gif->tadr & psHu32(DMAC_RBSR)); - ptag = (u32*)dmaGetAddr(gif->tadr); - - id = (ptag[0] >> 28) & 0x7; - gif->qwc = (ptag[0] & 0xffff); - gif->madr = ptag[1]; - mfifocycles += 2; - - gif->chcr = ( gif->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); - SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx mfifo qwc = %x spr0 madr = %x\n", - ptag[1], ptag[0], gif->qwc, id, gif->madr, gif->tadr, gifqwc, spr0->madr); - - gifqwc--; - switch (id) { - case 0: // Refe - Transfer Packet According to ADDR field - gif->tadr = psHu32(DMAC_RBOR) + ((gif->tadr + 16) & psHu32(DMAC_RBSR)); - gifdone = 2; //End Transfer - break; - - case 1: // CNT - Transfer QWC following the tag. - gif->madr = psHu32(DMAC_RBOR) + ((gif->tadr + 16) & psHu32(DMAC_RBSR)); //Set MADR to QW after Tag - gif->tadr = psHu32(DMAC_RBOR) + ((gif->madr + (gif->qwc << 4)) & psHu32(DMAC_RBSR)); //Set TADR to QW following the data - gifdone = 0; - break; - - case 2: // Next - Transfer QWC following tag. TADR = ADDR - temp = gif->madr; //Temporarily Store ADDR - gif->madr = psHu32(DMAC_RBOR) + ((gif->tadr + 16) & psHu32(DMAC_RBSR)); //Set MADR to QW following the tag - gif->tadr = temp; //Copy temporarily stored ADDR to Tag - gifdone = 0; - break; - - case 3: // Ref - Transfer QWC from ADDR field - case 4: // Refs - Transfer QWC from ADDR field (Stall Control) - gif->tadr = psHu32(DMAC_RBOR) + ((gif->tadr + 16) & psHu32(DMAC_RBSR)); //Set TADR to next tag - gifdone = 0; - break; - - case 7: // End - Transfer QWC following the tag - gif->madr = psHu32(DMAC_RBOR) + ((gif->tadr + 16) & psHu32(DMAC_RBSR)); //Set MADR to data following the tag - gif->tadr = psHu32(DMAC_RBOR) + ((gif->madr + (gif->qwc << 4)) & psHu32(DMAC_RBSR)); //Set TADR to QW following the data - gifdone = 2; //End Transfer - break; - } - if ((gif->chcr & 0x80) && (ptag[0] >> 31)) { - SPR_LOG("dmaIrq Set\n"); - gifdone = 2; - } - } - FreezeXMMRegs(1); - FreezeMMXRegs(1); - if (mfifoGIFchain() == -1) { - SysPrintf("GIF dmaChain error size=%d, madr=%lx, tadr=%lx\n", - gif->qwc, gif->madr, gif->tadr); - gifdone = 1; - } - FreezeXMMRegs(0); - FreezeMMXRegs(0); - - if(gif->qwc == 0 && gifdone == 2) gifdone = 1; - CPU_INT(11,mfifocycles); - - SPR_LOG("mfifoGIFtransfer end %x madr %x, tadr %x\n", gif->chcr, gif->madr, gif->tadr); -} - -void gifMFIFOInterrupt() -{ - if(!(gif->chcr & 0x100)) { SysPrintf("WTF GIFMFIFO\n");cpuRegs.interrupt &= ~(1 << 11); return ; } - - if(gifdone != 1) { - if(gifqwc <= 0) { - //SysPrintf("Empty\n"); - psHu32(GIF_STAT)&= ~0xE00; // OPH=0 | APATH=0 - hwDmacIrq(14); - return; - } - mfifoGIFtransfer(0); - return; - } -#ifdef PCSX2_DEVBUILD - if(gifdone == 0 || gif->qwc > 0) { - Console::Error("gifMFIFO Panic > Shouldnt go here!"); - return; - } -#endif - //if(gifqwc > 0)SysPrintf("GIF MFIFO ending with stuff in it %x\n", gifqwc); - gifqwc = 0; - gifdone = 0; - gif->chcr &= ~0x100; - hwDmacIrq(DMAC_GIF); - GSCSRr &= ~0xC000; //Clear FIFO stuff - GSCSRr |= 0x4000; //FIFO empty - //psHu32(GIF_MODE)&= ~0x4; - psHu32(GIF_STAT)&= ~0xE00; // OPH=0 | APATH=0 - psHu32(GIF_STAT)&= ~0x1F000000; // QFC=0 -} - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "VU.h" +#include "GS.h" +#include "iR5900.h" +#include "Counters.h" + +#include "VifDma.h" + +using std::min; + + +#define gif ((DMACh*)&psH[0xA000]) + +static u64 s_gstag=0; // used for querying the last tag +static int gspath3done=0; +static int gscycles = 0; + +__forceinline void gsInterrupt() { + GIF_LOG("gsInterrupt: %8.8x\n", cpuRegs.cycle); + + if((gif->chcr & 0x100) == 0){ + //SysPrintf("Eh? why are you still interrupting! chcr %x, qwc %x, done = %x\n", gif->chcr, gif->qwc, done); + return; + } + if(gif->qwc > 0 || gspath3done == 0) { + if( !(psHu32(DMAC_CTRL) & 0x1) ) { + Console::Notice("gs dma masked, re-scheduling..."); + // re-raise the int shortly in the future + CPU_INT( 2, 64 ); + return; + } + + GIFdma(); +#ifdef GSPATH3FIX + // re-reaise the IRQ as part of the mysterious Path3fix. + // fixme - this hack *should* have the gs_irq raised from the VIF, I think. It would be + // more efficient and more correct. (air) + if (!(vif1Regs->mskpath3 && (vif1ch->chcr & 0x100)) || (psHu32(GIF_MODE) & 0x1)) + CPU_INT( 2, 64 ); +#endif + return; + } + + gspath3done = 0; + gscycles = 0; + Path3transfer = 0; + gif->chcr &= ~0x100; + GSCSRr &= ~0xC000; //Clear FIFO stuff + GSCSRr |= 0x4000; //FIFO empty + //psHu32(GIF_MODE)&= ~0x4; + psHu32(GIF_STAT)&= ~0xE00; // OPH=0 | APATH=0 + psHu32(GIF_STAT)&= ~0x1F000000; // QFC=0 + hwDmacIrq(DMAC_GIF); + +} + +static void WRITERING_DMA(u32 *pMem, u32 qwc) +{ + psHu32(GIF_STAT) |= 0xE00; + + // Path3 transfer will be set to zero by the GIFtag handler. + Path3transfer = 1; + + if( mtgsThread != NULL ) + { + int sizetoread = (qwc)<<4; + sizetoread = mtgsThread->PrepDataPacket( GIF_PATH_3, pMem, qwc ); + u8* pgsmem = mtgsThread->GetDataPacketPtr(); + + /* check if page of endmem is valid (dark cloud2) */ + // fixme: this hack makes no sense, because the giftagDummy will + // process the full length of bytes regardess of how much we copy. + // So you'd think if we're truncating the copy to prevent DEPs, we + // should truncate the gif packet size too.. (air) + + // fixed? PrepDataPacket now returns the actual size of the packet. + // VIF handles scratchpad wrapping also, so this code shouldn't be needed anymore. + + memcpy_aligned(pgsmem, pMem, sizetoread<<4); + + mtgsThread->SendDataPacket(); + } + else + { + GSGIFTRANSFER3(pMem, qwc); + if( GSgetLastTag != NULL ) + { + GSgetLastTag(&s_gstag); + if( s_gstag == 1 ) + Path3transfer = 0; /* fixes SRS and others */ + } + } +} + +int _GIFchain() { +#ifdef GSPATH3FIX + u32 qwc = (psHu32(GIF_MODE) & 0x4 && vif1Regs->mskpath3) ? min(8, (int)gif->qwc) : gif->qwc; +#else + u32 qwc = gif->qwc; +#endif + u32 *pMem; + + //if (gif->qwc == 0) return 0; + + pMem = (u32*)dmaGetAddr(gif->madr); + if (pMem == NULL) { + // reset path3, fixes dark cloud 2 + + gsGIFSoftReset(4); + + //must increment madr and clear qwc, else it loops + gif->madr+= gif->qwc*16; + gif->qwc = 0; + Console::Notice( "Hackfix - NULL GIFchain" ); + return -1; + } + WRITERING_DMA(pMem, qwc); + + //if((psHu32(GIF_MODE) & 0x4)) amount -= qwc; + gif->madr+= qwc*16; + gif->qwc -= qwc; + return (qwc)*2; +} + +#define GIFchain() \ + if (gif->qwc) { \ + gscycles+= _GIFchain(); /* guessing */ \ + } + +int gscount = 0; +static int prevcycles = 0; +static u32* prevtag = NULL; + +void GIFdma() +{ + u32 *ptag; + u32 id; + + gscycles= prevcycles ? prevcycles: gscycles; + + if( (psHu32(GIF_CTRL) & 8) ) { // temporarily stop + SysPrintf("Gif dma temp paused?\n"); + return; + } + + GIF_LOG("dmaGIFstart chcr = %lx, madr = %lx, qwc = %lx\n tadr = %lx, asr0 = %lx, asr1 = %lx\n", gif->chcr, gif->madr, gif->qwc, gif->tadr, gif->asr0, gif->asr1); + +#ifndef GSPATH3FIX + if ( !(psHu32(GIF_MODE) & 0x4) ) { + if (vif1Regs->mskpath3 || psHu32(GIF_MODE) & 0x1) { + gif->chcr &= ~0x100; + psHu32(GIF_STAT)&= ~0xE00; // OPH=0 | APATH=0 + hwDmacIrq(2); + return; + } + } +#endif + + if ((psHu32(DMAC_CTRL) & 0xC0) == 0x80 && prevcycles != 0) { // STD == GIF + SysPrintf("GS Stall Control Source = %x, Drain = %x\n MADR = %x, STADR = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3, gif->madr, psHu32(DMAC_STADR)); + + if( gif->madr + (gif->qwc * 16) > psHu32(DMAC_STADR) ) { + CPU_INT(2, gscycles); + gscycles = 0; + return; + } + prevcycles = 0; + gif->qwc = 0; + } + + GSCSRr &= ~0xC000; //Clear FIFO stuff + GSCSRr |= 0x8000; //FIFO full + //psHu32(GIF_STAT)|= 0xE00; // OPH=1 | APATH=3 + psHu32(GIF_STAT)|= 0x10000000; // FQC=31, hack ;) + +#ifdef GSPATH3FIX + if (vif1Regs->mskpath3 || psHu32(GIF_MODE) & 0x1) { + if(gif->qwc == 0) { + if((gif->chcr & 0x10e) == 0x104) { + ptag = (u32*)dmaGetAddr(gif->tadr); //Set memory pointer to TADR + + if (ptag == NULL) { //Is ptag empty? + psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register + return; + } + gscycles += 2; + gif->chcr = ( gif->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + id = (ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag + gif->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag + gif->madr = ptag[1]; //MADR = ADDR field + gspath3done = hwDmacSrcChainWithStack(gif, id); + GIF_LOG("PTH3 MASK gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx\n", ptag[1], ptag[0], gif->qwc, id, gif->madr); + + if ((gif->chcr & 0x80) && ptag[0] >> 31) { //Check TIE bit of CHCR and IRQ bit of tag + GIF_LOG("PATH3 MSK dmaIrq Set\n"); + SysPrintf("GIF TIE\n"); + gspath3done |= 1; + } + } + } + // When MTGS is enabled, Gifchain calls WRITERING_DMA, which calls GSRINGBUF_DONECOPY, which freezes + // the registers inside of the FreezeXMMRegs calls here and in the other two below.. + // I'm not really sure that is intentional. --arcum42 + FreezeXMMRegs(1); + FreezeMMXRegs(1); + GIFchain(); + FreezeXMMRegs(0); // Theres a comment below that says not to unfreeze the xmm regs, so not sure about this. + FreezeMMXRegs(0); + + if((gspath3done == 1 || (gif->chcr & 0xc) == 0) && gif->qwc == 0){ + if(gif->qwc > 0) SysPrintf("Horray\n"); + gspath3done = 0; + gif->chcr &= ~0x100; + //psHu32(GIF_MODE)&= ~0x4; + GSCSRr &= ~0xC000; + GSCSRr |= 0x4000; + Path3transfer = 0; + psHu32(GIF_STAT)&= ~0x1F000E00; // OPH=0 | APATH=0 | QFC=0 + hwDmacIrq(DMAC_GIF); + } + //Dont unfreeze xmm regs here, Masked PATH3 can only be called by VIF, which is already handling it. + return; + } +#endif + //gscycles = 0; + // Transfer Dn_QWC from Dn_MADR to GIF + if ((gif->chcr & 0xc) == 0 || gif->qwc > 0) { // Normal Mode + //gscount++; + if ((psHu32(DMAC_CTRL) & 0xC0) == 0x80 && (gif->chcr & 0xc) == 0) { + SysPrintf("DMA Stall Control on GIF normal\n"); + } + FreezeXMMRegs(1); + FreezeMMXRegs(1); + GIFchain(); //Transfers the data set by the switch + FreezeXMMRegs(0); + FreezeMMXRegs(0); + if(gif->qwc == 0 && (gif->chcr & 0xc) == 0) gspath3done = 1; + } + else { + // Chain Mode + while (gspath3done == 0 && gif->qwc == 0) { //Loop if the transfers aren't intermittent + ptag = (u32*)dmaGetAddr(gif->tadr); //Set memory pointer to TADR + if (ptag == NULL) { //Is ptag empty? + psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register + return; + } + gscycles+=2; // Add 1 cycles from the QW read for the tag + + // Transfer dma tag if tte is set + if (gif->chcr & 0x40) { + //u32 temptag[4] = {0}; + //SysPrintf("GIF TTE: %x_%x\n", ptag[3], ptag[2]); + + //temptag[0] = ptag[2]; + //temptag[1] = ptag[3]; + //GSGIFTRANSFER3(ptag, 1); + } + + gif->chcr = ( gif->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + + id = (ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag + gif->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag + gif->madr = ptag[1]; //MADR = ADDR field + + gspath3done = hwDmacSrcChainWithStack(gif, id); + GIF_LOG("gifdmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx\n", ptag[1], ptag[0], gif->qwc, id, gif->madr); + + if ((psHu32(DMAC_CTRL) & 0xC0) == 0x80) { // STD == GIF + // there are still bugs, need to also check if gif->madr +16*qwc >= stadr, if not, stall + if(!gspath3done && gif->madr + (gif->qwc * 16) > psHu32(DMAC_STADR) && id == 4) { + // stalled + SysPrintf("GS Stall Control Source = %x, Drain = %x\n MADR = %x, STADR = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3,gif->madr, psHu32(DMAC_STADR)); + prevcycles = gscycles; + gif->tadr -= 16; + hwDmacIrq(13); + CPU_INT(2, gscycles); + gscycles = 0; + return; + } + } + + FreezeXMMRegs(1); + FreezeMMXRegs(1); + GIFchain(); //Transfers the data set by the switch + FreezeXMMRegs(0); + FreezeMMXRegs(0); + + if ((gif->chcr & 0x80) && ptag[0] >> 31) { //Check TIE bit of CHCR and IRQ bit of tag + GIF_LOG("dmaIrq Set\n"); + gspath3done = 1; + //gif->qwc = 0; + } + } + } + prevtag = NULL; + prevcycles = 0; + if (!(vif1Regs->mskpath3 || (psHu32(GIF_MODE) & 0x1))) { + CPU_INT(2, gscycles); + gscycles = 0; + } +} + +void dmaGIF() { + //if(vif1Regs->mskpath3 || (psHu32(GIF_MODE) & 0x1)){ + // CPU_INT(2, 48); //Wait time for the buffer to fill, fixes some timing problems in path 3 masking + //} //It takes the time of 24 QW for the BUS to become ready - The Punisher, And1 Streetball + //else + gspath3done = 0; // For some reason this doesnt clear? So when the system starts the thread, we will clear it :) + + if(gif->qwc > 0 && (gif->chcr & 0x4) == 0x4) + gspath3done = 1; //Halflife sets a QWC amount in chain mode, no tadr set. + + if ((psHu32(DMAC_CTRL) & 0xC) == 0xC ) { // GIF MFIFO + //SysPrintf("GIF MFIFO\n"); + gifMFIFOInterrupt(); + return; + } + + GIFdma(); +} + +#define spr0 ((DMACh*)&PS2MEM_HW[0xD000]) + +static unsigned int mfifocycles; +static unsigned int gifqwc = 0; +static unsigned int gifdone = 0; + +// called from only one location, so forceinline it: +static __forceinline int mfifoGIFrbTransfer() { + u32 qwc = (psHu32(GIF_MODE) & 0x4 && vif1Regs->mskpath3) ? min(8, (int)gif->qwc) : gif->qwc; + int mfifoqwc = min(gifqwc, qwc); + u32 *src; + + + /* Check if the transfer should wrap around the ring buffer */ + if ((gif->madr+mfifoqwc*16) > (psHu32(DMAC_RBOR) + psHu32(DMAC_RBSR)+16)) { + int s1 = ((psHu32(DMAC_RBOR) + psHu32(DMAC_RBSR)+16) - gif->madr) >> 4; + + // fixme - I don't think these should use WRITERING_DMA, since our source + // isn't the DmaGetAddr(gif->madr) address that WRITERING_DMA expects. + + /* it does, so first copy 's1' bytes from 'addr' to 'data' */ + src = (u32*)PSM(gif->madr); + if (src == NULL) return -1; + WRITERING_DMA(src, s1); + + /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */ + src = (u32*)PSM(psHu32(DMAC_RBOR)); + if (src == NULL) return -1; + WRITERING_DMA(src, (mfifoqwc - s1)); + + } else { + /* it doesn't, so just transfer 'qwc*16' words + from 'gif->madr' to GS */ + src = (u32*)PSM(gif->madr); + if (src == NULL) return -1; + + WRITERING_DMA(src, mfifoqwc); + gif->madr = psHu32(DMAC_RBOR) + (gif->madr & psHu32(DMAC_RBSR)); + } + + gifqwc -= mfifoqwc; + gif->qwc -= mfifoqwc; + gif->madr+= mfifoqwc*16; + mfifocycles+= (mfifoqwc) * 2; /* guessing */ + + + return 0; +} + +// called from only one location, so forceinline it: +static __forceinline int mfifoGIFchain() { + /* Is QWC = 0? if so there is nothing to transfer */ + + if (gif->qwc == 0) return 0; + + if (gif->madr >= psHu32(DMAC_RBOR) && + gif->madr <= (psHu32(DMAC_RBOR)+psHu32(DMAC_RBSR))) { + if (mfifoGIFrbTransfer() == -1) return -1; + } else { + int mfifoqwc = (psHu32(GIF_MODE) & 0x4 && vif1Regs->mskpath3) ? min(8, (int)gif->qwc) : gif->qwc; + u32 *pMem = (u32*)dmaGetAddr(gif->madr); + if (pMem == NULL) return -1; + + WRITERING_DMA(pMem, mfifoqwc); + gif->madr+= mfifoqwc*16; + gif->qwc -= mfifoqwc; + mfifocycles+= (mfifoqwc) * 2; /* guessing */ + } + + return 0; +} + + +void mfifoGIFtransfer(int qwc) { + u32 *ptag; + int id; + u32 temp = 0; + mfifocycles = 0; + + if(qwc > 0 ) { + gifqwc += qwc; + if(!(gif->chcr & 0x100))return; + } + SPR_LOG("mfifoGIFtransfer %x madr %x, tadr %x\n", gif->chcr, gif->madr, gif->tadr); + + if(gif->qwc == 0){ + if(gif->tadr == spr0->madr) { + #ifdef PCSX2_DEVBUILD + /*if( gifqwc > 1 ) + SysPrintf("gif mfifo tadr==madr but qwc = %d\n", gifqwc);*/ + #endif + //hwDmacIrq(14); + + return; + } + gif->tadr = psHu32(DMAC_RBOR) + (gif->tadr & psHu32(DMAC_RBSR)); + ptag = (u32*)dmaGetAddr(gif->tadr); + + id = (ptag[0] >> 28) & 0x7; + gif->qwc = (ptag[0] & 0xffff); + gif->madr = ptag[1]; + mfifocycles += 2; + + gif->chcr = ( gif->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); + SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx mfifo qwc = %x spr0 madr = %x\n", + ptag[1], ptag[0], gif->qwc, id, gif->madr, gif->tadr, gifqwc, spr0->madr); + + gifqwc--; + switch (id) { + case 0: // Refe - Transfer Packet According to ADDR field + gif->tadr = psHu32(DMAC_RBOR) + ((gif->tadr + 16) & psHu32(DMAC_RBSR)); + gifdone = 2; //End Transfer + break; + + case 1: // CNT - Transfer QWC following the tag. + gif->madr = psHu32(DMAC_RBOR) + ((gif->tadr + 16) & psHu32(DMAC_RBSR)); //Set MADR to QW after Tag + gif->tadr = psHu32(DMAC_RBOR) + ((gif->madr + (gif->qwc << 4)) & psHu32(DMAC_RBSR)); //Set TADR to QW following the data + gifdone = 0; + break; + + case 2: // Next - Transfer QWC following tag. TADR = ADDR + temp = gif->madr; //Temporarily Store ADDR + gif->madr = psHu32(DMAC_RBOR) + ((gif->tadr + 16) & psHu32(DMAC_RBSR)); //Set MADR to QW following the tag + gif->tadr = temp; //Copy temporarily stored ADDR to Tag + gifdone = 0; + break; + + case 3: // Ref - Transfer QWC from ADDR field + case 4: // Refs - Transfer QWC from ADDR field (Stall Control) + gif->tadr = psHu32(DMAC_RBOR) + ((gif->tadr + 16) & psHu32(DMAC_RBSR)); //Set TADR to next tag + gifdone = 0; + break; + + case 7: // End - Transfer QWC following the tag + gif->madr = psHu32(DMAC_RBOR) + ((gif->tadr + 16) & psHu32(DMAC_RBSR)); //Set MADR to data following the tag + gif->tadr = psHu32(DMAC_RBOR) + ((gif->madr + (gif->qwc << 4)) & psHu32(DMAC_RBSR)); //Set TADR to QW following the data + gifdone = 2; //End Transfer + break; + } + if ((gif->chcr & 0x80) && (ptag[0] >> 31)) { + SPR_LOG("dmaIrq Set\n"); + gifdone = 2; + } + } + FreezeXMMRegs(1); + FreezeMMXRegs(1); + if (mfifoGIFchain() == -1) { + SysPrintf("GIF dmaChain error size=%d, madr=%lx, tadr=%lx\n", + gif->qwc, gif->madr, gif->tadr); + gifdone = 1; + } + FreezeXMMRegs(0); + FreezeMMXRegs(0); + + if(gif->qwc == 0 && gifdone == 2) gifdone = 1; + CPU_INT(11,mfifocycles); + + SPR_LOG("mfifoGIFtransfer end %x madr %x, tadr %x\n", gif->chcr, gif->madr, gif->tadr); +} + +void gifMFIFOInterrupt() +{ + if(!(gif->chcr & 0x100)) { SysPrintf("WTF GIFMFIFO\n");cpuRegs.interrupt &= ~(1 << 11); return ; } + + if(gifdone != 1) { + if(gifqwc <= 0) { + //SysPrintf("Empty\n"); + psHu32(GIF_STAT)&= ~0xE00; // OPH=0 | APATH=0 + hwDmacIrq(14); + return; + } + mfifoGIFtransfer(0); + return; + } +#ifdef PCSX2_DEVBUILD + if(gifdone == 0 || gif->qwc > 0) { + Console::Error("gifMFIFO Panic > Shouldnt go here!"); + return; + } +#endif + //if(gifqwc > 0)SysPrintf("GIF MFIFO ending with stuff in it %x\n", gifqwc); + gifqwc = 0; + gifdone = 0; + gif->chcr &= ~0x100; + hwDmacIrq(DMAC_GIF); + GSCSRr &= ~0xC000; //Clear FIFO stuff + GSCSRr |= 0x4000; //FIFO empty + //psHu32(GIF_MODE)&= ~0x4; + psHu32(GIF_STAT)&= ~0xE00; // OPH=0 | APATH=0 + psHu32(GIF_STAT)&= ~0x1F000000; // QFC=0 +} + diff --git a/pcsx2/Hw.cpp b/pcsx2/Hw.cpp index 0c8617f6f4..f9566fb031 100644 --- a/pcsx2/Hw.cpp +++ b/pcsx2/Hw.cpp @@ -1,849 +1,849 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "iR5900.h" -#include "VUmicro.h" -#include "IopMem.h" - -// The full suite of hardware APIs: -#include "IPU/IPU.h" -#include "GS.h" -#include "Counters.h" -#include "Vif.h" -#include "VifDma.h" -#include "SPR.h" -#include "Sif.h" - -using namespace R5900; - -u8 *psH; // hw mem - -int rdram_devices = 2; // put 8 for TOOL and 2 for PS2 and PSX -int rdram_sdevid = 0; - -void hwInit() -{ - gsInit(); - vif0Init(); - vif1Init(); - vifDmaInit(); - sifInit(); - sprInit(); - ipuInit(); -} - -void hwShutdown() { - ipuShutdown(); -} - -void hwReset() -{ - hwInit(); - - memzero_ptr( PS2MEM_HW ); - //memset(PS2MEM_HW+0x2000, 0, 0x0000e000); - - psHu32(0xf520) = 0x1201; - psHu32(0xf260) = 0x1D000060; - // i guess this is kinda a version, it's used by some bioses - psHu32(0xf590) = 0x1201; - - gsReset(); - ipuReset(); -} - -__forceinline void intcInterrupt() -{ - if ((cpuRegs.CP0.n.Status.val & 0x400) != 0x400) return; - - if ((psHu32(INTC_STAT)) == 0) { - DevCon::Notice("*PCSX2*: intcInterrupt already cleared"); - return; - } - if ((psHu32(INTC_STAT) & psHu32(INTC_MASK)) == 0) return; - - HW_LOG("intcInterrupt %x\n", psHu32(INTC_STAT) & psHu32(INTC_MASK)); - if(psHu32(INTC_STAT) & 0x2){ - counters[0].hold = rcntRcount(0); - counters[1].hold = rcntRcount(1); - } - - cpuException(0x400, cpuRegs.branch); -} - -__forceinline void dmacInterrupt() -{ - if ((cpuRegs.CP0.n.Status.val & 0x10807) != 0x10801) return; - - if( ((psHu16(0xe012) & psHu16(0xe010)) == 0 ) && - ( psHu16(0xe010) & 0x8000) == 0 ) return; - - if((psHu32(DMAC_CTRL) & 0x1) == 0) return; - - HW_LOG("dmacInterrupt %x\n", (psHu16(0xe012) & psHu16(0xe010) || - psHu16(0xe010) & 0x8000)); - - cpuException(0x800, cpuRegs.branch); -} - -void hwIntcIrq(int n) { - psHu32(INTC_STAT)|= 1<= msize) { - int s1 = msize - addr; - int s2 = size - s1; - - /* it does, so first copy 's1' bytes from 'data' to 'addr' */ - dst = (u8*)PSM(addr); - if (dst == NULL) return -1; - Cpu->Clear(addr, s1/4); - memcpy_fast(dst, data, s1); - - /* and second copy 's2' bytes from '&data[s1]' to 'maddr' */ - dst = (u8*)PSM(psHu32(DMAC_RBOR)); - if (dst == NULL) return -1; - Cpu->Clear(psHu32(DMAC_RBOR), s2/4); - memcpy_fast(dst, &data[s1], s2); - } else { - //u32 * tempptr, * tempptr2; - - /* it doesn't, so just copy 'size' bytes from 'data' to 'addr' */ - dst = (u8*)PSM(addr); - if (dst == NULL) return -1; - Cpu->Clear(addr, size/4); - memcpy_fast(dst, data, size); - } - - return 0; -} - - -int hwDmacSrcChainWithStack(DMACh *dma, int id) { - u32 temp; - - switch (id) { - case 0: // Refe - Transfer Packet According to ADDR field - //dma->tadr += 16; - return 1; //End Transfer - - case 1: // CNT - Transfer QWC following the tag. - dma->madr = dma->tadr + 16; //Set MADR to QW after Tag - dma->tadr = dma->madr + (dma->qwc << 4); //Set TADR to QW following the data - return 0; - - case 2: // Next - Transfer QWC following tag. TADR = ADDR - temp = dma->madr; //Temporarily Store ADDR - dma->madr = dma->tadr + 16; //Set MADR to QW following the tag - dma->tadr = temp; //Copy temporarily stored ADDR to Tag - return 0; - - case 3: // Ref - Transfer QWC from ADDR field - case 4: // Refs - Transfer QWC from ADDR field (Stall Control) - dma->tadr += 16; //Set TADR to next tag - return 0; - - case 5: // Call - Transfer QWC following the tag, save succeeding tag - temp = dma->madr; //Temporarily Store ADDR - - dma->madr = dma->tadr + 16; //Set MADR to data following the tag - - if ((dma->chcr & 0x30) == 0x0) { //Check if ASR0 is empty - dma->asr0 = dma->madr + (dma->qwc << 4); //If yes store Succeeding tag - dma->chcr = (dma->chcr & 0xffffffcf) | 0x10; //1 Address in call stack - }else if((dma->chcr & 0x30) == 0x10){ - dma->chcr = (dma->chcr & 0xffffffcf) | 0x20; //2 Addresses in call stack - dma->asr1 = dma->madr + (dma->qwc << 4); //If no store Succeeding tag in ASR1 - }else { - SysPrintf("Call Stack Overflow (report if it fixes/breaks anything)\n"); - return 1; //Return done - } - dma->tadr = temp; //Set TADR to temporarily stored ADDR - - return 0; - - case 6: // Ret - Transfer QWC following the tag, load next tag - dma->madr = dma->tadr + 16; //Set MADR to data following the tag - - if ((dma->chcr & 0x30) == 0x20) { //If ASR1 is NOT equal to 0 (Contains address) - dma->chcr = (dma->chcr & 0xffffffcf) | 0x10; //1 Address left in call stack - dma->tadr = dma->asr1; //Read ASR1 as next tag - dma->asr1 = 0; //Clear ASR1 - } else { //If ASR1 is empty (No address held) - if((dma->chcr & 0x30) == 0x10) { //Check if ASR0 is NOT equal to 0 (Contains address) - dma->chcr = (dma->chcr & 0xffffffcf); //No addresses left in call stack - dma->tadr = dma->asr0; //Read ASR0 as next tag - dma->asr0 = 0; //Clear ASR0 - } else { //Else if ASR1 and ASR0 are empty - //dma->tadr += 16; //Clear tag address - Kills Klonoa 2 - return 1; //End Transfer - } - } - return 0; - - case 7: // End - Transfer QWC following the tag - dma->madr = dma->tadr + 16; //Set MADR to data following the tag - //comment out tadr fixes lemans - //dma->tadr = dma->madr + (dma->qwc << 4); //Dont Increment tag, breaks Soul Calibur II and III - return 1; //End Transfer - } - - return -1; -} - -int hwDmacSrcChain(DMACh *dma, int id) { - u32 temp; - - switch (id) { - case 0: // Refe - Transfer Packet According to ADDR field - //dma->tadr += 16; - return 1; //End Transfer - - case 1: // CNT - Transfer QWC following the tag. - dma->madr = dma->tadr + 16; //Set MADR to QW after Tag - dma->tadr = dma->madr + (dma->qwc << 4); //Set TADR to QW following the data - return 0; - - case 2: // Next - Transfer QWC following tag. TADR = ADDR - temp = dma->madr; //Temporarily Store ADDR - dma->madr = dma->tadr + 16; //Set MADR to QW following the tag - dma->tadr = temp; //Copy temporarily stored ADDR to Tag - return 0; - - case 3: // Ref - Transfer QWC from ADDR field - case 4: // Refs - Transfer QWC from ADDR field (Stall Control) - dma->tadr += 16; //Set TADR to next tag - return 0; - - case 7: // End - Transfer QWC following the tag - dma->madr = dma->tadr + 16; //Set MADR to data following the tag - //dma->tadr = dma->madr + (dma->qwc << 4); //Dont Increment tag, breaks Soul Calibur II and III - return 1; //End Transfer - } - - return -1; -} - -// Original hwRead/Write32 functions .. left in for now, for troubleshooting purposes. -#if 0 -mem32_t __fastcall hwRead32(u32 mem) -{ - // *Performance Warning* This function is called -A-LOT. Be weary when making changes. It - // could impact FPS significantly. - - // Optimization Note: - // Shortcut for the INTC_STAT register, which is checked *very* frequently as part of the EE's - // vsynch timers. INTC_STAT has the disadvantage of being in the 0x1000f000 case, which has - // a lot of additional registers in it, and combined with it's call frequency is a bad thing. - - if(mem == INTC_STAT) - { - // This one is checked alot, so leave it commented out unless you love 600 meg logfiles. - //HW_LOG("DMAC_STAT Read 32bit %x\n", psHu32(0xe010)); - return psHu32(INTC_STAT); - } - - const u16 masked_mem = mem & 0xffff; - - // We optimize the hw register reads by breaking them into manageable 4k chunks (for a total of - // 16 cases spanning the 64k PS2 hw register memory map). It helps also that the EE is, for - // the most part, designed so that various classes of registers are sectioned off into these - // 4k segments. - - // Notes: Breaks from the switch statement will return a standard hw memory read. - // Special case handling of reads should use "return" directly. - - switch( masked_mem>>12 ) // switch out as according to the 4k page of the access. - { - // Counters Registers - // This code uses some optimized trickery to produce more compact output. - // See below for the "reference" block to get a better idea what this code does. :) - - case 0x0: // counters 0 and 1 - case 0x1: // counters 2 and 3 - { - const uint cntidx = masked_mem >> 11; // neat trick to scale the counter HW address into 0-3 range. - switch( (masked_mem>>4) & 0xf ) - { - case 0x0: return (u16)rcntRcount(cntidx); - case 0x1: return (u16)counters[cntidx].modeval; - case 0x2: return (u16)counters[cntidx].target; - case 0x3: return (u16)counters[cntidx].hold; - } - } - -#if 0 // Counters Reference Block (original case setup) - case 0x10000000: return (u16)rcntRcount(0); - case 0x10000010: return (u16)counters[0].modeval; - case 0x10000020: return (u16)counters[0].target; - case 0x10000030: return (u16)counters[0].hold; - - case 0x10000800: return (u16)rcntRcount(1); - case 0x10000810: return (u16)counters[1].modeval; - case 0x10000820: return (u16)counters[1].target; - case 0x10000830: return (u16)counters[1].hold; - - case 0x10001000: return (u16)rcntRcount(2); - case 0x10001010: return (u16)counters[2].modeval; - case 0x10001020: return (u16)counters[2].target; - - case 0x10001800: return (u16)rcntRcount(3); - case 0x10001810: return (u16)counters[3].modeval; - case 0x10001820: return (u16)counters[3].target; -#endif - - break; - - case 0x2: return ipuRead32( mem ); - - case 0xf: - switch( (masked_mem >> 4) & 0xff ) - { - case 0x01: - HW_LOG("INTC_MASK Read32, value=0x%x", psHu32(INTC_MASK)); - break; - - case 0x13: // 0x1000f130 - case 0x26: // 0x1000f260 SBUS? - case 0x41: // 0x1000f410 - case 0x43: // MCH_RICM - return 0; - - case 0x24: // 0x1000f240: SBUS - return psHu32(0xf240) | 0xF0000102; - - case 0x44: // 0x1000f440: MCH_DRD - - if( !((psHu32(0xf430) >> 6) & 0xF) ) - { - switch ((psHu32(0xf430)>>16) & 0xFFF) - { - //MCH_RICM: x:4|SA:12|x:5|SDEV:1|SOP:4|SBC:1|SDEV:5 - - case 0x21://INIT - if(rdram_sdevid < rdram_devices) - { - rdram_sdevid++; - return 0x1F; - } - return 0; - - case 0x23://CNFGA - return 0x0D0D; //PVER=3 | MVER=16 | DBL=1 | REFBIT=5 - - case 0x24://CNFGB - //0x0110 for PSX SVER=0 | CORG=8(5x9x7) | SPT=1 | DEVTYP=0 | BYTE=0 - return 0x0090; //SVER=0 | CORG=4(5x9x6) | SPT=1 | DEVTYP=0 | BYTE=0 - - case 0x40://DEVID - return psHu32(0xf430) & 0x1F; // =SDEV - } - } - return 0; - } - break; - - /////////////////////////////////////////////////////// - // Most of the following case handlers are for developer builds only (logging). - // It'll all optimize to ziltch in public release builds. - - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0a: - { - const char* regName = "Unknown"; - - switch( mem ) - { - case D2_CHCR: regName = "DMA2_CHCR"; break; - case D2_MADR: regName = "DMA2_MADR"; break; - case D2_QWC: regName = "DMA2_QWC"; break; - case D2_TADR: regName = "DMA2_TADDR"; break; - case D2_ASR0: regName = "DMA2_ASR0"; break; - case D2_ASR1: regName = "DMA2_ASR1"; break; - case D2_SADR: regName = "DMA2_SADDR"; break; - } - - HW_LOG( "Hardware Read32 at 0x%x (%s), value=0x%x\n", mem, regName, psHu32(mem) ); - } - break; - - case 0x0b: - if( mem == D4_CHCR ) - HW_LOG("Hardware Read32 at 0x%x (IPU1:DMA4_CHCR), value=0x%x\n", mem, psHu32(mem)); - break; - - case 0x0c: - case 0x0d: - case 0x0e: - if( mem == DMAC_STAT ) - HW_LOG("DMAC_STAT Read32, value=0x%x\n", psHu32(DMAC_STAT)); - break; - - jNO_DEFAULT; - } - - // Optimization note: We masked 'mem' earlier, so it's safe to access PS2MEM_HW directly. - // (checked disasm, and MSVC 2008 fails to optimize it on its own) - - //return psHu32(mem); - return *((u32*)&PS2MEM_HW[masked_mem]); -} - - -__forceinline void __fastcall hwWrite32(u32 mem, u32 value) -{ - - if ((mem>=0x10002000) && (mem<0x10003000)) { //IPU regs - ipuWrite32(mem,value); - return; - } - if ((mem>=0x10003800) && (mem<0x10003c00)) { - vif0Write32(mem, value); - return; - } - if ((mem>=0x10003c00) && (mem<0x10004000)) { - vif1Write32(mem, value); - return; - } - - switch (mem) { - case 0x10000000: rcntWcount(0, value); break; - case 0x10000010: rcntWmode(0, value); break; - case 0x10000020: rcntWtarget(0, value); break; - case 0x10000030: rcntWhold(0, value); break; - - case 0x10000800: rcntWcount(1, value); break; - case 0x10000810: rcntWmode(1, value); break; - case 0x10000820: rcntWtarget(1, value); break; - case 0x10000830: rcntWhold(1, value); break; - - case 0x10001000: rcntWcount(2, value); break; - case 0x10001010: rcntWmode(2, value); break; - case 0x10001020: rcntWtarget(2, value); break; - - case 0x10001800: rcntWcount(3, value); break; - case 0x10001810: rcntWmode(3, value); break; - case 0x10001820: rcntWtarget(3, value); break; - - case GIF_CTRL: - //SysPrintf("GIF_CTRL write %x\n", value); - psHu32(mem) = value & 0x8; - if (value & 0x1) gsGIFReset(); - else if( value & 8 ) psHu32(GIF_STAT) |= 8; - else psHu32(GIF_STAT) &= ~8; - return; - - case GIF_MODE: - // need to set GIF_MODE (hamster ball) - psHu32(GIF_MODE) = value; - if (value & 0x1) psHu32(GIF_STAT)|= 0x1; - else psHu32(GIF_STAT)&= ~0x1; - if (value & 0x4) psHu32(GIF_STAT)|= 0x4; - else psHu32(GIF_STAT)&= ~0x4; - break; - - case GIF_STAT: // stat is readonly - SysPrintf("Gifstat write value = %x\n", value); - return; - - case 0x10008000: // dma0 - vif0 - DMA_LOG("VIF0dma %lx\n", value); - DmaExec(dmaVIF0, mem, value); - break; -//------------------------------------------------------------------ - case 0x10009000: // dma1 - vif1 - chcr - DMA_LOG("VIF1dma CHCR %lx\n", value); - DmaExec(dmaVIF1, mem, value); - break; -#ifdef PCSX2_DEVBUILD - case 0x10009010: // dma1 - vif1 - madr - HW_LOG("VIF1dma Madr %lx\n", value); - psHu32(mem) = value;//dma1 madr - break; - case 0x10009020: // dma1 - vif1 - qwc - HW_LOG("VIF1dma QWC %lx\n", value); - psHu32(mem) = value;//dma1 qwc - break; - case 0x10009030: // dma1 - vif1 - tadr - HW_LOG("VIF1dma TADR %lx\n", value); - psHu32(mem) = value;//dma1 tadr - break; - case 0x10009040: // dma1 - vif1 - asr0 - HW_LOG("VIF1dma ASR0 %lx\n", value); - psHu32(mem) = value;//dma1 asr0 - break; - case 0x10009050: // dma1 - vif1 - asr1 - HW_LOG("VIF1dma ASR1 %lx\n", value); - psHu32(mem) = value;//dma1 asr1 - break; - case 0x10009080: // dma1 - vif1 - sadr - HW_LOG("VIF1dma SADR %lx\n", value); - psHu32(mem) = value;//dma1 sadr - break; -#endif -//------------------------------------------------------------------ - case 0x1000a000: // dma2 - gif - DMA_LOG("0x%8.8x hwWrite32: GSdma %lx\n", cpuRegs.cycle, value); - DmaExec(dmaGIF, mem, value); - break; -#ifdef PCSX2_DEVBUILD - case 0x1000a010: - psHu32(mem) = value;//dma2 madr - HW_LOG("Hardware write DMA2_MADR 32bit at %x with value %x\n",mem,value); - break; - case 0x1000a020: - psHu32(mem) = value;//dma2 qwc - HW_LOG("Hardware write DMA2_QWC 32bit at %x with value %x\n",mem,value); - break; - case 0x1000a030: - psHu32(mem) = value;//dma2 taddr - HW_LOG("Hardware write DMA2_TADDR 32bit at %x with value %x\n",mem,value); - break; - case 0x1000a040: - psHu32(mem) = value;//dma2 asr0 - HW_LOG("Hardware write DMA2_ASR0 32bit at %x with value %x\n",mem,value); - break; - case 0x1000a050: - psHu32(mem) = value;//dma2 asr1 - HW_LOG("Hardware write DMA2_ASR1 32bit at %x with value %x\n",mem,value); - break; - case 0x1000a080: - psHu32(mem) = value;//dma2 saddr - HW_LOG("Hardware write DMA2_SADDR 32bit at %x with value %x\n",mem,value); - break; -#endif -//------------------------------------------------------------------ - case 0x1000b000: // dma3 - fromIPU - DMA_LOG("IPU0dma %lx\n", value); - DmaExec(dmaIPU0, mem, value); - break; -//------------------------------------------------------------------ -#ifdef PCSX2_DEVBUILD - case 0x1000b010: - psHu32(mem) = value;//dma2 madr - HW_LOG("Hardware write IPU0DMA_MADR 32bit at %x with value %x\n",mem,value); - break; - case 0x1000b020: - psHu32(mem) = value;//dma2 madr - HW_LOG("Hardware write IPU0DMA_QWC 32bit at %x with value %x\n",mem,value); - break; - case 0x1000b030: - psHu32(mem) = value;//dma2 tadr - HW_LOG("Hardware write IPU0DMA_TADR 32bit at %x with value %x\n",mem,value); - break; - case 0x1000b080: - psHu32(mem) = value;//dma2 saddr - HW_LOG("Hardware write IPU0DMA_SADDR 32bit at %x with value %x\n",mem,value); - break; -#endif -//------------------------------------------------------------------ - case 0x1000b400: // dma4 - toIPU - DMA_LOG("IPU1dma %lx\n", value); - DmaExec(dmaIPU1, mem, value); - break; -//------------------------------------------------------------------ -#ifdef PCSX2_DEVBUILD - case 0x1000b410: - psHu32(mem) = value;//dma2 madr - HW_LOG("Hardware write IPU1DMA_MADR 32bit at %x with value %x\n",mem,value); - break; - case 0x1000b420: - psHu32(mem) = value;//dma2 madr - HW_LOG("Hardware write IPU1DMA_QWC 32bit at %x with value %x\n",mem,value); - break; - case 0x1000b430: - psHu32(mem) = value;//dma2 tadr - HW_LOG("Hardware write IPU1DMA_TADR 32bit at %x with value %x\n",mem,value); - break; - case 0x1000b480: - psHu32(mem) = value;//dma2 saddr - HW_LOG("Hardware write IPU1DMA_SADDR 32bit at %x with value %x\n",mem,value); - break; -#endif -//------------------------------------------------------------------ - case 0x1000c000: // dma5 - sif0 - DMA_LOG("SIF0dma %lx\n", value); - //if (value == 0) psxSu32(0x30) = 0x40000; - DmaExec(dmaSIF0, mem, value); - break; -//------------------------------------------------------------------ - case 0x1000c400: // dma6 - sif1 - DMA_LOG("SIF1dma %lx\n", value); - DmaExec(dmaSIF1, mem, value); - break; -#ifdef PCSX2_DEVBUILD - case 0x1000c420: // dma6 - sif1 - qwc - HW_LOG("SIF1dma QWC = %lx\n", value); - psHu32(mem) = value; - break; - case 0x1000c430: // dma6 - sif1 - tadr - HW_LOG("SIF1dma TADR = %lx\n", value); - psHu32(mem) = value; - break; -#endif -//------------------------------------------------------------------ - case 0x1000c800: // dma7 - sif2 - DMA_LOG("SIF2dma %lx\n", value); - DmaExec(dmaSIF2, mem, value); - break; -//------------------------------------------------------------------ - case 0x1000d000: // dma8 - fromSPR - DMA_LOG("fromSPRdma %lx\n", value); - DmaExec(dmaSPR0, mem, value); - break; -//------------------------------------------------------------------ - case 0x1000d400: // dma9 - toSPR - DMA_LOG("toSPRdma %lx\n", value); - DmaExec(dmaSPR1, mem, value); - break; -//------------------------------------------------------------------ - case 0x1000e000: // DMAC_CTRL - HW_LOG("DMAC_CTRL Write 32bit %x\n", value); - psHu32(0xe000) = value; - break; - - case 0x1000e010: // DMAC_STAT - HW_LOG("DMAC_STAT Write 32bit %x\n", value); - psHu16(0xe010)&= ~(value & 0xffff); // clear on 1 - psHu16(0xe012) ^= (u16)(value >> 16); - - cpuTestDMACInts(); - break; -//------------------------------------------------------------------ - case 0x1000f000: // INTC_STAT - HW_LOG("INTC_STAT Write 32bit %x\n", value); - psHu32(0xf000)&=~value; - //cpuTestINTCInts(); - break; - - case 0x1000f010: // INTC_MASK - HW_LOG("INTC_MASK Write 32bit %x\n", value); - psHu32(0xf010) ^= (u16)value; - cpuTestINTCInts(); - break; -//------------------------------------------------------------------ - case 0x1000f430://MCH_RICM: x:4|SA:12|x:5|SDEV:1|SOP:4|SBC:1|SDEV:5 - if ((((value >> 16) & 0xFFF) == 0x21) && (((value >> 6) & 0xF) == 1) && (((psHu32(0xf440) >> 7) & 1) == 0))//INIT & SRP=0 - rdram_sdevid = 0; // if SIO repeater is cleared, reset sdevid - psHu32(mem) = value & ~0x80000000; //kill the busy bit - break; - - case 0x1000f440://MCH_DRD: - psHu32(mem) = value; - break; -//------------------------------------------------------------------ - case 0x1000f590: // DMAC_ENABLEW - HW_LOG("DMAC_ENABLEW Write 32bit %lx\n", value); - psHu32(0xf590) = value; - psHu32(0xf520) = value; - return; -//------------------------------------------------------------------ - case 0x1000f200: - psHu32(mem) = value; - break; - case 0x1000f220: - psHu32(mem) |= value; - break; - case 0x1000f230: - psHu32(mem) &= ~value; - break; - case 0x1000f240: - if(!(value & 0x100)) - psHu32(mem) &= ~0x100; - else - psHu32(mem) |= 0x100; - break; - case 0x1000f260: - psHu32(mem) = 0; - break; -//------------------------------------------------------------------ - case 0x1000f130: - case 0x1000f410: - HW_LOG("Unknown Hardware write 32 at %x with value %x (%x)\n", mem, value, cpuRegs.CP0.n.Status.val); - break; -//------------------------------------------------------------------ - default: - psHu32(mem) = value; - HW_LOG("Unknown Hardware write 32 at %x with value %x (%x)\n", mem, value, cpuRegs.CP0.n.Status.val); - break; - } -} - -#endif - -#if 0 -__forceinline void hwWrite64(u32 mem, u64 value) -{ - u32 val32; - int i; - - if ((mem>=0x10002000) && (mem<=0x10002030)) { - ipuWrite64(mem, value); - return; - } - - if ((mem>=0x10003800) && (mem<0x10003c00)) { - vif0Write32(mem, value); return; - } - if ((mem>=0x10003c00) && (mem<0x10004000)) { - vif1Write32(mem, value); return; - } - - switch (mem) { - case GIF_CTRL: - DevCon::Status("GIF_CTRL write 64", params value); - psHu32(mem) = value & 0x8; - if(value & 0x1) { - gsGIFReset(); - //gsReset(); - } - else { - if( value & 8 ) psHu32(GIF_STAT) |= 8; - else psHu32(GIF_STAT) &= ~8; - } - - return; - - case GIF_MODE: -#ifdef GSPATH3FIX - Console::Status("GIFMODE64 %x\n", params value); -#endif - psHu64(GIF_MODE) = value; - if (value & 0x1) psHu32(GIF_STAT)|= 0x1; - else psHu32(GIF_STAT)&= ~0x1; - if (value & 0x4) psHu32(GIF_STAT)|= 0x4; - else psHu32(GIF_STAT)&= ~0x4; - break; - - case GIF_STAT: // stat is readonly - return; - - case 0x1000a000: // dma2 - gif - DMA_LOG("0x%8.8x hwWrite64: GSdma %lx\n", cpuRegs.cycle, value); - DmaExec(dmaGIF, mem, value); - break; - - case 0x1000e000: // DMAC_CTRL - HW_LOG("DMAC_CTRL Write 64bit %x\n", value); - psHu64(mem) = value; - break; - - case 0x1000e010: // DMAC_STAT - HW_LOG("DMAC_STAT Write 64bit %x\n", value); - val32 = (u32)value; - psHu16(0xe010)&= ~(val32 & 0xffff); // clear on 1 - val32 = val32 >> 16; - for (i=0; i<16; i++) { // reverse on 1 - if (val32 & (1<= 0x10004000 && mem < 0x10008000) { - WriteFIFO(mem, value); return; - } - - switch (mem) { - case 0x1000f590: // DMAC_ENABLEW - psHu32(0xf590) = *(u32*)value; - psHu32(0xf520) = *(u32*)value; - break; - case 0x1000f130: - case 0x1000f410: - case 0x1000f430: - break; - - default: - - psHu64(mem ) = value[0]; - psHu64(mem+8) = value[1]; - - HW_LOG("Unknown Hardware write 128 at %x with value %x_%x (status=%x)\n", mem, value[1], value[0], cpuRegs.CP0.n.Status.val); - break; - } -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "iR5900.h" +#include "VUmicro.h" +#include "IopMem.h" + +// The full suite of hardware APIs: +#include "IPU/IPU.h" +#include "GS.h" +#include "Counters.h" +#include "Vif.h" +#include "VifDma.h" +#include "SPR.h" +#include "Sif.h" + +using namespace R5900; + +u8 *psH; // hw mem + +int rdram_devices = 2; // put 8 for TOOL and 2 for PS2 and PSX +int rdram_sdevid = 0; + +void hwInit() +{ + gsInit(); + vif0Init(); + vif1Init(); + vifDmaInit(); + sifInit(); + sprInit(); + ipuInit(); +} + +void hwShutdown() { + ipuShutdown(); +} + +void hwReset() +{ + hwInit(); + + memzero_ptr( PS2MEM_HW ); + //memset(PS2MEM_HW+0x2000, 0, 0x0000e000); + + psHu32(0xf520) = 0x1201; + psHu32(0xf260) = 0x1D000060; + // i guess this is kinda a version, it's used by some bioses + psHu32(0xf590) = 0x1201; + + gsReset(); + ipuReset(); +} + +__forceinline void intcInterrupt() +{ + if ((cpuRegs.CP0.n.Status.val & 0x400) != 0x400) return; + + if ((psHu32(INTC_STAT)) == 0) { + DevCon::Notice("*PCSX2*: intcInterrupt already cleared"); + return; + } + if ((psHu32(INTC_STAT) & psHu32(INTC_MASK)) == 0) return; + + HW_LOG("intcInterrupt %x\n", psHu32(INTC_STAT) & psHu32(INTC_MASK)); + if(psHu32(INTC_STAT) & 0x2){ + counters[0].hold = rcntRcount(0); + counters[1].hold = rcntRcount(1); + } + + cpuException(0x400, cpuRegs.branch); +} + +__forceinline void dmacInterrupt() +{ + if ((cpuRegs.CP0.n.Status.val & 0x10807) != 0x10801) return; + + if( ((psHu16(0xe012) & psHu16(0xe010)) == 0 ) && + ( psHu16(0xe010) & 0x8000) == 0 ) return; + + if((psHu32(DMAC_CTRL) & 0x1) == 0) return; + + HW_LOG("dmacInterrupt %x\n", (psHu16(0xe012) & psHu16(0xe010) || + psHu16(0xe010) & 0x8000)); + + cpuException(0x800, cpuRegs.branch); +} + +void hwIntcIrq(int n) { + psHu32(INTC_STAT)|= 1<= msize) { + int s1 = msize - addr; + int s2 = size - s1; + + /* it does, so first copy 's1' bytes from 'data' to 'addr' */ + dst = (u8*)PSM(addr); + if (dst == NULL) return -1; + Cpu->Clear(addr, s1/4); + memcpy_fast(dst, data, s1); + + /* and second copy 's2' bytes from '&data[s1]' to 'maddr' */ + dst = (u8*)PSM(psHu32(DMAC_RBOR)); + if (dst == NULL) return -1; + Cpu->Clear(psHu32(DMAC_RBOR), s2/4); + memcpy_fast(dst, &data[s1], s2); + } else { + //u32 * tempptr, * tempptr2; + + /* it doesn't, so just copy 'size' bytes from 'data' to 'addr' */ + dst = (u8*)PSM(addr); + if (dst == NULL) return -1; + Cpu->Clear(addr, size/4); + memcpy_fast(dst, data, size); + } + + return 0; +} + + +int hwDmacSrcChainWithStack(DMACh *dma, int id) { + u32 temp; + + switch (id) { + case 0: // Refe - Transfer Packet According to ADDR field + //dma->tadr += 16; + return 1; //End Transfer + + case 1: // CNT - Transfer QWC following the tag. + dma->madr = dma->tadr + 16; //Set MADR to QW after Tag + dma->tadr = dma->madr + (dma->qwc << 4); //Set TADR to QW following the data + return 0; + + case 2: // Next - Transfer QWC following tag. TADR = ADDR + temp = dma->madr; //Temporarily Store ADDR + dma->madr = dma->tadr + 16; //Set MADR to QW following the tag + dma->tadr = temp; //Copy temporarily stored ADDR to Tag + return 0; + + case 3: // Ref - Transfer QWC from ADDR field + case 4: // Refs - Transfer QWC from ADDR field (Stall Control) + dma->tadr += 16; //Set TADR to next tag + return 0; + + case 5: // Call - Transfer QWC following the tag, save succeeding tag + temp = dma->madr; //Temporarily Store ADDR + + dma->madr = dma->tadr + 16; //Set MADR to data following the tag + + if ((dma->chcr & 0x30) == 0x0) { //Check if ASR0 is empty + dma->asr0 = dma->madr + (dma->qwc << 4); //If yes store Succeeding tag + dma->chcr = (dma->chcr & 0xffffffcf) | 0x10; //1 Address in call stack + }else if((dma->chcr & 0x30) == 0x10){ + dma->chcr = (dma->chcr & 0xffffffcf) | 0x20; //2 Addresses in call stack + dma->asr1 = dma->madr + (dma->qwc << 4); //If no store Succeeding tag in ASR1 + }else { + SysPrintf("Call Stack Overflow (report if it fixes/breaks anything)\n"); + return 1; //Return done + } + dma->tadr = temp; //Set TADR to temporarily stored ADDR + + return 0; + + case 6: // Ret - Transfer QWC following the tag, load next tag + dma->madr = dma->tadr + 16; //Set MADR to data following the tag + + if ((dma->chcr & 0x30) == 0x20) { //If ASR1 is NOT equal to 0 (Contains address) + dma->chcr = (dma->chcr & 0xffffffcf) | 0x10; //1 Address left in call stack + dma->tadr = dma->asr1; //Read ASR1 as next tag + dma->asr1 = 0; //Clear ASR1 + } else { //If ASR1 is empty (No address held) + if((dma->chcr & 0x30) == 0x10) { //Check if ASR0 is NOT equal to 0 (Contains address) + dma->chcr = (dma->chcr & 0xffffffcf); //No addresses left in call stack + dma->tadr = dma->asr0; //Read ASR0 as next tag + dma->asr0 = 0; //Clear ASR0 + } else { //Else if ASR1 and ASR0 are empty + //dma->tadr += 16; //Clear tag address - Kills Klonoa 2 + return 1; //End Transfer + } + } + return 0; + + case 7: // End - Transfer QWC following the tag + dma->madr = dma->tadr + 16; //Set MADR to data following the tag + //comment out tadr fixes lemans + //dma->tadr = dma->madr + (dma->qwc << 4); //Dont Increment tag, breaks Soul Calibur II and III + return 1; //End Transfer + } + + return -1; +} + +int hwDmacSrcChain(DMACh *dma, int id) { + u32 temp; + + switch (id) { + case 0: // Refe - Transfer Packet According to ADDR field + //dma->tadr += 16; + return 1; //End Transfer + + case 1: // CNT - Transfer QWC following the tag. + dma->madr = dma->tadr + 16; //Set MADR to QW after Tag + dma->tadr = dma->madr + (dma->qwc << 4); //Set TADR to QW following the data + return 0; + + case 2: // Next - Transfer QWC following tag. TADR = ADDR + temp = dma->madr; //Temporarily Store ADDR + dma->madr = dma->tadr + 16; //Set MADR to QW following the tag + dma->tadr = temp; //Copy temporarily stored ADDR to Tag + return 0; + + case 3: // Ref - Transfer QWC from ADDR field + case 4: // Refs - Transfer QWC from ADDR field (Stall Control) + dma->tadr += 16; //Set TADR to next tag + return 0; + + case 7: // End - Transfer QWC following the tag + dma->madr = dma->tadr + 16; //Set MADR to data following the tag + //dma->tadr = dma->madr + (dma->qwc << 4); //Dont Increment tag, breaks Soul Calibur II and III + return 1; //End Transfer + } + + return -1; +} + +// Original hwRead/Write32 functions .. left in for now, for troubleshooting purposes. +#if 0 +mem32_t __fastcall hwRead32(u32 mem) +{ + // *Performance Warning* This function is called -A-LOT. Be weary when making changes. It + // could impact FPS significantly. + + // Optimization Note: + // Shortcut for the INTC_STAT register, which is checked *very* frequently as part of the EE's + // vsynch timers. INTC_STAT has the disadvantage of being in the 0x1000f000 case, which has + // a lot of additional registers in it, and combined with it's call frequency is a bad thing. + + if(mem == INTC_STAT) + { + // This one is checked alot, so leave it commented out unless you love 600 meg logfiles. + //HW_LOG("DMAC_STAT Read 32bit %x\n", psHu32(0xe010)); + return psHu32(INTC_STAT); + } + + const u16 masked_mem = mem & 0xffff; + + // We optimize the hw register reads by breaking them into manageable 4k chunks (for a total of + // 16 cases spanning the 64k PS2 hw register memory map). It helps also that the EE is, for + // the most part, designed so that various classes of registers are sectioned off into these + // 4k segments. + + // Notes: Breaks from the switch statement will return a standard hw memory read. + // Special case handling of reads should use "return" directly. + + switch( masked_mem>>12 ) // switch out as according to the 4k page of the access. + { + // Counters Registers + // This code uses some optimized trickery to produce more compact output. + // See below for the "reference" block to get a better idea what this code does. :) + + case 0x0: // counters 0 and 1 + case 0x1: // counters 2 and 3 + { + const uint cntidx = masked_mem >> 11; // neat trick to scale the counter HW address into 0-3 range. + switch( (masked_mem>>4) & 0xf ) + { + case 0x0: return (u16)rcntRcount(cntidx); + case 0x1: return (u16)counters[cntidx].modeval; + case 0x2: return (u16)counters[cntidx].target; + case 0x3: return (u16)counters[cntidx].hold; + } + } + +#if 0 // Counters Reference Block (original case setup) + case 0x10000000: return (u16)rcntRcount(0); + case 0x10000010: return (u16)counters[0].modeval; + case 0x10000020: return (u16)counters[0].target; + case 0x10000030: return (u16)counters[0].hold; + + case 0x10000800: return (u16)rcntRcount(1); + case 0x10000810: return (u16)counters[1].modeval; + case 0x10000820: return (u16)counters[1].target; + case 0x10000830: return (u16)counters[1].hold; + + case 0x10001000: return (u16)rcntRcount(2); + case 0x10001010: return (u16)counters[2].modeval; + case 0x10001020: return (u16)counters[2].target; + + case 0x10001800: return (u16)rcntRcount(3); + case 0x10001810: return (u16)counters[3].modeval; + case 0x10001820: return (u16)counters[3].target; +#endif + + break; + + case 0x2: return ipuRead32( mem ); + + case 0xf: + switch( (masked_mem >> 4) & 0xff ) + { + case 0x01: + HW_LOG("INTC_MASK Read32, value=0x%x", psHu32(INTC_MASK)); + break; + + case 0x13: // 0x1000f130 + case 0x26: // 0x1000f260 SBUS? + case 0x41: // 0x1000f410 + case 0x43: // MCH_RICM + return 0; + + case 0x24: // 0x1000f240: SBUS + return psHu32(0xf240) | 0xF0000102; + + case 0x44: // 0x1000f440: MCH_DRD + + if( !((psHu32(0xf430) >> 6) & 0xF) ) + { + switch ((psHu32(0xf430)>>16) & 0xFFF) + { + //MCH_RICM: x:4|SA:12|x:5|SDEV:1|SOP:4|SBC:1|SDEV:5 + + case 0x21://INIT + if(rdram_sdevid < rdram_devices) + { + rdram_sdevid++; + return 0x1F; + } + return 0; + + case 0x23://CNFGA + return 0x0D0D; //PVER=3 | MVER=16 | DBL=1 | REFBIT=5 + + case 0x24://CNFGB + //0x0110 for PSX SVER=0 | CORG=8(5x9x7) | SPT=1 | DEVTYP=0 | BYTE=0 + return 0x0090; //SVER=0 | CORG=4(5x9x6) | SPT=1 | DEVTYP=0 | BYTE=0 + + case 0x40://DEVID + return psHu32(0xf430) & 0x1F; // =SDEV + } + } + return 0; + } + break; + + /////////////////////////////////////////////////////// + // Most of the following case handlers are for developer builds only (logging). + // It'll all optimize to ziltch in public release builds. + + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + { + const char* regName = "Unknown"; + + switch( mem ) + { + case D2_CHCR: regName = "DMA2_CHCR"; break; + case D2_MADR: regName = "DMA2_MADR"; break; + case D2_QWC: regName = "DMA2_QWC"; break; + case D2_TADR: regName = "DMA2_TADDR"; break; + case D2_ASR0: regName = "DMA2_ASR0"; break; + case D2_ASR1: regName = "DMA2_ASR1"; break; + case D2_SADR: regName = "DMA2_SADDR"; break; + } + + HW_LOG( "Hardware Read32 at 0x%x (%s), value=0x%x\n", mem, regName, psHu32(mem) ); + } + break; + + case 0x0b: + if( mem == D4_CHCR ) + HW_LOG("Hardware Read32 at 0x%x (IPU1:DMA4_CHCR), value=0x%x\n", mem, psHu32(mem)); + break; + + case 0x0c: + case 0x0d: + case 0x0e: + if( mem == DMAC_STAT ) + HW_LOG("DMAC_STAT Read32, value=0x%x\n", psHu32(DMAC_STAT)); + break; + + jNO_DEFAULT; + } + + // Optimization note: We masked 'mem' earlier, so it's safe to access PS2MEM_HW directly. + // (checked disasm, and MSVC 2008 fails to optimize it on its own) + + //return psHu32(mem); + return *((u32*)&PS2MEM_HW[masked_mem]); +} + + +__forceinline void __fastcall hwWrite32(u32 mem, u32 value) +{ + + if ((mem>=0x10002000) && (mem<0x10003000)) { //IPU regs + ipuWrite32(mem,value); + return; + } + if ((mem>=0x10003800) && (mem<0x10003c00)) { + vif0Write32(mem, value); + return; + } + if ((mem>=0x10003c00) && (mem<0x10004000)) { + vif1Write32(mem, value); + return; + } + + switch (mem) { + case 0x10000000: rcntWcount(0, value); break; + case 0x10000010: rcntWmode(0, value); break; + case 0x10000020: rcntWtarget(0, value); break; + case 0x10000030: rcntWhold(0, value); break; + + case 0x10000800: rcntWcount(1, value); break; + case 0x10000810: rcntWmode(1, value); break; + case 0x10000820: rcntWtarget(1, value); break; + case 0x10000830: rcntWhold(1, value); break; + + case 0x10001000: rcntWcount(2, value); break; + case 0x10001010: rcntWmode(2, value); break; + case 0x10001020: rcntWtarget(2, value); break; + + case 0x10001800: rcntWcount(3, value); break; + case 0x10001810: rcntWmode(3, value); break; + case 0x10001820: rcntWtarget(3, value); break; + + case GIF_CTRL: + //SysPrintf("GIF_CTRL write %x\n", value); + psHu32(mem) = value & 0x8; + if (value & 0x1) gsGIFReset(); + else if( value & 8 ) psHu32(GIF_STAT) |= 8; + else psHu32(GIF_STAT) &= ~8; + return; + + case GIF_MODE: + // need to set GIF_MODE (hamster ball) + psHu32(GIF_MODE) = value; + if (value & 0x1) psHu32(GIF_STAT)|= 0x1; + else psHu32(GIF_STAT)&= ~0x1; + if (value & 0x4) psHu32(GIF_STAT)|= 0x4; + else psHu32(GIF_STAT)&= ~0x4; + break; + + case GIF_STAT: // stat is readonly + SysPrintf("Gifstat write value = %x\n", value); + return; + + case 0x10008000: // dma0 - vif0 + DMA_LOG("VIF0dma %lx\n", value); + DmaExec(dmaVIF0, mem, value); + break; +//------------------------------------------------------------------ + case 0x10009000: // dma1 - vif1 - chcr + DMA_LOG("VIF1dma CHCR %lx\n", value); + DmaExec(dmaVIF1, mem, value); + break; +#ifdef PCSX2_DEVBUILD + case 0x10009010: // dma1 - vif1 - madr + HW_LOG("VIF1dma Madr %lx\n", value); + psHu32(mem) = value;//dma1 madr + break; + case 0x10009020: // dma1 - vif1 - qwc + HW_LOG("VIF1dma QWC %lx\n", value); + psHu32(mem) = value;//dma1 qwc + break; + case 0x10009030: // dma1 - vif1 - tadr + HW_LOG("VIF1dma TADR %lx\n", value); + psHu32(mem) = value;//dma1 tadr + break; + case 0x10009040: // dma1 - vif1 - asr0 + HW_LOG("VIF1dma ASR0 %lx\n", value); + psHu32(mem) = value;//dma1 asr0 + break; + case 0x10009050: // dma1 - vif1 - asr1 + HW_LOG("VIF1dma ASR1 %lx\n", value); + psHu32(mem) = value;//dma1 asr1 + break; + case 0x10009080: // dma1 - vif1 - sadr + HW_LOG("VIF1dma SADR %lx\n", value); + psHu32(mem) = value;//dma1 sadr + break; +#endif +//------------------------------------------------------------------ + case 0x1000a000: // dma2 - gif + DMA_LOG("0x%8.8x hwWrite32: GSdma %lx\n", cpuRegs.cycle, value); + DmaExec(dmaGIF, mem, value); + break; +#ifdef PCSX2_DEVBUILD + case 0x1000a010: + psHu32(mem) = value;//dma2 madr + HW_LOG("Hardware write DMA2_MADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a020: + psHu32(mem) = value;//dma2 qwc + HW_LOG("Hardware write DMA2_QWC 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a030: + psHu32(mem) = value;//dma2 taddr + HW_LOG("Hardware write DMA2_TADDR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a040: + psHu32(mem) = value;//dma2 asr0 + HW_LOG("Hardware write DMA2_ASR0 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a050: + psHu32(mem) = value;//dma2 asr1 + HW_LOG("Hardware write DMA2_ASR1 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a080: + psHu32(mem) = value;//dma2 saddr + HW_LOG("Hardware write DMA2_SADDR 32bit at %x with value %x\n",mem,value); + break; +#endif +//------------------------------------------------------------------ + case 0x1000b000: // dma3 - fromIPU + DMA_LOG("IPU0dma %lx\n", value); + DmaExec(dmaIPU0, mem, value); + break; +//------------------------------------------------------------------ +#ifdef PCSX2_DEVBUILD + case 0x1000b010: + psHu32(mem) = value;//dma2 madr + HW_LOG("Hardware write IPU0DMA_MADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b020: + psHu32(mem) = value;//dma2 madr + HW_LOG("Hardware write IPU0DMA_QWC 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b030: + psHu32(mem) = value;//dma2 tadr + HW_LOG("Hardware write IPU0DMA_TADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b080: + psHu32(mem) = value;//dma2 saddr + HW_LOG("Hardware write IPU0DMA_SADDR 32bit at %x with value %x\n",mem,value); + break; +#endif +//------------------------------------------------------------------ + case 0x1000b400: // dma4 - toIPU + DMA_LOG("IPU1dma %lx\n", value); + DmaExec(dmaIPU1, mem, value); + break; +//------------------------------------------------------------------ +#ifdef PCSX2_DEVBUILD + case 0x1000b410: + psHu32(mem) = value;//dma2 madr + HW_LOG("Hardware write IPU1DMA_MADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b420: + psHu32(mem) = value;//dma2 madr + HW_LOG("Hardware write IPU1DMA_QWC 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b430: + psHu32(mem) = value;//dma2 tadr + HW_LOG("Hardware write IPU1DMA_TADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b480: + psHu32(mem) = value;//dma2 saddr + HW_LOG("Hardware write IPU1DMA_SADDR 32bit at %x with value %x\n",mem,value); + break; +#endif +//------------------------------------------------------------------ + case 0x1000c000: // dma5 - sif0 + DMA_LOG("SIF0dma %lx\n", value); + //if (value == 0) psxSu32(0x30) = 0x40000; + DmaExec(dmaSIF0, mem, value); + break; +//------------------------------------------------------------------ + case 0x1000c400: // dma6 - sif1 + DMA_LOG("SIF1dma %lx\n", value); + DmaExec(dmaSIF1, mem, value); + break; +#ifdef PCSX2_DEVBUILD + case 0x1000c420: // dma6 - sif1 - qwc + HW_LOG("SIF1dma QWC = %lx\n", value); + psHu32(mem) = value; + break; + case 0x1000c430: // dma6 - sif1 - tadr + HW_LOG("SIF1dma TADR = %lx\n", value); + psHu32(mem) = value; + break; +#endif +//------------------------------------------------------------------ + case 0x1000c800: // dma7 - sif2 + DMA_LOG("SIF2dma %lx\n", value); + DmaExec(dmaSIF2, mem, value); + break; +//------------------------------------------------------------------ + case 0x1000d000: // dma8 - fromSPR + DMA_LOG("fromSPRdma %lx\n", value); + DmaExec(dmaSPR0, mem, value); + break; +//------------------------------------------------------------------ + case 0x1000d400: // dma9 - toSPR + DMA_LOG("toSPRdma %lx\n", value); + DmaExec(dmaSPR1, mem, value); + break; +//------------------------------------------------------------------ + case 0x1000e000: // DMAC_CTRL + HW_LOG("DMAC_CTRL Write 32bit %x\n", value); + psHu32(0xe000) = value; + break; + + case 0x1000e010: // DMAC_STAT + HW_LOG("DMAC_STAT Write 32bit %x\n", value); + psHu16(0xe010)&= ~(value & 0xffff); // clear on 1 + psHu16(0xe012) ^= (u16)(value >> 16); + + cpuTestDMACInts(); + break; +//------------------------------------------------------------------ + case 0x1000f000: // INTC_STAT + HW_LOG("INTC_STAT Write 32bit %x\n", value); + psHu32(0xf000)&=~value; + //cpuTestINTCInts(); + break; + + case 0x1000f010: // INTC_MASK + HW_LOG("INTC_MASK Write 32bit %x\n", value); + psHu32(0xf010) ^= (u16)value; + cpuTestINTCInts(); + break; +//------------------------------------------------------------------ + case 0x1000f430://MCH_RICM: x:4|SA:12|x:5|SDEV:1|SOP:4|SBC:1|SDEV:5 + if ((((value >> 16) & 0xFFF) == 0x21) && (((value >> 6) & 0xF) == 1) && (((psHu32(0xf440) >> 7) & 1) == 0))//INIT & SRP=0 + rdram_sdevid = 0; // if SIO repeater is cleared, reset sdevid + psHu32(mem) = value & ~0x80000000; //kill the busy bit + break; + + case 0x1000f440://MCH_DRD: + psHu32(mem) = value; + break; +//------------------------------------------------------------------ + case 0x1000f590: // DMAC_ENABLEW + HW_LOG("DMAC_ENABLEW Write 32bit %lx\n", value); + psHu32(0xf590) = value; + psHu32(0xf520) = value; + return; +//------------------------------------------------------------------ + case 0x1000f200: + psHu32(mem) = value; + break; + case 0x1000f220: + psHu32(mem) |= value; + break; + case 0x1000f230: + psHu32(mem) &= ~value; + break; + case 0x1000f240: + if(!(value & 0x100)) + psHu32(mem) &= ~0x100; + else + psHu32(mem) |= 0x100; + break; + case 0x1000f260: + psHu32(mem) = 0; + break; +//------------------------------------------------------------------ + case 0x1000f130: + case 0x1000f410: + HW_LOG("Unknown Hardware write 32 at %x with value %x (%x)\n", mem, value, cpuRegs.CP0.n.Status.val); + break; +//------------------------------------------------------------------ + default: + psHu32(mem) = value; + HW_LOG("Unknown Hardware write 32 at %x with value %x (%x)\n", mem, value, cpuRegs.CP0.n.Status.val); + break; + } +} + +#endif + +#if 0 +__forceinline void hwWrite64(u32 mem, u64 value) +{ + u32 val32; + int i; + + if ((mem>=0x10002000) && (mem<=0x10002030)) { + ipuWrite64(mem, value); + return; + } + + if ((mem>=0x10003800) && (mem<0x10003c00)) { + vif0Write32(mem, value); return; + } + if ((mem>=0x10003c00) && (mem<0x10004000)) { + vif1Write32(mem, value); return; + } + + switch (mem) { + case GIF_CTRL: + DevCon::Status("GIF_CTRL write 64", params value); + psHu32(mem) = value & 0x8; + if(value & 0x1) { + gsGIFReset(); + //gsReset(); + } + else { + if( value & 8 ) psHu32(GIF_STAT) |= 8; + else psHu32(GIF_STAT) &= ~8; + } + + return; + + case GIF_MODE: +#ifdef GSPATH3FIX + Console::Status("GIFMODE64 %x\n", params value); +#endif + psHu64(GIF_MODE) = value; + if (value & 0x1) psHu32(GIF_STAT)|= 0x1; + else psHu32(GIF_STAT)&= ~0x1; + if (value & 0x4) psHu32(GIF_STAT)|= 0x4; + else psHu32(GIF_STAT)&= ~0x4; + break; + + case GIF_STAT: // stat is readonly + return; + + case 0x1000a000: // dma2 - gif + DMA_LOG("0x%8.8x hwWrite64: GSdma %lx\n", cpuRegs.cycle, value); + DmaExec(dmaGIF, mem, value); + break; + + case 0x1000e000: // DMAC_CTRL + HW_LOG("DMAC_CTRL Write 64bit %x\n", value); + psHu64(mem) = value; + break; + + case 0x1000e010: // DMAC_STAT + HW_LOG("DMAC_STAT Write 64bit %x\n", value); + val32 = (u32)value; + psHu16(0xe010)&= ~(val32 & 0xffff); // clear on 1 + val32 = val32 >> 16; + for (i=0; i<16; i++) { // reverse on 1 + if (val32 & (1<= 0x10004000 && mem < 0x10008000) { + WriteFIFO(mem, value); return; + } + + switch (mem) { + case 0x1000f590: // DMAC_ENABLEW + psHu32(0xf590) = *(u32*)value; + psHu32(0xf520) = *(u32*)value; + break; + case 0x1000f130: + case 0x1000f410: + case 0x1000f430: + break; + + default: + + psHu64(mem ) = value[0]; + psHu64(mem+8) = value[1]; + + HW_LOG("Unknown Hardware write 128 at %x with value %x_%x (status=%x)\n", mem, value[1], value[0], cpuRegs.CP0.n.Status.val); + break; + } +} #endif \ No newline at end of file diff --git a/pcsx2/Hw.h b/pcsx2/Hw.h index e0dee83883..8ee210efa4 100644 --- a/pcsx2/Hw.h +++ b/pcsx2/Hw.h @@ -1,444 +1,444 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __HW_H__ -#define __HW_H__ - -extern u8 *psH; // hw mem - -#define psHs8(mem) (*(s8 *)&PS2MEM_HW[(mem) & 0xffff]) -#define psHs16(mem) (*(s16*)&PS2MEM_HW[(mem) & 0xffff]) -#define psHs32(mem) (*(s32*)&PS2MEM_HW[(mem) & 0xffff]) -#define psHs64(mem) (*(s64*)&PS2MEM_HW[(mem) & 0xffff]) -#define psHu8(mem) (*(u8 *)&PS2MEM_HW[(mem) & 0xffff]) -#define psHu16(mem) (*(u16*)&PS2MEM_HW[(mem) & 0xffff]) -#define psHu32(mem) (*(u32*)&PS2MEM_HW[(mem) & 0xffff]) -#define psHu64(mem) (*(u64*)&PS2MEM_HW[(mem) & 0xffff]) - -extern void CPU_INT( u32 n, s32 ecycle ); - -////////////////////////////////////////////////////////////////////////// -// Hardware FIFOs (128 bit access only!) -// -// VIF0 -- 0x10004000 -- psH[0x4000] -// VIF1 -- 0x10005000 -- psH[0x5000] -// GIF -- 0x10006000 -- psH[0x6000] -// IPUout -- 0x10007000 -- psH[0x7000] -// IPUin -- 0x10007010 -- psH[0x7010] - -void __fastcall ReadFIFO_page_4(u32 mem, mem128_t *out); -void __fastcall ReadFIFO_page_5(u32 mem, mem128_t *out); -void __fastcall ReadFIFO_page_6(u32 mem, mem128_t *out); -void __fastcall ReadFIFO_page_7(u32 mem, mem128_t *out); - -void __fastcall WriteFIFO_page_4(u32 mem, const mem128_t *value); -void __fastcall WriteFIFO_page_5(u32 mem, const mem128_t *value); -void __fastcall WriteFIFO_page_6(u32 mem, const mem128_t *value); -void __fastcall WriteFIFO_page_7(u32 mem, const mem128_t *value); - - -// -// --- DMA --- -// - -struct DMACh { - u32 chcr; - u32 null0[3]; - u32 madr; - u32 null1[3]; - u16 qwc; u16 pad; - u32 null2[3]; - u32 tadr; - u32 null3[3]; - u32 asr0; - u32 null4[3]; - u32 asr1; - u32 null5[11]; - u32 sadr; -}; - -// HW defines - -#define RCNT0_COUNT 0x10000000 -#define RCNT0_MODE 0x10000010 -#define RCNT0_TARGET 0x10000020 -#define RCNT0_HOLD 0x10000030 - -#define RCNT1_COUNT 0x10000800 -#define RCNT1_MODE 0x10000810 -#define RCNT1_TARGET 0x10000820 -#define RCNT1_HOLD 0x10000830 - -#define RCNT2_COUNT 0x10001000 -#define RCNT2_MODE 0x10001010 -#define RCNT2_TARGET 0x10001020 - -#define RCNT3_COUNT 0x10001800 -#define RCNT3_MODE 0x10001810 -#define RCNT3_TARGET 0x10001820 - -#define IPU_CMD 0x10002000 -#define IPU_CTRL 0x10002010 -#define IPU_BP 0x10002020 -#define IPU_TOP 0x10002030 - -#define GIF_CTRL 0x10003000 -#define GIF_MODE 0x10003010 -#define GIF_STAT 0x10003020 -#define GIF_TAG0 0x10003040 -#define GIF_TAG1 0x10003050 -#define GIF_TAG2 0x10003060 -#define GIF_TAG3 0x10003070 -#define GIF_CNT 0x10003080 -#define GIF_P3CNT 0x10003090 -#define GIF_P3TAG 0x100030A0 - -#define GIF_FIFO 0x10006000 - -#define IPUout_FIFO 0x10007000 -#define IPUin_FIFO 0x10007010 - -//VIF0 -#define D0_CHCR 0x10008000 -#define D0_MADR 0x10008010 -#define D0_QWC 0x10008020 - -//VIF1 -#define D1_CHCR 0x10009000 -#define D1_MADR 0x10009010 -#define D1_QWC 0x10009020 -#define D1_TADR 0x10009030 -#define D1_ASR0 0x10009040 -#define D1_ASR1 0x10009050 -#define D1_SADR 0x10009080 - -//GS -#define D2_CHCR 0x1000A000 -#define D2_MADR 0x1000A010 -#define D2_QWC 0x1000A020 -#define D2_TADR 0x1000A030 -#define D2_ASR0 0x1000A040 -#define D2_ASR1 0x1000A050 -#define D2_SADR 0x1000A080 - -//fromIPU -#define D3_CHCR 0x1000B000 -#define D3_MADR 0x1000B010 -#define D3_QWC 0x1000B020 -#define D3_TADR 0x1000B030 -#define D3_SADR 0x1000B080 - -//toIPU -#define D4_CHCR 0x1000B400 -#define D4_MADR 0x1000B410 -#define D4_QWC 0x1000B420 -#define D4_TADR 0x1000B430 -#define D4_SADR 0x1000B480 - -//SIF0 -#define D5_CHCR 0x1000C000 -#define D5_MADR 0x1000C010 -#define D5_QWC 0x1000C020 - -//SIF1 -#define D6_CHCR 0x1000C400 -#define D6_MADR 0x1000C410 -#define D6_QWC 0x1000C420 - -//SIF2 -#define D7_CHCR 0x1000C800 -#define D7_MADR 0x1000C810 -#define D7_QWC 0x1000C820 - -//fromSPR -#define D8_CHCR 0x1000D000 -#define D8_MADR 0x1000D010 -#define D8_QWC 0x1000D020 -#define D8_SADR 0x1000D080 - - -#define DMAC_CTRL 0x1000E000 -#define DMAC_STAT 0x1000E010 -#define DMAC_PCR 0x1000E020 -#define DMAC_SQWC 0x1000E030 -#define DMAC_RBSR 0x1000E040 -#define DMAC_RBOR 0x1000E050 -#define DMAC_STADR 0x1000E060 - -#define INTC_STAT 0x1000F000 -#define INTC_MASK 0x1000F010 - -#define SBUS_F220 0x1000F220 -#define SBUS_SMFLG 0x1000F230 -#define SBUS_F240 0x1000F240 - -#define DMAC_ENABLER 0x1000F520 -#define DMAC_ENABLEW 0x1000F590 - -#define SBFLG_IOPALIVE 0x10000 -#define SBFLG_IOPSYNC 0x40000 - -#define GS_PMODE 0x12000000 -#define GS_SMODE1 0x12000010 -#define GS_SMODE2 0x12000020 -#define GS_SRFSH 0x12000030 -#define GS_SYNCH1 0x12000040 -#define GS_SYNCH2 0x12000050 -#define GS_SYNCV 0x12000060 -#define GS_DISPFB1 0x12000070 -#define GS_DISPLAY1 0x12000080 -#define GS_DISPFB2 0x12000090 -#define GS_DISPLAY2 0x120000A0 -#define GS_EXTBUF 0x120000B0 -#define GS_EXTDATA 0x120000C0 -#define GS_EXTWRITE 0x120000D0 -#define GS_BGCOLOR 0x120000E0 -#define GS_CSR 0x12001000 -#define GS_IMR 0x12001010 -#define GS_BUSDIR 0x12001040 -#define GS_SIGLBLID 0x12001080 - -#define INTC_GS 0 -#define INTC_SBUS 1 -#define INTC_VBLANK_S 2 -#define INTC_VBLANK_E 3 -#define INTC_VIF0 4 -#define INTC_VIF1 5 -#define INTC_VU0 6 -#define INTC_VU1 7 -#define INTC_IPU 8 -#define INTC_TIM0 9 -#define INTC_TIM1 10 -#define INTC_TIM2 11 -#define INTC_TIM3 12 - -#define DMAC_STAT_SIS (1<<13) // stall condition -#define DMAC_STAT_MEIS (1<<14) // mfifo empty -#define DMAC_STAT_BEIS (1<<15) // bus error -#define DMAC_STAT_SIM (1<<29) // stall mask -#define DMAC_STAT_MEIM (1<<30) // mfifo mask - -#define DMAC_VIF0 0 -#define DMAC_VIF1 1 -#define DMAC_GIF 2 -#define DMAC_FROM_IPU 3 -#define DMAC_TO_IPU 4 -#define DMAC_SIF0 5 -#define DMAC_SIF1 6 -#define DMAC_SIF2 7 -#define DMAC_FROM_SPR 8 -#define DMAC_TO_SPR 9 -#define DMAC_ERROR 15 - -#define VIF0_STAT_VPS_W (1) -#define VIF0_STAT_VPS_D (2) -#define VIF0_STAT_VPS_T (3) -#define VIF0_STAT_VPS (3) -#define VIF0_STAT_VEW (1<<2) -#define VIF0_STAT_MRK (1<<6) -#define VIF0_STAT_DBF (1<<7) -#define VIF0_STAT_VSS (1<<8) -#define VIF0_STAT_VFS (1<<9) -#define VIF0_STAT_VIS (1<<10) -#define VIF0_STAT_INT (1<<11) -#define VIF0_STAT_ER0 (1<<12) -#define VIF0_STAT_ER1 (1<<13) - -#define VIF1_STAT_VPS_W (1) -#define VIF1_STAT_VPS_D (2) -#define VIF1_STAT_VPS_T (3) -#define VIF1_STAT_VPS (3) -#define VIF1_STAT_VEW (1<<2) -#define VIF1_STAT_VGW (1<<3) -#define VIF1_STAT_MRK (1<<6) -#define VIF1_STAT_DBF (1<<7) -#define VIF1_STAT_VSS (1<<8) -#define VIF1_STAT_VFS (1<<9) -#define VIF1_STAT_VIS (1<<10) -#define VIF1_STAT_INT (1<<11) -#define VIF1_STAT_ER0 (1<<12) -#define VIF1_STAT_ER1 (1<<13) -#define VIF1_STAT_FDR (1<<23) - -//DMA interrupts & masks -#define BEISintr (0x8000) -#define VIF0intr (0x10001) -#define VIF1intr (0x20002) -#define GIFintr (0x40004) -#define IPU0intr (0x80008) -#define IPU1intr (0x100010) -#define SIF0intr (0x200020) -#define SIF1intr (0x400040) -#define SIF2intr (0x800080) -#define SPR0intr (0x1000100) -#define SPR1intr (0x2000200) -#define SISintr (0x20002000) -#define MEISintr (0x40004000) - -#define DMAend(dma, num) { \ - dma->chcr &= ~0x100; \ - psHu32(DMAC_STAT)|= 1<>12 ].aPFNs == NULL ) { - SysPrintf("dmaGetAddr: memLUT PFN warning\n"); - return NULL;//p; - } - - pbase = (u8*)memLUT[ (p-PS2MEM_BASE)>>12 ].aVFNs[0]; - if( pbase != NULL ) - p = pbase + ((u32)p&0xfff); -#endif - - return p; -} - -#else - -// Note: Dma addresses are guaranteed to be aligned to 16 bytes (128 bits) -static __forceinline void *dmaGetAddr(u32 addr) { - u8 *ptr; - -// if (addr & 0xf) { DMA_LOG("*PCSX2*: DMA address not 128bit aligned: %8.8x\n", addr); } - - if (addr & 0x80000000) { // teh sux why the f00k 0xE0000000 - return (void*)&psS[addr & 0x3ff0]; - } - - ptr = (u8*)vtlb_GetPhyPtr(addr&0x1FFFFFF0); - if (ptr == NULL) { - Console::Error("*PCSX2*: DMA error: %8.8x", params addr); - return NULL; - } - return ptr; -} - -#endif - -void hwInit(); -void hwReset(); -void hwShutdown(); - -// hw read functions -extern u8 hwRead8 (u32 mem); -extern u16 hwRead16(u32 mem); - -extern mem32_t __fastcall hwRead32_page_00(u32 mem); -extern mem32_t __fastcall hwRead32_page_01(u32 mem); -extern mem32_t __fastcall hwRead32_page_02(u32 mem); -extern mem32_t __fastcall hwRead32_page_0F(u32 mem); -extern mem32_t __fastcall hwRead32_generic(u32 mem); - -extern void __fastcall hwRead64_page_00(u32 mem, mem64_t* result ); -extern void __fastcall hwRead64_page_01(u32 mem, mem64_t* result ); -extern void __fastcall hwRead64_page_02(u32 mem, mem64_t* result ); -extern void __fastcall hwRead64_generic(u32 mem, mem64_t* result ); - -extern void __fastcall hwRead128_page_00(u32 mem, mem128_t* result ); -extern void __fastcall hwRead128_page_01(u32 mem, mem128_t* result ); -extern void __fastcall hwRead128_page_02(u32 mem, mem128_t* result ); -extern void __fastcall hwRead128_generic(u32 mem, mem128_t *out); - -// hw write functions -extern void hwWrite8 (u32 mem, u8 value); -extern void hwWrite16(u32 mem, u16 value); - -extern void __fastcall hwWrite32_page_00( u32 mem, u32 value ); -extern void __fastcall hwWrite32_page_01( u32 mem, u32 value ); -extern void __fastcall hwWrite32_page_02( u32 mem, u32 value ); -extern void __fastcall hwWrite32_page_03( u32 mem, u32 value ); -extern void __fastcall hwWrite32_page_0B( u32 mem, u32 value ); -extern void __fastcall hwWrite32_page_0E( u32 mem, u32 value ); -extern void __fastcall hwWrite32_page_0F( u32 mem, u32 value ); -extern void __fastcall hwWrite32_generic( u32 mem, u32 value ); - -extern void __fastcall hwWrite64_page_02( u32 mem, const mem64_t* srcval ); -extern void __fastcall hwWrite64_page_03( u32 mem, const mem64_t* srcval ); -extern void __fastcall hwWrite64_page_0E( u32 mem, const mem64_t* srcval ); -extern void __fastcall hwWrite64_generic( u32 mem, const mem64_t* srcval ); - -extern void __fastcall hwWrite128_generic(u32 mem, const mem128_t *srcval); - -// legacy - used for debugging sometimes -//extern mem32_t __fastcall hwRead32(u32 mem); -//extern void __fastcall hwWrite32(u32 mem, u32 value); - -//extern void hwWrite64(u32 mem, u64 value); -//extern void hwWrite128(u32 mem, const u64 *value); - -void hwIntcIrq(int n); -void hwDmacIrq(int n); - -int hwMFIFORead(u32 addr, u8 *data, u32 size); -int hwMFIFOWrite(u32 addr, u8 *data, u32 size); - -int hwDmacSrcChainWithStack(DMACh *dma, int id); -int hwDmacSrcChain(DMACh *dma, int id); - -int hwConstRead8 (u32 x86reg, u32 mem, u32 sign); -int hwConstRead16(u32 x86reg, u32 mem, u32 sign); -int hwConstRead32(u32 x86reg, u32 mem); -void hwConstRead64(u32 mem, int mmreg); -void hwConstRead128(u32 mem, int xmmreg); - -void hwConstWrite8 (u32 mem, int mmreg); -void hwConstWrite16(u32 mem, int mmreg); -void hwConstWrite32(u32 mem, int mmreg); -void hwConstWrite64(u32 mem, int mmreg); -void hwConstWrite128(u32 mem, int xmmreg); - -extern void intcInterrupt(); -extern void dmacInterrupt(); - -extern int rdram_devices, rdram_sdevid; - -#endif /* __HW_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __HW_H__ +#define __HW_H__ + +extern u8 *psH; // hw mem + +#define psHs8(mem) (*(s8 *)&PS2MEM_HW[(mem) & 0xffff]) +#define psHs16(mem) (*(s16*)&PS2MEM_HW[(mem) & 0xffff]) +#define psHs32(mem) (*(s32*)&PS2MEM_HW[(mem) & 0xffff]) +#define psHs64(mem) (*(s64*)&PS2MEM_HW[(mem) & 0xffff]) +#define psHu8(mem) (*(u8 *)&PS2MEM_HW[(mem) & 0xffff]) +#define psHu16(mem) (*(u16*)&PS2MEM_HW[(mem) & 0xffff]) +#define psHu32(mem) (*(u32*)&PS2MEM_HW[(mem) & 0xffff]) +#define psHu64(mem) (*(u64*)&PS2MEM_HW[(mem) & 0xffff]) + +extern void CPU_INT( u32 n, s32 ecycle ); + +////////////////////////////////////////////////////////////////////////// +// Hardware FIFOs (128 bit access only!) +// +// VIF0 -- 0x10004000 -- psH[0x4000] +// VIF1 -- 0x10005000 -- psH[0x5000] +// GIF -- 0x10006000 -- psH[0x6000] +// IPUout -- 0x10007000 -- psH[0x7000] +// IPUin -- 0x10007010 -- psH[0x7010] + +void __fastcall ReadFIFO_page_4(u32 mem, mem128_t *out); +void __fastcall ReadFIFO_page_5(u32 mem, mem128_t *out); +void __fastcall ReadFIFO_page_6(u32 mem, mem128_t *out); +void __fastcall ReadFIFO_page_7(u32 mem, mem128_t *out); + +void __fastcall WriteFIFO_page_4(u32 mem, const mem128_t *value); +void __fastcall WriteFIFO_page_5(u32 mem, const mem128_t *value); +void __fastcall WriteFIFO_page_6(u32 mem, const mem128_t *value); +void __fastcall WriteFIFO_page_7(u32 mem, const mem128_t *value); + + +// +// --- DMA --- +// + +struct DMACh { + u32 chcr; + u32 null0[3]; + u32 madr; + u32 null1[3]; + u16 qwc; u16 pad; + u32 null2[3]; + u32 tadr; + u32 null3[3]; + u32 asr0; + u32 null4[3]; + u32 asr1; + u32 null5[11]; + u32 sadr; +}; + +// HW defines + +#define RCNT0_COUNT 0x10000000 +#define RCNT0_MODE 0x10000010 +#define RCNT0_TARGET 0x10000020 +#define RCNT0_HOLD 0x10000030 + +#define RCNT1_COUNT 0x10000800 +#define RCNT1_MODE 0x10000810 +#define RCNT1_TARGET 0x10000820 +#define RCNT1_HOLD 0x10000830 + +#define RCNT2_COUNT 0x10001000 +#define RCNT2_MODE 0x10001010 +#define RCNT2_TARGET 0x10001020 + +#define RCNT3_COUNT 0x10001800 +#define RCNT3_MODE 0x10001810 +#define RCNT3_TARGET 0x10001820 + +#define IPU_CMD 0x10002000 +#define IPU_CTRL 0x10002010 +#define IPU_BP 0x10002020 +#define IPU_TOP 0x10002030 + +#define GIF_CTRL 0x10003000 +#define GIF_MODE 0x10003010 +#define GIF_STAT 0x10003020 +#define GIF_TAG0 0x10003040 +#define GIF_TAG1 0x10003050 +#define GIF_TAG2 0x10003060 +#define GIF_TAG3 0x10003070 +#define GIF_CNT 0x10003080 +#define GIF_P3CNT 0x10003090 +#define GIF_P3TAG 0x100030A0 + +#define GIF_FIFO 0x10006000 + +#define IPUout_FIFO 0x10007000 +#define IPUin_FIFO 0x10007010 + +//VIF0 +#define D0_CHCR 0x10008000 +#define D0_MADR 0x10008010 +#define D0_QWC 0x10008020 + +//VIF1 +#define D1_CHCR 0x10009000 +#define D1_MADR 0x10009010 +#define D1_QWC 0x10009020 +#define D1_TADR 0x10009030 +#define D1_ASR0 0x10009040 +#define D1_ASR1 0x10009050 +#define D1_SADR 0x10009080 + +//GS +#define D2_CHCR 0x1000A000 +#define D2_MADR 0x1000A010 +#define D2_QWC 0x1000A020 +#define D2_TADR 0x1000A030 +#define D2_ASR0 0x1000A040 +#define D2_ASR1 0x1000A050 +#define D2_SADR 0x1000A080 + +//fromIPU +#define D3_CHCR 0x1000B000 +#define D3_MADR 0x1000B010 +#define D3_QWC 0x1000B020 +#define D3_TADR 0x1000B030 +#define D3_SADR 0x1000B080 + +//toIPU +#define D4_CHCR 0x1000B400 +#define D4_MADR 0x1000B410 +#define D4_QWC 0x1000B420 +#define D4_TADR 0x1000B430 +#define D4_SADR 0x1000B480 + +//SIF0 +#define D5_CHCR 0x1000C000 +#define D5_MADR 0x1000C010 +#define D5_QWC 0x1000C020 + +//SIF1 +#define D6_CHCR 0x1000C400 +#define D6_MADR 0x1000C410 +#define D6_QWC 0x1000C420 + +//SIF2 +#define D7_CHCR 0x1000C800 +#define D7_MADR 0x1000C810 +#define D7_QWC 0x1000C820 + +//fromSPR +#define D8_CHCR 0x1000D000 +#define D8_MADR 0x1000D010 +#define D8_QWC 0x1000D020 +#define D8_SADR 0x1000D080 + + +#define DMAC_CTRL 0x1000E000 +#define DMAC_STAT 0x1000E010 +#define DMAC_PCR 0x1000E020 +#define DMAC_SQWC 0x1000E030 +#define DMAC_RBSR 0x1000E040 +#define DMAC_RBOR 0x1000E050 +#define DMAC_STADR 0x1000E060 + +#define INTC_STAT 0x1000F000 +#define INTC_MASK 0x1000F010 + +#define SBUS_F220 0x1000F220 +#define SBUS_SMFLG 0x1000F230 +#define SBUS_F240 0x1000F240 + +#define DMAC_ENABLER 0x1000F520 +#define DMAC_ENABLEW 0x1000F590 + +#define SBFLG_IOPALIVE 0x10000 +#define SBFLG_IOPSYNC 0x40000 + +#define GS_PMODE 0x12000000 +#define GS_SMODE1 0x12000010 +#define GS_SMODE2 0x12000020 +#define GS_SRFSH 0x12000030 +#define GS_SYNCH1 0x12000040 +#define GS_SYNCH2 0x12000050 +#define GS_SYNCV 0x12000060 +#define GS_DISPFB1 0x12000070 +#define GS_DISPLAY1 0x12000080 +#define GS_DISPFB2 0x12000090 +#define GS_DISPLAY2 0x120000A0 +#define GS_EXTBUF 0x120000B0 +#define GS_EXTDATA 0x120000C0 +#define GS_EXTWRITE 0x120000D0 +#define GS_BGCOLOR 0x120000E0 +#define GS_CSR 0x12001000 +#define GS_IMR 0x12001010 +#define GS_BUSDIR 0x12001040 +#define GS_SIGLBLID 0x12001080 + +#define INTC_GS 0 +#define INTC_SBUS 1 +#define INTC_VBLANK_S 2 +#define INTC_VBLANK_E 3 +#define INTC_VIF0 4 +#define INTC_VIF1 5 +#define INTC_VU0 6 +#define INTC_VU1 7 +#define INTC_IPU 8 +#define INTC_TIM0 9 +#define INTC_TIM1 10 +#define INTC_TIM2 11 +#define INTC_TIM3 12 + +#define DMAC_STAT_SIS (1<<13) // stall condition +#define DMAC_STAT_MEIS (1<<14) // mfifo empty +#define DMAC_STAT_BEIS (1<<15) // bus error +#define DMAC_STAT_SIM (1<<29) // stall mask +#define DMAC_STAT_MEIM (1<<30) // mfifo mask + +#define DMAC_VIF0 0 +#define DMAC_VIF1 1 +#define DMAC_GIF 2 +#define DMAC_FROM_IPU 3 +#define DMAC_TO_IPU 4 +#define DMAC_SIF0 5 +#define DMAC_SIF1 6 +#define DMAC_SIF2 7 +#define DMAC_FROM_SPR 8 +#define DMAC_TO_SPR 9 +#define DMAC_ERROR 15 + +#define VIF0_STAT_VPS_W (1) +#define VIF0_STAT_VPS_D (2) +#define VIF0_STAT_VPS_T (3) +#define VIF0_STAT_VPS (3) +#define VIF0_STAT_VEW (1<<2) +#define VIF0_STAT_MRK (1<<6) +#define VIF0_STAT_DBF (1<<7) +#define VIF0_STAT_VSS (1<<8) +#define VIF0_STAT_VFS (1<<9) +#define VIF0_STAT_VIS (1<<10) +#define VIF0_STAT_INT (1<<11) +#define VIF0_STAT_ER0 (1<<12) +#define VIF0_STAT_ER1 (1<<13) + +#define VIF1_STAT_VPS_W (1) +#define VIF1_STAT_VPS_D (2) +#define VIF1_STAT_VPS_T (3) +#define VIF1_STAT_VPS (3) +#define VIF1_STAT_VEW (1<<2) +#define VIF1_STAT_VGW (1<<3) +#define VIF1_STAT_MRK (1<<6) +#define VIF1_STAT_DBF (1<<7) +#define VIF1_STAT_VSS (1<<8) +#define VIF1_STAT_VFS (1<<9) +#define VIF1_STAT_VIS (1<<10) +#define VIF1_STAT_INT (1<<11) +#define VIF1_STAT_ER0 (1<<12) +#define VIF1_STAT_ER1 (1<<13) +#define VIF1_STAT_FDR (1<<23) + +//DMA interrupts & masks +#define BEISintr (0x8000) +#define VIF0intr (0x10001) +#define VIF1intr (0x20002) +#define GIFintr (0x40004) +#define IPU0intr (0x80008) +#define IPU1intr (0x100010) +#define SIF0intr (0x200020) +#define SIF1intr (0x400040) +#define SIF2intr (0x800080) +#define SPR0intr (0x1000100) +#define SPR1intr (0x2000200) +#define SISintr (0x20002000) +#define MEISintr (0x40004000) + +#define DMAend(dma, num) { \ + dma->chcr &= ~0x100; \ + psHu32(DMAC_STAT)|= 1<>12 ].aPFNs == NULL ) { + SysPrintf("dmaGetAddr: memLUT PFN warning\n"); + return NULL;//p; + } + + pbase = (u8*)memLUT[ (p-PS2MEM_BASE)>>12 ].aVFNs[0]; + if( pbase != NULL ) + p = pbase + ((u32)p&0xfff); +#endif + + return p; +} + +#else + +// Note: Dma addresses are guaranteed to be aligned to 16 bytes (128 bits) +static __forceinline void *dmaGetAddr(u32 addr) { + u8 *ptr; + +// if (addr & 0xf) { DMA_LOG("*PCSX2*: DMA address not 128bit aligned: %8.8x\n", addr); } + + if (addr & 0x80000000) { // teh sux why the f00k 0xE0000000 + return (void*)&psS[addr & 0x3ff0]; + } + + ptr = (u8*)vtlb_GetPhyPtr(addr&0x1FFFFFF0); + if (ptr == NULL) { + Console::Error("*PCSX2*: DMA error: %8.8x", params addr); + return NULL; + } + return ptr; +} + +#endif + +void hwInit(); +void hwReset(); +void hwShutdown(); + +// hw read functions +extern u8 hwRead8 (u32 mem); +extern u16 hwRead16(u32 mem); + +extern mem32_t __fastcall hwRead32_page_00(u32 mem); +extern mem32_t __fastcall hwRead32_page_01(u32 mem); +extern mem32_t __fastcall hwRead32_page_02(u32 mem); +extern mem32_t __fastcall hwRead32_page_0F(u32 mem); +extern mem32_t __fastcall hwRead32_generic(u32 mem); + +extern void __fastcall hwRead64_page_00(u32 mem, mem64_t* result ); +extern void __fastcall hwRead64_page_01(u32 mem, mem64_t* result ); +extern void __fastcall hwRead64_page_02(u32 mem, mem64_t* result ); +extern void __fastcall hwRead64_generic(u32 mem, mem64_t* result ); + +extern void __fastcall hwRead128_page_00(u32 mem, mem128_t* result ); +extern void __fastcall hwRead128_page_01(u32 mem, mem128_t* result ); +extern void __fastcall hwRead128_page_02(u32 mem, mem128_t* result ); +extern void __fastcall hwRead128_generic(u32 mem, mem128_t *out); + +// hw write functions +extern void hwWrite8 (u32 mem, u8 value); +extern void hwWrite16(u32 mem, u16 value); + +extern void __fastcall hwWrite32_page_00( u32 mem, u32 value ); +extern void __fastcall hwWrite32_page_01( u32 mem, u32 value ); +extern void __fastcall hwWrite32_page_02( u32 mem, u32 value ); +extern void __fastcall hwWrite32_page_03( u32 mem, u32 value ); +extern void __fastcall hwWrite32_page_0B( u32 mem, u32 value ); +extern void __fastcall hwWrite32_page_0E( u32 mem, u32 value ); +extern void __fastcall hwWrite32_page_0F( u32 mem, u32 value ); +extern void __fastcall hwWrite32_generic( u32 mem, u32 value ); + +extern void __fastcall hwWrite64_page_02( u32 mem, const mem64_t* srcval ); +extern void __fastcall hwWrite64_page_03( u32 mem, const mem64_t* srcval ); +extern void __fastcall hwWrite64_page_0E( u32 mem, const mem64_t* srcval ); +extern void __fastcall hwWrite64_generic( u32 mem, const mem64_t* srcval ); + +extern void __fastcall hwWrite128_generic(u32 mem, const mem128_t *srcval); + +// legacy - used for debugging sometimes +//extern mem32_t __fastcall hwRead32(u32 mem); +//extern void __fastcall hwWrite32(u32 mem, u32 value); + +//extern void hwWrite64(u32 mem, u64 value); +//extern void hwWrite128(u32 mem, const u64 *value); + +void hwIntcIrq(int n); +void hwDmacIrq(int n); + +int hwMFIFORead(u32 addr, u8 *data, u32 size); +int hwMFIFOWrite(u32 addr, u8 *data, u32 size); + +int hwDmacSrcChainWithStack(DMACh *dma, int id); +int hwDmacSrcChain(DMACh *dma, int id); + +int hwConstRead8 (u32 x86reg, u32 mem, u32 sign); +int hwConstRead16(u32 x86reg, u32 mem, u32 sign); +int hwConstRead32(u32 x86reg, u32 mem); +void hwConstRead64(u32 mem, int mmreg); +void hwConstRead128(u32 mem, int xmmreg); + +void hwConstWrite8 (u32 mem, int mmreg); +void hwConstWrite16(u32 mem, int mmreg); +void hwConstWrite32(u32 mem, int mmreg); +void hwConstWrite64(u32 mem, int mmreg); +void hwConstWrite128(u32 mem, int xmmreg); + +extern void intcInterrupt(); +extern void dmacInterrupt(); + +extern int rdram_devices, rdram_sdevid; + +#endif /* __HW_H__ */ diff --git a/pcsx2/HwRead.cpp b/pcsx2/HwRead.cpp index 125c7aa172..8430a59b9f 100644 --- a/pcsx2/HwRead.cpp +++ b/pcsx2/HwRead.cpp @@ -1,359 +1,359 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "iR5900.h" -#include "VUmicro.h" -#include "IopMem.h" - -// The full suite of hardware APIs: -#include "IPU/IPU.h" -#include "GS.h" -#include "Counters.h" -#include "Vif.h" -#include "VifDma.h" -#include "SPR.h" -#include "Sif.h" - -using namespace R5900; - -///////////////////////////////////////////////////////////////////////// -// Hardware READ 8 bit - -__forceinline u8 hwRead8(u32 mem) -{ - u8 ret; - - if( mem >= 0x10002000 && mem < 0x10008000 ) - DevCon::Notice("Unexpected hwRead8 from 0x%x", params mem); - - switch (mem) - { - case 0x10000000: ret = (u8)rcntRcount(0); break; - case 0x10000010: ret = (u8)counters[0].modeval; break; - case 0x10000020: ret = (u8)counters[0].target; break; - case 0x10000030: ret = (u8)counters[0].hold; break; - case 0x10000001: ret = (u8)(rcntRcount(0)>>8); break; - case 0x10000011: ret = (u8)(counters[0].modeval>>8); break; - case 0x10000021: ret = (u8)(counters[0].target>>8); break; - case 0x10000031: ret = (u8)(counters[0].hold>>8); break; - - case 0x10000800: ret = (u8)rcntRcount(1); break; - case 0x10000810: ret = (u8)counters[1].modeval; break; - case 0x10000820: ret = (u8)counters[1].target; break; - case 0x10000830: ret = (u8)counters[1].hold; break; - case 0x10000801: ret = (u8)(rcntRcount(1)>>8); break; - case 0x10000811: ret = (u8)(counters[1].modeval>>8); break; - case 0x10000821: ret = (u8)(counters[1].target>>8); break; - case 0x10000831: ret = (u8)(counters[1].hold>>8); break; - - case 0x10001000: ret = (u8)rcntRcount(2); break; - case 0x10001010: ret = (u8)counters[2].modeval; break; - case 0x10001020: ret = (u8)counters[2].target; break; - case 0x10001001: ret = (u8)(rcntRcount(2)>>8); break; - case 0x10001011: ret = (u8)(counters[2].modeval>>8); break; - case 0x10001021: ret = (u8)(counters[2].target>>8); break; - - case 0x10001800: ret = (u8)rcntRcount(3); break; - case 0x10001810: ret = (u8)counters[3].modeval; break; - case 0x10001820: ret = (u8)counters[3].target; break; - case 0x10001801: ret = (u8)(rcntRcount(3)>>8); break; - case 0x10001811: ret = (u8)(counters[3].modeval>>8); break; - case 0x10001821: ret = (u8)(counters[3].target>>8); break; - - default: - if ((mem & 0xffffff0f) == 0x1000f200) - { - if(mem == 0x1000f260) ret = 0; - else if(mem == 0x1000F240) { - ret = psHu32(mem); - //psHu32(mem) &= ~0x4000; - } - else ret = psHu32(mem); - return (u8)ret; - } - - ret = psHu8(mem); - HW_LOG("Unknown Hardware Read 8 at %x\n",mem); - break; - } - - return ret; -} - -///////////////////////////////////////////////////////////////////////// -// Hardware READ 16 bit - -__forceinline u16 hwRead16(u32 mem) -{ - u16 ret; - - if( mem >= 0x10002000 && mem < 0x10008000 ) - Console::Notice("Unexpected hwRead16 from 0x%x", params mem); - - switch (mem) { - case 0x10000000: ret = (u16)rcntRcount(0); break; - case 0x10000010: ret = (u16)counters[0].modeval; break; - case 0x10000020: ret = (u16)counters[0].target; break; - case 0x10000030: ret = (u16)counters[0].hold; break; - - case 0x10000800: ret = (u16)rcntRcount(1); break; - case 0x10000810: ret = (u16)counters[1].modeval; break; - case 0x10000820: ret = (u16)counters[1].target; break; - case 0x10000830: ret = (u16)counters[1].hold; break; - - case 0x10001000: ret = (u16)rcntRcount(2); break; - case 0x10001010: ret = (u16)counters[2].modeval; break; - case 0x10001020: ret = (u16)counters[2].target; break; - - case 0x10001800: ret = (u16)rcntRcount(3); break; - case 0x10001810: ret = (u16)counters[3].modeval; break; - case 0x10001820: ret = (u16)counters[3].target; break; - - default: - if ((mem & 0xffffff0f) == 0x1000f200) { - if(mem == 0x1000f260) ret = 0; - else if(mem == 0x1000F240) { - ret = psHu16(mem) | 0x0102; - psHu32(mem) &= ~0x4000; - } - else ret = psHu32(mem); - return (u16)ret; - } - ret = psHu16(mem); - HW_LOG("Hardware Read16 at 0x%x, value= 0x%x\n", ret, mem); - break; - } - return ret; -} - -///////////////////////////////////////////////////////////////////////// -// Hardware READ 32 bit - -// Reads hardware registers for page 0 (counters 0 and 1) -mem32_t __fastcall hwRead32_page_00(u32 mem) -{ - mem &= 0xffff; - switch( mem ) - { - case 0x00: return (u16)rcntRcount(0); - case 0x10: return (u16)counters[0].modeval; - case 0x20: return (u16)counters[0].target; - case 0x30: return (u16)counters[0].hold; - - case 0x800: return (u16)rcntRcount(1); - case 0x810: return (u16)counters[1].modeval; - case 0x820: return (u16)counters[1].target; - case 0x830: return (u16)counters[1].hold; - } - - return *((u32*)&PS2MEM_HW[mem]); -} - -// Reads hardware registers for page 1 (counters 2 and 3) -mem32_t __fastcall hwRead32_page_01(u32 mem) -{ - mem &= 0xffff; - switch( mem ) - { - case 0x1000: return (u16)rcntRcount(2); - case 0x1010: return (u16)counters[2].modeval; - case 0x1020: return (u16)counters[2].target; - - case 0x1800: return (u16)rcntRcount(3); - case 0x1810: return (u16)counters[3].modeval; - case 0x1820: return (u16)counters[3].target; - } - - return *((u32*)&PS2MEM_HW[mem]); -} - -// Reads hardware registers for page 15 (0x0F). -mem32_t __fastcall hwRead32_page_0F(u32 mem) -{ - // *Performance Warning* This function is called -A-LOT. Be weary when making changes. It - // could impact FPS significantly. - - mem &= 0xffff; - - switch( mem ) - { - case 0xf000: - // This one is checked alot, so leave it commented out unless you love 600 meg logfiles. - //HW_LOG("DMAC_STAT Read 32bit %x\n", psHu32(0xe010)); - break; - - case 0xf010: - HW_LOG("INTC_MASK Read32, value=0x%x", psHu32(INTC_MASK)); - break; - - case 0xf130: // 0x1000f130 - case 0xf260: // 0x1000f260 SBUS? - case 0xf410: // 0x1000f410 - case 0xf430: // MCH_RICM - return 0; - - case 0xf240: // 0x1000f240: SBUS - return psHu32(0xf240) | 0xF0000102; - - case 0xf440: // 0x1000f440: MCH_DRD - - if( !((psHu32(0xf430) >> 6) & 0xF) ) - { - switch ((psHu32(0xf430)>>16) & 0xFFF) - { - //MCH_RICM: x:4|SA:12|x:5|SDEV:1|SOP:4|SBC:1|SDEV:5 - - case 0x21://INIT - if(rdram_sdevid < rdram_devices) - { - rdram_sdevid++; - return 0x1F; - } - return 0; - - case 0x23://CNFGA - return 0x0D0D; //PVER=3 | MVER=16 | DBL=1 | REFBIT=5 - - case 0x24://CNFGB - //0x0110 for PSX SVER=0 | CORG=8(5x9x7) | SPT=1 | DEVTYP=0 | BYTE=0 - return 0x0090; //SVER=0 | CORG=4(5x9x6) | SPT=1 | DEVTYP=0 | BYTE=0 - - case 0x40://DEVID - return psHu32(0xf430) & 0x1F; // =SDEV - } - } - return 0; - } - return *((u32*)&PS2MEM_HW[mem]); -} - -mem32_t __fastcall hwRead32_page_02(u32 mem) -{ - return ipuRead32( mem ); -} - -// Used for all pages not explicitly specified above. -mem32_t __fastcall hwRead32_generic(u32 mem) -{ - const u16 masked_mem = mem & 0xffff; - - switch( masked_mem>>12 ) // switch out as according to the 4k page of the access. - { - /////////////////////////////////////////////////////// - // Most of the following case handlers are for developer builds only (logging). - // It'll all optimize to ziltch in public release builds. - - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0a: - { - const char* regName = "Unknown"; - - switch( mem ) - { - case D2_CHCR: regName = "DMA2_CHCR"; break; - case D2_MADR: regName = "DMA2_MADR"; break; - case D2_QWC: regName = "DMA2_QWC"; break; - case D2_TADR: regName = "DMA2_TADDR"; break; - case D2_ASR0: regName = "DMA2_ASR0"; break; - case D2_ASR1: regName = "DMA2_ASR1"; break; - case D2_SADR: regName = "DMA2_SADDR"; break; - } - - HW_LOG( "Hardware Read32 at 0x%x (%s), value=0x%x\n", mem, regName, psHu32(mem) ); - } - break; - - case 0x0b: - if( mem == D4_CHCR ) - HW_LOG("Hardware Read32 at 0x%x (IPU1:DMA4_CHCR), value=0x%x\n", mem, psHu32(mem)); - break; - - case 0x0c: - case 0x0d: - case 0x0e: - if( mem == DMAC_STAT ) - HW_LOG("DMAC_STAT Read32, value=0x%x\n", psHu32(DMAC_STAT)); - break; - - jNO_DEFAULT; - } - - return *((u32*)&PS2MEM_HW[masked_mem]); -} - -///////////////////////////////////////////////////////////////////////// -// Hardware READ 64 bit - -void __fastcall hwRead64_page_00(u32 mem, mem64_t* result ) -{ - *result = hwRead32_page_00( mem ); -} - -void __fastcall hwRead64_page_01(u32 mem, mem64_t* result ) -{ - *result = hwRead32_page_01( mem ); -} - -void __fastcall hwRead64_page_02(u32 mem, mem64_t* result ) -{ - *result = ipuRead64(mem); -} - -void __fastcall hwRead64_generic(u32 mem, mem64_t* result ) -{ - *result = psHu64(mem); - HW_LOG("Unknown Hardware Read 64 at %x\n",mem); -} - -///////////////////////////////////////////////////////////////////////// -// Hardware READ 128 bit - -void __fastcall hwRead128_page_00(u32 mem, mem128_t* result ) -{ - result[0] = hwRead32_page_00( mem ); - result[1] = 0; -} - -void __fastcall hwRead128_page_01(u32 mem, mem128_t* result ) -{ - result[0] = hwRead32_page_01( mem ); - result[1] = 0; -} - -void __fastcall hwRead128_page_02(u32 mem, mem128_t* result ) -{ - // IPU is currently unhandled in 128 bit mode. - HW_LOG("Unknown Hardware Read 128 at %x (IPU)\n",mem); -} - -void __fastcall hwRead128_generic(u32 mem, mem128_t* out) -{ - out[0] = psHu64(mem); - out[1] = psHu64(mem+8); - - HW_LOG("Unknown Hardware Read 128 at %x\n",mem); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "iR5900.h" +#include "VUmicro.h" +#include "IopMem.h" + +// The full suite of hardware APIs: +#include "IPU/IPU.h" +#include "GS.h" +#include "Counters.h" +#include "Vif.h" +#include "VifDma.h" +#include "SPR.h" +#include "Sif.h" + +using namespace R5900; + +///////////////////////////////////////////////////////////////////////// +// Hardware READ 8 bit + +__forceinline u8 hwRead8(u32 mem) +{ + u8 ret; + + if( mem >= 0x10002000 && mem < 0x10008000 ) + DevCon::Notice("Unexpected hwRead8 from 0x%x", params mem); + + switch (mem) + { + case 0x10000000: ret = (u8)rcntRcount(0); break; + case 0x10000010: ret = (u8)counters[0].modeval; break; + case 0x10000020: ret = (u8)counters[0].target; break; + case 0x10000030: ret = (u8)counters[0].hold; break; + case 0x10000001: ret = (u8)(rcntRcount(0)>>8); break; + case 0x10000011: ret = (u8)(counters[0].modeval>>8); break; + case 0x10000021: ret = (u8)(counters[0].target>>8); break; + case 0x10000031: ret = (u8)(counters[0].hold>>8); break; + + case 0x10000800: ret = (u8)rcntRcount(1); break; + case 0x10000810: ret = (u8)counters[1].modeval; break; + case 0x10000820: ret = (u8)counters[1].target; break; + case 0x10000830: ret = (u8)counters[1].hold; break; + case 0x10000801: ret = (u8)(rcntRcount(1)>>8); break; + case 0x10000811: ret = (u8)(counters[1].modeval>>8); break; + case 0x10000821: ret = (u8)(counters[1].target>>8); break; + case 0x10000831: ret = (u8)(counters[1].hold>>8); break; + + case 0x10001000: ret = (u8)rcntRcount(2); break; + case 0x10001010: ret = (u8)counters[2].modeval; break; + case 0x10001020: ret = (u8)counters[2].target; break; + case 0x10001001: ret = (u8)(rcntRcount(2)>>8); break; + case 0x10001011: ret = (u8)(counters[2].modeval>>8); break; + case 0x10001021: ret = (u8)(counters[2].target>>8); break; + + case 0x10001800: ret = (u8)rcntRcount(3); break; + case 0x10001810: ret = (u8)counters[3].modeval; break; + case 0x10001820: ret = (u8)counters[3].target; break; + case 0x10001801: ret = (u8)(rcntRcount(3)>>8); break; + case 0x10001811: ret = (u8)(counters[3].modeval>>8); break; + case 0x10001821: ret = (u8)(counters[3].target>>8); break; + + default: + if ((mem & 0xffffff0f) == 0x1000f200) + { + if(mem == 0x1000f260) ret = 0; + else if(mem == 0x1000F240) { + ret = psHu32(mem); + //psHu32(mem) &= ~0x4000; + } + else ret = psHu32(mem); + return (u8)ret; + } + + ret = psHu8(mem); + HW_LOG("Unknown Hardware Read 8 at %x\n",mem); + break; + } + + return ret; +} + +///////////////////////////////////////////////////////////////////////// +// Hardware READ 16 bit + +__forceinline u16 hwRead16(u32 mem) +{ + u16 ret; + + if( mem >= 0x10002000 && mem < 0x10008000 ) + Console::Notice("Unexpected hwRead16 from 0x%x", params mem); + + switch (mem) { + case 0x10000000: ret = (u16)rcntRcount(0); break; + case 0x10000010: ret = (u16)counters[0].modeval; break; + case 0x10000020: ret = (u16)counters[0].target; break; + case 0x10000030: ret = (u16)counters[0].hold; break; + + case 0x10000800: ret = (u16)rcntRcount(1); break; + case 0x10000810: ret = (u16)counters[1].modeval; break; + case 0x10000820: ret = (u16)counters[1].target; break; + case 0x10000830: ret = (u16)counters[1].hold; break; + + case 0x10001000: ret = (u16)rcntRcount(2); break; + case 0x10001010: ret = (u16)counters[2].modeval; break; + case 0x10001020: ret = (u16)counters[2].target; break; + + case 0x10001800: ret = (u16)rcntRcount(3); break; + case 0x10001810: ret = (u16)counters[3].modeval; break; + case 0x10001820: ret = (u16)counters[3].target; break; + + default: + if ((mem & 0xffffff0f) == 0x1000f200) { + if(mem == 0x1000f260) ret = 0; + else if(mem == 0x1000F240) { + ret = psHu16(mem) | 0x0102; + psHu32(mem) &= ~0x4000; + } + else ret = psHu32(mem); + return (u16)ret; + } + ret = psHu16(mem); + HW_LOG("Hardware Read16 at 0x%x, value= 0x%x\n", ret, mem); + break; + } + return ret; +} + +///////////////////////////////////////////////////////////////////////// +// Hardware READ 32 bit + +// Reads hardware registers for page 0 (counters 0 and 1) +mem32_t __fastcall hwRead32_page_00(u32 mem) +{ + mem &= 0xffff; + switch( mem ) + { + case 0x00: return (u16)rcntRcount(0); + case 0x10: return (u16)counters[0].modeval; + case 0x20: return (u16)counters[0].target; + case 0x30: return (u16)counters[0].hold; + + case 0x800: return (u16)rcntRcount(1); + case 0x810: return (u16)counters[1].modeval; + case 0x820: return (u16)counters[1].target; + case 0x830: return (u16)counters[1].hold; + } + + return *((u32*)&PS2MEM_HW[mem]); +} + +// Reads hardware registers for page 1 (counters 2 and 3) +mem32_t __fastcall hwRead32_page_01(u32 mem) +{ + mem &= 0xffff; + switch( mem ) + { + case 0x1000: return (u16)rcntRcount(2); + case 0x1010: return (u16)counters[2].modeval; + case 0x1020: return (u16)counters[2].target; + + case 0x1800: return (u16)rcntRcount(3); + case 0x1810: return (u16)counters[3].modeval; + case 0x1820: return (u16)counters[3].target; + } + + return *((u32*)&PS2MEM_HW[mem]); +} + +// Reads hardware registers for page 15 (0x0F). +mem32_t __fastcall hwRead32_page_0F(u32 mem) +{ + // *Performance Warning* This function is called -A-LOT. Be weary when making changes. It + // could impact FPS significantly. + + mem &= 0xffff; + + switch( mem ) + { + case 0xf000: + // This one is checked alot, so leave it commented out unless you love 600 meg logfiles. + //HW_LOG("DMAC_STAT Read 32bit %x\n", psHu32(0xe010)); + break; + + case 0xf010: + HW_LOG("INTC_MASK Read32, value=0x%x", psHu32(INTC_MASK)); + break; + + case 0xf130: // 0x1000f130 + case 0xf260: // 0x1000f260 SBUS? + case 0xf410: // 0x1000f410 + case 0xf430: // MCH_RICM + return 0; + + case 0xf240: // 0x1000f240: SBUS + return psHu32(0xf240) | 0xF0000102; + + case 0xf440: // 0x1000f440: MCH_DRD + + if( !((psHu32(0xf430) >> 6) & 0xF) ) + { + switch ((psHu32(0xf430)>>16) & 0xFFF) + { + //MCH_RICM: x:4|SA:12|x:5|SDEV:1|SOP:4|SBC:1|SDEV:5 + + case 0x21://INIT + if(rdram_sdevid < rdram_devices) + { + rdram_sdevid++; + return 0x1F; + } + return 0; + + case 0x23://CNFGA + return 0x0D0D; //PVER=3 | MVER=16 | DBL=1 | REFBIT=5 + + case 0x24://CNFGB + //0x0110 for PSX SVER=0 | CORG=8(5x9x7) | SPT=1 | DEVTYP=0 | BYTE=0 + return 0x0090; //SVER=0 | CORG=4(5x9x6) | SPT=1 | DEVTYP=0 | BYTE=0 + + case 0x40://DEVID + return psHu32(0xf430) & 0x1F; // =SDEV + } + } + return 0; + } + return *((u32*)&PS2MEM_HW[mem]); +} + +mem32_t __fastcall hwRead32_page_02(u32 mem) +{ + return ipuRead32( mem ); +} + +// Used for all pages not explicitly specified above. +mem32_t __fastcall hwRead32_generic(u32 mem) +{ + const u16 masked_mem = mem & 0xffff; + + switch( masked_mem>>12 ) // switch out as according to the 4k page of the access. + { + /////////////////////////////////////////////////////// + // Most of the following case handlers are for developer builds only (logging). + // It'll all optimize to ziltch in public release builds. + + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + { + const char* regName = "Unknown"; + + switch( mem ) + { + case D2_CHCR: regName = "DMA2_CHCR"; break; + case D2_MADR: regName = "DMA2_MADR"; break; + case D2_QWC: regName = "DMA2_QWC"; break; + case D2_TADR: regName = "DMA2_TADDR"; break; + case D2_ASR0: regName = "DMA2_ASR0"; break; + case D2_ASR1: regName = "DMA2_ASR1"; break; + case D2_SADR: regName = "DMA2_SADDR"; break; + } + + HW_LOG( "Hardware Read32 at 0x%x (%s), value=0x%x\n", mem, regName, psHu32(mem) ); + } + break; + + case 0x0b: + if( mem == D4_CHCR ) + HW_LOG("Hardware Read32 at 0x%x (IPU1:DMA4_CHCR), value=0x%x\n", mem, psHu32(mem)); + break; + + case 0x0c: + case 0x0d: + case 0x0e: + if( mem == DMAC_STAT ) + HW_LOG("DMAC_STAT Read32, value=0x%x\n", psHu32(DMAC_STAT)); + break; + + jNO_DEFAULT; + } + + return *((u32*)&PS2MEM_HW[masked_mem]); +} + +///////////////////////////////////////////////////////////////////////// +// Hardware READ 64 bit + +void __fastcall hwRead64_page_00(u32 mem, mem64_t* result ) +{ + *result = hwRead32_page_00( mem ); +} + +void __fastcall hwRead64_page_01(u32 mem, mem64_t* result ) +{ + *result = hwRead32_page_01( mem ); +} + +void __fastcall hwRead64_page_02(u32 mem, mem64_t* result ) +{ + *result = ipuRead64(mem); +} + +void __fastcall hwRead64_generic(u32 mem, mem64_t* result ) +{ + *result = psHu64(mem); + HW_LOG("Unknown Hardware Read 64 at %x\n",mem); +} + +///////////////////////////////////////////////////////////////////////// +// Hardware READ 128 bit + +void __fastcall hwRead128_page_00(u32 mem, mem128_t* result ) +{ + result[0] = hwRead32_page_00( mem ); + result[1] = 0; +} + +void __fastcall hwRead128_page_01(u32 mem, mem128_t* result ) +{ + result[0] = hwRead32_page_01( mem ); + result[1] = 0; +} + +void __fastcall hwRead128_page_02(u32 mem, mem128_t* result ) +{ + // IPU is currently unhandled in 128 bit mode. + HW_LOG("Unknown Hardware Read 128 at %x (IPU)\n",mem); +} + +void __fastcall hwRead128_generic(u32 mem, mem128_t* out) +{ + out[0] = psHu64(mem); + out[1] = psHu64(mem+8); + + HW_LOG("Unknown Hardware Read 128 at %x\n",mem); +} diff --git a/pcsx2/HwWrite.cpp b/pcsx2/HwWrite.cpp index 66d69c2f1d..4573db269c 100644 --- a/pcsx2/HwWrite.cpp +++ b/pcsx2/HwWrite.cpp @@ -1,880 +1,880 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "iR5900.h" -#include "VUmicro.h" -#include "IopMem.h" - -// The full suite of hardware APIs: -#include "IPU/IPU.h" -#include "GS.h" -#include "Counters.h" -#include "Vif.h" -#include "VifDma.h" -#include "SPR.h" -#include "Sif.h" - -using namespace R5900; - -///////////////////////////////////////////////////////////////////////// -// DMA Execution Interfaces - -// dark cloud2 uses 8 bit DMAs register writes -static __forceinline void DmaExec8( void (*func)(), u32 mem, u8 value ) -{ - psHu8(mem) = (u8)value; - if ((psHu8(mem) & 0x1) && (psHu32(DMAC_CTRL) & 0x1)) - { - /*SysPrintf("Running DMA 8 %x\n", psHu32(mem & ~0x1));*/ - func(); - } -} - -static __forceinline void DmaExec16( void (*func)(), u32 mem, u16 value ) -{ - psHu16(mem) = (u16)value; - if ((psHu16(mem) & 0x100) && (psHu32(DMAC_CTRL) & 0x1)) - { - //SysPrintf("16bit DMA Start\n"); - func(); - } -} - -static void DmaExec( void (*func)(), u32 mem, u32 value ) -{ - /* Keep the old tag if in chain mode and hw doesnt set it*/ - if( (value & 0xc) == 0x4 && (value & 0xffff0000) == 0) - psHu32(mem) = (psHu32(mem) & 0xFFFF0000) | (u16)value; - else /* Else (including Normal mode etc) write whatever the hardware sends*/ - psHu32(mem) = (u32)value; - - if ((psHu32(mem) & 0x100) && (psHu32(DMAC_CTRL) & 0x1)) - func(); -} - - -///////////////////////////////////////////////////////////////////////// -// Hardware WRITE 8 bit - -char sio_buffer[1024]; -int sio_count; - -void hwWrite8(u32 mem, u8 value) { - -#ifdef PCSX2_DEVBUILD - if( mem >= 0x10002000 && mem < 0x10008000 ) - SysPrintf("hwWrite8 to %x\n", mem); -#endif - - switch (mem) { - case 0x10000000: rcntWcount(0, value); break; - case 0x10000010: rcntWmode(0, (counters[0].modeval & 0xff00) | value); break; - case 0x10000011: rcntWmode(0, (counters[0].modeval & 0xff) | value << 8); break; - case 0x10000020: rcntWtarget(0, value); break; - case 0x10000030: rcntWhold(0, value); break; - - case 0x10000800: rcntWcount(1, value); break; - case 0x10000810: rcntWmode(1, (counters[1].modeval & 0xff00) | value); break; - case 0x10000811: rcntWmode(1, (counters[1].modeval & 0xff) | value << 8); break; - case 0x10000820: rcntWtarget(1, value); break; - case 0x10000830: rcntWhold(1, value); break; - - case 0x10001000: rcntWcount(2, value); break; - case 0x10001010: rcntWmode(2, (counters[2].modeval & 0xff00) | value); break; - case 0x10001011: rcntWmode(2, (counters[2].modeval & 0xff) | value << 8); break; - case 0x10001020: rcntWtarget(2, value); break; - - case 0x10001800: rcntWcount(3, value); break; - case 0x10001810: rcntWmode(3, (counters[3].modeval & 0xff00) | value); break; - case 0x10001811: rcntWmode(3, (counters[3].modeval & 0xff) | value << 8); break; - case 0x10001820: rcntWtarget(3, value); break; - - case 0x1000f180: - if (value == '\n') { - sio_buffer[sio_count] = 0; - Console::WriteLn( Color_Cyan, sio_buffer ); - sio_count = 0; - } else { - if (sio_count < 1023) { - sio_buffer[sio_count++] = value; - } - } - break; - - case 0x10003c02: //Tony Hawks Project 8 uses this - vif1Write32(mem & ~0x2, value << 16); - break; - case 0x10008001: // dma0 - vif0 - DMA_LOG("VIF0dma %lx\n", value); - DmaExec8(dmaVIF0, mem, value); - break; - - case 0x10009001: // dma1 - vif1 - DMA_LOG("VIF1dma %lx\n", value); - DmaExec8(dmaVIF1, mem, value); - break; - - case 0x1000a001: // dma2 - gif - DMA_LOG("0x%8.8x hwWrite8: GSdma %lx 0x%lx\n", cpuRegs.cycle, value); - DmaExec8(dmaGIF, mem, value); - break; - - case 0x1000b001: // dma3 - fromIPU - DMA_LOG("IPU0dma %lx\n", value); - DmaExec8(dmaIPU0, mem, value); - break; - - case 0x1000b401: // dma4 - toIPU - DMA_LOG("IPU1dma %lx\n", value); - DmaExec8(dmaIPU1, mem, value); - break; - - case 0x1000c001: // dma5 - sif0 - DMA_LOG("SIF0dma %lx\n", value); -// if (value == 0) psxSu32(0x30) = 0x40000; - DmaExec8(dmaSIF0, mem, value); - break; - - case 0x1000c401: // dma6 - sif1 - DMA_LOG("SIF1dma %lx\n", value); - DmaExec8(dmaSIF1, mem, value); - break; - - case 0x1000c801: // dma7 - sif2 - DMA_LOG("SIF2dma %lx\n", value); - DmaExec8(dmaSIF2, mem, value); - break; - - case 0x1000d001: // dma8 - fromSPR - DMA_LOG("fromSPRdma8 %lx\n", value); - DmaExec8(dmaSPR0, mem, value); - break; - - case 0x1000d401: // dma9 - toSPR - DMA_LOG("toSPRdma8 %lx\n", value); - DmaExec8(dmaSPR1, mem, value); - break; - - case 0x1000f592: // DMAC_ENABLEW - psHu8(0xf592) = value; - psHu8(0xf522) = value; - break; - - case 0x1000f200: // SIF(?) - psHu8(mem) = value; - break; - - case 0x1000f240:// SIF(?) - if(!(value & 0x100)) - psHu32(mem) &= ~0x100; - break; - - default: - assert( (mem&0xff0f) != 0xf200 ); - - switch(mem&~3) { - case 0x1000f130: - case 0x1000f410: - case 0x1000f430: - break; - default: - psHu8(mem) = value; - } - HW_LOG("Unknown Hardware write 8 at %x with value %x\n", mem, value); - break; - } -} - -__forceinline void hwWrite16(u32 mem, u16 value) -{ - if( mem >= 0x10002000 && mem < 0x10008000 ) - Console::Notice( "hwWrite16 to %x", params mem ); - - switch(mem) - { - case 0x10000000: rcntWcount(0, value); break; - case 0x10000010: rcntWmode(0, value); break; - case 0x10000020: rcntWtarget(0, value); break; - case 0x10000030: rcntWhold(0, value); break; - - case 0x10000800: rcntWcount(1, value); break; - case 0x10000810: rcntWmode(1, value); break; - case 0x10000820: rcntWtarget(1, value); break; - case 0x10000830: rcntWhold(1, value); break; - - case 0x10001000: rcntWcount(2, value); break; - case 0x10001010: rcntWmode(2, value); break; - case 0x10001020: rcntWtarget(2, value); break; - - case 0x10001800: rcntWcount(3, value); break; - case 0x10001810: rcntWmode(3, value); break; - case 0x10001820: rcntWtarget(3, value); break; - - case 0x10008000: // dma0 - vif0 - DMA_LOG("VIF0dma %lx\n", value); - DmaExec16(dmaVIF0, mem, value); - break; - - case 0x10009000: // dma1 - vif1 - chcr - DMA_LOG("VIF1dma CHCR %lx\n", value); - DmaExec16(dmaVIF1, mem, value); - break; - -#ifdef PCSX2_DEVBUILD - case 0x10009010: // dma1 - vif1 - madr - HW_LOG("VIF1dma Madr %lx\n", value); - psHu16(mem) = value;//dma1 madr - break; - case 0x10009020: // dma1 - vif1 - qwc - HW_LOG("VIF1dma QWC %lx\n", value); - psHu16(mem) = value;//dma1 qwc - break; - case 0x10009030: // dma1 - vif1 - tadr - HW_LOG("VIF1dma TADR %lx\n", value); - psHu16(mem) = value;//dma1 tadr - break; - case 0x10009040: // dma1 - vif1 - asr0 - HW_LOG("VIF1dma ASR0 %lx\n", value); - psHu16(mem) = value;//dma1 asr0 - break; - case 0x10009050: // dma1 - vif1 - asr1 - HW_LOG("VIF1dma ASR1 %lx\n", value); - psHu16(mem) = value;//dma1 asr1 - break; - case 0x10009080: // dma1 - vif1 - sadr - HW_LOG("VIF1dma SADR %lx\n", value); - psHu16(mem) = value;//dma1 sadr - break; -#endif -// --------------------------------------------------- - - case 0x1000a000: // dma2 - gif - DMA_LOG("0x%8.8x hwWrite32: GSdma %lx\n", cpuRegs.cycle, value); - DmaExec16(dmaGIF, mem, value); - break; - -#ifdef PCSX2_DEVBUILD - case 0x1000a010: - psHu16(mem) = value;//dma2 madr - HW_LOG("Hardware write DMA2_MADR 32bit at %x with value %x\n",mem,value); - break; - case 0x1000a020: - psHu16(mem) = value;//dma2 qwc - HW_LOG("Hardware write DMA2_QWC 32bit at %x with value %x\n",mem,value); - break; - case 0x1000a030: - psHu16(mem) = value;//dma2 taddr - HW_LOG("Hardware write DMA2_TADDR 32bit at %x with value %x\n",mem,value); - break; - case 0x1000a040: - psHu16(mem) = value;//dma2 asr0 - HW_LOG("Hardware write DMA2_ASR0 32bit at %x with value %x\n",mem,value); - break; - case 0x1000a050: - psHu16(mem) = value;//dma2 asr1 - HW_LOG("Hardware write DMA2_ASR1 32bit at %x with value %x\n",mem,value); - break; - case 0x1000a080: - psHu16(mem) = value;//dma2 saddr - HW_LOG("Hardware write DMA2_SADDR 32bit at %x with value %x\n",mem,value); - break; -#endif - - case 0x1000b000: // dma3 - fromIPU - DMA_LOG("IPU0dma %lx\n", value); - DmaExec16(dmaIPU0, mem, value); - break; - -#ifdef PCSX2_DEVBUILD - case 0x1000b010: - psHu16(mem) = value;//dma2 madr - HW_LOG("Hardware write IPU0DMA_MADR 32bit at %x with value %x\n",mem,value); - break; - case 0x1000b020: - psHu16(mem) = value;//dma2 madr - HW_LOG("Hardware write IPU0DMA_QWC 32bit at %x with value %x\n",mem,value); - break; - case 0x1000b030: - psHu16(mem) = value;//dma2 tadr - HW_LOG("Hardware write IPU0DMA_TADR 32bit at %x with value %x\n",mem,value); - break; - case 0x1000b080: - psHu16(mem) = value;//dma2 saddr - HW_LOG("Hardware write IPU0DMA_SADDR 32bit at %x with value %x\n",mem,value); - break; -#endif - - case 0x1000b400: // dma4 - toIPU - DMA_LOG("IPU1dma %lx\n", value); - DmaExec16(dmaIPU1, mem, value); - break; - -#ifdef PCSX2_DEVBUILD - case 0x1000b410: - psHu16(mem) = value;//dma2 madr - HW_LOG("Hardware write IPU1DMA_MADR 32bit at %x with value %x\n",mem,value); - break; - case 0x1000b420: - psHu16(mem) = value;//dma2 madr - HW_LOG("Hardware write IPU1DMA_QWC 32bit at %x with value %x\n",mem,value); - break; - case 0x1000b430: - psHu16(mem) = value;//dma2 tadr - HW_LOG("Hardware write IPU1DMA_TADR 32bit at %x with value %x\n",mem,value); - break; - case 0x1000b480: - psHu16(mem) = value;//dma2 saddr - HW_LOG("Hardware write IPU1DMA_SADDR 32bit at %x with value %x\n",mem,value); - break; -#endif - case 0x1000c000: // dma5 - sif0 - DMA_LOG("SIF0dma %lx\n", value); -// if (value == 0) psxSu32(0x30) = 0x40000; - DmaExec16(dmaSIF0, mem, value); - break; - - case 0x1000c002: - //? - break; - case 0x1000c400: // dma6 - sif1 - DMA_LOG("SIF1dma %lx\n", value); - DmaExec16(dmaSIF1, mem, value); - break; - -#ifdef PCSX2_DEVBUILD - case 0x1000c420: // dma6 - sif1 - qwc - HW_LOG("SIF1dma QWC = %lx\n", value); - psHu16(mem) = value; - break; - - case 0x1000c430: // dma6 - sif1 - tadr - HW_LOG("SIF1dma TADR = %lx\n", value); - psHu16(mem) = value; - break; -#endif - - case 0x1000c800: // dma7 - sif2 - DMA_LOG("SIF2dma %lx\n", value); - DmaExec16(dmaSIF2, mem, value); - break; - case 0x1000c802: - //? - break; - case 0x1000d000: // dma8 - fromSPR - DMA_LOG("fromSPRdma %lx\n", value); - DmaExec16(dmaSPR0, mem, value); - break; - - case 0x1000d400: // dma9 - toSPR - DMA_LOG("toSPRdma %lx\n", value); - DmaExec16(dmaSPR1, mem, value); - break; - case 0x1000f592: // DMAC_ENABLEW - psHu16(0xf592) = value; - psHu16(0xf522) = value; - break; - case 0x1000f130: - case 0x1000f132: - case 0x1000f410: - case 0x1000f412: - case 0x1000f430: - case 0x1000f432: - break; - - case 0x1000f200: - psHu16(mem) = value; - break; - - case 0x1000f220: - psHu16(mem) |= value; - break; - case 0x1000f230: - psHu16(mem) &= ~value; - break; - case 0x1000f240: - if(!(value & 0x100)) - psHu16(mem) &= ~0x100; - else - psHu16(mem) |= 0x100; - break; - case 0x1000f260: - psHu16(mem) = 0; - break; - - default: - psHu16(mem) = value; - HW_LOG("Unknown Hardware write 16 at %x with value %x\n",mem,value); - } -} - -// Page 0 of HW memory houses registers for Counters 0 and 1 -void __fastcall hwWrite32_page_00( u32 mem, u32 value ) -{ - mem &= 0xffff; - switch (mem) - { - case 0x000: rcntWcount(0, value); return; - case 0x010: rcntWmode(0, value); return; - case 0x020: rcntWtarget(0, value); return; - case 0x030: rcntWhold(0, value); return; - - case 0x800: rcntWcount(1, value); return; - case 0x810: rcntWmode(1, value); return; - case 0x820: rcntWtarget(1, value); return; - case 0x830: rcntWhold(1, value); return; - } - - *((u32*)&PS2MEM_HW[mem]) = value; -} - -// Page 1 of HW memory houses registers for Counters 2 and 3 -void __fastcall hwWrite32_page_01( u32 mem, u32 value ) -{ - mem &= 0xffff; - switch (mem) - { - case 0x1000: rcntWcount(2, value); return; - case 0x1010: rcntWmode(2, value); return; - case 0x1020: rcntWtarget(2, value); return; - - case 0x1800: rcntWcount(3, value); return; - case 0x1810: rcntWmode(3, value); return; - case 0x1820: rcntWtarget(3, value); return; - } - - *((u32*)&PS2MEM_HW[mem]) = value; -} - -// page 2 is the IPU register space! -void __fastcall hwWrite32_page_02( u32 mem, u32 value ) -{ - ipuWrite32(mem, value); -} - -// Page 3 contains writes to vif0 and vif1 registers, plus some GIF stuff! -void __fastcall hwWrite32_page_03( u32 mem, u32 value ) -{ - if(mem>=0x10003800) - { - if(mem<0x10003c00) - vif0Write32(mem, value); - else - vif1Write32(mem, value); - return; - } - - switch (mem) - { - case GIF_CTRL: - psHu32(mem) = value & 0x8; - if (value & 0x1) - gsGIFReset(); - else if( value & 8 ) - psHu32(GIF_STAT) |= 8; - else - psHu32(GIF_STAT) &= ~8; - break; - - case GIF_MODE: - { - // need to set GIF_MODE (hamster ball) - psHu32(GIF_MODE) = value; - - // set/clear bits 0 and 2 as per the GIF_MODE value. - const u32 bitmask = 0x1 | 0x4; - psHu32(GIF_STAT) &= ~bitmask; - psHu32(GIF_STAT) |= (u32)value & bitmask; - } - break; - - case GIF_STAT: // stat is readonly - DevCon::Notice("*PCSX2* GIFSTAT write value = 0x%x (readonly, ignored)", params value); - break; - - default: - psHu32(mem) = value; - } -} - -void __fastcall hwWrite32_page_0B( u32 mem, u32 value ) -{ - // Used for developer logging -- optimized away in Public Release. - const char* regName = "Unknown"; - - switch( mem ) - { - case D3_CHCR: // dma3 - fromIPU - DMA_LOG("IPU0dma EXECUTE, value=0x%x\n", value); - DmaExec(dmaIPU0, mem, value); - return; - - case D3_MADR: regName = "IPU0DMA_MADR"; break; - case D3_QWC: regName = "IPU0DMA_QWC"; break; - case D3_TADR: regName = "IPU0DMA_TADR"; break; - case D3_SADR: regName = "IPU0DMA_SADDR"; break; - - //------------------------------------------------------------------ - - case D4_CHCR: // dma4 - toIPU - DMA_LOG("IPU1dma EXECUTE, value=0x%x\n", value); - DmaExec(dmaIPU1, mem, value); - return; - - case D4_MADR: regName = "IPU1DMA_MADR"; break; - case D4_QWC: regName = "IPU1DMA_QWC"; break; - case D4_TADR: regName = "IPU1DMA_TADR"; break; - case D4_SADR: regName = "IPU1DMA_SADDR"; break; - } - - HW_LOG( "Hardware Write32 at 0x%x (%s), value=0x%x\n", mem, regName, value ); - psHu32(mem) = value; -} - -void __fastcall hwWrite32_page_0E( u32 mem, u32 value ) -{ - if( mem == DMAC_CTRL ) - { - HW_LOG("DMAC_CTRL Write 32bit %x\n", value); - } - else if( mem == DMAC_STAT ) - { - HW_LOG("DMAC_STAT Write 32bit %x\n", value); - - // lower 16 bits: clear on 1 - // upper 16 bits: reverse on 1 - - psHu16(0xe010) &= ~(value & 0xffff); - psHu16(0xe012) ^= (u16)(value >> 16); - - cpuTestDMACInts(); - return; - } - - psHu32(mem) = value; -} - -void __fastcall hwWrite32_page_0F( u32 mem, u32 value ) -{ - // Shift the middle 8 bits (bits 4-12) into the lower 8 bits. - // This helps the compiler optimize the switch statement into a lookup table. :) - -#define HELPSWITCH(m) (((m)>>4) & 0xff) - - switch( HELPSWITCH(mem) ) - { - case HELPSWITCH(INTC_STAT): - HW_LOG("INTC_STAT Write 32bit %x\n", value); - psHu32(INTC_STAT) &= ~value; - //cpuTestINTCInts(); - break; - - case HELPSWITCH(INTC_MASK): - HW_LOG("INTC_MASK Write 32bit %x\n", value); - psHu32(INTC_MASK) ^= (u16)value; - cpuTestINTCInts(); - break; - - //------------------------------------------------------------------ - case HELPSWITCH(0x1000f430)://MCH_RICM: x:4|SA:12|x:5|SDEV:1|SOP:4|SBC:1|SDEV:5 - if ((((value >> 16) & 0xFFF) == 0x21) && (((value >> 6) & 0xF) == 1) && (((psHu32(0xf440) >> 7) & 1) == 0))//INIT & SRP=0 - rdram_sdevid = 0; // if SIO repeater is cleared, reset sdevid - psHu32(mem) = value & ~0x80000000; //kill the busy bit - break; - - case HELPSWITCH(0x1000f200): - psHu32(mem) = value; - break; - case HELPSWITCH(0x1000f220): - psHu32(mem) |= value; - break; - case HELPSWITCH(0x1000f230): - psHu32(mem) &= ~value; - break; - case HELPSWITCH(0x1000f240): - if(!(value & 0x100)) - psHu32(mem) &= ~0x100; - else - psHu32(mem) |= 0x100; - break; - case HELPSWITCH(0x1000f260): - psHu32(mem) = 0; - break; - - case HELPSWITCH(0x1000f440)://MCH_DRD: - psHu32(mem) = value; - break; - - case HELPSWITCH(0x1000f590): // DMAC_ENABLEW - HW_LOG("DMAC_ENABLEW Write 32bit %lx\n", value); - psHu32(0xf590) = value; - psHu32(0xf520) = value; - break; - - //------------------------------------------------------------------ - case HELPSWITCH(0x1000f130): - case HELPSWITCH(0x1000f410): - HW_LOG("Unknown Hardware write 32 at %x with value %x (%x)\n", mem, value, cpuRegs.CP0.n.Status.val); - break; - - default: - psHu32(mem) = value; - } -} - -void __fastcall hwWrite32_generic( u32 mem, u32 value ) -{ - // Used for developer logging -- optimized away in Public Release. - const char* regName = "Unknown"; - - switch (mem) - { - case D0_CHCR: // dma0 - vif0 - DMA_LOG("VIF0dma EXECUTE, value=0x%x\n", value); - DmaExec(dmaVIF0, mem, value); - return; - -//------------------------------------------------------------------ - case D1_CHCR: // dma1 - vif1 - chcr - DMA_LOG("VIF1dma EXECUTE, value=0x%x\n", value); - DmaExec(dmaVIF1, mem, value); - return; - - case D1_MADR: regName = "VIF1dma MADR"; break; - case D1_QWC: regName = "VIF1dma QWC"; break; - case D1_TADR: regName = "VIF1dma TADR"; break; - case D1_ASR0: regName = "VIF1dma ASR0"; break; - case D1_ASR1: regName = "VIF1dma ASR1"; break; - case D1_SADR: regName = "VIF1dma SADR"; break; - -//------------------------------------------------------------------ - case D2_CHCR: // dma2 - gif - DMA_LOG("GIFdma EXECUTE, value=0x%x", value); - DmaExec(dmaGIF, mem, value); - return; - - case D2_MADR: regName = "GIFdma MADR"; break; - case D2_QWC: regName = "GIFdma QWC"; break; - case D2_TADR: regName = "GIFdma TADDR"; break; - case D2_ASR0: regName = "GIFdma ASR0"; break; - case D2_ASR1: regName = "GIFdma ASR1"; break; - case D2_SADR: regName = "GIFdma SADDR"; break; - -//------------------------------------------------------------------ - case 0x1000c000: // dma5 - sif0 - DMA_LOG("SIF0dma EXECUTE, value=0x%x\n", value); - //if (value == 0) psxSu32(0x30) = 0x40000; - DmaExec(dmaSIF0, mem, value); - return; -//------------------------------------------------------------------ - case 0x1000c400: // dma6 - sif1 - DMA_LOG("SIF1dma EXECUTE, value=0x%x\n", value); - DmaExec(dmaSIF1, mem, value); - return; - - case 0x1000c420: regName = "SIF1dma QWC"; break; - case 0x1000c430: regName = "SIF1dma TADR"; break; - -//------------------------------------------------------------------ - case 0x1000c800: // dma7 - sif2 - DMA_LOG("SIF2dma EXECUTE, value=0x%x\n", value); - DmaExec(dmaSIF2, mem, value); - return; -//------------------------------------------------------------------ - case 0x1000d000: // dma8 - fromSPR - DMA_LOG("SPR0dma EXECUTE (fromSPR), value=0x%x\n", value); - DmaExec(dmaSPR0, mem, value); - return; -//------------------------------------------------------------------ - case 0x1000d400: // dma9 - toSPR - DMA_LOG("SPR0dma EXECUTE (toSPR), value=0x%x\n", value); - DmaExec(dmaSPR1, mem, value); - return; - } - HW_LOG( "Hardware Write32 at 0x%x (%s), value=0x%x\n", mem, regName, value ); - psHu32(mem) = value; -} - -///////////////////////////////////////////////////////////////////////// -// HW Write 64 bit - -void __fastcall hwWrite64_page_02( u32 mem, const mem64_t* srcval ) -{ - //hwWrite64( mem, *srcval ); return; - ipuWrite64( mem, *srcval ); -} - -void __fastcall hwWrite64_page_03( u32 mem, const mem64_t* srcval ) -{ - //hwWrite64( mem, *srcval ); return; - const u64 value = *srcval; - - if(mem>=0x10003800) - { - if(mem<0x10003c00) - vif0Write32(mem, value); - else - vif1Write32(mem, value); - return; - } - - switch (mem) - { - case GIF_CTRL: - DevCon::Status("GIF_CTRL write 64", params value); - psHu32(mem) = value & 0x8; - if(value & 0x1) - gsGIFReset(); - else - { - if( value & 8 ) - psHu32(GIF_STAT) |= 8; - else - psHu32(GIF_STAT) &= ~8; - } - - return; - - case GIF_MODE: - { -#ifdef GSPATH3FIX - Console::Status("GIFMODE64 %x\n", params value); -#endif - psHu64(GIF_MODE) = value; - - // set/clear bits 0 and 2 as per the GIF_MODE value. - const u32 bitmask = 0x1 | 0x4; - psHu32(GIF_STAT) &= ~bitmask; - psHu32(GIF_STAT) |= (u32)value & bitmask; - } - - case GIF_STAT: // stat is readonly - return; - } -} - -void __fastcall hwWrite64_page_0E( u32 mem, const mem64_t* srcval ) -{ - //hwWrite64( mem, *srcval ); return; - - const u64 value = *srcval; - - if( mem == DMAC_CTRL ) - { - HW_LOG("DMAC_CTRL Write 64bit %x\n", value); - } - else if( mem == DMAC_STAT ) - { - HW_LOG("DMAC_STAT Write 64bit %x\n", value); - - // lower 16 bits: clear on 1 - // upper 16 bits: reverse on 1 - - psHu16(0xe010) &= ~(value & 0xffff); - psHu16(0xe012) ^= (u16)(value >> 16); - - cpuTestDMACInts(); - return; - } - - psHu64(mem) = value; -} - -void __fastcall hwWrite64_generic( u32 mem, const mem64_t* srcval ) -{ - //hwWrite64( mem, *srcval ); return; - - const u64 value = *srcval; - - switch (mem) - { - case 0x1000a000: // dma2 - gif - DMA_LOG("0x%8.8x hwWrite64: GSdma %x\n", cpuRegs.cycle, value); - DmaExec(dmaGIF, mem, value); - break; - - case INTC_STAT: - HW_LOG("INTC_STAT Write 64bit %x\n", (u32)value); - psHu32(INTC_STAT) &= ~value; - //cpuTestINTCInts(); - break; - - case INTC_MASK: - HW_LOG("INTC_MASK Write 64bit %x\n", (u32)value); - psHu32(INTC_MASK) ^= (u16)value; - cpuTestINTCInts(); - break; - - case 0x1000f130: - case 0x1000f410: - case 0x1000f430: - break; - - case 0x1000f590: // DMAC_ENABLEW - psHu32(0xf590) = value; - psHu32(0xf520) = value; - break; - - default: - psHu64(mem) = value; - HW_LOG("Unknown Hardware write 64 at %x with value %x (status=%x)\n",mem,value, cpuRegs.CP0.n.Status.val); - break; - } -} - -///////////////////////////////////////////////////////////////////////// -// HW Write 128 bit - -void __fastcall hwWrite128_generic(u32 mem, const mem128_t *srcval) -{ - //hwWrite128( mem, srcval ); return; - - switch (mem) - { - case INTC_STAT: - HW_LOG("INTC_STAT Write 64bit %x\n", (u32)srcval[0]); - psHu32(INTC_STAT) &= ~srcval[0]; - //cpuTestINTCInts(); - break; - - case INTC_MASK: - HW_LOG("INTC_MASK Write 64bit %x\n", (u32)srcval[0]); - psHu32(INTC_MASK) ^= (u16)srcval[0]; - cpuTestINTCInts(); - break; - - case 0x1000f590: // DMAC_ENABLEW - psHu32(0xf590) = srcval[0]; - psHu32(0xf520) = srcval[0]; - break; - - case 0x1000f130: - case 0x1000f410: - case 0x1000f430: - break; - - default: - psHu64(mem ) = srcval[0]; - psHu64(mem+8) = srcval[1]; - - HW_LOG("Unknown Hardware write 128 at %x with value %x_%x (status=%x)\n", mem, srcval[1], srcval[0], cpuRegs.CP0.n.Status.val); - break; - } -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "iR5900.h" +#include "VUmicro.h" +#include "IopMem.h" + +// The full suite of hardware APIs: +#include "IPU/IPU.h" +#include "GS.h" +#include "Counters.h" +#include "Vif.h" +#include "VifDma.h" +#include "SPR.h" +#include "Sif.h" + +using namespace R5900; + +///////////////////////////////////////////////////////////////////////// +// DMA Execution Interfaces + +// dark cloud2 uses 8 bit DMAs register writes +static __forceinline void DmaExec8( void (*func)(), u32 mem, u8 value ) +{ + psHu8(mem) = (u8)value; + if ((psHu8(mem) & 0x1) && (psHu32(DMAC_CTRL) & 0x1)) + { + /*SysPrintf("Running DMA 8 %x\n", psHu32(mem & ~0x1));*/ + func(); + } +} + +static __forceinline void DmaExec16( void (*func)(), u32 mem, u16 value ) +{ + psHu16(mem) = (u16)value; + if ((psHu16(mem) & 0x100) && (psHu32(DMAC_CTRL) & 0x1)) + { + //SysPrintf("16bit DMA Start\n"); + func(); + } +} + +static void DmaExec( void (*func)(), u32 mem, u32 value ) +{ + /* Keep the old tag if in chain mode and hw doesnt set it*/ + if( (value & 0xc) == 0x4 && (value & 0xffff0000) == 0) + psHu32(mem) = (psHu32(mem) & 0xFFFF0000) | (u16)value; + else /* Else (including Normal mode etc) write whatever the hardware sends*/ + psHu32(mem) = (u32)value; + + if ((psHu32(mem) & 0x100) && (psHu32(DMAC_CTRL) & 0x1)) + func(); +} + + +///////////////////////////////////////////////////////////////////////// +// Hardware WRITE 8 bit + +char sio_buffer[1024]; +int sio_count; + +void hwWrite8(u32 mem, u8 value) { + +#ifdef PCSX2_DEVBUILD + if( mem >= 0x10002000 && mem < 0x10008000 ) + SysPrintf("hwWrite8 to %x\n", mem); +#endif + + switch (mem) { + case 0x10000000: rcntWcount(0, value); break; + case 0x10000010: rcntWmode(0, (counters[0].modeval & 0xff00) | value); break; + case 0x10000011: rcntWmode(0, (counters[0].modeval & 0xff) | value << 8); break; + case 0x10000020: rcntWtarget(0, value); break; + case 0x10000030: rcntWhold(0, value); break; + + case 0x10000800: rcntWcount(1, value); break; + case 0x10000810: rcntWmode(1, (counters[1].modeval & 0xff00) | value); break; + case 0x10000811: rcntWmode(1, (counters[1].modeval & 0xff) | value << 8); break; + case 0x10000820: rcntWtarget(1, value); break; + case 0x10000830: rcntWhold(1, value); break; + + case 0x10001000: rcntWcount(2, value); break; + case 0x10001010: rcntWmode(2, (counters[2].modeval & 0xff00) | value); break; + case 0x10001011: rcntWmode(2, (counters[2].modeval & 0xff) | value << 8); break; + case 0x10001020: rcntWtarget(2, value); break; + + case 0x10001800: rcntWcount(3, value); break; + case 0x10001810: rcntWmode(3, (counters[3].modeval & 0xff00) | value); break; + case 0x10001811: rcntWmode(3, (counters[3].modeval & 0xff) | value << 8); break; + case 0x10001820: rcntWtarget(3, value); break; + + case 0x1000f180: + if (value == '\n') { + sio_buffer[sio_count] = 0; + Console::WriteLn( Color_Cyan, sio_buffer ); + sio_count = 0; + } else { + if (sio_count < 1023) { + sio_buffer[sio_count++] = value; + } + } + break; + + case 0x10003c02: //Tony Hawks Project 8 uses this + vif1Write32(mem & ~0x2, value << 16); + break; + case 0x10008001: // dma0 - vif0 + DMA_LOG("VIF0dma %lx\n", value); + DmaExec8(dmaVIF0, mem, value); + break; + + case 0x10009001: // dma1 - vif1 + DMA_LOG("VIF1dma %lx\n", value); + DmaExec8(dmaVIF1, mem, value); + break; + + case 0x1000a001: // dma2 - gif + DMA_LOG("0x%8.8x hwWrite8: GSdma %lx 0x%lx\n", cpuRegs.cycle, value); + DmaExec8(dmaGIF, mem, value); + break; + + case 0x1000b001: // dma3 - fromIPU + DMA_LOG("IPU0dma %lx\n", value); + DmaExec8(dmaIPU0, mem, value); + break; + + case 0x1000b401: // dma4 - toIPU + DMA_LOG("IPU1dma %lx\n", value); + DmaExec8(dmaIPU1, mem, value); + break; + + case 0x1000c001: // dma5 - sif0 + DMA_LOG("SIF0dma %lx\n", value); +// if (value == 0) psxSu32(0x30) = 0x40000; + DmaExec8(dmaSIF0, mem, value); + break; + + case 0x1000c401: // dma6 - sif1 + DMA_LOG("SIF1dma %lx\n", value); + DmaExec8(dmaSIF1, mem, value); + break; + + case 0x1000c801: // dma7 - sif2 + DMA_LOG("SIF2dma %lx\n", value); + DmaExec8(dmaSIF2, mem, value); + break; + + case 0x1000d001: // dma8 - fromSPR + DMA_LOG("fromSPRdma8 %lx\n", value); + DmaExec8(dmaSPR0, mem, value); + break; + + case 0x1000d401: // dma9 - toSPR + DMA_LOG("toSPRdma8 %lx\n", value); + DmaExec8(dmaSPR1, mem, value); + break; + + case 0x1000f592: // DMAC_ENABLEW + psHu8(0xf592) = value; + psHu8(0xf522) = value; + break; + + case 0x1000f200: // SIF(?) + psHu8(mem) = value; + break; + + case 0x1000f240:// SIF(?) + if(!(value & 0x100)) + psHu32(mem) &= ~0x100; + break; + + default: + assert( (mem&0xff0f) != 0xf200 ); + + switch(mem&~3) { + case 0x1000f130: + case 0x1000f410: + case 0x1000f430: + break; + default: + psHu8(mem) = value; + } + HW_LOG("Unknown Hardware write 8 at %x with value %x\n", mem, value); + break; + } +} + +__forceinline void hwWrite16(u32 mem, u16 value) +{ + if( mem >= 0x10002000 && mem < 0x10008000 ) + Console::Notice( "hwWrite16 to %x", params mem ); + + switch(mem) + { + case 0x10000000: rcntWcount(0, value); break; + case 0x10000010: rcntWmode(0, value); break; + case 0x10000020: rcntWtarget(0, value); break; + case 0x10000030: rcntWhold(0, value); break; + + case 0x10000800: rcntWcount(1, value); break; + case 0x10000810: rcntWmode(1, value); break; + case 0x10000820: rcntWtarget(1, value); break; + case 0x10000830: rcntWhold(1, value); break; + + case 0x10001000: rcntWcount(2, value); break; + case 0x10001010: rcntWmode(2, value); break; + case 0x10001020: rcntWtarget(2, value); break; + + case 0x10001800: rcntWcount(3, value); break; + case 0x10001810: rcntWmode(3, value); break; + case 0x10001820: rcntWtarget(3, value); break; + + case 0x10008000: // dma0 - vif0 + DMA_LOG("VIF0dma %lx\n", value); + DmaExec16(dmaVIF0, mem, value); + break; + + case 0x10009000: // dma1 - vif1 - chcr + DMA_LOG("VIF1dma CHCR %lx\n", value); + DmaExec16(dmaVIF1, mem, value); + break; + +#ifdef PCSX2_DEVBUILD + case 0x10009010: // dma1 - vif1 - madr + HW_LOG("VIF1dma Madr %lx\n", value); + psHu16(mem) = value;//dma1 madr + break; + case 0x10009020: // dma1 - vif1 - qwc + HW_LOG("VIF1dma QWC %lx\n", value); + psHu16(mem) = value;//dma1 qwc + break; + case 0x10009030: // dma1 - vif1 - tadr + HW_LOG("VIF1dma TADR %lx\n", value); + psHu16(mem) = value;//dma1 tadr + break; + case 0x10009040: // dma1 - vif1 - asr0 + HW_LOG("VIF1dma ASR0 %lx\n", value); + psHu16(mem) = value;//dma1 asr0 + break; + case 0x10009050: // dma1 - vif1 - asr1 + HW_LOG("VIF1dma ASR1 %lx\n", value); + psHu16(mem) = value;//dma1 asr1 + break; + case 0x10009080: // dma1 - vif1 - sadr + HW_LOG("VIF1dma SADR %lx\n", value); + psHu16(mem) = value;//dma1 sadr + break; +#endif +// --------------------------------------------------- + + case 0x1000a000: // dma2 - gif + DMA_LOG("0x%8.8x hwWrite32: GSdma %lx\n", cpuRegs.cycle, value); + DmaExec16(dmaGIF, mem, value); + break; + +#ifdef PCSX2_DEVBUILD + case 0x1000a010: + psHu16(mem) = value;//dma2 madr + HW_LOG("Hardware write DMA2_MADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a020: + psHu16(mem) = value;//dma2 qwc + HW_LOG("Hardware write DMA2_QWC 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a030: + psHu16(mem) = value;//dma2 taddr + HW_LOG("Hardware write DMA2_TADDR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a040: + psHu16(mem) = value;//dma2 asr0 + HW_LOG("Hardware write DMA2_ASR0 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a050: + psHu16(mem) = value;//dma2 asr1 + HW_LOG("Hardware write DMA2_ASR1 32bit at %x with value %x\n",mem,value); + break; + case 0x1000a080: + psHu16(mem) = value;//dma2 saddr + HW_LOG("Hardware write DMA2_SADDR 32bit at %x with value %x\n",mem,value); + break; +#endif + + case 0x1000b000: // dma3 - fromIPU + DMA_LOG("IPU0dma %lx\n", value); + DmaExec16(dmaIPU0, mem, value); + break; + +#ifdef PCSX2_DEVBUILD + case 0x1000b010: + psHu16(mem) = value;//dma2 madr + HW_LOG("Hardware write IPU0DMA_MADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b020: + psHu16(mem) = value;//dma2 madr + HW_LOG("Hardware write IPU0DMA_QWC 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b030: + psHu16(mem) = value;//dma2 tadr + HW_LOG("Hardware write IPU0DMA_TADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b080: + psHu16(mem) = value;//dma2 saddr + HW_LOG("Hardware write IPU0DMA_SADDR 32bit at %x with value %x\n",mem,value); + break; +#endif + + case 0x1000b400: // dma4 - toIPU + DMA_LOG("IPU1dma %lx\n", value); + DmaExec16(dmaIPU1, mem, value); + break; + +#ifdef PCSX2_DEVBUILD + case 0x1000b410: + psHu16(mem) = value;//dma2 madr + HW_LOG("Hardware write IPU1DMA_MADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b420: + psHu16(mem) = value;//dma2 madr + HW_LOG("Hardware write IPU1DMA_QWC 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b430: + psHu16(mem) = value;//dma2 tadr + HW_LOG("Hardware write IPU1DMA_TADR 32bit at %x with value %x\n",mem,value); + break; + case 0x1000b480: + psHu16(mem) = value;//dma2 saddr + HW_LOG("Hardware write IPU1DMA_SADDR 32bit at %x with value %x\n",mem,value); + break; +#endif + case 0x1000c000: // dma5 - sif0 + DMA_LOG("SIF0dma %lx\n", value); +// if (value == 0) psxSu32(0x30) = 0x40000; + DmaExec16(dmaSIF0, mem, value); + break; + + case 0x1000c002: + //? + break; + case 0x1000c400: // dma6 - sif1 + DMA_LOG("SIF1dma %lx\n", value); + DmaExec16(dmaSIF1, mem, value); + break; + +#ifdef PCSX2_DEVBUILD + case 0x1000c420: // dma6 - sif1 - qwc + HW_LOG("SIF1dma QWC = %lx\n", value); + psHu16(mem) = value; + break; + + case 0x1000c430: // dma6 - sif1 - tadr + HW_LOG("SIF1dma TADR = %lx\n", value); + psHu16(mem) = value; + break; +#endif + + case 0x1000c800: // dma7 - sif2 + DMA_LOG("SIF2dma %lx\n", value); + DmaExec16(dmaSIF2, mem, value); + break; + case 0x1000c802: + //? + break; + case 0x1000d000: // dma8 - fromSPR + DMA_LOG("fromSPRdma %lx\n", value); + DmaExec16(dmaSPR0, mem, value); + break; + + case 0x1000d400: // dma9 - toSPR + DMA_LOG("toSPRdma %lx\n", value); + DmaExec16(dmaSPR1, mem, value); + break; + case 0x1000f592: // DMAC_ENABLEW + psHu16(0xf592) = value; + psHu16(0xf522) = value; + break; + case 0x1000f130: + case 0x1000f132: + case 0x1000f410: + case 0x1000f412: + case 0x1000f430: + case 0x1000f432: + break; + + case 0x1000f200: + psHu16(mem) = value; + break; + + case 0x1000f220: + psHu16(mem) |= value; + break; + case 0x1000f230: + psHu16(mem) &= ~value; + break; + case 0x1000f240: + if(!(value & 0x100)) + psHu16(mem) &= ~0x100; + else + psHu16(mem) |= 0x100; + break; + case 0x1000f260: + psHu16(mem) = 0; + break; + + default: + psHu16(mem) = value; + HW_LOG("Unknown Hardware write 16 at %x with value %x\n",mem,value); + } +} + +// Page 0 of HW memory houses registers for Counters 0 and 1 +void __fastcall hwWrite32_page_00( u32 mem, u32 value ) +{ + mem &= 0xffff; + switch (mem) + { + case 0x000: rcntWcount(0, value); return; + case 0x010: rcntWmode(0, value); return; + case 0x020: rcntWtarget(0, value); return; + case 0x030: rcntWhold(0, value); return; + + case 0x800: rcntWcount(1, value); return; + case 0x810: rcntWmode(1, value); return; + case 0x820: rcntWtarget(1, value); return; + case 0x830: rcntWhold(1, value); return; + } + + *((u32*)&PS2MEM_HW[mem]) = value; +} + +// Page 1 of HW memory houses registers for Counters 2 and 3 +void __fastcall hwWrite32_page_01( u32 mem, u32 value ) +{ + mem &= 0xffff; + switch (mem) + { + case 0x1000: rcntWcount(2, value); return; + case 0x1010: rcntWmode(2, value); return; + case 0x1020: rcntWtarget(2, value); return; + + case 0x1800: rcntWcount(3, value); return; + case 0x1810: rcntWmode(3, value); return; + case 0x1820: rcntWtarget(3, value); return; + } + + *((u32*)&PS2MEM_HW[mem]) = value; +} + +// page 2 is the IPU register space! +void __fastcall hwWrite32_page_02( u32 mem, u32 value ) +{ + ipuWrite32(mem, value); +} + +// Page 3 contains writes to vif0 and vif1 registers, plus some GIF stuff! +void __fastcall hwWrite32_page_03( u32 mem, u32 value ) +{ + if(mem>=0x10003800) + { + if(mem<0x10003c00) + vif0Write32(mem, value); + else + vif1Write32(mem, value); + return; + } + + switch (mem) + { + case GIF_CTRL: + psHu32(mem) = value & 0x8; + if (value & 0x1) + gsGIFReset(); + else if( value & 8 ) + psHu32(GIF_STAT) |= 8; + else + psHu32(GIF_STAT) &= ~8; + break; + + case GIF_MODE: + { + // need to set GIF_MODE (hamster ball) + psHu32(GIF_MODE) = value; + + // set/clear bits 0 and 2 as per the GIF_MODE value. + const u32 bitmask = 0x1 | 0x4; + psHu32(GIF_STAT) &= ~bitmask; + psHu32(GIF_STAT) |= (u32)value & bitmask; + } + break; + + case GIF_STAT: // stat is readonly + DevCon::Notice("*PCSX2* GIFSTAT write value = 0x%x (readonly, ignored)", params value); + break; + + default: + psHu32(mem) = value; + } +} + +void __fastcall hwWrite32_page_0B( u32 mem, u32 value ) +{ + // Used for developer logging -- optimized away in Public Release. + const char* regName = "Unknown"; + + switch( mem ) + { + case D3_CHCR: // dma3 - fromIPU + DMA_LOG("IPU0dma EXECUTE, value=0x%x\n", value); + DmaExec(dmaIPU0, mem, value); + return; + + case D3_MADR: regName = "IPU0DMA_MADR"; break; + case D3_QWC: regName = "IPU0DMA_QWC"; break; + case D3_TADR: regName = "IPU0DMA_TADR"; break; + case D3_SADR: regName = "IPU0DMA_SADDR"; break; + + //------------------------------------------------------------------ + + case D4_CHCR: // dma4 - toIPU + DMA_LOG("IPU1dma EXECUTE, value=0x%x\n", value); + DmaExec(dmaIPU1, mem, value); + return; + + case D4_MADR: regName = "IPU1DMA_MADR"; break; + case D4_QWC: regName = "IPU1DMA_QWC"; break; + case D4_TADR: regName = "IPU1DMA_TADR"; break; + case D4_SADR: regName = "IPU1DMA_SADDR"; break; + } + + HW_LOG( "Hardware Write32 at 0x%x (%s), value=0x%x\n", mem, regName, value ); + psHu32(mem) = value; +} + +void __fastcall hwWrite32_page_0E( u32 mem, u32 value ) +{ + if( mem == DMAC_CTRL ) + { + HW_LOG("DMAC_CTRL Write 32bit %x\n", value); + } + else if( mem == DMAC_STAT ) + { + HW_LOG("DMAC_STAT Write 32bit %x\n", value); + + // lower 16 bits: clear on 1 + // upper 16 bits: reverse on 1 + + psHu16(0xe010) &= ~(value & 0xffff); + psHu16(0xe012) ^= (u16)(value >> 16); + + cpuTestDMACInts(); + return; + } + + psHu32(mem) = value; +} + +void __fastcall hwWrite32_page_0F( u32 mem, u32 value ) +{ + // Shift the middle 8 bits (bits 4-12) into the lower 8 bits. + // This helps the compiler optimize the switch statement into a lookup table. :) + +#define HELPSWITCH(m) (((m)>>4) & 0xff) + + switch( HELPSWITCH(mem) ) + { + case HELPSWITCH(INTC_STAT): + HW_LOG("INTC_STAT Write 32bit %x\n", value); + psHu32(INTC_STAT) &= ~value; + //cpuTestINTCInts(); + break; + + case HELPSWITCH(INTC_MASK): + HW_LOG("INTC_MASK Write 32bit %x\n", value); + psHu32(INTC_MASK) ^= (u16)value; + cpuTestINTCInts(); + break; + + //------------------------------------------------------------------ + case HELPSWITCH(0x1000f430)://MCH_RICM: x:4|SA:12|x:5|SDEV:1|SOP:4|SBC:1|SDEV:5 + if ((((value >> 16) & 0xFFF) == 0x21) && (((value >> 6) & 0xF) == 1) && (((psHu32(0xf440) >> 7) & 1) == 0))//INIT & SRP=0 + rdram_sdevid = 0; // if SIO repeater is cleared, reset sdevid + psHu32(mem) = value & ~0x80000000; //kill the busy bit + break; + + case HELPSWITCH(0x1000f200): + psHu32(mem) = value; + break; + case HELPSWITCH(0x1000f220): + psHu32(mem) |= value; + break; + case HELPSWITCH(0x1000f230): + psHu32(mem) &= ~value; + break; + case HELPSWITCH(0x1000f240): + if(!(value & 0x100)) + psHu32(mem) &= ~0x100; + else + psHu32(mem) |= 0x100; + break; + case HELPSWITCH(0x1000f260): + psHu32(mem) = 0; + break; + + case HELPSWITCH(0x1000f440)://MCH_DRD: + psHu32(mem) = value; + break; + + case HELPSWITCH(0x1000f590): // DMAC_ENABLEW + HW_LOG("DMAC_ENABLEW Write 32bit %lx\n", value); + psHu32(0xf590) = value; + psHu32(0xf520) = value; + break; + + //------------------------------------------------------------------ + case HELPSWITCH(0x1000f130): + case HELPSWITCH(0x1000f410): + HW_LOG("Unknown Hardware write 32 at %x with value %x (%x)\n", mem, value, cpuRegs.CP0.n.Status.val); + break; + + default: + psHu32(mem) = value; + } +} + +void __fastcall hwWrite32_generic( u32 mem, u32 value ) +{ + // Used for developer logging -- optimized away in Public Release. + const char* regName = "Unknown"; + + switch (mem) + { + case D0_CHCR: // dma0 - vif0 + DMA_LOG("VIF0dma EXECUTE, value=0x%x\n", value); + DmaExec(dmaVIF0, mem, value); + return; + +//------------------------------------------------------------------ + case D1_CHCR: // dma1 - vif1 - chcr + DMA_LOG("VIF1dma EXECUTE, value=0x%x\n", value); + DmaExec(dmaVIF1, mem, value); + return; + + case D1_MADR: regName = "VIF1dma MADR"; break; + case D1_QWC: regName = "VIF1dma QWC"; break; + case D1_TADR: regName = "VIF1dma TADR"; break; + case D1_ASR0: regName = "VIF1dma ASR0"; break; + case D1_ASR1: regName = "VIF1dma ASR1"; break; + case D1_SADR: regName = "VIF1dma SADR"; break; + +//------------------------------------------------------------------ + case D2_CHCR: // dma2 - gif + DMA_LOG("GIFdma EXECUTE, value=0x%x", value); + DmaExec(dmaGIF, mem, value); + return; + + case D2_MADR: regName = "GIFdma MADR"; break; + case D2_QWC: regName = "GIFdma QWC"; break; + case D2_TADR: regName = "GIFdma TADDR"; break; + case D2_ASR0: regName = "GIFdma ASR0"; break; + case D2_ASR1: regName = "GIFdma ASR1"; break; + case D2_SADR: regName = "GIFdma SADDR"; break; + +//------------------------------------------------------------------ + case 0x1000c000: // dma5 - sif0 + DMA_LOG("SIF0dma EXECUTE, value=0x%x\n", value); + //if (value == 0) psxSu32(0x30) = 0x40000; + DmaExec(dmaSIF0, mem, value); + return; +//------------------------------------------------------------------ + case 0x1000c400: // dma6 - sif1 + DMA_LOG("SIF1dma EXECUTE, value=0x%x\n", value); + DmaExec(dmaSIF1, mem, value); + return; + + case 0x1000c420: regName = "SIF1dma QWC"; break; + case 0x1000c430: regName = "SIF1dma TADR"; break; + +//------------------------------------------------------------------ + case 0x1000c800: // dma7 - sif2 + DMA_LOG("SIF2dma EXECUTE, value=0x%x\n", value); + DmaExec(dmaSIF2, mem, value); + return; +//------------------------------------------------------------------ + case 0x1000d000: // dma8 - fromSPR + DMA_LOG("SPR0dma EXECUTE (fromSPR), value=0x%x\n", value); + DmaExec(dmaSPR0, mem, value); + return; +//------------------------------------------------------------------ + case 0x1000d400: // dma9 - toSPR + DMA_LOG("SPR0dma EXECUTE (toSPR), value=0x%x\n", value); + DmaExec(dmaSPR1, mem, value); + return; + } + HW_LOG( "Hardware Write32 at 0x%x (%s), value=0x%x\n", mem, regName, value ); + psHu32(mem) = value; +} + +///////////////////////////////////////////////////////////////////////// +// HW Write 64 bit + +void __fastcall hwWrite64_page_02( u32 mem, const mem64_t* srcval ) +{ + //hwWrite64( mem, *srcval ); return; + ipuWrite64( mem, *srcval ); +} + +void __fastcall hwWrite64_page_03( u32 mem, const mem64_t* srcval ) +{ + //hwWrite64( mem, *srcval ); return; + const u64 value = *srcval; + + if(mem>=0x10003800) + { + if(mem<0x10003c00) + vif0Write32(mem, value); + else + vif1Write32(mem, value); + return; + } + + switch (mem) + { + case GIF_CTRL: + DevCon::Status("GIF_CTRL write 64", params value); + psHu32(mem) = value & 0x8; + if(value & 0x1) + gsGIFReset(); + else + { + if( value & 8 ) + psHu32(GIF_STAT) |= 8; + else + psHu32(GIF_STAT) &= ~8; + } + + return; + + case GIF_MODE: + { +#ifdef GSPATH3FIX + Console::Status("GIFMODE64 %x\n", params value); +#endif + psHu64(GIF_MODE) = value; + + // set/clear bits 0 and 2 as per the GIF_MODE value. + const u32 bitmask = 0x1 | 0x4; + psHu32(GIF_STAT) &= ~bitmask; + psHu32(GIF_STAT) |= (u32)value & bitmask; + } + + case GIF_STAT: // stat is readonly + return; + } +} + +void __fastcall hwWrite64_page_0E( u32 mem, const mem64_t* srcval ) +{ + //hwWrite64( mem, *srcval ); return; + + const u64 value = *srcval; + + if( mem == DMAC_CTRL ) + { + HW_LOG("DMAC_CTRL Write 64bit %x\n", value); + } + else if( mem == DMAC_STAT ) + { + HW_LOG("DMAC_STAT Write 64bit %x\n", value); + + // lower 16 bits: clear on 1 + // upper 16 bits: reverse on 1 + + psHu16(0xe010) &= ~(value & 0xffff); + psHu16(0xe012) ^= (u16)(value >> 16); + + cpuTestDMACInts(); + return; + } + + psHu64(mem) = value; +} + +void __fastcall hwWrite64_generic( u32 mem, const mem64_t* srcval ) +{ + //hwWrite64( mem, *srcval ); return; + + const u64 value = *srcval; + + switch (mem) + { + case 0x1000a000: // dma2 - gif + DMA_LOG("0x%8.8x hwWrite64: GSdma %x\n", cpuRegs.cycle, value); + DmaExec(dmaGIF, mem, value); + break; + + case INTC_STAT: + HW_LOG("INTC_STAT Write 64bit %x\n", (u32)value); + psHu32(INTC_STAT) &= ~value; + //cpuTestINTCInts(); + break; + + case INTC_MASK: + HW_LOG("INTC_MASK Write 64bit %x\n", (u32)value); + psHu32(INTC_MASK) ^= (u16)value; + cpuTestINTCInts(); + break; + + case 0x1000f130: + case 0x1000f410: + case 0x1000f430: + break; + + case 0x1000f590: // DMAC_ENABLEW + psHu32(0xf590) = value; + psHu32(0xf520) = value; + break; + + default: + psHu64(mem) = value; + HW_LOG("Unknown Hardware write 64 at %x with value %x (status=%x)\n",mem,value, cpuRegs.CP0.n.Status.val); + break; + } +} + +///////////////////////////////////////////////////////////////////////// +// HW Write 128 bit + +void __fastcall hwWrite128_generic(u32 mem, const mem128_t *srcval) +{ + //hwWrite128( mem, srcval ); return; + + switch (mem) + { + case INTC_STAT: + HW_LOG("INTC_STAT Write 64bit %x\n", (u32)srcval[0]); + psHu32(INTC_STAT) &= ~srcval[0]; + //cpuTestINTCInts(); + break; + + case INTC_MASK: + HW_LOG("INTC_MASK Write 64bit %x\n", (u32)srcval[0]); + psHu32(INTC_MASK) ^= (u16)srcval[0]; + cpuTestINTCInts(); + break; + + case 0x1000f590: // DMAC_ENABLEW + psHu32(0xf590) = srcval[0]; + psHu32(0xf520) = srcval[0]; + break; + + case 0x1000f130: + case 0x1000f410: + case 0x1000f430: + break; + + default: + psHu64(mem ) = srcval[0]; + psHu64(mem+8) = srcval[1]; + + HW_LOG("Unknown Hardware write 128 at %x with value %x_%x (status=%x)\n", mem, srcval[1], srcval[0], cpuRegs.CP0.n.Status.val); + break; + } +} diff --git a/pcsx2/IPU/IPU.cpp b/pcsx2/IPU/IPU.cpp index 1e9b8aeca1..8d280b4eb0 100644 --- a/pcsx2/IPU/IPU.cpp +++ b/pcsx2/IPU/IPU.cpp @@ -1,1743 +1,1743 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" - -#include "IPU.h" -#include "mpeg2lib/Mpeg.h" -#include "yuv2rgb.h" -#include "coroutine.h" - -#include "Vif.h" - -using namespace std; // for min / max - -// Zero cycle IRQ schedules aren't really good, but the IPU uses them. -// Better to throw the IRQ inline: - -#define IPU_INT0_FROM() ipu0Interrupt() -//#define IPU_INT0_FROM() CPU_INT( DMAC_FROM_IPU, 0 ) - -// IPU Inline'd IRQs : Calls the IPU interrupt handlers directly instead of -// feeding them through the EE's branch test. (see IPU.H for details) - -#ifdef IPU_INLINE_IRQS -# define IPU_INT_TO( cycles ) ipu1Interrupt() -# define IPU_INT_FROM( cycles ) ipu0Interrupt() -# define IPU_FORCEINLINE -#else -# define IPU_INT_TO( cycles ) CPU_INT( DMAC_TO_IPU, cycles ) -# define IPU_INT_FROM( cycles ) CPU_INT( DMAC_FROM_IPU, cycles ) -# define IPU_FORCEINLINE __forceinline -#endif - -//IPUregisters g_ipuRegsReal; - -#define ipu0dma ((DMACh *)&PS2MEM_HW[0xb000]) -#define ipu1dma ((DMACh *)&PS2MEM_HW[0xb400]) - -#define IPU_DMA_GIFSTALL 1 -#define IPU_DMA_TIE0 2 -#define IPU_DMA_TIE1 4 -#define IPU_DMA_ACTV1 8 -#define IPU_DMA_DOTIE1 16 -#define IPU_DMA_FIREINT0 32 -#define IPU_DMA_FIREINT1 64 -#define IPU_DMA_VIFSTALL 128 - -static int g_nDMATransfer = 0; -int g_nIPU0Data = 0; // data left to transfer -u8* g_pIPU0Pointer = NULL; -int g_nCmdPos[2] = {0}, g_nCmdIndex = 0; -int ipuCurCmd = 0xffffffff; - - -int FOreadpos = 0, FOwritepos = 0; -static int FIreadpos = 0, FIwritepos = 0; -PCSX2_ALIGNED16(u32 fifo_input[32]); -PCSX2_ALIGNED16(u32 fifo_output[32]); - -void ReorderBitstream(); - -// the BP doesn't advance and returns -1 if there is no data to be read -tIPU_BP g_BP; -static coroutine_t s_routine; // used for executing BDEC/IDEC -static int s_RoutineDone = 0; -static u32 s_tempstack[0x4000]; // 64k - -void IPUCMD_WRITE(u32 val); -void IPUWorker(); -int IPU0dma(); -int IPU1dma(); - -// Color conversion stuff, the memory layout is a total hack -// convert_data_buffer is a pointer to the internal rgb struct (the first param in convert_init_t) -//char convert_data_buffer[sizeof(convert_rgb_t)]; -char convert_data_buffer[0x1C]; - -convert_init_t convert_init={convert_data_buffer, sizeof(convert_data_buffer)}; -convert_t *convert; - -// Quantization matrix -static u8 niq[64], //non-intraquant matrix - iq[64]; //intraquant matrix -u16 vqclut[16]; //clut conversion table -static u8 s_thresh[2]; //thresholds for color conversions -int coded_block_pattern=0; -PCSX2_ALIGNED16(macroblock_8 mb8); -PCSX2_ALIGNED16(macroblock_16 mb16); -PCSX2_ALIGNED16(macroblock_rgb32 rgb32); -PCSX2_ALIGNED16(macroblock_rgb16 rgb16); - -u8 indx4[16*16/2]; -u32 mpeg2_inited; //mpeg2_idct_init() must be called only once -u8 PCT[]={'r', 'I', 'P', 'B', 'D', '-', '-', '-'}; -decoder_t g_decoder; //static, only to place it in bss -decoder_t tempdec; - -extern "C" -{ - extern u8 mpeg2_scan_norm[64]; - extern u8 mpeg2_scan_alt[64]; -} - -PCSX2_ALIGNED16(u8 _readbits[80]); //local buffer (ring buffer) -u8* readbits = _readbits; // always can decrement by one 1qw - -#define SATURATE_4BITS(val) ((val)>15 ? 15 : (val)) - -void IPUProcessInterrupt() -{ - if( ipuRegs->ctrl.BUSY ) { - IPUWorker(); - } -} - -///////////////////////////////////////////////////////// -// Register accesses (run on EE thread) -int ipuInit() -{ - memzero_obj(*ipuRegs); - memzero_obj(g_BP); - - //other stuff - g_decoder.intra_quantizer_matrix =(u8*)iq; - g_decoder.non_intra_quantizer_matrix =(u8*)niq; - g_decoder.picture_structure = FRAME_PICTURE; //default: progressive...my guess:P - g_decoder.mb8 =&mb8; - g_decoder.mb16=&mb16; - g_decoder.rgb32=&rgb32; - g_decoder.rgb16=&rgb16; - g_decoder.stride=16; - - return 0; -} - -void ipuReset() -{ - memzero_obj(*ipuRegs); - g_nDMATransfer = 0; -} - -void ipuShutdown() -{ -} - -// fixme - ipuFreeze looks fairly broken. Should probably take a closer look at some point. - -void SaveState::ipuFreeze() { - IPUProcessInterrupt(); - - FreezeMem(ipuRegs, sizeof(IPUregisters)); - Freeze(g_nDMATransfer); - Freeze(FIreadpos); - Freeze(FIwritepos); - Freeze(fifo_input); - Freeze(FOreadpos); - Freeze(FOwritepos); - Freeze(fifo_output); - Freeze(g_BP); - Freeze(niq); - Freeze(iq); - Freeze(vqclut); - Freeze(s_thresh); - Freeze(coded_block_pattern); - Freeze(g_decoder); - Freeze(mpeg2_scan_norm); - Freeze(mpeg2_scan_alt); - Freeze(g_nCmdPos); - Freeze(g_nCmdIndex); - Freeze(ipuCurCmd); - - Freeze(_readbits); - - int temp = readbits-_readbits; - Freeze(temp); - - if( IsLoading() ) - { - readbits = _readbits; - - //other stuff - g_decoder.intra_quantizer_matrix =(u8*)iq; - g_decoder.non_intra_quantizer_matrix =(u8*)niq; - g_decoder.picture_structure = FRAME_PICTURE; //default: progressive...my guess:P - g_decoder.mb8 =&mb8; - g_decoder.mb16=&mb16; - g_decoder.rgb32=&rgb32; - g_decoder.rgb16=&rgb16; - g_decoder.stride=16; - - if (!mpeg2_inited){ - mpeg2_idct_init(); - convert=convert_rgb (CONVERT_RGB, 32); - convert(16, 16, 0, NULL, &convert_init); - memzero_obj(mb8.Y); - memzero_obj(mb8.Cb); - memzero_obj(mb8.Cr); - memzero_obj(mb16.Y); - memzero_obj(mb16.Cb); - memzero_obj(mb16.Cr); - mpeg2_inited=1; - } - } -} - -bool ipuCanFreeze() -{ - return ipuCurCmd == 0xffffffff; -} - -__forceinline u32 ipuRead32(u32 mem) -{ - IPUProcessInterrupt(); - - switch (mem){ - - case 0x10002010: // IPU_CTRL - ipuRegs->ctrl.IFC = g_BP.IFC; - //ipuRegs->ctrl.OFC = min(g_nIPU0Data, 8); // check if transfering to ipu0 - ipuRegs->ctrl.CBP = coded_block_pattern; - - if( !ipuRegs->ctrl.BUSY ) - IPU_LOG("Ipu read32: IPU_CTRL=0x%08X %x\n", ipuRegs->ctrl._u32, cpuRegs.pc); - - return ipuRegs->ctrl._u32; - - case 0x10002020: // IPU_BP - - ipuRegs->ipubp = g_BP.BP & 0x7f; - ipuRegs->ipubp |= g_BP.IFC<<8; - ipuRegs->ipubp |= (g_BP.FP+g_BP.bufferhasnew) << 16; - - IPU_LOG("Ipu read32: IPU_BP=0x%08X\n", *(u32*)&g_BP); - return ipuRegs->ipubp; - } - - return *(u32*)(((u8*)ipuRegs)+(mem&0xff)); // ipu repeats every 0x100 -} - -__forceinline u64 ipuRead64(u32 mem) -{ - IPUProcessInterrupt(); - -#ifdef PCSX2_DEVBUILD - if( mem == 0x10002010 ) { - SysPrintf("reading 64bit IPU ctrl\n"); - } - if( mem == 0x10002020 ) { - SysPrintf("reading 64bit IPU top\n"); - } -#endif - - switch (mem){ - case 0x10002000: // IPU_CMD - - //if(!ipuRegs->cmd.BUSY){ - if( ipuRegs->cmd.DATA&0xffffff ) - IPU_LOG("Ipu read64: IPU_CMD=BUSY=%x, DATA=%08X\n", ipuRegs->cmd.BUSY?1:0,ipuRegs->cmd.DATA); - //return *(u64*)&ipuRegs->cmd; - break; - - case 0x10002030: // IPU_TOP - IPU_LOG("Ipu read64: IPU_TOP=%x, bp = %d\n",ipuRegs->top,g_BP.BP); - - //return *(u64*)&ipuRegs->top; - break; - - default: - IPU_LOG("Ipu read64: Unknown=%x\n", mem); - break; - - } - return *(u64*)(((u8*)ipuRegs)+(mem&0xff)); -} - -void ipuSoftReset() -{ - if (!mpeg2_inited){ - mpeg2_idct_init(); - convert=convert_rgb (CONVERT_RGB, 32); - convert(16, 16, 0, NULL, &convert_init); - memzero_obj(mb8.Y); - memzero_obj(mb8.Cb); - memzero_obj(mb8.Cr); - memzero_obj(mb16.Y); - memzero_obj(mb16.Cb); - memzero_obj(mb16.Cr); - mpeg2_inited=1; - } - - FIFOto_clear(); - memzero_obj(fifo_output); - FOwritepos = 0; - FOreadpos = 0; - coded_block_pattern = 0; - - //g_nDMATransfer = 0; - - ipuRegs->ctrl._u32 = 0; - g_BP.BP = 0; - g_BP.IFC = 0; - g_BP.FP = 0; - g_BP.bufferhasnew = 0; - ipuRegs->top = 0; - g_nCmdIndex = 0; - ipuCurCmd = 0xffffffff; - g_nCmdPos[0] = 0; g_nCmdPos[1] = 0; -} - -__forceinline void ipuWrite32(u32 mem,u32 value) -{ - IPUProcessInterrupt(); - - switch (mem){ - case 0x10002000: // IPU_CMD - IPU_LOG("Ipu write32: IPU_CMD=0x%08X\n",value); - IPUCMD_WRITE(value); - break; - case 0x10002010: // IPU_CTRL - ipuRegs->ctrl._u32 = (value&0x47f30000)|(ipuRegs->ctrl._u32&0x8000ffff); - if( ipuRegs->ctrl.IDP == 3 ) { - SysPrintf("IPU Invalid Intra DC Precision, switching to 9 bits\n"); - ipuRegs->ctrl.IDP = 1; - } - if (ipuRegs->ctrl.RST & 0x1) { // RESET - ipuSoftReset(); - } - - IPU_LOG("Ipu write32: IPU_CTRL=0x%08X\n",value); - - break; - default: - IPU_LOG("Ipu write32: Unknown=%x\n", mem); - *(u32*)((u8*)ipuRegs + (mem&0xfff)) = value; - break; - } -} - -__forceinline void ipuWrite64(u32 mem, u64 value) -{ - IPUProcessInterrupt(); - - switch (mem){ - case 0x10002000: - IPU_LOG("Ipu write64: IPU_CMD=0x%08X\n",value); - IPUCMD_WRITE((u32)value); - break; - - default: - IPU_LOG("Ipu write64: Unknown=%x\n", mem); - *(u64*)((u8*)ipuRegs + (mem&0xfff)) = value; - break; - } -} - - -////////////////////////////////////////////////////// -// IPU Commands (exec on worker thread only) - -static void ipuBCLR(u32 val) { - FIFOto_clear(); - g_BP.BP = val & 0x7F; - g_BP.FP = 0; - g_BP.bufferhasnew = 0; - g_BP.IFC = 0; - ipuRegs->ctrl.BUSY = 0; - ipuRegs->cmd.BUSY = 0; - memzero_ptr<80>(readbits); - IPU_LOG("Clear IPU input FIFO. Set Bit offset=0x%X\n", g_BP.BP); -} - -static __forceinline BOOL ipuIDEC(u32 val) -{ - tIPU_CMD_IDEC idec( val ); - - - IPU_LOG("IPU IDEC command.\n"); - if (idec.FB){ IPU_LOG(" Skip %d bits.",idec.FB);} - IPU_LOG(" Quantizer step code=0x%X.",idec.QSC); - if (idec.DTD==0){ IPU_LOG(" Does not decode DT."); - }else{ IPU_LOG(" Decodes DT.");} - if (idec.SGN==0){ IPU_LOG(" No bias."); - }else{ IPU_LOG(" Bias=128.");} - if (idec.DTE==1){ IPU_LOG(" Dither Enabled.");} - if (idec.OFM==0){ IPU_LOG(" Output format is RGB32."); - }else{ IPU_LOG(" Output format is RGB16.");} - IPU_LOG("\n"); - - g_BP.BP+= idec.FB;//skip FB bits - //from IPU_CTRL - ipuRegs->ctrl.PCT = I_TYPE; //Intra DECoding;) - g_decoder.coding_type =ipuRegs->ctrl.PCT; - g_decoder.mpeg1 =ipuRegs->ctrl.MP1; - g_decoder.q_scale_type =ipuRegs->ctrl.QST; - g_decoder.intra_vlc_format=ipuRegs->ctrl.IVF; - g_decoder.scan =ipuRegs->ctrl.AS ? mpeg2_scan_alt: mpeg2_scan_norm; - g_decoder.intra_dc_precision=ipuRegs->ctrl.IDP; - //from IDEC value - g_decoder.quantizer_scale =idec.QSC; - g_decoder.frame_pred_frame_dct=!idec.DTD; - g_decoder.sgn =idec.SGN; - g_decoder.dte =idec.DTE; - g_decoder.ofm =idec.OFM; - //other stuff - g_decoder.dcr =1;//resets DC prediction value - - s_routine = so_create(mpeg2sliceIDEC, &s_RoutineDone, s_tempstack, sizeof(s_tempstack)); - assert( s_routine != NULL ); - so_call(s_routine); - if(s_RoutineDone) - s_routine = NULL; - - return s_RoutineDone; -} - -#ifdef _DEBUG -static int s_bdec=0; -#else -#define s_bdec 0 -#endif - -static __forceinline BOOL ipuBDEC(u32 val) -{ - tIPU_CMD_BDEC bdec( val ); - - IPU_LOG("IPU BDEC(macroblock decode) command %x, num: 0x%x\n",cpuRegs.pc, s_bdec); - if (bdec.FB){ IPU_LOG(" Skip 0x%X bits.", bdec.FB);} - if (bdec.MBI){ IPU_LOG(" Intra MB.");} - else{ IPU_LOG(" Non-intra MB.");} - if (bdec.DCR){ IPU_LOG(" Resets DC prediction value.");} - else{ IPU_LOG(" Doesn't reset DC prediction value.");} - if (bdec.DT){ IPU_LOG(" Use field DCT.");} - else{ IPU_LOG(" Use frame DCT.");} - IPU_LOG(" Quantizer step=0x%X\n",bdec.QSC); -#ifdef _DEBUG - s_bdec++; -#endif - - g_BP.BP+= bdec.FB;//skip FB bits - g_decoder.coding_type = I_TYPE; - g_decoder.mpeg1 =ipuRegs->ctrl.MP1; - g_decoder.q_scale_type =ipuRegs->ctrl.QST; - g_decoder.intra_vlc_format=ipuRegs->ctrl.IVF; - g_decoder.scan =ipuRegs->ctrl.AS ? mpeg2_scan_alt: mpeg2_scan_norm; - g_decoder.intra_dc_precision=ipuRegs->ctrl.IDP; - //from BDEC value - /* JayteeMaster: the quantizer (linear/non linear) depends on the q_scale_type */ - g_decoder.quantizer_scale =g_decoder.q_scale_type?non_linear_quantizer_scale [bdec.QSC]:bdec.QSC<<1; - g_decoder.macroblock_modes =bdec.DT ? DCT_TYPE_INTERLACED : 0; - g_decoder.dcr =bdec.DCR; - g_decoder.macroblock_modes|=bdec.MBI ? MACROBLOCK_INTRA : MACROBLOCK_PATTERN; - - memzero_obj(mb8); - memzero_obj(mb16); - - s_routine = so_create(mpeg2_slice, &s_RoutineDone, s_tempstack, sizeof(s_tempstack)); - assert( s_routine != NULL ); - so_call(s_routine); - if(s_RoutineDone) - s_routine = NULL; - return s_RoutineDone; -} - -static BOOL __fastcall ipuVDEC(u32 val) { - - switch( g_nCmdPos[0] ) { - case 0: - ipuRegs->cmd.DATA = 0; - if( !getBits32((u8*)&g_decoder.bitstream_buf, 0) ) - return FALSE; - - g_decoder.bitstream_bits = -16; - BigEndian(g_decoder.bitstream_buf, g_decoder.bitstream_buf); - - switch((val >> 26) & 3){ - case 0://Macroblock Address Increment - g_decoder.mpeg1 =ipuRegs->ctrl.MP1; - ipuRegs->cmd.DATA = get_macroblock_address_increment(&g_decoder); - break; - case 1://Macroblock Type //known issues: no error detected - g_decoder.frame_pred_frame_dct=1;//prevent DCT_TYPE_INTERLACED - g_decoder.coding_type =ipuRegs->ctrl.PCT; - ipuRegs->cmd.DATA=get_macroblock_modes(&g_decoder); - break; - case 2://Motion Code //known issues: no error detected - ipuRegs->cmd.DATA=get_motion_delta(&g_decoder,0); - break; - case 3://DMVector - ipuRegs->cmd.DATA=get_dmv(&g_decoder); - break; - } - - g_BP.BP+=(g_decoder.bitstream_bits+16); - if((int)g_BP.BP < 0) { - g_BP.BP += 128; - ReorderBitstream(); - } - - FillInternalBuffer(&g_BP.BP,1,0); - - ipuRegs->cmd.DATA = (ipuRegs->cmd.DATA & 0xFFFF) | ((g_decoder.bitstream_bits+16) << 16); - ipuRegs->ctrl.ECD = (ipuRegs->cmd.DATA==0); - - case 1: - if( !getBits32((u8*)&ipuRegs->top, 0) ) { - g_nCmdPos[0] = 1; - return FALSE; - } - - BigEndian(ipuRegs->top, ipuRegs->top); - - IPU_LOG("IPU VDEC command data 0x%x(0x%x). Skip 0x%X bits/Table=%d (%s), pct %d\n", - ipuRegs->cmd.DATA,ipuRegs->cmd.DATA >> 16,val & 0x3f, (val >> 26) & 3, (val >> 26) & 1 ? - ((val >> 26) & 2 ? "DMV" : "MBT") : (((val >> 26) & 2 ? "MC" : "MBAI")),ipuRegs->ctrl.PCT); - - return TRUE; - - jNO_DEFAULT - } - - return FALSE; -} - -static BOOL ipuFDEC(u32 val) -{ - if( !getBits32((u8*)&ipuRegs->cmd.DATA, 0) ) - return FALSE; - - BigEndian(ipuRegs->cmd.DATA, ipuRegs->cmd.DATA); - ipuRegs->top = ipuRegs->cmd.DATA; - - IPU_LOG("FDEC read: 0x%8.8x\n", ipuRegs->top); - - return TRUE; -} - -static __forceinline BOOL ipuSETIQ(u32 val) -{ - int i; - - if ((val >> 27) & 1){ - g_nCmdPos[0] += getBits((u8*)niq + g_nCmdPos[0], 512-8*g_nCmdPos[0], 1); // 8*8*8 - - IPU_LOG("Read non-intra quantization matrix from IPU FIFO.\n"); - for (i=0; i<8; i++){ - IPU_LOG("%02X %02X %02X %02X %02X %02X %02X %02X\n", - niq[i*8+0], niq[i*8+1], niq[i*8+2], niq[i*8+3], - niq[i*8+4], niq[i*8+5], niq[i*8+6], niq[i*8+7]); - } - }else{ - g_nCmdPos[0] += getBits((u8*)iq+8*g_nCmdPos[0], 512-8*g_nCmdPos[0], 1); - IPU_LOG("Read intra quantization matrix from IPU FIFO.\n"); - for (i=0; i<8; i++){ - IPU_LOG("%02X %02X %02X %02X %02X %02X %02X %02X\n", - iq[i*8+0], iq[i*8+1], iq[i*8+2], iq[i*8+3], - iq[i*8+4], iq[i*8+5], iq[i*8+6], iq[i*8+7]); - } - } - - return g_nCmdPos[0] == 64; -} - -static __forceinline BOOL ipuSETVQ(u32 val) -{ - g_nCmdPos[0] += getBits((u8*)vqclut+g_nCmdPos[0], 256-8*g_nCmdPos[0], 1); // 16*2*8 - - if( g_nCmdPos[0] == 32 ) - { - IPU_LOG("IPU SETVQ command.\nRead VQCLUT table from IPU FIFO.\n"); - IPU_LOG( - "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d " - "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d\n" - "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d " - "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d\n", - vqclut[0] >> 10, (vqclut[0] >> 5) & 0x1F, vqclut[0] & 0x1F, - vqclut[1] >> 10, (vqclut[1] >> 5) & 0x1F, vqclut[1] & 0x1F, - vqclut[2] >> 10, (vqclut[2] >> 5) & 0x1F, vqclut[2] & 0x1F, - vqclut[3] >> 10, (vqclut[3] >> 5) & 0x1F, vqclut[3] & 0x1F, - vqclut[4] >> 10, (vqclut[4] >> 5) & 0x1F, vqclut[4] & 0x1F, - vqclut[5] >> 10, (vqclut[5] >> 5) & 0x1F, vqclut[5] & 0x1F, - vqclut[6] >> 10, (vqclut[6] >> 5) & 0x1F, vqclut[6] & 0x1F, - vqclut[7] >> 10, (vqclut[7] >> 5) & 0x1F, vqclut[7] & 0x1F, - vqclut[8] >> 10, (vqclut[8] >> 5) & 0x1F, vqclut[8] & 0x1F, - vqclut[9] >> 10, (vqclut[9] >> 5) & 0x1F, vqclut[9] & 0x1F, - vqclut[10] >> 10, (vqclut[10] >> 5) & 0x1F, vqclut[10] & 0x1F, - vqclut[11] >> 10, (vqclut[11] >> 5) & 0x1F, vqclut[11] & 0x1F, - vqclut[12] >> 10, (vqclut[12] >> 5) & 0x1F, vqclut[12] & 0x1F, - vqclut[13] >> 10, (vqclut[13] >> 5) & 0x1F, vqclut[13] & 0x1F, - vqclut[14] >> 10, (vqclut[14] >> 5) & 0x1F, vqclut[14] & 0x1F, - vqclut[15] >> 10, (vqclut[15] >> 5) & 0x1F, vqclut[15] & 0x1F); - } - - return g_nCmdPos[0] == 32; -} - -// IPU Transfers are split into 8Qwords so we need to send ALL the data -static BOOL __fastcall ipuCSC(u32 val) -{ - tIPU_CMD_CSC csc( val ); - - IPU_LOG("IPU CSC(Colorspace conversion from YCbCr) command (%d).\n",csc.MBC); - if (csc.OFM){ IPU_LOG("Output format is RGB16. ");} - else{ IPU_LOG("Output format is RGB32. ");} - if (csc.DTE){ IPU_LOG("Dithering enabled."); } - - //SysPrintf("CSC\n"); - for (;g_nCmdIndex<(int)csc.MBC; g_nCmdIndex++){ - - if( g_nCmdPos[0] < 3072/8 ) { - g_nCmdPos[0] += getBits((u8*)&mb8+g_nCmdPos[0], 3072-8*g_nCmdPos[0], 1); - - if( g_nCmdPos[0] < 3072/8 ) - return FALSE; - - ipu_csc(&mb8, &rgb32, 0); - if (csc.OFM){ - ipu_dither2(&rgb32, &rgb16, csc.DTE); - } - } - - if (csc.OFM){ - while(g_nCmdPos[1] < 32) - { - g_nCmdPos[1] += FIFOfrom_write(((u32*)&rgb16)+4*g_nCmdPos[1], 32-g_nCmdPos[1]); - - if( g_nCmdPos[1] <= 0 ) - return FALSE; - } - } - else { - while(g_nCmdPos[1] < 64) - { - g_nCmdPos[1] += FIFOfrom_write(((u32*)&rgb32)+4*g_nCmdPos[1], 64-g_nCmdPos[1]); - - if( g_nCmdPos[1] <= 0 ) - return FALSE; - } - } - - g_nCmdPos[0] = 0; - g_nCmdPos[1] = 0; - } - - return TRUE; -} - -// Todo - Need to add the same stop and start code as CSC -static BOOL ipuPACK(u32 val) -{ - tIPU_CMD_CSC csc( val ); - - IPU_LOG("IPU PACK (Colorspace conversion from RGB32) command.\n"); - if (csc.OFM){ IPU_LOG("Output format is RGB16. ");} - else{ IPU_LOG("Output format is INDX4. ");} - if (csc.DTE){ IPU_LOG("Dithering enabled."); } - IPU_LOG("Number of macroblocks to be converted: %d\n", csc.MBC); - - for (;g_nCmdIndex<(int)csc.MBC; g_nCmdIndex++){ - - if( g_nCmdPos[0] < 512 ) { - g_nCmdPos[0] += getBits((u8*)&mb8+g_nCmdPos[0], 512-8*g_nCmdPos[0], 1); - - if( g_nCmdPos[0] < 64 ) - return FALSE; - - ipu_csc(&mb8, &rgb32, 0); - ipu_dither2(&rgb32, &rgb16, csc.DTE); - if (csc.OFM){ - ipu_vq(&rgb16, indx4); - } - } - - if (csc.OFM) { - g_nCmdPos[1] += FIFOfrom_write(((u32*)&rgb16)+4*g_nCmdPos[1], 32-g_nCmdPos[1]); - - if( g_nCmdPos[1] < 32 ) - return FALSE; - } - else { - g_nCmdPos[1] += FIFOfrom_write(((u32*)indx4)+4*g_nCmdPos[1], 8-g_nCmdPos[1]); - - if( g_nCmdPos[1] < 8 ) - return FALSE; - } - - g_nCmdPos[0] = 0; - g_nCmdPos[1] = 0; - } - - return TRUE; -} - -static void ipuSETTH(u32 val) { - s_thresh[0] = (val & 0xff); - s_thresh[1] = ((val>>16) & 0xff); - IPU_LOG("IPU SETTH (Set threshold value)command %x.\n", val&0xff00ff); -} - -/////////////////////// -// IPU Worker Thread // -/////////////////////// -#define IPU_INTERRUPT(dma) { \ - hwIntcIrq(INTC_IPU); \ -} - -void IPUCMD_WRITE(u32 val) { - - // don't process anything if currently busy - if( ipuRegs->ctrl.BUSY ) { - // wait for thread - SysPrintf("IPU BUSY!\n"); - } - - ipuRegs->ctrl.ECD = 0; - ipuRegs->ctrl.SCD = 0; //clear ECD/SCD - ipuRegs->cmd.DATA = val; - g_nCmdPos[0] = 0; - - switch (ipuRegs->cmd.CMD) { - case SCE_IPU_BCLR: - ipuBCLR(val); - IPU_INTERRUPT(DMAC_TO_IPU); - return; - - case SCE_IPU_VDEC: - - g_BP.BP+= val & 0x3F; - - // check if enough data in queue - if( ipuVDEC(val) ) { - return; - } - - ipuRegs->cmd.BUSY = 0x80000000; - ipuRegs->topbusy = 0x80000000; - - break; - - case SCE_IPU_FDEC: - IPU_LOG("IPU FDEC command. Skip 0x%X bits, FIFO 0x%X qwords, BP 0x%X, FP %d, CHCR 0x%x, %x\n", - val & 0x3f,g_BP.IFC,(int)g_BP.BP,g_BP.FP,((DMACh*)&PS2MEM_HW[0xb400])->chcr,cpuRegs.pc); - - g_BP.BP+= val & 0x3F; - - if( ipuFDEC(val) ) { - return; - } - - ipuRegs->cmd.BUSY = 0x80000000; - ipuRegs->topbusy = 0x80000000; - - break; - - case SCE_IPU_SETTH: - ipuSETTH(val); - hwIntcIrq(INTC_IPU); - return; - - case SCE_IPU_SETIQ: - IPU_LOG("IPU SETIQ command.\n"); - - if (val & 0x3f) - IPU_LOG("Skip %d bits.\n", val & 0x3f); - - g_BP.BP+= val & 0x3F; - - if( ipuSETIQ(ipuRegs->cmd.DATA) ) { - return; - } - - break; - case SCE_IPU_SETVQ: - if( ipuSETVQ(ipuRegs->cmd.DATA) ) { - return; - } - - break; - case SCE_IPU_CSC: - g_nCmdPos[1] = 0; - g_nCmdIndex = 0; - - if( ipuCSC(ipuRegs->cmd.DATA) ) { - if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) - IPU_INT0_FROM(); - return; - } - - break; - case SCE_IPU_PACK: - - g_nCmdPos[1] = 0; - g_nCmdIndex = 0; - - if( ipuPACK(ipuRegs->cmd.DATA) ) { - return; - } - - break; - - case SCE_IPU_IDEC: - if( ipuIDEC(val) ) { - // idec done, ipu0 done too - if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) - IPU_INT0_FROM(); - return; - } - - ipuRegs->topbusy = 0x80000000; - // have to resort to the thread - ipuCurCmd = val>>28; - ipuRegs->ctrl.BUSY = 1; - - return; - - case SCE_IPU_BDEC: - if( ipuBDEC(val)) { - if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) - IPU_INT0_FROM(); - if (ipuRegs->ctrl.SCD || ipuRegs->ctrl.ECD) - hwIntcIrq(INTC_IPU); - - return; - } - - ipuRegs->topbusy = 0x80000000; - ipuCurCmd = val>>28; - ipuRegs->ctrl.BUSY = 1; - - return; - } - - // have to resort to the thread - ipuCurCmd = val>>28; - ipuRegs->ctrl.BUSY = 1; - hwIntcIrq(INTC_IPU); -} - -void IPUWorker() -{ - assert( ipuRegs->ctrl.BUSY ); - - switch (ipuCurCmd) { - case SCE_IPU_VDEC: - if( !ipuVDEC(ipuRegs->cmd.DATA) ) - { - hwIntcIrq(INTC_IPU); - return; - } - - ipuRegs->cmd.BUSY = 0; - ipuRegs->topbusy = 0; - - break; - - case SCE_IPU_FDEC: - if( !ipuFDEC(ipuRegs->cmd.DATA) ) - { - hwIntcIrq(INTC_IPU); - return; - } - - ipuRegs->cmd.BUSY = 0; - ipuRegs->topbusy = 0; - - break; - - case SCE_IPU_SETIQ: - if( !ipuSETIQ(ipuRegs->cmd.DATA) ) - { - hwIntcIrq(INTC_IPU); - return; - } - - break; - case SCE_IPU_SETVQ: - if( !ipuSETVQ(ipuRegs->cmd.DATA) ) - { - hwIntcIrq(INTC_IPU); - return; - } - - break; - case SCE_IPU_CSC: - if( !ipuCSC(ipuRegs->cmd.DATA) ) - { - hwIntcIrq(INTC_IPU); - return; - } - - if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) - IPU_INT0_FROM(); - break; - case SCE_IPU_PACK: - if( !ipuPACK(ipuRegs->cmd.DATA) ) - { - hwIntcIrq(INTC_IPU); - return; - } - - break; - - case SCE_IPU_IDEC: - so_call(s_routine); - if( !s_RoutineDone ) { - hwIntcIrq(INTC_IPU); - return; - } - - ipuRegs->ctrl.OFC = 0; - ipuRegs->ctrl.BUSY = 0; - ipuRegs->topbusy = 0; - ipuRegs->cmd.BUSY = 0; - ipuCurCmd = 0xffffffff; - // CHECK!: IPU0dma remains when IDEC is done, so we need to clear it - if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) - IPU_INT0_FROM(); - - s_routine = NULL; - break; - case SCE_IPU_BDEC: - so_call(s_routine); - if(!s_RoutineDone) - { - hwIntcIrq(INTC_IPU); - return; - } - - ipuRegs->ctrl.BUSY = 0; - ipuRegs->topbusy = 0; - ipuRegs->cmd.BUSY = 0; - ipuCurCmd = 0xffffffff; - if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) - IPU_INT0_FROM(); - s_routine = NULL; - if (ipuRegs->ctrl.SCD || ipuRegs->ctrl.ECD) - hwIntcIrq(INTC_IPU); - return; - - default: - SysPrintf("Unknown IPU command: %x\n", ipuRegs->cmd.CMD); - break; - } - - // success - ipuRegs->ctrl.BUSY = 0; - ipuCurCmd = 0xffffffff; -} - -///////////////// -// Buffer reader - -// move the readbits queue -__forceinline void inc_readbits() -{ - readbits += 16; - if( readbits >= _readbits+64 ) { - - // move back - *(u64*)(_readbits) = *(u64*)(_readbits+64); - *(u64*)(_readbits+8) = *(u64*)(_readbits+72); - readbits = _readbits; - } -} - -// returns the pointer of readbits moved by 1 qword -__forceinline u8* next_readbits() -{ - return readbits + 16; -} - -// returns the pointer of readbits moved by 1 qword -u8* prev_readbits() -{ - if( readbits < _readbits+16 ) { - return _readbits+48-(readbits-_readbits); - } - - return readbits-16; -} - -void ReorderBitstream() -{ - readbits = prev_readbits(); - g_BP.FP = 2; -} - - -// IPU has a 2qword internal buffer whose status is pointed by FP. -// If FP is 1, there's 1 qword in buffer. Second qword is only loaded -// incase there are less than 32bits available in the first qword. -// \return Number of bits available (clamps at 16 bits) -u16 __fastcall FillInternalBuffer(u32 * pointer, u32 advance, u32 size) -{ - if(g_BP.FP == 0) - { - if( FIFOto_read(next_readbits()) == 0 ) - return 0; - - inc_readbits(); - g_BP.FP = 1; - } - else if(g_BP.FP < 2 && (*(int*)pointer+size) >= 128) - { - if( FIFOto_read(next_readbits()) ) - { - g_BP.FP += 1; - } - } - - if(*(int*)pointer >= 128) - { - assert( g_BP.FP >= 1); - - if(g_BP.FP > 1) - { - inc_readbits(); - } - - if(advance) - { - g_BP.FP--; - *pointer &= 127; - } - } - - return g_BP.FP >= 1 ? g_BP.FP*128-(*(int*)pointer) : 0; -} - -// whenever reading fractions of bytes. The low bits always come from the next byte -// while the high bits come from the current byte -u8 __fastcall getBits32(u8 *address, u32 advance) -{ - register u32 mask, shift=0; - u8* readpos; - - // Check if the current BP has exceeded or reached the limit of 128 - if( FillInternalBuffer(&g_BP.BP,1,32) < 32 ) - return 0; - - readpos = readbits+(int)g_BP.BP/8; - - if (g_BP.BP & 7) { - - shift = g_BP.BP&7; - mask = (0xff>>shift); - mask = mask|(mask<<8)|(mask<<16)|(mask<<24); - - *(u32*)address = ((~mask&*(u32*)(readpos+1))>>(8-shift)) | (((mask)&*(u32*)readpos)<>shift); - mask = mask|(mask<<8); - - *(u16*)address = ((~mask&*(u16*)(readpos+1))>>(8-shift)) | (((mask)&*(u16*)readpos)<>shift); - - *(u8*)address = (((~mask)&readpos[1])>>(8-shift)) | (((mask)&*readpos)<> (pointer&7)) << - (8-howmuch-(pointer&7))) & 0xFF; - mask &= readbits[((pointer)>>3)]; - mask >>= 8-howmuch-(pointer&7); - pointer += howmuch; - size -= howmuch; - shift -= howmuch; - *address |= mask << shift; - } - - ++address; - } - else - { - u8* readmem; - while (size) - { - if( FillInternalBuffer(&pointer,advance,8) < 8 ) - { - if(advance) - { - g_BP.BP = pointer; - } - return address-oldaddr; - } - - howmuch = min(128-pointer, size); - size -= howmuch; - - readmem = readbits + (pointer>>3); - pointer += howmuch; - howmuch >>= 3; - - while(howmuch >= 4) { - *(u32*)address = *(u32*)readmem; - howmuch -= 4; - address += 4; - readmem += 4; - } - - switch(howmuch) { - case 3: address[2] = readmem[2]; - case 2: address[1] = readmem[1]; - case 1: address[0] = readmem[0]; - case 0: - break; - - jNO_DEFAULT - } - - address += howmuch; - } - } - - // If not advance then reset the Reading buffer value - if(advance) - { - g_BP.BP = pointer; - - } - else readbits = oldbits; // restore the last pointer - - return address-oldaddr; -} - -///////////////////// CORE FUNCTIONS ///////////////// -void Skl_YUV_To_RGB32_MMX(u8 *RGB, const int Dst_BpS, const u8 *Y, const u8 *U, const u8 *V, - const int Src_BpS, const int Width, const int Height); - -void __fastcall ipu_csc(macroblock_8 *mb8, macroblock_rgb32 *rgb32, int sgn){ - int i; - u8* p = (u8*)rgb32; - - convert_init.start(convert_init.id, (u8*)rgb32, CONVERT_FRAME); - convert_init.copy(convert_init.id, (u8*)mb8->Y, (u8*)mb8->Cr, (u8*)mb8->Cb, 0); - - if( s_thresh[0] > 0 ) { - for(i = 0; i < 64*4; i++, p += 4) { - if( p[0] < s_thresh[0] && p[1] < s_thresh[0] && p[2] < s_thresh[0] ) - *(u32*)p = 0; - else - p[3] = (p[1] < s_thresh[1] && p[2] < s_thresh[1] && p[3] < s_thresh[1]) ? 0x40 : 0x80; - } - } - else if( s_thresh[1] > 0 ) { - for(i = 0; i < 64*4; i++, p += 4) { - p[3] = (p[1] < s_thresh[1] && p[2] < s_thresh[1] && p[3] < s_thresh[1]) ? 0x40 : 0x80; - } - } - else { - for(i = 0; i < 64; i++, p += 16) { - p[3] = p[7] = p[11] = p[15] = 0x80; - } - } -} - -void __fastcall ipu_dither2(const macroblock_rgb32* rgb32, macroblock_rgb16 *rgb16, int dte) -{ - int i, j; - for(i = 0; i < 16; ++i) { - for(j = 0; j < 16; ++j) { - rgb16->c[i][j].r = rgb32->c[i][j].r>>3; - rgb16->c[i][j].g = rgb32->c[i][j].g>>3; - rgb16->c[i][j].b = rgb32->c[i][j].b>>3; - rgb16->c[i][j].a = rgb32->c[i][j].a==0x40; - } - } -} - -void __fastcall ipu_dither(macroblock_8 *mb8, macroblock_rgb16 *rgb16, int dte) -{ - //SysPrintf("IPU: Dither not implemented"); -} - -void __fastcall ipu_vq(macroblock_rgb16 *rgb16, u8* indx4){ - Console::Error("IPU: VQ not implemented"); -} - -void __fastcall ipu_copy(const macroblock_8 *mb8, macroblock_16 *mb16) { - const u8 *s=(const u8*)mb8; - s16 *d=(s16*)mb16; - int i; - for (i=0; i< 256; i++) *d++ = *s++; //Y bias - 16 - for (i=0; i< 64; i++) *d++ = *s++; //Cr bias - 128 - for (i=0; i< 64; i++) *d++ = *s++; //Cb bias - 128 - /*for(i = 0; i < 384/(16*6); ++i, s += 16*4, d += 16*4) { - __m128i r0, r1, r2, r3, r4, r5, r6, r7; - - r0 = _mm_load_si128((__m128i*)s); - r2 = _mm_load_si128((__m128i*)s+1); - r4 = _mm_load_si128((__m128i*)s+2); - r6 = _mm_load_si128((__m128i*)s+3); - - // signed shift - r1 = _mm_srai_epi16(_mm_unpackhi_epi8(r0, r0), 8); - r0 = _mm_srai_epi16(_mm_unpacklo_epi8(r0, r0), 8); - r3 = _mm_srai_epi16(_mm_unpackhi_epi8(r2, r2), 8); - r2 = _mm_srai_epi16(_mm_unpacklo_epi8(r2, r2), 8); - r5 = _mm_srai_epi16(_mm_unpackhi_epi8(r4, r4), 8); - r4 = _mm_srai_epi16(_mm_unpacklo_epi8(r4, r4), 8); - r7 = _mm_srai_epi16(_mm_unpackhi_epi8(r6, r6), 8); - r6 = _mm_srai_epi16(_mm_unpacklo_epi8(r6, r6), 8); - - _mm_store_si128((__m128i*)d, r0); - _mm_store_si128((__m128i*)d+1, r1); - _mm_store_si128((__m128i*)d+2, r2); - _mm_store_si128((__m128i*)d+3, r3); - _mm_store_si128((__m128i*)d+4, r4); - _mm_store_si128((__m128i*)d+5, r5); - _mm_store_si128((__m128i*)d+6, r6); - _mm_store_si128((__m128i*)d+7, r7); - }*/ -} - -///////////////////// IPU DMA //////////////////////// -void FIFOto_clear() -{ - //assert( g_BP.IFC == 0 ); - memzero_obj(fifo_input); - g_BP.IFC = 0; - ipuRegs->ctrl.IFC = 0; - FIreadpos = 0; - FIwritepos = 0; -} - -int FIFOto_read(void *value) -{ - // wait until enough data - if( g_BP.IFC == 0 ) { - if( IPU1dma() == 0 ) - return 0; - - assert( g_BP.IFC > 0 ); - } - - // transfer 1 qword, split into two transfers - ((u32*)value)[0] = fifo_input[FIreadpos]; fifo_input[FIreadpos] = 0; - ((u32*)value)[1] = fifo_input[FIreadpos+1]; fifo_input[FIreadpos+1] = 0; - ((u32*)value)[2] = fifo_input[FIreadpos+2]; fifo_input[FIreadpos+2] = 0; - ((u32*)value)[3] = fifo_input[FIreadpos+3]; fifo_input[FIreadpos+3] = 0; - FIreadpos = (FIreadpos + 4) & 31; - g_BP.IFC--; - return 1; -} - -int FIFOto_write(u32* pMem, int size) -{ - int transsize; - int firsttrans = min(size, 8-(int)g_BP.IFC); - - g_BP.IFC+=firsttrans; - transsize = firsttrans; - - while(transsize-- > 0) { - fifo_input[FIwritepos] = pMem[0]; - fifo_input[FIwritepos+1] = pMem[1]; - fifo_input[FIwritepos+2] = pMem[2]; - fifo_input[FIwritepos+3] = pMem[3]; - FIwritepos = (FIwritepos+4)&31; - pMem +=4; - } - - return firsttrans; -} - -#define IPU1chain() { \ - if(ipu1dma->qwc > 0) \ - { \ - int qwc = ipu1dma->qwc; \ - pMem = (u32*)dmaGetAddr(ipu1dma->madr); \ - if (pMem == NULL) { Console::Error("ipu1dma NULL!"); return totalqwc; } \ - qwc = FIFOto_write(pMem, qwc); \ - ipu1dma->madr += qwc<< 4; \ - ipu1dma->qwc -= qwc; \ - totalqwc += qwc; \ - if( ipu1dma->qwc > 0 ) { \ - g_nDMATransfer |= IPU_DMA_ACTV1; \ - return totalqwc; \ - } \ - } \ -} - -int IPU1dma() -{ - u32 *ptag, *pMem; - int done=0; - int ipu1cycles = 0; - int totalqwc = 0; - - assert( !(ipu1dma->chcr&0x40) ); - - if( !(ipu1dma->chcr & 0x100) || (cpuRegs.interrupt & (1<qwc > 0 ) { - IPU1chain(); - - if ((ipu1dma->chcr & 0x80) && (g_nDMATransfer&IPU_DMA_DOTIE1)) { //Check TIE bit of CHCR and IRQ bit of tag - SysPrintf("IPU1 TIE\n"); - - IPU_INT_TO(totalqwc*BIAS); - g_nDMATransfer &= ~(IPU_DMA_ACTV1|IPU_DMA_DOTIE1); - g_nDMATransfer |= IPU_DMA_TIE1; - return totalqwc; - } - - g_nDMATransfer &= ~(IPU_DMA_ACTV1|IPU_DMA_DOTIE1); - - if( (ipu1dma->chcr&0xc) == 0 ) { - IPU_INT_TO(totalqwc*BIAS); - return totalqwc; - } - else { - u32 tag = ipu1dma->chcr; // upper bits describe current tag - - if ((ipu1dma->chcr & 0x80) && (tag&0x80000000)) { - ptag = (u32*)dmaGetAddr(ipu1dma->tadr); - - switch(tag&0x70000000) { - case 0x00000000: ipu1dma->tadr += 16; break; - case 0x70000000: ipu1dma->tadr = ipu1dma->madr; break; - } - - ipu1dma->chcr = (ipu1dma->chcr & 0xFFFF) | ( (*ptag) & 0xFFFF0000 ); - IPU_LOG("IPU dmaIrq Set\n"); - IPU_INT_TO(totalqwc*BIAS); - g_nDMATransfer |= IPU_DMA_TIE1; - return totalqwc; - } - - switch( tag&0x70000000 ) - { - case 0x00000000: - ipu1dma->tadr += 16; - IPU_INT_TO((1+totalqwc)*BIAS); - return totalqwc; - - case 0x70000000: - ipu1dma->tadr = ipu1dma->madr; - IPU_INT_TO((1+totalqwc)*BIAS); - return totalqwc; - } - } - } - - if ((ipu1dma->chcr & 0xc) == 0 && ipu1dma->qwc == 0) { // Normal Mode - //SysPrintf("ipu1 normal empty qwc?\n"); - return totalqwc; - } - - // Transfer Dn_QWC from Dn_MADR to GIF - - if ((ipu1dma->chcr & 0xc) == 0 || ipu1dma->qwc > 0) { // Normal Mode - IPU_LOG("dmaIPU1 Normal size=%d, addr=%lx, fifosize=%x\n", - ipu1dma->qwc, ipu1dma->madr, 8 - g_BP.IFC); - IPU1chain(); - IPU_INT_TO((ipu1cycles+totalqwc)*BIAS); - return totalqwc; - } - else - { - // Chain Mode - //while (done == 0) { // Loop while Dn_CHCR.STR is 1 - ptag = (u32*)dmaGetAddr(ipu1dma->tadr); //Set memory pointer to TADR - if (ptag == NULL) { //Is ptag empty? - SysPrintf("IPU1 BUSERR\n"); - ipu1dma->chcr = ( ipu1dma->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 - psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register - return totalqwc; - } - ipu1cycles+=1; // Add 1 cycles from the QW read for the tag - - ipu1dma->chcr = ( ipu1dma->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 - ipu1dma->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag - //ipu1dma->madr = ptag[1]; //MADR = ADDR field - - //done = hwDmacSrcChainWithStack(ipu1dma, id); - switch(ptag[0] & 0x70000000) { - case 0x00000000: // refe - // do not change tadr - ipu1dma->madr = ptag[1]; - done = 1; - break; - - case 0x10000000: // cnt - ipu1dma->madr = ipu1dma->tadr + 16; - // Set the taddr to the next tag - ipu1dma->tadr += 16 + (ipu1dma->qwc << 4); - break; - - case 0x20000000: // next - ipu1dma->madr = ipu1dma->tadr + 16; - ipu1dma->tadr = ptag[1]; - break; - - case 0x30000000: // ref - ipu1dma->madr = ptag[1]; - ipu1dma->tadr += 16; - break; - - case 0x70000000: // end - // do not change tadr - ipu1dma->madr = ipu1dma->tadr + 16; - done = 1; - break; - - default: - Console::Error("IPU ERROR: different transfer mode!, Please report to PCSX2 Team\n"); - break; - } - - IPU_LOG("dmaIPU1 dmaChain %8.8x_%8.8x size=%d, addr=%lx, fifosize=%x\n", - ptag[1], ptag[0], ipu1dma->qwc, ipu1dma->madr, 8 - g_BP.IFC); - - if( (ipu1dma->chcr & 0x80) && ptag[0] & 0x80000000 ) - g_nDMATransfer |= IPU_DMA_DOTIE1; - else - g_nDMATransfer &= ~IPU_DMA_DOTIE1; - - //Britney Dance beat does a blank NEXT tag, for some odd reason the fix doesnt work if after IPU1Chain O_o - if(ipu1dma->qwc == 0 && done == 0 && !(g_nDMATransfer & IPU_DMA_DOTIE1)) IPU1dma(); - - IPU1chain(); - - if ((ipu1dma->chcr & 0x80) && (ptag[0]&0x80000000) && ipu1dma->qwc == 0) { //Check TIE bit of CHCR and IRQ bit of tag - SysPrintf("IPU1 TIE\n"); - - if( done ) { - ptag = (u32*)dmaGetAddr(ipu1dma->tadr); - - switch(ptag[0]&0x70000000) { - case 0x00000000: ipu1dma->tadr += 16; break; - case 0x70000000: ipu1dma->tadr = ipu1dma->madr; break; - } - - ipu1dma->chcr = (ipu1dma->chcr & 0xFFFF) | ( (*ptag) & 0xFFFF0000 ); - } - - IPU_INT_TO(ipu1cycles+totalqwc*BIAS); - g_nDMATransfer |= IPU_DMA_TIE1; - return totalqwc; - } - - if(ipu1dma->qwc == 0) - { - switch( ptag[0]&0x70000000 ) - { - case 0x00000000: - ipu1dma->tadr += 16; - break; - - case 0x70000000: - ipu1dma->tadr = ipu1dma->madr; - break; - } - } - } - - IPU_INT_TO((ipu1cycles+totalqwc)*BIAS); - return totalqwc; -} - - -int FIFOfrom_write(u32 *value,int size) -{ - int transsize; - int firsttrans; - - if((int)ipuRegs->ctrl.OFC >= 8) - { - if(IPU0dma() == 0) - { -// ipuRegs->ctrl.OFC = 0; - } - } - - transsize = min(size,8-(int)ipuRegs->ctrl.OFC); - firsttrans = transsize; - - while(transsize-- > 0) { - fifo_output[FOwritepos] = ((u32*)value)[0]; - fifo_output[FOwritepos+1] = ((u32*)value)[1]; - fifo_output[FOwritepos+2] = ((u32*)value)[2]; - fifo_output[FOwritepos+3] = ((u32*)value)[3]; - FOwritepos = (FOwritepos+4)&31; - value += 4; - } - - ipuRegs->ctrl.OFC+=firsttrans; - IPU0dma(); - //SysPrintf("Written %d qwords, %d\n",firsttrans,ipuRegs->ctrl.OFC); - - return firsttrans; -} - -void FIFOfrom_read(void *value,int size) -{ - ipuRegs->ctrl.OFC -= size; - while(size > 0) - { - // transfer 1 qword, split into two transfers - ((u32*)value)[0] = fifo_output[FOreadpos]; fifo_output[FOreadpos] = 0; - ((u32*)value)[1] = fifo_output[FOreadpos+1]; fifo_output[FOreadpos+1] = 0; - ((u32*)value)[2] = fifo_output[FOreadpos+2]; fifo_output[FOreadpos+2] = 0; - ((u32*)value)[3] = fifo_output[FOreadpos+3]; fifo_output[FOreadpos+3] = 0; - value = (u32*)value + 4; - FOreadpos = (FOreadpos + 4) & 31; - size--; - } -} - - -void FIFOfrom_readsingle(void *value) -{ - if(ipuRegs->ctrl.OFC > 0) - { - ipuRegs->ctrl.OFC --; - // transfer 1 qword, split into two transfers - ((u32*)value)[0] = fifo_output[FOreadpos]; fifo_output[FOreadpos] = 0; - ((u32*)value)[1] = fifo_output[FOreadpos+1]; fifo_output[FOreadpos+1] = 0; - ((u32*)value)[2] = fifo_output[FOreadpos+2]; fifo_output[FOreadpos+2] = 0; - ((u32*)value)[3] = fifo_output[FOreadpos+3]; fifo_output[FOreadpos+3] = 0; - FOreadpos = (FOreadpos + 4) & 31; - } -} - -int IPU0dma() -{ - int readsize; - void* pMem; - - //int qwc = ipu0dma->qwc; - //u32 chcr = ipu0dma->chcr; - - if( !(ipu0dma->chcr & 0x100) || (cpuRegs.interrupt & (1<qwc == 0) - return 0; - - assert( !(ipu0dma->chcr&0x40) ); - - IPU_LOG("dmaIPU0 chcr = %lx, madr = %lx, qwc = %lx\n", - ipu0dma->chcr, ipu0dma->madr, ipu0dma->qwc); - - assert((ipu0dma->chcr & 0xC) == 0 ); - pMem = (u32*)dmaGetAddr(ipu0dma->madr); - readsize = min(ipu0dma->qwc, (u16)ipuRegs->ctrl.OFC); - FIFOfrom_read(pMem,readsize); - ipu0dma->madr += readsize<< 4; - ipu0dma->qwc -= readsize; // note: qwc is u16 - if(ipu0dma->qwc == 0) { - if ((psHu32(DMAC_CTRL) & 0x30) == 0x30) { // STS == fromIPU - psHu32(DMAC_STADR) = ipu0dma->madr; - switch (psHu32(DMAC_CTRL) & 0xC0) { - case 0x80: // GIF - g_nDMATransfer |= IPU_DMA_GIFSTALL; - break; - case 0x40: // VIF - g_nDMATransfer |= IPU_DMA_VIFSTALL; - break; - } - } - IPU_INT_FROM( readsize*BIAS ); - } - - return readsize; -} - -void dmaIPU0() // fromIPU -{ - if( ipuRegs->ctrl.BUSY ) - IPUWorker(); -} - -void dmaIPU1() // toIPU -{ - //g_nDMATransfer &= ~(IPU_DMA_ACTV1|IPU_DMA_DOTIE1); - IPU1dma(); - if( ipuRegs->ctrl.BUSY ) - IPUWorker(); -} - -extern void GIFdma(); - -void ipu0Interrupt() { - IPU_LOG("ipu0Interrupt: %x\n", cpuRegs.cycle); - - if( g_nDMATransfer & IPU_DMA_FIREINT0 ) { - hwIntcIrq(INTC_IPU); - g_nDMATransfer &= ~IPU_DMA_FIREINT0; - } - - if( g_nDMATransfer & IPU_DMA_GIFSTALL ) { - // gif - g_nDMATransfer &= ~IPU_DMA_GIFSTALL; - if(((DMACh*)&PS2MEM_HW[0xA000])->chcr & 0x100) GIFdma(); - } - - if( g_nDMATransfer & IPU_DMA_VIFSTALL ) { - // vif - g_nDMATransfer &= ~IPU_DMA_VIFSTALL; - if(((DMACh*)&PS2MEM_HW[0x9000])->chcr & 0x100)dmaVIF1(); - } - - if( g_nDMATransfer & IPU_DMA_TIE0 ) { - g_nDMATransfer &= ~IPU_DMA_TIE0; - } - - ipu0dma->chcr &= ~0x100; - - hwDmacIrq(DMAC_FROM_IPU); -} - -IPU_FORCEINLINE void ipu1Interrupt() { - IPU_LOG("ipu1Interrupt %x:\n", cpuRegs.cycle); - - if( g_nDMATransfer & IPU_DMA_FIREINT1 ) { - hwIntcIrq(INTC_IPU); - g_nDMATransfer &= ~IPU_DMA_FIREINT1; - } - - if( g_nDMATransfer & IPU_DMA_TIE1 ) { - g_nDMATransfer &= ~IPU_DMA_TIE1; - }else - ipu1dma->chcr &= ~0x100; - - hwDmacIrq(DMAC_TO_IPU); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" + +#include "IPU.h" +#include "mpeg2lib/Mpeg.h" +#include "yuv2rgb.h" +#include "coroutine.h" + +#include "Vif.h" + +using namespace std; // for min / max + +// Zero cycle IRQ schedules aren't really good, but the IPU uses them. +// Better to throw the IRQ inline: + +#define IPU_INT0_FROM() ipu0Interrupt() +//#define IPU_INT0_FROM() CPU_INT( DMAC_FROM_IPU, 0 ) + +// IPU Inline'd IRQs : Calls the IPU interrupt handlers directly instead of +// feeding them through the EE's branch test. (see IPU.H for details) + +#ifdef IPU_INLINE_IRQS +# define IPU_INT_TO( cycles ) ipu1Interrupt() +# define IPU_INT_FROM( cycles ) ipu0Interrupt() +# define IPU_FORCEINLINE +#else +# define IPU_INT_TO( cycles ) CPU_INT( DMAC_TO_IPU, cycles ) +# define IPU_INT_FROM( cycles ) CPU_INT( DMAC_FROM_IPU, cycles ) +# define IPU_FORCEINLINE __forceinline +#endif + +//IPUregisters g_ipuRegsReal; + +#define ipu0dma ((DMACh *)&PS2MEM_HW[0xb000]) +#define ipu1dma ((DMACh *)&PS2MEM_HW[0xb400]) + +#define IPU_DMA_GIFSTALL 1 +#define IPU_DMA_TIE0 2 +#define IPU_DMA_TIE1 4 +#define IPU_DMA_ACTV1 8 +#define IPU_DMA_DOTIE1 16 +#define IPU_DMA_FIREINT0 32 +#define IPU_DMA_FIREINT1 64 +#define IPU_DMA_VIFSTALL 128 + +static int g_nDMATransfer = 0; +int g_nIPU0Data = 0; // data left to transfer +u8* g_pIPU0Pointer = NULL; +int g_nCmdPos[2] = {0}, g_nCmdIndex = 0; +int ipuCurCmd = 0xffffffff; + + +int FOreadpos = 0, FOwritepos = 0; +static int FIreadpos = 0, FIwritepos = 0; +PCSX2_ALIGNED16(u32 fifo_input[32]); +PCSX2_ALIGNED16(u32 fifo_output[32]); + +void ReorderBitstream(); + +// the BP doesn't advance and returns -1 if there is no data to be read +tIPU_BP g_BP; +static coroutine_t s_routine; // used for executing BDEC/IDEC +static int s_RoutineDone = 0; +static u32 s_tempstack[0x4000]; // 64k + +void IPUCMD_WRITE(u32 val); +void IPUWorker(); +int IPU0dma(); +int IPU1dma(); + +// Color conversion stuff, the memory layout is a total hack +// convert_data_buffer is a pointer to the internal rgb struct (the first param in convert_init_t) +//char convert_data_buffer[sizeof(convert_rgb_t)]; +char convert_data_buffer[0x1C]; + +convert_init_t convert_init={convert_data_buffer, sizeof(convert_data_buffer)}; +convert_t *convert; + +// Quantization matrix +static u8 niq[64], //non-intraquant matrix + iq[64]; //intraquant matrix +u16 vqclut[16]; //clut conversion table +static u8 s_thresh[2]; //thresholds for color conversions +int coded_block_pattern=0; +PCSX2_ALIGNED16(macroblock_8 mb8); +PCSX2_ALIGNED16(macroblock_16 mb16); +PCSX2_ALIGNED16(macroblock_rgb32 rgb32); +PCSX2_ALIGNED16(macroblock_rgb16 rgb16); + +u8 indx4[16*16/2]; +u32 mpeg2_inited; //mpeg2_idct_init() must be called only once +u8 PCT[]={'r', 'I', 'P', 'B', 'D', '-', '-', '-'}; +decoder_t g_decoder; //static, only to place it in bss +decoder_t tempdec; + +extern "C" +{ + extern u8 mpeg2_scan_norm[64]; + extern u8 mpeg2_scan_alt[64]; +} + +PCSX2_ALIGNED16(u8 _readbits[80]); //local buffer (ring buffer) +u8* readbits = _readbits; // always can decrement by one 1qw + +#define SATURATE_4BITS(val) ((val)>15 ? 15 : (val)) + +void IPUProcessInterrupt() +{ + if( ipuRegs->ctrl.BUSY ) { + IPUWorker(); + } +} + +///////////////////////////////////////////////////////// +// Register accesses (run on EE thread) +int ipuInit() +{ + memzero_obj(*ipuRegs); + memzero_obj(g_BP); + + //other stuff + g_decoder.intra_quantizer_matrix =(u8*)iq; + g_decoder.non_intra_quantizer_matrix =(u8*)niq; + g_decoder.picture_structure = FRAME_PICTURE; //default: progressive...my guess:P + g_decoder.mb8 =&mb8; + g_decoder.mb16=&mb16; + g_decoder.rgb32=&rgb32; + g_decoder.rgb16=&rgb16; + g_decoder.stride=16; + + return 0; +} + +void ipuReset() +{ + memzero_obj(*ipuRegs); + g_nDMATransfer = 0; +} + +void ipuShutdown() +{ +} + +// fixme - ipuFreeze looks fairly broken. Should probably take a closer look at some point. + +void SaveState::ipuFreeze() { + IPUProcessInterrupt(); + + FreezeMem(ipuRegs, sizeof(IPUregisters)); + Freeze(g_nDMATransfer); + Freeze(FIreadpos); + Freeze(FIwritepos); + Freeze(fifo_input); + Freeze(FOreadpos); + Freeze(FOwritepos); + Freeze(fifo_output); + Freeze(g_BP); + Freeze(niq); + Freeze(iq); + Freeze(vqclut); + Freeze(s_thresh); + Freeze(coded_block_pattern); + Freeze(g_decoder); + Freeze(mpeg2_scan_norm); + Freeze(mpeg2_scan_alt); + Freeze(g_nCmdPos); + Freeze(g_nCmdIndex); + Freeze(ipuCurCmd); + + Freeze(_readbits); + + int temp = readbits-_readbits; + Freeze(temp); + + if( IsLoading() ) + { + readbits = _readbits; + + //other stuff + g_decoder.intra_quantizer_matrix =(u8*)iq; + g_decoder.non_intra_quantizer_matrix =(u8*)niq; + g_decoder.picture_structure = FRAME_PICTURE; //default: progressive...my guess:P + g_decoder.mb8 =&mb8; + g_decoder.mb16=&mb16; + g_decoder.rgb32=&rgb32; + g_decoder.rgb16=&rgb16; + g_decoder.stride=16; + + if (!mpeg2_inited){ + mpeg2_idct_init(); + convert=convert_rgb (CONVERT_RGB, 32); + convert(16, 16, 0, NULL, &convert_init); + memzero_obj(mb8.Y); + memzero_obj(mb8.Cb); + memzero_obj(mb8.Cr); + memzero_obj(mb16.Y); + memzero_obj(mb16.Cb); + memzero_obj(mb16.Cr); + mpeg2_inited=1; + } + } +} + +bool ipuCanFreeze() +{ + return ipuCurCmd == 0xffffffff; +} + +__forceinline u32 ipuRead32(u32 mem) +{ + IPUProcessInterrupt(); + + switch (mem){ + + case 0x10002010: // IPU_CTRL + ipuRegs->ctrl.IFC = g_BP.IFC; + //ipuRegs->ctrl.OFC = min(g_nIPU0Data, 8); // check if transfering to ipu0 + ipuRegs->ctrl.CBP = coded_block_pattern; + + if( !ipuRegs->ctrl.BUSY ) + IPU_LOG("Ipu read32: IPU_CTRL=0x%08X %x\n", ipuRegs->ctrl._u32, cpuRegs.pc); + + return ipuRegs->ctrl._u32; + + case 0x10002020: // IPU_BP + + ipuRegs->ipubp = g_BP.BP & 0x7f; + ipuRegs->ipubp |= g_BP.IFC<<8; + ipuRegs->ipubp |= (g_BP.FP+g_BP.bufferhasnew) << 16; + + IPU_LOG("Ipu read32: IPU_BP=0x%08X\n", *(u32*)&g_BP); + return ipuRegs->ipubp; + } + + return *(u32*)(((u8*)ipuRegs)+(mem&0xff)); // ipu repeats every 0x100 +} + +__forceinline u64 ipuRead64(u32 mem) +{ + IPUProcessInterrupt(); + +#ifdef PCSX2_DEVBUILD + if( mem == 0x10002010 ) { + SysPrintf("reading 64bit IPU ctrl\n"); + } + if( mem == 0x10002020 ) { + SysPrintf("reading 64bit IPU top\n"); + } +#endif + + switch (mem){ + case 0x10002000: // IPU_CMD + + //if(!ipuRegs->cmd.BUSY){ + if( ipuRegs->cmd.DATA&0xffffff ) + IPU_LOG("Ipu read64: IPU_CMD=BUSY=%x, DATA=%08X\n", ipuRegs->cmd.BUSY?1:0,ipuRegs->cmd.DATA); + //return *(u64*)&ipuRegs->cmd; + break; + + case 0x10002030: // IPU_TOP + IPU_LOG("Ipu read64: IPU_TOP=%x, bp = %d\n",ipuRegs->top,g_BP.BP); + + //return *(u64*)&ipuRegs->top; + break; + + default: + IPU_LOG("Ipu read64: Unknown=%x\n", mem); + break; + + } + return *(u64*)(((u8*)ipuRegs)+(mem&0xff)); +} + +void ipuSoftReset() +{ + if (!mpeg2_inited){ + mpeg2_idct_init(); + convert=convert_rgb (CONVERT_RGB, 32); + convert(16, 16, 0, NULL, &convert_init); + memzero_obj(mb8.Y); + memzero_obj(mb8.Cb); + memzero_obj(mb8.Cr); + memzero_obj(mb16.Y); + memzero_obj(mb16.Cb); + memzero_obj(mb16.Cr); + mpeg2_inited=1; + } + + FIFOto_clear(); + memzero_obj(fifo_output); + FOwritepos = 0; + FOreadpos = 0; + coded_block_pattern = 0; + + //g_nDMATransfer = 0; + + ipuRegs->ctrl._u32 = 0; + g_BP.BP = 0; + g_BP.IFC = 0; + g_BP.FP = 0; + g_BP.bufferhasnew = 0; + ipuRegs->top = 0; + g_nCmdIndex = 0; + ipuCurCmd = 0xffffffff; + g_nCmdPos[0] = 0; g_nCmdPos[1] = 0; +} + +__forceinline void ipuWrite32(u32 mem,u32 value) +{ + IPUProcessInterrupt(); + + switch (mem){ + case 0x10002000: // IPU_CMD + IPU_LOG("Ipu write32: IPU_CMD=0x%08X\n",value); + IPUCMD_WRITE(value); + break; + case 0x10002010: // IPU_CTRL + ipuRegs->ctrl._u32 = (value&0x47f30000)|(ipuRegs->ctrl._u32&0x8000ffff); + if( ipuRegs->ctrl.IDP == 3 ) { + SysPrintf("IPU Invalid Intra DC Precision, switching to 9 bits\n"); + ipuRegs->ctrl.IDP = 1; + } + if (ipuRegs->ctrl.RST & 0x1) { // RESET + ipuSoftReset(); + } + + IPU_LOG("Ipu write32: IPU_CTRL=0x%08X\n",value); + + break; + default: + IPU_LOG("Ipu write32: Unknown=%x\n", mem); + *(u32*)((u8*)ipuRegs + (mem&0xfff)) = value; + break; + } +} + +__forceinline void ipuWrite64(u32 mem, u64 value) +{ + IPUProcessInterrupt(); + + switch (mem){ + case 0x10002000: + IPU_LOG("Ipu write64: IPU_CMD=0x%08X\n",value); + IPUCMD_WRITE((u32)value); + break; + + default: + IPU_LOG("Ipu write64: Unknown=%x\n", mem); + *(u64*)((u8*)ipuRegs + (mem&0xfff)) = value; + break; + } +} + + +////////////////////////////////////////////////////// +// IPU Commands (exec on worker thread only) + +static void ipuBCLR(u32 val) { + FIFOto_clear(); + g_BP.BP = val & 0x7F; + g_BP.FP = 0; + g_BP.bufferhasnew = 0; + g_BP.IFC = 0; + ipuRegs->ctrl.BUSY = 0; + ipuRegs->cmd.BUSY = 0; + memzero_ptr<80>(readbits); + IPU_LOG("Clear IPU input FIFO. Set Bit offset=0x%X\n", g_BP.BP); +} + +static __forceinline BOOL ipuIDEC(u32 val) +{ + tIPU_CMD_IDEC idec( val ); + + + IPU_LOG("IPU IDEC command.\n"); + if (idec.FB){ IPU_LOG(" Skip %d bits.",idec.FB);} + IPU_LOG(" Quantizer step code=0x%X.",idec.QSC); + if (idec.DTD==0){ IPU_LOG(" Does not decode DT."); + }else{ IPU_LOG(" Decodes DT.");} + if (idec.SGN==0){ IPU_LOG(" No bias."); + }else{ IPU_LOG(" Bias=128.");} + if (idec.DTE==1){ IPU_LOG(" Dither Enabled.");} + if (idec.OFM==0){ IPU_LOG(" Output format is RGB32."); + }else{ IPU_LOG(" Output format is RGB16.");} + IPU_LOG("\n"); + + g_BP.BP+= idec.FB;//skip FB bits + //from IPU_CTRL + ipuRegs->ctrl.PCT = I_TYPE; //Intra DECoding;) + g_decoder.coding_type =ipuRegs->ctrl.PCT; + g_decoder.mpeg1 =ipuRegs->ctrl.MP1; + g_decoder.q_scale_type =ipuRegs->ctrl.QST; + g_decoder.intra_vlc_format=ipuRegs->ctrl.IVF; + g_decoder.scan =ipuRegs->ctrl.AS ? mpeg2_scan_alt: mpeg2_scan_norm; + g_decoder.intra_dc_precision=ipuRegs->ctrl.IDP; + //from IDEC value + g_decoder.quantizer_scale =idec.QSC; + g_decoder.frame_pred_frame_dct=!idec.DTD; + g_decoder.sgn =idec.SGN; + g_decoder.dte =idec.DTE; + g_decoder.ofm =idec.OFM; + //other stuff + g_decoder.dcr =1;//resets DC prediction value + + s_routine = so_create(mpeg2sliceIDEC, &s_RoutineDone, s_tempstack, sizeof(s_tempstack)); + assert( s_routine != NULL ); + so_call(s_routine); + if(s_RoutineDone) + s_routine = NULL; + + return s_RoutineDone; +} + +#ifdef _DEBUG +static int s_bdec=0; +#else +#define s_bdec 0 +#endif + +static __forceinline BOOL ipuBDEC(u32 val) +{ + tIPU_CMD_BDEC bdec( val ); + + IPU_LOG("IPU BDEC(macroblock decode) command %x, num: 0x%x\n",cpuRegs.pc, s_bdec); + if (bdec.FB){ IPU_LOG(" Skip 0x%X bits.", bdec.FB);} + if (bdec.MBI){ IPU_LOG(" Intra MB.");} + else{ IPU_LOG(" Non-intra MB.");} + if (bdec.DCR){ IPU_LOG(" Resets DC prediction value.");} + else{ IPU_LOG(" Doesn't reset DC prediction value.");} + if (bdec.DT){ IPU_LOG(" Use field DCT.");} + else{ IPU_LOG(" Use frame DCT.");} + IPU_LOG(" Quantizer step=0x%X\n",bdec.QSC); +#ifdef _DEBUG + s_bdec++; +#endif + + g_BP.BP+= bdec.FB;//skip FB bits + g_decoder.coding_type = I_TYPE; + g_decoder.mpeg1 =ipuRegs->ctrl.MP1; + g_decoder.q_scale_type =ipuRegs->ctrl.QST; + g_decoder.intra_vlc_format=ipuRegs->ctrl.IVF; + g_decoder.scan =ipuRegs->ctrl.AS ? mpeg2_scan_alt: mpeg2_scan_norm; + g_decoder.intra_dc_precision=ipuRegs->ctrl.IDP; + //from BDEC value + /* JayteeMaster: the quantizer (linear/non linear) depends on the q_scale_type */ + g_decoder.quantizer_scale =g_decoder.q_scale_type?non_linear_quantizer_scale [bdec.QSC]:bdec.QSC<<1; + g_decoder.macroblock_modes =bdec.DT ? DCT_TYPE_INTERLACED : 0; + g_decoder.dcr =bdec.DCR; + g_decoder.macroblock_modes|=bdec.MBI ? MACROBLOCK_INTRA : MACROBLOCK_PATTERN; + + memzero_obj(mb8); + memzero_obj(mb16); + + s_routine = so_create(mpeg2_slice, &s_RoutineDone, s_tempstack, sizeof(s_tempstack)); + assert( s_routine != NULL ); + so_call(s_routine); + if(s_RoutineDone) + s_routine = NULL; + return s_RoutineDone; +} + +static BOOL __fastcall ipuVDEC(u32 val) { + + switch( g_nCmdPos[0] ) { + case 0: + ipuRegs->cmd.DATA = 0; + if( !getBits32((u8*)&g_decoder.bitstream_buf, 0) ) + return FALSE; + + g_decoder.bitstream_bits = -16; + BigEndian(g_decoder.bitstream_buf, g_decoder.bitstream_buf); + + switch((val >> 26) & 3){ + case 0://Macroblock Address Increment + g_decoder.mpeg1 =ipuRegs->ctrl.MP1; + ipuRegs->cmd.DATA = get_macroblock_address_increment(&g_decoder); + break; + case 1://Macroblock Type //known issues: no error detected + g_decoder.frame_pred_frame_dct=1;//prevent DCT_TYPE_INTERLACED + g_decoder.coding_type =ipuRegs->ctrl.PCT; + ipuRegs->cmd.DATA=get_macroblock_modes(&g_decoder); + break; + case 2://Motion Code //known issues: no error detected + ipuRegs->cmd.DATA=get_motion_delta(&g_decoder,0); + break; + case 3://DMVector + ipuRegs->cmd.DATA=get_dmv(&g_decoder); + break; + } + + g_BP.BP+=(g_decoder.bitstream_bits+16); + if((int)g_BP.BP < 0) { + g_BP.BP += 128; + ReorderBitstream(); + } + + FillInternalBuffer(&g_BP.BP,1,0); + + ipuRegs->cmd.DATA = (ipuRegs->cmd.DATA & 0xFFFF) | ((g_decoder.bitstream_bits+16) << 16); + ipuRegs->ctrl.ECD = (ipuRegs->cmd.DATA==0); + + case 1: + if( !getBits32((u8*)&ipuRegs->top, 0) ) { + g_nCmdPos[0] = 1; + return FALSE; + } + + BigEndian(ipuRegs->top, ipuRegs->top); + + IPU_LOG("IPU VDEC command data 0x%x(0x%x). Skip 0x%X bits/Table=%d (%s), pct %d\n", + ipuRegs->cmd.DATA,ipuRegs->cmd.DATA >> 16,val & 0x3f, (val >> 26) & 3, (val >> 26) & 1 ? + ((val >> 26) & 2 ? "DMV" : "MBT") : (((val >> 26) & 2 ? "MC" : "MBAI")),ipuRegs->ctrl.PCT); + + return TRUE; + + jNO_DEFAULT + } + + return FALSE; +} + +static BOOL ipuFDEC(u32 val) +{ + if( !getBits32((u8*)&ipuRegs->cmd.DATA, 0) ) + return FALSE; + + BigEndian(ipuRegs->cmd.DATA, ipuRegs->cmd.DATA); + ipuRegs->top = ipuRegs->cmd.DATA; + + IPU_LOG("FDEC read: 0x%8.8x\n", ipuRegs->top); + + return TRUE; +} + +static __forceinline BOOL ipuSETIQ(u32 val) +{ + int i; + + if ((val >> 27) & 1){ + g_nCmdPos[0] += getBits((u8*)niq + g_nCmdPos[0], 512-8*g_nCmdPos[0], 1); // 8*8*8 + + IPU_LOG("Read non-intra quantization matrix from IPU FIFO.\n"); + for (i=0; i<8; i++){ + IPU_LOG("%02X %02X %02X %02X %02X %02X %02X %02X\n", + niq[i*8+0], niq[i*8+1], niq[i*8+2], niq[i*8+3], + niq[i*8+4], niq[i*8+5], niq[i*8+6], niq[i*8+7]); + } + }else{ + g_nCmdPos[0] += getBits((u8*)iq+8*g_nCmdPos[0], 512-8*g_nCmdPos[0], 1); + IPU_LOG("Read intra quantization matrix from IPU FIFO.\n"); + for (i=0; i<8; i++){ + IPU_LOG("%02X %02X %02X %02X %02X %02X %02X %02X\n", + iq[i*8+0], iq[i*8+1], iq[i*8+2], iq[i*8+3], + iq[i*8+4], iq[i*8+5], iq[i*8+6], iq[i*8+7]); + } + } + + return g_nCmdPos[0] == 64; +} + +static __forceinline BOOL ipuSETVQ(u32 val) +{ + g_nCmdPos[0] += getBits((u8*)vqclut+g_nCmdPos[0], 256-8*g_nCmdPos[0], 1); // 16*2*8 + + if( g_nCmdPos[0] == 32 ) + { + IPU_LOG("IPU SETVQ command.\nRead VQCLUT table from IPU FIFO.\n"); + IPU_LOG( + "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d " + "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d\n" + "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d " + "%02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d %02d:%02d:%02d\n", + vqclut[0] >> 10, (vqclut[0] >> 5) & 0x1F, vqclut[0] & 0x1F, + vqclut[1] >> 10, (vqclut[1] >> 5) & 0x1F, vqclut[1] & 0x1F, + vqclut[2] >> 10, (vqclut[2] >> 5) & 0x1F, vqclut[2] & 0x1F, + vqclut[3] >> 10, (vqclut[3] >> 5) & 0x1F, vqclut[3] & 0x1F, + vqclut[4] >> 10, (vqclut[4] >> 5) & 0x1F, vqclut[4] & 0x1F, + vqclut[5] >> 10, (vqclut[5] >> 5) & 0x1F, vqclut[5] & 0x1F, + vqclut[6] >> 10, (vqclut[6] >> 5) & 0x1F, vqclut[6] & 0x1F, + vqclut[7] >> 10, (vqclut[7] >> 5) & 0x1F, vqclut[7] & 0x1F, + vqclut[8] >> 10, (vqclut[8] >> 5) & 0x1F, vqclut[8] & 0x1F, + vqclut[9] >> 10, (vqclut[9] >> 5) & 0x1F, vqclut[9] & 0x1F, + vqclut[10] >> 10, (vqclut[10] >> 5) & 0x1F, vqclut[10] & 0x1F, + vqclut[11] >> 10, (vqclut[11] >> 5) & 0x1F, vqclut[11] & 0x1F, + vqclut[12] >> 10, (vqclut[12] >> 5) & 0x1F, vqclut[12] & 0x1F, + vqclut[13] >> 10, (vqclut[13] >> 5) & 0x1F, vqclut[13] & 0x1F, + vqclut[14] >> 10, (vqclut[14] >> 5) & 0x1F, vqclut[14] & 0x1F, + vqclut[15] >> 10, (vqclut[15] >> 5) & 0x1F, vqclut[15] & 0x1F); + } + + return g_nCmdPos[0] == 32; +} + +// IPU Transfers are split into 8Qwords so we need to send ALL the data +static BOOL __fastcall ipuCSC(u32 val) +{ + tIPU_CMD_CSC csc( val ); + + IPU_LOG("IPU CSC(Colorspace conversion from YCbCr) command (%d).\n",csc.MBC); + if (csc.OFM){ IPU_LOG("Output format is RGB16. ");} + else{ IPU_LOG("Output format is RGB32. ");} + if (csc.DTE){ IPU_LOG("Dithering enabled."); } + + //SysPrintf("CSC\n"); + for (;g_nCmdIndex<(int)csc.MBC; g_nCmdIndex++){ + + if( g_nCmdPos[0] < 3072/8 ) { + g_nCmdPos[0] += getBits((u8*)&mb8+g_nCmdPos[0], 3072-8*g_nCmdPos[0], 1); + + if( g_nCmdPos[0] < 3072/8 ) + return FALSE; + + ipu_csc(&mb8, &rgb32, 0); + if (csc.OFM){ + ipu_dither2(&rgb32, &rgb16, csc.DTE); + } + } + + if (csc.OFM){ + while(g_nCmdPos[1] < 32) + { + g_nCmdPos[1] += FIFOfrom_write(((u32*)&rgb16)+4*g_nCmdPos[1], 32-g_nCmdPos[1]); + + if( g_nCmdPos[1] <= 0 ) + return FALSE; + } + } + else { + while(g_nCmdPos[1] < 64) + { + g_nCmdPos[1] += FIFOfrom_write(((u32*)&rgb32)+4*g_nCmdPos[1], 64-g_nCmdPos[1]); + + if( g_nCmdPos[1] <= 0 ) + return FALSE; + } + } + + g_nCmdPos[0] = 0; + g_nCmdPos[1] = 0; + } + + return TRUE; +} + +// Todo - Need to add the same stop and start code as CSC +static BOOL ipuPACK(u32 val) +{ + tIPU_CMD_CSC csc( val ); + + IPU_LOG("IPU PACK (Colorspace conversion from RGB32) command.\n"); + if (csc.OFM){ IPU_LOG("Output format is RGB16. ");} + else{ IPU_LOG("Output format is INDX4. ");} + if (csc.DTE){ IPU_LOG("Dithering enabled."); } + IPU_LOG("Number of macroblocks to be converted: %d\n", csc.MBC); + + for (;g_nCmdIndex<(int)csc.MBC; g_nCmdIndex++){ + + if( g_nCmdPos[0] < 512 ) { + g_nCmdPos[0] += getBits((u8*)&mb8+g_nCmdPos[0], 512-8*g_nCmdPos[0], 1); + + if( g_nCmdPos[0] < 64 ) + return FALSE; + + ipu_csc(&mb8, &rgb32, 0); + ipu_dither2(&rgb32, &rgb16, csc.DTE); + if (csc.OFM){ + ipu_vq(&rgb16, indx4); + } + } + + if (csc.OFM) { + g_nCmdPos[1] += FIFOfrom_write(((u32*)&rgb16)+4*g_nCmdPos[1], 32-g_nCmdPos[1]); + + if( g_nCmdPos[1] < 32 ) + return FALSE; + } + else { + g_nCmdPos[1] += FIFOfrom_write(((u32*)indx4)+4*g_nCmdPos[1], 8-g_nCmdPos[1]); + + if( g_nCmdPos[1] < 8 ) + return FALSE; + } + + g_nCmdPos[0] = 0; + g_nCmdPos[1] = 0; + } + + return TRUE; +} + +static void ipuSETTH(u32 val) { + s_thresh[0] = (val & 0xff); + s_thresh[1] = ((val>>16) & 0xff); + IPU_LOG("IPU SETTH (Set threshold value)command %x.\n", val&0xff00ff); +} + +/////////////////////// +// IPU Worker Thread // +/////////////////////// +#define IPU_INTERRUPT(dma) { \ + hwIntcIrq(INTC_IPU); \ +} + +void IPUCMD_WRITE(u32 val) { + + // don't process anything if currently busy + if( ipuRegs->ctrl.BUSY ) { + // wait for thread + SysPrintf("IPU BUSY!\n"); + } + + ipuRegs->ctrl.ECD = 0; + ipuRegs->ctrl.SCD = 0; //clear ECD/SCD + ipuRegs->cmd.DATA = val; + g_nCmdPos[0] = 0; + + switch (ipuRegs->cmd.CMD) { + case SCE_IPU_BCLR: + ipuBCLR(val); + IPU_INTERRUPT(DMAC_TO_IPU); + return; + + case SCE_IPU_VDEC: + + g_BP.BP+= val & 0x3F; + + // check if enough data in queue + if( ipuVDEC(val) ) { + return; + } + + ipuRegs->cmd.BUSY = 0x80000000; + ipuRegs->topbusy = 0x80000000; + + break; + + case SCE_IPU_FDEC: + IPU_LOG("IPU FDEC command. Skip 0x%X bits, FIFO 0x%X qwords, BP 0x%X, FP %d, CHCR 0x%x, %x\n", + val & 0x3f,g_BP.IFC,(int)g_BP.BP,g_BP.FP,((DMACh*)&PS2MEM_HW[0xb400])->chcr,cpuRegs.pc); + + g_BP.BP+= val & 0x3F; + + if( ipuFDEC(val) ) { + return; + } + + ipuRegs->cmd.BUSY = 0x80000000; + ipuRegs->topbusy = 0x80000000; + + break; + + case SCE_IPU_SETTH: + ipuSETTH(val); + hwIntcIrq(INTC_IPU); + return; + + case SCE_IPU_SETIQ: + IPU_LOG("IPU SETIQ command.\n"); + + if (val & 0x3f) + IPU_LOG("Skip %d bits.\n", val & 0x3f); + + g_BP.BP+= val & 0x3F; + + if( ipuSETIQ(ipuRegs->cmd.DATA) ) { + return; + } + + break; + case SCE_IPU_SETVQ: + if( ipuSETVQ(ipuRegs->cmd.DATA) ) { + return; + } + + break; + case SCE_IPU_CSC: + g_nCmdPos[1] = 0; + g_nCmdIndex = 0; + + if( ipuCSC(ipuRegs->cmd.DATA) ) { + if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) + IPU_INT0_FROM(); + return; + } + + break; + case SCE_IPU_PACK: + + g_nCmdPos[1] = 0; + g_nCmdIndex = 0; + + if( ipuPACK(ipuRegs->cmd.DATA) ) { + return; + } + + break; + + case SCE_IPU_IDEC: + if( ipuIDEC(val) ) { + // idec done, ipu0 done too + if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) + IPU_INT0_FROM(); + return; + } + + ipuRegs->topbusy = 0x80000000; + // have to resort to the thread + ipuCurCmd = val>>28; + ipuRegs->ctrl.BUSY = 1; + + return; + + case SCE_IPU_BDEC: + if( ipuBDEC(val)) { + if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) + IPU_INT0_FROM(); + if (ipuRegs->ctrl.SCD || ipuRegs->ctrl.ECD) + hwIntcIrq(INTC_IPU); + + return; + } + + ipuRegs->topbusy = 0x80000000; + ipuCurCmd = val>>28; + ipuRegs->ctrl.BUSY = 1; + + return; + } + + // have to resort to the thread + ipuCurCmd = val>>28; + ipuRegs->ctrl.BUSY = 1; + hwIntcIrq(INTC_IPU); +} + +void IPUWorker() +{ + assert( ipuRegs->ctrl.BUSY ); + + switch (ipuCurCmd) { + case SCE_IPU_VDEC: + if( !ipuVDEC(ipuRegs->cmd.DATA) ) + { + hwIntcIrq(INTC_IPU); + return; + } + + ipuRegs->cmd.BUSY = 0; + ipuRegs->topbusy = 0; + + break; + + case SCE_IPU_FDEC: + if( !ipuFDEC(ipuRegs->cmd.DATA) ) + { + hwIntcIrq(INTC_IPU); + return; + } + + ipuRegs->cmd.BUSY = 0; + ipuRegs->topbusy = 0; + + break; + + case SCE_IPU_SETIQ: + if( !ipuSETIQ(ipuRegs->cmd.DATA) ) + { + hwIntcIrq(INTC_IPU); + return; + } + + break; + case SCE_IPU_SETVQ: + if( !ipuSETVQ(ipuRegs->cmd.DATA) ) + { + hwIntcIrq(INTC_IPU); + return; + } + + break; + case SCE_IPU_CSC: + if( !ipuCSC(ipuRegs->cmd.DATA) ) + { + hwIntcIrq(INTC_IPU); + return; + } + + if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) + IPU_INT0_FROM(); + break; + case SCE_IPU_PACK: + if( !ipuPACK(ipuRegs->cmd.DATA) ) + { + hwIntcIrq(INTC_IPU); + return; + } + + break; + + case SCE_IPU_IDEC: + so_call(s_routine); + if( !s_RoutineDone ) { + hwIntcIrq(INTC_IPU); + return; + } + + ipuRegs->ctrl.OFC = 0; + ipuRegs->ctrl.BUSY = 0; + ipuRegs->topbusy = 0; + ipuRegs->cmd.BUSY = 0; + ipuCurCmd = 0xffffffff; + // CHECK!: IPU0dma remains when IDEC is done, so we need to clear it + if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) + IPU_INT0_FROM(); + + s_routine = NULL; + break; + case SCE_IPU_BDEC: + so_call(s_routine); + if(!s_RoutineDone) + { + hwIntcIrq(INTC_IPU); + return; + } + + ipuRegs->ctrl.BUSY = 0; + ipuRegs->topbusy = 0; + ipuRegs->cmd.BUSY = 0; + ipuCurCmd = 0xffffffff; + if(ipu0dma->qwc > 0 && (ipu0dma->chcr & 0x100)) + IPU_INT0_FROM(); + s_routine = NULL; + if (ipuRegs->ctrl.SCD || ipuRegs->ctrl.ECD) + hwIntcIrq(INTC_IPU); + return; + + default: + SysPrintf("Unknown IPU command: %x\n", ipuRegs->cmd.CMD); + break; + } + + // success + ipuRegs->ctrl.BUSY = 0; + ipuCurCmd = 0xffffffff; +} + +///////////////// +// Buffer reader + +// move the readbits queue +__forceinline void inc_readbits() +{ + readbits += 16; + if( readbits >= _readbits+64 ) { + + // move back + *(u64*)(_readbits) = *(u64*)(_readbits+64); + *(u64*)(_readbits+8) = *(u64*)(_readbits+72); + readbits = _readbits; + } +} + +// returns the pointer of readbits moved by 1 qword +__forceinline u8* next_readbits() +{ + return readbits + 16; +} + +// returns the pointer of readbits moved by 1 qword +u8* prev_readbits() +{ + if( readbits < _readbits+16 ) { + return _readbits+48-(readbits-_readbits); + } + + return readbits-16; +} + +void ReorderBitstream() +{ + readbits = prev_readbits(); + g_BP.FP = 2; +} + + +// IPU has a 2qword internal buffer whose status is pointed by FP. +// If FP is 1, there's 1 qword in buffer. Second qword is only loaded +// incase there are less than 32bits available in the first qword. +// \return Number of bits available (clamps at 16 bits) +u16 __fastcall FillInternalBuffer(u32 * pointer, u32 advance, u32 size) +{ + if(g_BP.FP == 0) + { + if( FIFOto_read(next_readbits()) == 0 ) + return 0; + + inc_readbits(); + g_BP.FP = 1; + } + else if(g_BP.FP < 2 && (*(int*)pointer+size) >= 128) + { + if( FIFOto_read(next_readbits()) ) + { + g_BP.FP += 1; + } + } + + if(*(int*)pointer >= 128) + { + assert( g_BP.FP >= 1); + + if(g_BP.FP > 1) + { + inc_readbits(); + } + + if(advance) + { + g_BP.FP--; + *pointer &= 127; + } + } + + return g_BP.FP >= 1 ? g_BP.FP*128-(*(int*)pointer) : 0; +} + +// whenever reading fractions of bytes. The low bits always come from the next byte +// while the high bits come from the current byte +u8 __fastcall getBits32(u8 *address, u32 advance) +{ + register u32 mask, shift=0; + u8* readpos; + + // Check if the current BP has exceeded or reached the limit of 128 + if( FillInternalBuffer(&g_BP.BP,1,32) < 32 ) + return 0; + + readpos = readbits+(int)g_BP.BP/8; + + if (g_BP.BP & 7) { + + shift = g_BP.BP&7; + mask = (0xff>>shift); + mask = mask|(mask<<8)|(mask<<16)|(mask<<24); + + *(u32*)address = ((~mask&*(u32*)(readpos+1))>>(8-shift)) | (((mask)&*(u32*)readpos)<>shift); + mask = mask|(mask<<8); + + *(u16*)address = ((~mask&*(u16*)(readpos+1))>>(8-shift)) | (((mask)&*(u16*)readpos)<>shift); + + *(u8*)address = (((~mask)&readpos[1])>>(8-shift)) | (((mask)&*readpos)<> (pointer&7)) << + (8-howmuch-(pointer&7))) & 0xFF; + mask &= readbits[((pointer)>>3)]; + mask >>= 8-howmuch-(pointer&7); + pointer += howmuch; + size -= howmuch; + shift -= howmuch; + *address |= mask << shift; + } + + ++address; + } + else + { + u8* readmem; + while (size) + { + if( FillInternalBuffer(&pointer,advance,8) < 8 ) + { + if(advance) + { + g_BP.BP = pointer; + } + return address-oldaddr; + } + + howmuch = min(128-pointer, size); + size -= howmuch; + + readmem = readbits + (pointer>>3); + pointer += howmuch; + howmuch >>= 3; + + while(howmuch >= 4) { + *(u32*)address = *(u32*)readmem; + howmuch -= 4; + address += 4; + readmem += 4; + } + + switch(howmuch) { + case 3: address[2] = readmem[2]; + case 2: address[1] = readmem[1]; + case 1: address[0] = readmem[0]; + case 0: + break; + + jNO_DEFAULT + } + + address += howmuch; + } + } + + // If not advance then reset the Reading buffer value + if(advance) + { + g_BP.BP = pointer; + + } + else readbits = oldbits; // restore the last pointer + + return address-oldaddr; +} + +///////////////////// CORE FUNCTIONS ///////////////// +void Skl_YUV_To_RGB32_MMX(u8 *RGB, const int Dst_BpS, const u8 *Y, const u8 *U, const u8 *V, + const int Src_BpS, const int Width, const int Height); + +void __fastcall ipu_csc(macroblock_8 *mb8, macroblock_rgb32 *rgb32, int sgn){ + int i; + u8* p = (u8*)rgb32; + + convert_init.start(convert_init.id, (u8*)rgb32, CONVERT_FRAME); + convert_init.copy(convert_init.id, (u8*)mb8->Y, (u8*)mb8->Cr, (u8*)mb8->Cb, 0); + + if( s_thresh[0] > 0 ) { + for(i = 0; i < 64*4; i++, p += 4) { + if( p[0] < s_thresh[0] && p[1] < s_thresh[0] && p[2] < s_thresh[0] ) + *(u32*)p = 0; + else + p[3] = (p[1] < s_thresh[1] && p[2] < s_thresh[1] && p[3] < s_thresh[1]) ? 0x40 : 0x80; + } + } + else if( s_thresh[1] > 0 ) { + for(i = 0; i < 64*4; i++, p += 4) { + p[3] = (p[1] < s_thresh[1] && p[2] < s_thresh[1] && p[3] < s_thresh[1]) ? 0x40 : 0x80; + } + } + else { + for(i = 0; i < 64; i++, p += 16) { + p[3] = p[7] = p[11] = p[15] = 0x80; + } + } +} + +void __fastcall ipu_dither2(const macroblock_rgb32* rgb32, macroblock_rgb16 *rgb16, int dte) +{ + int i, j; + for(i = 0; i < 16; ++i) { + for(j = 0; j < 16; ++j) { + rgb16->c[i][j].r = rgb32->c[i][j].r>>3; + rgb16->c[i][j].g = rgb32->c[i][j].g>>3; + rgb16->c[i][j].b = rgb32->c[i][j].b>>3; + rgb16->c[i][j].a = rgb32->c[i][j].a==0x40; + } + } +} + +void __fastcall ipu_dither(macroblock_8 *mb8, macroblock_rgb16 *rgb16, int dte) +{ + //SysPrintf("IPU: Dither not implemented"); +} + +void __fastcall ipu_vq(macroblock_rgb16 *rgb16, u8* indx4){ + Console::Error("IPU: VQ not implemented"); +} + +void __fastcall ipu_copy(const macroblock_8 *mb8, macroblock_16 *mb16) { + const u8 *s=(const u8*)mb8; + s16 *d=(s16*)mb16; + int i; + for (i=0; i< 256; i++) *d++ = *s++; //Y bias - 16 + for (i=0; i< 64; i++) *d++ = *s++; //Cr bias - 128 + for (i=0; i< 64; i++) *d++ = *s++; //Cb bias - 128 + /*for(i = 0; i < 384/(16*6); ++i, s += 16*4, d += 16*4) { + __m128i r0, r1, r2, r3, r4, r5, r6, r7; + + r0 = _mm_load_si128((__m128i*)s); + r2 = _mm_load_si128((__m128i*)s+1); + r4 = _mm_load_si128((__m128i*)s+2); + r6 = _mm_load_si128((__m128i*)s+3); + + // signed shift + r1 = _mm_srai_epi16(_mm_unpackhi_epi8(r0, r0), 8); + r0 = _mm_srai_epi16(_mm_unpacklo_epi8(r0, r0), 8); + r3 = _mm_srai_epi16(_mm_unpackhi_epi8(r2, r2), 8); + r2 = _mm_srai_epi16(_mm_unpacklo_epi8(r2, r2), 8); + r5 = _mm_srai_epi16(_mm_unpackhi_epi8(r4, r4), 8); + r4 = _mm_srai_epi16(_mm_unpacklo_epi8(r4, r4), 8); + r7 = _mm_srai_epi16(_mm_unpackhi_epi8(r6, r6), 8); + r6 = _mm_srai_epi16(_mm_unpacklo_epi8(r6, r6), 8); + + _mm_store_si128((__m128i*)d, r0); + _mm_store_si128((__m128i*)d+1, r1); + _mm_store_si128((__m128i*)d+2, r2); + _mm_store_si128((__m128i*)d+3, r3); + _mm_store_si128((__m128i*)d+4, r4); + _mm_store_si128((__m128i*)d+5, r5); + _mm_store_si128((__m128i*)d+6, r6); + _mm_store_si128((__m128i*)d+7, r7); + }*/ +} + +///////////////////// IPU DMA //////////////////////// +void FIFOto_clear() +{ + //assert( g_BP.IFC == 0 ); + memzero_obj(fifo_input); + g_BP.IFC = 0; + ipuRegs->ctrl.IFC = 0; + FIreadpos = 0; + FIwritepos = 0; +} + +int FIFOto_read(void *value) +{ + // wait until enough data + if( g_BP.IFC == 0 ) { + if( IPU1dma() == 0 ) + return 0; + + assert( g_BP.IFC > 0 ); + } + + // transfer 1 qword, split into two transfers + ((u32*)value)[0] = fifo_input[FIreadpos]; fifo_input[FIreadpos] = 0; + ((u32*)value)[1] = fifo_input[FIreadpos+1]; fifo_input[FIreadpos+1] = 0; + ((u32*)value)[2] = fifo_input[FIreadpos+2]; fifo_input[FIreadpos+2] = 0; + ((u32*)value)[3] = fifo_input[FIreadpos+3]; fifo_input[FIreadpos+3] = 0; + FIreadpos = (FIreadpos + 4) & 31; + g_BP.IFC--; + return 1; +} + +int FIFOto_write(u32* pMem, int size) +{ + int transsize; + int firsttrans = min(size, 8-(int)g_BP.IFC); + + g_BP.IFC+=firsttrans; + transsize = firsttrans; + + while(transsize-- > 0) { + fifo_input[FIwritepos] = pMem[0]; + fifo_input[FIwritepos+1] = pMem[1]; + fifo_input[FIwritepos+2] = pMem[2]; + fifo_input[FIwritepos+3] = pMem[3]; + FIwritepos = (FIwritepos+4)&31; + pMem +=4; + } + + return firsttrans; +} + +#define IPU1chain() { \ + if(ipu1dma->qwc > 0) \ + { \ + int qwc = ipu1dma->qwc; \ + pMem = (u32*)dmaGetAddr(ipu1dma->madr); \ + if (pMem == NULL) { Console::Error("ipu1dma NULL!"); return totalqwc; } \ + qwc = FIFOto_write(pMem, qwc); \ + ipu1dma->madr += qwc<< 4; \ + ipu1dma->qwc -= qwc; \ + totalqwc += qwc; \ + if( ipu1dma->qwc > 0 ) { \ + g_nDMATransfer |= IPU_DMA_ACTV1; \ + return totalqwc; \ + } \ + } \ +} + +int IPU1dma() +{ + u32 *ptag, *pMem; + int done=0; + int ipu1cycles = 0; + int totalqwc = 0; + + assert( !(ipu1dma->chcr&0x40) ); + + if( !(ipu1dma->chcr & 0x100) || (cpuRegs.interrupt & (1<qwc > 0 ) { + IPU1chain(); + + if ((ipu1dma->chcr & 0x80) && (g_nDMATransfer&IPU_DMA_DOTIE1)) { //Check TIE bit of CHCR and IRQ bit of tag + SysPrintf("IPU1 TIE\n"); + + IPU_INT_TO(totalqwc*BIAS); + g_nDMATransfer &= ~(IPU_DMA_ACTV1|IPU_DMA_DOTIE1); + g_nDMATransfer |= IPU_DMA_TIE1; + return totalqwc; + } + + g_nDMATransfer &= ~(IPU_DMA_ACTV1|IPU_DMA_DOTIE1); + + if( (ipu1dma->chcr&0xc) == 0 ) { + IPU_INT_TO(totalqwc*BIAS); + return totalqwc; + } + else { + u32 tag = ipu1dma->chcr; // upper bits describe current tag + + if ((ipu1dma->chcr & 0x80) && (tag&0x80000000)) { + ptag = (u32*)dmaGetAddr(ipu1dma->tadr); + + switch(tag&0x70000000) { + case 0x00000000: ipu1dma->tadr += 16; break; + case 0x70000000: ipu1dma->tadr = ipu1dma->madr; break; + } + + ipu1dma->chcr = (ipu1dma->chcr & 0xFFFF) | ( (*ptag) & 0xFFFF0000 ); + IPU_LOG("IPU dmaIrq Set\n"); + IPU_INT_TO(totalqwc*BIAS); + g_nDMATransfer |= IPU_DMA_TIE1; + return totalqwc; + } + + switch( tag&0x70000000 ) + { + case 0x00000000: + ipu1dma->tadr += 16; + IPU_INT_TO((1+totalqwc)*BIAS); + return totalqwc; + + case 0x70000000: + ipu1dma->tadr = ipu1dma->madr; + IPU_INT_TO((1+totalqwc)*BIAS); + return totalqwc; + } + } + } + + if ((ipu1dma->chcr & 0xc) == 0 && ipu1dma->qwc == 0) { // Normal Mode + //SysPrintf("ipu1 normal empty qwc?\n"); + return totalqwc; + } + + // Transfer Dn_QWC from Dn_MADR to GIF + + if ((ipu1dma->chcr & 0xc) == 0 || ipu1dma->qwc > 0) { // Normal Mode + IPU_LOG("dmaIPU1 Normal size=%d, addr=%lx, fifosize=%x\n", + ipu1dma->qwc, ipu1dma->madr, 8 - g_BP.IFC); + IPU1chain(); + IPU_INT_TO((ipu1cycles+totalqwc)*BIAS); + return totalqwc; + } + else + { + // Chain Mode + //while (done == 0) { // Loop while Dn_CHCR.STR is 1 + ptag = (u32*)dmaGetAddr(ipu1dma->tadr); //Set memory pointer to TADR + if (ptag == NULL) { //Is ptag empty? + SysPrintf("IPU1 BUSERR\n"); + ipu1dma->chcr = ( ipu1dma->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register + return totalqwc; + } + ipu1cycles+=1; // Add 1 cycles from the QW read for the tag + + ipu1dma->chcr = ( ipu1dma->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + ipu1dma->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag + //ipu1dma->madr = ptag[1]; //MADR = ADDR field + + //done = hwDmacSrcChainWithStack(ipu1dma, id); + switch(ptag[0] & 0x70000000) { + case 0x00000000: // refe + // do not change tadr + ipu1dma->madr = ptag[1]; + done = 1; + break; + + case 0x10000000: // cnt + ipu1dma->madr = ipu1dma->tadr + 16; + // Set the taddr to the next tag + ipu1dma->tadr += 16 + (ipu1dma->qwc << 4); + break; + + case 0x20000000: // next + ipu1dma->madr = ipu1dma->tadr + 16; + ipu1dma->tadr = ptag[1]; + break; + + case 0x30000000: // ref + ipu1dma->madr = ptag[1]; + ipu1dma->tadr += 16; + break; + + case 0x70000000: // end + // do not change tadr + ipu1dma->madr = ipu1dma->tadr + 16; + done = 1; + break; + + default: + Console::Error("IPU ERROR: different transfer mode!, Please report to PCSX2 Team\n"); + break; + } + + IPU_LOG("dmaIPU1 dmaChain %8.8x_%8.8x size=%d, addr=%lx, fifosize=%x\n", + ptag[1], ptag[0], ipu1dma->qwc, ipu1dma->madr, 8 - g_BP.IFC); + + if( (ipu1dma->chcr & 0x80) && ptag[0] & 0x80000000 ) + g_nDMATransfer |= IPU_DMA_DOTIE1; + else + g_nDMATransfer &= ~IPU_DMA_DOTIE1; + + //Britney Dance beat does a blank NEXT tag, for some odd reason the fix doesnt work if after IPU1Chain O_o + if(ipu1dma->qwc == 0 && done == 0 && !(g_nDMATransfer & IPU_DMA_DOTIE1)) IPU1dma(); + + IPU1chain(); + + if ((ipu1dma->chcr & 0x80) && (ptag[0]&0x80000000) && ipu1dma->qwc == 0) { //Check TIE bit of CHCR and IRQ bit of tag + SysPrintf("IPU1 TIE\n"); + + if( done ) { + ptag = (u32*)dmaGetAddr(ipu1dma->tadr); + + switch(ptag[0]&0x70000000) { + case 0x00000000: ipu1dma->tadr += 16; break; + case 0x70000000: ipu1dma->tadr = ipu1dma->madr; break; + } + + ipu1dma->chcr = (ipu1dma->chcr & 0xFFFF) | ( (*ptag) & 0xFFFF0000 ); + } + + IPU_INT_TO(ipu1cycles+totalqwc*BIAS); + g_nDMATransfer |= IPU_DMA_TIE1; + return totalqwc; + } + + if(ipu1dma->qwc == 0) + { + switch( ptag[0]&0x70000000 ) + { + case 0x00000000: + ipu1dma->tadr += 16; + break; + + case 0x70000000: + ipu1dma->tadr = ipu1dma->madr; + break; + } + } + } + + IPU_INT_TO((ipu1cycles+totalqwc)*BIAS); + return totalqwc; +} + + +int FIFOfrom_write(u32 *value,int size) +{ + int transsize; + int firsttrans; + + if((int)ipuRegs->ctrl.OFC >= 8) + { + if(IPU0dma() == 0) + { +// ipuRegs->ctrl.OFC = 0; + } + } + + transsize = min(size,8-(int)ipuRegs->ctrl.OFC); + firsttrans = transsize; + + while(transsize-- > 0) { + fifo_output[FOwritepos] = ((u32*)value)[0]; + fifo_output[FOwritepos+1] = ((u32*)value)[1]; + fifo_output[FOwritepos+2] = ((u32*)value)[2]; + fifo_output[FOwritepos+3] = ((u32*)value)[3]; + FOwritepos = (FOwritepos+4)&31; + value += 4; + } + + ipuRegs->ctrl.OFC+=firsttrans; + IPU0dma(); + //SysPrintf("Written %d qwords, %d\n",firsttrans,ipuRegs->ctrl.OFC); + + return firsttrans; +} + +void FIFOfrom_read(void *value,int size) +{ + ipuRegs->ctrl.OFC -= size; + while(size > 0) + { + // transfer 1 qword, split into two transfers + ((u32*)value)[0] = fifo_output[FOreadpos]; fifo_output[FOreadpos] = 0; + ((u32*)value)[1] = fifo_output[FOreadpos+1]; fifo_output[FOreadpos+1] = 0; + ((u32*)value)[2] = fifo_output[FOreadpos+2]; fifo_output[FOreadpos+2] = 0; + ((u32*)value)[3] = fifo_output[FOreadpos+3]; fifo_output[FOreadpos+3] = 0; + value = (u32*)value + 4; + FOreadpos = (FOreadpos + 4) & 31; + size--; + } +} + + +void FIFOfrom_readsingle(void *value) +{ + if(ipuRegs->ctrl.OFC > 0) + { + ipuRegs->ctrl.OFC --; + // transfer 1 qword, split into two transfers + ((u32*)value)[0] = fifo_output[FOreadpos]; fifo_output[FOreadpos] = 0; + ((u32*)value)[1] = fifo_output[FOreadpos+1]; fifo_output[FOreadpos+1] = 0; + ((u32*)value)[2] = fifo_output[FOreadpos+2]; fifo_output[FOreadpos+2] = 0; + ((u32*)value)[3] = fifo_output[FOreadpos+3]; fifo_output[FOreadpos+3] = 0; + FOreadpos = (FOreadpos + 4) & 31; + } +} + +int IPU0dma() +{ + int readsize; + void* pMem; + + //int qwc = ipu0dma->qwc; + //u32 chcr = ipu0dma->chcr; + + if( !(ipu0dma->chcr & 0x100) || (cpuRegs.interrupt & (1<qwc == 0) + return 0; + + assert( !(ipu0dma->chcr&0x40) ); + + IPU_LOG("dmaIPU0 chcr = %lx, madr = %lx, qwc = %lx\n", + ipu0dma->chcr, ipu0dma->madr, ipu0dma->qwc); + + assert((ipu0dma->chcr & 0xC) == 0 ); + pMem = (u32*)dmaGetAddr(ipu0dma->madr); + readsize = min(ipu0dma->qwc, (u16)ipuRegs->ctrl.OFC); + FIFOfrom_read(pMem,readsize); + ipu0dma->madr += readsize<< 4; + ipu0dma->qwc -= readsize; // note: qwc is u16 + if(ipu0dma->qwc == 0) { + if ((psHu32(DMAC_CTRL) & 0x30) == 0x30) { // STS == fromIPU + psHu32(DMAC_STADR) = ipu0dma->madr; + switch (psHu32(DMAC_CTRL) & 0xC0) { + case 0x80: // GIF + g_nDMATransfer |= IPU_DMA_GIFSTALL; + break; + case 0x40: // VIF + g_nDMATransfer |= IPU_DMA_VIFSTALL; + break; + } + } + IPU_INT_FROM( readsize*BIAS ); + } + + return readsize; +} + +void dmaIPU0() // fromIPU +{ + if( ipuRegs->ctrl.BUSY ) + IPUWorker(); +} + +void dmaIPU1() // toIPU +{ + //g_nDMATransfer &= ~(IPU_DMA_ACTV1|IPU_DMA_DOTIE1); + IPU1dma(); + if( ipuRegs->ctrl.BUSY ) + IPUWorker(); +} + +extern void GIFdma(); + +void ipu0Interrupt() { + IPU_LOG("ipu0Interrupt: %x\n", cpuRegs.cycle); + + if( g_nDMATransfer & IPU_DMA_FIREINT0 ) { + hwIntcIrq(INTC_IPU); + g_nDMATransfer &= ~IPU_DMA_FIREINT0; + } + + if( g_nDMATransfer & IPU_DMA_GIFSTALL ) { + // gif + g_nDMATransfer &= ~IPU_DMA_GIFSTALL; + if(((DMACh*)&PS2MEM_HW[0xA000])->chcr & 0x100) GIFdma(); + } + + if( g_nDMATransfer & IPU_DMA_VIFSTALL ) { + // vif + g_nDMATransfer &= ~IPU_DMA_VIFSTALL; + if(((DMACh*)&PS2MEM_HW[0x9000])->chcr & 0x100)dmaVIF1(); + } + + if( g_nDMATransfer & IPU_DMA_TIE0 ) { + g_nDMATransfer &= ~IPU_DMA_TIE0; + } + + ipu0dma->chcr &= ~0x100; + + hwDmacIrq(DMAC_FROM_IPU); +} + +IPU_FORCEINLINE void ipu1Interrupt() { + IPU_LOG("ipu1Interrupt %x:\n", cpuRegs.cycle); + + if( g_nDMATransfer & IPU_DMA_FIREINT1 ) { + hwIntcIrq(INTC_IPU); + g_nDMATransfer &= ~IPU_DMA_FIREINT1; + } + + if( g_nDMATransfer & IPU_DMA_TIE1 ) { + g_nDMATransfer &= ~IPU_DMA_TIE1; + }else + ipu1dma->chcr &= ~0x100; + + hwDmacIrq(DMAC_TO_IPU); +} diff --git a/pcsx2/IPU/IPU.h b/pcsx2/IPU/IPU.h index acb0f36c88..8bf5774e15 100644 --- a/pcsx2/IPU/IPU.h +++ b/pcsx2/IPU/IPU.h @@ -1,265 +1,265 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __IPU_H__ -#define __IPU_H__ - -// IPU_INLINE_IRQS -// Scheduling ints into the future is a purist approach to emulation, and -// is mostly cosmetic since the emulator itself performs all actions instantly -// (as far as the emulated CPU is concerned). In some cases this can actually -// cause more sync problems than it supposedly solves, due to accumulated -// delays incurred by the recompiler's low cycle update rate and also Pcsx2 -// failing to properly handle pre-emptive DMA/IRQs or cpu exceptions. - -// Uncomment the following line to enable inline IRQs for the IPU. Tests show -// that it doesn't have any effect on compatibility or audio/video sync, and it -// speeds up movie playback by some 6-8%. But it lacks the purist touch, so it's -// not enabled by default. - -//#define IPU_INLINE_IRQS - - -#ifdef _MSC_VER -#pragma pack(1) -#endif - -// -// Bitfield Structure -// -union tIPU_CMD { - struct { - u32 OPTION : 28; // VDEC decoded value - u32 CMD : 4; // last command - u32 _BUSY; - }; - struct { - u32 DATA; - u32 BUSY; - }; -}; - -#define IPU_CTRL_IFC_M (0x0f<< 0) -#define IPU_CTRL_OFC_M (0x0f<< 4) -#define IPU_CTRL_CBP_M (0x3f<< 8) -#define IPU_CTRL_ECD_M (0x01<<14) -#define IPU_CTRL_SCD_M (0x01<<15) -#define IPU_CTRL_IDP_M (0x03<<16) -#define IPU_CTRL_AS_M (0x01<<20) -#define IPU_CTRL_IVF_M (0x01<<21) -#define IPU_CTRL_QST_M (0x01<<22) -#define IPU_CTRL_MP1_M (0x01<<23) -#define IPU_CTRL_PCT_M (0x07<<24) -#define IPU_CTRL_RST_M (0x01<<30) -#define IPU_CTRL_BUSY_M (0x01<<31) - -#define IPU_CTRL_IFC_O ( 0) -#define IPU_CTRL_OFC_O ( 4) -#define IPU_CTRL_CBP_O ( 8) -#define IPU_CTRL_ECD_O (14) -#define IPU_CTRL_SCD_O (15) -#define IPU_CTRL_IDP_O (16) -#define IPU_CTRL_AS_O (20) -#define IPU_CTRL_IVF_O (21) -#define IPU_CTRL_QST_O (22) -#define IPU_CTRL_MP1_O (23) -#define IPU_CTRL_PCT_O (24) -#define IPU_CTRL_RST_O (30) -#define IPU_CTRL_BUSY_O (31) - - -// -// Bitfield Structure -// -union tIPU_CTRL { - struct { - u32 IFC : 4; // Input FIFO counter - u32 OFC : 4; // Output FIFO counter - u32 CBP : 6; // Coded block pattern - u32 ECD : 1; // Error code pattern - u32 SCD : 1; // Start code detected - u32 IDP : 2; // Intra DC precision - u32 resv0 : 2; - u32 AS : 1; // Alternate scan - u32 IVF : 1; // Intra VLC format - u32 QST : 1; // Q scale step - u32 MP1 : 1; // MPEG1 bit strea - u32 PCT : 3; // Picture Type - u32 resv1 : 3; - u32 RST : 1; // Reset - u32 BUSY : 1; // Busy - }; - u32 _u32; -}; - -#define IPU_BP_BP_M (0x7f<< 0) -#define IPU_BP_IFC_M (0x0f<< 8) -#define IPU_BP_FP_M (0x03<<16) - -#define IPU_BP_BP_O ( 0) -#define IPU_BP_IFC_O ( 8) -#define IPU_BP_FP_O (16) - - -// -// Bitfield Structure -// -struct tIPU_BP { - u32 BP; // Bit stream point - u16 IFC; // Input FIFO counter - u8 FP; // FIFO point - u8 bufferhasnew; -}; - -#ifdef _WIN32 -#pragma pack() -#endif - -union tIPU_CMD_IDEC -{ - struct - { - u32 FB : 6; - u32 UN2 :10; - u32 QSC : 5; - u32 UN1 : 3; - u32 DTD : 1; - u32 SGN : 1; - u32 DTE : 1; - u32 OFM : 1; - u32 cmd : 4; - }; - - u32 value; - - tIPU_CMD_IDEC( u32 val ) : value( val ) - { - } -}; - -union tIPU_CMD_BDEC -{ - struct - { - u32 FB : 6; - u32 UN2 :10; - u32 QSC : 5; - u32 UN1 : 4; - u32 DT : 1; - u32 DCR : 1; - u32 MBI : 1; - u32 cmd : 4; - }; - u32 value; - - tIPU_CMD_BDEC( u32 val ) : value( val ) - { - } -}; - -union tIPU_CMD_CSC -{ - struct - { - u32 MBC :11; - u32 UN2 :15; - u32 DTE : 1; - u32 OFM : 1; - u32 cmd : 4; - }; - u32 value; - - tIPU_CMD_CSC( u32 val ) : value( val ) - { - } -}; - -enum SCE_IPU -{ - SCE_IPU_BCLR = 0x0 -, SCE_IPU_IDEC -, SCE_IPU_BDEC -, SCE_IPU_VDEC -, SCE_IPU_FDEC -, SCE_IPU_SETIQ -, SCE_IPU_SETVQ -, SCE_IPU_CSC -, SCE_IPU_PACK -, SCE_IPU_SETTH -}; - -struct IPUregisters { - tIPU_CMD cmd; - u32 dummy0[2]; - tIPU_CTRL ctrl; - u32 dummy1[3]; - u32 ipubp; - u32 dummy2[3]; - u32 top; - u32 topbusy; - u32 dummy3[2]; -}; - -#define ipuRegs ((IPUregisters*)(PS2MEM_HW+0x2000)) - -extern tIPU_BP g_BP; -extern int coded_block_pattern; -extern int g_nIPU0Data; // or 0x80000000 whenever transferring -extern u8* g_pIPU0Pointer; - - -void dmaIPU0(); -void dmaIPU1(); - -int ipuInit(); -void ipuReset(); -void ipuShutdown(); -int ipuFreeze(gzFile f, int Mode); -bool ipuCanFreeze(); - - -extern u32 ipuRead32(u32 mem); -extern u64 ipuRead64(u32 mem); -extern void ipuWrite32(u32 mem,u32 value); -extern void ipuWrite64(u32 mem,u64 value); - -int ipuConstRead32(u32 x86reg, u32 mem); -void ipuConstRead64(u32 mem, int mmreg); -void ipuConstWrite32(u32 mem, int mmreg); -void ipuConstWrite64(u32 mem, int mmreg); - -extern void IPUCMD_WRITE(u32 val); -extern void ipuSoftReset(); -extern void IPUProcessInterrupt(); -extern void ipu0Interrupt(); -extern void ipu1Interrupt(); - -extern u16 __fastcall FillInternalBuffer(u32 * pointer, u32 advance, u32 size); -extern u8 __fastcall getBits32(u8 *address, u32 advance); -extern u8 __fastcall getBits16(u8 *address, u32 advance); -extern u8 __fastcall getBits8(u8 *address, u32 advance); -extern int __fastcall getBits(u8 *address, u32 size, u32 advance); - -// returns number of qw read -int FIFOfrom_write(u32 * value, int size); -void FIFOfrom_read(void *value,int size); -int FIFOto_read(void *value); -int FIFOto_write(u32* pMem, int size); -void FIFOto_clear(); - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __IPU_H__ +#define __IPU_H__ + +// IPU_INLINE_IRQS +// Scheduling ints into the future is a purist approach to emulation, and +// is mostly cosmetic since the emulator itself performs all actions instantly +// (as far as the emulated CPU is concerned). In some cases this can actually +// cause more sync problems than it supposedly solves, due to accumulated +// delays incurred by the recompiler's low cycle update rate and also Pcsx2 +// failing to properly handle pre-emptive DMA/IRQs or cpu exceptions. + +// Uncomment the following line to enable inline IRQs for the IPU. Tests show +// that it doesn't have any effect on compatibility or audio/video sync, and it +// speeds up movie playback by some 6-8%. But it lacks the purist touch, so it's +// not enabled by default. + +//#define IPU_INLINE_IRQS + + +#ifdef _MSC_VER +#pragma pack(1) +#endif + +// +// Bitfield Structure +// +union tIPU_CMD { + struct { + u32 OPTION : 28; // VDEC decoded value + u32 CMD : 4; // last command + u32 _BUSY; + }; + struct { + u32 DATA; + u32 BUSY; + }; +}; + +#define IPU_CTRL_IFC_M (0x0f<< 0) +#define IPU_CTRL_OFC_M (0x0f<< 4) +#define IPU_CTRL_CBP_M (0x3f<< 8) +#define IPU_CTRL_ECD_M (0x01<<14) +#define IPU_CTRL_SCD_M (0x01<<15) +#define IPU_CTRL_IDP_M (0x03<<16) +#define IPU_CTRL_AS_M (0x01<<20) +#define IPU_CTRL_IVF_M (0x01<<21) +#define IPU_CTRL_QST_M (0x01<<22) +#define IPU_CTRL_MP1_M (0x01<<23) +#define IPU_CTRL_PCT_M (0x07<<24) +#define IPU_CTRL_RST_M (0x01<<30) +#define IPU_CTRL_BUSY_M (0x01<<31) + +#define IPU_CTRL_IFC_O ( 0) +#define IPU_CTRL_OFC_O ( 4) +#define IPU_CTRL_CBP_O ( 8) +#define IPU_CTRL_ECD_O (14) +#define IPU_CTRL_SCD_O (15) +#define IPU_CTRL_IDP_O (16) +#define IPU_CTRL_AS_O (20) +#define IPU_CTRL_IVF_O (21) +#define IPU_CTRL_QST_O (22) +#define IPU_CTRL_MP1_O (23) +#define IPU_CTRL_PCT_O (24) +#define IPU_CTRL_RST_O (30) +#define IPU_CTRL_BUSY_O (31) + + +// +// Bitfield Structure +// +union tIPU_CTRL { + struct { + u32 IFC : 4; // Input FIFO counter + u32 OFC : 4; // Output FIFO counter + u32 CBP : 6; // Coded block pattern + u32 ECD : 1; // Error code pattern + u32 SCD : 1; // Start code detected + u32 IDP : 2; // Intra DC precision + u32 resv0 : 2; + u32 AS : 1; // Alternate scan + u32 IVF : 1; // Intra VLC format + u32 QST : 1; // Q scale step + u32 MP1 : 1; // MPEG1 bit strea + u32 PCT : 3; // Picture Type + u32 resv1 : 3; + u32 RST : 1; // Reset + u32 BUSY : 1; // Busy + }; + u32 _u32; +}; + +#define IPU_BP_BP_M (0x7f<< 0) +#define IPU_BP_IFC_M (0x0f<< 8) +#define IPU_BP_FP_M (0x03<<16) + +#define IPU_BP_BP_O ( 0) +#define IPU_BP_IFC_O ( 8) +#define IPU_BP_FP_O (16) + + +// +// Bitfield Structure +// +struct tIPU_BP { + u32 BP; // Bit stream point + u16 IFC; // Input FIFO counter + u8 FP; // FIFO point + u8 bufferhasnew; +}; + +#ifdef _WIN32 +#pragma pack() +#endif + +union tIPU_CMD_IDEC +{ + struct + { + u32 FB : 6; + u32 UN2 :10; + u32 QSC : 5; + u32 UN1 : 3; + u32 DTD : 1; + u32 SGN : 1; + u32 DTE : 1; + u32 OFM : 1; + u32 cmd : 4; + }; + + u32 value; + + tIPU_CMD_IDEC( u32 val ) : value( val ) + { + } +}; + +union tIPU_CMD_BDEC +{ + struct + { + u32 FB : 6; + u32 UN2 :10; + u32 QSC : 5; + u32 UN1 : 4; + u32 DT : 1; + u32 DCR : 1; + u32 MBI : 1; + u32 cmd : 4; + }; + u32 value; + + tIPU_CMD_BDEC( u32 val ) : value( val ) + { + } +}; + +union tIPU_CMD_CSC +{ + struct + { + u32 MBC :11; + u32 UN2 :15; + u32 DTE : 1; + u32 OFM : 1; + u32 cmd : 4; + }; + u32 value; + + tIPU_CMD_CSC( u32 val ) : value( val ) + { + } +}; + +enum SCE_IPU +{ + SCE_IPU_BCLR = 0x0 +, SCE_IPU_IDEC +, SCE_IPU_BDEC +, SCE_IPU_VDEC +, SCE_IPU_FDEC +, SCE_IPU_SETIQ +, SCE_IPU_SETVQ +, SCE_IPU_CSC +, SCE_IPU_PACK +, SCE_IPU_SETTH +}; + +struct IPUregisters { + tIPU_CMD cmd; + u32 dummy0[2]; + tIPU_CTRL ctrl; + u32 dummy1[3]; + u32 ipubp; + u32 dummy2[3]; + u32 top; + u32 topbusy; + u32 dummy3[2]; +}; + +#define ipuRegs ((IPUregisters*)(PS2MEM_HW+0x2000)) + +extern tIPU_BP g_BP; +extern int coded_block_pattern; +extern int g_nIPU0Data; // or 0x80000000 whenever transferring +extern u8* g_pIPU0Pointer; + + +void dmaIPU0(); +void dmaIPU1(); + +int ipuInit(); +void ipuReset(); +void ipuShutdown(); +int ipuFreeze(gzFile f, int Mode); +bool ipuCanFreeze(); + + +extern u32 ipuRead32(u32 mem); +extern u64 ipuRead64(u32 mem); +extern void ipuWrite32(u32 mem,u32 value); +extern void ipuWrite64(u32 mem,u64 value); + +int ipuConstRead32(u32 x86reg, u32 mem); +void ipuConstRead64(u32 mem, int mmreg); +void ipuConstWrite32(u32 mem, int mmreg); +void ipuConstWrite64(u32 mem, int mmreg); + +extern void IPUCMD_WRITE(u32 val); +extern void ipuSoftReset(); +extern void IPUProcessInterrupt(); +extern void ipu0Interrupt(); +extern void ipu1Interrupt(); + +extern u16 __fastcall FillInternalBuffer(u32 * pointer, u32 advance, u32 size); +extern u8 __fastcall getBits32(u8 *address, u32 advance); +extern u8 __fastcall getBits16(u8 *address, u32 advance); +extern u8 __fastcall getBits8(u8 *address, u32 advance); +extern int __fastcall getBits(u8 *address, u32 size, u32 advance); + +// returns number of qw read +int FIFOfrom_write(u32 * value, int size); +void FIFOfrom_read(void *value,int size); +int FIFOto_read(void *value); +int FIFOto_write(u32* pMem, int size); +void FIFOto_clear(); + +#endif diff --git a/pcsx2/IPU/coroutine.cpp b/pcsx2/IPU/coroutine.cpp index aeb290b1ff..229c6aa24d 100644 --- a/pcsx2/IPU/coroutine.cpp +++ b/pcsx2/IPU/coroutine.cpp @@ -1,158 +1,158 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "coroutine.h" - -struct coroutine { - void* pcalladdr; - void *pcurstack; - - uptr storeebx, storeesi, storeedi, storeebp; - - int restore; // if nonzero, restore the registers - int alloc; - //struct s_coroutine *caller; - //struct s_coroutine *restarget; - -}; - -#define CO_STK_ALIGN 256 -#define CO_STK_COROSIZE ((sizeof(coroutine) + CO_STK_ALIGN - 1) & ~(CO_STK_ALIGN - 1)) -#define CO_MIN_SIZE (4 * 1024) - -coroutine* g_pCurrentRoutine; - -coroutine_t so_create(void (*func)(void *), void *data, void *stack, int size) -{ - void* endstack; - int alloc = 0; // r = CO_STK_COROSIZE; - coroutine *co; - - if ((size &= ~(sizeof(long) - 1)) < CO_MIN_SIZE) - return NULL; - if (!stack) { - size = (size + sizeof(coroutine) + CO_STK_ALIGN - 1) & ~(CO_STK_ALIGN - 1); - stack = malloc(size); - if (!stack) - return NULL; - alloc = size; - } - endstack = (char*)stack + size - 64; - co = (coroutine*)stack; - stack = (char *) stack + CO_STK_COROSIZE; - *(void**)endstack = NULL; - *(void**)((char*)endstack+sizeof(void*)) = data; - co->alloc = alloc; - co->pcalladdr = (void*)func; - co->pcurstack = endstack; - return co; -} - -void so_delete(coroutine_t coro) -{ - coroutine *co = (coroutine *) coro; - assert( co != NULL ); - if (co->alloc) - free(co); -} - -// see acoroutines.S and acoroutines.asm for other asm implementations -#if defined(_MSC_VER) - -__declspec(naked) void so_call(coroutine_t coro) -{ - __asm { - mov eax, dword ptr [esp+4] - test dword ptr [eax+24], 1 - jnz RestoreRegs - mov [eax+8], ebx - mov [eax+12], esi - mov [eax+16], edi - mov [eax+20], ebp - mov dword ptr [eax+24], 1 - jmp CallFn -RestoreRegs: - // have to load and save at the same time - mov ecx, [eax+8] - mov edx, [eax+12] - mov [eax+8], ebx - mov [eax+12], esi - mov ebx, ecx - mov esi, edx - mov ecx, [eax+16] - mov edx, [eax+20] - mov [eax+16], edi - mov [eax+20], ebp - mov edi, ecx - mov ebp, edx - -CallFn: - mov [g_pCurrentRoutine], eax - mov ecx, esp - mov esp, [eax+4] - mov [eax+4], ecx - - jmp dword ptr [eax] - } -} - -__declspec(naked) void so_resume(void) -{ - __asm { - mov eax, [g_pCurrentRoutine] - mov ecx, [eax+8] - mov edx, [eax+12] - mov [eax+8], ebx - mov [eax+12], esi - mov ebx, ecx - mov esi, edx - mov ecx, [eax+16] - mov edx, [eax+20] - mov [eax+16], edi - mov [eax+20], ebp - mov edi, ecx - mov ebp, edx - - // put the return address in pcalladdr - mov ecx, [esp] - mov [eax], ecx - add esp, 4 // remove the return address - - // swap stack pointers - mov ecx, [eax+4] - mov [eax+4], esp - mov esp, ecx - ret - } -} - -__declspec(naked) void so_exit(void) -{ - __asm { - mov eax, [g_pCurrentRoutine] - mov esp, [eax+4] - mov ebx, [eax+8] - mov esi, [eax+12] - mov edi, [eax+16] - mov ebp, [eax+20] - ret - } -} -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "coroutine.h" + +struct coroutine { + void* pcalladdr; + void *pcurstack; + + uptr storeebx, storeesi, storeedi, storeebp; + + int restore; // if nonzero, restore the registers + int alloc; + //struct s_coroutine *caller; + //struct s_coroutine *restarget; + +}; + +#define CO_STK_ALIGN 256 +#define CO_STK_COROSIZE ((sizeof(coroutine) + CO_STK_ALIGN - 1) & ~(CO_STK_ALIGN - 1)) +#define CO_MIN_SIZE (4 * 1024) + +coroutine* g_pCurrentRoutine; + +coroutine_t so_create(void (*func)(void *), void *data, void *stack, int size) +{ + void* endstack; + int alloc = 0; // r = CO_STK_COROSIZE; + coroutine *co; + + if ((size &= ~(sizeof(long) - 1)) < CO_MIN_SIZE) + return NULL; + if (!stack) { + size = (size + sizeof(coroutine) + CO_STK_ALIGN - 1) & ~(CO_STK_ALIGN - 1); + stack = malloc(size); + if (!stack) + return NULL; + alloc = size; + } + endstack = (char*)stack + size - 64; + co = (coroutine*)stack; + stack = (char *) stack + CO_STK_COROSIZE; + *(void**)endstack = NULL; + *(void**)((char*)endstack+sizeof(void*)) = data; + co->alloc = alloc; + co->pcalladdr = (void*)func; + co->pcurstack = endstack; + return co; +} + +void so_delete(coroutine_t coro) +{ + coroutine *co = (coroutine *) coro; + assert( co != NULL ); + if (co->alloc) + free(co); +} + +// see acoroutines.S and acoroutines.asm for other asm implementations +#if defined(_MSC_VER) + +__declspec(naked) void so_call(coroutine_t coro) +{ + __asm { + mov eax, dword ptr [esp+4] + test dword ptr [eax+24], 1 + jnz RestoreRegs + mov [eax+8], ebx + mov [eax+12], esi + mov [eax+16], edi + mov [eax+20], ebp + mov dword ptr [eax+24], 1 + jmp CallFn +RestoreRegs: + // have to load and save at the same time + mov ecx, [eax+8] + mov edx, [eax+12] + mov [eax+8], ebx + mov [eax+12], esi + mov ebx, ecx + mov esi, edx + mov ecx, [eax+16] + mov edx, [eax+20] + mov [eax+16], edi + mov [eax+20], ebp + mov edi, ecx + mov ebp, edx + +CallFn: + mov [g_pCurrentRoutine], eax + mov ecx, esp + mov esp, [eax+4] + mov [eax+4], ecx + + jmp dword ptr [eax] + } +} + +__declspec(naked) void so_resume(void) +{ + __asm { + mov eax, [g_pCurrentRoutine] + mov ecx, [eax+8] + mov edx, [eax+12] + mov [eax+8], ebx + mov [eax+12], esi + mov ebx, ecx + mov esi, edx + mov ecx, [eax+16] + mov edx, [eax+20] + mov [eax+16], edi + mov [eax+20], ebp + mov edi, ecx + mov ebp, edx + + // put the return address in pcalladdr + mov ecx, [esp] + mov [eax], ecx + add esp, 4 // remove the return address + + // swap stack pointers + mov ecx, [eax+4] + mov [eax+4], esp + mov esp, ecx + ret + } +} + +__declspec(naked) void so_exit(void) +{ + __asm { + mov eax, [g_pCurrentRoutine] + mov esp, [eax+4] + mov ebx, [eax+8] + mov esi, [eax+12] + mov edi, [eax+16] + mov ebp, [eax+20] + ret + } +} +#endif diff --git a/pcsx2/IPU/coroutine.h b/pcsx2/IPU/coroutine.h index e9edfd956f..59b8c91a0d 100644 --- a/pcsx2/IPU/coroutine.h +++ b/pcsx2/IPU/coroutine.h @@ -1,37 +1,37 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef PCSX2_COROUTINE_LIB -#define PCSX2_COROUTINE_LIB - -// low level coroutine library -typedef void *coroutine_t; - -coroutine_t so_create(void (*func)(void *), void *data, void *stack, int size); -void so_delete(coroutine_t coro); - -#ifdef __LINUX__ -extern "C" { -#endif -void so_call(coroutine_t coro); -void so_resume(void); -void so_exit(void); -#ifdef __LINUX__ -} -#endif -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef PCSX2_COROUTINE_LIB +#define PCSX2_COROUTINE_LIB + +// low level coroutine library +typedef void *coroutine_t; + +coroutine_t so_create(void (*func)(void *), void *data, void *stack, int size); +void so_delete(coroutine_t coro); + +#ifdef __LINUX__ +extern "C" { +#endif +void so_call(coroutine_t coro); +void so_resume(void); +void so_exit(void); +#ifdef __LINUX__ +} +#endif +#endif diff --git a/pcsx2/IPU/mpeg2lib/Idct.cpp b/pcsx2/IPU/mpeg2lib/Idct.cpp index a285e74ad0..35d8380689 100644 --- a/pcsx2/IPU/mpeg2lib/Idct.cpp +++ b/pcsx2/IPU/mpeg2lib/Idct.cpp @@ -1,307 +1,307 @@ -/* - * idct.c - * Copyright (C) 2000-2002 Michel Lespinasse - * Copyright (C) 1999-2000 Aaron Holtzman - * Modified by Florin for PCSX2 emu - * - * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. - * See http://libmpeg2.sourceforge.net/ for updates. - * - * mpeg2dec 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. - * - * mpeg2dec 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "IPU.h" - -#define W1 2841 /* 2048*sqrt (2)*cos (1*pi/16) */ -#define W2 2676 /* 2048*sqrt (2)*cos (2*pi/16) */ -#define W3 2408 /* 2048*sqrt (2)*cos (3*pi/16) */ -#define W5 1609 /* 2048*sqrt (2)*cos (5*pi/16) */ -#define W6 1108 /* 2048*sqrt (2)*cos (6*pi/16) */ -#define W7 565 /* 2048*sqrt (2)*cos (7*pi/16) */ -#define clp(val,res) res = (val < 0) ? 0 : ((val > 255) ? 255 : val); -#define clp2(val,res) res = (val < -255) ? -255 : ((val > 255) ? 255 : val); - -/* idct main entry point */ -void (__fastcall *mpeg2_idct_copy) (s16 * block, u8 * dest, int stride); -/* JayteeMaster: changed dest to 16 bit signed */ -void (__fastcall *mpeg2_idct_add) (int last, s16 * block, - /*u8*/s16 * dest, int stride); - -/* - * In legal streams, the IDCT output should be between -384 and +384. - * In corrupted streams, it is possible to force the IDCT output to go - * to +-3826 - this is the worst case for a column IDCT where the - * column inputs are 16-bit values. - */ -static u8 clip_lut[1024]; -#define CLIP(i) ((clip_lut+384)[(i)]) - -#if 0 -#define BUTTERFLY(t0,t1,W0,W1,d0,d1) \ -do { \ - t0 = W0*d0 + W1*d1; \ - t1 = W0*d1 - W1*d0; \ -} while (0) -#else -#define BUTTERFLY(t0,t1,W0,W1,d0,d1) \ -do { \ - int tmp = W0 * (d0 + d1); \ - t0 = tmp + (W1 - W0) * d1; \ - t1 = tmp - (W1 + W0) * d0; \ -} while (0) -#endif - -static __forceinline void idct_row (s16 * const block) -{ - int d0, d1, d2, d3; - int a0, a1, a2, a3, b0, b1, b2, b3; - int t0, t1, t2, t3; - - /* shortcut */ - if (!(block[1] | ((s32 *)block)[1] | ((s32 *)block)[2] | - ((s32 *)block)[3])) { - u32 tmp = (u16) (block[0] << 3); - tmp |= tmp << 16; - ((s32 *)block)[0] = tmp; - ((s32 *)block)[1] = tmp; - ((s32 *)block)[2] = tmp; - ((s32 *)block)[3] = tmp; - return; - } - - d0 = (block[0] << 11) + 128; - d1 = block[1]; - d2 = block[2] << 11; - d3 = block[3]; - t0 = d0 + d2; - t1 = d0 - d2; - BUTTERFLY (t2, t3, W6, W2, d3, d1); - a0 = t0 + t2; - a1 = t1 + t3; - a2 = t1 - t3; - a3 = t0 - t2; - - d0 = block[4]; - d1 = block[5]; - d2 = block[6]; - d3 = block[7]; - BUTTERFLY (t0, t1, W7, W1, d3, d0); - BUTTERFLY (t2, t3, W3, W5, d1, d2); - b0 = t0 + t2; - b3 = t1 + t3; - t0 -= t2; - t1 -= t3; - b1 = ((t0 + t1) * 181) >> 8; - b2 = ((t0 - t1) * 181) >> 8; - - block[0] = (a0 + b0) >> 8; - block[1] = (a1 + b1) >> 8; - block[2] = (a2 + b2) >> 8; - block[3] = (a3 + b3) >> 8; - block[4] = (a3 - b3) >> 8; - block[5] = (a2 - b2) >> 8; - block[6] = (a1 - b1) >> 8; - block[7] = (a0 - b0) >> 8; -} - -static __forceinline void idct_col (s16 * const block) -{ - int d0, d1, d2, d3; - int a0, a1, a2, a3, b0, b1, b2, b3; - int t0, t1, t2, t3; - - d0 = (block[8*0] << 11) + 65536; - d1 = block[8*1]; - d2 = block[8*2] << 11; - d3 = block[8*3]; - t0 = d0 + d2; - t1 = d0 - d2; - BUTTERFLY (t2, t3, W6, W2, d3, d1); - a0 = t0 + t2; - a1 = t1 + t3; - a2 = t1 - t3; - a3 = t0 - t2; - - d0 = block[8*4]; - d1 = block[8*5]; - d2 = block[8*6]; - d3 = block[8*7]; - BUTTERFLY (t0, t1, W7, W1, d3, d0); - BUTTERFLY (t2, t3, W3, W5, d1, d2); - b0 = t0 + t2; - b3 = t1 + t3; - t0 = (t0 - t2) >> 8; - t1 = (t1 - t3) >> 8; - b1 = (t0 + t1) * 181; - b2 = (t0 - t1) * 181; - - block[8*0] = (a0 + b0) >> 17; - block[8*1] = (a1 + b1) >> 17; - block[8*2] = (a2 + b2) >> 17; - block[8*3] = (a3 + b3) >> 17; - block[8*4] = (a3 - b3) >> 17; - block[8*5] = (a2 - b2) >> 17; - block[8*6] = (a1 - b1) >> 17; - block[8*7] = (a0 - b0) >> 17; -} - -static void __fastcall mpeg2_idct_copy_c (s16 * block, u8 * dest, - const int stride) -{ - int i; - - for (i = 0; i < 8; i++) - idct_row (block + 8 * i); - for (i = 0; i < 8; i++) - idct_col (block + i); - do { - dest[0] = CLIP (block[0]); - dest[1] = CLIP (block[1]); - dest[2] = CLIP (block[2]); - dest[3] = CLIP (block[3]); - dest[4] = CLIP (block[4]); - dest[5] = CLIP (block[5]); - dest[6] = CLIP (block[6]); - dest[7] = CLIP (block[7]); - - block[0] = 0; block[1] = 0; block[2] = 0; block[3] = 0; - block[4] = 0; block[5] = 0; block[6] = 0; block[7] = 0; - - dest += stride; - block += 8; - } while (--i); -} - -/* JayteeMaster: changed dest to 16 bit signed */ -static void __fastcall mpeg2_idct_add_c (const int last, s16 * block, - /*u8*/s16 * dest, const int stride) -{ - int i; - - if (last != 129 || (block[0] & 7) == 4) { - for (i = 0; i < 8; i++) - idct_row (block + 8 * i); - for (i = 0; i < 8; i++) - idct_col (block + i); - do { - dest[0] = block[0]; - dest[1] = block[1]; - dest[2] = block[2]; - dest[3] = block[3]; - dest[4] = block[4]; - dest[5] = block[5]; - dest[6] = block[6]; - dest[7] = block[7]; - - block[0] = 0; block[1] = 0; block[2] = 0; block[3] = 0; - block[4] = 0; block[5] = 0; block[6] = 0; block[7] = 0; - - dest += stride; - block += 8; - } while (--i); - } else { - int DC; - - DC = (block[0] + 4) >> 3; - block[0] = block[63] = 0; - i = 8; - do { - dest[0] = DC; - dest[1] = DC; - dest[2] = DC; - dest[3] = DC; - dest[4] = DC; - dest[5] = DC; - dest[6] = DC; - dest[7] = DC; - dest += stride; - } while (--i); - } -} - -extern "C" -{ -u8 mpeg2_scan_norm[64] = { - /* Zig-Zag scan pattern */ - 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 -}; - -u8 mpeg2_scan_alt[64] = { - /* Alternate scan pattern */ - 0, 8, 16, 24, 1, 9, 2, 10, 17, 25, 32, 40, 48, 56, 57, 49, - 41, 33, 26, 18, 3, 11, 4, 12, 19, 27, 34, 42, 50, 58, 35, 43, - 51, 59, 20, 28, 5, 13, 6, 14, 21, 29, 36, 44, 52, 60, 37, 45, - 53, 61, 22, 30, 7, 15, 23, 31, 38, 46, 54, 62, 39, 47, 55, 63 -}; -}; - -/* idct_mmx.c */ -void mpeg2_idct_copy_mmxext (s16 * block, u8 * dest, int stride); -void mpeg2_idct_add_mmxext (int last, s16 * block, - s16 * dest, int stride); -void mpeg2_idct_copy_mmx (s16 * block, u8 * dest, int stride); -void mpeg2_idct_add_mmx (int last, s16 * block, - s16 * dest, int stride); -void mpeg2_idct_mmx_init (void); - -void mpeg2_idct_init() -{ -#if !defined(_MSC_VER) || _MSC_VER < 1400 // ignore vc2005 and beyond - int i, j; - -/* if(hasMultimediaExtensions == 1) - { - mpeg2_idct_copy = mpeg2_idct_copy_mmx; - mpeg2_idct_add = mpeg2_idct_add_mmx; - mpeg2_idct_mmx_init (); - }else if(hasMultimediaExtensionsExt == 1) - { - mpeg2_idct_copy = mpeg2_idct_copy_mmxext; - mpeg2_idct_add = mpeg2_idct_add_mmxext; - mpeg2_idct_mmx_init (); - }else*/ - { - mpeg2_idct_copy = mpeg2_idct_copy_c; - mpeg2_idct_add = mpeg2_idct_add_c; - for (i = -384; i < 640; i++) - clip_lut[i+384] = (i < 0) ? 0 : ((i > 255) ? 255 : i); - for (i = 0; i < 64; i++) { - j = mpeg2_scan_norm[i]; - mpeg2_scan_norm[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); - j = mpeg2_scan_alt[i]; - mpeg2_scan_alt[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); - } - } - -#else //blah vcnet2005 idiocity :D - int i,j; - mpeg2_idct_copy = mpeg2_idct_copy_c; - mpeg2_idct_add = mpeg2_idct_add_c; - for (i = -384; i < 640; i++) - clip_lut[i+384] = (i < 0) ? 0 : ((i > 255) ? 255 : i); - for (i = 0; i < 64; i++) { - j = mpeg2_scan_norm[i]; - mpeg2_scan_norm[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); - j = mpeg2_scan_alt[i]; - mpeg2_scan_alt[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); - } -#endif -} +/* + * idct.c + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * Modified by Florin for PCSX2 emu + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * See http://libmpeg2.sourceforge.net/ for updates. + * + * mpeg2dec 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. + * + * mpeg2dec 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "IPU.h" + +#define W1 2841 /* 2048*sqrt (2)*cos (1*pi/16) */ +#define W2 2676 /* 2048*sqrt (2)*cos (2*pi/16) */ +#define W3 2408 /* 2048*sqrt (2)*cos (3*pi/16) */ +#define W5 1609 /* 2048*sqrt (2)*cos (5*pi/16) */ +#define W6 1108 /* 2048*sqrt (2)*cos (6*pi/16) */ +#define W7 565 /* 2048*sqrt (2)*cos (7*pi/16) */ +#define clp(val,res) res = (val < 0) ? 0 : ((val > 255) ? 255 : val); +#define clp2(val,res) res = (val < -255) ? -255 : ((val > 255) ? 255 : val); + +/* idct main entry point */ +void (__fastcall *mpeg2_idct_copy) (s16 * block, u8 * dest, int stride); +/* JayteeMaster: changed dest to 16 bit signed */ +void (__fastcall *mpeg2_idct_add) (int last, s16 * block, + /*u8*/s16 * dest, int stride); + +/* + * In legal streams, the IDCT output should be between -384 and +384. + * In corrupted streams, it is possible to force the IDCT output to go + * to +-3826 - this is the worst case for a column IDCT where the + * column inputs are 16-bit values. + */ +static u8 clip_lut[1024]; +#define CLIP(i) ((clip_lut+384)[(i)]) + +#if 0 +#define BUTTERFLY(t0,t1,W0,W1,d0,d1) \ +do { \ + t0 = W0*d0 + W1*d1; \ + t1 = W0*d1 - W1*d0; \ +} while (0) +#else +#define BUTTERFLY(t0,t1,W0,W1,d0,d1) \ +do { \ + int tmp = W0 * (d0 + d1); \ + t0 = tmp + (W1 - W0) * d1; \ + t1 = tmp - (W1 + W0) * d0; \ +} while (0) +#endif + +static __forceinline void idct_row (s16 * const block) +{ + int d0, d1, d2, d3; + int a0, a1, a2, a3, b0, b1, b2, b3; + int t0, t1, t2, t3; + + /* shortcut */ + if (!(block[1] | ((s32 *)block)[1] | ((s32 *)block)[2] | + ((s32 *)block)[3])) { + u32 tmp = (u16) (block[0] << 3); + tmp |= tmp << 16; + ((s32 *)block)[0] = tmp; + ((s32 *)block)[1] = tmp; + ((s32 *)block)[2] = tmp; + ((s32 *)block)[3] = tmp; + return; + } + + d0 = (block[0] << 11) + 128; + d1 = block[1]; + d2 = block[2] << 11; + d3 = block[3]; + t0 = d0 + d2; + t1 = d0 - d2; + BUTTERFLY (t2, t3, W6, W2, d3, d1); + a0 = t0 + t2; + a1 = t1 + t3; + a2 = t1 - t3; + a3 = t0 - t2; + + d0 = block[4]; + d1 = block[5]; + d2 = block[6]; + d3 = block[7]; + BUTTERFLY (t0, t1, W7, W1, d3, d0); + BUTTERFLY (t2, t3, W3, W5, d1, d2); + b0 = t0 + t2; + b3 = t1 + t3; + t0 -= t2; + t1 -= t3; + b1 = ((t0 + t1) * 181) >> 8; + b2 = ((t0 - t1) * 181) >> 8; + + block[0] = (a0 + b0) >> 8; + block[1] = (a1 + b1) >> 8; + block[2] = (a2 + b2) >> 8; + block[3] = (a3 + b3) >> 8; + block[4] = (a3 - b3) >> 8; + block[5] = (a2 - b2) >> 8; + block[6] = (a1 - b1) >> 8; + block[7] = (a0 - b0) >> 8; +} + +static __forceinline void idct_col (s16 * const block) +{ + int d0, d1, d2, d3; + int a0, a1, a2, a3, b0, b1, b2, b3; + int t0, t1, t2, t3; + + d0 = (block[8*0] << 11) + 65536; + d1 = block[8*1]; + d2 = block[8*2] << 11; + d3 = block[8*3]; + t0 = d0 + d2; + t1 = d0 - d2; + BUTTERFLY (t2, t3, W6, W2, d3, d1); + a0 = t0 + t2; + a1 = t1 + t3; + a2 = t1 - t3; + a3 = t0 - t2; + + d0 = block[8*4]; + d1 = block[8*5]; + d2 = block[8*6]; + d3 = block[8*7]; + BUTTERFLY (t0, t1, W7, W1, d3, d0); + BUTTERFLY (t2, t3, W3, W5, d1, d2); + b0 = t0 + t2; + b3 = t1 + t3; + t0 = (t0 - t2) >> 8; + t1 = (t1 - t3) >> 8; + b1 = (t0 + t1) * 181; + b2 = (t0 - t1) * 181; + + block[8*0] = (a0 + b0) >> 17; + block[8*1] = (a1 + b1) >> 17; + block[8*2] = (a2 + b2) >> 17; + block[8*3] = (a3 + b3) >> 17; + block[8*4] = (a3 - b3) >> 17; + block[8*5] = (a2 - b2) >> 17; + block[8*6] = (a1 - b1) >> 17; + block[8*7] = (a0 - b0) >> 17; +} + +static void __fastcall mpeg2_idct_copy_c (s16 * block, u8 * dest, + const int stride) +{ + int i; + + for (i = 0; i < 8; i++) + idct_row (block + 8 * i); + for (i = 0; i < 8; i++) + idct_col (block + i); + do { + dest[0] = CLIP (block[0]); + dest[1] = CLIP (block[1]); + dest[2] = CLIP (block[2]); + dest[3] = CLIP (block[3]); + dest[4] = CLIP (block[4]); + dest[5] = CLIP (block[5]); + dest[6] = CLIP (block[6]); + dest[7] = CLIP (block[7]); + + block[0] = 0; block[1] = 0; block[2] = 0; block[3] = 0; + block[4] = 0; block[5] = 0; block[6] = 0; block[7] = 0; + + dest += stride; + block += 8; + } while (--i); +} + +/* JayteeMaster: changed dest to 16 bit signed */ +static void __fastcall mpeg2_idct_add_c (const int last, s16 * block, + /*u8*/s16 * dest, const int stride) +{ + int i; + + if (last != 129 || (block[0] & 7) == 4) { + for (i = 0; i < 8; i++) + idct_row (block + 8 * i); + for (i = 0; i < 8; i++) + idct_col (block + i); + do { + dest[0] = block[0]; + dest[1] = block[1]; + dest[2] = block[2]; + dest[3] = block[3]; + dest[4] = block[4]; + dest[5] = block[5]; + dest[6] = block[6]; + dest[7] = block[7]; + + block[0] = 0; block[1] = 0; block[2] = 0; block[3] = 0; + block[4] = 0; block[5] = 0; block[6] = 0; block[7] = 0; + + dest += stride; + block += 8; + } while (--i); + } else { + int DC; + + DC = (block[0] + 4) >> 3; + block[0] = block[63] = 0; + i = 8; + do { + dest[0] = DC; + dest[1] = DC; + dest[2] = DC; + dest[3] = DC; + dest[4] = DC; + dest[5] = DC; + dest[6] = DC; + dest[7] = DC; + dest += stride; + } while (--i); + } +} + +extern "C" +{ +u8 mpeg2_scan_norm[64] = { + /* Zig-Zag scan pattern */ + 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 +}; + +u8 mpeg2_scan_alt[64] = { + /* Alternate scan pattern */ + 0, 8, 16, 24, 1, 9, 2, 10, 17, 25, 32, 40, 48, 56, 57, 49, + 41, 33, 26, 18, 3, 11, 4, 12, 19, 27, 34, 42, 50, 58, 35, 43, + 51, 59, 20, 28, 5, 13, 6, 14, 21, 29, 36, 44, 52, 60, 37, 45, + 53, 61, 22, 30, 7, 15, 23, 31, 38, 46, 54, 62, 39, 47, 55, 63 +}; +}; + +/* idct_mmx.c */ +void mpeg2_idct_copy_mmxext (s16 * block, u8 * dest, int stride); +void mpeg2_idct_add_mmxext (int last, s16 * block, + s16 * dest, int stride); +void mpeg2_idct_copy_mmx (s16 * block, u8 * dest, int stride); +void mpeg2_idct_add_mmx (int last, s16 * block, + s16 * dest, int stride); +void mpeg2_idct_mmx_init (void); + +void mpeg2_idct_init() +{ +#if !defined(_MSC_VER) || _MSC_VER < 1400 // ignore vc2005 and beyond + int i, j; + +/* if(hasMultimediaExtensions == 1) + { + mpeg2_idct_copy = mpeg2_idct_copy_mmx; + mpeg2_idct_add = mpeg2_idct_add_mmx; + mpeg2_idct_mmx_init (); + }else if(hasMultimediaExtensionsExt == 1) + { + mpeg2_idct_copy = mpeg2_idct_copy_mmxext; + mpeg2_idct_add = mpeg2_idct_add_mmxext; + mpeg2_idct_mmx_init (); + }else*/ + { + mpeg2_idct_copy = mpeg2_idct_copy_c; + mpeg2_idct_add = mpeg2_idct_add_c; + for (i = -384; i < 640; i++) + clip_lut[i+384] = (i < 0) ? 0 : ((i > 255) ? 255 : i); + for (i = 0; i < 64; i++) { + j = mpeg2_scan_norm[i]; + mpeg2_scan_norm[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); + j = mpeg2_scan_alt[i]; + mpeg2_scan_alt[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); + } + } + +#else //blah vcnet2005 idiocity :D + int i,j; + mpeg2_idct_copy = mpeg2_idct_copy_c; + mpeg2_idct_add = mpeg2_idct_add_c; + for (i = -384; i < 640; i++) + clip_lut[i+384] = (i < 0) ? 0 : ((i > 255) ? 255 : i); + for (i = 0; i < 64; i++) { + j = mpeg2_scan_norm[i]; + mpeg2_scan_norm[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); + j = mpeg2_scan_alt[i]; + mpeg2_scan_alt[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); + } +#endif +} diff --git a/pcsx2/IPU/mpeg2lib/Mpeg.cpp b/pcsx2/IPU/mpeg2lib/Mpeg.cpp index 4df1793c70..85fb80e084 100644 --- a/pcsx2/IPU/mpeg2lib/Mpeg.cpp +++ b/pcsx2/IPU/mpeg2lib/Mpeg.cpp @@ -1,1368 +1,1368 @@ -/* - * Mpeg.c - * Copyright (C) 2000-2002 Michel Lespinasse - * Copyright (C) 1999-2000 Aaron Holtzman - * Modified by Florin for PCSX2 emu - * - * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. - * See http://libmpeg2.sourceforge.net/ for updates. - * - * mpeg2dec 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. - * - * mpeg2dec 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 - */ - -// [Air] Note: many functions in this module are large and only used once, so they -// have been forced to inline since it won't bloat the program and gets rid of -// some call overhead. - -#include "PrecompiledHeader.h" - -#include "Common.h" -#include "IPU.h" -#include "Mpeg.h" -#include "Vlc.h" -#include "coroutine.h" - -int non_linear_quantizer_scale [] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 10, 12, 14, 16, 18, 20, 22, - 24, 28, 32, 36, 40, 44, 48, 52, - 56, 64, 72, 80, 88, 96, 104, 112 -}; - -/* Bitstream and buffer needs to be reallocated in order for successful - reading of the old data. Here the old data stored in the 2nd slot - of the internal buffer is copied to 1st slot, and the new data read - into 1st slot is copied to the 2nd slot. Which will later be copied - back to the 1st slot when 128bits have been read. -*/ -extern void ReorderBitstream(); - -int get_macroblock_modes (decoder_t * const decoder) -{ -#define bit_buf (decoder->bitstream_buf) -#define bits (decoder->bitstream_bits) -#define bit_ptr (decoder->bitstream_ptr) - int macroblock_modes; - const MBtab * tab; - - switch (decoder->coding_type) { - case I_TYPE: - - macroblock_modes = UBITS (bit_buf, 2); - - if( macroblock_modes == 0 ) - return 0; // error - - tab = MB_I + (macroblock_modes>>1); - DUMPBITS (bit_buf, bits, tab->len); - macroblock_modes = tab->modes; - - if ((! (decoder->frame_pred_frame_dct)) && - (decoder->picture_structure == FRAME_PICTURE)) { - macroblock_modes |= UBITS (bit_buf, 1) * DCT_TYPE_INTERLACED; - DUMPBITS (bit_buf, bits, 1); - } - - return macroblock_modes; - - case P_TYPE: - - macroblock_modes = UBITS (bit_buf, 6); - - if( macroblock_modes == 0 ) - return 0; // error - - tab = MB_P + (macroblock_modes>>1); - DUMPBITS (bit_buf, bits, tab->len); - macroblock_modes = tab->modes; - - if (decoder->picture_structure != FRAME_PICTURE) { - if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) { - macroblock_modes |= UBITS (bit_buf, 2) * MOTION_TYPE_BASE; - DUMPBITS (bit_buf, bits, 2); - } - return macroblock_modes; - } else if (decoder->frame_pred_frame_dct) { - if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) - macroblock_modes |= MC_FRAME; - return macroblock_modes; - } else { - if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) { - macroblock_modes |= UBITS (bit_buf, 2) * MOTION_TYPE_BASE; - DUMPBITS (bit_buf, bits, 2); - } - if (macroblock_modes & (MACROBLOCK_INTRA | MACROBLOCK_PATTERN)) { - macroblock_modes |= UBITS (bit_buf, 1) * DCT_TYPE_INTERLACED; - DUMPBITS (bit_buf, bits, 1); - } - return macroblock_modes; - } - - case B_TYPE: - - macroblock_modes = UBITS (bit_buf, 6); - - if( macroblock_modes == 0 ) - return 0; // error - tab = MB_B + macroblock_modes; - DUMPBITS (bit_buf, bits, tab->len); - macroblock_modes = tab->modes; - - if (decoder->picture_structure != FRAME_PICTURE) { - if (! (macroblock_modes & MACROBLOCK_INTRA)) { - macroblock_modes |= UBITS (bit_buf, 2) * MOTION_TYPE_BASE; - DUMPBITS (bit_buf, bits, 2); - } - return macroblock_modes; - } else if (decoder->frame_pred_frame_dct) { - /* if (! (macroblock_modes & MACROBLOCK_INTRA)) */ - macroblock_modes |= MC_FRAME; - return macroblock_modes; - } else { - if (macroblock_modes & MACROBLOCK_INTRA) - goto intra; - macroblock_modes |= UBITS (bit_buf, 2) * MOTION_TYPE_BASE; - DUMPBITS (bit_buf, bits, 2); - if (macroblock_modes & (MACROBLOCK_INTRA | MACROBLOCK_PATTERN)) { - intra: - macroblock_modes |= UBITS (bit_buf, 1) * DCT_TYPE_INTERLACED; - DUMPBITS (bit_buf, bits, 1); - } - return macroblock_modes; - } - - case D_TYPE: - - macroblock_modes = UBITS (bit_buf, 1); - if( macroblock_modes == 0 ) - return 0; // error - DUMPBITS (bit_buf, bits, 1); - return MACROBLOCK_INTRA; - - default: - return 0; - } -#undef bit_buf -#undef bits -#undef bit_ptr -} - -static __forceinline int get_quantizer_scale (decoder_t * const decoder) -{ - int quantizer_scale_code; - - quantizer_scale_code = UBITS (decoder->bitstream_buf, 5); - DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, 5); - - if (decoder->q_scale_type) return non_linear_quantizer_scale [quantizer_scale_code]; - else return quantizer_scale_code << 1; -} - -static __forceinline int get_coded_block_pattern (decoder_t * const decoder) -{ - const CBPtab * tab; - - NEEDBITS (decoder->bitstream_buf, decoder->bitstream_bits, decoder->bitstream_ptr); - - if (decoder->bitstream_buf >= 0x20000000) { - tab = CBP_7 + (UBITS (decoder->bitstream_buf, 7) - 16); - DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, tab->len); - return tab->cbp; - } - - tab = CBP_9 + UBITS (decoder->bitstream_buf, 9); - DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, tab->len); - return tab->cbp; -} - -static __forceinline int get_luma_dc_dct_diff (decoder_t * const decoder) -{ -#define bit_buf (decoder->bitstream_buf) -#define bits (decoder->bitstream_bits) -#define bit_ptr (decoder->bitstream_ptr) - - const DCtab * tab; - int size; - int dc_diff; - - if (bit_buf < 0xf8000000) { - tab = DC_lum_5 + UBITS (bit_buf, 5); - size = tab->size; - if (size) { - DUMPBITS (bit_buf, bits, tab->len); - bits += size; - dc_diff = - UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); - bit_buf <<= size; - return dc_diff; - } else { - DUMPBITS (bit_buf, bits, 3); - return 0; - } - } - - tab = DC_long + (UBITS (bit_buf, 9) - 0x1e0);//0x1e0); - size = tab->size; - DUMPBITS (bit_buf, bits, tab->len); - NEEDBITS (bit_buf, bits, bit_ptr); - dc_diff = UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); - DUMPBITS (bit_buf, bits, size); - return dc_diff; -#undef bit_buf -#undef bits -#undef bit_ptr -} - -static __forceinline int get_chroma_dc_dct_diff (decoder_t * const decoder) -{ -#define bit_buf (decoder->bitstream_buf) -#define bits (decoder->bitstream_bits) -#define bit_ptr (decoder->bitstream_ptr) - - const DCtab * tab; - int size; - int dc_diff; - - if (bit_buf < 0xf8000000) { - tab = DC_chrom_5 + UBITS (bit_buf, 5); - size = tab->size; - if (size) { - DUMPBITS (bit_buf, bits, tab->len); - bits += size; - dc_diff = - UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); - bit_buf <<= size; - return dc_diff; - } else { - DUMPBITS (bit_buf, bits, 2); - return 0; - } - } - - tab = DC_long + (UBITS (bit_buf, 10) - 0x3e0); - size = tab->size; - DUMPBITS (bit_buf, bits, tab->len + 1); - NEEDBITS (bit_buf, bits, bit_ptr); - dc_diff = UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); - DUMPBITS (bit_buf, bits, size); - return dc_diff; -#undef bit_buf -#undef bits -#undef bit_ptr -} - -#define SATURATE(val) \ -do { \ - if (((u32)(val + 2048) > 4095)) \ - val = SBITS (val, 1) ^ 2047; \ -} while (0) - -static __forceinline void get_intra_block_B14 (decoder_t * const decoder) -{ - int i; - int j; - int val; - const u8 * scan = decoder->scan; - const u8 * quant_matrix = decoder->intra_quantizer_matrix; - int quantizer_scale = decoder->quantizer_scale; - int mismatch; - const DCTtab * tab; - u32 bit_buf; - u8 * bit_ptr; - int bits; - s16 * dest; - - dest = decoder->DCTblock; - i = 0; - mismatch = ~dest[0]; - - bit_buf = decoder->bitstream_buf; - bits = decoder->bitstream_bits; - bit_ptr = decoder->bitstream_ptr; - - NEEDBITS (bit_buf, bits, bit_ptr); - - while (1) { - if (bit_buf >= 0x28000000) { - - tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5); - - i += tab->run; - if (i >= 64) break; /* end of block */ - - normal_code: - j = scan[i]; - bit_buf <<= tab->len; - bits += tab->len + 1; - /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ - val = (tab->level * quantizer_scale * quant_matrix[i]) >> 4; - - /* if (bitstream_get (1)) val = -val; */ - val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); - - SATURATE (val); - dest[j] = val; - mismatch ^= val; - - bit_buf <<= 1; - NEEDBITS (bit_buf, bits, bit_ptr); - - continue; - - } else if (bit_buf >= 0x04000000) { - - tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4); - - i += tab->run; - if (i < 64) goto normal_code; - - /* escape code */ - - i += UBITS (bit_buf << 6, 6) - 64; - if (i >= 64) break; /* illegal, check needed to avoid buffer overflow */ - - j = scan[i]; - - DUMPBITS (bit_buf, bits, 12); - NEEDBITS (bit_buf, bits, bit_ptr); - /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ - val = (SBITS (bit_buf, 12) * quantizer_scale * quant_matrix[i]) / 16; - - SATURATE (val); - dest[j] = val; - mismatch ^= val; - - DUMPBITS (bit_buf, bits, 12); - NEEDBITS (bit_buf, bits, bit_ptr); - - continue; - - } else if (bit_buf >= 0x02000000) { - tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8); - i += tab->run; - if (i < 64) goto normal_code; - } else if (bit_buf >= 0x00800000) { - tab = DCT_13 + (UBITS (bit_buf, 13) - 16); - i += tab->run; - if (i < 64) goto normal_code; - } else if (bit_buf >= 0x00200000) { - tab = DCT_15 + (UBITS (bit_buf, 15) - 16); - i += tab->run; - if (i < 64) goto normal_code; - } else { - tab = DCT_16 + UBITS (bit_buf, 16); - bit_buf <<= 16; - GETWORD(&bit_buf,bits+16); - i += tab->run; - if (i < 64) goto normal_code; - } - break; /* illegal, check needed to avoid buffer overflow */ - } - dest[63] ^= mismatch & 1; - if( (bit_buf>>30) != 0x2 ) - ipuRegs->ctrl.ECD = 1; - DUMPBITS (bit_buf, bits, tab->len); /* dump end of block code */ - decoder->bitstream_buf = bit_buf; - decoder->bitstream_bits = bits; -} - -static __forceinline void get_intra_block_B15 (decoder_t * const decoder) -{ - int i; - int j; - int val; - const u8 * scan = decoder->scan; - const u8 * quant_matrix = decoder->intra_quantizer_matrix; - int quantizer_scale = decoder->quantizer_scale; - int mismatch; - const DCTtab * tab; - u32 bit_buf; - u8 * bit_ptr; - int bits; - s16 * dest; - - dest = decoder->DCTblock; - i = 0; - mismatch = ~dest[0]; - - bit_buf = decoder->bitstream_buf; - bits = decoder->bitstream_bits; - bit_ptr = decoder->bitstream_ptr; - - NEEDBITS (bit_buf, bits, bit_ptr); - - while (1) { - if (bit_buf >= 0x04000000) { - - tab = DCT_B15_8 + (UBITS (bit_buf, 8) - 4); - - i += tab->run; - if (i < 64) { - normal_code: - j = scan[i]; - bit_buf <<= tab->len; - bits += tab->len + 1; - /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ - val = (tab->level * quantizer_scale * quant_matrix[i]) >> 4; - - /* if (bitstream_get (1)) val = -val; */ - val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); - - SATURATE (val); - dest[j] = val; - mismatch ^= val; - - bit_buf <<= 1; - NEEDBITS (bit_buf, bits, bit_ptr); - - continue; - - } else { - /* end of block. I commented out this code because if we */ - /* dont exit here we will still exit at the later test :) */ - //if (i >= 128) break; /* end of block */ - /* escape code */ - - i += UBITS (bit_buf << 6, 6) - 64; - if (i >= 64) break; /* illegal, check against buffer overflow */ - - j = scan[i]; - - DUMPBITS (bit_buf, bits, 12); - NEEDBITS (bit_buf, bits, bit_ptr); - /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ - val = (SBITS (bit_buf, 12) * quantizer_scale * quant_matrix[i]) / 16; - - SATURATE (val); - dest[j] = val; - mismatch ^= val; - - DUMPBITS (bit_buf, bits, 12); - NEEDBITS (bit_buf, bits, bit_ptr); - - continue; - } - } else if (bit_buf >= 0x02000000) { - tab = DCT_B15_10 + (UBITS (bit_buf, 10) - 8); - i += tab->run; - if (i < 64) goto normal_code; - } else if (bit_buf >= 0x00800000) { - tab = DCT_13 + (UBITS (bit_buf, 13) - 16); - i += tab->run; - if (i < 64) goto normal_code; - } else if (bit_buf >= 0x00200000) { - tab = DCT_15 + (UBITS (bit_buf, 15) - 16); - i += tab->run; - if (i < 64) goto normal_code; - } else { - tab = DCT_16 + UBITS (bit_buf, 16); - bit_buf <<= 16; - GETWORD(&bit_buf,bits+16); - i += tab->run; - if (i < 64) goto normal_code; - } - break; /* illegal, check needed to avoid buffer overflow */ - } - dest[63] ^= mismatch & 1; - if( (bit_buf>>28) != 0x6 ) - ipuRegs->ctrl.ECD = 1; - DUMPBITS (bit_buf, bits, tab->len); /* dump end of block code */ - decoder->bitstream_buf = bit_buf; - decoder->bitstream_bits = bits; -} - -static __forceinline int get_non_intra_block (decoder_t * const decoder) -{ -#define bit_buf (decoder->bitstream_buf) -#define bits (decoder->bitstream_bits) -#define bit_ptr (decoder->bitstream_ptr) - int i; - int j; - int val; - const u8 * scan = decoder->scan; - const u8 * quant_matrix = decoder->non_intra_quantizer_matrix; - int quantizer_scale = decoder->quantizer_scale; - int mismatch; - const DCTtab * tab; - s16 * dest; - - i = -1; - mismatch = -1; - dest = decoder->DCTblock; - - - NEEDBITS (bit_buf, bits, bit_ptr); - if (bit_buf >= 0x28000000) { - tab = DCT_B14DC_5 + (UBITS (bit_buf, 5) - 5); - goto entry_1; - } else - goto entry_2; - - while (1) { - if (bit_buf >= 0x28000000) { - - tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5); - - entry_1: - i += tab->run; - if (i >= 64) - break; /* end of block */ - - normal_code: - j = scan[i]; - bit_buf <<= tab->len; - bits += tab->len + 1; - /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ - val = ((2*tab->level+1) * quantizer_scale * quant_matrix[i]) >> 5; - - /* if (bitstream_get (1)) val = -val; */ - val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); - - SATURATE (val); - dest[j] = val; - mismatch ^= val; - - bit_buf <<= 1; - NEEDBITS (bit_buf, bits, bit_ptr); - - continue; - - } - - entry_2: - if (bit_buf >= 0x04000000) { - - tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4); - - i += tab->run; - if (i < 64) - goto normal_code; - - /* escape code */ - - i += UBITS (bit_buf << 6, 6) - 64; - if (i >= 64) - break; /* illegal, check needed to avoid buffer overflow */ - - j = scan[i]; - - DUMPBITS (bit_buf, bits, 12); - NEEDBITS (bit_buf, bits, bit_ptr); - val = 2 * (SBITS (bit_buf, 12) + SBITS (bit_buf, 1)) + 1; - /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ - val = (val * quantizer_scale * quant_matrix[i]) / 32; - - SATURATE (val); - dest[j] = val; - mismatch ^= val; - - DUMPBITS (bit_buf, bits, 12); - NEEDBITS (bit_buf, bits, bit_ptr); - - continue; - - } else if (bit_buf >= 0x02000000) { - tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8); - i += tab->run; - if (i < 64) - goto normal_code; - } else if (bit_buf >= 0x00800000) { - tab = DCT_13 + (UBITS (bit_buf, 13) - 16); - i += tab->run; - if (i < 64) - goto normal_code; - } else if (bit_buf >= 0x00200000) { - tab = DCT_15 + (UBITS (bit_buf, 15) - 16); - i += tab->run; - if (i < 64) - goto normal_code; - } else { - tab = DCT_16 + UBITS (bit_buf, 16); - bit_buf <<= 16; - GETWORD(&bit_buf,bits+16); - i += tab->run; - if (i < 64) - goto normal_code; - } - break; /* illegal, check needed to avoid buffer overflow */ - } - dest[63] ^= mismatch & 1; - if( (bit_buf>>30) != 0x2 ) - ipuRegs->ctrl.ECD = 1; - - DUMPBITS (bit_buf, bits, tab->len); /* dump end of block code */ - decoder->bitstream_buf = bit_buf; - decoder->bitstream_bits = bits; - return i; -#undef bit_buf -#undef bits -#undef bit_ptr -} - -static __forceinline void get_mpeg1_intra_block (decoder_t * const decoder) -{ - int i; - int j; - int val; - const u8 * scan = decoder->scan; - const u8 * quant_matrix = decoder->intra_quantizer_matrix; - int quantizer_scale = decoder->quantizer_scale; - const DCTtab * tab; - u32 bit_buf; - int bits; - u8 * bit_ptr; - s16 * dest; - - i = 0; - dest = decoder->DCTblock; - - bit_buf = decoder->bitstream_buf; - bits = decoder->bitstream_bits; - bit_ptr = decoder->bitstream_ptr; - - NEEDBITS (bit_buf, bits, bit_ptr); - - while (1) { - if (bit_buf >= 0x28000000) { - - tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5); - - i += tab->run; - if (i >= 64) - break; /* end of block */ - - normal_code: - j = scan[i]; - bit_buf <<= tab->len; - bits += tab->len + 1; - /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ - val = (tab->level * quantizer_scale * quant_matrix[i]) >> 4; - - /* oddification */ - val = (val - 1) | 1; - - /* if (bitstream_get (1)) val = -val; */ - val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); - - SATURATE (val); - dest[j] = val; - - bit_buf <<= 1; - NEEDBITS (bit_buf, bits, bit_ptr); - - continue; - - } else if (bit_buf >= 0x04000000) { - - tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4); - - i += tab->run; - if (i < 64) - goto normal_code; - - /* escape code */ - - i += UBITS (bit_buf << 6, 6) - 64; - if (i >= 64) - break; /* illegal, check needed to avoid buffer overflow */ - - j = scan[i]; - - DUMPBITS (bit_buf, bits, 12); - NEEDBITS (bit_buf, bits, bit_ptr); - val = SBITS (bit_buf, 8); - if (! (val & 0x7f)) { - DUMPBITS (bit_buf, bits, 8); - val = UBITS (bit_buf, 8) + 2 * val; - } - /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ - val = (val * quantizer_scale * quant_matrix[i]) >> 4; - - /* oddification */ - val = (val + ~SBITS (val, 1)) | 1; - - SATURATE (val); - dest[j] = val; - - DUMPBITS (bit_buf, bits, 8); - NEEDBITS (bit_buf, bits, bit_ptr); - - continue; - - } else if (bit_buf >= 0x02000000) { - tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8); - i += tab->run; - if (i < 64) - goto normal_code; - } else if (bit_buf >= 0x00800000) { - tab = DCT_13 + (UBITS (bit_buf, 13) - 16); - i += tab->run; - if (i < 64) - goto normal_code; - } else if (bit_buf >= 0x00200000) { - tab = DCT_15 + (UBITS (bit_buf, 15) - 16); - i += tab->run; - if (i < 64) - goto normal_code; - } else { - tab = DCT_16 + UBITS (bit_buf, 16); - bit_buf <<= 16; - GETWORD(&bit_buf,bits+16); - i += tab->run; - if (i < 64) - goto normal_code; - } - break; /* illegal, check needed to avoid buffer overflow */ - } - if( (bit_buf>>30) != 0x2 ) - ipuRegs->ctrl.ECD = 1; - - DUMPBITS (bit_buf, bits, 2); /* dump end of block code */ - decoder->bitstream_buf = bit_buf; - decoder->bitstream_bits = bits; -} - -static __forceinline int get_mpeg1_non_intra_block (decoder_t * const decoder) -{ - int i; - int j; - int val; - const u8 * scan = decoder->scan; - const u8 * quant_matrix = decoder->non_intra_quantizer_matrix; - int quantizer_scale = decoder->quantizer_scale; - const DCTtab * tab; - u32 bit_buf; - int bits; - u8 * bit_ptr; - s16 * dest; - - i = -1; - dest = decoder->DCTblock; - - bit_buf = decoder->bitstream_buf; - bits = decoder->bitstream_bits; - bit_ptr = decoder->bitstream_ptr; - - NEEDBITS (bit_buf, bits, bit_ptr); - if (bit_buf >= 0x28000000) { - tab = DCT_B14DC_5 + (UBITS (bit_buf, 5) - 5); - goto entry_1; - } else - goto entry_2; - - while (1) { - if (bit_buf >= 0x28000000) { - - tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5); - - entry_1: - i += tab->run; - if (i >= 64) - break; /* end of block */ - - normal_code: - j = scan[i]; - bit_buf <<= tab->len; - bits += tab->len + 1; - /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ - val = ((2*tab->level+1) * quantizer_scale * quant_matrix[i]) >> 5; - - /* oddification */ - val = (val - 1) | 1; - - /* if (bitstream_get (1)) val = -val; */ - val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); - - SATURATE (val); - dest[j] = val; - - bit_buf <<= 1; - NEEDBITS (bit_buf, bits, bit_ptr); - - continue; - - } - - entry_2: - if (bit_buf >= 0x04000000) { - - tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4); - - i += tab->run; - if (i < 64) - goto normal_code; - - /* escape code */ - - i += UBITS (bit_buf << 6, 6) - 64; - if (i >= 64) - break; /* illegal, check needed to avoid buffer overflow */ - - j = scan[i]; - - DUMPBITS (bit_buf, bits, 12); - NEEDBITS (bit_buf, bits, bit_ptr); - val = SBITS (bit_buf, 8); - if (! (val & 0x7f)) { - DUMPBITS (bit_buf, bits, 8); - val = UBITS (bit_buf, 8) + 2 * val; - } - val = 2 * (val + SBITS (val, 1)) + 1; - /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ - val = (val * quantizer_scale * quant_matrix[i]) / 32; - - /* oddification */ - val = (val + ~SBITS (val, 1)) | 1; - - SATURATE (val); - dest[j] = val; - - DUMPBITS (bit_buf, bits, 8); - NEEDBITS (bit_buf, bits, bit_ptr); - - continue; - - } else if (bit_buf >= 0x02000000) { - tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8); - i += tab->run; - if (i < 64) - goto normal_code; - } else if (bit_buf >= 0x00800000) { - tab = DCT_13 + (UBITS (bit_buf, 13) - 16); - i += tab->run; - if (i < 64) - goto normal_code; - } else if (bit_buf >= 0x00200000) { - tab = DCT_15 + (UBITS (bit_buf, 15) - 16); - i += tab->run; - if (i < 64) - goto normal_code; - } else { - tab = DCT_16 + UBITS (bit_buf, 16); - bit_buf <<= 16; - GETWORD(&bit_buf,bits+16); - i += tab->run; - if (i < 64) - goto normal_code; - } - break; /* illegal, check needed to avoid buffer overflow */ - } - if( (bit_buf>>30) != 0x2 ) - ipuRegs->ctrl.ECD = 1; - - DUMPBITS (bit_buf, bits, 2); /* dump end of block code */ - decoder->bitstream_buf = bit_buf; - decoder->bitstream_bits = bits; - return i; -} - -static void __fastcall slice_intra_DCT (decoder_t * const decoder, const int cc, - u8 * const dest, const int stride) -{ - NEEDBITS (decoder->bitstream_buf, decoder->bitstream_bits, decoder->bitstream_ptr); - /* Get the intra DC coefficient and inverse quantize it */ - if (cc == 0) decoder->dc_dct_pred[0] += get_luma_dc_dct_diff (decoder); - else decoder->dc_dct_pred[cc] += get_chroma_dc_dct_diff (decoder); - - decoder->DCTblock[0] = decoder->dc_dct_pred[cc] << (3 - decoder->intra_dc_precision); - - if (decoder->mpeg1) get_mpeg1_intra_block (decoder); - else if (decoder->intra_vlc_format){ - get_intra_block_B15 (decoder); - }else{ - get_intra_block_B14 (decoder); - } - - mpeg2_idct_copy (decoder->DCTblock, dest, stride); -} - -/* JayteeMaster: changed dest to 16 bit signed */ -static void __fastcall slice_non_intra_DCT (decoder_t * const decoder, - /*u8*/s16 * const dest, const int stride){ - int last; - memzero_obj(decoder->DCTblock); - if (decoder->mpeg1) last = get_mpeg1_non_intra_block (decoder); - else last = get_non_intra_block (decoder); - - mpeg2_idct_add (last, decoder->DCTblock, dest, stride); -} - -#if defined(_MSC_VER) -#pragma pack(push, 1) -#endif -struct TGA_HEADER -{ - u8 identsize; // size of ID field that follows 18 u8 header (0 usually) - u8 colourmaptype; // type of colour map 0=none, 1=has palette - u8 imagetype; // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed - - s16 colourmapstart; // first colour map entry in palette - s16 colourmaplength; // number of colours in palette - u8 colourmapbits; // number of bits per palette entry 15,16,24,32 - - s16 xstart; // image x origin - s16 ystart; // image y origin - s16 width; // image width in pixels - s16 height; // image height in pixels - u8 bits; // image bits per pixel 8,16,24,32 - u8 descriptor; // image descriptor bits (vh flip bits) - - // pixel data follows header -#if defined(_MSC_VER) -}; -#pragma pack(pop) -#else -} __attribute__((packed)); -#endif - -void SaveTGA(const char* filename, int width, int height, void* pdata) -{ - TGA_HEADER hdr; - FILE* f = fopen(filename, "wb"); - if( f == NULL ) - return; - - assert( sizeof(TGA_HEADER) == 18 && sizeof(hdr) == 18 ); - - memzero_obj(hdr); - hdr.imagetype = 2; - hdr.bits = 32; - hdr.width = width; - hdr.height = height; - hdr.descriptor |= 8|(1<<5); // 8bit alpha, flip vertical - - fwrite(&hdr, sizeof(hdr), 1, f); - fwrite(pdata, width*height*4, 1, f); - fclose(f); -} -static int s_index = 0; //, s_frame = 0; - -void SaveRGB32(u8* ptr) -{ - char filename[255]; - sprintf(filename, "frames/frame%.4d.tga", s_index++); - SaveTGA(filename, 16, 16, ptr); -} - -void waitForSCD() -{ - u8 bit8 = 1; - - while(!getBits8((u8*)&bit8, 0)) - so_resume(); - - if (bit8==0) - { - if (g_BP.BP & 7) - g_BP.BP += 8 - (g_BP.BP&7); - - ipuRegs->ctrl.SCD = 1; - } - - while(!getBits32((u8*)&ipuRegs->top, 0)) - { - so_resume(); - } - - BigEndian(ipuRegs->top, ipuRegs->top); - - /*if(ipuRegs->ctrl.SCD) - { - switch(ipuRegs->top & 0xFFFFFFF0) - { - case 0x100: - case 0x1A0: - break; - case 0x1B0: - ipuRegs->ctrl.SCD = 0; - if(ipuRegs->top == 0x1b4) ipuRegs->ctrl.ECD = 1; - //else - //{ - // do - // { - // while(!getBits32((u8*)&ipuRegs->top, 1)) - // { - // so_resume(); - // } - - // BigEndian(ipuRegs->top, ipuRegs->top); - // } - // while((ipuRegs->top & 0xfffffff0) != 0x100); - //} - break; - default: - ipuRegs->ctrl.SCD = 0; - break; - } - }*/ -} - -void mpeg2sliceIDEC(void* pdone) -{ - u32 read; - - decoder_t * decoder = &g_decoder; - - *(int*)pdone = 0; - bitstream_init(decoder); - - decoder->dc_dct_pred[0] = - decoder->dc_dct_pred[1] = - decoder->dc_dct_pred[2] = 128 << decoder->intra_dc_precision; - - decoder->mbc=0; - ipuRegs->ctrl.ECD = 0; - - if (UBITS (decoder->bitstream_buf, 2) == 0) - { - ipuRegs->ctrl.SCD = 0; - }else{ - while (1) { - int DCT_offset, DCT_stride; - int mba_inc; - const MBAtab * mba; - - NEEDBITS (decoder->bitstream_buf, decoder->bitstream_bits, decoder->bitstream_ptr); - - decoder->macroblock_modes = get_macroblock_modes (decoder); - - /* maybe integrate MACROBLOCK_QUANT test into get_macroblock_modes ? */ - if (decoder->macroblock_modes & MACROBLOCK_QUANT)//only IDEC - decoder->quantizer_scale = get_quantizer_scale (decoder); - - if (decoder->macroblock_modes & DCT_TYPE_INTERLACED) { - DCT_offset = decoder->stride; - DCT_stride = decoder->stride * 2; - } else { - DCT_offset = decoder->stride * 8; - DCT_stride = decoder->stride; - } - - if (decoder->macroblock_modes & MACROBLOCK_INTRA) { - decoder->coded_block_pattern = 0x3F;//all 6 blocks - //ipuRegs->ctrl.CBP = 0x3f; - - memzero_obj(*decoder->mb8); - memzero_obj(*decoder->rgb32); - - slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y, DCT_stride); - slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y + 8, DCT_stride); - slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y + DCT_offset, DCT_stride); - slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y + DCT_offset + 8, DCT_stride); - slice_intra_DCT (decoder, 1, (u8*)decoder->mb8->Cb, decoder->stride>>1); - slice_intra_DCT (decoder, 2, (u8*)decoder->mb8->Cr, decoder->stride>>1); - - // Send The MacroBlock via DmaIpuFrom - if (decoder->ofm==0){ - ipu_csc(decoder->mb8, decoder->rgb32, decoder->sgn); - - g_nIPU0Data = 64; - g_pIPU0Pointer = (u8*)decoder->rgb32; - //if( s_frame >= 39 ) SaveRGB32(g_pIPU0Pointer); - while(g_nIPU0Data > 0) { - read = FIFOfrom_write((u32*)g_pIPU0Pointer,g_nIPU0Data); - if( read == 0 ) - { - so_resume(); - } - else { - g_pIPU0Pointer += read*16; - g_nIPU0Data -= read; - } - } - } - else{ - //ipu_dither(decoder->mb8, decoder->rgb16, decoder->dte); - ipu_csc(decoder->mb8, decoder->rgb32, decoder->dte); - ipu_dither2(decoder->rgb32, decoder->rgb16, decoder->dte); - - g_nIPU0Data = 32; - g_pIPU0Pointer = (u8*)decoder->rgb16; - //if( s_frame >= 39 ) SaveRGB32(g_pIPU0Pointer); - while(g_nIPU0Data > 0) { - read = FIFOfrom_write((u32*)g_pIPU0Pointer,g_nIPU0Data); - if( read == 0 ){ - so_resume(); - } - else { - g_pIPU0Pointer += read*16; - g_nIPU0Data -= read; - } - } - } - decoder->mbc++; - } - - NEEDBITS (decoder->bitstream_buf, decoder->bitstream_bits, decoder->bitstream_ptr); - - mba_inc = 0; - while (1) { - if (decoder->bitstream_buf >= 0x10000000) { - mba = MBA_5 + (UBITS (decoder->bitstream_buf, 5) - 2); - break; - } else if (decoder->bitstream_buf >= 0x03000000) { - mba = MBA_11 + (UBITS (decoder->bitstream_buf, 11) - 24); - break; - } else switch (UBITS (decoder->bitstream_buf, 11)) { - case 8: /* macroblock_escape */ - mba_inc += 33; - /* pass through */ - case 15: /* macroblock_stuffing (MPEG1 only) */ - DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, 11); - NEEDBITS (decoder->bitstream_buf, decoder->bitstream_bits, decoder->bitstream_ptr); - continue; - default: /* end of slice/frame, or error? */ - { - ipuRegs->ctrl.SCD = 0; - coded_block_pattern=decoder->coded_block_pattern; - - g_BP.BP+=decoder->bitstream_bits-16; - - if((int)g_BP.BP < 0) { - g_BP.BP = 128 + (int)g_BP.BP; - - // After BP is positioned correctly, we need to reload the old buffer - // so that reading may continue properly - ReorderBitstream(); - } - - FillInternalBuffer(&g_BP.BP,1,0); - - waitForSCD(); - - *(int*)pdone = 1; - so_exit(); - } - } - } - DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, mba->len); - mba_inc += mba->mba; - - if (mba_inc) { - decoder->dc_dct_pred[0] = decoder->dc_dct_pred[1] = - decoder->dc_dct_pred[2] = 128 << decoder->intra_dc_precision; - do { - decoder->mbc++; - } while (--mba_inc); - } - } - } - - ipuRegs->ctrl.SCD = 0; - - coded_block_pattern=decoder->coded_block_pattern; - - g_BP.BP+=decoder->bitstream_bits-16; - - if((int)g_BP.BP < 0) { - g_BP.BP = 128 + (int)g_BP.BP; - - // After BP is positioned correctly, we need to reload the old buffer - // so that reading may continue properly - ReorderBitstream(); - } - - FillInternalBuffer(&g_BP.BP,1,0); - - waitForSCD(); - - *(int*)pdone = 1; - so_exit(); -} - -void mpeg2_slice(void* pdone) -{ - int DCT_offset, DCT_stride; - //u8 bit8=0; - //u32 fp = g_BP.FP; - u32 bp; - decoder_t * decoder = &g_decoder; - u32 size = 0; - - *(int*)pdone = 0; - ipuRegs->ctrl.ECD = 0; - - memzero_obj(*decoder->mb8); - memzero_obj(*decoder->mb16); - - bitstream_init (decoder); - - if (decoder->dcr) - decoder->dc_dct_pred[0] = decoder->dc_dct_pred[1] = - decoder->dc_dct_pred[2] = 128 << decoder->intra_dc_precision; - - if (decoder->macroblock_modes & DCT_TYPE_INTERLACED) { - DCT_offset = decoder->stride; - DCT_stride = decoder->stride * 2; - } else { - DCT_offset = decoder->stride * 8; - DCT_stride = decoder->stride; - } - if (decoder->macroblock_modes & MACROBLOCK_INTRA) { - decoder->coded_block_pattern = 0x3F;//all 6 blocks - slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y, DCT_stride); - slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y + 8, DCT_stride); - slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y + DCT_offset, DCT_stride); - slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y + DCT_offset + 8, DCT_stride); - slice_intra_DCT (decoder, 1, (u8*)decoder->mb8->Cb, decoder->stride>>1); - slice_intra_DCT (decoder, 2, (u8*)decoder->mb8->Cr, decoder->stride>>1); - ipu_copy(decoder->mb8,decoder->mb16); - } else { - if (decoder->macroblock_modes & MACROBLOCK_PATTERN) { - decoder->coded_block_pattern = get_coded_block_pattern (decoder); - /* JayteeMaster: changed from mb8 to mb16 and from u8 to s16 */ - if (decoder->coded_block_pattern & 0x20) slice_non_intra_DCT (decoder, (s16*)decoder->mb16->Y, DCT_stride); - if (decoder->coded_block_pattern & 0x10) slice_non_intra_DCT (decoder, (s16*)decoder->mb16->Y + 8, DCT_stride); - if (decoder->coded_block_pattern & 0x08) slice_non_intra_DCT (decoder, (s16*)decoder->mb16->Y + DCT_offset, DCT_stride); - if (decoder->coded_block_pattern & 0x04) slice_non_intra_DCT (decoder, (s16*)decoder->mb16->Y + DCT_offset + 8, DCT_stride); - if (decoder->coded_block_pattern & 0x2) slice_non_intra_DCT (decoder, (s16*)decoder->mb16->Cb, decoder->stride>>1); - if (decoder->coded_block_pattern & 0x1) slice_non_intra_DCT (decoder, (s16*)decoder->mb16->Cr, decoder->stride>>1); - - } - } - - //Send The MacroBlock via DmaIpuFrom - size = 0; // Reset - - ipuRegs->ctrl.SCD=0; - coded_block_pattern=decoder->coded_block_pattern; - - bp = g_BP.BP; - g_BP.BP+=((int)decoder->bitstream_bits-16); - // BP goes from 0 to 128, so negative values mean to read old buffer - // so we minus from 128 to get the correct BP - if((int)g_BP.BP < 0) { - g_BP.BP = 128 + (int)g_BP.BP; - - // After BP is positioned correctly, we need to reload the old buffer - // so that reading may continue properly - ReorderBitstream(); - } - - FillInternalBuffer(&g_BP.BP,1,0); - - decoder->mbc = 1; - g_nIPU0Data = 48; - g_pIPU0Pointer = (u8*)decoder->mb16; - while(g_nIPU0Data > 0) { - size = FIFOfrom_write((u32*)g_pIPU0Pointer,g_nIPU0Data); - if( size == 0 ) - so_resume(); - else { - g_pIPU0Pointer += size*16; - g_nIPU0Data -= size; - } - } - - waitForSCD(); - - decoder->bitstream_bits = 0; - *(int*)pdone = 1; - so_exit(); -} - -int __forceinline get_motion_delta (decoder_t * const decoder, - const int f_code) -{ -#define bit_buf (decoder->bitstream_buf) -#define bits (decoder->bitstream_bits) -#define bit_ptr (decoder->bitstream_ptr) - - int delta; - int sign; - const MVtab * tab; - - if ( (bit_buf & 0x80000000) ) { - DUMPBITS (bit_buf, bits, 1); - return 0x00010000; - } else if ( (bit_buf & 0xf0000000) || ((bit_buf & 0xfc000000)==0x0c000000) ) { - - tab = MV_4 + UBITS (bit_buf, 4); - delta = (tab->delta << f_code) + 1; - bits += tab->len + f_code + 1; - bit_buf <<= tab->len; - - sign = SBITS (bit_buf, 1); - bit_buf <<= 1; - - if (f_code) - delta += UBITS (bit_buf, f_code); - bit_buf <<= f_code; - - return (delta ^ sign) - sign; - - } else { - - tab = MV_10 + UBITS (bit_buf, 10); - delta = (tab->delta << f_code) + 1; - bits += tab->len + 1; - bit_buf <<= tab->len; - - sign = SBITS (bit_buf, 1); - bit_buf <<= 1; - - if (f_code) { - NEEDBITS (bit_buf, bits, bit_ptr); - delta += UBITS (bit_buf, f_code); - DUMPBITS (bit_buf, bits, f_code); - } - - return (delta ^ sign) - sign; - - } -#undef bit_buf -#undef bits -#undef bit_ptr -} - -int __forceinline get_dmv (decoder_t * const decoder) -{ -#define bit_buf (decoder->bitstream_buf) -#define bits (decoder->bitstream_bits) -#define bit_ptr (decoder->bitstream_ptr) - - const DMVtab * tab; - - tab = DMV_2 + UBITS (bit_buf, 2); - DUMPBITS (bit_buf, bits, tab->len); - return tab->dmv; -#undef bit_buf -#undef bits -#undef bit_ptr -} - -int get_macroblock_address_increment(decoder_t * const decoder){ - const MBAtab *mba; - - if (decoder->bitstream_buf >= 0x10000000) - mba = MBA_5 + (UBITS (decoder->bitstream_buf, 5) - 2); - else if (decoder->bitstream_buf >= 0x03000000) - mba = MBA_11 + (UBITS (decoder->bitstream_buf, 11) - 24); - else switch (UBITS (decoder->bitstream_buf, 11)) { - case 8: /* macroblock_escape */ - DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, 11); - return 0x23; - case 15: /* macroblock_stuffing (MPEG1 only) */ - if (decoder->mpeg1){ - DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, 11); - return 0x22; - } - default: - return 0;//error - } - - DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, mba->len); - return mba->mba + 1; -} +/* + * Mpeg.c + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * Modified by Florin for PCSX2 emu + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * See http://libmpeg2.sourceforge.net/ for updates. + * + * mpeg2dec 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. + * + * mpeg2dec 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 + */ + +// [Air] Note: many functions in this module are large and only used once, so they +// have been forced to inline since it won't bloat the program and gets rid of +// some call overhead. + +#include "PrecompiledHeader.h" + +#include "Common.h" +#include "IPU.h" +#include "Mpeg.h" +#include "Vlc.h" +#include "coroutine.h" + +int non_linear_quantizer_scale [] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 10, 12, 14, 16, 18, 20, 22, + 24, 28, 32, 36, 40, 44, 48, 52, + 56, 64, 72, 80, 88, 96, 104, 112 +}; + +/* Bitstream and buffer needs to be reallocated in order for successful + reading of the old data. Here the old data stored in the 2nd slot + of the internal buffer is copied to 1st slot, and the new data read + into 1st slot is copied to the 2nd slot. Which will later be copied + back to the 1st slot when 128bits have been read. +*/ +extern void ReorderBitstream(); + +int get_macroblock_modes (decoder_t * const decoder) +{ +#define bit_buf (decoder->bitstream_buf) +#define bits (decoder->bitstream_bits) +#define bit_ptr (decoder->bitstream_ptr) + int macroblock_modes; + const MBtab * tab; + + switch (decoder->coding_type) { + case I_TYPE: + + macroblock_modes = UBITS (bit_buf, 2); + + if( macroblock_modes == 0 ) + return 0; // error + + tab = MB_I + (macroblock_modes>>1); + DUMPBITS (bit_buf, bits, tab->len); + macroblock_modes = tab->modes; + + if ((! (decoder->frame_pred_frame_dct)) && + (decoder->picture_structure == FRAME_PICTURE)) { + macroblock_modes |= UBITS (bit_buf, 1) * DCT_TYPE_INTERLACED; + DUMPBITS (bit_buf, bits, 1); + } + + return macroblock_modes; + + case P_TYPE: + + macroblock_modes = UBITS (bit_buf, 6); + + if( macroblock_modes == 0 ) + return 0; // error + + tab = MB_P + (macroblock_modes>>1); + DUMPBITS (bit_buf, bits, tab->len); + macroblock_modes = tab->modes; + + if (decoder->picture_structure != FRAME_PICTURE) { + if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) { + macroblock_modes |= UBITS (bit_buf, 2) * MOTION_TYPE_BASE; + DUMPBITS (bit_buf, bits, 2); + } + return macroblock_modes; + } else if (decoder->frame_pred_frame_dct) { + if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) + macroblock_modes |= MC_FRAME; + return macroblock_modes; + } else { + if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) { + macroblock_modes |= UBITS (bit_buf, 2) * MOTION_TYPE_BASE; + DUMPBITS (bit_buf, bits, 2); + } + if (macroblock_modes & (MACROBLOCK_INTRA | MACROBLOCK_PATTERN)) { + macroblock_modes |= UBITS (bit_buf, 1) * DCT_TYPE_INTERLACED; + DUMPBITS (bit_buf, bits, 1); + } + return macroblock_modes; + } + + case B_TYPE: + + macroblock_modes = UBITS (bit_buf, 6); + + if( macroblock_modes == 0 ) + return 0; // error + tab = MB_B + macroblock_modes; + DUMPBITS (bit_buf, bits, tab->len); + macroblock_modes = tab->modes; + + if (decoder->picture_structure != FRAME_PICTURE) { + if (! (macroblock_modes & MACROBLOCK_INTRA)) { + macroblock_modes |= UBITS (bit_buf, 2) * MOTION_TYPE_BASE; + DUMPBITS (bit_buf, bits, 2); + } + return macroblock_modes; + } else if (decoder->frame_pred_frame_dct) { + /* if (! (macroblock_modes & MACROBLOCK_INTRA)) */ + macroblock_modes |= MC_FRAME; + return macroblock_modes; + } else { + if (macroblock_modes & MACROBLOCK_INTRA) + goto intra; + macroblock_modes |= UBITS (bit_buf, 2) * MOTION_TYPE_BASE; + DUMPBITS (bit_buf, bits, 2); + if (macroblock_modes & (MACROBLOCK_INTRA | MACROBLOCK_PATTERN)) { + intra: + macroblock_modes |= UBITS (bit_buf, 1) * DCT_TYPE_INTERLACED; + DUMPBITS (bit_buf, bits, 1); + } + return macroblock_modes; + } + + case D_TYPE: + + macroblock_modes = UBITS (bit_buf, 1); + if( macroblock_modes == 0 ) + return 0; // error + DUMPBITS (bit_buf, bits, 1); + return MACROBLOCK_INTRA; + + default: + return 0; + } +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static __forceinline int get_quantizer_scale (decoder_t * const decoder) +{ + int quantizer_scale_code; + + quantizer_scale_code = UBITS (decoder->bitstream_buf, 5); + DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, 5); + + if (decoder->q_scale_type) return non_linear_quantizer_scale [quantizer_scale_code]; + else return quantizer_scale_code << 1; +} + +static __forceinline int get_coded_block_pattern (decoder_t * const decoder) +{ + const CBPtab * tab; + + NEEDBITS (decoder->bitstream_buf, decoder->bitstream_bits, decoder->bitstream_ptr); + + if (decoder->bitstream_buf >= 0x20000000) { + tab = CBP_7 + (UBITS (decoder->bitstream_buf, 7) - 16); + DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, tab->len); + return tab->cbp; + } + + tab = CBP_9 + UBITS (decoder->bitstream_buf, 9); + DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, tab->len); + return tab->cbp; +} + +static __forceinline int get_luma_dc_dct_diff (decoder_t * const decoder) +{ +#define bit_buf (decoder->bitstream_buf) +#define bits (decoder->bitstream_bits) +#define bit_ptr (decoder->bitstream_ptr) + + const DCtab * tab; + int size; + int dc_diff; + + if (bit_buf < 0xf8000000) { + tab = DC_lum_5 + UBITS (bit_buf, 5); + size = tab->size; + if (size) { + DUMPBITS (bit_buf, bits, tab->len); + bits += size; + dc_diff = + UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); + bit_buf <<= size; + return dc_diff; + } else { + DUMPBITS (bit_buf, bits, 3); + return 0; + } + } + + tab = DC_long + (UBITS (bit_buf, 9) - 0x1e0);//0x1e0); + size = tab->size; + DUMPBITS (bit_buf, bits, tab->len); + NEEDBITS (bit_buf, bits, bit_ptr); + dc_diff = UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); + DUMPBITS (bit_buf, bits, size); + return dc_diff; +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static __forceinline int get_chroma_dc_dct_diff (decoder_t * const decoder) +{ +#define bit_buf (decoder->bitstream_buf) +#define bits (decoder->bitstream_bits) +#define bit_ptr (decoder->bitstream_ptr) + + const DCtab * tab; + int size; + int dc_diff; + + if (bit_buf < 0xf8000000) { + tab = DC_chrom_5 + UBITS (bit_buf, 5); + size = tab->size; + if (size) { + DUMPBITS (bit_buf, bits, tab->len); + bits += size; + dc_diff = + UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); + bit_buf <<= size; + return dc_diff; + } else { + DUMPBITS (bit_buf, bits, 2); + return 0; + } + } + + tab = DC_long + (UBITS (bit_buf, 10) - 0x3e0); + size = tab->size; + DUMPBITS (bit_buf, bits, tab->len + 1); + NEEDBITS (bit_buf, bits, bit_ptr); + dc_diff = UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size); + DUMPBITS (bit_buf, bits, size); + return dc_diff; +#undef bit_buf +#undef bits +#undef bit_ptr +} + +#define SATURATE(val) \ +do { \ + if (((u32)(val + 2048) > 4095)) \ + val = SBITS (val, 1) ^ 2047; \ +} while (0) + +static __forceinline void get_intra_block_B14 (decoder_t * const decoder) +{ + int i; + int j; + int val; + const u8 * scan = decoder->scan; + const u8 * quant_matrix = decoder->intra_quantizer_matrix; + int quantizer_scale = decoder->quantizer_scale; + int mismatch; + const DCTtab * tab; + u32 bit_buf; + u8 * bit_ptr; + int bits; + s16 * dest; + + dest = decoder->DCTblock; + i = 0; + mismatch = ~dest[0]; + + bit_buf = decoder->bitstream_buf; + bits = decoder->bitstream_bits; + bit_ptr = decoder->bitstream_ptr; + + NEEDBITS (bit_buf, bits, bit_ptr); + + while (1) { + if (bit_buf >= 0x28000000) { + + tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5); + + i += tab->run; + if (i >= 64) break; /* end of block */ + + normal_code: + j = scan[i]; + bit_buf <<= tab->len; + bits += tab->len + 1; + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = (tab->level * quantizer_scale * quant_matrix[i]) >> 4; + + /* if (bitstream_get (1)) val = -val; */ + val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); + + SATURATE (val); + dest[j] = val; + mismatch ^= val; + + bit_buf <<= 1; + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else if (bit_buf >= 0x04000000) { + + tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4); + + i += tab->run; + if (i < 64) goto normal_code; + + /* escape code */ + + i += UBITS (bit_buf << 6, 6) - 64; + if (i >= 64) break; /* illegal, check needed to avoid buffer overflow */ + + j = scan[i]; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = (SBITS (bit_buf, 12) * quantizer_scale * quant_matrix[i]) / 16; + + SATURATE (val); + dest[j] = val; + mismatch ^= val; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else if (bit_buf >= 0x02000000) { + tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8); + i += tab->run; + if (i < 64) goto normal_code; + } else if (bit_buf >= 0x00800000) { + tab = DCT_13 + (UBITS (bit_buf, 13) - 16); + i += tab->run; + if (i < 64) goto normal_code; + } else if (bit_buf >= 0x00200000) { + tab = DCT_15 + (UBITS (bit_buf, 15) - 16); + i += tab->run; + if (i < 64) goto normal_code; + } else { + tab = DCT_16 + UBITS (bit_buf, 16); + bit_buf <<= 16; + GETWORD(&bit_buf,bits+16); + i += tab->run; + if (i < 64) goto normal_code; + } + break; /* illegal, check needed to avoid buffer overflow */ + } + dest[63] ^= mismatch & 1; + if( (bit_buf>>30) != 0x2 ) + ipuRegs->ctrl.ECD = 1; + DUMPBITS (bit_buf, bits, tab->len); /* dump end of block code */ + decoder->bitstream_buf = bit_buf; + decoder->bitstream_bits = bits; +} + +static __forceinline void get_intra_block_B15 (decoder_t * const decoder) +{ + int i; + int j; + int val; + const u8 * scan = decoder->scan; + const u8 * quant_matrix = decoder->intra_quantizer_matrix; + int quantizer_scale = decoder->quantizer_scale; + int mismatch; + const DCTtab * tab; + u32 bit_buf; + u8 * bit_ptr; + int bits; + s16 * dest; + + dest = decoder->DCTblock; + i = 0; + mismatch = ~dest[0]; + + bit_buf = decoder->bitstream_buf; + bits = decoder->bitstream_bits; + bit_ptr = decoder->bitstream_ptr; + + NEEDBITS (bit_buf, bits, bit_ptr); + + while (1) { + if (bit_buf >= 0x04000000) { + + tab = DCT_B15_8 + (UBITS (bit_buf, 8) - 4); + + i += tab->run; + if (i < 64) { + normal_code: + j = scan[i]; + bit_buf <<= tab->len; + bits += tab->len + 1; + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = (tab->level * quantizer_scale * quant_matrix[i]) >> 4; + + /* if (bitstream_get (1)) val = -val; */ + val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); + + SATURATE (val); + dest[j] = val; + mismatch ^= val; + + bit_buf <<= 1; + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else { + /* end of block. I commented out this code because if we */ + /* dont exit here we will still exit at the later test :) */ + //if (i >= 128) break; /* end of block */ + /* escape code */ + + i += UBITS (bit_buf << 6, 6) - 64; + if (i >= 64) break; /* illegal, check against buffer overflow */ + + j = scan[i]; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = (SBITS (bit_buf, 12) * quantizer_scale * quant_matrix[i]) / 16; + + SATURATE (val); + dest[j] = val; + mismatch ^= val; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + } + } else if (bit_buf >= 0x02000000) { + tab = DCT_B15_10 + (UBITS (bit_buf, 10) - 8); + i += tab->run; + if (i < 64) goto normal_code; + } else if (bit_buf >= 0x00800000) { + tab = DCT_13 + (UBITS (bit_buf, 13) - 16); + i += tab->run; + if (i < 64) goto normal_code; + } else if (bit_buf >= 0x00200000) { + tab = DCT_15 + (UBITS (bit_buf, 15) - 16); + i += tab->run; + if (i < 64) goto normal_code; + } else { + tab = DCT_16 + UBITS (bit_buf, 16); + bit_buf <<= 16; + GETWORD(&bit_buf,bits+16); + i += tab->run; + if (i < 64) goto normal_code; + } + break; /* illegal, check needed to avoid buffer overflow */ + } + dest[63] ^= mismatch & 1; + if( (bit_buf>>28) != 0x6 ) + ipuRegs->ctrl.ECD = 1; + DUMPBITS (bit_buf, bits, tab->len); /* dump end of block code */ + decoder->bitstream_buf = bit_buf; + decoder->bitstream_bits = bits; +} + +static __forceinline int get_non_intra_block (decoder_t * const decoder) +{ +#define bit_buf (decoder->bitstream_buf) +#define bits (decoder->bitstream_bits) +#define bit_ptr (decoder->bitstream_ptr) + int i; + int j; + int val; + const u8 * scan = decoder->scan; + const u8 * quant_matrix = decoder->non_intra_quantizer_matrix; + int quantizer_scale = decoder->quantizer_scale; + int mismatch; + const DCTtab * tab; + s16 * dest; + + i = -1; + mismatch = -1; + dest = decoder->DCTblock; + + + NEEDBITS (bit_buf, bits, bit_ptr); + if (bit_buf >= 0x28000000) { + tab = DCT_B14DC_5 + (UBITS (bit_buf, 5) - 5); + goto entry_1; + } else + goto entry_2; + + while (1) { + if (bit_buf >= 0x28000000) { + + tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5); + + entry_1: + i += tab->run; + if (i >= 64) + break; /* end of block */ + + normal_code: + j = scan[i]; + bit_buf <<= tab->len; + bits += tab->len + 1; + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = ((2*tab->level+1) * quantizer_scale * quant_matrix[i]) >> 5; + + /* if (bitstream_get (1)) val = -val; */ + val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); + + SATURATE (val); + dest[j] = val; + mismatch ^= val; + + bit_buf <<= 1; + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } + + entry_2: + if (bit_buf >= 0x04000000) { + + tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4); + + i += tab->run; + if (i < 64) + goto normal_code; + + /* escape code */ + + i += UBITS (bit_buf << 6, 6) - 64; + if (i >= 64) + break; /* illegal, check needed to avoid buffer overflow */ + + j = scan[i]; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + val = 2 * (SBITS (bit_buf, 12) + SBITS (bit_buf, 1)) + 1; + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = (val * quantizer_scale * quant_matrix[i]) / 32; + + SATURATE (val); + dest[j] = val; + mismatch ^= val; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else if (bit_buf >= 0x02000000) { + tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00800000) { + tab = DCT_13 + (UBITS (bit_buf, 13) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00200000) { + tab = DCT_15 + (UBITS (bit_buf, 15) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else { + tab = DCT_16 + UBITS (bit_buf, 16); + bit_buf <<= 16; + GETWORD(&bit_buf,bits+16); + i += tab->run; + if (i < 64) + goto normal_code; + } + break; /* illegal, check needed to avoid buffer overflow */ + } + dest[63] ^= mismatch & 1; + if( (bit_buf>>30) != 0x2 ) + ipuRegs->ctrl.ECD = 1; + + DUMPBITS (bit_buf, bits, tab->len); /* dump end of block code */ + decoder->bitstream_buf = bit_buf; + decoder->bitstream_bits = bits; + return i; +#undef bit_buf +#undef bits +#undef bit_ptr +} + +static __forceinline void get_mpeg1_intra_block (decoder_t * const decoder) +{ + int i; + int j; + int val; + const u8 * scan = decoder->scan; + const u8 * quant_matrix = decoder->intra_quantizer_matrix; + int quantizer_scale = decoder->quantizer_scale; + const DCTtab * tab; + u32 bit_buf; + int bits; + u8 * bit_ptr; + s16 * dest; + + i = 0; + dest = decoder->DCTblock; + + bit_buf = decoder->bitstream_buf; + bits = decoder->bitstream_bits; + bit_ptr = decoder->bitstream_ptr; + + NEEDBITS (bit_buf, bits, bit_ptr); + + while (1) { + if (bit_buf >= 0x28000000) { + + tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5); + + i += tab->run; + if (i >= 64) + break; /* end of block */ + + normal_code: + j = scan[i]; + bit_buf <<= tab->len; + bits += tab->len + 1; + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = (tab->level * quantizer_scale * quant_matrix[i]) >> 4; + + /* oddification */ + val = (val - 1) | 1; + + /* if (bitstream_get (1)) val = -val; */ + val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); + + SATURATE (val); + dest[j] = val; + + bit_buf <<= 1; + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else if (bit_buf >= 0x04000000) { + + tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4); + + i += tab->run; + if (i < 64) + goto normal_code; + + /* escape code */ + + i += UBITS (bit_buf << 6, 6) - 64; + if (i >= 64) + break; /* illegal, check needed to avoid buffer overflow */ + + j = scan[i]; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + val = SBITS (bit_buf, 8); + if (! (val & 0x7f)) { + DUMPBITS (bit_buf, bits, 8); + val = UBITS (bit_buf, 8) + 2 * val; + } + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = (val * quantizer_scale * quant_matrix[i]) >> 4; + + /* oddification */ + val = (val + ~SBITS (val, 1)) | 1; + + SATURATE (val); + dest[j] = val; + + DUMPBITS (bit_buf, bits, 8); + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else if (bit_buf >= 0x02000000) { + tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00800000) { + tab = DCT_13 + (UBITS (bit_buf, 13) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00200000) { + tab = DCT_15 + (UBITS (bit_buf, 15) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else { + tab = DCT_16 + UBITS (bit_buf, 16); + bit_buf <<= 16; + GETWORD(&bit_buf,bits+16); + i += tab->run; + if (i < 64) + goto normal_code; + } + break; /* illegal, check needed to avoid buffer overflow */ + } + if( (bit_buf>>30) != 0x2 ) + ipuRegs->ctrl.ECD = 1; + + DUMPBITS (bit_buf, bits, 2); /* dump end of block code */ + decoder->bitstream_buf = bit_buf; + decoder->bitstream_bits = bits; +} + +static __forceinline int get_mpeg1_non_intra_block (decoder_t * const decoder) +{ + int i; + int j; + int val; + const u8 * scan = decoder->scan; + const u8 * quant_matrix = decoder->non_intra_quantizer_matrix; + int quantizer_scale = decoder->quantizer_scale; + const DCTtab * tab; + u32 bit_buf; + int bits; + u8 * bit_ptr; + s16 * dest; + + i = -1; + dest = decoder->DCTblock; + + bit_buf = decoder->bitstream_buf; + bits = decoder->bitstream_bits; + bit_ptr = decoder->bitstream_ptr; + + NEEDBITS (bit_buf, bits, bit_ptr); + if (bit_buf >= 0x28000000) { + tab = DCT_B14DC_5 + (UBITS (bit_buf, 5) - 5); + goto entry_1; + } else + goto entry_2; + + while (1) { + if (bit_buf >= 0x28000000) { + + tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5); + + entry_1: + i += tab->run; + if (i >= 64) + break; /* end of block */ + + normal_code: + j = scan[i]; + bit_buf <<= tab->len; + bits += tab->len + 1; + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = ((2*tab->level+1) * quantizer_scale * quant_matrix[i]) >> 5; + + /* oddification */ + val = (val - 1) | 1; + + /* if (bitstream_get (1)) val = -val; */ + val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1); + + SATURATE (val); + dest[j] = val; + + bit_buf <<= 1; + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } + + entry_2: + if (bit_buf >= 0x04000000) { + + tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4); + + i += tab->run; + if (i < 64) + goto normal_code; + + /* escape code */ + + i += UBITS (bit_buf << 6, 6) - 64; + if (i >= 64) + break; /* illegal, check needed to avoid buffer overflow */ + + j = scan[i]; + + DUMPBITS (bit_buf, bits, 12); + NEEDBITS (bit_buf, bits, bit_ptr); + val = SBITS (bit_buf, 8); + if (! (val & 0x7f)) { + DUMPBITS (bit_buf, bits, 8); + val = UBITS (bit_buf, 8) + 2 * val; + } + val = 2 * (val + SBITS (val, 1)) + 1; + /* JayteeMaster: 10 points! Replaced quant_matrix[j] by quant_matrix[i] as should be */ + val = (val * quantizer_scale * quant_matrix[i]) / 32; + + /* oddification */ + val = (val + ~SBITS (val, 1)) | 1; + + SATURATE (val); + dest[j] = val; + + DUMPBITS (bit_buf, bits, 8); + NEEDBITS (bit_buf, bits, bit_ptr); + + continue; + + } else if (bit_buf >= 0x02000000) { + tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00800000) { + tab = DCT_13 + (UBITS (bit_buf, 13) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else if (bit_buf >= 0x00200000) { + tab = DCT_15 + (UBITS (bit_buf, 15) - 16); + i += tab->run; + if (i < 64) + goto normal_code; + } else { + tab = DCT_16 + UBITS (bit_buf, 16); + bit_buf <<= 16; + GETWORD(&bit_buf,bits+16); + i += tab->run; + if (i < 64) + goto normal_code; + } + break; /* illegal, check needed to avoid buffer overflow */ + } + if( (bit_buf>>30) != 0x2 ) + ipuRegs->ctrl.ECD = 1; + + DUMPBITS (bit_buf, bits, 2); /* dump end of block code */ + decoder->bitstream_buf = bit_buf; + decoder->bitstream_bits = bits; + return i; +} + +static void __fastcall slice_intra_DCT (decoder_t * const decoder, const int cc, + u8 * const dest, const int stride) +{ + NEEDBITS (decoder->bitstream_buf, decoder->bitstream_bits, decoder->bitstream_ptr); + /* Get the intra DC coefficient and inverse quantize it */ + if (cc == 0) decoder->dc_dct_pred[0] += get_luma_dc_dct_diff (decoder); + else decoder->dc_dct_pred[cc] += get_chroma_dc_dct_diff (decoder); + + decoder->DCTblock[0] = decoder->dc_dct_pred[cc] << (3 - decoder->intra_dc_precision); + + if (decoder->mpeg1) get_mpeg1_intra_block (decoder); + else if (decoder->intra_vlc_format){ + get_intra_block_B15 (decoder); + }else{ + get_intra_block_B14 (decoder); + } + + mpeg2_idct_copy (decoder->DCTblock, dest, stride); +} + +/* JayteeMaster: changed dest to 16 bit signed */ +static void __fastcall slice_non_intra_DCT (decoder_t * const decoder, + /*u8*/s16 * const dest, const int stride){ + int last; + memzero_obj(decoder->DCTblock); + if (decoder->mpeg1) last = get_mpeg1_non_intra_block (decoder); + else last = get_non_intra_block (decoder); + + mpeg2_idct_add (last, decoder->DCTblock, dest, stride); +} + +#if defined(_MSC_VER) +#pragma pack(push, 1) +#endif +struct TGA_HEADER +{ + u8 identsize; // size of ID field that follows 18 u8 header (0 usually) + u8 colourmaptype; // type of colour map 0=none, 1=has palette + u8 imagetype; // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed + + s16 colourmapstart; // first colour map entry in palette + s16 colourmaplength; // number of colours in palette + u8 colourmapbits; // number of bits per palette entry 15,16,24,32 + + s16 xstart; // image x origin + s16 ystart; // image y origin + s16 width; // image width in pixels + s16 height; // image height in pixels + u8 bits; // image bits per pixel 8,16,24,32 + u8 descriptor; // image descriptor bits (vh flip bits) + + // pixel data follows header +#if defined(_MSC_VER) +}; +#pragma pack(pop) +#else +} __attribute__((packed)); +#endif + +void SaveTGA(const char* filename, int width, int height, void* pdata) +{ + TGA_HEADER hdr; + FILE* f = fopen(filename, "wb"); + if( f == NULL ) + return; + + assert( sizeof(TGA_HEADER) == 18 && sizeof(hdr) == 18 ); + + memzero_obj(hdr); + hdr.imagetype = 2; + hdr.bits = 32; + hdr.width = width; + hdr.height = height; + hdr.descriptor |= 8|(1<<5); // 8bit alpha, flip vertical + + fwrite(&hdr, sizeof(hdr), 1, f); + fwrite(pdata, width*height*4, 1, f); + fclose(f); +} +static int s_index = 0; //, s_frame = 0; + +void SaveRGB32(u8* ptr) +{ + char filename[255]; + sprintf(filename, "frames/frame%.4d.tga", s_index++); + SaveTGA(filename, 16, 16, ptr); +} + +void waitForSCD() +{ + u8 bit8 = 1; + + while(!getBits8((u8*)&bit8, 0)) + so_resume(); + + if (bit8==0) + { + if (g_BP.BP & 7) + g_BP.BP += 8 - (g_BP.BP&7); + + ipuRegs->ctrl.SCD = 1; + } + + while(!getBits32((u8*)&ipuRegs->top, 0)) + { + so_resume(); + } + + BigEndian(ipuRegs->top, ipuRegs->top); + + /*if(ipuRegs->ctrl.SCD) + { + switch(ipuRegs->top & 0xFFFFFFF0) + { + case 0x100: + case 0x1A0: + break; + case 0x1B0: + ipuRegs->ctrl.SCD = 0; + if(ipuRegs->top == 0x1b4) ipuRegs->ctrl.ECD = 1; + //else + //{ + // do + // { + // while(!getBits32((u8*)&ipuRegs->top, 1)) + // { + // so_resume(); + // } + + // BigEndian(ipuRegs->top, ipuRegs->top); + // } + // while((ipuRegs->top & 0xfffffff0) != 0x100); + //} + break; + default: + ipuRegs->ctrl.SCD = 0; + break; + } + }*/ +} + +void mpeg2sliceIDEC(void* pdone) +{ + u32 read; + + decoder_t * decoder = &g_decoder; + + *(int*)pdone = 0; + bitstream_init(decoder); + + decoder->dc_dct_pred[0] = + decoder->dc_dct_pred[1] = + decoder->dc_dct_pred[2] = 128 << decoder->intra_dc_precision; + + decoder->mbc=0; + ipuRegs->ctrl.ECD = 0; + + if (UBITS (decoder->bitstream_buf, 2) == 0) + { + ipuRegs->ctrl.SCD = 0; + }else{ + while (1) { + int DCT_offset, DCT_stride; + int mba_inc; + const MBAtab * mba; + + NEEDBITS (decoder->bitstream_buf, decoder->bitstream_bits, decoder->bitstream_ptr); + + decoder->macroblock_modes = get_macroblock_modes (decoder); + + /* maybe integrate MACROBLOCK_QUANT test into get_macroblock_modes ? */ + if (decoder->macroblock_modes & MACROBLOCK_QUANT)//only IDEC + decoder->quantizer_scale = get_quantizer_scale (decoder); + + if (decoder->macroblock_modes & DCT_TYPE_INTERLACED) { + DCT_offset = decoder->stride; + DCT_stride = decoder->stride * 2; + } else { + DCT_offset = decoder->stride * 8; + DCT_stride = decoder->stride; + } + + if (decoder->macroblock_modes & MACROBLOCK_INTRA) { + decoder->coded_block_pattern = 0x3F;//all 6 blocks + //ipuRegs->ctrl.CBP = 0x3f; + + memzero_obj(*decoder->mb8); + memzero_obj(*decoder->rgb32); + + slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y, DCT_stride); + slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y + 8, DCT_stride); + slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y + DCT_offset, DCT_stride); + slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y + DCT_offset + 8, DCT_stride); + slice_intra_DCT (decoder, 1, (u8*)decoder->mb8->Cb, decoder->stride>>1); + slice_intra_DCT (decoder, 2, (u8*)decoder->mb8->Cr, decoder->stride>>1); + + // Send The MacroBlock via DmaIpuFrom + if (decoder->ofm==0){ + ipu_csc(decoder->mb8, decoder->rgb32, decoder->sgn); + + g_nIPU0Data = 64; + g_pIPU0Pointer = (u8*)decoder->rgb32; + //if( s_frame >= 39 ) SaveRGB32(g_pIPU0Pointer); + while(g_nIPU0Data > 0) { + read = FIFOfrom_write((u32*)g_pIPU0Pointer,g_nIPU0Data); + if( read == 0 ) + { + so_resume(); + } + else { + g_pIPU0Pointer += read*16; + g_nIPU0Data -= read; + } + } + } + else{ + //ipu_dither(decoder->mb8, decoder->rgb16, decoder->dte); + ipu_csc(decoder->mb8, decoder->rgb32, decoder->dte); + ipu_dither2(decoder->rgb32, decoder->rgb16, decoder->dte); + + g_nIPU0Data = 32; + g_pIPU0Pointer = (u8*)decoder->rgb16; + //if( s_frame >= 39 ) SaveRGB32(g_pIPU0Pointer); + while(g_nIPU0Data > 0) { + read = FIFOfrom_write((u32*)g_pIPU0Pointer,g_nIPU0Data); + if( read == 0 ){ + so_resume(); + } + else { + g_pIPU0Pointer += read*16; + g_nIPU0Data -= read; + } + } + } + decoder->mbc++; + } + + NEEDBITS (decoder->bitstream_buf, decoder->bitstream_bits, decoder->bitstream_ptr); + + mba_inc = 0; + while (1) { + if (decoder->bitstream_buf >= 0x10000000) { + mba = MBA_5 + (UBITS (decoder->bitstream_buf, 5) - 2); + break; + } else if (decoder->bitstream_buf >= 0x03000000) { + mba = MBA_11 + (UBITS (decoder->bitstream_buf, 11) - 24); + break; + } else switch (UBITS (decoder->bitstream_buf, 11)) { + case 8: /* macroblock_escape */ + mba_inc += 33; + /* pass through */ + case 15: /* macroblock_stuffing (MPEG1 only) */ + DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, 11); + NEEDBITS (decoder->bitstream_buf, decoder->bitstream_bits, decoder->bitstream_ptr); + continue; + default: /* end of slice/frame, or error? */ + { + ipuRegs->ctrl.SCD = 0; + coded_block_pattern=decoder->coded_block_pattern; + + g_BP.BP+=decoder->bitstream_bits-16; + + if((int)g_BP.BP < 0) { + g_BP.BP = 128 + (int)g_BP.BP; + + // After BP is positioned correctly, we need to reload the old buffer + // so that reading may continue properly + ReorderBitstream(); + } + + FillInternalBuffer(&g_BP.BP,1,0); + + waitForSCD(); + + *(int*)pdone = 1; + so_exit(); + } + } + } + DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, mba->len); + mba_inc += mba->mba; + + if (mba_inc) { + decoder->dc_dct_pred[0] = decoder->dc_dct_pred[1] = + decoder->dc_dct_pred[2] = 128 << decoder->intra_dc_precision; + do { + decoder->mbc++; + } while (--mba_inc); + } + } + } + + ipuRegs->ctrl.SCD = 0; + + coded_block_pattern=decoder->coded_block_pattern; + + g_BP.BP+=decoder->bitstream_bits-16; + + if((int)g_BP.BP < 0) { + g_BP.BP = 128 + (int)g_BP.BP; + + // After BP is positioned correctly, we need to reload the old buffer + // so that reading may continue properly + ReorderBitstream(); + } + + FillInternalBuffer(&g_BP.BP,1,0); + + waitForSCD(); + + *(int*)pdone = 1; + so_exit(); +} + +void mpeg2_slice(void* pdone) +{ + int DCT_offset, DCT_stride; + //u8 bit8=0; + //u32 fp = g_BP.FP; + u32 bp; + decoder_t * decoder = &g_decoder; + u32 size = 0; + + *(int*)pdone = 0; + ipuRegs->ctrl.ECD = 0; + + memzero_obj(*decoder->mb8); + memzero_obj(*decoder->mb16); + + bitstream_init (decoder); + + if (decoder->dcr) + decoder->dc_dct_pred[0] = decoder->dc_dct_pred[1] = + decoder->dc_dct_pred[2] = 128 << decoder->intra_dc_precision; + + if (decoder->macroblock_modes & DCT_TYPE_INTERLACED) { + DCT_offset = decoder->stride; + DCT_stride = decoder->stride * 2; + } else { + DCT_offset = decoder->stride * 8; + DCT_stride = decoder->stride; + } + if (decoder->macroblock_modes & MACROBLOCK_INTRA) { + decoder->coded_block_pattern = 0x3F;//all 6 blocks + slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y, DCT_stride); + slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y + 8, DCT_stride); + slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y + DCT_offset, DCT_stride); + slice_intra_DCT (decoder, 0, (u8*)decoder->mb8->Y + DCT_offset + 8, DCT_stride); + slice_intra_DCT (decoder, 1, (u8*)decoder->mb8->Cb, decoder->stride>>1); + slice_intra_DCT (decoder, 2, (u8*)decoder->mb8->Cr, decoder->stride>>1); + ipu_copy(decoder->mb8,decoder->mb16); + } else { + if (decoder->macroblock_modes & MACROBLOCK_PATTERN) { + decoder->coded_block_pattern = get_coded_block_pattern (decoder); + /* JayteeMaster: changed from mb8 to mb16 and from u8 to s16 */ + if (decoder->coded_block_pattern & 0x20) slice_non_intra_DCT (decoder, (s16*)decoder->mb16->Y, DCT_stride); + if (decoder->coded_block_pattern & 0x10) slice_non_intra_DCT (decoder, (s16*)decoder->mb16->Y + 8, DCT_stride); + if (decoder->coded_block_pattern & 0x08) slice_non_intra_DCT (decoder, (s16*)decoder->mb16->Y + DCT_offset, DCT_stride); + if (decoder->coded_block_pattern & 0x04) slice_non_intra_DCT (decoder, (s16*)decoder->mb16->Y + DCT_offset + 8, DCT_stride); + if (decoder->coded_block_pattern & 0x2) slice_non_intra_DCT (decoder, (s16*)decoder->mb16->Cb, decoder->stride>>1); + if (decoder->coded_block_pattern & 0x1) slice_non_intra_DCT (decoder, (s16*)decoder->mb16->Cr, decoder->stride>>1); + + } + } + + //Send The MacroBlock via DmaIpuFrom + size = 0; // Reset + + ipuRegs->ctrl.SCD=0; + coded_block_pattern=decoder->coded_block_pattern; + + bp = g_BP.BP; + g_BP.BP+=((int)decoder->bitstream_bits-16); + // BP goes from 0 to 128, so negative values mean to read old buffer + // so we minus from 128 to get the correct BP + if((int)g_BP.BP < 0) { + g_BP.BP = 128 + (int)g_BP.BP; + + // After BP is positioned correctly, we need to reload the old buffer + // so that reading may continue properly + ReorderBitstream(); + } + + FillInternalBuffer(&g_BP.BP,1,0); + + decoder->mbc = 1; + g_nIPU0Data = 48; + g_pIPU0Pointer = (u8*)decoder->mb16; + while(g_nIPU0Data > 0) { + size = FIFOfrom_write((u32*)g_pIPU0Pointer,g_nIPU0Data); + if( size == 0 ) + so_resume(); + else { + g_pIPU0Pointer += size*16; + g_nIPU0Data -= size; + } + } + + waitForSCD(); + + decoder->bitstream_bits = 0; + *(int*)pdone = 1; + so_exit(); +} + +int __forceinline get_motion_delta (decoder_t * const decoder, + const int f_code) +{ +#define bit_buf (decoder->bitstream_buf) +#define bits (decoder->bitstream_bits) +#define bit_ptr (decoder->bitstream_ptr) + + int delta; + int sign; + const MVtab * tab; + + if ( (bit_buf & 0x80000000) ) { + DUMPBITS (bit_buf, bits, 1); + return 0x00010000; + } else if ( (bit_buf & 0xf0000000) || ((bit_buf & 0xfc000000)==0x0c000000) ) { + + tab = MV_4 + UBITS (bit_buf, 4); + delta = (tab->delta << f_code) + 1; + bits += tab->len + f_code + 1; + bit_buf <<= tab->len; + + sign = SBITS (bit_buf, 1); + bit_buf <<= 1; + + if (f_code) + delta += UBITS (bit_buf, f_code); + bit_buf <<= f_code; + + return (delta ^ sign) - sign; + + } else { + + tab = MV_10 + UBITS (bit_buf, 10); + delta = (tab->delta << f_code) + 1; + bits += tab->len + 1; + bit_buf <<= tab->len; + + sign = SBITS (bit_buf, 1); + bit_buf <<= 1; + + if (f_code) { + NEEDBITS (bit_buf, bits, bit_ptr); + delta += UBITS (bit_buf, f_code); + DUMPBITS (bit_buf, bits, f_code); + } + + return (delta ^ sign) - sign; + + } +#undef bit_buf +#undef bits +#undef bit_ptr +} + +int __forceinline get_dmv (decoder_t * const decoder) +{ +#define bit_buf (decoder->bitstream_buf) +#define bits (decoder->bitstream_bits) +#define bit_ptr (decoder->bitstream_ptr) + + const DMVtab * tab; + + tab = DMV_2 + UBITS (bit_buf, 2); + DUMPBITS (bit_buf, bits, tab->len); + return tab->dmv; +#undef bit_buf +#undef bits +#undef bit_ptr +} + +int get_macroblock_address_increment(decoder_t * const decoder){ + const MBAtab *mba; + + if (decoder->bitstream_buf >= 0x10000000) + mba = MBA_5 + (UBITS (decoder->bitstream_buf, 5) - 2); + else if (decoder->bitstream_buf >= 0x03000000) + mba = MBA_11 + (UBITS (decoder->bitstream_buf, 11) - 24); + else switch (UBITS (decoder->bitstream_buf, 11)) { + case 8: /* macroblock_escape */ + DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, 11); + return 0x23; + case 15: /* macroblock_stuffing (MPEG1 only) */ + if (decoder->mpeg1){ + DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, 11); + return 0x22; + } + default: + return 0;//error + } + + DUMPBITS (decoder->bitstream_buf, decoder->bitstream_bits, mba->len); + return mba->mba + 1; +} diff --git a/pcsx2/IPU/mpeg2lib/Mpeg.h b/pcsx2/IPU/mpeg2lib/Mpeg.h index 8c21b78525..8e81ac0a10 100644 --- a/pcsx2/IPU/mpeg2lib/Mpeg.h +++ b/pcsx2/IPU/mpeg2lib/Mpeg.h @@ -1,203 +1,203 @@ -/* - * Mpeg.h - * Copyright (C) 2000-2002 Michel Lespinasse - * Copyright (C) 1999-2000 Aaron Holtzman - * Modified by Florin for PCSX2 emu - * - * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. - * See http://libmpeg2.sourceforge.net/ for updates. - * - * mpeg2dec 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. - * - * mpeg2dec 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 - */ - -#ifndef __MPEG_H__ -#define __MPEG_H__ - -/* macroblock modes */ -#define MACROBLOCK_INTRA 1 -#define MACROBLOCK_PATTERN 2 -#define MACROBLOCK_MOTION_BACKWARD 4 -#define MACROBLOCK_MOTION_FORWARD 8 -#define MACROBLOCK_QUANT 16 -#define DCT_TYPE_INTERLACED 32 -/* motion_type */ -#define MOTION_TYPE_SHIFT 6 -#define MOTION_TYPE_MASK (3*64) -#define MOTION_TYPE_BASE 64 -#define MC_FIELD (1*64) -#define MC_FRAME (2*64) -#define MC_16X8 (2*64) -#define MC_DMV (3*64) - -/* picture structure */ -#define TOP_FIELD 1 -#define BOTTOM_FIELD 2 -#define FRAME_PICTURE 3 - -/* picture coding type */ -#define I_TYPE 1 -#define P_TYPE 2 -#define B_TYPE 3 -#define D_TYPE 4 - -struct macroblock_8{ - unsigned char Y[16][16]; //0 - unsigned char Cb[8][8]; //1 - unsigned char Cr[8][8]; //2 -}; - -struct macroblock_16{ - short Y[16][16]; //0 - short Cb[8][8]; //1 - short Cr[8][8]; //2 -}; - -struct rgb32{ - unsigned char r, g, b, a; -}; - -struct macroblock_rgb32{ - struct rgb32 c[16][16]; -}; - -struct rgb16{ - unsigned short r:5, g:5, b:5, a:1; -}; - -struct macroblock_rgb16{ - struct rgb16 c[16][16]; -}; - -struct decoder_t { - /* first, state that carries information from one macroblock to the */ - /* next inside a slice, and is never used outside of mpeg2_slice() */ - - /* DCT coefficients - should be kept aligned ! */ - s16 DCTblock[64]; - - /* bit parsing stuff */ - u32 bitstream_buf; /* current 32 bit working set */ - int bitstream_bits; /* used bits in working set */ - u8 * bitstream_ptr; /* buffer with stream data; 128 bits buffer */ - - struct macroblock_8 *mb8; - struct macroblock_16 *mb16; - struct macroblock_rgb32 *rgb32; - struct macroblock_rgb16 *rgb16; - - int stride; - - /* predictor for DC coefficients in intra blocks */ - s16 dc_dct_pred[3]; - - int quantizer_scale; /* remove */ - int dmv_offset; /* remove */ - - /* now non-slice-specific information */ - - /* sequence header stuff */ - u8 *intra_quantizer_matrix; - u8 *non_intra_quantizer_matrix; - - /* picture header stuff */ - - /* what type of picture this is (I, P, B, D) */ - int coding_type; - - /* picture coding extension stuff */ - - /* quantization factor for intra dc coefficients */ - int intra_dc_precision; - /* top/bottom/both fields */ - int picture_structure; - /* bool to indicate all predictions are frame based */ - int frame_pred_frame_dct; - /* bool to indicate whether intra blocks have motion vectors */ - /* (for concealment) */ - int concealment_motion_vectors; - /* bit to indicate which quantization table to use */ - int q_scale_type; - /* bool to use different vlc tables */ - int intra_vlc_format; - /* used for DMV MC */ - int top_field_first; - // Pseudo Sign Offset - int sgn; - // Dither Enable - int dte; - // Output Format - int ofm; - // Macroblock count - int mbc; - // Macroblock type - int macroblock_modes; - // DC Reset - int dcr; - // Coded block pattern - int coded_block_pattern; - - /* stuff derived from bitstream */ - - /* pointer to the zigzag scan we're supposed to be using */ - const u8 * scan; - - int second_field; - - int mpeg1; -}; - -extern void (__fastcall *mpeg2_idct_copy) (s16 * block, u8* dest, int stride); -extern void (__fastcall *mpeg2_idct_add) (int last, s16 * block, - /*u8*/s16* dest, int stride); - -#define IDEC 0 -#define BDEC 1 - -void mpeg2sliceIDEC(void* pdone); -void mpeg2_slice(void* pdone); -int get_macroblock_address_increment(decoder_t * const decoder); -int get_macroblock_modes (decoder_t * const decoder); - -extern int get_motion_delta (decoder_t * const decoder, const int f_code); -extern int get_dmv (decoder_t * const decoder); - -extern int non_linear_quantizer_scale[]; -extern decoder_t g_decoder; - -void __fastcall ipu_csc(macroblock_8 *mb8, macroblock_rgb32 *rgb32, int sgn); -void __fastcall ipu_dither(macroblock_8 *mb8, macroblock_rgb16 *rgb16, int dte); -void __fastcall ipu_dither2(const macroblock_rgb32* rgb32, macroblock_rgb16 *rgb16, int dte); -void __fastcall ipu_vq(macroblock_rgb16 *rgb16, u8* indx4); -void __fastcall ipu_copy(const macroblock_8 *mb8, macroblock_16 *mb16); - -int slice (decoder_t * const decoder, u8 * buffer); -/* idct.c */ -void mpeg2_idct_init (); - -#ifdef _MSC_VER -#define BigEndian(out, in) out = _byteswap_ulong(in) -#else -//#define BigEndian(out, in) \ -// __asm__(".intel_syntax\n" \ -// "bswap %0\n" \ -// ".att_syntax\n" : "=r"(out) : "0"(in) ) - -#define BigEndian(out, in) \ - out = (((((in) >> 24) & 0xFF) << 0) + ((((in) >> 16) & 0xFF) << 8) + \ - ((((in) >> 8) & 0xFF) << 16) + ((((in) >> 0) & 0xFF) << 24)); - -#endif - -#endif//__MPEG_H__ +/* + * Mpeg.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * Modified by Florin for PCSX2 emu + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * See http://libmpeg2.sourceforge.net/ for updates. + * + * mpeg2dec 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. + * + * mpeg2dec 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 + */ + +#ifndef __MPEG_H__ +#define __MPEG_H__ + +/* macroblock modes */ +#define MACROBLOCK_INTRA 1 +#define MACROBLOCK_PATTERN 2 +#define MACROBLOCK_MOTION_BACKWARD 4 +#define MACROBLOCK_MOTION_FORWARD 8 +#define MACROBLOCK_QUANT 16 +#define DCT_TYPE_INTERLACED 32 +/* motion_type */ +#define MOTION_TYPE_SHIFT 6 +#define MOTION_TYPE_MASK (3*64) +#define MOTION_TYPE_BASE 64 +#define MC_FIELD (1*64) +#define MC_FRAME (2*64) +#define MC_16X8 (2*64) +#define MC_DMV (3*64) + +/* picture structure */ +#define TOP_FIELD 1 +#define BOTTOM_FIELD 2 +#define FRAME_PICTURE 3 + +/* picture coding type */ +#define I_TYPE 1 +#define P_TYPE 2 +#define B_TYPE 3 +#define D_TYPE 4 + +struct macroblock_8{ + unsigned char Y[16][16]; //0 + unsigned char Cb[8][8]; //1 + unsigned char Cr[8][8]; //2 +}; + +struct macroblock_16{ + short Y[16][16]; //0 + short Cb[8][8]; //1 + short Cr[8][8]; //2 +}; + +struct rgb32{ + unsigned char r, g, b, a; +}; + +struct macroblock_rgb32{ + struct rgb32 c[16][16]; +}; + +struct rgb16{ + unsigned short r:5, g:5, b:5, a:1; +}; + +struct macroblock_rgb16{ + struct rgb16 c[16][16]; +}; + +struct decoder_t { + /* first, state that carries information from one macroblock to the */ + /* next inside a slice, and is never used outside of mpeg2_slice() */ + + /* DCT coefficients - should be kept aligned ! */ + s16 DCTblock[64]; + + /* bit parsing stuff */ + u32 bitstream_buf; /* current 32 bit working set */ + int bitstream_bits; /* used bits in working set */ + u8 * bitstream_ptr; /* buffer with stream data; 128 bits buffer */ + + struct macroblock_8 *mb8; + struct macroblock_16 *mb16; + struct macroblock_rgb32 *rgb32; + struct macroblock_rgb16 *rgb16; + + int stride; + + /* predictor for DC coefficients in intra blocks */ + s16 dc_dct_pred[3]; + + int quantizer_scale; /* remove */ + int dmv_offset; /* remove */ + + /* now non-slice-specific information */ + + /* sequence header stuff */ + u8 *intra_quantizer_matrix; + u8 *non_intra_quantizer_matrix; + + /* picture header stuff */ + + /* what type of picture this is (I, P, B, D) */ + int coding_type; + + /* picture coding extension stuff */ + + /* quantization factor for intra dc coefficients */ + int intra_dc_precision; + /* top/bottom/both fields */ + int picture_structure; + /* bool to indicate all predictions are frame based */ + int frame_pred_frame_dct; + /* bool to indicate whether intra blocks have motion vectors */ + /* (for concealment) */ + int concealment_motion_vectors; + /* bit to indicate which quantization table to use */ + int q_scale_type; + /* bool to use different vlc tables */ + int intra_vlc_format; + /* used for DMV MC */ + int top_field_first; + // Pseudo Sign Offset + int sgn; + // Dither Enable + int dte; + // Output Format + int ofm; + // Macroblock count + int mbc; + // Macroblock type + int macroblock_modes; + // DC Reset + int dcr; + // Coded block pattern + int coded_block_pattern; + + /* stuff derived from bitstream */ + + /* pointer to the zigzag scan we're supposed to be using */ + const u8 * scan; + + int second_field; + + int mpeg1; +}; + +extern void (__fastcall *mpeg2_idct_copy) (s16 * block, u8* dest, int stride); +extern void (__fastcall *mpeg2_idct_add) (int last, s16 * block, + /*u8*/s16* dest, int stride); + +#define IDEC 0 +#define BDEC 1 + +void mpeg2sliceIDEC(void* pdone); +void mpeg2_slice(void* pdone); +int get_macroblock_address_increment(decoder_t * const decoder); +int get_macroblock_modes (decoder_t * const decoder); + +extern int get_motion_delta (decoder_t * const decoder, const int f_code); +extern int get_dmv (decoder_t * const decoder); + +extern int non_linear_quantizer_scale[]; +extern decoder_t g_decoder; + +void __fastcall ipu_csc(macroblock_8 *mb8, macroblock_rgb32 *rgb32, int sgn); +void __fastcall ipu_dither(macroblock_8 *mb8, macroblock_rgb16 *rgb16, int dte); +void __fastcall ipu_dither2(const macroblock_rgb32* rgb32, macroblock_rgb16 *rgb16, int dte); +void __fastcall ipu_vq(macroblock_rgb16 *rgb16, u8* indx4); +void __fastcall ipu_copy(const macroblock_8 *mb8, macroblock_16 *mb16); + +int slice (decoder_t * const decoder, u8 * buffer); +/* idct.c */ +void mpeg2_idct_init (); + +#ifdef _MSC_VER +#define BigEndian(out, in) out = _byteswap_ulong(in) +#else +//#define BigEndian(out, in) \ +// __asm__(".intel_syntax\n" \ +// "bswap %0\n" \ +// ".att_syntax\n" : "=r"(out) : "0"(in) ) + +#define BigEndian(out, in) \ + out = (((((in) >> 24) & 0xFF) << 0) + ((((in) >> 16) & 0xFF) << 8) + \ + ((((in) >> 8) & 0xFF) << 16) + ((((in) >> 0) & 0xFF) << 24)); + +#endif + +#endif//__MPEG_H__ diff --git a/pcsx2/IPU/mpeg2lib/Vlc.h b/pcsx2/IPU/mpeg2lib/Vlc.h index 495d9ce9bd..10d3353949 100644 --- a/pcsx2/IPU/mpeg2lib/Vlc.h +++ b/pcsx2/IPU/mpeg2lib/Vlc.h @@ -1,446 +1,446 @@ -/* - * vlc.h - * Copyright (C) 2000-2002 Michel Lespinasse - * Copyright (C) 1999-2000 Aaron Holtzman - * Modified by Florin for PCSX2 emu - * - * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. - * See http://libmpeg2.sourceforge.net/ for updates. - * - * mpeg2dec 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. - * - * mpeg2dec 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 - */ - -#ifndef __VLC_H__ -#define __VLC_H__ - -#include "coroutine.h" - -static u8 data[2]; -static u8 dword[4]; -extern tIPU_BP g_BP; -extern decoder_t g_decoder; -extern void ReorderBitstream(); - -static __forceinline void GETWORD(u32 * bit_buf,int bits) -{ - while(!getBits16(data,1)) - { - so_resume(); - } - *bit_buf |= ((data[0] << 8) | data[1]) << (bits); -} - -static __forceinline void bitstream_init (decoder_t * decoder){ - decoder->bitstream_bits = -16; - - while( !getBits32(dword, 1) ) - so_resume(); - - decoder->bitstream_buf = (dword[0] << 24) | (dword[1] << 16) | - (dword[2] << 8) |dword[3]; -} - -/* make sure that there are at least 16 valid bits in bit_buf */ -#define NEEDBITS(bit_buf,bits,bit_ptr) \ -do { \ - if (bits > 0) { \ - GETWORD(&bit_buf,bits); \ - bits -= 16; \ - } \ -} while (0) - -/* remove num valid bits from bit_buf */ -#define DUMPBITS(bit_buf,bits,num) \ -do { \ - /*IPU_LOG("DUMPBITS %d\n",num);*/ \ - bit_buf <<= (num); \ - bits += (num); \ -} while (0) - -/* take num bits from the high part of bit_buf and zero extend them */ -#define UBITS(bit_buf,num) (((u32)(bit_buf)) >> (32 - (num))) - -/* take num bits from the high part of bit_buf and sign extend them */ -#define SBITS(bit_buf,num) (((s32)(bit_buf)) >> (32 - (num))) - -struct MBtab { - u8 modes; - u8 len; -}; - -struct MVtab { - u8 delta; - u8 len; -}; - -struct DMVtab { - s8 dmv; - u8 len; -}; - -struct CBPtab { - u8 cbp; - u8 len; -}; - -struct DCtab { - u8 size; - u8 len; -}; - -struct DCTtab { - u8 run; - u8 level; - u8 len; -}; - -struct MBAtab { - u8 mba; - u8 len; -}; - - -#define INTRA MACROBLOCK_INTRA -#define QUANT MACROBLOCK_QUANT - -static const MBtab MB_I [] = { - {INTRA|QUANT, 2}, {INTRA, 1} -}; - -#define MC MACROBLOCK_MOTION_FORWARD -#define CODED MACROBLOCK_PATTERN - -static const MBtab MB_P [] = { - {INTRA|QUANT, 6}, {CODED|QUANT, 5}, {MC|CODED|QUANT, 5}, {INTRA, 5}, - {MC, 3}, {MC, 3}, {MC, 3}, {MC, 3}, - {CODED, 2}, {CODED, 2}, {CODED, 2}, {CODED, 2}, - {CODED, 2}, {CODED, 2}, {CODED, 2}, {CODED, 2}, - {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, - {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, - {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, - {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1} -}; - -#define FWD MACROBLOCK_MOTION_FORWARD -#define BWD MACROBLOCK_MOTION_BACKWARD -#define INTER MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD - -static const MBtab MB_B [] = { - {0, 0}, {INTRA|QUANT, 6}, - {BWD|CODED|QUANT, 6}, {FWD|CODED|QUANT, 6}, - {INTER|CODED|QUANT, 5}, {INTER|CODED|QUANT, 5}, - {INTRA, 5}, {INTRA, 5}, - {FWD, 4}, {FWD, 4}, {FWD, 4}, {FWD, 4}, - {FWD|CODED, 4}, {FWD|CODED, 4}, {FWD|CODED, 4}, {FWD|CODED, 4}, - {BWD, 3}, {BWD, 3}, {BWD, 3}, {BWD, 3}, - {BWD, 3}, {BWD, 3}, {BWD, 3}, {BWD, 3}, - {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, - {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, - {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, - {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, - {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, - {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, - {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, - {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, - {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, - {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2} -}; - -#undef INTRA -#undef QUANT -#undef MC -#undef CODED -#undef FWD -#undef BWD -#undef INTER - - -static const MVtab MV_4 [] = { - { 3, 6}, { 2, 4}, { 1, 3}, { 1, 3}, { 0, 2}, { 0, 2}, { 0, 2}, { 0, 2} -}; - -static const MVtab MV_10 [] = { - { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, - { 0,10}, { 0,10}, { 0,10}, { 0,10}, {15,10}, {14,10}, {13,10}, {12,10}, - {11,10}, {10,10}, { 9, 9}, { 9, 9}, { 8, 9}, { 8, 9}, { 7, 9}, { 7, 9}, - { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, - { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, - { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7} -}; - - -static const DMVtab DMV_2 [] = { - { 0, 1}, { 0, 1}, { 1, 2}, {-1, 2} -}; - - -static const CBPtab CBP_7 [] = { - {0x22, 7}, {0x12, 7}, {0x0a, 7}, {0x06, 7}, - {0x21, 7}, {0x11, 7}, {0x09, 7}, {0x05, 7}, - {0x3f, 6}, {0x3f, 6}, {0x03, 6}, {0x03, 6}, - {0x24, 6}, {0x24, 6}, {0x18, 6}, {0x18, 6}, - {0x3e, 5}, {0x3e, 5}, {0x3e, 5}, {0x3e, 5}, - {0x02, 5}, {0x02, 5}, {0x02, 5}, {0x02, 5}, - {0x3d, 5}, {0x3d, 5}, {0x3d, 5}, {0x3d, 5}, - {0x01, 5}, {0x01, 5}, {0x01, 5}, {0x01, 5}, - {0x38, 5}, {0x38, 5}, {0x38, 5}, {0x38, 5}, - {0x34, 5}, {0x34, 5}, {0x34, 5}, {0x34, 5}, - {0x2c, 5}, {0x2c, 5}, {0x2c, 5}, {0x2c, 5}, - {0x1c, 5}, {0x1c, 5}, {0x1c, 5}, {0x1c, 5}, - {0x28, 5}, {0x28, 5}, {0x28, 5}, {0x28, 5}, - {0x14, 5}, {0x14, 5}, {0x14, 5}, {0x14, 5}, - {0x30, 5}, {0x30, 5}, {0x30, 5}, {0x30, 5}, - {0x0c, 5}, {0x0c, 5}, {0x0c, 5}, {0x0c, 5}, - {0x20, 4}, {0x20, 4}, {0x20, 4}, {0x20, 4}, - {0x20, 4}, {0x20, 4}, {0x20, 4}, {0x20, 4}, - {0x10, 4}, {0x10, 4}, {0x10, 4}, {0x10, 4}, - {0x10, 4}, {0x10, 4}, {0x10, 4}, {0x10, 4}, - {0x08, 4}, {0x08, 4}, {0x08, 4}, {0x08, 4}, - {0x08, 4}, {0x08, 4}, {0x08, 4}, {0x08, 4}, - {0x04, 4}, {0x04, 4}, {0x04, 4}, {0x04, 4}, - {0x04, 4}, {0x04, 4}, {0x04, 4}, {0x04, 4}, - {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, - {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, - {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, - {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3} -}; - -static const CBPtab CBP_9 [] = { - {0, 0}, {0x00, 9}, {0x27, 9}, {0x1b, 9}, - {0x3b, 9}, {0x37, 9}, {0x2f, 9}, {0x1f, 9}, - {0x3a, 8}, {0x3a, 8}, {0x36, 8}, {0x36, 8}, - {0x2e, 8}, {0x2e, 8}, {0x1e, 8}, {0x1e, 8}, - {0x39, 8}, {0x39, 8}, {0x35, 8}, {0x35, 8}, - {0x2d, 8}, {0x2d, 8}, {0x1d, 8}, {0x1d, 8}, - {0x26, 8}, {0x26, 8}, {0x1a, 8}, {0x1a, 8}, - {0x25, 8}, {0x25, 8}, {0x19, 8}, {0x19, 8}, - {0x2b, 8}, {0x2b, 8}, {0x17, 8}, {0x17, 8}, - {0x33, 8}, {0x33, 8}, {0x0f, 8}, {0x0f, 8}, - {0x2a, 8}, {0x2a, 8}, {0x16, 8}, {0x16, 8}, - {0x32, 8}, {0x32, 8}, {0x0e, 8}, {0x0e, 8}, - {0x29, 8}, {0x29, 8}, {0x15, 8}, {0x15, 8}, - {0x31, 8}, {0x31, 8}, {0x0d, 8}, {0x0d, 8}, - {0x23, 8}, {0x23, 8}, {0x13, 8}, {0x13, 8}, - {0x0b, 8}, {0x0b, 8}, {0x07, 8}, {0x07, 8} -}; - -static const DCtab DC_lum_5 [] = { - {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, - {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, - {0, 3}, {0, 3}, {0, 3}, {0, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, - {4, 3}, {4, 3}, {4, 3}, {4, 3}, {5, 4}, {5, 4}, {6, 5} -}; - -static const DCtab DC_chrom_5 [] = { - {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, - {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, - {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, - {3, 3}, {3, 3}, {3, 3}, {3, 3}, {4, 4}, {4, 4}, {5, 5} -}; - -static const DCtab DC_long [] = { - {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, { 6, 5}, { 6, 5}, - {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, { 6, 5}, { 6, 5}, - {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, { 7, 6}, { 7, 6}, - {8, 7}, {8, 7}, {8, 7}, {8, 7}, {9, 8}, {9, 8}, {10, 9}, {11, 9} -}; - - -static const DCTtab DCT_16 [] = { - {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, - {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, - {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, - {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, - { 2,18, 0}, { 2,17, 0}, { 2,16, 0}, { 2,15, 0}, - { 7, 3, 0}, { 17, 2, 0}, { 16, 2, 0}, { 15, 2, 0}, - { 14, 2, 0}, { 13, 2, 0}, { 12, 2, 0}, { 32, 1, 0}, - { 31, 1, 0}, { 30, 1, 0}, { 29, 1, 0}, { 28, 1, 0} -}; - -static const DCTtab DCT_15 [] = { - { 1,40,15}, { 1,39,15}, { 1,38,15}, { 1,37,15}, - { 1,36,15}, { 1,35,15}, { 1,34,15}, { 1,33,15}, - { 1,32,15}, { 2,14,15}, { 2,13,15}, { 2,12,15}, - { 2,11,15}, { 2,10,15}, { 2, 9,15}, { 2, 8,15}, - { 1,31,14}, { 1,31,14}, { 1,30,14}, { 1,30,14}, - { 1,29,14}, { 1,29,14}, { 1,28,14}, { 1,28,14}, - { 1,27,14}, { 1,27,14}, { 1,26,14}, { 1,26,14}, - { 1,25,14}, { 1,25,14}, { 1,24,14}, { 1,24,14}, - { 1,23,14}, { 1,23,14}, { 1,22,14}, { 1,22,14}, - { 1,21,14}, { 1,21,14}, { 1,20,14}, { 1,20,14}, - { 1,19,14}, { 1,19,14}, { 1,18,14}, { 1,18,14}, - { 1,17,14}, { 1,17,14}, { 1,16,14}, { 1,16,14} -}; - -static const DCTtab DCT_13 [] = { - { 11, 2,13}, { 10, 2,13}, { 6, 3,13}, { 4, 4,13}, - { 3, 5,13}, { 2, 7,13}, { 2, 6,13}, { 1,15,13}, - { 1,14,13}, { 1,13,13}, { 1,12,13}, { 27, 1,13}, - { 26, 1,13}, { 25, 1,13}, { 24, 1,13}, { 23, 1,13}, - { 1,11,12}, { 1,11,12}, { 9, 2,12}, { 9, 2,12}, - { 5, 3,12}, { 5, 3,12}, { 1,10,12}, { 1,10,12}, - { 3, 4,12}, { 3, 4,12}, { 8, 2,12}, { 8, 2,12}, - { 22, 1,12}, { 22, 1,12}, { 21, 1,12}, { 21, 1,12}, - { 1, 9,12}, { 1, 9,12}, { 20, 1,12}, { 20, 1,12}, - { 19, 1,12}, { 19, 1,12}, { 2, 5,12}, { 2, 5,12}, - { 4, 3,12}, { 4, 3,12}, { 1, 8,12}, { 1, 8,12}, - { 7, 2,12}, { 7, 2,12}, { 18, 1,12}, { 18, 1,12} -}; - -static const DCTtab DCT_B14_10 [] = { - { 17, 1,10}, { 6, 2,10}, { 1, 7,10}, { 3, 3,10}, - { 2, 4,10}, { 16, 1,10}, { 15, 1,10}, { 5, 2,10} -}; - -static const DCTtab DCT_B14_8 [] = { - { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, - { 3, 2, 7}, { 3, 2, 7}, { 10, 1, 7}, { 10, 1, 7}, - { 1, 4, 7}, { 1, 4, 7}, { 9, 1, 7}, { 9, 1, 7}, - { 8, 1, 6}, { 8, 1, 6}, { 8, 1, 6}, { 8, 1, 6}, - { 7, 1, 6}, { 7, 1, 6}, { 7, 1, 6}, { 7, 1, 6}, - { 2, 2, 6}, { 2, 2, 6}, { 2, 2, 6}, { 2, 2, 6}, - { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, - { 14, 1, 8}, { 1, 6, 8}, { 13, 1, 8}, { 12, 1, 8}, - { 4, 2, 8}, { 2, 3, 8}, { 1, 5, 8}, { 11, 1, 8} -}; - -static const DCTtab DCT_B14AC_5 [] = { - { 1, 3, 5}, { 5, 1, 5}, { 4, 1, 5}, - { 1, 2, 4}, { 1, 2, 4}, { 3, 1, 4}, { 3, 1, 4}, - { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, - {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, - {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, - { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, - { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2} -}; - -static const DCTtab DCT_B14DC_5 [] = { - { 1, 3, 5}, { 5, 1, 5}, { 4, 1, 5}, - { 1, 2, 4}, { 1, 2, 4}, { 3, 1, 4}, { 3, 1, 4}, - { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, - { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, - { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, - { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, - { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1} -}; - -static const DCTtab DCT_B15_10 [] = { - { 6, 2, 9}, { 6, 2, 9}, { 15, 1, 9}, { 15, 1, 9}, - { 3, 4,10}, { 17, 1,10}, { 16, 1, 9}, { 16, 1, 9} -}; - -static const DCTtab DCT_B15_8 [] = { - { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, - { 8, 1, 7}, { 8, 1, 7}, { 9, 1, 7}, { 9, 1, 7}, - { 7, 1, 7}, { 7, 1, 7}, { 3, 2, 7}, { 3, 2, 7}, - { 1, 7, 6}, { 1, 7, 6}, { 1, 7, 6}, { 1, 7, 6}, - { 1, 6, 6}, { 1, 6, 6}, { 1, 6, 6}, { 1, 6, 6}, - { 5, 1, 6}, { 5, 1, 6}, { 5, 1, 6}, { 5, 1, 6}, - { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, - { 2, 5, 8}, { 12, 1, 8}, { 1,11, 8}, { 1,10, 8}, - { 14, 1, 8}, { 13, 1, 8}, { 4, 2, 8}, { 2, 4, 8}, - { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, - { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, - { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, - { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, - { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, - { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, - { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, - { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, - { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, - { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, - { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, - { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, - { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, - { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, - {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, - {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, - {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, - {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, - { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, - { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, - { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, - { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, - { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, - { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, - { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, - { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, - { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, - { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, - { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, - { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, - { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, - { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, - { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, - { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, - { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, - { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, - { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, - { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, - { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, - { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, - { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, - { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, - { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, - { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, - { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, - { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, - { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, - { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, - { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, - { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, - { 10, 1, 7}, { 10, 1, 7}, { 2, 3, 7}, { 2, 3, 7}, - { 11, 1, 7}, { 11, 1, 7}, { 1, 8, 7}, { 1, 8, 7}, - { 1, 9, 7}, { 1, 9, 7}, { 1,12, 8}, { 1,13, 8}, - { 3, 3, 8}, { 5, 2, 8}, { 1,14, 8}, { 1,15, 8} -}; - - -static const MBAtab MBA_5 [] = { - {6, 5}, {5, 5}, {4, 4}, {4, 4}, {3, 4}, {3, 4}, - {2, 3}, {2, 3}, {2, 3}, {2, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, - {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, - {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1} -}; - -static const MBAtab MBA_11 [] = { - {32, 11}, {31, 11}, {30, 11}, {29, 11}, - {28, 11}, {27, 11}, {26, 11}, {25, 11}, - {24, 11}, {23, 11}, {22, 11}, {21, 11}, - {20, 10}, {20, 10}, {19, 10}, {19, 10}, - {18, 10}, {18, 10}, {17, 10}, {17, 10}, - {16, 10}, {16, 10}, {15, 10}, {15, 10}, - {14, 8}, {14, 8}, {14, 8}, {14, 8}, - {14, 8}, {14, 8}, {14, 8}, {14, 8}, - {13, 8}, {13, 8}, {13, 8}, {13, 8}, - {13, 8}, {13, 8}, {13, 8}, {13, 8}, - {12, 8}, {12, 8}, {12, 8}, {12, 8}, - {12, 8}, {12, 8}, {12, 8}, {12, 8}, - {11, 8}, {11, 8}, {11, 8}, {11, 8}, - {11, 8}, {11, 8}, {11, 8}, {11, 8}, - {10, 8}, {10, 8}, {10, 8}, {10, 8}, - {10, 8}, {10, 8}, {10, 8}, {10, 8}, - { 9, 8}, { 9, 8}, { 9, 8}, { 9, 8}, - { 9, 8}, { 9, 8}, { 9, 8}, { 9, 8}, - { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, - { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, - { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, - { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, - { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7}, - { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7}, - { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7}, - { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7} -}; -#endif//__VLC_H__ +/* + * vlc.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * Modified by Florin for PCSX2 emu + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * See http://libmpeg2.sourceforge.net/ for updates. + * + * mpeg2dec 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. + * + * mpeg2dec 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 + */ + +#ifndef __VLC_H__ +#define __VLC_H__ + +#include "coroutine.h" + +static u8 data[2]; +static u8 dword[4]; +extern tIPU_BP g_BP; +extern decoder_t g_decoder; +extern void ReorderBitstream(); + +static __forceinline void GETWORD(u32 * bit_buf,int bits) +{ + while(!getBits16(data,1)) + { + so_resume(); + } + *bit_buf |= ((data[0] << 8) | data[1]) << (bits); +} + +static __forceinline void bitstream_init (decoder_t * decoder){ + decoder->bitstream_bits = -16; + + while( !getBits32(dword, 1) ) + so_resume(); + + decoder->bitstream_buf = (dword[0] << 24) | (dword[1] << 16) | + (dword[2] << 8) |dword[3]; +} + +/* make sure that there are at least 16 valid bits in bit_buf */ +#define NEEDBITS(bit_buf,bits,bit_ptr) \ +do { \ + if (bits > 0) { \ + GETWORD(&bit_buf,bits); \ + bits -= 16; \ + } \ +} while (0) + +/* remove num valid bits from bit_buf */ +#define DUMPBITS(bit_buf,bits,num) \ +do { \ + /*IPU_LOG("DUMPBITS %d\n",num);*/ \ + bit_buf <<= (num); \ + bits += (num); \ +} while (0) + +/* take num bits from the high part of bit_buf and zero extend them */ +#define UBITS(bit_buf,num) (((u32)(bit_buf)) >> (32 - (num))) + +/* take num bits from the high part of bit_buf and sign extend them */ +#define SBITS(bit_buf,num) (((s32)(bit_buf)) >> (32 - (num))) + +struct MBtab { + u8 modes; + u8 len; +}; + +struct MVtab { + u8 delta; + u8 len; +}; + +struct DMVtab { + s8 dmv; + u8 len; +}; + +struct CBPtab { + u8 cbp; + u8 len; +}; + +struct DCtab { + u8 size; + u8 len; +}; + +struct DCTtab { + u8 run; + u8 level; + u8 len; +}; + +struct MBAtab { + u8 mba; + u8 len; +}; + + +#define INTRA MACROBLOCK_INTRA +#define QUANT MACROBLOCK_QUANT + +static const MBtab MB_I [] = { + {INTRA|QUANT, 2}, {INTRA, 1} +}; + +#define MC MACROBLOCK_MOTION_FORWARD +#define CODED MACROBLOCK_PATTERN + +static const MBtab MB_P [] = { + {INTRA|QUANT, 6}, {CODED|QUANT, 5}, {MC|CODED|QUANT, 5}, {INTRA, 5}, + {MC, 3}, {MC, 3}, {MC, 3}, {MC, 3}, + {CODED, 2}, {CODED, 2}, {CODED, 2}, {CODED, 2}, + {CODED, 2}, {CODED, 2}, {CODED, 2}, {CODED, 2}, + {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, + {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, + {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, + {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1} +}; + +#define FWD MACROBLOCK_MOTION_FORWARD +#define BWD MACROBLOCK_MOTION_BACKWARD +#define INTER MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD + +static const MBtab MB_B [] = { + {0, 0}, {INTRA|QUANT, 6}, + {BWD|CODED|QUANT, 6}, {FWD|CODED|QUANT, 6}, + {INTER|CODED|QUANT, 5}, {INTER|CODED|QUANT, 5}, + {INTRA, 5}, {INTRA, 5}, + {FWD, 4}, {FWD, 4}, {FWD, 4}, {FWD, 4}, + {FWD|CODED, 4}, {FWD|CODED, 4}, {FWD|CODED, 4}, {FWD|CODED, 4}, + {BWD, 3}, {BWD, 3}, {BWD, 3}, {BWD, 3}, + {BWD, 3}, {BWD, 3}, {BWD, 3}, {BWD, 3}, + {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, + {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, + {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, + {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, + {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, + {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, + {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, + {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, + {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, + {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2} +}; + +#undef INTRA +#undef QUANT +#undef MC +#undef CODED +#undef FWD +#undef BWD +#undef INTER + + +static const MVtab MV_4 [] = { + { 3, 6}, { 2, 4}, { 1, 3}, { 1, 3}, { 0, 2}, { 0, 2}, { 0, 2}, { 0, 2} +}; + +static const MVtab MV_10 [] = { + { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, + { 0,10}, { 0,10}, { 0,10}, { 0,10}, {15,10}, {14,10}, {13,10}, {12,10}, + {11,10}, {10,10}, { 9, 9}, { 9, 9}, { 8, 9}, { 8, 9}, { 7, 9}, { 7, 9}, + { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, + { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, + { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7} +}; + + +static const DMVtab DMV_2 [] = { + { 0, 1}, { 0, 1}, { 1, 2}, {-1, 2} +}; + + +static const CBPtab CBP_7 [] = { + {0x22, 7}, {0x12, 7}, {0x0a, 7}, {0x06, 7}, + {0x21, 7}, {0x11, 7}, {0x09, 7}, {0x05, 7}, + {0x3f, 6}, {0x3f, 6}, {0x03, 6}, {0x03, 6}, + {0x24, 6}, {0x24, 6}, {0x18, 6}, {0x18, 6}, + {0x3e, 5}, {0x3e, 5}, {0x3e, 5}, {0x3e, 5}, + {0x02, 5}, {0x02, 5}, {0x02, 5}, {0x02, 5}, + {0x3d, 5}, {0x3d, 5}, {0x3d, 5}, {0x3d, 5}, + {0x01, 5}, {0x01, 5}, {0x01, 5}, {0x01, 5}, + {0x38, 5}, {0x38, 5}, {0x38, 5}, {0x38, 5}, + {0x34, 5}, {0x34, 5}, {0x34, 5}, {0x34, 5}, + {0x2c, 5}, {0x2c, 5}, {0x2c, 5}, {0x2c, 5}, + {0x1c, 5}, {0x1c, 5}, {0x1c, 5}, {0x1c, 5}, + {0x28, 5}, {0x28, 5}, {0x28, 5}, {0x28, 5}, + {0x14, 5}, {0x14, 5}, {0x14, 5}, {0x14, 5}, + {0x30, 5}, {0x30, 5}, {0x30, 5}, {0x30, 5}, + {0x0c, 5}, {0x0c, 5}, {0x0c, 5}, {0x0c, 5}, + {0x20, 4}, {0x20, 4}, {0x20, 4}, {0x20, 4}, + {0x20, 4}, {0x20, 4}, {0x20, 4}, {0x20, 4}, + {0x10, 4}, {0x10, 4}, {0x10, 4}, {0x10, 4}, + {0x10, 4}, {0x10, 4}, {0x10, 4}, {0x10, 4}, + {0x08, 4}, {0x08, 4}, {0x08, 4}, {0x08, 4}, + {0x08, 4}, {0x08, 4}, {0x08, 4}, {0x08, 4}, + {0x04, 4}, {0x04, 4}, {0x04, 4}, {0x04, 4}, + {0x04, 4}, {0x04, 4}, {0x04, 4}, {0x04, 4}, + {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, + {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, + {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, + {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3} +}; + +static const CBPtab CBP_9 [] = { + {0, 0}, {0x00, 9}, {0x27, 9}, {0x1b, 9}, + {0x3b, 9}, {0x37, 9}, {0x2f, 9}, {0x1f, 9}, + {0x3a, 8}, {0x3a, 8}, {0x36, 8}, {0x36, 8}, + {0x2e, 8}, {0x2e, 8}, {0x1e, 8}, {0x1e, 8}, + {0x39, 8}, {0x39, 8}, {0x35, 8}, {0x35, 8}, + {0x2d, 8}, {0x2d, 8}, {0x1d, 8}, {0x1d, 8}, + {0x26, 8}, {0x26, 8}, {0x1a, 8}, {0x1a, 8}, + {0x25, 8}, {0x25, 8}, {0x19, 8}, {0x19, 8}, + {0x2b, 8}, {0x2b, 8}, {0x17, 8}, {0x17, 8}, + {0x33, 8}, {0x33, 8}, {0x0f, 8}, {0x0f, 8}, + {0x2a, 8}, {0x2a, 8}, {0x16, 8}, {0x16, 8}, + {0x32, 8}, {0x32, 8}, {0x0e, 8}, {0x0e, 8}, + {0x29, 8}, {0x29, 8}, {0x15, 8}, {0x15, 8}, + {0x31, 8}, {0x31, 8}, {0x0d, 8}, {0x0d, 8}, + {0x23, 8}, {0x23, 8}, {0x13, 8}, {0x13, 8}, + {0x0b, 8}, {0x0b, 8}, {0x07, 8}, {0x07, 8} +}; + +static const DCtab DC_lum_5 [] = { + {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, + {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, + {0, 3}, {0, 3}, {0, 3}, {0, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, + {4, 3}, {4, 3}, {4, 3}, {4, 3}, {5, 4}, {5, 4}, {6, 5} +}; + +static const DCtab DC_chrom_5 [] = { + {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, + {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, + {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, + {3, 3}, {3, 3}, {3, 3}, {3, 3}, {4, 4}, {4, 4}, {5, 5} +}; + +static const DCtab DC_long [] = { + {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, { 6, 5}, { 6, 5}, + {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, { 6, 5}, { 6, 5}, + {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, { 7, 6}, { 7, 6}, + {8, 7}, {8, 7}, {8, 7}, {8, 7}, {9, 8}, {9, 8}, {10, 9}, {11, 9} +}; + + +static const DCTtab DCT_16 [] = { + {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, + {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, + {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, + {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, + { 2,18, 0}, { 2,17, 0}, { 2,16, 0}, { 2,15, 0}, + { 7, 3, 0}, { 17, 2, 0}, { 16, 2, 0}, { 15, 2, 0}, + { 14, 2, 0}, { 13, 2, 0}, { 12, 2, 0}, { 32, 1, 0}, + { 31, 1, 0}, { 30, 1, 0}, { 29, 1, 0}, { 28, 1, 0} +}; + +static const DCTtab DCT_15 [] = { + { 1,40,15}, { 1,39,15}, { 1,38,15}, { 1,37,15}, + { 1,36,15}, { 1,35,15}, { 1,34,15}, { 1,33,15}, + { 1,32,15}, { 2,14,15}, { 2,13,15}, { 2,12,15}, + { 2,11,15}, { 2,10,15}, { 2, 9,15}, { 2, 8,15}, + { 1,31,14}, { 1,31,14}, { 1,30,14}, { 1,30,14}, + { 1,29,14}, { 1,29,14}, { 1,28,14}, { 1,28,14}, + { 1,27,14}, { 1,27,14}, { 1,26,14}, { 1,26,14}, + { 1,25,14}, { 1,25,14}, { 1,24,14}, { 1,24,14}, + { 1,23,14}, { 1,23,14}, { 1,22,14}, { 1,22,14}, + { 1,21,14}, { 1,21,14}, { 1,20,14}, { 1,20,14}, + { 1,19,14}, { 1,19,14}, { 1,18,14}, { 1,18,14}, + { 1,17,14}, { 1,17,14}, { 1,16,14}, { 1,16,14} +}; + +static const DCTtab DCT_13 [] = { + { 11, 2,13}, { 10, 2,13}, { 6, 3,13}, { 4, 4,13}, + { 3, 5,13}, { 2, 7,13}, { 2, 6,13}, { 1,15,13}, + { 1,14,13}, { 1,13,13}, { 1,12,13}, { 27, 1,13}, + { 26, 1,13}, { 25, 1,13}, { 24, 1,13}, { 23, 1,13}, + { 1,11,12}, { 1,11,12}, { 9, 2,12}, { 9, 2,12}, + { 5, 3,12}, { 5, 3,12}, { 1,10,12}, { 1,10,12}, + { 3, 4,12}, { 3, 4,12}, { 8, 2,12}, { 8, 2,12}, + { 22, 1,12}, { 22, 1,12}, { 21, 1,12}, { 21, 1,12}, + { 1, 9,12}, { 1, 9,12}, { 20, 1,12}, { 20, 1,12}, + { 19, 1,12}, { 19, 1,12}, { 2, 5,12}, { 2, 5,12}, + { 4, 3,12}, { 4, 3,12}, { 1, 8,12}, { 1, 8,12}, + { 7, 2,12}, { 7, 2,12}, { 18, 1,12}, { 18, 1,12} +}; + +static const DCTtab DCT_B14_10 [] = { + { 17, 1,10}, { 6, 2,10}, { 1, 7,10}, { 3, 3,10}, + { 2, 4,10}, { 16, 1,10}, { 15, 1,10}, { 5, 2,10} +}; + +static const DCTtab DCT_B14_8 [] = { + { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, + { 3, 2, 7}, { 3, 2, 7}, { 10, 1, 7}, { 10, 1, 7}, + { 1, 4, 7}, { 1, 4, 7}, { 9, 1, 7}, { 9, 1, 7}, + { 8, 1, 6}, { 8, 1, 6}, { 8, 1, 6}, { 8, 1, 6}, + { 7, 1, 6}, { 7, 1, 6}, { 7, 1, 6}, { 7, 1, 6}, + { 2, 2, 6}, { 2, 2, 6}, { 2, 2, 6}, { 2, 2, 6}, + { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, + { 14, 1, 8}, { 1, 6, 8}, { 13, 1, 8}, { 12, 1, 8}, + { 4, 2, 8}, { 2, 3, 8}, { 1, 5, 8}, { 11, 1, 8} +}; + +static const DCTtab DCT_B14AC_5 [] = { + { 1, 3, 5}, { 5, 1, 5}, { 4, 1, 5}, + { 1, 2, 4}, { 1, 2, 4}, { 3, 1, 4}, { 3, 1, 4}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, + {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2} +}; + +static const DCTtab DCT_B14DC_5 [] = { + { 1, 3, 5}, { 5, 1, 5}, { 4, 1, 5}, + { 1, 2, 4}, { 1, 2, 4}, { 3, 1, 4}, { 3, 1, 4}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, + { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, + { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, + { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1} +}; + +static const DCTtab DCT_B15_10 [] = { + { 6, 2, 9}, { 6, 2, 9}, { 15, 1, 9}, { 15, 1, 9}, + { 3, 4,10}, { 17, 1,10}, { 16, 1, 9}, { 16, 1, 9} +}; + +static const DCTtab DCT_B15_8 [] = { + { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, + { 8, 1, 7}, { 8, 1, 7}, { 9, 1, 7}, { 9, 1, 7}, + { 7, 1, 7}, { 7, 1, 7}, { 3, 2, 7}, { 3, 2, 7}, + { 1, 7, 6}, { 1, 7, 6}, { 1, 7, 6}, { 1, 7, 6}, + { 1, 6, 6}, { 1, 6, 6}, { 1, 6, 6}, { 1, 6, 6}, + { 5, 1, 6}, { 5, 1, 6}, { 5, 1, 6}, { 5, 1, 6}, + { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, + { 2, 5, 8}, { 12, 1, 8}, { 1,11, 8}, { 1,10, 8}, + { 14, 1, 8}, { 13, 1, 8}, { 4, 2, 8}, { 2, 4, 8}, + { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, + { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, + { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, + { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, + { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, + { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, + {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, + {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, + {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, + { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, + { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, + { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, + { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, + { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, + { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, + { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, + { 10, 1, 7}, { 10, 1, 7}, { 2, 3, 7}, { 2, 3, 7}, + { 11, 1, 7}, { 11, 1, 7}, { 1, 8, 7}, { 1, 8, 7}, + { 1, 9, 7}, { 1, 9, 7}, { 1,12, 8}, { 1,13, 8}, + { 3, 3, 8}, { 5, 2, 8}, { 1,14, 8}, { 1,15, 8} +}; + + +static const MBAtab MBA_5 [] = { + {6, 5}, {5, 5}, {4, 4}, {4, 4}, {3, 4}, {3, 4}, + {2, 3}, {2, 3}, {2, 3}, {2, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1} +}; + +static const MBAtab MBA_11 [] = { + {32, 11}, {31, 11}, {30, 11}, {29, 11}, + {28, 11}, {27, 11}, {26, 11}, {25, 11}, + {24, 11}, {23, 11}, {22, 11}, {21, 11}, + {20, 10}, {20, 10}, {19, 10}, {19, 10}, + {18, 10}, {18, 10}, {17, 10}, {17, 10}, + {16, 10}, {16, 10}, {15, 10}, {15, 10}, + {14, 8}, {14, 8}, {14, 8}, {14, 8}, + {14, 8}, {14, 8}, {14, 8}, {14, 8}, + {13, 8}, {13, 8}, {13, 8}, {13, 8}, + {13, 8}, {13, 8}, {13, 8}, {13, 8}, + {12, 8}, {12, 8}, {12, 8}, {12, 8}, + {12, 8}, {12, 8}, {12, 8}, {12, 8}, + {11, 8}, {11, 8}, {11, 8}, {11, 8}, + {11, 8}, {11, 8}, {11, 8}, {11, 8}, + {10, 8}, {10, 8}, {10, 8}, {10, 8}, + {10, 8}, {10, 8}, {10, 8}, {10, 8}, + { 9, 8}, { 9, 8}, { 9, 8}, { 9, 8}, + { 9, 8}, { 9, 8}, { 9, 8}, { 9, 8}, + { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, + { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, + { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, + { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, + { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7}, + { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7}, + { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7}, + { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7} +}; +#endif//__VLC_H__ diff --git a/pcsx2/IPU/yuv2rgb.cpp b/pcsx2/IPU/yuv2rgb.cpp index edc73dc03d..d76997a809 100644 --- a/pcsx2/IPU/yuv2rgb.cpp +++ b/pcsx2/IPU/yuv2rgb.cpp @@ -1,514 +1,514 @@ -/* - * yuv2rgb.c - * Copyright (C) 2000-2002 Michel Lespinasse - * Copyright (C) 1999-2000 Aaron Holtzman - * Modified by Florin for PCSX2 emu - * - * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. - * See http://libmpeg2.sourceforge.net/ for updates. - * - * mpeg2dec 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. - * - * mpeg2dec 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 "PrecompiledHeader.h" - -#include "System.h" -#include "mpeg2lib/Mpeg.h" -#include "yuv2rgb.h" - -//#include "convert_internal.h" //START -struct convert_rgb_t { - u8 * rgb_ptr; - int width; - int uv_stride, uv_stride_frame; - int rgb_stride, rgb_stride_frame; - void (__fastcall * yuv2rgb) (u8 *, u8 *, u8 *, u8 *, - void *, void *, int); -}; - -typedef void __fastcall yuv2rgb_copy (void * id, u8 * const * src, - unsigned int v_offset); - -yuv2rgb_copy __fastcall * yuv2rgb_init_mmxext (int bpp, int mode); -yuv2rgb_copy __fastcall * yuv2rgb_init_mmx (int bpp, int mode); -yuv2rgb_copy __fastcall * yuv2rgb_init_mlib (int bpp, int mode); -//#include "convert_internal.h" //END - -static u32 matrix_coefficients = 6; - -const s32 Inverse_Table_6_9[8][4] = { - {117504, 138453, 13954, 34903}, /*0 no sequence_display_extension */ - {117504, 138453, 13954, 34903}, /*1 ITU-R Rec. 709 (1990) */ - {104597, 132201, 25675, 53279}, /*2 unspecified */ - {104597, 132201, 25675, 53279}, /*3 reserved */ - {104448, 132798, 24759, 53109}, /*4 FCC */ - {104597, 132201, 25675, 53279}, /*5 ITU-R Rec. 624-4 System B, G */ - {104597, 132201, 25675, 53279}, /*6 SMPTE 170M */ - {117579, 136230, 16907, 35559} /*7 SMPTE 240M (1987) */ -}; - -typedef void __fastcall yuv2rgb_c_internal (u8 *, u8 *, u8 *, u8 *, - void *, void *, int); - -void * table_rV[256]; -void * table_gU[256]; -int table_gV[256]; -void * table_bU[256]; - -#define _RGB(type,i) \ - U = pu[i]; \ - V = pv[i]; \ - r = (type *) table_rV[V]; \ - g = (type *) (((u8 *)table_gU[U]) + table_gV[V]); \ - b = (type *) table_bU[U]; - -#define DST(py,dst,i) \ - Y = py[2*i]; \ - dst[2*i] = r[Y] + g[Y] + b[Y]; \ - Y = py[2*i+1]; \ - dst[2*i+1] = r[Y] + g[Y] + b[Y]; - -#define DSTRGB(py,dst,i) \ - Y = py[2*i]; \ - dst[6*i] = r[Y]; dst[6*i+1] = g[Y]; dst[6*i+2] = b[Y]; \ - Y = py[2*i+1]; \ - dst[6*i+3] = r[Y]; dst[6*i+4] = g[Y]; dst[6*i+5] = b[Y]; - -#define DSTBGR(py,dst,i) \ - Y = py[2*i]; \ - dst[6*i] = b[Y]; dst[6*i+1] = g[Y]; dst[6*i+2] = r[Y]; \ - Y = py[2*i+1]; \ - dst[6*i+3] = b[Y]; dst[6*i+4] = g[Y]; dst[6*i+5] = r[Y]; - -static void __fastcall yuv2rgb_c_32 (u8 * py_1, u8 * py_2, - u8 * pu, u8 * pv, - void * _dst_1, void * _dst_2, int width) -{ - int U, V, Y; - u32 * r, * g, * b; - u32 * dst_1, * dst_2; - - width >>= 3; - dst_1 = (u32 *) _dst_1; - dst_2 = (u32 *) _dst_2; - - do { - _RGB (u32, 0); - DST (py_1, dst_1, 0); - DST (py_2, dst_2, 0); - - _RGB (u32, 1); - DST (py_2, dst_2, 1); - DST (py_1, dst_1, 1); - - _RGB (u32, 2); - DST (py_1, dst_1, 2); - DST (py_2, dst_2, 2); - - _RGB (u32, 3); - DST (py_2, dst_2, 3); - DST (py_1, dst_1, 3); - - pu += 4; - pv += 4; - py_1 += 8; - py_2 += 8; - dst_1 += 8; - dst_2 += 8; - } while (--width); -} - -/* This is very near from the yuv2rgb_c_32 code */ -static void __fastcall yuv2rgb_c_24_rgb (u8 * py_1, u8 * py_2, - u8 * pu, u8 * pv, - void * _dst_1, void * _dst_2, int width) -{ - int U, V, Y; - u8 * r, * g, * b; - u8 * dst_1, * dst_2; - - width >>= 3; - dst_1 = (u8 *) _dst_1; - dst_2 = (u8 *) _dst_2; - - do { - _RGB (u8, 0); - DSTRGB (py_1, dst_1, 0); - DSTRGB (py_2, dst_2, 0); - - _RGB (u8, 1); - DSTRGB (py_2, dst_2, 1); - DSTRGB (py_1, dst_1, 1); - - _RGB (u8, 2); - DSTRGB (py_1, dst_1, 2); - DSTRGB (py_2, dst_2, 2); - - _RGB (u8, 3); - DSTRGB (py_2, dst_2, 3); - DSTRGB (py_1, dst_1, 3); - - pu += 4; - pv += 4; - py_1 += 8; - py_2 += 8; - dst_1 += 24; - dst_2 += 24; - } while (--width); -} - -/* only trivial mods from yuv2rgb_c_24_rgb */ -static void __fastcall yuv2rgb_c_24_bgr (u8 * py_1, u8 * py_2, - u8 * pu, u8 * pv, - void * _dst_1, void * _dst_2, int width) -{ - int U, V, Y; - u8 * r, * g, * b; - u8 * dst_1, * dst_2; - - width >>= 3; - dst_1 = (u8 *) _dst_1; - dst_2 = (u8 *) _dst_2; - - do { - _RGB (u8, 0); - DSTBGR (py_1, dst_1, 0); - DSTBGR (py_2, dst_2, 0); - - _RGB (u8, 1); - DSTBGR (py_2, dst_2, 1); - DSTBGR (py_1, dst_1, 1); - - _RGB (u8, 2); - DSTBGR (py_1, dst_1, 2); - DSTBGR (py_2, dst_2, 2); - - _RGB (u8, 3); - DSTBGR (py_2, dst_2, 3); - DSTBGR (py_1, dst_1, 3); - - pu += 4; - pv += 4; - py_1 += 8; - py_2 += 8; - dst_1 += 24; - dst_2 += 24; - } while (--width); -} - -/* This is exactly the same code as yuv2rgb_c_32 except for the types of */ -/* r, g, b, dst_1, dst_2 */ -static void __fastcall yuv2rgb_c_16 (u8 * py_1, u8 * py_2, - u8 * pu, u8 * pv, - void * _dst_1, void * _dst_2, int width) -{ - int U, V, Y; - u16 * r, * g, * b; - u16 * dst_1, * dst_2; - - width >>= 3; - dst_1 = (u16 *) _dst_1; - dst_2 = (u16 *) _dst_2; - - do { - _RGB (u16, 0); - DST (py_1, dst_1, 0); - DST (py_2, dst_2, 0); - - _RGB (u16, 1); - DST (py_2, dst_2, 1); - DST (py_1, dst_1, 1); - - _RGB (u16, 2); - DST (py_1, dst_1, 2); - DST (py_2, dst_2, 2); - - _RGB (u16, 3); - DST (py_2, dst_2, 3); - DST (py_1, dst_1, 3); - - pu += 4; - pv += 4; - py_1 += 8; - py_2 += 8; - dst_1 += 8; - dst_2 += 8; - } while (--width); -} - -static int div_round (int dividend, int divisor) -{ - if (dividend > 0) - return (dividend + (divisor>>1)) / divisor; - else - return -((-dividend + (divisor>>1)) / divisor); -} - -static yuv2rgb_c_internal __fastcall * yuv2rgb_c_init (int order, int bpp) -{ - int i; - u8 table_Y[1024]; - u32 * table_32 = 0; - u16 * table_16 = 0; - u8 * table_8 = 0; - int entry_size = 0; - void * table_r = 0; - void * table_g = 0; - void * table_b = 0; - yuv2rgb_c_internal * yuv2rgb; - - int crv = Inverse_Table_6_9[matrix_coefficients][0]; - int cbu = Inverse_Table_6_9[matrix_coefficients][1]; - int cgu = -Inverse_Table_6_9[matrix_coefficients][2]; - int cgv = -Inverse_Table_6_9[matrix_coefficients][3]; - - for (i = 0; i < 1024; i++) - { - int j; - - j = (76309 * (i - 384 - 16) + 32768) >> 16; - j = (j < 0) ? 0 : ((j > 255) ? 255 : j); - table_Y[i] = j; - } - - switch (bpp) - { - case 32: - yuv2rgb = yuv2rgb_c_32; - - table_32 = (u32 *) malloc ((197 + 2*682 + 256 + 132) * - sizeof (u32)); - - entry_size = sizeof (u32); - table_r = table_32 + 197; - table_b = table_32 + 197 + 685; - table_g = table_32 + 197 + 2*682; - - for (i = -197; i < 256+197; i++) - ((u32 *) table_r)[i] = - table_Y[i+384] << ((order == CONVERT_RGB) ? 16 : 0); - for (i = -132; i < 256+132; i++) - ((u32 *) table_g)[i] = table_Y[i+384] << 8; - for (i = -232; i < 256+232; i++) - ((u32 *) table_b)[i] = - table_Y[i+384] << ((order == CONVERT_RGB) ? 0 : 16); - break; - - case 24: - yuv2rgb = (order == CONVERT_RGB) ? yuv2rgb_c_24_rgb : yuv2rgb_c_24_bgr; - - table_8 = (u8 *) malloc ((256 + 2*232) * sizeof (u8)); - - entry_size = sizeof (u8); - table_r = table_g = table_b = table_8 + 232; - - for (i = -232; i < 256+232; i++) - ((u8 * )table_b)[i] = table_Y[i+384]; - break; - - case 15: - case 16: - yuv2rgb = yuv2rgb_c_16; - - table_16 = (u16 *) malloc ((197 + 2*682 + 256 + 132) * - sizeof (u16)); - - entry_size = sizeof (u16); - table_r = table_16 + 197; - table_b = table_16 + 197 + 685; - table_g = table_16 + 197 + 2*682; - - for (i = -197; i < 256+197; i++) { - int j = table_Y[i+384] >> 3; - - if (order == CONVERT_RGB) - j <<= ((bpp==16) ? 11 : 10); - - ((u16 *)table_r)[i] = j; - } - for (i = -132; i < 256+132; i++) { - int j = table_Y[i+384] >> ((bpp==16) ? 2 : 3); - - ((u16 *)table_g)[i] = j << 5; - } - for (i = -232; i < 256+232; i++) { - int j = table_Y[i+384] >> 3; - - if (order == CONVERT_RGB) - j <<= ((bpp==16) ? 11 : 10); - - ((u16 *)table_b)[i] = j; - } - break; - -#ifdef PCSX2_DEVBUILD - default: - DevCon::Error( "IPU Panic! %ibpp not supported by yuv2rgb", params bpp ); -#else - jNO_DEFAULT -#endif - } - - for (i = 0; i < 256; i++) { - table_rV[i] = (((u8 *)table_r) + - entry_size * div_round (crv * (i-128), 76309)); - table_gU[i] = (((u8 *)table_g) + - entry_size * div_round (cgu * (i-128), 76309)); - table_gV[i] = entry_size * div_round (cgv * (i-128), 76309); - table_bU[i] = (((u8 *)table_b) + - entry_size * div_round (cbu * (i-128), 76309)); - } - - return yuv2rgb; -} - -static void __fastcall convert_yuv2rgb_c (void * _id, u8 * Y, u8 * Cr, u8 * Cb, - unsigned int v_offset) -{ - convert_rgb_t * id = (convert_rgb_t *) _id; - u8 * dst; - u8 * py; - u8 * pu; - u8 * pv; - int loop; - - dst = id->rgb_ptr + id->rgb_stride * v_offset; - py = Y; pu = Cr; pv = Cb; - - loop = 8; - do { - id->yuv2rgb (py, py + (id->uv_stride << 1), pu, pv, - dst, dst + id->rgb_stride, id->width); - py += id->uv_stride << 2; - pu += id->uv_stride; - pv += id->uv_stride; - dst += 2 * id->rgb_stride; - } while (--loop); -} - -static void __fastcall convert_start (void * _id, u8 * dest, int flags) -{ - convert_rgb_t * id = (convert_rgb_t *) _id; - id->rgb_ptr = dest; - switch (flags) { - case CONVERT_BOTTOM_FIELD: - id->rgb_ptr += id->rgb_stride_frame; - /* break thru */ - case CONVERT_TOP_FIELD: - id->uv_stride = id->uv_stride_frame << 1; - id->rgb_stride = id->rgb_stride_frame << 1; - break; - default: - id->uv_stride = id->uv_stride_frame; - id->rgb_stride = id->rgb_stride_frame; - } -} - -static void __fastcall convert_internal (int order, int bpp, int width, int height, - u32 accel, void * arg, convert_init_t * result) -{ - convert_rgb_t * id = (convert_rgb_t *) result->id; - - if (!id) { - result->id_size = sizeof (convert_rgb_t); - } else { - id->width = width; - id->uv_stride_frame = width >> 1; - id->rgb_stride_frame = ((bpp + 7) >> 3) * width; - - result->buf_size[0] = id->rgb_stride_frame * height; - result->buf_size[1] = result->buf_size[2] = 0; - result->start = convert_start; - - result->copy = NULL; - #ifdef ARCH_X86 - if ((result->copy == NULL) && (accel & MPEG2_ACCEL_X86_MMXEXT)) { - result->copy = yuv2rgb_init_mmxext (order, bpp); - } - if ((result->copy == NULL) && (accel & MPEG2_ACCEL_X86_MMX)) { - result->copy = yuv2rgb_init_mmx (order, bpp); - } - #endif - #ifdef LIBVO_MLIB - if ((result->copy == NULL) && (accel & MPEG2_ACCEL_MLIB)) { - result->copy = yuv2rgb_init_mlib (order, bpp); - } - #endif - if (result->copy == NULL) { - result->copy = convert_yuv2rgb_c; - id->yuv2rgb = yuv2rgb_c_init (order, bpp); - } - } -} - -void __fastcall convert_rgb32 (int width, int height, u32 accel, void * arg, - convert_init_t * result) -{ - convert_internal (CONVERT_RGB, 32, width, height, accel, arg, result); -} - -void __fastcall convert_rgb24 (int width, int height, u32 accel, void * arg, - convert_init_t * result) -{ - convert_internal (CONVERT_RGB, 24, width, height, accel, arg, result); -} - -void __fastcall convert_rgb16 (int width, int height, u32 accel, void * arg, - convert_init_t * result) -{ - convert_internal (CONVERT_RGB, 16, width, height, accel, arg, result); -} - -void __fastcall convert_rgb15 (int width, int height, u32 accel, void * arg, - convert_init_t * result) -{ - convert_internal (CONVERT_RGB, 15, width, height, accel, arg, result); -} - -void __fastcall convert_bgr32 (int width, int height, u32 accel, void * arg, - convert_init_t * result) -{ - convert_internal (CONVERT_BGR, 32, width, height, accel, arg, result); -} - -void __fastcall convert_bgr24 (int width, int height, u32 accel, void * arg, - convert_init_t * result) -{ - convert_internal (CONVERT_BGR, 24, width, height, accel, arg, result); -} - -void __fastcall convert_bgr16 (int width, int height, u32 accel, void * arg, - convert_init_t * result) -{ - convert_internal (CONVERT_BGR, 16, width, height, accel, arg, result); -} - -void __fastcall convert_bgr15 (int width, int height, u32 accel, void * arg, - convert_init_t * result) -{ - convert_internal (CONVERT_BGR, 15, width, height, accel, arg, result); -} - -__forceinline convert_t* convert_rgb (int order, int bpp) -{ - if (order == CONVERT_RGB || order == CONVERT_BGR) - switch (bpp) { - case 32: return (order == CONVERT_RGB) ? convert_rgb32 : convert_bgr32; - case 24: return (order == CONVERT_RGB) ? convert_rgb24 : convert_bgr24; - case 16: return (order == CONVERT_RGB) ? convert_rgb16 : convert_bgr16; - case 15: return (order == CONVERT_RGB) ? convert_rgb15 : convert_bgr15; - } - return NULL; -} +/* + * yuv2rgb.c + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * Modified by Florin for PCSX2 emu + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * See http://libmpeg2.sourceforge.net/ for updates. + * + * mpeg2dec 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. + * + * mpeg2dec 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 "PrecompiledHeader.h" + +#include "System.h" +#include "mpeg2lib/Mpeg.h" +#include "yuv2rgb.h" + +//#include "convert_internal.h" //START +struct convert_rgb_t { + u8 * rgb_ptr; + int width; + int uv_stride, uv_stride_frame; + int rgb_stride, rgb_stride_frame; + void (__fastcall * yuv2rgb) (u8 *, u8 *, u8 *, u8 *, + void *, void *, int); +}; + +typedef void __fastcall yuv2rgb_copy (void * id, u8 * const * src, + unsigned int v_offset); + +yuv2rgb_copy __fastcall * yuv2rgb_init_mmxext (int bpp, int mode); +yuv2rgb_copy __fastcall * yuv2rgb_init_mmx (int bpp, int mode); +yuv2rgb_copy __fastcall * yuv2rgb_init_mlib (int bpp, int mode); +//#include "convert_internal.h" //END + +static u32 matrix_coefficients = 6; + +const s32 Inverse_Table_6_9[8][4] = { + {117504, 138453, 13954, 34903}, /*0 no sequence_display_extension */ + {117504, 138453, 13954, 34903}, /*1 ITU-R Rec. 709 (1990) */ + {104597, 132201, 25675, 53279}, /*2 unspecified */ + {104597, 132201, 25675, 53279}, /*3 reserved */ + {104448, 132798, 24759, 53109}, /*4 FCC */ + {104597, 132201, 25675, 53279}, /*5 ITU-R Rec. 624-4 System B, G */ + {104597, 132201, 25675, 53279}, /*6 SMPTE 170M */ + {117579, 136230, 16907, 35559} /*7 SMPTE 240M (1987) */ +}; + +typedef void __fastcall yuv2rgb_c_internal (u8 *, u8 *, u8 *, u8 *, + void *, void *, int); + +void * table_rV[256]; +void * table_gU[256]; +int table_gV[256]; +void * table_bU[256]; + +#define _RGB(type,i) \ + U = pu[i]; \ + V = pv[i]; \ + r = (type *) table_rV[V]; \ + g = (type *) (((u8 *)table_gU[U]) + table_gV[V]); \ + b = (type *) table_bU[U]; + +#define DST(py,dst,i) \ + Y = py[2*i]; \ + dst[2*i] = r[Y] + g[Y] + b[Y]; \ + Y = py[2*i+1]; \ + dst[2*i+1] = r[Y] + g[Y] + b[Y]; + +#define DSTRGB(py,dst,i) \ + Y = py[2*i]; \ + dst[6*i] = r[Y]; dst[6*i+1] = g[Y]; dst[6*i+2] = b[Y]; \ + Y = py[2*i+1]; \ + dst[6*i+3] = r[Y]; dst[6*i+4] = g[Y]; dst[6*i+5] = b[Y]; + +#define DSTBGR(py,dst,i) \ + Y = py[2*i]; \ + dst[6*i] = b[Y]; dst[6*i+1] = g[Y]; dst[6*i+2] = r[Y]; \ + Y = py[2*i+1]; \ + dst[6*i+3] = b[Y]; dst[6*i+4] = g[Y]; dst[6*i+5] = r[Y]; + +static void __fastcall yuv2rgb_c_32 (u8 * py_1, u8 * py_2, + u8 * pu, u8 * pv, + void * _dst_1, void * _dst_2, int width) +{ + int U, V, Y; + u32 * r, * g, * b; + u32 * dst_1, * dst_2; + + width >>= 3; + dst_1 = (u32 *) _dst_1; + dst_2 = (u32 *) _dst_2; + + do { + _RGB (u32, 0); + DST (py_1, dst_1, 0); + DST (py_2, dst_2, 0); + + _RGB (u32, 1); + DST (py_2, dst_2, 1); + DST (py_1, dst_1, 1); + + _RGB (u32, 2); + DST (py_1, dst_1, 2); + DST (py_2, dst_2, 2); + + _RGB (u32, 3); + DST (py_2, dst_2, 3); + DST (py_1, dst_1, 3); + + pu += 4; + pv += 4; + py_1 += 8; + py_2 += 8; + dst_1 += 8; + dst_2 += 8; + } while (--width); +} + +/* This is very near from the yuv2rgb_c_32 code */ +static void __fastcall yuv2rgb_c_24_rgb (u8 * py_1, u8 * py_2, + u8 * pu, u8 * pv, + void * _dst_1, void * _dst_2, int width) +{ + int U, V, Y; + u8 * r, * g, * b; + u8 * dst_1, * dst_2; + + width >>= 3; + dst_1 = (u8 *) _dst_1; + dst_2 = (u8 *) _dst_2; + + do { + _RGB (u8, 0); + DSTRGB (py_1, dst_1, 0); + DSTRGB (py_2, dst_2, 0); + + _RGB (u8, 1); + DSTRGB (py_2, dst_2, 1); + DSTRGB (py_1, dst_1, 1); + + _RGB (u8, 2); + DSTRGB (py_1, dst_1, 2); + DSTRGB (py_2, dst_2, 2); + + _RGB (u8, 3); + DSTRGB (py_2, dst_2, 3); + DSTRGB (py_1, dst_1, 3); + + pu += 4; + pv += 4; + py_1 += 8; + py_2 += 8; + dst_1 += 24; + dst_2 += 24; + } while (--width); +} + +/* only trivial mods from yuv2rgb_c_24_rgb */ +static void __fastcall yuv2rgb_c_24_bgr (u8 * py_1, u8 * py_2, + u8 * pu, u8 * pv, + void * _dst_1, void * _dst_2, int width) +{ + int U, V, Y; + u8 * r, * g, * b; + u8 * dst_1, * dst_2; + + width >>= 3; + dst_1 = (u8 *) _dst_1; + dst_2 = (u8 *) _dst_2; + + do { + _RGB (u8, 0); + DSTBGR (py_1, dst_1, 0); + DSTBGR (py_2, dst_2, 0); + + _RGB (u8, 1); + DSTBGR (py_2, dst_2, 1); + DSTBGR (py_1, dst_1, 1); + + _RGB (u8, 2); + DSTBGR (py_1, dst_1, 2); + DSTBGR (py_2, dst_2, 2); + + _RGB (u8, 3); + DSTBGR (py_2, dst_2, 3); + DSTBGR (py_1, dst_1, 3); + + pu += 4; + pv += 4; + py_1 += 8; + py_2 += 8; + dst_1 += 24; + dst_2 += 24; + } while (--width); +} + +/* This is exactly the same code as yuv2rgb_c_32 except for the types of */ +/* r, g, b, dst_1, dst_2 */ +static void __fastcall yuv2rgb_c_16 (u8 * py_1, u8 * py_2, + u8 * pu, u8 * pv, + void * _dst_1, void * _dst_2, int width) +{ + int U, V, Y; + u16 * r, * g, * b; + u16 * dst_1, * dst_2; + + width >>= 3; + dst_1 = (u16 *) _dst_1; + dst_2 = (u16 *) _dst_2; + + do { + _RGB (u16, 0); + DST (py_1, dst_1, 0); + DST (py_2, dst_2, 0); + + _RGB (u16, 1); + DST (py_2, dst_2, 1); + DST (py_1, dst_1, 1); + + _RGB (u16, 2); + DST (py_1, dst_1, 2); + DST (py_2, dst_2, 2); + + _RGB (u16, 3); + DST (py_2, dst_2, 3); + DST (py_1, dst_1, 3); + + pu += 4; + pv += 4; + py_1 += 8; + py_2 += 8; + dst_1 += 8; + dst_2 += 8; + } while (--width); +} + +static int div_round (int dividend, int divisor) +{ + if (dividend > 0) + return (dividend + (divisor>>1)) / divisor; + else + return -((-dividend + (divisor>>1)) / divisor); +} + +static yuv2rgb_c_internal __fastcall * yuv2rgb_c_init (int order, int bpp) +{ + int i; + u8 table_Y[1024]; + u32 * table_32 = 0; + u16 * table_16 = 0; + u8 * table_8 = 0; + int entry_size = 0; + void * table_r = 0; + void * table_g = 0; + void * table_b = 0; + yuv2rgb_c_internal * yuv2rgb; + + int crv = Inverse_Table_6_9[matrix_coefficients][0]; + int cbu = Inverse_Table_6_9[matrix_coefficients][1]; + int cgu = -Inverse_Table_6_9[matrix_coefficients][2]; + int cgv = -Inverse_Table_6_9[matrix_coefficients][3]; + + for (i = 0; i < 1024; i++) + { + int j; + + j = (76309 * (i - 384 - 16) + 32768) >> 16; + j = (j < 0) ? 0 : ((j > 255) ? 255 : j); + table_Y[i] = j; + } + + switch (bpp) + { + case 32: + yuv2rgb = yuv2rgb_c_32; + + table_32 = (u32 *) malloc ((197 + 2*682 + 256 + 132) * + sizeof (u32)); + + entry_size = sizeof (u32); + table_r = table_32 + 197; + table_b = table_32 + 197 + 685; + table_g = table_32 + 197 + 2*682; + + for (i = -197; i < 256+197; i++) + ((u32 *) table_r)[i] = + table_Y[i+384] << ((order == CONVERT_RGB) ? 16 : 0); + for (i = -132; i < 256+132; i++) + ((u32 *) table_g)[i] = table_Y[i+384] << 8; + for (i = -232; i < 256+232; i++) + ((u32 *) table_b)[i] = + table_Y[i+384] << ((order == CONVERT_RGB) ? 0 : 16); + break; + + case 24: + yuv2rgb = (order == CONVERT_RGB) ? yuv2rgb_c_24_rgb : yuv2rgb_c_24_bgr; + + table_8 = (u8 *) malloc ((256 + 2*232) * sizeof (u8)); + + entry_size = sizeof (u8); + table_r = table_g = table_b = table_8 + 232; + + for (i = -232; i < 256+232; i++) + ((u8 * )table_b)[i] = table_Y[i+384]; + break; + + case 15: + case 16: + yuv2rgb = yuv2rgb_c_16; + + table_16 = (u16 *) malloc ((197 + 2*682 + 256 + 132) * + sizeof (u16)); + + entry_size = sizeof (u16); + table_r = table_16 + 197; + table_b = table_16 + 197 + 685; + table_g = table_16 + 197 + 2*682; + + for (i = -197; i < 256+197; i++) { + int j = table_Y[i+384] >> 3; + + if (order == CONVERT_RGB) + j <<= ((bpp==16) ? 11 : 10); + + ((u16 *)table_r)[i] = j; + } + for (i = -132; i < 256+132; i++) { + int j = table_Y[i+384] >> ((bpp==16) ? 2 : 3); + + ((u16 *)table_g)[i] = j << 5; + } + for (i = -232; i < 256+232; i++) { + int j = table_Y[i+384] >> 3; + + if (order == CONVERT_RGB) + j <<= ((bpp==16) ? 11 : 10); + + ((u16 *)table_b)[i] = j; + } + break; + +#ifdef PCSX2_DEVBUILD + default: + DevCon::Error( "IPU Panic! %ibpp not supported by yuv2rgb", params bpp ); +#else + jNO_DEFAULT +#endif + } + + for (i = 0; i < 256; i++) { + table_rV[i] = (((u8 *)table_r) + + entry_size * div_round (crv * (i-128), 76309)); + table_gU[i] = (((u8 *)table_g) + + entry_size * div_round (cgu * (i-128), 76309)); + table_gV[i] = entry_size * div_round (cgv * (i-128), 76309); + table_bU[i] = (((u8 *)table_b) + + entry_size * div_round (cbu * (i-128), 76309)); + } + + return yuv2rgb; +} + +static void __fastcall convert_yuv2rgb_c (void * _id, u8 * Y, u8 * Cr, u8 * Cb, + unsigned int v_offset) +{ + convert_rgb_t * id = (convert_rgb_t *) _id; + u8 * dst; + u8 * py; + u8 * pu; + u8 * pv; + int loop; + + dst = id->rgb_ptr + id->rgb_stride * v_offset; + py = Y; pu = Cr; pv = Cb; + + loop = 8; + do { + id->yuv2rgb (py, py + (id->uv_stride << 1), pu, pv, + dst, dst + id->rgb_stride, id->width); + py += id->uv_stride << 2; + pu += id->uv_stride; + pv += id->uv_stride; + dst += 2 * id->rgb_stride; + } while (--loop); +} + +static void __fastcall convert_start (void * _id, u8 * dest, int flags) +{ + convert_rgb_t * id = (convert_rgb_t *) _id; + id->rgb_ptr = dest; + switch (flags) { + case CONVERT_BOTTOM_FIELD: + id->rgb_ptr += id->rgb_stride_frame; + /* break thru */ + case CONVERT_TOP_FIELD: + id->uv_stride = id->uv_stride_frame << 1; + id->rgb_stride = id->rgb_stride_frame << 1; + break; + default: + id->uv_stride = id->uv_stride_frame; + id->rgb_stride = id->rgb_stride_frame; + } +} + +static void __fastcall convert_internal (int order, int bpp, int width, int height, + u32 accel, void * arg, convert_init_t * result) +{ + convert_rgb_t * id = (convert_rgb_t *) result->id; + + if (!id) { + result->id_size = sizeof (convert_rgb_t); + } else { + id->width = width; + id->uv_stride_frame = width >> 1; + id->rgb_stride_frame = ((bpp + 7) >> 3) * width; + + result->buf_size[0] = id->rgb_stride_frame * height; + result->buf_size[1] = result->buf_size[2] = 0; + result->start = convert_start; + + result->copy = NULL; + #ifdef ARCH_X86 + if ((result->copy == NULL) && (accel & MPEG2_ACCEL_X86_MMXEXT)) { + result->copy = yuv2rgb_init_mmxext (order, bpp); + } + if ((result->copy == NULL) && (accel & MPEG2_ACCEL_X86_MMX)) { + result->copy = yuv2rgb_init_mmx (order, bpp); + } + #endif + #ifdef LIBVO_MLIB + if ((result->copy == NULL) && (accel & MPEG2_ACCEL_MLIB)) { + result->copy = yuv2rgb_init_mlib (order, bpp); + } + #endif + if (result->copy == NULL) { + result->copy = convert_yuv2rgb_c; + id->yuv2rgb = yuv2rgb_c_init (order, bpp); + } + } +} + +void __fastcall convert_rgb32 (int width, int height, u32 accel, void * arg, + convert_init_t * result) +{ + convert_internal (CONVERT_RGB, 32, width, height, accel, arg, result); +} + +void __fastcall convert_rgb24 (int width, int height, u32 accel, void * arg, + convert_init_t * result) +{ + convert_internal (CONVERT_RGB, 24, width, height, accel, arg, result); +} + +void __fastcall convert_rgb16 (int width, int height, u32 accel, void * arg, + convert_init_t * result) +{ + convert_internal (CONVERT_RGB, 16, width, height, accel, arg, result); +} + +void __fastcall convert_rgb15 (int width, int height, u32 accel, void * arg, + convert_init_t * result) +{ + convert_internal (CONVERT_RGB, 15, width, height, accel, arg, result); +} + +void __fastcall convert_bgr32 (int width, int height, u32 accel, void * arg, + convert_init_t * result) +{ + convert_internal (CONVERT_BGR, 32, width, height, accel, arg, result); +} + +void __fastcall convert_bgr24 (int width, int height, u32 accel, void * arg, + convert_init_t * result) +{ + convert_internal (CONVERT_BGR, 24, width, height, accel, arg, result); +} + +void __fastcall convert_bgr16 (int width, int height, u32 accel, void * arg, + convert_init_t * result) +{ + convert_internal (CONVERT_BGR, 16, width, height, accel, arg, result); +} + +void __fastcall convert_bgr15 (int width, int height, u32 accel, void * arg, + convert_init_t * result) +{ + convert_internal (CONVERT_BGR, 15, width, height, accel, arg, result); +} + +__forceinline convert_t* convert_rgb (int order, int bpp) +{ + if (order == CONVERT_RGB || order == CONVERT_BGR) + switch (bpp) { + case 32: return (order == CONVERT_RGB) ? convert_rgb32 : convert_bgr32; + case 24: return (order == CONVERT_RGB) ? convert_rgb24 : convert_bgr24; + case 16: return (order == CONVERT_RGB) ? convert_rgb16 : convert_bgr16; + case 15: return (order == CONVERT_RGB) ? convert_rgb15 : convert_bgr15; + } + return NULL; +} diff --git a/pcsx2/IPU/yuv2rgb.h b/pcsx2/IPU/yuv2rgb.h index 656a87f57a..9d802a7d52 100644 --- a/pcsx2/IPU/yuv2rgb.h +++ b/pcsx2/IPU/yuv2rgb.h @@ -1,57 +1,57 @@ -/* - * yuv2rgb.h - * Copyright (C) 2000-2002 Michel Lespinasse - * Copyright (C) 1999-2000 Aaron Holtzman - * Modified by Florin for PCSX2 emu - * - * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. - * See http://libmpeg2.sourceforge.net/ for updates. - * - * mpeg2dec 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. - * - * mpeg2dec 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 - */ - -#ifndef YUV2RGB_H -#define YUV2RGB_H - -#define CONVERT_FRAME 0 -#define CONVERT_TOP_FIELD 1 -#define CONVERT_BOTTOM_FIELD 2 -#define CONVERT_BOTH_FIELDS 3 - -struct convert_init_t { - void * id; - int id_size; - int buf_size[3]; - void (__fastcall* start) (void * id, u8 * dest, int flags); - void (__fastcall* copy) (void * id, u8 * Y, u8 * Cr, u8 * Cb, unsigned int v_offset); -}; - -typedef void __fastcall convert_t (int width, int height, u32 accel, void * arg, - convert_init_t * result); - -convert_t convert_rgb32; -convert_t convert_rgb24; -convert_t convert_rgb16; -convert_t convert_rgb15; -convert_t convert_bgr32; -convert_t convert_bgr24; -convert_t convert_bgr16; -convert_t convert_bgr15; - -#define CONVERT_RGB 0 -#define CONVERT_BGR 1 -extern convert_t* convert_rgb (int order, int bpp); - -#endif /* YUV2RGB_H */ +/* + * yuv2rgb.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * Modified by Florin for PCSX2 emu + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * See http://libmpeg2.sourceforge.net/ for updates. + * + * mpeg2dec 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. + * + * mpeg2dec 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 + */ + +#ifndef YUV2RGB_H +#define YUV2RGB_H + +#define CONVERT_FRAME 0 +#define CONVERT_TOP_FIELD 1 +#define CONVERT_BOTTOM_FIELD 2 +#define CONVERT_BOTH_FIELDS 3 + +struct convert_init_t { + void * id; + int id_size; + int buf_size[3]; + void (__fastcall* start) (void * id, u8 * dest, int flags); + void (__fastcall* copy) (void * id, u8 * Y, u8 * Cr, u8 * Cb, unsigned int v_offset); +}; + +typedef void __fastcall convert_t (int width, int height, u32 accel, void * arg, + convert_init_t * result); + +convert_t convert_rgb32; +convert_t convert_rgb24; +convert_t convert_rgb16; +convert_t convert_rgb15; +convert_t convert_bgr32; +convert_t convert_bgr24; +convert_t convert_bgr16; +convert_t convert_bgr15; + +#define CONVERT_RGB 0 +#define CONVERT_BGR 1 +extern convert_t* convert_rgb (int order, int bpp); + +#endif /* YUV2RGB_H */ diff --git a/pcsx2/Interpreter.cpp b/pcsx2/Interpreter.cpp index 70b665235d..618abc6cf0 100644 --- a/pcsx2/Interpreter.cpp +++ b/pcsx2/Interpreter.cpp @@ -1,284 +1,284 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "R5900.h" -#include "R5900OpcodeTables.h" - -#include - -using namespace R5900; // for OPCODE and OpcodeImpl - -extern int vu0branch, vu1branch; - -static int branch2 = 0; -static u32 cpuBlockCycles = 0; // 3 bit fixed point version of cycle count -static std::string disOut; - -// These macros are used to assemble the repassembler functions - -#ifdef PCSX2_DEVBUILD -static void debugI() -{ - //CPU_LOG("%s\n", disR5900Current.getCString()); - if (cpuRegs.GPR.n.r0.UD[0] || cpuRegs.GPR.n.r0.UD[1]) Console::Error("R0 is not zero!!!!"); -} -#else -static void debugI() {} -#endif - -//long int runs=0; - -static void execI() -{ -#ifdef _DEBUG - memRead32(cpuRegs.pc, &cpuRegs.code); - debugI(); -#else - cpuRegs.code = *(u32 *)PSM(cpuRegs.pc); -#endif - - const OPCODE& opcode = GetCurrentInstruction(); - //use this to find out what opcodes your game uses. very slow! (rama) - //runs++; - //if (runs > 1599999999){ //leave some time to startup the testgame - // if (opcode.Name[0] == 'L') { //find all opcodes beginning with "L" - // SysPrintf ("Load %s\n",opcode.Name); - // } - //} - - cpuBlockCycles += opcode.cycles; - cpuRegs.pc += 4; - - opcode.interpret(); -} - -static bool EventRaised = false; - -static __forceinline void _doBranch_shared(u32 tar) -{ - branch2 = cpuRegs.branch = 1; - execI(); - - // branch being 0 means an exception was thrown, since only the exception - // handler should ever clear it. - - if( cpuRegs.branch != 0 ) - { - cpuRegs.pc = tar; - cpuRegs.branch = 0; - } -} - -static void __fastcall doBranch( u32 target ) -{ - _doBranch_shared( target ); - cpuRegs.cycle += cpuBlockCycles >> 3; - cpuBlockCycles &= (1<<3)-1; - EventRaised |= intEventTest(); -} - -void __fastcall intDoBranch(u32 target) -{ - //SysPrintf("Interpreter Branch \n"); - _doBranch_shared( target ); - - if( Cpu == &intCpu ) - { - cpuRegs.cycle += cpuBlockCycles >> 3; - cpuBlockCycles &= (1<<3)-1; - EventRaised |= intEventTest(); - } -} - -void intSetBranch() { - branch2 = /*cpuRegs.branch =*/ 1; -} - -//////////////////////////////////////////////////////////////////// -// R5900 Branching Instructions! -// These are the interpreter versions of the branch instructions. Unlike other -// types of interpreter instructions which can be called safely from the recompilers, -// these instructions are not "recSafe" because they may not invoke the -// necessary branch test logic that the recs need to maintain sync with the -// cpuRegs.pc and delaySlot instruction and such. - -namespace R5900 { -namespace Interpreter { -namespace OpcodeImpl { - -/********************************************************* -* Jump to target * -* Format: OP target * -*********************************************************/ - -void J() { - doBranch(_JumpTarget_); -} - -void JAL() { - _SetLink(31); doBranch(_JumpTarget_); -} - -/********************************************************* -* Register branch logic * -* Format: OP rs, rt, offset * -*********************************************************/ -#define RepBranchi32(op) \ - if (cpuRegs.GPR.r[_Rs_].SD[0] op cpuRegs.GPR.r[_Rt_].SD[0]) doBranch(_BranchTarget_); \ - else intEventTest(); - - -void BEQ() { RepBranchi32(==) } // Branch if Rs == Rt -void BNE() { RepBranchi32(!=) } // Branch if Rs != Rt - -/********************************************************* -* Register branch logic * -* Format: OP rs, offset * -*********************************************************/ -#define RepZBranchi32(op) \ - if(cpuRegs.GPR.r[_Rs_].SD[0] op 0) { \ - doBranch(_BranchTarget_); \ - } - -#define RepZBranchLinki32(op) \ - _SetLink(31); \ - if(cpuRegs.GPR.r[_Rs_].SD[0] op 0) { \ - doBranch(_BranchTarget_); \ - } - -void BGEZ() { RepZBranchi32(>=) } // Branch if Rs >= 0 -void BGEZAL() { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link -void BGTZ() { RepZBranchi32(>) } // Branch if Rs > 0 -void BLEZ() { RepZBranchi32(<=) } // Branch if Rs <= 0 -void BLTZ() { RepZBranchi32(<) } // Branch if Rs < 0 -void BLTZAL() { RepZBranchLinki32(<) } // Branch if Rs < 0 and link - - -/********************************************************* -* Register branch logic Likely * -* Format: OP rs, offset * -*********************************************************/ -#define RepZBranchi32Likely(op) \ - if(cpuRegs.GPR.r[_Rs_].SD[0] op 0) { \ - doBranch(_BranchTarget_); \ - } else { cpuRegs.pc +=4; intEventTest(); } - -#define RepZBranchLinki32Likely(op) \ - _SetLink(31); \ - if(cpuRegs.GPR.r[_Rs_].SD[0] op 0) { \ - doBranch(_BranchTarget_); \ - } else { cpuRegs.pc +=4; intEventTest(); } - -#define RepBranchi32Likely(op) \ - if(cpuRegs.GPR.r[_Rs_].SD[0] op cpuRegs.GPR.r[_Rt_].SD[0]) { \ - doBranch(_BranchTarget_); \ - } else { cpuRegs.pc +=4; intEventTest(); } - - -void BEQL() { RepBranchi32Likely(==) } // Branch if Rs == Rt -void BNEL() { RepBranchi32Likely(!=) } // Branch if Rs != Rt -void BLEZL() { RepZBranchi32Likely(<=) } // Branch if Rs <= 0 -void BGTZL() { RepZBranchi32Likely(>) } // Branch if Rs > 0 -void BLTZL() { RepZBranchi32Likely(<) } // Branch if Rs < 0 -void BGEZL() { RepZBranchi32Likely(>=) } // Branch if Rs >= 0 -void BLTZALL() { RepZBranchLinki32Likely(<) } // Branch if Rs < 0 and link -void BGEZALL() { RepZBranchLinki32Likely(>=) } // Branch if Rs >= 0 and link - -/********************************************************* -* Register jump * -* Format: OP rs, rd * -*********************************************************/ -void JR() { - doBranch(cpuRegs.GPR.r[_Rs_].UL[0]); -} - -void JALR() { - u32 temp = cpuRegs.GPR.r[_Rs_].UL[0]; - if (_Rd_) { _SetLink(_Rd_); } - doBranch(temp); -} - -} } } // end namespace R5900::Interpreter::OpcodeImpl - -//////////////////////////////////////////////////////// - -void intAlloc() -{ - // fixme : detect cpu for use the optimize asm code -} - -void intReset() -{ - cpuRegs.branch = 0; - branch2 = 0; -} - -bool intEventTest() -{ - // Perform counters, ints, and IOP updates: - return _cpuBranchTest_Shared(); -} - -void intExecute() -{ - g_EEFreezeRegs = false; - - // Mem protection should be handled by the caller here so that it can be - // done in a more optimized fashion. - - EventRaised = false; - - while( !EventRaised ) - { - execI(); - } -} - -static void intExecuteBlock() -{ - g_EEFreezeRegs = false; - - branch2 = 0; - while (!branch2) execI(); -} - -static void intStep() -{ - g_EEFreezeRegs = false; - execI(); -} - -static void intClear(u32 Addr, u32 Size) -{ -} - -static void intShutdown() { -} - -R5900cpu intCpu = { - intAlloc, - intReset, - intStep, - intExecute, - intExecuteBlock, - intClear, - intShutdown -}; +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "R5900.h" +#include "R5900OpcodeTables.h" + +#include + +using namespace R5900; // for OPCODE and OpcodeImpl + +extern int vu0branch, vu1branch; + +static int branch2 = 0; +static u32 cpuBlockCycles = 0; // 3 bit fixed point version of cycle count +static std::string disOut; + +// These macros are used to assemble the repassembler functions + +#ifdef PCSX2_DEVBUILD +static void debugI() +{ + //CPU_LOG("%s\n", disR5900Current.getCString()); + if (cpuRegs.GPR.n.r0.UD[0] || cpuRegs.GPR.n.r0.UD[1]) Console::Error("R0 is not zero!!!!"); +} +#else +static void debugI() {} +#endif + +//long int runs=0; + +static void execI() +{ +#ifdef _DEBUG + memRead32(cpuRegs.pc, &cpuRegs.code); + debugI(); +#else + cpuRegs.code = *(u32 *)PSM(cpuRegs.pc); +#endif + + const OPCODE& opcode = GetCurrentInstruction(); + //use this to find out what opcodes your game uses. very slow! (rama) + //runs++; + //if (runs > 1599999999){ //leave some time to startup the testgame + // if (opcode.Name[0] == 'L') { //find all opcodes beginning with "L" + // SysPrintf ("Load %s\n",opcode.Name); + // } + //} + + cpuBlockCycles += opcode.cycles; + cpuRegs.pc += 4; + + opcode.interpret(); +} + +static bool EventRaised = false; + +static __forceinline void _doBranch_shared(u32 tar) +{ + branch2 = cpuRegs.branch = 1; + execI(); + + // branch being 0 means an exception was thrown, since only the exception + // handler should ever clear it. + + if( cpuRegs.branch != 0 ) + { + cpuRegs.pc = tar; + cpuRegs.branch = 0; + } +} + +static void __fastcall doBranch( u32 target ) +{ + _doBranch_shared( target ); + cpuRegs.cycle += cpuBlockCycles >> 3; + cpuBlockCycles &= (1<<3)-1; + EventRaised |= intEventTest(); +} + +void __fastcall intDoBranch(u32 target) +{ + //SysPrintf("Interpreter Branch \n"); + _doBranch_shared( target ); + + if( Cpu == &intCpu ) + { + cpuRegs.cycle += cpuBlockCycles >> 3; + cpuBlockCycles &= (1<<3)-1; + EventRaised |= intEventTest(); + } +} + +void intSetBranch() { + branch2 = /*cpuRegs.branch =*/ 1; +} + +//////////////////////////////////////////////////////////////////// +// R5900 Branching Instructions! +// These are the interpreter versions of the branch instructions. Unlike other +// types of interpreter instructions which can be called safely from the recompilers, +// these instructions are not "recSafe" because they may not invoke the +// necessary branch test logic that the recs need to maintain sync with the +// cpuRegs.pc and delaySlot instruction and such. + +namespace R5900 { +namespace Interpreter { +namespace OpcodeImpl { + +/********************************************************* +* Jump to target * +* Format: OP target * +*********************************************************/ + +void J() { + doBranch(_JumpTarget_); +} + +void JAL() { + _SetLink(31); doBranch(_JumpTarget_); +} + +/********************************************************* +* Register branch logic * +* Format: OP rs, rt, offset * +*********************************************************/ +#define RepBranchi32(op) \ + if (cpuRegs.GPR.r[_Rs_].SD[0] op cpuRegs.GPR.r[_Rt_].SD[0]) doBranch(_BranchTarget_); \ + else intEventTest(); + + +void BEQ() { RepBranchi32(==) } // Branch if Rs == Rt +void BNE() { RepBranchi32(!=) } // Branch if Rs != Rt + +/********************************************************* +* Register branch logic * +* Format: OP rs, offset * +*********************************************************/ +#define RepZBranchi32(op) \ + if(cpuRegs.GPR.r[_Rs_].SD[0] op 0) { \ + doBranch(_BranchTarget_); \ + } + +#define RepZBranchLinki32(op) \ + _SetLink(31); \ + if(cpuRegs.GPR.r[_Rs_].SD[0] op 0) { \ + doBranch(_BranchTarget_); \ + } + +void BGEZ() { RepZBranchi32(>=) } // Branch if Rs >= 0 +void BGEZAL() { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link +void BGTZ() { RepZBranchi32(>) } // Branch if Rs > 0 +void BLEZ() { RepZBranchi32(<=) } // Branch if Rs <= 0 +void BLTZ() { RepZBranchi32(<) } // Branch if Rs < 0 +void BLTZAL() { RepZBranchLinki32(<) } // Branch if Rs < 0 and link + + +/********************************************************* +* Register branch logic Likely * +* Format: OP rs, offset * +*********************************************************/ +#define RepZBranchi32Likely(op) \ + if(cpuRegs.GPR.r[_Rs_].SD[0] op 0) { \ + doBranch(_BranchTarget_); \ + } else { cpuRegs.pc +=4; intEventTest(); } + +#define RepZBranchLinki32Likely(op) \ + _SetLink(31); \ + if(cpuRegs.GPR.r[_Rs_].SD[0] op 0) { \ + doBranch(_BranchTarget_); \ + } else { cpuRegs.pc +=4; intEventTest(); } + +#define RepBranchi32Likely(op) \ + if(cpuRegs.GPR.r[_Rs_].SD[0] op cpuRegs.GPR.r[_Rt_].SD[0]) { \ + doBranch(_BranchTarget_); \ + } else { cpuRegs.pc +=4; intEventTest(); } + + +void BEQL() { RepBranchi32Likely(==) } // Branch if Rs == Rt +void BNEL() { RepBranchi32Likely(!=) } // Branch if Rs != Rt +void BLEZL() { RepZBranchi32Likely(<=) } // Branch if Rs <= 0 +void BGTZL() { RepZBranchi32Likely(>) } // Branch if Rs > 0 +void BLTZL() { RepZBranchi32Likely(<) } // Branch if Rs < 0 +void BGEZL() { RepZBranchi32Likely(>=) } // Branch if Rs >= 0 +void BLTZALL() { RepZBranchLinki32Likely(<) } // Branch if Rs < 0 and link +void BGEZALL() { RepZBranchLinki32Likely(>=) } // Branch if Rs >= 0 and link + +/********************************************************* +* Register jump * +* Format: OP rs, rd * +*********************************************************/ +void JR() { + doBranch(cpuRegs.GPR.r[_Rs_].UL[0]); +} + +void JALR() { + u32 temp = cpuRegs.GPR.r[_Rs_].UL[0]; + if (_Rd_) { _SetLink(_Rd_); } + doBranch(temp); +} + +} } } // end namespace R5900::Interpreter::OpcodeImpl + +//////////////////////////////////////////////////////// + +void intAlloc() +{ + // fixme : detect cpu for use the optimize asm code +} + +void intReset() +{ + cpuRegs.branch = 0; + branch2 = 0; +} + +bool intEventTest() +{ + // Perform counters, ints, and IOP updates: + return _cpuBranchTest_Shared(); +} + +void intExecute() +{ + g_EEFreezeRegs = false; + + // Mem protection should be handled by the caller here so that it can be + // done in a more optimized fashion. + + EventRaised = false; + + while( !EventRaised ) + { + execI(); + } +} + +static void intExecuteBlock() +{ + g_EEFreezeRegs = false; + + branch2 = 0; + while (!branch2) execI(); +} + +static void intStep() +{ + g_EEFreezeRegs = false; + execI(); +} + +static void intClear(u32 Addr, u32 Size) +{ +} + +static void intShutdown() { +} + +R5900cpu intCpu = { + intAlloc, + intReset, + intStep, + intExecute, + intExecuteBlock, + intClear, + intShutdown +}; diff --git a/pcsx2/IopBios.cpp b/pcsx2/IopBios.cpp index 6d767964ed..0092db2bd7 100644 --- a/pcsx2/IopBios.cpp +++ b/pcsx2/IopBios.cpp @@ -1,292 +1,292 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include -#include "PsxCommon.h" - -namespace R3000A { - -const char *biosA0n[256] = { -// 0x00 - "open", "lseek", "read", "write", - "close", "ioctl", "exit", "sys_a0_07", - "getc", "putc", "todigit", "atof", - "strtoul", "strtol", "abs", "labs", -// 0x10 - "atoi", "atol", "atob", "setjmp", - "longjmp", "strcat", "strncat", "strcmp", - "strncmp", "strcpy", "strncpy", "strlen", - "index", "rindex", "strchr", "strrchr", -// 0x20 - "strpbrk", "strspn", "strcspn", "strtok", - "strstr", "toupper", "tolower", "bcopy", - "bzero", "bcmp", "memcpy", "memset", - "memmove", "memcmp", "memchr", "rand", -// 0x30 - "srand", "qsort", "strtod", "malloc", - "free", "lsearch", "bsearch", "calloc", - "realloc", "InitHeap", "_exit", "getchar", - "putchar", "gets", "puts", "printf", -// 0x40 - "sys_a0_40", "LoadTest", "Load", "Exec", - "FlushCache", "InstallInterruptHandler", "GPU_dw", "mem2vram", - "SendGPUStatus", "GPU_cw", "GPU_cwb", "SendPackets", - "sys_a0_4c", "GetGPUStatus", "GPU_sync", "sys_a0_4f", -// 0x50 - "sys_a0_50", "LoadExec", "GetSysSp", "sys_a0_53", - "_96_init()", "_bu_init()", "_96_remove()", "sys_a0_57", - "sys_a0_58", "sys_a0_59", "sys_a0_5a", "dev_tty_init", - "dev_tty_open", "sys_a0_5d", "dev_tty_ioctl","dev_cd_open", -// 0x60 - "dev_cd_read", "dev_cd_close", "dev_cd_firstfile", "dev_cd_nextfile", - "dev_cd_chdir", "dev_card_open", "dev_card_read", "dev_card_write", - "dev_card_close", "dev_card_firstfile", "dev_card_nextfile","dev_card_erase", - "dev_card_undelete","dev_card_format", "dev_card_rename", "dev_card_6f", -// 0x70 - "_bu_init", "_96_init", "_96_remove", "sys_a0_73", - "sys_a0_74", "sys_a0_75", "sys_a0_76", "sys_a0_77", - "_96_CdSeekL", "sys_a0_79", "sys_a0_7a", "sys_a0_7b", - "_96_CdGetStatus", "sys_a0_7d", "_96_CdRead", "sys_a0_7f", -// 0x80 - "sys_a0_80", "sys_a0_81", "sys_a0_82", "sys_a0_83", - "sys_a0_84", "_96_CdStop", "sys_a0_86", "sys_a0_87", - "sys_a0_88", "sys_a0_89", "sys_a0_8a", "sys_a0_8b", - "sys_a0_8c", "sys_a0_8d", "sys_a0_8e", "sys_a0_8f", -// 0x90 - "sys_a0_90", "sys_a0_91", "sys_a0_92", "sys_a0_93", - "sys_a0_94", "sys_a0_95", "AddCDROMDevice", "AddMemCardDevide", - "DisableKernelIORedirection", "EnableKernelIORedirection", "sys_a0_9a", "sys_a0_9b", - "SetConf", "GetConf", "sys_a0_9e", "SetMem", -// 0xa0 - "_boot", "SystemError", "EnqueueCdIntr", "DequeueCdIntr", - "sys_a0_a4", "ReadSector", "get_cd_status", "bufs_cb_0", - "bufs_cb_1", "bufs_cb_2", "bufs_cb_3", "_card_info", - "_card_load", "_card_auto", "bufs_cd_4", "sys_a0_af", -// 0xb0 - "sys_a0_b0", "sys_a0_b1", "do_a_long_jmp", "sys_a0_b3", - "?? sub_function", -}; - -const char *biosB0n[256] = { -// 0x00 - "SysMalloc", "sys_b0_01", "sys_b0_02", "sys_b0_03", - "sys_b0_04", "sys_b0_05", "sys_b0_06", "DeliverEvent", - "OpenEvent", "CloseEvent", "WaitEvent", "TestEvent", - "EnableEvent", "DisableEvent", "OpenTh", "CloseTh", -// 0x10 - "ChangeTh", "sys_b0_11", "InitPAD", "StartPAD", - "StopPAD", "PAD_init", "PAD_dr", "ReturnFromExecption", - "ResetEntryInt", "HookEntryInt", "sys_b0_1a", "sys_b0_1b", - "sys_b0_1c", "sys_b0_1d", "sys_b0_1e", "sys_b0_1f", -// 0x20 - "UnDeliverEvent", "sys_b0_21", "sys_b0_22", "sys_b0_23", - "sys_b0_24", "sys_b0_25", "sys_b0_26", "sys_b0_27", - "sys_b0_28", "sys_b0_29", "sys_b0_2a", "sys_b0_2b", - "sys_b0_2c", "sys_b0_2d", "sys_b0_2e", "sys_b0_2f", -// 0x30 - "sys_b0_30", "sys_b0_31", "open", "lseek", - "read", "write", "close", "ioctl", - "exit", "sys_b0_39", "getc", "putc", - "getchar", "putchar", "gets", "puts", -// 0x40 - "cd", "format", "firstfile", "nextfile", - "rename", "delete", "undelete", "AddDevice", - "RemoteDevice", "PrintInstalledDevices", "InitCARD", "StartCARD", - "StopCARD", "sys_b0_4d", "_card_write", "_card_read", -// 0x50 - "_new_card", "Krom2RawAdd", "sys_b0_52", "sys_b0_53", - "_get_errno", "_get_error", "GetC0Table", "GetB0Table", - "_card_chan", "sys_b0_59", "sys_b0_5a", "ChangeClearPAD", - "_card_status", "_card_wait", -}; - -const char *biosC0n[256] = { -// 0x00 - "InitRCnt", "InitException", "SysEnqIntRP", "SysDeqIntRP", - "get_free_EvCB_slot", "get_free_TCB_slot", "ExceptionHandler", "InstallExeptionHandler", - "SysInitMemory", "SysInitKMem", "ChangeClearRCnt", "SystemError", - "InitDefInt", "sys_c0_0d", "sys_c0_0e", "sys_c0_0f", -// 0x10 - "sys_c0_10", "sys_c0_11", "InstallDevices", "FlushStfInOutPut", - "sys_c0_14", "_cdevinput", "_cdevscan", "_circgetc", - "_circputc", "ioabort", "sys_c0_1a", "KernelRedirect", - "PatchAOTable", -}; - -//#define r0 (psxRegs.GPR.n.r0) -#define at (psxRegs.GPR.n.at) -#define v0 (psxRegs.GPR.n.v0) -#define v1 (psxRegs.GPR.n.v1) -#define a0 (psxRegs.GPR.n.a0) -#define a1 (psxRegs.GPR.n.a1) -#define a2 (psxRegs.GPR.n.a2) -#define a3 (psxRegs.GPR.n.a3) -#define t0 (psxRegs.GPR.n.t0) -#define t1 (psxRegs.GPR.n.t1) -#define t2 (psxRegs.GPR.n.t2) -#define t3 (psxRegs.GPR.n.t3) -#define t4 (psxRegs.GPR.n.t4) -#define t5 (psxRegs.GPR.n.t5) -#define t6 (psxRegs.GPR.n.t6) -#define t7 (psxRegs.GPR.n.t7) -#define s0 (psxRegs.GPR.n.s0) -#define s1 (psxRegs.GPR.n.s1) -#define s2 (psxRegs.GPR.n.s2) -#define s3 (psxRegs.GPR.n.s3) -#define s4 (psxRegs.GPR.n.s4) -#define s5 (psxRegs.GPR.n.s5) -#define s6 (psxRegs.GPR.n.s6) -#define s7 (psxRegs.GPR.n.s7) -#define t8 (psxRegs.GPR.n.t6) -#define t9 (psxRegs.GPR.n.t7) -#define k0 (psxRegs.GPR.n.k0) -#define k1 (psxRegs.GPR.n.k1) -#define gp (psxRegs.GPR.n.gp) -#define sp (psxRegs.GPR.n.sp) -#define fp (psxRegs.GPR.n.s8) -#define ra (psxRegs.GPR.n.ra) -#define pc0 (psxRegs.pc) - -#define Ra0 ((char*)PSXM(a0)) -#define Ra1 ((char*)PSXM(a1)) -#define Ra2 ((char*)PSXM(a2)) -#define Ra3 ((char*)PSXM(a3)) -#define Rv0 ((char*)PSXM(v0)) -#define Rsp ((char*)PSXM(sp)) - -void bios_write() { // 0x35/0x03 - - - if (a0 == 1) { // stdout - char *ptr = Ra1; - - while (a2 > 0) { - SysPrintf("%c", *ptr++); a2--; - } - pc0 = ra; return; - } - PSXBIOS_LOG("bios_%s: %x,%x,%x\n", biosB0n[0x35], a0, a1, a2); - - v0 = -1; - pc0 = ra; -} - -void bios_printf() { // 3f - char tmp[1024]; - char tmp2[1024]; - unsigned long save[4]; - char *ptmp = tmp; - int n=1, i=0, j; - - memcpy(save, (char*)PSXM(sp), 4*4); - psxMu32(sp) = a0; - psxMu32(sp + 4) = a1; - psxMu32(sp + 8) = a2; - psxMu32(sp + 12) = a3; - - while (Ra0[i]) { - switch (Ra0[i]) { - case '%': - j = 0; - tmp2[j++] = '%'; -_start: - switch (Ra0[++i]) { - case '.': - case 'l': - tmp2[j++] = Ra0[i]; goto _start; - default: - if (Ra0[i] >= '0' && Ra0[i] <= '9') { - tmp2[j++] = Ra0[i]; - goto _start; - } - break; - } - tmp2[j++] = Ra0[i]; - tmp2[j] = 0; - - switch (Ra0[i]) { - case 'f': case 'F': - ptmp+= sprintf(ptmp, tmp2, (float)psxMu32(sp + n * 4)); n++; break; - case 'a': case 'A': - case 'e': case 'E': - case 'g': case 'G': - ptmp+= sprintf(ptmp, tmp2, (double)psxMu32(sp + n * 4)); n++; break; - case 'p': - case 'i': - case 'd': case 'D': - case 'o': case 'O': - case 'x': case 'X': - ptmp+= sprintf(ptmp, tmp2, (unsigned int)psxMu32(sp + n * 4)); n++; break; - case 'c': - ptmp+= sprintf(ptmp, tmp2, (unsigned char)psxMu32(sp + n * 4)); n++; break; - case 's': - ptmp+= sprintf(ptmp, tmp2, (char*)PSXM(psxMu32(sp + n * 4))); n++; break; - case '%': - *ptmp++ = Ra0[i]; break; - } - i++; - break; - default: - *ptmp++ = Ra0[i++]; - } - } - *ptmp = 0; - - memcpy((char*)PSXM(sp), save, 4*4); - - Console::Write( Color_Cyan, "%s", params tmp); - - pc0 = ra; -} - -void bios_putchar () { // 3d - Console::Write( Color_Cyan, "%c", params a0 ); - pc0 = ra; -} - -void bios_puts () { // 3e/3f - Console::Write( Color_Cyan, Ra0 ); - pc0 = ra; -} - -void (*biosA0[256])(); -void (*biosB0[256])(); -void (*biosC0[256])(); - -void psxBiosInit() { - int i; - - for(i = 0; i < 256; i++) { - biosA0[i] = NULL; - biosB0[i] = NULL; - biosC0[i] = NULL; - } - biosA0[0x3e] = bios_puts; - biosA0[0x3f] = bios_printf; - - biosB0[0x3d] = bios_putchar; - biosB0[0x3f] = bios_puts; - -} - -void psxBiosShutdown() { -} - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include +#include "PsxCommon.h" + +namespace R3000A { + +const char *biosA0n[256] = { +// 0x00 + "open", "lseek", "read", "write", + "close", "ioctl", "exit", "sys_a0_07", + "getc", "putc", "todigit", "atof", + "strtoul", "strtol", "abs", "labs", +// 0x10 + "atoi", "atol", "atob", "setjmp", + "longjmp", "strcat", "strncat", "strcmp", + "strncmp", "strcpy", "strncpy", "strlen", + "index", "rindex", "strchr", "strrchr", +// 0x20 + "strpbrk", "strspn", "strcspn", "strtok", + "strstr", "toupper", "tolower", "bcopy", + "bzero", "bcmp", "memcpy", "memset", + "memmove", "memcmp", "memchr", "rand", +// 0x30 + "srand", "qsort", "strtod", "malloc", + "free", "lsearch", "bsearch", "calloc", + "realloc", "InitHeap", "_exit", "getchar", + "putchar", "gets", "puts", "printf", +// 0x40 + "sys_a0_40", "LoadTest", "Load", "Exec", + "FlushCache", "InstallInterruptHandler", "GPU_dw", "mem2vram", + "SendGPUStatus", "GPU_cw", "GPU_cwb", "SendPackets", + "sys_a0_4c", "GetGPUStatus", "GPU_sync", "sys_a0_4f", +// 0x50 + "sys_a0_50", "LoadExec", "GetSysSp", "sys_a0_53", + "_96_init()", "_bu_init()", "_96_remove()", "sys_a0_57", + "sys_a0_58", "sys_a0_59", "sys_a0_5a", "dev_tty_init", + "dev_tty_open", "sys_a0_5d", "dev_tty_ioctl","dev_cd_open", +// 0x60 + "dev_cd_read", "dev_cd_close", "dev_cd_firstfile", "dev_cd_nextfile", + "dev_cd_chdir", "dev_card_open", "dev_card_read", "dev_card_write", + "dev_card_close", "dev_card_firstfile", "dev_card_nextfile","dev_card_erase", + "dev_card_undelete","dev_card_format", "dev_card_rename", "dev_card_6f", +// 0x70 + "_bu_init", "_96_init", "_96_remove", "sys_a0_73", + "sys_a0_74", "sys_a0_75", "sys_a0_76", "sys_a0_77", + "_96_CdSeekL", "sys_a0_79", "sys_a0_7a", "sys_a0_7b", + "_96_CdGetStatus", "sys_a0_7d", "_96_CdRead", "sys_a0_7f", +// 0x80 + "sys_a0_80", "sys_a0_81", "sys_a0_82", "sys_a0_83", + "sys_a0_84", "_96_CdStop", "sys_a0_86", "sys_a0_87", + "sys_a0_88", "sys_a0_89", "sys_a0_8a", "sys_a0_8b", + "sys_a0_8c", "sys_a0_8d", "sys_a0_8e", "sys_a0_8f", +// 0x90 + "sys_a0_90", "sys_a0_91", "sys_a0_92", "sys_a0_93", + "sys_a0_94", "sys_a0_95", "AddCDROMDevice", "AddMemCardDevide", + "DisableKernelIORedirection", "EnableKernelIORedirection", "sys_a0_9a", "sys_a0_9b", + "SetConf", "GetConf", "sys_a0_9e", "SetMem", +// 0xa0 + "_boot", "SystemError", "EnqueueCdIntr", "DequeueCdIntr", + "sys_a0_a4", "ReadSector", "get_cd_status", "bufs_cb_0", + "bufs_cb_1", "bufs_cb_2", "bufs_cb_3", "_card_info", + "_card_load", "_card_auto", "bufs_cd_4", "sys_a0_af", +// 0xb0 + "sys_a0_b0", "sys_a0_b1", "do_a_long_jmp", "sys_a0_b3", + "?? sub_function", +}; + +const char *biosB0n[256] = { +// 0x00 + "SysMalloc", "sys_b0_01", "sys_b0_02", "sys_b0_03", + "sys_b0_04", "sys_b0_05", "sys_b0_06", "DeliverEvent", + "OpenEvent", "CloseEvent", "WaitEvent", "TestEvent", + "EnableEvent", "DisableEvent", "OpenTh", "CloseTh", +// 0x10 + "ChangeTh", "sys_b0_11", "InitPAD", "StartPAD", + "StopPAD", "PAD_init", "PAD_dr", "ReturnFromExecption", + "ResetEntryInt", "HookEntryInt", "sys_b0_1a", "sys_b0_1b", + "sys_b0_1c", "sys_b0_1d", "sys_b0_1e", "sys_b0_1f", +// 0x20 + "UnDeliverEvent", "sys_b0_21", "sys_b0_22", "sys_b0_23", + "sys_b0_24", "sys_b0_25", "sys_b0_26", "sys_b0_27", + "sys_b0_28", "sys_b0_29", "sys_b0_2a", "sys_b0_2b", + "sys_b0_2c", "sys_b0_2d", "sys_b0_2e", "sys_b0_2f", +// 0x30 + "sys_b0_30", "sys_b0_31", "open", "lseek", + "read", "write", "close", "ioctl", + "exit", "sys_b0_39", "getc", "putc", + "getchar", "putchar", "gets", "puts", +// 0x40 + "cd", "format", "firstfile", "nextfile", + "rename", "delete", "undelete", "AddDevice", + "RemoteDevice", "PrintInstalledDevices", "InitCARD", "StartCARD", + "StopCARD", "sys_b0_4d", "_card_write", "_card_read", +// 0x50 + "_new_card", "Krom2RawAdd", "sys_b0_52", "sys_b0_53", + "_get_errno", "_get_error", "GetC0Table", "GetB0Table", + "_card_chan", "sys_b0_59", "sys_b0_5a", "ChangeClearPAD", + "_card_status", "_card_wait", +}; + +const char *biosC0n[256] = { +// 0x00 + "InitRCnt", "InitException", "SysEnqIntRP", "SysDeqIntRP", + "get_free_EvCB_slot", "get_free_TCB_slot", "ExceptionHandler", "InstallExeptionHandler", + "SysInitMemory", "SysInitKMem", "ChangeClearRCnt", "SystemError", + "InitDefInt", "sys_c0_0d", "sys_c0_0e", "sys_c0_0f", +// 0x10 + "sys_c0_10", "sys_c0_11", "InstallDevices", "FlushStfInOutPut", + "sys_c0_14", "_cdevinput", "_cdevscan", "_circgetc", + "_circputc", "ioabort", "sys_c0_1a", "KernelRedirect", + "PatchAOTable", +}; + +//#define r0 (psxRegs.GPR.n.r0) +#define at (psxRegs.GPR.n.at) +#define v0 (psxRegs.GPR.n.v0) +#define v1 (psxRegs.GPR.n.v1) +#define a0 (psxRegs.GPR.n.a0) +#define a1 (psxRegs.GPR.n.a1) +#define a2 (psxRegs.GPR.n.a2) +#define a3 (psxRegs.GPR.n.a3) +#define t0 (psxRegs.GPR.n.t0) +#define t1 (psxRegs.GPR.n.t1) +#define t2 (psxRegs.GPR.n.t2) +#define t3 (psxRegs.GPR.n.t3) +#define t4 (psxRegs.GPR.n.t4) +#define t5 (psxRegs.GPR.n.t5) +#define t6 (psxRegs.GPR.n.t6) +#define t7 (psxRegs.GPR.n.t7) +#define s0 (psxRegs.GPR.n.s0) +#define s1 (psxRegs.GPR.n.s1) +#define s2 (psxRegs.GPR.n.s2) +#define s3 (psxRegs.GPR.n.s3) +#define s4 (psxRegs.GPR.n.s4) +#define s5 (psxRegs.GPR.n.s5) +#define s6 (psxRegs.GPR.n.s6) +#define s7 (psxRegs.GPR.n.s7) +#define t8 (psxRegs.GPR.n.t6) +#define t9 (psxRegs.GPR.n.t7) +#define k0 (psxRegs.GPR.n.k0) +#define k1 (psxRegs.GPR.n.k1) +#define gp (psxRegs.GPR.n.gp) +#define sp (psxRegs.GPR.n.sp) +#define fp (psxRegs.GPR.n.s8) +#define ra (psxRegs.GPR.n.ra) +#define pc0 (psxRegs.pc) + +#define Ra0 ((char*)PSXM(a0)) +#define Ra1 ((char*)PSXM(a1)) +#define Ra2 ((char*)PSXM(a2)) +#define Ra3 ((char*)PSXM(a3)) +#define Rv0 ((char*)PSXM(v0)) +#define Rsp ((char*)PSXM(sp)) + +void bios_write() { // 0x35/0x03 + + + if (a0 == 1) { // stdout + char *ptr = Ra1; + + while (a2 > 0) { + SysPrintf("%c", *ptr++); a2--; + } + pc0 = ra; return; + } + PSXBIOS_LOG("bios_%s: %x,%x,%x\n", biosB0n[0x35], a0, a1, a2); + + v0 = -1; + pc0 = ra; +} + +void bios_printf() { // 3f + char tmp[1024]; + char tmp2[1024]; + unsigned long save[4]; + char *ptmp = tmp; + int n=1, i=0, j; + + memcpy(save, (char*)PSXM(sp), 4*4); + psxMu32(sp) = a0; + psxMu32(sp + 4) = a1; + psxMu32(sp + 8) = a2; + psxMu32(sp + 12) = a3; + + while (Ra0[i]) { + switch (Ra0[i]) { + case '%': + j = 0; + tmp2[j++] = '%'; +_start: + switch (Ra0[++i]) { + case '.': + case 'l': + tmp2[j++] = Ra0[i]; goto _start; + default: + if (Ra0[i] >= '0' && Ra0[i] <= '9') { + tmp2[j++] = Ra0[i]; + goto _start; + } + break; + } + tmp2[j++] = Ra0[i]; + tmp2[j] = 0; + + switch (Ra0[i]) { + case 'f': case 'F': + ptmp+= sprintf(ptmp, tmp2, (float)psxMu32(sp + n * 4)); n++; break; + case 'a': case 'A': + case 'e': case 'E': + case 'g': case 'G': + ptmp+= sprintf(ptmp, tmp2, (double)psxMu32(sp + n * 4)); n++; break; + case 'p': + case 'i': + case 'd': case 'D': + case 'o': case 'O': + case 'x': case 'X': + ptmp+= sprintf(ptmp, tmp2, (unsigned int)psxMu32(sp + n * 4)); n++; break; + case 'c': + ptmp+= sprintf(ptmp, tmp2, (unsigned char)psxMu32(sp + n * 4)); n++; break; + case 's': + ptmp+= sprintf(ptmp, tmp2, (char*)PSXM(psxMu32(sp + n * 4))); n++; break; + case '%': + *ptmp++ = Ra0[i]; break; + } + i++; + break; + default: + *ptmp++ = Ra0[i++]; + } + } + *ptmp = 0; + + memcpy((char*)PSXM(sp), save, 4*4); + + Console::Write( Color_Cyan, "%s", params tmp); + + pc0 = ra; +} + +void bios_putchar () { // 3d + Console::Write( Color_Cyan, "%c", params a0 ); + pc0 = ra; +} + +void bios_puts () { // 3e/3f + Console::Write( Color_Cyan, Ra0 ); + pc0 = ra; +} + +void (*biosA0[256])(); +void (*biosB0[256])(); +void (*biosC0[256])(); + +void psxBiosInit() { + int i; + + for(i = 0; i < 256; i++) { + biosA0[i] = NULL; + biosB0[i] = NULL; + biosC0[i] = NULL; + } + biosA0[0x3e] = bios_puts; + biosA0[0x3f] = bios_printf; + + biosB0[0x3d] = bios_putchar; + biosB0[0x3f] = bios_puts; + +} + +void psxBiosShutdown() { +} + } // end namespace R3000A \ No newline at end of file diff --git a/pcsx2/IopBios.h b/pcsx2/IopBios.h index f565df0373..dd7fa4094a 100644 --- a/pcsx2/IopBios.h +++ b/pcsx2/IopBios.h @@ -1,41 +1,41 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __PSXBIOS_H__ -#define __PSXBIOS_H__ - -namespace R3000A -{ - extern const char *biosA0n[256]; - extern const char *biosB0n[256]; - extern const char *biosC0n[256]; - - void psxBiosInit(); - void psxBiosShutdown(); - void psxBiosException(); - void psxBiosFreeze(int Mode); - - extern void (*biosA0[256])(); - extern void (*biosB0[256])(); - extern void (*biosC0[256])(); - - extern void bios_write(); - extern void bios_printf(); - -} -#endif /* __PSXBIOS_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __PSXBIOS_H__ +#define __PSXBIOS_H__ + +namespace R3000A +{ + extern const char *biosA0n[256]; + extern const char *biosB0n[256]; + extern const char *biosC0n[256]; + + void psxBiosInit(); + void psxBiosShutdown(); + void psxBiosException(); + void psxBiosFreeze(int Mode); + + extern void (*biosA0[256])(); + extern void (*biosB0[256])(); + extern void (*biosC0[256])(); + + extern void bios_write(); + extern void bios_printf(); + +} +#endif /* __PSXBIOS_H__ */ diff --git a/pcsx2/IopBios2.h b/pcsx2/IopBios2.h index 68af2547f0..5f63885fd2 100644 --- a/pcsx2/IopBios2.h +++ b/pcsx2/IopBios2.h @@ -1,94 +1,94 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -/***** sysmem imageInfo -00000800: 00 16 00 00 70 14 00 00 ¦ 01 01 00 00 01 00 00 00 -0000 next: .word ? //00001600 -0004 name: .word ? //00001470 -0008 version: .half ? //0101 -000A flags: .half ? //---- -000C index: .half ? //0001 -000E field_E: .half ? //---- -00000810: 90 08 00 00 A0 94 00 00 ¦ 30 08 00 00 40 0C 00 00 -0010 entry: .word ? //00000890 -0014 gp_value: .word ? //000094A0 -0018 p1_vaddr: .word ? //00000830 -001C text_size: .word ? //00000C40 -00000820: 40 00 00 00 10 00 00 00 ¦ 00 00 00 00 00 00 00 00 -0020 data_size: .word ? //00000040 -0024 bss_size: .word ? //00000010 -0028 field_28: .word ? //-------- -002C field_2C: .word ? //-------- -*****/ - -#ifndef __PSX_BIOS_H__ -#define __PSX_BIOS_H__ - -struct irxImageInfo { - u32 next, //+00 - name; //+04 - u16 version, //+08 - flags, //+0A - index, //+0C - _unkE; //+0E - u32 entry, //+10 - _gp, //+14 - vaddr, //+18 - text_size, //+1C - data_size, //+20 - bss_size, //+24 - _pad28, //+28 - _pad2C; //+2C -}; //=30 - -struct _sifServer { - int active; - u32 server; - u32 fhandler; -}; - -#define SIF_SERVERS 32 - -_sifServer sifServer[SIF_SERVERS]; - -// max modules/funcs - -#define IRX_MODULES 64 -#define IRX_FUNCS 256 - -struct irxFunc { - u32 num; - u32 entry; -}; - -struct irxModule { - int active; - u32 name[2]; - irxFunc funcs[IRX_FUNCS]; -}; - -irxModule irxMod[IRX_MODULES]; - - -void iopModulesInit(); -int iopSetImportFunc(u32 *ptr); -int iopSetExportFunc(u32 *ptr); -void sifServerCall(u32 server, u32 num, char *bin, int insize, char *bout, int outsize); -void sifAddServer(u32 server, u32 fhandler); - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +/***** sysmem imageInfo +00000800: 00 16 00 00 70 14 00 00 ¦ 01 01 00 00 01 00 00 00 +0000 next: .word ? //00001600 +0004 name: .word ? //00001470 +0008 version: .half ? //0101 +000A flags: .half ? //---- +000C index: .half ? //0001 +000E field_E: .half ? //---- +00000810: 90 08 00 00 A0 94 00 00 ¦ 30 08 00 00 40 0C 00 00 +0010 entry: .word ? //00000890 +0014 gp_value: .word ? //000094A0 +0018 p1_vaddr: .word ? //00000830 +001C text_size: .word ? //00000C40 +00000820: 40 00 00 00 10 00 00 00 ¦ 00 00 00 00 00 00 00 00 +0020 data_size: .word ? //00000040 +0024 bss_size: .word ? //00000010 +0028 field_28: .word ? //-------- +002C field_2C: .word ? //-------- +*****/ + +#ifndef __PSX_BIOS_H__ +#define __PSX_BIOS_H__ + +struct irxImageInfo { + u32 next, //+00 + name; //+04 + u16 version, //+08 + flags, //+0A + index, //+0C + _unkE; //+0E + u32 entry, //+10 + _gp, //+14 + vaddr, //+18 + text_size, //+1C + data_size, //+20 + bss_size, //+24 + _pad28, //+28 + _pad2C; //+2C +}; //=30 + +struct _sifServer { + int active; + u32 server; + u32 fhandler; +}; + +#define SIF_SERVERS 32 + +_sifServer sifServer[SIF_SERVERS]; + +// max modules/funcs + +#define IRX_MODULES 64 +#define IRX_FUNCS 256 + +struct irxFunc { + u32 num; + u32 entry; +}; + +struct irxModule { + int active; + u32 name[2]; + irxFunc funcs[IRX_FUNCS]; +}; + +irxModule irxMod[IRX_MODULES]; + + +void iopModulesInit(); +int iopSetImportFunc(u32 *ptr); +int iopSetExportFunc(u32 *ptr); +void sifServerCall(u32 server, u32 num, char *bin, int insize, char *bout, int outsize); +void sifAddServer(u32 server, u32 fhandler); + +#endif diff --git a/pcsx2/IopCounters.cpp b/pcsx2/IopCounters.cpp index 3f30937e2b..60207e4862 100644 --- a/pcsx2/IopCounters.cpp +++ b/pcsx2/IopCounters.cpp @@ -1,746 +1,746 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -// Note on INTC usage: All counters code is always called from inside the context of an -// event test, so instead of using the iopTestIntc we just set the 0x1070 flags directly. -// The EventText function will pick it up. - -#include "PrecompiledHeader.h" - -#include -#include "PsxCommon.h" - -psxCounter psxCounters[8]; -s32 psxNextCounter; -u32 psxNextsCounter; -u8 psxhblankgate = 0; -u8 psxvblankgate = 0; - -// flags when the gate is off or counter disabled. (do not count) -#define IOPCNT_STOPPED (0x10000000ul) - -// used to disable targets until after an overflow -#define IOPCNT_FUTURE_TARGET (0x1000000000ULL) - -#define IOPCNT_ENABLE_GATE (1<<0) // enables gate-based counters -#define IOPCNT_INT_TARGET (1<<4) // 0x10 triggers an interrupt on targets -#define IOPCNT_INT_OVERFLOW (1<<5) // 0x20 triggers an interrupt on overflows -#define IOPCNT_ALT_SOURCE (1<<8) // 0x100 uses hblank on counters 1 and 3, and PSXCLOCK on counter 0 - -// Use an arbitrary value to flag HBLANK counters. -// These counters will be counted by the hblank gates coming from the EE, -// which ensures they stay 100% in sync with the EE's hblank counters. -#define PSXHBLANK 0x2001 - -static void psxRcntReset(int index) -{ - psxCounters[index].count = 0; - psxCounters[index].mode&= ~0x18301C00; - psxCounters[index].sCycleT = psxRegs.cycle; -} - -static void _rcntSet( int cntidx ) -{ - u64 overflowCap = (cntidx>=3) ? 0x100000000ULL : 0x10000; - u64 c; - - const psxCounter& counter = psxCounters[cntidx]; - - // psxNextCounter is relative to the psxRegs.cycle when rcntUpdate() was last called. - // However, the current _rcntSet could be called at any cycle count, so we need to take - // that into account. Adding the difference from that cycle count to the current one - // will do the trick! - - if( counter.mode & IOPCNT_STOPPED || counter.rate == PSXHBLANK) return; - - // check for special cases where the overflow or target has just passed - // (we probably missed it because we're doing/checking other things) - if( counter.count > overflowCap || counter.count > counter.target ) - { - psxNextCounter = 4; - return; - } - - c = (u64)((overflowCap - counter.count) * counter.rate) - (psxRegs.cycle - counter.sCycleT); - c += psxRegs.cycle - psxNextsCounter; // adjust for time passed since last rcntUpdate(); - if(c < (u64)psxNextCounter) psxNextCounter = (u32)c; - - //if((counter.mode & 0x10) == 0 || psxCounters[i].target > 0xffff) continue; - if( counter.target & IOPCNT_FUTURE_TARGET ) return; - - c = (s64)((counter.target - counter.count) * counter.rate) - (psxRegs.cycle - counter.sCycleT); - c += psxRegs.cycle - psxNextsCounter; // adjust for time passed since last rcntUpdate(); - if(c < (u64)psxNextCounter) psxNextCounter = (u32)c; -} - - -void psxRcntInit() { - int i; - - memzero_obj( psxCounters ); - - for (i=0; i<3; i++) { - psxCounters[i].rate = 1; - psxCounters[i].mode|= 0x0400; - psxCounters[i].target = IOPCNT_FUTURE_TARGET; - } - for (i=3; i<6; i++) { - psxCounters[i].rate = 1; - psxCounters[i].mode|= 0x0400; - psxCounters[i].target = IOPCNT_FUTURE_TARGET; - } - - psxCounters[0].interrupt = 0x10; - psxCounters[1].interrupt = 0x20; - psxCounters[2].interrupt = 0x40; - - psxCounters[3].interrupt = 0x04000; - psxCounters[4].interrupt = 0x08000; - psxCounters[5].interrupt = 0x10000; - - if (SPU2async != NULL) - { - psxCounters[6].rate = 768*12; - psxCounters[6].CycleT = psxCounters[6].rate; - psxCounters[6].mode = 0x8; - } - - if (USBasync != NULL) - { - psxCounters[7].rate = PSXCLK/1000; - psxCounters[7].CycleT = psxCounters[7].rate; - psxCounters[7].mode = 0x8; - } - - for (i=0; i<8; i++) - psxCounters[i].sCycleT = psxRegs.cycle; - - // Tell the IOP to branch ASAP, so that timers can get - // configured properly. - psxNextCounter = 1; - psxNextsCounter = psxRegs.cycle; -} - -static void __fastcall _rcntTestTarget( int i ) -{ - if( psxCounters[i].count < psxCounters[i].target ) return; - - PSXCNT_LOG("IOP Counter[%d] target 0x%I64x >= 0x%I64x (mode: %x)\n", - i, psxCounters[i].count, psxCounters[i].target, psxCounters[i].mode); - - if (psxCounters[i].mode & IOPCNT_INT_TARGET) - { - // Target interrupt - - if(psxCounters[i].mode & 0x80) - psxCounters[i].mode &= ~0x0400; // Interrupt flag - psxCounters[i].mode |= 0x0800; // Target flag - - psxHu32(0x1070) |= psxCounters[i].interrupt; - } - - if (psxCounters[i].mode & 0x08) - { - // Reset on target - psxCounters[i].count -= psxCounters[i].target; - if(!(psxCounters[i].mode & 0x40)) - { - SysPrintf("Counter %x repeat intr not set on zero ret, ignoring target\n", i); - psxCounters[i].target |= IOPCNT_FUTURE_TARGET; - } - } else psxCounters[i].target |= IOPCNT_FUTURE_TARGET; -} - - -static __forceinline void _rcntTestOverflow( int i ) -{ - u64 maxTarget = ( i < 3 ) ? 0xffff : 0xfffffffful; - if( psxCounters[i].count <= maxTarget ) return; - - PSXCNT_LOG("IOP Counter[%d] overflow 0x%I64x >= 0x%I64x (mode: %x)\n", - i, psxCounters[i].count, maxTarget, psxCounters[i].mode ); - - if(psxCounters[i].mode & IOPCNT_INT_OVERFLOW) - { - // Overflow interrupt - psxHu32(0x1070) |= psxCounters[i].interrupt; - psxCounters[i].mode |= 0x1000; // Overflow flag - if(psxCounters[i].mode & 0x80) - psxCounters[i].mode &= ~0x0400; // Interrupt flag - } - - // Update count and target. - // Count wraps around back to zero, while the target is restored (if needed). - // (high bit of the target gets set by rcntWtarget when the target is behind - // the counter value, and thus should not be flagged until after an overflow) - - psxCounters[i].count &= maxTarget; - psxCounters[i].target &= maxTarget; -} - -/* -Gate: - TM_NO_GATE 000 - TM_GATE_ON_Count 001 - TM_GATE_ON_ClearStart 011 - TM_GATE_ON_Clear_OFF_Start 101 - TM_GATE_ON_Start 111 - - V-blank ----+ +----------------------------+ +------ - | | | | - | | | | - +----+ +----+ - TM_NO_GATE: - - 0================================>============ - - TM_GATE_ON_Count: - - <---->0==========================><---->0===== - - TM_GATE_ON_ClearStart: - - 0====>0================================>0===== - - TM_GATE_ON_Clear_OFF_Start: - - 0====><-------------------------->0====><----- - - TM_GATE_ON_Start: - - <---->0==========================>============ -*/ - -static void _psxCheckStartGate( int i ) -{ - if(!(psxCounters[i].mode & IOPCNT_ENABLE_GATE)) return; //Ignore Gate - - switch((psxCounters[i].mode & 0x6) >> 1) - { - case 0x0: //GATE_ON_count - stop count on gate start: - - // get the current count at the time of stoppage: - psxCounters[i].count = ( i < 3 ) ? - psxRcntRcount16( i ) : psxRcntRcount32( i ); - psxCounters[i].mode |= IOPCNT_STOPPED; - return; - - case 0x1: //GATE_ON_ClearStart - count normally with resets after every end gate - // do nothing - All counting will be done on a need-to-count basis. - return; - - case 0x2: //GATE_ON_Clear_OFF_Start - start counting on gate start, stop on gate end - psxCounters[i].count = 0; - psxCounters[i].sCycleT = psxRegs.cycle; - psxCounters[i].mode &= ~IOPCNT_STOPPED; - break; - - case 0x3: //GATE_ON_Start - start and count normally on gate end (no restarts or stops or clears) - // do nothing! - return; - } - _rcntSet( i ); -} - -static void _psxCheckEndGate(int i) -{ - if(!(psxCounters[i].mode & IOPCNT_ENABLE_GATE)) return; //Ignore Gate - - switch((psxCounters[i].mode & 0x6) >> 1) - { - case 0x0: //GATE_ON_count - reset and start counting - case 0x1: //GATE_ON_ClearStart - count normally with resets after every end gate - psxCounters[i].count = 0; - psxCounters[i].sCycleT = psxRegs.cycle; - psxCounters[i].mode &= ~IOPCNT_STOPPED; - break; - - case 0x2: //GATE_ON_Clear_OFF_Start - start counting on gate start, stop on gate end - psxCounters[i].count = ( i < 3 ) ? - psxRcntRcount16( i ) : psxRcntRcount32( i ); - psxCounters[i].mode |= IOPCNT_STOPPED; - return; // do not set the counter - - case 0x3: //GATE_ON_Start - start and count normally (no restarts or stops or clears) - if( psxCounters[i].mode & IOPCNT_STOPPED ) - { - psxCounters[i].count = 0; - psxCounters[i].sCycleT = psxRegs.cycle; - psxCounters[i].mode &= ~IOPCNT_STOPPED; - } - break; - } - _rcntSet( i ); -} - -void psxCheckStartGate16(int i) -{ - assert( i < 3 ); - - if(i == 0) // hSync counting... - { - // AlternateSource/scanline counters for Gates 1 and 3. - // We count them here so that they stay nicely synced with the EE's hsync. - - const u32 altSourceCheck = IOPCNT_ALT_SOURCE | IOPCNT_ENABLE_GATE; - const u32 stoppedGateCheck = (IOPCNT_STOPPED | altSourceCheck ); - - // count if alt source is enabled and either: - // * the gate is enabled and not stopped. - // * the gate is disabled. - - if( (psxCounters[1].mode & altSourceCheck) == IOPCNT_ALT_SOURCE || - (psxCounters[1].mode & stoppedGateCheck ) == altSourceCheck ) - { - psxCounters[1].count++; - _rcntTestTarget( 1 ); - _rcntTestOverflow( 1 ); - } - - if( (psxCounters[3].mode & altSourceCheck) == IOPCNT_ALT_SOURCE || - (psxCounters[3].mode & stoppedGateCheck ) == altSourceCheck ) - { - psxCounters[3].count++; - _rcntTestTarget( 3 ); - _rcntTestOverflow( 3 ); - } - } - - _psxCheckStartGate( i ); -} - -void psxCheckEndGate16(int i) -{ - assert(i < 3); - _psxCheckEndGate( i ); -} - -static void psxCheckStartGate32(int i) -{ - // 32 bit gate is called for gate 3 only. Ever. - assert(i == 3); - _psxCheckStartGate( i ); -} - -static void psxCheckEndGate32(int i) -{ - assert(i == 3); - _psxCheckEndGate( i ); -} - - -void psxVBlankStart() -{ - cdvdVsync(); - psxHu32(0x1070) |= 1; - if(psxvblankgate & (1 << 1)) psxCheckStartGate16(1); - if(psxvblankgate & (1 << 3)) psxCheckStartGate32(3); -} - -void psxVBlankEnd() -{ - psxHu32(0x1070) |= 0x800; - if(psxvblankgate & (1 << 1)) psxCheckEndGate16(1); - if(psxvblankgate & (1 << 3)) psxCheckEndGate32(3); -} - -void psxRcntUpdate() -{ - int i; - //u32 change = 0; - - for (i=0; i<=5; i++) - { - s32 change = psxRegs.cycle - psxCounters[i].sCycleT; - - // don't count disabled, gated, or hblank counters... - // We can't check the ALTSOURCE flag because the PSXCLOCK source *should* - // be counted here. - - if( psxCounters[i].mode & (IOPCNT_STOPPED | IOPCNT_ENABLE_GATE) ) continue; - if( psxCounters[i].rate == PSXHBLANK ) continue; - if( change <= 0 ) continue; - - psxCounters[i].count += change / psxCounters[i].rate; - if(psxCounters[i].rate != 1) - { - change -= (change / psxCounters[i].rate) * psxCounters[i].rate; - psxCounters[i].sCycleT = psxRegs.cycle - change; - } - else - psxCounters[i].sCycleT = psxRegs.cycle; - } - - // Do target/overflow testing - // Optimization Note: This approach is very sound. Please do not try to unroll it - // as the size of the Test functions will cause code cache clutter and slowness. - - for( i=0; i<6; i++ ) - { - // don't do target/oveflow checks for hblankers. Those - // checks are done when the counters are updated. - if( psxCounters[i].rate == PSXHBLANK ) continue; - if( psxCounters[i].mode & IOPCNT_STOPPED ) continue; - - _rcntTestTarget( i ); - _rcntTestOverflow( i ); - - // perform second target test because if we overflowed above it's possible we - // already shot past our target if it was very near zero. - - //if( psxCounters[i].count >= psxCounters[i].target ) _rcntTestTarget( i ); - } - - psxNextCounter = 0xffffff; - psxNextsCounter = psxRegs.cycle; - - if(SPU2async) - { - const s32 difference = psxRegs.cycle - psxCounters[6].sCycleT; - s32 c = psxCounters[6].CycleT; - - if(difference >= psxCounters[6].CycleT) - { - SPU2async(difference); - psxCounters[6].sCycleT = psxRegs.cycle; - psxCounters[6].CycleT = psxCounters[6].rate; - } - else c -= difference; - psxNextCounter = c; - } - - if(USBasync) - { - const s32 difference = psxRegs.cycle - psxCounters[7].sCycleT; - s32 c = psxCounters[7].CycleT; - - if(difference >= psxCounters[7].CycleT) - { - USBasync(difference); - psxCounters[7].sCycleT = psxRegs.cycle; - psxCounters[7].CycleT = psxCounters[7].rate; - } - else c -= difference; - if (c < psxNextCounter) psxNextCounter = c; - } - - for (i=0; i<6; i++) _rcntSet( i ); -} - -void psxRcntWcount16(int index, u32 value) -{ - u32 change; - - assert( index < 3 ); - PSXCNT_LOG("IOP Counter[%d] writeCount16 = %x\n", index, value); - - if(psxCounters[index].rate != PSXHBLANK) - { - // Re-adjust the sCycleT to match where the counter is currently - // (remainder of the rate divided into the time passed will do the trick) - - change = psxRegs.cycle - psxCounters[index].sCycleT; - psxCounters[index].sCycleT = psxRegs.cycle - (change % psxCounters[index].rate); - } - - psxCounters[index].count = value & 0xffff; - psxCounters[index].target &= 0xffff; - _rcntSet( index ); -} - -void psxRcntWcount32(int index, u32 value) -{ - u32 change; - - assert( index >= 3 && index < 6 ); - PSXCNT_LOG("IOP Counter[%d] writeCount32 = %x\n", index, value); - - if(psxCounters[index].rate != PSXHBLANK) - { - // Re-adjust the sCycleT to match where the counter is currently - // (remainder of the rate divided into the time passed will do the trick) - - change = psxRegs.cycle - psxCounters[index].sCycleT; - psxCounters[index].sCycleT = psxRegs.cycle - (change % psxCounters[index].rate); - } - - psxCounters[index].count = value & 0xffffffff; - psxCounters[index].target &= 0xffffffff; - _rcntSet( index ); -} - -void psxRcnt0Wmode(u32 value) -{ - PSXCNT_LOG("IOP Counter[0] writeMode = %lx\n", value); - - psxCounters[0].mode = value; - psxCounters[0].mode|= 0x0400; - psxCounters[0].rate = 1; - - if(value & IOPCNT_ALT_SOURCE) - psxCounters[0].rate = PSXPIXEL; - - if(psxCounters[0].mode & IOPCNT_ENABLE_GATE) - { - // gated counters are added up as per the h/vblank timers. - PSXCNT_LOG("IOP Counter[0] Gate Check set, value = %x\n", value); - psxhblankgate |= 1; - } - else psxhblankgate &= ~1; - - psxCounters[0].count = 0; - psxCounters[0].sCycleT = psxRegs.cycle; - psxCounters[0].target &= 0xffff; - - _rcntSet( 0 ); -} - -void psxRcnt1Wmode(u32 value) -{ - PSXCNT_LOG("IOP Counter[0] writeMode = %lx\n", value); - - psxCounters[1].mode = value; - psxCounters[1].mode|= 0x0400; - psxCounters[1].rate = 1; - - if(value & IOPCNT_ALT_SOURCE) - psxCounters[1].rate = PSXHBLANK; - - if(psxCounters[1].mode & IOPCNT_ENABLE_GATE) - { - PSXCNT_LOG("IOP Counter[1] Gate Check set, value = %x\n", value); - psxvblankgate |= 1<<1; - } - else psxvblankgate &= ~(1<<1); - - psxCounters[1].count = 0; - psxCounters[1].sCycleT = psxRegs.cycle; - psxCounters[1].target &= 0xffff; - _rcntSet( 1 ); -} - -void psxRcnt2Wmode(u32 value) -{ - PSXCNT_LOG("IOP Counter[0] writeMode = %lx\n", value); - - psxCounters[2].mode = value; - psxCounters[2].mode|= 0x0400; - - switch(value & 0x200) - { - case 0x200: psxCounters[2].rate = 8; break; - case 0x000: psxCounters[2].rate = 1; break; - } - - if((psxCounters[2].mode & 0x7) == 0x7 || (psxCounters[2].mode & 0x7) == 0x1) - { - //SysPrintf("Gate set on IOP C2, disabling\n"); - psxCounters[2].mode |= IOPCNT_STOPPED; - } - - psxCounters[2].count = 0; - psxCounters[2].sCycleT = psxRegs.cycle; - psxCounters[2].target &= 0xffff; - _rcntSet( 2 ); -} - -void psxRcnt3Wmode(u32 value) -{ - PSXCNT_LOG("IOP Counter[3] writeMode = %lx\n", value); - - psxCounters[3].mode = value; - psxCounters[3].rate = 1; - psxCounters[3].mode|= 0x0400; - - if(value & IOPCNT_ALT_SOURCE) - psxCounters[3].rate = PSXHBLANK; - - if(psxCounters[3].mode & IOPCNT_ENABLE_GATE) - { - PSXCNT_LOG("IOP Counter[3] Gate Check set, value = %x\n", value); - psxvblankgate |= 1<<3; - } - else psxvblankgate &= ~(1<<3); - - psxCounters[3].count = 0; - psxCounters[3].sCycleT = psxRegs.cycle; - psxCounters[3].target &= 0xffffffff; - _rcntSet( 3 ); -} - -void psxRcnt4Wmode(u32 value) -{ - PSXCNT_LOG("IOP Counter[4] writeMode = %lx\n", value); - - psxCounters[4].mode = value; - psxCounters[4].mode|= 0x0400; - - switch(value & 0x6000) - { - case 0x0000: psxCounters[4].rate = 1; break; - case 0x2000: psxCounters[4].rate = 8; break; - case 0x4000: psxCounters[4].rate = 16; break; - case 0x6000: psxCounters[4].rate = 256; break; - } - // Need to set a rate and target - if((psxCounters[4].mode & 0x7) == 0x7 || (psxCounters[4].mode & 0x7) == 0x1) - { - SysPrintf("Gate set on IOP C4, disabling\n"); - psxCounters[4].mode |= IOPCNT_STOPPED; - } - - psxCounters[4].count = 0; - psxCounters[4].sCycleT = psxRegs.cycle; - psxCounters[4].target &= 0xffffffff; - _rcntSet( 4 ); -} - -void psxRcnt5Wmode(u32 value) -{ - PSXCNT_LOG("IOP Counter[5] writeMode = %lx\n", value); - - psxCounters[5].mode = value; - psxCounters[5].mode|= 0x0400; - - switch(value & 0x6000) - { - case 0x0000: psxCounters[5].rate = 1; break; - case 0x2000: psxCounters[5].rate = 8; break; - case 0x4000: psxCounters[5].rate = 16; break; - case 0x6000: psxCounters[5].rate = 256; break; - } - // Need to set a rate and target - if((psxCounters[5].mode & 0x7) == 0x7 || (psxCounters[5].mode & 0x7) == 0x1) - { - SysPrintf("Gate set on IOP C5, disabling\n"); - psxCounters[5].mode |= IOPCNT_STOPPED; - } - - psxCounters[5].count = 0; - psxCounters[5].sCycleT = psxRegs.cycle; - psxCounters[5].target &= 0xffffffff; - _rcntSet( 5 ); -} - -void psxRcntWtarget16(int index, u32 value) -{ - assert( index < 3 ); - PSXCNT_LOG("IOP Counter[%d] writeTarget16 = %lx\n", index, value); - psxCounters[index].target = value & 0xffff; - - // protect the target from an early arrival. - // if the target is behind the current count, then set the target overflow - // flag, so that the target won't be active until after the next overflow. - - if(psxCounters[index].target <= psxRcntCycles(index)) - psxCounters[index].target |= IOPCNT_FUTURE_TARGET; - - _rcntSet( index ); -} - -void psxRcntWtarget32(int index, u32 value) -{ - assert( index >= 3 && index < 6); - PSXCNT_LOG("IOP Counter[%d] writeTarget32 = %lx\n", index, value); - - psxCounters[index].target = value; - - // protect the target from an early arrival. - // if the target is behind the current count, then set the target overflow - // flag, so that the target won't be active until after the next overflow. - - if(psxCounters[index].target <= psxRcntCycles(index)) - psxCounters[index].target |= IOPCNT_FUTURE_TARGET; - - _rcntSet( index ); -} - -u16 psxRcntRcount16(int index) -{ - u32 retval = (u32)psxCounters[index].count; - - assert( index < 3 ); - - PSXCNT_LOG("IOP Counter[%d] readCount16 = %lx\n", index, (u16)retval ); - - // Don't count HBLANK timers - // Don't count stopped gates either. - - if( !( psxCounters[index].mode & IOPCNT_STOPPED ) && - ( psxCounters[index].rate != PSXHBLANK ) ) - { - u32 delta = (u32)((psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate); - retval += delta; - PSXCNT_LOG(" (delta = %lx)\n", delta ); - } - - return (u16)retval; -} - -u32 psxRcntRcount32(int index) -{ - u32 retval = (u32)psxCounters[index].count; - - assert( index >= 3 && index < 6 ); - - PSXCNT_LOG("IOP Counter[%d] readCount32 = %lx\n", index, retval ); - - if( !( psxCounters[index].mode & IOPCNT_STOPPED ) && - ( psxCounters[index].rate != PSXHBLANK ) ) - { - u32 delta = (u32)((psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate); - retval += delta; - PSXCNT_LOG(" (delta = %lx)\n", delta ); - } - - return retval; -} - -u64 psxRcntCycles(int index) -{ - if(psxCounters[index].mode & IOPCNT_STOPPED || psxCounters[index].rate == PSXHBLANK ) return psxCounters[index].count; - return (u64)(psxCounters[index].count + (u32)((psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate)); -} - -void psxRcntSetGates() -{ - if(psxCounters[0].mode & IOPCNT_ENABLE_GATE) - psxhblankgate |= 1; - else - psxhblankgate &= ~1; - - if(psxCounters[1].mode & IOPCNT_ENABLE_GATE) - psxvblankgate |= 1<<1; - else - psxvblankgate &= ~(1<<1); - - if(psxCounters[3].mode & IOPCNT_ENABLE_GATE) - psxvblankgate |= 1<<3; - else - psxvblankgate &= ~(1<<3); -} - -void SaveState::psxRcntFreeze() -{ - Freeze(psxCounters); - Freeze(psxNextCounter); - Freeze(psxNextsCounter); - - if( IsLoading() ) - psxRcntSetGates(); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +// Note on INTC usage: All counters code is always called from inside the context of an +// event test, so instead of using the iopTestIntc we just set the 0x1070 flags directly. +// The EventText function will pick it up. + +#include "PrecompiledHeader.h" + +#include +#include "PsxCommon.h" + +psxCounter psxCounters[8]; +s32 psxNextCounter; +u32 psxNextsCounter; +u8 psxhblankgate = 0; +u8 psxvblankgate = 0; + +// flags when the gate is off or counter disabled. (do not count) +#define IOPCNT_STOPPED (0x10000000ul) + +// used to disable targets until after an overflow +#define IOPCNT_FUTURE_TARGET (0x1000000000ULL) + +#define IOPCNT_ENABLE_GATE (1<<0) // enables gate-based counters +#define IOPCNT_INT_TARGET (1<<4) // 0x10 triggers an interrupt on targets +#define IOPCNT_INT_OVERFLOW (1<<5) // 0x20 triggers an interrupt on overflows +#define IOPCNT_ALT_SOURCE (1<<8) // 0x100 uses hblank on counters 1 and 3, and PSXCLOCK on counter 0 + +// Use an arbitrary value to flag HBLANK counters. +// These counters will be counted by the hblank gates coming from the EE, +// which ensures they stay 100% in sync with the EE's hblank counters. +#define PSXHBLANK 0x2001 + +static void psxRcntReset(int index) +{ + psxCounters[index].count = 0; + psxCounters[index].mode&= ~0x18301C00; + psxCounters[index].sCycleT = psxRegs.cycle; +} + +static void _rcntSet( int cntidx ) +{ + u64 overflowCap = (cntidx>=3) ? 0x100000000ULL : 0x10000; + u64 c; + + const psxCounter& counter = psxCounters[cntidx]; + + // psxNextCounter is relative to the psxRegs.cycle when rcntUpdate() was last called. + // However, the current _rcntSet could be called at any cycle count, so we need to take + // that into account. Adding the difference from that cycle count to the current one + // will do the trick! + + if( counter.mode & IOPCNT_STOPPED || counter.rate == PSXHBLANK) return; + + // check for special cases where the overflow or target has just passed + // (we probably missed it because we're doing/checking other things) + if( counter.count > overflowCap || counter.count > counter.target ) + { + psxNextCounter = 4; + return; + } + + c = (u64)((overflowCap - counter.count) * counter.rate) - (psxRegs.cycle - counter.sCycleT); + c += psxRegs.cycle - psxNextsCounter; // adjust for time passed since last rcntUpdate(); + if(c < (u64)psxNextCounter) psxNextCounter = (u32)c; + + //if((counter.mode & 0x10) == 0 || psxCounters[i].target > 0xffff) continue; + if( counter.target & IOPCNT_FUTURE_TARGET ) return; + + c = (s64)((counter.target - counter.count) * counter.rate) - (psxRegs.cycle - counter.sCycleT); + c += psxRegs.cycle - psxNextsCounter; // adjust for time passed since last rcntUpdate(); + if(c < (u64)psxNextCounter) psxNextCounter = (u32)c; +} + + +void psxRcntInit() { + int i; + + memzero_obj( psxCounters ); + + for (i=0; i<3; i++) { + psxCounters[i].rate = 1; + psxCounters[i].mode|= 0x0400; + psxCounters[i].target = IOPCNT_FUTURE_TARGET; + } + for (i=3; i<6; i++) { + psxCounters[i].rate = 1; + psxCounters[i].mode|= 0x0400; + psxCounters[i].target = IOPCNT_FUTURE_TARGET; + } + + psxCounters[0].interrupt = 0x10; + psxCounters[1].interrupt = 0x20; + psxCounters[2].interrupt = 0x40; + + psxCounters[3].interrupt = 0x04000; + psxCounters[4].interrupt = 0x08000; + psxCounters[5].interrupt = 0x10000; + + if (SPU2async != NULL) + { + psxCounters[6].rate = 768*12; + psxCounters[6].CycleT = psxCounters[6].rate; + psxCounters[6].mode = 0x8; + } + + if (USBasync != NULL) + { + psxCounters[7].rate = PSXCLK/1000; + psxCounters[7].CycleT = psxCounters[7].rate; + psxCounters[7].mode = 0x8; + } + + for (i=0; i<8; i++) + psxCounters[i].sCycleT = psxRegs.cycle; + + // Tell the IOP to branch ASAP, so that timers can get + // configured properly. + psxNextCounter = 1; + psxNextsCounter = psxRegs.cycle; +} + +static void __fastcall _rcntTestTarget( int i ) +{ + if( psxCounters[i].count < psxCounters[i].target ) return; + + PSXCNT_LOG("IOP Counter[%d] target 0x%I64x >= 0x%I64x (mode: %x)\n", + i, psxCounters[i].count, psxCounters[i].target, psxCounters[i].mode); + + if (psxCounters[i].mode & IOPCNT_INT_TARGET) + { + // Target interrupt + + if(psxCounters[i].mode & 0x80) + psxCounters[i].mode &= ~0x0400; // Interrupt flag + psxCounters[i].mode |= 0x0800; // Target flag + + psxHu32(0x1070) |= psxCounters[i].interrupt; + } + + if (psxCounters[i].mode & 0x08) + { + // Reset on target + psxCounters[i].count -= psxCounters[i].target; + if(!(psxCounters[i].mode & 0x40)) + { + SysPrintf("Counter %x repeat intr not set on zero ret, ignoring target\n", i); + psxCounters[i].target |= IOPCNT_FUTURE_TARGET; + } + } else psxCounters[i].target |= IOPCNT_FUTURE_TARGET; +} + + +static __forceinline void _rcntTestOverflow( int i ) +{ + u64 maxTarget = ( i < 3 ) ? 0xffff : 0xfffffffful; + if( psxCounters[i].count <= maxTarget ) return; + + PSXCNT_LOG("IOP Counter[%d] overflow 0x%I64x >= 0x%I64x (mode: %x)\n", + i, psxCounters[i].count, maxTarget, psxCounters[i].mode ); + + if(psxCounters[i].mode & IOPCNT_INT_OVERFLOW) + { + // Overflow interrupt + psxHu32(0x1070) |= psxCounters[i].interrupt; + psxCounters[i].mode |= 0x1000; // Overflow flag + if(psxCounters[i].mode & 0x80) + psxCounters[i].mode &= ~0x0400; // Interrupt flag + } + + // Update count and target. + // Count wraps around back to zero, while the target is restored (if needed). + // (high bit of the target gets set by rcntWtarget when the target is behind + // the counter value, and thus should not be flagged until after an overflow) + + psxCounters[i].count &= maxTarget; + psxCounters[i].target &= maxTarget; +} + +/* +Gate: + TM_NO_GATE 000 + TM_GATE_ON_Count 001 + TM_GATE_ON_ClearStart 011 + TM_GATE_ON_Clear_OFF_Start 101 + TM_GATE_ON_Start 111 + + V-blank ----+ +----------------------------+ +------ + | | | | + | | | | + +----+ +----+ + TM_NO_GATE: + + 0================================>============ + + TM_GATE_ON_Count: + + <---->0==========================><---->0===== + + TM_GATE_ON_ClearStart: + + 0====>0================================>0===== + + TM_GATE_ON_Clear_OFF_Start: + + 0====><-------------------------->0====><----- + + TM_GATE_ON_Start: + + <---->0==========================>============ +*/ + +static void _psxCheckStartGate( int i ) +{ + if(!(psxCounters[i].mode & IOPCNT_ENABLE_GATE)) return; //Ignore Gate + + switch((psxCounters[i].mode & 0x6) >> 1) + { + case 0x0: //GATE_ON_count - stop count on gate start: + + // get the current count at the time of stoppage: + psxCounters[i].count = ( i < 3 ) ? + psxRcntRcount16( i ) : psxRcntRcount32( i ); + psxCounters[i].mode |= IOPCNT_STOPPED; + return; + + case 0x1: //GATE_ON_ClearStart - count normally with resets after every end gate + // do nothing - All counting will be done on a need-to-count basis. + return; + + case 0x2: //GATE_ON_Clear_OFF_Start - start counting on gate start, stop on gate end + psxCounters[i].count = 0; + psxCounters[i].sCycleT = psxRegs.cycle; + psxCounters[i].mode &= ~IOPCNT_STOPPED; + break; + + case 0x3: //GATE_ON_Start - start and count normally on gate end (no restarts or stops or clears) + // do nothing! + return; + } + _rcntSet( i ); +} + +static void _psxCheckEndGate(int i) +{ + if(!(psxCounters[i].mode & IOPCNT_ENABLE_GATE)) return; //Ignore Gate + + switch((psxCounters[i].mode & 0x6) >> 1) + { + case 0x0: //GATE_ON_count - reset and start counting + case 0x1: //GATE_ON_ClearStart - count normally with resets after every end gate + psxCounters[i].count = 0; + psxCounters[i].sCycleT = psxRegs.cycle; + psxCounters[i].mode &= ~IOPCNT_STOPPED; + break; + + case 0x2: //GATE_ON_Clear_OFF_Start - start counting on gate start, stop on gate end + psxCounters[i].count = ( i < 3 ) ? + psxRcntRcount16( i ) : psxRcntRcount32( i ); + psxCounters[i].mode |= IOPCNT_STOPPED; + return; // do not set the counter + + case 0x3: //GATE_ON_Start - start and count normally (no restarts or stops or clears) + if( psxCounters[i].mode & IOPCNT_STOPPED ) + { + psxCounters[i].count = 0; + psxCounters[i].sCycleT = psxRegs.cycle; + psxCounters[i].mode &= ~IOPCNT_STOPPED; + } + break; + } + _rcntSet( i ); +} + +void psxCheckStartGate16(int i) +{ + assert( i < 3 ); + + if(i == 0) // hSync counting... + { + // AlternateSource/scanline counters for Gates 1 and 3. + // We count them here so that they stay nicely synced with the EE's hsync. + + const u32 altSourceCheck = IOPCNT_ALT_SOURCE | IOPCNT_ENABLE_GATE; + const u32 stoppedGateCheck = (IOPCNT_STOPPED | altSourceCheck ); + + // count if alt source is enabled and either: + // * the gate is enabled and not stopped. + // * the gate is disabled. + + if( (psxCounters[1].mode & altSourceCheck) == IOPCNT_ALT_SOURCE || + (psxCounters[1].mode & stoppedGateCheck ) == altSourceCheck ) + { + psxCounters[1].count++; + _rcntTestTarget( 1 ); + _rcntTestOverflow( 1 ); + } + + if( (psxCounters[3].mode & altSourceCheck) == IOPCNT_ALT_SOURCE || + (psxCounters[3].mode & stoppedGateCheck ) == altSourceCheck ) + { + psxCounters[3].count++; + _rcntTestTarget( 3 ); + _rcntTestOverflow( 3 ); + } + } + + _psxCheckStartGate( i ); +} + +void psxCheckEndGate16(int i) +{ + assert(i < 3); + _psxCheckEndGate( i ); +} + +static void psxCheckStartGate32(int i) +{ + // 32 bit gate is called for gate 3 only. Ever. + assert(i == 3); + _psxCheckStartGate( i ); +} + +static void psxCheckEndGate32(int i) +{ + assert(i == 3); + _psxCheckEndGate( i ); +} + + +void psxVBlankStart() +{ + cdvdVsync(); + psxHu32(0x1070) |= 1; + if(psxvblankgate & (1 << 1)) psxCheckStartGate16(1); + if(psxvblankgate & (1 << 3)) psxCheckStartGate32(3); +} + +void psxVBlankEnd() +{ + psxHu32(0x1070) |= 0x800; + if(psxvblankgate & (1 << 1)) psxCheckEndGate16(1); + if(psxvblankgate & (1 << 3)) psxCheckEndGate32(3); +} + +void psxRcntUpdate() +{ + int i; + //u32 change = 0; + + for (i=0; i<=5; i++) + { + s32 change = psxRegs.cycle - psxCounters[i].sCycleT; + + // don't count disabled, gated, or hblank counters... + // We can't check the ALTSOURCE flag because the PSXCLOCK source *should* + // be counted here. + + if( psxCounters[i].mode & (IOPCNT_STOPPED | IOPCNT_ENABLE_GATE) ) continue; + if( psxCounters[i].rate == PSXHBLANK ) continue; + if( change <= 0 ) continue; + + psxCounters[i].count += change / psxCounters[i].rate; + if(psxCounters[i].rate != 1) + { + change -= (change / psxCounters[i].rate) * psxCounters[i].rate; + psxCounters[i].sCycleT = psxRegs.cycle - change; + } + else + psxCounters[i].sCycleT = psxRegs.cycle; + } + + // Do target/overflow testing + // Optimization Note: This approach is very sound. Please do not try to unroll it + // as the size of the Test functions will cause code cache clutter and slowness. + + for( i=0; i<6; i++ ) + { + // don't do target/oveflow checks for hblankers. Those + // checks are done when the counters are updated. + if( psxCounters[i].rate == PSXHBLANK ) continue; + if( psxCounters[i].mode & IOPCNT_STOPPED ) continue; + + _rcntTestTarget( i ); + _rcntTestOverflow( i ); + + // perform second target test because if we overflowed above it's possible we + // already shot past our target if it was very near zero. + + //if( psxCounters[i].count >= psxCounters[i].target ) _rcntTestTarget( i ); + } + + psxNextCounter = 0xffffff; + psxNextsCounter = psxRegs.cycle; + + if(SPU2async) + { + const s32 difference = psxRegs.cycle - psxCounters[6].sCycleT; + s32 c = psxCounters[6].CycleT; + + if(difference >= psxCounters[6].CycleT) + { + SPU2async(difference); + psxCounters[6].sCycleT = psxRegs.cycle; + psxCounters[6].CycleT = psxCounters[6].rate; + } + else c -= difference; + psxNextCounter = c; + } + + if(USBasync) + { + const s32 difference = psxRegs.cycle - psxCounters[7].sCycleT; + s32 c = psxCounters[7].CycleT; + + if(difference >= psxCounters[7].CycleT) + { + USBasync(difference); + psxCounters[7].sCycleT = psxRegs.cycle; + psxCounters[7].CycleT = psxCounters[7].rate; + } + else c -= difference; + if (c < psxNextCounter) psxNextCounter = c; + } + + for (i=0; i<6; i++) _rcntSet( i ); +} + +void psxRcntWcount16(int index, u32 value) +{ + u32 change; + + assert( index < 3 ); + PSXCNT_LOG("IOP Counter[%d] writeCount16 = %x\n", index, value); + + if(psxCounters[index].rate != PSXHBLANK) + { + // Re-adjust the sCycleT to match where the counter is currently + // (remainder of the rate divided into the time passed will do the trick) + + change = psxRegs.cycle - psxCounters[index].sCycleT; + psxCounters[index].sCycleT = psxRegs.cycle - (change % psxCounters[index].rate); + } + + psxCounters[index].count = value & 0xffff; + psxCounters[index].target &= 0xffff; + _rcntSet( index ); +} + +void psxRcntWcount32(int index, u32 value) +{ + u32 change; + + assert( index >= 3 && index < 6 ); + PSXCNT_LOG("IOP Counter[%d] writeCount32 = %x\n", index, value); + + if(psxCounters[index].rate != PSXHBLANK) + { + // Re-adjust the sCycleT to match where the counter is currently + // (remainder of the rate divided into the time passed will do the trick) + + change = psxRegs.cycle - psxCounters[index].sCycleT; + psxCounters[index].sCycleT = psxRegs.cycle - (change % psxCounters[index].rate); + } + + psxCounters[index].count = value & 0xffffffff; + psxCounters[index].target &= 0xffffffff; + _rcntSet( index ); +} + +void psxRcnt0Wmode(u32 value) +{ + PSXCNT_LOG("IOP Counter[0] writeMode = %lx\n", value); + + psxCounters[0].mode = value; + psxCounters[0].mode|= 0x0400; + psxCounters[0].rate = 1; + + if(value & IOPCNT_ALT_SOURCE) + psxCounters[0].rate = PSXPIXEL; + + if(psxCounters[0].mode & IOPCNT_ENABLE_GATE) + { + // gated counters are added up as per the h/vblank timers. + PSXCNT_LOG("IOP Counter[0] Gate Check set, value = %x\n", value); + psxhblankgate |= 1; + } + else psxhblankgate &= ~1; + + psxCounters[0].count = 0; + psxCounters[0].sCycleT = psxRegs.cycle; + psxCounters[0].target &= 0xffff; + + _rcntSet( 0 ); +} + +void psxRcnt1Wmode(u32 value) +{ + PSXCNT_LOG("IOP Counter[0] writeMode = %lx\n", value); + + psxCounters[1].mode = value; + psxCounters[1].mode|= 0x0400; + psxCounters[1].rate = 1; + + if(value & IOPCNT_ALT_SOURCE) + psxCounters[1].rate = PSXHBLANK; + + if(psxCounters[1].mode & IOPCNT_ENABLE_GATE) + { + PSXCNT_LOG("IOP Counter[1] Gate Check set, value = %x\n", value); + psxvblankgate |= 1<<1; + } + else psxvblankgate &= ~(1<<1); + + psxCounters[1].count = 0; + psxCounters[1].sCycleT = psxRegs.cycle; + psxCounters[1].target &= 0xffff; + _rcntSet( 1 ); +} + +void psxRcnt2Wmode(u32 value) +{ + PSXCNT_LOG("IOP Counter[0] writeMode = %lx\n", value); + + psxCounters[2].mode = value; + psxCounters[2].mode|= 0x0400; + + switch(value & 0x200) + { + case 0x200: psxCounters[2].rate = 8; break; + case 0x000: psxCounters[2].rate = 1; break; + } + + if((psxCounters[2].mode & 0x7) == 0x7 || (psxCounters[2].mode & 0x7) == 0x1) + { + //SysPrintf("Gate set on IOP C2, disabling\n"); + psxCounters[2].mode |= IOPCNT_STOPPED; + } + + psxCounters[2].count = 0; + psxCounters[2].sCycleT = psxRegs.cycle; + psxCounters[2].target &= 0xffff; + _rcntSet( 2 ); +} + +void psxRcnt3Wmode(u32 value) +{ + PSXCNT_LOG("IOP Counter[3] writeMode = %lx\n", value); + + psxCounters[3].mode = value; + psxCounters[3].rate = 1; + psxCounters[3].mode|= 0x0400; + + if(value & IOPCNT_ALT_SOURCE) + psxCounters[3].rate = PSXHBLANK; + + if(psxCounters[3].mode & IOPCNT_ENABLE_GATE) + { + PSXCNT_LOG("IOP Counter[3] Gate Check set, value = %x\n", value); + psxvblankgate |= 1<<3; + } + else psxvblankgate &= ~(1<<3); + + psxCounters[3].count = 0; + psxCounters[3].sCycleT = psxRegs.cycle; + psxCounters[3].target &= 0xffffffff; + _rcntSet( 3 ); +} + +void psxRcnt4Wmode(u32 value) +{ + PSXCNT_LOG("IOP Counter[4] writeMode = %lx\n", value); + + psxCounters[4].mode = value; + psxCounters[4].mode|= 0x0400; + + switch(value & 0x6000) + { + case 0x0000: psxCounters[4].rate = 1; break; + case 0x2000: psxCounters[4].rate = 8; break; + case 0x4000: psxCounters[4].rate = 16; break; + case 0x6000: psxCounters[4].rate = 256; break; + } + // Need to set a rate and target + if((psxCounters[4].mode & 0x7) == 0x7 || (psxCounters[4].mode & 0x7) == 0x1) + { + SysPrintf("Gate set on IOP C4, disabling\n"); + psxCounters[4].mode |= IOPCNT_STOPPED; + } + + psxCounters[4].count = 0; + psxCounters[4].sCycleT = psxRegs.cycle; + psxCounters[4].target &= 0xffffffff; + _rcntSet( 4 ); +} + +void psxRcnt5Wmode(u32 value) +{ + PSXCNT_LOG("IOP Counter[5] writeMode = %lx\n", value); + + psxCounters[5].mode = value; + psxCounters[5].mode|= 0x0400; + + switch(value & 0x6000) + { + case 0x0000: psxCounters[5].rate = 1; break; + case 0x2000: psxCounters[5].rate = 8; break; + case 0x4000: psxCounters[5].rate = 16; break; + case 0x6000: psxCounters[5].rate = 256; break; + } + // Need to set a rate and target + if((psxCounters[5].mode & 0x7) == 0x7 || (psxCounters[5].mode & 0x7) == 0x1) + { + SysPrintf("Gate set on IOP C5, disabling\n"); + psxCounters[5].mode |= IOPCNT_STOPPED; + } + + psxCounters[5].count = 0; + psxCounters[5].sCycleT = psxRegs.cycle; + psxCounters[5].target &= 0xffffffff; + _rcntSet( 5 ); +} + +void psxRcntWtarget16(int index, u32 value) +{ + assert( index < 3 ); + PSXCNT_LOG("IOP Counter[%d] writeTarget16 = %lx\n", index, value); + psxCounters[index].target = value & 0xffff; + + // protect the target from an early arrival. + // if the target is behind the current count, then set the target overflow + // flag, so that the target won't be active until after the next overflow. + + if(psxCounters[index].target <= psxRcntCycles(index)) + psxCounters[index].target |= IOPCNT_FUTURE_TARGET; + + _rcntSet( index ); +} + +void psxRcntWtarget32(int index, u32 value) +{ + assert( index >= 3 && index < 6); + PSXCNT_LOG("IOP Counter[%d] writeTarget32 = %lx\n", index, value); + + psxCounters[index].target = value; + + // protect the target from an early arrival. + // if the target is behind the current count, then set the target overflow + // flag, so that the target won't be active until after the next overflow. + + if(psxCounters[index].target <= psxRcntCycles(index)) + psxCounters[index].target |= IOPCNT_FUTURE_TARGET; + + _rcntSet( index ); +} + +u16 psxRcntRcount16(int index) +{ + u32 retval = (u32)psxCounters[index].count; + + assert( index < 3 ); + + PSXCNT_LOG("IOP Counter[%d] readCount16 = %lx\n", index, (u16)retval ); + + // Don't count HBLANK timers + // Don't count stopped gates either. + + if( !( psxCounters[index].mode & IOPCNT_STOPPED ) && + ( psxCounters[index].rate != PSXHBLANK ) ) + { + u32 delta = (u32)((psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate); + retval += delta; + PSXCNT_LOG(" (delta = %lx)\n", delta ); + } + + return (u16)retval; +} + +u32 psxRcntRcount32(int index) +{ + u32 retval = (u32)psxCounters[index].count; + + assert( index >= 3 && index < 6 ); + + PSXCNT_LOG("IOP Counter[%d] readCount32 = %lx\n", index, retval ); + + if( !( psxCounters[index].mode & IOPCNT_STOPPED ) && + ( psxCounters[index].rate != PSXHBLANK ) ) + { + u32 delta = (u32)((psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate); + retval += delta; + PSXCNT_LOG(" (delta = %lx)\n", delta ); + } + + return retval; +} + +u64 psxRcntCycles(int index) +{ + if(psxCounters[index].mode & IOPCNT_STOPPED || psxCounters[index].rate == PSXHBLANK ) return psxCounters[index].count; + return (u64)(psxCounters[index].count + (u32)((psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate)); +} + +void psxRcntSetGates() +{ + if(psxCounters[0].mode & IOPCNT_ENABLE_GATE) + psxhblankgate |= 1; + else + psxhblankgate &= ~1; + + if(psxCounters[1].mode & IOPCNT_ENABLE_GATE) + psxvblankgate |= 1<<1; + else + psxvblankgate &= ~(1<<1); + + if(psxCounters[3].mode & IOPCNT_ENABLE_GATE) + psxvblankgate |= 1<<3; + else + psxvblankgate &= ~(1<<3); +} + +void SaveState::psxRcntFreeze() +{ + Freeze(psxCounters); + Freeze(psxNextCounter); + Freeze(psxNextsCounter); + + if( IsLoading() ) + psxRcntSetGates(); +} diff --git a/pcsx2/IopCounters.h b/pcsx2/IopCounters.h index a8ce59d3f5..4dc4540958 100644 --- a/pcsx2/IopCounters.h +++ b/pcsx2/IopCounters.h @@ -1,62 +1,62 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __PSXCOUNTERS_H__ -#define __PSXCOUNTERS_H__ - -// fixme: sCycle, Cycle, and otarget are unused -// Can't remove them without making a new savestate version though. - -struct psxCounter { - u64 count, target; - u32 mode; - u32 rate, interrupt, otarget; - u32 sCycle, Cycle; - u32 sCycleT; - s32 CycleT; -}; - -extern psxCounter psxCounters[8]; -extern s32 psxNextCounter; -extern u32 psxNextsCounter; - -void psxRcntInit(); -void psxRcntUpdate(); -void cntspu2async(); -void psxRcntWcount16(int index, u32 value); -void psxRcntWcount32(int index, u32 value); -void psxRcnt0Wmode(u32 value); -void psxRcnt1Wmode(u32 value); -void psxRcnt2Wmode(u32 value); -void psxRcnt3Wmode(u32 value); -void psxRcnt4Wmode(u32 value); -void psxRcnt5Wmode(u32 value); -void psxRcntWtarget16(int index, u32 value); -void psxRcntWtarget32(int index, u32 value); -u16 psxRcntRcount16(int index); -u32 psxRcntRcount32(int index); -u64 psxRcntCycles(int index); - -void psxVBlankStart(); -void psxVBlankEnd(); -void psxCheckStartGate16(int i); -void psxCheckEndGate16(int i); -//static void psxCheckStartGate32(int i); -//static void psxCheckEndGate32(int i); - -#endif /* __PSXCOUNTERS_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __PSXCOUNTERS_H__ +#define __PSXCOUNTERS_H__ + +// fixme: sCycle, Cycle, and otarget are unused +// Can't remove them without making a new savestate version though. + +struct psxCounter { + u64 count, target; + u32 mode; + u32 rate, interrupt, otarget; + u32 sCycle, Cycle; + u32 sCycleT; + s32 CycleT; +}; + +extern psxCounter psxCounters[8]; +extern s32 psxNextCounter; +extern u32 psxNextsCounter; + +void psxRcntInit(); +void psxRcntUpdate(); +void cntspu2async(); +void psxRcntWcount16(int index, u32 value); +void psxRcntWcount32(int index, u32 value); +void psxRcnt0Wmode(u32 value); +void psxRcnt1Wmode(u32 value); +void psxRcnt2Wmode(u32 value); +void psxRcnt3Wmode(u32 value); +void psxRcnt4Wmode(u32 value); +void psxRcnt5Wmode(u32 value); +void psxRcntWtarget16(int index, u32 value); +void psxRcntWtarget32(int index, u32 value); +u16 psxRcntRcount16(int index); +u32 psxRcntRcount32(int index); +u64 psxRcntCycles(int index); + +void psxVBlankStart(); +void psxVBlankEnd(); +void psxCheckStartGate16(int i); +void psxCheckEndGate16(int i); +//static void psxCheckStartGate32(int i); +//static void psxCheckEndGate32(int i); + +#endif /* __PSXCOUNTERS_H__ */ diff --git a/pcsx2/IopDma.cpp b/pcsx2/IopDma.cpp index d6eb47c079..895f3514da 100644 --- a/pcsx2/IopDma.cpp +++ b/pcsx2/IopDma.cpp @@ -1,382 +1,382 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "PsxCommon.h" - -using namespace R3000A; - -// Dma0/1 in Mdec.c -// Dma3 in CdRom.c -// Dma8 in PsxSpd.c -// Dma11/12 in PsxSio2.c - -int iopsifbusy[2] = { 0, 0 }; - -static void __fastcall psxDmaGeneric(u32 madr, u32 bcr, u32 chcr, u32 spuCore, _SPU2writeDMA4Mem spu2WriteFunc, _SPU2readDMA4Mem spu2ReadFunc ) -{ - const char dmaNum = spuCore ? '7' : '4'; - /*if (chcr & 0x400) DevCon::Status("SPU 2 DMA %c linked list chain mode! chcr = %x madr = %x bcr = %x\n", dmaNum, chcr, madr, bcr); - if (chcr & 0x40000000) DevCon::Notice("SPU 2 DMA %c Unusual bit set on 'to' direction chcr = %x madr = %x bcr = %x\n", dmaNum, chcr, madr, bcr); - if ((chcr & 0x1) == 0) DevCon::Status("SPU 2 DMA %c loading from spu2 memory chcr = %x madr = %x bcr = %x\n", dmaNum, chcr, madr, bcr);*/ - - const int size = (bcr >> 16) * (bcr & 0xFFFF); - - // Update the spu2 to the current cycle before initiating the DMA - - if(SPU2async) - { - SPU2async(psxRegs.cycle - psxCounters[6].sCycleT); - //Console::Status("cycles sent to SPU2 %x\n", psxRegs.cycle - psxCounters[6].sCycleT); - - psxCounters[6].sCycleT = psxRegs.cycle; - psxCounters[6].CycleT = size * 3; - - psxNextCounter -= (psxRegs.cycle-psxNextsCounter); - psxNextsCounter = psxRegs.cycle; - if(psxCounters[6].CycleT < psxNextCounter) - psxNextCounter = psxCounters[6].CycleT; - } - - switch (chcr) - { - case 0x01000201: //cpu to spu2 transfer - PSXDMA_LOG("*** DMA %c - mem2spu *** %lx addr = %lx size = %lx\n", dmaNum, chcr, madr, bcr); - spu2WriteFunc((u16 *)PSXM(madr), size*2); - break; - - case 0x01000200: //spu2 to cpu transfer - PSXDMA_LOG("*** DMA %c - spu2mem *** %lx addr = %lx size = %lx\n", dmaNum, chcr, madr, bcr); - spu2ReadFunc((u16 *)PSXM(madr), size*2); - psxCpu->Clear(spuCore ? HW_DMA7_MADR : HW_DMA4_MADR, size); - break; - - default: - Console::Error("*** DMA %c - SPU unknown *** %lx addr = %lx size = %lx\n", params dmaNum, chcr, madr, bcr); - break; - } -} - -void psxDma4(u32 madr, u32 bcr, u32 chcr) // SPU2's Core 0 -{ - psxDmaGeneric( madr, bcr, chcr, 0, SPU2writeDMA4Mem, SPU2readDMA4Mem ); -} - -int psxDma4Interrupt() -{ - HW_DMA4_CHCR &= ~0x01000000; - psxDmaInterrupt(4); - iopIntcIrq( 9 ); - return 1; -} - -void psxDma2(u32 madr, u32 bcr, u32 chcr) // GPU -{ - HW_DMA2_CHCR &= ~0x01000000; - psxDmaInterrupt(2); -} - -void psxDma6(u32 madr, u32 bcr, u32 chcr) -{ - u32 *mem = (u32 *)PSXM(madr); - - PSXDMA_LOG("*** DMA 6 - OT *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); - - if (chcr == 0x11000002) { - while (bcr--) { - *mem-- = (madr - 4) & 0xffffff; - madr -= 4; - } - mem++; *mem = 0xffffff; - } else { - // Unknown option - PSXDMA_LOG("*** DMA 6 - OT unknown *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); - } - HW_DMA6_CHCR &= ~0x01000000; - psxDmaInterrupt(6); -} - -void psxDma7(u32 madr, u32 bcr, u32 chcr) // SPU2's Core 1 -{ - psxDmaGeneric( madr, bcr, chcr, 1, SPU2writeDMA7Mem, SPU2readDMA7Mem ); -} - -int psxDma7Interrupt() -{ - HW_DMA7_CHCR &= ~0x01000000; - psxDmaInterrupt2(0); - //iopIntcIrq( 9 ); - return 1; - -} -extern int eesifbusy[2]; -void psxDma9(u32 madr, u32 bcr, u32 chcr) -{ - SIF_LOG("IOP: dmaSIF0 chcr = %lx, madr = %lx, bcr = %lx, tadr = %lx\n", chcr, madr, bcr, HW_DMA9_TADR); - - iopsifbusy[0] = 1; - psHu32(0x1000F240) |= 0x2000; - - if (eesifbusy[0] == 1) { - SIF0Dma(); - psHu32(0x1000F240) &= ~0x20; - psHu32(0x1000F240) &= ~0x2000; - } -} - -void psxDma10(u32 madr, u32 bcr, u32 chcr) { - SIF_LOG("IOP: dmaSIF1 chcr = %lx, madr = %lx, bcr = %lx\n", chcr, madr, bcr); - - iopsifbusy[1] = 1; - psHu32(0x1000F240) |= 0x4000; - - if (eesifbusy[1] == 1) { - FreezeXMMRegs(1); - SIF1Dma(); - psHu32(0x1000F240) &= ~0x40; - psHu32(0x1000F240) &= ~0x100; - psHu32(0x1000F240) &= ~0x4000; - FreezeXMMRegs(0); - } -} - -void psxDma8(u32 madr, u32 bcr, u32 chcr) { - - const int size = (bcr >> 16) * (bcr & 0xFFFF) * 8; - - switch (chcr & 0x01000201) { - case 0x01000201: //cpu to dev9 transfer - PSXDMA_LOG("*** DMA 8 - DEV9 mem2dev9 *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); - DEV9writeDMA8Mem((u32*)PSXM(madr), size); - break; - - case 0x01000200: //dev9 to cpu transfer - PSXDMA_LOG("*** DMA 8 - DEV9 dev9mem *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); - DEV9readDMA8Mem((u32*)PSXM(madr), size); - break; - - default: - PSXDMA_LOG("*** DMA 8 - DEV9 unknown *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); - break; - } - HW_DMA8_CHCR &= ~0x01000000; - psxDmaInterrupt2(1); -} - -void dev9Interrupt() { - if( (dev9Handler != NULL) && (dev9Handler() != 1) ) - return; - - iopIntcIrq( 13 ); - hwIntcIrq(INTC_SBUS); -} - -void dev9Irq(int cycles) { - PSX_INT(IopEvt_DEV9, cycles); -} - -void usbInterrupt() { - if( usbHandler != NULL && (usbHandler() != 1) ) - return; - - iopIntcIrq( 22 ); - hwIntcIrq(INTC_SBUS); -} - -void usbIrq(int cycles) { - PSX_INT(IopEvt_USB, cycles); -} - -void fwIrq() { - iopIntcIrq( 24 ); - hwIntcIrq(INTC_SBUS); -} - -void spu2DMA4Irq() { - SPU2interruptDMA4(); - //HW_DMA4_BCR = 0; - HW_DMA4_CHCR &= ~0x01000000; - psxDmaInterrupt(4); -} - -void spu2DMA7Irq() { - SPU2interruptDMA7(); - //HW_DMA7_BCR = 0; - HW_DMA7_CHCR &= ~0x01000000; - psxDmaInterrupt2(0); -} - -void spu2Irq() { - iopIntcIrq( 9 ); - hwIntcIrq(INTC_SBUS); -} - -void iopIntcIrq( uint irqType ) -{ - psxHu32(0x1070)|= 1<> 16) * (bcr & 0xFFFF); - - IopChannels[channel].Control = chcr | DMA_CTRL_ACTIVE; - IopChannels[channel].MemAddr = madr; - IopChannels[channel].ByteCount = size; -} - -void IopDmaUpdate(u32 elapsed) -{ - u32 MinDelay = 0xFFFFFFFF; - - for(int i=0;iControl&DMA_CTRL_ACTIVE) - { - ch->Target-=elapsed; - if(ch->Target<=0) - { - if(ch->ByteCount<=0) - { - ch->Control &= ~DMA_CTRL_ACTIVE; - RaiseDmaIrq(i); - IopDmaHandlers[i].Interrupt(i); - } - else - { - // TODO: Make sure it's the right order - DmaHandler handler = (ch->Control&DMA_CTRL_DIRECTION)?IopDmaHandlers[i].Read:IopDmaHandlers[i].Write; - - u32 BCount = 0; - s32 Target = (handler)?handler(i,(u32*)PSXM(ch->MemAddr),ch->ByteCount,&BCount):0; - - ch->Target = 100; - if(Target<0) - { - // TODO: ... What to do if the plugin errors? :P - } - else if(BCount!=0) - { - ch->MemAddr += BCount; - ch->ByteCount -= BCount; - - ch->Target = BCount / ch->Width; - } - - if (Target!=0) ch->Target=Target; - } - } - } - } -} - -s32 errDmaRead (s32 channel, u32* data, u32 wordsLeft, u32* wordsProcessed) -{ - Console::Error("ERROR: Tried to read using DMA %d (%s). Ignoring.",0,channel,IopDmaNames[channel]); - - *wordsProcessed = wordsLeft; - return 0; -} - -s32 errDmaWrite (s32 channel, u32* data, u32 wordsLeft, u32* wordsProcessed) -{ - Console::Error("ERROR: Tried to write using DMA %d (%s). Ignoring.",0,channel,IopDmaNames[channel]); - - *wordsProcessed = wordsLeft; - return 0; -} - - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "PsxCommon.h" + +using namespace R3000A; + +// Dma0/1 in Mdec.c +// Dma3 in CdRom.c +// Dma8 in PsxSpd.c +// Dma11/12 in PsxSio2.c + +int iopsifbusy[2] = { 0, 0 }; + +static void __fastcall psxDmaGeneric(u32 madr, u32 bcr, u32 chcr, u32 spuCore, _SPU2writeDMA4Mem spu2WriteFunc, _SPU2readDMA4Mem spu2ReadFunc ) +{ + const char dmaNum = spuCore ? '7' : '4'; + /*if (chcr & 0x400) DevCon::Status("SPU 2 DMA %c linked list chain mode! chcr = %x madr = %x bcr = %x\n", dmaNum, chcr, madr, bcr); + if (chcr & 0x40000000) DevCon::Notice("SPU 2 DMA %c Unusual bit set on 'to' direction chcr = %x madr = %x bcr = %x\n", dmaNum, chcr, madr, bcr); + if ((chcr & 0x1) == 0) DevCon::Status("SPU 2 DMA %c loading from spu2 memory chcr = %x madr = %x bcr = %x\n", dmaNum, chcr, madr, bcr);*/ + + const int size = (bcr >> 16) * (bcr & 0xFFFF); + + // Update the spu2 to the current cycle before initiating the DMA + + if(SPU2async) + { + SPU2async(psxRegs.cycle - psxCounters[6].sCycleT); + //Console::Status("cycles sent to SPU2 %x\n", psxRegs.cycle - psxCounters[6].sCycleT); + + psxCounters[6].sCycleT = psxRegs.cycle; + psxCounters[6].CycleT = size * 3; + + psxNextCounter -= (psxRegs.cycle-psxNextsCounter); + psxNextsCounter = psxRegs.cycle; + if(psxCounters[6].CycleT < psxNextCounter) + psxNextCounter = psxCounters[6].CycleT; + } + + switch (chcr) + { + case 0x01000201: //cpu to spu2 transfer + PSXDMA_LOG("*** DMA %c - mem2spu *** %lx addr = %lx size = %lx\n", dmaNum, chcr, madr, bcr); + spu2WriteFunc((u16 *)PSXM(madr), size*2); + break; + + case 0x01000200: //spu2 to cpu transfer + PSXDMA_LOG("*** DMA %c - spu2mem *** %lx addr = %lx size = %lx\n", dmaNum, chcr, madr, bcr); + spu2ReadFunc((u16 *)PSXM(madr), size*2); + psxCpu->Clear(spuCore ? HW_DMA7_MADR : HW_DMA4_MADR, size); + break; + + default: + Console::Error("*** DMA %c - SPU unknown *** %lx addr = %lx size = %lx\n", params dmaNum, chcr, madr, bcr); + break; + } +} + +void psxDma4(u32 madr, u32 bcr, u32 chcr) // SPU2's Core 0 +{ + psxDmaGeneric( madr, bcr, chcr, 0, SPU2writeDMA4Mem, SPU2readDMA4Mem ); +} + +int psxDma4Interrupt() +{ + HW_DMA4_CHCR &= ~0x01000000; + psxDmaInterrupt(4); + iopIntcIrq( 9 ); + return 1; +} + +void psxDma2(u32 madr, u32 bcr, u32 chcr) // GPU +{ + HW_DMA2_CHCR &= ~0x01000000; + psxDmaInterrupt(2); +} + +void psxDma6(u32 madr, u32 bcr, u32 chcr) +{ + u32 *mem = (u32 *)PSXM(madr); + + PSXDMA_LOG("*** DMA 6 - OT *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); + + if (chcr == 0x11000002) { + while (bcr--) { + *mem-- = (madr - 4) & 0xffffff; + madr -= 4; + } + mem++; *mem = 0xffffff; + } else { + // Unknown option + PSXDMA_LOG("*** DMA 6 - OT unknown *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); + } + HW_DMA6_CHCR &= ~0x01000000; + psxDmaInterrupt(6); +} + +void psxDma7(u32 madr, u32 bcr, u32 chcr) // SPU2's Core 1 +{ + psxDmaGeneric( madr, bcr, chcr, 1, SPU2writeDMA7Mem, SPU2readDMA7Mem ); +} + +int psxDma7Interrupt() +{ + HW_DMA7_CHCR &= ~0x01000000; + psxDmaInterrupt2(0); + //iopIntcIrq( 9 ); + return 1; + +} +extern int eesifbusy[2]; +void psxDma9(u32 madr, u32 bcr, u32 chcr) +{ + SIF_LOG("IOP: dmaSIF0 chcr = %lx, madr = %lx, bcr = %lx, tadr = %lx\n", chcr, madr, bcr, HW_DMA9_TADR); + + iopsifbusy[0] = 1; + psHu32(0x1000F240) |= 0x2000; + + if (eesifbusy[0] == 1) { + SIF0Dma(); + psHu32(0x1000F240) &= ~0x20; + psHu32(0x1000F240) &= ~0x2000; + } +} + +void psxDma10(u32 madr, u32 bcr, u32 chcr) { + SIF_LOG("IOP: dmaSIF1 chcr = %lx, madr = %lx, bcr = %lx\n", chcr, madr, bcr); + + iopsifbusy[1] = 1; + psHu32(0x1000F240) |= 0x4000; + + if (eesifbusy[1] == 1) { + FreezeXMMRegs(1); + SIF1Dma(); + psHu32(0x1000F240) &= ~0x40; + psHu32(0x1000F240) &= ~0x100; + psHu32(0x1000F240) &= ~0x4000; + FreezeXMMRegs(0); + } +} + +void psxDma8(u32 madr, u32 bcr, u32 chcr) { + + const int size = (bcr >> 16) * (bcr & 0xFFFF) * 8; + + switch (chcr & 0x01000201) { + case 0x01000201: //cpu to dev9 transfer + PSXDMA_LOG("*** DMA 8 - DEV9 mem2dev9 *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); + DEV9writeDMA8Mem((u32*)PSXM(madr), size); + break; + + case 0x01000200: //dev9 to cpu transfer + PSXDMA_LOG("*** DMA 8 - DEV9 dev9mem *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); + DEV9readDMA8Mem((u32*)PSXM(madr), size); + break; + + default: + PSXDMA_LOG("*** DMA 8 - DEV9 unknown *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); + break; + } + HW_DMA8_CHCR &= ~0x01000000; + psxDmaInterrupt2(1); +} + +void dev9Interrupt() { + if( (dev9Handler != NULL) && (dev9Handler() != 1) ) + return; + + iopIntcIrq( 13 ); + hwIntcIrq(INTC_SBUS); +} + +void dev9Irq(int cycles) { + PSX_INT(IopEvt_DEV9, cycles); +} + +void usbInterrupt() { + if( usbHandler != NULL && (usbHandler() != 1) ) + return; + + iopIntcIrq( 22 ); + hwIntcIrq(INTC_SBUS); +} + +void usbIrq(int cycles) { + PSX_INT(IopEvt_USB, cycles); +} + +void fwIrq() { + iopIntcIrq( 24 ); + hwIntcIrq(INTC_SBUS); +} + +void spu2DMA4Irq() { + SPU2interruptDMA4(); + //HW_DMA4_BCR = 0; + HW_DMA4_CHCR &= ~0x01000000; + psxDmaInterrupt(4); +} + +void spu2DMA7Irq() { + SPU2interruptDMA7(); + //HW_DMA7_BCR = 0; + HW_DMA7_CHCR &= ~0x01000000; + psxDmaInterrupt2(0); +} + +void spu2Irq() { + iopIntcIrq( 9 ); + hwIntcIrq(INTC_SBUS); +} + +void iopIntcIrq( uint irqType ) +{ + psxHu32(0x1070)|= 1<> 16) * (bcr & 0xFFFF); + + IopChannels[channel].Control = chcr | DMA_CTRL_ACTIVE; + IopChannels[channel].MemAddr = madr; + IopChannels[channel].ByteCount = size; +} + +void IopDmaUpdate(u32 elapsed) +{ + u32 MinDelay = 0xFFFFFFFF; + + for(int i=0;iControl&DMA_CTRL_ACTIVE) + { + ch->Target-=elapsed; + if(ch->Target<=0) + { + if(ch->ByteCount<=0) + { + ch->Control &= ~DMA_CTRL_ACTIVE; + RaiseDmaIrq(i); + IopDmaHandlers[i].Interrupt(i); + } + else + { + // TODO: Make sure it's the right order + DmaHandler handler = (ch->Control&DMA_CTRL_DIRECTION)?IopDmaHandlers[i].Read:IopDmaHandlers[i].Write; + + u32 BCount = 0; + s32 Target = (handler)?handler(i,(u32*)PSXM(ch->MemAddr),ch->ByteCount,&BCount):0; + + ch->Target = 100; + if(Target<0) + { + // TODO: ... What to do if the plugin errors? :P + } + else if(BCount!=0) + { + ch->MemAddr += BCount; + ch->ByteCount -= BCount; + + ch->Target = BCount / ch->Width; + } + + if (Target!=0) ch->Target=Target; + } + } + } + } +} + +s32 errDmaRead (s32 channel, u32* data, u32 wordsLeft, u32* wordsProcessed) +{ + Console::Error("ERROR: Tried to read using DMA %d (%s). Ignoring.",0,channel,IopDmaNames[channel]); + + *wordsProcessed = wordsLeft; + return 0; +} + +s32 errDmaWrite (s32 channel, u32* data, u32 wordsLeft, u32* wordsProcessed) +{ + Console::Error("ERROR: Tried to write using DMA %d (%s). Ignoring.",0,channel,IopDmaNames[channel]); + + *wordsProcessed = wordsLeft; + return 0; +} + + +#endif diff --git a/pcsx2/IopDma.h b/pcsx2/IopDma.h index 7304c85ad8..32b5562211 100644 --- a/pcsx2/IopDma.h +++ b/pcsx2/IopDma.h @@ -1,48 +1,48 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __PSXDMA_H__ -#define __PSXDMA_H__ - -#include "PS2Edefs.h" - -void psxDma2(u32 madr, u32 bcr, u32 chcr); -void psxDma3(u32 madr, u32 bcr, u32 chcr); -void psxDma4(u32 madr, u32 bcr, u32 chcr); -void psxDma6(u32 madr, u32 bcr, u32 chcr); -void psxDma7(u32 madr, u32 bcr, u32 chcr); -void psxDma8(u32 madr, u32 bcr, u32 chcr); -void psxDma9(u32 madr, u32 bcr, u32 chcr); -void psxDma10(u32 madr, u32 bcr, u32 chcr); - -int psxDma4Interrupt(); -int psxDma7Interrupt(); -void dev9Interrupt(); -void dev9Irq(int cycles); -void usbInterrupt(); -void usbIrq(int cycles); -void fwIrq(); -void spu2Irq(); - -extern void iopIntcIrq( uint irqType ); -extern void iopTestIntc(); - -extern DEV9handler dev9Handler; -extern USBhandler usbHandler; - -#endif /* __PSXDMA_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __PSXDMA_H__ +#define __PSXDMA_H__ + +#include "PS2Edefs.h" + +void psxDma2(u32 madr, u32 bcr, u32 chcr); +void psxDma3(u32 madr, u32 bcr, u32 chcr); +void psxDma4(u32 madr, u32 bcr, u32 chcr); +void psxDma6(u32 madr, u32 bcr, u32 chcr); +void psxDma7(u32 madr, u32 bcr, u32 chcr); +void psxDma8(u32 madr, u32 bcr, u32 chcr); +void psxDma9(u32 madr, u32 bcr, u32 chcr); +void psxDma10(u32 madr, u32 bcr, u32 chcr); + +int psxDma4Interrupt(); +int psxDma7Interrupt(); +void dev9Interrupt(); +void dev9Irq(int cycles); +void usbInterrupt(); +void usbIrq(int cycles); +void fwIrq(); +void spu2Irq(); + +extern void iopIntcIrq( uint irqType ); +extern void iopTestIntc(); + +extern DEV9handler dev9Handler; +extern USBhandler usbHandler; + +#endif /* __PSXDMA_H__ */ diff --git a/pcsx2/IopHw.cpp b/pcsx2/IopHw.cpp index 72defd2dd3..582bce6d6b 100644 --- a/pcsx2/IopHw.cpp +++ b/pcsx2/IopHw.cpp @@ -1,1413 +1,1413 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "PsxCommon.h" -#include "Misc.h" -#include "iR5900.h" - -// NOTE: Any modifications to read/write fns should also go into their const counterparts -// found in iPsxHw.cpp. - -void psxHwReset() { -/* if (Config.Sio) psxHu32(0x1070) |= 0x80; - if (Config.SpuIrq) psxHu32(0x1070) |= 0x200;*/ - - memzero_ptr<0x10000>(psxH); - -// mdecInit(); //initialize mdec decoder - cdrReset(); - cdvdReset(); - psxRcntInit(); - sioInit(); - //sio2Reset(); -} - -u8 psxHwRead8(u32 add) { - u8 hard; - - if (add >= 0x1f801600 && add < 0x1f801700) { - return USBread8(add); - } - - switch (add) { - case 0x1f801040: hard = sioRead8();break; - // case 0x1f801050: hard = serial_read8(); break;//for use of serial port ignore for now - - case 0x1f80146e: // DEV9_R_REV - return DEV9read8(add); - -#ifdef PCSX2_DEVBUILD - case 0x1f801100: - case 0x1f801104: - case 0x1f801108: - case 0x1f801110: - case 0x1f801114: - case 0x1f801118: - case 0x1f801120: - case 0x1f801124: - case 0x1f801128: - case 0x1f801480: - case 0x1f801484: - case 0x1f801488: - case 0x1f801490: - case 0x1f801494: - case 0x1f801498: - case 0x1f8014a0: - case 0x1f8014a4: - case 0x1f8014a8: - SysPrintf("8bit counter read %x\n", add); - hard = psxHu8(add); - return hard; -#endif - - case 0x1f801800: hard = cdrRead0(); break; - case 0x1f801801: hard = cdrRead1(); break; - case 0x1f801802: hard = cdrRead2(); break; - case 0x1f801803: hard = cdrRead3(); break; - - case 0x1f803100: // PS/EE/IOP conf related - hard = 0x10; // Dram 2M - break; - - case 0x1F808264: - hard = sio2_fifoOut();//sio2 serial data feed/fifo_out - PSXHW_LOG("SIO2 read8 DATAOUT %08X\n", hard); - return hard; - - default: - hard = psxHu8(add); - PSXHW_LOG("*Unknown 8bit read at address %lx\n", add); - return hard; - } - - PSXHW_LOG("*Known 8bit read at address %lx value %x\n", add, hard); - return hard; -} - -u16 psxHwRead16(u32 add) { - u16 hard; - - if (add >= 0x1f801600 && add < 0x1f801700) { - return USBread16(add); - } - - switch (add) { - - case 0x1f801070: PSXHW_LOG("IREG 16bit read %x\n", psxHu16(0x1070)); - return psxHu16(0x1070); - case 0x1f801074: PSXHW_LOG("IMASK 16bit read %x\n", psxHu16(0x1074)); - return psxHu16(0x1074); - - case 0x1f801040: - hard = sioRead8(); - hard|= sioRead8() << 8; - PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); - return hard; - case 0x1f801044: - hard = sio.StatReg; - PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); - return hard; - case 0x1f801048: - hard = sio.ModeReg; - PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); - return hard; - case 0x1f80104a: - hard = sio.CtrlReg; - PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); - return hard; - case 0x1f80104e: - hard = sio.BaudReg; - PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); - return hard; - - //Serial port stuff not support now ;P - // case 0x1f801050: hard = serial_read16(); break; - // case 0x1f801054: hard = serial_status_read(); break; - // case 0x1f80105a: hard = serial_control_read(); break; - // case 0x1f80105e: hard = serial_baud_read(); break; - - case 0x1f801100: - hard = (u16)psxRcntRcount16(0); - PSXCNT_LOG("T0 count read16: %x\n", hard); - return hard; - case 0x1f801104: - hard = psxCounters[0].mode; - psxCounters[0].mode &= ~0x1800; - psxCounters[0].mode |= 0x400; - PSXCNT_LOG("T0 mode read16: %x\n", hard); - return hard; - case 0x1f801108: - hard = psxCounters[0].target; - PSXCNT_LOG("T0 target read16: %x\n", hard); - return hard; - case 0x1f801110: - hard = (u16)psxRcntRcount16(1); - PSXCNT_LOG("T1 count read16: %x\n", hard); - return hard; - case 0x1f801114: - hard = psxCounters[1].mode; - psxCounters[1].mode &= ~0x1800; - psxCounters[1].mode |= 0x400; - PSXCNT_LOG("T1 mode read16: %x\n", hard); - return hard; - case 0x1f801118: - hard = psxCounters[1].target; - PSXCNT_LOG("T1 target read16: %x\n", hard); - return hard; - case 0x1f801120: - hard = (u16)psxRcntRcount16(2); - PSXCNT_LOG("T2 count read16: %x\n", hard); - return hard; - case 0x1f801124: - hard = psxCounters[2].mode; - psxCounters[2].mode &= ~0x1800; - psxCounters[2].mode |= 0x400; - PSXCNT_LOG("T2 mode read16: %x\n", hard); - return hard; - case 0x1f801128: - hard = psxCounters[2].target; - PSXCNT_LOG("T2 target read16: %x\n", hard); - return hard; - - case 0x1f80146e: // DEV9_R_REV - return DEV9read16(add); - - case 0x1f801480: - hard = (u16)psxRcntRcount32(3); - PSXCNT_LOG("T3 count read16: %lx\n", hard); - return hard; - case 0x1f801484: - hard = psxCounters[3].mode; - psxCounters[3].mode &= ~0x1800; - psxCounters[3].mode |= 0x400; - PSXCNT_LOG("T3 mode read16: %lx\n", hard); - return hard; - case 0x1f801488: - hard = psxCounters[3].target; - PSXCNT_LOG("T3 target read16: %lx\n", hard); - return hard; - case 0x1f801490: - hard = (u16)psxRcntRcount32(4); - PSXCNT_LOG("T4 count read16: %lx\n", hard); - return hard; - case 0x1f801494: - hard = psxCounters[4].mode; - psxCounters[4].mode &= ~0x1800; - psxCounters[4].mode |= 0x400; - PSXCNT_LOG("T4 mode read16: %lx\n", hard); - return hard; - case 0x1f801498: - hard = psxCounters[4].target; - PSXCNT_LOG("T4 target read16: %lx\n", hard); - return hard; - case 0x1f8014a0: - hard = (u16)psxRcntRcount32(5); - PSXCNT_LOG("T5 count read16: %lx\n", hard); - return hard; - case 0x1f8014a4: - hard = psxCounters[5].mode; - psxCounters[5].mode &= ~0x1800; - psxCounters[5].mode |= 0x400; - PSXCNT_LOG("T5 mode read16: %lx\n", hard); - return hard; - case 0x1f8014a8: - hard = psxCounters[5].target; - PSXCNT_LOG("T5 target read16: %lx\n", hard); - return hard; - - case 0x1f801504: - hard = psxHu16(0x1504); - PSXHW_LOG("DMA7 BCR_size 16bit read %lx\n", hard); - return hard; - case 0x1f801506: - hard = psxHu16(0x1506); - PSXHW_LOG("DMA7 BCR_count 16bit read %lx\n", hard); - return hard; - //case 0x1f802030: hard = //int_2000???? - //case 0x1f802040: hard =//dip switches...?? - - default: - if (add>=0x1f801c00 && add<0x1f801e00) { - hard = SPU2read(add); - } else { - hard = psxHu16(add); - PSXHW_LOG("*Unknown 16bit read at address %lx\n", add); - } - return hard; - } - - - PSXHW_LOG("*Known 16bit read at address %lx value %x\n", add, hard); - return hard; -} - -u32 psxHwRead32(u32 add) { - u32 hard; - - if (add >= 0x1f801600 && add < 0x1f801700) { - return USBread32(add); - } - if (add >= 0x1f808400 && add <= 0x1f808550) {//the size is a complete guess.. - return FWread32(add); - } - - switch (add) { - case 0x1f801040: - hard = sioRead8(); - hard|= sioRead8() << 8; - hard|= sioRead8() << 16; - hard|= sioRead8() << 24; - PAD_LOG("sio read32 ;ret = %lx\n", hard); - return hard; - - // case 0x1f801050: hard = serial_read32(); break;//serial port - case 0x1f801060: - PSXHW_LOG("RAM size read %lx\n", psxHu32(0x1060)); - return psxHu32(0x1060); - case 0x1f801070: PSXHW_LOG("IREG 32bit read %x\n", psxHu32(0x1070)); - return psxHu32(0x1070); - case 0x1f801074: PSXHW_LOG("IMASK 32bit read %x\n", psxHu32(0x1074)); - return psxHu32(0x1074); - case 0x1f801078: - PSXHW_LOG("ICTRL 32bit read %x\n", psxHu32(0x1078)); - hard = psxHu32(0x1078); - psxHu32(0x1078) = 0; - return hard; - -/* case 0x1f801810: -// hard = GPU_readData(); - PSXHW_LOG("GPU DATA 32bit read %lx\n", hard); - return hard;*/ -/* case 0x1f801814: - hard = GPU_readStatus(); - PSXHW_LOG("GPU STATUS 32bit read %lx\n", hard); - return hard; -*/ -/* case 0x1f801820: hard = mdecRead0(); break; - case 0x1f801824: hard = mdecRead1(); break; -*/ - - case 0x1f8010a0: - PSXHW_LOG("DMA2 MADR 32bit read %lx\n", psxHu32(0x10a0)); - return HW_DMA2_MADR; - case 0x1f8010a4: - PSXHW_LOG("DMA2 BCR 32bit read %lx\n", psxHu32(0x10a4)); - return HW_DMA2_BCR; - case 0x1f8010a8: - PSXHW_LOG("DMA2 CHCR 32bit read %lx\n", psxHu32(0x10a8)); - return HW_DMA2_CHCR; - - case 0x1f8010b0: - PSXHW_LOG("DMA3 MADR 32bit read %lx\n", psxHu32(0x10b0)); - return HW_DMA3_MADR; - case 0x1f8010b4: - PSXHW_LOG("DMA3 BCR 32bit read %lx\n", psxHu32(0x10b4)); - return HW_DMA3_BCR; - case 0x1f8010b8: - PSXHW_LOG("DMA3 CHCR 32bit read %lx\n", psxHu32(0x10b8)); - return HW_DMA3_CHCR; - - case 0x1f801520: - PSXHW_LOG("DMA9 MADR 32bit read %lx\n", HW_DMA9_MADR); - return HW_DMA9_MADR; - case 0x1f801524: - PSXHW_LOG("DMA9 BCR 32bit read %lx\n", HW_DMA9_BCR); - return HW_DMA9_BCR; - case 0x1f801528: - PSXHW_LOG("DMA9 CHCR 32bit read %lx\n", HW_DMA9_CHCR); - return HW_DMA9_CHCR; - case 0x1f80152C: - PSXHW_LOG("DMA9 TADR 32bit read %lx\n", HW_DMA9_TADR); - return HW_DMA9_TADR; - - case 0x1f801530: - PSXHW_LOG("DMA10 MADR 32bit read %lx\n", HW_DMA10_MADR); - return HW_DMA10_MADR; - case 0x1f801534: - PSXHW_LOG("DMA10 BCR 32bit read %lx\n", HW_DMA10_BCR); - return HW_DMA10_BCR; - case 0x1f801538: - PSXHW_LOG("DMA10 CHCR 32bit read %lx\n", HW_DMA10_CHCR); - return HW_DMA10_CHCR; - -// case 0x1f8010f0: PSXHW_LOG("DMA PCR 32bit read " << psxHu32(0x10f0)); -// return HW_DMA_PCR; // dma rest channel - - case 0x1f8010f4: - PSXHW_LOG("DMA ICR 32bit read %lx\n", HW_DMA_ICR); - return HW_DMA_ICR; - -//SSBus registers - case 0x1f801000: - hard = psxHu32(0x1000); - PSXHW_LOG("SSBUS 32bit read %lx\n", hard); - return hard; - case 0x1f801004: - hard = psxHu32(0x1004); - PSXHW_LOG("SSBUS 32bit read %lx\n", hard); - return hard; - case 0x1f801008: - hard = psxHu32(0x1008); - PSXHW_LOG("SSBUS 32bit read %lx\n", hard); - return hard; - case 0x1f80100C: - hard = psxHu32(0x100C); - PSXHW_LOG("SSBUS dev1_delay 32bit read %lx\n", hard); - return hard; - case 0x1f801010: - hard = psxHu32(0x1010); - PSXHW_LOG("SSBUS rom_delay 32bit read %lx\n", hard); - return hard; - case 0x1f801014: - hard = psxHu32(0x1014); - PSXHW_LOG("SSBUS spu_delay 32bit read %lx\n", hard); - return hard; - case 0x1f801018: - hard = psxHu32(0x1018); - PSXHW_LOG("SSBUS dev5_delay 32bit read %lx\n", hard); - return hard; - case 0x1f80101C: - hard = psxHu32(0x101C); - PSXHW_LOG("SSBUS 32bit read %lx\n", hard); - return hard; - case 0x1f801020: - hard = psxHu32(0x1020); - PSXHW_LOG("SSBUS com_delay 32bit read %lx\n", hard); - return hard; - case 0x1f801400: - hard = psxHu32(0x1400); - PSXHW_LOG("SSBUS dev1_addr 32bit read %lx\n", hard); - return hard; - case 0x1f801404: - hard = psxHu32(0x1404); - PSXHW_LOG("SSBUS spu_addr 32bit read %lx\n", hard); - return hard; - case 0x1f801408: - hard = psxHu32(0x1408); - PSXHW_LOG("SSBUS dev5_addr 32bit read %lx\n", hard); - return hard; - case 0x1f80140C: - hard = psxHu32(0x140C); - PSXHW_LOG("SSBUS spu1_addr 32bit read %lx\n", hard); - return hard; - case 0x1f801410: - hard = psxHu32(0x1410); - PSXHW_LOG("SSBUS 32bit read %lx\n", hard); - return hard; - case 0x1f801414: - hard = psxHu32(0x1414); - PSXHW_LOG("SSBUS spu1_delay 32bit read %lx\n", hard); - return hard; - case 0x1f801418: - hard = psxHu32(0x1418); - PSXHW_LOG("SSBUS 32bit read %lx\n", hard); - return hard; - case 0x1f80141C: - hard = psxHu32(0x141C); - PSXHW_LOG("SSBUS 32bit read %lx\n", hard); - return hard; - case 0x1f801420: - hard = psxHu32(0x1420); - PSXHW_LOG("SSBUS 32bit read %lx\n", hard); - return hard; - - case 0x1f8010f0: - PSXHW_LOG("DMA PCR 32bit read %lx\n", HW_DMA_PCR); - return HW_DMA_PCR; - - case 0x1f8010c8: - PSXHW_LOG("DMA4 CHCR 32bit read %lx\n", HW_DMA4_CHCR); - return HW_DMA4_CHCR; // DMA4 chcr (SPU DMA) - - // time for rootcounters :) - case 0x1f801100: - hard = (u16)psxRcntRcount16(0); - PSXCNT_LOG("T0 count read32: %lx\n", hard); - return hard; - case 0x1f801104: - hard = (u16)psxCounters[0].mode; - PSXCNT_LOG("T0 mode read32: %lx\n", hard); - return hard; - case 0x1f801108: - hard = psxCounters[0].target; - PSXCNT_LOG("T0 target read32: %lx\n", hard); - return hard; - case 0x1f801110: - hard = (u16)psxRcntRcount16(1); - PSXCNT_LOG("T1 count read32: %lx\n", hard); - return hard; - case 0x1f801114: - hard = (u16)psxCounters[1].mode; - PSXCNT_LOG("T1 mode read32: %lx\n", hard); - return hard; - case 0x1f801118: - hard = psxCounters[1].target; - PSXCNT_LOG("T1 target read32: %lx\n", hard); - return hard; - case 0x1f801120: - hard = (u16)psxRcntRcount16(2); - PSXCNT_LOG("T2 count read32: %lx\n", hard); - return hard; - case 0x1f801124: - hard = (u16)psxCounters[2].mode; - PSXCNT_LOG("T2 mode read32: %lx\n", hard); - return hard; - case 0x1f801128: - hard = psxCounters[2].target; - PSXCNT_LOG("T2 target read32: %lx\n", hard); - return hard; - - case 0x1f801480: - hard = (u32)psxRcntRcount32(3); - PSXCNT_LOG("T3 count read32: %lx\n", hard); - return hard; - case 0x1f801484: - hard = (u16)psxCounters[3].mode; - PSXCNT_LOG("T3 mode read32: %lx\n", hard); - return hard; - case 0x1f801488: - hard = psxCounters[3].target; - PSXCNT_LOG("T3 target read32: %lx\n", hard); - return hard; - case 0x1f801490: - hard = (u32)psxRcntRcount32(4); - PSXCNT_LOG("T4 count read32: %lx\n", hard); - return hard; - case 0x1f801494: - hard = (u16)psxCounters[4].mode; - PSXCNT_LOG("T4 mode read32: %lx\n", hard); - return hard; - case 0x1f801498: - hard = psxCounters[4].target; - PSXCNT_LOG("T4 target read32: %lx\n", hard); - return hard; - case 0x1f8014a0: - hard = (u32)psxRcntRcount32(5); - PSXCNT_LOG("T5 count read32: %lx\n", hard); - return hard; - case 0x1f8014a4: - hard = (u16)psxCounters[5].mode; - PSXCNT_LOG("T5 mode read32: %lx\n", hard); - return hard; - case 0x1f8014a8: - hard = psxCounters[5].target; - PSXCNT_LOG("T5 target read32: %lx\n", hard); - return hard; - - case 0x1f801450: - hard = psxHu32(add); - PSXHW_LOG("%08X ICFG 32bit read %x\n", psxRegs.pc, hard); - return hard; - - - case 0x1F8010C0: - HW_DMA4_MADR = SPU2ReadMemAddr(0); - return HW_DMA4_MADR; - - case 0x1f801500: - HW_DMA7_MADR = SPU2ReadMemAddr(1); - PSXHW_LOG("DMA7 MADR 32bit read %lx\n", HW_DMA7_MADR); - return HW_DMA7_MADR; // DMA7 madr - case 0x1f801504: - PSXHW_LOG("DMA7 BCR 32bit read %lx\n", HW_DMA7_BCR); - return HW_DMA7_BCR; // DMA7 bcr - - case 0x1f801508: - PSXHW_LOG("DMA7 CHCR 32bit read %lx\n", HW_DMA7_CHCR); - return HW_DMA7_CHCR; // DMA7 chcr (SPU2) - - case 0x1f801570: - hard = psxHu32(0x1570); - PSXHW_LOG("DMA PCR2 32bit read %lx\n", hard); - return hard; - case 0x1f801574: - PSXHW_LOG("DMA ICR2 32bit read %lx\n", HW_DMA_ICR2); - return HW_DMA_ICR2; - - case 0x1F808200: - case 0x1F808204: - case 0x1F808208: - case 0x1F80820C: - case 0x1F808210: - case 0x1F808214: - case 0x1F808218: - case 0x1F80821C: - case 0x1F808220: - case 0x1F808224: - case 0x1F808228: - case 0x1F80822C: - case 0x1F808230: - case 0x1F808234: - case 0x1F808238: - case 0x1F80823C: - hard=sio2_getSend3((add-0x1F808200)/4); - PSXHW_LOG("SIO2 read param[%d] (%lx)\n", (add-0x1F808200)/4, hard); - return hard; - - case 0x1F808240: - case 0x1F808248: - case 0x1F808250: - case 0x1F80825C: - hard=sio2_getSend1((add-0x1F808240)/8); - PSXHW_LOG("SIO2 read send1[%d] (%lx)\n", (add-0x1F808240)/8, hard); - return hard; - - case 0x1F808244: - case 0x1F80824C: - case 0x1F808254: - case 0x1F808258: - hard=sio2_getSend2((add-0x1F808244)/8); - PSXHW_LOG("SIO2 read send2[%d] (%lx)\n", (add-0x1F808244)/8, hard); - return hard; - - case 0x1F808268: - hard=sio2_getCtrl(); - PSXHW_LOG("SIO2 read CTRL (%lx)\n", hard); - return hard; - - case 0x1F80826C: - hard=sio2_getRecv1(); - PSXHW_LOG("SIO2 read Recv1 (%lx)\n", hard); - return hard; - - case 0x1F808270: - hard=sio2_getRecv2(); - PSXHW_LOG("SIO2 read Recv2 (%lx)\n", hard); - return hard; - - case 0x1F808274: - hard=sio2_getRecv3(); - PSXHW_LOG("SIO2 read Recv3 (%lx)\n", hard); - return hard; - - case 0x1F808278: - hard=sio2_get8278(); - PSXHW_LOG("SIO2 read [8278] (%lx)\n", hard); - return hard; - - case 0x1F80827C: - hard=sio2_get827C(); - PSXHW_LOG("SIO2 read [827C] (%lx)\n", hard); - return hard; - - case 0x1F808280: - hard=sio2_getIntr(); - PSXHW_LOG("SIO2 read INTR (%lx)\n", hard); - return hard; - - default: - hard = psxHu32(add); - PSXHW_LOG("*Unknown 32bit read at address %lx: %lx\n", add, hard); - return hard; - } - PSXHW_LOG("*Known 32bit read at address %lx: %lx\n", add, hard); - return hard; -} - -int g_pbufi; -s8 g_pbuf[1024]; - -#define DmaExec(n) { \ - if (HW_DMA##n##_CHCR & 0x01000000 && \ - HW_DMA_PCR & (8 << (n * 4))) { \ - psxDma##n(HW_DMA##n##_MADR, HW_DMA##n##_BCR, HW_DMA##n##_CHCR); \ - } \ -} - -void psxHwWrite8(u32 add, u8 value) { - if (add >= 0x1f801600 && add < 0x1f801700) { - USBwrite8(add, value); return; - } - if((add & 0xf) == 0xa) SysPrintf("8bit write (possible chcr set) %x value %x\n", add, value); - switch (add) { - case 0x1f801040: - sioWrite8(value); - break; - // case 0x1f801050: serial_write8(value); break;//serial port - - case 0x1f801100: - case 0x1f801104: - case 0x1f801108: - case 0x1f801110: - case 0x1f801114: - case 0x1f801118: - case 0x1f801120: - case 0x1f801124: - case 0x1f801128: - case 0x1f801480: - case 0x1f801484: - case 0x1f801488: - case 0x1f801490: - case 0x1f801494: - case 0x1f801498: - case 0x1f8014a0: - case 0x1f8014a4: - case 0x1f8014a8: - SysPrintf("8bit counter write %x\n", add); - psxHu8(add) = value; - return; - case 0x1f801450: - if (value) { PSXHW_LOG("%08X ICFG 8bit write %lx\n", psxRegs.pc, value); } - psxHu8(0x1450) = value; - return; - - case 0x1f801800: cdrWrite0(value); break; - case 0x1f801801: cdrWrite1(value); break; - case 0x1f801802: cdrWrite2(value); break; - case 0x1f801803: cdrWrite3(value); break; - - case 0x1f80380c: - if (value == '\r') break; - if (value == '\n' || g_pbufi >= 1023) { - g_pbuf[g_pbufi++] = 0; g_pbufi = 0; - SysPrintf("%s\n", g_pbuf); - } - else g_pbuf[g_pbufi++] = value; - psxHu8(add) = value; - return; - - case 0x1F808260: - PSXHW_LOG("SIO2 write8 DATAIN <- %08X\n", value); - sio2_serialIn(value);return;//serial data feed/fifo - - default: - psxHu8(add) = value; - PSXHW_LOG("*Unknown 8bit write at address %lx value %x\n", add, value); - return; - } - psxHu8(add) = value; - PSXHW_LOG("*Known 8bit write at address %lx value %x\n", add, value); -} - -void psxHwWrite16(u32 add, u16 value) { - if (add >= 0x1f801600 && add < 0x1f801700) { - USBwrite16(add, value); return; - } - - if((add & 0xf) == 0x9) DevCon::WriteLn("16bit write (possible chcr set) %x value %x", params add, value); - - switch (add) { - case 0x1f801040: - sioWrite8((u8)value); - sioWrite8((u8)(value>>8)); - PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); - return; - case 0x1f801044: - PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); - return; - case 0x1f801048: - sio.ModeReg = value; - PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); - return; - case 0x1f80104a: // control register - sioWriteCtrl16(value); - PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); - return; - case 0x1f80104e: // baudrate register - sio.BaudReg = value; - PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); - return; - - //serial port ;P - // case 0x1f801050: serial_write16(value); break; - // case 0x1f80105a: serial_control_write(value);break; - // case 0x1f80105e: serial_baud_write(value); break; - // case 0x1f801054: serial_status_write(value); break; - - case 0x1f801070: - PSXHW_LOG("IREG 16bit write %x\n", value); -// if (Config.Sio) psxHu16(0x1070) |= 0x80; -// if (Config.SpuIrq) psxHu16(0x1070) |= 0x200; - psxHu16(0x1070) &= value; - return; - - case 0x1f801074: - PSXHW_LOG("IMASK 16bit write %x\n", value); - psxHu16(0x1074) = value; - iopTestIntc(); - return; - - case 0x1f801078: // see the 32-bit version for notes! - PSXHW_LOG("ICTRL 16bit write %x\n", value); - psxHu16(0x1078) = value; - iopTestIntc(); - return; - - case 0x1f8010c4: - PSXHW_LOG("DMA4 BCR_size 16bit write %lx\n", value); - psxHu16(0x10c4) = value; - return; // DMA4 bcr_size - - case 0x1f8010c6: - PSXHW_LOG("DMA4 BCR_count 16bit write %lx\n", value); - psxHu16(0x10c6) = value; return; // DMA4 bcr_count - - case 0x1f801100: - PSXCNT_LOG("COUNTER 0 COUNT 16bit write %x\n", value); - psxRcntWcount16(0, value); return; - case 0x1f801104: - PSXCNT_LOG("COUNTER 0 MODE 16bit write %x\n", value); - psxRcnt0Wmode(value); return; - case 0x1f801108: - PSXCNT_LOG("COUNTER 0 TARGET 16bit write %x\n", value); - psxRcntWtarget16(0, value); return; - - case 0x1f801110: - PSXCNT_LOG("COUNTER 1 COUNT 16bit write %x\n", value); - psxRcntWcount16(1, value); return; - case 0x1f801114: - PSXCNT_LOG("COUNTER 1 MODE 16bit write %x\n", value); - psxRcnt1Wmode(value); return; - case 0x1f801118: - PSXCNT_LOG("COUNTER 1 TARGET 16bit write %x\n", value); - psxRcntWtarget16(1, value); return; - - case 0x1f801120: - PSXCNT_LOG("COUNTER 2 COUNT 16bit write %x\n", value); - psxRcntWcount16(2, value); return; - case 0x1f801124: - PSXCNT_LOG("COUNTER 2 MODE 16bit write %x\n", value); - psxRcnt2Wmode(value); return; - case 0x1f801128: - PSXCNT_LOG("COUNTER 2 TARGET 16bit write %x\n", value); - psxRcntWtarget16(2, value); return; - - case 0x1f801450: - if (value) { PSXHW_LOG("%08X ICFG 16bit write %lx\n", psxRegs.pc, value); } - psxHu16(0x1450) = value/* & (~0x8)*/; - return; - - case 0x1f801480: - PSXCNT_LOG("COUNTER 3 COUNT 16bit write %lx\n", value); - psxRcntWcount32(3, value); return; - case 0x1f801484: - PSXCNT_LOG("COUNTER 3 MODE 16bit write %lx\n", value); - psxRcnt3Wmode(value); return; - case 0x1f801488: - PSXCNT_LOG("COUNTER 3 TARGET 16bit write %lx\n", value); - psxRcntWtarget32(3, value); return; - - case 0x1f801490: - PSXCNT_LOG("COUNTER 4 COUNT 16bit write %lx\n", value); - psxRcntWcount32(4, value); return; - case 0x1f801494: - PSXCNT_LOG("COUNTER 4 MODE 16bit write %lx\n", value); - psxRcnt4Wmode(value); return; - case 0x1f801498: - PSXCNT_LOG("COUNTER 4 TARGET 16bit write %lx\n", value); - psxRcntWtarget32(4, value); return; - - case 0x1f8014a0: - PSXCNT_LOG("COUNTER 5 COUNT 16bit write %lx\n", value); - psxRcntWcount32(5, value); return; - case 0x1f8014a4: - PSXCNT_LOG("COUNTER 5 MODE 16bit write %lx\n", value); - psxRcnt5Wmode(value); return; - case 0x1f8014a8: - PSXCNT_LOG("COUNTER 5 TARGET 16bit write %lx\n", value); - psxRcntWtarget32(5, value); return; - - case 0x1f801504: - psxHu16(0x1504) = value; - PSXHW_LOG("DMA7 BCR_size 16bit write %lx\n", value); - return; - case 0x1f801506: - psxHu16(0x1506) = value; - PSXHW_LOG("DMA7 BCR_count 16bit write %lx\n", value); - return; - default: - if (add>=0x1f801c00 && add<0x1f801e00) { - SPU2write(add, value); - return; - } - - psxHu16(add) = value; - PSXHW_LOG("*Unknown 16bit write at address %lx value %x\n", add, value); - return; - } - psxHu16(add) = value; - PSXHW_LOG("*Known 16bit write at address %lx value %x\n", add, value); -} - -#define DmaExec2(n) { \ - if (HW_DMA##n##_CHCR & 0x01000000 && \ - HW_DMA_PCR2 & (8 << ((n-7) * 4))) { \ - psxDma##n(HW_DMA##n##_MADR, HW_DMA##n##_BCR, HW_DMA##n##_CHCR); \ - } \ -} - -void psxHwWrite32(u32 add, u32 value) { - if (add >= 0x1f801600 && add < 0x1f801700) { - USBwrite32(add, value); return; - } - if (add >= 0x1f808400 && add <= 0x1f808550) { - FWwrite32(add, value); return; - } - switch (add) { - case 0x1f801040: - sioWrite8((u8)value); - sioWrite8((u8)((value&0xff) >> 8)); - sioWrite8((u8)((value&0xff) >> 16)); - sioWrite8((u8)((value&0xff) >> 24)); - PAD_LOG("sio write32 %lx\n", value); - return; - // case 0x1f801050: serial_write32(value); break;//serial port - case 0x1f801060: - PSXHW_LOG("RAM size write %lx\n", value); - psxHu32(add) = value; - return; // Ram size - -//------------------------------------------------------------------ - case 0x1f801070: - PSXHW_LOG("IREG 32bit write %lx\n", value); -// if (Config.Sio) psxHu32(0x1070) |= 0x80; -// if (Config.SpuIrq) psxHu32(0x1070) |= 0x200; - psxHu32(0x1070) &= value; - return; - - case 0x1f801074: - PSXHW_LOG("IMASK 32bit write %lx\n", value); - psxHu32(0x1074) = value; - iopTestIntc(); - return; - - case 0x1f801078: - PSXHW_LOG("ICTRL 32bit write %lx\n", value); - psxHu32(0x1078) = value; //1; //According to pSXAuthor this allways becomes 1 on write, but MHPB won't boot if value is not writen ;p - iopTestIntc(); - return; - -//------------------------------------------------------------------ - //SSBus registers - case 0x1f801000: - psxHu32(0x1000) = value; - PSXHW_LOG("SSBUS 32bit write %lx\n", value); - return; - case 0x1f801004: - psxHu32(0x1004) = value; - PSXHW_LOG("SSBUS 32bit write %lx\n", value); - return; - case 0x1f801008: - psxHu32(0x1008) = value; - PSXHW_LOG("SSBUS 32bit write %lx\n", value); - return; - case 0x1f80100C: - psxHu32(0x100C) = value; - PSXHW_LOG("SSBUS dev1_delay 32bit write %lx\n", value); - return; - case 0x1f801010: - psxHu32(0x1010) = value; - PSXHW_LOG("SSBUS rom_delay 32bit write %lx\n", value); - return; - case 0x1f801014: - psxHu32(0x1014) = value; - PSXHW_LOG("SSBUS spu_delay 32bit write %lx\n", value); - return; - case 0x1f801018: - psxHu32(0x1018) = value; - PSXHW_LOG("SSBUS dev5_delay 32bit write %lx\n", value); - return; - case 0x1f80101C: - psxHu32(0x101C) = value; - PSXHW_LOG("SSBUS 32bit write %lx\n", value); - return; - case 0x1f801020: - psxHu32(0x1020) = value; - PSXHW_LOG("SSBUS com_delay 32bit write %lx\n", value); - return; - case 0x1f801400: - psxHu32(0x1400) = value; - PSXHW_LOG("SSBUS dev1_addr 32bit write %lx\n", value); - return; - case 0x1f801404: - psxHu32(0x1404) = value; - PSXHW_LOG("SSBUS spu_addr 32bit write %lx\n", value); - return; - case 0x1f801408: - psxHu32(0x1408) = value; - PSXHW_LOG("SSBUS dev5_addr 32bit write %lx\n", value); - return; - case 0x1f80140C: - psxHu32(0x140C) = value; - PSXHW_LOG("SSBUS spu1_addr 32bit write %lx\n", value); - return; - case 0x1f801410: - psxHu32(0x1410) = value; - PSXHW_LOG("SSBUS 32bit write %lx\n", value); - return; - case 0x1f801414: - psxHu32(0x1414) = value; - PSXHW_LOG("SSBUS spu1_delay 32bit write %lx\n", value); - return; - case 0x1f801418: - psxHu32(0x1418) = value; - PSXHW_LOG("SSBUS 32bit write %lx\n", value); - return; - case 0x1f80141C: - psxHu32(0x141C) = value; - PSXHW_LOG("SSBUS 32bit write %lx\n", value); - return; - case 0x1f801420: - psxHu32(0x1420) = value; - PSXHW_LOG("SSBUS 32bit write %lx\n", value); - return; - -//------------------------------------------------------------------ - case 0x1f801080: - PSXHW_LOG("DMA0 MADR 32bit write %lx\n", value); - HW_DMA0_MADR = value; return; // DMA0 madr - case 0x1f801084: - PSXHW_LOG("DMA0 BCR 32bit write %lx\n", value); - HW_DMA0_BCR = value; return; // DMA0 bcr - case 0x1f801088: - PSXHW_LOG("DMA0 CHCR 32bit write %lx\n", value); - HW_DMA0_CHCR = value; // DMA0 chcr (MDEC in DMA) -// DmaExec(0); - return; - -//------------------------------------------------------------------ - case 0x1f801090: - PSXHW_LOG("DMA1 MADR 32bit write %lx\n", value); - HW_DMA1_MADR = value; return; // DMA1 madr - case 0x1f801094: - PSXHW_LOG("DMA1 BCR 32bit write %lx\n", value); - HW_DMA1_BCR = value; return; // DMA1 bcr - case 0x1f801098: - PSXHW_LOG("DMA1 CHCR 32bit write %lx\n", value); - HW_DMA1_CHCR = value; // DMA1 chcr (MDEC out DMA) -// DmaExec(1); - return; - -//------------------------------------------------------------------ - case 0x1f8010a0: - PSXHW_LOG("DMA2 MADR 32bit write %lx\n", value); - HW_DMA2_MADR = value; return; // DMA2 madr - case 0x1f8010a4: - PSXHW_LOG("DMA2 BCR 32bit write %lx\n", value); - HW_DMA2_BCR = value; return; // DMA2 bcr - case 0x1f8010a8: - PSXHW_LOG("DMA2 CHCR 32bit write %lx\n", value); - HW_DMA2_CHCR = value; // DMA2 chcr (GPU DMA) - DmaExec(2); - return; - -//------------------------------------------------------------------ - case 0x1f8010b0: - PSXHW_LOG("DMA3 MADR 32bit write %lx\n", value); - HW_DMA3_MADR = value; return; // DMA3 madr - case 0x1f8010b4: - PSXHW_LOG("DMA3 BCR 32bit write %lx\n", value); - HW_DMA3_BCR = value; return; // DMA3 bcr - case 0x1f8010b8: - PSXHW_LOG("DMA3 CHCR 32bit write %lx\n", value); - HW_DMA3_CHCR = value; // DMA3 chcr (CDROM DMA) - DmaExec(3); - - return; - -//------------------------------------------------------------------ - case 0x1f8010c0: - PSXHW_LOG("DMA4 MADR 32bit write %lx\n", value); - SPU2WriteMemAddr(0,value); - HW_DMA4_MADR = value; return; // DMA4 madr - case 0x1f8010c4: - PSXHW_LOG("DMA4 BCR 32bit write %lx\n", value); - HW_DMA4_BCR = value; return; // DMA4 bcr - case 0x1f8010c8: - PSXHW_LOG("DMA4 CHCR 32bit write %lx\n", value); - HW_DMA4_CHCR = value; // DMA4 chcr (SPU DMA) - DmaExec(4); - return; - -//------------------------------------------------------------------ -#if 0 - case 0x1f8010d0: break; //DMA5write_madr(); - case 0x1f8010d4: break; //DMA5write_bcr(); - case 0x1f8010d8: break; //DMA5write_chcr(); // Not yet needed?? -#endif - - case 0x1f8010e0: - PSXHW_LOG("DMA6 MADR 32bit write %lx\n", value); - HW_DMA6_MADR = value; return; // DMA6 madr - case 0x1f8010e4: - PSXHW_LOG("DMA6 BCR 32bit write %lx\n", value); - HW_DMA6_BCR = value; return; // DMA6 bcr - case 0x1f8010e8: - PSXHW_LOG("DMA6 CHCR 32bit write %lx\n", value); - HW_DMA6_CHCR = value; // DMA6 chcr (OT clear) - DmaExec(6); - return; - -//------------------------------------------------------------------ - case 0x1f801500: - PSXHW_LOG("DMA7 MADR 32bit write %lx\n", value); - SPU2WriteMemAddr(1,value); - HW_DMA7_MADR = value; return; // DMA7 madr - case 0x1f801504: - PSXHW_LOG("DMA7 BCR 32bit write %lx\n", value); - HW_DMA7_BCR = value; return; // DMA7 bcr - case 0x1f801508: - PSXHW_LOG("DMA7 CHCR 32bit write %lx\n", value); - HW_DMA7_CHCR = value; // DMA7 chcr (SPU2) - DmaExec2(7); - return; - -//------------------------------------------------------------------ - case 0x1f801510: - PSXHW_LOG("DMA8 MADR 32bit write %lx\n", value); - HW_DMA8_MADR = value; return; // DMA8 madr - case 0x1f801514: - PSXHW_LOG("DMA8 BCR 32bit write %lx\n", value); - HW_DMA8_BCR = value; return; // DMA8 bcr - case 0x1f801518: - PSXHW_LOG("DMA8 CHCR 32bit write %lx\n", value); - HW_DMA8_CHCR = value; // DMA8 chcr (DEV9) - DmaExec2(8); - return; - -//------------------------------------------------------------------ - case 0x1f801520: - PSXHW_LOG("DMA9 MADR 32bit write %lx\n", value); - HW_DMA9_MADR = value; return; // DMA9 madr - case 0x1f801524: - PSXHW_LOG("DMA9 BCR 32bit write %lx\n", value); - HW_DMA9_BCR = value; return; // DMA9 bcr - case 0x1f801528: - PSXHW_LOG("DMA9 CHCR 32bit write %lx\n", value); - HW_DMA9_CHCR = value; // DMA9 chcr (SIF0) - DmaExec2(9); - return; - case 0x1f80152c: - PSXHW_LOG("DMA9 TADR 32bit write %lx\n", value); - HW_DMA9_TADR = value; return; // DMA9 tadr - -//------------------------------------------------------------------ - case 0x1f801530: - PSXHW_LOG("DMA10 MADR 32bit write %lx\n", value); - HW_DMA10_MADR = value; return; // DMA10 madr - case 0x1f801534: - PSXHW_LOG("DMA10 BCR 32bit write %lx\n", value); - HW_DMA10_BCR = value; return; // DMA10 bcr - case 0x1f801538: - PSXHW_LOG("DMA10 CHCR 32bit write %lx\n", value); - HW_DMA10_CHCR = value; // DMA10 chcr (SIF1) - DmaExec2(10); - return; - -//------------------------------------------------------------------ - case 0x1f801540: - PSXHW_LOG("DMA11 SIO2in MADR 32bit write %lx\n", value); - HW_DMA11_MADR = value; return; - - case 0x1f801544: - PSXHW_LOG("DMA11 SIO2in BCR 32bit write %lx\n", value); - HW_DMA11_BCR = value; return; - case 0x1f801548: - PSXHW_LOG("DMA11 SIO2in CHCR 32bit write %lx\n", value); - HW_DMA11_CHCR = value; // DMA11 chcr (SIO2 in) - DmaExec2(11); - return; - -//------------------------------------------------------------------ - case 0x1f801550: - PSXHW_LOG("DMA12 SIO2out MADR 32bit write %lx\n", value); - HW_DMA12_MADR = value; return; - - case 0x1f801554: - PSXHW_LOG("DMA12 SIO2out BCR 32bit write %lx\n", value); - HW_DMA12_BCR = value; return; - case 0x1f801558: - PSXHW_LOG("DMA12 SIO2out CHCR 32bit write %lx\n", value); - HW_DMA12_CHCR = value; // DMA12 chcr (SIO2 out) - DmaExec2(12); - return; - -//------------------------------------------------------------------ - case 0x1f801570: - psxHu32(0x1570) = value; - PSXHW_LOG("DMA PCR2 32bit write %lx\n", value); - return; - case 0x1f8010f0: - PSXHW_LOG("DMA PCR 32bit write %lx\n", value); - HW_DMA_PCR = value; - return; - - case 0x1f8010f4: - PSXHW_LOG("DMA ICR 32bit write %lx\n", value); - { - u32 tmp = (~value) & HW_DMA_ICR; - HW_DMA_ICR = ((tmp ^ value) & 0xffffff) ^ tmp; - } - return; - - case 0x1f801574: - PSXHW_LOG("DMA ICR2 32bit write %lx\n", value); - { - u32 tmp = (~value) & HW_DMA_ICR2; - HW_DMA_ICR2 = ((tmp ^ value) & 0xffffff) ^ tmp; - } - return; - -//------------------------------------------------------------------ -/* case 0x1f801810: - PSXHW_LOG("GPU DATA 32bit write %lx\n", value); - GPU_writeData(value); return; - case 0x1f801814: - PSXHW_LOG("GPU STATUS 32bit write %lx\n", value); - GPU_writeStatus(value); return; -*/ -/* case 0x1f801820: - mdecWrite0(value); break; - case 0x1f801824: - mdecWrite1(value); break; -*/ - case 0x1f801100: - PSXCNT_LOG("COUNTER 0 COUNT 32bit write %lx\n", value); - psxRcntWcount16(0, value ); return; - case 0x1f801104: - PSXCNT_LOG("COUNTER 0 MODE 32bit write %lx\n", value); - psxRcnt0Wmode(value); return; - case 0x1f801108: - PSXCNT_LOG("COUNTER 0 TARGET 32bit write %lx\n", value); - psxRcntWtarget16(0, value ); return; - - case 0x1f801110: - PSXCNT_LOG("COUNTER 1 COUNT 32bit write %lx\n", value); - psxRcntWcount16(1, value ); return; - case 0x1f801114: - PSXCNT_LOG("COUNTER 1 MODE 32bit write %lx\n", value); - psxRcnt1Wmode(value); return; - case 0x1f801118: - PSXCNT_LOG("COUNTER 1 TARGET 32bit write %lx\n", value); - psxRcntWtarget16(1, value ); return; - - case 0x1f801120: - PSXCNT_LOG("COUNTER 2 COUNT 32bit write %lx\n", value); - psxRcntWcount16(2, value ); return; - case 0x1f801124: - PSXCNT_LOG("COUNTER 2 MODE 32bit write %lx\n", value); - psxRcnt2Wmode(value); return; - case 0x1f801128: - PSXCNT_LOG("COUNTER 2 TARGET 32bit write %lx\n", value); - psxRcntWtarget16(2, value); return; - - case 0x1f801480: - PSXCNT_LOG("COUNTER 3 COUNT 32bit write %lx\n", value); - psxRcntWcount32(3, value); return; - case 0x1f801484: - PSXCNT_LOG("COUNTER 3 MODE 32bit write %lx\n", value); - psxRcnt3Wmode(value); return; - case 0x1f801488: - PSXCNT_LOG("COUNTER 3 TARGET 32bit write %lx\n", value); - psxRcntWtarget32(3, value); return; - - case 0x1f801490: - PSXCNT_LOG("COUNTER 4 COUNT 32bit write %lx\n", value); - psxRcntWcount32(4, value); return; - case 0x1f801494: - PSXCNT_LOG("COUNTER 4 MODE 32bit write %lx\n", value); - psxRcnt4Wmode(value); return; - case 0x1f801498: - PSXCNT_LOG("COUNTER 4 TARGET 32bit write %lx\n", value); - psxRcntWtarget32(4, value); return; - - case 0x1f8014a0: - PSXCNT_LOG("COUNTER 5 COUNT 32bit write %lx\n", value); - psxRcntWcount32(5, value); return; - case 0x1f8014a4: - PSXCNT_LOG("COUNTER 5 MODE 32bit write %lx\n", value); - psxRcnt5Wmode(value); return; - case 0x1f8014a8: - PSXCNT_LOG("COUNTER 5 TARGET 32bit write %lx\n", value); - psxRcntWtarget32(5, value); return; - -//------------------------------------------------------------------ - case 0x1f8014c0: - PSXHW_LOG("RTC_HOLDMODE 32bit write %lx\n", value); - Console::Notice("** RTC_HOLDMODE 32bit write %lx", params value); - break; - - case 0x1f801450: - if (value) { PSXHW_LOG("%08X ICFG 32bit write %lx\n", psxRegs.pc, value); } -/* if (value && - psxSu32(0x20) == 0x20000 && - (psxSu32(0x30) == 0x20000 || - psxSu32(0x30) == 0x40000)) { // don't ask me why :P - psxSu32(0x20) = 0x10000; - psxSu32(0x30) = 0x10000; - }*/ - psxHu32(0x1450) = /*(*/value/* & (~0x8)) | (psxHu32(0x1450) & 0x8)*/; - return; - -//------------------------------------------------------------------ - case 0x1F808200: - case 0x1F808204: - case 0x1F808208: - case 0x1F80820C: - case 0x1F808210: - case 0x1F808214: - case 0x1F808218: - case 0x1F80821C: - case 0x1F808220: - case 0x1F808224: - case 0x1F808228: - case 0x1F80822C: - case 0x1F808230: - case 0x1F808234: - case 0x1F808238: - case 0x1F80823C: - PSXHW_LOG("SIO2 write param[%d] <- %lx\n", (add-0x1F808200)/4, value); - sio2_setSend3((add-0x1F808200)/4, value); return; - - case 0x1F808240: - case 0x1F808248: - case 0x1F808250: - case 0x1F808258: - PSXHW_LOG("SIO2 write send1[%d] <- %lx\n", (add-0x1F808240)/8, value); - sio2_setSend1((add-0x1F808240)/8, value); return; - - case 0x1F808244: - case 0x1F80824C: - case 0x1F808254: - case 0x1F80825C: - PSXHW_LOG("SIO2 write send2[%d] <- %lx\n", (add-0x1F808244)/8, value); - sio2_setSend2((add-0x1F808244)/8, value); return; - - case 0x1F808268: - PSXHW_LOG("SIO2 write CTRL <- %lx\n", value); - sio2_setCtrl(value); return; - - case 0x1F808278: - PSXHW_LOG("SIO2 write [8278] <- %lx\n", value); - sio2_set8278(value); return; - - case 0x1F80827C: - PSXHW_LOG("SIO2 write [827C] <- %lx\n", value); - sio2_set827C(value); return; - - case 0x1F808280: - PSXHW_LOG("SIO2 write INTR <- %lx\n", value); - sio2_setIntr(value); return; - -//------------------------------------------------------------------ - default: - psxHu32(add) = value; - PSXHW_LOG("*Unknown 32bit write at address %lx value %lx\n", add, value); - return; - } - psxHu32(add) = value; - PSXHW_LOG("*Known 32bit write at address %lx value %lx\n", add, value); -} - -u8 psxHw4Read8(u32 add) { - u8 hard; - - switch (add) { - case 0x1f402004: return cdvdRead04(); - case 0x1f402005: return cdvdRead05(); - case 0x1f402006: return cdvdRead06(); - case 0x1f402007: return cdvdRead07(); - case 0x1f402008: return cdvdRead08(); - case 0x1f40200A: return cdvdRead0A(); - case 0x1f40200B: return cdvdRead0B(); - case 0x1f40200C: return cdvdRead0C(); - case 0x1f40200D: return cdvdRead0D(); - case 0x1f40200E: return cdvdRead0E(); - case 0x1f40200F: return cdvdRead0F(); - case 0x1f402013: return cdvdRead13(); - case 0x1f402015: return cdvdRead15(); - case 0x1f402016: return cdvdRead16(); - case 0x1f402017: return cdvdRead17(); - case 0x1f402018: return cdvdRead18(); - case 0x1f402020: return cdvdRead20(); - case 0x1f402021: return cdvdRead21(); - case 0x1f402022: return cdvdRead22(); - case 0x1f402023: return cdvdRead23(); - case 0x1f402024: return cdvdRead24(); - case 0x1f402028: return cdvdRead28(); - case 0x1f402029: return cdvdRead29(); - case 0x1f40202A: return cdvdRead2A(); - case 0x1f40202B: return cdvdRead2B(); - case 0x1f40202C: return cdvdRead2C(); - case 0x1f402030: return cdvdRead30(); - case 0x1f402031: return cdvdRead31(); - case 0x1f402032: return cdvdRead32(); - case 0x1f402033: return cdvdRead33(); - case 0x1f402034: return cdvdRead34(); - case 0x1f402038: return cdvdRead38(); - case 0x1f402039: return cdvdRead39(); - case 0x1f40203A: return cdvdRead3A(); - default: - // note: use SysPrintF to notify console since this is a potentially serious - // emulation problem: - //PSXHW_LOG("*Unknown 8bit read at address %lx\n", add); - SysPrintf("*Unknown 8bit read at address %lx\n", add); - return 0; - } - - PSXHW_LOG("*Known 8bit read at address %lx value %x\n", add, hard); - - return hard; -} - -void psxHw4Write8(u32 add, u8 value) { - - switch (add) { - case 0x1f402004: cdvdWrite04(value); return; - case 0x1f402005: cdvdWrite05(value); return; - case 0x1f402006: cdvdWrite06(value); return; - case 0x1f402007: cdvdWrite07(value); return; - case 0x1f402008: cdvdWrite08(value); return; - case 0x1f40200A: cdvdWrite0A(value); return; - case 0x1f40200F: cdvdWrite0F(value); return; - case 0x1f402014: cdvdWrite14(value); return; - case 0x1f402016: cdvdWrite16(value); return; - case 0x1f402017: cdvdWrite17(value); return; - case 0x1f402018: cdvdWrite18(value); return; - case 0x1f40203A: cdvdWrite3A(value); return; - default: - //PSXHW_LOG("*Unknown 8bit write at address %lx value %x\n", add, value); - Console::Notice("*Unknown 8bit write at address %lx value %x", params add, value); - return; - } - PSXHW_LOG("*Known 8bit write at address %lx value %x\n", add, value); -} - -void psxDmaInterrupt(int n) { - if (HW_DMA_ICR & (1 << (16 + n))) { - HW_DMA_ICR|= (1 << (24 + n)); - psxRegs.CP0.n.Cause |= 1 << (9 + n); - iopIntcIrq( 3 ); - } -} - -void psxDmaInterrupt2(int n) { - if (HW_DMA_ICR2 & (1 << (16 + n))) { -/* if (HW_DMA_ICR2 & (1 << (24 + n))) { - SysPrintf("*PCSX2*: HW_DMA_ICR2 n=%d already set\n", n); - } - if (psxHu32(0x1070) & 8) { - SysPrintf("*PCSX2*: psxHu32(0x1070) 8 already set (n=%d)\n", n); - }*/ - HW_DMA_ICR2|= (1 << (24 + n)); - psxRegs.CP0.n.Cause |= 1 << (16 + n); - iopIntcIrq( 3 ); - } -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "PsxCommon.h" +#include "Misc.h" +#include "iR5900.h" + +// NOTE: Any modifications to read/write fns should also go into their const counterparts +// found in iPsxHw.cpp. + +void psxHwReset() { +/* if (Config.Sio) psxHu32(0x1070) |= 0x80; + if (Config.SpuIrq) psxHu32(0x1070) |= 0x200;*/ + + memzero_ptr<0x10000>(psxH); + +// mdecInit(); //initialize mdec decoder + cdrReset(); + cdvdReset(); + psxRcntInit(); + sioInit(); + //sio2Reset(); +} + +u8 psxHwRead8(u32 add) { + u8 hard; + + if (add >= 0x1f801600 && add < 0x1f801700) { + return USBread8(add); + } + + switch (add) { + case 0x1f801040: hard = sioRead8();break; + // case 0x1f801050: hard = serial_read8(); break;//for use of serial port ignore for now + + case 0x1f80146e: // DEV9_R_REV + return DEV9read8(add); + +#ifdef PCSX2_DEVBUILD + case 0x1f801100: + case 0x1f801104: + case 0x1f801108: + case 0x1f801110: + case 0x1f801114: + case 0x1f801118: + case 0x1f801120: + case 0x1f801124: + case 0x1f801128: + case 0x1f801480: + case 0x1f801484: + case 0x1f801488: + case 0x1f801490: + case 0x1f801494: + case 0x1f801498: + case 0x1f8014a0: + case 0x1f8014a4: + case 0x1f8014a8: + SysPrintf("8bit counter read %x\n", add); + hard = psxHu8(add); + return hard; +#endif + + case 0x1f801800: hard = cdrRead0(); break; + case 0x1f801801: hard = cdrRead1(); break; + case 0x1f801802: hard = cdrRead2(); break; + case 0x1f801803: hard = cdrRead3(); break; + + case 0x1f803100: // PS/EE/IOP conf related + hard = 0x10; // Dram 2M + break; + + case 0x1F808264: + hard = sio2_fifoOut();//sio2 serial data feed/fifo_out + PSXHW_LOG("SIO2 read8 DATAOUT %08X\n", hard); + return hard; + + default: + hard = psxHu8(add); + PSXHW_LOG("*Unknown 8bit read at address %lx\n", add); + return hard; + } + + PSXHW_LOG("*Known 8bit read at address %lx value %x\n", add, hard); + return hard; +} + +u16 psxHwRead16(u32 add) { + u16 hard; + + if (add >= 0x1f801600 && add < 0x1f801700) { + return USBread16(add); + } + + switch (add) { + + case 0x1f801070: PSXHW_LOG("IREG 16bit read %x\n", psxHu16(0x1070)); + return psxHu16(0x1070); + case 0x1f801074: PSXHW_LOG("IMASK 16bit read %x\n", psxHu16(0x1074)); + return psxHu16(0x1074); + + case 0x1f801040: + hard = sioRead8(); + hard|= sioRead8() << 8; + PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); + return hard; + case 0x1f801044: + hard = sio.StatReg; + PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); + return hard; + case 0x1f801048: + hard = sio.ModeReg; + PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); + return hard; + case 0x1f80104a: + hard = sio.CtrlReg; + PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); + return hard; + case 0x1f80104e: + hard = sio.BaudReg; + PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); + return hard; + + //Serial port stuff not support now ;P + // case 0x1f801050: hard = serial_read16(); break; + // case 0x1f801054: hard = serial_status_read(); break; + // case 0x1f80105a: hard = serial_control_read(); break; + // case 0x1f80105e: hard = serial_baud_read(); break; + + case 0x1f801100: + hard = (u16)psxRcntRcount16(0); + PSXCNT_LOG("T0 count read16: %x\n", hard); + return hard; + case 0x1f801104: + hard = psxCounters[0].mode; + psxCounters[0].mode &= ~0x1800; + psxCounters[0].mode |= 0x400; + PSXCNT_LOG("T0 mode read16: %x\n", hard); + return hard; + case 0x1f801108: + hard = psxCounters[0].target; + PSXCNT_LOG("T0 target read16: %x\n", hard); + return hard; + case 0x1f801110: + hard = (u16)psxRcntRcount16(1); + PSXCNT_LOG("T1 count read16: %x\n", hard); + return hard; + case 0x1f801114: + hard = psxCounters[1].mode; + psxCounters[1].mode &= ~0x1800; + psxCounters[1].mode |= 0x400; + PSXCNT_LOG("T1 mode read16: %x\n", hard); + return hard; + case 0x1f801118: + hard = psxCounters[1].target; + PSXCNT_LOG("T1 target read16: %x\n", hard); + return hard; + case 0x1f801120: + hard = (u16)psxRcntRcount16(2); + PSXCNT_LOG("T2 count read16: %x\n", hard); + return hard; + case 0x1f801124: + hard = psxCounters[2].mode; + psxCounters[2].mode &= ~0x1800; + psxCounters[2].mode |= 0x400; + PSXCNT_LOG("T2 mode read16: %x\n", hard); + return hard; + case 0x1f801128: + hard = psxCounters[2].target; + PSXCNT_LOG("T2 target read16: %x\n", hard); + return hard; + + case 0x1f80146e: // DEV9_R_REV + return DEV9read16(add); + + case 0x1f801480: + hard = (u16)psxRcntRcount32(3); + PSXCNT_LOG("T3 count read16: %lx\n", hard); + return hard; + case 0x1f801484: + hard = psxCounters[3].mode; + psxCounters[3].mode &= ~0x1800; + psxCounters[3].mode |= 0x400; + PSXCNT_LOG("T3 mode read16: %lx\n", hard); + return hard; + case 0x1f801488: + hard = psxCounters[3].target; + PSXCNT_LOG("T3 target read16: %lx\n", hard); + return hard; + case 0x1f801490: + hard = (u16)psxRcntRcount32(4); + PSXCNT_LOG("T4 count read16: %lx\n", hard); + return hard; + case 0x1f801494: + hard = psxCounters[4].mode; + psxCounters[4].mode &= ~0x1800; + psxCounters[4].mode |= 0x400; + PSXCNT_LOG("T4 mode read16: %lx\n", hard); + return hard; + case 0x1f801498: + hard = psxCounters[4].target; + PSXCNT_LOG("T4 target read16: %lx\n", hard); + return hard; + case 0x1f8014a0: + hard = (u16)psxRcntRcount32(5); + PSXCNT_LOG("T5 count read16: %lx\n", hard); + return hard; + case 0x1f8014a4: + hard = psxCounters[5].mode; + psxCounters[5].mode &= ~0x1800; + psxCounters[5].mode |= 0x400; + PSXCNT_LOG("T5 mode read16: %lx\n", hard); + return hard; + case 0x1f8014a8: + hard = psxCounters[5].target; + PSXCNT_LOG("T5 target read16: %lx\n", hard); + return hard; + + case 0x1f801504: + hard = psxHu16(0x1504); + PSXHW_LOG("DMA7 BCR_size 16bit read %lx\n", hard); + return hard; + case 0x1f801506: + hard = psxHu16(0x1506); + PSXHW_LOG("DMA7 BCR_count 16bit read %lx\n", hard); + return hard; + //case 0x1f802030: hard = //int_2000???? + //case 0x1f802040: hard =//dip switches...?? + + default: + if (add>=0x1f801c00 && add<0x1f801e00) { + hard = SPU2read(add); + } else { + hard = psxHu16(add); + PSXHW_LOG("*Unknown 16bit read at address %lx\n", add); + } + return hard; + } + + + PSXHW_LOG("*Known 16bit read at address %lx value %x\n", add, hard); + return hard; +} + +u32 psxHwRead32(u32 add) { + u32 hard; + + if (add >= 0x1f801600 && add < 0x1f801700) { + return USBread32(add); + } + if (add >= 0x1f808400 && add <= 0x1f808550) {//the size is a complete guess.. + return FWread32(add); + } + + switch (add) { + case 0x1f801040: + hard = sioRead8(); + hard|= sioRead8() << 8; + hard|= sioRead8() << 16; + hard|= sioRead8() << 24; + PAD_LOG("sio read32 ;ret = %lx\n", hard); + return hard; + + // case 0x1f801050: hard = serial_read32(); break;//serial port + case 0x1f801060: + PSXHW_LOG("RAM size read %lx\n", psxHu32(0x1060)); + return psxHu32(0x1060); + case 0x1f801070: PSXHW_LOG("IREG 32bit read %x\n", psxHu32(0x1070)); + return psxHu32(0x1070); + case 0x1f801074: PSXHW_LOG("IMASK 32bit read %x\n", psxHu32(0x1074)); + return psxHu32(0x1074); + case 0x1f801078: + PSXHW_LOG("ICTRL 32bit read %x\n", psxHu32(0x1078)); + hard = psxHu32(0x1078); + psxHu32(0x1078) = 0; + return hard; + +/* case 0x1f801810: +// hard = GPU_readData(); + PSXHW_LOG("GPU DATA 32bit read %lx\n", hard); + return hard;*/ +/* case 0x1f801814: + hard = GPU_readStatus(); + PSXHW_LOG("GPU STATUS 32bit read %lx\n", hard); + return hard; +*/ +/* case 0x1f801820: hard = mdecRead0(); break; + case 0x1f801824: hard = mdecRead1(); break; +*/ + + case 0x1f8010a0: + PSXHW_LOG("DMA2 MADR 32bit read %lx\n", psxHu32(0x10a0)); + return HW_DMA2_MADR; + case 0x1f8010a4: + PSXHW_LOG("DMA2 BCR 32bit read %lx\n", psxHu32(0x10a4)); + return HW_DMA2_BCR; + case 0x1f8010a8: + PSXHW_LOG("DMA2 CHCR 32bit read %lx\n", psxHu32(0x10a8)); + return HW_DMA2_CHCR; + + case 0x1f8010b0: + PSXHW_LOG("DMA3 MADR 32bit read %lx\n", psxHu32(0x10b0)); + return HW_DMA3_MADR; + case 0x1f8010b4: + PSXHW_LOG("DMA3 BCR 32bit read %lx\n", psxHu32(0x10b4)); + return HW_DMA3_BCR; + case 0x1f8010b8: + PSXHW_LOG("DMA3 CHCR 32bit read %lx\n", psxHu32(0x10b8)); + return HW_DMA3_CHCR; + + case 0x1f801520: + PSXHW_LOG("DMA9 MADR 32bit read %lx\n", HW_DMA9_MADR); + return HW_DMA9_MADR; + case 0x1f801524: + PSXHW_LOG("DMA9 BCR 32bit read %lx\n", HW_DMA9_BCR); + return HW_DMA9_BCR; + case 0x1f801528: + PSXHW_LOG("DMA9 CHCR 32bit read %lx\n", HW_DMA9_CHCR); + return HW_DMA9_CHCR; + case 0x1f80152C: + PSXHW_LOG("DMA9 TADR 32bit read %lx\n", HW_DMA9_TADR); + return HW_DMA9_TADR; + + case 0x1f801530: + PSXHW_LOG("DMA10 MADR 32bit read %lx\n", HW_DMA10_MADR); + return HW_DMA10_MADR; + case 0x1f801534: + PSXHW_LOG("DMA10 BCR 32bit read %lx\n", HW_DMA10_BCR); + return HW_DMA10_BCR; + case 0x1f801538: + PSXHW_LOG("DMA10 CHCR 32bit read %lx\n", HW_DMA10_CHCR); + return HW_DMA10_CHCR; + +// case 0x1f8010f0: PSXHW_LOG("DMA PCR 32bit read " << psxHu32(0x10f0)); +// return HW_DMA_PCR; // dma rest channel + + case 0x1f8010f4: + PSXHW_LOG("DMA ICR 32bit read %lx\n", HW_DMA_ICR); + return HW_DMA_ICR; + +//SSBus registers + case 0x1f801000: + hard = psxHu32(0x1000); + PSXHW_LOG("SSBUS 32bit read %lx\n", hard); + return hard; + case 0x1f801004: + hard = psxHu32(0x1004); + PSXHW_LOG("SSBUS 32bit read %lx\n", hard); + return hard; + case 0x1f801008: + hard = psxHu32(0x1008); + PSXHW_LOG("SSBUS 32bit read %lx\n", hard); + return hard; + case 0x1f80100C: + hard = psxHu32(0x100C); + PSXHW_LOG("SSBUS dev1_delay 32bit read %lx\n", hard); + return hard; + case 0x1f801010: + hard = psxHu32(0x1010); + PSXHW_LOG("SSBUS rom_delay 32bit read %lx\n", hard); + return hard; + case 0x1f801014: + hard = psxHu32(0x1014); + PSXHW_LOG("SSBUS spu_delay 32bit read %lx\n", hard); + return hard; + case 0x1f801018: + hard = psxHu32(0x1018); + PSXHW_LOG("SSBUS dev5_delay 32bit read %lx\n", hard); + return hard; + case 0x1f80101C: + hard = psxHu32(0x101C); + PSXHW_LOG("SSBUS 32bit read %lx\n", hard); + return hard; + case 0x1f801020: + hard = psxHu32(0x1020); + PSXHW_LOG("SSBUS com_delay 32bit read %lx\n", hard); + return hard; + case 0x1f801400: + hard = psxHu32(0x1400); + PSXHW_LOG("SSBUS dev1_addr 32bit read %lx\n", hard); + return hard; + case 0x1f801404: + hard = psxHu32(0x1404); + PSXHW_LOG("SSBUS spu_addr 32bit read %lx\n", hard); + return hard; + case 0x1f801408: + hard = psxHu32(0x1408); + PSXHW_LOG("SSBUS dev5_addr 32bit read %lx\n", hard); + return hard; + case 0x1f80140C: + hard = psxHu32(0x140C); + PSXHW_LOG("SSBUS spu1_addr 32bit read %lx\n", hard); + return hard; + case 0x1f801410: + hard = psxHu32(0x1410); + PSXHW_LOG("SSBUS 32bit read %lx\n", hard); + return hard; + case 0x1f801414: + hard = psxHu32(0x1414); + PSXHW_LOG("SSBUS spu1_delay 32bit read %lx\n", hard); + return hard; + case 0x1f801418: + hard = psxHu32(0x1418); + PSXHW_LOG("SSBUS 32bit read %lx\n", hard); + return hard; + case 0x1f80141C: + hard = psxHu32(0x141C); + PSXHW_LOG("SSBUS 32bit read %lx\n", hard); + return hard; + case 0x1f801420: + hard = psxHu32(0x1420); + PSXHW_LOG("SSBUS 32bit read %lx\n", hard); + return hard; + + case 0x1f8010f0: + PSXHW_LOG("DMA PCR 32bit read %lx\n", HW_DMA_PCR); + return HW_DMA_PCR; + + case 0x1f8010c8: + PSXHW_LOG("DMA4 CHCR 32bit read %lx\n", HW_DMA4_CHCR); + return HW_DMA4_CHCR; // DMA4 chcr (SPU DMA) + + // time for rootcounters :) + case 0x1f801100: + hard = (u16)psxRcntRcount16(0); + PSXCNT_LOG("T0 count read32: %lx\n", hard); + return hard; + case 0x1f801104: + hard = (u16)psxCounters[0].mode; + PSXCNT_LOG("T0 mode read32: %lx\n", hard); + return hard; + case 0x1f801108: + hard = psxCounters[0].target; + PSXCNT_LOG("T0 target read32: %lx\n", hard); + return hard; + case 0x1f801110: + hard = (u16)psxRcntRcount16(1); + PSXCNT_LOG("T1 count read32: %lx\n", hard); + return hard; + case 0x1f801114: + hard = (u16)psxCounters[1].mode; + PSXCNT_LOG("T1 mode read32: %lx\n", hard); + return hard; + case 0x1f801118: + hard = psxCounters[1].target; + PSXCNT_LOG("T1 target read32: %lx\n", hard); + return hard; + case 0x1f801120: + hard = (u16)psxRcntRcount16(2); + PSXCNT_LOG("T2 count read32: %lx\n", hard); + return hard; + case 0x1f801124: + hard = (u16)psxCounters[2].mode; + PSXCNT_LOG("T2 mode read32: %lx\n", hard); + return hard; + case 0x1f801128: + hard = psxCounters[2].target; + PSXCNT_LOG("T2 target read32: %lx\n", hard); + return hard; + + case 0x1f801480: + hard = (u32)psxRcntRcount32(3); + PSXCNT_LOG("T3 count read32: %lx\n", hard); + return hard; + case 0x1f801484: + hard = (u16)psxCounters[3].mode; + PSXCNT_LOG("T3 mode read32: %lx\n", hard); + return hard; + case 0x1f801488: + hard = psxCounters[3].target; + PSXCNT_LOG("T3 target read32: %lx\n", hard); + return hard; + case 0x1f801490: + hard = (u32)psxRcntRcount32(4); + PSXCNT_LOG("T4 count read32: %lx\n", hard); + return hard; + case 0x1f801494: + hard = (u16)psxCounters[4].mode; + PSXCNT_LOG("T4 mode read32: %lx\n", hard); + return hard; + case 0x1f801498: + hard = psxCounters[4].target; + PSXCNT_LOG("T4 target read32: %lx\n", hard); + return hard; + case 0x1f8014a0: + hard = (u32)psxRcntRcount32(5); + PSXCNT_LOG("T5 count read32: %lx\n", hard); + return hard; + case 0x1f8014a4: + hard = (u16)psxCounters[5].mode; + PSXCNT_LOG("T5 mode read32: %lx\n", hard); + return hard; + case 0x1f8014a8: + hard = psxCounters[5].target; + PSXCNT_LOG("T5 target read32: %lx\n", hard); + return hard; + + case 0x1f801450: + hard = psxHu32(add); + PSXHW_LOG("%08X ICFG 32bit read %x\n", psxRegs.pc, hard); + return hard; + + + case 0x1F8010C0: + HW_DMA4_MADR = SPU2ReadMemAddr(0); + return HW_DMA4_MADR; + + case 0x1f801500: + HW_DMA7_MADR = SPU2ReadMemAddr(1); + PSXHW_LOG("DMA7 MADR 32bit read %lx\n", HW_DMA7_MADR); + return HW_DMA7_MADR; // DMA7 madr + case 0x1f801504: + PSXHW_LOG("DMA7 BCR 32bit read %lx\n", HW_DMA7_BCR); + return HW_DMA7_BCR; // DMA7 bcr + + case 0x1f801508: + PSXHW_LOG("DMA7 CHCR 32bit read %lx\n", HW_DMA7_CHCR); + return HW_DMA7_CHCR; // DMA7 chcr (SPU2) + + case 0x1f801570: + hard = psxHu32(0x1570); + PSXHW_LOG("DMA PCR2 32bit read %lx\n", hard); + return hard; + case 0x1f801574: + PSXHW_LOG("DMA ICR2 32bit read %lx\n", HW_DMA_ICR2); + return HW_DMA_ICR2; + + case 0x1F808200: + case 0x1F808204: + case 0x1F808208: + case 0x1F80820C: + case 0x1F808210: + case 0x1F808214: + case 0x1F808218: + case 0x1F80821C: + case 0x1F808220: + case 0x1F808224: + case 0x1F808228: + case 0x1F80822C: + case 0x1F808230: + case 0x1F808234: + case 0x1F808238: + case 0x1F80823C: + hard=sio2_getSend3((add-0x1F808200)/4); + PSXHW_LOG("SIO2 read param[%d] (%lx)\n", (add-0x1F808200)/4, hard); + return hard; + + case 0x1F808240: + case 0x1F808248: + case 0x1F808250: + case 0x1F80825C: + hard=sio2_getSend1((add-0x1F808240)/8); + PSXHW_LOG("SIO2 read send1[%d] (%lx)\n", (add-0x1F808240)/8, hard); + return hard; + + case 0x1F808244: + case 0x1F80824C: + case 0x1F808254: + case 0x1F808258: + hard=sio2_getSend2((add-0x1F808244)/8); + PSXHW_LOG("SIO2 read send2[%d] (%lx)\n", (add-0x1F808244)/8, hard); + return hard; + + case 0x1F808268: + hard=sio2_getCtrl(); + PSXHW_LOG("SIO2 read CTRL (%lx)\n", hard); + return hard; + + case 0x1F80826C: + hard=sio2_getRecv1(); + PSXHW_LOG("SIO2 read Recv1 (%lx)\n", hard); + return hard; + + case 0x1F808270: + hard=sio2_getRecv2(); + PSXHW_LOG("SIO2 read Recv2 (%lx)\n", hard); + return hard; + + case 0x1F808274: + hard=sio2_getRecv3(); + PSXHW_LOG("SIO2 read Recv3 (%lx)\n", hard); + return hard; + + case 0x1F808278: + hard=sio2_get8278(); + PSXHW_LOG("SIO2 read [8278] (%lx)\n", hard); + return hard; + + case 0x1F80827C: + hard=sio2_get827C(); + PSXHW_LOG("SIO2 read [827C] (%lx)\n", hard); + return hard; + + case 0x1F808280: + hard=sio2_getIntr(); + PSXHW_LOG("SIO2 read INTR (%lx)\n", hard); + return hard; + + default: + hard = psxHu32(add); + PSXHW_LOG("*Unknown 32bit read at address %lx: %lx\n", add, hard); + return hard; + } + PSXHW_LOG("*Known 32bit read at address %lx: %lx\n", add, hard); + return hard; +} + +int g_pbufi; +s8 g_pbuf[1024]; + +#define DmaExec(n) { \ + if (HW_DMA##n##_CHCR & 0x01000000 && \ + HW_DMA_PCR & (8 << (n * 4))) { \ + psxDma##n(HW_DMA##n##_MADR, HW_DMA##n##_BCR, HW_DMA##n##_CHCR); \ + } \ +} + +void psxHwWrite8(u32 add, u8 value) { + if (add >= 0x1f801600 && add < 0x1f801700) { + USBwrite8(add, value); return; + } + if((add & 0xf) == 0xa) SysPrintf("8bit write (possible chcr set) %x value %x\n", add, value); + switch (add) { + case 0x1f801040: + sioWrite8(value); + break; + // case 0x1f801050: serial_write8(value); break;//serial port + + case 0x1f801100: + case 0x1f801104: + case 0x1f801108: + case 0x1f801110: + case 0x1f801114: + case 0x1f801118: + case 0x1f801120: + case 0x1f801124: + case 0x1f801128: + case 0x1f801480: + case 0x1f801484: + case 0x1f801488: + case 0x1f801490: + case 0x1f801494: + case 0x1f801498: + case 0x1f8014a0: + case 0x1f8014a4: + case 0x1f8014a8: + SysPrintf("8bit counter write %x\n", add); + psxHu8(add) = value; + return; + case 0x1f801450: + if (value) { PSXHW_LOG("%08X ICFG 8bit write %lx\n", psxRegs.pc, value); } + psxHu8(0x1450) = value; + return; + + case 0x1f801800: cdrWrite0(value); break; + case 0x1f801801: cdrWrite1(value); break; + case 0x1f801802: cdrWrite2(value); break; + case 0x1f801803: cdrWrite3(value); break; + + case 0x1f80380c: + if (value == '\r') break; + if (value == '\n' || g_pbufi >= 1023) { + g_pbuf[g_pbufi++] = 0; g_pbufi = 0; + SysPrintf("%s\n", g_pbuf); + } + else g_pbuf[g_pbufi++] = value; + psxHu8(add) = value; + return; + + case 0x1F808260: + PSXHW_LOG("SIO2 write8 DATAIN <- %08X\n", value); + sio2_serialIn(value);return;//serial data feed/fifo + + default: + psxHu8(add) = value; + PSXHW_LOG("*Unknown 8bit write at address %lx value %x\n", add, value); + return; + } + psxHu8(add) = value; + PSXHW_LOG("*Known 8bit write at address %lx value %x\n", add, value); +} + +void psxHwWrite16(u32 add, u16 value) { + if (add >= 0x1f801600 && add < 0x1f801700) { + USBwrite16(add, value); return; + } + + if((add & 0xf) == 0x9) DevCon::WriteLn("16bit write (possible chcr set) %x value %x", params add, value); + + switch (add) { + case 0x1f801040: + sioWrite8((u8)value); + sioWrite8((u8)(value>>8)); + PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); + return; + case 0x1f801044: + PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); + return; + case 0x1f801048: + sio.ModeReg = value; + PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); + return; + case 0x1f80104a: // control register + sioWriteCtrl16(value); + PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); + return; + case 0x1f80104e: // baudrate register + sio.BaudReg = value; + PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); + return; + + //serial port ;P + // case 0x1f801050: serial_write16(value); break; + // case 0x1f80105a: serial_control_write(value);break; + // case 0x1f80105e: serial_baud_write(value); break; + // case 0x1f801054: serial_status_write(value); break; + + case 0x1f801070: + PSXHW_LOG("IREG 16bit write %x\n", value); +// if (Config.Sio) psxHu16(0x1070) |= 0x80; +// if (Config.SpuIrq) psxHu16(0x1070) |= 0x200; + psxHu16(0x1070) &= value; + return; + + case 0x1f801074: + PSXHW_LOG("IMASK 16bit write %x\n", value); + psxHu16(0x1074) = value; + iopTestIntc(); + return; + + case 0x1f801078: // see the 32-bit version for notes! + PSXHW_LOG("ICTRL 16bit write %x\n", value); + psxHu16(0x1078) = value; + iopTestIntc(); + return; + + case 0x1f8010c4: + PSXHW_LOG("DMA4 BCR_size 16bit write %lx\n", value); + psxHu16(0x10c4) = value; + return; // DMA4 bcr_size + + case 0x1f8010c6: + PSXHW_LOG("DMA4 BCR_count 16bit write %lx\n", value); + psxHu16(0x10c6) = value; return; // DMA4 bcr_count + + case 0x1f801100: + PSXCNT_LOG("COUNTER 0 COUNT 16bit write %x\n", value); + psxRcntWcount16(0, value); return; + case 0x1f801104: + PSXCNT_LOG("COUNTER 0 MODE 16bit write %x\n", value); + psxRcnt0Wmode(value); return; + case 0x1f801108: + PSXCNT_LOG("COUNTER 0 TARGET 16bit write %x\n", value); + psxRcntWtarget16(0, value); return; + + case 0x1f801110: + PSXCNT_LOG("COUNTER 1 COUNT 16bit write %x\n", value); + psxRcntWcount16(1, value); return; + case 0x1f801114: + PSXCNT_LOG("COUNTER 1 MODE 16bit write %x\n", value); + psxRcnt1Wmode(value); return; + case 0x1f801118: + PSXCNT_LOG("COUNTER 1 TARGET 16bit write %x\n", value); + psxRcntWtarget16(1, value); return; + + case 0x1f801120: + PSXCNT_LOG("COUNTER 2 COUNT 16bit write %x\n", value); + psxRcntWcount16(2, value); return; + case 0x1f801124: + PSXCNT_LOG("COUNTER 2 MODE 16bit write %x\n", value); + psxRcnt2Wmode(value); return; + case 0x1f801128: + PSXCNT_LOG("COUNTER 2 TARGET 16bit write %x\n", value); + psxRcntWtarget16(2, value); return; + + case 0x1f801450: + if (value) { PSXHW_LOG("%08X ICFG 16bit write %lx\n", psxRegs.pc, value); } + psxHu16(0x1450) = value/* & (~0x8)*/; + return; + + case 0x1f801480: + PSXCNT_LOG("COUNTER 3 COUNT 16bit write %lx\n", value); + psxRcntWcount32(3, value); return; + case 0x1f801484: + PSXCNT_LOG("COUNTER 3 MODE 16bit write %lx\n", value); + psxRcnt3Wmode(value); return; + case 0x1f801488: + PSXCNT_LOG("COUNTER 3 TARGET 16bit write %lx\n", value); + psxRcntWtarget32(3, value); return; + + case 0x1f801490: + PSXCNT_LOG("COUNTER 4 COUNT 16bit write %lx\n", value); + psxRcntWcount32(4, value); return; + case 0x1f801494: + PSXCNT_LOG("COUNTER 4 MODE 16bit write %lx\n", value); + psxRcnt4Wmode(value); return; + case 0x1f801498: + PSXCNT_LOG("COUNTER 4 TARGET 16bit write %lx\n", value); + psxRcntWtarget32(4, value); return; + + case 0x1f8014a0: + PSXCNT_LOG("COUNTER 5 COUNT 16bit write %lx\n", value); + psxRcntWcount32(5, value); return; + case 0x1f8014a4: + PSXCNT_LOG("COUNTER 5 MODE 16bit write %lx\n", value); + psxRcnt5Wmode(value); return; + case 0x1f8014a8: + PSXCNT_LOG("COUNTER 5 TARGET 16bit write %lx\n", value); + psxRcntWtarget32(5, value); return; + + case 0x1f801504: + psxHu16(0x1504) = value; + PSXHW_LOG("DMA7 BCR_size 16bit write %lx\n", value); + return; + case 0x1f801506: + psxHu16(0x1506) = value; + PSXHW_LOG("DMA7 BCR_count 16bit write %lx\n", value); + return; + default: + if (add>=0x1f801c00 && add<0x1f801e00) { + SPU2write(add, value); + return; + } + + psxHu16(add) = value; + PSXHW_LOG("*Unknown 16bit write at address %lx value %x\n", add, value); + return; + } + psxHu16(add) = value; + PSXHW_LOG("*Known 16bit write at address %lx value %x\n", add, value); +} + +#define DmaExec2(n) { \ + if (HW_DMA##n##_CHCR & 0x01000000 && \ + HW_DMA_PCR2 & (8 << ((n-7) * 4))) { \ + psxDma##n(HW_DMA##n##_MADR, HW_DMA##n##_BCR, HW_DMA##n##_CHCR); \ + } \ +} + +void psxHwWrite32(u32 add, u32 value) { + if (add >= 0x1f801600 && add < 0x1f801700) { + USBwrite32(add, value); return; + } + if (add >= 0x1f808400 && add <= 0x1f808550) { + FWwrite32(add, value); return; + } + switch (add) { + case 0x1f801040: + sioWrite8((u8)value); + sioWrite8((u8)((value&0xff) >> 8)); + sioWrite8((u8)((value&0xff) >> 16)); + sioWrite8((u8)((value&0xff) >> 24)); + PAD_LOG("sio write32 %lx\n", value); + return; + // case 0x1f801050: serial_write32(value); break;//serial port + case 0x1f801060: + PSXHW_LOG("RAM size write %lx\n", value); + psxHu32(add) = value; + return; // Ram size + +//------------------------------------------------------------------ + case 0x1f801070: + PSXHW_LOG("IREG 32bit write %lx\n", value); +// if (Config.Sio) psxHu32(0x1070) |= 0x80; +// if (Config.SpuIrq) psxHu32(0x1070) |= 0x200; + psxHu32(0x1070) &= value; + return; + + case 0x1f801074: + PSXHW_LOG("IMASK 32bit write %lx\n", value); + psxHu32(0x1074) = value; + iopTestIntc(); + return; + + case 0x1f801078: + PSXHW_LOG("ICTRL 32bit write %lx\n", value); + psxHu32(0x1078) = value; //1; //According to pSXAuthor this allways becomes 1 on write, but MHPB won't boot if value is not writen ;p + iopTestIntc(); + return; + +//------------------------------------------------------------------ + //SSBus registers + case 0x1f801000: + psxHu32(0x1000) = value; + PSXHW_LOG("SSBUS 32bit write %lx\n", value); + return; + case 0x1f801004: + psxHu32(0x1004) = value; + PSXHW_LOG("SSBUS 32bit write %lx\n", value); + return; + case 0x1f801008: + psxHu32(0x1008) = value; + PSXHW_LOG("SSBUS 32bit write %lx\n", value); + return; + case 0x1f80100C: + psxHu32(0x100C) = value; + PSXHW_LOG("SSBUS dev1_delay 32bit write %lx\n", value); + return; + case 0x1f801010: + psxHu32(0x1010) = value; + PSXHW_LOG("SSBUS rom_delay 32bit write %lx\n", value); + return; + case 0x1f801014: + psxHu32(0x1014) = value; + PSXHW_LOG("SSBUS spu_delay 32bit write %lx\n", value); + return; + case 0x1f801018: + psxHu32(0x1018) = value; + PSXHW_LOG("SSBUS dev5_delay 32bit write %lx\n", value); + return; + case 0x1f80101C: + psxHu32(0x101C) = value; + PSXHW_LOG("SSBUS 32bit write %lx\n", value); + return; + case 0x1f801020: + psxHu32(0x1020) = value; + PSXHW_LOG("SSBUS com_delay 32bit write %lx\n", value); + return; + case 0x1f801400: + psxHu32(0x1400) = value; + PSXHW_LOG("SSBUS dev1_addr 32bit write %lx\n", value); + return; + case 0x1f801404: + psxHu32(0x1404) = value; + PSXHW_LOG("SSBUS spu_addr 32bit write %lx\n", value); + return; + case 0x1f801408: + psxHu32(0x1408) = value; + PSXHW_LOG("SSBUS dev5_addr 32bit write %lx\n", value); + return; + case 0x1f80140C: + psxHu32(0x140C) = value; + PSXHW_LOG("SSBUS spu1_addr 32bit write %lx\n", value); + return; + case 0x1f801410: + psxHu32(0x1410) = value; + PSXHW_LOG("SSBUS 32bit write %lx\n", value); + return; + case 0x1f801414: + psxHu32(0x1414) = value; + PSXHW_LOG("SSBUS spu1_delay 32bit write %lx\n", value); + return; + case 0x1f801418: + psxHu32(0x1418) = value; + PSXHW_LOG("SSBUS 32bit write %lx\n", value); + return; + case 0x1f80141C: + psxHu32(0x141C) = value; + PSXHW_LOG("SSBUS 32bit write %lx\n", value); + return; + case 0x1f801420: + psxHu32(0x1420) = value; + PSXHW_LOG("SSBUS 32bit write %lx\n", value); + return; + +//------------------------------------------------------------------ + case 0x1f801080: + PSXHW_LOG("DMA0 MADR 32bit write %lx\n", value); + HW_DMA0_MADR = value; return; // DMA0 madr + case 0x1f801084: + PSXHW_LOG("DMA0 BCR 32bit write %lx\n", value); + HW_DMA0_BCR = value; return; // DMA0 bcr + case 0x1f801088: + PSXHW_LOG("DMA0 CHCR 32bit write %lx\n", value); + HW_DMA0_CHCR = value; // DMA0 chcr (MDEC in DMA) +// DmaExec(0); + return; + +//------------------------------------------------------------------ + case 0x1f801090: + PSXHW_LOG("DMA1 MADR 32bit write %lx\n", value); + HW_DMA1_MADR = value; return; // DMA1 madr + case 0x1f801094: + PSXHW_LOG("DMA1 BCR 32bit write %lx\n", value); + HW_DMA1_BCR = value; return; // DMA1 bcr + case 0x1f801098: + PSXHW_LOG("DMA1 CHCR 32bit write %lx\n", value); + HW_DMA1_CHCR = value; // DMA1 chcr (MDEC out DMA) +// DmaExec(1); + return; + +//------------------------------------------------------------------ + case 0x1f8010a0: + PSXHW_LOG("DMA2 MADR 32bit write %lx\n", value); + HW_DMA2_MADR = value; return; // DMA2 madr + case 0x1f8010a4: + PSXHW_LOG("DMA2 BCR 32bit write %lx\n", value); + HW_DMA2_BCR = value; return; // DMA2 bcr + case 0x1f8010a8: + PSXHW_LOG("DMA2 CHCR 32bit write %lx\n", value); + HW_DMA2_CHCR = value; // DMA2 chcr (GPU DMA) + DmaExec(2); + return; + +//------------------------------------------------------------------ + case 0x1f8010b0: + PSXHW_LOG("DMA3 MADR 32bit write %lx\n", value); + HW_DMA3_MADR = value; return; // DMA3 madr + case 0x1f8010b4: + PSXHW_LOG("DMA3 BCR 32bit write %lx\n", value); + HW_DMA3_BCR = value; return; // DMA3 bcr + case 0x1f8010b8: + PSXHW_LOG("DMA3 CHCR 32bit write %lx\n", value); + HW_DMA3_CHCR = value; // DMA3 chcr (CDROM DMA) + DmaExec(3); + + return; + +//------------------------------------------------------------------ + case 0x1f8010c0: + PSXHW_LOG("DMA4 MADR 32bit write %lx\n", value); + SPU2WriteMemAddr(0,value); + HW_DMA4_MADR = value; return; // DMA4 madr + case 0x1f8010c4: + PSXHW_LOG("DMA4 BCR 32bit write %lx\n", value); + HW_DMA4_BCR = value; return; // DMA4 bcr + case 0x1f8010c8: + PSXHW_LOG("DMA4 CHCR 32bit write %lx\n", value); + HW_DMA4_CHCR = value; // DMA4 chcr (SPU DMA) + DmaExec(4); + return; + +//------------------------------------------------------------------ +#if 0 + case 0x1f8010d0: break; //DMA5write_madr(); + case 0x1f8010d4: break; //DMA5write_bcr(); + case 0x1f8010d8: break; //DMA5write_chcr(); // Not yet needed?? +#endif + + case 0x1f8010e0: + PSXHW_LOG("DMA6 MADR 32bit write %lx\n", value); + HW_DMA6_MADR = value; return; // DMA6 madr + case 0x1f8010e4: + PSXHW_LOG("DMA6 BCR 32bit write %lx\n", value); + HW_DMA6_BCR = value; return; // DMA6 bcr + case 0x1f8010e8: + PSXHW_LOG("DMA6 CHCR 32bit write %lx\n", value); + HW_DMA6_CHCR = value; // DMA6 chcr (OT clear) + DmaExec(6); + return; + +//------------------------------------------------------------------ + case 0x1f801500: + PSXHW_LOG("DMA7 MADR 32bit write %lx\n", value); + SPU2WriteMemAddr(1,value); + HW_DMA7_MADR = value; return; // DMA7 madr + case 0x1f801504: + PSXHW_LOG("DMA7 BCR 32bit write %lx\n", value); + HW_DMA7_BCR = value; return; // DMA7 bcr + case 0x1f801508: + PSXHW_LOG("DMA7 CHCR 32bit write %lx\n", value); + HW_DMA7_CHCR = value; // DMA7 chcr (SPU2) + DmaExec2(7); + return; + +//------------------------------------------------------------------ + case 0x1f801510: + PSXHW_LOG("DMA8 MADR 32bit write %lx\n", value); + HW_DMA8_MADR = value; return; // DMA8 madr + case 0x1f801514: + PSXHW_LOG("DMA8 BCR 32bit write %lx\n", value); + HW_DMA8_BCR = value; return; // DMA8 bcr + case 0x1f801518: + PSXHW_LOG("DMA8 CHCR 32bit write %lx\n", value); + HW_DMA8_CHCR = value; // DMA8 chcr (DEV9) + DmaExec2(8); + return; + +//------------------------------------------------------------------ + case 0x1f801520: + PSXHW_LOG("DMA9 MADR 32bit write %lx\n", value); + HW_DMA9_MADR = value; return; // DMA9 madr + case 0x1f801524: + PSXHW_LOG("DMA9 BCR 32bit write %lx\n", value); + HW_DMA9_BCR = value; return; // DMA9 bcr + case 0x1f801528: + PSXHW_LOG("DMA9 CHCR 32bit write %lx\n", value); + HW_DMA9_CHCR = value; // DMA9 chcr (SIF0) + DmaExec2(9); + return; + case 0x1f80152c: + PSXHW_LOG("DMA9 TADR 32bit write %lx\n", value); + HW_DMA9_TADR = value; return; // DMA9 tadr + +//------------------------------------------------------------------ + case 0x1f801530: + PSXHW_LOG("DMA10 MADR 32bit write %lx\n", value); + HW_DMA10_MADR = value; return; // DMA10 madr + case 0x1f801534: + PSXHW_LOG("DMA10 BCR 32bit write %lx\n", value); + HW_DMA10_BCR = value; return; // DMA10 bcr + case 0x1f801538: + PSXHW_LOG("DMA10 CHCR 32bit write %lx\n", value); + HW_DMA10_CHCR = value; // DMA10 chcr (SIF1) + DmaExec2(10); + return; + +//------------------------------------------------------------------ + case 0x1f801540: + PSXHW_LOG("DMA11 SIO2in MADR 32bit write %lx\n", value); + HW_DMA11_MADR = value; return; + + case 0x1f801544: + PSXHW_LOG("DMA11 SIO2in BCR 32bit write %lx\n", value); + HW_DMA11_BCR = value; return; + case 0x1f801548: + PSXHW_LOG("DMA11 SIO2in CHCR 32bit write %lx\n", value); + HW_DMA11_CHCR = value; // DMA11 chcr (SIO2 in) + DmaExec2(11); + return; + +//------------------------------------------------------------------ + case 0x1f801550: + PSXHW_LOG("DMA12 SIO2out MADR 32bit write %lx\n", value); + HW_DMA12_MADR = value; return; + + case 0x1f801554: + PSXHW_LOG("DMA12 SIO2out BCR 32bit write %lx\n", value); + HW_DMA12_BCR = value; return; + case 0x1f801558: + PSXHW_LOG("DMA12 SIO2out CHCR 32bit write %lx\n", value); + HW_DMA12_CHCR = value; // DMA12 chcr (SIO2 out) + DmaExec2(12); + return; + +//------------------------------------------------------------------ + case 0x1f801570: + psxHu32(0x1570) = value; + PSXHW_LOG("DMA PCR2 32bit write %lx\n", value); + return; + case 0x1f8010f0: + PSXHW_LOG("DMA PCR 32bit write %lx\n", value); + HW_DMA_PCR = value; + return; + + case 0x1f8010f4: + PSXHW_LOG("DMA ICR 32bit write %lx\n", value); + { + u32 tmp = (~value) & HW_DMA_ICR; + HW_DMA_ICR = ((tmp ^ value) & 0xffffff) ^ tmp; + } + return; + + case 0x1f801574: + PSXHW_LOG("DMA ICR2 32bit write %lx\n", value); + { + u32 tmp = (~value) & HW_DMA_ICR2; + HW_DMA_ICR2 = ((tmp ^ value) & 0xffffff) ^ tmp; + } + return; + +//------------------------------------------------------------------ +/* case 0x1f801810: + PSXHW_LOG("GPU DATA 32bit write %lx\n", value); + GPU_writeData(value); return; + case 0x1f801814: + PSXHW_LOG("GPU STATUS 32bit write %lx\n", value); + GPU_writeStatus(value); return; +*/ +/* case 0x1f801820: + mdecWrite0(value); break; + case 0x1f801824: + mdecWrite1(value); break; +*/ + case 0x1f801100: + PSXCNT_LOG("COUNTER 0 COUNT 32bit write %lx\n", value); + psxRcntWcount16(0, value ); return; + case 0x1f801104: + PSXCNT_LOG("COUNTER 0 MODE 32bit write %lx\n", value); + psxRcnt0Wmode(value); return; + case 0x1f801108: + PSXCNT_LOG("COUNTER 0 TARGET 32bit write %lx\n", value); + psxRcntWtarget16(0, value ); return; + + case 0x1f801110: + PSXCNT_LOG("COUNTER 1 COUNT 32bit write %lx\n", value); + psxRcntWcount16(1, value ); return; + case 0x1f801114: + PSXCNT_LOG("COUNTER 1 MODE 32bit write %lx\n", value); + psxRcnt1Wmode(value); return; + case 0x1f801118: + PSXCNT_LOG("COUNTER 1 TARGET 32bit write %lx\n", value); + psxRcntWtarget16(1, value ); return; + + case 0x1f801120: + PSXCNT_LOG("COUNTER 2 COUNT 32bit write %lx\n", value); + psxRcntWcount16(2, value ); return; + case 0x1f801124: + PSXCNT_LOG("COUNTER 2 MODE 32bit write %lx\n", value); + psxRcnt2Wmode(value); return; + case 0x1f801128: + PSXCNT_LOG("COUNTER 2 TARGET 32bit write %lx\n", value); + psxRcntWtarget16(2, value); return; + + case 0x1f801480: + PSXCNT_LOG("COUNTER 3 COUNT 32bit write %lx\n", value); + psxRcntWcount32(3, value); return; + case 0x1f801484: + PSXCNT_LOG("COUNTER 3 MODE 32bit write %lx\n", value); + psxRcnt3Wmode(value); return; + case 0x1f801488: + PSXCNT_LOG("COUNTER 3 TARGET 32bit write %lx\n", value); + psxRcntWtarget32(3, value); return; + + case 0x1f801490: + PSXCNT_LOG("COUNTER 4 COUNT 32bit write %lx\n", value); + psxRcntWcount32(4, value); return; + case 0x1f801494: + PSXCNT_LOG("COUNTER 4 MODE 32bit write %lx\n", value); + psxRcnt4Wmode(value); return; + case 0x1f801498: + PSXCNT_LOG("COUNTER 4 TARGET 32bit write %lx\n", value); + psxRcntWtarget32(4, value); return; + + case 0x1f8014a0: + PSXCNT_LOG("COUNTER 5 COUNT 32bit write %lx\n", value); + psxRcntWcount32(5, value); return; + case 0x1f8014a4: + PSXCNT_LOG("COUNTER 5 MODE 32bit write %lx\n", value); + psxRcnt5Wmode(value); return; + case 0x1f8014a8: + PSXCNT_LOG("COUNTER 5 TARGET 32bit write %lx\n", value); + psxRcntWtarget32(5, value); return; + +//------------------------------------------------------------------ + case 0x1f8014c0: + PSXHW_LOG("RTC_HOLDMODE 32bit write %lx\n", value); + Console::Notice("** RTC_HOLDMODE 32bit write %lx", params value); + break; + + case 0x1f801450: + if (value) { PSXHW_LOG("%08X ICFG 32bit write %lx\n", psxRegs.pc, value); } +/* if (value && + psxSu32(0x20) == 0x20000 && + (psxSu32(0x30) == 0x20000 || + psxSu32(0x30) == 0x40000)) { // don't ask me why :P + psxSu32(0x20) = 0x10000; + psxSu32(0x30) = 0x10000; + }*/ + psxHu32(0x1450) = /*(*/value/* & (~0x8)) | (psxHu32(0x1450) & 0x8)*/; + return; + +//------------------------------------------------------------------ + case 0x1F808200: + case 0x1F808204: + case 0x1F808208: + case 0x1F80820C: + case 0x1F808210: + case 0x1F808214: + case 0x1F808218: + case 0x1F80821C: + case 0x1F808220: + case 0x1F808224: + case 0x1F808228: + case 0x1F80822C: + case 0x1F808230: + case 0x1F808234: + case 0x1F808238: + case 0x1F80823C: + PSXHW_LOG("SIO2 write param[%d] <- %lx\n", (add-0x1F808200)/4, value); + sio2_setSend3((add-0x1F808200)/4, value); return; + + case 0x1F808240: + case 0x1F808248: + case 0x1F808250: + case 0x1F808258: + PSXHW_LOG("SIO2 write send1[%d] <- %lx\n", (add-0x1F808240)/8, value); + sio2_setSend1((add-0x1F808240)/8, value); return; + + case 0x1F808244: + case 0x1F80824C: + case 0x1F808254: + case 0x1F80825C: + PSXHW_LOG("SIO2 write send2[%d] <- %lx\n", (add-0x1F808244)/8, value); + sio2_setSend2((add-0x1F808244)/8, value); return; + + case 0x1F808268: + PSXHW_LOG("SIO2 write CTRL <- %lx\n", value); + sio2_setCtrl(value); return; + + case 0x1F808278: + PSXHW_LOG("SIO2 write [8278] <- %lx\n", value); + sio2_set8278(value); return; + + case 0x1F80827C: + PSXHW_LOG("SIO2 write [827C] <- %lx\n", value); + sio2_set827C(value); return; + + case 0x1F808280: + PSXHW_LOG("SIO2 write INTR <- %lx\n", value); + sio2_setIntr(value); return; + +//------------------------------------------------------------------ + default: + psxHu32(add) = value; + PSXHW_LOG("*Unknown 32bit write at address %lx value %lx\n", add, value); + return; + } + psxHu32(add) = value; + PSXHW_LOG("*Known 32bit write at address %lx value %lx\n", add, value); +} + +u8 psxHw4Read8(u32 add) { + u8 hard; + + switch (add) { + case 0x1f402004: return cdvdRead04(); + case 0x1f402005: return cdvdRead05(); + case 0x1f402006: return cdvdRead06(); + case 0x1f402007: return cdvdRead07(); + case 0x1f402008: return cdvdRead08(); + case 0x1f40200A: return cdvdRead0A(); + case 0x1f40200B: return cdvdRead0B(); + case 0x1f40200C: return cdvdRead0C(); + case 0x1f40200D: return cdvdRead0D(); + case 0x1f40200E: return cdvdRead0E(); + case 0x1f40200F: return cdvdRead0F(); + case 0x1f402013: return cdvdRead13(); + case 0x1f402015: return cdvdRead15(); + case 0x1f402016: return cdvdRead16(); + case 0x1f402017: return cdvdRead17(); + case 0x1f402018: return cdvdRead18(); + case 0x1f402020: return cdvdRead20(); + case 0x1f402021: return cdvdRead21(); + case 0x1f402022: return cdvdRead22(); + case 0x1f402023: return cdvdRead23(); + case 0x1f402024: return cdvdRead24(); + case 0x1f402028: return cdvdRead28(); + case 0x1f402029: return cdvdRead29(); + case 0x1f40202A: return cdvdRead2A(); + case 0x1f40202B: return cdvdRead2B(); + case 0x1f40202C: return cdvdRead2C(); + case 0x1f402030: return cdvdRead30(); + case 0x1f402031: return cdvdRead31(); + case 0x1f402032: return cdvdRead32(); + case 0x1f402033: return cdvdRead33(); + case 0x1f402034: return cdvdRead34(); + case 0x1f402038: return cdvdRead38(); + case 0x1f402039: return cdvdRead39(); + case 0x1f40203A: return cdvdRead3A(); + default: + // note: use SysPrintF to notify console since this is a potentially serious + // emulation problem: + //PSXHW_LOG("*Unknown 8bit read at address %lx\n", add); + SysPrintf("*Unknown 8bit read at address %lx\n", add); + return 0; + } + + PSXHW_LOG("*Known 8bit read at address %lx value %x\n", add, hard); + + return hard; +} + +void psxHw4Write8(u32 add, u8 value) { + + switch (add) { + case 0x1f402004: cdvdWrite04(value); return; + case 0x1f402005: cdvdWrite05(value); return; + case 0x1f402006: cdvdWrite06(value); return; + case 0x1f402007: cdvdWrite07(value); return; + case 0x1f402008: cdvdWrite08(value); return; + case 0x1f40200A: cdvdWrite0A(value); return; + case 0x1f40200F: cdvdWrite0F(value); return; + case 0x1f402014: cdvdWrite14(value); return; + case 0x1f402016: cdvdWrite16(value); return; + case 0x1f402017: cdvdWrite17(value); return; + case 0x1f402018: cdvdWrite18(value); return; + case 0x1f40203A: cdvdWrite3A(value); return; + default: + //PSXHW_LOG("*Unknown 8bit write at address %lx value %x\n", add, value); + Console::Notice("*Unknown 8bit write at address %lx value %x", params add, value); + return; + } + PSXHW_LOG("*Known 8bit write at address %lx value %x\n", add, value); +} + +void psxDmaInterrupt(int n) { + if (HW_DMA_ICR & (1 << (16 + n))) { + HW_DMA_ICR|= (1 << (24 + n)); + psxRegs.CP0.n.Cause |= 1 << (9 + n); + iopIntcIrq( 3 ); + } +} + +void psxDmaInterrupt2(int n) { + if (HW_DMA_ICR2 & (1 << (16 + n))) { +/* if (HW_DMA_ICR2 & (1 << (24 + n))) { + SysPrintf("*PCSX2*: HW_DMA_ICR2 n=%d already set\n", n); + } + if (psxHu32(0x1070) & 8) { + SysPrintf("*PCSX2*: psxHu32(0x1070) 8 already set (n=%d)\n", n); + }*/ + HW_DMA_ICR2|= (1 << (24 + n)); + psxRegs.CP0.n.Cause |= 1 << (16 + n); + iopIntcIrq( 3 ); + } +} diff --git a/pcsx2/IopHw.h b/pcsx2/IopHw.h index 4108b82e6b..c94d3d7a72 100644 --- a/pcsx2/IopHw.h +++ b/pcsx2/IopHw.h @@ -1,130 +1,130 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __PSXHW_H__ -#define __PSXHW_H__ - -#include "R3000A.h" -#include "IopMem.h" - -#define HW_DMA0_MADR (psxHu32(0x1080)) // MDEC in DMA -#define HW_DMA0_BCR (psxHu32(0x1084)) -#define HW_DMA0_CHCR (psxHu32(0x1088)) - -#define HW_DMA1_MADR (psxHu32(0x1090)) // MDEC out DMA -#define HW_DMA1_BCR (psxHu32(0x1094)) -#define HW_DMA1_CHCR (psxHu32(0x1098)) - -#define HW_DMA2_MADR (psxHu32(0x10a0)) // GPU DMA -#define HW_DMA2_BCR (psxHu32(0x10a4)) -#define HW_DMA2_CHCR (psxHu32(0x10a8)) -#define HW_DMA2_TADR (psxHu32(0x10ac)) - -#define HW_DMA3_MADR (psxHu32(0x10b0)) // CDROM DMA -#define HW_DMA3_BCR (psxHu32(0x10b4)) -#define HW_DMA3_BCR_L16 (psxHu16(0x10b4)) -#define HW_DMA3_BCR_H16 (psxHu16(0x10b6)) -#define HW_DMA3_CHCR (psxHu32(0x10b8)) - -#define HW_DMA4_MADR (psxHu32(0x10c0)) // SPU DMA -#define HW_DMA4_BCR (psxHu32(0x10c4)) -#define HW_DMA4_CHCR (psxHu32(0x10c8)) -#define HW_DMA4_TADR (psxHu32(0x10cc)) - -#define HW_DMA6_MADR (psxHu32(0x10e0)) // GPU DMA (OT) -#define HW_DMA6_BCR (psxHu32(0x10e4)) -#define HW_DMA6_CHCR (psxHu32(0x10e8)) - -#define HW_DMA7_MADR (psxHu32(0x1500)) // SPU2 DMA -#define HW_DMA7_BCR (psxHu32(0x1504)) -#define HW_DMA7_CHCR (psxHu32(0x1508)) - -#define HW_DMA8_MADR (psxHu32(0x1510)) // DEV9 DMA -#define HW_DMA8_BCR (psxHu32(0x1514)) -#define HW_DMA8_CHCR (psxHu32(0x1518)) - -#define HW_DMA9_MADR (psxHu32(0x1520)) // SIF0 DMA -#define HW_DMA9_BCR (psxHu32(0x1524)) -#define HW_DMA9_CHCR (psxHu32(0x1528)) -#define HW_DMA9_TADR (psxHu32(0x152c)) - -#define HW_DMA10_MADR (psxHu32(0x1530)) // SIF1 DMA -#define HW_DMA10_BCR (psxHu32(0x1534)) -#define HW_DMA10_CHCR (psxHu32(0x1538)) - -#define HW_DMA11_MADR (psxHu32(0x1540)) // SIO2 in -#define HW_DMA11_BCR (psxHu32(0x1544)) -#define HW_DMA11_CHCR (psxHu32(0x1548)) - -#define HW_DMA12_MADR (psxHu32(0x1550)) // SIO2 out -#define HW_DMA12_BCR (psxHu32(0x1554)) -#define HW_DMA12_CHCR (psxHu32(0x1558)) - -#define HW_DMA_PCR (psxHu32(0x10f0)) -#define HW_DMA_ICR (psxHu32(0x10f4)) - -#define HW_DMA_PCR2 (psxHu32(0x1570)) -#define HW_DMA_ICR2 (psxHu32(0x1574)) - -enum IopEventId -{ - IopEvt_Cdvd = 5 // General Cdvd commands (Seek, Standby, Break, etc) -, IopEvt_SIF0 = 9 -, IopEvt_SIF1 = 10 -, IopEvt_Dma11 = 11 -, IopEvt_Dma12 = 12 -, IopEvt_SIO = 16 -, IopEvt_Cdrom = 17 -, IopEvt_CdromRead = 18 -, IopEvt_CdvdRead = 19 -, IopEvt_DEV9 = 20 -, IopEvt_USB = 21 -}; - -extern void PSX_INT( IopEventId n, s32 ecycle); - -extern void psxSetNextBranch( u32 startCycle, s32 delta ); -extern void psxSetNextBranchDelta( s32 delta ); - -void psxHwReset(); -u8 psxHwRead8 (u32 add); -u16 psxHwRead16(u32 add); -u32 psxHwRead32(u32 add); - -void psxHwWrite8 (u32 add, u8 value); -void psxHwWrite16(u32 add, u16 value); -void psxHwWrite32(u32 add, u32 value); - -u8 psxHw4Read8 (u32 add); -void psxHw4Write8(u32 add, u8 value); - -void psxDmaInterrupt(int n); -void psxDmaInterrupt2(int n); - -int psxHwFreeze(gzFile f, int Mode); - -int psxHwConstRead8(u32 x86reg, u32 add, u32 sign); -int psxHwConstRead16(u32 x86reg, u32 add, u32 sign); -int psxHwConstRead32(u32 x86reg, u32 add); -void psxHwConstWrite8(u32 add, int mmreg); -void psxHwConstWrite16(u32 add, int mmreg); -void psxHwConstWrite32(u32 add, int mmreg); -int psxHw4ConstRead8 (u32 x86reg, u32 add, u32 sign); -void psxHw4ConstWrite8(u32 add, int mmreg); - -#endif /* __PSXHW_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __PSXHW_H__ +#define __PSXHW_H__ + +#include "R3000A.h" +#include "IopMem.h" + +#define HW_DMA0_MADR (psxHu32(0x1080)) // MDEC in DMA +#define HW_DMA0_BCR (psxHu32(0x1084)) +#define HW_DMA0_CHCR (psxHu32(0x1088)) + +#define HW_DMA1_MADR (psxHu32(0x1090)) // MDEC out DMA +#define HW_DMA1_BCR (psxHu32(0x1094)) +#define HW_DMA1_CHCR (psxHu32(0x1098)) + +#define HW_DMA2_MADR (psxHu32(0x10a0)) // GPU DMA +#define HW_DMA2_BCR (psxHu32(0x10a4)) +#define HW_DMA2_CHCR (psxHu32(0x10a8)) +#define HW_DMA2_TADR (psxHu32(0x10ac)) + +#define HW_DMA3_MADR (psxHu32(0x10b0)) // CDROM DMA +#define HW_DMA3_BCR (psxHu32(0x10b4)) +#define HW_DMA3_BCR_L16 (psxHu16(0x10b4)) +#define HW_DMA3_BCR_H16 (psxHu16(0x10b6)) +#define HW_DMA3_CHCR (psxHu32(0x10b8)) + +#define HW_DMA4_MADR (psxHu32(0x10c0)) // SPU DMA +#define HW_DMA4_BCR (psxHu32(0x10c4)) +#define HW_DMA4_CHCR (psxHu32(0x10c8)) +#define HW_DMA4_TADR (psxHu32(0x10cc)) + +#define HW_DMA6_MADR (psxHu32(0x10e0)) // GPU DMA (OT) +#define HW_DMA6_BCR (psxHu32(0x10e4)) +#define HW_DMA6_CHCR (psxHu32(0x10e8)) + +#define HW_DMA7_MADR (psxHu32(0x1500)) // SPU2 DMA +#define HW_DMA7_BCR (psxHu32(0x1504)) +#define HW_DMA7_CHCR (psxHu32(0x1508)) + +#define HW_DMA8_MADR (psxHu32(0x1510)) // DEV9 DMA +#define HW_DMA8_BCR (psxHu32(0x1514)) +#define HW_DMA8_CHCR (psxHu32(0x1518)) + +#define HW_DMA9_MADR (psxHu32(0x1520)) // SIF0 DMA +#define HW_DMA9_BCR (psxHu32(0x1524)) +#define HW_DMA9_CHCR (psxHu32(0x1528)) +#define HW_DMA9_TADR (psxHu32(0x152c)) + +#define HW_DMA10_MADR (psxHu32(0x1530)) // SIF1 DMA +#define HW_DMA10_BCR (psxHu32(0x1534)) +#define HW_DMA10_CHCR (psxHu32(0x1538)) + +#define HW_DMA11_MADR (psxHu32(0x1540)) // SIO2 in +#define HW_DMA11_BCR (psxHu32(0x1544)) +#define HW_DMA11_CHCR (psxHu32(0x1548)) + +#define HW_DMA12_MADR (psxHu32(0x1550)) // SIO2 out +#define HW_DMA12_BCR (psxHu32(0x1554)) +#define HW_DMA12_CHCR (psxHu32(0x1558)) + +#define HW_DMA_PCR (psxHu32(0x10f0)) +#define HW_DMA_ICR (psxHu32(0x10f4)) + +#define HW_DMA_PCR2 (psxHu32(0x1570)) +#define HW_DMA_ICR2 (psxHu32(0x1574)) + +enum IopEventId +{ + IopEvt_Cdvd = 5 // General Cdvd commands (Seek, Standby, Break, etc) +, IopEvt_SIF0 = 9 +, IopEvt_SIF1 = 10 +, IopEvt_Dma11 = 11 +, IopEvt_Dma12 = 12 +, IopEvt_SIO = 16 +, IopEvt_Cdrom = 17 +, IopEvt_CdromRead = 18 +, IopEvt_CdvdRead = 19 +, IopEvt_DEV9 = 20 +, IopEvt_USB = 21 +}; + +extern void PSX_INT( IopEventId n, s32 ecycle); + +extern void psxSetNextBranch( u32 startCycle, s32 delta ); +extern void psxSetNextBranchDelta( s32 delta ); + +void psxHwReset(); +u8 psxHwRead8 (u32 add); +u16 psxHwRead16(u32 add); +u32 psxHwRead32(u32 add); + +void psxHwWrite8 (u32 add, u8 value); +void psxHwWrite16(u32 add, u16 value); +void psxHwWrite32(u32 add, u32 value); + +u8 psxHw4Read8 (u32 add); +void psxHw4Write8(u32 add, u8 value); + +void psxDmaInterrupt(int n); +void psxDmaInterrupt2(int n); + +int psxHwFreeze(gzFile f, int Mode); + +int psxHwConstRead8(u32 x86reg, u32 add, u32 sign); +int psxHwConstRead16(u32 x86reg, u32 add, u32 sign); +int psxHwConstRead32(u32 x86reg, u32 add); +void psxHwConstWrite8(u32 add, int mmreg); +void psxHwConstWrite16(u32 add, int mmreg); +void psxHwConstWrite32(u32 add, int mmreg); +int psxHw4ConstRead8 (u32 x86reg, u32 add, u32 sign); +void psxHw4ConstWrite8(u32 add, int mmreg); + +#endif /* __PSXHW_H__ */ diff --git a/pcsx2/IopMem.cpp b/pcsx2/IopMem.cpp index a83118ecbc..1511b269f9 100644 --- a/pcsx2/IopMem.cpp +++ b/pcsx2/IopMem.cpp @@ -1,783 +1,783 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "PsxCommon.h" -#include "VU.h" -#include "iCore.h" -#include "Hw.h" -#include "iR3000A.h" - -int g_psxWriteOk=1; -static u32 writectrl; - -#ifdef PCSX2_VIRTUAL_MEM -void psxMemAlloc() -{ - // In VirtualMemory land all mem taken care by memAlloc -} - -void psxMemReset() -{ - memzero_ptr(psxM); -} - -void psxMemShutdown() -{ -} - -u8 psxMemRead8(u32 mem) -{ - u32 t = (mem >> 16) & 0x1fff; - - switch(t) { - case 0x1f80: - mem&= 0x1fffffff; - if (mem < 0x1f801000) - return psxHu8(mem); - else - return psxHwRead8(mem); - break; - -#ifdef _DEBUG - case 0x1d00: assert(0); -#endif - - case 0x1f40: - mem &= 0x1fffffff; - return psxHw4Read8(mem); - - case 0x1000: return DEV9read8(mem & 0x1FFFFFFF); - - default: - assert( g_psxWriteOk ); - return *(u8*)PSXM(mem); - } -} - -u16 psxMemRead16(u32 mem) -{ - u32 t = (mem >> 16) & 0x1fff; - - switch(t) { - case 0x1f80: - mem&= 0x1fffffff; - if (mem < 0x1f801000) - return psxHu16(mem); - else - return psxHwRead16(mem); - break; - - case 0x1d00: - SIF_LOG("Sif reg read %x value %x\n", mem, psxHu16(mem)); - switch(mem & 0xF0) - { - case 0x40: return psHu16(0x1000F240) | 0x0002; - case 0x60: return 0; - default: return *(u16*)(PS2MEM_HW+0xf200+(mem&0xf0)); - } - break; - - case 0x1f90: - return SPU2read(mem & 0x1FFFFFFF); - case 0x1000: - return DEV9read16(mem & 0x1FFFFFFF); - - default: - assert( g_psxWriteOk ); - return *(u16*)PSXM(mem); - } -} - -u32 psxMemRead32(u32 mem) -{ - u32 t = (mem >> 16) & 0x1fff; - - switch(t) { - case 0x1f80: - mem&= 0x1fffffff; - if (mem < 0x1f801000) - return psxHu32(mem); - else - return psxHwRead32(mem); - break; - - case 0x1d00: - SIF_LOG("Sif reg read %x value %x\n", mem, psxHu32(mem)); - switch(mem & 0xF0) - { - case 0x40: return psHu32(0x1000F240) | 0xF0000002; - case 0x60: return 0; - default: return *(u32*)(PS2MEM_HW+0xf200+(mem&0xf0)); - } - break; - - case 0x1fff: return g_psxWriteOk; - case 0x1000: - return DEV9read32(mem & 0x1FFFFFFF); - - default: - //assert(g_psxWriteOk); - if( mem == 0xfffe0130 ) - return writectrl; - else if( mem == 0xffffffff ) - return writectrl; - else if( g_psxWriteOk ) - return *(u32*)PSXM(mem); - else return 0; - } -} - -void psxMemWrite8(u32 mem, u8 value) -{ - u32 t = (mem >> 16) & 0x1fff; - - switch(t) { - case 0x1f80: - mem&= 0x1fffffff; - if (mem < 0x1f801000) - psxHu8(mem) = value; - else - psxHwWrite8(mem, value); - break; - - case 0x1f40: - mem&= 0x1fffffff; - psxHw4Write8(mem, value); - break; - - case 0x1d00: - SysPrintf("sw8 [0x%08X]=0x%08X\n", mem, value); - *(u8*)(PS2MEM_HW+0xf200+(mem&0xff)) = value; - break; - - case 0x1000: - DEV9write8(mem & 0x1fffffff, value); - return; - - default: - assert(g_psxWriteOk); - *(u8 *)PSXM(mem) = value; - psxCpu->Clear(mem&~3, 1); - break; - } -} - -void psxMemWrite16(u32 mem, u16 value) -{ - u32 t = (mem >> 16) & 0x1fff; - switch(t) { - case 0x1600: - //HACK: DEV9 VM crash fix - break; - case 0x1f80: - mem&= 0x1fffffff; - if (mem < 0x1f801000) - psxHu16(mem) = value; - else - psxHwWrite16(mem, value); - break; - - case 0x1d00: - switch (mem & 0xf0) { - case 0x10: - // write to ps2 mem - psHu16(0x1000F210) = value; - return; - case 0x40: - { - u32 temp = value & 0xF0; - // write to ps2 mem - if(value & 0x20 || value & 0x80) - { - psHu16(0x1000F240) &= ~0xF000; - psHu16(0x1000F240) |= 0x2000; - } - - if(psHu16(0x1000F240) & temp) psHu16(0x1000F240) &= ~temp; - else psHu16(0x1000F240) |= temp; - return; - } - case 0x60: - psHu32(0x1000F260) = 0; - return; - default: - assert(0); - } - return; - - case 0x1f90: - SPU2write(mem & 0x1FFFFFFF, value); return; - - case 0x1000: - DEV9write16(mem & 0x1fffffff, value); return; - default: - assert( g_psxWriteOk ); - *(u16 *)PSXM(mem) = value; - psxCpu->Clear(mem&~3, 1); - break; - } -} - -void psxMemWrite32(u32 mem, u32 value) -{ - u32 t = (mem >> 16) & 0x1fff; - switch(t) { - case 0x1f80: - mem&= 0x1fffffff; - if (mem < 0x1f801000) - psxHu32(mem) = value; - else - psxHwWrite32(mem, value); - break; - - case 0x1d00: - switch (mem & 0xf0) { - case 0x10: - // write to ps2 mem - psHu32(0x1000F210) = value; - return; - case 0x20: - // write to ps2 mem - psHu32(0x1000F220) &= ~value; - return; - case 0x30: - // write to ps2 mem - psHu32(0x1000F230) |= value; - return; - case 0x40: - { - u32 temp = value & 0xF0; - // write to ps2 mem - if(value & 0x20 || value & 0x80) - { - psHu32(0x1000F240) &= ~0xF000; - psHu32(0x1000F240) |= 0x2000; - } - - - if(psHu32(0x1000F240) & temp) psHu32(0x1000F240) &= ~temp; - else psHu32(0x1000F240) |= temp; - return; - } - case 0x60: - psHu32(0x1000F260) = 0; - return; - - default: - *(u32*)(PS2MEM_HW+0xf200+(mem&0xf0)) = value; - } - - return; - - case 0x1000: - DEV9write32(mem & 0x1fffffff, value); - return; - - case 0x1ffe: - if( mem == 0xfffe0130 ) { - writectrl = value; - switch (value) { - case 0x800: case 0x804: - case 0xc00: case 0xc04: - case 0xcc0: case 0xcc4: - case 0x0c4: - g_psxWriteOk = 0; - //PSXMEM_LOG("writectrl: writenot ok\n"); - break; - case 0x1e988: - case 0x1edd8: - g_psxWriteOk = 1; - //PSXMEM_LOG("writectrl: write ok\n"); - break; - default: - PSXMEM_LOG("unk %8.8lx = %x\n", mem, value); - break; - } - } - break; - - default: - - if( g_psxWriteOk ) { - *(u32 *)PSXM(mem) = value; - psxCpu->Clear(mem&~3, 1); - } - - break; - } -} - -#else - -// TLB functions - -#ifdef TLB_DEBUG_MEM -void* PSXM(u32 mem) -{ - return (psxMemRLUT[(mem) >> 16] == 0 ? NULL : (void*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff))); -} - -void* _PSXM(u32 mem) -{ - return ((void*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff))); -} -#endif - -u8 *psxM = NULL; -u8 *psxP = NULL; -u8 *psxH = NULL; -u8 *psxS = NULL; - -uptr *psxMemWLUT = NULL; -const uptr *psxMemRLUT = NULL; - -static u8* m_psxAllMem = NULL; -static const uint m_psxMemSize = - Ps2MemSize::IopRam + - Ps2MemSize::IopHardware + - 0x00010000 + // psxP - 0x00010000 ; // psxS - -void psxMemAlloc() -{ - if( m_psxAllMem == NULL ) - m_psxAllMem = vtlb_malloc( m_psxMemSize, 4096, 0x21000000 ); - - if( m_psxAllMem == NULL) - throw Exception::OutOfMemory( "psxMemAlloc > failed allocating memory for the IOP processor." ); - - u8* curpos = m_psxAllMem; - psxM = curpos; curpos += Ps2MemSize::IopRam; - psxP = curpos; curpos += 0x00010000; - psxH = curpos; curpos += Ps2MemSize::IopHardware; - psxS = curpos; //curpos += 0x00010000; - - psxMemWLUT = (uptr*)_aligned_malloc(0x10000 * sizeof(uptr) * 2, 16); - psxMemRLUT = psxMemWLUT + 0x10000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16); -} - -// Note! Resetting the IOP's memory state is dependent on having *all* psx memory allocated, -// which is performed by MemInit and PsxMemInit() -void psxMemReset() -{ - jASSUME( psxMemWLUT != NULL ); - jASSUME( m_psxAllMem != NULL ); - - DbgCon::Status( "psxMemReset > Resetting core memory!" ); - - memzero_ptr<0x10000 * sizeof(uptr) * 2>( psxMemWLUT ); // clears both allocations, RLUT and WLUT - memzero_ptr( m_psxAllMem ); - - // Trick! We're accessing RLUT here through WLUT, since it's the non-const pointer. - // So the ones with a 1 prefixed (ala 0x18000, etc) are RLUT tables. - for (int i=0; i<0x0080; i++) - { - psxMemWLUT[i + 0x0000] = (uptr)&psxM[(i & 0x1f) << 16]; - psxMemWLUT[i + 0x8000] = (uptr)&psxM[(i & 0x1f) << 16]; - psxMemWLUT[i + 0xa000] = (uptr)&psxM[(i & 0x1f) << 16]; - - // RLUTs, accessed through WLUT. - psxMemWLUT[i + 0x10000] = (uptr)&psxM[(i & 0x1f) << 16]; - psxMemWLUT[i + 0x18000] = (uptr)&psxM[(i & 0x1f) << 16]; - psxMemWLUT[i + 0x1a000] = (uptr)&psxM[(i & 0x1f) << 16]; - } - - // A few single-page allocations... - psxMemWLUT[0x11f00] = (uptr)psxP; - psxMemWLUT[0x11f80] = (uptr)psxH; - psxMemWLUT[0x1bf80] = (uptr)psxH; - - psxMemWLUT[0x1f00] = (uptr)psxP; - psxMemWLUT[0x1f80] = (uptr)psxH; - psxMemWLUT[0xbf80] = (uptr)psxH; - - // Read-only memory areas, so don't map WLUT for these... - for (int i=0; i<0x0040; i++) - { - psxMemWLUT[i + 0x11fc0] = (uptr)&PS2MEM_ROM[i << 16]; - psxMemWLUT[i + 0x19fc0] = (uptr)&PS2MEM_ROM[i << 16]; - psxMemWLUT[i + 0x1bfc0] = (uptr)&PS2MEM_ROM[i << 16]; - } - - for (int i=0; i<0x0004; i++) - { - psxMemWLUT[i + 0x11e00] = (uptr)&PS2MEM_ROM1[i << 16]; - psxMemWLUT[i + 0x19e00] = (uptr)&PS2MEM_ROM1[i << 16]; - psxMemWLUT[i + 0x1be00] = (uptr)&PS2MEM_ROM1[i << 16]; - } - - // Scratchpad! (which is read only? (air)) - psxMemWLUT[0x11d00] = (uptr)psxS; - psxMemWLUT[0x1bd00] = (uptr)psxS; - - // why isn't scratchpad read/write? (air) - //for (i=0; i<0x0001; i++) psxMemWLUT[i + 0x1d00] = (uptr)&psxS[i << 16]; - //for (i=0; i<0x0001; i++) psxMemWLUT[i + 0xbd00] = (uptr)&psxS[i << 16]; - - // this one looks like an old hack for some special write-only memory area, - // but leaving it in for reference (air) - //for (i=0; i<0x0008; i++) psxMemWLUT[i + 0xbfc0] = (uptr)&psR[i << 16]; -} - -void psxMemShutdown() -{ - vtlb_free( m_psxAllMem, m_psxMemSize ); - m_psxAllMem = NULL; - //safe_aligned_free( m_psxAllMem ); - - psxM = psxP = psxH = psxS = NULL; - - safe_aligned_free(psxMemWLUT); - psxMemRLUT = NULL; -} - -u8 psxMemRead8(u32 mem) { - const u8* p; - u32 t; - - t = (mem >> 16) & 0x1fff; - if (t == 0x1f80) { - mem&= 0x1fffffff; - if (mem < 0x1f801000) - return psxHu8(mem); - else - return psxHwRead8(mem); - } else - if (t == 0x1f40) { - mem&= 0x1fffffff; - return psxHw4Read8(mem); - } else { - p = (const u8*)(psxMemRLUT[mem >> 16]); - if (p != NULL) { - return *(const u8 *)(p + (mem & 0xffff)); - } else { - if (t == 0x1000) return DEV9read8(mem & 0x1FFFFFFF); - PSXMEM_LOG("err lb %8.8lx\n", mem); - return 0; - } - } -} - -u16 psxMemRead16(u32 mem) { - const u8* p; - u32 t; - - t = (mem >> 16) & 0x1fff; - if (t == 0x1f80) { - mem&= 0x1fffffff; - if (mem < 0x1f801000) - return psxHu16(mem); - else - return psxHwRead16(mem); - } else { - p = (const u8*)(psxMemRLUT[mem >> 16]); - if (p != NULL) { - if (t == 0x1d00) { - u16 ret; - switch(mem & 0xF0) - { - case 0x00: - ret= psHu16(0x1000F200); - break; - case 0x10: - ret= psHu16(0x1000F210); - break; - case 0x40: - ret= psHu16(0x1000F240) | 0x0002; - break; - case 0x60: - ret = 0; - break; - default: - ret = psxHu16(mem); - break; - } - SIF_LOG("Sif reg read %x value %x\n", mem, ret); - return ret; - } - return *(const u16 *)(p + (mem & 0xffff)); - } else { - if (t == 0x1F90) - return SPU2read(mem & 0x1FFFFFFF); - if (t == 0x1000) return DEV9read16(mem & 0x1FFFFFFF); - PSXMEM_LOG("err lh %8.8lx\n", mem); - return 0; - } - } -} - -u32 psxMemRead32(u32 mem) { - const u8* p; - u32 t; - t = (mem >> 16) & 0x1fff; - if (t == 0x1f80) { - mem&= 0x1fffffff; - if (mem < 0x1f801000) - return psxHu32(mem); - else - return psxHwRead32(mem); - } else { - //see also Hw.c - p = (const u8*)(psxMemRLUT[mem >> 16]); - if (p != NULL) { - if (t == 0x1d00) { - u32 ret; - switch(mem & 0xF0) - { - case 0x00: - ret= psHu32(0x1000F200); - break; - case 0x10: - ret= psHu32(0x1000F210); - break; - case 0x20: - ret= psHu32(0x1000F220); - break; - case 0x30: // EE Side - ret= psHu32(0x1000F230); - break; - case 0x40: - ret= psHu32(0x1000F240) | 0xF0000002; - break; - case 0x60: - ret = 0; - break; - default: - ret = psxHu32(mem); - break; - } - SIF_LOG("Sif reg read %x value %x\n", mem, ret); - return ret; - } - return *(const u32 *)(p + (mem & 0xffff)); - } else { - if (t == 0x1000) return DEV9read32(mem & 0x1FFFFFFF); - - if (mem != 0xfffe0130) { -#ifdef PSXMEM_LOG - if (g_psxWriteOk) PSXMEM_LOG("err lw %8.8lx\n", mem); -#endif - } else { - return writectrl; - } - return 0; - } - } -} - -void psxMemWrite8(u32 mem, u8 value) { - char *p; - u32 t; - - t = (mem >> 16) & 0x1fff; - if (t == 0x1f80) { - mem&= 0x1fffffff; - if (mem < 0x1f801000) - psxHu8(mem) = value; - else - psxHwWrite8(mem, value); - } else - if (t == 0x1f40) { - mem&= 0x1fffffff; - psxHw4Write8(mem, value); - } else { - p = (char *)(psxMemWLUT[mem >> 16]); - if (p != NULL) { - *(u8 *)(p + (mem & 0xffff)) = value; - psxCpu->Clear(mem&~3, 1); - } else { - if ((t & 0x1FFF)==0x1D00) SysPrintf("sw8 [0x%08X]=0x%08X\n", mem, value); - if (t == 0x1d00) { - psxSu8(mem) = value; return; - } - if (t == 0x1000) { - DEV9write8(mem & 0x1fffffff, value); return; - } - PSXMEM_LOG("err sb %8.8lx = %x\n", mem, value); - } - } -} - -void psxMemWrite16(u32 mem, u16 value) { - char *p; - u32 t; - - t = (mem >> 16) & 0x1fff; - if (t == 0x1f80) { - mem&= 0x1fffffff; - if (mem < 0x1f801000) - psxHu16(mem) = value; - else - psxHwWrite16(mem, value); - } else { - p = (char *)(psxMemWLUT[mem >> 16]); - if (p != NULL) { - if ((t & 0x1FFF)==0x1D00) SysPrintf("sw16 [0x%08X]=0x%08X\n", mem, value); - *(u16 *)(p + (mem & 0xffff)) = value; - psxCpu->Clear(mem&~3, 1); - } else { - if (t == 0x1d00) { - switch (mem & 0xf0) { - case 0x10: - // write to ps2 mem - psHu16(0x1000F210) = value; - return; - case 0x40: - { - u32 temp = value & 0xF0; - // write to ps2 mem - if(value & 0x20 || value & 0x80) - { - psHu16(0x1000F240) &= ~0xF000; - psHu16(0x1000F240) |= 0x2000; - } - - - if(psHu16(0x1000F240) & temp) psHu16(0x1000F240) &= ~temp; - else psHu16(0x1000F240) |= temp; - return; - } - case 0x60: - psHu32(0x1000F260) = 0; - return; - - } - psxSu16(mem) = value; return; - } - if (t == 0x1F90) { - SPU2write(mem & 0x1FFFFFFF, value); return; - } - if (t == 0x1000) { - DEV9write16(mem & 0x1fffffff, value); return; - } - PSXMEM_LOG("err sh %8.8lx = %x\n", mem, value); - } - } -} - -void psxMemWrite32(u32 mem, u32 value) { - char *p; - u32 t; - - t = (mem >> 16) & 0x1fff; - if (t == 0x1f80) { - mem&= 0x1fffffff; - if (mem < 0x1f801000) - psxHu32(mem) = value; - else - psxHwWrite32(mem, value); - } else { - //see also Hw.c - p = (char *)(psxMemWLUT[mem >> 16]); - if (p != NULL) { - *(u32 *)(p + (mem & 0xffff)) = value; - psxCpu->Clear(mem&~3, 1); - } else { - if (mem != 0xfffe0130) { - if (t == 0x1d00) { - MEM_LOG("iop Sif reg write %x value %x\n", mem, value); - switch (mem & 0xf0) { - case 0x10: - // write to ps2 mem - psHu32(0x1000F210) = value; - return; - case 0x20: - // write to ps2 mem - psHu32(0x1000F220) &= ~value; - return; - case 0x30: - // write to ps2 mem - psHu32(0x1000F230) |= value; - return; - case 0x40: - { - u32 temp = value & 0xF0; - // write to ps2 mem - if(value & 0x20 || value & 0x80) - { - psHu32(0x1000F240) &= ~0xF000; - psHu32(0x1000F240) |= 0x2000; - } - - - if(psHu32(0x1000F240) & temp) psHu32(0x1000F240) &= ~temp; - else psHu32(0x1000F240) |= temp; - return; - } - case 0x60: - psHu32(0x1000F260) = 0; - return; - - } - psxSu32(mem) = value; - - // write to ps2 mem - if( (mem & 0xf0) != 0x60 ) - *(u32*)(PS2MEM_HW+0xf200+(mem&0xf0)) = value; - return; - } - if (t == 0x1000) { - DEV9write32(mem & 0x1fffffff, value); return; - } - - //if (!g_psxWriteOk) psxCpu->Clear(mem&~3, 1); - if (g_psxWriteOk) { PSXMEM_LOG("err sw %8.8lx = %x\n", mem, value); } - } else { - writectrl = value; - switch (value) { - case 0x800: case 0x804: - case 0xc00: case 0xc04: - case 0xcc0: case 0xcc4: - case 0x0c4: - if (g_psxWriteOk == 0) break; - g_psxWriteOk = 0; - - // Performance note: Use a for loop instead of memset/memzero - // This generates *much* more efficient code in this particular case (due to few iterations) - for (int i=0; i<0x0080; i++) - { - psxMemWLUT[i + 0x0000] = 0; - psxMemWLUT[i + 0x8000] = 0; - psxMemWLUT[i + 0xa000] = 0; - } - //PSXMEM_LOG("writectrl: writenot ok\n"); - break; - case 0x1e988: - case 0x1edd8: - if (g_psxWriteOk == 1) break; - g_psxWriteOk = 1; - for (int i=0; i<0x0080; i++) - { - psxMemWLUT[i + 0x0000] = (uptr)&psxM[(i & 0x1f) << 16]; - psxMemWLUT[i + 0x8000] = (uptr)&psxM[(i & 0x1f) << 16]; - psxMemWLUT[i + 0xa000] = (uptr)&psxM[(i & 0x1f) << 16]; - } - //PSXMEM_LOG("writectrl: write ok\n"); - break; - default: - PSXMEM_LOG("unk %8.8lx = %x\n", mem, value); - break; - } - } - } - } -} - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "PsxCommon.h" +#include "VU.h" +#include "iCore.h" +#include "Hw.h" +#include "iR3000A.h" + +int g_psxWriteOk=1; +static u32 writectrl; + +#ifdef PCSX2_VIRTUAL_MEM +void psxMemAlloc() +{ + // In VirtualMemory land all mem taken care by memAlloc +} + +void psxMemReset() +{ + memzero_ptr(psxM); +} + +void psxMemShutdown() +{ +} + +u8 psxMemRead8(u32 mem) +{ + u32 t = (mem >> 16) & 0x1fff; + + switch(t) { + case 0x1f80: + mem&= 0x1fffffff; + if (mem < 0x1f801000) + return psxHu8(mem); + else + return psxHwRead8(mem); + break; + +#ifdef _DEBUG + case 0x1d00: assert(0); +#endif + + case 0x1f40: + mem &= 0x1fffffff; + return psxHw4Read8(mem); + + case 0x1000: return DEV9read8(mem & 0x1FFFFFFF); + + default: + assert( g_psxWriteOk ); + return *(u8*)PSXM(mem); + } +} + +u16 psxMemRead16(u32 mem) +{ + u32 t = (mem >> 16) & 0x1fff; + + switch(t) { + case 0x1f80: + mem&= 0x1fffffff; + if (mem < 0x1f801000) + return psxHu16(mem); + else + return psxHwRead16(mem); + break; + + case 0x1d00: + SIF_LOG("Sif reg read %x value %x\n", mem, psxHu16(mem)); + switch(mem & 0xF0) + { + case 0x40: return psHu16(0x1000F240) | 0x0002; + case 0x60: return 0; + default: return *(u16*)(PS2MEM_HW+0xf200+(mem&0xf0)); + } + break; + + case 0x1f90: + return SPU2read(mem & 0x1FFFFFFF); + case 0x1000: + return DEV9read16(mem & 0x1FFFFFFF); + + default: + assert( g_psxWriteOk ); + return *(u16*)PSXM(mem); + } +} + +u32 psxMemRead32(u32 mem) +{ + u32 t = (mem >> 16) & 0x1fff; + + switch(t) { + case 0x1f80: + mem&= 0x1fffffff; + if (mem < 0x1f801000) + return psxHu32(mem); + else + return psxHwRead32(mem); + break; + + case 0x1d00: + SIF_LOG("Sif reg read %x value %x\n", mem, psxHu32(mem)); + switch(mem & 0xF0) + { + case 0x40: return psHu32(0x1000F240) | 0xF0000002; + case 0x60: return 0; + default: return *(u32*)(PS2MEM_HW+0xf200+(mem&0xf0)); + } + break; + + case 0x1fff: return g_psxWriteOk; + case 0x1000: + return DEV9read32(mem & 0x1FFFFFFF); + + default: + //assert(g_psxWriteOk); + if( mem == 0xfffe0130 ) + return writectrl; + else if( mem == 0xffffffff ) + return writectrl; + else if( g_psxWriteOk ) + return *(u32*)PSXM(mem); + else return 0; + } +} + +void psxMemWrite8(u32 mem, u8 value) +{ + u32 t = (mem >> 16) & 0x1fff; + + switch(t) { + case 0x1f80: + mem&= 0x1fffffff; + if (mem < 0x1f801000) + psxHu8(mem) = value; + else + psxHwWrite8(mem, value); + break; + + case 0x1f40: + mem&= 0x1fffffff; + psxHw4Write8(mem, value); + break; + + case 0x1d00: + SysPrintf("sw8 [0x%08X]=0x%08X\n", mem, value); + *(u8*)(PS2MEM_HW+0xf200+(mem&0xff)) = value; + break; + + case 0x1000: + DEV9write8(mem & 0x1fffffff, value); + return; + + default: + assert(g_psxWriteOk); + *(u8 *)PSXM(mem) = value; + psxCpu->Clear(mem&~3, 1); + break; + } +} + +void psxMemWrite16(u32 mem, u16 value) +{ + u32 t = (mem >> 16) & 0x1fff; + switch(t) { + case 0x1600: + //HACK: DEV9 VM crash fix + break; + case 0x1f80: + mem&= 0x1fffffff; + if (mem < 0x1f801000) + psxHu16(mem) = value; + else + psxHwWrite16(mem, value); + break; + + case 0x1d00: + switch (mem & 0xf0) { + case 0x10: + // write to ps2 mem + psHu16(0x1000F210) = value; + return; + case 0x40: + { + u32 temp = value & 0xF0; + // write to ps2 mem + if(value & 0x20 || value & 0x80) + { + psHu16(0x1000F240) &= ~0xF000; + psHu16(0x1000F240) |= 0x2000; + } + + if(psHu16(0x1000F240) & temp) psHu16(0x1000F240) &= ~temp; + else psHu16(0x1000F240) |= temp; + return; + } + case 0x60: + psHu32(0x1000F260) = 0; + return; + default: + assert(0); + } + return; + + case 0x1f90: + SPU2write(mem & 0x1FFFFFFF, value); return; + + case 0x1000: + DEV9write16(mem & 0x1fffffff, value); return; + default: + assert( g_psxWriteOk ); + *(u16 *)PSXM(mem) = value; + psxCpu->Clear(mem&~3, 1); + break; + } +} + +void psxMemWrite32(u32 mem, u32 value) +{ + u32 t = (mem >> 16) & 0x1fff; + switch(t) { + case 0x1f80: + mem&= 0x1fffffff; + if (mem < 0x1f801000) + psxHu32(mem) = value; + else + psxHwWrite32(mem, value); + break; + + case 0x1d00: + switch (mem & 0xf0) { + case 0x10: + // write to ps2 mem + psHu32(0x1000F210) = value; + return; + case 0x20: + // write to ps2 mem + psHu32(0x1000F220) &= ~value; + return; + case 0x30: + // write to ps2 mem + psHu32(0x1000F230) |= value; + return; + case 0x40: + { + u32 temp = value & 0xF0; + // write to ps2 mem + if(value & 0x20 || value & 0x80) + { + psHu32(0x1000F240) &= ~0xF000; + psHu32(0x1000F240) |= 0x2000; + } + + + if(psHu32(0x1000F240) & temp) psHu32(0x1000F240) &= ~temp; + else psHu32(0x1000F240) |= temp; + return; + } + case 0x60: + psHu32(0x1000F260) = 0; + return; + + default: + *(u32*)(PS2MEM_HW+0xf200+(mem&0xf0)) = value; + } + + return; + + case 0x1000: + DEV9write32(mem & 0x1fffffff, value); + return; + + case 0x1ffe: + if( mem == 0xfffe0130 ) { + writectrl = value; + switch (value) { + case 0x800: case 0x804: + case 0xc00: case 0xc04: + case 0xcc0: case 0xcc4: + case 0x0c4: + g_psxWriteOk = 0; + //PSXMEM_LOG("writectrl: writenot ok\n"); + break; + case 0x1e988: + case 0x1edd8: + g_psxWriteOk = 1; + //PSXMEM_LOG("writectrl: write ok\n"); + break; + default: + PSXMEM_LOG("unk %8.8lx = %x\n", mem, value); + break; + } + } + break; + + default: + + if( g_psxWriteOk ) { + *(u32 *)PSXM(mem) = value; + psxCpu->Clear(mem&~3, 1); + } + + break; + } +} + +#else + +// TLB functions + +#ifdef TLB_DEBUG_MEM +void* PSXM(u32 mem) +{ + return (psxMemRLUT[(mem) >> 16] == 0 ? NULL : (void*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff))); +} + +void* _PSXM(u32 mem) +{ + return ((void*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff))); +} +#endif + +u8 *psxM = NULL; +u8 *psxP = NULL; +u8 *psxH = NULL; +u8 *psxS = NULL; + +uptr *psxMemWLUT = NULL; +const uptr *psxMemRLUT = NULL; + +static u8* m_psxAllMem = NULL; +static const uint m_psxMemSize = + Ps2MemSize::IopRam + + Ps2MemSize::IopHardware + + 0x00010000 + // psxP + 0x00010000 ; // psxS + +void psxMemAlloc() +{ + if( m_psxAllMem == NULL ) + m_psxAllMem = vtlb_malloc( m_psxMemSize, 4096, 0x21000000 ); + + if( m_psxAllMem == NULL) + throw Exception::OutOfMemory( "psxMemAlloc > failed allocating memory for the IOP processor." ); + + u8* curpos = m_psxAllMem; + psxM = curpos; curpos += Ps2MemSize::IopRam; + psxP = curpos; curpos += 0x00010000; + psxH = curpos; curpos += Ps2MemSize::IopHardware; + psxS = curpos; //curpos += 0x00010000; + + psxMemWLUT = (uptr*)_aligned_malloc(0x10000 * sizeof(uptr) * 2, 16); + psxMemRLUT = psxMemWLUT + 0x10000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16); +} + +// Note! Resetting the IOP's memory state is dependent on having *all* psx memory allocated, +// which is performed by MemInit and PsxMemInit() +void psxMemReset() +{ + jASSUME( psxMemWLUT != NULL ); + jASSUME( m_psxAllMem != NULL ); + + DbgCon::Status( "psxMemReset > Resetting core memory!" ); + + memzero_ptr<0x10000 * sizeof(uptr) * 2>( psxMemWLUT ); // clears both allocations, RLUT and WLUT + memzero_ptr( m_psxAllMem ); + + // Trick! We're accessing RLUT here through WLUT, since it's the non-const pointer. + // So the ones with a 1 prefixed (ala 0x18000, etc) are RLUT tables. + for (int i=0; i<0x0080; i++) + { + psxMemWLUT[i + 0x0000] = (uptr)&psxM[(i & 0x1f) << 16]; + psxMemWLUT[i + 0x8000] = (uptr)&psxM[(i & 0x1f) << 16]; + psxMemWLUT[i + 0xa000] = (uptr)&psxM[(i & 0x1f) << 16]; + + // RLUTs, accessed through WLUT. + psxMemWLUT[i + 0x10000] = (uptr)&psxM[(i & 0x1f) << 16]; + psxMemWLUT[i + 0x18000] = (uptr)&psxM[(i & 0x1f) << 16]; + psxMemWLUT[i + 0x1a000] = (uptr)&psxM[(i & 0x1f) << 16]; + } + + // A few single-page allocations... + psxMemWLUT[0x11f00] = (uptr)psxP; + psxMemWLUT[0x11f80] = (uptr)psxH; + psxMemWLUT[0x1bf80] = (uptr)psxH; + + psxMemWLUT[0x1f00] = (uptr)psxP; + psxMemWLUT[0x1f80] = (uptr)psxH; + psxMemWLUT[0xbf80] = (uptr)psxH; + + // Read-only memory areas, so don't map WLUT for these... + for (int i=0; i<0x0040; i++) + { + psxMemWLUT[i + 0x11fc0] = (uptr)&PS2MEM_ROM[i << 16]; + psxMemWLUT[i + 0x19fc0] = (uptr)&PS2MEM_ROM[i << 16]; + psxMemWLUT[i + 0x1bfc0] = (uptr)&PS2MEM_ROM[i << 16]; + } + + for (int i=0; i<0x0004; i++) + { + psxMemWLUT[i + 0x11e00] = (uptr)&PS2MEM_ROM1[i << 16]; + psxMemWLUT[i + 0x19e00] = (uptr)&PS2MEM_ROM1[i << 16]; + psxMemWLUT[i + 0x1be00] = (uptr)&PS2MEM_ROM1[i << 16]; + } + + // Scratchpad! (which is read only? (air)) + psxMemWLUT[0x11d00] = (uptr)psxS; + psxMemWLUT[0x1bd00] = (uptr)psxS; + + // why isn't scratchpad read/write? (air) + //for (i=0; i<0x0001; i++) psxMemWLUT[i + 0x1d00] = (uptr)&psxS[i << 16]; + //for (i=0; i<0x0001; i++) psxMemWLUT[i + 0xbd00] = (uptr)&psxS[i << 16]; + + // this one looks like an old hack for some special write-only memory area, + // but leaving it in for reference (air) + //for (i=0; i<0x0008; i++) psxMemWLUT[i + 0xbfc0] = (uptr)&psR[i << 16]; +} + +void psxMemShutdown() +{ + vtlb_free( m_psxAllMem, m_psxMemSize ); + m_psxAllMem = NULL; + //safe_aligned_free( m_psxAllMem ); + + psxM = psxP = psxH = psxS = NULL; + + safe_aligned_free(psxMemWLUT); + psxMemRLUT = NULL; +} + +u8 psxMemRead8(u32 mem) { + const u8* p; + u32 t; + + t = (mem >> 16) & 0x1fff; + if (t == 0x1f80) { + mem&= 0x1fffffff; + if (mem < 0x1f801000) + return psxHu8(mem); + else + return psxHwRead8(mem); + } else + if (t == 0x1f40) { + mem&= 0x1fffffff; + return psxHw4Read8(mem); + } else { + p = (const u8*)(psxMemRLUT[mem >> 16]); + if (p != NULL) { + return *(const u8 *)(p + (mem & 0xffff)); + } else { + if (t == 0x1000) return DEV9read8(mem & 0x1FFFFFFF); + PSXMEM_LOG("err lb %8.8lx\n", mem); + return 0; + } + } +} + +u16 psxMemRead16(u32 mem) { + const u8* p; + u32 t; + + t = (mem >> 16) & 0x1fff; + if (t == 0x1f80) { + mem&= 0x1fffffff; + if (mem < 0x1f801000) + return psxHu16(mem); + else + return psxHwRead16(mem); + } else { + p = (const u8*)(psxMemRLUT[mem >> 16]); + if (p != NULL) { + if (t == 0x1d00) { + u16 ret; + switch(mem & 0xF0) + { + case 0x00: + ret= psHu16(0x1000F200); + break; + case 0x10: + ret= psHu16(0x1000F210); + break; + case 0x40: + ret= psHu16(0x1000F240) | 0x0002; + break; + case 0x60: + ret = 0; + break; + default: + ret = psxHu16(mem); + break; + } + SIF_LOG("Sif reg read %x value %x\n", mem, ret); + return ret; + } + return *(const u16 *)(p + (mem & 0xffff)); + } else { + if (t == 0x1F90) + return SPU2read(mem & 0x1FFFFFFF); + if (t == 0x1000) return DEV9read16(mem & 0x1FFFFFFF); + PSXMEM_LOG("err lh %8.8lx\n", mem); + return 0; + } + } +} + +u32 psxMemRead32(u32 mem) { + const u8* p; + u32 t; + t = (mem >> 16) & 0x1fff; + if (t == 0x1f80) { + mem&= 0x1fffffff; + if (mem < 0x1f801000) + return psxHu32(mem); + else + return psxHwRead32(mem); + } else { + //see also Hw.c + p = (const u8*)(psxMemRLUT[mem >> 16]); + if (p != NULL) { + if (t == 0x1d00) { + u32 ret; + switch(mem & 0xF0) + { + case 0x00: + ret= psHu32(0x1000F200); + break; + case 0x10: + ret= psHu32(0x1000F210); + break; + case 0x20: + ret= psHu32(0x1000F220); + break; + case 0x30: // EE Side + ret= psHu32(0x1000F230); + break; + case 0x40: + ret= psHu32(0x1000F240) | 0xF0000002; + break; + case 0x60: + ret = 0; + break; + default: + ret = psxHu32(mem); + break; + } + SIF_LOG("Sif reg read %x value %x\n", mem, ret); + return ret; + } + return *(const u32 *)(p + (mem & 0xffff)); + } else { + if (t == 0x1000) return DEV9read32(mem & 0x1FFFFFFF); + + if (mem != 0xfffe0130) { +#ifdef PSXMEM_LOG + if (g_psxWriteOk) PSXMEM_LOG("err lw %8.8lx\n", mem); +#endif + } else { + return writectrl; + } + return 0; + } + } +} + +void psxMemWrite8(u32 mem, u8 value) { + char *p; + u32 t; + + t = (mem >> 16) & 0x1fff; + if (t == 0x1f80) { + mem&= 0x1fffffff; + if (mem < 0x1f801000) + psxHu8(mem) = value; + else + psxHwWrite8(mem, value); + } else + if (t == 0x1f40) { + mem&= 0x1fffffff; + psxHw4Write8(mem, value); + } else { + p = (char *)(psxMemWLUT[mem >> 16]); + if (p != NULL) { + *(u8 *)(p + (mem & 0xffff)) = value; + psxCpu->Clear(mem&~3, 1); + } else { + if ((t & 0x1FFF)==0x1D00) SysPrintf("sw8 [0x%08X]=0x%08X\n", mem, value); + if (t == 0x1d00) { + psxSu8(mem) = value; return; + } + if (t == 0x1000) { + DEV9write8(mem & 0x1fffffff, value); return; + } + PSXMEM_LOG("err sb %8.8lx = %x\n", mem, value); + } + } +} + +void psxMemWrite16(u32 mem, u16 value) { + char *p; + u32 t; + + t = (mem >> 16) & 0x1fff; + if (t == 0x1f80) { + mem&= 0x1fffffff; + if (mem < 0x1f801000) + psxHu16(mem) = value; + else + psxHwWrite16(mem, value); + } else { + p = (char *)(psxMemWLUT[mem >> 16]); + if (p != NULL) { + if ((t & 0x1FFF)==0x1D00) SysPrintf("sw16 [0x%08X]=0x%08X\n", mem, value); + *(u16 *)(p + (mem & 0xffff)) = value; + psxCpu->Clear(mem&~3, 1); + } else { + if (t == 0x1d00) { + switch (mem & 0xf0) { + case 0x10: + // write to ps2 mem + psHu16(0x1000F210) = value; + return; + case 0x40: + { + u32 temp = value & 0xF0; + // write to ps2 mem + if(value & 0x20 || value & 0x80) + { + psHu16(0x1000F240) &= ~0xF000; + psHu16(0x1000F240) |= 0x2000; + } + + + if(psHu16(0x1000F240) & temp) psHu16(0x1000F240) &= ~temp; + else psHu16(0x1000F240) |= temp; + return; + } + case 0x60: + psHu32(0x1000F260) = 0; + return; + + } + psxSu16(mem) = value; return; + } + if (t == 0x1F90) { + SPU2write(mem & 0x1FFFFFFF, value); return; + } + if (t == 0x1000) { + DEV9write16(mem & 0x1fffffff, value); return; + } + PSXMEM_LOG("err sh %8.8lx = %x\n", mem, value); + } + } +} + +void psxMemWrite32(u32 mem, u32 value) { + char *p; + u32 t; + + t = (mem >> 16) & 0x1fff; + if (t == 0x1f80) { + mem&= 0x1fffffff; + if (mem < 0x1f801000) + psxHu32(mem) = value; + else + psxHwWrite32(mem, value); + } else { + //see also Hw.c + p = (char *)(psxMemWLUT[mem >> 16]); + if (p != NULL) { + *(u32 *)(p + (mem & 0xffff)) = value; + psxCpu->Clear(mem&~3, 1); + } else { + if (mem != 0xfffe0130) { + if (t == 0x1d00) { + MEM_LOG("iop Sif reg write %x value %x\n", mem, value); + switch (mem & 0xf0) { + case 0x10: + // write to ps2 mem + psHu32(0x1000F210) = value; + return; + case 0x20: + // write to ps2 mem + psHu32(0x1000F220) &= ~value; + return; + case 0x30: + // write to ps2 mem + psHu32(0x1000F230) |= value; + return; + case 0x40: + { + u32 temp = value & 0xF0; + // write to ps2 mem + if(value & 0x20 || value & 0x80) + { + psHu32(0x1000F240) &= ~0xF000; + psHu32(0x1000F240) |= 0x2000; + } + + + if(psHu32(0x1000F240) & temp) psHu32(0x1000F240) &= ~temp; + else psHu32(0x1000F240) |= temp; + return; + } + case 0x60: + psHu32(0x1000F260) = 0; + return; + + } + psxSu32(mem) = value; + + // write to ps2 mem + if( (mem & 0xf0) != 0x60 ) + *(u32*)(PS2MEM_HW+0xf200+(mem&0xf0)) = value; + return; + } + if (t == 0x1000) { + DEV9write32(mem & 0x1fffffff, value); return; + } + + //if (!g_psxWriteOk) psxCpu->Clear(mem&~3, 1); + if (g_psxWriteOk) { PSXMEM_LOG("err sw %8.8lx = %x\n", mem, value); } + } else { + writectrl = value; + switch (value) { + case 0x800: case 0x804: + case 0xc00: case 0xc04: + case 0xcc0: case 0xcc4: + case 0x0c4: + if (g_psxWriteOk == 0) break; + g_psxWriteOk = 0; + + // Performance note: Use a for loop instead of memset/memzero + // This generates *much* more efficient code in this particular case (due to few iterations) + for (int i=0; i<0x0080; i++) + { + psxMemWLUT[i + 0x0000] = 0; + psxMemWLUT[i + 0x8000] = 0; + psxMemWLUT[i + 0xa000] = 0; + } + //PSXMEM_LOG("writectrl: writenot ok\n"); + break; + case 0x1e988: + case 0x1edd8: + if (g_psxWriteOk == 1) break; + g_psxWriteOk = 1; + for (int i=0; i<0x0080; i++) + { + psxMemWLUT[i + 0x0000] = (uptr)&psxM[(i & 0x1f) << 16]; + psxMemWLUT[i + 0x8000] = (uptr)&psxM[(i & 0x1f) << 16]; + psxMemWLUT[i + 0xa000] = (uptr)&psxM[(i & 0x1f) << 16]; + } + //PSXMEM_LOG("writectrl: write ok\n"); + break; + default: + PSXMEM_LOG("unk %8.8lx = %x\n", mem, value); + break; + } + } + } + } +} + +#endif diff --git a/pcsx2/IopMem.h b/pcsx2/IopMem.h index 93d6e26eda..cb9498c42d 100644 --- a/pcsx2/IopMem.h +++ b/pcsx2/IopMem.h @@ -1,103 +1,103 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __PSXMEMORY_H__ -#define __PSXMEMORY_H__ - -extern u8 *psxM; -extern u8 *psxP; -extern u8 *psxH; -extern u8 *psxS; -extern uptr *psxMemWLUT; -extern const uptr *psxMemRLUT; - -#ifdef TLB_DEBUG_MEM -void* PSXM(u32 mem); -void* _PSXM(u32 mem); -#else -#define PSXM(mem) (psxMemRLUT[(mem) >> 16] == 0 ? NULL : (void*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff))) -#define _PSXM(mem) ((const void*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff))) -#endif - -#define psxSs8(mem) psxS[(mem) & 0xffff] -#define psxSs16(mem) (*(s16*)&psxS[(mem) & 0xffff]) -#define psxSs32(mem) (*(s32*)&psxS[(mem) & 0xffff]) -#define psxSu8(mem) (*(u8*) &psxS[(mem) & 0xffff]) -#define psxSu16(mem) (*(u16*)&psxS[(mem) & 0xffff]) -#define psxSu32(mem) (*(u32*)&psxS[(mem) & 0xffff]) - -#define psxMs8(mem) psxM[(mem) & 0x1fffff] -#define psxMs16(mem) (*(s16*)&psxM[(mem) & 0x1fffff]) -#define psxMs32(mem) (*(s32*)&psxM[(mem) & 0x1fffff]) -#define psxMu8(mem) (*(u8*) &psxM[(mem) & 0x1fffff]) -#define psxMu16(mem) (*(u16*)&psxM[(mem) & 0x1fffff]) -#define psxMu32(mem) (*(u32*)&psxM[(mem) & 0x1fffff]) -#define psxMu64(mem) (*(u64*)&psxM[(mem) & 0x1fffff]) - -#define psxPs8(mem) psxP[(mem) & 0xffff] -#define psxPs16(mem) (*(s16*)&psxP[(mem) & 0xffff]) -#define psxPs32(mem) (*(s32*)&psxP[(mem) & 0xffff]) -#define psxPu8(mem) (*(u8*) &psxP[(mem) & 0xffff]) -#define psxPu16(mem) (*(u16*)&psxP[(mem) & 0xffff]) -#define psxPu32(mem) (*(u32*)&psxP[(mem) & 0xffff]) - -#define psxHs8(mem) psxH[(mem) & 0xffff] -#define psxHs16(mem) (*(s16*)&psxH[(mem) & 0xffff]) -#define psxHs32(mem) (*(s32*)&psxH[(mem) & 0xffff]) -#define psxHu8(mem) (*(u8*) &psxH[(mem) & 0xffff]) -#define psxHu16(mem) (*(u16*)&psxH[(mem) & 0xffff]) -#define psxHu32(mem) (*(u32*)&psxH[(mem) & 0xffff]) - -#define PSXMs8(mem) (*(s8 *)_PSXM(mem)) -#define PSXMs16(mem) (*(s16*)_PSXM(mem)) -#define PSXMs32(mem) (*(s32*)_PSXM(mem)) -#define PSXMu8(mem) (*(u8 *)_PSXM(mem)) -#define PSXMu16(mem) (*(u16*)_PSXM(mem)) -#define PSXMu32(mem) (*(u32*)_PSXM(mem)) - -void psxMemAlloc(); -void psxMemReset(); -void psxMemShutdown(); - -u8 psxMemRead8 (u32 mem); -u16 psxMemRead16(u32 mem); -u32 psxMemRead32(u32 mem); -void psxMemWrite8 (u32 mem, u8 value); -void psxMemWrite16(u32 mem, u16 value); -void psxMemWrite32(u32 mem, u32 value); - -// x86reg and mmreg are always x86 regs -void psxRecMemRead8(); -int psxRecMemConstRead8(u32 x86reg, u32 mem, u32 sign); - -void psxRecMemRead16(); -int psxRecMemConstRead16(u32 x86reg, u32 mem, u32 sign); - -void psxRecMemRead32(); -int psxRecMemConstRead32(u32 x86reg, u32 mem); - -void psxRecMemWrite8(); -int psxRecMemConstWrite8(u32 mem, int mmreg); - -void psxRecMemWrite16(); -int psxRecMemConstWrite16(u32 mem, int mmreg); - -void psxRecMemWrite32(); -int psxRecMemConstWrite32(u32 mem, int mmreg); - -#endif /* __PSXMEMORY_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __PSXMEMORY_H__ +#define __PSXMEMORY_H__ + +extern u8 *psxM; +extern u8 *psxP; +extern u8 *psxH; +extern u8 *psxS; +extern uptr *psxMemWLUT; +extern const uptr *psxMemRLUT; + +#ifdef TLB_DEBUG_MEM +void* PSXM(u32 mem); +void* _PSXM(u32 mem); +#else +#define PSXM(mem) (psxMemRLUT[(mem) >> 16] == 0 ? NULL : (void*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff))) +#define _PSXM(mem) ((const void*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff))) +#endif + +#define psxSs8(mem) psxS[(mem) & 0xffff] +#define psxSs16(mem) (*(s16*)&psxS[(mem) & 0xffff]) +#define psxSs32(mem) (*(s32*)&psxS[(mem) & 0xffff]) +#define psxSu8(mem) (*(u8*) &psxS[(mem) & 0xffff]) +#define psxSu16(mem) (*(u16*)&psxS[(mem) & 0xffff]) +#define psxSu32(mem) (*(u32*)&psxS[(mem) & 0xffff]) + +#define psxMs8(mem) psxM[(mem) & 0x1fffff] +#define psxMs16(mem) (*(s16*)&psxM[(mem) & 0x1fffff]) +#define psxMs32(mem) (*(s32*)&psxM[(mem) & 0x1fffff]) +#define psxMu8(mem) (*(u8*) &psxM[(mem) & 0x1fffff]) +#define psxMu16(mem) (*(u16*)&psxM[(mem) & 0x1fffff]) +#define psxMu32(mem) (*(u32*)&psxM[(mem) & 0x1fffff]) +#define psxMu64(mem) (*(u64*)&psxM[(mem) & 0x1fffff]) + +#define psxPs8(mem) psxP[(mem) & 0xffff] +#define psxPs16(mem) (*(s16*)&psxP[(mem) & 0xffff]) +#define psxPs32(mem) (*(s32*)&psxP[(mem) & 0xffff]) +#define psxPu8(mem) (*(u8*) &psxP[(mem) & 0xffff]) +#define psxPu16(mem) (*(u16*)&psxP[(mem) & 0xffff]) +#define psxPu32(mem) (*(u32*)&psxP[(mem) & 0xffff]) + +#define psxHs8(mem) psxH[(mem) & 0xffff] +#define psxHs16(mem) (*(s16*)&psxH[(mem) & 0xffff]) +#define psxHs32(mem) (*(s32*)&psxH[(mem) & 0xffff]) +#define psxHu8(mem) (*(u8*) &psxH[(mem) & 0xffff]) +#define psxHu16(mem) (*(u16*)&psxH[(mem) & 0xffff]) +#define psxHu32(mem) (*(u32*)&psxH[(mem) & 0xffff]) + +#define PSXMs8(mem) (*(s8 *)_PSXM(mem)) +#define PSXMs16(mem) (*(s16*)_PSXM(mem)) +#define PSXMs32(mem) (*(s32*)_PSXM(mem)) +#define PSXMu8(mem) (*(u8 *)_PSXM(mem)) +#define PSXMu16(mem) (*(u16*)_PSXM(mem)) +#define PSXMu32(mem) (*(u32*)_PSXM(mem)) + +void psxMemAlloc(); +void psxMemReset(); +void psxMemShutdown(); + +u8 psxMemRead8 (u32 mem); +u16 psxMemRead16(u32 mem); +u32 psxMemRead32(u32 mem); +void psxMemWrite8 (u32 mem, u8 value); +void psxMemWrite16(u32 mem, u16 value); +void psxMemWrite32(u32 mem, u32 value); + +// x86reg and mmreg are always x86 regs +void psxRecMemRead8(); +int psxRecMemConstRead8(u32 x86reg, u32 mem, u32 sign); + +void psxRecMemRead16(); +int psxRecMemConstRead16(u32 x86reg, u32 mem, u32 sign); + +void psxRecMemRead32(); +int psxRecMemConstRead32(u32 x86reg, u32 mem); + +void psxRecMemWrite8(); +int psxRecMemConstWrite8(u32 mem, int mmreg); + +void psxRecMemWrite16(); +int psxRecMemConstWrite16(u32 mem, int mmreg); + +void psxRecMemWrite32(); +int psxRecMemConstWrite32(u32 mem, int mmreg); + +#endif /* __PSXMEMORY_H__ */ diff --git a/pcsx2/IopSio2.cpp b/pcsx2/IopSio2.cpp index d46502728b..8ec6a926df 100644 --- a/pcsx2/IopSio2.cpp +++ b/pcsx2/IopSio2.cpp @@ -1,266 +1,266 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "PsxCommon.h" - -sio2Struct sio2; - -/* -w [8268]=0x3bc sio2_start/sio2man -r [8270] padman_start/padman - padman->7480[00]=bit4; - padman->7480[13]=bit5; - packetExchange(&703F8); -w [8268]|=0x0C; -........ -w [8268]|=0x01; - -only recv2 & dataout influences padman -*/ - -// 0xBF808200,0xBF808204,0xBF808208,0xBF80820C, -// 0xBF808210,0xBF808214,0xBF808218,0xBF80821C, packet->sendArray3 -// 0xBF808220,0xBF808224,0xBF808228,0xBF80822C, call12/13_s/getparams -// 0xBF808230,0xBF808234,0xBF808238,0xBF80823C, - -// 0xBF808240,0xBF808248,0xBF808250,0xBF808258, packet->sendArray1/call_7/8 -// 0xBF808244,0xBF80824C,0xBF808254,0xBF80825C, packet->sendArray2/call_9/10 - -// 0xBF808260, serial data/fifo in/out s/get8260_datain/out packet->sendbuf(nomem!) -// 0xBF808268, ctrl s/get8268_ctrl - -// 0xBF80826C, packet->recv1/2/3 get826C_recv1, get8270_recv2, get8274_recv3 -// 0xBF808270,0xBF808274, - -// 0xBF808278,0xBF80827C, s/get8278, s/get827C -// 0xBF808280 interrupt related s/get8280_intr - - -void sio2Reset() { - DevCon::Status( "Sio2 Reset" ); - memzero_obj(sio2); - sio2.packet.recvVal1 = 0x1D100; // Nothing is connected at start -} - -u32 sio2_getRecv1() { - PAD_LOG("Reading Recv1 = %x\n",sio2.packet.recvVal1); - - return sio2.packet.recvVal1; -} - -u32 sio2_getRecv2() { - PAD_LOG("Reading Recv2 = %x\n",0xF); - - return 0xf; -}//0, 0x10, 0x20, 0x10 | 0x20; bits 4 & 5 - -u32 sio2_getRecv3() { - if(sio2.packet.recvVal3 == 0x8C || sio2.packet.recvVal3 == 0x8b || - sio2.packet.recvVal3 == 0x83) - { - PAD_LOG("Reading Recv3 = %x\n",sio2.packet.recvVal3); - - sio.packetsize = sio2.packet.recvVal3; - sio2.packet.recvVal3 = 0; // Reset - return sio.packetsize; - } - else - { - PAD_LOG("Reading Recv3 = %x\n",sio.packetsize << 16); - - return sio.packetsize << 16; - } -} - -void sio2_setSend1(u32 index, u32 value){sio2.packet.sendArray1[index]=value;} //0->3 -u32 sio2_getSend1(u32 index){return sio2.packet.sendArray1[index];} //0->3 -void sio2_setSend2(u32 index, u32 value){sio2.packet.sendArray2[index]=value;} //0->3 -u32 sio2_getSend2(u32 index){return sio2.packet.sendArray2[index];} //0->3 - -void sio2_setSend3(u32 index, u32 value) -{ -// int i; - sio2.packet.sendArray3[index]=value; -// if (index==15){ -// for (i=0; i<4; i++){PAD_LOG("0x%08X ", sio2.packet.sendArray1[i]);}PAD_LOG("\n"); -// for (i=0; i<4; i++){PAD_LOG("0x%08X ", sio2.packet.sendArray2[i]);}PAD_LOG("\n"); -// for (i=0; i<8; i++){PAD_LOG("0x%08X ", sio2.packet.sendArray3[i]);}PAD_LOG("\n"); -// for ( ; i<16; i++){PAD_LOG("0x%08X ", sio2.packet.sendArray3[i]);}PAD_LOG("\n"); - PAD_LOG("[%d] : 0x%08X\n", index,sio2.packet.sendArray3[index]); -// } -} //0->15 - -u32 sio2_getSend3(u32 index) {return sio2.packet.sendArray3[index];} //0->15 - -void sio2_setCtrl(u32 value){ - sio2.ctrl=value; - if (sio2.ctrl & 1){ //recv packet - //handle data that had been sent - - iopIntcIrq( 17 ); - //SBUS - sio2.recvIndex=0; - sio2.ctrl &= ~1; - } else { // send packet - //clean up - sio2.packet.sendSize=0; //reset size - sio2.cmdport=0; - sio2.cmdlength=0; - sioWriteCtrl16(SIO_RESET); - } -} -u32 sio2_getCtrl(){return sio2.ctrl;} - -void sio2_setIntr(u32 value){sio2.intr=value;} -u32 sio2_getIntr(){ - return sio2.intr; -} - -void sio2_set8278(u32 value){sio2._8278=value;} -u32 sio2_get8278(){return sio2._8278;} -void sio2_set827C(u32 value){sio2._827C=value;} -u32 sio2_get827C(){return sio2._827C;} - -void sio2_serialIn(u8 value){ - u16 ctrl=0x0002; - if (sio2.packet.sendArray3[sio2.cmdport] && (sio2.cmdlength==0)) - { - - sio2.cmdlength=(sio2.packet.sendArray3[sio2.cmdport] >> 8) & 0x1FF; - ctrl &= ~0x2000; - ctrl |= (sio2.packet.sendArray3[sio2.cmdport] & 1) << 13; - //sioWriteCtrl16(SIO_RESET); - sioWriteCtrl16(ctrl); - PSXDMA_LOG("sio2_fifoIn: ctrl = %x, cmdlength = %x, cmdport = %d (%x)\n", ctrl, sio2.cmdlength, sio2.cmdport, sio2.packet.sendArray3[sio2.cmdport]); - - sio2.cmdport++; - } - - if (sio2.cmdlength) sio2.cmdlength--; - sioWrite8(value); - - if (sio2.packet.sendSize > BUFSIZE) {//asadr - Console::Notice("*PCSX2*: sendSize >= %d", params BUFSIZE); - } else { - sio2.buf[sio2.packet.sendSize] = sioRead8(); - sio2.packet.sendSize++; - } -} -extern void SIODMAWrite(u8 value); - -void sio2_fifoIn(u8 value){ - u16 ctrl=0x0002; - if (sio2.packet.sendArray3[sio2.cmdport] && (sio2.cmdlength==0)) - { - - sio2.cmdlength=(sio2.packet.sendArray3[sio2.cmdport] >> 8) & 0x1FF; - ctrl &= ~0x2000; - ctrl |= (sio2.packet.sendArray3[sio2.cmdport] & 1) << 13; - //sioWriteCtrl16(SIO_RESET); - sioWriteCtrl16(ctrl); - PSXDMA_LOG("sio2_fifoIn: ctrl = %x, cmdlength = %x, cmdport = %d (%x)\n", ctrl, sio2.cmdlength, sio2.cmdport, sio2.packet.sendArray3[sio2.cmdport]); - - sio2.cmdport++; - } - - if (sio2.cmdlength) sio2.cmdlength--; - SIODMAWrite(value); - - if (sio2.packet.sendSize > BUFSIZE) {//asadr - SysPrintf("*PCSX2*: sendSize >= %d\n", BUFSIZE); - } else { - sio2.buf[sio2.packet.sendSize] = sioRead8(); - sio2.packet.sendSize++; - } -} - -u8 sio2_fifoOut(){ - if (sio2.recvIndex <= sio2.packet.sendSize){ - //PAD_LOG("READING %x\n",sio2.buf[sio2.recvIndex]); - return sio2.buf[sio2.recvIndex++]; - } else { - Console::Error( "*PCSX2*: buffer overrun" ); - } - return 0; // No Data -} - -void SaveState::sio2Freeze() -{ - Freeze(sio2); -} - -///////////////////////////////////////////////// -//////////////////////////////////////////// DMA -///////////////////////////////////////////////// - -void psxDma11(u32 madr, u32 bcr, u32 chcr) { - unsigned int i, j; - int size = (bcr >> 16) * (bcr & 0xffff); - PSXDMA_LOG("*** DMA 11 - SIO2 in *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); - - if (chcr != 0x01000201) return; - - for(i = 0; i < (bcr >> 16); i++) - { - sio.count = 1; - for(j = 0; j < ((bcr & 0xFFFF) * 4); j++) - { - sio2_fifoIn(PSXMu8(madr)); - madr++; - if(sio2.packet.sendSize == BUFSIZE) - goto finished; - } - } - -finished: - HW_DMA11_MADR = madr; - PSX_INT(IopEvt_Dma11,(size>>2)); // Interrupts should always occur at the end -} - -void psxDMA11Interrupt() -{ - HW_DMA11_CHCR &= ~0x01000000; - psxDmaInterrupt2(4); -} - -void psxDma12(u32 madr, u32 bcr, u32 chcr) { - int size = ((bcr >> 16) * (bcr & 0xFFFF)) * 4; - PSXDMA_LOG("*** DMA 12 - SIO2 out *** %lx addr = %lx size = %lx\n", chcr, madr, size); - - if (chcr != 0x41000200) return; - - sio2.recvIndex = 0; // Set To start; saqib - - bcr = size; - while (bcr > 0) { - PSXMu8(madr) = sio2_fifoOut(); - bcr--; madr++; - if(sio2.recvIndex == sio2.packet.sendSize) break; - } - HW_DMA12_MADR = madr; - PSX_INT(IopEvt_Dma12,(size>>2)); // Interrupts should always occur at the end -} - -void psxDMA12Interrupt() -{ - HW_DMA12_CHCR &= ~0x01000000; - psxDmaInterrupt2(5); -} - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "PsxCommon.h" + +sio2Struct sio2; + +/* +w [8268]=0x3bc sio2_start/sio2man +r [8270] padman_start/padman + padman->7480[00]=bit4; + padman->7480[13]=bit5; + packetExchange(&703F8); +w [8268]|=0x0C; +........ +w [8268]|=0x01; + +only recv2 & dataout influences padman +*/ + +// 0xBF808200,0xBF808204,0xBF808208,0xBF80820C, +// 0xBF808210,0xBF808214,0xBF808218,0xBF80821C, packet->sendArray3 +// 0xBF808220,0xBF808224,0xBF808228,0xBF80822C, call12/13_s/getparams +// 0xBF808230,0xBF808234,0xBF808238,0xBF80823C, + +// 0xBF808240,0xBF808248,0xBF808250,0xBF808258, packet->sendArray1/call_7/8 +// 0xBF808244,0xBF80824C,0xBF808254,0xBF80825C, packet->sendArray2/call_9/10 + +// 0xBF808260, serial data/fifo in/out s/get8260_datain/out packet->sendbuf(nomem!) +// 0xBF808268, ctrl s/get8268_ctrl + +// 0xBF80826C, packet->recv1/2/3 get826C_recv1, get8270_recv2, get8274_recv3 +// 0xBF808270,0xBF808274, + +// 0xBF808278,0xBF80827C, s/get8278, s/get827C +// 0xBF808280 interrupt related s/get8280_intr + + +void sio2Reset() { + DevCon::Status( "Sio2 Reset" ); + memzero_obj(sio2); + sio2.packet.recvVal1 = 0x1D100; // Nothing is connected at start +} + +u32 sio2_getRecv1() { + PAD_LOG("Reading Recv1 = %x\n",sio2.packet.recvVal1); + + return sio2.packet.recvVal1; +} + +u32 sio2_getRecv2() { + PAD_LOG("Reading Recv2 = %x\n",0xF); + + return 0xf; +}//0, 0x10, 0x20, 0x10 | 0x20; bits 4 & 5 + +u32 sio2_getRecv3() { + if(sio2.packet.recvVal3 == 0x8C || sio2.packet.recvVal3 == 0x8b || + sio2.packet.recvVal3 == 0x83) + { + PAD_LOG("Reading Recv3 = %x\n",sio2.packet.recvVal3); + + sio.packetsize = sio2.packet.recvVal3; + sio2.packet.recvVal3 = 0; // Reset + return sio.packetsize; + } + else + { + PAD_LOG("Reading Recv3 = %x\n",sio.packetsize << 16); + + return sio.packetsize << 16; + } +} + +void sio2_setSend1(u32 index, u32 value){sio2.packet.sendArray1[index]=value;} //0->3 +u32 sio2_getSend1(u32 index){return sio2.packet.sendArray1[index];} //0->3 +void sio2_setSend2(u32 index, u32 value){sio2.packet.sendArray2[index]=value;} //0->3 +u32 sio2_getSend2(u32 index){return sio2.packet.sendArray2[index];} //0->3 + +void sio2_setSend3(u32 index, u32 value) +{ +// int i; + sio2.packet.sendArray3[index]=value; +// if (index==15){ +// for (i=0; i<4; i++){PAD_LOG("0x%08X ", sio2.packet.sendArray1[i]);}PAD_LOG("\n"); +// for (i=0; i<4; i++){PAD_LOG("0x%08X ", sio2.packet.sendArray2[i]);}PAD_LOG("\n"); +// for (i=0; i<8; i++){PAD_LOG("0x%08X ", sio2.packet.sendArray3[i]);}PAD_LOG("\n"); +// for ( ; i<16; i++){PAD_LOG("0x%08X ", sio2.packet.sendArray3[i]);}PAD_LOG("\n"); + PAD_LOG("[%d] : 0x%08X\n", index,sio2.packet.sendArray3[index]); +// } +} //0->15 + +u32 sio2_getSend3(u32 index) {return sio2.packet.sendArray3[index];} //0->15 + +void sio2_setCtrl(u32 value){ + sio2.ctrl=value; + if (sio2.ctrl & 1){ //recv packet + //handle data that had been sent + + iopIntcIrq( 17 ); + //SBUS + sio2.recvIndex=0; + sio2.ctrl &= ~1; + } else { // send packet + //clean up + sio2.packet.sendSize=0; //reset size + sio2.cmdport=0; + sio2.cmdlength=0; + sioWriteCtrl16(SIO_RESET); + } +} +u32 sio2_getCtrl(){return sio2.ctrl;} + +void sio2_setIntr(u32 value){sio2.intr=value;} +u32 sio2_getIntr(){ + return sio2.intr; +} + +void sio2_set8278(u32 value){sio2._8278=value;} +u32 sio2_get8278(){return sio2._8278;} +void sio2_set827C(u32 value){sio2._827C=value;} +u32 sio2_get827C(){return sio2._827C;} + +void sio2_serialIn(u8 value){ + u16 ctrl=0x0002; + if (sio2.packet.sendArray3[sio2.cmdport] && (sio2.cmdlength==0)) + { + + sio2.cmdlength=(sio2.packet.sendArray3[sio2.cmdport] >> 8) & 0x1FF; + ctrl &= ~0x2000; + ctrl |= (sio2.packet.sendArray3[sio2.cmdport] & 1) << 13; + //sioWriteCtrl16(SIO_RESET); + sioWriteCtrl16(ctrl); + PSXDMA_LOG("sio2_fifoIn: ctrl = %x, cmdlength = %x, cmdport = %d (%x)\n", ctrl, sio2.cmdlength, sio2.cmdport, sio2.packet.sendArray3[sio2.cmdport]); + + sio2.cmdport++; + } + + if (sio2.cmdlength) sio2.cmdlength--; + sioWrite8(value); + + if (sio2.packet.sendSize > BUFSIZE) {//asadr + Console::Notice("*PCSX2*: sendSize >= %d", params BUFSIZE); + } else { + sio2.buf[sio2.packet.sendSize] = sioRead8(); + sio2.packet.sendSize++; + } +} +extern void SIODMAWrite(u8 value); + +void sio2_fifoIn(u8 value){ + u16 ctrl=0x0002; + if (sio2.packet.sendArray3[sio2.cmdport] && (sio2.cmdlength==0)) + { + + sio2.cmdlength=(sio2.packet.sendArray3[sio2.cmdport] >> 8) & 0x1FF; + ctrl &= ~0x2000; + ctrl |= (sio2.packet.sendArray3[sio2.cmdport] & 1) << 13; + //sioWriteCtrl16(SIO_RESET); + sioWriteCtrl16(ctrl); + PSXDMA_LOG("sio2_fifoIn: ctrl = %x, cmdlength = %x, cmdport = %d (%x)\n", ctrl, sio2.cmdlength, sio2.cmdport, sio2.packet.sendArray3[sio2.cmdport]); + + sio2.cmdport++; + } + + if (sio2.cmdlength) sio2.cmdlength--; + SIODMAWrite(value); + + if (sio2.packet.sendSize > BUFSIZE) {//asadr + SysPrintf("*PCSX2*: sendSize >= %d\n", BUFSIZE); + } else { + sio2.buf[sio2.packet.sendSize] = sioRead8(); + sio2.packet.sendSize++; + } +} + +u8 sio2_fifoOut(){ + if (sio2.recvIndex <= sio2.packet.sendSize){ + //PAD_LOG("READING %x\n",sio2.buf[sio2.recvIndex]); + return sio2.buf[sio2.recvIndex++]; + } else { + Console::Error( "*PCSX2*: buffer overrun" ); + } + return 0; // No Data +} + +void SaveState::sio2Freeze() +{ + Freeze(sio2); +} + +///////////////////////////////////////////////// +//////////////////////////////////////////// DMA +///////////////////////////////////////////////// + +void psxDma11(u32 madr, u32 bcr, u32 chcr) { + unsigned int i, j; + int size = (bcr >> 16) * (bcr & 0xffff); + PSXDMA_LOG("*** DMA 11 - SIO2 in *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); + + if (chcr != 0x01000201) return; + + for(i = 0; i < (bcr >> 16); i++) + { + sio.count = 1; + for(j = 0; j < ((bcr & 0xFFFF) * 4); j++) + { + sio2_fifoIn(PSXMu8(madr)); + madr++; + if(sio2.packet.sendSize == BUFSIZE) + goto finished; + } + } + +finished: + HW_DMA11_MADR = madr; + PSX_INT(IopEvt_Dma11,(size>>2)); // Interrupts should always occur at the end +} + +void psxDMA11Interrupt() +{ + HW_DMA11_CHCR &= ~0x01000000; + psxDmaInterrupt2(4); +} + +void psxDma12(u32 madr, u32 bcr, u32 chcr) { + int size = ((bcr >> 16) * (bcr & 0xFFFF)) * 4; + PSXDMA_LOG("*** DMA 12 - SIO2 out *** %lx addr = %lx size = %lx\n", chcr, madr, size); + + if (chcr != 0x41000200) return; + + sio2.recvIndex = 0; // Set To start; saqib + + bcr = size; + while (bcr > 0) { + PSXMu8(madr) = sio2_fifoOut(); + bcr--; madr++; + if(sio2.recvIndex == sio2.packet.sendSize) break; + } + HW_DMA12_MADR = madr; + PSX_INT(IopEvt_Dma12,(size>>2)); // Interrupts should always occur at the end +} + +void psxDMA12Interrupt() +{ + HW_DMA12_CHCR &= ~0x01000000; + psxDmaInterrupt2(5); +} + diff --git a/pcsx2/IopSio2.h b/pcsx2/IopSio2.h index b8642462f0..34f9e8f388 100644 --- a/pcsx2/IopSio2.h +++ b/pcsx2/IopSio2.h @@ -1,99 +1,99 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __PSXSIO2_H__ -#define __PSXSIO2_H__ - - -#define BUFSIZE 8448 - -//from sio2man.c - -struct SIO2_packet { - unsigned int recvVal1; // 0x00 - unsigned int sendArray1[4]; // 0x04-0x10 - unsigned int sendArray2[4]; // 0x14-0x20 - - unsigned int recvVal2; // 0x24 - - unsigned int sendArray3[16]; // 0x28-0x64 - - unsigned int recvVal3; // 0x68 - - int sendSize; // 0x6C - int recvSize; // 0x70 - - unsigned char *sendBuf; // 0x74 - unsigned char *recvBuf; // 0x78 - - unsigned int dmacAddress1; - unsigned int dmacSize1; - unsigned int dmacCount1; - unsigned int dmacAddress2; - unsigned int dmacSize2; - unsigned int dmacCount2; -}; - -struct sio2Struct { - struct SIO2_packet packet; - u32 ctrl; - u32 intr; - u32 _8278, _827C; - int recvIndex; - u32 hackedRecv; - int cmdport; - int cmdlength; //length of a command sent to a port - //is less_equal than the dma send size - u8 buf[BUFSIZE]; -}; - -extern sio2Struct sio2; - -void sio2Reset(); - -u32 sio2_getRecv1(); -u32 sio2_getRecv2(); -u32 sio2_getRecv3(); -void sio2_setSend1(u32 index, u32 value); //0->3 -u32 sio2_getSend1(u32 index); //0->3 -void sio2_setSend2(u32 index, u32 value); //0->3 -u32 sio2_getSend2(u32 index); //0->3 -void sio2_setSend3(u32 index, u32 value); //0->15 -u32 sio2_getSend3(u32 index); //0->15 - -void sio2_setCtrl(u32 value); -u32 sio2_getCtrl(); -void sio2_setIntr(u32 value); -u32 sio2_getIntr(); -void sio2_set8278(u32 value); -u32 sio2_get8278(); -void sio2_set827C(u32 value); -u32 sio2_get827C(); - -void sio2_serialIn(u8 value); -void sio2_fifoIn(u8 value); -u8 sio2_fifoOut(); - -void psxDma11(u32 madr, u32 bcr, u32 chcr); -void psxDma12(u32 madr, u32 bcr, u32 chcr); - -void psxDMA11Interrupt(); -void psxDMA12Interrupt(); - -#endif /* __PSXSIO2_H__ */ - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __PSXSIO2_H__ +#define __PSXSIO2_H__ + + +#define BUFSIZE 8448 + +//from sio2man.c + +struct SIO2_packet { + unsigned int recvVal1; // 0x00 + unsigned int sendArray1[4]; // 0x04-0x10 + unsigned int sendArray2[4]; // 0x14-0x20 + + unsigned int recvVal2; // 0x24 + + unsigned int sendArray3[16]; // 0x28-0x64 + + unsigned int recvVal3; // 0x68 + + int sendSize; // 0x6C + int recvSize; // 0x70 + + unsigned char *sendBuf; // 0x74 + unsigned char *recvBuf; // 0x78 + + unsigned int dmacAddress1; + unsigned int dmacSize1; + unsigned int dmacCount1; + unsigned int dmacAddress2; + unsigned int dmacSize2; + unsigned int dmacCount2; +}; + +struct sio2Struct { + struct SIO2_packet packet; + u32 ctrl; + u32 intr; + u32 _8278, _827C; + int recvIndex; + u32 hackedRecv; + int cmdport; + int cmdlength; //length of a command sent to a port + //is less_equal than the dma send size + u8 buf[BUFSIZE]; +}; + +extern sio2Struct sio2; + +void sio2Reset(); + +u32 sio2_getRecv1(); +u32 sio2_getRecv2(); +u32 sio2_getRecv3(); +void sio2_setSend1(u32 index, u32 value); //0->3 +u32 sio2_getSend1(u32 index); //0->3 +void sio2_setSend2(u32 index, u32 value); //0->3 +u32 sio2_getSend2(u32 index); //0->3 +void sio2_setSend3(u32 index, u32 value); //0->15 +u32 sio2_getSend3(u32 index); //0->15 + +void sio2_setCtrl(u32 value); +u32 sio2_getCtrl(); +void sio2_setIntr(u32 value); +u32 sio2_getIntr(); +void sio2_set8278(u32 value); +u32 sio2_get8278(); +void sio2_set827C(u32 value); +u32 sio2_get827C(); + +void sio2_serialIn(u8 value); +void sio2_fifoIn(u8 value); +u8 sio2_fifoOut(); + +void psxDma11(u32 madr, u32 bcr, u32 chcr); +void psxDma12(u32 madr, u32 bcr, u32 chcr); + +void psxDMA11Interrupt(); +void psxDMA12Interrupt(); + +#endif /* __PSXSIO2_H__ */ + diff --git a/pcsx2/Linux/ConfigDlg.cpp b/pcsx2/Linux/ConfigDlg.cpp index 42944085a1..bdcec688a1 100644 --- a/pcsx2/Linux/ConfigDlg.cpp +++ b/pcsx2/Linux/ConfigDlg.cpp @@ -1,644 +1,644 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "ConfigDlg.h" - -using namespace std; -using namespace R5900; - -bool applychanges = FALSE; - -static void FindComboText(GtkWidget *combo, char plist[255][255], GList *list, char *conf) -{ - if (strlen(conf) > 0) SetActiveComboItem(GTK_COMBO_BOX(combo), plist, list, conf); -} - - -static bool GetComboText(GtkWidget *combo, char plist[255][255], char *conf) -{ - int i; - - char *tmp = (char*)gtk_combo_box_get_active_text(GTK_COMBO_BOX(combo)); - - if (tmp == NULL) return FALSE; - for (i = 2;i < 255;i += 2) - { - if (!strcmp(tmp, plist[i-1])) - { - strcpy(conf, plist[i-2]); - break; - } - } - return TRUE; -} - -static void ConfPlugin(PluginConf confs, char* plugin, const char* name) -{ - void *drv; - void (*conf)(); - char file[g_MaxPath]; - - GetComboText(confs.Combo, confs.plist, plugin); - strcpy(file, Config.PluginsDir); - strcat(file, plugin); - - drv = SysLoadLibrary(file); -#ifndef LOCAL_PLUGIN_INIS - getcwd(file, ARRAYSIZE(file)); /* store current dir */ - chdir(Config.PluginsDir); /* change dirs so that plugins can find their config file*/ -#endif - if (drv == NULL) return; - - conf = (void (*)()) SysLoadSym(drv, name); - if (SysLibError() == NULL) conf(); -#ifndef LOCAL_PLUGIN_INIS - chdir(file); /* change back*/ -#endif - SysCloseLibrary(drv); -} - - -static void TestPlugin(PluginConf confs, char* plugin, const char* name) -{ - void *drv; - s32(* (*conf)())(); - char file[g_MaxPath]; - int ret = 0; - - GetComboText(confs.Combo, confs.plist, plugin); - strcpy(file, Config.PluginsDir); - strcat(file, plugin); - - drv = SysLoadLibrary(file); - getcwd(file, ARRAYSIZE(file)); /* store current dir */ - chdir(Config.PluginsDir); /* change dirs so that plugins can find their config file*/ - if (drv == NULL) return; - - conf = (s32(* (*)())()) SysLoadSym(drv, name); - if (SysLibError() == NULL) ret = (s32) conf(); - chdir(file); /* change back*/ - SysCloseLibrary(drv); - - if (ret == 0) - Msgbox::Alert("This plugin reports that should work correctly"); - else - Msgbox::Alert("This plugin reports that should not work correctly"); -} - -void OnConf_Gs(GtkMenuItem *menuitem, gpointer user_data) -{ - char file[255]; - - getcwd(file, ARRAYSIZE(file)); - chdir(Config.PluginsDir); - gtk_widget_set_sensitive(MainWindow, FALSE); - GSconfigure(); - chdir(file); - gtk_widget_set_sensitive(MainWindow, TRUE); -} - -void OnConf_Pads(GtkMenuItem *menuitem, gpointer user_data) -{ - char file[255]; - - getcwd(file, ARRAYSIZE(file)); - chdir(Config.PluginsDir); - gtk_widget_set_sensitive(MainWindow, FALSE); - PAD1configure(); - if (strcmp(Config.PAD1, Config.PAD2)) PAD2configure(); - chdir(file); - gtk_widget_set_sensitive(MainWindow, TRUE); -} - -void OnConf_Spu2(GtkMenuItem *menuitem, gpointer user_data) -{ - char file[255]; - - getcwd(file, ARRAYSIZE(file)); - chdir(Config.PluginsDir); - gtk_widget_set_sensitive(MainWindow, FALSE); - SPU2configure(); - gtk_widget_set_sensitive(MainWindow, TRUE); - chdir(file); -} - -void OnConf_Cdvd(GtkMenuItem *menuitem, gpointer user_data) -{ - char file[255]; - - getcwd(file, ARRAYSIZE(file)); - chdir(Config.PluginsDir); - gtk_widget_set_sensitive(MainWindow, FALSE); - CDVDconfigure(); - gtk_widget_set_sensitive(MainWindow, TRUE); - chdir(file); -} - -void OnConf_Dev9(GtkMenuItem *menuitem, gpointer user_data) -{ - char file[255]; - - getcwd(file, ARRAYSIZE(file)); - chdir(Config.PluginsDir); - gtk_widget_set_sensitive(MainWindow, FALSE); - DEV9configure(); - gtk_widget_set_sensitive(MainWindow, TRUE); - chdir(file); -} - -void OnConf_Usb(GtkMenuItem *menuitem, gpointer user_data) -{ - char file[255]; - - getcwd(file, ARRAYSIZE(file)); - chdir(Config.PluginsDir); - gtk_widget_set_sensitive(MainWindow, FALSE); - USBconfigure(); - gtk_widget_set_sensitive(MainWindow, TRUE); - chdir(file); -} - -void OnConf_Fw(GtkMenuItem *menuitem, gpointer user_data) -{ - char file[255]; - - getcwd(file, ARRAYSIZE(file)); - chdir(Config.PluginsDir); - gtk_widget_set_sensitive(MainWindow, FALSE); - FWconfigure(); - gtk_widget_set_sensitive(MainWindow, TRUE); - chdir(file); -} - -void SetActiveComboItem(GtkComboBox *widget, char plist[255][255], GList *list, char *conf) -{ - GList *temp; - int i = 0, pindex = 0, item = -1; - - if (strlen(conf) > 0) - { - for (i = 2;i < 255;i += 2) - { - if (!strcmp(conf, plist[i-2])) - { - pindex = i - 1; - break; - } - } - } - - i = 0; - temp = list; - - while (temp) - { - if (!strcmp(plist[pindex], (char*)temp->data)) - item = i; - - temp = temp->next; - i++; - } - - if (item <= 0) item = 0; - gtk_combo_box_set_active(GTK_COMBO_BOX(widget), item); -} - -void OnConfConf_Ok(GtkButton *button, gpointer user_data) -{ - applychanges = TRUE; - - if (!GetComboText(GSConfS.Combo, GSConfS.plist, Config.GS)) - applychanges = FALSE; - if (!GetComboText(PAD1ConfS.Combo, PAD1ConfS.plist, Config.PAD1)) - applychanges = FALSE; - if (!GetComboText(PAD2ConfS.Combo, PAD2ConfS.plist, Config.PAD2)) - applychanges = FALSE; - if (!GetComboText(SPU2ConfS.Combo, SPU2ConfS.plist, Config.SPU2)) - applychanges = FALSE; - if (!GetComboText(CDVDConfS.Combo, CDVDConfS.plist, Config.CDVD)) - applychanges = FALSE; - if (!GetComboText(DEV9ConfS.Combo, DEV9ConfS.plist, Config.DEV9)) - applychanges = FALSE; - if (!GetComboText(USBConfS.Combo, USBConfS.plist, Config.USB)) - applychanges = FALSE; - if (!GetComboText(FWConfS.Combo, FWConfS.plist, Config.FW)) - applychanges = FALSE; - if (!GetComboText(BiosConfS.Combo, BiosConfS.plist, Config.Bios)) - applychanges = FALSE; - - SaveConfig(); - - if (configuringplug == FALSE) - { - ReleasePlugins(); - LoadPlugins(); - } - - gtk_widget_destroy(ConfDlg); - if (MainWindow) gtk_widget_set_sensitive(MainWindow, TRUE); - gtk_main_quit(); -} - -void OnConfConf_GsConf(GtkButton *button, gpointer user_data) -{ - ConfPlugin(GSConfS, Config.GS, "GSconfigure"); -} - -void OnConfConf_GsTest(GtkButton *button, gpointer user_data) -{ - TestPlugin(GSConfS, Config.GS, "GStest"); -} - -void OnConfConf_GsAbout(GtkButton *button, gpointer user_data) -{ - ConfPlugin(GSConfS, Config.GS, "GSabout"); -} - -void OnConfConf_Pad1Conf(GtkButton *button, gpointer user_data) -{ - ConfPlugin(PAD1ConfS, Config.PAD1, "PADconfigure"); -} - -void OnConfConf_Pad1Test(GtkButton *button, gpointer user_data) -{ - TestPlugin(PAD1ConfS, Config.PAD1, "PADtest"); -} - -void OnConfConf_Pad1About(GtkButton *button, gpointer user_data) -{ - ConfPlugin(PAD1ConfS, Config.PAD1, "PADabout"); -} - -void OnConfConf_Pad2Conf(GtkButton *button, gpointer user_data) -{ - ConfPlugin(PAD2ConfS, Config.PAD2, "PADconfigure"); -} - -void OnConfConf_Pad2Test(GtkButton *button, gpointer user_data) -{ - TestPlugin(PAD2ConfS, Config.PAD2, "PADtest"); -} - -void OnConfConf_Pad2About(GtkButton *button, gpointer user_data) -{ - ConfPlugin(PAD2ConfS, Config.PAD2, "PADabout"); -} - -void OnConfConf_Spu2Conf(GtkButton *button, gpointer user_data) -{ - ConfPlugin(SPU2ConfS, Config.SPU2, "SPU2configure"); -} - -void OnConfConf_Spu2Test(GtkButton *button, gpointer user_data) -{ - TestPlugin(SPU2ConfS, Config.SPU2, "SPU2test"); -} - -void OnConfConf_Spu2About(GtkButton *button, gpointer user_data) -{ - ConfPlugin(SPU2ConfS, Config.SPU2, "SPU2about"); -} - -void OnConfConf_CdvdConf(GtkButton *button, gpointer user_data) -{ - ConfPlugin(CDVDConfS, Config.CDVD, "CDVDconfigure"); -} - -void OnConfConf_CdvdTest(GtkButton *button, gpointer user_data) -{ - TestPlugin(CDVDConfS, Config.CDVD, "CDVDtest"); -} - -void OnConfConf_CdvdAbout(GtkButton *button, gpointer user_data) -{ - ConfPlugin(CDVDConfS, Config.CDVD, "CDVDabout"); -} - -void OnConfConf_Dev9Conf(GtkButton *button, gpointer user_data) -{ - ConfPlugin(DEV9ConfS, Config.DEV9, "DEV9configure"); -} - -void OnConfConf_Dev9Test(GtkButton *button, gpointer user_data) -{ - TestPlugin(DEV9ConfS, Config.DEV9, "DEV9test"); -} - -void OnConfConf_Dev9About(GtkButton *button, gpointer user_data) -{ - ConfPlugin(DEV9ConfS, Config.DEV9, "DEV9about"); -} - -void OnConfConf_UsbConf(GtkButton *button, gpointer user_data) -{ - ConfPlugin(USBConfS, Config.USB, "USBconfigure"); -} - -void OnConfConf_UsbTest(GtkButton *button, gpointer user_data) -{ - TestPlugin(USBConfS, Config.USB, "USBtest"); -} - -void OnConfConf_UsbAbout(GtkButton *button, gpointer user_data) -{ - ConfPlugin(USBConfS, Config.USB, "USBabout"); -} - -void OnConfConf_FWConf(GtkButton *button, gpointer user_data) -{ - ConfPlugin(FWConfS, Config.FW, "FWconfigure"); -} - -void OnConfConf_FWTest(GtkButton *button, gpointer user_data) -{ - TestPlugin(FWConfS, Config.FW, "FWtest"); -} - -void OnConfConf_FWAbout(GtkButton *button, gpointer user_data) -{ - ConfPlugin(FWConfS, Config.FW, "FWabout"); -} - - -void SetComboToGList(GtkComboBox *widget, GList *list) -{ - GList *temp; - - while (gtk_combo_box_get_active_text(widget) != NULL) - { - gtk_combo_box_remove_text(GTK_COMBO_BOX(widget), 0); - gtk_combo_box_set_active(GTK_COMBO_BOX(widget), 0); - } - - temp = list; - while (temp != NULL) - { - gtk_combo_box_append_text(GTK_COMBO_BOX(widget), (char*)temp->data); - - temp = temp->next; - } - - gtk_combo_box_set_active(GTK_COMBO_BOX(widget), 0); -} - -static void ConfCreatePConf(const char *name, PluginConf *confs, char *config) -{ - char tmp[50]; - - sprintf(tmp, "GtkCombo_%s", name); - confs->Combo = lookup_widget(ConfDlg, tmp); - SetComboToGList(GTK_COMBO_BOX(confs->Combo), confs->PluginNameList); - FindComboText(confs->Combo, confs->plist, confs->PluginNameList, config); -} - -void UpdateConfDlg() -{ - FindPlugins(); - - ConfCreatePConf("Gs", &GSConfS, Config.GS); - ConfCreatePConf("Pad1", &PAD1ConfS, Config.PAD1); - ConfCreatePConf("Pad2", &PAD2ConfS, Config.PAD2); - ConfCreatePConf("Spu2", &SPU2ConfS, Config.SPU2); - ConfCreatePConf("Cdvd", &CDVDConfS, Config.CDVD); - ConfCreatePConf("Dev9", &DEV9ConfS, Config.DEV9); - ConfCreatePConf("Usb", &USBConfS, Config.USB); - ConfCreatePConf("FW", &FWConfS, Config.FW); - ConfCreatePConf("Bios", &BiosConfS, Config.Bios); -} - -void GetDirectory(GtkWidget *topWindow, const char *message, char *reply) -{ - gchar *File; - GtkWidget *dialog; - gint result; - - dialog = gtk_file_chooser_dialog_new(message, GTK_WINDOW(topWindow), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL); - result = gtk_dialog_run(GTK_DIALOG(dialog)); - - switch (result) - { - case(GTK_RESPONSE_OK): - File = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - - strcpy(reply, File); - if (reply[strlen(reply)-1] != '/') - strcat(reply, "/"); - - default: - gtk_widget_destroy(dialog); - } -} - -void OnConfConf_PluginsPath(GtkButton *button, gpointer user_data) -{ - char reply[g_MaxPath]; - - GetDirectory(ConfDlg, "Choose the Plugin Directory:", reply); - strcpy(Config.PluginsDir, reply); - - UpdateConfDlg(); -} - -void OnConfConf_BiosPath(GtkButton *button, gpointer user_data) -{ - char reply[g_MaxPath]; - - GetDirectory(ConfDlg, "Choose the Bios Directory:", reply); - strcpy(Config.BiosDir, reply); - - UpdateConfDlg(); -} - -void OnConf_Conf(GtkMenuItem *menuitem, gpointer user_data) -{ - FindPlugins(); - - ConfDlg = create_ConfDlg(); - gtk_window_set_title(GTK_WINDOW(ConfDlg), "Configuration"); - - UpdateConfDlg(); - - gtk_widget_show_all(ConfDlg); - if (MainWindow) gtk_widget_set_sensitive(MainWindow, FALSE); - gtk_main(); -} - -static void ComboAddPlugin(char name[g_MaxPath], PluginConf *confs, u32 version, struct dirent *ent) -{ - sprintf(name, "%s %ld.%ld.%ld", PS2EgetLibName(), (version >> 8)&0xff , version&0xff, (version >> 24)&0xff); - confs->plugins += 2; - strcpy(confs->plist[confs->plugins-1], name); - strcpy(confs->plist[confs->plugins-2], ent->d_name); - confs->PluginNameList = g_list_append(confs->PluginNameList, confs->plist[confs->plugins-1]); -} - -void FindPlugins() -{ - DIR *dir; - struct dirent *ent; - void *Handle; - char plugin[g_MaxPath], name[g_MaxPath]; - - GSConfS.plugins = 0; CDVDConfS.plugins = 0; DEV9ConfS.plugins = 0; - PAD1ConfS.plugins = 0; PAD2ConfS.plugins = 0; SPU2ConfS.plugins = 0; - USBConfS.plugins = 0; FWConfS.plugins = 0; BiosConfS.plugins = 0; - GSConfS.PluginNameList = NULL; CDVDConfS.PluginNameList = NULL; DEV9ConfS.PluginNameList = NULL; - PAD1ConfS.PluginNameList = NULL; PAD2ConfS.PluginNameList = NULL; SPU2ConfS.PluginNameList = NULL; - USBConfS.PluginNameList = NULL; FWConfS.PluginNameList = NULL; BiosConfS.PluginNameList = NULL; - - dir = opendir(Config.PluginsDir); - if (dir == NULL) - { - Msgbox::Alert("Could not open '%s' directory", params Config.PluginsDir); - return; - } - while ((ent = readdir(dir)) != NULL) - { - u32 version; - u32 type; - - sprintf(plugin, "%s%s", Config.PluginsDir, ent->d_name); - - if (strstr(plugin, ".so") == NULL) continue; - Handle = dlopen(plugin, RTLD_NOW); - if (Handle == NULL) - { - Console::Error("Can't open %s: %s\n", params ent->d_name, dlerror()); - continue; - } - - PS2EgetLibType = (_PS2EgetLibType) dlsym(Handle, "PS2EgetLibType"); - PS2EgetLibName = (_PS2EgetLibName) dlsym(Handle, "PS2EgetLibName"); - PS2EgetLibVersion2 = (_PS2EgetLibVersion2) dlsym(Handle, "PS2EgetLibVersion2"); - - if (PS2EgetLibType == NULL) - { - Console::Error("PS2EgetLibType==NULL for %s", params ent->d_name); - continue; - } - if (PS2EgetLibName == NULL) - { - Console::Error("PS2EgetLibName==NULL for %s", params ent->d_name); - continue; - } - if (PS2EgetLibVersion2 == NULL) - { - Console::Error("PS2EgetLibVersion2==NULL for %s", params ent->d_name); - continue; - } - - type = PS2EgetLibType(); - - if (type & PS2E_LT_GS) - { - version = PS2EgetLibVersion2(PS2E_LT_GS); - - if (((version >> 16)&0xff) == PS2E_GS_VERSION) - ComboAddPlugin(name, &GSConfS, version, ent); - else - Console::Notice("Plugin %s: Version %x != %x", params plugin, (version >> 16)&0xff, PS2E_GS_VERSION); - } - if (type & PS2E_LT_PAD) - { - _PADquery query; - - query = (_PADquery)dlsym(Handle, "PADquery"); - version = PS2EgetLibVersion2(PS2E_LT_PAD); - - if (((version >> 16)&0xff) == PS2E_PAD_VERSION && query) - { - if (query() & 0x1) ComboAddPlugin(name, &PAD1ConfS, version, ent); - if (query() & 0x2) ComboAddPlugin(name, &PAD2ConfS, version, ent); - } - else - Console::Notice("Plugin %s: Version %x != %x", params plugin, (version >> 16)&0xff, PS2E_PAD_VERSION); - } - if (type & PS2E_LT_SPU2) - { - version = PS2EgetLibVersion2(PS2E_LT_SPU2); - - if (((version >> 16)&0xff) == PS2E_SPU2_VERSION) - ComboAddPlugin(name, &SPU2ConfS, version, ent); - else - Console::Notice("Plugin %s: Version %x != %x", params plugin, (version >> 16)&0xff, PS2E_SPU2_VERSION); - } - if (type & PS2E_LT_CDVD) - { - version = PS2EgetLibVersion2(PS2E_LT_CDVD); - - if (((version >> 16)&0xff) == PS2E_CDVD_VERSION) - ComboAddPlugin(name, &CDVDConfS, version, ent); - else - Console::Notice("Plugin %s: Version %x != %x", params plugin, (version >> 16)&0xff, PS2E_CDVD_VERSION); - } - if (type & PS2E_LT_DEV9) - { - version = PS2EgetLibVersion2(PS2E_LT_DEV9); - - if (((version >> 16)&0xff) == PS2E_DEV9_VERSION) - ComboAddPlugin(name, &DEV9ConfS, version, ent); - else - Console::Notice("DEV9Plugin %s: Version %x != %x", params plugin, (version >> 16)&0xff, PS2E_DEV9_VERSION); - } - if (type & PS2E_LT_USB) - { - version = PS2EgetLibVersion2(PS2E_LT_USB); - - if (((version >> 16)&0xff) == PS2E_USB_VERSION) - ComboAddPlugin(name, &USBConfS, version, ent); - else - Console::Notice("USBPlugin %s: Version %x != %x", params plugin, (version >> 16)&0xff, PS2E_USB_VERSION); - } - if (type & PS2E_LT_FW) - { - version = PS2EgetLibVersion2(PS2E_LT_FW); - - if (((version >> 16)&0xff) == PS2E_FW_VERSION) - ComboAddPlugin(name, &FWConfS, version, ent); - else - Console::Notice("FWPlugin %s: Version %x != %x", params plugin, (version >> 16)&0xff, PS2E_FW_VERSION); - } - } - closedir(dir); - - dir = opendir(Config.BiosDir); - if (dir == NULL) - { - Msgbox::Alert("Could not open '%s' directory", params Config.BiosDir); - return; - } - - while ((ent = readdir(dir)) != NULL) - { - struct stat buf; - char description[50]; //2002-09-28 (Florin) - - sprintf(plugin, "%s%s", Config.BiosDir, ent->d_name); - if (stat(plugin, &buf) == -1) continue; - if (buf.st_size > (1024*4096)) continue; //2002-09-28 (Florin) - if (!IsBIOS(ent->d_name, description)) continue;//2002-09-28 (Florin) - - BiosConfS.plugins += 2; - snprintf(BiosConfS.plist[BiosConfS.plugins-1], sizeof(BiosConfS.plist[0]), "%s (", description); - strncat(BiosConfS.plist[BiosConfS.plugins-1], ent->d_name, min(sizeof(BiosConfS.plist[0] - 2), strlen(ent->d_name))); - strcat(BiosConfS.plist[BiosConfS.plugins-1], ")"); - strcpy(BiosConfS.plist[BiosConfS.plugins-2], ent->d_name); - BiosConfS.PluginNameList = g_list_append(BiosConfS.PluginNameList, BiosConfS.plist[BiosConfS.plugins-1]); - } - closedir(dir); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "ConfigDlg.h" + +using namespace std; +using namespace R5900; + +bool applychanges = FALSE; + +static void FindComboText(GtkWidget *combo, char plist[255][255], GList *list, char *conf) +{ + if (strlen(conf) > 0) SetActiveComboItem(GTK_COMBO_BOX(combo), plist, list, conf); +} + + +static bool GetComboText(GtkWidget *combo, char plist[255][255], char *conf) +{ + int i; + + char *tmp = (char*)gtk_combo_box_get_active_text(GTK_COMBO_BOX(combo)); + + if (tmp == NULL) return FALSE; + for (i = 2;i < 255;i += 2) + { + if (!strcmp(tmp, plist[i-1])) + { + strcpy(conf, plist[i-2]); + break; + } + } + return TRUE; +} + +static void ConfPlugin(PluginConf confs, char* plugin, const char* name) +{ + void *drv; + void (*conf)(); + char file[g_MaxPath]; + + GetComboText(confs.Combo, confs.plist, plugin); + strcpy(file, Config.PluginsDir); + strcat(file, plugin); + + drv = SysLoadLibrary(file); +#ifndef LOCAL_PLUGIN_INIS + getcwd(file, ARRAYSIZE(file)); /* store current dir */ + chdir(Config.PluginsDir); /* change dirs so that plugins can find their config file*/ +#endif + if (drv == NULL) return; + + conf = (void (*)()) SysLoadSym(drv, name); + if (SysLibError() == NULL) conf(); +#ifndef LOCAL_PLUGIN_INIS + chdir(file); /* change back*/ +#endif + SysCloseLibrary(drv); +} + + +static void TestPlugin(PluginConf confs, char* plugin, const char* name) +{ + void *drv; + s32(* (*conf)())(); + char file[g_MaxPath]; + int ret = 0; + + GetComboText(confs.Combo, confs.plist, plugin); + strcpy(file, Config.PluginsDir); + strcat(file, plugin); + + drv = SysLoadLibrary(file); + getcwd(file, ARRAYSIZE(file)); /* store current dir */ + chdir(Config.PluginsDir); /* change dirs so that plugins can find their config file*/ + if (drv == NULL) return; + + conf = (s32(* (*)())()) SysLoadSym(drv, name); + if (SysLibError() == NULL) ret = (s32) conf(); + chdir(file); /* change back*/ + SysCloseLibrary(drv); + + if (ret == 0) + Msgbox::Alert("This plugin reports that should work correctly"); + else + Msgbox::Alert("This plugin reports that should not work correctly"); +} + +void OnConf_Gs(GtkMenuItem *menuitem, gpointer user_data) +{ + char file[255]; + + getcwd(file, ARRAYSIZE(file)); + chdir(Config.PluginsDir); + gtk_widget_set_sensitive(MainWindow, FALSE); + GSconfigure(); + chdir(file); + gtk_widget_set_sensitive(MainWindow, TRUE); +} + +void OnConf_Pads(GtkMenuItem *menuitem, gpointer user_data) +{ + char file[255]; + + getcwd(file, ARRAYSIZE(file)); + chdir(Config.PluginsDir); + gtk_widget_set_sensitive(MainWindow, FALSE); + PAD1configure(); + if (strcmp(Config.PAD1, Config.PAD2)) PAD2configure(); + chdir(file); + gtk_widget_set_sensitive(MainWindow, TRUE); +} + +void OnConf_Spu2(GtkMenuItem *menuitem, gpointer user_data) +{ + char file[255]; + + getcwd(file, ARRAYSIZE(file)); + chdir(Config.PluginsDir); + gtk_widget_set_sensitive(MainWindow, FALSE); + SPU2configure(); + gtk_widget_set_sensitive(MainWindow, TRUE); + chdir(file); +} + +void OnConf_Cdvd(GtkMenuItem *menuitem, gpointer user_data) +{ + char file[255]; + + getcwd(file, ARRAYSIZE(file)); + chdir(Config.PluginsDir); + gtk_widget_set_sensitive(MainWindow, FALSE); + CDVDconfigure(); + gtk_widget_set_sensitive(MainWindow, TRUE); + chdir(file); +} + +void OnConf_Dev9(GtkMenuItem *menuitem, gpointer user_data) +{ + char file[255]; + + getcwd(file, ARRAYSIZE(file)); + chdir(Config.PluginsDir); + gtk_widget_set_sensitive(MainWindow, FALSE); + DEV9configure(); + gtk_widget_set_sensitive(MainWindow, TRUE); + chdir(file); +} + +void OnConf_Usb(GtkMenuItem *menuitem, gpointer user_data) +{ + char file[255]; + + getcwd(file, ARRAYSIZE(file)); + chdir(Config.PluginsDir); + gtk_widget_set_sensitive(MainWindow, FALSE); + USBconfigure(); + gtk_widget_set_sensitive(MainWindow, TRUE); + chdir(file); +} + +void OnConf_Fw(GtkMenuItem *menuitem, gpointer user_data) +{ + char file[255]; + + getcwd(file, ARRAYSIZE(file)); + chdir(Config.PluginsDir); + gtk_widget_set_sensitive(MainWindow, FALSE); + FWconfigure(); + gtk_widget_set_sensitive(MainWindow, TRUE); + chdir(file); +} + +void SetActiveComboItem(GtkComboBox *widget, char plist[255][255], GList *list, char *conf) +{ + GList *temp; + int i = 0, pindex = 0, item = -1; + + if (strlen(conf) > 0) + { + for (i = 2;i < 255;i += 2) + { + if (!strcmp(conf, plist[i-2])) + { + pindex = i - 1; + break; + } + } + } + + i = 0; + temp = list; + + while (temp) + { + if (!strcmp(plist[pindex], (char*)temp->data)) + item = i; + + temp = temp->next; + i++; + } + + if (item <= 0) item = 0; + gtk_combo_box_set_active(GTK_COMBO_BOX(widget), item); +} + +void OnConfConf_Ok(GtkButton *button, gpointer user_data) +{ + applychanges = TRUE; + + if (!GetComboText(GSConfS.Combo, GSConfS.plist, Config.GS)) + applychanges = FALSE; + if (!GetComboText(PAD1ConfS.Combo, PAD1ConfS.plist, Config.PAD1)) + applychanges = FALSE; + if (!GetComboText(PAD2ConfS.Combo, PAD2ConfS.plist, Config.PAD2)) + applychanges = FALSE; + if (!GetComboText(SPU2ConfS.Combo, SPU2ConfS.plist, Config.SPU2)) + applychanges = FALSE; + if (!GetComboText(CDVDConfS.Combo, CDVDConfS.plist, Config.CDVD)) + applychanges = FALSE; + if (!GetComboText(DEV9ConfS.Combo, DEV9ConfS.plist, Config.DEV9)) + applychanges = FALSE; + if (!GetComboText(USBConfS.Combo, USBConfS.plist, Config.USB)) + applychanges = FALSE; + if (!GetComboText(FWConfS.Combo, FWConfS.plist, Config.FW)) + applychanges = FALSE; + if (!GetComboText(BiosConfS.Combo, BiosConfS.plist, Config.Bios)) + applychanges = FALSE; + + SaveConfig(); + + if (configuringplug == FALSE) + { + ReleasePlugins(); + LoadPlugins(); + } + + gtk_widget_destroy(ConfDlg); + if (MainWindow) gtk_widget_set_sensitive(MainWindow, TRUE); + gtk_main_quit(); +} + +void OnConfConf_GsConf(GtkButton *button, gpointer user_data) +{ + ConfPlugin(GSConfS, Config.GS, "GSconfigure"); +} + +void OnConfConf_GsTest(GtkButton *button, gpointer user_data) +{ + TestPlugin(GSConfS, Config.GS, "GStest"); +} + +void OnConfConf_GsAbout(GtkButton *button, gpointer user_data) +{ + ConfPlugin(GSConfS, Config.GS, "GSabout"); +} + +void OnConfConf_Pad1Conf(GtkButton *button, gpointer user_data) +{ + ConfPlugin(PAD1ConfS, Config.PAD1, "PADconfigure"); +} + +void OnConfConf_Pad1Test(GtkButton *button, gpointer user_data) +{ + TestPlugin(PAD1ConfS, Config.PAD1, "PADtest"); +} + +void OnConfConf_Pad1About(GtkButton *button, gpointer user_data) +{ + ConfPlugin(PAD1ConfS, Config.PAD1, "PADabout"); +} + +void OnConfConf_Pad2Conf(GtkButton *button, gpointer user_data) +{ + ConfPlugin(PAD2ConfS, Config.PAD2, "PADconfigure"); +} + +void OnConfConf_Pad2Test(GtkButton *button, gpointer user_data) +{ + TestPlugin(PAD2ConfS, Config.PAD2, "PADtest"); +} + +void OnConfConf_Pad2About(GtkButton *button, gpointer user_data) +{ + ConfPlugin(PAD2ConfS, Config.PAD2, "PADabout"); +} + +void OnConfConf_Spu2Conf(GtkButton *button, gpointer user_data) +{ + ConfPlugin(SPU2ConfS, Config.SPU2, "SPU2configure"); +} + +void OnConfConf_Spu2Test(GtkButton *button, gpointer user_data) +{ + TestPlugin(SPU2ConfS, Config.SPU2, "SPU2test"); +} + +void OnConfConf_Spu2About(GtkButton *button, gpointer user_data) +{ + ConfPlugin(SPU2ConfS, Config.SPU2, "SPU2about"); +} + +void OnConfConf_CdvdConf(GtkButton *button, gpointer user_data) +{ + ConfPlugin(CDVDConfS, Config.CDVD, "CDVDconfigure"); +} + +void OnConfConf_CdvdTest(GtkButton *button, gpointer user_data) +{ + TestPlugin(CDVDConfS, Config.CDVD, "CDVDtest"); +} + +void OnConfConf_CdvdAbout(GtkButton *button, gpointer user_data) +{ + ConfPlugin(CDVDConfS, Config.CDVD, "CDVDabout"); +} + +void OnConfConf_Dev9Conf(GtkButton *button, gpointer user_data) +{ + ConfPlugin(DEV9ConfS, Config.DEV9, "DEV9configure"); +} + +void OnConfConf_Dev9Test(GtkButton *button, gpointer user_data) +{ + TestPlugin(DEV9ConfS, Config.DEV9, "DEV9test"); +} + +void OnConfConf_Dev9About(GtkButton *button, gpointer user_data) +{ + ConfPlugin(DEV9ConfS, Config.DEV9, "DEV9about"); +} + +void OnConfConf_UsbConf(GtkButton *button, gpointer user_data) +{ + ConfPlugin(USBConfS, Config.USB, "USBconfigure"); +} + +void OnConfConf_UsbTest(GtkButton *button, gpointer user_data) +{ + TestPlugin(USBConfS, Config.USB, "USBtest"); +} + +void OnConfConf_UsbAbout(GtkButton *button, gpointer user_data) +{ + ConfPlugin(USBConfS, Config.USB, "USBabout"); +} + +void OnConfConf_FWConf(GtkButton *button, gpointer user_data) +{ + ConfPlugin(FWConfS, Config.FW, "FWconfigure"); +} + +void OnConfConf_FWTest(GtkButton *button, gpointer user_data) +{ + TestPlugin(FWConfS, Config.FW, "FWtest"); +} + +void OnConfConf_FWAbout(GtkButton *button, gpointer user_data) +{ + ConfPlugin(FWConfS, Config.FW, "FWabout"); +} + + +void SetComboToGList(GtkComboBox *widget, GList *list) +{ + GList *temp; + + while (gtk_combo_box_get_active_text(widget) != NULL) + { + gtk_combo_box_remove_text(GTK_COMBO_BOX(widget), 0); + gtk_combo_box_set_active(GTK_COMBO_BOX(widget), 0); + } + + temp = list; + while (temp != NULL) + { + gtk_combo_box_append_text(GTK_COMBO_BOX(widget), (char*)temp->data); + + temp = temp->next; + } + + gtk_combo_box_set_active(GTK_COMBO_BOX(widget), 0); +} + +static void ConfCreatePConf(const char *name, PluginConf *confs, char *config) +{ + char tmp[50]; + + sprintf(tmp, "GtkCombo_%s", name); + confs->Combo = lookup_widget(ConfDlg, tmp); + SetComboToGList(GTK_COMBO_BOX(confs->Combo), confs->PluginNameList); + FindComboText(confs->Combo, confs->plist, confs->PluginNameList, config); +} + +void UpdateConfDlg() +{ + FindPlugins(); + + ConfCreatePConf("Gs", &GSConfS, Config.GS); + ConfCreatePConf("Pad1", &PAD1ConfS, Config.PAD1); + ConfCreatePConf("Pad2", &PAD2ConfS, Config.PAD2); + ConfCreatePConf("Spu2", &SPU2ConfS, Config.SPU2); + ConfCreatePConf("Cdvd", &CDVDConfS, Config.CDVD); + ConfCreatePConf("Dev9", &DEV9ConfS, Config.DEV9); + ConfCreatePConf("Usb", &USBConfS, Config.USB); + ConfCreatePConf("FW", &FWConfS, Config.FW); + ConfCreatePConf("Bios", &BiosConfS, Config.Bios); +} + +void GetDirectory(GtkWidget *topWindow, const char *message, char *reply) +{ + gchar *File; + GtkWidget *dialog; + gint result; + + dialog = gtk_file_chooser_dialog_new(message, GTK_WINDOW(topWindow), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL); + result = gtk_dialog_run(GTK_DIALOG(dialog)); + + switch (result) + { + case(GTK_RESPONSE_OK): + File = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + + strcpy(reply, File); + if (reply[strlen(reply)-1] != '/') + strcat(reply, "/"); + + default: + gtk_widget_destroy(dialog); + } +} + +void OnConfConf_PluginsPath(GtkButton *button, gpointer user_data) +{ + char reply[g_MaxPath]; + + GetDirectory(ConfDlg, "Choose the Plugin Directory:", reply); + strcpy(Config.PluginsDir, reply); + + UpdateConfDlg(); +} + +void OnConfConf_BiosPath(GtkButton *button, gpointer user_data) +{ + char reply[g_MaxPath]; + + GetDirectory(ConfDlg, "Choose the Bios Directory:", reply); + strcpy(Config.BiosDir, reply); + + UpdateConfDlg(); +} + +void OnConf_Conf(GtkMenuItem *menuitem, gpointer user_data) +{ + FindPlugins(); + + ConfDlg = create_ConfDlg(); + gtk_window_set_title(GTK_WINDOW(ConfDlg), "Configuration"); + + UpdateConfDlg(); + + gtk_widget_show_all(ConfDlg); + if (MainWindow) gtk_widget_set_sensitive(MainWindow, FALSE); + gtk_main(); +} + +static void ComboAddPlugin(char name[g_MaxPath], PluginConf *confs, u32 version, struct dirent *ent) +{ + sprintf(name, "%s %ld.%ld.%ld", PS2EgetLibName(), (version >> 8)&0xff , version&0xff, (version >> 24)&0xff); + confs->plugins += 2; + strcpy(confs->plist[confs->plugins-1], name); + strcpy(confs->plist[confs->plugins-2], ent->d_name); + confs->PluginNameList = g_list_append(confs->PluginNameList, confs->plist[confs->plugins-1]); +} + +void FindPlugins() +{ + DIR *dir; + struct dirent *ent; + void *Handle; + char plugin[g_MaxPath], name[g_MaxPath]; + + GSConfS.plugins = 0; CDVDConfS.plugins = 0; DEV9ConfS.plugins = 0; + PAD1ConfS.plugins = 0; PAD2ConfS.plugins = 0; SPU2ConfS.plugins = 0; + USBConfS.plugins = 0; FWConfS.plugins = 0; BiosConfS.plugins = 0; + GSConfS.PluginNameList = NULL; CDVDConfS.PluginNameList = NULL; DEV9ConfS.PluginNameList = NULL; + PAD1ConfS.PluginNameList = NULL; PAD2ConfS.PluginNameList = NULL; SPU2ConfS.PluginNameList = NULL; + USBConfS.PluginNameList = NULL; FWConfS.PluginNameList = NULL; BiosConfS.PluginNameList = NULL; + + dir = opendir(Config.PluginsDir); + if (dir == NULL) + { + Msgbox::Alert("Could not open '%s' directory", params Config.PluginsDir); + return; + } + while ((ent = readdir(dir)) != NULL) + { + u32 version; + u32 type; + + sprintf(plugin, "%s%s", Config.PluginsDir, ent->d_name); + + if (strstr(plugin, ".so") == NULL) continue; + Handle = dlopen(plugin, RTLD_NOW); + if (Handle == NULL) + { + Console::Error("Can't open %s: %s\n", params ent->d_name, dlerror()); + continue; + } + + PS2EgetLibType = (_PS2EgetLibType) dlsym(Handle, "PS2EgetLibType"); + PS2EgetLibName = (_PS2EgetLibName) dlsym(Handle, "PS2EgetLibName"); + PS2EgetLibVersion2 = (_PS2EgetLibVersion2) dlsym(Handle, "PS2EgetLibVersion2"); + + if (PS2EgetLibType == NULL) + { + Console::Error("PS2EgetLibType==NULL for %s", params ent->d_name); + continue; + } + if (PS2EgetLibName == NULL) + { + Console::Error("PS2EgetLibName==NULL for %s", params ent->d_name); + continue; + } + if (PS2EgetLibVersion2 == NULL) + { + Console::Error("PS2EgetLibVersion2==NULL for %s", params ent->d_name); + continue; + } + + type = PS2EgetLibType(); + + if (type & PS2E_LT_GS) + { + version = PS2EgetLibVersion2(PS2E_LT_GS); + + if (((version >> 16)&0xff) == PS2E_GS_VERSION) + ComboAddPlugin(name, &GSConfS, version, ent); + else + Console::Notice("Plugin %s: Version %x != %x", params plugin, (version >> 16)&0xff, PS2E_GS_VERSION); + } + if (type & PS2E_LT_PAD) + { + _PADquery query; + + query = (_PADquery)dlsym(Handle, "PADquery"); + version = PS2EgetLibVersion2(PS2E_LT_PAD); + + if (((version >> 16)&0xff) == PS2E_PAD_VERSION && query) + { + if (query() & 0x1) ComboAddPlugin(name, &PAD1ConfS, version, ent); + if (query() & 0x2) ComboAddPlugin(name, &PAD2ConfS, version, ent); + } + else + Console::Notice("Plugin %s: Version %x != %x", params plugin, (version >> 16)&0xff, PS2E_PAD_VERSION); + } + if (type & PS2E_LT_SPU2) + { + version = PS2EgetLibVersion2(PS2E_LT_SPU2); + + if (((version >> 16)&0xff) == PS2E_SPU2_VERSION) + ComboAddPlugin(name, &SPU2ConfS, version, ent); + else + Console::Notice("Plugin %s: Version %x != %x", params plugin, (version >> 16)&0xff, PS2E_SPU2_VERSION); + } + if (type & PS2E_LT_CDVD) + { + version = PS2EgetLibVersion2(PS2E_LT_CDVD); + + if (((version >> 16)&0xff) == PS2E_CDVD_VERSION) + ComboAddPlugin(name, &CDVDConfS, version, ent); + else + Console::Notice("Plugin %s: Version %x != %x", params plugin, (version >> 16)&0xff, PS2E_CDVD_VERSION); + } + if (type & PS2E_LT_DEV9) + { + version = PS2EgetLibVersion2(PS2E_LT_DEV9); + + if (((version >> 16)&0xff) == PS2E_DEV9_VERSION) + ComboAddPlugin(name, &DEV9ConfS, version, ent); + else + Console::Notice("DEV9Plugin %s: Version %x != %x", params plugin, (version >> 16)&0xff, PS2E_DEV9_VERSION); + } + if (type & PS2E_LT_USB) + { + version = PS2EgetLibVersion2(PS2E_LT_USB); + + if (((version >> 16)&0xff) == PS2E_USB_VERSION) + ComboAddPlugin(name, &USBConfS, version, ent); + else + Console::Notice("USBPlugin %s: Version %x != %x", params plugin, (version >> 16)&0xff, PS2E_USB_VERSION); + } + if (type & PS2E_LT_FW) + { + version = PS2EgetLibVersion2(PS2E_LT_FW); + + if (((version >> 16)&0xff) == PS2E_FW_VERSION) + ComboAddPlugin(name, &FWConfS, version, ent); + else + Console::Notice("FWPlugin %s: Version %x != %x", params plugin, (version >> 16)&0xff, PS2E_FW_VERSION); + } + } + closedir(dir); + + dir = opendir(Config.BiosDir); + if (dir == NULL) + { + Msgbox::Alert("Could not open '%s' directory", params Config.BiosDir); + return; + } + + while ((ent = readdir(dir)) != NULL) + { + struct stat buf; + char description[50]; //2002-09-28 (Florin) + + sprintf(plugin, "%s%s", Config.BiosDir, ent->d_name); + if (stat(plugin, &buf) == -1) continue; + if (buf.st_size > (1024*4096)) continue; //2002-09-28 (Florin) + if (!IsBIOS(ent->d_name, description)) continue;//2002-09-28 (Florin) + + BiosConfS.plugins += 2; + snprintf(BiosConfS.plist[BiosConfS.plugins-1], sizeof(BiosConfS.plist[0]), "%s (", description); + strncat(BiosConfS.plist[BiosConfS.plugins-1], ent->d_name, min(sizeof(BiosConfS.plist[0] - 2), strlen(ent->d_name))); + strcat(BiosConfS.plist[BiosConfS.plugins-1], ")"); + strcpy(BiosConfS.plist[BiosConfS.plugins-2], ent->d_name); + BiosConfS.PluginNameList = g_list_append(BiosConfS.PluginNameList, BiosConfS.plist[BiosConfS.plugins-1]); + } + closedir(dir); +} diff --git a/pcsx2/Linux/ConfigDlg.h b/pcsx2/Linux/ConfigDlg.h index eee448450e..82624f6e58 100644 --- a/pcsx2/Linux/ConfigDlg.h +++ b/pcsx2/Linux/ConfigDlg.h @@ -1,68 +1,68 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __CONFIGDLG_H__ -#define __CONFIGDLG_H__ - -#include "Linux.h" -#include "R3000A.h" -#include "IopMem.h" - -typedef struct -{ - GtkWidget *Combo; - GList *PluginNameList; - char plist[255][255]; - int plugins; -} PluginConf; - -PluginConf GSConfS; -PluginConf PAD1ConfS; -PluginConf PAD2ConfS; -PluginConf SPU2ConfS; -PluginConf CDVDConfS; -PluginConf DEV9ConfS; -PluginConf USBConfS; -PluginConf FWConfS; -PluginConf BiosConfS; - -GtkWidget *ConfDlg; - -_PS2EgetLibType PS2EgetLibType = NULL; -_PS2EgetLibVersion2 PS2EgetLibVersion2 = NULL; -_PS2EgetLibName PS2EgetLibName = NULL; - -// Helper Functions -void FindPlugins(); -void OnConf_Gs(GtkMenuItem *menuitem, gpointer user_data); -void OnConf_Pads(GtkMenuItem *menuitem, gpointer user_data); -void OnConf_Cpu(GtkMenuItem *menuitem, gpointer user_data); -void OnConf_Conf(GtkMenuItem *menuitem, gpointer user_data); -void SetActiveComboItem(GtkComboBox *widget, char plist[255][255], GList *list, char *conf); -void SetComboToGList(GtkComboBox *widget, GList *list); -static void ConfPlugin(PluginConf confs, char* plugin, const char* name); -static void TestPlugin(PluginConf confs, char* plugin, const char* name); - -extern void CheckSlots(); - - - - - - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __CONFIGDLG_H__ +#define __CONFIGDLG_H__ + +#include "Linux.h" +#include "R3000A.h" +#include "IopMem.h" + +typedef struct +{ + GtkWidget *Combo; + GList *PluginNameList; + char plist[255][255]; + int plugins; +} PluginConf; + +PluginConf GSConfS; +PluginConf PAD1ConfS; +PluginConf PAD2ConfS; +PluginConf SPU2ConfS; +PluginConf CDVDConfS; +PluginConf DEV9ConfS; +PluginConf USBConfS; +PluginConf FWConfS; +PluginConf BiosConfS; + +GtkWidget *ConfDlg; + +_PS2EgetLibType PS2EgetLibType = NULL; +_PS2EgetLibVersion2 PS2EgetLibVersion2 = NULL; +_PS2EgetLibName PS2EgetLibName = NULL; + +// Helper Functions +void FindPlugins(); +void OnConf_Gs(GtkMenuItem *menuitem, gpointer user_data); +void OnConf_Pads(GtkMenuItem *menuitem, gpointer user_data); +void OnConf_Cpu(GtkMenuItem *menuitem, gpointer user_data); +void OnConf_Conf(GtkMenuItem *menuitem, gpointer user_data); +void SetActiveComboItem(GtkComboBox *widget, char plist[255][255], GList *list, char *conf); +void SetComboToGList(GtkComboBox *widget, GList *list); +static void ConfPlugin(PluginConf confs, char* plugin, const char* name); +static void TestPlugin(PluginConf confs, char* plugin, const char* name); + +extern void CheckSlots(); + + + + + + #endif // __CONFIGDLG_H__ \ No newline at end of file diff --git a/pcsx2/Linux/DebugDlg.cpp b/pcsx2/Linux/DebugDlg.cpp index 094274cbee..62fb08b1a4 100644 --- a/pcsx2/Linux/DebugDlg.cpp +++ b/pcsx2/Linux/DebugDlg.cpp @@ -1,445 +1,445 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "DebugDlg.h" -using namespace R5900; - -void UpdateDebugger() -{ - - char *str; - int i; - std::string output; - - DebugAdj->value = (gfloat)dPC / 4; - gtk_list_store_clear(ListDVModel); - - for (i = 0; i < 23; i++) - { - GtkTreeIter iter; - u32 *mem; - u32 pc = dPC + i * 4; - if (DebugMode) - { - mem = (u32*)PSXM(pc); - } - else - mem = (u32*)PSM(pc); - - if (mem == NULL) - { - sprintf(nullAddr, "%8.8lX:\tNULL MEMORY", pc); - str = nullAddr; - } - else - { - std::string output; - - disR5900Fasm(output, *mem, pc); - output.copy(str, 256); - } - gtk_list_store_append(ListDVModel, &iter); - gtk_list_store_set(ListDVModel, &iter, 0, str, -1); - - } -} - -void OnDebug_Close(GtkButton *button, gpointer user_data) -{ - ClosePlugins(); - gtk_widget_destroy(DebugWnd); - gtk_main_quit(); - gtk_widget_set_sensitive(MainWindow, TRUE); -} - -void OnDebug_ScrollChange(GtkAdjustment *adj) -{ - dPC = (u32)adj->value * 4; - dPC &= ~0x3; - - UpdateDebugger(); -} - -void OnSetPC_Ok(GtkButton *button, gpointer user_data) -{ - char *str = (char*)gtk_entry_get_text(GTK_ENTRY(SetPCEntry)); - - sscanf(str, "%lx", &dPC); - dPC &= ~0x3; - - gtk_widget_destroy(SetPCDlg); - gtk_main_quit(); - gtk_widget_set_sensitive(DebugWnd, TRUE); - UpdateDebugger(); -} - -void OnSetPC_Cancel(GtkButton *button, gpointer user_data) -{ - gtk_widget_destroy(SetPCDlg); - gtk_main_quit(); - gtk_widget_set_sensitive(DebugWnd, TRUE); -} - -void OnDebug_SetPC(GtkButton *button, gpointer user_data) -{ - SetPCDlg = create_SetPCDlg(); - - SetPCEntry = lookup_widget(SetPCDlg, "GtkEntry_dPC"); - - gtk_widget_show_all(SetPCDlg); - gtk_widget_set_sensitive(DebugWnd, FALSE); - gtk_main(); -} - -void OnSetBPA_Ok(GtkButton *button, gpointer user_data) -{ - char *str = (char*)gtk_entry_get_text(GTK_ENTRY(SetBPAEntry)); - - sscanf(str, "%lx", &dBPA); - dBPA &= ~0x3; - - gtk_widget_destroy(SetBPADlg); - gtk_main_quit(); - gtk_widget_set_sensitive(DebugWnd, TRUE); - UpdateDebugger(); -} - -void OnSetBPA_Cancel(GtkButton *button, gpointer user_data) -{ - gtk_widget_destroy(SetBPADlg); - gtk_main_quit(); - gtk_widget_set_sensitive(DebugWnd, TRUE); -} - -void OnDebug_SetBPA(GtkButton *button, gpointer user_data) -{ - SetBPADlg = create_SetBPADlg(); - - SetBPAEntry = lookup_widget(SetBPADlg, "GtkEntry_BPA"); - - gtk_widget_show_all(SetBPADlg); - gtk_widget_set_sensitive(DebugWnd, FALSE); - gtk_main(); -} - -void OnSetBPC_Ok(GtkButton *button, gpointer user_data) -{ - char *str = (char*)gtk_entry_get_text(GTK_ENTRY(SetBPCEntry)); - - sscanf(str, "%lx", &dBPC); - - gtk_widget_destroy(SetBPCDlg); - gtk_main_quit(); - gtk_widget_set_sensitive(DebugWnd, TRUE); - UpdateDebugger(); -} - -void OnSetBPC_Cancel(GtkButton *button, gpointer user_data) -{ - gtk_widget_destroy(SetBPCDlg); - gtk_main_quit(); - gtk_widget_set_sensitive(DebugWnd, TRUE); -} - -void OnDebug_SetBPC(GtkButton *button, gpointer user_data) -{ - SetBPCDlg = create_SetBPCDlg(); - - SetBPCEntry = lookup_widget(SetBPCDlg, "GtkEntry_BPC"); - - gtk_widget_show_all(SetBPCDlg); - gtk_widget_set_sensitive(DebugWnd, FALSE); - gtk_main(); -} - -void OnDebug_ClearBPs(GtkButton *button, gpointer user_data) -{ - dBPA = -1; - dBPC = -1; -} - -void OnDumpC_Ok(GtkButton *button, gpointer user_data) -{ - FILE *f; - char *str = (char*)gtk_entry_get_text(GTK_ENTRY(DumpCFEntry)); - u32 addrf, addrt; - - sscanf(str, "%lx", &addrf); - addrf &= ~0x3; - str = (char*)gtk_entry_get_text(GTK_ENTRY(DumpCTEntry)); - sscanf(str, "%lx", &addrt); - addrt &= ~0x3; - - f = fopen("dump.txt", "w"); - if (f == NULL) return; - - while (addrf != addrt) - { - u32 *mem; - - if (DebugMode) - { - mem = (u32*)PSXM(addrf); - } - else - { - mem = (u32*)PSM(addrf); - } - - if (mem == NULL) - { - sprintf(nullAddr, "%8.8lX:\tNULL MEMORY", addrf); - str = nullAddr; - } - else - { - std::string output; - - disR5900Fasm(output, *mem, addrf); - output.copy(str, 256); - } - - fprintf(f, "%s\n", str); - addrf += 4; - } - - fclose(f); - gtk_widget_destroy(DumpCDlg); - gtk_main_quit(); - gtk_widget_set_sensitive(DebugWnd, TRUE); -} - -void OnDumpC_Cancel(GtkButton *button, gpointer user_data) -{ - gtk_widget_destroy(DumpCDlg); - gtk_main_quit(); - gtk_widget_set_sensitive(DebugWnd, TRUE); -} - -void OnDebug_DumpCode(GtkButton *button, gpointer user_data) -{ - DumpCDlg = create_DumpCDlg(); - - DumpCFEntry = lookup_widget(DumpCDlg, "GtkEntry_DumpCF"); - DumpCTEntry = lookup_widget(DumpCDlg, "GtkEntry_DumpCT"); - - gtk_widget_show_all(DumpCDlg); - gtk_widget_set_sensitive(DebugWnd, FALSE); - gtk_main(); -} - -void OnDumpR_Ok(GtkButton *button, gpointer user_data) -{ - FILE *f; - char *str = (char*)gtk_entry_get_text(GTK_ENTRY(DumpRFEntry)); - u32 addrf, addrt; - - sscanf(str, "%lx", &addrf); - addrf &= ~0x3; - str = (char*)gtk_entry_get_text(GTK_ENTRY(DumpRTEntry)); - sscanf(str, "%lx", &addrt); - addrt &= ~0x3; - - f = fopen("dump.txt", "w"); - if (f == NULL) return; - - while (addrf != addrt) - { - u32 *mem; - u32 out; - - if (DebugMode) - { - mem = (u32*)PSXM(addrf); - } - else - { - mem = (u32*)PSM(addrf); - } - if (mem == NULL) out = 0; - else out = *mem; - - fwrite(&out, 4, 1, f); - addrf += 4; - } - - fclose(f); - gtk_widget_destroy(DumpRDlg); - gtk_main_quit(); - gtk_widget_set_sensitive(DebugWnd, TRUE); -} - -void OnDumpR_Cancel(GtkButton *button, gpointer user_data) -{ - gtk_widget_destroy(DumpRDlg); - gtk_main_quit(); - gtk_widget_set_sensitive(DebugWnd, TRUE); -} - -void OnDebug_RawDump(GtkButton *button, gpointer user_data) -{ - DumpRDlg = create_DumpRDlg(); - - DumpRFEntry = lookup_widget(DumpRDlg, "GtkEntry_DumpRF"); - DumpRTEntry = lookup_widget(DumpRDlg, "GtkEntry_DumpRT"); - - gtk_widget_show_all(DumpRDlg); - gtk_widget_set_sensitive(DebugWnd, FALSE); - gtk_main(); -} - -void OnDebug_Step(GtkButton *button, gpointer user_data) -{ - Cpu->Step(); - dPC = cpuRegs.pc; - UpdateDebugger(); -} - -void OnDebug_Skip(GtkButton *button, gpointer user_data) -{ - cpuRegs.pc += 4; - dPC = cpuRegs.pc; - UpdateDebugger(); -} - -int HasBreakPoint(u32 pc) -{ - if (pc == dBPA) return 1; - if (DebugMode == 0) - { - if ((cpuRegs.cycle - 10) <= dBPC && - (cpuRegs.cycle + 10) >= dBPC) return 1; - } - else - { - if ((psxRegs.cycle - 100) <= dBPC && - (psxRegs.cycle + 100) >= dBPC) return 1; - } - return 0; -} - -void OnDebug_Go(GtkButton *button, gpointer user_data) -{ - for (;;) - { - if (HasBreakPoint(cpuRegs.pc)) break; - Cpu->Step(); - } - dPC = cpuRegs.pc; - UpdateDebugger(); -} - -void OnDebug_Log(GtkButton *button, gpointer user_data) -{ -#ifdef PCSX2_DEVBUILD - //Log = 1 - Log; -#endif -} - -void OnDebug_EEMode(GtkToggleButton *togglebutton, gpointer user_data) -{ - DebugMode = 0; - dPC = cpuRegs.pc; - UpdateDebugger(); -} - -void OnDebug_IOPMode(GtkToggleButton *togglebutton, gpointer user_data) -{ - DebugMode = 1; - dPC = psxRegs.pc; - UpdateDebugger(); -} - -void OnMemWrite32_Ok(GtkButton *button, gpointer user_data) -{ - char *mem = (char*)gtk_entry_get_text(GTK_ENTRY(MemEntry)); - char *data = (char*)gtk_entry_get_text(GTK_ENTRY(DataEntry)); - - printf("memWrite32: %s, %s\n", mem, data); - memWrite32(strtol(mem, (char**)NULL, 0), strtol(data, (char**)NULL, 0)); - gtk_widget_destroy(MemWriteDlg); - gtk_main_quit(); - gtk_widget_set_sensitive(DebugWnd, TRUE); -} - -void OnMemWrite32_Cancel(GtkButton *button, gpointer user_data) -{ - gtk_widget_destroy(MemWriteDlg); - gtk_main_quit(); - gtk_widget_set_sensitive(DebugWnd, TRUE); -} - -void OnDebug_memWrite32(GtkButton *button, gpointer user_data) -{ - MemWriteDlg = create_MemWrite32(); - - MemEntry = lookup_widget(MemWriteDlg, "GtkEntry_Mem"); - DataEntry = lookup_widget(MemWriteDlg, "GtkEntry_Data"); - - gtk_widget_show_all(MemWriteDlg); - gtk_widget_set_sensitive(DebugWnd, FALSE); - gtk_main(); - - UpdateDebugger(); -} - -void OnDebug_Debugger(GtkMenuItem *menuitem, gpointer user_data) -{ - GtkWidget *scroll; - GtkCellRenderer *renderer; - GtkTreeViewColumn *column; - - if (OpenPlugins(NULL) == -1) return; - - /*if (!efile) - efile=GetPS2ElfName(elfname); - if (efile) - loadElfFile(elfname); - efile=0;*/ - - dPC = cpuRegs.pc; - - DebugWnd = create_DebugWnd(); - - ListDVModel = gtk_list_store_new(1, G_TYPE_STRING); - ListDV = lookup_widget(DebugWnd, "GtkList_DisView"); - gtk_tree_view_set_model(GTK_TREE_VIEW(ListDV), GTK_TREE_MODEL(ListDVModel)); - renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes("heading", renderer, - "text", 0, - NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(ListDV), column); - scroll = lookup_widget(DebugWnd, "GtkVScrollbar_VList"); - - DebugAdj = GTK_RANGE(scroll)->adjustment; - DebugAdj->lower = (gfloat)0x00000000 / 4; - DebugAdj->upper = (gfloat)0xffffffff / 4; - DebugAdj->step_increment = (gfloat)1; - DebugAdj->page_increment = (gfloat)20; - DebugAdj->page_size = (gfloat)23; - - gtk_signal_connect(GTK_OBJECT(DebugAdj), - "value_changed", GTK_SIGNAL_FUNC(OnDebug_ScrollChange), - NULL); - - UpdateDebugger(); - - gtk_widget_show_all(DebugWnd); - gtk_widget_set_sensitive(MainWindow, FALSE); - gtk_main(); +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "DebugDlg.h" +using namespace R5900; + +void UpdateDebugger() +{ + + char *str; + int i; + std::string output; + + DebugAdj->value = (gfloat)dPC / 4; + gtk_list_store_clear(ListDVModel); + + for (i = 0; i < 23; i++) + { + GtkTreeIter iter; + u32 *mem; + u32 pc = dPC + i * 4; + if (DebugMode) + { + mem = (u32*)PSXM(pc); + } + else + mem = (u32*)PSM(pc); + + if (mem == NULL) + { + sprintf(nullAddr, "%8.8lX:\tNULL MEMORY", pc); + str = nullAddr; + } + else + { + std::string output; + + disR5900Fasm(output, *mem, pc); + output.copy(str, 256); + } + gtk_list_store_append(ListDVModel, &iter); + gtk_list_store_set(ListDVModel, &iter, 0, str, -1); + + } +} + +void OnDebug_Close(GtkButton *button, gpointer user_data) +{ + ClosePlugins(); + gtk_widget_destroy(DebugWnd); + gtk_main_quit(); + gtk_widget_set_sensitive(MainWindow, TRUE); +} + +void OnDebug_ScrollChange(GtkAdjustment *adj) +{ + dPC = (u32)adj->value * 4; + dPC &= ~0x3; + + UpdateDebugger(); +} + +void OnSetPC_Ok(GtkButton *button, gpointer user_data) +{ + char *str = (char*)gtk_entry_get_text(GTK_ENTRY(SetPCEntry)); + + sscanf(str, "%lx", &dPC); + dPC &= ~0x3; + + gtk_widget_destroy(SetPCDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); + UpdateDebugger(); +} + +void OnSetPC_Cancel(GtkButton *button, gpointer user_data) +{ + gtk_widget_destroy(SetPCDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); +} + +void OnDebug_SetPC(GtkButton *button, gpointer user_data) +{ + SetPCDlg = create_SetPCDlg(); + + SetPCEntry = lookup_widget(SetPCDlg, "GtkEntry_dPC"); + + gtk_widget_show_all(SetPCDlg); + gtk_widget_set_sensitive(DebugWnd, FALSE); + gtk_main(); +} + +void OnSetBPA_Ok(GtkButton *button, gpointer user_data) +{ + char *str = (char*)gtk_entry_get_text(GTK_ENTRY(SetBPAEntry)); + + sscanf(str, "%lx", &dBPA); + dBPA &= ~0x3; + + gtk_widget_destroy(SetBPADlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); + UpdateDebugger(); +} + +void OnSetBPA_Cancel(GtkButton *button, gpointer user_data) +{ + gtk_widget_destroy(SetBPADlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); +} + +void OnDebug_SetBPA(GtkButton *button, gpointer user_data) +{ + SetBPADlg = create_SetBPADlg(); + + SetBPAEntry = lookup_widget(SetBPADlg, "GtkEntry_BPA"); + + gtk_widget_show_all(SetBPADlg); + gtk_widget_set_sensitive(DebugWnd, FALSE); + gtk_main(); +} + +void OnSetBPC_Ok(GtkButton *button, gpointer user_data) +{ + char *str = (char*)gtk_entry_get_text(GTK_ENTRY(SetBPCEntry)); + + sscanf(str, "%lx", &dBPC); + + gtk_widget_destroy(SetBPCDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); + UpdateDebugger(); +} + +void OnSetBPC_Cancel(GtkButton *button, gpointer user_data) +{ + gtk_widget_destroy(SetBPCDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); +} + +void OnDebug_SetBPC(GtkButton *button, gpointer user_data) +{ + SetBPCDlg = create_SetBPCDlg(); + + SetBPCEntry = lookup_widget(SetBPCDlg, "GtkEntry_BPC"); + + gtk_widget_show_all(SetBPCDlg); + gtk_widget_set_sensitive(DebugWnd, FALSE); + gtk_main(); +} + +void OnDebug_ClearBPs(GtkButton *button, gpointer user_data) +{ + dBPA = -1; + dBPC = -1; +} + +void OnDumpC_Ok(GtkButton *button, gpointer user_data) +{ + FILE *f; + char *str = (char*)gtk_entry_get_text(GTK_ENTRY(DumpCFEntry)); + u32 addrf, addrt; + + sscanf(str, "%lx", &addrf); + addrf &= ~0x3; + str = (char*)gtk_entry_get_text(GTK_ENTRY(DumpCTEntry)); + sscanf(str, "%lx", &addrt); + addrt &= ~0x3; + + f = fopen("dump.txt", "w"); + if (f == NULL) return; + + while (addrf != addrt) + { + u32 *mem; + + if (DebugMode) + { + mem = (u32*)PSXM(addrf); + } + else + { + mem = (u32*)PSM(addrf); + } + + if (mem == NULL) + { + sprintf(nullAddr, "%8.8lX:\tNULL MEMORY", addrf); + str = nullAddr; + } + else + { + std::string output; + + disR5900Fasm(output, *mem, addrf); + output.copy(str, 256); + } + + fprintf(f, "%s\n", str); + addrf += 4; + } + + fclose(f); + gtk_widget_destroy(DumpCDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); +} + +void OnDumpC_Cancel(GtkButton *button, gpointer user_data) +{ + gtk_widget_destroy(DumpCDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); +} + +void OnDebug_DumpCode(GtkButton *button, gpointer user_data) +{ + DumpCDlg = create_DumpCDlg(); + + DumpCFEntry = lookup_widget(DumpCDlg, "GtkEntry_DumpCF"); + DumpCTEntry = lookup_widget(DumpCDlg, "GtkEntry_DumpCT"); + + gtk_widget_show_all(DumpCDlg); + gtk_widget_set_sensitive(DebugWnd, FALSE); + gtk_main(); +} + +void OnDumpR_Ok(GtkButton *button, gpointer user_data) +{ + FILE *f; + char *str = (char*)gtk_entry_get_text(GTK_ENTRY(DumpRFEntry)); + u32 addrf, addrt; + + sscanf(str, "%lx", &addrf); + addrf &= ~0x3; + str = (char*)gtk_entry_get_text(GTK_ENTRY(DumpRTEntry)); + sscanf(str, "%lx", &addrt); + addrt &= ~0x3; + + f = fopen("dump.txt", "w"); + if (f == NULL) return; + + while (addrf != addrt) + { + u32 *mem; + u32 out; + + if (DebugMode) + { + mem = (u32*)PSXM(addrf); + } + else + { + mem = (u32*)PSM(addrf); + } + if (mem == NULL) out = 0; + else out = *mem; + + fwrite(&out, 4, 1, f); + addrf += 4; + } + + fclose(f); + gtk_widget_destroy(DumpRDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); +} + +void OnDumpR_Cancel(GtkButton *button, gpointer user_data) +{ + gtk_widget_destroy(DumpRDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); +} + +void OnDebug_RawDump(GtkButton *button, gpointer user_data) +{ + DumpRDlg = create_DumpRDlg(); + + DumpRFEntry = lookup_widget(DumpRDlg, "GtkEntry_DumpRF"); + DumpRTEntry = lookup_widget(DumpRDlg, "GtkEntry_DumpRT"); + + gtk_widget_show_all(DumpRDlg); + gtk_widget_set_sensitive(DebugWnd, FALSE); + gtk_main(); +} + +void OnDebug_Step(GtkButton *button, gpointer user_data) +{ + Cpu->Step(); + dPC = cpuRegs.pc; + UpdateDebugger(); +} + +void OnDebug_Skip(GtkButton *button, gpointer user_data) +{ + cpuRegs.pc += 4; + dPC = cpuRegs.pc; + UpdateDebugger(); +} + +int HasBreakPoint(u32 pc) +{ + if (pc == dBPA) return 1; + if (DebugMode == 0) + { + if ((cpuRegs.cycle - 10) <= dBPC && + (cpuRegs.cycle + 10) >= dBPC) return 1; + } + else + { + if ((psxRegs.cycle - 100) <= dBPC && + (psxRegs.cycle + 100) >= dBPC) return 1; + } + return 0; +} + +void OnDebug_Go(GtkButton *button, gpointer user_data) +{ + for (;;) + { + if (HasBreakPoint(cpuRegs.pc)) break; + Cpu->Step(); + } + dPC = cpuRegs.pc; + UpdateDebugger(); +} + +void OnDebug_Log(GtkButton *button, gpointer user_data) +{ +#ifdef PCSX2_DEVBUILD + //Log = 1 - Log; +#endif +} + +void OnDebug_EEMode(GtkToggleButton *togglebutton, gpointer user_data) +{ + DebugMode = 0; + dPC = cpuRegs.pc; + UpdateDebugger(); +} + +void OnDebug_IOPMode(GtkToggleButton *togglebutton, gpointer user_data) +{ + DebugMode = 1; + dPC = psxRegs.pc; + UpdateDebugger(); +} + +void OnMemWrite32_Ok(GtkButton *button, gpointer user_data) +{ + char *mem = (char*)gtk_entry_get_text(GTK_ENTRY(MemEntry)); + char *data = (char*)gtk_entry_get_text(GTK_ENTRY(DataEntry)); + + printf("memWrite32: %s, %s\n", mem, data); + memWrite32(strtol(mem, (char**)NULL, 0), strtol(data, (char**)NULL, 0)); + gtk_widget_destroy(MemWriteDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); +} + +void OnMemWrite32_Cancel(GtkButton *button, gpointer user_data) +{ + gtk_widget_destroy(MemWriteDlg); + gtk_main_quit(); + gtk_widget_set_sensitive(DebugWnd, TRUE); +} + +void OnDebug_memWrite32(GtkButton *button, gpointer user_data) +{ + MemWriteDlg = create_MemWrite32(); + + MemEntry = lookup_widget(MemWriteDlg, "GtkEntry_Mem"); + DataEntry = lookup_widget(MemWriteDlg, "GtkEntry_Data"); + + gtk_widget_show_all(MemWriteDlg); + gtk_widget_set_sensitive(DebugWnd, FALSE); + gtk_main(); + + UpdateDebugger(); +} + +void OnDebug_Debugger(GtkMenuItem *menuitem, gpointer user_data) +{ + GtkWidget *scroll; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + if (OpenPlugins(NULL) == -1) return; + + /*if (!efile) + efile=GetPS2ElfName(elfname); + if (efile) + loadElfFile(elfname); + efile=0;*/ + + dPC = cpuRegs.pc; + + DebugWnd = create_DebugWnd(); + + ListDVModel = gtk_list_store_new(1, G_TYPE_STRING); + ListDV = lookup_widget(DebugWnd, "GtkList_DisView"); + gtk_tree_view_set_model(GTK_TREE_VIEW(ListDV), GTK_TREE_MODEL(ListDVModel)); + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes("heading", renderer, + "text", 0, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(ListDV), column); + scroll = lookup_widget(DebugWnd, "GtkVScrollbar_VList"); + + DebugAdj = GTK_RANGE(scroll)->adjustment; + DebugAdj->lower = (gfloat)0x00000000 / 4; + DebugAdj->upper = (gfloat)0xffffffff / 4; + DebugAdj->step_increment = (gfloat)1; + DebugAdj->page_increment = (gfloat)20; + DebugAdj->page_size = (gfloat)23; + + gtk_signal_connect(GTK_OBJECT(DebugAdj), + "value_changed", GTK_SIGNAL_FUNC(OnDebug_ScrollChange), + NULL); + + UpdateDebugger(); + + gtk_widget_show_all(DebugWnd); + gtk_widget_set_sensitive(MainWindow, FALSE); + gtk_main(); } \ No newline at end of file diff --git a/pcsx2/Linux/DebugDlg.h b/pcsx2/Linux/DebugDlg.h index a712e591ab..8ff4fddc5b 100644 --- a/pcsx2/Linux/DebugDlg.h +++ b/pcsx2/Linux/DebugDlg.h @@ -1,46 +1,46 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __DEBUGDLG_H__ -#define __DEBUGDLG_H__ - -#include "Linux.h" -#include "R3000A.h" -#include "IopMem.h" - - -GtkWidget *ListDV; -GtkListStore *ListDVModel; -GtkWidget *SetPCDlg, *SetPCEntry; -GtkWidget *SetBPADlg, *SetBPAEntry; -GtkWidget *SetBPCDlg, *SetBPCEntry; -GtkWidget *DumpCDlg, *DumpCTEntry, *DumpCFEntry; -GtkWidget *DumpRDlg, *DumpRTEntry, *DumpRFEntry; -GtkWidget *MemWriteDlg, *MemEntry, *DataEntry; -GtkAdjustment *DebugAdj; - -extern int efile; -extern char elfname[g_MaxPath]; - -int DebugMode; // 0 - EE | 1 - IOP -static u32 dPC, dBPA = -1, dBPC = -1; -static char nullAddr[g_MaxPath]; - -GtkWidget *DebugWnd; - -#endif // __DEBUGDLG_H__ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __DEBUGDLG_H__ +#define __DEBUGDLG_H__ + +#include "Linux.h" +#include "R3000A.h" +#include "IopMem.h" + + +GtkWidget *ListDV; +GtkListStore *ListDVModel; +GtkWidget *SetPCDlg, *SetPCEntry; +GtkWidget *SetBPADlg, *SetBPAEntry; +GtkWidget *SetBPCDlg, *SetBPCEntry; +GtkWidget *DumpCDlg, *DumpCTEntry, *DumpCFEntry; +GtkWidget *DumpRDlg, *DumpRTEntry, *DumpRFEntry; +GtkWidget *MemWriteDlg, *MemEntry, *DataEntry; +GtkAdjustment *DebugAdj; + +extern int efile; +extern char elfname[g_MaxPath]; + +int DebugMode; // 0 - EE | 1 - IOP +static u32 dPC, dBPA = -1, dBPC = -1; +static char nullAddr[g_MaxPath]; + +GtkWidget *DebugWnd; + +#endif // __DEBUGDLG_H__ diff --git a/pcsx2/Linux/Linux.h b/pcsx2/Linux/Linux.h index 409ca43a57..ff7531385f 100644 --- a/pcsx2/Linux/Linux.h +++ b/pcsx2/Linux/Linux.h @@ -1,187 +1,187 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __LINUX_H__ -#define __LINUX_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "PrecompiledHeader.h" -#include "Paths.h" -#include "Common.h" - -#include "Counters.h" -#include "VUmicro.h" -#include "Plugins.h" -#include "x86/ix86/ix86.h" -#include "x86/iR5900.h" - - #ifdef __cplusplus -extern "C" -{ -#endif - -#include "support.h" -#include "callbacks.h" -#include "interface.h" - -#ifdef __cplusplus -} -#endif - -extern void SaveConfig(); - -extern bool UseGui; - -extern int Pcsx2Configure(); - -extern int LoadConfig(); -extern void SaveConfig(); - -extern void SysRestorableReset(); -extern void SignalExit(int sig); -extern bool isSlotUsed(int num); -typedef struct -{ - char lang[g_MaxPath]; -} _langs; - -_langs *langs; -unsigned int langsMax; - -typedef enum -{ - GS, - PAD1, - PAD2, - SPU, - CDVD, - DEV9, - USB, - FW, - BIOS -} plugin_types; - -extern GtkWidget *MainWindow; -extern bool configuringplug; - - -char cfgfile[g_MaxPath]; - -/* Hacks */ - -int Config_hacks_backup; - -#define is_checked(main_widget, widget_name) (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(main_widget, widget_name)))) -#define set_checked(main_widget,widget_name, state) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(main_widget, widget_name)), state) - -#define set_flag(v, flag, value) if (value == TRUE) v |= flag; else v &= flag; -#define get_flag(v,flag) ((v & (1 << flag)) != 0) - -char ee_log_names[17][32] = -{ - "Cpu Log", - "Mem Log", - "HW Log", - "Dma Log", - "Bios Log", - "Elf Log", - "Fpu Log", - "MMI Log", - "VU0 Log", - "Cop0 Log", - "Vif Log", - "SPR Log", - "GIF Log", - "Sif Log", - "IPU Log", - "VU Micro Log", - "RPC Log" -}; - -char iop_log_names[9][32] = -{ - "IOP Log", - "Mem Log", - "HW Log", - "Bios Log", - "Dma Log", - "Pad Log", - "Gte Log", - "Cdr Log", - "GPU Log" -}; - -#define FLAG_VU_ADD_SUB 0x1 -#define FLAG_VU_CLIP 0x2 -#define FLAG_FPU_CLAMP 0x4 -#define FLAG_VU_BRANCH 0x8 -#define FLAG_AVOID_DELAY_HANDLING 0x10 - -#define FLAG_VU_NO_OVERFLOW 0x2 -#define FLAG_VU_EXTRA_OVERFLOW 0x40 - -#define FLAG_FPU_NO_OVERFLOW 0x800 -#define FLAG_FPU_EXTRA_OVERFLOW 0x1000 - -#define FLAG_EE_2_SYNC 0x1 -#define FLAG_IOP_2_SYNC 0x10 -#define FLAG_TRIPLE_SYNC 0x20 -#define FLAG_ESC 0x400 - -#define FLAG_ROUND_NEAR 0x0000 -#define FLAG_ROUND_NEGATIVE 0x2000 -#define FLAG_ROUND_POSITIVE 0x4000 -#define FLAG_ROUND_ZERO 0x6000 - -#define FLAG_FLUSH_ZERO 0x8000 -#define FLAG_DENORMAL_ZERO 0x0040 - -#define FLAG_VU_CLAMP_NONE 0x0 -#define FLAG_VU_CLAMP_NORMAL 0x1 -#define FLAG_VU_CLAMP_EXTRA 0x3 -#define FLAG_VU_CLAMP_EXTRA_PRESERVE 0x7 - -#define FLAG_EE_CLAMP_NONE 0x0 -#define FLAG_EE_CLAMP_NORMAL 0x1 -#define FLAG_EE_CLAMP_EXTRA_PRESERVE 0x3 - -#endif /* __LINUX_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __LINUX_H__ +#define __LINUX_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "PrecompiledHeader.h" +#include "Paths.h" +#include "Common.h" + +#include "Counters.h" +#include "VUmicro.h" +#include "Plugins.h" +#include "x86/ix86/ix86.h" +#include "x86/iR5900.h" + + #ifdef __cplusplus +extern "C" +{ +#endif + +#include "support.h" +#include "callbacks.h" +#include "interface.h" + +#ifdef __cplusplus +} +#endif + +extern void SaveConfig(); + +extern bool UseGui; + +extern int Pcsx2Configure(); + +extern int LoadConfig(); +extern void SaveConfig(); + +extern void SysRestorableReset(); +extern void SignalExit(int sig); +extern bool isSlotUsed(int num); +typedef struct +{ + char lang[g_MaxPath]; +} _langs; + +_langs *langs; +unsigned int langsMax; + +typedef enum +{ + GS, + PAD1, + PAD2, + SPU, + CDVD, + DEV9, + USB, + FW, + BIOS +} plugin_types; + +extern GtkWidget *MainWindow; +extern bool configuringplug; + + +char cfgfile[g_MaxPath]; + +/* Hacks */ + +int Config_hacks_backup; + +#define is_checked(main_widget, widget_name) (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(main_widget, widget_name)))) +#define set_checked(main_widget,widget_name, state) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(main_widget, widget_name)), state) + +#define set_flag(v, flag, value) if (value == TRUE) v |= flag; else v &= flag; +#define get_flag(v,flag) ((v & (1 << flag)) != 0) + +char ee_log_names[17][32] = +{ + "Cpu Log", + "Mem Log", + "HW Log", + "Dma Log", + "Bios Log", + "Elf Log", + "Fpu Log", + "MMI Log", + "VU0 Log", + "Cop0 Log", + "Vif Log", + "SPR Log", + "GIF Log", + "Sif Log", + "IPU Log", + "VU Micro Log", + "RPC Log" +}; + +char iop_log_names[9][32] = +{ + "IOP Log", + "Mem Log", + "HW Log", + "Bios Log", + "Dma Log", + "Pad Log", + "Gte Log", + "Cdr Log", + "GPU Log" +}; + +#define FLAG_VU_ADD_SUB 0x1 +#define FLAG_VU_CLIP 0x2 +#define FLAG_FPU_CLAMP 0x4 +#define FLAG_VU_BRANCH 0x8 +#define FLAG_AVOID_DELAY_HANDLING 0x10 + +#define FLAG_VU_NO_OVERFLOW 0x2 +#define FLAG_VU_EXTRA_OVERFLOW 0x40 + +#define FLAG_FPU_NO_OVERFLOW 0x800 +#define FLAG_FPU_EXTRA_OVERFLOW 0x1000 + +#define FLAG_EE_2_SYNC 0x1 +#define FLAG_IOP_2_SYNC 0x10 +#define FLAG_TRIPLE_SYNC 0x20 +#define FLAG_ESC 0x400 + +#define FLAG_ROUND_NEAR 0x0000 +#define FLAG_ROUND_NEGATIVE 0x2000 +#define FLAG_ROUND_POSITIVE 0x4000 +#define FLAG_ROUND_ZERO 0x6000 + +#define FLAG_FLUSH_ZERO 0x8000 +#define FLAG_DENORMAL_ZERO 0x0040 + +#define FLAG_VU_CLAMP_NONE 0x0 +#define FLAG_VU_CLAMP_NORMAL 0x1 +#define FLAG_VU_CLAMP_EXTRA 0x3 +#define FLAG_VU_CLAMP_EXTRA_PRESERVE 0x7 + +#define FLAG_EE_CLAMP_NONE 0x0 +#define FLAG_EE_CLAMP_NORMAL 0x1 +#define FLAG_EE_CLAMP_EXTRA_PRESERVE 0x3 + +#endif /* __LINUX_H__ */ diff --git a/pcsx2/Linux/LnxConsole.cpp b/pcsx2/Linux/LnxConsole.cpp index ee000a42ad..8b3fe4fa65 100644 --- a/pcsx2/Linux/LnxConsole.cpp +++ b/pcsx2/Linux/LnxConsole.cpp @@ -1,145 +1,145 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "Linux.h" - -#define COLOR_RESET "\033[0m" - -// Linux Note : The Linux Console is pretty simple. It just dumps to the stdio! -// (no console open/close/title stuff tho, so those functions are dummies) - -// Fixme - A lot of extra \ns are being added in here somewhere. I think it's -// partially in SetColor/ClearColor, as colored lines have more extra \ns then the other -// lines. -namespace Console -{ -static const char* tbl_color_codes[] = -{ - "\033[30m" // black - , "\033[31m" // red - , "\033[32m" // green - , "\033[33m" // yellow - , "\033[34m" // blue - , "\033[35m" // magenta - , "\033[36m" // cyan - , "\033[37m" // white! -}; - -void SetTitle(const string& title) -{ -} - -void Open() -{ -} - -void Close() -{ -} - -__forceinline bool __fastcall Newline() -{ - if (Config.PsxOut) - puts("\n"); - - if (emuLog != NULL) - { - fputs("\n", emuLog); - fflush(emuLog); - } - - return false; -} - -__forceinline bool __fastcall Write(const char* fmt) -{ - if (Config.PsxOut) - puts(fmt); - - if (emuLog != NULL) - fputs(fmt, emuLog); - - return false; -} - -void __fastcall SetColor(Colors color) -{ - Write(tbl_color_codes[color]); -} - -void ClearColor() -{ - Write(COLOR_RESET); -} -} - -namespace Msgbox -{ -bool Alert(const char* fmt) -{ - GtkWidget *dialog; - - if (!UseGui) - { - Console::Error(fmt); - return false; - } - - - dialog = gtk_message_dialog_new(GTK_WINDOW(MainWindow), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, fmt); - gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - - return false; -} - -bool Alert(const char* fmt, VARG_PARAM dummy, ...) -{ - GtkWidget *dialog; - string msg; - va_list list; - - va_start(list, dummy); - vssprintf(msg, fmt, list); - va_end(list); - - // fixme: using NULL terminators on std::string might work, but are technically "incorrect." - // This should use one of the std::string trimming functions instead. - if (msg[msg.length()-1] == '\n') - msg[msg.length()-1] = 0; - - if (!UseGui) - { - Console::Error(msg.c_str()); - return false; - } - - dialog = gtk_message_dialog_new(GTK_WINDOW(MainWindow), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, msg.c_str()); - gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - - return false; -} -} - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "Linux.h" + +#define COLOR_RESET "\033[0m" + +// Linux Note : The Linux Console is pretty simple. It just dumps to the stdio! +// (no console open/close/title stuff tho, so those functions are dummies) + +// Fixme - A lot of extra \ns are being added in here somewhere. I think it's +// partially in SetColor/ClearColor, as colored lines have more extra \ns then the other +// lines. +namespace Console +{ +static const char* tbl_color_codes[] = +{ + "\033[30m" // black + , "\033[31m" // red + , "\033[32m" // green + , "\033[33m" // yellow + , "\033[34m" // blue + , "\033[35m" // magenta + , "\033[36m" // cyan + , "\033[37m" // white! +}; + +void SetTitle(const string& title) +{ +} + +void Open() +{ +} + +void Close() +{ +} + +__forceinline bool __fastcall Newline() +{ + if (Config.PsxOut) + puts("\n"); + + if (emuLog != NULL) + { + fputs("\n", emuLog); + fflush(emuLog); + } + + return false; +} + +__forceinline bool __fastcall Write(const char* fmt) +{ + if (Config.PsxOut) + puts(fmt); + + if (emuLog != NULL) + fputs(fmt, emuLog); + + return false; +} + +void __fastcall SetColor(Colors color) +{ + Write(tbl_color_codes[color]); +} + +void ClearColor() +{ + Write(COLOR_RESET); +} +} + +namespace Msgbox +{ +bool Alert(const char* fmt) +{ + GtkWidget *dialog; + + if (!UseGui) + { + Console::Error(fmt); + return false; + } + + + dialog = gtk_message_dialog_new(GTK_WINDOW(MainWindow), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, fmt); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + + return false; +} + +bool Alert(const char* fmt, VARG_PARAM dummy, ...) +{ + GtkWidget *dialog; + string msg; + va_list list; + + va_start(list, dummy); + vssprintf(msg, fmt, list); + va_end(list); + + // fixme: using NULL terminators on std::string might work, but are technically "incorrect." + // This should use one of the std::string trimming functions instead. + if (msg[msg.length()-1] == '\n') + msg[msg.length()-1] = 0; + + if (!UseGui) + { + Console::Error(msg.c_str()); + return false; + } + + dialog = gtk_message_dialog_new(GTK_WINDOW(MainWindow), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, msg.c_str()); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + + return false; +} +} + diff --git a/pcsx2/Linux/LnxMain.cpp b/pcsx2/Linux/LnxMain.cpp index a599a98141..b9dd0028b4 100644 --- a/pcsx2/Linux/LnxMain.cpp +++ b/pcsx2/Linux/LnxMain.cpp @@ -1,637 +1,637 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "LnxMain.h" - -using namespace R5900; - -DIR *dir; -GtkWidget *FileSel; -GtkWidget *MsgDlg; -bool configuringplug = FALSE; -const char* g_pRunGSState = NULL; - -int efile = 0; -char elfname[g_MaxPath]; -bool Slots[5] = { false, false, false, false, false }; - -#ifdef PCSX2_DEVBUILD -TESTRUNARGS g_TestRun; -#endif - - -int main(int argc, char *argv[]) -{ - char *file = NULL; - char elfname[g_MaxPath]; - int i = 1; - - efile = 0; -#ifdef ENABLE_NLS - setlocale(LC_ALL, ""); - bindtextdomain(PACKAGE, "Langs"); - textdomain(PACKAGE); -#endif - - printf("\n"); - mkdir(CONFIG_DIR, 0755); - - strcpy(cfgfile, CONFIG_DIR "/pcsx2.cfg"); - -#ifdef PCSX2_DEVBUILD - memset(&g_TestRun, 0, sizeof(g_TestRun)); -#endif - - while (i < argc) - { - char* token = argv[i++]; - - if (stricmp(token, "-help") == 0 || stricmp(token, "--help") == 0 || stricmp(token, "-h") == 0) - { - //Msgbox::Alert( phelpmsg ); - return 0; - } - else if (stricmp(token, "-efile") == 0) - { - token = argv[i++]; - if (token != NULL) - { - efile = atoi(token); - } - } - else if (stricmp(token, "-nogui") == 0) - { - UseGui = FALSE; - } - else if (stricmp(token, "-loadgs") == 0) - { - g_pRunGSState = argv[i++]; - } -#ifdef PCSX2_DEVBUILD - else if (stricmp(token, "-image") == 0) - { - g_TestRun.pimagename = argv[i++]; - } - else if (stricmp(token, "-log") == 0) - { - g_TestRun.plogname = argv[i++]; - } - else if (stricmp(token, "-logopt") == 0) - { - token = argv[i++]; - if (token != NULL) - { - if (token[0] == '0' && token[1] == 'x') token += 2; - sscanf(token, "%x", &varLog); - } - } - else if (stricmp(token, "-frame") == 0) - { - token = argv[i++]; - if (token != NULL) - { - g_TestRun.frame = atoi(token); - } - } - else if (stricmp(token, "-numimages") == 0) - { - token = argv[i++]; - if (token != NULL) - { - g_TestRun.numimages = atoi(token); - } - } - else if (stricmp(token, "-jpg") == 0) - { - g_TestRun.jpgcapture = 1; - } - else if (stricmp(token, "-gs") == 0) - { - token = argv[i++]; - g_TestRun.pgsdll = token; - } - else if (stricmp(token, "-cdvd") == 0) - { - token = argv[i++]; - g_TestRun.pcdvddll = token; - } - else if (stricmp(token, "-spu") == 0) - { - token = argv[i++]; - g_TestRun.pspudll = token; - } - else if (stricmp(token, "-test") == 0) - { - g_TestRun.enabled = 1; - } -#endif - else if (stricmp(token, "-pad") == 0) - { - token = argv[i++]; - printf("-pad ignored\n"); - } - else if (stricmp(token, "-loadgs") == 0) - { - token = argv[i++]; - g_pRunGSState = token; - } - else - { - file = token; - printf("opening file %s\n", file); - } - } - -#ifdef PCSX2_DEVBUILD - g_TestRun.efile = efile; - g_TestRun.ptitle = file; -#endif - - // make gtk thread safe if using MTGS - if (CHECK_MULTIGS) - { - g_thread_init(NULL); - gdk_threads_init(); - } - - if (UseGui) - { - gtk_init(NULL, NULL); - } - - if (LoadConfig() == -1) - { - - memset(&Config, 0, sizeof(Config)); - strcpy(Config.BiosDir, DEFAULT_BIOS_DIR "/"); - strcpy(Config.PluginsDir, DEFAULT_PLUGINS_DIR "/"); - Config.Patch = 1; - Config.Options = PCSX2_EEREC | PCSX2_VU0REC | PCSX2_VU1REC; - Config.sseMXCSR = DEFAULT_sseMXCSR; - Config.sseVUMXCSR = DEFAULT_sseVUMXCSR; - - Msgbox::Alert("Pcsx2 needs to be configured"); - Pcsx2Configure(); - - return 0; - } - - InitLanguages(); - - if (Config.PsxOut) - { - // output the help commands - Console::WriteLn("\tF1 - save state"); - Console::WriteLn("\t(Shift +) F2 - cycle states"); - Console::WriteLn("\tF3 - load state"); - -#ifdef PCSX2_DEVBUILD - Console::WriteLn("\tF10 - dump performance counters"); - Console::WriteLn("\tF11 - save GS state"); - Console::WriteLn("\tF12 - dump hardware registers"); -#endif - } - - if (!SysInit()) return 1; - -#ifdef PCSX2_DEVBUILD - if (g_pRunGSState) - { - LoadGSState(g_pRunGSState); - SysClose(); - return 0; - } -#endif - - if (UseGui && (file == NULL)) - { - StartGui(); - return 0; - } - - if (OpenPlugins(file) == -1) return -1; - - SysReset(); - - cpuExecuteBios(); - if (file) strcpy(elfname, file); - if (!efile) efile = GetPS2ElfName(elfname); - loadElfFile(elfname); - - ExecuteCpu(); - - return 0; -} - -void InitLanguages() -{ - char *lang; - int i = 1; - - if (Config.Lang[0] == 0) - { - strcpy(Config.Lang, "en"); - } - - langs = (_langs*)malloc(sizeof(_langs)); - strcpy(langs[0].lang, "en"); - dir = opendir(LANGS_DIR); - - while ((lang = GetLanguageNext()) != NULL) - { - langs = (_langs*)realloc(langs, sizeof(_langs) * (i + 1)); - strcpy(langs[i].lang, lang); - i++; - } - - CloseLanguages(); - langsMax = i; -} - -char *GetLanguageNext() -{ - struct dirent *ent; - - if (dir == NULL) return NULL; - for (;;) - { - ent = readdir(dir); - if (ent == NULL) return NULL; - - if (!strcmp(ent->d_name, ".")) continue; - if (!strcmp(ent->d_name, "..")) continue; - break; - } - - return ent->d_name; -} - -void CloseLanguages() -{ - if (dir) closedir(dir); -} - -void ChangeLanguage(char *lang) -{ - strcpy(Config.Lang, lang); - SaveConfig(); -} - -void OnMsg_Ok() -{ - gtk_widget_destroy(MsgDlg); - gtk_main_quit(); -} - - -void On_Dialog_Cancelled(GtkButton* button, gpointer user_data) -{ - gtk_widget_destroy((GtkWidget*)gtk_widget_get_toplevel((GtkWidget*)button)); - gtk_widget_set_sensitive(MainWindow, TRUE); - gtk_main_quit(); -} - -void StartGui() -{ - GtkWidget *Menu; - GtkWidget *Item; - - u32 i; - - add_pixmap_directory(".pixmaps"); - MainWindow = create_MainWindow(); - - if (SVN_REV != 0) - gtk_window_set_title(GTK_WINDOW(MainWindow), "PCSX2 "PCSX2_VERSION" "SVN_REV); - else - gtk_window_set_title(GTK_WINDOW(MainWindow), "PCSX2 "PCSX2_VERSION); - - // status bar - pStatusBar = gtk_statusbar_new(); - gtk_box_pack_start(GTK_BOX(lookup_widget(MainWindow, "status_box")), pStatusBar, TRUE, TRUE, 0); - gtk_widget_show(pStatusBar); - - gtk_statusbar_push(GTK_STATUSBAR(pStatusBar), 0, - "F1 - save, F2 - next state, Shift+F2 - prev state, F3 - load, F8 - snapshot"); - - // add all the languages - Item = lookup_widget(MainWindow, "GtkMenuItem_Language"); - Menu = gtk_menu_new(); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(Item), Menu); - - for (i = 0; i < langsMax; i++) - { - Item = gtk_check_menu_item_new_with_label(ParseLang(langs[i].lang)); - gtk_widget_show(Item); - gtk_container_add(GTK_CONTAINER(Menu), Item); - gtk_check_menu_item_set_show_toggle(GTK_CHECK_MENU_ITEM(Item), TRUE); - if (!strcmp(Config.Lang, langs[i].lang)) - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(Item), TRUE); - - gtk_signal_connect(GTK_OBJECT(Item), "activate", - GTK_SIGNAL_FUNC(OnLanguage), - (gpointer)(uptr)i); - } - - // check the appropriate menu items - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(lookup_widget(MainWindow, "enable_console1")), Config.PsxOut); - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(lookup_widget(MainWindow, "enable_patches1")), Config.Patch); - - // disable anything not implemented or not working properly. - gtk_widget_set_sensitive(GTK_WIDGET(lookup_widget(MainWindow, "patch_browser1")), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(lookup_widget(MainWindow, "patch_finder2")), FALSE); -#ifndef PCSX2_DEVBUILD - gtk_widget_set_sensitive(GTK_WIDGET(lookup_widget(MainWindow, "GtkMenuItem_Logging")), FALSE); -#endif - - CheckSlots(); - - gtk_widget_show_all(MainWindow); - gtk_window_activate_focus(GTK_WINDOW(MainWindow)); - gtk_main(); -} - -void OnDestroy(GtkObject *object, gpointer user_data) {} - -gboolean OnDelete(GtkWidget *widget, GdkEvent *event, gpointer user_data) -{ - pcsx2_exit(); - return (FALSE); -} - -int Pcsx2Configure() -{ - if (!UseGui) return 0; - - configuringplug = TRUE; - MainWindow = NULL; - OnConf_Conf(NULL, 0); - configuringplug = FALSE; - - return applychanges; -} - -void OnLanguage(GtkMenuItem *menuitem, gpointer user_data) -{ - ChangeLanguage(langs[(int)(uptr)user_data].lang); - gtk_widget_destroy(MainWindow); - gtk_main_quit(); - while (gtk_events_pending()) gtk_main_iteration(); - StartGui(); -} - -void OnFile_RunCD(GtkMenuItem *menuitem, gpointer user_data) -{ - safe_free(g_RecoveryState); - ResetPlugins(); - RunExecute(NULL); -} - -void OnRunElf_Ok(GtkButton* button, gpointer user_data) -{ - gchar *File; - - File = (gchar*)gtk_file_selection_get_filename(GTK_FILE_SELECTION(FileSel)); - strcpy(elfname, File); - gtk_widget_destroy(FileSel); - - RunExecute(elfname); -} - -void OnRunElf_Cancel(GtkButton* button, gpointer user_data) -{ - gtk_widget_destroy(FileSel); -} - -void OnFile_LoadElf(GtkMenuItem *menuitem, gpointer user_data) -{ - GtkWidget *Ok, *Cancel; - - FileSel = gtk_file_selection_new("Select Psx Elf File"); - - Ok = GTK_FILE_SELECTION(FileSel)->ok_button; - gtk_signal_connect(GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnRunElf_Ok), NULL); - gtk_widget_show(Ok); - - Cancel = GTK_FILE_SELECTION(FileSel)->cancel_button; - gtk_signal_connect(GTK_OBJECT(Cancel), "clicked", GTK_SIGNAL_FUNC(OnRunElf_Cancel), NULL); - gtk_widget_show(Cancel); - - gtk_widget_show(FileSel); - gdk_window_raise(FileSel->window); -} - -void pcsx2_exit() -{ - DIR *dir; - struct dirent *ent; - void *Handle; - char plugin[g_MaxPath]; - - // with this the problem with plugins that are linked with the pthread - // library is solved - - dir = opendir(Config.PluginsDir); - if (dir != NULL) - { - while ((ent = readdir(dir)) != NULL) - { - sprintf(plugin, "%s%s", Config.PluginsDir, ent->d_name); - - if (strstr(plugin, ".so") == NULL) continue; - Handle = dlopen(plugin, RTLD_NOW); - if (Handle == NULL) continue; - } - } - - printf("PCSX2 Quitting\n"); - - if (UseGui) - { - gtk_main_quit(); - SysClose(); - gtk_exit(0); - } - else - { - SysClose(); - exit(0); - } -} - -void SignalExit(int sig) -{ - ClosePlugins(); - pcsx2_exit(); -} - -void OnFile_Exit(GtkMenuItem *menuitem, gpointer user_data) -{ - pcsx2_exit(); -} - -void OnEmu_Run(GtkMenuItem *menuitem, gpointer user_data) -{ - if (g_EmulationInProgress) - ExecuteCpu(); - else - RunExecute(NULL, true); // boots bios if no savestate is to be recovered - -} - -void OnEmu_Reset(GtkMenuItem *menuitem, gpointer user_data) -{ - SysReset(); -} - -void ResetMenuSlots() -{ - GtkWidget *Item; - char str[g_MaxPath], str2[g_MaxPath]; - int i; - - for (i = 0; i < 5; i++) - { - - sprintf(str, "load_slot_%d", i); - sprintf(str2, "save_slot_%d", i); - Item = lookup_widget(MainWindow, str); - - if GTK_IS_WIDGET(Item) - gtk_widget_set_sensitive(Item, Slots[i]); - else - Console::Error("No such widget: %s", params str); - - Item = lookup_widget(MainWindow, str2); - gtk_widget_set_sensitive(Item, (ElfCRC != 0)); - - } -} - -void CheckSlots() -{ - int i = 0; - - if (ElfCRC == 0) Console::Notice("Disabling game slots until a game is loaded."); - - for (i=0; i<5; i++) - { - if (isSlotUsed(i)) - Slots[i] = true; - else - Slots[i] = false; - } - ResetMenuSlots(); -} - -//2002-09-28 (Florin) -void OnArguments_Ok(GtkButton *button, gpointer user_data) -{ - char *str; - - str = (char*)gtk_entry_get_text(GTK_ENTRY(widgetCmdLine)); - memcpy(args, str, g_MaxPath); - - gtk_widget_destroy(CmdLine); - gtk_widget_set_sensitive(MainWindow, TRUE); - gtk_main_quit(); -} - -void OnEmu_Arguments(GtkMenuItem *menuitem, gpointer user_data) -{ - GtkWidget *widgetCmdLine; - - CmdLine = create_CmdLine(); - gtk_window_set_title(GTK_WINDOW(CmdLine), _("Program arguments")); - - widgetCmdLine = lookup_widget(CmdLine, "GtkEntry_dCMDLINE"); - - gtk_entry_set_text(GTK_ENTRY(widgetCmdLine), args); - gtk_widget_show_all(CmdLine); - gtk_widget_set_sensitive(MainWindow, FALSE); - gtk_main(); -} - -void OnLogging_Ok(GtkButton *button, gpointer user_data) -{ -#ifdef PCSX2_DEVBUILD - GtkWidget *Btn; - char str[32]; - int i, ret; - - - for (i = 0; i < 32; i++) - { - if (((i > 16) && (i < 20)) || (i == 29)) - continue; - - sprintf(str, "Log%d", i); - Btn = lookup_widget(LogDlg, str); - ret = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(Btn)); - if (ret) varLog |= 1 << i; - else varLog &= ~(1 << i); - } - - SaveConfig(); -#endif - - gtk_widget_destroy(LogDlg); - gtk_widget_set_sensitive(MainWindow, TRUE); - gtk_main_quit(); -} - -void OnDebug_Logging(GtkMenuItem *menuitem, gpointer user_data) -{ - GtkWidget *Btn; - char str[32]; - int i; - - LogDlg = create_Logging(); - - - for (i = 0; i < 32; i++) - { - if (((i > 16) && (i < 20)) || (i == 29)) - continue; - - sprintf(str, "Log%d", i); - Btn = lookup_widget(LogDlg, str); - gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(Btn), varLog & (1 << i)); - } - - gtk_widget_show_all(LogDlg); - gtk_widget_set_sensitive(MainWindow, FALSE); - gtk_main(); -} - -void on_patch_browser1_activate(GtkMenuItem *menuitem, gpointer user_data) {} - -void on_patch_finder2_activate(GtkMenuItem *menuitem, gpointer user_data) {} - -void on_enable_console1_activate(GtkMenuItem *menuitem, gpointer user_data) -{ - Config.PsxOut = (int)gtk_check_menu_item_get_active((GtkCheckMenuItem*)menuitem); - SaveConfig(); -} - -void on_enable_patches1_activate(GtkMenuItem *menuitem, gpointer user_data) -{ - Config.Patch = (int)gtk_check_menu_item_get_active((GtkCheckMenuItem*)menuitem); - SaveConfig(); -} - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "LnxMain.h" + +using namespace R5900; + +DIR *dir; +GtkWidget *FileSel; +GtkWidget *MsgDlg; +bool configuringplug = FALSE; +const char* g_pRunGSState = NULL; + +int efile = 0; +char elfname[g_MaxPath]; +bool Slots[5] = { false, false, false, false, false }; + +#ifdef PCSX2_DEVBUILD +TESTRUNARGS g_TestRun; +#endif + + +int main(int argc, char *argv[]) +{ + char *file = NULL; + char elfname[g_MaxPath]; + int i = 1; + + efile = 0; +#ifdef ENABLE_NLS + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, "Langs"); + textdomain(PACKAGE); +#endif + + printf("\n"); + mkdir(CONFIG_DIR, 0755); + + strcpy(cfgfile, CONFIG_DIR "/pcsx2.cfg"); + +#ifdef PCSX2_DEVBUILD + memset(&g_TestRun, 0, sizeof(g_TestRun)); +#endif + + while (i < argc) + { + char* token = argv[i++]; + + if (stricmp(token, "-help") == 0 || stricmp(token, "--help") == 0 || stricmp(token, "-h") == 0) + { + //Msgbox::Alert( phelpmsg ); + return 0; + } + else if (stricmp(token, "-efile") == 0) + { + token = argv[i++]; + if (token != NULL) + { + efile = atoi(token); + } + } + else if (stricmp(token, "-nogui") == 0) + { + UseGui = FALSE; + } + else if (stricmp(token, "-loadgs") == 0) + { + g_pRunGSState = argv[i++]; + } +#ifdef PCSX2_DEVBUILD + else if (stricmp(token, "-image") == 0) + { + g_TestRun.pimagename = argv[i++]; + } + else if (stricmp(token, "-log") == 0) + { + g_TestRun.plogname = argv[i++]; + } + else if (stricmp(token, "-logopt") == 0) + { + token = argv[i++]; + if (token != NULL) + { + if (token[0] == '0' && token[1] == 'x') token += 2; + sscanf(token, "%x", &varLog); + } + } + else if (stricmp(token, "-frame") == 0) + { + token = argv[i++]; + if (token != NULL) + { + g_TestRun.frame = atoi(token); + } + } + else if (stricmp(token, "-numimages") == 0) + { + token = argv[i++]; + if (token != NULL) + { + g_TestRun.numimages = atoi(token); + } + } + else if (stricmp(token, "-jpg") == 0) + { + g_TestRun.jpgcapture = 1; + } + else if (stricmp(token, "-gs") == 0) + { + token = argv[i++]; + g_TestRun.pgsdll = token; + } + else if (stricmp(token, "-cdvd") == 0) + { + token = argv[i++]; + g_TestRun.pcdvddll = token; + } + else if (stricmp(token, "-spu") == 0) + { + token = argv[i++]; + g_TestRun.pspudll = token; + } + else if (stricmp(token, "-test") == 0) + { + g_TestRun.enabled = 1; + } +#endif + else if (stricmp(token, "-pad") == 0) + { + token = argv[i++]; + printf("-pad ignored\n"); + } + else if (stricmp(token, "-loadgs") == 0) + { + token = argv[i++]; + g_pRunGSState = token; + } + else + { + file = token; + printf("opening file %s\n", file); + } + } + +#ifdef PCSX2_DEVBUILD + g_TestRun.efile = efile; + g_TestRun.ptitle = file; +#endif + + // make gtk thread safe if using MTGS + if (CHECK_MULTIGS) + { + g_thread_init(NULL); + gdk_threads_init(); + } + + if (UseGui) + { + gtk_init(NULL, NULL); + } + + if (LoadConfig() == -1) + { + + memset(&Config, 0, sizeof(Config)); + strcpy(Config.BiosDir, DEFAULT_BIOS_DIR "/"); + strcpy(Config.PluginsDir, DEFAULT_PLUGINS_DIR "/"); + Config.Patch = 1; + Config.Options = PCSX2_EEREC | PCSX2_VU0REC | PCSX2_VU1REC; + Config.sseMXCSR = DEFAULT_sseMXCSR; + Config.sseVUMXCSR = DEFAULT_sseVUMXCSR; + + Msgbox::Alert("Pcsx2 needs to be configured"); + Pcsx2Configure(); + + return 0; + } + + InitLanguages(); + + if (Config.PsxOut) + { + // output the help commands + Console::WriteLn("\tF1 - save state"); + Console::WriteLn("\t(Shift +) F2 - cycle states"); + Console::WriteLn("\tF3 - load state"); + +#ifdef PCSX2_DEVBUILD + Console::WriteLn("\tF10 - dump performance counters"); + Console::WriteLn("\tF11 - save GS state"); + Console::WriteLn("\tF12 - dump hardware registers"); +#endif + } + + if (!SysInit()) return 1; + +#ifdef PCSX2_DEVBUILD + if (g_pRunGSState) + { + LoadGSState(g_pRunGSState); + SysClose(); + return 0; + } +#endif + + if (UseGui && (file == NULL)) + { + StartGui(); + return 0; + } + + if (OpenPlugins(file) == -1) return -1; + + SysReset(); + + cpuExecuteBios(); + if (file) strcpy(elfname, file); + if (!efile) efile = GetPS2ElfName(elfname); + loadElfFile(elfname); + + ExecuteCpu(); + + return 0; +} + +void InitLanguages() +{ + char *lang; + int i = 1; + + if (Config.Lang[0] == 0) + { + strcpy(Config.Lang, "en"); + } + + langs = (_langs*)malloc(sizeof(_langs)); + strcpy(langs[0].lang, "en"); + dir = opendir(LANGS_DIR); + + while ((lang = GetLanguageNext()) != NULL) + { + langs = (_langs*)realloc(langs, sizeof(_langs) * (i + 1)); + strcpy(langs[i].lang, lang); + i++; + } + + CloseLanguages(); + langsMax = i; +} + +char *GetLanguageNext() +{ + struct dirent *ent; + + if (dir == NULL) return NULL; + for (;;) + { + ent = readdir(dir); + if (ent == NULL) return NULL; + + if (!strcmp(ent->d_name, ".")) continue; + if (!strcmp(ent->d_name, "..")) continue; + break; + } + + return ent->d_name; +} + +void CloseLanguages() +{ + if (dir) closedir(dir); +} + +void ChangeLanguage(char *lang) +{ + strcpy(Config.Lang, lang); + SaveConfig(); +} + +void OnMsg_Ok() +{ + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + + +void On_Dialog_Cancelled(GtkButton* button, gpointer user_data) +{ + gtk_widget_destroy((GtkWidget*)gtk_widget_get_toplevel((GtkWidget*)button)); + gtk_widget_set_sensitive(MainWindow, TRUE); + gtk_main_quit(); +} + +void StartGui() +{ + GtkWidget *Menu; + GtkWidget *Item; + + u32 i; + + add_pixmap_directory(".pixmaps"); + MainWindow = create_MainWindow(); + + if (SVN_REV != 0) + gtk_window_set_title(GTK_WINDOW(MainWindow), "PCSX2 "PCSX2_VERSION" "SVN_REV); + else + gtk_window_set_title(GTK_WINDOW(MainWindow), "PCSX2 "PCSX2_VERSION); + + // status bar + pStatusBar = gtk_statusbar_new(); + gtk_box_pack_start(GTK_BOX(lookup_widget(MainWindow, "status_box")), pStatusBar, TRUE, TRUE, 0); + gtk_widget_show(pStatusBar); + + gtk_statusbar_push(GTK_STATUSBAR(pStatusBar), 0, + "F1 - save, F2 - next state, Shift+F2 - prev state, F3 - load, F8 - snapshot"); + + // add all the languages + Item = lookup_widget(MainWindow, "GtkMenuItem_Language"); + Menu = gtk_menu_new(); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(Item), Menu); + + for (i = 0; i < langsMax; i++) + { + Item = gtk_check_menu_item_new_with_label(ParseLang(langs[i].lang)); + gtk_widget_show(Item); + gtk_container_add(GTK_CONTAINER(Menu), Item); + gtk_check_menu_item_set_show_toggle(GTK_CHECK_MENU_ITEM(Item), TRUE); + if (!strcmp(Config.Lang, langs[i].lang)) + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(Item), TRUE); + + gtk_signal_connect(GTK_OBJECT(Item), "activate", + GTK_SIGNAL_FUNC(OnLanguage), + (gpointer)(uptr)i); + } + + // check the appropriate menu items + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(lookup_widget(MainWindow, "enable_console1")), Config.PsxOut); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(lookup_widget(MainWindow, "enable_patches1")), Config.Patch); + + // disable anything not implemented or not working properly. + gtk_widget_set_sensitive(GTK_WIDGET(lookup_widget(MainWindow, "patch_browser1")), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(lookup_widget(MainWindow, "patch_finder2")), FALSE); +#ifndef PCSX2_DEVBUILD + gtk_widget_set_sensitive(GTK_WIDGET(lookup_widget(MainWindow, "GtkMenuItem_Logging")), FALSE); +#endif + + CheckSlots(); + + gtk_widget_show_all(MainWindow); + gtk_window_activate_focus(GTK_WINDOW(MainWindow)); + gtk_main(); +} + +void OnDestroy(GtkObject *object, gpointer user_data) {} + +gboolean OnDelete(GtkWidget *widget, GdkEvent *event, gpointer user_data) +{ + pcsx2_exit(); + return (FALSE); +} + +int Pcsx2Configure() +{ + if (!UseGui) return 0; + + configuringplug = TRUE; + MainWindow = NULL; + OnConf_Conf(NULL, 0); + configuringplug = FALSE; + + return applychanges; +} + +void OnLanguage(GtkMenuItem *menuitem, gpointer user_data) +{ + ChangeLanguage(langs[(int)(uptr)user_data].lang); + gtk_widget_destroy(MainWindow); + gtk_main_quit(); + while (gtk_events_pending()) gtk_main_iteration(); + StartGui(); +} + +void OnFile_RunCD(GtkMenuItem *menuitem, gpointer user_data) +{ + safe_free(g_RecoveryState); + ResetPlugins(); + RunExecute(NULL); +} + +void OnRunElf_Ok(GtkButton* button, gpointer user_data) +{ + gchar *File; + + File = (gchar*)gtk_file_selection_get_filename(GTK_FILE_SELECTION(FileSel)); + strcpy(elfname, File); + gtk_widget_destroy(FileSel); + + RunExecute(elfname); +} + +void OnRunElf_Cancel(GtkButton* button, gpointer user_data) +{ + gtk_widget_destroy(FileSel); +} + +void OnFile_LoadElf(GtkMenuItem *menuitem, gpointer user_data) +{ + GtkWidget *Ok, *Cancel; + + FileSel = gtk_file_selection_new("Select Psx Elf File"); + + Ok = GTK_FILE_SELECTION(FileSel)->ok_button; + gtk_signal_connect(GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnRunElf_Ok), NULL); + gtk_widget_show(Ok); + + Cancel = GTK_FILE_SELECTION(FileSel)->cancel_button; + gtk_signal_connect(GTK_OBJECT(Cancel), "clicked", GTK_SIGNAL_FUNC(OnRunElf_Cancel), NULL); + gtk_widget_show(Cancel); + + gtk_widget_show(FileSel); + gdk_window_raise(FileSel->window); +} + +void pcsx2_exit() +{ + DIR *dir; + struct dirent *ent; + void *Handle; + char plugin[g_MaxPath]; + + // with this the problem with plugins that are linked with the pthread + // library is solved + + dir = opendir(Config.PluginsDir); + if (dir != NULL) + { + while ((ent = readdir(dir)) != NULL) + { + sprintf(plugin, "%s%s", Config.PluginsDir, ent->d_name); + + if (strstr(plugin, ".so") == NULL) continue; + Handle = dlopen(plugin, RTLD_NOW); + if (Handle == NULL) continue; + } + } + + printf("PCSX2 Quitting\n"); + + if (UseGui) + { + gtk_main_quit(); + SysClose(); + gtk_exit(0); + } + else + { + SysClose(); + exit(0); + } +} + +void SignalExit(int sig) +{ + ClosePlugins(); + pcsx2_exit(); +} + +void OnFile_Exit(GtkMenuItem *menuitem, gpointer user_data) +{ + pcsx2_exit(); +} + +void OnEmu_Run(GtkMenuItem *menuitem, gpointer user_data) +{ + if (g_EmulationInProgress) + ExecuteCpu(); + else + RunExecute(NULL, true); // boots bios if no savestate is to be recovered + +} + +void OnEmu_Reset(GtkMenuItem *menuitem, gpointer user_data) +{ + SysReset(); +} + +void ResetMenuSlots() +{ + GtkWidget *Item; + char str[g_MaxPath], str2[g_MaxPath]; + int i; + + for (i = 0; i < 5; i++) + { + + sprintf(str, "load_slot_%d", i); + sprintf(str2, "save_slot_%d", i); + Item = lookup_widget(MainWindow, str); + + if GTK_IS_WIDGET(Item) + gtk_widget_set_sensitive(Item, Slots[i]); + else + Console::Error("No such widget: %s", params str); + + Item = lookup_widget(MainWindow, str2); + gtk_widget_set_sensitive(Item, (ElfCRC != 0)); + + } +} + +void CheckSlots() +{ + int i = 0; + + if (ElfCRC == 0) Console::Notice("Disabling game slots until a game is loaded."); + + for (i=0; i<5; i++) + { + if (isSlotUsed(i)) + Slots[i] = true; + else + Slots[i] = false; + } + ResetMenuSlots(); +} + +//2002-09-28 (Florin) +void OnArguments_Ok(GtkButton *button, gpointer user_data) +{ + char *str; + + str = (char*)gtk_entry_get_text(GTK_ENTRY(widgetCmdLine)); + memcpy(args, str, g_MaxPath); + + gtk_widget_destroy(CmdLine); + gtk_widget_set_sensitive(MainWindow, TRUE); + gtk_main_quit(); +} + +void OnEmu_Arguments(GtkMenuItem *menuitem, gpointer user_data) +{ + GtkWidget *widgetCmdLine; + + CmdLine = create_CmdLine(); + gtk_window_set_title(GTK_WINDOW(CmdLine), _("Program arguments")); + + widgetCmdLine = lookup_widget(CmdLine, "GtkEntry_dCMDLINE"); + + gtk_entry_set_text(GTK_ENTRY(widgetCmdLine), args); + gtk_widget_show_all(CmdLine); + gtk_widget_set_sensitive(MainWindow, FALSE); + gtk_main(); +} + +void OnLogging_Ok(GtkButton *button, gpointer user_data) +{ +#ifdef PCSX2_DEVBUILD + GtkWidget *Btn; + char str[32]; + int i, ret; + + + for (i = 0; i < 32; i++) + { + if (((i > 16) && (i < 20)) || (i == 29)) + continue; + + sprintf(str, "Log%d", i); + Btn = lookup_widget(LogDlg, str); + ret = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(Btn)); + if (ret) varLog |= 1 << i; + else varLog &= ~(1 << i); + } + + SaveConfig(); +#endif + + gtk_widget_destroy(LogDlg); + gtk_widget_set_sensitive(MainWindow, TRUE); + gtk_main_quit(); +} + +void OnDebug_Logging(GtkMenuItem *menuitem, gpointer user_data) +{ + GtkWidget *Btn; + char str[32]; + int i; + + LogDlg = create_Logging(); + + + for (i = 0; i < 32; i++) + { + if (((i > 16) && (i < 20)) || (i == 29)) + continue; + + sprintf(str, "Log%d", i); + Btn = lookup_widget(LogDlg, str); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(Btn), varLog & (1 << i)); + } + + gtk_widget_show_all(LogDlg); + gtk_widget_set_sensitive(MainWindow, FALSE); + gtk_main(); +} + +void on_patch_browser1_activate(GtkMenuItem *menuitem, gpointer user_data) {} + +void on_patch_finder2_activate(GtkMenuItem *menuitem, gpointer user_data) {} + +void on_enable_console1_activate(GtkMenuItem *menuitem, gpointer user_data) +{ + Config.PsxOut = (int)gtk_check_menu_item_get_active((GtkCheckMenuItem*)menuitem); + SaveConfig(); +} + +void on_enable_patches1_activate(GtkMenuItem *menuitem, gpointer user_data) +{ + Config.Patch = (int)gtk_check_menu_item_get_active((GtkCheckMenuItem*)menuitem); + SaveConfig(); +} + diff --git a/pcsx2/Linux/LnxMain.h b/pcsx2/Linux/LnxMain.h index 82623f3497..fdfb88e139 100644 --- a/pcsx2/Linux/LnxMain.h +++ b/pcsx2/Linux/LnxMain.h @@ -1,76 +1,76 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __LNXMAIN_H__ -#define __LNXMAIN_H__ - -#include "Linux.h" - -void SignalExit(int sig); -extern bool applychanges; - -extern MemoryAlloc* g_RecoveryState; -extern bool g_EmulationInProgress; // Set TRUE if a game is actively running (set to false on reset) - -extern void RunExecute(const char* elf_file, bool use_bios = false); -void OnLanguage(GtkMenuItem *menuitem, gpointer user_data); -extern void ExecuteCpu(); -extern void CheckSlots(); -extern bool isSlotUsed(int num); - -void InitLanguages(); -char *GetLanguageNext(); -void CloseLanguages(); - -void StartGui(); -void pcsx2_exit(); -GtkWidget *MainWindow; -GtkWidget *pStatusBar = NULL, *Status_Box; -GtkWidget *CmdLine; //2002-09-28 (Florin) -GtkWidget *widgetCmdLine; -GtkWidget *LogDlg; - -GtkAccelGroup *AccelGroup; - -const char* phelpmsg = - "\tpcsx2 [options] [file]\n\n" - "-cfg [file] {configuration file}\n" - "-efile [efile] {0 - reset, 1 - runcd (default), 2 - loadelf}\n" - "-help {display this help file}\n" - "-nogui {Don't use gui when launching}\n" - "-loadgs [file} {Loads a gsstate}\n" - "\n" -#ifdef PCSX2_DEVBUILD - "Testing Options: \n" - "\t-frame [frame] {game will run up to this frame before exiting}\n" - "\t-image [name] {path and base name of image (do not include the .ext)}\n" - "\t-jpg {save images to jpg format}\n" - "\t-log [name] {log path to save log file in}\n" - "\t-logopt [hex] {log options in hex (see debug.h) }\n" - "\t-numimages [num] {after hitting frame, this many images will be captures every 20 frames}\n" - "\t-test {Triggers testing mode (only for dev builds)}\n" - "\n" -#endif - "Load Plugins:\n" - "\t-cdvd [libpath] {specify the library load path of the CDVD plugin}\n" - "\t-gs [libpath] {specify the library load path of the GS plugin}\n" - "-pad [tsxcal] {specify to hold down on the triangle, square, circle, x, start, select buttons}\n" - "\t-spu [libpath] {specify the library load path of the SPU2 plugin}\n" - "\n"; - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __LNXMAIN_H__ +#define __LNXMAIN_H__ + +#include "Linux.h" + +void SignalExit(int sig); +extern bool applychanges; + +extern MemoryAlloc* g_RecoveryState; +extern bool g_EmulationInProgress; // Set TRUE if a game is actively running (set to false on reset) + +extern void RunExecute(const char* elf_file, bool use_bios = false); +void OnLanguage(GtkMenuItem *menuitem, gpointer user_data); +extern void ExecuteCpu(); +extern void CheckSlots(); +extern bool isSlotUsed(int num); + +void InitLanguages(); +char *GetLanguageNext(); +void CloseLanguages(); + +void StartGui(); +void pcsx2_exit(); +GtkWidget *MainWindow; +GtkWidget *pStatusBar = NULL, *Status_Box; +GtkWidget *CmdLine; //2002-09-28 (Florin) +GtkWidget *widgetCmdLine; +GtkWidget *LogDlg; + +GtkAccelGroup *AccelGroup; + +const char* phelpmsg = + "\tpcsx2 [options] [file]\n\n" + "-cfg [file] {configuration file}\n" + "-efile [efile] {0 - reset, 1 - runcd (default), 2 - loadelf}\n" + "-help {display this help file}\n" + "-nogui {Don't use gui when launching}\n" + "-loadgs [file} {Loads a gsstate}\n" + "\n" +#ifdef PCSX2_DEVBUILD + "Testing Options: \n" + "\t-frame [frame] {game will run up to this frame before exiting}\n" + "\t-image [name] {path and base name of image (do not include the .ext)}\n" + "\t-jpg {save images to jpg format}\n" + "\t-log [name] {log path to save log file in}\n" + "\t-logopt [hex] {log options in hex (see debug.h) }\n" + "\t-numimages [num] {after hitting frame, this many images will be captures every 20 frames}\n" + "\t-test {Triggers testing mode (only for dev builds)}\n" + "\n" +#endif + "Load Plugins:\n" + "\t-cdvd [libpath] {specify the library load path of the CDVD plugin}\n" + "\t-gs [libpath] {specify the library load path of the GS plugin}\n" + "-pad [tsxcal] {specify to hold down on the triangle, square, circle, x, start, select buttons}\n" + "\t-spu [libpath] {specify the library load path of the SPU2 plugin}\n" + "\n"; + +#endif diff --git a/pcsx2/Linux/LnxThreads.cpp b/pcsx2/Linux/LnxThreads.cpp index 89854955f3..837227ef31 100644 --- a/pcsx2/Linux/LnxThreads.cpp +++ b/pcsx2/Linux/LnxThreads.cpp @@ -1,200 +1,200 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "Threading.h" -#include "Linux.h" -#include "../x86/ix86/ix86.h" - -// Note: assuming multicore is safer because it forces the interlocked routines to use -// the LOCK prefix. The prefix works on single core CPUs fine (but is slow), but not -// having the LOCK prefix is very bad indeed. - -static bool isMultiCore = true; // assume more than one CPU (safer) - -namespace Threading -{ - // Note: Apparently this solution is Linux/Solaris only. - // FreeBSD/OsX need something far more complicated (apparently) - void CountLogicalCores( int LogicalCoresPerPhysicalCPU, int PhysicalCoresPerPhysicalCPU ) - { - const uint numCPU = sysconf( _SC_NPROCESSORS_ONLN ); - if( numCPU > 0 ) - { - isMultiCore = numCPU > 1; - cpuinfo.LogicalCores = numCPU; - cpuinfo.PhysicalCores = ( numCPU / LogicalCoresPerPhysicalCPU ) * PhysicalCoresPerPhysicalCPU; - } - else - { - // Indeterminate? - cpuinfo.LogicalCores = 1; - cpuinfo.PhysicalCores = 1; - } - } - - __forceinline void Timeslice() - { - usleep(500); - } - - // For use in spin/wait loops, Acts as a hint to Intel CPUs and should, in theory - // improve performance and reduce cpu power consumption. - __forceinline void SpinWait() - { - // If this doesn't compile you can just comment it out (it only serves as a - // performance hint and isn't required). - __asm__ ( "pause" ); - } - - void* Thread::_internal_callback( void* itsme ) - { - jASSUME( itsme != NULL ); - Thread& owner = *((Thread*)itsme); - - try - { - owner.m_returncode = owner.Callback(); - } - catch( std::exception& ex ) - { - Console::Error( "Thread terminated abnormally with error:\n%s", params ex.what() ); - owner.m_returncode = -1; - } - - owner.m_terminated = true; - return NULL; - } - - ///////////////////////////////////////////////////////////////////////// - // Cross-platform atomic operations for GCC. - // These are much faster than the old versions for single core CPUs. - // Note, I've disabled the single core optimization, because pcsx2 shouldn't - // ever create threads on single core CPUs anyway. - - __forceinline long pcsx2_InterlockedExchange(volatile long* Target, long Value) - { - long result; - /* - * The XCHG instruction always locks the bus with or without the - * LOCKED prefix. This makes it significantly slower than CMPXCHG on - * uni-processor machines. The Windows InterlockedExchange function - * is nearly 3 times faster than the XCHG instruction, so this routine - * is not yet very useful for speeding up pthreads. - */ - - - if( true ) //isMultiCore ) - { - __asm__ __volatile__ ( - "xchgl %2,%1" - :"=r" (result) - :"m" (*Target), "0" (Value)); - } - else - { - /* - * Faster version of XCHG for uni-processor systems because - * it doesn't lock the bus. If an interrupt or context switch - * occurs between the movl and the cmpxchgl then the value in - * 'location' may have changed, in which case we will loop - * back to do the movl again. - */ - - __asm__ __volatile__ ( - "0:\n\t" - "movl %1,%%eax\n\t" - "cmpxchgl %2,%1\n\t" - "jnz 0b" - :"=&a" (result) - :"m" (*Target), "r" (Value)); - } - - return result; - } - - __forceinline long pcsx2_InterlockedExchangeAdd(volatile long* Addend, long Value) - { - if( true ) //isMultiCore ) - { - __asm__ __volatile__( - ".intel_syntax\n" - "lock xadd [%0], %%eax\n" - ".att_syntax\n" : : "r"(Addend), "a"(Value) : "memory"); - } - else - { - __asm__ __volatile__( - ".intel_syntax\n" - "xadd [%0], %%eax\n" - ".att_syntax\n" : : "r"(Addend), "a"(Value) : "memory"); - } - } - - __forceinline long pcsx2_InterlockedCompareExchange(volatile long *dest, long value, long comp) - { - long result; - - if( true ) //isMultiCore ) - { - __asm__ __volatile__ ( - "lock\n\t" - "cmpxchgl %2,%1" /* if (EAX == [location]) */ - /* [location] = value */ - /* else */ - /* EAX = [location] */ - :"=a" (result) - :"m" (*dest), "r" (value), "a" (comp)); - } - else - { - __asm__ __volatile__ ( - "cmpxchgl %2,%1" /* if (EAX == [location]) */ - /* [location] = value */ - /* else */ - /* EAX = [location] */ - :"=a" (result) - :"m" (*dest), "r" (value), "a" (comp)); - } - - return result; - } - - #ifdef __x86_64__ - __forceinline void pcsx2_InterlockedExchange64(volatile s64* Target, s64 Value) - { - __asm__ __volatile__( - ".intel_syntax\n" - "lock xchg [%0], %%rax\n" - ".att_syntax\n" : : "r"(Target), "a"(Value) : "memory" - ); - return 0; - } - - __forceinline s64 pcsx2_InterlockedCompareExchange64(volatile s64* dest, s64 exch, s64 comp) - { - s64 old; - __asm__ __volatile__( - "lock; cmpxchgq %q2, %q1" - : "=a" (old) - : "r" (exch), "m" (*dest), "a" (comp) - ); - return old; - } -#endif - -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "Threading.h" +#include "Linux.h" +#include "../x86/ix86/ix86.h" + +// Note: assuming multicore is safer because it forces the interlocked routines to use +// the LOCK prefix. The prefix works on single core CPUs fine (but is slow), but not +// having the LOCK prefix is very bad indeed. + +static bool isMultiCore = true; // assume more than one CPU (safer) + +namespace Threading +{ + // Note: Apparently this solution is Linux/Solaris only. + // FreeBSD/OsX need something far more complicated (apparently) + void CountLogicalCores( int LogicalCoresPerPhysicalCPU, int PhysicalCoresPerPhysicalCPU ) + { + const uint numCPU = sysconf( _SC_NPROCESSORS_ONLN ); + if( numCPU > 0 ) + { + isMultiCore = numCPU > 1; + cpuinfo.LogicalCores = numCPU; + cpuinfo.PhysicalCores = ( numCPU / LogicalCoresPerPhysicalCPU ) * PhysicalCoresPerPhysicalCPU; + } + else + { + // Indeterminate? + cpuinfo.LogicalCores = 1; + cpuinfo.PhysicalCores = 1; + } + } + + __forceinline void Timeslice() + { + usleep(500); + } + + // For use in spin/wait loops, Acts as a hint to Intel CPUs and should, in theory + // improve performance and reduce cpu power consumption. + __forceinline void SpinWait() + { + // If this doesn't compile you can just comment it out (it only serves as a + // performance hint and isn't required). + __asm__ ( "pause" ); + } + + void* Thread::_internal_callback( void* itsme ) + { + jASSUME( itsme != NULL ); + Thread& owner = *((Thread*)itsme); + + try + { + owner.m_returncode = owner.Callback(); + } + catch( std::exception& ex ) + { + Console::Error( "Thread terminated abnormally with error:\n%s", params ex.what() ); + owner.m_returncode = -1; + } + + owner.m_terminated = true; + return NULL; + } + + ///////////////////////////////////////////////////////////////////////// + // Cross-platform atomic operations for GCC. + // These are much faster than the old versions for single core CPUs. + // Note, I've disabled the single core optimization, because pcsx2 shouldn't + // ever create threads on single core CPUs anyway. + + __forceinline long pcsx2_InterlockedExchange(volatile long* Target, long Value) + { + long result; + /* + * The XCHG instruction always locks the bus with or without the + * LOCKED prefix. This makes it significantly slower than CMPXCHG on + * uni-processor machines. The Windows InterlockedExchange function + * is nearly 3 times faster than the XCHG instruction, so this routine + * is not yet very useful for speeding up pthreads. + */ + + + if( true ) //isMultiCore ) + { + __asm__ __volatile__ ( + "xchgl %2,%1" + :"=r" (result) + :"m" (*Target), "0" (Value)); + } + else + { + /* + * Faster version of XCHG for uni-processor systems because + * it doesn't lock the bus. If an interrupt or context switch + * occurs between the movl and the cmpxchgl then the value in + * 'location' may have changed, in which case we will loop + * back to do the movl again. + */ + + __asm__ __volatile__ ( + "0:\n\t" + "movl %1,%%eax\n\t" + "cmpxchgl %2,%1\n\t" + "jnz 0b" + :"=&a" (result) + :"m" (*Target), "r" (Value)); + } + + return result; + } + + __forceinline long pcsx2_InterlockedExchangeAdd(volatile long* Addend, long Value) + { + if( true ) //isMultiCore ) + { + __asm__ __volatile__( + ".intel_syntax\n" + "lock xadd [%0], %%eax\n" + ".att_syntax\n" : : "r"(Addend), "a"(Value) : "memory"); + } + else + { + __asm__ __volatile__( + ".intel_syntax\n" + "xadd [%0], %%eax\n" + ".att_syntax\n" : : "r"(Addend), "a"(Value) : "memory"); + } + } + + __forceinline long pcsx2_InterlockedCompareExchange(volatile long *dest, long value, long comp) + { + long result; + + if( true ) //isMultiCore ) + { + __asm__ __volatile__ ( + "lock\n\t" + "cmpxchgl %2,%1" /* if (EAX == [location]) */ + /* [location] = value */ + /* else */ + /* EAX = [location] */ + :"=a" (result) + :"m" (*dest), "r" (value), "a" (comp)); + } + else + { + __asm__ __volatile__ ( + "cmpxchgl %2,%1" /* if (EAX == [location]) */ + /* [location] = value */ + /* else */ + /* EAX = [location] */ + :"=a" (result) + :"m" (*dest), "r" (value), "a" (comp)); + } + + return result; + } + + #ifdef __x86_64__ + __forceinline void pcsx2_InterlockedExchange64(volatile s64* Target, s64 Value) + { + __asm__ __volatile__( + ".intel_syntax\n" + "lock xchg [%0], %%rax\n" + ".att_syntax\n" : : "r"(Target), "a"(Value) : "memory" + ); + return 0; + } + + __forceinline s64 pcsx2_InterlockedCompareExchange64(volatile s64* dest, s64 exch, s64 comp) + { + s64 old; + __asm__ __volatile__( + "lock; cmpxchgq %q2, %q1" + : "=a" (old) + : "r" (exch), "m" (*dest), "a" (comp) + ); + return old; + } +#endif + +} diff --git a/pcsx2/Linux/Makefile.am b/pcsx2/Linux/Makefile.am index c56b73563b..c4f2a14087 100644 --- a/pcsx2/Linux/Makefile.am +++ b/pcsx2/Linux/Makefile.am @@ -1,20 +1,20 @@ -AUTOMAKE_OPTIONS = foreign -INCLUDES = $(shell pkg-config --cflags gtk+-2.0) -I@srcdir@/../ -I@srcdir@/../common/ - -bin_PROGRAMS = pcsx2 - -# the application source, library search path, and link libraries -pcsx2_SOURCES = \ -interface.c support.c LnxMain.cpp LnxThreads.cpp LnxConsole.cpp LnxSysExec.cpp \ -AboutDlg.cpp ConfigDlg.cpp DebugDlg.cpp AdvancedDlg.cpp CpuDlg.cpp HacksDlg.cpp Pref.cpp \ -GtkGui.h Linux.h LnxMain.h ConfigDlg.h DebugDlg.h interface.h callbacks.h memzero.h support.h - -pcsx2_LDFLAGS = - -pcsx2_DEPENDENCIES = ../libpcsx2.a ../IPU/libIPU.a ../IPU/mpeg2lib/libmpeg2IPU.a ../RDebug/libRDebug.a ../tinyxml/libtinyxml.a -pcsx2_DEPENDENCIES += ../x86/libx86recomp.a ../x86/ix86/libix86.a -pcsx2_DEPENDENCIES += ../DebugTools/libDebugTools.a - -pcsx2_LDADD = ../libpcsx2.a ../IPU/libIPU.a ../IPU/mpeg2lib/libmpeg2IPU.a ../RDebug/libRDebug.a ../tinyxml/libtinyxml.a -pcsx2_LDADD += ../x86/libx86recomp.a ../x86/ix86/libix86.a +AUTOMAKE_OPTIONS = foreign +INCLUDES = $(shell pkg-config --cflags gtk+-2.0) -I@srcdir@/../ -I@srcdir@/../common/ + +bin_PROGRAMS = pcsx2 + +# the application source, library search path, and link libraries +pcsx2_SOURCES = \ +interface.c support.c LnxMain.cpp LnxThreads.cpp LnxConsole.cpp LnxSysExec.cpp \ +AboutDlg.cpp ConfigDlg.cpp DebugDlg.cpp AdvancedDlg.cpp CpuDlg.cpp HacksDlg.cpp Pref.cpp \ +GtkGui.h Linux.h LnxMain.h ConfigDlg.h DebugDlg.h interface.h callbacks.h memzero.h support.h + +pcsx2_LDFLAGS = + +pcsx2_DEPENDENCIES = ../libpcsx2.a ../IPU/libIPU.a ../IPU/mpeg2lib/libmpeg2IPU.a ../RDebug/libRDebug.a ../tinyxml/libtinyxml.a +pcsx2_DEPENDENCIES += ../x86/libx86recomp.a ../x86/ix86/libix86.a +pcsx2_DEPENDENCIES += ../DebugTools/libDebugTools.a + +pcsx2_LDADD = ../libpcsx2.a ../IPU/libIPU.a ../IPU/mpeg2lib/libmpeg2IPU.a ../RDebug/libRDebug.a ../tinyxml/libtinyxml.a +pcsx2_LDADD += ../x86/libx86recomp.a ../x86/ix86/libix86.a pcsx2_LDADD += ../DebugTools/libDebugTools.a \ No newline at end of file diff --git a/pcsx2/Linux/Pref.cpp b/pcsx2/Linux/Pref.cpp index 9ff433914b..dba493b14d 100644 --- a/pcsx2/Linux/Pref.cpp +++ b/pcsx2/Linux/Pref.cpp @@ -1,177 +1,177 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "Linux.h" - -FILE *pref_file; -char *data; - -static void SetValue(const char *name, char *var) -{ - fprintf(pref_file, "%s = %s\n", name, var); -} - -static void SetValuel(const char *name, s32 var) -{ - fprintf(pref_file, "%s = %x\n", name, var); -} - -#define GetValue(name, var) {\ - char * tmp; \ - tmp = strstr(data, name); \ - if (tmp != NULL) { \ - tmp+=strlen(name); \ - while ((*tmp == ' ') || (*tmp == '=')) tmp++; \ - if (*tmp != '\n') sscanf(tmp, "%s", var); \ - } \ -} - -#define GetValuel(name, var) {\ - char * tmp; \ - tmp = strstr(data, name); \ - if (tmp != NULL) { \ - tmp+=strlen(name); \ - while ((*tmp == ' ') || (*tmp == '=')) tmp++; \ - if (*tmp != '\n') sscanf(tmp, "%x", &var); \ - } \ -} - -int LoadConfig() -{ - struct stat buf; - int size; - - if (stat(cfgfile, &buf) == -1) return -1; - size = buf.st_size; - - pref_file = fopen(cfgfile, "r"); - if (pref_file == NULL) return -1; - - data = (char*)malloc(size); - if (data == NULL) return -1; - - fread(data, 1, size, pref_file); - fclose(pref_file); - - GetValue("Bios", Config.Bios); - Config.Lang[0] = 0; - GetValue("Lang", Config.Lang); - GetValuel("Ps2Out", Config.PsxOut); - GetValuel("ThPriority", Config.ThPriority); - GetValue("PluginsDir", Config.PluginsDir); - GetValue("BiosDir", Config.BiosDir); - GetValue("Mcd1", Config.Mcd1); - GetValue("Mcd2", Config.Mcd2); - - GetValue("GS", Config.GS); - GetValue("SPU2", Config.SPU2); - GetValue("CDVD", Config.CDVD); - GetValue("PAD1", Config.PAD1); - GetValue("PAD2", Config.PAD2); - GetValue("DEV9", Config.DEV9); - GetValue("USB", Config.USB); - GetValue("FW", Config.FW); - - GetValuel("Patch", Config.Patch); -#ifdef PCSX2_DEVBUILD - GetValuel("varLog", varLog); -#endif - GetValuel("Options", Config.Options); - GetValuel("Hacks", Config.Hacks); - GetValuel("Fixes", Config.GameFixes); - - GetValuel("CustomFps", Config.CustomFps); - GetValuel("CustomFrameskip", Config.CustomFrameSkip); - GetValuel("CustomConsecutiveFrames", Config.CustomConsecutiveFrames); - GetValuel("CustomConsecutiveSkip", Config.CustomConsecutiveSkip); - - // Note - order is currently important. - GetValuel("sseMXCSR", Config.sseMXCSR); - GetValuel("sseVUMXCSR", Config.sseVUMXCSR); - GetValuel("eeOptions", Config.eeOptions); - GetValuel("vuOptions", Config.vuOptions); - - free(data); - -#ifdef ENABLE_NLS - if (Config.Lang[0]) - { - extern int _nl_msg_cat_cntr; - - setenv("LANGUAGE", Config.Lang, 1); - ++_nl_msg_cat_cntr; - } -#endif - - return 0; -} - -///////////////////////////////////////////////////////// - -void SaveConfig() -{ - - pref_file = fopen(cfgfile, "w"); - if (pref_file == NULL) return; - - SetValue("Bios", Config.Bios); - SetValue("Lang", Config.Lang); - SetValue("PluginsDir", Config.PluginsDir); - SetValue("BiosDir", Config.BiosDir); - SetValuel("Ps2Out", Config.PsxOut); - SetValuel("ThPriority", Config.ThPriority); - SetValue("Mcd1", Config.Mcd1); - SetValue("Mcd2", Config.Mcd2); - - SetValue("GS", Config.GS); - SetValue("SPU2", Config.SPU2); - SetValue("CDVD", Config.CDVD); - SetValue("PAD1", Config.PAD1); - SetValue("PAD2", Config.PAD2); - SetValue("DEV9", Config.DEV9); - SetValue("USB", Config.USB); - SetValue("FW", Config.FW); - - SetValuel("Options", Config.Options); - - // Remove Fast Branches hack for now: - Config.Hacks &= ~0x80; - - SetValuel("Hacks", Config.Hacks); - SetValuel("Fixes", Config.GameFixes); - - SetValuel("Patch", Config.Patch); - - SetValuel("CustomFps", Config.CustomFps); - SetValuel("CustomFrameskip", Config.CustomFrameSkip); - SetValuel("CustomConsecutiveFrames", Config.CustomConsecutiveFrames); - SetValuel("CustomConsecutiveSkip", Config.CustomConsecutiveSkip); - - SetValuel("sseMXCSR", Config.sseMXCSR); - SetValuel("sseVUMXCSR", Config.sseVUMXCSR); - SetValuel("eeOptions", Config.eeOptions); - SetValuel("vuOptions", Config.vuOptions); - -#ifdef PCSX2_DEVBUILD - SetValuel("varLog", varLog); -#endif - - fclose(pref_file); - - return; -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "Linux.h" + +FILE *pref_file; +char *data; + +static void SetValue(const char *name, char *var) +{ + fprintf(pref_file, "%s = %s\n", name, var); +} + +static void SetValuel(const char *name, s32 var) +{ + fprintf(pref_file, "%s = %x\n", name, var); +} + +#define GetValue(name, var) {\ + char * tmp; \ + tmp = strstr(data, name); \ + if (tmp != NULL) { \ + tmp+=strlen(name); \ + while ((*tmp == ' ') || (*tmp == '=')) tmp++; \ + if (*tmp != '\n') sscanf(tmp, "%s", var); \ + } \ +} + +#define GetValuel(name, var) {\ + char * tmp; \ + tmp = strstr(data, name); \ + if (tmp != NULL) { \ + tmp+=strlen(name); \ + while ((*tmp == ' ') || (*tmp == '=')) tmp++; \ + if (*tmp != '\n') sscanf(tmp, "%x", &var); \ + } \ +} + +int LoadConfig() +{ + struct stat buf; + int size; + + if (stat(cfgfile, &buf) == -1) return -1; + size = buf.st_size; + + pref_file = fopen(cfgfile, "r"); + if (pref_file == NULL) return -1; + + data = (char*)malloc(size); + if (data == NULL) return -1; + + fread(data, 1, size, pref_file); + fclose(pref_file); + + GetValue("Bios", Config.Bios); + Config.Lang[0] = 0; + GetValue("Lang", Config.Lang); + GetValuel("Ps2Out", Config.PsxOut); + GetValuel("ThPriority", Config.ThPriority); + GetValue("PluginsDir", Config.PluginsDir); + GetValue("BiosDir", Config.BiosDir); + GetValue("Mcd1", Config.Mcd1); + GetValue("Mcd2", Config.Mcd2); + + GetValue("GS", Config.GS); + GetValue("SPU2", Config.SPU2); + GetValue("CDVD", Config.CDVD); + GetValue("PAD1", Config.PAD1); + GetValue("PAD2", Config.PAD2); + GetValue("DEV9", Config.DEV9); + GetValue("USB", Config.USB); + GetValue("FW", Config.FW); + + GetValuel("Patch", Config.Patch); +#ifdef PCSX2_DEVBUILD + GetValuel("varLog", varLog); +#endif + GetValuel("Options", Config.Options); + GetValuel("Hacks", Config.Hacks); + GetValuel("Fixes", Config.GameFixes); + + GetValuel("CustomFps", Config.CustomFps); + GetValuel("CustomFrameskip", Config.CustomFrameSkip); + GetValuel("CustomConsecutiveFrames", Config.CustomConsecutiveFrames); + GetValuel("CustomConsecutiveSkip", Config.CustomConsecutiveSkip); + + // Note - order is currently important. + GetValuel("sseMXCSR", Config.sseMXCSR); + GetValuel("sseVUMXCSR", Config.sseVUMXCSR); + GetValuel("eeOptions", Config.eeOptions); + GetValuel("vuOptions", Config.vuOptions); + + free(data); + +#ifdef ENABLE_NLS + if (Config.Lang[0]) + { + extern int _nl_msg_cat_cntr; + + setenv("LANGUAGE", Config.Lang, 1); + ++_nl_msg_cat_cntr; + } +#endif + + return 0; +} + +///////////////////////////////////////////////////////// + +void SaveConfig() +{ + + pref_file = fopen(cfgfile, "w"); + if (pref_file == NULL) return; + + SetValue("Bios", Config.Bios); + SetValue("Lang", Config.Lang); + SetValue("PluginsDir", Config.PluginsDir); + SetValue("BiosDir", Config.BiosDir); + SetValuel("Ps2Out", Config.PsxOut); + SetValuel("ThPriority", Config.ThPriority); + SetValue("Mcd1", Config.Mcd1); + SetValue("Mcd2", Config.Mcd2); + + SetValue("GS", Config.GS); + SetValue("SPU2", Config.SPU2); + SetValue("CDVD", Config.CDVD); + SetValue("PAD1", Config.PAD1); + SetValue("PAD2", Config.PAD2); + SetValue("DEV9", Config.DEV9); + SetValue("USB", Config.USB); + SetValue("FW", Config.FW); + + SetValuel("Options", Config.Options); + + // Remove Fast Branches hack for now: + Config.Hacks &= ~0x80; + + SetValuel("Hacks", Config.Hacks); + SetValuel("Fixes", Config.GameFixes); + + SetValuel("Patch", Config.Patch); + + SetValuel("CustomFps", Config.CustomFps); + SetValuel("CustomFrameskip", Config.CustomFrameSkip); + SetValuel("CustomConsecutiveFrames", Config.CustomConsecutiveFrames); + SetValuel("CustomConsecutiveSkip", Config.CustomConsecutiveSkip); + + SetValuel("sseMXCSR", Config.sseMXCSR); + SetValuel("sseVUMXCSR", Config.sseVUMXCSR); + SetValuel("eeOptions", Config.eeOptions); + SetValuel("vuOptions", Config.vuOptions); + +#ifdef PCSX2_DEVBUILD + SetValuel("varLog", varLog); +#endif + + fclose(pref_file); + + return; +} diff --git a/pcsx2/Linux/memzero.h b/pcsx2/Linux/memzero.h index 86fc9c9625..c46759dbd9 100644 --- a/pcsx2/Linux/memzero.h +++ b/pcsx2/Linux/memzero.h @@ -1,182 +1,182 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef _LNX_MEMZERO_H_ -#define _LNX_MEMZERO_H_ - -// This header contains non-optimized implementation of memzero_ptr and memset8_obj, -// memset16_obj, etc. - -template< u32 data, typename T > -static __forceinline void memset32_obj( T& obj ) -{ - // this function works on 32-bit aligned lengths of data only. - // If the data length is not a factor of 32 bits, the C++ optimizing compiler will - // probably just generate mysteriously broken code in Release builds. ;) - - jASSUME( (sizeof(T) & 0x3) == 0 ); - - u32* dest = (u32*)&obj; - for( int i=sizeof(T)>>2; i; --i, ++dest ) - *dest = data; -} - -template< uint size > -static __forceinline void memzero_ptr( void* dest ) -{ - memset( dest, 0, size ); -} - -template< typename T > -static __forceinline void memzero_obj( T& obj ) -{ - memset( &obj, 0, sizeof( T ) ); -} - -template< u8 data, typename T > -static __forceinline void memset8_obj( T& obj ) -{ - // Aligned sizes use the optimized 32 bit inline memset. Unaligned sizes use memset. - if( (sizeof(T) & 0x3) != 0 ) - memset( &obj, data, sizeof( T ) ); - else - memset32_obj( obj ); -} - -template< u16 data, typename T > -static __forceinline void memset16_obj( T& obj ) -{ - if( (sizeof(T) & 0x3) != 0 ) - _memset_16_unaligned( &obj, data, sizeof( T ) ); - else - memset32_obj( obj ); -} - - -// An optimized memset for 8 bit destination data. -template< u8 data, size_t bytes > -static __forceinline void memset_8( void *dest ) -{ - if( bytes == 0 ) return; - - if( (bytes & 0x3) != 0 ) - { - // unaligned data length. No point in doing an optimized inline version (too complicated!) - // So fall back on the compiler implementation: - - memset( dest, data, bytes ); - return; - } - - // This function only works on 32-bit alignments of data copied. - jASSUME( (bytes & 0x3) == 0 ); - - enum - { - remdat = bytes>>2, - data32 = data + (data<<8) + (data<<16) + (data<<24) - }; - - // macro to execute the x86/32 "stosd" copies. - switch( remdat ) - { - case 1: - *(u32*)dest = data32; - return; - - case 2: - ((u32*)dest)[0] = data32; - ((u32*)dest)[1] = data32; - return; - - case 3: - __asm__ - ( - ".intel_syntax\n" - "cld\n" -// "mov %edi, %0\n" -// "mov %eax, %1\n" - "stosd\n" - "stosd\n" - "stosd\n" - ".att_syntax\n" - : - : "D"(dest), "a"(data32) -// D - edi, a -- eax, c ecx - : - ); - return; - - case 4: - __asm__ - ( - ".intel_syntax\n" - "cld\n" -// "mov %edi, %0\n" -// "mov %eax, %1\n" - "stosd\n" - "stosd\n" - "stosd\n" - "stosd\n" - ".att_syntax\n" - : - : "D"(dest), "a"(data32) - : - - ); - return; - - case 5: - __asm__ - ( - ".intel_syntax\n" - "cld\n" -// "mov %edi, %0\n" -// "mov %eax, %1\n" - "stosd\n" - "stosd\n" - "stosd\n" - "stosd\n" - "stosd\n" - ".att_syntax\n" - : - : "D"(dest), "a"(data32) - : - - ); - return; - - default: - __asm__ - ( - ".intel_syntax\n" - "cld\n" -// "mov ecx, %0\n" -// "mov edi, %1\n" -// "mov eax, %2\n" - "rep stosd\n" - ".att_syntax\n" - : - : "c"(remdat), "D"(dest), "a"(data32) - : - ); - return; - } -} - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef _LNX_MEMZERO_H_ +#define _LNX_MEMZERO_H_ + +// This header contains non-optimized implementation of memzero_ptr and memset8_obj, +// memset16_obj, etc. + +template< u32 data, typename T > +static __forceinline void memset32_obj( T& obj ) +{ + // this function works on 32-bit aligned lengths of data only. + // If the data length is not a factor of 32 bits, the C++ optimizing compiler will + // probably just generate mysteriously broken code in Release builds. ;) + + jASSUME( (sizeof(T) & 0x3) == 0 ); + + u32* dest = (u32*)&obj; + for( int i=sizeof(T)>>2; i; --i, ++dest ) + *dest = data; +} + +template< uint size > +static __forceinline void memzero_ptr( void* dest ) +{ + memset( dest, 0, size ); +} + +template< typename T > +static __forceinline void memzero_obj( T& obj ) +{ + memset( &obj, 0, sizeof( T ) ); +} + +template< u8 data, typename T > +static __forceinline void memset8_obj( T& obj ) +{ + // Aligned sizes use the optimized 32 bit inline memset. Unaligned sizes use memset. + if( (sizeof(T) & 0x3) != 0 ) + memset( &obj, data, sizeof( T ) ); + else + memset32_obj( obj ); +} + +template< u16 data, typename T > +static __forceinline void memset16_obj( T& obj ) +{ + if( (sizeof(T) & 0x3) != 0 ) + _memset_16_unaligned( &obj, data, sizeof( T ) ); + else + memset32_obj( obj ); +} + + +// An optimized memset for 8 bit destination data. +template< u8 data, size_t bytes > +static __forceinline void memset_8( void *dest ) +{ + if( bytes == 0 ) return; + + if( (bytes & 0x3) != 0 ) + { + // unaligned data length. No point in doing an optimized inline version (too complicated!) + // So fall back on the compiler implementation: + + memset( dest, data, bytes ); + return; + } + + // This function only works on 32-bit alignments of data copied. + jASSUME( (bytes & 0x3) == 0 ); + + enum + { + remdat = bytes>>2, + data32 = data + (data<<8) + (data<<16) + (data<<24) + }; + + // macro to execute the x86/32 "stosd" copies. + switch( remdat ) + { + case 1: + *(u32*)dest = data32; + return; + + case 2: + ((u32*)dest)[0] = data32; + ((u32*)dest)[1] = data32; + return; + + case 3: + __asm__ + ( + ".intel_syntax\n" + "cld\n" +// "mov %edi, %0\n" +// "mov %eax, %1\n" + "stosd\n" + "stosd\n" + "stosd\n" + ".att_syntax\n" + : + : "D"(dest), "a"(data32) +// D - edi, a -- eax, c ecx + : + ); + return; + + case 4: + __asm__ + ( + ".intel_syntax\n" + "cld\n" +// "mov %edi, %0\n" +// "mov %eax, %1\n" + "stosd\n" + "stosd\n" + "stosd\n" + "stosd\n" + ".att_syntax\n" + : + : "D"(dest), "a"(data32) + : + + ); + return; + + case 5: + __asm__ + ( + ".intel_syntax\n" + "cld\n" +// "mov %edi, %0\n" +// "mov %eax, %1\n" + "stosd\n" + "stosd\n" + "stosd\n" + "stosd\n" + "stosd\n" + ".att_syntax\n" + : + : "D"(dest), "a"(data32) + : + + ); + return; + + default: + __asm__ + ( + ".intel_syntax\n" + "cld\n" +// "mov ecx, %0\n" +// "mov edi, %1\n" +// "mov eax, %2\n" + "rep stosd\n" + ".att_syntax\n" + : + : "c"(remdat), "D"(dest), "a"(data32) + : + ); + return; + } +} + +#endif diff --git a/pcsx2/MMI.cpp b/pcsx2/MMI.cpp index 9b44343cb5..2a59510a59 100644 --- a/pcsx2/MMI.cpp +++ b/pcsx2/MMI.cpp @@ -1,1566 +1,1566 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "DebugTools/Debug.h" -#include "R5900.h" -#include "R5900OpcodeTables.h" - -namespace R5900 { -namespace Interpreter { -namespace OpcodeImpl { - - ///////////////////////////////////////////////////////////////// - // Non-MMI Instructions! - // - // Several instructions in the MMI opcode class are actually just regular - // instructions which have been added to "extend" the R5900's instruction - // set. They're here, because if not here they'd be homeless. - // - The Pcsx2 team, doing their part to fight homelessness - - void MADD() { - s64 temp = (s64)((u64)cpuRegs.LO.UL[0] | ((u64)cpuRegs.HI.UL[0] << 32)) + - ((s64)cpuRegs.GPR.r[_Rs_].SL[0] * (s64)cpuRegs.GPR.r[_Rt_].SL[0]); - - cpuRegs.LO.SD[0] = (s32)(temp & 0xffffffff); - cpuRegs.HI.SD[0] = (s32)(temp >> 32); - - if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[0] = cpuRegs.LO.SD[0]; - } - - void MADDU() { - u64 tempu = (u64)((u64)cpuRegs.LO.UL[0] | ((u64)cpuRegs.HI.UL[0] << 32)) + - ((u64)cpuRegs.GPR.r[_Rs_].UL[0] * (u64)cpuRegs.GPR.r[_Rt_].UL[0]); - - cpuRegs.LO.SD[0] = (s32)(tempu & 0xffffffff); - cpuRegs.HI.SD[0] = (s32)(tempu >> 32); - - if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[0] = cpuRegs.LO.SD[0]; - } - - void MADD1() { - s64 temp = (s64)((u64)cpuRegs.LO.UL[2] | ((u64)cpuRegs.HI.UL[2] << 32)) + - ((s64)cpuRegs.GPR.r[_Rs_].SL[0] * (s64)cpuRegs.GPR.r[_Rt_].SL[0]); - - cpuRegs.LO.SD[1] = (s32)(temp & 0xffffffff); - cpuRegs.HI.SD[1] = (s32)(temp >> 32); - - if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[0] = cpuRegs.LO.SD[1]; - } - - void MADDU1() { - u64 tempu = (u64)((u64)cpuRegs.LO.UL[2] | ((u64)cpuRegs.HI.UL[2] << 32)) + - ((u64)cpuRegs.GPR.r[_Rs_].UL[0] * (u64)cpuRegs.GPR.r[_Rt_].UL[0]); - - cpuRegs.LO.SD[1] = (s32)(tempu & 0xffffffff); - cpuRegs.HI.SD[1] = (s32)(tempu >> 32); - - if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[0] = cpuRegs.LO.SD[1]; - } - - void MFHI1() { - if (!_Rd_) return; - cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.HI.UD[1]; - } - - void MFLO1() { - if (!_Rd_) return; - cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[1]; - } - - void MTHI1() { - cpuRegs.HI.UD[1] = cpuRegs.GPR.r[_Rs_].UD[0]; - } - - void MTLO1() { - cpuRegs.LO.UD[1] = cpuRegs.GPR.r[_Rs_].UD[0]; - } - - void MULT1() { - s64 temp = (s64)cpuRegs.GPR.r[_Rs_].SL[0] * (s64)cpuRegs.GPR.r[_Rt_].SL[0]; - - cpuRegs.LO.UD[1] = (s64)(s32)(temp & 0xffffffff); - cpuRegs.HI.UD[1] = (s64)(s32)(temp >> 32); - - /* Modified a bit . asadr */ - if (_Rd_) cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[1]; - } - - void MULTU1() { - u64 tempu = (u64)cpuRegs.GPR.r[_Rs_].UL[0] * (u64)cpuRegs.GPR.r[_Rt_].UL[0]; - - cpuRegs.LO.UD[1] = (s32)(tempu & 0xffffffff); - cpuRegs.HI.UD[1] = (s32)(tempu >> 32); - - if (_Rd_) cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[1]; - } - - void DIV1() { - if (cpuRegs.GPR.r[_Rt_].SL[0] != 0) { - cpuRegs.LO.SD[1] = cpuRegs.GPR.r[_Rs_].SL[0] / cpuRegs.GPR.r[_Rt_].SL[0]; - cpuRegs.HI.SD[1] = cpuRegs.GPR.r[_Rs_].SL[0] % cpuRegs.GPR.r[_Rt_].SL[0]; - } - } - - void DIVU1() { - if (cpuRegs.GPR.r[_Rt_].UL[0] != 0) { - cpuRegs.LO.UD[1] = cpuRegs.GPR.r[_Rs_].UL[0] / cpuRegs.GPR.r[_Rt_].UL[0]; - cpuRegs.HI.UD[1] = cpuRegs.GPR.r[_Rs_].UL[0] % cpuRegs.GPR.r[_Rt_].UL[0]; - } - } - -namespace MMI { - -//*****************MMI OPCODES********************************* - -__forceinline void _PLZCW(int n) -{ - // This function counts the number of "like" bits in the source register, starting - // with the MSB and working its way down, and returns the result MINUS ONE. - // So 0xff00 would return 7, not 8. - - int c = 0; - s32 i = cpuRegs.GPR.r[_Rs_].SL[n]; - - // Negate the source based on the sign bit. This allows us to use a simple - // unified bit test of the MSB for either condition. - if( i >= 0 ) i = ~i; - - // shift first, compare, then increment. This excludes the sign bit from our final count. - while( i <<= 1, i < 0 ) c++; - - cpuRegs.GPR.r[_Rd_].UL[n] = c; -} - -void PLZCW() { - if (!_Rd_) return; - - _PLZCW (0); - _PLZCW (1); -} - -#define PMFHL_CLAMP(dst, src) \ - if ((int)src > (int)0x00007fff) dst = 0x7fff; \ - else \ - if ((int)src < (int)0xffff8000) dst = 0x8000; \ - else dst = (u16)src; - -void PMFHL() { - if (!_Rd_) return; - - switch (_Sa_) { - case 0x00: // LW - cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[0]; - cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[0]; - cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[2]; - cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[2]; - break; - - case 0x01: // UW - cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[1]; - cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[1]; - cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[3]; - cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[3]; - break; - - case 0x02: // SLW - { - u64 TempU64 = ((u64)cpuRegs.HI.UL[0] << 32) | (u64)cpuRegs.LO.UL[0]; - if (TempU64 >= 0x000000007fffffffLL) { - cpuRegs.GPR.r[_Rd_].UD[0] = 0x000000007fffffffLL; - } else if (TempU64 <= 0xffffffff80000000LL) { - cpuRegs.GPR.r[_Rd_].UD[0] = 0xffffffff80000000LL; - } else { - cpuRegs.GPR.r[_Rd_].UD[0] = (s64)cpuRegs.LO.SL[0]; - } - - TempU64 = ((u64)cpuRegs.HI.UL[2] << 32) | (u64)cpuRegs.LO.UL[2]; - if (TempU64 >= 0x000000007fffffffLL) { - cpuRegs.GPR.r[_Rd_].UD[1] = 0x000000007fffffffLL; - } else if (TempU64 <= 0xffffffff80000000LL) { - cpuRegs.GPR.r[_Rd_].UD[1] = 0xffffffff80000000LL; - } else { - cpuRegs.GPR.r[_Rd_].UD[1] = (s64)cpuRegs.LO.SL[2]; - } - } - break; - - case 0x03: // LH - cpuRegs.GPR.r[_Rd_].US[0] = cpuRegs.LO.US[0]; - cpuRegs.GPR.r[_Rd_].US[1] = cpuRegs.LO.US[2]; - cpuRegs.GPR.r[_Rd_].US[2] = cpuRegs.HI.US[0]; - cpuRegs.GPR.r[_Rd_].US[3] = cpuRegs.HI.US[2]; - cpuRegs.GPR.r[_Rd_].US[4] = cpuRegs.LO.US[4]; - cpuRegs.GPR.r[_Rd_].US[5] = cpuRegs.LO.US[6]; - cpuRegs.GPR.r[_Rd_].US[6] = cpuRegs.HI.US[4]; - cpuRegs.GPR.r[_Rd_].US[7] = cpuRegs.HI.US[6]; - break; - - case 0x04: // SH - PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[0], cpuRegs.LO.UL[0]); - PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[1], cpuRegs.LO.UL[1]); - PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[2], cpuRegs.HI.UL[0]); - PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[3], cpuRegs.HI.UL[1]); - PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[4], cpuRegs.LO.UL[2]); - PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[5], cpuRegs.LO.UL[3]); - PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[6], cpuRegs.HI.UL[2]); - PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[7], cpuRegs.HI.UL[3]); - break; - } -} - -void PMTHL() { - if (_Sa_ != 0) return; - - cpuRegs.LO.UL[0] = cpuRegs.GPR.r[_Rs_].UL[0]; - cpuRegs.HI.UL[0] = cpuRegs.GPR.r[_Rs_].UL[1]; - cpuRegs.LO.UL[2] = cpuRegs.GPR.r[_Rs_].UL[2]; - cpuRegs.HI.UL[2] = cpuRegs.GPR.r[_Rs_].UL[3]; -} - -__forceinline void _PSLLH(int n) -{ - cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rt_].US[n] << ( _Sa_ & 0xf ); -} - -void PSLLH() { - if (!_Rd_) return; - - _PSLLH(0); _PSLLH(1); _PSLLH(2); _PSLLH(3); - _PSLLH(4); _PSLLH(5); _PSLLH(6); _PSLLH(7); -} - -__forceinline void _PSRLH(int n) -{ - cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rt_].US[n] >> ( _Sa_ & 0xf ); -} - -void PSRLH () { - if (!_Rd_) return; - - _PSRLH(0); _PSRLH(1); _PSRLH(2); _PSRLH(3); - _PSRLH(4); _PSRLH(5); _PSRLH(6); _PSRLH(7); -} - -__forceinline void _PSRAH(int n) -{ - cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rt_].SS[n] >> ( _Sa_ & 0xf ); -} - -void PSRAH() { - if (!_Rd_) return; - - _PSRAH(0); _PSRAH(1); _PSRAH(2); _PSRAH(3); - _PSRAH(4); _PSRAH(5); _PSRAH(6); _PSRAH(7); -} - -__forceinline void _PSLLW(int n) -{ - cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rt_].UL[n] << _Sa_; -} - -void PSLLW() { - if (!_Rd_) return; - - _PSLLW(0); _PSLLW(1); _PSLLW(2); _PSLLW(3); -} - -__forceinline void _PSRLW(int n) -{ - cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rt_].UL[n] >> _Sa_; -} - -void PSRLW() { - if (!_Rd_) return; - - _PSRLW(0); _PSRLW(1); _PSRLW(2); _PSRLW(3); -} - -__forceinline void _PSRAW(int n) -{ - cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rt_].SL[n] >> _Sa_; -} - -void PSRAW() { - if (!_Rd_) return; - - _PSRAW(0); _PSRAW(1); _PSRAW(2); _PSRAW(3); -} - -//*****************END OF MMI OPCODES************************** -//*************************MMI0 OPCODES************************ - -__forceinline void _PADDW(int n) -{ - cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rs_].UL[n] + cpuRegs.GPR.r[_Rt_].UL[n]; -} - -void PADDW() { - if (!_Rd_) return; - - _PADDW(0); _PADDW(1); _PADDW(2); _PADDW(3); -} - -__forceinline void _PSUBW(int n) -{ - cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rs_].UL[n] - cpuRegs.GPR.r[_Rt_].UL[n]; -} - -void PSUBW() { - if (!_Rd_) return; - - _PSUBW(0); _PSUBW(1); _PSUBW(2); _PSUBW(3); -} - -__forceinline void _PCGTW(int n) -{ - if (cpuRegs.GPR.r[_Rs_].SL[n] > cpuRegs.GPR.r[_Rt_].SL[n]) - cpuRegs.GPR.r[_Rd_].UL[n] = 0xFFFFFFFF; - else - cpuRegs.GPR.r[_Rd_].UL[n] = 0x00000000; -} - -void PCGTW() { - if (!_Rd_) return; - - _PCGTW(0); _PCGTW(1); _PCGTW(2); _PCGTW(3); -} - -__forceinline void _PMAXW(int n) -{ - if (cpuRegs.GPR.r[_Rs_].SL[n] > cpuRegs.GPR.r[_Rt_].SL[n]) - cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rs_].UL[n]; - else - cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rt_].UL[n]; -} - -void PMAXW() { - if (!_Rd_) return; - - _PMAXW(0); _PMAXW(1); _PMAXW(2); _PMAXW(3); -} - -__forceinline void _PADDH(int n) -{ - cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rs_].US[n] + cpuRegs.GPR.r[_Rt_].US[n]; -} - -void PADDH() { - if (!_Rd_) return; - - _PADDH(0); _PADDH(1); _PADDH(2); _PADDH(3); - _PADDH(4); _PADDH(5); _PADDH(6); _PADDH(7); -} - -__forceinline void _PSUBH(int n) -{ - cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rs_].US[n] - cpuRegs.GPR.r[_Rt_].US[n]; -} - -void PSUBH() { - if (!_Rd_) return; - - _PSUBH(0); _PSUBH(1); _PSUBH(2); _PSUBH(3); - _PSUBH(4); _PSUBH(5); _PSUBH(6); _PSUBH(7); -} - -__forceinline void _PCGTH(int n) -{ - if (cpuRegs.GPR.r[_Rs_].SS[n] > cpuRegs.GPR.r[_Rt_].SS[n]) - cpuRegs.GPR.r[_Rd_].US[n] = 0xFFFF; - else - cpuRegs.GPR.r[_Rd_].US[n] = 0x0000; -} - -void PCGTH() { - if (!_Rd_) return; - - _PCGTH(0); _PCGTH(1); _PCGTH(2); _PCGTH(3); - _PCGTH(4); _PCGTH(5); _PCGTH(6); _PCGTH(7); -} - -__forceinline void _PMAXH(int n) -{ - if (cpuRegs.GPR.r[_Rs_].SS[n] > cpuRegs.GPR.r[_Rt_].SS[n]) - cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rs_].US[n]; - else - cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rt_].US[n]; -} - -void PMAXH() { - if (!_Rd_) return; - - _PMAXH(0); _PMAXH(1); _PMAXH(2); _PMAXH(3); - _PMAXH(4); _PMAXH(5); _PMAXH(6); _PMAXH(7); -} - -__forceinline void _PADDB(int n) -{ - cpuRegs.GPR.r[_Rd_].SC[n] = cpuRegs.GPR.r[_Rs_].SC[n] + cpuRegs.GPR.r[_Rt_].SC[n]; -} - -void PADDB() { - int i; - if (!_Rd_) return; - - for( i=0; i<16; i++ ) - _PADDB( i ); -} - -__forceinline void _PSUBB(int n) -{ - cpuRegs.GPR.r[_Rd_].SC[n] = cpuRegs.GPR.r[_Rs_].SC[n] - cpuRegs.GPR.r[_Rt_].SC[n]; -} - -void PSUBB() { - int i; - if (!_Rd_) return; - - for( i=0; i<16; i++ ) - _PSUBB( i ); -} - -__forceinline void _PCGTB(int n) -{ - if (cpuRegs.GPR.r[_Rs_].SC[n] > cpuRegs.GPR.r[_Rt_].SC[n]) - cpuRegs.GPR.r[_Rd_].UC[n] = 0xFF; - else - cpuRegs.GPR.r[_Rd_].UC[n] = 0x00; -} - -void PCGTB() { - int i; - if (!_Rd_) return; - - for( i=0; i<16; i++ ) - _PCGTB( i ); -} - -__forceinline void _PADDSW(int n) -{ - s64 sTemp64; - - sTemp64 = (s64)cpuRegs.GPR.r[_Rs_].SL[n] + (s64)cpuRegs.GPR.r[_Rt_].SL[n]; - if (sTemp64 > 0x7FFFFFFF) - cpuRegs.GPR.r[_Rd_].UL[n] = 0x7FFFFFFF; - else if ((sTemp64 < (s32)0x80000000) ) - cpuRegs.GPR.r[_Rd_].UL[n] = 0x80000000LL; - else - cpuRegs.GPR.r[_Rd_].UL[n] = (s32)sTemp64; -} - -void PADDSW() { - if (!_Rd_) return; - - _PADDSW(0); _PADDSW(1); _PADDSW(2); _PADDSW(3); -} - -__forceinline void _PSUBSW(int n) -{ - s64 sTemp64; - - sTemp64 = (s64)cpuRegs.GPR.r[_Rs_].SL[n] - (s64)cpuRegs.GPR.r[_Rt_].SL[n]; - - if (sTemp64 >= 0x7FFFFFFF) - cpuRegs.GPR.r[_Rd_].UL[n] = 0x7FFFFFFF; - else if ((sTemp64 < (s32)0x80000000)) - cpuRegs.GPR.r[_Rd_].UL[n] = 0x80000000; - else - cpuRegs.GPR.r[_Rd_].UL[n] = (s32)sTemp64; -} - -void PSUBSW() { - if (!_Rd_) return; - - _PSUBSW(0); - _PSUBSW(1); - _PSUBSW(2); - _PSUBSW(3); -} - -void PEXTLW() { - GPR_reg Rs, Rt; - - if (!_Rd_) return; - - Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; - cpuRegs.GPR.r[_Rd_].UL[0] = Rt.UL[0]; - cpuRegs.GPR.r[_Rd_].UL[1] = Rs.UL[0]; - cpuRegs.GPR.r[_Rd_].UL[2] = Rt.UL[1]; - cpuRegs.GPR.r[_Rd_].UL[3] = Rs.UL[1]; -} - -void PPACW() { - GPR_reg Rs, Rt; - - if (!_Rd_) return; - - Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; - cpuRegs.GPR.r[_Rd_].UL[0] = Rt.UL[0]; - cpuRegs.GPR.r[_Rd_].UL[1] = Rt.UL[2]; - cpuRegs.GPR.r[_Rd_].UL[2] = Rs.UL[0]; - cpuRegs.GPR.r[_Rd_].UL[3] = Rs.UL[2]; -} - -__forceinline void _PADDSH(int n) -{ - s32 sTemp32; - sTemp32 = (s32)cpuRegs.GPR.r[_Rs_].SS[n] + (s32)cpuRegs.GPR.r[_Rt_].SS[n]; - - if (sTemp32 > 0x7FFF) - cpuRegs.GPR.r[_Rd_].US[n] = 0x7FFF; - else if ((sTemp32 < (s32)0xffff8000) ) - cpuRegs.GPR.r[_Rd_].US[n] = 0x8000; - else - cpuRegs.GPR.r[_Rd_].US[n] = (s16)sTemp32; -} - -void PADDSH() { - if (!_Rd_) return; - - _PADDSH(0); _PADDSH(1); _PADDSH(2); _PADDSH(3); - _PADDSH(4); _PADDSH(5); _PADDSH(6); _PADDSH(7); -} - -__forceinline void _PSUBSH(int n) -{ - s32 sTemp32; - sTemp32 = (s32)cpuRegs.GPR.r[_Rs_].SS[n] - (s32)cpuRegs.GPR.r[_Rt_].SS[n]; - - if (sTemp32 >= 0x7FFF) - cpuRegs.GPR.r[_Rd_].US[n] = 0x7FFF; - else if ((sTemp32 < (s32)0xffff8000) ) - cpuRegs.GPR.r[_Rd_].US[n] = 0x8000; - else - cpuRegs.GPR.r[_Rd_].US[n] = (s16)sTemp32; -} - -void PSUBSH() { - if (!_Rd_) return; - - _PSUBSH(0); _PSUBSH(1); _PSUBSH(2); _PSUBSH(3); - _PSUBSH(4); _PSUBSH(5); _PSUBSH(6); _PSUBSH(7); -} - -void PEXTLH() { - GPR_reg Rs, Rt; - - if (!_Rd_) return; - - Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; - cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[0]; - cpuRegs.GPR.r[_Rd_].US[1] = Rs.US[0]; - cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[1]; - cpuRegs.GPR.r[_Rd_].US[3] = Rs.US[1]; - cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[2]; - cpuRegs.GPR.r[_Rd_].US[5] = Rs.US[2]; - cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[3]; - cpuRegs.GPR.r[_Rd_].US[7] = Rs.US[3]; -} - -void PPACH() { - GPR_reg Rs, Rt; - - if (!_Rd_) return; - - Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; - cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[0]; - cpuRegs.GPR.r[_Rd_].US[1] = Rt.US[2]; - cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[4]; - cpuRegs.GPR.r[_Rd_].US[3] = Rt.US[6]; - cpuRegs.GPR.r[_Rd_].US[4] = Rs.US[0]; - cpuRegs.GPR.r[_Rd_].US[5] = Rs.US[2]; - cpuRegs.GPR.r[_Rd_].US[6] = Rs.US[4]; - cpuRegs.GPR.r[_Rd_].US[7] = Rs.US[6]; -} - -__forceinline void _PADDSB(int n) -{ - s16 sTemp16; - sTemp16 = (s16)cpuRegs.GPR.r[_Rs_].SC[n] + (s16)cpuRegs.GPR.r[_Rt_].SC[n]; - - if (sTemp16 > 0x7F) - cpuRegs.GPR.r[_Rd_].UC[n] = 0x7F; - else if ((sTemp16 < 0x180) && (sTemp16 >= 0x100)) - cpuRegs.GPR.r[_Rd_].UC[n] = 0x80; - else - cpuRegs.GPR.r[_Rd_].UC[n] = (s8)sTemp16; -} - -void PADDSB() { - int i; - if (!_Rd_) return; - - for( i=0; i<16; i++ ) - _PADDSB(i); -} - -static __forceinline void _PSUBSB( u8 n ) -{ - s16 sTemp16; - sTemp16 = (s16)cpuRegs.GPR.r[_Rs_].SC[n] - (s16)cpuRegs.GPR.r[_Rt_].SC[n]; - - if (sTemp16 >= 0x7F) - cpuRegs.GPR.r[_Rd_].UC[n] = 0x7F; - else if ((sTemp16 < 0x180) && (sTemp16 >= 0x100)) - cpuRegs.GPR.r[_Rd_].UC[n] = 0x80; - else - cpuRegs.GPR.r[_Rd_].UC[n] = (s8)sTemp16; -} - -void PSUBSB() { - int i; - if (!_Rd_) return; - - for( i=0; i<16; i++ ) - _PSUBSB(i); -} - -void PEXTLB() { - GPR_reg Rs, Rt; - - if (!_Rd_) return; - - Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; - cpuRegs.GPR.r[_Rd_].UC[0] = Rt.UC[0]; - cpuRegs.GPR.r[_Rd_].UC[1] = Rs.UC[0]; - cpuRegs.GPR.r[_Rd_].UC[2] = Rt.UC[1]; - cpuRegs.GPR.r[_Rd_].UC[3] = Rs.UC[1]; - - cpuRegs.GPR.r[_Rd_].UC[4] = Rt.UC[2]; - cpuRegs.GPR.r[_Rd_].UC[5] = Rs.UC[2]; - cpuRegs.GPR.r[_Rd_].UC[6] = Rt.UC[3]; - cpuRegs.GPR.r[_Rd_].UC[7] = Rs.UC[3]; - - cpuRegs.GPR.r[_Rd_].UC[8] = Rt.UC[4]; - cpuRegs.GPR.r[_Rd_].UC[9] = Rs.UC[4]; - cpuRegs.GPR.r[_Rd_].UC[10] = Rt.UC[5]; - cpuRegs.GPR.r[_Rd_].UC[11] = Rs.UC[5]; - - cpuRegs.GPR.r[_Rd_].UC[12] = Rt.UC[6]; - cpuRegs.GPR.r[_Rd_].UC[13] = Rs.UC[6]; - cpuRegs.GPR.r[_Rd_].UC[14] = Rt.UC[7]; - cpuRegs.GPR.r[_Rd_].UC[15] = Rs.UC[7]; -} - -void PPACB() { - GPR_reg Rs, Rt; - - if (!_Rd_) return; - - Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; - cpuRegs.GPR.r[_Rd_].UC[0] = Rt.UC[0]; - cpuRegs.GPR.r[_Rd_].UC[1] = Rt.UC[2]; - cpuRegs.GPR.r[_Rd_].UC[2] = Rt.UC[4]; - cpuRegs.GPR.r[_Rd_].UC[3] = Rt.UC[6]; - - cpuRegs.GPR.r[_Rd_].UC[4] = Rt.UC[8]; - cpuRegs.GPR.r[_Rd_].UC[5] = Rt.UC[10]; - cpuRegs.GPR.r[_Rd_].UC[6] = Rt.UC[12]; - cpuRegs.GPR.r[_Rd_].UC[7] = Rt.UC[14]; - - cpuRegs.GPR.r[_Rd_].UC[8] = Rs.UC[0]; - cpuRegs.GPR.r[_Rd_].UC[9] = Rs.UC[2]; - cpuRegs.GPR.r[_Rd_].UC[10] = Rs.UC[4]; - cpuRegs.GPR.r[_Rd_].UC[11] = Rs.UC[6]; - - cpuRegs.GPR.r[_Rd_].UC[12] = Rs.UC[8]; - cpuRegs.GPR.r[_Rd_].UC[13] = Rs.UC[10]; - cpuRegs.GPR.r[_Rd_].UC[14] = Rs.UC[12]; - cpuRegs.GPR.r[_Rd_].UC[15] = Rs.UC[14]; -} - -__forceinline void _PEXT5(int n) -{ - cpuRegs.GPR.r[_Rd_].UL[n] = \ - ((cpuRegs.GPR.r[_Rt_].UL[n] & 0x0000001F) << 3) | \ - ((cpuRegs.GPR.r[_Rt_].UL[n] & 0x000003E0) << 6) | \ - ((cpuRegs.GPR.r[_Rt_].UL[n] & 0x00007C00) << 9) | \ - ((cpuRegs.GPR.r[_Rt_].UL[n] & 0x00008000) << 16); -} - -void PEXT5() { - if (!_Rd_) return; - - _PEXT5(0); _PEXT5(1); _PEXT5(2); _PEXT5(3); -} - -__forceinline void _PPAC5(int n) -{ - cpuRegs.GPR.r[_Rd_].UL[n] = \ - ((cpuRegs.GPR.r[_Rt_].UL[n] >> 3) & 0x0000001F) | \ - ((cpuRegs.GPR.r[_Rt_].UL[n] >> 6) & 0x000003E0) | \ - ((cpuRegs.GPR.r[_Rt_].UL[n] >> 9) & 0x00007C00) | \ - ((cpuRegs.GPR.r[_Rt_].UL[n] >> 16) & 0x00008000); -} - -void PPAC5() { - if (!_Rd_) return; - - _PPAC5(0); _PPAC5(1); _PPAC5(2); _PPAC5(3); -} - -//***END OF MMI0 OPCODES****************************************** -//**********MMI1 OPCODES************************************** - -__forceinline void _PABSW(int n) -{ - cpuRegs.GPR.r[_Rd_].UL[n] = abs(cpuRegs.GPR.r[_Rt_].SL[n]); -} - -void PABSW() { - if (!_Rd_) return; - - _PABSW(0); _PABSW(1); _PABSW(2); _PABSW(3); -} - -__forceinline void _PCEQW(int n) -{ - if (cpuRegs.GPR.r[_Rs_].UL[n] == cpuRegs.GPR.r[_Rt_].UL[n]) - cpuRegs.GPR.r[_Rd_].UL[n] = 0xFFFFFFFF; - else - cpuRegs.GPR.r[_Rd_].UL[n] = 0x00000000; -} - -void PCEQW() { - if (!_Rd_) return; - - _PCEQW(0); _PCEQW(1); _PCEQW(2); _PCEQW(3); -} - -static __forceinline void _PMINW( u8 n ) -{ - if (cpuRegs.GPR.r[_Rs_].SL[n] < cpuRegs.GPR.r[_Rt_].SL[n]) - cpuRegs.GPR.r[_Rd_].SL[n] = cpuRegs.GPR.r[_Rs_].SL[n]; - else - cpuRegs.GPR.r[_Rd_].SL[n] = cpuRegs.GPR.r[_Rt_].SL[n]; -} - -void PMINW() { - if (!_Rd_) return; - - _PMINW(0); _PMINW(1); _PMINW(2); _PMINW(3); -} - -void PADSBH() { - if (!_Rd_) return; - - _PSUBH(0); _PSUBH(1); _PSUBH(2); _PSUBH(3); - _PADDH(4); _PADDH(5); _PADDH(6); _PADDH(7); -} - -__forceinline void _PABSH(int n) -{ - cpuRegs.GPR.r[_Rd_].US[n] = abs(cpuRegs.GPR.r[_Rt_].SS[n]); -} - -void PABSH() { - if (!_Rd_) return; - - _PABSH(0); _PABSH(1); _PABSH(2); _PABSH(3); - _PABSH(4); _PABSH(5); _PABSH(6); _PABSH(7); -} - -static __forceinline void _PCEQH( u8 n ) -{ - if (cpuRegs.GPR.r[_Rs_].US[n] == cpuRegs.GPR.r[_Rt_].US[n]) - cpuRegs.GPR.r[_Rd_].US[n] = 0xFFFF; - else - cpuRegs.GPR.r[_Rd_].US[n] = 0x0000; -} - -void PCEQH() { - if (!_Rd_) return; - - _PCEQH(0); _PCEQH(1); _PCEQH(2); _PCEQH(3); - _PCEQH(4); _PCEQH(5); _PCEQH(6); _PCEQH(7); -} - -static __forceinline void _PMINH( u8 n ) -{ - if (cpuRegs.GPR.r[_Rs_].SS[n] < cpuRegs.GPR.r[_Rt_].SS[n]) - cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rs_].US[n]; - else - cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rt_].US[n]; -} - -void PMINH() { - if (!_Rd_) return; - - _PMINH(0); _PMINH(1); _PMINH(2); _PMINH(3); - _PMINH(4); _PMINH(5); _PMINH(6); _PMINH(7); -} - -__forceinline void _PCEQB(int n) -{ - if (cpuRegs.GPR.r[_Rs_].UC[n] == cpuRegs.GPR.r[_Rt_].UC[n]) - cpuRegs.GPR.r[_Rd_].UC[n] = 0xFF; - else - cpuRegs.GPR.r[_Rd_].UC[n] = 0x00; -} - -void PCEQB() { - int i; - if (!_Rd_) return; - - for( i=0; i<16; i++ ) - _PCEQB(i); -} - -__forceinline void _PADDUW(int n) -{ - s64 tmp; - tmp = (s64)cpuRegs.GPR.r[_Rs_].UL[n] + (s64)cpuRegs.GPR.r[_Rt_].UL[n]; - - if (tmp > 0xffffffff) - cpuRegs.GPR.r[_Rd_].UL[n] = 0xffffffff; - else - cpuRegs.GPR.r[_Rd_].UL[n] = (u32)tmp; -} - -void PADDUW () { - if (!_Rd_) return; - - _PADDUW(0); _PADDUW(1); _PADDUW(2); _PADDUW(3); -} - -__forceinline void _PSUBUW(int n) -{ - s64 sTemp64; - sTemp64 = (s64)cpuRegs.GPR.r[_Rs_].UL[n] - (s64)cpuRegs.GPR.r[_Rt_].UL[n]; - - if (sTemp64 <= 0x0) - cpuRegs.GPR.r[_Rd_].UL[n] = 0x0; - else - cpuRegs.GPR.r[_Rd_].UL[n] = (u32)sTemp64; -} - -void PSUBUW() { - if (!_Rd_) return; - - _PSUBUW(0); _PSUBUW(1); _PSUBUW(2); _PSUBUW(3); -} - -void PEXTUW() { - GPR_reg Rs, Rt; - - if (!_Rd_) return; - - Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; - cpuRegs.GPR.r[_Rd_].UL[0] = Rt.UL[2]; - cpuRegs.GPR.r[_Rd_].UL[1] = Rs.UL[2]; - cpuRegs.GPR.r[_Rd_].UL[2] = Rt.UL[3]; - cpuRegs.GPR.r[_Rd_].UL[3] = Rs.UL[3]; -} - -__forceinline void _PADDUH(int n) -{ - s32 sTemp32; - sTemp32 = (s32)cpuRegs.GPR.r[_Rs_].US[n] + (s32)cpuRegs.GPR.r[_Rt_].US[n]; - - if (sTemp32 > 0xFFFF) - cpuRegs.GPR.r[_Rd_].US[n] = 0xFFFF; - else - cpuRegs.GPR.r[_Rd_].US[n] = (u16)sTemp32; -} - -void PADDUH() { - if (!_Rd_) return; - - _PADDUH(0); _PADDUH(1); _PADDUH(2); _PADDUH(3); - _PADDUH(4); _PADDUH(5); _PADDUH(6); _PADDUH(7); -} - -__forceinline void _PSUBUH(int n) -{ - s32 sTemp32; - sTemp32 = (s32)cpuRegs.GPR.r[_Rs_].US[n] - (s32)cpuRegs.GPR.r[_Rt_].US[n]; - - if (sTemp32 <= 0x0) - cpuRegs.GPR.r[_Rd_].US[n] = 0x0; - else - cpuRegs.GPR.r[_Rd_].US[n] = (u16)sTemp32; -} - -void PSUBUH() { - if (!_Rd_) return; - - _PSUBUH(0); _PSUBUH(1); _PSUBUH(2); _PSUBUH(3); - _PSUBUH(4); _PSUBUH(5); _PSUBUH(6); _PSUBUH(7); -} - -void PEXTUH() { - GPR_reg Rs, Rt; - - if (!_Rd_) return; - - Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; - cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[4]; - cpuRegs.GPR.r[_Rd_].US[1] = Rs.US[4]; - cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[5]; - cpuRegs.GPR.r[_Rd_].US[3] = Rs.US[5]; - - cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[6]; - cpuRegs.GPR.r[_Rd_].US[5] = Rs.US[6]; - cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[7]; - cpuRegs.GPR.r[_Rd_].US[7] = Rs.US[7]; -} - -__forceinline void _PADDUB(int n) -{ - u16 Temp16; - Temp16 = (u16)cpuRegs.GPR.r[_Rs_].UC[n] + (u16)cpuRegs.GPR.r[_Rt_].UC[n]; - - if (Temp16 > 0xFF) - cpuRegs.GPR.r[_Rd_].UC[n] = 0xFF; - else - cpuRegs.GPR.r[_Rd_].UC[n] = (u8)Temp16; -} - -void PADDUB() { - int i; - if (!_Rd_) return; - - for( i=0; i<16; i++ ) - _PADDUB(i); -} - -__forceinline void _PSUBUB(int n) { - s16 sTemp16; - sTemp16 = (s16)cpuRegs.GPR.r[_Rs_].UC[n] - (s16)cpuRegs.GPR.r[_Rt_].UC[n]; - - if (sTemp16 <= 0x0) - cpuRegs.GPR.r[_Rd_].UC[n] = 0x0; - else - cpuRegs.GPR.r[_Rd_].UC[n] = (u8)sTemp16; -} - -void PSUBUB() { - int i; - if (!_Rd_) return; - - for( i=0; i<16; i++ ) - _PSUBUB(i); -} - -void PEXTUB() { - GPR_reg Rs, Rt; - - if (!_Rd_) return; - - Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; - cpuRegs.GPR.r[_Rd_].UC[0] = Rt.UC[8]; - cpuRegs.GPR.r[_Rd_].UC[1] = Rs.UC[8]; - cpuRegs.GPR.r[_Rd_].UC[2] = Rt.UC[9]; - cpuRegs.GPR.r[_Rd_].UC[3] = Rs.UC[9]; - cpuRegs.GPR.r[_Rd_].UC[4] = Rt.UC[10]; - cpuRegs.GPR.r[_Rd_].UC[5] = Rs.UC[10]; - cpuRegs.GPR.r[_Rd_].UC[6] = Rt.UC[11]; - cpuRegs.GPR.r[_Rd_].UC[7] = Rs.UC[11]; - cpuRegs.GPR.r[_Rd_].UC[8] = Rt.UC[12]; - cpuRegs.GPR.r[_Rd_].UC[9] = Rs.UC[12]; - cpuRegs.GPR.r[_Rd_].UC[10] = Rt.UC[13]; - cpuRegs.GPR.r[_Rd_].UC[11] = Rs.UC[13]; - cpuRegs.GPR.r[_Rd_].UC[12] = Rt.UC[14]; - cpuRegs.GPR.r[_Rd_].UC[13] = Rs.UC[14]; - cpuRegs.GPR.r[_Rd_].UC[14] = Rt.UC[15]; - cpuRegs.GPR.r[_Rd_].UC[15] = Rs.UC[15]; -} - -//int saZero = 0; -void QFSRV() { // JayteeMaster: changed a bit to avoid screw up - GPR_reg Rd; - if (!_Rd_) return; - - if (cpuRegs.sa == 0) { - cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0]; - cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rt_].UD[1]; - //saZero++; - //if( saZero >= 388800 ) - //Console::WriteLn( "SA Is Zero, Bitch: %d zeros and counting.", params saZero ); - } else { - //Console::WriteLn( "SA Properly Valued at: %d (after %d zeros)", params cpuRegs.sa, saZero ); - //saZero = 0; - if (cpuRegs.sa < 64) { - /* - cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0] >> cpuRegs.sa; - cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rt_].UD[1] >> cpuRegs.sa; - cpuRegs.GPR.r[_Rd_].UD[0]|= cpuRegs.GPR.r[_Rt_].UD[1] << (64 - cpuRegs.sa); - cpuRegs.GPR.r[_Rd_].UD[1]|= cpuRegs.GPR.r[_Rs_].UD[0] << (64 - cpuRegs.sa); - */ - Rd.UD[0] = cpuRegs.GPR.r[_Rt_].UD[0] >> cpuRegs.sa; - Rd.UD[1] = cpuRegs.GPR.r[_Rt_].UD[1] >> cpuRegs.sa; - Rd.UD[0]|= cpuRegs.GPR.r[_Rt_].UD[1] << (64 - cpuRegs.sa); - Rd.UD[1]|= cpuRegs.GPR.r[_Rs_].UD[0] << (64 - cpuRegs.sa); - cpuRegs.GPR.r[_Rd_] = Rd; - } else { - /* - cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[1] >> (cpuRegs.sa - 64); - cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rs_].UD[0] >> (cpuRegs.sa - 64); - cpuRegs.GPR.r[_Rd_].UD[0]|= cpuRegs.GPR.r[_Rs_].UD[0] << (128 - cpuRegs.sa); - cpuRegs.GPR.r[_Rd_].UD[1]|= cpuRegs.GPR.r[_Rs_].UD[1] << (128 - cpuRegs.sa); - */ - Rd.UD[0] = cpuRegs.GPR.r[_Rt_].UD[1] >> (cpuRegs.sa - 64); - Rd.UD[1] = cpuRegs.GPR.r[_Rs_].UD[0] >> (cpuRegs.sa - 64); - Rd.UD[0]|= cpuRegs.GPR.r[_Rs_].UD[0] << (128 - cpuRegs.sa); - Rd.UD[1]|= cpuRegs.GPR.r[_Rs_].UD[1] << (128 - cpuRegs.sa); - cpuRegs.GPR.r[_Rd_] = Rd; - } - } -} - -//********END OF MMI1 OPCODES*********************************** - -//*********MMI2 OPCODES*************************************** - -__forceinline void _PMADDW(int dd, int ss) -{ - s64 temp = (s64)((s64)cpuRegs.LO.SL[ss] | ((s64)cpuRegs.HI.SL[ss] << 32)) + - ((s64)cpuRegs.GPR.r[_Rs_].SL[ss] * (s64)cpuRegs.GPR.r[_Rt_].SL[ss]); - - cpuRegs.LO.SD[dd] = (s32)(temp & 0xffffffff); - cpuRegs.HI.SD[dd] = (s32)(temp >> 32); - - if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[dd] = temp; -} - -void PMADDW() { - _PMADDW(0, 0); - _PMADDW(1, 2); -} - -void PSLLVW() { - if (!_Rd_) return; - - cpuRegs.GPR.r[_Rd_].UD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] << - (cpuRegs.GPR.r[_Rs_].UL[0] & 0x1F)); - cpuRegs.GPR.r[_Rd_].UD[1] = (s32)(cpuRegs.GPR.r[_Rt_].UL[2] << - (cpuRegs.GPR.r[_Rs_].UL[2] & 0x1F)); -} - -void PSRLVW() { - if (!_Rd_) return; - - cpuRegs.GPR.r[_Rd_].UD[0] = (cpuRegs.GPR.r[_Rt_].UL[0] >> - (cpuRegs.GPR.r[_Rs_].UL[0] & 0x1F)); - cpuRegs.GPR.r[_Rd_].UD[1] = (cpuRegs.GPR.r[_Rt_].UL[2] >> - (cpuRegs.GPR.r[_Rs_].UL[2] & 0x1F)); -} - -__forceinline void _PMSUBW(int dd, int ss) -{ - s64 temp = (s64)((s64)cpuRegs.LO.SL[ss] | ((s64)cpuRegs.HI.SL[ss] << 32)) - - ((s64)cpuRegs.GPR.r[_Rs_].SL[ss] * (s64)cpuRegs.GPR.r[_Rt_].SL[ss]); - - cpuRegs.LO.SD[dd] = (s32)(temp & 0xffffffff); - cpuRegs.HI.SD[dd] = (s32)(temp >> 32); - - if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[dd] = temp; -} - -void PMSUBW() { - _PMSUBW(0, 0); - _PMSUBW(1, 2); -} - -void PMFHI() { - if (!_Rd_) return; - - cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.HI.UD[0]; - cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.HI.UD[1]; -} - -void PMFLO() { - if (!_Rd_) return; - - cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[0]; - cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.LO.UD[1]; -} - -void PINTH() { - GPR_reg Rs, Rt; - - if (!_Rd_) return; - - Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; - cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[0]; - cpuRegs.GPR.r[_Rd_].US[1] = Rs.US[4]; - cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[1]; - cpuRegs.GPR.r[_Rd_].US[3] = Rs.US[5]; - cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[2]; - cpuRegs.GPR.r[_Rd_].US[5] = Rs.US[6]; - cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[3]; - cpuRegs.GPR.r[_Rd_].US[7] = Rs.US[7]; -} - -__forceinline void _PMULTW(int dd, int ss) -{ - s64 temp = (s64)cpuRegs.GPR.r[_Rs_].SL[ss] * (s64)cpuRegs.GPR.r[_Rt_].SL[ss]; - - cpuRegs.LO.UD[dd] = (s32)(temp & 0xffffffff); - cpuRegs.HI.UD[dd] = (s32)(temp >> 32); - - if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[dd] = temp; -} - -void PMULTW() { - _PMULTW(0, 0); - _PMULTW(1, 2); -} - -__forceinline void _PDIVW(int dd, int ss) -{ - if (cpuRegs.GPR.r[_Rt_].UL[ss] != 0) - { - cpuRegs.LO.SD[dd] = cpuRegs.GPR.r[_Rs_].SL[ss] / cpuRegs.GPR.r[_Rt_].SL[ss]; - cpuRegs.HI.SD[dd] = cpuRegs.GPR.r[_Rs_].SL[ss] % cpuRegs.GPR.r[_Rt_].SL[ss]; - } -} - -void PDIVW() { - _PDIVW(0, 0); - _PDIVW(1, 2); -} - -void PCPYLD() { - if (!_Rd_) return; - - // note: first _Rs_, since the other way when _Rd_ equals - // _Rs_ or _Rt_ this would screw up - cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rs_].UD[0]; - cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0]; -} - -void PMADDH() { // JayteeMaster: changed a bit to avoid screw up - s32 temp; - - temp = cpuRegs.LO.UL[0] + (s32)cpuRegs.GPR.r[_Rs_].SS[0] * (s32)cpuRegs.GPR.r[_Rt_].SS[0]; - cpuRegs.LO.UL[0] = temp; - /* if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[0] = temp; */ - - temp = cpuRegs.LO.UL[1] + (s32)cpuRegs.GPR.r[_Rs_].SS[1] * (s32)cpuRegs.GPR.r[_Rt_].SS[1]; - cpuRegs.LO.UL[1] = temp; - - temp = cpuRegs.HI.UL[0] + (s32)cpuRegs.GPR.r[_Rs_].SS[2] * (s32)cpuRegs.GPR.r[_Rt_].SS[2]; - cpuRegs.HI.UL[0] = temp; - /* if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[1] = temp; */ - - temp = cpuRegs.HI.UL[1] + (s32)cpuRegs.GPR.r[_Rs_].SS[3] * (s32)cpuRegs.GPR.r[_Rt_].SS[3]; - cpuRegs.HI.UL[1] = temp; - - temp = cpuRegs.LO.UL[2] + (s32)cpuRegs.GPR.r[_Rs_].SS[4] * (s32)cpuRegs.GPR.r[_Rt_].SS[4]; - cpuRegs.LO.UL[2] = temp; - /* if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[2] = temp; */ - - temp = cpuRegs.LO.UL[3] + (s32)cpuRegs.GPR.r[_Rs_].SS[5] * (s32)cpuRegs.GPR.r[_Rt_].SS[5]; - cpuRegs.LO.UL[3] = temp; - - temp = cpuRegs.HI.UL[2] + (s32)cpuRegs.GPR.r[_Rs_].SS[6] * (s32)cpuRegs.GPR.r[_Rt_].SS[6]; - cpuRegs.HI.UL[2] = temp; - /* if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[3] = temp; */ - - temp = cpuRegs.HI.UL[3] + (s32)cpuRegs.GPR.r[_Rs_].SS[7] * (s32)cpuRegs.GPR.r[_Rt_].SS[7]; - cpuRegs.HI.UL[3] = temp; - - if (_Rd_) { - cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[0]; - cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[0]; - cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[2]; - cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[2]; - } - -} - -// JayteeMaster: changed a bit to avoid screw up -__forceinline void _PHMADH_LO(int dd, int n) -{ - s32 temp = (s32)cpuRegs.GPR.r[_Rs_].SS[n+1] * (s32)cpuRegs.GPR.r[_Rt_].SS[n+1] + \ - (s32)cpuRegs.GPR.r[_Rs_].SS[n] * (s32)cpuRegs.GPR.r[_Rt_].SS[n]; - - cpuRegs.LO.UL[dd] = temp; -} - -__forceinline void _PHMADH_HI(int dd, int n) -{ - s32 temp = (s32)cpuRegs.GPR.r[_Rs_].SS[n+1] * (s32)cpuRegs.GPR.r[_Rt_].SS[n+1] + \ - (s32)cpuRegs.GPR.r[_Rs_].SS[n] * (s32)cpuRegs.GPR.r[_Rt_].SS[n]; - - cpuRegs.HI.UL[dd] = temp; -} - -void PHMADH() { // JayteeMaster: changed a bit to avoid screw up. Also used 0,2,4,6 instead of 0,1,2,3 - _PHMADH_LO(0, 0); - _PHMADH_HI(0, 2); - _PHMADH_LO(2, 4); - _PHMADH_HI(2, 6); - if (_Rd_) { - cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[0]; - cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[0]; - cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[2]; - cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[2]; - } -} - -void PAND() { - if (!_Rd_) return; - - cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] & cpuRegs.GPR.r[_Rt_].UD[0]; - cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rs_].UD[1] & cpuRegs.GPR.r[_Rt_].UD[1]; -} - -void PXOR() { - if (!_Rd_) return; - - cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] ^ cpuRegs.GPR.r[_Rt_].UD[0]; - cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rs_].UD[1] ^ cpuRegs.GPR.r[_Rt_].UD[1]; -} - -void PMSUBH() { // JayteeMaster: changed a bit to avoid screw up - s32 temp; - - temp = cpuRegs.LO.UL[0] - (s32)cpuRegs.GPR.r[_Rs_].SS[0] * (s32)cpuRegs.GPR.r[_Rt_].SS[0]; - cpuRegs.LO.UL[0] = temp; - /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[0] = temp;*/ - - temp = cpuRegs.LO.UL[1] - (s32)cpuRegs.GPR.r[_Rs_].SS[1] * (s32)cpuRegs.GPR.r[_Rt_].SS[1]; - cpuRegs.LO.UL[1] = temp; - - temp = cpuRegs.HI.UL[0] - (s32)cpuRegs.GPR.r[_Rs_].SS[2] * (s32)cpuRegs.GPR.r[_Rt_].SS[2]; - cpuRegs.HI.UL[0] = temp; - /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[1] = temp;*/ - - temp = cpuRegs.HI.UL[1] - (s32)cpuRegs.GPR.r[_Rs_].SS[3] * (s32)cpuRegs.GPR.r[_Rt_].SS[3]; - cpuRegs.HI.UL[1] = temp; - - temp = cpuRegs.LO.UL[2] - (s32)cpuRegs.GPR.r[_Rs_].SS[4] * (s32)cpuRegs.GPR.r[_Rt_].SS[4]; - cpuRegs.LO.UL[2] = temp; - /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[2] = temp;*/ - - temp = cpuRegs.LO.UL[3] - (s32)cpuRegs.GPR.r[_Rs_].SS[5] * (s32)cpuRegs.GPR.r[_Rt_].SS[5]; - cpuRegs.LO.UL[3] = temp; - - temp = cpuRegs.HI.UL[2] - (s32)cpuRegs.GPR.r[_Rs_].SS[6] * (s32)cpuRegs.GPR.r[_Rt_].SS[6]; - cpuRegs.HI.UL[2] = temp; - /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[3] = temp;*/ - - temp = cpuRegs.HI.UL[3] - (s32)cpuRegs.GPR.r[_Rs_].SS[7] * (s32)cpuRegs.GPR.r[_Rt_].SS[7]; - cpuRegs.HI.UL[3] = temp; - - if (_Rd_) { - cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[0]; - cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[0]; - cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[2]; - cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[2]; - } -} - -// JayteeMaster: changed a bit to avoid screw up -__forceinline void _PHMSBH_LO(int dd, int n, int rdd) -{ - s32 temp = (s32)cpuRegs.GPR.r[_Rs_].SS[n+1] * (s32)cpuRegs.GPR.r[_Rt_].SS[n+1] - \ - (s32)cpuRegs.GPR.r[_Rs_].SS[n] * (s32)cpuRegs.GPR.r[_Rt_].SS[n]; - - cpuRegs.LO.UL[dd] = temp; -} -__forceinline void _PHMSBH_HI(int dd, int n, int rdd) -{ - s32 temp = (s32)cpuRegs.GPR.r[_Rs_].SS[n+1] * (s32)cpuRegs.GPR.r[_Rt_].SS[n+1] - \ - (s32)cpuRegs.GPR.r[_Rs_].SS[n] * (s32)cpuRegs.GPR.r[_Rt_].SS[n]; - - cpuRegs.HI.UL[dd] = temp; -} - -void PHMSBH() { // JayteeMaster: changed a bit to avoid screw up - _PHMSBH_LO(0, 0, 0); - _PHMSBH_HI(0, 2, 1); - _PHMSBH_LO(2, 4, 2); - _PHMSBH_HI(2, 6, 3); - if (_Rd_) { - cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[0]; - cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[0]; - cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[2]; - cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[2]; - } -} - -void PEXEH() { - GPR_reg Rt; - - if (!_Rd_) return; - - Rt = cpuRegs.GPR.r[_Rt_]; - cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[2]; - cpuRegs.GPR.r[_Rd_].US[1] = Rt.US[1]; - cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[0]; - cpuRegs.GPR.r[_Rd_].US[3] = Rt.US[3]; - cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[6]; - cpuRegs.GPR.r[_Rd_].US[5] = Rt.US[5]; - cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[4]; - cpuRegs.GPR.r[_Rd_].US[7] = Rt.US[7]; -} - -void PREVH () { - GPR_reg Rt; - - if (!_Rd_) return; - - Rt = cpuRegs.GPR.r[_Rt_]; - cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[3]; - cpuRegs.GPR.r[_Rd_].US[1] = Rt.US[2]; - cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[1]; - cpuRegs.GPR.r[_Rd_].US[3] = Rt.US[0]; - cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[7]; - cpuRegs.GPR.r[_Rd_].US[5] = Rt.US[6]; - cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[5]; - cpuRegs.GPR.r[_Rd_].US[7] = Rt.US[4]; -} - -void PMULTH() { // JayteeMaster: changed a bit to avoid screw up - s32 temp; - - temp = (s32)cpuRegs.GPR.r[_Rs_].SS[0] * (s32)cpuRegs.GPR.r[_Rt_].SS[0]; - cpuRegs.LO.UL[0] = temp; - /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[0] = temp;*/ - - temp = (s32)cpuRegs.GPR.r[_Rs_].SS[1] * (s32)cpuRegs.GPR.r[_Rt_].SS[1]; - cpuRegs.LO.UL[1] = temp; - - temp = (s32)cpuRegs.GPR.r[_Rs_].SS[2] * (s32)cpuRegs.GPR.r[_Rt_].SS[2]; - cpuRegs.HI.UL[0] = temp; - /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[1] = temp;*/ - - temp = (s32)cpuRegs.GPR.r[_Rs_].SS[3] * (s32)cpuRegs.GPR.r[_Rt_].SS[3]; - cpuRegs.HI.UL[1] = temp; - - temp = (s32)cpuRegs.GPR.r[_Rs_].SS[4] * (s32)cpuRegs.GPR.r[_Rt_].SS[4]; - cpuRegs.LO.UL[2] = temp; - /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[2] = temp;*/ - - temp = (s32)cpuRegs.GPR.r[_Rs_].SS[5] * (s32)cpuRegs.GPR.r[_Rt_].SS[5]; - cpuRegs.LO.UL[3] = temp; - - temp = (s32)cpuRegs.GPR.r[_Rs_].SS[6] * (s32)cpuRegs.GPR.r[_Rt_].SS[6]; - cpuRegs.HI.UL[2] = temp; - /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[3] = temp;*/ - - temp = (s32)cpuRegs.GPR.r[_Rs_].SS[7] * (s32)cpuRegs.GPR.r[_Rt_].SS[7]; - cpuRegs.HI.UL[3] = temp; - - if (_Rd_) { - cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[0]; - cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[0]; - cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[2]; - cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[2]; - } -} - -__forceinline void _PDIVBW(int n) -{ - cpuRegs.LO.UL[n] = (s32)(cpuRegs.GPR.r[_Rs_].SL[n] / cpuRegs.GPR.r[_Rt_].SS[0]); - cpuRegs.HI.UL[n] = (s16)(cpuRegs.GPR.r[_Rs_].SL[n] % cpuRegs.GPR.r[_Rt_].SS[0]); -} - -void PDIVBW() { - if (cpuRegs.GPR.r[_Rt_].US[0] == 0) return; - - _PDIVBW(0); _PDIVBW(1); _PDIVBW(2); _PDIVBW(3); -} - -void PEXEW() { - GPR_reg Rt; - - if (!_Rd_) return; - - Rt = cpuRegs.GPR.r[_Rt_]; - cpuRegs.GPR.r[_Rd_].UL[0] = Rt.UL[2]; - cpuRegs.GPR.r[_Rd_].UL[1] = Rt.UL[1]; - cpuRegs.GPR.r[_Rd_].UL[2] = Rt.UL[0]; - cpuRegs.GPR.r[_Rd_].UL[3] = Rt.UL[3]; -} - -void PROT3W() { - GPR_reg Rt; - - if (!_Rd_) return; - - Rt = cpuRegs.GPR.r[_Rt_]; - cpuRegs.GPR.r[_Rd_].UL[0] = Rt.UL[1]; - cpuRegs.GPR.r[_Rd_].UL[1] = Rt.UL[2]; - cpuRegs.GPR.r[_Rd_].UL[2] = Rt.UL[0]; - cpuRegs.GPR.r[_Rd_].UL[3] = Rt.UL[3]; -} - -//*****END OF MMI2 OPCODES*********************************** - -//*************************MMI3 OPCODES************************ - -__forceinline void _PMADDUW(int dd, int ss) -{ - u64 tempu = (u64)((u64)cpuRegs.LO.UL[ss] | ((u64)cpuRegs.HI.UL[ss] << 32)) + \ - ((u64)cpuRegs.GPR.r[_Rs_].UL[ss] * (u64)cpuRegs.GPR.r[_Rt_].UL[ss]); - - cpuRegs.LO.SD[dd] = (s32)(tempu & 0xffffffff); - cpuRegs.HI.SD[dd] = (s32)(tempu >> 32); - - if (_Rd_) cpuRegs.GPR.r[_Rd_].UD[dd] = tempu; -} - -void PMADDUW() { - _PMADDUW(0, 0); - _PMADDUW(1, 2); -} - -void PSRAVW() { - if (!_Rd_) return; - - cpuRegs.GPR.r[_Rd_].UD[0] = (cpuRegs.GPR.r[_Rt_].SL[0] >> - (cpuRegs.GPR.r[_Rs_].UL[0] & 0x1F)); - cpuRegs.GPR.r[_Rd_].UD[1] = (cpuRegs.GPR.r[_Rt_].SL[2] >> - (cpuRegs.GPR.r[_Rs_].UL[2] & 0x1F)); -} - -void PMTHI() { - cpuRegs.HI.UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; - cpuRegs.HI.UD[1] = cpuRegs.GPR.r[_Rs_].UD[1]; -} - -void PMTLO() { - cpuRegs.LO.UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; - cpuRegs.LO.UD[1] = cpuRegs.GPR.r[_Rs_].UD[1]; -} - -void PINTEH() { - GPR_reg Rs, Rt; - - if (!_Rd_) return; - - Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; - cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[0]; - cpuRegs.GPR.r[_Rd_].US[1] = Rs.US[0]; - cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[2]; - cpuRegs.GPR.r[_Rd_].US[3] = Rs.US[2]; - cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[4]; - cpuRegs.GPR.r[_Rd_].US[5] = Rs.US[4]; - cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[6]; - cpuRegs.GPR.r[_Rd_].US[7] = Rs.US[6]; -} - -__forceinline void _PMULTUW(int dd, int ss) -{ - u64 tempu = (u64)cpuRegs.GPR.r[_Rs_].UL[ss] * (u64)cpuRegs.GPR.r[_Rt_].UL[ss]; - - cpuRegs.LO.UD[dd] = (s32)(tempu & 0xffffffff); - cpuRegs.HI.UD[dd] = (s32)(tempu >> 32); - - if (_Rd_) cpuRegs.GPR.r[_Rd_].UD[dd] = tempu; -} - - -void PMULTUW() { - _PMULTUW(0, 0); - _PMULTUW(1, 2); -} - -__forceinline void _PDIVUW(int dd, int ss) -{ - if (cpuRegs.GPR.r[_Rt_].UL[ss] != 0) { - cpuRegs.LO.UD[dd] = (u64)cpuRegs.GPR.r[_Rs_].UL[ss] / (u64)cpuRegs.GPR.r[_Rt_].UL[ss]; - cpuRegs.HI.UD[dd] = (u64)cpuRegs.GPR.r[_Rs_].UL[ss] % (u64)cpuRegs.GPR.r[_Rt_].UL[ss]; - } -} - -void PDIVUW() { - _PDIVUW(0, 0); - _PDIVUW(1, 2); -} - -void PCPYUD() { - if (!_Rd_) return; - - // note: first _Rs_, since the other way when _Rd_ equals - // _Rs_ or _Rt_ this would screw up - cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[1]; - cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rt_].UD[1]; -} - -void POR() { - if (!_Rd_) return; - - cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] | cpuRegs.GPR.r[_Rt_].UD[0]; - cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rs_].UD[1] | cpuRegs.GPR.r[_Rt_].UD[1]; -} - -void PNOR () { - if (!_Rd_) return; - - cpuRegs.GPR.r[_Rd_].UD[0] = ~(cpuRegs.GPR.r[_Rs_].UD[0] | cpuRegs.GPR.r[_Rt_].UD[0]); - cpuRegs.GPR.r[_Rd_].UD[1] = ~(cpuRegs.GPR.r[_Rs_].UD[1] | cpuRegs.GPR.r[_Rt_].UD[1]); -} - -void PEXCH() { - GPR_reg Rt; - - if (!_Rd_) return; - - Rt = cpuRegs.GPR.r[_Rt_]; - cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[0]; - cpuRegs.GPR.r[_Rd_].US[1] = Rt.US[2]; - cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[1]; - cpuRegs.GPR.r[_Rd_].US[3] = Rt.US[3]; - cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[4]; - cpuRegs.GPR.r[_Rd_].US[5] = Rt.US[6]; - cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[5]; - cpuRegs.GPR.r[_Rd_].US[7] = Rt.US[7]; -} - -void PCPYH() { - GPR_reg Rt; - - if (!_Rd_) return; - - Rt = cpuRegs.GPR.r[_Rt_]; - cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[0]; - cpuRegs.GPR.r[_Rd_].US[1] = Rt.US[0]; - cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[0]; - cpuRegs.GPR.r[_Rd_].US[3] = Rt.US[0]; - cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[4]; - cpuRegs.GPR.r[_Rd_].US[5] = Rt.US[4]; - cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[4]; - cpuRegs.GPR.r[_Rd_].US[7] = Rt.US[4]; -} - -void PEXCW() { - GPR_reg Rt; - - if (!_Rd_) return; - - Rt = cpuRegs.GPR.r[_Rt_]; - cpuRegs.GPR.r[_Rd_].UL[0] = Rt.UL[0]; - cpuRegs.GPR.r[_Rd_].UL[1] = Rt.UL[2]; - cpuRegs.GPR.r[_Rd_].UL[2] = Rt.UL[1]; - cpuRegs.GPR.r[_Rd_].UL[3] = Rt.UL[3]; -} - -//**********************END OF MMI3 OPCODES******************** - -// obs: -// QFSRV not verified - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "DebugTools/Debug.h" +#include "R5900.h" +#include "R5900OpcodeTables.h" + +namespace R5900 { +namespace Interpreter { +namespace OpcodeImpl { + + ///////////////////////////////////////////////////////////////// + // Non-MMI Instructions! + // + // Several instructions in the MMI opcode class are actually just regular + // instructions which have been added to "extend" the R5900's instruction + // set. They're here, because if not here they'd be homeless. + // - The Pcsx2 team, doing their part to fight homelessness + + void MADD() { + s64 temp = (s64)((u64)cpuRegs.LO.UL[0] | ((u64)cpuRegs.HI.UL[0] << 32)) + + ((s64)cpuRegs.GPR.r[_Rs_].SL[0] * (s64)cpuRegs.GPR.r[_Rt_].SL[0]); + + cpuRegs.LO.SD[0] = (s32)(temp & 0xffffffff); + cpuRegs.HI.SD[0] = (s32)(temp >> 32); + + if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[0] = cpuRegs.LO.SD[0]; + } + + void MADDU() { + u64 tempu = (u64)((u64)cpuRegs.LO.UL[0] | ((u64)cpuRegs.HI.UL[0] << 32)) + + ((u64)cpuRegs.GPR.r[_Rs_].UL[0] * (u64)cpuRegs.GPR.r[_Rt_].UL[0]); + + cpuRegs.LO.SD[0] = (s32)(tempu & 0xffffffff); + cpuRegs.HI.SD[0] = (s32)(tempu >> 32); + + if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[0] = cpuRegs.LO.SD[0]; + } + + void MADD1() { + s64 temp = (s64)((u64)cpuRegs.LO.UL[2] | ((u64)cpuRegs.HI.UL[2] << 32)) + + ((s64)cpuRegs.GPR.r[_Rs_].SL[0] * (s64)cpuRegs.GPR.r[_Rt_].SL[0]); + + cpuRegs.LO.SD[1] = (s32)(temp & 0xffffffff); + cpuRegs.HI.SD[1] = (s32)(temp >> 32); + + if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[0] = cpuRegs.LO.SD[1]; + } + + void MADDU1() { + u64 tempu = (u64)((u64)cpuRegs.LO.UL[2] | ((u64)cpuRegs.HI.UL[2] << 32)) + + ((u64)cpuRegs.GPR.r[_Rs_].UL[0] * (u64)cpuRegs.GPR.r[_Rt_].UL[0]); + + cpuRegs.LO.SD[1] = (s32)(tempu & 0xffffffff); + cpuRegs.HI.SD[1] = (s32)(tempu >> 32); + + if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[0] = cpuRegs.LO.SD[1]; + } + + void MFHI1() { + if (!_Rd_) return; + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.HI.UD[1]; + } + + void MFLO1() { + if (!_Rd_) return; + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[1]; + } + + void MTHI1() { + cpuRegs.HI.UD[1] = cpuRegs.GPR.r[_Rs_].UD[0]; + } + + void MTLO1() { + cpuRegs.LO.UD[1] = cpuRegs.GPR.r[_Rs_].UD[0]; + } + + void MULT1() { + s64 temp = (s64)cpuRegs.GPR.r[_Rs_].SL[0] * (s64)cpuRegs.GPR.r[_Rt_].SL[0]; + + cpuRegs.LO.UD[1] = (s64)(s32)(temp & 0xffffffff); + cpuRegs.HI.UD[1] = (s64)(s32)(temp >> 32); + + /* Modified a bit . asadr */ + if (_Rd_) cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[1]; + } + + void MULTU1() { + u64 tempu = (u64)cpuRegs.GPR.r[_Rs_].UL[0] * (u64)cpuRegs.GPR.r[_Rt_].UL[0]; + + cpuRegs.LO.UD[1] = (s32)(tempu & 0xffffffff); + cpuRegs.HI.UD[1] = (s32)(tempu >> 32); + + if (_Rd_) cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[1]; + } + + void DIV1() { + if (cpuRegs.GPR.r[_Rt_].SL[0] != 0) { + cpuRegs.LO.SD[1] = cpuRegs.GPR.r[_Rs_].SL[0] / cpuRegs.GPR.r[_Rt_].SL[0]; + cpuRegs.HI.SD[1] = cpuRegs.GPR.r[_Rs_].SL[0] % cpuRegs.GPR.r[_Rt_].SL[0]; + } + } + + void DIVU1() { + if (cpuRegs.GPR.r[_Rt_].UL[0] != 0) { + cpuRegs.LO.UD[1] = cpuRegs.GPR.r[_Rs_].UL[0] / cpuRegs.GPR.r[_Rt_].UL[0]; + cpuRegs.HI.UD[1] = cpuRegs.GPR.r[_Rs_].UL[0] % cpuRegs.GPR.r[_Rt_].UL[0]; + } + } + +namespace MMI { + +//*****************MMI OPCODES********************************* + +__forceinline void _PLZCW(int n) +{ + // This function counts the number of "like" bits in the source register, starting + // with the MSB and working its way down, and returns the result MINUS ONE. + // So 0xff00 would return 7, not 8. + + int c = 0; + s32 i = cpuRegs.GPR.r[_Rs_].SL[n]; + + // Negate the source based on the sign bit. This allows us to use a simple + // unified bit test of the MSB for either condition. + if( i >= 0 ) i = ~i; + + // shift first, compare, then increment. This excludes the sign bit from our final count. + while( i <<= 1, i < 0 ) c++; + + cpuRegs.GPR.r[_Rd_].UL[n] = c; +} + +void PLZCW() { + if (!_Rd_) return; + + _PLZCW (0); + _PLZCW (1); +} + +#define PMFHL_CLAMP(dst, src) \ + if ((int)src > (int)0x00007fff) dst = 0x7fff; \ + else \ + if ((int)src < (int)0xffff8000) dst = 0x8000; \ + else dst = (u16)src; + +void PMFHL() { + if (!_Rd_) return; + + switch (_Sa_) { + case 0x00: // LW + cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[2]; + break; + + case 0x01: // UW + cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[1]; + cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[1]; + cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[3]; + cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[3]; + break; + + case 0x02: // SLW + { + u64 TempU64 = ((u64)cpuRegs.HI.UL[0] << 32) | (u64)cpuRegs.LO.UL[0]; + if (TempU64 >= 0x000000007fffffffLL) { + cpuRegs.GPR.r[_Rd_].UD[0] = 0x000000007fffffffLL; + } else if (TempU64 <= 0xffffffff80000000LL) { + cpuRegs.GPR.r[_Rd_].UD[0] = 0xffffffff80000000LL; + } else { + cpuRegs.GPR.r[_Rd_].UD[0] = (s64)cpuRegs.LO.SL[0]; + } + + TempU64 = ((u64)cpuRegs.HI.UL[2] << 32) | (u64)cpuRegs.LO.UL[2]; + if (TempU64 >= 0x000000007fffffffLL) { + cpuRegs.GPR.r[_Rd_].UD[1] = 0x000000007fffffffLL; + } else if (TempU64 <= 0xffffffff80000000LL) { + cpuRegs.GPR.r[_Rd_].UD[1] = 0xffffffff80000000LL; + } else { + cpuRegs.GPR.r[_Rd_].UD[1] = (s64)cpuRegs.LO.SL[2]; + } + } + break; + + case 0x03: // LH + cpuRegs.GPR.r[_Rd_].US[0] = cpuRegs.LO.US[0]; + cpuRegs.GPR.r[_Rd_].US[1] = cpuRegs.LO.US[2]; + cpuRegs.GPR.r[_Rd_].US[2] = cpuRegs.HI.US[0]; + cpuRegs.GPR.r[_Rd_].US[3] = cpuRegs.HI.US[2]; + cpuRegs.GPR.r[_Rd_].US[4] = cpuRegs.LO.US[4]; + cpuRegs.GPR.r[_Rd_].US[5] = cpuRegs.LO.US[6]; + cpuRegs.GPR.r[_Rd_].US[6] = cpuRegs.HI.US[4]; + cpuRegs.GPR.r[_Rd_].US[7] = cpuRegs.HI.US[6]; + break; + + case 0x04: // SH + PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[0], cpuRegs.LO.UL[0]); + PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[1], cpuRegs.LO.UL[1]); + PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[2], cpuRegs.HI.UL[0]); + PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[3], cpuRegs.HI.UL[1]); + PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[4], cpuRegs.LO.UL[2]); + PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[5], cpuRegs.LO.UL[3]); + PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[6], cpuRegs.HI.UL[2]); + PMFHL_CLAMP(cpuRegs.GPR.r[_Rd_].US[7], cpuRegs.HI.UL[3]); + break; + } +} + +void PMTHL() { + if (_Sa_ != 0) return; + + cpuRegs.LO.UL[0] = cpuRegs.GPR.r[_Rs_].UL[0]; + cpuRegs.HI.UL[0] = cpuRegs.GPR.r[_Rs_].UL[1]; + cpuRegs.LO.UL[2] = cpuRegs.GPR.r[_Rs_].UL[2]; + cpuRegs.HI.UL[2] = cpuRegs.GPR.r[_Rs_].UL[3]; +} + +__forceinline void _PSLLH(int n) +{ + cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rt_].US[n] << ( _Sa_ & 0xf ); +} + +void PSLLH() { + if (!_Rd_) return; + + _PSLLH(0); _PSLLH(1); _PSLLH(2); _PSLLH(3); + _PSLLH(4); _PSLLH(5); _PSLLH(6); _PSLLH(7); +} + +__forceinline void _PSRLH(int n) +{ + cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rt_].US[n] >> ( _Sa_ & 0xf ); +} + +void PSRLH () { + if (!_Rd_) return; + + _PSRLH(0); _PSRLH(1); _PSRLH(2); _PSRLH(3); + _PSRLH(4); _PSRLH(5); _PSRLH(6); _PSRLH(7); +} + +__forceinline void _PSRAH(int n) +{ + cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rt_].SS[n] >> ( _Sa_ & 0xf ); +} + +void PSRAH() { + if (!_Rd_) return; + + _PSRAH(0); _PSRAH(1); _PSRAH(2); _PSRAH(3); + _PSRAH(4); _PSRAH(5); _PSRAH(6); _PSRAH(7); +} + +__forceinline void _PSLLW(int n) +{ + cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rt_].UL[n] << _Sa_; +} + +void PSLLW() { + if (!_Rd_) return; + + _PSLLW(0); _PSLLW(1); _PSLLW(2); _PSLLW(3); +} + +__forceinline void _PSRLW(int n) +{ + cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rt_].UL[n] >> _Sa_; +} + +void PSRLW() { + if (!_Rd_) return; + + _PSRLW(0); _PSRLW(1); _PSRLW(2); _PSRLW(3); +} + +__forceinline void _PSRAW(int n) +{ + cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rt_].SL[n] >> _Sa_; +} + +void PSRAW() { + if (!_Rd_) return; + + _PSRAW(0); _PSRAW(1); _PSRAW(2); _PSRAW(3); +} + +//*****************END OF MMI OPCODES************************** +//*************************MMI0 OPCODES************************ + +__forceinline void _PADDW(int n) +{ + cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rs_].UL[n] + cpuRegs.GPR.r[_Rt_].UL[n]; +} + +void PADDW() { + if (!_Rd_) return; + + _PADDW(0); _PADDW(1); _PADDW(2); _PADDW(3); +} + +__forceinline void _PSUBW(int n) +{ + cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rs_].UL[n] - cpuRegs.GPR.r[_Rt_].UL[n]; +} + +void PSUBW() { + if (!_Rd_) return; + + _PSUBW(0); _PSUBW(1); _PSUBW(2); _PSUBW(3); +} + +__forceinline void _PCGTW(int n) +{ + if (cpuRegs.GPR.r[_Rs_].SL[n] > cpuRegs.GPR.r[_Rt_].SL[n]) + cpuRegs.GPR.r[_Rd_].UL[n] = 0xFFFFFFFF; + else + cpuRegs.GPR.r[_Rd_].UL[n] = 0x00000000; +} + +void PCGTW() { + if (!_Rd_) return; + + _PCGTW(0); _PCGTW(1); _PCGTW(2); _PCGTW(3); +} + +__forceinline void _PMAXW(int n) +{ + if (cpuRegs.GPR.r[_Rs_].SL[n] > cpuRegs.GPR.r[_Rt_].SL[n]) + cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rs_].UL[n]; + else + cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rt_].UL[n]; +} + +void PMAXW() { + if (!_Rd_) return; + + _PMAXW(0); _PMAXW(1); _PMAXW(2); _PMAXW(3); +} + +__forceinline void _PADDH(int n) +{ + cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rs_].US[n] + cpuRegs.GPR.r[_Rt_].US[n]; +} + +void PADDH() { + if (!_Rd_) return; + + _PADDH(0); _PADDH(1); _PADDH(2); _PADDH(3); + _PADDH(4); _PADDH(5); _PADDH(6); _PADDH(7); +} + +__forceinline void _PSUBH(int n) +{ + cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rs_].US[n] - cpuRegs.GPR.r[_Rt_].US[n]; +} + +void PSUBH() { + if (!_Rd_) return; + + _PSUBH(0); _PSUBH(1); _PSUBH(2); _PSUBH(3); + _PSUBH(4); _PSUBH(5); _PSUBH(6); _PSUBH(7); +} + +__forceinline void _PCGTH(int n) +{ + if (cpuRegs.GPR.r[_Rs_].SS[n] > cpuRegs.GPR.r[_Rt_].SS[n]) + cpuRegs.GPR.r[_Rd_].US[n] = 0xFFFF; + else + cpuRegs.GPR.r[_Rd_].US[n] = 0x0000; +} + +void PCGTH() { + if (!_Rd_) return; + + _PCGTH(0); _PCGTH(1); _PCGTH(2); _PCGTH(3); + _PCGTH(4); _PCGTH(5); _PCGTH(6); _PCGTH(7); +} + +__forceinline void _PMAXH(int n) +{ + if (cpuRegs.GPR.r[_Rs_].SS[n] > cpuRegs.GPR.r[_Rt_].SS[n]) + cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rs_].US[n]; + else + cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rt_].US[n]; +} + +void PMAXH() { + if (!_Rd_) return; + + _PMAXH(0); _PMAXH(1); _PMAXH(2); _PMAXH(3); + _PMAXH(4); _PMAXH(5); _PMAXH(6); _PMAXH(7); +} + +__forceinline void _PADDB(int n) +{ + cpuRegs.GPR.r[_Rd_].SC[n] = cpuRegs.GPR.r[_Rs_].SC[n] + cpuRegs.GPR.r[_Rt_].SC[n]; +} + +void PADDB() { + int i; + if (!_Rd_) return; + + for( i=0; i<16; i++ ) + _PADDB( i ); +} + +__forceinline void _PSUBB(int n) +{ + cpuRegs.GPR.r[_Rd_].SC[n] = cpuRegs.GPR.r[_Rs_].SC[n] - cpuRegs.GPR.r[_Rt_].SC[n]; +} + +void PSUBB() { + int i; + if (!_Rd_) return; + + for( i=0; i<16; i++ ) + _PSUBB( i ); +} + +__forceinline void _PCGTB(int n) +{ + if (cpuRegs.GPR.r[_Rs_].SC[n] > cpuRegs.GPR.r[_Rt_].SC[n]) + cpuRegs.GPR.r[_Rd_].UC[n] = 0xFF; + else + cpuRegs.GPR.r[_Rd_].UC[n] = 0x00; +} + +void PCGTB() { + int i; + if (!_Rd_) return; + + for( i=0; i<16; i++ ) + _PCGTB( i ); +} + +__forceinline void _PADDSW(int n) +{ + s64 sTemp64; + + sTemp64 = (s64)cpuRegs.GPR.r[_Rs_].SL[n] + (s64)cpuRegs.GPR.r[_Rt_].SL[n]; + if (sTemp64 > 0x7FFFFFFF) + cpuRegs.GPR.r[_Rd_].UL[n] = 0x7FFFFFFF; + else if ((sTemp64 < (s32)0x80000000) ) + cpuRegs.GPR.r[_Rd_].UL[n] = 0x80000000LL; + else + cpuRegs.GPR.r[_Rd_].UL[n] = (s32)sTemp64; +} + +void PADDSW() { + if (!_Rd_) return; + + _PADDSW(0); _PADDSW(1); _PADDSW(2); _PADDSW(3); +} + +__forceinline void _PSUBSW(int n) +{ + s64 sTemp64; + + sTemp64 = (s64)cpuRegs.GPR.r[_Rs_].SL[n] - (s64)cpuRegs.GPR.r[_Rt_].SL[n]; + + if (sTemp64 >= 0x7FFFFFFF) + cpuRegs.GPR.r[_Rd_].UL[n] = 0x7FFFFFFF; + else if ((sTemp64 < (s32)0x80000000)) + cpuRegs.GPR.r[_Rd_].UL[n] = 0x80000000; + else + cpuRegs.GPR.r[_Rd_].UL[n] = (s32)sTemp64; +} + +void PSUBSW() { + if (!_Rd_) return; + + _PSUBSW(0); + _PSUBSW(1); + _PSUBSW(2); + _PSUBSW(3); +} + +void PEXTLW() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].UL[0] = Rt.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[1] = Rs.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[2] = Rt.UL[1]; + cpuRegs.GPR.r[_Rd_].UL[3] = Rs.UL[1]; +} + +void PPACW() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].UL[0] = Rt.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[1] = Rt.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[2] = Rs.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[3] = Rs.UL[2]; +} + +__forceinline void _PADDSH(int n) +{ + s32 sTemp32; + sTemp32 = (s32)cpuRegs.GPR.r[_Rs_].SS[n] + (s32)cpuRegs.GPR.r[_Rt_].SS[n]; + + if (sTemp32 > 0x7FFF) + cpuRegs.GPR.r[_Rd_].US[n] = 0x7FFF; + else if ((sTemp32 < (s32)0xffff8000) ) + cpuRegs.GPR.r[_Rd_].US[n] = 0x8000; + else + cpuRegs.GPR.r[_Rd_].US[n] = (s16)sTemp32; +} + +void PADDSH() { + if (!_Rd_) return; + + _PADDSH(0); _PADDSH(1); _PADDSH(2); _PADDSH(3); + _PADDSH(4); _PADDSH(5); _PADDSH(6); _PADDSH(7); +} + +__forceinline void _PSUBSH(int n) +{ + s32 sTemp32; + sTemp32 = (s32)cpuRegs.GPR.r[_Rs_].SS[n] - (s32)cpuRegs.GPR.r[_Rt_].SS[n]; + + if (sTemp32 >= 0x7FFF) + cpuRegs.GPR.r[_Rd_].US[n] = 0x7FFF; + else if ((sTemp32 < (s32)0xffff8000) ) + cpuRegs.GPR.r[_Rd_].US[n] = 0x8000; + else + cpuRegs.GPR.r[_Rd_].US[n] = (s16)sTemp32; +} + +void PSUBSH() { + if (!_Rd_) return; + + _PSUBSH(0); _PSUBSH(1); _PSUBSH(2); _PSUBSH(3); + _PSUBSH(4); _PSUBSH(5); _PSUBSH(6); _PSUBSH(7); +} + +void PEXTLH() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[1] = Rs.US[0]; + cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[1]; + cpuRegs.GPR.r[_Rd_].US[3] = Rs.US[1]; + cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[2]; + cpuRegs.GPR.r[_Rd_].US[5] = Rs.US[2]; + cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[3]; + cpuRegs.GPR.r[_Rd_].US[7] = Rs.US[3]; +} + +void PPACH() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[1] = Rt.US[2]; + cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[4]; + cpuRegs.GPR.r[_Rd_].US[3] = Rt.US[6]; + cpuRegs.GPR.r[_Rd_].US[4] = Rs.US[0]; + cpuRegs.GPR.r[_Rd_].US[5] = Rs.US[2]; + cpuRegs.GPR.r[_Rd_].US[6] = Rs.US[4]; + cpuRegs.GPR.r[_Rd_].US[7] = Rs.US[6]; +} + +__forceinline void _PADDSB(int n) +{ + s16 sTemp16; + sTemp16 = (s16)cpuRegs.GPR.r[_Rs_].SC[n] + (s16)cpuRegs.GPR.r[_Rt_].SC[n]; + + if (sTemp16 > 0x7F) + cpuRegs.GPR.r[_Rd_].UC[n] = 0x7F; + else if ((sTemp16 < 0x180) && (sTemp16 >= 0x100)) + cpuRegs.GPR.r[_Rd_].UC[n] = 0x80; + else + cpuRegs.GPR.r[_Rd_].UC[n] = (s8)sTemp16; +} + +void PADDSB() { + int i; + if (!_Rd_) return; + + for( i=0; i<16; i++ ) + _PADDSB(i); +} + +static __forceinline void _PSUBSB( u8 n ) +{ + s16 sTemp16; + sTemp16 = (s16)cpuRegs.GPR.r[_Rs_].SC[n] - (s16)cpuRegs.GPR.r[_Rt_].SC[n]; + + if (sTemp16 >= 0x7F) + cpuRegs.GPR.r[_Rd_].UC[n] = 0x7F; + else if ((sTemp16 < 0x180) && (sTemp16 >= 0x100)) + cpuRegs.GPR.r[_Rd_].UC[n] = 0x80; + else + cpuRegs.GPR.r[_Rd_].UC[n] = (s8)sTemp16; +} + +void PSUBSB() { + int i; + if (!_Rd_) return; + + for( i=0; i<16; i++ ) + _PSUBSB(i); +} + +void PEXTLB() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].UC[0] = Rt.UC[0]; + cpuRegs.GPR.r[_Rd_].UC[1] = Rs.UC[0]; + cpuRegs.GPR.r[_Rd_].UC[2] = Rt.UC[1]; + cpuRegs.GPR.r[_Rd_].UC[3] = Rs.UC[1]; + + cpuRegs.GPR.r[_Rd_].UC[4] = Rt.UC[2]; + cpuRegs.GPR.r[_Rd_].UC[5] = Rs.UC[2]; + cpuRegs.GPR.r[_Rd_].UC[6] = Rt.UC[3]; + cpuRegs.GPR.r[_Rd_].UC[7] = Rs.UC[3]; + + cpuRegs.GPR.r[_Rd_].UC[8] = Rt.UC[4]; + cpuRegs.GPR.r[_Rd_].UC[9] = Rs.UC[4]; + cpuRegs.GPR.r[_Rd_].UC[10] = Rt.UC[5]; + cpuRegs.GPR.r[_Rd_].UC[11] = Rs.UC[5]; + + cpuRegs.GPR.r[_Rd_].UC[12] = Rt.UC[6]; + cpuRegs.GPR.r[_Rd_].UC[13] = Rs.UC[6]; + cpuRegs.GPR.r[_Rd_].UC[14] = Rt.UC[7]; + cpuRegs.GPR.r[_Rd_].UC[15] = Rs.UC[7]; +} + +void PPACB() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].UC[0] = Rt.UC[0]; + cpuRegs.GPR.r[_Rd_].UC[1] = Rt.UC[2]; + cpuRegs.GPR.r[_Rd_].UC[2] = Rt.UC[4]; + cpuRegs.GPR.r[_Rd_].UC[3] = Rt.UC[6]; + + cpuRegs.GPR.r[_Rd_].UC[4] = Rt.UC[8]; + cpuRegs.GPR.r[_Rd_].UC[5] = Rt.UC[10]; + cpuRegs.GPR.r[_Rd_].UC[6] = Rt.UC[12]; + cpuRegs.GPR.r[_Rd_].UC[7] = Rt.UC[14]; + + cpuRegs.GPR.r[_Rd_].UC[8] = Rs.UC[0]; + cpuRegs.GPR.r[_Rd_].UC[9] = Rs.UC[2]; + cpuRegs.GPR.r[_Rd_].UC[10] = Rs.UC[4]; + cpuRegs.GPR.r[_Rd_].UC[11] = Rs.UC[6]; + + cpuRegs.GPR.r[_Rd_].UC[12] = Rs.UC[8]; + cpuRegs.GPR.r[_Rd_].UC[13] = Rs.UC[10]; + cpuRegs.GPR.r[_Rd_].UC[14] = Rs.UC[12]; + cpuRegs.GPR.r[_Rd_].UC[15] = Rs.UC[14]; +} + +__forceinline void _PEXT5(int n) +{ + cpuRegs.GPR.r[_Rd_].UL[n] = \ + ((cpuRegs.GPR.r[_Rt_].UL[n] & 0x0000001F) << 3) | \ + ((cpuRegs.GPR.r[_Rt_].UL[n] & 0x000003E0) << 6) | \ + ((cpuRegs.GPR.r[_Rt_].UL[n] & 0x00007C00) << 9) | \ + ((cpuRegs.GPR.r[_Rt_].UL[n] & 0x00008000) << 16); +} + +void PEXT5() { + if (!_Rd_) return; + + _PEXT5(0); _PEXT5(1); _PEXT5(2); _PEXT5(3); +} + +__forceinline void _PPAC5(int n) +{ + cpuRegs.GPR.r[_Rd_].UL[n] = \ + ((cpuRegs.GPR.r[_Rt_].UL[n] >> 3) & 0x0000001F) | \ + ((cpuRegs.GPR.r[_Rt_].UL[n] >> 6) & 0x000003E0) | \ + ((cpuRegs.GPR.r[_Rt_].UL[n] >> 9) & 0x00007C00) | \ + ((cpuRegs.GPR.r[_Rt_].UL[n] >> 16) & 0x00008000); +} + +void PPAC5() { + if (!_Rd_) return; + + _PPAC5(0); _PPAC5(1); _PPAC5(2); _PPAC5(3); +} + +//***END OF MMI0 OPCODES****************************************** +//**********MMI1 OPCODES************************************** + +__forceinline void _PABSW(int n) +{ + cpuRegs.GPR.r[_Rd_].UL[n] = abs(cpuRegs.GPR.r[_Rt_].SL[n]); +} + +void PABSW() { + if (!_Rd_) return; + + _PABSW(0); _PABSW(1); _PABSW(2); _PABSW(3); +} + +__forceinline void _PCEQW(int n) +{ + if (cpuRegs.GPR.r[_Rs_].UL[n] == cpuRegs.GPR.r[_Rt_].UL[n]) + cpuRegs.GPR.r[_Rd_].UL[n] = 0xFFFFFFFF; + else + cpuRegs.GPR.r[_Rd_].UL[n] = 0x00000000; +} + +void PCEQW() { + if (!_Rd_) return; + + _PCEQW(0); _PCEQW(1); _PCEQW(2); _PCEQW(3); +} + +static __forceinline void _PMINW( u8 n ) +{ + if (cpuRegs.GPR.r[_Rs_].SL[n] < cpuRegs.GPR.r[_Rt_].SL[n]) + cpuRegs.GPR.r[_Rd_].SL[n] = cpuRegs.GPR.r[_Rs_].SL[n]; + else + cpuRegs.GPR.r[_Rd_].SL[n] = cpuRegs.GPR.r[_Rt_].SL[n]; +} + +void PMINW() { + if (!_Rd_) return; + + _PMINW(0); _PMINW(1); _PMINW(2); _PMINW(3); +} + +void PADSBH() { + if (!_Rd_) return; + + _PSUBH(0); _PSUBH(1); _PSUBH(2); _PSUBH(3); + _PADDH(4); _PADDH(5); _PADDH(6); _PADDH(7); +} + +__forceinline void _PABSH(int n) +{ + cpuRegs.GPR.r[_Rd_].US[n] = abs(cpuRegs.GPR.r[_Rt_].SS[n]); +} + +void PABSH() { + if (!_Rd_) return; + + _PABSH(0); _PABSH(1); _PABSH(2); _PABSH(3); + _PABSH(4); _PABSH(5); _PABSH(6); _PABSH(7); +} + +static __forceinline void _PCEQH( u8 n ) +{ + if (cpuRegs.GPR.r[_Rs_].US[n] == cpuRegs.GPR.r[_Rt_].US[n]) + cpuRegs.GPR.r[_Rd_].US[n] = 0xFFFF; + else + cpuRegs.GPR.r[_Rd_].US[n] = 0x0000; +} + +void PCEQH() { + if (!_Rd_) return; + + _PCEQH(0); _PCEQH(1); _PCEQH(2); _PCEQH(3); + _PCEQH(4); _PCEQH(5); _PCEQH(6); _PCEQH(7); +} + +static __forceinline void _PMINH( u8 n ) +{ + if (cpuRegs.GPR.r[_Rs_].SS[n] < cpuRegs.GPR.r[_Rt_].SS[n]) + cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rs_].US[n]; + else + cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rt_].US[n]; +} + +void PMINH() { + if (!_Rd_) return; + + _PMINH(0); _PMINH(1); _PMINH(2); _PMINH(3); + _PMINH(4); _PMINH(5); _PMINH(6); _PMINH(7); +} + +__forceinline void _PCEQB(int n) +{ + if (cpuRegs.GPR.r[_Rs_].UC[n] == cpuRegs.GPR.r[_Rt_].UC[n]) + cpuRegs.GPR.r[_Rd_].UC[n] = 0xFF; + else + cpuRegs.GPR.r[_Rd_].UC[n] = 0x00; +} + +void PCEQB() { + int i; + if (!_Rd_) return; + + for( i=0; i<16; i++ ) + _PCEQB(i); +} + +__forceinline void _PADDUW(int n) +{ + s64 tmp; + tmp = (s64)cpuRegs.GPR.r[_Rs_].UL[n] + (s64)cpuRegs.GPR.r[_Rt_].UL[n]; + + if (tmp > 0xffffffff) + cpuRegs.GPR.r[_Rd_].UL[n] = 0xffffffff; + else + cpuRegs.GPR.r[_Rd_].UL[n] = (u32)tmp; +} + +void PADDUW () { + if (!_Rd_) return; + + _PADDUW(0); _PADDUW(1); _PADDUW(2); _PADDUW(3); +} + +__forceinline void _PSUBUW(int n) +{ + s64 sTemp64; + sTemp64 = (s64)cpuRegs.GPR.r[_Rs_].UL[n] - (s64)cpuRegs.GPR.r[_Rt_].UL[n]; + + if (sTemp64 <= 0x0) + cpuRegs.GPR.r[_Rd_].UL[n] = 0x0; + else + cpuRegs.GPR.r[_Rd_].UL[n] = (u32)sTemp64; +} + +void PSUBUW() { + if (!_Rd_) return; + + _PSUBUW(0); _PSUBUW(1); _PSUBUW(2); _PSUBUW(3); +} + +void PEXTUW() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].UL[0] = Rt.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[1] = Rs.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[2] = Rt.UL[3]; + cpuRegs.GPR.r[_Rd_].UL[3] = Rs.UL[3]; +} + +__forceinline void _PADDUH(int n) +{ + s32 sTemp32; + sTemp32 = (s32)cpuRegs.GPR.r[_Rs_].US[n] + (s32)cpuRegs.GPR.r[_Rt_].US[n]; + + if (sTemp32 > 0xFFFF) + cpuRegs.GPR.r[_Rd_].US[n] = 0xFFFF; + else + cpuRegs.GPR.r[_Rd_].US[n] = (u16)sTemp32; +} + +void PADDUH() { + if (!_Rd_) return; + + _PADDUH(0); _PADDUH(1); _PADDUH(2); _PADDUH(3); + _PADDUH(4); _PADDUH(5); _PADDUH(6); _PADDUH(7); +} + +__forceinline void _PSUBUH(int n) +{ + s32 sTemp32; + sTemp32 = (s32)cpuRegs.GPR.r[_Rs_].US[n] - (s32)cpuRegs.GPR.r[_Rt_].US[n]; + + if (sTemp32 <= 0x0) + cpuRegs.GPR.r[_Rd_].US[n] = 0x0; + else + cpuRegs.GPR.r[_Rd_].US[n] = (u16)sTemp32; +} + +void PSUBUH() { + if (!_Rd_) return; + + _PSUBUH(0); _PSUBUH(1); _PSUBUH(2); _PSUBUH(3); + _PSUBUH(4); _PSUBUH(5); _PSUBUH(6); _PSUBUH(7); +} + +void PEXTUH() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[4]; + cpuRegs.GPR.r[_Rd_].US[1] = Rs.US[4]; + cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[5]; + cpuRegs.GPR.r[_Rd_].US[3] = Rs.US[5]; + + cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[6]; + cpuRegs.GPR.r[_Rd_].US[5] = Rs.US[6]; + cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[7]; + cpuRegs.GPR.r[_Rd_].US[7] = Rs.US[7]; +} + +__forceinline void _PADDUB(int n) +{ + u16 Temp16; + Temp16 = (u16)cpuRegs.GPR.r[_Rs_].UC[n] + (u16)cpuRegs.GPR.r[_Rt_].UC[n]; + + if (Temp16 > 0xFF) + cpuRegs.GPR.r[_Rd_].UC[n] = 0xFF; + else + cpuRegs.GPR.r[_Rd_].UC[n] = (u8)Temp16; +} + +void PADDUB() { + int i; + if (!_Rd_) return; + + for( i=0; i<16; i++ ) + _PADDUB(i); +} + +__forceinline void _PSUBUB(int n) { + s16 sTemp16; + sTemp16 = (s16)cpuRegs.GPR.r[_Rs_].UC[n] - (s16)cpuRegs.GPR.r[_Rt_].UC[n]; + + if (sTemp16 <= 0x0) + cpuRegs.GPR.r[_Rd_].UC[n] = 0x0; + else + cpuRegs.GPR.r[_Rd_].UC[n] = (u8)sTemp16; +} + +void PSUBUB() { + int i; + if (!_Rd_) return; + + for( i=0; i<16; i++ ) + _PSUBUB(i); +} + +void PEXTUB() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].UC[0] = Rt.UC[8]; + cpuRegs.GPR.r[_Rd_].UC[1] = Rs.UC[8]; + cpuRegs.GPR.r[_Rd_].UC[2] = Rt.UC[9]; + cpuRegs.GPR.r[_Rd_].UC[3] = Rs.UC[9]; + cpuRegs.GPR.r[_Rd_].UC[4] = Rt.UC[10]; + cpuRegs.GPR.r[_Rd_].UC[5] = Rs.UC[10]; + cpuRegs.GPR.r[_Rd_].UC[6] = Rt.UC[11]; + cpuRegs.GPR.r[_Rd_].UC[7] = Rs.UC[11]; + cpuRegs.GPR.r[_Rd_].UC[8] = Rt.UC[12]; + cpuRegs.GPR.r[_Rd_].UC[9] = Rs.UC[12]; + cpuRegs.GPR.r[_Rd_].UC[10] = Rt.UC[13]; + cpuRegs.GPR.r[_Rd_].UC[11] = Rs.UC[13]; + cpuRegs.GPR.r[_Rd_].UC[12] = Rt.UC[14]; + cpuRegs.GPR.r[_Rd_].UC[13] = Rs.UC[14]; + cpuRegs.GPR.r[_Rd_].UC[14] = Rt.UC[15]; + cpuRegs.GPR.r[_Rd_].UC[15] = Rs.UC[15]; +} + +//int saZero = 0; +void QFSRV() { // JayteeMaster: changed a bit to avoid screw up + GPR_reg Rd; + if (!_Rd_) return; + + if (cpuRegs.sa == 0) { + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0]; + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rt_].UD[1]; + //saZero++; + //if( saZero >= 388800 ) + //Console::WriteLn( "SA Is Zero, Bitch: %d zeros and counting.", params saZero ); + } else { + //Console::WriteLn( "SA Properly Valued at: %d (after %d zeros)", params cpuRegs.sa, saZero ); + //saZero = 0; + if (cpuRegs.sa < 64) { + /* + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0] >> cpuRegs.sa; + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rt_].UD[1] >> cpuRegs.sa; + cpuRegs.GPR.r[_Rd_].UD[0]|= cpuRegs.GPR.r[_Rt_].UD[1] << (64 - cpuRegs.sa); + cpuRegs.GPR.r[_Rd_].UD[1]|= cpuRegs.GPR.r[_Rs_].UD[0] << (64 - cpuRegs.sa); + */ + Rd.UD[0] = cpuRegs.GPR.r[_Rt_].UD[0] >> cpuRegs.sa; + Rd.UD[1] = cpuRegs.GPR.r[_Rt_].UD[1] >> cpuRegs.sa; + Rd.UD[0]|= cpuRegs.GPR.r[_Rt_].UD[1] << (64 - cpuRegs.sa); + Rd.UD[1]|= cpuRegs.GPR.r[_Rs_].UD[0] << (64 - cpuRegs.sa); + cpuRegs.GPR.r[_Rd_] = Rd; + } else { + /* + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[1] >> (cpuRegs.sa - 64); + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rs_].UD[0] >> (cpuRegs.sa - 64); + cpuRegs.GPR.r[_Rd_].UD[0]|= cpuRegs.GPR.r[_Rs_].UD[0] << (128 - cpuRegs.sa); + cpuRegs.GPR.r[_Rd_].UD[1]|= cpuRegs.GPR.r[_Rs_].UD[1] << (128 - cpuRegs.sa); + */ + Rd.UD[0] = cpuRegs.GPR.r[_Rt_].UD[1] >> (cpuRegs.sa - 64); + Rd.UD[1] = cpuRegs.GPR.r[_Rs_].UD[0] >> (cpuRegs.sa - 64); + Rd.UD[0]|= cpuRegs.GPR.r[_Rs_].UD[0] << (128 - cpuRegs.sa); + Rd.UD[1]|= cpuRegs.GPR.r[_Rs_].UD[1] << (128 - cpuRegs.sa); + cpuRegs.GPR.r[_Rd_] = Rd; + } + } +} + +//********END OF MMI1 OPCODES*********************************** + +//*********MMI2 OPCODES*************************************** + +__forceinline void _PMADDW(int dd, int ss) +{ + s64 temp = (s64)((s64)cpuRegs.LO.SL[ss] | ((s64)cpuRegs.HI.SL[ss] << 32)) + + ((s64)cpuRegs.GPR.r[_Rs_].SL[ss] * (s64)cpuRegs.GPR.r[_Rt_].SL[ss]); + + cpuRegs.LO.SD[dd] = (s32)(temp & 0xffffffff); + cpuRegs.HI.SD[dd] = (s32)(temp >> 32); + + if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[dd] = temp; +} + +void PMADDW() { + _PMADDW(0, 0); + _PMADDW(1, 2); +} + +void PSLLVW() { + if (!_Rd_) return; + + cpuRegs.GPR.r[_Rd_].UD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] << + (cpuRegs.GPR.r[_Rs_].UL[0] & 0x1F)); + cpuRegs.GPR.r[_Rd_].UD[1] = (s32)(cpuRegs.GPR.r[_Rt_].UL[2] << + (cpuRegs.GPR.r[_Rs_].UL[2] & 0x1F)); +} + +void PSRLVW() { + if (!_Rd_) return; + + cpuRegs.GPR.r[_Rd_].UD[0] = (cpuRegs.GPR.r[_Rt_].UL[0] >> + (cpuRegs.GPR.r[_Rs_].UL[0] & 0x1F)); + cpuRegs.GPR.r[_Rd_].UD[1] = (cpuRegs.GPR.r[_Rt_].UL[2] >> + (cpuRegs.GPR.r[_Rs_].UL[2] & 0x1F)); +} + +__forceinline void _PMSUBW(int dd, int ss) +{ + s64 temp = (s64)((s64)cpuRegs.LO.SL[ss] | ((s64)cpuRegs.HI.SL[ss] << 32)) - + ((s64)cpuRegs.GPR.r[_Rs_].SL[ss] * (s64)cpuRegs.GPR.r[_Rt_].SL[ss]); + + cpuRegs.LO.SD[dd] = (s32)(temp & 0xffffffff); + cpuRegs.HI.SD[dd] = (s32)(temp >> 32); + + if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[dd] = temp; +} + +void PMSUBW() { + _PMSUBW(0, 0); + _PMSUBW(1, 2); +} + +void PMFHI() { + if (!_Rd_) return; + + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.HI.UD[0]; + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.HI.UD[1]; +} + +void PMFLO() { + if (!_Rd_) return; + + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[0]; + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.LO.UD[1]; +} + +void PINTH() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[1] = Rs.US[4]; + cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[1]; + cpuRegs.GPR.r[_Rd_].US[3] = Rs.US[5]; + cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[2]; + cpuRegs.GPR.r[_Rd_].US[5] = Rs.US[6]; + cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[3]; + cpuRegs.GPR.r[_Rd_].US[7] = Rs.US[7]; +} + +__forceinline void _PMULTW(int dd, int ss) +{ + s64 temp = (s64)cpuRegs.GPR.r[_Rs_].SL[ss] * (s64)cpuRegs.GPR.r[_Rt_].SL[ss]; + + cpuRegs.LO.UD[dd] = (s32)(temp & 0xffffffff); + cpuRegs.HI.UD[dd] = (s32)(temp >> 32); + + if (_Rd_) cpuRegs.GPR.r[_Rd_].SD[dd] = temp; +} + +void PMULTW() { + _PMULTW(0, 0); + _PMULTW(1, 2); +} + +__forceinline void _PDIVW(int dd, int ss) +{ + if (cpuRegs.GPR.r[_Rt_].UL[ss] != 0) + { + cpuRegs.LO.SD[dd] = cpuRegs.GPR.r[_Rs_].SL[ss] / cpuRegs.GPR.r[_Rt_].SL[ss]; + cpuRegs.HI.SD[dd] = cpuRegs.GPR.r[_Rs_].SL[ss] % cpuRegs.GPR.r[_Rt_].SL[ss]; + } +} + +void PDIVW() { + _PDIVW(0, 0); + _PDIVW(1, 2); +} + +void PCPYLD() { + if (!_Rd_) return; + + // note: first _Rs_, since the other way when _Rd_ equals + // _Rs_ or _Rt_ this would screw up + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rs_].UD[0]; + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0]; +} + +void PMADDH() { // JayteeMaster: changed a bit to avoid screw up + s32 temp; + + temp = cpuRegs.LO.UL[0] + (s32)cpuRegs.GPR.r[_Rs_].SS[0] * (s32)cpuRegs.GPR.r[_Rt_].SS[0]; + cpuRegs.LO.UL[0] = temp; + /* if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[0] = temp; */ + + temp = cpuRegs.LO.UL[1] + (s32)cpuRegs.GPR.r[_Rs_].SS[1] * (s32)cpuRegs.GPR.r[_Rt_].SS[1]; + cpuRegs.LO.UL[1] = temp; + + temp = cpuRegs.HI.UL[0] + (s32)cpuRegs.GPR.r[_Rs_].SS[2] * (s32)cpuRegs.GPR.r[_Rt_].SS[2]; + cpuRegs.HI.UL[0] = temp; + /* if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[1] = temp; */ + + temp = cpuRegs.HI.UL[1] + (s32)cpuRegs.GPR.r[_Rs_].SS[3] * (s32)cpuRegs.GPR.r[_Rt_].SS[3]; + cpuRegs.HI.UL[1] = temp; + + temp = cpuRegs.LO.UL[2] + (s32)cpuRegs.GPR.r[_Rs_].SS[4] * (s32)cpuRegs.GPR.r[_Rt_].SS[4]; + cpuRegs.LO.UL[2] = temp; + /* if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[2] = temp; */ + + temp = cpuRegs.LO.UL[3] + (s32)cpuRegs.GPR.r[_Rs_].SS[5] * (s32)cpuRegs.GPR.r[_Rt_].SS[5]; + cpuRegs.LO.UL[3] = temp; + + temp = cpuRegs.HI.UL[2] + (s32)cpuRegs.GPR.r[_Rs_].SS[6] * (s32)cpuRegs.GPR.r[_Rt_].SS[6]; + cpuRegs.HI.UL[2] = temp; + /* if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[3] = temp; */ + + temp = cpuRegs.HI.UL[3] + (s32)cpuRegs.GPR.r[_Rs_].SS[7] * (s32)cpuRegs.GPR.r[_Rt_].SS[7]; + cpuRegs.HI.UL[3] = temp; + + if (_Rd_) { + cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[2]; + } + +} + +// JayteeMaster: changed a bit to avoid screw up +__forceinline void _PHMADH_LO(int dd, int n) +{ + s32 temp = (s32)cpuRegs.GPR.r[_Rs_].SS[n+1] * (s32)cpuRegs.GPR.r[_Rt_].SS[n+1] + \ + (s32)cpuRegs.GPR.r[_Rs_].SS[n] * (s32)cpuRegs.GPR.r[_Rt_].SS[n]; + + cpuRegs.LO.UL[dd] = temp; +} + +__forceinline void _PHMADH_HI(int dd, int n) +{ + s32 temp = (s32)cpuRegs.GPR.r[_Rs_].SS[n+1] * (s32)cpuRegs.GPR.r[_Rt_].SS[n+1] + \ + (s32)cpuRegs.GPR.r[_Rs_].SS[n] * (s32)cpuRegs.GPR.r[_Rt_].SS[n]; + + cpuRegs.HI.UL[dd] = temp; +} + +void PHMADH() { // JayteeMaster: changed a bit to avoid screw up. Also used 0,2,4,6 instead of 0,1,2,3 + _PHMADH_LO(0, 0); + _PHMADH_HI(0, 2); + _PHMADH_LO(2, 4); + _PHMADH_HI(2, 6); + if (_Rd_) { + cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[2]; + } +} + +void PAND() { + if (!_Rd_) return; + + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] & cpuRegs.GPR.r[_Rt_].UD[0]; + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rs_].UD[1] & cpuRegs.GPR.r[_Rt_].UD[1]; +} + +void PXOR() { + if (!_Rd_) return; + + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] ^ cpuRegs.GPR.r[_Rt_].UD[0]; + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rs_].UD[1] ^ cpuRegs.GPR.r[_Rt_].UD[1]; +} + +void PMSUBH() { // JayteeMaster: changed a bit to avoid screw up + s32 temp; + + temp = cpuRegs.LO.UL[0] - (s32)cpuRegs.GPR.r[_Rs_].SS[0] * (s32)cpuRegs.GPR.r[_Rt_].SS[0]; + cpuRegs.LO.UL[0] = temp; + /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[0] = temp;*/ + + temp = cpuRegs.LO.UL[1] - (s32)cpuRegs.GPR.r[_Rs_].SS[1] * (s32)cpuRegs.GPR.r[_Rt_].SS[1]; + cpuRegs.LO.UL[1] = temp; + + temp = cpuRegs.HI.UL[0] - (s32)cpuRegs.GPR.r[_Rs_].SS[2] * (s32)cpuRegs.GPR.r[_Rt_].SS[2]; + cpuRegs.HI.UL[0] = temp; + /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[1] = temp;*/ + + temp = cpuRegs.HI.UL[1] - (s32)cpuRegs.GPR.r[_Rs_].SS[3] * (s32)cpuRegs.GPR.r[_Rt_].SS[3]; + cpuRegs.HI.UL[1] = temp; + + temp = cpuRegs.LO.UL[2] - (s32)cpuRegs.GPR.r[_Rs_].SS[4] * (s32)cpuRegs.GPR.r[_Rt_].SS[4]; + cpuRegs.LO.UL[2] = temp; + /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[2] = temp;*/ + + temp = cpuRegs.LO.UL[3] - (s32)cpuRegs.GPR.r[_Rs_].SS[5] * (s32)cpuRegs.GPR.r[_Rt_].SS[5]; + cpuRegs.LO.UL[3] = temp; + + temp = cpuRegs.HI.UL[2] - (s32)cpuRegs.GPR.r[_Rs_].SS[6] * (s32)cpuRegs.GPR.r[_Rt_].SS[6]; + cpuRegs.HI.UL[2] = temp; + /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[3] = temp;*/ + + temp = cpuRegs.HI.UL[3] - (s32)cpuRegs.GPR.r[_Rs_].SS[7] * (s32)cpuRegs.GPR.r[_Rt_].SS[7]; + cpuRegs.HI.UL[3] = temp; + + if (_Rd_) { + cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[2]; + } +} + +// JayteeMaster: changed a bit to avoid screw up +__forceinline void _PHMSBH_LO(int dd, int n, int rdd) +{ + s32 temp = (s32)cpuRegs.GPR.r[_Rs_].SS[n+1] * (s32)cpuRegs.GPR.r[_Rt_].SS[n+1] - \ + (s32)cpuRegs.GPR.r[_Rs_].SS[n] * (s32)cpuRegs.GPR.r[_Rt_].SS[n]; + + cpuRegs.LO.UL[dd] = temp; +} +__forceinline void _PHMSBH_HI(int dd, int n, int rdd) +{ + s32 temp = (s32)cpuRegs.GPR.r[_Rs_].SS[n+1] * (s32)cpuRegs.GPR.r[_Rt_].SS[n+1] - \ + (s32)cpuRegs.GPR.r[_Rs_].SS[n] * (s32)cpuRegs.GPR.r[_Rt_].SS[n]; + + cpuRegs.HI.UL[dd] = temp; +} + +void PHMSBH() { // JayteeMaster: changed a bit to avoid screw up + _PHMSBH_LO(0, 0, 0); + _PHMSBH_HI(0, 2, 1); + _PHMSBH_LO(2, 4, 2); + _PHMSBH_HI(2, 6, 3); + if (_Rd_) { + cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[2]; + } +} + +void PEXEH() { + GPR_reg Rt; + + if (!_Rd_) return; + + Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[2]; + cpuRegs.GPR.r[_Rd_].US[1] = Rt.US[1]; + cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[3] = Rt.US[3]; + cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[6]; + cpuRegs.GPR.r[_Rd_].US[5] = Rt.US[5]; + cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[4]; + cpuRegs.GPR.r[_Rd_].US[7] = Rt.US[7]; +} + +void PREVH () { + GPR_reg Rt; + + if (!_Rd_) return; + + Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[3]; + cpuRegs.GPR.r[_Rd_].US[1] = Rt.US[2]; + cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[1]; + cpuRegs.GPR.r[_Rd_].US[3] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[7]; + cpuRegs.GPR.r[_Rd_].US[5] = Rt.US[6]; + cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[5]; + cpuRegs.GPR.r[_Rd_].US[7] = Rt.US[4]; +} + +void PMULTH() { // JayteeMaster: changed a bit to avoid screw up + s32 temp; + + temp = (s32)cpuRegs.GPR.r[_Rs_].SS[0] * (s32)cpuRegs.GPR.r[_Rt_].SS[0]; + cpuRegs.LO.UL[0] = temp; + /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[0] = temp;*/ + + temp = (s32)cpuRegs.GPR.r[_Rs_].SS[1] * (s32)cpuRegs.GPR.r[_Rt_].SS[1]; + cpuRegs.LO.UL[1] = temp; + + temp = (s32)cpuRegs.GPR.r[_Rs_].SS[2] * (s32)cpuRegs.GPR.r[_Rt_].SS[2]; + cpuRegs.HI.UL[0] = temp; + /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[1] = temp;*/ + + temp = (s32)cpuRegs.GPR.r[_Rs_].SS[3] * (s32)cpuRegs.GPR.r[_Rt_].SS[3]; + cpuRegs.HI.UL[1] = temp; + + temp = (s32)cpuRegs.GPR.r[_Rs_].SS[4] * (s32)cpuRegs.GPR.r[_Rt_].SS[4]; + cpuRegs.LO.UL[2] = temp; + /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[2] = temp;*/ + + temp = (s32)cpuRegs.GPR.r[_Rs_].SS[5] * (s32)cpuRegs.GPR.r[_Rt_].SS[5]; + cpuRegs.LO.UL[3] = temp; + + temp = (s32)cpuRegs.GPR.r[_Rs_].SS[6] * (s32)cpuRegs.GPR.r[_Rt_].SS[6]; + cpuRegs.HI.UL[2] = temp; + /*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[3] = temp;*/ + + temp = (s32)cpuRegs.GPR.r[_Rs_].SS[7] * (s32)cpuRegs.GPR.r[_Rt_].SS[7]; + cpuRegs.HI.UL[3] = temp; + + if (_Rd_) { + cpuRegs.GPR.r[_Rd_].UL[0] = cpuRegs.LO.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[1] = cpuRegs.HI.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[2] = cpuRegs.LO.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[3] = cpuRegs.HI.UL[2]; + } +} + +__forceinline void _PDIVBW(int n) +{ + cpuRegs.LO.UL[n] = (s32)(cpuRegs.GPR.r[_Rs_].SL[n] / cpuRegs.GPR.r[_Rt_].SS[0]); + cpuRegs.HI.UL[n] = (s16)(cpuRegs.GPR.r[_Rs_].SL[n] % cpuRegs.GPR.r[_Rt_].SS[0]); +} + +void PDIVBW() { + if (cpuRegs.GPR.r[_Rt_].US[0] == 0) return; + + _PDIVBW(0); _PDIVBW(1); _PDIVBW(2); _PDIVBW(3); +} + +void PEXEW() { + GPR_reg Rt; + + if (!_Rd_) return; + + Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].UL[0] = Rt.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[1] = Rt.UL[1]; + cpuRegs.GPR.r[_Rd_].UL[2] = Rt.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[3] = Rt.UL[3]; +} + +void PROT3W() { + GPR_reg Rt; + + if (!_Rd_) return; + + Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].UL[0] = Rt.UL[1]; + cpuRegs.GPR.r[_Rd_].UL[1] = Rt.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[2] = Rt.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[3] = Rt.UL[3]; +} + +//*****END OF MMI2 OPCODES*********************************** + +//*************************MMI3 OPCODES************************ + +__forceinline void _PMADDUW(int dd, int ss) +{ + u64 tempu = (u64)((u64)cpuRegs.LO.UL[ss] | ((u64)cpuRegs.HI.UL[ss] << 32)) + \ + ((u64)cpuRegs.GPR.r[_Rs_].UL[ss] * (u64)cpuRegs.GPR.r[_Rt_].UL[ss]); + + cpuRegs.LO.SD[dd] = (s32)(tempu & 0xffffffff); + cpuRegs.HI.SD[dd] = (s32)(tempu >> 32); + + if (_Rd_) cpuRegs.GPR.r[_Rd_].UD[dd] = tempu; +} + +void PMADDUW() { + _PMADDUW(0, 0); + _PMADDUW(1, 2); +} + +void PSRAVW() { + if (!_Rd_) return; + + cpuRegs.GPR.r[_Rd_].UD[0] = (cpuRegs.GPR.r[_Rt_].SL[0] >> + (cpuRegs.GPR.r[_Rs_].UL[0] & 0x1F)); + cpuRegs.GPR.r[_Rd_].UD[1] = (cpuRegs.GPR.r[_Rt_].SL[2] >> + (cpuRegs.GPR.r[_Rs_].UL[2] & 0x1F)); +} + +void PMTHI() { + cpuRegs.HI.UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; + cpuRegs.HI.UD[1] = cpuRegs.GPR.r[_Rs_].UD[1]; +} + +void PMTLO() { + cpuRegs.LO.UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; + cpuRegs.LO.UD[1] = cpuRegs.GPR.r[_Rs_].UD[1]; +} + +void PINTEH() { + GPR_reg Rs, Rt; + + if (!_Rd_) return; + + Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[1] = Rs.US[0]; + cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[2]; + cpuRegs.GPR.r[_Rd_].US[3] = Rs.US[2]; + cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[4]; + cpuRegs.GPR.r[_Rd_].US[5] = Rs.US[4]; + cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[6]; + cpuRegs.GPR.r[_Rd_].US[7] = Rs.US[6]; +} + +__forceinline void _PMULTUW(int dd, int ss) +{ + u64 tempu = (u64)cpuRegs.GPR.r[_Rs_].UL[ss] * (u64)cpuRegs.GPR.r[_Rt_].UL[ss]; + + cpuRegs.LO.UD[dd] = (s32)(tempu & 0xffffffff); + cpuRegs.HI.UD[dd] = (s32)(tempu >> 32); + + if (_Rd_) cpuRegs.GPR.r[_Rd_].UD[dd] = tempu; +} + + +void PMULTUW() { + _PMULTUW(0, 0); + _PMULTUW(1, 2); +} + +__forceinline void _PDIVUW(int dd, int ss) +{ + if (cpuRegs.GPR.r[_Rt_].UL[ss] != 0) { + cpuRegs.LO.UD[dd] = (u64)cpuRegs.GPR.r[_Rs_].UL[ss] / (u64)cpuRegs.GPR.r[_Rt_].UL[ss]; + cpuRegs.HI.UD[dd] = (u64)cpuRegs.GPR.r[_Rs_].UL[ss] % (u64)cpuRegs.GPR.r[_Rt_].UL[ss]; + } +} + +void PDIVUW() { + _PDIVUW(0, 0); + _PDIVUW(1, 2); +} + +void PCPYUD() { + if (!_Rd_) return; + + // note: first _Rs_, since the other way when _Rd_ equals + // _Rs_ or _Rt_ this would screw up + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[1]; + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rt_].UD[1]; +} + +void POR() { + if (!_Rd_) return; + + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] | cpuRegs.GPR.r[_Rt_].UD[0]; + cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rs_].UD[1] | cpuRegs.GPR.r[_Rt_].UD[1]; +} + +void PNOR () { + if (!_Rd_) return; + + cpuRegs.GPR.r[_Rd_].UD[0] = ~(cpuRegs.GPR.r[_Rs_].UD[0] | cpuRegs.GPR.r[_Rt_].UD[0]); + cpuRegs.GPR.r[_Rd_].UD[1] = ~(cpuRegs.GPR.r[_Rs_].UD[1] | cpuRegs.GPR.r[_Rt_].UD[1]); +} + +void PEXCH() { + GPR_reg Rt; + + if (!_Rd_) return; + + Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[1] = Rt.US[2]; + cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[1]; + cpuRegs.GPR.r[_Rd_].US[3] = Rt.US[3]; + cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[4]; + cpuRegs.GPR.r[_Rd_].US[5] = Rt.US[6]; + cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[5]; + cpuRegs.GPR.r[_Rd_].US[7] = Rt.US[7]; +} + +void PCPYH() { + GPR_reg Rt; + + if (!_Rd_) return; + + Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].US[0] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[1] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[2] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[3] = Rt.US[0]; + cpuRegs.GPR.r[_Rd_].US[4] = Rt.US[4]; + cpuRegs.GPR.r[_Rd_].US[5] = Rt.US[4]; + cpuRegs.GPR.r[_Rd_].US[6] = Rt.US[4]; + cpuRegs.GPR.r[_Rd_].US[7] = Rt.US[4]; +} + +void PEXCW() { + GPR_reg Rt; + + if (!_Rd_) return; + + Rt = cpuRegs.GPR.r[_Rt_]; + cpuRegs.GPR.r[_Rd_].UL[0] = Rt.UL[0]; + cpuRegs.GPR.r[_Rd_].UL[1] = Rt.UL[2]; + cpuRegs.GPR.r[_Rd_].UL[2] = Rt.UL[1]; + cpuRegs.GPR.r[_Rd_].UL[3] = Rt.UL[3]; +} + +//**********************END OF MMI3 OPCODES******************** + +// obs: +// QFSRV not verified + }}} } // end namespace R5900::Interpreter::OpcodeImpl::MMI \ No newline at end of file diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index 40f2542365..4fe965e7e5 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -1,1053 +1,1053 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include -#include - -#include "Common.h" -#include "VU.h" -#include "GS.h" -#include "iR5900.h" -#include "VifDma.h" - -#include "SamplProf.h" - -// Uncomment this to enable profiling of the GS RingBufferCopy function. -//#define PCSX2_GSRING_SAMPLING_STATS - -#ifdef PCSX2_GSRING_TX_STATS -#include -#endif - -using namespace Threading; -using namespace std; - -#ifdef DEBUG -#define MTGS_LOG Console::WriteLn -#else -#define MTGS_LOG 0&& -#endif - -// forces the compiler to treat a non-volatile value as volatile. -// This allows us to declare the vars as non-volatile and only use -// them as volatile when appropriate (more optimized). - -#define volatize(x) (*reinterpret_cast(&(x))) - -///////////////////////////////////////////////////////////////////////////// -// BEGIN -- MTGS GIFtag Parse Implementation -// -// The MTGS needs a dummy "GS plugin" for processing SIGNAL, FINISH, and LABEL -// commands. These commands trigger gsIRQs, which need to be handled accurately -// in synch with the EE (which can be running several frames ahead of the MTGS) -// -// Yeah, it's a lot of work, but the performance gains are huge, even on HT cpus. - -// unpack the registers -// registers are stored as a sequence of 4 bit values in the -// upper 64 bits of the GIFTAG. That sucks for us, so we unpack -// them into an 8 bit array. -__forceinline void GIFPath::PrepRegs() -{ - if( tag.nreg == 0 ) - { - u32 tempreg = tag.regs[0]; - for(u32 i=0; i<16; ++i, tempreg >>= 4) - { - if( i == 8 ) tempreg = tag.regs[1]; - assert( (tempreg&0xf) < 0x64 ); - regs[i] = tempreg & 0xf; - } - } - else - { - u32 tempreg = tag.regs[0]; - for(u32 i=0; i>= 4) - { - assert( (tempreg&0xf) < 0x64 ); - regs[i] = tempreg & 0xf; - } - } -} - -void GIFPath::SetTag(const void* mem) -{ - tag = *((GIFTAG*)mem); - curreg = 0; - - PrepRegs(); -} - -u32 GIFPath::GetReg() -{ - return regs[curreg]; -} - -static void _mtgsFreezeGIF( SaveState& state, GIFPath (&paths)[3] ) -{ - for(int i=0; i<3; i++ ) - { - state.Freeze( paths[i].tag ); - state.Freeze( paths[i].curreg ); - } - - for(int i=0; i<3; i++ ) - { - state.Freeze( paths[i].regs ); - } -} - -void SaveState::mtgsFreeze() -{ - if( mtgsThread != NULL ) - { - mtgsThread->Freeze( *this ); - } - else - { - // save some zero'd dummy info... - // This isn't ideal, and it could lead to problems in very rare - // circumstances, but most of the time should be perfectly fine. - - GIFPath path[3]; - memzero_obj( path ); - _mtgsFreezeGIF( *this, path ); - } -} - - -static void RegHandlerSIGNAL(const u32* data) -{ - MTGS_LOG("MTGS SIGNAL data %x_%x CSRw %x\n",data[0], data[1], CSRw); - - GSSIGLBLID->SIGID = (GSSIGLBLID->SIGID&~data[1])|(data[0]&data[1]); - - if ((CSRw & 0x1)) - GSCSRr |= 1; // signal - - if (!(GSIMR&0x100) ) - gsIrq(); -} - -static void RegHandlerFINISH(const u32* data) -{ - MTGS_LOG("MTGS FINISH data %x_%x CSRw %x\n",data[0], data[1], CSRw); - - if ((CSRw & 0x2)) - GSCSRr |= 2; // finish - - if (!(GSIMR&0x200) ) - gsIrq(); - -} - -static void RegHandlerLABEL(const u32* data) -{ - GSSIGLBLID->LBLID = (GSSIGLBLID->LBLID&~data[1])|(data[0]&data[1]); -} - -// END -- MTGS GIFtag Parse Implementation -///////////////////////////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////////////////////////// -// MTGS Threaded Class Implementation - -mtgsThreadObject* mtgsThread = NULL; - -#ifdef RINGBUF_DEBUG_STACK -#include -std::list ringposStack; -#endif - -#ifdef _DEBUG -// debug variable used to check for bad code bits where copies are started -// but never closed, or closed without having been started. (GSRingBufCopy calls -// should always be followed by a call to GSRINGBUF_DONECOPY) -static int copyLock = 0; -#endif - -typedef void (*GIFRegHandler)(const u32* data); -static GIFRegHandler s_GSHandlers[3] = { RegHandlerSIGNAL, RegHandlerFINISH, RegHandlerLABEL }; - -mtgsThreadObject::mtgsThreadObject() : - m_RingPos( 0 ) -, m_WritePos( 0 ) - -, m_post_InitDone() -, m_lock_RingRestart() - -, m_CopyCommandTally( 0 ) -, m_CopyDataTally( 0 ) -, m_RingBufferIsBusy( 0 ) -, m_packet_size( 0 ) -, m_packet_ringpos( 0 ) - -#ifdef RINGBUF_DEBUG_STACK -, m_lock_Stack() -#endif -, m_RingBuffer( m_RingBufferSize + (Ps2MemSize::GSregs/sizeof(u128)) ) -, m_gsMem( (u8*)m_RingBuffer.GetPtr( m_RingBufferSize ) ) -{ - memzero_obj( m_path ); - - // Wait for the thread to finish initialization (it runs GSinit, which can take - // some time since it's creating a new window and all), and then check for errors. - - m_post_event.Post(); // tell MTGS we're done here - m_post_InitDone.Wait(); // and wait for MTGS to be done there! - - if( m_returncode != 0 ) // means the thread failed to init the GS plugin - throw Exception::PluginFailure( "GS", "The GS plugin failed to open/initialize." ); -} - -mtgsThreadObject::~mtgsThreadObject() -{ -} - -void mtgsThreadObject::Close() -{ - Console::WriteLn( "MTGS > Closing GS thread..." ); - SendSimplePacket( GS_RINGTYPE_QUIT, 0, 0, 0 ); - SetEvent(); - pthread_join( m_thread, NULL ); -} - -void mtgsThreadObject::Reset() -{ - // MTGS Reset process: - // * clear the ringbuffer. - // * Signal a reset. - // * clear the path and byRegs structs (used by GIFtagDummy) - - AtomicExchange( m_RingPos, m_WritePos ); - - MTGS_LOG( "MTGS > Sending Reset...\n" ); - SendSimplePacket( GS_RINGTYPE_RESET, 0, 0, 0 ); - SendSimplePacket( GS_RINGTYPE_FRAMESKIP, 0, 0, 0 ); - - memzero_obj( m_path ); -} - -// Processes a GIFtag & packet, and throws out some gsIRQs as needed. -// Used to keep interrupts in sync with the EE, while the GS itself -// runs potentially several frames behind. -// size - size of the packet in simd128's -__forceinline u32 mtgsThreadObject::_gifTransferDummy( GIF_PATH pathidx, const u8* pMem, u32 size ) -{ - GIFPath& path = m_path[pathidx]; - -#ifdef PCSX2_GSRING_SAMPLING_STATS - static uptr profStartPtr = 0; - static uptr profEndPtr = 0; - if( profStartPtr == 0 ) - { - __asm - { - __beginfunc: - mov profStartPtr, offset __beginfunc; - mov profEndPtr, offset __endfunc; - } - ProfilerRegisterSource( "GSRingBufCopy", (void*)profStartPtr, profEndPtr - profStartPtr ); - } -#endif - - while(size > 0) - { - bool eop = false; - - if(path.tag.nloop == 0) - { - path.SetTag( pMem ); - - pMem += sizeof(GIFTAG); - --size; - - if(pathidx == 2 && path.tag.eop) - Path3transfer = 0; - - if( pathidx == 0 ) - { - // hack: if too much data for VU1, just ignore. - - // The GIF is evil : if nreg is 0, it's really 16. Otherwise it's the value in nreg. - const int numregs = ((path.tag.nreg-1)&15)+1; - - if((path.tag.nloop * numregs) > (size * ((path.tag.flg == 1) ? 2 : 1))) - { - path.tag.nloop = 0; - return ++size; - } - } - - - /*f(path.tag.pre) - { - assert(path.tag.flg != GIF_FLG_IMAGE); // kingdom hearts, ffxii, tales of abyss - - if((path.tag.flg & 2) == 0) - { - // Primitive handler... Nothing for the Dummy to do here. - - //GIFReg r; - //r.i64 = path.tag.PRIM; - //(this->*m_fpGIFRegHandlers[GIF_A_D_REG_PRIM])(&r); - } - }*/ - - if(path.tag.eop) - { - eop = true; - } - else if(path.tag.nloop == 0) - { - if(pathidx == 0 && g_FFXHack) - continue; - - eop = true; - } - } - - if(path.tag.nloop > 0) - { - switch(path.tag.flg) - { - case GIF_FLG_PACKED: - - while(size > 0) - { - if( path.GetReg() == 0xe ) - { - const int handler = pMem[8]; - if(handler >= 0x60 && handler < 0x63) - s_GSHandlers[handler&0x3]((const u32*)pMem); - } - size--; - pMem += 16; // 128 bits! //sizeof(GIFPackedReg); - - if((++path.curreg & 0xf) == path.tag.nreg) - { - path.curreg = 0; - path.tag.nloop--; - - if(path.tag.nloop == 0) - break; - } - } - break; - - case GIF_FLG_REGLIST: - - size *= 2; - - while(size > 0) - { - const int handler = path.GetReg(); - if(handler >= 0x60 && handler < 0x63) - s_GSHandlers[handler&0x3]((const u32*)pMem); - - size--; - pMem += 8; //sizeof(GIFReg); -- 64 bits! - - if((++path.curreg & 0xf) == path.tag.nreg) - { - path.curreg = 0; - path.tag.nloop--; - - if(path.tag.nloop == 0) - { - break; - } - } - } - - if(size & 1) pMem += 8; //sizeof(GIFReg); - size /= 2; - - break; - - case GIF_FLG_IMAGE2: // hmmm - assert(0); - path.tag.nloop = 0; - - break; - - case GIF_FLG_IMAGE: - { - int len = (int)min(size, path.tag.nloop); - - pMem += len * 16; - path.tag.nloop -= len; - size -= len; - } - break; - - jNO_DEFAULT; - - } - } - - if(eop && ((int)size <= 0 || pathidx == 0)) - { - break; - } - } - - if(pathidx == 0) - { - if(!path.tag.eop && path.tag.nloop > 0) - { - path.tag.nloop = 0; - DevCon::Write( "path1 hack! " ); - - // This means that the giftag data got screwly somewhere - // along the way (often means curreg was in a bad state or something) - } - } -#ifdef PCSX2_GSRING_SAMPLING_STATS - __asm - { - __endfunc: - nop; - } -#endif - return size; -} - -struct PacketTagType -{ - u32 command; - u32 data[3]; -}; - -int mtgsThreadObject::Callback() -{ - Console::WriteLn("MTGS > Thread Started, Opening GS Plugin..."); - - // Wait for the MTGS to initialize structures. - m_post_event.Wait(); - - memcpy_aligned( m_gsMem, PS2MEM_GS, sizeof(m_gsMem) ); - GSsetBaseMem( m_gsMem ); - - m_returncode = GSopen((void *)&pDsp, "PCSX2", 1); - GSCSRr = 0x551B400F; // 0x55190000 - m_post_InitDone.Post(); - if (m_returncode != 0) { return m_returncode; } // error msg will be issued to the user by Plugins.c - Console::WriteLn("MTGS > GSopen Finished."); - -#ifdef RINGBUF_DEBUG_STACK - PacketTagType prevCmd; -#endif - - while( true ) - { - m_post_event.Wait(); - - AtomicExchange( m_RingBufferIsBusy, 1 ); - - // note: m_RingPos is intentionally not volatile, because it should only - // ever be modified by this thread. - while( m_RingPos != volatize(m_WritePos)) - { - assert( m_RingPos < m_RingBufferSize ); - - const PacketTagType& tag = (PacketTagType&)m_RingBuffer[m_RingPos]; - u32 ringposinc = 1; - -#ifdef RINGBUF_DEBUG_STACK - // pop a ringpos off the stack. It should match this one! - - m_lock_Stack.Lock(); - uptr stackpos = ringposStack.back(); - if( stackpos != m_RingPos ) - { - Console::Error( "MTGS Ringbuffer Critical Failure ---> %x to %x (prevCmd: %x)\n", params stackpos, m_RingPos, prevCmd.command ); - } - assert( stackpos == m_RingPos ); - prevCmd = tag; - ringposStack.pop_back(); - m_lock_Stack.Unlock(); -#endif - - switch( tag.command ) - { - case GS_RINGTYPE_RESTART: - AtomicExchange(m_RingPos, 0); - - // stall for a bit to let the MainThread have time to update the g_pGSWritePos. - m_lock_RingRestart.Lock(); - m_lock_RingRestart.Unlock(); - continue; - - case GS_RINGTYPE_P1: - { - const int qsize = tag.data[0]; - const u128* data = m_RingBuffer.GetPtr( m_RingPos+1 ); - - // make sure that tag>>16 is the MAX size readable - //GSgifTransfer1(((u32*)data) - 0x1000 + 4*qsize, 0x4000-qsize*16); - GSgifTransfer1((u32*)(data - 0x400 + qsize), 0x4000-qsize*16); - ringposinc += qsize; - } - break; - - case GS_RINGTYPE_P2: - { - const int qsize = tag.data[0]; - const u128* data = m_RingBuffer.GetPtr( m_RingPos+1 ); - GSgifTransfer2((u32*)data, qsize); - ringposinc += qsize; - } - break; - - case GS_RINGTYPE_P3: - { - const int qsize = tag.data[0]; - const u128* data = m_RingBuffer.GetPtr( m_RingPos+1 ); - GSgifTransfer3((u32*)data, qsize); - ringposinc += qsize; - } - break; - - case GS_RINGTYPE_VSYNC: - { - GSvsync(tag.data[0]); - - gsFrameSkip( !tag.data[1] ); - - if( PAD1update != NULL ) PAD1update(0); - if( PAD2update != NULL ) PAD2update(1); - } - break; - - case GS_RINGTYPE_FRAMESKIP: - _gs_ResetFrameskip(); - break; - - case GS_RINGTYPE_MEMWRITE8: - m_gsMem[tag.data[0]] = (u8)tag.data[1]; - break; - case GS_RINGTYPE_MEMWRITE16: - *(u16*)(m_gsMem+tag.data[0]) = (u16)tag.data[1]; - break; - case GS_RINGTYPE_MEMWRITE32: - *(u32*)(m_gsMem+tag.data[0]) = tag.data[1]; - break; - case GS_RINGTYPE_MEMWRITE64: - *(u64*)(m_gsMem+tag.data[0]) = *(u64*)&tag.data[1]; - break; - - case GS_RINGTYPE_FREEZE: - { - freezeData* data = (freezeData*)(*(uptr*)&tag.data[1]); - int mode = tag.data[0]; - GSfreeze( mode, data ); - break; - } - - case GS_RINGTYPE_RECORD: - { - int record = tag.data[0]; - if( GSsetupRecording != NULL ) GSsetupRecording(record, NULL); - if( SPU2setupRecording != NULL ) SPU2setupRecording(record, NULL); - break; - } - - case GS_RINGTYPE_RESET: - MTGS_LOG( "MTGS > Receiving Reset...\n" ); - if( GSreset != NULL ) GSreset(); - break; - - case GS_RINGTYPE_SOFTRESET: - { - int mask = tag.data[0]; - MTGS_LOG( "MTGS > Receiving GIF Soft Reset (mask: %d)\n", mask ); - GSgifSoftReset( mask ); - break; - } - - case GS_RINGTYPE_WRITECSR: - GSwriteCSR( tag.data[0] ); - break; - - case GS_RINGTYPE_MODECHANGE: - _gs_ChangeTimings( tag.data[0], tag.data[1] ); - break; - - case GS_RINGTYPE_STARTTIME: - m_iSlowStart += tag.data[0]; - break; - - case GS_RINGTYPE_QUIT: - GSclose(); - return 0; - -#ifdef PCSX2_DEVBUILD - default: - Console::Error("GSThreadProc, bad packet (%x) at m_RingPos: %x, m_WritePos: %x", params tag.command, m_RingPos, m_WritePos); - assert(0); - m_RingPos = m_WritePos; - continue; -#else - // Optimized performance in non-Dev builds. - jNO_DEFAULT; -#endif - } - - uint newringpos = m_RingPos + ringposinc; - assert( newringpos <= m_RingBufferSize ); - newringpos &= m_RingBufferMask; - AtomicExchange( m_RingPos, newringpos ); - } - AtomicExchange( m_RingBufferIsBusy, 0 ); - } -} - -// Waits for the GS to empty out the entire ring buffer contents. -// Used primarily for plugin startup/shutdown. -void mtgsThreadObject::WaitGS() -{ - // Freeze registers because some kernel code likes to destroy them - FreezeXMMRegs(1); - FreezeMMXRegs(1); - SetEvent(); - while( volatize(m_RingPos) != volatize(m_WritePos) ) - { - Timeslice(); - //SpinWait(); - } - FreezeXMMRegs(0); - FreezeMMXRegs(0); -} - -// Sets the gsEvent flag and releases a timeslice. -// For use in loops that wait on the GS thread to do certain things. -void mtgsThreadObject::SetEvent() -{ - m_post_event.Post(); - m_CopyCommandTally = 0; - m_CopyDataTally = 0; -} - -void mtgsThreadObject::PrepEventWait() -{ - // Freeze registers because some kernel code likes to destroy them - FreezeXMMRegs(1); - FreezeMMXRegs(1); - //Console::Notice( "MTGS Stall! EE waits for nothing! ... except your GPU sometimes." ); - SetEvent(); - Timeslice(); -} - -void mtgsThreadObject::PostEventWait() const -{ - FreezeMMXRegs(0); - FreezeXMMRegs(0); -} - -u8* mtgsThreadObject::GetDataPacketPtr() const -{ - return (u8*)m_RingBuffer.GetPtr( m_packet_ringpos ); -} - -// Closes the data packet send command, and initiates the gs thread (if needed). -void mtgsThreadObject::SendDataPacket() -{ - // make sure a previous copy block has been started somewhere. - jASSUME( m_packet_size != 0 ); - - uint temp = m_packet_ringpos + m_packet_size; - jASSUME( temp <= m_RingBufferSize ); - temp &= m_RingBufferMask; - -#ifdef _DEBUG - if( m_packet_ringpos + m_packet_size < m_RingBufferSize ) - { - uint readpos = volatize(m_RingPos); - if( readpos != m_WritePos ) - { - // The writepos should never leapfrog the readpos - // since that indicates a bad write. - if( m_packet_ringpos < readpos ) - assert( temp < readpos ); - } - - // Updating the writepos should never make it equal the readpos, since - // that would stop the buffer prematurely (and indicates bad code in the - // ringbuffer manager) - assert( readpos != temp ); - } -#endif - - AtomicExchange( m_WritePos, temp ); - - m_packet_size = 0; - - if( m_RingBufferIsBusy ) return; - - // The ringbuffer is current in a resting state, so if enough copies have - // queued up then go ahead and initiate the GS thread.. - - // Optimization notes: What we're doing here is initiating a "burst" mode on - // the thread, which improves its cache hit performance and makes it more friendly - // to other threads in Pcsx2 and such. Primary is the Command Tally, and then a - // secondary data size threshold for games that do lots of texture swizzling. - - // 16 was the best value I found so far. - // tested values: - // 24 - very slow on HT machines (+5% drop in fps) - // 8 - roughly 2% slower on HT machines. - - m_CopyDataTally += m_packet_size; - if( ( m_CopyDataTally > 0x8000 ) || ( ++m_CopyCommandTally > 16 ) ) - { - FreezeXMMRegs(1); - FreezeMMXRegs(1); - //Console::Status( "MTGS Kick! DataSize : 0x%5.8x, CommandTally : %d", m_CopyDataTally, m_CopyCommandTally ); - SetEvent(); - FreezeMMXRegs(0); - FreezeXMMRegs(0); - } -} - -int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u64* srcdata, u32 size ) -{ - return PrepDataPacket( pathidx, (u8*)srcdata, size ); -} - -int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u32* srcdata, u32 size ) -{ - return PrepDataPacket( pathidx, (u8*)srcdata, size ); -} - -#ifdef PCSX2_GSRING_TX_STATS -static u32 ringtx_s=0; -static u32 ringtx_s_ulg=0; -static u32 ringtx_s_min=0xFFFFFFFF; -static u32 ringtx_s_max=0; -static u32 ringtx_c=0; -static u32 ringtx_inf[32][32]; -static u32 ringtx_inf_s[32]; -#endif - -#ifdef PCSX2_GSRING_SAMPLING_STATS -static u32 GSRingBufCopySz = 0; -#endif - -// returns the amount of giftag data not processed (in simd128 values). -// Return value is used by VU1 XGKICK to hack-fix data packets which are too -// large for VU1 memory. -// Parameters: -// size - size of the packet data, in smd128's -int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 size ) -{ -#ifdef PCSX2_GSRING_TX_STATS - ringtx_s+=size; - ringtx_s_ulg+=size&0x7F; - ringtx_s_min=min(ringtx_s_min,size); - ringtx_s_max=max(ringtx_s_max,size); - ringtx_c++; - unsigned long tx_sz; - if (_BitScanReverse(&tx_sz,size)) - { - unsigned long tx_algn; - _BitScanForward(&tx_algn,size); - ringtx_inf[tx_sz][tx_algn]++; - ringtx_inf_s[tx_sz]+=size; - } - if (ringtx_s>=128*1024*1024) - { - Console::Status("GSRingBufCopy:128MB in %d tx -> b/tx: AVG = %.2f , max = %d, min = %d",ringtx_c,ringtx_s/(float)ringtx_c,ringtx_s_max,ringtx_s_min); - for (int i=0;i<32;i++) - { - u32 total_bucket=0; - u32 bucket_subitems=0; - for (int j=0;j<32;j++) - { - if (ringtx_inf[i][j]) - { - total_bucket+=ringtx_inf[i][j]; - bucket_subitems++; - Console::Notice("GSRingBufCopy :tx [%d,%d] algn %d : count= %d [%.2f%%]",1<= readpos) - - PrepEventWait(); - while( true ) - { - uint readpos = volatize(m_RingPos); - if( writepos >= readpos ) break; - if( writepos+size < readpos ) break; - SpinWait(); - } - PostEventWait(); - } - } - else if( writepos + size > m_RingBufferSize ) - { - // If the incoming packet doesn't fit, then start over from - // the start of the ring buffer (it's a lot easier than trying - // to wrap the packet around the end of the buffer). - - // We have to be careful not to leapfrog our read-position. If it's - // greater than the current write position then we need to stall - // until it loops around to the beginning of the buffer - - PrepEventWait(); - while( true ) - { - uint readpos = volatize(m_RingPos); - - // is the buffer empty? - if( readpos == writepos ) break; - - // Also: Wait for the readpos to go past the start of the buffer - // Otherwise it'll stop dead in its tracks when we set the new write - // position below (bad!) - if( readpos < writepos && readpos != 0 ) break; - - SpinWait(); - } - - m_lock_RingRestart.Lock(); - SendSimplePacket( GS_RINGTYPE_RESTART, 0, 0, 0 ); - writepos = 0; - AtomicExchange( m_WritePos, writepos ); - m_lock_RingRestart.Unlock(); - SetEvent(); - - // stall until the read position is past the end of our incoming block, - // or until it reaches the current write position (signals an empty buffer). - while( true ) - { - uint readpos = volatize(m_RingPos); - - if( readpos == m_WritePos ) break; - if( writepos+size < readpos ) break; - - SpinWait(); - } - PostEventWait(); - } - else // always true - if( writepos + size == MTGS_RINGBUFFEREND ) - { - // Yay. Perfect fit. What are the odds? - //SysPrintf( "MTGS > Perfect Fit!\n"); - - PrepEventWait(); - while( true ) - { - uint readpos = volatize(m_RingPos); - - // stop waiting if the buffer is empty! - if( writepos == readpos ) break; - - // Copy is ready so long as readpos is less than writepos and *not* - // equal to the base of the ringbuffer (otherwise the buffer will stop - // when the writepos is wrapped around to zero later-on in SendDataPacket) - if( readpos < writepos && readpos != 0 ) break; - - SpinWait(); - } - PostEventWait(); - } - -#ifdef RINGBUF_DEBUG_STACK - m_lock_Stack.Lock(); - ringposStack.push_front( writepos ); - m_lock_Stack.Unlock(); -#endif - - // Command qword: Low word is the command, and the high word is the packet - // length in SIMDs (128 bits). - - PacketTagType& tag = (PacketTagType&)m_RingBuffer[m_WritePos]; - tag.command = pathidx+1; - tag.data[0] = m_packet_size; - m_packet_ringpos = m_WritePos + 1; - - return m_packet_size; -} - -__forceinline uint mtgsThreadObject::_PrepForSimplePacket() -{ -#ifdef RINGBUF_DEBUG_STACK - m_lock_Stack.Lock(); - ringposStack.push_front( m_WritePos ); - m_lock_Stack.Unlock(); -#endif - - uint future_writepos = m_WritePos+1; - jASSUME( future_writepos <= m_RingBufferSize ); - - future_writepos &= m_RingBufferMask; - - if( future_writepos == volatize(m_RingPos) ) - { - PrepEventWait(); - do - { - SpinWait(); - } while( future_writepos == volatize(m_RingPos) ); - PostEventWait(); - } - - return future_writepos; -} - -__forceinline void mtgsThreadObject::_FinishSimplePacket( uint future_writepos ) -{ - assert( future_writepos != volatize(m_RingPos) ); - AtomicExchange( m_WritePos, future_writepos ); -} - -void mtgsThreadObject::SendSimplePacket( GS_RINGTYPE type, int data0, int data1, int data2 ) -{ - const uint thefuture = _PrepForSimplePacket(); - PacketTagType& tag = (PacketTagType&)m_RingBuffer[m_WritePos]; - - tag.command = type; - tag.data[0] = data0; - tag.data[1] = data1; - tag.data[2] = data2; - - _FinishSimplePacket( thefuture ); -} - -void mtgsThreadObject::SendPointerPacket( GS_RINGTYPE type, u32 data0, void* data1 ) -{ - const uint thefuture = _PrepForSimplePacket(); - PacketTagType& tag = (PacketTagType&)m_RingBuffer[m_WritePos]; - - tag.command = type; - tag.data[0] = data0; - *(uptr*)&tag.data[1] = (uptr)data1; - - _FinishSimplePacket( thefuture ); -} - -// Waits for the GS to empty out the entire ring buffer contents. -// Used primarily for plugin startup/shutdown. -void mtgsWaitGS() -{ - if( mtgsThread == NULL ) return; - mtgsThread->WaitGS(); -} - -bool mtgsOpen() -{ - // Check the config flag since our thread object has yet to be created - if( !CHECK_MULTIGS ) return false; - - // better not be a thread already running, yo! - assert( mtgsThread == NULL ); - - try - { - mtgsThread = new mtgsThreadObject(); - } - catch( Exception::ThreadCreationError& ) - { - Console::Error( "MTGS > Thread creation failed!" ); - mtgsThread = NULL; - return false; - } - return true; -} - - -void mtgsThreadObject::GIFSoftReset( int mask ) -{ - if(mask & 1) memzero_obj(m_path[0]); - if(mask & 2) memzero_obj(m_path[1]); - if(mask & 4) memzero_obj(m_path[2]); - - if( GSgifSoftReset == NULL ) return; - - MTGS_LOG( "MTGS > Sending GIF Soft Reset (mask: %d)\n", mask ); - mtgsThread->SendSimplePacket( GS_RINGTYPE_SOFTRESET, mask, 0, 0 ); -} - -void mtgsThreadObject::Freeze( SaveState& state ) -{ - _mtgsFreezeGIF( state, this->m_path ); -} - -// this function is needed because of recompiled calls from iGS.cpp -// (currently used in GCC only) -void mtgsRingBufSimplePacket( s32 command, u32 data0, u32 data1, u32 data2 ) -{ - mtgsThread->SendSimplePacket( (GS_RINGTYPE)command, data0, data1, data2 ); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include +#include + +#include "Common.h" +#include "VU.h" +#include "GS.h" +#include "iR5900.h" +#include "VifDma.h" + +#include "SamplProf.h" + +// Uncomment this to enable profiling of the GS RingBufferCopy function. +//#define PCSX2_GSRING_SAMPLING_STATS + +#ifdef PCSX2_GSRING_TX_STATS +#include +#endif + +using namespace Threading; +using namespace std; + +#ifdef DEBUG +#define MTGS_LOG Console::WriteLn +#else +#define MTGS_LOG 0&& +#endif + +// forces the compiler to treat a non-volatile value as volatile. +// This allows us to declare the vars as non-volatile and only use +// them as volatile when appropriate (more optimized). + +#define volatize(x) (*reinterpret_cast(&(x))) + +///////////////////////////////////////////////////////////////////////////// +// BEGIN -- MTGS GIFtag Parse Implementation +// +// The MTGS needs a dummy "GS plugin" for processing SIGNAL, FINISH, and LABEL +// commands. These commands trigger gsIRQs, which need to be handled accurately +// in synch with the EE (which can be running several frames ahead of the MTGS) +// +// Yeah, it's a lot of work, but the performance gains are huge, even on HT cpus. + +// unpack the registers +// registers are stored as a sequence of 4 bit values in the +// upper 64 bits of the GIFTAG. That sucks for us, so we unpack +// them into an 8 bit array. +__forceinline void GIFPath::PrepRegs() +{ + if( tag.nreg == 0 ) + { + u32 tempreg = tag.regs[0]; + for(u32 i=0; i<16; ++i, tempreg >>= 4) + { + if( i == 8 ) tempreg = tag.regs[1]; + assert( (tempreg&0xf) < 0x64 ); + regs[i] = tempreg & 0xf; + } + } + else + { + u32 tempreg = tag.regs[0]; + for(u32 i=0; i>= 4) + { + assert( (tempreg&0xf) < 0x64 ); + regs[i] = tempreg & 0xf; + } + } +} + +void GIFPath::SetTag(const void* mem) +{ + tag = *((GIFTAG*)mem); + curreg = 0; + + PrepRegs(); +} + +u32 GIFPath::GetReg() +{ + return regs[curreg]; +} + +static void _mtgsFreezeGIF( SaveState& state, GIFPath (&paths)[3] ) +{ + for(int i=0; i<3; i++ ) + { + state.Freeze( paths[i].tag ); + state.Freeze( paths[i].curreg ); + } + + for(int i=0; i<3; i++ ) + { + state.Freeze( paths[i].regs ); + } +} + +void SaveState::mtgsFreeze() +{ + if( mtgsThread != NULL ) + { + mtgsThread->Freeze( *this ); + } + else + { + // save some zero'd dummy info... + // This isn't ideal, and it could lead to problems in very rare + // circumstances, but most of the time should be perfectly fine. + + GIFPath path[3]; + memzero_obj( path ); + _mtgsFreezeGIF( *this, path ); + } +} + + +static void RegHandlerSIGNAL(const u32* data) +{ + MTGS_LOG("MTGS SIGNAL data %x_%x CSRw %x\n",data[0], data[1], CSRw); + + GSSIGLBLID->SIGID = (GSSIGLBLID->SIGID&~data[1])|(data[0]&data[1]); + + if ((CSRw & 0x1)) + GSCSRr |= 1; // signal + + if (!(GSIMR&0x100) ) + gsIrq(); +} + +static void RegHandlerFINISH(const u32* data) +{ + MTGS_LOG("MTGS FINISH data %x_%x CSRw %x\n",data[0], data[1], CSRw); + + if ((CSRw & 0x2)) + GSCSRr |= 2; // finish + + if (!(GSIMR&0x200) ) + gsIrq(); + +} + +static void RegHandlerLABEL(const u32* data) +{ + GSSIGLBLID->LBLID = (GSSIGLBLID->LBLID&~data[1])|(data[0]&data[1]); +} + +// END -- MTGS GIFtag Parse Implementation +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// +// MTGS Threaded Class Implementation + +mtgsThreadObject* mtgsThread = NULL; + +#ifdef RINGBUF_DEBUG_STACK +#include +std::list ringposStack; +#endif + +#ifdef _DEBUG +// debug variable used to check for bad code bits where copies are started +// but never closed, or closed without having been started. (GSRingBufCopy calls +// should always be followed by a call to GSRINGBUF_DONECOPY) +static int copyLock = 0; +#endif + +typedef void (*GIFRegHandler)(const u32* data); +static GIFRegHandler s_GSHandlers[3] = { RegHandlerSIGNAL, RegHandlerFINISH, RegHandlerLABEL }; + +mtgsThreadObject::mtgsThreadObject() : + m_RingPos( 0 ) +, m_WritePos( 0 ) + +, m_post_InitDone() +, m_lock_RingRestart() + +, m_CopyCommandTally( 0 ) +, m_CopyDataTally( 0 ) +, m_RingBufferIsBusy( 0 ) +, m_packet_size( 0 ) +, m_packet_ringpos( 0 ) + +#ifdef RINGBUF_DEBUG_STACK +, m_lock_Stack() +#endif +, m_RingBuffer( m_RingBufferSize + (Ps2MemSize::GSregs/sizeof(u128)) ) +, m_gsMem( (u8*)m_RingBuffer.GetPtr( m_RingBufferSize ) ) +{ + memzero_obj( m_path ); + + // Wait for the thread to finish initialization (it runs GSinit, which can take + // some time since it's creating a new window and all), and then check for errors. + + m_post_event.Post(); // tell MTGS we're done here + m_post_InitDone.Wait(); // and wait for MTGS to be done there! + + if( m_returncode != 0 ) // means the thread failed to init the GS plugin + throw Exception::PluginFailure( "GS", "The GS plugin failed to open/initialize." ); +} + +mtgsThreadObject::~mtgsThreadObject() +{ +} + +void mtgsThreadObject::Close() +{ + Console::WriteLn( "MTGS > Closing GS thread..." ); + SendSimplePacket( GS_RINGTYPE_QUIT, 0, 0, 0 ); + SetEvent(); + pthread_join( m_thread, NULL ); +} + +void mtgsThreadObject::Reset() +{ + // MTGS Reset process: + // * clear the ringbuffer. + // * Signal a reset. + // * clear the path and byRegs structs (used by GIFtagDummy) + + AtomicExchange( m_RingPos, m_WritePos ); + + MTGS_LOG( "MTGS > Sending Reset...\n" ); + SendSimplePacket( GS_RINGTYPE_RESET, 0, 0, 0 ); + SendSimplePacket( GS_RINGTYPE_FRAMESKIP, 0, 0, 0 ); + + memzero_obj( m_path ); +} + +// Processes a GIFtag & packet, and throws out some gsIRQs as needed. +// Used to keep interrupts in sync with the EE, while the GS itself +// runs potentially several frames behind. +// size - size of the packet in simd128's +__forceinline u32 mtgsThreadObject::_gifTransferDummy( GIF_PATH pathidx, const u8* pMem, u32 size ) +{ + GIFPath& path = m_path[pathidx]; + +#ifdef PCSX2_GSRING_SAMPLING_STATS + static uptr profStartPtr = 0; + static uptr profEndPtr = 0; + if( profStartPtr == 0 ) + { + __asm + { + __beginfunc: + mov profStartPtr, offset __beginfunc; + mov profEndPtr, offset __endfunc; + } + ProfilerRegisterSource( "GSRingBufCopy", (void*)profStartPtr, profEndPtr - profStartPtr ); + } +#endif + + while(size > 0) + { + bool eop = false; + + if(path.tag.nloop == 0) + { + path.SetTag( pMem ); + + pMem += sizeof(GIFTAG); + --size; + + if(pathidx == 2 && path.tag.eop) + Path3transfer = 0; + + if( pathidx == 0 ) + { + // hack: if too much data for VU1, just ignore. + + // The GIF is evil : if nreg is 0, it's really 16. Otherwise it's the value in nreg. + const int numregs = ((path.tag.nreg-1)&15)+1; + + if((path.tag.nloop * numregs) > (size * ((path.tag.flg == 1) ? 2 : 1))) + { + path.tag.nloop = 0; + return ++size; + } + } + + + /*f(path.tag.pre) + { + assert(path.tag.flg != GIF_FLG_IMAGE); // kingdom hearts, ffxii, tales of abyss + + if((path.tag.flg & 2) == 0) + { + // Primitive handler... Nothing for the Dummy to do here. + + //GIFReg r; + //r.i64 = path.tag.PRIM; + //(this->*m_fpGIFRegHandlers[GIF_A_D_REG_PRIM])(&r); + } + }*/ + + if(path.tag.eop) + { + eop = true; + } + else if(path.tag.nloop == 0) + { + if(pathidx == 0 && g_FFXHack) + continue; + + eop = true; + } + } + + if(path.tag.nloop > 0) + { + switch(path.tag.flg) + { + case GIF_FLG_PACKED: + + while(size > 0) + { + if( path.GetReg() == 0xe ) + { + const int handler = pMem[8]; + if(handler >= 0x60 && handler < 0x63) + s_GSHandlers[handler&0x3]((const u32*)pMem); + } + size--; + pMem += 16; // 128 bits! //sizeof(GIFPackedReg); + + if((++path.curreg & 0xf) == path.tag.nreg) + { + path.curreg = 0; + path.tag.nloop--; + + if(path.tag.nloop == 0) + break; + } + } + break; + + case GIF_FLG_REGLIST: + + size *= 2; + + while(size > 0) + { + const int handler = path.GetReg(); + if(handler >= 0x60 && handler < 0x63) + s_GSHandlers[handler&0x3]((const u32*)pMem); + + size--; + pMem += 8; //sizeof(GIFReg); -- 64 bits! + + if((++path.curreg & 0xf) == path.tag.nreg) + { + path.curreg = 0; + path.tag.nloop--; + + if(path.tag.nloop == 0) + { + break; + } + } + } + + if(size & 1) pMem += 8; //sizeof(GIFReg); + size /= 2; + + break; + + case GIF_FLG_IMAGE2: // hmmm + assert(0); + path.tag.nloop = 0; + + break; + + case GIF_FLG_IMAGE: + { + int len = (int)min(size, path.tag.nloop); + + pMem += len * 16; + path.tag.nloop -= len; + size -= len; + } + break; + + jNO_DEFAULT; + + } + } + + if(eop && ((int)size <= 0 || pathidx == 0)) + { + break; + } + } + + if(pathidx == 0) + { + if(!path.tag.eop && path.tag.nloop > 0) + { + path.tag.nloop = 0; + DevCon::Write( "path1 hack! " ); + + // This means that the giftag data got screwly somewhere + // along the way (often means curreg was in a bad state or something) + } + } +#ifdef PCSX2_GSRING_SAMPLING_STATS + __asm + { + __endfunc: + nop; + } +#endif + return size; +} + +struct PacketTagType +{ + u32 command; + u32 data[3]; +}; + +int mtgsThreadObject::Callback() +{ + Console::WriteLn("MTGS > Thread Started, Opening GS Plugin..."); + + // Wait for the MTGS to initialize structures. + m_post_event.Wait(); + + memcpy_aligned( m_gsMem, PS2MEM_GS, sizeof(m_gsMem) ); + GSsetBaseMem( m_gsMem ); + + m_returncode = GSopen((void *)&pDsp, "PCSX2", 1); + GSCSRr = 0x551B400F; // 0x55190000 + m_post_InitDone.Post(); + if (m_returncode != 0) { return m_returncode; } // error msg will be issued to the user by Plugins.c + Console::WriteLn("MTGS > GSopen Finished."); + +#ifdef RINGBUF_DEBUG_STACK + PacketTagType prevCmd; +#endif + + while( true ) + { + m_post_event.Wait(); + + AtomicExchange( m_RingBufferIsBusy, 1 ); + + // note: m_RingPos is intentionally not volatile, because it should only + // ever be modified by this thread. + while( m_RingPos != volatize(m_WritePos)) + { + assert( m_RingPos < m_RingBufferSize ); + + const PacketTagType& tag = (PacketTagType&)m_RingBuffer[m_RingPos]; + u32 ringposinc = 1; + +#ifdef RINGBUF_DEBUG_STACK + // pop a ringpos off the stack. It should match this one! + + m_lock_Stack.Lock(); + uptr stackpos = ringposStack.back(); + if( stackpos != m_RingPos ) + { + Console::Error( "MTGS Ringbuffer Critical Failure ---> %x to %x (prevCmd: %x)\n", params stackpos, m_RingPos, prevCmd.command ); + } + assert( stackpos == m_RingPos ); + prevCmd = tag; + ringposStack.pop_back(); + m_lock_Stack.Unlock(); +#endif + + switch( tag.command ) + { + case GS_RINGTYPE_RESTART: + AtomicExchange(m_RingPos, 0); + + // stall for a bit to let the MainThread have time to update the g_pGSWritePos. + m_lock_RingRestart.Lock(); + m_lock_RingRestart.Unlock(); + continue; + + case GS_RINGTYPE_P1: + { + const int qsize = tag.data[0]; + const u128* data = m_RingBuffer.GetPtr( m_RingPos+1 ); + + // make sure that tag>>16 is the MAX size readable + //GSgifTransfer1(((u32*)data) - 0x1000 + 4*qsize, 0x4000-qsize*16); + GSgifTransfer1((u32*)(data - 0x400 + qsize), 0x4000-qsize*16); + ringposinc += qsize; + } + break; + + case GS_RINGTYPE_P2: + { + const int qsize = tag.data[0]; + const u128* data = m_RingBuffer.GetPtr( m_RingPos+1 ); + GSgifTransfer2((u32*)data, qsize); + ringposinc += qsize; + } + break; + + case GS_RINGTYPE_P3: + { + const int qsize = tag.data[0]; + const u128* data = m_RingBuffer.GetPtr( m_RingPos+1 ); + GSgifTransfer3((u32*)data, qsize); + ringposinc += qsize; + } + break; + + case GS_RINGTYPE_VSYNC: + { + GSvsync(tag.data[0]); + + gsFrameSkip( !tag.data[1] ); + + if( PAD1update != NULL ) PAD1update(0); + if( PAD2update != NULL ) PAD2update(1); + } + break; + + case GS_RINGTYPE_FRAMESKIP: + _gs_ResetFrameskip(); + break; + + case GS_RINGTYPE_MEMWRITE8: + m_gsMem[tag.data[0]] = (u8)tag.data[1]; + break; + case GS_RINGTYPE_MEMWRITE16: + *(u16*)(m_gsMem+tag.data[0]) = (u16)tag.data[1]; + break; + case GS_RINGTYPE_MEMWRITE32: + *(u32*)(m_gsMem+tag.data[0]) = tag.data[1]; + break; + case GS_RINGTYPE_MEMWRITE64: + *(u64*)(m_gsMem+tag.data[0]) = *(u64*)&tag.data[1]; + break; + + case GS_RINGTYPE_FREEZE: + { + freezeData* data = (freezeData*)(*(uptr*)&tag.data[1]); + int mode = tag.data[0]; + GSfreeze( mode, data ); + break; + } + + case GS_RINGTYPE_RECORD: + { + int record = tag.data[0]; + if( GSsetupRecording != NULL ) GSsetupRecording(record, NULL); + if( SPU2setupRecording != NULL ) SPU2setupRecording(record, NULL); + break; + } + + case GS_RINGTYPE_RESET: + MTGS_LOG( "MTGS > Receiving Reset...\n" ); + if( GSreset != NULL ) GSreset(); + break; + + case GS_RINGTYPE_SOFTRESET: + { + int mask = tag.data[0]; + MTGS_LOG( "MTGS > Receiving GIF Soft Reset (mask: %d)\n", mask ); + GSgifSoftReset( mask ); + break; + } + + case GS_RINGTYPE_WRITECSR: + GSwriteCSR( tag.data[0] ); + break; + + case GS_RINGTYPE_MODECHANGE: + _gs_ChangeTimings( tag.data[0], tag.data[1] ); + break; + + case GS_RINGTYPE_STARTTIME: + m_iSlowStart += tag.data[0]; + break; + + case GS_RINGTYPE_QUIT: + GSclose(); + return 0; + +#ifdef PCSX2_DEVBUILD + default: + Console::Error("GSThreadProc, bad packet (%x) at m_RingPos: %x, m_WritePos: %x", params tag.command, m_RingPos, m_WritePos); + assert(0); + m_RingPos = m_WritePos; + continue; +#else + // Optimized performance in non-Dev builds. + jNO_DEFAULT; +#endif + } + + uint newringpos = m_RingPos + ringposinc; + assert( newringpos <= m_RingBufferSize ); + newringpos &= m_RingBufferMask; + AtomicExchange( m_RingPos, newringpos ); + } + AtomicExchange( m_RingBufferIsBusy, 0 ); + } +} + +// Waits for the GS to empty out the entire ring buffer contents. +// Used primarily for plugin startup/shutdown. +void mtgsThreadObject::WaitGS() +{ + // Freeze registers because some kernel code likes to destroy them + FreezeXMMRegs(1); + FreezeMMXRegs(1); + SetEvent(); + while( volatize(m_RingPos) != volatize(m_WritePos) ) + { + Timeslice(); + //SpinWait(); + } + FreezeXMMRegs(0); + FreezeMMXRegs(0); +} + +// Sets the gsEvent flag and releases a timeslice. +// For use in loops that wait on the GS thread to do certain things. +void mtgsThreadObject::SetEvent() +{ + m_post_event.Post(); + m_CopyCommandTally = 0; + m_CopyDataTally = 0; +} + +void mtgsThreadObject::PrepEventWait() +{ + // Freeze registers because some kernel code likes to destroy them + FreezeXMMRegs(1); + FreezeMMXRegs(1); + //Console::Notice( "MTGS Stall! EE waits for nothing! ... except your GPU sometimes." ); + SetEvent(); + Timeslice(); +} + +void mtgsThreadObject::PostEventWait() const +{ + FreezeMMXRegs(0); + FreezeXMMRegs(0); +} + +u8* mtgsThreadObject::GetDataPacketPtr() const +{ + return (u8*)m_RingBuffer.GetPtr( m_packet_ringpos ); +} + +// Closes the data packet send command, and initiates the gs thread (if needed). +void mtgsThreadObject::SendDataPacket() +{ + // make sure a previous copy block has been started somewhere. + jASSUME( m_packet_size != 0 ); + + uint temp = m_packet_ringpos + m_packet_size; + jASSUME( temp <= m_RingBufferSize ); + temp &= m_RingBufferMask; + +#ifdef _DEBUG + if( m_packet_ringpos + m_packet_size < m_RingBufferSize ) + { + uint readpos = volatize(m_RingPos); + if( readpos != m_WritePos ) + { + // The writepos should never leapfrog the readpos + // since that indicates a bad write. + if( m_packet_ringpos < readpos ) + assert( temp < readpos ); + } + + // Updating the writepos should never make it equal the readpos, since + // that would stop the buffer prematurely (and indicates bad code in the + // ringbuffer manager) + assert( readpos != temp ); + } +#endif + + AtomicExchange( m_WritePos, temp ); + + m_packet_size = 0; + + if( m_RingBufferIsBusy ) return; + + // The ringbuffer is current in a resting state, so if enough copies have + // queued up then go ahead and initiate the GS thread.. + + // Optimization notes: What we're doing here is initiating a "burst" mode on + // the thread, which improves its cache hit performance and makes it more friendly + // to other threads in Pcsx2 and such. Primary is the Command Tally, and then a + // secondary data size threshold for games that do lots of texture swizzling. + + // 16 was the best value I found so far. + // tested values: + // 24 - very slow on HT machines (+5% drop in fps) + // 8 - roughly 2% slower on HT machines. + + m_CopyDataTally += m_packet_size; + if( ( m_CopyDataTally > 0x8000 ) || ( ++m_CopyCommandTally > 16 ) ) + { + FreezeXMMRegs(1); + FreezeMMXRegs(1); + //Console::Status( "MTGS Kick! DataSize : 0x%5.8x, CommandTally : %d", m_CopyDataTally, m_CopyCommandTally ); + SetEvent(); + FreezeMMXRegs(0); + FreezeXMMRegs(0); + } +} + +int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u64* srcdata, u32 size ) +{ + return PrepDataPacket( pathidx, (u8*)srcdata, size ); +} + +int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u32* srcdata, u32 size ) +{ + return PrepDataPacket( pathidx, (u8*)srcdata, size ); +} + +#ifdef PCSX2_GSRING_TX_STATS +static u32 ringtx_s=0; +static u32 ringtx_s_ulg=0; +static u32 ringtx_s_min=0xFFFFFFFF; +static u32 ringtx_s_max=0; +static u32 ringtx_c=0; +static u32 ringtx_inf[32][32]; +static u32 ringtx_inf_s[32]; +#endif + +#ifdef PCSX2_GSRING_SAMPLING_STATS +static u32 GSRingBufCopySz = 0; +#endif + +// returns the amount of giftag data not processed (in simd128 values). +// Return value is used by VU1 XGKICK to hack-fix data packets which are too +// large for VU1 memory. +// Parameters: +// size - size of the packet data, in smd128's +int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 size ) +{ +#ifdef PCSX2_GSRING_TX_STATS + ringtx_s+=size; + ringtx_s_ulg+=size&0x7F; + ringtx_s_min=min(ringtx_s_min,size); + ringtx_s_max=max(ringtx_s_max,size); + ringtx_c++; + unsigned long tx_sz; + if (_BitScanReverse(&tx_sz,size)) + { + unsigned long tx_algn; + _BitScanForward(&tx_algn,size); + ringtx_inf[tx_sz][tx_algn]++; + ringtx_inf_s[tx_sz]+=size; + } + if (ringtx_s>=128*1024*1024) + { + Console::Status("GSRingBufCopy:128MB in %d tx -> b/tx: AVG = %.2f , max = %d, min = %d",ringtx_c,ringtx_s/(float)ringtx_c,ringtx_s_max,ringtx_s_min); + for (int i=0;i<32;i++) + { + u32 total_bucket=0; + u32 bucket_subitems=0; + for (int j=0;j<32;j++) + { + if (ringtx_inf[i][j]) + { + total_bucket+=ringtx_inf[i][j]; + bucket_subitems++; + Console::Notice("GSRingBufCopy :tx [%d,%d] algn %d : count= %d [%.2f%%]",1<= readpos) + + PrepEventWait(); + while( true ) + { + uint readpos = volatize(m_RingPos); + if( writepos >= readpos ) break; + if( writepos+size < readpos ) break; + SpinWait(); + } + PostEventWait(); + } + } + else if( writepos + size > m_RingBufferSize ) + { + // If the incoming packet doesn't fit, then start over from + // the start of the ring buffer (it's a lot easier than trying + // to wrap the packet around the end of the buffer). + + // We have to be careful not to leapfrog our read-position. If it's + // greater than the current write position then we need to stall + // until it loops around to the beginning of the buffer + + PrepEventWait(); + while( true ) + { + uint readpos = volatize(m_RingPos); + + // is the buffer empty? + if( readpos == writepos ) break; + + // Also: Wait for the readpos to go past the start of the buffer + // Otherwise it'll stop dead in its tracks when we set the new write + // position below (bad!) + if( readpos < writepos && readpos != 0 ) break; + + SpinWait(); + } + + m_lock_RingRestart.Lock(); + SendSimplePacket( GS_RINGTYPE_RESTART, 0, 0, 0 ); + writepos = 0; + AtomicExchange( m_WritePos, writepos ); + m_lock_RingRestart.Unlock(); + SetEvent(); + + // stall until the read position is past the end of our incoming block, + // or until it reaches the current write position (signals an empty buffer). + while( true ) + { + uint readpos = volatize(m_RingPos); + + if( readpos == m_WritePos ) break; + if( writepos+size < readpos ) break; + + SpinWait(); + } + PostEventWait(); + } + else // always true - if( writepos + size == MTGS_RINGBUFFEREND ) + { + // Yay. Perfect fit. What are the odds? + //SysPrintf( "MTGS > Perfect Fit!\n"); + + PrepEventWait(); + while( true ) + { + uint readpos = volatize(m_RingPos); + + // stop waiting if the buffer is empty! + if( writepos == readpos ) break; + + // Copy is ready so long as readpos is less than writepos and *not* + // equal to the base of the ringbuffer (otherwise the buffer will stop + // when the writepos is wrapped around to zero later-on in SendDataPacket) + if( readpos < writepos && readpos != 0 ) break; + + SpinWait(); + } + PostEventWait(); + } + +#ifdef RINGBUF_DEBUG_STACK + m_lock_Stack.Lock(); + ringposStack.push_front( writepos ); + m_lock_Stack.Unlock(); +#endif + + // Command qword: Low word is the command, and the high word is the packet + // length in SIMDs (128 bits). + + PacketTagType& tag = (PacketTagType&)m_RingBuffer[m_WritePos]; + tag.command = pathidx+1; + tag.data[0] = m_packet_size; + m_packet_ringpos = m_WritePos + 1; + + return m_packet_size; +} + +__forceinline uint mtgsThreadObject::_PrepForSimplePacket() +{ +#ifdef RINGBUF_DEBUG_STACK + m_lock_Stack.Lock(); + ringposStack.push_front( m_WritePos ); + m_lock_Stack.Unlock(); +#endif + + uint future_writepos = m_WritePos+1; + jASSUME( future_writepos <= m_RingBufferSize ); + + future_writepos &= m_RingBufferMask; + + if( future_writepos == volatize(m_RingPos) ) + { + PrepEventWait(); + do + { + SpinWait(); + } while( future_writepos == volatize(m_RingPos) ); + PostEventWait(); + } + + return future_writepos; +} + +__forceinline void mtgsThreadObject::_FinishSimplePacket( uint future_writepos ) +{ + assert( future_writepos != volatize(m_RingPos) ); + AtomicExchange( m_WritePos, future_writepos ); +} + +void mtgsThreadObject::SendSimplePacket( GS_RINGTYPE type, int data0, int data1, int data2 ) +{ + const uint thefuture = _PrepForSimplePacket(); + PacketTagType& tag = (PacketTagType&)m_RingBuffer[m_WritePos]; + + tag.command = type; + tag.data[0] = data0; + tag.data[1] = data1; + tag.data[2] = data2; + + _FinishSimplePacket( thefuture ); +} + +void mtgsThreadObject::SendPointerPacket( GS_RINGTYPE type, u32 data0, void* data1 ) +{ + const uint thefuture = _PrepForSimplePacket(); + PacketTagType& tag = (PacketTagType&)m_RingBuffer[m_WritePos]; + + tag.command = type; + tag.data[0] = data0; + *(uptr*)&tag.data[1] = (uptr)data1; + + _FinishSimplePacket( thefuture ); +} + +// Waits for the GS to empty out the entire ring buffer contents. +// Used primarily for plugin startup/shutdown. +void mtgsWaitGS() +{ + if( mtgsThread == NULL ) return; + mtgsThread->WaitGS(); +} + +bool mtgsOpen() +{ + // Check the config flag since our thread object has yet to be created + if( !CHECK_MULTIGS ) return false; + + // better not be a thread already running, yo! + assert( mtgsThread == NULL ); + + try + { + mtgsThread = new mtgsThreadObject(); + } + catch( Exception::ThreadCreationError& ) + { + Console::Error( "MTGS > Thread creation failed!" ); + mtgsThread = NULL; + return false; + } + return true; +} + + +void mtgsThreadObject::GIFSoftReset( int mask ) +{ + if(mask & 1) memzero_obj(m_path[0]); + if(mask & 2) memzero_obj(m_path[1]); + if(mask & 4) memzero_obj(m_path[2]); + + if( GSgifSoftReset == NULL ) return; + + MTGS_LOG( "MTGS > Sending GIF Soft Reset (mask: %d)\n", mask ); + mtgsThread->SendSimplePacket( GS_RINGTYPE_SOFTRESET, mask, 0, 0 ); +} + +void mtgsThreadObject::Freeze( SaveState& state ) +{ + _mtgsFreezeGIF( state, this->m_path ); +} + +// this function is needed because of recompiled calls from iGS.cpp +// (currently used in GCC only) +void mtgsRingBufSimplePacket( s32 command, u32 data0, u32 data1, u32 data2 ) +{ + mtgsThread->SendSimplePacket( (GS_RINGTYPE)command, data0, data1, data2 ); +} diff --git a/pcsx2/Mdec.cpp b/pcsx2/Mdec.cpp index af7733e015..3b16800591 100644 --- a/pcsx2/Mdec.cpp +++ b/pcsx2/Mdec.cpp @@ -1,420 +1,420 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -/* This code was based on the FPSE v0.08 Mdec decoder*/ - -#include -#include - -#include "Misc.h" -#include "PsxCommon.h" -#include "Mdec.h" - -int iq_y[DCTSIZE2],iq_uv[DCTSIZE2]; - -static void idct1(int *block) -{ - int i, val; - - val = RANGE(DESCALE(block[0], PASS1_BITS+3)); - - for(i=0;i>16)*(bcr&0xffff); - - if (cmd==0x40000001) { - u8 *p = (u8*)PSXM(adr); - iqtab_init(iq_y,p); - iqtab_init(iq_uv,p+64); - } - else if ((cmd&0xf5ff0000)==0x30000000) { - mdec.rl = (u16*)PSXM(adr); - } - - HW_DMA0_CHCR &= ~0x01000000; - psxDmaInterrupt(0); -} - -void psxDma1(u32 adr, u32 bcr, u32 chcr) { - int blk[DCTSIZE2*6]; - unsigned short *image; - int size; - - CDR_LOG("DMA1 %lx %lx %lx (cmd = %lx)\n", adr, bcr, chcr, mdec.command); - - if (chcr!=0x01000200) return; - - size = (bcr>>16)*(bcr&0xffff); - image = (u16*)PSXM(adr); - if (mdec.command&0x08000000) { - for (;size>0;size-=(16*16)/2,image+=(16*16)) { - mdec.rl = rl2blk(blk,mdec.rl); - yuv2rgb15(blk,image); - } - } else { - for (;size>0;size-=(24*16)/2,image+=(24*16)) { - mdec.rl = rl2blk(blk,mdec.rl); - yuv2rgb24(blk,(u8 *)image); - } - } - - HW_DMA1_CHCR &= ~0x01000000; - psxDmaInterrupt(1); -} - -static int zscan[DCTSIZE2] = { - 0 ,1 ,8 ,16,9 ,2 ,3 ,10, - 17,24,32,25,18,11,4 ,5 , - 12,19,26,33,40,48,41,34, - 27,20,13,6 ,7 ,14,21,28, - 35,42,49,56,57,50,43,36, - 29,22,15,23,30,37,44,51, - 58,59,52,45,38,31,39,46, - 53,60,61,54,47,55,62,63 -}; - -static int aanscales[DCTSIZE2] = { - 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, - 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, - 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, - 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, - 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, - 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, - 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, - 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 -}; - -void iqtab_init(int *iqtab,unsigned char *iq_y) -{ - int i; - - for(i=0;i>(CONST_BITS14-IFAST_SCALE_BITS); - } -} - -unsigned short* rl2blk(int *blk,unsigned short *mdec_rl) { - int i,k,q_scale,rl; - int *iqtab; - - memset (blk, 0, 6*DCTSIZE2*4); - iqtab = iq_uv; - for(i=0;i<6;i++) { // decode blocks (Cr,Cb,Y1,Y2,Y3,Y4) - if (i>1) iqtab = iq_y; - - // zigzag transformation - rl = *mdec_rl++; - q_scale = RUNOF(rl); - blk[0] = iqtab[0]*VALOF(rl); - for(k = 0;;) { - rl = *mdec_rl++; - if (rl==NOP) break; - k += RUNOF(rl)+1; // skip level zero-coefficients - if (k > 63) break; - blk[zscan[k]] = (VALOF(rl) * iqtab[k] * q_scale) / 8; // / 16; - } - - idct(blk,k+1); - blk+=DCTSIZE2; - } - return mdec_rl; -} - -unsigned char roundtbl[256*3]; - -void round_init(void) { - int i; - for(i=0;i<256;i++) { - roundtbl[i]=0; - roundtbl[i+256]=i; - roundtbl[i+512]=255; - } -} - -void yuv2rgb15(int *blk,unsigned short *image) { - int x,y; - int *Yblk = blk+DCTSIZE2*2; - int Cb,Cr,R,G,B; - int *Cbblk = blk; - int *Crblk = blk+DCTSIZE2; - - if (!(Config.Mdec&0x1)) - for (y=0;y<16;y+=2,Crblk+=4,Cbblk+=4,Yblk+=8,image+=24) { - if (y==8) Yblk+=DCTSIZE2; - for (x=0;x<4;x++,image+=2,Crblk++,Cbblk++,Yblk+=2) { - Cr = *Crblk; - Cb = *Cbblk; - R = MULR(Cr); - G = MULG(Cb) + MULG2(Cr); - B = MULB(Cb); - - RGB15(0, Yblk[0]); - RGB15(1, Yblk[1]); - RGB15(16, Yblk[8]); - RGB15(17, Yblk[9]); - - Cr = *(Crblk+4); - Cb = *(Cbblk+4); - R = MULR(Cr); - G = MULG(Cb) + MULG2(Cr); - B = MULB(Cb); - - RGB15(8, Yblk[DCTSIZE2+0]); - RGB15(9, Yblk[DCTSIZE2+1]); - RGB15(24, Yblk[DCTSIZE2+8]); - RGB15(25, Yblk[DCTSIZE2+9]); - } - } else - for (y=0;y<16;y+=2,Yblk+=8,image+=24) { - if (y==8) Yblk+=DCTSIZE2; - for (x=0;x<4;x++,image+=2,Yblk+=2) { - RGB15BW(0, Yblk[0]); - RGB15BW(1, Yblk[1]); - RGB15BW(16, Yblk[8]); - RGB15BW(17, Yblk[9]); - - RGB15BW(8, Yblk[DCTSIZE2+0]); - RGB15BW(9, Yblk[DCTSIZE2+1]); - RGB15BW(24, Yblk[DCTSIZE2+8]); - RGB15BW(25, Yblk[DCTSIZE2+9]); - } - } -} - -void yuv2rgb24(int *blk,unsigned char *image) { - int x,y; - int *Yblk = blk+DCTSIZE2*2; - int Cb,Cr,R,G,B; - int *Cbblk = blk; - int *Crblk = blk+DCTSIZE2; - - if (!(Config.Mdec&0x1)) - for (y=0;y<16;y+=2,Crblk+=4,Cbblk+=4,Yblk+=8,image+=24*3) { - if (y==8) Yblk+=DCTSIZE2; - for (x=0;x<4;x++,image+=6,Crblk++,Cbblk++,Yblk+=2) { - Cr = *Crblk; - Cb = *Cbblk; - R = MULR(Cr); - G = MULG(Cb) + MULG2(Cr); - B = MULB(Cb); - - RGB24(0, Yblk[0]); - RGB24(1*3, Yblk[1]); - RGB24(16*3, Yblk[8]); - RGB24(17*3, Yblk[9]); - - Cr = *(Crblk+4); - Cb = *(Cbblk+4); - R = MULR(Cr); - G = MULG(Cb) + MULG2(Cr); - B = MULB(Cb); - - RGB24(8*3, Yblk[DCTSIZE2+0]); - RGB24(9*3, Yblk[DCTSIZE2+1]); - RGB24(24*3, Yblk[DCTSIZE2+8]); - RGB24(25*3, Yblk[DCTSIZE2+9]); - } - } else - for (y=0;y<16;y+=2,Yblk+=8,image+=24*3) { - if (y==8) Yblk+=DCTSIZE2; - for (x=0;x<4;x++,image+=6,Yblk+=2) { - RGB24BW(0, Yblk[0]); - RGB24BW(1*3, Yblk[1]); - RGB24BW(16*3, Yblk[8]); - RGB24BW(17*3, Yblk[9]); - - RGB24BW(8*3, Yblk[DCTSIZE2+0]); - RGB24BW(9*3, Yblk[DCTSIZE2+1]); - RGB24BW(24*3, Yblk[DCTSIZE2+8]); - RGB24BW(25*3, Yblk[DCTSIZE2+9]); - } - } -} - -int SaveState::mdecFreeze() { - Freeze(mdec); - Freeze(iq_y); - Freeze(iq_uv); - - return 0; - -} - - - - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +/* This code was based on the FPSE v0.08 Mdec decoder*/ + +#include +#include + +#include "Misc.h" +#include "PsxCommon.h" +#include "Mdec.h" + +int iq_y[DCTSIZE2],iq_uv[DCTSIZE2]; + +static void idct1(int *block) +{ + int i, val; + + val = RANGE(DESCALE(block[0], PASS1_BITS+3)); + + for(i=0;i>16)*(bcr&0xffff); + + if (cmd==0x40000001) { + u8 *p = (u8*)PSXM(adr); + iqtab_init(iq_y,p); + iqtab_init(iq_uv,p+64); + } + else if ((cmd&0xf5ff0000)==0x30000000) { + mdec.rl = (u16*)PSXM(adr); + } + + HW_DMA0_CHCR &= ~0x01000000; + psxDmaInterrupt(0); +} + +void psxDma1(u32 adr, u32 bcr, u32 chcr) { + int blk[DCTSIZE2*6]; + unsigned short *image; + int size; + + CDR_LOG("DMA1 %lx %lx %lx (cmd = %lx)\n", adr, bcr, chcr, mdec.command); + + if (chcr!=0x01000200) return; + + size = (bcr>>16)*(bcr&0xffff); + image = (u16*)PSXM(adr); + if (mdec.command&0x08000000) { + for (;size>0;size-=(16*16)/2,image+=(16*16)) { + mdec.rl = rl2blk(blk,mdec.rl); + yuv2rgb15(blk,image); + } + } else { + for (;size>0;size-=(24*16)/2,image+=(24*16)) { + mdec.rl = rl2blk(blk,mdec.rl); + yuv2rgb24(blk,(u8 *)image); + } + } + + HW_DMA1_CHCR &= ~0x01000000; + psxDmaInterrupt(1); +} + +static int zscan[DCTSIZE2] = { + 0 ,1 ,8 ,16,9 ,2 ,3 ,10, + 17,24,32,25,18,11,4 ,5 , + 12,19,26,33,40,48,41,34, + 27,20,13,6 ,7 ,14,21,28, + 35,42,49,56,57,50,43,36, + 29,22,15,23,30,37,44,51, + 58,59,52,45,38,31,39,46, + 53,60,61,54,47,55,62,63 +}; + +static int aanscales[DCTSIZE2] = { + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 +}; + +void iqtab_init(int *iqtab,unsigned char *iq_y) +{ + int i; + + for(i=0;i>(CONST_BITS14-IFAST_SCALE_BITS); + } +} + +unsigned short* rl2blk(int *blk,unsigned short *mdec_rl) { + int i,k,q_scale,rl; + int *iqtab; + + memset (blk, 0, 6*DCTSIZE2*4); + iqtab = iq_uv; + for(i=0;i<6;i++) { // decode blocks (Cr,Cb,Y1,Y2,Y3,Y4) + if (i>1) iqtab = iq_y; + + // zigzag transformation + rl = *mdec_rl++; + q_scale = RUNOF(rl); + blk[0] = iqtab[0]*VALOF(rl); + for(k = 0;;) { + rl = *mdec_rl++; + if (rl==NOP) break; + k += RUNOF(rl)+1; // skip level zero-coefficients + if (k > 63) break; + blk[zscan[k]] = (VALOF(rl) * iqtab[k] * q_scale) / 8; // / 16; + } + + idct(blk,k+1); + blk+=DCTSIZE2; + } + return mdec_rl; +} + +unsigned char roundtbl[256*3]; + +void round_init(void) { + int i; + for(i=0;i<256;i++) { + roundtbl[i]=0; + roundtbl[i+256]=i; + roundtbl[i+512]=255; + } +} + +void yuv2rgb15(int *blk,unsigned short *image) { + int x,y; + int *Yblk = blk+DCTSIZE2*2; + int Cb,Cr,R,G,B; + int *Cbblk = blk; + int *Crblk = blk+DCTSIZE2; + + if (!(Config.Mdec&0x1)) + for (y=0;y<16;y+=2,Crblk+=4,Cbblk+=4,Yblk+=8,image+=24) { + if (y==8) Yblk+=DCTSIZE2; + for (x=0;x<4;x++,image+=2,Crblk++,Cbblk++,Yblk+=2) { + Cr = *Crblk; + Cb = *Cbblk; + R = MULR(Cr); + G = MULG(Cb) + MULG2(Cr); + B = MULB(Cb); + + RGB15(0, Yblk[0]); + RGB15(1, Yblk[1]); + RGB15(16, Yblk[8]); + RGB15(17, Yblk[9]); + + Cr = *(Crblk+4); + Cb = *(Cbblk+4); + R = MULR(Cr); + G = MULG(Cb) + MULG2(Cr); + B = MULB(Cb); + + RGB15(8, Yblk[DCTSIZE2+0]); + RGB15(9, Yblk[DCTSIZE2+1]); + RGB15(24, Yblk[DCTSIZE2+8]); + RGB15(25, Yblk[DCTSIZE2+9]); + } + } else + for (y=0;y<16;y+=2,Yblk+=8,image+=24) { + if (y==8) Yblk+=DCTSIZE2; + for (x=0;x<4;x++,image+=2,Yblk+=2) { + RGB15BW(0, Yblk[0]); + RGB15BW(1, Yblk[1]); + RGB15BW(16, Yblk[8]); + RGB15BW(17, Yblk[9]); + + RGB15BW(8, Yblk[DCTSIZE2+0]); + RGB15BW(9, Yblk[DCTSIZE2+1]); + RGB15BW(24, Yblk[DCTSIZE2+8]); + RGB15BW(25, Yblk[DCTSIZE2+9]); + } + } +} + +void yuv2rgb24(int *blk,unsigned char *image) { + int x,y; + int *Yblk = blk+DCTSIZE2*2; + int Cb,Cr,R,G,B; + int *Cbblk = blk; + int *Crblk = blk+DCTSIZE2; + + if (!(Config.Mdec&0x1)) + for (y=0;y<16;y+=2,Crblk+=4,Cbblk+=4,Yblk+=8,image+=24*3) { + if (y==8) Yblk+=DCTSIZE2; + for (x=0;x<4;x++,image+=6,Crblk++,Cbblk++,Yblk+=2) { + Cr = *Crblk; + Cb = *Cbblk; + R = MULR(Cr); + G = MULG(Cb) + MULG2(Cr); + B = MULB(Cb); + + RGB24(0, Yblk[0]); + RGB24(1*3, Yblk[1]); + RGB24(16*3, Yblk[8]); + RGB24(17*3, Yblk[9]); + + Cr = *(Crblk+4); + Cb = *(Cbblk+4); + R = MULR(Cr); + G = MULG(Cb) + MULG2(Cr); + B = MULB(Cb); + + RGB24(8*3, Yblk[DCTSIZE2+0]); + RGB24(9*3, Yblk[DCTSIZE2+1]); + RGB24(24*3, Yblk[DCTSIZE2+8]); + RGB24(25*3, Yblk[DCTSIZE2+9]); + } + } else + for (y=0;y<16;y+=2,Yblk+=8,image+=24*3) { + if (y==8) Yblk+=DCTSIZE2; + for (x=0;x<4;x++,image+=6,Yblk+=2) { + RGB24BW(0, Yblk[0]); + RGB24BW(1*3, Yblk[1]); + RGB24BW(16*3, Yblk[8]); + RGB24BW(17*3, Yblk[9]); + + RGB24BW(8*3, Yblk[DCTSIZE2+0]); + RGB24BW(9*3, Yblk[DCTSIZE2+1]); + RGB24BW(24*3, Yblk[DCTSIZE2+8]); + RGB24BW(25*3, Yblk[DCTSIZE2+9]); + } + } +} + +int SaveState::mdecFreeze() { + Freeze(mdec); + Freeze(iq_y); + Freeze(iq_uv); + + return 0; + +} + + + + diff --git a/pcsx2/Mdec.h b/pcsx2/Mdec.h index ca9f4dfefd..e54dae3a9e 100644 --- a/pcsx2/Mdec.h +++ b/pcsx2/Mdec.h @@ -1,110 +1,110 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __MDEC_H__ -#define __MDEC_H__ - - -// mdec status: -#define MDEC_BUSY 0x20000000 -#define MDEC_DREQ 0x18000000 -#define MDEC_FIFO 0xc0000000 -#define MDEC_RGB24 0x02000000 -#define MDEC_STP 0x00800000 - - -#define CONST_BITS 8 -#define PASS1_BITS 2 -#define CONST_BITS14 14 -#define IFAST_SCALE_BITS 2 - -#define FIX_1_082392200 (277) -#define FIX_1_414213562 (362) -#define FIX_1_847759065 (473) -#define FIX_2_613125930 (669) - -#define MULTIPLY(var,const) (DESCALE((var) * (const), CONST_BITS)) - -#define DEQUANTIZE(coef,quantval) (coef) - -#define DESCALE(x,n) ((x)>>(n)) -#define RANGE(n) (n) - -#define DCTSIZE 8 -#define DCTSIZE2 64 - -#define RUNOF(a) ((a)>>10) -#define VALOF(a) (((int)(a)<<(32-10))>>(32-10)) -#define NOP 0xfe00 - -#define FIXED - -#ifdef FIXED -#define MULR(a) ((((int)0x0000059B) * (a)) >> 10) -#define MULG(a) ((((int)0xFFFFFEA1) * (a)) >> 10) -#define MULG2(a) ((((int)0xFFFFFD25) * (a)) >> 10) -#define MULB(a) ((((int)0x00000716) * (a)) >> 10) -#else -#define MULR(a) ((int)((float)1.40200 * (a))) -#define MULG(a) ((int)((float)-0.3437 * (a))) -#define MULG2(a) ((int)((float)-0.7143 * (a))) -#define MULB(a) ((int)((float)1.77200 * (a))) -#endif - -#define MAKERGB15(r,g,b) ( (((r)>>3)<<10)|(((g)>>3)<<5)|((b)>>3) ) -#define ROUND(c) roundtbl[((c)+128+256)]//&0x3ff] - -#define RGB15(n, Y) \ - image[n] = MAKERGB15(ROUND(Y + R),ROUND(Y + G),ROUND(Y + B)); - -#define RGB15BW(n, Y) \ - image[n] = MAKERGB15(ROUND(Y),ROUND(Y),ROUND(Y)); - -#define RGB24(n, Y) \ - image[n+2] = ROUND(Y + R); \ - image[n+1] = ROUND(Y + G); \ - image[n+0] = ROUND(Y + B); - -#define RGB24BW(n, Y) \ - image[n+2] = ROUND(Y); \ - image[n+1] = ROUND(Y); \ - image[n+0] = ROUND(Y); - -void mdecInit(); -void mdecWrite0(u32 data); -void mdecWrite1(u32 data); -u32 mdecRead0(); -u32 mdecRead1(); -void psxDma0(u32 madr, u32 bcr, u32 chcr); -void psxDma1(u32 madr, u32 bcr, u32 chcr); -int mdecFreeze(gzFile f, int Mode); - -unsigned short* rl2blk(int *blk,unsigned short *mdec_rl); -void iqtab_init(int *iqtab,unsigned char *iq_y); -void round_init(void); -void yuv2rgb24(int *blk,unsigned char *image); -void yuv2rgb15(int *blk,unsigned short *image); - -struct { - unsigned long command; - unsigned long status; - unsigned short *rl; - int rlsize; -} mdec; - -#endif /* __MDEC_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __MDEC_H__ +#define __MDEC_H__ + + +// mdec status: +#define MDEC_BUSY 0x20000000 +#define MDEC_DREQ 0x18000000 +#define MDEC_FIFO 0xc0000000 +#define MDEC_RGB24 0x02000000 +#define MDEC_STP 0x00800000 + + +#define CONST_BITS 8 +#define PASS1_BITS 2 +#define CONST_BITS14 14 +#define IFAST_SCALE_BITS 2 + +#define FIX_1_082392200 (277) +#define FIX_1_414213562 (362) +#define FIX_1_847759065 (473) +#define FIX_2_613125930 (669) + +#define MULTIPLY(var,const) (DESCALE((var) * (const), CONST_BITS)) + +#define DEQUANTIZE(coef,quantval) (coef) + +#define DESCALE(x,n) ((x)>>(n)) +#define RANGE(n) (n) + +#define DCTSIZE 8 +#define DCTSIZE2 64 + +#define RUNOF(a) ((a)>>10) +#define VALOF(a) (((int)(a)<<(32-10))>>(32-10)) +#define NOP 0xfe00 + +#define FIXED + +#ifdef FIXED +#define MULR(a) ((((int)0x0000059B) * (a)) >> 10) +#define MULG(a) ((((int)0xFFFFFEA1) * (a)) >> 10) +#define MULG2(a) ((((int)0xFFFFFD25) * (a)) >> 10) +#define MULB(a) ((((int)0x00000716) * (a)) >> 10) +#else +#define MULR(a) ((int)((float)1.40200 * (a))) +#define MULG(a) ((int)((float)-0.3437 * (a))) +#define MULG2(a) ((int)((float)-0.7143 * (a))) +#define MULB(a) ((int)((float)1.77200 * (a))) +#endif + +#define MAKERGB15(r,g,b) ( (((r)>>3)<<10)|(((g)>>3)<<5)|((b)>>3) ) +#define ROUND(c) roundtbl[((c)+128+256)]//&0x3ff] + +#define RGB15(n, Y) \ + image[n] = MAKERGB15(ROUND(Y + R),ROUND(Y + G),ROUND(Y + B)); + +#define RGB15BW(n, Y) \ + image[n] = MAKERGB15(ROUND(Y),ROUND(Y),ROUND(Y)); + +#define RGB24(n, Y) \ + image[n+2] = ROUND(Y + R); \ + image[n+1] = ROUND(Y + G); \ + image[n+0] = ROUND(Y + B); + +#define RGB24BW(n, Y) \ + image[n+2] = ROUND(Y); \ + image[n+1] = ROUND(Y); \ + image[n+0] = ROUND(Y); + +void mdecInit(); +void mdecWrite0(u32 data); +void mdecWrite1(u32 data); +u32 mdecRead0(); +u32 mdecRead1(); +void psxDma0(u32 madr, u32 bcr, u32 chcr); +void psxDma1(u32 madr, u32 bcr, u32 chcr); +int mdecFreeze(gzFile f, int Mode); + +unsigned short* rl2blk(int *blk,unsigned short *mdec_rl); +void iqtab_init(int *iqtab,unsigned char *iq_y); +void round_init(void); +void yuv2rgb24(int *blk,unsigned char *image); +void yuv2rgb15(int *blk,unsigned short *image); + +struct { + unsigned long command; + unsigned long status; + unsigned short *rl; + int rlsize; +} mdec; + +#endif /* __MDEC_H__ */ diff --git a/pcsx2/MemcpyFast.h b/pcsx2/MemcpyFast.h index c6bc23247f..6fda7b772e 100644 --- a/pcsx2/MemcpyFast.h +++ b/pcsx2/MemcpyFast.h @@ -1,59 +1,59 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __MEMCPY_FAST_H__ -#define __MEMCPY_FAST_H__ - -//#include "Misc.h" - -void _memset16_unaligned( void* dest, u16 data, size_t size ); - -#if defined(_WIN32) && !defined(__x86_64__) - - // The new simplified memcpy_amd_ is now faster than memcpy_raz_. - // memcpy_amd_ also does mmx register saving, negating the need for freezeregs (code cleanup!) - // Additionally, using one single memcpy implementation keeps the code cache cleaner. - - //extern void __fastcall memcpy_raz_udst(void *dest, const void *src, size_t bytes); - //extern void __fastcall memcpy_raz_usrc(void *dest, const void *src, size_t bytes); - //extern void __fastcall memcpy_raz_(void *dest, const void *src, size_t bytes); - extern void __fastcall memcpy_amd_(void *dest, const void *src, size_t bytes); - -# include "windows/memzero.h" -# define memcpy_fast memcpy_amd_ -# define memcpy_aligned memcpy_amd_ - -#else - - // for now linux uses the GCC memcpy/memset implementations. - #define memcpy_fast memcpy - #define memcpy_raz_ memcpy - #define memcpy_raz_u memcpy - - #define memcpy_aligned memcpy - #define memcpy_raz_u memcpy - - #include "Linux/memzero.h" - -#endif - - -extern u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize); -extern void memxor_mmx(void* dst, const void* src1, int cmpsize); - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __MEMCPY_FAST_H__ +#define __MEMCPY_FAST_H__ + +//#include "Misc.h" + +void _memset16_unaligned( void* dest, u16 data, size_t size ); + +#if defined(_WIN32) && !defined(__x86_64__) + + // The new simplified memcpy_amd_ is now faster than memcpy_raz_. + // memcpy_amd_ also does mmx register saving, negating the need for freezeregs (code cleanup!) + // Additionally, using one single memcpy implementation keeps the code cache cleaner. + + //extern void __fastcall memcpy_raz_udst(void *dest, const void *src, size_t bytes); + //extern void __fastcall memcpy_raz_usrc(void *dest, const void *src, size_t bytes); + //extern void __fastcall memcpy_raz_(void *dest, const void *src, size_t bytes); + extern void __fastcall memcpy_amd_(void *dest, const void *src, size_t bytes); + +# include "windows/memzero.h" +# define memcpy_fast memcpy_amd_ +# define memcpy_aligned memcpy_amd_ + +#else + + // for now linux uses the GCC memcpy/memset implementations. + #define memcpy_fast memcpy + #define memcpy_raz_ memcpy + #define memcpy_raz_u memcpy + + #define memcpy_aligned memcpy + #define memcpy_raz_u memcpy + + #include "Linux/memzero.h" + +#endif + + +extern u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize); +extern void memxor_mmx(void* dst, const void* src1, int cmpsize); + +#endif diff --git a/pcsx2/Memory.cpp b/pcsx2/Memory.cpp index 7212f54f50..b65441ffc9 100644 --- a/pcsx2/Memory.cpp +++ b/pcsx2/Memory.cpp @@ -1,952 +1,952 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -/* - -RAM ---- -0x00100000-0x01ffffff this is the physical address for the ram.its cached there -0x20100000-0x21ffffff uncached -0x30100000-0x31ffffff uncached & acceleretade -0xa0000000-0xa1ffffff MIRROR might...??? -0x80000000-0x81ffffff MIRROR might... ???? - -scratch pad ----------- -0x70000000-0x70003fff scratch pad - -BIOS ----- -0x1FC00000 - 0x1FFFFFFF un-cached -0x9FC00000 - 0x9FFFFFFF cached -0xBFC00000 - 0xBFFFFFFF un-cached -*/ - -#include "PrecompiledHeader.h" - -#pragma warning(disable:4799) // No EMMS at end of function - -#include - -#include "Common.h" -#include "iR5900.h" - -#include "PsxCommon.h" -#include "VUmicro.h" -#include "GS.h" -#include "vtlb.h" -#include "IPU/IPU.h" - - -#ifdef ENABLECACHE -#include "Cache.h" -#endif - -#ifdef __LINUX__ -#include -#endif - -//#define FULLTLB -int MemMode = 0; // 0 is Kernel Mode, 1 is Supervisor Mode, 2 is User Mode - -void memSetKernelMode() { - //Do something here - MemMode = 0; -} - -void memSetSupervisorMode() { -} - -void memSetUserMode() { - -} - -u16 ba0R16(u32 mem) -{ - //MEM_LOG("ba00000 Memory read16 address %x\n", mem); - - if (mem == 0x1a000006) { - static int ba6; - ba6++; - if (ba6 == 3) ba6 = 0; - return ba6; - } - return 0; -} - - -// Attempts to load a BIOS rom file, by trying multiple combinations of base filename -// and extension. The bios specified in Config.Bios is used as the base. -void loadBiosRom( const char *ext, u8 *dest, long maxSize ) -{ - string Bios1; - string Bios; - long filesize; - - Path::Combine( Bios, Config.BiosDir, Config.Bios ); - - // Try first a basic extension concatenation (normally results in something like name.bin.rom1) - ssprintf(Bios1, "%hs.%s", &Bios, ext); - if( (filesize=Path::getFileSize( Bios1 ) ) <= 0 ) - { - // Try the name properly extensioned next (name.rom1) - Path::ReplaceExtension( Bios1, Bios, ext ); - if( (filesize=Path::getFileSize( Bios1 ) ) <= 0 ) - { - // Try for the old-style method (rom1.bin) - Path::Combine( Bios1, Config.BiosDir, ext ); - Bios1 += ".bin"; - if( (filesize=Path::getFileSize( Bios1 ) ) <= 0 ) - { - Console::Error( "\n\n\n" - "**************\n" - "%s NOT FOUND\n" - "**************\n\n\n", params ext - ); - return; - } - } - } - - // if we made it this far, we have a successful file found: - - FILE *fp = fopen(Bios1.c_str(), "rb"); - fread(dest, 1, std::min( maxSize, filesize ), fp); - fclose(fp); -} - -u32 psMPWC[(Ps2MemSize::Base/32)>>12]; -std::vector psMPWVA[Ps2MemSize::Base>>12]; - -u8 *psM = NULL; //32mb Main Ram -u8 *psR = NULL; //4mb rom area -u8 *psR1 = NULL; //256kb rom1 area (actually 196kb, but can't mask this) -u8 *psR2 = NULL; // 0x00080000 -u8 *psER = NULL; // 0x001C0000 -u8 *psS = NULL; //0.015 mb, scratch pad - -#define CHECK_MEM(mem) //MyMemCheck(mem) - -void MyMemCheck(u32 mem) -{ - if( mem == 0x1c02f2a0 ) - SysPrintf("yo\n"); -} - -///////////////////////////// -// REGULAR MEM START -///////////////////////////// -vtlbHandler tlb_fallback_0; -vtlbHandler tlb_fallback_1; -vtlbHandler tlb_fallback_2; -vtlbHandler tlb_fallback_3; -vtlbHandler tlb_fallback_4; -vtlbHandler tlb_fallback_5; -vtlbHandler tlb_fallback_6; -vtlbHandler tlb_fallback_7; -vtlbHandler tlb_fallback_8; - -vtlbHandler vu0_micro_mem[2]; // 0 - dynarec, 1 - interpreter -vtlbHandler vu1_micro_mem[2]; // 0 - dynarec, 1 - interpreter - -vtlbHandler hw_by_page[0x10]; -vtlbHandler gs_page_0; -vtlbHandler gs_page_1; - - -// Used to remap the VUmicro memory according to the VU0/VU1 dynarec setting. -// (the VU memory operations are different for recs vs. interpreters) -void memMapVUmicro() -{ - vtlb_MapHandler(vu0_micro_mem[CHECK_VU0REC ? 0 : 1],0x11000000,0x00004000); - vtlb_MapHandler(vu1_micro_mem[CHECK_VU1REC ? 0 : 1],0x11008000,0x00004000); - - vtlb_MapBlock(VU0.Mem,0x11004000,0x00004000,0x1000); - vtlb_MapBlock(VU1.Mem,0x1100c000,0x00004000); -} - -void memMapPhy() -{ - //Main mem - vtlb_MapBlock(psM,0x00000000,Ps2MemSize::Base);//mirrored on first 256 mb ? - - //Rom - vtlb_MapBlock(psR,0x1fc00000,Ps2MemSize::Rom);//Writable ? - //Rom 1 - vtlb_MapBlock(psR1,0x1e000000,Ps2MemSize::Rom1);//Writable ? - //Rom 2 ? - vtlb_MapBlock(psR2,0x1e400000,Ps2MemSize::Rom2);//Writable ? - //EEProm ? - vtlb_MapBlock(psER,0x1e040000,Ps2MemSize::ERom);//Writable ? - - //IOP mem - vtlb_MapBlock(psxM,0x1c000000,0x00800000); - - //These fallback to mem* stuff ... - vtlb_MapHandler(tlb_fallback_1,0x10000000,0x10000); - vtlb_MapHandler(tlb_fallback_7,0x14000000,0x10000); - vtlb_MapHandler(tlb_fallback_4,0x18000000,0x10000); - vtlb_MapHandler(tlb_fallback_5,0x1a000000,0x10000); - vtlb_MapHandler(tlb_fallback_6,0x12000000,0x10000); - vtlb_MapHandler(tlb_fallback_8,0x1f000000,0x10000); - vtlb_MapHandler(tlb_fallback_3,0x1f400000,0x10000); - vtlb_MapHandler(tlb_fallback_2,0x1f800000,0x10000); - vtlb_MapHandler(tlb_fallback_8,0x1f900000,0x10000); - -#ifdef PCSX2_DEVBUILD - // Bind fallback handlers used for logging purposes only. - // In release mode the Vtlb will map these addresses directly instead of using - // the read/write handlers (which just issue logs and do normal memOps) -#endif - - // map specific optimized page handlers for HW accesses - vtlb_MapHandler(hw_by_page[0x0], 0x10000000, 0x01000); - vtlb_MapHandler(hw_by_page[0x1], 0x10001000, 0x01000); - vtlb_MapHandler(hw_by_page[0x2], 0x10002000, 0x01000); - vtlb_MapHandler(hw_by_page[0x3], 0x10003000, 0x01000); - vtlb_MapHandler(hw_by_page[0x4], 0x10004000, 0x01000); - vtlb_MapHandler(hw_by_page[0x5], 0x10005000, 0x01000); - vtlb_MapHandler(hw_by_page[0x6], 0x10006000, 0x01000); - vtlb_MapHandler(hw_by_page[0x7], 0x10007000, 0x01000); - vtlb_MapHandler(hw_by_page[0xb], 0x1000b000, 0x01000); - vtlb_MapHandler(hw_by_page[0xe], 0x1000e000, 0x01000); - vtlb_MapHandler(hw_by_page[0xf], 0x1000f000, 0x01000); - - vtlb_MapHandler(gs_page_0, 0x12000000, 0x01000); - vtlb_MapHandler(gs_page_1, 0x12001000, 0x01000); -} - -//Why is this required ? -void memMapKernelMem() -{ - //lower 512 mb: direct map - //vtlb_VMap(0x00000000,0x00000000,0x20000000); - //0x8* mirror - vtlb_VMap(0x80000000,0x00000000,0x20000000); - //0xa* mirror - vtlb_VMap(0xA0000000,0x00000000,0x20000000); -} - -//what do do with these ? -void memMapSupervisorMem() -{ -} - -void memMapUserMem() -{ -} - -template -mem8_t __fastcall _ext_memRead8 (u32 mem) -{ - switch (p) - { - case 1: // hwm - return hwRead8(mem); - case 2: // psh - return psxHwRead8(mem); - case 3: // psh4 - return psxHw4Read8(mem); - case 6: // gsm - return gsRead8(mem); - case 7: // dev9 - { - mem8_t retval = DEV9read8(mem & ~0xa4000000); - SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0xa4000000, retval); - return retval; - } - } - - MEM_LOG("Unknown Memory Read8 from address %8.8x\n", mem); - cpuTlbMissR(mem, cpuRegs.branch); - return 0; -} - -template -mem16_t __fastcall _ext_memRead16(u32 mem) -{ - switch (p) - { - case 1: // hwm - return hwRead16(mem); - case 2: // psh - return psxHwRead16(mem); - case 4: // b80 - MEM_LOG("b800000 Memory read16 address %x\n", mem); - return 0; - case 5: // ba0 - return ba0R16(mem); - case 6: // gsm - return gsRead16(mem); - - case 7: // dev9 - { - mem16_t retval = DEV9read16(mem & ~0xa4000000); - SysPrintf("DEV9 read16 %8.8lx: %4.4lx\n", mem & ~0xa4000000, retval); - return retval; - } - - case 8: // spu2 - return SPU2read(mem); - } - MEM_LOG("Unknown Memory read16 from address %8.8x\n", mem); - cpuTlbMissR(mem, cpuRegs.branch); - return 0; -} - -template -mem32_t __fastcall _ext_memRead32(u32 mem) -{ - switch (p) - { - case 2: // psh - return psxHwRead32(mem); - case 6: // gsm - return gsRead32(mem); - case 7: // dev9 - { - mem32_t retval = DEV9read32(mem & ~0xa4000000); - SysPrintf("DEV9 read32 %8.8lx: %8.8lx\n", mem & ~0xa4000000, retval); - return retval; - } - } - - MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val); - cpuTlbMissR(mem, cpuRegs.branch); - return 0; -} - -template -void __fastcall _ext_memRead64(u32 mem, mem64_t *out) -{ - switch (p) - { - case 6: // gsm - *out = gsRead64(mem); return; - } - - MEM_LOG("Unknown Memory read64 from address %8.8x\n", mem); - cpuTlbMissR(mem, cpuRegs.branch); -} - -template -void __fastcall _ext_memRead128(u32 mem, mem128_t *out) -{ - switch (p) - { - //case 1: // hwm - // hwRead128(mem & ~0xa0000000, out); return; - case 6: // gsm - out[0] = gsRead64(mem ); - out[1] = gsRead64(mem+8); return; - } - - MEM_LOG("Unknown Memory read128 from address %8.8x\n", mem); - cpuTlbMissR(mem, cpuRegs.branch); -} - -template -void __fastcall _ext_memWrite8 (u32 mem, u8 value) -{ - switch (p) { - case 1: // hwm - hwWrite8(mem, value); - return; - case 2: // psh - psxHwWrite8(mem, value); return; - case 3: // psh4 - psxHw4Write8(mem, value); return; - case 6: // gsm - gsWrite8(mem, value); return; - case 7: // dev9 - DEV9write8(mem & ~0xa4000000, value); - SysPrintf("DEV9 write8 %8.8lx: %2.2lx\n", mem & ~0xa4000000, value); - return; - } - - MEM_LOG("Unknown Memory write8 to address %x with data %2.2x\n", mem, value); - cpuTlbMissW(mem, cpuRegs.branch); -} -template -void __fastcall _ext_memWrite16(u32 mem, u16 value) -{ - switch (p) { - case 1: // hwm - hwWrite16(mem, value); - return; - case 2: // psh - psxHwWrite16(mem, value); return; - case 5: // ba0 - MEM_LOG("ba00000 Memory write16 to address %x with data %x\n", mem, value); - return; - case 6: // gsm - gsWrite16(mem, value); return; - case 7: // dev9 - DEV9write16(mem & ~0xa4000000, value); - SysPrintf("DEV9 write16 %8.8lx: %4.4lx\n", mem & ~0xa4000000, value); - return; - case 8: // spu2 - SPU2write(mem, value); return; - } - MEM_LOG("Unknown Memory write16 to address %x with data %4.4x\n", mem, value); - cpuTlbMissW(mem, cpuRegs.branch); -} -template -void __fastcall _ext_memWrite32(u32 mem, u32 value) -{ - switch (p) { - case 2: // psh - psxHwWrite32(mem, value); return; - case 6: // gsm - gsWrite32(mem, value); return; - case 7: // dev9 - DEV9write32(mem & ~0xa4000000, value); - SysPrintf("DEV9 write32 %8.8lx: %8.8lx\n", mem & ~0xa4000000, value); - return; - } - MEM_LOG("Unknown Memory write32 to address %x with data %8.8x\n", mem, value); - cpuTlbMissW(mem, cpuRegs.branch); -} -template -void __fastcall _ext_memWrite64(u32 mem, const u64* value) -{ - - /*switch (p) { - //case 1: // hwm - // hwWrite64(mem & ~0xa0000000, *value); - // return; - //case 6: // gsm - // gsWrite64(mem & ~0xa0000000, *value); return; - }*/ - - MEM_LOG("Unknown Memory write64 to address %x with data %8.8x_%8.8x\n", mem, (u32)(*value>>32), (u32)*value); - cpuTlbMissW(mem, cpuRegs.branch); -} -template -void __fastcall _ext_memWrite128(u32 mem, const u64 *value) -{ - /*switch (p) { - //case 1: // hwm - // hwWrite128(mem & ~0xa0000000, value); - // return; - //case 6: // gsm - // mem &= ~0xa0000000; - // gsWrite64(mem, value[0]); - // gsWrite64(mem+8, value[1]); return; - }*/ - - MEM_LOG("Unknown Memory write128 to address %x with data %8.8x_%8.8x_%8.8x_%8.8x\n", mem, ((u32*)value)[3], ((u32*)value)[2], ((u32*)value)[1], ((u32*)value)[0]); - cpuTlbMissW(mem, cpuRegs.branch); -} - -#define vtlb_RegisterHandlerTempl1(nam,t) vtlb_RegisterHandler(nam##Read8,nam##Read16,nam##Read32,nam##Read64,nam##Read128, \ - nam##Write8,nam##Write16,nam##Write32,nam##Write64,nam##Write128) - -#define vtlb_RegisterHandlerTempl2(nam,t,rec) vtlb_RegisterHandler(nam##Read8,nam##Read16,nam##Read32,nam##Read64,nam##Read128, \ - nam##Write8,nam##Write16,nam##Write32,nam##Write64,nam##Write128) - -typedef void __fastcall ClearFunc_t( u32 addr, u32 qwc ); - -template -static __forceinline void ClearVuFunc( u32 addr, u32 size ) -{ - if( dynarec ) - { - if( vunum==0 ) - VU0micro::recClear(addr,size); - else - VU1micro::recClear(addr,size); - } - else - { - if( vunum==0 ) - VU0micro::intClear(addr,size); - else - VU1micro::intClear(addr,size); - } -} - -template -mem8_t __fastcall vuMicroRead8(u32 addr) -{ - addr&=(vunum==0)?0xfff:0x3fff; - VURegs* vu=(vunum==0)?&VU0:&VU1; - - return vu->Micro[addr]; -} - -template -mem16_t __fastcall vuMicroRead16(u32 addr) -{ - addr&=(vunum==0)?0xfff:0x3fff; - VURegs* vu=(vunum==0)?&VU0:&VU1; - - return *(u16*)&vu->Micro[addr]; -} - -template -mem32_t __fastcall vuMicroRead32(u32 addr) -{ - addr&=(vunum==0)?0xfff:0x3fff; - VURegs* vu=(vunum==0)?&VU0:&VU1; - - return *(u32*)&vu->Micro[addr]; -} - -template -void __fastcall vuMicroRead64(u32 addr,mem64_t* data) -{ - addr&=(vunum==0)?0xfff:0x3fff; - VURegs* vu=(vunum==0)?&VU0:&VU1; - - *data=*(u64*)&vu->Micro[addr]; -} - -template -void __fastcall vuMicroRead128(u32 addr,mem128_t* data) -{ - addr&=(vunum==0)?0xfff:0x3fff; - VURegs* vu=(vunum==0)?&VU0:&VU1; - - data[0]=*(u64*)&vu->Micro[addr]; - data[1]=*(u64*)&vu->Micro[addr+8]; -} - -// [TODO] : Profile this code and see how often the VUs get written, and how -// often it changes the values being written (invoking a cpuClear). - -template -void __fastcall vuMicroWrite8(u32 addr,mem8_t data) -{ - addr &= (vunum==0) ? 0xfff : 0x3fff; - VURegs& vu = (vunum==0) ? VU0 : VU1; - - if (vu.Micro[addr]!=data) - { - ClearVuFunc(addr&(~7), 8); // Clear before writing new data (clearing 8 bytes because an instruction is 8 bytes) (cottonvibes) - vu.Micro[addr]=data; - } -} - -template -void __fastcall vuMicroWrite16(u32 addr,mem16_t data) -{ - addr &= (vunum==0) ? 0xfff : 0x3fff; - VURegs& vu = (vunum==0) ? VU0 : VU1; - - if (*(u16*)&vu.Micro[addr]!=data) - { - ClearVuFunc(addr&(~7), 8); - *(u16*)&vu.Micro[addr]=data; - } -} - -template -void __fastcall vuMicroWrite32(u32 addr,mem32_t data) -{ - addr &= (vunum==0) ? 0xfff : 0x3fff; - VURegs& vu = (vunum==0) ? VU0 : VU1; - - if (*(u32*)&vu.Micro[addr]!=data) - { - ClearVuFunc(addr&(~7), 8); - *(u32*)&vu.Micro[addr]=data; - } -} - -template -void __fastcall vuMicroWrite64(u32 addr,const mem64_t* data) -{ - addr &= (vunum==0) ? 0xfff : 0x3fff; - VURegs& vu = (vunum==0) ? VU0 : VU1; - - if (*(u64*)&vu.Micro[addr]!=data[0]) - { - ClearVuFunc(addr&(~7), 8); - *(u64*)&vu.Micro[addr]=data[0]; - } -} - -template -void __fastcall vuMicroWrite128(u32 addr,const mem128_t* data) -{ - addr &= (vunum==0) ? 0xfff : 0x3fff; - VURegs& vu = (vunum==0) ? VU0 : VU1; - - if (*(u64*)&vu.Micro[addr]!=data[0] || *(u64*)&vu.Micro[addr+8]!=data[1]) - { - ClearVuFunc(addr&(~7), 16); - *(u64*)&vu.Micro[addr]=data[0]; - *(u64*)&vu.Micro[addr+8]=data[1]; - } -} - -void memSetPageAddr(u32 vaddr, u32 paddr) -{ - //SysPrintf("memSetPageAddr: %8.8x -> %8.8x\n", vaddr, paddr); - - vtlb_VMap(vaddr,paddr,0x1000); - -} - -void memClearPageAddr(u32 vaddr) -{ - //SysPrintf("memClearPageAddr: %8.8x\n", vaddr); - - vtlb_VMapUnmap(vaddr,0x1000); // -> whut ? - -#ifdef FULLTLB - memLUTRK[vaddr >> 12] = 0; - memLUTWK[vaddr >> 12] = 0; -#endif -} - -/////////////////////////////////////////////////////////////////////////// -// PS2 Memory Init / Reset / Shutdown - -static const uint m_allMemSize = - Ps2MemSize::Rom + Ps2MemSize::Rom1 + Ps2MemSize::Rom2 + Ps2MemSize::ERom + - Ps2MemSize::Base + Ps2MemSize::Hardware + Ps2MemSize::Scratch; - -static u8* m_psAllMem = NULL; - -void memAlloc() -{ - if( m_psAllMem == NULL ) - m_psAllMem = vtlb_malloc( m_allMemSize, 4096, 0x2400000 ); - - if( m_psAllMem == NULL) - throw Exception::OutOfMemory( "memAlloc > failed to allocate PS2's base ram/rom/scratchpad." ); - - u8* curpos = m_psAllMem; - psM = curpos; curpos += Ps2MemSize::Base; - psR = curpos; curpos += Ps2MemSize::Rom; - psR1 = curpos; curpos += Ps2MemSize::Rom1; - psR2 = curpos; curpos += Ps2MemSize::Rom2; - psER = curpos; curpos += Ps2MemSize::ERom; - psH = curpos; curpos += Ps2MemSize::Hardware; - psS = curpos; //curpos += Ps2MemSize::Scratch; -} - -void memShutdown() -{ - vtlb_free( m_psAllMem, m_allMemSize ); - m_psAllMem = NULL; - psM = psR = psR1 = psR2 = psER = psS = psH = NULL; - vtlb_Term(); -} - -// Resets memory mappings, unmaps TLBs, reloads bios roms, etc. -void memReset() -{ - // VTLB Protection Preparations. - -#ifdef _WIN32 - DWORD OldProtect; - // make sure can write - VirtualProtect(m_psAllMem, m_allMemSize, PAGE_READWRITE, &OldProtect); -#else - mprotect(m_psAllMem, m_allMemSize, PROT_READ|PROT_WRITE); -#endif - - // Note!! Ideally the vtlb should only be initialized once, and then subsequent - // resets of the system hardware would only clear vtlb mappings, but since the - // rest of the emu is not really set up to support a "soft" reset of that sort - // we opt for the hard/safe version. - - memzero_ptr( m_psAllMem ); -#ifdef ENABLECACHE - memset(pCache,0,sizeof(_cacheS)*64); -#endif - - vtlb_Init(); - - tlb_fallback_0=vtlb_RegisterHandlerTempl1(_ext_mem,0); - tlb_fallback_2=vtlb_RegisterHandlerTempl1(_ext_mem,2); - tlb_fallback_3=vtlb_RegisterHandlerTempl1(_ext_mem,3); - tlb_fallback_4=vtlb_RegisterHandlerTempl1(_ext_mem,4); - tlb_fallback_5=vtlb_RegisterHandlerTempl1(_ext_mem,5); - //tlb_fallback_6=vtlb_RegisterHandlerTempl1(_ext_mem,6); - tlb_fallback_7=vtlb_RegisterHandlerTempl1(_ext_mem,7); - tlb_fallback_8=vtlb_RegisterHandlerTempl1(_ext_mem,8); - - // Dynarec versions of VUs - vu0_micro_mem[0] = vtlb_RegisterHandlerTempl2(vuMicro,0,true); - vu1_micro_mem[0] = vtlb_RegisterHandlerTempl2(vuMicro,1,true); - - // Interpreter versions of VUs - vu0_micro_mem[1] = vtlb_RegisterHandlerTempl2(vuMicro,0,false); - vu1_micro_mem[1] = vtlb_RegisterHandlerTempl2(vuMicro,1,false); - - ////////////////////////////////////////////////////////////////////// - // psHw Optimized Mappings - // The HW Registers have been split into pages to improve optimization. - // Anything not explicitly mapped into one of the hw_by_page handlers will be handled - // by the default/generic tlb_fallback_1 handler. - - tlb_fallback_1 = vtlb_RegisterHandler( - _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_generic, hwRead64_generic, hwRead128_generic, - _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_generic, hwWrite64_generic, hwWrite128_generic - ); - - hw_by_page[0x0] = vtlb_RegisterHandler( - _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_page_00, hwRead64_page_00, hwRead128_page_00, - _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_00, hwWrite64_generic, hwWrite128_generic - ); - - hw_by_page[0x1] = vtlb_RegisterHandler( - _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_page_01, hwRead64_page_01, hwRead128_page_01, - _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_01, hwWrite64_generic, hwWrite128_generic - ); - - hw_by_page[0x2] = vtlb_RegisterHandler( - _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_page_02, hwRead64_page_02, hwRead128_page_02, - _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_02, hwWrite64_page_02, hwWrite128_generic - ); - - hw_by_page[0x3] = vtlb_RegisterHandler( - _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_generic, hwRead64_generic, hwRead128_generic, - _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_03, hwWrite64_page_03, hwWrite128_generic - ); - - hw_by_page[0x4] = vtlb_RegisterHandler( - _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_generic, hwRead64_generic, ReadFIFO_page_4, - _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_generic, hwWrite64_generic, WriteFIFO_page_4 - ); - - hw_by_page[0x5] = vtlb_RegisterHandler( - _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_generic, hwRead64_generic, ReadFIFO_page_5, - _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_generic, hwWrite64_generic, WriteFIFO_page_5 - ); - - hw_by_page[0x6] = vtlb_RegisterHandler( - _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_generic, hwRead64_generic, ReadFIFO_page_6, - _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_generic, hwWrite64_generic, WriteFIFO_page_6 - ); - - hw_by_page[0x7] = vtlb_RegisterHandler( - _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_generic, hwRead64_generic, ReadFIFO_page_7, - _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_generic, hwWrite64_generic, WriteFIFO_page_7 - ); - - hw_by_page[0xb] = vtlb_RegisterHandler( - _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_generic, hwRead64_generic, hwRead128_generic, - _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_0B, hwWrite64_generic, hwWrite128_generic - ); - - hw_by_page[0xe] = vtlb_RegisterHandler( - _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_generic, hwRead64_generic, hwRead128_generic, - _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_0E, hwWrite64_page_0E, hwWrite128_generic - ); - - hw_by_page[0xf] = vtlb_RegisterHandler( - _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_page_0F, hwRead64_generic, hwRead128_generic, - _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_0F, hwWrite64_generic, hwWrite128_generic - ); - - ////////////////////////////////////////////////////////////////////// - // GS Optimized Mappings - - tlb_fallback_6 = vtlb_RegisterHandler( - _ext_memRead8<6>, _ext_memRead16<6>, _ext_memRead32<6>, _ext_memRead64<6>, _ext_memRead128<6>, - _ext_memWrite8<6>, _ext_memWrite16<6>, _ext_memWrite32<6>, gsWrite64_generic, gsWrite128_generic - ); - - gs_page_0 = vtlb_RegisterHandler( - _ext_memRead8<6>, _ext_memRead16<6>, _ext_memRead32<6>, _ext_memRead64<6>, _ext_memRead128<6>, - _ext_memWrite8<6>, _ext_memWrite16<6>, _ext_memWrite32<6>, gsWrite64_page_00, gsWrite128_page_00 - ); - - gs_page_1 = vtlb_RegisterHandler( - _ext_memRead8<6>, _ext_memRead16<6>, _ext_memRead32<6>, _ext_memRead64<6>, _ext_memRead128<6>, - _ext_memWrite8<6>, _ext_memWrite16<6>, _ext_memWrite32<6>, gsWrite64_page_01, gsWrite128_page_01 - ); - - //vtlb_Reset(); - - // reset memLUT (?) - //vtlb_VMap(0x00000000,0x00000000,0x20000000); - //vtlb_VMapUnmap(0x20000000,0x60000000); - - memMapPhy(); - memMapVUmicro(); - memMapKernelMem(); - memMapSupervisorMem(); - memMapUserMem(); - memSetKernelMode(); - - vtlb_VMap(0x00000000,0x00000000,0x20000000); - vtlb_VMapUnmap(0x20000000,0x60000000); - - string Bios; - FILE *fp; - - Path::Combine( Bios, Config.BiosDir, Config.Bios ); - - long filesize; - if( ( filesize = Path::getFileSize( Bios ) ) <= 0 ) - { - //Console::Error("Unable to load bios: '%s', PCSX2 can't run without that", params Bios); - throw Exception::FileNotFound( Bios, - "The specified Bios file was not found. A bios is required for Pcsx2 to run.\n\nFile not found" ); - } - - fp = fopen(Bios.c_str(), "rb"); - fread(PS2MEM_ROM, 1, std::min( (long)Ps2MemSize::Rom, filesize ), fp); - fclose(fp); - - BiosVersion = GetBiosVersion(); - Console::Status("Bios Version %d.%d", params BiosVersion >> 8, BiosVersion & 0xff); - - //injectIRX("host.irx"); //not fully tested; still buggy - - loadBiosRom("rom1", PS2MEM_ROM1, Ps2MemSize::Rom1); - loadBiosRom("rom2", PS2MEM_ROM2, Ps2MemSize::Rom2); - loadBiosRom("erom", PS2MEM_EROM, Ps2MemSize::ERom); -} - -int mmap_GetRamPageInfo(void* ptr) -{ - u32 offset=((u8*)ptr-psM); - if (offset>=Ps2MemSize::Base) - return -1; //not in ram, no tracking done ... - offset>>=12; - return (psMPWC[(offset/32)]&(1<<(offset&31)))?1:0; -} - -void mmap_MarkCountedRamPage(void* ptr,u32 vaddr) -{ -#ifdef _WIN32 - DWORD old; - VirtualProtect(ptr,1,PAGE_READONLY,&old); -#else - // fixed? mprotect needs input and size to be aligned to 4096 bytes pagesize. - // 'ptr' should be aligned properly, but a size of 1 was invalid. (air) - mprotect(ptr, getpagesize(), PROT_READ); -#endif - - u32 offset=((u8*)ptr-psM); - offset>>=12; - - for (u32 i=0;i>12);i++) - { - psMPWVA[i].clear(); - } -#ifdef _WIN32 - DWORD old; - VirtualProtect(psM,Ps2MemSize::Base,PAGE_READWRITE,&old); -#else - mprotect(psM,Ps2MemSize::Base, PROT_READ|PROT_WRITE); -#endif -} - -#ifdef _WIN32 -int SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps) -{ - const _EXCEPTION_RECORD& ExceptionRecord = *eps->ExceptionRecord; - //const _CONTEXT& ContextRecord = *eps->ContextRecord; - - if (ExceptionRecord.ExceptionCode != EXCEPTION_ACCESS_VIOLATION) - { - return EXCEPTION_CONTINUE_SEARCH; - } - - // get bad virtual address - u32 offset = (u8*)ExceptionRecord.ExceptionInformation[1]-psM; - - if (offset>=Ps2MemSize::Base) - return EXCEPTION_CONTINUE_SEARCH; - - DWORD old; - VirtualProtect(&psM[offset],1,PAGE_READWRITE,&old); - - offset>>=12; - psMPWC[(offset/32)]|=(1<<(offset&31)); - - for (u32 i=0;iClear(psMPWVA[offset][i],0x1000); - } - psMPWVA[offset].clear(); - - return EXCEPTION_CONTINUE_EXECUTION; -} - -#else -#include "errno.h" - -void InstallLinuxExceptionHandler() -{ - struct sigaction sa; - - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; - sa.sa_sigaction = &SysPageFaultExceptionFilter; - sigaction(SIGSEGV, &sa, NULL); -} - -void ReleaseLinuxExceptionHandler() -{ - // Code this later. -} -// Linux implementation of SIGSEGV handler. Bind it using sigaction(). -// This is my shot in the dark. Probably needs some work. Good luck! (air) -void SysPageFaultExceptionFilter( int signal, siginfo_t *info, void * ) -{ - int err; - u32 pagesize = getpagesize(); - - //DevCon::Error("SysPageFaultExceptionFilter!"); - // get bad virtual address - u32 offset = (u8*)info->si_addr - psM; - uptr pageoffset = ( offset / pagesize ) * pagesize; - - DevCon::Status( "Protected memory cleanup. Offset 0x%x", params offset ); - - if (offset>=Ps2MemSize::Base) - { - // Bad mojo! Completly invalid address. - // Instigate a crash or abort emulation or something. - assert( false ); - } - - err = mprotect( &psM[pageoffset], pagesize, PROT_READ | PROT_WRITE ); - if (err) DevCon::Error("SysPageFaultExceptionFilter: %s", params strerror(errno)); - - offset>>=12; - psMPWC[(offset/32)]|=(1<<(offset&31)); - - for (u32 i=0;iClear(psMPWVA[offset][i],0x1000); - } - psMPWVA[offset].clear(); -} -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +/* + +RAM +--- +0x00100000-0x01ffffff this is the physical address for the ram.its cached there +0x20100000-0x21ffffff uncached +0x30100000-0x31ffffff uncached & acceleretade +0xa0000000-0xa1ffffff MIRROR might...??? +0x80000000-0x81ffffff MIRROR might... ???? + +scratch pad +---------- +0x70000000-0x70003fff scratch pad + +BIOS +---- +0x1FC00000 - 0x1FFFFFFF un-cached +0x9FC00000 - 0x9FFFFFFF cached +0xBFC00000 - 0xBFFFFFFF un-cached +*/ + +#include "PrecompiledHeader.h" + +#pragma warning(disable:4799) // No EMMS at end of function + +#include + +#include "Common.h" +#include "iR5900.h" + +#include "PsxCommon.h" +#include "VUmicro.h" +#include "GS.h" +#include "vtlb.h" +#include "IPU/IPU.h" + + +#ifdef ENABLECACHE +#include "Cache.h" +#endif + +#ifdef __LINUX__ +#include +#endif + +//#define FULLTLB +int MemMode = 0; // 0 is Kernel Mode, 1 is Supervisor Mode, 2 is User Mode + +void memSetKernelMode() { + //Do something here + MemMode = 0; +} + +void memSetSupervisorMode() { +} + +void memSetUserMode() { + +} + +u16 ba0R16(u32 mem) +{ + //MEM_LOG("ba00000 Memory read16 address %x\n", mem); + + if (mem == 0x1a000006) { + static int ba6; + ba6++; + if (ba6 == 3) ba6 = 0; + return ba6; + } + return 0; +} + + +// Attempts to load a BIOS rom file, by trying multiple combinations of base filename +// and extension. The bios specified in Config.Bios is used as the base. +void loadBiosRom( const char *ext, u8 *dest, long maxSize ) +{ + string Bios1; + string Bios; + long filesize; + + Path::Combine( Bios, Config.BiosDir, Config.Bios ); + + // Try first a basic extension concatenation (normally results in something like name.bin.rom1) + ssprintf(Bios1, "%hs.%s", &Bios, ext); + if( (filesize=Path::getFileSize( Bios1 ) ) <= 0 ) + { + // Try the name properly extensioned next (name.rom1) + Path::ReplaceExtension( Bios1, Bios, ext ); + if( (filesize=Path::getFileSize( Bios1 ) ) <= 0 ) + { + // Try for the old-style method (rom1.bin) + Path::Combine( Bios1, Config.BiosDir, ext ); + Bios1 += ".bin"; + if( (filesize=Path::getFileSize( Bios1 ) ) <= 0 ) + { + Console::Error( "\n\n\n" + "**************\n" + "%s NOT FOUND\n" + "**************\n\n\n", params ext + ); + return; + } + } + } + + // if we made it this far, we have a successful file found: + + FILE *fp = fopen(Bios1.c_str(), "rb"); + fread(dest, 1, std::min( maxSize, filesize ), fp); + fclose(fp); +} + +u32 psMPWC[(Ps2MemSize::Base/32)>>12]; +std::vector psMPWVA[Ps2MemSize::Base>>12]; + +u8 *psM = NULL; //32mb Main Ram +u8 *psR = NULL; //4mb rom area +u8 *psR1 = NULL; //256kb rom1 area (actually 196kb, but can't mask this) +u8 *psR2 = NULL; // 0x00080000 +u8 *psER = NULL; // 0x001C0000 +u8 *psS = NULL; //0.015 mb, scratch pad + +#define CHECK_MEM(mem) //MyMemCheck(mem) + +void MyMemCheck(u32 mem) +{ + if( mem == 0x1c02f2a0 ) + SysPrintf("yo\n"); +} + +///////////////////////////// +// REGULAR MEM START +///////////////////////////// +vtlbHandler tlb_fallback_0; +vtlbHandler tlb_fallback_1; +vtlbHandler tlb_fallback_2; +vtlbHandler tlb_fallback_3; +vtlbHandler tlb_fallback_4; +vtlbHandler tlb_fallback_5; +vtlbHandler tlb_fallback_6; +vtlbHandler tlb_fallback_7; +vtlbHandler tlb_fallback_8; + +vtlbHandler vu0_micro_mem[2]; // 0 - dynarec, 1 - interpreter +vtlbHandler vu1_micro_mem[2]; // 0 - dynarec, 1 - interpreter + +vtlbHandler hw_by_page[0x10]; +vtlbHandler gs_page_0; +vtlbHandler gs_page_1; + + +// Used to remap the VUmicro memory according to the VU0/VU1 dynarec setting. +// (the VU memory operations are different for recs vs. interpreters) +void memMapVUmicro() +{ + vtlb_MapHandler(vu0_micro_mem[CHECK_VU0REC ? 0 : 1],0x11000000,0x00004000); + vtlb_MapHandler(vu1_micro_mem[CHECK_VU1REC ? 0 : 1],0x11008000,0x00004000); + + vtlb_MapBlock(VU0.Mem,0x11004000,0x00004000,0x1000); + vtlb_MapBlock(VU1.Mem,0x1100c000,0x00004000); +} + +void memMapPhy() +{ + //Main mem + vtlb_MapBlock(psM,0x00000000,Ps2MemSize::Base);//mirrored on first 256 mb ? + + //Rom + vtlb_MapBlock(psR,0x1fc00000,Ps2MemSize::Rom);//Writable ? + //Rom 1 + vtlb_MapBlock(psR1,0x1e000000,Ps2MemSize::Rom1);//Writable ? + //Rom 2 ? + vtlb_MapBlock(psR2,0x1e400000,Ps2MemSize::Rom2);//Writable ? + //EEProm ? + vtlb_MapBlock(psER,0x1e040000,Ps2MemSize::ERom);//Writable ? + + //IOP mem + vtlb_MapBlock(psxM,0x1c000000,0x00800000); + + //These fallback to mem* stuff ... + vtlb_MapHandler(tlb_fallback_1,0x10000000,0x10000); + vtlb_MapHandler(tlb_fallback_7,0x14000000,0x10000); + vtlb_MapHandler(tlb_fallback_4,0x18000000,0x10000); + vtlb_MapHandler(tlb_fallback_5,0x1a000000,0x10000); + vtlb_MapHandler(tlb_fallback_6,0x12000000,0x10000); + vtlb_MapHandler(tlb_fallback_8,0x1f000000,0x10000); + vtlb_MapHandler(tlb_fallback_3,0x1f400000,0x10000); + vtlb_MapHandler(tlb_fallback_2,0x1f800000,0x10000); + vtlb_MapHandler(tlb_fallback_8,0x1f900000,0x10000); + +#ifdef PCSX2_DEVBUILD + // Bind fallback handlers used for logging purposes only. + // In release mode the Vtlb will map these addresses directly instead of using + // the read/write handlers (which just issue logs and do normal memOps) +#endif + + // map specific optimized page handlers for HW accesses + vtlb_MapHandler(hw_by_page[0x0], 0x10000000, 0x01000); + vtlb_MapHandler(hw_by_page[0x1], 0x10001000, 0x01000); + vtlb_MapHandler(hw_by_page[0x2], 0x10002000, 0x01000); + vtlb_MapHandler(hw_by_page[0x3], 0x10003000, 0x01000); + vtlb_MapHandler(hw_by_page[0x4], 0x10004000, 0x01000); + vtlb_MapHandler(hw_by_page[0x5], 0x10005000, 0x01000); + vtlb_MapHandler(hw_by_page[0x6], 0x10006000, 0x01000); + vtlb_MapHandler(hw_by_page[0x7], 0x10007000, 0x01000); + vtlb_MapHandler(hw_by_page[0xb], 0x1000b000, 0x01000); + vtlb_MapHandler(hw_by_page[0xe], 0x1000e000, 0x01000); + vtlb_MapHandler(hw_by_page[0xf], 0x1000f000, 0x01000); + + vtlb_MapHandler(gs_page_0, 0x12000000, 0x01000); + vtlb_MapHandler(gs_page_1, 0x12001000, 0x01000); +} + +//Why is this required ? +void memMapKernelMem() +{ + //lower 512 mb: direct map + //vtlb_VMap(0x00000000,0x00000000,0x20000000); + //0x8* mirror + vtlb_VMap(0x80000000,0x00000000,0x20000000); + //0xa* mirror + vtlb_VMap(0xA0000000,0x00000000,0x20000000); +} + +//what do do with these ? +void memMapSupervisorMem() +{ +} + +void memMapUserMem() +{ +} + +template +mem8_t __fastcall _ext_memRead8 (u32 mem) +{ + switch (p) + { + case 1: // hwm + return hwRead8(mem); + case 2: // psh + return psxHwRead8(mem); + case 3: // psh4 + return psxHw4Read8(mem); + case 6: // gsm + return gsRead8(mem); + case 7: // dev9 + { + mem8_t retval = DEV9read8(mem & ~0xa4000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0xa4000000, retval); + return retval; + } + } + + MEM_LOG("Unknown Memory Read8 from address %8.8x\n", mem); + cpuTlbMissR(mem, cpuRegs.branch); + return 0; +} + +template +mem16_t __fastcall _ext_memRead16(u32 mem) +{ + switch (p) + { + case 1: // hwm + return hwRead16(mem); + case 2: // psh + return psxHwRead16(mem); + case 4: // b80 + MEM_LOG("b800000 Memory read16 address %x\n", mem); + return 0; + case 5: // ba0 + return ba0R16(mem); + case 6: // gsm + return gsRead16(mem); + + case 7: // dev9 + { + mem16_t retval = DEV9read16(mem & ~0xa4000000); + SysPrintf("DEV9 read16 %8.8lx: %4.4lx\n", mem & ~0xa4000000, retval); + return retval; + } + + case 8: // spu2 + return SPU2read(mem); + } + MEM_LOG("Unknown Memory read16 from address %8.8x\n", mem); + cpuTlbMissR(mem, cpuRegs.branch); + return 0; +} + +template +mem32_t __fastcall _ext_memRead32(u32 mem) +{ + switch (p) + { + case 2: // psh + return psxHwRead32(mem); + case 6: // gsm + return gsRead32(mem); + case 7: // dev9 + { + mem32_t retval = DEV9read32(mem & ~0xa4000000); + SysPrintf("DEV9 read32 %8.8lx: %8.8lx\n", mem & ~0xa4000000, retval); + return retval; + } + } + + MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val); + cpuTlbMissR(mem, cpuRegs.branch); + return 0; +} + +template +void __fastcall _ext_memRead64(u32 mem, mem64_t *out) +{ + switch (p) + { + case 6: // gsm + *out = gsRead64(mem); return; + } + + MEM_LOG("Unknown Memory read64 from address %8.8x\n", mem); + cpuTlbMissR(mem, cpuRegs.branch); +} + +template +void __fastcall _ext_memRead128(u32 mem, mem128_t *out) +{ + switch (p) + { + //case 1: // hwm + // hwRead128(mem & ~0xa0000000, out); return; + case 6: // gsm + out[0] = gsRead64(mem ); + out[1] = gsRead64(mem+8); return; + } + + MEM_LOG("Unknown Memory read128 from address %8.8x\n", mem); + cpuTlbMissR(mem, cpuRegs.branch); +} + +template +void __fastcall _ext_memWrite8 (u32 mem, u8 value) +{ + switch (p) { + case 1: // hwm + hwWrite8(mem, value); + return; + case 2: // psh + psxHwWrite8(mem, value); return; + case 3: // psh4 + psxHw4Write8(mem, value); return; + case 6: // gsm + gsWrite8(mem, value); return; + case 7: // dev9 + DEV9write8(mem & ~0xa4000000, value); + SysPrintf("DEV9 write8 %8.8lx: %2.2lx\n", mem & ~0xa4000000, value); + return; + } + + MEM_LOG("Unknown Memory write8 to address %x with data %2.2x\n", mem, value); + cpuTlbMissW(mem, cpuRegs.branch); +} +template +void __fastcall _ext_memWrite16(u32 mem, u16 value) +{ + switch (p) { + case 1: // hwm + hwWrite16(mem, value); + return; + case 2: // psh + psxHwWrite16(mem, value); return; + case 5: // ba0 + MEM_LOG("ba00000 Memory write16 to address %x with data %x\n", mem, value); + return; + case 6: // gsm + gsWrite16(mem, value); return; + case 7: // dev9 + DEV9write16(mem & ~0xa4000000, value); + SysPrintf("DEV9 write16 %8.8lx: %4.4lx\n", mem & ~0xa4000000, value); + return; + case 8: // spu2 + SPU2write(mem, value); return; + } + MEM_LOG("Unknown Memory write16 to address %x with data %4.4x\n", mem, value); + cpuTlbMissW(mem, cpuRegs.branch); +} +template +void __fastcall _ext_memWrite32(u32 mem, u32 value) +{ + switch (p) { + case 2: // psh + psxHwWrite32(mem, value); return; + case 6: // gsm + gsWrite32(mem, value); return; + case 7: // dev9 + DEV9write32(mem & ~0xa4000000, value); + SysPrintf("DEV9 write32 %8.8lx: %8.8lx\n", mem & ~0xa4000000, value); + return; + } + MEM_LOG("Unknown Memory write32 to address %x with data %8.8x\n", mem, value); + cpuTlbMissW(mem, cpuRegs.branch); +} +template +void __fastcall _ext_memWrite64(u32 mem, const u64* value) +{ + + /*switch (p) { + //case 1: // hwm + // hwWrite64(mem & ~0xa0000000, *value); + // return; + //case 6: // gsm + // gsWrite64(mem & ~0xa0000000, *value); return; + }*/ + + MEM_LOG("Unknown Memory write64 to address %x with data %8.8x_%8.8x\n", mem, (u32)(*value>>32), (u32)*value); + cpuTlbMissW(mem, cpuRegs.branch); +} +template +void __fastcall _ext_memWrite128(u32 mem, const u64 *value) +{ + /*switch (p) { + //case 1: // hwm + // hwWrite128(mem & ~0xa0000000, value); + // return; + //case 6: // gsm + // mem &= ~0xa0000000; + // gsWrite64(mem, value[0]); + // gsWrite64(mem+8, value[1]); return; + }*/ + + MEM_LOG("Unknown Memory write128 to address %x with data %8.8x_%8.8x_%8.8x_%8.8x\n", mem, ((u32*)value)[3], ((u32*)value)[2], ((u32*)value)[1], ((u32*)value)[0]); + cpuTlbMissW(mem, cpuRegs.branch); +} + +#define vtlb_RegisterHandlerTempl1(nam,t) vtlb_RegisterHandler(nam##Read8,nam##Read16,nam##Read32,nam##Read64,nam##Read128, \ + nam##Write8,nam##Write16,nam##Write32,nam##Write64,nam##Write128) + +#define vtlb_RegisterHandlerTempl2(nam,t,rec) vtlb_RegisterHandler(nam##Read8,nam##Read16,nam##Read32,nam##Read64,nam##Read128, \ + nam##Write8,nam##Write16,nam##Write32,nam##Write64,nam##Write128) + +typedef void __fastcall ClearFunc_t( u32 addr, u32 qwc ); + +template +static __forceinline void ClearVuFunc( u32 addr, u32 size ) +{ + if( dynarec ) + { + if( vunum==0 ) + VU0micro::recClear(addr,size); + else + VU1micro::recClear(addr,size); + } + else + { + if( vunum==0 ) + VU0micro::intClear(addr,size); + else + VU1micro::intClear(addr,size); + } +} + +template +mem8_t __fastcall vuMicroRead8(u32 addr) +{ + addr&=(vunum==0)?0xfff:0x3fff; + VURegs* vu=(vunum==0)?&VU0:&VU1; + + return vu->Micro[addr]; +} + +template +mem16_t __fastcall vuMicroRead16(u32 addr) +{ + addr&=(vunum==0)?0xfff:0x3fff; + VURegs* vu=(vunum==0)?&VU0:&VU1; + + return *(u16*)&vu->Micro[addr]; +} + +template +mem32_t __fastcall vuMicroRead32(u32 addr) +{ + addr&=(vunum==0)?0xfff:0x3fff; + VURegs* vu=(vunum==0)?&VU0:&VU1; + + return *(u32*)&vu->Micro[addr]; +} + +template +void __fastcall vuMicroRead64(u32 addr,mem64_t* data) +{ + addr&=(vunum==0)?0xfff:0x3fff; + VURegs* vu=(vunum==0)?&VU0:&VU1; + + *data=*(u64*)&vu->Micro[addr]; +} + +template +void __fastcall vuMicroRead128(u32 addr,mem128_t* data) +{ + addr&=(vunum==0)?0xfff:0x3fff; + VURegs* vu=(vunum==0)?&VU0:&VU1; + + data[0]=*(u64*)&vu->Micro[addr]; + data[1]=*(u64*)&vu->Micro[addr+8]; +} + +// [TODO] : Profile this code and see how often the VUs get written, and how +// often it changes the values being written (invoking a cpuClear). + +template +void __fastcall vuMicroWrite8(u32 addr,mem8_t data) +{ + addr &= (vunum==0) ? 0xfff : 0x3fff; + VURegs& vu = (vunum==0) ? VU0 : VU1; + + if (vu.Micro[addr]!=data) + { + ClearVuFunc(addr&(~7), 8); // Clear before writing new data (clearing 8 bytes because an instruction is 8 bytes) (cottonvibes) + vu.Micro[addr]=data; + } +} + +template +void __fastcall vuMicroWrite16(u32 addr,mem16_t data) +{ + addr &= (vunum==0) ? 0xfff : 0x3fff; + VURegs& vu = (vunum==0) ? VU0 : VU1; + + if (*(u16*)&vu.Micro[addr]!=data) + { + ClearVuFunc(addr&(~7), 8); + *(u16*)&vu.Micro[addr]=data; + } +} + +template +void __fastcall vuMicroWrite32(u32 addr,mem32_t data) +{ + addr &= (vunum==0) ? 0xfff : 0x3fff; + VURegs& vu = (vunum==0) ? VU0 : VU1; + + if (*(u32*)&vu.Micro[addr]!=data) + { + ClearVuFunc(addr&(~7), 8); + *(u32*)&vu.Micro[addr]=data; + } +} + +template +void __fastcall vuMicroWrite64(u32 addr,const mem64_t* data) +{ + addr &= (vunum==0) ? 0xfff : 0x3fff; + VURegs& vu = (vunum==0) ? VU0 : VU1; + + if (*(u64*)&vu.Micro[addr]!=data[0]) + { + ClearVuFunc(addr&(~7), 8); + *(u64*)&vu.Micro[addr]=data[0]; + } +} + +template +void __fastcall vuMicroWrite128(u32 addr,const mem128_t* data) +{ + addr &= (vunum==0) ? 0xfff : 0x3fff; + VURegs& vu = (vunum==0) ? VU0 : VU1; + + if (*(u64*)&vu.Micro[addr]!=data[0] || *(u64*)&vu.Micro[addr+8]!=data[1]) + { + ClearVuFunc(addr&(~7), 16); + *(u64*)&vu.Micro[addr]=data[0]; + *(u64*)&vu.Micro[addr+8]=data[1]; + } +} + +void memSetPageAddr(u32 vaddr, u32 paddr) +{ + //SysPrintf("memSetPageAddr: %8.8x -> %8.8x\n", vaddr, paddr); + + vtlb_VMap(vaddr,paddr,0x1000); + +} + +void memClearPageAddr(u32 vaddr) +{ + //SysPrintf("memClearPageAddr: %8.8x\n", vaddr); + + vtlb_VMapUnmap(vaddr,0x1000); // -> whut ? + +#ifdef FULLTLB + memLUTRK[vaddr >> 12] = 0; + memLUTWK[vaddr >> 12] = 0; +#endif +} + +/////////////////////////////////////////////////////////////////////////// +// PS2 Memory Init / Reset / Shutdown + +static const uint m_allMemSize = + Ps2MemSize::Rom + Ps2MemSize::Rom1 + Ps2MemSize::Rom2 + Ps2MemSize::ERom + + Ps2MemSize::Base + Ps2MemSize::Hardware + Ps2MemSize::Scratch; + +static u8* m_psAllMem = NULL; + +void memAlloc() +{ + if( m_psAllMem == NULL ) + m_psAllMem = vtlb_malloc( m_allMemSize, 4096, 0x2400000 ); + + if( m_psAllMem == NULL) + throw Exception::OutOfMemory( "memAlloc > failed to allocate PS2's base ram/rom/scratchpad." ); + + u8* curpos = m_psAllMem; + psM = curpos; curpos += Ps2MemSize::Base; + psR = curpos; curpos += Ps2MemSize::Rom; + psR1 = curpos; curpos += Ps2MemSize::Rom1; + psR2 = curpos; curpos += Ps2MemSize::Rom2; + psER = curpos; curpos += Ps2MemSize::ERom; + psH = curpos; curpos += Ps2MemSize::Hardware; + psS = curpos; //curpos += Ps2MemSize::Scratch; +} + +void memShutdown() +{ + vtlb_free( m_psAllMem, m_allMemSize ); + m_psAllMem = NULL; + psM = psR = psR1 = psR2 = psER = psS = psH = NULL; + vtlb_Term(); +} + +// Resets memory mappings, unmaps TLBs, reloads bios roms, etc. +void memReset() +{ + // VTLB Protection Preparations. + +#ifdef _WIN32 + DWORD OldProtect; + // make sure can write + VirtualProtect(m_psAllMem, m_allMemSize, PAGE_READWRITE, &OldProtect); +#else + mprotect(m_psAllMem, m_allMemSize, PROT_READ|PROT_WRITE); +#endif + + // Note!! Ideally the vtlb should only be initialized once, and then subsequent + // resets of the system hardware would only clear vtlb mappings, but since the + // rest of the emu is not really set up to support a "soft" reset of that sort + // we opt for the hard/safe version. + + memzero_ptr( m_psAllMem ); +#ifdef ENABLECACHE + memset(pCache,0,sizeof(_cacheS)*64); +#endif + + vtlb_Init(); + + tlb_fallback_0=vtlb_RegisterHandlerTempl1(_ext_mem,0); + tlb_fallback_2=vtlb_RegisterHandlerTempl1(_ext_mem,2); + tlb_fallback_3=vtlb_RegisterHandlerTempl1(_ext_mem,3); + tlb_fallback_4=vtlb_RegisterHandlerTempl1(_ext_mem,4); + tlb_fallback_5=vtlb_RegisterHandlerTempl1(_ext_mem,5); + //tlb_fallback_6=vtlb_RegisterHandlerTempl1(_ext_mem,6); + tlb_fallback_7=vtlb_RegisterHandlerTempl1(_ext_mem,7); + tlb_fallback_8=vtlb_RegisterHandlerTempl1(_ext_mem,8); + + // Dynarec versions of VUs + vu0_micro_mem[0] = vtlb_RegisterHandlerTempl2(vuMicro,0,true); + vu1_micro_mem[0] = vtlb_RegisterHandlerTempl2(vuMicro,1,true); + + // Interpreter versions of VUs + vu0_micro_mem[1] = vtlb_RegisterHandlerTempl2(vuMicro,0,false); + vu1_micro_mem[1] = vtlb_RegisterHandlerTempl2(vuMicro,1,false); + + ////////////////////////////////////////////////////////////////////// + // psHw Optimized Mappings + // The HW Registers have been split into pages to improve optimization. + // Anything not explicitly mapped into one of the hw_by_page handlers will be handled + // by the default/generic tlb_fallback_1 handler. + + tlb_fallback_1 = vtlb_RegisterHandler( + _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_generic, hwRead64_generic, hwRead128_generic, + _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_generic, hwWrite64_generic, hwWrite128_generic + ); + + hw_by_page[0x0] = vtlb_RegisterHandler( + _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_page_00, hwRead64_page_00, hwRead128_page_00, + _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_00, hwWrite64_generic, hwWrite128_generic + ); + + hw_by_page[0x1] = vtlb_RegisterHandler( + _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_page_01, hwRead64_page_01, hwRead128_page_01, + _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_01, hwWrite64_generic, hwWrite128_generic + ); + + hw_by_page[0x2] = vtlb_RegisterHandler( + _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_page_02, hwRead64_page_02, hwRead128_page_02, + _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_02, hwWrite64_page_02, hwWrite128_generic + ); + + hw_by_page[0x3] = vtlb_RegisterHandler( + _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_generic, hwRead64_generic, hwRead128_generic, + _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_03, hwWrite64_page_03, hwWrite128_generic + ); + + hw_by_page[0x4] = vtlb_RegisterHandler( + _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_generic, hwRead64_generic, ReadFIFO_page_4, + _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_generic, hwWrite64_generic, WriteFIFO_page_4 + ); + + hw_by_page[0x5] = vtlb_RegisterHandler( + _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_generic, hwRead64_generic, ReadFIFO_page_5, + _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_generic, hwWrite64_generic, WriteFIFO_page_5 + ); + + hw_by_page[0x6] = vtlb_RegisterHandler( + _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_generic, hwRead64_generic, ReadFIFO_page_6, + _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_generic, hwWrite64_generic, WriteFIFO_page_6 + ); + + hw_by_page[0x7] = vtlb_RegisterHandler( + _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_generic, hwRead64_generic, ReadFIFO_page_7, + _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_generic, hwWrite64_generic, WriteFIFO_page_7 + ); + + hw_by_page[0xb] = vtlb_RegisterHandler( + _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_generic, hwRead64_generic, hwRead128_generic, + _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_0B, hwWrite64_generic, hwWrite128_generic + ); + + hw_by_page[0xe] = vtlb_RegisterHandler( + _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_generic, hwRead64_generic, hwRead128_generic, + _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_0E, hwWrite64_page_0E, hwWrite128_generic + ); + + hw_by_page[0xf] = vtlb_RegisterHandler( + _ext_memRead8<1>, _ext_memRead16<1>, hwRead32_page_0F, hwRead64_generic, hwRead128_generic, + _ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_0F, hwWrite64_generic, hwWrite128_generic + ); + + ////////////////////////////////////////////////////////////////////// + // GS Optimized Mappings + + tlb_fallback_6 = vtlb_RegisterHandler( + _ext_memRead8<6>, _ext_memRead16<6>, _ext_memRead32<6>, _ext_memRead64<6>, _ext_memRead128<6>, + _ext_memWrite8<6>, _ext_memWrite16<6>, _ext_memWrite32<6>, gsWrite64_generic, gsWrite128_generic + ); + + gs_page_0 = vtlb_RegisterHandler( + _ext_memRead8<6>, _ext_memRead16<6>, _ext_memRead32<6>, _ext_memRead64<6>, _ext_memRead128<6>, + _ext_memWrite8<6>, _ext_memWrite16<6>, _ext_memWrite32<6>, gsWrite64_page_00, gsWrite128_page_00 + ); + + gs_page_1 = vtlb_RegisterHandler( + _ext_memRead8<6>, _ext_memRead16<6>, _ext_memRead32<6>, _ext_memRead64<6>, _ext_memRead128<6>, + _ext_memWrite8<6>, _ext_memWrite16<6>, _ext_memWrite32<6>, gsWrite64_page_01, gsWrite128_page_01 + ); + + //vtlb_Reset(); + + // reset memLUT (?) + //vtlb_VMap(0x00000000,0x00000000,0x20000000); + //vtlb_VMapUnmap(0x20000000,0x60000000); + + memMapPhy(); + memMapVUmicro(); + memMapKernelMem(); + memMapSupervisorMem(); + memMapUserMem(); + memSetKernelMode(); + + vtlb_VMap(0x00000000,0x00000000,0x20000000); + vtlb_VMapUnmap(0x20000000,0x60000000); + + string Bios; + FILE *fp; + + Path::Combine( Bios, Config.BiosDir, Config.Bios ); + + long filesize; + if( ( filesize = Path::getFileSize( Bios ) ) <= 0 ) + { + //Console::Error("Unable to load bios: '%s', PCSX2 can't run without that", params Bios); + throw Exception::FileNotFound( Bios, + "The specified Bios file was not found. A bios is required for Pcsx2 to run.\n\nFile not found" ); + } + + fp = fopen(Bios.c_str(), "rb"); + fread(PS2MEM_ROM, 1, std::min( (long)Ps2MemSize::Rom, filesize ), fp); + fclose(fp); + + BiosVersion = GetBiosVersion(); + Console::Status("Bios Version %d.%d", params BiosVersion >> 8, BiosVersion & 0xff); + + //injectIRX("host.irx"); //not fully tested; still buggy + + loadBiosRom("rom1", PS2MEM_ROM1, Ps2MemSize::Rom1); + loadBiosRom("rom2", PS2MEM_ROM2, Ps2MemSize::Rom2); + loadBiosRom("erom", PS2MEM_EROM, Ps2MemSize::ERom); +} + +int mmap_GetRamPageInfo(void* ptr) +{ + u32 offset=((u8*)ptr-psM); + if (offset>=Ps2MemSize::Base) + return -1; //not in ram, no tracking done ... + offset>>=12; + return (psMPWC[(offset/32)]&(1<<(offset&31)))?1:0; +} + +void mmap_MarkCountedRamPage(void* ptr,u32 vaddr) +{ +#ifdef _WIN32 + DWORD old; + VirtualProtect(ptr,1,PAGE_READONLY,&old); +#else + // fixed? mprotect needs input and size to be aligned to 4096 bytes pagesize. + // 'ptr' should be aligned properly, but a size of 1 was invalid. (air) + mprotect(ptr, getpagesize(), PROT_READ); +#endif + + u32 offset=((u8*)ptr-psM); + offset>>=12; + + for (u32 i=0;i>12);i++) + { + psMPWVA[i].clear(); + } +#ifdef _WIN32 + DWORD old; + VirtualProtect(psM,Ps2MemSize::Base,PAGE_READWRITE,&old); +#else + mprotect(psM,Ps2MemSize::Base, PROT_READ|PROT_WRITE); +#endif +} + +#ifdef _WIN32 +int SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps) +{ + const _EXCEPTION_RECORD& ExceptionRecord = *eps->ExceptionRecord; + //const _CONTEXT& ContextRecord = *eps->ContextRecord; + + if (ExceptionRecord.ExceptionCode != EXCEPTION_ACCESS_VIOLATION) + { + return EXCEPTION_CONTINUE_SEARCH; + } + + // get bad virtual address + u32 offset = (u8*)ExceptionRecord.ExceptionInformation[1]-psM; + + if (offset>=Ps2MemSize::Base) + return EXCEPTION_CONTINUE_SEARCH; + + DWORD old; + VirtualProtect(&psM[offset],1,PAGE_READWRITE,&old); + + offset>>=12; + psMPWC[(offset/32)]|=(1<<(offset&31)); + + for (u32 i=0;iClear(psMPWVA[offset][i],0x1000); + } + psMPWVA[offset].clear(); + + return EXCEPTION_CONTINUE_EXECUTION; +} + +#else +#include "errno.h" + +void InstallLinuxExceptionHandler() +{ + struct sigaction sa; + + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = &SysPageFaultExceptionFilter; + sigaction(SIGSEGV, &sa, NULL); +} + +void ReleaseLinuxExceptionHandler() +{ + // Code this later. +} +// Linux implementation of SIGSEGV handler. Bind it using sigaction(). +// This is my shot in the dark. Probably needs some work. Good luck! (air) +void SysPageFaultExceptionFilter( int signal, siginfo_t *info, void * ) +{ + int err; + u32 pagesize = getpagesize(); + + //DevCon::Error("SysPageFaultExceptionFilter!"); + // get bad virtual address + u32 offset = (u8*)info->si_addr - psM; + uptr pageoffset = ( offset / pagesize ) * pagesize; + + DevCon::Status( "Protected memory cleanup. Offset 0x%x", params offset ); + + if (offset>=Ps2MemSize::Base) + { + // Bad mojo! Completly invalid address. + // Instigate a crash or abort emulation or something. + assert( false ); + } + + err = mprotect( &psM[pageoffset], pagesize, PROT_READ | PROT_WRITE ); + if (err) DevCon::Error("SysPageFaultExceptionFilter: %s", params strerror(errno)); + + offset>>=12; + psMPWC[(offset/32)]|=(1<<(offset&31)); + + for (u32 i=0;iClear(psMPWVA[offset][i],0x1000); + } + psMPWVA[offset].clear(); +} +#endif diff --git a/pcsx2/Memory.h b/pcsx2/Memory.h index a9c908c7eb..35d8c25c3e 100644 --- a/pcsx2/Memory.h +++ b/pcsx2/Memory.h @@ -1,303 +1,303 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -////////// -// Rewritten by zerofrog to add os virtual memory -////////// - -#ifndef __MEMORY_H__ -#define __MEMORY_H__ - -#ifdef __LINUX__ -#include -#endif - -//#define ENABLECACHE - -namespace Ps2MemSize -{ - static const uint Base = 0x02000000; // 32 MB main memory! - static const uint Rom = 0x00400000; // 4 MB main rom - static const uint Rom1 = 0x00040000; // DVD player - static const uint Rom2 = 0x00080000; // Chinese rom extension (?) - static const uint ERom = 0x001C0000; // DVD player extensions (?) - static const uint Hardware = 0x00010000; - static const uint Scratch = 0x00004000; - - static const uint IopRam = 0x00200000; // 2MB main ram on the IOP. - static const uint IopHardware = 0x00010000; - - static const uint GSregs = 0x00002000; // 8k for the GS registers and stuff. -} - -extern u8 *psM; //32mb Main Ram -extern u8 *psR; //4mb rom area -extern u8 *psR1; //256kb rom1 area (actually 196kb, but can't mask this) -extern u8 *psR2; // 0x00080000 -extern u8 *psER; // 0x001C0000 -extern u8 *psS; //0.015 mb, scratch pad - -#define PS2MEM_BASE psM -#define PS2MEM_HW psH -#define PS2MEM_ROM psR -#define PS2MEM_ROM1 psR1 -#define PS2MEM_ROM2 psR2 -#define PS2MEM_EROM psER -#define PS2MEM_SCRATCH psS - -extern u8 g_RealGSMem[0x2000]; -#define PS2MEM_GS g_RealGSMem - -//#define _PSM(mem) (memLUTR[(mem) >> 12] == 0 ? NULL : (void*)(memLUTR[(mem) >> 12] + ((mem) & 0xfff))) -#define PSM(mem) (vtlb_GetPhyPtr(mem&0x1fffffff)) //pcsx2 is a competition.The one with most hacks wins :D - -#define psMs8(mem) (*(s8 *)&PS2MEM_BASE[(mem) & 0x1ffffff]) -#define psMs16(mem) (*(s16*)&PS2MEM_BASE[(mem) & 0x1ffffff]) -#define psMs32(mem) (*(s32*)&PS2MEM_BASE[(mem) & 0x1ffffff]) -#define psMs64(mem) (*(s64*)&PS2MEM_BASE[(mem) & 0x1ffffff]) -#define psMu8(mem) (*(u8 *)&PS2MEM_BASE[(mem) & 0x1ffffff]) -#define psMu16(mem) (*(u16*)&PS2MEM_BASE[(mem) & 0x1ffffff]) -#define psMu32(mem) (*(u32*)&PS2MEM_BASE[(mem) & 0x1ffffff]) -#define psMu64(mem) (*(u64*)&PS2MEM_BASE[(mem) & 0x1ffffff]) - -#define psRs8(mem) (*(s8 *)&PS2MEM_ROM[(mem) & 0x3fffff]) -#define psRs16(mem) (*(s16*)&PS2MEM_ROM[(mem) & 0x3fffff]) -#define psRs32(mem) (*(s32*)&PS2MEM_ROM[(mem) & 0x3fffff]) -#define psRs64(mem) (*(s64*)&PS2MEM_ROM[(mem) & 0x3fffff]) -#define psRu8(mem) (*(u8 *)&PS2MEM_ROM[(mem) & 0x3fffff]) -#define psRu16(mem) (*(u16*)&PS2MEM_ROM[(mem) & 0x3fffff]) -#define psRu32(mem) (*(u32*)&PS2MEM_ROM[(mem) & 0x3fffff]) -#define psRu64(mem) (*(u64*)&PS2MEM_ROM[(mem) & 0x3fffff]) - -#define psR1s8(mem) (*(s8 *)&PS2MEM_ROM1[(mem) & 0x3ffff]) -#define psR1s16(mem) (*(s16*)&PS2MEM_ROM1[(mem) & 0x3ffff]) -#define psR1s32(mem) (*(s32*)&PS2MEM_ROM1[(mem) & 0x3ffff]) -#define psR1s64(mem) (*(s64*)&PS2MEM_ROM1[(mem) & 0x3ffff]) -#define psR1u8(mem) (*(u8 *)&PS2MEM_ROM1[(mem) & 0x3ffff]) -#define psR1u16(mem) (*(u16*)&PS2MEM_ROM1[(mem) & 0x3ffff]) -#define psR1u32(mem) (*(u32*)&PS2MEM_ROM1[(mem) & 0x3ffff]) -#define psR1u64(mem) (*(u64*)&PS2MEM_ROM1[(mem) & 0x3ffff]) - -#define psR2s8(mem) (*(s8 *)&PS2MEM_ROM2[(mem) & 0x3ffff]) -#define psR2s16(mem) (*(s16*)&PS2MEM_ROM2[(mem) & 0x3ffff]) -#define psR2s32(mem) (*(s32*)&PS2MEM_ROM2[(mem) & 0x3ffff]) -#define psR2s64(mem) (*(s64*)&PS2MEM_ROM2[(mem) & 0x3ffff]) -#define psR2u8(mem) (*(u8 *)&PS2MEM_ROM2[(mem) & 0x3ffff]) -#define psR2u16(mem) (*(u16*)&PS2MEM_ROM2[(mem) & 0x3ffff]) -#define psR2u32(mem) (*(u32*)&PS2MEM_ROM2[(mem) & 0x3ffff]) -#define psR2u64(mem) (*(u64*)&PS2MEM_ROM2[(mem) & 0x3ffff]) - -#define psERs8(mem) (*(s8 *)&PS2MEM_EROM[(mem) & 0x3ffff]) -#define psERs16(mem) (*(s16*)&PS2MEM_EROM[(mem) & 0x3ffff]) -#define psERs32(mem) (*(s32*)&PS2MEM_EROM[(mem) & 0x3ffff]) -#define psERs64(mem) (*(s64*)&PS2MEM_EROM[(mem) & 0x3ffff]) -#define psERu8(mem) (*(u8 *)&PS2MEM_EROM[(mem) & 0x3ffff]) -#define psERu16(mem) (*(u16*)&PS2MEM_EROM[(mem) & 0x3ffff]) -#define psERu32(mem) (*(u32*)&PS2MEM_EROM[(mem) & 0x3ffff]) -#define psERu64(mem) (*(u64*)&PS2MEM_EROM[(mem) & 0x3ffff]) - -#define psSs8(mem) (*(s8 *)&PS2MEM_SCRATCH[(mem) & 0x3fff]) -#define psSs16(mem) (*(s16*)&PS2MEM_SCRATCH[(mem) & 0x3fff]) -#define psSs32(mem) (*(s32*)&PS2MEM_SCRATCH[(mem) & 0x3fff]) -#define psSs64(mem) (*(s64*)&PS2MEM_SCRATCH[(mem) & 0x3fff]) -#define psSu8(mem) (*(u8 *)&PS2MEM_SCRATCH[(mem) & 0x3fff]) -#define psSu16(mem) (*(u16*)&PS2MEM_SCRATCH[(mem) & 0x3fff]) -#define psSu32(mem) (*(u32*)&PS2MEM_SCRATCH[(mem) & 0x3fff]) -#define psSu64(mem) (*(u64*)&PS2MEM_SCRATCH[(mem) & 0x3fff]) - -#define PSMs8(mem) (*(s8 *)PSM(mem)) -#define PSMs16(mem) (*(s16*)PSM(mem)) -#define PSMs32(mem) (*(s32*)PSM(mem)) -#define PSMs64(mem) (*(s64*)PSM(mem)) -#define PSMu8(mem) (*(u8 *)PSM(mem)) -#define PSMu16(mem) (*(u16*)PSM(mem)) -#define PSMu32(mem) (*(u32*)PSM(mem)) -#define PSMu64(mem) (*(u64*)PSM(mem)) - -extern void memAlloc(); -extern void memReset(); // clears PS2 ram and loads the bios. Throws Exception::FileNotFound on error. -extern void memShutdown(); -extern void memSetKernelMode(); -extern void memSetSupervisorMode(); -extern void memSetUserMode(); -extern void memSetPageAddr(u32 vaddr, u32 paddr); -extern void memClearPageAddr(u32 vaddr); - -extern void memMapVUmicro(); - -#ifdef __LINUX__ -void SysPageFaultExceptionFilter( int signal, siginfo_t *info, void * ); -void __fastcall InstallLinuxExceptionHandler(); -void __fastcall ReleaseLinuxExceptionHandler(); -#else -int SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps); -#endif - -#include "vtlb.h" - -int mmap_GetRamPageInfo(void* ptr); -void mmap_MarkCountedRamPage(void* ptr,u32 vaddr); -void mmap_ResetBlockTracking(); - -extern void __fastcall memRead8(u32 mem, u8 *out); -extern void __fastcall memRead16(u32 mem, u16 *out); -extern void __fastcall memRead32(u32 mem, u32 *out); - -#define memRead64 vtlb_memRead64 -#define memRead128 vtlb_memRead128 - -#define memWrite8 vtlb_memWrite8 -#define memWrite16 vtlb_memWrite16 -#define memWrite32 vtlb_memWrite32 -#define memWrite64 vtlb_memWrite64 -#define memWrite128 vtlb_memWrite128 - -#define _eeReadConstMem8 0&& -#define _eeReadConstMem16 0&& -#define _eeReadConstMem32 0&& -#define _eeReadConstMem128 0&& -#define _eeWriteConstMem8 0&& -#define _eeWriteConstMem16 0&& -#define _eeWriteConstMem32 0&& -#define _eeWriteConstMem64 0&& -#define _eeWriteConstMem128 0&& -#define _eeMoveMMREGtoR 0&& - -// extra ops -#define _eeWriteConstMem16OP 0&& -#define _eeWriteConstMem32OP 0&& - -#define recMemConstRead8 0&& -#define recMemConstRead16 0&& -#define recMemConstRead32 0&& -#define recMemConstRead64 0&& -#define recMemConstRead128 0&& - -#define recMemConstWrite8 0&& -#define recMemConstWrite16 0&& -#define recMemConstWrite32 0&& -#define recMemConstWrite64 0&& -#define recMemConstWrite128 0&& - -extern void loadBiosRom( const char *ext, u8 *dest, long maxSize ); -extern u16 ba0R16(u32 mem); - -////////////////////////////////////////////////////////////////////////// -// The rest of this header contains the old VM version of the Memory.h API. -// Left in for references purposes. - -#ifdef PCSX2_VIRTUAL_MEM - -#define PS2MEM_BASE_ 0x15000000 -#define PS2MEM_PSX_ (PS2MEM_BASE_+0x1c000000) - -#ifdef _WIN32 -struct PSMEMORYMAP -{ - uptr* aPFNs, *aVFNs; -}; -#endif - -#define TRANSFORM_ADDR(memaddr) ( ((u32)(memaddr)>=0x40000000) ? ((memaddr)&~0xa0000000) : (memaddr) ) - -//new memory model -#define PS2MEM_BASE ((u8*)PS2MEM_BASE_) -#define PS2MEM_HW ((u8*)((u32)PS2MEM_BASE+0x10000000)) -#define PS2MEM_ROM ((u8*)((u32)PS2MEM_BASE+0x1fc00000)) -#define PS2MEM_ROM1 ((u8*)((u32)PS2MEM_BASE+0x1e000000)) -#define PS2MEM_ROM2 ((u8*)((u32)PS2MEM_BASE+0x1e400000)) -#define PS2MEM_EROM ((u8*)((u32)PS2MEM_BASE+0x1e040000)) -#define PS2MEM_PSX ((u8*)PS2MEM_PSX_) -#define PS2MEM_SCRATCH ((u8*)((u32)PS2MEM_BASE+0x50000000)) -#define PS2MEM_VU0MICRO ((u8*)((u32)PS2MEM_BASE+0x11000000)) -#define PS2MEM_VU0MEM ((u8*)((u32)PS2MEM_BASE+0x11004000)) -#define PS2MEM_VU1MICRO ((u8*)((u32)PS2MEM_BASE+0x11008000)) -#define PS2MEM_VU1MEM ((u8*)((u32)PS2MEM_BASE+0x1100c000)) - -// function for mapping memory -#define PS2MEM_PSXHW ((u8*)((u32)PS2MEM_BASE+0x1f800000)) -//#define PS2MEM_PSXHW2 ((u8*)((u32)PS2MEM_BASE+0x1fa00000)) -#define PS2MEM_PSXHW4 ((u8*)((u32)PS2MEM_BASE+0x1f400000)) -#define PS2MEM_GS ((u8*)((u32)PS2MEM_BASE+0x12000000)) -#define PS2MEM_DEV9 ((u8*)((u32)PS2MEM_BASE+0x14000000)) -#define PS2MEM_SPU2 ((u8*)((u32)PS2MEM_BASE+0x1f900000)) -#define PS2MEM_SPU2_ ((u8*)((u32)PS2MEM_BASE+0x1f000000)) // ? -#define PS2MEM_B80 ((u8*)((u32)PS2MEM_BASE+0x18000000)) -#define PS2MEM_BA0 ((u8*)((u32)PS2MEM_BASE+0x1a000000)) - -#define PSM(mem) (PS2MEM_BASE + TRANSFORM_ADDR(mem)) - -int __fastcall memRead8(u32 mem, u8 *out); -int __fastcall memRead8RS(u32 mem, u64 *out); -int __fastcall memRead8RU(u32 mem, u64 *out); -int __fastcall memRead16(u32 mem, u16 *out); -int __fastcall memRead16RS(u32 mem, u64 *out); -int __fastcall memRead16RU(u32 mem, u64 *out); -int __fastcall memRead32(u32 mem, u32 *out); -int __fastcall memRead32RS(u32 mem, u64 *out); -int __fastcall memRead32RU(u32 mem, u64 *out); -int __fastcall memRead64(u32 mem, u64 *out); -int __fastcall memRead128(u32 mem, u64 *out); -void __fastcall memWrite8 (u32 mem, u8 value); -void __fastcall memWrite16(u32 mem, u16 value); -void __fastcall memWrite32(u32 mem, u32 value); -void __fastcall memWrite64(u32 mem, const u64 *value); -void __fastcall memWrite128(u32 mem, const u64 *value); - -// recMemConstRead8, recMemConstRead16, recMemConstRead32 return 1 if a call was made, 0 otherwise -u8 recMemRead8(); -u16 recMemRead16(); -u32 recMemRead32(); -void recMemRead64(u64 *out); -void recMemRead128(u64 *out); - -void recMemWrite8(); -void recMemWrite16(); -void recMemWrite32(); -void recMemWrite64(); -void recMemWrite128(); - -void _eeReadConstMem8(int mmreg, u32 mem, int sign); -void _eeReadConstMem16(int mmreg, u32 mem, int sign); -void _eeReadConstMem32(int mmreg, u32 mem); -void _eeReadConstMem128(int mmreg, u32 mem); -void _eeWriteConstMem8(u32 mem, int mmreg); -void _eeWriteConstMem16(u32 mem, int mmreg); -void _eeWriteConstMem32(u32 mem, int mmreg); -void _eeWriteConstMem64(u32 mem, int mmreg); -void _eeWriteConstMem128(u32 mem, int mmreg); -void _eeMoveMMREGtoR(int to, int mmreg); - -// extra ops -void _eeWriteConstMem16OP(u32 mem, int mmreg, int op); -void _eeWriteConstMem32OP(u32 mem, int mmreg, int op); - -int recMemConstRead8(u32 x86reg, u32 mem, u32 sign); -int recMemConstRead16(u32 x86reg, u32 mem, u32 sign); -int recMemConstRead32(u32 x86reg, u32 mem); -void recMemConstRead64(u32 mem, int mmreg); -void recMemConstRead128(u32 mem, int xmmreg); - -int recMemConstWrite8(u32 mem, int mmreg); -int recMemConstWrite16(u32 mem, int mmreg); -int recMemConstWrite32(u32 mem, int mmreg); -int recMemConstWrite64(u32 mem, int mmreg); -int recMemConstWrite128(u32 mem, int xmmreg); -#endif - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +////////// +// Rewritten by zerofrog to add os virtual memory +////////// + +#ifndef __MEMORY_H__ +#define __MEMORY_H__ + +#ifdef __LINUX__ +#include +#endif + +//#define ENABLECACHE + +namespace Ps2MemSize +{ + static const uint Base = 0x02000000; // 32 MB main memory! + static const uint Rom = 0x00400000; // 4 MB main rom + static const uint Rom1 = 0x00040000; // DVD player + static const uint Rom2 = 0x00080000; // Chinese rom extension (?) + static const uint ERom = 0x001C0000; // DVD player extensions (?) + static const uint Hardware = 0x00010000; + static const uint Scratch = 0x00004000; + + static const uint IopRam = 0x00200000; // 2MB main ram on the IOP. + static const uint IopHardware = 0x00010000; + + static const uint GSregs = 0x00002000; // 8k for the GS registers and stuff. +} + +extern u8 *psM; //32mb Main Ram +extern u8 *psR; //4mb rom area +extern u8 *psR1; //256kb rom1 area (actually 196kb, but can't mask this) +extern u8 *psR2; // 0x00080000 +extern u8 *psER; // 0x001C0000 +extern u8 *psS; //0.015 mb, scratch pad + +#define PS2MEM_BASE psM +#define PS2MEM_HW psH +#define PS2MEM_ROM psR +#define PS2MEM_ROM1 psR1 +#define PS2MEM_ROM2 psR2 +#define PS2MEM_EROM psER +#define PS2MEM_SCRATCH psS + +extern u8 g_RealGSMem[0x2000]; +#define PS2MEM_GS g_RealGSMem + +//#define _PSM(mem) (memLUTR[(mem) >> 12] == 0 ? NULL : (void*)(memLUTR[(mem) >> 12] + ((mem) & 0xfff))) +#define PSM(mem) (vtlb_GetPhyPtr(mem&0x1fffffff)) //pcsx2 is a competition.The one with most hacks wins :D + +#define psMs8(mem) (*(s8 *)&PS2MEM_BASE[(mem) & 0x1ffffff]) +#define psMs16(mem) (*(s16*)&PS2MEM_BASE[(mem) & 0x1ffffff]) +#define psMs32(mem) (*(s32*)&PS2MEM_BASE[(mem) & 0x1ffffff]) +#define psMs64(mem) (*(s64*)&PS2MEM_BASE[(mem) & 0x1ffffff]) +#define psMu8(mem) (*(u8 *)&PS2MEM_BASE[(mem) & 0x1ffffff]) +#define psMu16(mem) (*(u16*)&PS2MEM_BASE[(mem) & 0x1ffffff]) +#define psMu32(mem) (*(u32*)&PS2MEM_BASE[(mem) & 0x1ffffff]) +#define psMu64(mem) (*(u64*)&PS2MEM_BASE[(mem) & 0x1ffffff]) + +#define psRs8(mem) (*(s8 *)&PS2MEM_ROM[(mem) & 0x3fffff]) +#define psRs16(mem) (*(s16*)&PS2MEM_ROM[(mem) & 0x3fffff]) +#define psRs32(mem) (*(s32*)&PS2MEM_ROM[(mem) & 0x3fffff]) +#define psRs64(mem) (*(s64*)&PS2MEM_ROM[(mem) & 0x3fffff]) +#define psRu8(mem) (*(u8 *)&PS2MEM_ROM[(mem) & 0x3fffff]) +#define psRu16(mem) (*(u16*)&PS2MEM_ROM[(mem) & 0x3fffff]) +#define psRu32(mem) (*(u32*)&PS2MEM_ROM[(mem) & 0x3fffff]) +#define psRu64(mem) (*(u64*)&PS2MEM_ROM[(mem) & 0x3fffff]) + +#define psR1s8(mem) (*(s8 *)&PS2MEM_ROM1[(mem) & 0x3ffff]) +#define psR1s16(mem) (*(s16*)&PS2MEM_ROM1[(mem) & 0x3ffff]) +#define psR1s32(mem) (*(s32*)&PS2MEM_ROM1[(mem) & 0x3ffff]) +#define psR1s64(mem) (*(s64*)&PS2MEM_ROM1[(mem) & 0x3ffff]) +#define psR1u8(mem) (*(u8 *)&PS2MEM_ROM1[(mem) & 0x3ffff]) +#define psR1u16(mem) (*(u16*)&PS2MEM_ROM1[(mem) & 0x3ffff]) +#define psR1u32(mem) (*(u32*)&PS2MEM_ROM1[(mem) & 0x3ffff]) +#define psR1u64(mem) (*(u64*)&PS2MEM_ROM1[(mem) & 0x3ffff]) + +#define psR2s8(mem) (*(s8 *)&PS2MEM_ROM2[(mem) & 0x3ffff]) +#define psR2s16(mem) (*(s16*)&PS2MEM_ROM2[(mem) & 0x3ffff]) +#define psR2s32(mem) (*(s32*)&PS2MEM_ROM2[(mem) & 0x3ffff]) +#define psR2s64(mem) (*(s64*)&PS2MEM_ROM2[(mem) & 0x3ffff]) +#define psR2u8(mem) (*(u8 *)&PS2MEM_ROM2[(mem) & 0x3ffff]) +#define psR2u16(mem) (*(u16*)&PS2MEM_ROM2[(mem) & 0x3ffff]) +#define psR2u32(mem) (*(u32*)&PS2MEM_ROM2[(mem) & 0x3ffff]) +#define psR2u64(mem) (*(u64*)&PS2MEM_ROM2[(mem) & 0x3ffff]) + +#define psERs8(mem) (*(s8 *)&PS2MEM_EROM[(mem) & 0x3ffff]) +#define psERs16(mem) (*(s16*)&PS2MEM_EROM[(mem) & 0x3ffff]) +#define psERs32(mem) (*(s32*)&PS2MEM_EROM[(mem) & 0x3ffff]) +#define psERs64(mem) (*(s64*)&PS2MEM_EROM[(mem) & 0x3ffff]) +#define psERu8(mem) (*(u8 *)&PS2MEM_EROM[(mem) & 0x3ffff]) +#define psERu16(mem) (*(u16*)&PS2MEM_EROM[(mem) & 0x3ffff]) +#define psERu32(mem) (*(u32*)&PS2MEM_EROM[(mem) & 0x3ffff]) +#define psERu64(mem) (*(u64*)&PS2MEM_EROM[(mem) & 0x3ffff]) + +#define psSs8(mem) (*(s8 *)&PS2MEM_SCRATCH[(mem) & 0x3fff]) +#define psSs16(mem) (*(s16*)&PS2MEM_SCRATCH[(mem) & 0x3fff]) +#define psSs32(mem) (*(s32*)&PS2MEM_SCRATCH[(mem) & 0x3fff]) +#define psSs64(mem) (*(s64*)&PS2MEM_SCRATCH[(mem) & 0x3fff]) +#define psSu8(mem) (*(u8 *)&PS2MEM_SCRATCH[(mem) & 0x3fff]) +#define psSu16(mem) (*(u16*)&PS2MEM_SCRATCH[(mem) & 0x3fff]) +#define psSu32(mem) (*(u32*)&PS2MEM_SCRATCH[(mem) & 0x3fff]) +#define psSu64(mem) (*(u64*)&PS2MEM_SCRATCH[(mem) & 0x3fff]) + +#define PSMs8(mem) (*(s8 *)PSM(mem)) +#define PSMs16(mem) (*(s16*)PSM(mem)) +#define PSMs32(mem) (*(s32*)PSM(mem)) +#define PSMs64(mem) (*(s64*)PSM(mem)) +#define PSMu8(mem) (*(u8 *)PSM(mem)) +#define PSMu16(mem) (*(u16*)PSM(mem)) +#define PSMu32(mem) (*(u32*)PSM(mem)) +#define PSMu64(mem) (*(u64*)PSM(mem)) + +extern void memAlloc(); +extern void memReset(); // clears PS2 ram and loads the bios. Throws Exception::FileNotFound on error. +extern void memShutdown(); +extern void memSetKernelMode(); +extern void memSetSupervisorMode(); +extern void memSetUserMode(); +extern void memSetPageAddr(u32 vaddr, u32 paddr); +extern void memClearPageAddr(u32 vaddr); + +extern void memMapVUmicro(); + +#ifdef __LINUX__ +void SysPageFaultExceptionFilter( int signal, siginfo_t *info, void * ); +void __fastcall InstallLinuxExceptionHandler(); +void __fastcall ReleaseLinuxExceptionHandler(); +#else +int SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps); +#endif + +#include "vtlb.h" + +int mmap_GetRamPageInfo(void* ptr); +void mmap_MarkCountedRamPage(void* ptr,u32 vaddr); +void mmap_ResetBlockTracking(); + +extern void __fastcall memRead8(u32 mem, u8 *out); +extern void __fastcall memRead16(u32 mem, u16 *out); +extern void __fastcall memRead32(u32 mem, u32 *out); + +#define memRead64 vtlb_memRead64 +#define memRead128 vtlb_memRead128 + +#define memWrite8 vtlb_memWrite8 +#define memWrite16 vtlb_memWrite16 +#define memWrite32 vtlb_memWrite32 +#define memWrite64 vtlb_memWrite64 +#define memWrite128 vtlb_memWrite128 + +#define _eeReadConstMem8 0&& +#define _eeReadConstMem16 0&& +#define _eeReadConstMem32 0&& +#define _eeReadConstMem128 0&& +#define _eeWriteConstMem8 0&& +#define _eeWriteConstMem16 0&& +#define _eeWriteConstMem32 0&& +#define _eeWriteConstMem64 0&& +#define _eeWriteConstMem128 0&& +#define _eeMoveMMREGtoR 0&& + +// extra ops +#define _eeWriteConstMem16OP 0&& +#define _eeWriteConstMem32OP 0&& + +#define recMemConstRead8 0&& +#define recMemConstRead16 0&& +#define recMemConstRead32 0&& +#define recMemConstRead64 0&& +#define recMemConstRead128 0&& + +#define recMemConstWrite8 0&& +#define recMemConstWrite16 0&& +#define recMemConstWrite32 0&& +#define recMemConstWrite64 0&& +#define recMemConstWrite128 0&& + +extern void loadBiosRom( const char *ext, u8 *dest, long maxSize ); +extern u16 ba0R16(u32 mem); + +////////////////////////////////////////////////////////////////////////// +// The rest of this header contains the old VM version of the Memory.h API. +// Left in for references purposes. + +#ifdef PCSX2_VIRTUAL_MEM + +#define PS2MEM_BASE_ 0x15000000 +#define PS2MEM_PSX_ (PS2MEM_BASE_+0x1c000000) + +#ifdef _WIN32 +struct PSMEMORYMAP +{ + uptr* aPFNs, *aVFNs; +}; +#endif + +#define TRANSFORM_ADDR(memaddr) ( ((u32)(memaddr)>=0x40000000) ? ((memaddr)&~0xa0000000) : (memaddr) ) + +//new memory model +#define PS2MEM_BASE ((u8*)PS2MEM_BASE_) +#define PS2MEM_HW ((u8*)((u32)PS2MEM_BASE+0x10000000)) +#define PS2MEM_ROM ((u8*)((u32)PS2MEM_BASE+0x1fc00000)) +#define PS2MEM_ROM1 ((u8*)((u32)PS2MEM_BASE+0x1e000000)) +#define PS2MEM_ROM2 ((u8*)((u32)PS2MEM_BASE+0x1e400000)) +#define PS2MEM_EROM ((u8*)((u32)PS2MEM_BASE+0x1e040000)) +#define PS2MEM_PSX ((u8*)PS2MEM_PSX_) +#define PS2MEM_SCRATCH ((u8*)((u32)PS2MEM_BASE+0x50000000)) +#define PS2MEM_VU0MICRO ((u8*)((u32)PS2MEM_BASE+0x11000000)) +#define PS2MEM_VU0MEM ((u8*)((u32)PS2MEM_BASE+0x11004000)) +#define PS2MEM_VU1MICRO ((u8*)((u32)PS2MEM_BASE+0x11008000)) +#define PS2MEM_VU1MEM ((u8*)((u32)PS2MEM_BASE+0x1100c000)) + +// function for mapping memory +#define PS2MEM_PSXHW ((u8*)((u32)PS2MEM_BASE+0x1f800000)) +//#define PS2MEM_PSXHW2 ((u8*)((u32)PS2MEM_BASE+0x1fa00000)) +#define PS2MEM_PSXHW4 ((u8*)((u32)PS2MEM_BASE+0x1f400000)) +#define PS2MEM_GS ((u8*)((u32)PS2MEM_BASE+0x12000000)) +#define PS2MEM_DEV9 ((u8*)((u32)PS2MEM_BASE+0x14000000)) +#define PS2MEM_SPU2 ((u8*)((u32)PS2MEM_BASE+0x1f900000)) +#define PS2MEM_SPU2_ ((u8*)((u32)PS2MEM_BASE+0x1f000000)) // ? +#define PS2MEM_B80 ((u8*)((u32)PS2MEM_BASE+0x18000000)) +#define PS2MEM_BA0 ((u8*)((u32)PS2MEM_BASE+0x1a000000)) + +#define PSM(mem) (PS2MEM_BASE + TRANSFORM_ADDR(mem)) + +int __fastcall memRead8(u32 mem, u8 *out); +int __fastcall memRead8RS(u32 mem, u64 *out); +int __fastcall memRead8RU(u32 mem, u64 *out); +int __fastcall memRead16(u32 mem, u16 *out); +int __fastcall memRead16RS(u32 mem, u64 *out); +int __fastcall memRead16RU(u32 mem, u64 *out); +int __fastcall memRead32(u32 mem, u32 *out); +int __fastcall memRead32RS(u32 mem, u64 *out); +int __fastcall memRead32RU(u32 mem, u64 *out); +int __fastcall memRead64(u32 mem, u64 *out); +int __fastcall memRead128(u32 mem, u64 *out); +void __fastcall memWrite8 (u32 mem, u8 value); +void __fastcall memWrite16(u32 mem, u16 value); +void __fastcall memWrite32(u32 mem, u32 value); +void __fastcall memWrite64(u32 mem, const u64 *value); +void __fastcall memWrite128(u32 mem, const u64 *value); + +// recMemConstRead8, recMemConstRead16, recMemConstRead32 return 1 if a call was made, 0 otherwise +u8 recMemRead8(); +u16 recMemRead16(); +u32 recMemRead32(); +void recMemRead64(u64 *out); +void recMemRead128(u64 *out); + +void recMemWrite8(); +void recMemWrite16(); +void recMemWrite32(); +void recMemWrite64(); +void recMemWrite128(); + +void _eeReadConstMem8(int mmreg, u32 mem, int sign); +void _eeReadConstMem16(int mmreg, u32 mem, int sign); +void _eeReadConstMem32(int mmreg, u32 mem); +void _eeReadConstMem128(int mmreg, u32 mem); +void _eeWriteConstMem8(u32 mem, int mmreg); +void _eeWriteConstMem16(u32 mem, int mmreg); +void _eeWriteConstMem32(u32 mem, int mmreg); +void _eeWriteConstMem64(u32 mem, int mmreg); +void _eeWriteConstMem128(u32 mem, int mmreg); +void _eeMoveMMREGtoR(int to, int mmreg); + +// extra ops +void _eeWriteConstMem16OP(u32 mem, int mmreg, int op); +void _eeWriteConstMem32OP(u32 mem, int mmreg, int op); + +int recMemConstRead8(u32 x86reg, u32 mem, u32 sign); +int recMemConstRead16(u32 x86reg, u32 mem, u32 sign); +int recMemConstRead32(u32 x86reg, u32 mem); +void recMemConstRead64(u32 mem, int mmreg); +void recMemConstRead128(u32 mem, int xmmreg); + +int recMemConstWrite8(u32 mem, int mmreg); +int recMemConstWrite16(u32 mem, int mmreg); +int recMemConstWrite32(u32 mem, int mmreg); +int recMemConstWrite64(u32 mem, int mmreg); +int recMemConstWrite128(u32 mem, int xmmreg); +#endif + +#endif diff --git a/pcsx2/MemoryCard.cpp b/pcsx2/MemoryCard.cpp index 79fc6f799e..96a70d7e1e 100644 --- a/pcsx2/MemoryCard.cpp +++ b/pcsx2/MemoryCard.cpp @@ -1,158 +1,158 @@ -/* Pcsx2 - Pc Ps2 Emulator -* Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Misc.h" -#include "MemoryCard.h" -#include "Paths.h" - -#ifdef WIN32 -extern void NTFS_CompressFile( const char* file ); -#endif - -static FILE* MemoryCard[2] = { NULL, NULL }; - -// Ensures memory card files are created/initialized. -void MemoryCard_Init() -{ - for( int i=0; i<2; i++ ) - { - if( MemoryCard[i] == NULL ) - MemoryCard[i] = LoadMcd(i); - } -} - -void MemoryCard_Shutdown() -{ - for( int i=0; i<2; i++ ) - { - if(MemoryCard[0]) fclose(MemoryCard[i]); - MemoryCard[0] = NULL; - } -} - -bool TestMcdIsPresent( int mcd ) -{ - jASSUME( mcd == 0 || mcd == 1 ); - return MemoryCard[mcd] != NULL; -} - -FILE *LoadMcd(int mcd) -{ - string str; - FILE *f; - - jASSUME( mcd == 0 || mcd == 1 ); - str = (mcd == 0) ? Config.Mcd1 : Config.Mcd2; - - if( str.empty() ) - Path::Combine( str, MEMCARDS_DIR, fmt_string( "Mcd00%d.ps2", mcd ) ); - - if( !Path::Exists(str) ) - CreateMcd(str.c_str()); - -#ifdef WIN32 - NTFS_CompressFile( str.c_str() ); -#endif - - f = fopen(str.c_str(), "r+b"); - - if (f == NULL) { - Msgbox::Alert("Failed loading MemCard from file: %hs", params &str); - return NULL; - } - - return f; -} - -void SeekMcd(FILE *f, u32 adr) -{ - u32 size; - - fseek(f, 0, SEEK_END); size = ftell(f); - if (size == MCD_SIZE + 64) - fseek(f, adr + 64, SEEK_SET); - else if (size == MCD_SIZE + 3904) - fseek(f, adr + 3904, SEEK_SET); - else - fseek(f, adr, SEEK_SET); -} - -void ReadMcd(int mcd, u8 *data, u32 adr, int size) -{ - jASSUME( mcd == 0 || mcd == 1 ); - FILE* const mcfp = MemoryCard[mcd]; - - if (mcfp == NULL) { - memset(data, 0, size); - return; - } - SeekMcd(mcfp, adr); - fread(data, 1, size, mcfp); -} - -void SaveMcd(int mcd, const u8 *data, u32 adr, int size) -{ - jASSUME( mcd == 0 || mcd == 1 ); - FILE* const mcfp = MemoryCard[mcd]; - - SeekMcd(mcfp, adr); - u8 *currentdata = (u8 *)malloc(size); - fread(currentdata, 1, size, mcfp); - for (int i=0; i(data); // clears to -1's - - jASSUME( mcd == 0 || mcd == 1 ); - FILE* const mcfp = MemoryCard[mcd]; - SeekMcd(mcfp, adr); - fwrite(data, 1, 528*16, mcfp); -} - - -void CreateMcd(const char *mcd) -{ - FILE *fp; - int i=0, j=0; - //int enc[16] = {0x77,0x7f,0x7f,0x77,0x7f,0x7f,0x77,0x7f,0x7f,0x77,0x7f,0x7f,0,0,0,0}; - - fp = fopen(mcd, "wb"); - if (fp == NULL) return; - for(i=0; i < 16384; i++) - { - for(j=0; j < 528; j++) fputc(0xFF,fp); - // for(j=0; j < 16; j++) fputc(enc[j],fp); - } - fclose(fp); -} - +/* Pcsx2 - Pc Ps2 Emulator +* Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Misc.h" +#include "MemoryCard.h" +#include "Paths.h" + +#ifdef WIN32 +extern void NTFS_CompressFile( const char* file ); +#endif + +static FILE* MemoryCard[2] = { NULL, NULL }; + +// Ensures memory card files are created/initialized. +void MemoryCard_Init() +{ + for( int i=0; i<2; i++ ) + { + if( MemoryCard[i] == NULL ) + MemoryCard[i] = LoadMcd(i); + } +} + +void MemoryCard_Shutdown() +{ + for( int i=0; i<2; i++ ) + { + if(MemoryCard[0]) fclose(MemoryCard[i]); + MemoryCard[0] = NULL; + } +} + +bool TestMcdIsPresent( int mcd ) +{ + jASSUME( mcd == 0 || mcd == 1 ); + return MemoryCard[mcd] != NULL; +} + +FILE *LoadMcd(int mcd) +{ + string str; + FILE *f; + + jASSUME( mcd == 0 || mcd == 1 ); + str = (mcd == 0) ? Config.Mcd1 : Config.Mcd2; + + if( str.empty() ) + Path::Combine( str, MEMCARDS_DIR, fmt_string( "Mcd00%d.ps2", mcd ) ); + + if( !Path::Exists(str) ) + CreateMcd(str.c_str()); + +#ifdef WIN32 + NTFS_CompressFile( str.c_str() ); +#endif + + f = fopen(str.c_str(), "r+b"); + + if (f == NULL) { + Msgbox::Alert("Failed loading MemCard from file: %hs", params &str); + return NULL; + } + + return f; +} + +void SeekMcd(FILE *f, u32 adr) +{ + u32 size; + + fseek(f, 0, SEEK_END); size = ftell(f); + if (size == MCD_SIZE + 64) + fseek(f, adr + 64, SEEK_SET); + else if (size == MCD_SIZE + 3904) + fseek(f, adr + 3904, SEEK_SET); + else + fseek(f, adr, SEEK_SET); +} + +void ReadMcd(int mcd, u8 *data, u32 adr, int size) +{ + jASSUME( mcd == 0 || mcd == 1 ); + FILE* const mcfp = MemoryCard[mcd]; + + if (mcfp == NULL) { + memset(data, 0, size); + return; + } + SeekMcd(mcfp, adr); + fread(data, 1, size, mcfp); +} + +void SaveMcd(int mcd, const u8 *data, u32 adr, int size) +{ + jASSUME( mcd == 0 || mcd == 1 ); + FILE* const mcfp = MemoryCard[mcd]; + + SeekMcd(mcfp, adr); + u8 *currentdata = (u8 *)malloc(size); + fread(currentdata, 1, size, mcfp); + for (int i=0; i(data); // clears to -1's + + jASSUME( mcd == 0 || mcd == 1 ); + FILE* const mcfp = MemoryCard[mcd]; + SeekMcd(mcfp, adr); + fwrite(data, 1, 528*16, mcfp); +} + + +void CreateMcd(const char *mcd) +{ + FILE *fp; + int i=0, j=0; + //int enc[16] = {0x77,0x7f,0x7f,0x77,0x7f,0x7f,0x77,0x7f,0x7f,0x77,0x7f,0x7f,0,0,0,0}; + + fp = fopen(mcd, "wb"); + if (fp == NULL) return; + for(i=0; i < 16384; i++) + { + for(j=0; j < 528; j++) fputc(0xFF,fp); + // for(j=0; j < 16; j++) fputc(enc[j],fp); + } + fclose(fp); +} + diff --git a/pcsx2/MemoryCard.h b/pcsx2/MemoryCard.h index 17e6a87fdf..c1bd451701 100644 --- a/pcsx2/MemoryCard.h +++ b/pcsx2/MemoryCard.h @@ -1,49 +1,49 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef _MEMORYCARD_H_ -#define _MEMORYCARD_H_ - -static const int MCD_SIZE = 1024 * 8 * 16; -static const int MC2_SIZE = 1024 * 528 * 16; - -extern void MemoryCard_Init(); -extern void MemoryCard_Shutdown(); - -extern bool TestMcdIsPresent(int mcd); -extern FILE *LoadMcd(int mcd); -extern void ReadMcd(int mcd, u8 *data, u32 adr, int size); -extern void SaveMcd(int mcd, const u8 *data, u32 adr, int size); -extern void EraseMcd(int mcd, u32 adr); -extern void CreateMcd(const char *mcd); - -#if 0 // unused code? -struct McdBlock -{ - s8 Title[48]; - s8 ID[14]; - s8 Name[16]; - int IconCount; - u16 Icon[16*16*3]; - u8 Flags; -}; - -void GetMcdBlockInfo(int mcd, int block, McdBlock *info); -#endif - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef _MEMORYCARD_H_ +#define _MEMORYCARD_H_ + +static const int MCD_SIZE = 1024 * 8 * 16; +static const int MC2_SIZE = 1024 * 528 * 16; + +extern void MemoryCard_Init(); +extern void MemoryCard_Shutdown(); + +extern bool TestMcdIsPresent(int mcd); +extern FILE *LoadMcd(int mcd); +extern void ReadMcd(int mcd, u8 *data, u32 adr, int size); +extern void SaveMcd(int mcd, const u8 *data, u32 adr, int size); +extern void EraseMcd(int mcd, u32 adr); +extern void CreateMcd(const char *mcd); + +#if 0 // unused code? +struct McdBlock +{ + s8 Title[48]; + s8 ID[14]; + s8 Name[16]; + int IconCount; + u16 Icon[16*16*3]; + u8 Flags; +}; + +void GetMcdBlockInfo(int mcd, int block, McdBlock *info); +#endif + +#endif diff --git a/pcsx2/MemoryVM.cpp b/pcsx2/MemoryVM.cpp index 9f67252b1a..d5d9e15501 100644 --- a/pcsx2/MemoryVM.cpp +++ b/pcsx2/MemoryVM.cpp @@ -1,2140 +1,2140 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -// Virtual memory model for Pcsx2. -// This module is left in primarily as a reference for the implementation of constant -// propagation. - -#include "PrecompiledHeader.h" -#include "Common.h" -#include "iR5900.h" - -#include "PsxCommon.h" -#include "VUmicro.h" -#include "GS.h" -#include "vtlb.h" -#include "IPU/IPU.h" - -#ifdef PCSX2_VIRTUAL_MEM -#include "iR3000A.h" // VM handles both Iop and EE memory from here. >_< -#include "Counters.h" -#endif - -#pragma warning(disable:4799) // No EMMS at end of function - -#ifdef ENABLECACHE -#include "Cache.h" -#endif - -#ifdef __LINUX__ -#include -#endif - -///////////////////////////// -// VIRTUAL MEM START -///////////////////////////// -#ifdef PCSX2_VIRTUAL_MEM - -class vm_alloc_failed_exception : public std::runtime_error -{ -public: - void* requested_addr; - int requested_size; - void* returned_addr; - - explicit vm_alloc_failed_exception( void* reqadr, uint reqsize, void* retadr ) : - std::runtime_error( "virtual memory allocation failure." ) - , requested_addr( reqadr ) - , requested_size( reqsize ) - , returned_addr( retadr ) - {} -}; - -PSMEMORYBLOCK s_psM = {0}, s_psHw = {0}, s_psS = {0}, s_psxM = {0}, s_psVuMem = {0}; - -static void PHYSICAL_ALLOC( void* ptr, uint size, PSMEMORYBLOCK& block) -{ - if(SysPhysicalAlloc(size, &block) == -1 ) - throw vm_alloc_failed_exception( ptr, size, NULL ); - if(SysVirtualPhyAlloc(ptr, size, &block) == -1) - throw vm_alloc_failed_exception( ptr, size, NULL ); -} - -static void PHYSICAL_FREE( void* ptr, uint size, PSMEMORYBLOCK& block) -{ - SysVirtualFree(ptr, size); - SysPhysicalFree(&block); -} - - -#ifdef _WIN32 // windows implementation of vm - -static PSMEMORYMAP initMemoryMap(uptr* aPFNs, uptr* aVFNs) -{ - PSMEMORYMAP m; - m.aPFNs = aPFNs; - m.aVFNs = aVFNs; - return m; -} - -// only do vm hack for release -#ifndef PCSX2_DEVBUILD -#define VM_HACK -#endif - -// virtual memory blocks -PSMEMORYMAP *memLUT = NULL; - -static void VIRTUAL_ALLOC( void* base, uint size, uint Protection) -{ - LPVOID lpMemReserved = VirtualAlloc( base, size, MEM_RESERVE|MEM_COMMIT, Protection ); - if( base != lpMemReserved ) - throw vm_alloc_failed_exception( base, size, lpMemReserved ); -} - -static void ReserveExtraMem( void* base, uint size ) -{ - void* pExtraMem = VirtualAlloc(base, size, MEM_RESERVE|MEM_PHYSICAL, PAGE_READWRITE); - if( pExtraMem != base ) - throw vm_alloc_failed_exception( base, size, pExtraMem); -} - -void memAlloc() -{ - LPVOID pExtraMem = NULL; - - // release the previous reserved mem - VirtualFree(PS2MEM_BASE, 0, MEM_RELEASE); - - try - { - // allocate all virtual memory - PHYSICAL_ALLOC(PS2MEM_BASE, Ps2MemSize::Base, s_psM); - VIRTUAL_ALLOC(PS2MEM_ROM, Ps2MemSize::Rom, PAGE_READONLY); - VIRTUAL_ALLOC(PS2MEM_ROM1, Ps2MemSize::Rom1, PAGE_READONLY); - VIRTUAL_ALLOC(PS2MEM_ROM2, Ps2MemSize::Rom2, PAGE_READONLY); - VIRTUAL_ALLOC(PS2MEM_EROM, Ps2MemSize::ERom, PAGE_READONLY); - PHYSICAL_ALLOC(PS2MEM_SCRATCH, Ps2MemSize::Scratch, s_psS); - PHYSICAL_ALLOC(PS2MEM_HW, Ps2MemSize::Hardware, s_psHw); - PHYSICAL_ALLOC(PS2MEM_PSX, Ps2MemSize::IopRam, s_psxM); - PHYSICAL_ALLOC(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem); - - VIRTUAL_ALLOC(PS2MEM_PSXHW, Ps2MemSize::IopHardware, PAGE_READWRITE); - //VIRTUAL_ALLOC(PS2MEM_PSXHW2, 0x00010000, PAGE_READWRITE); - VIRTUAL_ALLOC(PS2MEM_PSXHW4, 0x00010000, PAGE_NOACCESS); - VIRTUAL_ALLOC(PS2MEM_GS, 0x00002000, PAGE_READWRITE); - VIRTUAL_ALLOC(PS2MEM_DEV9, 0x00010000, PAGE_NOACCESS); - VIRTUAL_ALLOC(PS2MEM_SPU2, 0x00010000, PAGE_NOACCESS); - VIRTUAL_ALLOC(PS2MEM_SPU2_, 0x00010000, PAGE_NOACCESS); - - VIRTUAL_ALLOC(PS2MEM_B80, 0x00010000, PAGE_READWRITE); - VIRTUAL_ALLOC(PS2MEM_BA0, 0x00010000, PAGE_READWRITE); - - // reserve the left over 224Mb, don't map - ReserveExtraMem( PS2MEM_BASE+Ps2MemSize::Base, 0x0e000000 ); - - // reserve left over psx mem - ReserveExtraMem( PS2MEM_PSX+Ps2MemSize::IopRam, 0x00600000 ); - - // reserve gs mem - ReserveExtraMem( PS2MEM_BASE+0x20000000, 0x10000000 ); - - // special addrs mmap - VIRTUAL_ALLOC(PS2MEM_BASE+0x5fff0000, 0x10000, PAGE_READWRITE); - - // alloc virtual mappings - if( memLUT == NULL ) - memLUT = (PSMEMORYMAP*)_aligned_malloc(0x100000 * sizeof(PSMEMORYMAP), 16); - if( memLUT == NULL ) - throw Exception::OutOfMemory( "memAlloc VM > failed to allocated memory for LUT." ); - } - catch( vm_alloc_failed_exception& ex ) - { - Console::Error( "Virtual Memory Error > Cannot reserve %dk memory block at 0x%8.8x", params - ex.requested_size / 1024, ex.requested_addr ); - - Console::Error( "\tError code: %d \tReturned address: 0x%8.8x", params - GetLastError(), ex.returned_addr); - - memShutdown(); - } - catch( std::exception& ) - { - memShutdown(); - } -} - -void memShutdown() -{ - // Free up the "extra mem" reservations - VirtualFree(PS2MEM_BASE+Ps2MemSize::Base, 0, MEM_RELEASE); - VirtualFree(PS2MEM_PSX+Ps2MemSize::IopRam, 0, MEM_RELEASE); - VirtualFree(PS2MEM_BASE+0x20000000, 0, MEM_RELEASE); // GS reservation - - PHYSICAL_FREE(PS2MEM_BASE, Ps2MemSize::Base, s_psM); - SysMunmap(PS2MEM_ROM, Ps2MemSize::Rom); - SysMunmap(PS2MEM_ROM1, Ps2MemSize::Rom1); - SysMunmap(PS2MEM_ROM2, Ps2MemSize::Rom2); - SysMunmap(PS2MEM_EROM, Ps2MemSize::ERom); - PHYSICAL_FREE(PS2MEM_SCRATCH, Ps2MemSize::Scratch, s_psS); - PHYSICAL_FREE(PS2MEM_HW, Ps2MemSize::Hardware, s_psHw); - PHYSICAL_FREE(PS2MEM_PSX, Ps2MemSize::IopRam, s_psxM); - PHYSICAL_FREE(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem); - - SysMunmap(PS2MEM_VU0MICRO, 0x00010000); // allocate for all VUs - - SysMunmap(PS2MEM_PSXHW, Ps2MemSize::IopHardware); - //SysMunmap(PS2MEM_PSXHW2, 0x00010000); - SysMunmap(PS2MEM_PSXHW4, 0x00010000); - SysMunmap(PS2MEM_GS, 0x00002000); - SysMunmap(PS2MEM_DEV9, 0x00010000); - SysMunmap(PS2MEM_SPU2, 0x00010000); - SysMunmap(PS2MEM_SPU2_, 0x00010000); - - SysMunmap(PS2MEM_B80, 0x00010000); - SysMunmap(PS2MEM_BA0, 0x00010000); - - // Special Addrs.. ? - SysMunmap(PS2MEM_BASE+0x5fff0000, 0x10000); - - VirtualFree(PS2MEM_VU0MICRO, 0, MEM_RELEASE); - - safe_aligned_free( memLUT ); - - // reserve mem - VirtualAlloc(PS2MEM_BASE, 0x40000000, MEM_RESERVE, PAGE_NOACCESS); -} - -//NOTE: A lot of the code reading depends on the registers being less than 8 -// MOV8 88/8A -// MOV16 6689 -// MOV32 89/8B -// SSEMtoR64 120f -// SSERtoM64 130f -// SSEMtoR128 280f -// SSERtoM128 290f - -#define SKIP_WRITE() { \ - switch(code&0xff) { \ - case 0x88: \ - if( !(code&0x8000) ) goto DefaultHandler; \ - ContextRecord->Eip += 6; \ - break; \ - case 0x66: \ - assert( code&0x800000 ); \ - assert( (code&0xffff) == 0x8966 ); \ - ContextRecord->Eip += 7; \ - break; \ - case 0x89: \ - assert( code&0x8000 ); \ - ContextRecord->Eip += 6; \ - break; \ - case 0x0f: /* 130f, 230f*/ \ - assert( (code&0xffff) == 0x290f || (code&0xffff) == 0x130f ); \ - assert( code&0x800000 ); \ - ContextRecord->Eip += 7; \ - break; \ - default: \ - goto DefaultHandler; \ -} \ -} \ - -#define SKIP_READ() { \ - switch(code&0xff) { \ - case 0x8A: \ - if( !(code&0x8000) ) goto DefaultHandler; \ - ContextRecord->Eip += 6; \ - rd = (code>>(8+3))&7; \ - break; \ - case 0x66: \ - if( (code&0x07000000) == 0x05000000 ) ContextRecord->Eip += 8; /* 8 for mem reads*/ \ - else ContextRecord->Eip += 4 + ((code&0x1f000000) == 0x0c000000) + !!(code&0x40000000); \ - rd = (code>>(24+3))&7; \ - break; \ - case 0x8B: \ - if( !(code&0x8000) ) goto DefaultHandler; \ - ContextRecord->Eip += 6; \ - rd = (code>>(8+3))&7; \ - break; \ - case 0x0f: { \ - assert( (code&0xffff)==0x120f || (code&0xffff)==0x280f || (code&0xffff) == 0xb60f || (code&0xffff) == 0xb70f ); \ - if( !(code&0x800000) ) goto DefaultHandler; \ - ContextRecord->Eip += 7; \ - rd = (code>>(16+3))&7; \ - break; } \ - default: \ - goto DefaultHandler; \ -} \ -} \ - -int SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps) -{ - struct _EXCEPTION_RECORD* ExceptionRecord = eps->ExceptionRecord; - struct _CONTEXT* ContextRecord = eps->ContextRecord; - - u32 addr; - - C_ASSERT(sizeof(ContextRecord->Eax) == 4); - - // If the exception is not a page fault, exit. - if (ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION) - { - return EXCEPTION_CONTINUE_SEARCH; - } - - // get bad virtual address - addr = (u32)ExceptionRecord->ExceptionInformation[1]; - - if( (unsigned)(addr-(u32)PS2MEM_BASE) < 0x60000000) { - PSMEMORYMAP* pmap; - - pmap = &memLUT[(addr-(u32)PS2MEM_BASE)>>12]; - - if( !pmap->aPFNs ) { - // NOTE: this is a hack because the address is truncated and there's no way - // to tell what it's upper bits are (due to OS limitations). - pmap += 0x80000; - if( !pmap->aPFNs ) { - pmap += 0x20000; - if( !pmap->aPFNs ) goto OtherException; - } - //else addr += 0x20000000; - } - - { - //LPVOID pnewaddr; not used - uptr curvaddr = pmap->aVFNs[0]; - - if( curvaddr ) { - // delete the current mapping - SysMapUserPhysicalPages((void*)curvaddr, 1, NULL, 0); - } - - assert( pmap->aPFNs[0] != 0 ); - - pmap->aVFNs[0] = curvaddr = addr&~0xfff; - if( SysMapUserPhysicalPages((void*)curvaddr, 1, pmap->aPFNs, 0) ) - return EXCEPTION_CONTINUE_EXECUTION; - - // try allocing the virtual mem - //pnewaddr = <- not used - /* use here the size of allocation granularity and force rounding down, - because in reserve mode the address is rounded up/down to the nearest - multiple of this granularity; if you did it not this way, in some cases - the same address would be used twice, so the api fails */ - VirtualAlloc((void*)(curvaddr&~0xffff), 0x10000, MEM_RESERVE|MEM_PHYSICAL, PAGE_READWRITE); - - if( SysMapUserPhysicalPages((void*)curvaddr, 1, pmap->aPFNs, 0) ) - return EXCEPTION_CONTINUE_EXECUTION; - - Console::Error("Virtual Memory Error > page 0x%x cannot be found %d (p:%x,v:%x)", params - addr-(u32)PS2MEM_BASE, GetLastError(), pmap->aPFNs[0], curvaddr); - } - } - // check if vumem - else if( (addr&0xffff4000) == 0x11000000 ) { - // vu0mem - SysMapUserPhysicalPages((void*)s_psVuMem.aVFNs[1], 1, NULL, 0); - - s_psVuMem.aVFNs[1] = addr&~0xfff; - SysMapUserPhysicalPages((void*)addr, 1, s_psVuMem.aPFNs, 1); - - //SysPrintf("Exception: vumem\n"); - return EXCEPTION_CONTINUE_EXECUTION; - } -OtherException: - -#ifdef VM_HACK - { - u32 code = *(u32*)ExceptionRecord->ExceptionAddress; - u32 rd = 0; - - if( ExceptionRecord->ExceptionInformation[0] ) { - //SKIP_WRITE(); - // shouldn't be writing - } - else { - SysPrintf("vmhack "); - SKIP_READ(); - //((u32*)&ContextRecord->Eax)[rd] = 0; - return EXCEPTION_CONTINUE_EXECUTION; // TODO: verify this!!! - } - } -DefaultHandler: -#endif - - return EXCEPTION_CONTINUE_SEARCH; -} - -#else // linux implementation - -#define VIRTUAL_ALLOC(base, size, Protection) { \ - void* lpMemReserved = mmap( base, size, Protection, MAP_PRIVATE|MAP_ANONYMOUS ); \ - if( lpMemReserved == NULL || base != lpMemReserved ) \ -{ \ - SysPrintf("Cannot reserve memory at 0x%8.8x(%x).\n", base, lpMemReserved); \ - perror("err"); \ - goto eCleanupAndExit; \ -} \ -} \ - -#define VIRTUAL_FREE(ptr, size) munmap(ptr, size) - -uptr *memLUT = NULL; - -void memAlloc() -{ - int i; - LPVOID pExtraMem = NULL; - - // release the previous reserved mem - munmap(PS2MEM_BASE, 0x40000000); - - // allocate all virtual memory - PHYSICAL_ALLOC(PS2MEM_BASE, Ps2MemSize::Base, s_psM); - VIRTUAL_ALLOC(PS2MEM_ROM, Ps2MemSize::Rom, PROT_READ); - VIRTUAL_ALLOC(PS2MEM_ROM1, Ps2MemSize::Rom1, PROT_READ); - VIRTUAL_ALLOC(PS2MEM_ROM2, Ps2MemSize::Rom2, PROT_READ); - VIRTUAL_ALLOC(PS2MEM_EROM, Ps2MemSize::ERom, PROT_READ); - PHYSICAL_ALLOC(PS2MEM_SCRATCH, 0x00010000, s_psS); - PHYSICAL_ALLOC(PS2MEM_HW, Ps2MemSize::Hardware, s_psHw); - PHYSICAL_ALLOC(PS2MEM_PSX, Ps2MemSize::IopRam, s_psxM); - PHYSICAL_ALLOC(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem); - - VIRTUAL_ALLOC(PS2MEM_PSXHW, Ps2MemSize::IopHardware, PROT_READ|PROT_WRITE); - VIRTUAL_ALLOC(PS2MEM_PSXHW4, 0x00010000, PROT_NONE); - VIRTUAL_ALLOC(PS2MEM_GS, 0x00002000, PROT_READ|PROT_WRITE); - VIRTUAL_ALLOC(PS2MEM_DEV9, 0x00010000, PROT_NONE); - VIRTUAL_ALLOC(PS2MEM_SPU2, 0x00010000, PROT_NONE); - VIRTUAL_ALLOC(PS2MEM_SPU2_, 0x00010000, PROT_NONE); - - VIRTUAL_ALLOC(PS2MEM_B80, 0x00010000, PROT_READ|PROT_WRITE); - VIRTUAL_ALLOC(PS2MEM_BA0, 0x00010000, PROT_READ|PROT_WRITE); - - // special addrs mmap - VIRTUAL_ALLOC(PS2MEM_BASE+0x5fff0000, 0x10000, PROT_READ|PROT_WRITE); - -eCleanupAndExit: - memShutdown(); - return -1; -} - -void memShutdown() -{ - VIRTUAL_FREE(PS2MEM_BASE, 0x40000000); - VIRTUAL_FREE(PS2MEM_PSX, 0x00800000); - - PHYSICAL_FREE(PS2MEM_BASE, Ps2MemSize::Base, s_psM); - VIRTUAL_FREE(PS2MEM_ROM, Ps2MemSize::Rom); - VIRTUAL_FREE(PS2MEM_ROM1, Ps2MemSize::Rom1); - VIRTUAL_FREE(PS2MEM_ROM2, Ps2MemSize::Rom2); - VIRTUAL_FREE(PS2MEM_EROM, Ps2MemSize::ERom); - PHYSICAL_FREE(PS2MEM_SCRATCH, 0x00010000, s_psS); - PHYSICAL_FREE(PS2MEM_HW, Ps2MemSize::Hardware, s_psHw); - PHYSICAL_FREE(PS2MEM_PSX, Ps2MemSize::IopRam, s_psxM); - PHYSICAL_FREE(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem); - - VIRTUAL_FREE(PS2MEM_VU0MICRO, 0x00010000); // allocate for all VUs - - VIRTUAL_FREE(PS2MEM_PSXHW, Ps2MemSize::IopHardware); - VIRTUAL_FREE(PS2MEM_PSXHW4, 0x00010000); - VIRTUAL_FREE(PS2MEM_GS, 0x00002000); - VIRTUAL_FREE(PS2MEM_DEV9, 0x00010000); - VIRTUAL_FREE(PS2MEM_SPU2, 0x00010000); - VIRTUAL_FREE(PS2MEM_SPU2_, 0x00010000); - - VIRTUAL_FREE(PS2MEM_B80, 0x00010000); - VIRTUAL_FREE(PS2MEM_BA0, 0x00010000); - - VirtualFree(PS2MEM_VU0MICRO, 0, MEM_RELEASE); - - safe_aligned_free(memLUT); - - // reserve mem - if( mmap(PS2MEM_BASE, 0x40000000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0) != PS2MEM_BASE ) { - SysPrintf("failed to reserve mem\n"); - } -} - -#endif // _WIN32 - -void vm_Reset() -{ - jASSUME( memLUT != NULL ); - - memzero_ptr(memLUT); - for (int i=0; i<0x02000; i++) memLUT[i + 0x00000] = initMemoryMap(&s_psM.aPFNs[i], &s_psM.aVFNs[i]); - for (int i=2; i<0x00010; i++) memLUT[i + 0x10000] = initMemoryMap(&s_psHw.aPFNs[i], &s_psHw.aVFNs[i]); - for (int i=0; i<0x00800; i++) memLUT[i + 0x1c000] = initMemoryMap(&s_psxM.aPFNs[(i & 0x1ff)], &s_psxM.aVFNs[(i & 0x1ff)]); - for (int i=0; i<0x00004; i++) - { - memLUT[i + 0x11000] = initMemoryMap(&s_psVuMem.aPFNs[0], &s_psVuMem.aVFNs[0]); - memLUT[i + 0x11004] = initMemoryMap(&s_psVuMem.aPFNs[1], &s_psVuMem.aVFNs[1]); - memLUT[i + 0x11008] = initMemoryMap(&s_psVuMem.aPFNs[4+i], &s_psVuMem.aVFNs[4+i]); - memLUT[i + 0x1100c] = initMemoryMap(&s_psVuMem.aPFNs[8+i], &s_psVuMem.aVFNs[8+i]); - - // Yay! Scratchpad mapping! We love the scratchpad. - memLUT[i + 0x50000] = initMemoryMap(&s_psS.aPFNs[i], &s_psS.aVFNs[i]); - } - - // map to other modes - memcpy(memLUT+0x80000, memLUT, 0x20000*sizeof(PSMEMORYMAP)); - memcpy(memLUT+0xa0000, memLUT, 0x20000*sizeof(PSMEMORYMAP)); -} - -// Some games read/write between different addrs but same physical memory -// this causes major slowdowns because it goes into the exception handler, so use this (zerofrog) -u32 VM_RETRANSLATE(u32 mem) -{ - u8* p, *pbase; - if( (mem&0xffff0000) == 0x50000000 ) // reserved scratch pad mem - return PS2MEM_BASE_+mem; - - p = (u8*)dmaGetAddrBase(mem); - -#ifdef _WIN32 - // do manual LUT since IPU/SPR seems to use addrs 0x3000xxxx quite often - if( memLUT[ (p-PS2MEM_BASE)>>12 ].aPFNs == NULL ) { - return PS2MEM_BASE_+mem; - } - - pbase = (u8*)memLUT[ (p-PS2MEM_BASE)>>12 ].aVFNs[0]; - if( pbase != NULL ) - p = pbase + ((u32)p&0xfff); -#endif - - return (u32)p; -} - -void memSetPageAddr(u32 vaddr, u32 paddr) { - - PSMEMORYMAP* pmap; - - if( vaddr == paddr ) - return; - - if( (vaddr>>28) != 1 && (vaddr>>28) != 9 && (vaddr>>28) != 11 ) { -#ifdef _WIN32 - pmap = &memLUT[vaddr >> 12]; - - if( pmap->aPFNs != NULL && (pmap->aPFNs != memLUT[paddr>>12].aPFNs || - pmap->aVFNs[0] != TRANSFORM_ADDR(vaddr)+(u32)PS2MEM_BASE) ) { - - SysMapUserPhysicalPages((void*)pmap->aVFNs[0], 1, NULL, 0); - pmap->aVFNs[0] = 0; - } - - *pmap = memLUT[paddr >> 12]; -#else - memLUT[vaddr>>12] = memLUT[paddr>>12]; -#endif - } -} - -void memClearPageAddr(u32 vaddr) { - // SysPrintf("memClearPageAddr: %8.8x\n", vaddr); - - if ((vaddr & 0xffffc000) == 0x70000000) return; - -#ifdef _WIN32 - // if( vaddr >= 0x20000000 && vaddr < 0x80000000 ) { - // Cpu->Clear(vaddr&~0xfff, 0x1000/4); - // if( memLUT[vaddr>>12].aVFNs != NULL ) { - // SysMapUserPhysicalPages((void*)memLUT[vaddr>>12].aVFNs[0], 1, NULL, 0 ); - // memLUT[vaddr>>12].aVFNs = NULL; - // memLUT[vaddr>>12].aPFNs = NULL; - // } - // } -#else - if( memLUT[vaddr>>12] != NULL ) { - SysVirtualFree(memLUT[vaddr>>12], 0x1000); - memLUT[vaddr>>12] = 0; - } -#endif -} - -u8 recMemRead8() -{ - register u32 mem; - __asm mov mem, ecx // already anded with ~0xa0000000 - - switch( (mem&~0xffff) ) { -case 0x1f400000: return psxHw4Read8(mem); -case 0x10000000: return hwRead8(mem); -case 0x1f800000: return psxHwRead8(mem); -case 0x12000000: return *(PS2MEM_BASE+(mem&~0xc00)); -case 0x14000000: - { - u32 ret = DEV9read8(mem & ~0x04000000); - SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, ret); - return ret; - } - -default: - return *(u8*)(PS2MEM_BASE+mem); - } - MEM_LOG("Unknown Memory read32 from address %8.8x\n", mem); - - cpuTlbMissR(mem, cpuRegs.branch); - - return 0; -} - -void _eeReadConstMem8(int mmreg, u32 mem, int sign) -{ - assert( !IS_XMMREG(mmreg)); - - if( IS_MMXREG(mmreg) ) { - SetMMXstate(); - MOVDMtoMMX(mmreg&0xf, mem-3); - assert(0); - } - else { - if( sign ) MOVSX32M8toR(mmreg, mem); - else MOVZX32M8toR(mmreg, mem); - } -} - -void _eeReadConstMem16(int mmreg, u32 mem, int sign) -{ - assert( !IS_XMMREG(mmreg)); - - if( IS_MMXREG(mmreg) ) { - SetMMXstate(); - MOVDMtoMMX(mmreg&0xf, mem-2); - assert(0); - } - else { - if( sign ) MOVSX32M16toR(mmreg, mem); - else MOVZX32M16toR(mmreg, mem); - } -} - -void _eeReadConstMem32(int mmreg, u32 mem) -{ - if( IS_XMMREG(mmreg) ) SSEX_MOVD_M32_to_XMM(mmreg&0xf, mem); - else if( IS_MMXREG(mmreg) ) { - SetMMXstate(); - MOVDMtoMMX(mmreg&0xf, mem); - } - else MOV32MtoR(mmreg, mem); -} - -void _eeReadConstMem128(int mmreg, u32 mem) -{ - if( IS_MMXREG(mmreg) ) { - SetMMXstate(); - MOVQMtoR((mmreg>>4)&0xf, mem+8); - MOVQMtoR(mmreg&0xf, mem); - } - else SSEX_MOVDQA_M128_to_XMM( mmreg&0xf, mem); -} - -void _eeWriteConstMem8(u32 mem, int mmreg) -{ - assert( !IS_XMMREG(mmreg) && !IS_MMXREG(mmreg) ); - if( IS_EECONSTREG(mmreg) ) MOV8ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); - else if( IS_PSXCONSTREG(mmreg) ) MOV8ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); - else MOV8RtoM(mem, mmreg); -} - -void _eeWriteConstMem16(u32 mem, int mmreg) -{ - assert( !IS_XMMREG(mmreg) && !IS_MMXREG(mmreg) ); - if( IS_EECONSTREG(mmreg) ) MOV16ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); - else if( IS_PSXCONSTREG(mmreg) ) MOV16ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); - else MOV16RtoM(mem, mmreg); -} - -// op - 0 for AND, 1 for OR -void _eeWriteConstMem16OP(u32 mem, int mmreg, int op) -{ - assert( !IS_XMMREG(mmreg) && !IS_MMXREG(mmreg) ); - switch(op) { -case 0: // AND operation - if( IS_EECONSTREG(mmreg) ) AND16ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); - else if( IS_PSXCONSTREG(mmreg) ) AND16ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); - else AND16RtoM(mem, mmreg); - break; -case 1: // OR operation - if( IS_EECONSTREG(mmreg) ) OR16ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); - else if( IS_PSXCONSTREG(mmreg) ) OR16ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); - else OR16RtoM(mem, mmreg); - break; - - jNO_DEFAULT - } -} - -void _eeWriteConstMem32(u32 mem, int mmreg) -{ - if( IS_XMMREG(mmreg) ) SSE2_MOVD_XMM_to_M32(mem, mmreg&0xf); - else if( IS_MMXREG(mmreg) ) { - SetMMXstate(); - MOVDMMXtoM(mem, mmreg&0xf); - } - else if( IS_EECONSTREG(mmreg) ) MOV32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); - else if( IS_PSXCONSTREG(mmreg) ) MOV32ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); - else MOV32RtoM(mem, mmreg); -} - -void _eeWriteConstMem32OP(u32 mem, int mmreg, int op) -{ - switch(op) { -case 0: // and - if( IS_XMMREG(mmreg) ) { - _deleteEEreg((mmreg>>16)&0x1f, 1); - SSE2_PAND_M128_to_XMM(mmreg&0xf, mem); - SSE2_MOVD_XMM_to_M32(mem, mmreg&0xf); - } - else if( IS_MMXREG(mmreg) ) { - _deleteEEreg((mmreg>>16)&0x1f, 1); - SetMMXstate(); - PANDMtoR(mmreg&0xf, mem); - MOVDMMXtoM(mem, mmreg&0xf); - } - else if( IS_EECONSTREG(mmreg) ) { - AND32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); - } - else if( IS_PSXCONSTREG(mmreg) ) { - AND32ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); - } - else { - AND32RtoM(mem, mmreg&0xf); - } - break; - -case 1: // or - if( IS_XMMREG(mmreg) ) { - _deleteEEreg((mmreg>>16)&0x1f, 1); - SSE2_POR_M128_to_XMM(mmreg&0xf, mem); - SSE2_MOVD_XMM_to_M32(mem, mmreg&0xf); - } - else if( IS_MMXREG(mmreg) ) { - _deleteEEreg((mmreg>>16)&0x1f, 1); - SetMMXstate(); - PORMtoR(mmreg&0xf, mem); - MOVDMMXtoM(mem, mmreg&0xf); - } - else if( IS_EECONSTREG(mmreg) ) { - OR32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); - } - else if( IS_PSXCONSTREG(mmreg) ) { - OR32ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); - } - else { - OR32RtoM(mem, mmreg&0xf); - } - break; - -case 2: // not and - if( mmreg & MEM_XMMTAG ) { - _deleteEEreg(mmreg>>16, 1); - SSEX_PANDN_M128_to_XMM(mmreg&0xf, mem); - SSEX_MOVD_XMM_to_M32(mem, mmreg&0xf); - } - else if( mmreg & MEM_MMXTAG ) { - _deleteEEreg(mmreg>>16, 1); - PANDNMtoR(mmreg&0xf, mem); - MOVDMMXtoM(mem, mmreg&0xf); - } - else if( IS_EECONSTREG(mmreg) ) { - AND32ItoM(mem, ~g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); - } - else if( IS_PSXCONSTREG(mmreg) ) { - AND32ItoM(mem, ~g_psxConstRegs[((mmreg>>16)&0x1f)]); - } - else { - NOT32R(mmreg&0xf); - AND32RtoM(mem, mmreg&0xf); - } - break; - -default: assert(0); - } -} - -void _eeWriteConstMem64(u32 mem, int mmreg) -{ - if( IS_XMMREG(mmreg) ) SSE_MOVLPS_XMM_to_M64(mem, mmreg&0xf); - else if( IS_MMXREG(mmreg) ) { - SetMMXstate(); - MOVQRtoM(mem, mmreg&0xf); - } - else if( IS_EECONSTREG(mmreg) ) { - MOV32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); - MOV32ItoM(mem+4, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[1]); - } - else assert(0); -} - -void _eeWriteConstMem128(u32 mem, int mmreg) -{ - if( IS_MMXREG(mmreg) ) { - SetMMXstate(); - MOVQRtoM(mem, mmreg&0xf); - MOVQRtoM(mem+8, (mmreg>>4)&0xf); - } - else if( IS_EECONSTREG(mmreg) ) { - SetMMXstate(); - MOV32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); - MOV32ItoM(mem+4, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[1]); - MOVQRtoM(mem+8, mmreg&0xf); - } - else SSEX_MOVDQA_XMM_to_M128(mem, mmreg&0xf); -} - -void _eeMoveMMREGtoR(x86IntRegType to, int mmreg) -{ - if( IS_XMMREG(mmreg) ) SSE2_MOVD_XMM_to_R(to, mmreg&0xf); - else if( IS_MMXREG(mmreg) ) { - SetMMXstate(); - MOVD32MMXtoR(to, mmreg&0xf); - } - else if( IS_EECONSTREG(mmreg) ) MOV32ItoR(to, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); - else if( IS_PSXCONSTREG(mmreg) ) MOV32ItoR(to, g_psxConstRegs[((mmreg>>16)&0x1f)]); - else if( mmreg != to ) MOV32RtoR(to, mmreg); -} - -int recMemConstRead8(u32 x86reg, u32 mem, u32 sign) -{ - mem = TRANSFORM_ADDR(mem); - - switch( mem>>16 ) { -case 0x1f40: return psxHw4ConstRead8(x86reg, mem, sign); -case 0x1000: return hwConstRead8(x86reg, mem, sign); -case 0x1f80: return psxHwConstRead8(x86reg, mem, sign); -case 0x1200: return gsConstRead8(x86reg, mem, sign); -case 0x1400: - { - iFlushCall(0); - PUSH32I(mem & ~0x04000000); - CALLFunc((u32)DEV9read8); - if( sign ) MOVSX32R8toR(EAX, EAX); - else MOVZX32R8toR(EAX, EAX); - return 1; - } - -default: - _eeReadConstMem8(x86reg, VM_RETRANSLATE(mem), sign); - return 0; - } -} - -u16 recMemRead16() { - - register u32 mem; - __asm mov mem, ecx // already anded with ~0xa0000000 - - switch( mem>>16 ) { - case 0x1000: return hwRead16(mem); - case 0x1f80: return psxHwRead16(mem); - case 0x1200: return *(u16*)(PS2MEM_BASE+(mem&~0xc00)); - case 0x1800: return 0; - case 0x1a00: return ba0R16(mem); - case 0x1f90: - case 0x1f00: - return SPU2read(mem); - case 0x1400: - { - u32 ret = DEV9read16(mem & ~0x04000000); - SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, ret); - return ret; - } - - default: - return *(u16*)(PS2MEM_BASE+mem); - } - MEM_LOG("Unknown Memory read16 from address %8.8x\n", mem); - cpuTlbMissR(mem, cpuRegs.branch); - return 0; -} - -int recMemConstRead16(u32 x86reg, u32 mem, u32 sign) -{ - mem = TRANSFORM_ADDR(mem); - - switch( mem>>16 ) { -case 0x1000: return hwConstRead16(x86reg, mem, sign); -case 0x1f80: return psxHwConstRead16(x86reg, mem, sign); -case 0x1200: return gsConstRead16(x86reg, mem, sign); -case 0x1800: - if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf); - else XOR32RtoR(x86reg, x86reg); - return 0; -case 0x1a00: - iFlushCall(0); - PUSH32I(mem); - CALLFunc((u32)ba0R16); - ADD32ItoR(ESP, 4); - if( sign ) MOVSX32R16toR(EAX, EAX); - else MOVZX32R16toR(EAX, EAX); - return 1; - -case 0x1f90: -case 0x1f00: - iFlushCall(0); - PUSH32I(mem); - CALLFunc((u32)SPU2read); - if( sign ) MOVSX32R16toR(EAX, EAX); - else MOVZX32R16toR(EAX, EAX); - return 1; - -case 0x1400: - iFlushCall(0); - PUSH32I(mem & ~0x04000000); - CALLFunc((u32)DEV9read16); - if( sign ) MOVSX32R16toR(EAX, EAX); - else MOVZX32R16toR(EAX, EAX); - return 1; - -default: - _eeReadConstMem16(x86reg, VM_RETRANSLATE(mem), sign); - return 0; - } -} - -__declspec(naked) -u32 recMemRead32() { - // ecx is address - already anded with ~0xa0000000 - __asm { - - mov edx, ecx - shr edx, 16 - cmp dx, 0x1000 - je hwread - cmp dx, 0x1f80 - je psxhwread - cmp dx, 0x1200 - je gsread - cmp dx, 0x1400 - je devread - - // default read - mov eax, dword ptr [ecx+PS2MEM_BASE_] - ret - } - -hwread: - { - __asm { - cmp ecx, 0x10002000 - jb counterread - - cmp ecx, 0x1000f260 - je hwsifpresetread - cmp ecx, 0x1000f240 - je hwsifsyncread - cmp ecx, 0x1000f440 - je hwmch_drd - cmp ecx, 0x1000f430 - je hwmch_ricm - - cmp ecx, 0x10003000 - jb hwdefread2 - mov eax, dword ptr [ecx+PS2MEM_BASE_] - ret - - // ipu -hwdefread2: - push ecx - call ipuRead32 - add esp, 4 - ret - - // sif -hwsifpresetread: - xor eax, eax - ret -hwsifsyncread: - mov eax, 0x1000F240 - mov eax, dword ptr [eax+PS2MEM_BASE_] - or eax, 0xF0000102 - ret - } - -counterread: - { - static u32 mem, index; - - // counters - __asm mov mem, ecx - index = (mem>>11)&3; - - if( (mem&0x7ff) == 0 ) { - __asm { - push index - call rcntRcount - add esp, 4 - and eax, 0xffff - ret - } - } - - index = (u32)&counters[index] + ((mem>>2)&0xc); - - __asm { - mov eax, index - mov eax, dword ptr [eax] - movzx eax, ax - ret - } - } - -hwmch_drd: // MCH_DRD - __asm { - mov eax, dword ptr [ecx+PS2MEM_BASE_-0x10] - shr eax, 6 - test eax, 0xf - jz mch_drd_2 -hwmch_ricm: - xor eax, eax - ret - -mch_drd_2: - shr eax, 10 - and eax, 0xfff - cmp eax, 0x21 // INIT - je mch_drd_init - cmp eax, 0x23 // CNFGA - je mch_drd_cnfga - cmp eax, 0x24 // CNFGB - je mch_drd_cnfgb - cmp eax, 0x40 // DEVID - je mch_drd_devid - xor eax, eax - ret - -mch_drd_init: - mov edx, rdram_devices - xor eax, eax - cmp edx, rdram_sdevid - setg al - add rdram_sdevid, eax - imul eax, 0x1f - ret - -mch_drd_cnfga: - mov eax, 0x0D0D - ret - -mch_drd_cnfgb: - mov eax, 0x0090 - ret - -mch_drd_devid: - mov eax, dword ptr [ecx+PS2MEM_BASE_-0x10] - and eax, 0x1f - ret - } - } - -psxhwread: - __asm { - push ecx - call psxHwRead32 - add esp, 4 - ret - } - -gsread: - __asm { - and ecx, 0xfffff3ff - mov eax, dword ptr [ecx+PS2MEM_BASE_] - ret - } - -devread: - __asm { - and ecx, 0xfbffffff - push ecx - call DEV9read32 - add esp, 4 - ret - } -} - -int recMemConstRead32(u32 x86reg, u32 mem) -{ - mem = TRANSFORM_ADDR(mem); - - switch( (mem&~0xffff) ) { -case 0x10000000: return hwConstRead32(x86reg, mem); -case 0x1f800000: return psxHwConstRead32(x86reg, mem); -case 0x12000000: return gsConstRead32(x86reg, mem); -case 0x14000000: - iFlushCall(0); - PUSH32I(mem & ~0x04000000); - CALLFunc((u32)DEV9read32); - return 1; - -default: - _eeReadConstMem32(x86reg, VM_RETRANSLATE(mem)); - return 0; - } -} - -void recMemRead64(u64 *out) -{ - register u32 mem; - __asm mov mem, ecx // already anded with ~0xa0000000 - - switch( (mem&0xffff0000) ) { -case 0x10000000: *out = hwRead64(mem); return; -case 0x11000000: *out = *(u64*)(PS2MEM_BASE+mem); return; -case 0x12000000: *out = *(u64*)(PS2MEM_BASE+(mem&~0xc00)); return; - -default: - //assert(0); - *out = *(u64*)(PS2MEM_BASE+mem); - return; - } - - MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val); - cpuTlbMissR(mem, cpuRegs.branch); -} - -void recMemConstRead64(u32 mem, int mmreg) -{ - mem = TRANSFORM_ADDR(mem); - - switch( (mem&0xffff0000) ) { -case 0x10000000: hwConstRead64(mem, mmreg); return; -case 0x12000000: gsConstRead64(mem, mmreg); return; -default: - if( IS_XMMREG(mmreg) ) SSE_MOVLPS_M64_to_XMM(mmreg&0xff, VM_RETRANSLATE(mem)); - else { - MOVQMtoR(mmreg, VM_RETRANSLATE(mem)); - SetMMXstate(); - } - return; - } -} - -void recMemRead128(u64 *out) { - - register u32 mem; - __asm mov mem, ecx // already anded with ~0xa0000000 - - switch( (mem&0xffff0000) ) { - case 0x10000000: - hwRead128(mem, out); - return; - case 0x12000000: - out[0] = *(u64*)(PS2MEM_BASE+(mem&~0xc00)); - out[1] = *(u64*)(PS2MEM_BASE+(mem&~0xc00)+8); - return; - case 0x11000000: - out[0] = *(u64*)(PS2MEM_BASE+mem); - out[1] = *(u64*)(PS2MEM_BASE+mem+8); - return; - default: - //assert(0); - out[0] = *(u64*)(PS2MEM_BASE+mem); - out[1] = *(u64*)(PS2MEM_BASE+mem+8); - return; - } - - MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val); - cpuTlbMissR(mem, cpuRegs.branch); -} - -void recMemConstRead128(u32 mem, int xmmreg) -{ - mem = TRANSFORM_ADDR(mem); - - switch( (mem&0xffff0000) ) { -case 0x10000000: hwConstRead128(mem, xmmreg); return; -case 0x12000000: gsConstRead128(mem, xmmreg); return; -default: - _eeReadConstMem128(xmmreg, VM_RETRANSLATE(mem)); - return; - } -} - -void errwrite() -{ - int i, bit, tempeax; - __asm mov i, ecx - __asm mov tempeax, eax - __asm mov bit, edx - SysPrintf("Error write%d at %x\n", bit, i); - assert(0); - __asm mov eax, tempeax - __asm mov ecx, i -} - -void recMemWrite8() -{ - register u32 mem; - register u8 value; - __asm mov mem, ecx // already anded with ~0xa0000000 - __asm mov value, al - - switch( mem>>16 ) { -case 0x1f40: psxHw4Write8(mem, value); return; -case 0x1000: hwWrite8(mem, value); return; -case 0x1f80: psxHwWrite8(mem, value); return; -case 0x1200: gsWrite8(mem, value); return; -case 0x1400: - DEV9write8(mem & ~0x04000000, value); - SysPrintf("DEV9 write8 %8.8lx: %2.2lx\n", mem & ~0x04000000, value); - return; - -#ifdef _DEBUG -case 0x1100: assert(0); -#endif -default: - // vus, bad addrs, etc - *(u8*)(PS2MEM_BASE+mem) = value; - return; - } - MEM_LOG("Unknown Memory write8 to address %x with data %2.2x\n", mem, value); - cpuTlbMissW(mem, cpuRegs.branch); -} - -int recMemConstWrite8(u32 mem, int mmreg) -{ - mem = TRANSFORM_ADDR(mem); - - switch( mem>>16 ) { -case 0x1f40: psxHw4ConstWrite8(mem, mmreg); return 0; -case 0x1000: hwConstWrite8(mem, mmreg); return 0; -case 0x1f80: psxHwConstWrite8(mem, mmreg); return 0; -case 0x1200: gsConstWrite8(mem, mmreg); return 0; -case 0x1400: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(mem & ~0x04000000); - CALLFunc((u32)DEV9write8); - return 0; - -case 0x1100: - _eeWriteConstMem8(PS2MEM_BASE_+mem, mmreg); - - if( mem < 0x11004000 ) { - PUSH32I(1); - PUSH32I(mem&0x3ff8); - CALLFunc((u32)CpuVU0->Clear); - ADD32ItoR(ESP, 8); - } - else if( mem >= 0x11008000 && mem < 0x1100c000 ) { - PUSH32I(1); - PUSH32I(mem&0x3ff8); - CALLFunc((u32)CpuVU1->Clear); - ADD32ItoR(ESP, 8); - } - return 0; - -default: - _eeWriteConstMem8(PS2MEM_BASE_+mem, mmreg); - return 1; - } -} - -void recMemWrite16() { - - register u32 mem; - register u16 value; - __asm mov mem, ecx // already anded with ~0xa0000000 - __asm mov value, ax - - switch( mem>>16 ) { - case 0x1000: hwWrite16(mem, value); return; - case 0x1600: - //HACK: DEV9 VM crash fix - return; - case 0x1f80: psxHwWrite16(mem, value); return; - case 0x1200: gsWrite16(mem, value); return; - case 0x1f90: - case 0x1f00: SPU2write(mem, value); return; - case 0x1400: - DEV9write16(mem & ~0x04000000, value); - SysPrintf("DEV9 write16 %8.8lx: %4.4lx\n", mem & ~0x04000000, value); - return; - -#ifdef _DEBUG - case 0x1100: assert(0); -#endif - default: - // vus, bad addrs, etc - *(u16*)(PS2MEM_BASE+mem) = value; - return; - } - MEM_LOG("Unknown Memory write16 to address %x with data %4.4x\n", mem, value); - cpuTlbMissW(mem, cpuRegs.branch); -} - -int recMemConstWrite16(u32 mem, int mmreg) -{ - mem = TRANSFORM_ADDR(mem); - - switch( mem>>16 ) { -case 0x1000: hwConstWrite16(mem, mmreg); return 0; -case 0x1600: - //HACK: DEV9 VM crash fix - return 0; -case 0x1f80: psxHwConstWrite16(mem, mmreg); return 0; -case 0x1200: gsConstWrite16(mem, mmreg); return 0; -case 0x1f90: -case 0x1f00: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(mem); - CALLFunc((u32)SPU2write); - return 0; -case 0x1400: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(mem & ~0x04000000); - CALLFunc((u32)DEV9write16); - return 0; - -case 0x1100: - _eeWriteConstMem16(PS2MEM_BASE_+mem, mmreg); - - if( mem < 0x11004000 ) { - PUSH32I(1); - PUSH32I(mem&0x3ff8); - CALLFunc((u32)CpuVU0->Clear); - ADD32ItoR(ESP, 8); - } - else if( mem >= 0x11008000 && mem < 0x1100c000 ) { - PUSH32I(1); - PUSH32I(mem&0x3ff8); - CALLFunc((u32)CpuVU1->Clear); - ADD32ItoR(ESP, 8); - } - return 0; - -default: - _eeWriteConstMem16(PS2MEM_BASE_+mem, mmreg); - return 1; - } -} - -C_ASSERT( sizeof(BASEBLOCK) == 8 ); - -__declspec(naked) -void recMemWrite32() -{ - // ecx is address - already anded with ~0xa0000000 - __asm { - - mov edx, ecx - shr edx, 16 - cmp dx, 0x1000 - je hwwrite - cmp dx, 0x1f80 - je psxwrite - cmp dx, 0x1200 - je gswrite - cmp dx, 0x1400 - je devwrite - cmp dx, 0x1100 - je vuwrite - } - - __asm { - // default write - mov dword ptr [ecx+PS2MEM_BASE_], eax - ret - -hwwrite: - push eax - push ecx - call hwWrite32 - add esp, 8 - ret -psxwrite: - push eax - push ecx - call psxHwWrite32 - add esp, 8 - ret -gswrite: - push eax - push ecx - call gsWrite32 - add esp, 8 - ret -devwrite: - and ecx, 0xfbffffff - push eax - push ecx - call DEV9write32 - add esp, 8 - ret -vuwrite: - // default write - mov dword ptr [ecx+PS2MEM_BASE_], eax - - cmp ecx, 0x11004000 - jge vu1write - and ecx, 0x3ff8 - // clear vu0mem - mov eax, CpuVU0 - push 1 - push ecx - call [eax]CpuVU0.Clear - add esp, 8 - ret - -vu1write: - cmp ecx, 0x11008000 - jl vuend - cmp ecx, 0x1100c000 - jge vuend - // clear vu1mem - and ecx, 0x3ff8 - mov eax, CpuVU1 - push 1 - push ecx - call [eax]CpuVU1.Clear - add esp, 8 -vuend: - ret - } -} - -int recMemConstWrite32(u32 mem, int mmreg) -{ - mem = TRANSFORM_ADDR(mem); - - switch( mem&0xffff0000 ) { -case 0x10000000: hwConstWrite32(mem, mmreg); return 0; -case 0x1f800000: psxHwConstWrite32(mem, mmreg); return 0; -case 0x12000000: gsConstWrite32(mem, mmreg); return 0; -case 0x1f900000: -case 0x1f000000: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(mem); - CALLFunc((u32)SPU2write); - return 0; -case 0x14000000: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(mem & ~0x04000000); - CALLFunc((u32)DEV9write32); - return 0; - -case 0x11000000: - _eeWriteConstMem32(PS2MEM_BASE_+mem, mmreg); - - if( mem < 0x11004000 ) { - PUSH32I(1); - PUSH32I(mem&0x3ff8); - CALLFunc((u32)CpuVU0->Clear); - ADD32ItoR(ESP, 8); - } - else if( mem >= 0x11008000 && mem < 0x1100c000 ) { - PUSH32I(1); - PUSH32I(mem&0x3ff8); - CALLFunc((u32)CpuVU1->Clear); - ADD32ItoR(ESP, 8); - } - return 0; - -default: - _eeWriteConstMem32(PS2MEM_BASE_+mem, mmreg); - return 1; - } -} - -__declspec(naked) void recMemWrite64() -{ - __asm { - mov edx, ecx - shr edx, 16 - cmp dx, 0x1000 - je hwwrite - cmp dx, 0x1200 - je gswrite - cmp dx, 0x1100 - je vuwrite - } - - __asm { - // default write - mov edx, 64 - call errwrite - -hwwrite: - push dword ptr [eax+4] - push dword ptr [eax] - push ecx - call hwWrite64 - add esp, 12 - ret - -gswrite: - push dword ptr [eax+4] - push dword ptr [eax] - push ecx - call gsWrite64 - add esp, 12 - ret - -vuwrite: - mov ebx, dword ptr [eax] - mov edx, dword ptr [eax+4] - mov dword ptr [ecx+PS2MEM_BASE_], ebx - mov dword ptr [ecx+PS2MEM_BASE_+4], edx - - cmp ecx, 0x11004000 - jge vu1write - and ecx, 0x3ff8 - // clear vu0mem - mov eax, CpuVU0 - push 2 - push ecx - call [eax]CpuVU0.Clear - add esp, 8 - ret - -vu1write: - cmp ecx, 0x11008000 - jl vuend - cmp ecx, 0x1100c000 - jge vuend - // clear vu1mem - and ecx, 0x3ff8 - mov eax, CpuVU0 - push 2 - push ecx - call [eax]CpuVU1.Clear - add esp, 8 -vuend: - ret - } -} - -int recMemConstWrite64(u32 mem, int mmreg) -{ - mem = TRANSFORM_ADDR(mem); - - switch( (mem>>16) ) { -case 0x1000: hwConstWrite64(mem, mmreg); return 0; -case 0x1200: gsConstWrite64(mem, mmreg); return 0; - -case 0x1100: - _eeWriteConstMem64(PS2MEM_BASE_+mem, mmreg); - - if( mem < 0x11004000 ) { - PUSH32I(2); - PUSH32I(mem&0x3ff8); - CALLFunc((u32)CpuVU0->Clear); - ADD32ItoR(ESP, 8); - } - else if( mem >= 0x11008000 && mem < 0x1100c000 ) { - PUSH32I(2); - PUSH32I(mem&0x3ff8); - CALLFunc((u32)CpuVU1->Clear); - ADD32ItoR(ESP, 8); - } - return 0; - -default: - _eeWriteConstMem64(PS2MEM_BASE_+mem, mmreg); - return 1; - } -} - -__declspec(naked) -void recMemWrite128() -{ - __asm { - - mov edx, ecx - shr edx, 16 - cmp dx, 0x1000 - je hwwrite - cmp dx, 0x1200 - je gswrite - cmp dx, 0x1100 - je vuwrite - } - - __asm { - mov edx, 128 - call errwrite - -hwwrite: - - push eax - push ecx - call hwWrite128 - add esp, 8 - ret - -vuwrite: - mov ebx, dword ptr [eax] - mov edx, dword ptr [eax+4] - mov edi, dword ptr [eax+8] - mov eax, dword ptr [eax+12] - mov dword ptr [ecx+PS2MEM_BASE_], ebx - mov dword ptr [ecx+PS2MEM_BASE_+4], edx - mov dword ptr [ecx+PS2MEM_BASE_+8], edi - mov dword ptr [ecx+PS2MEM_BASE_+12], eax - - cmp ecx, 0x11004000 - jge vu1write - and ecx, 0x3ff8 - // clear vu0mem - mov eax, CpuVU0 - push 4 - push ecx - call [eax]CpuVU0.Clear - add esp, 8 - ret - -vu1write: - cmp ecx, 0x11008000 - jl vuend - cmp ecx, 0x1100c000 - jge vuend - // clear vu1mem - and ecx, 0x3ff8 - mov eax, CpuVU1 - push 4 - push ecx - call [eax]CpuVU1.Clear - add esp, 8 -vuend: - - // default write - //movaps xmm7, qword ptr [eax] - - // removes possible exceptions and saves on remapping memory - // *might* be faster for certain games, no way to tell - // cmp ecx, 0x20000000 - // jb Write128 - // - // // look for better mapping - // mov edx, ecx - // shr edx, 12 - // shl edx, 3 - // add edx, memLUT - // mov edx, dword ptr [edx + 4] - // cmp edx, 0 - // je Write128 - // mov edx, dword ptr [edx] - // cmp edx, 0 - // je Write128 - // and ecx, 0xfff - // movaps qword ptr [ecx+edx], xmm7 - // jmp CheckOverwrite - //Write128: - //movaps qword ptr [ecx+PS2MEM_BASE_], xmm7 - ret - -gswrite: - sub esp, 8 - movlps xmm7, qword ptr [eax] - movlps qword ptr [esp], xmm7 - push ecx - call gsWrite64 - - // call again for upper 8 bytes - movlps xmm7, qword ptr [eax+8] - movlps qword ptr [esp+4], xmm7 - add [esp], 8 - call gsWrite64 - add esp, 12 - ret - } -} - -int recMemConstWrite128(u32 mem, int mmreg) -{ - mem = TRANSFORM_ADDR(mem); - - switch( (mem&0xffff0000) ) { -case 0x10000000: hwConstWrite128(mem, mmreg); return 0; -case 0x12000000: gsConstWrite128(mem, mmreg); return 0; - -case 0x11000000: - _eeWriteConstMem128(PS2MEM_BASE_+mem, mmreg); - - if( mem < 0x11004000 ) { - PUSH32I(4); - PUSH32I(mem&0x3ff8); - CALLFunc((u32)CpuVU0->Clear); - ADD32ItoR(ESP, 8); - } - else if( mem >= 0x11008000 && mem < 0x1100c000 ) { - PUSH32I(4); - PUSH32I(mem&0x3ff8); - CALLFunc((u32)CpuVU1->Clear); - ADD32ItoR(ESP, 8); - } - return 0; - -default: - _eeWriteConstMem128(PS2MEM_BASE_+mem, mmreg); - return 1; - } -} - -int __fastcall memRead8 (u32 mem, u8 *out) { - - mem = TRANSFORM_ADDR(mem); - switch( (mem&~0xffff) ) { - case 0x1f400000: *out = psxHw4Read8(mem); return 0; - case 0x10000000: *out = hwRead8(mem); return 0; - case 0x1f800000: *out = psxHwRead8(mem); return 0; - case 0x12000000: *out = gsRead8(mem); return 0; - case 0x14000000: - *out = DEV9read8(mem & ~0x04000000); - SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); - return 0; - - default: - *out = *(u8*)(PS2MEM_BASE+mem); - return 0; - } - -#ifdef MEM_LOG - MEM_LOG("Unknown Memory read32 from address %8.8x\n", mem); -#endif - cpuTlbMissR(mem, cpuRegs.branch); - - return -1; -} - -int __fastcall memRead8RS (u32 mem, u64 *out) -{ - mem = TRANSFORM_ADDR(mem); - switch( (mem&~0xffff) ) { -case 0x1f400000: *out = (s8)psxHw4Read8(mem); return 0; -case 0x10000000: *out = (s8)hwRead8(mem); return 0; -case 0x1f800000: *out = (s8)psxHwRead8(mem); return 0; -case 0x12000000: *out = (s8)gsRead8(mem); return 0; -case 0x14000000: - *out = (s8)DEV9read8(mem & ~0x04000000); - SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); - return 0; - -default: - *out = *(s8*)(PS2MEM_BASE+mem); - return 0; - } - MEM_LOG("Unknown Memory read32 from address %8.8x\n", mem); - cpuTlbMissR(mem, cpuRegs.branch); - - return -1; -} - -int __fastcall memRead8RU (u32 mem, u64 *out) -{ - mem = TRANSFORM_ADDR(mem); - switch( (mem&~0xffff) ) { -case 0x1f400000: *out = (u8)psxHw4Read8(mem); return 0; -case 0x10000000: *out = (u8)hwRead8(mem); return 0; -case 0x1f800000: *out = (u8)psxHwRead8(mem); return 0; -case 0x12000000: *out = (u8)gsRead8(mem); return 0; -case 0x14000000: - *out = (u8)DEV9read8(mem & ~0x04000000); - SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); - return 0; - -default: - *out = *(u8*)(PS2MEM_BASE+mem); - return 0; - } - MEM_LOG("Unknown Memory read32 from address %8.8x\n", mem); - cpuTlbMissR(mem, cpuRegs.branch); - - return -1; -} - -int __fastcall memRead16(u32 mem, u16 *out) { - - mem = TRANSFORM_ADDR(mem); - switch( (mem&~0xffff) ) { - case 0x10000000: *out = hwRead16(mem); return 0; - case 0x1f800000: *out = psxHwRead16(mem); return 0; - case 0x12000000: *out = gsRead16(mem); return 0; - case 0x18000000: *out = 0; return 0; - case 0x1a000000: *out = ba0R16(mem); return 0; - case 0x1f900000: - case 0x1f000000: - *out = SPU2read(mem); return 0; - break; - case 0x14000000: - *out = DEV9read16(mem & ~0x04000000); - SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); - return 0; - - default: - *out = *(u16*)(PS2MEM_BASE+mem); - return 0; - } - MEM_LOG("Unknown Memory read16 from address %8.8x\n", mem); - cpuTlbMissR(mem, cpuRegs.branch); - return -1; -} - -int __fastcall memRead16RS(u32 mem, u64 *out) { - - mem = TRANSFORM_ADDR(mem); - switch( (mem&~0xffff) ) { - case 0x10000000: *out = (s16)hwRead16(mem); return 0; - case 0x1f800000: *out = (s16)psxHwRead16(mem); return 0; - case 0x12000000: *out = (s16)gsRead16(mem); return 0; - case 0x18000000: *out = 0; return 0; - case 0x1a000000: *out = (s16)ba0R16(mem); return 0; - case 0x1f900000: - case 0x1f000000: - *out = (s16)SPU2read(mem); return 0; - break; - case 0x14000000: - *out = (s16)DEV9read16(mem & ~0x04000000); - SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); - return 0; - - default: - *out = *(s16*)(PS2MEM_BASE+mem); - return 0; - } - MEM_LOG("Unknown Memory read16 from address %8.8x\n", mem); - cpuTlbMissR(mem, cpuRegs.branch); - return -1; -} - -int __fastcall memRead16RU(u32 mem, u64 *out) { - - mem = TRANSFORM_ADDR(mem); - switch( (mem&~0xffff) ) { - case 0x10000000: *out = (u16)hwRead16(mem ); return 0; - case 0x1f800000: *out = (u16)psxHwRead16(mem ); return 0; - case 0x12000000: *out = (u16)gsRead16(mem); return 0; - case 0x18000000: *out = 0; return 0; - case 0x1a000000: *out = (u16)ba0R16(mem); return 0; - case 0x1f900000: - case 0x1f000000: - *out = (u16)SPU2read(mem ); return 0; - break; - case 0x14000000: - *out = (u16)DEV9read16(mem & ~0x04000000); - SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); - return 0; - - default: - *out = *(u16*)(PS2MEM_BASE+mem); - return 0; - } - MEM_LOG("Unknown Memory read16 from address %8.8x\n", mem); - cpuTlbMissR(mem, cpuRegs.branch); - return -1; -} - -int __fastcall memRead32(u32 mem, u32 *out) { - - mem = TRANSFORM_ADDR(mem); - switch( (mem&~0xffff) ) { - case 0x10000000: *out = hwRead32(mem); return 0; - case 0x1f800000: *out = psxHwRead32(mem); return 0; - case 0x12000000: *out = gsRead32(mem); return 0; - case 0x14000000: - *out = (u32)DEV9read32(mem & ~0x04000000); - SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); - return 0; - - default: - *out = *(u32*)(PS2MEM_BASE+mem); - return 0; - } - - MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val); - cpuTlbMissR(mem, cpuRegs.branch); - - return -1; -} - -int __fastcall memRead32RS(u32 mem, u64 *out) -{ - mem = TRANSFORM_ADDR(mem); - switch( (mem&~0xffff) ) { -case 0x10000000: *out = (s32)hwRead32(mem); return 0; -case 0x1f800000: *out = (s32)psxHwRead32(mem); return 0; -case 0x12000000: *out = (s32)gsRead32(mem); return 0; -case 0x14000000: - *out = (s32)DEV9read32(mem & ~0x04000000); - SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); - return 0; - -default: - *out = *(s32*)(PS2MEM_BASE+mem); - return 0; - } - - MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val); - cpuTlbMissR(mem, cpuRegs.branch); - - return -1; -} - -int __fastcall memRead32RU(u32 mem, u64 *out) -{ - mem = TRANSFORM_ADDR(mem); - switch( (mem&~0xffff) ) { -case 0x10000000: *out = (u32)hwRead32(mem); return 0; -case 0x1f800000: *out = (u32)psxHwRead32(mem); return 0; -case 0x12000000: *out = (u32)gsRead32(mem); return 0; -case 0x14000000: - *out = (u32)DEV9read32(mem & ~0x04000000); - SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); - return 0; - -default: - *out = *(u32*)(PS2MEM_BASE+mem); - return 0; - } - - MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val); - cpuTlbMissR(mem, cpuRegs.branch); - - return -1; -} - -int __fastcall memRead64(u32 mem, u64 *out) { - mem = TRANSFORM_ADDR(mem); - switch( (mem&~0xffff) ) { - case 0x10000000: *out = hwRead64(mem); return 0; - case 0x12000000: *out = gsRead64(mem); return 0; - - default: - *out = *(u64*)(PS2MEM_BASE+mem); - return 0; - } - - MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val); - cpuTlbMissR(mem, cpuRegs.branch); - - return -1; -} - -int __fastcall memRead128(u32 mem, u64 *out) { - - mem = TRANSFORM_ADDR(mem); - switch( (mem&~0xffff) ) { - case 0x10000000: - hwRead128(mem, out); - return 0; - case 0x12000000: - out[0] = gsRead64(mem); - out[1] = gsRead64(mem + 8); - return 0; - - default: - out[0] = *(u64*)(PS2MEM_BASE+mem); - out[1] = *(u64*)(PS2MEM_BASE+mem+8); - return 0; - } - - MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val); - cpuTlbMissR(mem, cpuRegs.branch); - - return -1; -} - -void __fastcall memWrite8 (u32 mem, u8 value) { - - mem = TRANSFORM_ADDR(mem); - switch( (mem&~0xffff) ) { - case 0x1f400000: psxHw4Write8(mem, value); return; - case 0x10000000: hwWrite8(mem, value); return; - case 0x1f800000: psxHwWrite8(mem, value); return; - case 0x12000000: gsWrite8(mem, value); return; - case 0x14000000: - DEV9write8(mem & ~0x04000000, value); - SysPrintf("DEV9 write8 %8.8lx: %2.2lx\n", mem & ~0x04000000, value); - return; - - default: - *(u8*)(PS2MEM_BASE+mem) = value; - - if (CHECK_EEREC) { - REC_CLEARM(mem&~3); - } - return; - } - MEM_LOG("Unknown Memory write8 to address %x with data %2.2x\n", mem, value); - cpuTlbMissW(mem, cpuRegs.branch); -} - -void __fastcall memWrite16(u32 mem, u16 value) { - - mem = TRANSFORM_ADDR(mem); - switch( (mem&~0xffff) ) { - case 0x10000000: hwWrite16(mem, value); return; - case 0x1f800000: psxHwWrite16(mem, value); return; - case 0x12000000: gsWrite16(mem, value); return; - case 0x1f900000: - case 0x1f000000: SPU2write(mem, value); return; - case 0x14000000: - DEV9write16(mem & ~0x04000000, value); - SysPrintf("DEV9 write16 %8.8lx: %4.4lx\n", mem & ~0x04000000, value); - return; - - default: - *(u16*)(PS2MEM_BASE+mem) = value; - if (CHECK_EEREC) { - REC_CLEARM(mem&~3); - } - return; - } - MEM_LOG("Unknown Memory write16 to address %x with data %4.4x\n", mem, value); - cpuTlbMissW(mem, cpuRegs.branch); -} - -void __fastcall memWrite32(u32 mem, u32 value) -{ - mem = TRANSFORM_ADDR(mem); - switch( (mem&~0xffff) ) { -case 0x10000000: hwWrite32(mem, value); return; -case 0x1f800000: psxHwWrite32(mem, value); return; -case 0x12000000: gsWrite32(mem, value); return; -case 0x1f900000: -case 0x1f000000: SPU2write(mem, value); return; -case 0x14000000: - DEV9write32(mem & ~0x4000000, value); - SysPrintf("DEV9 write32 %8.8lx: %8.8lx\n", mem & ~0x4000000, value); - return; - -default: - *(u32*)(PS2MEM_BASE+mem) = value; - - if (CHECK_EEREC) { - REC_CLEARM(mem); - } - return; - } - MEM_LOG("Unknown Memory write32 to address %x with data %8.8x\n", mem, value); - cpuTlbMissW(mem, cpuRegs.branch); -} - -void __fastcall memWrite64(u32 mem, const u64* value) { - - mem = TRANSFORM_ADDR(mem); - switch( (mem&~0xffff) ) { - case 0x10000000: hwWrite64(mem, *value); return; - case 0x12000000: gsWrite64(mem, *value); return; - - default: - *(u64*)(PS2MEM_BASE+mem) = *value; - - if (CHECK_EEREC) { - REC_CLEARM(mem); - REC_CLEARM(mem+4); - } - return; - } - MEM_LOG("Unknown Memory write64 to address %x with data %8.8x_%8.8x\n", mem, (u32)((*value)>>32), (u32)value); - cpuTlbMissW(mem, cpuRegs.branch); -} - -void __fastcall memWrite128(u32 mem, const u64 *value) { - - mem = TRANSFORM_ADDR(mem); - switch( (mem&~0xffff) ) { - case 0x10000000: hwWrite128(mem, value); return; - case 0x12000000: - gsWrite64(mem, value[0]); - gsWrite64(mem + 8, value[1]); - return; - - default: - *(u64*)(PS2MEM_BASE+mem) = value[0]; - *(u64*)(PS2MEM_BASE+mem+8) = value[1]; - - if (CHECK_EEREC) { - REC_CLEARM(mem); - REC_CLEARM(mem+4); - REC_CLEARM(mem+8); - REC_CLEARM(mem+12); - } - return; - } - MEM_LOG("Unknown Memory write128 to address %x with data %8.8x_%8.8x_%8.8x_%8.8x\n", mem, ((u32*)value)[3], ((u32*)value)[2], ((u32*)value)[1], ((u32*)value)[0]); - cpuTlbMissW(mem, cpuRegs.branch); -} - -// Resets memory mappings, unmaps TLBs, reloads bios roms, etc. -void memReset() -{ -#ifdef _WIN32 - DWORD OldProtect; - // make sure can write - VirtualProtect(PS2MEM_ROM, Ps2MemSize::Rom, PAGE_READWRITE, &OldProtect); - VirtualProtect(PS2MEM_ROM1, Ps2MemSize::Rom1, PAGE_READWRITE, &OldProtect); - VirtualProtect(PS2MEM_ROM2, Ps2MemSize::Rom2, PAGE_READWRITE, &OldProtect); - VirtualProtect(PS2MEM_EROM, Ps2MemSize::ERom, PAGE_READWRITE, &OldProtect); -#else - mprotect(PS2EMEM_ROM, Ps2MemSize::Rom, PROT_READ|PROT_WRITE); - mprotect(PS2EMEM_ROM1, Ps2MemSize::Rom1, PROT_READ|PROT_WRITE); - mprotect(PS2EMEM_ROM2, Ps2MemSize::Rom2, PROT_READ|PROT_WRITE); - mprotect(PS2EMEM_EROM, Ps2MemSize::ERom, PROT_READ|PROT_WRITE); -#endif - - memzero_ptr(PS2MEM_BASE); - memzero_ptr(PS2MEM_SCRATCH); - vm_Reset(); - - string Bios; - FILE *fp; - - Path::Combine( Bios, Config.BiosDir, Config.Bios ); - - long filesize; - if( ( filesize = Path::getFileSize( Bios ) ) <= 0 ) - { - //Console::Error("Unable to load bios: '%s', PCSX2 can't run without that", params Bios); - throw Exception::FileNotFound( Bios, - "The specified Bios file was not found. A bios is required for Pcsx2 to run.\n\nFile not found" ); - } - - fp = fopen(Bios.c_str(), "rb"); - fread(PS2MEM_ROM, 1, std::min( (long)Ps2MemSize::Rom, filesize ), fp); - fclose(fp); - - BiosVersion = GetBiosVersion(); - Console::Status("Bios Version %d.%d", params BiosVersion >> 8, BiosVersion & 0xff); - - //injectIRX("host.irx"); //not fully tested; still buggy - - loadBiosRom("rom1", PS2MEM_ROM1, Ps2MemSize::Rom1); - loadBiosRom("rom2", PS2MEM_ROM2, Ps2MemSize::Rom2); - loadBiosRom("erom", PS2MEM_EROM, Ps2MemSize::ERom); - -#ifdef _WIN32 - VirtualProtect(PS2MEM_ROM, Ps2MemSize::Rom, PAGE_READONLY, &OldProtect); - VirtualProtect(PS2MEM_ROM1, Ps2MemSize::Rom1, PAGE_READONLY, &OldProtect); - VirtualProtect(PS2MEM_ROM2, Ps2MemSize::Rom2, PAGE_READONLY, &OldProtect); - VirtualProtect(PS2MEM_EROM, Ps2MemSize::ERom, PAGE_READONLY, &OldProtect); -#else - mprotect(PS2EMEM_ROM, Ps2MemSize::Rom, PROT_READ); - mprotect(PS2EMEM_ROM1, Ps2MemSize::Rom1, PROT_READ); - mprotect(PS2EMEM_ROM2, Ps2MemSize::Rom2, PROT_READ); - mprotect(PS2EMEM_EROM, Ps2MemSize::ERom, PROT_READ); -#endif -} - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +// Virtual memory model for Pcsx2. +// This module is left in primarily as a reference for the implementation of constant +// propagation. + +#include "PrecompiledHeader.h" +#include "Common.h" +#include "iR5900.h" + +#include "PsxCommon.h" +#include "VUmicro.h" +#include "GS.h" +#include "vtlb.h" +#include "IPU/IPU.h" + +#ifdef PCSX2_VIRTUAL_MEM +#include "iR3000A.h" // VM handles both Iop and EE memory from here. >_< +#include "Counters.h" +#endif + +#pragma warning(disable:4799) // No EMMS at end of function + +#ifdef ENABLECACHE +#include "Cache.h" +#endif + +#ifdef __LINUX__ +#include +#endif + +///////////////////////////// +// VIRTUAL MEM START +///////////////////////////// +#ifdef PCSX2_VIRTUAL_MEM + +class vm_alloc_failed_exception : public std::runtime_error +{ +public: + void* requested_addr; + int requested_size; + void* returned_addr; + + explicit vm_alloc_failed_exception( void* reqadr, uint reqsize, void* retadr ) : + std::runtime_error( "virtual memory allocation failure." ) + , requested_addr( reqadr ) + , requested_size( reqsize ) + , returned_addr( retadr ) + {} +}; + +PSMEMORYBLOCK s_psM = {0}, s_psHw = {0}, s_psS = {0}, s_psxM = {0}, s_psVuMem = {0}; + +static void PHYSICAL_ALLOC( void* ptr, uint size, PSMEMORYBLOCK& block) +{ + if(SysPhysicalAlloc(size, &block) == -1 ) + throw vm_alloc_failed_exception( ptr, size, NULL ); + if(SysVirtualPhyAlloc(ptr, size, &block) == -1) + throw vm_alloc_failed_exception( ptr, size, NULL ); +} + +static void PHYSICAL_FREE( void* ptr, uint size, PSMEMORYBLOCK& block) +{ + SysVirtualFree(ptr, size); + SysPhysicalFree(&block); +} + + +#ifdef _WIN32 // windows implementation of vm + +static PSMEMORYMAP initMemoryMap(uptr* aPFNs, uptr* aVFNs) +{ + PSMEMORYMAP m; + m.aPFNs = aPFNs; + m.aVFNs = aVFNs; + return m; +} + +// only do vm hack for release +#ifndef PCSX2_DEVBUILD +#define VM_HACK +#endif + +// virtual memory blocks +PSMEMORYMAP *memLUT = NULL; + +static void VIRTUAL_ALLOC( void* base, uint size, uint Protection) +{ + LPVOID lpMemReserved = VirtualAlloc( base, size, MEM_RESERVE|MEM_COMMIT, Protection ); + if( base != lpMemReserved ) + throw vm_alloc_failed_exception( base, size, lpMemReserved ); +} + +static void ReserveExtraMem( void* base, uint size ) +{ + void* pExtraMem = VirtualAlloc(base, size, MEM_RESERVE|MEM_PHYSICAL, PAGE_READWRITE); + if( pExtraMem != base ) + throw vm_alloc_failed_exception( base, size, pExtraMem); +} + +void memAlloc() +{ + LPVOID pExtraMem = NULL; + + // release the previous reserved mem + VirtualFree(PS2MEM_BASE, 0, MEM_RELEASE); + + try + { + // allocate all virtual memory + PHYSICAL_ALLOC(PS2MEM_BASE, Ps2MemSize::Base, s_psM); + VIRTUAL_ALLOC(PS2MEM_ROM, Ps2MemSize::Rom, PAGE_READONLY); + VIRTUAL_ALLOC(PS2MEM_ROM1, Ps2MemSize::Rom1, PAGE_READONLY); + VIRTUAL_ALLOC(PS2MEM_ROM2, Ps2MemSize::Rom2, PAGE_READONLY); + VIRTUAL_ALLOC(PS2MEM_EROM, Ps2MemSize::ERom, PAGE_READONLY); + PHYSICAL_ALLOC(PS2MEM_SCRATCH, Ps2MemSize::Scratch, s_psS); + PHYSICAL_ALLOC(PS2MEM_HW, Ps2MemSize::Hardware, s_psHw); + PHYSICAL_ALLOC(PS2MEM_PSX, Ps2MemSize::IopRam, s_psxM); + PHYSICAL_ALLOC(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem); + + VIRTUAL_ALLOC(PS2MEM_PSXHW, Ps2MemSize::IopHardware, PAGE_READWRITE); + //VIRTUAL_ALLOC(PS2MEM_PSXHW2, 0x00010000, PAGE_READWRITE); + VIRTUAL_ALLOC(PS2MEM_PSXHW4, 0x00010000, PAGE_NOACCESS); + VIRTUAL_ALLOC(PS2MEM_GS, 0x00002000, PAGE_READWRITE); + VIRTUAL_ALLOC(PS2MEM_DEV9, 0x00010000, PAGE_NOACCESS); + VIRTUAL_ALLOC(PS2MEM_SPU2, 0x00010000, PAGE_NOACCESS); + VIRTUAL_ALLOC(PS2MEM_SPU2_, 0x00010000, PAGE_NOACCESS); + + VIRTUAL_ALLOC(PS2MEM_B80, 0x00010000, PAGE_READWRITE); + VIRTUAL_ALLOC(PS2MEM_BA0, 0x00010000, PAGE_READWRITE); + + // reserve the left over 224Mb, don't map + ReserveExtraMem( PS2MEM_BASE+Ps2MemSize::Base, 0x0e000000 ); + + // reserve left over psx mem + ReserveExtraMem( PS2MEM_PSX+Ps2MemSize::IopRam, 0x00600000 ); + + // reserve gs mem + ReserveExtraMem( PS2MEM_BASE+0x20000000, 0x10000000 ); + + // special addrs mmap + VIRTUAL_ALLOC(PS2MEM_BASE+0x5fff0000, 0x10000, PAGE_READWRITE); + + // alloc virtual mappings + if( memLUT == NULL ) + memLUT = (PSMEMORYMAP*)_aligned_malloc(0x100000 * sizeof(PSMEMORYMAP), 16); + if( memLUT == NULL ) + throw Exception::OutOfMemory( "memAlloc VM > failed to allocated memory for LUT." ); + } + catch( vm_alloc_failed_exception& ex ) + { + Console::Error( "Virtual Memory Error > Cannot reserve %dk memory block at 0x%8.8x", params + ex.requested_size / 1024, ex.requested_addr ); + + Console::Error( "\tError code: %d \tReturned address: 0x%8.8x", params + GetLastError(), ex.returned_addr); + + memShutdown(); + } + catch( std::exception& ) + { + memShutdown(); + } +} + +void memShutdown() +{ + // Free up the "extra mem" reservations + VirtualFree(PS2MEM_BASE+Ps2MemSize::Base, 0, MEM_RELEASE); + VirtualFree(PS2MEM_PSX+Ps2MemSize::IopRam, 0, MEM_RELEASE); + VirtualFree(PS2MEM_BASE+0x20000000, 0, MEM_RELEASE); // GS reservation + + PHYSICAL_FREE(PS2MEM_BASE, Ps2MemSize::Base, s_psM); + SysMunmap(PS2MEM_ROM, Ps2MemSize::Rom); + SysMunmap(PS2MEM_ROM1, Ps2MemSize::Rom1); + SysMunmap(PS2MEM_ROM2, Ps2MemSize::Rom2); + SysMunmap(PS2MEM_EROM, Ps2MemSize::ERom); + PHYSICAL_FREE(PS2MEM_SCRATCH, Ps2MemSize::Scratch, s_psS); + PHYSICAL_FREE(PS2MEM_HW, Ps2MemSize::Hardware, s_psHw); + PHYSICAL_FREE(PS2MEM_PSX, Ps2MemSize::IopRam, s_psxM); + PHYSICAL_FREE(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem); + + SysMunmap(PS2MEM_VU0MICRO, 0x00010000); // allocate for all VUs + + SysMunmap(PS2MEM_PSXHW, Ps2MemSize::IopHardware); + //SysMunmap(PS2MEM_PSXHW2, 0x00010000); + SysMunmap(PS2MEM_PSXHW4, 0x00010000); + SysMunmap(PS2MEM_GS, 0x00002000); + SysMunmap(PS2MEM_DEV9, 0x00010000); + SysMunmap(PS2MEM_SPU2, 0x00010000); + SysMunmap(PS2MEM_SPU2_, 0x00010000); + + SysMunmap(PS2MEM_B80, 0x00010000); + SysMunmap(PS2MEM_BA0, 0x00010000); + + // Special Addrs.. ? + SysMunmap(PS2MEM_BASE+0x5fff0000, 0x10000); + + VirtualFree(PS2MEM_VU0MICRO, 0, MEM_RELEASE); + + safe_aligned_free( memLUT ); + + // reserve mem + VirtualAlloc(PS2MEM_BASE, 0x40000000, MEM_RESERVE, PAGE_NOACCESS); +} + +//NOTE: A lot of the code reading depends on the registers being less than 8 +// MOV8 88/8A +// MOV16 6689 +// MOV32 89/8B +// SSEMtoR64 120f +// SSERtoM64 130f +// SSEMtoR128 280f +// SSERtoM128 290f + +#define SKIP_WRITE() { \ + switch(code&0xff) { \ + case 0x88: \ + if( !(code&0x8000) ) goto DefaultHandler; \ + ContextRecord->Eip += 6; \ + break; \ + case 0x66: \ + assert( code&0x800000 ); \ + assert( (code&0xffff) == 0x8966 ); \ + ContextRecord->Eip += 7; \ + break; \ + case 0x89: \ + assert( code&0x8000 ); \ + ContextRecord->Eip += 6; \ + break; \ + case 0x0f: /* 130f, 230f*/ \ + assert( (code&0xffff) == 0x290f || (code&0xffff) == 0x130f ); \ + assert( code&0x800000 ); \ + ContextRecord->Eip += 7; \ + break; \ + default: \ + goto DefaultHandler; \ +} \ +} \ + +#define SKIP_READ() { \ + switch(code&0xff) { \ + case 0x8A: \ + if( !(code&0x8000) ) goto DefaultHandler; \ + ContextRecord->Eip += 6; \ + rd = (code>>(8+3))&7; \ + break; \ + case 0x66: \ + if( (code&0x07000000) == 0x05000000 ) ContextRecord->Eip += 8; /* 8 for mem reads*/ \ + else ContextRecord->Eip += 4 + ((code&0x1f000000) == 0x0c000000) + !!(code&0x40000000); \ + rd = (code>>(24+3))&7; \ + break; \ + case 0x8B: \ + if( !(code&0x8000) ) goto DefaultHandler; \ + ContextRecord->Eip += 6; \ + rd = (code>>(8+3))&7; \ + break; \ + case 0x0f: { \ + assert( (code&0xffff)==0x120f || (code&0xffff)==0x280f || (code&0xffff) == 0xb60f || (code&0xffff) == 0xb70f ); \ + if( !(code&0x800000) ) goto DefaultHandler; \ + ContextRecord->Eip += 7; \ + rd = (code>>(16+3))&7; \ + break; } \ + default: \ + goto DefaultHandler; \ +} \ +} \ + +int SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps) +{ + struct _EXCEPTION_RECORD* ExceptionRecord = eps->ExceptionRecord; + struct _CONTEXT* ContextRecord = eps->ContextRecord; + + u32 addr; + + C_ASSERT(sizeof(ContextRecord->Eax) == 4); + + // If the exception is not a page fault, exit. + if (ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION) + { + return EXCEPTION_CONTINUE_SEARCH; + } + + // get bad virtual address + addr = (u32)ExceptionRecord->ExceptionInformation[1]; + + if( (unsigned)(addr-(u32)PS2MEM_BASE) < 0x60000000) { + PSMEMORYMAP* pmap; + + pmap = &memLUT[(addr-(u32)PS2MEM_BASE)>>12]; + + if( !pmap->aPFNs ) { + // NOTE: this is a hack because the address is truncated and there's no way + // to tell what it's upper bits are (due to OS limitations). + pmap += 0x80000; + if( !pmap->aPFNs ) { + pmap += 0x20000; + if( !pmap->aPFNs ) goto OtherException; + } + //else addr += 0x20000000; + } + + { + //LPVOID pnewaddr; not used + uptr curvaddr = pmap->aVFNs[0]; + + if( curvaddr ) { + // delete the current mapping + SysMapUserPhysicalPages((void*)curvaddr, 1, NULL, 0); + } + + assert( pmap->aPFNs[0] != 0 ); + + pmap->aVFNs[0] = curvaddr = addr&~0xfff; + if( SysMapUserPhysicalPages((void*)curvaddr, 1, pmap->aPFNs, 0) ) + return EXCEPTION_CONTINUE_EXECUTION; + + // try allocing the virtual mem + //pnewaddr = <- not used + /* use here the size of allocation granularity and force rounding down, + because in reserve mode the address is rounded up/down to the nearest + multiple of this granularity; if you did it not this way, in some cases + the same address would be used twice, so the api fails */ + VirtualAlloc((void*)(curvaddr&~0xffff), 0x10000, MEM_RESERVE|MEM_PHYSICAL, PAGE_READWRITE); + + if( SysMapUserPhysicalPages((void*)curvaddr, 1, pmap->aPFNs, 0) ) + return EXCEPTION_CONTINUE_EXECUTION; + + Console::Error("Virtual Memory Error > page 0x%x cannot be found %d (p:%x,v:%x)", params + addr-(u32)PS2MEM_BASE, GetLastError(), pmap->aPFNs[0], curvaddr); + } + } + // check if vumem + else if( (addr&0xffff4000) == 0x11000000 ) { + // vu0mem + SysMapUserPhysicalPages((void*)s_psVuMem.aVFNs[1], 1, NULL, 0); + + s_psVuMem.aVFNs[1] = addr&~0xfff; + SysMapUserPhysicalPages((void*)addr, 1, s_psVuMem.aPFNs, 1); + + //SysPrintf("Exception: vumem\n"); + return EXCEPTION_CONTINUE_EXECUTION; + } +OtherException: + +#ifdef VM_HACK + { + u32 code = *(u32*)ExceptionRecord->ExceptionAddress; + u32 rd = 0; + + if( ExceptionRecord->ExceptionInformation[0] ) { + //SKIP_WRITE(); + // shouldn't be writing + } + else { + SysPrintf("vmhack "); + SKIP_READ(); + //((u32*)&ContextRecord->Eax)[rd] = 0; + return EXCEPTION_CONTINUE_EXECUTION; // TODO: verify this!!! + } + } +DefaultHandler: +#endif + + return EXCEPTION_CONTINUE_SEARCH; +} + +#else // linux implementation + +#define VIRTUAL_ALLOC(base, size, Protection) { \ + void* lpMemReserved = mmap( base, size, Protection, MAP_PRIVATE|MAP_ANONYMOUS ); \ + if( lpMemReserved == NULL || base != lpMemReserved ) \ +{ \ + SysPrintf("Cannot reserve memory at 0x%8.8x(%x).\n", base, lpMemReserved); \ + perror("err"); \ + goto eCleanupAndExit; \ +} \ +} \ + +#define VIRTUAL_FREE(ptr, size) munmap(ptr, size) + +uptr *memLUT = NULL; + +void memAlloc() +{ + int i; + LPVOID pExtraMem = NULL; + + // release the previous reserved mem + munmap(PS2MEM_BASE, 0x40000000); + + // allocate all virtual memory + PHYSICAL_ALLOC(PS2MEM_BASE, Ps2MemSize::Base, s_psM); + VIRTUAL_ALLOC(PS2MEM_ROM, Ps2MemSize::Rom, PROT_READ); + VIRTUAL_ALLOC(PS2MEM_ROM1, Ps2MemSize::Rom1, PROT_READ); + VIRTUAL_ALLOC(PS2MEM_ROM2, Ps2MemSize::Rom2, PROT_READ); + VIRTUAL_ALLOC(PS2MEM_EROM, Ps2MemSize::ERom, PROT_READ); + PHYSICAL_ALLOC(PS2MEM_SCRATCH, 0x00010000, s_psS); + PHYSICAL_ALLOC(PS2MEM_HW, Ps2MemSize::Hardware, s_psHw); + PHYSICAL_ALLOC(PS2MEM_PSX, Ps2MemSize::IopRam, s_psxM); + PHYSICAL_ALLOC(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem); + + VIRTUAL_ALLOC(PS2MEM_PSXHW, Ps2MemSize::IopHardware, PROT_READ|PROT_WRITE); + VIRTUAL_ALLOC(PS2MEM_PSXHW4, 0x00010000, PROT_NONE); + VIRTUAL_ALLOC(PS2MEM_GS, 0x00002000, PROT_READ|PROT_WRITE); + VIRTUAL_ALLOC(PS2MEM_DEV9, 0x00010000, PROT_NONE); + VIRTUAL_ALLOC(PS2MEM_SPU2, 0x00010000, PROT_NONE); + VIRTUAL_ALLOC(PS2MEM_SPU2_, 0x00010000, PROT_NONE); + + VIRTUAL_ALLOC(PS2MEM_B80, 0x00010000, PROT_READ|PROT_WRITE); + VIRTUAL_ALLOC(PS2MEM_BA0, 0x00010000, PROT_READ|PROT_WRITE); + + // special addrs mmap + VIRTUAL_ALLOC(PS2MEM_BASE+0x5fff0000, 0x10000, PROT_READ|PROT_WRITE); + +eCleanupAndExit: + memShutdown(); + return -1; +} + +void memShutdown() +{ + VIRTUAL_FREE(PS2MEM_BASE, 0x40000000); + VIRTUAL_FREE(PS2MEM_PSX, 0x00800000); + + PHYSICAL_FREE(PS2MEM_BASE, Ps2MemSize::Base, s_psM); + VIRTUAL_FREE(PS2MEM_ROM, Ps2MemSize::Rom); + VIRTUAL_FREE(PS2MEM_ROM1, Ps2MemSize::Rom1); + VIRTUAL_FREE(PS2MEM_ROM2, Ps2MemSize::Rom2); + VIRTUAL_FREE(PS2MEM_EROM, Ps2MemSize::ERom); + PHYSICAL_FREE(PS2MEM_SCRATCH, 0x00010000, s_psS); + PHYSICAL_FREE(PS2MEM_HW, Ps2MemSize::Hardware, s_psHw); + PHYSICAL_FREE(PS2MEM_PSX, Ps2MemSize::IopRam, s_psxM); + PHYSICAL_FREE(PS2MEM_VU0MICRO, 0x00010000, s_psVuMem); + + VIRTUAL_FREE(PS2MEM_VU0MICRO, 0x00010000); // allocate for all VUs + + VIRTUAL_FREE(PS2MEM_PSXHW, Ps2MemSize::IopHardware); + VIRTUAL_FREE(PS2MEM_PSXHW4, 0x00010000); + VIRTUAL_FREE(PS2MEM_GS, 0x00002000); + VIRTUAL_FREE(PS2MEM_DEV9, 0x00010000); + VIRTUAL_FREE(PS2MEM_SPU2, 0x00010000); + VIRTUAL_FREE(PS2MEM_SPU2_, 0x00010000); + + VIRTUAL_FREE(PS2MEM_B80, 0x00010000); + VIRTUAL_FREE(PS2MEM_BA0, 0x00010000); + + VirtualFree(PS2MEM_VU0MICRO, 0, MEM_RELEASE); + + safe_aligned_free(memLUT); + + // reserve mem + if( mmap(PS2MEM_BASE, 0x40000000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0) != PS2MEM_BASE ) { + SysPrintf("failed to reserve mem\n"); + } +} + +#endif // _WIN32 + +void vm_Reset() +{ + jASSUME( memLUT != NULL ); + + memzero_ptr(memLUT); + for (int i=0; i<0x02000; i++) memLUT[i + 0x00000] = initMemoryMap(&s_psM.aPFNs[i], &s_psM.aVFNs[i]); + for (int i=2; i<0x00010; i++) memLUT[i + 0x10000] = initMemoryMap(&s_psHw.aPFNs[i], &s_psHw.aVFNs[i]); + for (int i=0; i<0x00800; i++) memLUT[i + 0x1c000] = initMemoryMap(&s_psxM.aPFNs[(i & 0x1ff)], &s_psxM.aVFNs[(i & 0x1ff)]); + for (int i=0; i<0x00004; i++) + { + memLUT[i + 0x11000] = initMemoryMap(&s_psVuMem.aPFNs[0], &s_psVuMem.aVFNs[0]); + memLUT[i + 0x11004] = initMemoryMap(&s_psVuMem.aPFNs[1], &s_psVuMem.aVFNs[1]); + memLUT[i + 0x11008] = initMemoryMap(&s_psVuMem.aPFNs[4+i], &s_psVuMem.aVFNs[4+i]); + memLUT[i + 0x1100c] = initMemoryMap(&s_psVuMem.aPFNs[8+i], &s_psVuMem.aVFNs[8+i]); + + // Yay! Scratchpad mapping! We love the scratchpad. + memLUT[i + 0x50000] = initMemoryMap(&s_psS.aPFNs[i], &s_psS.aVFNs[i]); + } + + // map to other modes + memcpy(memLUT+0x80000, memLUT, 0x20000*sizeof(PSMEMORYMAP)); + memcpy(memLUT+0xa0000, memLUT, 0x20000*sizeof(PSMEMORYMAP)); +} + +// Some games read/write between different addrs but same physical memory +// this causes major slowdowns because it goes into the exception handler, so use this (zerofrog) +u32 VM_RETRANSLATE(u32 mem) +{ + u8* p, *pbase; + if( (mem&0xffff0000) == 0x50000000 ) // reserved scratch pad mem + return PS2MEM_BASE_+mem; + + p = (u8*)dmaGetAddrBase(mem); + +#ifdef _WIN32 + // do manual LUT since IPU/SPR seems to use addrs 0x3000xxxx quite often + if( memLUT[ (p-PS2MEM_BASE)>>12 ].aPFNs == NULL ) { + return PS2MEM_BASE_+mem; + } + + pbase = (u8*)memLUT[ (p-PS2MEM_BASE)>>12 ].aVFNs[0]; + if( pbase != NULL ) + p = pbase + ((u32)p&0xfff); +#endif + + return (u32)p; +} + +void memSetPageAddr(u32 vaddr, u32 paddr) { + + PSMEMORYMAP* pmap; + + if( vaddr == paddr ) + return; + + if( (vaddr>>28) != 1 && (vaddr>>28) != 9 && (vaddr>>28) != 11 ) { +#ifdef _WIN32 + pmap = &memLUT[vaddr >> 12]; + + if( pmap->aPFNs != NULL && (pmap->aPFNs != memLUT[paddr>>12].aPFNs || + pmap->aVFNs[0] != TRANSFORM_ADDR(vaddr)+(u32)PS2MEM_BASE) ) { + + SysMapUserPhysicalPages((void*)pmap->aVFNs[0], 1, NULL, 0); + pmap->aVFNs[0] = 0; + } + + *pmap = memLUT[paddr >> 12]; +#else + memLUT[vaddr>>12] = memLUT[paddr>>12]; +#endif + } +} + +void memClearPageAddr(u32 vaddr) { + // SysPrintf("memClearPageAddr: %8.8x\n", vaddr); + + if ((vaddr & 0xffffc000) == 0x70000000) return; + +#ifdef _WIN32 + // if( vaddr >= 0x20000000 && vaddr < 0x80000000 ) { + // Cpu->Clear(vaddr&~0xfff, 0x1000/4); + // if( memLUT[vaddr>>12].aVFNs != NULL ) { + // SysMapUserPhysicalPages((void*)memLUT[vaddr>>12].aVFNs[0], 1, NULL, 0 ); + // memLUT[vaddr>>12].aVFNs = NULL; + // memLUT[vaddr>>12].aPFNs = NULL; + // } + // } +#else + if( memLUT[vaddr>>12] != NULL ) { + SysVirtualFree(memLUT[vaddr>>12], 0x1000); + memLUT[vaddr>>12] = 0; + } +#endif +} + +u8 recMemRead8() +{ + register u32 mem; + __asm mov mem, ecx // already anded with ~0xa0000000 + + switch( (mem&~0xffff) ) { +case 0x1f400000: return psxHw4Read8(mem); +case 0x10000000: return hwRead8(mem); +case 0x1f800000: return psxHwRead8(mem); +case 0x12000000: return *(PS2MEM_BASE+(mem&~0xc00)); +case 0x14000000: + { + u32 ret = DEV9read8(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, ret); + return ret; + } + +default: + return *(u8*)(PS2MEM_BASE+mem); + } + MEM_LOG("Unknown Memory read32 from address %8.8x\n", mem); + + cpuTlbMissR(mem, cpuRegs.branch); + + return 0; +} + +void _eeReadConstMem8(int mmreg, u32 mem, int sign) +{ + assert( !IS_XMMREG(mmreg)); + + if( IS_MMXREG(mmreg) ) { + SetMMXstate(); + MOVDMtoMMX(mmreg&0xf, mem-3); + assert(0); + } + else { + if( sign ) MOVSX32M8toR(mmreg, mem); + else MOVZX32M8toR(mmreg, mem); + } +} + +void _eeReadConstMem16(int mmreg, u32 mem, int sign) +{ + assert( !IS_XMMREG(mmreg)); + + if( IS_MMXREG(mmreg) ) { + SetMMXstate(); + MOVDMtoMMX(mmreg&0xf, mem-2); + assert(0); + } + else { + if( sign ) MOVSX32M16toR(mmreg, mem); + else MOVZX32M16toR(mmreg, mem); + } +} + +void _eeReadConstMem32(int mmreg, u32 mem) +{ + if( IS_XMMREG(mmreg) ) SSEX_MOVD_M32_to_XMM(mmreg&0xf, mem); + else if( IS_MMXREG(mmreg) ) { + SetMMXstate(); + MOVDMtoMMX(mmreg&0xf, mem); + } + else MOV32MtoR(mmreg, mem); +} + +void _eeReadConstMem128(int mmreg, u32 mem) +{ + if( IS_MMXREG(mmreg) ) { + SetMMXstate(); + MOVQMtoR((mmreg>>4)&0xf, mem+8); + MOVQMtoR(mmreg&0xf, mem); + } + else SSEX_MOVDQA_M128_to_XMM( mmreg&0xf, mem); +} + +void _eeWriteConstMem8(u32 mem, int mmreg) +{ + assert( !IS_XMMREG(mmreg) && !IS_MMXREG(mmreg) ); + if( IS_EECONSTREG(mmreg) ) MOV8ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + else if( IS_PSXCONSTREG(mmreg) ) MOV8ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); + else MOV8RtoM(mem, mmreg); +} + +void _eeWriteConstMem16(u32 mem, int mmreg) +{ + assert( !IS_XMMREG(mmreg) && !IS_MMXREG(mmreg) ); + if( IS_EECONSTREG(mmreg) ) MOV16ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + else if( IS_PSXCONSTREG(mmreg) ) MOV16ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); + else MOV16RtoM(mem, mmreg); +} + +// op - 0 for AND, 1 for OR +void _eeWriteConstMem16OP(u32 mem, int mmreg, int op) +{ + assert( !IS_XMMREG(mmreg) && !IS_MMXREG(mmreg) ); + switch(op) { +case 0: // AND operation + if( IS_EECONSTREG(mmreg) ) AND16ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + else if( IS_PSXCONSTREG(mmreg) ) AND16ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); + else AND16RtoM(mem, mmreg); + break; +case 1: // OR operation + if( IS_EECONSTREG(mmreg) ) OR16ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + else if( IS_PSXCONSTREG(mmreg) ) OR16ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); + else OR16RtoM(mem, mmreg); + break; + + jNO_DEFAULT + } +} + +void _eeWriteConstMem32(u32 mem, int mmreg) +{ + if( IS_XMMREG(mmreg) ) SSE2_MOVD_XMM_to_M32(mem, mmreg&0xf); + else if( IS_MMXREG(mmreg) ) { + SetMMXstate(); + MOVDMMXtoM(mem, mmreg&0xf); + } + else if( IS_EECONSTREG(mmreg) ) MOV32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + else if( IS_PSXCONSTREG(mmreg) ) MOV32ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); + else MOV32RtoM(mem, mmreg); +} + +void _eeWriteConstMem32OP(u32 mem, int mmreg, int op) +{ + switch(op) { +case 0: // and + if( IS_XMMREG(mmreg) ) { + _deleteEEreg((mmreg>>16)&0x1f, 1); + SSE2_PAND_M128_to_XMM(mmreg&0xf, mem); + SSE2_MOVD_XMM_to_M32(mem, mmreg&0xf); + } + else if( IS_MMXREG(mmreg) ) { + _deleteEEreg((mmreg>>16)&0x1f, 1); + SetMMXstate(); + PANDMtoR(mmreg&0xf, mem); + MOVDMMXtoM(mem, mmreg&0xf); + } + else if( IS_EECONSTREG(mmreg) ) { + AND32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + } + else if( IS_PSXCONSTREG(mmreg) ) { + AND32ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); + } + else { + AND32RtoM(mem, mmreg&0xf); + } + break; + +case 1: // or + if( IS_XMMREG(mmreg) ) { + _deleteEEreg((mmreg>>16)&0x1f, 1); + SSE2_POR_M128_to_XMM(mmreg&0xf, mem); + SSE2_MOVD_XMM_to_M32(mem, mmreg&0xf); + } + else if( IS_MMXREG(mmreg) ) { + _deleteEEreg((mmreg>>16)&0x1f, 1); + SetMMXstate(); + PORMtoR(mmreg&0xf, mem); + MOVDMMXtoM(mem, mmreg&0xf); + } + else if( IS_EECONSTREG(mmreg) ) { + OR32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + } + else if( IS_PSXCONSTREG(mmreg) ) { + OR32ItoM(mem, g_psxConstRegs[((mmreg>>16)&0x1f)]); + } + else { + OR32RtoM(mem, mmreg&0xf); + } + break; + +case 2: // not and + if( mmreg & MEM_XMMTAG ) { + _deleteEEreg(mmreg>>16, 1); + SSEX_PANDN_M128_to_XMM(mmreg&0xf, mem); + SSEX_MOVD_XMM_to_M32(mem, mmreg&0xf); + } + else if( mmreg & MEM_MMXTAG ) { + _deleteEEreg(mmreg>>16, 1); + PANDNMtoR(mmreg&0xf, mem); + MOVDMMXtoM(mem, mmreg&0xf); + } + else if( IS_EECONSTREG(mmreg) ) { + AND32ItoM(mem, ~g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + } + else if( IS_PSXCONSTREG(mmreg) ) { + AND32ItoM(mem, ~g_psxConstRegs[((mmreg>>16)&0x1f)]); + } + else { + NOT32R(mmreg&0xf); + AND32RtoM(mem, mmreg&0xf); + } + break; + +default: assert(0); + } +} + +void _eeWriteConstMem64(u32 mem, int mmreg) +{ + if( IS_XMMREG(mmreg) ) SSE_MOVLPS_XMM_to_M64(mem, mmreg&0xf); + else if( IS_MMXREG(mmreg) ) { + SetMMXstate(); + MOVQRtoM(mem, mmreg&0xf); + } + else if( IS_EECONSTREG(mmreg) ) { + MOV32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + MOV32ItoM(mem+4, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[1]); + } + else assert(0); +} + +void _eeWriteConstMem128(u32 mem, int mmreg) +{ + if( IS_MMXREG(mmreg) ) { + SetMMXstate(); + MOVQRtoM(mem, mmreg&0xf); + MOVQRtoM(mem+8, (mmreg>>4)&0xf); + } + else if( IS_EECONSTREG(mmreg) ) { + SetMMXstate(); + MOV32ItoM(mem, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + MOV32ItoM(mem+4, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[1]); + MOVQRtoM(mem+8, mmreg&0xf); + } + else SSEX_MOVDQA_XMM_to_M128(mem, mmreg&0xf); +} + +void _eeMoveMMREGtoR(x86IntRegType to, int mmreg) +{ + if( IS_XMMREG(mmreg) ) SSE2_MOVD_XMM_to_R(to, mmreg&0xf); + else if( IS_MMXREG(mmreg) ) { + SetMMXstate(); + MOVD32MMXtoR(to, mmreg&0xf); + } + else if( IS_EECONSTREG(mmreg) ) MOV32ItoR(to, g_cpuConstRegs[((mmreg>>16)&0x1f)].UL[0]); + else if( IS_PSXCONSTREG(mmreg) ) MOV32ItoR(to, g_psxConstRegs[((mmreg>>16)&0x1f)]); + else if( mmreg != to ) MOV32RtoR(to, mmreg); +} + +int recMemConstRead8(u32 x86reg, u32 mem, u32 sign) +{ + mem = TRANSFORM_ADDR(mem); + + switch( mem>>16 ) { +case 0x1f40: return psxHw4ConstRead8(x86reg, mem, sign); +case 0x1000: return hwConstRead8(x86reg, mem, sign); +case 0x1f80: return psxHwConstRead8(x86reg, mem, sign); +case 0x1200: return gsConstRead8(x86reg, mem, sign); +case 0x1400: + { + iFlushCall(0); + PUSH32I(mem & ~0x04000000); + CALLFunc((u32)DEV9read8); + if( sign ) MOVSX32R8toR(EAX, EAX); + else MOVZX32R8toR(EAX, EAX); + return 1; + } + +default: + _eeReadConstMem8(x86reg, VM_RETRANSLATE(mem), sign); + return 0; + } +} + +u16 recMemRead16() { + + register u32 mem; + __asm mov mem, ecx // already anded with ~0xa0000000 + + switch( mem>>16 ) { + case 0x1000: return hwRead16(mem); + case 0x1f80: return psxHwRead16(mem); + case 0x1200: return *(u16*)(PS2MEM_BASE+(mem&~0xc00)); + case 0x1800: return 0; + case 0x1a00: return ba0R16(mem); + case 0x1f90: + case 0x1f00: + return SPU2read(mem); + case 0x1400: + { + u32 ret = DEV9read16(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, ret); + return ret; + } + + default: + return *(u16*)(PS2MEM_BASE+mem); + } + MEM_LOG("Unknown Memory read16 from address %8.8x\n", mem); + cpuTlbMissR(mem, cpuRegs.branch); + return 0; +} + +int recMemConstRead16(u32 x86reg, u32 mem, u32 sign) +{ + mem = TRANSFORM_ADDR(mem); + + switch( mem>>16 ) { +case 0x1000: return hwConstRead16(x86reg, mem, sign); +case 0x1f80: return psxHwConstRead16(x86reg, mem, sign); +case 0x1200: return gsConstRead16(x86reg, mem, sign); +case 0x1800: + if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf); + else XOR32RtoR(x86reg, x86reg); + return 0; +case 0x1a00: + iFlushCall(0); + PUSH32I(mem); + CALLFunc((u32)ba0R16); + ADD32ItoR(ESP, 4); + if( sign ) MOVSX32R16toR(EAX, EAX); + else MOVZX32R16toR(EAX, EAX); + return 1; + +case 0x1f90: +case 0x1f00: + iFlushCall(0); + PUSH32I(mem); + CALLFunc((u32)SPU2read); + if( sign ) MOVSX32R16toR(EAX, EAX); + else MOVZX32R16toR(EAX, EAX); + return 1; + +case 0x1400: + iFlushCall(0); + PUSH32I(mem & ~0x04000000); + CALLFunc((u32)DEV9read16); + if( sign ) MOVSX32R16toR(EAX, EAX); + else MOVZX32R16toR(EAX, EAX); + return 1; + +default: + _eeReadConstMem16(x86reg, VM_RETRANSLATE(mem), sign); + return 0; + } +} + +__declspec(naked) +u32 recMemRead32() { + // ecx is address - already anded with ~0xa0000000 + __asm { + + mov edx, ecx + shr edx, 16 + cmp dx, 0x1000 + je hwread + cmp dx, 0x1f80 + je psxhwread + cmp dx, 0x1200 + je gsread + cmp dx, 0x1400 + je devread + + // default read + mov eax, dword ptr [ecx+PS2MEM_BASE_] + ret + } + +hwread: + { + __asm { + cmp ecx, 0x10002000 + jb counterread + + cmp ecx, 0x1000f260 + je hwsifpresetread + cmp ecx, 0x1000f240 + je hwsifsyncread + cmp ecx, 0x1000f440 + je hwmch_drd + cmp ecx, 0x1000f430 + je hwmch_ricm + + cmp ecx, 0x10003000 + jb hwdefread2 + mov eax, dword ptr [ecx+PS2MEM_BASE_] + ret + + // ipu +hwdefread2: + push ecx + call ipuRead32 + add esp, 4 + ret + + // sif +hwsifpresetread: + xor eax, eax + ret +hwsifsyncread: + mov eax, 0x1000F240 + mov eax, dword ptr [eax+PS2MEM_BASE_] + or eax, 0xF0000102 + ret + } + +counterread: + { + static u32 mem, index; + + // counters + __asm mov mem, ecx + index = (mem>>11)&3; + + if( (mem&0x7ff) == 0 ) { + __asm { + push index + call rcntRcount + add esp, 4 + and eax, 0xffff + ret + } + } + + index = (u32)&counters[index] + ((mem>>2)&0xc); + + __asm { + mov eax, index + mov eax, dword ptr [eax] + movzx eax, ax + ret + } + } + +hwmch_drd: // MCH_DRD + __asm { + mov eax, dword ptr [ecx+PS2MEM_BASE_-0x10] + shr eax, 6 + test eax, 0xf + jz mch_drd_2 +hwmch_ricm: + xor eax, eax + ret + +mch_drd_2: + shr eax, 10 + and eax, 0xfff + cmp eax, 0x21 // INIT + je mch_drd_init + cmp eax, 0x23 // CNFGA + je mch_drd_cnfga + cmp eax, 0x24 // CNFGB + je mch_drd_cnfgb + cmp eax, 0x40 // DEVID + je mch_drd_devid + xor eax, eax + ret + +mch_drd_init: + mov edx, rdram_devices + xor eax, eax + cmp edx, rdram_sdevid + setg al + add rdram_sdevid, eax + imul eax, 0x1f + ret + +mch_drd_cnfga: + mov eax, 0x0D0D + ret + +mch_drd_cnfgb: + mov eax, 0x0090 + ret + +mch_drd_devid: + mov eax, dword ptr [ecx+PS2MEM_BASE_-0x10] + and eax, 0x1f + ret + } + } + +psxhwread: + __asm { + push ecx + call psxHwRead32 + add esp, 4 + ret + } + +gsread: + __asm { + and ecx, 0xfffff3ff + mov eax, dword ptr [ecx+PS2MEM_BASE_] + ret + } + +devread: + __asm { + and ecx, 0xfbffffff + push ecx + call DEV9read32 + add esp, 4 + ret + } +} + +int recMemConstRead32(u32 x86reg, u32 mem) +{ + mem = TRANSFORM_ADDR(mem); + + switch( (mem&~0xffff) ) { +case 0x10000000: return hwConstRead32(x86reg, mem); +case 0x1f800000: return psxHwConstRead32(x86reg, mem); +case 0x12000000: return gsConstRead32(x86reg, mem); +case 0x14000000: + iFlushCall(0); + PUSH32I(mem & ~0x04000000); + CALLFunc((u32)DEV9read32); + return 1; + +default: + _eeReadConstMem32(x86reg, VM_RETRANSLATE(mem)); + return 0; + } +} + +void recMemRead64(u64 *out) +{ + register u32 mem; + __asm mov mem, ecx // already anded with ~0xa0000000 + + switch( (mem&0xffff0000) ) { +case 0x10000000: *out = hwRead64(mem); return; +case 0x11000000: *out = *(u64*)(PS2MEM_BASE+mem); return; +case 0x12000000: *out = *(u64*)(PS2MEM_BASE+(mem&~0xc00)); return; + +default: + //assert(0); + *out = *(u64*)(PS2MEM_BASE+mem); + return; + } + + MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val); + cpuTlbMissR(mem, cpuRegs.branch); +} + +void recMemConstRead64(u32 mem, int mmreg) +{ + mem = TRANSFORM_ADDR(mem); + + switch( (mem&0xffff0000) ) { +case 0x10000000: hwConstRead64(mem, mmreg); return; +case 0x12000000: gsConstRead64(mem, mmreg); return; +default: + if( IS_XMMREG(mmreg) ) SSE_MOVLPS_M64_to_XMM(mmreg&0xff, VM_RETRANSLATE(mem)); + else { + MOVQMtoR(mmreg, VM_RETRANSLATE(mem)); + SetMMXstate(); + } + return; + } +} + +void recMemRead128(u64 *out) { + + register u32 mem; + __asm mov mem, ecx // already anded with ~0xa0000000 + + switch( (mem&0xffff0000) ) { + case 0x10000000: + hwRead128(mem, out); + return; + case 0x12000000: + out[0] = *(u64*)(PS2MEM_BASE+(mem&~0xc00)); + out[1] = *(u64*)(PS2MEM_BASE+(mem&~0xc00)+8); + return; + case 0x11000000: + out[0] = *(u64*)(PS2MEM_BASE+mem); + out[1] = *(u64*)(PS2MEM_BASE+mem+8); + return; + default: + //assert(0); + out[0] = *(u64*)(PS2MEM_BASE+mem); + out[1] = *(u64*)(PS2MEM_BASE+mem+8); + return; + } + + MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val); + cpuTlbMissR(mem, cpuRegs.branch); +} + +void recMemConstRead128(u32 mem, int xmmreg) +{ + mem = TRANSFORM_ADDR(mem); + + switch( (mem&0xffff0000) ) { +case 0x10000000: hwConstRead128(mem, xmmreg); return; +case 0x12000000: gsConstRead128(mem, xmmreg); return; +default: + _eeReadConstMem128(xmmreg, VM_RETRANSLATE(mem)); + return; + } +} + +void errwrite() +{ + int i, bit, tempeax; + __asm mov i, ecx + __asm mov tempeax, eax + __asm mov bit, edx + SysPrintf("Error write%d at %x\n", bit, i); + assert(0); + __asm mov eax, tempeax + __asm mov ecx, i +} + +void recMemWrite8() +{ + register u32 mem; + register u8 value; + __asm mov mem, ecx // already anded with ~0xa0000000 + __asm mov value, al + + switch( mem>>16 ) { +case 0x1f40: psxHw4Write8(mem, value); return; +case 0x1000: hwWrite8(mem, value); return; +case 0x1f80: psxHwWrite8(mem, value); return; +case 0x1200: gsWrite8(mem, value); return; +case 0x1400: + DEV9write8(mem & ~0x04000000, value); + SysPrintf("DEV9 write8 %8.8lx: %2.2lx\n", mem & ~0x04000000, value); + return; + +#ifdef _DEBUG +case 0x1100: assert(0); +#endif +default: + // vus, bad addrs, etc + *(u8*)(PS2MEM_BASE+mem) = value; + return; + } + MEM_LOG("Unknown Memory write8 to address %x with data %2.2x\n", mem, value); + cpuTlbMissW(mem, cpuRegs.branch); +} + +int recMemConstWrite8(u32 mem, int mmreg) +{ + mem = TRANSFORM_ADDR(mem); + + switch( mem>>16 ) { +case 0x1f40: psxHw4ConstWrite8(mem, mmreg); return 0; +case 0x1000: hwConstWrite8(mem, mmreg); return 0; +case 0x1f80: psxHwConstWrite8(mem, mmreg); return 0; +case 0x1200: gsConstWrite8(mem, mmreg); return 0; +case 0x1400: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(mem & ~0x04000000); + CALLFunc((u32)DEV9write8); + return 0; + +case 0x1100: + _eeWriteConstMem8(PS2MEM_BASE_+mem, mmreg); + + if( mem < 0x11004000 ) { + PUSH32I(1); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)CpuVU0->Clear); + ADD32ItoR(ESP, 8); + } + else if( mem >= 0x11008000 && mem < 0x1100c000 ) { + PUSH32I(1); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)CpuVU1->Clear); + ADD32ItoR(ESP, 8); + } + return 0; + +default: + _eeWriteConstMem8(PS2MEM_BASE_+mem, mmreg); + return 1; + } +} + +void recMemWrite16() { + + register u32 mem; + register u16 value; + __asm mov mem, ecx // already anded with ~0xa0000000 + __asm mov value, ax + + switch( mem>>16 ) { + case 0x1000: hwWrite16(mem, value); return; + case 0x1600: + //HACK: DEV9 VM crash fix + return; + case 0x1f80: psxHwWrite16(mem, value); return; + case 0x1200: gsWrite16(mem, value); return; + case 0x1f90: + case 0x1f00: SPU2write(mem, value); return; + case 0x1400: + DEV9write16(mem & ~0x04000000, value); + SysPrintf("DEV9 write16 %8.8lx: %4.4lx\n", mem & ~0x04000000, value); + return; + +#ifdef _DEBUG + case 0x1100: assert(0); +#endif + default: + // vus, bad addrs, etc + *(u16*)(PS2MEM_BASE+mem) = value; + return; + } + MEM_LOG("Unknown Memory write16 to address %x with data %4.4x\n", mem, value); + cpuTlbMissW(mem, cpuRegs.branch); +} + +int recMemConstWrite16(u32 mem, int mmreg) +{ + mem = TRANSFORM_ADDR(mem); + + switch( mem>>16 ) { +case 0x1000: hwConstWrite16(mem, mmreg); return 0; +case 0x1600: + //HACK: DEV9 VM crash fix + return 0; +case 0x1f80: psxHwConstWrite16(mem, mmreg); return 0; +case 0x1200: gsConstWrite16(mem, mmreg); return 0; +case 0x1f90: +case 0x1f00: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(mem); + CALLFunc((u32)SPU2write); + return 0; +case 0x1400: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(mem & ~0x04000000); + CALLFunc((u32)DEV9write16); + return 0; + +case 0x1100: + _eeWriteConstMem16(PS2MEM_BASE_+mem, mmreg); + + if( mem < 0x11004000 ) { + PUSH32I(1); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)CpuVU0->Clear); + ADD32ItoR(ESP, 8); + } + else if( mem >= 0x11008000 && mem < 0x1100c000 ) { + PUSH32I(1); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)CpuVU1->Clear); + ADD32ItoR(ESP, 8); + } + return 0; + +default: + _eeWriteConstMem16(PS2MEM_BASE_+mem, mmreg); + return 1; + } +} + +C_ASSERT( sizeof(BASEBLOCK) == 8 ); + +__declspec(naked) +void recMemWrite32() +{ + // ecx is address - already anded with ~0xa0000000 + __asm { + + mov edx, ecx + shr edx, 16 + cmp dx, 0x1000 + je hwwrite + cmp dx, 0x1f80 + je psxwrite + cmp dx, 0x1200 + je gswrite + cmp dx, 0x1400 + je devwrite + cmp dx, 0x1100 + je vuwrite + } + + __asm { + // default write + mov dword ptr [ecx+PS2MEM_BASE_], eax + ret + +hwwrite: + push eax + push ecx + call hwWrite32 + add esp, 8 + ret +psxwrite: + push eax + push ecx + call psxHwWrite32 + add esp, 8 + ret +gswrite: + push eax + push ecx + call gsWrite32 + add esp, 8 + ret +devwrite: + and ecx, 0xfbffffff + push eax + push ecx + call DEV9write32 + add esp, 8 + ret +vuwrite: + // default write + mov dword ptr [ecx+PS2MEM_BASE_], eax + + cmp ecx, 0x11004000 + jge vu1write + and ecx, 0x3ff8 + // clear vu0mem + mov eax, CpuVU0 + push 1 + push ecx + call [eax]CpuVU0.Clear + add esp, 8 + ret + +vu1write: + cmp ecx, 0x11008000 + jl vuend + cmp ecx, 0x1100c000 + jge vuend + // clear vu1mem + and ecx, 0x3ff8 + mov eax, CpuVU1 + push 1 + push ecx + call [eax]CpuVU1.Clear + add esp, 8 +vuend: + ret + } +} + +int recMemConstWrite32(u32 mem, int mmreg) +{ + mem = TRANSFORM_ADDR(mem); + + switch( mem&0xffff0000 ) { +case 0x10000000: hwConstWrite32(mem, mmreg); return 0; +case 0x1f800000: psxHwConstWrite32(mem, mmreg); return 0; +case 0x12000000: gsConstWrite32(mem, mmreg); return 0; +case 0x1f900000: +case 0x1f000000: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(mem); + CALLFunc((u32)SPU2write); + return 0; +case 0x14000000: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(mem & ~0x04000000); + CALLFunc((u32)DEV9write32); + return 0; + +case 0x11000000: + _eeWriteConstMem32(PS2MEM_BASE_+mem, mmreg); + + if( mem < 0x11004000 ) { + PUSH32I(1); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)CpuVU0->Clear); + ADD32ItoR(ESP, 8); + } + else if( mem >= 0x11008000 && mem < 0x1100c000 ) { + PUSH32I(1); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)CpuVU1->Clear); + ADD32ItoR(ESP, 8); + } + return 0; + +default: + _eeWriteConstMem32(PS2MEM_BASE_+mem, mmreg); + return 1; + } +} + +__declspec(naked) void recMemWrite64() +{ + __asm { + mov edx, ecx + shr edx, 16 + cmp dx, 0x1000 + je hwwrite + cmp dx, 0x1200 + je gswrite + cmp dx, 0x1100 + je vuwrite + } + + __asm { + // default write + mov edx, 64 + call errwrite + +hwwrite: + push dword ptr [eax+4] + push dword ptr [eax] + push ecx + call hwWrite64 + add esp, 12 + ret + +gswrite: + push dword ptr [eax+4] + push dword ptr [eax] + push ecx + call gsWrite64 + add esp, 12 + ret + +vuwrite: + mov ebx, dword ptr [eax] + mov edx, dword ptr [eax+4] + mov dword ptr [ecx+PS2MEM_BASE_], ebx + mov dword ptr [ecx+PS2MEM_BASE_+4], edx + + cmp ecx, 0x11004000 + jge vu1write + and ecx, 0x3ff8 + // clear vu0mem + mov eax, CpuVU0 + push 2 + push ecx + call [eax]CpuVU0.Clear + add esp, 8 + ret + +vu1write: + cmp ecx, 0x11008000 + jl vuend + cmp ecx, 0x1100c000 + jge vuend + // clear vu1mem + and ecx, 0x3ff8 + mov eax, CpuVU0 + push 2 + push ecx + call [eax]CpuVU1.Clear + add esp, 8 +vuend: + ret + } +} + +int recMemConstWrite64(u32 mem, int mmreg) +{ + mem = TRANSFORM_ADDR(mem); + + switch( (mem>>16) ) { +case 0x1000: hwConstWrite64(mem, mmreg); return 0; +case 0x1200: gsConstWrite64(mem, mmreg); return 0; + +case 0x1100: + _eeWriteConstMem64(PS2MEM_BASE_+mem, mmreg); + + if( mem < 0x11004000 ) { + PUSH32I(2); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)CpuVU0->Clear); + ADD32ItoR(ESP, 8); + } + else if( mem >= 0x11008000 && mem < 0x1100c000 ) { + PUSH32I(2); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)CpuVU1->Clear); + ADD32ItoR(ESP, 8); + } + return 0; + +default: + _eeWriteConstMem64(PS2MEM_BASE_+mem, mmreg); + return 1; + } +} + +__declspec(naked) +void recMemWrite128() +{ + __asm { + + mov edx, ecx + shr edx, 16 + cmp dx, 0x1000 + je hwwrite + cmp dx, 0x1200 + je gswrite + cmp dx, 0x1100 + je vuwrite + } + + __asm { + mov edx, 128 + call errwrite + +hwwrite: + + push eax + push ecx + call hwWrite128 + add esp, 8 + ret + +vuwrite: + mov ebx, dword ptr [eax] + mov edx, dword ptr [eax+4] + mov edi, dword ptr [eax+8] + mov eax, dword ptr [eax+12] + mov dword ptr [ecx+PS2MEM_BASE_], ebx + mov dword ptr [ecx+PS2MEM_BASE_+4], edx + mov dword ptr [ecx+PS2MEM_BASE_+8], edi + mov dword ptr [ecx+PS2MEM_BASE_+12], eax + + cmp ecx, 0x11004000 + jge vu1write + and ecx, 0x3ff8 + // clear vu0mem + mov eax, CpuVU0 + push 4 + push ecx + call [eax]CpuVU0.Clear + add esp, 8 + ret + +vu1write: + cmp ecx, 0x11008000 + jl vuend + cmp ecx, 0x1100c000 + jge vuend + // clear vu1mem + and ecx, 0x3ff8 + mov eax, CpuVU1 + push 4 + push ecx + call [eax]CpuVU1.Clear + add esp, 8 +vuend: + + // default write + //movaps xmm7, qword ptr [eax] + + // removes possible exceptions and saves on remapping memory + // *might* be faster for certain games, no way to tell + // cmp ecx, 0x20000000 + // jb Write128 + // + // // look for better mapping + // mov edx, ecx + // shr edx, 12 + // shl edx, 3 + // add edx, memLUT + // mov edx, dword ptr [edx + 4] + // cmp edx, 0 + // je Write128 + // mov edx, dword ptr [edx] + // cmp edx, 0 + // je Write128 + // and ecx, 0xfff + // movaps qword ptr [ecx+edx], xmm7 + // jmp CheckOverwrite + //Write128: + //movaps qword ptr [ecx+PS2MEM_BASE_], xmm7 + ret + +gswrite: + sub esp, 8 + movlps xmm7, qword ptr [eax] + movlps qword ptr [esp], xmm7 + push ecx + call gsWrite64 + + // call again for upper 8 bytes + movlps xmm7, qword ptr [eax+8] + movlps qword ptr [esp+4], xmm7 + add [esp], 8 + call gsWrite64 + add esp, 12 + ret + } +} + +int recMemConstWrite128(u32 mem, int mmreg) +{ + mem = TRANSFORM_ADDR(mem); + + switch( (mem&0xffff0000) ) { +case 0x10000000: hwConstWrite128(mem, mmreg); return 0; +case 0x12000000: gsConstWrite128(mem, mmreg); return 0; + +case 0x11000000: + _eeWriteConstMem128(PS2MEM_BASE_+mem, mmreg); + + if( mem < 0x11004000 ) { + PUSH32I(4); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)CpuVU0->Clear); + ADD32ItoR(ESP, 8); + } + else if( mem >= 0x11008000 && mem < 0x1100c000 ) { + PUSH32I(4); + PUSH32I(mem&0x3ff8); + CALLFunc((u32)CpuVU1->Clear); + ADD32ItoR(ESP, 8); + } + return 0; + +default: + _eeWriteConstMem128(PS2MEM_BASE_+mem, mmreg); + return 1; + } +} + +int __fastcall memRead8 (u32 mem, u8 *out) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x1f400000: *out = psxHw4Read8(mem); return 0; + case 0x10000000: *out = hwRead8(mem); return 0; + case 0x1f800000: *out = psxHwRead8(mem); return 0; + case 0x12000000: *out = gsRead8(mem); return 0; + case 0x14000000: + *out = DEV9read8(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); + return 0; + + default: + *out = *(u8*)(PS2MEM_BASE+mem); + return 0; + } + +#ifdef MEM_LOG + MEM_LOG("Unknown Memory read32 from address %8.8x\n", mem); +#endif + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int __fastcall memRead8RS (u32 mem, u64 *out) +{ + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { +case 0x1f400000: *out = (s8)psxHw4Read8(mem); return 0; +case 0x10000000: *out = (s8)hwRead8(mem); return 0; +case 0x1f800000: *out = (s8)psxHwRead8(mem); return 0; +case 0x12000000: *out = (s8)gsRead8(mem); return 0; +case 0x14000000: + *out = (s8)DEV9read8(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); + return 0; + +default: + *out = *(s8*)(PS2MEM_BASE+mem); + return 0; + } + MEM_LOG("Unknown Memory read32 from address %8.8x\n", mem); + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int __fastcall memRead8RU (u32 mem, u64 *out) +{ + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { +case 0x1f400000: *out = (u8)psxHw4Read8(mem); return 0; +case 0x10000000: *out = (u8)hwRead8(mem); return 0; +case 0x1f800000: *out = (u8)psxHwRead8(mem); return 0; +case 0x12000000: *out = (u8)gsRead8(mem); return 0; +case 0x14000000: + *out = (u8)DEV9read8(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); + return 0; + +default: + *out = *(u8*)(PS2MEM_BASE+mem); + return 0; + } + MEM_LOG("Unknown Memory read32 from address %8.8x\n", mem); + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int __fastcall memRead16(u32 mem, u16 *out) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: *out = hwRead16(mem); return 0; + case 0x1f800000: *out = psxHwRead16(mem); return 0; + case 0x12000000: *out = gsRead16(mem); return 0; + case 0x18000000: *out = 0; return 0; + case 0x1a000000: *out = ba0R16(mem); return 0; + case 0x1f900000: + case 0x1f000000: + *out = SPU2read(mem); return 0; + break; + case 0x14000000: + *out = DEV9read16(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); + return 0; + + default: + *out = *(u16*)(PS2MEM_BASE+mem); + return 0; + } + MEM_LOG("Unknown Memory read16 from address %8.8x\n", mem); + cpuTlbMissR(mem, cpuRegs.branch); + return -1; +} + +int __fastcall memRead16RS(u32 mem, u64 *out) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: *out = (s16)hwRead16(mem); return 0; + case 0x1f800000: *out = (s16)psxHwRead16(mem); return 0; + case 0x12000000: *out = (s16)gsRead16(mem); return 0; + case 0x18000000: *out = 0; return 0; + case 0x1a000000: *out = (s16)ba0R16(mem); return 0; + case 0x1f900000: + case 0x1f000000: + *out = (s16)SPU2read(mem); return 0; + break; + case 0x14000000: + *out = (s16)DEV9read16(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); + return 0; + + default: + *out = *(s16*)(PS2MEM_BASE+mem); + return 0; + } + MEM_LOG("Unknown Memory read16 from address %8.8x\n", mem); + cpuTlbMissR(mem, cpuRegs.branch); + return -1; +} + +int __fastcall memRead16RU(u32 mem, u64 *out) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: *out = (u16)hwRead16(mem ); return 0; + case 0x1f800000: *out = (u16)psxHwRead16(mem ); return 0; + case 0x12000000: *out = (u16)gsRead16(mem); return 0; + case 0x18000000: *out = 0; return 0; + case 0x1a000000: *out = (u16)ba0R16(mem); return 0; + case 0x1f900000: + case 0x1f000000: + *out = (u16)SPU2read(mem ); return 0; + break; + case 0x14000000: + *out = (u16)DEV9read16(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); + return 0; + + default: + *out = *(u16*)(PS2MEM_BASE+mem); + return 0; + } + MEM_LOG("Unknown Memory read16 from address %8.8x\n", mem); + cpuTlbMissR(mem, cpuRegs.branch); + return -1; +} + +int __fastcall memRead32(u32 mem, u32 *out) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: *out = hwRead32(mem); return 0; + case 0x1f800000: *out = psxHwRead32(mem); return 0; + case 0x12000000: *out = gsRead32(mem); return 0; + case 0x14000000: + *out = (u32)DEV9read32(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); + return 0; + + default: + *out = *(u32*)(PS2MEM_BASE+mem); + return 0; + } + + MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val); + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int __fastcall memRead32RS(u32 mem, u64 *out) +{ + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { +case 0x10000000: *out = (s32)hwRead32(mem); return 0; +case 0x1f800000: *out = (s32)psxHwRead32(mem); return 0; +case 0x12000000: *out = (s32)gsRead32(mem); return 0; +case 0x14000000: + *out = (s32)DEV9read32(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); + return 0; + +default: + *out = *(s32*)(PS2MEM_BASE+mem); + return 0; + } + + MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val); + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int __fastcall memRead32RU(u32 mem, u64 *out) +{ + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { +case 0x10000000: *out = (u32)hwRead32(mem); return 0; +case 0x1f800000: *out = (u32)psxHwRead32(mem); return 0; +case 0x12000000: *out = (u32)gsRead32(mem); return 0; +case 0x14000000: + *out = (u32)DEV9read32(mem & ~0x04000000); + SysPrintf("DEV9 read8 %8.8lx: %2.2lx\n", mem & ~0x04000000, *out); + return 0; + +default: + *out = *(u32*)(PS2MEM_BASE+mem); + return 0; + } + + MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val); + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int __fastcall memRead64(u32 mem, u64 *out) { + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: *out = hwRead64(mem); return 0; + case 0x12000000: *out = gsRead64(mem); return 0; + + default: + *out = *(u64*)(PS2MEM_BASE+mem); + return 0; + } + + MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val); + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +int __fastcall memRead128(u32 mem, u64 *out) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: + hwRead128(mem, out); + return 0; + case 0x12000000: + out[0] = gsRead64(mem); + out[1] = gsRead64(mem + 8); + return 0; + + default: + out[0] = *(u64*)(PS2MEM_BASE+mem); + out[1] = *(u64*)(PS2MEM_BASE+mem+8); + return 0; + } + + MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)\n", mem, cpuRegs.CP0.n.Status.val); + cpuTlbMissR(mem, cpuRegs.branch); + + return -1; +} + +void __fastcall memWrite8 (u32 mem, u8 value) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x1f400000: psxHw4Write8(mem, value); return; + case 0x10000000: hwWrite8(mem, value); return; + case 0x1f800000: psxHwWrite8(mem, value); return; + case 0x12000000: gsWrite8(mem, value); return; + case 0x14000000: + DEV9write8(mem & ~0x04000000, value); + SysPrintf("DEV9 write8 %8.8lx: %2.2lx\n", mem & ~0x04000000, value); + return; + + default: + *(u8*)(PS2MEM_BASE+mem) = value; + + if (CHECK_EEREC) { + REC_CLEARM(mem&~3); + } + return; + } + MEM_LOG("Unknown Memory write8 to address %x with data %2.2x\n", mem, value); + cpuTlbMissW(mem, cpuRegs.branch); +} + +void __fastcall memWrite16(u32 mem, u16 value) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: hwWrite16(mem, value); return; + case 0x1f800000: psxHwWrite16(mem, value); return; + case 0x12000000: gsWrite16(mem, value); return; + case 0x1f900000: + case 0x1f000000: SPU2write(mem, value); return; + case 0x14000000: + DEV9write16(mem & ~0x04000000, value); + SysPrintf("DEV9 write16 %8.8lx: %4.4lx\n", mem & ~0x04000000, value); + return; + + default: + *(u16*)(PS2MEM_BASE+mem) = value; + if (CHECK_EEREC) { + REC_CLEARM(mem&~3); + } + return; + } + MEM_LOG("Unknown Memory write16 to address %x with data %4.4x\n", mem, value); + cpuTlbMissW(mem, cpuRegs.branch); +} + +void __fastcall memWrite32(u32 mem, u32 value) +{ + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { +case 0x10000000: hwWrite32(mem, value); return; +case 0x1f800000: psxHwWrite32(mem, value); return; +case 0x12000000: gsWrite32(mem, value); return; +case 0x1f900000: +case 0x1f000000: SPU2write(mem, value); return; +case 0x14000000: + DEV9write32(mem & ~0x4000000, value); + SysPrintf("DEV9 write32 %8.8lx: %8.8lx\n", mem & ~0x4000000, value); + return; + +default: + *(u32*)(PS2MEM_BASE+mem) = value; + + if (CHECK_EEREC) { + REC_CLEARM(mem); + } + return; + } + MEM_LOG("Unknown Memory write32 to address %x with data %8.8x\n", mem, value); + cpuTlbMissW(mem, cpuRegs.branch); +} + +void __fastcall memWrite64(u32 mem, const u64* value) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: hwWrite64(mem, *value); return; + case 0x12000000: gsWrite64(mem, *value); return; + + default: + *(u64*)(PS2MEM_BASE+mem) = *value; + + if (CHECK_EEREC) { + REC_CLEARM(mem); + REC_CLEARM(mem+4); + } + return; + } + MEM_LOG("Unknown Memory write64 to address %x with data %8.8x_%8.8x\n", mem, (u32)((*value)>>32), (u32)value); + cpuTlbMissW(mem, cpuRegs.branch); +} + +void __fastcall memWrite128(u32 mem, const u64 *value) { + + mem = TRANSFORM_ADDR(mem); + switch( (mem&~0xffff) ) { + case 0x10000000: hwWrite128(mem, value); return; + case 0x12000000: + gsWrite64(mem, value[0]); + gsWrite64(mem + 8, value[1]); + return; + + default: + *(u64*)(PS2MEM_BASE+mem) = value[0]; + *(u64*)(PS2MEM_BASE+mem+8) = value[1]; + + if (CHECK_EEREC) { + REC_CLEARM(mem); + REC_CLEARM(mem+4); + REC_CLEARM(mem+8); + REC_CLEARM(mem+12); + } + return; + } + MEM_LOG("Unknown Memory write128 to address %x with data %8.8x_%8.8x_%8.8x_%8.8x\n", mem, ((u32*)value)[3], ((u32*)value)[2], ((u32*)value)[1], ((u32*)value)[0]); + cpuTlbMissW(mem, cpuRegs.branch); +} + +// Resets memory mappings, unmaps TLBs, reloads bios roms, etc. +void memReset() +{ +#ifdef _WIN32 + DWORD OldProtect; + // make sure can write + VirtualProtect(PS2MEM_ROM, Ps2MemSize::Rom, PAGE_READWRITE, &OldProtect); + VirtualProtect(PS2MEM_ROM1, Ps2MemSize::Rom1, PAGE_READWRITE, &OldProtect); + VirtualProtect(PS2MEM_ROM2, Ps2MemSize::Rom2, PAGE_READWRITE, &OldProtect); + VirtualProtect(PS2MEM_EROM, Ps2MemSize::ERom, PAGE_READWRITE, &OldProtect); +#else + mprotect(PS2EMEM_ROM, Ps2MemSize::Rom, PROT_READ|PROT_WRITE); + mprotect(PS2EMEM_ROM1, Ps2MemSize::Rom1, PROT_READ|PROT_WRITE); + mprotect(PS2EMEM_ROM2, Ps2MemSize::Rom2, PROT_READ|PROT_WRITE); + mprotect(PS2EMEM_EROM, Ps2MemSize::ERom, PROT_READ|PROT_WRITE); +#endif + + memzero_ptr(PS2MEM_BASE); + memzero_ptr(PS2MEM_SCRATCH); + vm_Reset(); + + string Bios; + FILE *fp; + + Path::Combine( Bios, Config.BiosDir, Config.Bios ); + + long filesize; + if( ( filesize = Path::getFileSize( Bios ) ) <= 0 ) + { + //Console::Error("Unable to load bios: '%s', PCSX2 can't run without that", params Bios); + throw Exception::FileNotFound( Bios, + "The specified Bios file was not found. A bios is required for Pcsx2 to run.\n\nFile not found" ); + } + + fp = fopen(Bios.c_str(), "rb"); + fread(PS2MEM_ROM, 1, std::min( (long)Ps2MemSize::Rom, filesize ), fp); + fclose(fp); + + BiosVersion = GetBiosVersion(); + Console::Status("Bios Version %d.%d", params BiosVersion >> 8, BiosVersion & 0xff); + + //injectIRX("host.irx"); //not fully tested; still buggy + + loadBiosRom("rom1", PS2MEM_ROM1, Ps2MemSize::Rom1); + loadBiosRom("rom2", PS2MEM_ROM2, Ps2MemSize::Rom2); + loadBiosRom("erom", PS2MEM_EROM, Ps2MemSize::ERom); + +#ifdef _WIN32 + VirtualProtect(PS2MEM_ROM, Ps2MemSize::Rom, PAGE_READONLY, &OldProtect); + VirtualProtect(PS2MEM_ROM1, Ps2MemSize::Rom1, PAGE_READONLY, &OldProtect); + VirtualProtect(PS2MEM_ROM2, Ps2MemSize::Rom2, PAGE_READONLY, &OldProtect); + VirtualProtect(PS2MEM_EROM, Ps2MemSize::ERom, PAGE_READONLY, &OldProtect); +#else + mprotect(PS2EMEM_ROM, Ps2MemSize::Rom, PROT_READ); + mprotect(PS2EMEM_ROM1, Ps2MemSize::Rom1, PROT_READ); + mprotect(PS2EMEM_ROM2, Ps2MemSize::Rom2, PROT_READ); + mprotect(PS2EMEM_EROM, Ps2MemSize::ERom, PROT_READ); +#endif +} + +#endif diff --git a/pcsx2/Misc.cpp b/pcsx2/Misc.cpp index 18db8fe8fa..87d55e6898 100644 --- a/pcsx2/Misc.cpp +++ b/pcsx2/Misc.cpp @@ -1,823 +1,823 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#ifdef _WIN32 -#include "RDebug/deci2.h" -#else -#include -#endif - -#include - -#include "Common.h" -#include "PsxCommon.h" -#include "SaveState.h" - -#include "CDVDisodrv.h" -#include "VUmicro.h" -#include "VU.h" -#include "iCore.h" -#include "iVUzerorec.h" -#include "BaseblockEx.h" // for debuild block dumping (which may or may not work anymore?) - -#include "GS.h" -#include "COP0.h" -#include "Cache.h" - -#include "Paths.h" - -using namespace std; -using namespace R5900; - -PcsxConfig Config; -u32 BiosVersion; -char CdromId[12]; -static int g_Pcsx2Recording = 0; // true 1 if recording video and sound - -const char *LabelAuthors = { N_( - "PCSX2, a PS2 emulator\n\n" - "originally written by:\n" - "saqib, refraction, zerofrog,\n" - "shadow, linuzappz, florin,\n" - "nachbrenner, auMatt, loser, \n" - "alexey silinov, goldfinger\n" - "\n" - "Devs:\n" - "Arcum42, drkIIRaziel, Cottonvibes, \n" - "Jake.Stine, Rama\n\n" - "Testing:\n" - "Krakatos\n" - "\n" - "Webmasters: CKemu, Falcon4ever") -}; - -const char *LabelGreets = { N_( - "Greets to: Bobbi, Keith, CpUMasteR, Nave, Snake785\n\n" - "Special thanks to: Gigaherz, Gabest, Sjeep, Dreamtime, F|RES, BGnome, MrBrown, \n" - "Seta-San, Skarmeth, blackd_wd, _Demo_\n" - "\n" - "Credits: Hiryu && Sjeep for their libcdvd (iso parsing and filesystem driver code)\n" - "\n" - "Some betatester/support dudes: Belmont, bositman, ChaosCode, CKemu, crushtest," - "Falcon4ever, GeneralPlot, jegHegy, parotaku, Prafull, Razorblade, Rudy_X, Seta-san") -}; - -static struct { - const char *name; - u32 size; -} ioprps[]={ - {"IOPRP14", 43845}, - {"IOPRP142", 48109}, - {"IOPRP143", 58317}, - {"IOPRP144", 58525}, - {"IOPRP15", 82741}, - {"IOPRP151", 82917}, - {"IOPRP153", 82949}, - {"IOPRP16", 91909}, - {"IOPRP165", 98901}, - {"IOPRP20", 109809}, - {"IOPRP202", 110993}, - {"IOPRP205", 119797}, - {"IOPRP21", 126857}, - {"IOPRP211", 129577}, - {"IOPRP213", 129577}, - {"IOPRP214", 140945}, - {"IOPRP22", 199257}, - {"IOPRP221", 196937}, - {"IOPRP222", 198233}, - {"IOPRP224", 201065}, - {"IOPRP23", 230329}, - {"IOPRP234", 247641}, - {"IOPRP24", 251065}, - {"IOPRP241", 251049}, - {"IOPRP242", 252409}, - {"IOPRP243", 253201}, - {"IOPRP250", 264897}, - {"IOPRP252", 265233}, - {"IOPRP253", 267217}, - {"IOPRP254", 264449}, - {"IOPRP255", 264449}, - {"IOPRP260", 248945}, - {"IOPRP270", 249121}, - {"IOPRP271", 266817}, - {"IOPRP280", 269889}, - {"IOPRP300", 275345}, - {"DNAS280", 272753}, - {"DNAS270", 251729}, - {"DNAS271", 268977}, - {"DNAS300", 278641}, - {"DNAS280", 272705}, - {"DNAS255", 264945}, - {NULL, 0} -}; - -void GetRPCVersion(char *ioprp, char *rpcver){ - char *p=ioprp; - int i; - struct TocEntry te; - - if (p && (CDVD_findfile(p+strlen("cdromN:"), &te) != -1)){ - for (i=0; ioprps[i].size>0; i++) - if (te.fileSize==ioprps[i].size) - break; - if (ioprps[i].size>0) - p=(char *)ioprps[i].name; - } - // fixme - Is p really supposed to be set in the middle of an if statement? - if (p && (p=strstr(p, "IOPRP")+strlen("IOPRP"))){ - for (i=0;(i<4) && p && (*p>='0') && (*p<='9');i++, p++) rpcver[i]=*p; - for ( ; i<4 ;i++ ) rpcver[i]='0'; - } -} - -u32 GetBiosVersion() { - unsigned int fileOffset=0; - s8 *ROMVER; - char vermaj[8]; - char vermin[8]; - struct romdir *rd; - u32 version; - int i; - - for (i=0; i<512*1024; i++) { - rd = (struct romdir*)&psRu8(i); - if (strncmp(rd->fileName, "RESET", 5) == 0) - break; /* found romdir */ - } - if (i == 512*1024) return -1; - - while(strlen(rd->fileName) > 0){ - if (strcmp(rd->fileName, "ROMVER") == 0){ // found romver - ROMVER = &psRs8(fileOffset); - - strncpy(vermaj, (char *)(ROMVER+ 0), 2); vermaj[2] = 0; - strncpy(vermin, (char *)(ROMVER+ 2), 2); vermin[2] = 0; - version = strtol(vermaj, (char**)NULL, 0) << 8; - version|= strtol(vermin, (char**)NULL, 0); - - return version; - } - - if ((rd->fileSize % 0x10)==0) - fileOffset += rd->fileSize; - else - fileOffset += (rd->fileSize + 0x10) & 0xfffffff0; - - rd++; - } - - return -1; -} - -//2002-09-22 (Florin) -int IsBIOS(char *filename, char *description) -{ - string Bios; - char ROMVER[14+1], zone[12+1]; - FILE *fp; - unsigned int fileOffset=0, found=FALSE; - struct romdir rd; - - Path::Combine( Bios, Config.BiosDir, filename ); - - int biosFileSize = Path::getFileSize( Bios ); - if( biosFileSize <= 0) return FALSE; - - fp = fopen(Bios.c_str(), "rb"); - if (fp == NULL) return FALSE; - - while ((ftell(fp)<512*1024) && (fread(&rd, DIRENTRY_SIZE, 1, fp)==1)) - if (strcmp(rd.fileName, "RESET") == 0) - break; /* found romdir */ - - if ((strcmp(rd.fileName, "RESET") != 0) || (rd.fileSize == 0)) { - fclose(fp); - return FALSE; //Unable to locate ROMDIR structure in file or a ioprpXXX.img - } - - while(strlen(rd.fileName) > 0){ - if (strcmp(rd.fileName, "ROMVER") == 0){ // found romver - unsigned int filepos=ftell(fp); - fseek(fp, fileOffset, SEEK_SET); - if (fread(&ROMVER, 14, 1, fp) == 0) break; - fseek(fp, filepos, SEEK_SET);//go back - - switch(ROMVER[4]){ - case 'T':sprintf(zone, "T10K "); break; - case 'X':sprintf(zone, "Test ");break; - case 'J':sprintf(zone, "Japan "); break; - case 'A':sprintf(zone, "USA "); break; - case 'E':sprintf(zone, "Europe"); break; - case 'H':sprintf(zone, "HK "); break; - case 'P':sprintf(zone, "Free "); break; - case 'C':sprintf(zone, "China "); break; - default: sprintf(zone, "%c ",ROMVER[4]); break;//shoudn't show - } - sprintf(description, "%s vXX.XX(XX/XX/XXXX) %s", zone, - ROMVER[5]=='C'?"Console":ROMVER[5]=='D'?"Devel":""); - strncpy(description+ 8, ROMVER+ 0, 2);//ver major - strncpy(description+11, ROMVER+ 2, 2);//ver minor - strncpy(description+14, ROMVER+12, 2);//day - strncpy(description+17, ROMVER+10, 2);//month - strncpy(description+20, ROMVER+ 6, 4);//year - found = TRUE; - } - - if ((rd.fileSize % 0x10)==0) - fileOffset += rd.fileSize; - else - fileOffset += (rd.fileSize + 0x10) & 0xfffffff0; - - if (fread(&rd, DIRENTRY_SIZE, 1, fp)==0) break; - } - fileOffset-=((rd.fileSize + 0x10) & 0xfffffff0) - rd.fileSize; - - fclose(fp); - - if (found) - { - char percent[6]; - - if ( biosFileSize < (int)fileOffset) - { - sprintf(percent, " %d%%", biosFileSize*100/(int)fileOffset); - strcat(description, percent);//we force users to have correct bioses, - //not that lame scph10000 of 513KB ;-) - } - return TRUE; - } - - return FALSE; //fail quietly -} - -// LOAD STUFF - -// fixme - Is there any reason why we shouldn't delete this define, and replace the array lengths -// with the actual numbers? -#define ISODCL(from, to) (to - from + 1) - -struct iso_directory_record { - char length [ISODCL (1, 1)]; /* length[1]; 711 */ - char ext_attr_length [ISODCL (2, 2)]; /* ext_attr_length[1]; 711 */ - char extent [ISODCL (3, 10)]; /* extent[8]; 733 */ - char size [ISODCL (11, 18)]; /* size[8]; 733 */ - char date [ISODCL (19, 25)]; /* date[7]; 7 by 711 */ - char flags [ISODCL (26, 26)]; /* flags[1]; */ - char file_unit_size [ISODCL (27, 27)]; /* file_unit_size[1]; 711 */ - char interleave [ISODCL (28, 28)]; /* interleave[1]; 711 */ - char volume_sequence_number [ISODCL (29, 32)]; /* volume_sequence_number[3]; 723 */ - unsigned char name_len [ISODCL (33, 33)]; /* name_len[1]; 711 */ - char name [1]; -}; - -int LoadCdrom() { - return 0; -} - -int CheckCdrom() { - u8 *buf; - - if (CDVDreadTrack(16, CDVD_MODE_2352) == -1) - return -1; - buf = CDVDgetBuffer(); - if (buf == NULL) - return -1; - - strncpy(CdromId, (char*)buf+52, 10); - - return 0; -} - -int GetPS2ElfName(char *name){ - int f; - char buffer[g_MaxPath];//if a file is longer...it should be shorter :D - char *pos; - TocEntry tocEntry; - - CDVDFS_init(); - - // check if the file exists - if (CDVD_findfile("SYSTEM.CNF;1", &tocEntry) != TRUE){ - Console::Error("Boot Error > SYSTEM.CNF not found"); - return 0;//could not find; not a PS/PS2 cdvd - } - - f=CDVDFS_open("SYSTEM.CNF;1", 1); - CDVDFS_read(f, buffer, g_MaxPath); - CDVDFS_close(f); - - buffer[tocEntry.fileSize]='\0'; - - pos=strstr(buffer, "BOOT2"); - if (pos==NULL){ - pos=strstr(buffer, "BOOT"); - if (pos==NULL) { - Console::Error("Boot Error > This is not a PS2 game!"); - return 0; - } - return 1; - } - pos+=strlen("BOOT2"); - while (pos && *pos && pos<=&buffer[255] - && (*pos<'A' || (*pos>'Z' && *pos<'a') || *pos>'z')) - pos++; - if (!pos || *pos==0) - return 0; - - sscanf(pos, "%s", name); - - if (strncmp("cdrom0:\\", name, 8) == 0) { - strncpy(CdromId, name+8, 11); CdromId[11] = 0; - } - -#ifdef PCSX2_DEVBUILD - FILE *fp; - int i; - - // inifile_read(CdromId); - fp = fopen("System.map", "r"); - if( fp == NULL ) return 2; - - u32 addr; - - Console::WriteLn("Loading System.map..."); - while (!feof(fp)) { - fseek(fp, 8, SEEK_CUR); - buffer[0] = '0'; buffer[1] = 'x'; - for (i=2; i<10; i++) buffer[i] = fgetc(fp); buffer[i] = 0; - addr = strtoul(buffer, (char**)NULL, 0); - fseek(fp, 3, SEEK_CUR); - for (i=0; iFreeze( g_nLeftGSFrames ); -} - -extern uptr pDsp; -void LoadGSState(const string& file) -{ - int ret; - gzLoadingState* f; - - Console::Status( "Loading GS State..." ); - - try - { - f = new gzLoadingState( file ); - } - catch( Exception::FileNotFound& ) - { - // file not found? try prefixing with sstates folder: - if( !Path::isRooted( file ) ) - { - string strfile; - Path::Combine( strfile, SSTATES_DIR, file ); - f = new gzLoadingState( strfile.c_str() ); - - // If this load attempt fails, then let the exception bubble up to - // the caller to deal with... - } - } - - // Always set gsIrq callback -- GS States are always exclusionary of MTGS mode - GSirqCallback( gsIrq ); - - ret = GSopen(&pDsp, "PCSX2", 0); - if (ret != 0) - { - delete f; - throw Exception::PluginFailure( "GS" ); - } - - ret = PAD1open((void *)&pDsp); - - f->Freeze(g_nLeftGSFrames); - f->gsFreeze(); - - f->FreezePlugin( "GS", gsSafeFreeze ); - - RunGSState( *f ); - - delete( f ); - - GSclose(); - PAD1close(); -} - -#endif - -struct LangDef { - char id[8]; - char name[64]; -}; - -LangDef sLangs[] = { - { "ar_AR", N_("Arabic") }, - { "bg_BG", N_("Bulgarian") }, - { "ca_CA", N_("Catalan") }, - { "cz_CZ", N_("Czech") }, - { "du_DU", N_("Dutch") }, - { "de_DE", N_("German") }, - { "el_EL", N_("Greek") }, - { "en_US", N_("English") }, - { "fr_FR", N_("French") }, - { "hb_HB" , N_("Hebrew") }, - { "hu_HU", N_("Hungarian") }, - { "it_IT", N_("Italian") }, - { "ja_JA", N_("Japanese") }, - { "pe_PE", N_("Persian") }, - { "po_PO", N_("Portuguese") }, - { "po_BR", N_("Portuguese BR") }, - { "pl_PL" , N_("Polish") }, - { "ro_RO", N_("Romanian") }, - { "ru_RU", N_("Russian") }, - { "es_ES", N_("Spanish") }, - { "sh_SH" , N_("S-Chinese") }, - { "sw_SW", N_("Swedish") }, - { "tc_TC", N_("T-Chinese") }, - { "tr_TR", N_("Turkish") }, - { "", "" }, -}; - - -char *ParseLang(char *id) { - int i=0; - - while (sLangs[i].id[0] != 0) { - if (!strcmp(id, sLangs[i].id)) - return _(sLangs[i].name); - i++; - } - - return id; -} - -#define NUM_STATES 10 -int StatesC = 0; - -extern char strgametitle[256]; - -char* mystrlwr( char* string ) -{ - assert( string != NULL ); - while ( 0 != ( *string++ = (char)tolower( *string ) ) ); - return string; -} - -static void GetGSStateFilename( string& dest ) -{ - string gsText; - ssprintf( gsText, "/%8.8X.%d.gs", ElfCRC, StatesC); - Path::Combine( dest, SSTATES_DIR, gsText ); -} - -void ProcessFKeys(int fkey, int shift) -{ - string Text; - - assert(fkey >= 1 && fkey <= 12 ); - - switch(fkey) { - case 1: - try - { - SaveState::GetFilename( Text, StatesC ); - gzSavingState( Text ).FreezeAll(); - } - catch( std::exception& ex ) - { - // 99% of the time this is a file permission error and the - // cpu state is intact so just display a passive msg to console. - - Console::Error( _( "Error > Could not save state to slot %d" ), params StatesC ); - Console::Error( ex.what() ); - } - break; - - case 2: - if( shift ) - StatesC = (StatesC+NUM_STATES-1) % NUM_STATES; - else - StatesC = (StatesC+1) % NUM_STATES; - - Console::Notice( _( " > Selected savestate slot %d" ), params StatesC); - - if( GSchangeSaveState != NULL ) { - SaveState::GetFilename(Text, StatesC); - GSchangeSaveState(StatesC, Text.c_str()); - } - break; - - case 3: - try - { - SaveState::GetFilename( Text, StatesC ); - gzLoadingState joe( Text ); // throws exception on version mismatch - cpuReset(); - SysResetExecutionState(); - joe.FreezeAll(); - } - catch( Exception::StateLoadError_Recoverable& ) - { - // At this point the cpu hasn't been reset, so we can return - // control to the user safely... (and silently) - } - catch( Exception::FileNotFound& ) - { - Console::Notice( _("Saveslot %d cannot be loaded; slot does not exist (file not found)"), params StatesC ); - } - catch( Exception::RuntimeError& ex ) - { - // This is the bad one. Chances are the cpu has been reset, so emulation has - // to be aborted. Sorry user! We'll give you some info for your trouble: - - Console::Error( _("An error occured while trying to load saveslot %d"), params StatesC ); - Console::Error( ex.cMessage() ); - Msgbox::Alert( - "Pcsx2 encountered an error while trying to load the savestate\n" - "and emulation had to be aborted." ); - - ClosePlugins(); - - throw Exception::CpuStateShutdown( - "Saveslot load failed; PS2 emulated state had to be shut down." ); // let the GUI handle the error "gracefully" - } - break; - - case 4: - { - const char* limitMsg; - u32 newOptions; - // cycle - if( shift ) { - // previous - newOptions = (Config.Options&~PCSX2_FRAMELIMIT_MASK)|(((Config.Options&PCSX2_FRAMELIMIT_MASK)+PCSX2_FRAMELIMIT_VUSKIP)&PCSX2_FRAMELIMIT_MASK); - } - else { - // next - newOptions = (Config.Options&~PCSX2_FRAMELIMIT_MASK)|(((Config.Options&PCSX2_FRAMELIMIT_MASK)+PCSX2_FRAMELIMIT_LIMIT)&PCSX2_FRAMELIMIT_MASK); - } - - gsResetFrameSkip(); - - switch(newOptions & PCSX2_FRAMELIMIT_MASK) { - case PCSX2_FRAMELIMIT_NORMAL: - limitMsg = "None/Normal"; - break; - case PCSX2_FRAMELIMIT_LIMIT: - limitMsg = "Limit"; - break; - case PCSX2_FRAMELIMIT_SKIP: - case PCSX2_FRAMELIMIT_VUSKIP: - if( GSsetFrameSkip == NULL ) - { - newOptions &= ~PCSX2_FRAMELIMIT_MASK; - Console::Notice("Notice: GS Plugin does not support frameskipping."); - limitMsg = "None/Normal"; - } - else - { - // When enabling Skipping we have to make sure Skipper (GS) and Limiter (EE) - // are properly synchronized. - gsDynamicSkipEnable(); - limitMsg = ((newOptions & PCSX2_FRAMELIMIT_MASK) == PCSX2_FRAMELIMIT_SKIP) ? "Skip" : "VUSkip"; - } - - break; - } - Threading::AtomicExchange( Config.Options, newOptions ); - - Console::Notice("Frame Limit Mode Changed: %s", params limitMsg ); - - // [Air]: Do we really want to save runtime changes to frameskipping? - //SaveConfig(); - } - break; - - // note: VK_F5-VK_F7 are reserved for GS - case 8: - GSmakeSnapshot("snap/"); - break; - -#ifdef PCSX2_DEVBUILD - case 10: - { - int num; - FILE* f; - BASEBLOCKEX** ppblocks = GetAllBaseBlocks(&num, 0); - - f = fopen("perflog.txt", "w"); - while(num-- > 0 ) { - if( ppblocks[0]->visited > 0 ) { - fprintf(f, "%u %u %u %u\n", ppblocks[0]->startpc, (u32)(ppblocks[0]->ltime.QuadPart / ppblocks[0]->visited), ppblocks[0]->visited, ppblocks[0]->size); - } - ppblocks[0]->visited = 0; - ppblocks[0]->ltime.QuadPart = 0; - ppblocks++; - } - fclose(f); - Console::Status( "perflog.txt written" ); - break; - } - - case 11: - if( mtgsThread != NULL ) { - Console::Notice( "Cannot make gsstates in MTGS mode" ); - } - else { - if( strgametitle[0] != 0 ) { - // only take the first two words - char name[256], *tok; - string gsText; - - tok = strtok(strgametitle, " "); - sprintf(name, "%s_", mystrlwr(tok)); - tok = strtok(NULL, " "); - if( tok != NULL ) strcat(name, tok); - - ssprintf( gsText, "%s.%d.gs", name, StatesC); - Path::Combine( Text, SSTATES_DIR, gsText ); - } - else - GetGSStateFilename( Text ); - - SaveGSState(Text); - } - break; -#endif - - case 12: - if( shift ) { -#ifdef PCSX2_DEVBUILD - iDumpRegisters(cpuRegs.pc, 0); - Console::Notice("hardware registers dumped EE:%x, IOP:%x\n", params cpuRegs.pc, psxRegs.pc); -#endif - } - else { - g_Pcsx2Recording ^= 1; - if( mtgsThread != NULL ) { - mtgsThread->SendSimplePacket(GS_RINGTYPE_RECORD, g_Pcsx2Recording, 0, 0); - } - else { - if( GSsetupRecording != NULL ) GSsetupRecording(g_Pcsx2Recording, NULL); - } - if( SPU2setupRecording != NULL ) SPU2setupRecording(g_Pcsx2Recording, NULL); - } - break; - } -} - -void injectIRX(const char *filename) -{ - string path; - char name[260], *p, *q; - struct romdir *rd; - int iROMDIR=-1, iIOPBTCONF=-1, iBLANK=-1, i, filesize; - FILE *fp; - - strcpy(name, filename); - for (i=0; name[i] && name[i]!='.' && i<10; i++) name[i]=toupper(name[i]);name[i]=0; - - //phase 1: find ROMDIR in bios - for (p=(char*)PS2MEM_ROM; p<(char*)PS2MEM_ROM+0x80000; p++) - if (strncmp(p, "RESET", 5)==0) - break; - rd=(struct romdir*)p; - - for (i=0; rd[i].fileName[0]; i++)if (strncmp(rd[i].fileName, name, strlen(name))==0)break; - if (rd[i].fileName[0])return;//already in;) - - //phase 2: make room in IOPBTCONF & ROMDIR - for (i=0; rd[i].fileName[0]; i++)if (strncmp(rd[i].fileName, "ROMDIR", 6)==0)iROMDIR=i; - for (i=0; rd[i].fileName[0]; i++)if (strncmp(rd[i].fileName, "IOPBTCONF", 9)==0)iIOPBTCONF=i; - - for (i=0; rd[i].fileName[0]; i++)if (rd[i].fileName[0]=='-')break; iBLANK=i; - rd[iBLANK].fileSize-=DIRENTRY_SIZE+DIRENTRY_SIZE; - p=(char*)PS2MEM_ROM;for (i=0; iq){*((u64*)p)=*((u64*)p-4);*((u64*)p+1)=*((u64*)p-3);p-=DIRENTRY_SIZE;} - *((u64*)p)=*((u64*)p+1)=0;p-=DIRENTRY_SIZE;rd[iIOPBTCONF].fileSize+=DIRENTRY_SIZE; - - q=(char*)PS2MEM_ROM;for (i=0; i<=iROMDIR; i++) q+=(rd[i].fileSize+0xF)&(~0xF); - while (p >q){*((u64*)p)=*((u64*)p-2);*((u64*)p+1)=*((u64*)p-1);p-=DIRENTRY_SIZE;} - *((u64*)p)=*((u64*)p+1)=0;p-=DIRENTRY_SIZE;rd[iROMDIR].fileSize+=DIRENTRY_SIZE; - - //phase 3: add the name to the end of IOPBTCONF - p=(char*)PS2MEM_ROM;for (i=0; i +#endif + +#include + +#include "Common.h" +#include "PsxCommon.h" +#include "SaveState.h" + +#include "CDVDisodrv.h" +#include "VUmicro.h" +#include "VU.h" +#include "iCore.h" +#include "iVUzerorec.h" +#include "BaseblockEx.h" // for debuild block dumping (which may or may not work anymore?) + +#include "GS.h" +#include "COP0.h" +#include "Cache.h" + +#include "Paths.h" + +using namespace std; +using namespace R5900; + +PcsxConfig Config; +u32 BiosVersion; +char CdromId[12]; +static int g_Pcsx2Recording = 0; // true 1 if recording video and sound + +const char *LabelAuthors = { N_( + "PCSX2, a PS2 emulator\n\n" + "originally written by:\n" + "saqib, refraction, zerofrog,\n" + "shadow, linuzappz, florin,\n" + "nachbrenner, auMatt, loser, \n" + "alexey silinov, goldfinger\n" + "\n" + "Devs:\n" + "Arcum42, drkIIRaziel, Cottonvibes, \n" + "Jake.Stine, Rama\n\n" + "Testing:\n" + "Krakatos\n" + "\n" + "Webmasters: CKemu, Falcon4ever") +}; + +const char *LabelGreets = { N_( + "Greets to: Bobbi, Keith, CpUMasteR, Nave, Snake785\n\n" + "Special thanks to: Gigaherz, Gabest, Sjeep, Dreamtime, F|RES, BGnome, MrBrown, \n" + "Seta-San, Skarmeth, blackd_wd, _Demo_\n" + "\n" + "Credits: Hiryu && Sjeep for their libcdvd (iso parsing and filesystem driver code)\n" + "\n" + "Some betatester/support dudes: Belmont, bositman, ChaosCode, CKemu, crushtest," + "Falcon4ever, GeneralPlot, jegHegy, parotaku, Prafull, Razorblade, Rudy_X, Seta-san") +}; + +static struct { + const char *name; + u32 size; +} ioprps[]={ + {"IOPRP14", 43845}, + {"IOPRP142", 48109}, + {"IOPRP143", 58317}, + {"IOPRP144", 58525}, + {"IOPRP15", 82741}, + {"IOPRP151", 82917}, + {"IOPRP153", 82949}, + {"IOPRP16", 91909}, + {"IOPRP165", 98901}, + {"IOPRP20", 109809}, + {"IOPRP202", 110993}, + {"IOPRP205", 119797}, + {"IOPRP21", 126857}, + {"IOPRP211", 129577}, + {"IOPRP213", 129577}, + {"IOPRP214", 140945}, + {"IOPRP22", 199257}, + {"IOPRP221", 196937}, + {"IOPRP222", 198233}, + {"IOPRP224", 201065}, + {"IOPRP23", 230329}, + {"IOPRP234", 247641}, + {"IOPRP24", 251065}, + {"IOPRP241", 251049}, + {"IOPRP242", 252409}, + {"IOPRP243", 253201}, + {"IOPRP250", 264897}, + {"IOPRP252", 265233}, + {"IOPRP253", 267217}, + {"IOPRP254", 264449}, + {"IOPRP255", 264449}, + {"IOPRP260", 248945}, + {"IOPRP270", 249121}, + {"IOPRP271", 266817}, + {"IOPRP280", 269889}, + {"IOPRP300", 275345}, + {"DNAS280", 272753}, + {"DNAS270", 251729}, + {"DNAS271", 268977}, + {"DNAS300", 278641}, + {"DNAS280", 272705}, + {"DNAS255", 264945}, + {NULL, 0} +}; + +void GetRPCVersion(char *ioprp, char *rpcver){ + char *p=ioprp; + int i; + struct TocEntry te; + + if (p && (CDVD_findfile(p+strlen("cdromN:"), &te) != -1)){ + for (i=0; ioprps[i].size>0; i++) + if (te.fileSize==ioprps[i].size) + break; + if (ioprps[i].size>0) + p=(char *)ioprps[i].name; + } + // fixme - Is p really supposed to be set in the middle of an if statement? + if (p && (p=strstr(p, "IOPRP")+strlen("IOPRP"))){ + for (i=0;(i<4) && p && (*p>='0') && (*p<='9');i++, p++) rpcver[i]=*p; + for ( ; i<4 ;i++ ) rpcver[i]='0'; + } +} + +u32 GetBiosVersion() { + unsigned int fileOffset=0; + s8 *ROMVER; + char vermaj[8]; + char vermin[8]; + struct romdir *rd; + u32 version; + int i; + + for (i=0; i<512*1024; i++) { + rd = (struct romdir*)&psRu8(i); + if (strncmp(rd->fileName, "RESET", 5) == 0) + break; /* found romdir */ + } + if (i == 512*1024) return -1; + + while(strlen(rd->fileName) > 0){ + if (strcmp(rd->fileName, "ROMVER") == 0){ // found romver + ROMVER = &psRs8(fileOffset); + + strncpy(vermaj, (char *)(ROMVER+ 0), 2); vermaj[2] = 0; + strncpy(vermin, (char *)(ROMVER+ 2), 2); vermin[2] = 0; + version = strtol(vermaj, (char**)NULL, 0) << 8; + version|= strtol(vermin, (char**)NULL, 0); + + return version; + } + + if ((rd->fileSize % 0x10)==0) + fileOffset += rd->fileSize; + else + fileOffset += (rd->fileSize + 0x10) & 0xfffffff0; + + rd++; + } + + return -1; +} + +//2002-09-22 (Florin) +int IsBIOS(char *filename, char *description) +{ + string Bios; + char ROMVER[14+1], zone[12+1]; + FILE *fp; + unsigned int fileOffset=0, found=FALSE; + struct romdir rd; + + Path::Combine( Bios, Config.BiosDir, filename ); + + int biosFileSize = Path::getFileSize( Bios ); + if( biosFileSize <= 0) return FALSE; + + fp = fopen(Bios.c_str(), "rb"); + if (fp == NULL) return FALSE; + + while ((ftell(fp)<512*1024) && (fread(&rd, DIRENTRY_SIZE, 1, fp)==1)) + if (strcmp(rd.fileName, "RESET") == 0) + break; /* found romdir */ + + if ((strcmp(rd.fileName, "RESET") != 0) || (rd.fileSize == 0)) { + fclose(fp); + return FALSE; //Unable to locate ROMDIR structure in file or a ioprpXXX.img + } + + while(strlen(rd.fileName) > 0){ + if (strcmp(rd.fileName, "ROMVER") == 0){ // found romver + unsigned int filepos=ftell(fp); + fseek(fp, fileOffset, SEEK_SET); + if (fread(&ROMVER, 14, 1, fp) == 0) break; + fseek(fp, filepos, SEEK_SET);//go back + + switch(ROMVER[4]){ + case 'T':sprintf(zone, "T10K "); break; + case 'X':sprintf(zone, "Test ");break; + case 'J':sprintf(zone, "Japan "); break; + case 'A':sprintf(zone, "USA "); break; + case 'E':sprintf(zone, "Europe"); break; + case 'H':sprintf(zone, "HK "); break; + case 'P':sprintf(zone, "Free "); break; + case 'C':sprintf(zone, "China "); break; + default: sprintf(zone, "%c ",ROMVER[4]); break;//shoudn't show + } + sprintf(description, "%s vXX.XX(XX/XX/XXXX) %s", zone, + ROMVER[5]=='C'?"Console":ROMVER[5]=='D'?"Devel":""); + strncpy(description+ 8, ROMVER+ 0, 2);//ver major + strncpy(description+11, ROMVER+ 2, 2);//ver minor + strncpy(description+14, ROMVER+12, 2);//day + strncpy(description+17, ROMVER+10, 2);//month + strncpy(description+20, ROMVER+ 6, 4);//year + found = TRUE; + } + + if ((rd.fileSize % 0x10)==0) + fileOffset += rd.fileSize; + else + fileOffset += (rd.fileSize + 0x10) & 0xfffffff0; + + if (fread(&rd, DIRENTRY_SIZE, 1, fp)==0) break; + } + fileOffset-=((rd.fileSize + 0x10) & 0xfffffff0) - rd.fileSize; + + fclose(fp); + + if (found) + { + char percent[6]; + + if ( biosFileSize < (int)fileOffset) + { + sprintf(percent, " %d%%", biosFileSize*100/(int)fileOffset); + strcat(description, percent);//we force users to have correct bioses, + //not that lame scph10000 of 513KB ;-) + } + return TRUE; + } + + return FALSE; //fail quietly +} + +// LOAD STUFF + +// fixme - Is there any reason why we shouldn't delete this define, and replace the array lengths +// with the actual numbers? +#define ISODCL(from, to) (to - from + 1) + +struct iso_directory_record { + char length [ISODCL (1, 1)]; /* length[1]; 711 */ + char ext_attr_length [ISODCL (2, 2)]; /* ext_attr_length[1]; 711 */ + char extent [ISODCL (3, 10)]; /* extent[8]; 733 */ + char size [ISODCL (11, 18)]; /* size[8]; 733 */ + char date [ISODCL (19, 25)]; /* date[7]; 7 by 711 */ + char flags [ISODCL (26, 26)]; /* flags[1]; */ + char file_unit_size [ISODCL (27, 27)]; /* file_unit_size[1]; 711 */ + char interleave [ISODCL (28, 28)]; /* interleave[1]; 711 */ + char volume_sequence_number [ISODCL (29, 32)]; /* volume_sequence_number[3]; 723 */ + unsigned char name_len [ISODCL (33, 33)]; /* name_len[1]; 711 */ + char name [1]; +}; + +int LoadCdrom() { + return 0; +} + +int CheckCdrom() { + u8 *buf; + + if (CDVDreadTrack(16, CDVD_MODE_2352) == -1) + return -1; + buf = CDVDgetBuffer(); + if (buf == NULL) + return -1; + + strncpy(CdromId, (char*)buf+52, 10); + + return 0; +} + +int GetPS2ElfName(char *name){ + int f; + char buffer[g_MaxPath];//if a file is longer...it should be shorter :D + char *pos; + TocEntry tocEntry; + + CDVDFS_init(); + + // check if the file exists + if (CDVD_findfile("SYSTEM.CNF;1", &tocEntry) != TRUE){ + Console::Error("Boot Error > SYSTEM.CNF not found"); + return 0;//could not find; not a PS/PS2 cdvd + } + + f=CDVDFS_open("SYSTEM.CNF;1", 1); + CDVDFS_read(f, buffer, g_MaxPath); + CDVDFS_close(f); + + buffer[tocEntry.fileSize]='\0'; + + pos=strstr(buffer, "BOOT2"); + if (pos==NULL){ + pos=strstr(buffer, "BOOT"); + if (pos==NULL) { + Console::Error("Boot Error > This is not a PS2 game!"); + return 0; + } + return 1; + } + pos+=strlen("BOOT2"); + while (pos && *pos && pos<=&buffer[255] + && (*pos<'A' || (*pos>'Z' && *pos<'a') || *pos>'z')) + pos++; + if (!pos || *pos==0) + return 0; + + sscanf(pos, "%s", name); + + if (strncmp("cdrom0:\\", name, 8) == 0) { + strncpy(CdromId, name+8, 11); CdromId[11] = 0; + } + +#ifdef PCSX2_DEVBUILD + FILE *fp; + int i; + + // inifile_read(CdromId); + fp = fopen("System.map", "r"); + if( fp == NULL ) return 2; + + u32 addr; + + Console::WriteLn("Loading System.map..."); + while (!feof(fp)) { + fseek(fp, 8, SEEK_CUR); + buffer[0] = '0'; buffer[1] = 'x'; + for (i=2; i<10; i++) buffer[i] = fgetc(fp); buffer[i] = 0; + addr = strtoul(buffer, (char**)NULL, 0); + fseek(fp, 3, SEEK_CUR); + for (i=0; iFreeze( g_nLeftGSFrames ); +} + +extern uptr pDsp; +void LoadGSState(const string& file) +{ + int ret; + gzLoadingState* f; + + Console::Status( "Loading GS State..." ); + + try + { + f = new gzLoadingState( file ); + } + catch( Exception::FileNotFound& ) + { + // file not found? try prefixing with sstates folder: + if( !Path::isRooted( file ) ) + { + string strfile; + Path::Combine( strfile, SSTATES_DIR, file ); + f = new gzLoadingState( strfile.c_str() ); + + // If this load attempt fails, then let the exception bubble up to + // the caller to deal with... + } + } + + // Always set gsIrq callback -- GS States are always exclusionary of MTGS mode + GSirqCallback( gsIrq ); + + ret = GSopen(&pDsp, "PCSX2", 0); + if (ret != 0) + { + delete f; + throw Exception::PluginFailure( "GS" ); + } + + ret = PAD1open((void *)&pDsp); + + f->Freeze(g_nLeftGSFrames); + f->gsFreeze(); + + f->FreezePlugin( "GS", gsSafeFreeze ); + + RunGSState( *f ); + + delete( f ); + + GSclose(); + PAD1close(); +} + +#endif + +struct LangDef { + char id[8]; + char name[64]; +}; + +LangDef sLangs[] = { + { "ar_AR", N_("Arabic") }, + { "bg_BG", N_("Bulgarian") }, + { "ca_CA", N_("Catalan") }, + { "cz_CZ", N_("Czech") }, + { "du_DU", N_("Dutch") }, + { "de_DE", N_("German") }, + { "el_EL", N_("Greek") }, + { "en_US", N_("English") }, + { "fr_FR", N_("French") }, + { "hb_HB" , N_("Hebrew") }, + { "hu_HU", N_("Hungarian") }, + { "it_IT", N_("Italian") }, + { "ja_JA", N_("Japanese") }, + { "pe_PE", N_("Persian") }, + { "po_PO", N_("Portuguese") }, + { "po_BR", N_("Portuguese BR") }, + { "pl_PL" , N_("Polish") }, + { "ro_RO", N_("Romanian") }, + { "ru_RU", N_("Russian") }, + { "es_ES", N_("Spanish") }, + { "sh_SH" , N_("S-Chinese") }, + { "sw_SW", N_("Swedish") }, + { "tc_TC", N_("T-Chinese") }, + { "tr_TR", N_("Turkish") }, + { "", "" }, +}; + + +char *ParseLang(char *id) { + int i=0; + + while (sLangs[i].id[0] != 0) { + if (!strcmp(id, sLangs[i].id)) + return _(sLangs[i].name); + i++; + } + + return id; +} + +#define NUM_STATES 10 +int StatesC = 0; + +extern char strgametitle[256]; + +char* mystrlwr( char* string ) +{ + assert( string != NULL ); + while ( 0 != ( *string++ = (char)tolower( *string ) ) ); + return string; +} + +static void GetGSStateFilename( string& dest ) +{ + string gsText; + ssprintf( gsText, "/%8.8X.%d.gs", ElfCRC, StatesC); + Path::Combine( dest, SSTATES_DIR, gsText ); +} + +void ProcessFKeys(int fkey, int shift) +{ + string Text; + + assert(fkey >= 1 && fkey <= 12 ); + + switch(fkey) { + case 1: + try + { + SaveState::GetFilename( Text, StatesC ); + gzSavingState( Text ).FreezeAll(); + } + catch( std::exception& ex ) + { + // 99% of the time this is a file permission error and the + // cpu state is intact so just display a passive msg to console. + + Console::Error( _( "Error > Could not save state to slot %d" ), params StatesC ); + Console::Error( ex.what() ); + } + break; + + case 2: + if( shift ) + StatesC = (StatesC+NUM_STATES-1) % NUM_STATES; + else + StatesC = (StatesC+1) % NUM_STATES; + + Console::Notice( _( " > Selected savestate slot %d" ), params StatesC); + + if( GSchangeSaveState != NULL ) { + SaveState::GetFilename(Text, StatesC); + GSchangeSaveState(StatesC, Text.c_str()); + } + break; + + case 3: + try + { + SaveState::GetFilename( Text, StatesC ); + gzLoadingState joe( Text ); // throws exception on version mismatch + cpuReset(); + SysResetExecutionState(); + joe.FreezeAll(); + } + catch( Exception::StateLoadError_Recoverable& ) + { + // At this point the cpu hasn't been reset, so we can return + // control to the user safely... (and silently) + } + catch( Exception::FileNotFound& ) + { + Console::Notice( _("Saveslot %d cannot be loaded; slot does not exist (file not found)"), params StatesC ); + } + catch( Exception::RuntimeError& ex ) + { + // This is the bad one. Chances are the cpu has been reset, so emulation has + // to be aborted. Sorry user! We'll give you some info for your trouble: + + Console::Error( _("An error occured while trying to load saveslot %d"), params StatesC ); + Console::Error( ex.cMessage() ); + Msgbox::Alert( + "Pcsx2 encountered an error while trying to load the savestate\n" + "and emulation had to be aborted." ); + + ClosePlugins(); + + throw Exception::CpuStateShutdown( + "Saveslot load failed; PS2 emulated state had to be shut down." ); // let the GUI handle the error "gracefully" + } + break; + + case 4: + { + const char* limitMsg; + u32 newOptions; + // cycle + if( shift ) { + // previous + newOptions = (Config.Options&~PCSX2_FRAMELIMIT_MASK)|(((Config.Options&PCSX2_FRAMELIMIT_MASK)+PCSX2_FRAMELIMIT_VUSKIP)&PCSX2_FRAMELIMIT_MASK); + } + else { + // next + newOptions = (Config.Options&~PCSX2_FRAMELIMIT_MASK)|(((Config.Options&PCSX2_FRAMELIMIT_MASK)+PCSX2_FRAMELIMIT_LIMIT)&PCSX2_FRAMELIMIT_MASK); + } + + gsResetFrameSkip(); + + switch(newOptions & PCSX2_FRAMELIMIT_MASK) { + case PCSX2_FRAMELIMIT_NORMAL: + limitMsg = "None/Normal"; + break; + case PCSX2_FRAMELIMIT_LIMIT: + limitMsg = "Limit"; + break; + case PCSX2_FRAMELIMIT_SKIP: + case PCSX2_FRAMELIMIT_VUSKIP: + if( GSsetFrameSkip == NULL ) + { + newOptions &= ~PCSX2_FRAMELIMIT_MASK; + Console::Notice("Notice: GS Plugin does not support frameskipping."); + limitMsg = "None/Normal"; + } + else + { + // When enabling Skipping we have to make sure Skipper (GS) and Limiter (EE) + // are properly synchronized. + gsDynamicSkipEnable(); + limitMsg = ((newOptions & PCSX2_FRAMELIMIT_MASK) == PCSX2_FRAMELIMIT_SKIP) ? "Skip" : "VUSkip"; + } + + break; + } + Threading::AtomicExchange( Config.Options, newOptions ); + + Console::Notice("Frame Limit Mode Changed: %s", params limitMsg ); + + // [Air]: Do we really want to save runtime changes to frameskipping? + //SaveConfig(); + } + break; + + // note: VK_F5-VK_F7 are reserved for GS + case 8: + GSmakeSnapshot("snap/"); + break; + +#ifdef PCSX2_DEVBUILD + case 10: + { + int num; + FILE* f; + BASEBLOCKEX** ppblocks = GetAllBaseBlocks(&num, 0); + + f = fopen("perflog.txt", "w"); + while(num-- > 0 ) { + if( ppblocks[0]->visited > 0 ) { + fprintf(f, "%u %u %u %u\n", ppblocks[0]->startpc, (u32)(ppblocks[0]->ltime.QuadPart / ppblocks[0]->visited), ppblocks[0]->visited, ppblocks[0]->size); + } + ppblocks[0]->visited = 0; + ppblocks[0]->ltime.QuadPart = 0; + ppblocks++; + } + fclose(f); + Console::Status( "perflog.txt written" ); + break; + } + + case 11: + if( mtgsThread != NULL ) { + Console::Notice( "Cannot make gsstates in MTGS mode" ); + } + else { + if( strgametitle[0] != 0 ) { + // only take the first two words + char name[256], *tok; + string gsText; + + tok = strtok(strgametitle, " "); + sprintf(name, "%s_", mystrlwr(tok)); + tok = strtok(NULL, " "); + if( tok != NULL ) strcat(name, tok); + + ssprintf( gsText, "%s.%d.gs", name, StatesC); + Path::Combine( Text, SSTATES_DIR, gsText ); + } + else + GetGSStateFilename( Text ); + + SaveGSState(Text); + } + break; +#endif + + case 12: + if( shift ) { +#ifdef PCSX2_DEVBUILD + iDumpRegisters(cpuRegs.pc, 0); + Console::Notice("hardware registers dumped EE:%x, IOP:%x\n", params cpuRegs.pc, psxRegs.pc); +#endif + } + else { + g_Pcsx2Recording ^= 1; + if( mtgsThread != NULL ) { + mtgsThread->SendSimplePacket(GS_RINGTYPE_RECORD, g_Pcsx2Recording, 0, 0); + } + else { + if( GSsetupRecording != NULL ) GSsetupRecording(g_Pcsx2Recording, NULL); + } + if( SPU2setupRecording != NULL ) SPU2setupRecording(g_Pcsx2Recording, NULL); + } + break; + } +} + +void injectIRX(const char *filename) +{ + string path; + char name[260], *p, *q; + struct romdir *rd; + int iROMDIR=-1, iIOPBTCONF=-1, iBLANK=-1, i, filesize; + FILE *fp; + + strcpy(name, filename); + for (i=0; name[i] && name[i]!='.' && i<10; i++) name[i]=toupper(name[i]);name[i]=0; + + //phase 1: find ROMDIR in bios + for (p=(char*)PS2MEM_ROM; p<(char*)PS2MEM_ROM+0x80000; p++) + if (strncmp(p, "RESET", 5)==0) + break; + rd=(struct romdir*)p; + + for (i=0; rd[i].fileName[0]; i++)if (strncmp(rd[i].fileName, name, strlen(name))==0)break; + if (rd[i].fileName[0])return;//already in;) + + //phase 2: make room in IOPBTCONF & ROMDIR + for (i=0; rd[i].fileName[0]; i++)if (strncmp(rd[i].fileName, "ROMDIR", 6)==0)iROMDIR=i; + for (i=0; rd[i].fileName[0]; i++)if (strncmp(rd[i].fileName, "IOPBTCONF", 9)==0)iIOPBTCONF=i; + + for (i=0; rd[i].fileName[0]; i++)if (rd[i].fileName[0]=='-')break; iBLANK=i; + rd[iBLANK].fileSize-=DIRENTRY_SIZE+DIRENTRY_SIZE; + p=(char*)PS2MEM_ROM;for (i=0; iq){*((u64*)p)=*((u64*)p-4);*((u64*)p+1)=*((u64*)p-3);p-=DIRENTRY_SIZE;} + *((u64*)p)=*((u64*)p+1)=0;p-=DIRENTRY_SIZE;rd[iIOPBTCONF].fileSize+=DIRENTRY_SIZE; + + q=(char*)PS2MEM_ROM;for (i=0; i<=iROMDIR; i++) q+=(rd[i].fileSize+0xF)&(~0xF); + while (p >q){*((u64*)p)=*((u64*)p-2);*((u64*)p+1)=*((u64*)p-1);p-=DIRENTRY_SIZE;} + *((u64*)p)=*((u64*)p+1)=0;p-=DIRENTRY_SIZE;rd[iROMDIR].fileSize+=DIRENTRY_SIZE; + + //phase 3: add the name to the end of IOPBTCONF + p=(char*)PS2MEM_ROM;for (i=0; i -#include -#endif - -#undef _ -#define _(String) dgettext (PACKAGE, String) -#ifdef gettext_noop -# define N_(String) gettext_noop (String) -#else -# define N_(String) (String) -#endif - -#else - -#define _(msgid) msgid -#define N_(msgid) msgid - -#endif // ENABLE_NLS - -// [TODO] : Move the config options mess from Misc.h into "config.h" or someting more sensible. - -///////////////////////////////////////////////////////////////////////// -// Session Configuration Override Flags -// -// a handful of flags that can override user configurations for the current application session -// only. This allows us to do things like force-disable recompilers if the memory allocations -// for them fail. -struct SessionOverrideFlags -{ - bool ForceDisableEErec:1; - bool ForceDisableVU0rec:1; - bool ForceDisableVU1rec:1; -}; - -extern SessionOverrideFlags g_Session; - -////////////////////////////////////////////////////////////////////////// -// Pcsx2 User Configuration Options! - -//#define PCSX2_MICROVU // Use Micro VU recs instead of Zero VU Recs -#define PCSX2_GSMULTITHREAD 1 // uses multi-threaded gs -#define PCSX2_EEREC 0x10 -#define PCSX2_VU0REC 0x20 -#define PCSX2_VU1REC 0x40 -#define PCSX2_FRAMELIMIT_MASK 0xc00 -#define PCSX2_FRAMELIMIT_NORMAL 0x000 -#define PCSX2_FRAMELIMIT_LIMIT 0x400 -#define PCSX2_FRAMELIMIT_SKIP 0x800 -#define PCSX2_FRAMELIMIT_VUSKIP 0xc00 - -#define CHECK_MULTIGS (Config.Options&PCSX2_GSMULTITHREAD) -#define CHECK_EEREC (!g_Session.ForceDisableEErec && Config.Options&PCSX2_EEREC) -//------------ SPEED/MISC HACKS!!! --------------- -#define CHECK_EE_CYCLERATE (Config.Hacks & 0x03) -#define CHECK_IOP_CYCLERATE (Config.Hacks & (1<<3)) -#define CHECK_WAITCYCLE_HACK (Config.Hacks & (1<<4)) -#define CHECK_ESCAPE_HACK (Config.Hacks & 0x400) -//------------ SPECIAL GAME FIXES!!! --------------- -#define CHECK_VUADDSUBHACK (Config.GameFixes & 0x1) // Special Fix for Tri-ace games, they use an encryption algorithm that requires VU addi opcode to be bit-accurate. -#define CHECK_FPUCLAMPHACK (Config.GameFixes & 0x4) // Special Fix for Tekken 5, different clamping for FPU (sets NaN to zero; doesn't clamp infinities) -#define CHECK_VUBRANCHHACK (Config.GameFixes & 0x8) // Special Fix for Magna Carta (note: Breaks Crash Bandicoot) -//------------ Advanced Options!!! --------------- -#define CHECK_VU_OVERFLOW (Config.vuOptions & 0x1) -#define CHECK_VU_EXTRA_OVERFLOW (Config.vuOptions & 0x2) // If enabled, Operands are clamped before being used in the VU recs -#define CHECK_VU_SIGN_OVERFLOW (Config.vuOptions & 0x4) -#define CHECK_VU_UNDERFLOW (Config.vuOptions & 0x8) -#define CHECK_VU_EXTRA_FLAGS 0 // Always disabled now // Sets correct flags in the VU recs -#define CHECK_FPU_OVERFLOW (Config.eeOptions & 0x1) -#define CHECK_FPU_EXTRA_OVERFLOW (Config.eeOptions & 0x2) // If enabled, Operands are checked for infinities before being used in the FPU recs -#define CHECK_FPU_EXTRA_FLAGS 1 // Always enabled now // Sets D/I flags on FPU instructions -#define DEFAULT_eeOptions 0x01 -#define DEFAULT_vuOptions 0x01 -//------------ DEFAULT sseMXCSR VALUES!!! --------------- -#define DEFAULT_sseMXCSR 0xffc0 //FPU rounding, DaZ, FtZ, "chop" -#define DEFAULT_sseVUMXCSR 0x7f80 //VU rounding, "chop" - -#define CHECK_FRAMELIMIT (Config.Options&PCSX2_FRAMELIMIT_MASK) - -#define CHECK_VU0REC (!g_Session.ForceDisableVU0rec && Config.Options&PCSX2_VU0REC) -#define CHECK_VU1REC (!g_Session.ForceDisableVU1rec && (Config.Options&PCSX2_VU1REC)) - - -struct PcsxConfig -{ - char Bios[g_MaxPath]; - char GS[g_MaxPath]; - char PAD1[g_MaxPath]; - char PAD2[g_MaxPath]; - char SPU2[g_MaxPath]; - char CDVD[g_MaxPath]; - char DEV9[g_MaxPath]; - char USB[g_MaxPath]; - char FW[g_MaxPath]; - char Mcd1[g_MaxPath]; - char Mcd2[g_MaxPath]; - char PluginsDir[g_MaxPath]; - char BiosDir[g_MaxPath]; - char Lang[g_MaxPath]; - - u32 Options; // PCSX2_X options - - bool PsxOut; - bool Profiler; // Displays profiling info to console - bool cdvdPrint; // Prints cdvd reads to console - bool closeGSonEsc; // closes the GS (and saves its state) on escape automatically. - - int PsxType; - int Cdda; - int Mdec; - int Patch; - int ThPriority; - int CustomFps; - int Hacks; - int GameFixes; - int CustomFrameSkip; - int CustomConsecutiveFrames; - int CustomConsecutiveSkip; - u32 sseMXCSR; - u32 sseVUMXCSR; - u32 eeOptions; - u32 vuOptions; -}; - -extern PcsxConfig Config; -extern u32 BiosVersion; -extern char CdromId[12]; -extern uptr pDsp; // what the hell is this unused piece of crap passed to every plugin for? (air) - -int LoadCdrom(); -int CheckCdrom(); -int GetPS2ElfName(char*); - -extern const char *LabelAuthors; -extern const char *LabelGreets; - -void SaveGSState(const string& file); -void LoadGSState(const string& file); - -char *ParseLang(char *id); -void ProcessFKeys(int fkey, int shift); // processes fkey related commands value 1-12 - -#define DIRENTRY_SIZE 16 - -#if defined(_MSC_VER) -#pragma pack(1) -#endif - -struct romdir{ - char fileName[10]; - u16 extInfoSize; - u32 fileSize; -#if defined(_MSC_VER) -}; //+22 -#else -} __attribute__((packed)); -#endif - -u32 GetBiosVersion(); -int IsBIOS(char *filename, char *description); - -extern u32 g_sseVUMXCSR, g_sseMXCSR; - -void SetCPUState(u32 sseMXCSR, u32 sseVUMXCSR); - -// when using mmx/xmm regs, use; 0 is load -// freezes no matter the state -extern void FreezeXMMRegs_(int save); -extern void FreezeMMXRegs_(int save); -extern bool g_EEFreezeRegs; -extern u8 g_globalMMXSaved; -extern u8 g_globalXMMSaved; - -// these macros check to see if needs freezing -#define FreezeXMMRegs(save) if( g_EEFreezeRegs ) { FreezeXMMRegs_(save); } -#define FreezeMMXRegs(save) if( g_EEFreezeRegs ) { FreezeMMXRegs_(save); } - -#ifdef _MSC_VER -#pragma pack() -#endif - -void injectIRX(const char *filename); - -extern void InitCPUTicks(); -extern u64 GetTickFrequency(); -extern u64 GetCPUTicks(); - - -#endif /* __MISC_H__ */ - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __MISC_H__ +#define __MISC_H__ + +#include "System.h" + +///////////////////////////////////////////////////////////////////////// +// GNU GetText / NLS + +#ifdef ENABLE_NLS + +#ifdef _WIN32 +#include "libintlmsc.h" +#else +#include +#include +#endif + +#undef _ +#define _(String) dgettext (PACKAGE, String) +#ifdef gettext_noop +# define N_(String) gettext_noop (String) +#else +# define N_(String) (String) +#endif + +#else + +#define _(msgid) msgid +#define N_(msgid) msgid + +#endif // ENABLE_NLS + +// [TODO] : Move the config options mess from Misc.h into "config.h" or someting more sensible. + +///////////////////////////////////////////////////////////////////////// +// Session Configuration Override Flags +// +// a handful of flags that can override user configurations for the current application session +// only. This allows us to do things like force-disable recompilers if the memory allocations +// for them fail. +struct SessionOverrideFlags +{ + bool ForceDisableEErec:1; + bool ForceDisableVU0rec:1; + bool ForceDisableVU1rec:1; +}; + +extern SessionOverrideFlags g_Session; + +////////////////////////////////////////////////////////////////////////// +// Pcsx2 User Configuration Options! + +//#define PCSX2_MICROVU // Use Micro VU recs instead of Zero VU Recs +#define PCSX2_GSMULTITHREAD 1 // uses multi-threaded gs +#define PCSX2_EEREC 0x10 +#define PCSX2_VU0REC 0x20 +#define PCSX2_VU1REC 0x40 +#define PCSX2_FRAMELIMIT_MASK 0xc00 +#define PCSX2_FRAMELIMIT_NORMAL 0x000 +#define PCSX2_FRAMELIMIT_LIMIT 0x400 +#define PCSX2_FRAMELIMIT_SKIP 0x800 +#define PCSX2_FRAMELIMIT_VUSKIP 0xc00 + +#define CHECK_MULTIGS (Config.Options&PCSX2_GSMULTITHREAD) +#define CHECK_EEREC (!g_Session.ForceDisableEErec && Config.Options&PCSX2_EEREC) +//------------ SPEED/MISC HACKS!!! --------------- +#define CHECK_EE_CYCLERATE (Config.Hacks & 0x03) +#define CHECK_IOP_CYCLERATE (Config.Hacks & (1<<3)) +#define CHECK_WAITCYCLE_HACK (Config.Hacks & (1<<4)) +#define CHECK_ESCAPE_HACK (Config.Hacks & 0x400) +//------------ SPECIAL GAME FIXES!!! --------------- +#define CHECK_VUADDSUBHACK (Config.GameFixes & 0x1) // Special Fix for Tri-ace games, they use an encryption algorithm that requires VU addi opcode to be bit-accurate. +#define CHECK_FPUCLAMPHACK (Config.GameFixes & 0x4) // Special Fix for Tekken 5, different clamping for FPU (sets NaN to zero; doesn't clamp infinities) +#define CHECK_VUBRANCHHACK (Config.GameFixes & 0x8) // Special Fix for Magna Carta (note: Breaks Crash Bandicoot) +//------------ Advanced Options!!! --------------- +#define CHECK_VU_OVERFLOW (Config.vuOptions & 0x1) +#define CHECK_VU_EXTRA_OVERFLOW (Config.vuOptions & 0x2) // If enabled, Operands are clamped before being used in the VU recs +#define CHECK_VU_SIGN_OVERFLOW (Config.vuOptions & 0x4) +#define CHECK_VU_UNDERFLOW (Config.vuOptions & 0x8) +#define CHECK_VU_EXTRA_FLAGS 0 // Always disabled now // Sets correct flags in the VU recs +#define CHECK_FPU_OVERFLOW (Config.eeOptions & 0x1) +#define CHECK_FPU_EXTRA_OVERFLOW (Config.eeOptions & 0x2) // If enabled, Operands are checked for infinities before being used in the FPU recs +#define CHECK_FPU_EXTRA_FLAGS 1 // Always enabled now // Sets D/I flags on FPU instructions +#define DEFAULT_eeOptions 0x01 +#define DEFAULT_vuOptions 0x01 +//------------ DEFAULT sseMXCSR VALUES!!! --------------- +#define DEFAULT_sseMXCSR 0xffc0 //FPU rounding, DaZ, FtZ, "chop" +#define DEFAULT_sseVUMXCSR 0x7f80 //VU rounding, "chop" + +#define CHECK_FRAMELIMIT (Config.Options&PCSX2_FRAMELIMIT_MASK) + +#define CHECK_VU0REC (!g_Session.ForceDisableVU0rec && Config.Options&PCSX2_VU0REC) +#define CHECK_VU1REC (!g_Session.ForceDisableVU1rec && (Config.Options&PCSX2_VU1REC)) + + +struct PcsxConfig +{ + char Bios[g_MaxPath]; + char GS[g_MaxPath]; + char PAD1[g_MaxPath]; + char PAD2[g_MaxPath]; + char SPU2[g_MaxPath]; + char CDVD[g_MaxPath]; + char DEV9[g_MaxPath]; + char USB[g_MaxPath]; + char FW[g_MaxPath]; + char Mcd1[g_MaxPath]; + char Mcd2[g_MaxPath]; + char PluginsDir[g_MaxPath]; + char BiosDir[g_MaxPath]; + char Lang[g_MaxPath]; + + u32 Options; // PCSX2_X options + + bool PsxOut; + bool Profiler; // Displays profiling info to console + bool cdvdPrint; // Prints cdvd reads to console + bool closeGSonEsc; // closes the GS (and saves its state) on escape automatically. + + int PsxType; + int Cdda; + int Mdec; + int Patch; + int ThPriority; + int CustomFps; + int Hacks; + int GameFixes; + int CustomFrameSkip; + int CustomConsecutiveFrames; + int CustomConsecutiveSkip; + u32 sseMXCSR; + u32 sseVUMXCSR; + u32 eeOptions; + u32 vuOptions; +}; + +extern PcsxConfig Config; +extern u32 BiosVersion; +extern char CdromId[12]; +extern uptr pDsp; // what the hell is this unused piece of crap passed to every plugin for? (air) + +int LoadCdrom(); +int CheckCdrom(); +int GetPS2ElfName(char*); + +extern const char *LabelAuthors; +extern const char *LabelGreets; + +void SaveGSState(const string& file); +void LoadGSState(const string& file); + +char *ParseLang(char *id); +void ProcessFKeys(int fkey, int shift); // processes fkey related commands value 1-12 + +#define DIRENTRY_SIZE 16 + +#if defined(_MSC_VER) +#pragma pack(1) +#endif + +struct romdir{ + char fileName[10]; + u16 extInfoSize; + u32 fileSize; +#if defined(_MSC_VER) +}; //+22 +#else +} __attribute__((packed)); +#endif + +u32 GetBiosVersion(); +int IsBIOS(char *filename, char *description); + +extern u32 g_sseVUMXCSR, g_sseMXCSR; + +void SetCPUState(u32 sseMXCSR, u32 sseVUMXCSR); + +// when using mmx/xmm regs, use; 0 is load +// freezes no matter the state +extern void FreezeXMMRegs_(int save); +extern void FreezeMMXRegs_(int save); +extern bool g_EEFreezeRegs; +extern u8 g_globalMMXSaved; +extern u8 g_globalXMMSaved; + +// these macros check to see if needs freezing +#define FreezeXMMRegs(save) if( g_EEFreezeRegs ) { FreezeXMMRegs_(save); } +#define FreezeMMXRegs(save) if( g_EEFreezeRegs ) { FreezeMMXRegs_(save); } + +#ifdef _MSC_VER +#pragma pack() +#endif + +void injectIRX(const char *filename); + +extern void InitCPUTicks(); +extern u64 GetTickFrequency(); +extern u64 GetCPUTicks(); + + +#endif /* __MISC_H__ */ + diff --git a/pcsx2/Patch.cpp b/pcsx2/Patch.cpp index b7527fa9e0..9228e64672 100644 --- a/pcsx2/Patch.cpp +++ b/pcsx2/Patch.cpp @@ -1,642 +1,642 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -// -// Includes -// -#include "PrecompiledHeader.h" - -#include "PsxCommon.h" -#include "Paths.h" -#include "Patch.h" -#include "VU.h" - -#ifdef _WIN32 -#include "windows/cheats/cheats.h" -#else -#include -#include -#endif - -#ifdef _MSC_VER -#pragma warning(disable:4996) //ignore the stricmp deprecated warning -#endif - -IniPatch patch[ MAX_PATCH ]; - -u32 SkipCount=0; -u32 IterationCount=0; -u32 IterationIncrement=0; -u32 ValueIncrement=0; -u32 PrevCheatType=0; -u32 PrevCheataddr = 0; -u32 LastType = 0; - -int g_ZeroGSOptions=0; -int patchnumber; - -char strgametitle[256]= {0}; - -// -// Variables -// -PatchTextTable commands[] = -{ - { "comment", 1, patchFunc_comment }, - { "gametitle", 2, patchFunc_gametitle }, - { "patch", 3, patchFunc_patch }, - { "fastmemory", 4, patchFunc_fastmemory }, // enable for faster but bugger mem (mvc2 is faster) - { "roundmode", 5, patchFunc_roundmode }, // changes rounding mode for floating point - // syntax: roundmode=X,Y - // possible values for X,Y: NEAR, DOWN, UP, CHOP - // X - EE rounding mode (default is NEAR) - // Y - VU rounding mode (default is CHOP) - { "zerogs", 6, patchFunc_zerogs }, // zerogs=hex - { "path3hack", 7, patchFunc_path3hack }, - { "vunanmode",8, patchFunc_vunanmode }, - { "ffxhack",9, patchFunc_ffxhack}, - { "xkickdelay",10, patchFunc_xkickdelay}, - { "", 0, NULL } -}; - -PatchTextTable dataType[] = -{ - { "byte", 1, NULL }, - { "short", 2, NULL }, - { "word", 3, NULL }, - { "double", 4, NULL }, - { "extended", 5, NULL }, - { "", 0, NULL } -}; - -PatchTextTable cpuCore[] = -{ - { "EE", 1, NULL }, - { "IOP", 2, NULL }, - { "", 0, NULL } -}; - -// -// Function Implementations -// - -int PatchTableExecute( char * text1, char * text2, PatchTextTable * Table ) -{ - int i = 0; - - while ( Table[ i ].text[ 0 ] ) - { - if ( !strcmp( Table[ i ].text, text1 ) ) - { - if ( Table[ i ].func ) - { - Table[ i ].func( text1, text2 ); - } - break; - } - i++; - } - - return Table[ i ].code; -} - -void _applypatch(int place, IniPatch *p) { - u8 u8Val=0; - u16 u16Val=0; - u32 u32Val=0; - u32 i; - - if (p->placetopatch != place) return; - if (p->enabled == 0) return; - - switch (p->cpu) { - case CPU_EE: - switch (p->type) { - case BYTE_T: - memWrite8(p->addr, (u8)p->data); - break; - case SHORT_T: - memWrite16(p->addr, (u16)p->data); - break; - case WORD_T: - memWrite32(p->addr, (u32)p->data); - break; - case DOUBLE_T: - memWrite64(p->addr, &p->data); - break; - case EXTENDED_T: - if (SkipCount > 0){ - SkipCount--; - } - else switch (PrevCheatType) { - case 0x3040: // vvvvvvvv 00000000 Inc - memRead32(PrevCheataddr,&u32Val); - memWrite32(PrevCheataddr, u32Val+(p->addr)); - PrevCheatType = 0; - break; - case 0x3050: // vvvvvvvv 00000000 Dec - memRead32(PrevCheataddr,&u32Val); - memWrite32(PrevCheataddr, u32Val-(p->addr)); - PrevCheatType = 0; - break; - case 0x4000: // vvvvvvvv iiiiiiii - for(i=0;iaddr+((u32)p->data*i))); - PrevCheatType = 0; - break; - case 0x5000: // dddddddd iiiiiiii - for(i=0;idata)+i,u8Val); - } - PrevCheatType = 0; - break; - case 0x6000: // 000Xnnnn iiiiiiii - // Get Number of pointers - if (IterationCount == 0) - IterationCount = (u32)p->addr&0x0000FFFF; - - // Read first pointer - LastType = ((u32)p->addr&0x000F0000)/0x10000; - memRead32(PrevCheataddr,&u32Val); - PrevCheataddr = u32Val+(u32)p->data; - IterationCount--; - - // Check if needed to read another pointer - if (IterationCount == 0){ - PrevCheatType = 0; - if (LastType==0x0) - memWrite8(PrevCheataddr,IterationIncrement&0xFF); - if (LastType==0x1) - memWrite16(PrevCheataddr,IterationIncrement&0xFFFF); - if (LastType==0x2) - memWrite32(PrevCheataddr,IterationIncrement); - } - else - PrevCheatType = 0x6001; - case 0x6001: // 000Xnnnn iiiiiiii - // Read first pointer - memRead32(PrevCheataddr,&u32Val); - PrevCheataddr =u32Val+(u32)p->addr; - IterationCount--; - - // Check if needed to read another pointer - if (IterationCount == 0){ - PrevCheatType = 0; - if (LastType==0x0) - memWrite8(PrevCheataddr,IterationIncrement&0xFF); - if (LastType==0x1) - memWrite16(PrevCheataddr,IterationIncrement&0xFFFF); - if (LastType==0x2) - memWrite32(PrevCheataddr,IterationIncrement); - } - else - { - memRead32(PrevCheataddr,&u32Val); - PrevCheataddr =u32Val+(u32)p->data; - IterationCount--; - if (IterationCount == 0){ - PrevCheatType = 0; - if (LastType==0x0) - memWrite8(PrevCheataddr,IterationIncrement&0xFF); - if (LastType==0x1) - memWrite16(PrevCheataddr,IterationIncrement&0xFFFF); - if (LastType==0x2) - memWrite32(PrevCheataddr,IterationIncrement); - } - } - default: - if ((p->addr&0xF0000000) == 0x00000000){ // 0aaaaaaa 0000000vv - memWrite8(p->addr&0x0FFFFFFF, (u8)p->data&0x000000FF); - PrevCheatType = 0; - } - else if ((p->addr&0xF0000000) == 0x10000000){ // 0aaaaaaa 0000vvvv - memWrite16(p->addr&0x0FFFFFFF, (u16)p->data&0x0000FFFF); - PrevCheatType = 0; - } - else if ((p->addr&0xF0000000) == 0x20000000){ // 0aaaaaaa vvvvvvvv - memWrite32(p->addr&0x0FFFFFFF, (u32)p->data); - PrevCheatType = 0; - } - else if ((p->addr&0xFFFF0000) == 0x30000000){ // 300000vv 0aaaaaaa Inc - memRead8((u32)p->data,&u8Val); - memWrite8((u32)p->data, u8Val+(p->addr&0x000000FF)); - PrevCheatType = 0; - } - else if ((p->addr&0xFFFF0000) == 0x30100000){ // 301000vv 0aaaaaaa Dec - memRead8((u32)p->data,&u8Val); - memWrite8((u32)p->data, u8Val-(p->addr&0x000000FF)); - PrevCheatType = 0; - } - else if ((p->addr&0xFFFF0000) == 0x30200000){ // 3020vvvv 0aaaaaaa Inc - memRead16((u32)p->data,&u16Val); - memWrite16((u32)p->data, u16Val+(p->addr&0x0000FFFF)); - PrevCheatType = 0; - } - else if ((p->addr&0xFFFF0000) == 0x30300000){ // 3030vvvv 0aaaaaaa Dec - memRead16((u32)p->data,&u16Val); - memWrite16((u32)p->data, u16Val-(p->addr&0x0000FFFF)); - PrevCheatType = 0; - } - else if ((p->addr&0xFFFF0000) == 0x30400000){ // 30400000 0aaaaaaa Inc + Another line - PrevCheatType= 0x3040; - PrevCheataddr= (u32)p->data; - } - else if ((p->addr&0xFFFF0000) == 0x30500000){ // 30500000 0aaaaaaa Inc + Another line - PrevCheatType= 0x3050; - PrevCheataddr= (u32)p->data; - } - else if ((p->addr&0xF0000000) == 0x40000000){ // 4aaaaaaa nnnnssss + Another line - IterationCount=((u32)p->data&0xFFFF0000)/0x10000; - IterationIncrement=((u32)p->data&0x0000FFFF)*4; - PrevCheataddr=(u32)p->addr&0x0FFFFFFF; - PrevCheatType= 0x4000; - } - else if ((p->addr&0xF0000000) == 0x50000000){ // 5sssssss nnnnnnnn + Another line - PrevCheataddr = (u32)p->addr&0x0FFFFFFF; - IterationCount=((u32)p->data); - PrevCheatType= 0x5000; - } - else if ((p->addr&0xF0000000) == 0x60000000){ // 6aaaaaaa 000000vv + Another line/s - PrevCheataddr = (u32)p->addr&0x0FFFFFFF; - IterationIncrement=((u32)p->data); - IterationCount=0; - PrevCheatType= 0x6000; - } - else if ((p->addr&0xF0000000) == 0x70000000) { - if ((p->data&0x00F00000) == 0x00000000){ // 7aaaaaaa 000000vv - memRead8((u32)p->addr&0x0FFFFFFF,&u8Val); - memWrite8((u32)p->addr&0x0FFFFFFF,(u8)(u8Val|(p->data&0x000000FF))); - }else if ((p->data&0x00F00000) == 0x00100000){ // 7aaaaaaa 0010vvvv - memRead16((u32)p->addr&0x0FFFFFFF,&u16Val); - memWrite16((u32)p->addr&0x0FFFFFFF,(u16)(u16Val|(p->data&0x0000FFFF))); - }else if ((p->data&0x00F00000) == 0x00200000){ // 7aaaaaaa 002000vv - memRead8((u32)p->addr&0x0FFFFFFF,&u8Val); - memWrite8((u32)p->addr&0x0FFFFFFF,(u8)(u8Val&(p->data&0x000000FF))); - }else if ((p->data&0x00F00000) == 0x00300000){ // 7aaaaaaa 0030vvvv - memRead16((u32)p->addr&0x0FFFFFFF,&u16Val); - memWrite16((u32)p->addr&0x0FFFFFFF,(u16)(u16Val&(p->data&0x0000FFFF))); - }else if ((p->data&0x00F00000) == 0x00400000){ // 7aaaaaaa 004000vv - memRead8((u32)p->addr&0x0FFFFFFF,&u8Val); - memWrite8((u32)p->addr&0x0FFFFFFF,(u8)(u8Val^(p->data&0x000000FF))); - }else if ((p->data&0x00F00000) == 0x00500000){ // 7aaaaaaa 0050vvvv - memRead16((u32)p->addr&0x0FFFFFFF,&u16Val); - memWrite16((u32)p->addr&0x0FFFFFFF,(u16)(u16Val^(p->data&0x0000FFFF))); - } - } - else if (p->addr < 0xE0000000) { - if ((((u32)p->data & 0xFFFF0000)==0x00000000) || - (((u32)p->data & 0xFFFF0000)==0x00100000) || - (((u32)p->data & 0xFFFF0000)==0x00200000) || - (((u32)p->data & 0xFFFF0000)==0x00300000)) { - memRead16((u32)p->addr&0x0FFFFFFF,&u16Val); - if (u16Val != (0x0000FFFF&(u32)p->data)) - SkipCount = 1; - PrevCheatType= 0; - } - } - else if (p->addr < 0xF0000000) { - if ((((u32)p->data&0xF0000000)==0x00000000) || - (((u32)p->data&0xF0000000)==0x10000000) || - (((u32)p->data&0xF0000000)==0x20000000) || - (((u32)p->data&0xF0000000)==0x30000000)) { - memRead16((u32)p->data&0x0FFFFFFF,&u16Val); - if (u16Val != (0x0000FFFF&(u32)p->addr)) - SkipCount = ((u32)p->addr&0xFFF0000)/0x10000; - PrevCheatType= 0; - } - } - } - } - break; - case CPU_IOP: { - switch (p->type) { - case BYTE_T: - psxMemWrite8(p->addr, (u8)p->data); - break; - case SHORT_T: - psxMemWrite16(p->addr, (u16)p->data); - break; - case WORD_T: - psxMemWrite32(p->addr, (u32)p->data); - break; - } - } - } -} - - -//this is for apply patches directly to memory -void applypatch(int place) { - int i; - - if (place == 0) { - Console::WriteLn(" patchnumber: %d", params patchnumber); - } - - for ( i = 0; i < patchnumber; i++ ) { - _applypatch(place, &patch[i]); - } -} - -void patchFunc_comment( char * text1, char * text2 ) -{ - Console::WriteLn( "comment: %s", params text2 ); -} - - -void patchFunc_gametitle( char * text1, char * text2 ) -{ - Console::WriteLn( "gametitle: %s", params text2 ); - sprintf(strgametitle,"%s",text2); - Console::SetTitle(strgametitle); -} - -void patchFunc_patch( char * cmd, char * param ) -{ - char * pText; - - if ( patchnumber >= MAX_PATCH ) - { - Console::Error( "Patch ERROR: Maximum number of patches reached: %s=%s", params cmd, param ); - return; - } - - pText = strtok( param, "," ); - pText = param; - - patch[ patchnumber ].placetopatch = strtol( pText, (char **)NULL, 0 ); - - pText = strtok( NULL, "," ); - inifile_trim( pText ); - patch[ patchnumber ].cpu = (patch_cpu_type)PatchTableExecute( pText, NULL, cpuCore ); - if ( patch[ patchnumber ].cpu == 0 ) - { - Console::Error( "Unrecognized patch '%s'", params pText ); - return; - } - - pText = strtok( NULL, "," ); - inifile_trim( pText ); - sscanf( pText, "%X", &patch[ patchnumber ].addr ); - - pText = strtok( NULL, "," ); - inifile_trim( pText ); - patch[ patchnumber ].type = (patch_data_type)PatchTableExecute( pText, NULL, dataType ); - if ( patch[ patchnumber ].type == 0 ) - { - Console::Error( "Unrecognized patch '%s'", params pText ); - return; - } - - pText = strtok( NULL, "," ); - inifile_trim( pText ); - sscanf( pText, "%I64X", &patch[ patchnumber ].data ); - - patch[ patchnumber ].enabled = 1; - - patchnumber++; -} - -//this routine is for executing the commands of the ini file -void inifile_command( char * cmd ) -{ - int code; - char command[ 256 ]; - char parameter[ 256 ]; - - // extract param part (after '=') - char * pEqual = strchr( cmd, '=' ); - - if ( ! pEqual ) - { - // fastmemory doesn't have = - pEqual = cmd+strlen(cmd); - } - - memzero_obj( command ); - memzero_obj( parameter ); - - strncpy( command, cmd, pEqual - cmd ); - strncpy( parameter, pEqual + 1, sizeof( parameter ) ); - - inifile_trim( command ); - inifile_trim( parameter ); - - code = PatchTableExecute( command, parameter, commands ); -} - -void inifile_trim( char * buffer ) -{ - char * pInit = buffer; - char * pEnd = NULL; - - while ( ( *pInit == ' ' ) || ( *pInit == '\t' ) ) //skip space - { - pInit++; - } - if ( ( pInit[ 0 ] == '/' ) && ( pInit[ 1 ] == '/' ) ) //remove comment - { - buffer[ 0 ] = '\0'; - return; - } - pEnd = pInit + strlen( pInit ) - 1; - if ( pEnd <= pInit ) - { - buffer[ 0 ] = '\0'; - return; - } - while ( ( *pEnd == '\r' ) || ( *pEnd == '\n' ) || - ( *pEnd == ' ' ) || ( *pEnd == '\t' ) ) - { - pEnd--; - } - if ( pEnd <= pInit ) - { - buffer[ 0 ] = '\0'; - return; - } - memmove( buffer, pInit, pEnd - pInit + 1 ); - buffer[ pEnd - pInit + 1 ] = '\0'; -} - -void inisection_process( FILE * f1 ) -{ - char buffer[ 1024 ]; - while( fgets( buffer, sizeof( buffer ), f1 ) ) - { - inifile_trim( buffer ); - if ( buffer[ 0 ] ) - { - inifile_command( buffer ); - } - } -} - -//this routine is for reading the ini file - -void inifile_read( const char * name ) -{ - FILE * f1; - char buffer[ 1024 ]; - - patchnumber = 0; -#ifdef _WIN32 - sprintf( buffer, PATCHES_DIR "\\%s.pnach", name ); -#else - sprintf( buffer, PATCHES_DIR "/%s.pnach", name ); -#endif - - f1 = fopen( buffer, "rt" ); - -#ifndef _WIN32 - if( !f1 ) { - // try all upper case because linux is case sensitive - char* pstart = buffer+8; - char* pend = buffer+strlen(buffer); - while(pstart != pend ) { - // stop at the first . since we only want to update the hex - if( *pstart == '.' ) - break; - *pstart++ = toupper(*pstart); - } - - f1 = fopen(buffer, "rt"); - } -#endif - - if( !f1 ) - { - Console::WriteLn( _( "No patch found.Resuming execution without a patch (this is NOT an error)." )); - return; - } - - inisection_process( f1 ); - - fclose( f1 ); -} - -void resetpatch( void ) -{ - patchnumber = 0; -} - -int AddPatch(int Mode, int Place, int Address, int Size, u64 data) -{ - - if ( patchnumber >= MAX_PATCH ) - { - Console::Error( "Patch ERROR: Maximum number of patches reached."); - return -1; - } - - patch[patchnumber].placetopatch = Mode; - - patch[patchnumber].cpu = (patch_cpu_type)Place; - patch[patchnumber].addr=Address; - patch[patchnumber].type=(patch_data_type)Size; - patch[patchnumber].data = data; - return patchnumber++; -} - -void patchFunc_ffxhack( char * cmd, char * param ) -{ - g_FFXHack = 1; -} - -void patchFunc_xkickdelay( char * cmd, char * param ) -{ - g_VUGameFixes |= VUFIX_XGKICKDELAY2; -} - -void patchFunc_fastmemory( char * cmd, char * param ) -{ - // only valid for recompilers - SetFastMemory(1); -} - - -void patchFunc_vunanmode( char * cmd, char * param ) -{ - // only valid for recompilers - SetVUNanMode(param != NULL ? atoi(param) : 1); -} - -void patchFunc_path3hack( char * cmd, char * param ) -{ - path3hack = 1; -} - -void patchFunc_roundmode( char * cmd, char * param ) -{ - int index; - char * pText; - - u32 eetype = (Config.sseMXCSR & 0x6000); - u32 vutype = (Config.sseVUMXCSR & 0x6000); - - index = 0; - pText = strtok( param, ", " ); - while(pText != NULL) { - u32 type = 0xffff; - - if( stricmp(pText, "near") == 0 ) { - type = 0x0000; - } - else if( stricmp(pText, "down") == 0 ) { - type = 0x2000; - } - else if( stricmp(pText, "up") == 0 ) { - type = 0x4000; - } - else if( stricmp(pText, "chop") == 0 ) { - type = 0x6000; - } - - if( type == 0xffff ) { - printf("bad argument (%s) to round mode! skipping...\n", pText); - break; - } - - if( index == 0 ) - eetype=type; - else - vutype=type; - - if( index == 1 ) - break; - - index++; - pText = strtok(NULL, ", "); - } - - SetRoundMode(eetype,vutype); -} - -void patchFunc_zerogs(char* cmd, char* param) -{ - sscanf(param, "%x", &g_ZeroGSOptions); -} - -void SetRoundMode(u32 ee, u32 vu) -{ - // don't set a state for interpreter only - //Msgbox::Alert("SetRoundMode: Config.sseMXCSR = %x; Config.sseVUMXCSR = %x \n", Config.sseMXCSR, Config.sseVUMXCSR); - - SetCPUState( (Config.sseMXCSR & 0x9fff) | ee, (Config.sseVUMXCSR & 0x9fff) | vu); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +// +// Includes +// +#include "PrecompiledHeader.h" + +#include "PsxCommon.h" +#include "Paths.h" +#include "Patch.h" +#include "VU.h" + +#ifdef _WIN32 +#include "windows/cheats/cheats.h" +#else +#include +#include +#endif + +#ifdef _MSC_VER +#pragma warning(disable:4996) //ignore the stricmp deprecated warning +#endif + +IniPatch patch[ MAX_PATCH ]; + +u32 SkipCount=0; +u32 IterationCount=0; +u32 IterationIncrement=0; +u32 ValueIncrement=0; +u32 PrevCheatType=0; +u32 PrevCheataddr = 0; +u32 LastType = 0; + +int g_ZeroGSOptions=0; +int patchnumber; + +char strgametitle[256]= {0}; + +// +// Variables +// +PatchTextTable commands[] = +{ + { "comment", 1, patchFunc_comment }, + { "gametitle", 2, patchFunc_gametitle }, + { "patch", 3, patchFunc_patch }, + { "fastmemory", 4, patchFunc_fastmemory }, // enable for faster but bugger mem (mvc2 is faster) + { "roundmode", 5, patchFunc_roundmode }, // changes rounding mode for floating point + // syntax: roundmode=X,Y + // possible values for X,Y: NEAR, DOWN, UP, CHOP + // X - EE rounding mode (default is NEAR) + // Y - VU rounding mode (default is CHOP) + { "zerogs", 6, patchFunc_zerogs }, // zerogs=hex + { "path3hack", 7, patchFunc_path3hack }, + { "vunanmode",8, patchFunc_vunanmode }, + { "ffxhack",9, patchFunc_ffxhack}, + { "xkickdelay",10, patchFunc_xkickdelay}, + { "", 0, NULL } +}; + +PatchTextTable dataType[] = +{ + { "byte", 1, NULL }, + { "short", 2, NULL }, + { "word", 3, NULL }, + { "double", 4, NULL }, + { "extended", 5, NULL }, + { "", 0, NULL } +}; + +PatchTextTable cpuCore[] = +{ + { "EE", 1, NULL }, + { "IOP", 2, NULL }, + { "", 0, NULL } +}; + +// +// Function Implementations +// + +int PatchTableExecute( char * text1, char * text2, PatchTextTable * Table ) +{ + int i = 0; + + while ( Table[ i ].text[ 0 ] ) + { + if ( !strcmp( Table[ i ].text, text1 ) ) + { + if ( Table[ i ].func ) + { + Table[ i ].func( text1, text2 ); + } + break; + } + i++; + } + + return Table[ i ].code; +} + +void _applypatch(int place, IniPatch *p) { + u8 u8Val=0; + u16 u16Val=0; + u32 u32Val=0; + u32 i; + + if (p->placetopatch != place) return; + if (p->enabled == 0) return; + + switch (p->cpu) { + case CPU_EE: + switch (p->type) { + case BYTE_T: + memWrite8(p->addr, (u8)p->data); + break; + case SHORT_T: + memWrite16(p->addr, (u16)p->data); + break; + case WORD_T: + memWrite32(p->addr, (u32)p->data); + break; + case DOUBLE_T: + memWrite64(p->addr, &p->data); + break; + case EXTENDED_T: + if (SkipCount > 0){ + SkipCount--; + } + else switch (PrevCheatType) { + case 0x3040: // vvvvvvvv 00000000 Inc + memRead32(PrevCheataddr,&u32Val); + memWrite32(PrevCheataddr, u32Val+(p->addr)); + PrevCheatType = 0; + break; + case 0x3050: // vvvvvvvv 00000000 Dec + memRead32(PrevCheataddr,&u32Val); + memWrite32(PrevCheataddr, u32Val-(p->addr)); + PrevCheatType = 0; + break; + case 0x4000: // vvvvvvvv iiiiiiii + for(i=0;iaddr+((u32)p->data*i))); + PrevCheatType = 0; + break; + case 0x5000: // dddddddd iiiiiiii + for(i=0;idata)+i,u8Val); + } + PrevCheatType = 0; + break; + case 0x6000: // 000Xnnnn iiiiiiii + // Get Number of pointers + if (IterationCount == 0) + IterationCount = (u32)p->addr&0x0000FFFF; + + // Read first pointer + LastType = ((u32)p->addr&0x000F0000)/0x10000; + memRead32(PrevCheataddr,&u32Val); + PrevCheataddr = u32Val+(u32)p->data; + IterationCount--; + + // Check if needed to read another pointer + if (IterationCount == 0){ + PrevCheatType = 0; + if (LastType==0x0) + memWrite8(PrevCheataddr,IterationIncrement&0xFF); + if (LastType==0x1) + memWrite16(PrevCheataddr,IterationIncrement&0xFFFF); + if (LastType==0x2) + memWrite32(PrevCheataddr,IterationIncrement); + } + else + PrevCheatType = 0x6001; + case 0x6001: // 000Xnnnn iiiiiiii + // Read first pointer + memRead32(PrevCheataddr,&u32Val); + PrevCheataddr =u32Val+(u32)p->addr; + IterationCount--; + + // Check if needed to read another pointer + if (IterationCount == 0){ + PrevCheatType = 0; + if (LastType==0x0) + memWrite8(PrevCheataddr,IterationIncrement&0xFF); + if (LastType==0x1) + memWrite16(PrevCheataddr,IterationIncrement&0xFFFF); + if (LastType==0x2) + memWrite32(PrevCheataddr,IterationIncrement); + } + else + { + memRead32(PrevCheataddr,&u32Val); + PrevCheataddr =u32Val+(u32)p->data; + IterationCount--; + if (IterationCount == 0){ + PrevCheatType = 0; + if (LastType==0x0) + memWrite8(PrevCheataddr,IterationIncrement&0xFF); + if (LastType==0x1) + memWrite16(PrevCheataddr,IterationIncrement&0xFFFF); + if (LastType==0x2) + memWrite32(PrevCheataddr,IterationIncrement); + } + } + default: + if ((p->addr&0xF0000000) == 0x00000000){ // 0aaaaaaa 0000000vv + memWrite8(p->addr&0x0FFFFFFF, (u8)p->data&0x000000FF); + PrevCheatType = 0; + } + else if ((p->addr&0xF0000000) == 0x10000000){ // 0aaaaaaa 0000vvvv + memWrite16(p->addr&0x0FFFFFFF, (u16)p->data&0x0000FFFF); + PrevCheatType = 0; + } + else if ((p->addr&0xF0000000) == 0x20000000){ // 0aaaaaaa vvvvvvvv + memWrite32(p->addr&0x0FFFFFFF, (u32)p->data); + PrevCheatType = 0; + } + else if ((p->addr&0xFFFF0000) == 0x30000000){ // 300000vv 0aaaaaaa Inc + memRead8((u32)p->data,&u8Val); + memWrite8((u32)p->data, u8Val+(p->addr&0x000000FF)); + PrevCheatType = 0; + } + else if ((p->addr&0xFFFF0000) == 0x30100000){ // 301000vv 0aaaaaaa Dec + memRead8((u32)p->data,&u8Val); + memWrite8((u32)p->data, u8Val-(p->addr&0x000000FF)); + PrevCheatType = 0; + } + else if ((p->addr&0xFFFF0000) == 0x30200000){ // 3020vvvv 0aaaaaaa Inc + memRead16((u32)p->data,&u16Val); + memWrite16((u32)p->data, u16Val+(p->addr&0x0000FFFF)); + PrevCheatType = 0; + } + else if ((p->addr&0xFFFF0000) == 0x30300000){ // 3030vvvv 0aaaaaaa Dec + memRead16((u32)p->data,&u16Val); + memWrite16((u32)p->data, u16Val-(p->addr&0x0000FFFF)); + PrevCheatType = 0; + } + else if ((p->addr&0xFFFF0000) == 0x30400000){ // 30400000 0aaaaaaa Inc + Another line + PrevCheatType= 0x3040; + PrevCheataddr= (u32)p->data; + } + else if ((p->addr&0xFFFF0000) == 0x30500000){ // 30500000 0aaaaaaa Inc + Another line + PrevCheatType= 0x3050; + PrevCheataddr= (u32)p->data; + } + else if ((p->addr&0xF0000000) == 0x40000000){ // 4aaaaaaa nnnnssss + Another line + IterationCount=((u32)p->data&0xFFFF0000)/0x10000; + IterationIncrement=((u32)p->data&0x0000FFFF)*4; + PrevCheataddr=(u32)p->addr&0x0FFFFFFF; + PrevCheatType= 0x4000; + } + else if ((p->addr&0xF0000000) == 0x50000000){ // 5sssssss nnnnnnnn + Another line + PrevCheataddr = (u32)p->addr&0x0FFFFFFF; + IterationCount=((u32)p->data); + PrevCheatType= 0x5000; + } + else if ((p->addr&0xF0000000) == 0x60000000){ // 6aaaaaaa 000000vv + Another line/s + PrevCheataddr = (u32)p->addr&0x0FFFFFFF; + IterationIncrement=((u32)p->data); + IterationCount=0; + PrevCheatType= 0x6000; + } + else if ((p->addr&0xF0000000) == 0x70000000) { + if ((p->data&0x00F00000) == 0x00000000){ // 7aaaaaaa 000000vv + memRead8((u32)p->addr&0x0FFFFFFF,&u8Val); + memWrite8((u32)p->addr&0x0FFFFFFF,(u8)(u8Val|(p->data&0x000000FF))); + }else if ((p->data&0x00F00000) == 0x00100000){ // 7aaaaaaa 0010vvvv + memRead16((u32)p->addr&0x0FFFFFFF,&u16Val); + memWrite16((u32)p->addr&0x0FFFFFFF,(u16)(u16Val|(p->data&0x0000FFFF))); + }else if ((p->data&0x00F00000) == 0x00200000){ // 7aaaaaaa 002000vv + memRead8((u32)p->addr&0x0FFFFFFF,&u8Val); + memWrite8((u32)p->addr&0x0FFFFFFF,(u8)(u8Val&(p->data&0x000000FF))); + }else if ((p->data&0x00F00000) == 0x00300000){ // 7aaaaaaa 0030vvvv + memRead16((u32)p->addr&0x0FFFFFFF,&u16Val); + memWrite16((u32)p->addr&0x0FFFFFFF,(u16)(u16Val&(p->data&0x0000FFFF))); + }else if ((p->data&0x00F00000) == 0x00400000){ // 7aaaaaaa 004000vv + memRead8((u32)p->addr&0x0FFFFFFF,&u8Val); + memWrite8((u32)p->addr&0x0FFFFFFF,(u8)(u8Val^(p->data&0x000000FF))); + }else if ((p->data&0x00F00000) == 0x00500000){ // 7aaaaaaa 0050vvvv + memRead16((u32)p->addr&0x0FFFFFFF,&u16Val); + memWrite16((u32)p->addr&0x0FFFFFFF,(u16)(u16Val^(p->data&0x0000FFFF))); + } + } + else if (p->addr < 0xE0000000) { + if ((((u32)p->data & 0xFFFF0000)==0x00000000) || + (((u32)p->data & 0xFFFF0000)==0x00100000) || + (((u32)p->data & 0xFFFF0000)==0x00200000) || + (((u32)p->data & 0xFFFF0000)==0x00300000)) { + memRead16((u32)p->addr&0x0FFFFFFF,&u16Val); + if (u16Val != (0x0000FFFF&(u32)p->data)) + SkipCount = 1; + PrevCheatType= 0; + } + } + else if (p->addr < 0xF0000000) { + if ((((u32)p->data&0xF0000000)==0x00000000) || + (((u32)p->data&0xF0000000)==0x10000000) || + (((u32)p->data&0xF0000000)==0x20000000) || + (((u32)p->data&0xF0000000)==0x30000000)) { + memRead16((u32)p->data&0x0FFFFFFF,&u16Val); + if (u16Val != (0x0000FFFF&(u32)p->addr)) + SkipCount = ((u32)p->addr&0xFFF0000)/0x10000; + PrevCheatType= 0; + } + } + } + } + break; + case CPU_IOP: { + switch (p->type) { + case BYTE_T: + psxMemWrite8(p->addr, (u8)p->data); + break; + case SHORT_T: + psxMemWrite16(p->addr, (u16)p->data); + break; + case WORD_T: + psxMemWrite32(p->addr, (u32)p->data); + break; + } + } + } +} + + +//this is for apply patches directly to memory +void applypatch(int place) { + int i; + + if (place == 0) { + Console::WriteLn(" patchnumber: %d", params patchnumber); + } + + for ( i = 0; i < patchnumber; i++ ) { + _applypatch(place, &patch[i]); + } +} + +void patchFunc_comment( char * text1, char * text2 ) +{ + Console::WriteLn( "comment: %s", params text2 ); +} + + +void patchFunc_gametitle( char * text1, char * text2 ) +{ + Console::WriteLn( "gametitle: %s", params text2 ); + sprintf(strgametitle,"%s",text2); + Console::SetTitle(strgametitle); +} + +void patchFunc_patch( char * cmd, char * param ) +{ + char * pText; + + if ( patchnumber >= MAX_PATCH ) + { + Console::Error( "Patch ERROR: Maximum number of patches reached: %s=%s", params cmd, param ); + return; + } + + pText = strtok( param, "," ); + pText = param; + + patch[ patchnumber ].placetopatch = strtol( pText, (char **)NULL, 0 ); + + pText = strtok( NULL, "," ); + inifile_trim( pText ); + patch[ patchnumber ].cpu = (patch_cpu_type)PatchTableExecute( pText, NULL, cpuCore ); + if ( patch[ patchnumber ].cpu == 0 ) + { + Console::Error( "Unrecognized patch '%s'", params pText ); + return; + } + + pText = strtok( NULL, "," ); + inifile_trim( pText ); + sscanf( pText, "%X", &patch[ patchnumber ].addr ); + + pText = strtok( NULL, "," ); + inifile_trim( pText ); + patch[ patchnumber ].type = (patch_data_type)PatchTableExecute( pText, NULL, dataType ); + if ( patch[ patchnumber ].type == 0 ) + { + Console::Error( "Unrecognized patch '%s'", params pText ); + return; + } + + pText = strtok( NULL, "," ); + inifile_trim( pText ); + sscanf( pText, "%I64X", &patch[ patchnumber ].data ); + + patch[ patchnumber ].enabled = 1; + + patchnumber++; +} + +//this routine is for executing the commands of the ini file +void inifile_command( char * cmd ) +{ + int code; + char command[ 256 ]; + char parameter[ 256 ]; + + // extract param part (after '=') + char * pEqual = strchr( cmd, '=' ); + + if ( ! pEqual ) + { + // fastmemory doesn't have = + pEqual = cmd+strlen(cmd); + } + + memzero_obj( command ); + memzero_obj( parameter ); + + strncpy( command, cmd, pEqual - cmd ); + strncpy( parameter, pEqual + 1, sizeof( parameter ) ); + + inifile_trim( command ); + inifile_trim( parameter ); + + code = PatchTableExecute( command, parameter, commands ); +} + +void inifile_trim( char * buffer ) +{ + char * pInit = buffer; + char * pEnd = NULL; + + while ( ( *pInit == ' ' ) || ( *pInit == '\t' ) ) //skip space + { + pInit++; + } + if ( ( pInit[ 0 ] == '/' ) && ( pInit[ 1 ] == '/' ) ) //remove comment + { + buffer[ 0 ] = '\0'; + return; + } + pEnd = pInit + strlen( pInit ) - 1; + if ( pEnd <= pInit ) + { + buffer[ 0 ] = '\0'; + return; + } + while ( ( *pEnd == '\r' ) || ( *pEnd == '\n' ) || + ( *pEnd == ' ' ) || ( *pEnd == '\t' ) ) + { + pEnd--; + } + if ( pEnd <= pInit ) + { + buffer[ 0 ] = '\0'; + return; + } + memmove( buffer, pInit, pEnd - pInit + 1 ); + buffer[ pEnd - pInit + 1 ] = '\0'; +} + +void inisection_process( FILE * f1 ) +{ + char buffer[ 1024 ]; + while( fgets( buffer, sizeof( buffer ), f1 ) ) + { + inifile_trim( buffer ); + if ( buffer[ 0 ] ) + { + inifile_command( buffer ); + } + } +} + +//this routine is for reading the ini file + +void inifile_read( const char * name ) +{ + FILE * f1; + char buffer[ 1024 ]; + + patchnumber = 0; +#ifdef _WIN32 + sprintf( buffer, PATCHES_DIR "\\%s.pnach", name ); +#else + sprintf( buffer, PATCHES_DIR "/%s.pnach", name ); +#endif + + f1 = fopen( buffer, "rt" ); + +#ifndef _WIN32 + if( !f1 ) { + // try all upper case because linux is case sensitive + char* pstart = buffer+8; + char* pend = buffer+strlen(buffer); + while(pstart != pend ) { + // stop at the first . since we only want to update the hex + if( *pstart == '.' ) + break; + *pstart++ = toupper(*pstart); + } + + f1 = fopen(buffer, "rt"); + } +#endif + + if( !f1 ) + { + Console::WriteLn( _( "No patch found.Resuming execution without a patch (this is NOT an error)." )); + return; + } + + inisection_process( f1 ); + + fclose( f1 ); +} + +void resetpatch( void ) +{ + patchnumber = 0; +} + +int AddPatch(int Mode, int Place, int Address, int Size, u64 data) +{ + + if ( patchnumber >= MAX_PATCH ) + { + Console::Error( "Patch ERROR: Maximum number of patches reached."); + return -1; + } + + patch[patchnumber].placetopatch = Mode; + + patch[patchnumber].cpu = (patch_cpu_type)Place; + patch[patchnumber].addr=Address; + patch[patchnumber].type=(patch_data_type)Size; + patch[patchnumber].data = data; + return patchnumber++; +} + +void patchFunc_ffxhack( char * cmd, char * param ) +{ + g_FFXHack = 1; +} + +void patchFunc_xkickdelay( char * cmd, char * param ) +{ + g_VUGameFixes |= VUFIX_XGKICKDELAY2; +} + +void patchFunc_fastmemory( char * cmd, char * param ) +{ + // only valid for recompilers + SetFastMemory(1); +} + + +void patchFunc_vunanmode( char * cmd, char * param ) +{ + // only valid for recompilers + SetVUNanMode(param != NULL ? atoi(param) : 1); +} + +void patchFunc_path3hack( char * cmd, char * param ) +{ + path3hack = 1; +} + +void patchFunc_roundmode( char * cmd, char * param ) +{ + int index; + char * pText; + + u32 eetype = (Config.sseMXCSR & 0x6000); + u32 vutype = (Config.sseVUMXCSR & 0x6000); + + index = 0; + pText = strtok( param, ", " ); + while(pText != NULL) { + u32 type = 0xffff; + + if( stricmp(pText, "near") == 0 ) { + type = 0x0000; + } + else if( stricmp(pText, "down") == 0 ) { + type = 0x2000; + } + else if( stricmp(pText, "up") == 0 ) { + type = 0x4000; + } + else if( stricmp(pText, "chop") == 0 ) { + type = 0x6000; + } + + if( type == 0xffff ) { + printf("bad argument (%s) to round mode! skipping...\n", pText); + break; + } + + if( index == 0 ) + eetype=type; + else + vutype=type; + + if( index == 1 ) + break; + + index++; + pText = strtok(NULL, ", "); + } + + SetRoundMode(eetype,vutype); +} + +void patchFunc_zerogs(char* cmd, char* param) +{ + sscanf(param, "%x", &g_ZeroGSOptions); +} + +void SetRoundMode(u32 ee, u32 vu) +{ + // don't set a state for interpreter only + //Msgbox::Alert("SetRoundMode: Config.sseMXCSR = %x; Config.sseVUMXCSR = %x \n", Config.sseMXCSR, Config.sseVUMXCSR); + + SetCPUState( (Config.sseMXCSR & 0x9fff) | ee, (Config.sseVUMXCSR & 0x9fff) | vu); +} diff --git a/pcsx2/Patch.h b/pcsx2/Patch.h index 12dacdf8f8..260aef8e35 100644 --- a/pcsx2/Patch.h +++ b/pcsx2/Patch.h @@ -1,134 +1,134 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef __PATCH_H__ -#define __PATCH_H__ - -#ifdef _WIN32 -#include -#endif - -#include "PS2Etypes.h" - -// -// Defines -// -#define MAX_PATCH 1024 - -#define IFIS(x,str) if(!strnicmp(x,str,sizeof(str)-1)) - -#define GETNEXT_PARAM() \ - while ( *param && ( *param != ',' ) ) param++; \ - if ( *param ) param++; \ - while ( *param && ( *param == ' ' ) ) param++; \ - if ( *param == 0 ) { Console::Error( _( "Not enough params for inicommand" ) ); return; } - -// -// Enums -// - -enum patch_cpu_type { - NO_CPU, - CPU_EE, - CPU_IOP -}; - -enum patch_data_type { - NO_TYPE, - BYTE_T, - SHORT_T, - WORD_T, - DOUBLE_T, - EXTENDED_T -}; - -// -// Typedefs -// -typedef void (*PATCHTABLEFUNC)( char * text1, char * text2 ); - -struct PatchTextTable -{ - const char *text; - int code; - PATCHTABLEFUNC func; -}; - -struct IniPatch -{ - int enabled; - int group; - patch_data_type type; - patch_cpu_type cpu; - int placetopatch; - u32 addr; - u64 data; -}; - -// -// Function prototypes -// -void patchFunc_comment( char * text1, char * text2 ); -void patchFunc_gametitle( char * text1, char * text2 ); -void patchFunc_patch( char * text1, char * text2 ); -void patchFunc_fastmemory( char * text1, char * text2 ); -void patchFunc_path3hack( char * text1, char * text2 ); -void patchFunc_roundmode( char * text1, char * text2 ); -void patchFunc_zerogs( char * text1, char * text2 ); -void patchFunc_vunanmode( char * text1, char * text2 ); -void patchFunc_ffxhack( char * text1, char * text2 ); -void patchFunc_xkickdelay( char * text1, char * text2 ); - -void inifile_trim( char * buffer ); - -// -// Variables -// -extern PatchTextTable commands[]; -extern PatchTextTable dataType[]; -extern PatchTextTable cpuCore[]; -extern IniPatch patch[ MAX_PATCH ]; -extern int patchnumber; - -#ifdef __LINUX__ -// Nasty, currently neccessary hack -extern u32 LinuxsseMXCSR; -extern u32 LinuxsseVUMXCSR; -#endif - -void applypatch( int place ); -void inifile_read( const char * name ); -void inifile_command( char * cmd ); -void resetpatch( void ); - -int AddPatch(int Mode, int Place, int Address, int Size, u64 data); - -extern void SetFastMemory(int); // iR5900LoadStore.c -extern void SetVUNanMode(int mode); - -extern int path3hack; -extern int g_FFXHack; -//extern int g_VUGameFixes; -extern int g_ZeroGSOptions; -extern u32 g_sseMXCSR; -extern u32 g_sseVUMXCSR; - -void SetRoundMode(u32 ee, u32 vu); -int LoadPatch(const std::string& patchfile); - -#endif /* __PATCH_H__ */ - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef __PATCH_H__ +#define __PATCH_H__ + +#ifdef _WIN32 +#include +#endif + +#include "PS2Etypes.h" + +// +// Defines +// +#define MAX_PATCH 1024 + +#define IFIS(x,str) if(!strnicmp(x,str,sizeof(str)-1)) + +#define GETNEXT_PARAM() \ + while ( *param && ( *param != ',' ) ) param++; \ + if ( *param ) param++; \ + while ( *param && ( *param == ' ' ) ) param++; \ + if ( *param == 0 ) { Console::Error( _( "Not enough params for inicommand" ) ); return; } + +// +// Enums +// + +enum patch_cpu_type { + NO_CPU, + CPU_EE, + CPU_IOP +}; + +enum patch_data_type { + NO_TYPE, + BYTE_T, + SHORT_T, + WORD_T, + DOUBLE_T, + EXTENDED_T +}; + +// +// Typedefs +// +typedef void (*PATCHTABLEFUNC)( char * text1, char * text2 ); + +struct PatchTextTable +{ + const char *text; + int code; + PATCHTABLEFUNC func; +}; + +struct IniPatch +{ + int enabled; + int group; + patch_data_type type; + patch_cpu_type cpu; + int placetopatch; + u32 addr; + u64 data; +}; + +// +// Function prototypes +// +void patchFunc_comment( char * text1, char * text2 ); +void patchFunc_gametitle( char * text1, char * text2 ); +void patchFunc_patch( char * text1, char * text2 ); +void patchFunc_fastmemory( char * text1, char * text2 ); +void patchFunc_path3hack( char * text1, char * text2 ); +void patchFunc_roundmode( char * text1, char * text2 ); +void patchFunc_zerogs( char * text1, char * text2 ); +void patchFunc_vunanmode( char * text1, char * text2 ); +void patchFunc_ffxhack( char * text1, char * text2 ); +void patchFunc_xkickdelay( char * text1, char * text2 ); + +void inifile_trim( char * buffer ); + +// +// Variables +// +extern PatchTextTable commands[]; +extern PatchTextTable dataType[]; +extern PatchTextTable cpuCore[]; +extern IniPatch patch[ MAX_PATCH ]; +extern int patchnumber; + +#ifdef __LINUX__ +// Nasty, currently neccessary hack +extern u32 LinuxsseMXCSR; +extern u32 LinuxsseVUMXCSR; +#endif + +void applypatch( int place ); +void inifile_read( const char * name ); +void inifile_command( char * cmd ); +void resetpatch( void ); + +int AddPatch(int Mode, int Place, int Address, int Size, u64 data); + +extern void SetFastMemory(int); // iR5900LoadStore.c +extern void SetVUNanMode(int mode); + +extern int path3hack; +extern int g_FFXHack; +//extern int g_VUGameFixes; +extern int g_ZeroGSOptions; +extern u32 g_sseMXCSR; +extern u32 g_sseVUMXCSR; + +void SetRoundMode(u32 ee, u32 vu); +int LoadPatch(const std::string& patchfile); + +#endif /* __PATCH_H__ */ + diff --git a/pcsx2/PathUtils.cpp b/pcsx2/PathUtils.cpp index 1514e147ae..7b0fd3bec2 100644 --- a/pcsx2/PathUtils.cpp +++ b/pcsx2/PathUtils.cpp @@ -1,234 +1,234 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" -#include "Common.h" - -#ifdef __LINUX__ -#ifndef _S_IFDIR -#define _S_IFDIR S_IFDIR -#endif - -#ifndef _S_IFREG -#define _S_IFREG S_IFREG -#endif -#endif - -namespace Path -{ - -#ifdef WIN32 -// Path Separator used when creating new paths. -static const char Separator( '\\' ); -// Path separators used when breaking existing paths into parts and pieces. -static const string Delimiters( "\\/" ); -#else -static const char Separator = '/'; -static const char Delimiters( '/' ); -#endif - -bool Exists( const string& path ) -{ - struct stat sbuf; - return stat( path.c_str(), &sbuf ) == 0; -} - -// This function returns false if the path does not exist, or if the path exists and -// is a file. -bool isDirectory( const string& path ) -{ - struct stat sbuf; - if( stat( path.c_str(), &sbuf ) == -1 ) return false; - return !!(sbuf.st_mode & _S_IFDIR); -} - -// This function returns false if the path does not exist, or if the path exists and -// is a directory. -bool isFile( const string& path ) -{ - struct stat sbuf; - if( stat( path.c_str(), &sbuf ) == -1 ) return false; - return !!(sbuf.st_mode & _S_IFREG); -} - -// Returns the length of the file. -// returns -1 if the file is not found. -int getFileSize( const string& path ) -{ - struct stat sbuf; - if( stat( path.c_str(), &sbuf ) == -1 ) return -1; - return sbuf.st_size; -} - -bool isRooted( const string& path ) -{ - // if the first character is a backslash or period, or the second character - // a colon, it's a safe bet we're rooted. - - if( path[0] == 0 ) return FALSE; -#ifdef WIN32 - return (path[0] == '/') || (path[0] == '\\') || (path[1] == ':'); -#else - return (path[0] == Separator); -#endif -} - -// Concatenates two pathnames together, inserting delimiters (backslash on win32) -// as needed! Assumes the 'dest' is allocated to at least g_MaxPath length. -void Combine( string& dest, const string& srcPath, const string& srcFile ) -{ - int pathlen, guesslen; - - if( srcFile.empty() ) - { - // No source filename? Return the path unmodified. - dest = srcPath; - return; - } - - if( isRooted( srcFile ) || srcPath.empty() ) - { - // No source path? Or source filename is rooted? - // Return the filename unmodified. - dest = srcFile; - return; - } - - // strip off the srcPath's trailing backslashes (if any) - // Note: The win32 build works better if I check for both forward and backslashes. - // This might be a problem on Linux builds or maybe it doesn't matter? - - pathlen = srcPath.length(); - while( pathlen > 0 && ((srcPath[pathlen-1] == '\\') || (srcPath[pathlen-1] == '/')) ) - --pathlen; - - // Concatenate strings: - guesslen = pathlen + srcFile.length() + 2; - - if( guesslen >= g_MaxPath ) - throw Exception::PathTooLong(); - - // Concatenate! - - dest.assign( srcPath.begin(), srcPath.begin()+pathlen ); - dest += Separator; - dest += srcFile; -} - -// Replaces the extension of the file with the one given. -void ReplaceExtension( string& dest, const string& src, const string& ext ) -{ - int pos = src.find_last_of( '.' ); - if( pos == string::npos || pos == 0 ) - dest = src; - else - dest.assign( src.begin(), src.begin()+pos ); - - if( !ext.empty() ) - { - dest += '.'; - dest += ext; - } -} - -// finds the starting character position of a filename for the given source path. -static int _findFilenamePosition( const string& src) -{ - // note: the source path could have multiple trailing slashes. We want to ignore those. - - unsigned int startpos = src.find_last_not_of( Delimiters ); - - if(startpos == string::npos ) - return 0; - - int pos; - - if( startpos < src.length() ) - { - string trimmed( src.begin(), src.begin()+startpos ); - pos = trimmed.find_last_of( Delimiters ); - } - else - { - pos = src.find_last_of( Delimiters ); - } - - if( pos == string::npos ) - return 0; - - return pos; -} - -void ReplaceFilename( string& dest, const string& src, const string& newfilename ) -{ - int pos = _findFilenamePosition( src ); - - if( pos == 0 ) - dest = src; - else - dest.assign( src.begin(), src.begin()+pos ); - - if( !newfilename.empty() ) - { - dest += '.'; - dest += newfilename; - } -} - -void GetFilename( const string& src, string& dest ) -{ - int pos = _findFilenamePosition( src ); - dest.assign( src.begin()+pos, src.end() ); -} - -void GetDirectory( const string& src, string& dest ) -{ - int pos = _findFilenamePosition( src ); - if( pos == 0 ) - dest.clear(); - else - dest.assign( src.begin(), src.begin()+pos ); -} - -void Split( const string& src, string& destpath, string& destfile ) -{ - int pos = _findFilenamePosition( src ); - - if( pos == 0 ) - { - destpath.clear(); - destfile = src; - } - else - { - destpath.assign( src.begin(), src.begin()+pos ); - destfile.assign( src.begin()+pos, src.end() ); - } -} - -// Assigns the base/root directory of the given path into dest. -// Example /this/that/something.txt -> dest == "/" -void GetRootDirectory( const string& src, string& dest ) -{ - int pos = src.find_first_of( Delimiters ); - if( pos == string::npos ) - dest.clear(); - else - dest.assign( src.begin(), src.begin()+pos ); -} -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" +#include "Common.h" + +#ifdef __LINUX__ +#ifndef _S_IFDIR +#define _S_IFDIR S_IFDIR +#endif + +#ifndef _S_IFREG +#define _S_IFREG S_IFREG +#endif +#endif + +namespace Path +{ + +#ifdef WIN32 +// Path Separator used when creating new paths. +static const char Separator( '\\' ); +// Path separators used when breaking existing paths into parts and pieces. +static const string Delimiters( "\\/" ); +#else +static const char Separator = '/'; +static const char Delimiters( '/' ); +#endif + +bool Exists( const string& path ) +{ + struct stat sbuf; + return stat( path.c_str(), &sbuf ) == 0; +} + +// This function returns false if the path does not exist, or if the path exists and +// is a file. +bool isDirectory( const string& path ) +{ + struct stat sbuf; + if( stat( path.c_str(), &sbuf ) == -1 ) return false; + return !!(sbuf.st_mode & _S_IFDIR); +} + +// This function returns false if the path does not exist, or if the path exists and +// is a directory. +bool isFile( const string& path ) +{ + struct stat sbuf; + if( stat( path.c_str(), &sbuf ) == -1 ) return false; + return !!(sbuf.st_mode & _S_IFREG); +} + +// Returns the length of the file. +// returns -1 if the file is not found. +int getFileSize( const string& path ) +{ + struct stat sbuf; + if( stat( path.c_str(), &sbuf ) == -1 ) return -1; + return sbuf.st_size; +} + +bool isRooted( const string& path ) +{ + // if the first character is a backslash or period, or the second character + // a colon, it's a safe bet we're rooted. + + if( path[0] == 0 ) return FALSE; +#ifdef WIN32 + return (path[0] == '/') || (path[0] == '\\') || (path[1] == ':'); +#else + return (path[0] == Separator); +#endif +} + +// Concatenates two pathnames together, inserting delimiters (backslash on win32) +// as needed! Assumes the 'dest' is allocated to at least g_MaxPath length. +void Combine( string& dest, const string& srcPath, const string& srcFile ) +{ + int pathlen, guesslen; + + if( srcFile.empty() ) + { + // No source filename? Return the path unmodified. + dest = srcPath; + return; + } + + if( isRooted( srcFile ) || srcPath.empty() ) + { + // No source path? Or source filename is rooted? + // Return the filename unmodified. + dest = srcFile; + return; + } + + // strip off the srcPath's trailing backslashes (if any) + // Note: The win32 build works better if I check for both forward and backslashes. + // This might be a problem on Linux builds or maybe it doesn't matter? + + pathlen = srcPath.length(); + while( pathlen > 0 && ((srcPath[pathlen-1] == '\\') || (srcPath[pathlen-1] == '/')) ) + --pathlen; + + // Concatenate strings: + guesslen = pathlen + srcFile.length() + 2; + + if( guesslen >= g_MaxPath ) + throw Exception::PathTooLong(); + + // Concatenate! + + dest.assign( srcPath.begin(), srcPath.begin()+pathlen ); + dest += Separator; + dest += srcFile; +} + +// Replaces the extension of the file with the one given. +void ReplaceExtension( string& dest, const string& src, const string& ext ) +{ + int pos = src.find_last_of( '.' ); + if( pos == string::npos || pos == 0 ) + dest = src; + else + dest.assign( src.begin(), src.begin()+pos ); + + if( !ext.empty() ) + { + dest += '.'; + dest += ext; + } +} + +// finds the starting character position of a filename for the given source path. +static int _findFilenamePosition( const string& src) +{ + // note: the source path could have multiple trailing slashes. We want to ignore those. + + unsigned int startpos = src.find_last_not_of( Delimiters ); + + if(startpos == string::npos ) + return 0; + + int pos; + + if( startpos < src.length() ) + { + string trimmed( src.begin(), src.begin()+startpos ); + pos = trimmed.find_last_of( Delimiters ); + } + else + { + pos = src.find_last_of( Delimiters ); + } + + if( pos == string::npos ) + return 0; + + return pos; +} + +void ReplaceFilename( string& dest, const string& src, const string& newfilename ) +{ + int pos = _findFilenamePosition( src ); + + if( pos == 0 ) + dest = src; + else + dest.assign( src.begin(), src.begin()+pos ); + + if( !newfilename.empty() ) + { + dest += '.'; + dest += newfilename; + } +} + +void GetFilename( const string& src, string& dest ) +{ + int pos = _findFilenamePosition( src ); + dest.assign( src.begin()+pos, src.end() ); +} + +void GetDirectory( const string& src, string& dest ) +{ + int pos = _findFilenamePosition( src ); + if( pos == 0 ) + dest.clear(); + else + dest.assign( src.begin(), src.begin()+pos ); +} + +void Split( const string& src, string& destpath, string& destfile ) +{ + int pos = _findFilenamePosition( src ); + + if( pos == 0 ) + { + destpath.clear(); + destfile = src; + } + else + { + destpath.assign( src.begin(), src.begin()+pos ); + destfile.assign( src.begin()+pos, src.end() ); + } +} + +// Assigns the base/root directory of the given path into dest. +// Example /this/that/something.txt -> dest == "/" +void GetRootDirectory( const string& src, string& dest ) +{ + int pos = src.find_first_of( Delimiters ); + if( pos == string::npos ) + dest.clear(); + else + dest.assign( src.begin(), src.begin()+pos ); +} +} diff --git a/pcsx2/Paths.h b/pcsx2/Paths.h index b78616da6c..97f9efbff1 100644 --- a/pcsx2/Paths.h +++ b/pcsx2/Paths.h @@ -1,39 +1,39 @@ -#ifndef _PCSX2_PATHS_H_ -#define _PCSX2_PATHS_H_ - -#define CONFIG_DIR "inis" - -#define DEFAULT_BIOS_DIR "bios" -#define DEFAULT_PLUGINS_DIR "plugins" - -#define MEMCARDS_DIR "memcards" -#define PATCHES_DIR "patches" - -#define SSTATES_DIR "sstates" -#define LANGS_DIR "Langs" -#define LOGS_DIR "logs" - -#define DEFAULT_MEMCARD1 "Mcd001.ps2" -#define DEFAULT_MEMCARD2 "Mcd002.ps2" - -#define g_MaxPath 255 // 255 is safer with antiquated Win32 ASCII APIs. - -namespace Path -{ - void Combine( std::string& dest, const std::string& srcPath, const std::string& srcFile ); - bool isRooted( const std::string& path ); - bool isDirectory( const std::string& path ); - bool isFile( const std::string& path ); - bool Exists( const std::string& path ); - int getFileSize( const std::string& path ); - - void ReplaceExtension( std::string& dest, const std::string& src, const std::string& ext ); - void ReplaceFilename( std::string& dest, const std::string& src, const std::string& newfilename ); - void GetFilename( const std::string& src, std::string& dest ); - void GetDirectory( const std::string& src, std::string& dest ); - void GetRootDirectory( const std::string& src, std::string& dest ); - void Split( const std::string& src, std::string& destpath, std::string& destfile ); - -} - -#endif +#ifndef _PCSX2_PATHS_H_ +#define _PCSX2_PATHS_H_ + +#define CONFIG_DIR "inis" + +#define DEFAULT_BIOS_DIR "bios" +#define DEFAULT_PLUGINS_DIR "plugins" + +#define MEMCARDS_DIR "memcards" +#define PATCHES_DIR "patches" + +#define SSTATES_DIR "sstates" +#define LANGS_DIR "Langs" +#define LOGS_DIR "logs" + +#define DEFAULT_MEMCARD1 "Mcd001.ps2" +#define DEFAULT_MEMCARD2 "Mcd002.ps2" + +#define g_MaxPath 255 // 255 is safer with antiquated Win32 ASCII APIs. + +namespace Path +{ + void Combine( std::string& dest, const std::string& srcPath, const std::string& srcFile ); + bool isRooted( const std::string& path ); + bool isDirectory( const std::string& path ); + bool isFile( const std::string& path ); + bool Exists( const std::string& path ); + int getFileSize( const std::string& path ); + + void ReplaceExtension( std::string& dest, const std::string& src, const std::string& ext ); + void ReplaceFilename( std::string& dest, const std::string& src, const std::string& newfilename ); + void GetFilename( const std::string& src, std::string& dest ); + void GetDirectory( const std::string& src, std::string& dest ); + void GetRootDirectory( const std::string& src, std::string& dest ); + void Split( const std::string& src, std::string& destpath, std::string& destfile ); + +} + +#endif diff --git a/pcsx2/Plugins.cpp b/pcsx2/Plugins.cpp index 508201eadc..b31345c5a2 100644 --- a/pcsx2/Plugins.cpp +++ b/pcsx2/Plugins.cpp @@ -1,884 +1,884 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "PsxCommon.h" -#include "GS.h" - -_GSinit GSinit; -_GSopen GSopen; -_GSclose GSclose; -_GSshutdown GSshutdown; -_GSvsync GSvsync; -_GSgifTransfer1 GSgifTransfer1; -_GSgifTransfer2 GSgifTransfer2; -_GSgifTransfer3 GSgifTransfer3; -_GSgetLastTag GSgetLastTag; -_GSgifSoftReset GSgifSoftReset; -_GSreadFIFO GSreadFIFO; -_GSreadFIFO2 GSreadFIFO2; - -_GSkeyEvent GSkeyEvent; -_GSchangeSaveState GSchangeSaveState; -_GSmakeSnapshot GSmakeSnapshot; -_GSmakeSnapshot2 GSmakeSnapshot2; -_GSirqCallback GSirqCallback; -_GSprintf GSprintf; -_GSsetBaseMem GSsetBaseMem; -_GSsetGameCRC GSsetGameCRC; -_GSsetFrameSkip GSsetFrameSkip; -_GSsetupRecording GSsetupRecording; -_GSreset GSreset; -_GSwriteCSR GSwriteCSR; -_GSgetDriverInfo GSgetDriverInfo; -#ifdef _WIN32 -_GSsetWindowInfo GSsetWindowInfo; -#endif -_GSfreeze GSfreeze; -_GSconfigure GSconfigure; -_GStest GStest; -_GSabout GSabout; - -// PAD1 -_PADinit PAD1init; -_PADopen PAD1open; -_PADclose PAD1close; -_PADshutdown PAD1shutdown; -_PADkeyEvent PAD1keyEvent; -_PADstartPoll PAD1startPoll; -_PADpoll PAD1poll; -_PADquery PAD1query; -_PADupdate PAD1update; - -_PADgsDriverInfo PAD1gsDriverInfo; -_PADconfigure PAD1configure; -_PADtest PAD1test; -_PADabout PAD1about; - -// PAD2 -_PADinit PAD2init; -_PADopen PAD2open; -_PADclose PAD2close; -_PADshutdown PAD2shutdown; -_PADkeyEvent PAD2keyEvent; -_PADstartPoll PAD2startPoll; -_PADpoll PAD2poll; -_PADquery PAD2query; -_PADupdate PAD2update; - -_PADgsDriverInfo PAD2gsDriverInfo; -_PADconfigure PAD2configure; -_PADtest PAD2test; -_PADabout PAD2about; - -// SIO[2] -_SIOinit SIOinit[2][9]; -_SIOopen SIOopen[2][9]; -_SIOclose SIOclose[2][9]; -_SIOshutdown SIOshutdown[2][9]; -_SIOstartPoll SIOstartPoll[2][9]; -_SIOpoll SIOpoll[2][9]; -_SIOquery SIOquery[2][9]; - -_SIOconfigure SIOconfigure[2][9]; -_SIOtest SIOtest[2][9]; -_SIOabout SIOabout[2][9]; - -// SPU2 -_SPU2init SPU2init; -_SPU2open SPU2open; -_SPU2close SPU2close; -_SPU2shutdown SPU2shutdown; -_SPU2write SPU2write; -_SPU2read SPU2read; -_SPU2readDMA4Mem SPU2readDMA4Mem; -_SPU2writeDMA4Mem SPU2writeDMA4Mem; -_SPU2interruptDMA4 SPU2interruptDMA4; -_SPU2readDMA7Mem SPU2readDMA7Mem; -_SPU2writeDMA7Mem SPU2writeDMA7Mem; -_SPU2setDMABaseAddr SPU2setDMABaseAddr; -_SPU2interruptDMA7 SPU2interruptDMA7; -_SPU2ReadMemAddr SPU2ReadMemAddr; -_SPU2setupRecording SPU2setupRecording; -_SPU2WriteMemAddr SPU2WriteMemAddr; -_SPU2irqCallback SPU2irqCallback; - -_SPU2setClockPtr SPU2setClockPtr; -_SPU2setTimeStretcher SPU2setTimeStretcher; - -_SPU2async SPU2async; -_SPU2freeze SPU2freeze; -_SPU2configure SPU2configure; -_SPU2test SPU2test; -_SPU2about SPU2about; - -// CDVD -_CDVDinit CDVDinit; -_CDVDopen CDVDopen; -_CDVDclose CDVDclose; -_CDVDshutdown CDVDshutdown; -_CDVDreadTrack CDVDreadTrack; -_CDVDgetBuffer CDVDgetBuffer; -_CDVDreadSubQ CDVDreadSubQ; -_CDVDgetTN CDVDgetTN; -_CDVDgetTD CDVDgetTD; -_CDVDgetTOC CDVDgetTOC; -_CDVDgetDiskType CDVDgetDiskType; -_CDVDgetTrayStatus CDVDgetTrayStatus; -_CDVDctrlTrayOpen CDVDctrlTrayOpen; -_CDVDctrlTrayClose CDVDctrlTrayClose; - -_CDVDconfigure CDVDconfigure; -_CDVDtest CDVDtest; -_CDVDabout CDVDabout; -_CDVDnewDiskCB CDVDnewDiskCB; - -// DEV9 -_DEV9init DEV9init; -_DEV9open DEV9open; -_DEV9close DEV9close; -_DEV9shutdown DEV9shutdown; -_DEV9read8 DEV9read8; -_DEV9read16 DEV9read16; -_DEV9read32 DEV9read32; -_DEV9write8 DEV9write8; -_DEV9write16 DEV9write16; -_DEV9write32 DEV9write32; -_DEV9readDMA8Mem DEV9readDMA8Mem; -_DEV9writeDMA8Mem DEV9writeDMA8Mem; -_DEV9irqCallback DEV9irqCallback; -_DEV9irqHandler DEV9irqHandler; - -_DEV9configure DEV9configure; -_DEV9freeze DEV9freeze; -_DEV9test DEV9test; -_DEV9about DEV9about; - -// USB -_USBinit USBinit; -_USBopen USBopen; -_USBclose USBclose; -_USBshutdown USBshutdown; -_USBread8 USBread8; -_USBread16 USBread16; -_USBread32 USBread32; -_USBwrite8 USBwrite8; -_USBwrite16 USBwrite16; -_USBwrite32 USBwrite32; -_USBasync USBasync; - -_USBirqCallback USBirqCallback; -_USBirqHandler USBirqHandler; -_USBsetRAM USBsetRAM; - -_USBconfigure USBconfigure; -_USBfreeze USBfreeze; -_USBtest USBtest; -_USBabout USBabout; - -// FW -_FWinit FWinit; -_FWopen FWopen; -_FWclose FWclose; -_FWshutdown FWshutdown; -_FWread32 FWread32; -_FWwrite32 FWwrite32; -_FWirqCallback FWirqCallback; - -_FWconfigure FWconfigure; -_FWfreeze FWfreeze; -_FWtest FWtest; -_FWabout FWabout; - - -DEV9handler dev9Handler; -USBhandler usbHandler; - -#define Sfy(x) #x -#define Strfy(x) Sfy(x) -#define MapSymbolVarType(var,type,name) var = (type)SysLoadSym(drv,Strfy(name)) -#define MapSymbolVar(var,name) MapSymbolVarType(var,_##name,name) -#define MapSymbolVar_Fallback(var,name,fallback) if((MapSymbolVar(var,name))==NULL) var = fallback -#define MapSymbolVar_Error(var,name) if((MapSymbolVar(var,name))==NULL) \ -{ \ - const char* errString = SysLibError(); \ - Msgbox::Alert("%s: Error loading %hs: %s", params &filename, #name, errString); \ - return -1; \ -} - -#define MapSymbol(name) MapSymbolVar(name,name) -#define MapSymbol_Fallback(name,fallback) MapSymbolVar_Fallback(name,name,fallback) -#define MapSymbol_Error(name) MapSymbolVar_Error(name,name) - -// for pad1/2 -#define MapSymbolPAD(var,sym,name) MapSymbolVar(var##name,sym##name) -#define MapSymbolPAD_Fallback(var,sym,name) if((MapSymbolVarType(var##name,_##sym##name,sym##name))==NULL) var##name = var##_##name -#define MapSymbolPAD_Error(var,sym,name) MapSymbolVar_Error(var##name,sym##name) - -#define TestPS2Esyms(type) if(_TestPS2Esyms(drv,PS2E_LT_##type,PS2E_##type##_VERSION,filename) < 0) return -1; - -int _TestPS2Esyms(void* drv, int type, int expected_version, const string& filename) -{ - _PS2EgetLibType PS2EgetLibType; - _PS2EgetLibVersion2 PS2EgetLibVersion2; - _PS2EgetLibName PS2EgetLibName; - - MapSymbol_Error(PS2EgetLibType); - MapSymbol_Error(PS2EgetLibVersion2); - MapSymbol_Error(PS2EgetLibName); - - int actual_version = ((PS2EgetLibVersion2(type) >> 16)&0xff); - - if( actual_version != expected_version) { - Msgbox::Alert("Can't load '%hs', wrong PS2E version (%x != %x)", params &filename, actual_version, expected_version); - return -1; - } - - return 0; -} - -//static const char *err; -//static int errval; - -void *GSplugin; - -void CALLBACK GS_printf(int timeout, char *fmt, ...) { - va_list list; - char msg[512]; - - va_start(list, fmt); - vsprintf(msg, fmt, list); - va_end(list); - - SysPrintf(msg); -} - -s32 CALLBACK GS_freeze(int mode, freezeData *data) { data->size = 0; return 0; } -void CALLBACK GS_keyEvent(keyEvent *ev) {} -void CALLBACK GS_makeSnapshot(const char *path) {} -void CALLBACK GS_irqCallback(void (*callback)()) {} -void CALLBACK GS_configure() {} -void CALLBACK GS_about() {} -s32 CALLBACK GS_test() { return 0; } - -int LoadGSplugin(const string& filename) -{ - void *drv; - - GSplugin = SysLoadLibrary(filename.c_str()); - if (GSplugin == NULL) { Msgbox::Alert ("Could Not Load GS Plugin '%hs': %s", params &filename, SysLibError()); return -1; } - drv = GSplugin; - TestPS2Esyms(GS); - MapSymbol_Error(GSinit); - MapSymbol_Error(GSshutdown); - MapSymbol_Error(GSopen); - MapSymbol_Error(GSclose); - MapSymbol_Error(GSgifTransfer1); - MapSymbol_Error(GSgifTransfer2); - MapSymbol_Error(GSgifTransfer3); - MapSymbol_Error(GSreadFIFO); - MapSymbol(GSgetLastTag); - MapSymbol(GSreadFIFO2); // optional - MapSymbol_Error(GSvsync); - - MapSymbol_Fallback(GSkeyEvent,GS_keyEvent); - MapSymbol(GSchangeSaveState); - MapSymbol(GSgifSoftReset); - MapSymbol_Fallback(GSmakeSnapshot,GS_makeSnapshot); - MapSymbol_Fallback(GSirqCallback,GS_irqCallback); - MapSymbol_Fallback(GSprintf,GS_printf); - MapSymbol_Error(GSsetBaseMem); - MapSymbol(GSsetGameCRC); - MapSymbol_Error(GSreset); - MapSymbol_Error(GSwriteCSR); - MapSymbol(GSmakeSnapshot2); - MapSymbol(GSgetDriverInfo); - - MapSymbol(GSsetFrameSkip); - MapSymbol(GSsetupRecording); - -#ifdef _WIN32 - MapSymbol(GSsetWindowInfo); -#endif - MapSymbol_Fallback(GSfreeze,GS_freeze); - MapSymbol_Fallback(GSconfigure,GS_configure); - MapSymbol_Fallback(GSabout,GS_about); - MapSymbol_Fallback(GStest,GS_test); - - return 0; -} - -void *PAD1plugin; - -void CALLBACK PAD1_configure() {} -void CALLBACK PAD1_about() {} -s32 CALLBACK PAD1_test() { return 0; } - -int LoadPAD1plugin(const string& filename) { - void *drv; - - PAD1plugin = SysLoadLibrary(filename.c_str()); - if (PAD1plugin == NULL) { Msgbox::Alert("Could Not Load PAD1 Plugin '%hs': %s", params &filename, SysLibError()); return -1; } - drv = PAD1plugin; - TestPS2Esyms(PAD); - MapSymbolPAD_Error(PAD1,PAD,init); - MapSymbolPAD_Error(PAD1,PAD,shutdown); - MapSymbolPAD_Error(PAD1,PAD,open); - MapSymbolPAD_Error(PAD1,PAD,close); - MapSymbolPAD_Error(PAD1,PAD,keyEvent); - MapSymbolPAD_Error(PAD1,PAD,startPoll); - MapSymbolPAD_Error(PAD1,PAD,poll); - MapSymbolPAD_Error(PAD1,PAD,query); - MapSymbolPAD(PAD1,PAD,update); - - MapSymbolPAD(PAD1,PAD,gsDriverInfo); - MapSymbolPAD_Fallback(PAD1,PAD,configure); - MapSymbolPAD_Fallback(PAD1,PAD,about); - MapSymbolPAD_Fallback(PAD1,PAD,test); - - return 0; -} - -void *PAD2plugin; - -void CALLBACK PAD2_configure() {} -void CALLBACK PAD2_about() {} -s32 CALLBACK PAD2_test() { return 0; } - -int LoadPAD2plugin(const string& filename) { - void *drv; - - PAD2plugin = SysLoadLibrary(filename.c_str()); - if (PAD2plugin == NULL) { Msgbox::Alert("Could Not Load PAD2 Plugin '%hs': %s", params &filename, SysLibError()); return -1; } - drv = PAD2plugin; - TestPS2Esyms(PAD); - MapSymbolPAD_Error(PAD2,PAD,init); - MapSymbolPAD_Error(PAD2,PAD,shutdown); - MapSymbolPAD_Error(PAD2,PAD,open); - MapSymbolPAD_Error(PAD2,PAD,close); - MapSymbolPAD_Error(PAD2,PAD,keyEvent); - MapSymbolPAD_Error(PAD2,PAD,startPoll); - MapSymbolPAD_Error(PAD2,PAD,poll); - MapSymbolPAD_Error(PAD2,PAD,query); - MapSymbolPAD(PAD2,PAD,update); - - MapSymbolPAD(PAD2,PAD,gsDriverInfo); - MapSymbolPAD_Fallback(PAD2,PAD,configure); - MapSymbolPAD_Fallback(PAD2,PAD,about); - MapSymbolPAD_Fallback(PAD2,PAD,test); - - return 0; -} - -void *SPU2plugin; - -s32 CALLBACK SPU2_freeze(int mode, freezeData *data) { data->size = 0; return 0; } -void CALLBACK SPU2_configure() {} -void CALLBACK SPU2_about() {} -s32 CALLBACK SPU2_test() { return 0; } - -int LoadSPU2plugin(const string& filename) { - void *drv; - - SPU2plugin = SysLoadLibrary(filename.c_str()); - if (SPU2plugin == NULL) { Msgbox::Alert("Could Not Load SPU2 Plugin '%hs': %s", params &filename, SysLibError()); return -1; } - drv = SPU2plugin; - TestPS2Esyms(SPU2); - MapSymbol_Error(SPU2init); - MapSymbol_Error(SPU2shutdown); - MapSymbol_Error(SPU2open); - MapSymbol_Error(SPU2close); - MapSymbol_Error(SPU2write); - MapSymbol_Error(SPU2read); - MapSymbol_Error(SPU2readDMA4Mem); - MapSymbol_Error(SPU2writeDMA4Mem); - MapSymbol_Error(SPU2interruptDMA4); - MapSymbol_Error(SPU2readDMA7Mem); - MapSymbol_Error(SPU2writeDMA7Mem); - MapSymbol_Error(SPU2interruptDMA7); - MapSymbol(SPU2setDMABaseAddr); - MapSymbol_Error(SPU2ReadMemAddr); - MapSymbol_Error(SPU2WriteMemAddr); - MapSymbol_Error(SPU2irqCallback); - - MapSymbol(SPU2setClockPtr); - - MapSymbol(SPU2setupRecording); - - MapSymbol_Fallback(SPU2freeze,SPU2_freeze); - MapSymbol_Fallback(SPU2configure,SPU2_configure); - MapSymbol_Fallback(SPU2about,SPU2_about); - MapSymbol_Fallback(SPU2test,SPU2_test); - MapSymbol(SPU2async); - - return 0; -} - -void *CDVDplugin; - -void CALLBACK CDVD_configure() {} -void CALLBACK CDVD_about() {} -s32 CALLBACK CDVD_test() { return 0; } - -int LoadCDVDplugin(const string& filename) { - void *drv; - - CDVDplugin = SysLoadLibrary(filename.c_str()); - if (CDVDplugin == NULL) { Msgbox::Alert("Could Not Load CDVD Plugin '%hs': %s", params &filename, SysLibError()); return -1; } - drv = CDVDplugin; - TestPS2Esyms(CDVD); - MapSymbol_Error(CDVDinit); - MapSymbol_Error(CDVDshutdown); - MapSymbol_Error(CDVDopen); - MapSymbol_Error(CDVDclose); - MapSymbol_Error(CDVDreadTrack); - MapSymbol_Error(CDVDgetBuffer); - MapSymbol_Error(CDVDreadSubQ); - MapSymbol_Error(CDVDgetTN); - MapSymbol_Error(CDVDgetTD); - MapSymbol_Error(CDVDgetTOC); - MapSymbol_Error(CDVDgetDiskType); - MapSymbol_Error(CDVDgetTrayStatus); - MapSymbol_Error(CDVDctrlTrayOpen); - MapSymbol_Error(CDVDctrlTrayClose); - - MapSymbol_Fallback(CDVDconfigure,CDVD_configure); - MapSymbol_Fallback(CDVDabout,CDVD_about); - MapSymbol_Fallback(CDVDtest,CDVD_test); - MapSymbol(CDVDnewDiskCB); - - return 0; -} - -void *DEV9plugin; - -s32 CALLBACK DEV9_freeze(int mode, freezeData *data) { data->size = 0; return 0; } -void CALLBACK DEV9_configure() {} -void CALLBACK DEV9_about() {} -s32 CALLBACK DEV9_test() { return 0; } - -int LoadDEV9plugin(const string& filename) { - void *drv; - - DEV9plugin = SysLoadLibrary(filename.c_str()); - if (DEV9plugin == NULL) { Msgbox::Alert("Could Not Load DEV9 Plugin '%hs': %s", params &filename, SysLibError()); return -1; } - drv = DEV9plugin; - TestPS2Esyms(DEV9); - MapSymbol_Error(DEV9init); - MapSymbol_Error(DEV9shutdown); - MapSymbol_Error(DEV9open); - MapSymbol_Error(DEV9close); - MapSymbol_Error(DEV9read8); - MapSymbol_Error(DEV9read16); - MapSymbol_Error(DEV9read32); - MapSymbol_Error(DEV9write8); - MapSymbol_Error(DEV9write16); - MapSymbol_Error(DEV9write32); - MapSymbol_Error(DEV9readDMA8Mem); - MapSymbol_Error(DEV9writeDMA8Mem); - MapSymbol_Error(DEV9irqCallback); - MapSymbol_Error(DEV9irqHandler); - - MapSymbol_Fallback(DEV9freeze,DEV9_freeze); - MapSymbol_Fallback(DEV9configure,DEV9_configure); - MapSymbol_Fallback(DEV9about,DEV9_about); - MapSymbol_Fallback(DEV9test,DEV9_test); - - return 0; -} - -void *USBplugin; - -s32 CALLBACK USB_freeze(int mode, freezeData *data) { data->size = 0; return 0; } -void CALLBACK USB_configure() {} -void CALLBACK USB_about() {} -s32 CALLBACK USB_test() { return 0; } - -int LoadUSBplugin(const string& filename) { - void *drv; - - USBplugin = SysLoadLibrary(filename.c_str()); - if (USBplugin == NULL) { Msgbox::Alert("Could Not Load USB Plugin '%hs': %s", params &filename, SysLibError()); return -1; } - drv = USBplugin; - TestPS2Esyms(USB); - MapSymbol_Error(USBinit); - MapSymbol_Error(USBshutdown); - MapSymbol_Error(USBopen); - MapSymbol_Error(USBclose); - MapSymbol_Error(USBread8); - MapSymbol_Error(USBread16); - MapSymbol_Error(USBread32); - MapSymbol_Error(USBwrite8); - MapSymbol_Error(USBwrite16); - MapSymbol_Error(USBwrite32); - MapSymbol_Error(USBirqCallback); - MapSymbol_Error(USBirqHandler); - MapSymbol_Error(USBsetRAM); - - MapSymbol(USBasync); - - MapSymbol_Fallback(USBfreeze,USB_freeze); - MapSymbol_Fallback(USBconfigure,USB_configure); - MapSymbol_Fallback(USBabout,USB_about); - MapSymbol_Fallback(USBtest,USB_test); - - return 0; -} -void *FWplugin; - -s32 CALLBACK FW_freeze(int mode, freezeData *data) { data->size = 0; return 0; } -void CALLBACK FW_configure() {} -void CALLBACK FW_about() {} -s32 CALLBACK FW_test() { return 0; } - -int LoadFWplugin(const string& filename) { - void *drv; - - FWplugin = SysLoadLibrary(filename.c_str()); - if (FWplugin == NULL) { Msgbox::Alert("Could Not Load FW Plugin '%hs': %s", params &filename, SysLibError()); return -1; } - drv = FWplugin; - TestPS2Esyms(FW); - MapSymbol_Error(FWinit); - MapSymbol_Error(FWshutdown); - MapSymbol_Error(FWopen); - MapSymbol_Error(FWclose); - MapSymbol_Error(FWread32); - MapSymbol_Error(FWwrite32); - MapSymbol_Error(FWirqCallback); - - MapSymbol_Fallback(FWfreeze,FW_freeze); - MapSymbol_Fallback(FWconfigure,FW_configure); - MapSymbol_Fallback(FWabout,FW_about); - MapSymbol_Fallback(FWtest,FW_test); - - return 0; -} - -struct PluginOpenStatusFlags -{ - u8 GS : 1 - , CDVD : 1 - , DEV9 : 1 - , USB : 1 - , SPU2 : 1 - , PAD1 : 1 - , PAD2 : 1 - , FW : 1; - -}; - -static PluginOpenStatusFlags OpenStatus = {0}; - -static bool loadp=false; - -int InitPlugins() { - int ret; - - ret = GSinit(); - if (ret != 0) { Msgbox::Alert("GSinit error: %d", params ret); return -1; } - ret = PAD1init(1); - if (ret != 0) { Msgbox::Alert("PAD1init error: %d", params ret); return -1; } - ret = PAD2init(2); - if (ret != 0) { Msgbox::Alert("PAD2init error: %d", params ret); return -1; } - ret = SPU2init(); - if (ret != 0) { Msgbox::Alert("SPU2init error: %d", params ret); return -1; } - ret = CDVDinit(); - if (ret != 0) { Msgbox::Alert("CDVDinit error: %d", params ret); return -1; } - ret = DEV9init(); - if (ret != 0) { Msgbox::Alert("DEV9init error: %d", params ret); return -1; } - ret = USBinit(); - if (ret != 0) { Msgbox::Alert("USBinit error: %d", params ret); return -1; } - ret = FWinit(); - if (ret != 0) { Msgbox::Alert("FWinit error: %d", params ret); return -1; } - return 0; -} - -void ShutdownPlugins() -{ - ClosePlugins(); - - // GS is a special case: It needs closed first usually. - // (the GS isn't always closed during emulation pauses) - if( OpenStatus.GS ) - { - gsClose(); - OpenStatus.GS = false; - } - - if( GSshutdown != NULL ) - GSshutdown(); - - if( PAD1shutdown != NULL ) - PAD1shutdown(); - if( PAD2shutdown != NULL ) - PAD2shutdown(); - - if( SPU2shutdown != NULL ) - SPU2shutdown(); - - if( CDVDshutdown != NULL ) - CDVDshutdown(); - - if( DEV9shutdown != NULL ) - DEV9shutdown(); - - if( USBshutdown != NULL ) - USBshutdown(); - - if( FWshutdown != NULL ) - FWshutdown(); -} - -int LoadPlugins() { - - if( loadp ) return 0; - string Plugin; - - Path::Combine( Plugin, Config.PluginsDir, Config.GS ); - if (LoadGSplugin(Plugin) == -1) return -1; - - Path::Combine( Plugin, Config.PluginsDir, Config.PAD1 ); - if (LoadPAD1plugin(Plugin) == -1) return -1; - - Path::Combine( Plugin, Config.PluginsDir, Config.PAD2); - if (LoadPAD2plugin(Plugin) == -1) return -1; - - Path::Combine( Plugin, Config.PluginsDir, Config.SPU2); - if (LoadSPU2plugin(Plugin) == -1) return -1; - - Path::Combine( Plugin, Config.PluginsDir, Config.CDVD); - if (LoadCDVDplugin(Plugin) == -1) return -1; - - Path::Combine( Plugin, Config.PluginsDir, Config.DEV9); - if (LoadDEV9plugin(Plugin) == -1) return -1; - - Path::Combine( Plugin, Config.PluginsDir, Config.USB); - if (LoadUSBplugin(Plugin) == -1) return -1; - - Path::Combine( Plugin, Config.PluginsDir, Config.FW); - if (LoadFWplugin(Plugin) == -1) return -1; - - if (InitPlugins() == -1) return -1; - - loadp=true; - - return 0; -} - -uptr pDsp; -extern void spu2DMA4Irq(); -extern void spu2DMA7Irq(); -extern void spu2Irq(); - -int OpenPlugins(const char* pTitleFilename) { - GSdriverInfo info; - int ret; - - if ( !loadp ) - throw Exception::InvalidOperation( "OpenPlugins cannot be called while the plugin state is uninitialized." ); - -#ifndef _WIN32 - // change dir so that CDVD can find its config file - char file[255], pNewTitle[255]; - getcwd(file, ARRAYSIZE(file)); - chdir(Config.PluginsDir); - - if( pTitleFilename != NULL && pTitleFilename[0] != '/' ) { - // because we are changing the dir, we have to set a new title if it is a relative dir - sprintf(pNewTitle, "%s/%s", file, pTitleFilename); - pTitleFilename = pNewTitle; - } -#endif - - if( !OpenStatus.CDVD ) - { - //first we need the data - if (CDVDnewDiskCB) CDVDnewDiskCB(cdvdNewDiskCB); - - ret = CDVDopen(pTitleFilename); - - if (ret != 0) { Msgbox::Alert("Error Opening CDVD Plugin"); goto OpenError; } - OpenStatus.CDVD = true; - cdvdNewDiskCB(); - } - - if( !OpenStatus.GS ) { - ret = gsOpen(); - if (ret != 0) { Msgbox::Alert("Error Opening GS Plugin"); goto OpenError; } - OpenStatus.GS = true; - - //then the user input - if (GSgetDriverInfo) { - GSgetDriverInfo(&info); - if (PAD1gsDriverInfo) PAD1gsDriverInfo(&info); - if (PAD2gsDriverInfo) PAD2gsDriverInfo(&info); - } - } - - if( !OpenStatus.PAD1 ) - { - ret = PAD1open((void *)&pDsp); - if (ret != 0) { Msgbox::Alert("Error Opening PAD1 Plugin"); goto OpenError; } - OpenStatus.PAD1 = true; - } - - if( !OpenStatus.PAD2 ) - { - ret = PAD2open((void *)&pDsp); - if (ret != 0) { Msgbox::Alert("Error Opening PAD2 Plugin"); goto OpenError; } - OpenStatus.PAD2 = true; - } - - //the sound - - if( !OpenStatus.SPU2 ) - { - SPU2irqCallback(spu2Irq,spu2DMA4Irq,spu2DMA7Irq); - if( SPU2setDMABaseAddr != NULL ) - SPU2setDMABaseAddr((uptr)psxM); - - if(SPU2setClockPtr != NULL) - SPU2setClockPtr(&psxRegs.cycle); - - ret = SPU2open((void*)&pDsp); - if (ret != 0) { Msgbox::Alert("Error Opening SPU2 Plugin"); goto OpenError; } - OpenStatus.SPU2 = true; - } - - //and last the dev9 - if( !OpenStatus.DEV9 ) - { - DEV9irqCallback(dev9Irq); - dev9Handler = DEV9irqHandler(); - ret = DEV9open(&psxRegs.pc); //((void *)&pDsp); - if (ret != 0) { Msgbox::Alert("Error Opening DEV9 Plugin"); goto OpenError; } - OpenStatus.DEV9 = true; - } - - if( !OpenStatus.USB ) - { - USBirqCallback(usbIrq); - usbHandler = USBirqHandler(); - USBsetRAM(psxM); - ret = USBopen((void *)&pDsp); - if (ret != 0) { Msgbox::Alert("Error Opening USB Plugin"); goto OpenError; } - OpenStatus.USB = true; - } - - if( !OpenStatus.FW ) - { - FWirqCallback(fwIrq); - ret = FWopen((void *)&pDsp); - if (ret != 0) { Msgbox::Alert("Error Opening FW Plugin"); goto OpenError; } - OpenStatus.FW = true; - } - -#ifdef __LINUX__ - chdir(file); -#endif - return 0; - -OpenError: - ClosePlugins(); -#ifdef __LINUX__ - chdir(file); -#endif - - return -1; -} - - -#define CLOSE_PLUGIN( name ) \ - if( OpenStatus.name ) { \ - name##close(); \ - OpenStatus.name = false; \ - } - - -void ClosePlugins() -{ - // GS plugin is special and is not always closed during emulation pauses. - // (that's because the GS is the most complicated plugin and to close it would - // require we save the GS state -- plus, Gsdx doesn't really support being - // closed) - - if( OpenStatus.GS ) - mtgsWaitGS(); - - CLOSE_PLUGIN( PAD1 ); - CLOSE_PLUGIN( PAD2 ); - - CLOSE_PLUGIN( CDVD ); - CLOSE_PLUGIN( DEV9 ); - CLOSE_PLUGIN( USB ); - CLOSE_PLUGIN( FW ); - CLOSE_PLUGIN( SPU2 ); -} - -void ResetPlugins() -{ - mtgsWaitGS(); - - ShutdownPlugins(); - InitPlugins(); -} - -void ReleasePlugins() -{ - if (!loadp) return; - - if (GSplugin == NULL || PAD1plugin == NULL || PAD2plugin == NULL || - SPU2plugin == NULL || CDVDplugin == NULL || DEV9plugin == NULL || - USBplugin == NULL || FWplugin == NULL) return; - - ShutdownPlugins(); - - SysCloseLibrary(GSplugin); GSplugin = NULL; - SysCloseLibrary(PAD1plugin); PAD1plugin = NULL; - SysCloseLibrary(PAD2plugin); PAD2plugin = NULL; - SysCloseLibrary(SPU2plugin); SPU2plugin = NULL; - SysCloseLibrary(CDVDplugin); CDVDplugin = NULL; - SysCloseLibrary(DEV9plugin); DEV9plugin = NULL; - SysCloseLibrary(USBplugin); USBplugin = NULL; - SysCloseLibrary(FWplugin); FWplugin = NULL; - loadp = false; -} - -void PluginsResetGS() -{ - CLOSE_PLUGIN( PAD1 ); - CLOSE_PLUGIN( PAD2 ); - - if( OpenStatus.GS ) - { - gsClose(); - OpenStatus.GS = false; - } - - if( OpenStatus.PAD1 ) - { - PAD1close(); - } - - GSshutdown(); - - int ret = GSinit(); - if (ret != 0) { Msgbox::Alert("GSinit error: %d", params ret); } -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "PsxCommon.h" +#include "GS.h" + +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgetLastTag GSgetLastTag; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSsetupRecording GSsetupRecording; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; +_PADupdate PAD1update; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; +_PADupdate PAD2update; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2setDMABaseAddr SPU2setDMABaseAddr; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2setupRecording SPU2setupRecording; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2setClockPtr SPU2setClockPtr; +_SPU2setTimeStretcher SPU2setTimeStretcher; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBasync USBasync; + +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; + + +DEV9handler dev9Handler; +USBhandler usbHandler; + +#define Sfy(x) #x +#define Strfy(x) Sfy(x) +#define MapSymbolVarType(var,type,name) var = (type)SysLoadSym(drv,Strfy(name)) +#define MapSymbolVar(var,name) MapSymbolVarType(var,_##name,name) +#define MapSymbolVar_Fallback(var,name,fallback) if((MapSymbolVar(var,name))==NULL) var = fallback +#define MapSymbolVar_Error(var,name) if((MapSymbolVar(var,name))==NULL) \ +{ \ + const char* errString = SysLibError(); \ + Msgbox::Alert("%s: Error loading %hs: %s", params &filename, #name, errString); \ + return -1; \ +} + +#define MapSymbol(name) MapSymbolVar(name,name) +#define MapSymbol_Fallback(name,fallback) MapSymbolVar_Fallback(name,name,fallback) +#define MapSymbol_Error(name) MapSymbolVar_Error(name,name) + +// for pad1/2 +#define MapSymbolPAD(var,sym,name) MapSymbolVar(var##name,sym##name) +#define MapSymbolPAD_Fallback(var,sym,name) if((MapSymbolVarType(var##name,_##sym##name,sym##name))==NULL) var##name = var##_##name +#define MapSymbolPAD_Error(var,sym,name) MapSymbolVar_Error(var##name,sym##name) + +#define TestPS2Esyms(type) if(_TestPS2Esyms(drv,PS2E_LT_##type,PS2E_##type##_VERSION,filename) < 0) return -1; + +int _TestPS2Esyms(void* drv, int type, int expected_version, const string& filename) +{ + _PS2EgetLibType PS2EgetLibType; + _PS2EgetLibVersion2 PS2EgetLibVersion2; + _PS2EgetLibName PS2EgetLibName; + + MapSymbol_Error(PS2EgetLibType); + MapSymbol_Error(PS2EgetLibVersion2); + MapSymbol_Error(PS2EgetLibName); + + int actual_version = ((PS2EgetLibVersion2(type) >> 16)&0xff); + + if( actual_version != expected_version) { + Msgbox::Alert("Can't load '%hs', wrong PS2E version (%x != %x)", params &filename, actual_version, expected_version); + return -1; + } + + return 0; +} + +//static const char *err; +//static int errval; + +void *GSplugin; + +void CALLBACK GS_printf(int timeout, char *fmt, ...) { + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + SysPrintf(msg); +} + +s32 CALLBACK GS_freeze(int mode, freezeData *data) { data->size = 0; return 0; } +void CALLBACK GS_keyEvent(keyEvent *ev) {} +void CALLBACK GS_makeSnapshot(const char *path) {} +void CALLBACK GS_irqCallback(void (*callback)()) {} +void CALLBACK GS_configure() {} +void CALLBACK GS_about() {} +s32 CALLBACK GS_test() { return 0; } + +int LoadGSplugin(const string& filename) +{ + void *drv; + + GSplugin = SysLoadLibrary(filename.c_str()); + if (GSplugin == NULL) { Msgbox::Alert ("Could Not Load GS Plugin '%hs': %s", params &filename, SysLibError()); return -1; } + drv = GSplugin; + TestPS2Esyms(GS); + MapSymbol_Error(GSinit); + MapSymbol_Error(GSshutdown); + MapSymbol_Error(GSopen); + MapSymbol_Error(GSclose); + MapSymbol_Error(GSgifTransfer1); + MapSymbol_Error(GSgifTransfer2); + MapSymbol_Error(GSgifTransfer3); + MapSymbol_Error(GSreadFIFO); + MapSymbol(GSgetLastTag); + MapSymbol(GSreadFIFO2); // optional + MapSymbol_Error(GSvsync); + + MapSymbol_Fallback(GSkeyEvent,GS_keyEvent); + MapSymbol(GSchangeSaveState); + MapSymbol(GSgifSoftReset); + MapSymbol_Fallback(GSmakeSnapshot,GS_makeSnapshot); + MapSymbol_Fallback(GSirqCallback,GS_irqCallback); + MapSymbol_Fallback(GSprintf,GS_printf); + MapSymbol_Error(GSsetBaseMem); + MapSymbol(GSsetGameCRC); + MapSymbol_Error(GSreset); + MapSymbol_Error(GSwriteCSR); + MapSymbol(GSmakeSnapshot2); + MapSymbol(GSgetDriverInfo); + + MapSymbol(GSsetFrameSkip); + MapSymbol(GSsetupRecording); + +#ifdef _WIN32 + MapSymbol(GSsetWindowInfo); +#endif + MapSymbol_Fallback(GSfreeze,GS_freeze); + MapSymbol_Fallback(GSconfigure,GS_configure); + MapSymbol_Fallback(GSabout,GS_about); + MapSymbol_Fallback(GStest,GS_test); + + return 0; +} + +void *PAD1plugin; + +void CALLBACK PAD1_configure() {} +void CALLBACK PAD1_about() {} +s32 CALLBACK PAD1_test() { return 0; } + +int LoadPAD1plugin(const string& filename) { + void *drv; + + PAD1plugin = SysLoadLibrary(filename.c_str()); + if (PAD1plugin == NULL) { Msgbox::Alert("Could Not Load PAD1 Plugin '%hs': %s", params &filename, SysLibError()); return -1; } + drv = PAD1plugin; + TestPS2Esyms(PAD); + MapSymbolPAD_Error(PAD1,PAD,init); + MapSymbolPAD_Error(PAD1,PAD,shutdown); + MapSymbolPAD_Error(PAD1,PAD,open); + MapSymbolPAD_Error(PAD1,PAD,close); + MapSymbolPAD_Error(PAD1,PAD,keyEvent); + MapSymbolPAD_Error(PAD1,PAD,startPoll); + MapSymbolPAD_Error(PAD1,PAD,poll); + MapSymbolPAD_Error(PAD1,PAD,query); + MapSymbolPAD(PAD1,PAD,update); + + MapSymbolPAD(PAD1,PAD,gsDriverInfo); + MapSymbolPAD_Fallback(PAD1,PAD,configure); + MapSymbolPAD_Fallback(PAD1,PAD,about); + MapSymbolPAD_Fallback(PAD1,PAD,test); + + return 0; +} + +void *PAD2plugin; + +void CALLBACK PAD2_configure() {} +void CALLBACK PAD2_about() {} +s32 CALLBACK PAD2_test() { return 0; } + +int LoadPAD2plugin(const string& filename) { + void *drv; + + PAD2plugin = SysLoadLibrary(filename.c_str()); + if (PAD2plugin == NULL) { Msgbox::Alert("Could Not Load PAD2 Plugin '%hs': %s", params &filename, SysLibError()); return -1; } + drv = PAD2plugin; + TestPS2Esyms(PAD); + MapSymbolPAD_Error(PAD2,PAD,init); + MapSymbolPAD_Error(PAD2,PAD,shutdown); + MapSymbolPAD_Error(PAD2,PAD,open); + MapSymbolPAD_Error(PAD2,PAD,close); + MapSymbolPAD_Error(PAD2,PAD,keyEvent); + MapSymbolPAD_Error(PAD2,PAD,startPoll); + MapSymbolPAD_Error(PAD2,PAD,poll); + MapSymbolPAD_Error(PAD2,PAD,query); + MapSymbolPAD(PAD2,PAD,update); + + MapSymbolPAD(PAD2,PAD,gsDriverInfo); + MapSymbolPAD_Fallback(PAD2,PAD,configure); + MapSymbolPAD_Fallback(PAD2,PAD,about); + MapSymbolPAD_Fallback(PAD2,PAD,test); + + return 0; +} + +void *SPU2plugin; + +s32 CALLBACK SPU2_freeze(int mode, freezeData *data) { data->size = 0; return 0; } +void CALLBACK SPU2_configure() {} +void CALLBACK SPU2_about() {} +s32 CALLBACK SPU2_test() { return 0; } + +int LoadSPU2plugin(const string& filename) { + void *drv; + + SPU2plugin = SysLoadLibrary(filename.c_str()); + if (SPU2plugin == NULL) { Msgbox::Alert("Could Not Load SPU2 Plugin '%hs': %s", params &filename, SysLibError()); return -1; } + drv = SPU2plugin; + TestPS2Esyms(SPU2); + MapSymbol_Error(SPU2init); + MapSymbol_Error(SPU2shutdown); + MapSymbol_Error(SPU2open); + MapSymbol_Error(SPU2close); + MapSymbol_Error(SPU2write); + MapSymbol_Error(SPU2read); + MapSymbol_Error(SPU2readDMA4Mem); + MapSymbol_Error(SPU2writeDMA4Mem); + MapSymbol_Error(SPU2interruptDMA4); + MapSymbol_Error(SPU2readDMA7Mem); + MapSymbol_Error(SPU2writeDMA7Mem); + MapSymbol_Error(SPU2interruptDMA7); + MapSymbol(SPU2setDMABaseAddr); + MapSymbol_Error(SPU2ReadMemAddr); + MapSymbol_Error(SPU2WriteMemAddr); + MapSymbol_Error(SPU2irqCallback); + + MapSymbol(SPU2setClockPtr); + + MapSymbol(SPU2setupRecording); + + MapSymbol_Fallback(SPU2freeze,SPU2_freeze); + MapSymbol_Fallback(SPU2configure,SPU2_configure); + MapSymbol_Fallback(SPU2about,SPU2_about); + MapSymbol_Fallback(SPU2test,SPU2_test); + MapSymbol(SPU2async); + + return 0; +} + +void *CDVDplugin; + +void CALLBACK CDVD_configure() {} +void CALLBACK CDVD_about() {} +s32 CALLBACK CDVD_test() { return 0; } + +int LoadCDVDplugin(const string& filename) { + void *drv; + + CDVDplugin = SysLoadLibrary(filename.c_str()); + if (CDVDplugin == NULL) { Msgbox::Alert("Could Not Load CDVD Plugin '%hs': %s", params &filename, SysLibError()); return -1; } + drv = CDVDplugin; + TestPS2Esyms(CDVD); + MapSymbol_Error(CDVDinit); + MapSymbol_Error(CDVDshutdown); + MapSymbol_Error(CDVDopen); + MapSymbol_Error(CDVDclose); + MapSymbol_Error(CDVDreadTrack); + MapSymbol_Error(CDVDgetBuffer); + MapSymbol_Error(CDVDreadSubQ); + MapSymbol_Error(CDVDgetTN); + MapSymbol_Error(CDVDgetTD); + MapSymbol_Error(CDVDgetTOC); + MapSymbol_Error(CDVDgetDiskType); + MapSymbol_Error(CDVDgetTrayStatus); + MapSymbol_Error(CDVDctrlTrayOpen); + MapSymbol_Error(CDVDctrlTrayClose); + + MapSymbol_Fallback(CDVDconfigure,CDVD_configure); + MapSymbol_Fallback(CDVDabout,CDVD_about); + MapSymbol_Fallback(CDVDtest,CDVD_test); + MapSymbol(CDVDnewDiskCB); + + return 0; +} + +void *DEV9plugin; + +s32 CALLBACK DEV9_freeze(int mode, freezeData *data) { data->size = 0; return 0; } +void CALLBACK DEV9_configure() {} +void CALLBACK DEV9_about() {} +s32 CALLBACK DEV9_test() { return 0; } + +int LoadDEV9plugin(const string& filename) { + void *drv; + + DEV9plugin = SysLoadLibrary(filename.c_str()); + if (DEV9plugin == NULL) { Msgbox::Alert("Could Not Load DEV9 Plugin '%hs': %s", params &filename, SysLibError()); return -1; } + drv = DEV9plugin; + TestPS2Esyms(DEV9); + MapSymbol_Error(DEV9init); + MapSymbol_Error(DEV9shutdown); + MapSymbol_Error(DEV9open); + MapSymbol_Error(DEV9close); + MapSymbol_Error(DEV9read8); + MapSymbol_Error(DEV9read16); + MapSymbol_Error(DEV9read32); + MapSymbol_Error(DEV9write8); + MapSymbol_Error(DEV9write16); + MapSymbol_Error(DEV9write32); + MapSymbol_Error(DEV9readDMA8Mem); + MapSymbol_Error(DEV9writeDMA8Mem); + MapSymbol_Error(DEV9irqCallback); + MapSymbol_Error(DEV9irqHandler); + + MapSymbol_Fallback(DEV9freeze,DEV9_freeze); + MapSymbol_Fallback(DEV9configure,DEV9_configure); + MapSymbol_Fallback(DEV9about,DEV9_about); + MapSymbol_Fallback(DEV9test,DEV9_test); + + return 0; +} + +void *USBplugin; + +s32 CALLBACK USB_freeze(int mode, freezeData *data) { data->size = 0; return 0; } +void CALLBACK USB_configure() {} +void CALLBACK USB_about() {} +s32 CALLBACK USB_test() { return 0; } + +int LoadUSBplugin(const string& filename) { + void *drv; + + USBplugin = SysLoadLibrary(filename.c_str()); + if (USBplugin == NULL) { Msgbox::Alert("Could Not Load USB Plugin '%hs': %s", params &filename, SysLibError()); return -1; } + drv = USBplugin; + TestPS2Esyms(USB); + MapSymbol_Error(USBinit); + MapSymbol_Error(USBshutdown); + MapSymbol_Error(USBopen); + MapSymbol_Error(USBclose); + MapSymbol_Error(USBread8); + MapSymbol_Error(USBread16); + MapSymbol_Error(USBread32); + MapSymbol_Error(USBwrite8); + MapSymbol_Error(USBwrite16); + MapSymbol_Error(USBwrite32); + MapSymbol_Error(USBirqCallback); + MapSymbol_Error(USBirqHandler); + MapSymbol_Error(USBsetRAM); + + MapSymbol(USBasync); + + MapSymbol_Fallback(USBfreeze,USB_freeze); + MapSymbol_Fallback(USBconfigure,USB_configure); + MapSymbol_Fallback(USBabout,USB_about); + MapSymbol_Fallback(USBtest,USB_test); + + return 0; +} +void *FWplugin; + +s32 CALLBACK FW_freeze(int mode, freezeData *data) { data->size = 0; return 0; } +void CALLBACK FW_configure() {} +void CALLBACK FW_about() {} +s32 CALLBACK FW_test() { return 0; } + +int LoadFWplugin(const string& filename) { + void *drv; + + FWplugin = SysLoadLibrary(filename.c_str()); + if (FWplugin == NULL) { Msgbox::Alert("Could Not Load FW Plugin '%hs': %s", params &filename, SysLibError()); return -1; } + drv = FWplugin; + TestPS2Esyms(FW); + MapSymbol_Error(FWinit); + MapSymbol_Error(FWshutdown); + MapSymbol_Error(FWopen); + MapSymbol_Error(FWclose); + MapSymbol_Error(FWread32); + MapSymbol_Error(FWwrite32); + MapSymbol_Error(FWirqCallback); + + MapSymbol_Fallback(FWfreeze,FW_freeze); + MapSymbol_Fallback(FWconfigure,FW_configure); + MapSymbol_Fallback(FWabout,FW_about); + MapSymbol_Fallback(FWtest,FW_test); + + return 0; +} + +struct PluginOpenStatusFlags +{ + u8 GS : 1 + , CDVD : 1 + , DEV9 : 1 + , USB : 1 + , SPU2 : 1 + , PAD1 : 1 + , PAD2 : 1 + , FW : 1; + +}; + +static PluginOpenStatusFlags OpenStatus = {0}; + +static bool loadp=false; + +int InitPlugins() { + int ret; + + ret = GSinit(); + if (ret != 0) { Msgbox::Alert("GSinit error: %d", params ret); return -1; } + ret = PAD1init(1); + if (ret != 0) { Msgbox::Alert("PAD1init error: %d", params ret); return -1; } + ret = PAD2init(2); + if (ret != 0) { Msgbox::Alert("PAD2init error: %d", params ret); return -1; } + ret = SPU2init(); + if (ret != 0) { Msgbox::Alert("SPU2init error: %d", params ret); return -1; } + ret = CDVDinit(); + if (ret != 0) { Msgbox::Alert("CDVDinit error: %d", params ret); return -1; } + ret = DEV9init(); + if (ret != 0) { Msgbox::Alert("DEV9init error: %d", params ret); return -1; } + ret = USBinit(); + if (ret != 0) { Msgbox::Alert("USBinit error: %d", params ret); return -1; } + ret = FWinit(); + if (ret != 0) { Msgbox::Alert("FWinit error: %d", params ret); return -1; } + return 0; +} + +void ShutdownPlugins() +{ + ClosePlugins(); + + // GS is a special case: It needs closed first usually. + // (the GS isn't always closed during emulation pauses) + if( OpenStatus.GS ) + { + gsClose(); + OpenStatus.GS = false; + } + + if( GSshutdown != NULL ) + GSshutdown(); + + if( PAD1shutdown != NULL ) + PAD1shutdown(); + if( PAD2shutdown != NULL ) + PAD2shutdown(); + + if( SPU2shutdown != NULL ) + SPU2shutdown(); + + if( CDVDshutdown != NULL ) + CDVDshutdown(); + + if( DEV9shutdown != NULL ) + DEV9shutdown(); + + if( USBshutdown != NULL ) + USBshutdown(); + + if( FWshutdown != NULL ) + FWshutdown(); +} + +int LoadPlugins() { + + if( loadp ) return 0; + string Plugin; + + Path::Combine( Plugin, Config.PluginsDir, Config.GS ); + if (LoadGSplugin(Plugin) == -1) return -1; + + Path::Combine( Plugin, Config.PluginsDir, Config.PAD1 ); + if (LoadPAD1plugin(Plugin) == -1) return -1; + + Path::Combine( Plugin, Config.PluginsDir, Config.PAD2); + if (LoadPAD2plugin(Plugin) == -1) return -1; + + Path::Combine( Plugin, Config.PluginsDir, Config.SPU2); + if (LoadSPU2plugin(Plugin) == -1) return -1; + + Path::Combine( Plugin, Config.PluginsDir, Config.CDVD); + if (LoadCDVDplugin(Plugin) == -1) return -1; + + Path::Combine( Plugin, Config.PluginsDir, Config.DEV9); + if (LoadDEV9plugin(Plugin) == -1) return -1; + + Path::Combine( Plugin, Config.PluginsDir, Config.USB); + if (LoadUSBplugin(Plugin) == -1) return -1; + + Path::Combine( Plugin, Config.PluginsDir, Config.FW); + if (LoadFWplugin(Plugin) == -1) return -1; + + if (InitPlugins() == -1) return -1; + + loadp=true; + + return 0; +} + +uptr pDsp; +extern void spu2DMA4Irq(); +extern void spu2DMA7Irq(); +extern void spu2Irq(); + +int OpenPlugins(const char* pTitleFilename) { + GSdriverInfo info; + int ret; + + if ( !loadp ) + throw Exception::InvalidOperation( "OpenPlugins cannot be called while the plugin state is uninitialized." ); + +#ifndef _WIN32 + // change dir so that CDVD can find its config file + char file[255], pNewTitle[255]; + getcwd(file, ARRAYSIZE(file)); + chdir(Config.PluginsDir); + + if( pTitleFilename != NULL && pTitleFilename[0] != '/' ) { + // because we are changing the dir, we have to set a new title if it is a relative dir + sprintf(pNewTitle, "%s/%s", file, pTitleFilename); + pTitleFilename = pNewTitle; + } +#endif + + if( !OpenStatus.CDVD ) + { + //first we need the data + if (CDVDnewDiskCB) CDVDnewDiskCB(cdvdNewDiskCB); + + ret = CDVDopen(pTitleFilename); + + if (ret != 0) { Msgbox::Alert("Error Opening CDVD Plugin"); goto OpenError; } + OpenStatus.CDVD = true; + cdvdNewDiskCB(); + } + + if( !OpenStatus.GS ) { + ret = gsOpen(); + if (ret != 0) { Msgbox::Alert("Error Opening GS Plugin"); goto OpenError; } + OpenStatus.GS = true; + + //then the user input + if (GSgetDriverInfo) { + GSgetDriverInfo(&info); + if (PAD1gsDriverInfo) PAD1gsDriverInfo(&info); + if (PAD2gsDriverInfo) PAD2gsDriverInfo(&info); + } + } + + if( !OpenStatus.PAD1 ) + { + ret = PAD1open((void *)&pDsp); + if (ret != 0) { Msgbox::Alert("Error Opening PAD1 Plugin"); goto OpenError; } + OpenStatus.PAD1 = true; + } + + if( !OpenStatus.PAD2 ) + { + ret = PAD2open((void *)&pDsp); + if (ret != 0) { Msgbox::Alert("Error Opening PAD2 Plugin"); goto OpenError; } + OpenStatus.PAD2 = true; + } + + //the sound + + if( !OpenStatus.SPU2 ) + { + SPU2irqCallback(spu2Irq,spu2DMA4Irq,spu2DMA7Irq); + if( SPU2setDMABaseAddr != NULL ) + SPU2setDMABaseAddr((uptr)psxM); + + if(SPU2setClockPtr != NULL) + SPU2setClockPtr(&psxRegs.cycle); + + ret = SPU2open((void*)&pDsp); + if (ret != 0) { Msgbox::Alert("Error Opening SPU2 Plugin"); goto OpenError; } + OpenStatus.SPU2 = true; + } + + //and last the dev9 + if( !OpenStatus.DEV9 ) + { + DEV9irqCallback(dev9Irq); + dev9Handler = DEV9irqHandler(); + ret = DEV9open(&psxRegs.pc); //((void *)&pDsp); + if (ret != 0) { Msgbox::Alert("Error Opening DEV9 Plugin"); goto OpenError; } + OpenStatus.DEV9 = true; + } + + if( !OpenStatus.USB ) + { + USBirqCallback(usbIrq); + usbHandler = USBirqHandler(); + USBsetRAM(psxM); + ret = USBopen((void *)&pDsp); + if (ret != 0) { Msgbox::Alert("Error Opening USB Plugin"); goto OpenError; } + OpenStatus.USB = true; + } + + if( !OpenStatus.FW ) + { + FWirqCallback(fwIrq); + ret = FWopen((void *)&pDsp); + if (ret != 0) { Msgbox::Alert("Error Opening FW Plugin"); goto OpenError; } + OpenStatus.FW = true; + } + +#ifdef __LINUX__ + chdir(file); +#endif + return 0; + +OpenError: + ClosePlugins(); +#ifdef __LINUX__ + chdir(file); +#endif + + return -1; +} + + +#define CLOSE_PLUGIN( name ) \ + if( OpenStatus.name ) { \ + name##close(); \ + OpenStatus.name = false; \ + } + + +void ClosePlugins() +{ + // GS plugin is special and is not always closed during emulation pauses. + // (that's because the GS is the most complicated plugin and to close it would + // require we save the GS state -- plus, Gsdx doesn't really support being + // closed) + + if( OpenStatus.GS ) + mtgsWaitGS(); + + CLOSE_PLUGIN( PAD1 ); + CLOSE_PLUGIN( PAD2 ); + + CLOSE_PLUGIN( CDVD ); + CLOSE_PLUGIN( DEV9 ); + CLOSE_PLUGIN( USB ); + CLOSE_PLUGIN( FW ); + CLOSE_PLUGIN( SPU2 ); +} + +void ResetPlugins() +{ + mtgsWaitGS(); + + ShutdownPlugins(); + InitPlugins(); +} + +void ReleasePlugins() +{ + if (!loadp) return; + + if (GSplugin == NULL || PAD1plugin == NULL || PAD2plugin == NULL || + SPU2plugin == NULL || CDVDplugin == NULL || DEV9plugin == NULL || + USBplugin == NULL || FWplugin == NULL) return; + + ShutdownPlugins(); + + SysCloseLibrary(GSplugin); GSplugin = NULL; + SysCloseLibrary(PAD1plugin); PAD1plugin = NULL; + SysCloseLibrary(PAD2plugin); PAD2plugin = NULL; + SysCloseLibrary(SPU2plugin); SPU2plugin = NULL; + SysCloseLibrary(CDVDplugin); CDVDplugin = NULL; + SysCloseLibrary(DEV9plugin); DEV9plugin = NULL; + SysCloseLibrary(USBplugin); USBplugin = NULL; + SysCloseLibrary(FWplugin); FWplugin = NULL; + loadp = false; +} + +void PluginsResetGS() +{ + CLOSE_PLUGIN( PAD1 ); + CLOSE_PLUGIN( PAD2 ); + + if( OpenStatus.GS ) + { + gsClose(); + OpenStatus.GS = false; + } + + if( OpenStatus.PAD1 ) + { + PAD1close(); + } + + GSshutdown(); + + int ret = GSinit(); + if (ret != 0) { Msgbox::Alert("GSinit error: %d", params ret); } +} diff --git a/pcsx2/Plugins.h b/pcsx2/Plugins.h index 0509c15bdc..a9759fded6 100644 --- a/pcsx2/Plugins.h +++ b/pcsx2/Plugins.h @@ -1,45 +1,45 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __PLUGINS_H__ -#define __PLUGINS_H__ - -#define PLUGINtypedefs -#define PLUGINfuncs -#include "PS2Edefs.h" - -// Loads plugins as specified in the Config global. -int LoadPlugins(); - -// Unloads all plugin DLLs. To change plugins, call ReleasePlugins followed by -// changes to Config.Plugins filenames, and then call LoadPlugins. -void ReleasePlugins(); - -int OpenPlugins(const char* pTitleFilename); -void ClosePlugins(); - -int InitPlugins(); - -// Completely shuts down all plugins and re-initializes them. (clean slate) -// Plugins are not unloaded, so changes to Config.Plugins values will not -// take effect. Use a manual set oc alls to ReleasePlugins and LoadPlugins for that. -void ResetPlugins(); - -void PluginsResetGS(); - -#endif /* __PLUGINS_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __PLUGINS_H__ +#define __PLUGINS_H__ + +#define PLUGINtypedefs +#define PLUGINfuncs +#include "PS2Edefs.h" + +// Loads plugins as specified in the Config global. +int LoadPlugins(); + +// Unloads all plugin DLLs. To change plugins, call ReleasePlugins followed by +// changes to Config.Plugins filenames, and then call LoadPlugins. +void ReleasePlugins(); + +int OpenPlugins(const char* pTitleFilename); +void ClosePlugins(); + +int InitPlugins(); + +// Completely shuts down all plugins and re-initializes them. (clean slate) +// Plugins are not unloaded, so changes to Config.Plugins values will not +// take effect. Use a manual set oc alls to ReleasePlugins and LoadPlugins for that. +void ResetPlugins(); + +void PluginsResetGS(); + +#endif /* __PLUGINS_H__ */ diff --git a/pcsx2/PrecompiledHeader.h b/pcsx2/PrecompiledHeader.h index 98edbb7016..72836c11d9 100644 --- a/pcsx2/PrecompiledHeader.h +++ b/pcsx2/PrecompiledHeader.h @@ -1,118 +1,118 @@ -#ifndef _PCSX2_PRECOMPILED_HEADER_ -#define _PCSX2_PRECOMPILED_HEADER_ - -#if defined (__linux__) // some distributions are lower case -# define __LINUX__ -#endif - -#ifndef _WIN32 -# include -#else - -// For now Windows headers are needed by all modules, so include it here so -// that it compiles nice and fast... - -// Force availability of to WinNT APIs (change to 0x600 to enable XP-specific APIs) -# define WINVER 0x0501 -# define _WIN32_WINNT 0x0501 - -# include - -// disable Windows versions of min/max -- we'll use the typesafe STL versions instead. -#undef min -#undef max - -#endif - -// Include the STL junk that's actually handy. - -#include -#include -#include -#include -#include // string.h under c++ -#include // stdio.h under c++ -#include -#include - -// ... and include some ANSI/POSIX C libs that are useful too, just for good measure. -// (these compile lightning fast with or without PCH, but they never change so -// might as well add them here) - -#include -#include -#include -#include -#include - -// TODO : Add items here that are local to Pcsx2 but stay relatively unchanged for -// long periods of time. - -#ifdef _WIN32 -// disable warning C4244: '=' : conversion from 'big' to 'small', possible loss of data -#pragma warning(disable:4244) -#endif - -using std::string; // we use it enough, so bring it into the global namespace. - -#include "zlib.h" -#include "PS2Etypes.h" -#include "StringUtils.h" - -//////////////////////////////////////////////////////////////////// -// Compiler/OS specific macros and defines -- Begin Section - -#if defined(_MSC_VER) - -# define strnicmp _strnicmp -# define stricmp _stricmp - -#else // must be GCC... - -# include -# include - -// Definitions added Feb 16, 2006 by efp -# ifndef __declspec -# define __declspec(x) -# endif - -// functions that linux lacks... -// fixme: this should probably be in a __LINUX__ conditional rather than -// a GCC conditional (since GCC on a windows platform would have these functions) -# define Sleep(seconds) usleep(1000*(seconds)) - -static __forceinline u32 timeGetTime() -{ - struct timeb t; - ftime(&t); - return (u32)(t.time*1000+t.millitm); -} - -# define BOOL int - -# undef TRUE -# undef FALSE -# define TRUE 1 -# define FALSE 0 - -# ifndef strnicmp -# define strnicmp strncasecmp -# endif - -# ifndef stricmp -# define stricmp strcasecmp -# endif - -#endif // end GCC/Linux stuff - -// compile-time assert -#ifndef C_ASSERT -# define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#ifndef __LINUX__ -# define __unused -#endif - -#endif +#ifndef _PCSX2_PRECOMPILED_HEADER_ +#define _PCSX2_PRECOMPILED_HEADER_ + +#if defined (__linux__) // some distributions are lower case +# define __LINUX__ +#endif + +#ifndef _WIN32 +# include +#else + +// For now Windows headers are needed by all modules, so include it here so +// that it compiles nice and fast... + +// Force availability of to WinNT APIs (change to 0x600 to enable XP-specific APIs) +# define WINVER 0x0501 +# define _WIN32_WINNT 0x0501 + +# include + +// disable Windows versions of min/max -- we'll use the typesafe STL versions instead. +#undef min +#undef max + +#endif + +// Include the STL junk that's actually handy. + +#include +#include +#include +#include +#include // string.h under c++ +#include // stdio.h under c++ +#include +#include + +// ... and include some ANSI/POSIX C libs that are useful too, just for good measure. +// (these compile lightning fast with or without PCH, but they never change so +// might as well add them here) + +#include +#include +#include +#include +#include + +// TODO : Add items here that are local to Pcsx2 but stay relatively unchanged for +// long periods of time. + +#ifdef _WIN32 +// disable warning C4244: '=' : conversion from 'big' to 'small', possible loss of data +#pragma warning(disable:4244) +#endif + +using std::string; // we use it enough, so bring it into the global namespace. + +#include "zlib.h" +#include "PS2Etypes.h" +#include "StringUtils.h" + +//////////////////////////////////////////////////////////////////// +// Compiler/OS specific macros and defines -- Begin Section + +#if defined(_MSC_VER) + +# define strnicmp _strnicmp +# define stricmp _stricmp + +#else // must be GCC... + +# include +# include + +// Definitions added Feb 16, 2006 by efp +# ifndef __declspec +# define __declspec(x) +# endif + +// functions that linux lacks... +// fixme: this should probably be in a __LINUX__ conditional rather than +// a GCC conditional (since GCC on a windows platform would have these functions) +# define Sleep(seconds) usleep(1000*(seconds)) + +static __forceinline u32 timeGetTime() +{ + struct timeb t; + ftime(&t); + return (u32)(t.time*1000+t.millitm); +} + +# define BOOL int + +# undef TRUE +# undef FALSE +# define TRUE 1 +# define FALSE 0 + +# ifndef strnicmp +# define strnicmp strncasecmp +# endif + +# ifndef stricmp +# define stricmp strcasecmp +# endif + +#endif // end GCC/Linux stuff + +// compile-time assert +#ifndef C_ASSERT +# define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#ifndef __LINUX__ +# define __unused +#endif + +#endif diff --git a/pcsx2/PsxCommon.h b/pcsx2/PsxCommon.h index ea669ab79e..a8fd2a14f3 100644 --- a/pcsx2/PsxCommon.h +++ b/pcsx2/PsxCommon.h @@ -1,53 +1,53 @@ -/* Pcsx2 - Pc Ps2 Emulator * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __PSXCOMMON_H__ -#define __PSXCOMMON_H__ - -#ifdef _WIN32 -#include -#endif - -#include "PS2Etypes.h" - -#include - -#include "System.h" -#include - -extern long LoadCdBios; -extern int cdOpenCase; - -#define PSXCLK (36864000ULL) /* 36.864 Mhz */ - -#include "Plugins.h" -#include "R3000A.h" -#include "IopMem.h" -#include "IopHw.h" -#include "IopBios.h" -#include "IopDma.h" -#include "IopCounters.h" -#include "CdRom.h" -#include "Sio.h" -#include "DebugTools/Debug.h" -#include "IopSio2.h" -#include "CDVD.h" -#include "Memory.h" -#include "Hw.h" -#include "Sif.h" - -#endif /* __PSXCOMMON_H__ */ +/* Pcsx2 - Pc Ps2 Emulator * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __PSXCOMMON_H__ +#define __PSXCOMMON_H__ + +#ifdef _WIN32 +#include +#endif + +#include "PS2Etypes.h" + +#include + +#include "System.h" +#include + +extern long LoadCdBios; +extern int cdOpenCase; + +#define PSXCLK (36864000ULL) /* 36.864 Mhz */ + +#include "Plugins.h" +#include "R3000A.h" +#include "IopMem.h" +#include "IopHw.h" +#include "IopBios.h" +#include "IopDma.h" +#include "IopCounters.h" +#include "CdRom.h" +#include "Sio.h" +#include "DebugTools/Debug.h" +#include "IopSio2.h" +#include "CDVD.h" +#include "Memory.h" +#include "Hw.h" +#include "Sif.h" + +#endif /* __PSXCOMMON_H__ */ diff --git a/pcsx2/R3000A.cpp b/pcsx2/R3000A.cpp index 54fb9f9a20..3df38c7d43 100644 --- a/pcsx2/R3000A.cpp +++ b/pcsx2/R3000A.cpp @@ -1,283 +1,283 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "PsxCommon.h" -#include "Misc.h" - -using namespace R3000A; - -R3000Acpu *psxCpu; - -// used for constant propagation -u32 g_psxConstRegs[32]; -u32 g_psxHasConstReg, g_psxFlushedConstReg; - -// Controls when branch tests are performed. -u32 g_psxNextBranchCycle = 0; - -// This value is used when the IOP execution is broken to return control to the EE. -// (which happens when the IOP throws EE-bound interrupts). It holds the value of -// psxCycleEE (which is set to zero to facilitate the code break), so that the unrun -// cycles can be accounted for later. -s32 psxBreak = 0; - -// tracks the IOP's current sync status with the EE. When it dips below zero, -// control is returned to the EE. -s32 psxCycleEE = -1; - -// Used to signal to the EE when important actions that need IOP-attention have -// happened (hsyncs, vsyncs, IOP exceptions, etc). IOP runs code whenever this -// is true, even if it's already running ahead a bit. -bool iopBranchAction = false; - -bool iopEventTestIsActive = false; - -PCSX2_ALIGNED16(psxRegisters psxRegs); - -void psxReset() -{ - memzero_obj(psxRegs); - - psxRegs.pc = 0xbfc00000; // Start in bootstrap - psxRegs.CP0.n.Status = 0x10900000; // COP0 enabled | BEV = 1 | TS = 1 - psxRegs.CP0.n.PRid = 0x0000001f; // PRevID = Revision ID, same as the IOP R3000A - - psxBreak = 0; - psxCycleEE = -1; - g_psxNextBranchCycle = psxRegs.cycle + 4; - - psxHwReset(); - psxBiosInit(); - //psxExecuteBios(); -} - -void psxShutdown() { - psxBiosShutdown(); - psxSIOShutdown(); - //psxCpu->Shutdown(); -} - -void psxException(u32 code, u32 bd) { -// PSXCPU_LOG("psxException %x: %x, %x\n", code, psxHu32(0x1070), psxHu32(0x1074)); - //SysPrintf("!! psxException %x: %x, %x\n", code, psxHu32(0x1070), psxHu32(0x1074)); - // Set the Cause - psxRegs.CP0.n.Cause &= ~0x7f; - psxRegs.CP0.n.Cause |= code; - - // Set the EPC & PC - if (bd) - { - PSXCPU_LOG("bd set\n"); - psxRegs.CP0.n.Cause|= 0x80000000; - psxRegs.CP0.n.EPC = (psxRegs.pc - 4); - } - else - psxRegs.CP0.n.EPC = (psxRegs.pc); - - if (psxRegs.CP0.n.Status & 0x400000) - psxRegs.pc = 0xbfc00180; - else - psxRegs.pc = 0x80000080; - - // Set the Status - psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status &~0x3f) | - ((psxRegs.CP0.n.Status & 0xf) << 2); - - /*if ((((PSXMu32(psxRegs.CP0.n.EPC) >> 24) & 0xfe) == 0x4a)) { - // "hokuto no ken" / "Crash Bandicot 2" ... fix - PSXMu32(psxRegs.CP0.n.EPC)&= ~0x02000000; - }*/ - - if (Config.PsxOut && !CHECK_EEREC) { - u32 call = psxRegs.GPR.n.t1 & 0xff; - switch (psxRegs.pc & 0x1fffff) { - case 0xa0: - - if (call != 0x28 && call != 0xe) - PSXBIOS_LOG("Bios call a0: %s (%x) %x,%x,%x,%x\n", biosA0n[call], call, psxRegs.GPR.n.a0, psxRegs.GPR.n.a1, psxRegs.GPR.n.a2, psxRegs.GPR.n.a3); - - if (biosA0[call]) - biosA0[call](); - break; - - case 0xb0: - if (call != 0x17 && call != 0xb) - PSXBIOS_LOG("Bios call b0: %s (%x) %x,%x,%x,%x\n", biosB0n[call], call, psxRegs.GPR.n.a0, psxRegs.GPR.n.a1, psxRegs.GPR.n.a2, psxRegs.GPR.n.a3); - - if (biosB0[call]) - biosB0[call](); - break; - - case 0xc0: - PSXBIOS_LOG("Bios call c0: %s (%x) %x,%x,%x,%x\n", biosC0n[call], call, psxRegs.GPR.n.a0, psxRegs.GPR.n.a1, psxRegs.GPR.n.a2, psxRegs.GPR.n.a3); - - if (biosC0[call]) - biosC0[call](); - break; - } - } - - /*if (psxRegs.CP0.n.Cause == 0x400 && (!(psxHu32(0x1450) & 0x8))) { - hwIntcIrq(1); - }*/ -} - -__forceinline void psxSetNextBranch( u32 startCycle, s32 delta ) -{ - // typecast the conditional to signed so that things don't blow up - // if startCycle is greater than our next branch cycle. - - if( (int)(g_psxNextBranchCycle - startCycle) > delta ) - g_psxNextBranchCycle = startCycle + delta; -} - -__forceinline void psxSetNextBranchDelta( s32 delta ) -{ - psxSetNextBranch( psxRegs.cycle, delta ); -} - -__forceinline int psxTestCycle( u32 startCycle, s32 delta ) -{ - // typecast the conditional to signed so that things don't explode - // if the startCycle is ahead of our current cpu cycle. - - return (int)(psxRegs.cycle - startCycle) >= delta; -} - -__forceinline void PSX_INT( IopEventId n, s32 ecycle ) -{ - // Generally speaking games shouldn't throw ints that haven't been cleared yet. - // It's usually indicative os something amiss in our emulation, so uncomment this - // code to help trap those sort of things. - - // Exception: IRQ16 - SIO - it drops ints like crazy when handling PAD stuff. - //if( /*n!=16 &&*/ psxRegs.interrupt & (1< Twice-thrown int on IRQ %d\n", n ); - - psxRegs.interrupt |= 1 << n; - - psxRegs.sCycle[n] = psxRegs.cycle; - psxRegs.eCycle[n] = ecycle; - - psxSetNextBranchDelta( ecycle ); - - if( psxCycleEE < 0 ) - { - // The EE called this int, so inform it to branch as needed: - // fixme - this doesn't take into account EE/IOP sync (the IOP may be running - // ahead or behind the EE as per the EEsCycles value) - s32 iopDelta = (g_psxNextBranchCycle-psxRegs.cycle)*8; - cpuSetNextBranchDelta( iopDelta ); - } -} - -static __forceinline void IopTestEvent( IopEventId n, void (*callback)() ) -{ - if( !(psxRegs.interrupt & (1 << n)) ) return; - - if( psxTestCycle( psxRegs.sCycle[n], psxRegs.eCycle[n] ) ) - { - psxRegs.interrupt &= ~(1 << n); - callback(); - } - else - psxSetNextBranch( psxRegs.sCycle[n], psxRegs.eCycle[n] ); -} - -static __forceinline void _psxTestInterrupts() -{ - IopTestEvent(IopEvt_SIF0, sif0Interrupt); // SIF0 - IopTestEvent(IopEvt_SIF1, sif1Interrupt); // SIF1 - IopTestEvent(IopEvt_SIO, sioInterrupt); - IopTestEvent(IopEvt_CdvdRead, cdvdReadInterrupt); - - // Profile-guided Optimization (sorta) - // The following ints are rarely called. Encasing them in a conditional - // as follows helps speed up most games. - - if( psxRegs.interrupt & ( (1ul<<5) | (3ul<<11) | (3ul<<20) | (3ul<<17) ) ) - { - IopTestEvent(IopEvt_Cdvd, cdvdActionInterrupt); - IopTestEvent(IopEvt_Dma11, psxDMA11Interrupt); // SIO2 - IopTestEvent(IopEvt_Dma12, psxDMA12Interrupt); // SIO2 - IopTestEvent(IopEvt_Cdrom, cdrInterrupt); - IopTestEvent(IopEvt_CdromRead, cdrReadInterrupt); - IopTestEvent(IopEvt_DEV9, dev9Interrupt); - IopTestEvent(IopEvt_USB, usbInterrupt); - } -} - -void psxBranchTest() -{ - if( psxTestCycle( psxNextsCounter, psxNextCounter ) ) - { - psxRcntUpdate(); - iopBranchAction = true; - } - - // start the next branch at the next counter event by default - // the interrupt code below will assign nearer branches if needed. - g_psxNextBranchCycle = psxNextsCounter+psxNextCounter; - - if (psxRegs.interrupt) - { - iopEventTestIsActive = true; - _psxTestInterrupts(); - iopEventTestIsActive = false; - } - - if( psxHu32(0x1078) == 0 ) return; - if( (psxHu32(0x1070) & psxHu32(0x1074)) == 0 ) return; - - if ((psxRegs.CP0.n.Status & 0xFE01) >= 0x401) - { - PSXCPU_LOG("Interrupt: %x %x\n", psxHu32(0x1070), psxHu32(0x1074)); - psxException(0, 0); - iopBranchAction = true; - } -} - -void iopTestIntc() -{ - if( psxHu32(0x1078) == 0 ) return; - if( (psxHu32(0x1070) & psxHu32(0x1074)) == 0 ) return; - - if( !eeEventTestIsActive ) - { - // An iop exception has occurred while the EE is running code. - // Inform the EE to branch so the IOP can handle it promptly: - - cpuSetNextBranchDelta( 16 ); - iopBranchAction = true; - //Console::Error( "** IOP Needs an EE EventText, kthx ** %d", params psxCycleEE ); - - // Note: No need to set the iop's branch delta here, since the EE - // will run an IOP branch test regardless. - } - else if( !iopEventTestIsActive ) - psxSetNextBranchDelta( 2 ); -} - -void psxExecuteBios() { -/* while (psxRegs.pc != 0x80030000) - psxCpu->ExecuteBlock(); - PSX_LOG("*BIOS END*\n"); -*/ -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "PsxCommon.h" +#include "Misc.h" + +using namespace R3000A; + +R3000Acpu *psxCpu; + +// used for constant propagation +u32 g_psxConstRegs[32]; +u32 g_psxHasConstReg, g_psxFlushedConstReg; + +// Controls when branch tests are performed. +u32 g_psxNextBranchCycle = 0; + +// This value is used when the IOP execution is broken to return control to the EE. +// (which happens when the IOP throws EE-bound interrupts). It holds the value of +// psxCycleEE (which is set to zero to facilitate the code break), so that the unrun +// cycles can be accounted for later. +s32 psxBreak = 0; + +// tracks the IOP's current sync status with the EE. When it dips below zero, +// control is returned to the EE. +s32 psxCycleEE = -1; + +// Used to signal to the EE when important actions that need IOP-attention have +// happened (hsyncs, vsyncs, IOP exceptions, etc). IOP runs code whenever this +// is true, even if it's already running ahead a bit. +bool iopBranchAction = false; + +bool iopEventTestIsActive = false; + +PCSX2_ALIGNED16(psxRegisters psxRegs); + +void psxReset() +{ + memzero_obj(psxRegs); + + psxRegs.pc = 0xbfc00000; // Start in bootstrap + psxRegs.CP0.n.Status = 0x10900000; // COP0 enabled | BEV = 1 | TS = 1 + psxRegs.CP0.n.PRid = 0x0000001f; // PRevID = Revision ID, same as the IOP R3000A + + psxBreak = 0; + psxCycleEE = -1; + g_psxNextBranchCycle = psxRegs.cycle + 4; + + psxHwReset(); + psxBiosInit(); + //psxExecuteBios(); +} + +void psxShutdown() { + psxBiosShutdown(); + psxSIOShutdown(); + //psxCpu->Shutdown(); +} + +void psxException(u32 code, u32 bd) { +// PSXCPU_LOG("psxException %x: %x, %x\n", code, psxHu32(0x1070), psxHu32(0x1074)); + //SysPrintf("!! psxException %x: %x, %x\n", code, psxHu32(0x1070), psxHu32(0x1074)); + // Set the Cause + psxRegs.CP0.n.Cause &= ~0x7f; + psxRegs.CP0.n.Cause |= code; + + // Set the EPC & PC + if (bd) + { + PSXCPU_LOG("bd set\n"); + psxRegs.CP0.n.Cause|= 0x80000000; + psxRegs.CP0.n.EPC = (psxRegs.pc - 4); + } + else + psxRegs.CP0.n.EPC = (psxRegs.pc); + + if (psxRegs.CP0.n.Status & 0x400000) + psxRegs.pc = 0xbfc00180; + else + psxRegs.pc = 0x80000080; + + // Set the Status + psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status &~0x3f) | + ((psxRegs.CP0.n.Status & 0xf) << 2); + + /*if ((((PSXMu32(psxRegs.CP0.n.EPC) >> 24) & 0xfe) == 0x4a)) { + // "hokuto no ken" / "Crash Bandicot 2" ... fix + PSXMu32(psxRegs.CP0.n.EPC)&= ~0x02000000; + }*/ + + if (Config.PsxOut && !CHECK_EEREC) { + u32 call = psxRegs.GPR.n.t1 & 0xff; + switch (psxRegs.pc & 0x1fffff) { + case 0xa0: + + if (call != 0x28 && call != 0xe) + PSXBIOS_LOG("Bios call a0: %s (%x) %x,%x,%x,%x\n", biosA0n[call], call, psxRegs.GPR.n.a0, psxRegs.GPR.n.a1, psxRegs.GPR.n.a2, psxRegs.GPR.n.a3); + + if (biosA0[call]) + biosA0[call](); + break; + + case 0xb0: + if (call != 0x17 && call != 0xb) + PSXBIOS_LOG("Bios call b0: %s (%x) %x,%x,%x,%x\n", biosB0n[call], call, psxRegs.GPR.n.a0, psxRegs.GPR.n.a1, psxRegs.GPR.n.a2, psxRegs.GPR.n.a3); + + if (biosB0[call]) + biosB0[call](); + break; + + case 0xc0: + PSXBIOS_LOG("Bios call c0: %s (%x) %x,%x,%x,%x\n", biosC0n[call], call, psxRegs.GPR.n.a0, psxRegs.GPR.n.a1, psxRegs.GPR.n.a2, psxRegs.GPR.n.a3); + + if (biosC0[call]) + biosC0[call](); + break; + } + } + + /*if (psxRegs.CP0.n.Cause == 0x400 && (!(psxHu32(0x1450) & 0x8))) { + hwIntcIrq(1); + }*/ +} + +__forceinline void psxSetNextBranch( u32 startCycle, s32 delta ) +{ + // typecast the conditional to signed so that things don't blow up + // if startCycle is greater than our next branch cycle. + + if( (int)(g_psxNextBranchCycle - startCycle) > delta ) + g_psxNextBranchCycle = startCycle + delta; +} + +__forceinline void psxSetNextBranchDelta( s32 delta ) +{ + psxSetNextBranch( psxRegs.cycle, delta ); +} + +__forceinline int psxTestCycle( u32 startCycle, s32 delta ) +{ + // typecast the conditional to signed so that things don't explode + // if the startCycle is ahead of our current cpu cycle. + + return (int)(psxRegs.cycle - startCycle) >= delta; +} + +__forceinline void PSX_INT( IopEventId n, s32 ecycle ) +{ + // Generally speaking games shouldn't throw ints that haven't been cleared yet. + // It's usually indicative os something amiss in our emulation, so uncomment this + // code to help trap those sort of things. + + // Exception: IRQ16 - SIO - it drops ints like crazy when handling PAD stuff. + //if( /*n!=16 &&*/ psxRegs.interrupt & (1< Twice-thrown int on IRQ %d\n", n ); + + psxRegs.interrupt |= 1 << n; + + psxRegs.sCycle[n] = psxRegs.cycle; + psxRegs.eCycle[n] = ecycle; + + psxSetNextBranchDelta( ecycle ); + + if( psxCycleEE < 0 ) + { + // The EE called this int, so inform it to branch as needed: + // fixme - this doesn't take into account EE/IOP sync (the IOP may be running + // ahead or behind the EE as per the EEsCycles value) + s32 iopDelta = (g_psxNextBranchCycle-psxRegs.cycle)*8; + cpuSetNextBranchDelta( iopDelta ); + } +} + +static __forceinline void IopTestEvent( IopEventId n, void (*callback)() ) +{ + if( !(psxRegs.interrupt & (1 << n)) ) return; + + if( psxTestCycle( psxRegs.sCycle[n], psxRegs.eCycle[n] ) ) + { + psxRegs.interrupt &= ~(1 << n); + callback(); + } + else + psxSetNextBranch( psxRegs.sCycle[n], psxRegs.eCycle[n] ); +} + +static __forceinline void _psxTestInterrupts() +{ + IopTestEvent(IopEvt_SIF0, sif0Interrupt); // SIF0 + IopTestEvent(IopEvt_SIF1, sif1Interrupt); // SIF1 + IopTestEvent(IopEvt_SIO, sioInterrupt); + IopTestEvent(IopEvt_CdvdRead, cdvdReadInterrupt); + + // Profile-guided Optimization (sorta) + // The following ints are rarely called. Encasing them in a conditional + // as follows helps speed up most games. + + if( psxRegs.interrupt & ( (1ul<<5) | (3ul<<11) | (3ul<<20) | (3ul<<17) ) ) + { + IopTestEvent(IopEvt_Cdvd, cdvdActionInterrupt); + IopTestEvent(IopEvt_Dma11, psxDMA11Interrupt); // SIO2 + IopTestEvent(IopEvt_Dma12, psxDMA12Interrupt); // SIO2 + IopTestEvent(IopEvt_Cdrom, cdrInterrupt); + IopTestEvent(IopEvt_CdromRead, cdrReadInterrupt); + IopTestEvent(IopEvt_DEV9, dev9Interrupt); + IopTestEvent(IopEvt_USB, usbInterrupt); + } +} + +void psxBranchTest() +{ + if( psxTestCycle( psxNextsCounter, psxNextCounter ) ) + { + psxRcntUpdate(); + iopBranchAction = true; + } + + // start the next branch at the next counter event by default + // the interrupt code below will assign nearer branches if needed. + g_psxNextBranchCycle = psxNextsCounter+psxNextCounter; + + if (psxRegs.interrupt) + { + iopEventTestIsActive = true; + _psxTestInterrupts(); + iopEventTestIsActive = false; + } + + if( psxHu32(0x1078) == 0 ) return; + if( (psxHu32(0x1070) & psxHu32(0x1074)) == 0 ) return; + + if ((psxRegs.CP0.n.Status & 0xFE01) >= 0x401) + { + PSXCPU_LOG("Interrupt: %x %x\n", psxHu32(0x1070), psxHu32(0x1074)); + psxException(0, 0); + iopBranchAction = true; + } +} + +void iopTestIntc() +{ + if( psxHu32(0x1078) == 0 ) return; + if( (psxHu32(0x1070) & psxHu32(0x1074)) == 0 ) return; + + if( !eeEventTestIsActive ) + { + // An iop exception has occurred while the EE is running code. + // Inform the EE to branch so the IOP can handle it promptly: + + cpuSetNextBranchDelta( 16 ); + iopBranchAction = true; + //Console::Error( "** IOP Needs an EE EventText, kthx ** %d", params psxCycleEE ); + + // Note: No need to set the iop's branch delta here, since the EE + // will run an IOP branch test regardless. + } + else if( !iopEventTestIsActive ) + psxSetNextBranchDelta( 2 ); +} + +void psxExecuteBios() { +/* while (psxRegs.pc != 0x80030000) + psxCpu->ExecuteBlock(); + PSX_LOG("*BIOS END*\n"); +*/ +} diff --git a/pcsx2/R3000A.h b/pcsx2/R3000A.h index 119e1d91a9..ab307762f6 100644 --- a/pcsx2/R3000A.h +++ b/pcsx2/R3000A.h @@ -1,217 +1,217 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __R3000A_H__ -#define __R3000A_H__ - -#include - -union GPRRegs { - struct { - u32 r0, at, v0, v1, a0, a1, a2, a3, - t0, t1, t2, t3, t4, t5, t6, t7, - s0, s1, s2, s3, s4, s5, s6, s7, - t8, t9, k0, k1, gp, sp, s8, ra, hi, lo; // hi needs to be at index 32! don't change - } n; - u32 r[34]; /* Lo, Hi in r[33] and r[32] */ -}; - -union CP0Regs { - struct { - u32 Index, Random, EntryLo0, EntryLo1, - Context, PageMask, Wired, Reserved0, - BadVAddr, Count, EntryHi, Compare, - Status, Cause, EPC, PRid, - Config, LLAddr, WatchLO, WatchHI, - XContext, Reserved1, Reserved2, Reserved3, - Reserved4, Reserved5, ECC, CacheErr, - TagLo, TagHi, ErrorEPC, Reserved6; - } n; - u32 r[32]; -}; - -struct SVector2D { - short x, y; -}; - -struct SVector2Dz { - short z, pad; -}; - -struct SVector3D { - short x, y, z, pad; -}; - -struct LVector3D { - short x, y, z, pad; -}; - -struct CBGR { - unsigned char r, g, b, c; -}; - -struct SMatrix3D { - short m11, m12, m13, m21, m22, m23, m31, m32, m33, pad; -}; - -union CP2Data { - struct { - SVector3D v0, v1, v2; - CBGR rgb; - s32 otz; - s32 ir0, ir1, ir2, ir3; - SVector2D sxy0, sxy1, sxy2, sxyp; - SVector2Dz sz0, sz1, sz2, sz3; - CBGR rgb0, rgb1, rgb2; - s32 reserved; - s32 mac0, mac1, mac2, mac3; - u32 irgb, orgb; - s32 lzcs, lzcr; - } n; - u32 r[32]; -}; - -union CP2Ctrl { - struct { - SMatrix3D rMatrix; - s32 trX, trY, trZ; - SMatrix3D lMatrix; - s32 rbk, gbk, bbk; - SMatrix3D cMatrix; - s32 rfc, gfc, bfc; - s32 ofx, ofy; - s32 h; - s32 dqa, dqb; - s32 zsf3, zsf4; - s32 flag; - } n; - u32 r[32]; -}; - -struct psxRegisters { - GPRRegs GPR; /* General Purpose Registers */ - CP0Regs CP0; /* Coprocessor0 Registers */ - CP2Data CP2D; /* Cop2 data registers */ - CP2Ctrl CP2C; /* Cop2 control registers */ - u32 pc; /* Program counter */ - u32 code; /* The instruction */ - u32 cycle; - u32 interrupt; - u32 sCycle[64]; // start cycle for signaled ints - s32 eCycle[64]; // cycle delta for signaled ints (sCycle + eCycle == branch cycle) - u32 _msflag[32]; - u32 _smflag[32]; -}; - -extern PCSX2_ALIGNED16_DECL(psxRegisters psxRegs); - -extern u32 g_psxNextBranchCycle; -extern s32 psxBreak; // used when the IOP execution is broken and control returned to the EE -extern s32 psxCycleEE; // tracks IOP's current sych status with the EE - -#ifndef _PC_ - -#define _i32(x) (s32)x -#define _u32(x) x - -#define _i16(x) (short)x -#define _u16(x) (unsigned short)x - -#define _i8(x) (char)x -#define _u8(x) (unsigned char)x - -/**** R3000A Instruction Macros ****/ -#define _PC_ psxRegs.pc // The next PC to be executed - -#define _Funct_ ((psxRegs.code ) & 0x3F) // The funct part of the instruction register -#define _Rd_ ((psxRegs.code >> 11) & 0x1F) // The rd part of the instruction register -#define _Rt_ ((psxRegs.code >> 16) & 0x1F) // The rt part of the instruction register -#define _Rs_ ((psxRegs.code >> 21) & 0x1F) // The rs part of the instruction register -#define _Sa_ ((psxRegs.code >> 6) & 0x1F) // The sa part of the instruction register -#define _Im_ ((unsigned short)psxRegs.code) // The immediate part of the instruction register -#define _Target_ (psxRegs.code & 0x03ffffff) // The target part of the instruction register - -#define _Imm_ ((short)psxRegs.code) // sign-extended immediate -#define _ImmU_ (psxRegs.code&0xffff) // zero-extended immediate - -#define _rRs_ psxRegs.GPR.r[_Rs_] // Rs register -#define _rRt_ psxRegs.GPR.r[_Rt_] // Rt register -#define _rRd_ psxRegs.GPR.r[_Rd_] // Rd register -#define _rSa_ psxRegs.GPR.r[_Sa_] // Sa register -#define _rFs_ psxRegs.CP0.r[_Rd_] // Fs register - -#define _c2dRs_ psxRegs.CP2D.r[_Rs_] // Rs cop2 data register -#define _c2dRt_ psxRegs.CP2D.r[_Rt_] // Rt cop2 data register -#define _c2dRd_ psxRegs.CP2D.r[_Rd_] // Rd cop2 data register -#define _c2dSa_ psxRegs.CP2D.r[_Sa_] // Sa cop2 data register - -#define _rHi_ psxRegs.GPR.n.hi // The HI register -#define _rLo_ psxRegs.GPR.n.lo // The LO register - -#define _JumpTarget_ ((_Target_ << 2) + (_PC_ & 0xf0000000)) // Calculates the target during a jump instruction -#define _BranchTarget_ (((s32)(s16)_Imm_ * 4) + _PC_) // Calculates the target during a branch instruction -//#define _JumpTarget_ ((_Target_ * 4) + (_PC_ & 0xf0000000)) // Calculates the target during a jump instruction -//#define _BranchTarget_ ((short)_Im_ * 4 + _PC_) // Calculates the target during a branch instruction - -#define _SetLink(x) psxRegs.GPR.r[x] = _PC_ + 4; // Sets the return address in the link register - -extern s32 EEsCycle; -extern u32 EEoCycle; - -#endif - -extern s32 psxNextCounter; -extern u32 psxNextsCounter; -extern bool iopBranchAction; -extern bool iopEventTestIsActive; - -// Branching status used when throwing exceptions. -extern bool iopIsDelaySlot; - -//////////////////////////////////////////////////////////////////// -// R3000A Public Interface / API - -struct R3000Acpu { - void (*Allocate)(); - void (*Reset)(); - void (*Execute)(); - s32 (*ExecuteBlock)( s32 eeCycles ); // executes the given number of EE cycles. - void (*Clear)(u32 Addr, u32 Size); - void (*Shutdown)(); -}; - -extern R3000Acpu *psxCpu; -extern R3000Acpu psxInt; -extern R3000Acpu psxRec; - -void psxReset(); -void psxShutdown(); -void psxException(u32 code, u32 step); -void psxBranchTest(); -void psxExecuteBios(); -void psxMemReset(); - -// Subsets -extern void (*psxBSC[64])(); -extern void (*psxSPC[64])(); -extern void (*psxREG[32])(); -extern void (*psxCP0[32])(); -extern void (*psxCP2[64])(); -extern void (*psxCP2BSC[32])(); - -#endif /* __R3000A_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __R3000A_H__ +#define __R3000A_H__ + +#include + +union GPRRegs { + struct { + u32 r0, at, v0, v1, a0, a1, a2, a3, + t0, t1, t2, t3, t4, t5, t6, t7, + s0, s1, s2, s3, s4, s5, s6, s7, + t8, t9, k0, k1, gp, sp, s8, ra, hi, lo; // hi needs to be at index 32! don't change + } n; + u32 r[34]; /* Lo, Hi in r[33] and r[32] */ +}; + +union CP0Regs { + struct { + u32 Index, Random, EntryLo0, EntryLo1, + Context, PageMask, Wired, Reserved0, + BadVAddr, Count, EntryHi, Compare, + Status, Cause, EPC, PRid, + Config, LLAddr, WatchLO, WatchHI, + XContext, Reserved1, Reserved2, Reserved3, + Reserved4, Reserved5, ECC, CacheErr, + TagLo, TagHi, ErrorEPC, Reserved6; + } n; + u32 r[32]; +}; + +struct SVector2D { + short x, y; +}; + +struct SVector2Dz { + short z, pad; +}; + +struct SVector3D { + short x, y, z, pad; +}; + +struct LVector3D { + short x, y, z, pad; +}; + +struct CBGR { + unsigned char r, g, b, c; +}; + +struct SMatrix3D { + short m11, m12, m13, m21, m22, m23, m31, m32, m33, pad; +}; + +union CP2Data { + struct { + SVector3D v0, v1, v2; + CBGR rgb; + s32 otz; + s32 ir0, ir1, ir2, ir3; + SVector2D sxy0, sxy1, sxy2, sxyp; + SVector2Dz sz0, sz1, sz2, sz3; + CBGR rgb0, rgb1, rgb2; + s32 reserved; + s32 mac0, mac1, mac2, mac3; + u32 irgb, orgb; + s32 lzcs, lzcr; + } n; + u32 r[32]; +}; + +union CP2Ctrl { + struct { + SMatrix3D rMatrix; + s32 trX, trY, trZ; + SMatrix3D lMatrix; + s32 rbk, gbk, bbk; + SMatrix3D cMatrix; + s32 rfc, gfc, bfc; + s32 ofx, ofy; + s32 h; + s32 dqa, dqb; + s32 zsf3, zsf4; + s32 flag; + } n; + u32 r[32]; +}; + +struct psxRegisters { + GPRRegs GPR; /* General Purpose Registers */ + CP0Regs CP0; /* Coprocessor0 Registers */ + CP2Data CP2D; /* Cop2 data registers */ + CP2Ctrl CP2C; /* Cop2 control registers */ + u32 pc; /* Program counter */ + u32 code; /* The instruction */ + u32 cycle; + u32 interrupt; + u32 sCycle[64]; // start cycle for signaled ints + s32 eCycle[64]; // cycle delta for signaled ints (sCycle + eCycle == branch cycle) + u32 _msflag[32]; + u32 _smflag[32]; +}; + +extern PCSX2_ALIGNED16_DECL(psxRegisters psxRegs); + +extern u32 g_psxNextBranchCycle; +extern s32 psxBreak; // used when the IOP execution is broken and control returned to the EE +extern s32 psxCycleEE; // tracks IOP's current sych status with the EE + +#ifndef _PC_ + +#define _i32(x) (s32)x +#define _u32(x) x + +#define _i16(x) (short)x +#define _u16(x) (unsigned short)x + +#define _i8(x) (char)x +#define _u8(x) (unsigned char)x + +/**** R3000A Instruction Macros ****/ +#define _PC_ psxRegs.pc // The next PC to be executed + +#define _Funct_ ((psxRegs.code ) & 0x3F) // The funct part of the instruction register +#define _Rd_ ((psxRegs.code >> 11) & 0x1F) // The rd part of the instruction register +#define _Rt_ ((psxRegs.code >> 16) & 0x1F) // The rt part of the instruction register +#define _Rs_ ((psxRegs.code >> 21) & 0x1F) // The rs part of the instruction register +#define _Sa_ ((psxRegs.code >> 6) & 0x1F) // The sa part of the instruction register +#define _Im_ ((unsigned short)psxRegs.code) // The immediate part of the instruction register +#define _Target_ (psxRegs.code & 0x03ffffff) // The target part of the instruction register + +#define _Imm_ ((short)psxRegs.code) // sign-extended immediate +#define _ImmU_ (psxRegs.code&0xffff) // zero-extended immediate + +#define _rRs_ psxRegs.GPR.r[_Rs_] // Rs register +#define _rRt_ psxRegs.GPR.r[_Rt_] // Rt register +#define _rRd_ psxRegs.GPR.r[_Rd_] // Rd register +#define _rSa_ psxRegs.GPR.r[_Sa_] // Sa register +#define _rFs_ psxRegs.CP0.r[_Rd_] // Fs register + +#define _c2dRs_ psxRegs.CP2D.r[_Rs_] // Rs cop2 data register +#define _c2dRt_ psxRegs.CP2D.r[_Rt_] // Rt cop2 data register +#define _c2dRd_ psxRegs.CP2D.r[_Rd_] // Rd cop2 data register +#define _c2dSa_ psxRegs.CP2D.r[_Sa_] // Sa cop2 data register + +#define _rHi_ psxRegs.GPR.n.hi // The HI register +#define _rLo_ psxRegs.GPR.n.lo // The LO register + +#define _JumpTarget_ ((_Target_ << 2) + (_PC_ & 0xf0000000)) // Calculates the target during a jump instruction +#define _BranchTarget_ (((s32)(s16)_Imm_ * 4) + _PC_) // Calculates the target during a branch instruction +//#define _JumpTarget_ ((_Target_ * 4) + (_PC_ & 0xf0000000)) // Calculates the target during a jump instruction +//#define _BranchTarget_ ((short)_Im_ * 4 + _PC_) // Calculates the target during a branch instruction + +#define _SetLink(x) psxRegs.GPR.r[x] = _PC_ + 4; // Sets the return address in the link register + +extern s32 EEsCycle; +extern u32 EEoCycle; + +#endif + +extern s32 psxNextCounter; +extern u32 psxNextsCounter; +extern bool iopBranchAction; +extern bool iopEventTestIsActive; + +// Branching status used when throwing exceptions. +extern bool iopIsDelaySlot; + +//////////////////////////////////////////////////////////////////// +// R3000A Public Interface / API + +struct R3000Acpu { + void (*Allocate)(); + void (*Reset)(); + void (*Execute)(); + s32 (*ExecuteBlock)( s32 eeCycles ); // executes the given number of EE cycles. + void (*Clear)(u32 Addr, u32 Size); + void (*Shutdown)(); +}; + +extern R3000Acpu *psxCpu; +extern R3000Acpu psxInt; +extern R3000Acpu psxRec; + +void psxReset(); +void psxShutdown(); +void psxException(u32 code, u32 step); +void psxBranchTest(); +void psxExecuteBios(); +void psxMemReset(); + +// Subsets +extern void (*psxBSC[64])(); +extern void (*psxSPC[64])(); +extern void (*psxREG[32])(); +extern void (*psxCP0[32])(); +extern void (*psxCP2[64])(); +extern void (*psxCP2BSC[32])(); + +#endif /* __R3000A_H__ */ diff --git a/pcsx2/R3000AInterpreter.cpp b/pcsx2/R3000AInterpreter.cpp index d22585c5ad..62b681d386 100644 --- a/pcsx2/R3000AInterpreter.cpp +++ b/pcsx2/R3000AInterpreter.cpp @@ -1,445 +1,445 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "PsxCommon.h" -#include "Common.h" - -using namespace R3000A; - -// Used to flag delay slot instructions when throwig exceptions. -bool iopIsDelaySlot = false; - -static bool branch2 = 0; -static u32 branchPC; - -static void doBranch(s32 tar); // forward declared prototype - -struct irxlib { - char name[16]; - char names[64][64]; - int maxn; -}; - -#define IRXLIBS 14 -irxlib irxlibs[32] = { -/*00*/ { { "sysmem" } , - { "start", "init_memory", "retonly", "return_addr_of_memsize", - "AllocSysMemory", "FreeSysMemory", "QueryMemSize", "QueryMaxFreeMemSize", - "QueryTotalFreeMemSize", "QueryBlockTopAddress", "QueryBlockSize", "retonly", - "retonly", "retonly", "Kprintf", "set_Kprintf" } , - 16 }, -/*01*/ { { "loadcore" } , - { "start", "retonly", "retonly_", "return_LibraryEntryTable", - "FlushIcache", "FlushDcache", "RegisterLibraryEntries", "ReleaseLibraryEntries", - "findFixImports", "restoreImports", "RegisterNonAutoLinkEntries", "QueryLibraryEntryTable", - "QueryBootMode", "RegisterBootMode", "setFlag", "resetFlag", - "linkModule", "unlinkModule", "retonly_", "retonly_", - "registerFunc", "jumpA0001B34", "read_header", "load_module", - "findImageInfo" }, - 25 }, -/*02*/ { { "excepman" } , - { "start", "reinit", "deinit", "getcommon", - "RegisterExceptionHandler", "RegisterPriorityExceptionHandler", - "RegisterDefaultExceptionHandler", "ReleaseExceptionHandler", - "ReleaseDefaultExceptionHandler" } , - 9 }, -/*03_4*/{ { "intrman" } , - { "start", "return_0", "deinit", "call3", - "RegisterIntrHandler", "ReleaseIntrHandler", "EnableIntr", "DisableIntr", - "CpuDisableIntr", "CpuEnableIntr", "syscall04", "syscall08", - "resetICTRL", "setICTRL", "syscall0C", "call15", - "call16", "CpuSuspendIntr", "CpuResumeIntr", "CpuSuspendIntr", - "CpuResumeIntr", "syscall10", "syscall14", "QueryIntrContext", - "QueryIntrStack", "iCatchMultiIntr", "retonly", "call27", - "set_h1", "reset_h1", "set_h2", "reset_h2" } , - 0x20 }, -/*05*/ { { "ssbusc" } , - { "start", "retonly", "return_0", "retonly", - "setTable1", "getTable1", "setTable2", "getTable2", - "setCOM_DELAY_1st", "getCOM_DELAY_1st", "setCOM_DELAY_2nd", "getCOM_DELAY_2nd", - "setCOM_DELAY_3rd", "getCOM_DELAY_3rd", "setCOM_DELAY_4th", "getCOM_DELAY_4th", - "setCOM_DELAY", "getCOM_DELAY" } , - 18 }, -/*06*/ { { "dmacman" } , - { "start", "retonly", "deinit", "retonly", - "SetD_MADR", "GetD_MADR", "SetD_BCR", "GetD_BCR", - "SetD_CHCR", "GetD_CHCR", "SetD_TADR", "GetD_TADR", - "Set_4_9_A", "Get_4_9_A", "SetDPCR", "GetDPCR", - "SetDPCR2", "GetDPCR2", "SetDPCR3", "GetDPCR3", - "SetDICR", "GetDICR", "SetDICR2", "GetDICR2", - "SetBF80157C", "GetBF80157C", "SetBF801578", "GetBF801578", - "SetDMA", "SetDMA_chainedSPU_SIF0", "SetDMA_SIF0", "SetDMA_SIF1", - "StartTransfer", "SetVal", "EnableDMAch", "DisableDMAch" } , - 36 }, -/*07_8*/{ { "timrman" } , - { "start", "retonly", "retonly", "call3", - "AllocHardTimer", "ReferHardTimer", "FreeHardTimer", "SetTimerMode", - "GetTimerStatus", "SetTimerCounter", "GetTimerCounter", "SetTimerCompare", - "GetTimerCompare", "SetHoldMode", "GetHoldMode", "GetHoldReg", - "GetHardTimerIntrCode" } , - 17 }, -/*09*/ { { "sysclib" } , - { "start", "reinit", "retonly", "retonly", - "setjmp", "longjmp", "toupper", "tolower", - "look_ctype_table", "get_ctype_table", "memchr", "memcmp", - "memcpy", "memmove", "memset", "bcmp", - "bcopy", "bzero", "prnt", "sprintf", - "strcat", "strchr", "strcmp", "strcpy", - "strcspn", "index", "rindex", "strlen", - "strncat", "strncmp", "strncpy", "strpbrk", - "strrchr", "strspn", "strstr", "strtok", - "strtol", "atob", "strtoul", "wmemcopy", - "wmemset", "vsprintf" } , - 0x2b }, -/*0A*/ { { "heaplib" } , - { "start", "retonly", "retonly", "retonly", - "CreateHeap", "DestroyHeap", "HeapMalloc", "HeapFree", - "HeapSize", "retonly", "retonly", "call11", - "call12", "call13", "call14", "call15", - "retonly", "retonly" } , - 18 }, -/*13*/ { { "stdio" } , - { "start", "unknown", "unknown", "unknown", - "printf" } , - 5 }, -/*14*/ { { "sifman" } , - { "start", "retonly", "deinit", "retonly", - "sceSif2Init", "sceSifInit", "sceSifSetDChain", "sceSifSetDma", - "sceSifDmaStat", "sceSifSend", "sceSifSendSync", "sceSifIsSending", - "sceSifSetSIF0DMA", "sceSifSendSync0", "sceSifIsSending0", "sceSifSetSIF1DMA", - "sceSifSendSync1", "sceSifIsSending1", "sceSifSetSIF2DMA", "sceSifSendSync2", - "sceSifIsSending2", "getEEIOPflags", "setEEIOPflags", "getIOPEEflags", - "setIOPEEflags", "getEErcvaddr", "getIOPrcvaddr", "setIOPrcvaddr", - "call28", "sceSifCheckInit", "setSif0CB", "resetSif0CB", - "retonly", "retonly", "retonly", "retonly" } , - 36 }, -/*16*/ { { "sifcmd" } , - { "start", "retonly", "deinit", "retonly", - "sceSifInitCmd", "sceSifExitCmd", "sceSifGetSreg", "sceSifSetSreg", - "sceSifSetCmdBuffer", "sceSifSetSysCmdBuffer", - "sceSifAddCmdHandler", "sceSifRemoveCmdHandler", - "sceSifSendCmd", "isceSifSendCmd", "sceSifInitRpc", "sceSifBindRpc", - "sceSifCallRpc", "sceSifRegisterRpc", - "sceSifCheckStatRpc", "sceSifSetRpcQueue", - "sceSifGetNextRequest", "sceSifExecRequest", - "sceSifRpcLoop", "sceSifGetOtherData", - "sceSifRemoveRpc", "sceSifRemoveRpcQueue", - "setSif1CB", "resetSif1CB", - "retonly", "retonly", "retonly", "retonly" } , - 32 }, -/*19*/ { { "cdvdman" } , - { "start", "retonly", "retonly", "retonly", - "sceCdInit", "sceCdStandby", "sceCdRead", "sceCdSeek", - "sceCdGetError", "sceCdGetToc", "sceCdSearchFile", "sceCdSync", - "sceCdGetDiskType", "sceCdDiskReady", "sceCdTrayReq", "sceCdStop", - "sceCdPosToInt", "sceCdIntToPos", "retonly", "call19", - "sceDvdRead", "sceCdCheckCmd", "_sceCdRI", "sceCdWriteILinkID", - "sceCdReadClock", "sceCdWriteRTC", "sceCdReadNVM", "sceCdWriteNVM", - "sceCdStatus", "sceCdApplySCmd", "setHDmode", "sceCdOpenConfig", - "sceCdCloseConfig", "sceCdReadConfig", "sceCdWriteConfig", "sceCdReadKey", - "sceCdDecSet", "sceCdCallback", "sceCdPause", "sceCdBreak", - "call40", "sceCdReadConsoleID", "sceCdWriteConsoleID", "sceCdGetMecaconVersion", - "sceCdGetReadPos", "AudioDigitalOut", "sceCdNop", "_sceGetFsvRbuf", - "_sceCdstm0Cb", "_sceCdstm1Cb", "_sceCdSC", "_sceCdRC", - "sceCdForbidDVDP", "sceCdReadSubQ", "sceCdApplyNCmd", "AutoAdjustCtrl", - "sceCdStInit", "sceCdStRead", "sceCdStSeek", "sceCdStStart", - "sceCdStStat", "sceCdStStop" } , - 62 }, -/*??*/ { { "sio2man" } , - { "start", "retonly", "deinit", "retonly", - "set8268_ctrl", "get8268_ctrl", "get826C_recv1", "call7_send1", - "call8_send1", "call9_send2", "call10_send2", "get8270_recv2", - "call12_set_params", "call13_get_params", "get8274_recv3", "set8278", - "get8278", "set827C", "get827C", "set8260_datain", - "get8264_dataout", "set8280_intr", "get8280_intr", "signalExchange1", - "signalExchange2", "packetExchange" } , - 26 } -}; - -#define Ra0 ((char*)PSXM(psxRegs.GPR.n.a0)) -#define Ra1 ((char*)PSXM(psxRegs.GPR.n.a1)) -#define Ra2 ((char*)PSXM(psxRegs.GPR.n.a2)) -#define Ra3 ((char*)PSXM(psxRegs.GPR.n.a3)) - -const char* intrname[]={ -"INT_VBLANK", "INT_GM", "INT_CDROM", "INT_DMA", //00 -"INT_RTC0", "INT_RTC1", "INT_RTC2", "INT_SIO0", //04 -"INT_SIO1", "INT_SPU", "INT_PIO", "INT_EVBLANK", //08 -"INT_DVD", "INT_PCMCIA", "INT_RTC3", "INT_RTC4", //0C -"INT_RTC5", "INT_SIO2", "INT_HTR0", "INT_HTR1", //10 -"INT_HTR2", "INT_HTR3", "INT_USB", "INT_EXTR", //14 -"INT_FWRE", "INT_FDMA", "INT_1A", "INT_1B", //18 -"INT_1C", "INT_1D", "INT_1E", "INT_1F", //1C -"INT_dmaMDECi", "INT_dmaMDECo", "INT_dmaGPU", "INT_dmaCD", //20 -"INT_dmaSPU", "INT_dmaPIO", "INT_dmaOTC", "INT_dmaBERR", //24 -"INT_dmaSPU2", "INT_dma8", "INT_dmaSIF0", "INT_dmaSIF1", //28 -"INT_dmaSIO2i", "INT_dmaSIO2o", "INT_2E", "INT_2F", //2C -"INT_30", "INT_31", "INT_32", "INT_33", //30 -"INT_34", "INT_35", "INT_36", "INT_37", //34 -"INT_38", "INT_39", "INT_3A", "INT_3B", //38 -"INT_3C", "INT_3D", "INT_3E", "INT_3F", //3C -"INT_MAX" //40 -}; - -void zeroEx() -{ -#ifdef PCSX2_DEVBUILD - u32 pc; - u32 code; - char *lib; - char *fname = NULL; - int i; - - if (!Config.PsxOut) return; - - pc = psxRegs.pc; - while (PSXMu32(pc) != 0x41e00000) pc-=4; - - lib = (char*)PSXM(pc+12); - code = PSXMu32(psxRegs.pc - 4) & 0xffff; - - for (i=0; i= (u32)irxlibs[i].maxn) break; - - fname = irxlibs[i].names[code]; - //if( strcmp(fname, "setIOPrcvaddr") == 0 ) { -// SysPrintf("yo\n"); -// varLog |= 0x100000; -// Log = 1; -// } - break; - } - } - - {char libz[9]; memcpy(libz, lib, 8); libz[8]=0; - PSXBIOS_LOG("%s: %s (%x)" - " (%x, %x, %x, %x)" //comment this line to disable param showing - , libz, fname == NULL ? "unknown" : fname, code, - psxRegs.GPR.n.a0, psxRegs.GPR.n.a1, psxRegs.GPR.n.a2, psxRegs.GPR.n.a3); - } - -// Log=0; -// if (!strcmp(lib, "intrman") && code == 0x11) Log=1; -// if (!strcmp(lib, "sifman") && code == 0x5) Log=1; -// if (!strcmp(lib, "sifcmd") && code == 0x4) Log=1; -// if (!strcmp(lib, "thbase") && code == 0x6) Log=1; -/* - if (!strcmp(lib, "sifcmd") && code == 0xe) { - branchPC = psxRegs.GPR.n.ra; - psxRegs.GPR.n.v0 = 0; - return; - } -*/ - if (!strncmp(lib, "ioman", 5) && code == 7) { - if (psxRegs.GPR.n.a0 == 1) { - pc = psxRegs.pc; - bios_write(); - psxRegs.pc = pc; - } - } - - if (!strncmp(lib, "sysmem", 6) && code == 0xe) { - bios_printf(); - psxRegs.pc = psxRegs.GPR.n.ra; - } - - if (!strncmp(lib, "loadcore", 8) && code == 6) { - DevCon::WriteLn("loadcore RegisterLibraryEntries (%x): %8.8s", params psxRegs.pc, PSXM(psxRegs.GPR.n.a0+12)); - } - - if (!strncmp(lib, "intrman", 7) && code == 4) { - DevCon::WriteLn("intrman RegisterIntrHandler (%x): intr %s, handler %x", params psxRegs.pc, intrname[psxRegs.GPR.n.a0], psxRegs.GPR.n.a2); - } - - if (!strncmp(lib, "sifcmd", 6) && code == 17) { - DevCon::WriteLn("sifcmd sceSifRegisterRpc (%x): rpc_id %x", params psxRegs.pc, psxRegs.GPR.n.a1); - } - - if (!strncmp(lib, "sysclib", 8)) - { - switch (code) - { - case 0x16: // strcmp - PSXBIOS_LOG(" \"%s\": \"%s\"", Ra0, Ra1); - break; - - case 0x1e: // strncpy - PSXBIOS_LOG(" \"%s\"", Ra1); - break; - } - } - -/* psxRegs.pc = branchPC; - pc = psxRegs.GPR.n.ra; - while (psxRegs.pc != pc) psxCpu->ExecuteBlock(); - - PSXBIOS_LOG("%s: %s (%x) END\n", lib, fname == NULL ? "unknown" : fname, code);*/ -#endif - -} -/*/==========================================CALL LOG -char* getName(char *file, u32 addr){ - FILE *f; u32 a; - static char name[100]; - - f=fopen(file, "r"); - if (!f) - name[0]=0; - else{ - while (!feof(f)){ - fscanf(f, "%08X %s\n", &a, name); - if (a==addr)break; - } - fclose(f); - } - return name; -} - -void spyFunctions(){ - register irxImageInfo *iii; - if (psxRegs.pc >= 0x200000) return; - for (iii=(irxImageInfo*)PSXM(0x800); iii && iii->text_size; - iii=iii->next ? (irxImageInfo*)PSXM(iii->next) : NULL) - if (iii->vaddr<=psxRegs.pc && psxRegs.pcvaddr+iii->text_size+iii->data_size+iii->bss_size){ - if (strcmp("secrman_for_cex", PSXM(iii->name))==0){ - char *name=getName("secrman.fun", psxRegs.pc-iii->vaddr); - if (strncmp("__push_params", name, 13)==0){ - PAD_LOG(PSXM(psxRegs.GPR.n.a0), psxRegs.GPR.n.a1, psxRegs.GPR.n.a2, psxRegs.GPR.n.a3); - }else{ - PAD_LOG("secrman: %s (ra=%06X cycle=%d)\n", name, psxRegs.GPR.n.ra-iii->vaddr, psxRegs.cycle);}}else - if (strcmp("mcman", PSXM(iii->name))==0){ - PAD_LOG("mcman: %s (ra=%06X cycle=%d)\n", getName("mcman.fun", psxRegs.pc-iii->vaddr), psxRegs.GPR.n.ra-iii->vaddr, psxRegs.cycle);}else - if (strcmp("padman", PSXM(iii->name))==0){ - PAD_LOG("padman: %s (ra=%06X cycle=%d)\n", getName("padman.fun", psxRegs.pc-iii->vaddr), psxRegs.GPR.n.ra-iii->vaddr, psxRegs.cycle);}else - if (strcmp("sio2man", PSXM(iii->name))==0){ - PAD_LOG("sio2man: %s (ra=%06X cycle=%d)\n", getName("sio2man.fun", psxRegs.pc-iii->vaddr), psxRegs.GPR.n.ra-iii->vaddr, psxRegs.cycle);} - break; - } -} -*/ - -/********************************************************* -* Register branch logic * -* Format: OP rs, offset * -*********************************************************/ -#define RepZBranchi32(op) if(_i32(_rRs_) op 0) doBranch(_BranchTarget_); -#define RepZBranchLinki32(op) if(_i32(_rRs_) op 0) { _SetLink(31); doBranch(_BranchTarget_); } - -void psxBGEZ() { RepZBranchi32(>=) } // Branch if Rs >= 0 -void psxBGEZAL() { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link -void psxBGTZ() { RepZBranchi32(>) } // Branch if Rs > 0 -void psxBLEZ() { RepZBranchi32(<=) } // Branch if Rs <= 0 -void psxBLTZ() { RepZBranchi32(<) } // Branch if Rs < 0 -void psxBLTZAL() { RepZBranchLinki32(<) } // Branch if Rs < 0 and link - -/********************************************************* -* Register branch logic * -* Format: OP rs, rt, offset * -*********************************************************/ -#define RepBranchi32(op) if(_i32(_rRs_) op _i32(_rRt_)) doBranch(_BranchTarget_); - -void psxBEQ() { RepBranchi32(==) } // Branch if Rs == Rt -void psxBNE() { RepBranchi32(!=) } // Branch if Rs != Rt - -/********************************************************* -* Jump to target * -* Format: OP target * -*********************************************************/ -void psxJ() { doBranch(_JumpTarget_); } -void psxJAL() { _SetLink(31); doBranch(_JumpTarget_); /*spyFunctions();*/ } - -/********************************************************* -* Register jump * -* Format: OP rs, rd * -*********************************************************/ -void psxJR() { doBranch(_u32(_rRs_)); } -void psxJALR() { if (_Rd_) { _SetLink(_Rd_); } doBranch(_u32(_rRs_)); } - -/////////////////////////////////////////// -// These macros are used to assemble the repassembler functions - -static __forceinline void execI() { - psxRegs.code = PSXMu32(psxRegs.pc); - - PSXCPU_LOG("%s\n", disR3000AF(psxRegs.code, psxRegs.pc)); - - psxRegs.pc+= 4; - psxRegs.cycle++; - psxCycleEE-=8; - - psxBSC[psxRegs.code >> 26](); -} - - -static void doBranch(s32 tar) { - branch2 = iopIsDelaySlot = true; - branchPC = tar; - execI(); - iopIsDelaySlot = false; - psxRegs.pc = branchPC; - - psxBranchTest(); -} - -static void intAlloc() { -} - -static void intReset() { -} - -static void intExecute() { - for (;;) execI(); -} - -#ifdef _DEBUG -extern u32 psxdump; -extern void iDumpPsxRegisters(u32,u32); -#endif - -static s32 intExecuteBlock( s32 eeCycles ) -{ - psxBreak = 0; - psxCycleEE = eeCycles; - - while (psxCycleEE > 0){ - branch2 = 0; - while (!branch2) { - execI(); - } - } - return psxBreak + psxCycleEE; -} - -static void intClear(u32 Addr, u32 Size) { -} - -static void intShutdown() { -} - -R3000Acpu psxInt = { - intAlloc, - intReset, - intExecute, - intExecuteBlock, - intClear, - intShutdown -}; +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "PsxCommon.h" +#include "Common.h" + +using namespace R3000A; + +// Used to flag delay slot instructions when throwig exceptions. +bool iopIsDelaySlot = false; + +static bool branch2 = 0; +static u32 branchPC; + +static void doBranch(s32 tar); // forward declared prototype + +struct irxlib { + char name[16]; + char names[64][64]; + int maxn; +}; + +#define IRXLIBS 14 +irxlib irxlibs[32] = { +/*00*/ { { "sysmem" } , + { "start", "init_memory", "retonly", "return_addr_of_memsize", + "AllocSysMemory", "FreeSysMemory", "QueryMemSize", "QueryMaxFreeMemSize", + "QueryTotalFreeMemSize", "QueryBlockTopAddress", "QueryBlockSize", "retonly", + "retonly", "retonly", "Kprintf", "set_Kprintf" } , + 16 }, +/*01*/ { { "loadcore" } , + { "start", "retonly", "retonly_", "return_LibraryEntryTable", + "FlushIcache", "FlushDcache", "RegisterLibraryEntries", "ReleaseLibraryEntries", + "findFixImports", "restoreImports", "RegisterNonAutoLinkEntries", "QueryLibraryEntryTable", + "QueryBootMode", "RegisterBootMode", "setFlag", "resetFlag", + "linkModule", "unlinkModule", "retonly_", "retonly_", + "registerFunc", "jumpA0001B34", "read_header", "load_module", + "findImageInfo" }, + 25 }, +/*02*/ { { "excepman" } , + { "start", "reinit", "deinit", "getcommon", + "RegisterExceptionHandler", "RegisterPriorityExceptionHandler", + "RegisterDefaultExceptionHandler", "ReleaseExceptionHandler", + "ReleaseDefaultExceptionHandler" } , + 9 }, +/*03_4*/{ { "intrman" } , + { "start", "return_0", "deinit", "call3", + "RegisterIntrHandler", "ReleaseIntrHandler", "EnableIntr", "DisableIntr", + "CpuDisableIntr", "CpuEnableIntr", "syscall04", "syscall08", + "resetICTRL", "setICTRL", "syscall0C", "call15", + "call16", "CpuSuspendIntr", "CpuResumeIntr", "CpuSuspendIntr", + "CpuResumeIntr", "syscall10", "syscall14", "QueryIntrContext", + "QueryIntrStack", "iCatchMultiIntr", "retonly", "call27", + "set_h1", "reset_h1", "set_h2", "reset_h2" } , + 0x20 }, +/*05*/ { { "ssbusc" } , + { "start", "retonly", "return_0", "retonly", + "setTable1", "getTable1", "setTable2", "getTable2", + "setCOM_DELAY_1st", "getCOM_DELAY_1st", "setCOM_DELAY_2nd", "getCOM_DELAY_2nd", + "setCOM_DELAY_3rd", "getCOM_DELAY_3rd", "setCOM_DELAY_4th", "getCOM_DELAY_4th", + "setCOM_DELAY", "getCOM_DELAY" } , + 18 }, +/*06*/ { { "dmacman" } , + { "start", "retonly", "deinit", "retonly", + "SetD_MADR", "GetD_MADR", "SetD_BCR", "GetD_BCR", + "SetD_CHCR", "GetD_CHCR", "SetD_TADR", "GetD_TADR", + "Set_4_9_A", "Get_4_9_A", "SetDPCR", "GetDPCR", + "SetDPCR2", "GetDPCR2", "SetDPCR3", "GetDPCR3", + "SetDICR", "GetDICR", "SetDICR2", "GetDICR2", + "SetBF80157C", "GetBF80157C", "SetBF801578", "GetBF801578", + "SetDMA", "SetDMA_chainedSPU_SIF0", "SetDMA_SIF0", "SetDMA_SIF1", + "StartTransfer", "SetVal", "EnableDMAch", "DisableDMAch" } , + 36 }, +/*07_8*/{ { "timrman" } , + { "start", "retonly", "retonly", "call3", + "AllocHardTimer", "ReferHardTimer", "FreeHardTimer", "SetTimerMode", + "GetTimerStatus", "SetTimerCounter", "GetTimerCounter", "SetTimerCompare", + "GetTimerCompare", "SetHoldMode", "GetHoldMode", "GetHoldReg", + "GetHardTimerIntrCode" } , + 17 }, +/*09*/ { { "sysclib" } , + { "start", "reinit", "retonly", "retonly", + "setjmp", "longjmp", "toupper", "tolower", + "look_ctype_table", "get_ctype_table", "memchr", "memcmp", + "memcpy", "memmove", "memset", "bcmp", + "bcopy", "bzero", "prnt", "sprintf", + "strcat", "strchr", "strcmp", "strcpy", + "strcspn", "index", "rindex", "strlen", + "strncat", "strncmp", "strncpy", "strpbrk", + "strrchr", "strspn", "strstr", "strtok", + "strtol", "atob", "strtoul", "wmemcopy", + "wmemset", "vsprintf" } , + 0x2b }, +/*0A*/ { { "heaplib" } , + { "start", "retonly", "retonly", "retonly", + "CreateHeap", "DestroyHeap", "HeapMalloc", "HeapFree", + "HeapSize", "retonly", "retonly", "call11", + "call12", "call13", "call14", "call15", + "retonly", "retonly" } , + 18 }, +/*13*/ { { "stdio" } , + { "start", "unknown", "unknown", "unknown", + "printf" } , + 5 }, +/*14*/ { { "sifman" } , + { "start", "retonly", "deinit", "retonly", + "sceSif2Init", "sceSifInit", "sceSifSetDChain", "sceSifSetDma", + "sceSifDmaStat", "sceSifSend", "sceSifSendSync", "sceSifIsSending", + "sceSifSetSIF0DMA", "sceSifSendSync0", "sceSifIsSending0", "sceSifSetSIF1DMA", + "sceSifSendSync1", "sceSifIsSending1", "sceSifSetSIF2DMA", "sceSifSendSync2", + "sceSifIsSending2", "getEEIOPflags", "setEEIOPflags", "getIOPEEflags", + "setIOPEEflags", "getEErcvaddr", "getIOPrcvaddr", "setIOPrcvaddr", + "call28", "sceSifCheckInit", "setSif0CB", "resetSif0CB", + "retonly", "retonly", "retonly", "retonly" } , + 36 }, +/*16*/ { { "sifcmd" } , + { "start", "retonly", "deinit", "retonly", + "sceSifInitCmd", "sceSifExitCmd", "sceSifGetSreg", "sceSifSetSreg", + "sceSifSetCmdBuffer", "sceSifSetSysCmdBuffer", + "sceSifAddCmdHandler", "sceSifRemoveCmdHandler", + "sceSifSendCmd", "isceSifSendCmd", "sceSifInitRpc", "sceSifBindRpc", + "sceSifCallRpc", "sceSifRegisterRpc", + "sceSifCheckStatRpc", "sceSifSetRpcQueue", + "sceSifGetNextRequest", "sceSifExecRequest", + "sceSifRpcLoop", "sceSifGetOtherData", + "sceSifRemoveRpc", "sceSifRemoveRpcQueue", + "setSif1CB", "resetSif1CB", + "retonly", "retonly", "retonly", "retonly" } , + 32 }, +/*19*/ { { "cdvdman" } , + { "start", "retonly", "retonly", "retonly", + "sceCdInit", "sceCdStandby", "sceCdRead", "sceCdSeek", + "sceCdGetError", "sceCdGetToc", "sceCdSearchFile", "sceCdSync", + "sceCdGetDiskType", "sceCdDiskReady", "sceCdTrayReq", "sceCdStop", + "sceCdPosToInt", "sceCdIntToPos", "retonly", "call19", + "sceDvdRead", "sceCdCheckCmd", "_sceCdRI", "sceCdWriteILinkID", + "sceCdReadClock", "sceCdWriteRTC", "sceCdReadNVM", "sceCdWriteNVM", + "sceCdStatus", "sceCdApplySCmd", "setHDmode", "sceCdOpenConfig", + "sceCdCloseConfig", "sceCdReadConfig", "sceCdWriteConfig", "sceCdReadKey", + "sceCdDecSet", "sceCdCallback", "sceCdPause", "sceCdBreak", + "call40", "sceCdReadConsoleID", "sceCdWriteConsoleID", "sceCdGetMecaconVersion", + "sceCdGetReadPos", "AudioDigitalOut", "sceCdNop", "_sceGetFsvRbuf", + "_sceCdstm0Cb", "_sceCdstm1Cb", "_sceCdSC", "_sceCdRC", + "sceCdForbidDVDP", "sceCdReadSubQ", "sceCdApplyNCmd", "AutoAdjustCtrl", + "sceCdStInit", "sceCdStRead", "sceCdStSeek", "sceCdStStart", + "sceCdStStat", "sceCdStStop" } , + 62 }, +/*??*/ { { "sio2man" } , + { "start", "retonly", "deinit", "retonly", + "set8268_ctrl", "get8268_ctrl", "get826C_recv1", "call7_send1", + "call8_send1", "call9_send2", "call10_send2", "get8270_recv2", + "call12_set_params", "call13_get_params", "get8274_recv3", "set8278", + "get8278", "set827C", "get827C", "set8260_datain", + "get8264_dataout", "set8280_intr", "get8280_intr", "signalExchange1", + "signalExchange2", "packetExchange" } , + 26 } +}; + +#define Ra0 ((char*)PSXM(psxRegs.GPR.n.a0)) +#define Ra1 ((char*)PSXM(psxRegs.GPR.n.a1)) +#define Ra2 ((char*)PSXM(psxRegs.GPR.n.a2)) +#define Ra3 ((char*)PSXM(psxRegs.GPR.n.a3)) + +const char* intrname[]={ +"INT_VBLANK", "INT_GM", "INT_CDROM", "INT_DMA", //00 +"INT_RTC0", "INT_RTC1", "INT_RTC2", "INT_SIO0", //04 +"INT_SIO1", "INT_SPU", "INT_PIO", "INT_EVBLANK", //08 +"INT_DVD", "INT_PCMCIA", "INT_RTC3", "INT_RTC4", //0C +"INT_RTC5", "INT_SIO2", "INT_HTR0", "INT_HTR1", //10 +"INT_HTR2", "INT_HTR3", "INT_USB", "INT_EXTR", //14 +"INT_FWRE", "INT_FDMA", "INT_1A", "INT_1B", //18 +"INT_1C", "INT_1D", "INT_1E", "INT_1F", //1C +"INT_dmaMDECi", "INT_dmaMDECo", "INT_dmaGPU", "INT_dmaCD", //20 +"INT_dmaSPU", "INT_dmaPIO", "INT_dmaOTC", "INT_dmaBERR", //24 +"INT_dmaSPU2", "INT_dma8", "INT_dmaSIF0", "INT_dmaSIF1", //28 +"INT_dmaSIO2i", "INT_dmaSIO2o", "INT_2E", "INT_2F", //2C +"INT_30", "INT_31", "INT_32", "INT_33", //30 +"INT_34", "INT_35", "INT_36", "INT_37", //34 +"INT_38", "INT_39", "INT_3A", "INT_3B", //38 +"INT_3C", "INT_3D", "INT_3E", "INT_3F", //3C +"INT_MAX" //40 +}; + +void zeroEx() +{ +#ifdef PCSX2_DEVBUILD + u32 pc; + u32 code; + char *lib; + char *fname = NULL; + int i; + + if (!Config.PsxOut) return; + + pc = psxRegs.pc; + while (PSXMu32(pc) != 0x41e00000) pc-=4; + + lib = (char*)PSXM(pc+12); + code = PSXMu32(psxRegs.pc - 4) & 0xffff; + + for (i=0; i= (u32)irxlibs[i].maxn) break; + + fname = irxlibs[i].names[code]; + //if( strcmp(fname, "setIOPrcvaddr") == 0 ) { +// SysPrintf("yo\n"); +// varLog |= 0x100000; +// Log = 1; +// } + break; + } + } + + {char libz[9]; memcpy(libz, lib, 8); libz[8]=0; + PSXBIOS_LOG("%s: %s (%x)" + " (%x, %x, %x, %x)" //comment this line to disable param showing + , libz, fname == NULL ? "unknown" : fname, code, + psxRegs.GPR.n.a0, psxRegs.GPR.n.a1, psxRegs.GPR.n.a2, psxRegs.GPR.n.a3); + } + +// Log=0; +// if (!strcmp(lib, "intrman") && code == 0x11) Log=1; +// if (!strcmp(lib, "sifman") && code == 0x5) Log=1; +// if (!strcmp(lib, "sifcmd") && code == 0x4) Log=1; +// if (!strcmp(lib, "thbase") && code == 0x6) Log=1; +/* + if (!strcmp(lib, "sifcmd") && code == 0xe) { + branchPC = psxRegs.GPR.n.ra; + psxRegs.GPR.n.v0 = 0; + return; + } +*/ + if (!strncmp(lib, "ioman", 5) && code == 7) { + if (psxRegs.GPR.n.a0 == 1) { + pc = psxRegs.pc; + bios_write(); + psxRegs.pc = pc; + } + } + + if (!strncmp(lib, "sysmem", 6) && code == 0xe) { + bios_printf(); + psxRegs.pc = psxRegs.GPR.n.ra; + } + + if (!strncmp(lib, "loadcore", 8) && code == 6) { + DevCon::WriteLn("loadcore RegisterLibraryEntries (%x): %8.8s", params psxRegs.pc, PSXM(psxRegs.GPR.n.a0+12)); + } + + if (!strncmp(lib, "intrman", 7) && code == 4) { + DevCon::WriteLn("intrman RegisterIntrHandler (%x): intr %s, handler %x", params psxRegs.pc, intrname[psxRegs.GPR.n.a0], psxRegs.GPR.n.a2); + } + + if (!strncmp(lib, "sifcmd", 6) && code == 17) { + DevCon::WriteLn("sifcmd sceSifRegisterRpc (%x): rpc_id %x", params psxRegs.pc, psxRegs.GPR.n.a1); + } + + if (!strncmp(lib, "sysclib", 8)) + { + switch (code) + { + case 0x16: // strcmp + PSXBIOS_LOG(" \"%s\": \"%s\"", Ra0, Ra1); + break; + + case 0x1e: // strncpy + PSXBIOS_LOG(" \"%s\"", Ra1); + break; + } + } + +/* psxRegs.pc = branchPC; + pc = psxRegs.GPR.n.ra; + while (psxRegs.pc != pc) psxCpu->ExecuteBlock(); + + PSXBIOS_LOG("%s: %s (%x) END\n", lib, fname == NULL ? "unknown" : fname, code);*/ +#endif + +} +/*/==========================================CALL LOG +char* getName(char *file, u32 addr){ + FILE *f; u32 a; + static char name[100]; + + f=fopen(file, "r"); + if (!f) + name[0]=0; + else{ + while (!feof(f)){ + fscanf(f, "%08X %s\n", &a, name); + if (a==addr)break; + } + fclose(f); + } + return name; +} + +void spyFunctions(){ + register irxImageInfo *iii; + if (psxRegs.pc >= 0x200000) return; + for (iii=(irxImageInfo*)PSXM(0x800); iii && iii->text_size; + iii=iii->next ? (irxImageInfo*)PSXM(iii->next) : NULL) + if (iii->vaddr<=psxRegs.pc && psxRegs.pcvaddr+iii->text_size+iii->data_size+iii->bss_size){ + if (strcmp("secrman_for_cex", PSXM(iii->name))==0){ + char *name=getName("secrman.fun", psxRegs.pc-iii->vaddr); + if (strncmp("__push_params", name, 13)==0){ + PAD_LOG(PSXM(psxRegs.GPR.n.a0), psxRegs.GPR.n.a1, psxRegs.GPR.n.a2, psxRegs.GPR.n.a3); + }else{ + PAD_LOG("secrman: %s (ra=%06X cycle=%d)\n", name, psxRegs.GPR.n.ra-iii->vaddr, psxRegs.cycle);}}else + if (strcmp("mcman", PSXM(iii->name))==0){ + PAD_LOG("mcman: %s (ra=%06X cycle=%d)\n", getName("mcman.fun", psxRegs.pc-iii->vaddr), psxRegs.GPR.n.ra-iii->vaddr, psxRegs.cycle);}else + if (strcmp("padman", PSXM(iii->name))==0){ + PAD_LOG("padman: %s (ra=%06X cycle=%d)\n", getName("padman.fun", psxRegs.pc-iii->vaddr), psxRegs.GPR.n.ra-iii->vaddr, psxRegs.cycle);}else + if (strcmp("sio2man", PSXM(iii->name))==0){ + PAD_LOG("sio2man: %s (ra=%06X cycle=%d)\n", getName("sio2man.fun", psxRegs.pc-iii->vaddr), psxRegs.GPR.n.ra-iii->vaddr, psxRegs.cycle);} + break; + } +} +*/ + +/********************************************************* +* Register branch logic * +* Format: OP rs, offset * +*********************************************************/ +#define RepZBranchi32(op) if(_i32(_rRs_) op 0) doBranch(_BranchTarget_); +#define RepZBranchLinki32(op) if(_i32(_rRs_) op 0) { _SetLink(31); doBranch(_BranchTarget_); } + +void psxBGEZ() { RepZBranchi32(>=) } // Branch if Rs >= 0 +void psxBGEZAL() { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link +void psxBGTZ() { RepZBranchi32(>) } // Branch if Rs > 0 +void psxBLEZ() { RepZBranchi32(<=) } // Branch if Rs <= 0 +void psxBLTZ() { RepZBranchi32(<) } // Branch if Rs < 0 +void psxBLTZAL() { RepZBranchLinki32(<) } // Branch if Rs < 0 and link + +/********************************************************* +* Register branch logic * +* Format: OP rs, rt, offset * +*********************************************************/ +#define RepBranchi32(op) if(_i32(_rRs_) op _i32(_rRt_)) doBranch(_BranchTarget_); + +void psxBEQ() { RepBranchi32(==) } // Branch if Rs == Rt +void psxBNE() { RepBranchi32(!=) } // Branch if Rs != Rt + +/********************************************************* +* Jump to target * +* Format: OP target * +*********************************************************/ +void psxJ() { doBranch(_JumpTarget_); } +void psxJAL() { _SetLink(31); doBranch(_JumpTarget_); /*spyFunctions();*/ } + +/********************************************************* +* Register jump * +* Format: OP rs, rd * +*********************************************************/ +void psxJR() { doBranch(_u32(_rRs_)); } +void psxJALR() { if (_Rd_) { _SetLink(_Rd_); } doBranch(_u32(_rRs_)); } + +/////////////////////////////////////////// +// These macros are used to assemble the repassembler functions + +static __forceinline void execI() { + psxRegs.code = PSXMu32(psxRegs.pc); + + PSXCPU_LOG("%s\n", disR3000AF(psxRegs.code, psxRegs.pc)); + + psxRegs.pc+= 4; + psxRegs.cycle++; + psxCycleEE-=8; + + psxBSC[psxRegs.code >> 26](); +} + + +static void doBranch(s32 tar) { + branch2 = iopIsDelaySlot = true; + branchPC = tar; + execI(); + iopIsDelaySlot = false; + psxRegs.pc = branchPC; + + psxBranchTest(); +} + +static void intAlloc() { +} + +static void intReset() { +} + +static void intExecute() { + for (;;) execI(); +} + +#ifdef _DEBUG +extern u32 psxdump; +extern void iDumpPsxRegisters(u32,u32); +#endif + +static s32 intExecuteBlock( s32 eeCycles ) +{ + psxBreak = 0; + psxCycleEE = eeCycles; + + while (psxCycleEE > 0){ + branch2 = 0; + while (!branch2) { + execI(); + } + } + return psxBreak + psxCycleEE; +} + +static void intClear(u32 Addr, u32 Size) { +} + +static void intShutdown() { +} + +R3000Acpu psxInt = { + intAlloc, + intReset, + intExecute, + intExecuteBlock, + intClear, + intShutdown +}; diff --git a/pcsx2/R3000AOpcodeTables.cpp b/pcsx2/R3000AOpcodeTables.cpp index 6e00ff3ccb..0c79020eca 100644 --- a/pcsx2/R3000AOpcodeTables.cpp +++ b/pcsx2/R3000AOpcodeTables.cpp @@ -1,383 +1,383 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "PsxCommon.h" -#include "Common.h" - -extern void zeroEx(); - -// Note: Branch instructions of the Interpreter are defined externally because -// the recompiler shouldn't be using them (it isn't entirely safe, due to the -// delay slot and event handling differences between recs and ints) -void psxBGEZ(); -void psxBGEZAL(); -void psxBGTZ(); -void psxBLEZ(); -void psxBLTZ(); -void psxBLTZAL(); - -void psxBEQ(); -void psxBNE(); -void psxJ(); -void psxJAL(); - -void psxJR(); -void psxJALR(); - -/********************************************************* -* Arithmetic with immediate operand * -* Format: OP rt, rs, immediate * -*********************************************************/ -void psxADDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im (Exception on Integer Overflow) -void psxADDIU() { // Rt = Rs + Im - if (!_Rt_) - { - zeroEx(); - return; - } - _rRt_ = _u32(_rRs_) + _Imm_ ; -} -void psxANDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; } // Rt = Rs And Im -void psxORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; } // Rt = Rs Or Im -void psxXORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; } // Rt = Rs Xor Im -void psxSLTI() { if (!_Rt_) return; _rRt_ = _i32(_rRs_) < _Imm_ ; } // Rt = Rs < Im (Signed) -void psxSLTIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) < _ImmU_; } // Rt = Rs < Im (Unsigned) - -/********************************************************* -* Register arithmetic * -* Format: OP rd, rs, rt * -*********************************************************/ -void psxADD() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt (Exception on Integer Overflow) -void psxADDU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt -void psxSUB() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt (Exception on Integer Overflow) -void psxSUBU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt -void psxAND() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) & _u32(_rRt_); } // Rd = Rs And Rt -void psxOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) | _u32(_rRt_); } // Rd = Rs Or Rt -void psxXOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) ^ _u32(_rRt_); } // Rd = Rs Xor Rt -void psxNOR() { if (!_Rd_) return; _rRd_ =~(_u32(_rRs_) | _u32(_rRt_)); }// Rd = Rs Nor Rt -void psxSLT() { if (!_Rd_) return; _rRd_ = _i32(_rRs_) < _i32(_rRt_); } // Rd = Rs < Rt (Signed) -void psxSLTU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); } // Rd = Rs < Rt (Unsigned) - -/********************************************************* -* Register mult/div & Register trap logic * -* Format: OP rs, rt * -*********************************************************/ -void psxDIV() { - if (_rRt_ != 0) { - _rLo_ = _i32(_rRs_) / _i32(_rRt_); - _rHi_ = _i32(_rRs_) % _i32(_rRt_); - } -} - -void psxDIVU() { - if (_rRt_ != 0) { - _rLo_ = _rRs_ / _rRt_; - _rHi_ = _rRs_ % _rRt_; - } -} - -void psxMULT() { - u64 res = (s64)((s64)_i32(_rRs_) * (s64)_i32(_rRt_)); - - psxRegs.GPR.n.lo = (u32)(res & 0xffffffff); - psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff); -} - -void psxMULTU() { - u64 res = (u64)((u64)_u32(_rRs_) * (u64)_u32(_rRt_)); - - psxRegs.GPR.n.lo = (u32)(res & 0xffffffff); - psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff); -} - -/********************************************************* -* Shift arithmetic with constant shift * -* Format: OP rd, rt, sa * -*********************************************************/ -void psxSLL() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) << _Sa_; } // Rd = Rt << sa -void psxSRA() { if (!_Rd_) return; _rRd_ = _i32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (arithmetic) -void psxSRL() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (logical) - -/********************************************************* -* Shift arithmetic with variant register shift * -* Format: OP rd, rt, rs * -*********************************************************/ -void psxSLLV() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) << _u32(_rRs_); } // Rd = Rt << rs -void psxSRAV() { if (!_Rd_) return; _rRd_ = _i32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (arithmetic) -void psxSRLV() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (logical) - -/********************************************************* -* Load higher 16 bits of the first word in GPR with imm * -* Format: OP rt, immediate * -*********************************************************/ -void psxLUI() { if (!_Rt_) return; _rRt_ = psxRegs.code << 16; } // Upper halfword of Rt = Im - -/********************************************************* -* Move from HI/LO to GPR * -* Format: OP rd * -*********************************************************/ -void psxMFHI() { if (!_Rd_) return; _rRd_ = _rHi_; } // Rd = Hi -void psxMFLO() { if (!_Rd_) return; _rRd_ = _rLo_; } // Rd = Lo - -/********************************************************* -* Move to GPR to HI/LO & Register jump * -* Format: OP rs * -*********************************************************/ -void psxMTHI() { _rHi_ = _rRs_; } // Hi = Rs -void psxMTLO() { _rLo_ = _rRs_; } // Lo = Rs - -/********************************************************* -* Special purpose instructions * -* Format: OP * -*********************************************************/ -void psxBREAK() { - // Break exception - psx rom doens't handles this - psxRegs.pc -= 4; - psxException(0x24, iopIsDelaySlot); -} - -void psxSYSCALL() { - psxRegs.pc -= 4; - psxException(0x20, iopIsDelaySlot); - -} - -void psxRFE() { -// SysPrintf("RFE\n"); - psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) | - ((psxRegs.CP0.n.Status & 0x3c) >> 2); -// Log=0; -} - -/********************************************************* -* Load and store for GPR * -* Format: OP rt, offset(base) * -*********************************************************/ - -#define _oB_ (_u32(_rRs_) + _Imm_) - -void psxLB() { - if (_Rt_) { - _rRt_ = (s8 )psxMemRead8(_oB_); - } else { - psxMemRead8(_oB_); - } -} - -void psxLBU() { - if (_Rt_) { - _rRt_ = psxMemRead8(_oB_); - } else { - psxMemRead8(_oB_); - } -} - -void psxLH() { - if (_Rt_) { - _rRt_ = (s16)psxMemRead16(_oB_); - } else { - psxMemRead16(_oB_); - } -} - -void psxLHU() { - if (_Rt_) { - _rRt_ = psxMemRead16(_oB_); - } else { - psxMemRead16(_oB_); - } -} - -void psxLW() { - if (_Rt_) { - _rRt_ = psxMemRead32(_oB_); - } else { - psxMemRead32(_oB_); - } -} - -void psxLWL() { - u32 shift = (_oB_ & 3) << 3; - u32 mem = psxMemRead32(_oB_ & 0xfffffffc); - - if (!_Rt_) return; - _rRt_ = ( _u32(_rRt_) & (0x00ffffff >> shift) ) | - ( mem << (24 - shift) ); - - /* - Mem = 1234. Reg = abcd - - 0 4bcd (mem << 24) | (reg & 0x00ffffff) - 1 34cd (mem << 16) | (reg & 0x0000ffff) - 2 234d (mem << 8) | (reg & 0x000000ff) - 3 1234 (mem ) | (reg & 0x00000000) - - */ -} - -void psxLWR() { - u32 shift = (_oB_ & 3) << 3; - u32 mem = psxMemRead32(_oB_ & 0xfffffffc); - - if (!_Rt_) return; - _rRt_ = ( _u32(_rRt_) & (0xffffff00 << (24 - shift)) ) | - ( mem >> shift ); - - /* - Mem = 1234. Reg = abcd - - 0 1234 (mem ) | (reg & 0x00000000) - 1 a123 (mem >> 8) | (reg & 0xff000000) - 2 ab12 (mem >> 16) | (reg & 0xffff0000) - 3 abc1 (mem >> 24) | (reg & 0xffffff00) - - */ -} - -void psxSB() { psxMemWrite8 (_oB_, _u8 (_rRt_)); } -void psxSH() { psxMemWrite16(_oB_, _u16(_rRt_)); } -void psxSW() { psxMemWrite32(_oB_, _u32(_rRt_)); } - -void psxSWL() { - u32 shift = (_oB_ & 3) << 3; - u32 mem = psxMemRead32(_oB_ & 0xfffffffc); - - psxMemWrite32((_oB_ & 0xfffffffc), ( ( _u32(_rRt_) >> (24 - shift) ) ) | - ( mem & (0xffffff00 << shift) )); - /* - Mem = 1234. Reg = abcd - - 0 123a (reg >> 24) | (mem & 0xffffff00) - 1 12ab (reg >> 16) | (mem & 0xffff0000) - 2 1abc (reg >> 8) | (mem & 0xff000000) - 3 abcd (reg ) | (mem & 0x00000000) - - */ -} - -void psxSWR() { - u32 shift = (_oB_ & 3) << 3; - u32 mem = psxMemRead32(_oB_ & 0xfffffffc); - - psxMemWrite32((_oB_ & 0xfffffffc), ( ( _u32(_rRt_) << shift ) | - (mem & (0x00ffffff >> (24 - shift)) ) ) ); - /* - Mem = 1234. Reg = abcd - - 0 abcd (reg ) | (mem & 0x00000000) - 1 bcd4 (reg << 8) | (mem & 0x000000ff) - 2 cd34 (reg << 16) | (mem & 0x0000ffff) - 3 d234 (reg << 24) | (mem & 0x00ffffff) - - */ -} - -/********************************************************* -* Moves between GPR and COPx * -* Format: OP rt, fs * -*********************************************************/ -void psxMFC0() { if (!_Rt_) return; _rRt_ = (int)_rFs_; } -void psxCFC0() { if (!_Rt_) return; _rRt_ = (int)_rFs_; } - -void psxMTC0() { _rFs_ = _u32(_rRt_); } -void psxCTC0() { _rFs_ = _u32(_rRt_); } - -/********************************************************* -* Unknow instruction (would generate an exception) * -* Format: ? * -*********************************************************/ -void psxNULL() { -SysPrintf("psx: Unimplemented op %x\n", psxRegs.code); -} - -void psxSPECIAL() { - psxSPC[_Funct_](); -} - -void psxREGIMM() { - psxREG[_Rt_](); -} - -void psxCOP0() { - psxCP0[_Rs_](); -} - -void psxCOP2() { - psxCP2[_Funct_](); -} - -void psxBASIC() { - psxCP2BSC[_Rs_](); -} - -void (*psxBSC[64])() = { - psxSPECIAL, psxREGIMM, psxJ , psxJAL , psxBEQ , psxBNE , psxBLEZ, psxBGTZ, - psxADDI , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI , - psxCOP0 , psxNULL , psxCOP2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, - psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, - psxLB , psxLH , psxLWL , psxLW , psxLBU , psxLHU , psxLWR , psxNULL, - psxSB , psxSH , psxSWL , psxSW , psxNULL, psxNULL, psxSWR , psxNULL, - psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, - psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL -}; - - -void (*psxSPC[64])() = { - psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV , psxNULL , psxSRLV, psxSRAV, - psxJR , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL, - psxMFHI, psxMTHI , psxMFLO, psxMTLO, psxNULL , psxNULL , psxNULL, psxNULL, - psxMULT, psxMULTU, psxDIV , psxDIVU, psxNULL , psxNULL , psxNULL, psxNULL, - psxADD , psxADDU , psxSUB , psxSUBU, psxAND , psxOR , psxXOR , psxNOR , - psxNULL, psxNULL , psxSLT , psxSLTU, psxNULL , psxNULL , psxNULL, psxNULL, - psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL, - psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL -}; - -void (*psxREG[32])() = { - psxBLTZ , psxBGEZ , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, - psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, - psxBLTZAL, psxBGEZAL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, - psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL -}; - -void (*psxCP0[32])() = { - psxMFC0, psxNULL, psxCFC0, psxNULL, psxMTC0, psxNULL, psxCTC0, psxNULL, - psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, - psxRFE , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, - psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL -}; - -void (*psxCP2[64])() = { - psxBASIC, psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL, psxNULL, // 00 - psxNULL , psxNULL , psxNULL , psxNULL, psxNULL , psxNULL , psxNULL , psxNULL, // 08 - psxNULL , psxNULL, psxNULL, psxNULL, psxNULL , psxNULL , psxNULL , psxNULL, // 10 - psxNULL , psxNULL , psxNULL , psxNULL, psxNULL , psxNULL , psxNULL , psxNULL, // 18 - psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 20 - psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, // 28 - psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 30 - psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL // 38 -}; - -void (*psxCP2BSC[32])() = { - psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, - psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, - psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, - psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL -}; +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "PsxCommon.h" +#include "Common.h" + +extern void zeroEx(); + +// Note: Branch instructions of the Interpreter are defined externally because +// the recompiler shouldn't be using them (it isn't entirely safe, due to the +// delay slot and event handling differences between recs and ints) +void psxBGEZ(); +void psxBGEZAL(); +void psxBGTZ(); +void psxBLEZ(); +void psxBLTZ(); +void psxBLTZAL(); + +void psxBEQ(); +void psxBNE(); +void psxJ(); +void psxJAL(); + +void psxJR(); +void psxJALR(); + +/********************************************************* +* Arithmetic with immediate operand * +* Format: OP rt, rs, immediate * +*********************************************************/ +void psxADDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im (Exception on Integer Overflow) +void psxADDIU() { // Rt = Rs + Im + if (!_Rt_) + { + zeroEx(); + return; + } + _rRt_ = _u32(_rRs_) + _Imm_ ; +} +void psxANDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; } // Rt = Rs And Im +void psxORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; } // Rt = Rs Or Im +void psxXORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; } // Rt = Rs Xor Im +void psxSLTI() { if (!_Rt_) return; _rRt_ = _i32(_rRs_) < _Imm_ ; } // Rt = Rs < Im (Signed) +void psxSLTIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) < _ImmU_; } // Rt = Rs < Im (Unsigned) + +/********************************************************* +* Register arithmetic * +* Format: OP rd, rs, rt * +*********************************************************/ +void psxADD() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt (Exception on Integer Overflow) +void psxADDU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt +void psxSUB() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt (Exception on Integer Overflow) +void psxSUBU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt +void psxAND() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) & _u32(_rRt_); } // Rd = Rs And Rt +void psxOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) | _u32(_rRt_); } // Rd = Rs Or Rt +void psxXOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) ^ _u32(_rRt_); } // Rd = Rs Xor Rt +void psxNOR() { if (!_Rd_) return; _rRd_ =~(_u32(_rRs_) | _u32(_rRt_)); }// Rd = Rs Nor Rt +void psxSLT() { if (!_Rd_) return; _rRd_ = _i32(_rRs_) < _i32(_rRt_); } // Rd = Rs < Rt (Signed) +void psxSLTU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); } // Rd = Rs < Rt (Unsigned) + +/********************************************************* +* Register mult/div & Register trap logic * +* Format: OP rs, rt * +*********************************************************/ +void psxDIV() { + if (_rRt_ != 0) { + _rLo_ = _i32(_rRs_) / _i32(_rRt_); + _rHi_ = _i32(_rRs_) % _i32(_rRt_); + } +} + +void psxDIVU() { + if (_rRt_ != 0) { + _rLo_ = _rRs_ / _rRt_; + _rHi_ = _rRs_ % _rRt_; + } +} + +void psxMULT() { + u64 res = (s64)((s64)_i32(_rRs_) * (s64)_i32(_rRt_)); + + psxRegs.GPR.n.lo = (u32)(res & 0xffffffff); + psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff); +} + +void psxMULTU() { + u64 res = (u64)((u64)_u32(_rRs_) * (u64)_u32(_rRt_)); + + psxRegs.GPR.n.lo = (u32)(res & 0xffffffff); + psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff); +} + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ +void psxSLL() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) << _Sa_; } // Rd = Rt << sa +void psxSRA() { if (!_Rd_) return; _rRd_ = _i32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (arithmetic) +void psxSRL() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (logical) + +/********************************************************* +* Shift arithmetic with variant register shift * +* Format: OP rd, rt, rs * +*********************************************************/ +void psxSLLV() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) << _u32(_rRs_); } // Rd = Rt << rs +void psxSRAV() { if (!_Rd_) return; _rRd_ = _i32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (arithmetic) +void psxSRLV() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (logical) + +/********************************************************* +* Load higher 16 bits of the first word in GPR with imm * +* Format: OP rt, immediate * +*********************************************************/ +void psxLUI() { if (!_Rt_) return; _rRt_ = psxRegs.code << 16; } // Upper halfword of Rt = Im + +/********************************************************* +* Move from HI/LO to GPR * +* Format: OP rd * +*********************************************************/ +void psxMFHI() { if (!_Rd_) return; _rRd_ = _rHi_; } // Rd = Hi +void psxMFLO() { if (!_Rd_) return; _rRd_ = _rLo_; } // Rd = Lo + +/********************************************************* +* Move to GPR to HI/LO & Register jump * +* Format: OP rs * +*********************************************************/ +void psxMTHI() { _rHi_ = _rRs_; } // Hi = Rs +void psxMTLO() { _rLo_ = _rRs_; } // Lo = Rs + +/********************************************************* +* Special purpose instructions * +* Format: OP * +*********************************************************/ +void psxBREAK() { + // Break exception - psx rom doens't handles this + psxRegs.pc -= 4; + psxException(0x24, iopIsDelaySlot); +} + +void psxSYSCALL() { + psxRegs.pc -= 4; + psxException(0x20, iopIsDelaySlot); + +} + +void psxRFE() { +// SysPrintf("RFE\n"); + psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) | + ((psxRegs.CP0.n.Status & 0x3c) >> 2); +// Log=0; +} + +/********************************************************* +* Load and store for GPR * +* Format: OP rt, offset(base) * +*********************************************************/ + +#define _oB_ (_u32(_rRs_) + _Imm_) + +void psxLB() { + if (_Rt_) { + _rRt_ = (s8 )psxMemRead8(_oB_); + } else { + psxMemRead8(_oB_); + } +} + +void psxLBU() { + if (_Rt_) { + _rRt_ = psxMemRead8(_oB_); + } else { + psxMemRead8(_oB_); + } +} + +void psxLH() { + if (_Rt_) { + _rRt_ = (s16)psxMemRead16(_oB_); + } else { + psxMemRead16(_oB_); + } +} + +void psxLHU() { + if (_Rt_) { + _rRt_ = psxMemRead16(_oB_); + } else { + psxMemRead16(_oB_); + } +} + +void psxLW() { + if (_Rt_) { + _rRt_ = psxMemRead32(_oB_); + } else { + psxMemRead32(_oB_); + } +} + +void psxLWL() { + u32 shift = (_oB_ & 3) << 3; + u32 mem = psxMemRead32(_oB_ & 0xfffffffc); + + if (!_Rt_) return; + _rRt_ = ( _u32(_rRt_) & (0x00ffffff >> shift) ) | + ( mem << (24 - shift) ); + + /* + Mem = 1234. Reg = abcd + + 0 4bcd (mem << 24) | (reg & 0x00ffffff) + 1 34cd (mem << 16) | (reg & 0x0000ffff) + 2 234d (mem << 8) | (reg & 0x000000ff) + 3 1234 (mem ) | (reg & 0x00000000) + + */ +} + +void psxLWR() { + u32 shift = (_oB_ & 3) << 3; + u32 mem = psxMemRead32(_oB_ & 0xfffffffc); + + if (!_Rt_) return; + _rRt_ = ( _u32(_rRt_) & (0xffffff00 << (24 - shift)) ) | + ( mem >> shift ); + + /* + Mem = 1234. Reg = abcd + + 0 1234 (mem ) | (reg & 0x00000000) + 1 a123 (mem >> 8) | (reg & 0xff000000) + 2 ab12 (mem >> 16) | (reg & 0xffff0000) + 3 abc1 (mem >> 24) | (reg & 0xffffff00) + + */ +} + +void psxSB() { psxMemWrite8 (_oB_, _u8 (_rRt_)); } +void psxSH() { psxMemWrite16(_oB_, _u16(_rRt_)); } +void psxSW() { psxMemWrite32(_oB_, _u32(_rRt_)); } + +void psxSWL() { + u32 shift = (_oB_ & 3) << 3; + u32 mem = psxMemRead32(_oB_ & 0xfffffffc); + + psxMemWrite32((_oB_ & 0xfffffffc), ( ( _u32(_rRt_) >> (24 - shift) ) ) | + ( mem & (0xffffff00 << shift) )); + /* + Mem = 1234. Reg = abcd + + 0 123a (reg >> 24) | (mem & 0xffffff00) + 1 12ab (reg >> 16) | (mem & 0xffff0000) + 2 1abc (reg >> 8) | (mem & 0xff000000) + 3 abcd (reg ) | (mem & 0x00000000) + + */ +} + +void psxSWR() { + u32 shift = (_oB_ & 3) << 3; + u32 mem = psxMemRead32(_oB_ & 0xfffffffc); + + psxMemWrite32((_oB_ & 0xfffffffc), ( ( _u32(_rRt_) << shift ) | + (mem & (0x00ffffff >> (24 - shift)) ) ) ); + /* + Mem = 1234. Reg = abcd + + 0 abcd (reg ) | (mem & 0x00000000) + 1 bcd4 (reg << 8) | (mem & 0x000000ff) + 2 cd34 (reg << 16) | (mem & 0x0000ffff) + 3 d234 (reg << 24) | (mem & 0x00ffffff) + + */ +} + +/********************************************************* +* Moves between GPR and COPx * +* Format: OP rt, fs * +*********************************************************/ +void psxMFC0() { if (!_Rt_) return; _rRt_ = (int)_rFs_; } +void psxCFC0() { if (!_Rt_) return; _rRt_ = (int)_rFs_; } + +void psxMTC0() { _rFs_ = _u32(_rRt_); } +void psxCTC0() { _rFs_ = _u32(_rRt_); } + +/********************************************************* +* Unknow instruction (would generate an exception) * +* Format: ? * +*********************************************************/ +void psxNULL() { +SysPrintf("psx: Unimplemented op %x\n", psxRegs.code); +} + +void psxSPECIAL() { + psxSPC[_Funct_](); +} + +void psxREGIMM() { + psxREG[_Rt_](); +} + +void psxCOP0() { + psxCP0[_Rs_](); +} + +void psxCOP2() { + psxCP2[_Funct_](); +} + +void psxBASIC() { + psxCP2BSC[_Rs_](); +} + +void (*psxBSC[64])() = { + psxSPECIAL, psxREGIMM, psxJ , psxJAL , psxBEQ , psxBNE , psxBLEZ, psxBGTZ, + psxADDI , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI , + psxCOP0 , psxNULL , psxCOP2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, + psxLB , psxLH , psxLWL , psxLW , psxLBU , psxLHU , psxLWR , psxNULL, + psxSB , psxSH , psxSWL , psxSW , psxNULL, psxNULL, psxSWR , psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL +}; + + +void (*psxSPC[64])() = { + psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV , psxNULL , psxSRLV, psxSRAV, + psxJR , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL, + psxMFHI, psxMTHI , psxMFLO, psxMTLO, psxNULL , psxNULL , psxNULL, psxNULL, + psxMULT, psxMULTU, psxDIV , psxDIVU, psxNULL , psxNULL , psxNULL, psxNULL, + psxADD , psxADDU , psxSUB , psxSUBU, psxAND , psxOR , psxXOR , psxNOR , + psxNULL, psxNULL , psxSLT , psxSLTU, psxNULL , psxNULL , psxNULL, psxNULL, + psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL, + psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL +}; + +void (*psxREG[32])() = { + psxBLTZ , psxBGEZ , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxBLTZAL, psxBGEZAL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL +}; + +void (*psxCP0[32])() = { + psxMFC0, psxNULL, psxCFC0, psxNULL, psxMTC0, psxNULL, psxCTC0, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxRFE , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL +}; + +void (*psxCP2[64])() = { + psxBASIC, psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL, psxNULL, // 00 + psxNULL , psxNULL , psxNULL , psxNULL, psxNULL , psxNULL , psxNULL , psxNULL, // 08 + psxNULL , psxNULL, psxNULL, psxNULL, psxNULL , psxNULL , psxNULL , psxNULL, // 10 + psxNULL , psxNULL , psxNULL , psxNULL, psxNULL , psxNULL , psxNULL , psxNULL, // 18 + psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 20 + psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, // 28 + psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 30 + psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL // 38 +}; + +void (*psxCP2BSC[32])() = { + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL +}; diff --git a/pcsx2/R5900.cpp b/pcsx2/R5900.cpp index 661d0598d0..2d8549139b 100644 --- a/pcsx2/R5900.cpp +++ b/pcsx2/R5900.cpp @@ -1,693 +1,693 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "Counters.h" - -#include "Memory.h" -#include "Hw.h" -#include "DebugTools/Debug.h" -#include "R3000A.h" -#include "VUmicro.h" -#include "COP0.h" - -#include "GS.h" -#include "IPU/IPU.h" -#include "Vif.h" -#include "VifDma.h" -#include "SPR.h" -#include "Sif.h" - -#include "Paths.h" - -using namespace R5900; // for R5900 disasm tools - -s32 EEsCycle; // used to sync the IOP to the EE -u32 EEoCycle; - -static int inter; - -PCSX2_ALIGNED16(cpuRegisters cpuRegs); -PCSX2_ALIGNED16(fpuRegisters fpuRegs); -PCSX2_ALIGNED16(tlbs tlb[48]); -R5900cpu *Cpu = NULL; - -u32 bExecBIOS = 0; // set if the BIOS has already been executed - -static bool cpuIsInitialized = false; -static uint eeWaitCycles = 1024; - -bool eeEventTestIsActive = false; - -// A run-once procedure for initializing the emulation state. -// Can be done anytime after allocating memory, and before calling Cpu->Execute(). -// Multiple calls to this function are automatically ignored. -/*void cpuInit() -{ - DevCon::WriteLn( "cpuInit > %s", params cpuIsInitialized ? "Initializing..." : "Skipping (already initialized)" ); - - if( cpuIsInitialized ) return; - - cpuIsInitialized = true; - - // non memInit() currently since we don't support soft resets. memory is initialized in full - // instead during cpuReset() [using memReset()] - //memInit(); -}*/ - -void cpuReset() -{ - mtgsWaitGS(); // GS better be done processing before we reset the EE, just in case. - //cpuInit(); // more just-in-caseness! - - //if( !cpuIsInitialized ) - { - cpuIsInitialized = true; - } - - memReset(); - psxMemReset(); - vuMicroMemReset(); - - memzero_obj(cpuRegs); - memzero_obj(fpuRegs); - memzero_obj(tlb); - - cpuRegs.pc = 0xbfc00000; ///set pc reg to stack - cpuRegs.CP0.n.Config = 0x440; - cpuRegs.CP0.n.Status.val = 0x70400004; //0x10900000 <-- wrong; // COP0 enabled | BEV = 1 | TS = 1 - cpuRegs.CP0.n.PRid = 0x00002e20; // PRevID = Revision ID, same as R5900 - fpuRegs.fprc[0] = 0x00002e00; // fpu Revision.. - fpuRegs.fprc[31] = 0x01000001; // fpu Status/Control - - g_nextBranchCycle = cpuRegs.cycle + 4; - EEsCycle = 0; - EEoCycle = cpuRegs.cycle; - eeWaitCycles = CHECK_WAITCYCLE_HACK ? 3072 : 768; - - // Cyclerate hacks effectively speed up the rate of event tests, so we can safely boost - // the WaitCycles value here for x2 and x3 modes: - if( CHECK_EE_CYCLERATE > 1 ) - eeWaitCycles += 1024; - - hwReset(); - vif0Reset(); - vif1Reset(); - rcntInit(); - psxReset(); -} - -void cpuShutdown() -{ - //if( !cpuIsInitialized ) return; - //cpuIsInitialized = false; - - mtgsWaitGS(); - - hwShutdown(); -// biosShutdown(); - psxShutdown(); - disR5900FreeSyms(); -} - -void cpuException(u32 code, u32 bd) -{ - cpuRegs.branch = 0; // Tells the interpreter that an exception occurred during a branch. - - u32 offset; - cpuRegs.CP0.n.Cause = code & 0xffff; - - if(cpuRegs.CP0.n.Status.b.ERL == 0){ //Error Level 0-1 - if(((code & 0x7C) >= 0x8) && ((code & 0x7C) <= 0xC)) offset = 0x0; //TLB Refill - else if ((code & 0x7C) == 0x0) offset = 0x200; //Interrupt - else offset = 0x180; // Everything else - - - if (cpuRegs.CP0.n.Status.b.EXL == 0) { - cpuRegs.CP0.n.Status.b.EXL = 1; - if (bd) { - Console::Notice("branch delay!!"); - cpuRegs.CP0.n.EPC = cpuRegs.pc - 4; - cpuRegs.CP0.n.Cause |= 0x80000000; - } else { - cpuRegs.CP0.n.EPC = cpuRegs.pc; - cpuRegs.CP0.n.Cause &= ~0x80000000; - } - } else { - offset = 0x180; //Overrride the cause - //Console::Notice("cpuException: Status.EXL = 1 cause %x", params code); - } - if (cpuRegs.CP0.n.Status.b.BEV == 0) { - cpuRegs.pc = 0x80000000 + offset; - } else { - cpuRegs.pc = 0xBFC00200 + offset; - } - } else { //Error Level 2 - Console::Error("*PCSX2* FIX ME: Level 2 cpuException"); - if((code & 0x38000) <= 0x8000 ) { //Reset / NMI - cpuRegs.pc = 0xBFC00000; - Console::Notice("Reset request"); - UpdateCP0Status(); - return; - } else if((code & 0x38000) == 0x10000) offset = 0x80; //Performance Counter - else if((code & 0x38000) == 0x18000) offset = 0x100; //Debug - else Console::Error("Unknown Level 2 Exception!! Cause %x", params code); - - if (cpuRegs.CP0.n.Status.b.EXL == 0) { - cpuRegs.CP0.n.Status.b.EXL = 1; - if (bd) { - Console::Notice("branch delay!!"); - cpuRegs.CP0.n.EPC = cpuRegs.pc - 4; - cpuRegs.CP0.n.Cause |= 0x80000000; - } else { - cpuRegs.CP0.n.EPC = cpuRegs.pc; - cpuRegs.CP0.n.Cause &= ~0x80000000; - } - } else { - offset = 0x180; //Overrride the cause - Console::Notice("cpuException: Status.EXL = 1 cause %x", params code); - } - - if (cpuRegs.CP0.n.Status.b.DEV == 0) { - cpuRegs.pc = 0x80000000 + offset; - } else { - cpuRegs.pc = 0xBFC00200 + offset; - } - } - UpdateCP0Status(); -} - -void cpuTlbMiss(u32 addr, u32 bd, u32 excode) { - Console::Error("cpuTlbMiss pc:%x, cycl:%x, addr: %x, status=%x, code=%x", params cpuRegs.pc, cpuRegs.cycle, addr, cpuRegs.CP0.n.Status.val, excode); - if (bd) { - Console::Notice("branch delay!!"); - } - - assert(0); // temporary - - cpuRegs.CP0.n.BadVAddr = addr; - cpuRegs.CP0.n.Context &= 0xFF80000F; - cpuRegs.CP0.n.Context |= (addr >> 9) & 0x007FFFF0; - cpuRegs.CP0.n.EntryHi = (addr & 0xFFFFE000) | (cpuRegs.CP0.n.EntryHi & 0x1FFF); - - cpuRegs.CP0.n.Cause = excode; - if (!(cpuRegs.CP0.n.Status.val & 0x2)) { // EXL bit - cpuRegs.CP0.n.EPC = cpuRegs.pc - 4; - } - - if ((cpuRegs.CP0.n.Status.val & 0x1) == 0) { - cpuRegs.pc = 0x80000000; - } else { - cpuRegs.pc = 0x80000180; - } - - cpuRegs.CP0.n.Status.b.EXL = 1; - UpdateCP0Status(); -// Log=1; varLog|= 0x40000000; -} - -void cpuTlbMissR(u32 addr, u32 bd) { - cpuTlbMiss(addr, bd, EXC_CODE_TLBL); -} - -void cpuTlbMissW(u32 addr, u32 bd) { - cpuTlbMiss(addr, bd, EXC_CODE_TLBS); -} - -void JumpCheckSym(u32 addr, u32 pc) { -#if 0 -// if (addr == 0x80051770) { SysPrintf("Log!: %s\n", PSM(cpuRegs.GPR.n.a0.UL[0])); Log=1; varLog|= 0x40000000; } - if (addr == 0x8002f150) { SysPrintf("printk: %s\n", PSM(cpuRegs.GPR.n.a0.UL[0])); } - if (addr == 0x8002aba0) return; - if (addr == 0x8002f450) return; - if (addr == 0x800dd520) return; -// if (addr == 0x80049300) SysPrintf("register_blkdev: %x\n", cpuRegs.GPR.n.a0.UL[0]); - if (addr == 0x8013cb70) { SysPrintf("change_root: %x\n", cpuRegs.GPR.n.a0.UL[0]); } -// if (addr == 0x8013d1e8) { SysPrintf("Log!\n"); Log++; if (Log==2) exit(0); varLog|= 0x40000000; } -// if (addr == 0x00234e88) { SysPrintf("StoreImage\n"); Log=1; /*psMu32(0x234e88) = 0x03e00008; psMu32(0x234e8c) = 0;*/ } -#endif -/* if ((pc >= 0x00131D50 && - pc < 0x00132454) || - (pc >= 0x00786a90 && - pc < 0x00786ac8))*/ - /*if (varLog & 0x40000000) { - char *str; - char *strf; - - str = disR5900GetSym(addr); - if (str != NULL) { - strf = disR5900GetUpperSym(pc); - if (strf) { - SysPrintf("Func %8.8x: %s (called by %8.8x: %s)\n", addr, str, pc, strf); - } else { - SysPrintf("Func %8.8x: %s (called by %x)\n", addr, str, pc); - } - if (!strcmp(str, "printf")) { SysPrintf("%s\n", (char*)PSM(cpuRegs.GPR.n.a0.UL[0])); } - if (!strcmp(str, "printk")) { SysPrintf("%s\n", (char*)PSM(cpuRegs.GPR.n.a0.UL[0])); } - } - }*/ -} - -void JumpCheckSymRet(u32 addr) { - /*if (varLog & 0x40000000) { - char *str; - str = disR5900GetUpperSym(addr); - if (str != NULL) { - SysPrintf("Return : %s, v0=%8.8x\n", str, cpuRegs.GPR.n.v0.UL[0]); - } - }*/ -} - -__forceinline void _cpuTestMissingINTC() { - if (cpuRegs.CP0.n.Status.val & 0x400 && - psHu32(INTC_STAT) & psHu32(INTC_MASK)) { - if ((cpuRegs.interrupt & (1 << 30)) == 0) { - SysPrintf("*PCSX2*: Error, missing INTC Interrupt\n"); - } - } -} - -__forceinline void _cpuTestMissingDMAC() { - if (cpuRegs.CP0.n.Status.val & 0x800 && - (psHu16(0xe012) & psHu16(0xe010) || - psHu16(0xe010) & 0x8000)) { - if ((cpuRegs.interrupt & (1 << 31)) == 0) { - SysPrintf("*PCSX2*: Error, missing DMAC Interrupt\n"); - } - } -} - -void cpuTestMissingHwInts() { - if ((cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001) { - _cpuTestMissingINTC(); - _cpuTestMissingDMAC(); -// _cpuTestTIMR(); - } -} - -// sets a branch test to occur some time from an arbitrary starting point. -__forceinline int cpuSetNextBranch( u32 startCycle, s32 delta ) -{ - // typecast the conditional to signed so that things don't blow up - // if startCycle is greater than our next branch cycle. - - if( (int)(g_nextBranchCycle - startCycle) > delta ) - { - g_nextBranchCycle = startCycle + delta; - return 1; - } - return 0; -} - -// sets a branch to occur some time from the current cycle -__forceinline int cpuSetNextBranchDelta( s32 delta ) -{ - return cpuSetNextBranch( cpuRegs.cycle, delta ); -} - -// tests the cpu cycle agaisnt the given start and delta values. -// Returns true if the delta time has passed. -__forceinline int cpuTestCycle( u32 startCycle, s32 delta ) -{ - // typecast the conditional to signed so that things don't explode - // if the startCycle is ahead of our current cpu cycle. - - return (int)(cpuRegs.cycle - startCycle) >= delta; -} - -// tells the EE to run the branch test the next time it gets a chance. -__forceinline void cpuSetBranch() -{ - g_nextBranchCycle = cpuRegs.cycle; -} - -void cpuClearInt( uint i ) -{ - jASSUME( i < 32 ); - cpuRegs.interrupt &= ~(1 << i); -} - -static __forceinline void TESTINT( u8 n, void (*callback)() ) -{ - if( !(cpuRegs.interrupt & (1 << n)) ) return; - - if( cpuTestCycle( cpuRegs.sCycle[n], cpuRegs.eCycle[n] ) ) - { - cpuClearInt( n ); - callback(); - } - else - cpuSetNextBranch( cpuRegs.sCycle[n], cpuRegs.eCycle[n] ); -} - -static __forceinline void _cpuTestInterrupts() -{ - /* These are 'pcsx2 interrupts', they handle asynchronous stuff - that depends on the cycle timings */ - - TESTINT(1, vif1Interrupt); - TESTINT(2, gsInterrupt); - TESTINT(5, EEsif0Interrupt); - TESTINT(6, EEsif1Interrupt); - - // Profile-guided Optimization (sorta) - // The following ints are rarely called. Encasing them in a conditional - // as follows helps speed up most games. - - if( cpuRegs.interrupt & ( 1 | (3 << 3) | (3<<8) | (3<<10)) ) - { - TESTINT(0, vif0Interrupt); -#ifndef IPU_INLINE_IRQS - TESTINT(3, ipu0Interrupt); - TESTINT(4, ipu1Interrupt); -#endif - TESTINT(8, SPRFROMinterrupt); - TESTINT(9, SPRTOinterrupt); - - TESTINT(10, vifMFIFOInterrupt); - TESTINT(11, gifMFIFOInterrupt); - } -} - -static __forceinline void _cpuTestTIMR() -{ - cpuRegs.CP0.n.Count += cpuRegs.cycle-s_iLastCOP0Cycle; - s_iLastCOP0Cycle = cpuRegs.cycle; - - // fixme: this looks like a hack to make up for the fact that the TIMR - // doesn't yet have a proper mechanism for setting itself up on a nextBranchCycle. - // A proper fix would schedule the TIMR to trigger at a specific cycle anytime - // the Count or Compare registers are modified. - - if ( (cpuRegs.CP0.n.Status.val & 0x8000) && - cpuRegs.CP0.n.Count >= cpuRegs.CP0.n.Compare && cpuRegs.CP0.n.Count < cpuRegs.CP0.n.Compare+1000 ) - { - Console::Status("timr intr: %x, %x", params cpuRegs.CP0.n.Count, cpuRegs.CP0.n.Compare); - cpuException(0x808000, cpuRegs.branch); - } -} - -static __forceinline void _cpuTestPERF() -{ - // fixme - The interpreter and recompiler both re-calculate these values - // whenever they are read, so updating them at regular intervals *should be* - // merely a common courtesy. But when I set them up to be called less - // frequently some games would crash. I'd like to figure out why someday. [Air] - - if((cpuRegs.PERF.n.pccr & 0x800003E0) == 0x80000020) { - cpuRegs.PERF.n.pcr0 += cpuRegs.cycle-s_iLastPERFCycle[0]; - s_iLastPERFCycle[0] = cpuRegs.cycle; - } - if((cpuRegs.PERF.n.pccr & 0x800F8000) == 0x80008000) { - cpuRegs.PERF.n.pcr1 += cpuRegs.cycle-s_iLastPERFCycle[1]; - s_iLastPERFCycle[1] = cpuRegs.cycle; - } -} - -// Checks the COP0.Status for exception enablings. -// Exception handling for certain modes is *not* currently supported, this function filters -// them out. Exceptions while the exception handler is active (EIE), or exceptions of any -// level other than 0 are ignored here. - -static bool cpuIntsEnabled() -{ - return cpuRegs.CP0.n.Status.b.EIE && cpuRegs.CP0.n.Status.b.IE && - !cpuRegs.CP0.n.Status.b.EXL && (cpuRegs.CP0.n.Status.b.ERL == 0); -} - -// if cpuRegs.cycle is greater than this cycle, should check cpuBranchTest for updates -u32 g_nextBranchCycle = 0; - -// Shared portion of the branch test, called from both the Interpreter -// and the recompiler. (moved here to help alleviate redundant code) -__forceinline bool _cpuBranchTest_Shared() -{ - eeEventTestIsActive = true; - g_nextBranchCycle = cpuRegs.cycle + eeWaitCycles; - - EEsCycle += cpuRegs.cycle - EEoCycle; - EEoCycle = cpuRegs.cycle; - - if( EEsCycle > 0 ) - iopBranchAction = true; - - // ---- Counters ------------- - bool vsyncEvent = false; - rcntUpdate_hScanline(); - - if( cpuTestCycle( nextsCounter, nextCounter ) ) - { - vsyncEvent = rcntUpdate(); - _cpuTestPERF(); - } - - _cpuTestTIMR(); - - // ---- Interrupts ------------- - // Handles all interrupts except 30 and 31, which are handled later. - - if( cpuRegs.interrupt & ~(3<<30) ) - _cpuTestInterrupts(); - - // ---- IOP ------------- - // * It's important to run a psxBranchTest before calling ExecuteBlock. This - // is because the IOP does not always perform branch tests before returning - // (during the prev branch) and also so it can act on the state the EE has - // given it before executing any code. - // - // * The IOP cannot always be run. If we run IOP code every time through the - // cpuBranchTest, the IOP generally starts to run way ahead of the EE. - - psxBranchTest(); - - if( iopBranchAction ) - { - //if( EEsCycle < -450 ) - // Console::WriteLn( " IOP ahead by: %d cycles", params -EEsCycle ); - - // Experimental and Probably Unnecessry Logic --> - // Check if the EE already has an exception pending, and if so we shouldn't - // waste too much time updating the IOP. Theory being that the EE and IOP should - // run closely in sync during raised exception events. But in practice it didn't - // seem to make much of a difference. - - // Note: The IOP is very good about chaining blocks together so it tends to - // run lots of cycles, even with only 32 (4 IOP) cycles specified here. That's - // probably why it doesn't improve sync much. - - /*bool eeExceptPending = cpuIntsEnabled() && - //( cpuRegs.CP0.n.Status.b.EIE && cpuRegs.CP0.n.Status.b.IE && (cpuRegs.CP0.n.Status.b.ERL == 0) ) && - //( (cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001 ) && - ( (cpuRegs.interrupt & (3<<30)) != 0 ); - - if( eeExceptPending ) - { - // ExecuteBlock returns a negative value, so subtract it from the cycle count - // specified to get the total cycles processed! :D - int cycleCount = std::min( EEsCycle, (s32)(eeWaitCycles>>4) ); - int cyclesRun = cycleCount - psxCpu->ExecuteBlock( cycleCount ); - EEsCycle -= cyclesRun; - //Console::Notice( "IOP Exception-Pending Execution -- EEsCycle: %d", params EEsCycle ); - } - else*/ - { - EEsCycle = psxCpu->ExecuteBlock( EEsCycle ); - } - - iopBranchAction = false; - } - - // ---- VU0 ------------- - - if (VU0.VI[REG_VPU_STAT].UL & 0x1) - { - // We're in a BranchTest. All dynarec registers are flushed - // so there is no need to freeze registers here. - CpuVU0.ExecuteBlock(); - - // This might be needed to keep the EE and VU0 in sync. - // A better fix will require hefty changes to the VU recs. -_- - if(VU0.VI[REG_VPU_STAT].UL & 0x1) - cpuSetNextBranchDelta( 768 ); - } - - // Note: We don't update the VU1 here because it runs it's micro-programs in - // one shot always. That is, when a program is executed the VU1 doesn't even - // bother to return until the program is completely finished. - - // ---- Schedule Next Event Test -------------- - - if( EEsCycle > 192 ) - { - // EE's running way ahead of the IOP still, so we should branch quickly to give the - // IOP extra timeslices in short order. - - cpuSetNextBranchDelta( 48 ); - //Console::Notice( "EE ahead of the IOP -- Rapid Branch! %d", params EEsCycle ); - } - - // The IOP could be running ahead/behind of us, so adjust the iop's next branch by its - // relative position to the EE (via EEsCycle) - cpuSetNextBranchDelta( ((g_psxNextBranchCycle-psxRegs.cycle)*8) - EEsCycle ); - - // Apply the hsync counter's nextCycle - cpuSetNextBranch( counters[4].sCycle, counters[4].CycleT ); - - // Apply vsync and other counter nextCycles - cpuSetNextBranch( nextsCounter, nextCounter ); - - eeEventTestIsActive = false; - - // ---- INTC / DMAC Exceptions ----------------- - // Raise the INTC and DMAC interrupts here, which usually throw exceptions. - // This should be done last since the IOP and the VU0 can raise several EE - // exceptions. - - //if ((cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001) - if( cpuIntsEnabled() ) - { - TESTINT(30, intcInterrupt); - TESTINT(31, dmacInterrupt); - } - - return vsyncEvent; -} - -void cpuTestINTCInts() -{ - if( cpuRegs.interrupt & (1 << 30) ) return; - //if( (cpuRegs.CP0.n.Status.val & 0x10407) != 0x10401 ) return; - if( !cpuIntsEnabled() ) return; - if( (psHu32(INTC_STAT) & psHu32(INTC_MASK)) == 0 ) return; - - cpuRegs.interrupt|= 1 << 30; - cpuRegs.sCycle[30] = cpuRegs.cycle; - cpuRegs.eCycle[30] = 0; - - // only set the next branch delta if the exception won't be handled for - // the current branch... - if( !eeEventTestIsActive ) - cpuSetNextBranchDelta( 4 ); - else if(psxCycleEE > 0) - { - psxBreak += psxCycleEE; // record the number of cycles the IOP didn't run. - psxCycleEE = 0; - } -} - -__forceinline void cpuTestDMACInts() -{ - if ( cpuRegs.interrupt & (1 << 31) ) return; - if ((cpuRegs.CP0.n.Status.val & 0x10807) != 0x10801) return; - - if ( ( (psHu16(0xe012) & psHu16(0xe010)) == 0) && - ( (psHu16(0xe010) & 0x8000) == 0) ) return; - - cpuRegs.interrupt|= 1 << 31; - cpuRegs.sCycle[31] = cpuRegs.cycle; - cpuRegs.eCycle[31] = 0; - - // only set the next branch delta if the exception won't be handled for - // the current branch... - if( !eeEventTestIsActive ) - cpuSetNextBranchDelta( 4 ); - else if(psxCycleEE > 0) - { - psxBreak += psxCycleEE; // record the number of cycles the IOP didn't run. - psxCycleEE = 0; - } -} - -__forceinline void cpuTestTIMRInts() { - if ((cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001) { - _cpuTestPERF(); - _cpuTestTIMR(); - } -} - -void cpuTestHwInts() { - cpuTestINTCInts(); - cpuTestDMACInts(); - cpuTestTIMRInts(); -} - -// This function performs a "hackish" execution of the BIOS stub, which initializes EE -// memory and hardware. It forcefully breaks execution when the stub is finished, prior -// to the PS2 logos being displayed. This allows us to "shortcut" right into a game -// without having to wait through the logos or endure game/bios localization checks. -void cpuExecuteBios() -{ - // Set the video mode to user's default request: - // (right now we always default to NTSC) - gsSetVideoRegionType( Config.PsxType & 1 ); - - Console::Notice( "* PCSX2 *: ExecuteBios" ); - - bExecBIOS = TRUE; - while (cpuRegs.pc != 0x00200008 && - cpuRegs.pc != 0x00100008) { - g_nextBranchCycle = cpuRegs.cycle; - Cpu->ExecuteBlock(); - } - - bExecBIOS = FALSE; -// { -// FILE* f = fopen("eebios.bin", "wb"); -// fwrite(PSM(0x80000000), 0x100000, 1, f); -// fclose(f); -// exit(0); - -// f = fopen("iopbios.bin", "wb"); -// fwrite(PS2MEM_PSX, 0x80000, 1, f); -// fclose(f); -// } - -// REC_CLEARM(0x00200008); -// REC_CLEARM(0x00100008); -// REC_CLEARM(cpuRegs.pc); - - // Reset the EErecs here, because the bios generates "slow" blocks that have hacky - // bBiosEnd checks in them and stuff. This deletes them so that the recs replace them - // with new faster versions: - Cpu->Reset(); - - Console::Notice("* PCSX2 *: ExecuteBios Complete"); - //GSprintf(5, "PCSX2 " PCSX2_VERSION "\nExecuteBios Complete\n"); -} - -__forceinline void CPU_INT( u32 n, s32 ecycle) -{ - cpuRegs.interrupt|= 1 << n; - cpuRegs.sCycle[n] = cpuRegs.cycle; - cpuRegs.eCycle[n] = ecycle; - - // Interrupt is happening soon: make sure both EE and IOP are aware. - - if( ecycle <= 28 && psxCycleEE > 0 ) - { - // If running in the IOP, force it to break immediately into the EE. - // the EE's branch test is due to run. - - psxBreak += psxCycleEE; // record the number of cycles the IOP didn't run. - psxCycleEE = 0; - } - - cpuSetNextBranchDelta( cpuRegs.eCycle[n] ); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "Counters.h" + +#include "Memory.h" +#include "Hw.h" +#include "DebugTools/Debug.h" +#include "R3000A.h" +#include "VUmicro.h" +#include "COP0.h" + +#include "GS.h" +#include "IPU/IPU.h" +#include "Vif.h" +#include "VifDma.h" +#include "SPR.h" +#include "Sif.h" + +#include "Paths.h" + +using namespace R5900; // for R5900 disasm tools + +s32 EEsCycle; // used to sync the IOP to the EE +u32 EEoCycle; + +static int inter; + +PCSX2_ALIGNED16(cpuRegisters cpuRegs); +PCSX2_ALIGNED16(fpuRegisters fpuRegs); +PCSX2_ALIGNED16(tlbs tlb[48]); +R5900cpu *Cpu = NULL; + +u32 bExecBIOS = 0; // set if the BIOS has already been executed + +static bool cpuIsInitialized = false; +static uint eeWaitCycles = 1024; + +bool eeEventTestIsActive = false; + +// A run-once procedure for initializing the emulation state. +// Can be done anytime after allocating memory, and before calling Cpu->Execute(). +// Multiple calls to this function are automatically ignored. +/*void cpuInit() +{ + DevCon::WriteLn( "cpuInit > %s", params cpuIsInitialized ? "Initializing..." : "Skipping (already initialized)" ); + + if( cpuIsInitialized ) return; + + cpuIsInitialized = true; + + // non memInit() currently since we don't support soft resets. memory is initialized in full + // instead during cpuReset() [using memReset()] + //memInit(); +}*/ + +void cpuReset() +{ + mtgsWaitGS(); // GS better be done processing before we reset the EE, just in case. + //cpuInit(); // more just-in-caseness! + + //if( !cpuIsInitialized ) + { + cpuIsInitialized = true; + } + + memReset(); + psxMemReset(); + vuMicroMemReset(); + + memzero_obj(cpuRegs); + memzero_obj(fpuRegs); + memzero_obj(tlb); + + cpuRegs.pc = 0xbfc00000; ///set pc reg to stack + cpuRegs.CP0.n.Config = 0x440; + cpuRegs.CP0.n.Status.val = 0x70400004; //0x10900000 <-- wrong; // COP0 enabled | BEV = 1 | TS = 1 + cpuRegs.CP0.n.PRid = 0x00002e20; // PRevID = Revision ID, same as R5900 + fpuRegs.fprc[0] = 0x00002e00; // fpu Revision.. + fpuRegs.fprc[31] = 0x01000001; // fpu Status/Control + + g_nextBranchCycle = cpuRegs.cycle + 4; + EEsCycle = 0; + EEoCycle = cpuRegs.cycle; + eeWaitCycles = CHECK_WAITCYCLE_HACK ? 3072 : 768; + + // Cyclerate hacks effectively speed up the rate of event tests, so we can safely boost + // the WaitCycles value here for x2 and x3 modes: + if( CHECK_EE_CYCLERATE > 1 ) + eeWaitCycles += 1024; + + hwReset(); + vif0Reset(); + vif1Reset(); + rcntInit(); + psxReset(); +} + +void cpuShutdown() +{ + //if( !cpuIsInitialized ) return; + //cpuIsInitialized = false; + + mtgsWaitGS(); + + hwShutdown(); +// biosShutdown(); + psxShutdown(); + disR5900FreeSyms(); +} + +void cpuException(u32 code, u32 bd) +{ + cpuRegs.branch = 0; // Tells the interpreter that an exception occurred during a branch. + + u32 offset; + cpuRegs.CP0.n.Cause = code & 0xffff; + + if(cpuRegs.CP0.n.Status.b.ERL == 0){ //Error Level 0-1 + if(((code & 0x7C) >= 0x8) && ((code & 0x7C) <= 0xC)) offset = 0x0; //TLB Refill + else if ((code & 0x7C) == 0x0) offset = 0x200; //Interrupt + else offset = 0x180; // Everything else + + + if (cpuRegs.CP0.n.Status.b.EXL == 0) { + cpuRegs.CP0.n.Status.b.EXL = 1; + if (bd) { + Console::Notice("branch delay!!"); + cpuRegs.CP0.n.EPC = cpuRegs.pc - 4; + cpuRegs.CP0.n.Cause |= 0x80000000; + } else { + cpuRegs.CP0.n.EPC = cpuRegs.pc; + cpuRegs.CP0.n.Cause &= ~0x80000000; + } + } else { + offset = 0x180; //Overrride the cause + //Console::Notice("cpuException: Status.EXL = 1 cause %x", params code); + } + if (cpuRegs.CP0.n.Status.b.BEV == 0) { + cpuRegs.pc = 0x80000000 + offset; + } else { + cpuRegs.pc = 0xBFC00200 + offset; + } + } else { //Error Level 2 + Console::Error("*PCSX2* FIX ME: Level 2 cpuException"); + if((code & 0x38000) <= 0x8000 ) { //Reset / NMI + cpuRegs.pc = 0xBFC00000; + Console::Notice("Reset request"); + UpdateCP0Status(); + return; + } else if((code & 0x38000) == 0x10000) offset = 0x80; //Performance Counter + else if((code & 0x38000) == 0x18000) offset = 0x100; //Debug + else Console::Error("Unknown Level 2 Exception!! Cause %x", params code); + + if (cpuRegs.CP0.n.Status.b.EXL == 0) { + cpuRegs.CP0.n.Status.b.EXL = 1; + if (bd) { + Console::Notice("branch delay!!"); + cpuRegs.CP0.n.EPC = cpuRegs.pc - 4; + cpuRegs.CP0.n.Cause |= 0x80000000; + } else { + cpuRegs.CP0.n.EPC = cpuRegs.pc; + cpuRegs.CP0.n.Cause &= ~0x80000000; + } + } else { + offset = 0x180; //Overrride the cause + Console::Notice("cpuException: Status.EXL = 1 cause %x", params code); + } + + if (cpuRegs.CP0.n.Status.b.DEV == 0) { + cpuRegs.pc = 0x80000000 + offset; + } else { + cpuRegs.pc = 0xBFC00200 + offset; + } + } + UpdateCP0Status(); +} + +void cpuTlbMiss(u32 addr, u32 bd, u32 excode) { + Console::Error("cpuTlbMiss pc:%x, cycl:%x, addr: %x, status=%x, code=%x", params cpuRegs.pc, cpuRegs.cycle, addr, cpuRegs.CP0.n.Status.val, excode); + if (bd) { + Console::Notice("branch delay!!"); + } + + assert(0); // temporary + + cpuRegs.CP0.n.BadVAddr = addr; + cpuRegs.CP0.n.Context &= 0xFF80000F; + cpuRegs.CP0.n.Context |= (addr >> 9) & 0x007FFFF0; + cpuRegs.CP0.n.EntryHi = (addr & 0xFFFFE000) | (cpuRegs.CP0.n.EntryHi & 0x1FFF); + + cpuRegs.CP0.n.Cause = excode; + if (!(cpuRegs.CP0.n.Status.val & 0x2)) { // EXL bit + cpuRegs.CP0.n.EPC = cpuRegs.pc - 4; + } + + if ((cpuRegs.CP0.n.Status.val & 0x1) == 0) { + cpuRegs.pc = 0x80000000; + } else { + cpuRegs.pc = 0x80000180; + } + + cpuRegs.CP0.n.Status.b.EXL = 1; + UpdateCP0Status(); +// Log=1; varLog|= 0x40000000; +} + +void cpuTlbMissR(u32 addr, u32 bd) { + cpuTlbMiss(addr, bd, EXC_CODE_TLBL); +} + +void cpuTlbMissW(u32 addr, u32 bd) { + cpuTlbMiss(addr, bd, EXC_CODE_TLBS); +} + +void JumpCheckSym(u32 addr, u32 pc) { +#if 0 +// if (addr == 0x80051770) { SysPrintf("Log!: %s\n", PSM(cpuRegs.GPR.n.a0.UL[0])); Log=1; varLog|= 0x40000000; } + if (addr == 0x8002f150) { SysPrintf("printk: %s\n", PSM(cpuRegs.GPR.n.a0.UL[0])); } + if (addr == 0x8002aba0) return; + if (addr == 0x8002f450) return; + if (addr == 0x800dd520) return; +// if (addr == 0x80049300) SysPrintf("register_blkdev: %x\n", cpuRegs.GPR.n.a0.UL[0]); + if (addr == 0x8013cb70) { SysPrintf("change_root: %x\n", cpuRegs.GPR.n.a0.UL[0]); } +// if (addr == 0x8013d1e8) { SysPrintf("Log!\n"); Log++; if (Log==2) exit(0); varLog|= 0x40000000; } +// if (addr == 0x00234e88) { SysPrintf("StoreImage\n"); Log=1; /*psMu32(0x234e88) = 0x03e00008; psMu32(0x234e8c) = 0;*/ } +#endif +/* if ((pc >= 0x00131D50 && + pc < 0x00132454) || + (pc >= 0x00786a90 && + pc < 0x00786ac8))*/ + /*if (varLog & 0x40000000) { + char *str; + char *strf; + + str = disR5900GetSym(addr); + if (str != NULL) { + strf = disR5900GetUpperSym(pc); + if (strf) { + SysPrintf("Func %8.8x: %s (called by %8.8x: %s)\n", addr, str, pc, strf); + } else { + SysPrintf("Func %8.8x: %s (called by %x)\n", addr, str, pc); + } + if (!strcmp(str, "printf")) { SysPrintf("%s\n", (char*)PSM(cpuRegs.GPR.n.a0.UL[0])); } + if (!strcmp(str, "printk")) { SysPrintf("%s\n", (char*)PSM(cpuRegs.GPR.n.a0.UL[0])); } + } + }*/ +} + +void JumpCheckSymRet(u32 addr) { + /*if (varLog & 0x40000000) { + char *str; + str = disR5900GetUpperSym(addr); + if (str != NULL) { + SysPrintf("Return : %s, v0=%8.8x\n", str, cpuRegs.GPR.n.v0.UL[0]); + } + }*/ +} + +__forceinline void _cpuTestMissingINTC() { + if (cpuRegs.CP0.n.Status.val & 0x400 && + psHu32(INTC_STAT) & psHu32(INTC_MASK)) { + if ((cpuRegs.interrupt & (1 << 30)) == 0) { + SysPrintf("*PCSX2*: Error, missing INTC Interrupt\n"); + } + } +} + +__forceinline void _cpuTestMissingDMAC() { + if (cpuRegs.CP0.n.Status.val & 0x800 && + (psHu16(0xe012) & psHu16(0xe010) || + psHu16(0xe010) & 0x8000)) { + if ((cpuRegs.interrupt & (1 << 31)) == 0) { + SysPrintf("*PCSX2*: Error, missing DMAC Interrupt\n"); + } + } +} + +void cpuTestMissingHwInts() { + if ((cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001) { + _cpuTestMissingINTC(); + _cpuTestMissingDMAC(); +// _cpuTestTIMR(); + } +} + +// sets a branch test to occur some time from an arbitrary starting point. +__forceinline int cpuSetNextBranch( u32 startCycle, s32 delta ) +{ + // typecast the conditional to signed so that things don't blow up + // if startCycle is greater than our next branch cycle. + + if( (int)(g_nextBranchCycle - startCycle) > delta ) + { + g_nextBranchCycle = startCycle + delta; + return 1; + } + return 0; +} + +// sets a branch to occur some time from the current cycle +__forceinline int cpuSetNextBranchDelta( s32 delta ) +{ + return cpuSetNextBranch( cpuRegs.cycle, delta ); +} + +// tests the cpu cycle agaisnt the given start and delta values. +// Returns true if the delta time has passed. +__forceinline int cpuTestCycle( u32 startCycle, s32 delta ) +{ + // typecast the conditional to signed so that things don't explode + // if the startCycle is ahead of our current cpu cycle. + + return (int)(cpuRegs.cycle - startCycle) >= delta; +} + +// tells the EE to run the branch test the next time it gets a chance. +__forceinline void cpuSetBranch() +{ + g_nextBranchCycle = cpuRegs.cycle; +} + +void cpuClearInt( uint i ) +{ + jASSUME( i < 32 ); + cpuRegs.interrupt &= ~(1 << i); +} + +static __forceinline void TESTINT( u8 n, void (*callback)() ) +{ + if( !(cpuRegs.interrupt & (1 << n)) ) return; + + if( cpuTestCycle( cpuRegs.sCycle[n], cpuRegs.eCycle[n] ) ) + { + cpuClearInt( n ); + callback(); + } + else + cpuSetNextBranch( cpuRegs.sCycle[n], cpuRegs.eCycle[n] ); +} + +static __forceinline void _cpuTestInterrupts() +{ + /* These are 'pcsx2 interrupts', they handle asynchronous stuff + that depends on the cycle timings */ + + TESTINT(1, vif1Interrupt); + TESTINT(2, gsInterrupt); + TESTINT(5, EEsif0Interrupt); + TESTINT(6, EEsif1Interrupt); + + // Profile-guided Optimization (sorta) + // The following ints are rarely called. Encasing them in a conditional + // as follows helps speed up most games. + + if( cpuRegs.interrupt & ( 1 | (3 << 3) | (3<<8) | (3<<10)) ) + { + TESTINT(0, vif0Interrupt); +#ifndef IPU_INLINE_IRQS + TESTINT(3, ipu0Interrupt); + TESTINT(4, ipu1Interrupt); +#endif + TESTINT(8, SPRFROMinterrupt); + TESTINT(9, SPRTOinterrupt); + + TESTINT(10, vifMFIFOInterrupt); + TESTINT(11, gifMFIFOInterrupt); + } +} + +static __forceinline void _cpuTestTIMR() +{ + cpuRegs.CP0.n.Count += cpuRegs.cycle-s_iLastCOP0Cycle; + s_iLastCOP0Cycle = cpuRegs.cycle; + + // fixme: this looks like a hack to make up for the fact that the TIMR + // doesn't yet have a proper mechanism for setting itself up on a nextBranchCycle. + // A proper fix would schedule the TIMR to trigger at a specific cycle anytime + // the Count or Compare registers are modified. + + if ( (cpuRegs.CP0.n.Status.val & 0x8000) && + cpuRegs.CP0.n.Count >= cpuRegs.CP0.n.Compare && cpuRegs.CP0.n.Count < cpuRegs.CP0.n.Compare+1000 ) + { + Console::Status("timr intr: %x, %x", params cpuRegs.CP0.n.Count, cpuRegs.CP0.n.Compare); + cpuException(0x808000, cpuRegs.branch); + } +} + +static __forceinline void _cpuTestPERF() +{ + // fixme - The interpreter and recompiler both re-calculate these values + // whenever they are read, so updating them at regular intervals *should be* + // merely a common courtesy. But when I set them up to be called less + // frequently some games would crash. I'd like to figure out why someday. [Air] + + if((cpuRegs.PERF.n.pccr & 0x800003E0) == 0x80000020) { + cpuRegs.PERF.n.pcr0 += cpuRegs.cycle-s_iLastPERFCycle[0]; + s_iLastPERFCycle[0] = cpuRegs.cycle; + } + if((cpuRegs.PERF.n.pccr & 0x800F8000) == 0x80008000) { + cpuRegs.PERF.n.pcr1 += cpuRegs.cycle-s_iLastPERFCycle[1]; + s_iLastPERFCycle[1] = cpuRegs.cycle; + } +} + +// Checks the COP0.Status for exception enablings. +// Exception handling for certain modes is *not* currently supported, this function filters +// them out. Exceptions while the exception handler is active (EIE), or exceptions of any +// level other than 0 are ignored here. + +static bool cpuIntsEnabled() +{ + return cpuRegs.CP0.n.Status.b.EIE && cpuRegs.CP0.n.Status.b.IE && + !cpuRegs.CP0.n.Status.b.EXL && (cpuRegs.CP0.n.Status.b.ERL == 0); +} + +// if cpuRegs.cycle is greater than this cycle, should check cpuBranchTest for updates +u32 g_nextBranchCycle = 0; + +// Shared portion of the branch test, called from both the Interpreter +// and the recompiler. (moved here to help alleviate redundant code) +__forceinline bool _cpuBranchTest_Shared() +{ + eeEventTestIsActive = true; + g_nextBranchCycle = cpuRegs.cycle + eeWaitCycles; + + EEsCycle += cpuRegs.cycle - EEoCycle; + EEoCycle = cpuRegs.cycle; + + if( EEsCycle > 0 ) + iopBranchAction = true; + + // ---- Counters ------------- + bool vsyncEvent = false; + rcntUpdate_hScanline(); + + if( cpuTestCycle( nextsCounter, nextCounter ) ) + { + vsyncEvent = rcntUpdate(); + _cpuTestPERF(); + } + + _cpuTestTIMR(); + + // ---- Interrupts ------------- + // Handles all interrupts except 30 and 31, which are handled later. + + if( cpuRegs.interrupt & ~(3<<30) ) + _cpuTestInterrupts(); + + // ---- IOP ------------- + // * It's important to run a psxBranchTest before calling ExecuteBlock. This + // is because the IOP does not always perform branch tests before returning + // (during the prev branch) and also so it can act on the state the EE has + // given it before executing any code. + // + // * The IOP cannot always be run. If we run IOP code every time through the + // cpuBranchTest, the IOP generally starts to run way ahead of the EE. + + psxBranchTest(); + + if( iopBranchAction ) + { + //if( EEsCycle < -450 ) + // Console::WriteLn( " IOP ahead by: %d cycles", params -EEsCycle ); + + // Experimental and Probably Unnecessry Logic --> + // Check if the EE already has an exception pending, and if so we shouldn't + // waste too much time updating the IOP. Theory being that the EE and IOP should + // run closely in sync during raised exception events. But in practice it didn't + // seem to make much of a difference. + + // Note: The IOP is very good about chaining blocks together so it tends to + // run lots of cycles, even with only 32 (4 IOP) cycles specified here. That's + // probably why it doesn't improve sync much. + + /*bool eeExceptPending = cpuIntsEnabled() && + //( cpuRegs.CP0.n.Status.b.EIE && cpuRegs.CP0.n.Status.b.IE && (cpuRegs.CP0.n.Status.b.ERL == 0) ) && + //( (cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001 ) && + ( (cpuRegs.interrupt & (3<<30)) != 0 ); + + if( eeExceptPending ) + { + // ExecuteBlock returns a negative value, so subtract it from the cycle count + // specified to get the total cycles processed! :D + int cycleCount = std::min( EEsCycle, (s32)(eeWaitCycles>>4) ); + int cyclesRun = cycleCount - psxCpu->ExecuteBlock( cycleCount ); + EEsCycle -= cyclesRun; + //Console::Notice( "IOP Exception-Pending Execution -- EEsCycle: %d", params EEsCycle ); + } + else*/ + { + EEsCycle = psxCpu->ExecuteBlock( EEsCycle ); + } + + iopBranchAction = false; + } + + // ---- VU0 ------------- + + if (VU0.VI[REG_VPU_STAT].UL & 0x1) + { + // We're in a BranchTest. All dynarec registers are flushed + // so there is no need to freeze registers here. + CpuVU0.ExecuteBlock(); + + // This might be needed to keep the EE and VU0 in sync. + // A better fix will require hefty changes to the VU recs. -_- + if(VU0.VI[REG_VPU_STAT].UL & 0x1) + cpuSetNextBranchDelta( 768 ); + } + + // Note: We don't update the VU1 here because it runs it's micro-programs in + // one shot always. That is, when a program is executed the VU1 doesn't even + // bother to return until the program is completely finished. + + // ---- Schedule Next Event Test -------------- + + if( EEsCycle > 192 ) + { + // EE's running way ahead of the IOP still, so we should branch quickly to give the + // IOP extra timeslices in short order. + + cpuSetNextBranchDelta( 48 ); + //Console::Notice( "EE ahead of the IOP -- Rapid Branch! %d", params EEsCycle ); + } + + // The IOP could be running ahead/behind of us, so adjust the iop's next branch by its + // relative position to the EE (via EEsCycle) + cpuSetNextBranchDelta( ((g_psxNextBranchCycle-psxRegs.cycle)*8) - EEsCycle ); + + // Apply the hsync counter's nextCycle + cpuSetNextBranch( counters[4].sCycle, counters[4].CycleT ); + + // Apply vsync and other counter nextCycles + cpuSetNextBranch( nextsCounter, nextCounter ); + + eeEventTestIsActive = false; + + // ---- INTC / DMAC Exceptions ----------------- + // Raise the INTC and DMAC interrupts here, which usually throw exceptions. + // This should be done last since the IOP and the VU0 can raise several EE + // exceptions. + + //if ((cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001) + if( cpuIntsEnabled() ) + { + TESTINT(30, intcInterrupt); + TESTINT(31, dmacInterrupt); + } + + return vsyncEvent; +} + +void cpuTestINTCInts() +{ + if( cpuRegs.interrupt & (1 << 30) ) return; + //if( (cpuRegs.CP0.n.Status.val & 0x10407) != 0x10401 ) return; + if( !cpuIntsEnabled() ) return; + if( (psHu32(INTC_STAT) & psHu32(INTC_MASK)) == 0 ) return; + + cpuRegs.interrupt|= 1 << 30; + cpuRegs.sCycle[30] = cpuRegs.cycle; + cpuRegs.eCycle[30] = 0; + + // only set the next branch delta if the exception won't be handled for + // the current branch... + if( !eeEventTestIsActive ) + cpuSetNextBranchDelta( 4 ); + else if(psxCycleEE > 0) + { + psxBreak += psxCycleEE; // record the number of cycles the IOP didn't run. + psxCycleEE = 0; + } +} + +__forceinline void cpuTestDMACInts() +{ + if ( cpuRegs.interrupt & (1 << 31) ) return; + if ((cpuRegs.CP0.n.Status.val & 0x10807) != 0x10801) return; + + if ( ( (psHu16(0xe012) & psHu16(0xe010)) == 0) && + ( (psHu16(0xe010) & 0x8000) == 0) ) return; + + cpuRegs.interrupt|= 1 << 31; + cpuRegs.sCycle[31] = cpuRegs.cycle; + cpuRegs.eCycle[31] = 0; + + // only set the next branch delta if the exception won't be handled for + // the current branch... + if( !eeEventTestIsActive ) + cpuSetNextBranchDelta( 4 ); + else if(psxCycleEE > 0) + { + psxBreak += psxCycleEE; // record the number of cycles the IOP didn't run. + psxCycleEE = 0; + } +} + +__forceinline void cpuTestTIMRInts() { + if ((cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001) { + _cpuTestPERF(); + _cpuTestTIMR(); + } +} + +void cpuTestHwInts() { + cpuTestINTCInts(); + cpuTestDMACInts(); + cpuTestTIMRInts(); +} + +// This function performs a "hackish" execution of the BIOS stub, which initializes EE +// memory and hardware. It forcefully breaks execution when the stub is finished, prior +// to the PS2 logos being displayed. This allows us to "shortcut" right into a game +// without having to wait through the logos or endure game/bios localization checks. +void cpuExecuteBios() +{ + // Set the video mode to user's default request: + // (right now we always default to NTSC) + gsSetVideoRegionType( Config.PsxType & 1 ); + + Console::Notice( "* PCSX2 *: ExecuteBios" ); + + bExecBIOS = TRUE; + while (cpuRegs.pc != 0x00200008 && + cpuRegs.pc != 0x00100008) { + g_nextBranchCycle = cpuRegs.cycle; + Cpu->ExecuteBlock(); + } + + bExecBIOS = FALSE; +// { +// FILE* f = fopen("eebios.bin", "wb"); +// fwrite(PSM(0x80000000), 0x100000, 1, f); +// fclose(f); +// exit(0); + +// f = fopen("iopbios.bin", "wb"); +// fwrite(PS2MEM_PSX, 0x80000, 1, f); +// fclose(f); +// } + +// REC_CLEARM(0x00200008); +// REC_CLEARM(0x00100008); +// REC_CLEARM(cpuRegs.pc); + + // Reset the EErecs here, because the bios generates "slow" blocks that have hacky + // bBiosEnd checks in them and stuff. This deletes them so that the recs replace them + // with new faster versions: + Cpu->Reset(); + + Console::Notice("* PCSX2 *: ExecuteBios Complete"); + //GSprintf(5, "PCSX2 " PCSX2_VERSION "\nExecuteBios Complete\n"); +} + +__forceinline void CPU_INT( u32 n, s32 ecycle) +{ + cpuRegs.interrupt|= 1 << n; + cpuRegs.sCycle[n] = cpuRegs.cycle; + cpuRegs.eCycle[n] = ecycle; + + // Interrupt is happening soon: make sure both EE and IOP are aware. + + if( ecycle <= 28 && psxCycleEE > 0 ) + { + // If running in the IOP, force it to break immediately into the EE. + // the EE's branch test is due to run. + + psxBreak += psxCycleEE; // record the number of cycles the IOP didn't run. + psxCycleEE = 0; + } + + cpuSetNextBranchDelta( cpuRegs.eCycle[n] ); +} diff --git a/pcsx2/R5900.h b/pcsx2/R5900.h index 4462742071..0d8036a383 100644 --- a/pcsx2/R5900.h +++ b/pcsx2/R5900.h @@ -1,276 +1,276 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __R5900_H__ -#define __R5900_H__ - -extern bool g_EEFreezeRegs; - -// EE Bios function name tables. -namespace R5900 { -extern const char* const bios[256]; -} - -extern s32 EEsCycle; -extern u32 EEoCycle; -extern u32 bExecBIOS; - -union GPR_reg { // Declare union type GPR register - u64 UD[2]; //128 bits - s64 SD[2]; - u32 UL[4]; - s32 SL[4]; - u16 US[8]; - s16 SS[8]; - u8 UC[16]; - s8 SC[16]; -}; - -union GPRregs { - struct { - GPR_reg r0, at, v0, v1, a0, a1, a2, a3, - t0, t1, t2, t3, t4, t5, t6, t7, - s0, s1, s2, s3, s4, s5, s6, s7, - t8, t9, k0, k1, gp, sp, s8, ra; - } n; - GPR_reg r[32]; -}; - -union PERFregs { - struct { - u32 pccr, pcr0, pcr1, pad; - } n; - u32 r[4]; -}; - -union CP0regs { - struct { - u32 Index, Random, EntryLo0, EntryLo1, - Context, PageMask, Wired, Reserved0, - BadVAddr, Count, EntryHi, Compare; - union { - struct { - u32 IE:1; // Bit 0: Interrupt Enable flag. - u32 EXL:1; // Bit 1: Exception Level, set on any exception not covered by ERL. - u32 ERL:1; // Bit 2: Error level, set on Resetm NMI, perf/debug exceptions. - u32 KSU:2; // Bits 3-4: Kernel [clear] / Supervisor [set] mode - u32 unused0:3; - u32 IM:8; // Bits 10-15: Interrupt mask (bits 12,13,14 are unused) - u32 EIE:1; // Bit 16: IE bit enabler. When cleared, ints are disabled regardless of IE status. - u32 _EDI:1; // Bit 17: Interrupt Enable (set enables ints in all modes, clear enables ints in kernel mode only) - u32 CH:1; // Bit 18: Status of most recent cache instruction (set for hit, clear for miss) - u32 unused1:3; - u32 BEV:1; // Bit 22: if set, use bootstrap for TLB/general exceptions - u32 DEV:1; // Bit 23: if set, use bootstrap for perf/debug exceptions - u32 unused2:2; - u32 FR:1; // (?) - u32 unused3:1; - u32 CU:4; // Bits 28-31: Co-processor Usable flag - } b; - u32 val; - } Status; - u32 Cause, EPC, PRid, - Config, LLAddr, WatchLO, WatchHI, - XContext, Reserved1, Reserved2, Debug, - DEPC, PerfCnt, ErrCtl, CacheErr, - TagLo, TagHi, ErrorEPC, DESAVE; - } n; - u32 r[32]; -}; - -struct cpuRegisters { - GPRregs GPR; // GPR regs - // NOTE: don't change order since recompiler uses it - GPR_reg HI; - GPR_reg LO; // hi & log 128bit wide - CP0regs CP0; // is COP0 32bit? - u32 sa; // shift amount (32bit), needs to be 16 byte aligned - u32 constzero; // always 0, for MFSA - u32 pc; // Program counter, when changing offset in struct, check iR5900-X.S to make sure offset is correct - u32 code; // The instruction - PERFregs PERF; - u32 eCycle[32]; - u32 sCycle[32]; // for internal counters - u32 cycle; // calculate cpucycles.. - u32 interrupt; - int branch; - int opmode; // operating mode - u32 tempcycles; -}; - -// used for optimization -union GPR_reg64 { - u64 UD[1]; //64 bits - s64 SD[1]; - u32 UL[2]; - s32 SL[3]; - u16 US[4]; - s16 SS[4]; - u8 UC[8]; - s8 SC[8]; -}; - -union FPRreg { - float f; - u32 UL; -}; - -struct fpuRegisters { - FPRreg fpr[32]; // 32bit floating point registers - u32 fprc[32]; // 32bit floating point control registers - FPRreg ACC; // 32 bit accumulator -}; - -struct tlbs -{ - u32 PageMask,EntryHi; - u32 EntryLo0,EntryLo1; - u32 Mask, nMask; - u32 G; - u32 ASID; - u32 VPN2; - u32 PFN0; - u32 PFN1; - u32 S; -}; - -#ifndef _PC_ - -#define _i64(x) (s64)x -#define _u64(x) (u64)x - -#define _i32(x) (s32)x -#define _u32(x) (u32)x - -#define _i16(x) (s16)x -#define _u16(x) (u16)x - -#define _i8(x) (s8)x -#define _u8(x) (u8)x - -//////////////////////////////////////////////////////////////////// -// R5900 Instruction Macros - -#define _PC_ cpuRegs.pc // The next PC to be executed - -#define _Funct_ ((cpuRegs.code ) & 0x3F) // The funct part of the instruction register -#define _Rd_ ((cpuRegs.code >> 11) & 0x1F) // The rd part of the instruction register -#define _Rt_ ((cpuRegs.code >> 16) & 0x1F) // The rt part of the instruction register -#define _Rs_ ((cpuRegs.code >> 21) & 0x1F) // The rs part of the instruction register -#define _Sa_ ((cpuRegs.code >> 6) & 0x1F) // The sa part of the instruction register -#define _Im_ ((u16)cpuRegs.code) // The immediate part of the instruction register -#define _Target_ (cpuRegs.code & 0x03ffffff) // The target part of the instruction register - -#define _Imm_ ((s16)cpuRegs.code) // sign-extended immediate -#define _ImmU_ (cpuRegs.code&0xffff) // zero-extended immediate -#define _ImmSB_ (cpuRegs.code&0x8000) // gets the sign-bit of the immediate value - -#define _Opcode_ (cpuRegs.code >> 26 ) - -#define _JumpTarget_ ((_Target_ << 2) + (_PC_ & 0xf0000000)) // Calculates the target during a jump instruction -#define _BranchTarget_ (((s32)(s16)_Im_ * 4) + _PC_) // Calculates the target during a branch instruction - -#define _SetLink(x) cpuRegs.GPR.r[x].UD[0] = _PC_ + 4; // Sets the return address in the link register - -#endif - -void JumpCheckSym(u32 addr, u32 pc); -void JumpCheckSymRet(u32 addr); - -extern PCSX2_ALIGNED16_DECL(cpuRegisters cpuRegs); -extern PCSX2_ALIGNED16_DECL(fpuRegisters fpuRegs); -extern PCSX2_ALIGNED16_DECL(tlbs tlb[48]); - -extern u32 g_nextBranchCycle; -extern bool eeEventTestIsActive; -extern u32 s_iLastCOP0Cycle; -extern u32 s_iLastPERFCycle[2]; - -bool intEventTest(); -void intSetBranch(); - -// This is a special form of the interpreter's doBranch that is run from various -// parts of the Recs (namely COP0's branch codes and stuff). -void __fastcall intDoBranch(u32 target); - -//////////////////////////////////////////////////////////////////// -// R5900 Public Interface / API - -struct R5900cpu -{ - void (*Allocate)(); // throws exceptions on failure. - void (*Reset)(); - void (*Step)(); - void (*Execute)(); /* executes up to a break */ - void (*ExecuteBlock)(); - void (*Clear)(u32 Addr, u32 Size); - void (*Shutdown)(); // deallocates memory reserved by Allocate -}; - -extern R5900cpu *Cpu; -extern R5900cpu intCpu; -extern R5900cpu recCpu; - -extern void cpuInit(); -extern void cpuReset(); // can throw Exception::FileNotFound. -extern void cpuShutdown(); -extern void cpuExecuteBios(); -extern void cpuException(u32 code, u32 bd); -extern void cpuTlbMissR(u32 addr, u32 bd); -extern void cpuTlbMissW(u32 addr, u32 bd); -extern void cpuTestHwInts(); - -extern int cpuSetNextBranch( u32 startCycle, s32 delta ); -extern int cpuSetNextBranchDelta( s32 delta ); -extern int cpuTestCycle( u32 startCycle, s32 delta ); -extern void cpuSetBranch(); - -extern bool _cpuBranchTest_Shared(); // for internal use by the Dynarecs and Ints inside R5900: - -extern void cpuTestINTCInts(); -extern void cpuTestDMACInts(); -extern void cpuTestTIMRInts(); - -//////////////////////////////////////////////////////////////////// -// Exception Codes - -#define EXC_CODE(x) ((x)<<2) - -#define EXC_CODE_Int EXC_CODE(0) -#define EXC_CODE_Mod EXC_CODE(1) /* TLB Modification exception */ -#define EXC_CODE_TLBL EXC_CODE(2) /* TLB Miss exception (load or instruction fetch) */ -#define EXC_CODE_TLBS EXC_CODE(3) /* TLB Miss exception (store) */ -#define EXC_CODE_AdEL EXC_CODE(4) -#define EXC_CODE_AdES EXC_CODE(5) -#define EXC_CODE_IBE EXC_CODE(6) -#define EXC_CODE_DBE EXC_CODE(7) -#define EXC_CODE_Sys EXC_CODE(8) -#define EXC_CODE_Bp EXC_CODE(9) -#define EXC_CODE_Ri EXC_CODE(10) -#define EXC_CODE_CpU EXC_CODE(11) -#define EXC_CODE_Ov EXC_CODE(12) -#define EXC_CODE_Tr EXC_CODE(13) -#define EXC_CODE_FPE EXC_CODE(15) -#define EXC_CODE_WATCH EXC_CODE(23) -#define EXC_CODE__MASK 0x0000007c -#define EXC_CODE__SHIFT 2 - -#define EXC_TLB_STORE 1 -#define EXC_TLB_LOAD 0 - -#endif /* __R5900_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __R5900_H__ +#define __R5900_H__ + +extern bool g_EEFreezeRegs; + +// EE Bios function name tables. +namespace R5900 { +extern const char* const bios[256]; +} + +extern s32 EEsCycle; +extern u32 EEoCycle; +extern u32 bExecBIOS; + +union GPR_reg { // Declare union type GPR register + u64 UD[2]; //128 bits + s64 SD[2]; + u32 UL[4]; + s32 SL[4]; + u16 US[8]; + s16 SS[8]; + u8 UC[16]; + s8 SC[16]; +}; + +union GPRregs { + struct { + GPR_reg r0, at, v0, v1, a0, a1, a2, a3, + t0, t1, t2, t3, t4, t5, t6, t7, + s0, s1, s2, s3, s4, s5, s6, s7, + t8, t9, k0, k1, gp, sp, s8, ra; + } n; + GPR_reg r[32]; +}; + +union PERFregs { + struct { + u32 pccr, pcr0, pcr1, pad; + } n; + u32 r[4]; +}; + +union CP0regs { + struct { + u32 Index, Random, EntryLo0, EntryLo1, + Context, PageMask, Wired, Reserved0, + BadVAddr, Count, EntryHi, Compare; + union { + struct { + u32 IE:1; // Bit 0: Interrupt Enable flag. + u32 EXL:1; // Bit 1: Exception Level, set on any exception not covered by ERL. + u32 ERL:1; // Bit 2: Error level, set on Resetm NMI, perf/debug exceptions. + u32 KSU:2; // Bits 3-4: Kernel [clear] / Supervisor [set] mode + u32 unused0:3; + u32 IM:8; // Bits 10-15: Interrupt mask (bits 12,13,14 are unused) + u32 EIE:1; // Bit 16: IE bit enabler. When cleared, ints are disabled regardless of IE status. + u32 _EDI:1; // Bit 17: Interrupt Enable (set enables ints in all modes, clear enables ints in kernel mode only) + u32 CH:1; // Bit 18: Status of most recent cache instruction (set for hit, clear for miss) + u32 unused1:3; + u32 BEV:1; // Bit 22: if set, use bootstrap for TLB/general exceptions + u32 DEV:1; // Bit 23: if set, use bootstrap for perf/debug exceptions + u32 unused2:2; + u32 FR:1; // (?) + u32 unused3:1; + u32 CU:4; // Bits 28-31: Co-processor Usable flag + } b; + u32 val; + } Status; + u32 Cause, EPC, PRid, + Config, LLAddr, WatchLO, WatchHI, + XContext, Reserved1, Reserved2, Debug, + DEPC, PerfCnt, ErrCtl, CacheErr, + TagLo, TagHi, ErrorEPC, DESAVE; + } n; + u32 r[32]; +}; + +struct cpuRegisters { + GPRregs GPR; // GPR regs + // NOTE: don't change order since recompiler uses it + GPR_reg HI; + GPR_reg LO; // hi & log 128bit wide + CP0regs CP0; // is COP0 32bit? + u32 sa; // shift amount (32bit), needs to be 16 byte aligned + u32 constzero; // always 0, for MFSA + u32 pc; // Program counter, when changing offset in struct, check iR5900-X.S to make sure offset is correct + u32 code; // The instruction + PERFregs PERF; + u32 eCycle[32]; + u32 sCycle[32]; // for internal counters + u32 cycle; // calculate cpucycles.. + u32 interrupt; + int branch; + int opmode; // operating mode + u32 tempcycles; +}; + +// used for optimization +union GPR_reg64 { + u64 UD[1]; //64 bits + s64 SD[1]; + u32 UL[2]; + s32 SL[3]; + u16 US[4]; + s16 SS[4]; + u8 UC[8]; + s8 SC[8]; +}; + +union FPRreg { + float f; + u32 UL; +}; + +struct fpuRegisters { + FPRreg fpr[32]; // 32bit floating point registers + u32 fprc[32]; // 32bit floating point control registers + FPRreg ACC; // 32 bit accumulator +}; + +struct tlbs +{ + u32 PageMask,EntryHi; + u32 EntryLo0,EntryLo1; + u32 Mask, nMask; + u32 G; + u32 ASID; + u32 VPN2; + u32 PFN0; + u32 PFN1; + u32 S; +}; + +#ifndef _PC_ + +#define _i64(x) (s64)x +#define _u64(x) (u64)x + +#define _i32(x) (s32)x +#define _u32(x) (u32)x + +#define _i16(x) (s16)x +#define _u16(x) (u16)x + +#define _i8(x) (s8)x +#define _u8(x) (u8)x + +//////////////////////////////////////////////////////////////////// +// R5900 Instruction Macros + +#define _PC_ cpuRegs.pc // The next PC to be executed + +#define _Funct_ ((cpuRegs.code ) & 0x3F) // The funct part of the instruction register +#define _Rd_ ((cpuRegs.code >> 11) & 0x1F) // The rd part of the instruction register +#define _Rt_ ((cpuRegs.code >> 16) & 0x1F) // The rt part of the instruction register +#define _Rs_ ((cpuRegs.code >> 21) & 0x1F) // The rs part of the instruction register +#define _Sa_ ((cpuRegs.code >> 6) & 0x1F) // The sa part of the instruction register +#define _Im_ ((u16)cpuRegs.code) // The immediate part of the instruction register +#define _Target_ (cpuRegs.code & 0x03ffffff) // The target part of the instruction register + +#define _Imm_ ((s16)cpuRegs.code) // sign-extended immediate +#define _ImmU_ (cpuRegs.code&0xffff) // zero-extended immediate +#define _ImmSB_ (cpuRegs.code&0x8000) // gets the sign-bit of the immediate value + +#define _Opcode_ (cpuRegs.code >> 26 ) + +#define _JumpTarget_ ((_Target_ << 2) + (_PC_ & 0xf0000000)) // Calculates the target during a jump instruction +#define _BranchTarget_ (((s32)(s16)_Im_ * 4) + _PC_) // Calculates the target during a branch instruction + +#define _SetLink(x) cpuRegs.GPR.r[x].UD[0] = _PC_ + 4; // Sets the return address in the link register + +#endif + +void JumpCheckSym(u32 addr, u32 pc); +void JumpCheckSymRet(u32 addr); + +extern PCSX2_ALIGNED16_DECL(cpuRegisters cpuRegs); +extern PCSX2_ALIGNED16_DECL(fpuRegisters fpuRegs); +extern PCSX2_ALIGNED16_DECL(tlbs tlb[48]); + +extern u32 g_nextBranchCycle; +extern bool eeEventTestIsActive; +extern u32 s_iLastCOP0Cycle; +extern u32 s_iLastPERFCycle[2]; + +bool intEventTest(); +void intSetBranch(); + +// This is a special form of the interpreter's doBranch that is run from various +// parts of the Recs (namely COP0's branch codes and stuff). +void __fastcall intDoBranch(u32 target); + +//////////////////////////////////////////////////////////////////// +// R5900 Public Interface / API + +struct R5900cpu +{ + void (*Allocate)(); // throws exceptions on failure. + void (*Reset)(); + void (*Step)(); + void (*Execute)(); /* executes up to a break */ + void (*ExecuteBlock)(); + void (*Clear)(u32 Addr, u32 Size); + void (*Shutdown)(); // deallocates memory reserved by Allocate +}; + +extern R5900cpu *Cpu; +extern R5900cpu intCpu; +extern R5900cpu recCpu; + +extern void cpuInit(); +extern void cpuReset(); // can throw Exception::FileNotFound. +extern void cpuShutdown(); +extern void cpuExecuteBios(); +extern void cpuException(u32 code, u32 bd); +extern void cpuTlbMissR(u32 addr, u32 bd); +extern void cpuTlbMissW(u32 addr, u32 bd); +extern void cpuTestHwInts(); + +extern int cpuSetNextBranch( u32 startCycle, s32 delta ); +extern int cpuSetNextBranchDelta( s32 delta ); +extern int cpuTestCycle( u32 startCycle, s32 delta ); +extern void cpuSetBranch(); + +extern bool _cpuBranchTest_Shared(); // for internal use by the Dynarecs and Ints inside R5900: + +extern void cpuTestINTCInts(); +extern void cpuTestDMACInts(); +extern void cpuTestTIMRInts(); + +//////////////////////////////////////////////////////////////////// +// Exception Codes + +#define EXC_CODE(x) ((x)<<2) + +#define EXC_CODE_Int EXC_CODE(0) +#define EXC_CODE_Mod EXC_CODE(1) /* TLB Modification exception */ +#define EXC_CODE_TLBL EXC_CODE(2) /* TLB Miss exception (load or instruction fetch) */ +#define EXC_CODE_TLBS EXC_CODE(3) /* TLB Miss exception (store) */ +#define EXC_CODE_AdEL EXC_CODE(4) +#define EXC_CODE_AdES EXC_CODE(5) +#define EXC_CODE_IBE EXC_CODE(6) +#define EXC_CODE_DBE EXC_CODE(7) +#define EXC_CODE_Sys EXC_CODE(8) +#define EXC_CODE_Bp EXC_CODE(9) +#define EXC_CODE_Ri EXC_CODE(10) +#define EXC_CODE_CpU EXC_CODE(11) +#define EXC_CODE_Ov EXC_CODE(12) +#define EXC_CODE_Tr EXC_CODE(13) +#define EXC_CODE_FPE EXC_CODE(15) +#define EXC_CODE_WATCH EXC_CODE(23) +#define EXC_CODE__MASK 0x0000007c +#define EXC_CODE__SHIFT 2 + +#define EXC_TLB_STORE 1 +#define EXC_TLB_LOAD 0 + +#endif /* __R5900_H__ */ diff --git a/pcsx2/R5900OpcodeImpl.cpp b/pcsx2/R5900OpcodeImpl.cpp index 046f334350..c775fa864a 100644 --- a/pcsx2/R5900OpcodeImpl.cpp +++ b/pcsx2/R5900OpcodeImpl.cpp @@ -1,816 +1,816 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "R5900.h" -#include "R5900OpcodeTables.h" - -#include - -namespace R5900 -{ - const OPCODE& GetCurrentInstruction() - { - const OPCODE* opcode = &R5900::OpcodeTables::tbl_Standard[_Opcode_]; - - while( opcode->getsubclass != NULL ) - opcode = &opcode->getsubclass(); - - return *opcode; - } - - const char * const bios[256]= - { - //0x00 - "RFU000_FullReset", "ResetEE", "SetGsCrt", "RFU003", - "Exit", "RFU005", "LoadExecPS2", "ExecPS2", - "RFU008", "RFU009", "AddSbusIntcHandler", "RemoveSbusIntcHandler", - "Interrupt2Iop", "SetVTLBRefillHandler", "SetVCommonHandler", "SetVInterruptHandler", - //0x10 - "AddIntcHandler", "RemoveIntcHandler", "AddDmacHandler", "RemoveDmacHandler", - "_EnableIntc", "_DisableIntc", "_EnableDmac", "_DisableDmac", - "_SetAlarm", "_ReleaseAlarm", "_iEnableIntc", "_iDisableIntc", - "_iEnableDmac", "_iDisableDmac", "_iSetAlarm", "_iReleaseAlarm", - //0x20 - "CreateThread", "DeleteThread", "StartThread", "ExitThread", - "ExitDeleteThread", "TerminateThread", "iTerminateThread", "DisableDispatchThread", - "EnableDispatchThread", "ChangeThreadPriority", "iChangeThreadPriority", "RotateThreadReadyQueue", - "iRotateThreadReadyQueue", "ReleaseWaitThread", "iReleaseWaitThread", "GetThreadId", - //0x30 - "ReferThreadStatus","iReferThreadStatus", "SleepThread", "WakeupThread", - "_iWakeupThread", "CancelWakeupThread", "iCancelWakeupThread", "SuspendThread", - "iSuspendThread", "ResumeThread", "iResumeThread", "JoinThread", - "RFU060", "RFU061", "EndOfHeap", "RFU063", - //0x40 - "CreateSema", "DeleteSema", "SignalSema", "iSignalSema", - "WaitSema", "PollSema", "iPollSema", "ReferSemaStatus", - "iReferSemaStatus", "RFU073", "SetOsdConfigParam", "GetOsdConfigParam", - "GetGsHParam", "GetGsVParam", "SetGsHParam", "SetGsVParam", - //0x50 - "RFU080_CreateEventFlag", "RFU081_DeleteEventFlag", - "RFU082_SetEventFlag", "RFU083_iSetEventFlag", - "RFU084_ClearEventFlag", "RFU085_iClearEventFlag", - "RFU086_WaitEventFlag", "RFU087_PollEventFlag", - "RFU088_iPollEventFlag", "RFU089_ReferEventFlagStatus", - "RFU090_iReferEventFlagStatus", "RFU091_GetEntryAddress", - "EnableIntcHandler_iEnableIntcHandler", - "DisableIntcHandler_iDisableIntcHandler", - "EnableDmacHandler_iEnableDmacHandler", - "DisableDmacHandler_iDisableDmacHandler", - //0x60 - "KSeg0", "EnableCache", "DisableCache", "GetCop0", - "FlushCache", "RFU101", "CpuConfig", "iGetCop0", - "iFlushCache", "RFU105", "iCpuConfig", "sceSifStopDma", - "SetCPUTimerHandler", "SetCPUTimer", "SetOsdConfigParam2", "SetOsdConfigParam2", - //0x70 - "GsGetIMR_iGsGetIMR", "GsGetIMR_iGsPutIMR", "SetPgifHandler", "SetVSyncFlag", - "RFU116", "print", "sceSifDmaStat_isceSifDmaStat", "sceSifSetDma_isceSifSetDma", - "sceSifSetDChain_isceSifSetDChain", "sceSifSetReg", "sceSifGetReg", "ExecOSD", - "Deci2Call", "PSMode", "MachineType", "GetMemorySize", - }; - -namespace Interpreter { -namespace OpcodeImpl { - -void COP2() -{ - //std::string disOut; - //disR5900Fasm(disOut, cpuRegs.code, cpuRegs.pc); - - //VU0_LOG("%s\n", disOut.c_str()); - Int_COP2PrintTable[_Rs_](); -} - -void Unknown() { - CPU_LOG("%8.8lx: Unknown opcode called\n", cpuRegs.pc); -} - -void MMI_Unknown() { Console::Notice("Unknown MMI opcode called"); } -void COP0_Unknown() { Console::Notice("Unknown COP0 opcode called"); } -void COP1_Unknown() { Console::Notice("Unknown FPU/COP1 opcode called"); } - -/********************************************************* -* Arithmetic with immediate operand * -* Format: OP rt, rs, immediate * -*********************************************************/ -void ADDI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + _Imm_; }// Rt = Rs + Im signed!!!! -void ADDIU() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + _Imm_; }// Rt = Rs + Im signed !!! -void DADDI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + _Imm_; }// Rt = Rs + Im -void DADDIU() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + _Imm_; }// Rt = Rs + Im -void ANDI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] & (u64)_ImmU_; } // Rt = Rs And Im (zero-extended) -void ORI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] | (u64)_ImmU_; } // Rt = Rs Or Im (zero-extended) -void XORI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] ^ (u64)_ImmU_; } // Rt = Rs Xor Im (zero-extended) -void SLTI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] < (s64)(_Imm_); } // Rt = Rs < Im (signed) -void SLTIU() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] < (u64)(_Imm_); } // Rt = Rs < Im (unsigned) - -/********************************************************* -* Register arithmetic * -* Format: OP rd, rs, rt * -*********************************************************/ -void ADD() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + cpuRegs.GPR.r[_Rt_].SL[0];} // Rd = Rs + Rt (Exception on Integer Overflow) -void ADDU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + cpuRegs.GPR.r[_Rt_].SL[0];} // Rd = Rs + Rt -void DADD() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + cpuRegs.GPR.r[_Rt_].SD[0]; } -void DADDU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + cpuRegs.GPR.r[_Rt_].SD[0]; } -void SUB() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] - cpuRegs.GPR.r[_Rt_].SL[0];} // Rd = Rs - Rt (Exception on Integer Overflow) -void SUBU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] - cpuRegs.GPR.r[_Rt_].SL[0]; } // Rd = Rs - Rt -void DSUB() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] - cpuRegs.GPR.r[_Rt_].SD[0];} -void DSUBU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] - cpuRegs.GPR.r[_Rt_].SD[0]; } -void AND() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] & cpuRegs.GPR.r[_Rt_].UD[0]; } // Rd = Rs And Rt -void OR() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] | cpuRegs.GPR.r[_Rt_].UD[0]; } // Rd = Rs Or Rt -void XOR() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] ^ cpuRegs.GPR.r[_Rt_].UD[0]; } // Rd = Rs Xor Rt -void NOR() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] =~(cpuRegs.GPR.r[_Rs_].UD[0] | cpuRegs.GPR.r[_Rt_].UD[0]); }// Rd = Rs Nor Rt -void SLT() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] < cpuRegs.GPR.r[_Rt_].SD[0]; } // Rd = Rs < Rt (signed) -void SLTU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] < cpuRegs.GPR.r[_Rt_].UD[0]; } // Rd = Rs < Rt (unsigned) - -/********************************************************* -* Register mult/div & Register trap logic * -* Format: OP rs, rt * -*********************************************************/ -void DIV() { - if (cpuRegs.GPR.r[_Rt_].SL[0] != 0) { - cpuRegs.LO.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0] / cpuRegs.GPR.r[_Rt_].SL[0]; - cpuRegs.HI.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0] % cpuRegs.GPR.r[_Rt_].SL[0]; - } -} - -void DIVU() { - if (cpuRegs.GPR.r[_Rt_].UL[0] != 0) { - cpuRegs.LO.SD[0] = cpuRegs.GPR.r[_Rs_].UL[0] / cpuRegs.GPR.r[_Rt_].UL[0]; - cpuRegs.HI.SD[0] = cpuRegs.GPR.r[_Rs_].UL[0] % cpuRegs.GPR.r[_Rt_].UL[0]; - } -} - -void MULT() { //different in ps2... - s64 res = (s64)cpuRegs.GPR.r[_Rs_].SL[0] * (s64)cpuRegs.GPR.r[_Rt_].SL[0]; - - cpuRegs.LO.UD[0] = (s32)(res & 0xffffffff); - cpuRegs.HI.UD[0] = (s32)(res >> 32); - - if (!_Rd_) return; - cpuRegs.GPR.r[_Rd_].UD[0]= cpuRegs.LO.UD[0]; //that is the difference -} - -void MULTU() { //different in ps2.. - u64 res = (u64)cpuRegs.GPR.r[_Rs_].UL[0] * (u64)cpuRegs.GPR.r[_Rt_].UL[0]; - - cpuRegs.LO.UD[0] = (s32)(res & 0xffffffff); - cpuRegs.HI.UD[0] = (s32)(res >> 32); - - if (!_Rd_) return; - cpuRegs.GPR.r[_Rd_].UD[0]= cpuRegs.LO.UD[0]; //that is the difference -} - -/********************************************************* -* Load higher 16 bits of the first word in GPR with imm * -* Format: OP rt, immediate * -*********************************************************/ -void LUI() { - if (!_Rt_) return; - cpuRegs.GPR.r[_Rt_].UD[0] = (s32)(cpuRegs.code << 16); -} - -/********************************************************* -* Move from HI/LO to GPR * -* Format: OP rd * -*********************************************************/ -void MFHI() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.HI.UD[0]; } // Rd = Hi -void MFLO() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[0]; } // Rd = Lo - -/********************************************************* -* Move to GPR to HI/LO & Register jump * -* Format: OP rs * -*********************************************************/ -void MTHI() { cpuRegs.HI.UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; } // Hi = Rs -void MTLO() { cpuRegs.LO.UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; } // Lo = Rs - - -/********************************************************* -* Shift arithmetic with constant shift * -* Format: OP rd, rt, sa * -*********************************************************/ -void SLL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] << _Sa_); } // Rd = Rt << sa -void DSLL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] << _Sa_); } -void DSLL32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] << (_Sa_+32));} -void SRA() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].SL[0] >> _Sa_); } // Rd = Rt >> sa (arithmetic) -void DSRA() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (u64)(cpuRegs.GPR.r[_Rt_].SD[0] >> _Sa_); } -void DSRA32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (u64)(cpuRegs.GPR.r[_Rt_].SD[0] >> (_Sa_+32));} -void SRL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] >> _Sa_); } // Rd = Rt >> sa (logical) -void DSRL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] >> _Sa_); } -void DSRL32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] >> (_Sa_+32));} - -/********************************************************* -* Shift arithmetic with variant register shift * -* Format: OP rd, rt, rs * -*********************************************************/ -void SLLV() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] << (cpuRegs.GPR.r[_Rs_].UL[0] &0x1f));} // Rd = Rt << rs -void SRAV() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].SL[0] >> (cpuRegs.GPR.r[_Rs_].UL[0] &0x1f));} // Rd = Rt >> rs (arithmetic) -void SRLV() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] >> (cpuRegs.GPR.r[_Rs_].UL[0] &0x1f));} // Rd = Rt >> rs (logical) -void DSLLV(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] << (cpuRegs.GPR.r[_Rs_].UL[0] &0x3f));} -void DSRAV(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s64)(cpuRegs.GPR.r[_Rt_].SD[0] >> (cpuRegs.GPR.r[_Rs_].UL[0] &0x3f));} -void DSRLV(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] >> (cpuRegs.GPR.r[_Rs_].UL[0] &0x3f));} - -/********************************************************* -* Load and store for GPR * -* Format: OP rt, offset(base) * -*********************************************************/ - -void LB() { - u32 addr; - - addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - u8 temp; - const u32 rt=_Rt_; - - memRead8(addr, &temp); - if(rt!=0) - { - cpuRegs.GPR.r[rt].UD[0]=(s8)temp; - } -} - -void LBU() { - u32 addr; - - addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - u8 temp; - const u32 rt=_Rt_; - memRead8(addr, &temp); - if(rt!=0) - { - cpuRegs.GPR.r[rt].UD[0]=temp; - } -} - -void LH() { - u32 addr; - - addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - u16 temp; - const u32 rt=_Rt_; - memRead16(addr, &temp); - if(rt!=0) - { - cpuRegs.GPR.r[rt].UD[0]=(s16)temp; - } -} - -void LHU() { - u32 addr; - - addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - u16 temp; - const u32 rt=_Rt_; - memRead16(addr, &temp); - if(rt!=0) - { - cpuRegs.GPR.r[rt].UD[0]=temp; - } -} - - -void LW() { - u32 addr; - - addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - - u32 temp; - const u32 rt=_Rt_; - memRead32(addr, &temp); - if(rt!=0) - { - cpuRegs.GPR.r[rt].UD[0]=(s32)temp; - } -} - -void LWU() { - u32 addr; - - addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - - u32 temp; - const u32 rt=_Rt_; - memRead32(addr, &temp); - if(rt!=0) - { - cpuRegs.GPR.r[rt].UD[0]=temp; - } -} - -u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 }; -u32 LWL_SHIFT[4] = { 24, 16, 8, 0 }; - -void LWL() { - s32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - u32 shift = addr & 3; - u32 mem; - - if (!_Rt_) return; - memRead32(addr & ~3, &mem); - cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rt_].UL[0] & LWL_MASK[shift]) | - (mem << LWL_SHIFT[shift]); - - /* - Mem = 1234. Reg = abcd - - 0 4bcd (mem << 24) | (reg & 0x00ffffff) - 1 34cd (mem << 16) | (reg & 0x0000ffff) - 2 234d (mem << 8) | (reg & 0x000000ff) - 3 1234 (mem ) | (reg & 0x00000000) - */ -} - -u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 }; -u32 LWR_SHIFT[4] = { 0, 8, 16, 24 }; - -void LWR() { - s32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - u32 shift = addr & 3; - u32 mem; - - if (!_Rt_) return; - memRead32(addr & ~3, &mem); - cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rt_].UL[0] & LWR_MASK[shift]) | - (mem >> LWR_SHIFT[shift]); - - /* - Mem = 1234. Reg = abcd - - 0 1234 (mem ) | (reg & 0x00000000) - 1 a123 (mem >> 8) | (reg & 0xff000000) - 2 ab12 (mem >> 16) | (reg & 0xffff0000) - 3 abc1 (mem >> 24) | (reg & 0xffffff00) - */ -} - -void LD() { - s32 addr; - - addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - if (_Rt_) { - memRead64(addr, &cpuRegs.GPR.r[_Rt_].UD[0]); - } else { - u64 dummy; - memRead64(addr, &dummy); - } -} - -u64 LDL_MASK[8] = { 0x00ffffffffffffffLL, 0x0000ffffffffffffLL, 0x000000ffffffffffLL, 0x00000000ffffffffLL, - 0x0000000000ffffffLL, 0x000000000000ffffLL, 0x00000000000000ffLL, 0x0000000000000000LL }; -u32 LDL_SHIFT[8] = { 56, 48, 40, 32, 24, 16, 8, 0 }; - -void LDL() { - u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - u32 shift = addr & 7; - u64 mem; - - if (!_Rt_) return; - memRead64(addr & ~7, &mem); - cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rt_].UD[0] & LDL_MASK[shift]) | - (mem << LDL_SHIFT[shift]); -} - -u64 LDR_MASK[8] = { 0x0000000000000000LL, 0xff00000000000000LL, 0xffff000000000000LL, 0xffffff0000000000LL, - 0xffffffff00000000LL, 0xffffffffff000000LL, 0xffffffffffff0000LL, 0xffffffffffffff00LL }; -u32 LDR_SHIFT[8] = { 0, 8, 16, 24, 32, 40, 48, 56 }; - -void LDR() { - u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - u32 shift = addr & 7; - u64 mem; - - if (!_Rt_) return; - memRead64(addr & ~7, &mem); - cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rt_].UD[0] & LDR_MASK[shift]) | - (mem >> LDR_SHIFT[shift]); -} - -void LQ() { - u32 addr; - - addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - addr&=~0xf; - - if (_Rt_) { - memRead128(addr, &cpuRegs.GPR.r[_Rt_].UD[0]); - } else { - u64 val[2]; - memRead128(addr, val); - } -} - -void SB() { - u32 addr; - - addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - memWrite8(addr, cpuRegs.GPR.r[_Rt_].UC[0]); -} - -void SH() { - u32 addr; - - addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - memWrite16(addr, cpuRegs.GPR.r[_Rt_].US[0]); -} - -void SW(){ - u32 addr; - - addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - memWrite32(addr, cpuRegs.GPR.r[_Rt_].UL[0]); -} - -u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0x00000000 }; -u32 SWL_SHIFT[4] = { 24, 16, 8, 0 }; - -void SWL() { - u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - u32 shift = addr & 3; - u32 mem; - - memRead32(addr & ~3, &mem); - - memWrite32(addr & ~3, (cpuRegs.GPR.r[_Rt_].UL[0] >> SWL_SHIFT[shift]) | - ( mem & SWL_MASK[shift]) ); - /* - Mem = 1234. Reg = abcd - - 0 123a (reg >> 24) | (mem & 0xffffff00) - 1 12ab (reg >> 16) | (mem & 0xffff0000) - 2 1abc (reg >> 8) | (mem & 0xff000000) - 3 abcd (reg ) | (mem & 0x00000000) - */ -} - -u32 SWR_MASK[4] = { 0x00000000, 0x000000ff, 0x0000ffff, 0x00ffffff }; -u32 SWR_SHIFT[4] = { 0, 8, 16, 24 }; - -void SWR() { - u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - u32 shift = addr & 3; - u32 mem; - - memRead32(addr & ~3, &mem); - - memWrite32(addr & ~3, (cpuRegs.GPR.r[_Rt_].UL[0] << SWR_SHIFT[shift]) | - ( mem & SWR_MASK[shift]) ); - - /* - Mem = 1234. Reg = abcd - - 0 abcd (reg ) | (mem & 0x00000000) - 1 bcd4 (reg << 8) | (mem & 0x000000ff) - 2 cd34 (reg << 16) | (mem & 0x0000ffff) - 3 d234 (reg << 24) | (mem & 0x00ffffff) - */ -} - -void SD() { - u32 addr; - - addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - memWrite64(addr,&cpuRegs.GPR.r[_Rt_].UD[0]); -} - -u64 SDL_MASK[8] = { 0xffffffffffffff00LL, 0xffffffffffff0000LL, 0xffffffffff000000LL, 0xffffffff00000000LL, - 0xffffff0000000000LL, 0xffff000000000000LL, 0xff00000000000000LL, 0x0000000000000000LL }; -u32 SDL_SHIFT[8] = { 56, 48, 40, 32, 24, 16, 8, 0 }; - -void SDL() { - u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - u32 shift = addr & 7; - u64 mem; - - memRead64(addr & ~7, &mem); - mem =(cpuRegs.GPR.r[_Rt_].UD[0] >> SDL_SHIFT[shift]) | - ( mem & SDL_MASK[shift]); - memWrite64(addr & ~7, &mem); -} - -u64 SDR_MASK[8] = { 0x0000000000000000LL, 0x00000000000000ffLL, 0x000000000000ffffLL, 0x0000000000ffffffLL, - 0x00000000ffffffffLL, 0x000000ffffffffffLL, 0x0000ffffffffffffLL, 0x00ffffffffffffffLL }; -u32 SDR_SHIFT[8] = { 0, 8, 16, 24, 32, 40, 48, 56 }; - -void SDR() { - u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - u32 shift = addr & 7; - u64 mem; - - memRead64(addr & ~7, &mem); - mem=(cpuRegs.GPR.r[_Rt_].UD[0] << SDR_SHIFT[shift]) | - ( mem & SDR_MASK[shift]); - memWrite64(addr & ~7, &mem ); -} - -void SQ() { - u32 addr; - - addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; - addr&=~0xf; - memWrite128(addr, &cpuRegs.GPR.r[_Rt_].UD[0]); -} - -/********************************************************* -* Conditional Move * -* Format: OP rd, rs, rt * -*********************************************************/ - -void MOVZ() { - if (!_Rd_) return; - if (cpuRegs.GPR.r[_Rt_].UD[0] == 0) { - cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; - } -} -void MOVN() { - if (!_Rd_) return; - if (cpuRegs.GPR.r[_Rt_].UD[0] != 0) { - cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; - } -} - -/********************************************************* -* Special purpose instructions * -* Format: OP * -*********************************************************/ - -#include "Sifcmd.h" -/* -int __Deci2Call(int call, u32 *addr); -*/ -u32 *deci2addr = NULL; -u32 deci2handler; -char deci2buffer[256]; - -/* - * int Deci2Call(int, u_int *); - */ - -int __Deci2Call(int call, u32 *addr) -{ - if (call > 0x10) - return -1; - - switch (call) - { - case 1: // open - if( addr != NULL ) - { - deci2addr = (u32*)PSM(addr[1]); - BIOS_LOG("deci2open: %x,%x,%x,%x\n", - addr[3], addr[2], addr[1], addr[0]); - deci2handler = addr[2]; - } - else - { - deci2handler = NULL; - DevCon::Notice( "Deci2Call.Open > NULL address ignored." ); - } - return 1; - - case 2: // close - return 1; - - case 3: // reqsend - { - char reqaddr[128]; - if( addr != NULL ) - sprintf( reqaddr, "%x %x %x %x", addr[3], addr[2], addr[1], addr[0] ); - - BIOS_LOG("deci2reqsend: %s: deci2addr: %x,%x,%x,buf=%x %x,%x,len=%x,%x\n", - (( addr == NULL ) ? "NULL" : reqaddr), - deci2addr[7], deci2addr[6], deci2addr[5], deci2addr[4], - deci2addr[3], deci2addr[2], deci2addr[1], deci2addr[0]); - -// cpuRegs.pc = deci2handler; -// SysPrintf("deci2msg: %s", (char*)PSM(deci2addr[4]+0xc)); - if (deci2addr == NULL) return 1; - if (deci2addr[1]>0xc){ - u8* pdeciaddr = (u8*)dmaGetAddr(deci2addr[4]+0xc); - if( pdeciaddr == NULL ) - pdeciaddr = (u8*)PSM(deci2addr[4]+0xc); - else - pdeciaddr += (deci2addr[4]+0xc)%16; - memcpy(deci2buffer, pdeciaddr, deci2addr[1]-0xc); - deci2buffer[deci2addr[1]-0xc>=255?255:deci2addr[1]-0xc]='\0'; - Console::Write( Color_Cyan, deci2buffer ); - } - deci2addr[3] = 0; - return 1; - } - - case 4: // poll - if( addr != NULL ) - BIOS_LOG("deci2poll: %x,%x,%x,%x\n", addr[3], addr[2], addr[1], addr[0]); - return 1; - - case 5: // exrecv - return 1; - - case 6: // exsend - return 1; - - case 0x10://kputs - if( addr != NULL ) - Console::Write( Color_Cyan, "%s", params PSM(*addr)); - return 1; - } - - return 0; -} - - -void SYSCALL() -{ - u8 call; - - if (cpuRegs.GPR.n.v1.SL[0] < 0) - call = (u8)(-cpuRegs.GPR.n.v1.SL[0]); - else - call = cpuRegs.GPR.n.v1.UC[0]; - - BIOS_LOG("Bios call: %s (%x)\n", bios[call], call); - - if (call == 0x7c) - { - if(cpuRegs.GPR.n.a0.UL[0] == 0x10) - Console::Write( Color_Cyan, (char*)PSM(PSMu32(cpuRegs.GPR.n.a1.UL[0])) ); - else - __Deci2Call( cpuRegs.GPR.n.a0.UL[0], (u32*)PSM(cpuRegs.GPR.n.a1.UL[0]) ); - } - - if (call == 0x77) - { - t_sif_dma_transfer *dmat; - //struct t_sif_cmd_header *hdr; - //struct t_sif_rpc_bind *bind; - //struct t_rpc_server_data *server; - int n_transfer; - u32 addr; - //int sid; - - n_transfer = cpuRegs.GPR.n.a1.UL[0] - 1; - if (n_transfer >= 0) - { - addr = cpuRegs.GPR.n.a0.UL[0] + n_transfer * sizeof(t_sif_dma_transfer); - dmat = (t_sif_dma_transfer*)PSM(addr); - - BIOS_LOG("bios_%s: n_transfer=%d, size=%x, attr=%x, dest=%x, src=%x\n", - bios[cpuRegs.GPR.n.v1.UC[0]], n_transfer, - dmat->size, dmat->attr, - dmat->dest, dmat->src); - } - } - - cpuRegs.pc -= 4; - cpuException(0x20, cpuRegs.branch); -} - -void BREAK(void) { - cpuRegs.pc -= 4; - cpuException(0x24, cpuRegs.branch); -} - -void MFSA( void ) { - if (!_Rd_) return; - cpuRegs.GPR.r[_Rd_].SD[0] = (s64)cpuRegs.sa; -} - -void MTSA( void ) { - cpuRegs.sa = (s32)cpuRegs.GPR.r[_Rs_].SD[0]; -} - -void SYNC( void ) -{ -} - -void PREF( void ) -{ -} - - - -/********************************************************* -* Register trap * -* Format: OP rs, rt * -*********************************************************/ - -void TGE() { - if (cpuRegs.GPR.r[_Rs_].SD[0]>= cpuRegs.GPR.r[_Rt_].SD[0]) { - cpuException(EXC_CODE_Tr, cpuRegs.branch); - } - //SysPrintf( "TrapInstruction: TGE\n" ); -} - -void TGEU() { - if (cpuRegs.GPR.r[_Rs_].UD[0]>= cpuRegs.GPR.r[_Rt_].UD[0]) { - cpuException(EXC_CODE_Tr, cpuRegs.branch); - } - //SysPrintf( "TrapInstruction: TGEU\n" ); -} - -void TLT() { - if (cpuRegs.GPR.r[_Rs_].SD[0] < cpuRegs.GPR.r[_Rt_].SD[0]) { - cpuException(EXC_CODE_Tr, cpuRegs.branch); - } - //SysPrintf( "TrapInstruction: TLT\n" ); -} - -void TLTU() { - if (cpuRegs.GPR.r[_Rs_].UD[0] < cpuRegs.GPR.r[_Rt_].UD[0]) { - cpuException(EXC_CODE_Tr, cpuRegs.branch); - } - //SysPrintf( "TrapInstruction: TLTU\n" ); -} - -void TEQ() { - if (cpuRegs.GPR.r[_Rs_].SD[0] == cpuRegs.GPR.r[_Rt_].SD[0]) { - cpuException(EXC_CODE_Tr, cpuRegs.branch); - } - //SysPrintf( "TrapInstruction: TEQ\n" ); -} - -void TNE() { - if (cpuRegs.GPR.r[_Rs_].SD[0] != cpuRegs.GPR.r[_Rt_].SD[0]) { - cpuException(EXC_CODE_Tr, cpuRegs.branch); - } - //SysPrintf( "TrapInstruction: TNE\n" ); -} - -/********************************************************* -* Trap with immediate operand * -* Format: OP rs, rt * -*********************************************************/ - -void TGEI() { - - if (cpuRegs.GPR.r[_Rs_].SD[0] >= _Imm_) { - cpuException(EXC_CODE_Tr, cpuRegs.branch); - } - //SysPrintf( "TrapInstruction: Immediate\n" ); -} - -void TGEIU() { - if (cpuRegs.GPR.r[_Rs_].UD[0] >= _ImmU_) { - cpuException(EXC_CODE_Tr, cpuRegs.branch); - } - //SysPrintf( "TrapInstruction: Immediate\n" ); -} - -void TLTI() { - if(cpuRegs.GPR.r[_Rs_].SD[0] < _Imm_) { - cpuException(EXC_CODE_Tr, cpuRegs.branch); - } - //SysPrintf( "TrapInstruction: Immediate\n" ); -} - -void TLTIU() { - if (cpuRegs.GPR.r[_Rs_].UD[0] < _ImmU_) { - cpuException(EXC_CODE_Tr, cpuRegs.branch); - } - //SysPrintf( "TrapInstruction: Immediate\n" ); -} - -void TEQI() { - if (cpuRegs.GPR.r[_Rs_].SD[0] == _Imm_) { - cpuException(EXC_CODE_Tr, cpuRegs.branch); - } - //SysPrintf( "TrapInstruction: Immediate\n" ); -} - -void TNEI() { - if (cpuRegs.GPR.r[_Rs_].SD[0] != _Imm_) { - cpuException(EXC_CODE_Tr, cpuRegs.branch); - } - //SysPrintf( "TrapInstruction: Immediate\n" ); -} - -/********************************************************* -* Sa intructions * -* Format: OP rs, rt * -*********************************************************/ - -void MTSAB() { - cpuRegs.sa = ((cpuRegs.GPR.r[_Rs_].UL[0] & 0xF) ^ (_Imm_ & 0xF)) << 3; -} - -void MTSAH() { - cpuRegs.sa = ((cpuRegs.GPR.r[_Rs_].UL[0] & 0x7) ^ (_Imm_ & 0x7)) << 4; -} - -} } } // end namespace R5900::Interpreter::OpcodeImpl +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "R5900.h" +#include "R5900OpcodeTables.h" + +#include + +namespace R5900 +{ + const OPCODE& GetCurrentInstruction() + { + const OPCODE* opcode = &R5900::OpcodeTables::tbl_Standard[_Opcode_]; + + while( opcode->getsubclass != NULL ) + opcode = &opcode->getsubclass(); + + return *opcode; + } + + const char * const bios[256]= + { + //0x00 + "RFU000_FullReset", "ResetEE", "SetGsCrt", "RFU003", + "Exit", "RFU005", "LoadExecPS2", "ExecPS2", + "RFU008", "RFU009", "AddSbusIntcHandler", "RemoveSbusIntcHandler", + "Interrupt2Iop", "SetVTLBRefillHandler", "SetVCommonHandler", "SetVInterruptHandler", + //0x10 + "AddIntcHandler", "RemoveIntcHandler", "AddDmacHandler", "RemoveDmacHandler", + "_EnableIntc", "_DisableIntc", "_EnableDmac", "_DisableDmac", + "_SetAlarm", "_ReleaseAlarm", "_iEnableIntc", "_iDisableIntc", + "_iEnableDmac", "_iDisableDmac", "_iSetAlarm", "_iReleaseAlarm", + //0x20 + "CreateThread", "DeleteThread", "StartThread", "ExitThread", + "ExitDeleteThread", "TerminateThread", "iTerminateThread", "DisableDispatchThread", + "EnableDispatchThread", "ChangeThreadPriority", "iChangeThreadPriority", "RotateThreadReadyQueue", + "iRotateThreadReadyQueue", "ReleaseWaitThread", "iReleaseWaitThread", "GetThreadId", + //0x30 + "ReferThreadStatus","iReferThreadStatus", "SleepThread", "WakeupThread", + "_iWakeupThread", "CancelWakeupThread", "iCancelWakeupThread", "SuspendThread", + "iSuspendThread", "ResumeThread", "iResumeThread", "JoinThread", + "RFU060", "RFU061", "EndOfHeap", "RFU063", + //0x40 + "CreateSema", "DeleteSema", "SignalSema", "iSignalSema", + "WaitSema", "PollSema", "iPollSema", "ReferSemaStatus", + "iReferSemaStatus", "RFU073", "SetOsdConfigParam", "GetOsdConfigParam", + "GetGsHParam", "GetGsVParam", "SetGsHParam", "SetGsVParam", + //0x50 + "RFU080_CreateEventFlag", "RFU081_DeleteEventFlag", + "RFU082_SetEventFlag", "RFU083_iSetEventFlag", + "RFU084_ClearEventFlag", "RFU085_iClearEventFlag", + "RFU086_WaitEventFlag", "RFU087_PollEventFlag", + "RFU088_iPollEventFlag", "RFU089_ReferEventFlagStatus", + "RFU090_iReferEventFlagStatus", "RFU091_GetEntryAddress", + "EnableIntcHandler_iEnableIntcHandler", + "DisableIntcHandler_iDisableIntcHandler", + "EnableDmacHandler_iEnableDmacHandler", + "DisableDmacHandler_iDisableDmacHandler", + //0x60 + "KSeg0", "EnableCache", "DisableCache", "GetCop0", + "FlushCache", "RFU101", "CpuConfig", "iGetCop0", + "iFlushCache", "RFU105", "iCpuConfig", "sceSifStopDma", + "SetCPUTimerHandler", "SetCPUTimer", "SetOsdConfigParam2", "SetOsdConfigParam2", + //0x70 + "GsGetIMR_iGsGetIMR", "GsGetIMR_iGsPutIMR", "SetPgifHandler", "SetVSyncFlag", + "RFU116", "print", "sceSifDmaStat_isceSifDmaStat", "sceSifSetDma_isceSifSetDma", + "sceSifSetDChain_isceSifSetDChain", "sceSifSetReg", "sceSifGetReg", "ExecOSD", + "Deci2Call", "PSMode", "MachineType", "GetMemorySize", + }; + +namespace Interpreter { +namespace OpcodeImpl { + +void COP2() +{ + //std::string disOut; + //disR5900Fasm(disOut, cpuRegs.code, cpuRegs.pc); + + //VU0_LOG("%s\n", disOut.c_str()); + Int_COP2PrintTable[_Rs_](); +} + +void Unknown() { + CPU_LOG("%8.8lx: Unknown opcode called\n", cpuRegs.pc); +} + +void MMI_Unknown() { Console::Notice("Unknown MMI opcode called"); } +void COP0_Unknown() { Console::Notice("Unknown COP0 opcode called"); } +void COP1_Unknown() { Console::Notice("Unknown FPU/COP1 opcode called"); } + +/********************************************************* +* Arithmetic with immediate operand * +* Format: OP rt, rs, immediate * +*********************************************************/ +void ADDI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + _Imm_; }// Rt = Rs + Im signed!!!! +void ADDIU() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + _Imm_; }// Rt = Rs + Im signed !!! +void DADDI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + _Imm_; }// Rt = Rs + Im +void DADDIU() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + _Imm_; }// Rt = Rs + Im +void ANDI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] & (u64)_ImmU_; } // Rt = Rs And Im (zero-extended) +void ORI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] | (u64)_ImmU_; } // Rt = Rs Or Im (zero-extended) +void XORI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] ^ (u64)_ImmU_; } // Rt = Rs Xor Im (zero-extended) +void SLTI() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] < (s64)(_Imm_); } // Rt = Rs < Im (signed) +void SLTIU() { if (!_Rt_) return; cpuRegs.GPR.r[_Rt_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] < (u64)(_Imm_); } // Rt = Rs < Im (unsigned) + +/********************************************************* +* Register arithmetic * +* Format: OP rd, rs, rt * +*********************************************************/ +void ADD() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + cpuRegs.GPR.r[_Rt_].SL[0];} // Rd = Rs + Rt (Exception on Integer Overflow) +void ADDU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] + cpuRegs.GPR.r[_Rt_].SL[0];} // Rd = Rs + Rt +void DADD() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + cpuRegs.GPR.r[_Rt_].SD[0]; } +void DADDU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] + cpuRegs.GPR.r[_Rt_].SD[0]; } +void SUB() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] - cpuRegs.GPR.r[_Rt_].SL[0];} // Rd = Rs - Rt (Exception on Integer Overflow) +void SUBU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SL[0] - cpuRegs.GPR.r[_Rt_].SL[0]; } // Rd = Rs - Rt +void DSUB() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] - cpuRegs.GPR.r[_Rt_].SD[0];} +void DSUBU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] - cpuRegs.GPR.r[_Rt_].SD[0]; } +void AND() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] & cpuRegs.GPR.r[_Rt_].UD[0]; } // Rd = Rs And Rt +void OR() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] | cpuRegs.GPR.r[_Rt_].UD[0]; } // Rd = Rs Or Rt +void XOR() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] ^ cpuRegs.GPR.r[_Rt_].UD[0]; } // Rd = Rs Xor Rt +void NOR() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] =~(cpuRegs.GPR.r[_Rs_].UD[0] | cpuRegs.GPR.r[_Rt_].UD[0]); }// Rd = Rs Nor Rt +void SLT() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].SD[0] < cpuRegs.GPR.r[_Rt_].SD[0]; } // Rd = Rs < Rt (signed) +void SLTU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0] < cpuRegs.GPR.r[_Rt_].UD[0]; } // Rd = Rs < Rt (unsigned) + +/********************************************************* +* Register mult/div & Register trap logic * +* Format: OP rs, rt * +*********************************************************/ +void DIV() { + if (cpuRegs.GPR.r[_Rt_].SL[0] != 0) { + cpuRegs.LO.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0] / cpuRegs.GPR.r[_Rt_].SL[0]; + cpuRegs.HI.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0] % cpuRegs.GPR.r[_Rt_].SL[0]; + } +} + +void DIVU() { + if (cpuRegs.GPR.r[_Rt_].UL[0] != 0) { + cpuRegs.LO.SD[0] = cpuRegs.GPR.r[_Rs_].UL[0] / cpuRegs.GPR.r[_Rt_].UL[0]; + cpuRegs.HI.SD[0] = cpuRegs.GPR.r[_Rs_].UL[0] % cpuRegs.GPR.r[_Rt_].UL[0]; + } +} + +void MULT() { //different in ps2... + s64 res = (s64)cpuRegs.GPR.r[_Rs_].SL[0] * (s64)cpuRegs.GPR.r[_Rt_].SL[0]; + + cpuRegs.LO.UD[0] = (s32)(res & 0xffffffff); + cpuRegs.HI.UD[0] = (s32)(res >> 32); + + if (!_Rd_) return; + cpuRegs.GPR.r[_Rd_].UD[0]= cpuRegs.LO.UD[0]; //that is the difference +} + +void MULTU() { //different in ps2.. + u64 res = (u64)cpuRegs.GPR.r[_Rs_].UL[0] * (u64)cpuRegs.GPR.r[_Rt_].UL[0]; + + cpuRegs.LO.UD[0] = (s32)(res & 0xffffffff); + cpuRegs.HI.UD[0] = (s32)(res >> 32); + + if (!_Rd_) return; + cpuRegs.GPR.r[_Rd_].UD[0]= cpuRegs.LO.UD[0]; //that is the difference +} + +/********************************************************* +* Load higher 16 bits of the first word in GPR with imm * +* Format: OP rt, immediate * +*********************************************************/ +void LUI() { + if (!_Rt_) return; + cpuRegs.GPR.r[_Rt_].UD[0] = (s32)(cpuRegs.code << 16); +} + +/********************************************************* +* Move from HI/LO to GPR * +* Format: OP rd * +*********************************************************/ +void MFHI() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.HI.UD[0]; } // Rd = Hi +void MFLO() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[0]; } // Rd = Lo + +/********************************************************* +* Move to GPR to HI/LO & Register jump * +* Format: OP rs * +*********************************************************/ +void MTHI() { cpuRegs.HI.UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; } // Hi = Rs +void MTLO() { cpuRegs.LO.UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; } // Lo = Rs + + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ +void SLL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] << _Sa_); } // Rd = Rt << sa +void DSLL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] << _Sa_); } +void DSLL32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] << (_Sa_+32));} +void SRA() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].SL[0] >> _Sa_); } // Rd = Rt >> sa (arithmetic) +void DSRA() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (u64)(cpuRegs.GPR.r[_Rt_].SD[0] >> _Sa_); } +void DSRA32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (u64)(cpuRegs.GPR.r[_Rt_].SD[0] >> (_Sa_+32));} +void SRL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] >> _Sa_); } // Rd = Rt >> sa (logical) +void DSRL() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] >> _Sa_); } +void DSRL32(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] >> (_Sa_+32));} + +/********************************************************* +* Shift arithmetic with variant register shift * +* Format: OP rd, rt, rs * +*********************************************************/ +void SLLV() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] << (cpuRegs.GPR.r[_Rs_].UL[0] &0x1f));} // Rd = Rt << rs +void SRAV() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].SL[0] >> (cpuRegs.GPR.r[_Rs_].UL[0] &0x1f));} // Rd = Rt >> rs (arithmetic) +void SRLV() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s32)(cpuRegs.GPR.r[_Rt_].UL[0] >> (cpuRegs.GPR.r[_Rs_].UL[0] &0x1f));} // Rd = Rt >> rs (logical) +void DSLLV(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] << (cpuRegs.GPR.r[_Rs_].UL[0] &0x3f));} +void DSRAV(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].SD[0] = (s64)(cpuRegs.GPR.r[_Rt_].SD[0] >> (cpuRegs.GPR.r[_Rs_].UL[0] &0x3f));} +void DSRLV(){ if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (u64)(cpuRegs.GPR.r[_Rt_].UD[0] >> (cpuRegs.GPR.r[_Rs_].UL[0] &0x3f));} + +/********************************************************* +* Load and store for GPR * +* Format: OP rt, offset(base) * +*********************************************************/ + +void LB() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u8 temp; + const u32 rt=_Rt_; + + memRead8(addr, &temp); + if(rt!=0) + { + cpuRegs.GPR.r[rt].UD[0]=(s8)temp; + } +} + +void LBU() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u8 temp; + const u32 rt=_Rt_; + memRead8(addr, &temp); + if(rt!=0) + { + cpuRegs.GPR.r[rt].UD[0]=temp; + } +} + +void LH() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u16 temp; + const u32 rt=_Rt_; + memRead16(addr, &temp); + if(rt!=0) + { + cpuRegs.GPR.r[rt].UD[0]=(s16)temp; + } +} + +void LHU() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u16 temp; + const u32 rt=_Rt_; + memRead16(addr, &temp); + if(rt!=0) + { + cpuRegs.GPR.r[rt].UD[0]=temp; + } +} + + +void LW() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + + u32 temp; + const u32 rt=_Rt_; + memRead32(addr, &temp); + if(rt!=0) + { + cpuRegs.GPR.r[rt].UD[0]=(s32)temp; + } +} + +void LWU() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + + u32 temp; + const u32 rt=_Rt_; + memRead32(addr, &temp); + if(rt!=0) + { + cpuRegs.GPR.r[rt].UD[0]=temp; + } +} + +u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 }; +u32 LWL_SHIFT[4] = { 24, 16, 8, 0 }; + +void LWL() { + s32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u32 shift = addr & 3; + u32 mem; + + if (!_Rt_) return; + memRead32(addr & ~3, &mem); + cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rt_].UL[0] & LWL_MASK[shift]) | + (mem << LWL_SHIFT[shift]); + + /* + Mem = 1234. Reg = abcd + + 0 4bcd (mem << 24) | (reg & 0x00ffffff) + 1 34cd (mem << 16) | (reg & 0x0000ffff) + 2 234d (mem << 8) | (reg & 0x000000ff) + 3 1234 (mem ) | (reg & 0x00000000) + */ +} + +u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 }; +u32 LWR_SHIFT[4] = { 0, 8, 16, 24 }; + +void LWR() { + s32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u32 shift = addr & 3; + u32 mem; + + if (!_Rt_) return; + memRead32(addr & ~3, &mem); + cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rt_].UL[0] & LWR_MASK[shift]) | + (mem >> LWR_SHIFT[shift]); + + /* + Mem = 1234. Reg = abcd + + 0 1234 (mem ) | (reg & 0x00000000) + 1 a123 (mem >> 8) | (reg & 0xff000000) + 2 ab12 (mem >> 16) | (reg & 0xffff0000) + 3 abc1 (mem >> 24) | (reg & 0xffffff00) + */ +} + +void LD() { + s32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + if (_Rt_) { + memRead64(addr, &cpuRegs.GPR.r[_Rt_].UD[0]); + } else { + u64 dummy; + memRead64(addr, &dummy); + } +} + +u64 LDL_MASK[8] = { 0x00ffffffffffffffLL, 0x0000ffffffffffffLL, 0x000000ffffffffffLL, 0x00000000ffffffffLL, + 0x0000000000ffffffLL, 0x000000000000ffffLL, 0x00000000000000ffLL, 0x0000000000000000LL }; +u32 LDL_SHIFT[8] = { 56, 48, 40, 32, 24, 16, 8, 0 }; + +void LDL() { + u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u32 shift = addr & 7; + u64 mem; + + if (!_Rt_) return; + memRead64(addr & ~7, &mem); + cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rt_].UD[0] & LDL_MASK[shift]) | + (mem << LDL_SHIFT[shift]); +} + +u64 LDR_MASK[8] = { 0x0000000000000000LL, 0xff00000000000000LL, 0xffff000000000000LL, 0xffffff0000000000LL, + 0xffffffff00000000LL, 0xffffffffff000000LL, 0xffffffffffff0000LL, 0xffffffffffffff00LL }; +u32 LDR_SHIFT[8] = { 0, 8, 16, 24, 32, 40, 48, 56 }; + +void LDR() { + u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u32 shift = addr & 7; + u64 mem; + + if (!_Rt_) return; + memRead64(addr & ~7, &mem); + cpuRegs.GPR.r[_Rt_].UD[0] = (cpuRegs.GPR.r[_Rt_].UD[0] & LDR_MASK[shift]) | + (mem >> LDR_SHIFT[shift]); +} + +void LQ() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + addr&=~0xf; + + if (_Rt_) { + memRead128(addr, &cpuRegs.GPR.r[_Rt_].UD[0]); + } else { + u64 val[2]; + memRead128(addr, val); + } +} + +void SB() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + memWrite8(addr, cpuRegs.GPR.r[_Rt_].UC[0]); +} + +void SH() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + memWrite16(addr, cpuRegs.GPR.r[_Rt_].US[0]); +} + +void SW(){ + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + memWrite32(addr, cpuRegs.GPR.r[_Rt_].UL[0]); +} + +u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0x00000000 }; +u32 SWL_SHIFT[4] = { 24, 16, 8, 0 }; + +void SWL() { + u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u32 shift = addr & 3; + u32 mem; + + memRead32(addr & ~3, &mem); + + memWrite32(addr & ~3, (cpuRegs.GPR.r[_Rt_].UL[0] >> SWL_SHIFT[shift]) | + ( mem & SWL_MASK[shift]) ); + /* + Mem = 1234. Reg = abcd + + 0 123a (reg >> 24) | (mem & 0xffffff00) + 1 12ab (reg >> 16) | (mem & 0xffff0000) + 2 1abc (reg >> 8) | (mem & 0xff000000) + 3 abcd (reg ) | (mem & 0x00000000) + */ +} + +u32 SWR_MASK[4] = { 0x00000000, 0x000000ff, 0x0000ffff, 0x00ffffff }; +u32 SWR_SHIFT[4] = { 0, 8, 16, 24 }; + +void SWR() { + u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u32 shift = addr & 3; + u32 mem; + + memRead32(addr & ~3, &mem); + + memWrite32(addr & ~3, (cpuRegs.GPR.r[_Rt_].UL[0] << SWR_SHIFT[shift]) | + ( mem & SWR_MASK[shift]) ); + + /* + Mem = 1234. Reg = abcd + + 0 abcd (reg ) | (mem & 0x00000000) + 1 bcd4 (reg << 8) | (mem & 0x000000ff) + 2 cd34 (reg << 16) | (mem & 0x0000ffff) + 3 d234 (reg << 24) | (mem & 0x00ffffff) + */ +} + +void SD() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + memWrite64(addr,&cpuRegs.GPR.r[_Rt_].UD[0]); +} + +u64 SDL_MASK[8] = { 0xffffffffffffff00LL, 0xffffffffffff0000LL, 0xffffffffff000000LL, 0xffffffff00000000LL, + 0xffffff0000000000LL, 0xffff000000000000LL, 0xff00000000000000LL, 0x0000000000000000LL }; +u32 SDL_SHIFT[8] = { 56, 48, 40, 32, 24, 16, 8, 0 }; + +void SDL() { + u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u32 shift = addr & 7; + u64 mem; + + memRead64(addr & ~7, &mem); + mem =(cpuRegs.GPR.r[_Rt_].UD[0] >> SDL_SHIFT[shift]) | + ( mem & SDL_MASK[shift]); + memWrite64(addr & ~7, &mem); +} + +u64 SDR_MASK[8] = { 0x0000000000000000LL, 0x00000000000000ffLL, 0x000000000000ffffLL, 0x0000000000ffffffLL, + 0x00000000ffffffffLL, 0x000000ffffffffffLL, 0x0000ffffffffffffLL, 0x00ffffffffffffffLL }; +u32 SDR_SHIFT[8] = { 0, 8, 16, 24, 32, 40, 48, 56 }; + +void SDR() { + u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + u32 shift = addr & 7; + u64 mem; + + memRead64(addr & ~7, &mem); + mem=(cpuRegs.GPR.r[_Rt_].UD[0] << SDR_SHIFT[shift]) | + ( mem & SDR_MASK[shift]); + memWrite64(addr & ~7, &mem ); +} + +void SQ() { + u32 addr; + + addr = cpuRegs.GPR.r[_Rs_].UL[0] + _Imm_; + addr&=~0xf; + memWrite128(addr, &cpuRegs.GPR.r[_Rt_].UD[0]); +} + +/********************************************************* +* Conditional Move * +* Format: OP rd, rs, rt * +*********************************************************/ + +void MOVZ() { + if (!_Rd_) return; + if (cpuRegs.GPR.r[_Rt_].UD[0] == 0) { + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; + } +} +void MOVN() { + if (!_Rd_) return; + if (cpuRegs.GPR.r[_Rt_].UD[0] != 0) { + cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rs_].UD[0]; + } +} + +/********************************************************* +* Special purpose instructions * +* Format: OP * +*********************************************************/ + +#include "Sifcmd.h" +/* +int __Deci2Call(int call, u32 *addr); +*/ +u32 *deci2addr = NULL; +u32 deci2handler; +char deci2buffer[256]; + +/* + * int Deci2Call(int, u_int *); + */ + +int __Deci2Call(int call, u32 *addr) +{ + if (call > 0x10) + return -1; + + switch (call) + { + case 1: // open + if( addr != NULL ) + { + deci2addr = (u32*)PSM(addr[1]); + BIOS_LOG("deci2open: %x,%x,%x,%x\n", + addr[3], addr[2], addr[1], addr[0]); + deci2handler = addr[2]; + } + else + { + deci2handler = NULL; + DevCon::Notice( "Deci2Call.Open > NULL address ignored." ); + } + return 1; + + case 2: // close + return 1; + + case 3: // reqsend + { + char reqaddr[128]; + if( addr != NULL ) + sprintf( reqaddr, "%x %x %x %x", addr[3], addr[2], addr[1], addr[0] ); + + BIOS_LOG("deci2reqsend: %s: deci2addr: %x,%x,%x,buf=%x %x,%x,len=%x,%x\n", + (( addr == NULL ) ? "NULL" : reqaddr), + deci2addr[7], deci2addr[6], deci2addr[5], deci2addr[4], + deci2addr[3], deci2addr[2], deci2addr[1], deci2addr[0]); + +// cpuRegs.pc = deci2handler; +// SysPrintf("deci2msg: %s", (char*)PSM(deci2addr[4]+0xc)); + if (deci2addr == NULL) return 1; + if (deci2addr[1]>0xc){ + u8* pdeciaddr = (u8*)dmaGetAddr(deci2addr[4]+0xc); + if( pdeciaddr == NULL ) + pdeciaddr = (u8*)PSM(deci2addr[4]+0xc); + else + pdeciaddr += (deci2addr[4]+0xc)%16; + memcpy(deci2buffer, pdeciaddr, deci2addr[1]-0xc); + deci2buffer[deci2addr[1]-0xc>=255?255:deci2addr[1]-0xc]='\0'; + Console::Write( Color_Cyan, deci2buffer ); + } + deci2addr[3] = 0; + return 1; + } + + case 4: // poll + if( addr != NULL ) + BIOS_LOG("deci2poll: %x,%x,%x,%x\n", addr[3], addr[2], addr[1], addr[0]); + return 1; + + case 5: // exrecv + return 1; + + case 6: // exsend + return 1; + + case 0x10://kputs + if( addr != NULL ) + Console::Write( Color_Cyan, "%s", params PSM(*addr)); + return 1; + } + + return 0; +} + + +void SYSCALL() +{ + u8 call; + + if (cpuRegs.GPR.n.v1.SL[0] < 0) + call = (u8)(-cpuRegs.GPR.n.v1.SL[0]); + else + call = cpuRegs.GPR.n.v1.UC[0]; + + BIOS_LOG("Bios call: %s (%x)\n", bios[call], call); + + if (call == 0x7c) + { + if(cpuRegs.GPR.n.a0.UL[0] == 0x10) + Console::Write( Color_Cyan, (char*)PSM(PSMu32(cpuRegs.GPR.n.a1.UL[0])) ); + else + __Deci2Call( cpuRegs.GPR.n.a0.UL[0], (u32*)PSM(cpuRegs.GPR.n.a1.UL[0]) ); + } + + if (call == 0x77) + { + t_sif_dma_transfer *dmat; + //struct t_sif_cmd_header *hdr; + //struct t_sif_rpc_bind *bind; + //struct t_rpc_server_data *server; + int n_transfer; + u32 addr; + //int sid; + + n_transfer = cpuRegs.GPR.n.a1.UL[0] - 1; + if (n_transfer >= 0) + { + addr = cpuRegs.GPR.n.a0.UL[0] + n_transfer * sizeof(t_sif_dma_transfer); + dmat = (t_sif_dma_transfer*)PSM(addr); + + BIOS_LOG("bios_%s: n_transfer=%d, size=%x, attr=%x, dest=%x, src=%x\n", + bios[cpuRegs.GPR.n.v1.UC[0]], n_transfer, + dmat->size, dmat->attr, + dmat->dest, dmat->src); + } + } + + cpuRegs.pc -= 4; + cpuException(0x20, cpuRegs.branch); +} + +void BREAK(void) { + cpuRegs.pc -= 4; + cpuException(0x24, cpuRegs.branch); +} + +void MFSA( void ) { + if (!_Rd_) return; + cpuRegs.GPR.r[_Rd_].SD[0] = (s64)cpuRegs.sa; +} + +void MTSA( void ) { + cpuRegs.sa = (s32)cpuRegs.GPR.r[_Rs_].SD[0]; +} + +void SYNC( void ) +{ +} + +void PREF( void ) +{ +} + + + +/********************************************************* +* Register trap * +* Format: OP rs, rt * +*********************************************************/ + +void TGE() { + if (cpuRegs.GPR.r[_Rs_].SD[0]>= cpuRegs.GPR.r[_Rt_].SD[0]) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } + //SysPrintf( "TrapInstruction: TGE\n" ); +} + +void TGEU() { + if (cpuRegs.GPR.r[_Rs_].UD[0]>= cpuRegs.GPR.r[_Rt_].UD[0]) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } + //SysPrintf( "TrapInstruction: TGEU\n" ); +} + +void TLT() { + if (cpuRegs.GPR.r[_Rs_].SD[0] < cpuRegs.GPR.r[_Rt_].SD[0]) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } + //SysPrintf( "TrapInstruction: TLT\n" ); +} + +void TLTU() { + if (cpuRegs.GPR.r[_Rs_].UD[0] < cpuRegs.GPR.r[_Rt_].UD[0]) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } + //SysPrintf( "TrapInstruction: TLTU\n" ); +} + +void TEQ() { + if (cpuRegs.GPR.r[_Rs_].SD[0] == cpuRegs.GPR.r[_Rt_].SD[0]) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } + //SysPrintf( "TrapInstruction: TEQ\n" ); +} + +void TNE() { + if (cpuRegs.GPR.r[_Rs_].SD[0] != cpuRegs.GPR.r[_Rt_].SD[0]) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } + //SysPrintf( "TrapInstruction: TNE\n" ); +} + +/********************************************************* +* Trap with immediate operand * +* Format: OP rs, rt * +*********************************************************/ + +void TGEI() { + + if (cpuRegs.GPR.r[_Rs_].SD[0] >= _Imm_) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } + //SysPrintf( "TrapInstruction: Immediate\n" ); +} + +void TGEIU() { + if (cpuRegs.GPR.r[_Rs_].UD[0] >= _ImmU_) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } + //SysPrintf( "TrapInstruction: Immediate\n" ); +} + +void TLTI() { + if(cpuRegs.GPR.r[_Rs_].SD[0] < _Imm_) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } + //SysPrintf( "TrapInstruction: Immediate\n" ); +} + +void TLTIU() { + if (cpuRegs.GPR.r[_Rs_].UD[0] < _ImmU_) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } + //SysPrintf( "TrapInstruction: Immediate\n" ); +} + +void TEQI() { + if (cpuRegs.GPR.r[_Rs_].SD[0] == _Imm_) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } + //SysPrintf( "TrapInstruction: Immediate\n" ); +} + +void TNEI() { + if (cpuRegs.GPR.r[_Rs_].SD[0] != _Imm_) { + cpuException(EXC_CODE_Tr, cpuRegs.branch); + } + //SysPrintf( "TrapInstruction: Immediate\n" ); +} + +/********************************************************* +* Sa intructions * +* Format: OP rs, rt * +*********************************************************/ + +void MTSAB() { + cpuRegs.sa = ((cpuRegs.GPR.r[_Rs_].UL[0] & 0xF) ^ (_Imm_ & 0xF)) << 3; +} + +void MTSAH() { + cpuRegs.sa = ((cpuRegs.GPR.r[_Rs_].UL[0] & 0x7) ^ (_Imm_ & 0x7)) << 4; +} + +} } } // end namespace R5900::Interpreter::OpcodeImpl diff --git a/pcsx2/R5900OpcodeTables.cpp b/pcsx2/R5900OpcodeTables.cpp index 32913f8ef7..527dd0243c 100644 --- a/pcsx2/R5900OpcodeTables.cpp +++ b/pcsx2/R5900OpcodeTables.cpp @@ -1,696 +1,696 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -//all tables for R5900 are define here.. - -#include "PrecompiledHeader.h" -#include "R5900OpcodeTables.h" -#include "R5900.h" - -#include "x86/iR5900AritImm.h" -#include "x86/iR5900Arit.h" -#include "x86/iR5900MultDiv.h" -#include "x86/iR5900Shift.h" -#include "x86/iR5900Branch.h" -#include "x86/iR5900Jump.h" -#include "x86/iR5900LoadStore.h" -#include "x86/iR5900Move.h" -#include "x86/iMMI.h" -#include "x86/iCOP0.h" -#include "x86/iFPU.h" - -namespace R5900 -{ - namespace Opcodes - { - // Generates an entry for the given opcode name. - // Assumes the default function naming schemes for interpreter and recompiler functions. - # define MakeOpcode( name, cycles ) \ - static const OPCODE name = { \ - #name, \ - cycles, \ - NULL, \ - ::R5900::Interpreter::OpcodeImpl::name, \ - ::R5900::Dynarec::OpcodeImpl::rec##name, \ - ::R5900::OpcodeDisasm::name \ - } - -# define MakeOpcodeM( name, cycles ) \ - static const OPCODE name = { \ - #name, \ - cycles, \ - NULL, \ - ::R5900::Interpreter::OpcodeImpl::MMI::name, \ - ::R5900::Dynarec::OpcodeImpl::MMI::rec##name, \ - ::R5900::OpcodeDisasm::name \ - } - -# define MakeOpcode0( name, cycles ) \ - static const OPCODE name = { \ - #name, \ - cycles, \ - NULL, \ - ::R5900::Interpreter::OpcodeImpl::COP0::name, \ - ::R5900::Dynarec::OpcodeImpl::COP0::rec##name, \ - ::R5900::OpcodeDisasm::name \ - } - - # define MakeOpcode1( name, cycles ) \ - static const OPCODE name = { \ - #name, \ - cycles, \ - NULL, \ - ::R5900::Interpreter::OpcodeImpl::COP1::name, \ - ::R5900::Dynarec::OpcodeImpl::COP1::rec##name, \ - ::R5900::OpcodeDisasm::name \ - } - - # define MakeOpcodeClass( name ) \ - static const OPCODE name = { \ - #name, \ - 0, \ - R5900::Opcodes::Class_##name, \ - NULL, \ - NULL, \ - NULL \ - } - - // We're working on new hopefully better cycle ratios, but they're still a WIP. - // And yes this whole thing is an ugly hack. I'll clean it up once we have - // a better idea how exactly the cycle ratios will work best. - - namespace Cycles - { - static const int Default = 9; - static const int Branch = 11; - static const int CopDefault = 7; - - static const int Mult = 2*8; - static const int Div = 14*8; - static const int MMI_Mult = 3*8; - static const int MMI_Div = 22*8; - static const int MMI_Default = 14; - - static const int FPU_Mult = 12; - - static const int Store = 28; - static const int Load = 22; - - static const int StoreFast = 14; - static const int LoadFast = 12; - } - - using namespace Cycles; - - MakeOpcode( Unknown, Default ); - MakeOpcode( MMI_Unknown, Default ); - MakeOpcode( COP0_Unknown, Default ); - MakeOpcode( COP1_Unknown, Default ); - - // Class Subset Opcodes - // (not really opcodes, but rather entire subsets of other opcode classes) - - MakeOpcodeClass( SPECIAL ); - MakeOpcodeClass( REGIMM ); - //MakeOpcodeClass( COP2 ); - MakeOpcodeClass( MMI ); - MakeOpcodeClass( MMI0 ); - MakeOpcodeClass( MMI2 ); - MakeOpcodeClass( MMI1 ); - MakeOpcodeClass( MMI3 ); - - MakeOpcodeClass( COP0 ); - MakeOpcodeClass( COP1 ); - - // Misc Junk - - MakeOpcode( COP2, Default ); - - MakeOpcode( CACHE, Default ); - MakeOpcode( PREF, Default ); - MakeOpcode( SYSCALL, Default ); - MakeOpcode( BREAK, Default ); - MakeOpcode( SYNC, Default ); - - // Branch/Jump Opcodes - - MakeOpcode( J , Default ); - MakeOpcode( JAL, Default ); - MakeOpcode( JR, Default ); - MakeOpcode( JALR, Default ); - - MakeOpcode( BEQ, Branch ); - MakeOpcode( BNE, Branch ); - MakeOpcode( BLEZ, Branch ); - MakeOpcode( BGTZ, Branch ); - MakeOpcode( BEQL, Branch ); - MakeOpcode( BNEL, Branch ); - MakeOpcode( BLEZL, Branch ); - MakeOpcode( BGTZL, Branch ); - MakeOpcode( BLTZ, Branch ); - MakeOpcode( BGEZ, Branch ); - MakeOpcode( BLTZL, Branch ); - MakeOpcode( BGEZL, Branch ); - MakeOpcode( BLTZAL, Branch ); - MakeOpcode( BGEZAL, Branch ); - MakeOpcode( BLTZALL, Branch ); - MakeOpcode( BGEZALL, Branch ); - - MakeOpcode( TGEI, Branch ); - MakeOpcode( TGEIU, Branch ); - MakeOpcode( TLTI, Branch ); - MakeOpcode( TLTIU, Branch ); - MakeOpcode( TEQI, Branch ); - MakeOpcode( TNEI, Branch ); - MakeOpcode( TGE, Branch ); - MakeOpcode( TGEU, Branch ); - MakeOpcode( TLT, Branch ); - MakeOpcode( TLTU, Branch ); - MakeOpcode( TEQ, Branch ); - MakeOpcode( TNE, Branch ); - - // Arithmetic - - MakeOpcode( MULT, Mult ); - MakeOpcode( MULTU, Mult ); - MakeOpcode( MULT1, Mult ); - MakeOpcode( MULTU1, Mult ); - MakeOpcode( MADD, Mult ); - MakeOpcode( MADDU, Mult ); - MakeOpcode( MADD1, Mult ); - MakeOpcode( MADDU1, Mult ); - MakeOpcode( DIV, Div ); - MakeOpcode( DIVU, Div ); - MakeOpcode( DIV1, Div ); - MakeOpcode( DIVU1, Div ); - - MakeOpcode( ADDI, Default ); - MakeOpcode( ADDIU, Default ); - MakeOpcode( DADDI, Default ); - MakeOpcode( DADDIU, Default ); - MakeOpcode( DADD, Default ); - MakeOpcode( DADDU, Default ); - MakeOpcode( DSUB, Default ); - MakeOpcode( DSUBU, Default ); - MakeOpcode( ADD, Default ); - MakeOpcode( ADDU, Default ); - MakeOpcode( SUB, Default ); - MakeOpcode( SUBU, Default ); - - MakeOpcode( ANDI, Default ); - MakeOpcode( ORI, Default ); - MakeOpcode( XORI, Default ); - MakeOpcode( AND, Default ); - MakeOpcode( OR, Default ); - MakeOpcode( XOR, Default ); - MakeOpcode( NOR, Default ); - MakeOpcode( SLTI, Default ); - MakeOpcode( SLTIU, Default ); - MakeOpcode( SLT, Default ); - MakeOpcode( SLTU, Default ); - MakeOpcode( LUI, Default ); - MakeOpcode( SLL, Default ); - MakeOpcode( SRL, Default ); - MakeOpcode( SRA, Default ); - MakeOpcode( SLLV, Default ); - MakeOpcode( SRLV, Default ); - MakeOpcode( SRAV, Default ); - MakeOpcode( MOVZ, Default ); - MakeOpcode( MOVN, Default ); - MakeOpcode( DSLLV, Default ); - MakeOpcode( DSRLV, Default ); - MakeOpcode( DSRAV, Default ); - MakeOpcode( DSLL, Default ); - MakeOpcode( DSRL, Default ); - MakeOpcode( DSRA, Default ); - MakeOpcode( DSLL32, Default ); - MakeOpcode( DSRL32, Default ); - MakeOpcode( DSRA32, Default ); - - MakeOpcode( MFHI, Default ); - MakeOpcode( MTHI, Default ); - MakeOpcode( MFLO, Default ); - MakeOpcode( MTLO, Default ); - MakeOpcode( MFSA, Default ); - MakeOpcode( MTSA, Default ); - MakeOpcode( MTSAB, Default ); - MakeOpcode( MTSAH, Default ); - MakeOpcode( MFHI1, Default ); - MakeOpcode( MTHI1, Default ); - MakeOpcode( MFLO1, Default ); - MakeOpcode( MTLO1, Default ); - - // Loads! - - MakeOpcode( LDL, Load ); - MakeOpcode( LDR, Load ); - MakeOpcode( LQ, Load ); - MakeOpcode( LB, Load ); - MakeOpcode( LH, Load ); - MakeOpcode( LWL, Load ); - MakeOpcode( LW, LoadFast ); - MakeOpcode( LBU, Load ); - MakeOpcode( LHU, Load ); - MakeOpcode( LWR, Load ); - MakeOpcode( LWU, Load ); - MakeOpcode( LWC1, Load ); - MakeOpcode( LQC2, Load ); - MakeOpcode( LD, LoadFast ); - - // Stores! - - MakeOpcode( SQ, Store ); - MakeOpcode( SB, Store );//slow - MakeOpcode( SH, Store );//slow - MakeOpcode( SWL, Store ); - MakeOpcode( SW, StoreFast ); - MakeOpcode( SDL, Store ); - MakeOpcode( SDR, Store ); - MakeOpcode( SWR, Store ); - MakeOpcode( SWC1, Store ); - MakeOpcode( SQC2, Store ); - MakeOpcode( SD, StoreFast ); - - - // Multimedia Instructions! - - MakeOpcodeM( PLZCW, MMI_Default ); - MakeOpcodeM( PMFHL, MMI_Default ); - MakeOpcodeM( PMTHL, MMI_Default ); - MakeOpcodeM( PSLLH, MMI_Default ); - MakeOpcodeM( PSRLH, MMI_Default ); - MakeOpcodeM( PSRAH, MMI_Default ); - MakeOpcodeM( PSLLW, MMI_Default ); - MakeOpcodeM( PSRLW, MMI_Default ); - MakeOpcodeM( PSRAW, MMI_Default ); - - MakeOpcodeM( PADDW, MMI_Default ); - MakeOpcodeM( PADDH, MMI_Default ); - MakeOpcodeM( PADDB, MMI_Default ); - MakeOpcodeM( PADDSW, MMI_Default ); - MakeOpcodeM( PADDSH, MMI_Default ); - MakeOpcodeM( PADDSB, MMI_Default ); - MakeOpcodeM( PADDUW, MMI_Default ); - MakeOpcodeM( PADDUH, MMI_Default ); - MakeOpcodeM( PADDUB, MMI_Default ); - MakeOpcodeM( PSUBW, MMI_Default ); - MakeOpcodeM( PSUBH, MMI_Default ); - MakeOpcodeM( PSUBB, MMI_Default ); - MakeOpcodeM( PSUBSW, MMI_Default ); - MakeOpcodeM( PSUBSH, MMI_Default ); - MakeOpcodeM( PSUBSB, MMI_Default ); - MakeOpcodeM( PSUBUW, MMI_Default ); - MakeOpcodeM( PSUBUH, MMI_Default ); - MakeOpcodeM( PSUBUB, MMI_Default ); - - MakeOpcodeM( PCGTW, MMI_Default ); - MakeOpcodeM( PMAXW, MMI_Default ); - MakeOpcodeM( PMAXH, MMI_Default ); - MakeOpcodeM( PCGTH, MMI_Default ); - MakeOpcodeM( PCGTB, MMI_Default ); - MakeOpcodeM( PEXTLW, MMI_Default ); - MakeOpcodeM( PEXTLH, MMI_Default ); - MakeOpcodeM( PEXTLB, MMI_Default ); - MakeOpcodeM( PEXT5, MMI_Default ); - MakeOpcodeM( PPACW, MMI_Default ); - MakeOpcodeM( PPACH, MMI_Default ); - MakeOpcodeM( PPACB, MMI_Default ); - MakeOpcodeM( PPAC5, MMI_Default ); - - MakeOpcodeM( PABSW, MMI_Default ); - MakeOpcodeM( PABSH, MMI_Default ); - MakeOpcodeM( PCEQW, MMI_Default ); - MakeOpcodeM( PMINW, MMI_Default ); - MakeOpcodeM( PMINH, MMI_Default ); - MakeOpcodeM( PADSBH, MMI_Default ); - MakeOpcodeM( PCEQH, MMI_Default ); - MakeOpcodeM( PCEQB, MMI_Default ); - MakeOpcodeM( PEXTUW, MMI_Default ); - MakeOpcodeM( PEXTUH, MMI_Default ); - MakeOpcodeM( PEXTUB, MMI_Default ); - MakeOpcodeM( PSLLVW, MMI_Default ); - MakeOpcodeM( PSRLVW, MMI_Default ); - - MakeOpcodeM( QFSRV, MMI_Default ); - - MakeOpcodeM( PMADDH, MMI_Mult ); - MakeOpcodeM( PHMADH, MMI_Mult ); - MakeOpcodeM( PMSUBH, MMI_Mult ); - MakeOpcodeM( PHMSBH, MMI_Mult ); - MakeOpcodeM( PMULTH, MMI_Mult ); - MakeOpcodeM( PMADDW, MMI_Mult ); - MakeOpcodeM( PMSUBW, MMI_Mult ); - MakeOpcodeM( PMFHI, MMI_Mult ); - MakeOpcodeM( PMFLO, MMI_Mult ); - MakeOpcodeM( PMULTW, MMI_Mult ); - MakeOpcodeM( PMADDUW, MMI_Mult ); - MakeOpcodeM( PMULTUW, MMI_Mult ); - MakeOpcodeM( PDIVUW, MMI_Div ); - MakeOpcodeM( PDIVW, MMI_Div ); - MakeOpcodeM( PDIVBW, MMI_Div ); - - MakeOpcodeM( PINTH, MMI_Default ); - MakeOpcodeM( PCPYLD, MMI_Default ); - MakeOpcodeM( PAND, MMI_Default ); - MakeOpcodeM( PXOR, MMI_Default ); - MakeOpcodeM( PEXEH, MMI_Default ); - MakeOpcodeM( PREVH, MMI_Default ); - MakeOpcodeM( PEXEW, MMI_Default ); - MakeOpcodeM( PROT3W, MMI_Default ); - - MakeOpcodeM( PSRAVW, MMI_Default ); - MakeOpcodeM( PMTHI, MMI_Default ); - MakeOpcodeM( PMTLO, MMI_Default ); - MakeOpcodeM( PINTEH, MMI_Default ); - MakeOpcodeM( PCPYUD, MMI_Default ); - MakeOpcodeM( POR, MMI_Default ); - MakeOpcodeM( PNOR, MMI_Default ); - MakeOpcodeM( PEXCH, MMI_Default ); - MakeOpcodeM( PCPYH, MMI_Default ); - MakeOpcodeM( PEXCW, MMI_Default ); - - ////////////////////////////////////////////////////////// - // COP0 Instructions - - MakeOpcodeClass( COP0_C0 ); - MakeOpcodeClass( COP0_BC0 ); - - MakeOpcode0( MFC0, CopDefault ); - MakeOpcode0( MTC0, CopDefault ); - - MakeOpcode0( BC0F, Branch ); - MakeOpcode0( BC0T, Branch ); - MakeOpcode0( BC0FL, Branch ); - MakeOpcode0( BC0TL, Branch ); - - MakeOpcode0( TLBR, CopDefault ); - MakeOpcode0( TLBWI, CopDefault ); - MakeOpcode0( TLBWR, CopDefault ); - MakeOpcode0( TLBP, CopDefault ); - MakeOpcode0( ERET, CopDefault ); - MakeOpcode0( EI, CopDefault ); - MakeOpcode0( DI, CopDefault ); - - ////////////////////////////////////////////////////////// - // COP1 Instructions! - - MakeOpcodeClass( COP1_BC1 ); - MakeOpcodeClass( COP1_S ); - MakeOpcodeClass( COP1_W ); // contains CVT_S instruction *only* - - MakeOpcode1( MFC1, CopDefault ); - MakeOpcode1( CFC1, CopDefault ); - MakeOpcode1( MTC1, CopDefault ); - MakeOpcode1( CTC1, CopDefault ); - - MakeOpcode1( BC1F, Branch ); - MakeOpcode1( BC1T, Branch ); - MakeOpcode1( BC1FL, Branch ); - MakeOpcode1( BC1TL, Branch ); - - MakeOpcode1( ADD_S, CopDefault ); - MakeOpcode1( ADDA_S, CopDefault ); - MakeOpcode1( SUB_S, CopDefault ); - MakeOpcode1( SUBA_S, CopDefault ); - - MakeOpcode1( ABS_S, CopDefault ); - MakeOpcode1( MOV_S, CopDefault ); - MakeOpcode1( NEG_S, CopDefault ); - MakeOpcode1( MAX_S, CopDefault ); - MakeOpcode1( MIN_S, CopDefault ); - - MakeOpcode1( MUL_S, FPU_Mult ); - MakeOpcode1( DIV_S, 3*8 ); - MakeOpcode1( SQRT_S, 3*8 ); - MakeOpcode1( RSQRT_S, 4*8 ); - MakeOpcode1( MULA_S, FPU_Mult ); - MakeOpcode1( MADD_S, FPU_Mult ); - MakeOpcode1( MSUB_S, FPU_Mult ); - MakeOpcode1( MADDA_S, FPU_Mult ); - MakeOpcode1( MSUBA_S, FPU_Mult ); - - MakeOpcode1( C_F, CopDefault ); - MakeOpcode1( C_EQ, CopDefault ); - MakeOpcode1( C_LT, CopDefault ); - MakeOpcode1( C_LE, CopDefault ); - - MakeOpcode1( CVT_S, CopDefault ); - MakeOpcode1( CVT_W, CopDefault ); - } - - namespace OpcodeTables - { - using namespace Opcodes; - - const OPCODE tbl_Standard[64] = - { - SPECIAL, REGIMM, J, JAL, BEQ, BNE, BLEZ, BGTZ, - ADDI, ADDIU, SLTI, SLTIU, ANDI, ORI, XORI, LUI, - COP0, COP1, COP2, Unknown, BEQL, BNEL, BLEZL, BGTZL, - DADDI, DADDIU, LDL, LDR, MMI, Unknown, LQ, SQ, - LB, LH, LWL, LW, LBU, LHU, LWR, LWU, - SB, SH, SWL, SW, SDL, SDR, SWR, CACHE, - Unknown, LWC1, Unknown, PREF, Unknown, Unknown, LQC2, LD, - Unknown, SWC1, Unknown, Unknown, Unknown, Unknown, SQC2, SD - }; - - static const OPCODE tbl_Special[64] = - { - SLL, Unknown, SRL, SRA, SLLV, Unknown, SRLV, SRAV, - JR, JALR, MOVZ, MOVN, SYSCALL, BREAK, Unknown, SYNC, - MFHI, MTHI, MFLO, MTLO, DSLLV, Unknown, DSRLV, DSRAV, - MULT, MULTU, DIV, DIVU, Unknown, Unknown, Unknown, Unknown, - ADD, ADDU, SUB, SUBU, AND, OR, XOR, NOR, - MFSA, MTSA, SLT, SLTU, DADD, DADDU, DSUB, DSUBU, - TGE, TGEU, TLT, TLTU, TEQ, Unknown, TNE, Unknown, - DSLL, Unknown, DSRL, DSRA, DSLL32, Unknown, DSRL32, DSRA32 - }; - - static const OPCODE tbl_RegImm[32] = { - BLTZ, BGEZ, BLTZL, BGEZL, Unknown, Unknown, Unknown, Unknown, - TGEI, TGEIU, TLTI, TLTIU, TEQI, Unknown, TNEI, Unknown, - BLTZAL, BGEZAL, BLTZALL, BGEZALL, Unknown, Unknown, Unknown, Unknown, - MTSAB, MTSAH , Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, - }; - - static const OPCODE tbl_MMI[64] = - { - MADD, MADDU, MMI_Unknown, MMI_Unknown, PLZCW, MMI_Unknown, MMI_Unknown, MMI_Unknown, - MMI0, MMI2, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, - MFHI1, MTHI1, MFLO1, MTLO1, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, - MULT1, MULTU1, DIV1, DIVU1, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, - MADD1, MADDU1, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, - MMI1, MMI3, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, - PMFHL, PMTHL, MMI_Unknown, MMI_Unknown, PSLLH, MMI_Unknown, PSRLH, PSRAH, - MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, PSLLW, MMI_Unknown, PSRLW, PSRAW, - }; - - static const OPCODE tbl_MMI0[32] = - { - PADDW, PSUBW, PCGTW, PMAXW, - PADDH, PSUBH, PCGTH, PMAXH, - PADDB, PSUBB, PCGTB, MMI_Unknown, - MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, - PADDSW, PSUBSW, PEXTLW, PPACW, - PADDSH, PSUBSH, PEXTLH, PPACH, - PADDSB, PSUBSB, PEXTLB, PPACB, - MMI_Unknown, MMI_Unknown, PEXT5, PPAC5, - }; - - static const OPCODE tbl_MMI1[32] = - { - MMI_Unknown, PABSW, PCEQW, PMINW, - PADSBH, PABSH, PCEQH, PMINH, - MMI_Unknown, MMI_Unknown, PCEQB, MMI_Unknown, - MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, - PADDUW, PSUBUW, PEXTUW, MMI_Unknown, - PADDUH, PSUBUH, PEXTUH, MMI_Unknown, - PADDUB, PSUBUB, PEXTUB, QFSRV, - MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, - }; - - - static const OPCODE tbl_MMI2[32] = - { - PMADDW, MMI_Unknown, PSLLVW, PSRLVW, - PMSUBW, MMI_Unknown, MMI_Unknown, MMI_Unknown, - PMFHI, PMFLO, PINTH, MMI_Unknown, - PMULTW, PDIVW, PCPYLD, MMI_Unknown, - PMADDH, PHMADH, PAND, PXOR, - PMSUBH, PHMSBH, MMI_Unknown, MMI_Unknown, - MMI_Unknown, MMI_Unknown, PEXEH, PREVH, - PMULTH, PDIVBW, PEXEW, PROT3W, - }; - - static const OPCODE tbl_MMI3[32] = - { - PMADDUW, MMI_Unknown, MMI_Unknown, PSRAVW, - MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, - PMTHI, PMTLO, PINTEH, MMI_Unknown, - PMULTUW, PDIVUW, PCPYUD, MMI_Unknown, - MMI_Unknown, MMI_Unknown, POR, PNOR, - MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, - MMI_Unknown, MMI_Unknown, PEXCH, PCPYH, - MMI_Unknown, MMI_Unknown, PEXCW, MMI_Unknown, - }; - - static const OPCODE tbl_COP0[32] = - { - MFC0, COP0_Unknown, COP0_Unknown, COP0_Unknown, MTC0, COP0_Unknown, COP0_Unknown, COP0_Unknown, - COP0_BC0, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, - COP0_C0, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, - COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, - }; - - static const OPCODE tbl_COP0_BC0[32] = - { - BC0F, BC0T, BC0FL, BC0TL, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, - COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, - COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, - COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, - }; - - static const OPCODE tbl_COP0_C0[64] = - { - COP0_Unknown, TLBR, TLBWI, COP0_Unknown, COP0_Unknown, COP0_Unknown, TLBWR, COP0_Unknown, - TLBP, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, - COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, - ERET, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, - COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, - COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, - COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, - EI, DI, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown - }; - - static const OPCODE tbl_COP1[32] = - { - MFC1, COP1_Unknown, CFC1, COP1_Unknown, MTC1, COP1_Unknown, CTC1, COP1_Unknown, - COP1_BC1, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, - COP1_S, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_W, COP1_Unknown, COP1_Unknown, COP1_Unknown, - COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, - }; - - static const OPCODE tbl_COP1_BC1[32] = - { - BC1F, BC1T, BC1FL, BC1TL, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, - COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, - COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, - COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, - }; - - static const OPCODE tbl_COP1_S[64] = - { - ADD_S, SUB_S, MUL_S, DIV_S, SQRT_S, ABS_S, MOV_S, NEG_S, - COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, - COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,RSQRT_S, COP1_Unknown, - ADDA_S, SUBA_S, MULA_S, COP1_Unknown,MADD_S, MSUB_S, MADDA_S, MSUBA_S, - COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,CVT_W, COP1_Unknown,COP1_Unknown,COP1_Unknown, - MAX_S, MIN_S, COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, - C_F, COP1_Unknown,C_EQ, COP1_Unknown,C_LT, COP1_Unknown,C_LE, COP1_Unknown, - COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, - }; - - static const OPCODE tbl_COP1_W[64] = - { - COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, - COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, - COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, - COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, - CVT_S, COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, - COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, - COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, - COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, - }; - - } // end namespace R5900::OpcodeTables - - namespace Opcodes - { - using namespace OpcodeTables; - - const OPCODE& Class_SPECIAL() { return tbl_Special[_Funct_]; } - const OPCODE& Class_REGIMM() { return tbl_RegImm[_Rt_]; } - - const OPCODE& Class_MMI() { return tbl_MMI[_Funct_]; } - const OPCODE& Class_MMI0() { return tbl_MMI0[_Sa_]; } - const OPCODE& Class_MMI1() { return tbl_MMI1[_Sa_]; } - const OPCODE& Class_MMI2() { return tbl_MMI2[_Sa_]; } - const OPCODE& Class_MMI3() { return tbl_MMI3[_Sa_]; } - - const OPCODE& Class_COP0() { return tbl_COP0[_Rs_]; } - const OPCODE& Class_COP0_BC0() { return tbl_COP0_BC0[(cpuRegs.code >> 16) & 0x03]; } - const OPCODE& Class_COP0_C0() { return tbl_COP0_C0[_Funct_]; } - - const OPCODE& Class_COP1() { return tbl_COP1[_Rs_]; } - const OPCODE& Class_COP1_BC1() { return tbl_COP1_BC1[_Rt_]; } - const OPCODE& Class_COP1_S() { return tbl_COP1_S[_Funct_]; } - const OPCODE& Class_COP1_W() { return tbl_COP1_W[_Funct_]; } - - // These are for future use when the COP2 tables are completed. - //const OPCODE& Class_COP2() { return tbl_COP2[_Rs_]; } - //const OPCODE& Class_COP2_BC2() { return tbl_COP2_BC2[_Rt_]; } - //const OPCODE& Class_COP2_SPECIAL() { return tbl_COP2_SPECIAL[_Funct_]; } - //const OPCODE& Class_COP2_SPECIAL2() { return tbl_COP2_SPECIAL2[(cpuRegs.code & 0x3) | ((cpuRegs.code >> 4) & 0x7c)]; } - } -} // end namespace R5900 - -void (*Int_COP2PrintTable[32])() = { - COP2_Unknown, QMFC2, CFC2, COP2_Unknown, COP2_Unknown, QMTC2, CTC2, COP2_Unknown, - COP2_BC2, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, - COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, - COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, -}; - -void (*Int_COP2BC2PrintTable[32])() = { - BC2F, BC2T, BC2FL, BC2TL, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, - COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, - COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, - COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, -}; - -void (*Int_COP2SPECIAL1PrintTable[64])() = -{ - VADDx, VADDy, VADDz, VADDw, VSUBx, VSUBy, VSUBz, VSUBw, - VMADDx, VMADDy, VMADDz, VMADDw, VMSUBx, VMSUBy, VMSUBz, VMSUBw, - VMAXx, VMAXy, VMAXz, VMAXw, VMINIx, VMINIy, VMINIz, VMINIw, - VMULx, VMULy, VMULz, VMULw, VMULq, VMAXi, VMULi, VMINIi, - VADDq, VMADDq, VADDi, VMADDi, VSUBq, VMSUBq, VSUBi, VMSUBi, - VADD, VMADD, VMUL, VMAX, VSUB, VMSUB, VOPMSUB, VMINI, - VIADD, VISUB, VIADDI, COP2_Unknown,VIAND, VIOR, COP2_Unknown, COP2_Unknown, - VCALLMS, VCALLMSR, COP2_Unknown,COP2_Unknown,COP2_SPECIAL2,COP2_SPECIAL2,COP2_SPECIAL2,COP2_SPECIAL2, -}; - -void (*Int_COP2SPECIAL2PrintTable[128])() = -{ - VADDAx ,VADDAy ,VADDAz ,VADDAw ,VSUBAx ,VSUBAy ,VSUBAz ,VSUBAw, - VMADDAx ,VMADDAy ,VMADDAz ,VMADDAw ,VMSUBAx ,VMSUBAy ,VMSUBAz ,VMSUBAw, - VITOF0 ,VITOF4 ,VITOF12 ,VITOF15 ,VFTOI0 ,VFTOI4 ,VFTOI12 ,VFTOI15, - VMULAx ,VMULAy ,VMULAz ,VMULAw ,VMULAq ,VABS ,VMULAi ,VCLIPw, - VADDAq ,VMADDAq ,VADDAi ,VMADDAi ,VSUBAq ,VMSUBAq ,VSUBAi ,VMSUBAi, - VADDA ,VMADDA ,VMULA ,COP2_Unknown,VSUBA ,VMSUBA ,VOPMULA ,VNOP, - VMOVE ,VMR32 ,COP2_Unknown,COP2_Unknown,VLQI ,VSQI ,VLQD ,VSQD, - VDIV ,VSQRT ,VRSQRT ,VWAITQ ,VMTIR ,VMFIR ,VILWR ,VISWR, - VRNEXT ,VRGET ,VRINIT ,VRXOR ,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, - COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, - COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, - COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, - COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, - COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, - COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, - COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +//all tables for R5900 are define here.. + +#include "PrecompiledHeader.h" +#include "R5900OpcodeTables.h" +#include "R5900.h" + +#include "x86/iR5900AritImm.h" +#include "x86/iR5900Arit.h" +#include "x86/iR5900MultDiv.h" +#include "x86/iR5900Shift.h" +#include "x86/iR5900Branch.h" +#include "x86/iR5900Jump.h" +#include "x86/iR5900LoadStore.h" +#include "x86/iR5900Move.h" +#include "x86/iMMI.h" +#include "x86/iCOP0.h" +#include "x86/iFPU.h" + +namespace R5900 +{ + namespace Opcodes + { + // Generates an entry for the given opcode name. + // Assumes the default function naming schemes for interpreter and recompiler functions. + # define MakeOpcode( name, cycles ) \ + static const OPCODE name = { \ + #name, \ + cycles, \ + NULL, \ + ::R5900::Interpreter::OpcodeImpl::name, \ + ::R5900::Dynarec::OpcodeImpl::rec##name, \ + ::R5900::OpcodeDisasm::name \ + } + +# define MakeOpcodeM( name, cycles ) \ + static const OPCODE name = { \ + #name, \ + cycles, \ + NULL, \ + ::R5900::Interpreter::OpcodeImpl::MMI::name, \ + ::R5900::Dynarec::OpcodeImpl::MMI::rec##name, \ + ::R5900::OpcodeDisasm::name \ + } + +# define MakeOpcode0( name, cycles ) \ + static const OPCODE name = { \ + #name, \ + cycles, \ + NULL, \ + ::R5900::Interpreter::OpcodeImpl::COP0::name, \ + ::R5900::Dynarec::OpcodeImpl::COP0::rec##name, \ + ::R5900::OpcodeDisasm::name \ + } + + # define MakeOpcode1( name, cycles ) \ + static const OPCODE name = { \ + #name, \ + cycles, \ + NULL, \ + ::R5900::Interpreter::OpcodeImpl::COP1::name, \ + ::R5900::Dynarec::OpcodeImpl::COP1::rec##name, \ + ::R5900::OpcodeDisasm::name \ + } + + # define MakeOpcodeClass( name ) \ + static const OPCODE name = { \ + #name, \ + 0, \ + R5900::Opcodes::Class_##name, \ + NULL, \ + NULL, \ + NULL \ + } + + // We're working on new hopefully better cycle ratios, but they're still a WIP. + // And yes this whole thing is an ugly hack. I'll clean it up once we have + // a better idea how exactly the cycle ratios will work best. + + namespace Cycles + { + static const int Default = 9; + static const int Branch = 11; + static const int CopDefault = 7; + + static const int Mult = 2*8; + static const int Div = 14*8; + static const int MMI_Mult = 3*8; + static const int MMI_Div = 22*8; + static const int MMI_Default = 14; + + static const int FPU_Mult = 12; + + static const int Store = 28; + static const int Load = 22; + + static const int StoreFast = 14; + static const int LoadFast = 12; + } + + using namespace Cycles; + + MakeOpcode( Unknown, Default ); + MakeOpcode( MMI_Unknown, Default ); + MakeOpcode( COP0_Unknown, Default ); + MakeOpcode( COP1_Unknown, Default ); + + // Class Subset Opcodes + // (not really opcodes, but rather entire subsets of other opcode classes) + + MakeOpcodeClass( SPECIAL ); + MakeOpcodeClass( REGIMM ); + //MakeOpcodeClass( COP2 ); + MakeOpcodeClass( MMI ); + MakeOpcodeClass( MMI0 ); + MakeOpcodeClass( MMI2 ); + MakeOpcodeClass( MMI1 ); + MakeOpcodeClass( MMI3 ); + + MakeOpcodeClass( COP0 ); + MakeOpcodeClass( COP1 ); + + // Misc Junk + + MakeOpcode( COP2, Default ); + + MakeOpcode( CACHE, Default ); + MakeOpcode( PREF, Default ); + MakeOpcode( SYSCALL, Default ); + MakeOpcode( BREAK, Default ); + MakeOpcode( SYNC, Default ); + + // Branch/Jump Opcodes + + MakeOpcode( J , Default ); + MakeOpcode( JAL, Default ); + MakeOpcode( JR, Default ); + MakeOpcode( JALR, Default ); + + MakeOpcode( BEQ, Branch ); + MakeOpcode( BNE, Branch ); + MakeOpcode( BLEZ, Branch ); + MakeOpcode( BGTZ, Branch ); + MakeOpcode( BEQL, Branch ); + MakeOpcode( BNEL, Branch ); + MakeOpcode( BLEZL, Branch ); + MakeOpcode( BGTZL, Branch ); + MakeOpcode( BLTZ, Branch ); + MakeOpcode( BGEZ, Branch ); + MakeOpcode( BLTZL, Branch ); + MakeOpcode( BGEZL, Branch ); + MakeOpcode( BLTZAL, Branch ); + MakeOpcode( BGEZAL, Branch ); + MakeOpcode( BLTZALL, Branch ); + MakeOpcode( BGEZALL, Branch ); + + MakeOpcode( TGEI, Branch ); + MakeOpcode( TGEIU, Branch ); + MakeOpcode( TLTI, Branch ); + MakeOpcode( TLTIU, Branch ); + MakeOpcode( TEQI, Branch ); + MakeOpcode( TNEI, Branch ); + MakeOpcode( TGE, Branch ); + MakeOpcode( TGEU, Branch ); + MakeOpcode( TLT, Branch ); + MakeOpcode( TLTU, Branch ); + MakeOpcode( TEQ, Branch ); + MakeOpcode( TNE, Branch ); + + // Arithmetic + + MakeOpcode( MULT, Mult ); + MakeOpcode( MULTU, Mult ); + MakeOpcode( MULT1, Mult ); + MakeOpcode( MULTU1, Mult ); + MakeOpcode( MADD, Mult ); + MakeOpcode( MADDU, Mult ); + MakeOpcode( MADD1, Mult ); + MakeOpcode( MADDU1, Mult ); + MakeOpcode( DIV, Div ); + MakeOpcode( DIVU, Div ); + MakeOpcode( DIV1, Div ); + MakeOpcode( DIVU1, Div ); + + MakeOpcode( ADDI, Default ); + MakeOpcode( ADDIU, Default ); + MakeOpcode( DADDI, Default ); + MakeOpcode( DADDIU, Default ); + MakeOpcode( DADD, Default ); + MakeOpcode( DADDU, Default ); + MakeOpcode( DSUB, Default ); + MakeOpcode( DSUBU, Default ); + MakeOpcode( ADD, Default ); + MakeOpcode( ADDU, Default ); + MakeOpcode( SUB, Default ); + MakeOpcode( SUBU, Default ); + + MakeOpcode( ANDI, Default ); + MakeOpcode( ORI, Default ); + MakeOpcode( XORI, Default ); + MakeOpcode( AND, Default ); + MakeOpcode( OR, Default ); + MakeOpcode( XOR, Default ); + MakeOpcode( NOR, Default ); + MakeOpcode( SLTI, Default ); + MakeOpcode( SLTIU, Default ); + MakeOpcode( SLT, Default ); + MakeOpcode( SLTU, Default ); + MakeOpcode( LUI, Default ); + MakeOpcode( SLL, Default ); + MakeOpcode( SRL, Default ); + MakeOpcode( SRA, Default ); + MakeOpcode( SLLV, Default ); + MakeOpcode( SRLV, Default ); + MakeOpcode( SRAV, Default ); + MakeOpcode( MOVZ, Default ); + MakeOpcode( MOVN, Default ); + MakeOpcode( DSLLV, Default ); + MakeOpcode( DSRLV, Default ); + MakeOpcode( DSRAV, Default ); + MakeOpcode( DSLL, Default ); + MakeOpcode( DSRL, Default ); + MakeOpcode( DSRA, Default ); + MakeOpcode( DSLL32, Default ); + MakeOpcode( DSRL32, Default ); + MakeOpcode( DSRA32, Default ); + + MakeOpcode( MFHI, Default ); + MakeOpcode( MTHI, Default ); + MakeOpcode( MFLO, Default ); + MakeOpcode( MTLO, Default ); + MakeOpcode( MFSA, Default ); + MakeOpcode( MTSA, Default ); + MakeOpcode( MTSAB, Default ); + MakeOpcode( MTSAH, Default ); + MakeOpcode( MFHI1, Default ); + MakeOpcode( MTHI1, Default ); + MakeOpcode( MFLO1, Default ); + MakeOpcode( MTLO1, Default ); + + // Loads! + + MakeOpcode( LDL, Load ); + MakeOpcode( LDR, Load ); + MakeOpcode( LQ, Load ); + MakeOpcode( LB, Load ); + MakeOpcode( LH, Load ); + MakeOpcode( LWL, Load ); + MakeOpcode( LW, LoadFast ); + MakeOpcode( LBU, Load ); + MakeOpcode( LHU, Load ); + MakeOpcode( LWR, Load ); + MakeOpcode( LWU, Load ); + MakeOpcode( LWC1, Load ); + MakeOpcode( LQC2, Load ); + MakeOpcode( LD, LoadFast ); + + // Stores! + + MakeOpcode( SQ, Store ); + MakeOpcode( SB, Store );//slow + MakeOpcode( SH, Store );//slow + MakeOpcode( SWL, Store ); + MakeOpcode( SW, StoreFast ); + MakeOpcode( SDL, Store ); + MakeOpcode( SDR, Store ); + MakeOpcode( SWR, Store ); + MakeOpcode( SWC1, Store ); + MakeOpcode( SQC2, Store ); + MakeOpcode( SD, StoreFast ); + + + // Multimedia Instructions! + + MakeOpcodeM( PLZCW, MMI_Default ); + MakeOpcodeM( PMFHL, MMI_Default ); + MakeOpcodeM( PMTHL, MMI_Default ); + MakeOpcodeM( PSLLH, MMI_Default ); + MakeOpcodeM( PSRLH, MMI_Default ); + MakeOpcodeM( PSRAH, MMI_Default ); + MakeOpcodeM( PSLLW, MMI_Default ); + MakeOpcodeM( PSRLW, MMI_Default ); + MakeOpcodeM( PSRAW, MMI_Default ); + + MakeOpcodeM( PADDW, MMI_Default ); + MakeOpcodeM( PADDH, MMI_Default ); + MakeOpcodeM( PADDB, MMI_Default ); + MakeOpcodeM( PADDSW, MMI_Default ); + MakeOpcodeM( PADDSH, MMI_Default ); + MakeOpcodeM( PADDSB, MMI_Default ); + MakeOpcodeM( PADDUW, MMI_Default ); + MakeOpcodeM( PADDUH, MMI_Default ); + MakeOpcodeM( PADDUB, MMI_Default ); + MakeOpcodeM( PSUBW, MMI_Default ); + MakeOpcodeM( PSUBH, MMI_Default ); + MakeOpcodeM( PSUBB, MMI_Default ); + MakeOpcodeM( PSUBSW, MMI_Default ); + MakeOpcodeM( PSUBSH, MMI_Default ); + MakeOpcodeM( PSUBSB, MMI_Default ); + MakeOpcodeM( PSUBUW, MMI_Default ); + MakeOpcodeM( PSUBUH, MMI_Default ); + MakeOpcodeM( PSUBUB, MMI_Default ); + + MakeOpcodeM( PCGTW, MMI_Default ); + MakeOpcodeM( PMAXW, MMI_Default ); + MakeOpcodeM( PMAXH, MMI_Default ); + MakeOpcodeM( PCGTH, MMI_Default ); + MakeOpcodeM( PCGTB, MMI_Default ); + MakeOpcodeM( PEXTLW, MMI_Default ); + MakeOpcodeM( PEXTLH, MMI_Default ); + MakeOpcodeM( PEXTLB, MMI_Default ); + MakeOpcodeM( PEXT5, MMI_Default ); + MakeOpcodeM( PPACW, MMI_Default ); + MakeOpcodeM( PPACH, MMI_Default ); + MakeOpcodeM( PPACB, MMI_Default ); + MakeOpcodeM( PPAC5, MMI_Default ); + + MakeOpcodeM( PABSW, MMI_Default ); + MakeOpcodeM( PABSH, MMI_Default ); + MakeOpcodeM( PCEQW, MMI_Default ); + MakeOpcodeM( PMINW, MMI_Default ); + MakeOpcodeM( PMINH, MMI_Default ); + MakeOpcodeM( PADSBH, MMI_Default ); + MakeOpcodeM( PCEQH, MMI_Default ); + MakeOpcodeM( PCEQB, MMI_Default ); + MakeOpcodeM( PEXTUW, MMI_Default ); + MakeOpcodeM( PEXTUH, MMI_Default ); + MakeOpcodeM( PEXTUB, MMI_Default ); + MakeOpcodeM( PSLLVW, MMI_Default ); + MakeOpcodeM( PSRLVW, MMI_Default ); + + MakeOpcodeM( QFSRV, MMI_Default ); + + MakeOpcodeM( PMADDH, MMI_Mult ); + MakeOpcodeM( PHMADH, MMI_Mult ); + MakeOpcodeM( PMSUBH, MMI_Mult ); + MakeOpcodeM( PHMSBH, MMI_Mult ); + MakeOpcodeM( PMULTH, MMI_Mult ); + MakeOpcodeM( PMADDW, MMI_Mult ); + MakeOpcodeM( PMSUBW, MMI_Mult ); + MakeOpcodeM( PMFHI, MMI_Mult ); + MakeOpcodeM( PMFLO, MMI_Mult ); + MakeOpcodeM( PMULTW, MMI_Mult ); + MakeOpcodeM( PMADDUW, MMI_Mult ); + MakeOpcodeM( PMULTUW, MMI_Mult ); + MakeOpcodeM( PDIVUW, MMI_Div ); + MakeOpcodeM( PDIVW, MMI_Div ); + MakeOpcodeM( PDIVBW, MMI_Div ); + + MakeOpcodeM( PINTH, MMI_Default ); + MakeOpcodeM( PCPYLD, MMI_Default ); + MakeOpcodeM( PAND, MMI_Default ); + MakeOpcodeM( PXOR, MMI_Default ); + MakeOpcodeM( PEXEH, MMI_Default ); + MakeOpcodeM( PREVH, MMI_Default ); + MakeOpcodeM( PEXEW, MMI_Default ); + MakeOpcodeM( PROT3W, MMI_Default ); + + MakeOpcodeM( PSRAVW, MMI_Default ); + MakeOpcodeM( PMTHI, MMI_Default ); + MakeOpcodeM( PMTLO, MMI_Default ); + MakeOpcodeM( PINTEH, MMI_Default ); + MakeOpcodeM( PCPYUD, MMI_Default ); + MakeOpcodeM( POR, MMI_Default ); + MakeOpcodeM( PNOR, MMI_Default ); + MakeOpcodeM( PEXCH, MMI_Default ); + MakeOpcodeM( PCPYH, MMI_Default ); + MakeOpcodeM( PEXCW, MMI_Default ); + + ////////////////////////////////////////////////////////// + // COP0 Instructions + + MakeOpcodeClass( COP0_C0 ); + MakeOpcodeClass( COP0_BC0 ); + + MakeOpcode0( MFC0, CopDefault ); + MakeOpcode0( MTC0, CopDefault ); + + MakeOpcode0( BC0F, Branch ); + MakeOpcode0( BC0T, Branch ); + MakeOpcode0( BC0FL, Branch ); + MakeOpcode0( BC0TL, Branch ); + + MakeOpcode0( TLBR, CopDefault ); + MakeOpcode0( TLBWI, CopDefault ); + MakeOpcode0( TLBWR, CopDefault ); + MakeOpcode0( TLBP, CopDefault ); + MakeOpcode0( ERET, CopDefault ); + MakeOpcode0( EI, CopDefault ); + MakeOpcode0( DI, CopDefault ); + + ////////////////////////////////////////////////////////// + // COP1 Instructions! + + MakeOpcodeClass( COP1_BC1 ); + MakeOpcodeClass( COP1_S ); + MakeOpcodeClass( COP1_W ); // contains CVT_S instruction *only* + + MakeOpcode1( MFC1, CopDefault ); + MakeOpcode1( CFC1, CopDefault ); + MakeOpcode1( MTC1, CopDefault ); + MakeOpcode1( CTC1, CopDefault ); + + MakeOpcode1( BC1F, Branch ); + MakeOpcode1( BC1T, Branch ); + MakeOpcode1( BC1FL, Branch ); + MakeOpcode1( BC1TL, Branch ); + + MakeOpcode1( ADD_S, CopDefault ); + MakeOpcode1( ADDA_S, CopDefault ); + MakeOpcode1( SUB_S, CopDefault ); + MakeOpcode1( SUBA_S, CopDefault ); + + MakeOpcode1( ABS_S, CopDefault ); + MakeOpcode1( MOV_S, CopDefault ); + MakeOpcode1( NEG_S, CopDefault ); + MakeOpcode1( MAX_S, CopDefault ); + MakeOpcode1( MIN_S, CopDefault ); + + MakeOpcode1( MUL_S, FPU_Mult ); + MakeOpcode1( DIV_S, 3*8 ); + MakeOpcode1( SQRT_S, 3*8 ); + MakeOpcode1( RSQRT_S, 4*8 ); + MakeOpcode1( MULA_S, FPU_Mult ); + MakeOpcode1( MADD_S, FPU_Mult ); + MakeOpcode1( MSUB_S, FPU_Mult ); + MakeOpcode1( MADDA_S, FPU_Mult ); + MakeOpcode1( MSUBA_S, FPU_Mult ); + + MakeOpcode1( C_F, CopDefault ); + MakeOpcode1( C_EQ, CopDefault ); + MakeOpcode1( C_LT, CopDefault ); + MakeOpcode1( C_LE, CopDefault ); + + MakeOpcode1( CVT_S, CopDefault ); + MakeOpcode1( CVT_W, CopDefault ); + } + + namespace OpcodeTables + { + using namespace Opcodes; + + const OPCODE tbl_Standard[64] = + { + SPECIAL, REGIMM, J, JAL, BEQ, BNE, BLEZ, BGTZ, + ADDI, ADDIU, SLTI, SLTIU, ANDI, ORI, XORI, LUI, + COP0, COP1, COP2, Unknown, BEQL, BNEL, BLEZL, BGTZL, + DADDI, DADDIU, LDL, LDR, MMI, Unknown, LQ, SQ, + LB, LH, LWL, LW, LBU, LHU, LWR, LWU, + SB, SH, SWL, SW, SDL, SDR, SWR, CACHE, + Unknown, LWC1, Unknown, PREF, Unknown, Unknown, LQC2, LD, + Unknown, SWC1, Unknown, Unknown, Unknown, Unknown, SQC2, SD + }; + + static const OPCODE tbl_Special[64] = + { + SLL, Unknown, SRL, SRA, SLLV, Unknown, SRLV, SRAV, + JR, JALR, MOVZ, MOVN, SYSCALL, BREAK, Unknown, SYNC, + MFHI, MTHI, MFLO, MTLO, DSLLV, Unknown, DSRLV, DSRAV, + MULT, MULTU, DIV, DIVU, Unknown, Unknown, Unknown, Unknown, + ADD, ADDU, SUB, SUBU, AND, OR, XOR, NOR, + MFSA, MTSA, SLT, SLTU, DADD, DADDU, DSUB, DSUBU, + TGE, TGEU, TLT, TLTU, TEQ, Unknown, TNE, Unknown, + DSLL, Unknown, DSRL, DSRA, DSLL32, Unknown, DSRL32, DSRA32 + }; + + static const OPCODE tbl_RegImm[32] = { + BLTZ, BGEZ, BLTZL, BGEZL, Unknown, Unknown, Unknown, Unknown, + TGEI, TGEIU, TLTI, TLTIU, TEQI, Unknown, TNEI, Unknown, + BLTZAL, BGEZAL, BLTZALL, BGEZALL, Unknown, Unknown, Unknown, Unknown, + MTSAB, MTSAH , Unknown, Unknown, Unknown, Unknown, Unknown, Unknown, + }; + + static const OPCODE tbl_MMI[64] = + { + MADD, MADDU, MMI_Unknown, MMI_Unknown, PLZCW, MMI_Unknown, MMI_Unknown, MMI_Unknown, + MMI0, MMI2, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, + MFHI1, MTHI1, MFLO1, MTLO1, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, + MULT1, MULTU1, DIV1, DIVU1, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, + MADD1, MADDU1, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, + MMI1, MMI3, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, + PMFHL, PMTHL, MMI_Unknown, MMI_Unknown, PSLLH, MMI_Unknown, PSRLH, PSRAH, + MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, PSLLW, MMI_Unknown, PSRLW, PSRAW, + }; + + static const OPCODE tbl_MMI0[32] = + { + PADDW, PSUBW, PCGTW, PMAXW, + PADDH, PSUBH, PCGTH, PMAXH, + PADDB, PSUBB, PCGTB, MMI_Unknown, + MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, + PADDSW, PSUBSW, PEXTLW, PPACW, + PADDSH, PSUBSH, PEXTLH, PPACH, + PADDSB, PSUBSB, PEXTLB, PPACB, + MMI_Unknown, MMI_Unknown, PEXT5, PPAC5, + }; + + static const OPCODE tbl_MMI1[32] = + { + MMI_Unknown, PABSW, PCEQW, PMINW, + PADSBH, PABSH, PCEQH, PMINH, + MMI_Unknown, MMI_Unknown, PCEQB, MMI_Unknown, + MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, + PADDUW, PSUBUW, PEXTUW, MMI_Unknown, + PADDUH, PSUBUH, PEXTUH, MMI_Unknown, + PADDUB, PSUBUB, PEXTUB, QFSRV, + MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, + }; + + + static const OPCODE tbl_MMI2[32] = + { + PMADDW, MMI_Unknown, PSLLVW, PSRLVW, + PMSUBW, MMI_Unknown, MMI_Unknown, MMI_Unknown, + PMFHI, PMFLO, PINTH, MMI_Unknown, + PMULTW, PDIVW, PCPYLD, MMI_Unknown, + PMADDH, PHMADH, PAND, PXOR, + PMSUBH, PHMSBH, MMI_Unknown, MMI_Unknown, + MMI_Unknown, MMI_Unknown, PEXEH, PREVH, + PMULTH, PDIVBW, PEXEW, PROT3W, + }; + + static const OPCODE tbl_MMI3[32] = + { + PMADDUW, MMI_Unknown, MMI_Unknown, PSRAVW, + MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, + PMTHI, PMTLO, PINTEH, MMI_Unknown, + PMULTUW, PDIVUW, PCPYUD, MMI_Unknown, + MMI_Unknown, MMI_Unknown, POR, PNOR, + MMI_Unknown, MMI_Unknown, MMI_Unknown, MMI_Unknown, + MMI_Unknown, MMI_Unknown, PEXCH, PCPYH, + MMI_Unknown, MMI_Unknown, PEXCW, MMI_Unknown, + }; + + static const OPCODE tbl_COP0[32] = + { + MFC0, COP0_Unknown, COP0_Unknown, COP0_Unknown, MTC0, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_BC0, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_C0, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + }; + + static const OPCODE tbl_COP0_BC0[32] = + { + BC0F, BC0T, BC0FL, BC0TL, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + }; + + static const OPCODE tbl_COP0_C0[64] = + { + COP0_Unknown, TLBR, TLBWI, COP0_Unknown, COP0_Unknown, COP0_Unknown, TLBWR, COP0_Unknown, + TLBP, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + ERET, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, + EI, DI, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown, COP0_Unknown + }; + + static const OPCODE tbl_COP1[32] = + { + MFC1, COP1_Unknown, CFC1, COP1_Unknown, MTC1, COP1_Unknown, CTC1, COP1_Unknown, + COP1_BC1, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, + COP1_S, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_W, COP1_Unknown, COP1_Unknown, COP1_Unknown, + COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, + }; + + static const OPCODE tbl_COP1_BC1[32] = + { + BC1F, BC1T, BC1FL, BC1TL, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, + COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, + COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, + COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, COP1_Unknown, + }; + + static const OPCODE tbl_COP1_S[64] = + { + ADD_S, SUB_S, MUL_S, DIV_S, SQRT_S, ABS_S, MOV_S, NEG_S, + COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, + COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,RSQRT_S, COP1_Unknown, + ADDA_S, SUBA_S, MULA_S, COP1_Unknown,MADD_S, MSUB_S, MADDA_S, MSUBA_S, + COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,CVT_W, COP1_Unknown,COP1_Unknown,COP1_Unknown, + MAX_S, MIN_S, COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, + C_F, COP1_Unknown,C_EQ, COP1_Unknown,C_LT, COP1_Unknown,C_LE, COP1_Unknown, + COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, + }; + + static const OPCODE tbl_COP1_W[64] = + { + COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, + COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, + COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, + COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, + CVT_S, COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, + COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, + COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, + COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown,COP1_Unknown, + }; + + } // end namespace R5900::OpcodeTables + + namespace Opcodes + { + using namespace OpcodeTables; + + const OPCODE& Class_SPECIAL() { return tbl_Special[_Funct_]; } + const OPCODE& Class_REGIMM() { return tbl_RegImm[_Rt_]; } + + const OPCODE& Class_MMI() { return tbl_MMI[_Funct_]; } + const OPCODE& Class_MMI0() { return tbl_MMI0[_Sa_]; } + const OPCODE& Class_MMI1() { return tbl_MMI1[_Sa_]; } + const OPCODE& Class_MMI2() { return tbl_MMI2[_Sa_]; } + const OPCODE& Class_MMI3() { return tbl_MMI3[_Sa_]; } + + const OPCODE& Class_COP0() { return tbl_COP0[_Rs_]; } + const OPCODE& Class_COP0_BC0() { return tbl_COP0_BC0[(cpuRegs.code >> 16) & 0x03]; } + const OPCODE& Class_COP0_C0() { return tbl_COP0_C0[_Funct_]; } + + const OPCODE& Class_COP1() { return tbl_COP1[_Rs_]; } + const OPCODE& Class_COP1_BC1() { return tbl_COP1_BC1[_Rt_]; } + const OPCODE& Class_COP1_S() { return tbl_COP1_S[_Funct_]; } + const OPCODE& Class_COP1_W() { return tbl_COP1_W[_Funct_]; } + + // These are for future use when the COP2 tables are completed. + //const OPCODE& Class_COP2() { return tbl_COP2[_Rs_]; } + //const OPCODE& Class_COP2_BC2() { return tbl_COP2_BC2[_Rt_]; } + //const OPCODE& Class_COP2_SPECIAL() { return tbl_COP2_SPECIAL[_Funct_]; } + //const OPCODE& Class_COP2_SPECIAL2() { return tbl_COP2_SPECIAL2[(cpuRegs.code & 0x3) | ((cpuRegs.code >> 4) & 0x7c)]; } + } +} // end namespace R5900 + +void (*Int_COP2PrintTable[32])() = { + COP2_Unknown, QMFC2, CFC2, COP2_Unknown, COP2_Unknown, QMTC2, CTC2, COP2_Unknown, + COP2_BC2, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, + COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, + COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, COP2_SPECIAL, +}; + +void (*Int_COP2BC2PrintTable[32])() = { + BC2F, BC2T, BC2FL, BC2TL, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, + COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, + COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, + COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, COP2_Unknown, +}; + +void (*Int_COP2SPECIAL1PrintTable[64])() = +{ + VADDx, VADDy, VADDz, VADDw, VSUBx, VSUBy, VSUBz, VSUBw, + VMADDx, VMADDy, VMADDz, VMADDw, VMSUBx, VMSUBy, VMSUBz, VMSUBw, + VMAXx, VMAXy, VMAXz, VMAXw, VMINIx, VMINIy, VMINIz, VMINIw, + VMULx, VMULy, VMULz, VMULw, VMULq, VMAXi, VMULi, VMINIi, + VADDq, VMADDq, VADDi, VMADDi, VSUBq, VMSUBq, VSUBi, VMSUBi, + VADD, VMADD, VMUL, VMAX, VSUB, VMSUB, VOPMSUB, VMINI, + VIADD, VISUB, VIADDI, COP2_Unknown,VIAND, VIOR, COP2_Unknown, COP2_Unknown, + VCALLMS, VCALLMSR, COP2_Unknown,COP2_Unknown,COP2_SPECIAL2,COP2_SPECIAL2,COP2_SPECIAL2,COP2_SPECIAL2, +}; + +void (*Int_COP2SPECIAL2PrintTable[128])() = +{ + VADDAx ,VADDAy ,VADDAz ,VADDAw ,VSUBAx ,VSUBAy ,VSUBAz ,VSUBAw, + VMADDAx ,VMADDAy ,VMADDAz ,VMADDAw ,VMSUBAx ,VMSUBAy ,VMSUBAz ,VMSUBAw, + VITOF0 ,VITOF4 ,VITOF12 ,VITOF15 ,VFTOI0 ,VFTOI4 ,VFTOI12 ,VFTOI15, + VMULAx ,VMULAy ,VMULAz ,VMULAw ,VMULAq ,VABS ,VMULAi ,VCLIPw, + VADDAq ,VMADDAq ,VADDAi ,VMADDAi ,VSUBAq ,VMSUBAq ,VSUBAi ,VMSUBAi, + VADDA ,VMADDA ,VMULA ,COP2_Unknown,VSUBA ,VMSUBA ,VOPMULA ,VNOP, + VMOVE ,VMR32 ,COP2_Unknown,COP2_Unknown,VLQI ,VSQI ,VLQD ,VSQD, + VDIV ,VSQRT ,VRSQRT ,VWAITQ ,VMTIR ,VMFIR ,VILWR ,VISWR, + VRNEXT ,VRGET ,VRINIT ,VRXOR ,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, + COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, + COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, + COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, + COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, + COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, + COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, + COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown,COP2_Unknown, }; \ No newline at end of file diff --git a/pcsx2/R5900OpcodeTables.h b/pcsx2/R5900OpcodeTables.h index 80a9f9d45c..48686768a6 100644 --- a/pcsx2/R5900OpcodeTables.h +++ b/pcsx2/R5900OpcodeTables.h @@ -1,879 +1,879 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef _R5900_OPCODETABLES_H -#define _R5900_OPCODETABLES_H - -#include - -#include "PS2Etypes.h" - -// TODO : Move these into the OpcodeTables namespace -extern void (*Int_COP2PrintTable[32])(); -extern void (*Int_COP2BC2PrintTable[32])(); -extern void (*Int_COP2SPECIAL1PrintTable[64])(); -extern void (*Int_COP2SPECIAL2PrintTable[128])(); - -void COP2_BC2(); -void COP2_SPECIAL(); -void COP2_SPECIAL2(); -void COP2_Unknown(); - - -namespace R5900 -{ - namespace Dynarec { - namespace OpcodeImpl - { - void recNULL(); - void recUnknown(); - void recMMI_Unknown(); - void recCOP0_Unknown(); - void recCOP1_Unknown(); - - void recCOP2(); - - void recCACHE(); - void recPREF(); - void recSYSCALL(); - void recBREAK(); - void recSYNC(); - - void recMFSA(); - void recMTSA(); - void recMTSAB(); - void recMTSAH(); - - void recTGE(); - void recTGEU(); - void recTLT(); - void recTLTU(); - void recTEQ(); - void recTNE(); - void recTGEI(); - void recTGEIU(); - void recTLTI(); - void recTLTIU(); - void recTEQI(); - void recTNEI(); - - } } - - /////////////////////////////////////////////////////////////////////////// - // Encapsulates information about every opcode on the Emotion Engine and - // it's many co-processors. - struct OPCODE - { - // Textual name of the instruction. - const char Name[16]; - - // Number of cycles this instruction normally uses. - u8 cycles; - - const OPCODE& (*getsubclass)(); - - // Process the instruction using the interpreter. - // The action is performed immediately on the EE's cpu state. - void (*interpret)(); - - // Generate recompiled code for this instruction, injected into - // the current EErec block state. - void (*recompile)(); - - // Generates a string representation of the instruction and it's parameters, - // and pastes it into the given output parameter. - void (*disasm)( std::string& output ); - }; - - // Returns the current real instruction, as per the current cpuRegs settings. - const OPCODE& GetCurrentInstruction(); - - namespace OpcodeTables - { - using ::R5900::OPCODE; - - extern const OPCODE tbl_Standard[64]; - - /*extern const OPCODE Standard[64]; - extern const OPCODE Special[64]; - extern const OPCODE RegImm[32]; - extern const OPCODE MMI[64]; - extern const OPCODE MMI0[32]; - extern const OPCODE MMI1[32]; - extern const OPCODE MMI2[32]; - extern const OPCODE MMI3[32]; - - extern const OPCODE COP0[32]; - extern const OPCODE COP0_BC0[32]; - extern const OPCODE COP0_C0[64]; - - extern const OPCODE COP1[32]; - extern const OPCODE COP1_BC1[32]; - extern const OPCODE COP1_S[64]; - extern const OPCODE COP1_W[64];*/ - } - - namespace Opcodes - { - using ::R5900::OPCODE; - - const OPCODE& Class_SPECIAL(); - const OPCODE& Class_REGIMM(); - const OPCODE& Class_MMI(); - const OPCODE& Class_MMI0(); - const OPCODE& Class_MMI1(); - const OPCODE& Class_MMI2(); - const OPCODE& Class_MMI3(); - - const OPCODE& Class_COP0(); - const OPCODE& Class_COP0_BC0(); - const OPCODE& Class_COP0_C0(); - - const OPCODE& Class_COP1(); - const OPCODE& Class_COP1_BC1(); - const OPCODE& Class_COP1_S(); - const OPCODE& Class_COP1_W(); - } - - namespace OpcodeDisasm - { -//**************************************************************** - void Unknown( std::string& output ); - void COP0_Unknown( std::string& output ); - void COP1_Unknown( std::string& output ); - void MMI_Unknown( std::string& output ); - - void COP2( std::string& output ); - -// **********************Standard Opcodes************************** - void J( std::string& output ); - void JAL( std::string& output ); - void BEQ( std::string& output ); - void BNE( std::string& output ); - void BLEZ( std::string& output ); - void BGTZ( std::string& output ); - void ADDI( std::string& output ); - void ADDIU( std::string& output ); - void SLTI( std::string& output ); - void SLTIU( std::string& output ); - void ANDI( std::string& output ); - void ORI( std::string& output ); - void XORI( std::string& output ); - void LUI( std::string& output ); - void BEQL( std::string& output ); - void BNEL( std::string& output ); - void BLEZL( std::string& output ); - void BGTZL( std::string& output ); - void DADDI( std::string& output ); - void DADDIU( std::string& output ); - void LDL( std::string& output ); - void LDR( std::string& output ); - void LB( std::string& output ); - void LH( std::string& output ); - void LWL( std::string& output ); - void LW( std::string& output ); - void LBU( std::string& output ); - void LHU( std::string& output ); - void LWR( std::string& output ); - void LWU( std::string& output ); - void SB( std::string& output ); - void SH( std::string& output ); - void SWL( std::string& output ); - void SW( std::string& output ); - void SDL( std::string& output ); - void SDR( std::string& output ); - void SWR( std::string& output ); - void CACHE( std::string& output ); - void LWC1( std::string& output ); - void PREF( std::string& output ); - void LQC2( std::string& output ); - void LD( std::string& output ); - void SQC2( std::string& output ); - void SD( std::string& output ); - void LQ( std::string& output ); - void SQ( std::string& output ); - void SWC1( std::string& output ); -//*****************end of standard opcodes********************** -//********************SPECIAL OPCODES*************************** - void SLL( std::string& output ); - void SRL( std::string& output ); - void SRA( std::string& output ); - void SLLV( std::string& output ); - void SRLV( std::string& output ); - void SRAV( std::string& output ); - void JR( std::string& output ); - void JALR( std::string& output ); - void SYSCALL( std::string& output ); - void BREAK( std::string& output ); - void SYNC( std::string& output ); - void MFHI( std::string& output ); - void MTHI( std::string& output ); - void MFLO( std::string& output ); - void MTLO( std::string& output ); - void DSLLV( std::string& output ); - void DSRLV( std::string& output ); - void DSRAV( std::string& output ); - void MULT( std::string& output ); - void MULTU( std::string& output ); - void DIV( std::string& output ); - void DIVU( std::string& output ); - void ADD( std::string& output ); - void ADDU( std::string& output ); - void SUB( std::string& output ); - void SUBU( std::string& output ); - void AND( std::string& output ); - void OR( std::string& output ); - void XOR( std::string& output ); - void NOR( std::string& output ); - void SLT( std::string& output ); - void SLTU( std::string& output ); - void DADD( std::string& output ); - void DADDU( std::string& output ); - void DSUB( std::string& output ); - void DSUBU( std::string& output ); - void TGE( std::string& output ); - void TGEU( std::string& output ); - void TLT( std::string& output ); - void TLTU( std::string& output ); - void TEQ( std::string& output ); - void TNE( std::string& output ); - void DSLL( std::string& output ); - void DSRL( std::string& output ); - void DSRA( std::string& output ); - void DSLL32( std::string& output ); - void DSRL32( std::string& output ); - void DSRA32( std::string& output ); - void MOVZ( std::string& output ); - void MOVN( std::string& output ); - void MFSA( std::string& output ); - void MTSA( std::string& output ); -//*******************END OF SPECIAL OPCODES************************ -//***********************REGIMM OPCODES**************************** - void BLTZ( std::string& output ); - void BGEZ( std::string& output ); - void BLTZL( std::string& output ); - void BGEZL( std::string& output ); - void TGEI( std::string& output ); - void TGEIU( std::string& output ); - void TLTI( std::string& output ); - void TLTIU( std::string& output ); - void TEQI( std::string& output ); - void TNEI( std::string& output ); - void BLTZAL( std::string& output ); - void BGEZAL( std::string& output ); - void BLTZALL( std::string& output ); - void BGEZALL( std::string& output ); - void MTSAB( std::string& output ); - void MTSAH( std::string& output ); -//*******************END OF REGIMM OPCODES*********************** -//***********************MMI OPCODES***************************** - void MADD( std::string& output ); - void MADDU( std::string& output ); - void PLZCW( std::string& output ); - void MADD1( std::string& output ); - void MADDU1( std::string& output ); - void MFHI1( std::string& output ); - void MTHI1( std::string& output ); - void MFLO1( std::string& output ); - void MTLO1( std::string& output ); - void MULT1( std::string& output ); - void MULTU1( std::string& output ); - void DIV1( std::string& output ); - void DIVU1( std::string& output ); - void PMFHL( std::string& output ); - void PMTHL( std::string& output ); - void PSLLH( std::string& output ); - void PSRLH( std::string& output ); - void PSRAH( std::string& output ); - void PSLLW( std::string& output ); - void PSRLW( std::string& output ); - void PSRAW( std::string& output ); -//********************END OF MMI OPCODES*********************** -//***********************MMI0 OPCODES************************** - void PADDW( std::string& output ); - void PSUBW( std::string& output ); - void PCGTW( std::string& output ); - void PMAXW( std::string& output ); - void PADDH( std::string& output ); - void PSUBH( std::string& output ); - void PCGTH( std::string& output ); - void PMAXH( std::string& output ); - void PADDB( std::string& output ); - void PSUBB( std::string& output ); - void PCGTB( std::string& output ); - void PADDSW( std::string& output ); - void PSUBSW( std::string& output ); - void PEXTLW( std::string& output ); - void PPACW( std::string& output ); - void PADDSH( std::string& output ); - void PSUBSH( std::string& output ); - void PEXTLH( std::string& output ); - void PPACH( std::string& output ); - void PADDSB( std::string& output ); - void PSUBSB( std::string& output ); - void PEXTLB( std::string& output ); - void PPACB( std::string& output ); - void PEXT5( std::string& output ); - void PPAC5( std::string& output ); -//******************END OF MMI0 OPCODES*********************** -//*********************MMI1 OPCODES*************************** - void PABSW( std::string& output ); - void PCEQW( std::string& output ); - void PMINW( std::string& output ); - void PADSBH( std::string& output ); - void PABSH( std::string& output ); - void PCEQH( std::string& output ); - void PMINH( std::string& output ); - void PCEQB( std::string& output ); - void PADDUW( std::string& output ); - void PSUBUW( std::string& output ); - void PEXTUW( std::string& output ); - void PADDUH( std::string& output ); - void PSUBUH( std::string& output ); - void PEXTUH( std::string& output ); - void PADDUB( std::string& output ); - void PSUBUB( std::string& output ); - void PEXTUB( std::string& output ); - void QFSRV( std::string& output ); -//*****************END OF MMI1 OPCODES*********************** -//*********************MMI2 OPCODES************************** - void PMADDW( std::string& output ); - void PSLLVW( std::string& output ); - void PSRLVW( std::string& output ); - void PMSUBW( std::string& output ); - void PMFHI( std::string& output ); - void PMFLO( std::string& output ); - void PINTH( std::string& output ); - void PMULTW( std::string& output ); - void PDIVW( std::string& output ); - void PCPYLD( std::string& output ); - void PMADDH( std::string& output ); - void PHMADH( std::string& output ); - void PAND( std::string& output ); - void PXOR( std::string& output ); - void PMSUBH( std::string& output ); - void PHMSBH( std::string& output ); - void PEXEH( std::string& output ); - void PREVH( std::string& output ); - void PMULTH( std::string& output ); - void PDIVBW( std::string& output ); - void PEXEW( std::string& output ); - void PROT3W( std::string& output ); -//********************END OF MMI2 OPCODES******************** -//***********************MMI3 OPCODES************************ - void PMADDUW( std::string& output ); - void PSRAVW( std::string& output ); - void PMTHI( std::string& output ); - void PMTLO( std::string& output ); - void PINTEH( std::string& output ); - void PMULTUW( std::string& output ); - void PDIVUW( std::string& output ); - void PCPYUD( std::string& output ); - void POR( std::string& output ); - void PNOR( std::string& output ); - void PEXCH( std::string& output ); - void PCPYH( std::string& output ); - void PEXCW( std::string& output ); -//*********************END OF MMI3 OPCODES******************* -//************************COP0 OPCODES*********************** - void MFC0( std::string& output ); - void MTC0( std::string& output ); - void BC0F( std::string& output ); - void BC0T( std::string& output ); - void BC0FL( std::string& output ); - void BC0TL( std::string& output ); - void TLBR( std::string& output ); - void TLBWI( std::string& output ); - void TLBWR( std::string& output ); - void TLBP( std::string& output ); - void ERET( std::string& output ); - void DI( std::string& output ); - void EI( std::string& output ); -//***********************END OF COP0************************* -//**************COP1 - Floating Point Unit (FPU)************* - void MFC1( std::string& output ); - void CFC1( std::string& output ); - void MTC1( std::string& output ); - void CTC1( std::string& output ); - void BC1F( std::string& output ); - void BC1T( std::string& output ); - void BC1FL( std::string& output ); - void BC1TL( std::string& output ); - void ADD_S( std::string& output ); - void SUB_S( std::string& output ); - void MUL_S( std::string& output ); - void DIV_S( std::string& output ); - void SQRT_S( std::string& output ); - void ABS_S( std::string& output ); - void MOV_S( std::string& output ); - void NEG_S( std::string& output ); - void RSQRT_S( std::string& output ); - void ADDA_S( std::string& output ); - void SUBA_S( std::string& output ); - void MULA_S( std::string& output ); - void MADD_S( std::string& output ); - void MSUB_S( std::string& output ); - void MADDA_S( std::string& output ); - void MSUBA_S( std::string& output ); - void CVT_W( std::string& output ); - void MAX_S( std::string& output ); - void MIN_S( std::string& output ); - void C_F( std::string& output ); - void C_EQ( std::string& output ); - void C_LT( std::string& output ); - void C_LE( std::string& output ); - void CVT_S( std::string& output ); -//**********************END OF COP1*********************** - } - - namespace Interpreter { - namespace OpcodeImpl - { - using namespace ::R5900; - - void COP2(); - - void Unknown(); - void MMI_Unknown(); - void COP0_Unknown(); - void COP1_Unknown(); - -// **********************Standard Opcodes************************** - void J(); - void JAL(); - void BEQ(); - void BNE(); - void BLEZ(); - void BGTZ(); - void ADDI(); - void ADDIU(); - void SLTI(); - void SLTIU(); - void ANDI(); - void ORI(); - void XORI(); - void LUI(); - void BEQL(); - void BNEL(); - void BLEZL(); - void BGTZL(); - void DADDI(); - void DADDIU(); - void LDL(); - void LDR(); - void LB(); - void LH(); - void LWL(); - void LW(); - void LBU(); - void LHU(); - void LWR(); - void LWU(); - void SB(); - void SH(); - void SWL(); - void SW(); - void SDL(); - void SDR(); - void SWR(); - void CACHE(); - void LWC1(); - void PREF(); - void LQC2(); - void LD(); - void SQC2(); - void SD(); - void LQ(); - void SQ(); - void SWC1(); -//*****************end of standard opcodes********************** -//********************SPECIAL OPCODES*************************** - void SLL(); - void SRL(); - void SRA(); - void SLLV(); - void SRLV(); - void SRAV(); - void JR(); - void JALR(); - void SYSCALL(); - void BREAK(); - void SYNC(); - void MFHI(); - void MTHI(); - void MFLO(); - void MTLO(); - void DSLLV(); - void DSRLV(); - void DSRAV(); - void MULT(); - void MULTU(); - void DIV(); - void DIVU(); - void ADD(); - void ADDU(); - void SUB(); - void SUBU(); - void AND(); - void OR(); - void XOR(); - void NOR(); - void SLT(); - void SLTU(); - void DADD(); - void DADDU(); - void DSUB(); - void DSUBU(); - void TGE(); - void TGEU(); - void TLT(); - void TLTU(); - void TEQ(); - void TNE(); - void DSLL(); - void DSRL(); - void DSRA(); - void DSLL32(); - void DSRL32(); - void DSRA32(); - void MOVZ(); - void MOVN(); - void MFSA(); - void MTSA(); -//*******************END OF SPECIAL OPCODES************************ -//***********************REGIMM OPCODES**************************** - void BLTZ(); - void BGEZ(); - void BLTZL(); - void BGEZL(); - void TGEI(); - void TGEIU(); - void TLTI(); - void TLTIU(); - void TEQI(); - void TNEI(); - void BLTZAL(); - void BGEZAL(); - void BLTZALL(); - void BGEZALL(); - void MTSAB(); - void MTSAH(); -//*******************END OF REGIMM OPCODES*********************** -//***********************MMI OPCODES***************************** - void MADD(); - void MADDU(); - void MADD1(); - void MADDU1(); - void MFHI1(); - void MTHI1(); - void MFLO1(); - void MTLO1(); - void MULT1(); - void MULTU1(); - void DIV1(); - void DIVU1(); - - namespace MMI { - void PLZCW(); - void PMFHL(); - void PMTHL(); - void PSLLH(); - void PSRLH(); - void PSRAH(); - void PSLLW(); - void PSRLW(); - void PSRAW(); -//********************END OF MMI OPCODES*********************** -//***********************MMI0 OPCODES************************** - void PADDW(); - void PSUBW(); - void PCGTW(); - void PMAXW(); - void PADDH(); - void PSUBH(); - void PCGTH(); - void PMAXH(); - void PADDB(); - void PSUBB(); - void PCGTB(); - void PADDSW(); - void PSUBSW(); - void PEXTLW(); - void PPACW(); - void PADDSH(); - void PSUBSH(); - void PEXTLH(); - void PPACH(); - void PADDSB(); - void PSUBSB(); - void PEXTLB(); - void PPACB(); - void PEXT5(); - void PPAC5(); -//******************END OF MMI0 OPCODES*********************** -//*********************MMI1 OPCODES*************************** - void PABSW(); - void PCEQW(); - void PMINW(); - void PADSBH(); - void PABSH(); - void PCEQH(); - void PMINH(); - void PCEQB(); - void PADDUW(); - void PSUBUW(); - void PEXTUW(); - void PADDUH(); - void PSUBUH(); - void PEXTUH(); - void PADDUB(); - void PSUBUB(); - void PEXTUB(); - void QFSRV(); -//*****************END OF MMI1 OPCODES*********************** -//*********************MMI2 OPCODES************************** - void PMADDW(); - void PSLLVW(); - void PSRLVW(); - void PMSUBW(); - void PMFHI(); - void PMFLO(); - void PINTH(); - void PMULTW(); - void PDIVW(); - void PCPYLD(); - void PMADDH(); - void PHMADH(); - void PAND(); - void PXOR(); - void PMSUBH(); - void PHMSBH(); - void PEXEH(); - void PREVH(); - void PMULTH(); - void PDIVBW(); - void PEXEW(); - void PROT3W(); -//********************END OF MMI2 OPCODES******************** -//***********************MMI3 OPCODES************************ - void PMADDUW(); - void PSRAVW(); - void PMTHI(); - void PMTLO(); - void PINTEH(); - void PMULTUW(); - void PDIVUW(); - void PCPYUD(); - void POR(); - void PNOR(); - void PEXCH(); - void PCPYH(); - void PEXCW(); - } -//**********************END OF MMI3 OPCODES******************** -//*************************COP0 OPCODES************************ - namespace COP0 { - void MFC0(); - void MTC0(); - void BC0F(); - void BC0T(); - void BC0FL(); - void BC0TL(); - void TLBR(); - void TLBWI(); - void TLBWR(); - void TLBP(); - void ERET(); - void DI(); - void EI(); - } -//********************END OF COP0 OPCODES************************ -//************COP1 OPCODES - Floating Point Unit***************** - namespace COP1 { - void MFC1(); - void CFC1(); - void MTC1(); - void CTC1(); - void BC1F(); - void BC1T(); - void BC1FL(); - void BC1TL(); - void ADD_S(); - void SUB_S(); - void MUL_S(); - void DIV_S(); - void SQRT_S(); - void ABS_S(); - void MOV_S(); - void NEG_S(); - void RSQRT_S(); - void ADDA_S(); - void SUBA_S(); - void MULA_S(); - void MADD_S(); - void MSUB_S(); - void MADDA_S(); - void MSUBA_S(); - void CVT_W(); - void MAX_S(); - void MIN_S(); - void C_F(); - void C_EQ(); - void C_LT(); - void C_LE(); - void CVT_S(); - } - } } -} // End namespace R5900 - -//**************************************************************************** -//** COP2 - (VU0) ** -//**************************************************************************** -void QMFC2(); -void CFC2(); -void QMTC2(); -void CTC2(); -void BC2F(); -void BC2T(); -void BC2FL(); -void BC2TL(); -//*****************SPECIAL 1 VUO TABLE******************************* -void VADDx(); -void VADDy(); -void VADDz(); -void VADDw(); -void VSUBx(); -void VSUBy(); -void VSUBz(); -void VSUBw(); -void VMADDx(); -void VMADDy(); -void VMADDz(); -void VMADDw(); -void VMSUBx(); -void VMSUBy(); -void VMSUBz(); -void VMSUBw(); -void VMAXx(); -void VMAXy(); -void VMAXz(); -void VMAXw(); -void VMINIx(); -void VMINIy(); -void VMINIz(); -void VMINIw(); -void VMULx(); -void VMULy(); -void VMULz(); -void VMULw(); -void VMULq(); -void VMAXi(); -void VMULi(); -void VMINIi(); -void VADDq(); -void VMADDq(); -void VADDi(); -void VMADDi(); -void VSUBq(); -void VMSUBq(); -void VSUBi(); -void VMSUBi(); -void VADD(); -void VMADD(); -void VMUL(); -void VMAX(); -void VSUB(); -void VMSUB(); -void VOPMSUB(); -void VMINI(); -void VIADD(); -void VISUB(); -void VIADDI(); -void VIAND(); -void VIOR(); -void VCALLMS(); -void VCALLMSR(); -//***********************************END OF SPECIAL1 VU0 TABLE***************************** -//******************************SPECIAL2 VUO TABLE***************************************** -void VADDAx(); -void VADDAy(); -void VADDAz(); -void VADDAw(); -void VSUBAx(); -void VSUBAy(); -void VSUBAz(); -void VSUBAw(); -void VMADDAx(); -void VMADDAy(); -void VMADDAz(); -void VMADDAw(); -void VMSUBAx(); -void VMSUBAy(); -void VMSUBAz(); -void VMSUBAw(); -void VITOF0(); -void VITOF4(); -void VITOF12(); -void VITOF15(); -void VFTOI0(); -void VFTOI4(); -void VFTOI12(); -void VFTOI15(); -void VMULAx(); -void VMULAy(); -void VMULAz(); -void VMULAw(); -void VMULAq(); -void VABS(); -void VMULAi(); -void VCLIPw(); -void VADDAq(); -void VMADDAq(); -void VADDAi(); -void VMADDAi(); -void VSUBAq(); -void VMSUBAq(); -void VSUBAi(); -void VMSUBAi(); -void VADDA(); -void VMADDA(); -void VMULA(); -void VSUBA(); -void VMSUBA(); -void VOPMULA(); -void VNOP(); -void VMOVE(); -void VMR32(); -void VLQI(); -void VSQI(); -void VLQD(); -void VSQD(); -void VDIV(); -void VSQRT(); -void VRSQRT(); -void VWAITQ(); -void VMTIR(); -void VMFIR(); -void VILWR(); -void VISWR(); -void VRNEXT(); -void VRGET(); -void VRINIT(); -void VRXOR(); -//*******************END OF SPECIAL2 ********************* - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef _R5900_OPCODETABLES_H +#define _R5900_OPCODETABLES_H + +#include + +#include "PS2Etypes.h" + +// TODO : Move these into the OpcodeTables namespace +extern void (*Int_COP2PrintTable[32])(); +extern void (*Int_COP2BC2PrintTable[32])(); +extern void (*Int_COP2SPECIAL1PrintTable[64])(); +extern void (*Int_COP2SPECIAL2PrintTable[128])(); + +void COP2_BC2(); +void COP2_SPECIAL(); +void COP2_SPECIAL2(); +void COP2_Unknown(); + + +namespace R5900 +{ + namespace Dynarec { + namespace OpcodeImpl + { + void recNULL(); + void recUnknown(); + void recMMI_Unknown(); + void recCOP0_Unknown(); + void recCOP1_Unknown(); + + void recCOP2(); + + void recCACHE(); + void recPREF(); + void recSYSCALL(); + void recBREAK(); + void recSYNC(); + + void recMFSA(); + void recMTSA(); + void recMTSAB(); + void recMTSAH(); + + void recTGE(); + void recTGEU(); + void recTLT(); + void recTLTU(); + void recTEQ(); + void recTNE(); + void recTGEI(); + void recTGEIU(); + void recTLTI(); + void recTLTIU(); + void recTEQI(); + void recTNEI(); + + } } + + /////////////////////////////////////////////////////////////////////////// + // Encapsulates information about every opcode on the Emotion Engine and + // it's many co-processors. + struct OPCODE + { + // Textual name of the instruction. + const char Name[16]; + + // Number of cycles this instruction normally uses. + u8 cycles; + + const OPCODE& (*getsubclass)(); + + // Process the instruction using the interpreter. + // The action is performed immediately on the EE's cpu state. + void (*interpret)(); + + // Generate recompiled code for this instruction, injected into + // the current EErec block state. + void (*recompile)(); + + // Generates a string representation of the instruction and it's parameters, + // and pastes it into the given output parameter. + void (*disasm)( std::string& output ); + }; + + // Returns the current real instruction, as per the current cpuRegs settings. + const OPCODE& GetCurrentInstruction(); + + namespace OpcodeTables + { + using ::R5900::OPCODE; + + extern const OPCODE tbl_Standard[64]; + + /*extern const OPCODE Standard[64]; + extern const OPCODE Special[64]; + extern const OPCODE RegImm[32]; + extern const OPCODE MMI[64]; + extern const OPCODE MMI0[32]; + extern const OPCODE MMI1[32]; + extern const OPCODE MMI2[32]; + extern const OPCODE MMI3[32]; + + extern const OPCODE COP0[32]; + extern const OPCODE COP0_BC0[32]; + extern const OPCODE COP0_C0[64]; + + extern const OPCODE COP1[32]; + extern const OPCODE COP1_BC1[32]; + extern const OPCODE COP1_S[64]; + extern const OPCODE COP1_W[64];*/ + } + + namespace Opcodes + { + using ::R5900::OPCODE; + + const OPCODE& Class_SPECIAL(); + const OPCODE& Class_REGIMM(); + const OPCODE& Class_MMI(); + const OPCODE& Class_MMI0(); + const OPCODE& Class_MMI1(); + const OPCODE& Class_MMI2(); + const OPCODE& Class_MMI3(); + + const OPCODE& Class_COP0(); + const OPCODE& Class_COP0_BC0(); + const OPCODE& Class_COP0_C0(); + + const OPCODE& Class_COP1(); + const OPCODE& Class_COP1_BC1(); + const OPCODE& Class_COP1_S(); + const OPCODE& Class_COP1_W(); + } + + namespace OpcodeDisasm + { +//**************************************************************** + void Unknown( std::string& output ); + void COP0_Unknown( std::string& output ); + void COP1_Unknown( std::string& output ); + void MMI_Unknown( std::string& output ); + + void COP2( std::string& output ); + +// **********************Standard Opcodes************************** + void J( std::string& output ); + void JAL( std::string& output ); + void BEQ( std::string& output ); + void BNE( std::string& output ); + void BLEZ( std::string& output ); + void BGTZ( std::string& output ); + void ADDI( std::string& output ); + void ADDIU( std::string& output ); + void SLTI( std::string& output ); + void SLTIU( std::string& output ); + void ANDI( std::string& output ); + void ORI( std::string& output ); + void XORI( std::string& output ); + void LUI( std::string& output ); + void BEQL( std::string& output ); + void BNEL( std::string& output ); + void BLEZL( std::string& output ); + void BGTZL( std::string& output ); + void DADDI( std::string& output ); + void DADDIU( std::string& output ); + void LDL( std::string& output ); + void LDR( std::string& output ); + void LB( std::string& output ); + void LH( std::string& output ); + void LWL( std::string& output ); + void LW( std::string& output ); + void LBU( std::string& output ); + void LHU( std::string& output ); + void LWR( std::string& output ); + void LWU( std::string& output ); + void SB( std::string& output ); + void SH( std::string& output ); + void SWL( std::string& output ); + void SW( std::string& output ); + void SDL( std::string& output ); + void SDR( std::string& output ); + void SWR( std::string& output ); + void CACHE( std::string& output ); + void LWC1( std::string& output ); + void PREF( std::string& output ); + void LQC2( std::string& output ); + void LD( std::string& output ); + void SQC2( std::string& output ); + void SD( std::string& output ); + void LQ( std::string& output ); + void SQ( std::string& output ); + void SWC1( std::string& output ); +//*****************end of standard opcodes********************** +//********************SPECIAL OPCODES*************************** + void SLL( std::string& output ); + void SRL( std::string& output ); + void SRA( std::string& output ); + void SLLV( std::string& output ); + void SRLV( std::string& output ); + void SRAV( std::string& output ); + void JR( std::string& output ); + void JALR( std::string& output ); + void SYSCALL( std::string& output ); + void BREAK( std::string& output ); + void SYNC( std::string& output ); + void MFHI( std::string& output ); + void MTHI( std::string& output ); + void MFLO( std::string& output ); + void MTLO( std::string& output ); + void DSLLV( std::string& output ); + void DSRLV( std::string& output ); + void DSRAV( std::string& output ); + void MULT( std::string& output ); + void MULTU( std::string& output ); + void DIV( std::string& output ); + void DIVU( std::string& output ); + void ADD( std::string& output ); + void ADDU( std::string& output ); + void SUB( std::string& output ); + void SUBU( std::string& output ); + void AND( std::string& output ); + void OR( std::string& output ); + void XOR( std::string& output ); + void NOR( std::string& output ); + void SLT( std::string& output ); + void SLTU( std::string& output ); + void DADD( std::string& output ); + void DADDU( std::string& output ); + void DSUB( std::string& output ); + void DSUBU( std::string& output ); + void TGE( std::string& output ); + void TGEU( std::string& output ); + void TLT( std::string& output ); + void TLTU( std::string& output ); + void TEQ( std::string& output ); + void TNE( std::string& output ); + void DSLL( std::string& output ); + void DSRL( std::string& output ); + void DSRA( std::string& output ); + void DSLL32( std::string& output ); + void DSRL32( std::string& output ); + void DSRA32( std::string& output ); + void MOVZ( std::string& output ); + void MOVN( std::string& output ); + void MFSA( std::string& output ); + void MTSA( std::string& output ); +//*******************END OF SPECIAL OPCODES************************ +//***********************REGIMM OPCODES**************************** + void BLTZ( std::string& output ); + void BGEZ( std::string& output ); + void BLTZL( std::string& output ); + void BGEZL( std::string& output ); + void TGEI( std::string& output ); + void TGEIU( std::string& output ); + void TLTI( std::string& output ); + void TLTIU( std::string& output ); + void TEQI( std::string& output ); + void TNEI( std::string& output ); + void BLTZAL( std::string& output ); + void BGEZAL( std::string& output ); + void BLTZALL( std::string& output ); + void BGEZALL( std::string& output ); + void MTSAB( std::string& output ); + void MTSAH( std::string& output ); +//*******************END OF REGIMM OPCODES*********************** +//***********************MMI OPCODES***************************** + void MADD( std::string& output ); + void MADDU( std::string& output ); + void PLZCW( std::string& output ); + void MADD1( std::string& output ); + void MADDU1( std::string& output ); + void MFHI1( std::string& output ); + void MTHI1( std::string& output ); + void MFLO1( std::string& output ); + void MTLO1( std::string& output ); + void MULT1( std::string& output ); + void MULTU1( std::string& output ); + void DIV1( std::string& output ); + void DIVU1( std::string& output ); + void PMFHL( std::string& output ); + void PMTHL( std::string& output ); + void PSLLH( std::string& output ); + void PSRLH( std::string& output ); + void PSRAH( std::string& output ); + void PSLLW( std::string& output ); + void PSRLW( std::string& output ); + void PSRAW( std::string& output ); +//********************END OF MMI OPCODES*********************** +//***********************MMI0 OPCODES************************** + void PADDW( std::string& output ); + void PSUBW( std::string& output ); + void PCGTW( std::string& output ); + void PMAXW( std::string& output ); + void PADDH( std::string& output ); + void PSUBH( std::string& output ); + void PCGTH( std::string& output ); + void PMAXH( std::string& output ); + void PADDB( std::string& output ); + void PSUBB( std::string& output ); + void PCGTB( std::string& output ); + void PADDSW( std::string& output ); + void PSUBSW( std::string& output ); + void PEXTLW( std::string& output ); + void PPACW( std::string& output ); + void PADDSH( std::string& output ); + void PSUBSH( std::string& output ); + void PEXTLH( std::string& output ); + void PPACH( std::string& output ); + void PADDSB( std::string& output ); + void PSUBSB( std::string& output ); + void PEXTLB( std::string& output ); + void PPACB( std::string& output ); + void PEXT5( std::string& output ); + void PPAC5( std::string& output ); +//******************END OF MMI0 OPCODES*********************** +//*********************MMI1 OPCODES*************************** + void PABSW( std::string& output ); + void PCEQW( std::string& output ); + void PMINW( std::string& output ); + void PADSBH( std::string& output ); + void PABSH( std::string& output ); + void PCEQH( std::string& output ); + void PMINH( std::string& output ); + void PCEQB( std::string& output ); + void PADDUW( std::string& output ); + void PSUBUW( std::string& output ); + void PEXTUW( std::string& output ); + void PADDUH( std::string& output ); + void PSUBUH( std::string& output ); + void PEXTUH( std::string& output ); + void PADDUB( std::string& output ); + void PSUBUB( std::string& output ); + void PEXTUB( std::string& output ); + void QFSRV( std::string& output ); +//*****************END OF MMI1 OPCODES*********************** +//*********************MMI2 OPCODES************************** + void PMADDW( std::string& output ); + void PSLLVW( std::string& output ); + void PSRLVW( std::string& output ); + void PMSUBW( std::string& output ); + void PMFHI( std::string& output ); + void PMFLO( std::string& output ); + void PINTH( std::string& output ); + void PMULTW( std::string& output ); + void PDIVW( std::string& output ); + void PCPYLD( std::string& output ); + void PMADDH( std::string& output ); + void PHMADH( std::string& output ); + void PAND( std::string& output ); + void PXOR( std::string& output ); + void PMSUBH( std::string& output ); + void PHMSBH( std::string& output ); + void PEXEH( std::string& output ); + void PREVH( std::string& output ); + void PMULTH( std::string& output ); + void PDIVBW( std::string& output ); + void PEXEW( std::string& output ); + void PROT3W( std::string& output ); +//********************END OF MMI2 OPCODES******************** +//***********************MMI3 OPCODES************************ + void PMADDUW( std::string& output ); + void PSRAVW( std::string& output ); + void PMTHI( std::string& output ); + void PMTLO( std::string& output ); + void PINTEH( std::string& output ); + void PMULTUW( std::string& output ); + void PDIVUW( std::string& output ); + void PCPYUD( std::string& output ); + void POR( std::string& output ); + void PNOR( std::string& output ); + void PEXCH( std::string& output ); + void PCPYH( std::string& output ); + void PEXCW( std::string& output ); +//*********************END OF MMI3 OPCODES******************* +//************************COP0 OPCODES*********************** + void MFC0( std::string& output ); + void MTC0( std::string& output ); + void BC0F( std::string& output ); + void BC0T( std::string& output ); + void BC0FL( std::string& output ); + void BC0TL( std::string& output ); + void TLBR( std::string& output ); + void TLBWI( std::string& output ); + void TLBWR( std::string& output ); + void TLBP( std::string& output ); + void ERET( std::string& output ); + void DI( std::string& output ); + void EI( std::string& output ); +//***********************END OF COP0************************* +//**************COP1 - Floating Point Unit (FPU)************* + void MFC1( std::string& output ); + void CFC1( std::string& output ); + void MTC1( std::string& output ); + void CTC1( std::string& output ); + void BC1F( std::string& output ); + void BC1T( std::string& output ); + void BC1FL( std::string& output ); + void BC1TL( std::string& output ); + void ADD_S( std::string& output ); + void SUB_S( std::string& output ); + void MUL_S( std::string& output ); + void DIV_S( std::string& output ); + void SQRT_S( std::string& output ); + void ABS_S( std::string& output ); + void MOV_S( std::string& output ); + void NEG_S( std::string& output ); + void RSQRT_S( std::string& output ); + void ADDA_S( std::string& output ); + void SUBA_S( std::string& output ); + void MULA_S( std::string& output ); + void MADD_S( std::string& output ); + void MSUB_S( std::string& output ); + void MADDA_S( std::string& output ); + void MSUBA_S( std::string& output ); + void CVT_W( std::string& output ); + void MAX_S( std::string& output ); + void MIN_S( std::string& output ); + void C_F( std::string& output ); + void C_EQ( std::string& output ); + void C_LT( std::string& output ); + void C_LE( std::string& output ); + void CVT_S( std::string& output ); +//**********************END OF COP1*********************** + } + + namespace Interpreter { + namespace OpcodeImpl + { + using namespace ::R5900; + + void COP2(); + + void Unknown(); + void MMI_Unknown(); + void COP0_Unknown(); + void COP1_Unknown(); + +// **********************Standard Opcodes************************** + void J(); + void JAL(); + void BEQ(); + void BNE(); + void BLEZ(); + void BGTZ(); + void ADDI(); + void ADDIU(); + void SLTI(); + void SLTIU(); + void ANDI(); + void ORI(); + void XORI(); + void LUI(); + void BEQL(); + void BNEL(); + void BLEZL(); + void BGTZL(); + void DADDI(); + void DADDIU(); + void LDL(); + void LDR(); + void LB(); + void LH(); + void LWL(); + void LW(); + void LBU(); + void LHU(); + void LWR(); + void LWU(); + void SB(); + void SH(); + void SWL(); + void SW(); + void SDL(); + void SDR(); + void SWR(); + void CACHE(); + void LWC1(); + void PREF(); + void LQC2(); + void LD(); + void SQC2(); + void SD(); + void LQ(); + void SQ(); + void SWC1(); +//*****************end of standard opcodes********************** +//********************SPECIAL OPCODES*************************** + void SLL(); + void SRL(); + void SRA(); + void SLLV(); + void SRLV(); + void SRAV(); + void JR(); + void JALR(); + void SYSCALL(); + void BREAK(); + void SYNC(); + void MFHI(); + void MTHI(); + void MFLO(); + void MTLO(); + void DSLLV(); + void DSRLV(); + void DSRAV(); + void MULT(); + void MULTU(); + void DIV(); + void DIVU(); + void ADD(); + void ADDU(); + void SUB(); + void SUBU(); + void AND(); + void OR(); + void XOR(); + void NOR(); + void SLT(); + void SLTU(); + void DADD(); + void DADDU(); + void DSUB(); + void DSUBU(); + void TGE(); + void TGEU(); + void TLT(); + void TLTU(); + void TEQ(); + void TNE(); + void DSLL(); + void DSRL(); + void DSRA(); + void DSLL32(); + void DSRL32(); + void DSRA32(); + void MOVZ(); + void MOVN(); + void MFSA(); + void MTSA(); +//*******************END OF SPECIAL OPCODES************************ +//***********************REGIMM OPCODES**************************** + void BLTZ(); + void BGEZ(); + void BLTZL(); + void BGEZL(); + void TGEI(); + void TGEIU(); + void TLTI(); + void TLTIU(); + void TEQI(); + void TNEI(); + void BLTZAL(); + void BGEZAL(); + void BLTZALL(); + void BGEZALL(); + void MTSAB(); + void MTSAH(); +//*******************END OF REGIMM OPCODES*********************** +//***********************MMI OPCODES***************************** + void MADD(); + void MADDU(); + void MADD1(); + void MADDU1(); + void MFHI1(); + void MTHI1(); + void MFLO1(); + void MTLO1(); + void MULT1(); + void MULTU1(); + void DIV1(); + void DIVU1(); + + namespace MMI { + void PLZCW(); + void PMFHL(); + void PMTHL(); + void PSLLH(); + void PSRLH(); + void PSRAH(); + void PSLLW(); + void PSRLW(); + void PSRAW(); +//********************END OF MMI OPCODES*********************** +//***********************MMI0 OPCODES************************** + void PADDW(); + void PSUBW(); + void PCGTW(); + void PMAXW(); + void PADDH(); + void PSUBH(); + void PCGTH(); + void PMAXH(); + void PADDB(); + void PSUBB(); + void PCGTB(); + void PADDSW(); + void PSUBSW(); + void PEXTLW(); + void PPACW(); + void PADDSH(); + void PSUBSH(); + void PEXTLH(); + void PPACH(); + void PADDSB(); + void PSUBSB(); + void PEXTLB(); + void PPACB(); + void PEXT5(); + void PPAC5(); +//******************END OF MMI0 OPCODES*********************** +//*********************MMI1 OPCODES*************************** + void PABSW(); + void PCEQW(); + void PMINW(); + void PADSBH(); + void PABSH(); + void PCEQH(); + void PMINH(); + void PCEQB(); + void PADDUW(); + void PSUBUW(); + void PEXTUW(); + void PADDUH(); + void PSUBUH(); + void PEXTUH(); + void PADDUB(); + void PSUBUB(); + void PEXTUB(); + void QFSRV(); +//*****************END OF MMI1 OPCODES*********************** +//*********************MMI2 OPCODES************************** + void PMADDW(); + void PSLLVW(); + void PSRLVW(); + void PMSUBW(); + void PMFHI(); + void PMFLO(); + void PINTH(); + void PMULTW(); + void PDIVW(); + void PCPYLD(); + void PMADDH(); + void PHMADH(); + void PAND(); + void PXOR(); + void PMSUBH(); + void PHMSBH(); + void PEXEH(); + void PREVH(); + void PMULTH(); + void PDIVBW(); + void PEXEW(); + void PROT3W(); +//********************END OF MMI2 OPCODES******************** +//***********************MMI3 OPCODES************************ + void PMADDUW(); + void PSRAVW(); + void PMTHI(); + void PMTLO(); + void PINTEH(); + void PMULTUW(); + void PDIVUW(); + void PCPYUD(); + void POR(); + void PNOR(); + void PEXCH(); + void PCPYH(); + void PEXCW(); + } +//**********************END OF MMI3 OPCODES******************** +//*************************COP0 OPCODES************************ + namespace COP0 { + void MFC0(); + void MTC0(); + void BC0F(); + void BC0T(); + void BC0FL(); + void BC0TL(); + void TLBR(); + void TLBWI(); + void TLBWR(); + void TLBP(); + void ERET(); + void DI(); + void EI(); + } +//********************END OF COP0 OPCODES************************ +//************COP1 OPCODES - Floating Point Unit***************** + namespace COP1 { + void MFC1(); + void CFC1(); + void MTC1(); + void CTC1(); + void BC1F(); + void BC1T(); + void BC1FL(); + void BC1TL(); + void ADD_S(); + void SUB_S(); + void MUL_S(); + void DIV_S(); + void SQRT_S(); + void ABS_S(); + void MOV_S(); + void NEG_S(); + void RSQRT_S(); + void ADDA_S(); + void SUBA_S(); + void MULA_S(); + void MADD_S(); + void MSUB_S(); + void MADDA_S(); + void MSUBA_S(); + void CVT_W(); + void MAX_S(); + void MIN_S(); + void C_F(); + void C_EQ(); + void C_LT(); + void C_LE(); + void CVT_S(); + } + } } +} // End namespace R5900 + +//**************************************************************************** +//** COP2 - (VU0) ** +//**************************************************************************** +void QMFC2(); +void CFC2(); +void QMTC2(); +void CTC2(); +void BC2F(); +void BC2T(); +void BC2FL(); +void BC2TL(); +//*****************SPECIAL 1 VUO TABLE******************************* +void VADDx(); +void VADDy(); +void VADDz(); +void VADDw(); +void VSUBx(); +void VSUBy(); +void VSUBz(); +void VSUBw(); +void VMADDx(); +void VMADDy(); +void VMADDz(); +void VMADDw(); +void VMSUBx(); +void VMSUBy(); +void VMSUBz(); +void VMSUBw(); +void VMAXx(); +void VMAXy(); +void VMAXz(); +void VMAXw(); +void VMINIx(); +void VMINIy(); +void VMINIz(); +void VMINIw(); +void VMULx(); +void VMULy(); +void VMULz(); +void VMULw(); +void VMULq(); +void VMAXi(); +void VMULi(); +void VMINIi(); +void VADDq(); +void VMADDq(); +void VADDi(); +void VMADDi(); +void VSUBq(); +void VMSUBq(); +void VSUBi(); +void VMSUBi(); +void VADD(); +void VMADD(); +void VMUL(); +void VMAX(); +void VSUB(); +void VMSUB(); +void VOPMSUB(); +void VMINI(); +void VIADD(); +void VISUB(); +void VIADDI(); +void VIAND(); +void VIOR(); +void VCALLMS(); +void VCALLMSR(); +//***********************************END OF SPECIAL1 VU0 TABLE***************************** +//******************************SPECIAL2 VUO TABLE***************************************** +void VADDAx(); +void VADDAy(); +void VADDAz(); +void VADDAw(); +void VSUBAx(); +void VSUBAy(); +void VSUBAz(); +void VSUBAw(); +void VMADDAx(); +void VMADDAy(); +void VMADDAz(); +void VMADDAw(); +void VMSUBAx(); +void VMSUBAy(); +void VMSUBAz(); +void VMSUBAw(); +void VITOF0(); +void VITOF4(); +void VITOF12(); +void VITOF15(); +void VFTOI0(); +void VFTOI4(); +void VFTOI12(); +void VFTOI15(); +void VMULAx(); +void VMULAy(); +void VMULAz(); +void VMULAw(); +void VMULAq(); +void VABS(); +void VMULAi(); +void VCLIPw(); +void VADDAq(); +void VMADDAq(); +void VADDAi(); +void VMADDAi(); +void VSUBAq(); +void VMSUBAq(); +void VSUBAi(); +void VMSUBAi(); +void VADDA(); +void VMADDA(); +void VMULA(); +void VSUBA(); +void VMSUBA(); +void VOPMULA(); +void VNOP(); +void VMOVE(); +void VMR32(); +void VLQI(); +void VSQI(); +void VLQD(); +void VSQD(); +void VDIV(); +void VSQRT(); +void VRSQRT(); +void VWAITQ(); +void VMTIR(); +void VMFIR(); +void VILWR(); +void VISWR(); +void VRNEXT(); +void VRGET(); +void VRINIT(); +void VRXOR(); +//*******************END OF SPECIAL2 ********************* + +#endif diff --git a/pcsx2/RDebug/deci2.cpp b/pcsx2/RDebug/deci2.cpp index 43f061f272..ea686864b8 100644 --- a/pcsx2/RDebug/deci2.cpp +++ b/pcsx2/RDebug/deci2.cpp @@ -1,28 +1,28 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "deci2.h" - -void exchangeSD(DECI2_HEADER *h){ - u8 tmp =h->source; - h->source =h->destination; - h->destination =tmp; -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "deci2.h" + +void exchangeSD(DECI2_HEADER *h){ + u8 tmp =h->source; + h->source =h->destination; + h->destination =tmp; +} diff --git a/pcsx2/RDebug/deci2.h b/pcsx2/RDebug/deci2.h index 2c1562d38b..afa212536c 100644 --- a/pcsx2/RDebug/deci2.h +++ b/pcsx2/RDebug/deci2.h @@ -1,71 +1,71 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __DECI2_H__ -#define __DECI2_H__ - -#include "Common.h" -#include "deci2_dcmp.h" -#include "deci2_iloadp.h" -#include "deci2_dbgp.h" -#include "deci2_netmp.h" -#include "deci2_ttyp.h" - -#define PROTO_DCMP 0x0001 -#define PROTO_ITTYP 0x0110 -#define PROTO_IDBGP 0x0130 -#define PROTO_ILOADP 0x0150 -#define PROTO_ETTYP 0x0220 -#define PROTO_EDBGP 0x0230 -#define PROTO_NETMP 0x0400 - - -#pragma pack(1) -struct DECI2_HEADER { - u16 length, //+00 - _pad, //+02 - protocol; //+04 - char source, //+06 - destination;//+07 -}; //=08 - -struct DECI2_DBGP_BRK{ - u32 address, //+00 - count; //+04 -}; //=08 -#pragma pack() - -#define STOP 0 -#define RUN 1 - -extern DECI2_DBGP_BRK ebrk[32], ibrk[32]; -extern int ebrk_count, ibrk_count; -extern volatile long runStatus; -extern int runCode, runCount; - -#ifdef _WIN32 -extern HANDLE runEvent; //i don't like this; -#endif - -extern int connected; - //when add linux code this might change - -int writeData(const u8 *result); -void exchangeSD(DECI2_HEADER *h); - -#endif//__DECI2_H__ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __DECI2_H__ +#define __DECI2_H__ + +#include "Common.h" +#include "deci2_dcmp.h" +#include "deci2_iloadp.h" +#include "deci2_dbgp.h" +#include "deci2_netmp.h" +#include "deci2_ttyp.h" + +#define PROTO_DCMP 0x0001 +#define PROTO_ITTYP 0x0110 +#define PROTO_IDBGP 0x0130 +#define PROTO_ILOADP 0x0150 +#define PROTO_ETTYP 0x0220 +#define PROTO_EDBGP 0x0230 +#define PROTO_NETMP 0x0400 + + +#pragma pack(1) +struct DECI2_HEADER { + u16 length, //+00 + _pad, //+02 + protocol; //+04 + char source, //+06 + destination;//+07 +}; //=08 + +struct DECI2_DBGP_BRK{ + u32 address, //+00 + count; //+04 +}; //=08 +#pragma pack() + +#define STOP 0 +#define RUN 1 + +extern DECI2_DBGP_BRK ebrk[32], ibrk[32]; +extern int ebrk_count, ibrk_count; +extern volatile long runStatus; +extern int runCode, runCount; + +#ifdef _WIN32 +extern HANDLE runEvent; //i don't like this; +#endif + +extern int connected; + //when add linux code this might change + +int writeData(const u8 *result); +void exchangeSD(DECI2_HEADER *h); + +#endif//__DECI2_H__ diff --git a/pcsx2/RDebug/deci2_dbgp.cpp b/pcsx2/RDebug/deci2_dbgp.cpp index 0267aabe5c..5168b414fe 100644 --- a/pcsx2/RDebug/deci2_dbgp.cpp +++ b/pcsx2/RDebug/deci2_dbgp.cpp @@ -1,434 +1,434 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "PsxCommon.h" -#include "VUmicro.h" -#include "deci2.h" - -#include "Threading.h" -using namespace Threading; - -using namespace R5900; - -struct DECI2_DBGP_HEADER{ - DECI2_HEADER h; //+00 - u16 id; //+08 - u8 type, //+0A - code, //+0B - result, //+0C - count; //+0D - u16 _pad; //+0E -}; //=10 - -struct DECI2_DBGP_CONF{ - u32 major_ver, //+00 - minor_ver, //+04 - target_id, //+08 - _pad, //+0C - mem_align, //+10 - _pad2, //+14 - reg_size, //+18 - nreg, //+1C - nbrkpt, //+20 - ncont, //+24 - nstep, //+28 - nnext, //+2C - mem_limit_align, //+30 - mem_limit_size, //+34 - run_stop_state, //+38 - hdbg_area_addr, //+3C - hdbg_area_size; //+40 -}; //=44 - -DECI2_DBGP_CONF -cpu={3, 0, PROTO_EDBGP, 0, 0x41F, 1, 7, 32, 32, 1, 0xFF, 0xFF, 0x1F, 0x400, 2, 0x80020c70, 0x100}, -vu0={3, 0, PROTO_EDBGP, 0, 0x41F, 1, 7, 32, 32, 1, 0xFF, 0xFF, 0x1F, 0x400, 2, 0x80020c70, 0x100}, -vu1={3, 0, PROTO_EDBGP, 0, 0x41F, 1, 7, 32, 32, 1, 0xFF, 0xFF, 0x1F, 0x400, 2, 0x80020c70, 0x100}, -iop={3, 0, PROTO_IDBGP, 0, 0x00F, 1, 5, 62, 32, 1, 0x00, 0x00, 0x07, 0x200, 1, 0x0001E670, 0x100}; -//iop={3, 0, PROTO_IDBGP, 0, 0x00F, 1, 5, 62, 0, 1, 0x00, 0x00, 0x07, 0x200, 0, 0x00006940, 0x100}; - -#pragma pack(2) -struct DECI2_DBGP_EREG{ - u8 kind, //+00 - number; //+01 - u16 _pad; //+02 - u64 value[2]; //+04 -}; //=14 - -struct DECI2_DBGP_IREG{ - u8 kind, //+00 - number; //+01 - u16 _pad; //+02 - u32 value; //+04 -}; //=08 - -struct DECI2_DBGP_MEM{ - u8 space, //+00 - align; //+01 - u16 _pad; //+02 - u32 address; //+04 - u32 length; //+08 -}; //=0C - -struct DECI2_DBGP_RUN{ - u32 entry, //+00 - gp, //+04 - _pad, //+08 - _pad1, //+0C - argc; //+10 - //u32 argv; //+14 -}; //=18 -#pragma pack() - -void D2_DBGP(const u8 *inbuffer, u8 *outbuffer, char *message, char *eepc, char *ioppc, char *eecy, char *iopcy){ - const DECI2_DBGP_HEADER *in=(DECI2_DBGP_HEADER*)inbuffer; - DECI2_DBGP_HEADER* out=(DECI2_DBGP_HEADER*)outbuffer; - - DECI2_DBGP_EREG *eregs=(DECI2_DBGP_EREG*)&out[1]; - DECI2_DBGP_IREG *iregs=(DECI2_DBGP_IREG*)&out[1]; - DECI2_DBGP_MEM *mem =(DECI2_DBGP_MEM*) &out[1]; - const DECI2_DBGP_RUN*run =(DECI2_DBGP_RUN*) &in[1]; - - static char line[1024]; - int i, s; - - memcpy(outbuffer, inbuffer, 128*1024);//BUFFERSIZE - //out->h.length=sizeof(DECI2_DBGP_HEADER); - out->type++; - out->result=0; //ok - exchangeSD((DECI2_HEADER*)out); - switch(in->type){ - case 0x00://ok - sprintf(line, "%s/GETCONF", in->id==0?"CPU":in->id==1?"VU0":"VU1"); - - if (in->h.destination=='I'){ - memcpy(&out[1], &iop, sizeof(DECI2_DBGP_CONF)); - }else - switch(in->id){ - case 0:memcpy(&out[1], &cpu, sizeof(DECI2_DBGP_CONF));break; - case 1:memcpy(&out[1], &vu0, sizeof(DECI2_DBGP_CONF));break; - case 2:memcpy(&out[1], &vu1, sizeof(DECI2_DBGP_CONF));break; - } - break; - case 0x02://ok - sprintf(line, "%s/2", in->id==0?"CPU":in->id==1?"VU0":"VU1"); - break; - case 0x04://ok - sprintf(line, "%s/GETREG count=%d kind[0]=%d number[0]=%d", - in->id==0?"CPU":in->id==1?"VU0":"VU1", in->count, eregs[0].kind, eregs[0].number); - if (in->h.destination=='I'){ - for (i=0; icount; i++) - switch (iregs[i].kind){ - case 1:switch (iregs[i].number){ - case 0:iregs[i].value=psxRegs.GPR.n.lo;break; - case 1:iregs[i].value=psxRegs.GPR.n.hi;break; - } - break; - case 2:iregs[i].value=psxRegs.GPR.r[iregs[i].number]; break; - case 3: - if (iregs[i].number==14) psxRegs.CP0.n.EPC=psxRegs.pc; - iregs[i].value=psxRegs.CP0.r[iregs[i].number]; - break; - case 6:iregs[i].value=psxRegs.CP2D.r[iregs[i].number]; break; - case 7:iregs[i].value=psxRegs.CP2C.r[iregs[i].number]; break; - default: - iregs[0].value++;//dummy; might be assert(0) - } - }else - for (i=0; icount; i++) - switch (eregs[i].kind){ - case 0:memcpy(eregs[i].value, &cpuRegs.GPR.r[eregs[i].number], 16);break; - case 1: - switch(eregs[i].number){ - case 0:memcpy(eregs[i].value, &cpuRegs.HI.UD[0], 8);break; - case 1:memcpy(eregs[i].value, &cpuRegs.LO.UD[0], 8);break; - case 2:memcpy(eregs[i].value, &cpuRegs.HI.UD[1], 8);break; - case 3:memcpy(eregs[i].value, &cpuRegs.LO.UD[1], 8);break; - case 4:memcpy(eregs[i].value, &cpuRegs.sa, 4); break; - } - case 2: - if (eregs[i].number==14) cpuRegs.CP0.n.EPC=cpuRegs.pc; - memcpy(eregs[i].value, &cpuRegs.CP0.r[eregs[i].number], 4); - break; - case 3:break;//performance counter 32x3 - case 4:break;//hw debug reg 32x8 - case 5:memcpy(eregs[i].value, &fpuRegs.fpr[eregs[i].number], 4);break; - case 6:memcpy(eregs[i].value, &fpuRegs.fprc[eregs[i].number], 4);break; - case 7:memcpy(eregs[i].value, &VU0.VF[eregs[i].number], 16);break; - case 8:memcpy(eregs[i].value, &VU0.VI[eregs[i].number], 4);break; - case 9:memcpy(eregs[i].value, &VU1.VF[eregs[i].number], 16);break; - case 10:memcpy(eregs[i].value, &VU1.VI[eregs[i].number], 4);break; - default: - eregs[0].value[0]++;//dummy; might be assert(0) - } - break; - case 0x06://ok - sprintf(line, "%s/PUTREG count=%d kind[0]=%d number[0]=%d value=%016I64X_%016I64X", - in->id==0?"CPU":in->id==1?"VU0":"VU1", in->count, eregs[0].kind, eregs[0].number, eregs[0].value[1], eregs[0].value[0]); - if (in->h.destination=='I'){ - for (i=0; icount; i++) - switch (iregs[i].kind){ - case 1:switch (iregs[i].number){ - case 0:psxRegs.GPR.n.lo=iregs[i].value;break; - case 1:psxRegs.GPR.n.hi=iregs[i].value;break; - } - break; - case 2:psxRegs.GPR.r[iregs[i].number]=iregs[i].value; break; - case 3: - psxRegs.CP0.r[iregs[i].number]=iregs[i].value; - if (iregs[i].number==14) psxRegs.pc=psxRegs.CP0.n.EPC; - break; - case 6:psxRegs.CP2D.r[iregs[i].number]=iregs[i].value; break; - case 7:psxRegs.CP2C.r[iregs[i].number]=iregs[i].value; break; - default: - ;//dummy; might be assert(0) - } - }else - for (i=0; icount; i++) - switch (eregs[i].kind){ - case 0:memcpy(&cpuRegs.GPR.r[eregs[i].number], eregs[i].value, 16);break; - case 1: - switch(eregs[i].number){ - case 0:memcpy(&cpuRegs.HI.UD[0], eregs[i].value, 8);break; - case 1:memcpy(&cpuRegs.LO.UD[0], eregs[i].value, 8);break; - case 2:memcpy(&cpuRegs.HI.UD[1], eregs[i].value, 8);break; - case 3:memcpy(&cpuRegs.LO.UD[1], eregs[i].value, 8);break; - case 4:memcpy(&cpuRegs.sa, eregs[i].value, 4); break; - } - break; - case 2: - memcpy(&cpuRegs.CP0.r[eregs[i].number], eregs[i].value, 4); - if (eregs[i].number==14) cpuRegs.pc=cpuRegs.CP0.n.EPC; - break; - case 3:break;//performance counter 32x3 - case 4:break;//hw debug reg 32x8 - case 5:memcpy(&fpuRegs.fpr[eregs[i].number], eregs[i].value, 4);break; - case 6:memcpy(&fpuRegs.fprc[eregs[i].number], eregs[i].value, 4);break; - case 7:memcpy(&VU0.VF[eregs[i].number], eregs[i].value, 16);break; - case 8:memcpy(&VU0.VI[eregs[i].number], eregs[i].value, 4);break; - case 9:memcpy(&VU1.VF[eregs[i].number], eregs[i].value, 16);break; - case 10:memcpy(&VU1.VI[eregs[i].number], eregs[i].value, 4);break; - default: - ;//dummy; might be assert(0) - } - break; - case 0x08://ok - { - sprintf(line, "%s/RDMEM %08X/%X", - in->id==0?"CPU":in->id==1?"VU0":"VU1", mem->address, mem->length); - u8* data =(u8*)out+ //kids: don't try this at home! :D - ((sizeof(DECI2_DBGP_HEADER)+sizeof(DECI2_DBGP_MEM)+(1 << mem->align) - 1) & (0xFFFFFFFF << mem->align)); - - if ((mem->address & ((1 << mem->align)-1)) || - (mem->length & ((1 << mem->align)-1))){ - out->result=1; - strcat(line, " ALIGN ERROR"); - break; - } - if (in->h.destination=='I') - if (PSXM(mem->address & 0x1FFFFFFF)) - memcpy(data, PSXM(mem->address & 0x1FFFFFFF), mem->length); - else{ - out->result=0x11; - strcat(line, " ADDRESS ERROR"); - break; - } - else - { - switch(mem->space){ - case 0: - if ((mem->address & 0xF0000000) == 0x70000000) - memcpy(data, PSM(mem->address), mem->length); - else - if ((((mem->address & 0x1FFFFFFF)>128*1024*1024) || ((mem->address & 0x1FFFFFFF)<32*1024*1024)) && PSM(mem->address & 0x1FFFFFFF)) - memcpy(data, PSM(mem->address & 0x1FFFFFFF), mem->length); - else{ - out->result=0x11; - strcat(line, " ADDRESS ERROR"); - } - break; - case 1: - if (in->id==1) - memcpy(data, &VU0.Mem[mem->address & 0xFFF], mem->length); - else - memcpy(data, &VU1.Mem[mem->address & 0x3FFF], mem->length); - break; - case 2: - if (in->id==1) - memcpy(data, &VU0.Micro[mem->address & 0xFFF], mem->length); - else - memcpy(data, &VU1.Micro[mem->address & 0x3FFF], mem->length); - break; - } - } - out->h.length=mem->length+data-(u8*)out; - break; - } - - case 0x0a://ok - { - sprintf(line, "%s/WRMEM %08X/%X", - in->id==0?"CPU":in->id==1?"VU0":"VU1", mem->address, mem->length); - const u8* data=(u8*)in+ //kids: don't try this at home! :D - ((sizeof(DECI2_DBGP_HEADER)+sizeof(DECI2_DBGP_MEM)+(1 << mem->align) - 1) & (0xFFFFFFFF << mem->align)); - if (mem->length==4 && *(int*)data==0x0000000D) - strcat(line, " BREAKPOINT"); - if ((mem->address & ((1 << mem->align)-1)) || - (mem->length & ((1 << mem->align)-1))){ - out->result=1; - strcat(line, " ALIGN ERROR"); - break; - } - if (in->h.destination=='I') - if (PSXM(mem->address & 0x1FFFFFFF)) - memcpy(PSXM(mem->address & 0x1FFFFFFF), data, mem->length); - else{ - out->result=0x11; - strcat(line, " ADDRESS ERROR"); - break; - } - else - switch(mem->space){ - case 0: - if ((mem->address & 0xF0000000) == 0x70000000) - memcpy(PSM(mem->address), data, mem->length); - else - if (PSM(mem->address & 0x1FFFFFFF)) - memcpy(PSM(mem->address & 0x1FFFFFFF), data, mem->length); - else{ - out->result=0x11; - strcat(line, " ADDRESS ERROR"); - } - break; - case 1: - if (in->id==1) - memcpy(&VU0.Mem[mem->address & 0xFFF], data, mem->length); - else - memcpy(&VU1.Mem[mem->address & 0x3FFF], data, mem->length); - break; - case 2: - if (in->id==1) - memcpy(&VU0.Micro[mem->address & 0xFFF], data, mem->length); - else - memcpy(&VU1.Micro[mem->address & 0x3FFF], data, mem->length); - break; - } - out->h.length=sizeof(DECI2_DBGP_HEADER)+sizeof(DECI2_DBGP_MEM); - break; - } - case 0x10://ok - { - sprintf(line, "%s/GETBRKPT count=%d", - in->id==0?"CPU":in->id==1?"VU0":"VU1", in->count); - if (in->h.destination=='I') memcpy(&out[1], ibrk, out->count=ibrk_count); - else memcpy(&out[1], ebrk, out->count=ebrk_count); - out->h.length=sizeof(DECI2_DBGP_HEADER)+out->count*sizeof(DECI2_DBGP_BRK); - break; - } - case 0x12://ok [does not break on iop brkpts] - sprintf(line, "%s/PUTBRKPT count=%d", - in->id==0?"CPU":in->id==1?"VU0":"VU1", in->count); - out->h.length=sizeof(DECI2_DBGP_HEADER); - if (in->count>32){ - out->result=1; - strcat(line, "TOO MANY"); - break; - } - if (in->h.destination=='I') memcpy(ibrk, &out[1], ibrk_count=in->count); - else memcpy(ebrk, &out[1], ebrk_count=in->count); - out->count=0; - break; - case 0x14://ok, [w/o iop] - sprintf(line, "%s/BREAK count=%d", - in->id==0?"CPU":in->id==1?"VU0":"VU1", in->count); - if (in->h.destination=='I') - ; - else{ - out->result = ( pcsx2_InterlockedExchange(&runStatus, STOP)==STOP ? - 0x20 : 0x21 ); - out->code=0xFF; - Sleep(50); - } - break; - case 0x16://ok, [w/o iop] - sprintf(line, "%s/CONTINUE code=%s count=%d", - in->id==0?"CPU":in->id==1?"VU0":"VU1", - in->code==0?"CONT":in->code==1?"STEP":"NEXT", in->count); - if (in->h.destination=='I') - ; - else{ - pcsx2_InterlockedExchange(&runStatus, STOP); - Sleep(100);//first get the run thread to Wait state - runCount=in->count; - runCode=in->code; -#ifdef _WIN32 - SetEvent(runEvent);//kick it -#endif - } - break; - case 0x18://ok [without argc/argv stuff] - { - sprintf(line, "%s/RUN code=%d count=%d entry=0x%08X gp=0x%08X argc=%d", - in->id==0?"CPU":in->id==1?"VU0":"VU1", in->code, in->count, - run->entry, run->gp, run->argc); - cpuRegs.CP0.n.EPC=cpuRegs.pc=run->entry; - cpuRegs.GPR.n.gp.UL[0]=run->gp; -// threads_array[0].argc = run->argc; - u32* argv = (u32*)&run[1]; - for (i=0, s=0; i<(int)run->argc; i++, argv++) s+=argv[i]; - memcpy(PSM(0), argv, s); -// threads_array[0].argstring = 0; - pcsx2_InterlockedExchange((volatile long*)&runStatus, (u32)STOP); - Sleep(1000);//first get the run thread to Wait state - runCount=0; - runCode=0xFF; -#ifdef _WIN32 - SetEvent(runEvent);//awake it -#endif - out->h.length=sizeof(DECI2_DBGP_HEADER); - break; - } - default: - sprintf(line, "type=0x%02X code=%d count=%d [unknown]", in->type, in->code, in->count); - } - sprintf(message, "[DBGP %c->%c/%04X] %s", in->h.source, in->h.destination, in->h.length, line); - sprintf(eepc, "%08X", cpuRegs.pc); - sprintf(ioppc, "%08X", psxRegs.pc); - sprintf(eecy, "%d", cpuRegs.cycle); - sprintf(iopcy, "%d", psxRegs.cycle); - writeData(outbuffer); -} - -void sendBREAK(u8 source, u16 id, u8 code, u8 result, u8 count){ - static DECI2_DBGP_HEADER tmp; - tmp.h.length =sizeof(DECI2_DBGP_HEADER); - tmp.h._pad =0; - tmp.h.protocol =( source=='E' ? PROTO_EDBGP : PROTO_IDBGP ); - tmp.h.source =source; - tmp.h.destination='H'; - tmp.id =id; - tmp.type =0x15; - tmp.code =code; - tmp.result =result; - tmp.count =count; - tmp._pad =0; - writeData((u8*)&tmp); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "PsxCommon.h" +#include "VUmicro.h" +#include "deci2.h" + +#include "Threading.h" +using namespace Threading; + +using namespace R5900; + +struct DECI2_DBGP_HEADER{ + DECI2_HEADER h; //+00 + u16 id; //+08 + u8 type, //+0A + code, //+0B + result, //+0C + count; //+0D + u16 _pad; //+0E +}; //=10 + +struct DECI2_DBGP_CONF{ + u32 major_ver, //+00 + minor_ver, //+04 + target_id, //+08 + _pad, //+0C + mem_align, //+10 + _pad2, //+14 + reg_size, //+18 + nreg, //+1C + nbrkpt, //+20 + ncont, //+24 + nstep, //+28 + nnext, //+2C + mem_limit_align, //+30 + mem_limit_size, //+34 + run_stop_state, //+38 + hdbg_area_addr, //+3C + hdbg_area_size; //+40 +}; //=44 + +DECI2_DBGP_CONF +cpu={3, 0, PROTO_EDBGP, 0, 0x41F, 1, 7, 32, 32, 1, 0xFF, 0xFF, 0x1F, 0x400, 2, 0x80020c70, 0x100}, +vu0={3, 0, PROTO_EDBGP, 0, 0x41F, 1, 7, 32, 32, 1, 0xFF, 0xFF, 0x1F, 0x400, 2, 0x80020c70, 0x100}, +vu1={3, 0, PROTO_EDBGP, 0, 0x41F, 1, 7, 32, 32, 1, 0xFF, 0xFF, 0x1F, 0x400, 2, 0x80020c70, 0x100}, +iop={3, 0, PROTO_IDBGP, 0, 0x00F, 1, 5, 62, 32, 1, 0x00, 0x00, 0x07, 0x200, 1, 0x0001E670, 0x100}; +//iop={3, 0, PROTO_IDBGP, 0, 0x00F, 1, 5, 62, 0, 1, 0x00, 0x00, 0x07, 0x200, 0, 0x00006940, 0x100}; + +#pragma pack(2) +struct DECI2_DBGP_EREG{ + u8 kind, //+00 + number; //+01 + u16 _pad; //+02 + u64 value[2]; //+04 +}; //=14 + +struct DECI2_DBGP_IREG{ + u8 kind, //+00 + number; //+01 + u16 _pad; //+02 + u32 value; //+04 +}; //=08 + +struct DECI2_DBGP_MEM{ + u8 space, //+00 + align; //+01 + u16 _pad; //+02 + u32 address; //+04 + u32 length; //+08 +}; //=0C + +struct DECI2_DBGP_RUN{ + u32 entry, //+00 + gp, //+04 + _pad, //+08 + _pad1, //+0C + argc; //+10 + //u32 argv; //+14 +}; //=18 +#pragma pack() + +void D2_DBGP(const u8 *inbuffer, u8 *outbuffer, char *message, char *eepc, char *ioppc, char *eecy, char *iopcy){ + const DECI2_DBGP_HEADER *in=(DECI2_DBGP_HEADER*)inbuffer; + DECI2_DBGP_HEADER* out=(DECI2_DBGP_HEADER*)outbuffer; + + DECI2_DBGP_EREG *eregs=(DECI2_DBGP_EREG*)&out[1]; + DECI2_DBGP_IREG *iregs=(DECI2_DBGP_IREG*)&out[1]; + DECI2_DBGP_MEM *mem =(DECI2_DBGP_MEM*) &out[1]; + const DECI2_DBGP_RUN*run =(DECI2_DBGP_RUN*) &in[1]; + + static char line[1024]; + int i, s; + + memcpy(outbuffer, inbuffer, 128*1024);//BUFFERSIZE + //out->h.length=sizeof(DECI2_DBGP_HEADER); + out->type++; + out->result=0; //ok + exchangeSD((DECI2_HEADER*)out); + switch(in->type){ + case 0x00://ok + sprintf(line, "%s/GETCONF", in->id==0?"CPU":in->id==1?"VU0":"VU1"); + + if (in->h.destination=='I'){ + memcpy(&out[1], &iop, sizeof(DECI2_DBGP_CONF)); + }else + switch(in->id){ + case 0:memcpy(&out[1], &cpu, sizeof(DECI2_DBGP_CONF));break; + case 1:memcpy(&out[1], &vu0, sizeof(DECI2_DBGP_CONF));break; + case 2:memcpy(&out[1], &vu1, sizeof(DECI2_DBGP_CONF));break; + } + break; + case 0x02://ok + sprintf(line, "%s/2", in->id==0?"CPU":in->id==1?"VU0":"VU1"); + break; + case 0x04://ok + sprintf(line, "%s/GETREG count=%d kind[0]=%d number[0]=%d", + in->id==0?"CPU":in->id==1?"VU0":"VU1", in->count, eregs[0].kind, eregs[0].number); + if (in->h.destination=='I'){ + for (i=0; icount; i++) + switch (iregs[i].kind){ + case 1:switch (iregs[i].number){ + case 0:iregs[i].value=psxRegs.GPR.n.lo;break; + case 1:iregs[i].value=psxRegs.GPR.n.hi;break; + } + break; + case 2:iregs[i].value=psxRegs.GPR.r[iregs[i].number]; break; + case 3: + if (iregs[i].number==14) psxRegs.CP0.n.EPC=psxRegs.pc; + iregs[i].value=psxRegs.CP0.r[iregs[i].number]; + break; + case 6:iregs[i].value=psxRegs.CP2D.r[iregs[i].number]; break; + case 7:iregs[i].value=psxRegs.CP2C.r[iregs[i].number]; break; + default: + iregs[0].value++;//dummy; might be assert(0) + } + }else + for (i=0; icount; i++) + switch (eregs[i].kind){ + case 0:memcpy(eregs[i].value, &cpuRegs.GPR.r[eregs[i].number], 16);break; + case 1: + switch(eregs[i].number){ + case 0:memcpy(eregs[i].value, &cpuRegs.HI.UD[0], 8);break; + case 1:memcpy(eregs[i].value, &cpuRegs.LO.UD[0], 8);break; + case 2:memcpy(eregs[i].value, &cpuRegs.HI.UD[1], 8);break; + case 3:memcpy(eregs[i].value, &cpuRegs.LO.UD[1], 8);break; + case 4:memcpy(eregs[i].value, &cpuRegs.sa, 4); break; + } + case 2: + if (eregs[i].number==14) cpuRegs.CP0.n.EPC=cpuRegs.pc; + memcpy(eregs[i].value, &cpuRegs.CP0.r[eregs[i].number], 4); + break; + case 3:break;//performance counter 32x3 + case 4:break;//hw debug reg 32x8 + case 5:memcpy(eregs[i].value, &fpuRegs.fpr[eregs[i].number], 4);break; + case 6:memcpy(eregs[i].value, &fpuRegs.fprc[eregs[i].number], 4);break; + case 7:memcpy(eregs[i].value, &VU0.VF[eregs[i].number], 16);break; + case 8:memcpy(eregs[i].value, &VU0.VI[eregs[i].number], 4);break; + case 9:memcpy(eregs[i].value, &VU1.VF[eregs[i].number], 16);break; + case 10:memcpy(eregs[i].value, &VU1.VI[eregs[i].number], 4);break; + default: + eregs[0].value[0]++;//dummy; might be assert(0) + } + break; + case 0x06://ok + sprintf(line, "%s/PUTREG count=%d kind[0]=%d number[0]=%d value=%016I64X_%016I64X", + in->id==0?"CPU":in->id==1?"VU0":"VU1", in->count, eregs[0].kind, eregs[0].number, eregs[0].value[1], eregs[0].value[0]); + if (in->h.destination=='I'){ + for (i=0; icount; i++) + switch (iregs[i].kind){ + case 1:switch (iregs[i].number){ + case 0:psxRegs.GPR.n.lo=iregs[i].value;break; + case 1:psxRegs.GPR.n.hi=iregs[i].value;break; + } + break; + case 2:psxRegs.GPR.r[iregs[i].number]=iregs[i].value; break; + case 3: + psxRegs.CP0.r[iregs[i].number]=iregs[i].value; + if (iregs[i].number==14) psxRegs.pc=psxRegs.CP0.n.EPC; + break; + case 6:psxRegs.CP2D.r[iregs[i].number]=iregs[i].value; break; + case 7:psxRegs.CP2C.r[iregs[i].number]=iregs[i].value; break; + default: + ;//dummy; might be assert(0) + } + }else + for (i=0; icount; i++) + switch (eregs[i].kind){ + case 0:memcpy(&cpuRegs.GPR.r[eregs[i].number], eregs[i].value, 16);break; + case 1: + switch(eregs[i].number){ + case 0:memcpy(&cpuRegs.HI.UD[0], eregs[i].value, 8);break; + case 1:memcpy(&cpuRegs.LO.UD[0], eregs[i].value, 8);break; + case 2:memcpy(&cpuRegs.HI.UD[1], eregs[i].value, 8);break; + case 3:memcpy(&cpuRegs.LO.UD[1], eregs[i].value, 8);break; + case 4:memcpy(&cpuRegs.sa, eregs[i].value, 4); break; + } + break; + case 2: + memcpy(&cpuRegs.CP0.r[eregs[i].number], eregs[i].value, 4); + if (eregs[i].number==14) cpuRegs.pc=cpuRegs.CP0.n.EPC; + break; + case 3:break;//performance counter 32x3 + case 4:break;//hw debug reg 32x8 + case 5:memcpy(&fpuRegs.fpr[eregs[i].number], eregs[i].value, 4);break; + case 6:memcpy(&fpuRegs.fprc[eregs[i].number], eregs[i].value, 4);break; + case 7:memcpy(&VU0.VF[eregs[i].number], eregs[i].value, 16);break; + case 8:memcpy(&VU0.VI[eregs[i].number], eregs[i].value, 4);break; + case 9:memcpy(&VU1.VF[eregs[i].number], eregs[i].value, 16);break; + case 10:memcpy(&VU1.VI[eregs[i].number], eregs[i].value, 4);break; + default: + ;//dummy; might be assert(0) + } + break; + case 0x08://ok + { + sprintf(line, "%s/RDMEM %08X/%X", + in->id==0?"CPU":in->id==1?"VU0":"VU1", mem->address, mem->length); + u8* data =(u8*)out+ //kids: don't try this at home! :D + ((sizeof(DECI2_DBGP_HEADER)+sizeof(DECI2_DBGP_MEM)+(1 << mem->align) - 1) & (0xFFFFFFFF << mem->align)); + + if ((mem->address & ((1 << mem->align)-1)) || + (mem->length & ((1 << mem->align)-1))){ + out->result=1; + strcat(line, " ALIGN ERROR"); + break; + } + if (in->h.destination=='I') + if (PSXM(mem->address & 0x1FFFFFFF)) + memcpy(data, PSXM(mem->address & 0x1FFFFFFF), mem->length); + else{ + out->result=0x11; + strcat(line, " ADDRESS ERROR"); + break; + } + else + { + switch(mem->space){ + case 0: + if ((mem->address & 0xF0000000) == 0x70000000) + memcpy(data, PSM(mem->address), mem->length); + else + if ((((mem->address & 0x1FFFFFFF)>128*1024*1024) || ((mem->address & 0x1FFFFFFF)<32*1024*1024)) && PSM(mem->address & 0x1FFFFFFF)) + memcpy(data, PSM(mem->address & 0x1FFFFFFF), mem->length); + else{ + out->result=0x11; + strcat(line, " ADDRESS ERROR"); + } + break; + case 1: + if (in->id==1) + memcpy(data, &VU0.Mem[mem->address & 0xFFF], mem->length); + else + memcpy(data, &VU1.Mem[mem->address & 0x3FFF], mem->length); + break; + case 2: + if (in->id==1) + memcpy(data, &VU0.Micro[mem->address & 0xFFF], mem->length); + else + memcpy(data, &VU1.Micro[mem->address & 0x3FFF], mem->length); + break; + } + } + out->h.length=mem->length+data-(u8*)out; + break; + } + + case 0x0a://ok + { + sprintf(line, "%s/WRMEM %08X/%X", + in->id==0?"CPU":in->id==1?"VU0":"VU1", mem->address, mem->length); + const u8* data=(u8*)in+ //kids: don't try this at home! :D + ((sizeof(DECI2_DBGP_HEADER)+sizeof(DECI2_DBGP_MEM)+(1 << mem->align) - 1) & (0xFFFFFFFF << mem->align)); + if (mem->length==4 && *(int*)data==0x0000000D) + strcat(line, " BREAKPOINT"); + if ((mem->address & ((1 << mem->align)-1)) || + (mem->length & ((1 << mem->align)-1))){ + out->result=1; + strcat(line, " ALIGN ERROR"); + break; + } + if (in->h.destination=='I') + if (PSXM(mem->address & 0x1FFFFFFF)) + memcpy(PSXM(mem->address & 0x1FFFFFFF), data, mem->length); + else{ + out->result=0x11; + strcat(line, " ADDRESS ERROR"); + break; + } + else + switch(mem->space){ + case 0: + if ((mem->address & 0xF0000000) == 0x70000000) + memcpy(PSM(mem->address), data, mem->length); + else + if (PSM(mem->address & 0x1FFFFFFF)) + memcpy(PSM(mem->address & 0x1FFFFFFF), data, mem->length); + else{ + out->result=0x11; + strcat(line, " ADDRESS ERROR"); + } + break; + case 1: + if (in->id==1) + memcpy(&VU0.Mem[mem->address & 0xFFF], data, mem->length); + else + memcpy(&VU1.Mem[mem->address & 0x3FFF], data, mem->length); + break; + case 2: + if (in->id==1) + memcpy(&VU0.Micro[mem->address & 0xFFF], data, mem->length); + else + memcpy(&VU1.Micro[mem->address & 0x3FFF], data, mem->length); + break; + } + out->h.length=sizeof(DECI2_DBGP_HEADER)+sizeof(DECI2_DBGP_MEM); + break; + } + case 0x10://ok + { + sprintf(line, "%s/GETBRKPT count=%d", + in->id==0?"CPU":in->id==1?"VU0":"VU1", in->count); + if (in->h.destination=='I') memcpy(&out[1], ibrk, out->count=ibrk_count); + else memcpy(&out[1], ebrk, out->count=ebrk_count); + out->h.length=sizeof(DECI2_DBGP_HEADER)+out->count*sizeof(DECI2_DBGP_BRK); + break; + } + case 0x12://ok [does not break on iop brkpts] + sprintf(line, "%s/PUTBRKPT count=%d", + in->id==0?"CPU":in->id==1?"VU0":"VU1", in->count); + out->h.length=sizeof(DECI2_DBGP_HEADER); + if (in->count>32){ + out->result=1; + strcat(line, "TOO MANY"); + break; + } + if (in->h.destination=='I') memcpy(ibrk, &out[1], ibrk_count=in->count); + else memcpy(ebrk, &out[1], ebrk_count=in->count); + out->count=0; + break; + case 0x14://ok, [w/o iop] + sprintf(line, "%s/BREAK count=%d", + in->id==0?"CPU":in->id==1?"VU0":"VU1", in->count); + if (in->h.destination=='I') + ; + else{ + out->result = ( pcsx2_InterlockedExchange(&runStatus, STOP)==STOP ? + 0x20 : 0x21 ); + out->code=0xFF; + Sleep(50); + } + break; + case 0x16://ok, [w/o iop] + sprintf(line, "%s/CONTINUE code=%s count=%d", + in->id==0?"CPU":in->id==1?"VU0":"VU1", + in->code==0?"CONT":in->code==1?"STEP":"NEXT", in->count); + if (in->h.destination=='I') + ; + else{ + pcsx2_InterlockedExchange(&runStatus, STOP); + Sleep(100);//first get the run thread to Wait state + runCount=in->count; + runCode=in->code; +#ifdef _WIN32 + SetEvent(runEvent);//kick it +#endif + } + break; + case 0x18://ok [without argc/argv stuff] + { + sprintf(line, "%s/RUN code=%d count=%d entry=0x%08X gp=0x%08X argc=%d", + in->id==0?"CPU":in->id==1?"VU0":"VU1", in->code, in->count, + run->entry, run->gp, run->argc); + cpuRegs.CP0.n.EPC=cpuRegs.pc=run->entry; + cpuRegs.GPR.n.gp.UL[0]=run->gp; +// threads_array[0].argc = run->argc; + u32* argv = (u32*)&run[1]; + for (i=0, s=0; i<(int)run->argc; i++, argv++) s+=argv[i]; + memcpy(PSM(0), argv, s); +// threads_array[0].argstring = 0; + pcsx2_InterlockedExchange((volatile long*)&runStatus, (u32)STOP); + Sleep(1000);//first get the run thread to Wait state + runCount=0; + runCode=0xFF; +#ifdef _WIN32 + SetEvent(runEvent);//awake it +#endif + out->h.length=sizeof(DECI2_DBGP_HEADER); + break; + } + default: + sprintf(line, "type=0x%02X code=%d count=%d [unknown]", in->type, in->code, in->count); + } + sprintf(message, "[DBGP %c->%c/%04X] %s", in->h.source, in->h.destination, in->h.length, line); + sprintf(eepc, "%08X", cpuRegs.pc); + sprintf(ioppc, "%08X", psxRegs.pc); + sprintf(eecy, "%d", cpuRegs.cycle); + sprintf(iopcy, "%d", psxRegs.cycle); + writeData(outbuffer); +} + +void sendBREAK(u8 source, u16 id, u8 code, u8 result, u8 count){ + static DECI2_DBGP_HEADER tmp; + tmp.h.length =sizeof(DECI2_DBGP_HEADER); + tmp.h._pad =0; + tmp.h.protocol =( source=='E' ? PROTO_EDBGP : PROTO_IDBGP ); + tmp.h.source =source; + tmp.h.destination='H'; + tmp.id =id; + tmp.type =0x15; + tmp.code =code; + tmp.result =result; + tmp.count =count; + tmp._pad =0; + writeData((u8*)&tmp); +} diff --git a/pcsx2/RDebug/deci2_dbgp.h b/pcsx2/RDebug/deci2_dbgp.h index 4e0b508ece..8e846f71b5 100644 --- a/pcsx2/RDebug/deci2_dbgp.h +++ b/pcsx2/RDebug/deci2_dbgp.h @@ -1,28 +1,28 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __DECI2DBGP_H__ -#define __DECI2DBGP_H__ - -#include "Common.h" -#include "deci2.h" - -void D2_DBGP(const u8 *inbuffer, u8 *outbuffer, char *message, char *eepc, char *ioppc, char *eecy, char *iopcy); -void sendBREAK(u8 source, u16 id, u8 code, u8 result, u8 count); - -#endif//__DECI2DBGP_H__ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __DECI2DBGP_H__ +#define __DECI2DBGP_H__ + +#include "Common.h" +#include "deci2.h" + +void D2_DBGP(const u8 *inbuffer, u8 *outbuffer, char *message, char *eepc, char *ioppc, char *eecy, char *iopcy); +void sendBREAK(u8 source, u16 id, u8 code, u8 result, u8 count); + +#endif//__DECI2DBGP_H__ diff --git a/pcsx2/RDebug/deci2_dcmp.cpp b/pcsx2/RDebug/deci2_dcmp.cpp index 6318137fe6..5926af7aff 100644 --- a/pcsx2/RDebug/deci2_dcmp.cpp +++ b/pcsx2/RDebug/deci2_dcmp.cpp @@ -1,85 +1,85 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "deci2.h" - -struct DECI2_DCMP_HEADER{ - DECI2_HEADER h; //+00 - u8 type, //+08 - code; //+09 - u16 _pad; //+0A -}; //=0C - -struct DECI2_DCMP_CONNECT{ - u8 result, //+00 - _pad[3];//+01 - u64 EEboot, //+04 - IOPboot;//+0C -}; //=14 - -struct DECI2_DCMP_ECHO{ - u16 identifier, //+00 - sequence; //+02 - u8 data[32]; //+04 -}; //=24 - -void D2_DCMP(const u8 *inbuffer, u8 *outbuffer, char *message){ - DECI2_DCMP_HEADER *in=(DECI2_DCMP_HEADER*)inbuffer, - *out=(DECI2_DCMP_HEADER*)outbuffer; - u8 *data=(u8*)in+sizeof(DECI2_DCMP_HEADER); - - //DECI2_DCMP_CONNECT *connect=(DECI2_DCMP_CONNECT*)data; - //DECI2_DCMP_ECHO *echo =(DECI2_DCMP_ECHO*)data; - - memcpy(outbuffer, inbuffer, 128*1024);//BUFFERSIZE - out->h.length=sizeof(DECI2_DCMP_HEADER); -/* switch(in->type){ - case 0: - sprintf(message, " [DCMP] type=CONNECT code=%s EEboot=0x%I64X IOP=0x%I64X", - in->code==0?"CONNECT":"DISCONNECT", connect->EEboot, connect->IOPboot); - data=(u8*)out+sizeof(DECI2_DCMP_HEADER); - connect=(DECI2_DCMP_CONNECT*)data; - connect->result=0; - break; - case 1: - sprintf(message, " [DCMP] type=ECHO id=%X seq=%X", echo->identifier, echo->sequence); - exchangeSD(&out->h); - break; -// not implemented, not needed? - default: - sprintf(message, " [DCMP] type=%d[unknown]", in->type); - }*/ - out->code++; -} - -void sendDCMP(u16 protocol, u8 source, u8 destination, u8 type, u8 code, char *data, int size){ - static u8 tmp[100]; - ((DECI2_DCMP_HEADER*)tmp)->h.length =sizeof(DECI2_DCMP_HEADER)+size; - ((DECI2_DCMP_HEADER*)tmp)->h._pad =0; - ((DECI2_DCMP_HEADER*)tmp)->h.protocol =protocol; - ((DECI2_DCMP_HEADER*)tmp)->h.source =source; - ((DECI2_DCMP_HEADER*)tmp)->h.destination=destination; - ((DECI2_DCMP_HEADER*)tmp)->type =type; - ((DECI2_DCMP_HEADER*)tmp)->code =code; - ((DECI2_DCMP_HEADER*)tmp)->_pad =0; - memcpy(&tmp[sizeof(DECI2_DCMP_HEADER)], data, size); - writeData(tmp); +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "deci2.h" + +struct DECI2_DCMP_HEADER{ + DECI2_HEADER h; //+00 + u8 type, //+08 + code; //+09 + u16 _pad; //+0A +}; //=0C + +struct DECI2_DCMP_CONNECT{ + u8 result, //+00 + _pad[3];//+01 + u64 EEboot, //+04 + IOPboot;//+0C +}; //=14 + +struct DECI2_DCMP_ECHO{ + u16 identifier, //+00 + sequence; //+02 + u8 data[32]; //+04 +}; //=24 + +void D2_DCMP(const u8 *inbuffer, u8 *outbuffer, char *message){ + DECI2_DCMP_HEADER *in=(DECI2_DCMP_HEADER*)inbuffer, + *out=(DECI2_DCMP_HEADER*)outbuffer; + u8 *data=(u8*)in+sizeof(DECI2_DCMP_HEADER); + + //DECI2_DCMP_CONNECT *connect=(DECI2_DCMP_CONNECT*)data; + //DECI2_DCMP_ECHO *echo =(DECI2_DCMP_ECHO*)data; + + memcpy(outbuffer, inbuffer, 128*1024);//BUFFERSIZE + out->h.length=sizeof(DECI2_DCMP_HEADER); +/* switch(in->type){ + case 0: + sprintf(message, " [DCMP] type=CONNECT code=%s EEboot=0x%I64X IOP=0x%I64X", + in->code==0?"CONNECT":"DISCONNECT", connect->EEboot, connect->IOPboot); + data=(u8*)out+sizeof(DECI2_DCMP_HEADER); + connect=(DECI2_DCMP_CONNECT*)data; + connect->result=0; + break; + case 1: + sprintf(message, " [DCMP] type=ECHO id=%X seq=%X", echo->identifier, echo->sequence); + exchangeSD(&out->h); + break; +// not implemented, not needed? + default: + sprintf(message, " [DCMP] type=%d[unknown]", in->type); + }*/ + out->code++; +} + +void sendDCMP(u16 protocol, u8 source, u8 destination, u8 type, u8 code, char *data, int size){ + static u8 tmp[100]; + ((DECI2_DCMP_HEADER*)tmp)->h.length =sizeof(DECI2_DCMP_HEADER)+size; + ((DECI2_DCMP_HEADER*)tmp)->h._pad =0; + ((DECI2_DCMP_HEADER*)tmp)->h.protocol =protocol; + ((DECI2_DCMP_HEADER*)tmp)->h.source =source; + ((DECI2_DCMP_HEADER*)tmp)->h.destination=destination; + ((DECI2_DCMP_HEADER*)tmp)->type =type; + ((DECI2_DCMP_HEADER*)tmp)->code =code; + ((DECI2_DCMP_HEADER*)tmp)->_pad =0; + memcpy(&tmp[sizeof(DECI2_DCMP_HEADER)], data, size); + writeData(tmp); } \ No newline at end of file diff --git a/pcsx2/RDebug/deci2_dcmp.h b/pcsx2/RDebug/deci2_dcmp.h index 5fe87de7fb..d18e89ddee 100644 --- a/pcsx2/RDebug/deci2_dcmp.h +++ b/pcsx2/RDebug/deci2_dcmp.h @@ -1,28 +1,28 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __DECI2DCMP_H__ -#define __DECI2DCMP_H__ - -#include "Common.h" -#include "deci2.h" - -void D2_DCMP(const u8 *inbuffer, u8 *outbuffer, char *message); -void sendDCMP(u16 protocol, u8 source, u8 destination, u8 type, u8 code, char *data, int size); - -#endif//__DECI2DCMP_H__ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __DECI2DCMP_H__ +#define __DECI2DCMP_H__ + +#include "Common.h" +#include "deci2.h" + +void D2_DCMP(const u8 *inbuffer, u8 *outbuffer, char *message); +void sendDCMP(u16 protocol, u8 source, u8 destination, u8 type, u8 code, char *data, int size); + +#endif//__DECI2DCMP_H__ diff --git a/pcsx2/RDebug/deci2_drfp.cpp b/pcsx2/RDebug/deci2_drfp.cpp index a26af1dad5..94e31b1834 100644 --- a/pcsx2/RDebug/deci2_drfp.cpp +++ b/pcsx2/RDebug/deci2_drfp.cpp @@ -1,48 +1,48 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "Common.h" -#include "deci2.h" - -typedef struct tag_DECI2_DCMP_HEADER{ - DECI2_HEADER h; //+00 - u8 type, //+08 - code; //+09 - u16 _pad; //+0A -} DECI2_DCMP_HEADER; //=0C - -extern char d2_message[100]; - -void D2_DCMP(char *inbuffer, char *outbuffer, char *message){ - DECI2_DCMP_HEADER *in=(DECI2_DCMP_HEADER*)inbuffer, - *out=(DECI2_DCMP_HEADER*)outbuffer; - u8 *data=(u8*)in+sizeof(DECI2_DCMP_HEADER); - - memcpy(outbuffer, inbuffer, 128*1024);//BUFFERSIZE - out->h.length=sizeof(DECI2_DCMP_HEADER); - switch(in->type){ - case 4://[OK] - sprintf(message, " [DCMP] code=MESSAGE %s", data);//null terminated by the memset with 0 call - strcpy(d2_message, data); - break; - default: - sprintf(message, " [DCMP] code=%d[unknown] result=%d", netmp->code, netmp->result); - } - result->code++; - result->result=0; //ok -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "Common.h" +#include "deci2.h" + +typedef struct tag_DECI2_DCMP_HEADER{ + DECI2_HEADER h; //+00 + u8 type, //+08 + code; //+09 + u16 _pad; //+0A +} DECI2_DCMP_HEADER; //=0C + +extern char d2_message[100]; + +void D2_DCMP(char *inbuffer, char *outbuffer, char *message){ + DECI2_DCMP_HEADER *in=(DECI2_DCMP_HEADER*)inbuffer, + *out=(DECI2_DCMP_HEADER*)outbuffer; + u8 *data=(u8*)in+sizeof(DECI2_DCMP_HEADER); + + memcpy(outbuffer, inbuffer, 128*1024);//BUFFERSIZE + out->h.length=sizeof(DECI2_DCMP_HEADER); + switch(in->type){ + case 4://[OK] + sprintf(message, " [DCMP] code=MESSAGE %s", data);//null terminated by the memset with 0 call + strcpy(d2_message, data); + break; + default: + sprintf(message, " [DCMP] code=%d[unknown] result=%d", netmp->code, netmp->result); + } + result->code++; + result->result=0; //ok +} diff --git a/pcsx2/RDebug/deci2_drfp.h b/pcsx2/RDebug/deci2_drfp.h index 78c78eb254..1a9ba787d5 100644 --- a/pcsx2/RDebug/deci2_drfp.h +++ b/pcsx2/RDebug/deci2_drfp.h @@ -1,27 +1,27 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __DECI2DRFP_H__ -#define __DECI2DRFP_H__ - -#include "Common.h" -#include "deci2.h" - -void D2_(char *inbuffer, char *outbuffer, char *message); - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __DECI2DRFP_H__ +#define __DECI2DRFP_H__ + +#include "Common.h" +#include "deci2.h" + +void D2_(char *inbuffer, char *outbuffer, char *message); + #endif//__DECI2DRFP_H__ \ No newline at end of file diff --git a/pcsx2/RDebug/deci2_iloadp.cpp b/pcsx2/RDebug/deci2_iloadp.cpp index bc18f7a8e4..aa18a263a1 100644 --- a/pcsx2/RDebug/deci2_iloadp.cpp +++ b/pcsx2/RDebug/deci2_iloadp.cpp @@ -1,108 +1,108 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "PsxCommon.h" -#include "IopBios2.h" -#include "deci2.h" - -struct DECI2_ILOADP_HEADER{ - DECI2_HEADER h; //+00 - u8 code, //+08 cmd - action, //+09 - result, //+0A - stamp; //+0B - u32 moduleId; //+0C -}; //=10 - -struct DECI2_ILOADP_INFO{ - u16 version, //+00 - flags; //+02 - u32 module_address, //+04 - text_size, //+08 - data_size, //+0C - bss_size, //+10 - _pad[3]; //+14 -}; - -void writeInfo(DECI2_ILOADP_INFO *info, - u16 version, u16 flags, u32 module_address, - u32 text_size, u32 data_size, u32 bss_size){ - info->version =version; - info->flags =flags; - info->module_address=module_address; - info->text_size =text_size; - info->data_size =data_size; - info->bss_size =bss_size; - info->_pad[0]=info->_pad[1]=info->_pad[2]=0; -} - -void D2_ILOADP(const u8 *inbuffer, u8 *outbuffer, char *message){ - DECI2_ILOADP_HEADER *in=(DECI2_ILOADP_HEADER*)inbuffer, - *out=(DECI2_ILOADP_HEADER*)outbuffer; - u8 *data=(u8*)in+sizeof(DECI2_ILOADP_HEADER); - irxImageInfo *iii; - static char line[1024]; - - memcpy(outbuffer, inbuffer, 128*1024);//BUFFERSIZE - out->h.length=sizeof(DECI2_ILOADP_HEADER); - out->code++; - out->result=0; //ok - exchangeSD((DECI2_HEADER*)out); - switch(in->code){ - case 0: - sprintf(line, "code=START action=%d stamp=%d moduleId=0x%X", in->action, in->stamp, in->moduleId); - break; - case 2: - sprintf(line, "code=REMOVE action=%d stamp=%d moduleId=0x%X", in->action, in->stamp, in->moduleId); - break; - case 4: - sprintf(line, "code=LIST action=%d stamp=%d moduleId=0x%X", in->action, in->stamp, in->moduleId); - data=(u8*)out+sizeof(DECI2_ILOADP_HEADER); - for (iii=(irxImageInfo*)PSXM(0x800); iii; iii=iii->next?(irxImageInfo*)PSXM(iii->next):0, data+=4) - *(u32*)data=iii->index; - - out->h.length=data-(u8*)out; - break; - case 6: - sprintf(line, "code=INFO action=%d stamp=%d moduleId=0x%X", in->action, in->stamp, in->moduleId); - data=(u8*)out+sizeof(DECI2_ILOADP_HEADER); - for(iii=(irxImageInfo*)PSXM(0x800); iii; iii=iii->next?(irxImageInfo*)PSXM(iii->next):0) - if (iii->index==in->moduleId){ - writeInfo((DECI2_ILOADP_INFO*)data, - iii->version, iii->flags, iii->vaddr, iii->text_size, iii->data_size, iii->bss_size); - data+=sizeof(DECI2_ILOADP_INFO); - strcpy((char*)data, (char*)PSXM(iii->name)); - data+=strlen((char*)PSXM(iii->name))+4; - data=(u8*)((int)data & 0xFFFFFFFC); - break; - - } - out->h.length=data-(u8*)out; - break; - case 8: - sprintf(line, "code=WATCH action=%d stamp=%d moduleId=0x%X", in->action, in->stamp, in->moduleId); - break; - default: - sprintf(line, "code=%d[unknown]", in->code); - } - sprintf(message, "[ILOADP %c->%c/%04X] %s", in->h.source, in->h.destination, in->h.length, line); - writeData(outbuffer); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "PsxCommon.h" +#include "IopBios2.h" +#include "deci2.h" + +struct DECI2_ILOADP_HEADER{ + DECI2_HEADER h; //+00 + u8 code, //+08 cmd + action, //+09 + result, //+0A + stamp; //+0B + u32 moduleId; //+0C +}; //=10 + +struct DECI2_ILOADP_INFO{ + u16 version, //+00 + flags; //+02 + u32 module_address, //+04 + text_size, //+08 + data_size, //+0C + bss_size, //+10 + _pad[3]; //+14 +}; + +void writeInfo(DECI2_ILOADP_INFO *info, + u16 version, u16 flags, u32 module_address, + u32 text_size, u32 data_size, u32 bss_size){ + info->version =version; + info->flags =flags; + info->module_address=module_address; + info->text_size =text_size; + info->data_size =data_size; + info->bss_size =bss_size; + info->_pad[0]=info->_pad[1]=info->_pad[2]=0; +} + +void D2_ILOADP(const u8 *inbuffer, u8 *outbuffer, char *message){ + DECI2_ILOADP_HEADER *in=(DECI2_ILOADP_HEADER*)inbuffer, + *out=(DECI2_ILOADP_HEADER*)outbuffer; + u8 *data=(u8*)in+sizeof(DECI2_ILOADP_HEADER); + irxImageInfo *iii; + static char line[1024]; + + memcpy(outbuffer, inbuffer, 128*1024);//BUFFERSIZE + out->h.length=sizeof(DECI2_ILOADP_HEADER); + out->code++; + out->result=0; //ok + exchangeSD((DECI2_HEADER*)out); + switch(in->code){ + case 0: + sprintf(line, "code=START action=%d stamp=%d moduleId=0x%X", in->action, in->stamp, in->moduleId); + break; + case 2: + sprintf(line, "code=REMOVE action=%d stamp=%d moduleId=0x%X", in->action, in->stamp, in->moduleId); + break; + case 4: + sprintf(line, "code=LIST action=%d stamp=%d moduleId=0x%X", in->action, in->stamp, in->moduleId); + data=(u8*)out+sizeof(DECI2_ILOADP_HEADER); + for (iii=(irxImageInfo*)PSXM(0x800); iii; iii=iii->next?(irxImageInfo*)PSXM(iii->next):0, data+=4) + *(u32*)data=iii->index; + + out->h.length=data-(u8*)out; + break; + case 6: + sprintf(line, "code=INFO action=%d stamp=%d moduleId=0x%X", in->action, in->stamp, in->moduleId); + data=(u8*)out+sizeof(DECI2_ILOADP_HEADER); + for(iii=(irxImageInfo*)PSXM(0x800); iii; iii=iii->next?(irxImageInfo*)PSXM(iii->next):0) + if (iii->index==in->moduleId){ + writeInfo((DECI2_ILOADP_INFO*)data, + iii->version, iii->flags, iii->vaddr, iii->text_size, iii->data_size, iii->bss_size); + data+=sizeof(DECI2_ILOADP_INFO); + strcpy((char*)data, (char*)PSXM(iii->name)); + data+=strlen((char*)PSXM(iii->name))+4; + data=(u8*)((int)data & 0xFFFFFFFC); + break; + + } + out->h.length=data-(u8*)out; + break; + case 8: + sprintf(line, "code=WATCH action=%d stamp=%d moduleId=0x%X", in->action, in->stamp, in->moduleId); + break; + default: + sprintf(line, "code=%d[unknown]", in->code); + } + sprintf(message, "[ILOADP %c->%c/%04X] %s", in->h.source, in->h.destination, in->h.length, line); + writeData(outbuffer); +} diff --git a/pcsx2/RDebug/deci2_iloadp.h b/pcsx2/RDebug/deci2_iloadp.h index ee556235e0..77074b6b83 100644 --- a/pcsx2/RDebug/deci2_iloadp.h +++ b/pcsx2/RDebug/deci2_iloadp.h @@ -1,27 +1,27 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __DECI2ILOADP_H__ -#define __DECI2ILOADP_H__ - -#include "Common.h" -#include "deci2.h" - -void D2_ILOADP(const u8 *inbuffer, u8 *outbuffer, char *message); - -#endif//__DECI2ILOADP_H__ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __DECI2ILOADP_H__ +#define __DECI2ILOADP_H__ + +#include "Common.h" +#include "deci2.h" + +void D2_ILOADP(const u8 *inbuffer, u8 *outbuffer, char *message); + +#endif//__DECI2ILOADP_H__ diff --git a/pcsx2/RDebug/deci2_netmp.cpp b/pcsx2/RDebug/deci2_netmp.cpp index ca11d8131b..f871cacabe 100644 --- a/pcsx2/RDebug/deci2_netmp.cpp +++ b/pcsx2/RDebug/deci2_netmp.cpp @@ -1,136 +1,136 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "deci2.h" - -struct DECI2_NETMP_HEADER{ - DECI2_HEADER h; //+00 - u8 code, //+08 - result; //+09 -}; //=0A - -struct DECI2_NETMP_CONNECT{ - u8 priority, //+00 - _pad; //+01 - u16 protocol; //+02 -}; //=04 - -char d2_message[100]; -int d2_count=1; -DECI2_NETMP_CONNECT d2_connect[50]={0xFF, 0, 0x400}; - -void D2_NETMP(const u8 *inbuffer, u8 *outbuffer, char *message){ - DECI2_NETMP_HEADER *in=(DECI2_NETMP_HEADER*)inbuffer, - *out=(DECI2_NETMP_HEADER*)outbuffer; - u8 *data=(u8*)in+sizeof(DECI2_NETMP_HEADER); - DECI2_NETMP_CONNECT *connect=(DECI2_NETMP_CONNECT*)data; //connect - int i, n; - static char p[100], line[1024]; - u64 EEboot, IOPboot; //reset - u16 node; - - memcpy(outbuffer, inbuffer, 128*1024);//BUFFERSIZE - out->h.length=sizeof(DECI2_NETMP_HEADER); - out->code++; - out->result=0; //ok - switch(in->code){ - case 0: - n=(in->h.length-sizeof(DECI2_NETMP_HEADER)) / sizeof(DECI2_NETMP_CONNECT); - sprintf(line, "code=CONNECT"); - for (i=0; ih.length=data-(u8*)out; - writeData(outbuffer); - - node=(u16)'I'; - sendDCMP(PROTO_DCMP, 'H', 'H', 2, 0, (char*)&node, sizeof(node)); - - node=(u16)'E'; - sendDCMP(PROTO_DCMP, 'H', 'H', 2, 0, (char*)&node, sizeof(node)); - - node=PROTO_ILOADP; - sendDCMP(PROTO_DCMP, 'I', 'H', 2, 1, (char*)&node, sizeof(node)); - - for (i=0; i<10; i++){ - node=PROTO_ETTYP+i; - sendDCMP(PROTO_DCMP, 'E', 'H', 2, 1, (char*)&node, sizeof(node)); - - node=PROTO_ITTYP+i; - sendDCMP(PROTO_DCMP, 'E', 'H', 2, 1, (char*)&node, sizeof(node)); - } - node=PROTO_ETTYP+0xF; - sendDCMP(PROTO_DCMP, 'E', 'H', 2, 1, (char*)&node, sizeof(node)); - - node=PROTO_ITTYP+0xF; - sendDCMP(PROTO_DCMP, 'E', 'H', 2, 1, (char*)&node, sizeof(node)); - break; - case 4://[OK] - sprintf(line, "code=MESSAGE %s", data);//null terminated by the memset with 0 call - strcpy(d2_message, (char*)data); - writeData(outbuffer); - break; - case 6://[ok] - sprintf(line, "code=STATUS"); - data=(u8*)out+sizeof(DECI2_NETMP_HEADER)+2; - /* - memcpy(data, d2_connect, 1*sizeof(DECI2_NETMP_CONNECT)); - data+=1*sizeof(DECI2_NETMP_CONNECT); - *(u32*)data=1;//quite fast;) - data+=4; - memcpy(data, d2_message, strlen(d2_message)); - data+=strlen(d2_message); - *(u32*)data=0;//null end the string on a word boundary - data+=3;data=(u8*)((int)data & 0xFFFFFFFC);*/ - - out->h.length=data-(u8*)out; - writeData(outbuffer); - break; - case 8: - sprintf(line, "code=KILL protocol=0x%04X", *(u16*)data); - writeData(outbuffer); - break; - case 10: - sprintf(line, "code=VERSION %s", data); - data=(u8*)out+sizeof(DECI2_NETMP_HEADER); - strcpy((char*)data, "0.2.0");data+=strlen("0.2.0");//emu version;) - out->h.length=data-(u8*)out; - writeData(outbuffer); - break; - default: - sprintf(line, "code=%d[unknown] result=%d", in->code, in->result); - writeData(outbuffer); - } - sprintf(message, "[NETMP %c->%c/%04X] %s", in->h.source, in->h.destination, in->h.length, line); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "deci2.h" + +struct DECI2_NETMP_HEADER{ + DECI2_HEADER h; //+00 + u8 code, //+08 + result; //+09 +}; //=0A + +struct DECI2_NETMP_CONNECT{ + u8 priority, //+00 + _pad; //+01 + u16 protocol; //+02 +}; //=04 + +char d2_message[100]; +int d2_count=1; +DECI2_NETMP_CONNECT d2_connect[50]={0xFF, 0, 0x400}; + +void D2_NETMP(const u8 *inbuffer, u8 *outbuffer, char *message){ + DECI2_NETMP_HEADER *in=(DECI2_NETMP_HEADER*)inbuffer, + *out=(DECI2_NETMP_HEADER*)outbuffer; + u8 *data=(u8*)in+sizeof(DECI2_NETMP_HEADER); + DECI2_NETMP_CONNECT *connect=(DECI2_NETMP_CONNECT*)data; //connect + int i, n; + static char p[100], line[1024]; + u64 EEboot, IOPboot; //reset + u16 node; + + memcpy(outbuffer, inbuffer, 128*1024);//BUFFERSIZE + out->h.length=sizeof(DECI2_NETMP_HEADER); + out->code++; + out->result=0; //ok + switch(in->code){ + case 0: + n=(in->h.length-sizeof(DECI2_NETMP_HEADER)) / sizeof(DECI2_NETMP_CONNECT); + sprintf(line, "code=CONNECT"); + for (i=0; ih.length=data-(u8*)out; + writeData(outbuffer); + + node=(u16)'I'; + sendDCMP(PROTO_DCMP, 'H', 'H', 2, 0, (char*)&node, sizeof(node)); + + node=(u16)'E'; + sendDCMP(PROTO_DCMP, 'H', 'H', 2, 0, (char*)&node, sizeof(node)); + + node=PROTO_ILOADP; + sendDCMP(PROTO_DCMP, 'I', 'H', 2, 1, (char*)&node, sizeof(node)); + + for (i=0; i<10; i++){ + node=PROTO_ETTYP+i; + sendDCMP(PROTO_DCMP, 'E', 'H', 2, 1, (char*)&node, sizeof(node)); + + node=PROTO_ITTYP+i; + sendDCMP(PROTO_DCMP, 'E', 'H', 2, 1, (char*)&node, sizeof(node)); + } + node=PROTO_ETTYP+0xF; + sendDCMP(PROTO_DCMP, 'E', 'H', 2, 1, (char*)&node, sizeof(node)); + + node=PROTO_ITTYP+0xF; + sendDCMP(PROTO_DCMP, 'E', 'H', 2, 1, (char*)&node, sizeof(node)); + break; + case 4://[OK] + sprintf(line, "code=MESSAGE %s", data);//null terminated by the memset with 0 call + strcpy(d2_message, (char*)data); + writeData(outbuffer); + break; + case 6://[ok] + sprintf(line, "code=STATUS"); + data=(u8*)out+sizeof(DECI2_NETMP_HEADER)+2; + /* + memcpy(data, d2_connect, 1*sizeof(DECI2_NETMP_CONNECT)); + data+=1*sizeof(DECI2_NETMP_CONNECT); + *(u32*)data=1;//quite fast;) + data+=4; + memcpy(data, d2_message, strlen(d2_message)); + data+=strlen(d2_message); + *(u32*)data=0;//null end the string on a word boundary + data+=3;data=(u8*)((int)data & 0xFFFFFFFC);*/ + + out->h.length=data-(u8*)out; + writeData(outbuffer); + break; + case 8: + sprintf(line, "code=KILL protocol=0x%04X", *(u16*)data); + writeData(outbuffer); + break; + case 10: + sprintf(line, "code=VERSION %s", data); + data=(u8*)out+sizeof(DECI2_NETMP_HEADER); + strcpy((char*)data, "0.2.0");data+=strlen("0.2.0");//emu version;) + out->h.length=data-(u8*)out; + writeData(outbuffer); + break; + default: + sprintf(line, "code=%d[unknown] result=%d", in->code, in->result); + writeData(outbuffer); + } + sprintf(message, "[NETMP %c->%c/%04X] %s", in->h.source, in->h.destination, in->h.length, line); +} diff --git a/pcsx2/RDebug/deci2_netmp.h b/pcsx2/RDebug/deci2_netmp.h index fae6767118..87ed6b9a0b 100644 --- a/pcsx2/RDebug/deci2_netmp.h +++ b/pcsx2/RDebug/deci2_netmp.h @@ -1,27 +1,27 @@ - /* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __DECI2NETMP_H__ -#define __DECI2NETMP_H__ - -#include "Common.h" -#include "deci2.h" - -void D2_NETMP(const u8 *inbuffer, u8 *outbuffer, char *message); - -#endif//__DECI2NETMP_H__ + /* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __DECI2NETMP_H__ +#define __DECI2NETMP_H__ + +#include "Common.h" +#include "deci2.h" + +void D2_NETMP(const u8 *inbuffer, u8 *outbuffer, char *message); + +#endif//__DECI2NETMP_H__ diff --git a/pcsx2/RDebug/deci2_ttyp.cpp b/pcsx2/RDebug/deci2_ttyp.cpp index c397a5aa7e..8ee434b65d 100644 --- a/pcsx2/RDebug/deci2_ttyp.cpp +++ b/pcsx2/RDebug/deci2_ttyp.cpp @@ -1,43 +1,43 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "deci2.h" - -struct DECI2_TTYP_HEADER{ - DECI2_HEADER h; //+00 - u32 flushreq; //+08 - //u8 data[0]; //+0C // Not used, so commented out (cottonvibes) -}; //=0C - -void sendTTYP(u16 protocol, u8 source, char *data){ - static char tmp[2048]; - ((DECI2_TTYP_HEADER*)tmp)->h.length =sizeof(DECI2_TTYP_HEADER)+strlen(data); - ((DECI2_TTYP_HEADER*)tmp)->h._pad =0; - ((DECI2_TTYP_HEADER*)tmp)->h.protocol =protocol +(source=='E' ? PROTO_ETTYP : PROTO_ITTYP); - ((DECI2_TTYP_HEADER*)tmp)->h.source =source; - ((DECI2_TTYP_HEADER*)tmp)->h.destination='H'; - ((DECI2_TTYP_HEADER*)tmp)->flushreq =0; - if (((DECI2_TTYP_HEADER*)tmp)->h.length>2048) - Msgbox::Alert("TTYP: Buffer overflow"); - else - memcpy(&tmp[sizeof(DECI2_TTYP_HEADER)], data, strlen(data)); - //writeData(tmp); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "deci2.h" + +struct DECI2_TTYP_HEADER{ + DECI2_HEADER h; //+00 + u32 flushreq; //+08 + //u8 data[0]; //+0C // Not used, so commented out (cottonvibes) +}; //=0C + +void sendTTYP(u16 protocol, u8 source, char *data){ + static char tmp[2048]; + ((DECI2_TTYP_HEADER*)tmp)->h.length =sizeof(DECI2_TTYP_HEADER)+strlen(data); + ((DECI2_TTYP_HEADER*)tmp)->h._pad =0; + ((DECI2_TTYP_HEADER*)tmp)->h.protocol =protocol +(source=='E' ? PROTO_ETTYP : PROTO_ITTYP); + ((DECI2_TTYP_HEADER*)tmp)->h.source =source; + ((DECI2_TTYP_HEADER*)tmp)->h.destination='H'; + ((DECI2_TTYP_HEADER*)tmp)->flushreq =0; + if (((DECI2_TTYP_HEADER*)tmp)->h.length>2048) + Msgbox::Alert("TTYP: Buffer overflow"); + else + memcpy(&tmp[sizeof(DECI2_TTYP_HEADER)], data, strlen(data)); + //writeData(tmp); +} diff --git a/pcsx2/RDebug/deci2_ttyp.h b/pcsx2/RDebug/deci2_ttyp.h index 4edf5739b2..791d30a974 100644 --- a/pcsx2/RDebug/deci2_ttyp.h +++ b/pcsx2/RDebug/deci2_ttyp.h @@ -1,28 +1,28 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __DECI2TTYP_H__ -#define __DECI2TTYP_H__ - -#include "Common.h" -#include "deci2.h" - -//void D2_(char *inbuffer, char *outbuffer, char *message); -void sendTTYP(u16 protocol, u8 source, char *data); - -#endif//__DECI2TTYP_H__ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __DECI2TTYP_H__ +#define __DECI2TTYP_H__ + +#include "Common.h" +#include "deci2.h" + +//void D2_(char *inbuffer, char *outbuffer, char *message); +void sendTTYP(u16 protocol, u8 source, char *data); + +#endif//__DECI2TTYP_H__ diff --git a/pcsx2/SPR.cpp b/pcsx2/SPR.cpp index 02f1949f15..3ccf5d7a9b 100644 --- a/pcsx2/SPR.cpp +++ b/pcsx2/SPR.cpp @@ -1,388 +1,388 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "SPR.h" -#include "iR5900.h" -#include "VUmicro.h" - -#define spr0 ((DMACh*)&PS2MEM_HW[0xD000]) -#define spr1 ((DMACh*)&PS2MEM_HW[0xD400]) - -void sprInit() { -} - -//__forceinline static void SPR0transfer(u32 *data, int size) { -///* while (size > 0) { -// SPR_LOG("SPR1transfer: %x\n", *data); -// data++; size--; -// }*/ -// size <<= 2; -// if ((psHu32(DMAC_CTRL) & 0xC) == 0xC || // GIF MFIFO -// (psHu32(DMAC_CTRL) & 0xC) == 0x8) { // VIF1 MFIFO -// hwMFIFOWrite(spr0->madr, (u8*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff], size); -// } else { -// u32 * p = (u32*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff]; -// //WriteCodeSSE2(p,data,size >> 4); -// memcpy_fast((u8*)data, &PS2MEM_SCRATCH[spr0->sadr & 0x3fff], size); -// } -// spr0->sadr+= size; -//} - -static void TestClearVUs(u32 madr, u32 size) -{ - if( madr >= 0x11000000 ) { - if( madr < 0x11004000 ) { - DbgCon::Notice("scratch pad clearing vu0\n"); - CpuVU0.Clear(madr&0xfff, size); - } - else if( madr >= 0x11008000 && madr < 0x1100c000 ) { - DbgCon::Notice("scratch pad clearing vu1\n"); - CpuVU1.Clear(madr&0x3fff, size); - } - } -} - -int _SPR0chain() { - u32 *pMem; - - if (spr0->qwc == 0) return 0; - pMem = (u32*)dmaGetAddr(spr0->madr); - if (pMem == NULL) return -1; - - //SPR0transfer(pMem, qwc << 2); - - if ((psHu32(DMAC_CTRL) & 0xC) >= 0x8) { // 0x8 VIF1 MFIFO, 0xC GIF MFIFO - if((spr0->madr & ~psHu32(DMAC_RBSR)) != psHu32(DMAC_RBOR)) SysPrintf("SPR MFIFO Write outside MFIFO area\n"); - hwMFIFOWrite(spr0->madr, (u8*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc << 4); - spr0->madr += spr0->qwc << 4; - spr0->madr = psHu32(DMAC_RBOR) + (spr0->madr & psHu32(DMAC_RBSR)); - } else { - memcpy_fast((u8*)pMem, &PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc << 4); - Cpu->Clear(spr0->madr, spr0->qwc<<2); - // clear VU mem also! - TestClearVUs(spr0->madr, spr0->qwc << 2); // Wtf is going on here? AFAIK, only VIF should affect VU micromem (cottonvibes) - - spr0->madr += spr0->qwc << 4; - } - spr0->sadr += spr0->qwc << 4; - - - return (spr0->qwc) * BIAS; // bus is 1/2 the ee speed -} - -#define SPR0chain() \ - cycles += _SPR0chain(); \ - spr0->qwc = 0; - - -void _SPR0interleave() { - int qwc = spr0->qwc; - int sqwc = psHu32(DMAC_SQWC) & 0xff; - int tqwc = (psHu32(DMAC_SQWC) >> 16) & 0xff; - int cycles = 0; - u32 *pMem; - if(tqwc == 0) tqwc = qwc; - //SysPrintf("dmaSPR0 interleave\n"); - SPR_LOG("SPR0 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx\n", - spr0->qwc, tqwc, sqwc, spr0->madr, spr0->sadr); - - while (qwc > 0) { - spr0->qwc = std::min(tqwc, qwc); qwc-= spr0->qwc; - pMem = (u32*)dmaGetAddr(spr0->madr); - if ((psHu32(DMAC_CTRL) & 0xC) == 0xC || // GIF MFIFO - (psHu32(DMAC_CTRL) & 0xC) == 0x8) { // VIF1 MFIFO - hwMFIFOWrite(spr0->madr, (u8*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc<<4); - } else { - Cpu->Clear(spr0->madr, spr0->qwc<<2); - // clear VU mem also! - TestClearVUs(spr0->madr, spr0->qwc<<2); - memcpy_fast((u8*)pMem, &PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc<<4); - } - cycles += tqwc * BIAS; - spr0->sadr+= spr0->qwc * 16; - spr0->madr+= (sqwc+spr0->qwc)*16; //qwc-= sqwc; - } - - spr0->qwc = 0; - CPU_INT(8, cycles); -} - -static __forceinline void _dmaSPR0() { - - - if ((psHu32(DMAC_CTRL) & 0x30) == 0x20) { // STS == fromSPR - SysPrintf("SPR0 stall %d\n", (psHu32(DMAC_CTRL)>>6)&3); - } - - - - // Transfer Dn_QWC from SPR to Dn_MADR - - - - if ((spr0->chcr & 0xc) == 0x0) { // Normal Mode - int cycles = 0; - SPR0chain(); - CPU_INT(8, cycles); - - return; - } else if ((spr0->chcr & 0xc) == 0x4) { - int cycles = 0; - u32 *ptag; - int id; - int done = 0; - - if(spr0->qwc > 0){ - SPR0chain(); - CPU_INT(8, cycles); - - return; - } - // Destination Chain Mode - - while (done == 0) { // Loop while Dn_CHCR.STR is 1 - ptag = (u32*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff]; - spr0->sadr+= 16; - - // Transfer dma tag if tte is set -// if (spr0->chcr & 0x40) SPR0transfer(ptag, 4); - - spr0->chcr = ( spr0->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 - - id = (ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag - spr0->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag - spr0->madr = ptag[1]; //MADR = ADDR field - - SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx\n", - ptag[1], ptag[0], spr0->qwc, id, spr0->madr); - - if ((psHu32(DMAC_CTRL) & 0x30) == 0x20) { // STS == fromSPR - SysPrintf("SPR stall control\n"); - } - - switch (id) { - case 0: // CNTS - Transfer QWC following the tag (Stall Control) - if ((psHu32(DMAC_CTRL) & 0x30) == 0x20 ) psHu32(DMAC_STADR) = spr0->madr + (spr0->qwc * 16); //Copy MADR to DMAC_STADR stall addr register - break; - - case 1: // CNT - Transfer QWC following the tag. - break; - - case 7: // End - Transfer QWC following the tag - done = 1; //End Transfer - break; - } - SPR0chain(); - if (spr0->chcr & 0x80 && ptag[0] >> 31) { //Check TIE bit of CHCR and IRQ bit of tag - //SysPrintf("SPR0 TIE\n"); - done = 1; - spr0->qwc = 0; - break; - } - - -/* if (spr0->chcr & 0x80 && ptag[0] >> 31) { - SPR_LOG("dmaIrq Set\n"); - - spr0->chcr&= ~0x100; - hwDmacIrq(8); - return; - }*/ - } - CPU_INT(8, cycles); - } else { // Interleave Mode - _SPR0interleave(); - } - - - -} - -void SPRFROMinterrupt() -{ - spr0->chcr&= ~0x100; - hwDmacIrq(8); -} - -extern void mfifoGIFtransfer(int); -#define gif ((DMACh*)&PS2MEM_HW[0xA000]) -void dmaSPR0() { // fromSPR - int qwc = spr0->qwc; - - SPR_LOG("dmaSPR0 chcr = %lx, madr = %lx, qwc = %lx, sadr = %lx\n", - spr0->chcr, spr0->madr, spr0->qwc, spr0->sadr); - - _dmaSPR0(); - if ((psHu32(DMAC_CTRL) & 0xC) == 0xC) { // GIF MFIFO - if((spr0->madr & ~psHu32(DMAC_RBSR)) != psHu32(DMAC_RBOR)) SysPrintf("GIF MFIFO Write outside MFIFO area\n"); - spr0->madr = psHu32(DMAC_RBOR) + (spr0->madr & psHu32(DMAC_RBSR)); - //SysPrintf("mfifoGIFtransfer %x madr %x, tadr %x\n", gif->chcr, gif->madr, gif->tadr); - mfifoGIFtransfer(qwc); - } else - if ((psHu32(DMAC_CTRL) & 0xC) == 0x8) { // VIF1 MFIFO - if((spr0->madr & ~psHu32(DMAC_RBSR)) != psHu32(DMAC_RBOR)) SysPrintf("VIF MFIFO Write outside MFIFO area\n"); - spr0->madr = psHu32(DMAC_RBOR) + (spr0->madr & psHu32(DMAC_RBSR)); - //SysPrintf("mfifoVIF1transfer %x madr %x, tadr %x\n", vif1ch->chcr, vif1ch->madr, vif1ch->tadr); - //vifqwc+= qwc; - mfifoVIF1transfer(qwc); - } - -} - -__forceinline static void SPR1transfer(u32 *data, int size) { -/* { - int i; - for (i=0; isadr+i*4) & 0x3fff, data[i] ); - } - }*/ - //Cpu->Clear(spr1->sadr, size); // why? - memcpy_fast(&PS2MEM_SCRATCH[spr1->sadr & 0x3fff], (u8*)data, size << 2); - - spr1->sadr+= size << 2; -} - -int _SPR1chain() { - u32 *pMem; - - if (spr1->qwc == 0) return 0; - - pMem = (u32*)dmaGetAddr(spr1->madr); - if (pMem == NULL) return -1; - - SPR1transfer(pMem, spr1->qwc << 2); - spr1->madr+= spr1->qwc << 4; - - return (spr1->qwc) * BIAS; -} - -#define SPR1chain() \ - cycles += _SPR1chain(); \ - spr1->qwc = 0; - - -void _SPR1interleave() { - int qwc = spr1->qwc; - int sqwc = psHu32(DMAC_SQWC) & 0xff; - int tqwc = (psHu32(DMAC_SQWC) >> 16) & 0xff; - int cycles = 0; - u32 *pMem; - if(tqwc == 0) tqwc = qwc; - SPR_LOG("SPR1 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx\n", - spr1->qwc, tqwc, sqwc, spr1->madr, spr1->sadr); - - while (qwc > 0) { - spr1->qwc = std::min(tqwc, qwc); qwc-= spr1->qwc; - pMem = (u32*)dmaGetAddr(spr1->madr); - memcpy_fast(&PS2MEM_SCRATCH[spr1->sadr & 0x3fff], (u8*)pMem, spr1->qwc <<4); - spr1->sadr += spr1->qwc * 16; - cycles += spr1->qwc * BIAS; - spr1->madr+= (sqwc + spr1->qwc) * 16; //qwc-= sqwc; - } - - spr1->qwc = 0; - CPU_INT(9, cycles); - -} - -void dmaSPR1() { // toSPR - - -#ifdef SPR_LOG - SPR_LOG("dmaSPR1 chcr = 0x%x, madr = 0x%x, qwc = 0x%x\n" - " tadr = 0x%x, sadr = 0x%x\n", - spr1->chcr, spr1->madr, spr1->qwc, - spr1->tadr, spr1->sadr); -#endif - - - - - if ((spr1->chcr & 0xc) == 0) { // Normal Mode - int cycles = 0; - //if(spr1->qwc == 0 && (spr1->chcr & 0xc) == 1) spr1->qwc = 0xffff; - // Transfer Dn_QWC from Dn_MADR to SPR1 - SPR1chain(); - CPU_INT(9, cycles); - return; - } else if ((spr1->chcr & 0xc) == 0x4){ - int cycles = 0; - u32 *ptag; - int id, done=0; - - - if(spr1->qwc > 0){ - //if(spr1->qwc == 0 && (spr1->chcr & 0xc) == 1) spr1->qwc = 0xffff; - // Transfer Dn_QWC from Dn_MADR to SPR1 - SPR1chain(); - CPU_INT(9, cycles); - return; - } - // Chain Mode - - while (done == 0) { // Loop while Dn_CHCR.STR is 1 - ptag = (u32*)dmaGetAddr(spr1->tadr); //Set memory pointer to TADR - if (ptag == NULL) { //Is ptag empty? - SysPrintf("SPR1 Tag BUSERR\n"); - spr1->chcr = ( spr1->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 - psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register - done = 1; - break; - } - spr1->chcr = ( spr1->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 - - id = (ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag - spr1->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag - spr1->madr = ptag[1]; //MADR = ADDR field - - // Transfer dma tag if tte is set - if (spr1->chcr & 0x40) { - SPR_LOG("SPR TTE: %x_%x\n", ptag[3], ptag[2]); - SPR1transfer(ptag, 4); //Transfer Tag - } - - SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx\n", - ptag[1], ptag[0], spr1->qwc, id, spr1->madr); - - done = hwDmacSrcChain(spr1, id); - SPR1chain(); //Transfers the data set by the switch - - if (spr1->chcr & 0x80 && ptag[0] >> 31) { //Check TIE bit of CHCR and IRQ bit of tag - SPR_LOG("dmaIrq Set\n"); - - //SysPrintf("SPR1 TIE\n"); - spr1->qwc = 0; - break; - } - } - CPU_INT(9, cycles); - } else { // Interleave Mode - _SPR1interleave(); - } - -} - -void SPRTOinterrupt() -{ - spr1->chcr &= ~0x100; - hwDmacIrq(9); -} - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "SPR.h" +#include "iR5900.h" +#include "VUmicro.h" + +#define spr0 ((DMACh*)&PS2MEM_HW[0xD000]) +#define spr1 ((DMACh*)&PS2MEM_HW[0xD400]) + +void sprInit() { +} + +//__forceinline static void SPR0transfer(u32 *data, int size) { +///* while (size > 0) { +// SPR_LOG("SPR1transfer: %x\n", *data); +// data++; size--; +// }*/ +// size <<= 2; +// if ((psHu32(DMAC_CTRL) & 0xC) == 0xC || // GIF MFIFO +// (psHu32(DMAC_CTRL) & 0xC) == 0x8) { // VIF1 MFIFO +// hwMFIFOWrite(spr0->madr, (u8*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff], size); +// } else { +// u32 * p = (u32*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff]; +// //WriteCodeSSE2(p,data,size >> 4); +// memcpy_fast((u8*)data, &PS2MEM_SCRATCH[spr0->sadr & 0x3fff], size); +// } +// spr0->sadr+= size; +//} + +static void TestClearVUs(u32 madr, u32 size) +{ + if( madr >= 0x11000000 ) { + if( madr < 0x11004000 ) { + DbgCon::Notice("scratch pad clearing vu0\n"); + CpuVU0.Clear(madr&0xfff, size); + } + else if( madr >= 0x11008000 && madr < 0x1100c000 ) { + DbgCon::Notice("scratch pad clearing vu1\n"); + CpuVU1.Clear(madr&0x3fff, size); + } + } +} + +int _SPR0chain() { + u32 *pMem; + + if (spr0->qwc == 0) return 0; + pMem = (u32*)dmaGetAddr(spr0->madr); + if (pMem == NULL) return -1; + + //SPR0transfer(pMem, qwc << 2); + + if ((psHu32(DMAC_CTRL) & 0xC) >= 0x8) { // 0x8 VIF1 MFIFO, 0xC GIF MFIFO + if((spr0->madr & ~psHu32(DMAC_RBSR)) != psHu32(DMAC_RBOR)) SysPrintf("SPR MFIFO Write outside MFIFO area\n"); + hwMFIFOWrite(spr0->madr, (u8*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc << 4); + spr0->madr += spr0->qwc << 4; + spr0->madr = psHu32(DMAC_RBOR) + (spr0->madr & psHu32(DMAC_RBSR)); + } else { + memcpy_fast((u8*)pMem, &PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc << 4); + Cpu->Clear(spr0->madr, spr0->qwc<<2); + // clear VU mem also! + TestClearVUs(spr0->madr, spr0->qwc << 2); // Wtf is going on here? AFAIK, only VIF should affect VU micromem (cottonvibes) + + spr0->madr += spr0->qwc << 4; + } + spr0->sadr += spr0->qwc << 4; + + + return (spr0->qwc) * BIAS; // bus is 1/2 the ee speed +} + +#define SPR0chain() \ + cycles += _SPR0chain(); \ + spr0->qwc = 0; + + +void _SPR0interleave() { + int qwc = spr0->qwc; + int sqwc = psHu32(DMAC_SQWC) & 0xff; + int tqwc = (psHu32(DMAC_SQWC) >> 16) & 0xff; + int cycles = 0; + u32 *pMem; + if(tqwc == 0) tqwc = qwc; + //SysPrintf("dmaSPR0 interleave\n"); + SPR_LOG("SPR0 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx\n", + spr0->qwc, tqwc, sqwc, spr0->madr, spr0->sadr); + + while (qwc > 0) { + spr0->qwc = std::min(tqwc, qwc); qwc-= spr0->qwc; + pMem = (u32*)dmaGetAddr(spr0->madr); + if ((psHu32(DMAC_CTRL) & 0xC) == 0xC || // GIF MFIFO + (psHu32(DMAC_CTRL) & 0xC) == 0x8) { // VIF1 MFIFO + hwMFIFOWrite(spr0->madr, (u8*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc<<4); + } else { + Cpu->Clear(spr0->madr, spr0->qwc<<2); + // clear VU mem also! + TestClearVUs(spr0->madr, spr0->qwc<<2); + memcpy_fast((u8*)pMem, &PS2MEM_SCRATCH[spr0->sadr & 0x3fff], spr0->qwc<<4); + } + cycles += tqwc * BIAS; + spr0->sadr+= spr0->qwc * 16; + spr0->madr+= (sqwc+spr0->qwc)*16; //qwc-= sqwc; + } + + spr0->qwc = 0; + CPU_INT(8, cycles); +} + +static __forceinline void _dmaSPR0() { + + + if ((psHu32(DMAC_CTRL) & 0x30) == 0x20) { // STS == fromSPR + SysPrintf("SPR0 stall %d\n", (psHu32(DMAC_CTRL)>>6)&3); + } + + + + // Transfer Dn_QWC from SPR to Dn_MADR + + + + if ((spr0->chcr & 0xc) == 0x0) { // Normal Mode + int cycles = 0; + SPR0chain(); + CPU_INT(8, cycles); + + return; + } else if ((spr0->chcr & 0xc) == 0x4) { + int cycles = 0; + u32 *ptag; + int id; + int done = 0; + + if(spr0->qwc > 0){ + SPR0chain(); + CPU_INT(8, cycles); + + return; + } + // Destination Chain Mode + + while (done == 0) { // Loop while Dn_CHCR.STR is 1 + ptag = (u32*)&PS2MEM_SCRATCH[spr0->sadr & 0x3fff]; + spr0->sadr+= 16; + + // Transfer dma tag if tte is set +// if (spr0->chcr & 0x40) SPR0transfer(ptag, 4); + + spr0->chcr = ( spr0->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + + id = (ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag + spr0->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag + spr0->madr = ptag[1]; //MADR = ADDR field + + SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx\n", + ptag[1], ptag[0], spr0->qwc, id, spr0->madr); + + if ((psHu32(DMAC_CTRL) & 0x30) == 0x20) { // STS == fromSPR + SysPrintf("SPR stall control\n"); + } + + switch (id) { + case 0: // CNTS - Transfer QWC following the tag (Stall Control) + if ((psHu32(DMAC_CTRL) & 0x30) == 0x20 ) psHu32(DMAC_STADR) = spr0->madr + (spr0->qwc * 16); //Copy MADR to DMAC_STADR stall addr register + break; + + case 1: // CNT - Transfer QWC following the tag. + break; + + case 7: // End - Transfer QWC following the tag + done = 1; //End Transfer + break; + } + SPR0chain(); + if (spr0->chcr & 0x80 && ptag[0] >> 31) { //Check TIE bit of CHCR and IRQ bit of tag + //SysPrintf("SPR0 TIE\n"); + done = 1; + spr0->qwc = 0; + break; + } + + +/* if (spr0->chcr & 0x80 && ptag[0] >> 31) { + SPR_LOG("dmaIrq Set\n"); + + spr0->chcr&= ~0x100; + hwDmacIrq(8); + return; + }*/ + } + CPU_INT(8, cycles); + } else { // Interleave Mode + _SPR0interleave(); + } + + + +} + +void SPRFROMinterrupt() +{ + spr0->chcr&= ~0x100; + hwDmacIrq(8); +} + +extern void mfifoGIFtransfer(int); +#define gif ((DMACh*)&PS2MEM_HW[0xA000]) +void dmaSPR0() { // fromSPR + int qwc = spr0->qwc; + + SPR_LOG("dmaSPR0 chcr = %lx, madr = %lx, qwc = %lx, sadr = %lx\n", + spr0->chcr, spr0->madr, spr0->qwc, spr0->sadr); + + _dmaSPR0(); + if ((psHu32(DMAC_CTRL) & 0xC) == 0xC) { // GIF MFIFO + if((spr0->madr & ~psHu32(DMAC_RBSR)) != psHu32(DMAC_RBOR)) SysPrintf("GIF MFIFO Write outside MFIFO area\n"); + spr0->madr = psHu32(DMAC_RBOR) + (spr0->madr & psHu32(DMAC_RBSR)); + //SysPrintf("mfifoGIFtransfer %x madr %x, tadr %x\n", gif->chcr, gif->madr, gif->tadr); + mfifoGIFtransfer(qwc); + } else + if ((psHu32(DMAC_CTRL) & 0xC) == 0x8) { // VIF1 MFIFO + if((spr0->madr & ~psHu32(DMAC_RBSR)) != psHu32(DMAC_RBOR)) SysPrintf("VIF MFIFO Write outside MFIFO area\n"); + spr0->madr = psHu32(DMAC_RBOR) + (spr0->madr & psHu32(DMAC_RBSR)); + //SysPrintf("mfifoVIF1transfer %x madr %x, tadr %x\n", vif1ch->chcr, vif1ch->madr, vif1ch->tadr); + //vifqwc+= qwc; + mfifoVIF1transfer(qwc); + } + +} + +__forceinline static void SPR1transfer(u32 *data, int size) { +/* { + int i; + for (i=0; isadr+i*4) & 0x3fff, data[i] ); + } + }*/ + //Cpu->Clear(spr1->sadr, size); // why? + memcpy_fast(&PS2MEM_SCRATCH[spr1->sadr & 0x3fff], (u8*)data, size << 2); + + spr1->sadr+= size << 2; +} + +int _SPR1chain() { + u32 *pMem; + + if (spr1->qwc == 0) return 0; + + pMem = (u32*)dmaGetAddr(spr1->madr); + if (pMem == NULL) return -1; + + SPR1transfer(pMem, spr1->qwc << 2); + spr1->madr+= spr1->qwc << 4; + + return (spr1->qwc) * BIAS; +} + +#define SPR1chain() \ + cycles += _SPR1chain(); \ + spr1->qwc = 0; + + +void _SPR1interleave() { + int qwc = spr1->qwc; + int sqwc = psHu32(DMAC_SQWC) & 0xff; + int tqwc = (psHu32(DMAC_SQWC) >> 16) & 0xff; + int cycles = 0; + u32 *pMem; + if(tqwc == 0) tqwc = qwc; + SPR_LOG("SPR1 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx\n", + spr1->qwc, tqwc, sqwc, spr1->madr, spr1->sadr); + + while (qwc > 0) { + spr1->qwc = std::min(tqwc, qwc); qwc-= spr1->qwc; + pMem = (u32*)dmaGetAddr(spr1->madr); + memcpy_fast(&PS2MEM_SCRATCH[spr1->sadr & 0x3fff], (u8*)pMem, spr1->qwc <<4); + spr1->sadr += spr1->qwc * 16; + cycles += spr1->qwc * BIAS; + spr1->madr+= (sqwc + spr1->qwc) * 16; //qwc-= sqwc; + } + + spr1->qwc = 0; + CPU_INT(9, cycles); + +} + +void dmaSPR1() { // toSPR + + +#ifdef SPR_LOG + SPR_LOG("dmaSPR1 chcr = 0x%x, madr = 0x%x, qwc = 0x%x\n" + " tadr = 0x%x, sadr = 0x%x\n", + spr1->chcr, spr1->madr, spr1->qwc, + spr1->tadr, spr1->sadr); +#endif + + + + + if ((spr1->chcr & 0xc) == 0) { // Normal Mode + int cycles = 0; + //if(spr1->qwc == 0 && (spr1->chcr & 0xc) == 1) spr1->qwc = 0xffff; + // Transfer Dn_QWC from Dn_MADR to SPR1 + SPR1chain(); + CPU_INT(9, cycles); + return; + } else if ((spr1->chcr & 0xc) == 0x4){ + int cycles = 0; + u32 *ptag; + int id, done=0; + + + if(spr1->qwc > 0){ + //if(spr1->qwc == 0 && (spr1->chcr & 0xc) == 1) spr1->qwc = 0xffff; + // Transfer Dn_QWC from Dn_MADR to SPR1 + SPR1chain(); + CPU_INT(9, cycles); + return; + } + // Chain Mode + + while (done == 0) { // Loop while Dn_CHCR.STR is 1 + ptag = (u32*)dmaGetAddr(spr1->tadr); //Set memory pointer to TADR + if (ptag == NULL) { //Is ptag empty? + SysPrintf("SPR1 Tag BUSERR\n"); + spr1->chcr = ( spr1->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register + done = 1; + break; + } + spr1->chcr = ( spr1->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + + id = (ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag + spr1->qwc = (u16)ptag[0]; //QWC set to lower 16bits of the tag + spr1->madr = ptag[1]; //MADR = ADDR field + + // Transfer dma tag if tte is set + if (spr1->chcr & 0x40) { + SPR_LOG("SPR TTE: %x_%x\n", ptag[3], ptag[2]); + SPR1transfer(ptag, 4); //Transfer Tag + } + + SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx\n", + ptag[1], ptag[0], spr1->qwc, id, spr1->madr); + + done = hwDmacSrcChain(spr1, id); + SPR1chain(); //Transfers the data set by the switch + + if (spr1->chcr & 0x80 && ptag[0] >> 31) { //Check TIE bit of CHCR and IRQ bit of tag + SPR_LOG("dmaIrq Set\n"); + + //SysPrintf("SPR1 TIE\n"); + spr1->qwc = 0; + break; + } + } + CPU_INT(9, cycles); + } else { // Interleave Mode + _SPR1interleave(); + } + +} + +void SPRTOinterrupt() +{ + spr1->chcr &= ~0x100; + hwDmacIrq(9); +} + diff --git a/pcsx2/SPR.h b/pcsx2/SPR.h index e263231fb4..53d4412cd3 100644 --- a/pcsx2/SPR.h +++ b/pcsx2/SPR.h @@ -1,29 +1,29 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __SPR_H__ -#define __SPR_H__ - -#include "Common.h" - -void sprInit(); -void dmaSPR0(); -void dmaSPR1(); -void SPRFROMinterrupt(); -void SPRTOinterrupt(); -#endif /* __SPR_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __SPR_H__ +#define __SPR_H__ + +#include "Common.h" + +void sprInit(); +void dmaSPR0(); +void dmaSPR1(); +void SPRFROMinterrupt(); +void SPRTOinterrupt(); +#endif /* __SPR_H__ */ diff --git a/pcsx2/SafeArray.h b/pcsx2/SafeArray.h index 821ff44863..745c391cff 100644 --- a/pcsx2/SafeArray.h +++ b/pcsx2/SafeArray.h @@ -1,254 +1,254 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __SAFEARRAY_H__ -#define __SAFEARRAY_H__ - -#include "MemcpyFast.h" - -extern void* __fastcall pcsx2_aligned_malloc(size_t size, size_t align); -extern void* __fastcall pcsx2_aligned_realloc(void* handle, size_t size, size_t align); -extern void pcsx2_aligned_free(void* pmem); - -// aligned_malloc: Implement/declare linux equivalents here! -#if !defined(_MSC_VER) && !defined(HAVE_ALIGNED_MALLOC) -# define _aligned_malloc pcsx2_aligned_malloc -# define _aligned_free pcsx2_aligned_free -# define _aligned_realloc pcsx2_aligned_realloc -#endif - -////////////////////////////////////////////////////////////// -// Safe deallocation macros -- always check pointer validity (non-null) -// and set pointer to null on deallocation. - -#define safe_delete( ptr ) \ - if( ptr != NULL ) { \ - delete ptr; \ - ptr = NULL; \ - } - -#define safe_delete_array( ptr ) \ - if( ptr != NULL ) { \ - delete[] ptr; \ - ptr = NULL; \ - } - -#define safe_free( ptr ) \ - if( ptr != NULL ) { \ - free( ptr ); \ - ptr = NULL; \ - } - -#define safe_aligned_free( ptr ) \ - if( ptr != NULL ) { \ - _aligned_free( ptr ); \ - ptr = NULL; \ - } - -#define SafeSysMunmap( ptr, size ) \ - if( ptr != NULL ) { \ - SysMunmap( (uptr)ptr, size ); \ - ptr = NULL; \ - } - - -////////////////////////////////////////////////////////////////// -// Handy little class for allocating a resizable memory block, complete with -// exception-based error handling and automatic cleanup. - -template< typename T > -class MemoryAlloc : public NoncopyableObject -{ -public: - static const int DefaultChunkSize = 0x1000 * sizeof(T); - -public: - const std::string Name; // user-assigned block name - int ChunkSize; - -protected: - T* m_ptr; - int m_size; // size of the allocation of memory - - const static std::string m_str_Unnamed; -protected: - // Internal contructor for use by derrived classes. This allws a derrived class to - // use its own memory allocation (with an aligned memory, for example). - // Throws: - // Exception::OutOfMemory if the allocated_mem pointr is NULL. - explicit MemoryAlloc( const std::string& name, T* allocated_mem, int initSize ) : - Name( name ) - , ChunkSize( DefaultChunkSize ) - , m_ptr( allocated_mem ) - , m_size( initSize ) - { - if( m_ptr == NULL ) - throw Exception::OutOfMemory(); - } - - virtual T* _virtual_realloc( int newsize ) - { - return (T*)realloc( m_ptr, newsize * sizeof(T) ); - } - -public: - virtual ~MemoryAlloc() - { - safe_free( m_ptr ); - } - - explicit MemoryAlloc( const std::string& name="Unnamed" ) : - Name( name ) - , ChunkSize( DefaultChunkSize ) - , m_ptr( NULL ) - , m_size( 0 ) - { - } - - explicit MemoryAlloc( int initialSize, const std::string& name="Unnamed" ) : - Name( name ) - , ChunkSize( DefaultChunkSize ) - , m_ptr( (T*)malloc( initialSize * sizeof(T) ) ) - , m_size( initialSize ) - { - if( m_ptr == NULL ) - throw Exception::OutOfMemory(); - } - - // Returns the size of the memory allocation, as according to the array type. - int GetLength() const { return m_size; } - // Returns the size of the memory allocation in bytes. - int GetSizeInBytes() const { return m_size * sizeof(T); } - - // Ensures that the allocation is large enough to fit data of the - // amount requested. The memory allocation is not resized smaller. - void MakeRoomFor( int blockSize ) - { - std::string temp; - - if( blockSize > m_size ) - { - const uint newalloc = blockSize + ChunkSize; - m_ptr = _virtual_realloc( newalloc ); - if( m_ptr == NULL ) - { - throw Exception::OutOfMemory( - "Out-of-memory on block re-allocation. " - "Old size: " + to_string( m_size ) + " bytes, " - "New size: " + to_string( newalloc ) + " bytes" - ); - } - m_size = newalloc; - } - } - - // Gets a pointer to the requested allocation index. - // DevBuilds : Throws std::out_of_range() if the index is invalid. - T *GetPtr( uint idx=0 ) { return _getPtr( idx ); } - const T *GetPtr( uint idx=0 ) const { return _getPtr( idx ); } - - // Gets an element of this memory allocation much as if it were an array. - // DevBuilds : Throws std::out_of_range() if the index is invalid. - T& operator[]( int idx ) { return *_getPtr( (uint)idx ); } - const T& operator[]( int idx ) const { return *_getPtr( (uint)idx ); } - - virtual MemoryAlloc* Clone() const - { - MemoryAlloc* retval = new MemoryAlloc( m_size ); - memcpy_fast( retval->GetPtr(), m_ptr, sizeof(T) * m_size ); - return retval; - } - -protected: - // A safe array index fetcher. Throws an exception if the array index - // is outside the bounds of the array. - // Performance Considerations: This function adds quite a bit of overhead - // to array indexing and thus should be done infrequently if used in - // time-critical situations. Indead of using it from inside loops, cache - // the pointer into a local variable and use stad (unsafe) C indexes. - T* _getPtr( uint i ) const - { -#ifdef PCSX2_DEVBUILD - if( i >= (uint)m_size ) - { - throw Exception::IndexBoundsFault( - "Index out of bounds on MemoryAlloc: " + Name + - " (index=" + to_string(i) + - ", size=" + to_string(m_size) + ")" - ); - } -#endif - return &m_ptr[i]; - } - -}; - -////////////////////////////////////////////////////////////////// -// Handy little class for allocating a resizable memory block, complete with -// exception-based error handling and automatic cleanup. -// This one supports aligned data allocations too! - -template< typename T, uint Alignment > -class SafeAlignedArray : public MemoryAlloc -{ -protected: - T* _virtual_realloc( int newsize ) - { - return (T*)_aligned_realloc( this->m_ptr, newsize * sizeof(T), Alignment ); - } - - // Appends "(align: xx)" to the name of the allocation in devel builds. - // Maybe useful,maybe not... no harm in atatching it. :D - string _getName( const string& src ) - { -#ifdef PCSX2_DEVBUILD - return src + "(align:" + to_string(Alignment) + ")"; -#endif - return src; - } - -public: - virtual ~SafeAlignedArray() - { - safe_aligned_free( this->m_ptr ); - // mptr is set to null, so the parent class's destructor won't re-free it. - } - - explicit SafeAlignedArray( const std::string& name="Unnamed" ) : - MemoryAlloc::MemoryAlloc( name ) - { - } - - explicit SafeAlignedArray( int initialSize, const std::string& name="Unnamed" ) : - MemoryAlloc::MemoryAlloc( - _getName(name), - (T*)_aligned_malloc( initialSize * sizeof(T), Alignment ), - initialSize - ) - { - } - - virtual SafeAlignedArray* Clone() const - { - SafeAlignedArray* retval = new SafeAlignedArray( this->m_size ); - memcpy_fast( retval->GetPtr(), this->m_ptr, sizeof(T) * this->m_size ); - return retval; - } -}; - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __SAFEARRAY_H__ +#define __SAFEARRAY_H__ + +#include "MemcpyFast.h" + +extern void* __fastcall pcsx2_aligned_malloc(size_t size, size_t align); +extern void* __fastcall pcsx2_aligned_realloc(void* handle, size_t size, size_t align); +extern void pcsx2_aligned_free(void* pmem); + +// aligned_malloc: Implement/declare linux equivalents here! +#if !defined(_MSC_VER) && !defined(HAVE_ALIGNED_MALLOC) +# define _aligned_malloc pcsx2_aligned_malloc +# define _aligned_free pcsx2_aligned_free +# define _aligned_realloc pcsx2_aligned_realloc +#endif + +////////////////////////////////////////////////////////////// +// Safe deallocation macros -- always check pointer validity (non-null) +// and set pointer to null on deallocation. + +#define safe_delete( ptr ) \ + if( ptr != NULL ) { \ + delete ptr; \ + ptr = NULL; \ + } + +#define safe_delete_array( ptr ) \ + if( ptr != NULL ) { \ + delete[] ptr; \ + ptr = NULL; \ + } + +#define safe_free( ptr ) \ + if( ptr != NULL ) { \ + free( ptr ); \ + ptr = NULL; \ + } + +#define safe_aligned_free( ptr ) \ + if( ptr != NULL ) { \ + _aligned_free( ptr ); \ + ptr = NULL; \ + } + +#define SafeSysMunmap( ptr, size ) \ + if( ptr != NULL ) { \ + SysMunmap( (uptr)ptr, size ); \ + ptr = NULL; \ + } + + +////////////////////////////////////////////////////////////////// +// Handy little class for allocating a resizable memory block, complete with +// exception-based error handling and automatic cleanup. + +template< typename T > +class MemoryAlloc : public NoncopyableObject +{ +public: + static const int DefaultChunkSize = 0x1000 * sizeof(T); + +public: + const std::string Name; // user-assigned block name + int ChunkSize; + +protected: + T* m_ptr; + int m_size; // size of the allocation of memory + + const static std::string m_str_Unnamed; +protected: + // Internal contructor for use by derrived classes. This allws a derrived class to + // use its own memory allocation (with an aligned memory, for example). + // Throws: + // Exception::OutOfMemory if the allocated_mem pointr is NULL. + explicit MemoryAlloc( const std::string& name, T* allocated_mem, int initSize ) : + Name( name ) + , ChunkSize( DefaultChunkSize ) + , m_ptr( allocated_mem ) + , m_size( initSize ) + { + if( m_ptr == NULL ) + throw Exception::OutOfMemory(); + } + + virtual T* _virtual_realloc( int newsize ) + { + return (T*)realloc( m_ptr, newsize * sizeof(T) ); + } + +public: + virtual ~MemoryAlloc() + { + safe_free( m_ptr ); + } + + explicit MemoryAlloc( const std::string& name="Unnamed" ) : + Name( name ) + , ChunkSize( DefaultChunkSize ) + , m_ptr( NULL ) + , m_size( 0 ) + { + } + + explicit MemoryAlloc( int initialSize, const std::string& name="Unnamed" ) : + Name( name ) + , ChunkSize( DefaultChunkSize ) + , m_ptr( (T*)malloc( initialSize * sizeof(T) ) ) + , m_size( initialSize ) + { + if( m_ptr == NULL ) + throw Exception::OutOfMemory(); + } + + // Returns the size of the memory allocation, as according to the array type. + int GetLength() const { return m_size; } + // Returns the size of the memory allocation in bytes. + int GetSizeInBytes() const { return m_size * sizeof(T); } + + // Ensures that the allocation is large enough to fit data of the + // amount requested. The memory allocation is not resized smaller. + void MakeRoomFor( int blockSize ) + { + std::string temp; + + if( blockSize > m_size ) + { + const uint newalloc = blockSize + ChunkSize; + m_ptr = _virtual_realloc( newalloc ); + if( m_ptr == NULL ) + { + throw Exception::OutOfMemory( + "Out-of-memory on block re-allocation. " + "Old size: " + to_string( m_size ) + " bytes, " + "New size: " + to_string( newalloc ) + " bytes" + ); + } + m_size = newalloc; + } + } + + // Gets a pointer to the requested allocation index. + // DevBuilds : Throws std::out_of_range() if the index is invalid. + T *GetPtr( uint idx=0 ) { return _getPtr( idx ); } + const T *GetPtr( uint idx=0 ) const { return _getPtr( idx ); } + + // Gets an element of this memory allocation much as if it were an array. + // DevBuilds : Throws std::out_of_range() if the index is invalid. + T& operator[]( int idx ) { return *_getPtr( (uint)idx ); } + const T& operator[]( int idx ) const { return *_getPtr( (uint)idx ); } + + virtual MemoryAlloc* Clone() const + { + MemoryAlloc* retval = new MemoryAlloc( m_size ); + memcpy_fast( retval->GetPtr(), m_ptr, sizeof(T) * m_size ); + return retval; + } + +protected: + // A safe array index fetcher. Throws an exception if the array index + // is outside the bounds of the array. + // Performance Considerations: This function adds quite a bit of overhead + // to array indexing and thus should be done infrequently if used in + // time-critical situations. Indead of using it from inside loops, cache + // the pointer into a local variable and use stad (unsafe) C indexes. + T* _getPtr( uint i ) const + { +#ifdef PCSX2_DEVBUILD + if( i >= (uint)m_size ) + { + throw Exception::IndexBoundsFault( + "Index out of bounds on MemoryAlloc: " + Name + + " (index=" + to_string(i) + + ", size=" + to_string(m_size) + ")" + ); + } +#endif + return &m_ptr[i]; + } + +}; + +////////////////////////////////////////////////////////////////// +// Handy little class for allocating a resizable memory block, complete with +// exception-based error handling and automatic cleanup. +// This one supports aligned data allocations too! + +template< typename T, uint Alignment > +class SafeAlignedArray : public MemoryAlloc +{ +protected: + T* _virtual_realloc( int newsize ) + { + return (T*)_aligned_realloc( this->m_ptr, newsize * sizeof(T), Alignment ); + } + + // Appends "(align: xx)" to the name of the allocation in devel builds. + // Maybe useful,maybe not... no harm in atatching it. :D + string _getName( const string& src ) + { +#ifdef PCSX2_DEVBUILD + return src + "(align:" + to_string(Alignment) + ")"; +#endif + return src; + } + +public: + virtual ~SafeAlignedArray() + { + safe_aligned_free( this->m_ptr ); + // mptr is set to null, so the parent class's destructor won't re-free it. + } + + explicit SafeAlignedArray( const std::string& name="Unnamed" ) : + MemoryAlloc::MemoryAlloc( name ) + { + } + + explicit SafeAlignedArray( int initialSize, const std::string& name="Unnamed" ) : + MemoryAlloc::MemoryAlloc( + _getName(name), + (T*)_aligned_malloc( initialSize * sizeof(T), Alignment ), + initialSize + ) + { + } + + virtual SafeAlignedArray* Clone() const + { + SafeAlignedArray* retval = new SafeAlignedArray( this->m_size ); + memcpy_fast( retval->GetPtr(), this->m_ptr, sizeof(T) * this->m_size ); + return retval; + } +}; + +#endif diff --git a/pcsx2/SamplProf.h b/pcsx2/SamplProf.h index d34988d7c7..9949716c75 100644 --- a/pcsx2/SamplProf.h +++ b/pcsx2/SamplProf.h @@ -1,32 +1,32 @@ -#ifndef _SAMPLPROF_H_ -#define _SAMPLPROF_H_ - -#include "Common.h" - -// The profiler does not have a Linux version yet. -// So for now we turn it into duds for non-Win32 platforms. - -#if !defined( _DEBUG ) && defined( WIN32 ) - -void ProfilerInit(); -void ProfilerTerm(); -void ProfilerSetEnabled(bool Enabled); -void ProfilerRegisterSource(const char* Name, const void* buff, u32 sz); -void ProfilerRegisterSource(const char* Name, const void* function); -void ProfilerTerminateSource( const char* Name ); - -#else - -// Disables the profiler in Debug & Linux builds. -// Profiling info in debug builds isn't much use anyway and the console -// popups are annoying when you're trying to trace debug logs and stuff. - -#define ProfilerInit() (void)0 -#define ProfilerTerm() (void)0 -#define ProfilerSetEnabled 0&& -#define ProfilerRegisterSource 0&& -#define ProfilerTerminateSource 0&& - -#endif - -#endif +#ifndef _SAMPLPROF_H_ +#define _SAMPLPROF_H_ + +#include "Common.h" + +// The profiler does not have a Linux version yet. +// So for now we turn it into duds for non-Win32 platforms. + +#if !defined( _DEBUG ) && defined( WIN32 ) + +void ProfilerInit(); +void ProfilerTerm(); +void ProfilerSetEnabled(bool Enabled); +void ProfilerRegisterSource(const char* Name, const void* buff, u32 sz); +void ProfilerRegisterSource(const char* Name, const void* function); +void ProfilerTerminateSource( const char* Name ); + +#else + +// Disables the profiler in Debug & Linux builds. +// Profiling info in debug builds isn't much use anyway and the console +// popups are annoying when you're trying to trace debug logs and stuff. + +#define ProfilerInit() (void)0 +#define ProfilerTerm() (void)0 +#define ProfilerSetEnabled 0&& +#define ProfilerRegisterSource 0&& +#define ProfilerTerminateSource 0&& + +#endif + +#endif diff --git a/pcsx2/SaveState.cpp b/pcsx2/SaveState.cpp index 52317fc3e9..9ffba35c58 100644 --- a/pcsx2/SaveState.cpp +++ b/pcsx2/SaveState.cpp @@ -1,370 +1,370 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "PsxCommon.h" -#include "SaveState.h" - -#include "CDVDisodrv.h" -#include "VUmicro.h" -#include "VU.h" -#include "iCore.h" -#include "iVUzerorec.h" - -#include "GS.h" -#include "COP0.h" -#include "Cache.h" - - -using namespace R5900; - -extern int g_psxWriteOk; -extern void recResetEE(); -extern void recResetIOP(); - -// STATES - -static void PreLoadPrep() -{ - SysResetExecutionState(); -} - -static void PostLoadPrep() -{ - memzero_obj(pCache); -// WriteCP0Status(cpuRegs.CP0.n.Status.val); - for(int i=0; i<48; i++) MapTLB(i); -} - -void SaveState::GetFilename( string& dest, int slot ) -{ - string elfcrcText; - ssprintf( elfcrcText, "%8.8X.%3.3d", ElfCRC, slot ); - Path::Combine( dest, SSTATES_DIR, elfcrcText ); -} - -string SaveState::GetFilename( int slot ) -{ - string elfcrcText, dest; - GetFilename( dest, slot ); - return dest; -} - - -SaveState::SaveState( const char* msg, const string& destination ) : m_version( g_SaveVersion ) -{ - Console::WriteLn( "%s %hs", params msg, &destination ); -} - -s32 CALLBACK gsSafeFreeze( int mode, freezeData *data ) -{ - if( mtgsThread != NULL ) - { - if( mode == 2 ) - return GSfreeze( 2, data ); - - // have to call in thread, otherwise weird stuff will start happening - mtgsThread->SendPointerPacket( GS_RINGTYPE_FREEZE, mode, data ); - mtgsWaitGS(); - return 0; - } - else - { - // Single threaded... - return GSfreeze( mode, data ); - } -} - -void SaveState::FreezeAll() -{ - if( IsLoading() ) - PreLoadPrep(); - - FreezeMem(PS2MEM_BASE, Ps2MemSize::Base); // 32 MB main memory - FreezeMem(PS2MEM_ROM, Ps2MemSize::Rom); // 4 mb rom memory - FreezeMem(PS2MEM_ROM1, Ps2MemSize::Rom1); // 256kb rom1 memory - FreezeMem(PS2MEM_SCRATCH, Ps2MemSize::Scratch); // scratch pad - FreezeMem(PS2MEM_HW, Ps2MemSize::Hardware); // hardware memory - - Freeze(cpuRegs); // cpu regs + COP0 - Freeze(psxRegs); // iop regs - Freeze(fpuRegs); // fpu regs - Freeze(tlb); // tlbs - - Freeze(EEsCycle); - Freeze(EEoCycle); - Freeze(psxRegs.cycle); // used to be IOPoCycle. This retains compatibility. - Freeze(g_nextBranchCycle); - Freeze(g_psxNextBranchCycle); - - Freeze(s_iLastCOP0Cycle); - if( m_version >= 0x7a30000e ) - Freeze(s_iLastPERFCycle); - - Freeze(g_psxWriteOk); - - //hope didn't forgot any cpu.... - - rcntFreeze(); - gsFreeze(); - vuMicroFreeze(); - vif0Freeze(); - vif1Freeze(); - sifFreeze(); - ipuFreeze(); - - // iop now - FreezeMem(psxM, Ps2MemSize::IopRam); // 2 MB main memory - FreezeMem(psxH, Ps2MemSize::IopHardware); // hardware memory - //FreezeMem(psxS, 0x00010000); // sif memory - - sioFreeze(); - cdrFreeze(); - cdvdFreeze(); - psxRcntFreeze(); - sio2Freeze(); - - FreezePlugin( "GS", gsSafeFreeze ); - FreezePlugin( "SPU2", SPU2freeze ); - FreezePlugin( "DEV9", DEV9freeze ); - FreezePlugin( "USB", USBfreeze ); - - if( IsLoading() ) - PostLoadPrep(); -} - -// this function is yet incomplete. Version numbers hare still < 0x12 so it won't be run. -// (which is good because it won't work :P) -void SaveState::_testCdvdCrc() -{ - /*if( GetVersion() < 0x0012 ) return; - - u32 thiscrc = ElfCRC; - Freeze( thiscrc ); - if( thiscrc != ElfCRC ) - throw Exception::StateCrcMismatch( thiscrc, ElfCRC );*/ -} - -///////////////////////////////////////////////////////////////////////////// -// gzipped to/from disk state saves implementation - -gzBaseStateInfo::gzBaseStateInfo( const char* msg, const string& filename ) : - SaveState( msg, filename ) -, m_filename( filename ) -, m_file( NULL ) -{ -} - -gzBaseStateInfo::~gzBaseStateInfo() -{ - if( m_file != NULL ) - { - gzclose( m_file ); - m_file = NULL; - } -} - - -gzSavingState::gzSavingState( const string& filename ) : - gzBaseStateInfo( _("Saving state to: "), filename ) -{ - m_file = gzopen(filename.c_str(), "wb"); - if( m_file == NULL ) - throw Exception::FileNotFound(); - - Freeze( m_version ); -} - - -gzLoadingState::gzLoadingState( const string& filename ) : - gzBaseStateInfo( _("Loading state from: "), filename ) -{ - m_file = gzopen(filename.c_str(), "rb"); - if( m_file == NULL ) - throw Exception::FileNotFound(); - - gzread( m_file, &m_version, 4 ); - - if( m_version != g_SaveVersion ) - { - if( ( m_version >> 16 ) == 0x7a30 ) - { - Console::Error( - "Savestate load aborted:\n" - "\tVTLB edition cannot safely load savestates created by the VM edition." ); - throw Exception::UnsupportedStateVersion( m_version ); - } - } - - _testCdvdCrc(); -} - -gzLoadingState::~gzLoadingState() { } - - -void gzSavingState::FreezeMem( void* data, int size ) -{ - gzwrite( m_file, data, size ); -} - -void gzLoadingState::FreezeMem( void* data, int size ) -{ - gzread( m_file, data, size ); - if( gzeof( m_file ) ) - throw Exception::BadSavedState( m_filename ); -} - -void gzSavingState::FreezePlugin( const char* name, s32 (CALLBACK *freezer)(int mode, freezeData *data) ) -{ - Console::WriteLn( "\tSaving %s", params name ); - freezeData fP = { 0, NULL }; - - if (freezer(FREEZE_SIZE, &fP) == -1) - throw Exception::FreezePluginFailure( name, "saving" ); - - gzwrite(m_file, &fP.size, sizeof(fP.size)); - if( fP.size == 0 ) return; - - fP.data = (s8*)malloc(fP.size); - if (fP.data == NULL) - throw Exception::OutOfMemory(); - - if(freezer(FREEZE_SAVE, &fP) == -1) - throw Exception::FreezePluginFailure( name, "saving" ); - - if (fP.size) - { - gzwrite(m_file, fP.data, fP.size); - free(fP.data); - } -} - -void gzLoadingState::FreezePlugin( const char* name, s32 (CALLBACK *freezer)(int mode, freezeData *data) ) -{ - freezeData fP = { 0, NULL }; - Console::WriteLn( "\tLoading %s", params name ); - - gzread(m_file, &fP.size, sizeof(fP.size)); - if( fP.size == 0 ) return; - - fP.data = (s8*)malloc(fP.size); - if (fP.data == NULL) - throw Exception::OutOfMemory(); - gzread(m_file, fP.data, fP.size); - - if( gzeof( m_file ) ) - throw Exception::BadSavedState( m_filename ); - - if(freezer(FREEZE_LOAD, &fP) == -1) - throw Exception::FreezePluginFailure( name, "loading" ); - - if (fP.size) free(fP.data); -} - -////////////////////////////////////////////////////////////////////////////////// -// uncompressed to/from memory state saves implementation - -memBaseStateInfo::memBaseStateInfo( MemoryAlloc& memblock, const char* msg ) : - SaveState( msg, "Memory" ) -, m_memory( memblock ) -, m_idx( 0 ) -{ - // Always clear the MTGS thread state. - mtgsWaitGS(); -} - -memSavingState::memSavingState( MemoryAlloc& save_to ) : memBaseStateInfo( save_to, _("Saving state to: ") ) -{ - save_to.ChunkSize = ReallocThreshold; - save_to.MakeRoomFor( MemoryBaseAllocSize ); -} - -// Saving of state data to a memory buffer -void memSavingState::FreezeMem( void* data, int size ) -{ - const int end = m_idx+size; - m_memory.MakeRoomFor( end ); - - u8* dest = (u8*)m_memory.GetPtr(); - const u8* src = (u8*)data; - - for( ; m_idx& load_from ) : - memBaseStateInfo( load_from, _("Loading state from: ") ) -{ -} - -memLoadingState::~memLoadingState() { } - -// Loading of state data from a memory buffer... -void memLoadingState::FreezeMem( void* data, int size ) -{ - const int end = m_idx+size; - const u8* src = (u8*)m_memory.GetPtr(); - u8* dest = (u8*)data; - - for( ; m_idx m_memory.GetSizeInBytes() ) - { - assert(0); - throw Exception::BadSavedState( "memory" ); - } - - fP.data = ((s8*)m_memory.GetPtr()) + m_idx; - if(freezer(FREEZE_LOAD, &fP) == -1) - throw Exception::FreezePluginFailure( name, "loading" ); - - m_idx += fP.size; -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "PsxCommon.h" +#include "SaveState.h" + +#include "CDVDisodrv.h" +#include "VUmicro.h" +#include "VU.h" +#include "iCore.h" +#include "iVUzerorec.h" + +#include "GS.h" +#include "COP0.h" +#include "Cache.h" + + +using namespace R5900; + +extern int g_psxWriteOk; +extern void recResetEE(); +extern void recResetIOP(); + +// STATES + +static void PreLoadPrep() +{ + SysResetExecutionState(); +} + +static void PostLoadPrep() +{ + memzero_obj(pCache); +// WriteCP0Status(cpuRegs.CP0.n.Status.val); + for(int i=0; i<48; i++) MapTLB(i); +} + +void SaveState::GetFilename( string& dest, int slot ) +{ + string elfcrcText; + ssprintf( elfcrcText, "%8.8X.%3.3d", ElfCRC, slot ); + Path::Combine( dest, SSTATES_DIR, elfcrcText ); +} + +string SaveState::GetFilename( int slot ) +{ + string elfcrcText, dest; + GetFilename( dest, slot ); + return dest; +} + + +SaveState::SaveState( const char* msg, const string& destination ) : m_version( g_SaveVersion ) +{ + Console::WriteLn( "%s %hs", params msg, &destination ); +} + +s32 CALLBACK gsSafeFreeze( int mode, freezeData *data ) +{ + if( mtgsThread != NULL ) + { + if( mode == 2 ) + return GSfreeze( 2, data ); + + // have to call in thread, otherwise weird stuff will start happening + mtgsThread->SendPointerPacket( GS_RINGTYPE_FREEZE, mode, data ); + mtgsWaitGS(); + return 0; + } + else + { + // Single threaded... + return GSfreeze( mode, data ); + } +} + +void SaveState::FreezeAll() +{ + if( IsLoading() ) + PreLoadPrep(); + + FreezeMem(PS2MEM_BASE, Ps2MemSize::Base); // 32 MB main memory + FreezeMem(PS2MEM_ROM, Ps2MemSize::Rom); // 4 mb rom memory + FreezeMem(PS2MEM_ROM1, Ps2MemSize::Rom1); // 256kb rom1 memory + FreezeMem(PS2MEM_SCRATCH, Ps2MemSize::Scratch); // scratch pad + FreezeMem(PS2MEM_HW, Ps2MemSize::Hardware); // hardware memory + + Freeze(cpuRegs); // cpu regs + COP0 + Freeze(psxRegs); // iop regs + Freeze(fpuRegs); // fpu regs + Freeze(tlb); // tlbs + + Freeze(EEsCycle); + Freeze(EEoCycle); + Freeze(psxRegs.cycle); // used to be IOPoCycle. This retains compatibility. + Freeze(g_nextBranchCycle); + Freeze(g_psxNextBranchCycle); + + Freeze(s_iLastCOP0Cycle); + if( m_version >= 0x7a30000e ) + Freeze(s_iLastPERFCycle); + + Freeze(g_psxWriteOk); + + //hope didn't forgot any cpu.... + + rcntFreeze(); + gsFreeze(); + vuMicroFreeze(); + vif0Freeze(); + vif1Freeze(); + sifFreeze(); + ipuFreeze(); + + // iop now + FreezeMem(psxM, Ps2MemSize::IopRam); // 2 MB main memory + FreezeMem(psxH, Ps2MemSize::IopHardware); // hardware memory + //FreezeMem(psxS, 0x00010000); // sif memory + + sioFreeze(); + cdrFreeze(); + cdvdFreeze(); + psxRcntFreeze(); + sio2Freeze(); + + FreezePlugin( "GS", gsSafeFreeze ); + FreezePlugin( "SPU2", SPU2freeze ); + FreezePlugin( "DEV9", DEV9freeze ); + FreezePlugin( "USB", USBfreeze ); + + if( IsLoading() ) + PostLoadPrep(); +} + +// this function is yet incomplete. Version numbers hare still < 0x12 so it won't be run. +// (which is good because it won't work :P) +void SaveState::_testCdvdCrc() +{ + /*if( GetVersion() < 0x0012 ) return; + + u32 thiscrc = ElfCRC; + Freeze( thiscrc ); + if( thiscrc != ElfCRC ) + throw Exception::StateCrcMismatch( thiscrc, ElfCRC );*/ +} + +///////////////////////////////////////////////////////////////////////////// +// gzipped to/from disk state saves implementation + +gzBaseStateInfo::gzBaseStateInfo( const char* msg, const string& filename ) : + SaveState( msg, filename ) +, m_filename( filename ) +, m_file( NULL ) +{ +} + +gzBaseStateInfo::~gzBaseStateInfo() +{ + if( m_file != NULL ) + { + gzclose( m_file ); + m_file = NULL; + } +} + + +gzSavingState::gzSavingState( const string& filename ) : + gzBaseStateInfo( _("Saving state to: "), filename ) +{ + m_file = gzopen(filename.c_str(), "wb"); + if( m_file == NULL ) + throw Exception::FileNotFound(); + + Freeze( m_version ); +} + + +gzLoadingState::gzLoadingState( const string& filename ) : + gzBaseStateInfo( _("Loading state from: "), filename ) +{ + m_file = gzopen(filename.c_str(), "rb"); + if( m_file == NULL ) + throw Exception::FileNotFound(); + + gzread( m_file, &m_version, 4 ); + + if( m_version != g_SaveVersion ) + { + if( ( m_version >> 16 ) == 0x7a30 ) + { + Console::Error( + "Savestate load aborted:\n" + "\tVTLB edition cannot safely load savestates created by the VM edition." ); + throw Exception::UnsupportedStateVersion( m_version ); + } + } + + _testCdvdCrc(); +} + +gzLoadingState::~gzLoadingState() { } + + +void gzSavingState::FreezeMem( void* data, int size ) +{ + gzwrite( m_file, data, size ); +} + +void gzLoadingState::FreezeMem( void* data, int size ) +{ + gzread( m_file, data, size ); + if( gzeof( m_file ) ) + throw Exception::BadSavedState( m_filename ); +} + +void gzSavingState::FreezePlugin( const char* name, s32 (CALLBACK *freezer)(int mode, freezeData *data) ) +{ + Console::WriteLn( "\tSaving %s", params name ); + freezeData fP = { 0, NULL }; + + if (freezer(FREEZE_SIZE, &fP) == -1) + throw Exception::FreezePluginFailure( name, "saving" ); + + gzwrite(m_file, &fP.size, sizeof(fP.size)); + if( fP.size == 0 ) return; + + fP.data = (s8*)malloc(fP.size); + if (fP.data == NULL) + throw Exception::OutOfMemory(); + + if(freezer(FREEZE_SAVE, &fP) == -1) + throw Exception::FreezePluginFailure( name, "saving" ); + + if (fP.size) + { + gzwrite(m_file, fP.data, fP.size); + free(fP.data); + } +} + +void gzLoadingState::FreezePlugin( const char* name, s32 (CALLBACK *freezer)(int mode, freezeData *data) ) +{ + freezeData fP = { 0, NULL }; + Console::WriteLn( "\tLoading %s", params name ); + + gzread(m_file, &fP.size, sizeof(fP.size)); + if( fP.size == 0 ) return; + + fP.data = (s8*)malloc(fP.size); + if (fP.data == NULL) + throw Exception::OutOfMemory(); + gzread(m_file, fP.data, fP.size); + + if( gzeof( m_file ) ) + throw Exception::BadSavedState( m_filename ); + + if(freezer(FREEZE_LOAD, &fP) == -1) + throw Exception::FreezePluginFailure( name, "loading" ); + + if (fP.size) free(fP.data); +} + +////////////////////////////////////////////////////////////////////////////////// +// uncompressed to/from memory state saves implementation + +memBaseStateInfo::memBaseStateInfo( MemoryAlloc& memblock, const char* msg ) : + SaveState( msg, "Memory" ) +, m_memory( memblock ) +, m_idx( 0 ) +{ + // Always clear the MTGS thread state. + mtgsWaitGS(); +} + +memSavingState::memSavingState( MemoryAlloc& save_to ) : memBaseStateInfo( save_to, _("Saving state to: ") ) +{ + save_to.ChunkSize = ReallocThreshold; + save_to.MakeRoomFor( MemoryBaseAllocSize ); +} + +// Saving of state data to a memory buffer +void memSavingState::FreezeMem( void* data, int size ) +{ + const int end = m_idx+size; + m_memory.MakeRoomFor( end ); + + u8* dest = (u8*)m_memory.GetPtr(); + const u8* src = (u8*)data; + + for( ; m_idx& load_from ) : + memBaseStateInfo( load_from, _("Loading state from: ") ) +{ +} + +memLoadingState::~memLoadingState() { } + +// Loading of state data from a memory buffer... +void memLoadingState::FreezeMem( void* data, int size ) +{ + const int end = m_idx+size; + const u8* src = (u8*)m_memory.GetPtr(); + u8* dest = (u8*)data; + + for( ; m_idx m_memory.GetSizeInBytes() ) + { + assert(0); + throw Exception::BadSavedState( "memory" ); + } + + fP.data = ((s8*)m_memory.GetPtr()) + m_idx; + if(freezer(FREEZE_LOAD, &fP) == -1) + throw Exception::FreezePluginFailure( name, "loading" ); + + m_idx += fP.size; +} diff --git a/pcsx2/SaveState.h b/pcsx2/SaveState.h index a85ee83955..325567630f 100644 --- a/pcsx2/SaveState.h +++ b/pcsx2/SaveState.h @@ -1,205 +1,205 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef _SAVESTATE_H_ -#define _SAVESTATE_H_ - -#include - -// This shouldn't break Win compiles, but it does. -#ifdef __LINUX__ -#include "PS2Edefs.h" -#endif - -// Savestate Versioning! -// If you make changes to the savestate version, please increment the value below. - -static const u32 g_SaveVersion = 0x8b400002; - -// this function is meant to be sued in the place of GSfreeze, and provides a safe layer -// between the GS saving function and the MTGS's needs. :) -extern s32 CALLBACK gsSafeFreeze( int mode, freezeData *data ); - -// This class provides the base API for both loading and saving savestates. -// Normally you'll want to use one of the four "functional" derrived classes rather -// than this class directly: gzLoadingState, gzSavingState (gzipped disk-saved -// states), and memLoadingState, memSavingState (uncompressed memory states). -class SaveState -{ -protected: - u32 m_version; // version of the savestate being loaded. - -public: - SaveState( const char* msg, const string& destination ); - virtual ~SaveState() { } - - static void GetFilename( string& dest, int slot ); - static string GetFilename( int slot ); - - // Gets the version of savestate that this object is acting on. - // The version refers to the low 16 bits only (high 16 bits classifies Pcsx2 build types) - u32 GetVersion() const - { - // HACK! Matches the vTLB build versions with VM - return (m_version & 0xffff) + 0x10; - } - - // Loads or saves the entire emulation state. - // Note: The Cpu state must be reset, and plugins *open*, prior to Defrosting - // (loading) a state! - void FreezeAll(); - - // Loads or saves an arbitrary data type. Usable on atomic types, structs, and arrays. - // For dynamically allocated pointers use FreezeMem instead. - template - void Freeze( T& data ) - { - FreezeMem( &data, sizeof( T ) ); - } - - // FreezeLegacy can be used to load structures short of their full size, which is - // useful for loading structures that have had new stuff added since a previous version. - template - void FreezeLegacy( T& data, int sizeOfNewStuff ) - { - FreezeMem( &data, sizeof( T ) - sizeOfNewStuff ); - } - - // Loads or saves a plugin. Plugin name is for console logging purposes. - virtual void FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) )=0; - - // Loads or saves a memory block. - virtual void FreezeMem( void* data, int size )=0; - - // Returns true if this object is a StateSaving type object. - virtual bool IsSaving() const=0; - - // Returns true if this object is a StateLoading type object. - bool IsLoading() const { return !IsSaving(); } - - // note: gsFreeze() needs to be public because of the GSState recorder. - -public: - virtual void gsFreeze(); - -protected: - - // Used internally by constructors to check the cdvd's crc against the CRC of the savestate. - // This allows for proper exception handling of changed CDs on-the-fly. - void _testCdvdCrc(); - - - // Load/Save functions for the various components of our glorious emulator! - - void rcntFreeze(); - void vuMicroFreeze(); - void vif0Freeze(); - void vif1Freeze(); - void sifFreeze(); - void ipuFreeze(); - - void sioFreeze(); - void cdrFreeze(); - void cdvdFreeze(); - void psxRcntFreeze(); - void sio2Freeze(); - - // called by gsFreeze automatically. - void mtgsFreeze(); - -}; - -///////////////////////////////////////////////////////////////////////////////// -// Class Declarations for Savestates using zlib - -class gzBaseStateInfo : public SaveState -{ -protected: - const string m_filename; - gzFile m_file; // used for reading/writing disk saves - -public: - gzBaseStateInfo( const char* msg, const string& filename ); - - virtual ~gzBaseStateInfo(); -}; - -class gzSavingState : public gzBaseStateInfo -{ -public: - virtual ~gzSavingState() {} - gzSavingState( const string& filename ) ; - void FreezePlugin( const char* name, s32(CALLBACK *freezer)(int mode, freezeData *data) ); - void FreezeMem( void* data, int size ); - bool IsSaving() const { return true; } -}; - -class gzLoadingState : public gzBaseStateInfo -{ -public: - virtual ~gzLoadingState(); - gzLoadingState( const string& filename ); - - void FreezePlugin( const char* name, s32(CALLBACK *freezer)(int mode, freezeData *data) ); - void FreezeMem( void* data, int size ); - bool IsSaving() const { return false; } - bool Finished() const { return !!gzeof( m_file ); } -}; - -////////////////////////////////////////////////////////////////////////////////// - -class memBaseStateInfo : public SaveState -{ -protected: - MemoryAlloc& m_memory; - int m_idx; // current read/write index of the allocation - -public: - virtual ~memBaseStateInfo() { } - memBaseStateInfo( MemoryAlloc& memblock, const char* msg ); -}; - -class memSavingState : public memBaseStateInfo -{ -protected: - static const int ReallocThreshold = 0x200000; // 256k reallocation block size. - static const int MemoryBaseAllocSize = 0x02a00000; // 42 meg base alloc - -public: - virtual ~memSavingState() { } - memSavingState( MemoryAlloc& save_to ); - - void FreezePlugin( const char* name, s32(CALLBACK *freezer)(int mode, freezeData *data) ); - // Saving of state data to a memory buffer - void FreezeMem( void* data, int size ); - bool IsSaving() const { return true; } -}; - -class memLoadingState : public memBaseStateInfo -{ -public: - virtual ~memLoadingState(); - memLoadingState(MemoryAlloc& load_from ); - - void FreezePlugin( const char* name, s32(CALLBACK *freezer)(int mode, freezeData *data) ); - // Loading of state data from a memory buffer... - void FreezeMem( void* data, int size ); - bool IsSaving() const { return false; } -}; - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef _SAVESTATE_H_ +#define _SAVESTATE_H_ + +#include + +// This shouldn't break Win compiles, but it does. +#ifdef __LINUX__ +#include "PS2Edefs.h" +#endif + +// Savestate Versioning! +// If you make changes to the savestate version, please increment the value below. + +static const u32 g_SaveVersion = 0x8b400002; + +// this function is meant to be sued in the place of GSfreeze, and provides a safe layer +// between the GS saving function and the MTGS's needs. :) +extern s32 CALLBACK gsSafeFreeze( int mode, freezeData *data ); + +// This class provides the base API for both loading and saving savestates. +// Normally you'll want to use one of the four "functional" derrived classes rather +// than this class directly: gzLoadingState, gzSavingState (gzipped disk-saved +// states), and memLoadingState, memSavingState (uncompressed memory states). +class SaveState +{ +protected: + u32 m_version; // version of the savestate being loaded. + +public: + SaveState( const char* msg, const string& destination ); + virtual ~SaveState() { } + + static void GetFilename( string& dest, int slot ); + static string GetFilename( int slot ); + + // Gets the version of savestate that this object is acting on. + // The version refers to the low 16 bits only (high 16 bits classifies Pcsx2 build types) + u32 GetVersion() const + { + // HACK! Matches the vTLB build versions with VM + return (m_version & 0xffff) + 0x10; + } + + // Loads or saves the entire emulation state. + // Note: The Cpu state must be reset, and plugins *open*, prior to Defrosting + // (loading) a state! + void FreezeAll(); + + // Loads or saves an arbitrary data type. Usable on atomic types, structs, and arrays. + // For dynamically allocated pointers use FreezeMem instead. + template + void Freeze( T& data ) + { + FreezeMem( &data, sizeof( T ) ); + } + + // FreezeLegacy can be used to load structures short of their full size, which is + // useful for loading structures that have had new stuff added since a previous version. + template + void FreezeLegacy( T& data, int sizeOfNewStuff ) + { + FreezeMem( &data, sizeof( T ) - sizeOfNewStuff ); + } + + // Loads or saves a plugin. Plugin name is for console logging purposes. + virtual void FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) )=0; + + // Loads or saves a memory block. + virtual void FreezeMem( void* data, int size )=0; + + // Returns true if this object is a StateSaving type object. + virtual bool IsSaving() const=0; + + // Returns true if this object is a StateLoading type object. + bool IsLoading() const { return !IsSaving(); } + + // note: gsFreeze() needs to be public because of the GSState recorder. + +public: + virtual void gsFreeze(); + +protected: + + // Used internally by constructors to check the cdvd's crc against the CRC of the savestate. + // This allows for proper exception handling of changed CDs on-the-fly. + void _testCdvdCrc(); + + + // Load/Save functions for the various components of our glorious emulator! + + void rcntFreeze(); + void vuMicroFreeze(); + void vif0Freeze(); + void vif1Freeze(); + void sifFreeze(); + void ipuFreeze(); + + void sioFreeze(); + void cdrFreeze(); + void cdvdFreeze(); + void psxRcntFreeze(); + void sio2Freeze(); + + // called by gsFreeze automatically. + void mtgsFreeze(); + +}; + +///////////////////////////////////////////////////////////////////////////////// +// Class Declarations for Savestates using zlib + +class gzBaseStateInfo : public SaveState +{ +protected: + const string m_filename; + gzFile m_file; // used for reading/writing disk saves + +public: + gzBaseStateInfo( const char* msg, const string& filename ); + + virtual ~gzBaseStateInfo(); +}; + +class gzSavingState : public gzBaseStateInfo +{ +public: + virtual ~gzSavingState() {} + gzSavingState( const string& filename ) ; + void FreezePlugin( const char* name, s32(CALLBACK *freezer)(int mode, freezeData *data) ); + void FreezeMem( void* data, int size ); + bool IsSaving() const { return true; } +}; + +class gzLoadingState : public gzBaseStateInfo +{ +public: + virtual ~gzLoadingState(); + gzLoadingState( const string& filename ); + + void FreezePlugin( const char* name, s32(CALLBACK *freezer)(int mode, freezeData *data) ); + void FreezeMem( void* data, int size ); + bool IsSaving() const { return false; } + bool Finished() const { return !!gzeof( m_file ); } +}; + +////////////////////////////////////////////////////////////////////////////////// + +class memBaseStateInfo : public SaveState +{ +protected: + MemoryAlloc& m_memory; + int m_idx; // current read/write index of the allocation + +public: + virtual ~memBaseStateInfo() { } + memBaseStateInfo( MemoryAlloc& memblock, const char* msg ); +}; + +class memSavingState : public memBaseStateInfo +{ +protected: + static const int ReallocThreshold = 0x200000; // 256k reallocation block size. + static const int MemoryBaseAllocSize = 0x02a00000; // 42 meg base alloc + +public: + virtual ~memSavingState() { } + memSavingState( MemoryAlloc& save_to ); + + void FreezePlugin( const char* name, s32(CALLBACK *freezer)(int mode, freezeData *data) ); + // Saving of state data to a memory buffer + void FreezeMem( void* data, int size ); + bool IsSaving() const { return true; } +}; + +class memLoadingState : public memBaseStateInfo +{ +public: + virtual ~memLoadingState(); + memLoadingState(MemoryAlloc& load_from ); + + void FreezePlugin( const char* name, s32(CALLBACK *freezer)(int mode, freezeData *data) ); + // Loading of state data from a memory buffer... + void FreezeMem( void* data, int size ); + bool IsSaving() const { return false; } +}; + #endif \ No newline at end of file diff --git a/pcsx2/Sif.cpp b/pcsx2/Sif.cpp index 4a5cee18e7..7339c7c7ef 100644 --- a/pcsx2/Sif.cpp +++ b/pcsx2/Sif.cpp @@ -1,608 +1,608 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Sif.h" -#include "IopHw.h" -#include "Sifcmd.h" - -using namespace std; - -#define sif0dma ((DMACh*)&PS2MEM_HW[0xc000]) -#define sif1dma ((DMACh*)&PS2MEM_HW[0xc400]) -#define sif2dma ((DMACh*)&PS2MEM_HW[0xc800]) - -int eeSifTransfer; - -DMACh *sif0ch; -DMACh *sif1ch; -DMACh *sif2ch; - - -#define FIFO_SIF0_W 128 -#define FIFO_SIF1_W 128 - -struct _sif0{ - u32 fifoData[FIFO_SIF0_W]; - int fifoReadPos; - int fifoWritePos; - int fifoSize; - int chain; - int end; - int tagMode; - int counter; - struct sifData sifData; -}; - -struct _sif1 { - u32 fifoData[FIFO_SIF1_W]; - int fifoReadPos; - int fifoWritePos; - int fifoSize; - int chain; - int end; - int tagMode; - int counter; -}; - -static _sif0 sif0; -static _sif1 sif1; - -int eesifbusy[2] = { 0, 0 }; -extern int iopsifbusy[2]; - -void sifInit() -{ - memzero_obj(sif0); - memzero_obj(sif1); - memzero_obj(eesifbusy); - memzero_obj(iopsifbusy); -} - -static __forceinline void SIF0write(u32 *from, int words) -{ - /*if(FIFO_SIF0_W < (words+sif0.fifoWritePos)) {*/ - - const int wP0 = min((FIFO_SIF0_W-sif0.fifoWritePos),words); - const int wP1 = words - wP0; - - memcpy(&sif0.fifoData[sif0.fifoWritePos], from, wP0 << 2); - memcpy(&sif0.fifoData[0], &from[wP0], wP1 << 2); - - sif0.fifoWritePos = (sif0.fifoWritePos + words) & (FIFO_SIF0_W-1); - /*} - else - { - memcpy_fast(&sif0.fifoData[sif0.fifoWritePos], from, words << 2); - sif0.fifoWritePos += words; - }*/ - - sif0.fifoSize += words; - SIF_LOG(" SIF0 + %d = %d (pos=%d)\n", words, sif0.fifoSize, sif0.fifoWritePos); -} - -static __forceinline void SIF0read(u32 *to, int words) -{ - /*if(FIFO_SIF0_W < (words+sif0.fifoReadPos)) - {*/ - const int wP0 = min((FIFO_SIF0_W-sif0.fifoReadPos),words); - const int wP1 = words - wP0; - - memcpy(to, &sif0.fifoData[sif0.fifoReadPos], wP0 << 2); - memcpy(&to[wP0], &sif0.fifoData[0], wP1 << 2); - - sif0.fifoReadPos = (sif0.fifoReadPos + words) & (FIFO_SIF0_W-1); - /*} - else - { - memcpy_fast(to, &sif0.fifoData[sif0.fifoReadPos], words << 2); - sif0.fifoReadPos += words; - }*/ - - sif0.fifoSize -= words; - SIF_LOG(" SIF0 - %d = %d (pos=%d)\n", words, sif0.fifoSize, sif0.fifoReadPos); -} - -__forceinline void SIF1write(u32 *from, int words) -{ - /*if(FIFO_SIF1_W < (words+sif1.fifoWritePos)) - {*/ - const int wP0 = min((FIFO_SIF1_W-sif1.fifoWritePos),words); - const int wP1 = words - wP0; - - memcpy(&sif1.fifoData[sif1.fifoWritePos], from, wP0 << 2); - memcpy(&sif1.fifoData[0], &from[wP0], wP1 << 2); - - sif1.fifoWritePos = (sif1.fifoWritePos + words) & (FIFO_SIF1_W-1); - /*} - else - { - memcpy_fast(&sif1.fifoData[sif1.fifoWritePos], from, words << 2); - sif1.fifoWritePos += words; - }*/ - - sif1.fifoSize += words; - SIF_LOG(" SIF1 + %d = %d (pos=%d)\n", words, sif1.fifoSize, sif1.fifoWritePos); -} - -static __forceinline void SIF1read(u32 *to, int words) -{ - /*if(FIFO_SIF1_W < (words+sif1.fifoReadPos)) - {*/ - const int wP0 = min((FIFO_SIF1_W-sif1.fifoReadPos),words); - const int wP1 = words - wP0; - - memcpy(to, &sif1.fifoData[sif1.fifoReadPos], wP0 << 2); - memcpy(&to[wP0], &sif1.fifoData[0], wP1 << 2); - - sif1.fifoReadPos = (sif1.fifoReadPos + words) & (FIFO_SIF1_W-1); - /*} - else - { - memcpy_fast(to, &sif1.fifoData[sif1.fifoReadPos], words << 2); - sif1.fifoReadPos += words; - }*/ - - sif1.fifoSize -= words; - SIF_LOG(" SIF1 - %d = %d (pos=%d)\n", words, sif1.fifoSize, sif1.fifoReadPos); -} - -__forceinline void SIF0Dma() -{ - u32 *ptag; - int notDone = 1; - int cycles = 0, psxCycles = 0; - - SIF_LOG("SIF0 DMA start...\n"); - - do - { - - /*if ((psHu32(DMAC_CTRL) & 0xC0)) { - SysPrintf("DMA Stall Control %x\n",(psHu32(DMAC_CTRL) & 0xC0)); - }*/ - if(iopsifbusy[0] == 1) // If EE SIF0 is enabled - { - //int size = sif0.counter; //HW_DMA9_BCR >> 16; - - if(sif0.counter == 0) // If there's no more to transfer - { - // Note.. add normal mode here - if (sif0.sifData.data & 0xC0000000) // If NORMAL mode or end of CHAIN, or interrupt then stop DMA - { - SIF_LOG(" IOP SIF Stopped\n"); - - // Stop & signal interrupts on IOP - //HW_DMA9_CHCR &= ~0x01000000; //reset TR flag - //psxDmaInterrupt2(2); - iopsifbusy[0] = 0; - PSX_INT(IopEvt_SIF0, psxCycles); - // iop is 1/8th the clock rate of the EE and psxcycles is in words (not quadwords) - // So when we're all done, the equation looks like thus: - //PSX_INT(IopEvt_SIF0, ( ( psxCycles*BIAS ) / 4 ) / 8); - - //hwIntcIrq(INTC_SBUS); - sif0.sifData.data = 0; - notDone = 0; - } - else // Chain mode - { - // Process DMA tag at HW_DMA9_TADR - sif0.sifData = *(struct sifData *)PSXM(HW_DMA9_TADR); - - sif0.sifData.words = (sif0.sifData.words + 3) & 0xfffffffc; // Round up to nearest 4. - - SIF0write((u32*)PSXM(HW_DMA9_TADR+8), 4); - - //psxCycles += 2; - - HW_DMA9_MADR = sif0.sifData.data & 0xFFFFFF; - HW_DMA9_TADR += 16; ///HW_DMA9_MADR + 16 + sif0.sifData.words << 2; - //HW_DMA9_BCR = (sif0.sifData.words << 16) | 1; - sif0.counter = sif0.sifData.words & 0xFFFFFF; - notDone = 1; - - SIF_LOG(" SIF0 Tag: madr=%lx, tadr=%lx, counter=%lx (%08X_%08X)\n", HW_DMA9_MADR, HW_DMA9_TADR, sif0.counter, sif0.sifData.words, sif0.sifData.data); - if(sif0.sifData.data & 0x40000000) - SIF_LOG(" END\n"); - else - SIF_LOG(" CNT %08X, %08X\n", sif0.sifData.data, sif0.sifData.words); - } - } - else // There's some data ready to transfer into the fifo.. - { - int wTransfer = min(sif0.counter, FIFO_SIF0_W-sif0.fifoSize); // HW_DMA9_BCR >> 16; - - SIF_LOG("+++++++++++ %lX of %lX\n", wTransfer, sif0.counter /*(HW_DMA9_BCR >> 16)*/ ); - - SIF0write((u32*)PSXM(HW_DMA9_MADR), wTransfer); - HW_DMA9_MADR += wTransfer << 2; - //HW_DMA9_BCR = (HW_DMA9_BCR & 0xFFFF) | (((HW_DMA9_BCR >> 16) - wTransfer)<<16); - psxCycles += (wTransfer / 4) * BIAS; // fixme : should be / 16 - //psxCycles += wTransfer; - sif0.counter -= wTransfer; - - //notDone = 1; - } - } - - if(eesifbusy[0] == 1) // If EE SIF enabled and there's something to transfer - { - int size = sif0dma->qwc; - if ((psHu32(DMAC_CTRL) & 0x30) == 0x10) { // STS == fromSIF0 - SIF_LOG("SIF0 stall control\n"); - } - if(size > 0) // If we're reading something continue to do so - { - /*if(sif0.fifoSize > 0) - {*/ - int readSize = min(size, (sif0.fifoSize>>2)); - - //SIF_LOG(" EE SIF doing transfer %04Xqw to %08X\n", readSize, sif0dma->madr); - SIF_LOG("----------- %lX of %lX\n", readSize << 2, size << 2 ); - - _dmaGetAddr(sif0dma, ptag, sif0dma->madr, 5); - - SIF0read((u32*)ptag, readSize<<2); -// { -// int i; -// for(i = 0; i < readSize; ++i) { -// SIF_LOG("EE SIF0 read madr: %x %x %x %x\n", ((u32*)ptag)[4*i+0], ((u32*)ptag)[4*i+1], ((u32*)ptag)[4*i+2], ((u32*)ptag)[4*i+3]); -// } -// } - - Cpu->Clear(sif0dma->madr, readSize*4); - - cycles += readSize * BIAS; // fixme : BIAS is factored in below - //cycles += readSize; - sif0dma->qwc -= readSize; - sif0dma->madr += readSize << 4; - - //notDone = 1; - //} - } - - if(sif0dma->qwc == 0) - { - if((sif0dma->chcr & 0x80000080) == 0x80000080) // Stop on tag IRQ - { - // Tag interrupt - SIF_LOG(" EE SIF interrupt\n"); - - //sif0dma->chcr &= ~0x100; - eesifbusy[0] = 0; - CPU_INT(5, cycles*BIAS); - //hwDmacIrq(5); - notDone = 0; - } - else if(sif0.end) // Stop on tag END - { - // End tag. - SIF_LOG(" EE SIF end\n"); - - //sif0dma->chcr &= ~0x100; - //hwDmacIrq(5); - eesifbusy[0] = 0; - CPU_INT(5, cycles*BIAS); - notDone = 0; - } - else if(sif0.fifoSize >= 4) // Read a tag - { - static PCSX2_ALIGNED16(u32 tag[4]); - SIF0read((u32*)&tag[0], 4); // Tag - SIF_LOG(" EE SIF read tag: %x %x %x %x\n", tag[0], tag[1], tag[2], tag[3]); - - sif0dma->qwc = (u16)tag[0]; - sif0dma->madr = tag[1]; - sif0dma->chcr = (sif0dma->chcr & 0xffff) | (tag[0] & 0xffff0000); - - /*if ((sif0dma->chcr & 0x80) && (tag[0] >> 31)) { - SysPrintf("SIF0 TIE\n"); - }*/ - SIF_LOG(" EE SIF dest chain tag madr:%08X qwc:%04X id:%X irq:%d(%08X_%08X)\n", sif0dma->madr, sif0dma->qwc, (tag[0]>>28)&3, (tag[0]>>31)&1, tag[1], tag[0]); - - if ((psHu32(DMAC_CTRL) & 0x30) != 0 && ((tag[0]>>28)&3) == 0) - psHu32(DMAC_STADR) = sif0dma->madr + (sif0dma->qwc * 16); - notDone = 1; - sif0.chain = 1; - if(tag[0] & 0x40000000) - sif0.end = 1; - - } - } - } - }while(notDone); -} - -__forceinline void SIF1Dma() -{ - int id; - u32 *ptag; - int notDone; - int cycles = 0, psxCycles = 0; - notDone = 1; - do - { - if(eesifbusy[1] == 1) // If EE SIF1 is enabled - { - - if ((psHu32(DMAC_CTRL) & 0xC0) == 0xC0) - SIF_LOG("SIF1 stall control\n"); // STS == fromSIF1 - - if(sif1dma->qwc == 0) // If there's no more to transfer - { - if ((sif1dma->chcr & 0xc) == 0 || sif1.end) // If NORMAL mode or end of CHAIN then stop DMA - { - // Stop & signal interrupts on EE - //sif1dma->chcr &= ~0x100; - //hwDmacIrq(6); - SIF_LOG("EE SIF1 End %x\n", sif1.end); - eesifbusy[1] = 0; - notDone = 0; - CPU_INT(6, cycles*BIAS); - sif1.chain = 0; - sif1.end = 0; - } - else // Chain mode - { - // Process DMA tag at sif1dma->tadr - notDone = 1; - _dmaGetAddr(sif1dma, ptag, sif1dma->tadr, 6); - sif1dma->chcr = ( sif1dma->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); // Copy the tag - sif1dma->qwc = (u16)ptag[0]; - - if (sif1dma->chcr & 0x40) { - SysPrintf("SIF1 TTE\n"); - SIF1write(ptag+2, 2); - } - - sif1.chain = 1; - id = (ptag[0] >> 28) & 0x7; - - switch(id) - { - case 0: // refe - SIF_LOG(" REFE %08X\n", ptag[1]); - sif1.end = 1; - sif1dma->madr = ptag[1]; - sif1dma->tadr += 16; - break; - - case 1: // cnt - SIF_LOG(" CNT\n"); - sif1dma->madr = sif1dma->tadr + 16; - sif1dma->tadr = sif1dma->madr + (sif1dma->qwc << 4); - break; - - case 2: // next - SIF_LOG(" NEXT %08X\n", ptag[1]); - sif1dma->madr = sif1dma->tadr + 16; - sif1dma->tadr = ptag[1]; - break; - - case 3: // ref - case 4: // refs - SIF_LOG(" REF %08X\n", ptag[1]); - sif1dma->madr = ptag[1]; - sif1dma->tadr += 16; - break; - - case 7: // end - SIF_LOG(" END\n"); - sif1.end = 1; - sif1dma->madr = sif1dma->tadr + 16; - sif1dma->tadr = sif1dma->madr + (sif1dma->qwc << 4); - break; - - default: - SysPrintf("Bad addr1 source chain\n"); - } - if ((sif1dma->chcr & 0x80) && (ptag[0] >> 31)) { - SysPrintf("SIF1 TIE\n"); - sif1.end = 1; - } - } - } - else // There's some data ready to transfer into the fifo.. - { - int qwTransfer = sif1dma->qwc; - u32 *data; - - //notDone = 1; - _dmaGetAddr(sif1dma, data, sif1dma->madr, 6); - - if(qwTransfer > (FIFO_SIF1_W-sif1.fifoSize)/4) // Copy part of sif1dma into FIFO - qwTransfer = (FIFO_SIF1_W-sif1.fifoSize)/4; - - SIF1write(data, qwTransfer << 2); - - sif1dma->madr += qwTransfer << 4; - cycles += qwTransfer * BIAS; // fixme : BIAS is factored in above - //cycles += qwTransfer; // 1 cycle per quadword (BIAS is factored later) - sif1dma->qwc -= qwTransfer; - } - } - - if(iopsifbusy[1] == 1) // If IOP SIF enabled and there's something to transfer - { - int size = sif1.counter; - - if(size > 0) // If we're reading something continue to do so - { - /*if(sif1.fifoSize > 0) - {*/ - int readSize = size; - - if(readSize > sif1.fifoSize) readSize = sif1.fifoSize; - - SIF_LOG(" IOP SIF doing transfer %04X to %08X\n", readSize, HW_DMA10_MADR); - - SIF1read((u32*)PSXM(HW_DMA10_MADR), readSize); - psxCpu->Clear(HW_DMA10_MADR, readSize); - psxCycles += readSize / 4; // fixme: should be / 16 - sif1.counter = size-readSize; - HW_DMA10_MADR += readSize << 2; - //notDone = 1; - //} - } - - if(sif1.counter <= 0) - { - if(sif1.tagMode & 0x80) // Stop on tag IRQ - { - // Tag interrupt - SIF_LOG(" IOP SIF interrupt\n"); - //HW_DMA10_CHCR &= ~0x01000000; //reset TR flag - //psxDmaInterrupt2(3); - iopsifbusy[1] = 0; - PSX_INT(IopEvt_SIF1, psxCycles); - //hwIntcIrq(INTC_SBUS); - sif1.tagMode = 0; - notDone = 0; - } - else if(sif1.tagMode & 0x40) // Stop on tag END - { - // End tag. - SIF_LOG(" IOP SIF end\n"); - //HW_DMA10_CHCR &= ~0x01000000; //reset TR flag - //psxDmaInterrupt2(3); - iopsifbusy[1] = 0; - PSX_INT(IopEvt_SIF1, psxCycles); - //hwIntcIrq(INTC_SBUS); - sif1.tagMode = 0; - notDone = 0; - } - else if(sif1.fifoSize >= 4) // Read a tag - { - struct sifData d; - SIF1read((u32*)&d, 4); - SIF_LOG(" IOP SIF dest chain tag madr:%08X wc:%04X id:%X irq:%d\n", d.data & 0xffffff, d.words, (d.data>>28)&7, (d.data>>31)&1); - HW_DMA10_MADR = d.data & 0xffffff; - sif1.counter = d.words; - sif1.tagMode = (d.data >> 24) & 0xFF; - notDone = 1; - } - } - } - } while (notDone); -} - -__forceinline void sif0Interrupt() { - - HW_DMA9_CHCR &= ~0x01000000; - psxDmaInterrupt2(2); - //hwIntcIrq(INTC_SBUS); -} - -__forceinline void sif1Interrupt() { - - HW_DMA10_CHCR &= ~0x01000000; //reset TR flag - psxDmaInterrupt2(3); - //hwIntcIrq(INTC_SBUS); -} - -__forceinline void EEsif0Interrupt() { - sif0dma->chcr &= ~0x100; - hwDmacIrq(DMAC_SIF0); -} - -__forceinline void EEsif1Interrupt() { - hwDmacIrq(DMAC_SIF1); - sif1dma->chcr &= ~0x100; -} - -__forceinline void dmaSIF0() { - SIF_LOG("EE: dmaSIF0 chcr = %lx, madr = %lx, qwc = %lx, tadr = %lx\n", - sif0dma->chcr, sif0dma->madr, sif0dma->qwc, sif0dma->tadr); - - if (sif0.fifoReadPos != sif0.fifoWritePos) { - SIF_LOG("warning, sif0.fifoReadPos != sif0.fifoWritePos\n"); - } -// if(sif0dma->qwc > 0 & (sif0dma->chcr & 0x4) == 0x4) { -// sif0dma->chcr &= ~4; //Halflife sets a QWC amount in chain mode, no tadr set. -// SysPrintf("yo\n"); -// } - - psHu32(0x1000F240) |= 0x2000; - eesifbusy[0] = 1; - if(eesifbusy[0] == 1 && iopsifbusy[0] == 1) { - FreezeXMMRegs(1); - hwIntcIrq(INTC_SBUS); - SIF0Dma(); - psHu32(0x1000F240) &= ~0x20; - psHu32(0x1000F240) &= ~0x2000; - FreezeXMMRegs(0); - } -} - -__forceinline void dmaSIF1() { - SIF_LOG("EE: dmaSIF1 chcr = %lx, madr = %lx, qwc = %lx, tadr = %lx\n", - sif1dma->chcr, sif1dma->madr, sif1dma->qwc, sif1dma->tadr); - - if (sif1.fifoReadPos != sif1.fifoWritePos) { - SIF_LOG("warning, sif1.fifoReadPos != sif1.fifoWritePos\n"); - } - -// if(sif1dma->qwc > 0 & (sif1dma->chcr & 0x4) == 0x4) { -// sif1dma->chcr &= ~4; //Halflife sets a QWC amount in chain mode, no tadr set. -// SysPrintf("yo2\n"); -// } - - psHu32(0x1000F240) |= 0x4000; - eesifbusy[1] = 1; - if(eesifbusy[1] == 1 && iopsifbusy[1] == 1) { - FreezeXMMRegs(1); - SIF1Dma(); - psHu32(0x1000F240) &= ~0x40; - psHu32(0x1000F240) &= ~0x100; - psHu32(0x1000F240) &= ~0x4000; - FreezeXMMRegs(0); - } - -} - -__forceinline void dmaSIF2() { - SIF_LOG("dmaSIF2 chcr = %lx, madr = %lx, qwc = %lx\n", - sif2dma->chcr, sif2dma->madr, sif2dma->qwc); - - sif2dma->chcr&= ~0x100; - hwDmacIrq(7); - SysPrintf("*PCSX2*: dmaSIF2\n"); -} - - -void SaveState::sifFreeze() { - Freeze(sif0); - Freeze(sif1); - - if( GetVersion() >= 0x0012 ) - { - Freeze(eesifbusy); - Freeze(iopsifbusy); - } - else if( IsLoading() ) - { - // Old savestate, inferior data so... - // Take an educated guess on what they should be. Or well, set to 1 because - // it more or less forces them to "kick" - - iopsifbusy[0] = eesifbusy[0] = 1; - iopsifbusy[1] = eesifbusy[1] = 1; - } -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Sif.h" +#include "IopHw.h" +#include "Sifcmd.h" + +using namespace std; + +#define sif0dma ((DMACh*)&PS2MEM_HW[0xc000]) +#define sif1dma ((DMACh*)&PS2MEM_HW[0xc400]) +#define sif2dma ((DMACh*)&PS2MEM_HW[0xc800]) + +int eeSifTransfer; + +DMACh *sif0ch; +DMACh *sif1ch; +DMACh *sif2ch; + + +#define FIFO_SIF0_W 128 +#define FIFO_SIF1_W 128 + +struct _sif0{ + u32 fifoData[FIFO_SIF0_W]; + int fifoReadPos; + int fifoWritePos; + int fifoSize; + int chain; + int end; + int tagMode; + int counter; + struct sifData sifData; +}; + +struct _sif1 { + u32 fifoData[FIFO_SIF1_W]; + int fifoReadPos; + int fifoWritePos; + int fifoSize; + int chain; + int end; + int tagMode; + int counter; +}; + +static _sif0 sif0; +static _sif1 sif1; + +int eesifbusy[2] = { 0, 0 }; +extern int iopsifbusy[2]; + +void sifInit() +{ + memzero_obj(sif0); + memzero_obj(sif1); + memzero_obj(eesifbusy); + memzero_obj(iopsifbusy); +} + +static __forceinline void SIF0write(u32 *from, int words) +{ + /*if(FIFO_SIF0_W < (words+sif0.fifoWritePos)) {*/ + + const int wP0 = min((FIFO_SIF0_W-sif0.fifoWritePos),words); + const int wP1 = words - wP0; + + memcpy(&sif0.fifoData[sif0.fifoWritePos], from, wP0 << 2); + memcpy(&sif0.fifoData[0], &from[wP0], wP1 << 2); + + sif0.fifoWritePos = (sif0.fifoWritePos + words) & (FIFO_SIF0_W-1); + /*} + else + { + memcpy_fast(&sif0.fifoData[sif0.fifoWritePos], from, words << 2); + sif0.fifoWritePos += words; + }*/ + + sif0.fifoSize += words; + SIF_LOG(" SIF0 + %d = %d (pos=%d)\n", words, sif0.fifoSize, sif0.fifoWritePos); +} + +static __forceinline void SIF0read(u32 *to, int words) +{ + /*if(FIFO_SIF0_W < (words+sif0.fifoReadPos)) + {*/ + const int wP0 = min((FIFO_SIF0_W-sif0.fifoReadPos),words); + const int wP1 = words - wP0; + + memcpy(to, &sif0.fifoData[sif0.fifoReadPos], wP0 << 2); + memcpy(&to[wP0], &sif0.fifoData[0], wP1 << 2); + + sif0.fifoReadPos = (sif0.fifoReadPos + words) & (FIFO_SIF0_W-1); + /*} + else + { + memcpy_fast(to, &sif0.fifoData[sif0.fifoReadPos], words << 2); + sif0.fifoReadPos += words; + }*/ + + sif0.fifoSize -= words; + SIF_LOG(" SIF0 - %d = %d (pos=%d)\n", words, sif0.fifoSize, sif0.fifoReadPos); +} + +__forceinline void SIF1write(u32 *from, int words) +{ + /*if(FIFO_SIF1_W < (words+sif1.fifoWritePos)) + {*/ + const int wP0 = min((FIFO_SIF1_W-sif1.fifoWritePos),words); + const int wP1 = words - wP0; + + memcpy(&sif1.fifoData[sif1.fifoWritePos], from, wP0 << 2); + memcpy(&sif1.fifoData[0], &from[wP0], wP1 << 2); + + sif1.fifoWritePos = (sif1.fifoWritePos + words) & (FIFO_SIF1_W-1); + /*} + else + { + memcpy_fast(&sif1.fifoData[sif1.fifoWritePos], from, words << 2); + sif1.fifoWritePos += words; + }*/ + + sif1.fifoSize += words; + SIF_LOG(" SIF1 + %d = %d (pos=%d)\n", words, sif1.fifoSize, sif1.fifoWritePos); +} + +static __forceinline void SIF1read(u32 *to, int words) +{ + /*if(FIFO_SIF1_W < (words+sif1.fifoReadPos)) + {*/ + const int wP0 = min((FIFO_SIF1_W-sif1.fifoReadPos),words); + const int wP1 = words - wP0; + + memcpy(to, &sif1.fifoData[sif1.fifoReadPos], wP0 << 2); + memcpy(&to[wP0], &sif1.fifoData[0], wP1 << 2); + + sif1.fifoReadPos = (sif1.fifoReadPos + words) & (FIFO_SIF1_W-1); + /*} + else + { + memcpy_fast(to, &sif1.fifoData[sif1.fifoReadPos], words << 2); + sif1.fifoReadPos += words; + }*/ + + sif1.fifoSize -= words; + SIF_LOG(" SIF1 - %d = %d (pos=%d)\n", words, sif1.fifoSize, sif1.fifoReadPos); +} + +__forceinline void SIF0Dma() +{ + u32 *ptag; + int notDone = 1; + int cycles = 0, psxCycles = 0; + + SIF_LOG("SIF0 DMA start...\n"); + + do + { + + /*if ((psHu32(DMAC_CTRL) & 0xC0)) { + SysPrintf("DMA Stall Control %x\n",(psHu32(DMAC_CTRL) & 0xC0)); + }*/ + if(iopsifbusy[0] == 1) // If EE SIF0 is enabled + { + //int size = sif0.counter; //HW_DMA9_BCR >> 16; + + if(sif0.counter == 0) // If there's no more to transfer + { + // Note.. add normal mode here + if (sif0.sifData.data & 0xC0000000) // If NORMAL mode or end of CHAIN, or interrupt then stop DMA + { + SIF_LOG(" IOP SIF Stopped\n"); + + // Stop & signal interrupts on IOP + //HW_DMA9_CHCR &= ~0x01000000; //reset TR flag + //psxDmaInterrupt2(2); + iopsifbusy[0] = 0; + PSX_INT(IopEvt_SIF0, psxCycles); + // iop is 1/8th the clock rate of the EE and psxcycles is in words (not quadwords) + // So when we're all done, the equation looks like thus: + //PSX_INT(IopEvt_SIF0, ( ( psxCycles*BIAS ) / 4 ) / 8); + + //hwIntcIrq(INTC_SBUS); + sif0.sifData.data = 0; + notDone = 0; + } + else // Chain mode + { + // Process DMA tag at HW_DMA9_TADR + sif0.sifData = *(struct sifData *)PSXM(HW_DMA9_TADR); + + sif0.sifData.words = (sif0.sifData.words + 3) & 0xfffffffc; // Round up to nearest 4. + + SIF0write((u32*)PSXM(HW_DMA9_TADR+8), 4); + + //psxCycles += 2; + + HW_DMA9_MADR = sif0.sifData.data & 0xFFFFFF; + HW_DMA9_TADR += 16; ///HW_DMA9_MADR + 16 + sif0.sifData.words << 2; + //HW_DMA9_BCR = (sif0.sifData.words << 16) | 1; + sif0.counter = sif0.sifData.words & 0xFFFFFF; + notDone = 1; + + SIF_LOG(" SIF0 Tag: madr=%lx, tadr=%lx, counter=%lx (%08X_%08X)\n", HW_DMA9_MADR, HW_DMA9_TADR, sif0.counter, sif0.sifData.words, sif0.sifData.data); + if(sif0.sifData.data & 0x40000000) + SIF_LOG(" END\n"); + else + SIF_LOG(" CNT %08X, %08X\n", sif0.sifData.data, sif0.sifData.words); + } + } + else // There's some data ready to transfer into the fifo.. + { + int wTransfer = min(sif0.counter, FIFO_SIF0_W-sif0.fifoSize); // HW_DMA9_BCR >> 16; + + SIF_LOG("+++++++++++ %lX of %lX\n", wTransfer, sif0.counter /*(HW_DMA9_BCR >> 16)*/ ); + + SIF0write((u32*)PSXM(HW_DMA9_MADR), wTransfer); + HW_DMA9_MADR += wTransfer << 2; + //HW_DMA9_BCR = (HW_DMA9_BCR & 0xFFFF) | (((HW_DMA9_BCR >> 16) - wTransfer)<<16); + psxCycles += (wTransfer / 4) * BIAS; // fixme : should be / 16 + //psxCycles += wTransfer; + sif0.counter -= wTransfer; + + //notDone = 1; + } + } + + if(eesifbusy[0] == 1) // If EE SIF enabled and there's something to transfer + { + int size = sif0dma->qwc; + if ((psHu32(DMAC_CTRL) & 0x30) == 0x10) { // STS == fromSIF0 + SIF_LOG("SIF0 stall control\n"); + } + if(size > 0) // If we're reading something continue to do so + { + /*if(sif0.fifoSize > 0) + {*/ + int readSize = min(size, (sif0.fifoSize>>2)); + + //SIF_LOG(" EE SIF doing transfer %04Xqw to %08X\n", readSize, sif0dma->madr); + SIF_LOG("----------- %lX of %lX\n", readSize << 2, size << 2 ); + + _dmaGetAddr(sif0dma, ptag, sif0dma->madr, 5); + + SIF0read((u32*)ptag, readSize<<2); +// { +// int i; +// for(i = 0; i < readSize; ++i) { +// SIF_LOG("EE SIF0 read madr: %x %x %x %x\n", ((u32*)ptag)[4*i+0], ((u32*)ptag)[4*i+1], ((u32*)ptag)[4*i+2], ((u32*)ptag)[4*i+3]); +// } +// } + + Cpu->Clear(sif0dma->madr, readSize*4); + + cycles += readSize * BIAS; // fixme : BIAS is factored in below + //cycles += readSize; + sif0dma->qwc -= readSize; + sif0dma->madr += readSize << 4; + + //notDone = 1; + //} + } + + if(sif0dma->qwc == 0) + { + if((sif0dma->chcr & 0x80000080) == 0x80000080) // Stop on tag IRQ + { + // Tag interrupt + SIF_LOG(" EE SIF interrupt\n"); + + //sif0dma->chcr &= ~0x100; + eesifbusy[0] = 0; + CPU_INT(5, cycles*BIAS); + //hwDmacIrq(5); + notDone = 0; + } + else if(sif0.end) // Stop on tag END + { + // End tag. + SIF_LOG(" EE SIF end\n"); + + //sif0dma->chcr &= ~0x100; + //hwDmacIrq(5); + eesifbusy[0] = 0; + CPU_INT(5, cycles*BIAS); + notDone = 0; + } + else if(sif0.fifoSize >= 4) // Read a tag + { + static PCSX2_ALIGNED16(u32 tag[4]); + SIF0read((u32*)&tag[0], 4); // Tag + SIF_LOG(" EE SIF read tag: %x %x %x %x\n", tag[0], tag[1], tag[2], tag[3]); + + sif0dma->qwc = (u16)tag[0]; + sif0dma->madr = tag[1]; + sif0dma->chcr = (sif0dma->chcr & 0xffff) | (tag[0] & 0xffff0000); + + /*if ((sif0dma->chcr & 0x80) && (tag[0] >> 31)) { + SysPrintf("SIF0 TIE\n"); + }*/ + SIF_LOG(" EE SIF dest chain tag madr:%08X qwc:%04X id:%X irq:%d(%08X_%08X)\n", sif0dma->madr, sif0dma->qwc, (tag[0]>>28)&3, (tag[0]>>31)&1, tag[1], tag[0]); + + if ((psHu32(DMAC_CTRL) & 0x30) != 0 && ((tag[0]>>28)&3) == 0) + psHu32(DMAC_STADR) = sif0dma->madr + (sif0dma->qwc * 16); + notDone = 1; + sif0.chain = 1; + if(tag[0] & 0x40000000) + sif0.end = 1; + + } + } + } + }while(notDone); +} + +__forceinline void SIF1Dma() +{ + int id; + u32 *ptag; + int notDone; + int cycles = 0, psxCycles = 0; + notDone = 1; + do + { + if(eesifbusy[1] == 1) // If EE SIF1 is enabled + { + + if ((psHu32(DMAC_CTRL) & 0xC0) == 0xC0) + SIF_LOG("SIF1 stall control\n"); // STS == fromSIF1 + + if(sif1dma->qwc == 0) // If there's no more to transfer + { + if ((sif1dma->chcr & 0xc) == 0 || sif1.end) // If NORMAL mode or end of CHAIN then stop DMA + { + // Stop & signal interrupts on EE + //sif1dma->chcr &= ~0x100; + //hwDmacIrq(6); + SIF_LOG("EE SIF1 End %x\n", sif1.end); + eesifbusy[1] = 0; + notDone = 0; + CPU_INT(6, cycles*BIAS); + sif1.chain = 0; + sif1.end = 0; + } + else // Chain mode + { + // Process DMA tag at sif1dma->tadr + notDone = 1; + _dmaGetAddr(sif1dma, ptag, sif1dma->tadr, 6); + sif1dma->chcr = ( sif1dma->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); // Copy the tag + sif1dma->qwc = (u16)ptag[0]; + + if (sif1dma->chcr & 0x40) { + SysPrintf("SIF1 TTE\n"); + SIF1write(ptag+2, 2); + } + + sif1.chain = 1; + id = (ptag[0] >> 28) & 0x7; + + switch(id) + { + case 0: // refe + SIF_LOG(" REFE %08X\n", ptag[1]); + sif1.end = 1; + sif1dma->madr = ptag[1]; + sif1dma->tadr += 16; + break; + + case 1: // cnt + SIF_LOG(" CNT\n"); + sif1dma->madr = sif1dma->tadr + 16; + sif1dma->tadr = sif1dma->madr + (sif1dma->qwc << 4); + break; + + case 2: // next + SIF_LOG(" NEXT %08X\n", ptag[1]); + sif1dma->madr = sif1dma->tadr + 16; + sif1dma->tadr = ptag[1]; + break; + + case 3: // ref + case 4: // refs + SIF_LOG(" REF %08X\n", ptag[1]); + sif1dma->madr = ptag[1]; + sif1dma->tadr += 16; + break; + + case 7: // end + SIF_LOG(" END\n"); + sif1.end = 1; + sif1dma->madr = sif1dma->tadr + 16; + sif1dma->tadr = sif1dma->madr + (sif1dma->qwc << 4); + break; + + default: + SysPrintf("Bad addr1 source chain\n"); + } + if ((sif1dma->chcr & 0x80) && (ptag[0] >> 31)) { + SysPrintf("SIF1 TIE\n"); + sif1.end = 1; + } + } + } + else // There's some data ready to transfer into the fifo.. + { + int qwTransfer = sif1dma->qwc; + u32 *data; + + //notDone = 1; + _dmaGetAddr(sif1dma, data, sif1dma->madr, 6); + + if(qwTransfer > (FIFO_SIF1_W-sif1.fifoSize)/4) // Copy part of sif1dma into FIFO + qwTransfer = (FIFO_SIF1_W-sif1.fifoSize)/4; + + SIF1write(data, qwTransfer << 2); + + sif1dma->madr += qwTransfer << 4; + cycles += qwTransfer * BIAS; // fixme : BIAS is factored in above + //cycles += qwTransfer; // 1 cycle per quadword (BIAS is factored later) + sif1dma->qwc -= qwTransfer; + } + } + + if(iopsifbusy[1] == 1) // If IOP SIF enabled and there's something to transfer + { + int size = sif1.counter; + + if(size > 0) // If we're reading something continue to do so + { + /*if(sif1.fifoSize > 0) + {*/ + int readSize = size; + + if(readSize > sif1.fifoSize) readSize = sif1.fifoSize; + + SIF_LOG(" IOP SIF doing transfer %04X to %08X\n", readSize, HW_DMA10_MADR); + + SIF1read((u32*)PSXM(HW_DMA10_MADR), readSize); + psxCpu->Clear(HW_DMA10_MADR, readSize); + psxCycles += readSize / 4; // fixme: should be / 16 + sif1.counter = size-readSize; + HW_DMA10_MADR += readSize << 2; + //notDone = 1; + //} + } + + if(sif1.counter <= 0) + { + if(sif1.tagMode & 0x80) // Stop on tag IRQ + { + // Tag interrupt + SIF_LOG(" IOP SIF interrupt\n"); + //HW_DMA10_CHCR &= ~0x01000000; //reset TR flag + //psxDmaInterrupt2(3); + iopsifbusy[1] = 0; + PSX_INT(IopEvt_SIF1, psxCycles); + //hwIntcIrq(INTC_SBUS); + sif1.tagMode = 0; + notDone = 0; + } + else if(sif1.tagMode & 0x40) // Stop on tag END + { + // End tag. + SIF_LOG(" IOP SIF end\n"); + //HW_DMA10_CHCR &= ~0x01000000; //reset TR flag + //psxDmaInterrupt2(3); + iopsifbusy[1] = 0; + PSX_INT(IopEvt_SIF1, psxCycles); + //hwIntcIrq(INTC_SBUS); + sif1.tagMode = 0; + notDone = 0; + } + else if(sif1.fifoSize >= 4) // Read a tag + { + struct sifData d; + SIF1read((u32*)&d, 4); + SIF_LOG(" IOP SIF dest chain tag madr:%08X wc:%04X id:%X irq:%d\n", d.data & 0xffffff, d.words, (d.data>>28)&7, (d.data>>31)&1); + HW_DMA10_MADR = d.data & 0xffffff; + sif1.counter = d.words; + sif1.tagMode = (d.data >> 24) & 0xFF; + notDone = 1; + } + } + } + } while (notDone); +} + +__forceinline void sif0Interrupt() { + + HW_DMA9_CHCR &= ~0x01000000; + psxDmaInterrupt2(2); + //hwIntcIrq(INTC_SBUS); +} + +__forceinline void sif1Interrupt() { + + HW_DMA10_CHCR &= ~0x01000000; //reset TR flag + psxDmaInterrupt2(3); + //hwIntcIrq(INTC_SBUS); +} + +__forceinline void EEsif0Interrupt() { + sif0dma->chcr &= ~0x100; + hwDmacIrq(DMAC_SIF0); +} + +__forceinline void EEsif1Interrupt() { + hwDmacIrq(DMAC_SIF1); + sif1dma->chcr &= ~0x100; +} + +__forceinline void dmaSIF0() { + SIF_LOG("EE: dmaSIF0 chcr = %lx, madr = %lx, qwc = %lx, tadr = %lx\n", + sif0dma->chcr, sif0dma->madr, sif0dma->qwc, sif0dma->tadr); + + if (sif0.fifoReadPos != sif0.fifoWritePos) { + SIF_LOG("warning, sif0.fifoReadPos != sif0.fifoWritePos\n"); + } +// if(sif0dma->qwc > 0 & (sif0dma->chcr & 0x4) == 0x4) { +// sif0dma->chcr &= ~4; //Halflife sets a QWC amount in chain mode, no tadr set. +// SysPrintf("yo\n"); +// } + + psHu32(0x1000F240) |= 0x2000; + eesifbusy[0] = 1; + if(eesifbusy[0] == 1 && iopsifbusy[0] == 1) { + FreezeXMMRegs(1); + hwIntcIrq(INTC_SBUS); + SIF0Dma(); + psHu32(0x1000F240) &= ~0x20; + psHu32(0x1000F240) &= ~0x2000; + FreezeXMMRegs(0); + } +} + +__forceinline void dmaSIF1() { + SIF_LOG("EE: dmaSIF1 chcr = %lx, madr = %lx, qwc = %lx, tadr = %lx\n", + sif1dma->chcr, sif1dma->madr, sif1dma->qwc, sif1dma->tadr); + + if (sif1.fifoReadPos != sif1.fifoWritePos) { + SIF_LOG("warning, sif1.fifoReadPos != sif1.fifoWritePos\n"); + } + +// if(sif1dma->qwc > 0 & (sif1dma->chcr & 0x4) == 0x4) { +// sif1dma->chcr &= ~4; //Halflife sets a QWC amount in chain mode, no tadr set. +// SysPrintf("yo2\n"); +// } + + psHu32(0x1000F240) |= 0x4000; + eesifbusy[1] = 1; + if(eesifbusy[1] == 1 && iopsifbusy[1] == 1) { + FreezeXMMRegs(1); + SIF1Dma(); + psHu32(0x1000F240) &= ~0x40; + psHu32(0x1000F240) &= ~0x100; + psHu32(0x1000F240) &= ~0x4000; + FreezeXMMRegs(0); + } + +} + +__forceinline void dmaSIF2() { + SIF_LOG("dmaSIF2 chcr = %lx, madr = %lx, qwc = %lx\n", + sif2dma->chcr, sif2dma->madr, sif2dma->qwc); + + sif2dma->chcr&= ~0x100; + hwDmacIrq(7); + SysPrintf("*PCSX2*: dmaSIF2\n"); +} + + +void SaveState::sifFreeze() { + Freeze(sif0); + Freeze(sif1); + + if( GetVersion() >= 0x0012 ) + { + Freeze(eesifbusy); + Freeze(iopsifbusy); + } + else if( IsLoading() ) + { + // Old savestate, inferior data so... + // Take an educated guess on what they should be. Or well, set to 1 because + // it more or less forces them to "kick" + + iopsifbusy[0] = eesifbusy[0] = 1; + iopsifbusy[1] = eesifbusy[1] = 1; + } +} diff --git a/pcsx2/Sif.h b/pcsx2/Sif.h index e1608973e0..539a2e11c6 100644 --- a/pcsx2/Sif.h +++ b/pcsx2/Sif.h @@ -1,51 +1,51 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __SIF_H__ -#define __SIF_H__ - -#include "Common.h" - -struct sifData{ - int data, - words, - count, - addr; -}; - -extern int eeSifTransfer; - -extern DMACh *sif0ch; -extern DMACh *sif1ch; -extern DMACh *sif2ch; - -extern void sifInit(); -extern void SIF0Dma(); -extern void SIF1Dma(); -extern void dmaSIF0(); -extern void dmaSIF1(); -extern void dmaSIF2(); -extern void sif1Interrupt(); -extern void sif0Interrupt(); -extern void EEsif1Interrupt(); -extern void EEsif0Interrupt(); -extern int EEsif2Interrupt(); -int sifFreeze(gzFile f, int Mode); - - -#endif /* __SIF_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __SIF_H__ +#define __SIF_H__ + +#include "Common.h" + +struct sifData{ + int data, + words, + count, + addr; +}; + +extern int eeSifTransfer; + +extern DMACh *sif0ch; +extern DMACh *sif1ch; +extern DMACh *sif2ch; + +extern void sifInit(); +extern void SIF0Dma(); +extern void SIF1Dma(); +extern void dmaSIF0(); +extern void dmaSIF1(); +extern void dmaSIF2(); +extern void sif1Interrupt(); +extern void sif0Interrupt(); +extern void EEsif1Interrupt(); +extern void EEsif0Interrupt(); +extern int EEsif2Interrupt(); +int sifFreeze(gzFile f, int Mode); + + +#endif /* __SIF_H__ */ diff --git a/pcsx2/Sifcmd.h b/pcsx2/Sifcmd.h index 8734ab2ac7..90a9780d01 100644 --- a/pcsx2/Sifcmd.h +++ b/pcsx2/Sifcmd.h @@ -1,193 +1,193 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __SIFCMD_H__ -#define __SIFCMD_H__ - -/* from sifcmd.h */ - -#define SYSTEM_CMD 0x80000000 - -struct t_sif_cmd_header -{ - u32 size; - void *dest; - int command; - u32 unknown; -}; - -struct t_sif_dma_transfer -{ - void *src, - *dest; - int size; - int attr; -}; - -struct t_sif_handler -{ - void (*handler) ( void *a, void *b); - void *buff; -}; - -#define SYSTEM_CMD_CHANGE_SADDR 0x80000000 -#define SYSTEM_CMD_INIT_CMD 0x80000002 -struct t_sif_saddr{ - struct t_sif_cmd_header hdr; //+00 - void *newaddr; //+10 -}; //=14 - -#define SYSTEM_CMD_SET_SREG 0x80000001 -struct t_sif_sreg{ - struct t_sif_cmd_header hdr; //+00 - int index; //+10 - unsigned int value; //+14 -}; //=18 - -#define SYSTEM_CMD_RESET 0x80000003 -struct t_sif_reset{ - struct t_sif_cmd_header hdr; //+00 - int size, //+10 - flag; //+14 - char data[80]; //+18 -}; //=68 - -/* end of sifcmd.h */ - -/* from sifsrpc.h */ - -struct t_sif_rpc_rend -{ - struct t_sif_cmd_header sifcmd; - int rec_id; /* 04 */ - void *pkt_addr; /* 05 */ - int rpc_id; /* 06 */ - - struct t_rpc_client_data *client; /* 7 */ - u32 command; /* 8 */ - struct t_rpc_server_data *server; /* 9 */ - void *buff, /* 10 */ - *buff2; /* 11 */ -}; - -struct t_sif_rpc_other_data -{ - struct t_sif_cmd_header sifcmd; - int rec_id; /* 04 */ - void *pkt_addr; /* 05 */ - int rpc_id; /* 06 */ - - struct t_rpc_receive_data *receive; /* 07 */ - void *src; /* 08 */ - void *dest; /* 09 */ - int size; /* 10 */ -}; - -struct t_sif_rpc_bind -{ - struct t_sif_cmd_header sifcmd; - int rec_id; /* 04 */ - void *pkt_addr; /* 05 */ - int rpc_id; /* 06 */ - struct t_rpc_client_data *client; /* 07 */ - int rpc_number; /* 08 */ -}; - -struct t_sif_rpc_call -{ - struct t_sif_cmd_header sifcmd; - int rec_id; /* 04 */ - void *pkt_addr; /* 05 */ - int rpc_id; /* 06 */ - struct t_rpc_client_data *client; /* 07 */ - int rpc_number; /* 08 */ - int send_size; /* 09 */ - void *receive; /* 10 */ - int rec_size; /* 11 */ - int has_async_ef; /* 12 */ - struct t_rpc_server_data *server; /* 13 */ -}; - -struct t_rpc_server_data -{ - int command; /* 04 00 */ - - void * (*func)(u32, void *, int); /* 05 01 */ - void *buff; /* 06 02 */ - int size; /* 07 03 */ - - void * (*func2)(u32, void *, int); /* 08 04 */ - void *buff2; /* 09 05 */ - int size2; /* 10 06 */ - - struct t_rpc_client_data *client; /* 11 07 */ - void *pkt_addr; /* 12 08 */ - int rpc_number; /* 13 09 */ - - void *receive; /* 14 10 */ - int rec_size; /* 15 11 */ - int has_async_ef; /* 16 12 */ - int rec_id; /* 17 13 */ - - struct t_rpc_server_data *link; /* 18 14 */ - struct r_rpc_server_data *next; /* 19 15 */ - struct t_rpc_data_queue *queued_object; /* 20 16 */ -}; - - -struct t_rpc_header -{ - void *pkt_addr; /* 04 00 */ - u32 rpc_id; /* 05 01 */ - int sema_id; /* 06 02 */ - u32 mode; /* 07 03 */ -}; - - -struct t_rpc_client_data -{ - struct t_rpc_header hdr; - u32 command; /* 04 08 */ - void *buff, /* 05 09 */ - *buff2; /* 06 10 */ - void (*end_function) ( void *); /* 07 11 */ - void *end_param; /* 08 12*/ - struct t_rpc_server_data *server; /* 09 13 */ -}; - -struct t_rpc_receive_data -{ - struct t_rpc_header hdr; - void *src, /* 04 */ - *dest; /* 05 */ - int size; /* 06 */ -}; - -struct t_rpc_data_queue -{ - int thread_id, /* 00 */ - active; /* 01 */ - struct t_rpc_server_data *svdata_ref, /* 02 */ - *start, /* 03 */ - *end; /* 04 */ - struct t_rpc_data_queue *next; /* 05 */ -}; - -/* end of sifrpc.h */ - -#endif//__SIFCMD_H__ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __SIFCMD_H__ +#define __SIFCMD_H__ + +/* from sifcmd.h */ + +#define SYSTEM_CMD 0x80000000 + +struct t_sif_cmd_header +{ + u32 size; + void *dest; + int command; + u32 unknown; +}; + +struct t_sif_dma_transfer +{ + void *src, + *dest; + int size; + int attr; +}; + +struct t_sif_handler +{ + void (*handler) ( void *a, void *b); + void *buff; +}; + +#define SYSTEM_CMD_CHANGE_SADDR 0x80000000 +#define SYSTEM_CMD_INIT_CMD 0x80000002 +struct t_sif_saddr{ + struct t_sif_cmd_header hdr; //+00 + void *newaddr; //+10 +}; //=14 + +#define SYSTEM_CMD_SET_SREG 0x80000001 +struct t_sif_sreg{ + struct t_sif_cmd_header hdr; //+00 + int index; //+10 + unsigned int value; //+14 +}; //=18 + +#define SYSTEM_CMD_RESET 0x80000003 +struct t_sif_reset{ + struct t_sif_cmd_header hdr; //+00 + int size, //+10 + flag; //+14 + char data[80]; //+18 +}; //=68 + +/* end of sifcmd.h */ + +/* from sifsrpc.h */ + +struct t_sif_rpc_rend +{ + struct t_sif_cmd_header sifcmd; + int rec_id; /* 04 */ + void *pkt_addr; /* 05 */ + int rpc_id; /* 06 */ + + struct t_rpc_client_data *client; /* 7 */ + u32 command; /* 8 */ + struct t_rpc_server_data *server; /* 9 */ + void *buff, /* 10 */ + *buff2; /* 11 */ +}; + +struct t_sif_rpc_other_data +{ + struct t_sif_cmd_header sifcmd; + int rec_id; /* 04 */ + void *pkt_addr; /* 05 */ + int rpc_id; /* 06 */ + + struct t_rpc_receive_data *receive; /* 07 */ + void *src; /* 08 */ + void *dest; /* 09 */ + int size; /* 10 */ +}; + +struct t_sif_rpc_bind +{ + struct t_sif_cmd_header sifcmd; + int rec_id; /* 04 */ + void *pkt_addr; /* 05 */ + int rpc_id; /* 06 */ + struct t_rpc_client_data *client; /* 07 */ + int rpc_number; /* 08 */ +}; + +struct t_sif_rpc_call +{ + struct t_sif_cmd_header sifcmd; + int rec_id; /* 04 */ + void *pkt_addr; /* 05 */ + int rpc_id; /* 06 */ + struct t_rpc_client_data *client; /* 07 */ + int rpc_number; /* 08 */ + int send_size; /* 09 */ + void *receive; /* 10 */ + int rec_size; /* 11 */ + int has_async_ef; /* 12 */ + struct t_rpc_server_data *server; /* 13 */ +}; + +struct t_rpc_server_data +{ + int command; /* 04 00 */ + + void * (*func)(u32, void *, int); /* 05 01 */ + void *buff; /* 06 02 */ + int size; /* 07 03 */ + + void * (*func2)(u32, void *, int); /* 08 04 */ + void *buff2; /* 09 05 */ + int size2; /* 10 06 */ + + struct t_rpc_client_data *client; /* 11 07 */ + void *pkt_addr; /* 12 08 */ + int rpc_number; /* 13 09 */ + + void *receive; /* 14 10 */ + int rec_size; /* 15 11 */ + int has_async_ef; /* 16 12 */ + int rec_id; /* 17 13 */ + + struct t_rpc_server_data *link; /* 18 14 */ + struct r_rpc_server_data *next; /* 19 15 */ + struct t_rpc_data_queue *queued_object; /* 20 16 */ +}; + + +struct t_rpc_header +{ + void *pkt_addr; /* 04 00 */ + u32 rpc_id; /* 05 01 */ + int sema_id; /* 06 02 */ + u32 mode; /* 07 03 */ +}; + + +struct t_rpc_client_data +{ + struct t_rpc_header hdr; + u32 command; /* 04 08 */ + void *buff, /* 05 09 */ + *buff2; /* 06 10 */ + void (*end_function) ( void *); /* 07 11 */ + void *end_param; /* 08 12*/ + struct t_rpc_server_data *server; /* 09 13 */ +}; + +struct t_rpc_receive_data +{ + struct t_rpc_header hdr; + void *src, /* 04 */ + *dest; /* 05 */ + int size; /* 06 */ +}; + +struct t_rpc_data_queue +{ + int thread_id, /* 00 */ + active; /* 01 */ + struct t_rpc_server_data *svdata_ref, /* 02 */ + *start, /* 03 */ + *end; /* 04 */ + struct t_rpc_data_queue *next; /* 05 */ +}; + +/* end of sifrpc.h */ + +#endif//__SIFCMD_H__ diff --git a/pcsx2/Sio.cpp b/pcsx2/Sio.cpp index 887c2b13a7..9c8527d57e 100644 --- a/pcsx2/Sio.cpp +++ b/pcsx2/Sio.cpp @@ -1,564 +1,564 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "PsxCommon.h" -#include "MemoryCard.h" - -_sio sio; - -static const u8 cardh[4] = { 0xFF, 0xFF, 0x5a, 0x5d }; - -// Memory Card Specs : Sector size etc. -static const mc_command_0x26_tag mc_command_0x26= {'+', 512, 16, 0x4000, 0x52, 0x5A}; - -static int m_PostSavestateCards[2] = { 0, 0 }; - -// SIO Inline'd IRQs : Calls the SIO interrupt handlers directly instead of -// feeding them through the IOP's branch test. (see SIO.H for details) - -#ifdef SIO_INLINE_IRQS -#define SIO_INT() sioInterrupt() -#define SIO_FORCEINLINE -#else -__forceinline void SIO_INT() -{ - if( !(psxRegs.interrupt & (1<(sio.buf); - sio.buf[3] = sio.terminator; - sio.buf[2] = '+'; - sio.mcdst = 99; - sio2.packet.recvVal3 = 0x8c; - break; - case 0x12: // RESET - sio.bufcount = 8; - memset8_obj<0xff>(sio.buf); - sio.buf[3] = sio.terminator; - sio.buf[2] = '+'; - sio.mcdst = 99; - - sio2.packet.recvVal3 = 0x8c; - MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); - break; - case 0x81: // COMMIT - sio.bufcount = 8; - memset8_obj<0xff>(sio.buf); - sio.mcdst = 99; - sio.buf[3] = sio.terminator; - sio.buf[2] = '+'; - sio2.packet.recvVal3 = 0x8c; - if(value == 0x81) { - if(sio.mc_command==0x42) - sio2.packet.recvVal1 = 0x1600; // Writing - else if(sio.mc_command==0x43) sio2.packet.recvVal1 = 0x1700; // Reading - } - MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); - break; - case 0x21: - case 0x22: - case 0x23: // SECTOR SET - sio.bufcount = 8; sio.mcdst = 99; sio.sector=0; sio.k=0; - memset8_obj<0xff>(sio.buf); - sio2.packet.recvVal3 = 0x8c; - sio.buf[8]=sio.terminator; - sio.buf[7]='+'; - MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); - break; - case 0x24: - MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); - break; - case 0x25: - MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); - break; - case 0x26: - sio.bufcount = 12; sio.mcdst = 99; sio2.packet.recvVal3 = 0x83; - memset8_obj<0xff>(sio.buf); - memcpy(&sio.buf[2], &mc_command_0x26, sizeof(mc_command_0x26)); - sio.buf[12]=sio.terminator; - MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); - break; - case 0x27: - case 0x28: - case 0xBF: - sio.bufcount = 4; sio.mcdst = 99; sio2.packet.recvVal3 = 0x8b; - memset8_obj<0xff>(sio.buf); - sio.buf[4]=sio.terminator; - sio.buf[3]='+'; - MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); - break; - case 0x42: // WRITE - case 0x43: // READ - case 0x82: - if(value==0x82 && sio.lastsector==sio.sector) sio.mode = 2; - if(value==0x42) sio.mode = 0; - if(value==0x43) sio.lastsector = sio.sector; // Reading - - sio.bufcount =133; sio.mcdst = 99; - memset8_obj<0xff>(sio.buf); - sio.buf[133]=sio.terminator; - sio.buf[132]='+'; - MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); - break; - case 0xf0: - case 0xf1: - case 0xf2: - sio.mcdst = 99; - MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); - break; - case 0xf3: - case 0xf7: - sio.bufcount = 4; sio.mcdst = 99; - memset8_obj<0xff>(sio.buf); - sio.buf[4]=sio.terminator; - sio.buf[3]='+'; - MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); - break; - case 0x52: - sio.rdwr = 1; memset8_obj<0xff>(sio.buf); - sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+'; - MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); - break; - case 0x57: - sio.rdwr = 2; memset8_obj<0xff>(sio.buf); - sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+'; - MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); - break; - default: - sio.mcdst = 0; - memset8_obj<0xff>(sio.buf); - sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+'; - MEMCARDS_LOG("Unknown MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); - } - sio.mc_command=value; - return; - // FURTHER PROCESSING OF THE MEMORY CARD COMMANDS - case 99: - sio.packetsize++; - sio.parp++; - switch(sio.mc_command) - { - // SET_ERASE_PAGE; the next erase commands will *clear* data starting with the page set here - case 0x21: - // SET_WRITE_PAGE; the next write commands will commit data starting with the page set here - case 0x22: - // SET_READ_PAGE; the next read commands will return data starting with the page set here - case 0x23: - if (sio.parp==2)sio.sector|=(value & 0xFF)<< 0; - if (sio.parp==3)sio.sector|=(value & 0xFF)<< 8; - if (sio.parp==4)sio.sector|=(value & 0xFF)<<16; - if (sio.parp==5)sio.sector|=(value & 0xFF)<<24; - if (sio.parp==6) - { - if (sio_xor((u8 *)&sio.sector, 4) == value) - MEMCARDS_LOG("MC(%d) SET PAGE sio.sector 0x%04X\n", - sio.GetMemcardIndex()+1, sio.sector); - else - MEMCARDS_LOG("MC(%d) SET PAGE XOR value ERROR 0x%02X != ^0x%02X\n", - sio.GetMemcardIndex()+1, value, sio_xor((u8 *)&sio.sector, 4)); - } - break; - - // SET_TERMINATOR; reads the new terminator code - case 0x27: - if(sio.parp==2) { - sio.terminator = value; - sio.buf[4] = value; - MEMCARDS_LOG("MC(%d) SET TERMINATOR command 0x%02X\n", sio.GetMemcardIndex()+1, value); - - } - break; - - // GET_TERMINATOR; puts in position 3 the current terminator code and in 4 the default one - // depending on the param - case 0x28: - if(sio.parp == 2) { - sio.buf[2] = '+'; - sio.buf[3] = sio.terminator; - - //if(value == 0) sio.buf[4] = 0xFF; - sio.buf[4] = 0x55; - MEMCARDS_LOG("MC(%d) GET TERMINATOR command 0x%02X\n", sio.GetMemcardIndex()+1, value); - } - break; - // WRITE DATA - case 0x42: - if (sio.parp==2) { - sio.bufcount=5+value; - memset8_obj<0xff>(sio.buf); - sio.buf[sio.bufcount-1]='+'; - sio.buf[sio.bufcount]=sio.terminator; - MEMCARDS_LOG("MC(%d) WRITE command 0x%02X\n\n\n\n\n", sio.GetMemcardIndex()+1, value); - } - else - if ((sio.parp>2) && (sio.parp(sio.buf); - sio.buf[12] = 0; // Xor value of data from index 4 to 11 - sio.buf[3]='+'; - sio.buf[13] = sio.terminator; - break; - case 6: - case 7: - case 11: - sio.bufcount=13; - memset8_obj<0xff>(sio.buf); - sio.buf[12]='+'; - sio.buf[13] = sio.terminator; - break; - default: - sio.bufcount=4; - memset8_obj<0xff>(sio.buf); - sio.buf[3]='+'; - sio.buf[4] = sio.terminator; - } - } - break; - } - if (sio.bufcount<=sio.parp) sio.mcdst = 0; - return; - } - - switch (sio.mtapst) - { - case 0x1: - sio.packetsize++; - sio.parp = 1; - SIO_INT(); - switch(value) { - case 0x12: sio.mtapst = 2; sio.bufcount = 5; break; - case 0x13: sio.mtapst = 2; sio.bufcount = 5; break; - case 0x21: sio.mtapst = 2; sio.bufcount = 6; break; - } - sio.buf[sio.bufcount]='Z'; - sio.buf[sio.bufcount-1]='+'; - return; - case 0x2: - sio.packetsize++; - sio.parp++; - if (sio.bufcount<=sio.parp) sio.mcdst = 0; - SIO_INT(); - return; - } - - if(sio.count == 1 || way == 0) InitializeSIO(value); -} - -void InitializeSIO(u8 value) -{ - switch (value) { - case 0x01: // start pad - sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty - sio.StatReg |= RX_RDY; // Transfer is Ready - - switch (sio.CtrlReg&0x2002) { - case 0x0002: sio.buf[0] = PAD1startPoll(1); break; - case 0x2002: sio.buf[0] = PAD2startPoll(2); break; - } - - sio.bufcount = 2; - sio.parp = 0; - sio.padst = 1; - sio.packetsize = 1; - sio.count = 0; - sio2.packet.recvVal1 = 0x1100; // Pad is present - SIO_INT(); - return; - - case 0x21: // start mtap - sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty - sio.StatReg |= RX_RDY; // Transfer is Ready - sio.parp = 0; - sio.packetsize = 1; - sio.mtapst = 1; - sio.count = 0; - sio2.packet.recvVal1 = 0x1D100; // Mtap is not connected :) - SIO_INT(); - return; - - case 0x61: // start remote control sensor - sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty - sio.StatReg |= RX_RDY; // Transfer is Ready - sio.parp = 0; - sio.packetsize = 1; - sio.count = 0; - sio2.packet.recvVal1 = 0x1100; // Pad is present - SIO_INT(); - return; - - case 0x81: // start memcard - { - sio.StatReg &= ~TX_EMPTY; - sio.StatReg |= RX_RDY; - memcpy(sio.buf, cardh, 4); - sio.parp = 0; - sio.bufcount = 8; - sio.mcdst = 1; - sio.packetsize = 1; - sio.rdwr = 0; - sio.count = 0; - - // Memcard presence reporting! - // In addition to checking the presence of MemoryCard1/2 file handles, we check a - // variable which force-disables all memory cards after a savestate recovery. This - // is needed to inform certain games to clear their cached memorycard indexes. - - // Note: - // 0x01100 means Memcard is present - // 0x1D100 means Memcard is missing. - - const int mcidx = sio.GetMemcardIndex(); - - if( m_PostSavestateCards[mcidx] ) - { - m_PostSavestateCards[mcidx]--; - sio2.packet.recvVal1 = 0x1D100; - PAD_LOG( "START MEMCARD[%d] - post-savestate - reported as missing!\n", sio.GetMemcardIndex() ); - } - else - { - sio2.packet.recvVal1 = TestMcdIsPresent( sio.GetMemcardIndex() ) ? 0x1100 : 0x1D100; - PAD_LOG("START MEMCARD [%d] - %s\n", - sio.GetMemcardIndex(), TestMcdIsPresent( sio.GetMemcardIndex() ) ? "Present" : "Missing" ); - } - - SIO_INT(); - } - return; - } -} - -void sioWrite8(u8 value) -{ - SIO_CommandWrite(value,0); -} - -void SIODMAWrite(u8 value) -{ - SIO_CommandWrite(value,1); -} - -void sioWriteCtrl16(u16 value) { - sio.CtrlReg = value & ~RESET_ERR; - if (value & RESET_ERR) sio.StatReg &= ~IRQ; - if ((sio.CtrlReg & SIO_RESET) || (!sio.CtrlReg)) - { - sio.mtapst = 0; sio.padst = 0; sio.mcdst = 0; sio.parp = 0; - sio.StatReg = TX_RDY | TX_EMPTY; - psxRegs.interrupt &= ~(1<(sio.buf); + sio.buf[3] = sio.terminator; + sio.buf[2] = '+'; + sio.mcdst = 99; + sio2.packet.recvVal3 = 0x8c; + break; + case 0x12: // RESET + sio.bufcount = 8; + memset8_obj<0xff>(sio.buf); + sio.buf[3] = sio.terminator; + sio.buf[2] = '+'; + sio.mcdst = 99; + + sio2.packet.recvVal3 = 0x8c; + MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); + break; + case 0x81: // COMMIT + sio.bufcount = 8; + memset8_obj<0xff>(sio.buf); + sio.mcdst = 99; + sio.buf[3] = sio.terminator; + sio.buf[2] = '+'; + sio2.packet.recvVal3 = 0x8c; + if(value == 0x81) { + if(sio.mc_command==0x42) + sio2.packet.recvVal1 = 0x1600; // Writing + else if(sio.mc_command==0x43) sio2.packet.recvVal1 = 0x1700; // Reading + } + MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); + break; + case 0x21: + case 0x22: + case 0x23: // SECTOR SET + sio.bufcount = 8; sio.mcdst = 99; sio.sector=0; sio.k=0; + memset8_obj<0xff>(sio.buf); + sio2.packet.recvVal3 = 0x8c; + sio.buf[8]=sio.terminator; + sio.buf[7]='+'; + MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); + break; + case 0x24: + MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); + break; + case 0x25: + MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); + break; + case 0x26: + sio.bufcount = 12; sio.mcdst = 99; sio2.packet.recvVal3 = 0x83; + memset8_obj<0xff>(sio.buf); + memcpy(&sio.buf[2], &mc_command_0x26, sizeof(mc_command_0x26)); + sio.buf[12]=sio.terminator; + MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); + break; + case 0x27: + case 0x28: + case 0xBF: + sio.bufcount = 4; sio.mcdst = 99; sio2.packet.recvVal3 = 0x8b; + memset8_obj<0xff>(sio.buf); + sio.buf[4]=sio.terminator; + sio.buf[3]='+'; + MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); + break; + case 0x42: // WRITE + case 0x43: // READ + case 0x82: + if(value==0x82 && sio.lastsector==sio.sector) sio.mode = 2; + if(value==0x42) sio.mode = 0; + if(value==0x43) sio.lastsector = sio.sector; // Reading + + sio.bufcount =133; sio.mcdst = 99; + memset8_obj<0xff>(sio.buf); + sio.buf[133]=sio.terminator; + sio.buf[132]='+'; + MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); + break; + case 0xf0: + case 0xf1: + case 0xf2: + sio.mcdst = 99; + MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); + break; + case 0xf3: + case 0xf7: + sio.bufcount = 4; sio.mcdst = 99; + memset8_obj<0xff>(sio.buf); + sio.buf[4]=sio.terminator; + sio.buf[3]='+'; + MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); + break; + case 0x52: + sio.rdwr = 1; memset8_obj<0xff>(sio.buf); + sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+'; + MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); + break; + case 0x57: + sio.rdwr = 2; memset8_obj<0xff>(sio.buf); + sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+'; + MEMCARDS_LOG("MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); + break; + default: + sio.mcdst = 0; + memset8_obj<0xff>(sio.buf); + sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+'; + MEMCARDS_LOG("Unknown MC(%d) command 0x%02X\n", sio.GetMemcardIndex()+1, value); + } + sio.mc_command=value; + return; + // FURTHER PROCESSING OF THE MEMORY CARD COMMANDS + case 99: + sio.packetsize++; + sio.parp++; + switch(sio.mc_command) + { + // SET_ERASE_PAGE; the next erase commands will *clear* data starting with the page set here + case 0x21: + // SET_WRITE_PAGE; the next write commands will commit data starting with the page set here + case 0x22: + // SET_READ_PAGE; the next read commands will return data starting with the page set here + case 0x23: + if (sio.parp==2)sio.sector|=(value & 0xFF)<< 0; + if (sio.parp==3)sio.sector|=(value & 0xFF)<< 8; + if (sio.parp==4)sio.sector|=(value & 0xFF)<<16; + if (sio.parp==5)sio.sector|=(value & 0xFF)<<24; + if (sio.parp==6) + { + if (sio_xor((u8 *)&sio.sector, 4) == value) + MEMCARDS_LOG("MC(%d) SET PAGE sio.sector 0x%04X\n", + sio.GetMemcardIndex()+1, sio.sector); + else + MEMCARDS_LOG("MC(%d) SET PAGE XOR value ERROR 0x%02X != ^0x%02X\n", + sio.GetMemcardIndex()+1, value, sio_xor((u8 *)&sio.sector, 4)); + } + break; + + // SET_TERMINATOR; reads the new terminator code + case 0x27: + if(sio.parp==2) { + sio.terminator = value; + sio.buf[4] = value; + MEMCARDS_LOG("MC(%d) SET TERMINATOR command 0x%02X\n", sio.GetMemcardIndex()+1, value); + + } + break; + + // GET_TERMINATOR; puts in position 3 the current terminator code and in 4 the default one + // depending on the param + case 0x28: + if(sio.parp == 2) { + sio.buf[2] = '+'; + sio.buf[3] = sio.terminator; + + //if(value == 0) sio.buf[4] = 0xFF; + sio.buf[4] = 0x55; + MEMCARDS_LOG("MC(%d) GET TERMINATOR command 0x%02X\n", sio.GetMemcardIndex()+1, value); + } + break; + // WRITE DATA + case 0x42: + if (sio.parp==2) { + sio.bufcount=5+value; + memset8_obj<0xff>(sio.buf); + sio.buf[sio.bufcount-1]='+'; + sio.buf[sio.bufcount]=sio.terminator; + MEMCARDS_LOG("MC(%d) WRITE command 0x%02X\n\n\n\n\n", sio.GetMemcardIndex()+1, value); + } + else + if ((sio.parp>2) && (sio.parp(sio.buf); + sio.buf[12] = 0; // Xor value of data from index 4 to 11 + sio.buf[3]='+'; + sio.buf[13] = sio.terminator; + break; + case 6: + case 7: + case 11: + sio.bufcount=13; + memset8_obj<0xff>(sio.buf); + sio.buf[12]='+'; + sio.buf[13] = sio.terminator; + break; + default: + sio.bufcount=4; + memset8_obj<0xff>(sio.buf); + sio.buf[3]='+'; + sio.buf[4] = sio.terminator; + } + } + break; + } + if (sio.bufcount<=sio.parp) sio.mcdst = 0; + return; + } + + switch (sio.mtapst) + { + case 0x1: + sio.packetsize++; + sio.parp = 1; + SIO_INT(); + switch(value) { + case 0x12: sio.mtapst = 2; sio.bufcount = 5; break; + case 0x13: sio.mtapst = 2; sio.bufcount = 5; break; + case 0x21: sio.mtapst = 2; sio.bufcount = 6; break; + } + sio.buf[sio.bufcount]='Z'; + sio.buf[sio.bufcount-1]='+'; + return; + case 0x2: + sio.packetsize++; + sio.parp++; + if (sio.bufcount<=sio.parp) sio.mcdst = 0; + SIO_INT(); + return; + } + + if(sio.count == 1 || way == 0) InitializeSIO(value); +} + +void InitializeSIO(u8 value) +{ + switch (value) { + case 0x01: // start pad + sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty + sio.StatReg |= RX_RDY; // Transfer is Ready + + switch (sio.CtrlReg&0x2002) { + case 0x0002: sio.buf[0] = PAD1startPoll(1); break; + case 0x2002: sio.buf[0] = PAD2startPoll(2); break; + } + + sio.bufcount = 2; + sio.parp = 0; + sio.padst = 1; + sio.packetsize = 1; + sio.count = 0; + sio2.packet.recvVal1 = 0x1100; // Pad is present + SIO_INT(); + return; + + case 0x21: // start mtap + sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty + sio.StatReg |= RX_RDY; // Transfer is Ready + sio.parp = 0; + sio.packetsize = 1; + sio.mtapst = 1; + sio.count = 0; + sio2.packet.recvVal1 = 0x1D100; // Mtap is not connected :) + SIO_INT(); + return; + + case 0x61: // start remote control sensor + sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty + sio.StatReg |= RX_RDY; // Transfer is Ready + sio.parp = 0; + sio.packetsize = 1; + sio.count = 0; + sio2.packet.recvVal1 = 0x1100; // Pad is present + SIO_INT(); + return; + + case 0x81: // start memcard + { + sio.StatReg &= ~TX_EMPTY; + sio.StatReg |= RX_RDY; + memcpy(sio.buf, cardh, 4); + sio.parp = 0; + sio.bufcount = 8; + sio.mcdst = 1; + sio.packetsize = 1; + sio.rdwr = 0; + sio.count = 0; + + // Memcard presence reporting! + // In addition to checking the presence of MemoryCard1/2 file handles, we check a + // variable which force-disables all memory cards after a savestate recovery. This + // is needed to inform certain games to clear their cached memorycard indexes. + + // Note: + // 0x01100 means Memcard is present + // 0x1D100 means Memcard is missing. + + const int mcidx = sio.GetMemcardIndex(); + + if( m_PostSavestateCards[mcidx] ) + { + m_PostSavestateCards[mcidx]--; + sio2.packet.recvVal1 = 0x1D100; + PAD_LOG( "START MEMCARD[%d] - post-savestate - reported as missing!\n", sio.GetMemcardIndex() ); + } + else + { + sio2.packet.recvVal1 = TestMcdIsPresent( sio.GetMemcardIndex() ) ? 0x1100 : 0x1D100; + PAD_LOG("START MEMCARD [%d] - %s\n", + sio.GetMemcardIndex(), TestMcdIsPresent( sio.GetMemcardIndex() ) ? "Present" : "Missing" ); + } + + SIO_INT(); + } + return; + } +} + +void sioWrite8(u8 value) +{ + SIO_CommandWrite(value,0); +} + +void SIODMAWrite(u8 value) +{ + SIO_CommandWrite(value,1); +} + +void sioWriteCtrl16(u16 value) { + sio.CtrlReg = value & ~RESET_ERR; + if (value & RESET_ERR) sio.StatReg &= ~IRQ; + if ((sio.CtrlReg & SIO_RESET) || (!sio.CtrlReg)) + { + sio.mtapst = 0; sio.padst = 0; sio.mcdst = 0; sio.parp = 0; + sio.StatReg = TX_RDY | TX_EMPTY; + psxRegs.interrupt &= ~(1<> 13; - } -}; - -extern _sio sio; - -// Status Flags -#define TX_RDY 0x0001 -#define RX_RDY 0x0002 -#define TX_EMPTY 0x0004 -#define PARITY_ERR 0x0008 -#define RX_OVERRUN 0x0010 -#define FRAMING_ERR 0x0020 -#define SYNC_DETECT 0x0040 -#define DSR 0x0080 -#define CTS 0x0100 -#define IRQ 0x0200 - -// Control Flags -#define TX_PERM 0x0001 -#define DTR 0x0002 -#define RX_PERM 0x0004 -#define BREAK 0x0008 -#define RESET_ERR 0x0010 -#define RTS 0x0020 -#define SIO_RESET 0x0040 - -extern void sioInit(); -extern void sioShutdown(); -extern void psxSIOShutdown(); -extern u8 sioRead8(); -extern void sioWrite8(u8 value); -extern void sioWriteCtrl16(u16 value); -extern void sioInterrupt(); -extern void InitializeSIO(u8 value); - -#ifdef _MSC_VER -#pragma pack(1) -#endif -struct mc_command_0x26_tag{ - u8 field_151; //+02 flags - u16 sectorSize; //+03 divide to it - u16 field_2C; //+05 divide to it - u32 mc_size; //+07 - u8 mc_xor; //+0b don't forget to recalculate it!!! - u8 Z; //+0c -#ifdef _MSC_VER -}; -#pragma pack() -#else -} __attribute__((packed)); -#endif - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + + +#ifndef _SIO_H_ +#define _SIO_H_ + +// SIO IRQ Timings... +// Scheduling ints into the future is a purist approach to emulation, and +// is mostly cosmetic since the emulator itself performs all actions instantly +// (as far as the emulated CPU is concerned). In some cases this can actually +// cause more sync problems than it supposedly solves, due to accumulated +// delays incurred by the recompiler's low cycle update rate and also Pcsx2 +// failing to properly handle pre-emptive DMA/IRQs or cpu exceptions. + +// The SIO is one of these cases, where-by many games seem to be a lot happier +// if the SIO handles its IRQs instantly instead of scheduling them. +// Uncomment the line below for SIO instant-IRQ mode. It improves responsiveness +// considerably, fixes PAD latency problems in some games, and may even reduce the +// chance of saves getting corrupted (untested). But it lacks the purist touch, +// so it's not enabled by default. + +//#define SIO_INLINE_IRQS + + +struct _sio { + u16 StatReg; + u16 ModeReg; + u16 CtrlReg; + u16 BaudReg; + + u8 buf[256]; + u32 bufcount; + u32 parp; + u32 mcdst,rdwr; + u8 adrH,adrL; + u32 padst; + u32 mtapst; + u32 packetsize; + + u8 terminator; + u8 mode; + u8 mc_command; + u32 lastsector; + u32 sector; + u32 k; + u32 count; + + int GetMemcardIndex() const + { + return (CtrlReg&0x2000) >> 13; + } +}; + +extern _sio sio; + +// Status Flags +#define TX_RDY 0x0001 +#define RX_RDY 0x0002 +#define TX_EMPTY 0x0004 +#define PARITY_ERR 0x0008 +#define RX_OVERRUN 0x0010 +#define FRAMING_ERR 0x0020 +#define SYNC_DETECT 0x0040 +#define DSR 0x0080 +#define CTS 0x0100 +#define IRQ 0x0200 + +// Control Flags +#define TX_PERM 0x0001 +#define DTR 0x0002 +#define RX_PERM 0x0004 +#define BREAK 0x0008 +#define RESET_ERR 0x0010 +#define RTS 0x0020 +#define SIO_RESET 0x0040 + +extern void sioInit(); +extern void sioShutdown(); +extern void psxSIOShutdown(); +extern u8 sioRead8(); +extern void sioWrite8(u8 value); +extern void sioWriteCtrl16(u16 value); +extern void sioInterrupt(); +extern void InitializeSIO(u8 value); + +#ifdef _MSC_VER +#pragma pack(1) +#endif +struct mc_command_0x26_tag{ + u8 field_151; //+02 flags + u16 sectorSize; //+03 divide to it + u16 field_2C; //+05 divide to it + u32 mc_size; //+07 + u8 mc_xor; //+0b don't forget to recalculate it!!! + u8 Z; //+0c +#ifdef _MSC_VER +}; +#pragma pack() +#else +} __attribute__((packed)); +#endif + +#endif diff --git a/pcsx2/SourceLog.cpp b/pcsx2/SourceLog.cpp index 799453da90..c008e9f0f6 100644 --- a/pcsx2/SourceLog.cpp +++ b/pcsx2/SourceLog.cpp @@ -1,177 +1,177 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#ifdef _WIN32 -#include "RDebug/deci2.h" -#else -#include -#include "DebugTools/Debug.h" -#endif - -#include -#include - -#include "R3000A.h" -#include "iR5900.h" -#include "System.h" - -using namespace R5900; - -FILE *emuLog; - -#ifdef PCSX2_DEVBUILD -u32 varLog; - -// these used by the depreciated _old_Log only -u16 logProtocol; -u8 logSource; -#endif - -int connected=0; - -#define SYNC_LOGGING - -// writes text directly to the logfile, no newlines appended. -void __Log( const char* fmt, ... ) -{ - char tmp[2024]; - - va_list list; - va_start(list, fmt); - - // concatenate the log message after the prefix: - int length = vsprintf(tmp, fmt, list); - va_end( list ); - - assert( length <= 2020 ); - if( length > 2020 ) - { - Msgbox::Alert("Source Log Stack Corruption Detected. Program execution may become unstable."); - // fixme: should throw an exception here once we have proper exception handling implemented. - } - - if (varLog & 0x80000000) // log to console enabled? - { - Console::Write(tmp); - - } - else if( emuLog != NULL ) // manually write to the logfile. - { - fputs( tmp, emuLog ); - //fputs( "\r\n", emuLog ); - fflush( emuLog ); - } -} - -static __forceinline void _vSourceLog( u16 protocol, u8 source, u32 cpuPc, u32 cpuCycle, const char *fmt, va_list list ) -{ - char tmp[2024]; - - int prelength = sprintf( tmp, "%c/%8.8lx %8.8lx: ", source, cpuPc, cpuCycle ); - - // concatenate the log message after the prefix: - int length = vsprintf(&tmp[prelength], fmt, list); - assert( length <= 2020 ); - if( length > 2020 ) - { - Msgbox::Alert("Source Log Stack Corruption Detected. Program execution may become unstable."); - // fixme: should throw an exception here once we have proper exception handling implemented. - } - -#ifdef PCSX2_DEVBUILD -#ifdef _WIN32 - // Send log data to the (remote?) debugger. - if (connected && logProtocol>=0 && logProtocol<0x10) - { - sendTTYP(logProtocol, logSource, tmp); - } -#endif -#endif - - if (varLog & 0x80000000) // log to console enabled? - { - Console::WriteLn(tmp); - - } else if( emuLog != NULL ) // manually write to the logfile. - { - fputs( tmp, emuLog ); - //fputs( "\r\n", emuLog ); - fflush( emuLog ); - } -} - -// Note: This function automatically appends a newline character always! -// (actually it doesn't yet because too much legacy code, will fix soon!) -void SourceLog( u16 protocol, u8 source, u32 cpuPc, u32 cpuCycle, const char *fmt, ...) -{ - va_list list; - va_start(list, fmt); - _vSourceLog( protocol, source, cpuPc, cpuCycle, fmt, list ); - va_end(list); -} - -// Functions with variable argument lists can't be inlined. -#define IMPLEMENT_SOURCE_LOG( unit, source, protocol ) \ - void SrcLog_##unit( const char* fmt, ... ) \ - { \ - va_list list; \ - va_start( list, fmt ); \ - _vSourceLog( protocol, source, \ - (source == 'E') ? cpuRegs.pc : psxRegs.pc, \ - (source == 'E') ? cpuRegs.cycle : psxRegs.cycle, fmt, list ); \ - va_end( list ); \ - } \ - -IMPLEMENT_SOURCE_LOG( EECNT, 'E', 0 ) -IMPLEMENT_SOURCE_LOG( BIOS, 'E', 0 ) - -IMPLEMENT_SOURCE_LOG( CPU, 'E', 1 ) -IMPLEMENT_SOURCE_LOG( FPU, 'E', 1 ) -IMPLEMENT_SOURCE_LOG( MMI, 'E', 1 ) -IMPLEMENT_SOURCE_LOG( COP0, 'E', 1 ) - -IMPLEMENT_SOURCE_LOG( MEM, 'E', 6 ) -IMPLEMENT_SOURCE_LOG( HW, 'E', 6 ) -IMPLEMENT_SOURCE_LOG( DMA, 'E', 5 ) -IMPLEMENT_SOURCE_LOG( ELF, 'E', 7 ) -IMPLEMENT_SOURCE_LOG( VU0, 'E', 2 ) -IMPLEMENT_SOURCE_LOG( VIF, 'E', 3 ) -IMPLEMENT_SOURCE_LOG( SPR, 'E', 7 ) -IMPLEMENT_SOURCE_LOG( GIF, 'E', 4 ) -IMPLEMENT_SOURCE_LOG( SIF, 'E', 9 ) -IMPLEMENT_SOURCE_LOG( IPU, 'E', 8 ) -IMPLEMENT_SOURCE_LOG( VUM, 'E', 2 ) -IMPLEMENT_SOURCE_LOG( RPC, 'E', 9 ) - -IMPLEMENT_SOURCE_LOG( PSXCPU, 'I', 1 ) -IMPLEMENT_SOURCE_LOG( PSXMEM, 'I', 6 ) -IMPLEMENT_SOURCE_LOG( PSXHW, 'I', 2 ) -IMPLEMENT_SOURCE_LOG( PSXBIOS, 'I', 0 ) -IMPLEMENT_SOURCE_LOG( PSXDMA, 'I', 5 ) -IMPLEMENT_SOURCE_LOG( PSXCNT, 'I', 4 ) - -IMPLEMENT_SOURCE_LOG( MEMCARDS, 'I', 7 ) -IMPLEMENT_SOURCE_LOG( PAD, 'I', 7 ) -IMPLEMENT_SOURCE_LOG( GTE, 'I', 3 ) -IMPLEMENT_SOURCE_LOG( CDR, 'I', 8 ) - - - - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#ifdef _WIN32 +#include "RDebug/deci2.h" +#else +#include +#include "DebugTools/Debug.h" +#endif + +#include +#include + +#include "R3000A.h" +#include "iR5900.h" +#include "System.h" + +using namespace R5900; + +FILE *emuLog; + +#ifdef PCSX2_DEVBUILD +u32 varLog; + +// these used by the depreciated _old_Log only +u16 logProtocol; +u8 logSource; +#endif + +int connected=0; + +#define SYNC_LOGGING + +// writes text directly to the logfile, no newlines appended. +void __Log( const char* fmt, ... ) +{ + char tmp[2024]; + + va_list list; + va_start(list, fmt); + + // concatenate the log message after the prefix: + int length = vsprintf(tmp, fmt, list); + va_end( list ); + + assert( length <= 2020 ); + if( length > 2020 ) + { + Msgbox::Alert("Source Log Stack Corruption Detected. Program execution may become unstable."); + // fixme: should throw an exception here once we have proper exception handling implemented. + } + + if (varLog & 0x80000000) // log to console enabled? + { + Console::Write(tmp); + + } + else if( emuLog != NULL ) // manually write to the logfile. + { + fputs( tmp, emuLog ); + //fputs( "\r\n", emuLog ); + fflush( emuLog ); + } +} + +static __forceinline void _vSourceLog( u16 protocol, u8 source, u32 cpuPc, u32 cpuCycle, const char *fmt, va_list list ) +{ + char tmp[2024]; + + int prelength = sprintf( tmp, "%c/%8.8lx %8.8lx: ", source, cpuPc, cpuCycle ); + + // concatenate the log message after the prefix: + int length = vsprintf(&tmp[prelength], fmt, list); + assert( length <= 2020 ); + if( length > 2020 ) + { + Msgbox::Alert("Source Log Stack Corruption Detected. Program execution may become unstable."); + // fixme: should throw an exception here once we have proper exception handling implemented. + } + +#ifdef PCSX2_DEVBUILD +#ifdef _WIN32 + // Send log data to the (remote?) debugger. + if (connected && logProtocol>=0 && logProtocol<0x10) + { + sendTTYP(logProtocol, logSource, tmp); + } +#endif +#endif + + if (varLog & 0x80000000) // log to console enabled? + { + Console::WriteLn(tmp); + + } else if( emuLog != NULL ) // manually write to the logfile. + { + fputs( tmp, emuLog ); + //fputs( "\r\n", emuLog ); + fflush( emuLog ); + } +} + +// Note: This function automatically appends a newline character always! +// (actually it doesn't yet because too much legacy code, will fix soon!) +void SourceLog( u16 protocol, u8 source, u32 cpuPc, u32 cpuCycle, const char *fmt, ...) +{ + va_list list; + va_start(list, fmt); + _vSourceLog( protocol, source, cpuPc, cpuCycle, fmt, list ); + va_end(list); +} + +// Functions with variable argument lists can't be inlined. +#define IMPLEMENT_SOURCE_LOG( unit, source, protocol ) \ + void SrcLog_##unit( const char* fmt, ... ) \ + { \ + va_list list; \ + va_start( list, fmt ); \ + _vSourceLog( protocol, source, \ + (source == 'E') ? cpuRegs.pc : psxRegs.pc, \ + (source == 'E') ? cpuRegs.cycle : psxRegs.cycle, fmt, list ); \ + va_end( list ); \ + } \ + +IMPLEMENT_SOURCE_LOG( EECNT, 'E', 0 ) +IMPLEMENT_SOURCE_LOG( BIOS, 'E', 0 ) + +IMPLEMENT_SOURCE_LOG( CPU, 'E', 1 ) +IMPLEMENT_SOURCE_LOG( FPU, 'E', 1 ) +IMPLEMENT_SOURCE_LOG( MMI, 'E', 1 ) +IMPLEMENT_SOURCE_LOG( COP0, 'E', 1 ) + +IMPLEMENT_SOURCE_LOG( MEM, 'E', 6 ) +IMPLEMENT_SOURCE_LOG( HW, 'E', 6 ) +IMPLEMENT_SOURCE_LOG( DMA, 'E', 5 ) +IMPLEMENT_SOURCE_LOG( ELF, 'E', 7 ) +IMPLEMENT_SOURCE_LOG( VU0, 'E', 2 ) +IMPLEMENT_SOURCE_LOG( VIF, 'E', 3 ) +IMPLEMENT_SOURCE_LOG( SPR, 'E', 7 ) +IMPLEMENT_SOURCE_LOG( GIF, 'E', 4 ) +IMPLEMENT_SOURCE_LOG( SIF, 'E', 9 ) +IMPLEMENT_SOURCE_LOG( IPU, 'E', 8 ) +IMPLEMENT_SOURCE_LOG( VUM, 'E', 2 ) +IMPLEMENT_SOURCE_LOG( RPC, 'E', 9 ) + +IMPLEMENT_SOURCE_LOG( PSXCPU, 'I', 1 ) +IMPLEMENT_SOURCE_LOG( PSXMEM, 'I', 6 ) +IMPLEMENT_SOURCE_LOG( PSXHW, 'I', 2 ) +IMPLEMENT_SOURCE_LOG( PSXBIOS, 'I', 0 ) +IMPLEMENT_SOURCE_LOG( PSXDMA, 'I', 5 ) +IMPLEMENT_SOURCE_LOG( PSXCNT, 'I', 4 ) + +IMPLEMENT_SOURCE_LOG( MEMCARDS, 'I', 7 ) +IMPLEMENT_SOURCE_LOG( PAD, 'I', 7 ) +IMPLEMENT_SOURCE_LOG( GTE, 'I', 3 ) +IMPLEMENT_SOURCE_LOG( CDR, 'I', 8 ) + + + + diff --git a/pcsx2/Stats.cpp b/pcsx2/Stats.cpp index 4cccfb5d38..e3a8046175 100644 --- a/pcsx2/Stats.cpp +++ b/pcsx2/Stats.cpp @@ -1,72 +1,72 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include - -#include "Common.h" -#include "PsxCommon.h" -#include "Stats.h" - -#include "Paths.h" - -void statsOpen() { - stats.vsyncCount = 0; - stats.vsyncTime = time(NULL); - stats.eeCycles = 0; - stats.eeSCycle = 0; - stats.iopCycles = 0; - stats.iopSCycle = 0; -} - -void statsClose() { - time_t t; - FILE *f; - - t = time(NULL) - stats.vsyncTime; -#ifdef _WIN32 - f = fopen(LOGS_DIR "\\stats.txt", "w"); -#else - f = fopen(LOGS_DIR "/stats.txt", "w"); -#endif - if (!f) { SysPrintf("Can't open stats.txt\n"); return; } - fprintf(f, "-- PCSX2 v%s statics--\n\n", PCSX2_VERSION); - fprintf(f, "Ran for %d seconds\n", t); - fprintf(f, "Total VSyncs: %d (%s)\n", stats.vsyncCount, Config.PsxType ? "PAL" : "NTSC"); - fprintf(f, "VSyncs per Seconds: %g\n", (double)stats.vsyncCount / t); - fprintf(f, "Total EE Instructions Executed: %lld\n", stats.eeCycles); - fprintf(f, "Total IOP Instructions Executed: %lld\n", stats.iopCycles); - if (!CHECK_EEREC) fprintf(f, "Interpreter Mode\n"); - else fprintf(f, "Recompiler Mode: VUrec1 %s, VUrec0 %s\n", - CHECK_VU1REC ? "Enabled" : "Disabled", CHECK_VU0REC ? "Enabled" : "Disabled"); - fclose(f); -} - -void statsVSync() { - static u64 accum = 0, accumvu1 = 0; - static u32 frame = 0; - - stats.eeCycles+= cpuRegs.cycle - stats.eeSCycle; - stats.eeSCycle = cpuRegs.cycle; - stats.iopCycles+= psxRegs.cycle - stats.iopSCycle; - stats.iopSCycle = psxRegs.cycle; - stats.vsyncCount++; - stats.vif1count = 0; - stats.vu1count = 0; -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include + +#include "Common.h" +#include "PsxCommon.h" +#include "Stats.h" + +#include "Paths.h" + +void statsOpen() { + stats.vsyncCount = 0; + stats.vsyncTime = time(NULL); + stats.eeCycles = 0; + stats.eeSCycle = 0; + stats.iopCycles = 0; + stats.iopSCycle = 0; +} + +void statsClose() { + time_t t; + FILE *f; + + t = time(NULL) - stats.vsyncTime; +#ifdef _WIN32 + f = fopen(LOGS_DIR "\\stats.txt", "w"); +#else + f = fopen(LOGS_DIR "/stats.txt", "w"); +#endif + if (!f) { SysPrintf("Can't open stats.txt\n"); return; } + fprintf(f, "-- PCSX2 v%s statics--\n\n", PCSX2_VERSION); + fprintf(f, "Ran for %d seconds\n", t); + fprintf(f, "Total VSyncs: %d (%s)\n", stats.vsyncCount, Config.PsxType ? "PAL" : "NTSC"); + fprintf(f, "VSyncs per Seconds: %g\n", (double)stats.vsyncCount / t); + fprintf(f, "Total EE Instructions Executed: %lld\n", stats.eeCycles); + fprintf(f, "Total IOP Instructions Executed: %lld\n", stats.iopCycles); + if (!CHECK_EEREC) fprintf(f, "Interpreter Mode\n"); + else fprintf(f, "Recompiler Mode: VUrec1 %s, VUrec0 %s\n", + CHECK_VU1REC ? "Enabled" : "Disabled", CHECK_VU0REC ? "Enabled" : "Disabled"); + fclose(f); +} + +void statsVSync() { + static u64 accum = 0, accumvu1 = 0; + static u32 frame = 0; + + stats.eeCycles+= cpuRegs.cycle - stats.eeSCycle; + stats.eeSCycle = cpuRegs.cycle; + stats.iopCycles+= psxRegs.cycle - stats.iopSCycle; + stats.iopSCycle = psxRegs.cycle; + stats.vsyncCount++; + stats.vif1count = 0; + stats.vu1count = 0; +} diff --git a/pcsx2/Stats.h b/pcsx2/Stats.h index 1dc1d74f2d..518e7863fc 100644 --- a/pcsx2/Stats.h +++ b/pcsx2/Stats.h @@ -1,44 +1,44 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __STATS_H__ -#define __STATS_H__ - -#include - -struct Stats { - time_t vsyncTime; - u32 vsyncCount; - u32 eeCycles; - u32 eeSCycle; - u32 iopCycles; - u32 iopSCycle; - - u32 ticko; - u32 framecount; - u32 vu1count; - u32 vif1count; -}; - -Stats stats; - -void statsOpen(); -void statsClose(); -void statsVSync(); - -#endif /* __STATS_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __STATS_H__ +#define __STATS_H__ + +#include + +struct Stats { + time_t vsyncTime; + u32 vsyncCount; + u32 eeCycles; + u32 eeSCycle; + u32 iopCycles; + u32 iopSCycle; + + u32 ticko; + u32 framecount; + u32 vu1count; + u32 vif1count; +}; + +Stats stats; + +void statsOpen(); +void statsClose(); +void statsVSync(); + +#endif /* __STATS_H__ */ diff --git a/pcsx2/StringUtils.h b/pcsx2/StringUtils.h index 7bc3d074eb..d9707ed59b 100644 --- a/pcsx2/StringUtils.h +++ b/pcsx2/StringUtils.h @@ -1,75 +1,75 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef _PCSX2_STRINGUTILS_H_ -#define _PCSX2_STRINGUTILS_H_ - -#include -#include -#include - -// to_string: A utility template for quick and easy inline string type conversion. -// Use to_string(intval), or to_string(float), etc. Anything that the STL itself -// would support should be supported here. :) -template< typename T > -std::string to_string(const T& value) -{ - std::ostringstream oss; - oss << value; - return oss.str(); -} - -// dummy structure used to type-guard the dummy parameter that's been inserted to -// allow us to use the va_list feature on references. -struct _VARG_PARAM -{ - // just some value to make the struct length 32bits instead of 8 bits, so that the - // compiler generates somewhat more efficient code. - uint someval; -}; - -#ifdef _DEBUG - -#define params va_arg_dummy, -#define varg_assert() // jASSUME( dummy == &va_arg_dummy ); -// typedef the Va-Arg value to be a value type in debug builds. The value -// type requires a little more overhead in terms of code generation, but is always -// type-safe. The compiler will generate errors for any forgotten params value. -typedef _VARG_PARAM VARG_PARAM; - -#else - -#define params NULL, // using null is faster / more compact! -#define varg_assert() jASSUME( dummy == NULL ); -// typedef the Va-Arg value to be a pointer in release builds. Pointers -// generate more compact code by a small margin, but aren't entirely type safe since -// the compiler won't generate errors if you pass NULL or other values. -typedef _VARG_PARAM const * VARG_PARAM; - -#endif - -extern const _VARG_PARAM va_arg_dummy; - -extern void ssprintf(std::string& dest, const char* fmt, ...); -extern void ssappendf( std::string& dest, const char* format, ...); -extern void vssprintf(std::string& dest, const char* format, va_list args); -extern void vssappendf(std::string& dest, const char* format, va_list args); - -extern std::string fmt_string( const char* fmt, ... ); -extern std::string vfmt_string( const char* fmt, va_list args ); -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef _PCSX2_STRINGUTILS_H_ +#define _PCSX2_STRINGUTILS_H_ + +#include +#include +#include + +// to_string: A utility template for quick and easy inline string type conversion. +// Use to_string(intval), or to_string(float), etc. Anything that the STL itself +// would support should be supported here. :) +template< typename T > +std::string to_string(const T& value) +{ + std::ostringstream oss; + oss << value; + return oss.str(); +} + +// dummy structure used to type-guard the dummy parameter that's been inserted to +// allow us to use the va_list feature on references. +struct _VARG_PARAM +{ + // just some value to make the struct length 32bits instead of 8 bits, so that the + // compiler generates somewhat more efficient code. + uint someval; +}; + +#ifdef _DEBUG + +#define params va_arg_dummy, +#define varg_assert() // jASSUME( dummy == &va_arg_dummy ); +// typedef the Va-Arg value to be a value type in debug builds. The value +// type requires a little more overhead in terms of code generation, but is always +// type-safe. The compiler will generate errors for any forgotten params value. +typedef _VARG_PARAM VARG_PARAM; + +#else + +#define params NULL, // using null is faster / more compact! +#define varg_assert() jASSUME( dummy == NULL ); +// typedef the Va-Arg value to be a pointer in release builds. Pointers +// generate more compact code by a small margin, but aren't entirely type safe since +// the compiler won't generate errors if you pass NULL or other values. +typedef _VARG_PARAM const * VARG_PARAM; + +#endif + +extern const _VARG_PARAM va_arg_dummy; + +extern void ssprintf(std::string& dest, const char* fmt, ...); +extern void ssappendf( std::string& dest, const char* format, ...); +extern void vssprintf(std::string& dest, const char* format, va_list args); +extern void vssappendf(std::string& dest, const char* format, va_list args); + +extern std::string fmt_string( const char* fmt, ... ); +extern std::string vfmt_string( const char* fmt, va_list args ); +#endif diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp index 9f797eed7a..66291160ff 100644 --- a/pcsx2/System.cpp +++ b/pcsx2/System.cpp @@ -1,333 +1,333 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "VUmicro.h" -#include "Threading.h" - -#include "iR5900.h" -#include "iR3000A.h" -#include "IopMem.h" -#include "iVUzerorec.h" // for SuperVUReset - - -#include "x86/ix86/ix86.h" - -using namespace std; -using namespace Console; - -// disable all session overrides by default... -SessionOverrideFlags g_Session = {false}; - -bool sysInitialized = false; - -namespace Exception -{ - BaseException::~BaseException() throw() {} -} - - -// I can't believe I had to make my own version of trim. C++'s STL is totally whack. -// And I still had to fix it too. I found three samples of trim online and *all* three -// were buggy. People really need to learn to code before they start posting trim -// functions in their blogs. (air) -static void trim( string& line ) -{ - if ( line.empty() ) - return; - - int string_size = line.length(); - int beginning_of_string = 0; - int end_of_string = string_size - 1; - - bool encountered_characters = false; - - // find the start of characters in the string - while ( (beginning_of_string < string_size) && (!encountered_characters) ) - { - if ( (line[ beginning_of_string ] != ' ') && (line[ beginning_of_string ] != '\t') ) - encountered_characters = true; - else - ++beginning_of_string; - } - - // test if no characters were found in the string - if ( beginning_of_string == string_size ) - return; - - encountered_characters = false; - - // find the character in the string - while ( (end_of_string > beginning_of_string) && (!encountered_characters) ) - { - // if a space or tab was found then ignore it - if ( (line[ end_of_string ] != ' ') && (line[ end_of_string ] != '\t') ) - encountered_characters = true; - else - --end_of_string; - } - - // return the original string with all whitespace removed from its beginning and end - // + 1 at the end to add the space for the string delimiter - //line.substr( beginning_of_string, end_of_string - beginning_of_string + 1 ); - line.erase( end_of_string+1, string_size ); - line.erase( 0, beginning_of_string ); -} - - -// This function should be called once during program execution. -void SysDetect() -{ - if( sysInitialized ) return; - sysInitialized = true; - - Notice("PCSX2 " PCSX2_VERSION " - compiled on %s", params __DATE__ ); - Notice("Savestate version: %x", params g_SaveVersion); - - // fixme: This line is here for the purpose of creating external ASM code. Yah. >_< - DevCon::Notice( "EE pc offset: 0x%x, IOP pc offset: 0x%x", params (u32)&cpuRegs.pc - (u32)&cpuRegs, (u32)&psxRegs.pc - (u32)&psxRegs ); - - cpudetectInit(); - - string family( cpuinfo.x86Fam ); - trim( family ); - - SetColor( Console::Color_White ); - - WriteLn( "x86Init:" ); - WriteLn( - "\tCPU vendor name = %s\n" - "\tFamilyID = %x\n" - "\tx86Family = %s\n" - "\tCPU speed = %d.%03d Ghz\n" - "\tCores = %d physical [%d logical]\n" - "\tx86PType = %s\n" - "\tx86Flags = %8.8x %8.8x\n" - "\tx86EFlags = %8.8x\n", params - cpuinfo.x86ID, cpuinfo.x86StepID, family.c_str(), - cpuinfo.cpuspeed / 1000, cpuinfo.cpuspeed%1000, - cpuinfo.PhysicalCores, cpuinfo.LogicalCores, - cpuinfo.x86Type, cpuinfo.x86Flags, cpuinfo.x86Flags2, - cpuinfo.x86EFlags - ); - - WriteLn( "Features:" ); - WriteLn( - "\t%sDetected MMX\n" - "\t%sDetected SSE\n" - "\t%sDetected SSE2\n" - "\t%sDetected SSE3\n" - "\t%sDetected SSE4.1\n", params - cpucaps.hasMultimediaExtensions ? "" : "Not ", - cpucaps.hasStreamingSIMDExtensions ? "" : "Not ", - cpucaps.hasStreamingSIMD2Extensions ? "" : "Not ", - cpucaps.hasStreamingSIMD3Extensions ? "" : "Not ", - cpucaps.hasStreamingSIMD4Extensions ? "" : "Not " - ); - - if ( cpuinfo.x86ID[0] == 'A' ) //AMD cpu - { - WriteLn( " Extended AMD Features:" ); - WriteLn( - "\t%sDetected MMX2\n" - "\t%sDetected 3DNOW\n" - "\t%sDetected 3DNOW2\n", params - cpucaps.hasMultimediaExtensionsExt ? "" : "Not ", - cpucaps.has3DNOWInstructionExtensions ? "" : "Not ", - cpucaps.has3DNOWInstructionExtensionsExt ? "" : "Not " - ); - } - - Console::ClearColor(); -} - -// Allocates memory for all PS2 systems. -bool SysAllocateMem() -{ - // Allocate PS2 system ram space (required by interpreters and recompilers both) - - try - { - memAlloc(); - psxMemAlloc(); - vuMicroMemAlloc(); - } - catch( Exception::OutOfMemory& ex ) - { - // Failures on the core initialization of memory is bad, since it means the emulator is - // completely non-functional. If the failure is in the VM build then we can try running - // the VTLB build instead. If it's the VTLB build then ... ouch. - - // VTLB build must fail outright... - Msgbox::Alert( "Failed to allocate memory needed to run pcsx2.\n\nError: %s", params ex.cMessage() ); - SysShutdownMem(); - - return false; - } - - return true; -} - - -// Allocates memory for all recompilers, and force-disables any recs that fail to initialize. -// This should be done asap, since the recompilers tend to demand a lot of system resources, and prefer -// to have those resources at specific address ranges. The sooner memory is allocated, the better. -// Returns FALSE on *critical* failure (GUI should issue a msg and exit). -void SysAllocateDynarecs() -{ - // Attempt to initialize the recompilers. - // Most users want to use recs anyway, and if they are using interpreters I don't think the - // extra few megs of allocation is going to be an issue. - - try - { - // R5900 and R3000a must be rec-enabled together for now so if either fails they both fail. - recCpu.Allocate(); - psxRec.Allocate(); - } - catch( Exception::BaseException& ex ) - { - Msgbox::Alert( - "The EE/IOP recompiler failed to initialize with the following error:\n\n" - "%s" - "\n\nThe EE/IOP interpreter will be used instead (slow!).", params - ex.cMessage() - ); - - g_Session.ForceDisableEErec = true; - - recCpu.Shutdown(); - psxRec.Shutdown(); - } - - try - { - VU0micro::recAlloc(); - } - catch( Exception::BaseException& ex ) - { - Msgbox::Alert( - "The VU0 recompiler failed to initialize with the following error:\n\n" - "%s" - "\n\nThe VU0 interpreter will be used for this session (may slow down some games).", params - ex.cMessage() - ); - - g_Session.ForceDisableVU0rec = true; - VU0micro::recShutdown(); - } - - try - { - VU1micro::recAlloc(); - } - catch( Exception::BaseException& ex ) - { - Msgbox::Alert( - "The VU1 recompiler failed to initialize with the following error:\n\n" - "%s" - "\n\nThe VU1 interpreter will be used for this session (will slow down most games).", params - ex.cMessage() - ); - - g_Session.ForceDisableVU1rec = true; - VU1micro::recShutdown(); - } - - // If both VUrecs failed, then make sure the SuperVU is totally closed out: - if( !CHECK_VU0REC && !CHECK_VU1REC) - SuperVUDestroy( -1 ); - -} - -// This should be called last thing before Pcsx2 exits. -void SysShutdownMem() -{ - cpuShutdown(); - - vuMicroMemShutdown(); - psxMemShutdown(); - memShutdown(); -} - -// This should generally be called right before calling SysShutdownMem(), although you can optionally -// use it in conjunction with SysAllocDynarecs to allocate/free the dynarec resources on the fly (as -// risky as it might be, since dynarecs could very well fail on the second attempt). -void SysShutdownDynarecs() -{ - // Special SuperVU "complete" terminator. - SuperVUDestroy( -1 ); - - psxRec.Shutdown(); - recCpu.Shutdown(); -} - -// Resets all PS2 cpu execution states, which does not affect that actual PS2 state/condition. -// This can be called at any time outside the context of a Cpu->Execute() block without -// bad things happening (recompilers will slow down for a brief moment since rec code blocks -// are dumped). -// Use this method to reset the recs when important global pointers like the MTGS are re-assigned. -void SysResetExecutionState() -{ - if( CHECK_EEREC ) - { - Cpu = &recCpu; - psxCpu = &psxRec; - } - else - { - Cpu = &intCpu; - psxCpu = &psxInt; - } - - Cpu->Reset(); - psxCpu->Reset(); - - vuMicroCpuReset(); - - // make sure the VU1 doesn't have lingering "skip" enabled. - vu1MicroDisableSkip(); -} - -u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller) -{ - u8 *Mem = (u8*)SysMmap( base, size ); - - if( (Mem == NULL) || (bounds != 0 && (((uptr)Mem + size) > bounds)) ) - { - DevCon::Notice( "First try failed allocating %s at address 0x%x", params caller, base ); - - // memory allocation *must* have the top bit clear, so let's try again - // with NULL (let the OS pick something for us). - - SafeSysMunmap( Mem, size ); - - Mem = (u8*)SysMmap( NULL, size ); - if( bounds != 0 && (((uptr)Mem + size) > bounds) ) - { - DevCon::Error( "Fatal Error:\n\tSecond try failed allocating %s, block ptr 0x%x does not meet required criteria.", params caller, Mem ); - SafeSysMunmap( Mem, size ); - - // returns NULL, caller should throw an exception. - } - } - return Mem; -} - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "VUmicro.h" +#include "Threading.h" + +#include "iR5900.h" +#include "iR3000A.h" +#include "IopMem.h" +#include "iVUzerorec.h" // for SuperVUReset + + +#include "x86/ix86/ix86.h" + +using namespace std; +using namespace Console; + +// disable all session overrides by default... +SessionOverrideFlags g_Session = {false}; + +bool sysInitialized = false; + +namespace Exception +{ + BaseException::~BaseException() throw() {} +} + + +// I can't believe I had to make my own version of trim. C++'s STL is totally whack. +// And I still had to fix it too. I found three samples of trim online and *all* three +// were buggy. People really need to learn to code before they start posting trim +// functions in their blogs. (air) +static void trim( string& line ) +{ + if ( line.empty() ) + return; + + int string_size = line.length(); + int beginning_of_string = 0; + int end_of_string = string_size - 1; + + bool encountered_characters = false; + + // find the start of characters in the string + while ( (beginning_of_string < string_size) && (!encountered_characters) ) + { + if ( (line[ beginning_of_string ] != ' ') && (line[ beginning_of_string ] != '\t') ) + encountered_characters = true; + else + ++beginning_of_string; + } + + // test if no characters were found in the string + if ( beginning_of_string == string_size ) + return; + + encountered_characters = false; + + // find the character in the string + while ( (end_of_string > beginning_of_string) && (!encountered_characters) ) + { + // if a space or tab was found then ignore it + if ( (line[ end_of_string ] != ' ') && (line[ end_of_string ] != '\t') ) + encountered_characters = true; + else + --end_of_string; + } + + // return the original string with all whitespace removed from its beginning and end + // + 1 at the end to add the space for the string delimiter + //line.substr( beginning_of_string, end_of_string - beginning_of_string + 1 ); + line.erase( end_of_string+1, string_size ); + line.erase( 0, beginning_of_string ); +} + + +// This function should be called once during program execution. +void SysDetect() +{ + if( sysInitialized ) return; + sysInitialized = true; + + Notice("PCSX2 " PCSX2_VERSION " - compiled on %s", params __DATE__ ); + Notice("Savestate version: %x", params g_SaveVersion); + + // fixme: This line is here for the purpose of creating external ASM code. Yah. >_< + DevCon::Notice( "EE pc offset: 0x%x, IOP pc offset: 0x%x", params (u32)&cpuRegs.pc - (u32)&cpuRegs, (u32)&psxRegs.pc - (u32)&psxRegs ); + + cpudetectInit(); + + string family( cpuinfo.x86Fam ); + trim( family ); + + SetColor( Console::Color_White ); + + WriteLn( "x86Init:" ); + WriteLn( + "\tCPU vendor name = %s\n" + "\tFamilyID = %x\n" + "\tx86Family = %s\n" + "\tCPU speed = %d.%03d Ghz\n" + "\tCores = %d physical [%d logical]\n" + "\tx86PType = %s\n" + "\tx86Flags = %8.8x %8.8x\n" + "\tx86EFlags = %8.8x\n", params + cpuinfo.x86ID, cpuinfo.x86StepID, family.c_str(), + cpuinfo.cpuspeed / 1000, cpuinfo.cpuspeed%1000, + cpuinfo.PhysicalCores, cpuinfo.LogicalCores, + cpuinfo.x86Type, cpuinfo.x86Flags, cpuinfo.x86Flags2, + cpuinfo.x86EFlags + ); + + WriteLn( "Features:" ); + WriteLn( + "\t%sDetected MMX\n" + "\t%sDetected SSE\n" + "\t%sDetected SSE2\n" + "\t%sDetected SSE3\n" + "\t%sDetected SSE4.1\n", params + cpucaps.hasMultimediaExtensions ? "" : "Not ", + cpucaps.hasStreamingSIMDExtensions ? "" : "Not ", + cpucaps.hasStreamingSIMD2Extensions ? "" : "Not ", + cpucaps.hasStreamingSIMD3Extensions ? "" : "Not ", + cpucaps.hasStreamingSIMD4Extensions ? "" : "Not " + ); + + if ( cpuinfo.x86ID[0] == 'A' ) //AMD cpu + { + WriteLn( " Extended AMD Features:" ); + WriteLn( + "\t%sDetected MMX2\n" + "\t%sDetected 3DNOW\n" + "\t%sDetected 3DNOW2\n", params + cpucaps.hasMultimediaExtensionsExt ? "" : "Not ", + cpucaps.has3DNOWInstructionExtensions ? "" : "Not ", + cpucaps.has3DNOWInstructionExtensionsExt ? "" : "Not " + ); + } + + Console::ClearColor(); +} + +// Allocates memory for all PS2 systems. +bool SysAllocateMem() +{ + // Allocate PS2 system ram space (required by interpreters and recompilers both) + + try + { + memAlloc(); + psxMemAlloc(); + vuMicroMemAlloc(); + } + catch( Exception::OutOfMemory& ex ) + { + // Failures on the core initialization of memory is bad, since it means the emulator is + // completely non-functional. If the failure is in the VM build then we can try running + // the VTLB build instead. If it's the VTLB build then ... ouch. + + // VTLB build must fail outright... + Msgbox::Alert( "Failed to allocate memory needed to run pcsx2.\n\nError: %s", params ex.cMessage() ); + SysShutdownMem(); + + return false; + } + + return true; +} + + +// Allocates memory for all recompilers, and force-disables any recs that fail to initialize. +// This should be done asap, since the recompilers tend to demand a lot of system resources, and prefer +// to have those resources at specific address ranges. The sooner memory is allocated, the better. +// Returns FALSE on *critical* failure (GUI should issue a msg and exit). +void SysAllocateDynarecs() +{ + // Attempt to initialize the recompilers. + // Most users want to use recs anyway, and if they are using interpreters I don't think the + // extra few megs of allocation is going to be an issue. + + try + { + // R5900 and R3000a must be rec-enabled together for now so if either fails they both fail. + recCpu.Allocate(); + psxRec.Allocate(); + } + catch( Exception::BaseException& ex ) + { + Msgbox::Alert( + "The EE/IOP recompiler failed to initialize with the following error:\n\n" + "%s" + "\n\nThe EE/IOP interpreter will be used instead (slow!).", params + ex.cMessage() + ); + + g_Session.ForceDisableEErec = true; + + recCpu.Shutdown(); + psxRec.Shutdown(); + } + + try + { + VU0micro::recAlloc(); + } + catch( Exception::BaseException& ex ) + { + Msgbox::Alert( + "The VU0 recompiler failed to initialize with the following error:\n\n" + "%s" + "\n\nThe VU0 interpreter will be used for this session (may slow down some games).", params + ex.cMessage() + ); + + g_Session.ForceDisableVU0rec = true; + VU0micro::recShutdown(); + } + + try + { + VU1micro::recAlloc(); + } + catch( Exception::BaseException& ex ) + { + Msgbox::Alert( + "The VU1 recompiler failed to initialize with the following error:\n\n" + "%s" + "\n\nThe VU1 interpreter will be used for this session (will slow down most games).", params + ex.cMessage() + ); + + g_Session.ForceDisableVU1rec = true; + VU1micro::recShutdown(); + } + + // If both VUrecs failed, then make sure the SuperVU is totally closed out: + if( !CHECK_VU0REC && !CHECK_VU1REC) + SuperVUDestroy( -1 ); + +} + +// This should be called last thing before Pcsx2 exits. +void SysShutdownMem() +{ + cpuShutdown(); + + vuMicroMemShutdown(); + psxMemShutdown(); + memShutdown(); +} + +// This should generally be called right before calling SysShutdownMem(), although you can optionally +// use it in conjunction with SysAllocDynarecs to allocate/free the dynarec resources on the fly (as +// risky as it might be, since dynarecs could very well fail on the second attempt). +void SysShutdownDynarecs() +{ + // Special SuperVU "complete" terminator. + SuperVUDestroy( -1 ); + + psxRec.Shutdown(); + recCpu.Shutdown(); +} + +// Resets all PS2 cpu execution states, which does not affect that actual PS2 state/condition. +// This can be called at any time outside the context of a Cpu->Execute() block without +// bad things happening (recompilers will slow down for a brief moment since rec code blocks +// are dumped). +// Use this method to reset the recs when important global pointers like the MTGS are re-assigned. +void SysResetExecutionState() +{ + if( CHECK_EEREC ) + { + Cpu = &recCpu; + psxCpu = &psxRec; + } + else + { + Cpu = &intCpu; + psxCpu = &psxInt; + } + + Cpu->Reset(); + psxCpu->Reset(); + + vuMicroCpuReset(); + + // make sure the VU1 doesn't have lingering "skip" enabled. + vu1MicroDisableSkip(); +} + +u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller) +{ + u8 *Mem = (u8*)SysMmap( base, size ); + + if( (Mem == NULL) || (bounds != 0 && (((uptr)Mem + size) > bounds)) ) + { + DevCon::Notice( "First try failed allocating %s at address 0x%x", params caller, base ); + + // memory allocation *must* have the top bit clear, so let's try again + // with NULL (let the OS pick something for us). + + SafeSysMunmap( Mem, size ); + + Mem = (u8*)SysMmap( NULL, size ); + if( bounds != 0 && (((uptr)Mem + size) > bounds) ) + { + DevCon::Error( "Fatal Error:\n\tSecond try failed allocating %s, block ptr 0x%x does not meet required criteria.", params caller, Mem ); + SafeSysMunmap( Mem, size ); + + // returns NULL, caller should throw an exception. + } + } + return Mem; +} + diff --git a/pcsx2/System.h b/pcsx2/System.h index b8b97a880a..bcfe0073ba 100644 --- a/pcsx2/System.h +++ b/pcsx2/System.h @@ -1,213 +1,213 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __SYSTEM_H__ -#define __SYSTEM_H__ - -#include "PS2Etypes.h" -#include "Exceptions.h" -#include "Paths.h" -#include "MemcpyFast.h" -#include "SafeArray.h" - -void SysDetect(); // Detects cpu type and fills cpuInfo structs. -bool SysInit(); // Init logfiles, directories, critical memory resources, and other OS-specific one-time -void SysReset(); // Resets the various PS2 cpus, sub-systems, and recompilers. -void SysUpdate(); // Called on VBlank (to update i.e. pads) -void SysClose(); // Close mem and plugins - -bool SysAllocateMem(); // allocates memory for all PS2 systems; returns FALSe on critical error. -void SysAllocateDynarecs(); // allocates memory for all dynarecs, and force-disables any failures. -void SysShutdownDynarecs(); -void SysShutdownMem(); -void SysResetExecutionState(); - -void *SysLoadLibrary(const char *lib); // Loads Library -void *SysLoadSym(void *lib, const char *sym); // Loads Symbol from Library -const char *SysLibError(); // Gets previous error loading symbols -void SysCloseLibrary(void *lib); // Closes Library - -// Maps a block of memory for use as a recompiled code buffer. -// The allocated block has code execution privileges. -// Returns NULL on allocation failure. -void *SysMmap(uptr base, u32 size); - -// Maps a block of memory for use as a recompiled code buffer, and ensures that the -// allocation is below a certain memory address (specified in "bounds" parameter). -// The allocated block has code execution privileges. -// Returns NULL on allocation failure. -u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller="Unnamed"); - -// Unmaps a block allocated by SysMmap -void SysMunmap(uptr base, u32 size); - -// Writes text to the console. -// *DEPRECIATED* Use Console namespace methods instead. -void SysPrintf(const char *fmt, ...); // *DEPRECIATED* - -static __forceinline void SysMunmap( void* base, u32 size ) -{ - SysMunmap( (uptr)base, size ); -} - - -#ifdef _MSC_VER -# define PCSX2_MEM_PROTECT_BEGIN() __try { -# define PCSX2_MEM_PROTECT_END() } __except(SysPageFaultExceptionFilter(GetExceptionInformation())) {} -#else -# define PCSX2_MEM_PROTECT_BEGIN() InstallLinuxExceptionHandler() -# define PCSX2_MEM_PROTECT_END() ReleaseLinuxExceptionHandler() -#endif - - -// Console Namespace -- Replacements for SysPrintf. -// SysPrintf is depreciated -- We should phase these in over time. -namespace Console -{ - enum Colors - { - Color_Black = 0, - Color_Red, - Color_Green, - Color_Yellow, - Color_Blue, - Color_Magenta, - Color_Cyan, - Color_White - }; - - // va_args version of WriteLn, mostly for internal use only. - extern void __fastcall _WriteLn( Colors color, const char* fmt, va_list args ); - - extern void Open(); - extern void Close(); - extern void SetTitle( const std::string& title ); - - // Changes the active console color. - // This color will be unset by calls to colored text methods - // such as ErrorMsg and Notice. - extern void __fastcall SetColor( Colors color ); - - // Restores the console color to default (usually low-intensity white on Win32) - extern void ClearColor(); - - // The following Write functions return bool so that we can use macros to exclude - // them from different build types. The return values are always zero. - - // Writes a newline to the console. - extern bool __fastcall Newline(); - - // Writes an unformatted string of text to the console (fast!) - // No newline is appended. - extern bool __fastcall Write( const char* fmt ); - - // Writes an unformatted string of text to the console (fast!) - // A newline is automatically appended. - extern bool __fastcall WriteLn( const char* fmt ); - - // Writes an unformatted string of text to the console (fast!) - // A newline is automatically appended, and the console color reset to default. - extern bool __fastcall WriteLn( Colors color, const char* fmt ); - - // Writes a line of colored text to the console, with automatic newline appendage. - // The console color is reset to default when the operation is complete. - extern bool WriteLn( Colors color, const char* fmt, VARG_PARAM dummy, ... ); - - // Writes a line of colored text to the console (no newline). - // The console color is reset to default when the operation is complete. - extern bool Write( Colors color, const char* fmt, VARG_PARAM dummy, ... ); - extern bool Write( Colors color, const char* fmt ); - - // Writes a formatted message to the console (no newline) - extern bool Write( const char* fmt, VARG_PARAM dummy, ... ); - - // Writes a formatted message to the console, with appended newline. - extern bool WriteLn( const char* fmt, VARG_PARAM dummy, ... ); - - // Displays a message in the console with red emphasis. - // Newline is automatically appended. - extern bool Error( const char* fmt, VARG_PARAM dummy, ... ); - extern bool Error( const char* fmt ); - - // Displays a message in the console with yellow emphasis. - // Newline is automatically appended. - extern bool Notice( const char* fmt, VARG_PARAM dummy, ... ); - extern bool Notice( const char* fmt ); - - // Displays a message in the console with yellow emphasis. - // Newline is automatically appended. - extern bool Status( const char* fmt, VARG_PARAM dummy, ... ); - extern bool Status( const char* fmt ); -} - -// Different types of message boxes that the emulator can employ from the friendly confines -// of it's blissful unawareness of whatever GUI it runs under. :) All message boxes exhibit -// blocking behavior -- they prompt the user for action and only return after the user has -// responded to the prompt. -namespace Msgbox -{ - // Pops up an alert Dialog Box with a singular "OK" button. - // Always returns false. Replacement for SysMessage. - extern bool Alert( const char* fmt, VARG_PARAM dummy, ... ); - extern bool Alert( const char* fmt ); - - // Pops up a dialog box with Ok/Cancel buttons. Returns the result of the inquiry, - // true if OK, false if cancel. - extern bool OkCancel( const char* fmt, VARG_PARAM dummy, ... ); -} - -using Console::Color_Red; -using Console::Color_Green; -using Console::Color_Blue; -using Console::Color_Magenta; -using Console::Color_Cyan; -using Console::Color_Yellow; -using Console::Color_White; - -////////////////////////////////////////////////////////////// -// Dev / Debug conditionals -- -// Consts for using if() statements instead of uglier #ifdef macros. -// Abbreviated macros for dev/debug only consoles and msgboxes. - -#ifdef PCSX2_DEVBUILD - -# define DevCon Console -# define DevMsg MsgBox - static const bool IsDevBuild = true; - -#else - -# define DevCon 0&&Console -# define DevMsg - static const bool IsDevBuild = false; - -#endif - -#ifdef _DEBUG - -# define DbgCon Console - static const bool IsDebugBuild = true; - -#else - -# define DbgCon 0&&Console - static const bool IsDebugBuild = false; - -#endif - -#endif /* __SYSTEM_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __SYSTEM_H__ +#define __SYSTEM_H__ + +#include "PS2Etypes.h" +#include "Exceptions.h" +#include "Paths.h" +#include "MemcpyFast.h" +#include "SafeArray.h" + +void SysDetect(); // Detects cpu type and fills cpuInfo structs. +bool SysInit(); // Init logfiles, directories, critical memory resources, and other OS-specific one-time +void SysReset(); // Resets the various PS2 cpus, sub-systems, and recompilers. +void SysUpdate(); // Called on VBlank (to update i.e. pads) +void SysClose(); // Close mem and plugins + +bool SysAllocateMem(); // allocates memory for all PS2 systems; returns FALSe on critical error. +void SysAllocateDynarecs(); // allocates memory for all dynarecs, and force-disables any failures. +void SysShutdownDynarecs(); +void SysShutdownMem(); +void SysResetExecutionState(); + +void *SysLoadLibrary(const char *lib); // Loads Library +void *SysLoadSym(void *lib, const char *sym); // Loads Symbol from Library +const char *SysLibError(); // Gets previous error loading symbols +void SysCloseLibrary(void *lib); // Closes Library + +// Maps a block of memory for use as a recompiled code buffer. +// The allocated block has code execution privileges. +// Returns NULL on allocation failure. +void *SysMmap(uptr base, u32 size); + +// Maps a block of memory for use as a recompiled code buffer, and ensures that the +// allocation is below a certain memory address (specified in "bounds" parameter). +// The allocated block has code execution privileges. +// Returns NULL on allocation failure. +u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller="Unnamed"); + +// Unmaps a block allocated by SysMmap +void SysMunmap(uptr base, u32 size); + +// Writes text to the console. +// *DEPRECIATED* Use Console namespace methods instead. +void SysPrintf(const char *fmt, ...); // *DEPRECIATED* + +static __forceinline void SysMunmap( void* base, u32 size ) +{ + SysMunmap( (uptr)base, size ); +} + + +#ifdef _MSC_VER +# define PCSX2_MEM_PROTECT_BEGIN() __try { +# define PCSX2_MEM_PROTECT_END() } __except(SysPageFaultExceptionFilter(GetExceptionInformation())) {} +#else +# define PCSX2_MEM_PROTECT_BEGIN() InstallLinuxExceptionHandler() +# define PCSX2_MEM_PROTECT_END() ReleaseLinuxExceptionHandler() +#endif + + +// Console Namespace -- Replacements for SysPrintf. +// SysPrintf is depreciated -- We should phase these in over time. +namespace Console +{ + enum Colors + { + Color_Black = 0, + Color_Red, + Color_Green, + Color_Yellow, + Color_Blue, + Color_Magenta, + Color_Cyan, + Color_White + }; + + // va_args version of WriteLn, mostly for internal use only. + extern void __fastcall _WriteLn( Colors color, const char* fmt, va_list args ); + + extern void Open(); + extern void Close(); + extern void SetTitle( const std::string& title ); + + // Changes the active console color. + // This color will be unset by calls to colored text methods + // such as ErrorMsg and Notice. + extern void __fastcall SetColor( Colors color ); + + // Restores the console color to default (usually low-intensity white on Win32) + extern void ClearColor(); + + // The following Write functions return bool so that we can use macros to exclude + // them from different build types. The return values are always zero. + + // Writes a newline to the console. + extern bool __fastcall Newline(); + + // Writes an unformatted string of text to the console (fast!) + // No newline is appended. + extern bool __fastcall Write( const char* fmt ); + + // Writes an unformatted string of text to the console (fast!) + // A newline is automatically appended. + extern bool __fastcall WriteLn( const char* fmt ); + + // Writes an unformatted string of text to the console (fast!) + // A newline is automatically appended, and the console color reset to default. + extern bool __fastcall WriteLn( Colors color, const char* fmt ); + + // Writes a line of colored text to the console, with automatic newline appendage. + // The console color is reset to default when the operation is complete. + extern bool WriteLn( Colors color, const char* fmt, VARG_PARAM dummy, ... ); + + // Writes a line of colored text to the console (no newline). + // The console color is reset to default when the operation is complete. + extern bool Write( Colors color, const char* fmt, VARG_PARAM dummy, ... ); + extern bool Write( Colors color, const char* fmt ); + + // Writes a formatted message to the console (no newline) + extern bool Write( const char* fmt, VARG_PARAM dummy, ... ); + + // Writes a formatted message to the console, with appended newline. + extern bool WriteLn( const char* fmt, VARG_PARAM dummy, ... ); + + // Displays a message in the console with red emphasis. + // Newline is automatically appended. + extern bool Error( const char* fmt, VARG_PARAM dummy, ... ); + extern bool Error( const char* fmt ); + + // Displays a message in the console with yellow emphasis. + // Newline is automatically appended. + extern bool Notice( const char* fmt, VARG_PARAM dummy, ... ); + extern bool Notice( const char* fmt ); + + // Displays a message in the console with yellow emphasis. + // Newline is automatically appended. + extern bool Status( const char* fmt, VARG_PARAM dummy, ... ); + extern bool Status( const char* fmt ); +} + +// Different types of message boxes that the emulator can employ from the friendly confines +// of it's blissful unawareness of whatever GUI it runs under. :) All message boxes exhibit +// blocking behavior -- they prompt the user for action and only return after the user has +// responded to the prompt. +namespace Msgbox +{ + // Pops up an alert Dialog Box with a singular "OK" button. + // Always returns false. Replacement for SysMessage. + extern bool Alert( const char* fmt, VARG_PARAM dummy, ... ); + extern bool Alert( const char* fmt ); + + // Pops up a dialog box with Ok/Cancel buttons. Returns the result of the inquiry, + // true if OK, false if cancel. + extern bool OkCancel( const char* fmt, VARG_PARAM dummy, ... ); +} + +using Console::Color_Red; +using Console::Color_Green; +using Console::Color_Blue; +using Console::Color_Magenta; +using Console::Color_Cyan; +using Console::Color_Yellow; +using Console::Color_White; + +////////////////////////////////////////////////////////////// +// Dev / Debug conditionals -- +// Consts for using if() statements instead of uglier #ifdef macros. +// Abbreviated macros for dev/debug only consoles and msgboxes. + +#ifdef PCSX2_DEVBUILD + +# define DevCon Console +# define DevMsg MsgBox + static const bool IsDevBuild = true; + +#else + +# define DevCon 0&&Console +# define DevMsg + static const bool IsDevBuild = false; + +#endif + +#ifdef _DEBUG + +# define DbgCon Console + static const bool IsDebugBuild = true; + +#else + +# define DbgCon 0&&Console + static const bool IsDebugBuild = false; + +#endif + +#endif /* __SYSTEM_H__ */ diff --git a/pcsx2/ThreadTools.cpp b/pcsx2/ThreadTools.cpp index 528be69284..0dfeefee89 100644 --- a/pcsx2/ThreadTools.cpp +++ b/pcsx2/ThreadTools.cpp @@ -1,192 +1,192 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" -#include "Threading.h" - -using namespace Threading; - -namespace Threading -{ - Thread::Thread() : - m_thread() - , m_returncode( 0 ) - , m_terminated( false ) - , m_post_event() - { - if( pthread_create( &m_thread, NULL, _internal_callback, this ) != 0 ) - throw Exception::ThreadCreationError(); - } - - Thread::~Thread() - { - Close(); - } - - void Thread::Close() - { - pthread_cancel( m_thread ); - pthread_join( m_thread, NULL ); - } - - int Thread::GetReturnCode() const - { - if( !m_terminated ) - throw std::logic_error( "Thread is still running. No return code is available." ); - - return m_returncode; - } - - WaitEvent::WaitEvent() - { - int err = 0; - - err = pthread_cond_init(&cond, NULL); - err = pthread_mutex_init(&mutex, NULL); - } - - WaitEvent::~WaitEvent() - { - pthread_cond_destroy( &cond ); - pthread_mutex_destroy( &mutex ); - } - - void WaitEvent::Set() - { - pthread_mutex_lock( &mutex ); - pthread_cond_signal( &cond ); - pthread_mutex_unlock( &mutex ); - } - - void WaitEvent::Wait() - { - pthread_mutex_lock( &mutex ); - pthread_cond_wait( &cond, &mutex ); - pthread_mutex_unlock( &mutex ); - } - - Semaphore::Semaphore() - { - sem_init( &sema, false, 0 ); - } - - Semaphore::~Semaphore() - { - sem_destroy( &sema ); - } - - void Semaphore::Post() - { - sem_post( &sema ); - } - - void Semaphore::Post( int multiple ) - { -#if defined(_MSC_VER) - sem_post_multiple( &sema, multiple ); -#endif - } - - void Semaphore::Wait() - { - sem_wait( &sema ); - } - - int Semaphore::Count() - { - int retval; - sem_getvalue( &sema, &retval ); - return retval; - } - - MutexLock::MutexLock() - { - int err = 0; - err = pthread_mutex_init( &mutex, NULL ); - } - - MutexLock::~MutexLock() - { - pthread_mutex_destroy( &mutex ); - } - - void MutexLock::Lock() - { - pthread_mutex_lock( &mutex ); - } - - void MutexLock::Unlock() - { - pthread_mutex_unlock( &mutex ); - } - - ////////////////////////////////////////////////////////////////////// - // define some overloads for InterlockedExchanges - // for commonly used types, like u32 and s32. - - __forceinline void AtomicExchange( volatile u32& Target, u32 value ) - { - pcsx2_InterlockedExchange( (volatile long*)&Target, value ); - } - - __forceinline void AtomicExchangeAdd( volatile u32& Target, u32 value ) - { - pcsx2_InterlockedExchangeAdd( (volatile long*)&Target, value ); - } - - __forceinline void AtomicIncrement( volatile u32& Target ) - { - pcsx2_InterlockedExchangeAdd( (volatile long*)&Target, 1 ); - } - - __forceinline void AtomicDecrement( volatile u32& Target ) - { - pcsx2_InterlockedExchangeAdd( (volatile long*)&Target, -1 ); - } - - __forceinline void AtomicExchange( volatile s32& Target, s32 value ) - { - pcsx2_InterlockedExchange( (volatile long*)&Target, value ); - } - - __forceinline void AtomicExchangeAdd( s32& Target, u32 value ) - { - pcsx2_InterlockedExchangeAdd( (volatile long*)&Target, value ); - } - - __forceinline void AtomicIncrement( volatile s32& Target ) - { - pcsx2_InterlockedExchangeAdd( (volatile long*)&Target, 1 ); - } - - __forceinline void AtomicDecrement( volatile s32& Target ) - { - pcsx2_InterlockedExchangeAdd( (volatile long*)&Target, -1 ); - } - - __forceinline void _AtomicExchangePointer( const void ** target, const void* value ) - { - pcsx2_InterlockedExchange( (volatile long*)target, (long)value ); - } - - __forceinline void _AtomicCompareExchangePointer( const void ** target, const void* value, const void* comparand ) - { - pcsx2_InterlockedCompareExchange( (volatile long*)target, (long)value, (long)comparand ); - } - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" +#include "Threading.h" + +using namespace Threading; + +namespace Threading +{ + Thread::Thread() : + m_thread() + , m_returncode( 0 ) + , m_terminated( false ) + , m_post_event() + { + if( pthread_create( &m_thread, NULL, _internal_callback, this ) != 0 ) + throw Exception::ThreadCreationError(); + } + + Thread::~Thread() + { + Close(); + } + + void Thread::Close() + { + pthread_cancel( m_thread ); + pthread_join( m_thread, NULL ); + } + + int Thread::GetReturnCode() const + { + if( !m_terminated ) + throw std::logic_error( "Thread is still running. No return code is available." ); + + return m_returncode; + } + + WaitEvent::WaitEvent() + { + int err = 0; + + err = pthread_cond_init(&cond, NULL); + err = pthread_mutex_init(&mutex, NULL); + } + + WaitEvent::~WaitEvent() + { + pthread_cond_destroy( &cond ); + pthread_mutex_destroy( &mutex ); + } + + void WaitEvent::Set() + { + pthread_mutex_lock( &mutex ); + pthread_cond_signal( &cond ); + pthread_mutex_unlock( &mutex ); + } + + void WaitEvent::Wait() + { + pthread_mutex_lock( &mutex ); + pthread_cond_wait( &cond, &mutex ); + pthread_mutex_unlock( &mutex ); + } + + Semaphore::Semaphore() + { + sem_init( &sema, false, 0 ); + } + + Semaphore::~Semaphore() + { + sem_destroy( &sema ); + } + + void Semaphore::Post() + { + sem_post( &sema ); + } + + void Semaphore::Post( int multiple ) + { +#if defined(_MSC_VER) + sem_post_multiple( &sema, multiple ); +#endif + } + + void Semaphore::Wait() + { + sem_wait( &sema ); + } + + int Semaphore::Count() + { + int retval; + sem_getvalue( &sema, &retval ); + return retval; + } + + MutexLock::MutexLock() + { + int err = 0; + err = pthread_mutex_init( &mutex, NULL ); + } + + MutexLock::~MutexLock() + { + pthread_mutex_destroy( &mutex ); + } + + void MutexLock::Lock() + { + pthread_mutex_lock( &mutex ); + } + + void MutexLock::Unlock() + { + pthread_mutex_unlock( &mutex ); + } + + ////////////////////////////////////////////////////////////////////// + // define some overloads for InterlockedExchanges + // for commonly used types, like u32 and s32. + + __forceinline void AtomicExchange( volatile u32& Target, u32 value ) + { + pcsx2_InterlockedExchange( (volatile long*)&Target, value ); + } + + __forceinline void AtomicExchangeAdd( volatile u32& Target, u32 value ) + { + pcsx2_InterlockedExchangeAdd( (volatile long*)&Target, value ); + } + + __forceinline void AtomicIncrement( volatile u32& Target ) + { + pcsx2_InterlockedExchangeAdd( (volatile long*)&Target, 1 ); + } + + __forceinline void AtomicDecrement( volatile u32& Target ) + { + pcsx2_InterlockedExchangeAdd( (volatile long*)&Target, -1 ); + } + + __forceinline void AtomicExchange( volatile s32& Target, s32 value ) + { + pcsx2_InterlockedExchange( (volatile long*)&Target, value ); + } + + __forceinline void AtomicExchangeAdd( s32& Target, u32 value ) + { + pcsx2_InterlockedExchangeAdd( (volatile long*)&Target, value ); + } + + __forceinline void AtomicIncrement( volatile s32& Target ) + { + pcsx2_InterlockedExchangeAdd( (volatile long*)&Target, 1 ); + } + + __forceinline void AtomicDecrement( volatile s32& Target ) + { + pcsx2_InterlockedExchangeAdd( (volatile long*)&Target, -1 ); + } + + __forceinline void _AtomicExchangePointer( const void ** target, const void* value ) + { + pcsx2_InterlockedExchange( (volatile long*)target, (long)value ); + } + + __forceinline void _AtomicCompareExchangePointer( const void ** target, const void* value, const void* comparand ) + { + pcsx2_InterlockedCompareExchange( (volatile long*)target, (long)value, (long)comparand ); + } + } \ No newline at end of file diff --git a/pcsx2/Threading.h b/pcsx2/Threading.h index 5fbd5e95db..2f3b9e3cb3 100644 --- a/pcsx2/Threading.h +++ b/pcsx2/Threading.h @@ -1,135 +1,135 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef _THREADING_H_ -#define _THREADING_H_ - -#include // EBUSY -#include - -#include "PS2Etypes.h" -#include "Exceptions.h" - -namespace Threading -{ - /////////////////////////////////////////////////////////////// - // Define some useful object handles - wait events, mutexes. - - struct WaitEvent - { - pthread_cond_t cond; - pthread_mutex_t mutex; - - WaitEvent(); - ~WaitEvent(); - - void Set(); - void Wait(); - }; - - struct Semaphore - { - sem_t sema; - - Semaphore(); - ~Semaphore(); - - void Post(); - void Post( int multiple ); - void Wait(); - int Count(); - }; - - struct MutexLock - { - pthread_mutex_t mutex; - - MutexLock(); - ~MutexLock(); - - void Lock(); - void Unlock(); - }; - - // Returns the number of available logical CPUs (cores plus - // hyperthreaded cpus) - extern void CountLogicalCores( int LogicalCoresPerPhysicalCPU, int PhysicalCoresPerPhysicalCPU ); - - // Releases a timeslice to other threads. - extern void Timeslice(); - - // For use in spin/wait loops. - extern void SpinWait(); - - class Thread : NoncopyableObject - { - protected: - typedef int (*PlainJoeFP)(); - pthread_t m_thread; - int m_returncode; // value returned from the thread on close. - bool m_terminated; // set true after the thread has been closed. - Semaphore m_post_event; // general wait event that's needed by most threads. - - public: - virtual ~Thread(); - Thread(); - - virtual void Close(); - - // Gets the return code of the thread. - // Throws std::logic_error if the thread has not terminated. - int GetReturnCode() const; - - protected: - // Used to dispatch the thread callback function. - // (handles some thread cleanup on Win32, and is basically a typecast - // on linux). - static void* _internal_callback( void* func ); - - // Implemented by derrived class to handle threading actions! - virtual int Callback()=0; - }; - - // Our fundamental interlocking functions. All other useful interlocks can - // be derrived from these little beasties! - - extern long pcsx2_InterlockedExchange(volatile long* Target, long srcval); - extern long pcsx2_InterlockedCompareExchange( volatile long* target, long srcval, long comp ); - extern long pcsx2_InterlockedExchangeAdd( volatile long* target, long addval ); - - extern void AtomicExchange( volatile u32& Target, u32 value ); - extern void AtomicExchangeAdd( volatile u32& Target, u32 value ); - extern void AtomicIncrement( volatile u32& Target ); - extern void AtomicDecrement( volatile u32& Target ); - extern void AtomicExchange( volatile s32& Target, s32 value ); - extern void AtomicExchangeAdd( volatile s32& Target, u32 value ); - extern void AtomicIncrement( volatile s32& Target ); - extern void AtomicDecrement( volatile s32& Target ); - - extern void _AtomicExchangePointer( const void ** target, const void* value ); - extern void _AtomicCompareExchangePointer( const void ** target, const void* value, const void* comparand ); - - #define AtomicExchangePointer( target, value ) \ - _AtomicExchangePointer( (const void**)(&target), (const void*)(value) ) - - #define AtomicCompareExchangePointer( target, value, comparand ) \ - _AtomicCompareExchangePointer( (const void**)(&target), (const void*)(value), (const void*)(comparand) ) - -} - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef _THREADING_H_ +#define _THREADING_H_ + +#include // EBUSY +#include + +#include "PS2Etypes.h" +#include "Exceptions.h" + +namespace Threading +{ + /////////////////////////////////////////////////////////////// + // Define some useful object handles - wait events, mutexes. + + struct WaitEvent + { + pthread_cond_t cond; + pthread_mutex_t mutex; + + WaitEvent(); + ~WaitEvent(); + + void Set(); + void Wait(); + }; + + struct Semaphore + { + sem_t sema; + + Semaphore(); + ~Semaphore(); + + void Post(); + void Post( int multiple ); + void Wait(); + int Count(); + }; + + struct MutexLock + { + pthread_mutex_t mutex; + + MutexLock(); + ~MutexLock(); + + void Lock(); + void Unlock(); + }; + + // Returns the number of available logical CPUs (cores plus + // hyperthreaded cpus) + extern void CountLogicalCores( int LogicalCoresPerPhysicalCPU, int PhysicalCoresPerPhysicalCPU ); + + // Releases a timeslice to other threads. + extern void Timeslice(); + + // For use in spin/wait loops. + extern void SpinWait(); + + class Thread : NoncopyableObject + { + protected: + typedef int (*PlainJoeFP)(); + pthread_t m_thread; + int m_returncode; // value returned from the thread on close. + bool m_terminated; // set true after the thread has been closed. + Semaphore m_post_event; // general wait event that's needed by most threads. + + public: + virtual ~Thread(); + Thread(); + + virtual void Close(); + + // Gets the return code of the thread. + // Throws std::logic_error if the thread has not terminated. + int GetReturnCode() const; + + protected: + // Used to dispatch the thread callback function. + // (handles some thread cleanup on Win32, and is basically a typecast + // on linux). + static void* _internal_callback( void* func ); + + // Implemented by derrived class to handle threading actions! + virtual int Callback()=0; + }; + + // Our fundamental interlocking functions. All other useful interlocks can + // be derrived from these little beasties! + + extern long pcsx2_InterlockedExchange(volatile long* Target, long srcval); + extern long pcsx2_InterlockedCompareExchange( volatile long* target, long srcval, long comp ); + extern long pcsx2_InterlockedExchangeAdd( volatile long* target, long addval ); + + extern void AtomicExchange( volatile u32& Target, u32 value ); + extern void AtomicExchangeAdd( volatile u32& Target, u32 value ); + extern void AtomicIncrement( volatile u32& Target ); + extern void AtomicDecrement( volatile u32& Target ); + extern void AtomicExchange( volatile s32& Target, s32 value ); + extern void AtomicExchangeAdd( volatile s32& Target, u32 value ); + extern void AtomicIncrement( volatile s32& Target ); + extern void AtomicDecrement( volatile s32& Target ); + + extern void _AtomicExchangePointer( const void ** target, const void* value ); + extern void _AtomicCompareExchangePointer( const void ** target, const void* value, const void* comparand ); + + #define AtomicExchangePointer( target, value ) \ + _AtomicExchangePointer( (const void**)(&target), (const void*)(value) ) + + #define AtomicCompareExchangePointer( target, value, comparand ) \ + _AtomicCompareExchangePointer( (const void**)(&target), (const void*)(value), (const void*)(comparand) ) + +} + +#endif diff --git a/pcsx2/VU.h b/pcsx2/VU.h index d68e8ffcb1..278f79f121 100644 --- a/pcsx2/VU.h +++ b/pcsx2/VU.h @@ -1,201 +1,201 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __VU_H__ -#define __VU_H__ - -#include "Vif.h" - -#define REG_STATUS_FLAG 16 -#define REG_MAC_FLAG 17 -#define REG_CLIP_FLAG 18 -#define REG_ACC_FLAG 19 // dummy flag that indicates that VFACC is written/read (nothing to do with VI[19]) -#define REG_R 20 -#define REG_I 21 -#define REG_Q 22 -#define REG_P 23 // only exists in micromode -#define REG_VF0_FLAG 24 // dummy flag that indicates VF0 is read (nothing to do with VI[24]) -#define REG_TPC 26 -#define REG_CMSAR0 27 -#define REG_FBRST 28 -#define REG_VPU_STAT 29 -#define REG_CMSAR1 31 - -//interpreter hacks, WIP -//#define INT_VUSTALLHACK //some games work without those, big speedup -//#define INT_VUDOUBLEHACK - -enum VUStatus { - VU_Ready = 0, - VU_Run = 1, - VU_Stop = 2, -}; - -union VECTOR { - struct { - float x,y,z,w; - } f; - struct { - u32 x,y,z,w; - } i; - - float F[4]; - - u64 UD[2]; //128 bits - s64 SD[2]; - u32 UL[4]; - s32 SL[4]; - u16 US[8]; - s16 SS[8]; - u8 UC[16]; - s8 SC[16]; -}; - -struct REG_VI { - union { - float F; - s32 SL; - u32 UL; - s16 SS[2]; - u16 US[2]; - s8 SC[4]; - u8 UC[4]; - }; - u32 padding[3]; // needs padding to make them 128bit; VU0 maps VU1's VI regs as 128bits to addr 0x4xx0 in - // VU0 mem, with only lower 16 bits valid, and the upper 112bits are hardwired to 0 (cottonvibes) -}; - -#define VUFLAG_BREAKONMFLAG 0x00000001 -#define VUFLAG_MFLAGSET 0x00000002 - -struct fdivPipe { - int enable; - REG_VI reg; - u32 sCycle; - u32 Cycle; - u32 statusflag; -}; - -struct efuPipe { - int enable; - REG_VI reg; - u32 sCycle; - u32 Cycle; -}; - -struct fmacPipe { - int enable; - int reg; - int xyzw; - u32 sCycle; - u32 Cycle; - u32 macflag; - u32 statusflag; - u32 clipflag; -}; - -struct VURegs { - VECTOR VF[32]; // VF and VI need to be first in this struct for proper mapping - REG_VI VI[32]; // needs to be 128bit x 32 (cottonvibes) - VECTOR ACC; - REG_VI q; - REG_VI p; - - u32 macflag; - u32 statusflag; - u32 clipflag; - - u32 cycle; - u32 flags; - - void (*vuExec)(VURegs*); - VIFregisters *vifRegs; - - u8 *Mem; - u8 *Micro; - - u32 code; - u32 maxmem; - u32 maxmicro; - - u16 branch; - u16 ebit; - u32 branchpc; - - fmacPipe fmac[8]; - fdivPipe fdiv; - efuPipe efu; - - VURegs() : - Mem( NULL ) - , Micro( NULL ) - { - } -}; - -#define VUPIPE_NONE 0 -#define VUPIPE_FMAC 1 -#define VUPIPE_FDIV 2 -#define VUPIPE_EFU 3 -#define VUPIPE_IALU 4 -#define VUPIPE_BRANCH 5 -#define VUPIPE_XGKICK 6 - -#define VUREG_READ 0x1 -#define VUREG_WRITE 0x2 - -struct _VURegsNum { - u8 pipe; // if 0xff, COP2 - u8 VFwrite; - u8 VFwxyzw; - u8 VFr0xyzw; - u8 VFr1xyzw; - u8 VFread0; - u8 VFread1; - u32 VIwrite; - u32 VIread; - int cycles; -}; - -extern VURegs* g_pVU1; -extern PCSX2_ALIGNED16_DECL(VURegs VU0); - -#define VU1 (*g_pVU1) - - -#ifdef _WIN32 -extern __forceinline u32* GET_VU_MEM(VURegs* VU, u32 addr) -#else -static __forceinline u32* GET_VU_MEM(VURegs* VU, u32 addr) -#endif -{ - if( VU == g_pVU1 ) return (u32*)(VU1.Mem+(addr&0x3fff)); - - if( addr >= 0x4000 ) return (u32*)(VU0.Mem+(addr&0x43f0)); // get VF and VI regs (they're mapped to 0x4xx0 in VU0 mem!) - - return (u32*)(VU0.Mem+(addr&0x0fff)); // for addr 0x0000 to 0x4000 just wrap around -} - - -// various fixes to enable per game (all are off by default) -#define VUFIX_SIGNEDZERO 1 -#define VUFIX_EXTRAFLAGS 2 -#define VUFIX_XGKICKDELAY2 4 -extern int g_VUGameFixes; - -#endif /* __VU_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __VU_H__ +#define __VU_H__ + +#include "Vif.h" + +#define REG_STATUS_FLAG 16 +#define REG_MAC_FLAG 17 +#define REG_CLIP_FLAG 18 +#define REG_ACC_FLAG 19 // dummy flag that indicates that VFACC is written/read (nothing to do with VI[19]) +#define REG_R 20 +#define REG_I 21 +#define REG_Q 22 +#define REG_P 23 // only exists in micromode +#define REG_VF0_FLAG 24 // dummy flag that indicates VF0 is read (nothing to do with VI[24]) +#define REG_TPC 26 +#define REG_CMSAR0 27 +#define REG_FBRST 28 +#define REG_VPU_STAT 29 +#define REG_CMSAR1 31 + +//interpreter hacks, WIP +//#define INT_VUSTALLHACK //some games work without those, big speedup +//#define INT_VUDOUBLEHACK + +enum VUStatus { + VU_Ready = 0, + VU_Run = 1, + VU_Stop = 2, +}; + +union VECTOR { + struct { + float x,y,z,w; + } f; + struct { + u32 x,y,z,w; + } i; + + float F[4]; + + u64 UD[2]; //128 bits + s64 SD[2]; + u32 UL[4]; + s32 SL[4]; + u16 US[8]; + s16 SS[8]; + u8 UC[16]; + s8 SC[16]; +}; + +struct REG_VI { + union { + float F; + s32 SL; + u32 UL; + s16 SS[2]; + u16 US[2]; + s8 SC[4]; + u8 UC[4]; + }; + u32 padding[3]; // needs padding to make them 128bit; VU0 maps VU1's VI regs as 128bits to addr 0x4xx0 in + // VU0 mem, with only lower 16 bits valid, and the upper 112bits are hardwired to 0 (cottonvibes) +}; + +#define VUFLAG_BREAKONMFLAG 0x00000001 +#define VUFLAG_MFLAGSET 0x00000002 + +struct fdivPipe { + int enable; + REG_VI reg; + u32 sCycle; + u32 Cycle; + u32 statusflag; +}; + +struct efuPipe { + int enable; + REG_VI reg; + u32 sCycle; + u32 Cycle; +}; + +struct fmacPipe { + int enable; + int reg; + int xyzw; + u32 sCycle; + u32 Cycle; + u32 macflag; + u32 statusflag; + u32 clipflag; +}; + +struct VURegs { + VECTOR VF[32]; // VF and VI need to be first in this struct for proper mapping + REG_VI VI[32]; // needs to be 128bit x 32 (cottonvibes) + VECTOR ACC; + REG_VI q; + REG_VI p; + + u32 macflag; + u32 statusflag; + u32 clipflag; + + u32 cycle; + u32 flags; + + void (*vuExec)(VURegs*); + VIFregisters *vifRegs; + + u8 *Mem; + u8 *Micro; + + u32 code; + u32 maxmem; + u32 maxmicro; + + u16 branch; + u16 ebit; + u32 branchpc; + + fmacPipe fmac[8]; + fdivPipe fdiv; + efuPipe efu; + + VURegs() : + Mem( NULL ) + , Micro( NULL ) + { + } +}; + +#define VUPIPE_NONE 0 +#define VUPIPE_FMAC 1 +#define VUPIPE_FDIV 2 +#define VUPIPE_EFU 3 +#define VUPIPE_IALU 4 +#define VUPIPE_BRANCH 5 +#define VUPIPE_XGKICK 6 + +#define VUREG_READ 0x1 +#define VUREG_WRITE 0x2 + +struct _VURegsNum { + u8 pipe; // if 0xff, COP2 + u8 VFwrite; + u8 VFwxyzw; + u8 VFr0xyzw; + u8 VFr1xyzw; + u8 VFread0; + u8 VFread1; + u32 VIwrite; + u32 VIread; + int cycles; +}; + +extern VURegs* g_pVU1; +extern PCSX2_ALIGNED16_DECL(VURegs VU0); + +#define VU1 (*g_pVU1) + + +#ifdef _WIN32 +extern __forceinline u32* GET_VU_MEM(VURegs* VU, u32 addr) +#else +static __forceinline u32* GET_VU_MEM(VURegs* VU, u32 addr) +#endif +{ + if( VU == g_pVU1 ) return (u32*)(VU1.Mem+(addr&0x3fff)); + + if( addr >= 0x4000 ) return (u32*)(VU0.Mem+(addr&0x43f0)); // get VF and VI regs (they're mapped to 0x4xx0 in VU0 mem!) + + return (u32*)(VU0.Mem+(addr&0x0fff)); // for addr 0x0000 to 0x4000 just wrap around +} + + +// various fixes to enable per game (all are off by default) +#define VUFIX_SIGNEDZERO 1 +#define VUFIX_EXTRAFLAGS 2 +#define VUFIX_XGKICKDELAY2 4 +extern int g_VUGameFixes; + +#endif /* __VU_H__ */ diff --git a/pcsx2/VU0.cpp b/pcsx2/VU0.cpp index fdb41cf4fa..6a3ad14df1 100644 --- a/pcsx2/VU0.cpp +++ b/pcsx2/VU0.cpp @@ -1,364 +1,364 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -/* TODO - -Fix the flags Proper as they aren't handle now.. - -Add BC Table opcodes - -Add Interlock in QMFC2,QMTC2,CFC2,CTC2 - -Finish instruction set - -Bug Fixes!!! -*/ - -#include "PrecompiledHeader.h" - -#include - -#include "Common.h" -#include "DebugTools/Debug.h" -#include "R5900.h" -#include "R5900OpcodeTables.h" -#include "VUops.h" -#include "VUmicro.h" - -#define _Ft_ _Rt_ -#define _Fs_ _Rd_ -#define _Fd_ _Sa_ - -#define _X (cpuRegs.code>>24) & 0x1 -#define _Y (cpuRegs.code>>23) & 0x1 -#define _Z (cpuRegs.code>>22) & 0x1 -#define _W (cpuRegs.code>>21) & 0x1 - -#define _Fsf_ ((cpuRegs.code >> 21) & 0x03) -#define _Ftf_ ((cpuRegs.code >> 23) & 0x03) - -#include "VUflags.h" - -using namespace R5900; - -PCSX2_ALIGNED16(VURegs VU0); - -void COP2_BC2() { Int_COP2BC2PrintTable[_Rt_]();} -void COP2_SPECIAL() { Int_COP2SPECIAL1PrintTable[_Funct_]();} - -void COP2_SPECIAL2() { - Int_COP2SPECIAL2PrintTable[(cpuRegs.code & 0x3) | ((cpuRegs.code >> 4) & 0x7c)](); -} - -void COP2_Unknown() -{ - CPU_LOG("Unknown COP2 opcode called\n"); -} - -//**************************************************************************** -void _vu0WaitMicro() { - int startcycle; - - if ((VU0.VI[REG_VPU_STAT].UL & 0x1) == 0) { - return; - } - - startcycle = VU0.cycle; - - VU0.flags|= VUFLAG_BREAKONMFLAG; - VU0.flags&= ~VUFLAG_MFLAGSET; - - do { - CpuVU0.ExecuteBlock(); - // knockout kings 2002 loops here - if( VU0.cycle-startcycle > 0x1000 ) { - Console::Notice("VU0 perma-stall, breaking execution..."); // (email zero if gfx are bad) - break; - } - } while ((VU0.VI[REG_VPU_STAT].UL & 0x1) && (VU0.flags & VUFLAG_MFLAGSET) == 0); - - //NEW - cpuRegs.cycle += (VU0.cycle-startcycle)*2; - VU0.flags&= ~VUFLAG_BREAKONMFLAG; -} - -namespace R5900 { -namespace Interpreter{ -namespace OpcodeImpl -{ - void LQC2() { - u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + (s16)cpuRegs.code; - if (_Ft_) { - memRead128(addr, &VU0.VF[_Ft_].UD[0]); - } else { - u64 val[2]; - memRead128(addr, val); - } - } - - // Asadr.Changed - //TODO: check this - // HUH why ? doesn;t make any sense ... - void SQC2() { - u32 addr = _Imm_ + cpuRegs.GPR.r[_Rs_].UL[0]; - //memWrite64(addr, VU0.VF[_Ft_].UD[0]); - //memWrite64(addr+8,VU0.VF[_Ft_].UD[1]); - memWrite128(addr, &VU0.VF[_Ft_].UD[0]); - } -}}} - - -void QMFC2() { - if (cpuRegs.code & 1) { - _vu0WaitMicro(); - } - if (_Rt_ == 0) return; - cpuRegs.GPR.r[_Rt_].UD[0] = VU0.VF[_Fs_].UD[0]; - cpuRegs.GPR.r[_Rt_].UD[1] = VU0.VF[_Fs_].UD[1]; -} - -void QMTC2() { - if (cpuRegs.code & 1) { - _vu0WaitMicro(); - } - if (_Fs_ == 0) return; - VU0.VF[_Fs_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0]; - VU0.VF[_Fs_].UD[1] = cpuRegs.GPR.r[_Rt_].UD[1]; -} - -void CFC2() { - if (cpuRegs.code & 1) { - _vu0WaitMicro(); - } - if (_Rt_ == 0) return; - cpuRegs.GPR.r[_Rt_].UL[0] = VU0.VI[_Fs_].UL; - if(VU0.VI[_Fs_].UL & 0x80000000) - cpuRegs.GPR.r[_Rt_].UL[1] = 0xffffffff; - else - cpuRegs.GPR.r[_Rt_].UL[1] = 0; -} - -void CTC2() { - if (cpuRegs.code & 1) { - _vu0WaitMicro(); - } - if (_Fs_ == 0) return; - - switch(_Fs_) { - case REG_MAC_FLAG: // read-only - case REG_TPC: // read-only - case REG_VPU_STAT: // read-only - break; - case REG_FBRST: - VU0.VI[REG_FBRST].UL = cpuRegs.GPR.r[_Rt_].UL[0] & 0x0C0C; - if (cpuRegs.GPR.r[_Rt_].UL[0] & 0x1) { // VU0 Force Break - Console::Error("fixme: VU0 Force Break"); - } - if (cpuRegs.GPR.r[_Rt_].UL[0] & 0x2) { // VU0 Reset - //SysPrintf("fixme: VU0 Reset\n"); - vu0ResetRegs(); - } - if (cpuRegs.GPR.r[_Rt_].UL[0] & 0x100) { // VU1 Force Break - Console::Error("fixme: VU1 Force Break"); - } - if (cpuRegs.GPR.r[_Rt_].UL[0] & 0x200) { // VU1 Reset -// SysPrintf("fixme: VU1 Reset\n"); - vu1ResetRegs(); - } - break; - case REG_CMSAR1: // REG_CMSAR1 - if (!(VU0.VI[REG_VPU_STAT].UL & 0x100) ) { - VU1.VI[REG_TPC].UL = cpuRegs.GPR.r[_Rt_].US[0]; - vu1ExecMicro(VU1.VI[REG_TPC].UL); // Execute VU1 Micro SubRoutine - } - break; - default: - VU0.VI[_Fs_].UL = cpuRegs.GPR.r[_Rt_].UL[0]; - break; - } -} - -//--------------------------------------------------------------------------------------- - - -__forceinline void SYNCMSFLAGS() -{ - VU0.VI[REG_STATUS_FLAG].UL = VU0.statusflag; - VU0.VI[REG_MAC_FLAG].UL = VU0.macflag; -} - -__forceinline void SYNCFDIV() -{ - VU0.VI[REG_Q].UL = VU0.q.UL; - VU0.VI[REG_STATUS_FLAG].UL = VU0.statusflag; -} - -void VABS() { VU0.code = cpuRegs.code; _vuABS(&VU0); } -void VADD() { VU0.code = cpuRegs.code; _vuADD(&VU0); SYNCMSFLAGS(); } -void VADDi() { VU0.code = cpuRegs.code; _vuADDi(&VU0); SYNCMSFLAGS(); } -void VADDq() { VU0.code = cpuRegs.code; _vuADDq(&VU0); SYNCMSFLAGS(); } -void VADDx() { VU0.code = cpuRegs.code; _vuADDx(&VU0); SYNCMSFLAGS(); } -void VADDy() { VU0.code = cpuRegs.code; _vuADDy(&VU0); SYNCMSFLAGS(); } -void VADDz() { VU0.code = cpuRegs.code; _vuADDz(&VU0); SYNCMSFLAGS(); } -void VADDw() { VU0.code = cpuRegs.code; _vuADDw(&VU0); SYNCMSFLAGS(); } -void VADDA() { VU0.code = cpuRegs.code; _vuADDA(&VU0); SYNCMSFLAGS(); } -void VADDAi() { VU0.code = cpuRegs.code; _vuADDAi(&VU0); SYNCMSFLAGS(); } -void VADDAq() { VU0.code = cpuRegs.code; _vuADDAq(&VU0); SYNCMSFLAGS(); } -void VADDAx() { VU0.code = cpuRegs.code; _vuADDAx(&VU0); SYNCMSFLAGS(); } -void VADDAy() { VU0.code = cpuRegs.code; _vuADDAy(&VU0); SYNCMSFLAGS(); } -void VADDAz() { VU0.code = cpuRegs.code; _vuADDAz(&VU0); SYNCMSFLAGS(); } -void VADDAw() { VU0.code = cpuRegs.code; _vuADDAw(&VU0); SYNCMSFLAGS(); } -void VSUB() { VU0.code = cpuRegs.code; _vuSUB(&VU0); SYNCMSFLAGS(); } -void VSUBi() { VU0.code = cpuRegs.code; _vuSUBi(&VU0); SYNCMSFLAGS(); } -void VSUBq() { VU0.code = cpuRegs.code; _vuSUBq(&VU0); SYNCMSFLAGS(); } -void VSUBx() { VU0.code = cpuRegs.code; _vuSUBx(&VU0); SYNCMSFLAGS(); } -void VSUBy() { VU0.code = cpuRegs.code; _vuSUBy(&VU0); SYNCMSFLAGS(); } -void VSUBz() { VU0.code = cpuRegs.code; _vuSUBz(&VU0); SYNCMSFLAGS(); } -void VSUBw() { VU0.code = cpuRegs.code; _vuSUBw(&VU0); SYNCMSFLAGS(); } -void VSUBA() { VU0.code = cpuRegs.code; _vuSUBA(&VU0); SYNCMSFLAGS(); } -void VSUBAi() { VU0.code = cpuRegs.code; _vuSUBAi(&VU0); SYNCMSFLAGS(); } -void VSUBAq() { VU0.code = cpuRegs.code; _vuSUBAq(&VU0); SYNCMSFLAGS(); } -void VSUBAx() { VU0.code = cpuRegs.code; _vuSUBAx(&VU0); SYNCMSFLAGS(); } -void VSUBAy() { VU0.code = cpuRegs.code; _vuSUBAy(&VU0); SYNCMSFLAGS(); } -void VSUBAz() { VU0.code = cpuRegs.code; _vuSUBAz(&VU0); SYNCMSFLAGS(); } -void VSUBAw() { VU0.code = cpuRegs.code; _vuSUBAw(&VU0); SYNCMSFLAGS(); } -void VMUL() { VU0.code = cpuRegs.code; _vuMUL(&VU0); SYNCMSFLAGS(); } -void VMULi() { VU0.code = cpuRegs.code; _vuMULi(&VU0); SYNCMSFLAGS(); } -void VMULq() { VU0.code = cpuRegs.code; _vuMULq(&VU0); SYNCMSFLAGS(); } -void VMULx() { VU0.code = cpuRegs.code; _vuMULx(&VU0); SYNCMSFLAGS(); } -void VMULy() { VU0.code = cpuRegs.code; _vuMULy(&VU0); SYNCMSFLAGS(); } -void VMULz() { VU0.code = cpuRegs.code; _vuMULz(&VU0); SYNCMSFLAGS(); } -void VMULw() { VU0.code = cpuRegs.code; _vuMULw(&VU0); SYNCMSFLAGS(); } -void VMULA() { VU0.code = cpuRegs.code; _vuMULA(&VU0); SYNCMSFLAGS(); } -void VMULAi() { VU0.code = cpuRegs.code; _vuMULAi(&VU0); SYNCMSFLAGS(); } -void VMULAq() { VU0.code = cpuRegs.code; _vuMULAq(&VU0); SYNCMSFLAGS(); } -void VMULAx() { VU0.code = cpuRegs.code; _vuMULAx(&VU0); SYNCMSFLAGS(); } -void VMULAy() { VU0.code = cpuRegs.code; _vuMULAy(&VU0); SYNCMSFLAGS(); } -void VMULAz() { VU0.code = cpuRegs.code; _vuMULAz(&VU0); SYNCMSFLAGS(); } -void VMULAw() { VU0.code = cpuRegs.code; _vuMULAw(&VU0); SYNCMSFLAGS(); } -void VMADD() { VU0.code = cpuRegs.code; _vuMADD(&VU0); SYNCMSFLAGS(); } -void VMADDi() { VU0.code = cpuRegs.code; _vuMADDi(&VU0); SYNCMSFLAGS(); } -void VMADDq() { VU0.code = cpuRegs.code; _vuMADDq(&VU0); SYNCMSFLAGS(); } -void VMADDx() { VU0.code = cpuRegs.code; _vuMADDx(&VU0); SYNCMSFLAGS(); } -void VMADDy() { VU0.code = cpuRegs.code; _vuMADDy(&VU0); SYNCMSFLAGS(); } -void VMADDz() { VU0.code = cpuRegs.code; _vuMADDz(&VU0); SYNCMSFLAGS(); } -void VMADDw() { VU0.code = cpuRegs.code; _vuMADDw(&VU0); SYNCMSFLAGS(); } -void VMADDA() { VU0.code = cpuRegs.code; _vuMADDA(&VU0); SYNCMSFLAGS(); } -void VMADDAi() { VU0.code = cpuRegs.code; _vuMADDAi(&VU0); SYNCMSFLAGS(); } -void VMADDAq() { VU0.code = cpuRegs.code; _vuMADDAq(&VU0); SYNCMSFLAGS(); } -void VMADDAx() { VU0.code = cpuRegs.code; _vuMADDAx(&VU0); SYNCMSFLAGS(); } -void VMADDAy() { VU0.code = cpuRegs.code; _vuMADDAy(&VU0); SYNCMSFLAGS(); } -void VMADDAz() { VU0.code = cpuRegs.code; _vuMADDAz(&VU0); SYNCMSFLAGS(); } -void VMADDAw() { VU0.code = cpuRegs.code; _vuMADDAw(&VU0); SYNCMSFLAGS(); } -void VMSUB() { VU0.code = cpuRegs.code; _vuMSUB(&VU0); SYNCMSFLAGS(); } -void VMSUBi() { VU0.code = cpuRegs.code; _vuMSUBi(&VU0); SYNCMSFLAGS(); } -void VMSUBq() { VU0.code = cpuRegs.code; _vuMSUBq(&VU0); SYNCMSFLAGS(); } -void VMSUBx() { VU0.code = cpuRegs.code; _vuMSUBx(&VU0); SYNCMSFLAGS(); } -void VMSUBy() { VU0.code = cpuRegs.code; _vuMSUBy(&VU0); SYNCMSFLAGS(); } -void VMSUBz() { VU0.code = cpuRegs.code; _vuMSUBz(&VU0); SYNCMSFLAGS(); } -void VMSUBw() { VU0.code = cpuRegs.code; _vuMSUBw(&VU0); SYNCMSFLAGS(); } -void VMSUBA() { VU0.code = cpuRegs.code; _vuMSUBA(&VU0); SYNCMSFLAGS(); } -void VMSUBAi() { VU0.code = cpuRegs.code; _vuMSUBAi(&VU0); SYNCMSFLAGS(); } -void VMSUBAq() { VU0.code = cpuRegs.code; _vuMSUBAq(&VU0); SYNCMSFLAGS(); } -void VMSUBAx() { VU0.code = cpuRegs.code; _vuMSUBAx(&VU0); SYNCMSFLAGS(); } -void VMSUBAy() { VU0.code = cpuRegs.code; _vuMSUBAy(&VU0); SYNCMSFLAGS(); } -void VMSUBAz() { VU0.code = cpuRegs.code; _vuMSUBAz(&VU0); SYNCMSFLAGS(); } -void VMSUBAw() { VU0.code = cpuRegs.code; _vuMSUBAw(&VU0); SYNCMSFLAGS(); } -void VMAX() { VU0.code = cpuRegs.code; _vuMAX(&VU0); } -void VMAXi() { VU0.code = cpuRegs.code; _vuMAXi(&VU0); } -void VMAXx() { VU0.code = cpuRegs.code; _vuMAXx(&VU0); } -void VMAXy() { VU0.code = cpuRegs.code; _vuMAXy(&VU0); } -void VMAXz() { VU0.code = cpuRegs.code; _vuMAXz(&VU0); } -void VMAXw() { VU0.code = cpuRegs.code; _vuMAXw(&VU0); } -void VMINI() { VU0.code = cpuRegs.code; _vuMINI(&VU0); } -void VMINIi() { VU0.code = cpuRegs.code; _vuMINIi(&VU0); } -void VMINIx() { VU0.code = cpuRegs.code; _vuMINIx(&VU0); } -void VMINIy() { VU0.code = cpuRegs.code; _vuMINIy(&VU0); } -void VMINIz() { VU0.code = cpuRegs.code; _vuMINIz(&VU0); } -void VMINIw() { VU0.code = cpuRegs.code; _vuMINIw(&VU0); } -void VOPMULA() { VU0.code = cpuRegs.code; _vuOPMULA(&VU0); SYNCMSFLAGS(); } -void VOPMSUB() { VU0.code = cpuRegs.code; _vuOPMSUB(&VU0); SYNCMSFLAGS(); } -void VNOP() { VU0.code = cpuRegs.code; _vuNOP(&VU0); } -void VFTOI0() { VU0.code = cpuRegs.code; _vuFTOI0(&VU0); } -void VFTOI4() { VU0.code = cpuRegs.code; _vuFTOI4(&VU0); } -void VFTOI12() { VU0.code = cpuRegs.code; _vuFTOI12(&VU0); } -void VFTOI15() { VU0.code = cpuRegs.code; _vuFTOI15(&VU0); } -void VITOF0() { VU0.code = cpuRegs.code; _vuITOF0(&VU0); } -void VITOF4() { VU0.code = cpuRegs.code; _vuITOF4(&VU0); } -void VITOF12() { VU0.code = cpuRegs.code; _vuITOF12(&VU0); } -void VITOF15() { VU0.code = cpuRegs.code; _vuITOF15(&VU0); } -void VCLIPw() { VU0.code = cpuRegs.code; _vuCLIP(&VU0); VU0.VI[REG_CLIP_FLAG].UL = VU0.clipflag; } - -void VDIV() { VU0.code = cpuRegs.code; _vuDIV(&VU0); SYNCFDIV(); } -void VSQRT() { VU0.code = cpuRegs.code; _vuSQRT(&VU0); SYNCFDIV(); } -void VRSQRT() { VU0.code = cpuRegs.code; _vuRSQRT(&VU0); SYNCFDIV(); } -void VIADD() { VU0.code = cpuRegs.code; _vuIADD(&VU0); } -void VIADDI() { VU0.code = cpuRegs.code; _vuIADDI(&VU0); } -void VIADDIU() { VU0.code = cpuRegs.code; _vuIADDIU(&VU0); } -void VIAND() { VU0.code = cpuRegs.code; _vuIAND(&VU0); } -void VIOR() { VU0.code = cpuRegs.code; _vuIOR(&VU0); } -void VISUB() { VU0.code = cpuRegs.code; _vuISUB(&VU0); } -void VISUBIU() { VU0.code = cpuRegs.code; _vuISUBIU(&VU0); } -void VMOVE() { VU0.code = cpuRegs.code; _vuMOVE(&VU0); } -void VMFIR() { VU0.code = cpuRegs.code; _vuMFIR(&VU0); } -void VMTIR() { VU0.code = cpuRegs.code; _vuMTIR(&VU0); } -void VMR32() { VU0.code = cpuRegs.code; _vuMR32(&VU0); } -void VLQ() { VU0.code = cpuRegs.code; _vuLQ(&VU0); } -void VLQD() { VU0.code = cpuRegs.code; _vuLQD(&VU0); } -void VLQI() { VU0.code = cpuRegs.code; _vuLQI(&VU0); } -void VSQ() { VU0.code = cpuRegs.code; _vuSQ(&VU0); } -void VSQD() { VU0.code = cpuRegs.code; _vuSQD(&VU0); } -void VSQI() { VU0.code = cpuRegs.code; _vuSQI(&VU0); } -void VILW() { VU0.code = cpuRegs.code; _vuILW(&VU0); } -void VISW() { VU0.code = cpuRegs.code; _vuISW(&VU0); } -void VILWR() { VU0.code = cpuRegs.code; _vuILWR(&VU0); } -void VISWR() { VU0.code = cpuRegs.code; _vuISWR(&VU0); } -void VRINIT() { VU0.code = cpuRegs.code; _vuRINIT(&VU0); } -void VRGET() { VU0.code = cpuRegs.code; _vuRGET(&VU0); } -void VRNEXT() { VU0.code = cpuRegs.code; _vuRNEXT(&VU0); } -void VRXOR() { VU0.code = cpuRegs.code; _vuRXOR(&VU0); } -void VWAITQ() { VU0.code = cpuRegs.code; _vuWAITQ(&VU0); } -void VFSAND() { VU0.code = cpuRegs.code; _vuFSAND(&VU0); } -void VFSEQ() { VU0.code = cpuRegs.code; _vuFSEQ(&VU0); } -void VFSOR() { VU0.code = cpuRegs.code; _vuFSOR(&VU0); } -void VFSSET() { VU0.code = cpuRegs.code; _vuFSSET(&VU0); } -void VFMAND() { VU0.code = cpuRegs.code; _vuFMAND(&VU0); } -void VFMEQ() { VU0.code = cpuRegs.code; _vuFMEQ(&VU0); } -void VFMOR() { VU0.code = cpuRegs.code; _vuFMOR(&VU0); } -void VFCAND() { VU0.code = cpuRegs.code; _vuFCAND(&VU0); } -void VFCEQ() { VU0.code = cpuRegs.code; _vuFCEQ(&VU0); } -void VFCOR() { VU0.code = cpuRegs.code; _vuFCOR(&VU0); } -void VFCSET() { VU0.code = cpuRegs.code; _vuFCSET(&VU0); } -void VFCGET() { VU0.code = cpuRegs.code; _vuFCGET(&VU0); } -void VXITOP() { VU0.code = cpuRegs.code; _vuXITOP(&VU0); } - -// fixme: Shouldn't anything calling this function be calling vu0WaitMicro instead? -// Meaning that this function stalls, but doesn't increment the cpuRegs.cycle like -// you would think it should. -void vu0Finish() -{ - if( (VU0.VI[REG_VPU_STAT].UL & 0x1) ) { - int i = 0; - - while(i++ < 32) { - CpuVU0.ExecuteBlock(); - if(!(VU0.VI[REG_VPU_STAT].UL & 0x1)) - break; - } - if(VU0.VI[REG_VPU_STAT].UL & 0x1) { - VU0.VI[REG_VPU_STAT].UL &= ~1; - // this log tends to spam a lot (MGS3) - //Console::Notice("vu0Finish > stall aborted by force."); - } - } -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +/* TODO + -Fix the flags Proper as they aren't handle now.. + -Add BC Table opcodes + -Add Interlock in QMFC2,QMTC2,CFC2,CTC2 + -Finish instruction set + -Bug Fixes!!! +*/ + +#include "PrecompiledHeader.h" + +#include + +#include "Common.h" +#include "DebugTools/Debug.h" +#include "R5900.h" +#include "R5900OpcodeTables.h" +#include "VUops.h" +#include "VUmicro.h" + +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +#define _X (cpuRegs.code>>24) & 0x1 +#define _Y (cpuRegs.code>>23) & 0x1 +#define _Z (cpuRegs.code>>22) & 0x1 +#define _W (cpuRegs.code>>21) & 0x1 + +#define _Fsf_ ((cpuRegs.code >> 21) & 0x03) +#define _Ftf_ ((cpuRegs.code >> 23) & 0x03) + +#include "VUflags.h" + +using namespace R5900; + +PCSX2_ALIGNED16(VURegs VU0); + +void COP2_BC2() { Int_COP2BC2PrintTable[_Rt_]();} +void COP2_SPECIAL() { Int_COP2SPECIAL1PrintTable[_Funct_]();} + +void COP2_SPECIAL2() { + Int_COP2SPECIAL2PrintTable[(cpuRegs.code & 0x3) | ((cpuRegs.code >> 4) & 0x7c)](); +} + +void COP2_Unknown() +{ + CPU_LOG("Unknown COP2 opcode called\n"); +} + +//**************************************************************************** +void _vu0WaitMicro() { + int startcycle; + + if ((VU0.VI[REG_VPU_STAT].UL & 0x1) == 0) { + return; + } + + startcycle = VU0.cycle; + + VU0.flags|= VUFLAG_BREAKONMFLAG; + VU0.flags&= ~VUFLAG_MFLAGSET; + + do { + CpuVU0.ExecuteBlock(); + // knockout kings 2002 loops here + if( VU0.cycle-startcycle > 0x1000 ) { + Console::Notice("VU0 perma-stall, breaking execution..."); // (email zero if gfx are bad) + break; + } + } while ((VU0.VI[REG_VPU_STAT].UL & 0x1) && (VU0.flags & VUFLAG_MFLAGSET) == 0); + + //NEW + cpuRegs.cycle += (VU0.cycle-startcycle)*2; + VU0.flags&= ~VUFLAG_BREAKONMFLAG; +} + +namespace R5900 { +namespace Interpreter{ +namespace OpcodeImpl +{ + void LQC2() { + u32 addr = cpuRegs.GPR.r[_Rs_].UL[0] + (s16)cpuRegs.code; + if (_Ft_) { + memRead128(addr, &VU0.VF[_Ft_].UD[0]); + } else { + u64 val[2]; + memRead128(addr, val); + } + } + + // Asadr.Changed + //TODO: check this + // HUH why ? doesn;t make any sense ... + void SQC2() { + u32 addr = _Imm_ + cpuRegs.GPR.r[_Rs_].UL[0]; + //memWrite64(addr, VU0.VF[_Ft_].UD[0]); + //memWrite64(addr+8,VU0.VF[_Ft_].UD[1]); + memWrite128(addr, &VU0.VF[_Ft_].UD[0]); + } +}}} + + +void QMFC2() { + if (cpuRegs.code & 1) { + _vu0WaitMicro(); + } + if (_Rt_ == 0) return; + cpuRegs.GPR.r[_Rt_].UD[0] = VU0.VF[_Fs_].UD[0]; + cpuRegs.GPR.r[_Rt_].UD[1] = VU0.VF[_Fs_].UD[1]; +} + +void QMTC2() { + if (cpuRegs.code & 1) { + _vu0WaitMicro(); + } + if (_Fs_ == 0) return; + VU0.VF[_Fs_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0]; + VU0.VF[_Fs_].UD[1] = cpuRegs.GPR.r[_Rt_].UD[1]; +} + +void CFC2() { + if (cpuRegs.code & 1) { + _vu0WaitMicro(); + } + if (_Rt_ == 0) return; + cpuRegs.GPR.r[_Rt_].UL[0] = VU0.VI[_Fs_].UL; + if(VU0.VI[_Fs_].UL & 0x80000000) + cpuRegs.GPR.r[_Rt_].UL[1] = 0xffffffff; + else + cpuRegs.GPR.r[_Rt_].UL[1] = 0; +} + +void CTC2() { + if (cpuRegs.code & 1) { + _vu0WaitMicro(); + } + if (_Fs_ == 0) return; + + switch(_Fs_) { + case REG_MAC_FLAG: // read-only + case REG_TPC: // read-only + case REG_VPU_STAT: // read-only + break; + case REG_FBRST: + VU0.VI[REG_FBRST].UL = cpuRegs.GPR.r[_Rt_].UL[0] & 0x0C0C; + if (cpuRegs.GPR.r[_Rt_].UL[0] & 0x1) { // VU0 Force Break + Console::Error("fixme: VU0 Force Break"); + } + if (cpuRegs.GPR.r[_Rt_].UL[0] & 0x2) { // VU0 Reset + //SysPrintf("fixme: VU0 Reset\n"); + vu0ResetRegs(); + } + if (cpuRegs.GPR.r[_Rt_].UL[0] & 0x100) { // VU1 Force Break + Console::Error("fixme: VU1 Force Break"); + } + if (cpuRegs.GPR.r[_Rt_].UL[0] & 0x200) { // VU1 Reset +// SysPrintf("fixme: VU1 Reset\n"); + vu1ResetRegs(); + } + break; + case REG_CMSAR1: // REG_CMSAR1 + if (!(VU0.VI[REG_VPU_STAT].UL & 0x100) ) { + VU1.VI[REG_TPC].UL = cpuRegs.GPR.r[_Rt_].US[0]; + vu1ExecMicro(VU1.VI[REG_TPC].UL); // Execute VU1 Micro SubRoutine + } + break; + default: + VU0.VI[_Fs_].UL = cpuRegs.GPR.r[_Rt_].UL[0]; + break; + } +} + +//--------------------------------------------------------------------------------------- + + +__forceinline void SYNCMSFLAGS() +{ + VU0.VI[REG_STATUS_FLAG].UL = VU0.statusflag; + VU0.VI[REG_MAC_FLAG].UL = VU0.macflag; +} + +__forceinline void SYNCFDIV() +{ + VU0.VI[REG_Q].UL = VU0.q.UL; + VU0.VI[REG_STATUS_FLAG].UL = VU0.statusflag; +} + +void VABS() { VU0.code = cpuRegs.code; _vuABS(&VU0); } +void VADD() { VU0.code = cpuRegs.code; _vuADD(&VU0); SYNCMSFLAGS(); } +void VADDi() { VU0.code = cpuRegs.code; _vuADDi(&VU0); SYNCMSFLAGS(); } +void VADDq() { VU0.code = cpuRegs.code; _vuADDq(&VU0); SYNCMSFLAGS(); } +void VADDx() { VU0.code = cpuRegs.code; _vuADDx(&VU0); SYNCMSFLAGS(); } +void VADDy() { VU0.code = cpuRegs.code; _vuADDy(&VU0); SYNCMSFLAGS(); } +void VADDz() { VU0.code = cpuRegs.code; _vuADDz(&VU0); SYNCMSFLAGS(); } +void VADDw() { VU0.code = cpuRegs.code; _vuADDw(&VU0); SYNCMSFLAGS(); } +void VADDA() { VU0.code = cpuRegs.code; _vuADDA(&VU0); SYNCMSFLAGS(); } +void VADDAi() { VU0.code = cpuRegs.code; _vuADDAi(&VU0); SYNCMSFLAGS(); } +void VADDAq() { VU0.code = cpuRegs.code; _vuADDAq(&VU0); SYNCMSFLAGS(); } +void VADDAx() { VU0.code = cpuRegs.code; _vuADDAx(&VU0); SYNCMSFLAGS(); } +void VADDAy() { VU0.code = cpuRegs.code; _vuADDAy(&VU0); SYNCMSFLAGS(); } +void VADDAz() { VU0.code = cpuRegs.code; _vuADDAz(&VU0); SYNCMSFLAGS(); } +void VADDAw() { VU0.code = cpuRegs.code; _vuADDAw(&VU0); SYNCMSFLAGS(); } +void VSUB() { VU0.code = cpuRegs.code; _vuSUB(&VU0); SYNCMSFLAGS(); } +void VSUBi() { VU0.code = cpuRegs.code; _vuSUBi(&VU0); SYNCMSFLAGS(); } +void VSUBq() { VU0.code = cpuRegs.code; _vuSUBq(&VU0); SYNCMSFLAGS(); } +void VSUBx() { VU0.code = cpuRegs.code; _vuSUBx(&VU0); SYNCMSFLAGS(); } +void VSUBy() { VU0.code = cpuRegs.code; _vuSUBy(&VU0); SYNCMSFLAGS(); } +void VSUBz() { VU0.code = cpuRegs.code; _vuSUBz(&VU0); SYNCMSFLAGS(); } +void VSUBw() { VU0.code = cpuRegs.code; _vuSUBw(&VU0); SYNCMSFLAGS(); } +void VSUBA() { VU0.code = cpuRegs.code; _vuSUBA(&VU0); SYNCMSFLAGS(); } +void VSUBAi() { VU0.code = cpuRegs.code; _vuSUBAi(&VU0); SYNCMSFLAGS(); } +void VSUBAq() { VU0.code = cpuRegs.code; _vuSUBAq(&VU0); SYNCMSFLAGS(); } +void VSUBAx() { VU0.code = cpuRegs.code; _vuSUBAx(&VU0); SYNCMSFLAGS(); } +void VSUBAy() { VU0.code = cpuRegs.code; _vuSUBAy(&VU0); SYNCMSFLAGS(); } +void VSUBAz() { VU0.code = cpuRegs.code; _vuSUBAz(&VU0); SYNCMSFLAGS(); } +void VSUBAw() { VU0.code = cpuRegs.code; _vuSUBAw(&VU0); SYNCMSFLAGS(); } +void VMUL() { VU0.code = cpuRegs.code; _vuMUL(&VU0); SYNCMSFLAGS(); } +void VMULi() { VU0.code = cpuRegs.code; _vuMULi(&VU0); SYNCMSFLAGS(); } +void VMULq() { VU0.code = cpuRegs.code; _vuMULq(&VU0); SYNCMSFLAGS(); } +void VMULx() { VU0.code = cpuRegs.code; _vuMULx(&VU0); SYNCMSFLAGS(); } +void VMULy() { VU0.code = cpuRegs.code; _vuMULy(&VU0); SYNCMSFLAGS(); } +void VMULz() { VU0.code = cpuRegs.code; _vuMULz(&VU0); SYNCMSFLAGS(); } +void VMULw() { VU0.code = cpuRegs.code; _vuMULw(&VU0); SYNCMSFLAGS(); } +void VMULA() { VU0.code = cpuRegs.code; _vuMULA(&VU0); SYNCMSFLAGS(); } +void VMULAi() { VU0.code = cpuRegs.code; _vuMULAi(&VU0); SYNCMSFLAGS(); } +void VMULAq() { VU0.code = cpuRegs.code; _vuMULAq(&VU0); SYNCMSFLAGS(); } +void VMULAx() { VU0.code = cpuRegs.code; _vuMULAx(&VU0); SYNCMSFLAGS(); } +void VMULAy() { VU0.code = cpuRegs.code; _vuMULAy(&VU0); SYNCMSFLAGS(); } +void VMULAz() { VU0.code = cpuRegs.code; _vuMULAz(&VU0); SYNCMSFLAGS(); } +void VMULAw() { VU0.code = cpuRegs.code; _vuMULAw(&VU0); SYNCMSFLAGS(); } +void VMADD() { VU0.code = cpuRegs.code; _vuMADD(&VU0); SYNCMSFLAGS(); } +void VMADDi() { VU0.code = cpuRegs.code; _vuMADDi(&VU0); SYNCMSFLAGS(); } +void VMADDq() { VU0.code = cpuRegs.code; _vuMADDq(&VU0); SYNCMSFLAGS(); } +void VMADDx() { VU0.code = cpuRegs.code; _vuMADDx(&VU0); SYNCMSFLAGS(); } +void VMADDy() { VU0.code = cpuRegs.code; _vuMADDy(&VU0); SYNCMSFLAGS(); } +void VMADDz() { VU0.code = cpuRegs.code; _vuMADDz(&VU0); SYNCMSFLAGS(); } +void VMADDw() { VU0.code = cpuRegs.code; _vuMADDw(&VU0); SYNCMSFLAGS(); } +void VMADDA() { VU0.code = cpuRegs.code; _vuMADDA(&VU0); SYNCMSFLAGS(); } +void VMADDAi() { VU0.code = cpuRegs.code; _vuMADDAi(&VU0); SYNCMSFLAGS(); } +void VMADDAq() { VU0.code = cpuRegs.code; _vuMADDAq(&VU0); SYNCMSFLAGS(); } +void VMADDAx() { VU0.code = cpuRegs.code; _vuMADDAx(&VU0); SYNCMSFLAGS(); } +void VMADDAy() { VU0.code = cpuRegs.code; _vuMADDAy(&VU0); SYNCMSFLAGS(); } +void VMADDAz() { VU0.code = cpuRegs.code; _vuMADDAz(&VU0); SYNCMSFLAGS(); } +void VMADDAw() { VU0.code = cpuRegs.code; _vuMADDAw(&VU0); SYNCMSFLAGS(); } +void VMSUB() { VU0.code = cpuRegs.code; _vuMSUB(&VU0); SYNCMSFLAGS(); } +void VMSUBi() { VU0.code = cpuRegs.code; _vuMSUBi(&VU0); SYNCMSFLAGS(); } +void VMSUBq() { VU0.code = cpuRegs.code; _vuMSUBq(&VU0); SYNCMSFLAGS(); } +void VMSUBx() { VU0.code = cpuRegs.code; _vuMSUBx(&VU0); SYNCMSFLAGS(); } +void VMSUBy() { VU0.code = cpuRegs.code; _vuMSUBy(&VU0); SYNCMSFLAGS(); } +void VMSUBz() { VU0.code = cpuRegs.code; _vuMSUBz(&VU0); SYNCMSFLAGS(); } +void VMSUBw() { VU0.code = cpuRegs.code; _vuMSUBw(&VU0); SYNCMSFLAGS(); } +void VMSUBA() { VU0.code = cpuRegs.code; _vuMSUBA(&VU0); SYNCMSFLAGS(); } +void VMSUBAi() { VU0.code = cpuRegs.code; _vuMSUBAi(&VU0); SYNCMSFLAGS(); } +void VMSUBAq() { VU0.code = cpuRegs.code; _vuMSUBAq(&VU0); SYNCMSFLAGS(); } +void VMSUBAx() { VU0.code = cpuRegs.code; _vuMSUBAx(&VU0); SYNCMSFLAGS(); } +void VMSUBAy() { VU0.code = cpuRegs.code; _vuMSUBAy(&VU0); SYNCMSFLAGS(); } +void VMSUBAz() { VU0.code = cpuRegs.code; _vuMSUBAz(&VU0); SYNCMSFLAGS(); } +void VMSUBAw() { VU0.code = cpuRegs.code; _vuMSUBAw(&VU0); SYNCMSFLAGS(); } +void VMAX() { VU0.code = cpuRegs.code; _vuMAX(&VU0); } +void VMAXi() { VU0.code = cpuRegs.code; _vuMAXi(&VU0); } +void VMAXx() { VU0.code = cpuRegs.code; _vuMAXx(&VU0); } +void VMAXy() { VU0.code = cpuRegs.code; _vuMAXy(&VU0); } +void VMAXz() { VU0.code = cpuRegs.code; _vuMAXz(&VU0); } +void VMAXw() { VU0.code = cpuRegs.code; _vuMAXw(&VU0); } +void VMINI() { VU0.code = cpuRegs.code; _vuMINI(&VU0); } +void VMINIi() { VU0.code = cpuRegs.code; _vuMINIi(&VU0); } +void VMINIx() { VU0.code = cpuRegs.code; _vuMINIx(&VU0); } +void VMINIy() { VU0.code = cpuRegs.code; _vuMINIy(&VU0); } +void VMINIz() { VU0.code = cpuRegs.code; _vuMINIz(&VU0); } +void VMINIw() { VU0.code = cpuRegs.code; _vuMINIw(&VU0); } +void VOPMULA() { VU0.code = cpuRegs.code; _vuOPMULA(&VU0); SYNCMSFLAGS(); } +void VOPMSUB() { VU0.code = cpuRegs.code; _vuOPMSUB(&VU0); SYNCMSFLAGS(); } +void VNOP() { VU0.code = cpuRegs.code; _vuNOP(&VU0); } +void VFTOI0() { VU0.code = cpuRegs.code; _vuFTOI0(&VU0); } +void VFTOI4() { VU0.code = cpuRegs.code; _vuFTOI4(&VU0); } +void VFTOI12() { VU0.code = cpuRegs.code; _vuFTOI12(&VU0); } +void VFTOI15() { VU0.code = cpuRegs.code; _vuFTOI15(&VU0); } +void VITOF0() { VU0.code = cpuRegs.code; _vuITOF0(&VU0); } +void VITOF4() { VU0.code = cpuRegs.code; _vuITOF4(&VU0); } +void VITOF12() { VU0.code = cpuRegs.code; _vuITOF12(&VU0); } +void VITOF15() { VU0.code = cpuRegs.code; _vuITOF15(&VU0); } +void VCLIPw() { VU0.code = cpuRegs.code; _vuCLIP(&VU0); VU0.VI[REG_CLIP_FLAG].UL = VU0.clipflag; } + +void VDIV() { VU0.code = cpuRegs.code; _vuDIV(&VU0); SYNCFDIV(); } +void VSQRT() { VU0.code = cpuRegs.code; _vuSQRT(&VU0); SYNCFDIV(); } +void VRSQRT() { VU0.code = cpuRegs.code; _vuRSQRT(&VU0); SYNCFDIV(); } +void VIADD() { VU0.code = cpuRegs.code; _vuIADD(&VU0); } +void VIADDI() { VU0.code = cpuRegs.code; _vuIADDI(&VU0); } +void VIADDIU() { VU0.code = cpuRegs.code; _vuIADDIU(&VU0); } +void VIAND() { VU0.code = cpuRegs.code; _vuIAND(&VU0); } +void VIOR() { VU0.code = cpuRegs.code; _vuIOR(&VU0); } +void VISUB() { VU0.code = cpuRegs.code; _vuISUB(&VU0); } +void VISUBIU() { VU0.code = cpuRegs.code; _vuISUBIU(&VU0); } +void VMOVE() { VU0.code = cpuRegs.code; _vuMOVE(&VU0); } +void VMFIR() { VU0.code = cpuRegs.code; _vuMFIR(&VU0); } +void VMTIR() { VU0.code = cpuRegs.code; _vuMTIR(&VU0); } +void VMR32() { VU0.code = cpuRegs.code; _vuMR32(&VU0); } +void VLQ() { VU0.code = cpuRegs.code; _vuLQ(&VU0); } +void VLQD() { VU0.code = cpuRegs.code; _vuLQD(&VU0); } +void VLQI() { VU0.code = cpuRegs.code; _vuLQI(&VU0); } +void VSQ() { VU0.code = cpuRegs.code; _vuSQ(&VU0); } +void VSQD() { VU0.code = cpuRegs.code; _vuSQD(&VU0); } +void VSQI() { VU0.code = cpuRegs.code; _vuSQI(&VU0); } +void VILW() { VU0.code = cpuRegs.code; _vuILW(&VU0); } +void VISW() { VU0.code = cpuRegs.code; _vuISW(&VU0); } +void VILWR() { VU0.code = cpuRegs.code; _vuILWR(&VU0); } +void VISWR() { VU0.code = cpuRegs.code; _vuISWR(&VU0); } +void VRINIT() { VU0.code = cpuRegs.code; _vuRINIT(&VU0); } +void VRGET() { VU0.code = cpuRegs.code; _vuRGET(&VU0); } +void VRNEXT() { VU0.code = cpuRegs.code; _vuRNEXT(&VU0); } +void VRXOR() { VU0.code = cpuRegs.code; _vuRXOR(&VU0); } +void VWAITQ() { VU0.code = cpuRegs.code; _vuWAITQ(&VU0); } +void VFSAND() { VU0.code = cpuRegs.code; _vuFSAND(&VU0); } +void VFSEQ() { VU0.code = cpuRegs.code; _vuFSEQ(&VU0); } +void VFSOR() { VU0.code = cpuRegs.code; _vuFSOR(&VU0); } +void VFSSET() { VU0.code = cpuRegs.code; _vuFSSET(&VU0); } +void VFMAND() { VU0.code = cpuRegs.code; _vuFMAND(&VU0); } +void VFMEQ() { VU0.code = cpuRegs.code; _vuFMEQ(&VU0); } +void VFMOR() { VU0.code = cpuRegs.code; _vuFMOR(&VU0); } +void VFCAND() { VU0.code = cpuRegs.code; _vuFCAND(&VU0); } +void VFCEQ() { VU0.code = cpuRegs.code; _vuFCEQ(&VU0); } +void VFCOR() { VU0.code = cpuRegs.code; _vuFCOR(&VU0); } +void VFCSET() { VU0.code = cpuRegs.code; _vuFCSET(&VU0); } +void VFCGET() { VU0.code = cpuRegs.code; _vuFCGET(&VU0); } +void VXITOP() { VU0.code = cpuRegs.code; _vuXITOP(&VU0); } + +// fixme: Shouldn't anything calling this function be calling vu0WaitMicro instead? +// Meaning that this function stalls, but doesn't increment the cpuRegs.cycle like +// you would think it should. +void vu0Finish() +{ + if( (VU0.VI[REG_VPU_STAT].UL & 0x1) ) { + int i = 0; + + while(i++ < 32) { + CpuVU0.ExecuteBlock(); + if(!(VU0.VI[REG_VPU_STAT].UL & 0x1)) + break; + } + if(VU0.VI[REG_VPU_STAT].UL & 0x1) { + VU0.VI[REG_VPU_STAT].UL &= ~1; + // this log tends to spam a lot (MGS3) + //Console::Notice("vu0Finish > stall aborted by force."); + } + } +} diff --git a/pcsx2/VU0micro.cpp b/pcsx2/VU0micro.cpp index 02063891ab..59bc4130f7 100644 --- a/pcsx2/VU0micro.cpp +++ b/pcsx2/VU0micro.cpp @@ -1,454 +1,454 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -// This module contains code shared by both the dynarec and interpreter versions -// of the VU0 micro. - - -#include "PrecompiledHeader.h" - -#include - -#include "Common.h" -#include "DebugTools/Debug.h" -#include "R5900.h" -#include "iR5900.h" -#include "VUmicro.h" -#include "VUflags.h" -#include "VUops.h" - -#include "iVUzerorec.h" - -using namespace R5900; - -#define VF_VAL(x) ((x==0x80000000)?0:(x)) - -void iDumpVU0Registers() -{ - // fixme: This code is outdated, broken, and lacks printed labels. - // Needs heavy mods to be useful. -#if 0 - int i; - - for(i = 1; i < 32; ++i) { - __Log("v%d: %x %x %x %x, vi: ", i, VF_VAL(VU0.VF[i].UL[3]), VF_VAL(VU0.VF[i].UL[2]), - VF_VAL(VU0.VF[i].UL[1]), VF_VAL(VU0.VF[i].UL[0])); - if( i == REG_Q || i == REG_P ) __Log("%f\n", VU0.VI[i].F); - else if( i == REG_MAC_FLAG ) __Log("%x\n", 0);//VU0.VI[i].UL&0xff); - else if( i == REG_STATUS_FLAG ) __Log("%x\n", 0);//VU0.VI[i].UL&0x03); - else if( i == REG_CLIP_FLAG ) __Log("0\n"); - else __Log("%x\n", VU0.VI[i].UL); - } - __Log("vfACC: %f %f %f %f\n", VU0.ACC.F[3], VU0.ACC.F[2], VU0.ACC.F[1], VU0.ACC.F[0]); -#endif -} - -// This is called by the COP2 as per the CTC instruction -void vu0ResetRegs() -{ - VU0.VI[REG_VPU_STAT].UL &= ~0xff; // stop vu0 - VU0.VI[REG_FBRST].UL &= ~0xff; // stop vu0 - vif0Regs->stat &= ~4; -} - -void VU0MI_XGKICK() { -} - -void VU0MI_XTOP() { -} - -void vu0ExecMicro(u32 addr) { - VUM_LOG("vu0ExecMicro %x\n", addr); - - if(VU0.VI[REG_VPU_STAT].UL & 0x1) { - DevCon::Notice("vu0ExecMicro > Stalling for previous microprogram to finish"); - vu0Finish(); - } - VU0.VI[REG_VPU_STAT].UL|= 0x1; - VU0.VI[REG_VPU_STAT].UL&= ~0xAE; - - if (addr != -1) VU0.VI[REG_TPC].UL = addr; - _vuExecMicroDebug(VU0); - CpuVU0.ExecuteBlock(); - - // If the VU0 program didn't finish then we'll want to finish it up - // pretty soon. This fixes vmhacks in some games (Naruto Ultimate Ninja 2) - if(VU0.VI[REG_VPU_STAT].UL & 0x1) - cpuSetNextBranchDelta( 192 ); // fixme : ideally this should be higher, like 512 or so. -} - -void VU0unknown() { - assert(0); - - CPU_LOG("Unknown VU micromode opcode called\n"); -} - -void VU0regsunknown(_VURegsNum *VUregsn) { - assert(0); - - CPU_LOG("Unknown VU micromode opcode called\n"); -} - -_vuRegsTables(VU0, VU0regs); - - -/****************************************/ -/* VU Micromode Upper instructions */ -/****************************************/ - -void VU0MI_ABS() { _vuABS(&VU0); } -void VU0MI_ADD() { _vuADD(&VU0); } -void VU0MI_ADDi() { _vuADDi(&VU0); } -void VU0MI_ADDq() { _vuADDq(&VU0); } -void VU0MI_ADDx() { _vuADDx(&VU0); } -void VU0MI_ADDy() { _vuADDy(&VU0); } -void VU0MI_ADDz() { _vuADDz(&VU0); } -void VU0MI_ADDw() { _vuADDw(&VU0); } -void VU0MI_ADDA() { _vuADDA(&VU0); } -void VU0MI_ADDAi() { _vuADDAi(&VU0); } -void VU0MI_ADDAq() { _vuADDAq(&VU0); } -void VU0MI_ADDAx() { _vuADDAx(&VU0); } -void VU0MI_ADDAy() { _vuADDAy(&VU0); } -void VU0MI_ADDAz() { _vuADDAz(&VU0); } -void VU0MI_ADDAw() { _vuADDAw(&VU0); } -void VU0MI_SUB() { _vuSUB(&VU0); } -void VU0MI_SUBi() { _vuSUBi(&VU0); } -void VU0MI_SUBq() { _vuSUBq(&VU0); } -void VU0MI_SUBx() { _vuSUBx(&VU0); } -void VU0MI_SUBy() { _vuSUBy(&VU0); } -void VU0MI_SUBz() { _vuSUBz(&VU0); } -void VU0MI_SUBw() { _vuSUBw(&VU0); } -void VU0MI_SUBA() { _vuSUBA(&VU0); } -void VU0MI_SUBAi() { _vuSUBAi(&VU0); } -void VU0MI_SUBAq() { _vuSUBAq(&VU0); } -void VU0MI_SUBAx() { _vuSUBAx(&VU0); } -void VU0MI_SUBAy() { _vuSUBAy(&VU0); } -void VU0MI_SUBAz() { _vuSUBAz(&VU0); } -void VU0MI_SUBAw() { _vuSUBAw(&VU0); } -void VU0MI_MUL() { _vuMUL(&VU0); } -void VU0MI_MULi() { _vuMULi(&VU0); } -void VU0MI_MULq() { _vuMULq(&VU0); } -void VU0MI_MULx() { _vuMULx(&VU0); } -void VU0MI_MULy() { _vuMULy(&VU0); } -void VU0MI_MULz() { _vuMULz(&VU0); } -void VU0MI_MULw() { _vuMULw(&VU0); } -void VU0MI_MULA() { _vuMULA(&VU0); } -void VU0MI_MULAi() { _vuMULAi(&VU0); } -void VU0MI_MULAq() { _vuMULAq(&VU0); } -void VU0MI_MULAx() { _vuMULAx(&VU0); } -void VU0MI_MULAy() { _vuMULAy(&VU0); } -void VU0MI_MULAz() { _vuMULAz(&VU0); } -void VU0MI_MULAw() { _vuMULAw(&VU0); } -void VU0MI_MADD() { _vuMADD(&VU0); } -void VU0MI_MADDi() { _vuMADDi(&VU0); } -void VU0MI_MADDq() { _vuMADDq(&VU0); } -void VU0MI_MADDx() { _vuMADDx(&VU0); } -void VU0MI_MADDy() { _vuMADDy(&VU0); } -void VU0MI_MADDz() { _vuMADDz(&VU0); } -void VU0MI_MADDw() { _vuMADDw(&VU0); } -void VU0MI_MADDA() { _vuMADDA(&VU0); } -void VU0MI_MADDAi() { _vuMADDAi(&VU0); } -void VU0MI_MADDAq() { _vuMADDAq(&VU0); } -void VU0MI_MADDAx() { _vuMADDAx(&VU0); } -void VU0MI_MADDAy() { _vuMADDAy(&VU0); } -void VU0MI_MADDAz() { _vuMADDAz(&VU0); } -void VU0MI_MADDAw() { _vuMADDAw(&VU0); } -void VU0MI_MSUB() { _vuMSUB(&VU0); } -void VU0MI_MSUBi() { _vuMSUBi(&VU0); } -void VU0MI_MSUBq() { _vuMSUBq(&VU0); } -void VU0MI_MSUBx() { _vuMSUBx(&VU0); } -void VU0MI_MSUBy() { _vuMSUBy(&VU0); } -void VU0MI_MSUBz() { _vuMSUBz(&VU0); } -void VU0MI_MSUBw() { _vuMSUBw(&VU0); } -void VU0MI_MSUBA() { _vuMSUBA(&VU0); } -void VU0MI_MSUBAi() { _vuMSUBAi(&VU0); } -void VU0MI_MSUBAq() { _vuMSUBAq(&VU0); } -void VU0MI_MSUBAx() { _vuMSUBAx(&VU0); } -void VU0MI_MSUBAy() { _vuMSUBAy(&VU0); } -void VU0MI_MSUBAz() { _vuMSUBAz(&VU0); } -void VU0MI_MSUBAw() { _vuMSUBAw(&VU0); } -void VU0MI_MAX() { _vuMAX(&VU0); } -void VU0MI_MAXi() { _vuMAXi(&VU0); } -void VU0MI_MAXx() { _vuMAXx(&VU0); } -void VU0MI_MAXy() { _vuMAXy(&VU0); } -void VU0MI_MAXz() { _vuMAXz(&VU0); } -void VU0MI_MAXw() { _vuMAXw(&VU0); } -void VU0MI_MINI() { _vuMINI(&VU0); } -void VU0MI_MINIi() { _vuMINIi(&VU0); } -void VU0MI_MINIx() { _vuMINIx(&VU0); } -void VU0MI_MINIy() { _vuMINIy(&VU0); } -void VU0MI_MINIz() { _vuMINIz(&VU0); } -void VU0MI_MINIw() { _vuMINIw(&VU0); } -void VU0MI_OPMULA() { _vuOPMULA(&VU0); } -void VU0MI_OPMSUB() { _vuOPMSUB(&VU0); } -void VU0MI_NOP() { _vuNOP(&VU0); } -void VU0MI_FTOI0() { _vuFTOI0(&VU0); } -void VU0MI_FTOI4() { _vuFTOI4(&VU0); } -void VU0MI_FTOI12() { _vuFTOI12(&VU0); } -void VU0MI_FTOI15() { _vuFTOI15(&VU0); } -void VU0MI_ITOF0() { _vuITOF0(&VU0); } -void VU0MI_ITOF4() { _vuITOF4(&VU0); } -void VU0MI_ITOF12() { _vuITOF12(&VU0); } -void VU0MI_ITOF15() { _vuITOF15(&VU0); } -void VU0MI_CLIP() { _vuCLIP(&VU0); } - -/*****************************************/ -/* VU Micromode Lower instructions */ -/*****************************************/ - -void VU0MI_DIV() { _vuDIV(&VU0); } -void VU0MI_SQRT() { _vuSQRT(&VU0); } -void VU0MI_RSQRT() { _vuRSQRT(&VU0); } -void VU0MI_IADD() { _vuIADD(&VU0); } -void VU0MI_IADDI() { _vuIADDI(&VU0); } -void VU0MI_IADDIU() { _vuIADDIU(&VU0); } -void VU0MI_IAND() { _vuIAND(&VU0); } -void VU0MI_IOR() { _vuIOR(&VU0); } -void VU0MI_ISUB() { _vuISUB(&VU0); } -void VU0MI_ISUBIU() { _vuISUBIU(&VU0); } -void VU0MI_MOVE() { _vuMOVE(&VU0); } -void VU0MI_MFIR() { _vuMFIR(&VU0); } -void VU0MI_MTIR() { _vuMTIR(&VU0); } -void VU0MI_MR32() { _vuMR32(&VU0); } -void VU0MI_LQ() { _vuLQ(&VU0); } -void VU0MI_LQD() { _vuLQD(&VU0); } -void VU0MI_LQI() { _vuLQI(&VU0); } -void VU0MI_SQ() { _vuSQ(&VU0); } -void VU0MI_SQD() { _vuSQD(&VU0); } -void VU0MI_SQI() { _vuSQI(&VU0); } -void VU0MI_ILW() { _vuILW(&VU0); } -void VU0MI_ISW() { _vuISW(&VU0); } -void VU0MI_ILWR() { _vuILWR(&VU0); } -void VU0MI_ISWR() { _vuISWR(&VU0); } -void VU0MI_RINIT() { _vuRINIT(&VU0); } -void VU0MI_RGET() { _vuRGET(&VU0); } -void VU0MI_RNEXT() { _vuRNEXT(&VU0); } -void VU0MI_RXOR() { _vuRXOR(&VU0); } -void VU0MI_WAITQ() { _vuWAITQ(&VU0); } -void VU0MI_FSAND() { _vuFSAND(&VU0); } -void VU0MI_FSEQ() { _vuFSEQ(&VU0); } -void VU0MI_FSOR() { _vuFSOR(&VU0); } -void VU0MI_FSSET() { _vuFSSET(&VU0); } -void VU0MI_FMAND() { _vuFMAND(&VU0); } -void VU0MI_FMEQ() { _vuFMEQ(&VU0); } -void VU0MI_FMOR() { _vuFMOR(&VU0); } -void VU0MI_FCAND() { _vuFCAND(&VU0); } -void VU0MI_FCEQ() { _vuFCEQ(&VU0); } -void VU0MI_FCOR() { _vuFCOR(&VU0); } -void VU0MI_FCSET() { _vuFCSET(&VU0); } -void VU0MI_FCGET() { _vuFCGET(&VU0); } -void VU0MI_IBEQ() { _vuIBEQ(&VU0); } -void VU0MI_IBGEZ() { _vuIBGEZ(&VU0); } -void VU0MI_IBGTZ() { _vuIBGTZ(&VU0); } -void VU0MI_IBLTZ() { _vuIBLTZ(&VU0); } -void VU0MI_IBLEZ() { _vuIBLEZ(&VU0); } -void VU0MI_IBNE() { _vuIBNE(&VU0); } -void VU0MI_B() { _vuB(&VU0); } -void VU0MI_BAL() { _vuBAL(&VU0); } -void VU0MI_JR() { _vuJR(&VU0); } -void VU0MI_JALR() { _vuJALR(&VU0); } -void VU0MI_MFP() { _vuMFP(&VU0); } -void VU0MI_WAITP() { _vuWAITP(&VU0); } -void VU0MI_ESADD() { _vuESADD(&VU0); } -void VU0MI_ERSADD() { _vuERSADD(&VU0); } -void VU0MI_ELENG() { _vuELENG(&VU0); } -void VU0MI_ERLENG() { _vuERLENG(&VU0); } -void VU0MI_EATANxy() { _vuEATANxy(&VU0); } -void VU0MI_EATANxz() { _vuEATANxz(&VU0); } -void VU0MI_ESUM() { _vuESUM(&VU0); } -void VU0MI_ERCPR() { _vuERCPR(&VU0); } -void VU0MI_ESQRT() { _vuESQRT(&VU0); } -void VU0MI_ERSQRT() { _vuERSQRT(&VU0); } -void VU0MI_ESIN() { _vuESIN(&VU0); } -void VU0MI_EATAN() { _vuEATAN(&VU0); } -void VU0MI_EEXP() { _vuEEXP(&VU0); } -void VU0MI_XITOP() { _vuXITOP(&VU0); } - -/****************************************/ -/* VU Micromode Upper instructions */ -/****************************************/ - -void VU0regsMI_ABS(_VURegsNum *VUregsn) { _vuRegsABS(&VU0, VUregsn); } -void VU0regsMI_ADD(_VURegsNum *VUregsn) { _vuRegsADD(&VU0, VUregsn); } -void VU0regsMI_ADDi(_VURegsNum *VUregsn) { _vuRegsADDi(&VU0, VUregsn); } -void VU0regsMI_ADDq(_VURegsNum *VUregsn) { _vuRegsADDq(&VU0, VUregsn); } -void VU0regsMI_ADDx(_VURegsNum *VUregsn) { _vuRegsADDx(&VU0, VUregsn); } -void VU0regsMI_ADDy(_VURegsNum *VUregsn) { _vuRegsADDy(&VU0, VUregsn); } -void VU0regsMI_ADDz(_VURegsNum *VUregsn) { _vuRegsADDz(&VU0, VUregsn); } -void VU0regsMI_ADDw(_VURegsNum *VUregsn) { _vuRegsADDw(&VU0, VUregsn); } -void VU0regsMI_ADDA(_VURegsNum *VUregsn) { _vuRegsADDA(&VU0, VUregsn); } -void VU0regsMI_ADDAi(_VURegsNum *VUregsn) { _vuRegsADDAi(&VU0, VUregsn); } -void VU0regsMI_ADDAq(_VURegsNum *VUregsn) { _vuRegsADDAq(&VU0, VUregsn); } -void VU0regsMI_ADDAx(_VURegsNum *VUregsn) { _vuRegsADDAx(&VU0, VUregsn); } -void VU0regsMI_ADDAy(_VURegsNum *VUregsn) { _vuRegsADDAy(&VU0, VUregsn); } -void VU0regsMI_ADDAz(_VURegsNum *VUregsn) { _vuRegsADDAz(&VU0, VUregsn); } -void VU0regsMI_ADDAw(_VURegsNum *VUregsn) { _vuRegsADDAw(&VU0, VUregsn); } -void VU0regsMI_SUB(_VURegsNum *VUregsn) { _vuRegsSUB(&VU0, VUregsn); } -void VU0regsMI_SUBi(_VURegsNum *VUregsn) { _vuRegsSUBi(&VU0, VUregsn); } -void VU0regsMI_SUBq(_VURegsNum *VUregsn) { _vuRegsSUBq(&VU0, VUregsn); } -void VU0regsMI_SUBx(_VURegsNum *VUregsn) { _vuRegsSUBx(&VU0, VUregsn); } -void VU0regsMI_SUBy(_VURegsNum *VUregsn) { _vuRegsSUBy(&VU0, VUregsn); } -void VU0regsMI_SUBz(_VURegsNum *VUregsn) { _vuRegsSUBz(&VU0, VUregsn); } -void VU0regsMI_SUBw(_VURegsNum *VUregsn) { _vuRegsSUBw(&VU0, VUregsn); } -void VU0regsMI_SUBA(_VURegsNum *VUregsn) { _vuRegsSUBA(&VU0, VUregsn); } -void VU0regsMI_SUBAi(_VURegsNum *VUregsn) { _vuRegsSUBAi(&VU0, VUregsn); } -void VU0regsMI_SUBAq(_VURegsNum *VUregsn) { _vuRegsSUBAq(&VU0, VUregsn); } -void VU0regsMI_SUBAx(_VURegsNum *VUregsn) { _vuRegsSUBAx(&VU0, VUregsn); } -void VU0regsMI_SUBAy(_VURegsNum *VUregsn) { _vuRegsSUBAy(&VU0, VUregsn); } -void VU0regsMI_SUBAz(_VURegsNum *VUregsn) { _vuRegsSUBAz(&VU0, VUregsn); } -void VU0regsMI_SUBAw(_VURegsNum *VUregsn) { _vuRegsSUBAw(&VU0, VUregsn); } -void VU0regsMI_MUL(_VURegsNum *VUregsn) { _vuRegsMUL(&VU0, VUregsn); } -void VU0regsMI_MULi(_VURegsNum *VUregsn) { _vuRegsMULi(&VU0, VUregsn); } -void VU0regsMI_MULq(_VURegsNum *VUregsn) { _vuRegsMULq(&VU0, VUregsn); } -void VU0regsMI_MULx(_VURegsNum *VUregsn) { _vuRegsMULx(&VU0, VUregsn); } -void VU0regsMI_MULy(_VURegsNum *VUregsn) { _vuRegsMULy(&VU0, VUregsn); } -void VU0regsMI_MULz(_VURegsNum *VUregsn) { _vuRegsMULz(&VU0, VUregsn); } -void VU0regsMI_MULw(_VURegsNum *VUregsn) { _vuRegsMULw(&VU0, VUregsn); } -void VU0regsMI_MULA(_VURegsNum *VUregsn) { _vuRegsMULA(&VU0, VUregsn); } -void VU0regsMI_MULAi(_VURegsNum *VUregsn) { _vuRegsMULAi(&VU0, VUregsn); } -void VU0regsMI_MULAq(_VURegsNum *VUregsn) { _vuRegsMULAq(&VU0, VUregsn); } -void VU0regsMI_MULAx(_VURegsNum *VUregsn) { _vuRegsMULAx(&VU0, VUregsn); } -void VU0regsMI_MULAy(_VURegsNum *VUregsn) { _vuRegsMULAy(&VU0, VUregsn); } -void VU0regsMI_MULAz(_VURegsNum *VUregsn) { _vuRegsMULAz(&VU0, VUregsn); } -void VU0regsMI_MULAw(_VURegsNum *VUregsn) { _vuRegsMULAw(&VU0, VUregsn); } -void VU0regsMI_MADD(_VURegsNum *VUregsn) { _vuRegsMADD(&VU0, VUregsn); } -void VU0regsMI_MADDi(_VURegsNum *VUregsn) { _vuRegsMADDi(&VU0, VUregsn); } -void VU0regsMI_MADDq(_VURegsNum *VUregsn) { _vuRegsMADDq(&VU0, VUregsn); } -void VU0regsMI_MADDx(_VURegsNum *VUregsn) { _vuRegsMADDx(&VU0, VUregsn); } -void VU0regsMI_MADDy(_VURegsNum *VUregsn) { _vuRegsMADDy(&VU0, VUregsn); } -void VU0regsMI_MADDz(_VURegsNum *VUregsn) { _vuRegsMADDz(&VU0, VUregsn); } -void VU0regsMI_MADDw(_VURegsNum *VUregsn) { _vuRegsMADDw(&VU0, VUregsn); } -void VU0regsMI_MADDA(_VURegsNum *VUregsn) { _vuRegsMADDA(&VU0, VUregsn); } -void VU0regsMI_MADDAi(_VURegsNum *VUregsn) { _vuRegsMADDAi(&VU0, VUregsn); } -void VU0regsMI_MADDAq(_VURegsNum *VUregsn) { _vuRegsMADDAq(&VU0, VUregsn); } -void VU0regsMI_MADDAx(_VURegsNum *VUregsn) { _vuRegsMADDAx(&VU0, VUregsn); } -void VU0regsMI_MADDAy(_VURegsNum *VUregsn) { _vuRegsMADDAy(&VU0, VUregsn); } -void VU0regsMI_MADDAz(_VURegsNum *VUregsn) { _vuRegsMADDAz(&VU0, VUregsn); } -void VU0regsMI_MADDAw(_VURegsNum *VUregsn) { _vuRegsMADDAw(&VU0, VUregsn); } -void VU0regsMI_MSUB(_VURegsNum *VUregsn) { _vuRegsMSUB(&VU0, VUregsn); } -void VU0regsMI_MSUBi(_VURegsNum *VUregsn) { _vuRegsMSUBi(&VU0, VUregsn); } -void VU0regsMI_MSUBq(_VURegsNum *VUregsn) { _vuRegsMSUBq(&VU0, VUregsn); } -void VU0regsMI_MSUBx(_VURegsNum *VUregsn) { _vuRegsMSUBx(&VU0, VUregsn); } -void VU0regsMI_MSUBy(_VURegsNum *VUregsn) { _vuRegsMSUBy(&VU0, VUregsn); } -void VU0regsMI_MSUBz(_VURegsNum *VUregsn) { _vuRegsMSUBz(&VU0, VUregsn); } -void VU0regsMI_MSUBw(_VURegsNum *VUregsn) { _vuRegsMSUBw(&VU0, VUregsn); } -void VU0regsMI_MSUBA(_VURegsNum *VUregsn) { _vuRegsMSUBA(&VU0, VUregsn); } -void VU0regsMI_MSUBAi(_VURegsNum *VUregsn) { _vuRegsMSUBAi(&VU0, VUregsn); } -void VU0regsMI_MSUBAq(_VURegsNum *VUregsn) { _vuRegsMSUBAq(&VU0, VUregsn); } -void VU0regsMI_MSUBAx(_VURegsNum *VUregsn) { _vuRegsMSUBAx(&VU0, VUregsn); } -void VU0regsMI_MSUBAy(_VURegsNum *VUregsn) { _vuRegsMSUBAy(&VU0, VUregsn); } -void VU0regsMI_MSUBAz(_VURegsNum *VUregsn) { _vuRegsMSUBAz(&VU0, VUregsn); } -void VU0regsMI_MSUBAw(_VURegsNum *VUregsn) { _vuRegsMSUBAw(&VU0, VUregsn); } -void VU0regsMI_MAX(_VURegsNum *VUregsn) { _vuRegsMAX(&VU0, VUregsn); } -void VU0regsMI_MAXi(_VURegsNum *VUregsn) { _vuRegsMAXi(&VU0, VUregsn); } -void VU0regsMI_MAXx(_VURegsNum *VUregsn) { _vuRegsMAXx(&VU0, VUregsn); } -void VU0regsMI_MAXy(_VURegsNum *VUregsn) { _vuRegsMAXy(&VU0, VUregsn); } -void VU0regsMI_MAXz(_VURegsNum *VUregsn) { _vuRegsMAXz(&VU0, VUregsn); } -void VU0regsMI_MAXw(_VURegsNum *VUregsn) { _vuRegsMAXw(&VU0, VUregsn); } -void VU0regsMI_MINI(_VURegsNum *VUregsn) { _vuRegsMINI(&VU0, VUregsn); } -void VU0regsMI_MINIi(_VURegsNum *VUregsn) { _vuRegsMINIi(&VU0, VUregsn); } -void VU0regsMI_MINIx(_VURegsNum *VUregsn) { _vuRegsMINIx(&VU0, VUregsn); } -void VU0regsMI_MINIy(_VURegsNum *VUregsn) { _vuRegsMINIy(&VU0, VUregsn); } -void VU0regsMI_MINIz(_VURegsNum *VUregsn) { _vuRegsMINIz(&VU0, VUregsn); } -void VU0regsMI_MINIw(_VURegsNum *VUregsn) { _vuRegsMINIw(&VU0, VUregsn); } -void VU0regsMI_OPMULA(_VURegsNum *VUregsn) { _vuRegsOPMULA(&VU0, VUregsn); } -void VU0regsMI_OPMSUB(_VURegsNum *VUregsn) { _vuRegsOPMSUB(&VU0, VUregsn); } -void VU0regsMI_NOP(_VURegsNum *VUregsn) { _vuRegsNOP(&VU0, VUregsn); } -void VU0regsMI_FTOI0(_VURegsNum *VUregsn) { _vuRegsFTOI0(&VU0, VUregsn); } -void VU0regsMI_FTOI4(_VURegsNum *VUregsn) { _vuRegsFTOI4(&VU0, VUregsn); } -void VU0regsMI_FTOI12(_VURegsNum *VUregsn) { _vuRegsFTOI12(&VU0, VUregsn); } -void VU0regsMI_FTOI15(_VURegsNum *VUregsn) { _vuRegsFTOI15(&VU0, VUregsn); } -void VU0regsMI_ITOF0(_VURegsNum *VUregsn) { _vuRegsITOF0(&VU0, VUregsn); } -void VU0regsMI_ITOF4(_VURegsNum *VUregsn) { _vuRegsITOF4(&VU0, VUregsn); } -void VU0regsMI_ITOF12(_VURegsNum *VUregsn) { _vuRegsITOF12(&VU0, VUregsn); } -void VU0regsMI_ITOF15(_VURegsNum *VUregsn) { _vuRegsITOF15(&VU0, VUregsn); } -void VU0regsMI_CLIP(_VURegsNum *VUregsn) { _vuRegsCLIP(&VU0, VUregsn); } - -/*****************************************/ -/* VU Micromode Lower instructions */ -/*****************************************/ - -void VU0regsMI_DIV(_VURegsNum *VUregsn) { _vuRegsDIV(&VU0, VUregsn); } -void VU0regsMI_SQRT(_VURegsNum *VUregsn) { _vuRegsSQRT(&VU0, VUregsn); } -void VU0regsMI_RSQRT(_VURegsNum *VUregsn) { _vuRegsRSQRT(&VU0, VUregsn); } -void VU0regsMI_IADD(_VURegsNum *VUregsn) { _vuRegsIADD(&VU0, VUregsn); } -void VU0regsMI_IADDI(_VURegsNum *VUregsn) { _vuRegsIADDI(&VU0, VUregsn); } -void VU0regsMI_IADDIU(_VURegsNum *VUregsn) { _vuRegsIADDIU(&VU0, VUregsn); } -void VU0regsMI_IAND(_VURegsNum *VUregsn) { _vuRegsIAND(&VU0, VUregsn); } -void VU0regsMI_IOR(_VURegsNum *VUregsn) { _vuRegsIOR(&VU0, VUregsn); } -void VU0regsMI_ISUB(_VURegsNum *VUregsn) { _vuRegsISUB(&VU0, VUregsn); } -void VU0regsMI_ISUBIU(_VURegsNum *VUregsn) { _vuRegsISUBIU(&VU0, VUregsn); } -void VU0regsMI_MOVE(_VURegsNum *VUregsn) { _vuRegsMOVE(&VU0, VUregsn); } -void VU0regsMI_MFIR(_VURegsNum *VUregsn) { _vuRegsMFIR(&VU0, VUregsn); } -void VU0regsMI_MTIR(_VURegsNum *VUregsn) { _vuRegsMTIR(&VU0, VUregsn); } -void VU0regsMI_MR32(_VURegsNum *VUregsn) { _vuRegsMR32(&VU0, VUregsn); } -void VU0regsMI_LQ(_VURegsNum *VUregsn) { _vuRegsLQ(&VU0, VUregsn); } -void VU0regsMI_LQD(_VURegsNum *VUregsn) { _vuRegsLQD(&VU0, VUregsn); } -void VU0regsMI_LQI(_VURegsNum *VUregsn) { _vuRegsLQI(&VU0, VUregsn); } -void VU0regsMI_SQ(_VURegsNum *VUregsn) { _vuRegsSQ(&VU0, VUregsn); } -void VU0regsMI_SQD(_VURegsNum *VUregsn) { _vuRegsSQD(&VU0, VUregsn); } -void VU0regsMI_SQI(_VURegsNum *VUregsn) { _vuRegsSQI(&VU0, VUregsn); } -void VU0regsMI_ILW(_VURegsNum *VUregsn) { _vuRegsILW(&VU0, VUregsn); } -void VU0regsMI_ISW(_VURegsNum *VUregsn) { _vuRegsISW(&VU0, VUregsn); } -void VU0regsMI_ILWR(_VURegsNum *VUregsn) { _vuRegsILWR(&VU0, VUregsn); } -void VU0regsMI_ISWR(_VURegsNum *VUregsn) { _vuRegsISWR(&VU0, VUregsn); } -void VU0regsMI_RINIT(_VURegsNum *VUregsn) { _vuRegsRINIT(&VU0, VUregsn); } -void VU0regsMI_RGET(_VURegsNum *VUregsn) { _vuRegsRGET(&VU0, VUregsn); } -void VU0regsMI_RNEXT(_VURegsNum *VUregsn) { _vuRegsRNEXT(&VU0, VUregsn); } -void VU0regsMI_RXOR(_VURegsNum *VUregsn) { _vuRegsRXOR(&VU0, VUregsn); } -void VU0regsMI_WAITQ(_VURegsNum *VUregsn) { _vuRegsWAITQ(&VU0, VUregsn); } -void VU0regsMI_FSAND(_VURegsNum *VUregsn) { _vuRegsFSAND(&VU0, VUregsn); } -void VU0regsMI_FSEQ(_VURegsNum *VUregsn) { _vuRegsFSEQ(&VU0, VUregsn); } -void VU0regsMI_FSOR(_VURegsNum *VUregsn) { _vuRegsFSOR(&VU0, VUregsn); } -void VU0regsMI_FSSET(_VURegsNum *VUregsn) { _vuRegsFSSET(&VU0, VUregsn); } -void VU0regsMI_FMAND(_VURegsNum *VUregsn) { _vuRegsFMAND(&VU0, VUregsn); } -void VU0regsMI_FMEQ(_VURegsNum *VUregsn) { _vuRegsFMEQ(&VU0, VUregsn); } -void VU0regsMI_FMOR(_VURegsNum *VUregsn) { _vuRegsFMOR(&VU0, VUregsn); } -void VU0regsMI_FCAND(_VURegsNum *VUregsn) { _vuRegsFCAND(&VU0, VUregsn); } -void VU0regsMI_FCEQ(_VURegsNum *VUregsn) { _vuRegsFCEQ(&VU0, VUregsn); } -void VU0regsMI_FCOR(_VURegsNum *VUregsn) { _vuRegsFCOR(&VU0, VUregsn); } -void VU0regsMI_FCSET(_VURegsNum *VUregsn) { _vuRegsFCSET(&VU0, VUregsn); } -void VU0regsMI_FCGET(_VURegsNum *VUregsn) { _vuRegsFCGET(&VU0, VUregsn); } -void VU0regsMI_IBEQ(_VURegsNum *VUregsn) { _vuRegsIBEQ(&VU0, VUregsn); } -void VU0regsMI_IBGEZ(_VURegsNum *VUregsn) { _vuRegsIBGEZ(&VU0, VUregsn); } -void VU0regsMI_IBGTZ(_VURegsNum *VUregsn) { _vuRegsIBGTZ(&VU0, VUregsn); } -void VU0regsMI_IBLTZ(_VURegsNum *VUregsn) { _vuRegsIBLTZ(&VU0, VUregsn); } -void VU0regsMI_IBLEZ(_VURegsNum *VUregsn) { _vuRegsIBLEZ(&VU0, VUregsn); } -void VU0regsMI_IBNE(_VURegsNum *VUregsn) { _vuRegsIBNE(&VU0, VUregsn); } -void VU0regsMI_B(_VURegsNum *VUregsn) { _vuRegsB(&VU0, VUregsn); } -void VU0regsMI_BAL(_VURegsNum *VUregsn) { _vuRegsBAL(&VU0, VUregsn); } -void VU0regsMI_JR(_VURegsNum *VUregsn) { _vuRegsJR(&VU0, VUregsn); } -void VU0regsMI_JALR(_VURegsNum *VUregsn) { _vuRegsJALR(&VU0, VUregsn); } -void VU0regsMI_MFP(_VURegsNum *VUregsn) { _vuRegsMFP(&VU0, VUregsn); } -void VU0regsMI_WAITP(_VURegsNum *VUregsn) { _vuRegsWAITP(&VU0, VUregsn); } -void VU0regsMI_ESADD(_VURegsNum *VUregsn) { _vuRegsESADD(&VU0, VUregsn); } -void VU0regsMI_ERSADD(_VURegsNum *VUregsn) { _vuRegsERSADD(&VU0, VUregsn); } -void VU0regsMI_ELENG(_VURegsNum *VUregsn) { _vuRegsELENG(&VU0, VUregsn); } -void VU0regsMI_ERLENG(_VURegsNum *VUregsn) { _vuRegsERLENG(&VU0, VUregsn); } -void VU0regsMI_EATANxy(_VURegsNum *VUregsn) { _vuRegsEATANxy(&VU0, VUregsn); } -void VU0regsMI_EATANxz(_VURegsNum *VUregsn) { _vuRegsEATANxz(&VU0, VUregsn); } -void VU0regsMI_ESUM(_VURegsNum *VUregsn) { _vuRegsESUM(&VU0, VUregsn); } -void VU0regsMI_ERCPR(_VURegsNum *VUregsn) { _vuRegsERCPR(&VU0, VUregsn); } -void VU0regsMI_ESQRT(_VURegsNum *VUregsn) { _vuRegsESQRT(&VU0, VUregsn); } -void VU0regsMI_ERSQRT(_VURegsNum *VUregsn) { _vuRegsERSQRT(&VU0, VUregsn); } -void VU0regsMI_ESIN(_VURegsNum *VUregsn) { _vuRegsESIN(&VU0, VUregsn); } -void VU0regsMI_EATAN(_VURegsNum *VUregsn) { _vuRegsEATAN(&VU0, VUregsn); } -void VU0regsMI_EEXP(_VURegsNum *VUregsn) { _vuRegsEEXP(&VU0, VUregsn); } -void VU0regsMI_XITOP(_VURegsNum *VUregsn) { _vuRegsXITOP(&VU0, VUregsn); } -void VU0regsMI_XGKICK(_VURegsNum *VUregsn) { _vuRegsXGKICK(&VU0, VUregsn); } -void VU0regsMI_XTOP(_VURegsNum *VUregsn) { _vuRegsXTOP(&VU0, VUregsn); } +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +// This module contains code shared by both the dynarec and interpreter versions +// of the VU0 micro. + + +#include "PrecompiledHeader.h" + +#include + +#include "Common.h" +#include "DebugTools/Debug.h" +#include "R5900.h" +#include "iR5900.h" +#include "VUmicro.h" +#include "VUflags.h" +#include "VUops.h" + +#include "iVUzerorec.h" + +using namespace R5900; + +#define VF_VAL(x) ((x==0x80000000)?0:(x)) + +void iDumpVU0Registers() +{ + // fixme: This code is outdated, broken, and lacks printed labels. + // Needs heavy mods to be useful. +#if 0 + int i; + + for(i = 1; i < 32; ++i) { + __Log("v%d: %x %x %x %x, vi: ", i, VF_VAL(VU0.VF[i].UL[3]), VF_VAL(VU0.VF[i].UL[2]), + VF_VAL(VU0.VF[i].UL[1]), VF_VAL(VU0.VF[i].UL[0])); + if( i == REG_Q || i == REG_P ) __Log("%f\n", VU0.VI[i].F); + else if( i == REG_MAC_FLAG ) __Log("%x\n", 0);//VU0.VI[i].UL&0xff); + else if( i == REG_STATUS_FLAG ) __Log("%x\n", 0);//VU0.VI[i].UL&0x03); + else if( i == REG_CLIP_FLAG ) __Log("0\n"); + else __Log("%x\n", VU0.VI[i].UL); + } + __Log("vfACC: %f %f %f %f\n", VU0.ACC.F[3], VU0.ACC.F[2], VU0.ACC.F[1], VU0.ACC.F[0]); +#endif +} + +// This is called by the COP2 as per the CTC instruction +void vu0ResetRegs() +{ + VU0.VI[REG_VPU_STAT].UL &= ~0xff; // stop vu0 + VU0.VI[REG_FBRST].UL &= ~0xff; // stop vu0 + vif0Regs->stat &= ~4; +} + +void VU0MI_XGKICK() { +} + +void VU0MI_XTOP() { +} + +void vu0ExecMicro(u32 addr) { + VUM_LOG("vu0ExecMicro %x\n", addr); + + if(VU0.VI[REG_VPU_STAT].UL & 0x1) { + DevCon::Notice("vu0ExecMicro > Stalling for previous microprogram to finish"); + vu0Finish(); + } + VU0.VI[REG_VPU_STAT].UL|= 0x1; + VU0.VI[REG_VPU_STAT].UL&= ~0xAE; + + if (addr != -1) VU0.VI[REG_TPC].UL = addr; + _vuExecMicroDebug(VU0); + CpuVU0.ExecuteBlock(); + + // If the VU0 program didn't finish then we'll want to finish it up + // pretty soon. This fixes vmhacks in some games (Naruto Ultimate Ninja 2) + if(VU0.VI[REG_VPU_STAT].UL & 0x1) + cpuSetNextBranchDelta( 192 ); // fixme : ideally this should be higher, like 512 or so. +} + +void VU0unknown() { + assert(0); + + CPU_LOG("Unknown VU micromode opcode called\n"); +} + +void VU0regsunknown(_VURegsNum *VUregsn) { + assert(0); + + CPU_LOG("Unknown VU micromode opcode called\n"); +} + +_vuRegsTables(VU0, VU0regs); + + +/****************************************/ +/* VU Micromode Upper instructions */ +/****************************************/ + +void VU0MI_ABS() { _vuABS(&VU0); } +void VU0MI_ADD() { _vuADD(&VU0); } +void VU0MI_ADDi() { _vuADDi(&VU0); } +void VU0MI_ADDq() { _vuADDq(&VU0); } +void VU0MI_ADDx() { _vuADDx(&VU0); } +void VU0MI_ADDy() { _vuADDy(&VU0); } +void VU0MI_ADDz() { _vuADDz(&VU0); } +void VU0MI_ADDw() { _vuADDw(&VU0); } +void VU0MI_ADDA() { _vuADDA(&VU0); } +void VU0MI_ADDAi() { _vuADDAi(&VU0); } +void VU0MI_ADDAq() { _vuADDAq(&VU0); } +void VU0MI_ADDAx() { _vuADDAx(&VU0); } +void VU0MI_ADDAy() { _vuADDAy(&VU0); } +void VU0MI_ADDAz() { _vuADDAz(&VU0); } +void VU0MI_ADDAw() { _vuADDAw(&VU0); } +void VU0MI_SUB() { _vuSUB(&VU0); } +void VU0MI_SUBi() { _vuSUBi(&VU0); } +void VU0MI_SUBq() { _vuSUBq(&VU0); } +void VU0MI_SUBx() { _vuSUBx(&VU0); } +void VU0MI_SUBy() { _vuSUBy(&VU0); } +void VU0MI_SUBz() { _vuSUBz(&VU0); } +void VU0MI_SUBw() { _vuSUBw(&VU0); } +void VU0MI_SUBA() { _vuSUBA(&VU0); } +void VU0MI_SUBAi() { _vuSUBAi(&VU0); } +void VU0MI_SUBAq() { _vuSUBAq(&VU0); } +void VU0MI_SUBAx() { _vuSUBAx(&VU0); } +void VU0MI_SUBAy() { _vuSUBAy(&VU0); } +void VU0MI_SUBAz() { _vuSUBAz(&VU0); } +void VU0MI_SUBAw() { _vuSUBAw(&VU0); } +void VU0MI_MUL() { _vuMUL(&VU0); } +void VU0MI_MULi() { _vuMULi(&VU0); } +void VU0MI_MULq() { _vuMULq(&VU0); } +void VU0MI_MULx() { _vuMULx(&VU0); } +void VU0MI_MULy() { _vuMULy(&VU0); } +void VU0MI_MULz() { _vuMULz(&VU0); } +void VU0MI_MULw() { _vuMULw(&VU0); } +void VU0MI_MULA() { _vuMULA(&VU0); } +void VU0MI_MULAi() { _vuMULAi(&VU0); } +void VU0MI_MULAq() { _vuMULAq(&VU0); } +void VU0MI_MULAx() { _vuMULAx(&VU0); } +void VU0MI_MULAy() { _vuMULAy(&VU0); } +void VU0MI_MULAz() { _vuMULAz(&VU0); } +void VU0MI_MULAw() { _vuMULAw(&VU0); } +void VU0MI_MADD() { _vuMADD(&VU0); } +void VU0MI_MADDi() { _vuMADDi(&VU0); } +void VU0MI_MADDq() { _vuMADDq(&VU0); } +void VU0MI_MADDx() { _vuMADDx(&VU0); } +void VU0MI_MADDy() { _vuMADDy(&VU0); } +void VU0MI_MADDz() { _vuMADDz(&VU0); } +void VU0MI_MADDw() { _vuMADDw(&VU0); } +void VU0MI_MADDA() { _vuMADDA(&VU0); } +void VU0MI_MADDAi() { _vuMADDAi(&VU0); } +void VU0MI_MADDAq() { _vuMADDAq(&VU0); } +void VU0MI_MADDAx() { _vuMADDAx(&VU0); } +void VU0MI_MADDAy() { _vuMADDAy(&VU0); } +void VU0MI_MADDAz() { _vuMADDAz(&VU0); } +void VU0MI_MADDAw() { _vuMADDAw(&VU0); } +void VU0MI_MSUB() { _vuMSUB(&VU0); } +void VU0MI_MSUBi() { _vuMSUBi(&VU0); } +void VU0MI_MSUBq() { _vuMSUBq(&VU0); } +void VU0MI_MSUBx() { _vuMSUBx(&VU0); } +void VU0MI_MSUBy() { _vuMSUBy(&VU0); } +void VU0MI_MSUBz() { _vuMSUBz(&VU0); } +void VU0MI_MSUBw() { _vuMSUBw(&VU0); } +void VU0MI_MSUBA() { _vuMSUBA(&VU0); } +void VU0MI_MSUBAi() { _vuMSUBAi(&VU0); } +void VU0MI_MSUBAq() { _vuMSUBAq(&VU0); } +void VU0MI_MSUBAx() { _vuMSUBAx(&VU0); } +void VU0MI_MSUBAy() { _vuMSUBAy(&VU0); } +void VU0MI_MSUBAz() { _vuMSUBAz(&VU0); } +void VU0MI_MSUBAw() { _vuMSUBAw(&VU0); } +void VU0MI_MAX() { _vuMAX(&VU0); } +void VU0MI_MAXi() { _vuMAXi(&VU0); } +void VU0MI_MAXx() { _vuMAXx(&VU0); } +void VU0MI_MAXy() { _vuMAXy(&VU0); } +void VU0MI_MAXz() { _vuMAXz(&VU0); } +void VU0MI_MAXw() { _vuMAXw(&VU0); } +void VU0MI_MINI() { _vuMINI(&VU0); } +void VU0MI_MINIi() { _vuMINIi(&VU0); } +void VU0MI_MINIx() { _vuMINIx(&VU0); } +void VU0MI_MINIy() { _vuMINIy(&VU0); } +void VU0MI_MINIz() { _vuMINIz(&VU0); } +void VU0MI_MINIw() { _vuMINIw(&VU0); } +void VU0MI_OPMULA() { _vuOPMULA(&VU0); } +void VU0MI_OPMSUB() { _vuOPMSUB(&VU0); } +void VU0MI_NOP() { _vuNOP(&VU0); } +void VU0MI_FTOI0() { _vuFTOI0(&VU0); } +void VU0MI_FTOI4() { _vuFTOI4(&VU0); } +void VU0MI_FTOI12() { _vuFTOI12(&VU0); } +void VU0MI_FTOI15() { _vuFTOI15(&VU0); } +void VU0MI_ITOF0() { _vuITOF0(&VU0); } +void VU0MI_ITOF4() { _vuITOF4(&VU0); } +void VU0MI_ITOF12() { _vuITOF12(&VU0); } +void VU0MI_ITOF15() { _vuITOF15(&VU0); } +void VU0MI_CLIP() { _vuCLIP(&VU0); } + +/*****************************************/ +/* VU Micromode Lower instructions */ +/*****************************************/ + +void VU0MI_DIV() { _vuDIV(&VU0); } +void VU0MI_SQRT() { _vuSQRT(&VU0); } +void VU0MI_RSQRT() { _vuRSQRT(&VU0); } +void VU0MI_IADD() { _vuIADD(&VU0); } +void VU0MI_IADDI() { _vuIADDI(&VU0); } +void VU0MI_IADDIU() { _vuIADDIU(&VU0); } +void VU0MI_IAND() { _vuIAND(&VU0); } +void VU0MI_IOR() { _vuIOR(&VU0); } +void VU0MI_ISUB() { _vuISUB(&VU0); } +void VU0MI_ISUBIU() { _vuISUBIU(&VU0); } +void VU0MI_MOVE() { _vuMOVE(&VU0); } +void VU0MI_MFIR() { _vuMFIR(&VU0); } +void VU0MI_MTIR() { _vuMTIR(&VU0); } +void VU0MI_MR32() { _vuMR32(&VU0); } +void VU0MI_LQ() { _vuLQ(&VU0); } +void VU0MI_LQD() { _vuLQD(&VU0); } +void VU0MI_LQI() { _vuLQI(&VU0); } +void VU0MI_SQ() { _vuSQ(&VU0); } +void VU0MI_SQD() { _vuSQD(&VU0); } +void VU0MI_SQI() { _vuSQI(&VU0); } +void VU0MI_ILW() { _vuILW(&VU0); } +void VU0MI_ISW() { _vuISW(&VU0); } +void VU0MI_ILWR() { _vuILWR(&VU0); } +void VU0MI_ISWR() { _vuISWR(&VU0); } +void VU0MI_RINIT() { _vuRINIT(&VU0); } +void VU0MI_RGET() { _vuRGET(&VU0); } +void VU0MI_RNEXT() { _vuRNEXT(&VU0); } +void VU0MI_RXOR() { _vuRXOR(&VU0); } +void VU0MI_WAITQ() { _vuWAITQ(&VU0); } +void VU0MI_FSAND() { _vuFSAND(&VU0); } +void VU0MI_FSEQ() { _vuFSEQ(&VU0); } +void VU0MI_FSOR() { _vuFSOR(&VU0); } +void VU0MI_FSSET() { _vuFSSET(&VU0); } +void VU0MI_FMAND() { _vuFMAND(&VU0); } +void VU0MI_FMEQ() { _vuFMEQ(&VU0); } +void VU0MI_FMOR() { _vuFMOR(&VU0); } +void VU0MI_FCAND() { _vuFCAND(&VU0); } +void VU0MI_FCEQ() { _vuFCEQ(&VU0); } +void VU0MI_FCOR() { _vuFCOR(&VU0); } +void VU0MI_FCSET() { _vuFCSET(&VU0); } +void VU0MI_FCGET() { _vuFCGET(&VU0); } +void VU0MI_IBEQ() { _vuIBEQ(&VU0); } +void VU0MI_IBGEZ() { _vuIBGEZ(&VU0); } +void VU0MI_IBGTZ() { _vuIBGTZ(&VU0); } +void VU0MI_IBLTZ() { _vuIBLTZ(&VU0); } +void VU0MI_IBLEZ() { _vuIBLEZ(&VU0); } +void VU0MI_IBNE() { _vuIBNE(&VU0); } +void VU0MI_B() { _vuB(&VU0); } +void VU0MI_BAL() { _vuBAL(&VU0); } +void VU0MI_JR() { _vuJR(&VU0); } +void VU0MI_JALR() { _vuJALR(&VU0); } +void VU0MI_MFP() { _vuMFP(&VU0); } +void VU0MI_WAITP() { _vuWAITP(&VU0); } +void VU0MI_ESADD() { _vuESADD(&VU0); } +void VU0MI_ERSADD() { _vuERSADD(&VU0); } +void VU0MI_ELENG() { _vuELENG(&VU0); } +void VU0MI_ERLENG() { _vuERLENG(&VU0); } +void VU0MI_EATANxy() { _vuEATANxy(&VU0); } +void VU0MI_EATANxz() { _vuEATANxz(&VU0); } +void VU0MI_ESUM() { _vuESUM(&VU0); } +void VU0MI_ERCPR() { _vuERCPR(&VU0); } +void VU0MI_ESQRT() { _vuESQRT(&VU0); } +void VU0MI_ERSQRT() { _vuERSQRT(&VU0); } +void VU0MI_ESIN() { _vuESIN(&VU0); } +void VU0MI_EATAN() { _vuEATAN(&VU0); } +void VU0MI_EEXP() { _vuEEXP(&VU0); } +void VU0MI_XITOP() { _vuXITOP(&VU0); } + +/****************************************/ +/* VU Micromode Upper instructions */ +/****************************************/ + +void VU0regsMI_ABS(_VURegsNum *VUregsn) { _vuRegsABS(&VU0, VUregsn); } +void VU0regsMI_ADD(_VURegsNum *VUregsn) { _vuRegsADD(&VU0, VUregsn); } +void VU0regsMI_ADDi(_VURegsNum *VUregsn) { _vuRegsADDi(&VU0, VUregsn); } +void VU0regsMI_ADDq(_VURegsNum *VUregsn) { _vuRegsADDq(&VU0, VUregsn); } +void VU0regsMI_ADDx(_VURegsNum *VUregsn) { _vuRegsADDx(&VU0, VUregsn); } +void VU0regsMI_ADDy(_VURegsNum *VUregsn) { _vuRegsADDy(&VU0, VUregsn); } +void VU0regsMI_ADDz(_VURegsNum *VUregsn) { _vuRegsADDz(&VU0, VUregsn); } +void VU0regsMI_ADDw(_VURegsNum *VUregsn) { _vuRegsADDw(&VU0, VUregsn); } +void VU0regsMI_ADDA(_VURegsNum *VUregsn) { _vuRegsADDA(&VU0, VUregsn); } +void VU0regsMI_ADDAi(_VURegsNum *VUregsn) { _vuRegsADDAi(&VU0, VUregsn); } +void VU0regsMI_ADDAq(_VURegsNum *VUregsn) { _vuRegsADDAq(&VU0, VUregsn); } +void VU0regsMI_ADDAx(_VURegsNum *VUregsn) { _vuRegsADDAx(&VU0, VUregsn); } +void VU0regsMI_ADDAy(_VURegsNum *VUregsn) { _vuRegsADDAy(&VU0, VUregsn); } +void VU0regsMI_ADDAz(_VURegsNum *VUregsn) { _vuRegsADDAz(&VU0, VUregsn); } +void VU0regsMI_ADDAw(_VURegsNum *VUregsn) { _vuRegsADDAw(&VU0, VUregsn); } +void VU0regsMI_SUB(_VURegsNum *VUregsn) { _vuRegsSUB(&VU0, VUregsn); } +void VU0regsMI_SUBi(_VURegsNum *VUregsn) { _vuRegsSUBi(&VU0, VUregsn); } +void VU0regsMI_SUBq(_VURegsNum *VUregsn) { _vuRegsSUBq(&VU0, VUregsn); } +void VU0regsMI_SUBx(_VURegsNum *VUregsn) { _vuRegsSUBx(&VU0, VUregsn); } +void VU0regsMI_SUBy(_VURegsNum *VUregsn) { _vuRegsSUBy(&VU0, VUregsn); } +void VU0regsMI_SUBz(_VURegsNum *VUregsn) { _vuRegsSUBz(&VU0, VUregsn); } +void VU0regsMI_SUBw(_VURegsNum *VUregsn) { _vuRegsSUBw(&VU0, VUregsn); } +void VU0regsMI_SUBA(_VURegsNum *VUregsn) { _vuRegsSUBA(&VU0, VUregsn); } +void VU0regsMI_SUBAi(_VURegsNum *VUregsn) { _vuRegsSUBAi(&VU0, VUregsn); } +void VU0regsMI_SUBAq(_VURegsNum *VUregsn) { _vuRegsSUBAq(&VU0, VUregsn); } +void VU0regsMI_SUBAx(_VURegsNum *VUregsn) { _vuRegsSUBAx(&VU0, VUregsn); } +void VU0regsMI_SUBAy(_VURegsNum *VUregsn) { _vuRegsSUBAy(&VU0, VUregsn); } +void VU0regsMI_SUBAz(_VURegsNum *VUregsn) { _vuRegsSUBAz(&VU0, VUregsn); } +void VU0regsMI_SUBAw(_VURegsNum *VUregsn) { _vuRegsSUBAw(&VU0, VUregsn); } +void VU0regsMI_MUL(_VURegsNum *VUregsn) { _vuRegsMUL(&VU0, VUregsn); } +void VU0regsMI_MULi(_VURegsNum *VUregsn) { _vuRegsMULi(&VU0, VUregsn); } +void VU0regsMI_MULq(_VURegsNum *VUregsn) { _vuRegsMULq(&VU0, VUregsn); } +void VU0regsMI_MULx(_VURegsNum *VUregsn) { _vuRegsMULx(&VU0, VUregsn); } +void VU0regsMI_MULy(_VURegsNum *VUregsn) { _vuRegsMULy(&VU0, VUregsn); } +void VU0regsMI_MULz(_VURegsNum *VUregsn) { _vuRegsMULz(&VU0, VUregsn); } +void VU0regsMI_MULw(_VURegsNum *VUregsn) { _vuRegsMULw(&VU0, VUregsn); } +void VU0regsMI_MULA(_VURegsNum *VUregsn) { _vuRegsMULA(&VU0, VUregsn); } +void VU0regsMI_MULAi(_VURegsNum *VUregsn) { _vuRegsMULAi(&VU0, VUregsn); } +void VU0regsMI_MULAq(_VURegsNum *VUregsn) { _vuRegsMULAq(&VU0, VUregsn); } +void VU0regsMI_MULAx(_VURegsNum *VUregsn) { _vuRegsMULAx(&VU0, VUregsn); } +void VU0regsMI_MULAy(_VURegsNum *VUregsn) { _vuRegsMULAy(&VU0, VUregsn); } +void VU0regsMI_MULAz(_VURegsNum *VUregsn) { _vuRegsMULAz(&VU0, VUregsn); } +void VU0regsMI_MULAw(_VURegsNum *VUregsn) { _vuRegsMULAw(&VU0, VUregsn); } +void VU0regsMI_MADD(_VURegsNum *VUregsn) { _vuRegsMADD(&VU0, VUregsn); } +void VU0regsMI_MADDi(_VURegsNum *VUregsn) { _vuRegsMADDi(&VU0, VUregsn); } +void VU0regsMI_MADDq(_VURegsNum *VUregsn) { _vuRegsMADDq(&VU0, VUregsn); } +void VU0regsMI_MADDx(_VURegsNum *VUregsn) { _vuRegsMADDx(&VU0, VUregsn); } +void VU0regsMI_MADDy(_VURegsNum *VUregsn) { _vuRegsMADDy(&VU0, VUregsn); } +void VU0regsMI_MADDz(_VURegsNum *VUregsn) { _vuRegsMADDz(&VU0, VUregsn); } +void VU0regsMI_MADDw(_VURegsNum *VUregsn) { _vuRegsMADDw(&VU0, VUregsn); } +void VU0regsMI_MADDA(_VURegsNum *VUregsn) { _vuRegsMADDA(&VU0, VUregsn); } +void VU0regsMI_MADDAi(_VURegsNum *VUregsn) { _vuRegsMADDAi(&VU0, VUregsn); } +void VU0regsMI_MADDAq(_VURegsNum *VUregsn) { _vuRegsMADDAq(&VU0, VUregsn); } +void VU0regsMI_MADDAx(_VURegsNum *VUregsn) { _vuRegsMADDAx(&VU0, VUregsn); } +void VU0regsMI_MADDAy(_VURegsNum *VUregsn) { _vuRegsMADDAy(&VU0, VUregsn); } +void VU0regsMI_MADDAz(_VURegsNum *VUregsn) { _vuRegsMADDAz(&VU0, VUregsn); } +void VU0regsMI_MADDAw(_VURegsNum *VUregsn) { _vuRegsMADDAw(&VU0, VUregsn); } +void VU0regsMI_MSUB(_VURegsNum *VUregsn) { _vuRegsMSUB(&VU0, VUregsn); } +void VU0regsMI_MSUBi(_VURegsNum *VUregsn) { _vuRegsMSUBi(&VU0, VUregsn); } +void VU0regsMI_MSUBq(_VURegsNum *VUregsn) { _vuRegsMSUBq(&VU0, VUregsn); } +void VU0regsMI_MSUBx(_VURegsNum *VUregsn) { _vuRegsMSUBx(&VU0, VUregsn); } +void VU0regsMI_MSUBy(_VURegsNum *VUregsn) { _vuRegsMSUBy(&VU0, VUregsn); } +void VU0regsMI_MSUBz(_VURegsNum *VUregsn) { _vuRegsMSUBz(&VU0, VUregsn); } +void VU0regsMI_MSUBw(_VURegsNum *VUregsn) { _vuRegsMSUBw(&VU0, VUregsn); } +void VU0regsMI_MSUBA(_VURegsNum *VUregsn) { _vuRegsMSUBA(&VU0, VUregsn); } +void VU0regsMI_MSUBAi(_VURegsNum *VUregsn) { _vuRegsMSUBAi(&VU0, VUregsn); } +void VU0regsMI_MSUBAq(_VURegsNum *VUregsn) { _vuRegsMSUBAq(&VU0, VUregsn); } +void VU0regsMI_MSUBAx(_VURegsNum *VUregsn) { _vuRegsMSUBAx(&VU0, VUregsn); } +void VU0regsMI_MSUBAy(_VURegsNum *VUregsn) { _vuRegsMSUBAy(&VU0, VUregsn); } +void VU0regsMI_MSUBAz(_VURegsNum *VUregsn) { _vuRegsMSUBAz(&VU0, VUregsn); } +void VU0regsMI_MSUBAw(_VURegsNum *VUregsn) { _vuRegsMSUBAw(&VU0, VUregsn); } +void VU0regsMI_MAX(_VURegsNum *VUregsn) { _vuRegsMAX(&VU0, VUregsn); } +void VU0regsMI_MAXi(_VURegsNum *VUregsn) { _vuRegsMAXi(&VU0, VUregsn); } +void VU0regsMI_MAXx(_VURegsNum *VUregsn) { _vuRegsMAXx(&VU0, VUregsn); } +void VU0regsMI_MAXy(_VURegsNum *VUregsn) { _vuRegsMAXy(&VU0, VUregsn); } +void VU0regsMI_MAXz(_VURegsNum *VUregsn) { _vuRegsMAXz(&VU0, VUregsn); } +void VU0regsMI_MAXw(_VURegsNum *VUregsn) { _vuRegsMAXw(&VU0, VUregsn); } +void VU0regsMI_MINI(_VURegsNum *VUregsn) { _vuRegsMINI(&VU0, VUregsn); } +void VU0regsMI_MINIi(_VURegsNum *VUregsn) { _vuRegsMINIi(&VU0, VUregsn); } +void VU0regsMI_MINIx(_VURegsNum *VUregsn) { _vuRegsMINIx(&VU0, VUregsn); } +void VU0regsMI_MINIy(_VURegsNum *VUregsn) { _vuRegsMINIy(&VU0, VUregsn); } +void VU0regsMI_MINIz(_VURegsNum *VUregsn) { _vuRegsMINIz(&VU0, VUregsn); } +void VU0regsMI_MINIw(_VURegsNum *VUregsn) { _vuRegsMINIw(&VU0, VUregsn); } +void VU0regsMI_OPMULA(_VURegsNum *VUregsn) { _vuRegsOPMULA(&VU0, VUregsn); } +void VU0regsMI_OPMSUB(_VURegsNum *VUregsn) { _vuRegsOPMSUB(&VU0, VUregsn); } +void VU0regsMI_NOP(_VURegsNum *VUregsn) { _vuRegsNOP(&VU0, VUregsn); } +void VU0regsMI_FTOI0(_VURegsNum *VUregsn) { _vuRegsFTOI0(&VU0, VUregsn); } +void VU0regsMI_FTOI4(_VURegsNum *VUregsn) { _vuRegsFTOI4(&VU0, VUregsn); } +void VU0regsMI_FTOI12(_VURegsNum *VUregsn) { _vuRegsFTOI12(&VU0, VUregsn); } +void VU0regsMI_FTOI15(_VURegsNum *VUregsn) { _vuRegsFTOI15(&VU0, VUregsn); } +void VU0regsMI_ITOF0(_VURegsNum *VUregsn) { _vuRegsITOF0(&VU0, VUregsn); } +void VU0regsMI_ITOF4(_VURegsNum *VUregsn) { _vuRegsITOF4(&VU0, VUregsn); } +void VU0regsMI_ITOF12(_VURegsNum *VUregsn) { _vuRegsITOF12(&VU0, VUregsn); } +void VU0regsMI_ITOF15(_VURegsNum *VUregsn) { _vuRegsITOF15(&VU0, VUregsn); } +void VU0regsMI_CLIP(_VURegsNum *VUregsn) { _vuRegsCLIP(&VU0, VUregsn); } + +/*****************************************/ +/* VU Micromode Lower instructions */ +/*****************************************/ + +void VU0regsMI_DIV(_VURegsNum *VUregsn) { _vuRegsDIV(&VU0, VUregsn); } +void VU0regsMI_SQRT(_VURegsNum *VUregsn) { _vuRegsSQRT(&VU0, VUregsn); } +void VU0regsMI_RSQRT(_VURegsNum *VUregsn) { _vuRegsRSQRT(&VU0, VUregsn); } +void VU0regsMI_IADD(_VURegsNum *VUregsn) { _vuRegsIADD(&VU0, VUregsn); } +void VU0regsMI_IADDI(_VURegsNum *VUregsn) { _vuRegsIADDI(&VU0, VUregsn); } +void VU0regsMI_IADDIU(_VURegsNum *VUregsn) { _vuRegsIADDIU(&VU0, VUregsn); } +void VU0regsMI_IAND(_VURegsNum *VUregsn) { _vuRegsIAND(&VU0, VUregsn); } +void VU0regsMI_IOR(_VURegsNum *VUregsn) { _vuRegsIOR(&VU0, VUregsn); } +void VU0regsMI_ISUB(_VURegsNum *VUregsn) { _vuRegsISUB(&VU0, VUregsn); } +void VU0regsMI_ISUBIU(_VURegsNum *VUregsn) { _vuRegsISUBIU(&VU0, VUregsn); } +void VU0regsMI_MOVE(_VURegsNum *VUregsn) { _vuRegsMOVE(&VU0, VUregsn); } +void VU0regsMI_MFIR(_VURegsNum *VUregsn) { _vuRegsMFIR(&VU0, VUregsn); } +void VU0regsMI_MTIR(_VURegsNum *VUregsn) { _vuRegsMTIR(&VU0, VUregsn); } +void VU0regsMI_MR32(_VURegsNum *VUregsn) { _vuRegsMR32(&VU0, VUregsn); } +void VU0regsMI_LQ(_VURegsNum *VUregsn) { _vuRegsLQ(&VU0, VUregsn); } +void VU0regsMI_LQD(_VURegsNum *VUregsn) { _vuRegsLQD(&VU0, VUregsn); } +void VU0regsMI_LQI(_VURegsNum *VUregsn) { _vuRegsLQI(&VU0, VUregsn); } +void VU0regsMI_SQ(_VURegsNum *VUregsn) { _vuRegsSQ(&VU0, VUregsn); } +void VU0regsMI_SQD(_VURegsNum *VUregsn) { _vuRegsSQD(&VU0, VUregsn); } +void VU0regsMI_SQI(_VURegsNum *VUregsn) { _vuRegsSQI(&VU0, VUregsn); } +void VU0regsMI_ILW(_VURegsNum *VUregsn) { _vuRegsILW(&VU0, VUregsn); } +void VU0regsMI_ISW(_VURegsNum *VUregsn) { _vuRegsISW(&VU0, VUregsn); } +void VU0regsMI_ILWR(_VURegsNum *VUregsn) { _vuRegsILWR(&VU0, VUregsn); } +void VU0regsMI_ISWR(_VURegsNum *VUregsn) { _vuRegsISWR(&VU0, VUregsn); } +void VU0regsMI_RINIT(_VURegsNum *VUregsn) { _vuRegsRINIT(&VU0, VUregsn); } +void VU0regsMI_RGET(_VURegsNum *VUregsn) { _vuRegsRGET(&VU0, VUregsn); } +void VU0regsMI_RNEXT(_VURegsNum *VUregsn) { _vuRegsRNEXT(&VU0, VUregsn); } +void VU0regsMI_RXOR(_VURegsNum *VUregsn) { _vuRegsRXOR(&VU0, VUregsn); } +void VU0regsMI_WAITQ(_VURegsNum *VUregsn) { _vuRegsWAITQ(&VU0, VUregsn); } +void VU0regsMI_FSAND(_VURegsNum *VUregsn) { _vuRegsFSAND(&VU0, VUregsn); } +void VU0regsMI_FSEQ(_VURegsNum *VUregsn) { _vuRegsFSEQ(&VU0, VUregsn); } +void VU0regsMI_FSOR(_VURegsNum *VUregsn) { _vuRegsFSOR(&VU0, VUregsn); } +void VU0regsMI_FSSET(_VURegsNum *VUregsn) { _vuRegsFSSET(&VU0, VUregsn); } +void VU0regsMI_FMAND(_VURegsNum *VUregsn) { _vuRegsFMAND(&VU0, VUregsn); } +void VU0regsMI_FMEQ(_VURegsNum *VUregsn) { _vuRegsFMEQ(&VU0, VUregsn); } +void VU0regsMI_FMOR(_VURegsNum *VUregsn) { _vuRegsFMOR(&VU0, VUregsn); } +void VU0regsMI_FCAND(_VURegsNum *VUregsn) { _vuRegsFCAND(&VU0, VUregsn); } +void VU0regsMI_FCEQ(_VURegsNum *VUregsn) { _vuRegsFCEQ(&VU0, VUregsn); } +void VU0regsMI_FCOR(_VURegsNum *VUregsn) { _vuRegsFCOR(&VU0, VUregsn); } +void VU0regsMI_FCSET(_VURegsNum *VUregsn) { _vuRegsFCSET(&VU0, VUregsn); } +void VU0regsMI_FCGET(_VURegsNum *VUregsn) { _vuRegsFCGET(&VU0, VUregsn); } +void VU0regsMI_IBEQ(_VURegsNum *VUregsn) { _vuRegsIBEQ(&VU0, VUregsn); } +void VU0regsMI_IBGEZ(_VURegsNum *VUregsn) { _vuRegsIBGEZ(&VU0, VUregsn); } +void VU0regsMI_IBGTZ(_VURegsNum *VUregsn) { _vuRegsIBGTZ(&VU0, VUregsn); } +void VU0regsMI_IBLTZ(_VURegsNum *VUregsn) { _vuRegsIBLTZ(&VU0, VUregsn); } +void VU0regsMI_IBLEZ(_VURegsNum *VUregsn) { _vuRegsIBLEZ(&VU0, VUregsn); } +void VU0regsMI_IBNE(_VURegsNum *VUregsn) { _vuRegsIBNE(&VU0, VUregsn); } +void VU0regsMI_B(_VURegsNum *VUregsn) { _vuRegsB(&VU0, VUregsn); } +void VU0regsMI_BAL(_VURegsNum *VUregsn) { _vuRegsBAL(&VU0, VUregsn); } +void VU0regsMI_JR(_VURegsNum *VUregsn) { _vuRegsJR(&VU0, VUregsn); } +void VU0regsMI_JALR(_VURegsNum *VUregsn) { _vuRegsJALR(&VU0, VUregsn); } +void VU0regsMI_MFP(_VURegsNum *VUregsn) { _vuRegsMFP(&VU0, VUregsn); } +void VU0regsMI_WAITP(_VURegsNum *VUregsn) { _vuRegsWAITP(&VU0, VUregsn); } +void VU0regsMI_ESADD(_VURegsNum *VUregsn) { _vuRegsESADD(&VU0, VUregsn); } +void VU0regsMI_ERSADD(_VURegsNum *VUregsn) { _vuRegsERSADD(&VU0, VUregsn); } +void VU0regsMI_ELENG(_VURegsNum *VUregsn) { _vuRegsELENG(&VU0, VUregsn); } +void VU0regsMI_ERLENG(_VURegsNum *VUregsn) { _vuRegsERLENG(&VU0, VUregsn); } +void VU0regsMI_EATANxy(_VURegsNum *VUregsn) { _vuRegsEATANxy(&VU0, VUregsn); } +void VU0regsMI_EATANxz(_VURegsNum *VUregsn) { _vuRegsEATANxz(&VU0, VUregsn); } +void VU0regsMI_ESUM(_VURegsNum *VUregsn) { _vuRegsESUM(&VU0, VUregsn); } +void VU0regsMI_ERCPR(_VURegsNum *VUregsn) { _vuRegsERCPR(&VU0, VUregsn); } +void VU0regsMI_ESQRT(_VURegsNum *VUregsn) { _vuRegsESQRT(&VU0, VUregsn); } +void VU0regsMI_ERSQRT(_VURegsNum *VUregsn) { _vuRegsERSQRT(&VU0, VUregsn); } +void VU0regsMI_ESIN(_VURegsNum *VUregsn) { _vuRegsESIN(&VU0, VUregsn); } +void VU0regsMI_EATAN(_VURegsNum *VUregsn) { _vuRegsEATAN(&VU0, VUregsn); } +void VU0regsMI_EEXP(_VURegsNum *VUregsn) { _vuRegsEEXP(&VU0, VUregsn); } +void VU0regsMI_XITOP(_VURegsNum *VUregsn) { _vuRegsXITOP(&VU0, VUregsn); } +void VU0regsMI_XGKICK(_VURegsNum *VUregsn) { _vuRegsXGKICK(&VU0, VUregsn); } +void VU0regsMI_XTOP(_VURegsNum *VUregsn) { _vuRegsXTOP(&VU0, VUregsn); } diff --git a/pcsx2/VU0microInterp.cpp b/pcsx2/VU0microInterp.cpp index bee2122011..e940d754ee 100644 --- a/pcsx2/VU0microInterp.cpp +++ b/pcsx2/VU0microInterp.cpp @@ -1,253 +1,253 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "DebugTools/Debug.h" -#include "VUmicro.h" - -extern void _vuFlushAll(VURegs* VU); - -_vuTables(VU0, VU0); - -void _vu0ExecUpper(VURegs* VU, u32 *ptr) { - VU->code = ptr[1]; - IdebugUPPER(VU0); - VU0_UPPER_OPCODE[VU->code & 0x3f](); -} - -void _vu0ExecLower(VURegs* VU, u32 *ptr) { - VU->code = ptr[0]; - IdebugLOWER(VU0); - VU0_LOWER_OPCODE[VU->code >> 25](); -} - -int vu0branch = 0; -static void _vu0Exec(VURegs* VU) -{ - _VURegsNum lregs; - _VURegsNum uregs; - VECTOR _VF; - VECTOR _VFc; - REG_VI _VI; - REG_VI _VIc; - u32 *ptr; - int vfreg; - int vireg; - int discard=0; - - if(VU0.VI[REG_TPC].UL >= VU0.maxmicro){ -#ifdef CPU_LOG - SysPrintf("VU0 memory overflow!!: %x\n", VU->VI[REG_TPC].UL); -#endif - VU0.VI[REG_VPU_STAT].UL&= ~0x1; - VU->cycle++; - return; - } - - ptr = (u32*)&VU->Micro[VU->VI[REG_TPC].UL]; - VU->VI[REG_TPC].UL+=8; - - if (ptr[1] & 0x40000000) { - VU->ebit = 2; - } - if (ptr[1] & 0x20000000) { /* M flag */ - VU->flags|= VUFLAG_MFLAGSET; -// SysPrintf("fixme: M flag set\n"); - } - if (ptr[1] & 0x10000000) { /* D flag */ - if (VU0.VI[REG_FBRST].UL & 0x4) { - VU0.VI[REG_VPU_STAT].UL|= 0x2; - hwIntcIrq(INTC_VU0); - } - } - if (ptr[1] & 0x08000000) { /* T flag */ - if (VU0.VI[REG_FBRST].UL & 0x8) { - VU0.VI[REG_VPU_STAT].UL|= 0x4; - hwIntcIrq(INTC_VU0); - } - } - - VU->code = ptr[1]; - VU0regs_UPPER_OPCODE[VU->code & 0x3f](&uregs); -#ifndef INT_VUSTALLHACK - _vuTestUpperStalls(VU, &uregs); -#endif - - /* check upper flags */ - if (ptr[1] & 0x80000000) { /* I flag */ - _vu0ExecUpper(VU, ptr); - - VU->VI[REG_I].UL = ptr[0]; - memset(&lregs, 0, sizeof(lregs)); - } else { - VU->code = ptr[0]; - VU0regs_LOWER_OPCODE[VU->code >> 25](&lregs); -#ifndef INT_VUSTALLHACK - _vuTestLowerStalls(VU, &lregs); -#endif - - vu0branch = lregs.pipe == VUPIPE_BRANCH; - - vfreg = 0; vireg = 0; - if (uregs.VFwrite) { - if (lregs.VFwrite == uregs.VFwrite) { -// SysPrintf("*PCSX2*: Warning, VF write to the same reg in both lower/upper cycle\n"); - discard = 1; - } - if (lregs.VFread0 == uregs.VFwrite || - lregs.VFread1 == uregs.VFwrite) { -// SysPrintf("saving reg %d at pc=%x\n", i, VU->VI[REG_TPC].UL); - _VF = VU->VF[uregs.VFwrite]; - vfreg = uregs.VFwrite; - } - } - if (uregs.VIread & (1 << REG_CLIP_FLAG)) { - if (lregs.VIwrite & (1 << REG_CLIP_FLAG)) { - SysPrintf("*PCSX2*: Warning, VI write to the same reg in both lower/upper cycle\n"); - discard = 1; - } - if (lregs.VIread & (1 << REG_CLIP_FLAG)) { - _VI = VU0.VI[REG_CLIP_FLAG]; - vireg = REG_CLIP_FLAG; - } - } - - _vu0ExecUpper(VU, ptr); - - if (discard == 0) { - if (vfreg) { - _VFc = VU->VF[vfreg]; - VU->VF[vfreg] = _VF; - } - if (vireg) { - _VIc = VU->VI[vireg]; - VU->VI[vireg] = _VI; - } - - _vu0ExecLower(VU, ptr); - - if (vfreg) { - VU->VF[vfreg] = _VFc; - } - if (vireg) { - VU->VI[vireg] = _VIc; - } - } - } - _vuAddUpperStalls(VU, &uregs); - - if (!(ptr[1] & 0x80000000)) - _vuAddLowerStalls(VU, &lregs); - - _vuTestPipes(VU); - - if (VU->branch > 0) { - VU->branch--; - if (VU->branch == 0) { - VU->VI[REG_TPC].UL = VU->branchpc; - } - } - - if( VU->ebit > 0 ) { - if( VU->ebit-- == 1 ) { - _vuFlushAll(VU); - VU0.VI[REG_VPU_STAT].UL&= ~0x1; /* E flag */ - vif0Regs->stat&= ~0x4; - } - } -} - -void vu0Exec(VURegs* VU) -{ - if (VU->VI[REG_TPC].UL >= VU->maxmicro) { -#ifdef CPU_LOG - SysPrintf("VU0 memory overflow!!: %x\n", VU->VI[REG_TPC].UL); -#endif - VU0.VI[REG_VPU_STAT].UL&= ~0x1; - } else { - _vu0Exec(VU); - } - VU->cycle++; - - if (VU->VI[0].UL != 0) DbgCon::Error("VI[0] != 0!!!!\n"); - if (VU->VF[0].f.x != 0.0f) DbgCon::Error("VF[0].x != 0.0!!!!\n"); - if (VU->VF[0].f.y != 0.0f) DbgCon::Error("VF[0].y != 0.0!!!!\n"); - if (VU->VF[0].f.z != 0.0f) DbgCon::Error("VF[0].z != 0.0!!!!\n"); - if (VU->VF[0].f.w != 1.0f) DbgCon::Error("VF[0].w != 1.0!!!!\n"); -} - -namespace VU0micro -{ - void intAlloc() - { - } - - void intShutdown() - { - } - - void __fastcall intClear(u32 Addr, u32 Size) - { - } - - static void intReset() - { - } - - static void intStep() - { - vu0Exec( &VU0 ); - } - - static void intExecuteBlock() - { - int i; - - #ifdef _DEBUG - int prevbranch; - #endif - - for (i = 128; i--;) { - - if ((VU0.VI[REG_VPU_STAT].UL & 0x1) == 0) - break; - - #ifdef _DEBUG - prevbranch = vu0branch; - #endif - vu0Exec(&VU0); - } - - if( i < 0 && (VU0.branch || VU0.ebit) ) { - // execute one more - vu0Exec(&VU0); - } - } -} - -using namespace VU0micro; - -const VUmicroCpu intVU0 = -{ - intReset -, intStep -, intExecuteBlock -, intClear -}; +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "DebugTools/Debug.h" +#include "VUmicro.h" + +extern void _vuFlushAll(VURegs* VU); + +_vuTables(VU0, VU0); + +void _vu0ExecUpper(VURegs* VU, u32 *ptr) { + VU->code = ptr[1]; + IdebugUPPER(VU0); + VU0_UPPER_OPCODE[VU->code & 0x3f](); +} + +void _vu0ExecLower(VURegs* VU, u32 *ptr) { + VU->code = ptr[0]; + IdebugLOWER(VU0); + VU0_LOWER_OPCODE[VU->code >> 25](); +} + +int vu0branch = 0; +static void _vu0Exec(VURegs* VU) +{ + _VURegsNum lregs; + _VURegsNum uregs; + VECTOR _VF; + VECTOR _VFc; + REG_VI _VI; + REG_VI _VIc; + u32 *ptr; + int vfreg; + int vireg; + int discard=0; + + if(VU0.VI[REG_TPC].UL >= VU0.maxmicro){ +#ifdef CPU_LOG + SysPrintf("VU0 memory overflow!!: %x\n", VU->VI[REG_TPC].UL); +#endif + VU0.VI[REG_VPU_STAT].UL&= ~0x1; + VU->cycle++; + return; + } + + ptr = (u32*)&VU->Micro[VU->VI[REG_TPC].UL]; + VU->VI[REG_TPC].UL+=8; + + if (ptr[1] & 0x40000000) { + VU->ebit = 2; + } + if (ptr[1] & 0x20000000) { /* M flag */ + VU->flags|= VUFLAG_MFLAGSET; +// SysPrintf("fixme: M flag set\n"); + } + if (ptr[1] & 0x10000000) { /* D flag */ + if (VU0.VI[REG_FBRST].UL & 0x4) { + VU0.VI[REG_VPU_STAT].UL|= 0x2; + hwIntcIrq(INTC_VU0); + } + } + if (ptr[1] & 0x08000000) { /* T flag */ + if (VU0.VI[REG_FBRST].UL & 0x8) { + VU0.VI[REG_VPU_STAT].UL|= 0x4; + hwIntcIrq(INTC_VU0); + } + } + + VU->code = ptr[1]; + VU0regs_UPPER_OPCODE[VU->code & 0x3f](&uregs); +#ifndef INT_VUSTALLHACK + _vuTestUpperStalls(VU, &uregs); +#endif + + /* check upper flags */ + if (ptr[1] & 0x80000000) { /* I flag */ + _vu0ExecUpper(VU, ptr); + + VU->VI[REG_I].UL = ptr[0]; + memset(&lregs, 0, sizeof(lregs)); + } else { + VU->code = ptr[0]; + VU0regs_LOWER_OPCODE[VU->code >> 25](&lregs); +#ifndef INT_VUSTALLHACK + _vuTestLowerStalls(VU, &lregs); +#endif + + vu0branch = lregs.pipe == VUPIPE_BRANCH; + + vfreg = 0; vireg = 0; + if (uregs.VFwrite) { + if (lregs.VFwrite == uregs.VFwrite) { +// SysPrintf("*PCSX2*: Warning, VF write to the same reg in both lower/upper cycle\n"); + discard = 1; + } + if (lregs.VFread0 == uregs.VFwrite || + lregs.VFread1 == uregs.VFwrite) { +// SysPrintf("saving reg %d at pc=%x\n", i, VU->VI[REG_TPC].UL); + _VF = VU->VF[uregs.VFwrite]; + vfreg = uregs.VFwrite; + } + } + if (uregs.VIread & (1 << REG_CLIP_FLAG)) { + if (lregs.VIwrite & (1 << REG_CLIP_FLAG)) { + SysPrintf("*PCSX2*: Warning, VI write to the same reg in both lower/upper cycle\n"); + discard = 1; + } + if (lregs.VIread & (1 << REG_CLIP_FLAG)) { + _VI = VU0.VI[REG_CLIP_FLAG]; + vireg = REG_CLIP_FLAG; + } + } + + _vu0ExecUpper(VU, ptr); + + if (discard == 0) { + if (vfreg) { + _VFc = VU->VF[vfreg]; + VU->VF[vfreg] = _VF; + } + if (vireg) { + _VIc = VU->VI[vireg]; + VU->VI[vireg] = _VI; + } + + _vu0ExecLower(VU, ptr); + + if (vfreg) { + VU->VF[vfreg] = _VFc; + } + if (vireg) { + VU->VI[vireg] = _VIc; + } + } + } + _vuAddUpperStalls(VU, &uregs); + + if (!(ptr[1] & 0x80000000)) + _vuAddLowerStalls(VU, &lregs); + + _vuTestPipes(VU); + + if (VU->branch > 0) { + VU->branch--; + if (VU->branch == 0) { + VU->VI[REG_TPC].UL = VU->branchpc; + } + } + + if( VU->ebit > 0 ) { + if( VU->ebit-- == 1 ) { + _vuFlushAll(VU); + VU0.VI[REG_VPU_STAT].UL&= ~0x1; /* E flag */ + vif0Regs->stat&= ~0x4; + } + } +} + +void vu0Exec(VURegs* VU) +{ + if (VU->VI[REG_TPC].UL >= VU->maxmicro) { +#ifdef CPU_LOG + SysPrintf("VU0 memory overflow!!: %x\n", VU->VI[REG_TPC].UL); +#endif + VU0.VI[REG_VPU_STAT].UL&= ~0x1; + } else { + _vu0Exec(VU); + } + VU->cycle++; + + if (VU->VI[0].UL != 0) DbgCon::Error("VI[0] != 0!!!!\n"); + if (VU->VF[0].f.x != 0.0f) DbgCon::Error("VF[0].x != 0.0!!!!\n"); + if (VU->VF[0].f.y != 0.0f) DbgCon::Error("VF[0].y != 0.0!!!!\n"); + if (VU->VF[0].f.z != 0.0f) DbgCon::Error("VF[0].z != 0.0!!!!\n"); + if (VU->VF[0].f.w != 1.0f) DbgCon::Error("VF[0].w != 1.0!!!!\n"); +} + +namespace VU0micro +{ + void intAlloc() + { + } + + void intShutdown() + { + } + + void __fastcall intClear(u32 Addr, u32 Size) + { + } + + static void intReset() + { + } + + static void intStep() + { + vu0Exec( &VU0 ); + } + + static void intExecuteBlock() + { + int i; + + #ifdef _DEBUG + int prevbranch; + #endif + + for (i = 128; i--;) { + + if ((VU0.VI[REG_VPU_STAT].UL & 0x1) == 0) + break; + + #ifdef _DEBUG + prevbranch = vu0branch; + #endif + vu0Exec(&VU0); + } + + if( i < 0 && (VU0.branch || VU0.ebit) ) { + // execute one more + vu0Exec(&VU0); + } + } +} + +using namespace VU0micro; + +const VUmicroCpu intVU0 = +{ + intReset +, intStep +, intExecuteBlock +, intClear +}; diff --git a/pcsx2/VU1micro.cpp b/pcsx2/VU1micro.cpp index 54fdd032a5..dcf8a2dc2f 100644 --- a/pcsx2/VU1micro.cpp +++ b/pcsx2/VU1micro.cpp @@ -1,454 +1,454 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -// This module contains code shared by both the dynarec and interpreter versions -// of the VU0 micro. - -#include "PrecompiledHeader.h" - -#include - -#include "Common.h" -#include "VU.h" -#include "VUops.h" -#include "VUmicro.h" -#include "iVUmicro.h" -#include "iVUzerorec.h" - -VURegs* g_pVU1; - -#ifdef _DEBUG -u32 vudump = 0; -#endif - -#define VF_VAL(x) ((x==0x80000000)?0:(x)) - -void iDumpVU1Registers() -{ - // fixme: This code is outdated, broken, and lacks printed labels. - // Needs heavy mods to be useful. -#if 0 - int i; -// static int icount = 0; -// __Log("%x\n", icount); - for(i = 1; i < 32; ++i) { -// __Log("v%d: w%f(%x) z%f(%x) y%f(%x) x%f(%x), vi: ", i, VU1.VF[i].F[3], VU1.VF[i].UL[3], VU1.VF[i].F[2], VU1.VF[i].UL[2], -// VU1.VF[i].F[1], VU1.VF[i].UL[1], VU1.VF[i].F[0], VU1.VF[i].UL[0]); - //__Log("v%d: %f %f %f %f, vi: ", i, VU1.VF[i].F[3], VU1.VF[i].F[2], VU1.VF[i].F[1], VU1.VF[i].F[0]); - __Log("v%d: %x %x %x %x, vi: ", i, VF_VAL(VU1.VF[i].UL[3]), VF_VAL(VU1.VF[i].UL[2]), VF_VAL(VU1.VF[i].UL[1]), VF_VAL(VU1.VF[i].UL[0])); - if( i == REG_Q || i == REG_P ) __Log("%f\n", VU1.VI[i].F); - //else __Log("%x\n", VU1.VI[i].UL); - else __Log("%x\n", (i==REG_STATUS_FLAG||i==REG_MAC_FLAG||i==REG_CLIP_FLAG)?0:VU1.VI[i].UL); - } - __Log("vfACC: %f %f %f %f\n", VU1.ACC.F[3], VU1.ACC.F[2], VU1.ACC.F[1], VU1.ACC.F[0]); -#endif -} - -// This is called by the COP2 as per the CTC instruction -void vu1ResetRegs() -{ - VU0.VI[REG_VPU_STAT].UL &= ~0xff00; // stop vu1 - VU0.VI[REG_FBRST].UL &= ~0xff00; // stop vu1 - vif1Regs->stat &= ~4; -} - -static int count; - -void vu1ExecMicro(u32 addr) -{ - while(VU0.VI[REG_VPU_STAT].UL & 0x100) - { - VUM_LOG("vu1ExecMicro > Stalling until current microprogram finishes"); - CpuVU1.ExecuteBlock(); - } - - VUM_LOG("vu1ExecMicro %x\n", addr); - VUM_LOG("vu1ExecMicro %x (count=%d)\n", addr, count++); - - VU0.VI[REG_VPU_STAT].UL|= 0x100; - VU0.VI[REG_VPU_STAT].UL&= ~0x7E000; - vif1Regs->stat|= 0x4; - if (addr != -1) VU1.VI[REG_TPC].UL = addr; - _vuExecMicroDebug(VU1); - - CpuVU1.ExecuteBlock(); -} - -_vuRegsTables(VU1, VU1regs); - -void VU1unknown() { - //assert(0); - CPU_LOG("Unknown VU micromode opcode called\n"); -} - -void VU1regsunknown(_VURegsNum *VUregsn) { - //assert(0); - CPU_LOG("Unknown VU micromode opcode called\n"); -} - - - -/****************************************/ -/* VU Micromode Upper instructions */ -/****************************************/ - -void VU1MI_ABS() { _vuABS(&VU1); } -void VU1MI_ADD() { _vuADD(&VU1); } -void VU1MI_ADDi() { _vuADDi(&VU1); } -void VU1MI_ADDq() { _vuADDq(&VU1); } -void VU1MI_ADDx() { _vuADDx(&VU1); } -void VU1MI_ADDy() { _vuADDy(&VU1); } -void VU1MI_ADDz() { _vuADDz(&VU1); } -void VU1MI_ADDw() { _vuADDw(&VU1); } -void VU1MI_ADDA() { _vuADDA(&VU1); } -void VU1MI_ADDAi() { _vuADDAi(&VU1); } -void VU1MI_ADDAq() { _vuADDAq(&VU1); } -void VU1MI_ADDAx() { _vuADDAx(&VU1); } -void VU1MI_ADDAy() { _vuADDAy(&VU1); } -void VU1MI_ADDAz() { _vuADDAz(&VU1); } -void VU1MI_ADDAw() { _vuADDAw(&VU1); } -void VU1MI_SUB() { _vuSUB(&VU1); } -void VU1MI_SUBi() { _vuSUBi(&VU1); } -void VU1MI_SUBq() { _vuSUBq(&VU1); } -void VU1MI_SUBx() { _vuSUBx(&VU1); } -void VU1MI_SUBy() { _vuSUBy(&VU1); } -void VU1MI_SUBz() { _vuSUBz(&VU1); } -void VU1MI_SUBw() { _vuSUBw(&VU1); } -void VU1MI_SUBA() { _vuSUBA(&VU1); } -void VU1MI_SUBAi() { _vuSUBAi(&VU1); } -void VU1MI_SUBAq() { _vuSUBAq(&VU1); } -void VU1MI_SUBAx() { _vuSUBAx(&VU1); } -void VU1MI_SUBAy() { _vuSUBAy(&VU1); } -void VU1MI_SUBAz() { _vuSUBAz(&VU1); } -void VU1MI_SUBAw() { _vuSUBAw(&VU1); } -void VU1MI_MUL() { _vuMUL(&VU1); } -void VU1MI_MULi() { _vuMULi(&VU1); } -void VU1MI_MULq() { _vuMULq(&VU1); } -void VU1MI_MULx() { _vuMULx(&VU1); } -void VU1MI_MULy() { _vuMULy(&VU1); } -void VU1MI_MULz() { _vuMULz(&VU1); } -void VU1MI_MULw() { _vuMULw(&VU1); } -void VU1MI_MULA() { _vuMULA(&VU1); } -void VU1MI_MULAi() { _vuMULAi(&VU1); } -void VU1MI_MULAq() { _vuMULAq(&VU1); } -void VU1MI_MULAx() { _vuMULAx(&VU1); } -void VU1MI_MULAy() { _vuMULAy(&VU1); } -void VU1MI_MULAz() { _vuMULAz(&VU1); } -void VU1MI_MULAw() { _vuMULAw(&VU1); } -void VU1MI_MADD() { _vuMADD(&VU1); } -void VU1MI_MADDi() { _vuMADDi(&VU1); } -void VU1MI_MADDq() { _vuMADDq(&VU1); } -void VU1MI_MADDx() { _vuMADDx(&VU1); } -void VU1MI_MADDy() { _vuMADDy(&VU1); } -void VU1MI_MADDz() { _vuMADDz(&VU1); } -void VU1MI_MADDw() { _vuMADDw(&VU1); } -void VU1MI_MADDA() { _vuMADDA(&VU1); } -void VU1MI_MADDAi() { _vuMADDAi(&VU1); } -void VU1MI_MADDAq() { _vuMADDAq(&VU1); } -void VU1MI_MADDAx() { _vuMADDAx(&VU1); } -void VU1MI_MADDAy() { _vuMADDAy(&VU1); } -void VU1MI_MADDAz() { _vuMADDAz(&VU1); } -void VU1MI_MADDAw() { _vuMADDAw(&VU1); } -void VU1MI_MSUB() { _vuMSUB(&VU1); } -void VU1MI_MSUBi() { _vuMSUBi(&VU1); } -void VU1MI_MSUBq() { _vuMSUBq(&VU1); } -void VU1MI_MSUBx() { _vuMSUBx(&VU1); } -void VU1MI_MSUBy() { _vuMSUBy(&VU1); } -void VU1MI_MSUBz() { _vuMSUBz(&VU1); } -void VU1MI_MSUBw() { _vuMSUBw(&VU1); } -void VU1MI_MSUBA() { _vuMSUBA(&VU1); } -void VU1MI_MSUBAi() { _vuMSUBAi(&VU1); } -void VU1MI_MSUBAq() { _vuMSUBAq(&VU1); } -void VU1MI_MSUBAx() { _vuMSUBAx(&VU1); } -void VU1MI_MSUBAy() { _vuMSUBAy(&VU1); } -void VU1MI_MSUBAz() { _vuMSUBAz(&VU1); } -void VU1MI_MSUBAw() { _vuMSUBAw(&VU1); } -void VU1MI_MAX() { _vuMAX(&VU1); } -void VU1MI_MAXi() { _vuMAXi(&VU1); } -void VU1MI_MAXx() { _vuMAXx(&VU1); } -void VU1MI_MAXy() { _vuMAXy(&VU1); } -void VU1MI_MAXz() { _vuMAXz(&VU1); } -void VU1MI_MAXw() { _vuMAXw(&VU1); } -void VU1MI_MINI() { _vuMINI(&VU1); } -void VU1MI_MINIi() { _vuMINIi(&VU1); } -void VU1MI_MINIx() { _vuMINIx(&VU1); } -void VU1MI_MINIy() { _vuMINIy(&VU1); } -void VU1MI_MINIz() { _vuMINIz(&VU1); } -void VU1MI_MINIw() { _vuMINIw(&VU1); } -void VU1MI_OPMULA() { _vuOPMULA(&VU1); } -void VU1MI_OPMSUB() { _vuOPMSUB(&VU1); } -void VU1MI_NOP() { _vuNOP(&VU1); } -void VU1MI_FTOI0() { _vuFTOI0(&VU1); } -void VU1MI_FTOI4() { _vuFTOI4(&VU1); } -void VU1MI_FTOI12() { _vuFTOI12(&VU1); } -void VU1MI_FTOI15() { _vuFTOI15(&VU1); } -void VU1MI_ITOF0() { _vuITOF0(&VU1); } -void VU1MI_ITOF4() { _vuITOF4(&VU1); } -void VU1MI_ITOF12() { _vuITOF12(&VU1); } -void VU1MI_ITOF15() { _vuITOF15(&VU1); } -void VU1MI_CLIP() { _vuCLIP(&VU1); } - -/*****************************************/ -/* VU Micromode Lower instructions */ -/*****************************************/ - -void VU1MI_DIV() { _vuDIV(&VU1); } -void VU1MI_SQRT() { _vuSQRT(&VU1); } -void VU1MI_RSQRT() { _vuRSQRT(&VU1); } -void VU1MI_IADD() { _vuIADD(&VU1); } -void VU1MI_IADDI() { _vuIADDI(&VU1); } -void VU1MI_IADDIU() { _vuIADDIU(&VU1); } -void VU1MI_IAND() { _vuIAND(&VU1); } -void VU1MI_IOR() { _vuIOR(&VU1); } -void VU1MI_ISUB() { _vuISUB(&VU1); } -void VU1MI_ISUBIU() { _vuISUBIU(&VU1); } -void VU1MI_MOVE() { _vuMOVE(&VU1); } -void VU1MI_MFIR() { _vuMFIR(&VU1); } -void VU1MI_MTIR() { _vuMTIR(&VU1); } -void VU1MI_MR32() { _vuMR32(&VU1); } -void VU1MI_LQ() { _vuLQ(&VU1); } -void VU1MI_LQD() { _vuLQD(&VU1); } -void VU1MI_LQI() { _vuLQI(&VU1); } -void VU1MI_SQ() { _vuSQ(&VU1); } -void VU1MI_SQD() { _vuSQD(&VU1); } -void VU1MI_SQI() { _vuSQI(&VU1); } -void VU1MI_ILW() { _vuILW(&VU1); } -void VU1MI_ISW() { _vuISW(&VU1); } -void VU1MI_ILWR() { _vuILWR(&VU1); } -void VU1MI_ISWR() { _vuISWR(&VU1); } -void VU1MI_RINIT() { _vuRINIT(&VU1); } -void VU1MI_RGET() { _vuRGET(&VU1); } -void VU1MI_RNEXT() { _vuRNEXT(&VU1); } -void VU1MI_RXOR() { _vuRXOR(&VU1); } -void VU1MI_WAITQ() { _vuWAITQ(&VU1); } -void VU1MI_FSAND() { _vuFSAND(&VU1); } -void VU1MI_FSEQ() { _vuFSEQ(&VU1); } -void VU1MI_FSOR() { _vuFSOR(&VU1); } -void VU1MI_FSSET() { _vuFSSET(&VU1); } -void VU1MI_FMAND() { _vuFMAND(&VU1); } -void VU1MI_FMEQ() { _vuFMEQ(&VU1); } -void VU1MI_FMOR() { _vuFMOR(&VU1); } -void VU1MI_FCAND() { _vuFCAND(&VU1); } -void VU1MI_FCEQ() { _vuFCEQ(&VU1); } -void VU1MI_FCOR() { _vuFCOR(&VU1); } -void VU1MI_FCSET() { _vuFCSET(&VU1); } -void VU1MI_FCGET() { _vuFCGET(&VU1); } -void VU1MI_IBEQ() { _vuIBEQ(&VU1); } -void VU1MI_IBGEZ() { _vuIBGEZ(&VU1); } -void VU1MI_IBGTZ() { _vuIBGTZ(&VU1); } -void VU1MI_IBLTZ() { _vuIBLTZ(&VU1); } -void VU1MI_IBLEZ() { _vuIBLEZ(&VU1); } -void VU1MI_IBNE() { _vuIBNE(&VU1); } -void VU1MI_B() { _vuB(&VU1); } -void VU1MI_BAL() { _vuBAL(&VU1); } -void VU1MI_JR() { _vuJR(&VU1); } -void VU1MI_JALR() { _vuJALR(&VU1); } -void VU1MI_MFP() { _vuMFP(&VU1); } -void VU1MI_WAITP() { _vuWAITP(&VU1); } -void VU1MI_ESADD() { _vuESADD(&VU1); } -void VU1MI_ERSADD() { _vuERSADD(&VU1); } -void VU1MI_ELENG() { _vuELENG(&VU1); } -void VU1MI_ERLENG() { _vuERLENG(&VU1); } -void VU1MI_EATANxy() { _vuEATANxy(&VU1); } -void VU1MI_EATANxz() { _vuEATANxz(&VU1); } -void VU1MI_ESUM() { _vuESUM(&VU1); } -void VU1MI_ERCPR() { _vuERCPR(&VU1); } -void VU1MI_ESQRT() { _vuESQRT(&VU1); } -void VU1MI_ERSQRT() { _vuERSQRT(&VU1); } -void VU1MI_ESIN() { _vuESIN(&VU1); } -void VU1MI_EATAN() { _vuEATAN(&VU1); } -void VU1MI_EEXP() { _vuEEXP(&VU1); } -void VU1MI_XITOP() { _vuXITOP(&VU1); } -void VU1MI_XGKICK() { _vuXGKICK(&VU1); } -void VU1MI_XTOP() { _vuXTOP(&VU1); } - - - -/****************************************/ -/* VU Micromode Upper instructions */ -/****************************************/ - -void VU1regsMI_ABS(_VURegsNum *VUregsn) { _vuRegsABS(&VU1, VUregsn); } -void VU1regsMI_ADD(_VURegsNum *VUregsn) { _vuRegsADD(&VU1, VUregsn); } -void VU1regsMI_ADDi(_VURegsNum *VUregsn) { _vuRegsADDi(&VU1, VUregsn); } -void VU1regsMI_ADDq(_VURegsNum *VUregsn) { _vuRegsADDq(&VU1, VUregsn); } -void VU1regsMI_ADDx(_VURegsNum *VUregsn) { _vuRegsADDx(&VU1, VUregsn); } -void VU1regsMI_ADDy(_VURegsNum *VUregsn) { _vuRegsADDy(&VU1, VUregsn); } -void VU1regsMI_ADDz(_VURegsNum *VUregsn) { _vuRegsADDz(&VU1, VUregsn); } -void VU1regsMI_ADDw(_VURegsNum *VUregsn) { _vuRegsADDw(&VU1, VUregsn); } -void VU1regsMI_ADDA(_VURegsNum *VUregsn) { _vuRegsADDA(&VU1, VUregsn); } -void VU1regsMI_ADDAi(_VURegsNum *VUregsn) { _vuRegsADDAi(&VU1, VUregsn); } -void VU1regsMI_ADDAq(_VURegsNum *VUregsn) { _vuRegsADDAq(&VU1, VUregsn); } -void VU1regsMI_ADDAx(_VURegsNum *VUregsn) { _vuRegsADDAx(&VU1, VUregsn); } -void VU1regsMI_ADDAy(_VURegsNum *VUregsn) { _vuRegsADDAy(&VU1, VUregsn); } -void VU1regsMI_ADDAz(_VURegsNum *VUregsn) { _vuRegsADDAz(&VU1, VUregsn); } -void VU1regsMI_ADDAw(_VURegsNum *VUregsn) { _vuRegsADDAw(&VU1, VUregsn); } -void VU1regsMI_SUB(_VURegsNum *VUregsn) { _vuRegsSUB(&VU1, VUregsn); } -void VU1regsMI_SUBi(_VURegsNum *VUregsn) { _vuRegsSUBi(&VU1, VUregsn); } -void VU1regsMI_SUBq(_VURegsNum *VUregsn) { _vuRegsSUBq(&VU1, VUregsn); } -void VU1regsMI_SUBx(_VURegsNum *VUregsn) { _vuRegsSUBx(&VU1, VUregsn); } -void VU1regsMI_SUBy(_VURegsNum *VUregsn) { _vuRegsSUBy(&VU1, VUregsn); } -void VU1regsMI_SUBz(_VURegsNum *VUregsn) { _vuRegsSUBz(&VU1, VUregsn); } -void VU1regsMI_SUBw(_VURegsNum *VUregsn) { _vuRegsSUBw(&VU1, VUregsn); } -void VU1regsMI_SUBA(_VURegsNum *VUregsn) { _vuRegsSUBA(&VU1, VUregsn); } -void VU1regsMI_SUBAi(_VURegsNum *VUregsn) { _vuRegsSUBAi(&VU1, VUregsn); } -void VU1regsMI_SUBAq(_VURegsNum *VUregsn) { _vuRegsSUBAq(&VU1, VUregsn); } -void VU1regsMI_SUBAx(_VURegsNum *VUregsn) { _vuRegsSUBAx(&VU1, VUregsn); } -void VU1regsMI_SUBAy(_VURegsNum *VUregsn) { _vuRegsSUBAy(&VU1, VUregsn); } -void VU1regsMI_SUBAz(_VURegsNum *VUregsn) { _vuRegsSUBAz(&VU1, VUregsn); } -void VU1regsMI_SUBAw(_VURegsNum *VUregsn) { _vuRegsSUBAw(&VU1, VUregsn); } -void VU1regsMI_MUL(_VURegsNum *VUregsn) { _vuRegsMUL(&VU1, VUregsn); } -void VU1regsMI_MULi(_VURegsNum *VUregsn) { _vuRegsMULi(&VU1, VUregsn); } -void VU1regsMI_MULq(_VURegsNum *VUregsn) { _vuRegsMULq(&VU1, VUregsn); } -void VU1regsMI_MULx(_VURegsNum *VUregsn) { _vuRegsMULx(&VU1, VUregsn); } -void VU1regsMI_MULy(_VURegsNum *VUregsn) { _vuRegsMULy(&VU1, VUregsn); } -void VU1regsMI_MULz(_VURegsNum *VUregsn) { _vuRegsMULz(&VU1, VUregsn); } -void VU1regsMI_MULw(_VURegsNum *VUregsn) { _vuRegsMULw(&VU1, VUregsn); } -void VU1regsMI_MULA(_VURegsNum *VUregsn) { _vuRegsMULA(&VU1, VUregsn); } -void VU1regsMI_MULAi(_VURegsNum *VUregsn) { _vuRegsMULAi(&VU1, VUregsn); } -void VU1regsMI_MULAq(_VURegsNum *VUregsn) { _vuRegsMULAq(&VU1, VUregsn); } -void VU1regsMI_MULAx(_VURegsNum *VUregsn) { _vuRegsMULAx(&VU1, VUregsn); } -void VU1regsMI_MULAy(_VURegsNum *VUregsn) { _vuRegsMULAy(&VU1, VUregsn); } -void VU1regsMI_MULAz(_VURegsNum *VUregsn) { _vuRegsMULAz(&VU1, VUregsn); } -void VU1regsMI_MULAw(_VURegsNum *VUregsn) { _vuRegsMULAw(&VU1, VUregsn); } -void VU1regsMI_MADD(_VURegsNum *VUregsn) { _vuRegsMADD(&VU1, VUregsn); } -void VU1regsMI_MADDi(_VURegsNum *VUregsn) { _vuRegsMADDi(&VU1, VUregsn); } -void VU1regsMI_MADDq(_VURegsNum *VUregsn) { _vuRegsMADDq(&VU1, VUregsn); } -void VU1regsMI_MADDx(_VURegsNum *VUregsn) { _vuRegsMADDx(&VU1, VUregsn); } -void VU1regsMI_MADDy(_VURegsNum *VUregsn) { _vuRegsMADDy(&VU1, VUregsn); } -void VU1regsMI_MADDz(_VURegsNum *VUregsn) { _vuRegsMADDz(&VU1, VUregsn); } -void VU1regsMI_MADDw(_VURegsNum *VUregsn) { _vuRegsMADDw(&VU1, VUregsn); } -void VU1regsMI_MADDA(_VURegsNum *VUregsn) { _vuRegsMADDA(&VU1, VUregsn); } -void VU1regsMI_MADDAi(_VURegsNum *VUregsn) { _vuRegsMADDAi(&VU1, VUregsn); } -void VU1regsMI_MADDAq(_VURegsNum *VUregsn) { _vuRegsMADDAq(&VU1, VUregsn); } -void VU1regsMI_MADDAx(_VURegsNum *VUregsn) { _vuRegsMADDAx(&VU1, VUregsn); } -void VU1regsMI_MADDAy(_VURegsNum *VUregsn) { _vuRegsMADDAy(&VU1, VUregsn); } -void VU1regsMI_MADDAz(_VURegsNum *VUregsn) { _vuRegsMADDAz(&VU1, VUregsn); } -void VU1regsMI_MADDAw(_VURegsNum *VUregsn) { _vuRegsMADDAw(&VU1, VUregsn); } -void VU1regsMI_MSUB(_VURegsNum *VUregsn) { _vuRegsMSUB(&VU1, VUregsn); } -void VU1regsMI_MSUBi(_VURegsNum *VUregsn) { _vuRegsMSUBi(&VU1, VUregsn); } -void VU1regsMI_MSUBq(_VURegsNum *VUregsn) { _vuRegsMSUBq(&VU1, VUregsn); } -void VU1regsMI_MSUBx(_VURegsNum *VUregsn) { _vuRegsMSUBx(&VU1, VUregsn); } -void VU1regsMI_MSUBy(_VURegsNum *VUregsn) { _vuRegsMSUBy(&VU1, VUregsn); } -void VU1regsMI_MSUBz(_VURegsNum *VUregsn) { _vuRegsMSUBz(&VU1, VUregsn); } -void VU1regsMI_MSUBw(_VURegsNum *VUregsn) { _vuRegsMSUBw(&VU1, VUregsn); } -void VU1regsMI_MSUBA(_VURegsNum *VUregsn) { _vuRegsMSUBA(&VU1, VUregsn); } -void VU1regsMI_MSUBAi(_VURegsNum *VUregsn) { _vuRegsMSUBAi(&VU1, VUregsn); } -void VU1regsMI_MSUBAq(_VURegsNum *VUregsn) { _vuRegsMSUBAq(&VU1, VUregsn); } -void VU1regsMI_MSUBAx(_VURegsNum *VUregsn) { _vuRegsMSUBAx(&VU1, VUregsn); } -void VU1regsMI_MSUBAy(_VURegsNum *VUregsn) { _vuRegsMSUBAy(&VU1, VUregsn); } -void VU1regsMI_MSUBAz(_VURegsNum *VUregsn) { _vuRegsMSUBAz(&VU1, VUregsn); } -void VU1regsMI_MSUBAw(_VURegsNum *VUregsn) { _vuRegsMSUBAw(&VU1, VUregsn); } -void VU1regsMI_MAX(_VURegsNum *VUregsn) { _vuRegsMAX(&VU1, VUregsn); } -void VU1regsMI_MAXi(_VURegsNum *VUregsn) { _vuRegsMAXi(&VU1, VUregsn); } -void VU1regsMI_MAXx(_VURegsNum *VUregsn) { _vuRegsMAXx(&VU1, VUregsn); } -void VU1regsMI_MAXy(_VURegsNum *VUregsn) { _vuRegsMAXy(&VU1, VUregsn); } -void VU1regsMI_MAXz(_VURegsNum *VUregsn) { _vuRegsMAXz(&VU1, VUregsn); } -void VU1regsMI_MAXw(_VURegsNum *VUregsn) { _vuRegsMAXw(&VU1, VUregsn); } -void VU1regsMI_MINI(_VURegsNum *VUregsn) { _vuRegsMINI(&VU1, VUregsn); } -void VU1regsMI_MINIi(_VURegsNum *VUregsn) { _vuRegsMINIi(&VU1, VUregsn); } -void VU1regsMI_MINIx(_VURegsNum *VUregsn) { _vuRegsMINIx(&VU1, VUregsn); } -void VU1regsMI_MINIy(_VURegsNum *VUregsn) { _vuRegsMINIy(&VU1, VUregsn); } -void VU1regsMI_MINIz(_VURegsNum *VUregsn) { _vuRegsMINIz(&VU1, VUregsn); } -void VU1regsMI_MINIw(_VURegsNum *VUregsn) { _vuRegsMINIw(&VU1, VUregsn); } -void VU1regsMI_OPMULA(_VURegsNum *VUregsn) { _vuRegsOPMULA(&VU1, VUregsn); } -void VU1regsMI_OPMSUB(_VURegsNum *VUregsn) { _vuRegsOPMSUB(&VU1, VUregsn); } -void VU1regsMI_NOP(_VURegsNum *VUregsn) { _vuRegsNOP(&VU1, VUregsn); } -void VU1regsMI_FTOI0(_VURegsNum *VUregsn) { _vuRegsFTOI0(&VU1, VUregsn); } -void VU1regsMI_FTOI4(_VURegsNum *VUregsn) { _vuRegsFTOI4(&VU1, VUregsn); } -void VU1regsMI_FTOI12(_VURegsNum *VUregsn) { _vuRegsFTOI12(&VU1, VUregsn); } -void VU1regsMI_FTOI15(_VURegsNum *VUregsn) { _vuRegsFTOI15(&VU1, VUregsn); } -void VU1regsMI_ITOF0(_VURegsNum *VUregsn) { _vuRegsITOF0(&VU1, VUregsn); } -void VU1regsMI_ITOF4(_VURegsNum *VUregsn) { _vuRegsITOF4(&VU1, VUregsn); } -void VU1regsMI_ITOF12(_VURegsNum *VUregsn) { _vuRegsITOF12(&VU1, VUregsn); } -void VU1regsMI_ITOF15(_VURegsNum *VUregsn) { _vuRegsITOF15(&VU1, VUregsn); } -void VU1regsMI_CLIP(_VURegsNum *VUregsn) { _vuRegsCLIP(&VU1, VUregsn); } - -/*****************************************/ -/* VU Micromode Lower instructions */ -/*****************************************/ - -void VU1regsMI_DIV(_VURegsNum *VUregsn) { _vuRegsDIV(&VU1, VUregsn); } -void VU1regsMI_SQRT(_VURegsNum *VUregsn) { _vuRegsSQRT(&VU1, VUregsn); } -void VU1regsMI_RSQRT(_VURegsNum *VUregsn) { _vuRegsRSQRT(&VU1, VUregsn); } -void VU1regsMI_IADD(_VURegsNum *VUregsn) { _vuRegsIADD(&VU1, VUregsn); } -void VU1regsMI_IADDI(_VURegsNum *VUregsn) { _vuRegsIADDI(&VU1, VUregsn); } -void VU1regsMI_IADDIU(_VURegsNum *VUregsn) { _vuRegsIADDIU(&VU1, VUregsn); } -void VU1regsMI_IAND(_VURegsNum *VUregsn) { _vuRegsIAND(&VU1, VUregsn); } -void VU1regsMI_IOR(_VURegsNum *VUregsn) { _vuRegsIOR(&VU1, VUregsn); } -void VU1regsMI_ISUB(_VURegsNum *VUregsn) { _vuRegsISUB(&VU1, VUregsn); } -void VU1regsMI_ISUBIU(_VURegsNum *VUregsn) { _vuRegsISUBIU(&VU1, VUregsn); } -void VU1regsMI_MOVE(_VURegsNum *VUregsn) { _vuRegsMOVE(&VU1, VUregsn); } -void VU1regsMI_MFIR(_VURegsNum *VUregsn) { _vuRegsMFIR(&VU1, VUregsn); } -void VU1regsMI_MTIR(_VURegsNum *VUregsn) { _vuRegsMTIR(&VU1, VUregsn); } -void VU1regsMI_MR32(_VURegsNum *VUregsn) { _vuRegsMR32(&VU1, VUregsn); } -void VU1regsMI_LQ(_VURegsNum *VUregsn) { _vuRegsLQ(&VU1, VUregsn); } -void VU1regsMI_LQD(_VURegsNum *VUregsn) { _vuRegsLQD(&VU1, VUregsn); } -void VU1regsMI_LQI(_VURegsNum *VUregsn) { _vuRegsLQI(&VU1, VUregsn); } -void VU1regsMI_SQ(_VURegsNum *VUregsn) { _vuRegsSQ(&VU1, VUregsn); } -void VU1regsMI_SQD(_VURegsNum *VUregsn) { _vuRegsSQD(&VU1, VUregsn); } -void VU1regsMI_SQI(_VURegsNum *VUregsn) { _vuRegsSQI(&VU1, VUregsn); } -void VU1regsMI_ILW(_VURegsNum *VUregsn) { _vuRegsILW(&VU1, VUregsn); } -void VU1regsMI_ISW(_VURegsNum *VUregsn) { _vuRegsISW(&VU1, VUregsn); } -void VU1regsMI_ILWR(_VURegsNum *VUregsn) { _vuRegsILWR(&VU1, VUregsn); } -void VU1regsMI_ISWR(_VURegsNum *VUregsn) { _vuRegsISWR(&VU1, VUregsn); } -void VU1regsMI_RINIT(_VURegsNum *VUregsn) { _vuRegsRINIT(&VU1, VUregsn); } -void VU1regsMI_RGET(_VURegsNum *VUregsn) { _vuRegsRGET(&VU1, VUregsn); } -void VU1regsMI_RNEXT(_VURegsNum *VUregsn) { _vuRegsRNEXT(&VU1, VUregsn); } -void VU1regsMI_RXOR(_VURegsNum *VUregsn) { _vuRegsRXOR(&VU1, VUregsn); } -void VU1regsMI_WAITQ(_VURegsNum *VUregsn) { _vuRegsWAITQ(&VU1, VUregsn); } -void VU1regsMI_FSAND(_VURegsNum *VUregsn) { _vuRegsFSAND(&VU1, VUregsn); } -void VU1regsMI_FSEQ(_VURegsNum *VUregsn) { _vuRegsFSEQ(&VU1, VUregsn); } -void VU1regsMI_FSOR(_VURegsNum *VUregsn) { _vuRegsFSOR(&VU1, VUregsn); } -void VU1regsMI_FSSET(_VURegsNum *VUregsn) { _vuRegsFSSET(&VU1, VUregsn); } -void VU1regsMI_FMAND(_VURegsNum *VUregsn) { _vuRegsFMAND(&VU1, VUregsn); } -void VU1regsMI_FMEQ(_VURegsNum *VUregsn) { _vuRegsFMEQ(&VU1, VUregsn); } -void VU1regsMI_FMOR(_VURegsNum *VUregsn) { _vuRegsFMOR(&VU1, VUregsn); } -void VU1regsMI_FCAND(_VURegsNum *VUregsn) { _vuRegsFCAND(&VU1, VUregsn); } -void VU1regsMI_FCEQ(_VURegsNum *VUregsn) { _vuRegsFCEQ(&VU1, VUregsn); } -void VU1regsMI_FCOR(_VURegsNum *VUregsn) { _vuRegsFCOR(&VU1, VUregsn); } -void VU1regsMI_FCSET(_VURegsNum *VUregsn) { _vuRegsFCSET(&VU1, VUregsn); } -void VU1regsMI_FCGET(_VURegsNum *VUregsn) { _vuRegsFCGET(&VU1, VUregsn); } -void VU1regsMI_IBEQ(_VURegsNum *VUregsn) { _vuRegsIBEQ(&VU1, VUregsn); } -void VU1regsMI_IBGEZ(_VURegsNum *VUregsn) { _vuRegsIBGEZ(&VU1, VUregsn); } -void VU1regsMI_IBGTZ(_VURegsNum *VUregsn) { _vuRegsIBGTZ(&VU1, VUregsn); } -void VU1regsMI_IBLTZ(_VURegsNum *VUregsn) { _vuRegsIBLTZ(&VU1, VUregsn); } -void VU1regsMI_IBLEZ(_VURegsNum *VUregsn) { _vuRegsIBLEZ(&VU1, VUregsn); } -void VU1regsMI_IBNE(_VURegsNum *VUregsn) { _vuRegsIBNE(&VU1, VUregsn); } -void VU1regsMI_B(_VURegsNum *VUregsn) { _vuRegsB(&VU1, VUregsn); } -void VU1regsMI_BAL(_VURegsNum *VUregsn) { _vuRegsBAL(&VU1, VUregsn); } -void VU1regsMI_JR(_VURegsNum *VUregsn) { _vuRegsJR(&VU1, VUregsn); } -void VU1regsMI_JALR(_VURegsNum *VUregsn) { _vuRegsJALR(&VU1, VUregsn); } -void VU1regsMI_MFP(_VURegsNum *VUregsn) { _vuRegsMFP(&VU1, VUregsn); } -void VU1regsMI_WAITP(_VURegsNum *VUregsn) { _vuRegsWAITP(&VU1, VUregsn); } -void VU1regsMI_ESADD(_VURegsNum *VUregsn) { _vuRegsESADD(&VU1, VUregsn); } -void VU1regsMI_ERSADD(_VURegsNum *VUregsn) { _vuRegsERSADD(&VU1, VUregsn); } -void VU1regsMI_ELENG(_VURegsNum *VUregsn) { _vuRegsELENG(&VU1, VUregsn); } -void VU1regsMI_ERLENG(_VURegsNum *VUregsn) { _vuRegsERLENG(&VU1, VUregsn); } -void VU1regsMI_EATANxy(_VURegsNum *VUregsn) { _vuRegsEATANxy(&VU1, VUregsn); } -void VU1regsMI_EATANxz(_VURegsNum *VUregsn) { _vuRegsEATANxz(&VU1, VUregsn); } -void VU1regsMI_ESUM(_VURegsNum *VUregsn) { _vuRegsESUM(&VU1, VUregsn); } -void VU1regsMI_ERCPR(_VURegsNum *VUregsn) { _vuRegsERCPR(&VU1, VUregsn); } -void VU1regsMI_ESQRT(_VURegsNum *VUregsn) { _vuRegsESQRT(&VU1, VUregsn); } -void VU1regsMI_ERSQRT(_VURegsNum *VUregsn) { _vuRegsERSQRT(&VU1, VUregsn); } -void VU1regsMI_ESIN(_VURegsNum *VUregsn) { _vuRegsESIN(&VU1, VUregsn); } -void VU1regsMI_EATAN(_VURegsNum *VUregsn) { _vuRegsEATAN(&VU1, VUregsn); } -void VU1regsMI_EEXP(_VURegsNum *VUregsn) { _vuRegsEEXP(&VU1, VUregsn); } -void VU1regsMI_XITOP(_VURegsNum *VUregsn) { _vuRegsXITOP(&VU1, VUregsn); } -void VU1regsMI_XGKICK(_VURegsNum *VUregsn) { _vuRegsXGKICK(&VU1, VUregsn); } -void VU1regsMI_XTOP(_VURegsNum *VUregsn) { _vuRegsXTOP(&VU1, VUregsn); } +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +// This module contains code shared by both the dynarec and interpreter versions +// of the VU0 micro. + +#include "PrecompiledHeader.h" + +#include + +#include "Common.h" +#include "VU.h" +#include "VUops.h" +#include "VUmicro.h" +#include "iVUmicro.h" +#include "iVUzerorec.h" + +VURegs* g_pVU1; + +#ifdef _DEBUG +u32 vudump = 0; +#endif + +#define VF_VAL(x) ((x==0x80000000)?0:(x)) + +void iDumpVU1Registers() +{ + // fixme: This code is outdated, broken, and lacks printed labels. + // Needs heavy mods to be useful. +#if 0 + int i; +// static int icount = 0; +// __Log("%x\n", icount); + for(i = 1; i < 32; ++i) { +// __Log("v%d: w%f(%x) z%f(%x) y%f(%x) x%f(%x), vi: ", i, VU1.VF[i].F[3], VU1.VF[i].UL[3], VU1.VF[i].F[2], VU1.VF[i].UL[2], +// VU1.VF[i].F[1], VU1.VF[i].UL[1], VU1.VF[i].F[0], VU1.VF[i].UL[0]); + //__Log("v%d: %f %f %f %f, vi: ", i, VU1.VF[i].F[3], VU1.VF[i].F[2], VU1.VF[i].F[1], VU1.VF[i].F[0]); + __Log("v%d: %x %x %x %x, vi: ", i, VF_VAL(VU1.VF[i].UL[3]), VF_VAL(VU1.VF[i].UL[2]), VF_VAL(VU1.VF[i].UL[1]), VF_VAL(VU1.VF[i].UL[0])); + if( i == REG_Q || i == REG_P ) __Log("%f\n", VU1.VI[i].F); + //else __Log("%x\n", VU1.VI[i].UL); + else __Log("%x\n", (i==REG_STATUS_FLAG||i==REG_MAC_FLAG||i==REG_CLIP_FLAG)?0:VU1.VI[i].UL); + } + __Log("vfACC: %f %f %f %f\n", VU1.ACC.F[3], VU1.ACC.F[2], VU1.ACC.F[1], VU1.ACC.F[0]); +#endif +} + +// This is called by the COP2 as per the CTC instruction +void vu1ResetRegs() +{ + VU0.VI[REG_VPU_STAT].UL &= ~0xff00; // stop vu1 + VU0.VI[REG_FBRST].UL &= ~0xff00; // stop vu1 + vif1Regs->stat &= ~4; +} + +static int count; + +void vu1ExecMicro(u32 addr) +{ + while(VU0.VI[REG_VPU_STAT].UL & 0x100) + { + VUM_LOG("vu1ExecMicro > Stalling until current microprogram finishes"); + CpuVU1.ExecuteBlock(); + } + + VUM_LOG("vu1ExecMicro %x\n", addr); + VUM_LOG("vu1ExecMicro %x (count=%d)\n", addr, count++); + + VU0.VI[REG_VPU_STAT].UL|= 0x100; + VU0.VI[REG_VPU_STAT].UL&= ~0x7E000; + vif1Regs->stat|= 0x4; + if (addr != -1) VU1.VI[REG_TPC].UL = addr; + _vuExecMicroDebug(VU1); + + CpuVU1.ExecuteBlock(); +} + +_vuRegsTables(VU1, VU1regs); + +void VU1unknown() { + //assert(0); + CPU_LOG("Unknown VU micromode opcode called\n"); +} + +void VU1regsunknown(_VURegsNum *VUregsn) { + //assert(0); + CPU_LOG("Unknown VU micromode opcode called\n"); +} + + + +/****************************************/ +/* VU Micromode Upper instructions */ +/****************************************/ + +void VU1MI_ABS() { _vuABS(&VU1); } +void VU1MI_ADD() { _vuADD(&VU1); } +void VU1MI_ADDi() { _vuADDi(&VU1); } +void VU1MI_ADDq() { _vuADDq(&VU1); } +void VU1MI_ADDx() { _vuADDx(&VU1); } +void VU1MI_ADDy() { _vuADDy(&VU1); } +void VU1MI_ADDz() { _vuADDz(&VU1); } +void VU1MI_ADDw() { _vuADDw(&VU1); } +void VU1MI_ADDA() { _vuADDA(&VU1); } +void VU1MI_ADDAi() { _vuADDAi(&VU1); } +void VU1MI_ADDAq() { _vuADDAq(&VU1); } +void VU1MI_ADDAx() { _vuADDAx(&VU1); } +void VU1MI_ADDAy() { _vuADDAy(&VU1); } +void VU1MI_ADDAz() { _vuADDAz(&VU1); } +void VU1MI_ADDAw() { _vuADDAw(&VU1); } +void VU1MI_SUB() { _vuSUB(&VU1); } +void VU1MI_SUBi() { _vuSUBi(&VU1); } +void VU1MI_SUBq() { _vuSUBq(&VU1); } +void VU1MI_SUBx() { _vuSUBx(&VU1); } +void VU1MI_SUBy() { _vuSUBy(&VU1); } +void VU1MI_SUBz() { _vuSUBz(&VU1); } +void VU1MI_SUBw() { _vuSUBw(&VU1); } +void VU1MI_SUBA() { _vuSUBA(&VU1); } +void VU1MI_SUBAi() { _vuSUBAi(&VU1); } +void VU1MI_SUBAq() { _vuSUBAq(&VU1); } +void VU1MI_SUBAx() { _vuSUBAx(&VU1); } +void VU1MI_SUBAy() { _vuSUBAy(&VU1); } +void VU1MI_SUBAz() { _vuSUBAz(&VU1); } +void VU1MI_SUBAw() { _vuSUBAw(&VU1); } +void VU1MI_MUL() { _vuMUL(&VU1); } +void VU1MI_MULi() { _vuMULi(&VU1); } +void VU1MI_MULq() { _vuMULq(&VU1); } +void VU1MI_MULx() { _vuMULx(&VU1); } +void VU1MI_MULy() { _vuMULy(&VU1); } +void VU1MI_MULz() { _vuMULz(&VU1); } +void VU1MI_MULw() { _vuMULw(&VU1); } +void VU1MI_MULA() { _vuMULA(&VU1); } +void VU1MI_MULAi() { _vuMULAi(&VU1); } +void VU1MI_MULAq() { _vuMULAq(&VU1); } +void VU1MI_MULAx() { _vuMULAx(&VU1); } +void VU1MI_MULAy() { _vuMULAy(&VU1); } +void VU1MI_MULAz() { _vuMULAz(&VU1); } +void VU1MI_MULAw() { _vuMULAw(&VU1); } +void VU1MI_MADD() { _vuMADD(&VU1); } +void VU1MI_MADDi() { _vuMADDi(&VU1); } +void VU1MI_MADDq() { _vuMADDq(&VU1); } +void VU1MI_MADDx() { _vuMADDx(&VU1); } +void VU1MI_MADDy() { _vuMADDy(&VU1); } +void VU1MI_MADDz() { _vuMADDz(&VU1); } +void VU1MI_MADDw() { _vuMADDw(&VU1); } +void VU1MI_MADDA() { _vuMADDA(&VU1); } +void VU1MI_MADDAi() { _vuMADDAi(&VU1); } +void VU1MI_MADDAq() { _vuMADDAq(&VU1); } +void VU1MI_MADDAx() { _vuMADDAx(&VU1); } +void VU1MI_MADDAy() { _vuMADDAy(&VU1); } +void VU1MI_MADDAz() { _vuMADDAz(&VU1); } +void VU1MI_MADDAw() { _vuMADDAw(&VU1); } +void VU1MI_MSUB() { _vuMSUB(&VU1); } +void VU1MI_MSUBi() { _vuMSUBi(&VU1); } +void VU1MI_MSUBq() { _vuMSUBq(&VU1); } +void VU1MI_MSUBx() { _vuMSUBx(&VU1); } +void VU1MI_MSUBy() { _vuMSUBy(&VU1); } +void VU1MI_MSUBz() { _vuMSUBz(&VU1); } +void VU1MI_MSUBw() { _vuMSUBw(&VU1); } +void VU1MI_MSUBA() { _vuMSUBA(&VU1); } +void VU1MI_MSUBAi() { _vuMSUBAi(&VU1); } +void VU1MI_MSUBAq() { _vuMSUBAq(&VU1); } +void VU1MI_MSUBAx() { _vuMSUBAx(&VU1); } +void VU1MI_MSUBAy() { _vuMSUBAy(&VU1); } +void VU1MI_MSUBAz() { _vuMSUBAz(&VU1); } +void VU1MI_MSUBAw() { _vuMSUBAw(&VU1); } +void VU1MI_MAX() { _vuMAX(&VU1); } +void VU1MI_MAXi() { _vuMAXi(&VU1); } +void VU1MI_MAXx() { _vuMAXx(&VU1); } +void VU1MI_MAXy() { _vuMAXy(&VU1); } +void VU1MI_MAXz() { _vuMAXz(&VU1); } +void VU1MI_MAXw() { _vuMAXw(&VU1); } +void VU1MI_MINI() { _vuMINI(&VU1); } +void VU1MI_MINIi() { _vuMINIi(&VU1); } +void VU1MI_MINIx() { _vuMINIx(&VU1); } +void VU1MI_MINIy() { _vuMINIy(&VU1); } +void VU1MI_MINIz() { _vuMINIz(&VU1); } +void VU1MI_MINIw() { _vuMINIw(&VU1); } +void VU1MI_OPMULA() { _vuOPMULA(&VU1); } +void VU1MI_OPMSUB() { _vuOPMSUB(&VU1); } +void VU1MI_NOP() { _vuNOP(&VU1); } +void VU1MI_FTOI0() { _vuFTOI0(&VU1); } +void VU1MI_FTOI4() { _vuFTOI4(&VU1); } +void VU1MI_FTOI12() { _vuFTOI12(&VU1); } +void VU1MI_FTOI15() { _vuFTOI15(&VU1); } +void VU1MI_ITOF0() { _vuITOF0(&VU1); } +void VU1MI_ITOF4() { _vuITOF4(&VU1); } +void VU1MI_ITOF12() { _vuITOF12(&VU1); } +void VU1MI_ITOF15() { _vuITOF15(&VU1); } +void VU1MI_CLIP() { _vuCLIP(&VU1); } + +/*****************************************/ +/* VU Micromode Lower instructions */ +/*****************************************/ + +void VU1MI_DIV() { _vuDIV(&VU1); } +void VU1MI_SQRT() { _vuSQRT(&VU1); } +void VU1MI_RSQRT() { _vuRSQRT(&VU1); } +void VU1MI_IADD() { _vuIADD(&VU1); } +void VU1MI_IADDI() { _vuIADDI(&VU1); } +void VU1MI_IADDIU() { _vuIADDIU(&VU1); } +void VU1MI_IAND() { _vuIAND(&VU1); } +void VU1MI_IOR() { _vuIOR(&VU1); } +void VU1MI_ISUB() { _vuISUB(&VU1); } +void VU1MI_ISUBIU() { _vuISUBIU(&VU1); } +void VU1MI_MOVE() { _vuMOVE(&VU1); } +void VU1MI_MFIR() { _vuMFIR(&VU1); } +void VU1MI_MTIR() { _vuMTIR(&VU1); } +void VU1MI_MR32() { _vuMR32(&VU1); } +void VU1MI_LQ() { _vuLQ(&VU1); } +void VU1MI_LQD() { _vuLQD(&VU1); } +void VU1MI_LQI() { _vuLQI(&VU1); } +void VU1MI_SQ() { _vuSQ(&VU1); } +void VU1MI_SQD() { _vuSQD(&VU1); } +void VU1MI_SQI() { _vuSQI(&VU1); } +void VU1MI_ILW() { _vuILW(&VU1); } +void VU1MI_ISW() { _vuISW(&VU1); } +void VU1MI_ILWR() { _vuILWR(&VU1); } +void VU1MI_ISWR() { _vuISWR(&VU1); } +void VU1MI_RINIT() { _vuRINIT(&VU1); } +void VU1MI_RGET() { _vuRGET(&VU1); } +void VU1MI_RNEXT() { _vuRNEXT(&VU1); } +void VU1MI_RXOR() { _vuRXOR(&VU1); } +void VU1MI_WAITQ() { _vuWAITQ(&VU1); } +void VU1MI_FSAND() { _vuFSAND(&VU1); } +void VU1MI_FSEQ() { _vuFSEQ(&VU1); } +void VU1MI_FSOR() { _vuFSOR(&VU1); } +void VU1MI_FSSET() { _vuFSSET(&VU1); } +void VU1MI_FMAND() { _vuFMAND(&VU1); } +void VU1MI_FMEQ() { _vuFMEQ(&VU1); } +void VU1MI_FMOR() { _vuFMOR(&VU1); } +void VU1MI_FCAND() { _vuFCAND(&VU1); } +void VU1MI_FCEQ() { _vuFCEQ(&VU1); } +void VU1MI_FCOR() { _vuFCOR(&VU1); } +void VU1MI_FCSET() { _vuFCSET(&VU1); } +void VU1MI_FCGET() { _vuFCGET(&VU1); } +void VU1MI_IBEQ() { _vuIBEQ(&VU1); } +void VU1MI_IBGEZ() { _vuIBGEZ(&VU1); } +void VU1MI_IBGTZ() { _vuIBGTZ(&VU1); } +void VU1MI_IBLTZ() { _vuIBLTZ(&VU1); } +void VU1MI_IBLEZ() { _vuIBLEZ(&VU1); } +void VU1MI_IBNE() { _vuIBNE(&VU1); } +void VU1MI_B() { _vuB(&VU1); } +void VU1MI_BAL() { _vuBAL(&VU1); } +void VU1MI_JR() { _vuJR(&VU1); } +void VU1MI_JALR() { _vuJALR(&VU1); } +void VU1MI_MFP() { _vuMFP(&VU1); } +void VU1MI_WAITP() { _vuWAITP(&VU1); } +void VU1MI_ESADD() { _vuESADD(&VU1); } +void VU1MI_ERSADD() { _vuERSADD(&VU1); } +void VU1MI_ELENG() { _vuELENG(&VU1); } +void VU1MI_ERLENG() { _vuERLENG(&VU1); } +void VU1MI_EATANxy() { _vuEATANxy(&VU1); } +void VU1MI_EATANxz() { _vuEATANxz(&VU1); } +void VU1MI_ESUM() { _vuESUM(&VU1); } +void VU1MI_ERCPR() { _vuERCPR(&VU1); } +void VU1MI_ESQRT() { _vuESQRT(&VU1); } +void VU1MI_ERSQRT() { _vuERSQRT(&VU1); } +void VU1MI_ESIN() { _vuESIN(&VU1); } +void VU1MI_EATAN() { _vuEATAN(&VU1); } +void VU1MI_EEXP() { _vuEEXP(&VU1); } +void VU1MI_XITOP() { _vuXITOP(&VU1); } +void VU1MI_XGKICK() { _vuXGKICK(&VU1); } +void VU1MI_XTOP() { _vuXTOP(&VU1); } + + + +/****************************************/ +/* VU Micromode Upper instructions */ +/****************************************/ + +void VU1regsMI_ABS(_VURegsNum *VUregsn) { _vuRegsABS(&VU1, VUregsn); } +void VU1regsMI_ADD(_VURegsNum *VUregsn) { _vuRegsADD(&VU1, VUregsn); } +void VU1regsMI_ADDi(_VURegsNum *VUregsn) { _vuRegsADDi(&VU1, VUregsn); } +void VU1regsMI_ADDq(_VURegsNum *VUregsn) { _vuRegsADDq(&VU1, VUregsn); } +void VU1regsMI_ADDx(_VURegsNum *VUregsn) { _vuRegsADDx(&VU1, VUregsn); } +void VU1regsMI_ADDy(_VURegsNum *VUregsn) { _vuRegsADDy(&VU1, VUregsn); } +void VU1regsMI_ADDz(_VURegsNum *VUregsn) { _vuRegsADDz(&VU1, VUregsn); } +void VU1regsMI_ADDw(_VURegsNum *VUregsn) { _vuRegsADDw(&VU1, VUregsn); } +void VU1regsMI_ADDA(_VURegsNum *VUregsn) { _vuRegsADDA(&VU1, VUregsn); } +void VU1regsMI_ADDAi(_VURegsNum *VUregsn) { _vuRegsADDAi(&VU1, VUregsn); } +void VU1regsMI_ADDAq(_VURegsNum *VUregsn) { _vuRegsADDAq(&VU1, VUregsn); } +void VU1regsMI_ADDAx(_VURegsNum *VUregsn) { _vuRegsADDAx(&VU1, VUregsn); } +void VU1regsMI_ADDAy(_VURegsNum *VUregsn) { _vuRegsADDAy(&VU1, VUregsn); } +void VU1regsMI_ADDAz(_VURegsNum *VUregsn) { _vuRegsADDAz(&VU1, VUregsn); } +void VU1regsMI_ADDAw(_VURegsNum *VUregsn) { _vuRegsADDAw(&VU1, VUregsn); } +void VU1regsMI_SUB(_VURegsNum *VUregsn) { _vuRegsSUB(&VU1, VUregsn); } +void VU1regsMI_SUBi(_VURegsNum *VUregsn) { _vuRegsSUBi(&VU1, VUregsn); } +void VU1regsMI_SUBq(_VURegsNum *VUregsn) { _vuRegsSUBq(&VU1, VUregsn); } +void VU1regsMI_SUBx(_VURegsNum *VUregsn) { _vuRegsSUBx(&VU1, VUregsn); } +void VU1regsMI_SUBy(_VURegsNum *VUregsn) { _vuRegsSUBy(&VU1, VUregsn); } +void VU1regsMI_SUBz(_VURegsNum *VUregsn) { _vuRegsSUBz(&VU1, VUregsn); } +void VU1regsMI_SUBw(_VURegsNum *VUregsn) { _vuRegsSUBw(&VU1, VUregsn); } +void VU1regsMI_SUBA(_VURegsNum *VUregsn) { _vuRegsSUBA(&VU1, VUregsn); } +void VU1regsMI_SUBAi(_VURegsNum *VUregsn) { _vuRegsSUBAi(&VU1, VUregsn); } +void VU1regsMI_SUBAq(_VURegsNum *VUregsn) { _vuRegsSUBAq(&VU1, VUregsn); } +void VU1regsMI_SUBAx(_VURegsNum *VUregsn) { _vuRegsSUBAx(&VU1, VUregsn); } +void VU1regsMI_SUBAy(_VURegsNum *VUregsn) { _vuRegsSUBAy(&VU1, VUregsn); } +void VU1regsMI_SUBAz(_VURegsNum *VUregsn) { _vuRegsSUBAz(&VU1, VUregsn); } +void VU1regsMI_SUBAw(_VURegsNum *VUregsn) { _vuRegsSUBAw(&VU1, VUregsn); } +void VU1regsMI_MUL(_VURegsNum *VUregsn) { _vuRegsMUL(&VU1, VUregsn); } +void VU1regsMI_MULi(_VURegsNum *VUregsn) { _vuRegsMULi(&VU1, VUregsn); } +void VU1regsMI_MULq(_VURegsNum *VUregsn) { _vuRegsMULq(&VU1, VUregsn); } +void VU1regsMI_MULx(_VURegsNum *VUregsn) { _vuRegsMULx(&VU1, VUregsn); } +void VU1regsMI_MULy(_VURegsNum *VUregsn) { _vuRegsMULy(&VU1, VUregsn); } +void VU1regsMI_MULz(_VURegsNum *VUregsn) { _vuRegsMULz(&VU1, VUregsn); } +void VU1regsMI_MULw(_VURegsNum *VUregsn) { _vuRegsMULw(&VU1, VUregsn); } +void VU1regsMI_MULA(_VURegsNum *VUregsn) { _vuRegsMULA(&VU1, VUregsn); } +void VU1regsMI_MULAi(_VURegsNum *VUregsn) { _vuRegsMULAi(&VU1, VUregsn); } +void VU1regsMI_MULAq(_VURegsNum *VUregsn) { _vuRegsMULAq(&VU1, VUregsn); } +void VU1regsMI_MULAx(_VURegsNum *VUregsn) { _vuRegsMULAx(&VU1, VUregsn); } +void VU1regsMI_MULAy(_VURegsNum *VUregsn) { _vuRegsMULAy(&VU1, VUregsn); } +void VU1regsMI_MULAz(_VURegsNum *VUregsn) { _vuRegsMULAz(&VU1, VUregsn); } +void VU1regsMI_MULAw(_VURegsNum *VUregsn) { _vuRegsMULAw(&VU1, VUregsn); } +void VU1regsMI_MADD(_VURegsNum *VUregsn) { _vuRegsMADD(&VU1, VUregsn); } +void VU1regsMI_MADDi(_VURegsNum *VUregsn) { _vuRegsMADDi(&VU1, VUregsn); } +void VU1regsMI_MADDq(_VURegsNum *VUregsn) { _vuRegsMADDq(&VU1, VUregsn); } +void VU1regsMI_MADDx(_VURegsNum *VUregsn) { _vuRegsMADDx(&VU1, VUregsn); } +void VU1regsMI_MADDy(_VURegsNum *VUregsn) { _vuRegsMADDy(&VU1, VUregsn); } +void VU1regsMI_MADDz(_VURegsNum *VUregsn) { _vuRegsMADDz(&VU1, VUregsn); } +void VU1regsMI_MADDw(_VURegsNum *VUregsn) { _vuRegsMADDw(&VU1, VUregsn); } +void VU1regsMI_MADDA(_VURegsNum *VUregsn) { _vuRegsMADDA(&VU1, VUregsn); } +void VU1regsMI_MADDAi(_VURegsNum *VUregsn) { _vuRegsMADDAi(&VU1, VUregsn); } +void VU1regsMI_MADDAq(_VURegsNum *VUregsn) { _vuRegsMADDAq(&VU1, VUregsn); } +void VU1regsMI_MADDAx(_VURegsNum *VUregsn) { _vuRegsMADDAx(&VU1, VUregsn); } +void VU1regsMI_MADDAy(_VURegsNum *VUregsn) { _vuRegsMADDAy(&VU1, VUregsn); } +void VU1regsMI_MADDAz(_VURegsNum *VUregsn) { _vuRegsMADDAz(&VU1, VUregsn); } +void VU1regsMI_MADDAw(_VURegsNum *VUregsn) { _vuRegsMADDAw(&VU1, VUregsn); } +void VU1regsMI_MSUB(_VURegsNum *VUregsn) { _vuRegsMSUB(&VU1, VUregsn); } +void VU1regsMI_MSUBi(_VURegsNum *VUregsn) { _vuRegsMSUBi(&VU1, VUregsn); } +void VU1regsMI_MSUBq(_VURegsNum *VUregsn) { _vuRegsMSUBq(&VU1, VUregsn); } +void VU1regsMI_MSUBx(_VURegsNum *VUregsn) { _vuRegsMSUBx(&VU1, VUregsn); } +void VU1regsMI_MSUBy(_VURegsNum *VUregsn) { _vuRegsMSUBy(&VU1, VUregsn); } +void VU1regsMI_MSUBz(_VURegsNum *VUregsn) { _vuRegsMSUBz(&VU1, VUregsn); } +void VU1regsMI_MSUBw(_VURegsNum *VUregsn) { _vuRegsMSUBw(&VU1, VUregsn); } +void VU1regsMI_MSUBA(_VURegsNum *VUregsn) { _vuRegsMSUBA(&VU1, VUregsn); } +void VU1regsMI_MSUBAi(_VURegsNum *VUregsn) { _vuRegsMSUBAi(&VU1, VUregsn); } +void VU1regsMI_MSUBAq(_VURegsNum *VUregsn) { _vuRegsMSUBAq(&VU1, VUregsn); } +void VU1regsMI_MSUBAx(_VURegsNum *VUregsn) { _vuRegsMSUBAx(&VU1, VUregsn); } +void VU1regsMI_MSUBAy(_VURegsNum *VUregsn) { _vuRegsMSUBAy(&VU1, VUregsn); } +void VU1regsMI_MSUBAz(_VURegsNum *VUregsn) { _vuRegsMSUBAz(&VU1, VUregsn); } +void VU1regsMI_MSUBAw(_VURegsNum *VUregsn) { _vuRegsMSUBAw(&VU1, VUregsn); } +void VU1regsMI_MAX(_VURegsNum *VUregsn) { _vuRegsMAX(&VU1, VUregsn); } +void VU1regsMI_MAXi(_VURegsNum *VUregsn) { _vuRegsMAXi(&VU1, VUregsn); } +void VU1regsMI_MAXx(_VURegsNum *VUregsn) { _vuRegsMAXx(&VU1, VUregsn); } +void VU1regsMI_MAXy(_VURegsNum *VUregsn) { _vuRegsMAXy(&VU1, VUregsn); } +void VU1regsMI_MAXz(_VURegsNum *VUregsn) { _vuRegsMAXz(&VU1, VUregsn); } +void VU1regsMI_MAXw(_VURegsNum *VUregsn) { _vuRegsMAXw(&VU1, VUregsn); } +void VU1regsMI_MINI(_VURegsNum *VUregsn) { _vuRegsMINI(&VU1, VUregsn); } +void VU1regsMI_MINIi(_VURegsNum *VUregsn) { _vuRegsMINIi(&VU1, VUregsn); } +void VU1regsMI_MINIx(_VURegsNum *VUregsn) { _vuRegsMINIx(&VU1, VUregsn); } +void VU1regsMI_MINIy(_VURegsNum *VUregsn) { _vuRegsMINIy(&VU1, VUregsn); } +void VU1regsMI_MINIz(_VURegsNum *VUregsn) { _vuRegsMINIz(&VU1, VUregsn); } +void VU1regsMI_MINIw(_VURegsNum *VUregsn) { _vuRegsMINIw(&VU1, VUregsn); } +void VU1regsMI_OPMULA(_VURegsNum *VUregsn) { _vuRegsOPMULA(&VU1, VUregsn); } +void VU1regsMI_OPMSUB(_VURegsNum *VUregsn) { _vuRegsOPMSUB(&VU1, VUregsn); } +void VU1regsMI_NOP(_VURegsNum *VUregsn) { _vuRegsNOP(&VU1, VUregsn); } +void VU1regsMI_FTOI0(_VURegsNum *VUregsn) { _vuRegsFTOI0(&VU1, VUregsn); } +void VU1regsMI_FTOI4(_VURegsNum *VUregsn) { _vuRegsFTOI4(&VU1, VUregsn); } +void VU1regsMI_FTOI12(_VURegsNum *VUregsn) { _vuRegsFTOI12(&VU1, VUregsn); } +void VU1regsMI_FTOI15(_VURegsNum *VUregsn) { _vuRegsFTOI15(&VU1, VUregsn); } +void VU1regsMI_ITOF0(_VURegsNum *VUregsn) { _vuRegsITOF0(&VU1, VUregsn); } +void VU1regsMI_ITOF4(_VURegsNum *VUregsn) { _vuRegsITOF4(&VU1, VUregsn); } +void VU1regsMI_ITOF12(_VURegsNum *VUregsn) { _vuRegsITOF12(&VU1, VUregsn); } +void VU1regsMI_ITOF15(_VURegsNum *VUregsn) { _vuRegsITOF15(&VU1, VUregsn); } +void VU1regsMI_CLIP(_VURegsNum *VUregsn) { _vuRegsCLIP(&VU1, VUregsn); } + +/*****************************************/ +/* VU Micromode Lower instructions */ +/*****************************************/ + +void VU1regsMI_DIV(_VURegsNum *VUregsn) { _vuRegsDIV(&VU1, VUregsn); } +void VU1regsMI_SQRT(_VURegsNum *VUregsn) { _vuRegsSQRT(&VU1, VUregsn); } +void VU1regsMI_RSQRT(_VURegsNum *VUregsn) { _vuRegsRSQRT(&VU1, VUregsn); } +void VU1regsMI_IADD(_VURegsNum *VUregsn) { _vuRegsIADD(&VU1, VUregsn); } +void VU1regsMI_IADDI(_VURegsNum *VUregsn) { _vuRegsIADDI(&VU1, VUregsn); } +void VU1regsMI_IADDIU(_VURegsNum *VUregsn) { _vuRegsIADDIU(&VU1, VUregsn); } +void VU1regsMI_IAND(_VURegsNum *VUregsn) { _vuRegsIAND(&VU1, VUregsn); } +void VU1regsMI_IOR(_VURegsNum *VUregsn) { _vuRegsIOR(&VU1, VUregsn); } +void VU1regsMI_ISUB(_VURegsNum *VUregsn) { _vuRegsISUB(&VU1, VUregsn); } +void VU1regsMI_ISUBIU(_VURegsNum *VUregsn) { _vuRegsISUBIU(&VU1, VUregsn); } +void VU1regsMI_MOVE(_VURegsNum *VUregsn) { _vuRegsMOVE(&VU1, VUregsn); } +void VU1regsMI_MFIR(_VURegsNum *VUregsn) { _vuRegsMFIR(&VU1, VUregsn); } +void VU1regsMI_MTIR(_VURegsNum *VUregsn) { _vuRegsMTIR(&VU1, VUregsn); } +void VU1regsMI_MR32(_VURegsNum *VUregsn) { _vuRegsMR32(&VU1, VUregsn); } +void VU1regsMI_LQ(_VURegsNum *VUregsn) { _vuRegsLQ(&VU1, VUregsn); } +void VU1regsMI_LQD(_VURegsNum *VUregsn) { _vuRegsLQD(&VU1, VUregsn); } +void VU1regsMI_LQI(_VURegsNum *VUregsn) { _vuRegsLQI(&VU1, VUregsn); } +void VU1regsMI_SQ(_VURegsNum *VUregsn) { _vuRegsSQ(&VU1, VUregsn); } +void VU1regsMI_SQD(_VURegsNum *VUregsn) { _vuRegsSQD(&VU1, VUregsn); } +void VU1regsMI_SQI(_VURegsNum *VUregsn) { _vuRegsSQI(&VU1, VUregsn); } +void VU1regsMI_ILW(_VURegsNum *VUregsn) { _vuRegsILW(&VU1, VUregsn); } +void VU1regsMI_ISW(_VURegsNum *VUregsn) { _vuRegsISW(&VU1, VUregsn); } +void VU1regsMI_ILWR(_VURegsNum *VUregsn) { _vuRegsILWR(&VU1, VUregsn); } +void VU1regsMI_ISWR(_VURegsNum *VUregsn) { _vuRegsISWR(&VU1, VUregsn); } +void VU1regsMI_RINIT(_VURegsNum *VUregsn) { _vuRegsRINIT(&VU1, VUregsn); } +void VU1regsMI_RGET(_VURegsNum *VUregsn) { _vuRegsRGET(&VU1, VUregsn); } +void VU1regsMI_RNEXT(_VURegsNum *VUregsn) { _vuRegsRNEXT(&VU1, VUregsn); } +void VU1regsMI_RXOR(_VURegsNum *VUregsn) { _vuRegsRXOR(&VU1, VUregsn); } +void VU1regsMI_WAITQ(_VURegsNum *VUregsn) { _vuRegsWAITQ(&VU1, VUregsn); } +void VU1regsMI_FSAND(_VURegsNum *VUregsn) { _vuRegsFSAND(&VU1, VUregsn); } +void VU1regsMI_FSEQ(_VURegsNum *VUregsn) { _vuRegsFSEQ(&VU1, VUregsn); } +void VU1regsMI_FSOR(_VURegsNum *VUregsn) { _vuRegsFSOR(&VU1, VUregsn); } +void VU1regsMI_FSSET(_VURegsNum *VUregsn) { _vuRegsFSSET(&VU1, VUregsn); } +void VU1regsMI_FMAND(_VURegsNum *VUregsn) { _vuRegsFMAND(&VU1, VUregsn); } +void VU1regsMI_FMEQ(_VURegsNum *VUregsn) { _vuRegsFMEQ(&VU1, VUregsn); } +void VU1regsMI_FMOR(_VURegsNum *VUregsn) { _vuRegsFMOR(&VU1, VUregsn); } +void VU1regsMI_FCAND(_VURegsNum *VUregsn) { _vuRegsFCAND(&VU1, VUregsn); } +void VU1regsMI_FCEQ(_VURegsNum *VUregsn) { _vuRegsFCEQ(&VU1, VUregsn); } +void VU1regsMI_FCOR(_VURegsNum *VUregsn) { _vuRegsFCOR(&VU1, VUregsn); } +void VU1regsMI_FCSET(_VURegsNum *VUregsn) { _vuRegsFCSET(&VU1, VUregsn); } +void VU1regsMI_FCGET(_VURegsNum *VUregsn) { _vuRegsFCGET(&VU1, VUregsn); } +void VU1regsMI_IBEQ(_VURegsNum *VUregsn) { _vuRegsIBEQ(&VU1, VUregsn); } +void VU1regsMI_IBGEZ(_VURegsNum *VUregsn) { _vuRegsIBGEZ(&VU1, VUregsn); } +void VU1regsMI_IBGTZ(_VURegsNum *VUregsn) { _vuRegsIBGTZ(&VU1, VUregsn); } +void VU1regsMI_IBLTZ(_VURegsNum *VUregsn) { _vuRegsIBLTZ(&VU1, VUregsn); } +void VU1regsMI_IBLEZ(_VURegsNum *VUregsn) { _vuRegsIBLEZ(&VU1, VUregsn); } +void VU1regsMI_IBNE(_VURegsNum *VUregsn) { _vuRegsIBNE(&VU1, VUregsn); } +void VU1regsMI_B(_VURegsNum *VUregsn) { _vuRegsB(&VU1, VUregsn); } +void VU1regsMI_BAL(_VURegsNum *VUregsn) { _vuRegsBAL(&VU1, VUregsn); } +void VU1regsMI_JR(_VURegsNum *VUregsn) { _vuRegsJR(&VU1, VUregsn); } +void VU1regsMI_JALR(_VURegsNum *VUregsn) { _vuRegsJALR(&VU1, VUregsn); } +void VU1regsMI_MFP(_VURegsNum *VUregsn) { _vuRegsMFP(&VU1, VUregsn); } +void VU1regsMI_WAITP(_VURegsNum *VUregsn) { _vuRegsWAITP(&VU1, VUregsn); } +void VU1regsMI_ESADD(_VURegsNum *VUregsn) { _vuRegsESADD(&VU1, VUregsn); } +void VU1regsMI_ERSADD(_VURegsNum *VUregsn) { _vuRegsERSADD(&VU1, VUregsn); } +void VU1regsMI_ELENG(_VURegsNum *VUregsn) { _vuRegsELENG(&VU1, VUregsn); } +void VU1regsMI_ERLENG(_VURegsNum *VUregsn) { _vuRegsERLENG(&VU1, VUregsn); } +void VU1regsMI_EATANxy(_VURegsNum *VUregsn) { _vuRegsEATANxy(&VU1, VUregsn); } +void VU1regsMI_EATANxz(_VURegsNum *VUregsn) { _vuRegsEATANxz(&VU1, VUregsn); } +void VU1regsMI_ESUM(_VURegsNum *VUregsn) { _vuRegsESUM(&VU1, VUregsn); } +void VU1regsMI_ERCPR(_VURegsNum *VUregsn) { _vuRegsERCPR(&VU1, VUregsn); } +void VU1regsMI_ESQRT(_VURegsNum *VUregsn) { _vuRegsESQRT(&VU1, VUregsn); } +void VU1regsMI_ERSQRT(_VURegsNum *VUregsn) { _vuRegsERSQRT(&VU1, VUregsn); } +void VU1regsMI_ESIN(_VURegsNum *VUregsn) { _vuRegsESIN(&VU1, VUregsn); } +void VU1regsMI_EATAN(_VURegsNum *VUregsn) { _vuRegsEATAN(&VU1, VUregsn); } +void VU1regsMI_EEXP(_VURegsNum *VUregsn) { _vuRegsEEXP(&VU1, VUregsn); } +void VU1regsMI_XITOP(_VURegsNum *VUregsn) { _vuRegsXITOP(&VU1, VUregsn); } +void VU1regsMI_XGKICK(_VURegsNum *VUregsn) { _vuRegsXGKICK(&VU1, VUregsn); } +void VU1regsMI_XTOP(_VURegsNum *VUregsn) { _vuRegsXTOP(&VU1, VUregsn); } diff --git a/pcsx2/VU1microInterp.cpp b/pcsx2/VU1microInterp.cpp index 08329cff81..4d5fcd3791 100644 --- a/pcsx2/VU1microInterp.cpp +++ b/pcsx2/VU1microInterp.cpp @@ -1,237 +1,237 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "DebugTools/Debug.h" -#include "VUmicro.h" - -extern void _vuFlushAll(VURegs* VU); - -_vuTables(VU1, VU1); - -void _vu1ExecUpper(VURegs* VU, u32 *ptr) { - VU->code = ptr[1]; - IdebugUPPER(VU1); - VU1_UPPER_OPCODE[VU->code & 0x3f](); -} - -void _vu1ExecLower(VURegs* VU, u32 *ptr) { - VU->code = ptr[0]; - IdebugLOWER(VU1); - VU1_LOWER_OPCODE[VU->code >> 25](); -} - -int vu1branch = 0; - -static void _vu1Exec(VURegs* VU) -{ - _VURegsNum lregs; - _VURegsNum uregs; - VECTOR _VF; - VECTOR _VFc; - REG_VI _VI; - REG_VI _VIc; - u32 *ptr; - int vfreg; - int vireg; - int discard=0; - - if(VU->VI[REG_TPC].UL >= VU->maxmicro){ - CPU_LOG("VU1 memory overflow!!: %x\n", VU->VI[REG_TPC].UL); - VU->VI[REG_TPC].UL &= 0x3FFF; - /*VU0.VI[REG_VPU_STAT].UL&= ~0x100; - VU->cycle++; - return;*/ - } - ptr = (u32*)&VU->Micro[VU->VI[REG_TPC].UL]; - VU->VI[REG_TPC].UL+=8; - - if (ptr[1] & 0x40000000) { /* E flag */ - VU->ebit = 2; - } - if (ptr[1] & 0x10000000) { /* D flag */ - if (VU0.VI[REG_FBRST].UL & 0x400) { - VU0.VI[REG_VPU_STAT].UL|= 0x200; - hwIntcIrq(INTC_VU1); - } - } - if (ptr[1] & 0x08000000) { /* T flag */ - if (VU0.VI[REG_FBRST].UL & 0x800) { - VU0.VI[REG_VPU_STAT].UL|= 0x400; - hwIntcIrq(INTC_VU1); - } - } - - VUM_LOG("VU->cycle = %d (flags st=%x;mac=%x;clip=%x,q=%f)\n", VU->cycle, VU->statusflag, VU->macflag, VU->clipflag, VU->q.F); - - VU->code = ptr[1]; - VU1regs_UPPER_OPCODE[VU->code & 0x3f](&uregs); -#ifndef INT_VUSTALLHACK - _vuTestUpperStalls(VU, &uregs); -#endif - - /* check upper flags */ - if (ptr[1] & 0x80000000) { /* I flag */ - _vu1ExecUpper(VU, ptr); - - VU->VI[REG_I].UL = ptr[0]; - } else { - VU->code = ptr[0]; - VU1regs_LOWER_OPCODE[VU->code >> 25](&lregs); -#ifndef INT_VUSTALLHACK - _vuTestLowerStalls(VU, &lregs); -#endif - - vu1branch = lregs.pipe == VUPIPE_BRANCH; - - vfreg = 0; vireg = 0; - if (uregs.VFwrite) { - if (lregs.VFwrite == uregs.VFwrite) { -// SysPrintf("*PCSX2*: Warning, VF write to the same reg in both lower/upper cycle\n"); - discard = 1; - } - if (lregs.VFread0 == uregs.VFwrite || - lregs.VFread1 == uregs.VFwrite) { -// SysPrintf("saving reg %d at pc=%x\n", i, VU->VI[REG_TPC].UL); - _VF = VU->VF[uregs.VFwrite]; - vfreg = uregs.VFwrite; - } - } - if (uregs.VIread & (1 << REG_CLIP_FLAG)) { - if (lregs.VIwrite & (1 << REG_CLIP_FLAG)) { - SysPrintf("*PCSX2*: Warning, VI write to the same reg in both lower/upper cycle\n"); - discard = 1; - } - if (lregs.VIread & (1 << REG_CLIP_FLAG)) { - _VI = VU->VI[REG_CLIP_FLAG]; - vireg = REG_CLIP_FLAG; - } - } - - _vu1ExecUpper(VU, ptr); - - if (discard == 0) { - if (vfreg) { - _VFc = VU->VF[vfreg]; - VU->VF[vfreg] = _VF; - } - if (vireg) { - _VIc = VU->VI[vireg]; - VU->VI[vireg] = _VI; - } - - _vu1ExecLower(VU, ptr); - - if (vfreg) { - VU->VF[vfreg] = _VFc; - } - if (vireg) { - VU->VI[vireg] = _VIc; - } - } - } - _vuAddUpperStalls(VU, &uregs); - _vuAddLowerStalls(VU, &lregs); - - _vuTestPipes(VU); - - if (VU->branch > 0) { - if (VU->branch-- == 1) { - VU->VI[REG_TPC].UL = VU->branchpc; - } - } - - if( VU->ebit > 0 ) { - if( VU->ebit-- == 1 ) { - _vuFlushAll(VU); - VU0.VI[REG_VPU_STAT].UL&= ~0x100; - vif1Regs->stat&= ~0x4; - } - } -} - -void vu1Exec(VURegs* VU) -{ - _vu1Exec(VU); - VU->cycle++; - - if (VU->VI[0].UL != 0) DbgCon::Error("VI[0] != 0!!!!\n"); - if (VU->VF[0].f.x != 0.0f) DbgCon::Error("VF[0].x != 0.0!!!!\n"); - if (VU->VF[0].f.y != 0.0f) DbgCon::Error("VF[0].y != 0.0!!!!\n"); - if (VU->VF[0].f.z != 0.0f) DbgCon::Error("VF[0].z != 0.0!!!!\n"); - if (VU->VF[0].f.w != 1.0f) DbgCon::Error("VF[0].w != 1.0!!!!\n"); -} - -namespace VU1micro -{ - void intAlloc() - { - } - - void __fastcall intClear(u32 Addr, u32 Size) - { - } - - void intShutdown() - { - } - - static void intReset() - { - } - - static void intStep() - { - vu1Exec( &VU1 ); - } - - static void intExecuteBlock() - { - int i; - #ifdef _DEBUG - int prevbranch; - #endif - - for (i = 128; i--;) { - if ((VU0.VI[REG_VPU_STAT].UL & 0x100) == 0) - break; - - #ifdef _DEBUG - prevbranch = vu1branch; - #endif - vu1Exec(&VU1); - } - - if( i < 0 && (VU1.branch || VU1.ebit) ) { - // execute one more - vu1Exec(&VU1); - } - } -} - -using namespace VU1micro; - -const VUmicroCpu intVU1 = -{ - intReset -, intStep -, intExecuteBlock -, intClear -}; +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "DebugTools/Debug.h" +#include "VUmicro.h" + +extern void _vuFlushAll(VURegs* VU); + +_vuTables(VU1, VU1); + +void _vu1ExecUpper(VURegs* VU, u32 *ptr) { + VU->code = ptr[1]; + IdebugUPPER(VU1); + VU1_UPPER_OPCODE[VU->code & 0x3f](); +} + +void _vu1ExecLower(VURegs* VU, u32 *ptr) { + VU->code = ptr[0]; + IdebugLOWER(VU1); + VU1_LOWER_OPCODE[VU->code >> 25](); +} + +int vu1branch = 0; + +static void _vu1Exec(VURegs* VU) +{ + _VURegsNum lregs; + _VURegsNum uregs; + VECTOR _VF; + VECTOR _VFc; + REG_VI _VI; + REG_VI _VIc; + u32 *ptr; + int vfreg; + int vireg; + int discard=0; + + if(VU->VI[REG_TPC].UL >= VU->maxmicro){ + CPU_LOG("VU1 memory overflow!!: %x\n", VU->VI[REG_TPC].UL); + VU->VI[REG_TPC].UL &= 0x3FFF; + /*VU0.VI[REG_VPU_STAT].UL&= ~0x100; + VU->cycle++; + return;*/ + } + ptr = (u32*)&VU->Micro[VU->VI[REG_TPC].UL]; + VU->VI[REG_TPC].UL+=8; + + if (ptr[1] & 0x40000000) { /* E flag */ + VU->ebit = 2; + } + if (ptr[1] & 0x10000000) { /* D flag */ + if (VU0.VI[REG_FBRST].UL & 0x400) { + VU0.VI[REG_VPU_STAT].UL|= 0x200; + hwIntcIrq(INTC_VU1); + } + } + if (ptr[1] & 0x08000000) { /* T flag */ + if (VU0.VI[REG_FBRST].UL & 0x800) { + VU0.VI[REG_VPU_STAT].UL|= 0x400; + hwIntcIrq(INTC_VU1); + } + } + + VUM_LOG("VU->cycle = %d (flags st=%x;mac=%x;clip=%x,q=%f)\n", VU->cycle, VU->statusflag, VU->macflag, VU->clipflag, VU->q.F); + + VU->code = ptr[1]; + VU1regs_UPPER_OPCODE[VU->code & 0x3f](&uregs); +#ifndef INT_VUSTALLHACK + _vuTestUpperStalls(VU, &uregs); +#endif + + /* check upper flags */ + if (ptr[1] & 0x80000000) { /* I flag */ + _vu1ExecUpper(VU, ptr); + + VU->VI[REG_I].UL = ptr[0]; + } else { + VU->code = ptr[0]; + VU1regs_LOWER_OPCODE[VU->code >> 25](&lregs); +#ifndef INT_VUSTALLHACK + _vuTestLowerStalls(VU, &lregs); +#endif + + vu1branch = lregs.pipe == VUPIPE_BRANCH; + + vfreg = 0; vireg = 0; + if (uregs.VFwrite) { + if (lregs.VFwrite == uregs.VFwrite) { +// SysPrintf("*PCSX2*: Warning, VF write to the same reg in both lower/upper cycle\n"); + discard = 1; + } + if (lregs.VFread0 == uregs.VFwrite || + lregs.VFread1 == uregs.VFwrite) { +// SysPrintf("saving reg %d at pc=%x\n", i, VU->VI[REG_TPC].UL); + _VF = VU->VF[uregs.VFwrite]; + vfreg = uregs.VFwrite; + } + } + if (uregs.VIread & (1 << REG_CLIP_FLAG)) { + if (lregs.VIwrite & (1 << REG_CLIP_FLAG)) { + SysPrintf("*PCSX2*: Warning, VI write to the same reg in both lower/upper cycle\n"); + discard = 1; + } + if (lregs.VIread & (1 << REG_CLIP_FLAG)) { + _VI = VU->VI[REG_CLIP_FLAG]; + vireg = REG_CLIP_FLAG; + } + } + + _vu1ExecUpper(VU, ptr); + + if (discard == 0) { + if (vfreg) { + _VFc = VU->VF[vfreg]; + VU->VF[vfreg] = _VF; + } + if (vireg) { + _VIc = VU->VI[vireg]; + VU->VI[vireg] = _VI; + } + + _vu1ExecLower(VU, ptr); + + if (vfreg) { + VU->VF[vfreg] = _VFc; + } + if (vireg) { + VU->VI[vireg] = _VIc; + } + } + } + _vuAddUpperStalls(VU, &uregs); + _vuAddLowerStalls(VU, &lregs); + + _vuTestPipes(VU); + + if (VU->branch > 0) { + if (VU->branch-- == 1) { + VU->VI[REG_TPC].UL = VU->branchpc; + } + } + + if( VU->ebit > 0 ) { + if( VU->ebit-- == 1 ) { + _vuFlushAll(VU); + VU0.VI[REG_VPU_STAT].UL&= ~0x100; + vif1Regs->stat&= ~0x4; + } + } +} + +void vu1Exec(VURegs* VU) +{ + _vu1Exec(VU); + VU->cycle++; + + if (VU->VI[0].UL != 0) DbgCon::Error("VI[0] != 0!!!!\n"); + if (VU->VF[0].f.x != 0.0f) DbgCon::Error("VF[0].x != 0.0!!!!\n"); + if (VU->VF[0].f.y != 0.0f) DbgCon::Error("VF[0].y != 0.0!!!!\n"); + if (VU->VF[0].f.z != 0.0f) DbgCon::Error("VF[0].z != 0.0!!!!\n"); + if (VU->VF[0].f.w != 1.0f) DbgCon::Error("VF[0].w != 1.0!!!!\n"); +} + +namespace VU1micro +{ + void intAlloc() + { + } + + void __fastcall intClear(u32 Addr, u32 Size) + { + } + + void intShutdown() + { + } + + static void intReset() + { + } + + static void intStep() + { + vu1Exec( &VU1 ); + } + + static void intExecuteBlock() + { + int i; + #ifdef _DEBUG + int prevbranch; + #endif + + for (i = 128; i--;) { + if ((VU0.VI[REG_VPU_STAT].UL & 0x100) == 0) + break; + + #ifdef _DEBUG + prevbranch = vu1branch; + #endif + vu1Exec(&VU1); + } + + if( i < 0 && (VU1.branch || VU1.ebit) ) { + // execute one more + vu1Exec(&VU1); + } + } +} + +using namespace VU1micro; + +const VUmicroCpu intVU1 = +{ + intReset +, intStep +, intExecuteBlock +, intClear +}; diff --git a/pcsx2/VUflags.cpp b/pcsx2/VUflags.cpp index 84b43aad05..96ded42a22 100644 --- a/pcsx2/VUflags.cpp +++ b/pcsx2/VUflags.cpp @@ -1,124 +1,124 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include -#include - -#include "Common.h" -#include "VUmicro.h" -/*****************************************/ -/* NEW FLAGS */ //By asadr. Thnkx F|RES :p -/*****************************************/ - - -__inline void vuUpdateDI(VURegs * VU) { -// u32 Flag_S = 0; -// u32 Flag_I = 0; -// u32 Flag_D = 0; -// -// /* -// FLAG D - I -// */ -// Flag_I = (VU->statusflag >> 4) & 0x1; -// Flag_D = (VU->statusflag >> 5) & 0x1; -// -// VU->statusflag|= (Flag_I | (VU0.VI[REG_STATUS_FLAG].US[0] >> 4)) << 10; -// VU->statusflag|= (Flag_D | (VU0.VI[REG_STATUS_FLAG].US[0] >> 5)) << 11; -} - -__forceinline u32 VU_MAC_UPDATE( int shift, VURegs * VU, float f) -{ - u32 v = *(u32*)&f; - int exp = (v >> 23) & 0xff; - u32 s = v & 0x80000000; - - if (s) - VU->macflag |= 0x0010<macflag &= ~(0x0010<macflag = (VU->macflag & ~(0x1100<macflag = (VU->macflag&~(0x1000<macflag = (VU->macflag&~(0x0100<macflag = (VU->macflag & ~(0x1101<macflag&= ~(0x1111<<3); -} - -__forceinline void VU_MACy_CLEAR(VURegs * VU) -{ - VU->macflag&= ~(0x1111<<2); -} - -__forceinline void VU_MACz_CLEAR(VURegs * VU) -{ - VU->macflag&= ~(0x1111<<1); -} - -__forceinline void VU_MACw_CLEAR(VURegs * VU) -{ - VU->macflag&= ~(0x1111<<0); -} - -void VU_STAT_UPDATE(VURegs * VU) { - int newflag = 0 ; - if (VU->macflag & 0x000F) newflag = 0x1; - if (VU->macflag & 0x00F0) newflag |= 0x2; - if (VU->macflag & 0x0F00) newflag |= 0x4; - if (VU->macflag & 0xF000) newflag |= 0x8; - VU->statusflag = (VU->statusflag&0xc30)|newflag|((VU->statusflag&0xf)<<6); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include +#include + +#include "Common.h" +#include "VUmicro.h" +/*****************************************/ +/* NEW FLAGS */ //By asadr. Thnkx F|RES :p +/*****************************************/ + + +__inline void vuUpdateDI(VURegs * VU) { +// u32 Flag_S = 0; +// u32 Flag_I = 0; +// u32 Flag_D = 0; +// +// /* +// FLAG D - I +// */ +// Flag_I = (VU->statusflag >> 4) & 0x1; +// Flag_D = (VU->statusflag >> 5) & 0x1; +// +// VU->statusflag|= (Flag_I | (VU0.VI[REG_STATUS_FLAG].US[0] >> 4)) << 10; +// VU->statusflag|= (Flag_D | (VU0.VI[REG_STATUS_FLAG].US[0] >> 5)) << 11; +} + +__forceinline u32 VU_MAC_UPDATE( int shift, VURegs * VU, float f) +{ + u32 v = *(u32*)&f; + int exp = (v >> 23) & 0xff; + u32 s = v & 0x80000000; + + if (s) + VU->macflag |= 0x0010<macflag &= ~(0x0010<macflag = (VU->macflag & ~(0x1100<macflag = (VU->macflag&~(0x1000<macflag = (VU->macflag&~(0x0100<macflag = (VU->macflag & ~(0x1101<macflag&= ~(0x1111<<3); +} + +__forceinline void VU_MACy_CLEAR(VURegs * VU) +{ + VU->macflag&= ~(0x1111<<2); +} + +__forceinline void VU_MACz_CLEAR(VURegs * VU) +{ + VU->macflag&= ~(0x1111<<1); +} + +__forceinline void VU_MACw_CLEAR(VURegs * VU) +{ + VU->macflag&= ~(0x1111<<0); +} + +void VU_STAT_UPDATE(VURegs * VU) { + int newflag = 0 ; + if (VU->macflag & 0x000F) newflag = 0x1; + if (VU->macflag & 0x00F0) newflag |= 0x2; + if (VU->macflag & 0x0F00) newflag |= 0x4; + if (VU->macflag & 0xF000) newflag |= 0x8; + VU->statusflag = (VU->statusflag&0xc30)|newflag|((VU->statusflag&0xf)<<6); +} diff --git a/pcsx2/VUflags.h b/pcsx2/VUflags.h index cd6dcca5b7..4ecc98d5ab 100644 --- a/pcsx2/VUflags.h +++ b/pcsx2/VUflags.h @@ -1,39 +1,39 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __VUFLAGS_H__ -#define __VUFLAGS_H__ - -#include "VU.h" - -void vuUpdateDI(VURegs * VU); -__forceinline u32 VU_MAC_UPDATE( int shift, VURegs * VU, float f); -__forceinline u32 VU_MACx_UPDATE(VURegs * VU, float x); -__forceinline u32 VU_MACy_UPDATE(VURegs * VU, float y); -__forceinline u32 VU_MACz_UPDATE(VURegs * VU, float z); -__forceinline u32 VU_MACw_UPDATE(VURegs * VU, float w); -__forceinline void VU_MACx_CLEAR(VURegs * VU); -__forceinline void VU_MACy_CLEAR(VURegs * VU); -__forceinline void VU_MACz_CLEAR(VURegs * VU); -__forceinline void VU_MACw_CLEAR(VURegs * VU); -void VU_STAT_UPDATE(VURegs * VU); - - -#endif - - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __VUFLAGS_H__ +#define __VUFLAGS_H__ + +#include "VU.h" + +void vuUpdateDI(VURegs * VU); +__forceinline u32 VU_MAC_UPDATE( int shift, VURegs * VU, float f); +__forceinline u32 VU_MACx_UPDATE(VURegs * VU, float x); +__forceinline u32 VU_MACy_UPDATE(VURegs * VU, float y); +__forceinline u32 VU_MACz_UPDATE(VURegs * VU, float z); +__forceinline u32 VU_MACw_UPDATE(VURegs * VU, float w); +__forceinline void VU_MACx_CLEAR(VURegs * VU); +__forceinline void VU_MACy_CLEAR(VURegs * VU); +__forceinline void VU_MACz_CLEAR(VURegs * VU); +__forceinline void VU_MACw_CLEAR(VURegs * VU); +void VU_STAT_UPDATE(VURegs * VU); + + +#endif + + diff --git a/pcsx2/VUmicro.h b/pcsx2/VUmicro.h index 3c7199a8c5..71fbc99982 100644 --- a/pcsx2/VUmicro.h +++ b/pcsx2/VUmicro.h @@ -1,1314 +1,1314 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __VUMICRO_H__ -#define __VUMICRO_H__ - -#include "VU.h" - -struct VUmicroCpu -{ - void (*Reset)(); - void (*Step)(); - void (*ExecuteBlock)(); // VUs should support block-level execution only. - void (__fastcall *Clear)(u32 Addr, u32 Size); -}; - -extern VUmicroCpu CpuVU0; -extern const VUmicroCpu intVU0; -extern const VUmicroCpu recVU0; - -extern VUmicroCpu CpuVU1; -extern const VUmicroCpu intVU1; -extern const VUmicroCpu recVU1; - -namespace VU0micro -{ - extern void recAlloc(); - extern void recShutdown(); - extern void __fastcall recClear(u32 Addr, u32 Size); - - // Note: Interpreter functions are dummies -- they don't actually do anything. - extern void intAlloc(); - extern void intShutdown(); - extern void __fastcall intClear(u32 Addr, u32 Size); -} - -namespace VU1micro -{ - extern void recAlloc(); - extern void recShutdown(); - extern void __fastcall recClear(u32 Addr, u32 Size); - - // Note: Interpreter functions are dummies -- they don't actually do anything. - extern void intAlloc(); - extern void intShutdown(); - extern void __fastcall intClear(u32 Addr, u32 Size); -} - -///////////////////////////////////////////////////////////////// -// These functions initialize memory for both VUs. -// -void vuMicroMemAlloc(); -void vuMicroMemShutdown(); -void vuMicroMemReset(); - -// Resets VUs and assigns the cpuVU0 / cpuVU1 pointers as according to -// the CHECK_VU0REC / CHECK_VU1REC config options. -void vuMicroCpuReset(); - -///////////////////////////////////////////////////////////////// -// Everything else does stuff on a per-VU basis. -// -void iDumpVU0Registers(); -void iDumpVU1Registers(); - - -extern void (*VU0_LOWER_OPCODE[128])(); -extern void (*VU0_UPPER_OPCODE[64])(); - -extern void (*VU0_UPPER_FD_00_TABLE[32])(); -extern void (*VU0_UPPER_FD_01_TABLE[32])(); -extern void (*VU0_UPPER_FD_10_TABLE[32])(); -extern void (*VU0_UPPER_FD_11_TABLE[32])(); - -extern void (*VU0regs_LOWER_OPCODE[128])(_VURegsNum *VUregsn); -extern void (*VU0regs_UPPER_OPCODE[64])(_VURegsNum *VUregsn); - -extern void (*VU0regs_UPPER_FD_00_TABLE[32])(_VURegsNum *VUregsn); -extern void (*VU0regs_UPPER_FD_01_TABLE[32])(_VURegsNum *VUregsn); -extern void (*VU0regs_UPPER_FD_10_TABLE[32])(_VURegsNum *VUregsn); -extern void (*VU0regs_UPPER_FD_11_TABLE[32])(_VURegsNum *VUregsn); - -extern void (*VU1_LOWER_OPCODE[128])(); -extern void (*VU1_UPPER_OPCODE[64])(); - -extern void (*VU1_UPPER_FD_00_TABLE[32])(); -extern void (*VU1_UPPER_FD_01_TABLE[32])(); -extern void (*VU1_UPPER_FD_10_TABLE[32])(); -extern void (*VU1_UPPER_FD_11_TABLE[32])(); - -extern void (*VU1regs_LOWER_OPCODE[128])(_VURegsNum *VUregsn); -extern void (*VU1regs_UPPER_OPCODE[64])(_VURegsNum *VUregsn); - -extern void (*VU1regs_UPPER_FD_00_TABLE[32])(_VURegsNum *VUregsn); -extern void (*VU1regs_UPPER_FD_01_TABLE[32])(_VURegsNum *VUregsn); -extern void (*VU1regs_UPPER_FD_10_TABLE[32])(_VURegsNum *VUregsn); -extern void (*VU1regs_UPPER_FD_11_TABLE[32])(_VURegsNum *VUregsn); - -// VU0 -extern void vu0ResetRegs(); -extern void vu0ExecMicro(u32 addr); -extern void vu0Exec(VURegs* VU); -extern void vu0Finish(); -extern void recResetVU0( void ); - -// VU1 -extern void vu1ResetRegs(); -extern void vu1ExecMicro(u32 addr); -extern void vu1Exec(VURegs* VU); - -extern void vu1MicroEnableSkip(); -extern void vu1MicroDisableSkip(); -extern bool vu1MicroIsSkipping(); - -void VU0_UPPER_FD_00(); -void VU0_UPPER_FD_01(); -void VU0_UPPER_FD_10(); -void VU0_UPPER_FD_11(); - -void VU0LowerOP(); -void VU0LowerOP_T3_00(); -void VU0LowerOP_T3_01(); -void VU0LowerOP_T3_10(); -void VU0LowerOP_T3_11(); - -void VU0unknown(); - -void VU1_UPPER_FD_00(); -void VU1_UPPER_FD_01(); -void VU1_UPPER_FD_10(); -void VU1_UPPER_FD_11(); - -void VU1LowerOP(); -void VU1LowerOP_T3_00(); -void VU1LowerOP_T3_01(); -void VU1LowerOP_T3_10(); -void VU1LowerOP_T3_11(); - -void VU1unknown(); - -void VU0regs_UPPER_FD_00(_VURegsNum *VUregsn); -void VU0regs_UPPER_FD_01(_VURegsNum *VUregsn); -void VU0regs_UPPER_FD_10(_VURegsNum *VUregsn); -void VU0regs_UPPER_FD_11(_VURegsNum *VUregsn); - -void VU0regsLowerOP(_VURegsNum *VUregsn); -void VU0regsLowerOP_T3_00(_VURegsNum *VUregsn); -void VU0regsLowerOP_T3_01(_VURegsNum *VUregsn); -void VU0regsLowerOP_T3_10(_VURegsNum *VUregsn); -void VU0regsLowerOP_T3_11(_VURegsNum *VUregsn); - -void VU0regsunknown(_VURegsNum *VUregsn); - -void VU1regs_UPPER_FD_00(_VURegsNum *VUregsn); -void VU1regs_UPPER_FD_01(_VURegsNum *VUregsn); -void VU1regs_UPPER_FD_10(_VURegsNum *VUregsn); -void VU1regs_UPPER_FD_11(_VURegsNum *VUregsn); - -void VU1regsLowerOP(_VURegsNum *VUregsn); -void VU1regsLowerOP_T3_00(_VURegsNum *VUregsn); -void VU1regsLowerOP_T3_01(_VURegsNum *VUregsn); -void VU1regsLowerOP_T3_10(_VURegsNum *VUregsn); -void VU1regsLowerOP_T3_11(_VURegsNum *VUregsn); - -void VU1regsunknown(_VURegsNum *VUregsn); - -/***************************************** - VU0 Micromode Upper instructions -*****************************************/ - -void VU0MI_ABS(); -void VU0MI_ADD(); -void VU0MI_ADDi(); -void VU0MI_ADDq(); -void VU0MI_ADDx(); -void VU0MI_ADDy(); -void VU0MI_ADDz(); -void VU0MI_ADDw(); -void VU0MI_ADDA(); -void VU0MI_ADDAi(); -void VU0MI_ADDAq(); -void VU0MI_ADDAx(); -void VU0MI_ADDAy(); -void VU0MI_ADDAz(); -void VU0MI_ADDAw(); -void VU0MI_SUB(); -void VU0MI_SUBi(); -void VU0MI_SUBq(); -void VU0MI_SUBx(); -void VU0MI_SUBy(); -void VU0MI_SUBz(); -void VU0MI_SUBw(); -void VU0MI_SUBA(); -void VU0MI_SUBAi(); -void VU0MI_SUBAq(); -void VU0MI_SUBAx(); -void VU0MI_SUBAy(); -void VU0MI_SUBAz(); -void VU0MI_SUBAw(); -void VU0MI_MUL(); -void VU0MI_MULi(); -void VU0MI_MULq(); -void VU0MI_MULx(); -void VU0MI_MULy(); -void VU0MI_MULz(); -void VU0MI_MULw(); -void VU0MI_MULA(); -void VU0MI_MULAi(); -void VU0MI_MULAq(); -void VU0MI_MULAx(); -void VU0MI_MULAy(); -void VU0MI_MULAz(); -void VU0MI_MULAw(); -void VU0MI_MADD(); -void VU0MI_MADDi(); -void VU0MI_MADDq(); -void VU0MI_MADDx(); -void VU0MI_MADDy(); -void VU0MI_MADDz(); -void VU0MI_MADDw(); -void VU0MI_MADDA(); -void VU0MI_MADDAi(); -void VU0MI_MADDAq(); -void VU0MI_MADDAx(); -void VU0MI_MADDAy(); -void VU0MI_MADDAz(); -void VU0MI_MADDAw(); -void VU0MI_MSUB(); -void VU0MI_MSUBi(); -void VU0MI_MSUBq(); -void VU0MI_MSUBx(); -void VU0MI_MSUBy(); -void VU0MI_MSUBz(); -void VU0MI_MSUBw(); -void VU0MI_MSUBA(); -void VU0MI_MSUBAi(); -void VU0MI_MSUBAq(); -void VU0MI_MSUBAx(); -void VU0MI_MSUBAy(); -void VU0MI_MSUBAz(); -void VU0MI_MSUBAw(); -void VU0MI_MAX(); -void VU0MI_MAXi(); -void VU0MI_MAXx(); -void VU0MI_MAXy(); -void VU0MI_MAXz(); -void VU0MI_MAXw(); -void VU0MI_MINI(); -void VU0MI_MINIi(); -void VU0MI_MINIx(); -void VU0MI_MINIy(); -void VU0MI_MINIz(); -void VU0MI_MINIw(); -void VU0MI_OPMULA(); -void VU0MI_OPMSUB(); -void VU0MI_NOP(); -void VU0MI_FTOI0(); -void VU0MI_FTOI4(); -void VU0MI_FTOI12(); -void VU0MI_FTOI15(); -void VU0MI_ITOF0(); -void VU0MI_ITOF4(); -void VU0MI_ITOF12(); -void VU0MI_ITOF15(); -void VU0MI_CLIP(); - -/***************************************** - VU0 Micromode Lower instructions -*****************************************/ - -void VU0MI_DIV(); -void VU0MI_SQRT(); -void VU0MI_RSQRT(); -void VU0MI_IADD(); -void VU0MI_IADDI(); -void VU0MI_IADDIU(); -void VU0MI_IAND(); -void VU0MI_IOR(); -void VU0MI_ISUB(); -void VU0MI_ISUBIU(); -void VU0MI_MOVE(); -void VU0MI_MFIR(); -void VU0MI_MTIR(); -void VU0MI_MR32(); -void VU0MI_LQ(); -void VU0MI_LQD(); -void VU0MI_LQI(); -void VU0MI_SQ(); -void VU0MI_SQD(); -void VU0MI_SQI(); -void VU0MI_ILW(); -void VU0MI_ISW(); -void VU0MI_ILWR(); -void VU0MI_ISWR(); -void VU0MI_LOI(); -void VU0MI_RINIT(); -void VU0MI_RGET(); -void VU0MI_RNEXT(); -void VU0MI_RXOR(); -void VU0MI_WAITQ(); -void VU0MI_FSAND(); -void VU0MI_FSEQ(); -void VU0MI_FSOR(); -void VU0MI_FSSET(); -void VU0MI_FMAND(); -void VU0MI_FMEQ(); -void VU0MI_FMOR(); -void VU0MI_FCAND(); -void VU0MI_FCEQ(); -void VU0MI_FCOR(); -void VU0MI_FCSET(); -void VU0MI_FCGET(); -void VU0MI_IBEQ(); -void VU0MI_IBGEZ(); -void VU0MI_IBGTZ(); -void VU0MI_IBLEZ(); -void VU0MI_IBLTZ(); -void VU0MI_IBNE(); -void VU0MI_B(); -void VU0MI_BAL(); -void VU0MI_JR(); -void VU0MI_JALR(); -void VU0MI_MFP(); -void VU0MI_WAITP(); -void VU0MI_ESADD(); -void VU0MI_ERSADD(); -void VU0MI_ELENG(); -void VU0MI_ERLENG(); -void VU0MI_EATANxy(); -void VU0MI_EATANxz(); -void VU0MI_ESUM(); -void VU0MI_ERCPR(); -void VU0MI_ESQRT(); -void VU0MI_ERSQRT(); -void VU0MI_ESIN(); -void VU0MI_EATAN(); -void VU0MI_EEXP(); -void VU0MI_XGKICK(); -void VU0MI_XTOP(); -void VU0MI_XITOP(); - -/***************************************** - VU1 Micromode Upper instructions -*****************************************/ - -void VU0regsMI_ABS(_VURegsNum *VUregsn); -void VU0regsMI_ADD(_VURegsNum *VUregsn); -void VU0regsMI_ADDi(_VURegsNum *VUregsn); -void VU0regsMI_ADDq(_VURegsNum *VUregsn); -void VU0regsMI_ADDx(_VURegsNum *VUregsn); -void VU0regsMI_ADDy(_VURegsNum *VUregsn); -void VU0regsMI_ADDz(_VURegsNum *VUregsn); -void VU0regsMI_ADDw(_VURegsNum *VUregsn); -void VU0regsMI_ADDA(_VURegsNum *VUregsn); -void VU0regsMI_ADDAi(_VURegsNum *VUregsn); -void VU0regsMI_ADDAq(_VURegsNum *VUregsn); -void VU0regsMI_ADDAx(_VURegsNum *VUregsn); -void VU0regsMI_ADDAy(_VURegsNum *VUregsn); -void VU0regsMI_ADDAz(_VURegsNum *VUregsn); -void VU0regsMI_ADDAw(_VURegsNum *VUregsn); -void VU0regsMI_SUB(_VURegsNum *VUregsn); -void VU0regsMI_SUBi(_VURegsNum *VUregsn); -void VU0regsMI_SUBq(_VURegsNum *VUregsn); -void VU0regsMI_SUBx(_VURegsNum *VUregsn); -void VU0regsMI_SUBy(_VURegsNum *VUregsn); -void VU0regsMI_SUBz(_VURegsNum *VUregsn); -void VU0regsMI_SUBw(_VURegsNum *VUregsn); -void VU0regsMI_SUBA(_VURegsNum *VUregsn); -void VU0regsMI_SUBAi(_VURegsNum *VUregsn); -void VU0regsMI_SUBAq(_VURegsNum *VUregsn); -void VU0regsMI_SUBAx(_VURegsNum *VUregsn); -void VU0regsMI_SUBAy(_VURegsNum *VUregsn); -void VU0regsMI_SUBAz(_VURegsNum *VUregsn); -void VU0regsMI_SUBAw(_VURegsNum *VUregsn); -void VU0regsMI_MUL(_VURegsNum *VUregsn); -void VU0regsMI_MULi(_VURegsNum *VUregsn); -void VU0regsMI_MULq(_VURegsNum *VUregsn); -void VU0regsMI_MULx(_VURegsNum *VUregsn); -void VU0regsMI_MULy(_VURegsNum *VUregsn); -void VU0regsMI_MULz(_VURegsNum *VUregsn); -void VU0regsMI_MULw(_VURegsNum *VUregsn); -void VU0regsMI_MULA(_VURegsNum *VUregsn); -void VU0regsMI_MULAi(_VURegsNum *VUregsn); -void VU0regsMI_MULAq(_VURegsNum *VUregsn); -void VU0regsMI_MULAx(_VURegsNum *VUregsn); -void VU0regsMI_MULAy(_VURegsNum *VUregsn); -void VU0regsMI_MULAz(_VURegsNum *VUregsn); -void VU0regsMI_MULAw(_VURegsNum *VUregsn); -void VU0regsMI_MADD(_VURegsNum *VUregsn); -void VU0regsMI_MADDi(_VURegsNum *VUregsn); -void VU0regsMI_MADDq(_VURegsNum *VUregsn); -void VU0regsMI_MADDx(_VURegsNum *VUregsn); -void VU0regsMI_MADDy(_VURegsNum *VUregsn); -void VU0regsMI_MADDz(_VURegsNum *VUregsn); -void VU0regsMI_MADDw(_VURegsNum *VUregsn); -void VU0regsMI_MADDA(_VURegsNum *VUregsn); -void VU0regsMI_MADDAi(_VURegsNum *VUregsn); -void VU0regsMI_MADDAq(_VURegsNum *VUregsn); -void VU0regsMI_MADDAx(_VURegsNum *VUregsn); -void VU0regsMI_MADDAy(_VURegsNum *VUregsn); -void VU0regsMI_MADDAz(_VURegsNum *VUregsn); -void VU0regsMI_MADDAw(_VURegsNum *VUregsn); -void VU0regsMI_MSUB(_VURegsNum *VUregsn); -void VU0regsMI_MSUBi(_VURegsNum *VUregsn); -void VU0regsMI_MSUBq(_VURegsNum *VUregsn); -void VU0regsMI_MSUBx(_VURegsNum *VUregsn); -void VU0regsMI_MSUBy(_VURegsNum *VUregsn); -void VU0regsMI_MSUBz(_VURegsNum *VUregsn); -void VU0regsMI_MSUBw(_VURegsNum *VUregsn); -void VU0regsMI_MSUBA(_VURegsNum *VUregsn); -void VU0regsMI_MSUBAi(_VURegsNum *VUregsn); -void VU0regsMI_MSUBAq(_VURegsNum *VUregsn); -void VU0regsMI_MSUBAx(_VURegsNum *VUregsn); -void VU0regsMI_MSUBAy(_VURegsNum *VUregsn); -void VU0regsMI_MSUBAz(_VURegsNum *VUregsn); -void VU0regsMI_MSUBAw(_VURegsNum *VUregsn); -void VU0regsMI_MAX(_VURegsNum *VUregsn); -void VU0regsMI_MAXi(_VURegsNum *VUregsn); -void VU0regsMI_MAXx(_VURegsNum *VUregsn); -void VU0regsMI_MAXy(_VURegsNum *VUregsn); -void VU0regsMI_MAXz(_VURegsNum *VUregsn); -void VU0regsMI_MAXw(_VURegsNum *VUregsn); -void VU0regsMI_MINI(_VURegsNum *VUregsn); -void VU0regsMI_MINIi(_VURegsNum *VUregsn); -void VU0regsMI_MINIx(_VURegsNum *VUregsn); -void VU0regsMI_MINIy(_VURegsNum *VUregsn); -void VU0regsMI_MINIz(_VURegsNum *VUregsn); -void VU0regsMI_MINIw(_VURegsNum *VUregsn); -void VU0regsMI_OPMULA(_VURegsNum *VUregsn); -void VU0regsMI_OPMSUB(_VURegsNum *VUregsn); -void VU0regsMI_NOP(_VURegsNum *VUregsn); -void VU0regsMI_FTOI0(_VURegsNum *VUregsn); -void VU0regsMI_FTOI4(_VURegsNum *VUregsn); -void VU0regsMI_FTOI12(_VURegsNum *VUregsn); -void VU0regsMI_FTOI15(_VURegsNum *VUregsn); -void VU0regsMI_ITOF0(_VURegsNum *VUregsn); -void VU0regsMI_ITOF4(_VURegsNum *VUregsn); -void VU0regsMI_ITOF12(_VURegsNum *VUregsn); -void VU0regsMI_ITOF15(_VURegsNum *VUregsn); -void VU0regsMI_CLIP(_VURegsNum *VUregsn); - -/***************************************** - VU0 Micromode Lower instructions -*****************************************/ - -void VU0regsMI_DIV(_VURegsNum *VUregsn); -void VU0regsMI_SQRT(_VURegsNum *VUregsn); -void VU0regsMI_RSQRT(_VURegsNum *VUregsn); -void VU0regsMI_IADD(_VURegsNum *VUregsn); -void VU0regsMI_IADDI(_VURegsNum *VUregsn); -void VU0regsMI_IADDIU(_VURegsNum *VUregsn); -void VU0regsMI_IAND(_VURegsNum *VUregsn); -void VU0regsMI_IOR(_VURegsNum *VUregsn); -void VU0regsMI_ISUB(_VURegsNum *VUregsn); -void VU0regsMI_ISUBIU(_VURegsNum *VUregsn); -void VU0regsMI_MOVE(_VURegsNum *VUregsn); -void VU0regsMI_MFIR(_VURegsNum *VUregsn); -void VU0regsMI_MTIR(_VURegsNum *VUregsn); -void VU0regsMI_MR32(_VURegsNum *VUregsn); -void VU0regsMI_LQ(_VURegsNum *VUregsn); -void VU0regsMI_LQD(_VURegsNum *VUregsn); -void VU0regsMI_LQI(_VURegsNum *VUregsn); -void VU0regsMI_SQ(_VURegsNum *VUregsn); -void VU0regsMI_SQD(_VURegsNum *VUregsn); -void VU0regsMI_SQI(_VURegsNum *VUregsn); -void VU0regsMI_ILW(_VURegsNum *VUregsn); -void VU0regsMI_ISW(_VURegsNum *VUregsn); -void VU0regsMI_ILWR(_VURegsNum *VUregsn); -void VU0regsMI_ISWR(_VURegsNum *VUregsn); -void VU0regsMI_LOI(_VURegsNum *VUregsn); -void VU0regsMI_RINIT(_VURegsNum *VUregsn); -void VU0regsMI_RGET(_VURegsNum *VUregsn); -void VU0regsMI_RNEXT(_VURegsNum *VUregsn); -void VU0regsMI_RXOR(_VURegsNum *VUregsn); -void VU0regsMI_WAITQ(_VURegsNum *VUregsn); -void VU0regsMI_FSAND(_VURegsNum *VUregsn); -void VU0regsMI_FSEQ(_VURegsNum *VUregsn); -void VU0regsMI_FSOR(_VURegsNum *VUregsn); -void VU0regsMI_FSSET(_VURegsNum *VUregsn); -void VU0regsMI_FMAND(_VURegsNum *VUregsn); -void VU0regsMI_FMEQ(_VURegsNum *VUregsn); -void VU0regsMI_FMOR(_VURegsNum *VUregsn); -void VU0regsMI_FCAND(_VURegsNum *VUregsn); -void VU0regsMI_FCEQ(_VURegsNum *VUregsn); -void VU0regsMI_FCOR(_VURegsNum *VUregsn); -void VU0regsMI_FCSET(_VURegsNum *VUregsn); -void VU0regsMI_FCGET(_VURegsNum *VUregsn); -void VU0regsMI_IBEQ(_VURegsNum *VUregsn); -void VU0regsMI_IBGEZ(_VURegsNum *VUregsn); -void VU0regsMI_IBGTZ(_VURegsNum *VUregsn); -void VU0regsMI_IBLTZ(_VURegsNum *VUregsn); -void VU0regsMI_IBLEZ(_VURegsNum *VUregsn); -void VU0regsMI_IBNE(_VURegsNum *VUregsn); -void VU0regsMI_B(_VURegsNum *VUregsn); -void VU0regsMI_BAL(_VURegsNum *VUregsn); -void VU0regsMI_JR(_VURegsNum *VUregsn); -void VU0regsMI_JALR(_VURegsNum *VUregsn); -void VU0regsMI_MFP(_VURegsNum *VUregsn); -void VU0regsMI_WAITP(_VURegsNum *VUregsn); -void VU0regsMI_ESADD(_VURegsNum *VUregsn); -void VU0regsMI_ERSADD(_VURegsNum *VUregsn); -void VU0regsMI_ELENG(_VURegsNum *VUregsn); -void VU0regsMI_ERLENG(_VURegsNum *VUregsn); -void VU0regsMI_EATANxy(_VURegsNum *VUregsn); -void VU0regsMI_EATANxz(_VURegsNum *VUregsn); -void VU0regsMI_ESUM(_VURegsNum *VUregsn); -void VU0regsMI_ERCPR(_VURegsNum *VUregsn); -void VU0regsMI_ESQRT(_VURegsNum *VUregsn); -void VU0regsMI_ERSQRT(_VURegsNum *VUregsn); -void VU0regsMI_ESIN(_VURegsNum *VUregsn); -void VU0regsMI_EATAN(_VURegsNum *VUregsn); -void VU0regsMI_EEXP(_VURegsNum *VUregsn); -void VU0regsMI_XGKICK(_VURegsNum *VUregsn); -void VU0regsMI_XTOP(_VURegsNum *VUregsn); -void VU0regsMI_XITOP(_VURegsNum *VUregsn); - -/***************************************** - VU1 Micromode Upper instructions -*****************************************/ - -void VU1MI_ABS(); -void VU1MI_ADD(); -void VU1MI_ADDi(); -void VU1MI_ADDq(); -void VU1MI_ADDx(); -void VU1MI_ADDy(); -void VU1MI_ADDz(); -void VU1MI_ADDw(); -void VU1MI_ADDA(); -void VU1MI_ADDAi(); -void VU1MI_ADDAq(); -void VU1MI_ADDAx(); -void VU1MI_ADDAy(); -void VU1MI_ADDAz(); -void VU1MI_ADDAw(); -void VU1MI_SUB(); -void VU1MI_SUBi(); -void VU1MI_SUBq(); -void VU1MI_SUBx(); -void VU1MI_SUBy(); -void VU1MI_SUBz(); -void VU1MI_SUBw(); -void VU1MI_SUBA(); -void VU1MI_SUBAi(); -void VU1MI_SUBAq(); -void VU1MI_SUBAx(); -void VU1MI_SUBAy(); -void VU1MI_SUBAz(); -void VU1MI_SUBAw(); -void VU1MI_MUL(); -void VU1MI_MULi(); -void VU1MI_MULq(); -void VU1MI_MULx(); -void VU1MI_MULy(); -void VU1MI_MULz(); -void VU1MI_MULw(); -void VU1MI_MULA(); -void VU1MI_MULAi(); -void VU1MI_MULAq(); -void VU1MI_MULAx(); -void VU1MI_MULAy(); -void VU1MI_MULAz(); -void VU1MI_MULAw(); -void VU1MI_MADD(); -void VU1MI_MADDi(); -void VU1MI_MADDq(); -void VU1MI_MADDx(); -void VU1MI_MADDy(); -void VU1MI_MADDz(); -void VU1MI_MADDw(); -void VU1MI_MADDA(); -void VU1MI_MADDAi(); -void VU1MI_MADDAq(); -void VU1MI_MADDAx(); -void VU1MI_MADDAy(); -void VU1MI_MADDAz(); -void VU1MI_MADDAw(); -void VU1MI_MSUB(); -void VU1MI_MSUBi(); -void VU1MI_MSUBq(); -void VU1MI_MSUBx(); -void VU1MI_MSUBy(); -void VU1MI_MSUBz(); -void VU1MI_MSUBw(); -void VU1MI_MSUBA(); -void VU1MI_MSUBAi(); -void VU1MI_MSUBAq(); -void VU1MI_MSUBAx(); -void VU1MI_MSUBAy(); -void VU1MI_MSUBAz(); -void VU1MI_MSUBAw(); -void VU1MI_MAX(); -void VU1MI_MAXi(); -void VU1MI_MAXx(); -void VU1MI_MAXy(); -void VU1MI_MAXz(); -void VU1MI_MAXw(); -void VU1MI_MINI(); -void VU1MI_MINIi(); -void VU1MI_MINIx(); -void VU1MI_MINIy(); -void VU1MI_MINIz(); -void VU1MI_MINIw(); -void VU1MI_OPMULA(); -void VU1MI_OPMSUB(); -void VU1MI_NOP(); -void VU1MI_FTOI0(); -void VU1MI_FTOI4(); -void VU1MI_FTOI12(); -void VU1MI_FTOI15(); -void VU1MI_ITOF0(); -void VU1MI_ITOF4(); -void VU1MI_ITOF12(); -void VU1MI_ITOF15(); -void VU1MI_CLIP(); - -/***************************************** - VU1 Micromode Lower instructions -*****************************************/ - -void VU1MI_DIV(); -void VU1MI_SQRT(); -void VU1MI_RSQRT(); -void VU1MI_IADD(); -void VU1MI_IADDI(); -void VU1MI_IADDIU(); -void VU1MI_IAND(); -void VU1MI_IOR(); -void VU1MI_ISUB(); -void VU1MI_ISUBIU(); -void VU1MI_MOVE(); -void VU1MI_MFIR(); -void VU1MI_MTIR(); -void VU1MI_MR32(); -void VU1MI_LQ(); -void VU1MI_LQD(); -void VU1MI_LQI(); -void VU1MI_SQ(); -void VU1MI_SQD(); -void VU1MI_SQI(); -void VU1MI_ILW(); -void VU1MI_ISW(); -void VU1MI_ILWR(); -void VU1MI_ISWR(); -void VU1MI_LOI(); -void VU1MI_RINIT(); -void VU1MI_RGET(); -void VU1MI_RNEXT(); -void VU1MI_RXOR(); -void VU1MI_WAITQ(); -void VU1MI_FSAND(); -void VU1MI_FSEQ(); -void VU1MI_FSOR(); -void VU1MI_FSSET(); -void VU1MI_FMAND(); -void VU1MI_FMEQ(); -void VU1MI_FMOR(); -void VU1MI_FCAND(); -void VU1MI_FCEQ(); -void VU1MI_FCOR(); -void VU1MI_FCSET(); -void VU1MI_FCGET(); -void VU1MI_IBEQ(); -void VU1MI_IBGEZ(); -void VU1MI_IBGTZ(); -void VU1MI_IBLTZ(); -void VU1MI_IBLEZ(); -void VU1MI_IBNE(); -void VU1MI_B(); -void VU1MI_BAL(); -void VU1MI_JR(); -void VU1MI_JALR(); -void VU1MI_MFP(); -void VU1MI_WAITP(); -void VU1MI_ESADD(); -void VU1MI_ERSADD(); -void VU1MI_ELENG(); -void VU1MI_ERLENG(); -void VU1MI_EATANxy(); -void VU1MI_EATANxz(); -void VU1MI_ESUM(); -void VU1MI_ERCPR(); -void VU1MI_ESQRT(); -void VU1MI_ERSQRT(); -void VU1MI_ESIN(); -void VU1MI_EATAN(); -void VU1MI_EEXP(); -void VU1MI_XGKICK(); -void VU1MI_XTOP(); -void VU1MI_XITOP(); - -/***************************************** - VU1 Micromode Upper instructions -*****************************************/ - -void VU1regsMI_ABS(_VURegsNum *VUregsn); -void VU1regsMI_ADD(_VURegsNum *VUregsn); -void VU1regsMI_ADDi(_VURegsNum *VUregsn); -void VU1regsMI_ADDq(_VURegsNum *VUregsn); -void VU1regsMI_ADDx(_VURegsNum *VUregsn); -void VU1regsMI_ADDy(_VURegsNum *VUregsn); -void VU1regsMI_ADDz(_VURegsNum *VUregsn); -void VU1regsMI_ADDw(_VURegsNum *VUregsn); -void VU1regsMI_ADDA(_VURegsNum *VUregsn); -void VU1regsMI_ADDAi(_VURegsNum *VUregsn); -void VU1regsMI_ADDAq(_VURegsNum *VUregsn); -void VU1regsMI_ADDAx(_VURegsNum *VUregsn); -void VU1regsMI_ADDAy(_VURegsNum *VUregsn); -void VU1regsMI_ADDAz(_VURegsNum *VUregsn); -void VU1regsMI_ADDAw(_VURegsNum *VUregsn); -void VU1regsMI_SUB(_VURegsNum *VUregsn); -void VU1regsMI_SUBi(_VURegsNum *VUregsn); -void VU1regsMI_SUBq(_VURegsNum *VUregsn); -void VU1regsMI_SUBx(_VURegsNum *VUregsn); -void VU1regsMI_SUBy(_VURegsNum *VUregsn); -void VU1regsMI_SUBz(_VURegsNum *VUregsn); -void VU1regsMI_SUBw(_VURegsNum *VUregsn); -void VU1regsMI_SUBA(_VURegsNum *VUregsn); -void VU1regsMI_SUBAi(_VURegsNum *VUregsn); -void VU1regsMI_SUBAq(_VURegsNum *VUregsn); -void VU1regsMI_SUBAx(_VURegsNum *VUregsn); -void VU1regsMI_SUBAy(_VURegsNum *VUregsn); -void VU1regsMI_SUBAz(_VURegsNum *VUregsn); -void VU1regsMI_SUBAw(_VURegsNum *VUregsn); -void VU1regsMI_MUL(_VURegsNum *VUregsn); -void VU1regsMI_MULi(_VURegsNum *VUregsn); -void VU1regsMI_MULq(_VURegsNum *VUregsn); -void VU1regsMI_MULx(_VURegsNum *VUregsn); -void VU1regsMI_MULy(_VURegsNum *VUregsn); -void VU1regsMI_MULz(_VURegsNum *VUregsn); -void VU1regsMI_MULw(_VURegsNum *VUregsn); -void VU1regsMI_MULA(_VURegsNum *VUregsn); -void VU1regsMI_MULAi(_VURegsNum *VUregsn); -void VU1regsMI_MULAq(_VURegsNum *VUregsn); -void VU1regsMI_MULAx(_VURegsNum *VUregsn); -void VU1regsMI_MULAy(_VURegsNum *VUregsn); -void VU1regsMI_MULAz(_VURegsNum *VUregsn); -void VU1regsMI_MULAw(_VURegsNum *VUregsn); -void VU1regsMI_MADD(_VURegsNum *VUregsn); -void VU1regsMI_MADDi(_VURegsNum *VUregsn); -void VU1regsMI_MADDq(_VURegsNum *VUregsn); -void VU1regsMI_MADDx(_VURegsNum *VUregsn); -void VU1regsMI_MADDy(_VURegsNum *VUregsn); -void VU1regsMI_MADDz(_VURegsNum *VUregsn); -void VU1regsMI_MADDw(_VURegsNum *VUregsn); -void VU1regsMI_MADDA(_VURegsNum *VUregsn); -void VU1regsMI_MADDAi(_VURegsNum *VUregsn); -void VU1regsMI_MADDAq(_VURegsNum *VUregsn); -void VU1regsMI_MADDAx(_VURegsNum *VUregsn); -void VU1regsMI_MADDAy(_VURegsNum *VUregsn); -void VU1regsMI_MADDAz(_VURegsNum *VUregsn); -void VU1regsMI_MADDAw(_VURegsNum *VUregsn); -void VU1regsMI_MSUB(_VURegsNum *VUregsn); -void VU1regsMI_MSUBi(_VURegsNum *VUregsn); -void VU1regsMI_MSUBq(_VURegsNum *VUregsn); -void VU1regsMI_MSUBx(_VURegsNum *VUregsn); -void VU1regsMI_MSUBy(_VURegsNum *VUregsn); -void VU1regsMI_MSUBz(_VURegsNum *VUregsn); -void VU1regsMI_MSUBw(_VURegsNum *VUregsn); -void VU1regsMI_MSUBA(_VURegsNum *VUregsn); -void VU1regsMI_MSUBAi(_VURegsNum *VUregsn); -void VU1regsMI_MSUBAq(_VURegsNum *VUregsn); -void VU1regsMI_MSUBAx(_VURegsNum *VUregsn); -void VU1regsMI_MSUBAy(_VURegsNum *VUregsn); -void VU1regsMI_MSUBAz(_VURegsNum *VUregsn); -void VU1regsMI_MSUBAw(_VURegsNum *VUregsn); -void VU1regsMI_MAX(_VURegsNum *VUregsn); -void VU1regsMI_MAXi(_VURegsNum *VUregsn); -void VU1regsMI_MAXx(_VURegsNum *VUregsn); -void VU1regsMI_MAXy(_VURegsNum *VUregsn); -void VU1regsMI_MAXz(_VURegsNum *VUregsn); -void VU1regsMI_MAXw(_VURegsNum *VUregsn); -void VU1regsMI_MINI(_VURegsNum *VUregsn); -void VU1regsMI_MINIi(_VURegsNum *VUregsn); -void VU1regsMI_MINIx(_VURegsNum *VUregsn); -void VU1regsMI_MINIy(_VURegsNum *VUregsn); -void VU1regsMI_MINIz(_VURegsNum *VUregsn); -void VU1regsMI_MINIw(_VURegsNum *VUregsn); -void VU1regsMI_OPMULA(_VURegsNum *VUregsn); -void VU1regsMI_OPMSUB(_VURegsNum *VUregsn); -void VU1regsMI_NOP(_VURegsNum *VUregsn); -void VU1regsMI_FTOI0(_VURegsNum *VUregsn); -void VU1regsMI_FTOI4(_VURegsNum *VUregsn); -void VU1regsMI_FTOI12(_VURegsNum *VUregsn); -void VU1regsMI_FTOI15(_VURegsNum *VUregsn); -void VU1regsMI_ITOF0(_VURegsNum *VUregsn); -void VU1regsMI_ITOF4(_VURegsNum *VUregsn); -void VU1regsMI_ITOF12(_VURegsNum *VUregsn); -void VU1regsMI_ITOF15(_VURegsNum *VUregsn); -void VU1regsMI_CLIP(_VURegsNum *VUregsn); - -/***************************************** - VU1 Micromode Lower instructions -*****************************************/ - -void VU1regsMI_DIV(_VURegsNum *VUregsn); -void VU1regsMI_SQRT(_VURegsNum *VUregsn); -void VU1regsMI_RSQRT(_VURegsNum *VUregsn); -void VU1regsMI_IADD(_VURegsNum *VUregsn); -void VU1regsMI_IADDI(_VURegsNum *VUregsn); -void VU1regsMI_IADDIU(_VURegsNum *VUregsn); -void VU1regsMI_IAND(_VURegsNum *VUregsn); -void VU1regsMI_IOR(_VURegsNum *VUregsn); -void VU1regsMI_ISUB(_VURegsNum *VUregsn); -void VU1regsMI_ISUBIU(_VURegsNum *VUregsn); -void VU1regsMI_MOVE(_VURegsNum *VUregsn); -void VU1regsMI_MFIR(_VURegsNum *VUregsn); -void VU1regsMI_MTIR(_VURegsNum *VUregsn); -void VU1regsMI_MR32(_VURegsNum *VUregsn); -void VU1regsMI_LQ(_VURegsNum *VUregsn); -void VU1regsMI_LQD(_VURegsNum *VUregsn); -void VU1regsMI_LQI(_VURegsNum *VUregsn); -void VU1regsMI_SQ(_VURegsNum *VUregsn); -void VU1regsMI_SQD(_VURegsNum *VUregsn); -void VU1regsMI_SQI(_VURegsNum *VUregsn); -void VU1regsMI_ILW(_VURegsNum *VUregsn); -void VU1regsMI_ISW(_VURegsNum *VUregsn); -void VU1regsMI_ILWR(_VURegsNum *VUregsn); -void VU1regsMI_ISWR(_VURegsNum *VUregsn); -void VU1regsMI_LOI(_VURegsNum *VUregsn); -void VU1regsMI_RINIT(_VURegsNum *VUregsn); -void VU1regsMI_RGET(_VURegsNum *VUregsn); -void VU1regsMI_RNEXT(_VURegsNum *VUregsn); -void VU1regsMI_RXOR(_VURegsNum *VUregsn); -void VU1regsMI_WAITQ(_VURegsNum *VUregsn); -void VU1regsMI_FSAND(_VURegsNum *VUregsn); -void VU1regsMI_FSEQ(_VURegsNum *VUregsn); -void VU1regsMI_FSOR(_VURegsNum *VUregsn); -void VU1regsMI_FSSET(_VURegsNum *VUregsn); -void VU1regsMI_FMAND(_VURegsNum *VUregsn); -void VU1regsMI_FMEQ(_VURegsNum *VUregsn); -void VU1regsMI_FMOR(_VURegsNum *VUregsn); -void VU1regsMI_FCAND(_VURegsNum *VUregsn); -void VU1regsMI_FCEQ(_VURegsNum *VUregsn); -void VU1regsMI_FCOR(_VURegsNum *VUregsn); -void VU1regsMI_FCSET(_VURegsNum *VUregsn); -void VU1regsMI_FCGET(_VURegsNum *VUregsn); -void VU1regsMI_IBEQ(_VURegsNum *VUregsn); -void VU1regsMI_IBGEZ(_VURegsNum *VUregsn); -void VU1regsMI_IBGTZ(_VURegsNum *VUregsn); -void VU1regsMI_IBLTZ(_VURegsNum *VUregsn); -void VU1regsMI_IBLEZ(_VURegsNum *VUregsn); -void VU1regsMI_IBNE(_VURegsNum *VUregsn); -void VU1regsMI_B(_VURegsNum *VUregsn); -void VU1regsMI_BAL(_VURegsNum *VUregsn); -void VU1regsMI_JR(_VURegsNum *VUregsn); -void VU1regsMI_JALR(_VURegsNum *VUregsn); -void VU1regsMI_MFP(_VURegsNum *VUregsn); -void VU1regsMI_WAITP(_VURegsNum *VUregsn); -void VU1regsMI_ESADD(_VURegsNum *VUregsn); -void VU1regsMI_ERSADD(_VURegsNum *VUregsn); -void VU1regsMI_ELENG(_VURegsNum *VUregsn); -void VU1regsMI_ERLENG(_VURegsNum *VUregsn); -void VU1regsMI_EATANxy(_VURegsNum *VUregsn); -void VU1regsMI_EATANxz(_VURegsNum *VUregsn); -void VU1regsMI_ESUM(_VURegsNum *VUregsn); -void VU1regsMI_ERCPR(_VURegsNum *VUregsn); -void VU1regsMI_ESQRT(_VURegsNum *VUregsn); -void VU1regsMI_ERSQRT(_VURegsNum *VUregsn); -void VU1regsMI_ESIN(_VURegsNum *VUregsn); -void VU1regsMI_EATAN(_VURegsNum *VUregsn); -void VU1regsMI_EEXP(_VURegsNum *VUregsn); -void VU1regsMI_XGKICK(_VURegsNum *VUregsn); -void VU1regsMI_XTOP(_VURegsNum *VUregsn); -void VU1regsMI_XITOP(_VURegsNum *VUregsn); - -/***************************************** - VU Micromode Tables/Opcodes defs macros -*****************************************/ - - -#define _vuTables(VU, PREFIX) \ - \ -void (*PREFIX##_LOWER_OPCODE[128])() = { \ - PREFIX##MI_LQ , PREFIX##MI_SQ , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_ILW , PREFIX##MI_ISW , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_IADDIU, PREFIX##MI_ISUBIU, PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_FCEQ , PREFIX##MI_FCSET , PREFIX##MI_FCAND, PREFIX##MI_FCOR, /* 0x10 */ \ - PREFIX##MI_FSEQ , PREFIX##MI_FSSET , PREFIX##MI_FSAND, PREFIX##MI_FSOR, \ - PREFIX##MI_FMEQ , PREFIX##unknown , PREFIX##MI_FMAND, PREFIX##MI_FMOR, \ - PREFIX##MI_FCGET , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_B , PREFIX##MI_BAL , PREFIX##unknown , PREFIX##unknown, /* 0x20 */ \ - PREFIX##MI_JR , PREFIX##MI_JALR , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_IBEQ , PREFIX##MI_IBNE , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_IBLTZ , PREFIX##MI_IBGTZ , PREFIX##MI_IBLEZ, PREFIX##MI_IBGEZ, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x30 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##LowerOP , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x40*/ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x50 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x60 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x70 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ -}; \ - \ - void (*PREFIX##LowerOP_T3_00_OPCODE[32])() = { \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_MOVE , PREFIX##MI_LQI , PREFIX##MI_DIV , PREFIX##MI_MTIR, \ - PREFIX##MI_RNEXT , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##MI_MFP , PREFIX##MI_XTOP , PREFIX##MI_XGKICK, \ - PREFIX##MI_ESADD , PREFIX##MI_EATANxy, PREFIX##MI_ESQRT, PREFIX##MI_ESIN, \ -}; \ - \ - void (*PREFIX##LowerOP_T3_01_OPCODE[32])() = { \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_MR32 , PREFIX##MI_SQI , PREFIX##MI_SQRT , PREFIX##MI_MFIR, \ - PREFIX##MI_RGET , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##MI_XITOP, PREFIX##unknown, \ - PREFIX##MI_ERSADD, PREFIX##MI_EATANxz, PREFIX##MI_ERSQRT, PREFIX##MI_EATAN, \ -}; \ - \ - void (*PREFIX##LowerOP_T3_10_OPCODE[32])() = { \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##MI_LQD , PREFIX##MI_RSQRT, PREFIX##MI_ILWR, \ - PREFIX##MI_RINIT , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_ELENG , PREFIX##MI_ESUM , PREFIX##MI_ERCPR, PREFIX##MI_EEXP, \ -}; \ - \ - void (*PREFIX##LowerOP_T3_11_OPCODE[32])() = { \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##MI_SQD , PREFIX##MI_WAITQ, PREFIX##MI_ISWR, \ - PREFIX##MI_RXOR , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_ERLENG, PREFIX##unknown , PREFIX##MI_WAITP, PREFIX##unknown, \ -}; \ - \ - void (*PREFIX##LowerOP_OPCODE[64])() = { \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x20 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_IADD , PREFIX##MI_ISUB , PREFIX##MI_IADDI, PREFIX##unknown, /* 0x30 */ \ - PREFIX##MI_IAND , PREFIX##MI_IOR , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##LowerOP_T3_00, PREFIX##LowerOP_T3_01, PREFIX##LowerOP_T3_10, PREFIX##LowerOP_T3_11, \ -}; \ - \ - void (*PREFIX##_UPPER_OPCODE[64])() = { \ - PREFIX##MI_ADDx , PREFIX##MI_ADDy , PREFIX##MI_ADDz , PREFIX##MI_ADDw, \ - PREFIX##MI_SUBx , PREFIX##MI_SUBy , PREFIX##MI_SUBz , PREFIX##MI_SUBw, \ - PREFIX##MI_MADDx , PREFIX##MI_MADDy , PREFIX##MI_MADDz , PREFIX##MI_MADDw, \ - PREFIX##MI_MSUBx , PREFIX##MI_MSUBy , PREFIX##MI_MSUBz , PREFIX##MI_MSUBw, \ - PREFIX##MI_MAXx , PREFIX##MI_MAXy , PREFIX##MI_MAXz , PREFIX##MI_MAXw, /* 0x10 */ \ - PREFIX##MI_MINIx , PREFIX##MI_MINIy , PREFIX##MI_MINIz , PREFIX##MI_MINIw, \ - PREFIX##MI_MULx , PREFIX##MI_MULy , PREFIX##MI_MULz , PREFIX##MI_MULw, \ - PREFIX##MI_MULq , PREFIX##MI_MAXi , PREFIX##MI_MULi , PREFIX##MI_MINIi, \ - PREFIX##MI_ADDq , PREFIX##MI_MADDq , PREFIX##MI_ADDi , PREFIX##MI_MADDi, /* 0x20 */ \ - PREFIX##MI_SUBq , PREFIX##MI_MSUBq , PREFIX##MI_SUBi , PREFIX##MI_MSUBi, \ - PREFIX##MI_ADD , PREFIX##MI_MADD , PREFIX##MI_MUL , PREFIX##MI_MAX, \ - PREFIX##MI_SUB , PREFIX##MI_MSUB , PREFIX##MI_OPMSUB, PREFIX##MI_MINI, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x30 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##_UPPER_FD_00, PREFIX##_UPPER_FD_01, PREFIX##_UPPER_FD_10, PREFIX##_UPPER_FD_11, \ -}; \ - \ - void (*PREFIX##_UPPER_FD_00_TABLE[32])() = { \ - PREFIX##MI_ADDAx, PREFIX##MI_SUBAx , PREFIX##MI_MADDAx, PREFIX##MI_MSUBAx, \ - PREFIX##MI_ITOF0, PREFIX##MI_FTOI0, PREFIX##MI_MULAx , PREFIX##MI_MULAq , \ - PREFIX##MI_ADDAq, PREFIX##MI_SUBAq, PREFIX##MI_ADDA , PREFIX##MI_SUBA , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ -}; \ - \ - void (*PREFIX##_UPPER_FD_01_TABLE[32])() = { \ - PREFIX##MI_ADDAy , PREFIX##MI_SUBAy , PREFIX##MI_MADDAy, PREFIX##MI_MSUBAy, \ - PREFIX##MI_ITOF4 , PREFIX##MI_FTOI4 , PREFIX##MI_MULAy , PREFIX##MI_ABS , \ - PREFIX##MI_MADDAq, PREFIX##MI_MSUBAq, PREFIX##MI_MADDA , PREFIX##MI_MSUBA , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ -}; \ - \ - void (*PREFIX##_UPPER_FD_10_TABLE[32])() = { \ - PREFIX##MI_ADDAz , PREFIX##MI_SUBAz , PREFIX##MI_MADDAz, PREFIX##MI_MSUBAz, \ - PREFIX##MI_ITOF12, PREFIX##MI_FTOI12, PREFIX##MI_MULAz , PREFIX##MI_MULAi , \ - PREFIX##MI_ADDAi, PREFIX##MI_SUBAi , PREFIX##MI_MULA , PREFIX##MI_OPMULA, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ -}; \ - \ - void (*PREFIX##_UPPER_FD_11_TABLE[32])() = { \ - PREFIX##MI_ADDAw , PREFIX##MI_SUBAw , PREFIX##MI_MADDAw, PREFIX##MI_MSUBAw, \ - PREFIX##MI_ITOF15, PREFIX##MI_FTOI15, PREFIX##MI_MULAw , PREFIX##MI_CLIP , \ - PREFIX##MI_MADDAi, PREFIX##MI_MSUBAi, PREFIX##unknown , PREFIX##MI_NOP , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ -}; \ - \ - \ - \ - void PREFIX##_UPPER_FD_00() { \ - PREFIX##_UPPER_FD_00_TABLE[(VU.code >> 6) & 0x1f ](); \ -} \ - \ - void PREFIX##_UPPER_FD_01() { \ - PREFIX##_UPPER_FD_01_TABLE[(VU.code >> 6) & 0x1f](); \ -} \ - \ - void PREFIX##_UPPER_FD_10() { \ - PREFIX##_UPPER_FD_10_TABLE[(VU.code >> 6) & 0x1f](); \ -} \ - \ - void PREFIX##_UPPER_FD_11() { \ - PREFIX##_UPPER_FD_11_TABLE[(VU.code >> 6) & 0x1f](); \ -} \ - \ - void PREFIX##LowerOP() { \ - PREFIX##LowerOP_OPCODE[VU.code & 0x3f](); \ -} \ - \ - void PREFIX##LowerOP_T3_00() { \ - PREFIX##LowerOP_T3_00_OPCODE[(VU.code >> 6) & 0x1f](); \ -} \ - \ - void PREFIX##LowerOP_T3_01() { \ - PREFIX##LowerOP_T3_01_OPCODE[(VU.code >> 6) & 0x1f](); \ -} \ - \ - void PREFIX##LowerOP_T3_10() { \ - PREFIX##LowerOP_T3_10_OPCODE[(VU.code >> 6) & 0x1f](); \ -} \ - \ - void PREFIX##LowerOP_T3_11() { \ - PREFIX##LowerOP_T3_11_OPCODE[(VU.code >> 6) & 0x1f](); \ -} - -#define _vuRegsTables(VU, PREFIX) \ - \ -void (*PREFIX##_LOWER_OPCODE[128])(_VURegsNum *VUregsn) = { \ - PREFIX##MI_LQ , PREFIX##MI_SQ , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_ILW , PREFIX##MI_ISW , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_IADDIU, PREFIX##MI_ISUBIU, PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_FCEQ , PREFIX##MI_FCSET , PREFIX##MI_FCAND, PREFIX##MI_FCOR, /* 0x10 */ \ - PREFIX##MI_FSEQ , PREFIX##MI_FSSET , PREFIX##MI_FSAND, PREFIX##MI_FSOR, \ - PREFIX##MI_FMEQ , PREFIX##unknown , PREFIX##MI_FMAND, PREFIX##MI_FMOR, \ - PREFIX##MI_FCGET , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_B , PREFIX##MI_BAL , PREFIX##unknown , PREFIX##unknown, /* 0x20 */ \ - PREFIX##MI_JR , PREFIX##MI_JALR , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_IBEQ , PREFIX##MI_IBNE , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_IBLTZ , PREFIX##MI_IBGTZ , PREFIX##MI_IBLEZ, PREFIX##MI_IBGEZ, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x30 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##LowerOP , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x40*/ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x50 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x60 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x70 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ -}; \ - \ - void (*PREFIX##LowerOP_T3_00_OPCODE[32])(_VURegsNum *VUregsn) = { \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_MOVE , PREFIX##MI_LQI , PREFIX##MI_DIV , PREFIX##MI_MTIR, \ - PREFIX##MI_RNEXT , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##MI_MFP , PREFIX##MI_XTOP , PREFIX##MI_XGKICK, \ - PREFIX##MI_ESADD , PREFIX##MI_EATANxy, PREFIX##MI_ESQRT, PREFIX##MI_ESIN, \ -}; \ - \ - void (*PREFIX##LowerOP_T3_01_OPCODE[32])(_VURegsNum *VUregsn) = { \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_MR32 , PREFIX##MI_SQI , PREFIX##MI_SQRT , PREFIX##MI_MFIR, \ - PREFIX##MI_RGET , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##MI_XITOP, PREFIX##unknown, \ - PREFIX##MI_ERSADD, PREFIX##MI_EATANxz, PREFIX##MI_ERSQRT, PREFIX##MI_EATAN, \ -}; \ - \ - void (*PREFIX##LowerOP_T3_10_OPCODE[32])(_VURegsNum *VUregsn) = { \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##MI_LQD , PREFIX##MI_RSQRT, PREFIX##MI_ILWR, \ - PREFIX##MI_RINIT , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_ELENG , PREFIX##MI_ESUM , PREFIX##MI_ERCPR, PREFIX##MI_EEXP, \ -}; \ - \ - void (*PREFIX##LowerOP_T3_11_OPCODE[32])(_VURegsNum *VUregsn) = { \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##MI_SQD , PREFIX##MI_WAITQ, PREFIX##MI_ISWR, \ - PREFIX##MI_RXOR , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_ERLENG, PREFIX##unknown , PREFIX##MI_WAITP, PREFIX##unknown, \ -}; \ - \ - void (*PREFIX##LowerOP_OPCODE[64])(_VURegsNum *VUregsn) = { \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x20 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##MI_IADD , PREFIX##MI_ISUB , PREFIX##MI_IADDI, PREFIX##unknown, /* 0x30 */ \ - PREFIX##MI_IAND , PREFIX##MI_IOR , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##LowerOP_T3_00, PREFIX##LowerOP_T3_01, PREFIX##LowerOP_T3_10, PREFIX##LowerOP_T3_11, \ -}; \ - \ - void (*PREFIX##_UPPER_OPCODE[64])(_VURegsNum *VUregsn) = { \ - PREFIX##MI_ADDx , PREFIX##MI_ADDy , PREFIX##MI_ADDz , PREFIX##MI_ADDw, \ - PREFIX##MI_SUBx , PREFIX##MI_SUBy , PREFIX##MI_SUBz , PREFIX##MI_SUBw, \ - PREFIX##MI_MADDx , PREFIX##MI_MADDy , PREFIX##MI_MADDz , PREFIX##MI_MADDw, \ - PREFIX##MI_MSUBx , PREFIX##MI_MSUBy , PREFIX##MI_MSUBz , PREFIX##MI_MSUBw, \ - PREFIX##MI_MAXx , PREFIX##MI_MAXy , PREFIX##MI_MAXz , PREFIX##MI_MAXw, /* 0x10 */ \ - PREFIX##MI_MINIx , PREFIX##MI_MINIy , PREFIX##MI_MINIz , PREFIX##MI_MINIw, \ - PREFIX##MI_MULx , PREFIX##MI_MULy , PREFIX##MI_MULz , PREFIX##MI_MULw, \ - PREFIX##MI_MULq , PREFIX##MI_MAXi , PREFIX##MI_MULi , PREFIX##MI_MINIi, \ - PREFIX##MI_ADDq , PREFIX##MI_MADDq , PREFIX##MI_ADDi , PREFIX##MI_MADDi, /* 0x20 */ \ - PREFIX##MI_SUBq , PREFIX##MI_MSUBq , PREFIX##MI_SUBi , PREFIX##MI_MSUBi, \ - PREFIX##MI_ADD , PREFIX##MI_MADD , PREFIX##MI_MUL , PREFIX##MI_MAX, \ - PREFIX##MI_SUB , PREFIX##MI_MSUB , PREFIX##MI_OPMSUB, PREFIX##MI_MINI, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x30 */ \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ - PREFIX##_UPPER_FD_00, PREFIX##_UPPER_FD_01, PREFIX##_UPPER_FD_10, PREFIX##_UPPER_FD_11, \ -}; \ - \ - void (*PREFIX##_UPPER_FD_00_TABLE[32])(_VURegsNum *VUregsn) = { \ - PREFIX##MI_ADDAx, PREFIX##MI_SUBAx , PREFIX##MI_MADDAx, PREFIX##MI_MSUBAx, \ - PREFIX##MI_ITOF0, PREFIX##MI_FTOI0, PREFIX##MI_MULAx , PREFIX##MI_MULAq , \ - PREFIX##MI_ADDAq, PREFIX##MI_SUBAq, PREFIX##MI_ADDA , PREFIX##MI_SUBA , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ -}; \ - \ - void (*PREFIX##_UPPER_FD_01_TABLE[32])(_VURegsNum *VUregsn) = { \ - PREFIX##MI_ADDAy , PREFIX##MI_SUBAy , PREFIX##MI_MADDAy, PREFIX##MI_MSUBAy, \ - PREFIX##MI_ITOF4 , PREFIX##MI_FTOI4 , PREFIX##MI_MULAy , PREFIX##MI_ABS , \ - PREFIX##MI_MADDAq, PREFIX##MI_MSUBAq, PREFIX##MI_MADDA , PREFIX##MI_MSUBA , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ -}; \ - \ - void (*PREFIX##_UPPER_FD_10_TABLE[32])(_VURegsNum *VUregsn) = { \ - PREFIX##MI_ADDAz , PREFIX##MI_SUBAz , PREFIX##MI_MADDAz, PREFIX##MI_MSUBAz, \ - PREFIX##MI_ITOF12, PREFIX##MI_FTOI12, PREFIX##MI_MULAz , PREFIX##MI_MULAi , \ - PREFIX##MI_ADDAi, PREFIX##MI_SUBAi , PREFIX##MI_MULA , PREFIX##MI_OPMULA, \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ -}; \ - \ - void (*PREFIX##_UPPER_FD_11_TABLE[32])(_VURegsNum *VUregsn) = { \ - PREFIX##MI_ADDAw , PREFIX##MI_SUBAw , PREFIX##MI_MADDAw, PREFIX##MI_MSUBAw, \ - PREFIX##MI_ITOF15, PREFIX##MI_FTOI15, PREFIX##MI_MULAw , PREFIX##MI_CLIP , \ - PREFIX##MI_MADDAi, PREFIX##MI_MSUBAi, PREFIX##unknown , PREFIX##MI_NOP , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ - PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ -}; \ - \ - \ - \ - void PREFIX##_UPPER_FD_00(_VURegsNum *VUregsn) { \ - PREFIX##_UPPER_FD_00_TABLE[(VU.code >> 6) & 0x1f ](VUregsn); \ -} \ - \ - void PREFIX##_UPPER_FD_01(_VURegsNum *VUregsn) { \ - PREFIX##_UPPER_FD_01_TABLE[(VU.code >> 6) & 0x1f](VUregsn); \ -} \ - \ - void PREFIX##_UPPER_FD_10(_VURegsNum *VUregsn) { \ - PREFIX##_UPPER_FD_10_TABLE[(VU.code >> 6) & 0x1f](VUregsn); \ -} \ - \ - void PREFIX##_UPPER_FD_11(_VURegsNum *VUregsn) { \ - PREFIX##_UPPER_FD_11_TABLE[(VU.code >> 6) & 0x1f](VUregsn); \ -} \ - \ - void PREFIX##LowerOP(_VURegsNum *VUregsn) { \ - PREFIX##LowerOP_OPCODE[VU.code & 0x3f](VUregsn); \ -} \ - \ - void PREFIX##LowerOP_T3_00(_VURegsNum *VUregsn) { \ - PREFIX##LowerOP_T3_00_OPCODE[(VU.code >> 6) & 0x1f](VUregsn); \ -} \ - \ - void PREFIX##LowerOP_T3_01(_VURegsNum *VUregsn) { \ - PREFIX##LowerOP_T3_01_OPCODE[(VU.code >> 6) & 0x1f](VUregsn); \ -} \ - \ - void PREFIX##LowerOP_T3_10(_VURegsNum *VUregsn) { \ - PREFIX##LowerOP_T3_10_OPCODE[(VU.code >> 6) & 0x1f](VUregsn); \ -} \ - \ - void PREFIX##LowerOP_T3_11(_VURegsNum *VUregsn) { \ - PREFIX##LowerOP_T3_11_OPCODE[(VU.code >> 6) & 0x1f](VUregsn); \ -} - - -#ifdef VUM_LOG - -#define IdebugUPPER(VU) \ - VUM_LOG("%s\n", dis##VU##MicroUF(VU.code, VU.VI[REG_TPC].UL)); -#define IdebugLOWER(VU) \ - VUM_LOG("%s\n", dis##VU##MicroLF(VU.code, VU.VI[REG_TPC].UL)); - -#else - -#define IdebugUPPER(VU) -#define IdebugLOWER(VU) - -#endif - -#ifdef VUM_LOG -#define _vuExecMicroDebug(VU) \ - VUM_LOG("_vuExecMicro: %8.8x\n", VU.VI[REG_TPC].UL); -#else -#define _vuExecMicroDebug(VU) -#endif - -#include "VUops.h" - -#endif - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __VUMICRO_H__ +#define __VUMICRO_H__ + +#include "VU.h" + +struct VUmicroCpu +{ + void (*Reset)(); + void (*Step)(); + void (*ExecuteBlock)(); // VUs should support block-level execution only. + void (__fastcall *Clear)(u32 Addr, u32 Size); +}; + +extern VUmicroCpu CpuVU0; +extern const VUmicroCpu intVU0; +extern const VUmicroCpu recVU0; + +extern VUmicroCpu CpuVU1; +extern const VUmicroCpu intVU1; +extern const VUmicroCpu recVU1; + +namespace VU0micro +{ + extern void recAlloc(); + extern void recShutdown(); + extern void __fastcall recClear(u32 Addr, u32 Size); + + // Note: Interpreter functions are dummies -- they don't actually do anything. + extern void intAlloc(); + extern void intShutdown(); + extern void __fastcall intClear(u32 Addr, u32 Size); +} + +namespace VU1micro +{ + extern void recAlloc(); + extern void recShutdown(); + extern void __fastcall recClear(u32 Addr, u32 Size); + + // Note: Interpreter functions are dummies -- they don't actually do anything. + extern void intAlloc(); + extern void intShutdown(); + extern void __fastcall intClear(u32 Addr, u32 Size); +} + +///////////////////////////////////////////////////////////////// +// These functions initialize memory for both VUs. +// +void vuMicroMemAlloc(); +void vuMicroMemShutdown(); +void vuMicroMemReset(); + +// Resets VUs and assigns the cpuVU0 / cpuVU1 pointers as according to +// the CHECK_VU0REC / CHECK_VU1REC config options. +void vuMicroCpuReset(); + +///////////////////////////////////////////////////////////////// +// Everything else does stuff on a per-VU basis. +// +void iDumpVU0Registers(); +void iDumpVU1Registers(); + + +extern void (*VU0_LOWER_OPCODE[128])(); +extern void (*VU0_UPPER_OPCODE[64])(); + +extern void (*VU0_UPPER_FD_00_TABLE[32])(); +extern void (*VU0_UPPER_FD_01_TABLE[32])(); +extern void (*VU0_UPPER_FD_10_TABLE[32])(); +extern void (*VU0_UPPER_FD_11_TABLE[32])(); + +extern void (*VU0regs_LOWER_OPCODE[128])(_VURegsNum *VUregsn); +extern void (*VU0regs_UPPER_OPCODE[64])(_VURegsNum *VUregsn); + +extern void (*VU0regs_UPPER_FD_00_TABLE[32])(_VURegsNum *VUregsn); +extern void (*VU0regs_UPPER_FD_01_TABLE[32])(_VURegsNum *VUregsn); +extern void (*VU0regs_UPPER_FD_10_TABLE[32])(_VURegsNum *VUregsn); +extern void (*VU0regs_UPPER_FD_11_TABLE[32])(_VURegsNum *VUregsn); + +extern void (*VU1_LOWER_OPCODE[128])(); +extern void (*VU1_UPPER_OPCODE[64])(); + +extern void (*VU1_UPPER_FD_00_TABLE[32])(); +extern void (*VU1_UPPER_FD_01_TABLE[32])(); +extern void (*VU1_UPPER_FD_10_TABLE[32])(); +extern void (*VU1_UPPER_FD_11_TABLE[32])(); + +extern void (*VU1regs_LOWER_OPCODE[128])(_VURegsNum *VUregsn); +extern void (*VU1regs_UPPER_OPCODE[64])(_VURegsNum *VUregsn); + +extern void (*VU1regs_UPPER_FD_00_TABLE[32])(_VURegsNum *VUregsn); +extern void (*VU1regs_UPPER_FD_01_TABLE[32])(_VURegsNum *VUregsn); +extern void (*VU1regs_UPPER_FD_10_TABLE[32])(_VURegsNum *VUregsn); +extern void (*VU1regs_UPPER_FD_11_TABLE[32])(_VURegsNum *VUregsn); + +// VU0 +extern void vu0ResetRegs(); +extern void vu0ExecMicro(u32 addr); +extern void vu0Exec(VURegs* VU); +extern void vu0Finish(); +extern void recResetVU0( void ); + +// VU1 +extern void vu1ResetRegs(); +extern void vu1ExecMicro(u32 addr); +extern void vu1Exec(VURegs* VU); + +extern void vu1MicroEnableSkip(); +extern void vu1MicroDisableSkip(); +extern bool vu1MicroIsSkipping(); + +void VU0_UPPER_FD_00(); +void VU0_UPPER_FD_01(); +void VU0_UPPER_FD_10(); +void VU0_UPPER_FD_11(); + +void VU0LowerOP(); +void VU0LowerOP_T3_00(); +void VU0LowerOP_T3_01(); +void VU0LowerOP_T3_10(); +void VU0LowerOP_T3_11(); + +void VU0unknown(); + +void VU1_UPPER_FD_00(); +void VU1_UPPER_FD_01(); +void VU1_UPPER_FD_10(); +void VU1_UPPER_FD_11(); + +void VU1LowerOP(); +void VU1LowerOP_T3_00(); +void VU1LowerOP_T3_01(); +void VU1LowerOP_T3_10(); +void VU1LowerOP_T3_11(); + +void VU1unknown(); + +void VU0regs_UPPER_FD_00(_VURegsNum *VUregsn); +void VU0regs_UPPER_FD_01(_VURegsNum *VUregsn); +void VU0regs_UPPER_FD_10(_VURegsNum *VUregsn); +void VU0regs_UPPER_FD_11(_VURegsNum *VUregsn); + +void VU0regsLowerOP(_VURegsNum *VUregsn); +void VU0regsLowerOP_T3_00(_VURegsNum *VUregsn); +void VU0regsLowerOP_T3_01(_VURegsNum *VUregsn); +void VU0regsLowerOP_T3_10(_VURegsNum *VUregsn); +void VU0regsLowerOP_T3_11(_VURegsNum *VUregsn); + +void VU0regsunknown(_VURegsNum *VUregsn); + +void VU1regs_UPPER_FD_00(_VURegsNum *VUregsn); +void VU1regs_UPPER_FD_01(_VURegsNum *VUregsn); +void VU1regs_UPPER_FD_10(_VURegsNum *VUregsn); +void VU1regs_UPPER_FD_11(_VURegsNum *VUregsn); + +void VU1regsLowerOP(_VURegsNum *VUregsn); +void VU1regsLowerOP_T3_00(_VURegsNum *VUregsn); +void VU1regsLowerOP_T3_01(_VURegsNum *VUregsn); +void VU1regsLowerOP_T3_10(_VURegsNum *VUregsn); +void VU1regsLowerOP_T3_11(_VURegsNum *VUregsn); + +void VU1regsunknown(_VURegsNum *VUregsn); + +/***************************************** + VU0 Micromode Upper instructions +*****************************************/ + +void VU0MI_ABS(); +void VU0MI_ADD(); +void VU0MI_ADDi(); +void VU0MI_ADDq(); +void VU0MI_ADDx(); +void VU0MI_ADDy(); +void VU0MI_ADDz(); +void VU0MI_ADDw(); +void VU0MI_ADDA(); +void VU0MI_ADDAi(); +void VU0MI_ADDAq(); +void VU0MI_ADDAx(); +void VU0MI_ADDAy(); +void VU0MI_ADDAz(); +void VU0MI_ADDAw(); +void VU0MI_SUB(); +void VU0MI_SUBi(); +void VU0MI_SUBq(); +void VU0MI_SUBx(); +void VU0MI_SUBy(); +void VU0MI_SUBz(); +void VU0MI_SUBw(); +void VU0MI_SUBA(); +void VU0MI_SUBAi(); +void VU0MI_SUBAq(); +void VU0MI_SUBAx(); +void VU0MI_SUBAy(); +void VU0MI_SUBAz(); +void VU0MI_SUBAw(); +void VU0MI_MUL(); +void VU0MI_MULi(); +void VU0MI_MULq(); +void VU0MI_MULx(); +void VU0MI_MULy(); +void VU0MI_MULz(); +void VU0MI_MULw(); +void VU0MI_MULA(); +void VU0MI_MULAi(); +void VU0MI_MULAq(); +void VU0MI_MULAx(); +void VU0MI_MULAy(); +void VU0MI_MULAz(); +void VU0MI_MULAw(); +void VU0MI_MADD(); +void VU0MI_MADDi(); +void VU0MI_MADDq(); +void VU0MI_MADDx(); +void VU0MI_MADDy(); +void VU0MI_MADDz(); +void VU0MI_MADDw(); +void VU0MI_MADDA(); +void VU0MI_MADDAi(); +void VU0MI_MADDAq(); +void VU0MI_MADDAx(); +void VU0MI_MADDAy(); +void VU0MI_MADDAz(); +void VU0MI_MADDAw(); +void VU0MI_MSUB(); +void VU0MI_MSUBi(); +void VU0MI_MSUBq(); +void VU0MI_MSUBx(); +void VU0MI_MSUBy(); +void VU0MI_MSUBz(); +void VU0MI_MSUBw(); +void VU0MI_MSUBA(); +void VU0MI_MSUBAi(); +void VU0MI_MSUBAq(); +void VU0MI_MSUBAx(); +void VU0MI_MSUBAy(); +void VU0MI_MSUBAz(); +void VU0MI_MSUBAw(); +void VU0MI_MAX(); +void VU0MI_MAXi(); +void VU0MI_MAXx(); +void VU0MI_MAXy(); +void VU0MI_MAXz(); +void VU0MI_MAXw(); +void VU0MI_MINI(); +void VU0MI_MINIi(); +void VU0MI_MINIx(); +void VU0MI_MINIy(); +void VU0MI_MINIz(); +void VU0MI_MINIw(); +void VU0MI_OPMULA(); +void VU0MI_OPMSUB(); +void VU0MI_NOP(); +void VU0MI_FTOI0(); +void VU0MI_FTOI4(); +void VU0MI_FTOI12(); +void VU0MI_FTOI15(); +void VU0MI_ITOF0(); +void VU0MI_ITOF4(); +void VU0MI_ITOF12(); +void VU0MI_ITOF15(); +void VU0MI_CLIP(); + +/***************************************** + VU0 Micromode Lower instructions +*****************************************/ + +void VU0MI_DIV(); +void VU0MI_SQRT(); +void VU0MI_RSQRT(); +void VU0MI_IADD(); +void VU0MI_IADDI(); +void VU0MI_IADDIU(); +void VU0MI_IAND(); +void VU0MI_IOR(); +void VU0MI_ISUB(); +void VU0MI_ISUBIU(); +void VU0MI_MOVE(); +void VU0MI_MFIR(); +void VU0MI_MTIR(); +void VU0MI_MR32(); +void VU0MI_LQ(); +void VU0MI_LQD(); +void VU0MI_LQI(); +void VU0MI_SQ(); +void VU0MI_SQD(); +void VU0MI_SQI(); +void VU0MI_ILW(); +void VU0MI_ISW(); +void VU0MI_ILWR(); +void VU0MI_ISWR(); +void VU0MI_LOI(); +void VU0MI_RINIT(); +void VU0MI_RGET(); +void VU0MI_RNEXT(); +void VU0MI_RXOR(); +void VU0MI_WAITQ(); +void VU0MI_FSAND(); +void VU0MI_FSEQ(); +void VU0MI_FSOR(); +void VU0MI_FSSET(); +void VU0MI_FMAND(); +void VU0MI_FMEQ(); +void VU0MI_FMOR(); +void VU0MI_FCAND(); +void VU0MI_FCEQ(); +void VU0MI_FCOR(); +void VU0MI_FCSET(); +void VU0MI_FCGET(); +void VU0MI_IBEQ(); +void VU0MI_IBGEZ(); +void VU0MI_IBGTZ(); +void VU0MI_IBLEZ(); +void VU0MI_IBLTZ(); +void VU0MI_IBNE(); +void VU0MI_B(); +void VU0MI_BAL(); +void VU0MI_JR(); +void VU0MI_JALR(); +void VU0MI_MFP(); +void VU0MI_WAITP(); +void VU0MI_ESADD(); +void VU0MI_ERSADD(); +void VU0MI_ELENG(); +void VU0MI_ERLENG(); +void VU0MI_EATANxy(); +void VU0MI_EATANxz(); +void VU0MI_ESUM(); +void VU0MI_ERCPR(); +void VU0MI_ESQRT(); +void VU0MI_ERSQRT(); +void VU0MI_ESIN(); +void VU0MI_EATAN(); +void VU0MI_EEXP(); +void VU0MI_XGKICK(); +void VU0MI_XTOP(); +void VU0MI_XITOP(); + +/***************************************** + VU1 Micromode Upper instructions +*****************************************/ + +void VU0regsMI_ABS(_VURegsNum *VUregsn); +void VU0regsMI_ADD(_VURegsNum *VUregsn); +void VU0regsMI_ADDi(_VURegsNum *VUregsn); +void VU0regsMI_ADDq(_VURegsNum *VUregsn); +void VU0regsMI_ADDx(_VURegsNum *VUregsn); +void VU0regsMI_ADDy(_VURegsNum *VUregsn); +void VU0regsMI_ADDz(_VURegsNum *VUregsn); +void VU0regsMI_ADDw(_VURegsNum *VUregsn); +void VU0regsMI_ADDA(_VURegsNum *VUregsn); +void VU0regsMI_ADDAi(_VURegsNum *VUregsn); +void VU0regsMI_ADDAq(_VURegsNum *VUregsn); +void VU0regsMI_ADDAx(_VURegsNum *VUregsn); +void VU0regsMI_ADDAy(_VURegsNum *VUregsn); +void VU0regsMI_ADDAz(_VURegsNum *VUregsn); +void VU0regsMI_ADDAw(_VURegsNum *VUregsn); +void VU0regsMI_SUB(_VURegsNum *VUregsn); +void VU0regsMI_SUBi(_VURegsNum *VUregsn); +void VU0regsMI_SUBq(_VURegsNum *VUregsn); +void VU0regsMI_SUBx(_VURegsNum *VUregsn); +void VU0regsMI_SUBy(_VURegsNum *VUregsn); +void VU0regsMI_SUBz(_VURegsNum *VUregsn); +void VU0regsMI_SUBw(_VURegsNum *VUregsn); +void VU0regsMI_SUBA(_VURegsNum *VUregsn); +void VU0regsMI_SUBAi(_VURegsNum *VUregsn); +void VU0regsMI_SUBAq(_VURegsNum *VUregsn); +void VU0regsMI_SUBAx(_VURegsNum *VUregsn); +void VU0regsMI_SUBAy(_VURegsNum *VUregsn); +void VU0regsMI_SUBAz(_VURegsNum *VUregsn); +void VU0regsMI_SUBAw(_VURegsNum *VUregsn); +void VU0regsMI_MUL(_VURegsNum *VUregsn); +void VU0regsMI_MULi(_VURegsNum *VUregsn); +void VU0regsMI_MULq(_VURegsNum *VUregsn); +void VU0regsMI_MULx(_VURegsNum *VUregsn); +void VU0regsMI_MULy(_VURegsNum *VUregsn); +void VU0regsMI_MULz(_VURegsNum *VUregsn); +void VU0regsMI_MULw(_VURegsNum *VUregsn); +void VU0regsMI_MULA(_VURegsNum *VUregsn); +void VU0regsMI_MULAi(_VURegsNum *VUregsn); +void VU0regsMI_MULAq(_VURegsNum *VUregsn); +void VU0regsMI_MULAx(_VURegsNum *VUregsn); +void VU0regsMI_MULAy(_VURegsNum *VUregsn); +void VU0regsMI_MULAz(_VURegsNum *VUregsn); +void VU0regsMI_MULAw(_VURegsNum *VUregsn); +void VU0regsMI_MADD(_VURegsNum *VUregsn); +void VU0regsMI_MADDi(_VURegsNum *VUregsn); +void VU0regsMI_MADDq(_VURegsNum *VUregsn); +void VU0regsMI_MADDx(_VURegsNum *VUregsn); +void VU0regsMI_MADDy(_VURegsNum *VUregsn); +void VU0regsMI_MADDz(_VURegsNum *VUregsn); +void VU0regsMI_MADDw(_VURegsNum *VUregsn); +void VU0regsMI_MADDA(_VURegsNum *VUregsn); +void VU0regsMI_MADDAi(_VURegsNum *VUregsn); +void VU0regsMI_MADDAq(_VURegsNum *VUregsn); +void VU0regsMI_MADDAx(_VURegsNum *VUregsn); +void VU0regsMI_MADDAy(_VURegsNum *VUregsn); +void VU0regsMI_MADDAz(_VURegsNum *VUregsn); +void VU0regsMI_MADDAw(_VURegsNum *VUregsn); +void VU0regsMI_MSUB(_VURegsNum *VUregsn); +void VU0regsMI_MSUBi(_VURegsNum *VUregsn); +void VU0regsMI_MSUBq(_VURegsNum *VUregsn); +void VU0regsMI_MSUBx(_VURegsNum *VUregsn); +void VU0regsMI_MSUBy(_VURegsNum *VUregsn); +void VU0regsMI_MSUBz(_VURegsNum *VUregsn); +void VU0regsMI_MSUBw(_VURegsNum *VUregsn); +void VU0regsMI_MSUBA(_VURegsNum *VUregsn); +void VU0regsMI_MSUBAi(_VURegsNum *VUregsn); +void VU0regsMI_MSUBAq(_VURegsNum *VUregsn); +void VU0regsMI_MSUBAx(_VURegsNum *VUregsn); +void VU0regsMI_MSUBAy(_VURegsNum *VUregsn); +void VU0regsMI_MSUBAz(_VURegsNum *VUregsn); +void VU0regsMI_MSUBAw(_VURegsNum *VUregsn); +void VU0regsMI_MAX(_VURegsNum *VUregsn); +void VU0regsMI_MAXi(_VURegsNum *VUregsn); +void VU0regsMI_MAXx(_VURegsNum *VUregsn); +void VU0regsMI_MAXy(_VURegsNum *VUregsn); +void VU0regsMI_MAXz(_VURegsNum *VUregsn); +void VU0regsMI_MAXw(_VURegsNum *VUregsn); +void VU0regsMI_MINI(_VURegsNum *VUregsn); +void VU0regsMI_MINIi(_VURegsNum *VUregsn); +void VU0regsMI_MINIx(_VURegsNum *VUregsn); +void VU0regsMI_MINIy(_VURegsNum *VUregsn); +void VU0regsMI_MINIz(_VURegsNum *VUregsn); +void VU0regsMI_MINIw(_VURegsNum *VUregsn); +void VU0regsMI_OPMULA(_VURegsNum *VUregsn); +void VU0regsMI_OPMSUB(_VURegsNum *VUregsn); +void VU0regsMI_NOP(_VURegsNum *VUregsn); +void VU0regsMI_FTOI0(_VURegsNum *VUregsn); +void VU0regsMI_FTOI4(_VURegsNum *VUregsn); +void VU0regsMI_FTOI12(_VURegsNum *VUregsn); +void VU0regsMI_FTOI15(_VURegsNum *VUregsn); +void VU0regsMI_ITOF0(_VURegsNum *VUregsn); +void VU0regsMI_ITOF4(_VURegsNum *VUregsn); +void VU0regsMI_ITOF12(_VURegsNum *VUregsn); +void VU0regsMI_ITOF15(_VURegsNum *VUregsn); +void VU0regsMI_CLIP(_VURegsNum *VUregsn); + +/***************************************** + VU0 Micromode Lower instructions +*****************************************/ + +void VU0regsMI_DIV(_VURegsNum *VUregsn); +void VU0regsMI_SQRT(_VURegsNum *VUregsn); +void VU0regsMI_RSQRT(_VURegsNum *VUregsn); +void VU0regsMI_IADD(_VURegsNum *VUregsn); +void VU0regsMI_IADDI(_VURegsNum *VUregsn); +void VU0regsMI_IADDIU(_VURegsNum *VUregsn); +void VU0regsMI_IAND(_VURegsNum *VUregsn); +void VU0regsMI_IOR(_VURegsNum *VUregsn); +void VU0regsMI_ISUB(_VURegsNum *VUregsn); +void VU0regsMI_ISUBIU(_VURegsNum *VUregsn); +void VU0regsMI_MOVE(_VURegsNum *VUregsn); +void VU0regsMI_MFIR(_VURegsNum *VUregsn); +void VU0regsMI_MTIR(_VURegsNum *VUregsn); +void VU0regsMI_MR32(_VURegsNum *VUregsn); +void VU0regsMI_LQ(_VURegsNum *VUregsn); +void VU0regsMI_LQD(_VURegsNum *VUregsn); +void VU0regsMI_LQI(_VURegsNum *VUregsn); +void VU0regsMI_SQ(_VURegsNum *VUregsn); +void VU0regsMI_SQD(_VURegsNum *VUregsn); +void VU0regsMI_SQI(_VURegsNum *VUregsn); +void VU0regsMI_ILW(_VURegsNum *VUregsn); +void VU0regsMI_ISW(_VURegsNum *VUregsn); +void VU0regsMI_ILWR(_VURegsNum *VUregsn); +void VU0regsMI_ISWR(_VURegsNum *VUregsn); +void VU0regsMI_LOI(_VURegsNum *VUregsn); +void VU0regsMI_RINIT(_VURegsNum *VUregsn); +void VU0regsMI_RGET(_VURegsNum *VUregsn); +void VU0regsMI_RNEXT(_VURegsNum *VUregsn); +void VU0regsMI_RXOR(_VURegsNum *VUregsn); +void VU0regsMI_WAITQ(_VURegsNum *VUregsn); +void VU0regsMI_FSAND(_VURegsNum *VUregsn); +void VU0regsMI_FSEQ(_VURegsNum *VUregsn); +void VU0regsMI_FSOR(_VURegsNum *VUregsn); +void VU0regsMI_FSSET(_VURegsNum *VUregsn); +void VU0regsMI_FMAND(_VURegsNum *VUregsn); +void VU0regsMI_FMEQ(_VURegsNum *VUregsn); +void VU0regsMI_FMOR(_VURegsNum *VUregsn); +void VU0regsMI_FCAND(_VURegsNum *VUregsn); +void VU0regsMI_FCEQ(_VURegsNum *VUregsn); +void VU0regsMI_FCOR(_VURegsNum *VUregsn); +void VU0regsMI_FCSET(_VURegsNum *VUregsn); +void VU0regsMI_FCGET(_VURegsNum *VUregsn); +void VU0regsMI_IBEQ(_VURegsNum *VUregsn); +void VU0regsMI_IBGEZ(_VURegsNum *VUregsn); +void VU0regsMI_IBGTZ(_VURegsNum *VUregsn); +void VU0regsMI_IBLTZ(_VURegsNum *VUregsn); +void VU0regsMI_IBLEZ(_VURegsNum *VUregsn); +void VU0regsMI_IBNE(_VURegsNum *VUregsn); +void VU0regsMI_B(_VURegsNum *VUregsn); +void VU0regsMI_BAL(_VURegsNum *VUregsn); +void VU0regsMI_JR(_VURegsNum *VUregsn); +void VU0regsMI_JALR(_VURegsNum *VUregsn); +void VU0regsMI_MFP(_VURegsNum *VUregsn); +void VU0regsMI_WAITP(_VURegsNum *VUregsn); +void VU0regsMI_ESADD(_VURegsNum *VUregsn); +void VU0regsMI_ERSADD(_VURegsNum *VUregsn); +void VU0regsMI_ELENG(_VURegsNum *VUregsn); +void VU0regsMI_ERLENG(_VURegsNum *VUregsn); +void VU0regsMI_EATANxy(_VURegsNum *VUregsn); +void VU0regsMI_EATANxz(_VURegsNum *VUregsn); +void VU0regsMI_ESUM(_VURegsNum *VUregsn); +void VU0regsMI_ERCPR(_VURegsNum *VUregsn); +void VU0regsMI_ESQRT(_VURegsNum *VUregsn); +void VU0regsMI_ERSQRT(_VURegsNum *VUregsn); +void VU0regsMI_ESIN(_VURegsNum *VUregsn); +void VU0regsMI_EATAN(_VURegsNum *VUregsn); +void VU0regsMI_EEXP(_VURegsNum *VUregsn); +void VU0regsMI_XGKICK(_VURegsNum *VUregsn); +void VU0regsMI_XTOP(_VURegsNum *VUregsn); +void VU0regsMI_XITOP(_VURegsNum *VUregsn); + +/***************************************** + VU1 Micromode Upper instructions +*****************************************/ + +void VU1MI_ABS(); +void VU1MI_ADD(); +void VU1MI_ADDi(); +void VU1MI_ADDq(); +void VU1MI_ADDx(); +void VU1MI_ADDy(); +void VU1MI_ADDz(); +void VU1MI_ADDw(); +void VU1MI_ADDA(); +void VU1MI_ADDAi(); +void VU1MI_ADDAq(); +void VU1MI_ADDAx(); +void VU1MI_ADDAy(); +void VU1MI_ADDAz(); +void VU1MI_ADDAw(); +void VU1MI_SUB(); +void VU1MI_SUBi(); +void VU1MI_SUBq(); +void VU1MI_SUBx(); +void VU1MI_SUBy(); +void VU1MI_SUBz(); +void VU1MI_SUBw(); +void VU1MI_SUBA(); +void VU1MI_SUBAi(); +void VU1MI_SUBAq(); +void VU1MI_SUBAx(); +void VU1MI_SUBAy(); +void VU1MI_SUBAz(); +void VU1MI_SUBAw(); +void VU1MI_MUL(); +void VU1MI_MULi(); +void VU1MI_MULq(); +void VU1MI_MULx(); +void VU1MI_MULy(); +void VU1MI_MULz(); +void VU1MI_MULw(); +void VU1MI_MULA(); +void VU1MI_MULAi(); +void VU1MI_MULAq(); +void VU1MI_MULAx(); +void VU1MI_MULAy(); +void VU1MI_MULAz(); +void VU1MI_MULAw(); +void VU1MI_MADD(); +void VU1MI_MADDi(); +void VU1MI_MADDq(); +void VU1MI_MADDx(); +void VU1MI_MADDy(); +void VU1MI_MADDz(); +void VU1MI_MADDw(); +void VU1MI_MADDA(); +void VU1MI_MADDAi(); +void VU1MI_MADDAq(); +void VU1MI_MADDAx(); +void VU1MI_MADDAy(); +void VU1MI_MADDAz(); +void VU1MI_MADDAw(); +void VU1MI_MSUB(); +void VU1MI_MSUBi(); +void VU1MI_MSUBq(); +void VU1MI_MSUBx(); +void VU1MI_MSUBy(); +void VU1MI_MSUBz(); +void VU1MI_MSUBw(); +void VU1MI_MSUBA(); +void VU1MI_MSUBAi(); +void VU1MI_MSUBAq(); +void VU1MI_MSUBAx(); +void VU1MI_MSUBAy(); +void VU1MI_MSUBAz(); +void VU1MI_MSUBAw(); +void VU1MI_MAX(); +void VU1MI_MAXi(); +void VU1MI_MAXx(); +void VU1MI_MAXy(); +void VU1MI_MAXz(); +void VU1MI_MAXw(); +void VU1MI_MINI(); +void VU1MI_MINIi(); +void VU1MI_MINIx(); +void VU1MI_MINIy(); +void VU1MI_MINIz(); +void VU1MI_MINIw(); +void VU1MI_OPMULA(); +void VU1MI_OPMSUB(); +void VU1MI_NOP(); +void VU1MI_FTOI0(); +void VU1MI_FTOI4(); +void VU1MI_FTOI12(); +void VU1MI_FTOI15(); +void VU1MI_ITOF0(); +void VU1MI_ITOF4(); +void VU1MI_ITOF12(); +void VU1MI_ITOF15(); +void VU1MI_CLIP(); + +/***************************************** + VU1 Micromode Lower instructions +*****************************************/ + +void VU1MI_DIV(); +void VU1MI_SQRT(); +void VU1MI_RSQRT(); +void VU1MI_IADD(); +void VU1MI_IADDI(); +void VU1MI_IADDIU(); +void VU1MI_IAND(); +void VU1MI_IOR(); +void VU1MI_ISUB(); +void VU1MI_ISUBIU(); +void VU1MI_MOVE(); +void VU1MI_MFIR(); +void VU1MI_MTIR(); +void VU1MI_MR32(); +void VU1MI_LQ(); +void VU1MI_LQD(); +void VU1MI_LQI(); +void VU1MI_SQ(); +void VU1MI_SQD(); +void VU1MI_SQI(); +void VU1MI_ILW(); +void VU1MI_ISW(); +void VU1MI_ILWR(); +void VU1MI_ISWR(); +void VU1MI_LOI(); +void VU1MI_RINIT(); +void VU1MI_RGET(); +void VU1MI_RNEXT(); +void VU1MI_RXOR(); +void VU1MI_WAITQ(); +void VU1MI_FSAND(); +void VU1MI_FSEQ(); +void VU1MI_FSOR(); +void VU1MI_FSSET(); +void VU1MI_FMAND(); +void VU1MI_FMEQ(); +void VU1MI_FMOR(); +void VU1MI_FCAND(); +void VU1MI_FCEQ(); +void VU1MI_FCOR(); +void VU1MI_FCSET(); +void VU1MI_FCGET(); +void VU1MI_IBEQ(); +void VU1MI_IBGEZ(); +void VU1MI_IBGTZ(); +void VU1MI_IBLTZ(); +void VU1MI_IBLEZ(); +void VU1MI_IBNE(); +void VU1MI_B(); +void VU1MI_BAL(); +void VU1MI_JR(); +void VU1MI_JALR(); +void VU1MI_MFP(); +void VU1MI_WAITP(); +void VU1MI_ESADD(); +void VU1MI_ERSADD(); +void VU1MI_ELENG(); +void VU1MI_ERLENG(); +void VU1MI_EATANxy(); +void VU1MI_EATANxz(); +void VU1MI_ESUM(); +void VU1MI_ERCPR(); +void VU1MI_ESQRT(); +void VU1MI_ERSQRT(); +void VU1MI_ESIN(); +void VU1MI_EATAN(); +void VU1MI_EEXP(); +void VU1MI_XGKICK(); +void VU1MI_XTOP(); +void VU1MI_XITOP(); + +/***************************************** + VU1 Micromode Upper instructions +*****************************************/ + +void VU1regsMI_ABS(_VURegsNum *VUregsn); +void VU1regsMI_ADD(_VURegsNum *VUregsn); +void VU1regsMI_ADDi(_VURegsNum *VUregsn); +void VU1regsMI_ADDq(_VURegsNum *VUregsn); +void VU1regsMI_ADDx(_VURegsNum *VUregsn); +void VU1regsMI_ADDy(_VURegsNum *VUregsn); +void VU1regsMI_ADDz(_VURegsNum *VUregsn); +void VU1regsMI_ADDw(_VURegsNum *VUregsn); +void VU1regsMI_ADDA(_VURegsNum *VUregsn); +void VU1regsMI_ADDAi(_VURegsNum *VUregsn); +void VU1regsMI_ADDAq(_VURegsNum *VUregsn); +void VU1regsMI_ADDAx(_VURegsNum *VUregsn); +void VU1regsMI_ADDAy(_VURegsNum *VUregsn); +void VU1regsMI_ADDAz(_VURegsNum *VUregsn); +void VU1regsMI_ADDAw(_VURegsNum *VUregsn); +void VU1regsMI_SUB(_VURegsNum *VUregsn); +void VU1regsMI_SUBi(_VURegsNum *VUregsn); +void VU1regsMI_SUBq(_VURegsNum *VUregsn); +void VU1regsMI_SUBx(_VURegsNum *VUregsn); +void VU1regsMI_SUBy(_VURegsNum *VUregsn); +void VU1regsMI_SUBz(_VURegsNum *VUregsn); +void VU1regsMI_SUBw(_VURegsNum *VUregsn); +void VU1regsMI_SUBA(_VURegsNum *VUregsn); +void VU1regsMI_SUBAi(_VURegsNum *VUregsn); +void VU1regsMI_SUBAq(_VURegsNum *VUregsn); +void VU1regsMI_SUBAx(_VURegsNum *VUregsn); +void VU1regsMI_SUBAy(_VURegsNum *VUregsn); +void VU1regsMI_SUBAz(_VURegsNum *VUregsn); +void VU1regsMI_SUBAw(_VURegsNum *VUregsn); +void VU1regsMI_MUL(_VURegsNum *VUregsn); +void VU1regsMI_MULi(_VURegsNum *VUregsn); +void VU1regsMI_MULq(_VURegsNum *VUregsn); +void VU1regsMI_MULx(_VURegsNum *VUregsn); +void VU1regsMI_MULy(_VURegsNum *VUregsn); +void VU1regsMI_MULz(_VURegsNum *VUregsn); +void VU1regsMI_MULw(_VURegsNum *VUregsn); +void VU1regsMI_MULA(_VURegsNum *VUregsn); +void VU1regsMI_MULAi(_VURegsNum *VUregsn); +void VU1regsMI_MULAq(_VURegsNum *VUregsn); +void VU1regsMI_MULAx(_VURegsNum *VUregsn); +void VU1regsMI_MULAy(_VURegsNum *VUregsn); +void VU1regsMI_MULAz(_VURegsNum *VUregsn); +void VU1regsMI_MULAw(_VURegsNum *VUregsn); +void VU1regsMI_MADD(_VURegsNum *VUregsn); +void VU1regsMI_MADDi(_VURegsNum *VUregsn); +void VU1regsMI_MADDq(_VURegsNum *VUregsn); +void VU1regsMI_MADDx(_VURegsNum *VUregsn); +void VU1regsMI_MADDy(_VURegsNum *VUregsn); +void VU1regsMI_MADDz(_VURegsNum *VUregsn); +void VU1regsMI_MADDw(_VURegsNum *VUregsn); +void VU1regsMI_MADDA(_VURegsNum *VUregsn); +void VU1regsMI_MADDAi(_VURegsNum *VUregsn); +void VU1regsMI_MADDAq(_VURegsNum *VUregsn); +void VU1regsMI_MADDAx(_VURegsNum *VUregsn); +void VU1regsMI_MADDAy(_VURegsNum *VUregsn); +void VU1regsMI_MADDAz(_VURegsNum *VUregsn); +void VU1regsMI_MADDAw(_VURegsNum *VUregsn); +void VU1regsMI_MSUB(_VURegsNum *VUregsn); +void VU1regsMI_MSUBi(_VURegsNum *VUregsn); +void VU1regsMI_MSUBq(_VURegsNum *VUregsn); +void VU1regsMI_MSUBx(_VURegsNum *VUregsn); +void VU1regsMI_MSUBy(_VURegsNum *VUregsn); +void VU1regsMI_MSUBz(_VURegsNum *VUregsn); +void VU1regsMI_MSUBw(_VURegsNum *VUregsn); +void VU1regsMI_MSUBA(_VURegsNum *VUregsn); +void VU1regsMI_MSUBAi(_VURegsNum *VUregsn); +void VU1regsMI_MSUBAq(_VURegsNum *VUregsn); +void VU1regsMI_MSUBAx(_VURegsNum *VUregsn); +void VU1regsMI_MSUBAy(_VURegsNum *VUregsn); +void VU1regsMI_MSUBAz(_VURegsNum *VUregsn); +void VU1regsMI_MSUBAw(_VURegsNum *VUregsn); +void VU1regsMI_MAX(_VURegsNum *VUregsn); +void VU1regsMI_MAXi(_VURegsNum *VUregsn); +void VU1regsMI_MAXx(_VURegsNum *VUregsn); +void VU1regsMI_MAXy(_VURegsNum *VUregsn); +void VU1regsMI_MAXz(_VURegsNum *VUregsn); +void VU1regsMI_MAXw(_VURegsNum *VUregsn); +void VU1regsMI_MINI(_VURegsNum *VUregsn); +void VU1regsMI_MINIi(_VURegsNum *VUregsn); +void VU1regsMI_MINIx(_VURegsNum *VUregsn); +void VU1regsMI_MINIy(_VURegsNum *VUregsn); +void VU1regsMI_MINIz(_VURegsNum *VUregsn); +void VU1regsMI_MINIw(_VURegsNum *VUregsn); +void VU1regsMI_OPMULA(_VURegsNum *VUregsn); +void VU1regsMI_OPMSUB(_VURegsNum *VUregsn); +void VU1regsMI_NOP(_VURegsNum *VUregsn); +void VU1regsMI_FTOI0(_VURegsNum *VUregsn); +void VU1regsMI_FTOI4(_VURegsNum *VUregsn); +void VU1regsMI_FTOI12(_VURegsNum *VUregsn); +void VU1regsMI_FTOI15(_VURegsNum *VUregsn); +void VU1regsMI_ITOF0(_VURegsNum *VUregsn); +void VU1regsMI_ITOF4(_VURegsNum *VUregsn); +void VU1regsMI_ITOF12(_VURegsNum *VUregsn); +void VU1regsMI_ITOF15(_VURegsNum *VUregsn); +void VU1regsMI_CLIP(_VURegsNum *VUregsn); + +/***************************************** + VU1 Micromode Lower instructions +*****************************************/ + +void VU1regsMI_DIV(_VURegsNum *VUregsn); +void VU1regsMI_SQRT(_VURegsNum *VUregsn); +void VU1regsMI_RSQRT(_VURegsNum *VUregsn); +void VU1regsMI_IADD(_VURegsNum *VUregsn); +void VU1regsMI_IADDI(_VURegsNum *VUregsn); +void VU1regsMI_IADDIU(_VURegsNum *VUregsn); +void VU1regsMI_IAND(_VURegsNum *VUregsn); +void VU1regsMI_IOR(_VURegsNum *VUregsn); +void VU1regsMI_ISUB(_VURegsNum *VUregsn); +void VU1regsMI_ISUBIU(_VURegsNum *VUregsn); +void VU1regsMI_MOVE(_VURegsNum *VUregsn); +void VU1regsMI_MFIR(_VURegsNum *VUregsn); +void VU1regsMI_MTIR(_VURegsNum *VUregsn); +void VU1regsMI_MR32(_VURegsNum *VUregsn); +void VU1regsMI_LQ(_VURegsNum *VUregsn); +void VU1regsMI_LQD(_VURegsNum *VUregsn); +void VU1regsMI_LQI(_VURegsNum *VUregsn); +void VU1regsMI_SQ(_VURegsNum *VUregsn); +void VU1regsMI_SQD(_VURegsNum *VUregsn); +void VU1regsMI_SQI(_VURegsNum *VUregsn); +void VU1regsMI_ILW(_VURegsNum *VUregsn); +void VU1regsMI_ISW(_VURegsNum *VUregsn); +void VU1regsMI_ILWR(_VURegsNum *VUregsn); +void VU1regsMI_ISWR(_VURegsNum *VUregsn); +void VU1regsMI_LOI(_VURegsNum *VUregsn); +void VU1regsMI_RINIT(_VURegsNum *VUregsn); +void VU1regsMI_RGET(_VURegsNum *VUregsn); +void VU1regsMI_RNEXT(_VURegsNum *VUregsn); +void VU1regsMI_RXOR(_VURegsNum *VUregsn); +void VU1regsMI_WAITQ(_VURegsNum *VUregsn); +void VU1regsMI_FSAND(_VURegsNum *VUregsn); +void VU1regsMI_FSEQ(_VURegsNum *VUregsn); +void VU1regsMI_FSOR(_VURegsNum *VUregsn); +void VU1regsMI_FSSET(_VURegsNum *VUregsn); +void VU1regsMI_FMAND(_VURegsNum *VUregsn); +void VU1regsMI_FMEQ(_VURegsNum *VUregsn); +void VU1regsMI_FMOR(_VURegsNum *VUregsn); +void VU1regsMI_FCAND(_VURegsNum *VUregsn); +void VU1regsMI_FCEQ(_VURegsNum *VUregsn); +void VU1regsMI_FCOR(_VURegsNum *VUregsn); +void VU1regsMI_FCSET(_VURegsNum *VUregsn); +void VU1regsMI_FCGET(_VURegsNum *VUregsn); +void VU1regsMI_IBEQ(_VURegsNum *VUregsn); +void VU1regsMI_IBGEZ(_VURegsNum *VUregsn); +void VU1regsMI_IBGTZ(_VURegsNum *VUregsn); +void VU1regsMI_IBLTZ(_VURegsNum *VUregsn); +void VU1regsMI_IBLEZ(_VURegsNum *VUregsn); +void VU1regsMI_IBNE(_VURegsNum *VUregsn); +void VU1regsMI_B(_VURegsNum *VUregsn); +void VU1regsMI_BAL(_VURegsNum *VUregsn); +void VU1regsMI_JR(_VURegsNum *VUregsn); +void VU1regsMI_JALR(_VURegsNum *VUregsn); +void VU1regsMI_MFP(_VURegsNum *VUregsn); +void VU1regsMI_WAITP(_VURegsNum *VUregsn); +void VU1regsMI_ESADD(_VURegsNum *VUregsn); +void VU1regsMI_ERSADD(_VURegsNum *VUregsn); +void VU1regsMI_ELENG(_VURegsNum *VUregsn); +void VU1regsMI_ERLENG(_VURegsNum *VUregsn); +void VU1regsMI_EATANxy(_VURegsNum *VUregsn); +void VU1regsMI_EATANxz(_VURegsNum *VUregsn); +void VU1regsMI_ESUM(_VURegsNum *VUregsn); +void VU1regsMI_ERCPR(_VURegsNum *VUregsn); +void VU1regsMI_ESQRT(_VURegsNum *VUregsn); +void VU1regsMI_ERSQRT(_VURegsNum *VUregsn); +void VU1regsMI_ESIN(_VURegsNum *VUregsn); +void VU1regsMI_EATAN(_VURegsNum *VUregsn); +void VU1regsMI_EEXP(_VURegsNum *VUregsn); +void VU1regsMI_XGKICK(_VURegsNum *VUregsn); +void VU1regsMI_XTOP(_VURegsNum *VUregsn); +void VU1regsMI_XITOP(_VURegsNum *VUregsn); + +/***************************************** + VU Micromode Tables/Opcodes defs macros +*****************************************/ + + +#define _vuTables(VU, PREFIX) \ + \ +void (*PREFIX##_LOWER_OPCODE[128])() = { \ + PREFIX##MI_LQ , PREFIX##MI_SQ , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_ILW , PREFIX##MI_ISW , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_IADDIU, PREFIX##MI_ISUBIU, PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_FCEQ , PREFIX##MI_FCSET , PREFIX##MI_FCAND, PREFIX##MI_FCOR, /* 0x10 */ \ + PREFIX##MI_FSEQ , PREFIX##MI_FSSET , PREFIX##MI_FSAND, PREFIX##MI_FSOR, \ + PREFIX##MI_FMEQ , PREFIX##unknown , PREFIX##MI_FMAND, PREFIX##MI_FMOR, \ + PREFIX##MI_FCGET , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_B , PREFIX##MI_BAL , PREFIX##unknown , PREFIX##unknown, /* 0x20 */ \ + PREFIX##MI_JR , PREFIX##MI_JALR , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_IBEQ , PREFIX##MI_IBNE , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_IBLTZ , PREFIX##MI_IBGTZ , PREFIX##MI_IBLEZ, PREFIX##MI_IBGEZ, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x30 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##LowerOP , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x40*/ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x50 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x60 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x70 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ +}; \ + \ + void (*PREFIX##LowerOP_T3_00_OPCODE[32])() = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_MOVE , PREFIX##MI_LQI , PREFIX##MI_DIV , PREFIX##MI_MTIR, \ + PREFIX##MI_RNEXT , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##MI_MFP , PREFIX##MI_XTOP , PREFIX##MI_XGKICK, \ + PREFIX##MI_ESADD , PREFIX##MI_EATANxy, PREFIX##MI_ESQRT, PREFIX##MI_ESIN, \ +}; \ + \ + void (*PREFIX##LowerOP_T3_01_OPCODE[32])() = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_MR32 , PREFIX##MI_SQI , PREFIX##MI_SQRT , PREFIX##MI_MFIR, \ + PREFIX##MI_RGET , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##MI_XITOP, PREFIX##unknown, \ + PREFIX##MI_ERSADD, PREFIX##MI_EATANxz, PREFIX##MI_ERSQRT, PREFIX##MI_EATAN, \ +}; \ + \ + void (*PREFIX##LowerOP_T3_10_OPCODE[32])() = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##MI_LQD , PREFIX##MI_RSQRT, PREFIX##MI_ILWR, \ + PREFIX##MI_RINIT , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_ELENG , PREFIX##MI_ESUM , PREFIX##MI_ERCPR, PREFIX##MI_EEXP, \ +}; \ + \ + void (*PREFIX##LowerOP_T3_11_OPCODE[32])() = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##MI_SQD , PREFIX##MI_WAITQ, PREFIX##MI_ISWR, \ + PREFIX##MI_RXOR , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_ERLENG, PREFIX##unknown , PREFIX##MI_WAITP, PREFIX##unknown, \ +}; \ + \ + void (*PREFIX##LowerOP_OPCODE[64])() = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x20 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_IADD , PREFIX##MI_ISUB , PREFIX##MI_IADDI, PREFIX##unknown, /* 0x30 */ \ + PREFIX##MI_IAND , PREFIX##MI_IOR , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##LowerOP_T3_00, PREFIX##LowerOP_T3_01, PREFIX##LowerOP_T3_10, PREFIX##LowerOP_T3_11, \ +}; \ + \ + void (*PREFIX##_UPPER_OPCODE[64])() = { \ + PREFIX##MI_ADDx , PREFIX##MI_ADDy , PREFIX##MI_ADDz , PREFIX##MI_ADDw, \ + PREFIX##MI_SUBx , PREFIX##MI_SUBy , PREFIX##MI_SUBz , PREFIX##MI_SUBw, \ + PREFIX##MI_MADDx , PREFIX##MI_MADDy , PREFIX##MI_MADDz , PREFIX##MI_MADDw, \ + PREFIX##MI_MSUBx , PREFIX##MI_MSUBy , PREFIX##MI_MSUBz , PREFIX##MI_MSUBw, \ + PREFIX##MI_MAXx , PREFIX##MI_MAXy , PREFIX##MI_MAXz , PREFIX##MI_MAXw, /* 0x10 */ \ + PREFIX##MI_MINIx , PREFIX##MI_MINIy , PREFIX##MI_MINIz , PREFIX##MI_MINIw, \ + PREFIX##MI_MULx , PREFIX##MI_MULy , PREFIX##MI_MULz , PREFIX##MI_MULw, \ + PREFIX##MI_MULq , PREFIX##MI_MAXi , PREFIX##MI_MULi , PREFIX##MI_MINIi, \ + PREFIX##MI_ADDq , PREFIX##MI_MADDq , PREFIX##MI_ADDi , PREFIX##MI_MADDi, /* 0x20 */ \ + PREFIX##MI_SUBq , PREFIX##MI_MSUBq , PREFIX##MI_SUBi , PREFIX##MI_MSUBi, \ + PREFIX##MI_ADD , PREFIX##MI_MADD , PREFIX##MI_MUL , PREFIX##MI_MAX, \ + PREFIX##MI_SUB , PREFIX##MI_MSUB , PREFIX##MI_OPMSUB, PREFIX##MI_MINI, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x30 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##_UPPER_FD_00, PREFIX##_UPPER_FD_01, PREFIX##_UPPER_FD_10, PREFIX##_UPPER_FD_11, \ +}; \ + \ + void (*PREFIX##_UPPER_FD_00_TABLE[32])() = { \ + PREFIX##MI_ADDAx, PREFIX##MI_SUBAx , PREFIX##MI_MADDAx, PREFIX##MI_MSUBAx, \ + PREFIX##MI_ITOF0, PREFIX##MI_FTOI0, PREFIX##MI_MULAx , PREFIX##MI_MULAq , \ + PREFIX##MI_ADDAq, PREFIX##MI_SUBAq, PREFIX##MI_ADDA , PREFIX##MI_SUBA , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ +}; \ + \ + void (*PREFIX##_UPPER_FD_01_TABLE[32])() = { \ + PREFIX##MI_ADDAy , PREFIX##MI_SUBAy , PREFIX##MI_MADDAy, PREFIX##MI_MSUBAy, \ + PREFIX##MI_ITOF4 , PREFIX##MI_FTOI4 , PREFIX##MI_MULAy , PREFIX##MI_ABS , \ + PREFIX##MI_MADDAq, PREFIX##MI_MSUBAq, PREFIX##MI_MADDA , PREFIX##MI_MSUBA , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ +}; \ + \ + void (*PREFIX##_UPPER_FD_10_TABLE[32])() = { \ + PREFIX##MI_ADDAz , PREFIX##MI_SUBAz , PREFIX##MI_MADDAz, PREFIX##MI_MSUBAz, \ + PREFIX##MI_ITOF12, PREFIX##MI_FTOI12, PREFIX##MI_MULAz , PREFIX##MI_MULAi , \ + PREFIX##MI_ADDAi, PREFIX##MI_SUBAi , PREFIX##MI_MULA , PREFIX##MI_OPMULA, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ +}; \ + \ + void (*PREFIX##_UPPER_FD_11_TABLE[32])() = { \ + PREFIX##MI_ADDAw , PREFIX##MI_SUBAw , PREFIX##MI_MADDAw, PREFIX##MI_MSUBAw, \ + PREFIX##MI_ITOF15, PREFIX##MI_FTOI15, PREFIX##MI_MULAw , PREFIX##MI_CLIP , \ + PREFIX##MI_MADDAi, PREFIX##MI_MSUBAi, PREFIX##unknown , PREFIX##MI_NOP , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ +}; \ + \ + \ + \ + void PREFIX##_UPPER_FD_00() { \ + PREFIX##_UPPER_FD_00_TABLE[(VU.code >> 6) & 0x1f ](); \ +} \ + \ + void PREFIX##_UPPER_FD_01() { \ + PREFIX##_UPPER_FD_01_TABLE[(VU.code >> 6) & 0x1f](); \ +} \ + \ + void PREFIX##_UPPER_FD_10() { \ + PREFIX##_UPPER_FD_10_TABLE[(VU.code >> 6) & 0x1f](); \ +} \ + \ + void PREFIX##_UPPER_FD_11() { \ + PREFIX##_UPPER_FD_11_TABLE[(VU.code >> 6) & 0x1f](); \ +} \ + \ + void PREFIX##LowerOP() { \ + PREFIX##LowerOP_OPCODE[VU.code & 0x3f](); \ +} \ + \ + void PREFIX##LowerOP_T3_00() { \ + PREFIX##LowerOP_T3_00_OPCODE[(VU.code >> 6) & 0x1f](); \ +} \ + \ + void PREFIX##LowerOP_T3_01() { \ + PREFIX##LowerOP_T3_01_OPCODE[(VU.code >> 6) & 0x1f](); \ +} \ + \ + void PREFIX##LowerOP_T3_10() { \ + PREFIX##LowerOP_T3_10_OPCODE[(VU.code >> 6) & 0x1f](); \ +} \ + \ + void PREFIX##LowerOP_T3_11() { \ + PREFIX##LowerOP_T3_11_OPCODE[(VU.code >> 6) & 0x1f](); \ +} + +#define _vuRegsTables(VU, PREFIX) \ + \ +void (*PREFIX##_LOWER_OPCODE[128])(_VURegsNum *VUregsn) = { \ + PREFIX##MI_LQ , PREFIX##MI_SQ , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_ILW , PREFIX##MI_ISW , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_IADDIU, PREFIX##MI_ISUBIU, PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_FCEQ , PREFIX##MI_FCSET , PREFIX##MI_FCAND, PREFIX##MI_FCOR, /* 0x10 */ \ + PREFIX##MI_FSEQ , PREFIX##MI_FSSET , PREFIX##MI_FSAND, PREFIX##MI_FSOR, \ + PREFIX##MI_FMEQ , PREFIX##unknown , PREFIX##MI_FMAND, PREFIX##MI_FMOR, \ + PREFIX##MI_FCGET , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_B , PREFIX##MI_BAL , PREFIX##unknown , PREFIX##unknown, /* 0x20 */ \ + PREFIX##MI_JR , PREFIX##MI_JALR , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_IBEQ , PREFIX##MI_IBNE , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_IBLTZ , PREFIX##MI_IBGTZ , PREFIX##MI_IBLEZ, PREFIX##MI_IBGEZ, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x30 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##LowerOP , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x40*/ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x50 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x60 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x70 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ +}; \ + \ + void (*PREFIX##LowerOP_T3_00_OPCODE[32])(_VURegsNum *VUregsn) = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_MOVE , PREFIX##MI_LQI , PREFIX##MI_DIV , PREFIX##MI_MTIR, \ + PREFIX##MI_RNEXT , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##MI_MFP , PREFIX##MI_XTOP , PREFIX##MI_XGKICK, \ + PREFIX##MI_ESADD , PREFIX##MI_EATANxy, PREFIX##MI_ESQRT, PREFIX##MI_ESIN, \ +}; \ + \ + void (*PREFIX##LowerOP_T3_01_OPCODE[32])(_VURegsNum *VUregsn) = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_MR32 , PREFIX##MI_SQI , PREFIX##MI_SQRT , PREFIX##MI_MFIR, \ + PREFIX##MI_RGET , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##MI_XITOP, PREFIX##unknown, \ + PREFIX##MI_ERSADD, PREFIX##MI_EATANxz, PREFIX##MI_ERSQRT, PREFIX##MI_EATAN, \ +}; \ + \ + void (*PREFIX##LowerOP_T3_10_OPCODE[32])(_VURegsNum *VUregsn) = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##MI_LQD , PREFIX##MI_RSQRT, PREFIX##MI_ILWR, \ + PREFIX##MI_RINIT , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_ELENG , PREFIX##MI_ESUM , PREFIX##MI_ERCPR, PREFIX##MI_EEXP, \ +}; \ + \ + void (*PREFIX##LowerOP_T3_11_OPCODE[32])(_VURegsNum *VUregsn) = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##MI_SQD , PREFIX##MI_WAITQ, PREFIX##MI_ISWR, \ + PREFIX##MI_RXOR , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_ERLENG, PREFIX##unknown , PREFIX##MI_WAITP, PREFIX##unknown, \ +}; \ + \ + void (*PREFIX##LowerOP_OPCODE[64])(_VURegsNum *VUregsn) = { \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x10 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x20 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##MI_IADD , PREFIX##MI_ISUB , PREFIX##MI_IADDI, PREFIX##unknown, /* 0x30 */ \ + PREFIX##MI_IAND , PREFIX##MI_IOR , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##LowerOP_T3_00, PREFIX##LowerOP_T3_01, PREFIX##LowerOP_T3_10, PREFIX##LowerOP_T3_11, \ +}; \ + \ + void (*PREFIX##_UPPER_OPCODE[64])(_VURegsNum *VUregsn) = { \ + PREFIX##MI_ADDx , PREFIX##MI_ADDy , PREFIX##MI_ADDz , PREFIX##MI_ADDw, \ + PREFIX##MI_SUBx , PREFIX##MI_SUBy , PREFIX##MI_SUBz , PREFIX##MI_SUBw, \ + PREFIX##MI_MADDx , PREFIX##MI_MADDy , PREFIX##MI_MADDz , PREFIX##MI_MADDw, \ + PREFIX##MI_MSUBx , PREFIX##MI_MSUBy , PREFIX##MI_MSUBz , PREFIX##MI_MSUBw, \ + PREFIX##MI_MAXx , PREFIX##MI_MAXy , PREFIX##MI_MAXz , PREFIX##MI_MAXw, /* 0x10 */ \ + PREFIX##MI_MINIx , PREFIX##MI_MINIy , PREFIX##MI_MINIz , PREFIX##MI_MINIw, \ + PREFIX##MI_MULx , PREFIX##MI_MULy , PREFIX##MI_MULz , PREFIX##MI_MULw, \ + PREFIX##MI_MULq , PREFIX##MI_MAXi , PREFIX##MI_MULi , PREFIX##MI_MINIi, \ + PREFIX##MI_ADDq , PREFIX##MI_MADDq , PREFIX##MI_ADDi , PREFIX##MI_MADDi, /* 0x20 */ \ + PREFIX##MI_SUBq , PREFIX##MI_MSUBq , PREFIX##MI_SUBi , PREFIX##MI_MSUBi, \ + PREFIX##MI_ADD , PREFIX##MI_MADD , PREFIX##MI_MUL , PREFIX##MI_MAX, \ + PREFIX##MI_SUB , PREFIX##MI_MSUB , PREFIX##MI_OPMSUB, PREFIX##MI_MINI, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, /* 0x30 */ \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown, \ + PREFIX##_UPPER_FD_00, PREFIX##_UPPER_FD_01, PREFIX##_UPPER_FD_10, PREFIX##_UPPER_FD_11, \ +}; \ + \ + void (*PREFIX##_UPPER_FD_00_TABLE[32])(_VURegsNum *VUregsn) = { \ + PREFIX##MI_ADDAx, PREFIX##MI_SUBAx , PREFIX##MI_MADDAx, PREFIX##MI_MSUBAx, \ + PREFIX##MI_ITOF0, PREFIX##MI_FTOI0, PREFIX##MI_MULAx , PREFIX##MI_MULAq , \ + PREFIX##MI_ADDAq, PREFIX##MI_SUBAq, PREFIX##MI_ADDA , PREFIX##MI_SUBA , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ +}; \ + \ + void (*PREFIX##_UPPER_FD_01_TABLE[32])(_VURegsNum *VUregsn) = { \ + PREFIX##MI_ADDAy , PREFIX##MI_SUBAy , PREFIX##MI_MADDAy, PREFIX##MI_MSUBAy, \ + PREFIX##MI_ITOF4 , PREFIX##MI_FTOI4 , PREFIX##MI_MULAy , PREFIX##MI_ABS , \ + PREFIX##MI_MADDAq, PREFIX##MI_MSUBAq, PREFIX##MI_MADDA , PREFIX##MI_MSUBA , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ +}; \ + \ + void (*PREFIX##_UPPER_FD_10_TABLE[32])(_VURegsNum *VUregsn) = { \ + PREFIX##MI_ADDAz , PREFIX##MI_SUBAz , PREFIX##MI_MADDAz, PREFIX##MI_MSUBAz, \ + PREFIX##MI_ITOF12, PREFIX##MI_FTOI12, PREFIX##MI_MULAz , PREFIX##MI_MULAi , \ + PREFIX##MI_ADDAi, PREFIX##MI_SUBAi , PREFIX##MI_MULA , PREFIX##MI_OPMULA, \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ +}; \ + \ + void (*PREFIX##_UPPER_FD_11_TABLE[32])(_VURegsNum *VUregsn) = { \ + PREFIX##MI_ADDAw , PREFIX##MI_SUBAw , PREFIX##MI_MADDAw, PREFIX##MI_MSUBAw, \ + PREFIX##MI_ITOF15, PREFIX##MI_FTOI15, PREFIX##MI_MULAw , PREFIX##MI_CLIP , \ + PREFIX##MI_MADDAi, PREFIX##MI_MSUBAi, PREFIX##unknown , PREFIX##MI_NOP , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ + PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , PREFIX##unknown , \ +}; \ + \ + \ + \ + void PREFIX##_UPPER_FD_00(_VURegsNum *VUregsn) { \ + PREFIX##_UPPER_FD_00_TABLE[(VU.code >> 6) & 0x1f ](VUregsn); \ +} \ + \ + void PREFIX##_UPPER_FD_01(_VURegsNum *VUregsn) { \ + PREFIX##_UPPER_FD_01_TABLE[(VU.code >> 6) & 0x1f](VUregsn); \ +} \ + \ + void PREFIX##_UPPER_FD_10(_VURegsNum *VUregsn) { \ + PREFIX##_UPPER_FD_10_TABLE[(VU.code >> 6) & 0x1f](VUregsn); \ +} \ + \ + void PREFIX##_UPPER_FD_11(_VURegsNum *VUregsn) { \ + PREFIX##_UPPER_FD_11_TABLE[(VU.code >> 6) & 0x1f](VUregsn); \ +} \ + \ + void PREFIX##LowerOP(_VURegsNum *VUregsn) { \ + PREFIX##LowerOP_OPCODE[VU.code & 0x3f](VUregsn); \ +} \ + \ + void PREFIX##LowerOP_T3_00(_VURegsNum *VUregsn) { \ + PREFIX##LowerOP_T3_00_OPCODE[(VU.code >> 6) & 0x1f](VUregsn); \ +} \ + \ + void PREFIX##LowerOP_T3_01(_VURegsNum *VUregsn) { \ + PREFIX##LowerOP_T3_01_OPCODE[(VU.code >> 6) & 0x1f](VUregsn); \ +} \ + \ + void PREFIX##LowerOP_T3_10(_VURegsNum *VUregsn) { \ + PREFIX##LowerOP_T3_10_OPCODE[(VU.code >> 6) & 0x1f](VUregsn); \ +} \ + \ + void PREFIX##LowerOP_T3_11(_VURegsNum *VUregsn) { \ + PREFIX##LowerOP_T3_11_OPCODE[(VU.code >> 6) & 0x1f](VUregsn); \ +} + + +#ifdef VUM_LOG + +#define IdebugUPPER(VU) \ + VUM_LOG("%s\n", dis##VU##MicroUF(VU.code, VU.VI[REG_TPC].UL)); +#define IdebugLOWER(VU) \ + VUM_LOG("%s\n", dis##VU##MicroLF(VU.code, VU.VI[REG_TPC].UL)); + +#else + +#define IdebugUPPER(VU) +#define IdebugLOWER(VU) + +#endif + +#ifdef VUM_LOG +#define _vuExecMicroDebug(VU) \ + VUM_LOG("_vuExecMicro: %8.8x\n", VU.VI[REG_TPC].UL); +#else +#define _vuExecMicroDebug(VU) +#endif + +#include "VUops.h" + +#endif + diff --git a/pcsx2/VUmicroMem.cpp b/pcsx2/VUmicroMem.cpp index b058dd8ac3..0f73af365f 100644 --- a/pcsx2/VUmicroMem.cpp +++ b/pcsx2/VUmicroMem.cpp @@ -1,198 +1,198 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include - -#include "Common.h" -#include "R5900.h" -#include "VUmicro.h" - -#include "iVUzerorec.h" - -// The following CpuVU objects are value types instead of handles or pointers because they are -// modified on the fly to implement VU1 Skip. - -VUmicroCpu CpuVU0; // contains a working copy of the VU0 cpu functions/API -VUmicroCpu CpuVU1; // contains a working copy of the VU1 cpu functions/API - -static void DummyExecuteVU1Block(void) -{ - VU0.VI[ REG_VPU_STAT ].UL &= ~0x100; - VU1.vifRegs->stat &= ~4; // also reset the bit (grandia 3 works) -} - -void vu1MicroEnableSkip() -{ - CpuVU1.ExecuteBlock = DummyExecuteVU1Block; -} - -void vu1MicroDisableSkip() -{ - CpuVU1.ExecuteBlock = CHECK_VU1REC ? recVU1.ExecuteBlock : intVU1.ExecuteBlock; -} - -bool vu1MicroIsSkipping() -{ - return CpuVU1.ExecuteBlock == DummyExecuteVU1Block; -} - -void vuMicroCpuReset() -{ - CpuVU0 = CHECK_VU0REC ? recVU0 : intVU0; - CpuVU1 = CHECK_VU1REC ? recVU1 : intVU1; - CpuVU0.Reset(); - CpuVU1.Reset(); - - // SuperVUreset will do nothing is none of the recs are initialized. - // But it's needed if one or the other is initialized. - SuperVUReset(-1); -} - -static u8* m_vuAllMem = NULL; -static const uint m_vuMemSize = - 0x1000 + // VU0micro memory - 0x4000+0x800 + // VU0 memory and VU1 registers - 0x4000 + // VU1 memory - 0x4000;/* + // VU1micro memory - 0x4000; */ // HACKFIX (see below) - -// HACKFIX! (air) -// The VIFdma1 has a nasty habit of transferring data into the 4k page of memory above -// the VU1. (oops!!) This happens to be recLUT most of the time, which causes rapid death -// of our emulator. So we allocate some extra space here to keep VIF1 a little happier. - -// fixme - When the VIF is fixed, remove the third +0x4000 above. :) - -void vuMicroMemAlloc() -{ - if( m_vuAllMem == NULL ) - m_vuAllMem = vtlb_malloc( m_vuMemSize, 16, 0x28000000 ); - - if( m_vuAllMem == NULL ) - throw Exception::OutOfMemory( "vuMicroMemInit > Failed to allocate VUmicro memory." ); - - jASSUME( sizeof( VURegs ) <= 0x800 ); - - u8* curpos = m_vuAllMem; - VU0.Micro = curpos; curpos += 0x1000; - VU0.Mem = curpos; curpos += 0x4000; - g_pVU1 = (VURegs*)curpos; curpos += 0x800; - VU1.Micro = curpos; curpos += 0x4000; - VU1.Mem = curpos; - //curpos += 0x4000; -} - -void vuMicroMemShutdown() -{ - // -- VTLB Memory Allocation -- - - vtlb_free( m_vuAllMem, m_vuMemSize ); - m_vuAllMem = NULL; - g_pVU1 = NULL; -} - -void vuMicroMemReset() -{ - jASSUME( VU0.Mem != NULL ); - jASSUME( VU1.Mem != NULL ); - - memMapVUmicro(); - - // === VU0 Initialization === - memzero_obj(VU0.ACC); - memzero_obj(VU0.VF); - memzero_obj(VU0.VI); - VU0.VF[0].f.x = 0.0f; - VU0.VF[0].f.y = 0.0f; - VU0.VF[0].f.z = 0.0f; - VU0.VF[0].f.w = 1.0f; - VU0.VI[0].UL = 0; - memzero_ptr<4*1024>(VU0.Mem); - memzero_ptr<4*1024>(VU0.Micro); - - /* this is kinda tricky, maxmem is set to 0x4400 here, - tho it's not 100% accurate, since the mem goes from - 0x0000 - 0x1000 (Mem) and 0x4000 - 0x4400 (VU1 Regs), - i guess it shouldn't be a problem, - at least hope so :) (linuz) - */ - VU0.maxmem = 0x4800-4; //We are allocating 0x800 for vu1 reg's - VU0.maxmicro = 0x1000-4; - VU0.vuExec = vu0Exec; - VU0.vifRegs = vif0Regs; - - // === VU1 Initialization === - memzero_obj(VU1.ACC); - memzero_obj(VU1.VF); - memzero_obj(VU1.VI); - VU1.VF[0].f.x = 0.0f; - VU1.VF[0].f.y = 0.0f; - VU1.VF[0].f.z = 0.0f; - VU1.VF[0].f.w = 1.0f; - VU1.VI[0].UL = 0; - memzero_ptr<16*1024>(VU1.Mem); - memzero_ptr<16*1024>(VU1.Micro); - - VU1.maxmem = 0x4000-4;//16*1024-4; - VU1.maxmicro = 0x4000-4; -// VU1.VF = (VECTOR*)(VU0.Mem + 0x4000); -// VU1.VI = (REG_VI*)(VU0.Mem + 0x4200); - VU1.vuExec = vu1Exec; - VU1.vifRegs = vif1Regs; -} - -void SaveState::vuMicroFreeze() -{ - jASSUME( VU0.Mem != NULL ); - jASSUME( VU1.Mem != NULL ); - - Freeze(VU0.ACC); - Freeze(VU0.code); - FreezeMem(VU0.Mem, 4*1024); - FreezeMem(VU0.Micro, 4*1024); - - Freeze(VU0.VF); - if( GetVersion() >= 0x0012 ) - Freeze(VU0.VI); - else - { - // Old versions stored the VIregs as 32 bit values... - memzero_obj( VU0.VI ); - for(int i=0; i<32; i++ ) - Freeze( VU0.VI[i].UL ); - } - - Freeze(VU1.ACC); - Freeze(VU1.code); - FreezeMem(VU1.Mem, 16*1024); - FreezeMem(VU1.Micro, 16*1024); - - Freeze(VU1.VF); - if( GetVersion() >= 0x0012 ) - Freeze(VU1.VI); - else - { - // Old versions stored the VIregs as 32 bit values... - memzero_obj( VU1.VI ); - for(int i=0; i<32; i++ ) - Freeze( VU1.VI[i].UL ); - } - -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include + +#include "Common.h" +#include "R5900.h" +#include "VUmicro.h" + +#include "iVUzerorec.h" + +// The following CpuVU objects are value types instead of handles or pointers because they are +// modified on the fly to implement VU1 Skip. + +VUmicroCpu CpuVU0; // contains a working copy of the VU0 cpu functions/API +VUmicroCpu CpuVU1; // contains a working copy of the VU1 cpu functions/API + +static void DummyExecuteVU1Block(void) +{ + VU0.VI[ REG_VPU_STAT ].UL &= ~0x100; + VU1.vifRegs->stat &= ~4; // also reset the bit (grandia 3 works) +} + +void vu1MicroEnableSkip() +{ + CpuVU1.ExecuteBlock = DummyExecuteVU1Block; +} + +void vu1MicroDisableSkip() +{ + CpuVU1.ExecuteBlock = CHECK_VU1REC ? recVU1.ExecuteBlock : intVU1.ExecuteBlock; +} + +bool vu1MicroIsSkipping() +{ + return CpuVU1.ExecuteBlock == DummyExecuteVU1Block; +} + +void vuMicroCpuReset() +{ + CpuVU0 = CHECK_VU0REC ? recVU0 : intVU0; + CpuVU1 = CHECK_VU1REC ? recVU1 : intVU1; + CpuVU0.Reset(); + CpuVU1.Reset(); + + // SuperVUreset will do nothing is none of the recs are initialized. + // But it's needed if one or the other is initialized. + SuperVUReset(-1); +} + +static u8* m_vuAllMem = NULL; +static const uint m_vuMemSize = + 0x1000 + // VU0micro memory + 0x4000+0x800 + // VU0 memory and VU1 registers + 0x4000 + // VU1 memory + 0x4000;/* + // VU1micro memory + 0x4000; */ // HACKFIX (see below) + +// HACKFIX! (air) +// The VIFdma1 has a nasty habit of transferring data into the 4k page of memory above +// the VU1. (oops!!) This happens to be recLUT most of the time, which causes rapid death +// of our emulator. So we allocate some extra space here to keep VIF1 a little happier. + +// fixme - When the VIF is fixed, remove the third +0x4000 above. :) + +void vuMicroMemAlloc() +{ + if( m_vuAllMem == NULL ) + m_vuAllMem = vtlb_malloc( m_vuMemSize, 16, 0x28000000 ); + + if( m_vuAllMem == NULL ) + throw Exception::OutOfMemory( "vuMicroMemInit > Failed to allocate VUmicro memory." ); + + jASSUME( sizeof( VURegs ) <= 0x800 ); + + u8* curpos = m_vuAllMem; + VU0.Micro = curpos; curpos += 0x1000; + VU0.Mem = curpos; curpos += 0x4000; + g_pVU1 = (VURegs*)curpos; curpos += 0x800; + VU1.Micro = curpos; curpos += 0x4000; + VU1.Mem = curpos; + //curpos += 0x4000; +} + +void vuMicroMemShutdown() +{ + // -- VTLB Memory Allocation -- + + vtlb_free( m_vuAllMem, m_vuMemSize ); + m_vuAllMem = NULL; + g_pVU1 = NULL; +} + +void vuMicroMemReset() +{ + jASSUME( VU0.Mem != NULL ); + jASSUME( VU1.Mem != NULL ); + + memMapVUmicro(); + + // === VU0 Initialization === + memzero_obj(VU0.ACC); + memzero_obj(VU0.VF); + memzero_obj(VU0.VI); + VU0.VF[0].f.x = 0.0f; + VU0.VF[0].f.y = 0.0f; + VU0.VF[0].f.z = 0.0f; + VU0.VF[0].f.w = 1.0f; + VU0.VI[0].UL = 0; + memzero_ptr<4*1024>(VU0.Mem); + memzero_ptr<4*1024>(VU0.Micro); + + /* this is kinda tricky, maxmem is set to 0x4400 here, + tho it's not 100% accurate, since the mem goes from + 0x0000 - 0x1000 (Mem) and 0x4000 - 0x4400 (VU1 Regs), + i guess it shouldn't be a problem, + at least hope so :) (linuz) + */ + VU0.maxmem = 0x4800-4; //We are allocating 0x800 for vu1 reg's + VU0.maxmicro = 0x1000-4; + VU0.vuExec = vu0Exec; + VU0.vifRegs = vif0Regs; + + // === VU1 Initialization === + memzero_obj(VU1.ACC); + memzero_obj(VU1.VF); + memzero_obj(VU1.VI); + VU1.VF[0].f.x = 0.0f; + VU1.VF[0].f.y = 0.0f; + VU1.VF[0].f.z = 0.0f; + VU1.VF[0].f.w = 1.0f; + VU1.VI[0].UL = 0; + memzero_ptr<16*1024>(VU1.Mem); + memzero_ptr<16*1024>(VU1.Micro); + + VU1.maxmem = 0x4000-4;//16*1024-4; + VU1.maxmicro = 0x4000-4; +// VU1.VF = (VECTOR*)(VU0.Mem + 0x4000); +// VU1.VI = (REG_VI*)(VU0.Mem + 0x4200); + VU1.vuExec = vu1Exec; + VU1.vifRegs = vif1Regs; +} + +void SaveState::vuMicroFreeze() +{ + jASSUME( VU0.Mem != NULL ); + jASSUME( VU1.Mem != NULL ); + + Freeze(VU0.ACC); + Freeze(VU0.code); + FreezeMem(VU0.Mem, 4*1024); + FreezeMem(VU0.Micro, 4*1024); + + Freeze(VU0.VF); + if( GetVersion() >= 0x0012 ) + Freeze(VU0.VI); + else + { + // Old versions stored the VIregs as 32 bit values... + memzero_obj( VU0.VI ); + for(int i=0; i<32; i++ ) + Freeze( VU0.VI[i].UL ); + } + + Freeze(VU1.ACC); + Freeze(VU1.code); + FreezeMem(VU1.Mem, 16*1024); + FreezeMem(VU1.Micro, 16*1024); + + Freeze(VU1.VF); + if( GetVersion() >= 0x0012 ) + Freeze(VU1.VI); + else + { + // Old versions stored the VIregs as 32 bit values... + memzero_obj( VU1.VI ); + for(int i=0; i<32; i++ ) + Freeze( VU1.VI[i].UL ); + } + +} diff --git a/pcsx2/VUops.cpp b/pcsx2/VUops.cpp index bc33358014..f3123f4dd2 100644 --- a/pcsx2/VUops.cpp +++ b/pcsx2/VUops.cpp @@ -1,2929 +1,2929 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include - -#include "Common.h" -#include "VUmicro.h" -#include "VUflags.h" -#include "VUops.h" -#include "GS.h" - -//Lower/Upper instructions can use that.. -#define _Ft_ ((VU->code >> 16) & 0x1F) // The rt part of the instruction register -#define _Fs_ ((VU->code >> 11) & 0x1F) // The rd part of the instruction register -#define _Fd_ ((VU->code >> 6) & 0x1F) // The sa part of the instruction register - -#define _X ((VU->code>>24) & 0x1) -#define _Y ((VU->code>>23) & 0x1) -#define _Z ((VU->code>>22) & 0x1) -#define _W ((VU->code>>21) & 0x1) - -#define _XYZW ((VU->code>>21) & 0xF) - -#define _Fsf_ ((VU->code >> 21) & 0x03) -#define _Ftf_ ((VU->code >> 23) & 0x03) - -#define _Imm11_ (s32)(VU->code & 0x400 ? 0xfffffc00 | (VU->code & 0x3ff) : VU->code & 0x3ff) -#define _UImm11_ (s32)(VU->code & 0x7ff) - - -VECTOR RDzero; - -void _vuFMACflush(VURegs * VU) { - int i; - - for (i=0; i<8; i++) { - if (VU->fmac[i].enable == 0) continue; - - if ((VU->cycle - VU->fmac[i].sCycle) >= VU->fmac[i].Cycle) { - VUM_LOG("flushing FMAC pipe[%d] (macflag=%x)\n", i, VU->fmac[i].macflag); - - VU->fmac[i].enable = 0; - VU->VI[REG_MAC_FLAG].UL = VU->fmac[i].macflag; - VU->VI[REG_STATUS_FLAG].UL = VU->fmac[i].statusflag; - VU->VI[REG_CLIP_FLAG].UL = VU->fmac[i].clipflag; - } - } -} - -void _vuFDIVflush(VURegs * VU) { - if (VU->fdiv.enable == 0) return; - - if ((VU->cycle - VU->fdiv.sCycle) >= VU->fdiv.Cycle) { - VUM_LOG("flushing FDIV pipe\n"); - - VU->fdiv.enable = 0; - VU->VI[REG_Q].UL = VU->fdiv.reg.UL; - VU->VI[REG_STATUS_FLAG].UL = VU->fdiv.statusflag; - } -} - -void _vuEFUflush(VURegs * VU) { - if (VU->efu.enable == 0) return; - - if ((VU->cycle - VU->efu.sCycle) >= VU->efu.Cycle) { -// VUM_LOG("flushing EFU pipe\n"); - - VU->efu.enable = 0; - VU->VI[REG_P].UL = VU->efu.reg.UL; - } -} - -// called at end of program -void _vuFlushAll(VURegs* VU) -{ - int nRepeat = 1, i; - - do { - nRepeat = 0; - - for (i=0; i<8; i++) { - if (VU->fmac[i].enable == 0) continue; - - nRepeat = 1; - - if ((VU->cycle - VU->fmac[i].sCycle) >= VU->fmac[i].Cycle) { - VUM_LOG("flushing FMAC pipe[%d] (macflag=%x)\n", i, VU->fmac[i].macflag); - - VU->fmac[i].enable = 0; - VU->VI[REG_MAC_FLAG].UL = VU->fmac[i].macflag; - VU->VI[REG_STATUS_FLAG].UL = VU->fmac[i].statusflag; - VU->VI[REG_CLIP_FLAG].UL = VU->fmac[i].clipflag; - } - } - - if (VU->fdiv.enable ) { - - nRepeat = 1; - - if ((VU->cycle - VU->fdiv.sCycle) >= VU->fdiv.Cycle) { - VUM_LOG("flushing FDIV pipe\n"); - - nRepeat = 1; - VU->fdiv.enable = 0; - VU->VI[REG_Q].UL = VU->fdiv.reg.UL; - VU->VI[REG_STATUS_FLAG].UL = VU->fdiv.statusflag; - } - } - - if (VU->efu.enable) { - - nRepeat = 1; - - if ((VU->cycle - VU->efu.sCycle) >= VU->efu.Cycle) { - // VUM_LOG("flushing EFU pipe\n"); - - nRepeat = 1; - VU->efu.enable = 0; - VU->VI[REG_P].UL = VU->efu.reg.UL; - } - } - - VU->cycle++; - - } while(nRepeat); -} - -void _vuTestPipes(VURegs * VU) { - _vuFMACflush(VU); - _vuFDIVflush(VU); - _vuEFUflush(VU); -} - -void _vuFMACTestStall(VURegs * VU, int reg, int xyzw) { - int cycle; - int i; - - for (i=0; i<8; i++) { - if (VU->fmac[i].enable == 0) continue; - if (VU->fmac[i].reg == reg && - VU->fmac[i].xyzw & xyzw) break; - } - - if (i == 8) return; - - cycle = VU->fmac[i].Cycle - (VU->cycle - VU->fmac[i].sCycle) + 1; // add 1 delay! (fixes segaclassics bad geom) - VU->fmac[i].enable = 0; - VU->VI[REG_MAC_FLAG].UL = VU->fmac[i].macflag; - VU->VI[REG_STATUS_FLAG].UL = VU->fmac[i].statusflag; - VU->VI[REG_CLIP_FLAG].UL = VU->fmac[i].clipflag; - VUM_LOG("FMAC[%d] stall %d\n", i, cycle); - - VU->cycle+= cycle; - _vuTestPipes(VU); -} - -void _vuFMACAdd(VURegs * VU, int reg, int xyzw) { - int i; - - /* find a free fmac pipe */ - for (i=0; i<8; i++) { - if (VU->fmac[i].enable == 1) continue; - break; - } - if (i==8) { -// SysPrintf("*PCSX2*: error , out of fmacs %d\n", VU->cycle); - } - - VUM_LOG("adding FMAC pipe[%d]; xyzw=%x\n", i, xyzw); - - VU->fmac[i].enable = 1; - VU->fmac[i].sCycle = VU->cycle; - VU->fmac[i].Cycle = 3; - VU->fmac[i].reg = reg; - VU->fmac[i].xyzw = xyzw; - VU->fmac[i].macflag = VU->macflag; - VU->fmac[i].statusflag = VU->statusflag; - VU->fmac[i].clipflag = VU->clipflag; -} - -void _vuFDIVAdd(VURegs * VU, int cycles) { - VUM_LOG("adding FDIV pipe\n"); - - VU->fdiv.enable = 1; - VU->fdiv.sCycle = VU->cycle; - VU->fdiv.Cycle = cycles; - VU->fdiv.reg.F = VU->q.F; - VU->fdiv.statusflag = VU->statusflag; -} - -void _vuEFUAdd(VURegs * VU, int cycles) { -// VUM_LOG("adding EFU pipe\n"); - - VU->efu.enable = 1; - VU->efu.sCycle = VU->cycle; - VU->efu.Cycle = cycles; - VU->efu.reg.F = VU->p.F; -} - -void _vuFlushFDIV(VURegs * VU) { - int cycle; - - if (VU->fdiv.enable == 0) return; - - cycle = VU->fdiv.Cycle - (VU->cycle - VU->fdiv.sCycle); - VUM_LOG("waiting FDIV pipe %d\n", cycle); - - VU->fdiv.enable = 0; - VU->cycle+= cycle; - VU->VI[REG_Q].UL = VU->fdiv.reg.UL; - VU->VI[REG_STATUS_FLAG].UL = VU->fdiv.statusflag; -} - -void _vuFlushEFU(VURegs * VU) { - int cycle; - - if (VU->efu.enable == 0) return; - - cycle = VU->efu.Cycle - (VU->cycle - VU->efu.sCycle); -// VUM_LOG("waiting EFU pipe %d\n", cycle); - - VU->efu.enable = 0; - VU->cycle+= cycle; - VU->VI[REG_P].UL = VU->efu.reg.UL; -} - -void _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn) { - if (VUregsn->VFread0) { - _vuFMACTestStall(VU, VUregsn->VFread0, VUregsn->VFr0xyzw); - } - if (VUregsn->VFread1) { - _vuFMACTestStall(VU, VUregsn->VFread1, VUregsn->VFr1xyzw); - } -} - -void _vuAddFMACStalls(VURegs * VU, _VURegsNum *VUregsn) { - if (VUregsn->VFwrite) { - _vuFMACAdd(VU, VUregsn->VFwrite, VUregsn->VFwxyzw); - } else - if (VUregsn->VIwrite & (1 << REG_CLIP_FLAG)) { - _vuFMACAdd(VU, -REG_CLIP_FLAG, 0); - } else { - _vuFMACAdd(VU, 0, 0); - } -} - -void _vuTestFDIVStalls(VURegs * VU, _VURegsNum *VUregsn) { -// _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn); - _vuFlushFDIV(VU); -} - -void _vuAddFDIVStalls(VURegs * VU, _VURegsNum *VUregsn) { - if (VUregsn->VIwrite & (1 << REG_Q)) { - _vuFDIVAdd(VU, VUregsn->cycles); - } -} - - -void _vuTestEFUStalls(VURegs * VU, _VURegsNum *VUregsn) { -// _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn); - _vuFlushEFU(VU); -} - -void _vuAddEFUStalls(VURegs * VU, _VURegsNum *VUregsn) { - if (VUregsn->VIwrite & (1 << REG_P)) { - _vuEFUAdd(VU, VUregsn->cycles); - } -} - -void _vuTestUpperStalls(VURegs * VU, _VURegsNum *VUregsn) { - switch (VUregsn->pipe) { - case VUPIPE_FMAC: _vuTestFMACStalls(VU, VUregsn); break; - } -} - -void _vuTestLowerStalls(VURegs * VU, _VURegsNum *VUregsn) { - switch (VUregsn->pipe) { - case VUPIPE_FMAC: _vuTestFMACStalls(VU, VUregsn); break; - case VUPIPE_FDIV: _vuTestFDIVStalls(VU, VUregsn); break; - case VUPIPE_EFU: _vuTestEFUStalls(VU, VUregsn); break; - } -} - -void _vuAddUpperStalls(VURegs * VU, _VURegsNum *VUregsn) { - switch (VUregsn->pipe) { - case VUPIPE_FMAC: _vuAddFMACStalls(VU, VUregsn); break; - } -} - -void _vuAddLowerStalls(VURegs * VU, _VURegsNum *VUregsn) { - switch (VUregsn->pipe) { - case VUPIPE_FMAC: _vuAddFMACStalls(VU, VUregsn); break; - case VUPIPE_FDIV: _vuAddFDIVStalls(VU, VUregsn); break; - case VUPIPE_EFU: _vuAddEFUStalls(VU, VUregsn); break; - } -} - - -/******************************/ -/* VU Upper instructions */ -/******************************/ -#ifndef INT_VUDOUBLEHACK -static u32 d; -float vuDouble(u32 f) -{ - switch(f & 0x7f800000){ - case 0x0: - f &= 0x80000000; - return *(float*)&f; - break; - case 0x7f800000: - d = (f & 0x80000000)|0x7f7fffff; - return *(float*)&d; - break; - default: - return *(float*)&f; - break; - } -} -#else -float vuDouble(u32 f) -{ - return *(float*)&f; -} -#endif - -void _vuABS(VURegs * VU) { - if (_Ft_ == 0) return; - - if (_X){ VU->VF[_Ft_].f.x = fabs(vuDouble(VU->VF[_Fs_].i.x)); } - if (_Y){ VU->VF[_Ft_].f.y = fabs(vuDouble(VU->VF[_Fs_].i.y)); } - if (_Z){ VU->VF[_Ft_].f.z = fabs(vuDouble(VU->VF[_Fs_].i.z)); } - if (_W){ VU->VF[_Ft_].f.w = fabs(vuDouble(VU->VF[_Fs_].i.w)); } -}/*Reworked from define to function. asadr*/ - - -void _vuADD(VURegs * VU) { - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*Reworked from define to function. asadr*/ - - -void _vuADDi(VURegs * VU) { - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VI[REG_I].UL));} else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VI[REG_I].UL));} else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + vuDouble(VU->VI[REG_I].UL));} else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + vuDouble(VU->VI[REG_I].UL));} else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*Reworked from define to function. asadr*/ - -void _vuADDq(VURegs * VU) { - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VI[REG_Q].UL)); } else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VI[REG_Q].UL)); } else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + vuDouble(VU->VI[REG_Q].UL)); } else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + vuDouble(VU->VI[REG_Q].UL)); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*Reworked from define to function. asadr*/ - - -void _vuADDx(VURegs * VU) { - float ftx; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - ftx=vuDouble(VU->VF[_Ft_].i.x); - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + ftx); } else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + ftx); } else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + ftx); } else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + ftx); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*Reworked from define to function. asadr*/ - -void _vuADDy(VURegs * VU) { - float fty; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - fty=vuDouble(VU->VF[_Ft_].i.y); - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + fty);} else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + fty);} else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + fty);} else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + fty);} else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*Reworked from define to function. asadr*/ - -void _vuADDz(VURegs * VU) { - float ftz; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - ftz=vuDouble(VU->VF[_Ft_].i.z); - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + ftz); } else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + ftz); } else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + ftz); } else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + ftz); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*Reworked from define to function. asadr*/ - -void _vuADDw(VURegs * VU) { - float ftw; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - ftw=vuDouble(VU->VF[_Ft_].i.w); - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + ftw); } else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + ftw); } else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + ftw); } else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + ftw); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*Reworked from define to function. asadr*/ - -void _vuADDA(VURegs * VU) { - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*Reworked from define to function. asadr*/ - -void _vuADDAi(VURegs * VU) { - float ti = vuDouble(VU->VI[REG_I].UL); - - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + ti); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + ti); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + ti); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + ti); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*Reworked from define to function. asadr*/ - -void _vuADDAq(VURegs * VU) { - float tf = vuDouble(VU->VI[REG_Q].UL); - - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + tf); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + tf); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + tf); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + tf); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*Reworked from define to function. asadr*/ - -void _vuADDAx(VURegs * VU) { - float tx = vuDouble(VU->VF[_Ft_].i.x); - - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + tx); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + tx); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + tx); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + tx); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*Reworked from define to function. asadr*/ - -void _vuADDAy(VURegs * VU) { - float ty = vuDouble(VU->VF[_Ft_].i.y); - - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + ty); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + ty); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + ty); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + ty); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*Reworked from define to function. asadr*/ - -void _vuADDAz(VURegs * VU) { - float tz = vuDouble(VU->VF[_Ft_].i.z); - - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + tz); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + tz); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + tz); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + tz); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*Reworked from define to function. asadr*/ - -void _vuADDAw(VURegs * VU) { - float tw = vuDouble(VU->VF[_Ft_].i.w); - - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + tw); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + tw); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + tw); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + tw); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*Reworked from define to function. asadr*/ - - -void _vuSUB(VURegs * VU) { - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}//updated 10/05/03 shadow - -void _vuSUBi(VURegs * VU) { - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}//updated 10/05/03 shadow - -void _vuSUBq(VURegs * VU) { - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}//updated 10/05/03 shadow - -void _vuSUBx(VURegs * VU) { - float ftx; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - ftx=vuDouble(VU->VF[_Ft_].i.x); - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - ftx); } else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - ftx); } else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - ftx); } else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - ftx); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}//updated 10/05/03 shadow - -void _vuSUBy(VURegs * VU) { - float fty; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - fty=vuDouble(VU->VF[_Ft_].i.y); - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - fty); } else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - fty); } else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - fty); } else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - fty); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}//updated 10/05/03 shadow - -void _vuSUBz(VURegs * VU) { - float ftz; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - ftz=vuDouble(VU->VF[_Ft_].i.z); - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - ftz); } else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - ftz); } else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - ftz); } else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - ftz); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}//updated 10/05/03 shadow - -void _vuSUBw(VURegs * VU) { - float ftw; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - ftw=vuDouble(VU->VF[_Ft_].i.w); - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - ftw); } else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - ftw); } else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - ftw); } else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - ftw); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}//updated 10/05/03 shadow - - -void _vuSUBA(VURegs * VU) { - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}//updated 10/05/03 shadow - -void _vuSUBAi(VURegs * VU) { - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}//updated 10/05/03 shadow - -void _vuSUBAq(VURegs * VU) { - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}//updated 10/05/03 shadow - -void _vuSUBAx(VURegs * VU) { - float tx = vuDouble(VU->VF[_Ft_].i.x); - - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - tx); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - tx); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - tx); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - tx); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}//updated 10/05/03 shadow - -void _vuSUBAy(VURegs * VU) { - float ty = vuDouble(VU->VF[_Ft_].i.y); - - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - ty); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - ty); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - ty); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - ty); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}//updated 10/05/03 shadow - -void _vuSUBAz(VURegs * VU) { - float tz = vuDouble(VU->VF[_Ft_].i.z); - - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - tz); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - tz); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - tz); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - tz); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}//updated 10/05/03 shadow - -void _vuSUBAw(VURegs * VU) { - float tw = vuDouble(VU->VF[_Ft_].i.w); - - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - tw); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - tw); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - tw); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - tw); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}//updated 10/05/03 shadow - -void _vuMUL(VURegs * VU) { - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 8/05/03 shadow */ - -/* No need to presave I reg in ti. asadr */ -void _vuMULi(VURegs * VU) { - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 8/05/03 shadow */ - -void _vuMULq(VURegs * VU) { - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 8/05/03 shadow */ - -void _vuMULx(VURegs * VU) { - float ftx; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - ftx=vuDouble(VU->VF[_Ft_].i.x); - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * ftx); } else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * ftx); } else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * ftx); } else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * ftx); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 8/05/03 shadow */ - - -void _vuMULy(VURegs * VU) { - float fty; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - fty=vuDouble(VU->VF[_Ft_].i.y); - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * fty); } else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * fty); } else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * fty); } else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * fty); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 8/05/03 shadow */ - -void _vuMULz(VURegs * VU) { - float ftz; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - ftz=vuDouble(VU->VF[_Ft_].i.z); - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * ftz); } else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * ftz); } else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * ftz); } else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * ftz); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 8/05/03 shadow */ - -void _vuMULw(VURegs * VU) { - float ftw; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - ftw=vuDouble(VU->VF[_Ft_].i.w); - if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * ftw); } else VU_MACx_CLEAR(VU); - if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * ftw); } else VU_MACy_CLEAR(VU); - if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * ftw); } else VU_MACz_CLEAR(VU); - if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * ftw); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 8/05/03 shadow */ - - -void _vuMULA(VURegs * VU) { - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 8/05/03 shadow */ - -/* No need to presave I reg in ti. asadr */ -void _vuMULAi(VURegs * VU) { - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 8/05/03 shadow */ - -/* No need to presave Q reg in ti. asadr */ -void _vuMULAq(VURegs * VU) { - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 8/05/03 shadow */ - -/* No need to presave X reg in ti. asadr */ -void _vuMULAx(VURegs * VU) { - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 8/05/03 shadow */ - -void _vuMULAy(VURegs * VU) { - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 8/05/03 shadow */ - -void _vuMULAz(VURegs * VU) { - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 8/05/03 shadow */ - -void _vuMULAw(VURegs * VU) { - if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACx_CLEAR(VU); - if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACy_CLEAR(VU); - if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACz_CLEAR(VU); - if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 8/05/03 shadow */ - -void _vuMADD(VURegs * VU) { - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACx_CLEAR(VU); - if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACy_CLEAR(VU); - if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACz_CLEAR(VU); - if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 10/05/03 shadow */ - - -void _vuMADDi(VURegs * VU) { - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_I].UL))); else VU_MACx_CLEAR(VU); - if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_I].UL))); else VU_MACy_CLEAR(VU); - if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_I].UL))); else VU_MACz_CLEAR(VU); - if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_I].UL))); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 10/05/03 shadow */ - -/* No need to presave . asadr */ -void _vuMADDq(VURegs * VU) { - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACx_CLEAR(VU); - if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACy_CLEAR(VU); - if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACz_CLEAR(VU); - if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 10/05/03 shadow */ - -void _vuMADDx(VURegs * VU) { - float ftx; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - ftx=vuDouble(VU->VF[_Ft_].i.x); - if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * ftx)); else VU_MACx_CLEAR(VU); - if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * ftx)); else VU_MACy_CLEAR(VU); - if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * ftx)); else VU_MACz_CLEAR(VU); - if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * ftx)); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 10/05/03 shadow */ - -void _vuMADDy(VURegs * VU) { - float fty; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - fty=vuDouble(VU->VF[_Ft_].i.y); - if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * fty)); else VU_MACx_CLEAR(VU); - if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * fty)); else VU_MACy_CLEAR(VU); - if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * fty)); else VU_MACz_CLEAR(VU); - if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * fty)); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 10/05/03 shadow */ - -void _vuMADDz(VURegs * VU) { - float ftz; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - ftz=vuDouble(VU->VF[_Ft_].i.z); - if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * ftz)); else VU_MACx_CLEAR(VU); - if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * ftz)); else VU_MACy_CLEAR(VU); - if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * ftz)); else VU_MACz_CLEAR(VU); - if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * ftz)); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 10/05/03 shadow */ - -void _vuMADDw(VURegs * VU) { - float ftw; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - ftw=vuDouble(VU->VF[_Ft_].i.w); - if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * ftw)); else VU_MACx_CLEAR(VU); - if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * ftw)); else VU_MACy_CLEAR(VU); - if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * ftw)); else VU_MACz_CLEAR(VU); - if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * ftw)); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 10/05/03 shadow */ - -void _vuMADDA(VURegs * VU) { - if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACx_CLEAR(VU); - if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACy_CLEAR(VU); - if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACz_CLEAR(VU); - if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*last updated 10/05/03 shadow*/ - -void _vuMADDAi(VURegs * VU) { - float ti = vuDouble(VU->VI[REG_I].UL); - - if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * ti)); else VU_MACx_CLEAR(VU); - if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * ti)); else VU_MACy_CLEAR(VU); - if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * ti)); else VU_MACz_CLEAR(VU); - if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * ti)); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*last updated 10/05/03 shadow*/ - -void _vuMADDAq(VURegs * VU) { - float tq = vuDouble(VU->VI[REG_Q].UL); - - if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * tq)); else VU_MACx_CLEAR(VU); - if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * tq)); else VU_MACy_CLEAR(VU); - if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * tq)); else VU_MACz_CLEAR(VU); - if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * tq)); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*last update 10/05/03 shadow*/ - -void _vuMADDAx(VURegs * VU) { - if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACx_CLEAR(VU); - if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACy_CLEAR(VU); - if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACz_CLEAR(VU); - if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*last update 11/05/03 shadow*/ - -void _vuMADDAy(VURegs * VU) { - if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACx_CLEAR(VU); - if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACy_CLEAR(VU); - if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACz_CLEAR(VU); - if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*last update 11/05/03 shadow*/ - -void _vuMADDAz(VURegs * VU) { - if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACx_CLEAR(VU); - if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACy_CLEAR(VU); - if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACz_CLEAR(VU); - if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*last update 11/05/03 shadow*/ - -void _vuMADDAw(VURegs * VU) { - if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACx_CLEAR(VU); - if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACy_CLEAR(VU); - if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACz_CLEAR(VU); - if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*last update 11/05/03 shadow*/ - -void _vuMSUB(VURegs * VU) { - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACx_CLEAR(VU); - if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACy_CLEAR(VU); - if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACz_CLEAR(VU); - if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 11/05/03 shadow */ - -void _vuMSUBi(VURegs * VU) { - float ti = vuDouble(VU->VI[REG_I].UL); - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * ti ) ); else VU_MACx_CLEAR(VU); - if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * ti ) ); else VU_MACy_CLEAR(VU); - if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * ti ) ); else VU_MACz_CLEAR(VU); - if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * ti ) ); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 11/05/03 shadow */ - -void _vuMSUBq(VURegs * VU) { - float tq = vuDouble(VU->VI[REG_Q].UL); - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * tq ) ); else VU_MACx_CLEAR(VU); - if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * tq ) ); else VU_MACy_CLEAR(VU); - if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * tq ) ); else VU_MACz_CLEAR(VU); - if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * tq ) ); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 11/05/03 shadow */ - - -void _vuMSUBx(VURegs * VU) { - float ftx; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - ftx=vuDouble(VU->VF[_Ft_].i.x); - if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * ftx ) ); else VU_MACx_CLEAR(VU); - if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * ftx ) ); else VU_MACy_CLEAR(VU); - if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * ftx ) ); else VU_MACz_CLEAR(VU); - if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * ftx ) ); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 11/05/03 shadow */ - - -void _vuMSUBy(VURegs * VU) { - float fty; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - fty=vuDouble(VU->VF[_Ft_].i.y); - if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * fty ) ); else VU_MACx_CLEAR(VU); - if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * fty ) ); else VU_MACy_CLEAR(VU); - if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * fty ) ); else VU_MACz_CLEAR(VU); - if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * fty ) ); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 11/05/03 shadow */ - - -void _vuMSUBz(VURegs * VU) { - float ftz; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - ftz=vuDouble(VU->VF[_Ft_].i.z); - if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * ftz ) ); else VU_MACx_CLEAR(VU); - if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * ftz ) ); else VU_MACy_CLEAR(VU); - if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * ftz ) ); else VU_MACz_CLEAR(VU); - if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * ftz ) ); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 11/05/03 shadow */ - -void _vuMSUBw(VURegs * VU) { - float ftw; - VECTOR * dst; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - ftw=vuDouble(VU->VF[_Ft_].i.w); - if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * ftw ) ); else VU_MACx_CLEAR(VU); - if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * ftw ) ); else VU_MACy_CLEAR(VU); - if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * ftw ) ); else VU_MACz_CLEAR(VU); - if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * ftw ) ); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/* last update 11/05/03 shadow */ - - -void _vuMSUBA(VURegs * VU) { - if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACx_CLEAR(VU); - if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACy_CLEAR(VU); - if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACz_CLEAR(VU); - if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*last updated 11/05/03 shadow*/ - -void _vuMSUBAi(VURegs * VU) { - if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_I].UL))); else VU_MACx_CLEAR(VU); - if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_I].UL))); else VU_MACy_CLEAR(VU); - if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_I].UL))); else VU_MACz_CLEAR(VU); - if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_I].UL))); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*last updated 11/05/03 shadow*/ - -void _vuMSUBAq(VURegs * VU) { - if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACx_CLEAR(VU); - if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACy_CLEAR(VU); - if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACz_CLEAR(VU); - if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*last updated 11/05/03 shadow*/ - -void _vuMSUBAx(VURegs * VU) { - float tx = vuDouble(VU->VF[_Ft_].i.x); - - if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * tx)); else VU_MACx_CLEAR(VU); - if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * tx)); else VU_MACy_CLEAR(VU); - if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * tx)); else VU_MACz_CLEAR(VU); - if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * tx)); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*last updated 11/05/03 shadow*/ - -void _vuMSUBAy(VURegs * VU) { - float ty = vuDouble(VU->VF[_Ft_].i.y); - - if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * ty)); else VU_MACx_CLEAR(VU); - if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * ty)); else VU_MACy_CLEAR(VU); - if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * ty)); else VU_MACz_CLEAR(VU); - if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * ty)); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*last updated 11/05/03 shadow*/ - -void _vuMSUBAz(VURegs * VU) { - float tz = vuDouble(VU->VF[_Ft_].i.z); - - if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * tz)); else VU_MACx_CLEAR(VU); - if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * tz)); else VU_MACy_CLEAR(VU); - if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * tz)); else VU_MACz_CLEAR(VU); - if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * tz)); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*last updated 11/05/03 shadow*/ - -void _vuMSUBAw(VURegs * VU) { - float tw = vuDouble(VU->VF[_Ft_].i.w); - - if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * tw)); else VU_MACx_CLEAR(VU); - if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * tw)); else VU_MACy_CLEAR(VU); - if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * tw)); else VU_MACz_CLEAR(VU); - if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * tw)); else VU_MACw_CLEAR(VU); - VU_STAT_UPDATE(VU); -}/*last updated 11/05/03 shadow*/ - -u32 _MAX(u32 a, u32 b) { - if (a & 0x80000000) { // -a - if (b & 0x80000000) { // -b - return (a & 0x7fffffff) > (b & 0x7fffffff) ? b : a; - } else { // +b - return b; - } - } else { // +a - if (b & 0x80000000) { // -b - return a; - } else { // +b - return (a & 0x7fffffff) > (b & 0x7fffffff) ? a : b; - } - } - - return 0; -} - -void _vuMAX(VURegs * VU) { - if (_Fd_ == 0) return; - - /* ft is bc */ - if (_X) VU->VF[_Fd_].i.x = _MAX(VU->VF[_Fs_].i.x, (s32)VU->VF[_Ft_].i.x); - if (_Y) VU->VF[_Fd_].i.y = _MAX(VU->VF[_Fs_].i.y, (s32)VU->VF[_Ft_].i.y); - if (_Z) VU->VF[_Fd_].i.z = _MAX(VU->VF[_Fs_].i.z, (s32)VU->VF[_Ft_].i.z); - if (_W) VU->VF[_Fd_].i.w = _MAX(VU->VF[_Fs_].i.w, (s32)VU->VF[_Ft_].i.w); -}//checked 13/05/03 shadow - -void _vuMAXi(VURegs * VU) { - if (_Fd_ == 0) return; - - /* ft is bc */ - if (_X) VU->VF[_Fd_].i.x = _MAX(VU->VF[_Fs_].i.x, VU->VI[REG_I].UL); - if (_Y) VU->VF[_Fd_].i.y = _MAX(VU->VF[_Fs_].i.y, VU->VI[REG_I].UL); - if (_Z) VU->VF[_Fd_].i.z = _MAX(VU->VF[_Fs_].i.z, VU->VI[REG_I].UL); - if (_W) VU->VF[_Fd_].i.w = _MAX(VU->VF[_Fs_].i.w, VU->VI[REG_I].UL); -}//checked 13/05/03 shadow - -void _vuMAXx(VURegs * VU) { - s32 ftx; - if (_Fd_ == 0) return; - - ftx=(s32)VU->VF[_Ft_].i.x; - if (_X) VU->VF[_Fd_].i.x = _MAX(VU->VF[_Fs_].i.x, ftx); - if (_Y) VU->VF[_Fd_].i.y = _MAX(VU->VF[_Fs_].i.y, ftx); - if (_Z) VU->VF[_Fd_].i.z = _MAX(VU->VF[_Fs_].i.z, ftx); - if (_W) VU->VF[_Fd_].i.w = _MAX(VU->VF[_Fs_].i.w, ftx); -} -//checked 13/05/03 shadow - -void _vuMAXy(VURegs * VU) { - s32 fty; - if (_Fd_ == 0) return; - - fty=(s32)VU->VF[_Ft_].i.y; - if (_X) VU->VF[_Fd_].i.x = _MAX(VU->VF[_Fs_].i.x, fty); - if (_Y) VU->VF[_Fd_].i.y = _MAX(VU->VF[_Fs_].i.y, fty); - if (_Z) VU->VF[_Fd_].i.z = _MAX(VU->VF[_Fs_].i.z, fty); - if (_W) VU->VF[_Fd_].i.w = _MAX(VU->VF[_Fs_].i.w, fty); -}//checked 13/05/03 shadow - -void _vuMAXz(VURegs * VU) { - s32 ftz; - if (_Fd_ == 0) return; - - ftz=(s32)VU->VF[_Ft_].i.z; - if (_X) VU->VF[_Fd_].i.x = _MAX(VU->VF[_Fs_].i.x, ftz); - if (_Y) VU->VF[_Fd_].i.y = _MAX(VU->VF[_Fs_].i.y, ftz); - if (_Z) VU->VF[_Fd_].i.z = _MAX(VU->VF[_Fs_].i.z, ftz); - if (_W) VU->VF[_Fd_].i.w = _MAX(VU->VF[_Fs_].i.w, ftz); -} - -void _vuMAXw(VURegs * VU) { - s32 ftw; - if (_Fd_ == 0) return; - - ftw=(s32)VU->VF[_Ft_].i.w; - if (_X) VU->VF[_Fd_].i.x = _MAX(VU->VF[_Fs_].i.x, ftw); - if (_Y) VU->VF[_Fd_].i.y = _MAX(VU->VF[_Fs_].i.y, ftw); - if (_Z) VU->VF[_Fd_].i.z = _MAX(VU->VF[_Fs_].i.z, ftw); - if (_W) VU->VF[_Fd_].i.w = _MAX(VU->VF[_Fs_].i.w, ftw); -} - -u32 _MINI(u32 a, u32 b) { - if (a & 0x80000000) { // -a - if (b & 0x80000000) { // -b - return (a & 0x7fffffff) < (b & 0x7fffffff) ? b : a; - } else { // +b - return a; - } - } else { // +a - if (b & 0x80000000) { // -b - return b; - } else { // +b - return (a & 0x7fffffff) < (b & 0x7fffffff) ? a : b; - } - } - - return 0; -} - -void _vuMINI(VURegs * VU) { - if (_Fd_ == 0) return; - - /* ft is bc */ - if (_X) VU->VF[_Fd_].i.x = _MINI(VU->VF[_Fs_].i.x, (s32)VU->VF[_Ft_].i.x); - if (_Y) VU->VF[_Fd_].i.y = _MINI(VU->VF[_Fs_].i.y, (s32)VU->VF[_Ft_].i.y); - if (_Z) VU->VF[_Fd_].i.z = _MINI(VU->VF[_Fs_].i.z, (s32)VU->VF[_Ft_].i.z); - if (_W) VU->VF[_Fd_].i.w = _MINI(VU->VF[_Fs_].i.w, (s32)VU->VF[_Ft_].i.w); -}//checked 13/05/03 shadow - -void _vuMINIi(VURegs * VU) { - if (_Fd_ == 0) return; - - /* ft is bc */ - if (_X) VU->VF[_Fd_].i.x = _MINI(VU->VF[_Fs_].i.x, VU->VI[REG_I].UL); - if (_Y) VU->VF[_Fd_].i.y = _MINI(VU->VF[_Fs_].i.y, VU->VI[REG_I].UL); - if (_Z) VU->VF[_Fd_].i.z = _MINI(VU->VF[_Fs_].i.z, VU->VI[REG_I].UL); - if (_W) VU->VF[_Fd_].i.w = _MINI(VU->VF[_Fs_].i.w, VU->VI[REG_I].UL); -}//checked 13/05/03 shadow - -void _vuMINIx(VURegs * VU) { - s32 ftx; - if (_Fd_ == 0) return; - - ftx=(s32)VU->VF[_Ft_].i.x; - if (_X) VU->VF[_Fd_].i.x = _MINI(VU->VF[_Fs_].i.x, ftx); - if (_Y) VU->VF[_Fd_].i.y = _MINI(VU->VF[_Fs_].i.y, ftx); - if (_Z) VU->VF[_Fd_].i.z = _MINI(VU->VF[_Fs_].i.z, ftx); - if (_W) VU->VF[_Fd_].i.w = _MINI(VU->VF[_Fs_].i.w, ftx); -} -//checked 13/05/03 shadow - -void _vuMINIy(VURegs * VU) { - s32 fty; - if (_Fd_ == 0) return; - - fty=(s32)VU->VF[_Ft_].i.y; - if (_X) VU->VF[_Fd_].i.x = _MINI(VU->VF[_Fs_].i.x, fty); - if (_Y) VU->VF[_Fd_].i.y = _MINI(VU->VF[_Fs_].i.y, fty); - if (_Z) VU->VF[_Fd_].i.z = _MINI(VU->VF[_Fs_].i.z, fty); - if (_W) VU->VF[_Fd_].i.w = _MINI(VU->VF[_Fs_].i.w, fty); -}//checked 13/05/03 shadow - -void _vuMINIz(VURegs * VU) { - s32 ftz; - if (_Fd_ == 0) return; - - ftz=(s32)VU->VF[_Ft_].i.z; - if (_X) VU->VF[_Fd_].i.x = _MINI(VU->VF[_Fs_].i.x, ftz); - if (_Y) VU->VF[_Fd_].i.y = _MINI(VU->VF[_Fs_].i.y, ftz); - if (_Z) VU->VF[_Fd_].i.z = _MINI(VU->VF[_Fs_].i.z, ftz); - if (_W) VU->VF[_Fd_].i.w = _MINI(VU->VF[_Fs_].i.w, ftz); -} - -void _vuMINIw(VURegs * VU) { - s32 ftw; - if (_Fd_ == 0) return; - - ftw=(s32)VU->VF[_Ft_].i.w; - if (_X) VU->VF[_Fd_].i.x = _MINI(VU->VF[_Fs_].i.x, ftw); - if (_Y) VU->VF[_Fd_].i.y = _MINI(VU->VF[_Fs_].i.y, ftw); - if (_Z) VU->VF[_Fd_].i.z = _MINI(VU->VF[_Fs_].i.z, ftw); - if (_W) VU->VF[_Fd_].i.w = _MINI(VU->VF[_Fs_].i.w, ftw); -} - -void _vuOPMULA(VURegs * VU) { - VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.z)); - VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.x)); - VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.y)); - VU_STAT_UPDATE(VU); -}/*last updated 8/05/03 shadow*/ - -void _vuOPMSUB(VURegs * VU) { - VECTOR * dst; - float ftx, fty, ftz; - float fsx, fsy, fsz; - if (_Fd_ == 0) dst = &RDzero; - else dst = &VU->VF[_Fd_]; - - ftx = vuDouble(VU->VF[_Ft_].i.x); fty = vuDouble(VU->VF[_Ft_].i.y); ftz = vuDouble(VU->VF[_Ft_].i.z); - fsx = vuDouble(VU->VF[_Fs_].i.x); fsy = vuDouble(VU->VF[_Fs_].i.y); fsz = vuDouble(VU->VF[_Fs_].i.z); - dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - fsy * ftz); - dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - fsz * ftx); - dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - fsx * fty); - VU_STAT_UPDATE(VU); -}/*last updated 8/05/03 shadow*/ - -void _vuNOP(VURegs * VU) { -} - -void _vuFTOI0(VURegs * VU) { - if (_Ft_ == 0) return; - - if (_X) VU->VF[_Ft_].SL[0] = (s32)vuDouble(VU->VF[_Fs_].i.x); - if (_Y) VU->VF[_Ft_].SL[1] = (s32)vuDouble(VU->VF[_Fs_].i.y); - if (_Z) VU->VF[_Ft_].SL[2] = (s32)vuDouble(VU->VF[_Fs_].i.z); - if (_W) VU->VF[_Ft_].SL[3] = (s32)vuDouble(VU->VF[_Fs_].i.w); -} - -void _vuFTOI4(VURegs * VU) { - if (_Ft_ == 0) return; - - if (_X) VU->VF[_Ft_].SL[0] = float_to_int4(vuDouble(VU->VF[_Fs_].i.x)); - if (_Y) VU->VF[_Ft_].SL[1] = float_to_int4(vuDouble(VU->VF[_Fs_].i.y)); - if (_Z) VU->VF[_Ft_].SL[2] = float_to_int4(vuDouble(VU->VF[_Fs_].i.z)); - if (_W) VU->VF[_Ft_].SL[3] = float_to_int4(vuDouble(VU->VF[_Fs_].i.w)); -} - -void _vuFTOI12(VURegs * VU) { - if (_Ft_ == 0) return; - - if (_X) VU->VF[_Ft_].SL[0] = float_to_int12(vuDouble(VU->VF[_Fs_].i.x)); - if (_Y) VU->VF[_Ft_].SL[1] = float_to_int12(vuDouble(VU->VF[_Fs_].i.y)); - if (_Z) VU->VF[_Ft_].SL[2] = float_to_int12(vuDouble(VU->VF[_Fs_].i.z)); - if (_W) VU->VF[_Ft_].SL[3] = float_to_int12(vuDouble(VU->VF[_Fs_].i.w)); -} - -void _vuFTOI15(VURegs * VU) { - if (_Ft_ == 0) return; - - if (_X) VU->VF[_Ft_].SL[0] = float_to_int15(vuDouble(VU->VF[_Fs_].i.x)); - if (_Y) VU->VF[_Ft_].SL[1] = float_to_int15(vuDouble(VU->VF[_Fs_].i.y)); - if (_Z) VU->VF[_Ft_].SL[2] = float_to_int15(vuDouble(VU->VF[_Fs_].i.z)); - if (_W) VU->VF[_Ft_].SL[3] = float_to_int15(vuDouble(VU->VF[_Fs_].i.w)); -} - -void _vuITOF0(VURegs * VU) { - if (_Ft_ == 0) return; - - if (_X) VU->VF[_Ft_].f.x = (float)VU->VF[_Fs_].SL[0]; - if (_Y) VU->VF[_Ft_].f.y = (float)VU->VF[_Fs_].SL[1]; - if (_Z) VU->VF[_Ft_].f.z = (float)VU->VF[_Fs_].SL[2]; - if (_W) VU->VF[_Ft_].f.w = (float)VU->VF[_Fs_].SL[3]; -} - -void _vuITOF4(VURegs * VU) { - if (_Ft_ == 0) return; - - if (_X) VU->VF[_Ft_].f.x = int4_to_float(VU->VF[_Fs_].SL[0]); - if (_Y) VU->VF[_Ft_].f.y = int4_to_float(VU->VF[_Fs_].SL[1]); - if (_Z) VU->VF[_Ft_].f.z = int4_to_float(VU->VF[_Fs_].SL[2]); - if (_W) VU->VF[_Ft_].f.w = int4_to_float(VU->VF[_Fs_].SL[3]); -} - -void _vuITOF12(VURegs * VU) { - if (_Ft_ == 0) return; - - if (_X) VU->VF[_Ft_].f.x = int12_to_float(VU->VF[_Fs_].SL[0]); - if (_Y) VU->VF[_Ft_].f.y = int12_to_float(VU->VF[_Fs_].SL[1]); - if (_Z) VU->VF[_Ft_].f.z = int12_to_float(VU->VF[_Fs_].SL[2]); - if (_W) VU->VF[_Ft_].f.w = int12_to_float(VU->VF[_Fs_].SL[3]); -} - -void _vuITOF15(VURegs * VU) { - if (_Ft_ == 0) return; - - if (_X) VU->VF[_Ft_].f.x = int15_to_float(VU->VF[_Fs_].SL[0]); - if (_Y) VU->VF[_Ft_].f.y = int15_to_float(VU->VF[_Fs_].SL[1]); - if (_Z) VU->VF[_Ft_].f.z = int15_to_float(VU->VF[_Fs_].SL[2]); - if (_W) VU->VF[_Ft_].f.w = int15_to_float(VU->VF[_Fs_].SL[3]); -} - -/* Different type of clipping by presaving w. asadr */ -void _vuCLIP(VURegs * VU) { - float value = fabs(vuDouble(VU->VF[_Ft_].i.w)); - - VU->clipflag <<= 6; - if ( vuDouble(VU->VF[_Fs_].i.x) > +value ) VU->clipflag|= 0x01; - if ( vuDouble(VU->VF[_Fs_].i.x) < -value ) VU->clipflag|= 0x02; - if ( vuDouble(VU->VF[_Fs_].i.y) > +value ) VU->clipflag|= 0x04; - if ( vuDouble(VU->VF[_Fs_].i.y) < -value ) VU->clipflag|= 0x08; - if ( vuDouble(VU->VF[_Fs_].i.z) > +value ) VU->clipflag|= 0x10; - if ( vuDouble(VU->VF[_Fs_].i.z) < -value ) VU->clipflag|= 0x20; - VU->clipflag = VU->clipflag & 0xFFFFFF; - VU->VI[REG_CLIP_FLAG].UL = VU->clipflag; - - -}/*last update 16/07/05 refraction - Needs checking */ - - -/******************************/ -/* VU Lower instructions */ -/******************************/ - -void _vuDIV(VURegs * VU) { - float ft = vuDouble(VU->VF[_Ft_].UL[_Ftf_]); - float fs = vuDouble(VU->VF[_Fs_].UL[_Fsf_]); - -// _vuFMACTestStall(VU, _Fs_); _vuFMACTestStall(VU, _Ft_); - VU->statusflag = (VU->statusflag&0xfcf)|((VU->statusflag&0x30)<<6); - - if (ft == 0.0) { - if (fs == 0.0) { - VU->statusflag |= 0x10; - } else { - VU->statusflag |= 0x20; - } - if ((VU->VF[_Ft_].UL[_Ftf_] & 0x80000000) ^ - (VU->VF[_Fs_].UL[_Fsf_] & 0x80000000)) { - VU->q.UL = 0xFF7FFFFF; - } else { - VU->q.UL = 0x7F7FFFFF; - } - } else { - VU->q.F = fs / ft; - VU->q.F = vuDouble(VU->q.UL); - } -} //last update 15/01/06 zerofrog - -void _vuSQRT(VURegs * VU) { - float ft = vuDouble(VU->VF[_Ft_].UL[_Ftf_]); - -// _vuFMACTestStall(VU, _Ft_); - VU->statusflag = (VU->statusflag&0xfcf)|((VU->statusflag&0x30)<<6); - - if (ft < 0.0 ) - VU->statusflag |= 0x10; - VU->q.F = sqrt(fabs(ft)); - VU->q.F = vuDouble(VU->q.UL); -} //last update 15/01/06 zerofrog - - -/* Eminent Bug - Dvisior == 0 Check Missing ( D Flag Not Set ) */ -/* REFIXED....ASADR; rerefixed....zerofrog */ -void _vuRSQRT(VURegs * VU) { - float ft = vuDouble(VU->VF[_Ft_].UL[_Ftf_]); - float fs = vuDouble(VU->VF[_Fs_].UL[_Fsf_]); - float temp; - -// _vuFMACTestStall(VU, _Fs_); _vuFMACTestStall(VU, _Ft_); - VU->statusflag = (VU->statusflag&0xfcf)|((VU->statusflag&0x30)<<6); - - if ( ft == 0.0 ) { - VU->statusflag |= 0x20; - - if( fs != 0 ) { - if ((VU->VF[_Ft_].UL[_Ftf_] & 0x80000000) ^ - (VU->VF[_Fs_].UL[_Fsf_] & 0x80000000)) { - VU->q.UL = 0xFF7FFFFF; - } else { - VU->q.UL = 0x7F7FFFFF; - } - } - else { - if ((VU->VF[_Ft_].UL[_Ftf_] & 0x80000000) ^ - (VU->VF[_Fs_].UL[_Fsf_] & 0x80000000)) { - VU->q.UL = 0x80000000; - } else { - VU->q.UL = 0; - } - - VU->statusflag |= 0x10; - } - - } else { - if (ft < 0.0) { - VU->statusflag |= 0x10; - } - - temp = sqrt(fabs(ft)); - VU->q.F = fs / temp; - VU->q.F = vuDouble(VU->q.UL); - } -} //last update 15/01/06 zerofrog - - -void _vuIADDI(VURegs * VU) { - s16 imm = ((VU->code >> 6) & 0x1f); - imm = ((imm & 0x10 ? 0xfff0 : 0) | (imm & 0xf)); - if(_Ft_ == 0) return; - VU->VI[_Ft_].SS[0] = VU->VI[_Fs_].SS[0] + imm; -}//last checked 17/05/03 shadow NOTE: not quite sure about that - -void _vuIADDIU(VURegs * VU) { - if(_Ft_ == 0) return; - VU->VI[_Ft_].SS[0] = VU->VI[_Fs_].SS[0] + (((VU->code >> 10) & 0x7800) | (VU->code & 0x7ff)); -}//last checked 17/05/03 shadow - -void _vuIADD(VURegs * VU) { - if(_Fd_ == 0) return; - VU->VI[_Fd_].SS[0] = VU->VI[_Fs_].SS[0] + VU->VI[_Ft_].SS[0]; -}//last checked 17/05/03 shadow - -void _vuIAND(VURegs * VU) { - if(_Fd_ == 0) return; - VU->VI[_Fd_].US[0] = VU->VI[_Fs_].US[0] & VU->VI[_Ft_].US[0]; -}//last checked 17/05/03 shadow - -void _vuIOR(VURegs * VU) { - if(_Fd_ == 0) return; - VU->VI[_Fd_].US[0] = VU->VI[_Fs_].US[0] | VU->VI[_Ft_].US[0]; -} - -void _vuISUB(VURegs * VU) { - if(_Fd_ == 0) return; - VU->VI[_Fd_].SS[0] = VU->VI[_Fs_].SS[0] - VU->VI[_Ft_].SS[0]; -} - -void _vuISUBIU(VURegs * VU) { - if(_Ft_ == 0) return; - VU->VI[_Ft_].SS[0] = VU->VI[_Fs_].SS[0] - (((VU->code >> 10) & 0x7800) | (VU->code & 0x7ff)); -} - -void _vuMOVE(VURegs * VU) { - if(_Ft_ == 0) return; - - if (_X) VU->VF[_Ft_].UL[0] = VU->VF[_Fs_].UL[0]; - if (_Y) VU->VF[_Ft_].UL[1] = VU->VF[_Fs_].UL[1]; - if (_Z) VU->VF[_Ft_].UL[2] = VU->VF[_Fs_].UL[2]; - if (_W) VU->VF[_Ft_].UL[3] = VU->VF[_Fs_].UL[3]; -}//last checked 17/05/03 shadow - -void _vuMFIR(VURegs * VU) { - if (_Ft_ == 0) return; - - if (_X) VU->VF[_Ft_].SL[0] = (s32)VU->VI[_Fs_].SS[0]; - if (_Y) VU->VF[_Ft_].SL[1] = (s32)VU->VI[_Fs_].SS[0]; - if (_Z) VU->VF[_Ft_].SL[2] = (s32)VU->VI[_Fs_].SS[0]; - if (_W) VU->VF[_Ft_].SL[3] = (s32)VU->VI[_Fs_].SS[0]; -} - -// Big bug!!! mov from fs to ft not ft to fs. asadr -void _vuMTIR(VURegs * VU) { - if(_Ft_ == 0) return; - VU->VI[_Ft_].US[0] = *(u16*)&VU->VF[_Fs_].F[_Fsf_]; -} - -void _vuMR32(VURegs * VU) { - u32 tx; - if (_Ft_ == 0) return; - - tx = VU->VF[_Fs_].i.x; - if (_X) VU->VF[_Ft_].i.x = VU->VF[_Fs_].i.y; - if (_Y) VU->VF[_Ft_].i.y = VU->VF[_Fs_].i.z; - if (_Z) VU->VF[_Ft_].i.z = VU->VF[_Fs_].i.w; - if (_W) VU->VF[_Ft_].i.w = tx; -}//last updated 23/10/03 linuzappz - -void _vuLQ(VURegs * VU) { - s16 imm; - u16 addr; - u32 *ptr; - - if (_Ft_ == 0) return; - - imm = (VU->code & 0x400) ? (VU->code & 0x3ff) | 0xfc00 : (VU->code & 0x3ff); - addr = (imm + VU->VI[_Fs_].SS[0]) * 16; - - ptr = (u32*)GET_VU_MEM(VU, addr); - if (_X) VU->VF[_Ft_].UL[0] = ptr[0]; - if (_Y) VU->VF[_Ft_].UL[1] = ptr[1]; - if (_Z) VU->VF[_Ft_].UL[2] = ptr[2]; - if (_W) VU->VF[_Ft_].UL[3] = ptr[3]; -} - -void _vuLQD( VURegs * VU ) { - u32 addr; - u32 *ptr; - - if (_Fs_ != 0) VU->VI[_Fs_].US[0]--; - if (_Ft_ == 0) return; - - addr = VU->VI[_Fs_].US[0] * 16; - ptr = (u32*)GET_VU_MEM(VU, addr); - if (_X) VU->VF[_Ft_].UL[0] = ptr[0]; - if (_Y) VU->VF[_Ft_].UL[1] = ptr[1]; - if (_Z) VU->VF[_Ft_].UL[2] = ptr[2]; - if (_W) VU->VF[_Ft_].UL[3] = ptr[3]; -} - -void _vuLQI(VURegs * VU) { - if (_Ft_) { - u32 addr; - u32 *ptr; - - addr = VU->VI[_Fs_].US[0] * 16; - ptr = (u32*)GET_VU_MEM(VU, addr); - if (_X) VU->VF[_Ft_].UL[0] = ptr[0]; - if (_Y) VU->VF[_Ft_].UL[1] = ptr[1]; - if (_Z) VU->VF[_Ft_].UL[2] = ptr[2]; - if (_W) VU->VF[_Ft_].UL[3] = ptr[3]; - } - if (_Fs_ != 0) VU->VI[_Fs_].US[0]++; -} - -/* addr is now signed. Asadr */ -void _vuSQ(VURegs * VU) { - s16 imm; - u16 addr; - u32 *ptr; - - imm = (VU->code & 0x400) ? (VU->code & 0x3ff) | 0xfc00 : (VU->code & 0x3ff); - addr = (imm + VU->VI[_Ft_].SS[0]) * 16; - ptr = (u32*)GET_VU_MEM(VU, addr); - if (_X) ptr[0] = VU->VF[_Fs_].UL[0]; - if (_Y) ptr[1] = VU->VF[_Fs_].UL[1]; - if (_Z) ptr[2] = VU->VF[_Fs_].UL[2]; - if (_W) ptr[3] = VU->VF[_Fs_].UL[3]; -} - -void _vuSQD(VURegs * VU) { - u32 addr; - u32 *ptr; - - if(_Ft_ != 0) VU->VI[_Ft_].US[0]--; - addr = VU->VI[_Ft_].US[0] * 16; - ptr = (u32*)GET_VU_MEM(VU, addr); - if (_X) ptr[0] = VU->VF[_Fs_].UL[0]; - if (_Y) ptr[1] = VU->VF[_Fs_].UL[1]; - if (_Z) ptr[2] = VU->VF[_Fs_].UL[2]; - if (_W) ptr[3] = VU->VF[_Fs_].UL[3]; -} - -void _vuSQI(VURegs * VU) { - u32 addr; - u32 *ptr; - - addr = VU->VI[_Ft_].US[0] * 16; - ptr = (u32*)GET_VU_MEM(VU, addr); - if (_X) ptr[0] = VU->VF[_Fs_].UL[0]; - if (_Y) ptr[1] = VU->VF[_Fs_].UL[1]; - if (_Z) ptr[2] = VU->VF[_Fs_].UL[2]; - if (_W) ptr[3] = VU->VF[_Fs_].UL[3]; - if(_Ft_ != 0) VU->VI[_Ft_].US[0]++; -} - -/* addr now signed. asadr */ -void _vuILW(VURegs * VU) { - s16 imm; - u16 addr; - u16 *ptr; - if (_Ft_ == 0) return; - - imm = (VU->code & 0x400) ? (VU->code & 0x3ff) | 0xfc00 : (VU->code & 0x3ff); - addr = (imm + VU->VI[_Fs_].SS[0]) * 16; - ptr = (u16*)GET_VU_MEM(VU, addr); - if (_X) VU->VI[_Ft_].US[0] = ptr[0]; - if (_Y) VU->VI[_Ft_].US[0] = ptr[2]; - if (_Z) VU->VI[_Ft_].US[0] = ptr[4]; - if (_W) VU->VI[_Ft_].US[0] = ptr[6]; -} - -void _vuISW(VURegs * VU) { - s16 imm; - u16 addr; - u16 *ptr; - - imm = (VU->code & 0x400) ? (VU->code & 0x3ff) | 0xfc00 : (VU->code & 0x3ff); - addr = (imm + VU->VI[_Fs_].SS[0]) * 16; - ptr = (u16*)GET_VU_MEM(VU, addr); - if (_X) { ptr[0] = VU->VI[_Ft_].US[0]; ptr[1] = 0; } - if (_Y) { ptr[2] = VU->VI[_Ft_].US[0]; ptr[3] = 0; } - if (_Z) { ptr[4] = VU->VI[_Ft_].US[0]; ptr[5] = 0; } - if (_W) { ptr[6] = VU->VI[_Ft_].US[0]; ptr[7] = 0; } -} - -void _vuILWR(VURegs * VU) { - u32 addr; - u16 *ptr; - if (_Ft_ == 0) return; - - addr = VU->VI[_Fs_].US[0] * 16; - ptr = (u16*)GET_VU_MEM(VU, addr); - if (_X) VU->VI[_Ft_].US[0] = ptr[0]; - if (_Y) VU->VI[_Ft_].US[0] = ptr[2]; - if (_Z) VU->VI[_Ft_].US[0] = ptr[4]; - if (_W) VU->VI[_Ft_].US[0] = ptr[6]; -} - -void _vuISWR(VURegs * VU) { - u32 addr; - u16 *ptr; - - addr = VU->VI[_Fs_].US[0] * 16; - ptr = (u16*)GET_VU_MEM(VU, addr); - if (_X) { ptr[0] = VU->VI[_Ft_].US[0]; ptr[1] = 0; } - if (_Y) { ptr[2] = VU->VI[_Ft_].US[0]; ptr[3] = 0; } - if (_Z) { ptr[4] = VU->VI[_Ft_].US[0]; ptr[5] = 0; } - if (_W) { ptr[6] = VU->VI[_Ft_].US[0]; ptr[7] = 0; } -} - -/* code contributed by _Riff_ - -The following code implements a Galois form M-series LFSR that can be configured to have a width from 0 to 32. -A Galois field can be represented as G(X) = g_m * X^m + g_(m-1) * X^(m-1) + ... + g_1 * X^1 + g0. -A Galois form M-Series LFSR represents a Galois field where g0 = g_m = 1 and the generated set contains 2^M - 1 values. -In modulo-2 arithmetic, addition is replaced by XOR and multiplication is replaced by AND. -The code is written in such a way that the polynomial lsb (g0) should be set to 0 and g_m is not represented. -As an example for setting the polynomial variable correctly, the 23-bit M-series generating polynomial X^23+X^14 - would be specified as (1 << 14). -*/ - - -//The two-tap 23 stage M-series polynomials are x23+x18 and x23+x14 ((1 << 18) and (1 << 14), respectively). -//The reverse sequences can be generated by x23+x(23-18) and x23+x(23-14) ((1 << 9) and (1 << 5), respectively) -u32 poly = 1 << 5; - -void SetPoly(u32 newPoly) { - poly = poly & ~1; -} - -void AdvanceLFSR(VURegs * VU) { - // code from www.project-fao.org - int x = (VU->VI[REG_R].UL >> 4) & 1; - int y = (VU->VI[REG_R].UL >> 22) & 1; - VU->VI[REG_R].UL <<= 1; - VU->VI[REG_R].UL ^= x ^ y; - VU->VI[REG_R].UL = (VU->VI[REG_R].UL&0x7fffff)|0x3f800000; -} -// old -// u32 lfsr = VU->VI[REG_R].UL & 0x007FFFFF; -// u32 oldlfsr = lfsr; -// lfsr <<= 1; -// if (oldlfsr & 0x00400000) { -// lfsr ^= poly; -// lfsr |= 1; -// } -// -// VU->VI[REG_R].UL = 0x3F800000 | (lfsr & 0x007FFFFF); - -void _vuRINIT(VURegs * VU) { - VU->VI[REG_R].UL = 0x3F800000 | (VU->VF[_Fs_].UL[_Fsf_] & 0x007FFFFF); -} - -void _vuRGET(VURegs * VU) { - if (_Ft_ == 0) return; - - if (_X) VU->VF[_Ft_].UL[0] = VU->VI[REG_R].UL; - if (_Y) VU->VF[_Ft_].UL[1] = VU->VI[REG_R].UL; - if (_Z) VU->VF[_Ft_].UL[2] = VU->VI[REG_R].UL; - if (_W) VU->VF[_Ft_].UL[3] = VU->VI[REG_R].UL; -} - -void _vuRNEXT(VURegs * VU) { - if (_Ft_ == 0) return; - AdvanceLFSR(VU); - if (_X) VU->VF[_Ft_].UL[0] = VU->VI[REG_R].UL; - if (_Y) VU->VF[_Ft_].UL[1] = VU->VI[REG_R].UL; - if (_Z) VU->VF[_Ft_].UL[2] = VU->VI[REG_R].UL; - if (_W) VU->VF[_Ft_].UL[3] = VU->VI[REG_R].UL; -} - -void _vuRXOR(VURegs * VU) { - VU->VI[REG_R].UL = 0x3F800000 | ((VU->VI[REG_R].UL ^ VU->VF[_Fs_].UL[_Fsf_]) & 0x007FFFFF); -} - -void _vuWAITQ(VURegs * VU) { -} - -void _vuFSAND(VURegs * VU) { - u16 imm; - imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7ff); - if(_Ft_ == 0) return; - VU->VI[_Ft_].US[0] = (VU->VI[REG_STATUS_FLAG].US[0] & 0xFFF) & imm; -} - -void _vuFSEQ(VURegs * VU) { - u16 imm; - imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7ff); - if(_Ft_ == 0) return; - if((VU->VI[REG_STATUS_FLAG].US[0] & 0xFFF) == imm) VU->VI[_Ft_].US[0] = 1; - else VU->VI[_Ft_].US[0] = 0; -} - -void _vuFSOR(VURegs * VU) { - u16 imm; - imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7ff); - if(_Ft_ == 0) return; - VU->VI[_Ft_].US[0] = (VU->VI[REG_STATUS_FLAG].US[0] & 0xFFF) | imm; -} - -void _vuFSSET(VURegs * VU) { - u16 imm = 0; - imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7FF); - VU->statusflag = (imm & 0xFC0) | (VU->VI[REG_STATUS_FLAG].US[0] & 0x3F); -} - -void _vuFMAND(VURegs * VU) { - if(_Ft_ == 0) return; - VU->VI[_Ft_].US[0] = VU->VI[_Fs_].US[0] & (VU->VI[REG_MAC_FLAG].UL & 0xFFFF); -} - -void _vuFMEQ(VURegs * VU) { - if(_Ft_ == 0) return; - if((VU->VI[REG_MAC_FLAG].UL & 0xFFFF) == VU->VI[_Fs_].US[0]){ - VU->VI[_Ft_].US[0] =1;} else { VU->VI[_Ft_].US[0] =0; } -} - -void _vuFMOR(VURegs * VU) { - if(_Ft_ == 0) return; - VU->VI[_Ft_].US[0] = (VU->VI[REG_MAC_FLAG].UL & 0xFFFF) | VU->VI[_Fs_].US[0]; -} - -void _vuFCAND(VURegs * VU) { - if((VU->VI[REG_CLIP_FLAG].UL & 0xFFFFFF) & (VU->code & 0xFFFFFF)) VU->VI[1].US[0] = 1; - else VU->VI[1].US[0] = 0; -} - -void _vuFCEQ(VURegs * VU) { - if((VU->VI[REG_CLIP_FLAG].UL & 0xFFFFFF) == (VU->code & 0xFFFFFF)) VU->VI[1].US[0] = 1; - else VU->VI[1].US[0] = 0; -} - -void _vuFCOR(VURegs * VU) { - u32 hold = (VU->VI[REG_CLIP_FLAG].UL & 0xFFFFFF) | ( VU->code & 0xFFFFFF); - if(hold == 0xFFFFFF) VU->VI[1].US[0] = 1; - else VU->VI[1].US[0] = 0; -} - -void _vuFCSET(VURegs * VU) { - VU->clipflag = (u32) (VU->code & 0xFFFFFF); - VU->VI[REG_CLIP_FLAG].UL = (u32) (VU->code & 0xFFFFFF); -} - -void _vuFCGET(VURegs * VU) { - if(_Ft_ == 0) return; - VU->VI[_Ft_].US[0] = VU->VI[REG_CLIP_FLAG].UL & 0x0FFF; -} - -s32 _branchAddr(VURegs * VU) { - s32 bpc = VU->VI[REG_TPC].SL + ( _Imm11_ * 8 ); - //if (bpc < 0) bpc = VU->VI[REG_TPC].SL + _UImm11_ * 8; - bpc&= (VU == &VU1) ? 0x3fff : 0x0fff; - return bpc; -} - -void _setBranch(VURegs * VU, u32 bpc) { - VU->branch = 2; - VU->branchpc = bpc; -// VU->vuExec(VU); -// VU->VI[REG_TPC].UL = bpc; -} - -void _vuIBEQ(VURegs * VU) { - if (VU->VI[_Ft_].US[0] == VU->VI[_Fs_].US[0]) { - s32 bpc = _branchAddr(VU); - _setBranch(VU, bpc); - } -} - -void _vuIBGEZ(VURegs * VU) { - if (VU->VI[_Fs_].SS[0] >= 0) { - s32 bpc = _branchAddr(VU); - _setBranch(VU, bpc); - } -} - -void _vuIBGTZ(VURegs * VU) { - if (VU->VI[_Fs_].SS[0] > 0) { - s32 bpc = _branchAddr(VU); - _setBranch(VU, bpc); - } -} - -void _vuIBLEZ(VURegs * VU) { - if (VU->VI[_Fs_].SS[0] <= 0) { - s32 bpc = _branchAddr(VU); - _setBranch(VU, bpc); - } -} - -void _vuIBLTZ(VURegs * VU) { - if (VU->VI[_Fs_].SS[0] < 0) { - s32 bpc = _branchAddr(VU); - _setBranch(VU, bpc); - } -} - -void _vuIBNE(VURegs * VU) { - if (VU->VI[_Ft_].US[0] != VU->VI[_Fs_].US[0]) { - s32 bpc = _branchAddr(VU); - _setBranch(VU, bpc); - } -} - -void _vuB(VURegs * VU) { - s32 bpc = _branchAddr(VU); - _setBranch(VU, bpc); -} - -void _vuBAL(VURegs * VU) { - s32 bpc = _branchAddr(VU); - - if (_Ft_) { - VU->VI[_Ft_].US[0] = (VU->VI[REG_TPC].UL + 8)/8; - } - - _setBranch(VU, bpc); -} - -void _vuJR(VURegs * VU) { - u32 bpc = VU->VI[_Fs_].US[0] * 8; - _setBranch(VU, bpc); -} - -void _vuJALR(VURegs * VU) { - u32 bpc = VU->VI[_Fs_].US[0] * 8; - if (_Ft_) { - VU->VI[_Ft_].US[0] = (VU->VI[REG_TPC].UL + 8)/8; - } - - _setBranch(VU, bpc); -} - -void _vuMFP(VURegs * VU) { - if (_Ft_ == 0) return; - - if (_X) VU->VF[_Ft_].i.x = VU->VI[REG_P].UL; - if (_Y) VU->VF[_Ft_].i.y = VU->VI[REG_P].UL; - if (_Z) VU->VF[_Ft_].i.z = VU->VI[REG_P].UL; - if (_W) VU->VF[_Ft_].i.w = VU->VI[REG_P].UL; -} - -void _vuWAITP(VURegs * VU) { -} - -void _vuESADD(VURegs * VU) { - float p = vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Fs_].i.z); - VU->p.F = p; -} - -void _vuERSADD(VURegs * VU) { - float p = (vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Fs_].i.x)) + (vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Fs_].i.y)) + (vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Fs_].i.z)); - if (p != 0.0) - p = 1.0f / p; - VU->p.F = p; -} - -/* Fixed. Could have caused crash due to value being -ve for sqrt *asadr */ -void _vuELENG(VURegs * VU) { - float p = vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Fs_].i.z); - if(p >= 0){ - p = sqrt(p); - } - VU->p.F = p; -} - -/* Fixed. Could have caused crash due to divisor being = 0 *asadr */ -void _vuERLENG(VURegs * VU) { - float p = vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Fs_].i.z); - if (p >= 0) { - p = sqrt(p); - if (p != 0) { - p = 1.0f / p; - } - } - VU->p.F = p; -} - -/* Fixed. Could have caused crash due to divisor being = 0 *asadr */ -void _vuEATANxy(VURegs * VU) { - float p = 0; - if(vuDouble(VU->VF[_Fs_].i.x) != 0) { - p = atan2(vuDouble(VU->VF[_Fs_].i.y), vuDouble(VU->VF[_Fs_].i.x)); - } - VU->p.F = p; -} - -/* Fixed. Could have caused crash due to divisor being = 0 *asadr */ -void _vuEATANxz(VURegs * VU) { - float p = 0; - if(vuDouble(VU->VF[_Fs_].i.x) != 0) { - p = atan2(vuDouble(VU->VF[_Fs_].i.z), vuDouble(VU->VF[_Fs_].i.x)); - } - VU->p.F = p; -} - -void _vuESUM(VURegs * VU) { - float p = vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VF[_Fs_].i.z) + vuDouble(VU->VF[_Fs_].i.w); - VU->p.F = p; -} - -/* Fixed. Could have caused crash due to divisor being = 0 *asadr */ -void _vuERCPR(VURegs * VU) { - float p = vuDouble(VU->VF[_Fs_].UL[_Fsf_]); - if (p != 0){ - p = 1.0 / p; - } - VU->p.F = p; -} - -/* Fixed. Could have caused crash due to Value being -ve for sqrt *asadr */ -void _vuESQRT(VURegs * VU) { - float p = vuDouble(VU->VF[_Fs_].UL[_Fsf_]); - if (p >= 0){ - p = sqrt(p); - } - VU->p.F = p; -} - -/* Fixed. Could have caused crash due to divisor being = 0 *asadr */ -void _vuERSQRT(VURegs * VU) { - float p = vuDouble(VU->VF[_Fs_].UL[_Fsf_]); - if (p >= 0) { - p = sqrt(p); - if (p) { - p = 1.0f / p; - } - } - VU->p.F = p; -} - -void _vuESIN(VURegs * VU) { - float p = sin(vuDouble(VU->VF[_Fs_].UL[_Fsf_])); - VU->p.F = p; -} - -void _vuEATAN(VURegs * VU) { - float p = atan(vuDouble(VU->VF[_Fs_].UL[_Fsf_])); - VU->p.F = p; -} - -void _vuEEXP(VURegs * VU) { - float p = exp(-(vuDouble(VU->VF[_Fs_].UL[_Fsf_]))); - VU->p.F = p; -} - -void _vuXITOP(VURegs * VU) { - if (_Ft_ == 0) return; - VU->VI[_Ft_].US[0] = VU->vifRegs->itop; -} - -void _vuXGKICK(VURegs * VU) -{ - // flush all pipelines first (in the right order) - _vuFlushAll(VU); - GSGIFTRANSFER1((u32*)VU->Mem, (VU->VI[_Fs_].US[0]*16) & 0x3fff); -} - -void _vuXTOP(VURegs * VU) { - if(_Ft_ == 0) return; - VU->VI[_Ft_].US[0] = (u16)VU->vifRegs->top; -} - -#define GET_VF0_FLAG(reg) (((reg)==0)?(1<pipe = VUPIPE_FMAC; \ - VUregsn->VFwrite = _Fd_; \ - VUregsn->VFwxyzw = _XYZW; \ - VUregsn->VFread0 = _Fs_; \ - VUregsn->VFr0xyzw= _XYZW; \ - VUregsn->VFread1 = 0; \ - VUregsn->VIwrite = 0; \ - VUregsn->VIread = (1 << REG_I)|(ACC?(1<pipe = VUPIPE_FMAC; \ - VUregsn->VFwrite = _Fd_; \ - VUregsn->VFwxyzw = _XYZW; \ - VUregsn->VFread0 = _Fs_; \ - VUregsn->VFr0xyzw= _XYZW; \ - VUregsn->VFread1 = 0; \ - VUregsn->VIwrite = 0; \ - VUregsn->VIread = (1 << REG_Q)|(ACC?(1<pipe = VUPIPE_FMAC; \ - VUregsn->VFwrite = _Fd_; \ - VUregsn->VFwxyzw = _XYZW; \ - VUregsn->VFread0 = _Fs_; \ - VUregsn->VFr0xyzw= _XYZW; \ - VUregsn->VFread1 = _Ft_; \ - VUregsn->VFr1xyzw= _XYZW; \ - VUregsn->VIwrite = 0; \ - VUregsn->VIread = (ACC?(1<pipe = VUPIPE_FMAC; \ - VUregsn->VFwrite = _Fd_; \ - VUregsn->VFwxyzw = _XYZW; \ - VUregsn->VFread0 = _Fs_; \ - VUregsn->VFr0xyzw= _XYZW; \ - VUregsn->VFread1 = _Ft_; \ - VUregsn->VFr1xyzw= xyzw; \ - VUregsn->VIwrite = 0; \ - VUregsn->VIread = (ACC?(1<pipe = VUPIPE_FMAC; \ - VUregsn->VFwrite = 0; \ - VUregsn->VFwxyzw= _XYZW; \ - VUregsn->VFread0 = _Fs_; \ - VUregsn->VFr0xyzw= _XYZW; \ - VUregsn->VFread1 = 0; \ - VUregsn->VIwrite = (1<VIread = (1 << REG_I)|GET_VF0_FLAG(_Fs_)|((readacc||_XYZW!=15)?(1<pipe = VUPIPE_FMAC; \ - VUregsn->VFwrite = 0; \ - VUregsn->VFwxyzw= _XYZW; \ - VUregsn->VFread0 = _Fs_; \ - VUregsn->VFr0xyzw= _XYZW; \ - VUregsn->VFread1 = 0; \ - VUregsn->VIwrite = (1<VIread = (1 << REG_Q)|GET_VF0_FLAG(_Fs_)|((readacc||_XYZW!=15)?(1<pipe = VUPIPE_FMAC; \ - VUregsn->VFwrite = 0; \ - VUregsn->VFwxyzw= _XYZW; \ - VUregsn->VFread0 = _Fs_; \ - VUregsn->VFr0xyzw= _XYZW; \ - VUregsn->VFread1 = _Ft_; \ - VUregsn->VFr1xyzw= _XYZW; \ - VUregsn->VIwrite = (1<VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_)|((readacc||_XYZW!=15)?(1<pipe = VUPIPE_FMAC; \ - VUregsn->VFwrite = 0; \ - VUregsn->VFwxyzw= _XYZW; \ - VUregsn->VFread0 = _Fs_; \ - VUregsn->VFr0xyzw= _XYZW; \ - VUregsn->VFread1 = _Ft_; \ - VUregsn->VFr1xyzw= xyzw; \ - VUregsn->VIwrite = (1<VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_)|((readacc||_XYZW!=15)?(1<pipe = VUPIPE_FMAC; \ - VUregsn->VFwrite = _Ft_; \ - VUregsn->VFwxyzw = _XYZW; \ - VUregsn->VFread0 = _Fs_; \ - VUregsn->VFr0xyzw= _XYZW; \ - VUregsn->VFread1 = 0; \ - VUregsn->VFr1xyzw = 0xff; \ - VUregsn->VIwrite = 0; \ - VUregsn->VIread = (_Ft_ ? GET_VF0_FLAG(_Fs_) : 0); \ -} - -#define VUREGS_IDISIT(OP) \ -void _vuRegs##OP(VURegs * VU, _VURegsNum *VUregsn) { \ - VUregsn->pipe = VUPIPE_IALU; \ - VUregsn->VFwrite = 0; \ - VUregsn->VFread0 = 0; \ - VUregsn->VFread1 = 0; \ - VUregsn->VIwrite = 1 << _Fd_; \ - VUregsn->VIread = (1 << _Fs_) | (1 << _Ft_); \ -} - -#define VUREGS_ITIS(OP) \ -void _vuRegs##OP(VURegs * VU, _VURegsNum *VUregsn) { \ - VUregsn->pipe = VUPIPE_IALU; \ - VUregsn->VFwrite = 0; \ - VUregsn->VFread0 = 0; \ - VUregsn->VFread1 = 0; \ - VUregsn->VIwrite = 1 << _Ft_; \ - VUregsn->VIread = 1 << _Fs_; \ -} - -#define VUREGS_PFS(OP, _cycles) \ -void _vuRegs##OP(VURegs * VU, _VURegsNum *VUregsn) { \ - VUregsn->pipe = VUPIPE_EFU; \ - VUregsn->VFwrite = 0; \ - VUregsn->VFread0 = _Fs_; \ - VUregsn->VFr0xyzw= _XYZW; \ - VUregsn->VFread1 = 0; \ - VUregsn->VIwrite = 1 << REG_P; \ - VUregsn->VIread = GET_VF0_FLAG(_Fs_); \ - VUregsn->cycles = _cycles; \ -} - - - -VUREGS_FTFS(ABS); - -VUREGS_FDFSFT(ADD, 0); -VUREGS_FDFSI(ADDi, 0); -VUREGS_FDFSQ(ADDq, 0); -VUREGS_FDFSFTx(ADDx, 0); -VUREGS_FDFSFTy(ADDy, 0); -VUREGS_FDFSFTz(ADDz, 0); -VUREGS_FDFSFTw(ADDw, 0); - -VUREGS_ACCFSFT(ADDA, 0); -VUREGS_ACCFSI(ADDAi, 0); -VUREGS_ACCFSQ(ADDAq, 0); -VUREGS_ACCFSFTx(ADDAx, 0); -VUREGS_ACCFSFTy(ADDAy, 0); -VUREGS_ACCFSFTz(ADDAz, 0); -VUREGS_ACCFSFTw(ADDAw, 0); - -VUREGS_FDFSFT(SUB, 0); -VUREGS_FDFSI(SUBi, 0); -VUREGS_FDFSQ(SUBq, 0); -VUREGS_FDFSFTx(SUBx, 0); -VUREGS_FDFSFTy(SUBy, 0); -VUREGS_FDFSFTz(SUBz, 0); -VUREGS_FDFSFTw(SUBw, 0); - -VUREGS_ACCFSFT(SUBA, 0); -VUREGS_ACCFSI(SUBAi, 0); -VUREGS_ACCFSQ(SUBAq, 0); -VUREGS_ACCFSFTx(SUBAx, 0); -VUREGS_ACCFSFTy(SUBAy, 0); -VUREGS_ACCFSFTz(SUBAz, 0); -VUREGS_ACCFSFTw(SUBAw, 0); - -#define VUREGS_FDFSFTxyzw_MUL(OP, ACC, xyzw) \ -void _vuRegs##OP(VURegs * VU, _VURegsNum *VUregsn) { \ - if( _Ft_ == 0 && xyzw > 1 && _XYZW == 0xf ) { /* resetting to 0 */ \ - VUregsn->pipe = VUPIPE_FMAC; \ - VUregsn->VFwrite = ACC?0:_Fd_; \ - VUregsn->VFwxyzw = _XYZW; \ - VUregsn->VFread0 = 0; \ - VUregsn->VFr0xyzw= _XYZW; \ - VUregsn->VFread1 = 0; \ - VUregsn->VFr1xyzw= xyzw; \ - VUregsn->VIwrite = (ACC?(1<VIread = (ACC&&(_XYZW!=15))?(1<pipe = VUPIPE_FMAC; \ - VUregsn->VFwrite = ACC?0:_Fd_; \ - VUregsn->VFwxyzw = _XYZW; \ - VUregsn->VFread0 = _Fs_; \ - VUregsn->VFr0xyzw= _XYZW; \ - VUregsn->VFread1 = _Ft_; \ - VUregsn->VFr1xyzw= xyzw; \ - VUregsn->VIwrite = (ACC?(1<VIread = GET_VF0_FLAG(_Fs_)|((ACC&&(_XYZW!=15))?(1<pipe = VUPIPE_FMAC; \ - VUregsn->VFwrite = _Fd_; \ - VUregsn->VFwxyzw = _XYZW; \ - VUregsn->VFread0 = _Fs_; \ - VUregsn->VFr0xyzw= _XYZW; \ - VUregsn->VFread1 = _Ft_; \ - VUregsn->VFr1xyzw= xyzw; \ - VUregsn->VIwrite = 0; \ - VUregsn->VIread = (1<pipe = VUPIPE_FMAC; - VUregsn->VFwrite = _Fd_; - VUregsn->VFwxyzw = _XYZW; - VUregsn->VFread0 = _Fs_; - VUregsn->VFr0xyzw= _XYZW; - VUregsn->VFread1 = _Ft_; - VUregsn->VFr1xyzw= 1; - VUregsn->VIwrite = 0; - VUregsn->VIread = (1<VIread &= ~(1<VIread &= ~(1<VIread &= ~(1<VIread &= ~(1<pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFwxyzw= 0xE; - VUregsn->VFread0 = _Fs_; - VUregsn->VFr0xyzw= 0xE; - VUregsn->VFread1 = _Ft_; - VUregsn->VFr1xyzw= 0xE; - VUregsn->VIwrite = 1<VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_)|(1<pipe = VUPIPE_FMAC; - VUregsn->VFwrite = _Fd_; - VUregsn->VFwxyzw= 0xE; - VUregsn->VFread0 = _Fs_; - VUregsn->VFr0xyzw= 0xE; - VUregsn->VFread1 = _Ft_; - VUregsn->VFr1xyzw= 0xE; - VUregsn->VIwrite = 0; - VUregsn->VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_)|(1<pipe = VUPIPE_NONE; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 0; - VUregsn->VIread = 0; -} - -VUREGS_FTFS(FTOI0); -VUREGS_FTFS(FTOI4); -VUREGS_FTFS(FTOI12); -VUREGS_FTFS(FTOI15); -VUREGS_FTFS(ITOF0); -VUREGS_FTFS(ITOF4); -VUREGS_FTFS(ITOF12); -VUREGS_FTFS(ITOF15); - -void _vuRegsCLIP(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = _Fs_; - VUregsn->VFr0xyzw= 0xE; - VUregsn->VFread1 = _Ft_; - VUregsn->VFr1xyzw= 0x1; - VUregsn->VIwrite = 1 << REG_CLIP_FLAG; - VUregsn->VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_)|(1 << REG_CLIP_FLAG); -} - -/******************************/ -/* VU Lower instructions */ -/******************************/ - -void _vuRegsDIV(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FDIV; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = _Fs_; - VUregsn->VFr0xyzw= 1 << (3-_Fsf_); - VUregsn->VFread1 = _Ft_; - VUregsn->VFr1xyzw= 1 << (3-_Ftf_); - VUregsn->VIwrite = 1 << REG_Q; - VUregsn->VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_); - VUregsn->cycles = 6; -} - -void _vuRegsSQRT(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FDIV; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFr0xyzw = 0; - VUregsn->VFread1 = _Ft_; - VUregsn->VFr1xyzw = 1 << (3-_Ftf_); - VUregsn->VIwrite = 1 << REG_Q; - VUregsn->VIread = GET_VF0_FLAG(_Ft_); - VUregsn->cycles = 6; -} - -void _vuRegsRSQRT(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FDIV; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = _Fs_; - VUregsn->VFr0xyzw= 1 << (3-_Fsf_); - VUregsn->VFread1 = _Ft_; - VUregsn->VFr1xyzw= 1 << (3-_Ftf_); - VUregsn->VIwrite = 1 << REG_Q; - VUregsn->VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_); - VUregsn->cycles = 12; -} - -VUREGS_ITIS(IADDI); -VUREGS_ITIS(IADDIU); -VUREGS_IDISIT(IADD); -VUREGS_IDISIT(IAND); -VUREGS_IDISIT(IOR); -VUREGS_IDISIT(ISUB); -VUREGS_ITIS(ISUBIU); - -VUREGS_FTFS(MOVE); - -void _vuRegsMFIR(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = _Ft_; - VUregsn->VFwxyzw = _XYZW; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 0; - VUregsn->VIread = 1 << _Fs_; -} - -void _vuRegsMTIR(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = _Fs_; - VUregsn->VFr0xyzw= _XYZW; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << _Ft_; - VUregsn->VIread = GET_VF0_FLAG(_Fs_); -} - -VUREGS_FTFS(MR32); - -void _vuRegsLQ(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = _Ft_; - VUregsn->VFwxyzw = _XYZW; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 0; - VUregsn->VIread = 1 << _Fs_; -} - -void _vuRegsLQD(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = _Ft_; - VUregsn->VFwxyzw = _XYZW; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << _Fs_; - VUregsn->VIread = 1 << _Fs_; -} - -void _vuRegsLQI(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = _Ft_; - VUregsn->VFwxyzw = _XYZW; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << _Fs_; - VUregsn->VIread = 1 << _Fs_; -} - -void _vuRegsSQ(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = _Fs_; - VUregsn->VFr0xyzw= _XYZW; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 0; - VUregsn->VIread = (1 << _Ft_)|GET_VF0_FLAG(_Fs_); -} - -void _vuRegsSQD(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = _Fs_; - VUregsn->VFr0xyzw= _XYZW; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << _Ft_; - VUregsn->VIread = (1 << _Ft_)|GET_VF0_FLAG(_Fs_); -} - -void _vuRegsSQI(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = _Fs_; - VUregsn->VFr0xyzw= _XYZW; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << _Ft_; - VUregsn->VIread = (1 << _Ft_)|GET_VF0_FLAG(_Fs_); -} - -void _vuRegsILW(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_IALU; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << _Ft_; - VUregsn->VIread = 1 << _Fs_; -} - -void _vuRegsISW(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_IALU; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 0; - VUregsn->VIread = (1 << _Fs_) | (1 << _Ft_); -} - -void _vuRegsILWR(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_IALU; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = (1 << _Ft_); - VUregsn->VIread = (1 << _Fs_); -} - -void _vuRegsISWR(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_IALU; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 0; - VUregsn->VIread = (1 << _Fs_) | (1 << _Ft_); -} - -void _vuRegsRINIT(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = _Fs_; - VUregsn->VFr0xyzw= 1 << (3-_Fsf_); - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << REG_R; - VUregsn->VIread = GET_VF0_FLAG(_Fs_); -} - -void _vuRegsRGET(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = _Ft_; - VUregsn->VFwxyzw = _XYZW; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 0; - VUregsn->VIread = 1 << REG_R; -} - -void _vuRegsRNEXT(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = _Ft_; - VUregsn->VFwxyzw = _XYZW; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << REG_R; - VUregsn->VIread = 1 << REG_R; -} - -void _vuRegsRXOR(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = _Fs_; - VUregsn->VFr0xyzw= 1 << (3-_Fsf_); - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << REG_R; - VUregsn->VIread = (1 << REG_R)|GET_VF0_FLAG(_Fs_); -} - -void _vuRegsWAITQ(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FDIV; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 0; - VUregsn->VIread = 0; -} - -void _vuRegsFSAND(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << _Ft_; - VUregsn->VIread = 1 << REG_STATUS_FLAG; -} - -void _vuRegsFSEQ(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << _Ft_; - VUregsn->VIread = 1 << REG_STATUS_FLAG; -} - -void _vuRegsFSOR(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << _Ft_; - VUregsn->VIread = 1 << REG_STATUS_FLAG; -} - -void _vuRegsFSSET(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << REG_STATUS_FLAG; - VUregsn->VIread = 0;//1 << REG_STATUS_FLAG; this kills speed -} - -void _vuRegsFMAND(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << _Ft_; - VUregsn->VIread = (1 << REG_MAC_FLAG) | (1 << _Fs_); -} - -void _vuRegsFMEQ(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << _Ft_; - VUregsn->VIread = (1 << REG_MAC_FLAG) | (1 << _Fs_); -} - -void _vuRegsFMOR(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << _Ft_; - VUregsn->VIread = (1 << REG_MAC_FLAG) | (1 << _Fs_); -} - -void _vuRegsFCAND(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << 1; - VUregsn->VIread = 1 << REG_CLIP_FLAG; -} - -void _vuRegsFCEQ(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << 1; - VUregsn->VIread = 1 << REG_CLIP_FLAG; -} - -void _vuRegsFCOR(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << 1; - VUregsn->VIread = 1 << REG_CLIP_FLAG; -} - -void _vuRegsFCSET(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << REG_CLIP_FLAG; - VUregsn->VIread = 0; -} - -void _vuRegsFCGET(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << _Ft_; - VUregsn->VIread = 1 << REG_CLIP_FLAG; -} - -void _vuRegsIBEQ(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_BRANCH; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 0; - VUregsn->VIread = (1 << _Fs_) | (1 << _Ft_); -} - -void _vuRegsIBGEZ(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_BRANCH; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 0; - VUregsn->VIread = 1 << _Fs_; -} - -void _vuRegsIBGTZ(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_BRANCH; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 0; - VUregsn->VIread = 1 << _Fs_; -} - -void _vuRegsIBLEZ(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_BRANCH; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 0; - VUregsn->VIread = 1 << _Fs_; -} - -void _vuRegsIBLTZ(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_BRANCH; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 0; - VUregsn->VIread = 1 << _Fs_; -} - -void _vuRegsIBNE(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_BRANCH; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 0; - VUregsn->VIread = (1 << _Fs_) | (1 << _Ft_); -} - -void _vuRegsB(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_BRANCH; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 0; - VUregsn->VIread = 0; -} - -void _vuRegsBAL(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_BRANCH; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << _Ft_; - VUregsn->VIread = 0; -} - -void _vuRegsJR(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_BRANCH; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 0; - VUregsn->VIread = 1 << _Fs_; -} - -void _vuRegsJALR(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_BRANCH; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << _Ft_; - VUregsn->VIread = 1 << _Fs_; -} - -void _vuRegsMFP(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_FMAC; - VUregsn->VFwrite = _Ft_; - VUregsn->VFwxyzw = _XYZW; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 0; - VUregsn->VIread = 1 << REG_P; -} - -void _vuRegsWAITP(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_EFU; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 0; - VUregsn->VIread = 0; -} - -VUREGS_PFS(ESADD, 10); -VUREGS_PFS(ERSADD, 17); -VUREGS_PFS(ELENG, 17); -VUREGS_PFS(ERLENG, 23); -VUREGS_PFS(EATANxy, 53); -VUREGS_PFS(EATANxz, 53); -VUREGS_PFS(ESUM, 11); -VUREGS_PFS(ERCPR, 11); -VUREGS_PFS(ESQRT, 11); -VUREGS_PFS(ERSQRT, 17); -VUREGS_PFS(ESIN, 28); -VUREGS_PFS(EATAN, 53); -VUREGS_PFS(EEXP, 43); - -void _vuRegsXITOP(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_IALU; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << _Ft_; - VUregsn->VIread = 0; -} - -void _vuRegsXGKICK(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_XGKICK; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 0; - VUregsn->VIread = 1 << _Fs_; -} - -void _vuRegsXTOP(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->pipe = VUPIPE_IALU; - VUregsn->VFwrite = 0; - VUregsn->VFread0 = 0; - VUregsn->VFread1 = 0; - VUregsn->VIwrite = 1 << _Ft_; - VUregsn->VIread = 0; -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include + +#include "Common.h" +#include "VUmicro.h" +#include "VUflags.h" +#include "VUops.h" +#include "GS.h" + +//Lower/Upper instructions can use that.. +#define _Ft_ ((VU->code >> 16) & 0x1F) // The rt part of the instruction register +#define _Fs_ ((VU->code >> 11) & 0x1F) // The rd part of the instruction register +#define _Fd_ ((VU->code >> 6) & 0x1F) // The sa part of the instruction register + +#define _X ((VU->code>>24) & 0x1) +#define _Y ((VU->code>>23) & 0x1) +#define _Z ((VU->code>>22) & 0x1) +#define _W ((VU->code>>21) & 0x1) + +#define _XYZW ((VU->code>>21) & 0xF) + +#define _Fsf_ ((VU->code >> 21) & 0x03) +#define _Ftf_ ((VU->code >> 23) & 0x03) + +#define _Imm11_ (s32)(VU->code & 0x400 ? 0xfffffc00 | (VU->code & 0x3ff) : VU->code & 0x3ff) +#define _UImm11_ (s32)(VU->code & 0x7ff) + + +VECTOR RDzero; + +void _vuFMACflush(VURegs * VU) { + int i; + + for (i=0; i<8; i++) { + if (VU->fmac[i].enable == 0) continue; + + if ((VU->cycle - VU->fmac[i].sCycle) >= VU->fmac[i].Cycle) { + VUM_LOG("flushing FMAC pipe[%d] (macflag=%x)\n", i, VU->fmac[i].macflag); + + VU->fmac[i].enable = 0; + VU->VI[REG_MAC_FLAG].UL = VU->fmac[i].macflag; + VU->VI[REG_STATUS_FLAG].UL = VU->fmac[i].statusflag; + VU->VI[REG_CLIP_FLAG].UL = VU->fmac[i].clipflag; + } + } +} + +void _vuFDIVflush(VURegs * VU) { + if (VU->fdiv.enable == 0) return; + + if ((VU->cycle - VU->fdiv.sCycle) >= VU->fdiv.Cycle) { + VUM_LOG("flushing FDIV pipe\n"); + + VU->fdiv.enable = 0; + VU->VI[REG_Q].UL = VU->fdiv.reg.UL; + VU->VI[REG_STATUS_FLAG].UL = VU->fdiv.statusflag; + } +} + +void _vuEFUflush(VURegs * VU) { + if (VU->efu.enable == 0) return; + + if ((VU->cycle - VU->efu.sCycle) >= VU->efu.Cycle) { +// VUM_LOG("flushing EFU pipe\n"); + + VU->efu.enable = 0; + VU->VI[REG_P].UL = VU->efu.reg.UL; + } +} + +// called at end of program +void _vuFlushAll(VURegs* VU) +{ + int nRepeat = 1, i; + + do { + nRepeat = 0; + + for (i=0; i<8; i++) { + if (VU->fmac[i].enable == 0) continue; + + nRepeat = 1; + + if ((VU->cycle - VU->fmac[i].sCycle) >= VU->fmac[i].Cycle) { + VUM_LOG("flushing FMAC pipe[%d] (macflag=%x)\n", i, VU->fmac[i].macflag); + + VU->fmac[i].enable = 0; + VU->VI[REG_MAC_FLAG].UL = VU->fmac[i].macflag; + VU->VI[REG_STATUS_FLAG].UL = VU->fmac[i].statusflag; + VU->VI[REG_CLIP_FLAG].UL = VU->fmac[i].clipflag; + } + } + + if (VU->fdiv.enable ) { + + nRepeat = 1; + + if ((VU->cycle - VU->fdiv.sCycle) >= VU->fdiv.Cycle) { + VUM_LOG("flushing FDIV pipe\n"); + + nRepeat = 1; + VU->fdiv.enable = 0; + VU->VI[REG_Q].UL = VU->fdiv.reg.UL; + VU->VI[REG_STATUS_FLAG].UL = VU->fdiv.statusflag; + } + } + + if (VU->efu.enable) { + + nRepeat = 1; + + if ((VU->cycle - VU->efu.sCycle) >= VU->efu.Cycle) { + // VUM_LOG("flushing EFU pipe\n"); + + nRepeat = 1; + VU->efu.enable = 0; + VU->VI[REG_P].UL = VU->efu.reg.UL; + } + } + + VU->cycle++; + + } while(nRepeat); +} + +void _vuTestPipes(VURegs * VU) { + _vuFMACflush(VU); + _vuFDIVflush(VU); + _vuEFUflush(VU); +} + +void _vuFMACTestStall(VURegs * VU, int reg, int xyzw) { + int cycle; + int i; + + for (i=0; i<8; i++) { + if (VU->fmac[i].enable == 0) continue; + if (VU->fmac[i].reg == reg && + VU->fmac[i].xyzw & xyzw) break; + } + + if (i == 8) return; + + cycle = VU->fmac[i].Cycle - (VU->cycle - VU->fmac[i].sCycle) + 1; // add 1 delay! (fixes segaclassics bad geom) + VU->fmac[i].enable = 0; + VU->VI[REG_MAC_FLAG].UL = VU->fmac[i].macflag; + VU->VI[REG_STATUS_FLAG].UL = VU->fmac[i].statusflag; + VU->VI[REG_CLIP_FLAG].UL = VU->fmac[i].clipflag; + VUM_LOG("FMAC[%d] stall %d\n", i, cycle); + + VU->cycle+= cycle; + _vuTestPipes(VU); +} + +void _vuFMACAdd(VURegs * VU, int reg, int xyzw) { + int i; + + /* find a free fmac pipe */ + for (i=0; i<8; i++) { + if (VU->fmac[i].enable == 1) continue; + break; + } + if (i==8) { +// SysPrintf("*PCSX2*: error , out of fmacs %d\n", VU->cycle); + } + + VUM_LOG("adding FMAC pipe[%d]; xyzw=%x\n", i, xyzw); + + VU->fmac[i].enable = 1; + VU->fmac[i].sCycle = VU->cycle; + VU->fmac[i].Cycle = 3; + VU->fmac[i].reg = reg; + VU->fmac[i].xyzw = xyzw; + VU->fmac[i].macflag = VU->macflag; + VU->fmac[i].statusflag = VU->statusflag; + VU->fmac[i].clipflag = VU->clipflag; +} + +void _vuFDIVAdd(VURegs * VU, int cycles) { + VUM_LOG("adding FDIV pipe\n"); + + VU->fdiv.enable = 1; + VU->fdiv.sCycle = VU->cycle; + VU->fdiv.Cycle = cycles; + VU->fdiv.reg.F = VU->q.F; + VU->fdiv.statusflag = VU->statusflag; +} + +void _vuEFUAdd(VURegs * VU, int cycles) { +// VUM_LOG("adding EFU pipe\n"); + + VU->efu.enable = 1; + VU->efu.sCycle = VU->cycle; + VU->efu.Cycle = cycles; + VU->efu.reg.F = VU->p.F; +} + +void _vuFlushFDIV(VURegs * VU) { + int cycle; + + if (VU->fdiv.enable == 0) return; + + cycle = VU->fdiv.Cycle - (VU->cycle - VU->fdiv.sCycle); + VUM_LOG("waiting FDIV pipe %d\n", cycle); + + VU->fdiv.enable = 0; + VU->cycle+= cycle; + VU->VI[REG_Q].UL = VU->fdiv.reg.UL; + VU->VI[REG_STATUS_FLAG].UL = VU->fdiv.statusflag; +} + +void _vuFlushEFU(VURegs * VU) { + int cycle; + + if (VU->efu.enable == 0) return; + + cycle = VU->efu.Cycle - (VU->cycle - VU->efu.sCycle); +// VUM_LOG("waiting EFU pipe %d\n", cycle); + + VU->efu.enable = 0; + VU->cycle+= cycle; + VU->VI[REG_P].UL = VU->efu.reg.UL; +} + +void _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn) { + if (VUregsn->VFread0) { + _vuFMACTestStall(VU, VUregsn->VFread0, VUregsn->VFr0xyzw); + } + if (VUregsn->VFread1) { + _vuFMACTestStall(VU, VUregsn->VFread1, VUregsn->VFr1xyzw); + } +} + +void _vuAddFMACStalls(VURegs * VU, _VURegsNum *VUregsn) { + if (VUregsn->VFwrite) { + _vuFMACAdd(VU, VUregsn->VFwrite, VUregsn->VFwxyzw); + } else + if (VUregsn->VIwrite & (1 << REG_CLIP_FLAG)) { + _vuFMACAdd(VU, -REG_CLIP_FLAG, 0); + } else { + _vuFMACAdd(VU, 0, 0); + } +} + +void _vuTestFDIVStalls(VURegs * VU, _VURegsNum *VUregsn) { +// _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn); + _vuFlushFDIV(VU); +} + +void _vuAddFDIVStalls(VURegs * VU, _VURegsNum *VUregsn) { + if (VUregsn->VIwrite & (1 << REG_Q)) { + _vuFDIVAdd(VU, VUregsn->cycles); + } +} + + +void _vuTestEFUStalls(VURegs * VU, _VURegsNum *VUregsn) { +// _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn); + _vuFlushEFU(VU); +} + +void _vuAddEFUStalls(VURegs * VU, _VURegsNum *VUregsn) { + if (VUregsn->VIwrite & (1 << REG_P)) { + _vuEFUAdd(VU, VUregsn->cycles); + } +} + +void _vuTestUpperStalls(VURegs * VU, _VURegsNum *VUregsn) { + switch (VUregsn->pipe) { + case VUPIPE_FMAC: _vuTestFMACStalls(VU, VUregsn); break; + } +} + +void _vuTestLowerStalls(VURegs * VU, _VURegsNum *VUregsn) { + switch (VUregsn->pipe) { + case VUPIPE_FMAC: _vuTestFMACStalls(VU, VUregsn); break; + case VUPIPE_FDIV: _vuTestFDIVStalls(VU, VUregsn); break; + case VUPIPE_EFU: _vuTestEFUStalls(VU, VUregsn); break; + } +} + +void _vuAddUpperStalls(VURegs * VU, _VURegsNum *VUregsn) { + switch (VUregsn->pipe) { + case VUPIPE_FMAC: _vuAddFMACStalls(VU, VUregsn); break; + } +} + +void _vuAddLowerStalls(VURegs * VU, _VURegsNum *VUregsn) { + switch (VUregsn->pipe) { + case VUPIPE_FMAC: _vuAddFMACStalls(VU, VUregsn); break; + case VUPIPE_FDIV: _vuAddFDIVStalls(VU, VUregsn); break; + case VUPIPE_EFU: _vuAddEFUStalls(VU, VUregsn); break; + } +} + + +/******************************/ +/* VU Upper instructions */ +/******************************/ +#ifndef INT_VUDOUBLEHACK +static u32 d; +float vuDouble(u32 f) +{ + switch(f & 0x7f800000){ + case 0x0: + f &= 0x80000000; + return *(float*)&f; + break; + case 0x7f800000: + d = (f & 0x80000000)|0x7f7fffff; + return *(float*)&d; + break; + default: + return *(float*)&f; + break; + } +} +#else +float vuDouble(u32 f) +{ + return *(float*)&f; +} +#endif + +void _vuABS(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X){ VU->VF[_Ft_].f.x = fabs(vuDouble(VU->VF[_Fs_].i.x)); } + if (_Y){ VU->VF[_Ft_].f.y = fabs(vuDouble(VU->VF[_Fs_].i.y)); } + if (_Z){ VU->VF[_Ft_].f.z = fabs(vuDouble(VU->VF[_Fs_].i.z)); } + if (_W){ VU->VF[_Ft_].f.w = fabs(vuDouble(VU->VF[_Fs_].i.w)); } +}/*Reworked from define to function. asadr*/ + + +void _vuADD(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + + +void _vuADDi(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VI[REG_I].UL));} else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VI[REG_I].UL));} else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + vuDouble(VU->VI[REG_I].UL));} else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + vuDouble(VU->VI[REG_I].UL));} else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDq(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VI[REG_Q].UL)); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VI[REG_Q].UL)); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + vuDouble(VU->VI[REG_Q].UL)); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + vuDouble(VU->VI[REG_Q].UL)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + + +void _vuADDx(VURegs * VU) { + float ftx; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftx=vuDouble(VU->VF[_Ft_].i.x); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + ftx); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + ftx); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + ftx); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + ftx); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDy(VURegs * VU) { + float fty; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + fty=vuDouble(VU->VF[_Ft_].i.y); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + fty);} else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + fty);} else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + fty);} else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + fty);} else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDz(VURegs * VU) { + float ftz; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftz=vuDouble(VU->VF[_Ft_].i.z); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + ftz); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + ftz); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + ftz); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + ftz); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDw(VURegs * VU) { + float ftw; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftw=vuDouble(VU->VF[_Ft_].i.w); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + ftw); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + ftw); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + ftw); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + ftw); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDA(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDAi(VURegs * VU) { + float ti = vuDouble(VU->VI[REG_I].UL); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + ti); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + ti); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + ti); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + ti); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDAq(VURegs * VU) { + float tf = vuDouble(VU->VI[REG_Q].UL); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + tf); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + tf); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + tf); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + tf); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDAx(VURegs * VU) { + float tx = vuDouble(VU->VF[_Ft_].i.x); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + tx); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + tx); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + tx); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + tx); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDAy(VURegs * VU) { + float ty = vuDouble(VU->VF[_Ft_].i.y); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + ty); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + ty); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + ty); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + ty); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDAz(VURegs * VU) { + float tz = vuDouble(VU->VF[_Ft_].i.z); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + tz); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + tz); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + tz); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + tz); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + +void _vuADDAw(VURegs * VU) { + float tw = vuDouble(VU->VF[_Ft_].i.w); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) + tw); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) + tw); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) + tw); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) + tw); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*Reworked from define to function. asadr*/ + + +void _vuSUB(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBi(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBq(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBx(VURegs * VU) { + float ftx; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftx=vuDouble(VU->VF[_Ft_].i.x); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - ftx); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - ftx); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - ftx); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - ftx); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBy(VURegs * VU) { + float fty; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + fty=vuDouble(VU->VF[_Ft_].i.y); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - fty); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - fty); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - fty); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - fty); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBz(VURegs * VU) { + float ftz; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftz=vuDouble(VU->VF[_Ft_].i.z); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - ftz); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - ftz); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - ftz); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - ftz); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBw(VURegs * VU) { + float ftw; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftw=vuDouble(VU->VF[_Ft_].i.w); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - ftw); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - ftw); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - ftw); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - ftw); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + + +void _vuSUBA(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBAi(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - vuDouble(VU->VI[REG_I].UL)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBAq(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - vuDouble(VU->VI[REG_Q].UL)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBAx(VURegs * VU) { + float tx = vuDouble(VU->VF[_Ft_].i.x); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - tx); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - tx); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - tx); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - tx); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBAy(VURegs * VU) { + float ty = vuDouble(VU->VF[_Ft_].i.y); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - ty); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - ty); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - ty); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - ty); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBAz(VURegs * VU) { + float tz = vuDouble(VU->VF[_Ft_].i.z); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - tz); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - tz); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - tz); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - tz); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuSUBAw(VURegs * VU) { + float tw = vuDouble(VU->VF[_Ft_].i.w); + + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) - tw); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) - tw); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) - tw); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) - tw); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}//updated 10/05/03 shadow + +void _vuMUL(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +/* No need to presave I reg in ti. asadr */ +void _vuMULi(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +void _vuMULq(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +void _vuMULx(VURegs * VU) { + float ftx; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftx=vuDouble(VU->VF[_Ft_].i.x); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * ftx); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * ftx); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * ftx); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * ftx); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + + +void _vuMULy(VURegs * VU) { + float fty; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + fty=vuDouble(VU->VF[_Ft_].i.y); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * fty); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * fty); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * fty); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * fty); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +void _vuMULz(VURegs * VU) { + float ftz; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftz=vuDouble(VU->VF[_Ft_].i.z); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * ftz); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * ftz); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * ftz); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * ftz); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +void _vuMULw(VURegs * VU) { + float ftw; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftw=vuDouble(VU->VF[_Ft_].i.w); + if (_X){ dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * ftw); } else VU_MACx_CLEAR(VU); + if (_Y){ dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * ftw); } else VU_MACy_CLEAR(VU); + if (_Z){ dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * ftw); } else VU_MACz_CLEAR(VU); + if (_W){ dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * ftw); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + + +void _vuMULA(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +/* No need to presave I reg in ti. asadr */ +void _vuMULAi(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_I].UL)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +/* No need to presave Q reg in ti. asadr */ +void _vuMULAq(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_Q].UL)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +/* No need to presave X reg in ti. asadr */ +void _vuMULAx(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.x)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +void _vuMULAy(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.y)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +void _vuMULAz(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.z)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +void _vuMULAw(VURegs * VU) { + if (_X){ VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACx_CLEAR(VU); + if (_Y){ VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACy_CLEAR(VU); + if (_Z){ VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACz_CLEAR(VU); + if (_W){ VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w)); } else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 8/05/03 shadow */ + +void _vuMADD(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 10/05/03 shadow */ + + +void _vuMADDi(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_I].UL))); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_I].UL))); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_I].UL))); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_I].UL))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 10/05/03 shadow */ + +/* No need to presave . asadr */ +void _vuMADDq(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 10/05/03 shadow */ + +void _vuMADDx(VURegs * VU) { + float ftx; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftx=vuDouble(VU->VF[_Ft_].i.x); + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * ftx)); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * ftx)); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * ftx)); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * ftx)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 10/05/03 shadow */ + +void _vuMADDy(VURegs * VU) { + float fty; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + fty=vuDouble(VU->VF[_Ft_].i.y); + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * fty)); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * fty)); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * fty)); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * fty)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 10/05/03 shadow */ + +void _vuMADDz(VURegs * VU) { + float ftz; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftz=vuDouble(VU->VF[_Ft_].i.z); + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * ftz)); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * ftz)); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * ftz)); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * ftz)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 10/05/03 shadow */ + +void _vuMADDw(VURegs * VU) { + float ftw; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftw=vuDouble(VU->VF[_Ft_].i.w); + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * ftw)); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * ftw)); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * ftw)); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * ftw)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 10/05/03 shadow */ + +void _vuMADDA(VURegs * VU) { + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + (vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + (vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + (vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + (vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last updated 10/05/03 shadow*/ + +void _vuMADDAi(VURegs * VU) { + float ti = vuDouble(VU->VI[REG_I].UL); + + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * ti)); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * ti)); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * ti)); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * ti)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last updated 10/05/03 shadow*/ + +void _vuMADDAq(VURegs * VU) { + float tq = vuDouble(VU->VI[REG_Q].UL); + + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * tq)); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * tq)); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * tq)); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * tq)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last update 10/05/03 shadow*/ + +void _vuMADDAx(VURegs * VU) { + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last update 11/05/03 shadow*/ + +void _vuMADDAy(VURegs * VU) { + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last update 11/05/03 shadow*/ + +void _vuMADDAz(VURegs * VU) { + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last update 11/05/03 shadow*/ + +void _vuMADDAw(VURegs * VU) { + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) + ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) + ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) + ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) + ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last update 11/05/03 shadow*/ + +void _vuMSUB(VURegs * VU) { + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 11/05/03 shadow */ + +void _vuMSUBi(VURegs * VU) { + float ti = vuDouble(VU->VI[REG_I].UL); + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * ti ) ); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * ti ) ); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * ti ) ); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * ti ) ); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 11/05/03 shadow */ + +void _vuMSUBq(VURegs * VU) { + float tq = vuDouble(VU->VI[REG_Q].UL); + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * tq ) ); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * tq ) ); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * tq ) ); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * tq ) ); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 11/05/03 shadow */ + + +void _vuMSUBx(VURegs * VU) { + float ftx; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftx=vuDouble(VU->VF[_Ft_].i.x); + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * ftx ) ); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * ftx ) ); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * ftx ) ); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * ftx ) ); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 11/05/03 shadow */ + + +void _vuMSUBy(VURegs * VU) { + float fty; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + fty=vuDouble(VU->VF[_Ft_].i.y); + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * fty ) ); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * fty ) ); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * fty ) ); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * fty ) ); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 11/05/03 shadow */ + + +void _vuMSUBz(VURegs * VU) { + float ftz; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftz=vuDouble(VU->VF[_Ft_].i.z); + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * ftz ) ); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * ftz ) ); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * ftz ) ); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * ftz ) ); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 11/05/03 shadow */ + +void _vuMSUBw(VURegs * VU) { + float ftw; + VECTOR * dst; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftw=vuDouble(VU->VF[_Ft_].i.w); + if (_X) dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * ftw ) ); else VU_MACx_CLEAR(VU); + if (_Y) dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * ftw ) ); else VU_MACy_CLEAR(VU); + if (_Z) dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * ftw ) ); else VU_MACz_CLEAR(VU); + if (_W) dst->i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * ftw ) ); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/* last update 11/05/03 shadow */ + + +void _vuMSUBA(VURegs * VU) { + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.x))); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.y))); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.z))); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VF[_Ft_].i.w))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last updated 11/05/03 shadow*/ + +void _vuMSUBAi(VURegs * VU) { + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_I].UL))); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_I].UL))); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_I].UL))); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_I].UL))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last updated 11/05/03 shadow*/ + +void _vuMSUBAq(VURegs * VU) { + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * vuDouble(VU->VI[REG_Q].UL))); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last updated 11/05/03 shadow*/ + +void _vuMSUBAx(VURegs * VU) { + float tx = vuDouble(VU->VF[_Ft_].i.x); + + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * tx)); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * tx)); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * tx)); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * tx)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last updated 11/05/03 shadow*/ + +void _vuMSUBAy(VURegs * VU) { + float ty = vuDouble(VU->VF[_Ft_].i.y); + + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * ty)); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * ty)); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * ty)); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * ty)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last updated 11/05/03 shadow*/ + +void _vuMSUBAz(VURegs * VU) { + float tz = vuDouble(VU->VF[_Ft_].i.z); + + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * tz)); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * tz)); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * tz)); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * tz)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last updated 11/05/03 shadow*/ + +void _vuMSUBAw(VURegs * VU) { + float tw = vuDouble(VU->VF[_Ft_].i.w); + + if (_X) VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - ( vuDouble(VU->VF[_Fs_].i.x) * tw)); else VU_MACx_CLEAR(VU); + if (_Y) VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - ( vuDouble(VU->VF[_Fs_].i.y) * tw)); else VU_MACy_CLEAR(VU); + if (_Z) VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - ( vuDouble(VU->VF[_Fs_].i.z) * tw)); else VU_MACz_CLEAR(VU); + if (_W) VU->ACC.i.w = VU_MACw_UPDATE(VU, vuDouble(VU->ACC.i.w) - ( vuDouble(VU->VF[_Fs_].i.w) * tw)); else VU_MACw_CLEAR(VU); + VU_STAT_UPDATE(VU); +}/*last updated 11/05/03 shadow*/ + +u32 _MAX(u32 a, u32 b) { + if (a & 0x80000000) { // -a + if (b & 0x80000000) { // -b + return (a & 0x7fffffff) > (b & 0x7fffffff) ? b : a; + } else { // +b + return b; + } + } else { // +a + if (b & 0x80000000) { // -b + return a; + } else { // +b + return (a & 0x7fffffff) > (b & 0x7fffffff) ? a : b; + } + } + + return 0; +} + +void _vuMAX(VURegs * VU) { + if (_Fd_ == 0) return; + + /* ft is bc */ + if (_X) VU->VF[_Fd_].i.x = _MAX(VU->VF[_Fs_].i.x, (s32)VU->VF[_Ft_].i.x); + if (_Y) VU->VF[_Fd_].i.y = _MAX(VU->VF[_Fs_].i.y, (s32)VU->VF[_Ft_].i.y); + if (_Z) VU->VF[_Fd_].i.z = _MAX(VU->VF[_Fs_].i.z, (s32)VU->VF[_Ft_].i.z); + if (_W) VU->VF[_Fd_].i.w = _MAX(VU->VF[_Fs_].i.w, (s32)VU->VF[_Ft_].i.w); +}//checked 13/05/03 shadow + +void _vuMAXi(VURegs * VU) { + if (_Fd_ == 0) return; + + /* ft is bc */ + if (_X) VU->VF[_Fd_].i.x = _MAX(VU->VF[_Fs_].i.x, VU->VI[REG_I].UL); + if (_Y) VU->VF[_Fd_].i.y = _MAX(VU->VF[_Fs_].i.y, VU->VI[REG_I].UL); + if (_Z) VU->VF[_Fd_].i.z = _MAX(VU->VF[_Fs_].i.z, VU->VI[REG_I].UL); + if (_W) VU->VF[_Fd_].i.w = _MAX(VU->VF[_Fs_].i.w, VU->VI[REG_I].UL); +}//checked 13/05/03 shadow + +void _vuMAXx(VURegs * VU) { + s32 ftx; + if (_Fd_ == 0) return; + + ftx=(s32)VU->VF[_Ft_].i.x; + if (_X) VU->VF[_Fd_].i.x = _MAX(VU->VF[_Fs_].i.x, ftx); + if (_Y) VU->VF[_Fd_].i.y = _MAX(VU->VF[_Fs_].i.y, ftx); + if (_Z) VU->VF[_Fd_].i.z = _MAX(VU->VF[_Fs_].i.z, ftx); + if (_W) VU->VF[_Fd_].i.w = _MAX(VU->VF[_Fs_].i.w, ftx); +} +//checked 13/05/03 shadow + +void _vuMAXy(VURegs * VU) { + s32 fty; + if (_Fd_ == 0) return; + + fty=(s32)VU->VF[_Ft_].i.y; + if (_X) VU->VF[_Fd_].i.x = _MAX(VU->VF[_Fs_].i.x, fty); + if (_Y) VU->VF[_Fd_].i.y = _MAX(VU->VF[_Fs_].i.y, fty); + if (_Z) VU->VF[_Fd_].i.z = _MAX(VU->VF[_Fs_].i.z, fty); + if (_W) VU->VF[_Fd_].i.w = _MAX(VU->VF[_Fs_].i.w, fty); +}//checked 13/05/03 shadow + +void _vuMAXz(VURegs * VU) { + s32 ftz; + if (_Fd_ == 0) return; + + ftz=(s32)VU->VF[_Ft_].i.z; + if (_X) VU->VF[_Fd_].i.x = _MAX(VU->VF[_Fs_].i.x, ftz); + if (_Y) VU->VF[_Fd_].i.y = _MAX(VU->VF[_Fs_].i.y, ftz); + if (_Z) VU->VF[_Fd_].i.z = _MAX(VU->VF[_Fs_].i.z, ftz); + if (_W) VU->VF[_Fd_].i.w = _MAX(VU->VF[_Fs_].i.w, ftz); +} + +void _vuMAXw(VURegs * VU) { + s32 ftw; + if (_Fd_ == 0) return; + + ftw=(s32)VU->VF[_Ft_].i.w; + if (_X) VU->VF[_Fd_].i.x = _MAX(VU->VF[_Fs_].i.x, ftw); + if (_Y) VU->VF[_Fd_].i.y = _MAX(VU->VF[_Fs_].i.y, ftw); + if (_Z) VU->VF[_Fd_].i.z = _MAX(VU->VF[_Fs_].i.z, ftw); + if (_W) VU->VF[_Fd_].i.w = _MAX(VU->VF[_Fs_].i.w, ftw); +} + +u32 _MINI(u32 a, u32 b) { + if (a & 0x80000000) { // -a + if (b & 0x80000000) { // -b + return (a & 0x7fffffff) < (b & 0x7fffffff) ? b : a; + } else { // +b + return a; + } + } else { // +a + if (b & 0x80000000) { // -b + return b; + } else { // +b + return (a & 0x7fffffff) < (b & 0x7fffffff) ? a : b; + } + } + + return 0; +} + +void _vuMINI(VURegs * VU) { + if (_Fd_ == 0) return; + + /* ft is bc */ + if (_X) VU->VF[_Fd_].i.x = _MINI(VU->VF[_Fs_].i.x, (s32)VU->VF[_Ft_].i.x); + if (_Y) VU->VF[_Fd_].i.y = _MINI(VU->VF[_Fs_].i.y, (s32)VU->VF[_Ft_].i.y); + if (_Z) VU->VF[_Fd_].i.z = _MINI(VU->VF[_Fs_].i.z, (s32)VU->VF[_Ft_].i.z); + if (_W) VU->VF[_Fd_].i.w = _MINI(VU->VF[_Fs_].i.w, (s32)VU->VF[_Ft_].i.w); +}//checked 13/05/03 shadow + +void _vuMINIi(VURegs * VU) { + if (_Fd_ == 0) return; + + /* ft is bc */ + if (_X) VU->VF[_Fd_].i.x = _MINI(VU->VF[_Fs_].i.x, VU->VI[REG_I].UL); + if (_Y) VU->VF[_Fd_].i.y = _MINI(VU->VF[_Fs_].i.y, VU->VI[REG_I].UL); + if (_Z) VU->VF[_Fd_].i.z = _MINI(VU->VF[_Fs_].i.z, VU->VI[REG_I].UL); + if (_W) VU->VF[_Fd_].i.w = _MINI(VU->VF[_Fs_].i.w, VU->VI[REG_I].UL); +}//checked 13/05/03 shadow + +void _vuMINIx(VURegs * VU) { + s32 ftx; + if (_Fd_ == 0) return; + + ftx=(s32)VU->VF[_Ft_].i.x; + if (_X) VU->VF[_Fd_].i.x = _MINI(VU->VF[_Fs_].i.x, ftx); + if (_Y) VU->VF[_Fd_].i.y = _MINI(VU->VF[_Fs_].i.y, ftx); + if (_Z) VU->VF[_Fd_].i.z = _MINI(VU->VF[_Fs_].i.z, ftx); + if (_W) VU->VF[_Fd_].i.w = _MINI(VU->VF[_Fs_].i.w, ftx); +} +//checked 13/05/03 shadow + +void _vuMINIy(VURegs * VU) { + s32 fty; + if (_Fd_ == 0) return; + + fty=(s32)VU->VF[_Ft_].i.y; + if (_X) VU->VF[_Fd_].i.x = _MINI(VU->VF[_Fs_].i.x, fty); + if (_Y) VU->VF[_Fd_].i.y = _MINI(VU->VF[_Fs_].i.y, fty); + if (_Z) VU->VF[_Fd_].i.z = _MINI(VU->VF[_Fs_].i.z, fty); + if (_W) VU->VF[_Fd_].i.w = _MINI(VU->VF[_Fs_].i.w, fty); +}//checked 13/05/03 shadow + +void _vuMINIz(VURegs * VU) { + s32 ftz; + if (_Fd_ == 0) return; + + ftz=(s32)VU->VF[_Ft_].i.z; + if (_X) VU->VF[_Fd_].i.x = _MINI(VU->VF[_Fs_].i.x, ftz); + if (_Y) VU->VF[_Fd_].i.y = _MINI(VU->VF[_Fs_].i.y, ftz); + if (_Z) VU->VF[_Fd_].i.z = _MINI(VU->VF[_Fs_].i.z, ftz); + if (_W) VU->VF[_Fd_].i.w = _MINI(VU->VF[_Fs_].i.w, ftz); +} + +void _vuMINIw(VURegs * VU) { + s32 ftw; + if (_Fd_ == 0) return; + + ftw=(s32)VU->VF[_Ft_].i.w; + if (_X) VU->VF[_Fd_].i.x = _MINI(VU->VF[_Fs_].i.x, ftw); + if (_Y) VU->VF[_Fd_].i.y = _MINI(VU->VF[_Fs_].i.y, ftw); + if (_Z) VU->VF[_Fd_].i.z = _MINI(VU->VF[_Fs_].i.z, ftw); + if (_W) VU->VF[_Fd_].i.w = _MINI(VU->VF[_Fs_].i.w, ftw); +} + +void _vuOPMULA(VURegs * VU) { + VU->ACC.i.x = VU_MACx_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Ft_].i.z)); + VU->ACC.i.y = VU_MACy_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Ft_].i.x)); + VU->ACC.i.z = VU_MACz_UPDATE(VU, vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Ft_].i.y)); + VU_STAT_UPDATE(VU); +}/*last updated 8/05/03 shadow*/ + +void _vuOPMSUB(VURegs * VU) { + VECTOR * dst; + float ftx, fty, ftz; + float fsx, fsy, fsz; + if (_Fd_ == 0) dst = &RDzero; + else dst = &VU->VF[_Fd_]; + + ftx = vuDouble(VU->VF[_Ft_].i.x); fty = vuDouble(VU->VF[_Ft_].i.y); ftz = vuDouble(VU->VF[_Ft_].i.z); + fsx = vuDouble(VU->VF[_Fs_].i.x); fsy = vuDouble(VU->VF[_Fs_].i.y); fsz = vuDouble(VU->VF[_Fs_].i.z); + dst->i.x = VU_MACx_UPDATE(VU, vuDouble(VU->ACC.i.x) - fsy * ftz); + dst->i.y = VU_MACy_UPDATE(VU, vuDouble(VU->ACC.i.y) - fsz * ftx); + dst->i.z = VU_MACz_UPDATE(VU, vuDouble(VU->ACC.i.z) - fsx * fty); + VU_STAT_UPDATE(VU); +}/*last updated 8/05/03 shadow*/ + +void _vuNOP(VURegs * VU) { +} + +void _vuFTOI0(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].SL[0] = (s32)vuDouble(VU->VF[_Fs_].i.x); + if (_Y) VU->VF[_Ft_].SL[1] = (s32)vuDouble(VU->VF[_Fs_].i.y); + if (_Z) VU->VF[_Ft_].SL[2] = (s32)vuDouble(VU->VF[_Fs_].i.z); + if (_W) VU->VF[_Ft_].SL[3] = (s32)vuDouble(VU->VF[_Fs_].i.w); +} + +void _vuFTOI4(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].SL[0] = float_to_int4(vuDouble(VU->VF[_Fs_].i.x)); + if (_Y) VU->VF[_Ft_].SL[1] = float_to_int4(vuDouble(VU->VF[_Fs_].i.y)); + if (_Z) VU->VF[_Ft_].SL[2] = float_to_int4(vuDouble(VU->VF[_Fs_].i.z)); + if (_W) VU->VF[_Ft_].SL[3] = float_to_int4(vuDouble(VU->VF[_Fs_].i.w)); +} + +void _vuFTOI12(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].SL[0] = float_to_int12(vuDouble(VU->VF[_Fs_].i.x)); + if (_Y) VU->VF[_Ft_].SL[1] = float_to_int12(vuDouble(VU->VF[_Fs_].i.y)); + if (_Z) VU->VF[_Ft_].SL[2] = float_to_int12(vuDouble(VU->VF[_Fs_].i.z)); + if (_W) VU->VF[_Ft_].SL[3] = float_to_int12(vuDouble(VU->VF[_Fs_].i.w)); +} + +void _vuFTOI15(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].SL[0] = float_to_int15(vuDouble(VU->VF[_Fs_].i.x)); + if (_Y) VU->VF[_Ft_].SL[1] = float_to_int15(vuDouble(VU->VF[_Fs_].i.y)); + if (_Z) VU->VF[_Ft_].SL[2] = float_to_int15(vuDouble(VU->VF[_Fs_].i.z)); + if (_W) VU->VF[_Ft_].SL[3] = float_to_int15(vuDouble(VU->VF[_Fs_].i.w)); +} + +void _vuITOF0(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].f.x = (float)VU->VF[_Fs_].SL[0]; + if (_Y) VU->VF[_Ft_].f.y = (float)VU->VF[_Fs_].SL[1]; + if (_Z) VU->VF[_Ft_].f.z = (float)VU->VF[_Fs_].SL[2]; + if (_W) VU->VF[_Ft_].f.w = (float)VU->VF[_Fs_].SL[3]; +} + +void _vuITOF4(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].f.x = int4_to_float(VU->VF[_Fs_].SL[0]); + if (_Y) VU->VF[_Ft_].f.y = int4_to_float(VU->VF[_Fs_].SL[1]); + if (_Z) VU->VF[_Ft_].f.z = int4_to_float(VU->VF[_Fs_].SL[2]); + if (_W) VU->VF[_Ft_].f.w = int4_to_float(VU->VF[_Fs_].SL[3]); +} + +void _vuITOF12(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].f.x = int12_to_float(VU->VF[_Fs_].SL[0]); + if (_Y) VU->VF[_Ft_].f.y = int12_to_float(VU->VF[_Fs_].SL[1]); + if (_Z) VU->VF[_Ft_].f.z = int12_to_float(VU->VF[_Fs_].SL[2]); + if (_W) VU->VF[_Ft_].f.w = int12_to_float(VU->VF[_Fs_].SL[3]); +} + +void _vuITOF15(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].f.x = int15_to_float(VU->VF[_Fs_].SL[0]); + if (_Y) VU->VF[_Ft_].f.y = int15_to_float(VU->VF[_Fs_].SL[1]); + if (_Z) VU->VF[_Ft_].f.z = int15_to_float(VU->VF[_Fs_].SL[2]); + if (_W) VU->VF[_Ft_].f.w = int15_to_float(VU->VF[_Fs_].SL[3]); +} + +/* Different type of clipping by presaving w. asadr */ +void _vuCLIP(VURegs * VU) { + float value = fabs(vuDouble(VU->VF[_Ft_].i.w)); + + VU->clipflag <<= 6; + if ( vuDouble(VU->VF[_Fs_].i.x) > +value ) VU->clipflag|= 0x01; + if ( vuDouble(VU->VF[_Fs_].i.x) < -value ) VU->clipflag|= 0x02; + if ( vuDouble(VU->VF[_Fs_].i.y) > +value ) VU->clipflag|= 0x04; + if ( vuDouble(VU->VF[_Fs_].i.y) < -value ) VU->clipflag|= 0x08; + if ( vuDouble(VU->VF[_Fs_].i.z) > +value ) VU->clipflag|= 0x10; + if ( vuDouble(VU->VF[_Fs_].i.z) < -value ) VU->clipflag|= 0x20; + VU->clipflag = VU->clipflag & 0xFFFFFF; + VU->VI[REG_CLIP_FLAG].UL = VU->clipflag; + + +}/*last update 16/07/05 refraction - Needs checking */ + + +/******************************/ +/* VU Lower instructions */ +/******************************/ + +void _vuDIV(VURegs * VU) { + float ft = vuDouble(VU->VF[_Ft_].UL[_Ftf_]); + float fs = vuDouble(VU->VF[_Fs_].UL[_Fsf_]); + +// _vuFMACTestStall(VU, _Fs_); _vuFMACTestStall(VU, _Ft_); + VU->statusflag = (VU->statusflag&0xfcf)|((VU->statusflag&0x30)<<6); + + if (ft == 0.0) { + if (fs == 0.0) { + VU->statusflag |= 0x10; + } else { + VU->statusflag |= 0x20; + } + if ((VU->VF[_Ft_].UL[_Ftf_] & 0x80000000) ^ + (VU->VF[_Fs_].UL[_Fsf_] & 0x80000000)) { + VU->q.UL = 0xFF7FFFFF; + } else { + VU->q.UL = 0x7F7FFFFF; + } + } else { + VU->q.F = fs / ft; + VU->q.F = vuDouble(VU->q.UL); + } +} //last update 15/01/06 zerofrog + +void _vuSQRT(VURegs * VU) { + float ft = vuDouble(VU->VF[_Ft_].UL[_Ftf_]); + +// _vuFMACTestStall(VU, _Ft_); + VU->statusflag = (VU->statusflag&0xfcf)|((VU->statusflag&0x30)<<6); + + if (ft < 0.0 ) + VU->statusflag |= 0x10; + VU->q.F = sqrt(fabs(ft)); + VU->q.F = vuDouble(VU->q.UL); +} //last update 15/01/06 zerofrog + + +/* Eminent Bug - Dvisior == 0 Check Missing ( D Flag Not Set ) */ +/* REFIXED....ASADR; rerefixed....zerofrog */ +void _vuRSQRT(VURegs * VU) { + float ft = vuDouble(VU->VF[_Ft_].UL[_Ftf_]); + float fs = vuDouble(VU->VF[_Fs_].UL[_Fsf_]); + float temp; + +// _vuFMACTestStall(VU, _Fs_); _vuFMACTestStall(VU, _Ft_); + VU->statusflag = (VU->statusflag&0xfcf)|((VU->statusflag&0x30)<<6); + + if ( ft == 0.0 ) { + VU->statusflag |= 0x20; + + if( fs != 0 ) { + if ((VU->VF[_Ft_].UL[_Ftf_] & 0x80000000) ^ + (VU->VF[_Fs_].UL[_Fsf_] & 0x80000000)) { + VU->q.UL = 0xFF7FFFFF; + } else { + VU->q.UL = 0x7F7FFFFF; + } + } + else { + if ((VU->VF[_Ft_].UL[_Ftf_] & 0x80000000) ^ + (VU->VF[_Fs_].UL[_Fsf_] & 0x80000000)) { + VU->q.UL = 0x80000000; + } else { + VU->q.UL = 0; + } + + VU->statusflag |= 0x10; + } + + } else { + if (ft < 0.0) { + VU->statusflag |= 0x10; + } + + temp = sqrt(fabs(ft)); + VU->q.F = fs / temp; + VU->q.F = vuDouble(VU->q.UL); + } +} //last update 15/01/06 zerofrog + + +void _vuIADDI(VURegs * VU) { + s16 imm = ((VU->code >> 6) & 0x1f); + imm = ((imm & 0x10 ? 0xfff0 : 0) | (imm & 0xf)); + if(_Ft_ == 0) return; + VU->VI[_Ft_].SS[0] = VU->VI[_Fs_].SS[0] + imm; +}//last checked 17/05/03 shadow NOTE: not quite sure about that + +void _vuIADDIU(VURegs * VU) { + if(_Ft_ == 0) return; + VU->VI[_Ft_].SS[0] = VU->VI[_Fs_].SS[0] + (((VU->code >> 10) & 0x7800) | (VU->code & 0x7ff)); +}//last checked 17/05/03 shadow + +void _vuIADD(VURegs * VU) { + if(_Fd_ == 0) return; + VU->VI[_Fd_].SS[0] = VU->VI[_Fs_].SS[0] + VU->VI[_Ft_].SS[0]; +}//last checked 17/05/03 shadow + +void _vuIAND(VURegs * VU) { + if(_Fd_ == 0) return; + VU->VI[_Fd_].US[0] = VU->VI[_Fs_].US[0] & VU->VI[_Ft_].US[0]; +}//last checked 17/05/03 shadow + +void _vuIOR(VURegs * VU) { + if(_Fd_ == 0) return; + VU->VI[_Fd_].US[0] = VU->VI[_Fs_].US[0] | VU->VI[_Ft_].US[0]; +} + +void _vuISUB(VURegs * VU) { + if(_Fd_ == 0) return; + VU->VI[_Fd_].SS[0] = VU->VI[_Fs_].SS[0] - VU->VI[_Ft_].SS[0]; +} + +void _vuISUBIU(VURegs * VU) { + if(_Ft_ == 0) return; + VU->VI[_Ft_].SS[0] = VU->VI[_Fs_].SS[0] - (((VU->code >> 10) & 0x7800) | (VU->code & 0x7ff)); +} + +void _vuMOVE(VURegs * VU) { + if(_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].UL[0] = VU->VF[_Fs_].UL[0]; + if (_Y) VU->VF[_Ft_].UL[1] = VU->VF[_Fs_].UL[1]; + if (_Z) VU->VF[_Ft_].UL[2] = VU->VF[_Fs_].UL[2]; + if (_W) VU->VF[_Ft_].UL[3] = VU->VF[_Fs_].UL[3]; +}//last checked 17/05/03 shadow + +void _vuMFIR(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].SL[0] = (s32)VU->VI[_Fs_].SS[0]; + if (_Y) VU->VF[_Ft_].SL[1] = (s32)VU->VI[_Fs_].SS[0]; + if (_Z) VU->VF[_Ft_].SL[2] = (s32)VU->VI[_Fs_].SS[0]; + if (_W) VU->VF[_Ft_].SL[3] = (s32)VU->VI[_Fs_].SS[0]; +} + +// Big bug!!! mov from fs to ft not ft to fs. asadr +void _vuMTIR(VURegs * VU) { + if(_Ft_ == 0) return; + VU->VI[_Ft_].US[0] = *(u16*)&VU->VF[_Fs_].F[_Fsf_]; +} + +void _vuMR32(VURegs * VU) { + u32 tx; + if (_Ft_ == 0) return; + + tx = VU->VF[_Fs_].i.x; + if (_X) VU->VF[_Ft_].i.x = VU->VF[_Fs_].i.y; + if (_Y) VU->VF[_Ft_].i.y = VU->VF[_Fs_].i.z; + if (_Z) VU->VF[_Ft_].i.z = VU->VF[_Fs_].i.w; + if (_W) VU->VF[_Ft_].i.w = tx; +}//last updated 23/10/03 linuzappz + +void _vuLQ(VURegs * VU) { + s16 imm; + u16 addr; + u32 *ptr; + + if (_Ft_ == 0) return; + + imm = (VU->code & 0x400) ? (VU->code & 0x3ff) | 0xfc00 : (VU->code & 0x3ff); + addr = (imm + VU->VI[_Fs_].SS[0]) * 16; + + ptr = (u32*)GET_VU_MEM(VU, addr); + if (_X) VU->VF[_Ft_].UL[0] = ptr[0]; + if (_Y) VU->VF[_Ft_].UL[1] = ptr[1]; + if (_Z) VU->VF[_Ft_].UL[2] = ptr[2]; + if (_W) VU->VF[_Ft_].UL[3] = ptr[3]; +} + +void _vuLQD( VURegs * VU ) { + u32 addr; + u32 *ptr; + + if (_Fs_ != 0) VU->VI[_Fs_].US[0]--; + if (_Ft_ == 0) return; + + addr = VU->VI[_Fs_].US[0] * 16; + ptr = (u32*)GET_VU_MEM(VU, addr); + if (_X) VU->VF[_Ft_].UL[0] = ptr[0]; + if (_Y) VU->VF[_Ft_].UL[1] = ptr[1]; + if (_Z) VU->VF[_Ft_].UL[2] = ptr[2]; + if (_W) VU->VF[_Ft_].UL[3] = ptr[3]; +} + +void _vuLQI(VURegs * VU) { + if (_Ft_) { + u32 addr; + u32 *ptr; + + addr = VU->VI[_Fs_].US[0] * 16; + ptr = (u32*)GET_VU_MEM(VU, addr); + if (_X) VU->VF[_Ft_].UL[0] = ptr[0]; + if (_Y) VU->VF[_Ft_].UL[1] = ptr[1]; + if (_Z) VU->VF[_Ft_].UL[2] = ptr[2]; + if (_W) VU->VF[_Ft_].UL[3] = ptr[3]; + } + if (_Fs_ != 0) VU->VI[_Fs_].US[0]++; +} + +/* addr is now signed. Asadr */ +void _vuSQ(VURegs * VU) { + s16 imm; + u16 addr; + u32 *ptr; + + imm = (VU->code & 0x400) ? (VU->code & 0x3ff) | 0xfc00 : (VU->code & 0x3ff); + addr = (imm + VU->VI[_Ft_].SS[0]) * 16; + ptr = (u32*)GET_VU_MEM(VU, addr); + if (_X) ptr[0] = VU->VF[_Fs_].UL[0]; + if (_Y) ptr[1] = VU->VF[_Fs_].UL[1]; + if (_Z) ptr[2] = VU->VF[_Fs_].UL[2]; + if (_W) ptr[3] = VU->VF[_Fs_].UL[3]; +} + +void _vuSQD(VURegs * VU) { + u32 addr; + u32 *ptr; + + if(_Ft_ != 0) VU->VI[_Ft_].US[0]--; + addr = VU->VI[_Ft_].US[0] * 16; + ptr = (u32*)GET_VU_MEM(VU, addr); + if (_X) ptr[0] = VU->VF[_Fs_].UL[0]; + if (_Y) ptr[1] = VU->VF[_Fs_].UL[1]; + if (_Z) ptr[2] = VU->VF[_Fs_].UL[2]; + if (_W) ptr[3] = VU->VF[_Fs_].UL[3]; +} + +void _vuSQI(VURegs * VU) { + u32 addr; + u32 *ptr; + + addr = VU->VI[_Ft_].US[0] * 16; + ptr = (u32*)GET_VU_MEM(VU, addr); + if (_X) ptr[0] = VU->VF[_Fs_].UL[0]; + if (_Y) ptr[1] = VU->VF[_Fs_].UL[1]; + if (_Z) ptr[2] = VU->VF[_Fs_].UL[2]; + if (_W) ptr[3] = VU->VF[_Fs_].UL[3]; + if(_Ft_ != 0) VU->VI[_Ft_].US[0]++; +} + +/* addr now signed. asadr */ +void _vuILW(VURegs * VU) { + s16 imm; + u16 addr; + u16 *ptr; + if (_Ft_ == 0) return; + + imm = (VU->code & 0x400) ? (VU->code & 0x3ff) | 0xfc00 : (VU->code & 0x3ff); + addr = (imm + VU->VI[_Fs_].SS[0]) * 16; + ptr = (u16*)GET_VU_MEM(VU, addr); + if (_X) VU->VI[_Ft_].US[0] = ptr[0]; + if (_Y) VU->VI[_Ft_].US[0] = ptr[2]; + if (_Z) VU->VI[_Ft_].US[0] = ptr[4]; + if (_W) VU->VI[_Ft_].US[0] = ptr[6]; +} + +void _vuISW(VURegs * VU) { + s16 imm; + u16 addr; + u16 *ptr; + + imm = (VU->code & 0x400) ? (VU->code & 0x3ff) | 0xfc00 : (VU->code & 0x3ff); + addr = (imm + VU->VI[_Fs_].SS[0]) * 16; + ptr = (u16*)GET_VU_MEM(VU, addr); + if (_X) { ptr[0] = VU->VI[_Ft_].US[0]; ptr[1] = 0; } + if (_Y) { ptr[2] = VU->VI[_Ft_].US[0]; ptr[3] = 0; } + if (_Z) { ptr[4] = VU->VI[_Ft_].US[0]; ptr[5] = 0; } + if (_W) { ptr[6] = VU->VI[_Ft_].US[0]; ptr[7] = 0; } +} + +void _vuILWR(VURegs * VU) { + u32 addr; + u16 *ptr; + if (_Ft_ == 0) return; + + addr = VU->VI[_Fs_].US[0] * 16; + ptr = (u16*)GET_VU_MEM(VU, addr); + if (_X) VU->VI[_Ft_].US[0] = ptr[0]; + if (_Y) VU->VI[_Ft_].US[0] = ptr[2]; + if (_Z) VU->VI[_Ft_].US[0] = ptr[4]; + if (_W) VU->VI[_Ft_].US[0] = ptr[6]; +} + +void _vuISWR(VURegs * VU) { + u32 addr; + u16 *ptr; + + addr = VU->VI[_Fs_].US[0] * 16; + ptr = (u16*)GET_VU_MEM(VU, addr); + if (_X) { ptr[0] = VU->VI[_Ft_].US[0]; ptr[1] = 0; } + if (_Y) { ptr[2] = VU->VI[_Ft_].US[0]; ptr[3] = 0; } + if (_Z) { ptr[4] = VU->VI[_Ft_].US[0]; ptr[5] = 0; } + if (_W) { ptr[6] = VU->VI[_Ft_].US[0]; ptr[7] = 0; } +} + +/* code contributed by _Riff_ + +The following code implements a Galois form M-series LFSR that can be configured to have a width from 0 to 32. +A Galois field can be represented as G(X) = g_m * X^m + g_(m-1) * X^(m-1) + ... + g_1 * X^1 + g0. +A Galois form M-Series LFSR represents a Galois field where g0 = g_m = 1 and the generated set contains 2^M - 1 values. +In modulo-2 arithmetic, addition is replaced by XOR and multiplication is replaced by AND. +The code is written in such a way that the polynomial lsb (g0) should be set to 0 and g_m is not represented. +As an example for setting the polynomial variable correctly, the 23-bit M-series generating polynomial X^23+X^14 + would be specified as (1 << 14). +*/ + + +//The two-tap 23 stage M-series polynomials are x23+x18 and x23+x14 ((1 << 18) and (1 << 14), respectively). +//The reverse sequences can be generated by x23+x(23-18) and x23+x(23-14) ((1 << 9) and (1 << 5), respectively) +u32 poly = 1 << 5; + +void SetPoly(u32 newPoly) { + poly = poly & ~1; +} + +void AdvanceLFSR(VURegs * VU) { + // code from www.project-fao.org + int x = (VU->VI[REG_R].UL >> 4) & 1; + int y = (VU->VI[REG_R].UL >> 22) & 1; + VU->VI[REG_R].UL <<= 1; + VU->VI[REG_R].UL ^= x ^ y; + VU->VI[REG_R].UL = (VU->VI[REG_R].UL&0x7fffff)|0x3f800000; +} +// old +// u32 lfsr = VU->VI[REG_R].UL & 0x007FFFFF; +// u32 oldlfsr = lfsr; +// lfsr <<= 1; +// if (oldlfsr & 0x00400000) { +// lfsr ^= poly; +// lfsr |= 1; +// } +// +// VU->VI[REG_R].UL = 0x3F800000 | (lfsr & 0x007FFFFF); + +void _vuRINIT(VURegs * VU) { + VU->VI[REG_R].UL = 0x3F800000 | (VU->VF[_Fs_].UL[_Fsf_] & 0x007FFFFF); +} + +void _vuRGET(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].UL[0] = VU->VI[REG_R].UL; + if (_Y) VU->VF[_Ft_].UL[1] = VU->VI[REG_R].UL; + if (_Z) VU->VF[_Ft_].UL[2] = VU->VI[REG_R].UL; + if (_W) VU->VF[_Ft_].UL[3] = VU->VI[REG_R].UL; +} + +void _vuRNEXT(VURegs * VU) { + if (_Ft_ == 0) return; + AdvanceLFSR(VU); + if (_X) VU->VF[_Ft_].UL[0] = VU->VI[REG_R].UL; + if (_Y) VU->VF[_Ft_].UL[1] = VU->VI[REG_R].UL; + if (_Z) VU->VF[_Ft_].UL[2] = VU->VI[REG_R].UL; + if (_W) VU->VF[_Ft_].UL[3] = VU->VI[REG_R].UL; +} + +void _vuRXOR(VURegs * VU) { + VU->VI[REG_R].UL = 0x3F800000 | ((VU->VI[REG_R].UL ^ VU->VF[_Fs_].UL[_Fsf_]) & 0x007FFFFF); +} + +void _vuWAITQ(VURegs * VU) { +} + +void _vuFSAND(VURegs * VU) { + u16 imm; + imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7ff); + if(_Ft_ == 0) return; + VU->VI[_Ft_].US[0] = (VU->VI[REG_STATUS_FLAG].US[0] & 0xFFF) & imm; +} + +void _vuFSEQ(VURegs * VU) { + u16 imm; + imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7ff); + if(_Ft_ == 0) return; + if((VU->VI[REG_STATUS_FLAG].US[0] & 0xFFF) == imm) VU->VI[_Ft_].US[0] = 1; + else VU->VI[_Ft_].US[0] = 0; +} + +void _vuFSOR(VURegs * VU) { + u16 imm; + imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7ff); + if(_Ft_ == 0) return; + VU->VI[_Ft_].US[0] = (VU->VI[REG_STATUS_FLAG].US[0] & 0xFFF) | imm; +} + +void _vuFSSET(VURegs * VU) { + u16 imm = 0; + imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7FF); + VU->statusflag = (imm & 0xFC0) | (VU->VI[REG_STATUS_FLAG].US[0] & 0x3F); +} + +void _vuFMAND(VURegs * VU) { + if(_Ft_ == 0) return; + VU->VI[_Ft_].US[0] = VU->VI[_Fs_].US[0] & (VU->VI[REG_MAC_FLAG].UL & 0xFFFF); +} + +void _vuFMEQ(VURegs * VU) { + if(_Ft_ == 0) return; + if((VU->VI[REG_MAC_FLAG].UL & 0xFFFF) == VU->VI[_Fs_].US[0]){ + VU->VI[_Ft_].US[0] =1;} else { VU->VI[_Ft_].US[0] =0; } +} + +void _vuFMOR(VURegs * VU) { + if(_Ft_ == 0) return; + VU->VI[_Ft_].US[0] = (VU->VI[REG_MAC_FLAG].UL & 0xFFFF) | VU->VI[_Fs_].US[0]; +} + +void _vuFCAND(VURegs * VU) { + if((VU->VI[REG_CLIP_FLAG].UL & 0xFFFFFF) & (VU->code & 0xFFFFFF)) VU->VI[1].US[0] = 1; + else VU->VI[1].US[0] = 0; +} + +void _vuFCEQ(VURegs * VU) { + if((VU->VI[REG_CLIP_FLAG].UL & 0xFFFFFF) == (VU->code & 0xFFFFFF)) VU->VI[1].US[0] = 1; + else VU->VI[1].US[0] = 0; +} + +void _vuFCOR(VURegs * VU) { + u32 hold = (VU->VI[REG_CLIP_FLAG].UL & 0xFFFFFF) | ( VU->code & 0xFFFFFF); + if(hold == 0xFFFFFF) VU->VI[1].US[0] = 1; + else VU->VI[1].US[0] = 0; +} + +void _vuFCSET(VURegs * VU) { + VU->clipflag = (u32) (VU->code & 0xFFFFFF); + VU->VI[REG_CLIP_FLAG].UL = (u32) (VU->code & 0xFFFFFF); +} + +void _vuFCGET(VURegs * VU) { + if(_Ft_ == 0) return; + VU->VI[_Ft_].US[0] = VU->VI[REG_CLIP_FLAG].UL & 0x0FFF; +} + +s32 _branchAddr(VURegs * VU) { + s32 bpc = VU->VI[REG_TPC].SL + ( _Imm11_ * 8 ); + //if (bpc < 0) bpc = VU->VI[REG_TPC].SL + _UImm11_ * 8; + bpc&= (VU == &VU1) ? 0x3fff : 0x0fff; + return bpc; +} + +void _setBranch(VURegs * VU, u32 bpc) { + VU->branch = 2; + VU->branchpc = bpc; +// VU->vuExec(VU); +// VU->VI[REG_TPC].UL = bpc; +} + +void _vuIBEQ(VURegs * VU) { + if (VU->VI[_Ft_].US[0] == VU->VI[_Fs_].US[0]) { + s32 bpc = _branchAddr(VU); + _setBranch(VU, bpc); + } +} + +void _vuIBGEZ(VURegs * VU) { + if (VU->VI[_Fs_].SS[0] >= 0) { + s32 bpc = _branchAddr(VU); + _setBranch(VU, bpc); + } +} + +void _vuIBGTZ(VURegs * VU) { + if (VU->VI[_Fs_].SS[0] > 0) { + s32 bpc = _branchAddr(VU); + _setBranch(VU, bpc); + } +} + +void _vuIBLEZ(VURegs * VU) { + if (VU->VI[_Fs_].SS[0] <= 0) { + s32 bpc = _branchAddr(VU); + _setBranch(VU, bpc); + } +} + +void _vuIBLTZ(VURegs * VU) { + if (VU->VI[_Fs_].SS[0] < 0) { + s32 bpc = _branchAddr(VU); + _setBranch(VU, bpc); + } +} + +void _vuIBNE(VURegs * VU) { + if (VU->VI[_Ft_].US[0] != VU->VI[_Fs_].US[0]) { + s32 bpc = _branchAddr(VU); + _setBranch(VU, bpc); + } +} + +void _vuB(VURegs * VU) { + s32 bpc = _branchAddr(VU); + _setBranch(VU, bpc); +} + +void _vuBAL(VURegs * VU) { + s32 bpc = _branchAddr(VU); + + if (_Ft_) { + VU->VI[_Ft_].US[0] = (VU->VI[REG_TPC].UL + 8)/8; + } + + _setBranch(VU, bpc); +} + +void _vuJR(VURegs * VU) { + u32 bpc = VU->VI[_Fs_].US[0] * 8; + _setBranch(VU, bpc); +} + +void _vuJALR(VURegs * VU) { + u32 bpc = VU->VI[_Fs_].US[0] * 8; + if (_Ft_) { + VU->VI[_Ft_].US[0] = (VU->VI[REG_TPC].UL + 8)/8; + } + + _setBranch(VU, bpc); +} + +void _vuMFP(VURegs * VU) { + if (_Ft_ == 0) return; + + if (_X) VU->VF[_Ft_].i.x = VU->VI[REG_P].UL; + if (_Y) VU->VF[_Ft_].i.y = VU->VI[REG_P].UL; + if (_Z) VU->VF[_Ft_].i.z = VU->VI[REG_P].UL; + if (_W) VU->VF[_Ft_].i.w = VU->VI[REG_P].UL; +} + +void _vuWAITP(VURegs * VU) { +} + +void _vuESADD(VURegs * VU) { + float p = vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Fs_].i.z); + VU->p.F = p; +} + +void _vuERSADD(VURegs * VU) { + float p = (vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Fs_].i.x)) + (vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Fs_].i.y)) + (vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Fs_].i.z)); + if (p != 0.0) + p = 1.0f / p; + VU->p.F = p; +} + +/* Fixed. Could have caused crash due to value being -ve for sqrt *asadr */ +void _vuELENG(VURegs * VU) { + float p = vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Fs_].i.z); + if(p >= 0){ + p = sqrt(p); + } + VU->p.F = p; +} + +/* Fixed. Could have caused crash due to divisor being = 0 *asadr */ +void _vuERLENG(VURegs * VU) { + float p = vuDouble(VU->VF[_Fs_].i.x) * vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VF[_Fs_].i.y) * vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VF[_Fs_].i.z) * vuDouble(VU->VF[_Fs_].i.z); + if (p >= 0) { + p = sqrt(p); + if (p != 0) { + p = 1.0f / p; + } + } + VU->p.F = p; +} + +/* Fixed. Could have caused crash due to divisor being = 0 *asadr */ +void _vuEATANxy(VURegs * VU) { + float p = 0; + if(vuDouble(VU->VF[_Fs_].i.x) != 0) { + p = atan2(vuDouble(VU->VF[_Fs_].i.y), vuDouble(VU->VF[_Fs_].i.x)); + } + VU->p.F = p; +} + +/* Fixed. Could have caused crash due to divisor being = 0 *asadr */ +void _vuEATANxz(VURegs * VU) { + float p = 0; + if(vuDouble(VU->VF[_Fs_].i.x) != 0) { + p = atan2(vuDouble(VU->VF[_Fs_].i.z), vuDouble(VU->VF[_Fs_].i.x)); + } + VU->p.F = p; +} + +void _vuESUM(VURegs * VU) { + float p = vuDouble(VU->VF[_Fs_].i.x) + vuDouble(VU->VF[_Fs_].i.y) + vuDouble(VU->VF[_Fs_].i.z) + vuDouble(VU->VF[_Fs_].i.w); + VU->p.F = p; +} + +/* Fixed. Could have caused crash due to divisor being = 0 *asadr */ +void _vuERCPR(VURegs * VU) { + float p = vuDouble(VU->VF[_Fs_].UL[_Fsf_]); + if (p != 0){ + p = 1.0 / p; + } + VU->p.F = p; +} + +/* Fixed. Could have caused crash due to Value being -ve for sqrt *asadr */ +void _vuESQRT(VURegs * VU) { + float p = vuDouble(VU->VF[_Fs_].UL[_Fsf_]); + if (p >= 0){ + p = sqrt(p); + } + VU->p.F = p; +} + +/* Fixed. Could have caused crash due to divisor being = 0 *asadr */ +void _vuERSQRT(VURegs * VU) { + float p = vuDouble(VU->VF[_Fs_].UL[_Fsf_]); + if (p >= 0) { + p = sqrt(p); + if (p) { + p = 1.0f / p; + } + } + VU->p.F = p; +} + +void _vuESIN(VURegs * VU) { + float p = sin(vuDouble(VU->VF[_Fs_].UL[_Fsf_])); + VU->p.F = p; +} + +void _vuEATAN(VURegs * VU) { + float p = atan(vuDouble(VU->VF[_Fs_].UL[_Fsf_])); + VU->p.F = p; +} + +void _vuEEXP(VURegs * VU) { + float p = exp(-(vuDouble(VU->VF[_Fs_].UL[_Fsf_]))); + VU->p.F = p; +} + +void _vuXITOP(VURegs * VU) { + if (_Ft_ == 0) return; + VU->VI[_Ft_].US[0] = VU->vifRegs->itop; +} + +void _vuXGKICK(VURegs * VU) +{ + // flush all pipelines first (in the right order) + _vuFlushAll(VU); + GSGIFTRANSFER1((u32*)VU->Mem, (VU->VI[_Fs_].US[0]*16) & 0x3fff); +} + +void _vuXTOP(VURegs * VU) { + if(_Ft_ == 0) return; + VU->VI[_Ft_].US[0] = (u16)VU->vifRegs->top; +} + +#define GET_VF0_FLAG(reg) (((reg)==0)?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = _Fd_; \ + VUregsn->VFwxyzw = _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = 0; \ + VUregsn->VIwrite = 0; \ + VUregsn->VIread = (1 << REG_I)|(ACC?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = _Fd_; \ + VUregsn->VFwxyzw = _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = 0; \ + VUregsn->VIwrite = 0; \ + VUregsn->VIread = (1 << REG_Q)|(ACC?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = _Fd_; \ + VUregsn->VFwxyzw = _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = _Ft_; \ + VUregsn->VFr1xyzw= _XYZW; \ + VUregsn->VIwrite = 0; \ + VUregsn->VIread = (ACC?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = _Fd_; \ + VUregsn->VFwxyzw = _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = _Ft_; \ + VUregsn->VFr1xyzw= xyzw; \ + VUregsn->VIwrite = 0; \ + VUregsn->VIread = (ACC?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = 0; \ + VUregsn->VFwxyzw= _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = 0; \ + VUregsn->VIwrite = (1<VIread = (1 << REG_I)|GET_VF0_FLAG(_Fs_)|((readacc||_XYZW!=15)?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = 0; \ + VUregsn->VFwxyzw= _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = 0; \ + VUregsn->VIwrite = (1<VIread = (1 << REG_Q)|GET_VF0_FLAG(_Fs_)|((readacc||_XYZW!=15)?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = 0; \ + VUregsn->VFwxyzw= _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = _Ft_; \ + VUregsn->VFr1xyzw= _XYZW; \ + VUregsn->VIwrite = (1<VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_)|((readacc||_XYZW!=15)?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = 0; \ + VUregsn->VFwxyzw= _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = _Ft_; \ + VUregsn->VFr1xyzw= xyzw; \ + VUregsn->VIwrite = (1<VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_)|((readacc||_XYZW!=15)?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = _Ft_; \ + VUregsn->VFwxyzw = _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = 0; \ + VUregsn->VFr1xyzw = 0xff; \ + VUregsn->VIwrite = 0; \ + VUregsn->VIread = (_Ft_ ? GET_VF0_FLAG(_Fs_) : 0); \ +} + +#define VUREGS_IDISIT(OP) \ +void _vuRegs##OP(VURegs * VU, _VURegsNum *VUregsn) { \ + VUregsn->pipe = VUPIPE_IALU; \ + VUregsn->VFwrite = 0; \ + VUregsn->VFread0 = 0; \ + VUregsn->VFread1 = 0; \ + VUregsn->VIwrite = 1 << _Fd_; \ + VUregsn->VIread = (1 << _Fs_) | (1 << _Ft_); \ +} + +#define VUREGS_ITIS(OP) \ +void _vuRegs##OP(VURegs * VU, _VURegsNum *VUregsn) { \ + VUregsn->pipe = VUPIPE_IALU; \ + VUregsn->VFwrite = 0; \ + VUregsn->VFread0 = 0; \ + VUregsn->VFread1 = 0; \ + VUregsn->VIwrite = 1 << _Ft_; \ + VUregsn->VIread = 1 << _Fs_; \ +} + +#define VUREGS_PFS(OP, _cycles) \ +void _vuRegs##OP(VURegs * VU, _VURegsNum *VUregsn) { \ + VUregsn->pipe = VUPIPE_EFU; \ + VUregsn->VFwrite = 0; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = 0; \ + VUregsn->VIwrite = 1 << REG_P; \ + VUregsn->VIread = GET_VF0_FLAG(_Fs_); \ + VUregsn->cycles = _cycles; \ +} + + + +VUREGS_FTFS(ABS); + +VUREGS_FDFSFT(ADD, 0); +VUREGS_FDFSI(ADDi, 0); +VUREGS_FDFSQ(ADDq, 0); +VUREGS_FDFSFTx(ADDx, 0); +VUREGS_FDFSFTy(ADDy, 0); +VUREGS_FDFSFTz(ADDz, 0); +VUREGS_FDFSFTw(ADDw, 0); + +VUREGS_ACCFSFT(ADDA, 0); +VUREGS_ACCFSI(ADDAi, 0); +VUREGS_ACCFSQ(ADDAq, 0); +VUREGS_ACCFSFTx(ADDAx, 0); +VUREGS_ACCFSFTy(ADDAy, 0); +VUREGS_ACCFSFTz(ADDAz, 0); +VUREGS_ACCFSFTw(ADDAw, 0); + +VUREGS_FDFSFT(SUB, 0); +VUREGS_FDFSI(SUBi, 0); +VUREGS_FDFSQ(SUBq, 0); +VUREGS_FDFSFTx(SUBx, 0); +VUREGS_FDFSFTy(SUBy, 0); +VUREGS_FDFSFTz(SUBz, 0); +VUREGS_FDFSFTw(SUBw, 0); + +VUREGS_ACCFSFT(SUBA, 0); +VUREGS_ACCFSI(SUBAi, 0); +VUREGS_ACCFSQ(SUBAq, 0); +VUREGS_ACCFSFTx(SUBAx, 0); +VUREGS_ACCFSFTy(SUBAy, 0); +VUREGS_ACCFSFTz(SUBAz, 0); +VUREGS_ACCFSFTw(SUBAw, 0); + +#define VUREGS_FDFSFTxyzw_MUL(OP, ACC, xyzw) \ +void _vuRegs##OP(VURegs * VU, _VURegsNum *VUregsn) { \ + if( _Ft_ == 0 && xyzw > 1 && _XYZW == 0xf ) { /* resetting to 0 */ \ + VUregsn->pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = ACC?0:_Fd_; \ + VUregsn->VFwxyzw = _XYZW; \ + VUregsn->VFread0 = 0; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = 0; \ + VUregsn->VFr1xyzw= xyzw; \ + VUregsn->VIwrite = (ACC?(1<VIread = (ACC&&(_XYZW!=15))?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = ACC?0:_Fd_; \ + VUregsn->VFwxyzw = _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = _Ft_; \ + VUregsn->VFr1xyzw= xyzw; \ + VUregsn->VIwrite = (ACC?(1<VIread = GET_VF0_FLAG(_Fs_)|((ACC&&(_XYZW!=15))?(1<pipe = VUPIPE_FMAC; \ + VUregsn->VFwrite = _Fd_; \ + VUregsn->VFwxyzw = _XYZW; \ + VUregsn->VFread0 = _Fs_; \ + VUregsn->VFr0xyzw= _XYZW; \ + VUregsn->VFread1 = _Ft_; \ + VUregsn->VFr1xyzw= xyzw; \ + VUregsn->VIwrite = 0; \ + VUregsn->VIread = (1<pipe = VUPIPE_FMAC; + VUregsn->VFwrite = _Fd_; + VUregsn->VFwxyzw = _XYZW; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= _XYZW; + VUregsn->VFread1 = _Ft_; + VUregsn->VFr1xyzw= 1; + VUregsn->VIwrite = 0; + VUregsn->VIread = (1<VIread &= ~(1<VIread &= ~(1<VIread &= ~(1<VIread &= ~(1<pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFwxyzw= 0xE; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= 0xE; + VUregsn->VFread1 = _Ft_; + VUregsn->VFr1xyzw= 0xE; + VUregsn->VIwrite = 1<VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_)|(1<pipe = VUPIPE_FMAC; + VUregsn->VFwrite = _Fd_; + VUregsn->VFwxyzw= 0xE; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= 0xE; + VUregsn->VFread1 = _Ft_; + VUregsn->VFr1xyzw= 0xE; + VUregsn->VIwrite = 0; + VUregsn->VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_)|(1<pipe = VUPIPE_NONE; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 0; +} + +VUREGS_FTFS(FTOI0); +VUREGS_FTFS(FTOI4); +VUREGS_FTFS(FTOI12); +VUREGS_FTFS(FTOI15); +VUREGS_FTFS(ITOF0); +VUREGS_FTFS(ITOF4); +VUREGS_FTFS(ITOF12); +VUREGS_FTFS(ITOF15); + +void _vuRegsCLIP(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= 0xE; + VUregsn->VFread1 = _Ft_; + VUregsn->VFr1xyzw= 0x1; + VUregsn->VIwrite = 1 << REG_CLIP_FLAG; + VUregsn->VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_)|(1 << REG_CLIP_FLAG); +} + +/******************************/ +/* VU Lower instructions */ +/******************************/ + +void _vuRegsDIV(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FDIV; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= 1 << (3-_Fsf_); + VUregsn->VFread1 = _Ft_; + VUregsn->VFr1xyzw= 1 << (3-_Ftf_); + VUregsn->VIwrite = 1 << REG_Q; + VUregsn->VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_); + VUregsn->cycles = 6; +} + +void _vuRegsSQRT(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FDIV; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFr0xyzw = 0; + VUregsn->VFread1 = _Ft_; + VUregsn->VFr1xyzw = 1 << (3-_Ftf_); + VUregsn->VIwrite = 1 << REG_Q; + VUregsn->VIread = GET_VF0_FLAG(_Ft_); + VUregsn->cycles = 6; +} + +void _vuRegsRSQRT(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FDIV; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= 1 << (3-_Fsf_); + VUregsn->VFread1 = _Ft_; + VUregsn->VFr1xyzw= 1 << (3-_Ftf_); + VUregsn->VIwrite = 1 << REG_Q; + VUregsn->VIread = GET_VF0_FLAG(_Fs_)|GET_VF0_FLAG(_Ft_); + VUregsn->cycles = 12; +} + +VUREGS_ITIS(IADDI); +VUREGS_ITIS(IADDIU); +VUREGS_IDISIT(IADD); +VUREGS_IDISIT(IAND); +VUREGS_IDISIT(IOR); +VUREGS_IDISIT(ISUB); +VUREGS_ITIS(ISUBIU); + +VUREGS_FTFS(MOVE); + +void _vuRegsMFIR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = _Ft_; + VUregsn->VFwxyzw = _XYZW; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsMTIR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= _XYZW; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = GET_VF0_FLAG(_Fs_); +} + +VUREGS_FTFS(MR32); + +void _vuRegsLQ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = _Ft_; + VUregsn->VFwxyzw = _XYZW; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsLQD(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = _Ft_; + VUregsn->VFwxyzw = _XYZW; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Fs_; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsLQI(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = _Ft_; + VUregsn->VFwxyzw = _XYZW; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Fs_; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsSQ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= _XYZW; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = (1 << _Ft_)|GET_VF0_FLAG(_Fs_); +} + +void _vuRegsSQD(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= _XYZW; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = (1 << _Ft_)|GET_VF0_FLAG(_Fs_); +} + +void _vuRegsSQI(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= _XYZW; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = (1 << _Ft_)|GET_VF0_FLAG(_Fs_); +} + +void _vuRegsILW(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_IALU; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsISW(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_IALU; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = (1 << _Fs_) | (1 << _Ft_); +} + +void _vuRegsILWR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_IALU; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = (1 << _Ft_); + VUregsn->VIread = (1 << _Fs_); +} + +void _vuRegsISWR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_IALU; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = (1 << _Fs_) | (1 << _Ft_); +} + +void _vuRegsRINIT(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= 1 << (3-_Fsf_); + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << REG_R; + VUregsn->VIread = GET_VF0_FLAG(_Fs_); +} + +void _vuRegsRGET(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = _Ft_; + VUregsn->VFwxyzw = _XYZW; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << REG_R; +} + +void _vuRegsRNEXT(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = _Ft_; + VUregsn->VFwxyzw = _XYZW; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << REG_R; + VUregsn->VIread = 1 << REG_R; +} + +void _vuRegsRXOR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= 1 << (3-_Fsf_); + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << REG_R; + VUregsn->VIread = (1 << REG_R)|GET_VF0_FLAG(_Fs_); +} + +void _vuRegsWAITQ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FDIV; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 0; +} + +void _vuRegsFSAND(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = 1 << REG_STATUS_FLAG; +} + +void _vuRegsFSEQ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = 1 << REG_STATUS_FLAG; +} + +void _vuRegsFSOR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = 1 << REG_STATUS_FLAG; +} + +void _vuRegsFSSET(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << REG_STATUS_FLAG; + VUregsn->VIread = 0;//1 << REG_STATUS_FLAG; this kills speed +} + +void _vuRegsFMAND(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = (1 << REG_MAC_FLAG) | (1 << _Fs_); +} + +void _vuRegsFMEQ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = (1 << REG_MAC_FLAG) | (1 << _Fs_); +} + +void _vuRegsFMOR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = (1 << REG_MAC_FLAG) | (1 << _Fs_); +} + +void _vuRegsFCAND(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << 1; + VUregsn->VIread = 1 << REG_CLIP_FLAG; +} + +void _vuRegsFCEQ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << 1; + VUregsn->VIread = 1 << REG_CLIP_FLAG; +} + +void _vuRegsFCOR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << 1; + VUregsn->VIread = 1 << REG_CLIP_FLAG; +} + +void _vuRegsFCSET(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << REG_CLIP_FLAG; + VUregsn->VIread = 0; +} + +void _vuRegsFCGET(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = 1 << REG_CLIP_FLAG; +} + +void _vuRegsIBEQ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = (1 << _Fs_) | (1 << _Ft_); +} + +void _vuRegsIBGEZ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsIBGTZ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsIBLEZ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsIBLTZ(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsIBNE(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = (1 << _Fs_) | (1 << _Ft_); +} + +void _vuRegsB(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 0; +} + +void _vuRegsBAL(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = 0; +} + +void _vuRegsJR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsJALR(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_BRANCH; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsMFP(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_FMAC; + VUregsn->VFwrite = _Ft_; + VUregsn->VFwxyzw = _XYZW; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << REG_P; +} + +void _vuRegsWAITP(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_EFU; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 0; +} + +VUREGS_PFS(ESADD, 10); +VUREGS_PFS(ERSADD, 17); +VUREGS_PFS(ELENG, 17); +VUREGS_PFS(ERLENG, 23); +VUREGS_PFS(EATANxy, 53); +VUREGS_PFS(EATANxz, 53); +VUREGS_PFS(ESUM, 11); +VUREGS_PFS(ERCPR, 11); +VUREGS_PFS(ESQRT, 11); +VUREGS_PFS(ERSQRT, 17); +VUREGS_PFS(ESIN, 28); +VUREGS_PFS(EATAN, 53); +VUREGS_PFS(EEXP, 43); + +void _vuRegsXITOP(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_IALU; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = 0; +} + +void _vuRegsXGKICK(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_XGKICK; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 0; + VUregsn->VIread = 1 << _Fs_; +} + +void _vuRegsXTOP(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->pipe = VUPIPE_IALU; + VUregsn->VFwrite = 0; + VUregsn->VFread0 = 0; + VUregsn->VFread1 = 0; + VUregsn->VIwrite = 1 << _Ft_; + VUregsn->VIread = 0; +} diff --git a/pcsx2/VUops.h b/pcsx2/VUops.h index 748ccbc38c..6217a6c69d 100644 --- a/pcsx2/VUops.h +++ b/pcsx2/VUops.h @@ -1,399 +1,399 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __VU1OPS_H__ -#define __VU1OPS_H__ - -#include "VU.h" - -extern __forceinline u32 VU_MAC_UPDATE( int shift, VURegs * VU, float f); -extern __forceinline u32 VU_MACx_UPDATE(VURegs * VU, float x); -extern __forceinline u32 VU_MACy_UPDATE(VURegs * VU, float y); -extern __forceinline u32 VU_MACz_UPDATE(VURegs * VU, float z); -extern __forceinline u32 VU_MACw_UPDATE(VURegs * VU, float w); -extern __forceinline void VU_MACx_CLEAR(VURegs * VU); -extern __forceinline void VU_MACy_CLEAR(VURegs * VU); -extern __forceinline void VU_MACz_CLEAR(VURegs * VU); -extern __forceinline void VU_MACw_CLEAR(VURegs * VU); - -#define float_to_int4(x) (s32)((float)x * (1.0f / 0.0625f)) -#define float_to_int12(x) (s32)((float)x * (1.0f / 0.000244140625f)) -#define float_to_int15(x) (s32)((float)x * (1.0f / 0.000030517578125)) - -#define int4_to_float(x) (float)((float)x * 0.0625f) -#define int12_to_float(x) (float)((float)x * 0.000244140625f) -#define int15_to_float(x) (float)((float)x * 0.000030517578125) - -#define MAC_Reset( VU ) VU->VI[REG_MAC_FLAG].UL = VU->VI[REG_MAC_FLAG].UL & (~0xFFFF) - -void _vuSetCycleFlags(VURegs * VU); -void _vuFlushFDIV(VURegs * VU); -void _vuFlushEFU(VURegs * VU); -void _vuTestPipes(VURegs * VU); -void _vuTestUpperStalls(VURegs * VU, _VURegsNum *VUregsn); -void _vuTestLowerStalls(VURegs * VU, _VURegsNum *VUregsn); -void _vuAddUpperStalls(VURegs * VU, _VURegsNum *VUregsn); -void _vuAddLowerStalls(VURegs * VU, _VURegsNum *VUregsn); - -/******************************/ -/* VU Upper instructions */ -/******************************/ - -void _vuABS(VURegs * VU); -void _vuADD(VURegs * VU); -void _vuADDi(VURegs * VU); -void _vuADDq(VURegs * VU); -void _vuADDx(VURegs * VU); -void _vuADDy(VURegs * VU); -void _vuADDz(VURegs * VU); -void _vuADDw(VURegs * VU); -void _vuADDA(VURegs * VU); -void _vuADDAi(VURegs * VU); -void _vuADDAq(VURegs * VU); -void _vuADDAx(VURegs * VU); -void _vuADDAy(VURegs * VU); -void _vuADDAz(VURegs * VU); -void _vuADDAw(VURegs * VU); -void _vuSUB(VURegs * VU); -void _vuSUBi(VURegs * VU); -void _vuSUBq(VURegs * VU); -void _vuSUBx(VURegs * VU); -void _vuSUBy(VURegs * VU); -void _vuSUBz(VURegs * VU); -void _vuSUBw(VURegs * VU); -void _vuSUBA(VURegs * VU); -void _vuSUBAi(VURegs * VU); -void _vuSUBAq(VURegs * VU); -void _vuSUBAx(VURegs * VU); -void _vuSUBAy(VURegs * VU); -void _vuSUBAz(VURegs * VU); -void _vuSUBAw(VURegs * VU); -void _vuMUL(VURegs * VU); -void _vuMULi(VURegs * VU); -void _vuMULq(VURegs * VU); -void _vuMULx(VURegs * VU); -void _vuMULy(VURegs * VU); -void _vuMULz(VURegs * VU); -void _vuMULw(VURegs * VU); -void _vuMULA(VURegs * VU); -void _vuMULAi(VURegs * VU); -void _vuMULAq(VURegs * VU); -void _vuMULAx(VURegs * VU); -void _vuMULAy(VURegs * VU); -void _vuMULAz(VURegs * VU); -void _vuMULAw(VURegs * VU); -void _vuMADD(VURegs * VU) ; -void _vuMADDi(VURegs * VU); -void _vuMADDq(VURegs * VU); -void _vuMADDx(VURegs * VU); -void _vuMADDy(VURegs * VU); -void _vuMADDz(VURegs * VU); -void _vuMADDw(VURegs * VU); -void _vuMADDA(VURegs * VU); -void _vuMADDAi(VURegs * VU); -void _vuMADDAq(VURegs * VU); -void _vuMADDAx(VURegs * VU); -void _vuMADDAy(VURegs * VU); -void _vuMADDAz(VURegs * VU); -void _vuMADDAw(VURegs * VU); -void _vuMSUB(VURegs * VU); -void _vuMSUBi(VURegs * VU); -void _vuMSUBq(VURegs * VU); -void _vuMSUBx(VURegs * VU); -void _vuMSUBy(VURegs * VU); -void _vuMSUBz(VURegs * VU) ; -void _vuMSUBw(VURegs * VU) ; -void _vuMSUBA(VURegs * VU); -void _vuMSUBAi(VURegs * VU); -void _vuMSUBAq(VURegs * VU); -void _vuMSUBAx(VURegs * VU); -void _vuMSUBAy(VURegs * VU); -void _vuMSUBAz(VURegs * VU); -void _vuMSUBAw(VURegs * VU); -void _vuMAX(VURegs * VU); -void _vuMAXi(VURegs * VU); -void _vuMAXx(VURegs * VU); -void _vuMAXy(VURegs * VU); -void _vuMAXz(VURegs * VU); -void _vuMAXw(VURegs * VU); -void _vuMINI(VURegs * VU); -void _vuMINIi(VURegs * VU); -void _vuMINIx(VURegs * VU); -void _vuMINIy(VURegs * VU); -void _vuMINIz(VURegs * VU); -void _vuMINIw(VURegs * VU); -void _vuOPMULA(VURegs * VU); -void _vuOPMSUB(VURegs * VU); -void _vuNOP(VURegs * VU); -void _vuFTOI0(VURegs * VU); -void _vuFTOI4(VURegs * VU); -void _vuFTOI12(VURegs * VU); -void _vuFTOI15(VURegs * VU); -void _vuITOF0(VURegs * VU) ; -void _vuITOF4(VURegs * VU) ; -void _vuITOF12(VURegs * VU); -void _vuITOF15(VURegs * VU); -void _vuCLIP(VURegs * VU); -/******************************/ -/* VU Lower instructions */ -/******************************/ -void _vuDIV(VURegs * VU); -void _vuSQRT(VURegs * VU); -void _vuRSQRT(VURegs * VU); -void _vuIADDI(VURegs * VU); -void _vuIADDIU(VURegs * VU); -void _vuIADD(VURegs * VU); -void _vuIAND(VURegs * VU); -void _vuIOR(VURegs * VU); -void _vuISUB(VURegs * VU); -void _vuISUBIU(VURegs * VU); -void _vuMOVE(VURegs * VU); -void _vuMFIR(VURegs * VU); -void _vuMTIR(VURegs * VU); -void _vuMR32(VURegs * VU); -void _vuLQ(VURegs * VU) ; -void _vuLQD(VURegs * VU); -void _vuLQI(VURegs * VU); -void _vuSQ(VURegs * VU); -void _vuSQD(VURegs * VU); -void _vuSQI(VURegs * VU); -void _vuILW(VURegs * VU); -void _vuISW(VURegs * VU); -void _vuILWR(VURegs * VU); -void _vuISWR(VURegs * VU); -void _vuLOI(VURegs * VU); -void _vuRINIT(VURegs * VU); -void _vuRGET(VURegs * VU); -void _vuRNEXT(VURegs * VU); -void _vuRXOR(VURegs * VU); -void _vuWAITQ(VURegs * VU); -void _vuFSAND(VURegs * VU); -void _vuFSEQ(VURegs * VU); -void _vuFSOR(VURegs * VU); -void _vuFSSET(VURegs * VU); -void _vuFMAND(VURegs * VU); -void _vuFMEQ(VURegs * VU); -void _vuFMOR(VURegs * VU); -void _vuFCAND(VURegs * VU); -void _vuFCEQ(VURegs * VU); -void _vuFCOR(VURegs * VU); -void _vuFCSET(VURegs * VU); -void _vuFCGET(VURegs * VU); -void _vuIBEQ(VURegs * VU); -void _vuIBGEZ(VURegs * VU); -void _vuIBGTZ(VURegs * VU); -void _vuIBLEZ(VURegs * VU); -void _vuIBLTZ(VURegs * VU); -void _vuIBNE(VURegs * VU); -void _vuB(VURegs * VU); -void _vuBAL(VURegs * VU); -void _vuJR(VURegs * VU); -void _vuJALR(VURegs * VU); -void _vuMFP(VURegs * VU); -void _vuWAITP(VURegs * VU); -void _vuESADD(VURegs * VU); -void _vuERSADD(VURegs * VU); -void _vuELENG(VURegs * VU); -void _vuERLENG(VURegs * VU); -void _vuEATANxy(VURegs * VU); -void _vuEATANxz(VURegs * VU); -void _vuESUM(VURegs * VU); -void _vuERCPR(VURegs * VU); -void _vuESQRT(VURegs * VU); -void _vuERSQRT(VURegs * VU); -void _vuESIN(VURegs * VU); -void _vuEATAN(VURegs * VU); -void _vuEEXP(VURegs * VU); -void _vuXITOP(VURegs * VU); -void _vuXGKICK(VURegs * VU); -void _vuXTOP(VURegs * VU); - -/******************************/ -/* VU Upper instructions */ -/******************************/ - -void _vuRegsABS(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsADD(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsADDi(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsADDq(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsADDx(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsADDy(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsADDz(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsADDw(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsADDA(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsADDAi(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsADDAq(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsADDAx(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsADDAy(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsADDAz(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsADDAw(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsSUB(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsSUBi(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsSUBq(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsSUBx(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsSUBy(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsSUBz(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsSUBw(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsSUBA(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsSUBAi(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsSUBAq(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsSUBAx(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsSUBAy(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsSUBAz(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsSUBAw(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMUL(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMULi(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMULq(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMULx(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMULy(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMULz(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMULw(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMULA(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMULAi(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMULAq(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMULAx(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMULAy(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMULAz(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMULAw(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMADD(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMADDi(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMADDq(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMADDx(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMADDy(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMADDz(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMADDw(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMADDA(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMADDAi(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMADDAq(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMADDAx(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMADDAy(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMADDAz(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMADDAw(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMSUB(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMSUBi(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMSUBq(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMSUBx(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMSUBy(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMSUBz(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMSUBw(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMSUBA(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMSUBAi(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMSUBAq(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMSUBAx(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMSUBAy(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMSUBAz(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMSUBAw(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMAX(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMAXi(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMAXx(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMAXy(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMAXz(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMAXw(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMINI(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMINIi(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMINIx(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMINIy(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMINIz(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMINIw(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsOPMULA(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsOPMSUB(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsNOP(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsFTOI0(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsFTOI4(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsFTOI12(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsFTOI15(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsITOF0(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsITOF4(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsITOF12(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsITOF15(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsCLIP(VURegs * VU, _VURegsNum *VUregsn); -/******************************/ -/* VU Lower instructions */ -/******************************/ -void _vuRegsDIV(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsSQRT(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsRSQRT(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsIADDI(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsIADDIU(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsIADD(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsIAND(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsIOR(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsISUB(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsISUBIU(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMOVE(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMFIR(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMTIR(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMR32(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsLQ(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsLQD(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsLQI(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsSQ(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsSQD(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsSQI(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsILW(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsISW(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsILWR(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsISWR(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsLOI(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsRINIT(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsRGET(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsRNEXT(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsRXOR(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsWAITQ(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsFSAND(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsFSEQ(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsFSOR(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsFSSET(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsFMAND(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsFMEQ(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsFMOR(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsFCAND(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsFCEQ(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsFCOR(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsFCSET(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsFCGET(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsIBEQ(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsIBGEZ(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsIBGTZ(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsIBLEZ(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsIBLTZ(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsIBNE(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsB(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsBAL(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsJR(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsJALR(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsMFP(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsWAITP(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsESADD(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsERSADD(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsELENG(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsERLENG(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsEATANxy(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsEATANxz(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsESUM(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsERCPR(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsESQRT(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsERSQRT(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsESIN(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsEATAN(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsEEXP(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsXITOP(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsXGKICK(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsXTOP(VURegs * VU, _VURegsNum *VUregsn); - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __VU1OPS_H__ +#define __VU1OPS_H__ + +#include "VU.h" + +extern __forceinline u32 VU_MAC_UPDATE( int shift, VURegs * VU, float f); +extern __forceinline u32 VU_MACx_UPDATE(VURegs * VU, float x); +extern __forceinline u32 VU_MACy_UPDATE(VURegs * VU, float y); +extern __forceinline u32 VU_MACz_UPDATE(VURegs * VU, float z); +extern __forceinline u32 VU_MACw_UPDATE(VURegs * VU, float w); +extern __forceinline void VU_MACx_CLEAR(VURegs * VU); +extern __forceinline void VU_MACy_CLEAR(VURegs * VU); +extern __forceinline void VU_MACz_CLEAR(VURegs * VU); +extern __forceinline void VU_MACw_CLEAR(VURegs * VU); + +#define float_to_int4(x) (s32)((float)x * (1.0f / 0.0625f)) +#define float_to_int12(x) (s32)((float)x * (1.0f / 0.000244140625f)) +#define float_to_int15(x) (s32)((float)x * (1.0f / 0.000030517578125)) + +#define int4_to_float(x) (float)((float)x * 0.0625f) +#define int12_to_float(x) (float)((float)x * 0.000244140625f) +#define int15_to_float(x) (float)((float)x * 0.000030517578125) + +#define MAC_Reset( VU ) VU->VI[REG_MAC_FLAG].UL = VU->VI[REG_MAC_FLAG].UL & (~0xFFFF) + +void _vuSetCycleFlags(VURegs * VU); +void _vuFlushFDIV(VURegs * VU); +void _vuFlushEFU(VURegs * VU); +void _vuTestPipes(VURegs * VU); +void _vuTestUpperStalls(VURegs * VU, _VURegsNum *VUregsn); +void _vuTestLowerStalls(VURegs * VU, _VURegsNum *VUregsn); +void _vuAddUpperStalls(VURegs * VU, _VURegsNum *VUregsn); +void _vuAddLowerStalls(VURegs * VU, _VURegsNum *VUregsn); + +/******************************/ +/* VU Upper instructions */ +/******************************/ + +void _vuABS(VURegs * VU); +void _vuADD(VURegs * VU); +void _vuADDi(VURegs * VU); +void _vuADDq(VURegs * VU); +void _vuADDx(VURegs * VU); +void _vuADDy(VURegs * VU); +void _vuADDz(VURegs * VU); +void _vuADDw(VURegs * VU); +void _vuADDA(VURegs * VU); +void _vuADDAi(VURegs * VU); +void _vuADDAq(VURegs * VU); +void _vuADDAx(VURegs * VU); +void _vuADDAy(VURegs * VU); +void _vuADDAz(VURegs * VU); +void _vuADDAw(VURegs * VU); +void _vuSUB(VURegs * VU); +void _vuSUBi(VURegs * VU); +void _vuSUBq(VURegs * VU); +void _vuSUBx(VURegs * VU); +void _vuSUBy(VURegs * VU); +void _vuSUBz(VURegs * VU); +void _vuSUBw(VURegs * VU); +void _vuSUBA(VURegs * VU); +void _vuSUBAi(VURegs * VU); +void _vuSUBAq(VURegs * VU); +void _vuSUBAx(VURegs * VU); +void _vuSUBAy(VURegs * VU); +void _vuSUBAz(VURegs * VU); +void _vuSUBAw(VURegs * VU); +void _vuMUL(VURegs * VU); +void _vuMULi(VURegs * VU); +void _vuMULq(VURegs * VU); +void _vuMULx(VURegs * VU); +void _vuMULy(VURegs * VU); +void _vuMULz(VURegs * VU); +void _vuMULw(VURegs * VU); +void _vuMULA(VURegs * VU); +void _vuMULAi(VURegs * VU); +void _vuMULAq(VURegs * VU); +void _vuMULAx(VURegs * VU); +void _vuMULAy(VURegs * VU); +void _vuMULAz(VURegs * VU); +void _vuMULAw(VURegs * VU); +void _vuMADD(VURegs * VU) ; +void _vuMADDi(VURegs * VU); +void _vuMADDq(VURegs * VU); +void _vuMADDx(VURegs * VU); +void _vuMADDy(VURegs * VU); +void _vuMADDz(VURegs * VU); +void _vuMADDw(VURegs * VU); +void _vuMADDA(VURegs * VU); +void _vuMADDAi(VURegs * VU); +void _vuMADDAq(VURegs * VU); +void _vuMADDAx(VURegs * VU); +void _vuMADDAy(VURegs * VU); +void _vuMADDAz(VURegs * VU); +void _vuMADDAw(VURegs * VU); +void _vuMSUB(VURegs * VU); +void _vuMSUBi(VURegs * VU); +void _vuMSUBq(VURegs * VU); +void _vuMSUBx(VURegs * VU); +void _vuMSUBy(VURegs * VU); +void _vuMSUBz(VURegs * VU) ; +void _vuMSUBw(VURegs * VU) ; +void _vuMSUBA(VURegs * VU); +void _vuMSUBAi(VURegs * VU); +void _vuMSUBAq(VURegs * VU); +void _vuMSUBAx(VURegs * VU); +void _vuMSUBAy(VURegs * VU); +void _vuMSUBAz(VURegs * VU); +void _vuMSUBAw(VURegs * VU); +void _vuMAX(VURegs * VU); +void _vuMAXi(VURegs * VU); +void _vuMAXx(VURegs * VU); +void _vuMAXy(VURegs * VU); +void _vuMAXz(VURegs * VU); +void _vuMAXw(VURegs * VU); +void _vuMINI(VURegs * VU); +void _vuMINIi(VURegs * VU); +void _vuMINIx(VURegs * VU); +void _vuMINIy(VURegs * VU); +void _vuMINIz(VURegs * VU); +void _vuMINIw(VURegs * VU); +void _vuOPMULA(VURegs * VU); +void _vuOPMSUB(VURegs * VU); +void _vuNOP(VURegs * VU); +void _vuFTOI0(VURegs * VU); +void _vuFTOI4(VURegs * VU); +void _vuFTOI12(VURegs * VU); +void _vuFTOI15(VURegs * VU); +void _vuITOF0(VURegs * VU) ; +void _vuITOF4(VURegs * VU) ; +void _vuITOF12(VURegs * VU); +void _vuITOF15(VURegs * VU); +void _vuCLIP(VURegs * VU); +/******************************/ +/* VU Lower instructions */ +/******************************/ +void _vuDIV(VURegs * VU); +void _vuSQRT(VURegs * VU); +void _vuRSQRT(VURegs * VU); +void _vuIADDI(VURegs * VU); +void _vuIADDIU(VURegs * VU); +void _vuIADD(VURegs * VU); +void _vuIAND(VURegs * VU); +void _vuIOR(VURegs * VU); +void _vuISUB(VURegs * VU); +void _vuISUBIU(VURegs * VU); +void _vuMOVE(VURegs * VU); +void _vuMFIR(VURegs * VU); +void _vuMTIR(VURegs * VU); +void _vuMR32(VURegs * VU); +void _vuLQ(VURegs * VU) ; +void _vuLQD(VURegs * VU); +void _vuLQI(VURegs * VU); +void _vuSQ(VURegs * VU); +void _vuSQD(VURegs * VU); +void _vuSQI(VURegs * VU); +void _vuILW(VURegs * VU); +void _vuISW(VURegs * VU); +void _vuILWR(VURegs * VU); +void _vuISWR(VURegs * VU); +void _vuLOI(VURegs * VU); +void _vuRINIT(VURegs * VU); +void _vuRGET(VURegs * VU); +void _vuRNEXT(VURegs * VU); +void _vuRXOR(VURegs * VU); +void _vuWAITQ(VURegs * VU); +void _vuFSAND(VURegs * VU); +void _vuFSEQ(VURegs * VU); +void _vuFSOR(VURegs * VU); +void _vuFSSET(VURegs * VU); +void _vuFMAND(VURegs * VU); +void _vuFMEQ(VURegs * VU); +void _vuFMOR(VURegs * VU); +void _vuFCAND(VURegs * VU); +void _vuFCEQ(VURegs * VU); +void _vuFCOR(VURegs * VU); +void _vuFCSET(VURegs * VU); +void _vuFCGET(VURegs * VU); +void _vuIBEQ(VURegs * VU); +void _vuIBGEZ(VURegs * VU); +void _vuIBGTZ(VURegs * VU); +void _vuIBLEZ(VURegs * VU); +void _vuIBLTZ(VURegs * VU); +void _vuIBNE(VURegs * VU); +void _vuB(VURegs * VU); +void _vuBAL(VURegs * VU); +void _vuJR(VURegs * VU); +void _vuJALR(VURegs * VU); +void _vuMFP(VURegs * VU); +void _vuWAITP(VURegs * VU); +void _vuESADD(VURegs * VU); +void _vuERSADD(VURegs * VU); +void _vuELENG(VURegs * VU); +void _vuERLENG(VURegs * VU); +void _vuEATANxy(VURegs * VU); +void _vuEATANxz(VURegs * VU); +void _vuESUM(VURegs * VU); +void _vuERCPR(VURegs * VU); +void _vuESQRT(VURegs * VU); +void _vuERSQRT(VURegs * VU); +void _vuESIN(VURegs * VU); +void _vuEATAN(VURegs * VU); +void _vuEEXP(VURegs * VU); +void _vuXITOP(VURegs * VU); +void _vuXGKICK(VURegs * VU); +void _vuXTOP(VURegs * VU); + +/******************************/ +/* VU Upper instructions */ +/******************************/ + +void _vuRegsABS(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADD(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDA(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDAi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDAq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDAx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDAy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDAz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsADDAw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUB(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBA(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBAi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBAq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBAx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBAy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBAz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSUBAw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMUL(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULA(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULAi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULAq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULAx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULAy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULAz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMULAw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADD(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDA(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDAi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDAq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDAx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDAy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDAz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMADDAw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUB(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBA(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBAi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBAq(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBAx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBAy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBAz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMSUBAw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMAX(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMAXi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMAXx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMAXy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMAXz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMAXw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMINI(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMINIi(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMINIx(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMINIy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMINIz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMINIw(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsOPMULA(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsOPMSUB(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsNOP(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFTOI0(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFTOI4(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFTOI12(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFTOI15(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsITOF0(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsITOF4(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsITOF12(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsITOF15(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsCLIP(VURegs * VU, _VURegsNum *VUregsn); +/******************************/ +/* VU Lower instructions */ +/******************************/ +void _vuRegsDIV(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSQRT(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsRSQRT(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIADDI(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIADDIU(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIADD(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIAND(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIOR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsISUB(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsISUBIU(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMOVE(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMFIR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMTIR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMR32(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsLQ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsLQD(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsLQI(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSQ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSQD(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsSQI(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsILW(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsISW(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsILWR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsISWR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsLOI(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsRINIT(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsRGET(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsRNEXT(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsRXOR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsWAITQ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFSAND(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFSEQ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFSOR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFSSET(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFMAND(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFMEQ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFMOR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFCAND(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFCEQ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFCOR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFCSET(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsFCGET(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIBEQ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIBGEZ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIBGTZ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIBLEZ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIBLTZ(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsIBNE(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsB(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsBAL(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsJR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsJALR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsMFP(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsWAITP(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsESADD(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsERSADD(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsELENG(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsERLENG(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsEATANxy(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsEATANxz(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsESUM(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsERCPR(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsESQRT(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsERSQRT(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsESIN(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsEATAN(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsEEXP(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsXITOP(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsXGKICK(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsXTOP(VURegs * VU, _VURegsNum *VUregsn); + +#endif diff --git a/pcsx2/Vif.cpp b/pcsx2/Vif.cpp index 603514fc0b..0eec873685 100644 --- a/pcsx2/Vif.cpp +++ b/pcsx2/Vif.cpp @@ -1,609 +1,609 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" -#include - -#include "Common.h" -#include "ix86/ix86.h" -#include "VUmicro.h" - -#include "Vif.h" -#include "VifDma.h" - -#include - -VIFregisters *_vifRegs; -u32* _vifMaskRegs = NULL; -PCSX2_ALIGNED16(u32 g_vifRow0[4]); -PCSX2_ALIGNED16(u32 g_vifCol0[4]); -PCSX2_ALIGNED16(u32 g_vifRow1[4]); -PCSX2_ALIGNED16(u32 g_vifCol1[4]); -u32* _vifRow = NULL, *_vifCol = NULL; - -vifStruct *_vif; - -static int n; - -__forceinline static int _limit( int a, int max ) -{ - return ( a > max ? max : a ); -} - -#define _UNPACKpart( offnum, func ) \ - if ( ( size > 0 ) && ( _vifRegs->offset == offnum ) ) { \ - func; \ - size--; \ - _vifRegs->offset++; \ - } - -#define _UNPACKpart_nosize( offnum, func ) \ - if ( ( _vifRegs->offset == offnum ) ) { \ - func; \ - _vifRegs->offset++; \ - } - -static void writeX( u32 *dest, u32 data ) { - if (_vifRegs->code & 0x10000000) { - switch ( _vif->cl ) { - case 0: n = (_vifRegs->mask) & 0x3; break; - case 1: n = (_vifRegs->mask >> 8) & 0x3; break; - case 2: n = (_vifRegs->mask >> 16) & 0x3; break; - default: n = (_vifRegs->mask >> 24) & 0x3; break; - } - } else n = 0; - - switch ( n ) { - case 0: - if((_vif->cmd & 0x6F) == 0x6f) { - *dest = data; - break; - } - if (_vifRegs->mode == 1) { - *dest = data + _vifRegs->r0; - } else - if (_vifRegs->mode == 2) { - _vifRegs->r0 = data + _vifRegs->r0; - *dest = _vifRegs->r0; - } else { - *dest = data; - } - break; - case 1: *dest = _vifRegs->r0; break; - case 2: - switch ( _vif->cl ) { - case 0: *dest = _vifRegs->c0; break; - case 1: *dest = _vifRegs->c1; break; - case 2: *dest = _vifRegs->c2; break; - default: *dest = _vifRegs->c3; break; - } - break; - } -// VIF_LOG("writeX %8.8x : Mode %d, r0 = %x, data %8.8x\n", *dest,_vifRegs->mode,_vifRegs->r0,data); -} - -static void writeY( u32 *dest, u32 data ) { - if (_vifRegs->code & 0x10000000) { - switch ( _vif->cl ) { - case 0: n = (_vifRegs->mask >> 2) & 0x3; break; - case 1: n = (_vifRegs->mask >> 10) & 0x3; break; - case 2: n = (_vifRegs->mask >> 18) & 0x3; break; - default: n = (_vifRegs->mask >> 26) & 0x3; break; - } - } else n = 0; - - switch ( n ) { - case 0: - if((_vif->cmd & 0x6F) == 0x6f) { - *dest = data; - break; - } - if (_vifRegs->mode == 1) { - *dest = data + _vifRegs->r1; - } else - if (_vifRegs->mode == 2) { - _vifRegs->r1 = data + _vifRegs->r1; - *dest = _vifRegs->r1; - } else { - *dest = data; - } - break; - case 1: *dest = _vifRegs->r1; break; - case 2: - switch ( _vif->cl ) { - case 0: *dest = _vifRegs->c0; break; - case 1: *dest = _vifRegs->c1; break; - case 2: *dest = _vifRegs->c2; break; - default: *dest = _vifRegs->c3; break; - } - break; - } -// VIF_LOG("writeY %8.8x : Mode %d, r1 = %x, data %8.8x\n", *dest,_vifRegs->mode,_vifRegs->r1,data); -} - -static void writeZ( u32 *dest, u32 data ) { - if (_vifRegs->code & 0x10000000) { - switch ( _vif->cl ) { - case 0: n = (_vifRegs->mask >> 4) & 0x3; break; - case 1: n = (_vifRegs->mask >> 12) & 0x3; break; - case 2: n = (_vifRegs->mask >> 20) & 0x3; break; - default: n = (_vifRegs->mask >> 28) & 0x3; break; - } - } else n = 0; - - switch ( n ) { - case 0: - if((_vif->cmd & 0x6F) == 0x6f) { - *dest = data; - break; - } - if (_vifRegs->mode == 1) { - *dest = data + _vifRegs->r2; - } else - if (_vifRegs->mode == 2) { - _vifRegs->r2 = data + _vifRegs->r2; - *dest = _vifRegs->r2; - } else { - *dest = data; - } - break; - case 1: *dest = _vifRegs->r2; break; - case 2: - switch ( _vif->cl ) { - case 0: *dest = _vifRegs->c0; break; - case 1: *dest = _vifRegs->c1; break; - case 2: *dest = _vifRegs->c2; break; - default: *dest = _vifRegs->c3; break; - } - break; - } -// VIF_LOG("writeZ %8.8x : Mode %d, r2 = %x, data %8.8x\n", *dest,_vifRegs->mode,_vifRegs->r2,data); -} - -static void writeW( u32 *dest, u32 data ) { - if (_vifRegs->code & 0x10000000) { - switch ( _vif->cl ) { - case 0: n = (_vifRegs->mask >> 6) & 0x3; break; - case 1: n = (_vifRegs->mask >> 14) & 0x3; break; - case 2: n = (_vifRegs->mask >> 22) & 0x3; break; - default: n = (_vifRegs->mask >> 30) & 0x3; break; - } - } else n = 0; - - switch ( n ) { - case 0: - if((_vif->cmd & 0x6F) == 0x6f) { - *dest = data; - break; - } - if (_vifRegs->mode == 1) { - *dest = data + _vifRegs->r3; - } else - if (_vifRegs->mode == 2) { - _vifRegs->r3 = data + _vifRegs->r3; - *dest = _vifRegs->r3; - } else { - *dest = data; - } - break; - case 1: *dest = _vifRegs->r3; break; - case 2: - switch ( _vif->cl ) { - case 0: *dest = _vifRegs->c0; break; - case 1: *dest = _vifRegs->c1; break; - case 2: *dest = _vifRegs->c2; break; - default: *dest = _vifRegs->c3; break; - } - break; - } -// VIF_LOG("writeW %8.8x : Mode %d, r3 = %x, data %8.8x\n", *dest,_vifRegs->mode,_vifRegs->r3,data); -} - -void UNPACK_S_32(u32 *dest, u32 *data, int size) { - _UNPACKpart(0, writeX(dest++, *data) ); - _UNPACKpart(1, writeY(dest++, *data) ); - _UNPACKpart(2, writeZ(dest++, *data) ); - _UNPACKpart(3, writeW(dest , *data) ); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -void UNPACK_S_16s( u32 *dest, u32 *data, int size) { - s16 *sdata = (s16*)data; - _UNPACKpart(0, writeX(dest++, *sdata) ); - _UNPACKpart(1, writeY(dest++, *sdata) ); - _UNPACKpart(2, writeZ(dest++, *sdata) ); - _UNPACKpart(3, writeW(dest , *sdata) ); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -void UNPACK_S_16u( u32 *dest, u32 *data, int size) { - u16 *sdata = (u16*)data; - _UNPACKpart(0, writeX(dest++, *sdata) ); - _UNPACKpart(1, writeY(dest++, *sdata) ); - _UNPACKpart(2, writeZ(dest++, *sdata) ); - _UNPACKpart(3, writeW(dest , *sdata) ); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -void UNPACK_S_8s(u32 *dest, u32 *data, int size) { - s8 *cdata = (s8*)data; - _UNPACKpart(0, writeX(dest++, *cdata) ); - _UNPACKpart(1, writeY(dest++, *cdata) ); - _UNPACKpart(2, writeZ(dest++, *cdata) ); - _UNPACKpart(3, writeW(dest , *cdata) ); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -void UNPACK_S_8u(u32 *dest, u32 *data, int size) { - u8 *cdata = (u8*)data; - _UNPACKpart(0, writeX(dest++, *cdata) ); - _UNPACKpart(1, writeY(dest++, *cdata) ); - _UNPACKpart(2, writeZ(dest++, *cdata) ); - _UNPACKpart(3, writeW(dest , *cdata) ); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -void UNPACK_V2_32( u32 *dest, u32 *data, int size ) { - _UNPACKpart(0, writeX(dest++, *data++)); - _UNPACKpart(1, writeY(dest++, *data--)); - _UNPACKpart_nosize(2, writeZ(dest++, *data)); - _UNPACKpart_nosize(3, writeW(dest , 0)); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; - -} - -void UNPACK_V2_16s(u32 *dest, u32 *data, int size) { - s16 *sdata = (s16*)data; - _UNPACKpart(0, writeX(dest++, *sdata++)); - _UNPACKpart(1, writeY(dest++, *sdata--)); - _UNPACKpart_nosize(2,writeZ(dest++, *sdata++)); - _UNPACKpart_nosize(3,writeW(dest , *sdata)); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -void UNPACK_V2_16u(u32 *dest, u32 *data, int size) { - u16 *sdata = (u16*)data; - _UNPACKpart(0, writeX(dest++, *sdata++)); - _UNPACKpart(1, writeY(dest++, *sdata--)); - _UNPACKpart_nosize(2,writeZ(dest++, *sdata++)); - _UNPACKpart_nosize(3,writeW(dest , *sdata)); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -void UNPACK_V2_8s(u32 *dest, u32 *data, int size) { - s8 *cdata = (s8*)data; - _UNPACKpart(0, writeX(dest++, *cdata++)); - _UNPACKpart(1, writeY(dest++, *cdata--)); - _UNPACKpart_nosize(2,writeZ(dest++, *cdata++)); - _UNPACKpart_nosize(3,writeW(dest , *cdata)); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -void UNPACK_V2_8u(u32 *dest, u32 *data, int size) { - u8 *cdata = (u8*)data; - _UNPACKpart(0, writeX(dest++, *cdata++)); - _UNPACKpart(1, writeY(dest++, *cdata--)); - _UNPACKpart_nosize(2,writeZ(dest++, *cdata++)); - _UNPACKpart_nosize(3,writeW(dest , *cdata)); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -void UNPACK_V3_32(u32 *dest, u32 *data, int size) { - _UNPACKpart(0, writeX(dest++, *data++); ); - _UNPACKpart(1, writeY(dest++, *data++); ); - _UNPACKpart(2, writeZ(dest++, *data++); ); - _UNPACKpart_nosize(3, writeW(dest, *data); ); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -void UNPACK_V3_16s(u32 *dest, u32 *data, int size) { - s16 *sdata = (s16*)data; - _UNPACKpart(0, writeX(dest++, *sdata++)); - _UNPACKpart(1, writeY(dest++, *sdata++)); - _UNPACKpart(2, writeZ(dest++, *sdata++)); - _UNPACKpart_nosize(3,writeW(dest, *sdata)); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -void UNPACK_V3_16u(u32 *dest, u32 *data, int size) { - u16 *sdata = (u16*)data; - _UNPACKpart(0, writeX(dest++, *sdata++)); - _UNPACKpart(1, writeY(dest++, *sdata++)); - _UNPACKpart(2, writeZ(dest++, *sdata++)); - _UNPACKpart_nosize(3,writeW(dest, *sdata)); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -void UNPACK_V3_8s(u32 *dest, u32 *data, int size) { - s8 *cdata = (s8*)data; - _UNPACKpart(0, writeX(dest++, *cdata++)); - _UNPACKpart(1, writeY(dest++, *cdata++)); - _UNPACKpart(2, writeZ(dest++, *cdata++)); - _UNPACKpart_nosize(3,writeW(dest, *cdata)); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -void UNPACK_V3_8u(u32 *dest, u32 *data, int size) { - u8 *cdata = (u8*)data; - _UNPACKpart(0, writeX(dest++, *cdata++)); - _UNPACKpart(1, writeY(dest++, *cdata++)); - _UNPACKpart(2, writeZ(dest++, *cdata++)); - _UNPACKpart_nosize(3,writeW(dest, *cdata)); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -void UNPACK_V4_32( u32 *dest, u32 *data , int size) { - _UNPACKpart(0, writeX(dest++, *data++) ); - _UNPACKpart(1, writeY(dest++, *data++) ); - _UNPACKpart(2, writeZ(dest++, *data++) ); - _UNPACKpart(3, writeW(dest , *data ) ); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -void UNPACK_V4_16s(u32 *dest, u32 *data, int size) { - s16 *sdata = (s16*)data; - _UNPACKpart(0, writeX(dest++, *sdata++) ); - _UNPACKpart(1, writeY(dest++, *sdata++) ); - _UNPACKpart(2, writeZ(dest++, *sdata++) ); - _UNPACKpart(3, writeW(dest , *sdata ) ); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -void UNPACK_V4_16u(u32 *dest, u32 *data, int size) { - u16 *sdata = (u16*)data; - _UNPACKpart(0, writeX(dest++, *sdata++) ); - _UNPACKpart(1, writeY(dest++, *sdata++) ); - _UNPACKpart(2, writeZ(dest++, *sdata++) ); - _UNPACKpart(3, writeW(dest , *sdata ) ); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -void UNPACK_V4_8s(u32 *dest, u32 *data, int size) { - s8 *cdata = (s8*)data; - _UNPACKpart(0, writeX(dest++, *cdata++) ); - _UNPACKpart(1, writeY(dest++, *cdata++) ); - _UNPACKpart(2, writeZ(dest++, *cdata++) ); - _UNPACKpart(3, writeW(dest , *cdata ) ); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -void UNPACK_V4_8u(u32 *dest, u32 *data, int size) { - u8 *cdata = (u8*)data; - _UNPACKpart(0, writeX(dest++, *cdata++) ); - _UNPACKpart(1, writeY(dest++, *cdata++) ); - _UNPACKpart(2, writeZ(dest++, *cdata++) ); - _UNPACKpart(3, writeW(dest , *cdata ) ); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -void UNPACK_V4_5(u32 *dest, u32 *data, int size) { - - _UNPACKpart(0, writeX(dest++, (*data & 0x001f) << 3); ); - _UNPACKpart(1, writeY(dest++, (*data & 0x03e0) >> 2); ); - _UNPACKpart(2, writeZ(dest++, (*data & 0x7c00) >> 7); ); - _UNPACKpart(3, writeW(dest , (*data & 0x8000) >> 8); ); - if (_vifRegs->offset == 4) _vifRegs->offset = 0; -} - -static int cycles; -extern int g_vifCycles; -u16 vifqwc = 0; -static __forceinline int mfifoVIF1rbTransfer() { - u32 maddr = psHu32(DMAC_RBOR); - u32 ret, msize = psHu32(DMAC_RBOR) + psHu32(DMAC_RBSR) + 16; - u16 mfifoqwc = std::min(vif1ch->qwc, vifqwc); - u32 *src; - - /* Check if the transfer should wrap around the ring buffer */ - if ((vif1ch->madr+(mfifoqwc << 4)) > (msize)) { - int s1 = ((msize) - vif1ch->madr) >> 2; - - SPR_LOG("Split MFIFO\n"); - - /* it does, so first copy 's1' bytes from 'addr' to 'data' */ - src = (u32*)PSM(vif1ch->madr); - if (src == NULL) return -1; - if(vif1.vifstalled == 1){ - ret = VIF1transfer(src+vif1.irqoffset, s1-vif1.irqoffset, 0); - } - else - ret = VIF1transfer(src, s1, 0); - if(ret == -2) return ret; - - /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */ - vif1ch->madr = maddr; - - src = (u32*)PSM(maddr); - if (src == NULL) return -1; - ret = VIF1transfer(src, ((mfifoqwc << 2) - s1), 0); - } else - { - SPR_LOG("Direct MFIFO\n"); - - /* it doesn't, so just transfer 'qwc*4' words */ - src = (u32*)PSM(vif1ch->madr); - if (src == NULL) return -1; - if(vif1.vifstalled == 1) - ret = VIF1transfer(src+vif1.irqoffset, mfifoqwc*4-vif1.irqoffset, 0); - else - ret = VIF1transfer(src, mfifoqwc << 2, 0); - if(ret == -2) return ret; - } - - - return ret; -} - -static __forceinline int mfifoVIF1chain() { - int ret; - - /* Is QWC = 0? if so there is nothing to transfer */ - if (vif1ch->qwc == 0 && vif1.vifstalled == 0) return 0; - - - if (vif1ch->madr >= psHu32(DMAC_RBOR) && - vif1ch->madr <= (psHu32(DMAC_RBOR)+psHu32(DMAC_RBSR))) { - u16 startqwc = vif1ch->qwc; - ret = mfifoVIF1rbTransfer(); - vifqwc -= startqwc - vif1ch->qwc; - } else { - u32 *pMem = (u32*)dmaGetAddr(vif1ch->madr); - SPR_LOG("Non-MFIFO Location\n"); - - if (pMem == NULL) return -1; - if(vif1.vifstalled == 1){ - ret = VIF1transfer(pMem+vif1.irqoffset, vif1ch->qwc*4-vif1.irqoffset, 0); - }else - ret = VIF1transfer(pMem, vif1ch->qwc << 2, 0); - } - - return ret; -} - -#define spr0 ((DMACh*)&PS2MEM_HW[0xD000]) - -void mfifoVIF1transfer(int qwc) { - u32 *ptag; - int id; - int ret, temp; - - g_vifCycles = 0; - - if(qwc > 0){ - vifqwc += qwc; - vif1.done &= ~1; - SPR_LOG("Added %x qw to mfifo, total now %x\n", qwc, vifqwc); - if((vif1ch->chcr & 0x100) == 0 || vif1.vifstalled == 1) return; - } - - if(vif1ch->qwc == 0){ - ptag = (u32*)dmaGetAddr(vif1ch->tadr); - - if (vif1ch->chcr & 0x40) { - if( vif1.stallontag == 1) ret = VIF1transfer(ptag+(2+vif1.irqoffset), 2-vif1.irqoffset, 1); //Transfer Tag on Stall - else ret = VIF1transfer(ptag+2, 2, 1); //Transfer Tag - if (ret == -2) { - VIF_LOG("MFIFO Stallon tag\n"); - - vif1.stallontag = 1; - CPU_INT(10,cycles+g_vifCycles); - return; //IRQ set by VIFTransfer - } - } - - id = (ptag[0] >> 28) & 0x7; - vif1ch->qwc = (ptag[0] & 0xffff); - vif1ch->madr = ptag[1]; - cycles += 2; - - vif1ch->chcr = ( vif1ch->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); - - SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx mfifo qwc = %x spr0 madr = %x\n", - ptag[1], ptag[0], vif1ch->qwc, id, vif1ch->madr, vif1ch->tadr, vifqwc, spr0->madr); - vifqwc--; - - switch (id) { - case 0: // Refe - Transfer Packet According to ADDR field - vif1ch->tadr = psHu32(DMAC_RBOR) + ((vif1ch->tadr + 16) & psHu32(DMAC_RBSR)); - vif1.done = 2; //End Transfer - break; - - case 1: // CNT - Transfer QWC following the tag. - vif1ch->madr = psHu32(DMAC_RBOR) + ((vif1ch->tadr + 16) & psHu32(DMAC_RBSR)); //Set MADR to QW after Tag - vif1ch->tadr = psHu32(DMAC_RBOR) + ((vif1ch->madr + (vif1ch->qwc << 4)) & psHu32(DMAC_RBSR)); //Set TADR to QW following the data - vif1.done = 0; - break; - - case 2: // Next - Transfer QWC following tag. TADR = ADDR - temp = vif1ch->madr; //Temporarily Store ADDR - vif1ch->madr = psHu32(DMAC_RBOR) + ((vif1ch->tadr + 16) & psHu32(DMAC_RBSR)); //Set MADR to QW following the tag - vif1ch->tadr = temp; //Copy temporarily stored ADDR to Tag - if((temp & psHu32(DMAC_RBSR)) != psHu32(DMAC_RBOR)) SysPrintf("Next tag = %x outside ring %x size %x\n", temp, psHu32(DMAC_RBOR), psHu32(DMAC_RBSR)); - vif1.done = 0; - break; - - case 3: // Ref - Transfer QWC from ADDR field - case 4: // Refs - Transfer QWC from ADDR field (Stall Control) - vif1ch->tadr = psHu32(DMAC_RBOR) + ((vif1ch->tadr + 16) & psHu32(DMAC_RBSR)); //Set TADR to next tag - vif1.done = 0; - break; - - case 7: // End - Transfer QWC following the tag - vif1ch->madr = psHu32(DMAC_RBOR) + ((vif1ch->tadr + 16) & psHu32(DMAC_RBSR)); //Set MADR to data following the tag - vif1ch->tadr = psHu32(DMAC_RBOR) + ((vif1ch->madr + (vif1ch->qwc << 4)) & psHu32(DMAC_RBSR)); //Set TADR to QW following the data - vif1.done = 2; //End Transfer - break; - } - - if ((vif1ch->chcr & 0x80) && (ptag[0] >> 31)) { - VIF_LOG("dmaIrq Set\n"); - vif1.done = 2; - } - } - ret = mfifoVIF1chain(); - if (ret == -1) { - SysPrintf("VIF dmaChain error size=%d, madr=%lx, tadr=%lx\n", - vif1ch->qwc, vif1ch->madr, vif1ch->tadr); - vif1.done = 1; - CPU_INT(10,g_vifCycles); - } - if(ret == -2){ - VIF_LOG("MFIFO Stall\n"); - CPU_INT(10,g_vifCycles); - return; - } - - if(vif1.done == 2 && vif1ch->qwc == 0) vif1.done = 1; - CPU_INT(10,g_vifCycles); - SPR_LOG("mfifoVIF1transfer end %x madr %x, tadr %x vifqwc %x\n", vif1ch->chcr, vif1ch->madr, vif1ch->tadr, vifqwc); -} - -void vifMFIFOInterrupt() -{ - if(vif1.irq && vif1.tag.size == 0) { - vif1Regs->stat|= VIF1_STAT_INT; - hwIntcIrq(5); - --vif1.irq; - if(vif1Regs->stat & (VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS)) - { - vif1Regs->stat&= ~0x1F000000; // FQC=0 - vif1ch->chcr &= ~0x100; - return; - } - } - - if(vif1.done != 1) { - if(vifqwc <= 0){ - //SysPrintf("Empty\n"); - vif1.done |= 1; - hwDmacIrq(14); - return; - } - mfifoVIF1transfer(0); - return; - } - - vifqwc = 0; - vif1.done = 1; - vif1ch->chcr &= ~0x100; - hwDmacIrq(DMAC_VIF1); - VIF_LOG("vif mfifo dma end\n"); - - vif1Regs->stat&= ~0x1F000000; // FQC=0 - -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" +#include + +#include "Common.h" +#include "ix86/ix86.h" +#include "VUmicro.h" + +#include "Vif.h" +#include "VifDma.h" + +#include + +VIFregisters *_vifRegs; +u32* _vifMaskRegs = NULL; +PCSX2_ALIGNED16(u32 g_vifRow0[4]); +PCSX2_ALIGNED16(u32 g_vifCol0[4]); +PCSX2_ALIGNED16(u32 g_vifRow1[4]); +PCSX2_ALIGNED16(u32 g_vifCol1[4]); +u32* _vifRow = NULL, *_vifCol = NULL; + +vifStruct *_vif; + +static int n; + +__forceinline static int _limit( int a, int max ) +{ + return ( a > max ? max : a ); +} + +#define _UNPACKpart( offnum, func ) \ + if ( ( size > 0 ) && ( _vifRegs->offset == offnum ) ) { \ + func; \ + size--; \ + _vifRegs->offset++; \ + } + +#define _UNPACKpart_nosize( offnum, func ) \ + if ( ( _vifRegs->offset == offnum ) ) { \ + func; \ + _vifRegs->offset++; \ + } + +static void writeX( u32 *dest, u32 data ) { + if (_vifRegs->code & 0x10000000) { + switch ( _vif->cl ) { + case 0: n = (_vifRegs->mask) & 0x3; break; + case 1: n = (_vifRegs->mask >> 8) & 0x3; break; + case 2: n = (_vifRegs->mask >> 16) & 0x3; break; + default: n = (_vifRegs->mask >> 24) & 0x3; break; + } + } else n = 0; + + switch ( n ) { + case 0: + if((_vif->cmd & 0x6F) == 0x6f) { + *dest = data; + break; + } + if (_vifRegs->mode == 1) { + *dest = data + _vifRegs->r0; + } else + if (_vifRegs->mode == 2) { + _vifRegs->r0 = data + _vifRegs->r0; + *dest = _vifRegs->r0; + } else { + *dest = data; + } + break; + case 1: *dest = _vifRegs->r0; break; + case 2: + switch ( _vif->cl ) { + case 0: *dest = _vifRegs->c0; break; + case 1: *dest = _vifRegs->c1; break; + case 2: *dest = _vifRegs->c2; break; + default: *dest = _vifRegs->c3; break; + } + break; + } +// VIF_LOG("writeX %8.8x : Mode %d, r0 = %x, data %8.8x\n", *dest,_vifRegs->mode,_vifRegs->r0,data); +} + +static void writeY( u32 *dest, u32 data ) { + if (_vifRegs->code & 0x10000000) { + switch ( _vif->cl ) { + case 0: n = (_vifRegs->mask >> 2) & 0x3; break; + case 1: n = (_vifRegs->mask >> 10) & 0x3; break; + case 2: n = (_vifRegs->mask >> 18) & 0x3; break; + default: n = (_vifRegs->mask >> 26) & 0x3; break; + } + } else n = 0; + + switch ( n ) { + case 0: + if((_vif->cmd & 0x6F) == 0x6f) { + *dest = data; + break; + } + if (_vifRegs->mode == 1) { + *dest = data + _vifRegs->r1; + } else + if (_vifRegs->mode == 2) { + _vifRegs->r1 = data + _vifRegs->r1; + *dest = _vifRegs->r1; + } else { + *dest = data; + } + break; + case 1: *dest = _vifRegs->r1; break; + case 2: + switch ( _vif->cl ) { + case 0: *dest = _vifRegs->c0; break; + case 1: *dest = _vifRegs->c1; break; + case 2: *dest = _vifRegs->c2; break; + default: *dest = _vifRegs->c3; break; + } + break; + } +// VIF_LOG("writeY %8.8x : Mode %d, r1 = %x, data %8.8x\n", *dest,_vifRegs->mode,_vifRegs->r1,data); +} + +static void writeZ( u32 *dest, u32 data ) { + if (_vifRegs->code & 0x10000000) { + switch ( _vif->cl ) { + case 0: n = (_vifRegs->mask >> 4) & 0x3; break; + case 1: n = (_vifRegs->mask >> 12) & 0x3; break; + case 2: n = (_vifRegs->mask >> 20) & 0x3; break; + default: n = (_vifRegs->mask >> 28) & 0x3; break; + } + } else n = 0; + + switch ( n ) { + case 0: + if((_vif->cmd & 0x6F) == 0x6f) { + *dest = data; + break; + } + if (_vifRegs->mode == 1) { + *dest = data + _vifRegs->r2; + } else + if (_vifRegs->mode == 2) { + _vifRegs->r2 = data + _vifRegs->r2; + *dest = _vifRegs->r2; + } else { + *dest = data; + } + break; + case 1: *dest = _vifRegs->r2; break; + case 2: + switch ( _vif->cl ) { + case 0: *dest = _vifRegs->c0; break; + case 1: *dest = _vifRegs->c1; break; + case 2: *dest = _vifRegs->c2; break; + default: *dest = _vifRegs->c3; break; + } + break; + } +// VIF_LOG("writeZ %8.8x : Mode %d, r2 = %x, data %8.8x\n", *dest,_vifRegs->mode,_vifRegs->r2,data); +} + +static void writeW( u32 *dest, u32 data ) { + if (_vifRegs->code & 0x10000000) { + switch ( _vif->cl ) { + case 0: n = (_vifRegs->mask >> 6) & 0x3; break; + case 1: n = (_vifRegs->mask >> 14) & 0x3; break; + case 2: n = (_vifRegs->mask >> 22) & 0x3; break; + default: n = (_vifRegs->mask >> 30) & 0x3; break; + } + } else n = 0; + + switch ( n ) { + case 0: + if((_vif->cmd & 0x6F) == 0x6f) { + *dest = data; + break; + } + if (_vifRegs->mode == 1) { + *dest = data + _vifRegs->r3; + } else + if (_vifRegs->mode == 2) { + _vifRegs->r3 = data + _vifRegs->r3; + *dest = _vifRegs->r3; + } else { + *dest = data; + } + break; + case 1: *dest = _vifRegs->r3; break; + case 2: + switch ( _vif->cl ) { + case 0: *dest = _vifRegs->c0; break; + case 1: *dest = _vifRegs->c1; break; + case 2: *dest = _vifRegs->c2; break; + default: *dest = _vifRegs->c3; break; + } + break; + } +// VIF_LOG("writeW %8.8x : Mode %d, r3 = %x, data %8.8x\n", *dest,_vifRegs->mode,_vifRegs->r3,data); +} + +void UNPACK_S_32(u32 *dest, u32 *data, int size) { + _UNPACKpart(0, writeX(dest++, *data) ); + _UNPACKpart(1, writeY(dest++, *data) ); + _UNPACKpart(2, writeZ(dest++, *data) ); + _UNPACKpart(3, writeW(dest , *data) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_S_16s( u32 *dest, u32 *data, int size) { + s16 *sdata = (s16*)data; + _UNPACKpart(0, writeX(dest++, *sdata) ); + _UNPACKpart(1, writeY(dest++, *sdata) ); + _UNPACKpart(2, writeZ(dest++, *sdata) ); + _UNPACKpart(3, writeW(dest , *sdata) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_S_16u( u32 *dest, u32 *data, int size) { + u16 *sdata = (u16*)data; + _UNPACKpart(0, writeX(dest++, *sdata) ); + _UNPACKpart(1, writeY(dest++, *sdata) ); + _UNPACKpart(2, writeZ(dest++, *sdata) ); + _UNPACKpart(3, writeW(dest , *sdata) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_S_8s(u32 *dest, u32 *data, int size) { + s8 *cdata = (s8*)data; + _UNPACKpart(0, writeX(dest++, *cdata) ); + _UNPACKpart(1, writeY(dest++, *cdata) ); + _UNPACKpart(2, writeZ(dest++, *cdata) ); + _UNPACKpart(3, writeW(dest , *cdata) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_S_8u(u32 *dest, u32 *data, int size) { + u8 *cdata = (u8*)data; + _UNPACKpart(0, writeX(dest++, *cdata) ); + _UNPACKpart(1, writeY(dest++, *cdata) ); + _UNPACKpart(2, writeZ(dest++, *cdata) ); + _UNPACKpart(3, writeW(dest , *cdata) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V2_32( u32 *dest, u32 *data, int size ) { + _UNPACKpart(0, writeX(dest++, *data++)); + _UNPACKpart(1, writeY(dest++, *data--)); + _UNPACKpart_nosize(2, writeZ(dest++, *data)); + _UNPACKpart_nosize(3, writeW(dest , 0)); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; + +} + +void UNPACK_V2_16s(u32 *dest, u32 *data, int size) { + s16 *sdata = (s16*)data; + _UNPACKpart(0, writeX(dest++, *sdata++)); + _UNPACKpart(1, writeY(dest++, *sdata--)); + _UNPACKpart_nosize(2,writeZ(dest++, *sdata++)); + _UNPACKpart_nosize(3,writeW(dest , *sdata)); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V2_16u(u32 *dest, u32 *data, int size) { + u16 *sdata = (u16*)data; + _UNPACKpart(0, writeX(dest++, *sdata++)); + _UNPACKpart(1, writeY(dest++, *sdata--)); + _UNPACKpart_nosize(2,writeZ(dest++, *sdata++)); + _UNPACKpart_nosize(3,writeW(dest , *sdata)); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V2_8s(u32 *dest, u32 *data, int size) { + s8 *cdata = (s8*)data; + _UNPACKpart(0, writeX(dest++, *cdata++)); + _UNPACKpart(1, writeY(dest++, *cdata--)); + _UNPACKpart_nosize(2,writeZ(dest++, *cdata++)); + _UNPACKpart_nosize(3,writeW(dest , *cdata)); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V2_8u(u32 *dest, u32 *data, int size) { + u8 *cdata = (u8*)data; + _UNPACKpart(0, writeX(dest++, *cdata++)); + _UNPACKpart(1, writeY(dest++, *cdata--)); + _UNPACKpart_nosize(2,writeZ(dest++, *cdata++)); + _UNPACKpart_nosize(3,writeW(dest , *cdata)); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V3_32(u32 *dest, u32 *data, int size) { + _UNPACKpart(0, writeX(dest++, *data++); ); + _UNPACKpart(1, writeY(dest++, *data++); ); + _UNPACKpart(2, writeZ(dest++, *data++); ); + _UNPACKpart_nosize(3, writeW(dest, *data); ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V3_16s(u32 *dest, u32 *data, int size) { + s16 *sdata = (s16*)data; + _UNPACKpart(0, writeX(dest++, *sdata++)); + _UNPACKpart(1, writeY(dest++, *sdata++)); + _UNPACKpart(2, writeZ(dest++, *sdata++)); + _UNPACKpart_nosize(3,writeW(dest, *sdata)); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V3_16u(u32 *dest, u32 *data, int size) { + u16 *sdata = (u16*)data; + _UNPACKpart(0, writeX(dest++, *sdata++)); + _UNPACKpart(1, writeY(dest++, *sdata++)); + _UNPACKpart(2, writeZ(dest++, *sdata++)); + _UNPACKpart_nosize(3,writeW(dest, *sdata)); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V3_8s(u32 *dest, u32 *data, int size) { + s8 *cdata = (s8*)data; + _UNPACKpart(0, writeX(dest++, *cdata++)); + _UNPACKpart(1, writeY(dest++, *cdata++)); + _UNPACKpart(2, writeZ(dest++, *cdata++)); + _UNPACKpart_nosize(3,writeW(dest, *cdata)); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V3_8u(u32 *dest, u32 *data, int size) { + u8 *cdata = (u8*)data; + _UNPACKpart(0, writeX(dest++, *cdata++)); + _UNPACKpart(1, writeY(dest++, *cdata++)); + _UNPACKpart(2, writeZ(dest++, *cdata++)); + _UNPACKpart_nosize(3,writeW(dest, *cdata)); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V4_32( u32 *dest, u32 *data , int size) { + _UNPACKpart(0, writeX(dest++, *data++) ); + _UNPACKpart(1, writeY(dest++, *data++) ); + _UNPACKpart(2, writeZ(dest++, *data++) ); + _UNPACKpart(3, writeW(dest , *data ) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V4_16s(u32 *dest, u32 *data, int size) { + s16 *sdata = (s16*)data; + _UNPACKpart(0, writeX(dest++, *sdata++) ); + _UNPACKpart(1, writeY(dest++, *sdata++) ); + _UNPACKpart(2, writeZ(dest++, *sdata++) ); + _UNPACKpart(3, writeW(dest , *sdata ) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V4_16u(u32 *dest, u32 *data, int size) { + u16 *sdata = (u16*)data; + _UNPACKpart(0, writeX(dest++, *sdata++) ); + _UNPACKpart(1, writeY(dest++, *sdata++) ); + _UNPACKpart(2, writeZ(dest++, *sdata++) ); + _UNPACKpart(3, writeW(dest , *sdata ) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V4_8s(u32 *dest, u32 *data, int size) { + s8 *cdata = (s8*)data; + _UNPACKpart(0, writeX(dest++, *cdata++) ); + _UNPACKpart(1, writeY(dest++, *cdata++) ); + _UNPACKpart(2, writeZ(dest++, *cdata++) ); + _UNPACKpart(3, writeW(dest , *cdata ) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V4_8u(u32 *dest, u32 *data, int size) { + u8 *cdata = (u8*)data; + _UNPACKpart(0, writeX(dest++, *cdata++) ); + _UNPACKpart(1, writeY(dest++, *cdata++) ); + _UNPACKpart(2, writeZ(dest++, *cdata++) ); + _UNPACKpart(3, writeW(dest , *cdata ) ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +void UNPACK_V4_5(u32 *dest, u32 *data, int size) { + + _UNPACKpart(0, writeX(dest++, (*data & 0x001f) << 3); ); + _UNPACKpart(1, writeY(dest++, (*data & 0x03e0) >> 2); ); + _UNPACKpart(2, writeZ(dest++, (*data & 0x7c00) >> 7); ); + _UNPACKpart(3, writeW(dest , (*data & 0x8000) >> 8); ); + if (_vifRegs->offset == 4) _vifRegs->offset = 0; +} + +static int cycles; +extern int g_vifCycles; +u16 vifqwc = 0; +static __forceinline int mfifoVIF1rbTransfer() { + u32 maddr = psHu32(DMAC_RBOR); + u32 ret, msize = psHu32(DMAC_RBOR) + psHu32(DMAC_RBSR) + 16; + u16 mfifoqwc = std::min(vif1ch->qwc, vifqwc); + u32 *src; + + /* Check if the transfer should wrap around the ring buffer */ + if ((vif1ch->madr+(mfifoqwc << 4)) > (msize)) { + int s1 = ((msize) - vif1ch->madr) >> 2; + + SPR_LOG("Split MFIFO\n"); + + /* it does, so first copy 's1' bytes from 'addr' to 'data' */ + src = (u32*)PSM(vif1ch->madr); + if (src == NULL) return -1; + if(vif1.vifstalled == 1){ + ret = VIF1transfer(src+vif1.irqoffset, s1-vif1.irqoffset, 0); + } + else + ret = VIF1transfer(src, s1, 0); + if(ret == -2) return ret; + + /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */ + vif1ch->madr = maddr; + + src = (u32*)PSM(maddr); + if (src == NULL) return -1; + ret = VIF1transfer(src, ((mfifoqwc << 2) - s1), 0); + } else + { + SPR_LOG("Direct MFIFO\n"); + + /* it doesn't, so just transfer 'qwc*4' words */ + src = (u32*)PSM(vif1ch->madr); + if (src == NULL) return -1; + if(vif1.vifstalled == 1) + ret = VIF1transfer(src+vif1.irqoffset, mfifoqwc*4-vif1.irqoffset, 0); + else + ret = VIF1transfer(src, mfifoqwc << 2, 0); + if(ret == -2) return ret; + } + + + return ret; +} + +static __forceinline int mfifoVIF1chain() { + int ret; + + /* Is QWC = 0? if so there is nothing to transfer */ + if (vif1ch->qwc == 0 && vif1.vifstalled == 0) return 0; + + + if (vif1ch->madr >= psHu32(DMAC_RBOR) && + vif1ch->madr <= (psHu32(DMAC_RBOR)+psHu32(DMAC_RBSR))) { + u16 startqwc = vif1ch->qwc; + ret = mfifoVIF1rbTransfer(); + vifqwc -= startqwc - vif1ch->qwc; + } else { + u32 *pMem = (u32*)dmaGetAddr(vif1ch->madr); + SPR_LOG("Non-MFIFO Location\n"); + + if (pMem == NULL) return -1; + if(vif1.vifstalled == 1){ + ret = VIF1transfer(pMem+vif1.irqoffset, vif1ch->qwc*4-vif1.irqoffset, 0); + }else + ret = VIF1transfer(pMem, vif1ch->qwc << 2, 0); + } + + return ret; +} + +#define spr0 ((DMACh*)&PS2MEM_HW[0xD000]) + +void mfifoVIF1transfer(int qwc) { + u32 *ptag; + int id; + int ret, temp; + + g_vifCycles = 0; + + if(qwc > 0){ + vifqwc += qwc; + vif1.done &= ~1; + SPR_LOG("Added %x qw to mfifo, total now %x\n", qwc, vifqwc); + if((vif1ch->chcr & 0x100) == 0 || vif1.vifstalled == 1) return; + } + + if(vif1ch->qwc == 0){ + ptag = (u32*)dmaGetAddr(vif1ch->tadr); + + if (vif1ch->chcr & 0x40) { + if( vif1.stallontag == 1) ret = VIF1transfer(ptag+(2+vif1.irqoffset), 2-vif1.irqoffset, 1); //Transfer Tag on Stall + else ret = VIF1transfer(ptag+2, 2, 1); //Transfer Tag + if (ret == -2) { + VIF_LOG("MFIFO Stallon tag\n"); + + vif1.stallontag = 1; + CPU_INT(10,cycles+g_vifCycles); + return; //IRQ set by VIFTransfer + } + } + + id = (ptag[0] >> 28) & 0x7; + vif1ch->qwc = (ptag[0] & 0xffff); + vif1ch->madr = ptag[1]; + cycles += 2; + + vif1ch->chcr = ( vif1ch->chcr & 0xFFFF ) | ( (*ptag) & 0xFFFF0000 ); + + SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx mfifo qwc = %x spr0 madr = %x\n", + ptag[1], ptag[0], vif1ch->qwc, id, vif1ch->madr, vif1ch->tadr, vifqwc, spr0->madr); + vifqwc--; + + switch (id) { + case 0: // Refe - Transfer Packet According to ADDR field + vif1ch->tadr = psHu32(DMAC_RBOR) + ((vif1ch->tadr + 16) & psHu32(DMAC_RBSR)); + vif1.done = 2; //End Transfer + break; + + case 1: // CNT - Transfer QWC following the tag. + vif1ch->madr = psHu32(DMAC_RBOR) + ((vif1ch->tadr + 16) & psHu32(DMAC_RBSR)); //Set MADR to QW after Tag + vif1ch->tadr = psHu32(DMAC_RBOR) + ((vif1ch->madr + (vif1ch->qwc << 4)) & psHu32(DMAC_RBSR)); //Set TADR to QW following the data + vif1.done = 0; + break; + + case 2: // Next - Transfer QWC following tag. TADR = ADDR + temp = vif1ch->madr; //Temporarily Store ADDR + vif1ch->madr = psHu32(DMAC_RBOR) + ((vif1ch->tadr + 16) & psHu32(DMAC_RBSR)); //Set MADR to QW following the tag + vif1ch->tadr = temp; //Copy temporarily stored ADDR to Tag + if((temp & psHu32(DMAC_RBSR)) != psHu32(DMAC_RBOR)) SysPrintf("Next tag = %x outside ring %x size %x\n", temp, psHu32(DMAC_RBOR), psHu32(DMAC_RBSR)); + vif1.done = 0; + break; + + case 3: // Ref - Transfer QWC from ADDR field + case 4: // Refs - Transfer QWC from ADDR field (Stall Control) + vif1ch->tadr = psHu32(DMAC_RBOR) + ((vif1ch->tadr + 16) & psHu32(DMAC_RBSR)); //Set TADR to next tag + vif1.done = 0; + break; + + case 7: // End - Transfer QWC following the tag + vif1ch->madr = psHu32(DMAC_RBOR) + ((vif1ch->tadr + 16) & psHu32(DMAC_RBSR)); //Set MADR to data following the tag + vif1ch->tadr = psHu32(DMAC_RBOR) + ((vif1ch->madr + (vif1ch->qwc << 4)) & psHu32(DMAC_RBSR)); //Set TADR to QW following the data + vif1.done = 2; //End Transfer + break; + } + + if ((vif1ch->chcr & 0x80) && (ptag[0] >> 31)) { + VIF_LOG("dmaIrq Set\n"); + vif1.done = 2; + } + } + ret = mfifoVIF1chain(); + if (ret == -1) { + SysPrintf("VIF dmaChain error size=%d, madr=%lx, tadr=%lx\n", + vif1ch->qwc, vif1ch->madr, vif1ch->tadr); + vif1.done = 1; + CPU_INT(10,g_vifCycles); + } + if(ret == -2){ + VIF_LOG("MFIFO Stall\n"); + CPU_INT(10,g_vifCycles); + return; + } + + if(vif1.done == 2 && vif1ch->qwc == 0) vif1.done = 1; + CPU_INT(10,g_vifCycles); + SPR_LOG("mfifoVIF1transfer end %x madr %x, tadr %x vifqwc %x\n", vif1ch->chcr, vif1ch->madr, vif1ch->tadr, vifqwc); +} + +void vifMFIFOInterrupt() +{ + if(vif1.irq && vif1.tag.size == 0) { + vif1Regs->stat|= VIF1_STAT_INT; + hwIntcIrq(5); + --vif1.irq; + if(vif1Regs->stat & (VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS)) + { + vif1Regs->stat&= ~0x1F000000; // FQC=0 + vif1ch->chcr &= ~0x100; + return; + } + } + + if(vif1.done != 1) { + if(vifqwc <= 0){ + //SysPrintf("Empty\n"); + vif1.done |= 1; + hwDmacIrq(14); + return; + } + mfifoVIF1transfer(0); + return; + } + + vifqwc = 0; + vif1.done = 1; + vif1ch->chcr &= ~0x100; + hwDmacIrq(DMAC_VIF1); + VIF_LOG("vif mfifo dma end\n"); + + vif1Regs->stat&= ~0x1F000000; // FQC=0 + +} diff --git a/pcsx2/Vif.h b/pcsx2/Vif.h index 866195b32e..f5866252dd 100644 --- a/pcsx2/Vif.h +++ b/pcsx2/Vif.h @@ -1,113 +1,113 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __VIF_H__ -#define __VIF_H__ - -struct vifCycle { - u8 cl, wl; - u8 pad[2]; -}; - -struct VIFregisters { - u32 stat; - u32 pad0[3]; - u32 fbrst; - u32 pad1[3]; - u32 err; - u32 pad2[3]; - u32 mark; - u32 pad3[3]; - vifCycle cycle; //data write cycle - u32 pad4[3]; - u32 mode; - u32 pad5[3]; - u32 num; - u32 pad6[3]; - u32 mask; - u32 pad7[3]; - u32 code; - u32 pad8[3]; - u32 itops; - u32 pad9[3]; - u32 base; // Not used in VIF0 - u32 pad10[3]; - u32 ofst; // Not used in VIF0 - u32 pad11[3]; - u32 tops; // Not used in VIF0 - u32 pad12[3]; - u32 itop; - u32 pad13[3]; - u32 top; // Not used in VIF0 - u32 pad14[3]; - u32 mskpath3; - u32 pad15[3]; - u32 r0; // row0 register - u32 pad16[3]; - u32 r1; // row1 register - u32 pad17[3]; - u32 r2; // row2 register - u32 pad18[3]; - u32 r3; // row3 register - u32 pad19[3]; - u32 c0; // col0 register - u32 pad20[3]; - u32 c1; // col1 register - u32 pad21[3]; - u32 c2; // col2 register - u32 pad22[3]; - u32 c3; // col3 register - u32 pad23[3]; - u32 offset; // internal UNPACK offset - u32 addr; -}; - -extern "C" -{ - // these use cdecl for Asm code references. - extern VIFregisters *_vifRegs; - extern u32* _vifMaskRegs; - extern u32* _vifRow; - extern u32* _vifCol; -} - -#define vif0Regs ((VIFregisters*)&PS2MEM_HW[0x3800]) -#define vif1Regs ((VIFregisters*)&PS2MEM_HW[0x3c00]) - -void dmaVIF0(); -void dmaVIF1(); -void mfifoVIF1transfer(int qwc); -int VIF0transfer(u32 *data, int size, int istag); -int VIF1transfer(u32 *data, int size, int istag); -void vifMFIFOInterrupt(); - -void SetNewMask(u32* vif1masks, u32* hasmask, u32 mask, u32 oldmask); - -#define XMM_R0 xmm0 -#define XMM_R1 xmm1 -#define XMM_R2 xmm2 -#define XMM_WRITEMASK xmm3 -#define XMM_ROWMASK xmm4 -#define XMM_ROWCOLMASK xmm5 -#define XMM_ROW xmm6 -#define XMM_COL xmm7 - -#define XMM_R3 XMM_COL - - -#endif /* __VIF_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __VIF_H__ +#define __VIF_H__ + +struct vifCycle { + u8 cl, wl; + u8 pad[2]; +}; + +struct VIFregisters { + u32 stat; + u32 pad0[3]; + u32 fbrst; + u32 pad1[3]; + u32 err; + u32 pad2[3]; + u32 mark; + u32 pad3[3]; + vifCycle cycle; //data write cycle + u32 pad4[3]; + u32 mode; + u32 pad5[3]; + u32 num; + u32 pad6[3]; + u32 mask; + u32 pad7[3]; + u32 code; + u32 pad8[3]; + u32 itops; + u32 pad9[3]; + u32 base; // Not used in VIF0 + u32 pad10[3]; + u32 ofst; // Not used in VIF0 + u32 pad11[3]; + u32 tops; // Not used in VIF0 + u32 pad12[3]; + u32 itop; + u32 pad13[3]; + u32 top; // Not used in VIF0 + u32 pad14[3]; + u32 mskpath3; + u32 pad15[3]; + u32 r0; // row0 register + u32 pad16[3]; + u32 r1; // row1 register + u32 pad17[3]; + u32 r2; // row2 register + u32 pad18[3]; + u32 r3; // row3 register + u32 pad19[3]; + u32 c0; // col0 register + u32 pad20[3]; + u32 c1; // col1 register + u32 pad21[3]; + u32 c2; // col2 register + u32 pad22[3]; + u32 c3; // col3 register + u32 pad23[3]; + u32 offset; // internal UNPACK offset + u32 addr; +}; + +extern "C" +{ + // these use cdecl for Asm code references. + extern VIFregisters *_vifRegs; + extern u32* _vifMaskRegs; + extern u32* _vifRow; + extern u32* _vifCol; +} + +#define vif0Regs ((VIFregisters*)&PS2MEM_HW[0x3800]) +#define vif1Regs ((VIFregisters*)&PS2MEM_HW[0x3c00]) + +void dmaVIF0(); +void dmaVIF1(); +void mfifoVIF1transfer(int qwc); +int VIF0transfer(u32 *data, int size, int istag); +int VIF1transfer(u32 *data, int size, int istag); +void vifMFIFOInterrupt(); + +void SetNewMask(u32* vif1masks, u32* hasmask, u32 mask, u32 oldmask); + +#define XMM_R0 xmm0 +#define XMM_R1 xmm1 +#define XMM_R2 xmm2 +#define XMM_WRITEMASK xmm3 +#define XMM_ROWMASK xmm4 +#define XMM_ROWCOLMASK xmm5 +#define XMM_ROW xmm6 +#define XMM_COL xmm7 + +#define XMM_R3 XMM_COL + + +#endif /* __VIF_H__ */ diff --git a/pcsx2/VifDma.cpp b/pcsx2/VifDma.cpp index cbb8219101..1e25761697 100644 --- a/pcsx2/VifDma.cpp +++ b/pcsx2/VifDma.cpp @@ -1,2267 +1,2267 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "Vif.h" -#include "VUmicro.h" -#include "GS.h" - -#include "VifDma.h" - -#ifdef _MSC_VER -#include -#include -#endif - -using namespace std; // for min / max - -//#define VIFUNPACKDEBUG //enable unpack debugging output - -#define gif ((DMACh*)&PS2MEM_HW[0xA000]) - -// Extern variables -extern "C" -{ - // Need cdecl on these for ASM references. - extern VIFregisters *_vifRegs; - extern u32* _vifMaskRegs; - extern u32* _vifRow; - extern u32* _vifCol; -} - -extern PCSX2_ALIGNED16_DECL(u32 g_vifRow0[4]); -extern PCSX2_ALIGNED16_DECL(u32 g_vifCol0[4]); -extern PCSX2_ALIGNED16_DECL(u32 g_vifRow1[4]); -extern PCSX2_ALIGNED16_DECL(u32 g_vifCol1[4]); - -extern vifStruct *_vif; - -vifStruct vif0, vif1; - -PCSX2_ALIGNED16(u32 g_vif1Masks[64]); -PCSX2_ALIGNED16(u32 g_vif0Masks[64]); -u32 g_vif1HasMask3[4] = {0}, g_vif0HasMask3[4] = {0}; - -// Generic constants -static const unsigned int VIF0intc = 4; -static const unsigned int VIF1intc = 5; -static const unsigned int VIF0dmanum = 0; -static const unsigned int VIF1dmanum = 1; - -int g_vifCycles = 0; -int path3hack = 0; - -typedef void (*UNPACKFUNCTYPE)( u32 *dest, u32 *data, int size ); -typedef int (*UNPACKPARTFUNCTYPESSE)( u32 *dest, u32 *data, int size ); -extern void (*Vif1CMDTLB[82])(); -extern void (*Vif0CMDTLB[75])(); -extern int (*Vif1TransTLB[128])(u32 *data); -extern int (*Vif0TransTLB[128])(u32 *data); - -struct VIFUnpackFuncTable { - UNPACKFUNCTYPE funcU; - UNPACKFUNCTYPE funcS; - - int bsize; // currently unused - int dsize; // byte size of one channel - int gsize; // size of data in bytes used for each write cycle - int qsize; // used for unpack parts, num of vectors that - // will be decompressed from data for 1 cycle -}; - -/* block size; data size; group size; qword size; */ -#define _UNPACK_TABLE32(name, bsize, dsize, gsize, qsize) \ - { UNPACK_##name, UNPACK_##name, \ - bsize, dsize, gsize, qsize }, - -#define _UNPACK_TABLE(name, bsize, dsize, gsize, qsize) \ - { UNPACK_##name##u, UNPACK_##name##s, \ - bsize, dsize, gsize, qsize }, - -// Main table for function unpacking -static const VIFUnpackFuncTable VIFfuncTable[16] = { - _UNPACK_TABLE32(S_32, 1, 4, 4, 4) // 0x0 - S-32 - _UNPACK_TABLE(S_16, 2, 2, 2, 4) // 0x1 - S-16 - _UNPACK_TABLE(S_8, 4, 1, 1, 4) // 0x2 - S-8 - { NULL, NULL, 0, 0, 0, 0 }, // 0x3 - - _UNPACK_TABLE32(V2_32, 24, 4, 8, 2) // 0x4 - V2-32 - _UNPACK_TABLE(V2_16, 12, 2, 4, 2) // 0x5 - V2-16 - _UNPACK_TABLE(V2_8, 6, 1, 2, 2) // 0x6 - V2-8 - { NULL, NULL, 0, 0, 0, 0 }, // 0x7 - - _UNPACK_TABLE32(V3_32, 36, 4, 12, 3) // 0x8 - V3-32 - _UNPACK_TABLE(V3_16, 18, 2, 6, 3) // 0x9 - V3-16 - _UNPACK_TABLE(V3_8, 9, 1, 3, 3) // 0xA - V3-8 - { NULL, NULL, 0, 0, 0, 0 }, // 0xB - - _UNPACK_TABLE32(V4_32, 48, 4, 16, 4) // 0xC - V4-32 - _UNPACK_TABLE(V4_16, 24, 2, 8, 4) // 0xD - V4-16 - _UNPACK_TABLE(V4_8, 12, 1, 4, 4) // 0xE - V4-8 - _UNPACK_TABLE32(V4_5, 6, 2, 2, 4) // 0xF - V4-5 -}; - -struct VIFSSEUnpackTable { - // regular 0, 1, 2; mask 0, 1, 2 - UNPACKPARTFUNCTYPESSE funcU[9], funcS[9]; -}; - -#define DECL_UNPACK_TABLE_SSE(name, sign) \ -extern "C" { \ - extern int UNPACK_SkippingWrite_##name##_##sign##_Regular_0(u32* dest, u32* data, int dmasize); \ - extern int UNPACK_SkippingWrite_##name##_##sign##_Regular_1(u32* dest, u32* data, int dmasize); \ - extern int UNPACK_SkippingWrite_##name##_##sign##_Regular_2(u32* dest, u32* data, int dmasize); \ - extern int UNPACK_SkippingWrite_##name##_##sign##_Mask_0(u32* dest, u32* data, int dmasize); \ - extern int UNPACK_SkippingWrite_##name##_##sign##_Mask_1(u32* dest, u32* data, int dmasize); \ - extern int UNPACK_SkippingWrite_##name##_##sign##_Mask_2(u32* dest, u32* data, int dmasize); \ - extern int UNPACK_SkippingWrite_##name##_##sign##_WriteMask_0(u32* dest, u32* data, int dmasize); \ - extern int UNPACK_SkippingWrite_##name##_##sign##_WriteMask_1(u32* dest, u32* data, int dmasize); \ - extern int UNPACK_SkippingWrite_##name##_##sign##_WriteMask_2(u32* dest, u32* data, int dmasize); \ -} - -#define _UNPACK_TABLE_SSE(name, sign) \ - UNPACK_SkippingWrite_##name##_##sign##_Regular_0, \ - UNPACK_SkippingWrite_##name##_##sign##_Regular_1, \ - UNPACK_SkippingWrite_##name##_##sign##_Regular_2, \ - UNPACK_SkippingWrite_##name##_##sign##_Mask_0, \ - UNPACK_SkippingWrite_##name##_##sign##_Mask_1, \ - UNPACK_SkippingWrite_##name##_##sign##_Mask_2, \ - UNPACK_SkippingWrite_##name##_##sign##_WriteMask_0, \ - UNPACK_SkippingWrite_##name##_##sign##_WriteMask_1, \ - UNPACK_SkippingWrite_##name##_##sign##_WriteMask_2 \ - -#define _UNPACK_TABLE_SSE_NULL \ - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL - -// Main table for function unpacking -DECL_UNPACK_TABLE_SSE(S_32, u); -DECL_UNPACK_TABLE_SSE(S_16, u); -DECL_UNPACK_TABLE_SSE(S_8, u); -DECL_UNPACK_TABLE_SSE(S_16, s); -DECL_UNPACK_TABLE_SSE(S_8, s); - -DECL_UNPACK_TABLE_SSE(V2_32, u); -DECL_UNPACK_TABLE_SSE(V2_16, u); -DECL_UNPACK_TABLE_SSE(V2_8, u); -DECL_UNPACK_TABLE_SSE(V2_16, s); -DECL_UNPACK_TABLE_SSE(V2_8, s); - -DECL_UNPACK_TABLE_SSE(V3_32, u); -DECL_UNPACK_TABLE_SSE(V3_16, u); -DECL_UNPACK_TABLE_SSE(V3_8, u); -DECL_UNPACK_TABLE_SSE(V3_16, s); -DECL_UNPACK_TABLE_SSE(V3_8, s); - -DECL_UNPACK_TABLE_SSE(V4_32, u); -DECL_UNPACK_TABLE_SSE(V4_16, u); -DECL_UNPACK_TABLE_SSE(V4_8, u); -DECL_UNPACK_TABLE_SSE(V4_16, s); -DECL_UNPACK_TABLE_SSE(V4_8, s); -DECL_UNPACK_TABLE_SSE(V4_5, u); - -static const VIFSSEUnpackTable VIFfuncTableSSE[16] = { - { _UNPACK_TABLE_SSE(S_32, u), _UNPACK_TABLE_SSE(S_32, u) }, - { _UNPACK_TABLE_SSE(S_16, u), _UNPACK_TABLE_SSE(S_16, s) }, - { _UNPACK_TABLE_SSE(S_8, u), _UNPACK_TABLE_SSE(S_8, s) }, - { _UNPACK_TABLE_SSE_NULL, _UNPACK_TABLE_SSE_NULL }, - - { _UNPACK_TABLE_SSE(V2_32, u), _UNPACK_TABLE_SSE(V2_32, u) }, - { _UNPACK_TABLE_SSE(V2_16, u), _UNPACK_TABLE_SSE(V2_16, s) }, - { _UNPACK_TABLE_SSE(V2_8, u), _UNPACK_TABLE_SSE(V2_8, s) }, - { _UNPACK_TABLE_SSE_NULL, _UNPACK_TABLE_SSE_NULL }, - - { _UNPACK_TABLE_SSE(V3_32, u), _UNPACK_TABLE_SSE(V3_32, u) }, - { _UNPACK_TABLE_SSE(V3_16, u), _UNPACK_TABLE_SSE(V3_16, s) }, - { _UNPACK_TABLE_SSE(V3_8, u), _UNPACK_TABLE_SSE(V3_8, s) }, - { _UNPACK_TABLE_SSE_NULL, _UNPACK_TABLE_SSE_NULL }, - - { _UNPACK_TABLE_SSE(V4_32, u), _UNPACK_TABLE_SSE(V4_32, u) }, - { _UNPACK_TABLE_SSE(V4_16, u), _UNPACK_TABLE_SSE(V4_16, s) }, - { _UNPACK_TABLE_SSE(V4_8, u), _UNPACK_TABLE_SSE(V4_8, s) }, - { _UNPACK_TABLE_SSE(V4_5, u), _UNPACK_TABLE_SSE(V4_5, u) }, -}; - - -__forceinline void vif0FLUSH() { - int _cycles; - _cycles = VU0.cycle; - - // fixme: this code should call _vu0WaitMicro instead? I'm not sure if - // it's purposefully ignoring ee cycles or not (see below for more) - - vu0Finish(); - g_vifCycles+= (VU0.cycle - _cycles)*BIAS; -} - -__forceinline void vif1FLUSH() { - int _cycles; - _cycles = VU1.cycle; - - // fixme: Same as above, is this a "stalling" offense? I think the cycles should - // be added to cpuRegs.cycle instead of g_vifCycles, but not sure (air) - - if( VU0.VI[REG_VPU_STAT].UL & 0x100 ) { - do { - CpuVU1.ExecuteBlock(); - } while(VU0.VI[REG_VPU_STAT].UL & 0x100); - - g_vifCycles+= (VU1.cycle - _cycles)*BIAS; - } -} - -void vifDmaInit() { -} - -__forceinline static int _limit( int a, int max ) { - return ( a > max ? max : a ); -} - -static void ProcessMemSkip(int size, unsigned int unpackType, const unsigned int VIFdmanum){ - const VIFUnpackFuncTable *unpack; - vifStruct *vif; - VIFregisters *vifRegs; - unpack = &VIFfuncTable[ unpackType ]; -// varLog |= 0x00000400; - - if (VIFdmanum == 0) - { - vif = &vif0; - vifRegs = vif0Regs; - } - else - { - vif = &vif1; - vifRegs = vif1Regs; - } - - switch(unpackType){ - case 0x0: - vif->tag.addr += size*4; - VIFUNPACK_LOG("Processing S-32 skip, size = %d\n", size); - break; - case 0x1: - vif->tag.addr += size*8; - VIFUNPACK_LOG("Processing S-16 skip, size = %d\n", size); - break; - case 0x2: - vif->tag.addr += size*16; - VIFUNPACK_LOG("Processing S-8 skip, size = %d\n", size); - break; - case 0x4: - vif->tag.addr += size + ((size / unpack->gsize) * 8); - VIFUNPACK_LOG("Processing V2-32 skip, size = %d\n", size); - break; - case 0x5: - vif->tag.addr += (size * 2) + ((size / unpack->gsize) * 8); - VIFUNPACK_LOG("Processing V2-16 skip, size = %d\n", size); - break; - case 0x6: - vif->tag.addr += (size * 4) + ((size / unpack->gsize) * 8); - VIFUNPACK_LOG("Processing V2-8 skip, size = %d\n", size); - break; - case 0x8: - vif->tag.addr += size + ((size / unpack->gsize) * 4); - VIFUNPACK_LOG("Processing V3-32 skip, size = %d\n", size); - break; - case 0x9: - vif->tag.addr += (size * 2) + ((size / unpack->gsize) * 4); - VIFUNPACK_LOG("Processing V3-16 skip, size = %d\n", size); - break; - case 0xA: - vif->tag.addr += (size * 4) + ((size / unpack->gsize) * 4); - VIFUNPACK_LOG("Processing V3-8 skip, size = %d\n", size); - break; - case 0xC: - vif->tag.addr += size; - VIFUNPACK_LOG("Processing V4-32 skip, size = %d, CL = %d, WL = %d\n", size, vif1Regs->cycle.cl, vif1Regs->cycle.wl); - break; - case 0xD: - vif->tag.addr += size * 2; - VIFUNPACK_LOG("Processing V4-16 skip, size = %d\n", size); - break; - case 0xE: - vif->tag.addr += size * 4; - VIFUNPACK_LOG("Processing V4-8 skip, size = %d\n", size); - break; - case 0xF: - vif->tag.addr += size * 8; - VIFUNPACK_LOG("Processing V4-5 skip, size = %d\n", size); - break; - default: - SysPrintf("Invalid unpack type %x\n", unpackType); - break; - } - - if((vif->tag.addr & 0xf) == unpack->gsize) { - vif->tag.addr += 16 - unpack->gsize; - } -} - -//u32 unpacktotal = 0; - -static void VIFunpack(u32 *data, vifCode *v, int size, const unsigned int VIFdmanum) { - u32 *dest; - unsigned int unpackType; - UNPACKFUNCTYPE func; - const VIFUnpackFuncTable *ft; - vifStruct *vif; - VIFregisters *vifRegs; - VURegs * VU; - u8 *cdata = (u8*)data; - //u64 basetick = GetCPUTick(); -#ifdef _DEBUG - u32 memsize = VIFdmanum ? 0x4000 : 0x1000; -#endif - -#ifdef _MSC_VER - _mm_prefetch((char*)data, _MM_HINT_NTA); -#endif - - if (VIFdmanum == 0) - { - VU = &VU0; - vif = &vif0; - vifRegs = vif0Regs; - assert( v->addr < memsize ); - //v->addr &= 0xfff; - } - else - { - - VU = &VU1; - vif = &vif1; - vifRegs = vif1Regs; - assert( v->addr < memsize ); - //v->addr &= 0x3fff; - - if( vu1MicroIsSkipping() ) { - // don't process since the frame is dummy - vif->tag.addr += (size / (VIFfuncTable[ vif->cmd & 0xf ].gsize* vifRegs->cycle.wl)) * ((vifRegs->cycle.cl - vifRegs->cycle.wl)*16); - // unpacktotal += GetCPUTick()-basetick; - return; - } - } - - dest = (u32*)(VU->Mem + v->addr); - - VIF_LOG("VIF%d UNPACK: Mode=%x, v->size=%d, size=%d, v->addr=%x\n", - VIFdmanum, v->cmd & 0xf, v->size, size, v->addr ); - -#ifdef _DEBUG - if (v->size != size) { - VIF_LOG("*PCSX2*: warning v->size != size\n"); - } - if ((v->addr+size*4) > memsize) { - SysPrintf("*PCSX2*: fixme unpack overflow\n"); - SysPrintf( "VIF%d UNPACK: Mode=%x, v->size=%d, size=%d, v->addr=%x\n", - VIFdmanum, v->cmd & 0xf, v->size, size, v->addr ); - } -#endif - // The unpack type - unpackType = v->cmd & 0xf; - - if (size == 0) { - VIFUNPACK_LOG("*PCSX2*: Unpack %x with size 0!! v->size = %d cl = %d, wl = %d, mode %d mask %x\n", v->cmd, v->size, vifRegs->cycle.cl, vifRegs->cycle.wl, vifRegs->mode, vifRegs->mask); - } - -#ifdef _MSC_VER - _mm_prefetch((char*)data+128, _MM_HINT_NTA); -#endif - _vifRegs = (VIFregisters*)vifRegs; - _vifMaskRegs = VIFdmanum ? g_vif1Masks : g_vif0Masks; - _vif = vif; - _vifRow = VIFdmanum ? g_vifRow1 : g_vifRow0; - ft = &VIFfuncTable[ unpackType ]; - func = _vif->usn ? ft->funcU : ft->funcS; - - size<<= 2; -#ifdef _DEBUG - memsize = size; -#endif - if( _vifRegs->offset > 0) { - int destinc, unpacksize; - - VIFUNPACK_LOG("aligning packet size = %d offset %d addr %x\n", size, vifRegs->offset, vif->tag.addr); - - // SSE doesn't handle such small data - if (v->size != (size>>2))ProcessMemSkip(size, unpackType, VIFdmanum); - - if(vifRegs->offset < (u32)ft->qsize){ - if(((u32)size/(u32)ft->dsize) < ((u32)ft->qsize - vifRegs->offset)){ - SysPrintf("wasnt enough left size/dsize = %x left to write %x\n", (size/ft->dsize), (ft->qsize - vifRegs->offset)); - } - unpacksize = min(((u32)size/(u32)ft->dsize), ((u32)ft->qsize - vifRegs->offset)); - } - else { - unpacksize = 0; - SysPrintf("Unpack align offset = 0\n"); - } - destinc = (4 - ft->qsize) + unpacksize; - - func(dest, (u32*)cdata, unpacksize); - size -= unpacksize*ft->dsize; - cdata += unpacksize*ft->dsize; - - vifRegs->num--; - ++vif->cl; - if (vif->cl == vifRegs->cycle.wl) { - if(vifRegs->cycle.cl != vifRegs->cycle.wl){ - dest += ((vifRegs->cycle.cl - vifRegs->cycle.wl)<<2) + destinc; - } else { - dest += destinc; - } - vif->cl = 0; - } - else { - dest += destinc; - } - VIFUNPACK_LOG("aligning packet done size = %d offset %d addr %x\n", size, vifRegs->offset, vif->tag.addr); - - } else if (v->size != (size>>2))ProcessMemSkip(size, unpackType, VIFdmanum); - - if (vifRegs->cycle.cl >= vifRegs->cycle.wl) { // skipping write - -#ifdef _DEBUG - static int s_count=0; -#endif - - int incdest; - - if( vif->cl != 0 ) { - // continuation from last stream - - incdest = ((vifRegs->cycle.cl - vifRegs->cycle.wl)<<2) + 4; - while (size >= ft->gsize && vifRegs->num > 0) { - func( dest, (u32*)cdata, ft->qsize); - cdata += ft->gsize; - size -= ft->gsize; - - vifRegs->num--; - ++vif->cl; - if (vif->cl == vifRegs->cycle.wl) { - dest += incdest; - vif->cl = 0; - break; - } - - dest += 4; - } - - // have to update - _vifRow[0] = _vifRegs->r0; - _vifRow[1] = _vifRegs->r1; - _vifRow[2] = _vifRegs->r2; - _vifRow[3] = _vifRegs->r3; - - } - - if( size >= ft->gsize && !(v->addr&0xf)) { - const UNPACKPARTFUNCTYPESSE* pfn; - int writemask; - //static LARGE_INTEGER lbase, lfinal; - //QueryPerformanceCounter(&lbase); - u32 oldcycle = -1; - -// u16 tempdata[4] = { 0x8000, 0x7fff, 0x1010, 0xd0d0 }; -// vifRegs->cycle.cl = 4; -// vifRegs->cycle.wl = 1; -// SetNewMask(g_vif1Masks, g_vif1HasMask3, 0x3f, ~0x3f); -// memset(dest, 0xcd, 64*4); -// VIFfuncTableSSE[1].funcS[6](dest, (u32*)tempdata, 8); - -#ifdef _MSC_VER - if( VIFdmanum ) { - __asm movaps XMM_ROW, xmmword ptr [g_vifRow1] - __asm movaps XMM_COL, xmmword ptr [g_vifCol1] - } - else { - __asm movaps XMM_ROW, xmmword ptr [g_vifRow0] - __asm movaps XMM_COL, xmmword ptr [g_vifCol0] - } -#else - if( VIFdmanum ) { - __asm__(".intel_syntax\n" - "movaps %%xmm6, xmmword ptr [%0]\n" - "movaps %%xmm7, xmmword ptr [%1]\n" - ".att_syntax\n" : :"r"(g_vifRow1), "r"(g_vifCol1) ); - } - else { - __asm__(".intel_syntax\n" - "movaps %%xmm6, xmmword ptr [%0]\n" - "movaps %%xmm7, xmmword ptr [%1]\n" - ".att_syntax\n" : : "r"(g_vifRow0), "r"(g_vifCol0) ); - } -#endif - - if( vifRegs->cycle.cl == 0 || vifRegs->cycle.wl == 0 || (vifRegs->cycle.cl == vifRegs->cycle.wl && !(vifRegs->code&0x10000000)) ) { - oldcycle = *(u32*)&vifRegs->cycle; - vifRegs->cycle.cl = vifRegs->cycle.wl = 1; - } - size = min(size, (int)vifRegs->num*ft->gsize); //size will always be the same or smaller - - pfn = vif->usn ? VIFfuncTableSSE[unpackType].funcU: VIFfuncTableSSE[unpackType].funcS; - writemask = VIFdmanum ? g_vif1HasMask3[min(vifRegs->cycle.wl,(u8)3)] : g_vif0HasMask3[min(vifRegs->cycle.wl,(u8)3)]; - writemask = pfn[(((vifRegs->code & 0x10000000)>>28)<mode](dest, (u32*)cdata, size); - - if( oldcycle != -1 ) *(u32*)&vifRegs->cycle = oldcycle; - - // if size is left over, update the src,dst pointers - if( writemask > 0 ) { - int left = (size-writemask)/ft->gsize; - cdata += left * ft->gsize; - dest = (u32*)((u8*)dest + ((left/vifRegs->cycle.wl)*vifRegs->cycle.cl + left%vifRegs->cycle.wl)*16); - vifRegs->num -= left; - _vif->cl = (size % (ft->gsize*vifRegs->cycle.wl)) / ft->gsize; - } - else { - vifRegs->num -= size/ft->gsize; - if(vifRegs->num > 0) _vif->cl = (size % (ft->gsize*vifRegs->cycle.wl)) / ft->gsize; - } - - size = writemask; - - _vifRegs->r0 = _vifRow[0]; - _vifRegs->r1 = _vifRow[1]; - _vifRegs->r2 = _vifRow[2]; - _vifRegs->r3 = _vifRow[3]; - //QueryPerformanceCounter(&lfinal); - //((LARGE_INTEGER*)g_nCounters)->QuadPart += lfinal.QuadPart - lbase.QuadPart; - } - else - { - - if(unpackType == 0xC && vifRegs->cycle.cl == vifRegs->cycle.wl) { //No use when SSE is available - // v4-32 - if(vifRegs->mode == 0 && !(vifRegs->code & 0x10000000) && vif->usn == 0){ - vifRegs->num -= size>>4; - memcpy_fast((u8*)dest, cdata, size); - size = 0; - return; - } - } - - incdest = ((vifRegs->cycle.cl - vifRegs->cycle.wl)<<2) + 4; - - while (size >= ft->gsize && vifRegs->num > 0) { - func( dest, (u32*)cdata, ft->qsize); - cdata += ft->gsize; - size -= ft->gsize; - - vifRegs->num--; - ++vif->cl; - if (vif->cl == vifRegs->cycle.wl) { - dest += incdest; - vif->cl = 0; - } - else - { - dest += 4; - } - } - - // have to update - _vifRow[0] = _vifRegs->r0; - _vifRow[1] = _vifRegs->r1; - _vifRow[2] = _vifRegs->r2; - _vifRow[3] = _vifRegs->r3; - } - - // used for debugging vif -// { -// int i, j, k; -// u32* curdest = olddest; -// FILE* ftemp = fopen("temp.txt", s_count?"a+":"w"); -// fprintf(ftemp, "%x %x %x\n", s_count, size, vif->tag.addr); -// fprintf(ftemp, "%x %x %x\n", vifRegs->code>>24, vifRegs->mode, *(u32*)&vifRegs->cycle); -// fprintf(ftemp, "row: %x %x %x %x\n", _vifRow[0], _vifRow[1], _vifRow[2], _vifRow[3]); -// //fprintf(ftemp, "row2: %x %x %x %x\n", _vifRegs->r0, _vifRegs->r1, _vifRegs->r2, _vifRegs->r3); -// -// for(i = 0; i < memsize; ) { -// for(k = 0; k < vifRegs->cycle.wl; ++k) { -// for(j = 0; j <= ((vifRegs->code>>26)&3); ++j) { -// fprintf(ftemp, "%x ", curdest[4*k+j]); -// } -// } -// -// fprintf(ftemp, "\n"); -// curdest += 4*vifRegs->cycle.cl; -// i += (((vifRegs->code>>26)&3)+1)*ft->dsize*vifRegs->cycle.wl; -// } -// fclose(ftemp); -// } -// s_count++; - - if( size >= ft->dsize && vifRegs->num > 0) { - //VIF_LOG("warning, end with size = %d\n", size); - - /* unpack one qword */ - func(dest, (u32*)cdata, size / ft->dsize); - size = 0; - - VIFUNPACK_LOG("leftover done, size %d, vifnum %d, addr %x\n", size, vifRegs->num, vif->tag.addr); - } - - } - else { /* filling write */ - VIF_LOG("*PCSX2*: filling write\n"); - - VIFUNPACK_LOG("filling write %d cl %d, wl %d mask %x mode %x unpacktype %x\n", vifRegs->num, vifRegs->cycle.cl, vifRegs->cycle.wl, vifRegs->mask, vifRegs->mode, unpackType); - while (size >= ft->gsize || vifRegs->num > 0) { - if (vif->cl == vifRegs->cycle.wl) { - vif->cl = 0; - } - // - if (vif->cl < vifRegs->cycle.cl) { /* unpack one qword */ - func( dest, (u32*)cdata, ft->qsize); - cdata += ft->gsize; - size -= ft->gsize; - vif->cl++; - vifRegs->num--; - if (vif->cl == vifRegs->cycle.wl) { - vif->cl = 0; - } - } - else - { - func( dest, (u32*)cdata, ft->qsize); - vif->tag.addr += 16; - vifRegs->num--; - ++vif->cl; - - } - dest += 4; - if(vifRegs->num == 0) break; - } - } -} - -static void vuExecMicro( u32 addr, const u32 VIFdmanum ) -{ - int _cycles; - VURegs * VU; - //void (*_vuExecMicro)(); - -// MessageBox(NULL, "3d doesn't work\n", "Query", MB_OK); -// return; - - if (VIFdmanum == 0) { - VU = &VU0; - vif0FLUSH(); - } else { - VU = &VU1; - vif1FLUSH(); - } - if(VU->vifRegs->itops > (VIFdmanum ? 0x3ffu : 0xffu)) - SysPrintf("VIF%d ITOP overrun! %x\n", VIFdmanum, VU->vifRegs->itops); - - VU->vifRegs->itop = VU->vifRegs->itops; - - if (VIFdmanum == 1) { - /* in case we're handling a VIF1 execMicro - set the top with the tops value */ - VU->vifRegs->top = VU->vifRegs->tops & 0x3ff; - - /* is DBF flag set in VIF_STAT? */ - if (VU->vifRegs->stat & 0x80) { - /* it is, so set tops with base + ofst - and clear stat DBF flag */ - VU->vifRegs->tops = VU->vifRegs->base; - VU->vifRegs->stat &= ~0x80; - } else { - /* it is not, so set tops with base - and set the stat DBF flag */ - VU->vifRegs->tops = VU->vifRegs->base + VU->vifRegs->ofst; - VU->vifRegs->stat |= 0x80; - } - } - - if (VIFdmanum == 0) { - _cycles = VU0.cycle; - vu0ExecMicro(addr); - // too much delay - //g_vifCycles+= (VU0.cycle - _cycles)*BIAS; - } else { - _cycles = VU1.cycle; - vu1ExecMicro(addr); - // too much delay - //g_vifCycles+= (VU1.cycle - _cycles)*BIAS; - } -} - -u8 s_maskwrite[256]; -void vif0Init() -{ - - u32 i; - - for(i = 0; i < 256; ++i ) { - s_maskwrite[i] = ((i&3)==3)||((i&0xc)==0xc)||((i&0x30)==0x30)||((i&0xc0)==0xc0); - } - - SetNewMask(g_vif0Masks, g_vif0HasMask3, 0, 0xffffffff); -} - -static __forceinline void vif0UNPACK(u32 *data) { - int vifNum; - int vl, vn; - int len; - - if(vif0Regs->cycle.wl == 0 && vif0Regs->cycle.wl < vif0Regs->cycle.cl){ - SysPrintf("Vif0 CL %d, WL %d\n", vif0Regs->cycle.cl, vif0Regs->cycle.wl); - vif0.cmd &= ~0x7f; - return; - } - - vif0FLUSH(); - - vl = (vif0.cmd ) & 0x3; - vn = (vif0.cmd >> 2) & 0x3; - vif0.tag.addr = (vif0Regs->code & 0x3ff) << 4; - vif0.usn = (vif0Regs->code >> 14) & 0x1; - vifNum = (vif0Regs->code >> 16) & 0xff; - if ( vifNum == 0 ) vifNum = 256; - vif0Regs->num = vifNum; - - if ( vif0Regs->cycle.wl <= vif0Regs->cycle.cl ) { - len = ((( 32 >> vl ) * ( vn + 1 )) * vifNum + 31) >> 5; - } else { - int n = vif0Regs->cycle.cl * (vifNum / vif0Regs->cycle.wl) + - _limit( vifNum % vif0Regs->cycle.wl, vif0Regs->cycle.cl ); - - len = ( ((( 32 >> vl ) * ( vn + 1 )) * n) + 31 ) >> 5; - } - - vif0.wl = 0; vif0.cl = 0; - vif0.tag.cmd = vif0.cmd; - vif0.tag.addr &= 0xfff; - vif0.tag.size = len; - vif0Regs->offset = 0; -} - -static __forceinline void _vif0mpgTransfer(u32 addr, u32 *data, int size) { -/* SysPrintf("_vif0mpgTransfer addr=%x; size=%x\n", addr, size); - { - FILE *f = fopen("vu1.raw", "wb"); - fwrite(data, 1, size*4, f); - fclose(f); - }*/ - if (memcmp(VU0.Micro + addr, data, size << 2)) { - CpuVU0.Clear(addr, size << 2); // Clear before writing! :/ (cottonvibes) - memcpy_fast(VU0.Micro + addr, data, size << 2); - } -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Vif1 Data Transfer Commands -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -static int Vif0TransNull(u32 *data){ // Shouldnt go here - SysPrintf("VIF0 Shouldnt go here CMD = %x\n", vif0Regs->code); - vif0.cmd = 0; - return 0; -} -static int Vif0TransSTMask(u32 *data){ // STMASK - SetNewMask(g_vif0Masks, g_vif0HasMask3, data[0], vif0Regs->mask); - vif0Regs->mask = data[0]; - VIF_LOG("STMASK == %x\n", vif0Regs->mask); - - vif0.tag.size = 0; - vif0.cmd = 0; - return 1; -} - -static int Vif0TransSTRow(u32 *data){ // STROW - int ret; - - u32* pmem = &vif0Regs->r0+(vif0.tag.addr<<2); - u32* pmem2 = g_vifRow0+vif0.tag.addr; - assert( vif0.tag.addr < 4 ); - ret = min(4-vif0.tag.addr, vif0.vifpacketsize); - assert( ret > 0 ); - switch(ret) { - case 4: pmem[12] = data[3]; pmem2[3] = data[3]; - case 3: pmem[8] = data[2]; pmem2[2] = data[2]; - case 2: pmem[4] = data[1]; pmem2[1] = data[1]; - case 1: pmem[0] = data[0]; pmem2[0] = data[0]; break; - - jNO_DEFAULT - } - vif0.tag.addr += ret; - vif0.tag.size -= ret; - if(vif0.tag.size == 0) vif0.cmd = 0; - - return ret; -} - -static int Vif0TransSTCol(u32 *data){ // STCOL - int ret; - - u32* pmem = &vif0Regs->c0+(vif0.tag.addr<<2); - u32* pmem2 = g_vifCol0+vif0.tag.addr; - ret = min(4-vif0.tag.addr, vif0.vifpacketsize); - switch(ret) { - case 4: pmem[12] = data[3]; pmem2[3] = data[3]; - case 3: pmem[8] = data[2]; pmem2[2] = data[2]; - case 2: pmem[4] = data[1]; pmem2[1] = data[1]; - case 1: pmem[0] = data[0]; pmem2[0] = data[0]; break; - - jNO_DEFAULT - } - vif0.tag.addr += ret; - vif0.tag.size -= ret; - if(vif0.tag.size == 0) vif0.cmd = 0; - return ret; -} - -static int Vif0TransMPG(u32 *data){ // MPG - if (vif0.vifpacketsize < vif0.tag.size) { - _vif0mpgTransfer(vif0.tag.addr, data, vif0.vifpacketsize); - vif0.tag.addr += vif0.vifpacketsize << 2; - vif0.tag.size -= vif0.vifpacketsize; - return vif0.vifpacketsize; - } else { - int ret; - _vif0mpgTransfer(vif0.tag.addr, data, vif0.tag.size); - ret = vif0.tag.size; - vif0.tag.size = 0; - vif0.cmd = 0; - return ret; - } -} - -static int Vif0TransUnpack(u32 *data){ // UNPACK - FreezeXMMRegs(1); - if (vif0.vifpacketsize < vif0.tag.size) { - /* size is less that the total size, transfer is - 'in pieces' */ - VIFunpack(data, &vif0.tag, vif0.vifpacketsize, VIF0dmanum); - vif0.tag.size -= vif0.vifpacketsize; - FreezeXMMRegs(0); - return vif0.vifpacketsize; - } else { - int ret; - /* we got all the data, transfer it fully */ - VIFunpack(data, &vif0.tag, vif0.tag.size, VIF0dmanum); - ret = vif0.tag.size; - vif0.tag.size = 0; - vif0.cmd = 0; - FreezeXMMRegs(0); - return ret; - } - -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Vif0 CMD Base Commands -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -static void Vif0CMDNop(){ // NOP - vif0.cmd &= ~0x7f; -} - -static void Vif0CMDSTCycl(){ // STCYCL - vif0Regs->cycle.cl = (u8)vif0Regs->code; - vif0Regs->cycle.wl = (u8)(vif0Regs->code >> 8); - vif0.cmd &= ~0x7f; -} - -static void Vif0CMDITop(){ // ITOP - vif0Regs->itops = vif0Regs->code & 0x3ff; - vif0.cmd &= ~0x7f; -} - -static void Vif0CMDSTMod(){ // STMOD - vif0Regs->mode = vif0Regs->code & 0x3; - vif0.cmd &= ~0x7f; -} - -static void Vif0CMDMark(){ // MARK - vif0Regs->mark = (u16)vif0Regs->code; - vif0Regs->stat |= VIF0_STAT_MRK; - vif0.cmd &= ~0x7f; -} - -static void Vif0CMDFlushE(){ // FLUSHE - vif0FLUSH(); - vif0.cmd &= ~0x7f; -} - -static void Vif0CMDMSCALF(){ //MSCAL/F - vuExecMicro( (u16)(vif0Regs->code) << 3, VIF0dmanum ); - vif0.cmd &= ~0x7f; -} - -static void Vif0CMDMSCNT(){ // MSCNT - vuExecMicro( -1, VIF0dmanum ); - vif0.cmd &= ~0x7f; -} - -static void Vif0CMDSTMask(){ // STMASK - vif0.tag.size = 1; -} - -static void Vif0CMDSTRowCol(){// STROW / STCOL - vif0.tag.addr = 0; - vif0.tag.size = 4; -} - -static void Vif0CMDMPGTransfer(){ // MPG - int vifNum; - vif0FLUSH(); - vifNum = (u8)(vif0Regs->code >> 16); - if (vifNum == 0) vifNum = 256; - vif0.tag.addr = (u16)((vif0Regs->code) << 3) & 0xfff; - vif0.tag.size = vifNum * 2; -} - -static void Vif0CMDNull(){ // invalid opcode - // if ME1, then force the vif to interrupt - if ((vif0Regs->err & 0x4) == 0) { //Ignore vifcode and tag mismatch error - SysPrintf( "UNKNOWN VifCmd: %x\n", vif0.cmd ); - vif0Regs->stat |= 1 << 13; - vif0.irq++; - } - vif0.cmd &= ~0x7f; -} - -int VIF0transfer(u32 *data, int size, int istag) { - int ret; - int transferred=vif0.vifstalled ? vif0.irqoffset : 0; // irqoffset necessary to add up the right qws, or else will spin (spiderman) - VIF_LOG( "VIF0transfer: size %x (vif0.cmd %x)\n", size, vif0.cmd ); - - vif0.stallontag = 0; - vif0.vifstalled = 0; - vif0.vifpacketsize = size; - - while (vif0.vifpacketsize > 0) { - - if (vif0.cmd) { - vif0Regs->stat |= VIF0_STAT_VPS_T; //Decompression has started - } - - if (vif0.cmd) { - ret = Vif0TransTLB[(vif0.cmd & 0x7f)](data); - data+= ret; vif0.vifpacketsize-= ret; - if(vif0.cmd == 0) vif0Regs->stat &= ~VIF0_STAT_VPS_T; //We are once again waiting for a new vifcode as the command has cleared - continue; - } - - - - if(vif0.tag.size != 0) SysPrintf("no vif0 cmd but tag size is left last cmd read %x\n", vif0Regs->code); - // if interrupt and new cmd is NOT MARK - if(vif0.irq) break; - - vif0.cmd = (data[0] >> 24); - vif0Regs->code = data[0]; - - vif0Regs->stat |= VIF0_STAT_VPS_D; //We need to set these (Onimusha needs it) - - if ((vif0.cmd & 0x60) == 0x60) { - vif0UNPACK(data); - } else { - VIF_LOG( "VIFtransfer: cmd %x, num %x, imm %x, size %x\n", vif0.cmd, (data[0] >> 16) & 0xff, data[0] & 0xffff, size ); - - if((vif0.cmd & 0x7f) > 0x4A){ - if ((vif0Regs->err & 0x4) == 0) { //Ignore vifcode and tag mismatch error - SysPrintf( "UNKNOWN VifCmd: %x\n", vif0.cmd ); - vif0Regs->stat |= 1 << 13; - vif0.irq++; - } - vif0.cmd = 0; - } else Vif0CMDTLB[(vif0.cmd & 0x7f)](); - } - ++data; - --vif0.vifpacketsize; - - if ((vif0.cmd & 0x80)) { //i bit on vifcode and not masked by VIF0_ERR - if(!(vif0Regs->err & 0x1)){ - VIF_LOG( "Interrupt on VIFcmd: %x (INTC_MASK = %x)\n", vif0.cmd, psHu32(INTC_MASK) ); - - ++vif0.irq; - if(istag && vif0.tag.size <= vif0.vifpacketsize) vif0.stallontag = 1; - } - vif0.cmd &= 0x7f; - if(vif0.tag.size == 0) break; - } - } - transferred += size - vif0.vifpacketsize; - g_vifCycles+= (transferred >> 2)*BIAS; /* guessing */ - // use tag.size because some game doesn't like .cmd - //if( !vif0.cmd ) - - if (vif0.irq && vif0.tag.size == 0) { - vif0.vifstalled = 1; - - if(((vif0Regs->code >> 24) & 0x7f) != 0x7)vif0Regs->stat|= VIF0_STAT_VIS; - //else SysPrintf("VIF0 IRQ on MARK\n"); - // spiderman doesn't break on qw boundaries - vif0.irqoffset = transferred%4; // cannot lose the offset - - if( istag ) { - return -2; - } - - transferred = transferred >> 2; - vif0ch->madr+= (transferred << 4); - vif0ch->qwc-= transferred; - //SysPrintf("Stall on vif0, FromSPR = %x, Vif0MADR = %x Sif0MADR = %x STADR = %x\n", psHu32(0x1000d010), vif0ch->madr, psHu32(0x1000c010), psHu32(DMAC_STADR)); - return -2; - } - - vif0Regs->stat &= ~VIF0_STAT_VPS; //Vif goes idle as the stall happened between commands; - if( vif0.cmd ) vif0Regs->stat |= VIF0_STAT_VPS_W; //Otherwise we wait for the data - - if( !istag ) { - transferred = transferred >> 2; - vif0ch->madr+= (transferred << 4); - vif0ch->qwc-= transferred; - } - - return 0; -} - -int _VIF0chain() { - u32 *pMem; - u32 ret; - - //Hmm, it seems some games (Fatal Frame and Twisted Metal) Try to force the VIF to stop whatever its doing and do something else - //Okay... so in that case we will tell the vif to do so (Refraction) - if (vif0ch->qwc == 0 && vif0.vifstalled == 0) { - vif0Regs->stat &= ~VIF0_STAT_VPS; - vif0.cmd = 0; - vif0.tag.size = 0; - return 0; - } - - pMem = (u32*)dmaGetAddr(vif0ch->madr); - if (pMem == NULL) - return -1; - - if( vif0.vifstalled ) { - ret = VIF0transfer(pMem+vif0.irqoffset, vif0ch->qwc*4-vif0.irqoffset, 0); - } - else { - ret = VIF0transfer(pMem, vif0ch->qwc*4, 0); - } - - return ret; -} - -u32 *vif0ptag; - -int _chainVIF0() { - int id; - //int done=0; - int ret; - - vif0ptag = (u32*)dmaGetAddr(vif0ch->tadr); //Set memory pointer to TADR - if (vif0ptag == NULL) { //Is vif0ptag empty? - SysPrintf("Vif0 Tag BUSERR\n"); - vif0ch->chcr = ( vif0ch->chcr & 0xFFFF ) | ( (*vif0ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 - psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register - return -1; //Return -1 as an error has occurred - } - - id = (vif0ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag - vif0ch->qwc = (u16)vif0ptag[0]; //QWC set to lower 16bits of the tag - vif0ch->madr = vif0ptag[1]; //MADR = ADDR field - g_vifCycles+=1; // Add 1 g_vifCycles from the QW read for the tag - VIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx\n", - vif0ptag[1], vif0ptag[0], vif0ch->qwc, id, vif0ch->madr, vif0ch->tadr); - - vif0ch->chcr = ( vif0ch->chcr & 0xFFFF ) | ( (*vif0ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 - // Transfer dma tag if tte is set - - if (vif0ch->chcr & 0x40) { - if(vif0.vifstalled == 1) ret = VIF0transfer(vif0ptag+(2+vif0.irqoffset), 2-vif0.irqoffset, 1); //Transfer Tag on stall - else ret = VIF0transfer(vif0ptag+2, 2, 1); //Transfer Tag - if (ret == -1) return -1; //There has been an error - if (ret == -2) { - return -2; //IRQ set by VIFTransfer - } - } - - vif0.done |= hwDmacSrcChainWithStack(vif0ch, id); - - VIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx\n", - vif0ptag[1], vif0ptag[0], vif0ch->qwc, id, vif0ch->madr, vif0ch->tadr); - - - ret = _VIF0chain(); //Transfers the data set by the switch - - - if ((vif0ch->chcr & 0x80) && (vif0ptag[0] >> 31)) { //Check TIE bit of CHCR and IRQ bit of tag - VIF_LOG( "dmaIrq Set\n" ); - - vif0.done = 1; - return vif0.done; //End Transfer - } - return vif0.done; //Return Done -} - -void vif0Interrupt() { -// int ret; - g_vifCycles = 0; //Reset the cycle count, Wouldnt reset on stall if put lower down. - VIF_LOG("vif0Interrupt: %8.8x\n", cpuRegs.cycle); - - - if(vif0.irq && vif0.tag.size == 0) { - vif0Regs->stat|= VIF0_STAT_INT; - hwIntcIrq(VIF0intc); - --vif0.irq; - - if (vif0Regs->stat & (VIF0_STAT_VSS|VIF0_STAT_VIS|VIF0_STAT_VFS)) - { - vif0Regs->stat&= ~0xF000000; // FQC=0 - vif0ch->chcr &= ~0x100; - return; - } - if(vif0ch->qwc > 0 || vif0.irqoffset > 0){ - if(vif0.stallontag == 1) { - _chainVIF0(); - } - else _VIF0chain(); - CPU_INT(0, g_vifCycles); - return; - } - } - - - if((vif0ch->chcr & 0x100) == 0) SysPrintf("Vif0 running when CHCR = %x\n", vif0ch->chcr); - - - if (vif0ch->chcr & 0x4 && vif0.done == 0 && vif0.vifstalled == 0) { - - if( !(psHu32(DMAC_CTRL) & 0x1) ) { - SysPrintf("vif0 dma masked\n"); - return; - } - - if(vif0ch->qwc > 0) _VIF0chain(); - else _chainVIF0(); - CPU_INT(0, g_vifCycles); - return; - } - - - if(vif0ch->qwc > 0) SysPrintf("VIF0 Ending with QWC left\n"); - if(vif0.cmd != 0) SysPrintf("vif0.cmd still set %x\n", vif0.cmd); - vif0ch->chcr &= ~0x100; - hwDmacIrq(DMAC_VIF0); - vif0Regs->stat&= ~0xF000000; // FQC=0 - -} - -// Vif1 Data Transfer Table -int (*Vif0TransTLB[128])(u32 *data) = -{ - Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x7*/ - Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0xF*/ - Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x17*/ - Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x1F*/ - Vif0TransSTMask , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x27*/ - Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x2F*/ - Vif0TransSTRow , Vif0TransSTCol , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x37*/ - Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x3F*/ - Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x47*/ - Vif0TransNull , Vif0TransNull , Vif0TransMPG , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x4F*/ - Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x57*/ - Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x5F*/ - Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransNull , /*0x67*/ - Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , /*0x6F*/ - Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransNull , /*0x77*/ - Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransNull , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack /*0x7F*/ -}; - -// Vif1 CMD Table -void (*Vif0CMDTLB[75])() = -{ - Vif0CMDNop , Vif0CMDSTCycl , Vif0CMDNull , Vif0CMDNull , Vif0CMDITop , Vif0CMDSTMod , Vif0CMDNull, Vif0CMDMark , /*0x7*/ - Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0xF*/ - Vif0CMDFlushE , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull, Vif0CMDMSCALF, Vif0CMDMSCALF, Vif0CMDNull , Vif0CMDMSCNT, /*0x17*/ - Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x1F*/ - Vif0CMDSTMask , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x27*/ - Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x2F*/ - Vif0CMDSTRowCol, Vif0CMDSTRowCol, Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x37*/ - Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x3F*/ - Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x47*/ - Vif0CMDNull , Vif0CMDNull , Vif0CMDMPGTransfer -}; - -void dmaVIF0() { - VIF_LOG("dmaVIF0 chcr = %lx, madr = %lx, qwc = %lx\n" - " tadr = %lx, asr0 = %lx, asr1 = %lx\n", - vif0ch->chcr, vif0ch->madr, vif0ch->qwc, - vif0ch->tadr, vif0ch->asr0, vif0ch->asr1 ); - - if(vif0.done == 0) { - SysPrintf("VIF0 Double DMA issue, ignoring\n"); - return; - } - - g_vifCycles = 0; - - - vif0Regs->stat|= 0x8000000; // FQC=8 - - if (!(vif0ch->chcr & 0x4) || vif0ch->qwc > 0) { // Normal Mode - if(_VIF0chain() == -2) { - SysPrintf("Stall on normal %x\n", vif0Regs->stat); - vif0.vifstalled = 1; - return; - } - vif0.done = 1; - CPU_INT(0, g_vifCycles); - return; - } - - // Chain Mode - vif0.done = 0; - CPU_INT(0, 0); -} - - -void vif0Write32(u32 mem, u32 value) { - if (mem == 0x10003830) { // MARK - VIF_LOG("VIF0_MARK write32 0x%8.8x\n", value); - - /* Clear mark flag in VIF0_STAT and set mark with 'value' */ - vif0Regs->stat&= ~VIF0_STAT_MRK; - vif0Regs->mark = value; - } else - if (mem == 0x10003810) { // FBRST - VIF_LOG("VIF0_FBRST write32 0x%8.8x\n", value); - - if (value & 0x1) { - /* Reset VIF */ - //SysPrintf("Vif0 Reset %x\n", vif0Regs->stat); - memzero_obj(vif0); - vif0ch->qwc = 0; //? - cpuRegs.interrupt &= ~1; //Stop all vif0 DMA's - psHu64(0x10004000) = 0; - psHu64(0x10004008) = 0; - vif0.done = 1; - vif0Regs->err = 0; - vif0Regs->stat&= ~(0xF000000|VIF0_STAT_INT|VIF0_STAT_VSS|VIF0_STAT_VIS|VIF0_STAT_VFS|VIF0_STAT_VPS); // FQC=0 - } - if (value & 0x2) { - /* Force Break the VIF */ - /* I guess we should stop the VIF dma here - but not 100% sure (linuz) */ - cpuRegs.interrupt &= ~1; //Stop all vif0 DMA's - vif0Regs->stat |= VIF0_STAT_VFS; - vif0Regs->stat &= ~VIF0_STAT_VPS; - vif0.vifstalled = 1; - SysPrintf("vif0 force break\n"); - } - if (value & 0x4) { - /* Stop VIF */ - /* Not completly sure about this, can't remember what game - used this, but 'draining' the VIF helped it, instead of - just stoppin the VIF (linuz) */ - vif0Regs->stat |= VIF0_STAT_VSS; - vif0Regs->stat &= ~VIF0_STAT_VPS; - vif0.vifstalled = 1; - } - if (value & 0x8) { - int cancel = 0; - - /* Cancel stall, first check if there is a stall to cancel, - and then clear VIF0_STAT VSS|VFS|VIS|INT|ER0|ER1 bits */ - if (vif0Regs->stat & (VIF0_STAT_VSS|VIF0_STAT_VIS|VIF0_STAT_VFS)) { - cancel = 1; - } - - vif0Regs->stat &= ~(VIF0_STAT_VSS | VIF0_STAT_VFS | VIF0_STAT_VIS | - VIF0_STAT_INT | VIF0_STAT_ER0 | VIF0_STAT_ER1); - if (cancel) { - - if( vif0.vifstalled ) { - g_vifCycles = 0; - // loop necessary for spiderman - if(vif0.stallontag == 1){ - _chainVIF0(); - } else _VIF0chain(); - - vif0ch->chcr |= 0x100; - CPU_INT(0, g_vifCycles); // Gets the timing right - Flatout - } - } - } - } else - if (mem == 0x10003820) { // ERR - VIF_LOG("VIF0_ERR write32 0x%8.8x\n", value); - - /* Set VIF0_ERR with 'value' */ - vif0Regs->err = value; - } else{ - SysPrintf("Unknown Vif0 write to %x\n", mem); - if( mem >= 0x10003900 && mem < 0x10003980 ) { - - assert( (mem&0xf) == 0 ); - if( mem < 0x10003940 ) g_vifRow0[(mem>>4)&3] = value; - else g_vifCol0[(mem>>4)&3] = value; - } else psHu32(mem) = value; - } - - /* Other registers are read-only so do nothing for them */ -} - -void vif0Reset() { - /* Reset the whole VIF, meaning the internal pcsx2 vars - and all the registers */ - memzero_obj(vif0); - memzero_obj(*vif0Regs); - SetNewMask(g_vif0Masks, g_vif0HasMask3, 0, 0xffffffff); - psHu64(0x10004000) = 0; - psHu64(0x10004008) = 0; - vif0Regs->stat &= ~VIF0_STAT_VPS; - vif0.done = 1; - vif0Regs->stat&= ~0xF000000; // FQC=0 -} - -void SaveState::vif0Freeze() { - Freeze(vif0); - if( IsLoading() ) - SetNewMask(g_vif0Masks, g_vif0HasMask3, vif0Regs->mask, ~vif0Regs->mask); -} - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - - -void vif1Init() { - SetNewMask(g_vif1Masks, g_vif1HasMask3, 0, 0xffffffff); -} - -static __forceinline void vif1UNPACK(u32 *data) { - int vifNum; - int vl, vn; - //int len; - if(vif1Regs->cycle.wl == 0){ - if(vif1Regs->cycle.wl < vif1Regs->cycle.cl){ - SysPrintf("Vif1 CL %d, WL %d\n", vif1Regs->cycle.cl, vif1Regs->cycle.wl); - vif1.cmd &= ~0x7f; - return; -} - } - vif1FLUSH(); - - vl = (vif1.cmd ) & 0x3; - vn = (vif1.cmd >> 2) & 0x3; - - vif1.usn = (vif1Regs->code >> 14) & 0x1; - vifNum = (vif1Regs->code >> 16) & 0xff; - if ( vifNum == 0 ) vifNum = 256; - vif1Regs->num = vifNum; - - if ( vif1Regs->cycle.wl <= vif1Regs->cycle.cl ) { - vif1.tag.size = ((( 32 >> vl ) * ( vn + 1 )) * vifNum + 31) >> 5; - } else { - int n = vif1Regs->cycle.cl * (vifNum / vif1Regs->cycle.wl) + - _limit( vifNum % vif1Regs->cycle.wl, vif1Regs->cycle.cl ); - vif1.tag.size = ( ((( 32 >> vl ) * ( vn + 1 )) * n) + 31 ) >> 5; - } - if ( ( vif1Regs->code >> 15) & 0x1 ) { - vif1.tag.addr = (vif1Regs->code + vif1Regs->tops) & 0x3ff; - } else vif1.tag.addr = vif1Regs->code & 0x3ff; - - vif1.cl = 0; - vif1.tag.addr <<= 4; - - vif1.tag.cmd = vif1.cmd; -} - -static __forceinline void _vif1mpgTransfer(u32 addr, u32 *data, int size) { -/* SysPrintf("_vif1mpgTransfer addr=%x; size=%x\n", addr, size); - { - FILE *f = fopen("vu1.raw", "wb"); - fwrite(data, 1, size*4, f); - fclose(f); - }*/ - assert( VU1.Micro > 0 ); - if (memcmp(VU1.Micro + addr, data, size << 2)) { - CpuVU1.Clear(addr, size << 2); // Clear before writing! :/ - memcpy_fast(VU1.Micro + addr, data, size << 2); - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Vif1 Data Transfer Commands -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -static int Vif1TransNull(u32 *data){ // Shouldnt go here - SysPrintf("Shouldnt go here CMD = %x\n", vif1Regs->code); - vif1.cmd = 0; - return 0; -} -static int Vif1TransSTMask(u32 *data){ // STMASK - SetNewMask(g_vif1Masks, g_vif1HasMask3, data[0], vif1Regs->mask); - vif1Regs->mask = data[0]; - VIF_LOG("STMASK == %x\n", vif1Regs->mask); - - vif1.tag.size = 0; - vif1.cmd = 0; - return 1; -} - -static int Vif1TransSTRow(u32 *data){ - int ret; - - u32* pmem = &vif1Regs->r0+(vif1.tag.addr<<2); - u32* pmem2 = g_vifRow1+vif1.tag.addr; - assert( vif1.tag.addr < 4 ); - ret = min(4-vif1.tag.addr, vif1.vifpacketsize); - assert( ret > 0 ); - switch(ret) { - case 4: pmem[12] = data[3]; pmem2[3] = data[3]; - case 3: pmem[8] = data[2]; pmem2[2] = data[2]; - case 2: pmem[4] = data[1]; pmem2[1] = data[1]; - case 1: pmem[0] = data[0]; pmem2[0] = data[0]; break; - jNO_DEFAULT; - } - vif1.tag.addr += ret; - vif1.tag.size -= ret; - if(vif1.tag.size == 0) vif1.cmd = 0; - - return ret; -} - -static int Vif1TransSTCol(u32 *data){ - int ret; - - u32* pmem = &vif1Regs->c0+(vif1.tag.addr<<2); - u32* pmem2 = g_vifCol1+vif1.tag.addr; - ret = min(4-vif1.tag.addr, vif1.vifpacketsize); - switch(ret) { - case 4: pmem[12] = data[3]; pmem2[3] = data[3]; - case 3: pmem[8] = data[2]; pmem2[2] = data[2]; - case 2: pmem[4] = data[1]; pmem2[1] = data[1]; - case 1: pmem[0] = data[0]; pmem2[0] = data[0]; break; - jNO_DEFAULT; - } - vif1.tag.addr += ret; - vif1.tag.size -= ret; - if(vif1.tag.size == 0) vif1.cmd = 0; - return ret; -} - -static int Vif1TransMPG(u32 *data){ - if (vif1.vifpacketsize < vif1.tag.size) { - _vif1mpgTransfer(vif1.tag.addr, data, vif1.vifpacketsize); - vif1.tag.addr += vif1.vifpacketsize << 2; - vif1.tag.size -= vif1.vifpacketsize; - return vif1.vifpacketsize; - } else { - int ret; - _vif1mpgTransfer(vif1.tag.addr, data, vif1.tag.size); - ret = vif1.tag.size; - vif1.tag.size = 0; - vif1.cmd = 0; - return ret; - } -} -u32 splittransfer[4]; -u32 splitptr = 0; - -static int Vif1TransDirectHL(u32 *data){ - int ret = 0; - - - if(splitptr > 0){ //Leftover data from the last packet, filling the rest and sending to the GS - if(splitptr < 4 && vif1.vifpacketsize >= (4-splitptr)){ - - while(splitptr < 4){ - splittransfer[splitptr++] = (u32)data++; - ret++; - vif1.tag.size--; - } - } - - if( mtgsThread != NULL ) - { - // copy 16 bytes the fast way: - const u64* src = (u64*)splittransfer[0]; - const uint count = mtgsThread->PrepDataPacket( GIF_PATH_2, src, 1); - jASSUME( count == 1 ); - u64* dst = (u64*)mtgsThread->GetDataPacketPtr(); - dst[0] = src[0]; - dst[1] = src[1]; - - mtgsThread->SendDataPacket(); - } - else - { - FreezeXMMRegs(1); - FreezeMMXRegs(1); - GSGIFTRANSFER2((u32*)splittransfer[0], 1); - FreezeMMXRegs(0); - FreezeXMMRegs(0); - } - - if(vif1.tag.size == 0) vif1.cmd = 0; - splitptr = 0; - return ret; - } - if (vif1.vifpacketsize < vif1.tag.size) { - if(vif1.vifpacketsize < 4 && splitptr != 4) { //Not a full QW left in the buffer, saving left over data - ret = vif1.vifpacketsize; - while(ret > 0){ - splittransfer[splitptr++] = (u32)data++; - vif1.tag.size--; - ret--; - } - - return vif1.vifpacketsize; - } - - vif1.tag.size-= vif1.vifpacketsize; - ret = vif1.vifpacketsize; - } else { - ret = vif1.tag.size; - vif1.tag.size = 0; - vif1.cmd = 0; - } - - //TODO: ret is guaranteed to be qword aligned ? - - if( mtgsThread != NULL ) - { - //unaligned copy.VIF handling is -very- messy, so i'l use this code til i fix it :) - // Round ret up, just in case it's not 128bit aligned. - const uint count = mtgsThread->PrepDataPacket( GIF_PATH_2, data, (ret+3)>>2 ); - memcpy_fast( mtgsThread->GetDataPacketPtr(), data, count<<4 ); - mtgsThread->SendDataPacket(); - } - else { - - FreezeXMMRegs(1); - FreezeMMXRegs(1); - GSGIFTRANSFER2(data, (ret >> 2)); - FreezeMMXRegs(0); - FreezeXMMRegs(0); - } - - return ret; -} - - -static int Vif1TransUnpack(u32 *data){ - FreezeXMMRegs(1); - - if (vif1.vifpacketsize < vif1.tag.size) - { - /* size is less that the total size, transfer is - 'in pieces' */ - VIFunpack(data, &vif1.tag, vif1.vifpacketsize, VIF1dmanum); - vif1.tag.size -= vif1.vifpacketsize; - FreezeXMMRegs(0); - return vif1.vifpacketsize; - } - else - { - int ret; - /* we got all the data, transfer it fully */ - VIFunpack(data, &vif1.tag, vif1.tag.size, VIF1dmanum); - //g_vifCycles+= vif1.tag.size >> 1; - ret = vif1.tag.size; - vif1.tag.size = 0; - vif1.cmd = 0; - FreezeXMMRegs(0); - return ret; - } - -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Vif1 CMD Base Commands -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int transferred = 0; -int Path3transfer=0; -static void Vif1CMDNop(){ // NOP - vif1.cmd &= ~0x7f; -} -static void Vif1CMDSTCycl(){ // STCYCL - vif1Regs->cycle.cl = (u8)vif1Regs->code; - vif1Regs->cycle.wl = (u8)(vif1Regs->code >> 8); - vif1.cmd &= ~0x7f; -} -static void Vif1CMDOffset(){ // OFFSET - vif1Regs->ofst = vif1Regs->code & 0x3ff; - vif1Regs->stat &= ~0x80; - vif1Regs->tops = vif1Regs->base; - vif1.cmd &= ~0x7f; -} -static void Vif1CMDBase(){ // BASE - vif1Regs->base = vif1Regs->code & 0x3ff; - vif1.cmd &= ~0x7f; -} -static void Vif1CMDITop(){ // ITOP - vif1Regs->itops = vif1Regs->code & 0x3ff; - vif1.cmd &= ~0x7f; -} - -static void Vif1CMDSTMod(){ // STMOD - vif1Regs->mode = vif1Regs->code & 0x3; - vif1.cmd &= ~0x7f; -} - -static void Vif1CMDMskPath3(){ // MSKPATH3 - - vif1Regs->mskpath3 = (vif1Regs->code >> 15) & 0x1; - //SysPrintf("VIF MSKPATH3 %x\n", vif1Regs->mskpath3); -#ifdef GSPATH3FIX - - if ( (vif1Regs->code >> 15) & 0x1 ) { - while((gif->chcr & 0x100)){ //Can be done 2 different ways, depends on the game/company - if(path3hack == 0)if(Path3transfer == 0 && gif->qwc == 0) break; - - gsInterrupt(); - - if(path3hack == 1)if(gif->qwc == 0) break; //add games not working with it to elfheader.c to enable this instead - } - //while(gif->chcr & 0x100) gsInterrupt(); // Finish the transfer first - psHu32(GIF_STAT) |= 0x2; - } else { - if(gif->chcr & 0x100) CPU_INT(2, (transferred>>2) * BIAS); // Restart Path3 on its own, time it right! - psHu32(GIF_STAT) &= ~0x2; - } -#else - if ( vif1Regs->mskpath3 ) { - if(gif->qwc) _GIFchain(); // Finish the transfer first - psHu32(GIF_STAT) |= 0x2; - } else { - psHu32(GIF_STAT) &= ~0x2; - if(gif->qwc) _GIFchain(); // Finish the transfer first - } -#endif - vif1.cmd &= ~0x7f; -} - -static void Vif1CMDMark(){ // MARK - vif1Regs->mark = (u16)vif1Regs->code; - vif1Regs->stat |= VIF1_STAT_MRK; - vif1.cmd &= ~0x7f; -} -static void Vif1CMDFlush(){ // FLUSH/E/A - - vif1FLUSH(); - - if((vif1.cmd & 0x7f) == 0x13) { - while((gif->chcr & 0x100)){ - if(Path3transfer == 0 && gif->qwc == 0) break; - gsInterrupt(); - } - } - - vif1.cmd &= ~0x7f; -} -static void Vif1CMDMSCALF(){ //MSCAL/F - vuExecMicro( (u16)(vif1Regs->code) << 3, VIF1dmanum ); - vif1.cmd &= ~0x7f; -} -static void Vif1CMDMSCNT(){ // MSCNT - vuExecMicro( -1, VIF1dmanum ); - vif1.cmd &= ~0x7f; -} -static void Vif1CMDSTMask(){ // STMASK - vif1.tag.size = 1; -} -static void Vif1CMDSTRowCol(){// STROW / STCOL - vif1.tag.addr = 0; - vif1.tag.size = 4; -} - -static void Vif1CMDMPGTransfer(){ // MPG - int vifNum; - vif1FLUSH(); - vifNum = (u8)(vif1Regs->code >> 16); - if (vifNum == 0) vifNum = 256; - vif1.tag.addr = (u16)((vif1Regs->code) << 3) & 0x3fff; - vif1.tag.size = vifNum * 2; -} -static void Vif1CMDDirectHL(){ // DIRECT/HL - int vifImm; - vifImm = (u16)vif1Regs->code; - if (vifImm == 0) { - vif1.tag.size = 65536 << 2; - } else { - vif1.tag.size = vifImm << 2; - } - while((gif->chcr & 0x100) && (vif1.cmd & 0x7f) == 0x51){ - gsInterrupt(); //DirectHL flushes the lot - //if((psHu32(GIF_STAT) & 0xE00) == 0) break; - } -} -static void Vif1CMDNull(){ // invalid opcode - // if ME1, then force the vif to interrupt - - if ((vif1Regs->err & 0x4) == 0) { //Ignore vifcode and tag mismatch error - SysPrintf( "UNKNOWN VifCmd: %x\n", vif1.cmd ); - vif1Regs->stat |= 1 << 13; - vif1.irq++; - } - vif1.cmd = 0; -} - -// Vif1 Data Transfer Table - -int (*Vif1TransTLB[128])(u32 *data) = -{ - Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x7*/ - Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0xF*/ - Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x17*/ - Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x1F*/ - Vif1TransSTMask , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x27*/ - Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x2F*/ - Vif1TransSTRow , Vif1TransSTCol , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x37*/ - Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x3F*/ - Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x47*/ - Vif1TransNull , Vif1TransNull , Vif1TransMPG , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x4F*/ - Vif1TransDirectHL, Vif1TransDirectHL, Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x57*/ - Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x5F*/ - Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransNull , /*0x67*/ - Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , /*0x6F*/ - Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransNull , /*0x77*/ - Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransNull , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack /*0x7F*/ -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Vif1 CMD Table -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void (*Vif1CMDTLB[82])() = -{ - Vif1CMDNop , Vif1CMDSTCycl , Vif1CMDOffset , Vif1CMDBase , Vif1CMDITop , Vif1CMDSTMod , Vif1CMDMskPath3, Vif1CMDMark , /*0x7*/ - Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0xF*/ - Vif1CMDFlush , Vif1CMDFlush , Vif1CMDNull , Vif1CMDFlush, Vif1CMDMSCALF, Vif1CMDMSCALF, Vif1CMDNull , Vif1CMDMSCNT, /*0x17*/ - Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x1F*/ - Vif1CMDSTMask , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x27*/ - Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x2F*/ - Vif1CMDSTRowCol, Vif1CMDSTRowCol, Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x37*/ - Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x3F*/ - Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x47*/ - Vif1CMDNull , Vif1CMDNull , Vif1CMDMPGTransfer, Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x4F*/ - Vif1CMDDirectHL, Vif1CMDDirectHL -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int VIF1transfer(u32 *data, int size, int istag) { - int ret; - transferred=vif1.vifstalled ? vif1.irqoffset : 0; // irqoffset necessary to add up the right qws, or else will spin (spiderman) - - VIF_LOG( "VIF1transfer: size %x (vif1.cmd %x)\n", size, vif1.cmd ); - - vif1.irqoffset = 0; - vif1.vifstalled = 0; - vif1.stallontag = 0; - vif1.vifpacketsize = size; - - while (vif1.vifpacketsize > 0) { - - if (vif1.cmd) { - vif1Regs->stat |= VIF1_STAT_VPS_T; //Decompression has started - } - - if (vif1.cmd) { - ret = Vif1TransTLB[vif1.cmd](data); - data+= ret; vif1.vifpacketsize-= ret; - if(vif1.cmd == 0) vif1Regs->stat &= ~VIF1_STAT_VPS_T; //We are once again waiting for a new vifcode as the command has cleared - continue; - } - - if(vif1.tag.size != 0) SysPrintf("no vif1 cmd but tag size is left last cmd read %x\n", vif1Regs->code); - - if(vif1.irq) break; - - vif1.cmd = (data[0] >> 24); - vif1Regs->code = data[0]; - - vif1Regs->stat |= VIF1_STAT_VPS_D; - if ((vif1.cmd & 0x60) == 0x60) { - vif1UNPACK(data); - } else { - VIF_LOG( "VIFtransfer: cmd %x, num %x, imm %x, size %x\n", vif1.cmd, (data[0] >> 16) & 0xff, data[0] & 0xffff, vif1.vifpacketsize ); - - if((vif1.cmd & 0x7f) > 0x51){ - if ((vif1Regs->err & 0x4) == 0) { //Ignore vifcode and tag mismatch error - SysPrintf( "UNKNOWN VifCmd: %x\n", vif1.cmd ); - vif1Regs->stat |= 1 << 13; - vif1.irq++; - } - vif1.cmd = 0; - } else Vif1CMDTLB[(vif1.cmd & 0x7f)](); - } - - ++data; - --vif1.vifpacketsize; - - - if ((vif1.cmd & 0x80)) { //i bit on vifcode and not masked by VIF1_ERR - VIF_LOG( "Interrupt on VIFcmd: %x (INTC_MASK = %x)\n", vif1.cmd, psHu32(INTC_MASK) ); - - if(!(vif1Regs->err & 0x1)){ - ++vif1.irq; - if(istag && vif1.tag.size <= vif1.vifpacketsize) vif1.stallontag = 1; - } - vif1.cmd &= 0x7f; - if(vif1.tag.size == 0) break; - } - } - - transferred += size - vif1.vifpacketsize; - g_vifCycles+= (transferred>>2)*BIAS; /* guessing */ - - if (vif1.irq && vif1.cmd == 0) { - vif1.vifstalled = 1; - - - - if(((vif1Regs->code >> 24) & 0x7f) != 0x7)vif1Regs->stat|= VIF1_STAT_VIS; // Note: commenting this out fixes WALL-E - - // spiderman doesn't break on qw boundaries - vif1.irqoffset = transferred%4; // cannot lose the offset - - if( istag ) { - return -2; - } - - transferred = transferred >> 2; - vif1ch->madr+= (transferred << 4); - vif1ch->qwc-= transferred; - //SysPrintf("Stall on vif1, FromSPR = %x, Vif1MADR = %x Sif0MADR = %x STADR = %x\n", psHu32(0x1000d010), vif1ch->madr, psHu32(0x1000c010), psHu32(DMAC_STADR)); - return -2; - } - - vif1Regs->stat &= ~VIF1_STAT_VPS; //Vif goes idle as the stall happened between commands; - if( vif1.cmd ) vif1Regs->stat |= VIF1_STAT_VPS_W; //Otherwise we wait for the data - - if( !istag ) { - - transferred = transferred >> 2; - vif1ch->madr+= (transferred << 4); - vif1ch->qwc-= transferred; - } - - return 0; -} - -int _VIF1chain() { - u32 *pMem; - //u32 qwc = vif1ch->qwc; - u32 ret; - - //Hmm, it seems some games (Fatal Frame and Twisted Metal) Try to force the VIF to stop whatever its doing and do something else - //Okay... so in that case we will tell the vif to do so (Refraction) - if (vif1ch->qwc == 0 && vif1.vifstalled == 0) { - vif1Regs->stat &= ~VIF1_STAT_VPS; - vif1.cmd = 0; - vif1.tag.size = 0; - return 0; - } - - pMem = (u32*)dmaGetAddr(vif1ch->madr); - if (pMem == NULL) - return -1; - - VIF_LOG("VIF1chain size=%d, madr=%lx, tadr=%lx\n", - vif1ch->qwc, vif1ch->madr, vif1ch->tadr); - - if( vif1.vifstalled ) { - ret = VIF1transfer(pMem+vif1.irqoffset, vif1ch->qwc*4-vif1.irqoffset, 0); - } - else { - ret = VIF1transfer(pMem, vif1ch->qwc*4, 0); - } - /*vif1ch->madr+= (vif1ch->qwc << 4); - vif1ch->qwc-= qwc;*/ - - return ret; -} - -static int prevvifcycles = 0; -static u32* prevviftag = NULL; -u32 *vif1ptag; -int _chainVIF1() { - int id; - int ret; - - vif1ptag = (u32*)dmaGetAddr(vif1ch->tadr); //Set memory pointer to TADR - if (vif1ptag == NULL) { //Is vif0ptag empty? - SysPrintf("Vif1 Tag BUSERR\n"); - vif1ch->chcr = ( vif1ch->chcr & 0xFFFF ) | ( (*vif1ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 - psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register - return -1; //Return -1 as an error has occurred - } - - id = (vif1ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag - vif1ch->qwc = (u16)vif1ptag[0]; //QWC set to lower 16bits of the tag - vif1ch->madr = vif1ptag[1]; //MADR = ADDR field - g_vifCycles+=1; // Add 1 g_vifCycles from the QW read for the tag - - vif1ch->chcr = ( vif1ch->chcr & 0xFFFF ) | ( (*vif1ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 - // Transfer dma tag if tte is set - - VIF_LOG("VIF1 Tag %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx\n", - vif1ptag[1], vif1ptag[0], vif1ch->qwc, id, vif1ch->madr, vif1ch->tadr); - - //} else - - - if (!vif1.done && (psHu32(DMAC_CTRL) & 0xC0) == 0x40 && id == 4) { // STD == VIF1 - //vif1.done |= hwDmacSrcChainWithStack(vif1ch, id); - // there are still bugs, need to also check if gif->madr +16*qwc >= stadr, if not, stall - if( (vif1ch->madr + vif1ch->qwc * 16) >= psHu32(DMAC_STADR) ) { - // stalled - - hwDmacIrq(13); - return 0; - } - } - - if (vif1ch->chcr & 0x40) { - if(vif1.vifstalled == 1) ret = VIF1transfer(vif1ptag+(2+vif1.irqoffset), 2-vif1.irqoffset, 1); //Transfer Tag on stall - else ret = VIF1transfer(vif1ptag+2, 2, 1); //Transfer Tag - if (ret == -1) return -1; //There has been an error - if (ret == -2) { - return -2; //IRQ set by VIFTransfer - } - } - - vif1.done |= hwDmacSrcChainWithStack(vif1ch, id); - - ret = _VIF1chain(); //Transfers the data set by the switch - - if ((vif1ch->chcr & 0x80) && (vif1ptag[0] >> 31)) { //Check TIE bit of CHCR and IRQ bit of tag - VIF_LOG( "dmaIrq Set\n" ); - - vif1.done = 1; - return 0; //End Transfer - } - return vif1.done;//Return Done -} - -__forceinline void vif1Interrupt() { - VIF_LOG("vif1Interrupt: %8.8x\n", cpuRegs.cycle); - - g_vifCycles = 0; - - - if(vif1.irq && vif1.tag.size == 0) { - vif1Regs->stat|= VIF1_STAT_INT; - hwIntcIrq(VIF1intc); - --vif1.irq; - if(vif1Regs->stat & (VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS)) - { - vif1Regs->stat&= ~0x1F000000; // FQC=0 - // One game doesnt like vif stalling at end, cant remember what. Spiderman isnt keen on it tho - vif1ch->chcr &= ~0x100; - return; - } - - if(vif1ch->qwc > 0 || vif1.irqoffset > 0){ - if(vif1.stallontag == 1) { - _chainVIF1(); - } - else _VIF1chain();//CPU_INT(13, vif1ch->qwc * BIAS); - CPU_INT(1, 0); - return; - } - } - - - //} - if((vif1ch->chcr & 0x100) == 0) SysPrintf("Vif1 running when CHCR == %x\n", vif1ch->chcr); - - - if ((vif1ch->chcr & 0x104) == 0x104 && vif1.done == 0) { - - if( !(psHu32(DMAC_CTRL) & 0x1) ) { - SysPrintf("vif1 dma masked\n"); - return; - } - - _chainVIF1(); - CPU_INT(1, 0); - - return; - } -#ifdef PCSX2_DEVBUILD - if(vif1ch->qwc > 0) SysPrintf("VIF1 Ending with QWC left\n"); - if(vif1.cmd != 0) SysPrintf("vif1.cmd still set %x\n", vif1.cmd); -#endif - - prevviftag = NULL; - prevvifcycles = 0; - vif1ch->chcr &= ~0x100; - hwDmacIrq(DMAC_VIF1); - if(vif1Regs->mskpath3 == 0 || (vif1ch->chcr & 0x1) == 0x1)vif1Regs->stat&= ~0x1F000000; // FQC=0 -} - -#define spr0 ((DMACh*)&PS2MEM_HW[0xD000]) -void dmaVIF1() -{ - - VIF_LOG("dmaVIF1 chcr = %lx, madr = %lx, qwc = %lx\n" - " tadr = %lx, asr0 = %lx, asr1 = %lx\n", - vif1ch->chcr, vif1ch->madr, vif1ch->qwc, - vif1ch->tadr, vif1ch->asr0, vif1ch->asr1 ); - - if(vif1.done == 0 && (psHu32(DMAC_CTRL) & 0xC) != 0x8) { - SysPrintf("VIF1 Double DMA issue, ignoring\n"); - return; - } - - vif1.done = 0; - g_vifCycles = 0; - - if (((psHu32(DMAC_CTRL) & 0xC) == 0x8)) { // VIF MFIFO - //SysPrintf("VIFMFIFO\n"); - if(!(vif1ch->chcr & 0x4)) SysPrintf("MFIFO mode != Chain! %x\n", vif1ch->chcr); - if(vif1ch->madr != spr0->madr)vifMFIFOInterrupt(); - return; - } - -#ifdef PCSX2_DEVBUILD - if ((psHu32(DMAC_CTRL) & 0xC0) == 0x40) { // STD == VIF1 - //SysPrintf("VIF Stall Control Source = %x, Drain = %x\n", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3); - //return; - } -#endif - - - vif1Regs->stat|= 0x10000000; // FQC=16 - - if (!(vif1ch->chcr & 0x4) || vif1ch->qwc > 0) { // Normal Mode - if ((psHu32(DMAC_CTRL) & 0xC0) == 0x40) { - SysPrintf("DMA Stall Control on VIF1 normal\n"); - } - if ((vif1ch->chcr & 0x1)) { // to Memory - if(_VIF1chain() == -2) { - SysPrintf("Stall on normal\n"); - //vif1.vifstalled = 1; - } - CPU_INT(1, g_vifCycles); - } else { - - int size; - u64* pMem = (u64*)dmaGetAddr(vif1ch->madr); - - // VIF from gsMemory - - if (pMem == NULL) { //Is vif0ptag empty? - SysPrintf("Vif1 Tag BUSERR\n"); - psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register - vif1.done = 1; - vif1Regs->stat&= ~0x1f000000; - vif1ch->qwc = 0; - CPU_INT(1, 0); - - return; //Return -1 as an error has occurred - } - - // MTGS concerns: The MTGS is inherently disagreeable with the idea of downloading - // stuff from the GS. The *only* way to handle this case safely is to flush the GS - // completely and execute the transfer there-after. - - FreezeXMMRegs(1); - if( GSreadFIFO2 == NULL ) { - for (size=vif1ch->qwc; size>0; --size) { - if (size > 1 ) { - mtgsWaitGS(); - GSreadFIFO((u64*)&PS2MEM_HW[0x5000]); - } - pMem[0] = psHu64(0x5000); - pMem[1] = psHu64(0x5008); pMem+= 2; - } - } - else { - mtgsWaitGS(); - GSreadFIFO2(pMem, vif1ch->qwc); - - // set incase read - psHu64(0x5000) = pMem[2*vif1ch->qwc-2]; - psHu64(0x5008) = pMem[2*vif1ch->qwc-1]; - } - FreezeXMMRegs(0); - - if(vif1Regs->mskpath3 == 0)vif1Regs->stat&= ~0x1f000000; - g_vifCycles += vif1ch->qwc * 2; - vif1ch->madr += vif1ch->qwc * 16; // mgs3 scene changes - vif1ch->qwc = 0; - CPU_INT(1, g_vifCycles); - - } - - vif1.done = 1; - return; - } - - // Chain Mode - vif1.done = 0; - CPU_INT(1, 0); -} - - -void vif1Write32(u32 mem, u32 value) { - if (mem == 0x10003c30) { // MARK - VIF_LOG("VIF1_MARK write32 0x%8.8x\n", value); - - /* Clear mark flag in VIF1_STAT and set mark with 'value' */ - vif1Regs->stat&= ~VIF1_STAT_MRK; - vif1Regs->mark = value; - } else - if (mem == 0x10003c10) { // FBRST - VIF_LOG("VIF1_FBRST write32 0x%8.8x\n", value); - - if (value & 0x1) { - /* Reset VIF */ - memzero_obj(vif1); - cpuRegs.interrupt &= ~((1<<1) | (1<<10)); //Stop all vif1 DMA's - vif1ch->qwc = 0; //? - psHu64(0x10005000) = 0; - psHu64(0x10005008) = 0; - vif1.done = 1; - vif1Regs->err = 0; - vif1Regs->stat&= ~(0x1F800000|VIF1_STAT_INT|VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS|VIF1_STAT_VPS); // FQC=0 - } - if (value & 0x2) { - /* Force Break the VIF */ - /* I guess we should stop the VIF dma here - but not 100% sure (linuz) */ - vif1Regs->stat |= VIF1_STAT_VFS; - vif1Regs->stat &= ~VIF1_STAT_VPS; - cpuRegs.interrupt &= ~((1<<1) | (1<<10)); //Stop all vif1 DMA's - vif1.vifstalled = 1; - SysPrintf("vif1 force break\n"); - } - if (value & 0x4) { - /* Stop VIF */ - /* Not completly sure about this, can't remember what game - used this, but 'draining' the VIF helped it, instead of - just stoppin the VIF (linuz) */ - vif1Regs->stat |= VIF1_STAT_VSS; - vif1Regs->stat &= ~VIF1_STAT_VPS; - vif1.vifstalled = 1; - } - if (value & 0x8) { - int cancel = 0; - - /* Cancel stall, first check if there is a stall to cancel, - and then clear VIF1_STAT VSS|VFS|VIS|INT|ER0|ER1 bits */ - if (vif1Regs->stat & (VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS)) { - cancel = 1; - } - - vif1Regs->stat &= ~(VIF1_STAT_VSS | VIF1_STAT_VFS | VIF1_STAT_VIS | - VIF1_STAT_INT | VIF1_STAT_ER0 | VIF1_STAT_ER1); - if (cancel) { - - if( vif1.vifstalled ) { - g_vifCycles = 0; - // loop necessary for spiderman - if((psHu32(DMAC_CTRL) & 0xC) == 0x8){ - //SysPrintf("MFIFO Stall\n"); - CPU_INT(10, 0); - }else { - if(vif1.stallontag == 1){ - //SysPrintf("Sorting VIF Stall on tag\n"); - _chainVIF1(); - } else _VIF1chain(); - - CPU_INT(1, g_vifCycles); // Gets the timing right - Flatout - } - vif1ch->chcr |= 0x100; - } - } - } - } else - if (mem == 0x10003c20) { // ERR - VIF_LOG("VIF1_ERR write32 0x%8.8x\n", value); - - /* Set VIF1_ERR with 'value' */ - vif1Regs->err = value; - } else - if (mem == 0x10003c00) { // STAT - VIF_LOG("VIF1_STAT write32 0x%8.8x\n", value); - -#ifdef PCSX2_DEVBUILD - /* Only FDR bit is writable, so mask the rest */ - if( (vif1Regs->stat & VIF1_STAT_FDR) ^ (value & VIF1_STAT_FDR) ) { - // different so can't be stalled - if (vif1Regs->stat & (VIF1_STAT_INT|VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS)) { - SysPrintf("changing dir when vif1 fifo stalled\n"); - } - } -#endif - - vif1Regs->stat = (vif1Regs->stat & ~VIF1_STAT_FDR) | (value & VIF1_STAT_FDR); - if (vif1Regs->stat & VIF1_STAT_FDR) { - vif1Regs->stat|= 0x01000000; - } else { - vif1ch->qwc = 0; - vif1.vifstalled = 0; - vif1.done = 1; - vif1Regs->stat&= ~0x1F000000; // FQC=0 - } - } - else - if (mem == 0x10003c50) { // MODE - vif1Regs->mode = value; - } - else { - SysPrintf("Unknown Vif1 write to %x\n", mem); - if( mem >= 0x10003d00 && mem < 0x10003d80 ) { - assert( (mem&0xf) == 0 ); - if( mem < 0x10003d40) g_vifRow1[(mem>>4)&3] = value; - else g_vifCol1[(mem>>4)&3] = value; - } else psHu32(mem) = value; - } - - /* Other registers are read-only so do nothing for them */ -} - -void vif1Reset() { - /* Reset the whole VIF, meaning the internal pcsx2 vars - and all the registers */ - memzero_obj(vif1); - memzero_obj(*vif1Regs); - SetNewMask(g_vif1Masks, g_vif1HasMask3, 0, 0xffffffff); - psHu64(0x10005000) = 0; - psHu64(0x10005008) = 0; - vif1Regs->stat &= ~VIF1_STAT_VPS; - vif1.done = 1; - cpuRegs.interrupt &= ~((1<<1) | (1<<10)); //Stop all vif1 DMA's - vif1Regs->stat&= ~0x1F000000; // FQC=0 -} - -void SaveState::vif1Freeze() { - Freeze(vif1); - if( IsLoading() ) - SetNewMask(g_vif1Masks, g_vif1HasMask3, vif1Regs->mask, ~vif1Regs->mask); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "Vif.h" +#include "VUmicro.h" +#include "GS.h" + +#include "VifDma.h" + +#ifdef _MSC_VER +#include +#include +#endif + +using namespace std; // for min / max + +//#define VIFUNPACKDEBUG //enable unpack debugging output + +#define gif ((DMACh*)&PS2MEM_HW[0xA000]) + +// Extern variables +extern "C" +{ + // Need cdecl on these for ASM references. + extern VIFregisters *_vifRegs; + extern u32* _vifMaskRegs; + extern u32* _vifRow; + extern u32* _vifCol; +} + +extern PCSX2_ALIGNED16_DECL(u32 g_vifRow0[4]); +extern PCSX2_ALIGNED16_DECL(u32 g_vifCol0[4]); +extern PCSX2_ALIGNED16_DECL(u32 g_vifRow1[4]); +extern PCSX2_ALIGNED16_DECL(u32 g_vifCol1[4]); + +extern vifStruct *_vif; + +vifStruct vif0, vif1; + +PCSX2_ALIGNED16(u32 g_vif1Masks[64]); +PCSX2_ALIGNED16(u32 g_vif0Masks[64]); +u32 g_vif1HasMask3[4] = {0}, g_vif0HasMask3[4] = {0}; + +// Generic constants +static const unsigned int VIF0intc = 4; +static const unsigned int VIF1intc = 5; +static const unsigned int VIF0dmanum = 0; +static const unsigned int VIF1dmanum = 1; + +int g_vifCycles = 0; +int path3hack = 0; + +typedef void (*UNPACKFUNCTYPE)( u32 *dest, u32 *data, int size ); +typedef int (*UNPACKPARTFUNCTYPESSE)( u32 *dest, u32 *data, int size ); +extern void (*Vif1CMDTLB[82])(); +extern void (*Vif0CMDTLB[75])(); +extern int (*Vif1TransTLB[128])(u32 *data); +extern int (*Vif0TransTLB[128])(u32 *data); + +struct VIFUnpackFuncTable { + UNPACKFUNCTYPE funcU; + UNPACKFUNCTYPE funcS; + + int bsize; // currently unused + int dsize; // byte size of one channel + int gsize; // size of data in bytes used for each write cycle + int qsize; // used for unpack parts, num of vectors that + // will be decompressed from data for 1 cycle +}; + +/* block size; data size; group size; qword size; */ +#define _UNPACK_TABLE32(name, bsize, dsize, gsize, qsize) \ + { UNPACK_##name, UNPACK_##name, \ + bsize, dsize, gsize, qsize }, + +#define _UNPACK_TABLE(name, bsize, dsize, gsize, qsize) \ + { UNPACK_##name##u, UNPACK_##name##s, \ + bsize, dsize, gsize, qsize }, + +// Main table for function unpacking +static const VIFUnpackFuncTable VIFfuncTable[16] = { + _UNPACK_TABLE32(S_32, 1, 4, 4, 4) // 0x0 - S-32 + _UNPACK_TABLE(S_16, 2, 2, 2, 4) // 0x1 - S-16 + _UNPACK_TABLE(S_8, 4, 1, 1, 4) // 0x2 - S-8 + { NULL, NULL, 0, 0, 0, 0 }, // 0x3 + + _UNPACK_TABLE32(V2_32, 24, 4, 8, 2) // 0x4 - V2-32 + _UNPACK_TABLE(V2_16, 12, 2, 4, 2) // 0x5 - V2-16 + _UNPACK_TABLE(V2_8, 6, 1, 2, 2) // 0x6 - V2-8 + { NULL, NULL, 0, 0, 0, 0 }, // 0x7 + + _UNPACK_TABLE32(V3_32, 36, 4, 12, 3) // 0x8 - V3-32 + _UNPACK_TABLE(V3_16, 18, 2, 6, 3) // 0x9 - V3-16 + _UNPACK_TABLE(V3_8, 9, 1, 3, 3) // 0xA - V3-8 + { NULL, NULL, 0, 0, 0, 0 }, // 0xB + + _UNPACK_TABLE32(V4_32, 48, 4, 16, 4) // 0xC - V4-32 + _UNPACK_TABLE(V4_16, 24, 2, 8, 4) // 0xD - V4-16 + _UNPACK_TABLE(V4_8, 12, 1, 4, 4) // 0xE - V4-8 + _UNPACK_TABLE32(V4_5, 6, 2, 2, 4) // 0xF - V4-5 +}; + +struct VIFSSEUnpackTable { + // regular 0, 1, 2; mask 0, 1, 2 + UNPACKPARTFUNCTYPESSE funcU[9], funcS[9]; +}; + +#define DECL_UNPACK_TABLE_SSE(name, sign) \ +extern "C" { \ + extern int UNPACK_SkippingWrite_##name##_##sign##_Regular_0(u32* dest, u32* data, int dmasize); \ + extern int UNPACK_SkippingWrite_##name##_##sign##_Regular_1(u32* dest, u32* data, int dmasize); \ + extern int UNPACK_SkippingWrite_##name##_##sign##_Regular_2(u32* dest, u32* data, int dmasize); \ + extern int UNPACK_SkippingWrite_##name##_##sign##_Mask_0(u32* dest, u32* data, int dmasize); \ + extern int UNPACK_SkippingWrite_##name##_##sign##_Mask_1(u32* dest, u32* data, int dmasize); \ + extern int UNPACK_SkippingWrite_##name##_##sign##_Mask_2(u32* dest, u32* data, int dmasize); \ + extern int UNPACK_SkippingWrite_##name##_##sign##_WriteMask_0(u32* dest, u32* data, int dmasize); \ + extern int UNPACK_SkippingWrite_##name##_##sign##_WriteMask_1(u32* dest, u32* data, int dmasize); \ + extern int UNPACK_SkippingWrite_##name##_##sign##_WriteMask_2(u32* dest, u32* data, int dmasize); \ +} + +#define _UNPACK_TABLE_SSE(name, sign) \ + UNPACK_SkippingWrite_##name##_##sign##_Regular_0, \ + UNPACK_SkippingWrite_##name##_##sign##_Regular_1, \ + UNPACK_SkippingWrite_##name##_##sign##_Regular_2, \ + UNPACK_SkippingWrite_##name##_##sign##_Mask_0, \ + UNPACK_SkippingWrite_##name##_##sign##_Mask_1, \ + UNPACK_SkippingWrite_##name##_##sign##_Mask_2, \ + UNPACK_SkippingWrite_##name##_##sign##_WriteMask_0, \ + UNPACK_SkippingWrite_##name##_##sign##_WriteMask_1, \ + UNPACK_SkippingWrite_##name##_##sign##_WriteMask_2 \ + +#define _UNPACK_TABLE_SSE_NULL \ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + +// Main table for function unpacking +DECL_UNPACK_TABLE_SSE(S_32, u); +DECL_UNPACK_TABLE_SSE(S_16, u); +DECL_UNPACK_TABLE_SSE(S_8, u); +DECL_UNPACK_TABLE_SSE(S_16, s); +DECL_UNPACK_TABLE_SSE(S_8, s); + +DECL_UNPACK_TABLE_SSE(V2_32, u); +DECL_UNPACK_TABLE_SSE(V2_16, u); +DECL_UNPACK_TABLE_SSE(V2_8, u); +DECL_UNPACK_TABLE_SSE(V2_16, s); +DECL_UNPACK_TABLE_SSE(V2_8, s); + +DECL_UNPACK_TABLE_SSE(V3_32, u); +DECL_UNPACK_TABLE_SSE(V3_16, u); +DECL_UNPACK_TABLE_SSE(V3_8, u); +DECL_UNPACK_TABLE_SSE(V3_16, s); +DECL_UNPACK_TABLE_SSE(V3_8, s); + +DECL_UNPACK_TABLE_SSE(V4_32, u); +DECL_UNPACK_TABLE_SSE(V4_16, u); +DECL_UNPACK_TABLE_SSE(V4_8, u); +DECL_UNPACK_TABLE_SSE(V4_16, s); +DECL_UNPACK_TABLE_SSE(V4_8, s); +DECL_UNPACK_TABLE_SSE(V4_5, u); + +static const VIFSSEUnpackTable VIFfuncTableSSE[16] = { + { _UNPACK_TABLE_SSE(S_32, u), _UNPACK_TABLE_SSE(S_32, u) }, + { _UNPACK_TABLE_SSE(S_16, u), _UNPACK_TABLE_SSE(S_16, s) }, + { _UNPACK_TABLE_SSE(S_8, u), _UNPACK_TABLE_SSE(S_8, s) }, + { _UNPACK_TABLE_SSE_NULL, _UNPACK_TABLE_SSE_NULL }, + + { _UNPACK_TABLE_SSE(V2_32, u), _UNPACK_TABLE_SSE(V2_32, u) }, + { _UNPACK_TABLE_SSE(V2_16, u), _UNPACK_TABLE_SSE(V2_16, s) }, + { _UNPACK_TABLE_SSE(V2_8, u), _UNPACK_TABLE_SSE(V2_8, s) }, + { _UNPACK_TABLE_SSE_NULL, _UNPACK_TABLE_SSE_NULL }, + + { _UNPACK_TABLE_SSE(V3_32, u), _UNPACK_TABLE_SSE(V3_32, u) }, + { _UNPACK_TABLE_SSE(V3_16, u), _UNPACK_TABLE_SSE(V3_16, s) }, + { _UNPACK_TABLE_SSE(V3_8, u), _UNPACK_TABLE_SSE(V3_8, s) }, + { _UNPACK_TABLE_SSE_NULL, _UNPACK_TABLE_SSE_NULL }, + + { _UNPACK_TABLE_SSE(V4_32, u), _UNPACK_TABLE_SSE(V4_32, u) }, + { _UNPACK_TABLE_SSE(V4_16, u), _UNPACK_TABLE_SSE(V4_16, s) }, + { _UNPACK_TABLE_SSE(V4_8, u), _UNPACK_TABLE_SSE(V4_8, s) }, + { _UNPACK_TABLE_SSE(V4_5, u), _UNPACK_TABLE_SSE(V4_5, u) }, +}; + + +__forceinline void vif0FLUSH() { + int _cycles; + _cycles = VU0.cycle; + + // fixme: this code should call _vu0WaitMicro instead? I'm not sure if + // it's purposefully ignoring ee cycles or not (see below for more) + + vu0Finish(); + g_vifCycles+= (VU0.cycle - _cycles)*BIAS; +} + +__forceinline void vif1FLUSH() { + int _cycles; + _cycles = VU1.cycle; + + // fixme: Same as above, is this a "stalling" offense? I think the cycles should + // be added to cpuRegs.cycle instead of g_vifCycles, but not sure (air) + + if( VU0.VI[REG_VPU_STAT].UL & 0x100 ) { + do { + CpuVU1.ExecuteBlock(); + } while(VU0.VI[REG_VPU_STAT].UL & 0x100); + + g_vifCycles+= (VU1.cycle - _cycles)*BIAS; + } +} + +void vifDmaInit() { +} + +__forceinline static int _limit( int a, int max ) { + return ( a > max ? max : a ); +} + +static void ProcessMemSkip(int size, unsigned int unpackType, const unsigned int VIFdmanum){ + const VIFUnpackFuncTable *unpack; + vifStruct *vif; + VIFregisters *vifRegs; + unpack = &VIFfuncTable[ unpackType ]; +// varLog |= 0x00000400; + + if (VIFdmanum == 0) + { + vif = &vif0; + vifRegs = vif0Regs; + } + else + { + vif = &vif1; + vifRegs = vif1Regs; + } + + switch(unpackType){ + case 0x0: + vif->tag.addr += size*4; + VIFUNPACK_LOG("Processing S-32 skip, size = %d\n", size); + break; + case 0x1: + vif->tag.addr += size*8; + VIFUNPACK_LOG("Processing S-16 skip, size = %d\n", size); + break; + case 0x2: + vif->tag.addr += size*16; + VIFUNPACK_LOG("Processing S-8 skip, size = %d\n", size); + break; + case 0x4: + vif->tag.addr += size + ((size / unpack->gsize) * 8); + VIFUNPACK_LOG("Processing V2-32 skip, size = %d\n", size); + break; + case 0x5: + vif->tag.addr += (size * 2) + ((size / unpack->gsize) * 8); + VIFUNPACK_LOG("Processing V2-16 skip, size = %d\n", size); + break; + case 0x6: + vif->tag.addr += (size * 4) + ((size / unpack->gsize) * 8); + VIFUNPACK_LOG("Processing V2-8 skip, size = %d\n", size); + break; + case 0x8: + vif->tag.addr += size + ((size / unpack->gsize) * 4); + VIFUNPACK_LOG("Processing V3-32 skip, size = %d\n", size); + break; + case 0x9: + vif->tag.addr += (size * 2) + ((size / unpack->gsize) * 4); + VIFUNPACK_LOG("Processing V3-16 skip, size = %d\n", size); + break; + case 0xA: + vif->tag.addr += (size * 4) + ((size / unpack->gsize) * 4); + VIFUNPACK_LOG("Processing V3-8 skip, size = %d\n", size); + break; + case 0xC: + vif->tag.addr += size; + VIFUNPACK_LOG("Processing V4-32 skip, size = %d, CL = %d, WL = %d\n", size, vif1Regs->cycle.cl, vif1Regs->cycle.wl); + break; + case 0xD: + vif->tag.addr += size * 2; + VIFUNPACK_LOG("Processing V4-16 skip, size = %d\n", size); + break; + case 0xE: + vif->tag.addr += size * 4; + VIFUNPACK_LOG("Processing V4-8 skip, size = %d\n", size); + break; + case 0xF: + vif->tag.addr += size * 8; + VIFUNPACK_LOG("Processing V4-5 skip, size = %d\n", size); + break; + default: + SysPrintf("Invalid unpack type %x\n", unpackType); + break; + } + + if((vif->tag.addr & 0xf) == unpack->gsize) { + vif->tag.addr += 16 - unpack->gsize; + } +} + +//u32 unpacktotal = 0; + +static void VIFunpack(u32 *data, vifCode *v, int size, const unsigned int VIFdmanum) { + u32 *dest; + unsigned int unpackType; + UNPACKFUNCTYPE func; + const VIFUnpackFuncTable *ft; + vifStruct *vif; + VIFregisters *vifRegs; + VURegs * VU; + u8 *cdata = (u8*)data; + //u64 basetick = GetCPUTick(); +#ifdef _DEBUG + u32 memsize = VIFdmanum ? 0x4000 : 0x1000; +#endif + +#ifdef _MSC_VER + _mm_prefetch((char*)data, _MM_HINT_NTA); +#endif + + if (VIFdmanum == 0) + { + VU = &VU0; + vif = &vif0; + vifRegs = vif0Regs; + assert( v->addr < memsize ); + //v->addr &= 0xfff; + } + else + { + + VU = &VU1; + vif = &vif1; + vifRegs = vif1Regs; + assert( v->addr < memsize ); + //v->addr &= 0x3fff; + + if( vu1MicroIsSkipping() ) { + // don't process since the frame is dummy + vif->tag.addr += (size / (VIFfuncTable[ vif->cmd & 0xf ].gsize* vifRegs->cycle.wl)) * ((vifRegs->cycle.cl - vifRegs->cycle.wl)*16); + // unpacktotal += GetCPUTick()-basetick; + return; + } + } + + dest = (u32*)(VU->Mem + v->addr); + + VIF_LOG("VIF%d UNPACK: Mode=%x, v->size=%d, size=%d, v->addr=%x\n", + VIFdmanum, v->cmd & 0xf, v->size, size, v->addr ); + +#ifdef _DEBUG + if (v->size != size) { + VIF_LOG("*PCSX2*: warning v->size != size\n"); + } + if ((v->addr+size*4) > memsize) { + SysPrintf("*PCSX2*: fixme unpack overflow\n"); + SysPrintf( "VIF%d UNPACK: Mode=%x, v->size=%d, size=%d, v->addr=%x\n", + VIFdmanum, v->cmd & 0xf, v->size, size, v->addr ); + } +#endif + // The unpack type + unpackType = v->cmd & 0xf; + + if (size == 0) { + VIFUNPACK_LOG("*PCSX2*: Unpack %x with size 0!! v->size = %d cl = %d, wl = %d, mode %d mask %x\n", v->cmd, v->size, vifRegs->cycle.cl, vifRegs->cycle.wl, vifRegs->mode, vifRegs->mask); + } + +#ifdef _MSC_VER + _mm_prefetch((char*)data+128, _MM_HINT_NTA); +#endif + _vifRegs = (VIFregisters*)vifRegs; + _vifMaskRegs = VIFdmanum ? g_vif1Masks : g_vif0Masks; + _vif = vif; + _vifRow = VIFdmanum ? g_vifRow1 : g_vifRow0; + ft = &VIFfuncTable[ unpackType ]; + func = _vif->usn ? ft->funcU : ft->funcS; + + size<<= 2; +#ifdef _DEBUG + memsize = size; +#endif + if( _vifRegs->offset > 0) { + int destinc, unpacksize; + + VIFUNPACK_LOG("aligning packet size = %d offset %d addr %x\n", size, vifRegs->offset, vif->tag.addr); + + // SSE doesn't handle such small data + if (v->size != (size>>2))ProcessMemSkip(size, unpackType, VIFdmanum); + + if(vifRegs->offset < (u32)ft->qsize){ + if(((u32)size/(u32)ft->dsize) < ((u32)ft->qsize - vifRegs->offset)){ + SysPrintf("wasnt enough left size/dsize = %x left to write %x\n", (size/ft->dsize), (ft->qsize - vifRegs->offset)); + } + unpacksize = min(((u32)size/(u32)ft->dsize), ((u32)ft->qsize - vifRegs->offset)); + } + else { + unpacksize = 0; + SysPrintf("Unpack align offset = 0\n"); + } + destinc = (4 - ft->qsize) + unpacksize; + + func(dest, (u32*)cdata, unpacksize); + size -= unpacksize*ft->dsize; + cdata += unpacksize*ft->dsize; + + vifRegs->num--; + ++vif->cl; + if (vif->cl == vifRegs->cycle.wl) { + if(vifRegs->cycle.cl != vifRegs->cycle.wl){ + dest += ((vifRegs->cycle.cl - vifRegs->cycle.wl)<<2) + destinc; + } else { + dest += destinc; + } + vif->cl = 0; + } + else { + dest += destinc; + } + VIFUNPACK_LOG("aligning packet done size = %d offset %d addr %x\n", size, vifRegs->offset, vif->tag.addr); + + } else if (v->size != (size>>2))ProcessMemSkip(size, unpackType, VIFdmanum); + + if (vifRegs->cycle.cl >= vifRegs->cycle.wl) { // skipping write + +#ifdef _DEBUG + static int s_count=0; +#endif + + int incdest; + + if( vif->cl != 0 ) { + // continuation from last stream + + incdest = ((vifRegs->cycle.cl - vifRegs->cycle.wl)<<2) + 4; + while (size >= ft->gsize && vifRegs->num > 0) { + func( dest, (u32*)cdata, ft->qsize); + cdata += ft->gsize; + size -= ft->gsize; + + vifRegs->num--; + ++vif->cl; + if (vif->cl == vifRegs->cycle.wl) { + dest += incdest; + vif->cl = 0; + break; + } + + dest += 4; + } + + // have to update + _vifRow[0] = _vifRegs->r0; + _vifRow[1] = _vifRegs->r1; + _vifRow[2] = _vifRegs->r2; + _vifRow[3] = _vifRegs->r3; + + } + + if( size >= ft->gsize && !(v->addr&0xf)) { + const UNPACKPARTFUNCTYPESSE* pfn; + int writemask; + //static LARGE_INTEGER lbase, lfinal; + //QueryPerformanceCounter(&lbase); + u32 oldcycle = -1; + +// u16 tempdata[4] = { 0x8000, 0x7fff, 0x1010, 0xd0d0 }; +// vifRegs->cycle.cl = 4; +// vifRegs->cycle.wl = 1; +// SetNewMask(g_vif1Masks, g_vif1HasMask3, 0x3f, ~0x3f); +// memset(dest, 0xcd, 64*4); +// VIFfuncTableSSE[1].funcS[6](dest, (u32*)tempdata, 8); + +#ifdef _MSC_VER + if( VIFdmanum ) { + __asm movaps XMM_ROW, xmmword ptr [g_vifRow1] + __asm movaps XMM_COL, xmmword ptr [g_vifCol1] + } + else { + __asm movaps XMM_ROW, xmmword ptr [g_vifRow0] + __asm movaps XMM_COL, xmmword ptr [g_vifCol0] + } +#else + if( VIFdmanum ) { + __asm__(".intel_syntax\n" + "movaps %%xmm6, xmmword ptr [%0]\n" + "movaps %%xmm7, xmmword ptr [%1]\n" + ".att_syntax\n" : :"r"(g_vifRow1), "r"(g_vifCol1) ); + } + else { + __asm__(".intel_syntax\n" + "movaps %%xmm6, xmmword ptr [%0]\n" + "movaps %%xmm7, xmmword ptr [%1]\n" + ".att_syntax\n" : : "r"(g_vifRow0), "r"(g_vifCol0) ); + } +#endif + + if( vifRegs->cycle.cl == 0 || vifRegs->cycle.wl == 0 || (vifRegs->cycle.cl == vifRegs->cycle.wl && !(vifRegs->code&0x10000000)) ) { + oldcycle = *(u32*)&vifRegs->cycle; + vifRegs->cycle.cl = vifRegs->cycle.wl = 1; + } + size = min(size, (int)vifRegs->num*ft->gsize); //size will always be the same or smaller + + pfn = vif->usn ? VIFfuncTableSSE[unpackType].funcU: VIFfuncTableSSE[unpackType].funcS; + writemask = VIFdmanum ? g_vif1HasMask3[min(vifRegs->cycle.wl,(u8)3)] : g_vif0HasMask3[min(vifRegs->cycle.wl,(u8)3)]; + writemask = pfn[(((vifRegs->code & 0x10000000)>>28)<mode](dest, (u32*)cdata, size); + + if( oldcycle != -1 ) *(u32*)&vifRegs->cycle = oldcycle; + + // if size is left over, update the src,dst pointers + if( writemask > 0 ) { + int left = (size-writemask)/ft->gsize; + cdata += left * ft->gsize; + dest = (u32*)((u8*)dest + ((left/vifRegs->cycle.wl)*vifRegs->cycle.cl + left%vifRegs->cycle.wl)*16); + vifRegs->num -= left; + _vif->cl = (size % (ft->gsize*vifRegs->cycle.wl)) / ft->gsize; + } + else { + vifRegs->num -= size/ft->gsize; + if(vifRegs->num > 0) _vif->cl = (size % (ft->gsize*vifRegs->cycle.wl)) / ft->gsize; + } + + size = writemask; + + _vifRegs->r0 = _vifRow[0]; + _vifRegs->r1 = _vifRow[1]; + _vifRegs->r2 = _vifRow[2]; + _vifRegs->r3 = _vifRow[3]; + //QueryPerformanceCounter(&lfinal); + //((LARGE_INTEGER*)g_nCounters)->QuadPart += lfinal.QuadPart - lbase.QuadPart; + } + else + { + + if(unpackType == 0xC && vifRegs->cycle.cl == vifRegs->cycle.wl) { //No use when SSE is available + // v4-32 + if(vifRegs->mode == 0 && !(vifRegs->code & 0x10000000) && vif->usn == 0){ + vifRegs->num -= size>>4; + memcpy_fast((u8*)dest, cdata, size); + size = 0; + return; + } + } + + incdest = ((vifRegs->cycle.cl - vifRegs->cycle.wl)<<2) + 4; + + while (size >= ft->gsize && vifRegs->num > 0) { + func( dest, (u32*)cdata, ft->qsize); + cdata += ft->gsize; + size -= ft->gsize; + + vifRegs->num--; + ++vif->cl; + if (vif->cl == vifRegs->cycle.wl) { + dest += incdest; + vif->cl = 0; + } + else + { + dest += 4; + } + } + + // have to update + _vifRow[0] = _vifRegs->r0; + _vifRow[1] = _vifRegs->r1; + _vifRow[2] = _vifRegs->r2; + _vifRow[3] = _vifRegs->r3; + } + + // used for debugging vif +// { +// int i, j, k; +// u32* curdest = olddest; +// FILE* ftemp = fopen("temp.txt", s_count?"a+":"w"); +// fprintf(ftemp, "%x %x %x\n", s_count, size, vif->tag.addr); +// fprintf(ftemp, "%x %x %x\n", vifRegs->code>>24, vifRegs->mode, *(u32*)&vifRegs->cycle); +// fprintf(ftemp, "row: %x %x %x %x\n", _vifRow[0], _vifRow[1], _vifRow[2], _vifRow[3]); +// //fprintf(ftemp, "row2: %x %x %x %x\n", _vifRegs->r0, _vifRegs->r1, _vifRegs->r2, _vifRegs->r3); +// +// for(i = 0; i < memsize; ) { +// for(k = 0; k < vifRegs->cycle.wl; ++k) { +// for(j = 0; j <= ((vifRegs->code>>26)&3); ++j) { +// fprintf(ftemp, "%x ", curdest[4*k+j]); +// } +// } +// +// fprintf(ftemp, "\n"); +// curdest += 4*vifRegs->cycle.cl; +// i += (((vifRegs->code>>26)&3)+1)*ft->dsize*vifRegs->cycle.wl; +// } +// fclose(ftemp); +// } +// s_count++; + + if( size >= ft->dsize && vifRegs->num > 0) { + //VIF_LOG("warning, end with size = %d\n", size); + + /* unpack one qword */ + func(dest, (u32*)cdata, size / ft->dsize); + size = 0; + + VIFUNPACK_LOG("leftover done, size %d, vifnum %d, addr %x\n", size, vifRegs->num, vif->tag.addr); + } + + } + else { /* filling write */ + VIF_LOG("*PCSX2*: filling write\n"); + + VIFUNPACK_LOG("filling write %d cl %d, wl %d mask %x mode %x unpacktype %x\n", vifRegs->num, vifRegs->cycle.cl, vifRegs->cycle.wl, vifRegs->mask, vifRegs->mode, unpackType); + while (size >= ft->gsize || vifRegs->num > 0) { + if (vif->cl == vifRegs->cycle.wl) { + vif->cl = 0; + } + // + if (vif->cl < vifRegs->cycle.cl) { /* unpack one qword */ + func( dest, (u32*)cdata, ft->qsize); + cdata += ft->gsize; + size -= ft->gsize; + vif->cl++; + vifRegs->num--; + if (vif->cl == vifRegs->cycle.wl) { + vif->cl = 0; + } + } + else + { + func( dest, (u32*)cdata, ft->qsize); + vif->tag.addr += 16; + vifRegs->num--; + ++vif->cl; + + } + dest += 4; + if(vifRegs->num == 0) break; + } + } +} + +static void vuExecMicro( u32 addr, const u32 VIFdmanum ) +{ + int _cycles; + VURegs * VU; + //void (*_vuExecMicro)(); + +// MessageBox(NULL, "3d doesn't work\n", "Query", MB_OK); +// return; + + if (VIFdmanum == 0) { + VU = &VU0; + vif0FLUSH(); + } else { + VU = &VU1; + vif1FLUSH(); + } + if(VU->vifRegs->itops > (VIFdmanum ? 0x3ffu : 0xffu)) + SysPrintf("VIF%d ITOP overrun! %x\n", VIFdmanum, VU->vifRegs->itops); + + VU->vifRegs->itop = VU->vifRegs->itops; + + if (VIFdmanum == 1) { + /* in case we're handling a VIF1 execMicro + set the top with the tops value */ + VU->vifRegs->top = VU->vifRegs->tops & 0x3ff; + + /* is DBF flag set in VIF_STAT? */ + if (VU->vifRegs->stat & 0x80) { + /* it is, so set tops with base + ofst + and clear stat DBF flag */ + VU->vifRegs->tops = VU->vifRegs->base; + VU->vifRegs->stat &= ~0x80; + } else { + /* it is not, so set tops with base + and set the stat DBF flag */ + VU->vifRegs->tops = VU->vifRegs->base + VU->vifRegs->ofst; + VU->vifRegs->stat |= 0x80; + } + } + + if (VIFdmanum == 0) { + _cycles = VU0.cycle; + vu0ExecMicro(addr); + // too much delay + //g_vifCycles+= (VU0.cycle - _cycles)*BIAS; + } else { + _cycles = VU1.cycle; + vu1ExecMicro(addr); + // too much delay + //g_vifCycles+= (VU1.cycle - _cycles)*BIAS; + } +} + +u8 s_maskwrite[256]; +void vif0Init() +{ + + u32 i; + + for(i = 0; i < 256; ++i ) { + s_maskwrite[i] = ((i&3)==3)||((i&0xc)==0xc)||((i&0x30)==0x30)||((i&0xc0)==0xc0); + } + + SetNewMask(g_vif0Masks, g_vif0HasMask3, 0, 0xffffffff); +} + +static __forceinline void vif0UNPACK(u32 *data) { + int vifNum; + int vl, vn; + int len; + + if(vif0Regs->cycle.wl == 0 && vif0Regs->cycle.wl < vif0Regs->cycle.cl){ + SysPrintf("Vif0 CL %d, WL %d\n", vif0Regs->cycle.cl, vif0Regs->cycle.wl); + vif0.cmd &= ~0x7f; + return; + } + + vif0FLUSH(); + + vl = (vif0.cmd ) & 0x3; + vn = (vif0.cmd >> 2) & 0x3; + vif0.tag.addr = (vif0Regs->code & 0x3ff) << 4; + vif0.usn = (vif0Regs->code >> 14) & 0x1; + vifNum = (vif0Regs->code >> 16) & 0xff; + if ( vifNum == 0 ) vifNum = 256; + vif0Regs->num = vifNum; + + if ( vif0Regs->cycle.wl <= vif0Regs->cycle.cl ) { + len = ((( 32 >> vl ) * ( vn + 1 )) * vifNum + 31) >> 5; + } else { + int n = vif0Regs->cycle.cl * (vifNum / vif0Regs->cycle.wl) + + _limit( vifNum % vif0Regs->cycle.wl, vif0Regs->cycle.cl ); + + len = ( ((( 32 >> vl ) * ( vn + 1 )) * n) + 31 ) >> 5; + } + + vif0.wl = 0; vif0.cl = 0; + vif0.tag.cmd = vif0.cmd; + vif0.tag.addr &= 0xfff; + vif0.tag.size = len; + vif0Regs->offset = 0; +} + +static __forceinline void _vif0mpgTransfer(u32 addr, u32 *data, int size) { +/* SysPrintf("_vif0mpgTransfer addr=%x; size=%x\n", addr, size); + { + FILE *f = fopen("vu1.raw", "wb"); + fwrite(data, 1, size*4, f); + fclose(f); + }*/ + if (memcmp(VU0.Micro + addr, data, size << 2)) { + CpuVU0.Clear(addr, size << 2); // Clear before writing! :/ (cottonvibes) + memcpy_fast(VU0.Micro + addr, data, size << 2); + } +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Vif1 Data Transfer Commands +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static int Vif0TransNull(u32 *data){ // Shouldnt go here + SysPrintf("VIF0 Shouldnt go here CMD = %x\n", vif0Regs->code); + vif0.cmd = 0; + return 0; +} +static int Vif0TransSTMask(u32 *data){ // STMASK + SetNewMask(g_vif0Masks, g_vif0HasMask3, data[0], vif0Regs->mask); + vif0Regs->mask = data[0]; + VIF_LOG("STMASK == %x\n", vif0Regs->mask); + + vif0.tag.size = 0; + vif0.cmd = 0; + return 1; +} + +static int Vif0TransSTRow(u32 *data){ // STROW + int ret; + + u32* pmem = &vif0Regs->r0+(vif0.tag.addr<<2); + u32* pmem2 = g_vifRow0+vif0.tag.addr; + assert( vif0.tag.addr < 4 ); + ret = min(4-vif0.tag.addr, vif0.vifpacketsize); + assert( ret > 0 ); + switch(ret) { + case 4: pmem[12] = data[3]; pmem2[3] = data[3]; + case 3: pmem[8] = data[2]; pmem2[2] = data[2]; + case 2: pmem[4] = data[1]; pmem2[1] = data[1]; + case 1: pmem[0] = data[0]; pmem2[0] = data[0]; break; + + jNO_DEFAULT + } + vif0.tag.addr += ret; + vif0.tag.size -= ret; + if(vif0.tag.size == 0) vif0.cmd = 0; + + return ret; +} + +static int Vif0TransSTCol(u32 *data){ // STCOL + int ret; + + u32* pmem = &vif0Regs->c0+(vif0.tag.addr<<2); + u32* pmem2 = g_vifCol0+vif0.tag.addr; + ret = min(4-vif0.tag.addr, vif0.vifpacketsize); + switch(ret) { + case 4: pmem[12] = data[3]; pmem2[3] = data[3]; + case 3: pmem[8] = data[2]; pmem2[2] = data[2]; + case 2: pmem[4] = data[1]; pmem2[1] = data[1]; + case 1: pmem[0] = data[0]; pmem2[0] = data[0]; break; + + jNO_DEFAULT + } + vif0.tag.addr += ret; + vif0.tag.size -= ret; + if(vif0.tag.size == 0) vif0.cmd = 0; + return ret; +} + +static int Vif0TransMPG(u32 *data){ // MPG + if (vif0.vifpacketsize < vif0.tag.size) { + _vif0mpgTransfer(vif0.tag.addr, data, vif0.vifpacketsize); + vif0.tag.addr += vif0.vifpacketsize << 2; + vif0.tag.size -= vif0.vifpacketsize; + return vif0.vifpacketsize; + } else { + int ret; + _vif0mpgTransfer(vif0.tag.addr, data, vif0.tag.size); + ret = vif0.tag.size; + vif0.tag.size = 0; + vif0.cmd = 0; + return ret; + } +} + +static int Vif0TransUnpack(u32 *data){ // UNPACK + FreezeXMMRegs(1); + if (vif0.vifpacketsize < vif0.tag.size) { + /* size is less that the total size, transfer is + 'in pieces' */ + VIFunpack(data, &vif0.tag, vif0.vifpacketsize, VIF0dmanum); + vif0.tag.size -= vif0.vifpacketsize; + FreezeXMMRegs(0); + return vif0.vifpacketsize; + } else { + int ret; + /* we got all the data, transfer it fully */ + VIFunpack(data, &vif0.tag, vif0.tag.size, VIF0dmanum); + ret = vif0.tag.size; + vif0.tag.size = 0; + vif0.cmd = 0; + FreezeXMMRegs(0); + return ret; + } + +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Vif0 CMD Base Commands +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static void Vif0CMDNop(){ // NOP + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDSTCycl(){ // STCYCL + vif0Regs->cycle.cl = (u8)vif0Regs->code; + vif0Regs->cycle.wl = (u8)(vif0Regs->code >> 8); + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDITop(){ // ITOP + vif0Regs->itops = vif0Regs->code & 0x3ff; + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDSTMod(){ // STMOD + vif0Regs->mode = vif0Regs->code & 0x3; + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDMark(){ // MARK + vif0Regs->mark = (u16)vif0Regs->code; + vif0Regs->stat |= VIF0_STAT_MRK; + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDFlushE(){ // FLUSHE + vif0FLUSH(); + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDMSCALF(){ //MSCAL/F + vuExecMicro( (u16)(vif0Regs->code) << 3, VIF0dmanum ); + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDMSCNT(){ // MSCNT + vuExecMicro( -1, VIF0dmanum ); + vif0.cmd &= ~0x7f; +} + +static void Vif0CMDSTMask(){ // STMASK + vif0.tag.size = 1; +} + +static void Vif0CMDSTRowCol(){// STROW / STCOL + vif0.tag.addr = 0; + vif0.tag.size = 4; +} + +static void Vif0CMDMPGTransfer(){ // MPG + int vifNum; + vif0FLUSH(); + vifNum = (u8)(vif0Regs->code >> 16); + if (vifNum == 0) vifNum = 256; + vif0.tag.addr = (u16)((vif0Regs->code) << 3) & 0xfff; + vif0.tag.size = vifNum * 2; +} + +static void Vif0CMDNull(){ // invalid opcode + // if ME1, then force the vif to interrupt + if ((vif0Regs->err & 0x4) == 0) { //Ignore vifcode and tag mismatch error + SysPrintf( "UNKNOWN VifCmd: %x\n", vif0.cmd ); + vif0Regs->stat |= 1 << 13; + vif0.irq++; + } + vif0.cmd &= ~0x7f; +} + +int VIF0transfer(u32 *data, int size, int istag) { + int ret; + int transferred=vif0.vifstalled ? vif0.irqoffset : 0; // irqoffset necessary to add up the right qws, or else will spin (spiderman) + VIF_LOG( "VIF0transfer: size %x (vif0.cmd %x)\n", size, vif0.cmd ); + + vif0.stallontag = 0; + vif0.vifstalled = 0; + vif0.vifpacketsize = size; + + while (vif0.vifpacketsize > 0) { + + if (vif0.cmd) { + vif0Regs->stat |= VIF0_STAT_VPS_T; //Decompression has started + } + + if (vif0.cmd) { + ret = Vif0TransTLB[(vif0.cmd & 0x7f)](data); + data+= ret; vif0.vifpacketsize-= ret; + if(vif0.cmd == 0) vif0Regs->stat &= ~VIF0_STAT_VPS_T; //We are once again waiting for a new vifcode as the command has cleared + continue; + } + + + + if(vif0.tag.size != 0) SysPrintf("no vif0 cmd but tag size is left last cmd read %x\n", vif0Regs->code); + // if interrupt and new cmd is NOT MARK + if(vif0.irq) break; + + vif0.cmd = (data[0] >> 24); + vif0Regs->code = data[0]; + + vif0Regs->stat |= VIF0_STAT_VPS_D; //We need to set these (Onimusha needs it) + + if ((vif0.cmd & 0x60) == 0x60) { + vif0UNPACK(data); + } else { + VIF_LOG( "VIFtransfer: cmd %x, num %x, imm %x, size %x\n", vif0.cmd, (data[0] >> 16) & 0xff, data[0] & 0xffff, size ); + + if((vif0.cmd & 0x7f) > 0x4A){ + if ((vif0Regs->err & 0x4) == 0) { //Ignore vifcode and tag mismatch error + SysPrintf( "UNKNOWN VifCmd: %x\n", vif0.cmd ); + vif0Regs->stat |= 1 << 13; + vif0.irq++; + } + vif0.cmd = 0; + } else Vif0CMDTLB[(vif0.cmd & 0x7f)](); + } + ++data; + --vif0.vifpacketsize; + + if ((vif0.cmd & 0x80)) { //i bit on vifcode and not masked by VIF0_ERR + if(!(vif0Regs->err & 0x1)){ + VIF_LOG( "Interrupt on VIFcmd: %x (INTC_MASK = %x)\n", vif0.cmd, psHu32(INTC_MASK) ); + + ++vif0.irq; + if(istag && vif0.tag.size <= vif0.vifpacketsize) vif0.stallontag = 1; + } + vif0.cmd &= 0x7f; + if(vif0.tag.size == 0) break; + } + } + transferred += size - vif0.vifpacketsize; + g_vifCycles+= (transferred >> 2)*BIAS; /* guessing */ + // use tag.size because some game doesn't like .cmd + //if( !vif0.cmd ) + + if (vif0.irq && vif0.tag.size == 0) { + vif0.vifstalled = 1; + + if(((vif0Regs->code >> 24) & 0x7f) != 0x7)vif0Regs->stat|= VIF0_STAT_VIS; + //else SysPrintf("VIF0 IRQ on MARK\n"); + // spiderman doesn't break on qw boundaries + vif0.irqoffset = transferred%4; // cannot lose the offset + + if( istag ) { + return -2; + } + + transferred = transferred >> 2; + vif0ch->madr+= (transferred << 4); + vif0ch->qwc-= transferred; + //SysPrintf("Stall on vif0, FromSPR = %x, Vif0MADR = %x Sif0MADR = %x STADR = %x\n", psHu32(0x1000d010), vif0ch->madr, psHu32(0x1000c010), psHu32(DMAC_STADR)); + return -2; + } + + vif0Regs->stat &= ~VIF0_STAT_VPS; //Vif goes idle as the stall happened between commands; + if( vif0.cmd ) vif0Regs->stat |= VIF0_STAT_VPS_W; //Otherwise we wait for the data + + if( !istag ) { + transferred = transferred >> 2; + vif0ch->madr+= (transferred << 4); + vif0ch->qwc-= transferred; + } + + return 0; +} + +int _VIF0chain() { + u32 *pMem; + u32 ret; + + //Hmm, it seems some games (Fatal Frame and Twisted Metal) Try to force the VIF to stop whatever its doing and do something else + //Okay... so in that case we will tell the vif to do so (Refraction) + if (vif0ch->qwc == 0 && vif0.vifstalled == 0) { + vif0Regs->stat &= ~VIF0_STAT_VPS; + vif0.cmd = 0; + vif0.tag.size = 0; + return 0; + } + + pMem = (u32*)dmaGetAddr(vif0ch->madr); + if (pMem == NULL) + return -1; + + if( vif0.vifstalled ) { + ret = VIF0transfer(pMem+vif0.irqoffset, vif0ch->qwc*4-vif0.irqoffset, 0); + } + else { + ret = VIF0transfer(pMem, vif0ch->qwc*4, 0); + } + + return ret; +} + +u32 *vif0ptag; + +int _chainVIF0() { + int id; + //int done=0; + int ret; + + vif0ptag = (u32*)dmaGetAddr(vif0ch->tadr); //Set memory pointer to TADR + if (vif0ptag == NULL) { //Is vif0ptag empty? + SysPrintf("Vif0 Tag BUSERR\n"); + vif0ch->chcr = ( vif0ch->chcr & 0xFFFF ) | ( (*vif0ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register + return -1; //Return -1 as an error has occurred + } + + id = (vif0ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag + vif0ch->qwc = (u16)vif0ptag[0]; //QWC set to lower 16bits of the tag + vif0ch->madr = vif0ptag[1]; //MADR = ADDR field + g_vifCycles+=1; // Add 1 g_vifCycles from the QW read for the tag + VIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx\n", + vif0ptag[1], vif0ptag[0], vif0ch->qwc, id, vif0ch->madr, vif0ch->tadr); + + vif0ch->chcr = ( vif0ch->chcr & 0xFFFF ) | ( (*vif0ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + // Transfer dma tag if tte is set + + if (vif0ch->chcr & 0x40) { + if(vif0.vifstalled == 1) ret = VIF0transfer(vif0ptag+(2+vif0.irqoffset), 2-vif0.irqoffset, 1); //Transfer Tag on stall + else ret = VIF0transfer(vif0ptag+2, 2, 1); //Transfer Tag + if (ret == -1) return -1; //There has been an error + if (ret == -2) { + return -2; //IRQ set by VIFTransfer + } + } + + vif0.done |= hwDmacSrcChainWithStack(vif0ch, id); + + VIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx\n", + vif0ptag[1], vif0ptag[0], vif0ch->qwc, id, vif0ch->madr, vif0ch->tadr); + + + ret = _VIF0chain(); //Transfers the data set by the switch + + + if ((vif0ch->chcr & 0x80) && (vif0ptag[0] >> 31)) { //Check TIE bit of CHCR and IRQ bit of tag + VIF_LOG( "dmaIrq Set\n" ); + + vif0.done = 1; + return vif0.done; //End Transfer + } + return vif0.done; //Return Done +} + +void vif0Interrupt() { +// int ret; + g_vifCycles = 0; //Reset the cycle count, Wouldnt reset on stall if put lower down. + VIF_LOG("vif0Interrupt: %8.8x\n", cpuRegs.cycle); + + + if(vif0.irq && vif0.tag.size == 0) { + vif0Regs->stat|= VIF0_STAT_INT; + hwIntcIrq(VIF0intc); + --vif0.irq; + + if (vif0Regs->stat & (VIF0_STAT_VSS|VIF0_STAT_VIS|VIF0_STAT_VFS)) + { + vif0Regs->stat&= ~0xF000000; // FQC=0 + vif0ch->chcr &= ~0x100; + return; + } + if(vif0ch->qwc > 0 || vif0.irqoffset > 0){ + if(vif0.stallontag == 1) { + _chainVIF0(); + } + else _VIF0chain(); + CPU_INT(0, g_vifCycles); + return; + } + } + + + if((vif0ch->chcr & 0x100) == 0) SysPrintf("Vif0 running when CHCR = %x\n", vif0ch->chcr); + + + if (vif0ch->chcr & 0x4 && vif0.done == 0 && vif0.vifstalled == 0) { + + if( !(psHu32(DMAC_CTRL) & 0x1) ) { + SysPrintf("vif0 dma masked\n"); + return; + } + + if(vif0ch->qwc > 0) _VIF0chain(); + else _chainVIF0(); + CPU_INT(0, g_vifCycles); + return; + } + + + if(vif0ch->qwc > 0) SysPrintf("VIF0 Ending with QWC left\n"); + if(vif0.cmd != 0) SysPrintf("vif0.cmd still set %x\n", vif0.cmd); + vif0ch->chcr &= ~0x100; + hwDmacIrq(DMAC_VIF0); + vif0Regs->stat&= ~0xF000000; // FQC=0 + +} + +// Vif1 Data Transfer Table +int (*Vif0TransTLB[128])(u32 *data) = +{ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x7*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0xF*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x17*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x1F*/ + Vif0TransSTMask , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x27*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x2F*/ + Vif0TransSTRow , Vif0TransSTCol , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x37*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x3F*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x47*/ + Vif0TransNull , Vif0TransNull , Vif0TransMPG , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x4F*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x57*/ + Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , Vif0TransNull , /*0x5F*/ + Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransNull , /*0x67*/ + Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , /*0x6F*/ + Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransNull , /*0x77*/ + Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransNull , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack , Vif0TransUnpack /*0x7F*/ +}; + +// Vif1 CMD Table +void (*Vif0CMDTLB[75])() = +{ + Vif0CMDNop , Vif0CMDSTCycl , Vif0CMDNull , Vif0CMDNull , Vif0CMDITop , Vif0CMDSTMod , Vif0CMDNull, Vif0CMDMark , /*0x7*/ + Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0xF*/ + Vif0CMDFlushE , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull, Vif0CMDMSCALF, Vif0CMDMSCALF, Vif0CMDNull , Vif0CMDMSCNT, /*0x17*/ + Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x1F*/ + Vif0CMDSTMask , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x27*/ + Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x2F*/ + Vif0CMDSTRowCol, Vif0CMDSTRowCol, Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x37*/ + Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x3F*/ + Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , Vif0CMDNull , /*0x47*/ + Vif0CMDNull , Vif0CMDNull , Vif0CMDMPGTransfer +}; + +void dmaVIF0() { + VIF_LOG("dmaVIF0 chcr = %lx, madr = %lx, qwc = %lx\n" + " tadr = %lx, asr0 = %lx, asr1 = %lx\n", + vif0ch->chcr, vif0ch->madr, vif0ch->qwc, + vif0ch->tadr, vif0ch->asr0, vif0ch->asr1 ); + + if(vif0.done == 0) { + SysPrintf("VIF0 Double DMA issue, ignoring\n"); + return; + } + + g_vifCycles = 0; + + + vif0Regs->stat|= 0x8000000; // FQC=8 + + if (!(vif0ch->chcr & 0x4) || vif0ch->qwc > 0) { // Normal Mode + if(_VIF0chain() == -2) { + SysPrintf("Stall on normal %x\n", vif0Regs->stat); + vif0.vifstalled = 1; + return; + } + vif0.done = 1; + CPU_INT(0, g_vifCycles); + return; + } + + // Chain Mode + vif0.done = 0; + CPU_INT(0, 0); +} + + +void vif0Write32(u32 mem, u32 value) { + if (mem == 0x10003830) { // MARK + VIF_LOG("VIF0_MARK write32 0x%8.8x\n", value); + + /* Clear mark flag in VIF0_STAT and set mark with 'value' */ + vif0Regs->stat&= ~VIF0_STAT_MRK; + vif0Regs->mark = value; + } else + if (mem == 0x10003810) { // FBRST + VIF_LOG("VIF0_FBRST write32 0x%8.8x\n", value); + + if (value & 0x1) { + /* Reset VIF */ + //SysPrintf("Vif0 Reset %x\n", vif0Regs->stat); + memzero_obj(vif0); + vif0ch->qwc = 0; //? + cpuRegs.interrupt &= ~1; //Stop all vif0 DMA's + psHu64(0x10004000) = 0; + psHu64(0x10004008) = 0; + vif0.done = 1; + vif0Regs->err = 0; + vif0Regs->stat&= ~(0xF000000|VIF0_STAT_INT|VIF0_STAT_VSS|VIF0_STAT_VIS|VIF0_STAT_VFS|VIF0_STAT_VPS); // FQC=0 + } + if (value & 0x2) { + /* Force Break the VIF */ + /* I guess we should stop the VIF dma here + but not 100% sure (linuz) */ + cpuRegs.interrupt &= ~1; //Stop all vif0 DMA's + vif0Regs->stat |= VIF0_STAT_VFS; + vif0Regs->stat &= ~VIF0_STAT_VPS; + vif0.vifstalled = 1; + SysPrintf("vif0 force break\n"); + } + if (value & 0x4) { + /* Stop VIF */ + /* Not completly sure about this, can't remember what game + used this, but 'draining' the VIF helped it, instead of + just stoppin the VIF (linuz) */ + vif0Regs->stat |= VIF0_STAT_VSS; + vif0Regs->stat &= ~VIF0_STAT_VPS; + vif0.vifstalled = 1; + } + if (value & 0x8) { + int cancel = 0; + + /* Cancel stall, first check if there is a stall to cancel, + and then clear VIF0_STAT VSS|VFS|VIS|INT|ER0|ER1 bits */ + if (vif0Regs->stat & (VIF0_STAT_VSS|VIF0_STAT_VIS|VIF0_STAT_VFS)) { + cancel = 1; + } + + vif0Regs->stat &= ~(VIF0_STAT_VSS | VIF0_STAT_VFS | VIF0_STAT_VIS | + VIF0_STAT_INT | VIF0_STAT_ER0 | VIF0_STAT_ER1); + if (cancel) { + + if( vif0.vifstalled ) { + g_vifCycles = 0; + // loop necessary for spiderman + if(vif0.stallontag == 1){ + _chainVIF0(); + } else _VIF0chain(); + + vif0ch->chcr |= 0x100; + CPU_INT(0, g_vifCycles); // Gets the timing right - Flatout + } + } + } + } else + if (mem == 0x10003820) { // ERR + VIF_LOG("VIF0_ERR write32 0x%8.8x\n", value); + + /* Set VIF0_ERR with 'value' */ + vif0Regs->err = value; + } else{ + SysPrintf("Unknown Vif0 write to %x\n", mem); + if( mem >= 0x10003900 && mem < 0x10003980 ) { + + assert( (mem&0xf) == 0 ); + if( mem < 0x10003940 ) g_vifRow0[(mem>>4)&3] = value; + else g_vifCol0[(mem>>4)&3] = value; + } else psHu32(mem) = value; + } + + /* Other registers are read-only so do nothing for them */ +} + +void vif0Reset() { + /* Reset the whole VIF, meaning the internal pcsx2 vars + and all the registers */ + memzero_obj(vif0); + memzero_obj(*vif0Regs); + SetNewMask(g_vif0Masks, g_vif0HasMask3, 0, 0xffffffff); + psHu64(0x10004000) = 0; + psHu64(0x10004008) = 0; + vif0Regs->stat &= ~VIF0_STAT_VPS; + vif0.done = 1; + vif0Regs->stat&= ~0xF000000; // FQC=0 +} + +void SaveState::vif0Freeze() { + Freeze(vif0); + if( IsLoading() ) + SetNewMask(g_vif0Masks, g_vif0HasMask3, vif0Regs->mask, ~vif0Regs->mask); +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + + +void vif1Init() { + SetNewMask(g_vif1Masks, g_vif1HasMask3, 0, 0xffffffff); +} + +static __forceinline void vif1UNPACK(u32 *data) { + int vifNum; + int vl, vn; + //int len; + if(vif1Regs->cycle.wl == 0){ + if(vif1Regs->cycle.wl < vif1Regs->cycle.cl){ + SysPrintf("Vif1 CL %d, WL %d\n", vif1Regs->cycle.cl, vif1Regs->cycle.wl); + vif1.cmd &= ~0x7f; + return; +} + } + vif1FLUSH(); + + vl = (vif1.cmd ) & 0x3; + vn = (vif1.cmd >> 2) & 0x3; + + vif1.usn = (vif1Regs->code >> 14) & 0x1; + vifNum = (vif1Regs->code >> 16) & 0xff; + if ( vifNum == 0 ) vifNum = 256; + vif1Regs->num = vifNum; + + if ( vif1Regs->cycle.wl <= vif1Regs->cycle.cl ) { + vif1.tag.size = ((( 32 >> vl ) * ( vn + 1 )) * vifNum + 31) >> 5; + } else { + int n = vif1Regs->cycle.cl * (vifNum / vif1Regs->cycle.wl) + + _limit( vifNum % vif1Regs->cycle.wl, vif1Regs->cycle.cl ); + vif1.tag.size = ( ((( 32 >> vl ) * ( vn + 1 )) * n) + 31 ) >> 5; + } + if ( ( vif1Regs->code >> 15) & 0x1 ) { + vif1.tag.addr = (vif1Regs->code + vif1Regs->tops) & 0x3ff; + } else vif1.tag.addr = vif1Regs->code & 0x3ff; + + vif1.cl = 0; + vif1.tag.addr <<= 4; + + vif1.tag.cmd = vif1.cmd; +} + +static __forceinline void _vif1mpgTransfer(u32 addr, u32 *data, int size) { +/* SysPrintf("_vif1mpgTransfer addr=%x; size=%x\n", addr, size); + { + FILE *f = fopen("vu1.raw", "wb"); + fwrite(data, 1, size*4, f); + fclose(f); + }*/ + assert( VU1.Micro > 0 ); + if (memcmp(VU1.Micro + addr, data, size << 2)) { + CpuVU1.Clear(addr, size << 2); // Clear before writing! :/ + memcpy_fast(VU1.Micro + addr, data, size << 2); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Vif1 Data Transfer Commands +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static int Vif1TransNull(u32 *data){ // Shouldnt go here + SysPrintf("Shouldnt go here CMD = %x\n", vif1Regs->code); + vif1.cmd = 0; + return 0; +} +static int Vif1TransSTMask(u32 *data){ // STMASK + SetNewMask(g_vif1Masks, g_vif1HasMask3, data[0], vif1Regs->mask); + vif1Regs->mask = data[0]; + VIF_LOG("STMASK == %x\n", vif1Regs->mask); + + vif1.tag.size = 0; + vif1.cmd = 0; + return 1; +} + +static int Vif1TransSTRow(u32 *data){ + int ret; + + u32* pmem = &vif1Regs->r0+(vif1.tag.addr<<2); + u32* pmem2 = g_vifRow1+vif1.tag.addr; + assert( vif1.tag.addr < 4 ); + ret = min(4-vif1.tag.addr, vif1.vifpacketsize); + assert( ret > 0 ); + switch(ret) { + case 4: pmem[12] = data[3]; pmem2[3] = data[3]; + case 3: pmem[8] = data[2]; pmem2[2] = data[2]; + case 2: pmem[4] = data[1]; pmem2[1] = data[1]; + case 1: pmem[0] = data[0]; pmem2[0] = data[0]; break; + jNO_DEFAULT; + } + vif1.tag.addr += ret; + vif1.tag.size -= ret; + if(vif1.tag.size == 0) vif1.cmd = 0; + + return ret; +} + +static int Vif1TransSTCol(u32 *data){ + int ret; + + u32* pmem = &vif1Regs->c0+(vif1.tag.addr<<2); + u32* pmem2 = g_vifCol1+vif1.tag.addr; + ret = min(4-vif1.tag.addr, vif1.vifpacketsize); + switch(ret) { + case 4: pmem[12] = data[3]; pmem2[3] = data[3]; + case 3: pmem[8] = data[2]; pmem2[2] = data[2]; + case 2: pmem[4] = data[1]; pmem2[1] = data[1]; + case 1: pmem[0] = data[0]; pmem2[0] = data[0]; break; + jNO_DEFAULT; + } + vif1.tag.addr += ret; + vif1.tag.size -= ret; + if(vif1.tag.size == 0) vif1.cmd = 0; + return ret; +} + +static int Vif1TransMPG(u32 *data){ + if (vif1.vifpacketsize < vif1.tag.size) { + _vif1mpgTransfer(vif1.tag.addr, data, vif1.vifpacketsize); + vif1.tag.addr += vif1.vifpacketsize << 2; + vif1.tag.size -= vif1.vifpacketsize; + return vif1.vifpacketsize; + } else { + int ret; + _vif1mpgTransfer(vif1.tag.addr, data, vif1.tag.size); + ret = vif1.tag.size; + vif1.tag.size = 0; + vif1.cmd = 0; + return ret; + } +} +u32 splittransfer[4]; +u32 splitptr = 0; + +static int Vif1TransDirectHL(u32 *data){ + int ret = 0; + + + if(splitptr > 0){ //Leftover data from the last packet, filling the rest and sending to the GS + if(splitptr < 4 && vif1.vifpacketsize >= (4-splitptr)){ + + while(splitptr < 4){ + splittransfer[splitptr++] = (u32)data++; + ret++; + vif1.tag.size--; + } + } + + if( mtgsThread != NULL ) + { + // copy 16 bytes the fast way: + const u64* src = (u64*)splittransfer[0]; + const uint count = mtgsThread->PrepDataPacket( GIF_PATH_2, src, 1); + jASSUME( count == 1 ); + u64* dst = (u64*)mtgsThread->GetDataPacketPtr(); + dst[0] = src[0]; + dst[1] = src[1]; + + mtgsThread->SendDataPacket(); + } + else + { + FreezeXMMRegs(1); + FreezeMMXRegs(1); + GSGIFTRANSFER2((u32*)splittransfer[0], 1); + FreezeMMXRegs(0); + FreezeXMMRegs(0); + } + + if(vif1.tag.size == 0) vif1.cmd = 0; + splitptr = 0; + return ret; + } + if (vif1.vifpacketsize < vif1.tag.size) { + if(vif1.vifpacketsize < 4 && splitptr != 4) { //Not a full QW left in the buffer, saving left over data + ret = vif1.vifpacketsize; + while(ret > 0){ + splittransfer[splitptr++] = (u32)data++; + vif1.tag.size--; + ret--; + } + + return vif1.vifpacketsize; + } + + vif1.tag.size-= vif1.vifpacketsize; + ret = vif1.vifpacketsize; + } else { + ret = vif1.tag.size; + vif1.tag.size = 0; + vif1.cmd = 0; + } + + //TODO: ret is guaranteed to be qword aligned ? + + if( mtgsThread != NULL ) + { + //unaligned copy.VIF handling is -very- messy, so i'l use this code til i fix it :) + // Round ret up, just in case it's not 128bit aligned. + const uint count = mtgsThread->PrepDataPacket( GIF_PATH_2, data, (ret+3)>>2 ); + memcpy_fast( mtgsThread->GetDataPacketPtr(), data, count<<4 ); + mtgsThread->SendDataPacket(); + } + else { + + FreezeXMMRegs(1); + FreezeMMXRegs(1); + GSGIFTRANSFER2(data, (ret >> 2)); + FreezeMMXRegs(0); + FreezeXMMRegs(0); + } + + return ret; +} + + +static int Vif1TransUnpack(u32 *data){ + FreezeXMMRegs(1); + + if (vif1.vifpacketsize < vif1.tag.size) + { + /* size is less that the total size, transfer is + 'in pieces' */ + VIFunpack(data, &vif1.tag, vif1.vifpacketsize, VIF1dmanum); + vif1.tag.size -= vif1.vifpacketsize; + FreezeXMMRegs(0); + return vif1.vifpacketsize; + } + else + { + int ret; + /* we got all the data, transfer it fully */ + VIFunpack(data, &vif1.tag, vif1.tag.size, VIF1dmanum); + //g_vifCycles+= vif1.tag.size >> 1; + ret = vif1.tag.size; + vif1.tag.size = 0; + vif1.cmd = 0; + FreezeXMMRegs(0); + return ret; + } + +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Vif1 CMD Base Commands +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int transferred = 0; +int Path3transfer=0; +static void Vif1CMDNop(){ // NOP + vif1.cmd &= ~0x7f; +} +static void Vif1CMDSTCycl(){ // STCYCL + vif1Regs->cycle.cl = (u8)vif1Regs->code; + vif1Regs->cycle.wl = (u8)(vif1Regs->code >> 8); + vif1.cmd &= ~0x7f; +} +static void Vif1CMDOffset(){ // OFFSET + vif1Regs->ofst = vif1Regs->code & 0x3ff; + vif1Regs->stat &= ~0x80; + vif1Regs->tops = vif1Regs->base; + vif1.cmd &= ~0x7f; +} +static void Vif1CMDBase(){ // BASE + vif1Regs->base = vif1Regs->code & 0x3ff; + vif1.cmd &= ~0x7f; +} +static void Vif1CMDITop(){ // ITOP + vif1Regs->itops = vif1Regs->code & 0x3ff; + vif1.cmd &= ~0x7f; +} + +static void Vif1CMDSTMod(){ // STMOD + vif1Regs->mode = vif1Regs->code & 0x3; + vif1.cmd &= ~0x7f; +} + +static void Vif1CMDMskPath3(){ // MSKPATH3 + + vif1Regs->mskpath3 = (vif1Regs->code >> 15) & 0x1; + //SysPrintf("VIF MSKPATH3 %x\n", vif1Regs->mskpath3); +#ifdef GSPATH3FIX + + if ( (vif1Regs->code >> 15) & 0x1 ) { + while((gif->chcr & 0x100)){ //Can be done 2 different ways, depends on the game/company + if(path3hack == 0)if(Path3transfer == 0 && gif->qwc == 0) break; + + gsInterrupt(); + + if(path3hack == 1)if(gif->qwc == 0) break; //add games not working with it to elfheader.c to enable this instead + } + //while(gif->chcr & 0x100) gsInterrupt(); // Finish the transfer first + psHu32(GIF_STAT) |= 0x2; + } else { + if(gif->chcr & 0x100) CPU_INT(2, (transferred>>2) * BIAS); // Restart Path3 on its own, time it right! + psHu32(GIF_STAT) &= ~0x2; + } +#else + if ( vif1Regs->mskpath3 ) { + if(gif->qwc) _GIFchain(); // Finish the transfer first + psHu32(GIF_STAT) |= 0x2; + } else { + psHu32(GIF_STAT) &= ~0x2; + if(gif->qwc) _GIFchain(); // Finish the transfer first + } +#endif + vif1.cmd &= ~0x7f; +} + +static void Vif1CMDMark(){ // MARK + vif1Regs->mark = (u16)vif1Regs->code; + vif1Regs->stat |= VIF1_STAT_MRK; + vif1.cmd &= ~0x7f; +} +static void Vif1CMDFlush(){ // FLUSH/E/A + + vif1FLUSH(); + + if((vif1.cmd & 0x7f) == 0x13) { + while((gif->chcr & 0x100)){ + if(Path3transfer == 0 && gif->qwc == 0) break; + gsInterrupt(); + } + } + + vif1.cmd &= ~0x7f; +} +static void Vif1CMDMSCALF(){ //MSCAL/F + vuExecMicro( (u16)(vif1Regs->code) << 3, VIF1dmanum ); + vif1.cmd &= ~0x7f; +} +static void Vif1CMDMSCNT(){ // MSCNT + vuExecMicro( -1, VIF1dmanum ); + vif1.cmd &= ~0x7f; +} +static void Vif1CMDSTMask(){ // STMASK + vif1.tag.size = 1; +} +static void Vif1CMDSTRowCol(){// STROW / STCOL + vif1.tag.addr = 0; + vif1.tag.size = 4; +} + +static void Vif1CMDMPGTransfer(){ // MPG + int vifNum; + vif1FLUSH(); + vifNum = (u8)(vif1Regs->code >> 16); + if (vifNum == 0) vifNum = 256; + vif1.tag.addr = (u16)((vif1Regs->code) << 3) & 0x3fff; + vif1.tag.size = vifNum * 2; +} +static void Vif1CMDDirectHL(){ // DIRECT/HL + int vifImm; + vifImm = (u16)vif1Regs->code; + if (vifImm == 0) { + vif1.tag.size = 65536 << 2; + } else { + vif1.tag.size = vifImm << 2; + } + while((gif->chcr & 0x100) && (vif1.cmd & 0x7f) == 0x51){ + gsInterrupt(); //DirectHL flushes the lot + //if((psHu32(GIF_STAT) & 0xE00) == 0) break; + } +} +static void Vif1CMDNull(){ // invalid opcode + // if ME1, then force the vif to interrupt + + if ((vif1Regs->err & 0x4) == 0) { //Ignore vifcode and tag mismatch error + SysPrintf( "UNKNOWN VifCmd: %x\n", vif1.cmd ); + vif1Regs->stat |= 1 << 13; + vif1.irq++; + } + vif1.cmd = 0; +} + +// Vif1 Data Transfer Table + +int (*Vif1TransTLB[128])(u32 *data) = +{ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x7*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0xF*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x17*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x1F*/ + Vif1TransSTMask , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x27*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x2F*/ + Vif1TransSTRow , Vif1TransSTCol , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x37*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x3F*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x47*/ + Vif1TransNull , Vif1TransNull , Vif1TransMPG , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x4F*/ + Vif1TransDirectHL, Vif1TransDirectHL, Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x57*/ + Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , Vif1TransNull , /*0x5F*/ + Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransNull , /*0x67*/ + Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , /*0x6F*/ + Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransNull , /*0x77*/ + Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransNull , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack , Vif1TransUnpack /*0x7F*/ +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Vif1 CMD Table +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void (*Vif1CMDTLB[82])() = +{ + Vif1CMDNop , Vif1CMDSTCycl , Vif1CMDOffset , Vif1CMDBase , Vif1CMDITop , Vif1CMDSTMod , Vif1CMDMskPath3, Vif1CMDMark , /*0x7*/ + Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0xF*/ + Vif1CMDFlush , Vif1CMDFlush , Vif1CMDNull , Vif1CMDFlush, Vif1CMDMSCALF, Vif1CMDMSCALF, Vif1CMDNull , Vif1CMDMSCNT, /*0x17*/ + Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x1F*/ + Vif1CMDSTMask , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x27*/ + Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x2F*/ + Vif1CMDSTRowCol, Vif1CMDSTRowCol, Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x37*/ + Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x3F*/ + Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x47*/ + Vif1CMDNull , Vif1CMDNull , Vif1CMDMPGTransfer, Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , Vif1CMDNull , /*0x4F*/ + Vif1CMDDirectHL, Vif1CMDDirectHL +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int VIF1transfer(u32 *data, int size, int istag) { + int ret; + transferred=vif1.vifstalled ? vif1.irqoffset : 0; // irqoffset necessary to add up the right qws, or else will spin (spiderman) + + VIF_LOG( "VIF1transfer: size %x (vif1.cmd %x)\n", size, vif1.cmd ); + + vif1.irqoffset = 0; + vif1.vifstalled = 0; + vif1.stallontag = 0; + vif1.vifpacketsize = size; + + while (vif1.vifpacketsize > 0) { + + if (vif1.cmd) { + vif1Regs->stat |= VIF1_STAT_VPS_T; //Decompression has started + } + + if (vif1.cmd) { + ret = Vif1TransTLB[vif1.cmd](data); + data+= ret; vif1.vifpacketsize-= ret; + if(vif1.cmd == 0) vif1Regs->stat &= ~VIF1_STAT_VPS_T; //We are once again waiting for a new vifcode as the command has cleared + continue; + } + + if(vif1.tag.size != 0) SysPrintf("no vif1 cmd but tag size is left last cmd read %x\n", vif1Regs->code); + + if(vif1.irq) break; + + vif1.cmd = (data[0] >> 24); + vif1Regs->code = data[0]; + + vif1Regs->stat |= VIF1_STAT_VPS_D; + if ((vif1.cmd & 0x60) == 0x60) { + vif1UNPACK(data); + } else { + VIF_LOG( "VIFtransfer: cmd %x, num %x, imm %x, size %x\n", vif1.cmd, (data[0] >> 16) & 0xff, data[0] & 0xffff, vif1.vifpacketsize ); + + if((vif1.cmd & 0x7f) > 0x51){ + if ((vif1Regs->err & 0x4) == 0) { //Ignore vifcode and tag mismatch error + SysPrintf( "UNKNOWN VifCmd: %x\n", vif1.cmd ); + vif1Regs->stat |= 1 << 13; + vif1.irq++; + } + vif1.cmd = 0; + } else Vif1CMDTLB[(vif1.cmd & 0x7f)](); + } + + ++data; + --vif1.vifpacketsize; + + + if ((vif1.cmd & 0x80)) { //i bit on vifcode and not masked by VIF1_ERR + VIF_LOG( "Interrupt on VIFcmd: %x (INTC_MASK = %x)\n", vif1.cmd, psHu32(INTC_MASK) ); + + if(!(vif1Regs->err & 0x1)){ + ++vif1.irq; + if(istag && vif1.tag.size <= vif1.vifpacketsize) vif1.stallontag = 1; + } + vif1.cmd &= 0x7f; + if(vif1.tag.size == 0) break; + } + } + + transferred += size - vif1.vifpacketsize; + g_vifCycles+= (transferred>>2)*BIAS; /* guessing */ + + if (vif1.irq && vif1.cmd == 0) { + vif1.vifstalled = 1; + + + + if(((vif1Regs->code >> 24) & 0x7f) != 0x7)vif1Regs->stat|= VIF1_STAT_VIS; // Note: commenting this out fixes WALL-E + + // spiderman doesn't break on qw boundaries + vif1.irqoffset = transferred%4; // cannot lose the offset + + if( istag ) { + return -2; + } + + transferred = transferred >> 2; + vif1ch->madr+= (transferred << 4); + vif1ch->qwc-= transferred; + //SysPrintf("Stall on vif1, FromSPR = %x, Vif1MADR = %x Sif0MADR = %x STADR = %x\n", psHu32(0x1000d010), vif1ch->madr, psHu32(0x1000c010), psHu32(DMAC_STADR)); + return -2; + } + + vif1Regs->stat &= ~VIF1_STAT_VPS; //Vif goes idle as the stall happened between commands; + if( vif1.cmd ) vif1Regs->stat |= VIF1_STAT_VPS_W; //Otherwise we wait for the data + + if( !istag ) { + + transferred = transferred >> 2; + vif1ch->madr+= (transferred << 4); + vif1ch->qwc-= transferred; + } + + return 0; +} + +int _VIF1chain() { + u32 *pMem; + //u32 qwc = vif1ch->qwc; + u32 ret; + + //Hmm, it seems some games (Fatal Frame and Twisted Metal) Try to force the VIF to stop whatever its doing and do something else + //Okay... so in that case we will tell the vif to do so (Refraction) + if (vif1ch->qwc == 0 && vif1.vifstalled == 0) { + vif1Regs->stat &= ~VIF1_STAT_VPS; + vif1.cmd = 0; + vif1.tag.size = 0; + return 0; + } + + pMem = (u32*)dmaGetAddr(vif1ch->madr); + if (pMem == NULL) + return -1; + + VIF_LOG("VIF1chain size=%d, madr=%lx, tadr=%lx\n", + vif1ch->qwc, vif1ch->madr, vif1ch->tadr); + + if( vif1.vifstalled ) { + ret = VIF1transfer(pMem+vif1.irqoffset, vif1ch->qwc*4-vif1.irqoffset, 0); + } + else { + ret = VIF1transfer(pMem, vif1ch->qwc*4, 0); + } + /*vif1ch->madr+= (vif1ch->qwc << 4); + vif1ch->qwc-= qwc;*/ + + return ret; +} + +static int prevvifcycles = 0; +static u32* prevviftag = NULL; +u32 *vif1ptag; +int _chainVIF1() { + int id; + int ret; + + vif1ptag = (u32*)dmaGetAddr(vif1ch->tadr); //Set memory pointer to TADR + if (vif1ptag == NULL) { //Is vif0ptag empty? + SysPrintf("Vif1 Tag BUSERR\n"); + vif1ch->chcr = ( vif1ch->chcr & 0xFFFF ) | ( (*vif1ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register + return -1; //Return -1 as an error has occurred + } + + id = (vif1ptag[0] >> 28) & 0x7; //ID for DmaChain copied from bit 28 of the tag + vif1ch->qwc = (u16)vif1ptag[0]; //QWC set to lower 16bits of the tag + vif1ch->madr = vif1ptag[1]; //MADR = ADDR field + g_vifCycles+=1; // Add 1 g_vifCycles from the QW read for the tag + + vif1ch->chcr = ( vif1ch->chcr & 0xFFFF ) | ( (*vif1ptag) & 0xFFFF0000 ); //Transfer upper part of tag to CHCR bits 31-15 + // Transfer dma tag if tte is set + + VIF_LOG("VIF1 Tag %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx\n", + vif1ptag[1], vif1ptag[0], vif1ch->qwc, id, vif1ch->madr, vif1ch->tadr); + + //} else + + + if (!vif1.done && (psHu32(DMAC_CTRL) & 0xC0) == 0x40 && id == 4) { // STD == VIF1 + //vif1.done |= hwDmacSrcChainWithStack(vif1ch, id); + // there are still bugs, need to also check if gif->madr +16*qwc >= stadr, if not, stall + if( (vif1ch->madr + vif1ch->qwc * 16) >= psHu32(DMAC_STADR) ) { + // stalled + + hwDmacIrq(13); + return 0; + } + } + + if (vif1ch->chcr & 0x40) { + if(vif1.vifstalled == 1) ret = VIF1transfer(vif1ptag+(2+vif1.irqoffset), 2-vif1.irqoffset, 1); //Transfer Tag on stall + else ret = VIF1transfer(vif1ptag+2, 2, 1); //Transfer Tag + if (ret == -1) return -1; //There has been an error + if (ret == -2) { + return -2; //IRQ set by VIFTransfer + } + } + + vif1.done |= hwDmacSrcChainWithStack(vif1ch, id); + + ret = _VIF1chain(); //Transfers the data set by the switch + + if ((vif1ch->chcr & 0x80) && (vif1ptag[0] >> 31)) { //Check TIE bit of CHCR and IRQ bit of tag + VIF_LOG( "dmaIrq Set\n" ); + + vif1.done = 1; + return 0; //End Transfer + } + return vif1.done;//Return Done +} + +__forceinline void vif1Interrupt() { + VIF_LOG("vif1Interrupt: %8.8x\n", cpuRegs.cycle); + + g_vifCycles = 0; + + + if(vif1.irq && vif1.tag.size == 0) { + vif1Regs->stat|= VIF1_STAT_INT; + hwIntcIrq(VIF1intc); + --vif1.irq; + if(vif1Regs->stat & (VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS)) + { + vif1Regs->stat&= ~0x1F000000; // FQC=0 + // One game doesnt like vif stalling at end, cant remember what. Spiderman isnt keen on it tho + vif1ch->chcr &= ~0x100; + return; + } + + if(vif1ch->qwc > 0 || vif1.irqoffset > 0){ + if(vif1.stallontag == 1) { + _chainVIF1(); + } + else _VIF1chain();//CPU_INT(13, vif1ch->qwc * BIAS); + CPU_INT(1, 0); + return; + } + } + + + //} + if((vif1ch->chcr & 0x100) == 0) SysPrintf("Vif1 running when CHCR == %x\n", vif1ch->chcr); + + + if ((vif1ch->chcr & 0x104) == 0x104 && vif1.done == 0) { + + if( !(psHu32(DMAC_CTRL) & 0x1) ) { + SysPrintf("vif1 dma masked\n"); + return; + } + + _chainVIF1(); + CPU_INT(1, 0); + + return; + } +#ifdef PCSX2_DEVBUILD + if(vif1ch->qwc > 0) SysPrintf("VIF1 Ending with QWC left\n"); + if(vif1.cmd != 0) SysPrintf("vif1.cmd still set %x\n", vif1.cmd); +#endif + + prevviftag = NULL; + prevvifcycles = 0; + vif1ch->chcr &= ~0x100; + hwDmacIrq(DMAC_VIF1); + if(vif1Regs->mskpath3 == 0 || (vif1ch->chcr & 0x1) == 0x1)vif1Regs->stat&= ~0x1F000000; // FQC=0 +} + +#define spr0 ((DMACh*)&PS2MEM_HW[0xD000]) +void dmaVIF1() +{ + + VIF_LOG("dmaVIF1 chcr = %lx, madr = %lx, qwc = %lx\n" + " tadr = %lx, asr0 = %lx, asr1 = %lx\n", + vif1ch->chcr, vif1ch->madr, vif1ch->qwc, + vif1ch->tadr, vif1ch->asr0, vif1ch->asr1 ); + + if(vif1.done == 0 && (psHu32(DMAC_CTRL) & 0xC) != 0x8) { + SysPrintf("VIF1 Double DMA issue, ignoring\n"); + return; + } + + vif1.done = 0; + g_vifCycles = 0; + + if (((psHu32(DMAC_CTRL) & 0xC) == 0x8)) { // VIF MFIFO + //SysPrintf("VIFMFIFO\n"); + if(!(vif1ch->chcr & 0x4)) SysPrintf("MFIFO mode != Chain! %x\n", vif1ch->chcr); + if(vif1ch->madr != spr0->madr)vifMFIFOInterrupt(); + return; + } + +#ifdef PCSX2_DEVBUILD + if ((psHu32(DMAC_CTRL) & 0xC0) == 0x40) { // STD == VIF1 + //SysPrintf("VIF Stall Control Source = %x, Drain = %x\n", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3); + //return; + } +#endif + + + vif1Regs->stat|= 0x10000000; // FQC=16 + + if (!(vif1ch->chcr & 0x4) || vif1ch->qwc > 0) { // Normal Mode + if ((psHu32(DMAC_CTRL) & 0xC0) == 0x40) { + SysPrintf("DMA Stall Control on VIF1 normal\n"); + } + if ((vif1ch->chcr & 0x1)) { // to Memory + if(_VIF1chain() == -2) { + SysPrintf("Stall on normal\n"); + //vif1.vifstalled = 1; + } + CPU_INT(1, g_vifCycles); + } else { + + int size; + u64* pMem = (u64*)dmaGetAddr(vif1ch->madr); + + // VIF from gsMemory + + if (pMem == NULL) { //Is vif0ptag empty? + SysPrintf("Vif1 Tag BUSERR\n"); + psHu32(DMAC_STAT)|= 1<<15; //If yes, set BEIS (BUSERR) in DMAC_STAT register + vif1.done = 1; + vif1Regs->stat&= ~0x1f000000; + vif1ch->qwc = 0; + CPU_INT(1, 0); + + return; //Return -1 as an error has occurred + } + + // MTGS concerns: The MTGS is inherently disagreeable with the idea of downloading + // stuff from the GS. The *only* way to handle this case safely is to flush the GS + // completely and execute the transfer there-after. + + FreezeXMMRegs(1); + if( GSreadFIFO2 == NULL ) { + for (size=vif1ch->qwc; size>0; --size) { + if (size > 1 ) { + mtgsWaitGS(); + GSreadFIFO((u64*)&PS2MEM_HW[0x5000]); + } + pMem[0] = psHu64(0x5000); + pMem[1] = psHu64(0x5008); pMem+= 2; + } + } + else { + mtgsWaitGS(); + GSreadFIFO2(pMem, vif1ch->qwc); + + // set incase read + psHu64(0x5000) = pMem[2*vif1ch->qwc-2]; + psHu64(0x5008) = pMem[2*vif1ch->qwc-1]; + } + FreezeXMMRegs(0); + + if(vif1Regs->mskpath3 == 0)vif1Regs->stat&= ~0x1f000000; + g_vifCycles += vif1ch->qwc * 2; + vif1ch->madr += vif1ch->qwc * 16; // mgs3 scene changes + vif1ch->qwc = 0; + CPU_INT(1, g_vifCycles); + + } + + vif1.done = 1; + return; + } + + // Chain Mode + vif1.done = 0; + CPU_INT(1, 0); +} + + +void vif1Write32(u32 mem, u32 value) { + if (mem == 0x10003c30) { // MARK + VIF_LOG("VIF1_MARK write32 0x%8.8x\n", value); + + /* Clear mark flag in VIF1_STAT and set mark with 'value' */ + vif1Regs->stat&= ~VIF1_STAT_MRK; + vif1Regs->mark = value; + } else + if (mem == 0x10003c10) { // FBRST + VIF_LOG("VIF1_FBRST write32 0x%8.8x\n", value); + + if (value & 0x1) { + /* Reset VIF */ + memzero_obj(vif1); + cpuRegs.interrupt &= ~((1<<1) | (1<<10)); //Stop all vif1 DMA's + vif1ch->qwc = 0; //? + psHu64(0x10005000) = 0; + psHu64(0x10005008) = 0; + vif1.done = 1; + vif1Regs->err = 0; + vif1Regs->stat&= ~(0x1F800000|VIF1_STAT_INT|VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS|VIF1_STAT_VPS); // FQC=0 + } + if (value & 0x2) { + /* Force Break the VIF */ + /* I guess we should stop the VIF dma here + but not 100% sure (linuz) */ + vif1Regs->stat |= VIF1_STAT_VFS; + vif1Regs->stat &= ~VIF1_STAT_VPS; + cpuRegs.interrupt &= ~((1<<1) | (1<<10)); //Stop all vif1 DMA's + vif1.vifstalled = 1; + SysPrintf("vif1 force break\n"); + } + if (value & 0x4) { + /* Stop VIF */ + /* Not completly sure about this, can't remember what game + used this, but 'draining' the VIF helped it, instead of + just stoppin the VIF (linuz) */ + vif1Regs->stat |= VIF1_STAT_VSS; + vif1Regs->stat &= ~VIF1_STAT_VPS; + vif1.vifstalled = 1; + } + if (value & 0x8) { + int cancel = 0; + + /* Cancel stall, first check if there is a stall to cancel, + and then clear VIF1_STAT VSS|VFS|VIS|INT|ER0|ER1 bits */ + if (vif1Regs->stat & (VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS)) { + cancel = 1; + } + + vif1Regs->stat &= ~(VIF1_STAT_VSS | VIF1_STAT_VFS | VIF1_STAT_VIS | + VIF1_STAT_INT | VIF1_STAT_ER0 | VIF1_STAT_ER1); + if (cancel) { + + if( vif1.vifstalled ) { + g_vifCycles = 0; + // loop necessary for spiderman + if((psHu32(DMAC_CTRL) & 0xC) == 0x8){ + //SysPrintf("MFIFO Stall\n"); + CPU_INT(10, 0); + }else { + if(vif1.stallontag == 1){ + //SysPrintf("Sorting VIF Stall on tag\n"); + _chainVIF1(); + } else _VIF1chain(); + + CPU_INT(1, g_vifCycles); // Gets the timing right - Flatout + } + vif1ch->chcr |= 0x100; + } + } + } + } else + if (mem == 0x10003c20) { // ERR + VIF_LOG("VIF1_ERR write32 0x%8.8x\n", value); + + /* Set VIF1_ERR with 'value' */ + vif1Regs->err = value; + } else + if (mem == 0x10003c00) { // STAT + VIF_LOG("VIF1_STAT write32 0x%8.8x\n", value); + +#ifdef PCSX2_DEVBUILD + /* Only FDR bit is writable, so mask the rest */ + if( (vif1Regs->stat & VIF1_STAT_FDR) ^ (value & VIF1_STAT_FDR) ) { + // different so can't be stalled + if (vif1Regs->stat & (VIF1_STAT_INT|VIF1_STAT_VSS|VIF1_STAT_VIS|VIF1_STAT_VFS)) { + SysPrintf("changing dir when vif1 fifo stalled\n"); + } + } +#endif + + vif1Regs->stat = (vif1Regs->stat & ~VIF1_STAT_FDR) | (value & VIF1_STAT_FDR); + if (vif1Regs->stat & VIF1_STAT_FDR) { + vif1Regs->stat|= 0x01000000; + } else { + vif1ch->qwc = 0; + vif1.vifstalled = 0; + vif1.done = 1; + vif1Regs->stat&= ~0x1F000000; // FQC=0 + } + } + else + if (mem == 0x10003c50) { // MODE + vif1Regs->mode = value; + } + else { + SysPrintf("Unknown Vif1 write to %x\n", mem); + if( mem >= 0x10003d00 && mem < 0x10003d80 ) { + assert( (mem&0xf) == 0 ); + if( mem < 0x10003d40) g_vifRow1[(mem>>4)&3] = value; + else g_vifCol1[(mem>>4)&3] = value; + } else psHu32(mem) = value; + } + + /* Other registers are read-only so do nothing for them */ +} + +void vif1Reset() { + /* Reset the whole VIF, meaning the internal pcsx2 vars + and all the registers */ + memzero_obj(vif1); + memzero_obj(*vif1Regs); + SetNewMask(g_vif1Masks, g_vif1HasMask3, 0, 0xffffffff); + psHu64(0x10005000) = 0; + psHu64(0x10005008) = 0; + vif1Regs->stat &= ~VIF1_STAT_VPS; + vif1.done = 1; + cpuRegs.interrupt &= ~((1<<1) | (1<<10)); //Stop all vif1 DMA's + vif1Regs->stat&= ~0x1F000000; // FQC=0 +} + +void SaveState::vif1Freeze() { + Freeze(vif1); + if( IsLoading() ) + SetNewMask(g_vif1Masks, g_vif1HasMask3, vif1Regs->mask, ~vif1Regs->mask); +} diff --git a/pcsx2/VifDma.h b/pcsx2/VifDma.h index 6e24133de8..db80fc9343 100644 --- a/pcsx2/VifDma.h +++ b/pcsx2/VifDma.h @@ -1,97 +1,97 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef __VIFDMA_H__ -#define __VIFDMA_H__ - -struct vifCode { - u32 addr; - u32 size; - u32 cmd; - u16 wl; - u16 cl; -}; - -// NOTE, if debugging vif stalls, use sega classics, spyro, gt4, and taito -struct vifStruct { - vifCode tag; - int cmd; - int irq; - int cl; - int wl; - u8 usn; - u8 done; - u8 vifstalled; - u8 stallontag; - u8 irqoffset; // 32bit offset where next vif code is - u32 savedtag; // need this for backwards compat with save states - u32 vifpacketsize; -}; - -extern vifStruct vif0, vif1; -extern int Path3transfer; - -#define vif0ch ((DMACh*)&PS2MEM_HW[0x8000]) -#define vif1ch ((DMACh*)&PS2MEM_HW[0x9000]) - -void UNPACK_S_32( u32 *dest, u32 *data, int size ); - -void UNPACK_S_16u( u32 *dest, u32 *data, int size ); -void UNPACK_S_16s( u32 *dest, u32 *data, int size ); - -void UNPACK_S_8u( u32 *dest, u32 *data, int size ); -void UNPACK_S_8s( u32 *dest, u32 *data, int size ); - -void UNPACK_V2_32( u32 *dest, u32 *data, int size ); - -void UNPACK_V2_16u( u32 *dest, u32 *data, int size ); -void UNPACK_V2_16s( u32 *dest, u32 *data, int size ); - -void UNPACK_V2_8u( u32 *dest, u32 *data, int size ); -void UNPACK_V2_8s( u32 *dest, u32 *data, int size ); - -void UNPACK_V3_32( u32 *dest, u32 *data, int size ); - -void UNPACK_V3_16u( u32 *dest, u32 *data, int size ); -void UNPACK_V3_16s( u32 *dest, u32 *data, int size ); - -void UNPACK_V3_8u( u32 *dest, u32 *data, int size ); -void UNPACK_V3_8s( u32 *dest, u32 *data, int size ); - -void UNPACK_V4_32( u32 *dest, u32 *data, int size ); - -void UNPACK_V4_16u( u32 *dest, u32 *data, int size ); -void UNPACK_V4_16s( u32 *dest, u32 *data, int size ); - -void UNPACK_V4_8u( u32 *dest, u32 *data, int size ); -void UNPACK_V4_8s( u32 *dest, u32 *data, int size ); - -void UNPACK_V4_5( u32 *dest, u32 *data, int size ); - -void vifDmaInit(); -void vif0Init(); -void vif1Init(); -extern void vif0Interrupt(); -extern void vif1Interrupt(); - -void vif0Write32(u32 mem, u32 value); -void vif1Write32(u32 mem, u32 value); - -void vif0Reset(); -void vif1Reset(); - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef __VIFDMA_H__ +#define __VIFDMA_H__ + +struct vifCode { + u32 addr; + u32 size; + u32 cmd; + u16 wl; + u16 cl; +}; + +// NOTE, if debugging vif stalls, use sega classics, spyro, gt4, and taito +struct vifStruct { + vifCode tag; + int cmd; + int irq; + int cl; + int wl; + u8 usn; + u8 done; + u8 vifstalled; + u8 stallontag; + u8 irqoffset; // 32bit offset where next vif code is + u32 savedtag; // need this for backwards compat with save states + u32 vifpacketsize; +}; + +extern vifStruct vif0, vif1; +extern int Path3transfer; + +#define vif0ch ((DMACh*)&PS2MEM_HW[0x8000]) +#define vif1ch ((DMACh*)&PS2MEM_HW[0x9000]) + +void UNPACK_S_32( u32 *dest, u32 *data, int size ); + +void UNPACK_S_16u( u32 *dest, u32 *data, int size ); +void UNPACK_S_16s( u32 *dest, u32 *data, int size ); + +void UNPACK_S_8u( u32 *dest, u32 *data, int size ); +void UNPACK_S_8s( u32 *dest, u32 *data, int size ); + +void UNPACK_V2_32( u32 *dest, u32 *data, int size ); + +void UNPACK_V2_16u( u32 *dest, u32 *data, int size ); +void UNPACK_V2_16s( u32 *dest, u32 *data, int size ); + +void UNPACK_V2_8u( u32 *dest, u32 *data, int size ); +void UNPACK_V2_8s( u32 *dest, u32 *data, int size ); + +void UNPACK_V3_32( u32 *dest, u32 *data, int size ); + +void UNPACK_V3_16u( u32 *dest, u32 *data, int size ); +void UNPACK_V3_16s( u32 *dest, u32 *data, int size ); + +void UNPACK_V3_8u( u32 *dest, u32 *data, int size ); +void UNPACK_V3_8s( u32 *dest, u32 *data, int size ); + +void UNPACK_V4_32( u32 *dest, u32 *data, int size ); + +void UNPACK_V4_16u( u32 *dest, u32 *data, int size ); +void UNPACK_V4_16s( u32 *dest, u32 *data, int size ); + +void UNPACK_V4_8u( u32 *dest, u32 *data, int size ); +void UNPACK_V4_8s( u32 *dest, u32 *data, int size ); + +void UNPACK_V4_5( u32 *dest, u32 *data, int size ); + +void vifDmaInit(); +void vif0Init(); +void vif1Init(); +extern void vif0Interrupt(); +extern void vif1Interrupt(); + +void vif0Write32(u32 mem, u32 value); +void vif1Write32(u32 mem, u32 value); + +void vif0Reset(); +void vif1Reset(); + +#endif diff --git a/pcsx2/cheatscpp.h b/pcsx2/cheatscpp.h index 3a8ac28b98..e547b13779 100644 --- a/pcsx2/cheatscpp.h +++ b/pcsx2/cheatscpp.h @@ -1,48 +1,48 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef CHEATSCPP_H_INCLUDED -#define CHEATSCPP_H_INCLUDED - -class Group -{ -public: - string title; - bool enabled; - int parentIndex; - - Group(int nParent,bool nEnabled, string &nTitle); - -}; - -class Patch -{ -public: - string title; - int group; - bool enabled; - int patchIndex; - - Patch(int patch, int grp, bool en, string &ttl); - - Patch operator =(const Patch&p); -}; - -extern vector groups; -extern vector patches; - -#endif//CHEATSCPP_H_INCLUDED +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef CHEATSCPP_H_INCLUDED +#define CHEATSCPP_H_INCLUDED + +class Group +{ +public: + string title; + bool enabled; + int parentIndex; + + Group(int nParent,bool nEnabled, string &nTitle); + +}; + +class Patch +{ +public: + string title; + int group; + bool enabled; + int patchIndex; + + Patch(int patch, int grp, bool en, string &ttl); + + Patch operator =(const Patch&p); +}; + +extern vector groups; +extern vector patches; + +#endif//CHEATSCPP_H_INCLUDED diff --git a/pcsx2/common/PS2Edefs.h b/pcsx2/common/PS2Edefs.h index 1f65fc02b9..49b16e16d5 100644 --- a/pcsx2/common/PS2Edefs.h +++ b/pcsx2/common/PS2Edefs.h @@ -1,885 +1,885 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef __PS2EDEFS_H__ -#define __PS2EDEFS_H__ - -/* - * PS2E Definitions v0.6.2 (beta) - * - * Author: linuzappz@hotmail.com - * shadowpcsx2@yahoo.gr - * florinsasu@hotmail.com - */ - -/* - Notes: - * Since this is still beta things may change. - - * OSflags: - __LINUX__ (linux OS) - _WIN32 (win32 OS) - - * common return values (for ie. GSinit): - 0 - success - -1 - error - - * reserved keys: - F1 to F10 are reserved for the emulator - - * plugins should NOT change the current - working directory. - (on win32, add flag OFN_NOCHANGEDIR for - GetOpenFileName) - -*/ - -#include "PS2Etypes.h" - - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ - defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ - defined(USBdefs) || defined(FWdefs) -#define COMMONdefs -#endif - -// PS2EgetLibType returns (may be OR'd) -#define PS2E_LT_GS 0x01 -#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- -#define PS2E_LT_SPU2 0x04 -#define PS2E_LT_CDVD 0x08 -#define PS2E_LT_DEV9 0x10 -#define PS2E_LT_USB 0x20 -#define PS2E_LT_FW 0x40 -#define PS2E_LT_SIO 0x80 - -// PS2EgetLibVersion2 (high 16 bits) -#define PS2E_GS_VERSION 0x0006 -#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- -#define PS2E_SPU2_VERSION 0x0005 -#define PS2E_CDVD_VERSION 0x0005 -#define PS2E_DEV9_VERSION 0x0003 -#define PS2E_USB_VERSION 0x0003 -#define PS2E_FW_VERSION 0x0002 -#define PS2E_SIO_VERSION 0x0001 -#ifdef COMMONdefs - -u32 CALLBACK PS2EgetLibType(void); -u32 CALLBACK PS2EgetLibVersion2(u32 type); -char* CALLBACK PS2EgetLibName(void); - -#endif - -// key values: -/* key values must be OS dependant: - win32: the VK_XXX will be used (WinUser) - linux: the XK_XXX will be used (XFree86) -*/ - -// event values: -#define KEYPRESS 1 -#define KEYRELEASE 2 - -typedef struct _keyEvent { - u32 key; - u32 evt; -} keyEvent; - -// for 64bit compilers -typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; - -// plugin types -#define SIO_TYPE_PAD 0x00000001 -#define SIO_TYPE_MTAP 0x00000004 -#define SIO_TYPE_RM 0x00000040 -#define SIO_TYPE_MC 0x00000100 - -typedef int (CALLBACK * SIOchangeSlotCB)(int slot); - -typedef struct _cdvdSubQ { - u8 ctrl:4; // control and mode bits - u8 mode:4; // control and mode bits - u8 trackNum; // current track number (1 to 99) - u8 trackIndex; // current index within track (0 to 99) - u8 trackM; // current minute location on the disc (BCD encoded) - u8 trackS; // current sector location on the disc (BCD encoded) - u8 trackF; // current frame location on the disc (BCD encoded) - u8 pad; // unused - u8 discM; // current minute offset from first track (BCD encoded) - u8 discS; // current sector offset from first track (BCD encoded) - u8 discF; // current frame offset from first track (BCD encoded) -} cdvdSubQ; - -typedef struct _cdvdTD { // NOT bcd coded - u32 lsn; - u8 type; -} cdvdTD; - -typedef struct _cdvdTN { - u8 strack; //number of the first track (usually 1) - u8 etrack; //number of the last track -} cdvdTN; - -// CDVDreadTrack mode values: -#define CDVD_MODE_2352 0 // full 2352 bytes -#define CDVD_MODE_2340 1 // skip sync (12) bytes -#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq - -// CDVDgetDiskType returns: -#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc -#define CDVD_TYPE_DVDV 0xfe // DVD Video -#define CDVD_TYPE_CDDA 0xfd // Audio CD -#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD -#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) -#define CDVD_TYPE_PS2CD 0x12 // PS2 CD -#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) -#define CDVD_TYPE_PSCD 0x10 // PS CD -#define CDVD_TYPE_UNKNOWN 0x05 // Unknown -#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided -#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided -#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd -#define CDVD_TYPE_DETCT 0x01 // Detecting -#define CDVD_TYPE_NODISC 0x00 // No Disc - -// CDVDgetTrayStatus returns: -#define CDVD_TRAY_CLOSE 0x00 -#define CDVD_TRAY_OPEN 0x01 - -// cdvdTD.type (track types for cds) -#define CDVD_AUDIO_TRACK 0x01 -#define CDVD_MODE1_TRACK 0x41 -#define CDVD_MODE2_TRACK 0x61 - -#define CDVD_AUDIO_MASK 0x00 -#define CDVD_DATA_MASK 0x40 -// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) - -typedef void (*DEV9callback)(int cycles); -typedef int (*DEV9handler)(void); - -typedef void (*USBcallback)(int cycles); -typedef int (*USBhandler)(void); - -// freeze modes: -#define FREEZE_LOAD 0 -#define FREEZE_SAVE 1 -#define FREEZE_SIZE 2 - -typedef struct _GSdriverInfo { - char name[8]; - void *common; -} GSdriverInfo; - -#ifdef _WINDOWS_ -typedef struct _winInfo { // unsupported values must be set to zero - HWND hWnd; - HMENU hMenu; - HWND hStatusWnd; -} winInfo; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* GS plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef GSdefs - -// basic funcs - -s32 CALLBACK GSinit(); -s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); -void CALLBACK GSclose(); -void CALLBACK GSshutdown(); -void CALLBACK GSvsync(int field); -void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); -void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); -void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); -void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) -void CALLBACK GSgifSoftReset(u32 mask); -void CALLBACK GSreadFIFO(u64 *mem); -void CALLBACK GSreadFIFO2(u64 *mem, int qwc); - -// extended funcs - -// GSkeyEvent gets called when there is a keyEvent from the PAD plugin -void CALLBACK GSkeyEvent(keyEvent *ev); -void CALLBACK GSchangeSaveState(int, const char* filename); -void CALLBACK GSmakeSnapshot(char *path); -void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); -void CALLBACK GSirqCallback(void (*callback)()); -void CALLBACK GSprintf(int timeout, char *fmt, ...); -void CALLBACK GSsetBaseMem(void*); -void CALLBACK GSsetGameCRC(int crc, int gameoptions); - -// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done -void CALLBACK GSsetFrameSkip(int frameskip); - -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK GSsetupRecording(int start, void* pData); - -void CALLBACK GSreset(); -void CALLBACK GSwriteCSR(u32 value); -void CALLBACK GSgetDriverInfo(GSdriverInfo *info); -#ifdef _WIN32 -s32 CALLBACK GSsetWindowInfo(winInfo *info); -#endif -s32 CALLBACK GSfreeze(int mode, freezeData *data); -void CALLBACK GSconfigure(); -void CALLBACK GSabout(); -s32 CALLBACK GStest(); - -#endif - -/* PAD plugin API -=[ OBSOLETE ]=- */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef PADdefs - -// basic funcs - -s32 CALLBACK PADinit(u32 flags); -s32 CALLBACK PADopen(void *pDsp); -void CALLBACK PADclose(); -void CALLBACK PADshutdown(); -// PADkeyEvent is called every vsync (return NULL if no event) -keyEvent* CALLBACK PADkeyEvent(); -u8 CALLBACK PADstartPoll(int pad); -u8 CALLBACK PADpoll(u8 value); -// returns: 1 if supported pad1 -// 2 if supported pad2 -// 3 if both are supported -u32 CALLBACK PADquery(); - -// call to give a hint to the PAD plugin to query for the keyboard state. A -// good plugin will query the OS for keyboard state ONLY in this function. -// This function is necessary when multithreading because otherwise -// the PAD plugin can get into deadlocks with the thread that really owns -// the window (and input). Note that PADupdate can be called from a different -// thread than the other functions, so mutex or other multithreading primitives -// have to be added to maintain data integrity. -void CALLBACK PADupdate(int pad); - -// extended funcs - -void CALLBACK PADgsDriverInfo(GSdriverInfo *info); -void CALLBACK PADconfigure(); -void CALLBACK PADabout(); -s32 CALLBACK PADtest(); - -#endif - -/* SIO plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SIOdefs - -// basic funcs - -s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); -s32 CALLBACK SIOopen(void *pDsp); -void CALLBACK SIOclose(); -void CALLBACK SIOshutdown(); -u8 CALLBACK SIOstartPoll(u8 value); -u8 CALLBACK SIOpoll(u8 value); -// returns: SIO_TYPE_{PAD,MTAP,RM,MC} -u32 CALLBACK SIOquery(); - -// extended funcs - -void CALLBACK SIOconfigure(); -void CALLBACK SIOabout(); -s32 CALLBACK SIOtest(); - -#endif - -/* SPU2 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SPU2defs - -// basic funcs - -s32 CALLBACK SPU2init(); -s32 CALLBACK SPU2open(void *pDsp); -void CALLBACK SPU2close(); -void CALLBACK SPU2shutdown(); -void CALLBACK SPU2write(u32 mem, u16 value); -u16 CALLBACK SPU2read(u32 mem); -void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA4(); -void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); -void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); - -// all addresses passed by dma will be pointers to the array starting at baseaddr -// This function is necessary to successfully save and reload the spu2 state -void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); - -void CALLBACK SPU2interruptDMA7(); -u32 CALLBACK SPU2ReadMemAddr(int core); -void CALLBACK SPU2WriteMemAddr(int core,u32 value); -void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); - -// extended funcs -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK SPU2setupRecording(int start, void* pData); - -void CALLBACK SPU2setClockPtr(u32* ptr); -void CALLBACK SPU2setTimeStretcher(short int enable); - -void CALLBACK SPU2async(u32 cycles); -s32 CALLBACK SPU2freeze(int mode, freezeData *data); -void CALLBACK SPU2configure(); -void CALLBACK SPU2about(); -s32 CALLBACK SPU2test(); - -#endif - -/* CDVD plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef CDVDdefs - -// basic funcs - -s32 CALLBACK CDVDinit(); -s32 CALLBACK CDVDopen(const char* pTitleFilename); -void CALLBACK CDVDclose(); -void CALLBACK CDVDshutdown(); -s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); - -// return can be NULL (for async modes) -u8* CALLBACK CDVDgetBuffer(); - -s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) -s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information -s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type -s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc -s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx -s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx -s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray -s32 CALLBACK CDVDctrlTrayClose(); //close disc tray - -// extended funcs - -void CALLBACK CDVDconfigure(); -void CALLBACK CDVDabout(); -s32 CALLBACK CDVDtest(); -void CALLBACK CDVDnewDiskCB(void (*callback)()); - -#endif - -/* DEV9 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef DEV9defs - -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK DEV9init(); -s32 CALLBACK DEV9open(void *pDsp); -void CALLBACK DEV9close(); -void CALLBACK DEV9shutdown(); -u8 CALLBACK DEV9read8(u32 addr); -u16 CALLBACK DEV9read16(u32 addr); -u32 CALLBACK DEV9read32(u32 addr); -void CALLBACK DEV9write8(u32 addr, u8 value); -void CALLBACK DEV9write16(u32 addr, u16 value); -void CALLBACK DEV9write32(u32 addr, u32 value); -void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); -void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK DEV9irqCallback(DEV9callback callback); -DEV9handler CALLBACK DEV9irqHandler(void); - -// extended funcs - -s32 CALLBACK DEV9freeze(int mode, freezeData *data); -void CALLBACK DEV9configure(); -void CALLBACK DEV9about(); -s32 CALLBACK DEV9test(); - -#endif - -/* USB plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef USBdefs - -// basic funcs - -s32 CALLBACK USBinit(); -s32 CALLBACK USBopen(void *pDsp); -void CALLBACK USBclose(); -void CALLBACK USBshutdown(); -u8 CALLBACK USBread8(u32 addr); -u16 CALLBACK USBread16(u32 addr); -u32 CALLBACK USBread32(u32 addr); -void CALLBACK USBwrite8(u32 addr, u8 value); -void CALLBACK USBwrite16(u32 addr, u16 value); -void CALLBACK USBwrite32(u32 addr, u32 value); -void CALLBACK USBasync(u32 cycles); - -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK USBirqCallback(USBcallback callback); -USBhandler CALLBACK USBirqHandler(void); -void CALLBACK USBsetRAM(void *mem); - -// extended funcs - -s32 CALLBACK USBfreeze(int mode, freezeData *data); -void CALLBACK USBconfigure(); -void CALLBACK USBabout(); -s32 CALLBACK USBtest(); - -#endif - -/* FW plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef FWdefs -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK FWinit(); -s32 CALLBACK FWopen(void *pDsp); -void CALLBACK FWclose(); -void CALLBACK FWshutdown(); -u32 CALLBACK FWread32(u32 addr); -void CALLBACK FWwrite32(u32 addr, u32 value); -void CALLBACK FWirqCallback(void (*callback)()); - -// extended funcs - -s32 CALLBACK FWfreeze(int mode, freezeData *data); -void CALLBACK FWconfigure(); -void CALLBACK FWabout(); -s32 CALLBACK FWtest(); -#endif - -// might be useful for emulators -#ifdef PLUGINtypedefs - -typedef u32 (CALLBACK* _PS2EgetLibType)(void); -typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); -typedef char*(CALLBACK* _PS2EgetLibName)(void); - -// GS -// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _GSinit)(); -typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); -typedef void (CALLBACK* _GSclose)(); -typedef void (CALLBACK* _GSshutdown)(); -typedef void (CALLBACK* _GSvsync)(int field); -typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); -typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) -typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); -typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); -typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); - -typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); -typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); -typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); -typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); -typedef void (CALLBACK* _GSsetBaseMem)(void*); -typedef void (CALLBACK* _GSsetGameCRC)(int, int); -typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); -typedef int (CALLBACK* _GSsetupRecording)(int, void*); -typedef void (CALLBACK* _GSreset)(); -typedef void (CALLBACK* _GSwriteCSR)(u32 value); -typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); -#ifdef _WINDOWS_ -typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); -#endif -typedef void (CALLBACK* _GSmakeSnapshot)(const char *path); -typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); -typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _GSconfigure)(); -typedef s32 (CALLBACK* _GStest)(); -typedef void (CALLBACK* _GSabout)(); - -// PAD -typedef s32 (CALLBACK* _PADinit)(u32 flags); -typedef s32 (CALLBACK* _PADopen)(void *pDsp); -typedef void (CALLBACK* _PADclose)(); -typedef void (CALLBACK* _PADshutdown)(); -typedef keyEvent* (CALLBACK* _PADkeyEvent)(); -typedef u8 (CALLBACK* _PADstartPoll)(int pad); -typedef u8 (CALLBACK* _PADpoll)(u8 value); -typedef u32 (CALLBACK* _PADquery)(); -typedef void (CALLBACK* _PADupdate)(int pad); - -typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); -typedef void (CALLBACK* _PADconfigure)(); -typedef s32 (CALLBACK* _PADtest)(); -typedef void (CALLBACK* _PADabout)(); - -// SIO -typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); -typedef s32 (CALLBACK* _SIOopen)(void *pDsp); -typedef void (CALLBACK* _SIOclose)(); -typedef void (CALLBACK* _SIOshutdown)(); -typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); -typedef u8 (CALLBACK* _SIOpoll)(u8 value); -typedef u32 (CALLBACK* _SIOquery)(); - -typedef void (CALLBACK* _SIOconfigure)(); -typedef s32 (CALLBACK* _SIOtest)(); -typedef void (CALLBACK* _SIOabout)(); - -// SPU2 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _SPU2init)(); -typedef s32 (CALLBACK* _SPU2open)(void *pDsp); -typedef void (CALLBACK* _SPU2close)(); -typedef void (CALLBACK* _SPU2shutdown)(); -typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); -typedef u16 (CALLBACK* _SPU2read)(u32 mem); -typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA4)(); -typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); -typedef void (CALLBACK* _SPU2interruptDMA7)(); -typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); -typedef int (CALLBACK* _SPU2setupRecording)(int, void*); - -typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); -typedef void (CALLBACK* _SPU2setTimeStretcher)(short int enable); - -typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); -typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); -typedef void (CALLBACK* _SPU2async)(u32 cycles); -typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _SPU2configure)(); -typedef s32 (CALLBACK* _SPU2test)(); -typedef void (CALLBACK* _SPU2about)(); - - -// CDVD -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _CDVDinit)(); -typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); -typedef void (CALLBACK* _CDVDclose)(); -typedef void (CALLBACK* _CDVDshutdown)(); -typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); -typedef u8* (CALLBACK* _CDVDgetBuffer)(); -typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); -typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); -typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); -typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); -typedef s32 (CALLBACK* _CDVDgetDiskType)(); -typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); -typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); -typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); - -typedef void (CALLBACK* _CDVDconfigure)(); -typedef s32 (CALLBACK* _CDVDtest)(); -typedef void (CALLBACK* _CDVDabout)(); -typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); - -// DEV9 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _DEV9init)(); -typedef s32 (CALLBACK* _DEV9open)(void *pDsp); -typedef void (CALLBACK* _DEV9close)(); -typedef void (CALLBACK* _DEV9shutdown)(); -typedef u8 (CALLBACK* _DEV9read8)(u32 mem); -typedef u16 (CALLBACK* _DEV9read16)(u32 mem); -typedef u32 (CALLBACK* _DEV9read32)(u32 mem); -typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); -typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); -typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); -typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); -typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); - -typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _DEV9configure)(); -typedef s32 (CALLBACK* _DEV9test)(); -typedef void (CALLBACK* _DEV9about)(); - -// USB -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _USBinit)(); -typedef s32 (CALLBACK* _USBopen)(void *pDsp); -typedef void (CALLBACK* _USBclose)(); -typedef void (CALLBACK* _USBshutdown)(); -typedef u8 (CALLBACK* _USBread8)(u32 mem); -typedef u16 (CALLBACK* _USBread16)(u32 mem); -typedef u32 (CALLBACK* _USBread32)(u32 mem); -typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); -typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); -typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _USBasync)(u32 cycles); - - -typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); -typedef USBhandler (CALLBACK* _USBirqHandler)(void); -typedef void (CALLBACK* _USBsetRAM)(void *mem); - -typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _USBconfigure)(); -typedef s32 (CALLBACK* _USBtest)(); -typedef void (CALLBACK* _USBabout)(); - -//FW -typedef s32 (CALLBACK* _FWinit)(); -typedef s32 (CALLBACK* _FWopen)(void *pDsp); -typedef void (CALLBACK* _FWclose)(); -typedef void (CALLBACK* _FWshutdown)(); -typedef u32 (CALLBACK* _FWread32)(u32 mem); -typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); - -typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _FWconfigure)(); -typedef s32 (CALLBACK* _FWtest)(); -typedef void (CALLBACK* _FWabout)(); - -#endif - -#ifdef PLUGINfuncs - -// GS -extern _GSinit GSinit; -extern _GSopen GSopen; -extern _GSclose GSclose; -extern _GSshutdown GSshutdown; -extern _GSvsync GSvsync; -extern _GSgifTransfer1 GSgifTransfer1; -extern _GSgifTransfer2 GSgifTransfer2; -extern _GSgifTransfer3 GSgifTransfer3; -extern _GSgetLastTag GSgetLastTag; -extern _GSgifSoftReset GSgifSoftReset; -extern _GSreadFIFO GSreadFIFO; -extern _GSreadFIFO2 GSreadFIFO2; - -extern _GSkeyEvent GSkeyEvent; -extern _GSchangeSaveState GSchangeSaveState; -extern _GSmakeSnapshot GSmakeSnapshot; -extern _GSmakeSnapshot2 GSmakeSnapshot2; -extern _GSirqCallback GSirqCallback; -extern _GSprintf GSprintf; -extern _GSsetBaseMem GSsetBaseMem; -extern _GSsetGameCRC GSsetGameCRC; -extern _GSsetFrameSkip GSsetFrameSkip; -extern _GSsetupRecording GSsetupRecording; -extern _GSreset GSreset; -extern _GSwriteCSR GSwriteCSR; -extern _GSgetDriverInfo GSgetDriverInfo; -#ifdef _WINDOWS_ -extern _GSsetWindowInfo GSsetWindowInfo; -#endif -extern _GSfreeze GSfreeze; -extern _GSconfigure GSconfigure; -extern _GStest GStest; -extern _GSabout GSabout; - -// PAD1 -extern _PADinit PAD1init; -extern _PADopen PAD1open; -extern _PADclose PAD1close; -extern _PADshutdown PAD1shutdown; -extern _PADkeyEvent PAD1keyEvent; -extern _PADstartPoll PAD1startPoll; -extern _PADpoll PAD1poll; -extern _PADquery PAD1query; -extern _PADupdate PAD1update; - -extern _PADgsDriverInfo PAD1gsDriverInfo; -extern _PADconfigure PAD1configure; -extern _PADtest PAD1test; -extern _PADabout PAD1about; - -// PAD2 -extern _PADinit PAD2init; -extern _PADopen PAD2open; -extern _PADclose PAD2close; -extern _PADshutdown PAD2shutdown; -extern _PADkeyEvent PAD2keyEvent; -extern _PADstartPoll PAD2startPoll; -extern _PADpoll PAD2poll; -extern _PADquery PAD2query; -extern _PADupdate PAD2update; - -extern _PADgsDriverInfo PAD2gsDriverInfo; -extern _PADconfigure PAD2configure; -extern _PADtest PAD2test; -extern _PADabout PAD2about; - -// SIO[2] -extern _SIOinit SIOinit[2][9]; -extern _SIOopen SIOopen[2][9]; -extern _SIOclose SIOclose[2][9]; -extern _SIOshutdown SIOshutdown[2][9]; -extern _SIOstartPoll SIOstartPoll[2][9]; -extern _SIOpoll SIOpoll[2][9]; -extern _SIOquery SIOquery[2][9]; - -extern _SIOconfigure SIOconfigure[2][9]; -extern _SIOtest SIOtest[2][9]; -extern _SIOabout SIOabout[2][9]; - -// SPU2 -extern _SPU2init SPU2init; -extern _SPU2open SPU2open; -extern _SPU2close SPU2close; -extern _SPU2shutdown SPU2shutdown; -extern _SPU2write SPU2write; -extern _SPU2read SPU2read; -extern _SPU2readDMA4Mem SPU2readDMA4Mem; -extern _SPU2writeDMA4Mem SPU2writeDMA4Mem; -extern _SPU2interruptDMA4 SPU2interruptDMA4; -extern _SPU2readDMA7Mem SPU2readDMA7Mem; -extern _SPU2writeDMA7Mem SPU2writeDMA7Mem; -extern _SPU2setDMABaseAddr SPU2setDMABaseAddr; -extern _SPU2interruptDMA7 SPU2interruptDMA7; -extern _SPU2ReadMemAddr SPU2ReadMemAddr; -extern _SPU2setupRecording SPU2setupRecording; -extern _SPU2WriteMemAddr SPU2WriteMemAddr; -extern _SPU2irqCallback SPU2irqCallback; - -extern _SPU2setClockPtr SPU2setClockPtr; -extern _SPU2setTimeStretcher SPU2setTimeStretcher; - -extern _SPU2async SPU2async; -extern _SPU2freeze SPU2freeze; -extern _SPU2configure SPU2configure; -extern _SPU2test SPU2test; -extern _SPU2about SPU2about; - -// CDVD -extern _CDVDinit CDVDinit; -extern _CDVDopen CDVDopen; -extern _CDVDclose CDVDclose; -extern _CDVDshutdown CDVDshutdown; -extern _CDVDreadTrack CDVDreadTrack; -extern _CDVDgetBuffer CDVDgetBuffer; -extern _CDVDreadSubQ CDVDreadSubQ; -extern _CDVDgetTN CDVDgetTN; -extern _CDVDgetTD CDVDgetTD; -extern _CDVDgetTOC CDVDgetTOC; -extern _CDVDgetDiskType CDVDgetDiskType; -extern _CDVDgetTrayStatus CDVDgetTrayStatus; -extern _CDVDctrlTrayOpen CDVDctrlTrayOpen; -extern _CDVDctrlTrayClose CDVDctrlTrayClose; - -extern _CDVDconfigure CDVDconfigure; -extern _CDVDtest CDVDtest; -extern _CDVDabout CDVDabout; -extern _CDVDnewDiskCB CDVDnewDiskCB; - -// DEV9 -extern _DEV9init DEV9init; -extern _DEV9open DEV9open; -extern _DEV9close DEV9close; -extern _DEV9shutdown DEV9shutdown; -extern _DEV9read8 DEV9read8; -extern _DEV9read16 DEV9read16; -extern _DEV9read32 DEV9read32; -extern _DEV9write8 DEV9write8; -extern _DEV9write16 DEV9write16; -extern _DEV9write32 DEV9write32; -extern _DEV9readDMA8Mem DEV9readDMA8Mem; -extern _DEV9writeDMA8Mem DEV9writeDMA8Mem; -extern _DEV9irqCallback DEV9irqCallback; -extern _DEV9irqHandler DEV9irqHandler; - -extern _DEV9configure DEV9configure; -extern _DEV9freeze DEV9freeze; -extern _DEV9test DEV9test; -extern _DEV9about DEV9about; - -// USB -extern _USBinit USBinit; -extern _USBopen USBopen; -extern _USBclose USBclose; -extern _USBshutdown USBshutdown; -extern _USBread8 USBread8; -extern _USBread16 USBread16; -extern _USBread32 USBread32; -extern _USBwrite8 USBwrite8; -extern _USBwrite16 USBwrite16; -extern _USBwrite32 USBwrite32; -extern _USBasync USBasync; - -extern _USBirqCallback USBirqCallback; -extern _USBirqHandler USBirqHandler; -extern _USBsetRAM USBsetRAM; - -extern _USBconfigure USBconfigure; -extern _USBfreeze USBfreeze; -extern _USBtest USBtest; -extern _USBabout USBabout; - -// FW -extern _FWinit FWinit; -extern _FWopen FWopen; -extern _FWclose FWclose; -extern _FWshutdown FWshutdown; -extern _FWread32 FWread32; -extern _FWwrite32 FWwrite32; -extern _FWirqCallback FWirqCallback; - -extern _FWconfigure FWconfigure; -extern _FWfreeze FWfreeze; -extern _FWtest FWtest; -extern _FWabout FWabout; -#endif - -#ifdef __cplusplus -} // End extern "C" -#endif - -#endif /* __PS2EDEFS_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct _keyEvent { + u32 key; + u32 evt; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct _cdvdSubQ { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct _cdvdTD { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct _cdvdTN { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct _GSdriverInfo { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WINDOWS_ +typedef struct _winInfo { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2setClockPtr(u32* ptr); +void CALLBACK SPU2setTimeStretcher(short int enable); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +void CALLBACK USBasync(u32 cycles); + +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WINDOWS_ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(const char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); + +typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); +typedef void (CALLBACK* _SPU2setTimeStretcher)(short int enable); + +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBasync)(u32 cycles); + + +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +extern _GSinit GSinit; +extern _GSopen GSopen; +extern _GSclose GSclose; +extern _GSshutdown GSshutdown; +extern _GSvsync GSvsync; +extern _GSgifTransfer1 GSgifTransfer1; +extern _GSgifTransfer2 GSgifTransfer2; +extern _GSgifTransfer3 GSgifTransfer3; +extern _GSgetLastTag GSgetLastTag; +extern _GSgifSoftReset GSgifSoftReset; +extern _GSreadFIFO GSreadFIFO; +extern _GSreadFIFO2 GSreadFIFO2; + +extern _GSkeyEvent GSkeyEvent; +extern _GSchangeSaveState GSchangeSaveState; +extern _GSmakeSnapshot GSmakeSnapshot; +extern _GSmakeSnapshot2 GSmakeSnapshot2; +extern _GSirqCallback GSirqCallback; +extern _GSprintf GSprintf; +extern _GSsetBaseMem GSsetBaseMem; +extern _GSsetGameCRC GSsetGameCRC; +extern _GSsetFrameSkip GSsetFrameSkip; +extern _GSsetupRecording GSsetupRecording; +extern _GSreset GSreset; +extern _GSwriteCSR GSwriteCSR; +extern _GSgetDriverInfo GSgetDriverInfo; +#ifdef _WINDOWS_ +extern _GSsetWindowInfo GSsetWindowInfo; +#endif +extern _GSfreeze GSfreeze; +extern _GSconfigure GSconfigure; +extern _GStest GStest; +extern _GSabout GSabout; + +// PAD1 +extern _PADinit PAD1init; +extern _PADopen PAD1open; +extern _PADclose PAD1close; +extern _PADshutdown PAD1shutdown; +extern _PADkeyEvent PAD1keyEvent; +extern _PADstartPoll PAD1startPoll; +extern _PADpoll PAD1poll; +extern _PADquery PAD1query; +extern _PADupdate PAD1update; + +extern _PADgsDriverInfo PAD1gsDriverInfo; +extern _PADconfigure PAD1configure; +extern _PADtest PAD1test; +extern _PADabout PAD1about; + +// PAD2 +extern _PADinit PAD2init; +extern _PADopen PAD2open; +extern _PADclose PAD2close; +extern _PADshutdown PAD2shutdown; +extern _PADkeyEvent PAD2keyEvent; +extern _PADstartPoll PAD2startPoll; +extern _PADpoll PAD2poll; +extern _PADquery PAD2query; +extern _PADupdate PAD2update; + +extern _PADgsDriverInfo PAD2gsDriverInfo; +extern _PADconfigure PAD2configure; +extern _PADtest PAD2test; +extern _PADabout PAD2about; + +// SIO[2] +extern _SIOinit SIOinit[2][9]; +extern _SIOopen SIOopen[2][9]; +extern _SIOclose SIOclose[2][9]; +extern _SIOshutdown SIOshutdown[2][9]; +extern _SIOstartPoll SIOstartPoll[2][9]; +extern _SIOpoll SIOpoll[2][9]; +extern _SIOquery SIOquery[2][9]; + +extern _SIOconfigure SIOconfigure[2][9]; +extern _SIOtest SIOtest[2][9]; +extern _SIOabout SIOabout[2][9]; + +// SPU2 +extern _SPU2init SPU2init; +extern _SPU2open SPU2open; +extern _SPU2close SPU2close; +extern _SPU2shutdown SPU2shutdown; +extern _SPU2write SPU2write; +extern _SPU2read SPU2read; +extern _SPU2readDMA4Mem SPU2readDMA4Mem; +extern _SPU2writeDMA4Mem SPU2writeDMA4Mem; +extern _SPU2interruptDMA4 SPU2interruptDMA4; +extern _SPU2readDMA7Mem SPU2readDMA7Mem; +extern _SPU2writeDMA7Mem SPU2writeDMA7Mem; +extern _SPU2setDMABaseAddr SPU2setDMABaseAddr; +extern _SPU2interruptDMA7 SPU2interruptDMA7; +extern _SPU2ReadMemAddr SPU2ReadMemAddr; +extern _SPU2setupRecording SPU2setupRecording; +extern _SPU2WriteMemAddr SPU2WriteMemAddr; +extern _SPU2irqCallback SPU2irqCallback; + +extern _SPU2setClockPtr SPU2setClockPtr; +extern _SPU2setTimeStretcher SPU2setTimeStretcher; + +extern _SPU2async SPU2async; +extern _SPU2freeze SPU2freeze; +extern _SPU2configure SPU2configure; +extern _SPU2test SPU2test; +extern _SPU2about SPU2about; + +// CDVD +extern _CDVDinit CDVDinit; +extern _CDVDopen CDVDopen; +extern _CDVDclose CDVDclose; +extern _CDVDshutdown CDVDshutdown; +extern _CDVDreadTrack CDVDreadTrack; +extern _CDVDgetBuffer CDVDgetBuffer; +extern _CDVDreadSubQ CDVDreadSubQ; +extern _CDVDgetTN CDVDgetTN; +extern _CDVDgetTD CDVDgetTD; +extern _CDVDgetTOC CDVDgetTOC; +extern _CDVDgetDiskType CDVDgetDiskType; +extern _CDVDgetTrayStatus CDVDgetTrayStatus; +extern _CDVDctrlTrayOpen CDVDctrlTrayOpen; +extern _CDVDctrlTrayClose CDVDctrlTrayClose; + +extern _CDVDconfigure CDVDconfigure; +extern _CDVDtest CDVDtest; +extern _CDVDabout CDVDabout; +extern _CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +extern _DEV9init DEV9init; +extern _DEV9open DEV9open; +extern _DEV9close DEV9close; +extern _DEV9shutdown DEV9shutdown; +extern _DEV9read8 DEV9read8; +extern _DEV9read16 DEV9read16; +extern _DEV9read32 DEV9read32; +extern _DEV9write8 DEV9write8; +extern _DEV9write16 DEV9write16; +extern _DEV9write32 DEV9write32; +extern _DEV9readDMA8Mem DEV9readDMA8Mem; +extern _DEV9writeDMA8Mem DEV9writeDMA8Mem; +extern _DEV9irqCallback DEV9irqCallback; +extern _DEV9irqHandler DEV9irqHandler; + +extern _DEV9configure DEV9configure; +extern _DEV9freeze DEV9freeze; +extern _DEV9test DEV9test; +extern _DEV9about DEV9about; + +// USB +extern _USBinit USBinit; +extern _USBopen USBopen; +extern _USBclose USBclose; +extern _USBshutdown USBshutdown; +extern _USBread8 USBread8; +extern _USBread16 USBread16; +extern _USBread32 USBread32; +extern _USBwrite8 USBwrite8; +extern _USBwrite16 USBwrite16; +extern _USBwrite32 USBwrite32; +extern _USBasync USBasync; + +extern _USBirqCallback USBirqCallback; +extern _USBirqHandler USBirqHandler; +extern _USBsetRAM USBsetRAM; + +extern _USBconfigure USBconfigure; +extern _USBfreeze USBfreeze; +extern _USBtest USBtest; +extern _USBabout USBabout; + +// FW +extern _FWinit FWinit; +extern _FWopen FWopen; +extern _FWclose FWclose; +extern _FWshutdown FWshutdown; +extern _FWread32 FWread32; +extern _FWwrite32 FWwrite32; +extern _FWirqCallback FWirqCallback; + +extern _FWconfigure FWconfigure; +extern _FWfreeze FWfreeze; +extern _FWtest FWtest; +extern _FWabout FWabout; +#endif + +#ifdef __cplusplus +} // End extern "C" +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/pcsx2/common/PS2Etypes.h b/pcsx2/common/PS2Etypes.h index 59be1c3de4..4c62b47f0f 100644 --- a/pcsx2/common/PS2Etypes.h +++ b/pcsx2/common/PS2Etypes.h @@ -1,219 +1,219 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef __PS2ETYPES_H__ -#define __PS2ETYPES_H__ - -#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case -#define __LINUX__ -#endif - -#ifdef __CYGWIN__ -#define __LINUX__ -#endif - -#ifndef ARRAYSIZE -#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) -#endif - -#ifdef __LINUX__ -#define CALLBACK -#else -#define CALLBACK __stdcall -#endif - - -// jASSUME - give hints to the optimizer -// This is primarily useful for the default case switch optimizer, which enables VC to -// generate more compact switches. - -#ifdef NDEBUG -# define jBREAKPOINT() ((void) 0) -# ifdef _MSC_VER -# define jASSUME(exp) (__assume(exp)) -# else -# define jASSUME(exp) ((void) sizeof(exp)) -# endif -#else -# if defined(_MSC_VER) -# define jBREAKPOINT() do { __asm int 3 } while(0) -# else -# define jBREAKPOINT() ((void) *(volatile char *) 0) -# endif -# define jASSUME(exp) if(exp) ; else jBREAKPOINT() -#endif - -// disable the default case in a switch -#define jNO_DEFAULT \ -{ \ - break; \ - \ -default: \ - jASSUME(0); \ - break; \ -} - - -// Basic types -#if defined(_MSC_VER) - -typedef __int8 s8; -typedef __int16 s16; -typedef __int32 s32; -typedef __int64 s64; - -typedef unsigned __int8 u8; -typedef unsigned __int16 u16; -typedef unsigned __int32 u32; -typedef unsigned __int64 u64; - -typedef unsigned int uint; - -#define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x -#define PCSX2_ALIGNED16(x) __declspec(align(16)) x -#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x - -#define __naked __declspec(naked) - -#else // _MSC_VER - -#ifdef __LINUX__ - -#ifdef HAVE_STDINT_H -#include "stdint.h" - -typedef int8_t s8; -typedef int16_t s16; -typedef int32_t s32; -typedef int64_t s64; - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -typedef uintptr_t uptr; -typedef intptr_t sptr; - -#else // HAVE_STDINT_H - -typedef char s8; -typedef short s16; -typedef int s32; -typedef long long s64; - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long long u64; - -#endif // HAVE_STDINT_H - -typedef unsigned int uint; - -#define LONG long -typedef union _LARGE_INTEGER -{ - long long QuadPart; -} LARGE_INTEGER; - -#define __fastcall __attribute__((fastcall)) -#define __unused __attribute__((unused)) -#define _inline __inline__ __attribute__((unused)) -#define __forceinline __attribute__((always_inline,unused)) -#define __naked // GCC lacks the naked specifier - -#endif // __LINUX__ - -#define PCSX2_ALIGNED(alig,x) x __attribute((aligned(alig))) -#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) - -#define PCSX2_ALIGNED16_DECL(x) x - -#endif // _MSC_VER - -#if !defined(__LINUX__) || !defined(HAVE_STDINT_H) -#if defined(__x86_64__) -typedef u64 uptr; -typedef s64 sptr; -#else -typedef u32 uptr; -typedef s32 sptr; -#endif -#endif - -// A rough-and-ready cross platform 128-bit datatype, Non-SSE style. -#ifdef __cplusplus -struct u128 -{ - u64 lo; - u64 hi; - - // Implicit conversion from u64 - u128( u64 src ) : - lo( src ) - , hi( 0 ) {} - - // Implicit conversion from u32 - u128( u32 src ) : - lo( src ) - , hi( 0 ) {} -}; - -struct s128 -{ - s64 lo; - s64 hi; - - // Implicit conversion from u64 - s128( s64 src ) : - lo( src ) - , hi( 0 ) {} - - // Implicit conversion from u32 - s128( s32 src ) : - lo( src ) - , hi( 0 ) {} -}; - -#else - -typedef union _u128_t -{ - u64 lo; - u64 hi; -} u128; - -typedef union _s128_t -{ - s64 lo; - s64 hi; -} s128; - -#endif - -typedef struct { - int size; - s8 *data; -} freezeData; - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#endif /* __PS2ETYPES_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +#ifdef __CYGWIN__ +#define __LINUX__ +#endif + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#ifdef __LINUX__ +#define CALLBACK +#else +#define CALLBACK __stdcall +#endif + + +// jASSUME - give hints to the optimizer +// This is primarily useful for the default case switch optimizer, which enables VC to +// generate more compact switches. + +#ifdef NDEBUG +# define jBREAKPOINT() ((void) 0) +# ifdef _MSC_VER +# define jASSUME(exp) (__assume(exp)) +# else +# define jASSUME(exp) ((void) sizeof(exp)) +# endif +#else +# if defined(_MSC_VER) +# define jBREAKPOINT() do { __asm int 3 } while(0) +# else +# define jBREAKPOINT() ((void) *(volatile char *) 0) +# endif +# define jASSUME(exp) if(exp) ; else jBREAKPOINT() +#endif + +// disable the default case in a switch +#define jNO_DEFAULT \ +{ \ + break; \ + \ +default: \ + jASSUME(0); \ + break; \ +} + + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +typedef unsigned int uint; + +#define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x + +#define __naked __declspec(naked) + +#else // _MSC_VER + +#ifdef __LINUX__ + +#ifdef HAVE_STDINT_H +#include "stdint.h" + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef uintptr_t uptr; +typedef intptr_t sptr; + +#else // HAVE_STDINT_H + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#endif // HAVE_STDINT_H + +typedef unsigned int uint; + +#define LONG long +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; + +#define __fastcall __attribute__((fastcall)) +#define __unused __attribute__((unused)) +#define _inline __inline__ __attribute__((unused)) +#define __forceinline __attribute__((always_inline,unused)) +#define __naked // GCC lacks the naked specifier + +#endif // __LINUX__ + +#define PCSX2_ALIGNED(alig,x) x __attribute((aligned(alig))) +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) + +#define PCSX2_ALIGNED16_DECL(x) x + +#endif // _MSC_VER + +#if !defined(__LINUX__) || !defined(HAVE_STDINT_H) +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif +#endif + +// A rough-and-ready cross platform 128-bit datatype, Non-SSE style. +#ifdef __cplusplus +struct u128 +{ + u64 lo; + u64 hi; + + // Implicit conversion from u64 + u128( u64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + u128( u32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +struct s128 +{ + s64 lo; + s64 hi; + + // Implicit conversion from u64 + s128( s64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + s128( s32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +#else + +typedef union _u128_t +{ + u64 lo; + u64 hi; +} u128; + +typedef union _s128_t +{ + s64 lo; + s64 hi; +} s128; + +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/pcsx2/tinyxml/tinystr.cpp b/pcsx2/tinyxml/tinystr.cpp index 50a13f3a90..12850e99d8 100644 --- a/pcsx2/tinyxml/tinystr.cpp +++ b/pcsx2/tinyxml/tinystr.cpp @@ -1,116 +1,116 @@ -/* -www.sourceforge.net/projects/tinyxml -Original file by Yves Berquin. - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -/* - * THIS FILE WAS ALTERED BY Tyge Løvset, 7. April 2005. - */ - - -#ifndef TIXML_USE_STL - -#include "tinystr.h" - -// Error value for find primitive -const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1); - - -// Null rep. -TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, '\0' }; - - -void TiXmlString::reserve (size_type cap) -{ - if (cap > capacity()) - { - TiXmlString tmp; - tmp.init(length(), cap); - memcpy(tmp.start(), data(), length()); - swap(tmp); - } -} - - -TiXmlString& TiXmlString::assign(const char* str, size_type len) -{ - size_type cap = capacity(); - if (len > cap || cap > 3*(len + 8)) - { - TiXmlString tmp; - tmp.init(len); - memcpy(tmp.start(), str, len); - swap(tmp); - } - else - { - memmove(start(), str, len); - set_size(len); - } - return *this; -} - - -TiXmlString& TiXmlString::append(const char* str, size_type len) -{ - size_type newsize = length() + len; - if (newsize > capacity()) - { - reserve (newsize + capacity()); - } - memmove(finish(), str, len); - set_size(newsize); - return *this; -} - - -TiXmlString operator + (const TiXmlString & a, const TiXmlString & b) -{ - TiXmlString tmp; - tmp.reserve(a.length() + b.length()); - tmp += a; - tmp += b; - return tmp; -} - -TiXmlString operator + (const TiXmlString & a, const char* b) -{ - TiXmlString tmp; - TiXmlString::size_type b_len = static_cast( strlen(b) ); - tmp.reserve(a.length() + b_len); - tmp += a; - tmp.append(b, b_len); - return tmp; -} - -TiXmlString operator + (const char* a, const TiXmlString & b) -{ - TiXmlString tmp; - TiXmlString::size_type a_len = static_cast( strlen(a) ); - tmp.reserve(a_len + b.length()); - tmp.append(a, a_len); - tmp += b; - return tmp; -} - - -#endif // TIXML_USE_STL +/* +www.sourceforge.net/projects/tinyxml +Original file by Yves Berquin. + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +/* + * THIS FILE WAS ALTERED BY Tyge Løvset, 7. April 2005. + */ + + +#ifndef TIXML_USE_STL + +#include "tinystr.h" + +// Error value for find primitive +const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1); + + +// Null rep. +TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, '\0' }; + + +void TiXmlString::reserve (size_type cap) +{ + if (cap > capacity()) + { + TiXmlString tmp; + tmp.init(length(), cap); + memcpy(tmp.start(), data(), length()); + swap(tmp); + } +} + + +TiXmlString& TiXmlString::assign(const char* str, size_type len) +{ + size_type cap = capacity(); + if (len > cap || cap > 3*(len + 8)) + { + TiXmlString tmp; + tmp.init(len); + memcpy(tmp.start(), str, len); + swap(tmp); + } + else + { + memmove(start(), str, len); + set_size(len); + } + return *this; +} + + +TiXmlString& TiXmlString::append(const char* str, size_type len) +{ + size_type newsize = length() + len; + if (newsize > capacity()) + { + reserve (newsize + capacity()); + } + memmove(finish(), str, len); + set_size(newsize); + return *this; +} + + +TiXmlString operator + (const TiXmlString & a, const TiXmlString & b) +{ + TiXmlString tmp; + tmp.reserve(a.length() + b.length()); + tmp += a; + tmp += b; + return tmp; +} + +TiXmlString operator + (const TiXmlString & a, const char* b) +{ + TiXmlString tmp; + TiXmlString::size_type b_len = static_cast( strlen(b) ); + tmp.reserve(a.length() + b_len); + tmp += a; + tmp.append(b, b_len); + return tmp; +} + +TiXmlString operator + (const char* a, const TiXmlString & b) +{ + TiXmlString tmp; + TiXmlString::size_type a_len = static_cast( strlen(a) ); + tmp.reserve(a_len + b.length()); + tmp.append(a, a_len); + tmp += b; + return tmp; +} + + +#endif // TIXML_USE_STL diff --git a/pcsx2/tinyxml/tinystr.h b/pcsx2/tinyxml/tinystr.h index 74b6b7e815..3c2aa9d54d 100644 --- a/pcsx2/tinyxml/tinystr.h +++ b/pcsx2/tinyxml/tinystr.h @@ -1,319 +1,319 @@ -/* -www.sourceforge.net/projects/tinyxml -Original file by Yves Berquin. - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -/* - * THIS FILE WAS ALTERED BY Tyge Lovset, 7. April 2005. - * - * - completely rewritten. compact, clean, and fast implementation. - * - sizeof(TiXmlString) = pointer size (4 bytes on 32-bit systems) - * - fixed reserve() to work as per specification. - * - fixed buggy compares operator==(), operator<(), and operator>() - * - fixed operator+=() to take a const ref argument, following spec. - * - added "copy" constructor with length, and most compare operators. - * - added swap(), clear(), size(), capacity(), operator+(). - */ - -#ifndef TIXML_USE_STL - -#ifndef TIXML_STRING_INCLUDED -#define TIXML_STRING_INCLUDED - -#include -#include - -/* The support for explicit isn't that universal, and it isn't really - required - it is used to check that the TiXmlString class isn't incorrectly - used. Be nice to old compilers and macro it here: -*/ -#if defined(_MSC_VER) && (_MSC_VER >= 1200 ) - // Microsoft visual studio, version 6 and higher. - #define TIXML_EXPLICIT explicit -#elif defined(__GNUC__) && (__GNUC__ >= 3 ) - // GCC version 3 and higher.s - #define TIXML_EXPLICIT explicit -#else - #define TIXML_EXPLICIT -#endif - - -/* - TiXmlString is an emulation of a subset of the std::string template. - Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. - Only the member functions relevant to the TinyXML project have been implemented. - The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase - a string and there's no more room, we allocate a buffer twice as big as we need. -*/ -class TiXmlString -{ - public : - // The size type used - typedef size_t size_type; - - // Error value for find primitive - static const size_type npos; // = -1; - - - // TiXmlString empty constructor - TiXmlString () : rep_(&nullrep_) - { - } - - // TiXmlString copy constructor - TiXmlString ( const TiXmlString & copy) : rep_(0) - { - init(copy.length()); - memcpy(start(), copy.data(), length()); - } - - // TiXmlString constructor, based on a string - TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0) - { - init( static_cast( strlen(copy) )); - memcpy(start(), copy, length()); - } - - // TiXmlString constructor, based on a string - TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0) - { - init(len); - memcpy(start(), str, len); - } - - // TiXmlString destructor - ~TiXmlString () - { - quit(); - } - - // = operator - TiXmlString& operator = (const char * copy) - { - return assign( copy, (size_type)strlen(copy)); - } - - // = operator - TiXmlString& operator = (const TiXmlString & copy) - { - return assign(copy.start(), copy.length()); - } - - - // += operator. Maps to append - TiXmlString& operator += (const char * suffix) - { - return append(suffix, static_cast( strlen(suffix) )); - } - - // += operator. Maps to append - TiXmlString& operator += (char single) - { - return append(&single, 1); - } - - // += operator. Maps to append - TiXmlString& operator += (const TiXmlString & suffix) - { - return append(suffix.data(), suffix.length()); - } - - - // Convert a TiXmlString into a null-terminated char * - const char * c_str () const { return rep_->str; } - - // Convert a TiXmlString into a char * (need not be null terminated). - const char * data () const { return rep_->str; } - - // Return the length of a TiXmlString - size_type length () const { return rep_->size; } - - // Alias for length() - size_type size () const { return rep_->size; } - - // Checks if a TiXmlString is empty - bool empty () const { return rep_->size == 0; } - - // Return capacity of string - size_type capacity () const { return rep_->capacity; } - - - // single char extraction - const char& at (size_type index) const - { - assert( index < length() ); - return rep_->str[ index ]; - } - - // [] operator - char& operator [] (size_type index) const - { - assert( index < length() ); - return rep_->str[ index ]; - } - - // find a char in a string. Return TiXmlString::npos if not found - size_type find (char lookup) const - { - return find(lookup, 0); - } - - // find a char in a string from an offset. Return TiXmlString::npos if not found - size_type find (char tofind, size_type offset) const - { - if (offset >= length()) return npos; - - for (const char* p = c_str() + offset; *p != '\0'; ++p) - { - if (*p == tofind) return static_cast< size_type >( p - c_str() ); - } - return npos; - } - - void clear () - { - //Lee: - //The original was just too strange, though correct: - // TiXmlString().swap(*this); - //Instead use the quit & re-init: - quit(); - init(0,0); - } - - /* Function to reserve a big amount of data when we know we'll need it. Be aware that this - function DOES NOT clear the content of the TiXmlString if any exists. - */ - void reserve (size_type cap); - - TiXmlString& assign (const char* str, size_type len); - - TiXmlString& append (const char* str, size_type len); - - void swap (TiXmlString& other) - { - Rep* r = rep_; - rep_ = other.rep_; - other.rep_ = r; - } - - private: - - void init(size_type sz) { init(sz, sz); } - void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; } - char* start() const { return rep_->str; } - char* finish() const { return rep_->str + rep_->size; } - - struct Rep - { - size_type size, capacity; - char str[1]; - }; - - void init(size_type sz, size_type cap) - { - if (cap) - { - // Lee: the original form: - // rep_ = static_cast(operator new(sizeof(Rep) + cap)); - // doesn't work in some cases of new being overloaded. Switching - // to the normal allocation, although use an 'int' for systems - // that are overly picky about structure alignment. - const size_type bytesNeeded = sizeof(Rep) + cap; - const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); - rep_ = reinterpret_cast( new int[ intsNeeded ] ); - - rep_->str[ rep_->size = sz ] = '\0'; - rep_->capacity = cap; - } - else - { - rep_ = &nullrep_; - } - } - - void quit() - { - if (rep_ != &nullrep_) - { - // The rep_ is really an array of ints. (see the allocator, above). - // Cast it back before delete, so the compiler won't incorrectly call destructors. - delete [] ( reinterpret_cast( rep_ ) ); - } - } - - Rep * rep_; - static Rep nullrep_; - -} ; - - -inline bool operator == (const TiXmlString & a, const TiXmlString & b) -{ - return ( a.length() == b.length() ) // optimization on some platforms - && ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare -} -inline bool operator < (const TiXmlString & a, const TiXmlString & b) -{ - return strcmp(a.c_str(), b.c_str()) < 0; -} - -inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); } -inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; } -inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); } -inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); } - -inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; } -inline bool operator == (const char* a, const TiXmlString & b) { return b == a; } -inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); } -inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); } - -TiXmlString operator + (const TiXmlString & a, const TiXmlString & b); -TiXmlString operator + (const TiXmlString & a, const char* b); -TiXmlString operator + (const char* a, const TiXmlString & b); - - -/* - TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. - Only the operators that we need for TinyXML have been developped. -*/ -class TiXmlOutStream : public TiXmlString -{ -public : - - // TiXmlOutStream << operator. - TiXmlOutStream & operator << (const TiXmlString & in) - { - *this += in; - return *this; - } - - // TiXmlOutStream << operator. - TiXmlOutStream & operator << (const char * in) - { - *this += in; - return *this; - } - -} ; - -#endif // TIXML_STRING_INCLUDED -#endif // TIXML_USE_STL +/* +www.sourceforge.net/projects/tinyxml +Original file by Yves Berquin. + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +/* + * THIS FILE WAS ALTERED BY Tyge Lovset, 7. April 2005. + * + * - completely rewritten. compact, clean, and fast implementation. + * - sizeof(TiXmlString) = pointer size (4 bytes on 32-bit systems) + * - fixed reserve() to work as per specification. + * - fixed buggy compares operator==(), operator<(), and operator>() + * - fixed operator+=() to take a const ref argument, following spec. + * - added "copy" constructor with length, and most compare operators. + * - added swap(), clear(), size(), capacity(), operator+(). + */ + +#ifndef TIXML_USE_STL + +#ifndef TIXML_STRING_INCLUDED +#define TIXML_STRING_INCLUDED + +#include +#include + +/* The support for explicit isn't that universal, and it isn't really + required - it is used to check that the TiXmlString class isn't incorrectly + used. Be nice to old compilers and macro it here: +*/ +#if defined(_MSC_VER) && (_MSC_VER >= 1200 ) + // Microsoft visual studio, version 6 and higher. + #define TIXML_EXPLICIT explicit +#elif defined(__GNUC__) && (__GNUC__ >= 3 ) + // GCC version 3 and higher.s + #define TIXML_EXPLICIT explicit +#else + #define TIXML_EXPLICIT +#endif + + +/* + TiXmlString is an emulation of a subset of the std::string template. + Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. + Only the member functions relevant to the TinyXML project have been implemented. + The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase + a string and there's no more room, we allocate a buffer twice as big as we need. +*/ +class TiXmlString +{ + public : + // The size type used + typedef size_t size_type; + + // Error value for find primitive + static const size_type npos; // = -1; + + + // TiXmlString empty constructor + TiXmlString () : rep_(&nullrep_) + { + } + + // TiXmlString copy constructor + TiXmlString ( const TiXmlString & copy) : rep_(0) + { + init(copy.length()); + memcpy(start(), copy.data(), length()); + } + + // TiXmlString constructor, based on a string + TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0) + { + init( static_cast( strlen(copy) )); + memcpy(start(), copy, length()); + } + + // TiXmlString constructor, based on a string + TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0) + { + init(len); + memcpy(start(), str, len); + } + + // TiXmlString destructor + ~TiXmlString () + { + quit(); + } + + // = operator + TiXmlString& operator = (const char * copy) + { + return assign( copy, (size_type)strlen(copy)); + } + + // = operator + TiXmlString& operator = (const TiXmlString & copy) + { + return assign(copy.start(), copy.length()); + } + + + // += operator. Maps to append + TiXmlString& operator += (const char * suffix) + { + return append(suffix, static_cast( strlen(suffix) )); + } + + // += operator. Maps to append + TiXmlString& operator += (char single) + { + return append(&single, 1); + } + + // += operator. Maps to append + TiXmlString& operator += (const TiXmlString & suffix) + { + return append(suffix.data(), suffix.length()); + } + + + // Convert a TiXmlString into a null-terminated char * + const char * c_str () const { return rep_->str; } + + // Convert a TiXmlString into a char * (need not be null terminated). + const char * data () const { return rep_->str; } + + // Return the length of a TiXmlString + size_type length () const { return rep_->size; } + + // Alias for length() + size_type size () const { return rep_->size; } + + // Checks if a TiXmlString is empty + bool empty () const { return rep_->size == 0; } + + // Return capacity of string + size_type capacity () const { return rep_->capacity; } + + + // single char extraction + const char& at (size_type index) const + { + assert( index < length() ); + return rep_->str[ index ]; + } + + // [] operator + char& operator [] (size_type index) const + { + assert( index < length() ); + return rep_->str[ index ]; + } + + // find a char in a string. Return TiXmlString::npos if not found + size_type find (char lookup) const + { + return find(lookup, 0); + } + + // find a char in a string from an offset. Return TiXmlString::npos if not found + size_type find (char tofind, size_type offset) const + { + if (offset >= length()) return npos; + + for (const char* p = c_str() + offset; *p != '\0'; ++p) + { + if (*p == tofind) return static_cast< size_type >( p - c_str() ); + } + return npos; + } + + void clear () + { + //Lee: + //The original was just too strange, though correct: + // TiXmlString().swap(*this); + //Instead use the quit & re-init: + quit(); + init(0,0); + } + + /* Function to reserve a big amount of data when we know we'll need it. Be aware that this + function DOES NOT clear the content of the TiXmlString if any exists. + */ + void reserve (size_type cap); + + TiXmlString& assign (const char* str, size_type len); + + TiXmlString& append (const char* str, size_type len); + + void swap (TiXmlString& other) + { + Rep* r = rep_; + rep_ = other.rep_; + other.rep_ = r; + } + + private: + + void init(size_type sz) { init(sz, sz); } + void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; } + char* start() const { return rep_->str; } + char* finish() const { return rep_->str + rep_->size; } + + struct Rep + { + size_type size, capacity; + char str[1]; + }; + + void init(size_type sz, size_type cap) + { + if (cap) + { + // Lee: the original form: + // rep_ = static_cast(operator new(sizeof(Rep) + cap)); + // doesn't work in some cases of new being overloaded. Switching + // to the normal allocation, although use an 'int' for systems + // that are overly picky about structure alignment. + const size_type bytesNeeded = sizeof(Rep) + cap; + const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); + rep_ = reinterpret_cast( new int[ intsNeeded ] ); + + rep_->str[ rep_->size = sz ] = '\0'; + rep_->capacity = cap; + } + else + { + rep_ = &nullrep_; + } + } + + void quit() + { + if (rep_ != &nullrep_) + { + // The rep_ is really an array of ints. (see the allocator, above). + // Cast it back before delete, so the compiler won't incorrectly call destructors. + delete [] ( reinterpret_cast( rep_ ) ); + } + } + + Rep * rep_; + static Rep nullrep_; + +} ; + + +inline bool operator == (const TiXmlString & a, const TiXmlString & b) +{ + return ( a.length() == b.length() ) // optimization on some platforms + && ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare +} +inline bool operator < (const TiXmlString & a, const TiXmlString & b) +{ + return strcmp(a.c_str(), b.c_str()) < 0; +} + +inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); } +inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; } +inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); } +inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); } + +inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; } +inline bool operator == (const char* a, const TiXmlString & b) { return b == a; } +inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); } +inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); } + +TiXmlString operator + (const TiXmlString & a, const TiXmlString & b); +TiXmlString operator + (const TiXmlString & a, const char* b); +TiXmlString operator + (const char* a, const TiXmlString & b); + + +/* + TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. + Only the operators that we need for TinyXML have been developped. +*/ +class TiXmlOutStream : public TiXmlString +{ +public : + + // TiXmlOutStream << operator. + TiXmlOutStream & operator << (const TiXmlString & in) + { + *this += in; + return *this; + } + + // TiXmlOutStream << operator. + TiXmlOutStream & operator << (const char * in) + { + *this += in; + return *this; + } + +} ; + +#endif // TIXML_STRING_INCLUDED +#endif // TIXML_USE_STL diff --git a/pcsx2/tinyxml/tinyxml.cpp b/pcsx2/tinyxml/tinyxml.cpp index 64067b4622..1bd61cd6c9 100644 --- a/pcsx2/tinyxml/tinyxml.cpp +++ b/pcsx2/tinyxml/tinyxml.cpp @@ -1,1866 +1,1866 @@ -/* -www.sourceforge.net/projects/tinyxml -Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -#include - -#ifdef TIXML_USE_STL -#include -#include -#endif - -#include "tinyxml.h" - - -bool TiXmlBase::condenseWhiteSpace = true; - -void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_STRING* outString ) -{ - int i=0; - - while( i<(int)str.length() ) - { - unsigned char c = (unsigned char) str[i]; - - if ( c == '&' - && i < ( (int)str.length() - 2 ) - && str[i+1] == '#' - && str[i+2] == 'x' ) - { - // Hexadecimal character reference. - // Pass through unchanged. - // © -- copyright symbol, for example. - // - // The -1 is a bug fix from Rob Laveaux. It keeps - // an overflow from happening if there is no ';'. - // There are actually 2 ways to exit this loop - - // while fails (error case) and break (semicolon found). - // However, there is no mechanism (currently) for - // this function to return an error. - while ( i<(int)str.length()-1 ) - { - outString->append( str.c_str() + i, 1 ); - ++i; - if ( str[i] == ';' ) - break; - } - } - else if ( c == '&' ) - { - outString->append( entity[0].str, entity[0].strLength ); - ++i; - } - else if ( c == '<' ) - { - outString->append( entity[1].str, entity[1].strLength ); - ++i; - } - else if ( c == '>' ) - { - outString->append( entity[2].str, entity[2].strLength ); - ++i; - } - else if ( c == '\"' ) - { - outString->append( entity[3].str, entity[3].strLength ); - ++i; - } - else if ( c == '\'' ) - { - outString->append( entity[4].str, entity[4].strLength ); - ++i; - } - else if ( c < 32 ) - { - // Easy pass at non-alpha/numeric/symbol - // Below 32 is symbolic. - char buf[ 32 ]; - - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) ); - #else - sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); - #endif - - //*ME: warning C4267: convert 'size_t' to 'int' - //*ME: Int-Cast to make compiler happy ... - outString->append( buf, (int)strlen( buf ) ); - ++i; - } - else - { - //char realc = (char) c; - //outString->append( &realc, 1 ); - *outString += (char) c; // somewhat more efficient function call. - ++i; - } - } -} - - -TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() -{ - parent = 0; - type = _type; - firstChild = 0; - lastChild = 0; - prev = 0; - next = 0; -} - - -TiXmlNode::~TiXmlNode() -{ - TiXmlNode* node = firstChild; - TiXmlNode* temp = 0; - - while ( node ) - { - temp = node; - node = node->next; - delete temp; - } -} - - -void TiXmlNode::CopyTo( TiXmlNode* target ) const -{ - target->SetValue (value.c_str() ); - target->userData = userData; -} - - -void TiXmlNode::Clear() -{ - TiXmlNode* node = firstChild; - TiXmlNode* temp = 0; - - while ( node ) - { - temp = node; - node = node->next; - delete temp; - } - - firstChild = 0; - lastChild = 0; -} - - -TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) -{ - assert( node->parent == 0 || node->parent == this ); - assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); - - if ( node->Type() == TiXmlNode::DOCUMENT ) - { - delete node; - if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - node->parent = this; - - node->prev = lastChild; - node->next = 0; - - if ( lastChild ) - lastChild->next = node; - else - firstChild = node; // it was an empty list. - - lastChild = node; - return node; -} - - -TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) -{ - if ( addThis.Type() == TiXmlNode::DOCUMENT ) - { - if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - TiXmlNode* node = addThis.Clone(); - if ( !node ) - return 0; - - return LinkEndChild( node ); -} - - -TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) -{ - if ( !beforeThis || beforeThis->parent != this ) { - return 0; - } - if ( addThis.Type() == TiXmlNode::DOCUMENT ) - { - if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - TiXmlNode* node = addThis.Clone(); - if ( !node ) - return 0; - node->parent = this; - - node->next = beforeThis; - node->prev = beforeThis->prev; - if ( beforeThis->prev ) - { - beforeThis->prev->next = node; - } - else - { - assert( firstChild == beforeThis ); - firstChild = node; - } - beforeThis->prev = node; - return node; -} - - -TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) -{ - if ( !afterThis || afterThis->parent != this ) { - return 0; - } - if ( addThis.Type() == TiXmlNode::DOCUMENT ) - { - if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - TiXmlNode* node = addThis.Clone(); - if ( !node ) - return 0; - node->parent = this; - - node->prev = afterThis; - node->next = afterThis->next; - if ( afterThis->next ) - { - afterThis->next->prev = node; - } - else - { - assert( lastChild == afterThis ); - lastChild = node; - } - afterThis->next = node; - return node; -} - - -TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) -{ - if ( replaceThis->parent != this ) - return 0; - - TiXmlNode* node = withThis.Clone(); - if ( !node ) - return 0; - - node->next = replaceThis->next; - node->prev = replaceThis->prev; - - if ( replaceThis->next ) - replaceThis->next->prev = node; - else - lastChild = node; - - if ( replaceThis->prev ) - replaceThis->prev->next = node; - else - firstChild = node; - - delete replaceThis; - node->parent = this; - return node; -} - - -bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) -{ - if ( removeThis->parent != this ) - { - assert( 0 ); - return false; - } - - if ( removeThis->next ) - removeThis->next->prev = removeThis->prev; - else - lastChild = removeThis->prev; - - if ( removeThis->prev ) - removeThis->prev->next = removeThis->next; - else - firstChild = removeThis->next; - - delete removeThis; - return true; -} - -const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const -{ - const TiXmlNode* node; - for ( node = firstChild; node; node = node->next ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; -} - - -const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const -{ - const TiXmlNode* node; - for ( node = lastChild; node; node = node->prev ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; -} - - -const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const -{ - if ( !previous ) - { - return FirstChild(); - } - else - { - assert( previous->parent == this ); - return previous->NextSibling(); - } -} - - -const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const -{ - if ( !previous ) - { - return FirstChild( val ); - } - else - { - assert( previous->parent == this ); - return previous->NextSibling( val ); - } -} - - -const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const -{ - const TiXmlNode* node; - for ( node = next; node; node = node->next ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; -} - - -const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const -{ - const TiXmlNode* node; - for ( node = prev; node; node = node->prev ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; -} - - -void TiXmlElement::RemoveAttribute( const char * name ) -{ - #ifdef TIXML_USE_STL - TIXML_STRING str( name ); - TiXmlAttribute* node = attributeSet.Find( str ); - #else - TiXmlAttribute* node = attributeSet.Find( name ); - #endif - if ( node ) - { - attributeSet.Remove( node ); - delete node; - } -} - -const TiXmlElement* TiXmlNode::FirstChildElement() const -{ - const TiXmlNode* node; - - for ( node = FirstChild(); - node; - node = node->NextSibling() ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; -} - - -const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const -{ - const TiXmlNode* node; - - for ( node = FirstChild( _value ); - node; - node = node->NextSibling( _value ) ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; -} - - -const TiXmlElement* TiXmlNode::NextSiblingElement() const -{ - const TiXmlNode* node; - - for ( node = NextSibling(); - node; - node = node->NextSibling() ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; -} - - -const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const -{ - const TiXmlNode* node; - - for ( node = NextSibling( _value ); - node; - node = node->NextSibling( _value ) ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; -} - - -const TiXmlDocument* TiXmlNode::GetDocument() const -{ - const TiXmlNode* node; - - for( node = this; node; node = node->parent ) - { - if ( node->ToDocument() ) - return node->ToDocument(); - } - return 0; -} - - -TiXmlElement::TiXmlElement (const char * _value) - : TiXmlNode( TiXmlNode::ELEMENT ) -{ - firstChild = lastChild = 0; - value = _value; -} - - -#ifdef TIXML_USE_STL -TiXmlElement::TiXmlElement( const std::string& _value ) - : TiXmlNode( TiXmlNode::ELEMENT ) -{ - firstChild = lastChild = 0; - value = _value; -} -#endif - - -TiXmlElement::TiXmlElement( const TiXmlElement& copy) - : TiXmlNode( TiXmlNode::ELEMENT ) -{ - firstChild = lastChild = 0; - copy.CopyTo( this ); -} - - -void TiXmlElement::operator=( const TiXmlElement& base ) -{ - ClearThis(); - base.CopyTo( this ); -} - - -TiXmlElement::~TiXmlElement() -{ - ClearThis(); -} - - -void TiXmlElement::ClearThis() -{ - Clear(); - while( attributeSet.First() ) - { - TiXmlAttribute* node = attributeSet.First(); - attributeSet.Remove( node ); - delete node; - } -} - - -const char* TiXmlElement::Attribute( const char* name ) const -{ - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( node ) - return node->Value(); - return 0; -} - - -#ifdef TIXML_USE_STL -const std::string* TiXmlElement::Attribute( const std::string& name ) const -{ - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( node ) - return &node->ValueStr(); - return 0; -} -#endif - - -const char* TiXmlElement::Attribute( const char* name, int* i ) const -{ - const char* s = Attribute( name ); - if ( i ) - { - if ( s ) { - *i = atoi( s ); - } - else { - *i = 0; - } - } - return s; -} - - -#ifdef TIXML_USE_STL -const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const -{ - const std::string* s = Attribute( name ); - if ( i ) - { - if ( s ) { - *i = atoi( s->c_str() ); - } - else { - *i = 0; - } - } - return s; -} -#endif - - -const char* TiXmlElement::Attribute( const char* name, double* d ) const -{ - const char* s = Attribute( name ); - if ( d ) - { - if ( s ) { - *d = atof( s ); - } - else { - *d = 0; - } - } - return s; -} - - -#ifdef TIXML_USE_STL -const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const -{ - const std::string* s = Attribute( name ); - if ( d ) - { - if ( s ) { - *d = atof( s->c_str() ); - } - else { - *d = 0; - } - } - return s; -} -#endif - - -int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const -{ - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - return node->QueryIntValue( ival ); -} - - -#ifdef TIXML_USE_STL -int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const -{ - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - return node->QueryIntValue( ival ); -} -#endif - - -int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const -{ - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - return node->QueryDoubleValue( dval ); -} - - -#ifdef TIXML_USE_STL -int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const -{ - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - return node->QueryDoubleValue( dval ); -} -#endif - - -void TiXmlElement::SetAttribute( const char * name, int val ) -{ - char buf[64]; - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "%d", val ); - #else - sprintf( buf, "%d", val ); - #endif - SetAttribute( name, buf ); -} - - -#ifdef TIXML_USE_STL -void TiXmlElement::SetAttribute( const std::string& name, int val ) -{ - std::ostringstream oss; - oss << val; - SetAttribute( name, oss.str() ); -} -#endif - - -void TiXmlElement::SetDoubleAttribute( const char * name, double val ) -{ - char buf[256]; - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "%f", val ); - #else - sprintf( buf, "%f", val ); - #endif - SetAttribute( name, buf ); -} - - -void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) -{ - #ifdef TIXML_USE_STL - TIXML_STRING _name( cname ); - TIXML_STRING _value( cvalue ); - #else - const char* _name = cname; - const char* _value = cvalue; - #endif - - TiXmlAttribute* node = attributeSet.Find( _name ); - if ( node ) - { - node->SetValue( _value ); - return; - } - - TiXmlAttribute* attrib = new TiXmlAttribute( cname, cvalue ); - if ( attrib ) - { - attributeSet.Add( attrib ); - } - else - { - TiXmlDocument* document = GetDocument(); - if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); - } -} - - -#ifdef TIXML_USE_STL -void TiXmlElement::SetAttribute( const std::string& name, const std::string& _value ) -{ - TiXmlAttribute* node = attributeSet.Find( name ); - if ( node ) - { - node->SetValue( _value ); - return; - } - - TiXmlAttribute* attrib = new TiXmlAttribute( name, _value ); - if ( attrib ) - { - attributeSet.Add( attrib ); - } - else - { - TiXmlDocument* document = GetDocument(); - if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); - } -} -#endif - - -void TiXmlElement::Print( FILE* cfile, int depth ) const -{ - int i; - assert( cfile ); - for ( i=0; iNext() ) - { - fprintf( cfile, " " ); - attrib->Print( cfile, depth ); - } - - // There are 3 different formatting approaches: - // 1) An element without children is printed as a node - // 2) An element with only a text child is printed as text - // 3) An element with children is printed on multiple lines. - TiXmlNode* node; - if ( !firstChild ) - { - fprintf( cfile, " />" ); - } - else if ( firstChild == lastChild && firstChild->ToText() ) - { - fprintf( cfile, ">" ); - firstChild->Print( cfile, depth + 1 ); - fprintf( cfile, "", value.c_str() ); - } - else - { - fprintf( cfile, ">" ); - - for ( node = firstChild; node; node=node->NextSibling() ) - { - if ( !node->ToText() ) - { - fprintf( cfile, "\n" ); - } - node->Print( cfile, depth+1 ); - } - fprintf( cfile, "\n" ); - for( i=0; i", value.c_str() ); - } -} - - -void TiXmlElement::CopyTo( TiXmlElement* target ) const -{ - // superclass: - TiXmlNode::CopyTo( target ); - - // Element class: - // Clone the attributes, then clone the children. - const TiXmlAttribute* attribute = 0; - for( attribute = attributeSet.First(); - attribute; - attribute = attribute->Next() ) - { - target->SetAttribute( attribute->Name(), attribute->Value() ); - } - - TiXmlNode* node = 0; - for ( node = firstChild; node; node = node->NextSibling() ) - { - target->LinkEndChild( node->Clone() ); - } -} - -bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const -{ - if ( visitor->VisitEnter( *this, attributeSet.First() ) ) - { - for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) - { - if ( !node->Accept( visitor ) ) - break; - } - } - return visitor->VisitExit( *this ); -} - - -TiXmlNode* TiXmlElement::Clone() const -{ - TiXmlElement* clone = new TiXmlElement( Value() ); - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -const char* TiXmlElement::GetText() const -{ - const TiXmlNode* child = this->FirstChild(); - if ( child ) { - const TiXmlText* childText = child->ToText(); - if ( childText ) { - return childText->Value(); - } - } - return 0; -} - - -TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT ) -{ - tabsize = 4; - useMicrosoftBOM = false; - ClearError(); -} - -TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) -{ - tabsize = 4; - useMicrosoftBOM = false; - value = documentName; - ClearError(); -} - - -#ifdef TIXML_USE_STL -TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) -{ - tabsize = 4; - useMicrosoftBOM = false; - value = documentName; - ClearError(); -} -#endif - - -TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT ) -{ - copy.CopyTo( this ); -} - - -void TiXmlDocument::operator=( const TiXmlDocument& copy ) -{ - Clear(); - copy.CopyTo( this ); -} - - -bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) -{ - // See STL_STRING_BUG below. - //StringToBuffer buf( value ); - - return LoadFile( Value(), encoding ); -} - - -bool TiXmlDocument::SaveFile() const -{ - // See STL_STRING_BUG below. -// StringToBuffer buf( value ); -// -// if ( buf.buffer && SaveFile( buf.buffer ) ) -// return true; -// -// return false; - return SaveFile( Value() ); -} - -bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) -{ - // There was a really terrifying little bug here. The code: - // value = filename - // in the STL case, cause the assignment method of the std::string to - // be called. What is strange, is that the std::string had the same - // address as it's c_str() method, and so bad things happen. Looks - // like a bug in the Microsoft STL implementation. - // Add an extra string to avoid the crash. - TIXML_STRING filename( _filename ); - value = filename; - - // reading in binary mode so that tinyxml can normalize the EOL - FILE* file = fopen( value.c_str (), "rb" ); - - if ( file ) - { - bool result = LoadFile( file, encoding ); - fclose( file ); - return result; - } - else - { - SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } -} - -bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) -{ - if ( !file ) - { - SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } - - // Delete the existing data: - Clear(); - location.Clear(); - - // Get the file size, so we can pre-allocate the string. HUGE speed impact. - long length = 0; - fseek( file, 0, SEEK_END ); - length = ftell( file ); - fseek( file, 0, SEEK_SET ); - - // Strange case, but good to handle up front. - if ( length == 0 ) - { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } - - // If we have a file, assume it is all one big XML file, and read it in. - // The document parser may decide the document ends sooner than the entire file, however. - TIXML_STRING data; - data.reserve( length ); - - // Subtle bug here. TinyXml did use fgets. But from the XML spec: - // 2.11 End-of-Line Handling - // - // - // ...the XML processor MUST behave as if it normalized all line breaks in external - // parsed entities (including the document entity) on input, before parsing, by translating - // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to - // a single #xA character. - // - // - // It is not clear fgets does that, and certainly isn't clear it works cross platform. - // Generally, you expect fgets to translate from the convention of the OS to the c/unix - // convention, and not work generally. - - /* - while( fgets( buf, sizeof(buf), file ) ) - { - data += buf; - } - */ - - char* buf = new char[ length+1 ]; - buf[0] = 0; - - if ( fread( buf, length, 1, file ) != 1 ) { - delete [] buf; - SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } - - const char* lastPos = buf; - const char* p = buf; - - buf[length] = 0; - while( *p ) { - assert( p < (buf+length) ); - if ( *p == 0xa ) { - // Newline character. No special rules for this. Append all the characters - // since the last string, and include the newline. - data.append( lastPos, (p-lastPos+1) ); // append, include the newline - ++p; // move past the newline - lastPos = p; // and point to the new buffer (may be 0) - assert( p <= (buf+length) ); - } - else if ( *p == 0xd ) { - // Carriage return. Append what we have so far, then - // handle moving forward in the buffer. - if ( (p-lastPos) > 0 ) { - data.append( lastPos, p-lastPos ); // do not add the CR - } - data += (char)0xa; // a proper newline - - if ( *(p+1) == 0xa ) { - // Carriage return - new line sequence - p += 2; - lastPos = p; - assert( p <= (buf+length) ); - } - else { - // it was followed by something else...that is presumably characters again. - ++p; - lastPos = p; - assert( p <= (buf+length) ); - } - } - else { - ++p; - } - } - // Handle any left over characters. - if ( p-lastPos ) { - data.append( lastPos, p-lastPos ); - } - delete [] buf; - buf = 0; - - Parse( data.c_str(), 0, encoding ); - - if ( Error() ) - return false; - else - return true; -} - - -bool TiXmlDocument::SaveFile( const char * filename ) const -{ - // The old c stuff lives on... - FILE* fp = fopen( filename, "w" ); - if ( fp ) - { - bool result = SaveFile( fp ); - fclose( fp ); - return result; - } - return false; -} - - -bool TiXmlDocument::SaveFile( FILE* fp ) const -{ - if ( useMicrosoftBOM ) - { - const unsigned char TIXML_UTF_LEAD_0 = 0xefU; - const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; - const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; - - fputc( TIXML_UTF_LEAD_0, fp ); - fputc( TIXML_UTF_LEAD_1, fp ); - fputc( TIXML_UTF_LEAD_2, fp ); - } - Print( fp, 0 ); - return (ferror(fp) == 0); -} - - -void TiXmlDocument::CopyTo( TiXmlDocument* target ) const -{ - TiXmlNode::CopyTo( target ); - - target->error = error; - target->errorDesc = errorDesc.c_str (); - - TiXmlNode* node = 0; - for ( node = firstChild; node; node = node->NextSibling() ) - { - target->LinkEndChild( node->Clone() ); - } -} - - -TiXmlNode* TiXmlDocument::Clone() const -{ - TiXmlDocument* clone = new TiXmlDocument(); - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -void TiXmlDocument::Print( FILE* cfile, int depth ) const -{ - assert( cfile ); - for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) - { - node->Print( cfile, depth ); - fprintf( cfile, "\n" ); - } -} - - -bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const -{ - if ( visitor->VisitEnter( *this ) ) - { - for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) - { - if ( !node->Accept( visitor ) ) - break; - } - } - return visitor->VisitExit( *this ); -} - - -const TiXmlAttribute* TiXmlAttribute::Next() const -{ - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( next->value.empty() && next->name.empty() ) - return 0; - return next; -} - -/* -TiXmlAttribute* TiXmlAttribute::Next() -{ - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( next->value.empty() && next->name.empty() ) - return 0; - return next; -} -*/ - -const TiXmlAttribute* TiXmlAttribute::Previous() const -{ - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( prev->value.empty() && prev->name.empty() ) - return 0; - return prev; -} - -/* -TiXmlAttribute* TiXmlAttribute::Previous() -{ - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( prev->value.empty() && prev->name.empty() ) - return 0; - return prev; -} -*/ - -void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const -{ - TIXML_STRING n, v; - - PutString( name, &n ); - PutString( value, &v ); - - if (value.find ('\"') == TIXML_STRING::npos) { - if ( cfile ) { - fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); - } - if ( str ) { - (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; - } - } - else { - if ( cfile ) { - fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); - } - if ( str ) { - (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; - } - } -} - - -int TiXmlAttribute::QueryIntValue( int* ival ) const -{ - if ( sscanf( value.c_str(), "%d", ival ) == 1 ) - return TIXML_SUCCESS; - return TIXML_WRONG_TYPE; -} - -int TiXmlAttribute::QueryDoubleValue( double* dval ) const -{ - if ( sscanf( value.c_str(), "%lf", dval ) == 1 ) - return TIXML_SUCCESS; - return TIXML_WRONG_TYPE; -} - -void TiXmlAttribute::SetIntValue( int _value ) -{ - char buf [64]; - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); - #else - sprintf (buf, "%d", _value); - #endif - SetValue (buf); -} - -void TiXmlAttribute::SetDoubleValue( double _value ) -{ - char buf [256]; - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "%lf", _value); - #else - sprintf (buf, "%lf", _value); - #endif - SetValue (buf); -} - -int TiXmlAttribute::IntValue() const -{ - return atoi (value.c_str ()); -} - -double TiXmlAttribute::DoubleValue() const -{ - return atof (value.c_str ()); -} - - -TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT ) -{ - copy.CopyTo( this ); -} - - -void TiXmlComment::operator=( const TiXmlComment& base ) -{ - Clear(); - base.CopyTo( this ); -} - - -void TiXmlComment::Print( FILE* cfile, int depth ) const -{ - assert( cfile ); - for ( int i=0; i", value.c_str() ); -} - - -void TiXmlComment::CopyTo( TiXmlComment* target ) const -{ - TiXmlNode::CopyTo( target ); -} - - -bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const -{ - return visitor->Visit( *this ); -} - - -TiXmlNode* TiXmlComment::Clone() const -{ - TiXmlComment* clone = new TiXmlComment(); - - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -void TiXmlText::Print( FILE* cfile, int depth ) const -{ - assert( cfile ); - if ( cdata ) - { - int i; - fprintf( cfile, "\n" ); - for ( i=0; i\n", value.c_str() ); // unformatted output - } - else - { - TIXML_STRING buffer; - PutString( value, &buffer ); - fprintf( cfile, "%s", buffer.c_str() ); - } -} - - -void TiXmlText::CopyTo( TiXmlText* target ) const -{ - TiXmlNode::CopyTo( target ); - target->cdata = cdata; -} - - -bool TiXmlText::Accept( TiXmlVisitor* visitor ) const -{ - return visitor->Visit( *this ); -} - - -TiXmlNode* TiXmlText::Clone() const -{ - TiXmlText* clone = 0; - clone = new TiXmlText( "" ); - - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -TiXmlDeclaration::TiXmlDeclaration( const char * _version, - const char * _encoding, - const char * _standalone ) - : TiXmlNode( TiXmlNode::DECLARATION ) -{ - version = _version; - encoding = _encoding; - standalone = _standalone; -} - - -#ifdef TIXML_USE_STL -TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, - const std::string& _encoding, - const std::string& _standalone ) - : TiXmlNode( TiXmlNode::DECLARATION ) -{ - version = _version; - encoding = _encoding; - standalone = _standalone; -} -#endif - - -TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) - : TiXmlNode( TiXmlNode::DECLARATION ) -{ - copy.CopyTo( this ); -} - - -void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) -{ - Clear(); - copy.CopyTo( this ); -} - - -void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const -{ - if ( cfile ) fprintf( cfile, "" ); - if ( str ) (*str) += "?>"; -} - - -void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const -{ - TiXmlNode::CopyTo( target ); - - target->version = version; - target->encoding = encoding; - target->standalone = standalone; -} - - -bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const -{ - return visitor->Visit( *this ); -} - - -TiXmlNode* TiXmlDeclaration::Clone() const -{ - TiXmlDeclaration* clone = new TiXmlDeclaration(); - - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -void TiXmlUnknown::Print( FILE* cfile, int depth ) const -{ - for ( int i=0; i", value.c_str() ); -} - - -void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const -{ - TiXmlNode::CopyTo( target ); -} - - -bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const -{ - return visitor->Visit( *this ); -} - - -TiXmlNode* TiXmlUnknown::Clone() const -{ - TiXmlUnknown* clone = new TiXmlUnknown(); - - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -TiXmlAttributeSet::TiXmlAttributeSet() -{ - sentinel.next = &sentinel; - sentinel.prev = &sentinel; -} - - -TiXmlAttributeSet::~TiXmlAttributeSet() -{ - assert( sentinel.next == &sentinel ); - assert( sentinel.prev == &sentinel ); -} - - -void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) -{ - #ifdef TIXML_USE_STL - assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set. - #else - assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. - #endif - - addMe->next = &sentinel; - addMe->prev = sentinel.prev; - - sentinel.prev->next = addMe; - sentinel.prev = addMe; -} - -void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) -{ - TiXmlAttribute* node; - - for( node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( node == removeMe ) - { - node->prev->next = node->next; - node->next->prev = node->prev; - node->next = 0; - node->prev = 0; - return; - } - } - assert( 0 ); // we tried to remove a non-linked attribute. -} - - -#ifdef TIXML_USE_STL -const TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const -{ - for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( node->name == name ) - return node; - } - return 0; -} - -/* -TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) -{ - for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( node->name == name ) - return node; - } - return 0; -} -*/ -#endif - - -const TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const -{ - for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( strcmp( node->name.c_str(), name ) == 0 ) - return node; - } - return 0; -} - -/* -TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) -{ - for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( strcmp( node->name.c_str(), name ) == 0 ) - return node; - } - return 0; -} -*/ - -#ifdef TIXML_USE_STL -std::istream& operator>> (std::istream & in, TiXmlNode & base) -{ - TIXML_STRING tag; - tag.reserve( 8 * 1000 ); - base.StreamIn( &in, &tag ); - - base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); - return in; -} -#endif - - -#ifdef TIXML_USE_STL -std::ostream& operator<< (std::ostream & out, const TiXmlNode & base) -{ - TiXmlPrinter printer; - printer.SetStreamPrinting(); - base.Accept( &printer ); - out << printer.Str(); - - return out; -} - - -std::string& operator<< (std::string& out, const TiXmlNode& base ) -{ - TiXmlPrinter printer; - printer.SetStreamPrinting(); - base.Accept( &printer ); - out.append( printer.Str() ); - - return out; -} -#endif - - -TiXmlHandle TiXmlHandle::FirstChild() const -{ - if ( node ) - { - TiXmlNode* child = node->FirstChild(); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const -{ - if ( node ) - { - TiXmlNode* child = node->FirstChild( value ); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::FirstChildElement() const -{ - if ( node ) - { - TiXmlElement* child = node->FirstChildElement(); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const -{ - if ( node ) - { - TiXmlElement* child = node->FirstChildElement( value ); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::Child( int count ) const -{ - if ( node ) - { - int i; - TiXmlNode* child = node->FirstChild(); - for ( i=0; - child && iNextSibling(), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const -{ - if ( node ) - { - int i; - TiXmlNode* child = node->FirstChild( value ); - for ( i=0; - child && iNextSibling( value ), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::ChildElement( int count ) const -{ - if ( node ) - { - int i; - TiXmlElement* child = node->FirstChildElement(); - for ( i=0; - child && iNextSiblingElement(), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const -{ - if ( node ) - { - int i; - TiXmlElement* child = node->FirstChildElement( value ); - for ( i=0; - child && iNextSiblingElement( value ), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -bool TiXmlPrinter::VisitEnter( const TiXmlDocument& ) -{ - return true; -} - -bool TiXmlPrinter::VisitExit( const TiXmlDocument& ) -{ - return true; -} - -bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) -{ - DoIndent(); - buffer += "<"; - buffer += element.Value(); - - for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() ) - { - buffer += " "; - attrib->Print( 0, 0, &buffer ); - } - - if ( !element.FirstChild() ) - { - buffer += " />"; - DoLineBreak(); - } - else - { - buffer += ">"; - if ( element.FirstChild()->ToText() - && element.LastChild() == element.FirstChild() - && element.FirstChild()->ToText()->CDATA() == false ) - { - simpleTextPrint = true; - // no DoLineBreak()! - } - else - { - DoLineBreak(); - } - } - ++depth; - return true; -} - - -bool TiXmlPrinter::VisitExit( const TiXmlElement& element ) -{ - --depth; - if ( !element.FirstChild() ) - { - // nothing. - } - else - { - if ( simpleTextPrint ) - { - simpleTextPrint = false; - } - else - { - DoIndent(); - } - buffer += ""; - DoLineBreak(); - } - return true; -} - - -bool TiXmlPrinter::Visit( const TiXmlText& text ) -{ - if ( text.CDATA() ) - { - DoIndent(); - buffer += ""; - DoLineBreak(); - } - else if ( simpleTextPrint ) - { - buffer += text.Value(); - } - else - { - DoIndent(); - buffer += text.Value(); - DoLineBreak(); - } - return true; -} - - -bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration ) -{ - DoIndent(); - declaration.Print( 0, 0, &buffer ); - DoLineBreak(); - return true; -} - - -bool TiXmlPrinter::Visit( const TiXmlComment& comment ) -{ - DoIndent(); - buffer += ""; - DoLineBreak(); - return true; -} - - -bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown ) -{ - DoIndent(); - buffer += "<"; - buffer += unknown.Value(); - buffer += ">"; - DoLineBreak(); - return true; -} - +/* +www.sourceforge.net/projects/tinyxml +Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include + +#ifdef TIXML_USE_STL +#include +#include +#endif + +#include "tinyxml.h" + + +bool TiXmlBase::condenseWhiteSpace = true; + +void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_STRING* outString ) +{ + int i=0; + + while( i<(int)str.length() ) + { + unsigned char c = (unsigned char) str[i]; + + if ( c == '&' + && i < ( (int)str.length() - 2 ) + && str[i+1] == '#' + && str[i+2] == 'x' ) + { + // Hexadecimal character reference. + // Pass through unchanged. + // © -- copyright symbol, for example. + // + // The -1 is a bug fix from Rob Laveaux. It keeps + // an overflow from happening if there is no ';'. + // There are actually 2 ways to exit this loop - + // while fails (error case) and break (semicolon found). + // However, there is no mechanism (currently) for + // this function to return an error. + while ( i<(int)str.length()-1 ) + { + outString->append( str.c_str() + i, 1 ); + ++i; + if ( str[i] == ';' ) + break; + } + } + else if ( c == '&' ) + { + outString->append( entity[0].str, entity[0].strLength ); + ++i; + } + else if ( c == '<' ) + { + outString->append( entity[1].str, entity[1].strLength ); + ++i; + } + else if ( c == '>' ) + { + outString->append( entity[2].str, entity[2].strLength ); + ++i; + } + else if ( c == '\"' ) + { + outString->append( entity[3].str, entity[3].strLength ); + ++i; + } + else if ( c == '\'' ) + { + outString->append( entity[4].str, entity[4].strLength ); + ++i; + } + else if ( c < 32 ) + { + // Easy pass at non-alpha/numeric/symbol + // Below 32 is symbolic. + char buf[ 32 ]; + + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) ); + #else + sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); + #endif + + //*ME: warning C4267: convert 'size_t' to 'int' + //*ME: Int-Cast to make compiler happy ... + outString->append( buf, (int)strlen( buf ) ); + ++i; + } + else + { + //char realc = (char) c; + //outString->append( &realc, 1 ); + *outString += (char) c; // somewhat more efficient function call. + ++i; + } + } +} + + +TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() +{ + parent = 0; + type = _type; + firstChild = 0; + lastChild = 0; + prev = 0; + next = 0; +} + + +TiXmlNode::~TiXmlNode() +{ + TiXmlNode* node = firstChild; + TiXmlNode* temp = 0; + + while ( node ) + { + temp = node; + node = node->next; + delete temp; + } +} + + +void TiXmlNode::CopyTo( TiXmlNode* target ) const +{ + target->SetValue (value.c_str() ); + target->userData = userData; +} + + +void TiXmlNode::Clear() +{ + TiXmlNode* node = firstChild; + TiXmlNode* temp = 0; + + while ( node ) + { + temp = node; + node = node->next; + delete temp; + } + + firstChild = 0; + lastChild = 0; +} + + +TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) +{ + assert( node->parent == 0 || node->parent == this ); + assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); + + if ( node->Type() == TiXmlNode::DOCUMENT ) + { + delete node; + if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + node->parent = this; + + node->prev = lastChild; + node->next = 0; + + if ( lastChild ) + lastChild->next = node; + else + firstChild = node; // it was an empty list. + + lastChild = node; + return node; +} + + +TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) +{ + if ( addThis.Type() == TiXmlNode::DOCUMENT ) + { + if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + + return LinkEndChild( node ); +} + + +TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) +{ + if ( !beforeThis || beforeThis->parent != this ) { + return 0; + } + if ( addThis.Type() == TiXmlNode::DOCUMENT ) + { + if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + node->parent = this; + + node->next = beforeThis; + node->prev = beforeThis->prev; + if ( beforeThis->prev ) + { + beforeThis->prev->next = node; + } + else + { + assert( firstChild == beforeThis ); + firstChild = node; + } + beforeThis->prev = node; + return node; +} + + +TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) +{ + if ( !afterThis || afterThis->parent != this ) { + return 0; + } + if ( addThis.Type() == TiXmlNode::DOCUMENT ) + { + if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + node->parent = this; + + node->prev = afterThis; + node->next = afterThis->next; + if ( afterThis->next ) + { + afterThis->next->prev = node; + } + else + { + assert( lastChild == afterThis ); + lastChild = node; + } + afterThis->next = node; + return node; +} + + +TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) +{ + if ( replaceThis->parent != this ) + return 0; + + TiXmlNode* node = withThis.Clone(); + if ( !node ) + return 0; + + node->next = replaceThis->next; + node->prev = replaceThis->prev; + + if ( replaceThis->next ) + replaceThis->next->prev = node; + else + lastChild = node; + + if ( replaceThis->prev ) + replaceThis->prev->next = node; + else + firstChild = node; + + delete replaceThis; + node->parent = this; + return node; +} + + +bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) +{ + if ( removeThis->parent != this ) + { + assert( 0 ); + return false; + } + + if ( removeThis->next ) + removeThis->next->prev = removeThis->prev; + else + lastChild = removeThis->prev; + + if ( removeThis->prev ) + removeThis->prev->next = removeThis->next; + else + firstChild = removeThis->next; + + delete removeThis; + return true; +} + +const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = firstChild; node; node = node->next ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = lastChild; node; node = node->prev ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const +{ + if ( !previous ) + { + return FirstChild(); + } + else + { + assert( previous->parent == this ); + return previous->NextSibling(); + } +} + + +const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const +{ + if ( !previous ) + { + return FirstChild( val ); + } + else + { + assert( previous->parent == this ); + return previous->NextSibling( val ); + } +} + + +const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = next; node; node = node->next ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = prev; node; node = node->prev ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +void TiXmlElement::RemoveAttribute( const char * name ) +{ + #ifdef TIXML_USE_STL + TIXML_STRING str( name ); + TiXmlAttribute* node = attributeSet.Find( str ); + #else + TiXmlAttribute* node = attributeSet.Find( name ); + #endif + if ( node ) + { + attributeSet.Remove( node ); + delete node; + } +} + +const TiXmlElement* TiXmlNode::FirstChildElement() const +{ + const TiXmlNode* node; + + for ( node = FirstChild(); + node; + node = node->NextSibling() ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const +{ + const TiXmlNode* node; + + for ( node = FirstChild( _value ); + node; + node = node->NextSibling( _value ) ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlElement* TiXmlNode::NextSiblingElement() const +{ + const TiXmlNode* node; + + for ( node = NextSibling(); + node; + node = node->NextSibling() ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const +{ + const TiXmlNode* node; + + for ( node = NextSibling( _value ); + node; + node = node->NextSibling( _value ) ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlDocument* TiXmlNode::GetDocument() const +{ + const TiXmlNode* node; + + for( node = this; node; node = node->parent ) + { + if ( node->ToDocument() ) + return node->ToDocument(); + } + return 0; +} + + +TiXmlElement::TiXmlElement (const char * _value) + : TiXmlNode( TiXmlNode::ELEMENT ) +{ + firstChild = lastChild = 0; + value = _value; +} + + +#ifdef TIXML_USE_STL +TiXmlElement::TiXmlElement( const std::string& _value ) + : TiXmlNode( TiXmlNode::ELEMENT ) +{ + firstChild = lastChild = 0; + value = _value; +} +#endif + + +TiXmlElement::TiXmlElement( const TiXmlElement& copy) + : TiXmlNode( TiXmlNode::ELEMENT ) +{ + firstChild = lastChild = 0; + copy.CopyTo( this ); +} + + +void TiXmlElement::operator=( const TiXmlElement& base ) +{ + ClearThis(); + base.CopyTo( this ); +} + + +TiXmlElement::~TiXmlElement() +{ + ClearThis(); +} + + +void TiXmlElement::ClearThis() +{ + Clear(); + while( attributeSet.First() ) + { + TiXmlAttribute* node = attributeSet.First(); + attributeSet.Remove( node ); + delete node; + } +} + + +const char* TiXmlElement::Attribute( const char* name ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( node ) + return node->Value(); + return 0; +} + + +#ifdef TIXML_USE_STL +const std::string* TiXmlElement::Attribute( const std::string& name ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( node ) + return &node->ValueStr(); + return 0; +} +#endif + + +const char* TiXmlElement::Attribute( const char* name, int* i ) const +{ + const char* s = Attribute( name ); + if ( i ) + { + if ( s ) { + *i = atoi( s ); + } + else { + *i = 0; + } + } + return s; +} + + +#ifdef TIXML_USE_STL +const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const +{ + const std::string* s = Attribute( name ); + if ( i ) + { + if ( s ) { + *i = atoi( s->c_str() ); + } + else { + *i = 0; + } + } + return s; +} +#endif + + +const char* TiXmlElement::Attribute( const char* name, double* d ) const +{ + const char* s = Attribute( name ); + if ( d ) + { + if ( s ) { + *d = atof( s ); + } + else { + *d = 0; + } + } + return s; +} + + +#ifdef TIXML_USE_STL +const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const +{ + const std::string* s = Attribute( name ); + if ( d ) + { + if ( s ) { + *d = atof( s->c_str() ); + } + else { + *d = 0; + } + } + return s; +} +#endif + + +int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + return node->QueryIntValue( ival ); +} + + +#ifdef TIXML_USE_STL +int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + return node->QueryIntValue( ival ); +} +#endif + + +int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + return node->QueryDoubleValue( dval ); +} + + +#ifdef TIXML_USE_STL +int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + return node->QueryDoubleValue( dval ); +} +#endif + + +void TiXmlElement::SetAttribute( const char * name, int val ) +{ + char buf[64]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "%d", val ); + #else + sprintf( buf, "%d", val ); + #endif + SetAttribute( name, buf ); +} + + +#ifdef TIXML_USE_STL +void TiXmlElement::SetAttribute( const std::string& name, int val ) +{ + std::ostringstream oss; + oss << val; + SetAttribute( name, oss.str() ); +} +#endif + + +void TiXmlElement::SetDoubleAttribute( const char * name, double val ) +{ + char buf[256]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "%f", val ); + #else + sprintf( buf, "%f", val ); + #endif + SetAttribute( name, buf ); +} + + +void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) +{ + #ifdef TIXML_USE_STL + TIXML_STRING _name( cname ); + TIXML_STRING _value( cvalue ); + #else + const char* _name = cname; + const char* _value = cvalue; + #endif + + TiXmlAttribute* node = attributeSet.Find( _name ); + if ( node ) + { + node->SetValue( _value ); + return; + } + + TiXmlAttribute* attrib = new TiXmlAttribute( cname, cvalue ); + if ( attrib ) + { + attributeSet.Add( attrib ); + } + else + { + TiXmlDocument* document = GetDocument(); + if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); + } +} + + +#ifdef TIXML_USE_STL +void TiXmlElement::SetAttribute( const std::string& name, const std::string& _value ) +{ + TiXmlAttribute* node = attributeSet.Find( name ); + if ( node ) + { + node->SetValue( _value ); + return; + } + + TiXmlAttribute* attrib = new TiXmlAttribute( name, _value ); + if ( attrib ) + { + attributeSet.Add( attrib ); + } + else + { + TiXmlDocument* document = GetDocument(); + if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); + } +} +#endif + + +void TiXmlElement::Print( FILE* cfile, int depth ) const +{ + int i; + assert( cfile ); + for ( i=0; iNext() ) + { + fprintf( cfile, " " ); + attrib->Print( cfile, depth ); + } + + // There are 3 different formatting approaches: + // 1) An element without children is printed as a node + // 2) An element with only a text child is printed as text + // 3) An element with children is printed on multiple lines. + TiXmlNode* node; + if ( !firstChild ) + { + fprintf( cfile, " />" ); + } + else if ( firstChild == lastChild && firstChild->ToText() ) + { + fprintf( cfile, ">" ); + firstChild->Print( cfile, depth + 1 ); + fprintf( cfile, "", value.c_str() ); + } + else + { + fprintf( cfile, ">" ); + + for ( node = firstChild; node; node=node->NextSibling() ) + { + if ( !node->ToText() ) + { + fprintf( cfile, "\n" ); + } + node->Print( cfile, depth+1 ); + } + fprintf( cfile, "\n" ); + for( i=0; i", value.c_str() ); + } +} + + +void TiXmlElement::CopyTo( TiXmlElement* target ) const +{ + // superclass: + TiXmlNode::CopyTo( target ); + + // Element class: + // Clone the attributes, then clone the children. + const TiXmlAttribute* attribute = 0; + for( attribute = attributeSet.First(); + attribute; + attribute = attribute->Next() ) + { + target->SetAttribute( attribute->Name(), attribute->Value() ); + } + + TiXmlNode* node = 0; + for ( node = firstChild; node; node = node->NextSibling() ) + { + target->LinkEndChild( node->Clone() ); + } +} + +bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const +{ + if ( visitor->VisitEnter( *this, attributeSet.First() ) ) + { + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + if ( !node->Accept( visitor ) ) + break; + } + } + return visitor->VisitExit( *this ); +} + + +TiXmlNode* TiXmlElement::Clone() const +{ + TiXmlElement* clone = new TiXmlElement( Value() ); + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +const char* TiXmlElement::GetText() const +{ + const TiXmlNode* child = this->FirstChild(); + if ( child ) { + const TiXmlText* childText = child->ToText(); + if ( childText ) { + return childText->Value(); + } + } + return 0; +} + + +TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + tabsize = 4; + useMicrosoftBOM = false; + ClearError(); +} + +TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + tabsize = 4; + useMicrosoftBOM = false; + value = documentName; + ClearError(); +} + + +#ifdef TIXML_USE_STL +TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + tabsize = 4; + useMicrosoftBOM = false; + value = documentName; + ClearError(); +} +#endif + + +TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + copy.CopyTo( this ); +} + + +void TiXmlDocument::operator=( const TiXmlDocument& copy ) +{ + Clear(); + copy.CopyTo( this ); +} + + +bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) +{ + // See STL_STRING_BUG below. + //StringToBuffer buf( value ); + + return LoadFile( Value(), encoding ); +} + + +bool TiXmlDocument::SaveFile() const +{ + // See STL_STRING_BUG below. +// StringToBuffer buf( value ); +// +// if ( buf.buffer && SaveFile( buf.buffer ) ) +// return true; +// +// return false; + return SaveFile( Value() ); +} + +bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) +{ + // There was a really terrifying little bug here. The code: + // value = filename + // in the STL case, cause the assignment method of the std::string to + // be called. What is strange, is that the std::string had the same + // address as it's c_str() method, and so bad things happen. Looks + // like a bug in the Microsoft STL implementation. + // Add an extra string to avoid the crash. + TIXML_STRING filename( _filename ); + value = filename; + + // reading in binary mode so that tinyxml can normalize the EOL + FILE* file = fopen( value.c_str (), "rb" ); + + if ( file ) + { + bool result = LoadFile( file, encoding ); + fclose( file ); + return result; + } + else + { + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } +} + +bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) +{ + if ( !file ) + { + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + // Delete the existing data: + Clear(); + location.Clear(); + + // Get the file size, so we can pre-allocate the string. HUGE speed impact. + long length = 0; + fseek( file, 0, SEEK_END ); + length = ftell( file ); + fseek( file, 0, SEEK_SET ); + + // Strange case, but good to handle up front. + if ( length == 0 ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + // If we have a file, assume it is all one big XML file, and read it in. + // The document parser may decide the document ends sooner than the entire file, however. + TIXML_STRING data; + data.reserve( length ); + + // Subtle bug here. TinyXml did use fgets. But from the XML spec: + // 2.11 End-of-Line Handling + // + // + // ...the XML processor MUST behave as if it normalized all line breaks in external + // parsed entities (including the document entity) on input, before parsing, by translating + // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to + // a single #xA character. + // + // + // It is not clear fgets does that, and certainly isn't clear it works cross platform. + // Generally, you expect fgets to translate from the convention of the OS to the c/unix + // convention, and not work generally. + + /* + while( fgets( buf, sizeof(buf), file ) ) + { + data += buf; + } + */ + + char* buf = new char[ length+1 ]; + buf[0] = 0; + + if ( fread( buf, length, 1, file ) != 1 ) { + delete [] buf; + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + const char* lastPos = buf; + const char* p = buf; + + buf[length] = 0; + while( *p ) { + assert( p < (buf+length) ); + if ( *p == 0xa ) { + // Newline character. No special rules for this. Append all the characters + // since the last string, and include the newline. + data.append( lastPos, (p-lastPos+1) ); // append, include the newline + ++p; // move past the newline + lastPos = p; // and point to the new buffer (may be 0) + assert( p <= (buf+length) ); + } + else if ( *p == 0xd ) { + // Carriage return. Append what we have so far, then + // handle moving forward in the buffer. + if ( (p-lastPos) > 0 ) { + data.append( lastPos, p-lastPos ); // do not add the CR + } + data += (char)0xa; // a proper newline + + if ( *(p+1) == 0xa ) { + // Carriage return - new line sequence + p += 2; + lastPos = p; + assert( p <= (buf+length) ); + } + else { + // it was followed by something else...that is presumably characters again. + ++p; + lastPos = p; + assert( p <= (buf+length) ); + } + } + else { + ++p; + } + } + // Handle any left over characters. + if ( p-lastPos ) { + data.append( lastPos, p-lastPos ); + } + delete [] buf; + buf = 0; + + Parse( data.c_str(), 0, encoding ); + + if ( Error() ) + return false; + else + return true; +} + + +bool TiXmlDocument::SaveFile( const char * filename ) const +{ + // The old c stuff lives on... + FILE* fp = fopen( filename, "w" ); + if ( fp ) + { + bool result = SaveFile( fp ); + fclose( fp ); + return result; + } + return false; +} + + +bool TiXmlDocument::SaveFile( FILE* fp ) const +{ + if ( useMicrosoftBOM ) + { + const unsigned char TIXML_UTF_LEAD_0 = 0xefU; + const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; + const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + + fputc( TIXML_UTF_LEAD_0, fp ); + fputc( TIXML_UTF_LEAD_1, fp ); + fputc( TIXML_UTF_LEAD_2, fp ); + } + Print( fp, 0 ); + return (ferror(fp) == 0); +} + + +void TiXmlDocument::CopyTo( TiXmlDocument* target ) const +{ + TiXmlNode::CopyTo( target ); + + target->error = error; + target->errorDesc = errorDesc.c_str (); + + TiXmlNode* node = 0; + for ( node = firstChild; node; node = node->NextSibling() ) + { + target->LinkEndChild( node->Clone() ); + } +} + + +TiXmlNode* TiXmlDocument::Clone() const +{ + TiXmlDocument* clone = new TiXmlDocument(); + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlDocument::Print( FILE* cfile, int depth ) const +{ + assert( cfile ); + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + node->Print( cfile, depth ); + fprintf( cfile, "\n" ); + } +} + + +bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const +{ + if ( visitor->VisitEnter( *this ) ) + { + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + if ( !node->Accept( visitor ) ) + break; + } + } + return visitor->VisitExit( *this ); +} + + +const TiXmlAttribute* TiXmlAttribute::Next() const +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( next->value.empty() && next->name.empty() ) + return 0; + return next; +} + +/* +TiXmlAttribute* TiXmlAttribute::Next() +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( next->value.empty() && next->name.empty() ) + return 0; + return next; +} +*/ + +const TiXmlAttribute* TiXmlAttribute::Previous() const +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( prev->value.empty() && prev->name.empty() ) + return 0; + return prev; +} + +/* +TiXmlAttribute* TiXmlAttribute::Previous() +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( prev->value.empty() && prev->name.empty() ) + return 0; + return prev; +} +*/ + +void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const +{ + TIXML_STRING n, v; + + PutString( name, &n ); + PutString( value, &v ); + + if (value.find ('\"') == TIXML_STRING::npos) { + if ( cfile ) { + fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); + } + if ( str ) { + (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; + } + } + else { + if ( cfile ) { + fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); + } + if ( str ) { + (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; + } + } +} + + +int TiXmlAttribute::QueryIntValue( int* ival ) const +{ + if ( sscanf( value.c_str(), "%d", ival ) == 1 ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; +} + +int TiXmlAttribute::QueryDoubleValue( double* dval ) const +{ + if ( sscanf( value.c_str(), "%lf", dval ) == 1 ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; +} + +void TiXmlAttribute::SetIntValue( int _value ) +{ + char buf [64]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); + #else + sprintf (buf, "%d", _value); + #endif + SetValue (buf); +} + +void TiXmlAttribute::SetDoubleValue( double _value ) +{ + char buf [256]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "%lf", _value); + #else + sprintf (buf, "%lf", _value); + #endif + SetValue (buf); +} + +int TiXmlAttribute::IntValue() const +{ + return atoi (value.c_str ()); +} + +double TiXmlAttribute::DoubleValue() const +{ + return atof (value.c_str ()); +} + + +TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT ) +{ + copy.CopyTo( this ); +} + + +void TiXmlComment::operator=( const TiXmlComment& base ) +{ + Clear(); + base.CopyTo( this ); +} + + +void TiXmlComment::Print( FILE* cfile, int depth ) const +{ + assert( cfile ); + for ( int i=0; i", value.c_str() ); +} + + +void TiXmlComment::CopyTo( TiXmlComment* target ) const +{ + TiXmlNode::CopyTo( target ); +} + + +bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlComment::Clone() const +{ + TiXmlComment* clone = new TiXmlComment(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlText::Print( FILE* cfile, int depth ) const +{ + assert( cfile ); + if ( cdata ) + { + int i; + fprintf( cfile, "\n" ); + for ( i=0; i\n", value.c_str() ); // unformatted output + } + else + { + TIXML_STRING buffer; + PutString( value, &buffer ); + fprintf( cfile, "%s", buffer.c_str() ); + } +} + + +void TiXmlText::CopyTo( TiXmlText* target ) const +{ + TiXmlNode::CopyTo( target ); + target->cdata = cdata; +} + + +bool TiXmlText::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlText::Clone() const +{ + TiXmlText* clone = 0; + clone = new TiXmlText( "" ); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +TiXmlDeclaration::TiXmlDeclaration( const char * _version, + const char * _encoding, + const char * _standalone ) + : TiXmlNode( TiXmlNode::DECLARATION ) +{ + version = _version; + encoding = _encoding; + standalone = _standalone; +} + + +#ifdef TIXML_USE_STL +TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, + const std::string& _encoding, + const std::string& _standalone ) + : TiXmlNode( TiXmlNode::DECLARATION ) +{ + version = _version; + encoding = _encoding; + standalone = _standalone; +} +#endif + + +TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) + : TiXmlNode( TiXmlNode::DECLARATION ) +{ + copy.CopyTo( this ); +} + + +void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) +{ + Clear(); + copy.CopyTo( this ); +} + + +void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const +{ + if ( cfile ) fprintf( cfile, "" ); + if ( str ) (*str) += "?>"; +} + + +void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const +{ + TiXmlNode::CopyTo( target ); + + target->version = version; + target->encoding = encoding; + target->standalone = standalone; +} + + +bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlDeclaration::Clone() const +{ + TiXmlDeclaration* clone = new TiXmlDeclaration(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlUnknown::Print( FILE* cfile, int depth ) const +{ + for ( int i=0; i", value.c_str() ); +} + + +void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const +{ + TiXmlNode::CopyTo( target ); +} + + +bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlUnknown::Clone() const +{ + TiXmlUnknown* clone = new TiXmlUnknown(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +TiXmlAttributeSet::TiXmlAttributeSet() +{ + sentinel.next = &sentinel; + sentinel.prev = &sentinel; +} + + +TiXmlAttributeSet::~TiXmlAttributeSet() +{ + assert( sentinel.next == &sentinel ); + assert( sentinel.prev == &sentinel ); +} + + +void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) +{ + #ifdef TIXML_USE_STL + assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set. + #else + assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. + #endif + + addMe->next = &sentinel; + addMe->prev = sentinel.prev; + + sentinel.prev->next = addMe; + sentinel.prev = addMe; +} + +void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) +{ + TiXmlAttribute* node; + + for( node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node == removeMe ) + { + node->prev->next = node->next; + node->next->prev = node->prev; + node->next = 0; + node->prev = 0; + return; + } + } + assert( 0 ); // we tried to remove a non-linked attribute. +} + + +#ifdef TIXML_USE_STL +const TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const +{ + for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node->name == name ) + return node; + } + return 0; +} + +/* +TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) +{ + for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node->name == name ) + return node; + } + return 0; +} +*/ +#endif + + +const TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const +{ + for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( strcmp( node->name.c_str(), name ) == 0 ) + return node; + } + return 0; +} + +/* +TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) +{ + for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( strcmp( node->name.c_str(), name ) == 0 ) + return node; + } + return 0; +} +*/ + +#ifdef TIXML_USE_STL +std::istream& operator>> (std::istream & in, TiXmlNode & base) +{ + TIXML_STRING tag; + tag.reserve( 8 * 1000 ); + base.StreamIn( &in, &tag ); + + base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); + return in; +} +#endif + + +#ifdef TIXML_USE_STL +std::ostream& operator<< (std::ostream & out, const TiXmlNode & base) +{ + TiXmlPrinter printer; + printer.SetStreamPrinting(); + base.Accept( &printer ); + out << printer.Str(); + + return out; +} + + +std::string& operator<< (std::string& out, const TiXmlNode& base ) +{ + TiXmlPrinter printer; + printer.SetStreamPrinting(); + base.Accept( &printer ); + out.append( printer.Str() ); + + return out; +} +#endif + + +TiXmlHandle TiXmlHandle::FirstChild() const +{ + if ( node ) + { + TiXmlNode* child = node->FirstChild(); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const +{ + if ( node ) + { + TiXmlNode* child = node->FirstChild( value ); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChildElement() const +{ + if ( node ) + { + TiXmlElement* child = node->FirstChildElement(); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const +{ + if ( node ) + { + TiXmlElement* child = node->FirstChildElement( value ); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::Child( int count ) const +{ + if ( node ) + { + int i; + TiXmlNode* child = node->FirstChild(); + for ( i=0; + child && iNextSibling(), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const +{ + if ( node ) + { + int i; + TiXmlNode* child = node->FirstChild( value ); + for ( i=0; + child && iNextSibling( value ), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::ChildElement( int count ) const +{ + if ( node ) + { + int i; + TiXmlElement* child = node->FirstChildElement(); + for ( i=0; + child && iNextSiblingElement(), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const +{ + if ( node ) + { + int i; + TiXmlElement* child = node->FirstChildElement( value ); + for ( i=0; + child && iNextSiblingElement( value ), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +bool TiXmlPrinter::VisitEnter( const TiXmlDocument& ) +{ + return true; +} + +bool TiXmlPrinter::VisitExit( const TiXmlDocument& ) +{ + return true; +} + +bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) +{ + DoIndent(); + buffer += "<"; + buffer += element.Value(); + + for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() ) + { + buffer += " "; + attrib->Print( 0, 0, &buffer ); + } + + if ( !element.FirstChild() ) + { + buffer += " />"; + DoLineBreak(); + } + else + { + buffer += ">"; + if ( element.FirstChild()->ToText() + && element.LastChild() == element.FirstChild() + && element.FirstChild()->ToText()->CDATA() == false ) + { + simpleTextPrint = true; + // no DoLineBreak()! + } + else + { + DoLineBreak(); + } + } + ++depth; + return true; +} + + +bool TiXmlPrinter::VisitExit( const TiXmlElement& element ) +{ + --depth; + if ( !element.FirstChild() ) + { + // nothing. + } + else + { + if ( simpleTextPrint ) + { + simpleTextPrint = false; + } + else + { + DoIndent(); + } + buffer += ""; + DoLineBreak(); + } + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlText& text ) +{ + if ( text.CDATA() ) + { + DoIndent(); + buffer += ""; + DoLineBreak(); + } + else if ( simpleTextPrint ) + { + buffer += text.Value(); + } + else + { + DoIndent(); + buffer += text.Value(); + DoLineBreak(); + } + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration ) +{ + DoIndent(); + declaration.Print( 0, 0, &buffer ); + DoLineBreak(); + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlComment& comment ) +{ + DoIndent(); + buffer += ""; + DoLineBreak(); + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown ) +{ + DoIndent(); + buffer += "<"; + buffer += unknown.Value(); + buffer += ">"; + DoLineBreak(); + return true; +} + diff --git a/pcsx2/tinyxml/tinyxml.h b/pcsx2/tinyxml/tinyxml.h index d5df66864b..5391236e68 100644 --- a/pcsx2/tinyxml/tinyxml.h +++ b/pcsx2/tinyxml/tinyxml.h @@ -1,1776 +1,1776 @@ -/* -www.sourceforge.net/projects/tinyxml -Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - - -#ifndef TINYXML_INCLUDED -#define TINYXML_INCLUDED - -#ifdef _MSC_VER -#pragma warning( push ) -#pragma warning( disable : 4530 ) -#pragma warning( disable : 4786 ) -#endif - -#include -#include -#include -#include -#include - -// Help out windows: -#if defined( _DEBUG ) && !defined( DEBUG ) -#define DEBUG -#endif - -#ifdef TIXML_USE_STL - #include - #include - #include - #define TIXML_STRING std::string -#else - #include "tinystr.h" - #define TIXML_STRING TiXmlString -#endif - -// Deprecated library function hell. Compilers want to use the -// new safe versions. This probably doesn't fully address the problem, -// but it gets closer. There are too many compilers for me to fully -// test. If you get compilation troubles, undefine TIXML_SAFE -#define TIXML_SAFE - -#ifdef TIXML_SAFE - #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) - // Microsoft visual studio, version 2005 and higher. - #define TIXML_SNPRINTF _snprintf_s - #define TIXML_SNSCANF _snscanf_s - #elif defined(_MSC_VER) && (_MSC_VER >= 1200 ) - // Microsoft visual studio, version 6 and higher. - //#pragma message( "Using _sn* functions." ) - #define TIXML_SNPRINTF _snprintf - #define TIXML_SNSCANF _snscanf - #elif defined(__GNUC__) && (__GNUC__ >= 3 ) - // GCC version 3 and higher.s - //#warning( "Using sn* functions." ) - #define TIXML_SNPRINTF snprintf - #define TIXML_SNSCANF snscanf - #endif -#endif - -class TiXmlDocument; -class TiXmlElement; -class TiXmlComment; -class TiXmlUnknown; -class TiXmlAttribute; -class TiXmlText; -class TiXmlDeclaration; -class TiXmlParsingData; - -const int TIXML_MAJOR_VERSION = 2; -const int TIXML_MINOR_VERSION = 5; -const int TIXML_PATCH_VERSION = 2; - -/* Internal structure for tracking location of items - in the XML file. -*/ -struct TiXmlCursor -{ - TiXmlCursor() { Clear(); } - void Clear() { row = col = -1; } - - int row; // 0 based. - int col; // 0 based. -}; - - -/** - If you call the Accept() method, it requires being passed a TiXmlVisitor - class to handle callbacks. For nodes that contain other nodes (Document, Element) - you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves - are simple called with Visit(). - - If you return 'true' from a Visit method, recursive parsing will continue. If you return - false, no children of this node or its sibilings will be Visited. - - All flavors of Visit methods have a default implementation that returns 'true' (continue - visiting). You need to only override methods that are interesting to you. - - Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting. - - You should never change the document from a callback. - - @sa TiXmlNode::Accept() -*/ -class TiXmlVisitor -{ -public: - virtual ~TiXmlVisitor() {} - - /// Visit a document. - virtual bool VisitEnter( const TiXmlDocument& doc ) { return true; } - /// Visit a document. - virtual bool VisitExit( const TiXmlDocument& doc ) { return true; } - - /// Visit an element. - virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) { return true; } - /// Visit an element. - virtual bool VisitExit( const TiXmlElement& element ) { return true; } - - /// Visit a declaration - virtual bool Visit( const TiXmlDeclaration& declaration ) { return true; } - /// Visit a text node - virtual bool Visit( const TiXmlText& text ) { return true; } - /// Visit a comment node - virtual bool Visit( const TiXmlComment& comment ) { return true; } - /// Visit an unknow node - virtual bool Visit( const TiXmlUnknown& unknown ) { return true; } -}; - -// Only used by Attribute::Query functions -enum -{ - TIXML_SUCCESS, - TIXML_NO_ATTRIBUTE, - TIXML_WRONG_TYPE -}; - - -// Used by the parsing routines. -enum TiXmlEncoding -{ - TIXML_ENCODING_UNKNOWN, - TIXML_ENCODING_UTF8, - TIXML_ENCODING_LEGACY -}; - -const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; - -/** TiXmlBase is a base class for every class in TinyXml. - It does little except to establish that TinyXml classes - can be printed and provide some utility functions. - - In XML, the document and elements can contain - other elements and other types of nodes. - - @verbatim - A Document can contain: Element (container or leaf) - Comment (leaf) - Unknown (leaf) - Declaration( leaf ) - - An Element can contain: Element (container or leaf) - Text (leaf) - Attributes (not on tree) - Comment (leaf) - Unknown (leaf) - - A Decleration contains: Attributes (not on tree) - @endverbatim -*/ -class TiXmlBase -{ - friend class TiXmlNode; - friend class TiXmlElement; - friend class TiXmlDocument; - -public: - TiXmlBase() : userData(0) {} - virtual ~TiXmlBase() {} - - /** All TinyXml classes can print themselves to a filestream - or the string class (TiXmlString in non-STL mode, std::string - in STL mode.) Either or both cfile and str can be null. - - This is a formatted print, and will insert - tabs and newlines. - - (For an unformatted stream, use the << operator.) - */ - virtual void Print( FILE* cfile, int depth ) const = 0; - - /** The world does not agree on whether white space should be kept or - not. In order to make everyone happy, these global, static functions - are provided to set whether or not TinyXml will condense all white space - into a single space or not. The default is to condense. Note changing this - value is not thread safe. - */ - static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } - - /// Return the current white space setting. - static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } - - /** Return the position, in the original source file, of this node or attribute. - The row and column are 1-based. (That is the first row and first column is - 1,1). If the returns values are 0 or less, then the parser does not have - a row and column value. - - Generally, the row and column value will be set when the TiXmlDocument::Load(), - TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set - when the DOM was created from operator>>. - - The values reflect the initial load. Once the DOM is modified programmatically - (by adding or changing nodes and attributes) the new values will NOT update to - reflect changes in the document. - - There is a minor performance cost to computing the row and column. Computation - can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. - - @sa TiXmlDocument::SetTabSize() - */ - int Row() const { return location.row + 1; } - int Column() const { return location.col + 1; } ///< See Row() - - void SetUserData( void* user ) { userData = user; } ///< Set a pointer to arbitrary user data. - void* GetUserData() { return userData; } ///< Get a pointer to arbitrary user data. - const void* GetUserData() const { return userData; } ///< Get a pointer to arbitrary user data. - - // Table that returs, for a given lead byte, the total number of bytes - // in the UTF-8 sequence. - static const int utf8ByteTable[256]; - - virtual const char* Parse( const char* p, - TiXmlParsingData* data, - TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; - - enum - { - TIXML_NO_ERROR = 0, - TIXML_ERROR, - TIXML_ERROR_OPENING_FILE, - TIXML_ERROR_OUT_OF_MEMORY, - TIXML_ERROR_PARSING_ELEMENT, - TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, - TIXML_ERROR_READING_ELEMENT_VALUE, - TIXML_ERROR_READING_ATTRIBUTES, - TIXML_ERROR_PARSING_EMPTY, - TIXML_ERROR_READING_END_TAG, - TIXML_ERROR_PARSING_UNKNOWN, - TIXML_ERROR_PARSING_COMMENT, - TIXML_ERROR_PARSING_DECLARATION, - TIXML_ERROR_DOCUMENT_EMPTY, - TIXML_ERROR_EMBEDDED_NULL, - TIXML_ERROR_PARSING_CDATA, - TIXML_ERROR_DOCUMENT_TOP_ONLY, - - TIXML_ERROR_STRING_COUNT - }; - -protected: - - static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); - inline static bool IsWhiteSpace( char c ) - { - return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); - } - inline static bool IsWhiteSpace( int c ) - { - if ( c < 256 ) - return IsWhiteSpace( (char) c ); - return false; // Again, only truly correct for English/Latin...but usually works. - } - - #ifdef TIXML_USE_STL - static bool StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ); - static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag ); - #endif - - /* Reads an XML name into the string provided. Returns - a pointer just past the last character of the name, - or 0 if the function has an error. - */ - static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); - - /* Reads text. Returns a pointer past the given end tag. - Wickedly complex options, but it keeps the (sensitive) code in one place. - */ - static const char* ReadText( const char* in, // where to start - TIXML_STRING* text, // the string read - bool ignoreWhiteSpace, // whether to keep the white space - const char* endTag, // what ends this text - bool ignoreCase, // whether to ignore case in the end tag - TiXmlEncoding encoding ); // the current encoding - - // If an entity has been found, transform it into a character. - static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); - - // Get a character, while interpreting entities. - // The length can be from 0 to 4 bytes. - inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) - { - assert( p ); - if ( encoding == TIXML_ENCODING_UTF8 ) - { - *length = utf8ByteTable[ *((const unsigned char*)p) ]; - assert( *length >= 0 && *length < 5 ); - } - else - { - *length = 1; - } - - if ( *length == 1 ) - { - if ( *p == '&' ) - return GetEntity( p, _value, length, encoding ); - *_value = *p; - return p+1; - } - else if ( *length ) - { - //strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe), - // and the null terminator isn't needed - for( int i=0; p[i] && i<*length; ++i ) { - _value[i] = p[i]; - } - return p + (*length); - } - else - { - // Not valid text. - return 0; - } - } - - // Puts a string to a stream, expanding entities as it goes. - // Note this should not contian the '<', '>', etc, or they will be transformed into entities! - static void PutString( const TIXML_STRING& str, TIXML_STRING* out ); - - // Return true if the next characters in the stream are any of the endTag sequences. - // Ignore case only works for english, and should only be relied on when comparing - // to English words: StringEqual( p, "version", true ) is fine. - static bool StringEqual( const char* p, - const char* endTag, - bool ignoreCase, - TiXmlEncoding encoding ); - - static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; - - TiXmlCursor location; - - /// Field containing a generic user pointer - void* userData; - - // None of these methods are reliable for any language except English. - // Good for approximation, not great for accuracy. - static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); - static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); - inline static int ToLower( int v, TiXmlEncoding encoding ) - { - if ( encoding == TIXML_ENCODING_UTF8 ) - { - if ( v < 128 ) return tolower( v ); - return v; - } - else - { - return tolower( v ); - } - } - static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); - -private: - TiXmlBase( const TiXmlBase& ); // not implemented. - void operator=( const TiXmlBase& base ); // not allowed. - - struct Entity - { - const char* str; - unsigned int strLength; - char chr; - }; - enum - { - NUM_ENTITY = 5, - MAX_ENTITY_LENGTH = 6 - - }; - static Entity entity[ NUM_ENTITY ]; - static bool condenseWhiteSpace; -}; - - -/** The parent class for everything in the Document Object Model. - (Except for attributes). - Nodes have siblings, a parent, and children. A node can be - in a document, or stand on its own. The type of a TiXmlNode - can be queried, and it can be cast to its more defined type. -*/ -class TiXmlNode : public TiXmlBase -{ - friend class TiXmlDocument; - friend class TiXmlElement; - -public: - #ifdef TIXML_USE_STL - - /** An input stream operator, for every class. Tolerant of newlines and - formatting, but doesn't expect them. - */ - friend std::istream& operator >> (std::istream& in, TiXmlNode& base); - - /** An output stream operator, for every class. Note that this outputs - without any newlines or formatting, as opposed to Print(), which - includes tabs and new lines. - - The operator<< and operator>> are not completely symmetric. Writing - a node to a stream is very well defined. You'll get a nice stream - of output, without any extra whitespace or newlines. - - But reading is not as well defined. (As it always is.) If you create - a TiXmlElement (for example) and read that from an input stream, - the text needs to define an element or junk will result. This is - true of all input streams, but it's worth keeping in mind. - - A TiXmlDocument will read nodes until it reads a root element, and - all the children of that root element. - */ - friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); - - /// Appends the XML node or attribute to a std::string. - friend std::string& operator<< (std::string& out, const TiXmlNode& base ); - - #endif - - /** The types of XML nodes supported by TinyXml. (All the - unsupported types are picked up by UNKNOWN.) - */ - enum NodeType - { - DOCUMENT, - ELEMENT, - COMMENT, - UNKNOWN, - TEXT, - DECLARATION, - TYPECOUNT - }; - - virtual ~TiXmlNode(); - - /** The meaning of 'value' changes for the specific type of - TiXmlNode. - @verbatim - Document: filename of the xml file - Element: name of the element - Comment: the comment text - Unknown: the tag contents - Text: the text string - @endverbatim - - The subclasses will wrap this function. - */ - const char *Value() const { return value.c_str (); } - - #ifdef TIXML_USE_STL - /** Return Value() as a std::string. If you only use STL, - this is more efficient than calling Value(). - Only available in STL mode. - */ - const std::string& ValueStr() const { return value; } - #endif - - /** Changes the value of the node. Defined as: - @verbatim - Document: filename of the xml file - Element: name of the element - Comment: the comment text - Unknown: the tag contents - Text: the text string - @endverbatim - */ - void SetValue(const char * _value) { value = _value;} - - #ifdef TIXML_USE_STL - /// STL std::string form. - void SetValue( const std::string& _value ) { value = _value; } - #endif - - /// Delete all the children of this node. Does not affect 'this'. - void Clear(); - - /// One step up the DOM. - TiXmlNode* Parent() { return parent; } - const TiXmlNode* Parent() const { return parent; } - - const TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. - TiXmlNode* FirstChild() { return firstChild; } - const TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. - /// The first child of this node with the matching 'value'. Will be null if none found. - TiXmlNode* FirstChild( const char * _value ) { - // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe) - // call the method, cast the return back to non-const. - return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value )); - } - const TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. - TiXmlNode* LastChild() { return lastChild; } - - const TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. - TiXmlNode* LastChild( const char * _value ) { - return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value )); - } - - #ifdef TIXML_USE_STL - const TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. - TiXmlNode* FirstChild( const std::string& _value ) { return FirstChild (_value.c_str ()); } ///< STL std::string form. - const TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. - TiXmlNode* LastChild( const std::string& _value ) { return LastChild (_value.c_str ()); } ///< STL std::string form. - #endif - - /** An alternate way to walk the children of a node. - One way to iterate over nodes is: - @verbatim - for( child = parent->FirstChild(); child; child = child->NextSibling() ) - @endverbatim - - IterateChildren does the same thing with the syntax: - @verbatim - child = 0; - while( child = parent->IterateChildren( child ) ) - @endverbatim - - IterateChildren takes the previous child as input and finds - the next one. If the previous child is null, it returns the - first. IterateChildren will return null when done. - */ - const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const; - TiXmlNode* IterateChildren( const TiXmlNode* previous ) { - return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) ); - } - - /// This flavor of IterateChildren searches for children with a particular 'value' - const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const; - TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) { - return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) ); - } - - #ifdef TIXML_USE_STL - const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. - TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. - #endif - - /** Add a new node related to this. Adds a child past the LastChild. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); - - - /** Add a new node related to this. Adds a child past the LastChild. - - NOTE: the node to be added is passed by pointer, and will be - henceforth owned (and deleted) by tinyXml. This method is efficient - and avoids an extra copy, but should be used with care as it - uses a different memory model than the other insert functions. - - @sa InsertEndChild - */ - TiXmlNode* LinkEndChild( TiXmlNode* addThis ); - - /** Add a new node related to this. Adds a child before the specified child. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); - - /** Add a new node related to this. Adds a child after the specified child. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); - - /** Replace a child of this node. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); - - /// Delete a child of this node. - bool RemoveChild( TiXmlNode* removeThis ); - - /// Navigate to a sibling node. - const TiXmlNode* PreviousSibling() const { return prev; } - TiXmlNode* PreviousSibling() { return prev; } - - /// Navigate to a sibling node. - const TiXmlNode* PreviousSibling( const char * ) const; - TiXmlNode* PreviousSibling( const char *_prev ) { - return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) ); - } - - #ifdef TIXML_USE_STL - const TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. - TiXmlNode* PreviousSibling( const std::string& _value ) { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. - const TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. - TiXmlNode* NextSibling( const std::string& _value) { return NextSibling (_value.c_str ()); } ///< STL std::string form. - #endif - - /// Navigate to a sibling node. - const TiXmlNode* NextSibling() const { return next; } - TiXmlNode* NextSibling() { return next; } - - /// Navigate to a sibling node with the given 'value'. - const TiXmlNode* NextSibling( const char * ) const; - TiXmlNode* NextSibling( const char* _next ) { - return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) ); - } - - /** Convenience function to get through elements. - Calls NextSibling and ToElement. Will skip all non-Element - nodes. Returns 0 if there is not another element. - */ - const TiXmlElement* NextSiblingElement() const; - TiXmlElement* NextSiblingElement() { - return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() ); - } - - /** Convenience function to get through elements. - Calls NextSibling and ToElement. Will skip all non-Element - nodes. Returns 0 if there is not another element. - */ - const TiXmlElement* NextSiblingElement( const char * ) const; - TiXmlElement* NextSiblingElement( const char *_next ) { - return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) ); - } - - #ifdef TIXML_USE_STL - const TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. - TiXmlElement* NextSiblingElement( const std::string& _value) { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. - #endif - - /// Convenience function to get through elements. - const TiXmlElement* FirstChildElement() const; - TiXmlElement* FirstChildElement() { - return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() ); - } - - /// Convenience function to get through elements. - const TiXmlElement* FirstChildElement( const char * _value ) const; - TiXmlElement* FirstChildElement( const char * _value ) { - return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) ); - } - - #ifdef TIXML_USE_STL - const TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. - TiXmlElement* FirstChildElement( const std::string& _value ) { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. - #endif - - /** Query the type (as an enumerated value, above) of this node. - The possible types are: DOCUMENT, ELEMENT, COMMENT, - UNKNOWN, TEXT, and DECLARATION. - */ - int Type() const { return type; } - - /** Return a pointer to the Document this node lives in. - Returns null if not in a document. - */ - const TiXmlDocument* GetDocument() const; - TiXmlDocument* GetDocument() { - return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() ); - } - - /// Returns true if this node has no children. - bool NoChildren() const { return !firstChild; } - - virtual const TiXmlDocument* ToDocument() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlElement* ToElement() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlComment* ToComment() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlUnknown* ToUnknown() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlText* ToText() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - - virtual TiXmlDocument* ToDocument() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlElement* ToElement() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlComment* ToComment() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlUnknown* ToUnknown() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlText* ToText() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlDeclaration* ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - - /** Create an exact duplicate of this node and return it. The memory must be deleted - by the caller. - */ - virtual TiXmlNode* Clone() const = 0; - - /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the - XML tree will be conditionally visited and the host will be called back - via the TiXmlVisitor interface. - - This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse - the XML for the callbacks, so the performance of TinyXML is unchanged by using this - interface versus any other.) - - The interface has been based on ideas from: - - - http://www.saxproject.org/ - - http://c2.com/cgi/wiki?HierarchicalVisitorPattern - - Which are both good references for "visiting". - - An example of using Accept(): - @verbatim - TiXmlPrinter printer; - tinyxmlDoc.Accept( &printer ); - const char* xmlcstr = printer.CStr(); - @endverbatim - */ - virtual bool Accept( TiXmlVisitor* visitor ) const = 0; - -protected: - TiXmlNode( NodeType _type ); - - // Copy to the allocated object. Shared functionality between Clone, Copy constructor, - // and the assignment operator. - void CopyTo( TiXmlNode* target ) const; - - #ifdef TIXML_USE_STL - // The real work of the input operator. - virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0; - #endif - - // Figure out what is at *p, and parse it. Returns null if it is not an xml node. - TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); - - TiXmlNode* parent; - NodeType type; - - TiXmlNode* firstChild; - TiXmlNode* lastChild; - - TIXML_STRING value; - - TiXmlNode* prev; - TiXmlNode* next; - -private: - TiXmlNode( const TiXmlNode& ); // not implemented. - void operator=( const TiXmlNode& base ); // not allowed. -}; - - -/** An attribute is a name-value pair. Elements have an arbitrary - number of attributes, each with a unique name. - - @note The attributes are not TiXmlNodes, since they are not - part of the tinyXML document object model. There are other - suggested ways to look at this problem. -*/ -class TiXmlAttribute : public TiXmlBase -{ - friend class TiXmlAttributeSet; - -public: - /// Construct an empty attribute. - TiXmlAttribute() : TiXmlBase() - { - document = 0; - prev = next = 0; - } - - #ifdef TIXML_USE_STL - /// std::string constructor. - TiXmlAttribute( const std::string& _name, const std::string& _value ) - { - name = _name; - value = _value; - document = 0; - prev = next = 0; - } - #endif - - /// Construct an attribute with a name and value. - TiXmlAttribute( const char * _name, const char * _value ) - { - name = _name; - value = _value; - document = 0; - prev = next = 0; - } - - const char* Name() const { return name.c_str(); } ///< Return the name of this attribute. - const char* Value() const { return value.c_str(); } ///< Return the value of this attribute. - #ifdef TIXML_USE_STL - const std::string& ValueStr() const { return value; } ///< Return the value of this attribute. - #endif - int IntValue() const; ///< Return the value of this attribute, converted to an integer. - double DoubleValue() const; ///< Return the value of this attribute, converted to a double. - - // Get the tinyxml string representation - const TIXML_STRING& NameTStr() const { return name; } - - /** QueryIntValue examines the value string. It is an alternative to the - IntValue() method with richer error checking. - If the value is an integer, it is stored in 'value' and - the call returns TIXML_SUCCESS. If it is not - an integer, it returns TIXML_WRONG_TYPE. - - A specialized but useful call. Note that for success it returns 0, - which is the opposite of almost all other TinyXml calls. - */ - int QueryIntValue( int* _value ) const; - /// QueryDoubleValue examines the value string. See QueryIntValue(). - int QueryDoubleValue( double* _value ) const; - - void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. - void SetValue( const char* _value ) { value = _value; } ///< Set the value. - - void SetIntValue( int _value ); ///< Set the value from an integer. - void SetDoubleValue( double _value ); ///< Set the value from a double. - - #ifdef TIXML_USE_STL - /// STL std::string form. - void SetName( const std::string& _name ) { name = _name; } - /// STL std::string form. - void SetValue( const std::string& _value ) { value = _value; } - #endif - - /// Get the next sibling attribute in the DOM. Returns null at end. - const TiXmlAttribute* Next() const; - TiXmlAttribute* Next() { - return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() ); - } - - /// Get the previous sibling attribute in the DOM. Returns null at beginning. - const TiXmlAttribute* Previous() const; - TiXmlAttribute* Previous() { - return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() ); - } - - bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } - bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } - bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } - - /* Attribute parsing starts: first letter of the name - returns: the next char after the value end quote - */ - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - // Prints this Attribute to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const { - Print( cfile, depth, 0 ); - } - void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; - - // [internal use] - // Set the document pointer so the attribute can report errors. - void SetDocument( TiXmlDocument* doc ) { document = doc; } - -private: - TiXmlAttribute( const TiXmlAttribute& ); // not implemented. - void operator=( const TiXmlAttribute& base ); // not allowed. - - TiXmlDocument* document; // A pointer back to a document, for error reporting. - TIXML_STRING name; - TIXML_STRING value; - TiXmlAttribute* prev; - TiXmlAttribute* next; -}; - - -/* A class used to manage a group of attributes. - It is only used internally, both by the ELEMENT and the DECLARATION. - - The set can be changed transparent to the Element and Declaration - classes that use it, but NOT transparent to the Attribute - which has to implement a next() and previous() method. Which makes - it a bit problematic and prevents the use of STL. - - This version is implemented with circular lists because: - - I like circular lists - - it demonstrates some independence from the (typical) doubly linked list. -*/ -class TiXmlAttributeSet -{ -public: - TiXmlAttributeSet(); - ~TiXmlAttributeSet(); - - void Add( TiXmlAttribute* attribute ); - void Remove( TiXmlAttribute* attribute ); - - const TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } - TiXmlAttribute* First() { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } - const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } - TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } - - const TiXmlAttribute* Find( const char* _name ) const; - TiXmlAttribute* Find( const char* _name ) { - return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); - } - #ifdef TIXML_USE_STL - const TiXmlAttribute* Find( const std::string& _name ) const; - TiXmlAttribute* Find( const std::string& _name ) { - return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); - } - - #endif - -private: - //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element), - //*ME: this class must be also use a hidden/disabled copy-constructor !!! - TiXmlAttributeSet( const TiXmlAttributeSet& ); // not allowed - void operator=( const TiXmlAttributeSet& ); // not allowed (as TiXmlAttribute) - - TiXmlAttribute sentinel; -}; - - -/** The element is a container class. It has a value, the element name, - and can contain other elements, text, comments, and unknowns. - Elements also contain an arbitrary number of attributes. -*/ -class TiXmlElement : public TiXmlNode -{ -public: - /// Construct an element. - TiXmlElement (const char * in_value); - - #ifdef TIXML_USE_STL - /// std::string constructor. - TiXmlElement( const std::string& _value ); - #endif - - TiXmlElement( const TiXmlElement& ); - - void operator=( const TiXmlElement& base ); - - virtual ~TiXmlElement(); - - /** Given an attribute name, Attribute() returns the value - for the attribute of that name, or null if none exists. - */ - const char* Attribute( const char* name ) const; - - /** Given an attribute name, Attribute() returns the value - for the attribute of that name, or null if none exists. - If the attribute exists and can be converted to an integer, - the integer value will be put in the return 'i', if 'i' - is non-null. - */ - const char* Attribute( const char* name, int* i ) const; - - /** Given an attribute name, Attribute() returns the value - for the attribute of that name, or null if none exists. - If the attribute exists and can be converted to an double, - the double value will be put in the return 'd', if 'd' - is non-null. - */ - const char* Attribute( const char* name, double* d ) const; - - /** QueryIntAttribute examines the attribute - it is an alternative to the - Attribute() method with richer error checking. - If the attribute is an integer, it is stored in 'value' and - the call returns TIXML_SUCCESS. If it is not - an integer, it returns TIXML_WRONG_TYPE. If the attribute - does not exist, then TIXML_NO_ATTRIBUTE is returned. - */ - int QueryIntAttribute( const char* name, int* _value ) const; - /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). - int QueryDoubleAttribute( const char* name, double* _value ) const; - /// QueryFloatAttribute examines the attribute - see QueryIntAttribute(). - int QueryFloatAttribute( const char* name, float* _value ) const { - double d; - int result = QueryDoubleAttribute( name, &d ); - if ( result == TIXML_SUCCESS ) { - *_value = (float)d; - } - return result; - } - #ifdef TIXML_USE_STL - /** Template form of the attribute query which will try to read the - attribute into the specified type. Very easy, very powerful, but - be careful to make sure to call this with the correct type. - - @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE - */ - template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const - { - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - - std::stringstream sstream( node->ValueStr() ); - sstream >> *outValue; - if ( !sstream.fail() ) - return TIXML_SUCCESS; - return TIXML_WRONG_TYPE; - } - #endif - - /** Sets an attribute of name to a given value. The attribute - will be created if it does not exist, or changed if it does. - */ - void SetAttribute( const char* name, const char * _value ); - - #ifdef TIXML_USE_STL - const std::string* Attribute( const std::string& name ) const; - const std::string* Attribute( const std::string& name, int* i ) const; - const std::string* Attribute( const std::string& name, double* d ) const; - int QueryIntAttribute( const std::string& name, int* _value ) const; - int QueryDoubleAttribute( const std::string& name, double* _value ) const; - - /// STL std::string form. - void SetAttribute( const std::string& name, const std::string& _value ); - ///< STL std::string form. - void SetAttribute( const std::string& name, int _value ); - #endif - - /** Sets an attribute of name to a given value. The attribute - will be created if it does not exist, or changed if it does. - */ - void SetAttribute( const char * name, int value ); - - /** Sets an attribute of name to a given value. The attribute - will be created if it does not exist, or changed if it does. - */ - void SetDoubleAttribute( const char * name, double value ); - - /** Deletes an attribute with the given name. - */ - void RemoveAttribute( const char * name ); - #ifdef TIXML_USE_STL - void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. - #endif - - const TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. - TiXmlAttribute* FirstAttribute() { return attributeSet.First(); } - const TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. - TiXmlAttribute* LastAttribute() { return attributeSet.Last(); } - - /** Convenience function for easy access to the text inside an element. Although easy - and concise, GetText() is limited compared to getting the TiXmlText child - and accessing it directly. - - If the first child of 'this' is a TiXmlText, the GetText() - returns the character string of the Text node, else null is returned. - - This is a convenient method for getting the text of simple contained text: - @verbatim - This is text - const char* str = fooElement->GetText(); - @endverbatim - - 'str' will be a pointer to "This is text". - - Note that this function can be misleading. If the element foo was created from - this XML: - @verbatim - This is text - @endverbatim - - then the value of str would be null. The first child node isn't a text node, it is - another element. From this XML: - @verbatim - This is text - @endverbatim - GetText() will return "This is ". - - WARNING: GetText() accesses a child node - don't become confused with the - similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are - safe type casts on the referenced node. - */ - const char* GetText() const; - - /// Creates a new Element and returns it - the returned element is a copy. - virtual TiXmlNode* Clone() const; - // Print the Element to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const; - - /* Attribtue parsing starts: next char past '<' - returns: next char past '>' - */ - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlElement* ToElement() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlElement* ToElement() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* visitor ) const; - -protected: - - void CopyTo( TiXmlElement* target ) const; - void ClearThis(); // like clear, but initializes 'this' object as well - - // Used to be public [internal use] - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - /* [internal use] - Reads the "value" of the element -- another element, or text. - This should terminate with the current end tag. - */ - const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); - -private: - - TiXmlAttributeSet attributeSet; -}; - - -/** An XML comment. -*/ -class TiXmlComment : public TiXmlNode -{ -public: - /// Constructs an empty comment. - TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {} - /// Construct a comment from text. - TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::COMMENT ) { - SetValue( _value ); - } - TiXmlComment( const TiXmlComment& ); - void operator=( const TiXmlComment& base ); - - virtual ~TiXmlComment() {} - - /// Returns a copy of this Comment. - virtual TiXmlNode* Clone() const; - // Write this Comment to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const; - - /* Attribtue parsing starts: at the ! of the !-- - returns: next char past '>' - */ - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* visitor ) const; - -protected: - void CopyTo( TiXmlComment* target ) const; - - // used to be public - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif -// virtual void StreamOut( TIXML_OSTREAM * out ) const; - -private: - -}; - - -/** XML text. A text node can have 2 ways to output the next. "normal" output - and CDATA. It will default to the mode it was parsed from the XML file and - you generally want to leave it alone, but you can change the output mode with - SetCDATA() and query it with CDATA(). -*/ -class TiXmlText : public TiXmlNode -{ - friend class TiXmlElement; -public: - /** Constructor for text element. By default, it is treated as - normal, encoded text. If you want it be output as a CDATA text - element, set the parameter _cdata to 'true' - */ - TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TEXT) - { - SetValue( initValue ); - cdata = false; - } - virtual ~TiXmlText() {} - - #ifdef TIXML_USE_STL - /// Constructor. - TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT) - { - SetValue( initValue ); - cdata = false; - } - #endif - - TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT ) { copy.CopyTo( this ); } - void operator=( const TiXmlText& base ) { base.CopyTo( this ); } - - // Write this text object to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const; - - /// Queries whether this represents text using a CDATA section. - bool CDATA() const { return cdata; } - /// Turns on or off a CDATA representation of text. - void SetCDATA( bool _cdata ) { cdata = _cdata; } - - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlText* ToText() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* content ) const; - -protected : - /// [internal use] Creates a new Element and returns it. - virtual TiXmlNode* Clone() const; - void CopyTo( TiXmlText* target ) const; - - bool Blank() const; // returns true if all white space and new lines - // [internal use] - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - -private: - bool cdata; // true if this should be input and output as a CDATA style text element -}; - - -/** In correct XML the declaration is the first entry in the file. - @verbatim - - @endverbatim - - TinyXml will happily read or write files without a declaration, - however. There are 3 possible attributes to the declaration: - version, encoding, and standalone. - - Note: In this version of the code, the attributes are - handled as special cases, not generic attributes, simply - because there can only be at most 3 and they are always the same. -*/ -class TiXmlDeclaration : public TiXmlNode -{ -public: - /// Construct an empty declaration. - TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {} - -#ifdef TIXML_USE_STL - /// Constructor. - TiXmlDeclaration( const std::string& _version, - const std::string& _encoding, - const std::string& _standalone ); -#endif - - /// Construct. - TiXmlDeclaration( const char* _version, - const char* _encoding, - const char* _standalone ); - - TiXmlDeclaration( const TiXmlDeclaration& copy ); - void operator=( const TiXmlDeclaration& copy ); - - virtual ~TiXmlDeclaration() {} - - /// Version. Will return an empty string if none was found. - const char *Version() const { return version.c_str (); } - /// Encoding. Will return an empty string if none was found. - const char *Encoding() const { return encoding.c_str (); } - /// Is this a standalone document? - const char *Standalone() const { return standalone.c_str (); } - - /// Creates a copy of this Declaration and returns it. - virtual TiXmlNode* Clone() const; - // Print this declaration to a FILE stream. - virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; - virtual void Print( FILE* cfile, int depth ) const { - Print( cfile, depth, 0 ); - } - - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlDeclaration* ToDeclaration() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* visitor ) const; - -protected: - void CopyTo( TiXmlDeclaration* target ) const; - // used to be public - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - -private: - - TIXML_STRING version; - TIXML_STRING encoding; - TIXML_STRING standalone; -}; - - -/** Any tag that tinyXml doesn't recognize is saved as an - unknown. It is a tag of text, but should not be modified. - It will be written back to the XML, unchanged, when the file - is saved. - - DTD tags get thrown into TiXmlUnknowns. -*/ -class TiXmlUnknown : public TiXmlNode -{ -public: - TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {} - virtual ~TiXmlUnknown() {} - - TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN ) { copy.CopyTo( this ); } - void operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); } - - /// Creates a copy of this Unknown and returns it. - virtual TiXmlNode* Clone() const; - // Print this Unknown to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const; - - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* content ) const; - -protected: - void CopyTo( TiXmlUnknown* target ) const; - - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - -private: - -}; - - -/** Always the top level node. A document binds together all the - XML pieces. It can be saved, loaded, and printed to the screen. - The 'value' of a document node is the xml file name. -*/ -class TiXmlDocument : public TiXmlNode -{ -public: - /// Create an empty document, that has no name. - TiXmlDocument(); - /// Create a document with a name. The name of the document is also the filename of the xml. - TiXmlDocument( const char * documentName ); - - #ifdef TIXML_USE_STL - /// Constructor. - TiXmlDocument( const std::string& documentName ); - #endif - - TiXmlDocument( const TiXmlDocument& copy ); - void operator=( const TiXmlDocument& copy ); - - virtual ~TiXmlDocument() {} - - /** Load a file using the current document value. - Returns true if successful. Will delete any existing - document data before loading. - */ - bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); - /// Save a file using the current document value. Returns true if successful. - bool SaveFile() const; - /// Load a file using the given filename. Returns true if successful. - bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); - /// Save a file using the given filename. Returns true if successful. - bool SaveFile( const char * filename ) const; - /** Load a file using the given FILE*. Returns true if successful. Note that this method - doesn't stream - the entire object pointed at by the FILE* - will be interpreted as an XML file. TinyXML doesn't stream in XML from the current - file location. Streaming may be added in the future. - */ - bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); - /// Save a file using the given FILE*. Returns true if successful. - bool SaveFile( FILE* ) const; - - #ifdef TIXML_USE_STL - bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. - { -// StringToBuffer f( filename ); -// return ( f.buffer && LoadFile( f.buffer, encoding )); - return LoadFile( filename.c_str(), encoding ); - } - bool SaveFile( const std::string& filename ) const ///< STL std::string version. - { -// StringToBuffer f( filename ); -// return ( f.buffer && SaveFile( f.buffer )); - return SaveFile( filename.c_str() ); - } - #endif - - /** Parse the given null terminated block of xml data. Passing in an encoding to this - method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml - to use that encoding, regardless of what TinyXml might otherwise try to detect. - */ - virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); - - /** Get the root element -- the only top level element -- of the document. - In well formed XML, there should only be one. TinyXml is tolerant of - multiple elements at the document level. - */ - const TiXmlElement* RootElement() const { return FirstChildElement(); } - TiXmlElement* RootElement() { return FirstChildElement(); } - - /** If an error occurs, Error will be set to true. Also, - - The ErrorId() will contain the integer identifier of the error (not generally useful) - - The ErrorDesc() method will return the name of the error. (very useful) - - The ErrorRow() and ErrorCol() will return the location of the error (if known) - */ - bool Error() const { return error; } - - /// Contains a textual (english) description of the error if one occurs. - const char * ErrorDesc() const { return errorDesc.c_str (); } - - /** Generally, you probably want the error string ( ErrorDesc() ). But if you - prefer the ErrorId, this function will fetch it. - */ - int ErrorId() const { return errorId; } - - /** Returns the location (if known) of the error. The first column is column 1, - and the first row is row 1. A value of 0 means the row and column wasn't applicable - (memory errors, for example, have no row/column) or the parser lost the error. (An - error in the error reporting, in that case.) - - @sa SetTabSize, Row, Column - */ - int ErrorRow() const { return errorLocation.row+1; } - int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() - - /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol()) - to report the correct values for row and column. It does not change the output - or input in any way. - - By calling this method, with a tab size - greater than 0, the row and column of each node and attribute is stored - when the file is loaded. Very useful for tracking the DOM back in to - the source file. - - The tab size is required for calculating the location of nodes. If not - set, the default of 4 is used. The tabsize is set per document. Setting - the tabsize to 0 disables row/column tracking. - - Note that row and column tracking is not supported when using operator>>. - - The tab size needs to be enabled before the parse or load. Correct usage: - @verbatim - TiXmlDocument doc; - doc.SetTabSize( 8 ); - doc.Load( "myfile.xml" ); - @endverbatim - - @sa Row, Column - */ - void SetTabSize( int _tabsize ) { tabsize = _tabsize; } - - int TabSize() const { return tabsize; } - - /** If you have handled the error, it can be reset with this call. The error - state is automatically cleared if you Parse a new XML block. - */ - void ClearError() { error = false; - errorId = 0; - errorDesc = ""; - errorLocation.row = errorLocation.col = 0; - //errorLocation.last = 0; - } - - /** Write the document to standard out using formatted printing ("pretty print"). */ - void Print() const { Print( stdout, 0 ); } - - /* Write the document to a string using formatted printing ("pretty print"). This - will allocate a character array (new char[]) and return it as a pointer. The - calling code pust call delete[] on the return char* to avoid a memory leak. - */ - //char* PrintToMemory() const; - - /// Print this Document to a FILE stream. - virtual void Print( FILE* cfile, int depth = 0 ) const; - // [internal use] - void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); - - virtual const TiXmlDocument* ToDocument() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlDocument* ToDocument() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* content ) const; - -protected : - // [internal use] - virtual TiXmlNode* Clone() const; - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - -private: - void CopyTo( TiXmlDocument* target ) const; - - bool error; - int errorId; - TIXML_STRING errorDesc; - int tabsize; - TiXmlCursor errorLocation; - bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write. -}; - - -/** - A TiXmlHandle is a class that wraps a node pointer with null checks; this is - an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml - DOM structure. It is a separate utility class. - - Take an example: - @verbatim - - - - - - - @endverbatim - - Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very - easy to write a *lot* of code that looks like: - - @verbatim - TiXmlElement* root = document.FirstChildElement( "Document" ); - if ( root ) - { - TiXmlElement* element = root->FirstChildElement( "Element" ); - if ( element ) - { - TiXmlElement* child = element->FirstChildElement( "Child" ); - if ( child ) - { - TiXmlElement* child2 = child->NextSiblingElement( "Child" ); - if ( child2 ) - { - // Finally do something useful. - @endverbatim - - And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity - of such code. A TiXmlHandle checks for null pointers so it is perfectly safe - and correct to use: - - @verbatim - TiXmlHandle docHandle( &document ); - TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); - if ( child2 ) - { - // do something useful - @endverbatim - - Which is MUCH more concise and useful. - - It is also safe to copy handles - internally they are nothing more than node pointers. - @verbatim - TiXmlHandle handleCopy = handle; - @endverbatim - - What they should not be used for is iteration: - - @verbatim - int i=0; - while ( true ) - { - TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement(); - if ( !child ) - break; - // do something - ++i; - } - @endverbatim - - It seems reasonable, but it is in fact two embedded while loops. The Child method is - a linear walk to find the element, so this code would iterate much more than it needs - to. Instead, prefer: - - @verbatim - TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement(); - - for( child; child; child=child->NextSiblingElement() ) - { - // do something - } - @endverbatim -*/ -class TiXmlHandle -{ -public: - /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. - TiXmlHandle( TiXmlNode* _node ) { this->node = _node; } - /// Copy constructor - TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } - TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; } - - /// Return a handle to the first child node. - TiXmlHandle FirstChild() const; - /// Return a handle to the first child node with the given name. - TiXmlHandle FirstChild( const char * value ) const; - /// Return a handle to the first child element. - TiXmlHandle FirstChildElement() const; - /// Return a handle to the first child element with the given name. - TiXmlHandle FirstChildElement( const char * value ) const; - - /** Return a handle to the "index" child with the given name. - The first child is 0, the second 1, etc. - */ - TiXmlHandle Child( const char* value, int index ) const; - /** Return a handle to the "index" child. - The first child is 0, the second 1, etc. - */ - TiXmlHandle Child( int index ) const; - /** Return a handle to the "index" child element with the given name. - The first child element is 0, the second 1, etc. Note that only TiXmlElements - are indexed: other types are not counted. - */ - TiXmlHandle ChildElement( const char* value, int index ) const; - /** Return a handle to the "index" child element. - The first child element is 0, the second 1, etc. Note that only TiXmlElements - are indexed: other types are not counted. - */ - TiXmlHandle ChildElement( int index ) const; - - #ifdef TIXML_USE_STL - TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } - TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } - - TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } - TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } - #endif - - /** Return the handle as a TiXmlNode. This may return null. - */ - TiXmlNode* ToNode() const { return node; } - /** Return the handle as a TiXmlElement. This may return null. - */ - TiXmlElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } - /** Return the handle as a TiXmlText. This may return null. - */ - TiXmlText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } - /** Return the handle as a TiXmlUnknown. This may return null. - */ - TiXmlUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } - - /** @deprecated use ToNode. - Return the handle as a TiXmlNode. This may return null. - */ - TiXmlNode* Node() const { return ToNode(); } - /** @deprecated use ToElement. - Return the handle as a TiXmlElement. This may return null. - */ - TiXmlElement* Element() const { return ToElement(); } - /** @deprecated use ToText() - Return the handle as a TiXmlText. This may return null. - */ - TiXmlText* Text() const { return ToText(); } - /** @deprecated use ToUnknown() - Return the handle as a TiXmlUnknown. This may return null. - */ - TiXmlUnknown* Unknown() const { return ToUnknown(); } - -private: - TiXmlNode* node; -}; - - -/** Print to memory functionality. The TiXmlPrinter is useful when you need to: - - -# Print to memory (especially in non-STL mode) - -# Control formatting (line endings, etc.) - - When constructed, the TiXmlPrinter is in its default "pretty printing" mode. - Before calling Accept() you can call methods to control the printing - of the XML document. After TiXmlNode::Accept() is called, the printed document can - be accessed via the CStr(), Str(), and Size() methods. - - TiXmlPrinter uses the Visitor API. - @verbatim - TiXmlPrinter printer; - printer.SetIndent( "\t" ); - - doc.Accept( &printer ); - fprintf( stdout, "%s", printer.CStr() ); - @endverbatim -*/ -class TiXmlPrinter : public TiXmlVisitor -{ -public: - TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ), - buffer(), indent( " " ), lineBreak( "\n" ) {} - - virtual bool VisitEnter( const TiXmlDocument& doc ); - virtual bool VisitExit( const TiXmlDocument& doc ); - - virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ); - virtual bool VisitExit( const TiXmlElement& element ); - - virtual bool Visit( const TiXmlDeclaration& declaration ); - virtual bool Visit( const TiXmlText& text ); - virtual bool Visit( const TiXmlComment& comment ); - virtual bool Visit( const TiXmlUnknown& unknown ); - - /** Set the indent characters for printing. By default 4 spaces - but tab (\t) is also useful, or null/empty string for no indentation. - */ - void SetIndent( const char* _indent ) { indent = _indent ? _indent : "" ; } - /// Query the indention string. - const char* Indent() { return indent.c_str(); } - /** Set the line breaking string. By default set to newline (\n). - Some operating systems prefer other characters, or can be - set to the null/empty string for no indenation. - */ - void SetLineBreak( const char* _lineBreak ) { lineBreak = _lineBreak ? _lineBreak : ""; } - /// Query the current line breaking string. - const char* LineBreak() { return lineBreak.c_str(); } - - /** Switch over to "stream printing" which is the most dense formatting without - linebreaks. Common when the XML is needed for network transmission. - */ - void SetStreamPrinting() { indent = ""; - lineBreak = ""; - } - /// Return the result. - const char* CStr() { return buffer.c_str(); } - /// Return the length of the result string. - size_t Size() { return buffer.size(); } - - #ifdef TIXML_USE_STL - /// Return the result. - const std::string& Str() { return buffer; } - #endif - -private: - void DoIndent() { - for( int i=0; i +#include +#include +#include +#include + +// Help out windows: +#if defined( _DEBUG ) && !defined( DEBUG ) +#define DEBUG +#endif + +#ifdef TIXML_USE_STL + #include + #include + #include + #define TIXML_STRING std::string +#else + #include "tinystr.h" + #define TIXML_STRING TiXmlString +#endif + +// Deprecated library function hell. Compilers want to use the +// new safe versions. This probably doesn't fully address the problem, +// but it gets closer. There are too many compilers for me to fully +// test. If you get compilation troubles, undefine TIXML_SAFE +#define TIXML_SAFE + +#ifdef TIXML_SAFE + #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) + // Microsoft visual studio, version 2005 and higher. + #define TIXML_SNPRINTF _snprintf_s + #define TIXML_SNSCANF _snscanf_s + #elif defined(_MSC_VER) && (_MSC_VER >= 1200 ) + // Microsoft visual studio, version 6 and higher. + //#pragma message( "Using _sn* functions." ) + #define TIXML_SNPRINTF _snprintf + #define TIXML_SNSCANF _snscanf + #elif defined(__GNUC__) && (__GNUC__ >= 3 ) + // GCC version 3 and higher.s + //#warning( "Using sn* functions." ) + #define TIXML_SNPRINTF snprintf + #define TIXML_SNSCANF snscanf + #endif +#endif + +class TiXmlDocument; +class TiXmlElement; +class TiXmlComment; +class TiXmlUnknown; +class TiXmlAttribute; +class TiXmlText; +class TiXmlDeclaration; +class TiXmlParsingData; + +const int TIXML_MAJOR_VERSION = 2; +const int TIXML_MINOR_VERSION = 5; +const int TIXML_PATCH_VERSION = 2; + +/* Internal structure for tracking location of items + in the XML file. +*/ +struct TiXmlCursor +{ + TiXmlCursor() { Clear(); } + void Clear() { row = col = -1; } + + int row; // 0 based. + int col; // 0 based. +}; + + +/** + If you call the Accept() method, it requires being passed a TiXmlVisitor + class to handle callbacks. For nodes that contain other nodes (Document, Element) + you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves + are simple called with Visit(). + + If you return 'true' from a Visit method, recursive parsing will continue. If you return + false, no children of this node or its sibilings will be Visited. + + All flavors of Visit methods have a default implementation that returns 'true' (continue + visiting). You need to only override methods that are interesting to you. + + Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting. + + You should never change the document from a callback. + + @sa TiXmlNode::Accept() +*/ +class TiXmlVisitor +{ +public: + virtual ~TiXmlVisitor() {} + + /// Visit a document. + virtual bool VisitEnter( const TiXmlDocument& doc ) { return true; } + /// Visit a document. + virtual bool VisitExit( const TiXmlDocument& doc ) { return true; } + + /// Visit an element. + virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) { return true; } + /// Visit an element. + virtual bool VisitExit( const TiXmlElement& element ) { return true; } + + /// Visit a declaration + virtual bool Visit( const TiXmlDeclaration& declaration ) { return true; } + /// Visit a text node + virtual bool Visit( const TiXmlText& text ) { return true; } + /// Visit a comment node + virtual bool Visit( const TiXmlComment& comment ) { return true; } + /// Visit an unknow node + virtual bool Visit( const TiXmlUnknown& unknown ) { return true; } +}; + +// Only used by Attribute::Query functions +enum +{ + TIXML_SUCCESS, + TIXML_NO_ATTRIBUTE, + TIXML_WRONG_TYPE +}; + + +// Used by the parsing routines. +enum TiXmlEncoding +{ + TIXML_ENCODING_UNKNOWN, + TIXML_ENCODING_UTF8, + TIXML_ENCODING_LEGACY +}; + +const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; + +/** TiXmlBase is a base class for every class in TinyXml. + It does little except to establish that TinyXml classes + can be printed and provide some utility functions. + + In XML, the document and elements can contain + other elements and other types of nodes. + + @verbatim + A Document can contain: Element (container or leaf) + Comment (leaf) + Unknown (leaf) + Declaration( leaf ) + + An Element can contain: Element (container or leaf) + Text (leaf) + Attributes (not on tree) + Comment (leaf) + Unknown (leaf) + + A Decleration contains: Attributes (not on tree) + @endverbatim +*/ +class TiXmlBase +{ + friend class TiXmlNode; + friend class TiXmlElement; + friend class TiXmlDocument; + +public: + TiXmlBase() : userData(0) {} + virtual ~TiXmlBase() {} + + /** All TinyXml classes can print themselves to a filestream + or the string class (TiXmlString in non-STL mode, std::string + in STL mode.) Either or both cfile and str can be null. + + This is a formatted print, and will insert + tabs and newlines. + + (For an unformatted stream, use the << operator.) + */ + virtual void Print( FILE* cfile, int depth ) const = 0; + + /** The world does not agree on whether white space should be kept or + not. In order to make everyone happy, these global, static functions + are provided to set whether or not TinyXml will condense all white space + into a single space or not. The default is to condense. Note changing this + value is not thread safe. + */ + static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } + + /// Return the current white space setting. + static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } + + /** Return the position, in the original source file, of this node or attribute. + The row and column are 1-based. (That is the first row and first column is + 1,1). If the returns values are 0 or less, then the parser does not have + a row and column value. + + Generally, the row and column value will be set when the TiXmlDocument::Load(), + TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set + when the DOM was created from operator>>. + + The values reflect the initial load. Once the DOM is modified programmatically + (by adding or changing nodes and attributes) the new values will NOT update to + reflect changes in the document. + + There is a minor performance cost to computing the row and column. Computation + can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. + + @sa TiXmlDocument::SetTabSize() + */ + int Row() const { return location.row + 1; } + int Column() const { return location.col + 1; } ///< See Row() + + void SetUserData( void* user ) { userData = user; } ///< Set a pointer to arbitrary user data. + void* GetUserData() { return userData; } ///< Get a pointer to arbitrary user data. + const void* GetUserData() const { return userData; } ///< Get a pointer to arbitrary user data. + + // Table that returs, for a given lead byte, the total number of bytes + // in the UTF-8 sequence. + static const int utf8ByteTable[256]; + + virtual const char* Parse( const char* p, + TiXmlParsingData* data, + TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; + + enum + { + TIXML_NO_ERROR = 0, + TIXML_ERROR, + TIXML_ERROR_OPENING_FILE, + TIXML_ERROR_OUT_OF_MEMORY, + TIXML_ERROR_PARSING_ELEMENT, + TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, + TIXML_ERROR_READING_ELEMENT_VALUE, + TIXML_ERROR_READING_ATTRIBUTES, + TIXML_ERROR_PARSING_EMPTY, + TIXML_ERROR_READING_END_TAG, + TIXML_ERROR_PARSING_UNKNOWN, + TIXML_ERROR_PARSING_COMMENT, + TIXML_ERROR_PARSING_DECLARATION, + TIXML_ERROR_DOCUMENT_EMPTY, + TIXML_ERROR_EMBEDDED_NULL, + TIXML_ERROR_PARSING_CDATA, + TIXML_ERROR_DOCUMENT_TOP_ONLY, + + TIXML_ERROR_STRING_COUNT + }; + +protected: + + static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); + inline static bool IsWhiteSpace( char c ) + { + return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); + } + inline static bool IsWhiteSpace( int c ) + { + if ( c < 256 ) + return IsWhiteSpace( (char) c ); + return false; // Again, only truly correct for English/Latin...but usually works. + } + + #ifdef TIXML_USE_STL + static bool StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ); + static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag ); + #endif + + /* Reads an XML name into the string provided. Returns + a pointer just past the last character of the name, + or 0 if the function has an error. + */ + static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); + + /* Reads text. Returns a pointer past the given end tag. + Wickedly complex options, but it keeps the (sensitive) code in one place. + */ + static const char* ReadText( const char* in, // where to start + TIXML_STRING* text, // the string read + bool ignoreWhiteSpace, // whether to keep the white space + const char* endTag, // what ends this text + bool ignoreCase, // whether to ignore case in the end tag + TiXmlEncoding encoding ); // the current encoding + + // If an entity has been found, transform it into a character. + static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); + + // Get a character, while interpreting entities. + // The length can be from 0 to 4 bytes. + inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) + { + assert( p ); + if ( encoding == TIXML_ENCODING_UTF8 ) + { + *length = utf8ByteTable[ *((const unsigned char*)p) ]; + assert( *length >= 0 && *length < 5 ); + } + else + { + *length = 1; + } + + if ( *length == 1 ) + { + if ( *p == '&' ) + return GetEntity( p, _value, length, encoding ); + *_value = *p; + return p+1; + } + else if ( *length ) + { + //strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe), + // and the null terminator isn't needed + for( int i=0; p[i] && i<*length; ++i ) { + _value[i] = p[i]; + } + return p + (*length); + } + else + { + // Not valid text. + return 0; + } + } + + // Puts a string to a stream, expanding entities as it goes. + // Note this should not contian the '<', '>', etc, or they will be transformed into entities! + static void PutString( const TIXML_STRING& str, TIXML_STRING* out ); + + // Return true if the next characters in the stream are any of the endTag sequences. + // Ignore case only works for english, and should only be relied on when comparing + // to English words: StringEqual( p, "version", true ) is fine. + static bool StringEqual( const char* p, + const char* endTag, + bool ignoreCase, + TiXmlEncoding encoding ); + + static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; + + TiXmlCursor location; + + /// Field containing a generic user pointer + void* userData; + + // None of these methods are reliable for any language except English. + // Good for approximation, not great for accuracy. + static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); + static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); + inline static int ToLower( int v, TiXmlEncoding encoding ) + { + if ( encoding == TIXML_ENCODING_UTF8 ) + { + if ( v < 128 ) return tolower( v ); + return v; + } + else + { + return tolower( v ); + } + } + static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); + +private: + TiXmlBase( const TiXmlBase& ); // not implemented. + void operator=( const TiXmlBase& base ); // not allowed. + + struct Entity + { + const char* str; + unsigned int strLength; + char chr; + }; + enum + { + NUM_ENTITY = 5, + MAX_ENTITY_LENGTH = 6 + + }; + static Entity entity[ NUM_ENTITY ]; + static bool condenseWhiteSpace; +}; + + +/** The parent class for everything in the Document Object Model. + (Except for attributes). + Nodes have siblings, a parent, and children. A node can be + in a document, or stand on its own. The type of a TiXmlNode + can be queried, and it can be cast to its more defined type. +*/ +class TiXmlNode : public TiXmlBase +{ + friend class TiXmlDocument; + friend class TiXmlElement; + +public: + #ifdef TIXML_USE_STL + + /** An input stream operator, for every class. Tolerant of newlines and + formatting, but doesn't expect them. + */ + friend std::istream& operator >> (std::istream& in, TiXmlNode& base); + + /** An output stream operator, for every class. Note that this outputs + without any newlines or formatting, as opposed to Print(), which + includes tabs and new lines. + + The operator<< and operator>> are not completely symmetric. Writing + a node to a stream is very well defined. You'll get a nice stream + of output, without any extra whitespace or newlines. + + But reading is not as well defined. (As it always is.) If you create + a TiXmlElement (for example) and read that from an input stream, + the text needs to define an element or junk will result. This is + true of all input streams, but it's worth keeping in mind. + + A TiXmlDocument will read nodes until it reads a root element, and + all the children of that root element. + */ + friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); + + /// Appends the XML node or attribute to a std::string. + friend std::string& operator<< (std::string& out, const TiXmlNode& base ); + + #endif + + /** The types of XML nodes supported by TinyXml. (All the + unsupported types are picked up by UNKNOWN.) + */ + enum NodeType + { + DOCUMENT, + ELEMENT, + COMMENT, + UNKNOWN, + TEXT, + DECLARATION, + TYPECOUNT + }; + + virtual ~TiXmlNode(); + + /** The meaning of 'value' changes for the specific type of + TiXmlNode. + @verbatim + Document: filename of the xml file + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + + The subclasses will wrap this function. + */ + const char *Value() const { return value.c_str (); } + + #ifdef TIXML_USE_STL + /** Return Value() as a std::string. If you only use STL, + this is more efficient than calling Value(). + Only available in STL mode. + */ + const std::string& ValueStr() const { return value; } + #endif + + /** Changes the value of the node. Defined as: + @verbatim + Document: filename of the xml file + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + */ + void SetValue(const char * _value) { value = _value;} + + #ifdef TIXML_USE_STL + /// STL std::string form. + void SetValue( const std::string& _value ) { value = _value; } + #endif + + /// Delete all the children of this node. Does not affect 'this'. + void Clear(); + + /// One step up the DOM. + TiXmlNode* Parent() { return parent; } + const TiXmlNode* Parent() const { return parent; } + + const TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. + TiXmlNode* FirstChild() { return firstChild; } + const TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. + /// The first child of this node with the matching 'value'. Will be null if none found. + TiXmlNode* FirstChild( const char * _value ) { + // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe) + // call the method, cast the return back to non-const. + return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value )); + } + const TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. + TiXmlNode* LastChild() { return lastChild; } + + const TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. + TiXmlNode* LastChild( const char * _value ) { + return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value )); + } + + #ifdef TIXML_USE_STL + const TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* FirstChild( const std::string& _value ) { return FirstChild (_value.c_str ()); } ///< STL std::string form. + const TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* LastChild( const std::string& _value ) { return LastChild (_value.c_str ()); } ///< STL std::string form. + #endif + + /** An alternate way to walk the children of a node. + One way to iterate over nodes is: + @verbatim + for( child = parent->FirstChild(); child; child = child->NextSibling() ) + @endverbatim + + IterateChildren does the same thing with the syntax: + @verbatim + child = 0; + while( child = parent->IterateChildren( child ) ) + @endverbatim + + IterateChildren takes the previous child as input and finds + the next one. If the previous child is null, it returns the + first. IterateChildren will return null when done. + */ + const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const; + TiXmlNode* IterateChildren( const TiXmlNode* previous ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) ); + } + + /// This flavor of IterateChildren searches for children with a particular 'value' + const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const; + TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. + TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. + #endif + + /** Add a new node related to this. Adds a child past the LastChild. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); + + + /** Add a new node related to this. Adds a child past the LastChild. + + NOTE: the node to be added is passed by pointer, and will be + henceforth owned (and deleted) by tinyXml. This method is efficient + and avoids an extra copy, but should be used with care as it + uses a different memory model than the other insert functions. + + @sa InsertEndChild + */ + TiXmlNode* LinkEndChild( TiXmlNode* addThis ); + + /** Add a new node related to this. Adds a child before the specified child. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); + + /** Add a new node related to this. Adds a child after the specified child. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); + + /** Replace a child of this node. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); + + /// Delete a child of this node. + bool RemoveChild( TiXmlNode* removeThis ); + + /// Navigate to a sibling node. + const TiXmlNode* PreviousSibling() const { return prev; } + TiXmlNode* PreviousSibling() { return prev; } + + /// Navigate to a sibling node. + const TiXmlNode* PreviousSibling( const char * ) const; + TiXmlNode* PreviousSibling( const char *_prev ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* PreviousSibling( const std::string& _value ) { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. + const TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* NextSibling( const std::string& _value) { return NextSibling (_value.c_str ()); } ///< STL std::string form. + #endif + + /// Navigate to a sibling node. + const TiXmlNode* NextSibling() const { return next; } + TiXmlNode* NextSibling() { return next; } + + /// Navigate to a sibling node with the given 'value'. + const TiXmlNode* NextSibling( const char * ) const; + TiXmlNode* NextSibling( const char* _next ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) ); + } + + /** Convenience function to get through elements. + Calls NextSibling and ToElement. Will skip all non-Element + nodes. Returns 0 if there is not another element. + */ + const TiXmlElement* NextSiblingElement() const; + TiXmlElement* NextSiblingElement() { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() ); + } + + /** Convenience function to get through elements. + Calls NextSibling and ToElement. Will skip all non-Element + nodes. Returns 0 if there is not another element. + */ + const TiXmlElement* NextSiblingElement( const char * ) const; + TiXmlElement* NextSiblingElement( const char *_next ) { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. + TiXmlElement* NextSiblingElement( const std::string& _value) { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. + #endif + + /// Convenience function to get through elements. + const TiXmlElement* FirstChildElement() const; + TiXmlElement* FirstChildElement() { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() ); + } + + /// Convenience function to get through elements. + const TiXmlElement* FirstChildElement( const char * _value ) const; + TiXmlElement* FirstChildElement( const char * _value ) { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. + TiXmlElement* FirstChildElement( const std::string& _value ) { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. + #endif + + /** Query the type (as an enumerated value, above) of this node. + The possible types are: DOCUMENT, ELEMENT, COMMENT, + UNKNOWN, TEXT, and DECLARATION. + */ + int Type() const { return type; } + + /** Return a pointer to the Document this node lives in. + Returns null if not in a document. + */ + const TiXmlDocument* GetDocument() const; + TiXmlDocument* GetDocument() { + return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() ); + } + + /// Returns true if this node has no children. + bool NoChildren() const { return !firstChild; } + + virtual const TiXmlDocument* ToDocument() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlElement* ToElement() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlComment* ToComment() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlUnknown* ToUnknown() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlText* ToText() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + + virtual TiXmlDocument* ToDocument() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlElement* ToElement() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlComment* ToComment() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlUnknown* ToUnknown() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlText* ToText() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlDeclaration* ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + + /** Create an exact duplicate of this node and return it. The memory must be deleted + by the caller. + */ + virtual TiXmlNode* Clone() const = 0; + + /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the + XML tree will be conditionally visited and the host will be called back + via the TiXmlVisitor interface. + + This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse + the XML for the callbacks, so the performance of TinyXML is unchanged by using this + interface versus any other.) + + The interface has been based on ideas from: + + - http://www.saxproject.org/ + - http://c2.com/cgi/wiki?HierarchicalVisitorPattern + + Which are both good references for "visiting". + + An example of using Accept(): + @verbatim + TiXmlPrinter printer; + tinyxmlDoc.Accept( &printer ); + const char* xmlcstr = printer.CStr(); + @endverbatim + */ + virtual bool Accept( TiXmlVisitor* visitor ) const = 0; + +protected: + TiXmlNode( NodeType _type ); + + // Copy to the allocated object. Shared functionality between Clone, Copy constructor, + // and the assignment operator. + void CopyTo( TiXmlNode* target ) const; + + #ifdef TIXML_USE_STL + // The real work of the input operator. + virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0; + #endif + + // Figure out what is at *p, and parse it. Returns null if it is not an xml node. + TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); + + TiXmlNode* parent; + NodeType type; + + TiXmlNode* firstChild; + TiXmlNode* lastChild; + + TIXML_STRING value; + + TiXmlNode* prev; + TiXmlNode* next; + +private: + TiXmlNode( const TiXmlNode& ); // not implemented. + void operator=( const TiXmlNode& base ); // not allowed. +}; + + +/** An attribute is a name-value pair. Elements have an arbitrary + number of attributes, each with a unique name. + + @note The attributes are not TiXmlNodes, since they are not + part of the tinyXML document object model. There are other + suggested ways to look at this problem. +*/ +class TiXmlAttribute : public TiXmlBase +{ + friend class TiXmlAttributeSet; + +public: + /// Construct an empty attribute. + TiXmlAttribute() : TiXmlBase() + { + document = 0; + prev = next = 0; + } + + #ifdef TIXML_USE_STL + /// std::string constructor. + TiXmlAttribute( const std::string& _name, const std::string& _value ) + { + name = _name; + value = _value; + document = 0; + prev = next = 0; + } + #endif + + /// Construct an attribute with a name and value. + TiXmlAttribute( const char * _name, const char * _value ) + { + name = _name; + value = _value; + document = 0; + prev = next = 0; + } + + const char* Name() const { return name.c_str(); } ///< Return the name of this attribute. + const char* Value() const { return value.c_str(); } ///< Return the value of this attribute. + #ifdef TIXML_USE_STL + const std::string& ValueStr() const { return value; } ///< Return the value of this attribute. + #endif + int IntValue() const; ///< Return the value of this attribute, converted to an integer. + double DoubleValue() const; ///< Return the value of this attribute, converted to a double. + + // Get the tinyxml string representation + const TIXML_STRING& NameTStr() const { return name; } + + /** QueryIntValue examines the value string. It is an alternative to the + IntValue() method with richer error checking. + If the value is an integer, it is stored in 'value' and + the call returns TIXML_SUCCESS. If it is not + an integer, it returns TIXML_WRONG_TYPE. + + A specialized but useful call. Note that for success it returns 0, + which is the opposite of almost all other TinyXml calls. + */ + int QueryIntValue( int* _value ) const; + /// QueryDoubleValue examines the value string. See QueryIntValue(). + int QueryDoubleValue( double* _value ) const; + + void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. + void SetValue( const char* _value ) { value = _value; } ///< Set the value. + + void SetIntValue( int _value ); ///< Set the value from an integer. + void SetDoubleValue( double _value ); ///< Set the value from a double. + + #ifdef TIXML_USE_STL + /// STL std::string form. + void SetName( const std::string& _name ) { name = _name; } + /// STL std::string form. + void SetValue( const std::string& _value ) { value = _value; } + #endif + + /// Get the next sibling attribute in the DOM. Returns null at end. + const TiXmlAttribute* Next() const; + TiXmlAttribute* Next() { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() ); + } + + /// Get the previous sibling attribute in the DOM. Returns null at beginning. + const TiXmlAttribute* Previous() const; + TiXmlAttribute* Previous() { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() ); + } + + bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } + bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } + bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } + + /* Attribute parsing starts: first letter of the name + returns: the next char after the value end quote + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + // Prints this Attribute to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const { + Print( cfile, depth, 0 ); + } + void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; + + // [internal use] + // Set the document pointer so the attribute can report errors. + void SetDocument( TiXmlDocument* doc ) { document = doc; } + +private: + TiXmlAttribute( const TiXmlAttribute& ); // not implemented. + void operator=( const TiXmlAttribute& base ); // not allowed. + + TiXmlDocument* document; // A pointer back to a document, for error reporting. + TIXML_STRING name; + TIXML_STRING value; + TiXmlAttribute* prev; + TiXmlAttribute* next; +}; + + +/* A class used to manage a group of attributes. + It is only used internally, both by the ELEMENT and the DECLARATION. + + The set can be changed transparent to the Element and Declaration + classes that use it, but NOT transparent to the Attribute + which has to implement a next() and previous() method. Which makes + it a bit problematic and prevents the use of STL. + + This version is implemented with circular lists because: + - I like circular lists + - it demonstrates some independence from the (typical) doubly linked list. +*/ +class TiXmlAttributeSet +{ +public: + TiXmlAttributeSet(); + ~TiXmlAttributeSet(); + + void Add( TiXmlAttribute* attribute ); + void Remove( TiXmlAttribute* attribute ); + + const TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } + TiXmlAttribute* First() { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } + const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } + TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } + + const TiXmlAttribute* Find( const char* _name ) const; + TiXmlAttribute* Find( const char* _name ) { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); + } + #ifdef TIXML_USE_STL + const TiXmlAttribute* Find( const std::string& _name ) const; + TiXmlAttribute* Find( const std::string& _name ) { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); + } + + #endif + +private: + //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element), + //*ME: this class must be also use a hidden/disabled copy-constructor !!! + TiXmlAttributeSet( const TiXmlAttributeSet& ); // not allowed + void operator=( const TiXmlAttributeSet& ); // not allowed (as TiXmlAttribute) + + TiXmlAttribute sentinel; +}; + + +/** The element is a container class. It has a value, the element name, + and can contain other elements, text, comments, and unknowns. + Elements also contain an arbitrary number of attributes. +*/ +class TiXmlElement : public TiXmlNode +{ +public: + /// Construct an element. + TiXmlElement (const char * in_value); + + #ifdef TIXML_USE_STL + /// std::string constructor. + TiXmlElement( const std::string& _value ); + #endif + + TiXmlElement( const TiXmlElement& ); + + void operator=( const TiXmlElement& base ); + + virtual ~TiXmlElement(); + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + */ + const char* Attribute( const char* name ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + If the attribute exists and can be converted to an integer, + the integer value will be put in the return 'i', if 'i' + is non-null. + */ + const char* Attribute( const char* name, int* i ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + If the attribute exists and can be converted to an double, + the double value will be put in the return 'd', if 'd' + is non-null. + */ + const char* Attribute( const char* name, double* d ) const; + + /** QueryIntAttribute examines the attribute - it is an alternative to the + Attribute() method with richer error checking. + If the attribute is an integer, it is stored in 'value' and + the call returns TIXML_SUCCESS. If it is not + an integer, it returns TIXML_WRONG_TYPE. If the attribute + does not exist, then TIXML_NO_ATTRIBUTE is returned. + */ + int QueryIntAttribute( const char* name, int* _value ) const; + /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). + int QueryDoubleAttribute( const char* name, double* _value ) const; + /// QueryFloatAttribute examines the attribute - see QueryIntAttribute(). + int QueryFloatAttribute( const char* name, float* _value ) const { + double d; + int result = QueryDoubleAttribute( name, &d ); + if ( result == TIXML_SUCCESS ) { + *_value = (float)d; + } + return result; + } + #ifdef TIXML_USE_STL + /** Template form of the attribute query which will try to read the + attribute into the specified type. Very easy, very powerful, but + be careful to make sure to call this with the correct type. + + @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE + */ + template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const + { + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + + std::stringstream sstream( node->ValueStr() ); + sstream >> *outValue; + if ( !sstream.fail() ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; + } + #endif + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetAttribute( const char* name, const char * _value ); + + #ifdef TIXML_USE_STL + const std::string* Attribute( const std::string& name ) const; + const std::string* Attribute( const std::string& name, int* i ) const; + const std::string* Attribute( const std::string& name, double* d ) const; + int QueryIntAttribute( const std::string& name, int* _value ) const; + int QueryDoubleAttribute( const std::string& name, double* _value ) const; + + /// STL std::string form. + void SetAttribute( const std::string& name, const std::string& _value ); + ///< STL std::string form. + void SetAttribute( const std::string& name, int _value ); + #endif + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetAttribute( const char * name, int value ); + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetDoubleAttribute( const char * name, double value ); + + /** Deletes an attribute with the given name. + */ + void RemoveAttribute( const char * name ); + #ifdef TIXML_USE_STL + void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. + #endif + + const TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. + TiXmlAttribute* FirstAttribute() { return attributeSet.First(); } + const TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. + TiXmlAttribute* LastAttribute() { return attributeSet.Last(); } + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, GetText() is limited compared to getting the TiXmlText child + and accessing it directly. + + If the first child of 'this' is a TiXmlText, the GetText() + returns the character string of the Text node, else null is returned. + + This is a convenient method for getting the text of simple contained text: + @verbatim + This is text + const char* str = fooElement->GetText(); + @endverbatim + + 'str' will be a pointer to "This is text". + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then the value of str would be null. The first child node isn't a text node, it is + another element. From this XML: + @verbatim + This is text + @endverbatim + GetText() will return "This is ". + + WARNING: GetText() accesses a child node - don't become confused with the + similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are + safe type casts on the referenced node. + */ + const char* GetText() const; + + /// Creates a new Element and returns it - the returned element is a copy. + virtual TiXmlNode* Clone() const; + // Print the Element to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /* Attribtue parsing starts: next char past '<' + returns: next char past '>' + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlElement* ToElement() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlElement* ToElement() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* visitor ) const; + +protected: + + void CopyTo( TiXmlElement* target ) const; + void ClearThis(); // like clear, but initializes 'this' object as well + + // Used to be public [internal use] + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + /* [internal use] + Reads the "value" of the element -- another element, or text. + This should terminate with the current end tag. + */ + const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); + +private: + + TiXmlAttributeSet attributeSet; +}; + + +/** An XML comment. +*/ +class TiXmlComment : public TiXmlNode +{ +public: + /// Constructs an empty comment. + TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {} + /// Construct a comment from text. + TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::COMMENT ) { + SetValue( _value ); + } + TiXmlComment( const TiXmlComment& ); + void operator=( const TiXmlComment& base ); + + virtual ~TiXmlComment() {} + + /// Returns a copy of this Comment. + virtual TiXmlNode* Clone() const; + // Write this Comment to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /* Attribtue parsing starts: at the ! of the !-- + returns: next char past '>' + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* visitor ) const; + +protected: + void CopyTo( TiXmlComment* target ) const; + + // used to be public + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif +// virtual void StreamOut( TIXML_OSTREAM * out ) const; + +private: + +}; + + +/** XML text. A text node can have 2 ways to output the next. "normal" output + and CDATA. It will default to the mode it was parsed from the XML file and + you generally want to leave it alone, but you can change the output mode with + SetCDATA() and query it with CDATA(). +*/ +class TiXmlText : public TiXmlNode +{ + friend class TiXmlElement; +public: + /** Constructor for text element. By default, it is treated as + normal, encoded text. If you want it be output as a CDATA text + element, set the parameter _cdata to 'true' + */ + TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TEXT) + { + SetValue( initValue ); + cdata = false; + } + virtual ~TiXmlText() {} + + #ifdef TIXML_USE_STL + /// Constructor. + TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT) + { + SetValue( initValue ); + cdata = false; + } + #endif + + TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT ) { copy.CopyTo( this ); } + void operator=( const TiXmlText& base ) { base.CopyTo( this ); } + + // Write this text object to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /// Queries whether this represents text using a CDATA section. + bool CDATA() const { return cdata; } + /// Turns on or off a CDATA representation of text. + void SetCDATA( bool _cdata ) { cdata = _cdata; } + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlText* ToText() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* content ) const; + +protected : + /// [internal use] Creates a new Element and returns it. + virtual TiXmlNode* Clone() const; + void CopyTo( TiXmlText* target ) const; + + bool Blank() const; // returns true if all white space and new lines + // [internal use] + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + bool cdata; // true if this should be input and output as a CDATA style text element +}; + + +/** In correct XML the declaration is the first entry in the file. + @verbatim + + @endverbatim + + TinyXml will happily read or write files without a declaration, + however. There are 3 possible attributes to the declaration: + version, encoding, and standalone. + + Note: In this version of the code, the attributes are + handled as special cases, not generic attributes, simply + because there can only be at most 3 and they are always the same. +*/ +class TiXmlDeclaration : public TiXmlNode +{ +public: + /// Construct an empty declaration. + TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {} + +#ifdef TIXML_USE_STL + /// Constructor. + TiXmlDeclaration( const std::string& _version, + const std::string& _encoding, + const std::string& _standalone ); +#endif + + /// Construct. + TiXmlDeclaration( const char* _version, + const char* _encoding, + const char* _standalone ); + + TiXmlDeclaration( const TiXmlDeclaration& copy ); + void operator=( const TiXmlDeclaration& copy ); + + virtual ~TiXmlDeclaration() {} + + /// Version. Will return an empty string if none was found. + const char *Version() const { return version.c_str (); } + /// Encoding. Will return an empty string if none was found. + const char *Encoding() const { return encoding.c_str (); } + /// Is this a standalone document? + const char *Standalone() const { return standalone.c_str (); } + + /// Creates a copy of this Declaration and returns it. + virtual TiXmlNode* Clone() const; + // Print this declaration to a FILE stream. + virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; + virtual void Print( FILE* cfile, int depth ) const { + Print( cfile, depth, 0 ); + } + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlDeclaration* ToDeclaration() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* visitor ) const; + +protected: + void CopyTo( TiXmlDeclaration* target ) const; + // used to be public + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + + TIXML_STRING version; + TIXML_STRING encoding; + TIXML_STRING standalone; +}; + + +/** Any tag that tinyXml doesn't recognize is saved as an + unknown. It is a tag of text, but should not be modified. + It will be written back to the XML, unchanged, when the file + is saved. + + DTD tags get thrown into TiXmlUnknowns. +*/ +class TiXmlUnknown : public TiXmlNode +{ +public: + TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {} + virtual ~TiXmlUnknown() {} + + TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN ) { copy.CopyTo( this ); } + void operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); } + + /// Creates a copy of this Unknown and returns it. + virtual TiXmlNode* Clone() const; + // Print this Unknown to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* content ) const; + +protected: + void CopyTo( TiXmlUnknown* target ) const; + + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + +}; + + +/** Always the top level node. A document binds together all the + XML pieces. It can be saved, loaded, and printed to the screen. + The 'value' of a document node is the xml file name. +*/ +class TiXmlDocument : public TiXmlNode +{ +public: + /// Create an empty document, that has no name. + TiXmlDocument(); + /// Create a document with a name. The name of the document is also the filename of the xml. + TiXmlDocument( const char * documentName ); + + #ifdef TIXML_USE_STL + /// Constructor. + TiXmlDocument( const std::string& documentName ); + #endif + + TiXmlDocument( const TiXmlDocument& copy ); + void operator=( const TiXmlDocument& copy ); + + virtual ~TiXmlDocument() {} + + /** Load a file using the current document value. + Returns true if successful. Will delete any existing + document data before loading. + */ + bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the current document value. Returns true if successful. + bool SaveFile() const; + /// Load a file using the given filename. Returns true if successful. + bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the given filename. Returns true if successful. + bool SaveFile( const char * filename ) const; + /** Load a file using the given FILE*. Returns true if successful. Note that this method + doesn't stream - the entire object pointed at by the FILE* + will be interpreted as an XML file. TinyXML doesn't stream in XML from the current + file location. Streaming may be added in the future. + */ + bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the given FILE*. Returns true if successful. + bool SaveFile( FILE* ) const; + + #ifdef TIXML_USE_STL + bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. + { +// StringToBuffer f( filename ); +// return ( f.buffer && LoadFile( f.buffer, encoding )); + return LoadFile( filename.c_str(), encoding ); + } + bool SaveFile( const std::string& filename ) const ///< STL std::string version. + { +// StringToBuffer f( filename ); +// return ( f.buffer && SaveFile( f.buffer )); + return SaveFile( filename.c_str() ); + } + #endif + + /** Parse the given null terminated block of xml data. Passing in an encoding to this + method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml + to use that encoding, regardless of what TinyXml might otherwise try to detect. + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + + /** Get the root element -- the only top level element -- of the document. + In well formed XML, there should only be one. TinyXml is tolerant of + multiple elements at the document level. + */ + const TiXmlElement* RootElement() const { return FirstChildElement(); } + TiXmlElement* RootElement() { return FirstChildElement(); } + + /** If an error occurs, Error will be set to true. Also, + - The ErrorId() will contain the integer identifier of the error (not generally useful) + - The ErrorDesc() method will return the name of the error. (very useful) + - The ErrorRow() and ErrorCol() will return the location of the error (if known) + */ + bool Error() const { return error; } + + /// Contains a textual (english) description of the error if one occurs. + const char * ErrorDesc() const { return errorDesc.c_str (); } + + /** Generally, you probably want the error string ( ErrorDesc() ). But if you + prefer the ErrorId, this function will fetch it. + */ + int ErrorId() const { return errorId; } + + /** Returns the location (if known) of the error. The first column is column 1, + and the first row is row 1. A value of 0 means the row and column wasn't applicable + (memory errors, for example, have no row/column) or the parser lost the error. (An + error in the error reporting, in that case.) + + @sa SetTabSize, Row, Column + */ + int ErrorRow() const { return errorLocation.row+1; } + int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() + + /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol()) + to report the correct values for row and column. It does not change the output + or input in any way. + + By calling this method, with a tab size + greater than 0, the row and column of each node and attribute is stored + when the file is loaded. Very useful for tracking the DOM back in to + the source file. + + The tab size is required for calculating the location of nodes. If not + set, the default of 4 is used. The tabsize is set per document. Setting + the tabsize to 0 disables row/column tracking. + + Note that row and column tracking is not supported when using operator>>. + + The tab size needs to be enabled before the parse or load. Correct usage: + @verbatim + TiXmlDocument doc; + doc.SetTabSize( 8 ); + doc.Load( "myfile.xml" ); + @endverbatim + + @sa Row, Column + */ + void SetTabSize( int _tabsize ) { tabsize = _tabsize; } + + int TabSize() const { return tabsize; } + + /** If you have handled the error, it can be reset with this call. The error + state is automatically cleared if you Parse a new XML block. + */ + void ClearError() { error = false; + errorId = 0; + errorDesc = ""; + errorLocation.row = errorLocation.col = 0; + //errorLocation.last = 0; + } + + /** Write the document to standard out using formatted printing ("pretty print"). */ + void Print() const { Print( stdout, 0 ); } + + /* Write the document to a string using formatted printing ("pretty print"). This + will allocate a character array (new char[]) and return it as a pointer. The + calling code pust call delete[] on the return char* to avoid a memory leak. + */ + //char* PrintToMemory() const; + + /// Print this Document to a FILE stream. + virtual void Print( FILE* cfile, int depth = 0 ) const; + // [internal use] + void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); + + virtual const TiXmlDocument* ToDocument() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlDocument* ToDocument() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* content ) const; + +protected : + // [internal use] + virtual TiXmlNode* Clone() const; + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + void CopyTo( TiXmlDocument* target ) const; + + bool error; + int errorId; + TIXML_STRING errorDesc; + int tabsize; + TiXmlCursor errorLocation; + bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write. +}; + + +/** + A TiXmlHandle is a class that wraps a node pointer with null checks; this is + an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml + DOM structure. It is a separate utility class. + + Take an example: + @verbatim + + + + + + + @endverbatim + + Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very + easy to write a *lot* of code that looks like: + + @verbatim + TiXmlElement* root = document.FirstChildElement( "Document" ); + if ( root ) + { + TiXmlElement* element = root->FirstChildElement( "Element" ); + if ( element ) + { + TiXmlElement* child = element->FirstChildElement( "Child" ); + if ( child ) + { + TiXmlElement* child2 = child->NextSiblingElement( "Child" ); + if ( child2 ) + { + // Finally do something useful. + @endverbatim + + And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity + of such code. A TiXmlHandle checks for null pointers so it is perfectly safe + and correct to use: + + @verbatim + TiXmlHandle docHandle( &document ); + TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); + if ( child2 ) + { + // do something useful + @endverbatim + + Which is MUCH more concise and useful. + + It is also safe to copy handles - internally they are nothing more than node pointers. + @verbatim + TiXmlHandle handleCopy = handle; + @endverbatim + + What they should not be used for is iteration: + + @verbatim + int i=0; + while ( true ) + { + TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement(); + if ( !child ) + break; + // do something + ++i; + } + @endverbatim + + It seems reasonable, but it is in fact two embedded while loops. The Child method is + a linear walk to find the element, so this code would iterate much more than it needs + to. Instead, prefer: + + @verbatim + TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement(); + + for( child; child; child=child->NextSiblingElement() ) + { + // do something + } + @endverbatim +*/ +class TiXmlHandle +{ +public: + /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. + TiXmlHandle( TiXmlNode* _node ) { this->node = _node; } + /// Copy constructor + TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } + TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; } + + /// Return a handle to the first child node. + TiXmlHandle FirstChild() const; + /// Return a handle to the first child node with the given name. + TiXmlHandle FirstChild( const char * value ) const; + /// Return a handle to the first child element. + TiXmlHandle FirstChildElement() const; + /// Return a handle to the first child element with the given name. + TiXmlHandle FirstChildElement( const char * value ) const; + + /** Return a handle to the "index" child with the given name. + The first child is 0, the second 1, etc. + */ + TiXmlHandle Child( const char* value, int index ) const; + /** Return a handle to the "index" child. + The first child is 0, the second 1, etc. + */ + TiXmlHandle Child( int index ) const; + /** Return a handle to the "index" child element with the given name. + The first child element is 0, the second 1, etc. Note that only TiXmlElements + are indexed: other types are not counted. + */ + TiXmlHandle ChildElement( const char* value, int index ) const; + /** Return a handle to the "index" child element. + The first child element is 0, the second 1, etc. Note that only TiXmlElements + are indexed: other types are not counted. + */ + TiXmlHandle ChildElement( int index ) const; + + #ifdef TIXML_USE_STL + TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } + TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } + + TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } + TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } + #endif + + /** Return the handle as a TiXmlNode. This may return null. + */ + TiXmlNode* ToNode() const { return node; } + /** Return the handle as a TiXmlElement. This may return null. + */ + TiXmlElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } + /** Return the handle as a TiXmlText. This may return null. + */ + TiXmlText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } + /** Return the handle as a TiXmlUnknown. This may return null. + */ + TiXmlUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } + + /** @deprecated use ToNode. + Return the handle as a TiXmlNode. This may return null. + */ + TiXmlNode* Node() const { return ToNode(); } + /** @deprecated use ToElement. + Return the handle as a TiXmlElement. This may return null. + */ + TiXmlElement* Element() const { return ToElement(); } + /** @deprecated use ToText() + Return the handle as a TiXmlText. This may return null. + */ + TiXmlText* Text() const { return ToText(); } + /** @deprecated use ToUnknown() + Return the handle as a TiXmlUnknown. This may return null. + */ + TiXmlUnknown* Unknown() const { return ToUnknown(); } + +private: + TiXmlNode* node; +}; + + +/** Print to memory functionality. The TiXmlPrinter is useful when you need to: + + -# Print to memory (especially in non-STL mode) + -# Control formatting (line endings, etc.) + + When constructed, the TiXmlPrinter is in its default "pretty printing" mode. + Before calling Accept() you can call methods to control the printing + of the XML document. After TiXmlNode::Accept() is called, the printed document can + be accessed via the CStr(), Str(), and Size() methods. + + TiXmlPrinter uses the Visitor API. + @verbatim + TiXmlPrinter printer; + printer.SetIndent( "\t" ); + + doc.Accept( &printer ); + fprintf( stdout, "%s", printer.CStr() ); + @endverbatim +*/ +class TiXmlPrinter : public TiXmlVisitor +{ +public: + TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ), + buffer(), indent( " " ), lineBreak( "\n" ) {} + + virtual bool VisitEnter( const TiXmlDocument& doc ); + virtual bool VisitExit( const TiXmlDocument& doc ); + + virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ); + virtual bool VisitExit( const TiXmlElement& element ); + + virtual bool Visit( const TiXmlDeclaration& declaration ); + virtual bool Visit( const TiXmlText& text ); + virtual bool Visit( const TiXmlComment& comment ); + virtual bool Visit( const TiXmlUnknown& unknown ); + + /** Set the indent characters for printing. By default 4 spaces + but tab (\t) is also useful, or null/empty string for no indentation. + */ + void SetIndent( const char* _indent ) { indent = _indent ? _indent : "" ; } + /// Query the indention string. + const char* Indent() { return indent.c_str(); } + /** Set the line breaking string. By default set to newline (\n). + Some operating systems prefer other characters, or can be + set to the null/empty string for no indenation. + */ + void SetLineBreak( const char* _lineBreak ) { lineBreak = _lineBreak ? _lineBreak : ""; } + /// Query the current line breaking string. + const char* LineBreak() { return lineBreak.c_str(); } + + /** Switch over to "stream printing" which is the most dense formatting without + linebreaks. Common when the XML is needed for network transmission. + */ + void SetStreamPrinting() { indent = ""; + lineBreak = ""; + } + /// Return the result. + const char* CStr() { return buffer.c_str(); } + /// Return the length of the result string. + size_t Size() { return buffer.size(); } + + #ifdef TIXML_USE_STL + /// Return the result. + const std::string& Str() { return buffer; } + #endif + +private: + void DoIndent() { + for( int i=0; i -#include - -#include "tinyxml.h" - -//#define DEBUG_PARSER -#if defined( DEBUG_PARSER ) -# if defined( DEBUG ) && defined( _MSC_VER ) -# include -# define TIXML_LOG OutputDebugString -# else -# define TIXML_LOG printf -# endif -#endif - -// Note tha "PutString" hardcodes the same list. This -// is less flexible than it appears. Changing the entries -// or order will break putstring. -TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = -{ - { "&", 5, '&' }, - { "<", 4, '<' }, - { ">", 4, '>' }, - { """, 6, '\"' }, - { "'", 6, '\'' } -}; - -// Bunch of unicode info at: -// http://www.unicode.org/faq/utf_bom.html -// Including the basic of this table, which determines the #bytes in the -// sequence from the lead byte. 1 placed for invalid sequences -- -// although the result will be junk, pass it through as much as possible. -// Beware of the non-characters in UTF-8: -// ef bb bf (Microsoft "lead bytes") -// ef bf be -// ef bf bf - -const unsigned char TIXML_UTF_LEAD_0 = 0xefU; -const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; -const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; - -const int TiXmlBase::utf8ByteTable[256] = -{ - // 0 1 2 3 4 5 6 7 8 9 a b c d e f - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 - 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte - 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid -}; - - -void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) -{ - const unsigned long BYTE_MASK = 0xBF; - const unsigned long BYTE_MARK = 0x80; - const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - - if (input < 0x80) - *length = 1; - else if ( input < 0x800 ) - *length = 2; - else if ( input < 0x10000 ) - *length = 3; - else if ( input < 0x200000 ) - *length = 4; - else - { *length = 0; return; } // This code won't covert this correctly anyway. - - output += *length; - - // Scary scary fall throughs. - switch (*length) - { - case 4: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 3: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 2: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 1: - --output; - *output = (char)(input | FIRST_BYTE_MARK[*length]); - } -} - - -/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) -{ - // This will only work for low-ascii, everything else is assumed to be a valid - // letter. I'm not sure this is the best approach, but it is quite tricky trying - // to figure out alhabetical vs. not across encoding. So take a very - // conservative approach. - -// if ( encoding == TIXML_ENCODING_UTF8 ) -// { - if ( anyByte < 127 ) - return isalpha( anyByte ); - else - return 1; // What else to do? The unicode set is huge...get the english ones right. -// } -// else -// { -// return isalpha( anyByte ); -// } -} - - -/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) -{ - // This will only work for low-ascii, everything else is assumed to be a valid - // letter. I'm not sure this is the best approach, but it is quite tricky trying - // to figure out alhabetical vs. not across encoding. So take a very - // conservative approach. - -// if ( encoding == TIXML_ENCODING_UTF8 ) -// { - if ( anyByte < 127 ) - return isalnum( anyByte ); - else - return 1; // What else to do? The unicode set is huge...get the english ones right. -// } -// else -// { -// return isalnum( anyByte ); -// } -} - - -class TiXmlParsingData -{ - friend class TiXmlDocument; - public: - void Stamp( const char* now, TiXmlEncoding encoding ); - - const TiXmlCursor& Cursor() { return cursor; } - - private: - // Only used by the document! - TiXmlParsingData( const char* start, int _tabsize, int row, int col ) - { - assert( start ); - stamp = start; - tabsize = _tabsize; - cursor.row = row; - cursor.col = col; - } - - TiXmlCursor cursor; - const char* stamp; - int tabsize; -}; - - -void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) -{ - assert( now ); - - // Do nothing if the tabsize is 0. - if ( tabsize < 1 ) - { - return; - } - - // Get the current row, column. - int row = cursor.row; - int col = cursor.col; - const char* p = stamp; - assert( p ); - - while ( p < now ) - { - // Treat p as unsigned, so we have a happy compiler. - const unsigned char* pU = (const unsigned char*)p; - - // Code contributed by Fletcher Dunn: (modified by lee) - switch (*pU) { - case 0: - // We *should* never get here, but in case we do, don't - // advance past the terminating null character, ever - return; - - case '\r': - // bump down to the next line - ++row; - col = 0; - // Eat the character - ++p; - - // Check for \r\n sequence, and treat this as a single character - if (*p == '\n') { - ++p; - } - break; - - case '\n': - // bump down to the next line - ++row; - col = 0; - - // Eat the character - ++p; - - // Check for \n\r sequence, and treat this as a single - // character. (Yes, this bizarre thing does occur still - // on some arcane platforms...) - if (*p == '\r') { - ++p; - } - break; - - case '\t': - // Eat the character - ++p; - - // Skip to next tab stop - col = (col / tabsize + 1) * tabsize; - break; - - case TIXML_UTF_LEAD_0: - if ( encoding == TIXML_ENCODING_UTF8 ) - { - if ( *(p+1) && *(p+2) ) - { - // In these cases, don't advance the column. These are - // 0-width spaces. - if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) - p += 3; - else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) - p += 3; - else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) - p += 3; - else - { p +=3; ++col; } // A normal character. - } - } - else - { - ++p; - ++col; - } - break; - - default: - if ( encoding == TIXML_ENCODING_UTF8 ) - { - // Eat the 1 to 4 byte utf8 character. - int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; - if ( step == 0 ) - step = 1; // Error case from bad encoding, but handle gracefully. - p += step; - - // Just advance one column, of course. - ++col; - } - else - { - ++p; - ++col; - } - break; - } - } - cursor.row = row; - cursor.col = col; - assert( cursor.row >= -1 ); - assert( cursor.col >= -1 ); - stamp = p; - assert( stamp ); -} - - -const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) -{ - if ( !p || !*p ) - { - return 0; - } - if ( encoding == TIXML_ENCODING_UTF8 ) - { - while ( *p ) - { - const unsigned char* pU = (const unsigned char*)p; - - // Skip the stupid Microsoft UTF-8 Byte order marks - if ( *(pU+0)==TIXML_UTF_LEAD_0 - && *(pU+1)==TIXML_UTF_LEAD_1 - && *(pU+2)==TIXML_UTF_LEAD_2 ) - { - p += 3; - continue; - } - else if(*(pU+0)==TIXML_UTF_LEAD_0 - && *(pU+1)==0xbfU - && *(pU+2)==0xbeU ) - { - p += 3; - continue; - } - else if(*(pU+0)==TIXML_UTF_LEAD_0 - && *(pU+1)==0xbfU - && *(pU+2)==0xbfU ) - { - p += 3; - continue; - } - - if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) // Still using old rules for white space. - ++p; - else - break; - } - } - else - { - while ( *p && IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) - ++p; - } - - return p; -} - -#ifdef TIXML_USE_STL -/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ) -{ - for( ;; ) - { - if ( !in->good() ) return false; - - int c = in->peek(); - // At this scope, we can't get to a document. So fail silently. - if ( !IsWhiteSpace( c ) || c <= 0 ) - return true; - - *tag += (char) in->get(); - } -} - -/*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag ) -{ - //assert( character > 0 && character < 128 ); // else it won't work in utf-8 - while ( in->good() ) - { - int c = in->peek(); - if ( c == character ) - return true; - if ( c <= 0 ) // Silent failure: can't get document at this scope - return false; - - in->get(); - *tag += (char) c; - } - return false; -} -#endif - -// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The -// "assign" optimization removes over 10% of the execution time. -// -const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) -{ - // Oddly, not supported on some comilers, - //name->clear(); - // So use this: - *name = ""; - assert( p ); - - // Names start with letters or underscores. - // Of course, in unicode, tinyxml has no idea what a letter *is*. The - // algorithm is generous. - // - // After that, they can be letters, underscores, numbers, - // hyphens, or colons. (Colons are valid ony for namespaces, - // but tinyxml can't tell namespaces from names.) - if ( p && *p - && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) - { - const char* start = p; - while( p && *p - && ( IsAlphaNum( (unsigned char ) *p, encoding ) - || *p == '_' - || *p == '-' - || *p == '.' - || *p == ':' ) ) - { - //(*name) += *p; // expensive - ++p; - } - if ( p-start > 0 ) { - name->assign( start, p-start ); - } - return p; - } - return 0; -} - -const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) -{ - // Presume an entity, and pull it out. - TIXML_STRING ent; - int i; - *length = 0; - - if ( *(p+1) && *(p+1) == '#' && *(p+2) ) - { - unsigned long ucs = 0; - ptrdiff_t delta = 0; - unsigned mult = 1; - - if ( *(p+2) == 'x' ) - { - // Hexadecimal. - if ( !*(p+3) ) return 0; - - const char* q = p+3; - q = strchr( q, ';' ); - - if ( !q || !*q ) return 0; - - delta = q-p; - --q; - - while ( *q != 'x' ) - { - if ( *q >= '0' && *q <= '9' ) - ucs += mult * (*q - '0'); - else if ( *q >= 'a' && *q <= 'f' ) - ucs += mult * (*q - 'a' + 10); - else if ( *q >= 'A' && *q <= 'F' ) - ucs += mult * (*q - 'A' + 10 ); - else - return 0; - mult *= 16; - --q; - } - } - else - { - // Decimal. - if ( !*(p+2) ) return 0; - - const char* q = p+2; - q = strchr( q, ';' ); - - if ( !q || !*q ) return 0; - - delta = q-p; - --q; - - while ( *q != '#' ) - { - if ( *q >= '0' && *q <= '9' ) - ucs += mult * (*q - '0'); - else - return 0; - mult *= 10; - --q; - } - } - if ( encoding == TIXML_ENCODING_UTF8 ) - { - // convert the UCS to UTF-8 - ConvertUTF32ToUTF8( ucs, value, length ); - } - else - { - *value = (char)ucs; - *length = 1; - } - return p + delta + 1; - } - - // Now try to match it. - for( i=0; iappend( cArr, len ); - } - } - else - { - bool whitespace = false; - - // Remove leading white space: - p = SkipWhiteSpace( p, encoding ); - while ( p && *p - && !StringEqual( p, endTag, caseInsensitive, encoding ) ) - { - if ( *p == '\r' || *p == '\n' ) - { - whitespace = true; - ++p; - } - else if ( IsWhiteSpace( *p ) ) - { - whitespace = true; - ++p; - } - else - { - // If we've found whitespace, add it before the - // new character. Any whitespace just becomes a space. - if ( whitespace ) - { - (*text) += ' '; - whitespace = false; - } - int len; - char cArr[4] = { 0, 0, 0, 0 }; - p = GetChar( p, cArr, &len, encoding ); - if ( len == 1 ) - (*text) += cArr[0]; // more efficient - else - text->append( cArr, len ); - } - } - } - if ( p ) - p += strlen( endTag ); - return p; -} - -#ifdef TIXML_USE_STL - -void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) -{ - // The basic issue with a document is that we don't know what we're - // streaming. Read something presumed to be a tag (and hope), then - // identify it, and call the appropriate stream method on the tag. - // - // This "pre-streaming" will never read the closing ">" so the - // sub-tag can orient itself. - - if ( !StreamTo( in, '<', tag ) ) - { - SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - - while ( in->good() ) - { - int tagIndex = (int) tag->length(); - while ( in->good() && in->peek() != '>' ) - { - int c = in->get(); - if ( c <= 0 ) - { - SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - break; - } - (*tag) += (char) c; - } - - if ( in->good() ) - { - // We now have something we presume to be a node of - // some sort. Identify it, and call the node to - // continue streaming. - TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); - - if ( node ) - { - node->StreamIn( in, tag ); - bool isElement = node->ToElement() != 0; - delete node; - node = 0; - - // If this is the root element, we're done. Parsing will be - // done by the >> operator. - if ( isElement ) - { - return; - } - } - else - { - SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - } - } - // We should have returned sooner. - SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); -} - -#endif - -const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) -{ - ClearError(); - - // Parse away, at the document level. Since a document - // contains nothing but other tags, most of what happens - // here is skipping white space. - if ( !p || !*p ) - { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - // Note that, for a document, this needs to come - // before the while space skip, so that parsing - // starts from the pointer we are given. - location.Clear(); - if ( prevData ) - { - location.row = prevData->cursor.row; - location.col = prevData->cursor.col; - } - else - { - location.row = 0; - location.col = 0; - } - TiXmlParsingData data( p, TabSize(), location.row, location.col ); - location = data.Cursor(); - - if ( encoding == TIXML_ENCODING_UNKNOWN ) - { - // Check for the Microsoft UTF-8 lead bytes. - const unsigned char* pU = (const unsigned char*)p; - if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0 - && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1 - && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 ) - { - encoding = TIXML_ENCODING_UTF8; - useMicrosoftBOM = true; - } - } - - p = SkipWhiteSpace( p, encoding ); - if ( !p ) - { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - while ( p && *p ) - { - TiXmlNode* node = Identify( p, encoding ); - if ( node ) - { - p = node->Parse( p, &data, encoding ); - LinkEndChild( node ); - } - else - { - break; - } - - // Did we get encoding info? - if ( encoding == TIXML_ENCODING_UNKNOWN - && node->ToDeclaration() ) - { - TiXmlDeclaration* dec = node->ToDeclaration(); - const char* enc = dec->Encoding(); - assert( enc ); - - if ( *enc == 0 ) - encoding = TIXML_ENCODING_UTF8; - else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) - encoding = TIXML_ENCODING_UTF8; - else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) - encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice - else - encoding = TIXML_ENCODING_LEGACY; - } - - p = SkipWhiteSpace( p, encoding ); - } - - // Was this empty? - if ( !firstChild ) { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); - return 0; - } - - // All is well. - return p; -} - -void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) -{ - // The first error in a chain is more accurate - don't set again! - if ( error ) - return; - - assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); - error = true; - errorId = err; - errorDesc = errorString[ errorId ]; - - errorLocation.Clear(); - if ( pError && data ) - { - data->Stamp( pError, encoding ); - errorLocation = data->Cursor(); - } -} - - -TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) -{ - TiXmlNode* returnNode = 0; - - p = SkipWhiteSpace( p, encoding ); - if( !p || !*p || *p != '<' ) - { - return 0; - } - - TiXmlDocument* doc = GetDocument(); - p = SkipWhiteSpace( p, encoding ); - - if ( !p || !*p ) - { - return 0; - } - - // What is this thing? - // - Elements start with a letter or underscore, but xml is reserved. - // - Comments: "; - - if ( !StringEqual( p, startTag, false, encoding ) ) - { - document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); - return 0; - } - p += strlen( startTag ); - p = ReadText( p, &value, false, endTag, false, encoding ); - return p; -} - - -const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) -{ - p = SkipWhiteSpace( p, encoding ); - if ( !p || !*p ) return 0; - -// int tabsize = 4; -// if ( document ) -// tabsize = document->TabSize(); - - if ( data ) - { - data->Stamp( p, encoding ); - location = data->Cursor(); - } - // Read the name, the '=' and the value. - const char* pErr = p; - p = ReadName( p, &name, encoding ); - if ( !p || !*p ) - { - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); - return 0; - } - p = SkipWhiteSpace( p, encoding ); - if ( !p || !*p || *p != '=' ) - { - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); - return 0; - } - - ++p; // skip '=' - p = SkipWhiteSpace( p, encoding ); - if ( !p || !*p ) - { - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); - return 0; - } - - const char* end; - const char SINGLE_QUOTE = '\''; - const char DOUBLE_QUOTE = '\"'; - - if ( *p == SINGLE_QUOTE ) - { - ++p; - end = "\'"; // single quote in string - p = ReadText( p, &value, false, end, false, encoding ); - } - else if ( *p == DOUBLE_QUOTE ) - { - ++p; - end = "\""; // double quote in string - p = ReadText( p, &value, false, end, false, encoding ); - } - else - { - // All attribute values should be in single or double quotes. - // But this is such a common error that the parser will try - // its best, even without them. - value = ""; - while ( p && *p // existence - && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r' // whitespace - && *p != '/' && *p != '>' ) // tag end - { - if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { - // [ 1451649 ] Attribute values with trailing quotes not handled correctly - // We did not have an opening quote but seem to have a - // closing one. Give up and throw an error. - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); - return 0; - } - value += *p; - ++p; - } - } - return p; -} - -#ifdef TIXML_USE_STL -void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag ) -{ - while ( in->good() ) - { - int c = in->peek(); - if ( !cdata && (c == '<' ) ) - { - return; - } - if ( c <= 0 ) - { - TiXmlDocument* document = GetDocument(); - if ( document ) - document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - - (*tag) += (char) c; - in->get(); // "commits" the peek made above - - if ( cdata && c == '>' && tag->size() >= 3 ) { - size_t len = tag->size(); - if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { - // terminator of cdata. - return; - } - } - } -} -#endif - -const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) -{ - value = ""; - TiXmlDocument* document = GetDocument(); - - if ( data ) - { - data->Stamp( p, encoding ); - location = data->Cursor(); - } - - const char* const startTag = ""; - - if ( cdata || StringEqual( p, startTag, false, encoding ) ) - { - cdata = true; - - if ( !StringEqual( p, startTag, false, encoding ) ) - { - document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); - return 0; - } - p += strlen( startTag ); - - // Keep all the white space, ignore the encoding, etc. - while ( p && *p - && !StringEqual( p, endTag, false, encoding ) - ) - { - value += *p; - ++p; - } - - TIXML_STRING dummy; - p = ReadText( p, &dummy, false, endTag, false, encoding ); - return p; - } - else - { - bool ignoreWhite = true; - - const char* end = "<"; - p = ReadText( p, &value, ignoreWhite, end, false, encoding ); - if ( p ) - return p-1; // don't truncate the '<' - return 0; - } -} - -#ifdef TIXML_USE_STL -void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag ) -{ - while ( in->good() ) - { - int c = in->get(); - if ( c <= 0 ) - { - TiXmlDocument* document = GetDocument(); - if ( document ) - document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - (*tag) += (char) c; - - if ( c == '>' ) - { - // All is well. - return; - } - } -} -#endif - -const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) -{ - p = SkipWhiteSpace( p, _encoding ); - // Find the beginning, find the end, and look for - // the stuff in-between. - TiXmlDocument* document = GetDocument(); - if ( !p || !*p || !StringEqual( p, "SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); - return 0; - } - if ( data ) - { - data->Stamp( p, _encoding ); - location = data->Cursor(); - } - p += 5; - - version = ""; - encoding = ""; - standalone = ""; - - while ( p && *p ) - { - if ( *p == '>' ) - { - ++p; - return p; - } - - p = SkipWhiteSpace( p, _encoding ); - if ( StringEqual( p, "version", true, _encoding ) ) - { - TiXmlAttribute attrib; - p = attrib.Parse( p, data, _encoding ); - version = attrib.Value(); - } - else if ( StringEqual( p, "encoding", true, _encoding ) ) - { - TiXmlAttribute attrib; - p = attrib.Parse( p, data, _encoding ); - encoding = attrib.Value(); - } - else if ( StringEqual( p, "standalone", true, _encoding ) ) - { - TiXmlAttribute attrib; - p = attrib.Parse( p, data, _encoding ); - standalone = attrib.Value(); - } - else - { - // Read over whatever it is. - while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) - ++p; - } - } - return 0; -} - -bool TiXmlText::Blank() const -{ - for ( unsigned i=0; i +#include + +#include "tinyxml.h" + +//#define DEBUG_PARSER +#if defined( DEBUG_PARSER ) +# if defined( DEBUG ) && defined( _MSC_VER ) +# include +# define TIXML_LOG OutputDebugString +# else +# define TIXML_LOG printf +# endif +#endif + +// Note tha "PutString" hardcodes the same list. This +// is less flexible than it appears. Changing the entries +// or order will break putstring. +TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = +{ + { "&", 5, '&' }, + { "<", 4, '<' }, + { ">", 4, '>' }, + { """, 6, '\"' }, + { "'", 6, '\'' } +}; + +// Bunch of unicode info at: +// http://www.unicode.org/faq/utf_bom.html +// Including the basic of this table, which determines the #bytes in the +// sequence from the lead byte. 1 placed for invalid sequences -- +// although the result will be junk, pass it through as much as possible. +// Beware of the non-characters in UTF-8: +// ef bb bf (Microsoft "lead bytes") +// ef bf be +// ef bf bf + +const unsigned char TIXML_UTF_LEAD_0 = 0xefU; +const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; +const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + +const int TiXmlBase::utf8ByteTable[256] = +{ + // 0 1 2 3 4 5 6 7 8 9 a b c d e f + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 + 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte + 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid +}; + + +void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) +{ + const unsigned long BYTE_MASK = 0xBF; + const unsigned long BYTE_MARK = 0x80; + const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + if (input < 0x80) + *length = 1; + else if ( input < 0x800 ) + *length = 2; + else if ( input < 0x10000 ) + *length = 3; + else if ( input < 0x200000 ) + *length = 4; + else + { *length = 0; return; } // This code won't covert this correctly anyway. + + output += *length; + + // Scary scary fall throughs. + switch (*length) + { + case 4: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 3: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 2: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 1: + --output; + *output = (char)(input | FIRST_BYTE_MARK[*length]); + } +} + + +/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) +{ + // This will only work for low-ascii, everything else is assumed to be a valid + // letter. I'm not sure this is the best approach, but it is quite tricky trying + // to figure out alhabetical vs. not across encoding. So take a very + // conservative approach. + +// if ( encoding == TIXML_ENCODING_UTF8 ) +// { + if ( anyByte < 127 ) + return isalpha( anyByte ); + else + return 1; // What else to do? The unicode set is huge...get the english ones right. +// } +// else +// { +// return isalpha( anyByte ); +// } +} + + +/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) +{ + // This will only work for low-ascii, everything else is assumed to be a valid + // letter. I'm not sure this is the best approach, but it is quite tricky trying + // to figure out alhabetical vs. not across encoding. So take a very + // conservative approach. + +// if ( encoding == TIXML_ENCODING_UTF8 ) +// { + if ( anyByte < 127 ) + return isalnum( anyByte ); + else + return 1; // What else to do? The unicode set is huge...get the english ones right. +// } +// else +// { +// return isalnum( anyByte ); +// } +} + + +class TiXmlParsingData +{ + friend class TiXmlDocument; + public: + void Stamp( const char* now, TiXmlEncoding encoding ); + + const TiXmlCursor& Cursor() { return cursor; } + + private: + // Only used by the document! + TiXmlParsingData( const char* start, int _tabsize, int row, int col ) + { + assert( start ); + stamp = start; + tabsize = _tabsize; + cursor.row = row; + cursor.col = col; + } + + TiXmlCursor cursor; + const char* stamp; + int tabsize; +}; + + +void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) +{ + assert( now ); + + // Do nothing if the tabsize is 0. + if ( tabsize < 1 ) + { + return; + } + + // Get the current row, column. + int row = cursor.row; + int col = cursor.col; + const char* p = stamp; + assert( p ); + + while ( p < now ) + { + // Treat p as unsigned, so we have a happy compiler. + const unsigned char* pU = (const unsigned char*)p; + + // Code contributed by Fletcher Dunn: (modified by lee) + switch (*pU) { + case 0: + // We *should* never get here, but in case we do, don't + // advance past the terminating null character, ever + return; + + case '\r': + // bump down to the next line + ++row; + col = 0; + // Eat the character + ++p; + + // Check for \r\n sequence, and treat this as a single character + if (*p == '\n') { + ++p; + } + break; + + case '\n': + // bump down to the next line + ++row; + col = 0; + + // Eat the character + ++p; + + // Check for \n\r sequence, and treat this as a single + // character. (Yes, this bizarre thing does occur still + // on some arcane platforms...) + if (*p == '\r') { + ++p; + } + break; + + case '\t': + // Eat the character + ++p; + + // Skip to next tab stop + col = (col / tabsize + 1) * tabsize; + break; + + case TIXML_UTF_LEAD_0: + if ( encoding == TIXML_ENCODING_UTF8 ) + { + if ( *(p+1) && *(p+2) ) + { + // In these cases, don't advance the column. These are + // 0-width spaces. + if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) + p += 3; + else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) + p += 3; + else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) + p += 3; + else + { p +=3; ++col; } // A normal character. + } + } + else + { + ++p; + ++col; + } + break; + + default: + if ( encoding == TIXML_ENCODING_UTF8 ) + { + // Eat the 1 to 4 byte utf8 character. + int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; + if ( step == 0 ) + step = 1; // Error case from bad encoding, but handle gracefully. + p += step; + + // Just advance one column, of course. + ++col; + } + else + { + ++p; + ++col; + } + break; + } + } + cursor.row = row; + cursor.col = col; + assert( cursor.row >= -1 ); + assert( cursor.col >= -1 ); + stamp = p; + assert( stamp ); +} + + +const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) +{ + if ( !p || !*p ) + { + return 0; + } + if ( encoding == TIXML_ENCODING_UTF8 ) + { + while ( *p ) + { + const unsigned char* pU = (const unsigned char*)p; + + // Skip the stupid Microsoft UTF-8 Byte order marks + if ( *(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==TIXML_UTF_LEAD_1 + && *(pU+2)==TIXML_UTF_LEAD_2 ) + { + p += 3; + continue; + } + else if(*(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==0xbfU + && *(pU+2)==0xbeU ) + { + p += 3; + continue; + } + else if(*(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==0xbfU + && *(pU+2)==0xbfU ) + { + p += 3; + continue; + } + + if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) // Still using old rules for white space. + ++p; + else + break; + } + } + else + { + while ( *p && IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) + ++p; + } + + return p; +} + +#ifdef TIXML_USE_STL +/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ) +{ + for( ;; ) + { + if ( !in->good() ) return false; + + int c = in->peek(); + // At this scope, we can't get to a document. So fail silently. + if ( !IsWhiteSpace( c ) || c <= 0 ) + return true; + + *tag += (char) in->get(); + } +} + +/*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag ) +{ + //assert( character > 0 && character < 128 ); // else it won't work in utf-8 + while ( in->good() ) + { + int c = in->peek(); + if ( c == character ) + return true; + if ( c <= 0 ) // Silent failure: can't get document at this scope + return false; + + in->get(); + *tag += (char) c; + } + return false; +} +#endif + +// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The +// "assign" optimization removes over 10% of the execution time. +// +const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) +{ + // Oddly, not supported on some comilers, + //name->clear(); + // So use this: + *name = ""; + assert( p ); + + // Names start with letters or underscores. + // Of course, in unicode, tinyxml has no idea what a letter *is*. The + // algorithm is generous. + // + // After that, they can be letters, underscores, numbers, + // hyphens, or colons. (Colons are valid ony for namespaces, + // but tinyxml can't tell namespaces from names.) + if ( p && *p + && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) + { + const char* start = p; + while( p && *p + && ( IsAlphaNum( (unsigned char ) *p, encoding ) + || *p == '_' + || *p == '-' + || *p == '.' + || *p == ':' ) ) + { + //(*name) += *p; // expensive + ++p; + } + if ( p-start > 0 ) { + name->assign( start, p-start ); + } + return p; + } + return 0; +} + +const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) +{ + // Presume an entity, and pull it out. + TIXML_STRING ent; + int i; + *length = 0; + + if ( *(p+1) && *(p+1) == '#' && *(p+2) ) + { + unsigned long ucs = 0; + ptrdiff_t delta = 0; + unsigned mult = 1; + + if ( *(p+2) == 'x' ) + { + // Hexadecimal. + if ( !*(p+3) ) return 0; + + const char* q = p+3; + q = strchr( q, ';' ); + + if ( !q || !*q ) return 0; + + delta = q-p; + --q; + + while ( *q != 'x' ) + { + if ( *q >= '0' && *q <= '9' ) + ucs += mult * (*q - '0'); + else if ( *q >= 'a' && *q <= 'f' ) + ucs += mult * (*q - 'a' + 10); + else if ( *q >= 'A' && *q <= 'F' ) + ucs += mult * (*q - 'A' + 10 ); + else + return 0; + mult *= 16; + --q; + } + } + else + { + // Decimal. + if ( !*(p+2) ) return 0; + + const char* q = p+2; + q = strchr( q, ';' ); + + if ( !q || !*q ) return 0; + + delta = q-p; + --q; + + while ( *q != '#' ) + { + if ( *q >= '0' && *q <= '9' ) + ucs += mult * (*q - '0'); + else + return 0; + mult *= 10; + --q; + } + } + if ( encoding == TIXML_ENCODING_UTF8 ) + { + // convert the UCS to UTF-8 + ConvertUTF32ToUTF8( ucs, value, length ); + } + else + { + *value = (char)ucs; + *length = 1; + } + return p + delta + 1; + } + + // Now try to match it. + for( i=0; iappend( cArr, len ); + } + } + else + { + bool whitespace = false; + + // Remove leading white space: + p = SkipWhiteSpace( p, encoding ); + while ( p && *p + && !StringEqual( p, endTag, caseInsensitive, encoding ) ) + { + if ( *p == '\r' || *p == '\n' ) + { + whitespace = true; + ++p; + } + else if ( IsWhiteSpace( *p ) ) + { + whitespace = true; + ++p; + } + else + { + // If we've found whitespace, add it before the + // new character. Any whitespace just becomes a space. + if ( whitespace ) + { + (*text) += ' '; + whitespace = false; + } + int len; + char cArr[4] = { 0, 0, 0, 0 }; + p = GetChar( p, cArr, &len, encoding ); + if ( len == 1 ) + (*text) += cArr[0]; // more efficient + else + text->append( cArr, len ); + } + } + } + if ( p ) + p += strlen( endTag ); + return p; +} + +#ifdef TIXML_USE_STL + +void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + // The basic issue with a document is that we don't know what we're + // streaming. Read something presumed to be a tag (and hope), then + // identify it, and call the appropriate stream method on the tag. + // + // This "pre-streaming" will never read the closing ">" so the + // sub-tag can orient itself. + + if ( !StreamTo( in, '<', tag ) ) + { + SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + while ( in->good() ) + { + int tagIndex = (int) tag->length(); + while ( in->good() && in->peek() != '>' ) + { + int c = in->get(); + if ( c <= 0 ) + { + SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + break; + } + (*tag) += (char) c; + } + + if ( in->good() ) + { + // We now have something we presume to be a node of + // some sort. Identify it, and call the node to + // continue streaming. + TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); + + if ( node ) + { + node->StreamIn( in, tag ); + bool isElement = node->ToElement() != 0; + delete node; + node = 0; + + // If this is the root element, we're done. Parsing will be + // done by the >> operator. + if ( isElement ) + { + return; + } + } + else + { + SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + } + } + // We should have returned sooner. + SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); +} + +#endif + +const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) +{ + ClearError(); + + // Parse away, at the document level. Since a document + // contains nothing but other tags, most of what happens + // here is skipping white space. + if ( !p || !*p ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + // Note that, for a document, this needs to come + // before the while space skip, so that parsing + // starts from the pointer we are given. + location.Clear(); + if ( prevData ) + { + location.row = prevData->cursor.row; + location.col = prevData->cursor.col; + } + else + { + location.row = 0; + location.col = 0; + } + TiXmlParsingData data( p, TabSize(), location.row, location.col ); + location = data.Cursor(); + + if ( encoding == TIXML_ENCODING_UNKNOWN ) + { + // Check for the Microsoft UTF-8 lead bytes. + const unsigned char* pU = (const unsigned char*)p; + if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0 + && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1 + && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 ) + { + encoding = TIXML_ENCODING_UTF8; + useMicrosoftBOM = true; + } + } + + p = SkipWhiteSpace( p, encoding ); + if ( !p ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + while ( p && *p ) + { + TiXmlNode* node = Identify( p, encoding ); + if ( node ) + { + p = node->Parse( p, &data, encoding ); + LinkEndChild( node ); + } + else + { + break; + } + + // Did we get encoding info? + if ( encoding == TIXML_ENCODING_UNKNOWN + && node->ToDeclaration() ) + { + TiXmlDeclaration* dec = node->ToDeclaration(); + const char* enc = dec->Encoding(); + assert( enc ); + + if ( *enc == 0 ) + encoding = TIXML_ENCODING_UTF8; + else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) + encoding = TIXML_ENCODING_UTF8; + else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) + encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice + else + encoding = TIXML_ENCODING_LEGACY; + } + + p = SkipWhiteSpace( p, encoding ); + } + + // Was this empty? + if ( !firstChild ) { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); + return 0; + } + + // All is well. + return p; +} + +void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + // The first error in a chain is more accurate - don't set again! + if ( error ) + return; + + assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); + error = true; + errorId = err; + errorDesc = errorString[ errorId ]; + + errorLocation.Clear(); + if ( pError && data ) + { + data->Stamp( pError, encoding ); + errorLocation = data->Cursor(); + } +} + + +TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) +{ + TiXmlNode* returnNode = 0; + + p = SkipWhiteSpace( p, encoding ); + if( !p || !*p || *p != '<' ) + { + return 0; + } + + TiXmlDocument* doc = GetDocument(); + p = SkipWhiteSpace( p, encoding ); + + if ( !p || !*p ) + { + return 0; + } + + // What is this thing? + // - Elements start with a letter or underscore, but xml is reserved. + // - Comments: "; + + if ( !StringEqual( p, startTag, false, encoding ) ) + { + document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); + return 0; + } + p += strlen( startTag ); + p = ReadText( p, &value, false, endTag, false, encoding ); + return p; +} + + +const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p ) return 0; + +// int tabsize = 4; +// if ( document ) +// tabsize = document->TabSize(); + + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + // Read the name, the '=' and the value. + const char* pErr = p; + p = ReadName( p, &name, encoding ); + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); + return 0; + } + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p || *p != '=' ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + + ++p; // skip '=' + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + + const char* end; + const char SINGLE_QUOTE = '\''; + const char DOUBLE_QUOTE = '\"'; + + if ( *p == SINGLE_QUOTE ) + { + ++p; + end = "\'"; // single quote in string + p = ReadText( p, &value, false, end, false, encoding ); + } + else if ( *p == DOUBLE_QUOTE ) + { + ++p; + end = "\""; // double quote in string + p = ReadText( p, &value, false, end, false, encoding ); + } + else + { + // All attribute values should be in single or double quotes. + // But this is such a common error that the parser will try + // its best, even without them. + value = ""; + while ( p && *p // existence + && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r' // whitespace + && *p != '/' && *p != '>' ) // tag end + { + if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { + // [ 1451649 ] Attribute values with trailing quotes not handled correctly + // We did not have an opening quote but seem to have a + // closing one. Give up and throw an error. + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + value += *p; + ++p; + } + } + return p; +} + +#ifdef TIXML_USE_STL +void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + while ( in->good() ) + { + int c = in->peek(); + if ( !cdata && (c == '<' ) ) + { + return; + } + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + (*tag) += (char) c; + in->get(); // "commits" the peek made above + + if ( cdata && c == '>' && tag->size() >= 3 ) { + size_t len = tag->size(); + if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { + // terminator of cdata. + return; + } + } + } +} +#endif + +const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + value = ""; + TiXmlDocument* document = GetDocument(); + + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + + const char* const startTag = ""; + + if ( cdata || StringEqual( p, startTag, false, encoding ) ) + { + cdata = true; + + if ( !StringEqual( p, startTag, false, encoding ) ) + { + document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); + return 0; + } + p += strlen( startTag ); + + // Keep all the white space, ignore the encoding, etc. + while ( p && *p + && !StringEqual( p, endTag, false, encoding ) + ) + { + value += *p; + ++p; + } + + TIXML_STRING dummy; + p = ReadText( p, &dummy, false, endTag, false, encoding ); + return p; + } + else + { + bool ignoreWhite = true; + + const char* end = "<"; + p = ReadText( p, &value, ignoreWhite, end, false, encoding ); + if ( p ) + return p-1; // don't truncate the '<' + return 0; + } +} + +#ifdef TIXML_USE_STL +void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + while ( in->good() ) + { + int c = in->get(); + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + (*tag) += (char) c; + + if ( c == '>' ) + { + // All is well. + return; + } + } +} +#endif + +const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) +{ + p = SkipWhiteSpace( p, _encoding ); + // Find the beginning, find the end, and look for + // the stuff in-between. + TiXmlDocument* document = GetDocument(); + if ( !p || !*p || !StringEqual( p, "SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); + return 0; + } + if ( data ) + { + data->Stamp( p, _encoding ); + location = data->Cursor(); + } + p += 5; + + version = ""; + encoding = ""; + standalone = ""; + + while ( p && *p ) + { + if ( *p == '>' ) + { + ++p; + return p; + } + + p = SkipWhiteSpace( p, _encoding ); + if ( StringEqual( p, "version", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + version = attrib.Value(); + } + else if ( StringEqual( p, "encoding", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + encoding = attrib.Value(); + } + else if ( StringEqual( p, "standalone", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + standalone = attrib.Value(); + } + else + { + // Read over whatever it is. + while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) + ++p; + } + } + return 0; +} + +bool TiXmlText::Blank() const +{ + for ( unsigned i=0; i - -#ifdef KERNEL -#define NOFLOAT -#endif - -#define ZEROPAD 1 // Pad with zero (not to be confused with Zero's PAD plugin) -#define SIGN 2 // Unsigned/signed long -#define PLUS 4 // Show plus -#define SPACE 8 // Space if plus -#define LEFT 16 // Left justified -#define SPECIAL 32 // 0x -#define LARGE 64 // Use 'ABCDEF' instead of 'abcdef' - -#define is_digit(c) ((c) >= '0' && (c) <= '9') - -#ifdef __LINUX__ -#define _CVTBUFSIZE (309+40) -#endif - -static const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; -static const char *upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - -#ifdef NEED_STRLEN -static size_t strnlen(const char *s, size_t count) -{ - const char *sc; - for (sc = s; *sc != '\0' && count--; ++sc); - return sc - s; -} -#endif - -static void cvt(char (&buf)[_CVTBUFSIZE], double arg, int preci, int& decpt, int& sign, int eflag) -{ - int r2; - double fi, fj; - char *p, *p1; - - r2 = 0; - sign = 0; - p = &buf[0]; - if (arg < 0) - { - sign = 1; - arg = -arg; - } - arg = modf(arg, &fi); - p1 = &buf[_CVTBUFSIZE]; - - if (fi != 0) - { - while (fi != 0) - { - fj = modf(fi / 10, &fi); - *--p1 = (int)((fj + .03) * 10) + '0'; - r2++; - } - while (p1 < &buf[_CVTBUFSIZE]) *p++ = *p1++; - } - else if (arg > 0) - { - while ((fj = arg * 10) < 1) - { - arg = fj; - r2--; - } - } - - p1 = &buf[preci]; - - if (eflag == 0) p1 += r2; - decpt = r2; - if (p1 < &buf[0]) - { - buf[0] = '\0'; - return; - } - while (p <= p1 && p < &buf[_CVTBUFSIZE]) - { - arg *= 10; - arg = modf(arg, &fj); - *p++ = (int) fj + '0'; - } - if (p1 >= &buf[_CVTBUFSIZE]) - { - buf[_CVTBUFSIZE - 1] = '\0'; - return; - } - p = p1; - *p1 += 5; - while (*p1 > '9') - { - *p1 = '0'; - if (p1 > buf) - ++*--p1; - else - { - *p1 = '1'; - decpt++; - if (eflag == 0) - { - if (p > buf) *p = '0'; - p++; - } - } - } - *p = '\0'; - return; -} - -static void ecvtbuf(char (&buf)[_CVTBUFSIZE], double arg, int preci, int& decpt, int& sign) -{ - cvt(buf, arg, preci, decpt, sign, 1); -} - -static void fcvtbuf(char (&buf)[_CVTBUFSIZE], double arg, int preci, int& decpt, int& sign) -{ - cvt(buf, arg, preci, decpt, sign, 0); -} - -static int skip_atoi(const char **s) -{ - int i = 0; - while (is_digit(**s)) i = i*10 + *((*s)++) - '0'; - return i; -} - -template -static void number(std::string& dest, T num, int base, int size, int precision, int type) -{ - char c, sign, tmp[88]; - const char *dig = digits; - int i; - - if (type & LARGE) dig = upper_digits; - if (type & LEFT) type &= ~ZEROPAD; - if (base < 2 || base > 36) return; - - c = (type & ZEROPAD) ? '0' : ' '; - sign = 0; - if (type & SIGN) - { - if (num < 0) - { - sign = '-'; - num = -num; - size--; - } - else if (type & PLUS) - { - sign = '+'; - size--; - } - else if (type & SPACE) - { - sign = ' '; - size--; - } - } - - if (type & SPECIAL) - { - if (base == 16) - size -= 2; - else if (base == 8) - size--; - } - - i = 0; - - if (num == 0) - tmp[i++] = '0'; - else - { - while (num != 0) - { - tmp[i++] = dig[num % (uint) base]; - num = num / (uint) base; - } - } - - if (i > precision) precision = i; - size -= precision; - if (!(type & (ZEROPAD | LEFT))) while (size-- > 0) dest += ' '; - if (sign) dest += sign; - - if (type & SPECIAL) - { - if (base == 8) - dest += '0'; - else if (base == 16) - { - dest += '0'; - dest += digits[33]; - } - } - - if (!(type & LEFT)) while (size-- > 0) dest += c; - while (i < precision--) dest += '0'; - while (i-- > 0) dest += tmp[i]; - while (size-- > 0) dest += ' '; -} - -static void eaddr( std::string& dest, unsigned char *addr, int size, int precision, int type) -{ - char tmp[24]; - const char *dig = digits; - int i, len; - - if (type & LARGE) dig = upper_digits; - len = 0; - for (i = 0; i < 6; i++) - { - if (i != 0) tmp[len++] = ':'; - tmp[len++] = dig[addr[i] >> 4]; - tmp[len++] = dig[addr[i] & 0x0F]; - } - - if (!(type & LEFT)) while (len < size--) dest += ' '; - for (i = 0; i < len; ++i) dest += tmp[i]; - while (len < size--) dest += ' '; -} - -static void iaddr( std::string& dest, unsigned char *addr, int size, int precision, int type) -{ - char tmp[24]; - int i, n, len; - - len = 0; - for (i = 0; i < 4; i++) - { - if (i != 0) tmp[len++] = '.'; - n = addr[i]; - - if (n == 0) - tmp[len++] = digits[0]; - else - { - if (n >= 100) - { - tmp[len++] = digits[n / 100]; - n = n % 100; - tmp[len++] = digits[n / 10]; - n = n % 10; - } - else if (n >= 10) - { - tmp[len++] = digits[n / 10]; - n = n % 10; - } - - tmp[len++] = digits[n]; - } - } - - if (!(type & LEFT)) while (len < size--) dest += ' '; - for (i = 0; i < len; ++i) dest += tmp[i]; - while (len < size--) dest += ' '; -} - -#ifndef NOFLOAT - -static void cfltcvt(double value, char *buffer, char fmt, int precision) -{ - int decpt, sign, exp, pos; - char cvtbuf[_CVTBUFSIZE]; - int capexp = 0; - int magnitude; - - if (fmt == 'G' || fmt == 'E') - { - capexp = 1; - fmt += 'a' - 'A'; - } - - if (fmt == 'g') - { - ecvtbuf(cvtbuf, value, precision, decpt, sign); - - magnitude = decpt - 1; - if (magnitude < -4 || magnitude > precision - 1) - { - fmt = 'e'; - precision -= 1; - } - else - { - fmt = 'f'; - precision -= decpt; - } - } - - if (fmt == 'e') - { - ecvtbuf(cvtbuf, value, precision+1, decpt, sign); - - const char* digits = cvtbuf; - - if (sign) *buffer++ = '-'; - *buffer++ = *digits; - if (precision > 0) *buffer++ = '.'; - memcpy(buffer, digits + 1, precision); - buffer += precision; - *buffer++ = capexp ? 'E' : 'e'; - - if (decpt == 0) - { - if (value == 0.0) - exp = 0; - else - exp = -1; - } - else - exp = decpt - 1; - - if (exp < 0) - { - *buffer++ = '-'; - exp = -exp; - } - else - *buffer++ = '+'; - - buffer[2] = (exp % 10) + '0'; - exp = exp / 10; - buffer[1] = (exp % 10) + '0'; - exp = exp / 10; - buffer[0] = (exp % 10) + '0'; - buffer += 3; - } - else if (fmt == 'f') - { - fcvtbuf(cvtbuf, value, precision, decpt, sign); - - const char* digits = cvtbuf; - - if (sign) *buffer++ = '-'; - if (*digits) - { - if (decpt <= 0) - { - *buffer++ = '0'; - *buffer++ = '.'; - for (pos = 0; pos < -decpt; pos++) *buffer++ = '0'; - while (*digits) *buffer++ = *digits++; - } - else - { - pos = 0; - while (*digits) - { - if (pos++ == decpt) *buffer++ = '.'; - *buffer++ = *digits++; - } - } - } - else - { - *buffer++ = '0'; - if (precision > 0) - { - *buffer++ = '.'; - for (pos = 0; pos < precision; pos++) *buffer++ = '0'; - } - } - } - - *buffer = '\0'; -} - -static void forcdecpt(char *buffer) -{ - while (*buffer) - { - if (*buffer == '.') return; - if (*buffer == 'e' || *buffer == 'E') break; - buffer++; - } - - if (*buffer) - { - int n = strlen(buffer); - while (n > 0) - { - buffer[n + 1] = buffer[n]; - n--; - } - - *buffer = '.'; - } - else - { - *buffer++ = '.'; - *buffer = '\0'; - } -} - -static void cropzeros(char *buffer) -{ - char *stop; - - while (*buffer && *buffer != '.') buffer++; - if (*buffer++) - { - while (*buffer && *buffer != 'e' && *buffer != 'E') buffer++; - stop = buffer--; - while (*buffer == '0') buffer--; - if (*buffer == '.') buffer--; - while (*++buffer = *stop++); - } -} - -static void flt( std::string& dest, double num, int size, int precision, char fmt, int flags) -{ - char tmp[80]; - char c, sign; - int n, i; - - // Left align means no zero padding - if (flags & LEFT) flags &= ~ZEROPAD; - - // Determine padding and sign char - c = (flags & ZEROPAD) ? '0' : ' '; - sign = 0; - if (flags & SIGN) - { - if (num < 0.0) - { - sign = '-'; - num = -num; - size--; - } - else if (flags & PLUS) - { - sign = '+'; - size--; - } - else if (flags & SPACE) - { - sign = ' '; - size--; - } - } - - // Compute the precision value - if (precision < 0) - precision = 6; // Default precision: 6 - else if (precision == 0 && fmt == 'g') - precision = 1; // ANSI specified - - // Convert floating point number to text - cfltcvt(num, tmp, fmt, precision); - - // '#' and precision == 0 means force a decimal point - if ((flags & SPECIAL) && precision == 0) forcdecpt(tmp); - - // 'g' format means crop zero unless '#' given - if (fmt == 'g' && !(flags & SPECIAL)) cropzeros(tmp); - - n = strlen(tmp); - - // Output number with alignment and padding - size -= n; - if (!(flags & (ZEROPAD | LEFT))) while (size-- > 0) dest += ' '; - if (sign) dest += sign; - if (!(flags & LEFT)) while (size-- > 0) dest += c; - for (i = 0; i < n; i++) dest += tmp[i]; - while (size-- > 0) dest += ' '; -} - -#endif - -/////////////////////////////////////////////////////////////////////////// -// This is a "mostly" direct replacement for vsprintf, that is more secure and easier -// to use than vsnprintf or vsprintf_s. See the docs for ssprintf for usage notes. -void vssappendf(std::string& dest, const char* format, va_list args) -{ - int base; - - int flags; // Flags to number() - - int field_width; // Width of output field - int precision; // Min. # of digits for integers; max number of chars for from string - int qualifier; // 'h', 'l', or 'L' for integer fields - - // Optimization: Memory is cheap. Allocating it on the fly is not. Allocate more room - // than we'll likely need right upfront! - dest.reserve( strlen( format ) * 2 ); - - for( const char* fmt = format; *fmt; fmt++ ) - { - if (*fmt != '%') - { - dest += *fmt; - continue; - } - - // Process flags - flags = 0; -repeat: - fmt++; // This also skips first '%' - switch (*fmt) - { - case '-': flags |= LEFT; goto repeat; - case '+': flags |= PLUS; goto repeat; - case ' ': flags |= SPACE; goto repeat; - case '#': flags |= SPECIAL; goto repeat; - case '0': flags |= ZEROPAD; goto repeat; - } - - // Get field width - field_width = -1; - if (is_digit(*fmt)) - field_width = skip_atoi(&fmt); - else if (*fmt == '*') - { - fmt++; - field_width = va_arg(args, int); - if (field_width < 0) - { - field_width = -field_width; - flags |= LEFT; - } - } - - // Get the precision - precision = -1; - if (*fmt == '.') - { - ++fmt; - if (is_digit(*fmt)) - precision = skip_atoi(&fmt); - else if (*fmt == '*') - { - ++fmt; - precision = va_arg(args, int); - } - if (precision < 0) precision = 0; - } - - // Get the conversion qualifier - qualifier = -1; - if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ) - { - qualifier = *fmt; - fmt++; - } - - // Default base - base = 10; - - switch (*fmt) - { - case 'c': - if (!(flags & LEFT)) while (--field_width > 0) dest += ' '; - dest += (unsigned char) va_arg(args, int); - while (--field_width > 0) dest += ' '; - continue; - - case 's': - { - // let's add support for std::string as a formatted parameter! (air) - if( qualifier == 'h' ) - { - static const string nullstring( "" ); - - const std::string* ss = va_arg(args, std::string*); - if( ss == NULL ) ss = &nullstring; - int len = ss->length(); - if( precision < 0 ) - { - // no precision override so just copy the whole string. - if (!(flags & LEFT)) while (len < field_width--) dest += ' '; - dest += *ss; - } - else - { - if( len > precision ) len = precision; - if (!(flags & LEFT)) while (len < field_width--) dest += ' '; - dest.append( ss->begin(), ss->begin()+len ); - } - while (len < field_width--) dest += ' '; - } - else - { - const char* s = va_arg(args, char *); - if (!s) s = ""; - - int len = strlen(s); - if( precision < 0 ) - { - if (!(flags & LEFT)) while (len < field_width--) dest += ' '; - dest += s; - } - else - { - if( len > precision ) len = precision; - if (!(flags & LEFT)) while (len < field_width--) dest += ' '; - dest.append( s, s+len ); - } - while (len < field_width--) dest += ' '; - } - } - continue; - - case 'p': - { - if (field_width == -1) - { - field_width = 2 * sizeof(void *); - flags |= ZEROPAD; - } - // use sptr as it avoids warnings during template code gen. - number( dest, (sptr) va_arg(args, void *), 16, field_width, precision, flags ); - } - continue; - - case 'n': - if (qualifier == 'l') - { - long *ip = va_arg(args, long *); - *ip = dest.length(); - } - else - { - int *ip = va_arg(args, int *); - *ip = dest.length(); - } - continue; - - // What the hell is %a? (air) - case 'A': - flags |= LARGE; - - case 'a': - if (qualifier == 'l') - eaddr(dest, va_arg(args, unsigned char *), field_width, precision, flags); - else - iaddr(dest, va_arg(args, unsigned char *), field_width, precision, flags); - continue; - - // Integer number formats - set up the flags and "break" - case 'o': - base = 8; - break; - - case 'X': - flags |= LARGE; - - case 'x': - base = 16; - break; - - case 'd': - case 'i': - flags |= SIGN; - - case 'u': - break; - - #ifndef NOFLOAT - - case 'E': - case 'G': - case 'e': - case 'f': - case 'g': - flt(dest, va_arg(args, double), field_width, precision, *fmt, flags | SIGN); - continue; - - #endif - - default: - if (*fmt != '%') dest += '%'; - if (*fmt) - dest += *fmt; - else - --fmt; - continue; - } - - if (qualifier == 'L') - { - // 64-bit integer support! (air) - number(dest, va_arg(args, s64), base, field_width, precision, flags); - } - else - { - s32 num; - if (qualifier == 'h') - num = va_arg(args, s16); - else // 'l' qualifier or no qualifier means 32 bits on all our std target platforms. - num = va_arg(args, s32); - - number(dest, num, base, field_width, precision, flags); - } - } -} - -void vssprintf( std::string& dest, const char* format, va_list args ) -{ - dest.clear(); - vssappendf( dest, format, args ); -} - -void ssappendf( std::string& dest, const char* format, ...) -{ - va_list args; - va_start(args, format); - vssappendf( dest, format, args ); - va_end(args); -} - -// This is a "mostly" direct replacement for sprintf, based on std::string. -// The most notable difference in use is the requirement of a "params" keyword delimiting -// the format string from the parameters used to fill the string's tokens. It looks -// like this in practice: -// -// ssprintf( dest, "Yo Joe, %d. In the Hizzou %s.", params intval, strval ); -// -// In addition to all standard printf formatting tokens, ssprintf also supports a new token -// for std::string parameters as %hs (passed by reference/pointer). I opted for %hs (using 'h' -// as a qualifier) over %S because under MSVC %S acts as a char/widechar conversion. Note -// that these are passed by pointer so you *must* use the & operator most of the time. -// Example: -// -// ssprintf( dest, "Yo Joe, %hs.", params &strval ); -// -// This can be a cavet of sorts since forgetting to use the & will always compile but -// will cause undefined behavior and odd crashes (much like how the same thing happens -// when exchanging an intvalu for a c-string normally -- it's just more tricky with -// strings since we're not used to prefixing sprintf parameters with &s). -// -// === 64-bit -- s64 / u64 -- Support === -// -// ssprintf supports u64/s64 via the L qualifier, which can be prefixed to any one of the -// integer tokens (d, i, x). This isn't standard, but it's easy and doesn't conflict with -// anything, and none of the other 64-bit qualifiers aren't really standard anyway. -// Example: -// -// ssprintf( dest, "Yo Joe, %Ld, %Lx.", params int64, hex64 ); -// -void ssprintf(std::string& str, const char* fmt, ...) -{ - //varg_assert(); - - va_list args; - va_start(args, fmt); - vssprintf(str, fmt, args); - va_end(args); -} - -// See ssprintf for usage details and differences from sprintf formatting. -std::string fmt_string( const char* fmt, ... ) -{ - //varg_assert(); - - std::string retval; - va_list args; - va_start( args, fmt ); - vssprintf( retval, fmt, args ); - va_end( args ); - - return retval; -} - -std::string vfmt_string( const char* fmt, va_list args ) -{ - //varg_assert(); - - std::string retval; - vssprintf( retval, fmt, args ); - - return retval; -} +// +// Code base on: vsprintf.c +// +// Print formatting routines +// +// Copyright (C) 2002 Michael Ringgaard. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. Neither the name of the project nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// + +// modified by gigahers and air to write formatted output directly into a std::string container. + +#include "PrecompiledHeader.h" + +#include + +#ifdef KERNEL +#define NOFLOAT +#endif + +#define ZEROPAD 1 // Pad with zero (not to be confused with Zero's PAD plugin) +#define SIGN 2 // Unsigned/signed long +#define PLUS 4 // Show plus +#define SPACE 8 // Space if plus +#define LEFT 16 // Left justified +#define SPECIAL 32 // 0x +#define LARGE 64 // Use 'ABCDEF' instead of 'abcdef' + +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +#ifdef __LINUX__ +#define _CVTBUFSIZE (309+40) +#endif + +static const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; +static const char *upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +#ifdef NEED_STRLEN +static size_t strnlen(const char *s, size_t count) +{ + const char *sc; + for (sc = s; *sc != '\0' && count--; ++sc); + return sc - s; +} +#endif + +static void cvt(char (&buf)[_CVTBUFSIZE], double arg, int preci, int& decpt, int& sign, int eflag) +{ + int r2; + double fi, fj; + char *p, *p1; + + r2 = 0; + sign = 0; + p = &buf[0]; + if (arg < 0) + { + sign = 1; + arg = -arg; + } + arg = modf(arg, &fi); + p1 = &buf[_CVTBUFSIZE]; + + if (fi != 0) + { + while (fi != 0) + { + fj = modf(fi / 10, &fi); + *--p1 = (int)((fj + .03) * 10) + '0'; + r2++; + } + while (p1 < &buf[_CVTBUFSIZE]) *p++ = *p1++; + } + else if (arg > 0) + { + while ((fj = arg * 10) < 1) + { + arg = fj; + r2--; + } + } + + p1 = &buf[preci]; + + if (eflag == 0) p1 += r2; + decpt = r2; + if (p1 < &buf[0]) + { + buf[0] = '\0'; + return; + } + while (p <= p1 && p < &buf[_CVTBUFSIZE]) + { + arg *= 10; + arg = modf(arg, &fj); + *p++ = (int) fj + '0'; + } + if (p1 >= &buf[_CVTBUFSIZE]) + { + buf[_CVTBUFSIZE - 1] = '\0'; + return; + } + p = p1; + *p1 += 5; + while (*p1 > '9') + { + *p1 = '0'; + if (p1 > buf) + ++*--p1; + else + { + *p1 = '1'; + decpt++; + if (eflag == 0) + { + if (p > buf) *p = '0'; + p++; + } + } + } + *p = '\0'; + return; +} + +static void ecvtbuf(char (&buf)[_CVTBUFSIZE], double arg, int preci, int& decpt, int& sign) +{ + cvt(buf, arg, preci, decpt, sign, 1); +} + +static void fcvtbuf(char (&buf)[_CVTBUFSIZE], double arg, int preci, int& decpt, int& sign) +{ + cvt(buf, arg, preci, decpt, sign, 0); +} + +static int skip_atoi(const char **s) +{ + int i = 0; + while (is_digit(**s)) i = i*10 + *((*s)++) - '0'; + return i; +} + +template +static void number(std::string& dest, T num, int base, int size, int precision, int type) +{ + char c, sign, tmp[88]; + const char *dig = digits; + int i; + + if (type & LARGE) dig = upper_digits; + if (type & LEFT) type &= ~ZEROPAD; + if (base < 2 || base > 36) return; + + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) + { + if (num < 0) + { + sign = '-'; + num = -num; + size--; + } + else if (type & PLUS) + { + sign = '+'; + size--; + } + else if (type & SPACE) + { + sign = ' '; + size--; + } + } + + if (type & SPECIAL) + { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + + i = 0; + + if (num == 0) + tmp[i++] = '0'; + else + { + while (num != 0) + { + tmp[i++] = dig[num % (uint) base]; + num = num / (uint) base; + } + } + + if (i > precision) precision = i; + size -= precision; + if (!(type & (ZEROPAD | LEFT))) while (size-- > 0) dest += ' '; + if (sign) dest += sign; + + if (type & SPECIAL) + { + if (base == 8) + dest += '0'; + else if (base == 16) + { + dest += '0'; + dest += digits[33]; + } + } + + if (!(type & LEFT)) while (size-- > 0) dest += c; + while (i < precision--) dest += '0'; + while (i-- > 0) dest += tmp[i]; + while (size-- > 0) dest += ' '; +} + +static void eaddr( std::string& dest, unsigned char *addr, int size, int precision, int type) +{ + char tmp[24]; + const char *dig = digits; + int i, len; + + if (type & LARGE) dig = upper_digits; + len = 0; + for (i = 0; i < 6; i++) + { + if (i != 0) tmp[len++] = ':'; + tmp[len++] = dig[addr[i] >> 4]; + tmp[len++] = dig[addr[i] & 0x0F]; + } + + if (!(type & LEFT)) while (len < size--) dest += ' '; + for (i = 0; i < len; ++i) dest += tmp[i]; + while (len < size--) dest += ' '; +} + +static void iaddr( std::string& dest, unsigned char *addr, int size, int precision, int type) +{ + char tmp[24]; + int i, n, len; + + len = 0; + for (i = 0; i < 4; i++) + { + if (i != 0) tmp[len++] = '.'; + n = addr[i]; + + if (n == 0) + tmp[len++] = digits[0]; + else + { + if (n >= 100) + { + tmp[len++] = digits[n / 100]; + n = n % 100; + tmp[len++] = digits[n / 10]; + n = n % 10; + } + else if (n >= 10) + { + tmp[len++] = digits[n / 10]; + n = n % 10; + } + + tmp[len++] = digits[n]; + } + } + + if (!(type & LEFT)) while (len < size--) dest += ' '; + for (i = 0; i < len; ++i) dest += tmp[i]; + while (len < size--) dest += ' '; +} + +#ifndef NOFLOAT + +static void cfltcvt(double value, char *buffer, char fmt, int precision) +{ + int decpt, sign, exp, pos; + char cvtbuf[_CVTBUFSIZE]; + int capexp = 0; + int magnitude; + + if (fmt == 'G' || fmt == 'E') + { + capexp = 1; + fmt += 'a' - 'A'; + } + + if (fmt == 'g') + { + ecvtbuf(cvtbuf, value, precision, decpt, sign); + + magnitude = decpt - 1; + if (magnitude < -4 || magnitude > precision - 1) + { + fmt = 'e'; + precision -= 1; + } + else + { + fmt = 'f'; + precision -= decpt; + } + } + + if (fmt == 'e') + { + ecvtbuf(cvtbuf, value, precision+1, decpt, sign); + + const char* digits = cvtbuf; + + if (sign) *buffer++ = '-'; + *buffer++ = *digits; + if (precision > 0) *buffer++ = '.'; + memcpy(buffer, digits + 1, precision); + buffer += precision; + *buffer++ = capexp ? 'E' : 'e'; + + if (decpt == 0) + { + if (value == 0.0) + exp = 0; + else + exp = -1; + } + else + exp = decpt - 1; + + if (exp < 0) + { + *buffer++ = '-'; + exp = -exp; + } + else + *buffer++ = '+'; + + buffer[2] = (exp % 10) + '0'; + exp = exp / 10; + buffer[1] = (exp % 10) + '0'; + exp = exp / 10; + buffer[0] = (exp % 10) + '0'; + buffer += 3; + } + else if (fmt == 'f') + { + fcvtbuf(cvtbuf, value, precision, decpt, sign); + + const char* digits = cvtbuf; + + if (sign) *buffer++ = '-'; + if (*digits) + { + if (decpt <= 0) + { + *buffer++ = '0'; + *buffer++ = '.'; + for (pos = 0; pos < -decpt; pos++) *buffer++ = '0'; + while (*digits) *buffer++ = *digits++; + } + else + { + pos = 0; + while (*digits) + { + if (pos++ == decpt) *buffer++ = '.'; + *buffer++ = *digits++; + } + } + } + else + { + *buffer++ = '0'; + if (precision > 0) + { + *buffer++ = '.'; + for (pos = 0; pos < precision; pos++) *buffer++ = '0'; + } + } + } + + *buffer = '\0'; +} + +static void forcdecpt(char *buffer) +{ + while (*buffer) + { + if (*buffer == '.') return; + if (*buffer == 'e' || *buffer == 'E') break; + buffer++; + } + + if (*buffer) + { + int n = strlen(buffer); + while (n > 0) + { + buffer[n + 1] = buffer[n]; + n--; + } + + *buffer = '.'; + } + else + { + *buffer++ = '.'; + *buffer = '\0'; + } +} + +static void cropzeros(char *buffer) +{ + char *stop; + + while (*buffer && *buffer != '.') buffer++; + if (*buffer++) + { + while (*buffer && *buffer != 'e' && *buffer != 'E') buffer++; + stop = buffer--; + while (*buffer == '0') buffer--; + if (*buffer == '.') buffer--; + while (*++buffer = *stop++); + } +} + +static void flt( std::string& dest, double num, int size, int precision, char fmt, int flags) +{ + char tmp[80]; + char c, sign; + int n, i; + + // Left align means no zero padding + if (flags & LEFT) flags &= ~ZEROPAD; + + // Determine padding and sign char + c = (flags & ZEROPAD) ? '0' : ' '; + sign = 0; + if (flags & SIGN) + { + if (num < 0.0) + { + sign = '-'; + num = -num; + size--; + } + else if (flags & PLUS) + { + sign = '+'; + size--; + } + else if (flags & SPACE) + { + sign = ' '; + size--; + } + } + + // Compute the precision value + if (precision < 0) + precision = 6; // Default precision: 6 + else if (precision == 0 && fmt == 'g') + precision = 1; // ANSI specified + + // Convert floating point number to text + cfltcvt(num, tmp, fmt, precision); + + // '#' and precision == 0 means force a decimal point + if ((flags & SPECIAL) && precision == 0) forcdecpt(tmp); + + // 'g' format means crop zero unless '#' given + if (fmt == 'g' && !(flags & SPECIAL)) cropzeros(tmp); + + n = strlen(tmp); + + // Output number with alignment and padding + size -= n; + if (!(flags & (ZEROPAD | LEFT))) while (size-- > 0) dest += ' '; + if (sign) dest += sign; + if (!(flags & LEFT)) while (size-- > 0) dest += c; + for (i = 0; i < n; i++) dest += tmp[i]; + while (size-- > 0) dest += ' '; +} + +#endif + +/////////////////////////////////////////////////////////////////////////// +// This is a "mostly" direct replacement for vsprintf, that is more secure and easier +// to use than vsnprintf or vsprintf_s. See the docs for ssprintf for usage notes. +void vssappendf(std::string& dest, const char* format, va_list args) +{ + int base; + + int flags; // Flags to number() + + int field_width; // Width of output field + int precision; // Min. # of digits for integers; max number of chars for from string + int qualifier; // 'h', 'l', or 'L' for integer fields + + // Optimization: Memory is cheap. Allocating it on the fly is not. Allocate more room + // than we'll likely need right upfront! + dest.reserve( strlen( format ) * 2 ); + + for( const char* fmt = format; *fmt; fmt++ ) + { + if (*fmt != '%') + { + dest += *fmt; + continue; + } + + // Process flags + flags = 0; +repeat: + fmt++; // This also skips first '%' + switch (*fmt) + { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + // Get field width + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') + { + fmt++; + field_width = va_arg(args, int); + if (field_width < 0) + { + field_width = -field_width; + flags |= LEFT; + } + } + + // Get the precision + precision = -1; + if (*fmt == '.') + { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') + { + ++fmt; + precision = va_arg(args, int); + } + if (precision < 0) precision = 0; + } + + // Get the conversion qualifier + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ) + { + qualifier = *fmt; + fmt++; + } + + // Default base + base = 10; + + switch (*fmt) + { + case 'c': + if (!(flags & LEFT)) while (--field_width > 0) dest += ' '; + dest += (unsigned char) va_arg(args, int); + while (--field_width > 0) dest += ' '; + continue; + + case 's': + { + // let's add support for std::string as a formatted parameter! (air) + if( qualifier == 'h' ) + { + static const string nullstring( "" ); + + const std::string* ss = va_arg(args, std::string*); + if( ss == NULL ) ss = &nullstring; + int len = ss->length(); + if( precision < 0 ) + { + // no precision override so just copy the whole string. + if (!(flags & LEFT)) while (len < field_width--) dest += ' '; + dest += *ss; + } + else + { + if( len > precision ) len = precision; + if (!(flags & LEFT)) while (len < field_width--) dest += ' '; + dest.append( ss->begin(), ss->begin()+len ); + } + while (len < field_width--) dest += ' '; + } + else + { + const char* s = va_arg(args, char *); + if (!s) s = ""; + + int len = strlen(s); + if( precision < 0 ) + { + if (!(flags & LEFT)) while (len < field_width--) dest += ' '; + dest += s; + } + else + { + if( len > precision ) len = precision; + if (!(flags & LEFT)) while (len < field_width--) dest += ' '; + dest.append( s, s+len ); + } + while (len < field_width--) dest += ' '; + } + } + continue; + + case 'p': + { + if (field_width == -1) + { + field_width = 2 * sizeof(void *); + flags |= ZEROPAD; + } + // use sptr as it avoids warnings during template code gen. + number( dest, (sptr) va_arg(args, void *), 16, field_width, precision, flags ); + } + continue; + + case 'n': + if (qualifier == 'l') + { + long *ip = va_arg(args, long *); + *ip = dest.length(); + } + else + { + int *ip = va_arg(args, int *); + *ip = dest.length(); + } + continue; + + // What the hell is %a? (air) + case 'A': + flags |= LARGE; + + case 'a': + if (qualifier == 'l') + eaddr(dest, va_arg(args, unsigned char *), field_width, precision, flags); + else + iaddr(dest, va_arg(args, unsigned char *), field_width, precision, flags); + continue; + + // Integer number formats - set up the flags and "break" + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + + case 'u': + break; + + #ifndef NOFLOAT + + case 'E': + case 'G': + case 'e': + case 'f': + case 'g': + flt(dest, va_arg(args, double), field_width, precision, *fmt, flags | SIGN); + continue; + + #endif + + default: + if (*fmt != '%') dest += '%'; + if (*fmt) + dest += *fmt; + else + --fmt; + continue; + } + + if (qualifier == 'L') + { + // 64-bit integer support! (air) + number(dest, va_arg(args, s64), base, field_width, precision, flags); + } + else + { + s32 num; + if (qualifier == 'h') + num = va_arg(args, s16); + else // 'l' qualifier or no qualifier means 32 bits on all our std target platforms. + num = va_arg(args, s32); + + number(dest, num, base, field_width, precision, flags); + } + } +} + +void vssprintf( std::string& dest, const char* format, va_list args ) +{ + dest.clear(); + vssappendf( dest, format, args ); +} + +void ssappendf( std::string& dest, const char* format, ...) +{ + va_list args; + va_start(args, format); + vssappendf( dest, format, args ); + va_end(args); +} + +// This is a "mostly" direct replacement for sprintf, based on std::string. +// The most notable difference in use is the requirement of a "params" keyword delimiting +// the format string from the parameters used to fill the string's tokens. It looks +// like this in practice: +// +// ssprintf( dest, "Yo Joe, %d. In the Hizzou %s.", params intval, strval ); +// +// In addition to all standard printf formatting tokens, ssprintf also supports a new token +// for std::string parameters as %hs (passed by reference/pointer). I opted for %hs (using 'h' +// as a qualifier) over %S because under MSVC %S acts as a char/widechar conversion. Note +// that these are passed by pointer so you *must* use the & operator most of the time. +// Example: +// +// ssprintf( dest, "Yo Joe, %hs.", params &strval ); +// +// This can be a cavet of sorts since forgetting to use the & will always compile but +// will cause undefined behavior and odd crashes (much like how the same thing happens +// when exchanging an intvalu for a c-string normally -- it's just more tricky with +// strings since we're not used to prefixing sprintf parameters with &s). +// +// === 64-bit -- s64 / u64 -- Support === +// +// ssprintf supports u64/s64 via the L qualifier, which can be prefixed to any one of the +// integer tokens (d, i, x). This isn't standard, but it's easy and doesn't conflict with +// anything, and none of the other 64-bit qualifiers aren't really standard anyway. +// Example: +// +// ssprintf( dest, "Yo Joe, %Ld, %Lx.", params int64, hex64 ); +// +void ssprintf(std::string& str, const char* fmt, ...) +{ + //varg_assert(); + + va_list args; + va_start(args, fmt); + vssprintf(str, fmt, args); + va_end(args); +} + +// See ssprintf for usage details and differences from sprintf formatting. +std::string fmt_string( const char* fmt, ... ) +{ + //varg_assert(); + + std::string retval; + va_list args; + va_start( args, fmt ); + vssprintf( retval, fmt, args ); + va_end( args ); + + return retval; +} + +std::string vfmt_string( const char* fmt, va_list args ) +{ + //varg_assert(); + + std::string retval; + vssprintf( retval, fmt, args ); + + return retval; +} diff --git a/pcsx2/vtlb.cpp b/pcsx2/vtlb.cpp index cb78e41222..ce822163a3 100644 --- a/pcsx2/vtlb.cpp +++ b/pcsx2/vtlb.cpp @@ -1,591 +1,591 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -/* - EE physical map : - [0000 0000,1000 0000) -> Ram (mirrored ?) - [1000 0000,1400 0000) -> Registers - [1400 0000,1fc0 0000) -> Reserved (ingored writes, 'random' reads) - [1fc0 0000,2000 0000) -> Boot ROM - - [2000 0000,4000 0000) -> Unmapped (BUS ERROR) - [4000 0000,8000 0000) -> "Extended memory", probably unmapped (BUS ERROR) on retail ps2's :) - [8000 0000,FFFF FFFF] -> Unmapped (BUS ERROR) - - vtlb/phy only supports the [0000 0000,2000 0000) region, with 4k pages. - vtlb/vmap supports mapping to either of these locations, or some other (externaly) specified address. -*/ - -#include "PrecompiledHeader.h" - -#include "Common.h" -#include "vtlb.h" -#include "COP0.h" - -using namespace R5900; -using namespace vtlb_private; - -#ifdef PCSX2_DEVBUILD -#define verify(x) {if (!(x)) { (*(u8*)0)=3; }} -#else -#define verify jASSUME -#endif - -namespace vtlb_private -{ - s32 pmap[VTLB_PMAP_ITEMS]; //512KB - s32 vmap[VTLB_VMAP_ITEMS]; //4MB - - // first indexer -- 8/16/32/64/128 bit tables [values 0-4] - // second indexer -- read/write [0 or 1] - // third indexer -- 128 pages of memory! - void* RWFT[5][2][128]; -} - -vtlbHandler vtlbHandlerCount=0; - -vtlbHandler DefaultPhyHandler; -vtlbHandler UnmappedVirtHandler0; -vtlbHandler UnmappedVirtHandler1; -vtlbHandler UnmappedPhyHandler0; -vtlbHandler UnmappedPhyHandler1; - - - /* - __asm - { - mov eax,ecx; - shr ecx,12; - mov ecx,[ecx*4+vmap]; //translate - add ecx,eax; //transform - - js callfunction; //if <0 its invalid ptr :) - - mov eax,[ecx]; - mov [edx],eax; - xor eax,eax; - ret; - -callfunction: - xchg eax,ecx; - shr eax,12; //get the 'ppn' - - //ecx = original addr - //eax = function entry + 0x800000 - //edx = data ptr - jmp [readfunctions8-0x800000+eax]; - }*/ - -///////////////////////////////////////////////////////////////////////// -// Interpreter Implementations of VTLB Memory Operations. -// See recVTLB.cpp for the dynarec versions. - -// Interpreterd VTLB lookup for 8, 16, and 32 bit accesses -template -__forceinline DataType __fastcall MemOp_r0(u32 addr) -{ - u32 vmv=vmap[addr>>VTLB_PAGE_BITS]; - s32 ppf=addr+vmv; - - if (!(ppf<0)) - return *reinterpret_cast(ppf); - - //has to: translate, find function, call function - u32 hand=(u8)vmv; - u32 paddr=ppf-hand+0x80000000; - //SysPrintf("Translated 0x%08X to 0x%08X\n",addr,paddr); - //return reinterpret_cast::HandlerType*>(RWFT[TemplateHelper::sidx][0][hand])(paddr,data); - - switch( DataSize ) - { - case 8: return ((vltbMemR8FP*)RWFT[0][0][hand])(paddr); - case 16: return ((vltbMemR16FP*)RWFT[1][0][hand])(paddr); - case 32: return ((vltbMemR32FP*)RWFT[2][0][hand])(paddr); - - jNO_DEFAULT; - } -} - -// Interpreterd VTLB lookup for 64 and 128 bit accesses. -template -__forceinline void __fastcall MemOp_r1(u32 addr, DataType* data) -{ - u32 vmv=vmap[addr>>VTLB_PAGE_BITS]; - s32 ppf=addr+vmv; - - if (!(ppf<0)) - { - data[0]=*reinterpret_cast(ppf); - if (DataSize==128) - data[1]=*reinterpret_cast(ppf+8); - } - else - { - //has to: translate, find function, call function - u32 hand=(u8)vmv; - u32 paddr=ppf-hand+0x80000000; - //SysPrintf("Translated 0x%08X to 0x%08X\n",addr,paddr); - //return reinterpret_cast::HandlerType*>(RWFT[TemplateHelper::sidx][0][hand])(paddr,data); - - switch( DataSize ) - { - case 64: ((vltbMemR64FP*)RWFT[3][0][hand])(paddr, data); break; - case 128: ((vltbMemR128FP*)RWFT[4][0][hand])(paddr, data); break; - - jNO_DEFAULT; - } - } -} - -template -__forceinline void __fastcall MemOp_w0(u32 addr, DataType data) -{ - u32 vmv=vmap[addr>>VTLB_PAGE_BITS]; - s32 ppf=addr+vmv; - if (!(ppf<0)) - { - *reinterpret_cast(ppf)=data; - } - else - { - //has to: translate, find function, call function - u32 hand=(u8)vmv; - u32 paddr=ppf-hand+0x80000000; - //SysPrintf("Translted 0x%08X to 0x%08X\n",addr,paddr); - - switch( DataSize ) - { - case 8: return ((vltbMemW8FP*)RWFT[0][1][hand])(paddr, (u8)data); - case 16: return ((vltbMemW16FP*)RWFT[1][1][hand])(paddr, (u16)data); - case 32: return ((vltbMemW32FP*)RWFT[2][1][hand])(paddr, (u32)data); - - jNO_DEFAULT; - } - } -} -template -__forceinline void __fastcall MemOp_w1(u32 addr,const DataType* data) -{ - verify(DataSize==128 || DataSize==64); - u32 vmv=vmap[addr>>VTLB_PAGE_BITS]; - s32 ppf=addr+vmv; - if (!(ppf<0)) - { - *reinterpret_cast(ppf)=*data; - if (DataSize==128) - *reinterpret_cast(ppf+8)=data[1]; - } - else - { - //has to: translate, find function, call function - u32 hand=(u8)vmv; - u32 paddr=ppf-hand+0x80000000; - //SysPrintf("Translted 0x%08X to 0x%08X\n",addr,paddr); - switch( DataSize ) - { - case 64: return ((vltbMemW64FP*)RWFT[3][1][hand])(paddr, data); - case 128: return ((vltbMemW128FP*)RWFT[4][1][hand])(paddr, data); - - jNO_DEFAULT; - } - } -} - -mem8_t __fastcall vtlb_memRead8(u32 mem) -{ - return MemOp_r0<8,mem8_t>(mem); -} -mem16_t __fastcall vtlb_memRead16(u32 mem) -{ - return MemOp_r0<16,mem16_t>(mem); -} -mem32_t __fastcall vtlb_memRead32(u32 mem) -{ - return MemOp_r0<32,mem32_t>(mem); -} -void __fastcall vtlb_memRead64(u32 mem, u64 *out) -{ - return MemOp_r1<64,mem64_t>(mem,out); -} -void __fastcall vtlb_memRead128(u32 mem, u64 *out) -{ - return MemOp_r1<128,mem128_t>(mem,out); -} -void __fastcall vtlb_memWrite8 (u32 mem, mem8_t value) -{ - MemOp_w0<8,mem8_t>(mem,value); -} -void __fastcall vtlb_memWrite16(u32 mem, mem16_t value) -{ - MemOp_w0<16,mem16_t>(mem,value); -} -void __fastcall vtlb_memWrite32(u32 mem, mem32_t value) -{ - MemOp_w0<32,mem32_t>(mem,value); -} -void __fastcall vtlb_memWrite64(u32 mem, const mem64_t* value) -{ - MemOp_w1<64,mem64_t>(mem,value); -} -void __fastcall vtlb_memWrite128(u32 mem, const mem128_t *value) -{ - MemOp_w1<128,mem128_t>(mem,value); -} - -// Some functions used by interpreters and stuff... -// These maintain a "consistent" API with 64/128 reads. -void __fastcall memRead8(u32 mem, u8 *out) { *out = vtlb_memRead8( mem ); } -void __fastcall memRead16(u32 mem, u16 *out) { *out = vtlb_memRead16( mem ); } -void __fastcall memRead32(u32 mem, u32 *out) { *out = vtlb_memRead32( mem ); } - -///////////////////////////////////////////////////////////////////////// -// Error / TLB Miss Handlers -// - -// Generates a VtlbMiss Exception -static __forceinline void vtlb_Miss(u32 addr,u32 mode) -{ - Console::Error("vtlb miss : addr 0x%X, mode %d", params addr,mode); - verify(false); - - if (mode==0) - cpuTlbMissR(addr, cpuRegs.branch); - else - cpuTlbMissW(addr, cpuRegs.branch); -} - -// Just dies a horrible death for now. -// -static __forceinline void vtlb_BusError(u32 addr,u32 mode) -{ - Console::Error("vtlb bus error : addr 0x%X, mode %d\n",params addr,mode); - verify(false); -} - -///// Virtual Mapping Errors (TLB Miss) -template -mem8_t __fastcall vtlbUnmappedVRead8(u32 addr) { vtlb_Miss(addr|saddr,0); return 0; } -template -mem16_t __fastcall vtlbUnmappedVRead16(u32 addr) { vtlb_Miss(addr|saddr,0); return 0; } -template -mem32_t __fastcall vtlbUnmappedVRead32(u32 addr) { vtlb_Miss(addr|saddr,0); return 0; } -template -void __fastcall vtlbUnmappedVRead64(u32 addr,mem64_t* data) { vtlb_Miss(addr|saddr,0); } -template -void __fastcall vtlbUnmappedVRead128(u32 addr,mem128_t* data) { vtlb_Miss(addr|saddr,0); } -template -void __fastcall vtlbUnmappedVWrite8(u32 addr,mem8_t data) { vtlb_Miss(addr|saddr,1); } -template -void __fastcall vtlbUnmappedVWrite16(u32 addr,mem16_t data) { vtlb_Miss(addr|saddr,1); } -template -void __fastcall vtlbUnmappedVWrite32(u32 addr,mem32_t data) { vtlb_Miss(addr|saddr,1); } -template -void __fastcall vtlbUnmappedVWrite64(u32 addr,const mem64_t* data) { vtlb_Miss(addr|saddr,1); } -template -void __fastcall vtlbUnmappedVWrite128(u32 addr,const mem128_t* data) { vtlb_Miss(addr|saddr,1); } - -///// Physical Mapping Errors (Bus Error) -template -mem8_t __fastcall vtlbUnmappedPRead8(u32 addr) { vtlb_BusError(addr|saddr,0); return 0; } -template -mem16_t __fastcall vtlbUnmappedPRead16(u32 addr) { vtlb_BusError(addr|saddr,0); return 0; } -template -mem32_t __fastcall vtlbUnmappedPRead32(u32 addr) { vtlb_BusError(addr|saddr,0); return 0; } -template -void __fastcall vtlbUnmappedPRead64(u32 addr,mem64_t* data) { vtlb_BusError(addr|saddr,0); } -template -void __fastcall vtlbUnmappedPRead128(u32 addr,mem128_t* data) { vtlb_BusError(addr|saddr,0); } -template -void __fastcall vtlbUnmappedPWrite8(u32 addr,mem8_t data) { vtlb_BusError(addr|saddr,1); } -template -void __fastcall vtlbUnmappedPWrite16(u32 addr,mem16_t data) { vtlb_BusError(addr|saddr,1); } -template -void __fastcall vtlbUnmappedPWrite32(u32 addr,mem32_t data) { vtlb_BusError(addr|saddr,1); } -template -void __fastcall vtlbUnmappedPWrite64(u32 addr,const mem64_t* data) { vtlb_BusError(addr|saddr,1); } -template -void __fastcall vtlbUnmappedPWrite128(u32 addr,const mem128_t* data) { vtlb_BusError(addr|saddr,1); } - -///// VTLB mapping errors (unmapped address spaces) -mem8_t __fastcall vtlbDefaultPhyRead8(u32 addr) { Console::Error("vtlbDefaultPhyRead8: 0x%X",params addr); verify(false); return -1; } -mem16_t __fastcall vtlbDefaultPhyRead16(u32 addr) { Console::Error("vtlbDefaultPhyRead16: 0x%X",params addr); verify(false); return -1; } -mem32_t __fastcall vtlbDefaultPhyRead32(u32 addr) { Console::Error("vtlbDefaultPhyRead32: 0x%X",params addr); verify(false); return -1; } -void __fastcall vtlbDefaultPhyRead64(u32 addr,mem64_t* data) { Console::Error("vtlbDefaultPhyRead64: 0x%X",params addr); verify(false); } -void __fastcall vtlbDefaultPhyRead128(u32 addr,mem128_t* data) { Console::Error("vtlbDefaultPhyRead128: 0x%X",params addr); verify(false); } - -void __fastcall vtlbDefaultPhyWrite8(u32 addr,mem8_t data) { Console::Error("vtlbDefaultPhyWrite8: 0x%X",params addr); verify(false); } -void __fastcall vtlbDefaultPhyWrite16(u32 addr,mem16_t data) { Console::Error("vtlbDefaultPhyWrite16: 0x%X",params addr); verify(false); } -void __fastcall vtlbDefaultPhyWrite32(u32 addr,mem32_t data) { Console::Error("vtlbDefaultPhyWrite32: 0x%X",params addr); verify(false); } -void __fastcall vtlbDefaultPhyWrite64(u32 addr,const mem64_t* data) { Console::Error("vtlbDefaultPhyWrite64: 0x%X",params addr); verify(false); } -void __fastcall vtlbDefaultPhyWrite128(u32 addr,const mem128_t* data) { Console::Error("vtlbDefaultPhyWrite128: 0x%X",params addr); verify(false); } - - -///////////////////////////////////////////////////////////////////////// -// VTLB Public API -- Init/Term/RegisterHandler stuff -// - - -// Registers a handler into the VTLB's internal handler array. The handler defines specific behavior -// for how memory pages bound to the handler are read from / written to. If any of the handler pointers -// are NULL, the memory operations will be mapped to the BusError handler (thus generating BusError -// exceptions if the emulated app attempts to access them). -// -// Note: All handlers persist across calls to vtlb_Reset(), but are wiped/invalidated by calls to vtlb_Init() -// -// Returns a handle for the newly created handler See .vtlb_MapHandler for use of the return value. -vtlbHandler vtlb_RegisterHandler( vltbMemR8FP* r8,vltbMemR16FP* r16,vltbMemR32FP* r32,vltbMemR64FP* r64,vltbMemR128FP* r128, - vltbMemW8FP* w8,vltbMemW16FP* w16,vltbMemW32FP* w32,vltbMemW64FP* w64,vltbMemW128FP* w128) -{ - //write the code :p - vtlbHandler rv=vtlbHandlerCount++; - - RWFT[0][0][rv] = (r8!=0) ? r8:vtlbDefaultPhyRead8; - RWFT[1][0][rv] = (r16!=0) ? r16:vtlbDefaultPhyRead16; - RWFT[2][0][rv] = (r32!=0) ? r32:vtlbDefaultPhyRead32; - RWFT[3][0][rv] = (r64!=0) ? r64:vtlbDefaultPhyRead64; - RWFT[4][0][rv] = (r128!=0) ? r128:vtlbDefaultPhyRead128; - - RWFT[0][1][rv] = (w8!=0) ? w8:vtlbDefaultPhyWrite8; - RWFT[1][1][rv] = (w16!=0) ? w16:vtlbDefaultPhyWrite16; - RWFT[2][1][rv] = (w32!=0) ? w32:vtlbDefaultPhyWrite32; - RWFT[3][1][rv] = (w64!=0) ? w64:vtlbDefaultPhyWrite64; - RWFT[4][1][rv] = (w128!=0) ? w128:vtlbDefaultPhyWrite128; - - return rv; -} - -// Maps the given hander (created with vtlb_RegisterHandler) to the specified memory region. -// New mappings always assume priority over previous mappings, so place "generic" mappings for -// large areas of memory first, and then specialize specific small regions of memory afterward. -// A single handler can be mapped to many different regions by using multiple calls to this -// function. -// -// The memory region start and size parameters must be pagesize aligned. -void vtlb_MapHandler(vtlbHandler handler,u32 start,u32 size) -{ - verify(0==(start&VTLB_PAGE_MASK)); - verify(0==(size&VTLB_PAGE_MASK) && size>0); - s32 value=handler|0x80000000; - - while(size>0) - { - pmap[start>>VTLB_PAGE_BITS]=value; - - start+=VTLB_PAGE_SIZE; - size-=VTLB_PAGE_SIZE; - } -} - -void vtlb_MapBlock(void* base,u32 start,u32 size,u32 blocksize) -{ - s32 baseint=(s32)base; - - verify(0==(start&VTLB_PAGE_MASK)); - verify(0==(size&VTLB_PAGE_MASK) && size>0); - if (blocksize==0) - blocksize=size; - verify(0==(blocksize&VTLB_PAGE_MASK) && blocksize>0); - verify(0==(size%blocksize)); - - while(size>0) - { - u32 blocksz=blocksize; - s32 ptr=baseint; - - while(blocksz>0) - { - pmap[start>>VTLB_PAGE_BITS]=ptr; - - start+=VTLB_PAGE_SIZE; - ptr+=VTLB_PAGE_SIZE; - blocksz-=VTLB_PAGE_SIZE; - size-=VTLB_PAGE_SIZE; - } - } -} - -void vtlb_Mirror(u32 new_region,u32 start,u32 size) -{ - verify(0==(new_region&VTLB_PAGE_MASK)); - verify(0==(start&VTLB_PAGE_MASK)); - verify(0==(size&VTLB_PAGE_MASK) && size>0); - - while(size>0) - { - pmap[start>>VTLB_PAGE_BITS]=pmap[new_region>>VTLB_PAGE_BITS]; - - start+=VTLB_PAGE_SIZE; - new_region+=VTLB_PAGE_SIZE; - size-=VTLB_PAGE_SIZE; - } -} - -__forceinline void* vtlb_GetPhyPtr(u32 paddr) -{ - if (paddr>=VTLB_PMAP_SZ || pmap[paddr>>VTLB_PAGE_BITS]<0) - return 0; - else - return reinterpret_cast(pmap[paddr>>VTLB_PAGE_BITS]+(paddr&VTLB_PAGE_MASK)); - -} - -//virtual mappings -//TODO: Add invalid paddr checks -void vtlb_VMap(u32 vaddr,u32 paddr,u32 sz) -{ - verify(0==(vaddr&VTLB_PAGE_MASK)); - verify(0==(paddr&VTLB_PAGE_MASK)); - verify(0==(sz&VTLB_PAGE_MASK) && sz>0); - - while(sz>0) - { - s32 pme; - if (paddr>=VTLB_PMAP_SZ) - { - pme=UnmappedPhyHandler0; - if (paddr&0x80000000) - pme=UnmappedPhyHandler1; - pme|=0x80000000; - pme|=paddr;// top bit is set anyway ... - } - else - { - pme=pmap[paddr>>VTLB_PAGE_BITS]; - if (pme<0) - pme|=paddr;// top bit is set anyway ... - } - vmap[vaddr>>VTLB_PAGE_BITS]=pme-vaddr; - vaddr+=VTLB_PAGE_SIZE; - paddr+=VTLB_PAGE_SIZE; - sz-=VTLB_PAGE_SIZE; - } -} - -void vtlb_VMapBuffer(u32 vaddr,void* buffer,u32 sz) -{ - verify(0==(vaddr&VTLB_PAGE_MASK)); - verify(0==(sz&VTLB_PAGE_MASK) && sz>0); - u32 bu8=(u32)buffer; - while(sz>0) - { - vmap[vaddr>>VTLB_PAGE_BITS]=bu8-vaddr; - vaddr+=VTLB_PAGE_SIZE; - bu8+=VTLB_PAGE_SIZE; - sz-=VTLB_PAGE_SIZE; - } -} -void vtlb_VMapUnmap(u32 vaddr,u32 sz) -{ - verify(0==(vaddr&VTLB_PAGE_MASK)); - verify(0==(sz&VTLB_PAGE_MASK) && sz>0); - - while(sz>0) - { - u32 handl=UnmappedVirtHandler0; - if (vaddr&0x80000000) - { - handl=UnmappedVirtHandler1; - } - handl|=vaddr; // top bit is set anyway ... - handl|=0x80000000; - vmap[vaddr>>VTLB_PAGE_BITS]=handl-vaddr; - vaddr+=VTLB_PAGE_SIZE; - sz-=VTLB_PAGE_SIZE; - } -} - -// Clears vtlb handlers and memory mappings. -void vtlb_Init() -{ - vtlbHandlerCount=0; - memzero_obj(RWFT); - - //Register default handlers - //Unmapped Virt handlers _MUST_ be registered first. - //On address translation the top bit cannot be preserved.This is not normaly a problem since - //the physical address space can be 'compressed' to just 29 bits.However, to properly handle exceptions - //there must be a way to get the full address back.Thats why i use these 2 functions and encode the hi bit directly into em :) - - UnmappedVirtHandler0=vtlb_RegisterHandler(vtlbUnmappedVRead8<0>,vtlbUnmappedVRead16<0>,vtlbUnmappedVRead32<0>,vtlbUnmappedVRead64<0>,vtlbUnmappedVRead128<0>, - vtlbUnmappedVWrite8<0>,vtlbUnmappedVWrite16<0>,vtlbUnmappedVWrite32<0>,vtlbUnmappedVWrite64<0>,vtlbUnmappedVWrite128<0>); - - UnmappedVirtHandler1=vtlb_RegisterHandler(vtlbUnmappedVRead8<0x80000000>,vtlbUnmappedVRead16<0x80000000>,vtlbUnmappedVRead32<0x80000000>, - vtlbUnmappedVRead64<0x80000000>,vtlbUnmappedVRead128<0x80000000>, - vtlbUnmappedVWrite8<0x80000000>,vtlbUnmappedVWrite16<0x80000000>,vtlbUnmappedVWrite32<0x80000000>, - vtlbUnmappedVWrite64<0x80000000>,vtlbUnmappedVWrite128<0x80000000>); - - UnmappedPhyHandler0=vtlb_RegisterHandler(vtlbUnmappedPRead8<0>,vtlbUnmappedPRead16<0>,vtlbUnmappedPRead32<0>,vtlbUnmappedPRead64<0>,vtlbUnmappedPRead128<0>, - vtlbUnmappedPWrite8<0>,vtlbUnmappedPWrite16<0>,vtlbUnmappedPWrite32<0>,vtlbUnmappedPWrite64<0>,vtlbUnmappedPWrite128<0>); - - UnmappedPhyHandler1=vtlb_RegisterHandler(vtlbUnmappedPRead8<0x80000000>,vtlbUnmappedPRead16<0x80000000>,vtlbUnmappedPRead32<0x80000000>, - vtlbUnmappedPRead64<0x80000000>,vtlbUnmappedPRead128<0x80000000>, - vtlbUnmappedPWrite8<0x80000000>,vtlbUnmappedPWrite16<0x80000000>,vtlbUnmappedPWrite32<0x80000000>, - vtlbUnmappedPWrite64<0x80000000>,vtlbUnmappedPWrite128<0x80000000>); - DefaultPhyHandler=vtlb_RegisterHandler(0,0,0,0,0,0,0,0,0,0); - - //done ! - - //Setup the initial mappings - vtlb_MapHandler(DefaultPhyHandler,0,VTLB_PMAP_SZ); - - //Set the V space as unmapped - vtlb_VMapUnmap(0,(VTLB_VMAP_ITEMS-1)*VTLB_PAGE_SIZE); - //yeah i know, its stupid .. but this code has to be here for now ;p - vtlb_VMapUnmap((VTLB_VMAP_ITEMS-1)*VTLB_PAGE_SIZE,VTLB_PAGE_SIZE); -} - -// Performs a COP0-level reset of the PS2's TLB. -// This function should probably be part of the COP0 rather than here in VTLB. -void vtlb_Reset() -{ - for(int i=0; i<48; i++) UnmapTLB(i); -} - -void vtlb_Term() -{ - //nothing to do for now -} - -// This function allocates memory block with are compatible with the Vtlb's requirements -// for memory locations. The Vtlb requires the topmost bit (Sign bit) of the memory -// pointer to be cleared. Some operating systems and/or implementations of malloc do that, -// but others do not. So use this instead to allocate the memory correctly for your -// platform. -u8* vtlb_malloc( uint size, uint align, uptr tryBaseAddress ) -{ -#ifdef __LINUX__ - return SysMmapEx( tryBaseAddress, size, 0x80000000, "Vtlb" ); -#else - // Win32 just needs this, since malloc always maps below 2GB. - return (u8*)_aligned_malloc(size, align); -#endif -} - -void vtlb_free( void* pmem, uint size ) -{ - if( pmem == NULL ) return; - -#ifdef __LINUX__ - SafeSysMunmap( pmem, size ); -#else - // Make sure and unprotect memory first, since CrtDebug will try to write to it. - DWORD old; - VirtualProtect( pmem, size, PAGE_READWRITE, &old ); - safe_aligned_free( pmem ); -#endif -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +/* + EE physical map : + [0000 0000,1000 0000) -> Ram (mirrored ?) + [1000 0000,1400 0000) -> Registers + [1400 0000,1fc0 0000) -> Reserved (ingored writes, 'random' reads) + [1fc0 0000,2000 0000) -> Boot ROM + + [2000 0000,4000 0000) -> Unmapped (BUS ERROR) + [4000 0000,8000 0000) -> "Extended memory", probably unmapped (BUS ERROR) on retail ps2's :) + [8000 0000,FFFF FFFF] -> Unmapped (BUS ERROR) + + vtlb/phy only supports the [0000 0000,2000 0000) region, with 4k pages. + vtlb/vmap supports mapping to either of these locations, or some other (externaly) specified address. +*/ + +#include "PrecompiledHeader.h" + +#include "Common.h" +#include "vtlb.h" +#include "COP0.h" + +using namespace R5900; +using namespace vtlb_private; + +#ifdef PCSX2_DEVBUILD +#define verify(x) {if (!(x)) { (*(u8*)0)=3; }} +#else +#define verify jASSUME +#endif + +namespace vtlb_private +{ + s32 pmap[VTLB_PMAP_ITEMS]; //512KB + s32 vmap[VTLB_VMAP_ITEMS]; //4MB + + // first indexer -- 8/16/32/64/128 bit tables [values 0-4] + // second indexer -- read/write [0 or 1] + // third indexer -- 128 pages of memory! + void* RWFT[5][2][128]; +} + +vtlbHandler vtlbHandlerCount=0; + +vtlbHandler DefaultPhyHandler; +vtlbHandler UnmappedVirtHandler0; +vtlbHandler UnmappedVirtHandler1; +vtlbHandler UnmappedPhyHandler0; +vtlbHandler UnmappedPhyHandler1; + + + /* + __asm + { + mov eax,ecx; + shr ecx,12; + mov ecx,[ecx*4+vmap]; //translate + add ecx,eax; //transform + + js callfunction; //if <0 its invalid ptr :) + + mov eax,[ecx]; + mov [edx],eax; + xor eax,eax; + ret; + +callfunction: + xchg eax,ecx; + shr eax,12; //get the 'ppn' + + //ecx = original addr + //eax = function entry + 0x800000 + //edx = data ptr + jmp [readfunctions8-0x800000+eax]; + }*/ + +///////////////////////////////////////////////////////////////////////// +// Interpreter Implementations of VTLB Memory Operations. +// See recVTLB.cpp for the dynarec versions. + +// Interpreterd VTLB lookup for 8, 16, and 32 bit accesses +template +__forceinline DataType __fastcall MemOp_r0(u32 addr) +{ + u32 vmv=vmap[addr>>VTLB_PAGE_BITS]; + s32 ppf=addr+vmv; + + if (!(ppf<0)) + return *reinterpret_cast(ppf); + + //has to: translate, find function, call function + u32 hand=(u8)vmv; + u32 paddr=ppf-hand+0x80000000; + //SysPrintf("Translated 0x%08X to 0x%08X\n",addr,paddr); + //return reinterpret_cast::HandlerType*>(RWFT[TemplateHelper::sidx][0][hand])(paddr,data); + + switch( DataSize ) + { + case 8: return ((vltbMemR8FP*)RWFT[0][0][hand])(paddr); + case 16: return ((vltbMemR16FP*)RWFT[1][0][hand])(paddr); + case 32: return ((vltbMemR32FP*)RWFT[2][0][hand])(paddr); + + jNO_DEFAULT; + } +} + +// Interpreterd VTLB lookup for 64 and 128 bit accesses. +template +__forceinline void __fastcall MemOp_r1(u32 addr, DataType* data) +{ + u32 vmv=vmap[addr>>VTLB_PAGE_BITS]; + s32 ppf=addr+vmv; + + if (!(ppf<0)) + { + data[0]=*reinterpret_cast(ppf); + if (DataSize==128) + data[1]=*reinterpret_cast(ppf+8); + } + else + { + //has to: translate, find function, call function + u32 hand=(u8)vmv; + u32 paddr=ppf-hand+0x80000000; + //SysPrintf("Translated 0x%08X to 0x%08X\n",addr,paddr); + //return reinterpret_cast::HandlerType*>(RWFT[TemplateHelper::sidx][0][hand])(paddr,data); + + switch( DataSize ) + { + case 64: ((vltbMemR64FP*)RWFT[3][0][hand])(paddr, data); break; + case 128: ((vltbMemR128FP*)RWFT[4][0][hand])(paddr, data); break; + + jNO_DEFAULT; + } + } +} + +template +__forceinline void __fastcall MemOp_w0(u32 addr, DataType data) +{ + u32 vmv=vmap[addr>>VTLB_PAGE_BITS]; + s32 ppf=addr+vmv; + if (!(ppf<0)) + { + *reinterpret_cast(ppf)=data; + } + else + { + //has to: translate, find function, call function + u32 hand=(u8)vmv; + u32 paddr=ppf-hand+0x80000000; + //SysPrintf("Translted 0x%08X to 0x%08X\n",addr,paddr); + + switch( DataSize ) + { + case 8: return ((vltbMemW8FP*)RWFT[0][1][hand])(paddr, (u8)data); + case 16: return ((vltbMemW16FP*)RWFT[1][1][hand])(paddr, (u16)data); + case 32: return ((vltbMemW32FP*)RWFT[2][1][hand])(paddr, (u32)data); + + jNO_DEFAULT; + } + } +} +template +__forceinline void __fastcall MemOp_w1(u32 addr,const DataType* data) +{ + verify(DataSize==128 || DataSize==64); + u32 vmv=vmap[addr>>VTLB_PAGE_BITS]; + s32 ppf=addr+vmv; + if (!(ppf<0)) + { + *reinterpret_cast(ppf)=*data; + if (DataSize==128) + *reinterpret_cast(ppf+8)=data[1]; + } + else + { + //has to: translate, find function, call function + u32 hand=(u8)vmv; + u32 paddr=ppf-hand+0x80000000; + //SysPrintf("Translted 0x%08X to 0x%08X\n",addr,paddr); + switch( DataSize ) + { + case 64: return ((vltbMemW64FP*)RWFT[3][1][hand])(paddr, data); + case 128: return ((vltbMemW128FP*)RWFT[4][1][hand])(paddr, data); + + jNO_DEFAULT; + } + } +} + +mem8_t __fastcall vtlb_memRead8(u32 mem) +{ + return MemOp_r0<8,mem8_t>(mem); +} +mem16_t __fastcall vtlb_memRead16(u32 mem) +{ + return MemOp_r0<16,mem16_t>(mem); +} +mem32_t __fastcall vtlb_memRead32(u32 mem) +{ + return MemOp_r0<32,mem32_t>(mem); +} +void __fastcall vtlb_memRead64(u32 mem, u64 *out) +{ + return MemOp_r1<64,mem64_t>(mem,out); +} +void __fastcall vtlb_memRead128(u32 mem, u64 *out) +{ + return MemOp_r1<128,mem128_t>(mem,out); +} +void __fastcall vtlb_memWrite8 (u32 mem, mem8_t value) +{ + MemOp_w0<8,mem8_t>(mem,value); +} +void __fastcall vtlb_memWrite16(u32 mem, mem16_t value) +{ + MemOp_w0<16,mem16_t>(mem,value); +} +void __fastcall vtlb_memWrite32(u32 mem, mem32_t value) +{ + MemOp_w0<32,mem32_t>(mem,value); +} +void __fastcall vtlb_memWrite64(u32 mem, const mem64_t* value) +{ + MemOp_w1<64,mem64_t>(mem,value); +} +void __fastcall vtlb_memWrite128(u32 mem, const mem128_t *value) +{ + MemOp_w1<128,mem128_t>(mem,value); +} + +// Some functions used by interpreters and stuff... +// These maintain a "consistent" API with 64/128 reads. +void __fastcall memRead8(u32 mem, u8 *out) { *out = vtlb_memRead8( mem ); } +void __fastcall memRead16(u32 mem, u16 *out) { *out = vtlb_memRead16( mem ); } +void __fastcall memRead32(u32 mem, u32 *out) { *out = vtlb_memRead32( mem ); } + +///////////////////////////////////////////////////////////////////////// +// Error / TLB Miss Handlers +// + +// Generates a VtlbMiss Exception +static __forceinline void vtlb_Miss(u32 addr,u32 mode) +{ + Console::Error("vtlb miss : addr 0x%X, mode %d", params addr,mode); + verify(false); + + if (mode==0) + cpuTlbMissR(addr, cpuRegs.branch); + else + cpuTlbMissW(addr, cpuRegs.branch); +} + +// Just dies a horrible death for now. +// +static __forceinline void vtlb_BusError(u32 addr,u32 mode) +{ + Console::Error("vtlb bus error : addr 0x%X, mode %d\n",params addr,mode); + verify(false); +} + +///// Virtual Mapping Errors (TLB Miss) +template +mem8_t __fastcall vtlbUnmappedVRead8(u32 addr) { vtlb_Miss(addr|saddr,0); return 0; } +template +mem16_t __fastcall vtlbUnmappedVRead16(u32 addr) { vtlb_Miss(addr|saddr,0); return 0; } +template +mem32_t __fastcall vtlbUnmappedVRead32(u32 addr) { vtlb_Miss(addr|saddr,0); return 0; } +template +void __fastcall vtlbUnmappedVRead64(u32 addr,mem64_t* data) { vtlb_Miss(addr|saddr,0); } +template +void __fastcall vtlbUnmappedVRead128(u32 addr,mem128_t* data) { vtlb_Miss(addr|saddr,0); } +template +void __fastcall vtlbUnmappedVWrite8(u32 addr,mem8_t data) { vtlb_Miss(addr|saddr,1); } +template +void __fastcall vtlbUnmappedVWrite16(u32 addr,mem16_t data) { vtlb_Miss(addr|saddr,1); } +template +void __fastcall vtlbUnmappedVWrite32(u32 addr,mem32_t data) { vtlb_Miss(addr|saddr,1); } +template +void __fastcall vtlbUnmappedVWrite64(u32 addr,const mem64_t* data) { vtlb_Miss(addr|saddr,1); } +template +void __fastcall vtlbUnmappedVWrite128(u32 addr,const mem128_t* data) { vtlb_Miss(addr|saddr,1); } + +///// Physical Mapping Errors (Bus Error) +template +mem8_t __fastcall vtlbUnmappedPRead8(u32 addr) { vtlb_BusError(addr|saddr,0); return 0; } +template +mem16_t __fastcall vtlbUnmappedPRead16(u32 addr) { vtlb_BusError(addr|saddr,0); return 0; } +template +mem32_t __fastcall vtlbUnmappedPRead32(u32 addr) { vtlb_BusError(addr|saddr,0); return 0; } +template +void __fastcall vtlbUnmappedPRead64(u32 addr,mem64_t* data) { vtlb_BusError(addr|saddr,0); } +template +void __fastcall vtlbUnmappedPRead128(u32 addr,mem128_t* data) { vtlb_BusError(addr|saddr,0); } +template +void __fastcall vtlbUnmappedPWrite8(u32 addr,mem8_t data) { vtlb_BusError(addr|saddr,1); } +template +void __fastcall vtlbUnmappedPWrite16(u32 addr,mem16_t data) { vtlb_BusError(addr|saddr,1); } +template +void __fastcall vtlbUnmappedPWrite32(u32 addr,mem32_t data) { vtlb_BusError(addr|saddr,1); } +template +void __fastcall vtlbUnmappedPWrite64(u32 addr,const mem64_t* data) { vtlb_BusError(addr|saddr,1); } +template +void __fastcall vtlbUnmappedPWrite128(u32 addr,const mem128_t* data) { vtlb_BusError(addr|saddr,1); } + +///// VTLB mapping errors (unmapped address spaces) +mem8_t __fastcall vtlbDefaultPhyRead8(u32 addr) { Console::Error("vtlbDefaultPhyRead8: 0x%X",params addr); verify(false); return -1; } +mem16_t __fastcall vtlbDefaultPhyRead16(u32 addr) { Console::Error("vtlbDefaultPhyRead16: 0x%X",params addr); verify(false); return -1; } +mem32_t __fastcall vtlbDefaultPhyRead32(u32 addr) { Console::Error("vtlbDefaultPhyRead32: 0x%X",params addr); verify(false); return -1; } +void __fastcall vtlbDefaultPhyRead64(u32 addr,mem64_t* data) { Console::Error("vtlbDefaultPhyRead64: 0x%X",params addr); verify(false); } +void __fastcall vtlbDefaultPhyRead128(u32 addr,mem128_t* data) { Console::Error("vtlbDefaultPhyRead128: 0x%X",params addr); verify(false); } + +void __fastcall vtlbDefaultPhyWrite8(u32 addr,mem8_t data) { Console::Error("vtlbDefaultPhyWrite8: 0x%X",params addr); verify(false); } +void __fastcall vtlbDefaultPhyWrite16(u32 addr,mem16_t data) { Console::Error("vtlbDefaultPhyWrite16: 0x%X",params addr); verify(false); } +void __fastcall vtlbDefaultPhyWrite32(u32 addr,mem32_t data) { Console::Error("vtlbDefaultPhyWrite32: 0x%X",params addr); verify(false); } +void __fastcall vtlbDefaultPhyWrite64(u32 addr,const mem64_t* data) { Console::Error("vtlbDefaultPhyWrite64: 0x%X",params addr); verify(false); } +void __fastcall vtlbDefaultPhyWrite128(u32 addr,const mem128_t* data) { Console::Error("vtlbDefaultPhyWrite128: 0x%X",params addr); verify(false); } + + +///////////////////////////////////////////////////////////////////////// +// VTLB Public API -- Init/Term/RegisterHandler stuff +// + + +// Registers a handler into the VTLB's internal handler array. The handler defines specific behavior +// for how memory pages bound to the handler are read from / written to. If any of the handler pointers +// are NULL, the memory operations will be mapped to the BusError handler (thus generating BusError +// exceptions if the emulated app attempts to access them). +// +// Note: All handlers persist across calls to vtlb_Reset(), but are wiped/invalidated by calls to vtlb_Init() +// +// Returns a handle for the newly created handler See .vtlb_MapHandler for use of the return value. +vtlbHandler vtlb_RegisterHandler( vltbMemR8FP* r8,vltbMemR16FP* r16,vltbMemR32FP* r32,vltbMemR64FP* r64,vltbMemR128FP* r128, + vltbMemW8FP* w8,vltbMemW16FP* w16,vltbMemW32FP* w32,vltbMemW64FP* w64,vltbMemW128FP* w128) +{ + //write the code :p + vtlbHandler rv=vtlbHandlerCount++; + + RWFT[0][0][rv] = (r8!=0) ? r8:vtlbDefaultPhyRead8; + RWFT[1][0][rv] = (r16!=0) ? r16:vtlbDefaultPhyRead16; + RWFT[2][0][rv] = (r32!=0) ? r32:vtlbDefaultPhyRead32; + RWFT[3][0][rv] = (r64!=0) ? r64:vtlbDefaultPhyRead64; + RWFT[4][0][rv] = (r128!=0) ? r128:vtlbDefaultPhyRead128; + + RWFT[0][1][rv] = (w8!=0) ? w8:vtlbDefaultPhyWrite8; + RWFT[1][1][rv] = (w16!=0) ? w16:vtlbDefaultPhyWrite16; + RWFT[2][1][rv] = (w32!=0) ? w32:vtlbDefaultPhyWrite32; + RWFT[3][1][rv] = (w64!=0) ? w64:vtlbDefaultPhyWrite64; + RWFT[4][1][rv] = (w128!=0) ? w128:vtlbDefaultPhyWrite128; + + return rv; +} + +// Maps the given hander (created with vtlb_RegisterHandler) to the specified memory region. +// New mappings always assume priority over previous mappings, so place "generic" mappings for +// large areas of memory first, and then specialize specific small regions of memory afterward. +// A single handler can be mapped to many different regions by using multiple calls to this +// function. +// +// The memory region start and size parameters must be pagesize aligned. +void vtlb_MapHandler(vtlbHandler handler,u32 start,u32 size) +{ + verify(0==(start&VTLB_PAGE_MASK)); + verify(0==(size&VTLB_PAGE_MASK) && size>0); + s32 value=handler|0x80000000; + + while(size>0) + { + pmap[start>>VTLB_PAGE_BITS]=value; + + start+=VTLB_PAGE_SIZE; + size-=VTLB_PAGE_SIZE; + } +} + +void vtlb_MapBlock(void* base,u32 start,u32 size,u32 blocksize) +{ + s32 baseint=(s32)base; + + verify(0==(start&VTLB_PAGE_MASK)); + verify(0==(size&VTLB_PAGE_MASK) && size>0); + if (blocksize==0) + blocksize=size; + verify(0==(blocksize&VTLB_PAGE_MASK) && blocksize>0); + verify(0==(size%blocksize)); + + while(size>0) + { + u32 blocksz=blocksize; + s32 ptr=baseint; + + while(blocksz>0) + { + pmap[start>>VTLB_PAGE_BITS]=ptr; + + start+=VTLB_PAGE_SIZE; + ptr+=VTLB_PAGE_SIZE; + blocksz-=VTLB_PAGE_SIZE; + size-=VTLB_PAGE_SIZE; + } + } +} + +void vtlb_Mirror(u32 new_region,u32 start,u32 size) +{ + verify(0==(new_region&VTLB_PAGE_MASK)); + verify(0==(start&VTLB_PAGE_MASK)); + verify(0==(size&VTLB_PAGE_MASK) && size>0); + + while(size>0) + { + pmap[start>>VTLB_PAGE_BITS]=pmap[new_region>>VTLB_PAGE_BITS]; + + start+=VTLB_PAGE_SIZE; + new_region+=VTLB_PAGE_SIZE; + size-=VTLB_PAGE_SIZE; + } +} + +__forceinline void* vtlb_GetPhyPtr(u32 paddr) +{ + if (paddr>=VTLB_PMAP_SZ || pmap[paddr>>VTLB_PAGE_BITS]<0) + return 0; + else + return reinterpret_cast(pmap[paddr>>VTLB_PAGE_BITS]+(paddr&VTLB_PAGE_MASK)); + +} + +//virtual mappings +//TODO: Add invalid paddr checks +void vtlb_VMap(u32 vaddr,u32 paddr,u32 sz) +{ + verify(0==(vaddr&VTLB_PAGE_MASK)); + verify(0==(paddr&VTLB_PAGE_MASK)); + verify(0==(sz&VTLB_PAGE_MASK) && sz>0); + + while(sz>0) + { + s32 pme; + if (paddr>=VTLB_PMAP_SZ) + { + pme=UnmappedPhyHandler0; + if (paddr&0x80000000) + pme=UnmappedPhyHandler1; + pme|=0x80000000; + pme|=paddr;// top bit is set anyway ... + } + else + { + pme=pmap[paddr>>VTLB_PAGE_BITS]; + if (pme<0) + pme|=paddr;// top bit is set anyway ... + } + vmap[vaddr>>VTLB_PAGE_BITS]=pme-vaddr; + vaddr+=VTLB_PAGE_SIZE; + paddr+=VTLB_PAGE_SIZE; + sz-=VTLB_PAGE_SIZE; + } +} + +void vtlb_VMapBuffer(u32 vaddr,void* buffer,u32 sz) +{ + verify(0==(vaddr&VTLB_PAGE_MASK)); + verify(0==(sz&VTLB_PAGE_MASK) && sz>0); + u32 bu8=(u32)buffer; + while(sz>0) + { + vmap[vaddr>>VTLB_PAGE_BITS]=bu8-vaddr; + vaddr+=VTLB_PAGE_SIZE; + bu8+=VTLB_PAGE_SIZE; + sz-=VTLB_PAGE_SIZE; + } +} +void vtlb_VMapUnmap(u32 vaddr,u32 sz) +{ + verify(0==(vaddr&VTLB_PAGE_MASK)); + verify(0==(sz&VTLB_PAGE_MASK) && sz>0); + + while(sz>0) + { + u32 handl=UnmappedVirtHandler0; + if (vaddr&0x80000000) + { + handl=UnmappedVirtHandler1; + } + handl|=vaddr; // top bit is set anyway ... + handl|=0x80000000; + vmap[vaddr>>VTLB_PAGE_BITS]=handl-vaddr; + vaddr+=VTLB_PAGE_SIZE; + sz-=VTLB_PAGE_SIZE; + } +} + +// Clears vtlb handlers and memory mappings. +void vtlb_Init() +{ + vtlbHandlerCount=0; + memzero_obj(RWFT); + + //Register default handlers + //Unmapped Virt handlers _MUST_ be registered first. + //On address translation the top bit cannot be preserved.This is not normaly a problem since + //the physical address space can be 'compressed' to just 29 bits.However, to properly handle exceptions + //there must be a way to get the full address back.Thats why i use these 2 functions and encode the hi bit directly into em :) + + UnmappedVirtHandler0=vtlb_RegisterHandler(vtlbUnmappedVRead8<0>,vtlbUnmappedVRead16<0>,vtlbUnmappedVRead32<0>,vtlbUnmappedVRead64<0>,vtlbUnmappedVRead128<0>, + vtlbUnmappedVWrite8<0>,vtlbUnmappedVWrite16<0>,vtlbUnmappedVWrite32<0>,vtlbUnmappedVWrite64<0>,vtlbUnmappedVWrite128<0>); + + UnmappedVirtHandler1=vtlb_RegisterHandler(vtlbUnmappedVRead8<0x80000000>,vtlbUnmappedVRead16<0x80000000>,vtlbUnmappedVRead32<0x80000000>, + vtlbUnmappedVRead64<0x80000000>,vtlbUnmappedVRead128<0x80000000>, + vtlbUnmappedVWrite8<0x80000000>,vtlbUnmappedVWrite16<0x80000000>,vtlbUnmappedVWrite32<0x80000000>, + vtlbUnmappedVWrite64<0x80000000>,vtlbUnmappedVWrite128<0x80000000>); + + UnmappedPhyHandler0=vtlb_RegisterHandler(vtlbUnmappedPRead8<0>,vtlbUnmappedPRead16<0>,vtlbUnmappedPRead32<0>,vtlbUnmappedPRead64<0>,vtlbUnmappedPRead128<0>, + vtlbUnmappedPWrite8<0>,vtlbUnmappedPWrite16<0>,vtlbUnmappedPWrite32<0>,vtlbUnmappedPWrite64<0>,vtlbUnmappedPWrite128<0>); + + UnmappedPhyHandler1=vtlb_RegisterHandler(vtlbUnmappedPRead8<0x80000000>,vtlbUnmappedPRead16<0x80000000>,vtlbUnmappedPRead32<0x80000000>, + vtlbUnmappedPRead64<0x80000000>,vtlbUnmappedPRead128<0x80000000>, + vtlbUnmappedPWrite8<0x80000000>,vtlbUnmappedPWrite16<0x80000000>,vtlbUnmappedPWrite32<0x80000000>, + vtlbUnmappedPWrite64<0x80000000>,vtlbUnmappedPWrite128<0x80000000>); + DefaultPhyHandler=vtlb_RegisterHandler(0,0,0,0,0,0,0,0,0,0); + + //done ! + + //Setup the initial mappings + vtlb_MapHandler(DefaultPhyHandler,0,VTLB_PMAP_SZ); + + //Set the V space as unmapped + vtlb_VMapUnmap(0,(VTLB_VMAP_ITEMS-1)*VTLB_PAGE_SIZE); + //yeah i know, its stupid .. but this code has to be here for now ;p + vtlb_VMapUnmap((VTLB_VMAP_ITEMS-1)*VTLB_PAGE_SIZE,VTLB_PAGE_SIZE); +} + +// Performs a COP0-level reset of the PS2's TLB. +// This function should probably be part of the COP0 rather than here in VTLB. +void vtlb_Reset() +{ + for(int i=0; i<48; i++) UnmapTLB(i); +} + +void vtlb_Term() +{ + //nothing to do for now +} + +// This function allocates memory block with are compatible with the Vtlb's requirements +// for memory locations. The Vtlb requires the topmost bit (Sign bit) of the memory +// pointer to be cleared. Some operating systems and/or implementations of malloc do that, +// but others do not. So use this instead to allocate the memory correctly for your +// platform. +u8* vtlb_malloc( uint size, uint align, uptr tryBaseAddress ) +{ +#ifdef __LINUX__ + return SysMmapEx( tryBaseAddress, size, 0x80000000, "Vtlb" ); +#else + // Win32 just needs this, since malloc always maps below 2GB. + return (u8*)_aligned_malloc(size, align); +#endif +} + +void vtlb_free( void* pmem, uint size ) +{ + if( pmem == NULL ) return; + +#ifdef __LINUX__ + SafeSysMunmap( pmem, size ); +#else + // Make sure and unprotect memory first, since CrtDebug will try to write to it. + DWORD old; + VirtualProtect( pmem, size, PAGE_READWRITE, &old ); + safe_aligned_free( pmem ); +#endif +} diff --git a/pcsx2/vtlb.h b/pcsx2/vtlb.h index 5b7e17eea9..551388e4b3 100644 --- a/pcsx2/vtlb.h +++ b/pcsx2/vtlb.h @@ -1,79 +1,79 @@ -#ifndef _VTLB_H_ -#define _VTLB_H_ - -typedef u8 mem8_t; -typedef u16 mem16_t; -typedef u32 mem32_t; -typedef u64 mem64_t; -typedef u64 mem128_t; - -// Specialized function pointers for each read type -typedef mem8_t __fastcall vltbMemR8FP(u32 addr); -typedef mem16_t __fastcall vltbMemR16FP(u32 addr); -typedef mem32_t __fastcall vltbMemR32FP(u32 addr); -typedef void __fastcall vltbMemR64FP(u32 addr,mem64_t* data); -typedef void __fastcall vltbMemR128FP(u32 addr,mem128_t* data); - -// Specialized function pointers for each write type -typedef void __fastcall vltbMemW8FP(u32 addr,mem8_t data); -typedef void __fastcall vltbMemW16FP(u32 addr,mem16_t data); -typedef void __fastcall vltbMemW32FP(u32 addr,mem32_t data); -typedef void __fastcall vltbMemW64FP(u32 addr,const mem64_t* data); -typedef void __fastcall vltbMemW128FP(u32 addr,const mem128_t* data); - -typedef u32 vtlbHandler; - -extern void vtlb_Init(); -extern void vtlb_Reset(); -extern void vtlb_Term(); -extern u8* vtlb_malloc( uint size, uint align, uptr tryBaseAddress ); -extern void vtlb_free( void* pmem, uint size ); - - -//physical stuff -vtlbHandler vtlb_RegisterHandler( vltbMemR8FP* r8,vltbMemR16FP* r16,vltbMemR32FP* r32,vltbMemR64FP* r64,vltbMemR128FP* r128, - vltbMemW8FP* w8,vltbMemW16FP* w16,vltbMemW32FP* w32,vltbMemW64FP* w64,vltbMemW128FP* w128); - -extern void vtlb_MapHandler(vtlbHandler handler,u32 start,u32 size); -extern void vtlb_MapBlock(void* base,u32 start,u32 size,u32 blocksize=0); -extern void* vtlb_GetPhyPtr(u32 paddr); -//extern void vtlb_Mirror(u32 new_region,u32 start,u32 size); // -> not working yet :( - -//virtual mappings -extern void vtlb_VMap(u32 vaddr,u32 paddr,u32 sz); -extern void vtlb_VMapBuffer(u32 vaddr,void* buffer,u32 sz); -extern void vtlb_VMapUnmap(u32 vaddr,u32 sz); - -//Memory functions - -extern u8 __fastcall vtlb_memRead8(u32 mem); -extern u16 __fastcall vtlb_memRead16(u32 mem); -extern u32 __fastcall vtlb_memRead32(u32 mem); -extern void __fastcall vtlb_memRead64(u32 mem, u64 *out); -extern void __fastcall vtlb_memRead128(u32 mem, u64 *out); -extern void __fastcall vtlb_memWrite8 (u32 mem, u8 value); -extern void __fastcall vtlb_memWrite16(u32 mem, u16 value); -extern void __fastcall vtlb_memWrite32(u32 mem, u32 value); -extern void __fastcall vtlb_memWrite64(u32 mem, const u64* value); -extern void __fastcall vtlb_memWrite128(u32 mem, const u64* value); - -extern void vtlb_DynGenWrite(u32 sz); -extern void vtlb_DynGenRead32(u32 bits, bool sign); -extern void vtlb_DynGenRead64(u32 sz); - -namespace vtlb_private -{ - static const uint VTLB_PAGE_BITS = 12; - static const uint VTLB_PAGE_MASK = 4095; - static const uint VTLB_PAGE_SIZE = 4096; - - static const uint VTLB_PMAP_ITEMS = 0x20000000 / VTLB_PAGE_SIZE; - static const uint VTLB_PMAP_SZ = 0x20000000; - static const uint VTLB_VMAP_ITEMS = 0x100000000ULL / VTLB_PAGE_SIZE; - - extern void* RWFT[5][2][128]; - extern s32 pmap[VTLB_PMAP_ITEMS]; //512KB - extern s32 vmap[VTLB_VMAP_ITEMS]; //4MB -} - -#endif +#ifndef _VTLB_H_ +#define _VTLB_H_ + +typedef u8 mem8_t; +typedef u16 mem16_t; +typedef u32 mem32_t; +typedef u64 mem64_t; +typedef u64 mem128_t; + +// Specialized function pointers for each read type +typedef mem8_t __fastcall vltbMemR8FP(u32 addr); +typedef mem16_t __fastcall vltbMemR16FP(u32 addr); +typedef mem32_t __fastcall vltbMemR32FP(u32 addr); +typedef void __fastcall vltbMemR64FP(u32 addr,mem64_t* data); +typedef void __fastcall vltbMemR128FP(u32 addr,mem128_t* data); + +// Specialized function pointers for each write type +typedef void __fastcall vltbMemW8FP(u32 addr,mem8_t data); +typedef void __fastcall vltbMemW16FP(u32 addr,mem16_t data); +typedef void __fastcall vltbMemW32FP(u32 addr,mem32_t data); +typedef void __fastcall vltbMemW64FP(u32 addr,const mem64_t* data); +typedef void __fastcall vltbMemW128FP(u32 addr,const mem128_t* data); + +typedef u32 vtlbHandler; + +extern void vtlb_Init(); +extern void vtlb_Reset(); +extern void vtlb_Term(); +extern u8* vtlb_malloc( uint size, uint align, uptr tryBaseAddress ); +extern void vtlb_free( void* pmem, uint size ); + + +//physical stuff +vtlbHandler vtlb_RegisterHandler( vltbMemR8FP* r8,vltbMemR16FP* r16,vltbMemR32FP* r32,vltbMemR64FP* r64,vltbMemR128FP* r128, + vltbMemW8FP* w8,vltbMemW16FP* w16,vltbMemW32FP* w32,vltbMemW64FP* w64,vltbMemW128FP* w128); + +extern void vtlb_MapHandler(vtlbHandler handler,u32 start,u32 size); +extern void vtlb_MapBlock(void* base,u32 start,u32 size,u32 blocksize=0); +extern void* vtlb_GetPhyPtr(u32 paddr); +//extern void vtlb_Mirror(u32 new_region,u32 start,u32 size); // -> not working yet :( + +//virtual mappings +extern void vtlb_VMap(u32 vaddr,u32 paddr,u32 sz); +extern void vtlb_VMapBuffer(u32 vaddr,void* buffer,u32 sz); +extern void vtlb_VMapUnmap(u32 vaddr,u32 sz); + +//Memory functions + +extern u8 __fastcall vtlb_memRead8(u32 mem); +extern u16 __fastcall vtlb_memRead16(u32 mem); +extern u32 __fastcall vtlb_memRead32(u32 mem); +extern void __fastcall vtlb_memRead64(u32 mem, u64 *out); +extern void __fastcall vtlb_memRead128(u32 mem, u64 *out); +extern void __fastcall vtlb_memWrite8 (u32 mem, u8 value); +extern void __fastcall vtlb_memWrite16(u32 mem, u16 value); +extern void __fastcall vtlb_memWrite32(u32 mem, u32 value); +extern void __fastcall vtlb_memWrite64(u32 mem, const u64* value); +extern void __fastcall vtlb_memWrite128(u32 mem, const u64* value); + +extern void vtlb_DynGenWrite(u32 sz); +extern void vtlb_DynGenRead32(u32 bits, bool sign); +extern void vtlb_DynGenRead64(u32 sz); + +namespace vtlb_private +{ + static const uint VTLB_PAGE_BITS = 12; + static const uint VTLB_PAGE_MASK = 4095; + static const uint VTLB_PAGE_SIZE = 4096; + + static const uint VTLB_PMAP_ITEMS = 0x20000000 / VTLB_PAGE_SIZE; + static const uint VTLB_PMAP_SZ = 0x20000000; + static const uint VTLB_VMAP_ITEMS = 0x100000000ULL / VTLB_PAGE_SIZE; + + extern void* RWFT[5][2][128]; + extern s32 pmap[VTLB_PMAP_ITEMS]; //512KB + extern s32 vmap[VTLB_VMAP_ITEMS]; //4MB +} + +#endif diff --git a/pcsx2/windows/AboutDlg.cpp b/pcsx2/windows/AboutDlg.cpp index b5317c3ef7..77e34bb7a7 100644 --- a/pcsx2/windows/AboutDlg.cpp +++ b/pcsx2/windows/AboutDlg.cpp @@ -1,57 +1,57 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" -#include "Win32.h" - -#include "AboutDlg.h" -#include "Common.h" - -#define IDC_STATIC (-1) - -HWND hW; -HBITMAP hBMP, hSilverBMP; - -LRESULT WINAPI AboutDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { - - switch(uMsg) { - case WM_INITDIALOG: - hBMP = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(SPLASH_LOGO)); - hSilverBMP = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_PS2SILVER)); - - hW = CreateWindow("STATIC", "", WS_VISIBLE | WS_CHILD | SS_BITMAP, - 230, 10, 211, 110, hDlg, (HMENU)IDC_STATIC, GetModuleHandle(NULL), NULL); - SendMessage(hW, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBMP); - - SetWindowText(hDlg, _("About PCSX2")); - - Button_SetText(GetDlgItem(hDlg, IDOK), _("OK")); - Static_SetText(GetDlgItem(hDlg, IDC_PCSX_ABOUT_AUTHORS), _(LabelAuthors)); - Static_SetText(GetDlgItem(hDlg, IDC_PCSX_ABOUT_GREETS), _(LabelGreets)); - return TRUE; - - case WM_COMMAND: - switch(wParam) { - case IDOK: - EndDialog(hDlg, TRUE ); - return TRUE; - } - break; - } - return FALSE; -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" +#include "Win32.h" + +#include "AboutDlg.h" +#include "Common.h" + +#define IDC_STATIC (-1) + +HWND hW; +HBITMAP hBMP, hSilverBMP; + +LRESULT WINAPI AboutDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { + + switch(uMsg) { + case WM_INITDIALOG: + hBMP = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(SPLASH_LOGO)); + hSilverBMP = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_PS2SILVER)); + + hW = CreateWindow("STATIC", "", WS_VISIBLE | WS_CHILD | SS_BITMAP, + 230, 10, 211, 110, hDlg, (HMENU)IDC_STATIC, GetModuleHandle(NULL), NULL); + SendMessage(hW, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBMP); + + SetWindowText(hDlg, _("About PCSX2")); + + Button_SetText(GetDlgItem(hDlg, IDOK), _("OK")); + Static_SetText(GetDlgItem(hDlg, IDC_PCSX_ABOUT_AUTHORS), _(LabelAuthors)); + Static_SetText(GetDlgItem(hDlg, IDC_PCSX_ABOUT_GREETS), _(LabelGreets)); + return TRUE; + + case WM_COMMAND: + switch(wParam) { + case IDOK: + EndDialog(hDlg, TRUE ); + return TRUE; + } + break; + } + return FALSE; +} diff --git a/pcsx2/windows/AboutDlg.h b/pcsx2/windows/AboutDlg.h index 5807d5bcc1..088cb546c5 100644 --- a/pcsx2/windows/AboutDlg.h +++ b/pcsx2/windows/AboutDlg.h @@ -1,24 +1,24 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef _PCSX2_ABOUTDLG_H_ -#define _PCSX2_ABOUTDLG_H_ - -LRESULT WINAPI AboutDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef _PCSX2_ABOUTDLG_H_ +#define _PCSX2_ABOUTDLG_H_ + +LRESULT WINAPI AboutDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + +#endif diff --git a/pcsx2/windows/AdvancedDlg.cpp b/pcsx2/windows/AdvancedDlg.cpp index 993aaa7e08..fdf05af57d 100644 --- a/pcsx2/windows/AdvancedDlg.cpp +++ b/pcsx2/windows/AdvancedDlg.cpp @@ -1,183 +1,183 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Win32.h" - -#include "Common.h" -#include "ix86/ix86.h" - -// the EE and VU roundmodes are passed in so that we can "retain" the config values during -// default button action. The checkbox statuses are checked against the Config settings when -// the user hits OK, and the game only resets if they differ. - -static void InitRoundClampModes( HWND hDlg, u32 new_eeopt, u32 new_vuopt ) -{ - CheckRadioButton(hDlg, IDC_EE_ROUNDMODE0, IDC_EE_ROUNDMODE3, IDC_EE_ROUNDMODE0 + ((Config.sseMXCSR & 0x6000) >> 13)); - CheckRadioButton(hDlg, IDC_VU_ROUNDMODE0, IDC_VU_ROUNDMODE3, IDC_VU_ROUNDMODE0 + ((Config.sseVUMXCSR & 0x6000) >> 13)); - CheckRadioButton(hDlg, IDC_EE_CLAMPMODE0, IDC_EE_CLAMPMODE2, IDC_EE_CLAMPMODE0 + ((new_eeopt & 0x2) ? 2 : (new_eeopt & 0x1))); - - if (new_vuopt & 0x4) CheckRadioButton(hDlg, IDC_VU_CLAMPMODE0, IDC_VU_CLAMPMODE3, IDC_VU_CLAMPMODE0 + 3); - else if (new_vuopt & 0x2) CheckRadioButton(hDlg, IDC_VU_CLAMPMODE0, IDC_VU_CLAMPMODE3, IDC_VU_CLAMPMODE0 + 2); - else if (new_vuopt & 0x1) CheckRadioButton(hDlg, IDC_VU_CLAMPMODE0, IDC_VU_CLAMPMODE3, IDC_VU_CLAMPMODE0 + 1); - else CheckRadioButton(hDlg, IDC_VU_CLAMPMODE0, IDC_VU_CLAMPMODE3, IDC_VU_CLAMPMODE0 + 0); - - if (Config.sseMXCSR & 0x8000) CheckDlgButton(hDlg, IDC_EE_CHECK1, TRUE); - if (Config.sseVUMXCSR & 0x8000) CheckDlgButton(hDlg, IDC_VU_CHECK1, TRUE); -} - -BOOL APIENTRY AdvancedOptionsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case WM_INITDIALOG: - - InitRoundClampModes( hDlg, Config.eeOptions, Config.vuOptions ); - - if( !cpucaps.hasStreamingSIMD2Extensions ) { - // SSE1 cpus do not support Denormals Are Zero flag. - Config.sseMXCSR &= ~0x0040; - Config.sseVUMXCSR &= ~0x0040; - EnableWindow( GetDlgItem( hDlg, IDC_EE_CHECK2 ), FALSE ); - EnableWindow( GetDlgItem( hDlg, IDC_VU_CHECK2 ), FALSE ); - CheckDlgButton( hDlg, IDC_EE_CHECK2, FALSE ); - CheckDlgButton( hDlg, IDC_VU_CHECK2, FALSE ); - } - else { - if (Config.sseMXCSR & 0x0040) CheckDlgButton(hDlg, IDC_EE_CHECK2, TRUE); - if (Config.sseVUMXCSR & 0x0040) CheckDlgButton(hDlg, IDC_VU_CHECK2, TRUE); - } - - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDOK: - { - u32 new_eeopt = 0; - u32 new_vuopt = 0; - - Config.sseMXCSR &= 0x1fbf; - Config.sseVUMXCSR &= 0x1fbf; - - Config.sseMXCSR |= IsDlgButtonChecked(hDlg, IDC_EE_ROUNDMODE0) ? 0x0000 : 0; // Round Nearest - Config.sseMXCSR |= IsDlgButtonChecked(hDlg, IDC_EE_ROUNDMODE1) ? 0x2000 : 0; // Round Negative - Config.sseMXCSR |= IsDlgButtonChecked(hDlg, IDC_EE_ROUNDMODE2) ? 0x4000 : 0; // Round Postive - Config.sseMXCSR |= IsDlgButtonChecked(hDlg, IDC_EE_ROUNDMODE3) ? 0x6000 : 0; // Round Zero / Chop - - Config.sseVUMXCSR |= IsDlgButtonChecked(hDlg, IDC_VU_ROUNDMODE0) ? 0x0000 : 0; // Round Nearest - Config.sseVUMXCSR |= IsDlgButtonChecked(hDlg, IDC_VU_ROUNDMODE1) ? 0x2000 : 0; // Round Negative - Config.sseVUMXCSR |= IsDlgButtonChecked(hDlg, IDC_VU_ROUNDMODE2) ? 0x4000 : 0; // Round Postive - Config.sseVUMXCSR |= IsDlgButtonChecked(hDlg, IDC_VU_ROUNDMODE3) ? 0x6000 : 0; // Round Zero / Chop - - new_eeopt |= IsDlgButtonChecked(hDlg, IDC_EE_CLAMPMODE0) ? 0x0 : 0; - new_eeopt |= IsDlgButtonChecked(hDlg, IDC_EE_CLAMPMODE1) ? 0x1 : 0; - new_eeopt |= IsDlgButtonChecked(hDlg, IDC_EE_CLAMPMODE2) ? 0x3 : 0; - - new_vuopt |= IsDlgButtonChecked(hDlg, IDC_VU_CLAMPMODE0) ? 0x0 : 0; - new_vuopt |= IsDlgButtonChecked(hDlg, IDC_VU_CLAMPMODE1) ? 0x1 : 0; - new_vuopt |= IsDlgButtonChecked(hDlg, IDC_VU_CLAMPMODE2) ? 0x3 : 0; - new_vuopt |= IsDlgButtonChecked(hDlg, IDC_VU_CLAMPMODE3) ? 0x7 : 0; - - Config.sseMXCSR |= IsDlgButtonChecked(hDlg, IDC_EE_CHECK1) ? 0x8000 : 0; // FtZ - Config.sseVUMXCSR |= IsDlgButtonChecked(hDlg, IDC_VU_CHECK1) ? 0x8000 : 0; // FtZ - - Config.sseMXCSR |= IsDlgButtonChecked(hDlg, IDC_EE_CHECK2) ? 0x0040 : 0; // DaZ - Config.sseVUMXCSR |= IsDlgButtonChecked(hDlg, IDC_VU_CHECK2) ? 0x0040 : 0; // DaZ - - EndDialog(hDlg, TRUE); - - // Roundmode options do not require CPU resets to take effect. - SetCPUState(Config.sseMXCSR, Config.sseVUMXCSR); - - if( new_eeopt != Config.eeOptions || new_vuopt != Config.vuOptions ) - { - // these do, however... - Config.eeOptions = new_eeopt; - Config.vuOptions = new_vuopt; - SysRestorableReset(); - } - - SaveConfig(); - break; - } - - case IDCANCEL: - - EndDialog(hDlg, FALSE); - break; - - case IDDEFAULT: - - Config.sseMXCSR = DEFAULT_sseMXCSR; - Config.sseVUMXCSR = DEFAULT_sseVUMXCSR; - - // SSE1 cpus do not support Denormals Are Zero flag. - if( !cpucaps.hasStreamingSIMD2Extensions ) { - Config.sseMXCSR &= ~0x0040; - Config.sseVUMXCSR &= ~0x0040; - } - - InitRoundClampModes( hDlg, DEFAULT_eeOptions, DEFAULT_vuOptions ); - - CheckDlgButton(hDlg, IDC_EE_CHECK1, (Config.sseMXCSR & 0x8000) ? TRUE : FALSE); - CheckDlgButton(hDlg, IDC_VU_CHECK1, (Config.sseVUMXCSR & 0x8000) ? TRUE : FALSE); - - CheckDlgButton(hDlg, IDC_EE_CHECK2, (Config.sseMXCSR & 0x0040) ? TRUE : FALSE); - CheckDlgButton(hDlg, IDC_VU_CHECK2, (Config.sseVUMXCSR & 0x0040) ? TRUE : FALSE); - break; - - case IDC_EE_ROUNDMODE0: - case IDC_EE_ROUNDMODE1: - case IDC_EE_ROUNDMODE2: - case IDC_EE_ROUNDMODE3: - - CheckRadioButton(hDlg, IDC_EE_ROUNDMODE0, IDC_EE_ROUNDMODE3, IDC_EE_ROUNDMODE0 + ( LOWORD(wParam) % IDC_EE_ROUNDMODE0 ) ); - break; - - case IDC_VU_ROUNDMODE0: - case IDC_VU_ROUNDMODE1: - case IDC_VU_ROUNDMODE2: - case IDC_VU_ROUNDMODE3: - - CheckRadioButton(hDlg, IDC_VU_ROUNDMODE0, IDC_VU_ROUNDMODE3, IDC_VU_ROUNDMODE0 + ( LOWORD(wParam) % IDC_VU_ROUNDMODE0 ) ); - break; - - case IDC_EE_CLAMPMODE0: - case IDC_EE_CLAMPMODE1: - case IDC_EE_CLAMPMODE2: - - CheckRadioButton(hDlg, IDC_EE_CLAMPMODE0, IDC_EE_CLAMPMODE2, IDC_EE_CLAMPMODE0 + ( LOWORD(wParam) % IDC_EE_CLAMPMODE0 ) ); - break; - - case IDC_VU_CLAMPMODE0: - case IDC_VU_CLAMPMODE1: - case IDC_VU_CLAMPMODE2: - case IDC_VU_CLAMPMODE3: - - CheckRadioButton(hDlg, IDC_VU_CLAMPMODE0, IDC_VU_CLAMPMODE3, IDC_VU_CLAMPMODE0 + ( LOWORD(wParam) % IDC_VU_CLAMPMODE0 ) ); - break; - } - - return TRUE; - } - - return FALSE; -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Win32.h" + +#include "Common.h" +#include "ix86/ix86.h" + +// the EE and VU roundmodes are passed in so that we can "retain" the config values during +// default button action. The checkbox statuses are checked against the Config settings when +// the user hits OK, and the game only resets if they differ. + +static void InitRoundClampModes( HWND hDlg, u32 new_eeopt, u32 new_vuopt ) +{ + CheckRadioButton(hDlg, IDC_EE_ROUNDMODE0, IDC_EE_ROUNDMODE3, IDC_EE_ROUNDMODE0 + ((Config.sseMXCSR & 0x6000) >> 13)); + CheckRadioButton(hDlg, IDC_VU_ROUNDMODE0, IDC_VU_ROUNDMODE3, IDC_VU_ROUNDMODE0 + ((Config.sseVUMXCSR & 0x6000) >> 13)); + CheckRadioButton(hDlg, IDC_EE_CLAMPMODE0, IDC_EE_CLAMPMODE2, IDC_EE_CLAMPMODE0 + ((new_eeopt & 0x2) ? 2 : (new_eeopt & 0x1))); + + if (new_vuopt & 0x4) CheckRadioButton(hDlg, IDC_VU_CLAMPMODE0, IDC_VU_CLAMPMODE3, IDC_VU_CLAMPMODE0 + 3); + else if (new_vuopt & 0x2) CheckRadioButton(hDlg, IDC_VU_CLAMPMODE0, IDC_VU_CLAMPMODE3, IDC_VU_CLAMPMODE0 + 2); + else if (new_vuopt & 0x1) CheckRadioButton(hDlg, IDC_VU_CLAMPMODE0, IDC_VU_CLAMPMODE3, IDC_VU_CLAMPMODE0 + 1); + else CheckRadioButton(hDlg, IDC_VU_CLAMPMODE0, IDC_VU_CLAMPMODE3, IDC_VU_CLAMPMODE0 + 0); + + if (Config.sseMXCSR & 0x8000) CheckDlgButton(hDlg, IDC_EE_CHECK1, TRUE); + if (Config.sseVUMXCSR & 0x8000) CheckDlgButton(hDlg, IDC_VU_CHECK1, TRUE); +} + +BOOL APIENTRY AdvancedOptionsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + + InitRoundClampModes( hDlg, Config.eeOptions, Config.vuOptions ); + + if( !cpucaps.hasStreamingSIMD2Extensions ) { + // SSE1 cpus do not support Denormals Are Zero flag. + Config.sseMXCSR &= ~0x0040; + Config.sseVUMXCSR &= ~0x0040; + EnableWindow( GetDlgItem( hDlg, IDC_EE_CHECK2 ), FALSE ); + EnableWindow( GetDlgItem( hDlg, IDC_VU_CHECK2 ), FALSE ); + CheckDlgButton( hDlg, IDC_EE_CHECK2, FALSE ); + CheckDlgButton( hDlg, IDC_VU_CHECK2, FALSE ); + } + else { + if (Config.sseMXCSR & 0x0040) CheckDlgButton(hDlg, IDC_EE_CHECK2, TRUE); + if (Config.sseVUMXCSR & 0x0040) CheckDlgButton(hDlg, IDC_VU_CHECK2, TRUE); + } + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + { + u32 new_eeopt = 0; + u32 new_vuopt = 0; + + Config.sseMXCSR &= 0x1fbf; + Config.sseVUMXCSR &= 0x1fbf; + + Config.sseMXCSR |= IsDlgButtonChecked(hDlg, IDC_EE_ROUNDMODE0) ? 0x0000 : 0; // Round Nearest + Config.sseMXCSR |= IsDlgButtonChecked(hDlg, IDC_EE_ROUNDMODE1) ? 0x2000 : 0; // Round Negative + Config.sseMXCSR |= IsDlgButtonChecked(hDlg, IDC_EE_ROUNDMODE2) ? 0x4000 : 0; // Round Postive + Config.sseMXCSR |= IsDlgButtonChecked(hDlg, IDC_EE_ROUNDMODE3) ? 0x6000 : 0; // Round Zero / Chop + + Config.sseVUMXCSR |= IsDlgButtonChecked(hDlg, IDC_VU_ROUNDMODE0) ? 0x0000 : 0; // Round Nearest + Config.sseVUMXCSR |= IsDlgButtonChecked(hDlg, IDC_VU_ROUNDMODE1) ? 0x2000 : 0; // Round Negative + Config.sseVUMXCSR |= IsDlgButtonChecked(hDlg, IDC_VU_ROUNDMODE2) ? 0x4000 : 0; // Round Postive + Config.sseVUMXCSR |= IsDlgButtonChecked(hDlg, IDC_VU_ROUNDMODE3) ? 0x6000 : 0; // Round Zero / Chop + + new_eeopt |= IsDlgButtonChecked(hDlg, IDC_EE_CLAMPMODE0) ? 0x0 : 0; + new_eeopt |= IsDlgButtonChecked(hDlg, IDC_EE_CLAMPMODE1) ? 0x1 : 0; + new_eeopt |= IsDlgButtonChecked(hDlg, IDC_EE_CLAMPMODE2) ? 0x3 : 0; + + new_vuopt |= IsDlgButtonChecked(hDlg, IDC_VU_CLAMPMODE0) ? 0x0 : 0; + new_vuopt |= IsDlgButtonChecked(hDlg, IDC_VU_CLAMPMODE1) ? 0x1 : 0; + new_vuopt |= IsDlgButtonChecked(hDlg, IDC_VU_CLAMPMODE2) ? 0x3 : 0; + new_vuopt |= IsDlgButtonChecked(hDlg, IDC_VU_CLAMPMODE3) ? 0x7 : 0; + + Config.sseMXCSR |= IsDlgButtonChecked(hDlg, IDC_EE_CHECK1) ? 0x8000 : 0; // FtZ + Config.sseVUMXCSR |= IsDlgButtonChecked(hDlg, IDC_VU_CHECK1) ? 0x8000 : 0; // FtZ + + Config.sseMXCSR |= IsDlgButtonChecked(hDlg, IDC_EE_CHECK2) ? 0x0040 : 0; // DaZ + Config.sseVUMXCSR |= IsDlgButtonChecked(hDlg, IDC_VU_CHECK2) ? 0x0040 : 0; // DaZ + + EndDialog(hDlg, TRUE); + + // Roundmode options do not require CPU resets to take effect. + SetCPUState(Config.sseMXCSR, Config.sseVUMXCSR); + + if( new_eeopt != Config.eeOptions || new_vuopt != Config.vuOptions ) + { + // these do, however... + Config.eeOptions = new_eeopt; + Config.vuOptions = new_vuopt; + SysRestorableReset(); + } + + SaveConfig(); + break; + } + + case IDCANCEL: + + EndDialog(hDlg, FALSE); + break; + + case IDDEFAULT: + + Config.sseMXCSR = DEFAULT_sseMXCSR; + Config.sseVUMXCSR = DEFAULT_sseVUMXCSR; + + // SSE1 cpus do not support Denormals Are Zero flag. + if( !cpucaps.hasStreamingSIMD2Extensions ) { + Config.sseMXCSR &= ~0x0040; + Config.sseVUMXCSR &= ~0x0040; + } + + InitRoundClampModes( hDlg, DEFAULT_eeOptions, DEFAULT_vuOptions ); + + CheckDlgButton(hDlg, IDC_EE_CHECK1, (Config.sseMXCSR & 0x8000) ? TRUE : FALSE); + CheckDlgButton(hDlg, IDC_VU_CHECK1, (Config.sseVUMXCSR & 0x8000) ? TRUE : FALSE); + + CheckDlgButton(hDlg, IDC_EE_CHECK2, (Config.sseMXCSR & 0x0040) ? TRUE : FALSE); + CheckDlgButton(hDlg, IDC_VU_CHECK2, (Config.sseVUMXCSR & 0x0040) ? TRUE : FALSE); + break; + + case IDC_EE_ROUNDMODE0: + case IDC_EE_ROUNDMODE1: + case IDC_EE_ROUNDMODE2: + case IDC_EE_ROUNDMODE3: + + CheckRadioButton(hDlg, IDC_EE_ROUNDMODE0, IDC_EE_ROUNDMODE3, IDC_EE_ROUNDMODE0 + ( LOWORD(wParam) % IDC_EE_ROUNDMODE0 ) ); + break; + + case IDC_VU_ROUNDMODE0: + case IDC_VU_ROUNDMODE1: + case IDC_VU_ROUNDMODE2: + case IDC_VU_ROUNDMODE3: + + CheckRadioButton(hDlg, IDC_VU_ROUNDMODE0, IDC_VU_ROUNDMODE3, IDC_VU_ROUNDMODE0 + ( LOWORD(wParam) % IDC_VU_ROUNDMODE0 ) ); + break; + + case IDC_EE_CLAMPMODE0: + case IDC_EE_CLAMPMODE1: + case IDC_EE_CLAMPMODE2: + + CheckRadioButton(hDlg, IDC_EE_CLAMPMODE0, IDC_EE_CLAMPMODE2, IDC_EE_CLAMPMODE0 + ( LOWORD(wParam) % IDC_EE_CLAMPMODE0 ) ); + break; + + case IDC_VU_CLAMPMODE0: + case IDC_VU_CLAMPMODE1: + case IDC_VU_CLAMPMODE2: + case IDC_VU_CLAMPMODE3: + + CheckRadioButton(hDlg, IDC_VU_CLAMPMODE0, IDC_VU_CLAMPMODE3, IDC_VU_CLAMPMODE0 + ( LOWORD(wParam) % IDC_VU_CLAMPMODE0 ) ); + break; + } + + return TRUE; + } + + return FALSE; +} diff --git a/pcsx2/windows/ConfigDlg.cpp b/pcsx2/windows/ConfigDlg.cpp index 4e0359878e..a1f40fb650 100644 --- a/pcsx2/windows/ConfigDlg.cpp +++ b/pcsx2/windows/ConfigDlg.cpp @@ -1,578 +1,578 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" -#include "Win32.h" - -#include -#include "common.h" -#include "plugins.h" -#include "resource.h" - -struct ComboInitializer -{ - HWND hwnd; - - HANDLE Find; - HANDLE Lib; - - WIN32_FIND_DATA FindData; - - _PS2EgetLibType PS2E_GetLibType; - _PS2EgetLibName PS2E_GetLibName; - _PS2EgetLibVersion2 PS2E_GetLibVersion2; - - long version; - u32 type; - - ComboInitializer( HWND hwndDlg ) : - hwnd( hwndDlg ) - , Find( INVALID_HANDLE_VALUE ) - , Lib( NULL ) - , PS2E_GetLibType( NULL ) - , PS2E_GetLibName( NULL ) - , PS2E_GetLibVersion2( NULL ) - { - string tmpStr; - Path::Combine( tmpStr, Config.PluginsDir, "*.dll" ); - Find = FindFirstFile(tmpStr.c_str(), &FindData); - } - - ~ComboInitializer() - { - if (Find!=INVALID_HANDLE_VALUE) - FindClose(Find); - } - - bool FindNext() - { - return !!FindNextFile( Find, &FindData ); - } - - bool LoadNextLibrary() - { - string tmpStr; - Path::Combine( tmpStr, Config.PluginsDir, FindData.cFileName ); - Lib = LoadLibrary(tmpStr.c_str()); - if (Lib == NULL) - { - Console::Error( "Plugin load failure: %hs\n\tSysLibError Message: %s", params &tmpStr, SysLibError() ); - return false; - } - - PS2E_GetLibType = (_PS2EgetLibType) GetProcAddress((HMODULE)Lib,"PS2EgetLibType"); - PS2E_GetLibName = (_PS2EgetLibName) GetProcAddress((HMODULE)Lib,"PS2EgetLibName"); - PS2E_GetLibVersion2 = (_PS2EgetLibVersion2) GetProcAddress((HMODULE)Lib,"PS2EgetLibVersion2"); - - if( PS2E_GetLibType == NULL || PS2E_GetLibName == NULL || PS2E_GetLibVersion2 == NULL ) - return false; - - type = PS2E_GetLibType(); - return true; - } - - void AddPlugin(HWND hwndCombo, const char* str) - { - string tmpStr; - int i; - - ssprintf(tmpStr, "%s %d.%d.%d", PS2E_GetLibName(), (version>>8)&0xff, version&0xff, (version>>24)&0xff); - char* lp = (char *)malloc(strlen(FindData.cFileName)+8); - sprintf(lp, "%s", FindData.cFileName); - i = ComboBox_AddString(hwndCombo, tmpStr.c_str()); - ComboBox_SetItemData(hwndCombo, i, lp); - if (_stricmp(str, lp)==0) - ComboBox_SetCurSel(hwndCombo, i); - } - - bool CheckVersion( const char* typeStr, u32 pluginType, long checkver ) - { - if( type & pluginType ) - { - version = PS2E_GetLibVersion2( pluginType ); - if ( ((version >> 16)&0xff) == checkver ) - return true; - - Console::Notice("%s Plugin %s: Version %x != %x", params typeStr, FindData.cFileName, 0xff&(version >> 16), checkver); - } - return false; - } -}; - -BOOL OnConfigureDialog(HWND hW) { - HWND const hWC_GS=GetDlgItem(hW,IDC_LISTGS); - HWND const hWC_PAD1=GetDlgItem(hW,IDC_LISTPAD1); - HWND const hWC_PAD2=GetDlgItem(hW,IDC_LISTPAD2); - HWND const hWC_SPU2=GetDlgItem(hW,IDC_LISTSPU2); - HWND const hWC_CDVD=GetDlgItem(hW,IDC_LISTCDVD); - HWND const hWC_DEV9=GetDlgItem(hW,IDC_LISTDEV9); - HWND const hWC_USB=GetDlgItem(hW,IDC_LISTUSB); - HWND const hWC_FW=GetDlgItem(hW,IDC_LISTFW); - HWND const hWC_BIOS=GetDlgItem(hW,IDC_LISTBIOS); - - ComboInitializer tool(hW); - if( tool.Find == INVALID_HANDLE_VALUE ) // epic fail? - return FALSE; - - do - { - if( !tool.LoadNextLibrary() ) continue; - - if( tool.CheckVersion( "GS", PS2E_LT_GS, PS2E_GS_VERSION ) ) - tool.AddPlugin(hWC_GS, winConfig.GS); - - if (tool.type & PS2E_LT_PAD) - { - _PADquery query; - - query = (_PADquery)GetProcAddress((HMODULE)tool.Lib, "PADquery"); - if( query != NULL ) - { - if( tool.CheckVersion( "PAD", PS2E_LT_PAD, PS2E_PAD_VERSION ) ) - { - if (query() & 0x1) - tool.AddPlugin(hWC_PAD1, winConfig.PAD1); - if (query() & 0x2) - tool.AddPlugin(hWC_PAD2, winConfig.PAD2); - } - } - } - - if( tool.CheckVersion( "SPU2", PS2E_LT_SPU2, PS2E_SPU2_VERSION ) ) - tool.AddPlugin(hWC_SPU2, winConfig.SPU2); - - if( tool.CheckVersion( "CDVD", PS2E_LT_CDVD, PS2E_CDVD_VERSION ) ) - tool.AddPlugin(hWC_CDVD, winConfig.CDVD); - - if( tool.CheckVersion( "DEV9", PS2E_LT_DEV9, PS2E_DEV9_VERSION ) ) - tool.AddPlugin(hWC_DEV9, winConfig.DEV9); - - if( tool.CheckVersion( "USB", PS2E_LT_USB, PS2E_USB_VERSION ) ) - tool.AddPlugin(hWC_USB, winConfig.USB); - - if( tool.CheckVersion( "FW", PS2E_LT_FW, PS2E_FW_VERSION ) ) - tool.AddPlugin(hWC_FW, winConfig.FW); - - } while( tool.FindNext() ); - -// BIOS - - /*lp=(char *)malloc(strlen("HLE") + 1); - sprintf(lp, "HLE"); - i=ComboBox_AddString(hWC_BIOS, _("Internal HLE Bios")); - ComboBox_SetItemData(hWC_BIOS, i, lp); - if (_stricmp(Config.Bios, lp)==0) - ComboBox_SetCurSel(hWC_BIOS, i);*/ - - HANDLE Find; - - WIN32_FIND_DATA FindData; - string tmpStr; - - Path::Combine( tmpStr, Config.BiosDir, "*" ); - Find=FindFirstFile(tmpStr.c_str(), &FindData); - - do - { - char* lp; - int i; - - char description[50]; //2002-09-22 (Florin) - if (Find==INVALID_HANDLE_VALUE) break; - if (!strcmp(FindData.cFileName, ".")) continue; - if (!strcmp(FindData.cFileName, "..")) continue; - if (FindData.nFileSizeLow > 1024 * 4096) continue; //2002-09-22 (Florin) - if (!IsBIOS(FindData.cFileName, description)) continue;//2002-09-22 (Florin) - lp = (char *)malloc(strlen(FindData.cFileName)+8); - sprintf(lp, "%s", (char *)FindData.cFileName); - i = ComboBox_AddString(hWC_BIOS, description); //2002-09-22 (Florin) modified - ComboBox_SetItemData(hWC_BIOS, i, lp); - if (_stricmp(Config.Bios, FindData.cFileName)==0) - ComboBox_SetCurSel(hWC_BIOS, i); - } while (FindNextFile(Find,&FindData)); - - if (Find!=INVALID_HANDLE_VALUE) FindClose(Find); - - if (ComboBox_GetCurSel(hWC_GS) == -1) - ComboBox_SetCurSel(hWC_GS, 0); - if (ComboBox_GetCurSel(hWC_PAD1) == -1) - ComboBox_SetCurSel(hWC_PAD1, 0); - if (ComboBox_GetCurSel(hWC_PAD2) == -1) - ComboBox_SetCurSel(hWC_PAD2, 0); - if (ComboBox_GetCurSel(hWC_SPU2) == -1) - ComboBox_SetCurSel(hWC_SPU2, 0); - if (ComboBox_GetCurSel(hWC_CDVD) == -1) - ComboBox_SetCurSel(hWC_CDVD, 0); - if (ComboBox_GetCurSel(hWC_DEV9) == -1) - ComboBox_SetCurSel(hWC_DEV9, 0); - if (ComboBox_GetCurSel(hWC_USB) == -1) - ComboBox_SetCurSel(hWC_USB, 0); - if (ComboBox_GetCurSel(hWC_FW) == -1) - ComboBox_SetCurSel(hWC_FW, 0); - if (ComboBox_GetCurSel(hWC_BIOS) == -1) - ComboBox_SetCurSel(hWC_BIOS, 0); - - return TRUE; -} - -#define CleanCombo(item) \ - hWC = GetDlgItem(hW, item); \ - iCnt = ComboBox_GetCount(hWC); \ - for (i=0; i +#include "common.h" +#include "plugins.h" +#include "resource.h" + +struct ComboInitializer +{ + HWND hwnd; + + HANDLE Find; + HANDLE Lib; + + WIN32_FIND_DATA FindData; + + _PS2EgetLibType PS2E_GetLibType; + _PS2EgetLibName PS2E_GetLibName; + _PS2EgetLibVersion2 PS2E_GetLibVersion2; + + long version; + u32 type; + + ComboInitializer( HWND hwndDlg ) : + hwnd( hwndDlg ) + , Find( INVALID_HANDLE_VALUE ) + , Lib( NULL ) + , PS2E_GetLibType( NULL ) + , PS2E_GetLibName( NULL ) + , PS2E_GetLibVersion2( NULL ) + { + string tmpStr; + Path::Combine( tmpStr, Config.PluginsDir, "*.dll" ); + Find = FindFirstFile(tmpStr.c_str(), &FindData); + } + + ~ComboInitializer() + { + if (Find!=INVALID_HANDLE_VALUE) + FindClose(Find); + } + + bool FindNext() + { + return !!FindNextFile( Find, &FindData ); + } + + bool LoadNextLibrary() + { + string tmpStr; + Path::Combine( tmpStr, Config.PluginsDir, FindData.cFileName ); + Lib = LoadLibrary(tmpStr.c_str()); + if (Lib == NULL) + { + Console::Error( "Plugin load failure: %hs\n\tSysLibError Message: %s", params &tmpStr, SysLibError() ); + return false; + } + + PS2E_GetLibType = (_PS2EgetLibType) GetProcAddress((HMODULE)Lib,"PS2EgetLibType"); + PS2E_GetLibName = (_PS2EgetLibName) GetProcAddress((HMODULE)Lib,"PS2EgetLibName"); + PS2E_GetLibVersion2 = (_PS2EgetLibVersion2) GetProcAddress((HMODULE)Lib,"PS2EgetLibVersion2"); + + if( PS2E_GetLibType == NULL || PS2E_GetLibName == NULL || PS2E_GetLibVersion2 == NULL ) + return false; + + type = PS2E_GetLibType(); + return true; + } + + void AddPlugin(HWND hwndCombo, const char* str) + { + string tmpStr; + int i; + + ssprintf(tmpStr, "%s %d.%d.%d", PS2E_GetLibName(), (version>>8)&0xff, version&0xff, (version>>24)&0xff); + char* lp = (char *)malloc(strlen(FindData.cFileName)+8); + sprintf(lp, "%s", FindData.cFileName); + i = ComboBox_AddString(hwndCombo, tmpStr.c_str()); + ComboBox_SetItemData(hwndCombo, i, lp); + if (_stricmp(str, lp)==0) + ComboBox_SetCurSel(hwndCombo, i); + } + + bool CheckVersion( const char* typeStr, u32 pluginType, long checkver ) + { + if( type & pluginType ) + { + version = PS2E_GetLibVersion2( pluginType ); + if ( ((version >> 16)&0xff) == checkver ) + return true; + + Console::Notice("%s Plugin %s: Version %x != %x", params typeStr, FindData.cFileName, 0xff&(version >> 16), checkver); + } + return false; + } +}; + +BOOL OnConfigureDialog(HWND hW) { + HWND const hWC_GS=GetDlgItem(hW,IDC_LISTGS); + HWND const hWC_PAD1=GetDlgItem(hW,IDC_LISTPAD1); + HWND const hWC_PAD2=GetDlgItem(hW,IDC_LISTPAD2); + HWND const hWC_SPU2=GetDlgItem(hW,IDC_LISTSPU2); + HWND const hWC_CDVD=GetDlgItem(hW,IDC_LISTCDVD); + HWND const hWC_DEV9=GetDlgItem(hW,IDC_LISTDEV9); + HWND const hWC_USB=GetDlgItem(hW,IDC_LISTUSB); + HWND const hWC_FW=GetDlgItem(hW,IDC_LISTFW); + HWND const hWC_BIOS=GetDlgItem(hW,IDC_LISTBIOS); + + ComboInitializer tool(hW); + if( tool.Find == INVALID_HANDLE_VALUE ) // epic fail? + return FALSE; + + do + { + if( !tool.LoadNextLibrary() ) continue; + + if( tool.CheckVersion( "GS", PS2E_LT_GS, PS2E_GS_VERSION ) ) + tool.AddPlugin(hWC_GS, winConfig.GS); + + if (tool.type & PS2E_LT_PAD) + { + _PADquery query; + + query = (_PADquery)GetProcAddress((HMODULE)tool.Lib, "PADquery"); + if( query != NULL ) + { + if( tool.CheckVersion( "PAD", PS2E_LT_PAD, PS2E_PAD_VERSION ) ) + { + if (query() & 0x1) + tool.AddPlugin(hWC_PAD1, winConfig.PAD1); + if (query() & 0x2) + tool.AddPlugin(hWC_PAD2, winConfig.PAD2); + } + } + } + + if( tool.CheckVersion( "SPU2", PS2E_LT_SPU2, PS2E_SPU2_VERSION ) ) + tool.AddPlugin(hWC_SPU2, winConfig.SPU2); + + if( tool.CheckVersion( "CDVD", PS2E_LT_CDVD, PS2E_CDVD_VERSION ) ) + tool.AddPlugin(hWC_CDVD, winConfig.CDVD); + + if( tool.CheckVersion( "DEV9", PS2E_LT_DEV9, PS2E_DEV9_VERSION ) ) + tool.AddPlugin(hWC_DEV9, winConfig.DEV9); + + if( tool.CheckVersion( "USB", PS2E_LT_USB, PS2E_USB_VERSION ) ) + tool.AddPlugin(hWC_USB, winConfig.USB); + + if( tool.CheckVersion( "FW", PS2E_LT_FW, PS2E_FW_VERSION ) ) + tool.AddPlugin(hWC_FW, winConfig.FW); + + } while( tool.FindNext() ); + +// BIOS + + /*lp=(char *)malloc(strlen("HLE") + 1); + sprintf(lp, "HLE"); + i=ComboBox_AddString(hWC_BIOS, _("Internal HLE Bios")); + ComboBox_SetItemData(hWC_BIOS, i, lp); + if (_stricmp(Config.Bios, lp)==0) + ComboBox_SetCurSel(hWC_BIOS, i);*/ + + HANDLE Find; + + WIN32_FIND_DATA FindData; + string tmpStr; + + Path::Combine( tmpStr, Config.BiosDir, "*" ); + Find=FindFirstFile(tmpStr.c_str(), &FindData); + + do + { + char* lp; + int i; + + char description[50]; //2002-09-22 (Florin) + if (Find==INVALID_HANDLE_VALUE) break; + if (!strcmp(FindData.cFileName, ".")) continue; + if (!strcmp(FindData.cFileName, "..")) continue; + if (FindData.nFileSizeLow > 1024 * 4096) continue; //2002-09-22 (Florin) + if (!IsBIOS(FindData.cFileName, description)) continue;//2002-09-22 (Florin) + lp = (char *)malloc(strlen(FindData.cFileName)+8); + sprintf(lp, "%s", (char *)FindData.cFileName); + i = ComboBox_AddString(hWC_BIOS, description); //2002-09-22 (Florin) modified + ComboBox_SetItemData(hWC_BIOS, i, lp); + if (_stricmp(Config.Bios, FindData.cFileName)==0) + ComboBox_SetCurSel(hWC_BIOS, i); + } while (FindNextFile(Find,&FindData)); + + if (Find!=INVALID_HANDLE_VALUE) FindClose(Find); + + if (ComboBox_GetCurSel(hWC_GS) == -1) + ComboBox_SetCurSel(hWC_GS, 0); + if (ComboBox_GetCurSel(hWC_PAD1) == -1) + ComboBox_SetCurSel(hWC_PAD1, 0); + if (ComboBox_GetCurSel(hWC_PAD2) == -1) + ComboBox_SetCurSel(hWC_PAD2, 0); + if (ComboBox_GetCurSel(hWC_SPU2) == -1) + ComboBox_SetCurSel(hWC_SPU2, 0); + if (ComboBox_GetCurSel(hWC_CDVD) == -1) + ComboBox_SetCurSel(hWC_CDVD, 0); + if (ComboBox_GetCurSel(hWC_DEV9) == -1) + ComboBox_SetCurSel(hWC_DEV9, 0); + if (ComboBox_GetCurSel(hWC_USB) == -1) + ComboBox_SetCurSel(hWC_USB, 0); + if (ComboBox_GetCurSel(hWC_FW) == -1) + ComboBox_SetCurSel(hWC_FW, 0); + if (ComboBox_GetCurSel(hWC_BIOS) == -1) + ComboBox_SetCurSel(hWC_BIOS, 0); + + return TRUE; +} + +#define CleanCombo(item) \ + hWC = GetDlgItem(hW, item); \ + iCnt = ComboBox_GetCount(hWC); \ + for (i=0; i>10)); - - sprintf(cfps,"%d",Config.CustomFps); - SetDlgItemText(hW, IDC_CUSTOMFPS, cfps); - - sprintf(cFrameskip,"%d",Config.CustomFrameSkip); - SetDlgItemText(hW, IDC_CUSTOM_FRAMESKIP, cFrameskip); - - sprintf(cConsecutiveFrames,"%d",Config.CustomConsecutiveFrames); - SetDlgItemText(hW, IDC_CUSTOM_CONSECUTIVE_FRAMES, cConsecutiveFrames); - - sprintf(cConsecutiveSkip,"%d",Config.CustomConsecutiveSkip); - SetDlgItemText(hW, IDC_CUSTOM_CONSECUTIVE_SKIP, cConsecutiveSkip); - - //EnableWindow( GetDlgItem( hW, IDC_CPU_GSMULTI ), !g_GameInProgress ); - - return TRUE; - - case WM_COMMAND: - switch(LOWORD(wParam)) - { - case IDCANCEL: - EndDialog(hW, FALSE); - return FALSE; - - case IDOK: - newopts = 0; - - if( SendDlgItemMessage(hW,IDC_CPU_EEREC,BM_GETCHECK,0,0) ) newopts |= PCSX2_EEREC; - - if( SendDlgItemMessage(hW,IDC_CPU_VU0REC,BM_GETCHECK,0,0) ) newopts |= PCSX2_VU0REC; - if( SendDlgItemMessage(hW,IDC_CPU_VU1REC,BM_GETCHECK,0,0) ) newopts |= PCSX2_VU1REC; - - if( SendDlgItemMessage(hW,IDC_CPU_GSMULTI,BM_GETCHECK,0,0) ) newopts |= PCSX2_GSMULTITHREAD; - - if( SendDlgItemMessage(hW,IDC_CPU_FL_NORMAL,BM_GETCHECK,0,0) ) newopts |= PCSX2_FRAMELIMIT_NORMAL; - else if( SendDlgItemMessage(hW,IDC_CPU_FL_LIMIT,BM_GETCHECK,0,0) ) newopts |= PCSX2_FRAMELIMIT_LIMIT; - else if( SendDlgItemMessage(hW,IDC_CPU_FL_SKIP,BM_GETCHECK,0,0) ) newopts |= PCSX2_FRAMELIMIT_SKIP; - else if( SendDlgItemMessage(hW,IDC_CPU_FL_SKIPVU,BM_GETCHECK,0,0) ) newopts |= PCSX2_FRAMELIMIT_VUSKIP; - - GetDlgItemText(hW, IDC_CUSTOMFPS, cfps, 20); - Config.CustomFps = atoi(cfps); - - GetDlgItemText(hW, IDC_CUSTOM_FRAMESKIP, cFrameskip, 20); - Config.CustomFrameSkip = atoi(cFrameskip); - - GetDlgItemText(hW, IDC_CUSTOM_CONSECUTIVE_FRAMES, cConsecutiveFrames, 20); - Config.CustomConsecutiveFrames = atoi(cConsecutiveFrames); - - GetDlgItemText(hW, IDC_CUSTOM_CONSECUTIVE_SKIP, cConsecutiveSkip, 20); - Config.CustomConsecutiveSkip = atoi(cConsecutiveSkip); - - EndDialog(hW, TRUE); - - if( Config.Options != newopts ) - { - SysRestorableReset(); - - if( (Config.Options&PCSX2_GSMULTITHREAD) ^ (newopts&PCSX2_GSMULTITHREAD) ) - { - // Need the MTGS setting to take effect, so close out the plugins: - PluginsResetGS(); - if( CHECK_MULTIGS ) - Console::Notice( "MTGS mode disabled.\n\tEnjoy the fruits of single-threaded simpicity." ); - else - Console::Notice( "MTGS mode enabled.\n\tWelcome to multi-threaded awesomeness." ); - } - Config.Options = newopts; - } - else if( Cpu != NULL ) - UpdateVSyncRate(); - - SaveConfig(); - - return FALSE; - } - return TRUE; - } - return FALSE; -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" +#include "Win32.h" + +#include "Common.h" +#include "Counters.h" +#include "VUmicro.h" +#include "Plugins.h" + +#include "ix86/ix86.h" + +static void EnableDlgItem( HWND hwndDlg, uint itemidx, bool enabled ) +{ + EnableWindow( GetDlgItem( hwndDlg, itemidx ), enabled ); +} + +BOOL CALLBACK CpuDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + char cpuspeedc[20]; + char features[256]; + char cfps[20]; + char cFrameskip[20]; + char cConsecutiveFrames[20]; + char cConsecutiveSkip[20]; + u32 newopts; + + switch(uMsg) { + case WM_INITDIALOG: + SetWindowText(hW, _("Cpu Config")); + SetDlgItemText(hW, IDC_VENDORINPUT,cpuinfo.x86ID ); + SetDlgItemText(hW, IDC_FAMILYINPUT, cpuinfo.x86Fam); + sprintf(cpuspeedc,"%d MHZ",cpuinfo.cpuspeed); + SetDlgItemText(hW, IDC_CPUSPEEDINPUT, cpuspeedc); + Static_SetText(GetDlgItem(hW, IDC_VENDORNAME), _("CPU Vendor")); + Static_SetText(GetDlgItem(hW, IDC_FAMILYNAME), _("Family")); + Static_SetText(GetDlgItem(hW, IDC_CPUSPEEDNAME), _("CPU Speed")); + Static_SetText(GetDlgItem(hW, IDC_FEATURESNAME), _("Features")); + Static_SetText(GetDlgItem(hW, IDC_CPU_EEREC), _("EERec - EE/IOP recompiler (need MMX/SSE)")); + Static_SetText(GetDlgItem(hW, IDC_CPU_VUGROUP), _("VU Recompilers - All options are set by default")); + Static_SetText(GetDlgItem(hW, IDC_CPU_VU0REC), _("VU0rec - enable recompiler for VU0 unit")); + Static_SetText(GetDlgItem(hW, IDC_CPU_VU1REC), _("VU1rec - enable recompiler for VU1 unit")); + Static_SetText(GetDlgItem(hW, IDC_CPU_GSMULTI), _("Multi threaded GS mode (MTGS)\n(faster on dual core/HT procs, requires pcsx2 restart)")); + Static_SetText(GetDlgItem(hW, IDC_FRAMELIMIT), _("Frame Limiting (F4 key switches the mode in-game!)")); + Static_SetText(GetDlgItem(hW, IDC_CPU_FL_NORMAL), _("Normal - All frames are rendered as fast as possible.")); + Static_SetText(GetDlgItem(hW, IDC_CPU_FL_LIMIT), _("Limit - Force frames to normal speeds if too fast.")); + Static_SetText(GetDlgItem(hW, IDC_CPU_FL_SKIP), _("Frame Skip - In order to achieve normal speeds,\nsome frames are skipped (fast).\nFps displayed counts skipped frames too.")); + Static_SetText(GetDlgItem(hW, IDC_CPU_FL_SKIPVU), _("VU Skip - Same as 'Frame Skip', but tries to skip more.\nArtifacts might be present, but will be faster.")); + Static_SetText(GetDlgItem(hW, IDC_CUSTOM_FPS), _("Custom FPS Limit (0=auto):")); + Static_SetText(GetDlgItem(hW, IDC_FRAMESKIP_LABEL1), _("Skip Frames when slower than:\n(See Note 1)")); + Static_SetText(GetDlgItem(hW, IDC_FRAMESKIP_LABEL2), _("Consecutive Frames before skipping:\n(See Note 2)")); + Static_SetText(GetDlgItem(hW, IDC_FRAMESKIP_LABEL3), _("*Note 1: Will only skip when slower than this fps number.\n (0 = Auto) ; (9999 = Forced-Frameskip regardless of speed.)\n (e.g. If set to 45, will only skip when slower than 45fps.)")); + Static_SetText(GetDlgItem(hW, IDC_FRAMESKIP_LABEL4), _("*Note 2: Will render this number of consecutive frames before\n skipping the next frame. (0=default)\n (e.g. If set to 2, will render 2 frames before skipping 1.)")); + Static_SetText(GetDlgItem(hW, IDC_FRAMESKIP_LABEL5), _("Consecutive Frames to skip:\n(See Note 3)")); + Static_SetText(GetDlgItem(hW, IDC_FRAMESKIP_LABEL6), _("*Note 3: Will skip this number of frames before\n rendering the next sequence of frames. (0=default)\n (e.g. If set to 2, will skip 2 consecutive frames whenever its time\n to skip.)")); + + Button_SetText(GetDlgItem(hW, IDOK), _("OK")); + Button_SetText(GetDlgItem(hW, IDCANCEL), _("Cancel")); + + //features[0]=':'; + //strcat(features,""); + strcpy(features,""); + if(cpucaps.hasMultimediaExtensions) strcat(features,"MMX"); + if(cpucaps.hasStreamingSIMDExtensions) strcat(features,",SSE"); + if(cpucaps.hasStreamingSIMD2Extensions) strcat(features,",SSE2"); + if(cpucaps.hasStreamingSIMD3Extensions) strcat(features,",SSE3"); + if(cpucaps.hasStreamingSIMD4Extensions) strcat(features,",SSE4.1"); +// if(cpucaps.has3DNOWInstructionExtensions) strcat(features,",3DNOW"); +// if(cpucaps.has3DNOWInstructionExtensionsExt)strcat(features,",3DNOW+"); +// if(cpucaps.hasAMD64BitArchitecture) strcat(features,",x86-64"); + SetDlgItemText(hW, IDC_FEATURESINPUT, features); + + CheckDlgButton(hW, IDC_CPU_EEREC, !!(Config.Options&PCSX2_EEREC)); + CheckDlgButton(hW, IDC_CPU_VU0REC, !!(Config.Options&PCSX2_VU0REC)); + CheckDlgButton(hW, IDC_CPU_VU1REC, !!(Config.Options&PCSX2_VU1REC)); + + EnableDlgItem( hW, IDC_CPU_EEREC, !g_Session.ForceDisableEErec ); + EnableDlgItem( hW, IDC_CPU_VU0REC, !g_Session.ForceDisableVU0rec ); + EnableDlgItem( hW, IDC_CPU_VU1REC, !g_Session.ForceDisableVU1rec ); + + CheckDlgButton(hW, IDC_CPU_GSMULTI, !!CHECK_MULTIGS); + + CheckRadioButton(hW,IDC_CPU_FL_NORMAL, IDC_CPU_FL_NORMAL+3, IDC_CPU_FL_NORMAL+(CHECK_FRAMELIMIT>>10)); + + sprintf(cfps,"%d",Config.CustomFps); + SetDlgItemText(hW, IDC_CUSTOMFPS, cfps); + + sprintf(cFrameskip,"%d",Config.CustomFrameSkip); + SetDlgItemText(hW, IDC_CUSTOM_FRAMESKIP, cFrameskip); + + sprintf(cConsecutiveFrames,"%d",Config.CustomConsecutiveFrames); + SetDlgItemText(hW, IDC_CUSTOM_CONSECUTIVE_FRAMES, cConsecutiveFrames); + + sprintf(cConsecutiveSkip,"%d",Config.CustomConsecutiveSkip); + SetDlgItemText(hW, IDC_CUSTOM_CONSECUTIVE_SKIP, cConsecutiveSkip); + + //EnableWindow( GetDlgItem( hW, IDC_CPU_GSMULTI ), !g_GameInProgress ); + + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDCANCEL: + EndDialog(hW, FALSE); + return FALSE; + + case IDOK: + newopts = 0; + + if( SendDlgItemMessage(hW,IDC_CPU_EEREC,BM_GETCHECK,0,0) ) newopts |= PCSX2_EEREC; + + if( SendDlgItemMessage(hW,IDC_CPU_VU0REC,BM_GETCHECK,0,0) ) newopts |= PCSX2_VU0REC; + if( SendDlgItemMessage(hW,IDC_CPU_VU1REC,BM_GETCHECK,0,0) ) newopts |= PCSX2_VU1REC; + + if( SendDlgItemMessage(hW,IDC_CPU_GSMULTI,BM_GETCHECK,0,0) ) newopts |= PCSX2_GSMULTITHREAD; + + if( SendDlgItemMessage(hW,IDC_CPU_FL_NORMAL,BM_GETCHECK,0,0) ) newopts |= PCSX2_FRAMELIMIT_NORMAL; + else if( SendDlgItemMessage(hW,IDC_CPU_FL_LIMIT,BM_GETCHECK,0,0) ) newopts |= PCSX2_FRAMELIMIT_LIMIT; + else if( SendDlgItemMessage(hW,IDC_CPU_FL_SKIP,BM_GETCHECK,0,0) ) newopts |= PCSX2_FRAMELIMIT_SKIP; + else if( SendDlgItemMessage(hW,IDC_CPU_FL_SKIPVU,BM_GETCHECK,0,0) ) newopts |= PCSX2_FRAMELIMIT_VUSKIP; + + GetDlgItemText(hW, IDC_CUSTOMFPS, cfps, 20); + Config.CustomFps = atoi(cfps); + + GetDlgItemText(hW, IDC_CUSTOM_FRAMESKIP, cFrameskip, 20); + Config.CustomFrameSkip = atoi(cFrameskip); + + GetDlgItemText(hW, IDC_CUSTOM_CONSECUTIVE_FRAMES, cConsecutiveFrames, 20); + Config.CustomConsecutiveFrames = atoi(cConsecutiveFrames); + + GetDlgItemText(hW, IDC_CUSTOM_CONSECUTIVE_SKIP, cConsecutiveSkip, 20); + Config.CustomConsecutiveSkip = atoi(cConsecutiveSkip); + + EndDialog(hW, TRUE); + + if( Config.Options != newopts ) + { + SysRestorableReset(); + + if( (Config.Options&PCSX2_GSMULTITHREAD) ^ (newopts&PCSX2_GSMULTITHREAD) ) + { + // Need the MTGS setting to take effect, so close out the plugins: + PluginsResetGS(); + if( CHECK_MULTIGS ) + Console::Notice( "MTGS mode disabled.\n\tEnjoy the fruits of single-threaded simpicity." ); + else + Console::Notice( "MTGS mode enabled.\n\tWelcome to multi-threaded awesomeness." ); + } + Config.Options = newopts; + } + else if( Cpu != NULL ) + UpdateVSyncRate(); + + SaveConfig(); + + return FALSE; + } + return TRUE; + } + return FALSE; +} diff --git a/pcsx2/windows/DebugMemory.cpp b/pcsx2/windows/DebugMemory.cpp index 4d674701c5..4004103c7b 100644 --- a/pcsx2/windows/DebugMemory.cpp +++ b/pcsx2/windows/DebugMemory.cpp @@ -1,240 +1,240 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Win32.h" -#include "Common.h" -#include "resource.h" - -unsigned long memory_addr; -BOOL mem_inupdate = FALSE; -HWND memoryhWnd,hWnd_memscroll,hWnd_memorydump; -unsigned long memory_patch; -unsigned long data_patch; - -///MEMORY DUMP -unsigned char Debug_Read8(unsigned long addr)//just for anycase.. -{ -#ifdef _WIN32 - __try - { -#endif - u8 val8; - memRead8(addr, &val8); - return val8; -#ifdef _WIN32 - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return 0; - } -#endif -} - - -void RefreshMemory(void) -{ - int x, y; - unsigned long addr; - unsigned char b; - - char buf[128], text[32], temp[8]; - - - - addr = memory_addr; - - if (!mem_inupdate) - { - sprintf(buf, "%08X", addr); - SetDlgItemText(memoryhWnd, IDC_MEMORY_ADDR, buf); - } - - SendMessage(hWnd_memorydump, LB_RESETCONTENT, 0, 0); - - for (y = 0; y < 21; y++) - { - memzero_obj(text); - sprintf(buf, "%08X: ", addr); - - for (x = 0; x < 16; x++) - { - b = Debug_Read8(addr++); - - sprintf(temp, "%02X ", b); - strcat(buf, temp); - - if (b < 32 || b > 127) b = 32; - sprintf(temp, "%c", b); - strcat(text, temp); - - - if (x == 7) strcat(buf, " "); - } - - strcat(buf, " "); - strcat(buf, text); - - SendMessage(hWnd_memorydump, LB_ADDSTRING, 0, (LPARAM)buf); - } -} - - -BOOL APIENTRY DumpMemProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - char start[16], end[16], fname[128], buf[128]; - u32 start_pc, end_pc, addr; - u8 data; - - FILE *fp; - - switch (message) - { - case WM_INITDIALOG: - sprintf(buf, "%08X", cpuRegs.pc); - SetDlgItemText(hDlg, IDC_DUMPMEM_START, buf); - SetDlgItemText(hDlg, IDC_DUMPMEM_END, buf); - SetDlgItemText(hDlg, IDC_DUMPMEM_FNAME, "dump.raw"); - return TRUE; - - case WM_COMMAND: - if (LOWORD(wParam) == IDOK) - { - GetDlgItemText(hDlg, IDC_DUMPMEM_START, start, 9); - start[8] = 0; - sscanf(start, "%x", &start_pc); - start_pc &= 0xFFFFFFFC; - - GetDlgItemText(hDlg, IDC_DUMPMEM_END, end, 9); - end[8] = 0; - sscanf(end, "%x", &end_pc); - end_pc &= 0xFFFFFFFC; - - GetDlgItemText(hDlg, IDC_DUMPMEM_FNAME, fname, 128); - fp = fopen(fname, "wb"); - if (fp == NULL) - { - Msgbox::Alert("Can't open file '%s' for writing!", params fname); - } - else - { - for (addr = start_pc; addr < end_pc; addr ++) { - memRead8( addr, &data ); - fwrite(&data, 1, 1, fp); - } - - fclose(fp); - } - - EndDialog(hDlg, TRUE); - } else if (LOWORD(wParam) == IDCANCEL) { - EndDialog(hDlg, TRUE); - } - return TRUE; - } - - return FALSE; -} - - - -BOOL APIENTRY MemoryProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - - char buf[16]; - switch (message) - { - case WM_INITDIALOG: - memory_addr = cpuRegs.pc; - sprintf(buf, "%08X", memory_addr); - SetDlgItemText(hDlg, IDC_MEMORY_ADDR, buf); - memory_patch= 0; - sprintf(buf, "%08X", memory_patch); - SetDlgItemText(hDlg, IDC_ADDRESS_PATCH, buf); - data_patch=0; - sprintf(buf, "%08X", data_patch); - SetDlgItemText(hDlg, IDC_DATA_PATCH, buf); - hWnd_memorydump = GetDlgItem(hDlg, IDC_MEMORY_DUMP); - hWnd_memscroll = GetDlgItem(hDlg, IDC_MEM_SCROLL); - - - - SendMessage(hWnd_memorydump, LB_INITSTORAGE, 11, 1280); - SendMessage(hWnd_memscroll, SBM_SETRANGE, 0, MAXLONG); - SendMessage(hWnd_memscroll, SBM_SETPOS, MAXLONG / 2, TRUE); - - RefreshMemory(); - return TRUE; - case WM_VSCROLL: - switch ((int) LOWORD(wParam)) - { - case SB_LINEDOWN: memory_addr += 0x00000010; RefreshMemory(); break; - case SB_LINEUP: memory_addr -= 0x00000010; RefreshMemory(); break; - case SB_PAGEDOWN: memory_addr += 0x00000150; RefreshMemory(); break; - case SB_PAGEUP: memory_addr -= 0x00000150; RefreshMemory(); break; - } - - return TRUE; - - case WM_CLOSE: - EndDialog(hDlg, TRUE ); - return TRUE; - - - case WM_COMMAND: - if (HIWORD(wParam) == EN_UPDATE) - { - mem_inupdate = TRUE; - GetDlgItemText(hDlg, IDC_MEMORY_ADDR, buf, 9); - buf[8] = 0; - - sscanf(buf, "%x", &memory_addr); - RefreshMemory(); - mem_inupdate = FALSE; - return TRUE; - } - - switch (LOWORD(wParam)) { - case IDC_PATCH: - GetDlgItemText(hDlg, IDC_ADDRESS_PATCH, buf, 9);//32bit address - buf[8] = 0; - sscanf(buf, "%x", &memory_patch); - GetDlgItemText(hDlg, IDC_DATA_PATCH, buf, 9);//32 bit data only for far - buf[8] = 0; - sscanf(buf, "%x", &data_patch); - memWrite32( memory_patch, data_patch ); - sprintf(buf, "%08X", memory_patch); - SetDlgItemText(hDlg, IDC_MEMORY_ADDR, buf); - RefreshMemory(); - return TRUE; - - case IDC_DUMPRAW: - DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_DUMPMEM), hDlg, (DLGPROC)DumpMemProc); - - return TRUE; - - case IDC_MEMORY_CLOSE: - EndDialog(hDlg, TRUE ); - return TRUE; - } - break; - } - - return FALSE; -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Win32.h" +#include "Common.h" +#include "resource.h" + +unsigned long memory_addr; +BOOL mem_inupdate = FALSE; +HWND memoryhWnd,hWnd_memscroll,hWnd_memorydump; +unsigned long memory_patch; +unsigned long data_patch; + +///MEMORY DUMP +unsigned char Debug_Read8(unsigned long addr)//just for anycase.. +{ +#ifdef _WIN32 + __try + { +#endif + u8 val8; + memRead8(addr, &val8); + return val8; +#ifdef _WIN32 + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return 0; + } +#endif +} + + +void RefreshMemory(void) +{ + int x, y; + unsigned long addr; + unsigned char b; + + char buf[128], text[32], temp[8]; + + + + addr = memory_addr; + + if (!mem_inupdate) + { + sprintf(buf, "%08X", addr); + SetDlgItemText(memoryhWnd, IDC_MEMORY_ADDR, buf); + } + + SendMessage(hWnd_memorydump, LB_RESETCONTENT, 0, 0); + + for (y = 0; y < 21; y++) + { + memzero_obj(text); + sprintf(buf, "%08X: ", addr); + + for (x = 0; x < 16; x++) + { + b = Debug_Read8(addr++); + + sprintf(temp, "%02X ", b); + strcat(buf, temp); + + if (b < 32 || b > 127) b = 32; + sprintf(temp, "%c", b); + strcat(text, temp); + + + if (x == 7) strcat(buf, " "); + } + + strcat(buf, " "); + strcat(buf, text); + + SendMessage(hWnd_memorydump, LB_ADDSTRING, 0, (LPARAM)buf); + } +} + + +BOOL APIENTRY DumpMemProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char start[16], end[16], fname[128], buf[128]; + u32 start_pc, end_pc, addr; + u8 data; + + FILE *fp; + + switch (message) + { + case WM_INITDIALOG: + sprintf(buf, "%08X", cpuRegs.pc); + SetDlgItemText(hDlg, IDC_DUMPMEM_START, buf); + SetDlgItemText(hDlg, IDC_DUMPMEM_END, buf); + SetDlgItemText(hDlg, IDC_DUMPMEM_FNAME, "dump.raw"); + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) + { + GetDlgItemText(hDlg, IDC_DUMPMEM_START, start, 9); + start[8] = 0; + sscanf(start, "%x", &start_pc); + start_pc &= 0xFFFFFFFC; + + GetDlgItemText(hDlg, IDC_DUMPMEM_END, end, 9); + end[8] = 0; + sscanf(end, "%x", &end_pc); + end_pc &= 0xFFFFFFFC; + + GetDlgItemText(hDlg, IDC_DUMPMEM_FNAME, fname, 128); + fp = fopen(fname, "wb"); + if (fp == NULL) + { + Msgbox::Alert("Can't open file '%s' for writing!", params fname); + } + else + { + for (addr = start_pc; addr < end_pc; addr ++) { + memRead8( addr, &data ); + fwrite(&data, 1, 1, fp); + } + + fclose(fp); + } + + EndDialog(hDlg, TRUE); + } else if (LOWORD(wParam) == IDCANCEL) { + EndDialog(hDlg, TRUE); + } + return TRUE; + } + + return FALSE; +} + + + +BOOL APIENTRY MemoryProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + + char buf[16]; + switch (message) + { + case WM_INITDIALOG: + memory_addr = cpuRegs.pc; + sprintf(buf, "%08X", memory_addr); + SetDlgItemText(hDlg, IDC_MEMORY_ADDR, buf); + memory_patch= 0; + sprintf(buf, "%08X", memory_patch); + SetDlgItemText(hDlg, IDC_ADDRESS_PATCH, buf); + data_patch=0; + sprintf(buf, "%08X", data_patch); + SetDlgItemText(hDlg, IDC_DATA_PATCH, buf); + hWnd_memorydump = GetDlgItem(hDlg, IDC_MEMORY_DUMP); + hWnd_memscroll = GetDlgItem(hDlg, IDC_MEM_SCROLL); + + + + SendMessage(hWnd_memorydump, LB_INITSTORAGE, 11, 1280); + SendMessage(hWnd_memscroll, SBM_SETRANGE, 0, MAXLONG); + SendMessage(hWnd_memscroll, SBM_SETPOS, MAXLONG / 2, TRUE); + + RefreshMemory(); + return TRUE; + case WM_VSCROLL: + switch ((int) LOWORD(wParam)) + { + case SB_LINEDOWN: memory_addr += 0x00000010; RefreshMemory(); break; + case SB_LINEUP: memory_addr -= 0x00000010; RefreshMemory(); break; + case SB_PAGEDOWN: memory_addr += 0x00000150; RefreshMemory(); break; + case SB_PAGEUP: memory_addr -= 0x00000150; RefreshMemory(); break; + } + + return TRUE; + + case WM_CLOSE: + EndDialog(hDlg, TRUE ); + return TRUE; + + + case WM_COMMAND: + if (HIWORD(wParam) == EN_UPDATE) + { + mem_inupdate = TRUE; + GetDlgItemText(hDlg, IDC_MEMORY_ADDR, buf, 9); + buf[8] = 0; + + sscanf(buf, "%x", &memory_addr); + RefreshMemory(); + mem_inupdate = FALSE; + return TRUE; + } + + switch (LOWORD(wParam)) { + case IDC_PATCH: + GetDlgItemText(hDlg, IDC_ADDRESS_PATCH, buf, 9);//32bit address + buf[8] = 0; + sscanf(buf, "%x", &memory_patch); + GetDlgItemText(hDlg, IDC_DATA_PATCH, buf, 9);//32 bit data only for far + buf[8] = 0; + sscanf(buf, "%x", &data_patch); + memWrite32( memory_patch, data_patch ); + sprintf(buf, "%08X", memory_patch); + SetDlgItemText(hDlg, IDC_MEMORY_ADDR, buf); + RefreshMemory(); + return TRUE; + + case IDC_DUMPRAW: + DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_DUMPMEM), hDlg, (DLGPROC)DumpMemProc); + + return TRUE; + + case IDC_MEMORY_CLOSE: + EndDialog(hDlg, TRUE ); + return TRUE; + } + break; + } + + return FALSE; +} diff --git a/pcsx2/windows/Debugger.cpp b/pcsx2/windows/Debugger.cpp index ed46beb81c..4ded730d28 100644 --- a/pcsx2/windows/Debugger.cpp +++ b/pcsx2/windows/Debugger.cpp @@ -1,679 +1,679 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "win32.h" - -#include "resource.h" -#include "R5900OpcodeTables.h" -#include "Debugger.h" -#include "Common.h" -#include "IopMem.h" -#include "R3000A.h" - -#ifdef _MSC_VER -#pragma warning(disable:4996) //ignore the stricmp deprecated warning -#endif - -void RefreshIOPDebugger(void); -extern int ISR3000A;//for disasm -HWND hWnd_debugdisasm, hWnd_debugscroll,hWnd_IOP_debugdisasm, hWnd_IOP_debugscroll; -unsigned long DebuggerPC = 0; -HWND hRegDlg;//for debug registers.. -HWND debughWnd; -unsigned long DebuggerIOPPC=0; -HWND hIOPDlg;//IOP debugger - -breakpoints bkpt_regv[NUM_BREAKPOINTS]; - - -void RefreshDebugAll()//refresh disasm and register window -{ - RefreshDebugger(); - RefreshIOPDebugger(); - UpdateRegs(); -} - -void MakeDebugOpcode(void) -{ - memRead32( opcode_addr, &cpuRegs.code ); -} - -void MakeIOPDebugOpcode(void) -{ - psxRegs.code = PSXMu32( opcode_addr); -} - -BOOL HasBreakpoint() -{ - int t; - - for (t = 0; t < NUM_BREAKPOINTS; t++) - { - switch (bkpt_regv[t].type) { - case 1: // exec - if (cpuRegs.pc == bkpt_regv[t].value) return TRUE; - break; - - case 2: // count - if ((cpuRegs.cycle - 10) <= bkpt_regv[t].value && - (cpuRegs.cycle + 10) >= bkpt_regv[t].value) return TRUE; - break; - } - } - return FALSE; - -} -BOOL APIENTRY JumpProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - char buf[16]; - unsigned long temp; - - switch (message) - { - case WM_INITDIALOG: - sprintf(buf, "%08X", cpuRegs.pc); - SetDlgItemText(hDlg, IDC_JUMP_PC, buf); - return TRUE; - - case WM_COMMAND: - if (LOWORD(wParam) == IDOK) - { - GetDlgItemText(hDlg, IDC_JUMP_PC, buf, 9); - - buf[8] = 0; - sscanf(buf, "%x", &temp); - - temp &= 0xFFFFFFFC; - DebuggerPC = temp - 0x00000038; - - EndDialog(hDlg, TRUE); - } else if (LOWORD(wParam) == IDCANCEL) { - EndDialog(hDlg, TRUE); - } - return TRUE; - } - - return FALSE; -} - -extern void EEDumpRegs(FILE * fp); -extern void IOPDumpRegs(FILE * fp); -BOOL APIENTRY DumpProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - char start[16], end[16], fname[128], tmp[128]; - unsigned long start_pc, end_pc, temp; - - FILE *fp; - - switch (message) - { - case WM_INITDIALOG: - sprintf(tmp, "%08X", cpuRegs.pc); - SetDlgItemText(hDlg, IDC_DUMP_START, tmp); - SetDlgItemText(hDlg, IDC_DUMP_END, tmp); - SetDlgItemText(hDlg, IDC_DUMP_FNAME, "EEdisasm.txt"); - - sprintf(tmp, "%08X", psxRegs.pc); - SetDlgItemText(hDlg, IDC_DUMP_STARTIOP, tmp); - SetDlgItemText(hDlg, IDC_DUMP_ENDIOP, tmp); - SetDlgItemText(hDlg, IDC_DUMP_FNAMEIOP, "IOPdisasm.txt"); - return TRUE; - - case WM_COMMAND: - if (LOWORD(wParam) == IDOK) - { - GetDlgItemText(hDlg, IDC_DUMP_START, start, 9); - start[8] = 0; - sscanf(start, "%x", &start_pc); - start_pc &= 0xFFFFFFFC; - - GetDlgItemText(hDlg, IDC_DUMP_END, end, 9); - end[8] = 0; - sscanf(end, "%x", &end_pc); - end_pc &= 0xFFFFFFFC; - - GetDlgItemText(hDlg, IDC_DUMP_FNAME, fname, 128); - fp = fopen(fname, "wt"); - if (fp == NULL) - { - //MessageBox(MainhWnd, "Can't open file for writing!", NULL, MB_OK); - } - else - { - std::string output; - - fprintf(fp,"----------------------------------\n"); - fprintf(fp,"EE DISASM TEXT DOCUMENT BY PCSX2 \n"); - fprintf(fp,"----------------------------------\n"); - for (temp = start_pc; temp <= end_pc; temp += 4) - { - opcode_addr=temp; - MakeDebugOpcode(); - - output.assign( HasBreakpoint() ? "*" : "" ); - R5900::GetCurrentInstruction().disasm( output ); - - fprintf(fp, "%08X %08X: %s\n", temp, cpuRegs.code, output.c_str()); - } - - - fprintf(fp,"\n\n\n----------------------------------\n"); - fprintf(fp,"EE REGISTER DISASM TEXT DOCUMENT BY PCSX2 \n"); - fprintf(fp,"----------------------------------\n"); - EEDumpRegs(fp); - fclose(fp); - } - - - - GetDlgItemText(hDlg, IDC_DUMP_STARTIOP, start, 9); - start[8] = 0; - sscanf(start, "%x", &start_pc); - start_pc &= 0xFFFFFFFC; - - GetDlgItemText(hDlg, IDC_DUMP_ENDIOP, end, 9); - end[8] = 0; - sscanf(end, "%x", &end_pc); - end_pc &= 0xFFFFFFFC; - - GetDlgItemText(hDlg, IDC_DUMP_FNAMEIOP, fname, 128); - fp = fopen(fname, "wt"); - if (fp == NULL) - { - //MessageBox(MainhWnd, "Can't open file for writing!", NULL, MB_OK); - } - else - { - fprintf(fp,"----------------------------------\n"); - fprintf(fp,"IOP DISASM TEXT DOCUMENT BY PCSX2 \n"); - fprintf(fp,"----------------------------------\n"); - for (temp = start_pc; temp <= end_pc; temp += 4) - { - opcode_addr=temp; - MakeIOPDebugOpcode(); - R3000A::IOP_DEBUG_BSC[(psxRegs.code) >> 26](tmp); - fprintf(fp, "%08X %08X: %s\n", temp, psxRegs.code, tmp); - } - - fprintf(fp,"\n\n\n----------------------------------\n"); - fprintf(fp,"IOP REGISTER DISASM TEXT DOCUMENT BY PCSX2 \n"); - fprintf(fp,"----------------------------------\n"); - IOPDumpRegs(fp); - fclose(fp); - } - EndDialog(hDlg, TRUE); - } else if (LOWORD(wParam) == IDCANCEL) { - EndDialog(hDlg, TRUE); - } - return TRUE; - } - - return FALSE; -} - -BOOL APIENTRY BpexecProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - char buf[16]; - - switch (message) - { - case WM_INITDIALOG: - sprintf(buf, "%08X", bkpt_regv[0].value); - SetDlgItemText(hDlg, IDC_EXECBP, buf); - return TRUE; - - case WM_COMMAND: - if (LOWORD(wParam) == IDOK) - { - GetDlgItemText(hDlg, IDC_EXECBP, buf, 9); - - buf[8] = 0; - sscanf(buf, "%x", &bkpt_regv[0].value); - bkpt_regv[0].type = 1; - - EndDialog(hDlg, TRUE); - } else if (LOWORD(wParam) == IDCANCEL) { - EndDialog(hDlg, TRUE); - } - return TRUE; - } - - return FALSE; -} - -BOOL APIENTRY BpcntProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - char buf[16]; - - switch (message) - { - case WM_INITDIALOG: - sprintf(buf, "%08X", bkpt_regv[1].value); - SetDlgItemText(hDlg, IDC_CNTBP, buf); - return TRUE; - - case WM_COMMAND: - if (LOWORD(wParam) == IDOK) - { - GetDlgItemText(hDlg, IDC_CNTBP, buf, 9); - - buf[8] = 0; - sscanf(buf, "%x", &bkpt_regv[1].value); - bkpt_regv[1].type = 2; - - EndDialog(hDlg, TRUE); - } else if (LOWORD(wParam) == IDCANCEL) { - EndDialog(hDlg, TRUE); - } - return TRUE; - } - - return FALSE; -} -HINSTANCE m2_hInst; -HWND m2_hWnd; -HWND hIopDlg; - -LRESULT CALLBACK IOP_DISASM(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch(message) - { - case WM_INITDIALOG: - hWnd_IOP_debugdisasm = GetDlgItem(hDlg, IDC_DEBUG_DISASM_IOP); - hWnd_IOP_debugscroll = GetDlgItem(hDlg, IDC_DEBUG_SCROLL_IOP); - - SendMessage(hWnd_IOP_debugdisasm, LB_INITSTORAGE, 29, 1131); - SendMessage(hWnd_IOP_debugscroll, SBM_SETRANGE, 0, MAXLONG); - SendMessage(hWnd_IOP_debugscroll, SBM_SETPOS, MAXLONG / 2, TRUE); - RefreshIOPDebugger(); - return (TRUE); - case WM_VSCROLL: - switch ((int) LOWORD(wParam)) - { - case SB_LINEDOWN: DebuggerIOPPC += 0x00000004; RefreshIOPDebugger(); break; - case SB_LINEUP: DebuggerIOPPC -= 0x00000004; RefreshIOPDebugger(); break; - case SB_PAGEDOWN: DebuggerIOPPC += 0x00000029; RefreshIOPDebugger(); break; - case SB_PAGEUP: DebuggerIOPPC -= 0x00000029; RefreshIOPDebugger(); break; - } - return TRUE; - break; - case WM_COMMAND: - - switch(LOWORD(wParam)) - { - case (IDOK || IDCANCEL): - EndDialog(hDlg,TRUE); - return(TRUE); - break; - } - break; - } - - return(FALSE); -} -int CreatePropertySheet2(HWND hwndOwner) -{ - PROPSHEETPAGE psp[1]; - PROPSHEETHEADER psh; - - psp[0].dwSize = sizeof(PROPSHEETPAGE); - psp[0].dwFlags = PSP_USETITLE; - psp[0].hInstance = m2_hInst; - psp[0].pszTemplate = MAKEINTRESOURCE( IDD_IOP_DEBUG); - psp[0].pszIcon = NULL; - psp[0].pfnDlgProc =(DLGPROC)IOP_DISASM; - psp[0].pszTitle = "Iop Disasm"; - psp[0].lParam = 0; - - psh.dwSize = sizeof(PROPSHEETHEADER); - psh.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS; - psh.hwndParent =hwndOwner; - psh.hInstance = m2_hInst; - psh.pszIcon = NULL; - psh.pszCaption = (LPSTR) "IOP Debugger"; - psh.nStartPage = 0; - psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE); - psh.ppsp = (LPCPROPSHEETPAGE) &psp; - - return (PropertySheet(&psh)); -} - -/** non-zero if the dialog is currently executing instructions. */ -static int isRunning = 0; - -/** non-zero if the user has requested a break in the execution of instructions. */ -static int breakRequested = 0; - -static -void EnterRunningState(HWND hDlg) -{ - isRunning = 1; - breakRequested = 0; - EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_STEP_OVER), FALSE); - EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_STEP_EE), FALSE); - EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_STEP), FALSE); - EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_SKIP), FALSE); - OpenPlugins(NULL); -} - -static -void EnterHaltedState(HWND hDlg) -{ - isRunning = 0; - breakRequested = 0; - EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_STEP_OVER), TRUE); - EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_STEP_EE), TRUE); - EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_STEP), TRUE); - EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_SKIP), TRUE); -} - -BOOL APIENTRY DebuggerProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - FARPROC jmpproc, dumpproc; - FARPROC bpexecproc, bpcntproc; - u32 oldpc = 0; - - switch (message) - { - case WM_INITDIALOG: - ShowCursor(TRUE); - isRunning = 0; - breakRequested = 0; - - SetWindowText(hDlg, "R5900 Debugger"); - debughWnd=hDlg; - DebuggerPC = 0; - // Clear all breakpoints. - memzero_obj(bkpt_regv); - - hWnd_debugdisasm = GetDlgItem(hDlg, IDC_DEBUG_DISASM); - hWnd_debugscroll = GetDlgItem(hDlg, IDC_DEBUG_SCROLL); - - SendMessage(hWnd_debugdisasm, LB_INITSTORAGE, 29, 1131); - SendMessage(hWnd_debugscroll, SBM_SETRANGE, 0, MAXLONG); - SendMessage(hWnd_debugscroll, SBM_SETPOS, MAXLONG / 2, TRUE); - - hRegDlg = (HWND)CreatePropertySheet(hDlg); - hIopDlg = (HWND)CreatePropertySheet2(hDlg); - UpdateRegs(); - SetWindowPos(hRegDlg, NULL, 525, 0, 600, 515,0 ); - SetWindowPos(hIopDlg, NULL, 0 ,515,600,230,0); - RefreshDebugger(); - RefreshIOPDebugger(); - return TRUE; - - case WM_VSCROLL: - - switch ((int) LOWORD(wParam)) - { - case SB_LINEDOWN: DebuggerPC += 0x00000004; RefreshDebugAll(); break; - case SB_LINEUP: DebuggerPC -= 0x00000004; RefreshDebugAll(); break; - case SB_PAGEDOWN: DebuggerPC += 0x00000074; RefreshDebugAll(); break; - case SB_PAGEUP: DebuggerPC -= 0x00000074; RefreshDebugAll(); break; - } - return TRUE; - - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDC_DEBUG_STEP: - oldpc = psxRegs.pc; - EnterRunningState(hDlg); - Cpu->Step(); - while(oldpc == psxRegs.pc) Cpu->Step(); - DebuggerPC = 0; - DebuggerIOPPC=0; - EnterHaltedState(hDlg); - RefreshDebugAll(); - return TRUE; - - case IDC_DEBUG_STEP_EE: - EnterRunningState(hDlg); - Cpu->Step(); - EnterHaltedState(hDlg); - DebuggerPC = 0; - DebuggerIOPPC=0; - RefreshDebugAll(); - return TRUE; - - case IDC_DEBUG_STEP_OVER: - /* Step over a subroutine call. */ - /* Note that this may take some time to execute and - * because Cpu->Step() pumps the message loop, we need - * to guard against re-entry. We do that by disabling the step buttons. - */ - EnterRunningState(hDlg); - - memRead32(cpuRegs.pc, &cpuRegs.code); - - { - u32 target_pc = 0; - if (3 == (cpuRegs.code >> 26)){ - /* it's a JAL instruction. */ - target_pc = cpuRegs.pc + 8; - } else if (0x0c == (cpuRegs.code & 0xFF)){ - /* it's a syscall. */ - target_pc = cpuRegs.pc + 4; - } - if (0 != target_pc){ - while(target_pc != cpuRegs.pc && !breakRequested) { - Cpu->Step(); - } - } else { - Cpu->Step(); - } - } - - DebuggerPC = 0; - DebuggerIOPPC=0; - EnterHaltedState(hDlg); - RefreshDebugAll(); - - return TRUE; - - case IDC_DEBUG_SKIP: - cpuRegs.pc+= 4; - DebuggerPC = 0; - RefreshDebugAll(); - return TRUE; - - case IDC_DEBUG_BREAK: - breakRequested = 1; - return TRUE; - - case IDC_DEBUG_GO: - EnterRunningState(hDlg); - for (;;) { - if (breakRequested || HasBreakpoint()) { - Cpu->Step(); - break; - } - Cpu->Step(); - } - DebuggerPC = 0; - DebuggerIOPPC=0; - EnterHaltedState(hDlg); - RefreshDebugAll(); - return TRUE; - - case IDC_DEBUG_RUN_TO_CURSOR: - { - /* Run to the cursor without checking for breakpoints. */ - int sel = SendMessage(hWnd_debugdisasm, LB_GETCURSEL,0,0); - if (sel != LB_ERR){ - const u32 target_pc = DebuggerPC + sel*4; - EnterRunningState(hDlg); - while(target_pc != cpuRegs.pc && !breakRequested) { - Cpu->Step(); - } - DebuggerPC = 0; - DebuggerIOPPC=0; - EnterHaltedState(hDlg); - RefreshDebugAll(); - } - return TRUE; - } - - case IDC_DEBUG_STEP_TO_CURSOR: - { - int sel = SendMessage(hWnd_debugdisasm, LB_GETCURSEL,0,0); - if (sel != LB_ERR){ - const u32 target_pc = DebuggerPC + sel*4; - EnterRunningState(hDlg); - while(target_pc != cpuRegs.pc && !breakRequested) { - if (HasBreakpoint()) { - Cpu->Step(); - break; - } - Cpu->Step(); - } - DebuggerPC = 0; - DebuggerIOPPC=0; - EnterHaltedState(hDlg); - RefreshDebugAll(); - } - return TRUE; - } - - #ifdef PCSX2_DEVBUILD - case IDC_DEBUG_LOG: - if( varLog ) - varLog &= ~0x80000000; - else - varLog |= 0x80000000; - return TRUE; - #endif - - case IDC_DEBUG_RESETTOPC: - DebuggerPC = 0; - DebuggerIOPPC=0; - RefreshDebugAll(); - return TRUE; - - case IDC_DEBUG_JUMP: - jmpproc = MakeProcInstance((FARPROC)JumpProc, MainhInst); - DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_JUMP), debughWnd, (DLGPROC)jmpproc); - FreeProcInstance(jmpproc); - - RefreshDebugAll(); - return TRUE; - - case IDC_CPUOP: - // This updated a global opcode counter. - //UpdateR5900op(); - return TRUE; - - case IDC_DEBUG_BP_EXEC: - bpexecproc = MakeProcInstance((FARPROC)BpexecProc, MainhInst); - DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_BPEXEC), debughWnd, (DLGPROC)bpexecproc); - FreeProcInstance(bpexecproc); - return TRUE; - - case IDC_DEBUG_BP_COUNT: - bpcntproc = MakeProcInstance((FARPROC)BpcntProc, MainhInst); - DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_BPCNT), debughWnd, (DLGPROC)bpcntproc); - FreeProcInstance(bpcntproc); - return TRUE; - - case IDC_DEBUG_BP_CLEAR: - memzero_obj(bkpt_regv); - return TRUE; - - case IDC_DEBUG_DUMP: - dumpproc = MakeProcInstance((FARPROC)DumpProc, MainhInst); - DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_DUMP), debughWnd, (DLGPROC)dumpproc); - FreeProcInstance(dumpproc); - return TRUE; - - case IDC_DEBUG_MEMORY: - DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_MEMORY), debughWnd, (DLGPROC)MemoryProc); - return TRUE; - - case IDC_DEBUG_CLOSE: - - EndDialog(hRegDlg ,TRUE); - EndDialog(hDlg,TRUE); - EndDialog(hIopDlg,TRUE); - - ClosePlugins(); - isRunning = 0; - return TRUE; - - } - break; - } - - return FALSE; -} - -void RefreshDebugger(void) -{ - unsigned long t; - int cnt; - - if (DebuggerPC == 0) - DebuggerPC = cpuRegs.pc; //- 0x00000038; - - SendMessage(hWnd_debugdisasm, LB_RESETCONTENT, 0, 0); - - for (t = DebuggerPC, cnt = 0; t < (DebuggerPC + 0x00000074); t += 0x00000004, cnt++) - { - char syscall_str[256]; - // Make the opcode. - u32 *mem = (u32*)PSM(t); - if (mem == NULL) { - sprintf(syscall_str, "%8.8lx 00000000: NULL MEMORY", t); - } else { - /* special procesing for syscall. This should probably be moved into the disR5900Fasm() call in the future. */ - if (0x0c == *mem && 0x24030000 == (*(mem-1) & 0xFFFFFF00)){ - /* it's a syscall preceeded by a li v1,$data instruction. */ - u8 bios_call = *(mem-1) & 0xFF; - sprintf(syscall_str, "%08X:\tsyscall\t%s", t, R5900::bios[bios_call]); - } else { - std::string str; - R5900::disR5900Fasm(str, *mem, t); - str.copy( syscall_str, 256 ); - syscall_str[str.length()] = 0; - } - } - SendMessage(hWnd_debugdisasm, LB_ADDSTRING, 0, (LPARAM)syscall_str ); - } -} - -void RefreshIOPDebugger(void) -{ - unsigned long t; - int cnt; - - if (DebuggerIOPPC == 0){ - DebuggerIOPPC = psxRegs.pc; //- 0x00000038; - } - SendMessage(hWnd_IOP_debugdisasm, LB_RESETCONTENT, 0, 0); - - for (t = DebuggerIOPPC, cnt = 0; t < (DebuggerIOPPC + 0x00000029); t += 0x00000004, cnt++) - { - // Make the opcode. - u32 mem = PSXMu32(t); - char *str = R3000A::disR3000Fasm(mem, t); - SendMessage(hWnd_IOP_debugdisasm, LB_ADDSTRING, 0, (LPARAM)str); - } - -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "win32.h" + +#include "resource.h" +#include "R5900OpcodeTables.h" +#include "Debugger.h" +#include "Common.h" +#include "IopMem.h" +#include "R3000A.h" + +#ifdef _MSC_VER +#pragma warning(disable:4996) //ignore the stricmp deprecated warning +#endif + +void RefreshIOPDebugger(void); +extern int ISR3000A;//for disasm +HWND hWnd_debugdisasm, hWnd_debugscroll,hWnd_IOP_debugdisasm, hWnd_IOP_debugscroll; +unsigned long DebuggerPC = 0; +HWND hRegDlg;//for debug registers.. +HWND debughWnd; +unsigned long DebuggerIOPPC=0; +HWND hIOPDlg;//IOP debugger + +breakpoints bkpt_regv[NUM_BREAKPOINTS]; + + +void RefreshDebugAll()//refresh disasm and register window +{ + RefreshDebugger(); + RefreshIOPDebugger(); + UpdateRegs(); +} + +void MakeDebugOpcode(void) +{ + memRead32( opcode_addr, &cpuRegs.code ); +} + +void MakeIOPDebugOpcode(void) +{ + psxRegs.code = PSXMu32( opcode_addr); +} + +BOOL HasBreakpoint() +{ + int t; + + for (t = 0; t < NUM_BREAKPOINTS; t++) + { + switch (bkpt_regv[t].type) { + case 1: // exec + if (cpuRegs.pc == bkpt_regv[t].value) return TRUE; + break; + + case 2: // count + if ((cpuRegs.cycle - 10) <= bkpt_regv[t].value && + (cpuRegs.cycle + 10) >= bkpt_regv[t].value) return TRUE; + break; + } + } + return FALSE; + +} +BOOL APIENTRY JumpProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char buf[16]; + unsigned long temp; + + switch (message) + { + case WM_INITDIALOG: + sprintf(buf, "%08X", cpuRegs.pc); + SetDlgItemText(hDlg, IDC_JUMP_PC, buf); + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) + { + GetDlgItemText(hDlg, IDC_JUMP_PC, buf, 9); + + buf[8] = 0; + sscanf(buf, "%x", &temp); + + temp &= 0xFFFFFFFC; + DebuggerPC = temp - 0x00000038; + + EndDialog(hDlg, TRUE); + } else if (LOWORD(wParam) == IDCANCEL) { + EndDialog(hDlg, TRUE); + } + return TRUE; + } + + return FALSE; +} + +extern void EEDumpRegs(FILE * fp); +extern void IOPDumpRegs(FILE * fp); +BOOL APIENTRY DumpProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char start[16], end[16], fname[128], tmp[128]; + unsigned long start_pc, end_pc, temp; + + FILE *fp; + + switch (message) + { + case WM_INITDIALOG: + sprintf(tmp, "%08X", cpuRegs.pc); + SetDlgItemText(hDlg, IDC_DUMP_START, tmp); + SetDlgItemText(hDlg, IDC_DUMP_END, tmp); + SetDlgItemText(hDlg, IDC_DUMP_FNAME, "EEdisasm.txt"); + + sprintf(tmp, "%08X", psxRegs.pc); + SetDlgItemText(hDlg, IDC_DUMP_STARTIOP, tmp); + SetDlgItemText(hDlg, IDC_DUMP_ENDIOP, tmp); + SetDlgItemText(hDlg, IDC_DUMP_FNAMEIOP, "IOPdisasm.txt"); + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) + { + GetDlgItemText(hDlg, IDC_DUMP_START, start, 9); + start[8] = 0; + sscanf(start, "%x", &start_pc); + start_pc &= 0xFFFFFFFC; + + GetDlgItemText(hDlg, IDC_DUMP_END, end, 9); + end[8] = 0; + sscanf(end, "%x", &end_pc); + end_pc &= 0xFFFFFFFC; + + GetDlgItemText(hDlg, IDC_DUMP_FNAME, fname, 128); + fp = fopen(fname, "wt"); + if (fp == NULL) + { + //MessageBox(MainhWnd, "Can't open file for writing!", NULL, MB_OK); + } + else + { + std::string output; + + fprintf(fp,"----------------------------------\n"); + fprintf(fp,"EE DISASM TEXT DOCUMENT BY PCSX2 \n"); + fprintf(fp,"----------------------------------\n"); + for (temp = start_pc; temp <= end_pc; temp += 4) + { + opcode_addr=temp; + MakeDebugOpcode(); + + output.assign( HasBreakpoint() ? "*" : "" ); + R5900::GetCurrentInstruction().disasm( output ); + + fprintf(fp, "%08X %08X: %s\n", temp, cpuRegs.code, output.c_str()); + } + + + fprintf(fp,"\n\n\n----------------------------------\n"); + fprintf(fp,"EE REGISTER DISASM TEXT DOCUMENT BY PCSX2 \n"); + fprintf(fp,"----------------------------------\n"); + EEDumpRegs(fp); + fclose(fp); + } + + + + GetDlgItemText(hDlg, IDC_DUMP_STARTIOP, start, 9); + start[8] = 0; + sscanf(start, "%x", &start_pc); + start_pc &= 0xFFFFFFFC; + + GetDlgItemText(hDlg, IDC_DUMP_ENDIOP, end, 9); + end[8] = 0; + sscanf(end, "%x", &end_pc); + end_pc &= 0xFFFFFFFC; + + GetDlgItemText(hDlg, IDC_DUMP_FNAMEIOP, fname, 128); + fp = fopen(fname, "wt"); + if (fp == NULL) + { + //MessageBox(MainhWnd, "Can't open file for writing!", NULL, MB_OK); + } + else + { + fprintf(fp,"----------------------------------\n"); + fprintf(fp,"IOP DISASM TEXT DOCUMENT BY PCSX2 \n"); + fprintf(fp,"----------------------------------\n"); + for (temp = start_pc; temp <= end_pc; temp += 4) + { + opcode_addr=temp; + MakeIOPDebugOpcode(); + R3000A::IOP_DEBUG_BSC[(psxRegs.code) >> 26](tmp); + fprintf(fp, "%08X %08X: %s\n", temp, psxRegs.code, tmp); + } + + fprintf(fp,"\n\n\n----------------------------------\n"); + fprintf(fp,"IOP REGISTER DISASM TEXT DOCUMENT BY PCSX2 \n"); + fprintf(fp,"----------------------------------\n"); + IOPDumpRegs(fp); + fclose(fp); + } + EndDialog(hDlg, TRUE); + } else if (LOWORD(wParam) == IDCANCEL) { + EndDialog(hDlg, TRUE); + } + return TRUE; + } + + return FALSE; +} + +BOOL APIENTRY BpexecProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char buf[16]; + + switch (message) + { + case WM_INITDIALOG: + sprintf(buf, "%08X", bkpt_regv[0].value); + SetDlgItemText(hDlg, IDC_EXECBP, buf); + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) + { + GetDlgItemText(hDlg, IDC_EXECBP, buf, 9); + + buf[8] = 0; + sscanf(buf, "%x", &bkpt_regv[0].value); + bkpt_regv[0].type = 1; + + EndDialog(hDlg, TRUE); + } else if (LOWORD(wParam) == IDCANCEL) { + EndDialog(hDlg, TRUE); + } + return TRUE; + } + + return FALSE; +} + +BOOL APIENTRY BpcntProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char buf[16]; + + switch (message) + { + case WM_INITDIALOG: + sprintf(buf, "%08X", bkpt_regv[1].value); + SetDlgItemText(hDlg, IDC_CNTBP, buf); + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) + { + GetDlgItemText(hDlg, IDC_CNTBP, buf, 9); + + buf[8] = 0; + sscanf(buf, "%x", &bkpt_regv[1].value); + bkpt_regv[1].type = 2; + + EndDialog(hDlg, TRUE); + } else if (LOWORD(wParam) == IDCANCEL) { + EndDialog(hDlg, TRUE); + } + return TRUE; + } + + return FALSE; +} +HINSTANCE m2_hInst; +HWND m2_hWnd; +HWND hIopDlg; + +LRESULT CALLBACK IOP_DISASM(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_INITDIALOG: + hWnd_IOP_debugdisasm = GetDlgItem(hDlg, IDC_DEBUG_DISASM_IOP); + hWnd_IOP_debugscroll = GetDlgItem(hDlg, IDC_DEBUG_SCROLL_IOP); + + SendMessage(hWnd_IOP_debugdisasm, LB_INITSTORAGE, 29, 1131); + SendMessage(hWnd_IOP_debugscroll, SBM_SETRANGE, 0, MAXLONG); + SendMessage(hWnd_IOP_debugscroll, SBM_SETPOS, MAXLONG / 2, TRUE); + RefreshIOPDebugger(); + return (TRUE); + case WM_VSCROLL: + switch ((int) LOWORD(wParam)) + { + case SB_LINEDOWN: DebuggerIOPPC += 0x00000004; RefreshIOPDebugger(); break; + case SB_LINEUP: DebuggerIOPPC -= 0x00000004; RefreshIOPDebugger(); break; + case SB_PAGEDOWN: DebuggerIOPPC += 0x00000029; RefreshIOPDebugger(); break; + case SB_PAGEUP: DebuggerIOPPC -= 0x00000029; RefreshIOPDebugger(); break; + } + return TRUE; + break; + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case (IDOK || IDCANCEL): + EndDialog(hDlg,TRUE); + return(TRUE); + break; + } + break; + } + + return(FALSE); +} +int CreatePropertySheet2(HWND hwndOwner) +{ + PROPSHEETPAGE psp[1]; + PROPSHEETHEADER psh; + + psp[0].dwSize = sizeof(PROPSHEETPAGE); + psp[0].dwFlags = PSP_USETITLE; + psp[0].hInstance = m2_hInst; + psp[0].pszTemplate = MAKEINTRESOURCE( IDD_IOP_DEBUG); + psp[0].pszIcon = NULL; + psp[0].pfnDlgProc =(DLGPROC)IOP_DISASM; + psp[0].pszTitle = "Iop Disasm"; + psp[0].lParam = 0; + + psh.dwSize = sizeof(PROPSHEETHEADER); + psh.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS; + psh.hwndParent =hwndOwner; + psh.hInstance = m2_hInst; + psh.pszIcon = NULL; + psh.pszCaption = (LPSTR) "IOP Debugger"; + psh.nStartPage = 0; + psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE); + psh.ppsp = (LPCPROPSHEETPAGE) &psp; + + return (PropertySheet(&psh)); +} + +/** non-zero if the dialog is currently executing instructions. */ +static int isRunning = 0; + +/** non-zero if the user has requested a break in the execution of instructions. */ +static int breakRequested = 0; + +static +void EnterRunningState(HWND hDlg) +{ + isRunning = 1; + breakRequested = 0; + EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_STEP_OVER), FALSE); + EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_STEP_EE), FALSE); + EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_STEP), FALSE); + EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_SKIP), FALSE); + OpenPlugins(NULL); +} + +static +void EnterHaltedState(HWND hDlg) +{ + isRunning = 0; + breakRequested = 0; + EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_STEP_OVER), TRUE); + EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_STEP_EE), TRUE); + EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_STEP), TRUE); + EnableWindow(GetDlgItem(hDlg, IDC_DEBUG_SKIP), TRUE); +} + +BOOL APIENTRY DebuggerProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + FARPROC jmpproc, dumpproc; + FARPROC bpexecproc, bpcntproc; + u32 oldpc = 0; + + switch (message) + { + case WM_INITDIALOG: + ShowCursor(TRUE); + isRunning = 0; + breakRequested = 0; + + SetWindowText(hDlg, "R5900 Debugger"); + debughWnd=hDlg; + DebuggerPC = 0; + // Clear all breakpoints. + memzero_obj(bkpt_regv); + + hWnd_debugdisasm = GetDlgItem(hDlg, IDC_DEBUG_DISASM); + hWnd_debugscroll = GetDlgItem(hDlg, IDC_DEBUG_SCROLL); + + SendMessage(hWnd_debugdisasm, LB_INITSTORAGE, 29, 1131); + SendMessage(hWnd_debugscroll, SBM_SETRANGE, 0, MAXLONG); + SendMessage(hWnd_debugscroll, SBM_SETPOS, MAXLONG / 2, TRUE); + + hRegDlg = (HWND)CreatePropertySheet(hDlg); + hIopDlg = (HWND)CreatePropertySheet2(hDlg); + UpdateRegs(); + SetWindowPos(hRegDlg, NULL, 525, 0, 600, 515,0 ); + SetWindowPos(hIopDlg, NULL, 0 ,515,600,230,0); + RefreshDebugger(); + RefreshIOPDebugger(); + return TRUE; + + case WM_VSCROLL: + + switch ((int) LOWORD(wParam)) + { + case SB_LINEDOWN: DebuggerPC += 0x00000004; RefreshDebugAll(); break; + case SB_LINEUP: DebuggerPC -= 0x00000004; RefreshDebugAll(); break; + case SB_PAGEDOWN: DebuggerPC += 0x00000074; RefreshDebugAll(); break; + case SB_PAGEUP: DebuggerPC -= 0x00000074; RefreshDebugAll(); break; + } + return TRUE; + + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_DEBUG_STEP: + oldpc = psxRegs.pc; + EnterRunningState(hDlg); + Cpu->Step(); + while(oldpc == psxRegs.pc) Cpu->Step(); + DebuggerPC = 0; + DebuggerIOPPC=0; + EnterHaltedState(hDlg); + RefreshDebugAll(); + return TRUE; + + case IDC_DEBUG_STEP_EE: + EnterRunningState(hDlg); + Cpu->Step(); + EnterHaltedState(hDlg); + DebuggerPC = 0; + DebuggerIOPPC=0; + RefreshDebugAll(); + return TRUE; + + case IDC_DEBUG_STEP_OVER: + /* Step over a subroutine call. */ + /* Note that this may take some time to execute and + * because Cpu->Step() pumps the message loop, we need + * to guard against re-entry. We do that by disabling the step buttons. + */ + EnterRunningState(hDlg); + + memRead32(cpuRegs.pc, &cpuRegs.code); + + { + u32 target_pc = 0; + if (3 == (cpuRegs.code >> 26)){ + /* it's a JAL instruction. */ + target_pc = cpuRegs.pc + 8; + } else if (0x0c == (cpuRegs.code & 0xFF)){ + /* it's a syscall. */ + target_pc = cpuRegs.pc + 4; + } + if (0 != target_pc){ + while(target_pc != cpuRegs.pc && !breakRequested) { + Cpu->Step(); + } + } else { + Cpu->Step(); + } + } + + DebuggerPC = 0; + DebuggerIOPPC=0; + EnterHaltedState(hDlg); + RefreshDebugAll(); + + return TRUE; + + case IDC_DEBUG_SKIP: + cpuRegs.pc+= 4; + DebuggerPC = 0; + RefreshDebugAll(); + return TRUE; + + case IDC_DEBUG_BREAK: + breakRequested = 1; + return TRUE; + + case IDC_DEBUG_GO: + EnterRunningState(hDlg); + for (;;) { + if (breakRequested || HasBreakpoint()) { + Cpu->Step(); + break; + } + Cpu->Step(); + } + DebuggerPC = 0; + DebuggerIOPPC=0; + EnterHaltedState(hDlg); + RefreshDebugAll(); + return TRUE; + + case IDC_DEBUG_RUN_TO_CURSOR: + { + /* Run to the cursor without checking for breakpoints. */ + int sel = SendMessage(hWnd_debugdisasm, LB_GETCURSEL,0,0); + if (sel != LB_ERR){ + const u32 target_pc = DebuggerPC + sel*4; + EnterRunningState(hDlg); + while(target_pc != cpuRegs.pc && !breakRequested) { + Cpu->Step(); + } + DebuggerPC = 0; + DebuggerIOPPC=0; + EnterHaltedState(hDlg); + RefreshDebugAll(); + } + return TRUE; + } + + case IDC_DEBUG_STEP_TO_CURSOR: + { + int sel = SendMessage(hWnd_debugdisasm, LB_GETCURSEL,0,0); + if (sel != LB_ERR){ + const u32 target_pc = DebuggerPC + sel*4; + EnterRunningState(hDlg); + while(target_pc != cpuRegs.pc && !breakRequested) { + if (HasBreakpoint()) { + Cpu->Step(); + break; + } + Cpu->Step(); + } + DebuggerPC = 0; + DebuggerIOPPC=0; + EnterHaltedState(hDlg); + RefreshDebugAll(); + } + return TRUE; + } + + #ifdef PCSX2_DEVBUILD + case IDC_DEBUG_LOG: + if( varLog ) + varLog &= ~0x80000000; + else + varLog |= 0x80000000; + return TRUE; + #endif + + case IDC_DEBUG_RESETTOPC: + DebuggerPC = 0; + DebuggerIOPPC=0; + RefreshDebugAll(); + return TRUE; + + case IDC_DEBUG_JUMP: + jmpproc = MakeProcInstance((FARPROC)JumpProc, MainhInst); + DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_JUMP), debughWnd, (DLGPROC)jmpproc); + FreeProcInstance(jmpproc); + + RefreshDebugAll(); + return TRUE; + + case IDC_CPUOP: + // This updated a global opcode counter. + //UpdateR5900op(); + return TRUE; + + case IDC_DEBUG_BP_EXEC: + bpexecproc = MakeProcInstance((FARPROC)BpexecProc, MainhInst); + DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_BPEXEC), debughWnd, (DLGPROC)bpexecproc); + FreeProcInstance(bpexecproc); + return TRUE; + + case IDC_DEBUG_BP_COUNT: + bpcntproc = MakeProcInstance((FARPROC)BpcntProc, MainhInst); + DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_BPCNT), debughWnd, (DLGPROC)bpcntproc); + FreeProcInstance(bpcntproc); + return TRUE; + + case IDC_DEBUG_BP_CLEAR: + memzero_obj(bkpt_regv); + return TRUE; + + case IDC_DEBUG_DUMP: + dumpproc = MakeProcInstance((FARPROC)DumpProc, MainhInst); + DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_DUMP), debughWnd, (DLGPROC)dumpproc); + FreeProcInstance(dumpproc); + return TRUE; + + case IDC_DEBUG_MEMORY: + DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_MEMORY), debughWnd, (DLGPROC)MemoryProc); + return TRUE; + + case IDC_DEBUG_CLOSE: + + EndDialog(hRegDlg ,TRUE); + EndDialog(hDlg,TRUE); + EndDialog(hIopDlg,TRUE); + + ClosePlugins(); + isRunning = 0; + return TRUE; + + } + break; + } + + return FALSE; +} + +void RefreshDebugger(void) +{ + unsigned long t; + int cnt; + + if (DebuggerPC == 0) + DebuggerPC = cpuRegs.pc; //- 0x00000038; + + SendMessage(hWnd_debugdisasm, LB_RESETCONTENT, 0, 0); + + for (t = DebuggerPC, cnt = 0; t < (DebuggerPC + 0x00000074); t += 0x00000004, cnt++) + { + char syscall_str[256]; + // Make the opcode. + u32 *mem = (u32*)PSM(t); + if (mem == NULL) { + sprintf(syscall_str, "%8.8lx 00000000: NULL MEMORY", t); + } else { + /* special procesing for syscall. This should probably be moved into the disR5900Fasm() call in the future. */ + if (0x0c == *mem && 0x24030000 == (*(mem-1) & 0xFFFFFF00)){ + /* it's a syscall preceeded by a li v1,$data instruction. */ + u8 bios_call = *(mem-1) & 0xFF; + sprintf(syscall_str, "%08X:\tsyscall\t%s", t, R5900::bios[bios_call]); + } else { + std::string str; + R5900::disR5900Fasm(str, *mem, t); + str.copy( syscall_str, 256 ); + syscall_str[str.length()] = 0; + } + } + SendMessage(hWnd_debugdisasm, LB_ADDSTRING, 0, (LPARAM)syscall_str ); + } +} + +void RefreshIOPDebugger(void) +{ + unsigned long t; + int cnt; + + if (DebuggerIOPPC == 0){ + DebuggerIOPPC = psxRegs.pc; //- 0x00000038; + } + SendMessage(hWnd_IOP_debugdisasm, LB_RESETCONTENT, 0, 0); + + for (t = DebuggerIOPPC, cnt = 0; t < (DebuggerIOPPC + 0x00000029); t += 0x00000004, cnt++) + { + // Make the opcode. + u32 mem = PSXMu32(t); + char *str = R3000A::disR3000Fasm(mem, t); + SendMessage(hWnd_IOP_debugdisasm, LB_ADDSTRING, 0, (LPARAM)str); + } + +} diff --git a/pcsx2/windows/Debugger.h b/pcsx2/windows/Debugger.h index 0035ea942e..63df6f4c5d 100644 --- a/pcsx2/windows/Debugger.h +++ b/pcsx2/windows/Debugger.h @@ -1,47 +1,47 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 -#include -#include - -#define NUM_BREAKPOINTS 8 - -extern BOOL APIENTRY DebuggerProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); -extern BOOL APIENTRY MemoryProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); -extern void RefreshDebugger(void); - -extern unsigned long opcode_addr; - -struct breakpoints -{ - int type; - unsigned long value; -}; - - -LRESULT CALLBACK R5900reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); -LRESULT CALLBACK COP0reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); -LRESULT CALLBACK COP1reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); -LRESULT CALLBACK COP2Freg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); -LRESULT CALLBACK COP2Creg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); -LRESULT CALLBACK VU1Freg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); -LRESULT CALLBACK VU1Creg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); - -void UpdateRegs(void); -int CreatePropertySheet(HWND hwndOwner); +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 +#include +#include + +#define NUM_BREAKPOINTS 8 + +extern BOOL APIENTRY DebuggerProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +extern BOOL APIENTRY MemoryProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +extern void RefreshDebugger(void); + +extern unsigned long opcode_addr; + +struct breakpoints +{ + int type; + unsigned long value; +}; + + +LRESULT CALLBACK R5900reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK COP0reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK COP1reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK COP2Freg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK COP2Creg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK VU1Freg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK VU1Creg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); + +void UpdateRegs(void); +int CreatePropertySheet(HWND hwndOwner); diff --git a/pcsx2/windows/Debugreg.cpp b/pcsx2/windows/Debugreg.cpp index bf12ffa979..69c8f0b820 100644 --- a/pcsx2/windows/Debugreg.cpp +++ b/pcsx2/windows/Debugreg.cpp @@ -1,1486 +1,1486 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" -#include "Win32.h" - -#include - -#include "resource.h" -#include "Debugger.h" -#include "Debug.h" -#include "R5900.h" -#include "R3000a.h" -#include "VUmicro.h" - -HINSTANCE m_hInst; -HWND m_hWnd; -char text1[256]; - -// Wow! This module is a lot of copy-paste! -// Between this and DisAsm modules, *someone* needs a new Ctrl-V combo on their keyboard. (air) - -/*R3000a registers handle */ -static HWND IOPGPR0Handle=NULL; -static HWND IOPGPR1Handle=NULL; -static HWND IOPGPR2Handle=NULL; -static HWND IOPGPR3Handle=NULL; -static HWND IOPGPR4Handle=NULL; -static HWND IOPGPR5Handle=NULL; -static HWND IOPGPR6Handle=NULL; -static HWND IOPGPR7Handle=NULL; -static HWND IOPGPR8Handle=NULL; -static HWND IOPGPR9Handle=NULL; -static HWND IOPGPR10Handle=NULL; -static HWND IOPGPR11Handle=NULL; -static HWND IOPGPR12Handle=NULL; -static HWND IOPGPR13Handle=NULL; -static HWND IOPGPR14Handle=NULL; -static HWND IOPGPR15Handle=NULL; -static HWND IOPGPR16Handle=NULL; -static HWND IOPGPR17Handle=NULL; -static HWND IOPGPR18Handle=NULL; -static HWND IOPGPR19Handle=NULL; -static HWND IOPGPR20Handle=NULL; -static HWND IOPGPR21Handle=NULL; -static HWND IOPGPR22Handle=NULL; -static HWND IOPGPR23Handle=NULL; -static HWND IOPGPR24Handle=NULL; -static HWND IOPGPR25Handle=NULL; -static HWND IOPGPR26Handle=NULL; -static HWND IOPGPR27Handle=NULL; -static HWND IOPGPR28Handle=NULL; -static HWND IOPGPR29Handle=NULL; -static HWND IOPGPR30Handle=NULL; -static HWND IOPGPR31Handle=NULL; -static HWND IOPGPRPCHandle=NULL; -static HWND IOPGPRHIHandle=NULL; -static HWND IOPGPRLOHandle=NULL; - -/*R5900 registers handle */ -static HWND GPR0Handle=NULL; -static HWND GPR1Handle=NULL; -static HWND GPR2Handle=NULL; -static HWND GPR3Handle=NULL; -static HWND GPR4Handle=NULL; -static HWND GPR5Handle=NULL; -static HWND GPR6Handle=NULL; -static HWND GPR7Handle=NULL; -static HWND GPR8Handle=NULL; -static HWND GPR9Handle=NULL; -static HWND GPR10Handle=NULL; -static HWND GPR11Handle=NULL; -static HWND GPR12Handle=NULL; -static HWND GPR13Handle=NULL; -static HWND GPR14Handle=NULL; -static HWND GPR15Handle=NULL; -static HWND GPR16Handle=NULL; -static HWND GPR17Handle=NULL; -static HWND GPR18Handle=NULL; -static HWND GPR19Handle=NULL; -static HWND GPR20Handle=NULL; -static HWND GPR21Handle=NULL; -static HWND GPR22Handle=NULL; -static HWND GPR23Handle=NULL; -static HWND GPR24Handle=NULL; -static HWND GPR25Handle=NULL; -static HWND GPR26Handle=NULL; -static HWND GPR27Handle=NULL; -static HWND GPR28Handle=NULL; -static HWND GPR29Handle=NULL; -static HWND GPR30Handle=NULL; -static HWND GPR31Handle=NULL; -static HWND GPRPCHandle=NULL; -static HWND GPRHIHandle=NULL; -static HWND GPRLOHandle=NULL; -/*end of r3000a registers handle */ -/*cop0 registers here */ -static HWND COP00Handle=NULL; -static HWND COP01Handle=NULL; -static HWND COP02Handle=NULL; -static HWND COP03Handle=NULL; -static HWND COP04Handle=NULL; -static HWND COP05Handle=NULL; -static HWND COP06Handle=NULL; -static HWND COP07Handle=NULL; -static HWND COP08Handle=NULL; -static HWND COP09Handle=NULL; -static HWND COP010Handle=NULL; -static HWND COP011Handle=NULL; -static HWND COP012Handle=NULL; -static HWND COP013Handle=NULL; -static HWND COP014Handle=NULL; -static HWND COP015Handle=NULL; -static HWND COP016Handle=NULL; -static HWND COP017Handle=NULL; -static HWND COP018Handle=NULL; -static HWND COP019Handle=NULL; -static HWND COP020Handle=NULL; -static HWND COP021Handle=NULL; -static HWND COP022Handle=NULL; -static HWND COP023Handle=NULL; -static HWND COP024Handle=NULL; -static HWND COP025Handle=NULL; -static HWND COP026Handle=NULL; -static HWND COP027Handle=NULL; -static HWND COP028Handle=NULL; -static HWND COP029Handle=NULL; -static HWND COP030Handle=NULL; -static HWND COP031Handle=NULL; -static HWND COP0PCHandle=NULL; -static HWND COP0HIHandle=NULL; -static HWND COP0LOHandle=NULL; -/*end of cop0 registers */ -/*cop1 registers here */ -static HWND COP10Handle=NULL; -static HWND COP11Handle=NULL; -static HWND COP12Handle=NULL; -static HWND COP13Handle=NULL; -static HWND COP14Handle=NULL; -static HWND COP15Handle=NULL; -static HWND COP16Handle=NULL; -static HWND COP17Handle=NULL; -static HWND COP18Handle=NULL; -static HWND COP19Handle=NULL; -static HWND COP110Handle=NULL; -static HWND COP111Handle=NULL; -static HWND COP112Handle=NULL; -static HWND COP113Handle=NULL; -static HWND COP114Handle=NULL; -static HWND COP115Handle=NULL; -static HWND COP116Handle=NULL; -static HWND COP117Handle=NULL; -static HWND COP118Handle=NULL; -static HWND COP119Handle=NULL; -static HWND COP120Handle=NULL; -static HWND COP121Handle=NULL; -static HWND COP122Handle=NULL; -static HWND COP123Handle=NULL; -static HWND COP124Handle=NULL; -static HWND COP125Handle=NULL; -static HWND COP126Handle=NULL; -static HWND COP127Handle=NULL; -static HWND COP128Handle=NULL; -static HWND COP129Handle=NULL; -static HWND COP130Handle=NULL; -static HWND COP131Handle=NULL; -static HWND COP1C0Handle=NULL; -static HWND COP1C1Handle=NULL; -static HWND COP1ACCHandle=NULL; -/*end of cop1 registers */ -/*cop2 floating registers*/ -static HWND VU0F00Handle=NULL; -static HWND VU0F01Handle=NULL; -static HWND VU0F02Handle=NULL; -static HWND VU0F03Handle=NULL; -static HWND VU0F04Handle=NULL; -static HWND VU0F05Handle=NULL; -static HWND VU0F06Handle=NULL; -static HWND VU0F07Handle=NULL; -static HWND VU0F08Handle=NULL; -static HWND VU0F09Handle=NULL; -static HWND VU0F10Handle=NULL; -static HWND VU0F11Handle=NULL; -static HWND VU0F12Handle=NULL; -static HWND VU0F13Handle=NULL; -static HWND VU0F14Handle=NULL; -static HWND VU0F15Handle=NULL; -static HWND VU0F16Handle=NULL; -static HWND VU0F17Handle=NULL; -static HWND VU0F18Handle=NULL; -static HWND VU0F19Handle=NULL; -static HWND VU0F20Handle=NULL; -static HWND VU0F21Handle=NULL; -static HWND VU0F22Handle=NULL; -static HWND VU0F23Handle=NULL; -static HWND VU0F24Handle=NULL; -static HWND VU0F25Handle=NULL; -static HWND VU0F26Handle=NULL; -static HWND VU0F27Handle=NULL; -static HWND VU0F28Handle=NULL; -static HWND VU0F29Handle=NULL; -static HWND VU0F30Handle=NULL; -static HWND VU0F31Handle=NULL; -/*end of cop2 floating registers*/ -/*cop2 control registers */ -static HWND VU0C00Handle=NULL; -static HWND VU0C01Handle=NULL; -static HWND VU0C02Handle=NULL; -static HWND VU0C03Handle=NULL; -static HWND VU0C04Handle=NULL; -static HWND VU0C05Handle=NULL; -static HWND VU0C06Handle=NULL; -static HWND VU0C07Handle=NULL; -static HWND VU0C08Handle=NULL; -static HWND VU0C09Handle=NULL; -static HWND VU0C10Handle=NULL; -static HWND VU0C11Handle=NULL; -static HWND VU0C12Handle=NULL; -static HWND VU0C13Handle=NULL; -static HWND VU0C14Handle=NULL; -static HWND VU0C15Handle=NULL; -static HWND VU0C16Handle=NULL; -static HWND VU0C17Handle=NULL; -static HWND VU0C18Handle=NULL; -static HWND VU0C19Handle=NULL; -static HWND VU0C20Handle=NULL; -static HWND VU0C21Handle=NULL; -static HWND VU0C22Handle=NULL; -static HWND VU0C23Handle=NULL; -static HWND VU0C24Handle=NULL; -static HWND VU0C25Handle=NULL; -static HWND VU0C26Handle=NULL; -static HWND VU0C27Handle=NULL; -static HWND VU0C28Handle=NULL; -static HWND VU0C29Handle=NULL; -static HWND VU0C30Handle=NULL; -static HWND VU0C31Handle=NULL; -static HWND VU0ACCHandle=NULL; -/*end of cop2 control registers */ -/*vu1 floating registers*/ -static HWND VU1F00Handle=NULL; -static HWND VU1F01Handle=NULL; -static HWND VU1F02Handle=NULL; -static HWND VU1F03Handle=NULL; -static HWND VU1F04Handle=NULL; -static HWND VU1F05Handle=NULL; -static HWND VU1F06Handle=NULL; -static HWND VU1F07Handle=NULL; -static HWND VU1F08Handle=NULL; -static HWND VU1F09Handle=NULL; -static HWND VU1F10Handle=NULL; -static HWND VU1F11Handle=NULL; -static HWND VU1F12Handle=NULL; -static HWND VU1F13Handle=NULL; -static HWND VU1F14Handle=NULL; -static HWND VU1F15Handle=NULL; -static HWND VU1F16Handle=NULL; -static HWND VU1F17Handle=NULL; -static HWND VU1F18Handle=NULL; -static HWND VU1F19Handle=NULL; -static HWND VU1F20Handle=NULL; -static HWND VU1F21Handle=NULL; -static HWND VU1F22Handle=NULL; -static HWND VU1F23Handle=NULL; -static HWND VU1F24Handle=NULL; -static HWND VU1F25Handle=NULL; -static HWND VU1F26Handle=NULL; -static HWND VU1F27Handle=NULL; -static HWND VU1F28Handle=NULL; -static HWND VU1F29Handle=NULL; -static HWND VU1F30Handle=NULL; -static HWND VU1F31Handle=NULL; -/*end of vu1 floating registers*/ -/*vu1 control registers */ -static HWND VU1C00Handle=NULL; -static HWND VU1C01Handle=NULL; -static HWND VU1C02Handle=NULL; -static HWND VU1C03Handle=NULL; -static HWND VU1C04Handle=NULL; -static HWND VU1C05Handle=NULL; -static HWND VU1C06Handle=NULL; -static HWND VU1C07Handle=NULL; -static HWND VU1C08Handle=NULL; -static HWND VU1C09Handle=NULL; -static HWND VU1C10Handle=NULL; -static HWND VU1C11Handle=NULL; -static HWND VU1C12Handle=NULL; -static HWND VU1C13Handle=NULL; -static HWND VU1C14Handle=NULL; -static HWND VU1C15Handle=NULL; -static HWND VU1C16Handle=NULL; -static HWND VU1C17Handle=NULL; -static HWND VU1C18Handle=NULL; -static HWND VU1C19Handle=NULL; -static HWND VU1C20Handle=NULL; -static HWND VU1C21Handle=NULL; -static HWND VU1C22Handle=NULL; -static HWND VU1C23Handle=NULL; -static HWND VU1C24Handle=NULL; -static HWND VU1C25Handle=NULL; -static HWND VU1C26Handle=NULL; -static HWND VU1C27Handle=NULL; -static HWND VU1C28Handle=NULL; -static HWND VU1C29Handle=NULL; -static HWND VU1C30Handle=NULL; -static HWND VU1C31Handle=NULL; -static HWND VU1ACCHandle=NULL; -/*end of vu1 control registers */ - -LRESULT CALLBACK R3000reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); - -//comctl32 lib must add to project.. -int CreatePropertySheet(HWND hwndOwner) -{ - - PROPSHEETPAGE psp[7]; - PROPSHEETHEADER psh; - - psp[0].dwSize = sizeof(PROPSHEETPAGE); - psp[0].dwFlags = PSP_USETITLE; - psp[0].hInstance = m_hInst; - psp[0].pszTemplate = MAKEINTRESOURCE( IDD_GPREGS); - psp[0].pszIcon = NULL; - psp[0].pfnDlgProc =(DLGPROC)R5900reg; - psp[0].pszTitle = "R5900"; - psp[0].lParam = 0; - - psp[1].dwSize = sizeof(PROPSHEETPAGE); - psp[1].dwFlags = PSP_USETITLE; - psp[1].hInstance = m_hInst; - psp[1].pszTemplate = MAKEINTRESOURCE( IDD_CP0REGS ); - psp[1].pszIcon = NULL; - psp[1].pfnDlgProc =(DLGPROC)COP0reg; - psp[1].pszTitle = "COP0"; - psp[1].lParam = 0; - - psp[2].dwSize = sizeof(PROPSHEETPAGE); - psp[2].dwFlags = PSP_USETITLE; - psp[2].hInstance = m_hInst; - psp[2].pszTemplate = MAKEINTRESOURCE( IDD_CP1REGS ); - psp[2].pszIcon = NULL; - psp[2].pfnDlgProc =(DLGPROC)COP1reg; - psp[2].pszTitle = "COP1"; - psp[2].lParam = 0; - - psp[3].dwSize = sizeof(PROPSHEETPAGE); - psp[3].dwFlags = PSP_USETITLE; - psp[3].hInstance = m_hInst; - psp[3].pszTemplate = MAKEINTRESOURCE( IDD_VU0REGS ); - psp[3].pszIcon = NULL; - psp[3].pfnDlgProc =(DLGPROC)COP2Freg; - psp[3].pszTitle = "COP2F"; - psp[3].lParam = 0; - - psp[4].dwSize = sizeof(PROPSHEETPAGE); - psp[4].dwFlags = PSP_USETITLE; - psp[4].hInstance = m_hInst; - psp[4].pszTemplate = MAKEINTRESOURCE( IDD_VU0INTEGER ); - psp[4].pszIcon = NULL; - psp[4].pfnDlgProc =(DLGPROC)COP2Creg; - psp[4].pszTitle = "COP2C"; - psp[4].lParam = 0; - - psp[5].dwSize = sizeof(PROPSHEETPAGE); - psp[5].dwFlags = PSP_USETITLE; - psp[5].hInstance = m_hInst; - psp[5].pszTemplate = MAKEINTRESOURCE( IDD_VU1REGS ); - psp[5].pszIcon = NULL; - psp[5].pfnDlgProc =(DLGPROC)VU1Freg; - psp[5].pszTitle = "VU1F"; - psp[5].lParam = 0; - - psp[6].dwSize = sizeof(PROPSHEETPAGE); - psp[6].dwFlags = PSP_USETITLE; - psp[6].hInstance = m_hInst; - psp[6].pszTemplate = MAKEINTRESOURCE( IDD_VU1INTEGER ); - psp[6].pszIcon = NULL; - psp[6].pfnDlgProc =(DLGPROC)VU1Creg; - psp[6].pszTitle = "VU1C"; - psp[6].lParam = 0; - - psp[6].dwSize = sizeof(PROPSHEETPAGE); - psp[6].dwFlags = PSP_USETITLE; - psp[6].hInstance = m_hInst; - psp[6].pszTemplate = MAKEINTRESOURCE( IDD_IOPREGS ); - psp[6].pszIcon = NULL; - psp[6].pfnDlgProc =(DLGPROC)R3000reg; - psp[6].pszTitle = "R3000"; - psp[6].lParam = 0; - - psh.dwSize = sizeof(PROPSHEETHEADER); - psh.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS; - psh.hwndParent =hwndOwner; - psh.hInstance = m_hInst; - psh.pszIcon = NULL; - psh.pszCaption = (LPSTR) "Debugger"; - psh.nStartPage = 0; - psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE); - psh.ppsp = (LPCPROPSHEETPAGE) &psp; - - return (PropertySheet(&psh)); - -} -LRESULT CALLBACK R3000reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch(message) - { - case WM_INITDIALOG: - IOPGPR0Handle=GetDlgItem(hDlg,IDC_IOPGPR0); - IOPGPR1Handle=GetDlgItem(hDlg,IDC_IOPGPR1); - IOPGPR2Handle=GetDlgItem(hDlg,IDC_IOPGPR2); - IOPGPR3Handle=GetDlgItem(hDlg,IDC_IOPGPR3); - IOPGPR4Handle=GetDlgItem(hDlg,IDC_IOPGPR4); - IOPGPR5Handle=GetDlgItem(hDlg,IDC_IOPGPR5); - IOPGPR6Handle=GetDlgItem(hDlg,IDC_IOPGPR6); - IOPGPR7Handle=GetDlgItem(hDlg,IDC_IOPGPR7); - IOPGPR8Handle=GetDlgItem(hDlg,IDC_IOPGPR8); - IOPGPR9Handle=GetDlgItem(hDlg,IDC_IOPGPR9); - IOPGPR10Handle=GetDlgItem(hDlg,IDC_IOPGPR10); - IOPGPR11Handle=GetDlgItem(hDlg,IDC_IOPGPR11); - IOPGPR12Handle=GetDlgItem(hDlg,IDC_IOPGPR12); - IOPGPR13Handle=GetDlgItem(hDlg,IDC_IOPGPR13); - IOPGPR14Handle=GetDlgItem(hDlg,IDC_IOPGPR14); - IOPGPR15Handle=GetDlgItem(hDlg,IDC_IOPGPR15); - IOPGPR16Handle=GetDlgItem(hDlg,IDC_IOPGPR16); - IOPGPR17Handle=GetDlgItem(hDlg,IDC_IOPGPR17); - IOPGPR18Handle=GetDlgItem(hDlg,IDC_IOPGPR18); - IOPGPR19Handle=GetDlgItem(hDlg,IDC_IOPGPR19); - IOPGPR20Handle=GetDlgItem(hDlg,IDC_IOPGPR20); - IOPGPR21Handle=GetDlgItem(hDlg,IDC_IOPGPR21); - IOPGPR22Handle=GetDlgItem(hDlg,IDC_IOPGPR22); - IOPGPR23Handle=GetDlgItem(hDlg,IDC_IOPGPR23); - IOPGPR24Handle=GetDlgItem(hDlg,IDC_IOPGPR24); - IOPGPR25Handle=GetDlgItem(hDlg,IDC_IOPGPR25); - IOPGPR26Handle=GetDlgItem(hDlg,IDC_IOPGPR26); - IOPGPR27Handle=GetDlgItem(hDlg,IDC_IOPGPR27); - IOPGPR28Handle=GetDlgItem(hDlg,IDC_IOPGPR28); - IOPGPR29Handle=GetDlgItem(hDlg,IDC_IOPGPR29); - IOPGPR30Handle=GetDlgItem(hDlg,IDC_IOPGPR30); - IOPGPR31Handle=GetDlgItem(hDlg,IDC_IOPGPR31); - IOPGPRPCHandle=GetDlgItem(hDlg,IDC_IOPGPR_PC); - IOPGPRHIHandle=GetDlgItem(hDlg,IDC_IOPGPR_HI); - IOPGPRLOHandle=GetDlgItem(hDlg,IDC_IOPGPR_LO); - UpdateRegs(); - return (TRUE); - break; - case WM_COMMAND: - - switch(LOWORD(wParam)) - { - case (IDOK || IDCANCEL): - EndDialog(hDlg,TRUE); - return(TRUE); - break; - - } - break; - } - - return(FALSE); -} -LRESULT CALLBACK R5900reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch(message) - { - case WM_INITDIALOG: - GPR0Handle=GetDlgItem(hDlg,IDC_GPR0); - GPR1Handle=GetDlgItem(hDlg,IDC_GPR1); - GPR2Handle=GetDlgItem(hDlg,IDC_GPR2); - GPR3Handle=GetDlgItem(hDlg,IDC_GPR3); - GPR4Handle=GetDlgItem(hDlg,IDC_GPR4); - GPR5Handle=GetDlgItem(hDlg,IDC_GPR5); - GPR6Handle=GetDlgItem(hDlg,IDC_GPR6); - GPR7Handle=GetDlgItem(hDlg,IDC_GPR7); - GPR8Handle=GetDlgItem(hDlg,IDC_GPR8); - GPR9Handle=GetDlgItem(hDlg,IDC_GPR9); - GPR10Handle=GetDlgItem(hDlg,IDC_GPR10); - GPR11Handle=GetDlgItem(hDlg,IDC_GPR11); - GPR12Handle=GetDlgItem(hDlg,IDC_GPR12); - GPR13Handle=GetDlgItem(hDlg,IDC_GPR13); - GPR14Handle=GetDlgItem(hDlg,IDC_GPR14); - GPR15Handle=GetDlgItem(hDlg,IDC_GPR15); - GPR16Handle=GetDlgItem(hDlg,IDC_GPR16); - GPR17Handle=GetDlgItem(hDlg,IDC_GPR17); - GPR18Handle=GetDlgItem(hDlg,IDC_GPR18); - GPR19Handle=GetDlgItem(hDlg,IDC_GPR19); - GPR20Handle=GetDlgItem(hDlg,IDC_GPR20); - GPR21Handle=GetDlgItem(hDlg,IDC_GPR21); - GPR22Handle=GetDlgItem(hDlg,IDC_GPR22); - GPR23Handle=GetDlgItem(hDlg,IDC_GPR23); - GPR24Handle=GetDlgItem(hDlg,IDC_GPR24); - GPR25Handle=GetDlgItem(hDlg,IDC_GPR25); - GPR26Handle=GetDlgItem(hDlg,IDC_GPR26); - GPR27Handle=GetDlgItem(hDlg,IDC_GPR27); - GPR28Handle=GetDlgItem(hDlg,IDC_GPR28); - GPR29Handle=GetDlgItem(hDlg,IDC_GPR29); - GPR30Handle=GetDlgItem(hDlg,IDC_GPR30); - GPR31Handle=GetDlgItem(hDlg,IDC_GPR31); - GPRPCHandle=GetDlgItem(hDlg,IDC_GPR_PC); - GPRHIHandle=GetDlgItem(hDlg,IDC_GPR_HI); - GPRLOHandle=GetDlgItem(hDlg,IDC_GPR_LO); - UpdateRegs(); - return (TRUE); - break; - case WM_COMMAND: - - switch(LOWORD(wParam)) - { - case (IDOK || IDCANCEL): - EndDialog(hDlg,TRUE); - return(TRUE); - break; - - } - break; - } - - return(FALSE); -} -LRESULT CALLBACK COP0reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch(message) - { - case WM_INITDIALOG: - COP00Handle=GetDlgItem(hDlg,IDC_CP00); - COP01Handle=GetDlgItem(hDlg,IDC_CP01); - COP02Handle=GetDlgItem(hDlg,IDC_CP02); - COP03Handle=GetDlgItem(hDlg,IDC_CP03); - COP04Handle=GetDlgItem(hDlg,IDC_CP04); - COP05Handle=GetDlgItem(hDlg,IDC_CP05); - COP06Handle=GetDlgItem(hDlg,IDC_CP06); - COP07Handle=GetDlgItem(hDlg,IDC_CP07); - COP08Handle=GetDlgItem(hDlg,IDC_CP08); - COP09Handle=GetDlgItem(hDlg,IDC_CP09); - COP010Handle=GetDlgItem(hDlg,IDC_CP010); - COP011Handle=GetDlgItem(hDlg,IDC_CP011); - COP012Handle=GetDlgItem(hDlg,IDC_CP012); - COP013Handle=GetDlgItem(hDlg,IDC_CP013); - COP014Handle=GetDlgItem(hDlg,IDC_CP014); - COP015Handle=GetDlgItem(hDlg,IDC_CP015); - COP016Handle=GetDlgItem(hDlg,IDC_CP016); - COP017Handle=GetDlgItem(hDlg,IDC_CP017); - COP018Handle=GetDlgItem(hDlg,IDC_CP018); - COP019Handle=GetDlgItem(hDlg,IDC_CP019); - COP020Handle=GetDlgItem(hDlg,IDC_CP020); - COP021Handle=GetDlgItem(hDlg,IDC_CP021); - COP022Handle=GetDlgItem(hDlg,IDC_CP022); - COP023Handle=GetDlgItem(hDlg,IDC_CP023); - COP024Handle=GetDlgItem(hDlg,IDC_CP024); - COP025Handle=GetDlgItem(hDlg,IDC_CP025); - COP026Handle=GetDlgItem(hDlg,IDC_CP026); - COP027Handle=GetDlgItem(hDlg,IDC_CP027); - COP028Handle=GetDlgItem(hDlg,IDC_CP028); - COP029Handle=GetDlgItem(hDlg,IDC_CP029); - COP030Handle=GetDlgItem(hDlg,IDC_CP030); - COP031Handle=GetDlgItem(hDlg,IDC_CP031); - UpdateRegs(); - return (TRUE); - break; - case WM_COMMAND: - switch(LOWORD(wParam)) - { - case (IDOK || IDCANCEL): - EndDialog(hDlg,TRUE); - return(TRUE); - break; - - } - break; - } - - return(FALSE); -} -LRESULT CALLBACK COP1reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch(message) - { - case WM_INITDIALOG: - COP10Handle=GetDlgItem(hDlg,IDC_FP0); - COP11Handle=GetDlgItem(hDlg,IDC_FP1); - COP12Handle=GetDlgItem(hDlg,IDC_FP2); - COP13Handle=GetDlgItem(hDlg,IDC_FP3); - COP14Handle=GetDlgItem(hDlg,IDC_FP4); - COP15Handle=GetDlgItem(hDlg,IDC_FP5); - COP16Handle=GetDlgItem(hDlg,IDC_FP6); - COP17Handle=GetDlgItem(hDlg,IDC_FP7); - COP18Handle=GetDlgItem(hDlg,IDC_FP8); - COP19Handle=GetDlgItem(hDlg,IDC_FP9); - COP110Handle=GetDlgItem(hDlg,IDC_FP10); - COP111Handle=GetDlgItem(hDlg,IDC_FP11); - COP112Handle=GetDlgItem(hDlg,IDC_FP12); - COP113Handle=GetDlgItem(hDlg,IDC_FP13); - COP114Handle=GetDlgItem(hDlg,IDC_FP14); - COP115Handle=GetDlgItem(hDlg,IDC_FP15); - COP116Handle=GetDlgItem(hDlg,IDC_FP16); - COP117Handle=GetDlgItem(hDlg,IDC_FP17); - COP118Handle=GetDlgItem(hDlg,IDC_FP18); - COP119Handle=GetDlgItem(hDlg,IDC_FP19); - COP120Handle=GetDlgItem(hDlg,IDC_FP20); - COP121Handle=GetDlgItem(hDlg,IDC_FP21); - COP122Handle=GetDlgItem(hDlg,IDC_FP22); - COP123Handle=GetDlgItem(hDlg,IDC_FP23); - COP124Handle=GetDlgItem(hDlg,IDC_FP24); - COP125Handle=GetDlgItem(hDlg,IDC_FP25); - COP126Handle=GetDlgItem(hDlg,IDC_FP26); - COP127Handle=GetDlgItem(hDlg,IDC_FP27); - COP128Handle=GetDlgItem(hDlg,IDC_FP28); - COP129Handle=GetDlgItem(hDlg,IDC_FP29); - COP130Handle=GetDlgItem(hDlg,IDC_FP30); - COP131Handle=GetDlgItem(hDlg,IDC_FP31); - COP1C0Handle=GetDlgItem(hDlg,IDC_FCR0); - COP1C1Handle=GetDlgItem(hDlg,IDC_FCR31); - COP1ACCHandle=GetDlgItem(hDlg,IDC_FPU_ACC); - UpdateRegs(); - return (TRUE); - break; - case WM_COMMAND: - switch(LOWORD(wParam)) - { - case (IDOK || IDCANCEL): - EndDialog(hDlg,TRUE); - return(TRUE); - break; - - } - break; - } - - return(FALSE); -} - -LRESULT CALLBACK COP2Freg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch(message) - { - case WM_INITDIALOG: - VU0F00Handle=GetDlgItem(hDlg,IDC_VU0_VF00); - VU0F01Handle=GetDlgItem(hDlg,IDC_VU0_VF01); - VU0F02Handle=GetDlgItem(hDlg,IDC_VU0_VF02); - VU0F03Handle=GetDlgItem(hDlg,IDC_VU0_VF03); - VU0F04Handle=GetDlgItem(hDlg,IDC_VU0_VF04); - VU0F05Handle=GetDlgItem(hDlg,IDC_VU0_VF05); - VU0F06Handle=GetDlgItem(hDlg,IDC_VU0_VF06); - VU0F07Handle=GetDlgItem(hDlg,IDC_VU0_VF07); - VU0F08Handle=GetDlgItem(hDlg,IDC_VU0_VF08); - VU0F09Handle=GetDlgItem(hDlg,IDC_VU0_VF09); - VU0F10Handle=GetDlgItem(hDlg,IDC_VU0_VF10); - VU0F11Handle=GetDlgItem(hDlg,IDC_VU0_VF11); - VU0F12Handle=GetDlgItem(hDlg,IDC_VU0_VF12); - VU0F13Handle=GetDlgItem(hDlg,IDC_VU0_VF13); - VU0F14Handle=GetDlgItem(hDlg,IDC_VU0_VF14); - VU0F15Handle=GetDlgItem(hDlg,IDC_VU0_VF15); - VU0F16Handle=GetDlgItem(hDlg,IDC_VU0_VF16); - VU0F17Handle=GetDlgItem(hDlg,IDC_VU0_VF17); - VU0F18Handle=GetDlgItem(hDlg,IDC_VU0_VF18); - VU0F19Handle=GetDlgItem(hDlg,IDC_VU0_VF19); - VU0F20Handle=GetDlgItem(hDlg,IDC_VU0_VF20); - VU0F21Handle=GetDlgItem(hDlg,IDC_VU0_VF21); - VU0F22Handle=GetDlgItem(hDlg,IDC_VU0_VF22); - VU0F23Handle=GetDlgItem(hDlg,IDC_VU0_VF23); - VU0F24Handle=GetDlgItem(hDlg,IDC_VU0_VF24); - VU0F25Handle=GetDlgItem(hDlg,IDC_VU0_VF25); - VU0F26Handle=GetDlgItem(hDlg,IDC_VU0_VF26); - VU0F27Handle=GetDlgItem(hDlg,IDC_VU0_VF27); - VU0F28Handle=GetDlgItem(hDlg,IDC_VU0_VF28); - VU0F29Handle=GetDlgItem(hDlg,IDC_VU0_VF29); - VU0F30Handle=GetDlgItem(hDlg,IDC_VU0_VF30); - VU0F31Handle=GetDlgItem(hDlg,IDC_VU0_VF31); - UpdateRegs(); - return (TRUE); - break; - case WM_COMMAND: - - switch(LOWORD(wParam)) - { - case (IDOK || IDCANCEL): - EndDialog(hDlg,TRUE); - return(TRUE); - break; - - } - break; - } - - return(FALSE); -} -LRESULT CALLBACK COP2Creg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch(message) - { - case WM_INITDIALOG: - VU0C00Handle=GetDlgItem(hDlg,IDC_VU0_VI00); - VU0C01Handle=GetDlgItem(hDlg,IDC_VU0_VI01); - VU0C02Handle=GetDlgItem(hDlg,IDC_VU0_VI02); - VU0C03Handle=GetDlgItem(hDlg,IDC_VU0_VI03); - VU0C04Handle=GetDlgItem(hDlg,IDC_VU0_VI04); - VU0C05Handle=GetDlgItem(hDlg,IDC_VU0_VI05); - VU0C06Handle=GetDlgItem(hDlg,IDC_VU0_VI06); - VU0C07Handle=GetDlgItem(hDlg,IDC_VU0_VI07); - VU0C08Handle=GetDlgItem(hDlg,IDC_VU0_VI08); - VU0C09Handle=GetDlgItem(hDlg,IDC_VU0_VI09); - VU0C10Handle=GetDlgItem(hDlg,IDC_VU0_VI10); - VU0C11Handle=GetDlgItem(hDlg,IDC_VU0_VI11); - VU0C12Handle=GetDlgItem(hDlg,IDC_VU0_VI12); - VU0C13Handle=GetDlgItem(hDlg,IDC_VU0_VI13); - VU0C14Handle=GetDlgItem(hDlg,IDC_VU0_VI14); - VU0C15Handle=GetDlgItem(hDlg,IDC_VU0_VI15); - VU0C16Handle=GetDlgItem(hDlg,IDC_VU0_VI16); - VU0C17Handle=GetDlgItem(hDlg,IDC_VU0_VI17); - VU0C18Handle=GetDlgItem(hDlg,IDC_VU0_VI18); - VU0C19Handle=GetDlgItem(hDlg,IDC_VU0_VI19); - VU0C20Handle=GetDlgItem(hDlg,IDC_VU0_VI20); - VU0C21Handle=GetDlgItem(hDlg,IDC_VU0_VI21); - VU0C22Handle=GetDlgItem(hDlg,IDC_VU0_VI22); - VU0C23Handle=GetDlgItem(hDlg,IDC_VU0_VI23); - VU0C24Handle=GetDlgItem(hDlg,IDC_VU0_VI24); - VU0C25Handle=GetDlgItem(hDlg,IDC_VU0_VI25); - VU0C26Handle=GetDlgItem(hDlg,IDC_VU0_VI26); - VU0C27Handle=GetDlgItem(hDlg,IDC_VU0_VI27); - VU0C28Handle=GetDlgItem(hDlg,IDC_VU0_VI28); - VU0C29Handle=GetDlgItem(hDlg,IDC_VU0_VI29); - VU0C30Handle=GetDlgItem(hDlg,IDC_VU0_VI30); - VU0C31Handle=GetDlgItem(hDlg,IDC_VU0_VI31); - VU0ACCHandle=GetDlgItem(hDlg,IDC_VU0_ACC); - UpdateRegs(); - return (TRUE); - break; - case WM_COMMAND: - - switch(LOWORD(wParam)) - { - case (IDOK || IDCANCEL): - EndDialog(hDlg,TRUE); - return(TRUE); - break; - - } - break; - } - - return(FALSE); -} - - -LRESULT CALLBACK VU1Freg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch(message) - { - case WM_INITDIALOG: - VU1F00Handle=GetDlgItem(hDlg,IDC_VU1_VF00); - VU1F01Handle=GetDlgItem(hDlg,IDC_VU1_VF01); - VU1F02Handle=GetDlgItem(hDlg,IDC_VU1_VF02); - VU1F03Handle=GetDlgItem(hDlg,IDC_VU1_VF03); - VU1F04Handle=GetDlgItem(hDlg,IDC_VU1_VF04); - VU1F05Handle=GetDlgItem(hDlg,IDC_VU1_VF05); - VU1F06Handle=GetDlgItem(hDlg,IDC_VU1_VF06); - VU1F07Handle=GetDlgItem(hDlg,IDC_VU1_VF07); - VU1F08Handle=GetDlgItem(hDlg,IDC_VU1_VF08); - VU1F09Handle=GetDlgItem(hDlg,IDC_VU1_VF09); - VU1F10Handle=GetDlgItem(hDlg,IDC_VU1_VF10); - VU1F11Handle=GetDlgItem(hDlg,IDC_VU1_VF11); - VU1F12Handle=GetDlgItem(hDlg,IDC_VU1_VF12); - VU1F13Handle=GetDlgItem(hDlg,IDC_VU1_VF13); - VU1F14Handle=GetDlgItem(hDlg,IDC_VU1_VF14); - VU1F15Handle=GetDlgItem(hDlg,IDC_VU1_VF15); - VU1F16Handle=GetDlgItem(hDlg,IDC_VU1_VF16); - VU1F17Handle=GetDlgItem(hDlg,IDC_VU1_VF17); - VU1F18Handle=GetDlgItem(hDlg,IDC_VU1_VF18); - VU1F19Handle=GetDlgItem(hDlg,IDC_VU1_VF19); - VU1F20Handle=GetDlgItem(hDlg,IDC_VU1_VF20); - VU1F21Handle=GetDlgItem(hDlg,IDC_VU1_VF21); - VU1F22Handle=GetDlgItem(hDlg,IDC_VU1_VF22); - VU1F23Handle=GetDlgItem(hDlg,IDC_VU1_VF23); - VU1F24Handle=GetDlgItem(hDlg,IDC_VU1_VF24); - VU1F25Handle=GetDlgItem(hDlg,IDC_VU1_VF25); - VU1F26Handle=GetDlgItem(hDlg,IDC_VU1_VF26); - VU1F27Handle=GetDlgItem(hDlg,IDC_VU1_VF27); - VU1F28Handle=GetDlgItem(hDlg,IDC_VU1_VF28); - VU1F29Handle=GetDlgItem(hDlg,IDC_VU1_VF29); - VU1F30Handle=GetDlgItem(hDlg,IDC_VU1_VF30); - VU1F31Handle=GetDlgItem(hDlg,IDC_VU1_VF31); - UpdateRegs(); - return (TRUE); - break; - case WM_COMMAND: - - switch(LOWORD(wParam)) - { - case (IDOK || IDCANCEL): - EndDialog(hDlg,TRUE); - return(TRUE); - break; - - } - break; - } - - return(FALSE); -} -LRESULT CALLBACK VU1Creg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch(message) - { - case WM_INITDIALOG: - VU1C00Handle=GetDlgItem(hDlg,IDC_VU1_VI00); - VU1C01Handle=GetDlgItem(hDlg,IDC_VU1_VI01); - VU1C02Handle=GetDlgItem(hDlg,IDC_VU1_VI02); - VU1C03Handle=GetDlgItem(hDlg,IDC_VU1_VI03); - VU1C04Handle=GetDlgItem(hDlg,IDC_VU1_VI04); - VU1C05Handle=GetDlgItem(hDlg,IDC_VU1_VI05); - VU1C06Handle=GetDlgItem(hDlg,IDC_VU1_VI06); - VU1C07Handle=GetDlgItem(hDlg,IDC_VU1_VI07); - VU1C08Handle=GetDlgItem(hDlg,IDC_VU1_VI08); - VU1C09Handle=GetDlgItem(hDlg,IDC_VU1_VI09); - VU1C10Handle=GetDlgItem(hDlg,IDC_VU1_VI10); - VU1C11Handle=GetDlgItem(hDlg,IDC_VU1_VI11); - VU1C12Handle=GetDlgItem(hDlg,IDC_VU1_VI12); - VU1C13Handle=GetDlgItem(hDlg,IDC_VU1_VI13); - VU1C14Handle=GetDlgItem(hDlg,IDC_VU1_VI14); - VU1C15Handle=GetDlgItem(hDlg,IDC_VU1_VI15); - VU1C16Handle=GetDlgItem(hDlg,IDC_VU1_VI16); - VU1C17Handle=GetDlgItem(hDlg,IDC_VU1_VI17); - VU1C18Handle=GetDlgItem(hDlg,IDC_VU1_VI18); - VU1C19Handle=GetDlgItem(hDlg,IDC_VU1_VI19); - VU1C20Handle=GetDlgItem(hDlg,IDC_VU1_VI20); - VU1C21Handle=GetDlgItem(hDlg,IDC_VU1_VI21); - VU1C22Handle=GetDlgItem(hDlg,IDC_VU1_VI22); - VU1C23Handle=GetDlgItem(hDlg,IDC_VU1_VI23); - VU1C24Handle=GetDlgItem(hDlg,IDC_VU1_VI24); - VU1C25Handle=GetDlgItem(hDlg,IDC_VU1_VI25); - VU1C26Handle=GetDlgItem(hDlg,IDC_VU1_VI26); - VU1C27Handle=GetDlgItem(hDlg,IDC_VU1_VI27); - VU1C28Handle=GetDlgItem(hDlg,IDC_VU1_VI28); - VU1C29Handle=GetDlgItem(hDlg,IDC_VU1_VI29); - VU1C30Handle=GetDlgItem(hDlg,IDC_VU1_VI30); - VU1C31Handle=GetDlgItem(hDlg,IDC_VU1_VI31); - VU1ACCHandle=GetDlgItem(hDlg,IDC_VU1_ACC); - UpdateRegs(); - return (TRUE); - break; - case WM_COMMAND: - - switch(LOWORD(wParam)) - { - case (IDOK || IDCANCEL): - EndDialog(hDlg,TRUE); - return(TRUE); - break; - - } - break; - } - - return(FALSE); -} - -void UpdateRegs(void) -{ - - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[0]); - SendMessage(IOPGPR0Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[1]); - SendMessage(IOPGPR1Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[2]); - SendMessage(IOPGPR2Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[3]); - SendMessage(IOPGPR3Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[4]); - SendMessage(IOPGPR4Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[5]); - SendMessage(IOPGPR5Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[6]); - SendMessage(IOPGPR6Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[7]); - SendMessage(IOPGPR7Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[8]); - SendMessage(IOPGPR8Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[9]); - SendMessage(IOPGPR9Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[10]); - SendMessage(IOPGPR10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[11]); - SendMessage(IOPGPR11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[12]); - SendMessage(IOPGPR12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[13]); - SendMessage(IOPGPR13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[14]); - SendMessage(IOPGPR14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[15]); - SendMessage(IOPGPR15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[16]); - SendMessage(IOPGPR16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[17]); - SendMessage(IOPGPR17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[18]); - SendMessage(IOPGPR18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[19]); - SendMessage(IOPGPR19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[20]); - SendMessage(IOPGPR20Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[21]); - SendMessage(IOPGPR21Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[22]); - SendMessage(IOPGPR22Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[23]); - SendMessage(IOPGPR23Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[24]); - SendMessage(IOPGPR24Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[25]); - SendMessage(IOPGPR25Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[26]); - SendMessage(IOPGPR26Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[27]); - SendMessage(IOPGPR27Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[28]); - SendMessage(IOPGPR28Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[29]); - SendMessage(IOPGPR29Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[30]); - SendMessage(IOPGPR30Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[31]); - SendMessage(IOPGPR31Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",psxRegs.pc ); - SendMessage(IOPGPRPCHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[32]); - SendMessage(IOPGPRHIHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[33]); - SendMessage(IOPGPRLOHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[0].UL[3],cpuRegs.GPR.r[0].UL[2],cpuRegs.GPR.r[0].UL[1],cpuRegs.GPR.r[0].UL[0] ); - SendMessage(GPR0Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[1].UL[3], cpuRegs.GPR.r[1].UL[2],cpuRegs.GPR.r[1].UL[1],cpuRegs.GPR.r[1].UL[0] ); - SendMessage(GPR1Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[2].UL[3],cpuRegs.GPR.r[2].UL[2], cpuRegs.GPR.r[2].UL[1],cpuRegs.GPR.r[2].UL[0]); - SendMessage(GPR2Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[3].UL[3],cpuRegs.GPR.r[3].UL[2], cpuRegs.GPR.r[3].UL[1],cpuRegs.GPR.r[3].UL[0] ); - SendMessage(GPR3Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[4].UL[3],cpuRegs.GPR.r[4].UL[2], cpuRegs.GPR.r[4].UL[1],cpuRegs.GPR.r[4].UL[0] ); - SendMessage(GPR4Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[5].UL[3],cpuRegs.GPR.r[5].UL[2],cpuRegs.GPR.r[5].UL[1], cpuRegs.GPR.r[5].UL[0] ); - SendMessage(GPR5Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[6].UL[3],cpuRegs.GPR.r[6].UL[2], cpuRegs.GPR.r[6].UL[1], cpuRegs.GPR.r[6].UL[0]); - SendMessage(GPR6Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[7].UL[3], cpuRegs.GPR.r[7].UL[2],cpuRegs.GPR.r[7].UL[1],cpuRegs.GPR.r[7].UL[0] ); - SendMessage(GPR7Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[8].UL[3],cpuRegs.GPR.r[8].UL[2],cpuRegs.GPR.r[8].UL[1],cpuRegs.GPR.r[8].UL[0] ); - SendMessage(GPR8Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[9].UL[3],cpuRegs.GPR.r[9].UL[2],cpuRegs.GPR.r[9].UL[1], cpuRegs.GPR.r[9].UL[0] ); - SendMessage(GPR9Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[10].UL[3],cpuRegs.GPR.r[10].UL[2],cpuRegs.GPR.r[10].UL[1],cpuRegs.GPR.r[10].UL[0] ); - SendMessage(GPR10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[11].UL[3],cpuRegs.GPR.r[11].UL[2],cpuRegs.GPR.r[11].UL[1],cpuRegs.GPR.r[11].UL[0] ); - SendMessage(GPR11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[12].UL[3],cpuRegs.GPR.r[12].UL[2],cpuRegs.GPR.r[12].UL[1],cpuRegs.GPR.r[12].UL[0] ); - SendMessage(GPR12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[13].UL[3],cpuRegs.GPR.r[13].UL[2],cpuRegs.GPR.r[13].UL[1],cpuRegs.GPR.r[13].UL[0] ); - SendMessage(GPR13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[14].UL[3],cpuRegs.GPR.r[14].UL[2],cpuRegs.GPR.r[14].UL[1],cpuRegs.GPR.r[14].UL[0] ); - SendMessage(GPR14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[15].UL[3],cpuRegs.GPR.r[15].UL[2],cpuRegs.GPR.r[15].UL[1],cpuRegs.GPR.r[15].UL[0] ); - SendMessage(GPR15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[16].UL[3],cpuRegs.GPR.r[16].UL[2],cpuRegs.GPR.r[16].UL[1],cpuRegs.GPR.r[16].UL[0] ); - SendMessage(GPR16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[17].UL[3],cpuRegs.GPR.r[17].UL[2],cpuRegs.GPR.r[17].UL[1],cpuRegs.GPR.r[17].UL[0] ); - SendMessage(GPR17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[18].UL[3],cpuRegs.GPR.r[18].UL[2],cpuRegs.GPR.r[18].UL[1],cpuRegs.GPR.r[18].UL[0] ); - SendMessage(GPR18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[19].UL[3],cpuRegs.GPR.r[19].UL[2],cpuRegs.GPR.r[19].UL[1],cpuRegs.GPR.r[19].UL[0] ); - SendMessage(GPR19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[20].UL[3],cpuRegs.GPR.r[20].UL[2],cpuRegs.GPR.r[20].UL[1],cpuRegs.GPR.r[20].UL[0] ); - SendMessage(GPR20Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[21].UL[3],cpuRegs.GPR.r[21].UL[2],cpuRegs.GPR.r[21].UL[1],cpuRegs.GPR.r[21].UL[0] ); - SendMessage(GPR21Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[22].UL[3],cpuRegs.GPR.r[22].UL[2],cpuRegs.GPR.r[22].UL[1],cpuRegs.GPR.r[22].UL[0] ); - SendMessage(GPR22Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[23].UL[3],cpuRegs.GPR.r[23].UL[2],cpuRegs.GPR.r[23].UL[1],cpuRegs.GPR.r[23].UL[0] ); - SendMessage(GPR23Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[24].UL[3],cpuRegs.GPR.r[24].UL[2],cpuRegs.GPR.r[24].UL[1],cpuRegs.GPR.r[24].UL[0] ); - SendMessage(GPR24Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[25].UL[3],cpuRegs.GPR.r[25].UL[2],cpuRegs.GPR.r[25].UL[1],cpuRegs.GPR.r[25].UL[0] ); - SendMessage(GPR25Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[26].UL[3],cpuRegs.GPR.r[26].UL[2],cpuRegs.GPR.r[26].UL[1],cpuRegs.GPR.r[26].UL[0] ); - SendMessage(GPR26Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[27].UL[3],cpuRegs.GPR.r[27].UL[2],cpuRegs.GPR.r[27].UL[1],cpuRegs.GPR.r[27].UL[0] ); - SendMessage(GPR27Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[28].UL[3],cpuRegs.GPR.r[28].UL[2],cpuRegs.GPR.r[28].UL[1],cpuRegs.GPR.r[28].UL[0] ); - SendMessage(GPR28Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[29].UL[3],cpuRegs.GPR.r[29].UL[2],cpuRegs.GPR.r[29].UL[1],cpuRegs.GPR.r[29].UL[0] ); - SendMessage(GPR29Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[30].UL[3],cpuRegs.GPR.r[30].UL[2],cpuRegs.GPR.r[30].UL[1],cpuRegs.GPR.r[30].UL[0] ); - SendMessage(GPR30Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[31].UL[3],cpuRegs.GPR.r[31].UL[2],cpuRegs.GPR.r[31].UL[1],cpuRegs.GPR.r[31].UL[0] ); - SendMessage(GPR31Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.pc ); - SendMessage(GPRPCHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.HI.UL[3],cpuRegs.HI.UL[2] ,cpuRegs.HI.UL[1] ,cpuRegs.HI.UL[0] ); - SendMessage(GPRHIHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"0x%08X_%08X_%08X_%08X\0\0",cpuRegs.LO.UL[3],cpuRegs.LO.UL[2],cpuRegs.LO.UL[1],cpuRegs.LO.UL[0] ); - SendMessage(GPRLOHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[0] ); - SendMessage(COP00Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[1]); - SendMessage(COP01Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[2]); - SendMessage(COP02Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[3]); - SendMessage(COP03Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[4]); - SendMessage(COP04Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[5]); - SendMessage(COP05Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[6]); - SendMessage(COP06Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[7]); - SendMessage(COP07Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[8]); - SendMessage(COP08Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[9]); - SendMessage(COP09Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[10]); - SendMessage(COP010Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[11]); - SendMessage(COP011Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[12]); - SendMessage(COP012Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[13]); - SendMessage(COP013Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[14]); - SendMessage(COP014Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[15]); - SendMessage(COP015Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[16]); - SendMessage(COP016Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[17]); - SendMessage(COP017Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[18]); - SendMessage(COP018Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[19]); - SendMessage(COP019Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[20]); - SendMessage(COP020Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[21]); - SendMessage(COP021Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[22]); - SendMessage(COP022Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[23]); - SendMessage(COP023Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[24]); - SendMessage(COP024Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[25]); - SendMessage(COP025Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[26]); - SendMessage(COP026Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[27]); - SendMessage(COP027Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[28]); - SendMessage(COP028Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[29]); - SendMessage(COP029Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[30]); - SendMessage(COP030Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",cpuRegs.CP0.r[31]); - SendMessage(COP031Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - - sprintf(text1,"%f",fpuRegs.fpr[0].f ); - SendMessage(COP10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[1].f); - SendMessage(COP11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[2].f); - SendMessage(COP12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[3].f); - SendMessage(COP13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[4].f); - SendMessage(COP14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[5].f); - SendMessage(COP15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[6].f); - SendMessage(COP16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[7].f); - SendMessage(COP17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[8].f); - SendMessage(COP18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[9].f); - SendMessage(COP19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[10].f); - SendMessage(COP110Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[11].f); - SendMessage(COP111Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[12].f); - SendMessage(COP112Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[13].f); - SendMessage(COP113Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[14].f); - SendMessage(COP114Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[15].f); - SendMessage(COP115Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[16].f); - SendMessage(COP116Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[17].f); - SendMessage(COP117Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[18].f); - SendMessage(COP118Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[19].f); - SendMessage(COP119Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[20].f); - SendMessage(COP120Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[21].f); - SendMessage(COP121Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[22].f); - SendMessage(COP122Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[23].f); - SendMessage(COP123Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[24].f); - SendMessage(COP124Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[25].f); - SendMessage(COP125Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[26].f); - SendMessage(COP126Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[27].f); - SendMessage(COP127Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[28].f); - SendMessage(COP128Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[29].f); - SendMessage(COP129Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[30].f); - SendMessage(COP130Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.fpr[31].f); - SendMessage(COP131Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",fpuRegs.fprc[0]); - SendMessage(COP1C0Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",fpuRegs.fprc[31]); - SendMessage(COP1C1Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f",fpuRegs.ACC.f); - SendMessage(COP1ACCHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - - - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[0].f.w,VU0.VF[0].f.z,VU0.VF[0].f.y,VU0.VF[0].f.x ); - SendMessage(VU0F00Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[1].f.w,VU0.VF[1].f.z,VU0.VF[1].f.y,VU0.VF[1].f.x ); - SendMessage(VU0F01Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[2].f.w,VU0.VF[2].f.z,VU0.VF[2].f.y,VU0.VF[2].f.x ); - SendMessage(VU0F02Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[3].f.w,VU0.VF[3].f.z,VU0.VF[3].f.y,VU0.VF[3].f.x ); - SendMessage(VU0F03Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[4].f.w,VU0.VF[4].f.z,VU0.VF[4].f.y,VU0.VF[4].f.x ); - SendMessage(VU0F04Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[5].f.w,VU0.VF[5].f.z,VU0.VF[5].f.y,VU0.VF[5].f.x); - SendMessage(VU0F05Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[6].f.w,VU0.VF[6].f.z,VU0.VF[6].f.y,VU0.VF[6].f.x ); - SendMessage(VU0F06Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[7].f.w,VU0.VF[7].f.z,VU0.VF[7].f.y,VU0.VF[7].f.x ); - SendMessage(VU0F07Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[8].f.w,VU0.VF[8].f.z,VU0.VF[8].f.y,VU0.VF[8].f.x ); - SendMessage(VU0F08Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[9].f.w,VU0.VF[9].f.z,VU0.VF[9].f.y,VU0.VF[9].f.x ); - SendMessage(VU0F09Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[10].f.w,VU0.VF[10].f.z,VU0.VF[10].f.y,VU0.VF[10].f.x ); - SendMessage(VU0F10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[11].f.w,VU0.VF[11].f.z,VU0.VF[11].f.y,VU0.VF[11].f.x ); - SendMessage(VU0F11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[12].f.w,VU0.VF[12].f.z,VU0.VF[12].f.y,VU0.VF[12].f.x ); - SendMessage(VU0F12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[13].f.w,VU0.VF[13].f.z,VU0.VF[13].f.y,VU0.VF[13].f.x ); - SendMessage(VU0F13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[14].f.w,VU0.VF[14].f.z,VU0.VF[14].f.y,VU0.VF[14].f.x ); - SendMessage(VU0F14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[15].f.w,VU0.VF[15].f.z,VU0.VF[15].f.y,VU0.VF[15].f.x ); - SendMessage(VU0F15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[16].f.w,VU0.VF[16].f.z,VU0.VF[16].f.y,VU0.VF[16].f.x ); - SendMessage(VU0F16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[17].f.w,VU0.VF[17].f.z,VU0.VF[17].f.y,VU0.VF[17].f.x ); - SendMessage(VU0F17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[18].f.w,VU0.VF[18].f.z,VU0.VF[18].f.y,VU0.VF[18].f.x ); - SendMessage(VU0F18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[19].f.w,VU0.VF[19].f.z,VU0.VF[19].f.y,VU0.VF[19].f.x ); - SendMessage(VU0F19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[20].f.w,VU0.VF[20].f.z,VU0.VF[20].f.y,VU0.VF[20].f.x ); - SendMessage(VU0F20Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[21].f.w,VU0.VF[21].f.z,VU0.VF[21].f.y,VU0.VF[21].f.x ); - SendMessage(VU0F21Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[22].f.w,VU0.VF[22].f.z,VU0.VF[22].f.y,VU0.VF[22].f.x ); - SendMessage(VU0F22Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[23].f.w,VU0.VF[23].f.z,VU0.VF[23].f.y,VU0.VF[23].f.x ); - SendMessage(VU0F23Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[24].f.w,VU0.VF[24].f.z,VU0.VF[24].f.y,VU0.VF[24].f.x ); - SendMessage(VU0F24Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[25].f.w,VU0.VF[25].f.z,VU0.VF[25].f.y,VU0.VF[25].f.x ); - SendMessage(VU0F25Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[26].f.w,VU0.VF[26].f.z,VU0.VF[26].f.y,VU0.VF[26].f.x ); - SendMessage(VU0F26Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[27].f.w,VU0.VF[27].f.z,VU0.VF[27].f.y,VU0.VF[27].f.x ); - SendMessage(VU0F27Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[28].f.w,VU0.VF[28].f.z,VU0.VF[28].f.y,VU0.VF[28].f.x ); - SendMessage(VU0F28Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[29].f.w,VU0.VF[29].f.z,VU0.VF[29].f.y,VU0.VF[29].f.x ); - SendMessage(VU0F29Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[30].f.w,VU0.VF[30].f.z,VU0.VF[30].f.y,VU0.VF[30].f.x ); - SendMessage(VU0F30Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[31].f.w,VU0.VF[31].f.z,VU0.VF[31].f.y,VU0.VF[31].f.x ); - SendMessage(VU0F31Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - - - wsprintf(text1,"%x",VU0.VI[0] ); - SendMessage(VU0C00Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[1]); - SendMessage(VU0C01Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[2]); - SendMessage(VU0C02Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[3]); - SendMessage(VU0C03Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[4]); - SendMessage(VU0C04Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[5]); - SendMessage(VU0C05Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[6]); - SendMessage(VU0C06Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[7]); - SendMessage(VU0C07Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[8]); - SendMessage(VU0C08Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[9]); - SendMessage(VU0C09Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[10]); - SendMessage(VU0C10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[11]); - SendMessage(VU0C11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[12]); - SendMessage(VU0C12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[13]); - SendMessage(VU0C13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[14]); - SendMessage(VU0C14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[15]); - SendMessage(VU0C15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[16]); - SendMessage(VU0C16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[17]); - SendMessage(VU0C17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[18]); - SendMessage(VU0C18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[19]); - SendMessage(VU0C19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[20]); - SendMessage(VU0C20Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[21]); - SendMessage(VU0C21Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[22]); - SendMessage(VU0C22Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[23]); - SendMessage(VU0C23Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[24]); - SendMessage(VU0C24Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[25]); - SendMessage(VU0C25Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[26]); - SendMessage(VU0C26Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[27]); - SendMessage(VU0C27Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[28]); - SendMessage(VU0C28Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[29]); - SendMessage(VU0C29Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[30]); - SendMessage(VU0C30Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU0.VI[31]); - SendMessage(VU0C31Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - - sprintf(text1,"%f_%f_%f_%f\0",VU0.ACC.f.w,VU0.ACC.f.z,VU0.ACC.f.y,VU0.ACC.f.x ); - SendMessage(VU0ACCHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - - - - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[0].f.w,VU1.VF[0].f.z,VU1.VF[0].f.y,VU1.VF[0].f.x ); - SendMessage(VU1F00Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[1].f.w,VU1.VF[1].f.z,VU1.VF[1].f.y,VU1.VF[1].f.x ); - SendMessage(VU1F01Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[2].f.w,VU1.VF[2].f.z,VU1.VF[2].f.y,VU1.VF[2].f.x ); - SendMessage(VU1F02Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[3].f.w,VU1.VF[3].f.z,VU1.VF[3].f.y,VU1.VF[3].f.x ); - SendMessage(VU1F03Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[4].f.w,VU1.VF[4].f.z,VU1.VF[4].f.y,VU1.VF[4].f.x ); - SendMessage(VU1F04Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[5].f.w,VU1.VF[5].f.z,VU1.VF[5].f.y,VU1.VF[5].f.x); - SendMessage(VU1F05Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[6].f.w,VU1.VF[6].f.z,VU1.VF[6].f.y,VU1.VF[6].f.x ); - SendMessage(VU1F06Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[7].f.w,VU1.VF[7].f.z,VU1.VF[7].f.y,VU1.VF[7].f.x ); - SendMessage(VU1F07Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[8].f.w,VU1.VF[8].f.z,VU1.VF[8].f.y,VU1.VF[8].f.x ); - SendMessage(VU1F08Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[9].f.w,VU1.VF[9].f.z,VU1.VF[9].f.y,VU1.VF[9].f.x ); - SendMessage(VU1F09Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[10].f.w,VU1.VF[10].f.z,VU1.VF[10].f.y,VU1.VF[10].f.x ); - SendMessage(VU1F10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[11].f.w,VU1.VF[11].f.z,VU1.VF[11].f.y,VU1.VF[11].f.x ); - SendMessage(VU1F11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[12].f.w,VU1.VF[12].f.z,VU1.VF[12].f.y,VU1.VF[12].f.x ); - SendMessage(VU1F12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[13].f.w,VU1.VF[13].f.z,VU1.VF[13].f.y,VU1.VF[13].f.x ); - SendMessage(VU1F13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[14].f.w,VU1.VF[14].f.z,VU1.VF[14].f.y,VU1.VF[14].f.x ); - SendMessage(VU1F14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[15].f.w,VU1.VF[15].f.z,VU1.VF[15].f.y,VU1.VF[15].f.x ); - SendMessage(VU1F15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[16].f.w,VU1.VF[16].f.z,VU1.VF[16].f.y,VU1.VF[16].f.x ); - SendMessage(VU1F16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[17].f.w,VU1.VF[17].f.z,VU1.VF[17].f.y,VU1.VF[17].f.x ); - SendMessage(VU1F17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[18].f.w,VU1.VF[18].f.z,VU1.VF[18].f.y,VU1.VF[18].f.x ); - SendMessage(VU1F18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[19].f.w,VU1.VF[19].f.z,VU1.VF[19].f.y,VU1.VF[19].f.x ); - SendMessage(VU1F19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[20].f.w,VU1.VF[20].f.z,VU1.VF[20].f.y,VU1.VF[20].f.x ); - SendMessage(VU1F20Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[21].f.w,VU1.VF[21].f.z,VU1.VF[21].f.y,VU1.VF[21].f.x ); - SendMessage(VU1F21Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[22].f.w,VU1.VF[22].f.z,VU1.VF[22].f.y,VU1.VF[22].f.x ); - SendMessage(VU1F22Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[23].f.w,VU1.VF[23].f.z,VU1.VF[23].f.y,VU1.VF[23].f.x ); - SendMessage(VU1F23Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[24].f.w,VU1.VF[24].f.z,VU1.VF[24].f.y,VU1.VF[24].f.x ); - SendMessage(VU1F24Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[25].f.w,VU1.VF[25].f.z,VU1.VF[25].f.y,VU1.VF[25].f.x ); - SendMessage(VU1F25Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[26].f.w,VU1.VF[26].f.z,VU1.VF[26].f.y,VU1.VF[26].f.x ); - SendMessage(VU1F26Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[27].f.w,VU1.VF[27].f.z,VU1.VF[27].f.y,VU1.VF[27].f.x ); - SendMessage(VU1F27Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[28].f.w,VU1.VF[28].f.z,VU1.VF[28].f.y,VU1.VF[28].f.x ); - SendMessage(VU1F28Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[29].f.w,VU1.VF[29].f.z,VU1.VF[29].f.y,VU1.VF[29].f.x ); - SendMessage(VU1F29Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[30].f.w,VU1.VF[30].f.z,VU1.VF[30].f.y,VU1.VF[30].f.x ); - SendMessage(VU1F30Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[31].f.w,VU1.VF[31].f.z,VU1.VF[31].f.y,VU1.VF[31].f.x ); - SendMessage(VU1F31Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - - - wsprintf(text1,"%x",VU1.VI[0] ); - SendMessage(VU1C00Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[1]); - SendMessage(VU1C01Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[2]); - SendMessage(VU1C02Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[3]); - SendMessage(VU1C03Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[4]); - SendMessage(VU1C04Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[5]); - SendMessage(VU1C05Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[6]); - SendMessage(VU1C06Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[7]); - SendMessage(VU1C07Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[8]); - SendMessage(VU1C08Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[9]); - SendMessage(VU1C09Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[10]); - SendMessage(VU1C10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[11]); - SendMessage(VU1C11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[12]); - SendMessage(VU1C12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[13]); - SendMessage(VU1C13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[14]); - SendMessage(VU1C14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[15]); - SendMessage(VU1C15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[16]); - SendMessage(VU1C16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[17]); - SendMessage(VU1C17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[18]); - SendMessage(VU1C18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[19]); - SendMessage(VU1C19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[20]); - SendMessage(VU1C20Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[21]); - SendMessage(VU1C21Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[22]); - SendMessage(VU1C22Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[23]); - SendMessage(VU1C23Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[24]); - SendMessage(VU1C24Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[25]); - SendMessage(VU1C25Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[26]); - SendMessage(VU1C26Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[27]); - SendMessage(VU1C27Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[28]); - SendMessage(VU1C28Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[29]); - SendMessage(VU1C29Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[30]); - SendMessage(VU1C30Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - wsprintf(text1,"%x",VU1.VI[31]); - SendMessage(VU1C31Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - - sprintf(text1,"%f_%f_%f_%f\0",VU1.ACC.f.w,VU1.ACC.f.z,VU1.ACC.f.y,VU1.ACC.f.x ); - SendMessage(VU1ACCHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); - -} - - -void EEDumpRegs(FILE * fp) -{ - char text2[256]; - int i; - for(i = 0; i < 32; i++) - { - sprintf(text1,"%x_%x_%x_%x",cpuRegs.GPR.r[i].UL[3],cpuRegs.GPR.r[i].UL[2],cpuRegs.GPR.r[i].UL[1],cpuRegs.GPR.r[i].UL[0]); - sprintf(text2,"GPR Register %d: ",i+1); - fprintf(fp,text2); - fprintf(fp,text1); - fprintf(fp,"\n"); - } - sprintf(text1,"0x%x",cpuRegs.pc); - fprintf(fp,"PC Register : "); - fprintf(fp,text1); - fprintf(fp,"\n"); - sprintf(text1,"%x_%x_%x_%x",cpuRegs.HI.UL[3],cpuRegs.HI.UL[2],cpuRegs.HI.UL[1],cpuRegs.HI.UL[0]); - fprintf(fp,"GPR Register HI: "); - fprintf(fp,text1); - fprintf(fp,"\n"); - sprintf(text1,"%x_%x_%x_%x",cpuRegs.LO.UL[3],cpuRegs.LO.UL[2],cpuRegs.LO.UL[1],cpuRegs.LO.UL[0]); - fprintf(fp,"GPR Register LO: "); - fprintf(fp,text1); - fprintf(fp,"\n"); - - - for(i = 0; i < 32; i++) - { - sprintf(text1,"0x%x",cpuRegs.CP0.r[i]); - sprintf(text2,"COP0 Register %d: ",i+1); - fprintf(fp,text2); - fprintf(fp,text1); - fprintf(fp,"\n"); - } -} - -void IOPDumpRegs(FILE * fp) -{ - char text2[256]; - int i; - for(i = 0; i < 32; i++) - { - sprintf(text1,"%x",psxRegs.GPR.r[i]); - sprintf(text2,"GPR Register %d: ",i+1); - fprintf(fp,text2); - fprintf(fp,text1); - fprintf(fp,"\n"); - } - sprintf(text1,"0x%x",psxRegs.pc); - fprintf(fp,"PC Register : "); - fprintf(fp,text1); - fprintf(fp,"\n"); - sprintf(text1,"%x",psxRegs.GPR.r[32]); - fprintf(fp,"GPR Register HI: "); - fprintf(fp,text1); - fprintf(fp,"\n"); - sprintf(text1,"%x",psxRegs.GPR.r[33]); - fprintf(fp,"GPR Register LO: "); - fprintf(fp,text1); - fprintf(fp,"\n"); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" +#include "Win32.h" + +#include + +#include "resource.h" +#include "Debugger.h" +#include "Debug.h" +#include "R5900.h" +#include "R3000a.h" +#include "VUmicro.h" + +HINSTANCE m_hInst; +HWND m_hWnd; +char text1[256]; + +// Wow! This module is a lot of copy-paste! +// Between this and DisAsm modules, *someone* needs a new Ctrl-V combo on their keyboard. (air) + +/*R3000a registers handle */ +static HWND IOPGPR0Handle=NULL; +static HWND IOPGPR1Handle=NULL; +static HWND IOPGPR2Handle=NULL; +static HWND IOPGPR3Handle=NULL; +static HWND IOPGPR4Handle=NULL; +static HWND IOPGPR5Handle=NULL; +static HWND IOPGPR6Handle=NULL; +static HWND IOPGPR7Handle=NULL; +static HWND IOPGPR8Handle=NULL; +static HWND IOPGPR9Handle=NULL; +static HWND IOPGPR10Handle=NULL; +static HWND IOPGPR11Handle=NULL; +static HWND IOPGPR12Handle=NULL; +static HWND IOPGPR13Handle=NULL; +static HWND IOPGPR14Handle=NULL; +static HWND IOPGPR15Handle=NULL; +static HWND IOPGPR16Handle=NULL; +static HWND IOPGPR17Handle=NULL; +static HWND IOPGPR18Handle=NULL; +static HWND IOPGPR19Handle=NULL; +static HWND IOPGPR20Handle=NULL; +static HWND IOPGPR21Handle=NULL; +static HWND IOPGPR22Handle=NULL; +static HWND IOPGPR23Handle=NULL; +static HWND IOPGPR24Handle=NULL; +static HWND IOPGPR25Handle=NULL; +static HWND IOPGPR26Handle=NULL; +static HWND IOPGPR27Handle=NULL; +static HWND IOPGPR28Handle=NULL; +static HWND IOPGPR29Handle=NULL; +static HWND IOPGPR30Handle=NULL; +static HWND IOPGPR31Handle=NULL; +static HWND IOPGPRPCHandle=NULL; +static HWND IOPGPRHIHandle=NULL; +static HWND IOPGPRLOHandle=NULL; + +/*R5900 registers handle */ +static HWND GPR0Handle=NULL; +static HWND GPR1Handle=NULL; +static HWND GPR2Handle=NULL; +static HWND GPR3Handle=NULL; +static HWND GPR4Handle=NULL; +static HWND GPR5Handle=NULL; +static HWND GPR6Handle=NULL; +static HWND GPR7Handle=NULL; +static HWND GPR8Handle=NULL; +static HWND GPR9Handle=NULL; +static HWND GPR10Handle=NULL; +static HWND GPR11Handle=NULL; +static HWND GPR12Handle=NULL; +static HWND GPR13Handle=NULL; +static HWND GPR14Handle=NULL; +static HWND GPR15Handle=NULL; +static HWND GPR16Handle=NULL; +static HWND GPR17Handle=NULL; +static HWND GPR18Handle=NULL; +static HWND GPR19Handle=NULL; +static HWND GPR20Handle=NULL; +static HWND GPR21Handle=NULL; +static HWND GPR22Handle=NULL; +static HWND GPR23Handle=NULL; +static HWND GPR24Handle=NULL; +static HWND GPR25Handle=NULL; +static HWND GPR26Handle=NULL; +static HWND GPR27Handle=NULL; +static HWND GPR28Handle=NULL; +static HWND GPR29Handle=NULL; +static HWND GPR30Handle=NULL; +static HWND GPR31Handle=NULL; +static HWND GPRPCHandle=NULL; +static HWND GPRHIHandle=NULL; +static HWND GPRLOHandle=NULL; +/*end of r3000a registers handle */ +/*cop0 registers here */ +static HWND COP00Handle=NULL; +static HWND COP01Handle=NULL; +static HWND COP02Handle=NULL; +static HWND COP03Handle=NULL; +static HWND COP04Handle=NULL; +static HWND COP05Handle=NULL; +static HWND COP06Handle=NULL; +static HWND COP07Handle=NULL; +static HWND COP08Handle=NULL; +static HWND COP09Handle=NULL; +static HWND COP010Handle=NULL; +static HWND COP011Handle=NULL; +static HWND COP012Handle=NULL; +static HWND COP013Handle=NULL; +static HWND COP014Handle=NULL; +static HWND COP015Handle=NULL; +static HWND COP016Handle=NULL; +static HWND COP017Handle=NULL; +static HWND COP018Handle=NULL; +static HWND COP019Handle=NULL; +static HWND COP020Handle=NULL; +static HWND COP021Handle=NULL; +static HWND COP022Handle=NULL; +static HWND COP023Handle=NULL; +static HWND COP024Handle=NULL; +static HWND COP025Handle=NULL; +static HWND COP026Handle=NULL; +static HWND COP027Handle=NULL; +static HWND COP028Handle=NULL; +static HWND COP029Handle=NULL; +static HWND COP030Handle=NULL; +static HWND COP031Handle=NULL; +static HWND COP0PCHandle=NULL; +static HWND COP0HIHandle=NULL; +static HWND COP0LOHandle=NULL; +/*end of cop0 registers */ +/*cop1 registers here */ +static HWND COP10Handle=NULL; +static HWND COP11Handle=NULL; +static HWND COP12Handle=NULL; +static HWND COP13Handle=NULL; +static HWND COP14Handle=NULL; +static HWND COP15Handle=NULL; +static HWND COP16Handle=NULL; +static HWND COP17Handle=NULL; +static HWND COP18Handle=NULL; +static HWND COP19Handle=NULL; +static HWND COP110Handle=NULL; +static HWND COP111Handle=NULL; +static HWND COP112Handle=NULL; +static HWND COP113Handle=NULL; +static HWND COP114Handle=NULL; +static HWND COP115Handle=NULL; +static HWND COP116Handle=NULL; +static HWND COP117Handle=NULL; +static HWND COP118Handle=NULL; +static HWND COP119Handle=NULL; +static HWND COP120Handle=NULL; +static HWND COP121Handle=NULL; +static HWND COP122Handle=NULL; +static HWND COP123Handle=NULL; +static HWND COP124Handle=NULL; +static HWND COP125Handle=NULL; +static HWND COP126Handle=NULL; +static HWND COP127Handle=NULL; +static HWND COP128Handle=NULL; +static HWND COP129Handle=NULL; +static HWND COP130Handle=NULL; +static HWND COP131Handle=NULL; +static HWND COP1C0Handle=NULL; +static HWND COP1C1Handle=NULL; +static HWND COP1ACCHandle=NULL; +/*end of cop1 registers */ +/*cop2 floating registers*/ +static HWND VU0F00Handle=NULL; +static HWND VU0F01Handle=NULL; +static HWND VU0F02Handle=NULL; +static HWND VU0F03Handle=NULL; +static HWND VU0F04Handle=NULL; +static HWND VU0F05Handle=NULL; +static HWND VU0F06Handle=NULL; +static HWND VU0F07Handle=NULL; +static HWND VU0F08Handle=NULL; +static HWND VU0F09Handle=NULL; +static HWND VU0F10Handle=NULL; +static HWND VU0F11Handle=NULL; +static HWND VU0F12Handle=NULL; +static HWND VU0F13Handle=NULL; +static HWND VU0F14Handle=NULL; +static HWND VU0F15Handle=NULL; +static HWND VU0F16Handle=NULL; +static HWND VU0F17Handle=NULL; +static HWND VU0F18Handle=NULL; +static HWND VU0F19Handle=NULL; +static HWND VU0F20Handle=NULL; +static HWND VU0F21Handle=NULL; +static HWND VU0F22Handle=NULL; +static HWND VU0F23Handle=NULL; +static HWND VU0F24Handle=NULL; +static HWND VU0F25Handle=NULL; +static HWND VU0F26Handle=NULL; +static HWND VU0F27Handle=NULL; +static HWND VU0F28Handle=NULL; +static HWND VU0F29Handle=NULL; +static HWND VU0F30Handle=NULL; +static HWND VU0F31Handle=NULL; +/*end of cop2 floating registers*/ +/*cop2 control registers */ +static HWND VU0C00Handle=NULL; +static HWND VU0C01Handle=NULL; +static HWND VU0C02Handle=NULL; +static HWND VU0C03Handle=NULL; +static HWND VU0C04Handle=NULL; +static HWND VU0C05Handle=NULL; +static HWND VU0C06Handle=NULL; +static HWND VU0C07Handle=NULL; +static HWND VU0C08Handle=NULL; +static HWND VU0C09Handle=NULL; +static HWND VU0C10Handle=NULL; +static HWND VU0C11Handle=NULL; +static HWND VU0C12Handle=NULL; +static HWND VU0C13Handle=NULL; +static HWND VU0C14Handle=NULL; +static HWND VU0C15Handle=NULL; +static HWND VU0C16Handle=NULL; +static HWND VU0C17Handle=NULL; +static HWND VU0C18Handle=NULL; +static HWND VU0C19Handle=NULL; +static HWND VU0C20Handle=NULL; +static HWND VU0C21Handle=NULL; +static HWND VU0C22Handle=NULL; +static HWND VU0C23Handle=NULL; +static HWND VU0C24Handle=NULL; +static HWND VU0C25Handle=NULL; +static HWND VU0C26Handle=NULL; +static HWND VU0C27Handle=NULL; +static HWND VU0C28Handle=NULL; +static HWND VU0C29Handle=NULL; +static HWND VU0C30Handle=NULL; +static HWND VU0C31Handle=NULL; +static HWND VU0ACCHandle=NULL; +/*end of cop2 control registers */ +/*vu1 floating registers*/ +static HWND VU1F00Handle=NULL; +static HWND VU1F01Handle=NULL; +static HWND VU1F02Handle=NULL; +static HWND VU1F03Handle=NULL; +static HWND VU1F04Handle=NULL; +static HWND VU1F05Handle=NULL; +static HWND VU1F06Handle=NULL; +static HWND VU1F07Handle=NULL; +static HWND VU1F08Handle=NULL; +static HWND VU1F09Handle=NULL; +static HWND VU1F10Handle=NULL; +static HWND VU1F11Handle=NULL; +static HWND VU1F12Handle=NULL; +static HWND VU1F13Handle=NULL; +static HWND VU1F14Handle=NULL; +static HWND VU1F15Handle=NULL; +static HWND VU1F16Handle=NULL; +static HWND VU1F17Handle=NULL; +static HWND VU1F18Handle=NULL; +static HWND VU1F19Handle=NULL; +static HWND VU1F20Handle=NULL; +static HWND VU1F21Handle=NULL; +static HWND VU1F22Handle=NULL; +static HWND VU1F23Handle=NULL; +static HWND VU1F24Handle=NULL; +static HWND VU1F25Handle=NULL; +static HWND VU1F26Handle=NULL; +static HWND VU1F27Handle=NULL; +static HWND VU1F28Handle=NULL; +static HWND VU1F29Handle=NULL; +static HWND VU1F30Handle=NULL; +static HWND VU1F31Handle=NULL; +/*end of vu1 floating registers*/ +/*vu1 control registers */ +static HWND VU1C00Handle=NULL; +static HWND VU1C01Handle=NULL; +static HWND VU1C02Handle=NULL; +static HWND VU1C03Handle=NULL; +static HWND VU1C04Handle=NULL; +static HWND VU1C05Handle=NULL; +static HWND VU1C06Handle=NULL; +static HWND VU1C07Handle=NULL; +static HWND VU1C08Handle=NULL; +static HWND VU1C09Handle=NULL; +static HWND VU1C10Handle=NULL; +static HWND VU1C11Handle=NULL; +static HWND VU1C12Handle=NULL; +static HWND VU1C13Handle=NULL; +static HWND VU1C14Handle=NULL; +static HWND VU1C15Handle=NULL; +static HWND VU1C16Handle=NULL; +static HWND VU1C17Handle=NULL; +static HWND VU1C18Handle=NULL; +static HWND VU1C19Handle=NULL; +static HWND VU1C20Handle=NULL; +static HWND VU1C21Handle=NULL; +static HWND VU1C22Handle=NULL; +static HWND VU1C23Handle=NULL; +static HWND VU1C24Handle=NULL; +static HWND VU1C25Handle=NULL; +static HWND VU1C26Handle=NULL; +static HWND VU1C27Handle=NULL; +static HWND VU1C28Handle=NULL; +static HWND VU1C29Handle=NULL; +static HWND VU1C30Handle=NULL; +static HWND VU1C31Handle=NULL; +static HWND VU1ACCHandle=NULL; +/*end of vu1 control registers */ + +LRESULT CALLBACK R3000reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); + +//comctl32 lib must add to project.. +int CreatePropertySheet(HWND hwndOwner) +{ + + PROPSHEETPAGE psp[7]; + PROPSHEETHEADER psh; + + psp[0].dwSize = sizeof(PROPSHEETPAGE); + psp[0].dwFlags = PSP_USETITLE; + psp[0].hInstance = m_hInst; + psp[0].pszTemplate = MAKEINTRESOURCE( IDD_GPREGS); + psp[0].pszIcon = NULL; + psp[0].pfnDlgProc =(DLGPROC)R5900reg; + psp[0].pszTitle = "R5900"; + psp[0].lParam = 0; + + psp[1].dwSize = sizeof(PROPSHEETPAGE); + psp[1].dwFlags = PSP_USETITLE; + psp[1].hInstance = m_hInst; + psp[1].pszTemplate = MAKEINTRESOURCE( IDD_CP0REGS ); + psp[1].pszIcon = NULL; + psp[1].pfnDlgProc =(DLGPROC)COP0reg; + psp[1].pszTitle = "COP0"; + psp[1].lParam = 0; + + psp[2].dwSize = sizeof(PROPSHEETPAGE); + psp[2].dwFlags = PSP_USETITLE; + psp[2].hInstance = m_hInst; + psp[2].pszTemplate = MAKEINTRESOURCE( IDD_CP1REGS ); + psp[2].pszIcon = NULL; + psp[2].pfnDlgProc =(DLGPROC)COP1reg; + psp[2].pszTitle = "COP1"; + psp[2].lParam = 0; + + psp[3].dwSize = sizeof(PROPSHEETPAGE); + psp[3].dwFlags = PSP_USETITLE; + psp[3].hInstance = m_hInst; + psp[3].pszTemplate = MAKEINTRESOURCE( IDD_VU0REGS ); + psp[3].pszIcon = NULL; + psp[3].pfnDlgProc =(DLGPROC)COP2Freg; + psp[3].pszTitle = "COP2F"; + psp[3].lParam = 0; + + psp[4].dwSize = sizeof(PROPSHEETPAGE); + psp[4].dwFlags = PSP_USETITLE; + psp[4].hInstance = m_hInst; + psp[4].pszTemplate = MAKEINTRESOURCE( IDD_VU0INTEGER ); + psp[4].pszIcon = NULL; + psp[4].pfnDlgProc =(DLGPROC)COP2Creg; + psp[4].pszTitle = "COP2C"; + psp[4].lParam = 0; + + psp[5].dwSize = sizeof(PROPSHEETPAGE); + psp[5].dwFlags = PSP_USETITLE; + psp[5].hInstance = m_hInst; + psp[5].pszTemplate = MAKEINTRESOURCE( IDD_VU1REGS ); + psp[5].pszIcon = NULL; + psp[5].pfnDlgProc =(DLGPROC)VU1Freg; + psp[5].pszTitle = "VU1F"; + psp[5].lParam = 0; + + psp[6].dwSize = sizeof(PROPSHEETPAGE); + psp[6].dwFlags = PSP_USETITLE; + psp[6].hInstance = m_hInst; + psp[6].pszTemplate = MAKEINTRESOURCE( IDD_VU1INTEGER ); + psp[6].pszIcon = NULL; + psp[6].pfnDlgProc =(DLGPROC)VU1Creg; + psp[6].pszTitle = "VU1C"; + psp[6].lParam = 0; + + psp[6].dwSize = sizeof(PROPSHEETPAGE); + psp[6].dwFlags = PSP_USETITLE; + psp[6].hInstance = m_hInst; + psp[6].pszTemplate = MAKEINTRESOURCE( IDD_IOPREGS ); + psp[6].pszIcon = NULL; + psp[6].pfnDlgProc =(DLGPROC)R3000reg; + psp[6].pszTitle = "R3000"; + psp[6].lParam = 0; + + psh.dwSize = sizeof(PROPSHEETHEADER); + psh.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS; + psh.hwndParent =hwndOwner; + psh.hInstance = m_hInst; + psh.pszIcon = NULL; + psh.pszCaption = (LPSTR) "Debugger"; + psh.nStartPage = 0; + psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE); + psh.ppsp = (LPCPROPSHEETPAGE) &psp; + + return (PropertySheet(&psh)); + +} +LRESULT CALLBACK R3000reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_INITDIALOG: + IOPGPR0Handle=GetDlgItem(hDlg,IDC_IOPGPR0); + IOPGPR1Handle=GetDlgItem(hDlg,IDC_IOPGPR1); + IOPGPR2Handle=GetDlgItem(hDlg,IDC_IOPGPR2); + IOPGPR3Handle=GetDlgItem(hDlg,IDC_IOPGPR3); + IOPGPR4Handle=GetDlgItem(hDlg,IDC_IOPGPR4); + IOPGPR5Handle=GetDlgItem(hDlg,IDC_IOPGPR5); + IOPGPR6Handle=GetDlgItem(hDlg,IDC_IOPGPR6); + IOPGPR7Handle=GetDlgItem(hDlg,IDC_IOPGPR7); + IOPGPR8Handle=GetDlgItem(hDlg,IDC_IOPGPR8); + IOPGPR9Handle=GetDlgItem(hDlg,IDC_IOPGPR9); + IOPGPR10Handle=GetDlgItem(hDlg,IDC_IOPGPR10); + IOPGPR11Handle=GetDlgItem(hDlg,IDC_IOPGPR11); + IOPGPR12Handle=GetDlgItem(hDlg,IDC_IOPGPR12); + IOPGPR13Handle=GetDlgItem(hDlg,IDC_IOPGPR13); + IOPGPR14Handle=GetDlgItem(hDlg,IDC_IOPGPR14); + IOPGPR15Handle=GetDlgItem(hDlg,IDC_IOPGPR15); + IOPGPR16Handle=GetDlgItem(hDlg,IDC_IOPGPR16); + IOPGPR17Handle=GetDlgItem(hDlg,IDC_IOPGPR17); + IOPGPR18Handle=GetDlgItem(hDlg,IDC_IOPGPR18); + IOPGPR19Handle=GetDlgItem(hDlg,IDC_IOPGPR19); + IOPGPR20Handle=GetDlgItem(hDlg,IDC_IOPGPR20); + IOPGPR21Handle=GetDlgItem(hDlg,IDC_IOPGPR21); + IOPGPR22Handle=GetDlgItem(hDlg,IDC_IOPGPR22); + IOPGPR23Handle=GetDlgItem(hDlg,IDC_IOPGPR23); + IOPGPR24Handle=GetDlgItem(hDlg,IDC_IOPGPR24); + IOPGPR25Handle=GetDlgItem(hDlg,IDC_IOPGPR25); + IOPGPR26Handle=GetDlgItem(hDlg,IDC_IOPGPR26); + IOPGPR27Handle=GetDlgItem(hDlg,IDC_IOPGPR27); + IOPGPR28Handle=GetDlgItem(hDlg,IDC_IOPGPR28); + IOPGPR29Handle=GetDlgItem(hDlg,IDC_IOPGPR29); + IOPGPR30Handle=GetDlgItem(hDlg,IDC_IOPGPR30); + IOPGPR31Handle=GetDlgItem(hDlg,IDC_IOPGPR31); + IOPGPRPCHandle=GetDlgItem(hDlg,IDC_IOPGPR_PC); + IOPGPRHIHandle=GetDlgItem(hDlg,IDC_IOPGPR_HI); + IOPGPRLOHandle=GetDlgItem(hDlg,IDC_IOPGPR_LO); + UpdateRegs(); + return (TRUE); + break; + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case (IDOK || IDCANCEL): + EndDialog(hDlg,TRUE); + return(TRUE); + break; + + } + break; + } + + return(FALSE); +} +LRESULT CALLBACK R5900reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_INITDIALOG: + GPR0Handle=GetDlgItem(hDlg,IDC_GPR0); + GPR1Handle=GetDlgItem(hDlg,IDC_GPR1); + GPR2Handle=GetDlgItem(hDlg,IDC_GPR2); + GPR3Handle=GetDlgItem(hDlg,IDC_GPR3); + GPR4Handle=GetDlgItem(hDlg,IDC_GPR4); + GPR5Handle=GetDlgItem(hDlg,IDC_GPR5); + GPR6Handle=GetDlgItem(hDlg,IDC_GPR6); + GPR7Handle=GetDlgItem(hDlg,IDC_GPR7); + GPR8Handle=GetDlgItem(hDlg,IDC_GPR8); + GPR9Handle=GetDlgItem(hDlg,IDC_GPR9); + GPR10Handle=GetDlgItem(hDlg,IDC_GPR10); + GPR11Handle=GetDlgItem(hDlg,IDC_GPR11); + GPR12Handle=GetDlgItem(hDlg,IDC_GPR12); + GPR13Handle=GetDlgItem(hDlg,IDC_GPR13); + GPR14Handle=GetDlgItem(hDlg,IDC_GPR14); + GPR15Handle=GetDlgItem(hDlg,IDC_GPR15); + GPR16Handle=GetDlgItem(hDlg,IDC_GPR16); + GPR17Handle=GetDlgItem(hDlg,IDC_GPR17); + GPR18Handle=GetDlgItem(hDlg,IDC_GPR18); + GPR19Handle=GetDlgItem(hDlg,IDC_GPR19); + GPR20Handle=GetDlgItem(hDlg,IDC_GPR20); + GPR21Handle=GetDlgItem(hDlg,IDC_GPR21); + GPR22Handle=GetDlgItem(hDlg,IDC_GPR22); + GPR23Handle=GetDlgItem(hDlg,IDC_GPR23); + GPR24Handle=GetDlgItem(hDlg,IDC_GPR24); + GPR25Handle=GetDlgItem(hDlg,IDC_GPR25); + GPR26Handle=GetDlgItem(hDlg,IDC_GPR26); + GPR27Handle=GetDlgItem(hDlg,IDC_GPR27); + GPR28Handle=GetDlgItem(hDlg,IDC_GPR28); + GPR29Handle=GetDlgItem(hDlg,IDC_GPR29); + GPR30Handle=GetDlgItem(hDlg,IDC_GPR30); + GPR31Handle=GetDlgItem(hDlg,IDC_GPR31); + GPRPCHandle=GetDlgItem(hDlg,IDC_GPR_PC); + GPRHIHandle=GetDlgItem(hDlg,IDC_GPR_HI); + GPRLOHandle=GetDlgItem(hDlg,IDC_GPR_LO); + UpdateRegs(); + return (TRUE); + break; + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case (IDOK || IDCANCEL): + EndDialog(hDlg,TRUE); + return(TRUE); + break; + + } + break; + } + + return(FALSE); +} +LRESULT CALLBACK COP0reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_INITDIALOG: + COP00Handle=GetDlgItem(hDlg,IDC_CP00); + COP01Handle=GetDlgItem(hDlg,IDC_CP01); + COP02Handle=GetDlgItem(hDlg,IDC_CP02); + COP03Handle=GetDlgItem(hDlg,IDC_CP03); + COP04Handle=GetDlgItem(hDlg,IDC_CP04); + COP05Handle=GetDlgItem(hDlg,IDC_CP05); + COP06Handle=GetDlgItem(hDlg,IDC_CP06); + COP07Handle=GetDlgItem(hDlg,IDC_CP07); + COP08Handle=GetDlgItem(hDlg,IDC_CP08); + COP09Handle=GetDlgItem(hDlg,IDC_CP09); + COP010Handle=GetDlgItem(hDlg,IDC_CP010); + COP011Handle=GetDlgItem(hDlg,IDC_CP011); + COP012Handle=GetDlgItem(hDlg,IDC_CP012); + COP013Handle=GetDlgItem(hDlg,IDC_CP013); + COP014Handle=GetDlgItem(hDlg,IDC_CP014); + COP015Handle=GetDlgItem(hDlg,IDC_CP015); + COP016Handle=GetDlgItem(hDlg,IDC_CP016); + COP017Handle=GetDlgItem(hDlg,IDC_CP017); + COP018Handle=GetDlgItem(hDlg,IDC_CP018); + COP019Handle=GetDlgItem(hDlg,IDC_CP019); + COP020Handle=GetDlgItem(hDlg,IDC_CP020); + COP021Handle=GetDlgItem(hDlg,IDC_CP021); + COP022Handle=GetDlgItem(hDlg,IDC_CP022); + COP023Handle=GetDlgItem(hDlg,IDC_CP023); + COP024Handle=GetDlgItem(hDlg,IDC_CP024); + COP025Handle=GetDlgItem(hDlg,IDC_CP025); + COP026Handle=GetDlgItem(hDlg,IDC_CP026); + COP027Handle=GetDlgItem(hDlg,IDC_CP027); + COP028Handle=GetDlgItem(hDlg,IDC_CP028); + COP029Handle=GetDlgItem(hDlg,IDC_CP029); + COP030Handle=GetDlgItem(hDlg,IDC_CP030); + COP031Handle=GetDlgItem(hDlg,IDC_CP031); + UpdateRegs(); + return (TRUE); + break; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case (IDOK || IDCANCEL): + EndDialog(hDlg,TRUE); + return(TRUE); + break; + + } + break; + } + + return(FALSE); +} +LRESULT CALLBACK COP1reg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_INITDIALOG: + COP10Handle=GetDlgItem(hDlg,IDC_FP0); + COP11Handle=GetDlgItem(hDlg,IDC_FP1); + COP12Handle=GetDlgItem(hDlg,IDC_FP2); + COP13Handle=GetDlgItem(hDlg,IDC_FP3); + COP14Handle=GetDlgItem(hDlg,IDC_FP4); + COP15Handle=GetDlgItem(hDlg,IDC_FP5); + COP16Handle=GetDlgItem(hDlg,IDC_FP6); + COP17Handle=GetDlgItem(hDlg,IDC_FP7); + COP18Handle=GetDlgItem(hDlg,IDC_FP8); + COP19Handle=GetDlgItem(hDlg,IDC_FP9); + COP110Handle=GetDlgItem(hDlg,IDC_FP10); + COP111Handle=GetDlgItem(hDlg,IDC_FP11); + COP112Handle=GetDlgItem(hDlg,IDC_FP12); + COP113Handle=GetDlgItem(hDlg,IDC_FP13); + COP114Handle=GetDlgItem(hDlg,IDC_FP14); + COP115Handle=GetDlgItem(hDlg,IDC_FP15); + COP116Handle=GetDlgItem(hDlg,IDC_FP16); + COP117Handle=GetDlgItem(hDlg,IDC_FP17); + COP118Handle=GetDlgItem(hDlg,IDC_FP18); + COP119Handle=GetDlgItem(hDlg,IDC_FP19); + COP120Handle=GetDlgItem(hDlg,IDC_FP20); + COP121Handle=GetDlgItem(hDlg,IDC_FP21); + COP122Handle=GetDlgItem(hDlg,IDC_FP22); + COP123Handle=GetDlgItem(hDlg,IDC_FP23); + COP124Handle=GetDlgItem(hDlg,IDC_FP24); + COP125Handle=GetDlgItem(hDlg,IDC_FP25); + COP126Handle=GetDlgItem(hDlg,IDC_FP26); + COP127Handle=GetDlgItem(hDlg,IDC_FP27); + COP128Handle=GetDlgItem(hDlg,IDC_FP28); + COP129Handle=GetDlgItem(hDlg,IDC_FP29); + COP130Handle=GetDlgItem(hDlg,IDC_FP30); + COP131Handle=GetDlgItem(hDlg,IDC_FP31); + COP1C0Handle=GetDlgItem(hDlg,IDC_FCR0); + COP1C1Handle=GetDlgItem(hDlg,IDC_FCR31); + COP1ACCHandle=GetDlgItem(hDlg,IDC_FPU_ACC); + UpdateRegs(); + return (TRUE); + break; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case (IDOK || IDCANCEL): + EndDialog(hDlg,TRUE); + return(TRUE); + break; + + } + break; + } + + return(FALSE); +} + +LRESULT CALLBACK COP2Freg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_INITDIALOG: + VU0F00Handle=GetDlgItem(hDlg,IDC_VU0_VF00); + VU0F01Handle=GetDlgItem(hDlg,IDC_VU0_VF01); + VU0F02Handle=GetDlgItem(hDlg,IDC_VU0_VF02); + VU0F03Handle=GetDlgItem(hDlg,IDC_VU0_VF03); + VU0F04Handle=GetDlgItem(hDlg,IDC_VU0_VF04); + VU0F05Handle=GetDlgItem(hDlg,IDC_VU0_VF05); + VU0F06Handle=GetDlgItem(hDlg,IDC_VU0_VF06); + VU0F07Handle=GetDlgItem(hDlg,IDC_VU0_VF07); + VU0F08Handle=GetDlgItem(hDlg,IDC_VU0_VF08); + VU0F09Handle=GetDlgItem(hDlg,IDC_VU0_VF09); + VU0F10Handle=GetDlgItem(hDlg,IDC_VU0_VF10); + VU0F11Handle=GetDlgItem(hDlg,IDC_VU0_VF11); + VU0F12Handle=GetDlgItem(hDlg,IDC_VU0_VF12); + VU0F13Handle=GetDlgItem(hDlg,IDC_VU0_VF13); + VU0F14Handle=GetDlgItem(hDlg,IDC_VU0_VF14); + VU0F15Handle=GetDlgItem(hDlg,IDC_VU0_VF15); + VU0F16Handle=GetDlgItem(hDlg,IDC_VU0_VF16); + VU0F17Handle=GetDlgItem(hDlg,IDC_VU0_VF17); + VU0F18Handle=GetDlgItem(hDlg,IDC_VU0_VF18); + VU0F19Handle=GetDlgItem(hDlg,IDC_VU0_VF19); + VU0F20Handle=GetDlgItem(hDlg,IDC_VU0_VF20); + VU0F21Handle=GetDlgItem(hDlg,IDC_VU0_VF21); + VU0F22Handle=GetDlgItem(hDlg,IDC_VU0_VF22); + VU0F23Handle=GetDlgItem(hDlg,IDC_VU0_VF23); + VU0F24Handle=GetDlgItem(hDlg,IDC_VU0_VF24); + VU0F25Handle=GetDlgItem(hDlg,IDC_VU0_VF25); + VU0F26Handle=GetDlgItem(hDlg,IDC_VU0_VF26); + VU0F27Handle=GetDlgItem(hDlg,IDC_VU0_VF27); + VU0F28Handle=GetDlgItem(hDlg,IDC_VU0_VF28); + VU0F29Handle=GetDlgItem(hDlg,IDC_VU0_VF29); + VU0F30Handle=GetDlgItem(hDlg,IDC_VU0_VF30); + VU0F31Handle=GetDlgItem(hDlg,IDC_VU0_VF31); + UpdateRegs(); + return (TRUE); + break; + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case (IDOK || IDCANCEL): + EndDialog(hDlg,TRUE); + return(TRUE); + break; + + } + break; + } + + return(FALSE); +} +LRESULT CALLBACK COP2Creg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_INITDIALOG: + VU0C00Handle=GetDlgItem(hDlg,IDC_VU0_VI00); + VU0C01Handle=GetDlgItem(hDlg,IDC_VU0_VI01); + VU0C02Handle=GetDlgItem(hDlg,IDC_VU0_VI02); + VU0C03Handle=GetDlgItem(hDlg,IDC_VU0_VI03); + VU0C04Handle=GetDlgItem(hDlg,IDC_VU0_VI04); + VU0C05Handle=GetDlgItem(hDlg,IDC_VU0_VI05); + VU0C06Handle=GetDlgItem(hDlg,IDC_VU0_VI06); + VU0C07Handle=GetDlgItem(hDlg,IDC_VU0_VI07); + VU0C08Handle=GetDlgItem(hDlg,IDC_VU0_VI08); + VU0C09Handle=GetDlgItem(hDlg,IDC_VU0_VI09); + VU0C10Handle=GetDlgItem(hDlg,IDC_VU0_VI10); + VU0C11Handle=GetDlgItem(hDlg,IDC_VU0_VI11); + VU0C12Handle=GetDlgItem(hDlg,IDC_VU0_VI12); + VU0C13Handle=GetDlgItem(hDlg,IDC_VU0_VI13); + VU0C14Handle=GetDlgItem(hDlg,IDC_VU0_VI14); + VU0C15Handle=GetDlgItem(hDlg,IDC_VU0_VI15); + VU0C16Handle=GetDlgItem(hDlg,IDC_VU0_VI16); + VU0C17Handle=GetDlgItem(hDlg,IDC_VU0_VI17); + VU0C18Handle=GetDlgItem(hDlg,IDC_VU0_VI18); + VU0C19Handle=GetDlgItem(hDlg,IDC_VU0_VI19); + VU0C20Handle=GetDlgItem(hDlg,IDC_VU0_VI20); + VU0C21Handle=GetDlgItem(hDlg,IDC_VU0_VI21); + VU0C22Handle=GetDlgItem(hDlg,IDC_VU0_VI22); + VU0C23Handle=GetDlgItem(hDlg,IDC_VU0_VI23); + VU0C24Handle=GetDlgItem(hDlg,IDC_VU0_VI24); + VU0C25Handle=GetDlgItem(hDlg,IDC_VU0_VI25); + VU0C26Handle=GetDlgItem(hDlg,IDC_VU0_VI26); + VU0C27Handle=GetDlgItem(hDlg,IDC_VU0_VI27); + VU0C28Handle=GetDlgItem(hDlg,IDC_VU0_VI28); + VU0C29Handle=GetDlgItem(hDlg,IDC_VU0_VI29); + VU0C30Handle=GetDlgItem(hDlg,IDC_VU0_VI30); + VU0C31Handle=GetDlgItem(hDlg,IDC_VU0_VI31); + VU0ACCHandle=GetDlgItem(hDlg,IDC_VU0_ACC); + UpdateRegs(); + return (TRUE); + break; + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case (IDOK || IDCANCEL): + EndDialog(hDlg,TRUE); + return(TRUE); + break; + + } + break; + } + + return(FALSE); +} + + +LRESULT CALLBACK VU1Freg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_INITDIALOG: + VU1F00Handle=GetDlgItem(hDlg,IDC_VU1_VF00); + VU1F01Handle=GetDlgItem(hDlg,IDC_VU1_VF01); + VU1F02Handle=GetDlgItem(hDlg,IDC_VU1_VF02); + VU1F03Handle=GetDlgItem(hDlg,IDC_VU1_VF03); + VU1F04Handle=GetDlgItem(hDlg,IDC_VU1_VF04); + VU1F05Handle=GetDlgItem(hDlg,IDC_VU1_VF05); + VU1F06Handle=GetDlgItem(hDlg,IDC_VU1_VF06); + VU1F07Handle=GetDlgItem(hDlg,IDC_VU1_VF07); + VU1F08Handle=GetDlgItem(hDlg,IDC_VU1_VF08); + VU1F09Handle=GetDlgItem(hDlg,IDC_VU1_VF09); + VU1F10Handle=GetDlgItem(hDlg,IDC_VU1_VF10); + VU1F11Handle=GetDlgItem(hDlg,IDC_VU1_VF11); + VU1F12Handle=GetDlgItem(hDlg,IDC_VU1_VF12); + VU1F13Handle=GetDlgItem(hDlg,IDC_VU1_VF13); + VU1F14Handle=GetDlgItem(hDlg,IDC_VU1_VF14); + VU1F15Handle=GetDlgItem(hDlg,IDC_VU1_VF15); + VU1F16Handle=GetDlgItem(hDlg,IDC_VU1_VF16); + VU1F17Handle=GetDlgItem(hDlg,IDC_VU1_VF17); + VU1F18Handle=GetDlgItem(hDlg,IDC_VU1_VF18); + VU1F19Handle=GetDlgItem(hDlg,IDC_VU1_VF19); + VU1F20Handle=GetDlgItem(hDlg,IDC_VU1_VF20); + VU1F21Handle=GetDlgItem(hDlg,IDC_VU1_VF21); + VU1F22Handle=GetDlgItem(hDlg,IDC_VU1_VF22); + VU1F23Handle=GetDlgItem(hDlg,IDC_VU1_VF23); + VU1F24Handle=GetDlgItem(hDlg,IDC_VU1_VF24); + VU1F25Handle=GetDlgItem(hDlg,IDC_VU1_VF25); + VU1F26Handle=GetDlgItem(hDlg,IDC_VU1_VF26); + VU1F27Handle=GetDlgItem(hDlg,IDC_VU1_VF27); + VU1F28Handle=GetDlgItem(hDlg,IDC_VU1_VF28); + VU1F29Handle=GetDlgItem(hDlg,IDC_VU1_VF29); + VU1F30Handle=GetDlgItem(hDlg,IDC_VU1_VF30); + VU1F31Handle=GetDlgItem(hDlg,IDC_VU1_VF31); + UpdateRegs(); + return (TRUE); + break; + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case (IDOK || IDCANCEL): + EndDialog(hDlg,TRUE); + return(TRUE); + break; + + } + break; + } + + return(FALSE); +} +LRESULT CALLBACK VU1Creg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_INITDIALOG: + VU1C00Handle=GetDlgItem(hDlg,IDC_VU1_VI00); + VU1C01Handle=GetDlgItem(hDlg,IDC_VU1_VI01); + VU1C02Handle=GetDlgItem(hDlg,IDC_VU1_VI02); + VU1C03Handle=GetDlgItem(hDlg,IDC_VU1_VI03); + VU1C04Handle=GetDlgItem(hDlg,IDC_VU1_VI04); + VU1C05Handle=GetDlgItem(hDlg,IDC_VU1_VI05); + VU1C06Handle=GetDlgItem(hDlg,IDC_VU1_VI06); + VU1C07Handle=GetDlgItem(hDlg,IDC_VU1_VI07); + VU1C08Handle=GetDlgItem(hDlg,IDC_VU1_VI08); + VU1C09Handle=GetDlgItem(hDlg,IDC_VU1_VI09); + VU1C10Handle=GetDlgItem(hDlg,IDC_VU1_VI10); + VU1C11Handle=GetDlgItem(hDlg,IDC_VU1_VI11); + VU1C12Handle=GetDlgItem(hDlg,IDC_VU1_VI12); + VU1C13Handle=GetDlgItem(hDlg,IDC_VU1_VI13); + VU1C14Handle=GetDlgItem(hDlg,IDC_VU1_VI14); + VU1C15Handle=GetDlgItem(hDlg,IDC_VU1_VI15); + VU1C16Handle=GetDlgItem(hDlg,IDC_VU1_VI16); + VU1C17Handle=GetDlgItem(hDlg,IDC_VU1_VI17); + VU1C18Handle=GetDlgItem(hDlg,IDC_VU1_VI18); + VU1C19Handle=GetDlgItem(hDlg,IDC_VU1_VI19); + VU1C20Handle=GetDlgItem(hDlg,IDC_VU1_VI20); + VU1C21Handle=GetDlgItem(hDlg,IDC_VU1_VI21); + VU1C22Handle=GetDlgItem(hDlg,IDC_VU1_VI22); + VU1C23Handle=GetDlgItem(hDlg,IDC_VU1_VI23); + VU1C24Handle=GetDlgItem(hDlg,IDC_VU1_VI24); + VU1C25Handle=GetDlgItem(hDlg,IDC_VU1_VI25); + VU1C26Handle=GetDlgItem(hDlg,IDC_VU1_VI26); + VU1C27Handle=GetDlgItem(hDlg,IDC_VU1_VI27); + VU1C28Handle=GetDlgItem(hDlg,IDC_VU1_VI28); + VU1C29Handle=GetDlgItem(hDlg,IDC_VU1_VI29); + VU1C30Handle=GetDlgItem(hDlg,IDC_VU1_VI30); + VU1C31Handle=GetDlgItem(hDlg,IDC_VU1_VI31); + VU1ACCHandle=GetDlgItem(hDlg,IDC_VU1_ACC); + UpdateRegs(); + return (TRUE); + break; + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case (IDOK || IDCANCEL): + EndDialog(hDlg,TRUE); + return(TRUE); + break; + + } + break; + } + + return(FALSE); +} + +void UpdateRegs(void) +{ + + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[0]); + SendMessage(IOPGPR0Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[1]); + SendMessage(IOPGPR1Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[2]); + SendMessage(IOPGPR2Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[3]); + SendMessage(IOPGPR3Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[4]); + SendMessage(IOPGPR4Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[5]); + SendMessage(IOPGPR5Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[6]); + SendMessage(IOPGPR6Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[7]); + SendMessage(IOPGPR7Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[8]); + SendMessage(IOPGPR8Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[9]); + SendMessage(IOPGPR9Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[10]); + SendMessage(IOPGPR10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[11]); + SendMessage(IOPGPR11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[12]); + SendMessage(IOPGPR12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[13]); + SendMessage(IOPGPR13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[14]); + SendMessage(IOPGPR14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[15]); + SendMessage(IOPGPR15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[16]); + SendMessage(IOPGPR16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[17]); + SendMessage(IOPGPR17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[18]); + SendMessage(IOPGPR18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[19]); + SendMessage(IOPGPR19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[20]); + SendMessage(IOPGPR20Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[21]); + SendMessage(IOPGPR21Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[22]); + SendMessage(IOPGPR22Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[23]); + SendMessage(IOPGPR23Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[24]); + SendMessage(IOPGPR24Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[25]); + SendMessage(IOPGPR25Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[26]); + SendMessage(IOPGPR26Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[27]); + SendMessage(IOPGPR27Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[28]); + SendMessage(IOPGPR28Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[29]); + SendMessage(IOPGPR29Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[30]); + SendMessage(IOPGPR30Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[31]); + SendMessage(IOPGPR31Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",psxRegs.pc ); + SendMessage(IOPGPRPCHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[32]); + SendMessage(IOPGPRHIHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X\0",psxRegs.GPR.r[33]); + SendMessage(IOPGPRLOHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[0].UL[3],cpuRegs.GPR.r[0].UL[2],cpuRegs.GPR.r[0].UL[1],cpuRegs.GPR.r[0].UL[0] ); + SendMessage(GPR0Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[1].UL[3], cpuRegs.GPR.r[1].UL[2],cpuRegs.GPR.r[1].UL[1],cpuRegs.GPR.r[1].UL[0] ); + SendMessage(GPR1Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[2].UL[3],cpuRegs.GPR.r[2].UL[2], cpuRegs.GPR.r[2].UL[1],cpuRegs.GPR.r[2].UL[0]); + SendMessage(GPR2Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[3].UL[3],cpuRegs.GPR.r[3].UL[2], cpuRegs.GPR.r[3].UL[1],cpuRegs.GPR.r[3].UL[0] ); + SendMessage(GPR3Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[4].UL[3],cpuRegs.GPR.r[4].UL[2], cpuRegs.GPR.r[4].UL[1],cpuRegs.GPR.r[4].UL[0] ); + SendMessage(GPR4Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[5].UL[3],cpuRegs.GPR.r[5].UL[2],cpuRegs.GPR.r[5].UL[1], cpuRegs.GPR.r[5].UL[0] ); + SendMessage(GPR5Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[6].UL[3],cpuRegs.GPR.r[6].UL[2], cpuRegs.GPR.r[6].UL[1], cpuRegs.GPR.r[6].UL[0]); + SendMessage(GPR6Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[7].UL[3], cpuRegs.GPR.r[7].UL[2],cpuRegs.GPR.r[7].UL[1],cpuRegs.GPR.r[7].UL[0] ); + SendMessage(GPR7Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[8].UL[3],cpuRegs.GPR.r[8].UL[2],cpuRegs.GPR.r[8].UL[1],cpuRegs.GPR.r[8].UL[0] ); + SendMessage(GPR8Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[9].UL[3],cpuRegs.GPR.r[9].UL[2],cpuRegs.GPR.r[9].UL[1], cpuRegs.GPR.r[9].UL[0] ); + SendMessage(GPR9Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[10].UL[3],cpuRegs.GPR.r[10].UL[2],cpuRegs.GPR.r[10].UL[1],cpuRegs.GPR.r[10].UL[0] ); + SendMessage(GPR10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[11].UL[3],cpuRegs.GPR.r[11].UL[2],cpuRegs.GPR.r[11].UL[1],cpuRegs.GPR.r[11].UL[0] ); + SendMessage(GPR11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[12].UL[3],cpuRegs.GPR.r[12].UL[2],cpuRegs.GPR.r[12].UL[1],cpuRegs.GPR.r[12].UL[0] ); + SendMessage(GPR12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[13].UL[3],cpuRegs.GPR.r[13].UL[2],cpuRegs.GPR.r[13].UL[1],cpuRegs.GPR.r[13].UL[0] ); + SendMessage(GPR13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[14].UL[3],cpuRegs.GPR.r[14].UL[2],cpuRegs.GPR.r[14].UL[1],cpuRegs.GPR.r[14].UL[0] ); + SendMessage(GPR14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[15].UL[3],cpuRegs.GPR.r[15].UL[2],cpuRegs.GPR.r[15].UL[1],cpuRegs.GPR.r[15].UL[0] ); + SendMessage(GPR15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[16].UL[3],cpuRegs.GPR.r[16].UL[2],cpuRegs.GPR.r[16].UL[1],cpuRegs.GPR.r[16].UL[0] ); + SendMessage(GPR16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[17].UL[3],cpuRegs.GPR.r[17].UL[2],cpuRegs.GPR.r[17].UL[1],cpuRegs.GPR.r[17].UL[0] ); + SendMessage(GPR17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[18].UL[3],cpuRegs.GPR.r[18].UL[2],cpuRegs.GPR.r[18].UL[1],cpuRegs.GPR.r[18].UL[0] ); + SendMessage(GPR18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[19].UL[3],cpuRegs.GPR.r[19].UL[2],cpuRegs.GPR.r[19].UL[1],cpuRegs.GPR.r[19].UL[0] ); + SendMessage(GPR19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[20].UL[3],cpuRegs.GPR.r[20].UL[2],cpuRegs.GPR.r[20].UL[1],cpuRegs.GPR.r[20].UL[0] ); + SendMessage(GPR20Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[21].UL[3],cpuRegs.GPR.r[21].UL[2],cpuRegs.GPR.r[21].UL[1],cpuRegs.GPR.r[21].UL[0] ); + SendMessage(GPR21Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[22].UL[3],cpuRegs.GPR.r[22].UL[2],cpuRegs.GPR.r[22].UL[1],cpuRegs.GPR.r[22].UL[0] ); + SendMessage(GPR22Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[23].UL[3],cpuRegs.GPR.r[23].UL[2],cpuRegs.GPR.r[23].UL[1],cpuRegs.GPR.r[23].UL[0] ); + SendMessage(GPR23Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[24].UL[3],cpuRegs.GPR.r[24].UL[2],cpuRegs.GPR.r[24].UL[1],cpuRegs.GPR.r[24].UL[0] ); + SendMessage(GPR24Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[25].UL[3],cpuRegs.GPR.r[25].UL[2],cpuRegs.GPR.r[25].UL[1],cpuRegs.GPR.r[25].UL[0] ); + SendMessage(GPR25Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[26].UL[3],cpuRegs.GPR.r[26].UL[2],cpuRegs.GPR.r[26].UL[1],cpuRegs.GPR.r[26].UL[0] ); + SendMessage(GPR26Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[27].UL[3],cpuRegs.GPR.r[27].UL[2],cpuRegs.GPR.r[27].UL[1],cpuRegs.GPR.r[27].UL[0] ); + SendMessage(GPR27Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[28].UL[3],cpuRegs.GPR.r[28].UL[2],cpuRegs.GPR.r[28].UL[1],cpuRegs.GPR.r[28].UL[0] ); + SendMessage(GPR28Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[29].UL[3],cpuRegs.GPR.r[29].UL[2],cpuRegs.GPR.r[29].UL[1],cpuRegs.GPR.r[29].UL[0] ); + SendMessage(GPR29Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[30].UL[3],cpuRegs.GPR.r[30].UL[2],cpuRegs.GPR.r[30].UL[1],cpuRegs.GPR.r[30].UL[0] ); + SendMessage(GPR30Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.GPR.r[31].UL[3],cpuRegs.GPR.r[31].UL[2],cpuRegs.GPR.r[31].UL[1],cpuRegs.GPR.r[31].UL[0] ); + SendMessage(GPR31Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.pc ); + SendMessage(GPRPCHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0",cpuRegs.HI.UL[3],cpuRegs.HI.UL[2] ,cpuRegs.HI.UL[1] ,cpuRegs.HI.UL[0] ); + SendMessage(GPRHIHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"0x%08X_%08X_%08X_%08X\0\0",cpuRegs.LO.UL[3],cpuRegs.LO.UL[2],cpuRegs.LO.UL[1],cpuRegs.LO.UL[0] ); + SendMessage(GPRLOHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[0] ); + SendMessage(COP00Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[1]); + SendMessage(COP01Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[2]); + SendMessage(COP02Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[3]); + SendMessage(COP03Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[4]); + SendMessage(COP04Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[5]); + SendMessage(COP05Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[6]); + SendMessage(COP06Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[7]); + SendMessage(COP07Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[8]); + SendMessage(COP08Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[9]); + SendMessage(COP09Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[10]); + SendMessage(COP010Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[11]); + SendMessage(COP011Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[12]); + SendMessage(COP012Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[13]); + SendMessage(COP013Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[14]); + SendMessage(COP014Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[15]); + SendMessage(COP015Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[16]); + SendMessage(COP016Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[17]); + SendMessage(COP017Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[18]); + SendMessage(COP018Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[19]); + SendMessage(COP019Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[20]); + SendMessage(COP020Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[21]); + SendMessage(COP021Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[22]); + SendMessage(COP022Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[23]); + SendMessage(COP023Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[24]); + SendMessage(COP024Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[25]); + SendMessage(COP025Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[26]); + SendMessage(COP026Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[27]); + SendMessage(COP027Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[28]); + SendMessage(COP028Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[29]); + SendMessage(COP029Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[30]); + SendMessage(COP030Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",cpuRegs.CP0.r[31]); + SendMessage(COP031Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + + sprintf(text1,"%f",fpuRegs.fpr[0].f ); + SendMessage(COP10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[1].f); + SendMessage(COP11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[2].f); + SendMessage(COP12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[3].f); + SendMessage(COP13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[4].f); + SendMessage(COP14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[5].f); + SendMessage(COP15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[6].f); + SendMessage(COP16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[7].f); + SendMessage(COP17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[8].f); + SendMessage(COP18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[9].f); + SendMessage(COP19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[10].f); + SendMessage(COP110Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[11].f); + SendMessage(COP111Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[12].f); + SendMessage(COP112Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[13].f); + SendMessage(COP113Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[14].f); + SendMessage(COP114Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[15].f); + SendMessage(COP115Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[16].f); + SendMessage(COP116Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[17].f); + SendMessage(COP117Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[18].f); + SendMessage(COP118Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[19].f); + SendMessage(COP119Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[20].f); + SendMessage(COP120Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[21].f); + SendMessage(COP121Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[22].f); + SendMessage(COP122Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[23].f); + SendMessage(COP123Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[24].f); + SendMessage(COP124Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[25].f); + SendMessage(COP125Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[26].f); + SendMessage(COP126Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[27].f); + SendMessage(COP127Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[28].f); + SendMessage(COP128Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[29].f); + SendMessage(COP129Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[30].f); + SendMessage(COP130Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.fpr[31].f); + SendMessage(COP131Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",fpuRegs.fprc[0]); + SendMessage(COP1C0Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",fpuRegs.fprc[31]); + SendMessage(COP1C1Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f",fpuRegs.ACC.f); + SendMessage(COP1ACCHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + + + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[0].f.w,VU0.VF[0].f.z,VU0.VF[0].f.y,VU0.VF[0].f.x ); + SendMessage(VU0F00Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[1].f.w,VU0.VF[1].f.z,VU0.VF[1].f.y,VU0.VF[1].f.x ); + SendMessage(VU0F01Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[2].f.w,VU0.VF[2].f.z,VU0.VF[2].f.y,VU0.VF[2].f.x ); + SendMessage(VU0F02Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[3].f.w,VU0.VF[3].f.z,VU0.VF[3].f.y,VU0.VF[3].f.x ); + SendMessage(VU0F03Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[4].f.w,VU0.VF[4].f.z,VU0.VF[4].f.y,VU0.VF[4].f.x ); + SendMessage(VU0F04Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[5].f.w,VU0.VF[5].f.z,VU0.VF[5].f.y,VU0.VF[5].f.x); + SendMessage(VU0F05Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[6].f.w,VU0.VF[6].f.z,VU0.VF[6].f.y,VU0.VF[6].f.x ); + SendMessage(VU0F06Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[7].f.w,VU0.VF[7].f.z,VU0.VF[7].f.y,VU0.VF[7].f.x ); + SendMessage(VU0F07Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[8].f.w,VU0.VF[8].f.z,VU0.VF[8].f.y,VU0.VF[8].f.x ); + SendMessage(VU0F08Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[9].f.w,VU0.VF[9].f.z,VU0.VF[9].f.y,VU0.VF[9].f.x ); + SendMessage(VU0F09Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[10].f.w,VU0.VF[10].f.z,VU0.VF[10].f.y,VU0.VF[10].f.x ); + SendMessage(VU0F10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[11].f.w,VU0.VF[11].f.z,VU0.VF[11].f.y,VU0.VF[11].f.x ); + SendMessage(VU0F11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[12].f.w,VU0.VF[12].f.z,VU0.VF[12].f.y,VU0.VF[12].f.x ); + SendMessage(VU0F12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[13].f.w,VU0.VF[13].f.z,VU0.VF[13].f.y,VU0.VF[13].f.x ); + SendMessage(VU0F13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[14].f.w,VU0.VF[14].f.z,VU0.VF[14].f.y,VU0.VF[14].f.x ); + SendMessage(VU0F14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[15].f.w,VU0.VF[15].f.z,VU0.VF[15].f.y,VU0.VF[15].f.x ); + SendMessage(VU0F15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[16].f.w,VU0.VF[16].f.z,VU0.VF[16].f.y,VU0.VF[16].f.x ); + SendMessage(VU0F16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[17].f.w,VU0.VF[17].f.z,VU0.VF[17].f.y,VU0.VF[17].f.x ); + SendMessage(VU0F17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[18].f.w,VU0.VF[18].f.z,VU0.VF[18].f.y,VU0.VF[18].f.x ); + SendMessage(VU0F18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[19].f.w,VU0.VF[19].f.z,VU0.VF[19].f.y,VU0.VF[19].f.x ); + SendMessage(VU0F19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[20].f.w,VU0.VF[20].f.z,VU0.VF[20].f.y,VU0.VF[20].f.x ); + SendMessage(VU0F20Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[21].f.w,VU0.VF[21].f.z,VU0.VF[21].f.y,VU0.VF[21].f.x ); + SendMessage(VU0F21Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[22].f.w,VU0.VF[22].f.z,VU0.VF[22].f.y,VU0.VF[22].f.x ); + SendMessage(VU0F22Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[23].f.w,VU0.VF[23].f.z,VU0.VF[23].f.y,VU0.VF[23].f.x ); + SendMessage(VU0F23Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[24].f.w,VU0.VF[24].f.z,VU0.VF[24].f.y,VU0.VF[24].f.x ); + SendMessage(VU0F24Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[25].f.w,VU0.VF[25].f.z,VU0.VF[25].f.y,VU0.VF[25].f.x ); + SendMessage(VU0F25Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[26].f.w,VU0.VF[26].f.z,VU0.VF[26].f.y,VU0.VF[26].f.x ); + SendMessage(VU0F26Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[27].f.w,VU0.VF[27].f.z,VU0.VF[27].f.y,VU0.VF[27].f.x ); + SendMessage(VU0F27Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[28].f.w,VU0.VF[28].f.z,VU0.VF[28].f.y,VU0.VF[28].f.x ); + SendMessage(VU0F28Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[29].f.w,VU0.VF[29].f.z,VU0.VF[29].f.y,VU0.VF[29].f.x ); + SendMessage(VU0F29Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[30].f.w,VU0.VF[30].f.z,VU0.VF[30].f.y,VU0.VF[30].f.x ); + SendMessage(VU0F30Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU0.VF[31].f.w,VU0.VF[31].f.z,VU0.VF[31].f.y,VU0.VF[31].f.x ); + SendMessage(VU0F31Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + + + wsprintf(text1,"%x",VU0.VI[0] ); + SendMessage(VU0C00Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[1]); + SendMessage(VU0C01Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[2]); + SendMessage(VU0C02Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[3]); + SendMessage(VU0C03Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[4]); + SendMessage(VU0C04Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[5]); + SendMessage(VU0C05Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[6]); + SendMessage(VU0C06Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[7]); + SendMessage(VU0C07Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[8]); + SendMessage(VU0C08Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[9]); + SendMessage(VU0C09Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[10]); + SendMessage(VU0C10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[11]); + SendMessage(VU0C11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[12]); + SendMessage(VU0C12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[13]); + SendMessage(VU0C13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[14]); + SendMessage(VU0C14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[15]); + SendMessage(VU0C15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[16]); + SendMessage(VU0C16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[17]); + SendMessage(VU0C17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[18]); + SendMessage(VU0C18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[19]); + SendMessage(VU0C19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[20]); + SendMessage(VU0C20Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[21]); + SendMessage(VU0C21Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[22]); + SendMessage(VU0C22Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[23]); + SendMessage(VU0C23Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[24]); + SendMessage(VU0C24Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[25]); + SendMessage(VU0C25Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[26]); + SendMessage(VU0C26Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[27]); + SendMessage(VU0C27Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[28]); + SendMessage(VU0C28Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[29]); + SendMessage(VU0C29Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[30]); + SendMessage(VU0C30Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU0.VI[31]); + SendMessage(VU0C31Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + + sprintf(text1,"%f_%f_%f_%f\0",VU0.ACC.f.w,VU0.ACC.f.z,VU0.ACC.f.y,VU0.ACC.f.x ); + SendMessage(VU0ACCHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + + + + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[0].f.w,VU1.VF[0].f.z,VU1.VF[0].f.y,VU1.VF[0].f.x ); + SendMessage(VU1F00Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[1].f.w,VU1.VF[1].f.z,VU1.VF[1].f.y,VU1.VF[1].f.x ); + SendMessage(VU1F01Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[2].f.w,VU1.VF[2].f.z,VU1.VF[2].f.y,VU1.VF[2].f.x ); + SendMessage(VU1F02Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[3].f.w,VU1.VF[3].f.z,VU1.VF[3].f.y,VU1.VF[3].f.x ); + SendMessage(VU1F03Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[4].f.w,VU1.VF[4].f.z,VU1.VF[4].f.y,VU1.VF[4].f.x ); + SendMessage(VU1F04Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[5].f.w,VU1.VF[5].f.z,VU1.VF[5].f.y,VU1.VF[5].f.x); + SendMessage(VU1F05Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[6].f.w,VU1.VF[6].f.z,VU1.VF[6].f.y,VU1.VF[6].f.x ); + SendMessage(VU1F06Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[7].f.w,VU1.VF[7].f.z,VU1.VF[7].f.y,VU1.VF[7].f.x ); + SendMessage(VU1F07Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[8].f.w,VU1.VF[8].f.z,VU1.VF[8].f.y,VU1.VF[8].f.x ); + SendMessage(VU1F08Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[9].f.w,VU1.VF[9].f.z,VU1.VF[9].f.y,VU1.VF[9].f.x ); + SendMessage(VU1F09Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[10].f.w,VU1.VF[10].f.z,VU1.VF[10].f.y,VU1.VF[10].f.x ); + SendMessage(VU1F10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[11].f.w,VU1.VF[11].f.z,VU1.VF[11].f.y,VU1.VF[11].f.x ); + SendMessage(VU1F11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[12].f.w,VU1.VF[12].f.z,VU1.VF[12].f.y,VU1.VF[12].f.x ); + SendMessage(VU1F12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[13].f.w,VU1.VF[13].f.z,VU1.VF[13].f.y,VU1.VF[13].f.x ); + SendMessage(VU1F13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[14].f.w,VU1.VF[14].f.z,VU1.VF[14].f.y,VU1.VF[14].f.x ); + SendMessage(VU1F14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[15].f.w,VU1.VF[15].f.z,VU1.VF[15].f.y,VU1.VF[15].f.x ); + SendMessage(VU1F15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[16].f.w,VU1.VF[16].f.z,VU1.VF[16].f.y,VU1.VF[16].f.x ); + SendMessage(VU1F16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[17].f.w,VU1.VF[17].f.z,VU1.VF[17].f.y,VU1.VF[17].f.x ); + SendMessage(VU1F17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[18].f.w,VU1.VF[18].f.z,VU1.VF[18].f.y,VU1.VF[18].f.x ); + SendMessage(VU1F18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[19].f.w,VU1.VF[19].f.z,VU1.VF[19].f.y,VU1.VF[19].f.x ); + SendMessage(VU1F19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[20].f.w,VU1.VF[20].f.z,VU1.VF[20].f.y,VU1.VF[20].f.x ); + SendMessage(VU1F20Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[21].f.w,VU1.VF[21].f.z,VU1.VF[21].f.y,VU1.VF[21].f.x ); + SendMessage(VU1F21Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[22].f.w,VU1.VF[22].f.z,VU1.VF[22].f.y,VU1.VF[22].f.x ); + SendMessage(VU1F22Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[23].f.w,VU1.VF[23].f.z,VU1.VF[23].f.y,VU1.VF[23].f.x ); + SendMessage(VU1F23Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[24].f.w,VU1.VF[24].f.z,VU1.VF[24].f.y,VU1.VF[24].f.x ); + SendMessage(VU1F24Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[25].f.w,VU1.VF[25].f.z,VU1.VF[25].f.y,VU1.VF[25].f.x ); + SendMessage(VU1F25Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[26].f.w,VU1.VF[26].f.z,VU1.VF[26].f.y,VU1.VF[26].f.x ); + SendMessage(VU1F26Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[27].f.w,VU1.VF[27].f.z,VU1.VF[27].f.y,VU1.VF[27].f.x ); + SendMessage(VU1F27Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[28].f.w,VU1.VF[28].f.z,VU1.VF[28].f.y,VU1.VF[28].f.x ); + SendMessage(VU1F28Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[29].f.w,VU1.VF[29].f.z,VU1.VF[29].f.y,VU1.VF[29].f.x ); + SendMessage(VU1F29Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[30].f.w,VU1.VF[30].f.z,VU1.VF[30].f.y,VU1.VF[30].f.x ); + SendMessage(VU1F30Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + sprintf(text1,"%f_%f_%f_%f\0",VU1.VF[31].f.w,VU1.VF[31].f.z,VU1.VF[31].f.y,VU1.VF[31].f.x ); + SendMessage(VU1F31Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + + + wsprintf(text1,"%x",VU1.VI[0] ); + SendMessage(VU1C00Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[1]); + SendMessage(VU1C01Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[2]); + SendMessage(VU1C02Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[3]); + SendMessage(VU1C03Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[4]); + SendMessage(VU1C04Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[5]); + SendMessage(VU1C05Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[6]); + SendMessage(VU1C06Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[7]); + SendMessage(VU1C07Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[8]); + SendMessage(VU1C08Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[9]); + SendMessage(VU1C09Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[10]); + SendMessage(VU1C10Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[11]); + SendMessage(VU1C11Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[12]); + SendMessage(VU1C12Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[13]); + SendMessage(VU1C13Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[14]); + SendMessage(VU1C14Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[15]); + SendMessage(VU1C15Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[16]); + SendMessage(VU1C16Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[17]); + SendMessage(VU1C17Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[18]); + SendMessage(VU1C18Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[19]); + SendMessage(VU1C19Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[20]); + SendMessage(VU1C20Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[21]); + SendMessage(VU1C21Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[22]); + SendMessage(VU1C22Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[23]); + SendMessage(VU1C23Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[24]); + SendMessage(VU1C24Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[25]); + SendMessage(VU1C25Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[26]); + SendMessage(VU1C26Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[27]); + SendMessage(VU1C27Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[28]); + SendMessage(VU1C28Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[29]); + SendMessage(VU1C29Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[30]); + SendMessage(VU1C30Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + wsprintf(text1,"%x",VU1.VI[31]); + SendMessage(VU1C31Handle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + + sprintf(text1,"%f_%f_%f_%f\0",VU1.ACC.f.w,VU1.ACC.f.z,VU1.ACC.f.y,VU1.ACC.f.x ); + SendMessage(VU1ACCHandle,WM_SETTEXT,0,(LPARAM)(LPCTSTR)text1); + +} + + +void EEDumpRegs(FILE * fp) +{ + char text2[256]; + int i; + for(i = 0; i < 32; i++) + { + sprintf(text1,"%x_%x_%x_%x",cpuRegs.GPR.r[i].UL[3],cpuRegs.GPR.r[i].UL[2],cpuRegs.GPR.r[i].UL[1],cpuRegs.GPR.r[i].UL[0]); + sprintf(text2,"GPR Register %d: ",i+1); + fprintf(fp,text2); + fprintf(fp,text1); + fprintf(fp,"\n"); + } + sprintf(text1,"0x%x",cpuRegs.pc); + fprintf(fp,"PC Register : "); + fprintf(fp,text1); + fprintf(fp,"\n"); + sprintf(text1,"%x_%x_%x_%x",cpuRegs.HI.UL[3],cpuRegs.HI.UL[2],cpuRegs.HI.UL[1],cpuRegs.HI.UL[0]); + fprintf(fp,"GPR Register HI: "); + fprintf(fp,text1); + fprintf(fp,"\n"); + sprintf(text1,"%x_%x_%x_%x",cpuRegs.LO.UL[3],cpuRegs.LO.UL[2],cpuRegs.LO.UL[1],cpuRegs.LO.UL[0]); + fprintf(fp,"GPR Register LO: "); + fprintf(fp,text1); + fprintf(fp,"\n"); + + + for(i = 0; i < 32; i++) + { + sprintf(text1,"0x%x",cpuRegs.CP0.r[i]); + sprintf(text2,"COP0 Register %d: ",i+1); + fprintf(fp,text2); + fprintf(fp,text1); + fprintf(fp,"\n"); + } +} + +void IOPDumpRegs(FILE * fp) +{ + char text2[256]; + int i; + for(i = 0; i < 32; i++) + { + sprintf(text1,"%x",psxRegs.GPR.r[i]); + sprintf(text2,"GPR Register %d: ",i+1); + fprintf(fp,text2); + fprintf(fp,text1); + fprintf(fp,"\n"); + } + sprintf(text1,"0x%x",psxRegs.pc); + fprintf(fp,"PC Register : "); + fprintf(fp,text1); + fprintf(fp,"\n"); + sprintf(text1,"%x",psxRegs.GPR.r[32]); + fprintf(fp,"GPR Register HI: "); + fprintf(fp,text1); + fprintf(fp,"\n"); + sprintf(text1,"%x",psxRegs.GPR.r[33]); + fprintf(fp,"GPR Register LO: "); + fprintf(fp,text1); + fprintf(fp,"\n"); +} diff --git a/pcsx2/windows/HacksDlg.cpp b/pcsx2/windows/HacksDlg.cpp index 601f6d6a27..4857cd7121 100644 --- a/pcsx2/windows/HacksDlg.cpp +++ b/pcsx2/windows/HacksDlg.cpp @@ -1,74 +1,74 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" -#include "win32.h" - -BOOL APIENTRY HacksProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) { - case WM_INITDIALOG: - - CheckRadioButton( hDlg, IDC_EESYNC_DEFAULT, IDC_EESYNC3, IDC_EESYNC_DEFAULT + CHECK_EE_CYCLERATE ); - - if(CHECK_IOP_CYCLERATE) CheckDlgButton(hDlg, IDC_IOPSYNC, TRUE); - if(CHECK_WAITCYCLE_HACK) CheckDlgButton(hDlg, IDC_WAITCYCLES, TRUE); - if(CHECK_ESCAPE_HACK) CheckDlgButton(hDlg, IDC_ESCHACK, TRUE); - - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDOK: - { - int newhacks = 0; - for( int i=1; i<4; i++ ) - { - if( IsDlgButtonChecked(hDlg, IDC_EESYNC_DEFAULT+i) ) - { - newhacks = i; - break; - } - } - - newhacks |= IsDlgButtonChecked(hDlg, IDC_IOPSYNC) << 3; - newhacks |= IsDlgButtonChecked(hDlg, IDC_WAITCYCLES) << 4; - newhacks |= IsDlgButtonChecked(hDlg, IDC_ESCHACK) << 10; - - EndDialog(hDlg, TRUE); - - if( newhacks != Config.Hacks ) - { - SysRestorableReset(); - Config.Hacks = newhacks; - SaveConfig(); - } - } - return FALSE; - - case IDCANCEL: - EndDialog(hDlg, FALSE); - return FALSE; - } - return TRUE; - } - - return FALSE; -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" +#include "win32.h" + +BOOL APIENTRY HacksProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WM_INITDIALOG: + + CheckRadioButton( hDlg, IDC_EESYNC_DEFAULT, IDC_EESYNC3, IDC_EESYNC_DEFAULT + CHECK_EE_CYCLERATE ); + + if(CHECK_IOP_CYCLERATE) CheckDlgButton(hDlg, IDC_IOPSYNC, TRUE); + if(CHECK_WAITCYCLE_HACK) CheckDlgButton(hDlg, IDC_WAITCYCLES, TRUE); + if(CHECK_ESCAPE_HACK) CheckDlgButton(hDlg, IDC_ESCHACK, TRUE); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + { + int newhacks = 0; + for( int i=1; i<4; i++ ) + { + if( IsDlgButtonChecked(hDlg, IDC_EESYNC_DEFAULT+i) ) + { + newhacks = i; + break; + } + } + + newhacks |= IsDlgButtonChecked(hDlg, IDC_IOPSYNC) << 3; + newhacks |= IsDlgButtonChecked(hDlg, IDC_WAITCYCLES) << 4; + newhacks |= IsDlgButtonChecked(hDlg, IDC_ESCHACK) << 10; + + EndDialog(hDlg, TRUE); + + if( newhacks != Config.Hacks ) + { + SysRestorableReset(); + Config.Hacks = newhacks; + SaveConfig(); + } + } + return FALSE; + + case IDCANCEL: + EndDialog(hDlg, FALSE); + return FALSE; + } + return TRUE; + } + + return FALSE; +} diff --git a/pcsx2/windows/McdsDlg.c b/pcsx2/windows/McdsDlg.c index fd47b71c0c..5ebcb4c483 100644 --- a/pcsx2/windows/McdsDlg.c +++ b/pcsx2/windows/McdsDlg.c @@ -1,126 +1,126 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 -#include -#include -#include - -#include "Common.h" -#include "PsxCommon.h" -#include "plugins.h" -#include "resource.h" -#include "Win32.h" - -#include "Paths.h" - - -HWND mcdDlg; - - -void Open_Mcd_Proc(HWND hW, int mcd) { - OPENFILENAME ofn; - char szFileName[256]; - char szFileTitle[256]; - char szFilter[1024]; - char *str; - - memset(szFileName, 0, sizeof(szFileName)); - memset(szFileTitle, 0, sizeof(szFileTitle)); - memset(szFilter, 0, sizeof(szFilter)); - - - strcpy(szFilter, _("Ps2 Memory Card (*.ps2)")); - str = szFilter + strlen(szFilter) + 1; - strcpy(str, "*.ps2"); - - str+= strlen(str) + 1; - strcpy(str, _("All Files")); - str+= strlen(str) + 1; - strcpy(str, "*.*"); - - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = hW; - ofn.lpstrFilter = szFilter; - ofn.lpstrCustomFilter = NULL; - ofn.nMaxCustFilter = 0; - ofn.nFilterIndex = 1; - ofn.lpstrFile = szFileName; - ofn.nMaxFile = 256; - ofn.lpstrInitialDir = MEMCARDS_DIR; - ofn.lpstrFileTitle = szFileTitle; - ofn.nMaxFileTitle = 256; - ofn.lpstrTitle = NULL; - ofn.lpstrDefExt = "MC2"; - ofn.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR; - - if (GetOpenFileName ((LPOPENFILENAME)&ofn)) { - Edit_SetText(GetDlgItem(hW,mcd == 1 ? IDC_MCD1 : IDC_MCD2), szFileName); - } -} - -BOOL CALLBACK ConfigureMcdsDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { - switch(uMsg) { - case WM_INITDIALOG: - mcdDlg = hW; - - SetWindowText(hW, _("Memcard Manager")); - - Button_SetText(GetDlgItem(hW, IDOK), _("OK")); - Button_SetText(GetDlgItem(hW, IDCANCEL), _("Cancel")); - Button_SetText(GetDlgItem(hW, IDC_MCDSEL1), _("Select Mcd")); - Button_SetText(GetDlgItem(hW, IDC_MCDSEL2), _("Select Mcd")); - - Static_SetText(GetDlgItem(hW, IDC_FRAMEMCD1), _("Memory Card 1")); - Static_SetText(GetDlgItem(hW, IDC_FRAMEMCD2), _("Memory Card 2")); - - if (!strlen(Config.Mcd1)) strcpy(Config.Mcd1, "memcards\\Mcd001.ps2"); - if (!strlen(Config.Mcd2)) strcpy(Config.Mcd2, "memcards\\Mcd002.ps2"); - Edit_SetText(GetDlgItem(hW,IDC_MCD1), Config.Mcd1); - Edit_SetText(GetDlgItem(hW,IDC_MCD2), Config.Mcd2); - - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDC_MCDSEL1: - Open_Mcd_Proc(hW, 1); - return TRUE; - case IDC_MCDSEL2: - Open_Mcd_Proc(hW, 2); - return TRUE; - case IDCANCEL: - EndDialog(hW,FALSE); - - return TRUE; - case IDOK: - Edit_GetText(GetDlgItem(hW,IDC_MCD1), Config.Mcd1, 256); - Edit_GetText(GetDlgItem(hW,IDC_MCD2), Config.Mcd2, 256); - - SaveConfig(); - - EndDialog(hW,TRUE); - - return TRUE; - } - case WM_DESTROY: - return TRUE; - } - return FALSE; -} - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 +#include +#include +#include + +#include "Common.h" +#include "PsxCommon.h" +#include "plugins.h" +#include "resource.h" +#include "Win32.h" + +#include "Paths.h" + + +HWND mcdDlg; + + +void Open_Mcd_Proc(HWND hW, int mcd) { + OPENFILENAME ofn; + char szFileName[256]; + char szFileTitle[256]; + char szFilter[1024]; + char *str; + + memset(szFileName, 0, sizeof(szFileName)); + memset(szFileTitle, 0, sizeof(szFileTitle)); + memset(szFilter, 0, sizeof(szFilter)); + + + strcpy(szFilter, _("Ps2 Memory Card (*.ps2)")); + str = szFilter + strlen(szFilter) + 1; + strcpy(str, "*.ps2"); + + str+= strlen(str) + 1; + strcpy(str, _("All Files")); + str+= strlen(str) + 1; + strcpy(str, "*.*"); + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = hW; + ofn.lpstrFilter = szFilter; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 1; + ofn.lpstrFile = szFileName; + ofn.nMaxFile = 256; + ofn.lpstrInitialDir = MEMCARDS_DIR; + ofn.lpstrFileTitle = szFileTitle; + ofn.nMaxFileTitle = 256; + ofn.lpstrTitle = NULL; + ofn.lpstrDefExt = "MC2"; + ofn.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR; + + if (GetOpenFileName ((LPOPENFILENAME)&ofn)) { + Edit_SetText(GetDlgItem(hW,mcd == 1 ? IDC_MCD1 : IDC_MCD2), szFileName); + } +} + +BOOL CALLBACK ConfigureMcdsDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + mcdDlg = hW; + + SetWindowText(hW, _("Memcard Manager")); + + Button_SetText(GetDlgItem(hW, IDOK), _("OK")); + Button_SetText(GetDlgItem(hW, IDCANCEL), _("Cancel")); + Button_SetText(GetDlgItem(hW, IDC_MCDSEL1), _("Select Mcd")); + Button_SetText(GetDlgItem(hW, IDC_MCDSEL2), _("Select Mcd")); + + Static_SetText(GetDlgItem(hW, IDC_FRAMEMCD1), _("Memory Card 1")); + Static_SetText(GetDlgItem(hW, IDC_FRAMEMCD2), _("Memory Card 2")); + + if (!strlen(Config.Mcd1)) strcpy(Config.Mcd1, "memcards\\Mcd001.ps2"); + if (!strlen(Config.Mcd2)) strcpy(Config.Mcd2, "memcards\\Mcd002.ps2"); + Edit_SetText(GetDlgItem(hW,IDC_MCD1), Config.Mcd1); + Edit_SetText(GetDlgItem(hW,IDC_MCD2), Config.Mcd2); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_MCDSEL1: + Open_Mcd_Proc(hW, 1); + return TRUE; + case IDC_MCDSEL2: + Open_Mcd_Proc(hW, 2); + return TRUE; + case IDCANCEL: + EndDialog(hW,FALSE); + + return TRUE; + case IDOK: + Edit_GetText(GetDlgItem(hW,IDC_MCD1), Config.Mcd1, 256); + Edit_GetText(GetDlgItem(hW,IDC_MCD2), Config.Mcd2, 256); + + SaveConfig(); + + EndDialog(hW,TRUE); + + return TRUE; + } + case WM_DESTROY: + return TRUE; + } + return FALSE; +} + diff --git a/pcsx2/windows/McdsDlg.cpp b/pcsx2/windows/McdsDlg.cpp index 3c92c34808..7dd919747b 100644 --- a/pcsx2/windows/McdsDlg.cpp +++ b/pcsx2/windows/McdsDlg.cpp @@ -1,1743 +1,1743 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" -#include "Win32.h" - -#include -#include -#include "libintlmsc.h" - -#include "System.h" -#include "McdsDlg.h" - -#include -using namespace std; - - -u16 SJISTable[0xFFFF]; - - -void IniSJISTable() -{ - memzero_obj(SJISTable); - //Blow me sony for using this retarded sjis to store the savegame name - SJISTable[0x20] = 0x0020; - SJISTable[0x21] = 0x0021; - SJISTable[0x22] = 0x0022; - SJISTable[0x23] = 0x0023; - SJISTable[0x24] = 0x0024; - SJISTable[0x25] = 0x0025; - SJISTable[0x26] = 0x0026; - SJISTable[0x27] = 0x0027; - SJISTable[0x28] = 0x0028; - SJISTable[0x29] = 0x0029; - SJISTable[0x2A] = 0x002A; - SJISTable[0x2B] = 0x002B; - SJISTable[0x2C] = 0x002C; - SJISTable[0x2D] = 0x002D; - SJISTable[0x2E] = 0x002E; - SJISTable[0x2F] = 0x002F; - SJISTable[0x30] = 0x0030; - SJISTable[0x31] = 0x0031; - SJISTable[0x32] = 0x0032; - SJISTable[0x33] = 0x0033; - SJISTable[0x34] = 0x0034; - SJISTable[0x35] = 0x0035; - SJISTable[0x36] = 0x0036; - SJISTable[0x37] = 0x0037; - SJISTable[0x38] = 0x0038; - SJISTable[0x39] = 0x0039; - SJISTable[0x3A] = 0x003A; - SJISTable[0x3B] = 0x003B; - SJISTable[0x3C] = 0x003C; - SJISTable[0x3D] = 0x003D; - SJISTable[0x3E] = 0x003E; - SJISTable[0x3F] = 0x003F; - SJISTable[0x40] = 0x0040; - SJISTable[0x41] = 0x0041; - SJISTable[0x42] = 0x0042; - SJISTable[0x43] = 0x0043; - SJISTable[0x44] = 0x0044; - SJISTable[0x45] = 0x0045; - SJISTable[0x46] = 0x0046; - SJISTable[0x47] = 0x0047; - SJISTable[0x48] = 0x0048; - SJISTable[0x49] = 0x0049; - SJISTable[0x4A] = 0x004A; - SJISTable[0x4B] = 0x004B; - SJISTable[0x4C] = 0x004C; - SJISTable[0x4D] = 0x004D; - SJISTable[0x4E] = 0x004E; - SJISTable[0x4F] = 0x004F; - SJISTable[0x50] = 0x0050; - SJISTable[0x51] = 0x0051; - SJISTable[0x52] = 0x0052; - SJISTable[0x53] = 0x0053; - SJISTable[0x54] = 0x0054; - SJISTable[0x55] = 0x0055; - SJISTable[0x56] = 0x0056; - SJISTable[0x57] = 0x0057; - SJISTable[0x58] = 0x0058; - SJISTable[0x59] = 0x0059; - SJISTable[0x5A] = 0x005A; - SJISTable[0x5B] = 0x005B; - SJISTable[0x5C] = 0x00A5; - SJISTable[0x5D] = 0x005D; - SJISTable[0x5E] = 0x005E; - SJISTable[0x5F] = 0x005F; - SJISTable[0x60] = 0x0060; - SJISTable[0x61] = 0x0061; - SJISTable[0x62] = 0x0062; - SJISTable[0x63] = 0x0063; - SJISTable[0x64] = 0x0064; - SJISTable[0x65] = 0x0065; - SJISTable[0x66] = 0x0066; - SJISTable[0x67] = 0x0067; - SJISTable[0x68] = 0x0068; - SJISTable[0x69] = 0x0069; - SJISTable[0x6A] = 0x006A; - SJISTable[0x6B] = 0x006B; - SJISTable[0x6C] = 0x006C; - SJISTable[0x6D] = 0x006D; - SJISTable[0x6E] = 0x006E; - SJISTable[0x6F] = 0x006F; - SJISTable[0x70] = 0x0070; - SJISTable[0x71] = 0x0071; - SJISTable[0x72] = 0x0072; - SJISTable[0x73] = 0x0073; - SJISTable[0x74] = 0x0074; - SJISTable[0x75] = 0x0075; - SJISTable[0x76] = 0x0076; - SJISTable[0x77] = 0x0077; - SJISTable[0x78] = 0x0078; - SJISTable[0x79] = 0x0079; - SJISTable[0x7A] = 0x007A; - SJISTable[0x7B] = 0x007B; - SJISTable[0x7C] = 0x007C; - SJISTable[0x7D] = 0x007D; - SJISTable[0x7E] = 0x007E; - - SJISTable[0x8140] = 0x0020; - SJISTable[0x8149] = 0x0021; - SJISTable[0x22] = 0x0022; - SJISTable[0x8194] = 0x0023; - SJISTable[0x8190] = 0x0024; - SJISTable[0x8193] = 0x0025; - SJISTable[0x8195] = 0x0026; - SJISTable[0x27] = 0x0027; - SJISTable[0x8169] = 0x0028; - SJISTable[0x816A] = 0x0029; - SJISTable[0x8196] = 0x002A; - SJISTable[0x817B] = 0x002B; - SJISTable[0x8143] = 0x002C; - SJISTable[0x815D] = 0x002D; - SJISTable[0x8144] = 0x002E; - SJISTable[0x815E] = 0x002F; - SJISTable[0x824F] = 0x0030; - SJISTable[0x8250] = 0x0031; - SJISTable[0x8251] = 0x0032; - SJISTable[0x8252] = 0x0033; - SJISTable[0x8253] = 0x0034; - SJISTable[0x8254] = 0x0035; - SJISTable[0x8255] = 0x0036; - SJISTable[0x8256] = 0x0037; - SJISTable[0x8257] = 0x0038; - SJISTable[0x8258] = 0x0039; - SJISTable[0x8146] = 0x003A; - SJISTable[0x8147] = 0x003B; - SJISTable[0x8183] = 0x003C; - SJISTable[0x8181] = 0x003D; - SJISTable[0x8184] = 0x003E; - SJISTable[0x8148] = 0x003F; - SJISTable[0x8197] = 0x0040; - SJISTable[0x8260] = 0x0041; - SJISTable[0x8261] = 0x0042; - SJISTable[0x8262] = 0x0043; - SJISTable[0x8263] = 0x0044; - SJISTable[0x8264] = 0x0045; - SJISTable[0x8265] = 0x0046; - SJISTable[0x8266] = 0x0047; - SJISTable[0x8267] = 0x0048; - SJISTable[0x8268] = 0x0049; - SJISTable[0x8269] = 0x004A; - SJISTable[0x826A] = 0x004B; - SJISTable[0x826B] = 0x004C; - SJISTable[0x826C] = 0x004D; - SJISTable[0x826D] = 0x004E; - SJISTable[0x826E] = 0x004F; - SJISTable[0x826F] = 0x0050; - SJISTable[0x8270] = 0x0051; - SJISTable[0x8271] = 0x0052; - SJISTable[0x8272] = 0x0053; - SJISTable[0x8273] = 0x0054; - SJISTable[0x8274] = 0x0055; - SJISTable[0x8275] = 0x0056; - SJISTable[0x8276] = 0x0057; - SJISTable[0x8277] = 0x0058; - SJISTable[0x8278] = 0x0059; - SJISTable[0x8279] = 0x005A; - SJISTable[0x816D] = 0x005B; - SJISTable[0x818F] = 0x00A5; - SJISTable[0x816E] = 0x005D; - SJISTable[0x814F] = 0x005E; - SJISTable[0x8151] = 0x005F; - SJISTable[0x814D] = 0x0060; - SJISTable[0x8281] = 0x0061; - SJISTable[0x8282] = 0x0062; - SJISTable[0x8283] = 0x0063; - SJISTable[0x8284] = 0x0064; - SJISTable[0x8285] = 0x0065; - SJISTable[0x8286] = 0x0066; - SJISTable[0x8287] = 0x0067; - SJISTable[0x8288] = 0x0068; - SJISTable[0x8289] = 0x0069; - SJISTable[0x828A] = 0x006A; - SJISTable[0x828B] = 0x006B; - SJISTable[0x828C] = 0x006C; - SJISTable[0x828D] = 0x006D; - SJISTable[0x828E] = 0x006E; - SJISTable[0x828F] = 0x006F; - SJISTable[0x8290] = 0x0070; - SJISTable[0x8291] = 0x0071; - SJISTable[0x8292] = 0x0072; - SJISTable[0x8293] = 0x0073; - SJISTable[0x8294] = 0x0074; - SJISTable[0x8295] = 0x0075; - SJISTable[0x8296] = 0x0076; - SJISTable[0x8297] = 0x0077; - SJISTable[0x8298] = 0x0078; - SJISTable[0x8299] = 0x0079; - SJISTable[0x829A] = 0x007A; - SJISTable[0x816F] = 0x007B; - SJISTable[0x8162] = 0x007C; - SJISTable[0x8170] = 0x007D; - SJISTable[0x7E] = 0x007E; -} - - -HWND mcdDlg; -HTREEITEM root; -HWND treewindow; - -HTREEITEM AddTreeItem(HWND treeview, HTREEITEM parent, const char *name, LPARAM lp) -{ - TVINSERTSTRUCT node={ - parent, - 0, - { - TVIF_TEXT, - NULL, - TVIS_EXPANDED, - TVIS_EXPANDED, - (LPSTR)name, - 0, - 0, - 0, - 0, - lp, - 1 - } - }; - return TreeView_InsertItem(treeview,&node); -} - -void ReadDir(int cluster, int rec, HTREEITEM tree); - - -class Time -{ - public: - u8 sec; - u8 min; - u8 hour; - u8 day; - u8 month; - u16 year; -}; - - -class Dir -{ - protected: - - - public: - static const u16 DF_READ = 0x0001; - static const u16 DF_WRITE = 0x0002; - static const u16 DF_EXECUTE = 0x0004; - static const u16 DF_PROTECTED = 0x0008; - static const u16 DF_FILE = 0x0010; - static const u16 DF_DIRECTORY = 0x0020; - static const u16 DF_HIDDEN = 0x2000; - static const u16 DF_EXISTS = 0x8000; - - // Directory Attributes - u16 Mode; - s32 Lenght; - Time Created; - s32 Cluster; - u32 DirEntry; - Time Modified; - u32 Attribute; - s8 Name[256]; // just in case some names are longer - - // Parent dir and contents of dir - Dir *Parent; - vector Sons; - - // Used to store the contents of a file - u8 *File; - - Dir() - { - File = 0; - } - - bool IsHidden() - { - return (Mode & DF_HIDDEN) ? 1 : 0; - } - - bool IsFile() - { - return (Mode & DF_FILE) ? 1 : 0; - } - - bool IsDirectory() - { - return (Mode & DF_DIRECTORY) ? 1 : 0; - } - - bool Exists() - { - return (Mode & DF_EXISTS) ? 1 : 0; - } - - void Load(s8 *d) - { - File = 0; - // For the moment we dont need to load more data - Mode = *(u16 *)d; - Lenght = *(u32 *)(d + 0x04); - Cluster = *(u32 *)(d + 0x10); - strncpy(Name, d + 0x40, 255); - } - - Dir* AddSon(Dir &d) - { - d.Parent = this; - vector::iterator i = Sons.insert(Sons.end(), d); - return &i[0]; - } - - void Release() - { - for(unsigned int i=0;iFile + 12); - u32 NumVertex = *(u32 *)(File + 16); - - // Check if it's an ico file - if(FileID != 0x00010000) - { - MessageBox(mcdDlg, "It's not an ICO file.", "Error", 0); - return 0; - } - - // Is texture compressed? - if(TextureType != 0x07) - { - //MessageBox(mcdDlg, "Compressed texture, not yet supported.", "Error", 0); - //return; - } - - // Calculate the offset to the animation segment - u32 VertexSize = (AnimationShapes * 8) + 8 + 8; - u32 AnimationSegmentOffset = (VertexSize * NumVertex) + 20; - - // Check if we really are at the animation header - u32 AnimationID = *(u32 *)(File + AnimationSegmentOffset); - if(AnimationID != 0x00000001) - { - MessageBox(mcdDlg, "Animation header ID is incorrect.", "Error", 0); - return 0; - } - - // Get the size of all the animation segment - u32 FrameLenght = *(u32 *)(File + AnimationSegmentOffset + 4); - u32 NumberOfFrames = *(u32 *)(File + AnimationSegmentOffset + 16); - - u32 Offset = AnimationSegmentOffset + 20; - for(u32 i=0;i 0x07) - { - u32 CompressedDataSize = *(u32 *)(File + Offset); - //RLE compression - - Offset += 4; - u32 OffsetEnd = Offset + CompressedDataSize; - u32 WriteCount = 0; - - while(WriteCount < 0x8000 && Offset < OffsetEnd) - { - - u16 Data = *(u16 *)(File + Offset); - - if(Data < 0xFF00) //Replication - { - Offset += 2; - u16 Rep = *(u16 *)(File + Offset); - - for(int i=0;iLenght-0x8000*/Offset], 0x8000); - } - - // Convert from TIM to rgb - for(z=0;z<0x4000;z++) - { - dest[y] = 8 * (ico[z] & 0x1F); - dest[y+1] = 8 * ((ico[z] >>5) & 0x1F); - dest[y+2] = 8 * (ico[z] >>10); - y += 3; - } - - return 1; - } - -}; - - -class SaveGame -{ - public: - - Dir *D; - char Name1[256]; - char Name2[256]; - - u8 Icon[128*128*3]; - - - SaveGame(Dir *_Dir) - { - char IconName[256]; - - D = _Dir; - - // Find icon.sys - for(unsigned int i=0;iSons.size();i++) - { - if(!strcmp("icon.sys", D->Sons[i].Name)) - { - char temp[256]; - - // Get Name in SJIS format - u16 *p = (u16 *)(D->Sons[i].File + 192); - - while(*p != 0x0000) - { - // Switch bytes - u8 *pp = (u8 *)p; - u8 tb = *pp; - *pp = pp[1]; - pp[1] = tb; - - // Translate char - *p = SJISTable[*p]; - - p++; - } - - // Convert unicode string - wcstombs(temp, (wchar_t *)(D->Sons[i].File + 192), 255); - - // Get the second line separator - u16 SecondLine = *(u16 *)(D->Sons[i].File + 6); - SecondLine /= 2; - - // Copy the 2 parts of the string to different strings - strncpy(Name1, temp, SecondLine); - Name1[SecondLine] = 0; - - strcpy(Name2, &temp[SecondLine]); - if(strlen(Name2) + SecondLine > 68) - Name2[0] = 0; - - // Get the icon file name - strcpy(IconName, (char *)D->Sons[i].File + 260); - - } - } - - // Find the icon now - for(unsigned int i=0;iSons.size();i++) - { - if(!strcmp(IconName, D->Sons[i].Name)) - { - D->Sons[i].BuildICO((char*)Icon); - } - - } - } - - void AddIcoToImageList(HIMAGELIST il) - { - - HDC hDC = GetDC(NULL); - HDC memDC = CreateCompatibleDC (hDC); - HBITMAP memBM = CreateCompatibleBitmap ( hDC, 128, 128 ); - SelectObject ( memDC, memBM ); - - int px, py, pc=0; - for(px=0;px<128;px++){ - for(py=0;py<128;py++){ - SetPixel(memDC, py, px, RGB(Icon[pc], Icon[pc+1], Icon[pc+2])); - pc+=3; - } - } - - HDC memDC2 = CreateCompatibleDC (hDC); - HBITMAP memBM2 = CreateCompatibleBitmap ( hDC, 64, 64 ); - SelectObject ( memDC2, memBM2 ); - SetStretchBltMode(memDC2, HALFTONE); - StretchBlt(memDC2, 0, 0, 64, 64, memDC, 0, 0, 128, 128, SRCCOPY); - - DeleteDC(memDC2); - DeleteDC(memDC); - ImageList_Add(il, memBM2, NULL); - DeleteObject(memBM); - DeleteObject(memBM2); - ReleaseDC(NULL, hDC); - - - } - - void DrawICO(HWND hWnd) - { - // int px, py, pc=0; - HDC dc = GetDC(hWnd); - /* - for(px=0;px<128;px++){ - for(py=0;py<128;py++){ - SetPixel(dc, py, px, RGB(Icon[pc], Icon[pc+1], Icon[pc+2])); - pc+=3; - - } - } -*/ - /* - HDC hDC = GetDC(NULL); - HDC memDC = CreateCompatibleDC ( hDC ); - HBITMAP memBM = CreateCompatibleBitmap ( hDC, 256, 128 ); - SelectObject ( memDC, memBM ); - for(px=0;px<128;px++){ - for(py=0;py<128;py++){ - SetPixel(memDC, py, px, RGB(Icon[pc], Icon[pc+1], Icon[pc+2])); - pc+=3; - - } - } - RECT rect; - rect.left=132; - rect.right=255; - rect.top=4; - rect.bottom=255; - DrawText(memDC, Name1, strlen(Name1), &rect, 0); - rect.top=20; - DrawText(memDC, Name2, strlen(Name2), &rect, 0); - - - SetStretchBltMode(dc, HALFTONE); - StretchBlt(dc, 0, 0, 64, 64, memDC, 0, 0, 128, 128, SRCCOPY); - //BitBlt(dc, 0, 0, 256, 128, memDC, 0, 0, SRCCOPY); - */ - } - -}; - - -class MemoryCard -{ - public: - FILE *fp; - int FAT[256*256]; - int indirect_table[256]; - char FileName[1024]; - Dir Root; - vector SaveGameList; - HIMAGELIST ImageList; - - MemoryCard() - { - fp = 0; - ImageList = 0; - } - - int BuildFAT() - { - int IFC; - // indirect table containing the clusters with FAT data - int i, o; - - // First read IFC from the superblock (8MB cards only have 1) - fseek(fp, 0x50, SEEK_SET); - fread(&IFC, 4, 1, fp); - - if(IFC != 8) - { - MessageBox(mcdDlg, "IFC is not 8. Memory Card is probably corrupt.", "Error", 0); - return 0; - } - - DbgCon::WriteLn("IFC: %d", params IFC); - - // Read the cluster with the indirect data to the FAT. - fseek(fp, 0x420 * IFC, SEEK_SET); - fread(indirect_table, 4, 128, fp); - fseek(fp, (0x420 * IFC) + 0x210, SEEK_SET); - fread(&indirect_table[128], 4, 128, fp); - - // Build the FAT table from the indirect_table - o = 0; - i = 0; - - while(indirect_table[i] != 0xFFFFFFFF) - { - - fseek(fp, 0x420 * indirect_table[i], SEEK_SET); - fread(&FAT[o], 4, 128, fp); - o+=128; - - fseek(fp, (0x420 * indirect_table[i]) + 0x210, SEEK_SET); - fread(&FAT[o], 4, 128, fp); - o+=128; - - i++; - } - return 1; - } - - void ReadFile(Dir *d) - { - - int cluster = d->Cluster; - int size = d->Lenght; - int numclusters = (int)ceil((double)size / 1024); - int numpages = (int)ceil((double)size / 512); - int i=0, j=0, c=0, read=0; - d->File = (u8 *) malloc(size); - - - for(i=0;i 512) - read = 512; - - fseek(fp, 0xA920 + ((cluster) * 0x420), SEEK_SET); - fread(&d->File[c], 1, read, fp); - c+=read; - j++; - if(j == numpages) - break; - - read = size - c; - if(read > 512) - read = 512; - - fseek(fp, 0xA920 + (((cluster) * 0x420)+528), SEEK_SET); - fread(&d->File[c], 1, read, fp); - c+=read; - j++; - if(j == numpages) - break; - - cluster = FAT[cluster]; - cluster = cluster ^ 0x80000000; - if(cluster == 0x7FFFFFFF || cluster == 0xFFFFFFFF) - break; - } - - } - - void Read(u32 cluster, Dir *d) - { - int i; - s8 file1[512], file2[512]; - Dir D1, D2; - - for(i = 0; i < 0xffff; i++) - { - - // Read first page containing the first dir - fseek(fp, 0xA920 + ((cluster) * 0x420), SEEK_SET); - fread(file1, 1, 512, fp); - // Initialize the temporal dir - D1.Load(file1); - if(D1.Exists() && D1.Lenght >= 0 && D1.Cluster >= 0) - { - // If it exists add the dir to current dir - Dir *td = d->AddSon(D1); - - // If it's a directory and not . or .. recursive call - if(D1.IsDirectory() && D1.Name[0]!= '.' ) - { - Read(td->Cluster, td); - } - - // If it's a file load the file - if(D1.IsFile()) - { - ReadFile(td); - } - } - - - // Read second page with second dir or empty - fseek(fp, 0xA920 + (((cluster) * 0x420) + 528), SEEK_SET); - fread(file2, 1, 512, fp); - // Initialize the temporal dir and add it to current dir - D2.Load(file2); - if(D2.Exists() && D2.Lenght >= 0 && D2.Cluster >= 0) - { - Dir *td = d->AddSon(D2); - - if(D2.IsDirectory() && D2.Name[0]!= '.') - { - Read(td->Cluster, td); - } - - // If it's a file load the file - if(D2.IsFile() && D2.Name[0]!= '.') - { - ReadFile(td); - } - } - - // Get next cluster from the FAT table - cluster = FAT[cluster]; - cluster = cluster ^ 0x80000000; - if(cluster == 0x7FFFFFFF || cluster == 0xFFFFFFFF) - break; - } - - } - - void Load(char *filename) - { - strcpy(FileName, filename); - - // Clear previous data - if(fp != 0) - { - fclose(fp); - } - memzero_obj(FAT); - Root.Release(); - - SaveGameList.clear(); - ImageList_Destroy(ImageList); - - // Open memory card file - fp = fopen(FileName, "rb"); - - // Check if we opened the file - if(fp == NULL) - { - MessageBox(mcdDlg, "Unable to open memory card file.", "Error", 0); - return; - } - - // Build the FAT table for the card - if(BuildFAT() == 1) - { - // Read the root dir - Read(0, &Root); - } - - fclose(fp); - - ReadSaveGames(); - } - - void AddDirToTreeView(HWND hWnd, HTREEITEM tree, Dir *d) - { - for(unsigned int i=0;iSons.size();i++) - { - HTREEITEM temptree = AddTreeItem(hWnd, tree, d->Sons[i].Name, 0); - if(d->Sons[i].IsDirectory()) - { - TreeView_SetItemState(hWnd, temptree, TVIS_EXPANDED|TVIS_BOLD, 0x00F0); - AddDirToTreeView(hWnd, temptree, &d->Sons[i]); - } - } - } - - void AddToListView(HWND hWnd) - { - ListView_SetIconSpacing(hWnd, 128, 128); - ListView_DeleteAllItems(hWnd); - ListView_SetImageList(hWnd, ImageList, LVSIL_NORMAL); - - LVITEM item; - char temp[2560]; - item.mask = LVIF_IMAGE | LVIF_TEXT; - item.iItem = 0; - item.iSubItem = 0; - item.state = 0; - item.stateMask = 0; - item.pszText = temp; - item.cchTextMax = 255; - item.iImage = 1; - item.iIndent = 0; - item.lParam = 0; - - for(unsigned int i=0;iSons.size();i++) - { - if(!strcmp(file, d->Sons[i].Name)) - break; - } - - if(i == d->Sons.size()) - { - MessageBox(mcdDlg, "Unable to find the file.", "Error", 0); - return NULL; - } - - return &d->Sons[i]; - } - - void PaintICOFile(HWND hWnd, char *dir, char *name) - { - // First find the file - Dir *d = FindFile(dir, name); - if(d == NULL) - return; - - - - u32 FileID = *(u32 *)d->File; - u32 AnimationShapes = *(u32 *)(d->File + 4); - u32 TextureType = *(u32 *)(d->File + 8); - //u32 ConstantCheck = *(u32 *)(d->File + 12); - u32 NumVertex = *(u32 *)(d->File + 16); - - // Check if it's an ico file - if(FileID != 0x00010000) - { - MessageBox(mcdDlg, "It's not an ICO file.", "Error", 0); - return; - } - - // Is texture compressed? - if(TextureType != 0x07) - { - //MessageBox(mcdDlg, "Compressed texture, not yet supported.", "Error", 0); - //return; - } - - // Calculate the offset to the animation segment - u32 VertexSize = (AnimationShapes * 8) + 8 + 8; - u32 AnimationSegmentOffset = (VertexSize * NumVertex) + 20; - - // Check if we really are at the animation header - u32 AnimationID = *(u32 *)(d->File + AnimationSegmentOffset); - if(AnimationID != 0x00000001) - { - MessageBox(mcdDlg, "Animation header ID is incorrect.", "Error", 0); - return; - } - - // Get the size of all the animation segment - u32 FrameLenght = *(u32 *)(d->File + AnimationSegmentOffset + 4); - u32 NumberOfFrames = *(u32 *)(d->File + AnimationSegmentOffset + 16); - - u32 Offset = AnimationSegmentOffset + 20; - for(unsigned int i=0;iFile + Offset + 4); - Offset += 16 + (KeyNum * 8) - 8; // The -8 is there because the doc with the ico format spec is either wrong or I'm stupid - } - - int z, y=0; - u16 ico[0x4000]; - u8 cico[128*128*3]; - - if(TextureType > 0x07) - { - u32 CompressedDataSize = *(u32 *)(d->File + Offset); - //RLE compression - - Offset += 4; - u32 OffsetEnd = Offset + CompressedDataSize; - u32 WriteCount = 0; - - while(WriteCount < 0x8000 && Offset < OffsetEnd) - { - - u16 Data = *(u16 *)(d->File + Offset); - - if(Data < 0xFF00) //Replication - { - Offset += 2; - u16 Rep = *(u16 *)(d->File + Offset); - - for(int i=0;iFile + Offset); - WriteCount++; - Offset += 2; - } - } - - } - - } - else - { - // Get the texture from the file - memcpy(ico, &d->File[/*d->Lenght-0x8000*/Offset], 0x8000); - } - - // Convert from TIM to rgb - for(z=0;z<0x4000;z++) - { - cico[y] = 8 * (ico[z] & 0x1F); - cico[y+1] = 8 * ((ico[z] >>5) & 0x1F); - cico[y+2] = 8 * (ico[z] >>10); - y += 3; - } - - // Draw - int px, py, pc=0; - HDC dc = GetDC(hWnd); - for(px=0;px<128;px++){ - for(py=0;py<128;py++){ - SetPixel(dc, py, px, RGB(cico[pc], cico[pc+1], cico[pc+2])); - pc+=3; - - } - } - } - - - void ReadSaveGames() - { - // Initialize the conversion table for SJIS strings - IniSJISTable(); - - // Create the image list - ImageList = ImageList_Create(64, 64, ILC_COLOR32, 10, 256); - - for(unsigned int i=0;iSons.size(); // number of files inside the dir - *(u8 *)&dir[8] = 0; // creation time seconds - *(u8 *)&dir[9] = 0; // creation time minuts - *(u8 *)&dir[10] = 0; // creation time hours - *(u8 *)&dir[11] = 1; // creation time day - *(u8 *)&dir[12] = 1; // creation time month - *(u16 *)&dir[13] = 2008; // creation time year - *(u32 *)&dir[16] = dircluster; // cluster with the contents of the dir - *(u32 *)&dir[20] = 0; // dir entry for '.' - *(u8 *)&dir[24] = 0; // modification time seconds - *(u8 *)&dir[25] = 0; // modification time minuts - *(u8 *)&dir[26] = 0; // modification time hours - *(u8 *)&dir[27] = 1; // modification time day - *(u8 *)&dir[28] = 1; // modification time month - *(u16 *)&dir[29] = 2008; // modification time year - *(u32 *)&dir[32] = 0; // user attribute unused - strcpy(&dir[64], Di->Name); // DIRECTORY NAME - - - if(Lenght % 2) - { - // Find empty cluster... - int c = FindEmptyCluster(); - - // THIS MAY BE WRONG...TEST - FAT[oldcluster] = c; - FAT[c] = 0xFFFFFFFF; - - // Add dir to first page of new cluster - fseek(fp, 0xA920 + (((c) * 0x420) + 0), SEEK_SET); - fwrite(dir, 512, 1, fp); - } - else - { - // Add dir to second page of cluster - fseek(fp, 0xA920 + (((oldcluster) * 0x420) + 528), SEEK_SET); - fwrite(dir, 512, 1, fp); - } - - // CALCULATE CRCS OF CLUSTER - - - // INCREASE ROOT DIR SIZE BY 1 - fseek(fp, 0xA920 + (((0) * 0x420) + 4), SEEK_SET); - int nl = Lenght + 1; - fwrite(&nl, 4, 1, fp); - - - int numfiles = 5; - - // ADD FILE ENTRIES TO DIR ., .. - memzero_obj(dir); - *(u16 *)&dir[0] = Dir::DF_EXISTS | Dir::DF_DIRECTORY | Dir::DF_READ; // mode flag - *(u32 *)&dir[4] = numfiles; // number of files inside the dir - *(u8 *)&dir[8] = 0; // creation time seconds - *(u8 *)&dir[9] = 0; // creation time minuts - *(u8 *)&dir[10] = 0; // creation time hours - *(u8 *)&dir[11] = 1; // creation time day - *(u8 *)&dir[12] = 1; // creation time month - *(u16 *)&dir[13] = 2008; // creation time year - *(u32 *)&dir[16] = 0; // cluster with the contents of the dir - *(u32 *)&dir[20] = 0; // dir entry for '.' - *(u8 *)&dir[24] = 0; // modification time seconds - *(u8 *)&dir[25] = 0; // modification time minuts - *(u8 *)&dir[26] = 0; // modification time hours - *(u8 *)&dir[27] = 1; // modification time day - *(u8 *)&dir[28] = 1; // modification time month - *(u16 *)&dir[29] = 2008; // modification time year - *(u32 *)&dir[32] = 0; // user attribute unused - strcpy(&dir[64], "."); // DIRECTORY NAME - fseek(fp, 0xA920 + (((dircluster) * 0x420) + 0), SEEK_SET); - fwrite(dir, 512, 1, fp); - - memzero_obj(dir); - *(u16 *)&dir[0] = Dir::DF_EXISTS | Dir::DF_DIRECTORY | Dir::DF_READ; // mode flag - *(u32 *)&dir[4] = 2; // number of files inside the dir - *(u8 *)&dir[8] = 0; // creation time seconds - *(u8 *)&dir[9] = 0; // creation time minuts - *(u8 *)&dir[10] = 0; // creation time hours - *(u8 *)&dir[11] = 1; // creation time day - *(u8 *)&dir[12] = 1; // creation time month - *(u16 *)&dir[13] = 2008; // creation time year - *(u32 *)&dir[16] = 0; // cluster with the contents of the dir - *(u32 *)&dir[20] = 0; // dir entry for '.' - *(u8 *)&dir[24] = 0; // modification time seconds - *(u8 *)&dir[25] = 0; // modification time minuts - *(u8 *)&dir[26] = 0; // modification time hours - *(u8 *)&dir[27] = 1; // modification time day - *(u8 *)&dir[28] = 1; // modification time month - *(u16 *)&dir[29] = 2008; // modification time year - *(u32 *)&dir[32] = 0; // user attribute unused - strcpy(&dir[64], ".."); // DIRECTORY NAME - fseek(fp, 0xA920 + (((dircluster) * 0x420) + 528), SEEK_SET); - fwrite(dir, 512, 1, fp); - - FAT[dircluster] = 0xFFFFFFFF; - - - // ADD REST OF FILES - - for(int i=2;iFile, d->Lenght, 1, fp); - fclose(fp); - } - } -} - - - -FILE *fp; - -BOOL CALLBACK ConfigureMcdsDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { - switch(uMsg) { - case WM_INITDIALOG: - mcdDlg = hW; - - SetWindowText(hW, _("Memcard Manager")); - - Button_SetText(GetDlgItem(hW, IDOK), _("OK")); - Button_SetText(GetDlgItem(hW, IDCANCEL), _("Cancel")); - Button_SetText(GetDlgItem(hW, IDC_MCDSEL1), _("Select Mcd")); - Button_SetText(GetDlgItem(hW, IDC_MCDSEL2), _("Select Mcd")); - - Static_SetText(GetDlgItem(hW, IDC_FRAMEMCD1), _("Memory Card 1")); - Static_SetText(GetDlgItem(hW, IDC_FRAMEMCD2), _("Memory Card 2")); - - if (!strlen(Config.Mcd1)) strcpy(Config.Mcd1, MEMCARDS_DIR "\\" DEFAULT_MEMCARD1); - if (!strlen(Config.Mcd2)) strcpy(Config.Mcd2, MEMCARDS_DIR "\\" DEFAULT_MEMCARD2); - Edit_SetText(GetDlgItem(hW,IDC_MCD1), Config.Mcd1); - Edit_SetText(GetDlgItem(hW,IDC_MCD2), Config.Mcd2); - - //MC1.Load(Config.Mcd1); - //MC2.Load(Config.Mcd2); - - //MC1.AddCardToTreeView(GetDlgItem(hW, IDC_TREE1)); - //MC2.AddCardToTreeView(GetDlgItem(hW, IDC_TREE2)); - - //MC1.AddToListView(GetDlgItem(hW,IDC_LIST1)); - //MC2.AddToListView(GetDlgItem(hW,IDC_LIST2)); - - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - - case IDC_MCDSEL1: - Open_Mcd_Proc(hW, 1); - return TRUE; - - case IDC_MCDSEL2: - Open_Mcd_Proc(hW, 2); - return TRUE; - - case IDCANCEL: - { - EndDialog(hW,FALSE); - return TRUE; - } - - case IDOK: - Edit_GetText(GetDlgItem(hW,IDC_MCD1), Config.Mcd1, 256); - Edit_GetText(GetDlgItem(hW,IDC_MCD2), Config.Mcd2, 256); -// SaveConfig(); - - EndDialog(hW,TRUE); - return TRUE; - - case IDC_RELOAD1: - { - char cardname[1024]; - Edit_GetText(GetDlgItem(hW, IDC_MCD1), cardname, 1024); - MC1.Load(cardname); - MC1.AddToListView(GetDlgItem(hW,IDC_LIST1)); - //MC1.AddCardToTreeView(GetDlgItem(hW,IDC_TREE1)); - break; - } - - case IDC_RELOAD2: - { - char cardname[1024]; - Edit_GetText(GetDlgItem(hW, IDC_MCD2), cardname, 1024); - MC2.Load(cardname); - MC2.AddToListView(GetDlgItem(hW,IDC_LIST2)); - //MC2.AddCardToTreeView(GetDlgItem(hW,IDC_TREE2)); - break; - } - - case IDC_LOADICO1: - { - char cardname[1024]; - MC1.SaveRootDir("test"); - Edit_GetText(GetDlgItem(hW, IDC_MCD1), cardname, 1024); - MC1.Load(cardname); - MC1.AddToListView(GetDlgItem(hW,IDC_LIST1)); - /* - char dir[256], name[256]; - if(GetTreeViewSelection(GetDlgItem(mcdDlg, IDC_TREE1), dir, name)) - MC1.PaintICOFile(GetDlgItem(mcdDlg, IDC_ICON1), dir, name); - else - MessageBox(mcdDlg, "Please select a file.", "Error", 0); - */ - break; - } - - case IDC_LOADICO2: - { - /* - char dir[256], name[256]; - if(GetTreeViewSelection(GetDlgItem(mcdDlg, IDC_TREE2), dir, name)) - MC1.PaintICOFile(GetDlgItem(mcdDlg, IDC_ICON2), dir, name); - else - MessageBox(mcdDlg, "Please select a file.", "Error", 0); - */ - break; - } - - case IDC_SAVE1: - { - /* - char dir[256], name[256]; - if(GetTreeViewSelection(GetDlgItem(mcdDlg, IDC_TREE1), dir, name)) - SaveFileDialog(mcdDlg, 1, dir, name); - else - MessageBox(mcdDlg, "Please select a file.", "Error", 0); - */ - break; - } - - case IDC_SAVE2: - { - /* - char dir[256], name[256]; - if(GetTreeViewSelection(GetDlgItem(mcdDlg, IDC_TREE2), dir, name)) - SaveFileDialog(mcdDlg, 2, dir, name); - else - MessageBox(mcdDlg, "Please select a file.", "Error", 0); - */ - break; - } - } - case WM_DESTROY: - return TRUE; - } - return FALSE; -} - - - - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" +#include "Win32.h" + +#include +#include +#include "libintlmsc.h" + +#include "System.h" +#include "McdsDlg.h" + +#include +using namespace std; + + +u16 SJISTable[0xFFFF]; + + +void IniSJISTable() +{ + memzero_obj(SJISTable); + //Blow me sony for using this retarded sjis to store the savegame name + SJISTable[0x20] = 0x0020; + SJISTable[0x21] = 0x0021; + SJISTable[0x22] = 0x0022; + SJISTable[0x23] = 0x0023; + SJISTable[0x24] = 0x0024; + SJISTable[0x25] = 0x0025; + SJISTable[0x26] = 0x0026; + SJISTable[0x27] = 0x0027; + SJISTable[0x28] = 0x0028; + SJISTable[0x29] = 0x0029; + SJISTable[0x2A] = 0x002A; + SJISTable[0x2B] = 0x002B; + SJISTable[0x2C] = 0x002C; + SJISTable[0x2D] = 0x002D; + SJISTable[0x2E] = 0x002E; + SJISTable[0x2F] = 0x002F; + SJISTable[0x30] = 0x0030; + SJISTable[0x31] = 0x0031; + SJISTable[0x32] = 0x0032; + SJISTable[0x33] = 0x0033; + SJISTable[0x34] = 0x0034; + SJISTable[0x35] = 0x0035; + SJISTable[0x36] = 0x0036; + SJISTable[0x37] = 0x0037; + SJISTable[0x38] = 0x0038; + SJISTable[0x39] = 0x0039; + SJISTable[0x3A] = 0x003A; + SJISTable[0x3B] = 0x003B; + SJISTable[0x3C] = 0x003C; + SJISTable[0x3D] = 0x003D; + SJISTable[0x3E] = 0x003E; + SJISTable[0x3F] = 0x003F; + SJISTable[0x40] = 0x0040; + SJISTable[0x41] = 0x0041; + SJISTable[0x42] = 0x0042; + SJISTable[0x43] = 0x0043; + SJISTable[0x44] = 0x0044; + SJISTable[0x45] = 0x0045; + SJISTable[0x46] = 0x0046; + SJISTable[0x47] = 0x0047; + SJISTable[0x48] = 0x0048; + SJISTable[0x49] = 0x0049; + SJISTable[0x4A] = 0x004A; + SJISTable[0x4B] = 0x004B; + SJISTable[0x4C] = 0x004C; + SJISTable[0x4D] = 0x004D; + SJISTable[0x4E] = 0x004E; + SJISTable[0x4F] = 0x004F; + SJISTable[0x50] = 0x0050; + SJISTable[0x51] = 0x0051; + SJISTable[0x52] = 0x0052; + SJISTable[0x53] = 0x0053; + SJISTable[0x54] = 0x0054; + SJISTable[0x55] = 0x0055; + SJISTable[0x56] = 0x0056; + SJISTable[0x57] = 0x0057; + SJISTable[0x58] = 0x0058; + SJISTable[0x59] = 0x0059; + SJISTable[0x5A] = 0x005A; + SJISTable[0x5B] = 0x005B; + SJISTable[0x5C] = 0x00A5; + SJISTable[0x5D] = 0x005D; + SJISTable[0x5E] = 0x005E; + SJISTable[0x5F] = 0x005F; + SJISTable[0x60] = 0x0060; + SJISTable[0x61] = 0x0061; + SJISTable[0x62] = 0x0062; + SJISTable[0x63] = 0x0063; + SJISTable[0x64] = 0x0064; + SJISTable[0x65] = 0x0065; + SJISTable[0x66] = 0x0066; + SJISTable[0x67] = 0x0067; + SJISTable[0x68] = 0x0068; + SJISTable[0x69] = 0x0069; + SJISTable[0x6A] = 0x006A; + SJISTable[0x6B] = 0x006B; + SJISTable[0x6C] = 0x006C; + SJISTable[0x6D] = 0x006D; + SJISTable[0x6E] = 0x006E; + SJISTable[0x6F] = 0x006F; + SJISTable[0x70] = 0x0070; + SJISTable[0x71] = 0x0071; + SJISTable[0x72] = 0x0072; + SJISTable[0x73] = 0x0073; + SJISTable[0x74] = 0x0074; + SJISTable[0x75] = 0x0075; + SJISTable[0x76] = 0x0076; + SJISTable[0x77] = 0x0077; + SJISTable[0x78] = 0x0078; + SJISTable[0x79] = 0x0079; + SJISTable[0x7A] = 0x007A; + SJISTable[0x7B] = 0x007B; + SJISTable[0x7C] = 0x007C; + SJISTable[0x7D] = 0x007D; + SJISTable[0x7E] = 0x007E; + + SJISTable[0x8140] = 0x0020; + SJISTable[0x8149] = 0x0021; + SJISTable[0x22] = 0x0022; + SJISTable[0x8194] = 0x0023; + SJISTable[0x8190] = 0x0024; + SJISTable[0x8193] = 0x0025; + SJISTable[0x8195] = 0x0026; + SJISTable[0x27] = 0x0027; + SJISTable[0x8169] = 0x0028; + SJISTable[0x816A] = 0x0029; + SJISTable[0x8196] = 0x002A; + SJISTable[0x817B] = 0x002B; + SJISTable[0x8143] = 0x002C; + SJISTable[0x815D] = 0x002D; + SJISTable[0x8144] = 0x002E; + SJISTable[0x815E] = 0x002F; + SJISTable[0x824F] = 0x0030; + SJISTable[0x8250] = 0x0031; + SJISTable[0x8251] = 0x0032; + SJISTable[0x8252] = 0x0033; + SJISTable[0x8253] = 0x0034; + SJISTable[0x8254] = 0x0035; + SJISTable[0x8255] = 0x0036; + SJISTable[0x8256] = 0x0037; + SJISTable[0x8257] = 0x0038; + SJISTable[0x8258] = 0x0039; + SJISTable[0x8146] = 0x003A; + SJISTable[0x8147] = 0x003B; + SJISTable[0x8183] = 0x003C; + SJISTable[0x8181] = 0x003D; + SJISTable[0x8184] = 0x003E; + SJISTable[0x8148] = 0x003F; + SJISTable[0x8197] = 0x0040; + SJISTable[0x8260] = 0x0041; + SJISTable[0x8261] = 0x0042; + SJISTable[0x8262] = 0x0043; + SJISTable[0x8263] = 0x0044; + SJISTable[0x8264] = 0x0045; + SJISTable[0x8265] = 0x0046; + SJISTable[0x8266] = 0x0047; + SJISTable[0x8267] = 0x0048; + SJISTable[0x8268] = 0x0049; + SJISTable[0x8269] = 0x004A; + SJISTable[0x826A] = 0x004B; + SJISTable[0x826B] = 0x004C; + SJISTable[0x826C] = 0x004D; + SJISTable[0x826D] = 0x004E; + SJISTable[0x826E] = 0x004F; + SJISTable[0x826F] = 0x0050; + SJISTable[0x8270] = 0x0051; + SJISTable[0x8271] = 0x0052; + SJISTable[0x8272] = 0x0053; + SJISTable[0x8273] = 0x0054; + SJISTable[0x8274] = 0x0055; + SJISTable[0x8275] = 0x0056; + SJISTable[0x8276] = 0x0057; + SJISTable[0x8277] = 0x0058; + SJISTable[0x8278] = 0x0059; + SJISTable[0x8279] = 0x005A; + SJISTable[0x816D] = 0x005B; + SJISTable[0x818F] = 0x00A5; + SJISTable[0x816E] = 0x005D; + SJISTable[0x814F] = 0x005E; + SJISTable[0x8151] = 0x005F; + SJISTable[0x814D] = 0x0060; + SJISTable[0x8281] = 0x0061; + SJISTable[0x8282] = 0x0062; + SJISTable[0x8283] = 0x0063; + SJISTable[0x8284] = 0x0064; + SJISTable[0x8285] = 0x0065; + SJISTable[0x8286] = 0x0066; + SJISTable[0x8287] = 0x0067; + SJISTable[0x8288] = 0x0068; + SJISTable[0x8289] = 0x0069; + SJISTable[0x828A] = 0x006A; + SJISTable[0x828B] = 0x006B; + SJISTable[0x828C] = 0x006C; + SJISTable[0x828D] = 0x006D; + SJISTable[0x828E] = 0x006E; + SJISTable[0x828F] = 0x006F; + SJISTable[0x8290] = 0x0070; + SJISTable[0x8291] = 0x0071; + SJISTable[0x8292] = 0x0072; + SJISTable[0x8293] = 0x0073; + SJISTable[0x8294] = 0x0074; + SJISTable[0x8295] = 0x0075; + SJISTable[0x8296] = 0x0076; + SJISTable[0x8297] = 0x0077; + SJISTable[0x8298] = 0x0078; + SJISTable[0x8299] = 0x0079; + SJISTable[0x829A] = 0x007A; + SJISTable[0x816F] = 0x007B; + SJISTable[0x8162] = 0x007C; + SJISTable[0x8170] = 0x007D; + SJISTable[0x7E] = 0x007E; +} + + +HWND mcdDlg; +HTREEITEM root; +HWND treewindow; + +HTREEITEM AddTreeItem(HWND treeview, HTREEITEM parent, const char *name, LPARAM lp) +{ + TVINSERTSTRUCT node={ + parent, + 0, + { + TVIF_TEXT, + NULL, + TVIS_EXPANDED, + TVIS_EXPANDED, + (LPSTR)name, + 0, + 0, + 0, + 0, + lp, + 1 + } + }; + return TreeView_InsertItem(treeview,&node); +} + +void ReadDir(int cluster, int rec, HTREEITEM tree); + + +class Time +{ + public: + u8 sec; + u8 min; + u8 hour; + u8 day; + u8 month; + u16 year; +}; + + +class Dir +{ + protected: + + + public: + static const u16 DF_READ = 0x0001; + static const u16 DF_WRITE = 0x0002; + static const u16 DF_EXECUTE = 0x0004; + static const u16 DF_PROTECTED = 0x0008; + static const u16 DF_FILE = 0x0010; + static const u16 DF_DIRECTORY = 0x0020; + static const u16 DF_HIDDEN = 0x2000; + static const u16 DF_EXISTS = 0x8000; + + // Directory Attributes + u16 Mode; + s32 Lenght; + Time Created; + s32 Cluster; + u32 DirEntry; + Time Modified; + u32 Attribute; + s8 Name[256]; // just in case some names are longer + + // Parent dir and contents of dir + Dir *Parent; + vector Sons; + + // Used to store the contents of a file + u8 *File; + + Dir() + { + File = 0; + } + + bool IsHidden() + { + return (Mode & DF_HIDDEN) ? 1 : 0; + } + + bool IsFile() + { + return (Mode & DF_FILE) ? 1 : 0; + } + + bool IsDirectory() + { + return (Mode & DF_DIRECTORY) ? 1 : 0; + } + + bool Exists() + { + return (Mode & DF_EXISTS) ? 1 : 0; + } + + void Load(s8 *d) + { + File = 0; + // For the moment we dont need to load more data + Mode = *(u16 *)d; + Lenght = *(u32 *)(d + 0x04); + Cluster = *(u32 *)(d + 0x10); + strncpy(Name, d + 0x40, 255); + } + + Dir* AddSon(Dir &d) + { + d.Parent = this; + vector::iterator i = Sons.insert(Sons.end(), d); + return &i[0]; + } + + void Release() + { + for(unsigned int i=0;iFile + 12); + u32 NumVertex = *(u32 *)(File + 16); + + // Check if it's an ico file + if(FileID != 0x00010000) + { + MessageBox(mcdDlg, "It's not an ICO file.", "Error", 0); + return 0; + } + + // Is texture compressed? + if(TextureType != 0x07) + { + //MessageBox(mcdDlg, "Compressed texture, not yet supported.", "Error", 0); + //return; + } + + // Calculate the offset to the animation segment + u32 VertexSize = (AnimationShapes * 8) + 8 + 8; + u32 AnimationSegmentOffset = (VertexSize * NumVertex) + 20; + + // Check if we really are at the animation header + u32 AnimationID = *(u32 *)(File + AnimationSegmentOffset); + if(AnimationID != 0x00000001) + { + MessageBox(mcdDlg, "Animation header ID is incorrect.", "Error", 0); + return 0; + } + + // Get the size of all the animation segment + u32 FrameLenght = *(u32 *)(File + AnimationSegmentOffset + 4); + u32 NumberOfFrames = *(u32 *)(File + AnimationSegmentOffset + 16); + + u32 Offset = AnimationSegmentOffset + 20; + for(u32 i=0;i 0x07) + { + u32 CompressedDataSize = *(u32 *)(File + Offset); + //RLE compression + + Offset += 4; + u32 OffsetEnd = Offset + CompressedDataSize; + u32 WriteCount = 0; + + while(WriteCount < 0x8000 && Offset < OffsetEnd) + { + + u16 Data = *(u16 *)(File + Offset); + + if(Data < 0xFF00) //Replication + { + Offset += 2; + u16 Rep = *(u16 *)(File + Offset); + + for(int i=0;iLenght-0x8000*/Offset], 0x8000); + } + + // Convert from TIM to rgb + for(z=0;z<0x4000;z++) + { + dest[y] = 8 * (ico[z] & 0x1F); + dest[y+1] = 8 * ((ico[z] >>5) & 0x1F); + dest[y+2] = 8 * (ico[z] >>10); + y += 3; + } + + return 1; + } + +}; + + +class SaveGame +{ + public: + + Dir *D; + char Name1[256]; + char Name2[256]; + + u8 Icon[128*128*3]; + + + SaveGame(Dir *_Dir) + { + char IconName[256]; + + D = _Dir; + + // Find icon.sys + for(unsigned int i=0;iSons.size();i++) + { + if(!strcmp("icon.sys", D->Sons[i].Name)) + { + char temp[256]; + + // Get Name in SJIS format + u16 *p = (u16 *)(D->Sons[i].File + 192); + + while(*p != 0x0000) + { + // Switch bytes + u8 *pp = (u8 *)p; + u8 tb = *pp; + *pp = pp[1]; + pp[1] = tb; + + // Translate char + *p = SJISTable[*p]; + + p++; + } + + // Convert unicode string + wcstombs(temp, (wchar_t *)(D->Sons[i].File + 192), 255); + + // Get the second line separator + u16 SecondLine = *(u16 *)(D->Sons[i].File + 6); + SecondLine /= 2; + + // Copy the 2 parts of the string to different strings + strncpy(Name1, temp, SecondLine); + Name1[SecondLine] = 0; + + strcpy(Name2, &temp[SecondLine]); + if(strlen(Name2) + SecondLine > 68) + Name2[0] = 0; + + // Get the icon file name + strcpy(IconName, (char *)D->Sons[i].File + 260); + + } + } + + // Find the icon now + for(unsigned int i=0;iSons.size();i++) + { + if(!strcmp(IconName, D->Sons[i].Name)) + { + D->Sons[i].BuildICO((char*)Icon); + } + + } + } + + void AddIcoToImageList(HIMAGELIST il) + { + + HDC hDC = GetDC(NULL); + HDC memDC = CreateCompatibleDC (hDC); + HBITMAP memBM = CreateCompatibleBitmap ( hDC, 128, 128 ); + SelectObject ( memDC, memBM ); + + int px, py, pc=0; + for(px=0;px<128;px++){ + for(py=0;py<128;py++){ + SetPixel(memDC, py, px, RGB(Icon[pc], Icon[pc+1], Icon[pc+2])); + pc+=3; + } + } + + HDC memDC2 = CreateCompatibleDC (hDC); + HBITMAP memBM2 = CreateCompatibleBitmap ( hDC, 64, 64 ); + SelectObject ( memDC2, memBM2 ); + SetStretchBltMode(memDC2, HALFTONE); + StretchBlt(memDC2, 0, 0, 64, 64, memDC, 0, 0, 128, 128, SRCCOPY); + + DeleteDC(memDC2); + DeleteDC(memDC); + ImageList_Add(il, memBM2, NULL); + DeleteObject(memBM); + DeleteObject(memBM2); + ReleaseDC(NULL, hDC); + + + } + + void DrawICO(HWND hWnd) + { + // int px, py, pc=0; + HDC dc = GetDC(hWnd); + /* + for(px=0;px<128;px++){ + for(py=0;py<128;py++){ + SetPixel(dc, py, px, RGB(Icon[pc], Icon[pc+1], Icon[pc+2])); + pc+=3; + + } + } +*/ + /* + HDC hDC = GetDC(NULL); + HDC memDC = CreateCompatibleDC ( hDC ); + HBITMAP memBM = CreateCompatibleBitmap ( hDC, 256, 128 ); + SelectObject ( memDC, memBM ); + for(px=0;px<128;px++){ + for(py=0;py<128;py++){ + SetPixel(memDC, py, px, RGB(Icon[pc], Icon[pc+1], Icon[pc+2])); + pc+=3; + + } + } + RECT rect; + rect.left=132; + rect.right=255; + rect.top=4; + rect.bottom=255; + DrawText(memDC, Name1, strlen(Name1), &rect, 0); + rect.top=20; + DrawText(memDC, Name2, strlen(Name2), &rect, 0); + + + SetStretchBltMode(dc, HALFTONE); + StretchBlt(dc, 0, 0, 64, 64, memDC, 0, 0, 128, 128, SRCCOPY); + //BitBlt(dc, 0, 0, 256, 128, memDC, 0, 0, SRCCOPY); + */ + } + +}; + + +class MemoryCard +{ + public: + FILE *fp; + int FAT[256*256]; + int indirect_table[256]; + char FileName[1024]; + Dir Root; + vector SaveGameList; + HIMAGELIST ImageList; + + MemoryCard() + { + fp = 0; + ImageList = 0; + } + + int BuildFAT() + { + int IFC; + // indirect table containing the clusters with FAT data + int i, o; + + // First read IFC from the superblock (8MB cards only have 1) + fseek(fp, 0x50, SEEK_SET); + fread(&IFC, 4, 1, fp); + + if(IFC != 8) + { + MessageBox(mcdDlg, "IFC is not 8. Memory Card is probably corrupt.", "Error", 0); + return 0; + } + + DbgCon::WriteLn("IFC: %d", params IFC); + + // Read the cluster with the indirect data to the FAT. + fseek(fp, 0x420 * IFC, SEEK_SET); + fread(indirect_table, 4, 128, fp); + fseek(fp, (0x420 * IFC) + 0x210, SEEK_SET); + fread(&indirect_table[128], 4, 128, fp); + + // Build the FAT table from the indirect_table + o = 0; + i = 0; + + while(indirect_table[i] != 0xFFFFFFFF) + { + + fseek(fp, 0x420 * indirect_table[i], SEEK_SET); + fread(&FAT[o], 4, 128, fp); + o+=128; + + fseek(fp, (0x420 * indirect_table[i]) + 0x210, SEEK_SET); + fread(&FAT[o], 4, 128, fp); + o+=128; + + i++; + } + return 1; + } + + void ReadFile(Dir *d) + { + + int cluster = d->Cluster; + int size = d->Lenght; + int numclusters = (int)ceil((double)size / 1024); + int numpages = (int)ceil((double)size / 512); + int i=0, j=0, c=0, read=0; + d->File = (u8 *) malloc(size); + + + for(i=0;i 512) + read = 512; + + fseek(fp, 0xA920 + ((cluster) * 0x420), SEEK_SET); + fread(&d->File[c], 1, read, fp); + c+=read; + j++; + if(j == numpages) + break; + + read = size - c; + if(read > 512) + read = 512; + + fseek(fp, 0xA920 + (((cluster) * 0x420)+528), SEEK_SET); + fread(&d->File[c], 1, read, fp); + c+=read; + j++; + if(j == numpages) + break; + + cluster = FAT[cluster]; + cluster = cluster ^ 0x80000000; + if(cluster == 0x7FFFFFFF || cluster == 0xFFFFFFFF) + break; + } + + } + + void Read(u32 cluster, Dir *d) + { + int i; + s8 file1[512], file2[512]; + Dir D1, D2; + + for(i = 0; i < 0xffff; i++) + { + + // Read first page containing the first dir + fseek(fp, 0xA920 + ((cluster) * 0x420), SEEK_SET); + fread(file1, 1, 512, fp); + // Initialize the temporal dir + D1.Load(file1); + if(D1.Exists() && D1.Lenght >= 0 && D1.Cluster >= 0) + { + // If it exists add the dir to current dir + Dir *td = d->AddSon(D1); + + // If it's a directory and not . or .. recursive call + if(D1.IsDirectory() && D1.Name[0]!= '.' ) + { + Read(td->Cluster, td); + } + + // If it's a file load the file + if(D1.IsFile()) + { + ReadFile(td); + } + } + + + // Read second page with second dir or empty + fseek(fp, 0xA920 + (((cluster) * 0x420) + 528), SEEK_SET); + fread(file2, 1, 512, fp); + // Initialize the temporal dir and add it to current dir + D2.Load(file2); + if(D2.Exists() && D2.Lenght >= 0 && D2.Cluster >= 0) + { + Dir *td = d->AddSon(D2); + + if(D2.IsDirectory() && D2.Name[0]!= '.') + { + Read(td->Cluster, td); + } + + // If it's a file load the file + if(D2.IsFile() && D2.Name[0]!= '.') + { + ReadFile(td); + } + } + + // Get next cluster from the FAT table + cluster = FAT[cluster]; + cluster = cluster ^ 0x80000000; + if(cluster == 0x7FFFFFFF || cluster == 0xFFFFFFFF) + break; + } + + } + + void Load(char *filename) + { + strcpy(FileName, filename); + + // Clear previous data + if(fp != 0) + { + fclose(fp); + } + memzero_obj(FAT); + Root.Release(); + + SaveGameList.clear(); + ImageList_Destroy(ImageList); + + // Open memory card file + fp = fopen(FileName, "rb"); + + // Check if we opened the file + if(fp == NULL) + { + MessageBox(mcdDlg, "Unable to open memory card file.", "Error", 0); + return; + } + + // Build the FAT table for the card + if(BuildFAT() == 1) + { + // Read the root dir + Read(0, &Root); + } + + fclose(fp); + + ReadSaveGames(); + } + + void AddDirToTreeView(HWND hWnd, HTREEITEM tree, Dir *d) + { + for(unsigned int i=0;iSons.size();i++) + { + HTREEITEM temptree = AddTreeItem(hWnd, tree, d->Sons[i].Name, 0); + if(d->Sons[i].IsDirectory()) + { + TreeView_SetItemState(hWnd, temptree, TVIS_EXPANDED|TVIS_BOLD, 0x00F0); + AddDirToTreeView(hWnd, temptree, &d->Sons[i]); + } + } + } + + void AddToListView(HWND hWnd) + { + ListView_SetIconSpacing(hWnd, 128, 128); + ListView_DeleteAllItems(hWnd); + ListView_SetImageList(hWnd, ImageList, LVSIL_NORMAL); + + LVITEM item; + char temp[2560]; + item.mask = LVIF_IMAGE | LVIF_TEXT; + item.iItem = 0; + item.iSubItem = 0; + item.state = 0; + item.stateMask = 0; + item.pszText = temp; + item.cchTextMax = 255; + item.iImage = 1; + item.iIndent = 0; + item.lParam = 0; + + for(unsigned int i=0;iSons.size();i++) + { + if(!strcmp(file, d->Sons[i].Name)) + break; + } + + if(i == d->Sons.size()) + { + MessageBox(mcdDlg, "Unable to find the file.", "Error", 0); + return NULL; + } + + return &d->Sons[i]; + } + + void PaintICOFile(HWND hWnd, char *dir, char *name) + { + // First find the file + Dir *d = FindFile(dir, name); + if(d == NULL) + return; + + + + u32 FileID = *(u32 *)d->File; + u32 AnimationShapes = *(u32 *)(d->File + 4); + u32 TextureType = *(u32 *)(d->File + 8); + //u32 ConstantCheck = *(u32 *)(d->File + 12); + u32 NumVertex = *(u32 *)(d->File + 16); + + // Check if it's an ico file + if(FileID != 0x00010000) + { + MessageBox(mcdDlg, "It's not an ICO file.", "Error", 0); + return; + } + + // Is texture compressed? + if(TextureType != 0x07) + { + //MessageBox(mcdDlg, "Compressed texture, not yet supported.", "Error", 0); + //return; + } + + // Calculate the offset to the animation segment + u32 VertexSize = (AnimationShapes * 8) + 8 + 8; + u32 AnimationSegmentOffset = (VertexSize * NumVertex) + 20; + + // Check if we really are at the animation header + u32 AnimationID = *(u32 *)(d->File + AnimationSegmentOffset); + if(AnimationID != 0x00000001) + { + MessageBox(mcdDlg, "Animation header ID is incorrect.", "Error", 0); + return; + } + + // Get the size of all the animation segment + u32 FrameLenght = *(u32 *)(d->File + AnimationSegmentOffset + 4); + u32 NumberOfFrames = *(u32 *)(d->File + AnimationSegmentOffset + 16); + + u32 Offset = AnimationSegmentOffset + 20; + for(unsigned int i=0;iFile + Offset + 4); + Offset += 16 + (KeyNum * 8) - 8; // The -8 is there because the doc with the ico format spec is either wrong or I'm stupid + } + + int z, y=0; + u16 ico[0x4000]; + u8 cico[128*128*3]; + + if(TextureType > 0x07) + { + u32 CompressedDataSize = *(u32 *)(d->File + Offset); + //RLE compression + + Offset += 4; + u32 OffsetEnd = Offset + CompressedDataSize; + u32 WriteCount = 0; + + while(WriteCount < 0x8000 && Offset < OffsetEnd) + { + + u16 Data = *(u16 *)(d->File + Offset); + + if(Data < 0xFF00) //Replication + { + Offset += 2; + u16 Rep = *(u16 *)(d->File + Offset); + + for(int i=0;iFile + Offset); + WriteCount++; + Offset += 2; + } + } + + } + + } + else + { + // Get the texture from the file + memcpy(ico, &d->File[/*d->Lenght-0x8000*/Offset], 0x8000); + } + + // Convert from TIM to rgb + for(z=0;z<0x4000;z++) + { + cico[y] = 8 * (ico[z] & 0x1F); + cico[y+1] = 8 * ((ico[z] >>5) & 0x1F); + cico[y+2] = 8 * (ico[z] >>10); + y += 3; + } + + // Draw + int px, py, pc=0; + HDC dc = GetDC(hWnd); + for(px=0;px<128;px++){ + for(py=0;py<128;py++){ + SetPixel(dc, py, px, RGB(cico[pc], cico[pc+1], cico[pc+2])); + pc+=3; + + } + } + } + + + void ReadSaveGames() + { + // Initialize the conversion table for SJIS strings + IniSJISTable(); + + // Create the image list + ImageList = ImageList_Create(64, 64, ILC_COLOR32, 10, 256); + + for(unsigned int i=0;iSons.size(); // number of files inside the dir + *(u8 *)&dir[8] = 0; // creation time seconds + *(u8 *)&dir[9] = 0; // creation time minuts + *(u8 *)&dir[10] = 0; // creation time hours + *(u8 *)&dir[11] = 1; // creation time day + *(u8 *)&dir[12] = 1; // creation time month + *(u16 *)&dir[13] = 2008; // creation time year + *(u32 *)&dir[16] = dircluster; // cluster with the contents of the dir + *(u32 *)&dir[20] = 0; // dir entry for '.' + *(u8 *)&dir[24] = 0; // modification time seconds + *(u8 *)&dir[25] = 0; // modification time minuts + *(u8 *)&dir[26] = 0; // modification time hours + *(u8 *)&dir[27] = 1; // modification time day + *(u8 *)&dir[28] = 1; // modification time month + *(u16 *)&dir[29] = 2008; // modification time year + *(u32 *)&dir[32] = 0; // user attribute unused + strcpy(&dir[64], Di->Name); // DIRECTORY NAME + + + if(Lenght % 2) + { + // Find empty cluster... + int c = FindEmptyCluster(); + + // THIS MAY BE WRONG...TEST + FAT[oldcluster] = c; + FAT[c] = 0xFFFFFFFF; + + // Add dir to first page of new cluster + fseek(fp, 0xA920 + (((c) * 0x420) + 0), SEEK_SET); + fwrite(dir, 512, 1, fp); + } + else + { + // Add dir to second page of cluster + fseek(fp, 0xA920 + (((oldcluster) * 0x420) + 528), SEEK_SET); + fwrite(dir, 512, 1, fp); + } + + // CALCULATE CRCS OF CLUSTER + + + // INCREASE ROOT DIR SIZE BY 1 + fseek(fp, 0xA920 + (((0) * 0x420) + 4), SEEK_SET); + int nl = Lenght + 1; + fwrite(&nl, 4, 1, fp); + + + int numfiles = 5; + + // ADD FILE ENTRIES TO DIR ., .. + memzero_obj(dir); + *(u16 *)&dir[0] = Dir::DF_EXISTS | Dir::DF_DIRECTORY | Dir::DF_READ; // mode flag + *(u32 *)&dir[4] = numfiles; // number of files inside the dir + *(u8 *)&dir[8] = 0; // creation time seconds + *(u8 *)&dir[9] = 0; // creation time minuts + *(u8 *)&dir[10] = 0; // creation time hours + *(u8 *)&dir[11] = 1; // creation time day + *(u8 *)&dir[12] = 1; // creation time month + *(u16 *)&dir[13] = 2008; // creation time year + *(u32 *)&dir[16] = 0; // cluster with the contents of the dir + *(u32 *)&dir[20] = 0; // dir entry for '.' + *(u8 *)&dir[24] = 0; // modification time seconds + *(u8 *)&dir[25] = 0; // modification time minuts + *(u8 *)&dir[26] = 0; // modification time hours + *(u8 *)&dir[27] = 1; // modification time day + *(u8 *)&dir[28] = 1; // modification time month + *(u16 *)&dir[29] = 2008; // modification time year + *(u32 *)&dir[32] = 0; // user attribute unused + strcpy(&dir[64], "."); // DIRECTORY NAME + fseek(fp, 0xA920 + (((dircluster) * 0x420) + 0), SEEK_SET); + fwrite(dir, 512, 1, fp); + + memzero_obj(dir); + *(u16 *)&dir[0] = Dir::DF_EXISTS | Dir::DF_DIRECTORY | Dir::DF_READ; // mode flag + *(u32 *)&dir[4] = 2; // number of files inside the dir + *(u8 *)&dir[8] = 0; // creation time seconds + *(u8 *)&dir[9] = 0; // creation time minuts + *(u8 *)&dir[10] = 0; // creation time hours + *(u8 *)&dir[11] = 1; // creation time day + *(u8 *)&dir[12] = 1; // creation time month + *(u16 *)&dir[13] = 2008; // creation time year + *(u32 *)&dir[16] = 0; // cluster with the contents of the dir + *(u32 *)&dir[20] = 0; // dir entry for '.' + *(u8 *)&dir[24] = 0; // modification time seconds + *(u8 *)&dir[25] = 0; // modification time minuts + *(u8 *)&dir[26] = 0; // modification time hours + *(u8 *)&dir[27] = 1; // modification time day + *(u8 *)&dir[28] = 1; // modification time month + *(u16 *)&dir[29] = 2008; // modification time year + *(u32 *)&dir[32] = 0; // user attribute unused + strcpy(&dir[64], ".."); // DIRECTORY NAME + fseek(fp, 0xA920 + (((dircluster) * 0x420) + 528), SEEK_SET); + fwrite(dir, 512, 1, fp); + + FAT[dircluster] = 0xFFFFFFFF; + + + // ADD REST OF FILES + + for(int i=2;iFile, d->Lenght, 1, fp); + fclose(fp); + } + } +} + + + +FILE *fp; + +BOOL CALLBACK ConfigureMcdsDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + mcdDlg = hW; + + SetWindowText(hW, _("Memcard Manager")); + + Button_SetText(GetDlgItem(hW, IDOK), _("OK")); + Button_SetText(GetDlgItem(hW, IDCANCEL), _("Cancel")); + Button_SetText(GetDlgItem(hW, IDC_MCDSEL1), _("Select Mcd")); + Button_SetText(GetDlgItem(hW, IDC_MCDSEL2), _("Select Mcd")); + + Static_SetText(GetDlgItem(hW, IDC_FRAMEMCD1), _("Memory Card 1")); + Static_SetText(GetDlgItem(hW, IDC_FRAMEMCD2), _("Memory Card 2")); + + if (!strlen(Config.Mcd1)) strcpy(Config.Mcd1, MEMCARDS_DIR "\\" DEFAULT_MEMCARD1); + if (!strlen(Config.Mcd2)) strcpy(Config.Mcd2, MEMCARDS_DIR "\\" DEFAULT_MEMCARD2); + Edit_SetText(GetDlgItem(hW,IDC_MCD1), Config.Mcd1); + Edit_SetText(GetDlgItem(hW,IDC_MCD2), Config.Mcd2); + + //MC1.Load(Config.Mcd1); + //MC2.Load(Config.Mcd2); + + //MC1.AddCardToTreeView(GetDlgItem(hW, IDC_TREE1)); + //MC2.AddCardToTreeView(GetDlgItem(hW, IDC_TREE2)); + + //MC1.AddToListView(GetDlgItem(hW,IDC_LIST1)); + //MC2.AddToListView(GetDlgItem(hW,IDC_LIST2)); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + + case IDC_MCDSEL1: + Open_Mcd_Proc(hW, 1); + return TRUE; + + case IDC_MCDSEL2: + Open_Mcd_Proc(hW, 2); + return TRUE; + + case IDCANCEL: + { + EndDialog(hW,FALSE); + return TRUE; + } + + case IDOK: + Edit_GetText(GetDlgItem(hW,IDC_MCD1), Config.Mcd1, 256); + Edit_GetText(GetDlgItem(hW,IDC_MCD2), Config.Mcd2, 256); +// SaveConfig(); + + EndDialog(hW,TRUE); + return TRUE; + + case IDC_RELOAD1: + { + char cardname[1024]; + Edit_GetText(GetDlgItem(hW, IDC_MCD1), cardname, 1024); + MC1.Load(cardname); + MC1.AddToListView(GetDlgItem(hW,IDC_LIST1)); + //MC1.AddCardToTreeView(GetDlgItem(hW,IDC_TREE1)); + break; + } + + case IDC_RELOAD2: + { + char cardname[1024]; + Edit_GetText(GetDlgItem(hW, IDC_MCD2), cardname, 1024); + MC2.Load(cardname); + MC2.AddToListView(GetDlgItem(hW,IDC_LIST2)); + //MC2.AddCardToTreeView(GetDlgItem(hW,IDC_TREE2)); + break; + } + + case IDC_LOADICO1: + { + char cardname[1024]; + MC1.SaveRootDir("test"); + Edit_GetText(GetDlgItem(hW, IDC_MCD1), cardname, 1024); + MC1.Load(cardname); + MC1.AddToListView(GetDlgItem(hW,IDC_LIST1)); + /* + char dir[256], name[256]; + if(GetTreeViewSelection(GetDlgItem(mcdDlg, IDC_TREE1), dir, name)) + MC1.PaintICOFile(GetDlgItem(mcdDlg, IDC_ICON1), dir, name); + else + MessageBox(mcdDlg, "Please select a file.", "Error", 0); + */ + break; + } + + case IDC_LOADICO2: + { + /* + char dir[256], name[256]; + if(GetTreeViewSelection(GetDlgItem(mcdDlg, IDC_TREE2), dir, name)) + MC1.PaintICOFile(GetDlgItem(mcdDlg, IDC_ICON2), dir, name); + else + MessageBox(mcdDlg, "Please select a file.", "Error", 0); + */ + break; + } + + case IDC_SAVE1: + { + /* + char dir[256], name[256]; + if(GetTreeViewSelection(GetDlgItem(mcdDlg, IDC_TREE1), dir, name)) + SaveFileDialog(mcdDlg, 1, dir, name); + else + MessageBox(mcdDlg, "Please select a file.", "Error", 0); + */ + break; + } + + case IDC_SAVE2: + { + /* + char dir[256], name[256]; + if(GetTreeViewSelection(GetDlgItem(mcdDlg, IDC_TREE2), dir, name)) + SaveFileDialog(mcdDlg, 2, dir, name); + else + MessageBox(mcdDlg, "Please select a file.", "Error", 0); + */ + break; + } + } + case WM_DESTROY: + return TRUE; + } + return FALSE; +} + + + + diff --git a/pcsx2/windows/McdsDlg.h b/pcsx2/windows/McdsDlg.h index 756100a311..dfbe2f7587 100644 --- a/pcsx2/windows/McdsDlg.h +++ b/pcsx2/windows/McdsDlg.h @@ -1,24 +1,24 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __MCDSDLG_H__ -#define __MCDSDLG_H__ - -BOOL CALLBACK ConfigureMcdsDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); - -#endif /* __MCDSDLG_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __MCDSDLG_H__ +#define __MCDSDLG_H__ + +BOOL CALLBACK ConfigureMcdsDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); + +#endif /* __MCDSDLG_H__ */ diff --git a/pcsx2/windows/PatchBrowser.cpp b/pcsx2/windows/PatchBrowser.cpp index 8c4cbb7d3f..90e380c1c8 100644 --- a/pcsx2/windows/PatchBrowser.cpp +++ b/pcsx2/windows/PatchBrowser.cpp @@ -1,352 +1,352 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -/************************** -* -* patchbrowser.c contains all the src of patchbrowser window -* no interaction with emulation code -***************************/ - -#include "Win32.h" -#include "Common.h" -#include "resource.h" - -/* - * TODO: - * - not topmost - * - resize stuff - * - ask to save in exit (check if changed) - */ -BOOL CALLBACK PatchBDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { - - int tmpi,i; - char fileName[MAX_PATH], *tmpStr; - FILE *fp; - - switch(uMsg) { - - case WM_INITDIALOG: - SetWindowText(hW, _("Patches Browser")); - Button_SetText(GetDlgItem(hW,IDC_REFRESHPATCHLIST), _("Refresh List")); - Button_SetText(GetDlgItem(hW,IDC_NEWPATCH), _("New Patch")); - Button_SetText(GetDlgItem(hW,IDC_SAVEPATCH), _("Save Patch")); - Button_SetText(GetDlgItem(hW,IDC_EXITPB), _("Exit")); - Static_SetText(GetDlgItem(hW,IDC_GAMENAMESEARCH), _("Search game name patch:")); - //List Patches - ListPatches ((HWND) hW); - return TRUE; - - case WM_COMMAND: - switch(LOWORD(wParam)) { - - case IDC_NEWPATCH: - - i = Save_Patch_Proc(fileName); - if ( i == FALSE || (fp = fopen(fileName,"a")) == NULL ) { - MessageBox(hW,(LPCTSTR)"Couldn't create the file.",NULL,(UINT)MB_ICONERROR); - return FALSE; - } - - fclose(fp); - i = MessageBox(hW,(LPCTSTR)"File created sucessfully.\nClear textbox?",NULL,(UINT)(MB_YESNO|MB_ICONQUESTION)); - if (i==IDYES) SetDlgItemText(hW, IDC_PATCHTEXT, (LPCTSTR)""); - - return TRUE; - - case IDC_SAVEPATCH: - - i = Save_Patch_Proc(fileName); - if ( i == FALSE || (fp = fopen(fileName,"w")) == NULL ) { - MessageBox(hW,(LPCTSTR)"Couldn't save the file.",NULL,(UINT)MB_ICONERROR); - return FALSE; - } - - tmpi = SendDlgItemMessage(hW, IDC_PATCHTEXT, EM_GETLINECOUNT, (WPARAM)NULL, (LPARAM)NULL); - i=0; - for (;tmpi>=0;tmpi--) - i += SendDlgItemMessage(hW, IDC_PATCHTEXT, EM_LINELENGTH, (WPARAM)tmpi, (LPARAM)NULL); - - tmpStr = (char *) malloc(i); - sprintf(tmpStr,""); - SendDlgItemMessage(hW, IDC_PATCHTEXT, WM_GETTEXT, (WPARAM)i, (LPARAM)tmpStr); - - //remove \r - for (i=0,tmpi=0; tmpStr[i]!='\0'; i++) - if (tmpStr[i] != '\r') - tmpStr[tmpi++] = tmpStr[i]; - tmpStr[tmpi] = '\0'; - - fputs(tmpStr,fp); - - fclose(fp); - free(tmpStr); - - MessageBox(hW,(LPCTSTR)"File saved sucessfully.",NULL,(UINT)MB_ICONINFORMATION); - - return TRUE; - - case IDC_REFRESHPATCHLIST: - - //List Patches - ListPatches ((HWND) hW); - - return TRUE; - - case IDC_EXITPB: - - //Close Dialog - EndDialog(hW, FALSE); - - return TRUE; - - case IDC_PATCHCRCLIST: - - //Get selected item - tmpi = SendDlgItemMessage(hW, IDC_PATCHCRCLIST, LB_GETCURSEL, 0, 0); - SendDlgItemMessage(hW, IDC_PATCHCRCLIST, LB_GETTEXT, (WPARAM)tmpi, (LPARAM)fileName); - - return ReadPatch ((HWND) hW, fileName); - - case IDC_PATCHNAMELIST: - - //Get selected item - tmpi = SendDlgItemMessage(hW, IDC_PATCHNAMELIST, LB_GETCURSEL, 0, 0); - SendDlgItemMessage(hW, IDC_PATCHNAMELIST, LB_GETTEXT, (WPARAM)tmpi, (LPARAM)fileName); - - //another small hack :p - //eg. SOCOM Demo PAL (7dd01dd9.pnach) - for (i=0;i<(int)strlen(fileName);i++) - if (fileName[i] == '(') tmpi = i; - - sprintf(fileName,"%c%c%c%c%c%c%c%c%c%c%c%c%c%c", - fileName[tmpi+1],fileName[tmpi+2],fileName[tmpi+3], - fileName[tmpi+4],fileName[tmpi+5],fileName[tmpi+6], - fileName[tmpi+7],fileName[tmpi+8],fileName[tmpi+9], - fileName[tmpi+10],fileName[tmpi+11],fileName[tmpi+12], - fileName[tmpi+13],fileName[tmpi+14]); - - //sanity check - if (fileName[tmpi+15] != ')') return FALSE; - - return ReadPatch ((HWND) hW, fileName); - - case IDC_SEARCHPATCHTEXT: - - //get text - SendDlgItemMessage(hW, IDC_SEARCHPATCHTEXT, EM_GETLINE, 0, (LPARAM)fileName); - //search - tmpi = SendDlgItemMessage(hW, IDC_PATCHNAMELIST, LB_FINDSTRING, (WPARAM)-1, (LPARAM)fileName); - //select match item - SendDlgItemMessage(hW, IDC_PATCHNAMELIST, LB_SETCURSEL, (WPARAM)tmpi, (LPARAM)NULL); - - return TRUE; - } - return TRUE; - - case WM_CLOSE: - EndDialog(hW, FALSE); - break; - - } - return FALSE; -} -void ListPatches (HWND hW) { - - int i, tmpi, filesize, totalPatch=0, totalSize=0; - char tmpStr[MAX_PATH], *fileData; - WIN32_FIND_DATA FindData; - HANDLE Find; - FILE *fp; - - //clear listbox's - SendDlgItemMessage(hW, IDC_PATCHCRCLIST, (UINT)LB_RESETCONTENT, (WPARAM)NULL, (LPARAM)NULL); - SendDlgItemMessage(hW, IDC_PATCHNAMELIST, (UINT)LB_RESETCONTENT, (WPARAM)NULL, (LPARAM)NULL); - - //sprintf(tmpStr,"%s*.pnach", Config.PatchDir) - sprintf(tmpStr, "patches\\*.pnach"); - - Find = FindFirstFile(tmpStr, &FindData); - - do { - if (Find==INVALID_HANDLE_VALUE) break; - - sprintf(tmpStr,"%s", FindData.cFileName); - - //add file name to crc list - SendDlgItemMessage(hW, IDC_PATCHCRCLIST, (UINT) LB_ADDSTRING, (WPARAM)NULL, (LPARAM)tmpStr); - - //sprintf(tmpStr,"%s%s", Config.PatchDir, FindData.cFileName) - sprintf(tmpStr,"patches\\%s", FindData.cFileName); - - fp = fopen(tmpStr, "r"); - if (fp == NULL) break; - - fseek(fp, 0, SEEK_END); - filesize = ftell(fp); - totalSize += filesize; - fseek(fp, 0, SEEK_SET); - - fileData = (char *) malloc(filesize+1024); - sprintf(fileData,""); - - //read file - while((tmpi=fgetc(fp)) != EOF) - sprintf(fileData,"%s%c",fileData,tmpi); - - //small hack :p - for(i=0;ii;tmpi--) - fileData[tmpi] = fileData[tmpi-1]; - fileData[i] = '\r'; - fileData[i+1] = '\n'; - i++; - } - } - - SetDlgItemText(hW, IDC_PATCHTEXT, (LPCTSTR)fileData); - - sprintf(fileData,""); - fclose(fp); - - return TRUE; -} - - -//Left Trim (remove the spaces at the left of a string) -char * lTrim (char *s) { - int count=0,i,tmpi; - - for (i=0;i<(int)strlen(s); i++) { - if (s[i] == ' ') count++; - else { - for (tmpi=0;tmpi<(int)strlen(s);tmpi++) - s[tmpi] = s[tmpi+count]; - break; - } - } - return s; -} - - -BOOL Save_Patch_Proc( char * filename ) { - - OPENFILENAME ofn; - char szFileName[ 256 ]; - char szFileTitle[ 256 ]; - char * filter = "Patch Files (*.pnach)\0*.pnach\0ALL Files (*.*)\0*.*"; - - memset( &szFileName, 0, sizeof( szFileName ) ); - memset( &szFileTitle, 0, sizeof( szFileTitle ) ); - - ofn.lStructSize = sizeof( OPENFILENAME ); - ofn.hwndOwner = gApp.hWnd; - ofn.lpstrFilter = filter; - ofn.lpstrCustomFilter = NULL; - ofn.nMaxCustFilter = 0; - ofn.nFilterIndex = 1; - ofn.lpstrFile = szFileName; - ofn.nMaxFile = 256; - ofn.lpstrInitialDir = NULL; - ofn.lpstrFileTitle = szFileTitle; - ofn.nMaxFileTitle = 256; - ofn.lpstrTitle = NULL; - ofn.lpstrDefExt = "TXT"; - ofn.Flags = OFN_EXPLORER | OFN_LONGNAMES | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST; - - if ( GetSaveFileName( &ofn ) ) { - - strcpy( filename, szFileName ); - - return TRUE; - } - else { - return FALSE; - } -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +/************************** +* +* patchbrowser.c contains all the src of patchbrowser window +* no interaction with emulation code +***************************/ + +#include "Win32.h" +#include "Common.h" +#include "resource.h" + +/* + * TODO: + * - not topmost + * - resize stuff + * - ask to save in exit (check if changed) + */ +BOOL CALLBACK PatchBDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + + int tmpi,i; + char fileName[MAX_PATH], *tmpStr; + FILE *fp; + + switch(uMsg) { + + case WM_INITDIALOG: + SetWindowText(hW, _("Patches Browser")); + Button_SetText(GetDlgItem(hW,IDC_REFRESHPATCHLIST), _("Refresh List")); + Button_SetText(GetDlgItem(hW,IDC_NEWPATCH), _("New Patch")); + Button_SetText(GetDlgItem(hW,IDC_SAVEPATCH), _("Save Patch")); + Button_SetText(GetDlgItem(hW,IDC_EXITPB), _("Exit")); + Static_SetText(GetDlgItem(hW,IDC_GAMENAMESEARCH), _("Search game name patch:")); + //List Patches + ListPatches ((HWND) hW); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + + case IDC_NEWPATCH: + + i = Save_Patch_Proc(fileName); + if ( i == FALSE || (fp = fopen(fileName,"a")) == NULL ) { + MessageBox(hW,(LPCTSTR)"Couldn't create the file.",NULL,(UINT)MB_ICONERROR); + return FALSE; + } + + fclose(fp); + i = MessageBox(hW,(LPCTSTR)"File created sucessfully.\nClear textbox?",NULL,(UINT)(MB_YESNO|MB_ICONQUESTION)); + if (i==IDYES) SetDlgItemText(hW, IDC_PATCHTEXT, (LPCTSTR)""); + + return TRUE; + + case IDC_SAVEPATCH: + + i = Save_Patch_Proc(fileName); + if ( i == FALSE || (fp = fopen(fileName,"w")) == NULL ) { + MessageBox(hW,(LPCTSTR)"Couldn't save the file.",NULL,(UINT)MB_ICONERROR); + return FALSE; + } + + tmpi = SendDlgItemMessage(hW, IDC_PATCHTEXT, EM_GETLINECOUNT, (WPARAM)NULL, (LPARAM)NULL); + i=0; + for (;tmpi>=0;tmpi--) + i += SendDlgItemMessage(hW, IDC_PATCHTEXT, EM_LINELENGTH, (WPARAM)tmpi, (LPARAM)NULL); + + tmpStr = (char *) malloc(i); + sprintf(tmpStr,""); + SendDlgItemMessage(hW, IDC_PATCHTEXT, WM_GETTEXT, (WPARAM)i, (LPARAM)tmpStr); + + //remove \r + for (i=0,tmpi=0; tmpStr[i]!='\0'; i++) + if (tmpStr[i] != '\r') + tmpStr[tmpi++] = tmpStr[i]; + tmpStr[tmpi] = '\0'; + + fputs(tmpStr,fp); + + fclose(fp); + free(tmpStr); + + MessageBox(hW,(LPCTSTR)"File saved sucessfully.",NULL,(UINT)MB_ICONINFORMATION); + + return TRUE; + + case IDC_REFRESHPATCHLIST: + + //List Patches + ListPatches ((HWND) hW); + + return TRUE; + + case IDC_EXITPB: + + //Close Dialog + EndDialog(hW, FALSE); + + return TRUE; + + case IDC_PATCHCRCLIST: + + //Get selected item + tmpi = SendDlgItemMessage(hW, IDC_PATCHCRCLIST, LB_GETCURSEL, 0, 0); + SendDlgItemMessage(hW, IDC_PATCHCRCLIST, LB_GETTEXT, (WPARAM)tmpi, (LPARAM)fileName); + + return ReadPatch ((HWND) hW, fileName); + + case IDC_PATCHNAMELIST: + + //Get selected item + tmpi = SendDlgItemMessage(hW, IDC_PATCHNAMELIST, LB_GETCURSEL, 0, 0); + SendDlgItemMessage(hW, IDC_PATCHNAMELIST, LB_GETTEXT, (WPARAM)tmpi, (LPARAM)fileName); + + //another small hack :p + //eg. SOCOM Demo PAL (7dd01dd9.pnach) + for (i=0;i<(int)strlen(fileName);i++) + if (fileName[i] == '(') tmpi = i; + + sprintf(fileName,"%c%c%c%c%c%c%c%c%c%c%c%c%c%c", + fileName[tmpi+1],fileName[tmpi+2],fileName[tmpi+3], + fileName[tmpi+4],fileName[tmpi+5],fileName[tmpi+6], + fileName[tmpi+7],fileName[tmpi+8],fileName[tmpi+9], + fileName[tmpi+10],fileName[tmpi+11],fileName[tmpi+12], + fileName[tmpi+13],fileName[tmpi+14]); + + //sanity check + if (fileName[tmpi+15] != ')') return FALSE; + + return ReadPatch ((HWND) hW, fileName); + + case IDC_SEARCHPATCHTEXT: + + //get text + SendDlgItemMessage(hW, IDC_SEARCHPATCHTEXT, EM_GETLINE, 0, (LPARAM)fileName); + //search + tmpi = SendDlgItemMessage(hW, IDC_PATCHNAMELIST, LB_FINDSTRING, (WPARAM)-1, (LPARAM)fileName); + //select match item + SendDlgItemMessage(hW, IDC_PATCHNAMELIST, LB_SETCURSEL, (WPARAM)tmpi, (LPARAM)NULL); + + return TRUE; + } + return TRUE; + + case WM_CLOSE: + EndDialog(hW, FALSE); + break; + + } + return FALSE; +} +void ListPatches (HWND hW) { + + int i, tmpi, filesize, totalPatch=0, totalSize=0; + char tmpStr[MAX_PATH], *fileData; + WIN32_FIND_DATA FindData; + HANDLE Find; + FILE *fp; + + //clear listbox's + SendDlgItemMessage(hW, IDC_PATCHCRCLIST, (UINT)LB_RESETCONTENT, (WPARAM)NULL, (LPARAM)NULL); + SendDlgItemMessage(hW, IDC_PATCHNAMELIST, (UINT)LB_RESETCONTENT, (WPARAM)NULL, (LPARAM)NULL); + + //sprintf(tmpStr,"%s*.pnach", Config.PatchDir) + sprintf(tmpStr, "patches\\*.pnach"); + + Find = FindFirstFile(tmpStr, &FindData); + + do { + if (Find==INVALID_HANDLE_VALUE) break; + + sprintf(tmpStr,"%s", FindData.cFileName); + + //add file name to crc list + SendDlgItemMessage(hW, IDC_PATCHCRCLIST, (UINT) LB_ADDSTRING, (WPARAM)NULL, (LPARAM)tmpStr); + + //sprintf(tmpStr,"%s%s", Config.PatchDir, FindData.cFileName) + sprintf(tmpStr,"patches\\%s", FindData.cFileName); + + fp = fopen(tmpStr, "r"); + if (fp == NULL) break; + + fseek(fp, 0, SEEK_END); + filesize = ftell(fp); + totalSize += filesize; + fseek(fp, 0, SEEK_SET); + + fileData = (char *) malloc(filesize+1024); + sprintf(fileData,""); + + //read file + while((tmpi=fgetc(fp)) != EOF) + sprintf(fileData,"%s%c",fileData,tmpi); + + //small hack :p + for(i=0;ii;tmpi--) + fileData[tmpi] = fileData[tmpi-1]; + fileData[i] = '\r'; + fileData[i+1] = '\n'; + i++; + } + } + + SetDlgItemText(hW, IDC_PATCHTEXT, (LPCTSTR)fileData); + + sprintf(fileData,""); + fclose(fp); + + return TRUE; +} + + +//Left Trim (remove the spaces at the left of a string) +char * lTrim (char *s) { + int count=0,i,tmpi; + + for (i=0;i<(int)strlen(s); i++) { + if (s[i] == ' ') count++; + else { + for (tmpi=0;tmpi<(int)strlen(s);tmpi++) + s[tmpi] = s[tmpi+count]; + break; + } + } + return s; +} + + +BOOL Save_Patch_Proc( char * filename ) { + + OPENFILENAME ofn; + char szFileName[ 256 ]; + char szFileTitle[ 256 ]; + char * filter = "Patch Files (*.pnach)\0*.pnach\0ALL Files (*.*)\0*.*"; + + memset( &szFileName, 0, sizeof( szFileName ) ); + memset( &szFileTitle, 0, sizeof( szFileTitle ) ); + + ofn.lStructSize = sizeof( OPENFILENAME ); + ofn.hwndOwner = gApp.hWnd; + ofn.lpstrFilter = filter; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 1; + ofn.lpstrFile = szFileName; + ofn.nMaxFile = 256; + ofn.lpstrInitialDir = NULL; + ofn.lpstrFileTitle = szFileTitle; + ofn.nMaxFileTitle = 256; + ofn.lpstrTitle = NULL; + ofn.lpstrDefExt = "TXT"; + ofn.Flags = OFN_EXPLORER | OFN_LONGNAMES | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST; + + if ( GetSaveFileName( &ofn ) ) { + + strcpy( filename, szFileName ); + + return TRUE; + } + else { + return FALSE; + } +} diff --git a/pcsx2/windows/RDebugger.cpp b/pcsx2/windows/RDebugger.cpp index 3127e87836..9dfcc64018 100644 --- a/pcsx2/windows/RDebugger.cpp +++ b/pcsx2/windows/RDebugger.cpp @@ -1,374 +1,374 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" -#include "Win32.h" - -#include -#include "Debugger.h" -#include "RDebugger.h" -#include "Common.h" -#include "R3000A.h" -#include "../rdebug/deci2.h" - -u32 port=8510; -SOCKET serversocket, remote; -char message[1024]; //message to add to listbox - -volatile long runStatus=STOP; -int runCode=0, runCount=1; -HANDLE runEvent=NULL; - -DECI2_DBGP_BRK ebrk[32], - ibrk[32]; -int ebrk_count=0, - ibrk_count=0; - -int debuggedCpu=0; //default is to debug EE cpu; IOP=1 -u32 breakAddress=0; //disabled; ie. you cannot use address 0 for a breakpoint -u32 breakCycle=0; //disabled; ie. you cannot stop after 0 cycles - -int CreateSocket(HWND hDlg, int port){ - WSADATA wsadata; - SOCKADDR_IN saServer; - - if (WSAStartup( MAKEWORD(1, 1), &wsadata) || - ((serversocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))==INVALID_SOCKET)){ - MessageBox(hDlg, "Could not create socket\n[Is TCP/IP installed? WinSock 1.1 or above?]", 0, MB_OK); - return FALSE; - } - sprintf(message, "[PCSX2] %s status=%s", wsadata.szDescription, wsadata.szSystemStatus); - ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), message); - - saServer.sin_family = AF_INET; - saServer.sin_addr.S_un.S_addr = INADDR_ANY; // accept any address - saServer.sin_port = htons(port); // port to listen to - - if (bind(serversocket, (LPSOCKADDR)&saServer, sizeof(struct sockaddr))==SOCKET_ERROR){ - sprintf(message, "Could not bind to port %d\n" - "[Is there another server running on that port?]", port); - MessageBox(hDlg, message, 0, MB_OK); - closesocket(serversocket); - return FALSE; - } - sprintf(message, "[PCSX2] Port %d is opened", port); - ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), message); - - // SOMAXCONN connections in queque? maybe 1 is enough... - if (listen(serversocket, SOMAXCONN) == SOCKET_ERROR){ - sprintf(message, "Listening for a connection failed\n" - "[dunno?]"); - MessageBox(hDlg, message, 0, MB_OK); - closesocket(serversocket); - return FALSE; - } - sprintf(message, "[PCSX2] Listening for a connection to establish..."); - ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), message); - - cpuRegs.CP0.n.EPC=cpuRegs.pc; - psxRegs.CP0.n.EPC=psxRegs.pc; - sprintf(message, "%08X", cpuRegs.pc); - Edit_SetText(GetDlgItem(hDlg, IDC_EEPC), message); - sprintf(message, "%08X", psxRegs.pc); - Edit_SetText(GetDlgItem(hDlg, IDC_IOPPC), message); - sprintf(message, "%d", cpuRegs.cycle); - Edit_SetText(GetDlgItem(hDlg, IDC_EECYCLE), message); - sprintf(message, "%d", psxRegs.cycle); - Edit_SetText(GetDlgItem(hDlg, IDC_IOPCYCLE), message); - Button_SetCheck(GetDlgItem(hDlg, IDC_DEBUGEE), (debuggedCpu==0)); - Button_SetCheck(GetDlgItem(hDlg, IDC_DEBUGIOP), (debuggedCpu==1)); - Edit_LimitText(GetDlgItem(hDlg, IDC_STOPAT), 8); //8 hex digits - Edit_LimitText(GetDlgItem(hDlg, IDC_STOPAFTER), 10);//10 decimal digits - sprintf(message, "%08X", breakAddress); - Edit_SetText(GetDlgItem(hDlg, IDC_STOPAT), message); - sprintf(message, "%d", breakCycle); - Edit_SetText(GetDlgItem(hDlg, IDC_STOPAFTER), message); - - Button_Enable(GetDlgItem(hDlg, IDC_DEBUGIOP), FALSE);//////////////////////// - - return TRUE; -} - -int readData(u8 *buffer){ - int r, count=0; - u8 *p=buffer; - - memset(buffer, 0, BUFFERSIZE); - while (((count+= r = recv(remote, (char*)p, BUFFERSIZE, 0))!=INVALID_SOCKET) && - (count<*(u16*)buffer)) - p+=r; - - if (r==INVALID_SOCKET) - return 0; - - return count; -} - -int writeData(const u8 *result){ - int r;/*, i; - static char l[300], p[10]; - DECI2_HEADER *header=(DECI2_HEADER*)result; -*/ - r = send(remote, (const char*)result, *(u16*)result, 0); - if (r==SOCKET_ERROR) - return 0; -/* - sprintf(l, "size=%d, src=%c dst=%c proto=0x%04X ", - header->length-8, header->source, header->destination, header->protocol); - for (i=8; i<*(u16*)result; i++){ - sprintf(p, "%02X ", result[i]); - strcat(l, p); - } - Msgbox::Alert(l); -*/ - return r; -} - -DWORD WINAPI ServingFunction(LPVOID lpParam){ - static u8 buffer[BUFFERSIZE], //a big buffer - result[BUFFERSIZE]; //a big buffer - static TCHAR eepc[9], ioppc[9], eecy[15], iopcy[15]; - SOCKADDR_IN saClient; - HWND hDlg=(HWND)lpParam; - int size=sizeof(struct sockaddr); - int exit=FALSE; - - if ((remote = accept(serversocket, (struct sockaddr*)&saClient, &size))==INVALID_SOCKET){ - ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), "[PCSX2] Commmunication lost. THE END"); - return FALSE; - } - sprintf(message, "[PCSX2] Connected to %d.%d.%d.%d on remote port %d", - saClient.sin_addr.S_un.S_un_b.s_b1, - saClient.sin_addr.S_un.S_un_b.s_b2, - saClient.sin_addr.S_un.S_un_b.s_b3, - saClient.sin_addr.S_un.S_un_b.s_b4, - saClient.sin_port); - ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), message); - ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), "[PCSX2] Start serving..."); - connected=1;//from this point on, all log stuff goes to ttyp - - //sendBREAK('E', 0, 0xff, 0x21, 1); //do not enable this unless you know what you are doing! - while (!exit && readData(buffer)){ - DECI2_HEADER *header=(DECI2_HEADER*)buffer; - - switch(header->protocol){ - case 0x0000:exit=TRUE; break; - case PROTO_DCMP:D2_DCMP(buffer, result, message); break; -// case 0x0120:D2_DRFP_EE(buffer, result, message); break; -// case 0x0121:D2_DRFP_IOP(buffer, result, message); break; -// case 0x0122:break; - case PROTO_IDBGP:D2_DBGP(buffer, result, message, eepc, ioppc, eecy, iopcy); break; -// case 0x0140:break; - case PROTO_ILOADP:D2_ILOADP(buffer, result, message); break; - case PROTO_EDBGP:D2_DBGP(buffer, result, message, eepc, ioppc, eecy, iopcy);break; -// case 0x0240:break; - case PROTO_NETMP:D2_NETMP(buffer, result, message); break; - default: - sprintf(message, "[DECI2 %c->%c/%04X] Protocol=0x%04X", - header->source, header->destination, - header->length, header->protocol); - ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), message); - continue; - } - if (exit==FALSE){ - ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), message); - Edit_SetText(GetDlgItem(hDlg, IDC_EEPC), eepc); - Edit_SetText(GetDlgItem(hDlg, IDC_IOPPC), ioppc); - Edit_SetText(GetDlgItem(hDlg, IDC_EECYCLE), eecy); - Edit_SetText(GetDlgItem(hDlg, IDC_IOPCYCLE), iopcy); - } - } - connected=0; - - ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), "[PCSX2] Connection closed. THE END"); - return TRUE; -} - -DWORD WINAPI Run2(LPVOID lpParam){ - HWND hDlg=(HWND)lpParam; - static char pc[9]; - int i; - - while (1){ - if (runStatus==RUN){ - if (PSMu32(cpuRegs.pc)==0x0000000D){ - sendBREAK('E', 0, runCode, 0x22, runCount); - InterlockedExchange(&runStatus, STOP); - continue; - } - if ((runCode==2) && (//next - ((PSMu32(cpuRegs.pc) & 0xFC000000)==0x0C000000) ||//JAL - ((PSMu32(cpuRegs.pc) & 0xFC00003F)==0x00000009) ||//JALR - ((PSMu32(cpuRegs.pc) & 0xFC00003F)==0x0000000C) //SYSCALL - )){u32 tmppc=cpuRegs.pc, skip=(PSMu32(cpuRegs.pc) & 0xFC00003F)==0x0000000C ? 4 : 8; - while (cpuRegs.pc!=tmppc+skip) - Cpu->Step(); - }else - Cpu->Step(); //use this with breakpoints & step-by-step -// Cpu->ExecuteBlock(); //use this to run faster, but not for stepping -// sprintf(pc, "%08X", cpuRegs.pc);Edit_SetText(GetDlgItem(hDlg, IDC_EEPC), pc); -// sprintf(pc, "%08X", psxRegs.pc);Edit_SetText(GetDlgItem(hDlg, IDC_IOPPC), pc); -// sprintf(pc, "%d", cpuRegs.cycle);Edit_SetText(GetDlgItem(hDlg, IDC_EECYCLE), pc); -// sprintf(pc, "%d", psxRegs.cycle);Edit_SetText(GetDlgItem(hDlg, IDC_IOPCYCLE), pc); - if (runCount!=0 && --runCount==0){ - sendBREAK('E', 0, runCode, 0x23, runCount); - InterlockedExchange(&runStatus, STOP); - continue; - } - if ((breakAddress) && (breakAddress==cpuRegs.pc)){ - sendBREAK('E', 0, runCode, 0x21, runCount); - InterlockedExchange(&runStatus, STOP); - continue; - } - if ((breakCycle) && (breakCycle==cpuRegs.cycle)){ - sendBREAK('E', 0, runCode, 0x21, runCount); - InterlockedExchange(&runStatus, STOP); - breakCycle=0; - Edit_SetText(GetDlgItem(hDlg, IDC_STOPAFTER), "0"); - continue; - } - for (i=0; i +#include "Debugger.h" +#include "RDebugger.h" +#include "Common.h" +#include "R3000A.h" +#include "../rdebug/deci2.h" + +u32 port=8510; +SOCKET serversocket, remote; +char message[1024]; //message to add to listbox + +volatile long runStatus=STOP; +int runCode=0, runCount=1; +HANDLE runEvent=NULL; + +DECI2_DBGP_BRK ebrk[32], + ibrk[32]; +int ebrk_count=0, + ibrk_count=0; + +int debuggedCpu=0; //default is to debug EE cpu; IOP=1 +u32 breakAddress=0; //disabled; ie. you cannot use address 0 for a breakpoint +u32 breakCycle=0; //disabled; ie. you cannot stop after 0 cycles + +int CreateSocket(HWND hDlg, int port){ + WSADATA wsadata; + SOCKADDR_IN saServer; + + if (WSAStartup( MAKEWORD(1, 1), &wsadata) || + ((serversocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))==INVALID_SOCKET)){ + MessageBox(hDlg, "Could not create socket\n[Is TCP/IP installed? WinSock 1.1 or above?]", 0, MB_OK); + return FALSE; + } + sprintf(message, "[PCSX2] %s status=%s", wsadata.szDescription, wsadata.szSystemStatus); + ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), message); + + saServer.sin_family = AF_INET; + saServer.sin_addr.S_un.S_addr = INADDR_ANY; // accept any address + saServer.sin_port = htons(port); // port to listen to + + if (bind(serversocket, (LPSOCKADDR)&saServer, sizeof(struct sockaddr))==SOCKET_ERROR){ + sprintf(message, "Could not bind to port %d\n" + "[Is there another server running on that port?]", port); + MessageBox(hDlg, message, 0, MB_OK); + closesocket(serversocket); + return FALSE; + } + sprintf(message, "[PCSX2] Port %d is opened", port); + ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), message); + + // SOMAXCONN connections in queque? maybe 1 is enough... + if (listen(serversocket, SOMAXCONN) == SOCKET_ERROR){ + sprintf(message, "Listening for a connection failed\n" + "[dunno?]"); + MessageBox(hDlg, message, 0, MB_OK); + closesocket(serversocket); + return FALSE; + } + sprintf(message, "[PCSX2] Listening for a connection to establish..."); + ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), message); + + cpuRegs.CP0.n.EPC=cpuRegs.pc; + psxRegs.CP0.n.EPC=psxRegs.pc; + sprintf(message, "%08X", cpuRegs.pc); + Edit_SetText(GetDlgItem(hDlg, IDC_EEPC), message); + sprintf(message, "%08X", psxRegs.pc); + Edit_SetText(GetDlgItem(hDlg, IDC_IOPPC), message); + sprintf(message, "%d", cpuRegs.cycle); + Edit_SetText(GetDlgItem(hDlg, IDC_EECYCLE), message); + sprintf(message, "%d", psxRegs.cycle); + Edit_SetText(GetDlgItem(hDlg, IDC_IOPCYCLE), message); + Button_SetCheck(GetDlgItem(hDlg, IDC_DEBUGEE), (debuggedCpu==0)); + Button_SetCheck(GetDlgItem(hDlg, IDC_DEBUGIOP), (debuggedCpu==1)); + Edit_LimitText(GetDlgItem(hDlg, IDC_STOPAT), 8); //8 hex digits + Edit_LimitText(GetDlgItem(hDlg, IDC_STOPAFTER), 10);//10 decimal digits + sprintf(message, "%08X", breakAddress); + Edit_SetText(GetDlgItem(hDlg, IDC_STOPAT), message); + sprintf(message, "%d", breakCycle); + Edit_SetText(GetDlgItem(hDlg, IDC_STOPAFTER), message); + + Button_Enable(GetDlgItem(hDlg, IDC_DEBUGIOP), FALSE);//////////////////////// + + return TRUE; +} + +int readData(u8 *buffer){ + int r, count=0; + u8 *p=buffer; + + memset(buffer, 0, BUFFERSIZE); + while (((count+= r = recv(remote, (char*)p, BUFFERSIZE, 0))!=INVALID_SOCKET) && + (count<*(u16*)buffer)) + p+=r; + + if (r==INVALID_SOCKET) + return 0; + + return count; +} + +int writeData(const u8 *result){ + int r;/*, i; + static char l[300], p[10]; + DECI2_HEADER *header=(DECI2_HEADER*)result; +*/ + r = send(remote, (const char*)result, *(u16*)result, 0); + if (r==SOCKET_ERROR) + return 0; +/* + sprintf(l, "size=%d, src=%c dst=%c proto=0x%04X ", + header->length-8, header->source, header->destination, header->protocol); + for (i=8; i<*(u16*)result; i++){ + sprintf(p, "%02X ", result[i]); + strcat(l, p); + } + Msgbox::Alert(l); +*/ + return r; +} + +DWORD WINAPI ServingFunction(LPVOID lpParam){ + static u8 buffer[BUFFERSIZE], //a big buffer + result[BUFFERSIZE]; //a big buffer + static TCHAR eepc[9], ioppc[9], eecy[15], iopcy[15]; + SOCKADDR_IN saClient; + HWND hDlg=(HWND)lpParam; + int size=sizeof(struct sockaddr); + int exit=FALSE; + + if ((remote = accept(serversocket, (struct sockaddr*)&saClient, &size))==INVALID_SOCKET){ + ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), "[PCSX2] Commmunication lost. THE END"); + return FALSE; + } + sprintf(message, "[PCSX2] Connected to %d.%d.%d.%d on remote port %d", + saClient.sin_addr.S_un.S_un_b.s_b1, + saClient.sin_addr.S_un.S_un_b.s_b2, + saClient.sin_addr.S_un.S_un_b.s_b3, + saClient.sin_addr.S_un.S_un_b.s_b4, + saClient.sin_port); + ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), message); + ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), "[PCSX2] Start serving..."); + connected=1;//from this point on, all log stuff goes to ttyp + + //sendBREAK('E', 0, 0xff, 0x21, 1); //do not enable this unless you know what you are doing! + while (!exit && readData(buffer)){ + DECI2_HEADER *header=(DECI2_HEADER*)buffer; + + switch(header->protocol){ + case 0x0000:exit=TRUE; break; + case PROTO_DCMP:D2_DCMP(buffer, result, message); break; +// case 0x0120:D2_DRFP_EE(buffer, result, message); break; +// case 0x0121:D2_DRFP_IOP(buffer, result, message); break; +// case 0x0122:break; + case PROTO_IDBGP:D2_DBGP(buffer, result, message, eepc, ioppc, eecy, iopcy); break; +// case 0x0140:break; + case PROTO_ILOADP:D2_ILOADP(buffer, result, message); break; + case PROTO_EDBGP:D2_DBGP(buffer, result, message, eepc, ioppc, eecy, iopcy);break; +// case 0x0240:break; + case PROTO_NETMP:D2_NETMP(buffer, result, message); break; + default: + sprintf(message, "[DECI2 %c->%c/%04X] Protocol=0x%04X", + header->source, header->destination, + header->length, header->protocol); + ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), message); + continue; + } + if (exit==FALSE){ + ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), message); + Edit_SetText(GetDlgItem(hDlg, IDC_EEPC), eepc); + Edit_SetText(GetDlgItem(hDlg, IDC_IOPPC), ioppc); + Edit_SetText(GetDlgItem(hDlg, IDC_EECYCLE), eecy); + Edit_SetText(GetDlgItem(hDlg, IDC_IOPCYCLE), iopcy); + } + } + connected=0; + + ListBox_AddString(GetDlgItem(hDlg, IDC_COMMUNICATION), "[PCSX2] Connection closed. THE END"); + return TRUE; +} + +DWORD WINAPI Run2(LPVOID lpParam){ + HWND hDlg=(HWND)lpParam; + static char pc[9]; + int i; + + while (1){ + if (runStatus==RUN){ + if (PSMu32(cpuRegs.pc)==0x0000000D){ + sendBREAK('E', 0, runCode, 0x22, runCount); + InterlockedExchange(&runStatus, STOP); + continue; + } + if ((runCode==2) && (//next + ((PSMu32(cpuRegs.pc) & 0xFC000000)==0x0C000000) ||//JAL + ((PSMu32(cpuRegs.pc) & 0xFC00003F)==0x00000009) ||//JALR + ((PSMu32(cpuRegs.pc) & 0xFC00003F)==0x0000000C) //SYSCALL + )){u32 tmppc=cpuRegs.pc, skip=(PSMu32(cpuRegs.pc) & 0xFC00003F)==0x0000000C ? 4 : 8; + while (cpuRegs.pc!=tmppc+skip) + Cpu->Step(); + }else + Cpu->Step(); //use this with breakpoints & step-by-step +// Cpu->ExecuteBlock(); //use this to run faster, but not for stepping +// sprintf(pc, "%08X", cpuRegs.pc);Edit_SetText(GetDlgItem(hDlg, IDC_EEPC), pc); +// sprintf(pc, "%08X", psxRegs.pc);Edit_SetText(GetDlgItem(hDlg, IDC_IOPPC), pc); +// sprintf(pc, "%d", cpuRegs.cycle);Edit_SetText(GetDlgItem(hDlg, IDC_EECYCLE), pc); +// sprintf(pc, "%d", psxRegs.cycle);Edit_SetText(GetDlgItem(hDlg, IDC_IOPCYCLE), pc); + if (runCount!=0 && --runCount==0){ + sendBREAK('E', 0, runCode, 0x23, runCount); + InterlockedExchange(&runStatus, STOP); + continue; + } + if ((breakAddress) && (breakAddress==cpuRegs.pc)){ + sendBREAK('E', 0, runCode, 0x21, runCount); + InterlockedExchange(&runStatus, STOP); + continue; + } + if ((breakCycle) && (breakCycle==cpuRegs.cycle)){ + sendBREAK('E', 0, runCode, 0x21, runCount); + InterlockedExchange(&runStatus, STOP); + breakCycle=0; + Edit_SetText(GetDlgItem(hDlg, IDC_STOPAFTER), "0"); + continue; + } + for (i=0; i -#include -#include - -#define BUFFERSIZE (128*1024) - -extern LRESULT WINAPI RemoteDebuggerParamsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); -extern LRESULT WINAPI RemoteDebuggerProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 +#include +#include + +#define BUFFERSIZE (128*1024) + +extern LRESULT WINAPI RemoteDebuggerParamsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +extern LRESULT WINAPI RemoteDebuggerProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); diff --git a/pcsx2/windows/SamplProf.cpp b/pcsx2/windows/SamplProf.cpp index d2e02c4d96..41c44de87b 100644 --- a/pcsx2/windows/SamplProf.cpp +++ b/pcsx2/windows/SamplProf.cpp @@ -1,325 +1,325 @@ - -#include "PrecompiledHeader.h" - -#ifndef _DEBUG - -#include "SamplProf.h" -#include -#include - -using namespace std; - -DWORD GetModuleFromPtr(IN void* ptr,OUT LPSTR lpFilename,IN DWORD nSize) -{ - MEMORY_BASIC_INFORMATION mbi; - VirtualQuery(ptr,&mbi,sizeof(mbi)); - return GetModuleFileName((HMODULE)mbi.AllocationBase,lpFilename,nSize); -} -struct Module -{ - uptr base; - uptr end; - uptr len; - string name; - u32 ticks; - - Module(const char* name, const void* ptr) - { - if (name!=0) - this->name=name; - FromAddress(ptr,name==0); - ticks=0; - } - Module(const char* name, const void* b, u32 s) - { - this->name=name; - FromValues(b,s); - ticks=0; - } - bool operator<(const Module &other) const - { - return ticks>other.ticks; - } - string ToString(u32 total_ticks) - { - return name + ": " + to_string(ticks*100/(float)total_ticks) + " "; - } - bool Inside(uptr val) { return val>=base && val<=end; } - void FromAddress(const void* ptr,bool getname) - { - char filename[512]; - char filename2[512]; - static const void* ptr_old=0; - - if (ptr_old==ptr) - return; - ptr_old=ptr; - - MEMORY_BASIC_INFORMATION mbi; - VirtualQuery(ptr,&mbi,sizeof(mbi)); - base=(u32)mbi.AllocationBase; - GetModuleFileName((HMODULE)mbi.AllocationBase,filename,512); - len=(u8*)mbi.BaseAddress-(u8*)mbi.AllocationBase+mbi.RegionSize; - - if (getname) - { - name=filename; - size_t last=name.find_last_of('\\'); - last=last==name.npos?0:last+1; - name=name.substr(last); - } - - for(;;) - { - VirtualQuery(((u8*)base)+len,&mbi,sizeof(mbi)); - if (!(mbi.Type&MEM_IMAGE)) - break; - - if (!GetModuleFileName((HMODULE)mbi.AllocationBase,filename2,512)) - break; - - if (strcmp(filename,filename2)!=0) - break; - len+=mbi.RegionSize; - } - - - end=base+len-1; - } - void FromValues(const void* b,u32 s) - { - base= (uptr)b; - len=s; - end=base+len-1; - } -}; - -typedef map MapType; - -static vector ProfModules; -static MapType ProfUnknownHash; - -static HANDLE hEmuThread = NULL; -static HANDLE hMtgsThread = NULL; -static HANDLE hProfThread = NULL; - -static CRITICAL_SECTION ProfModulesLock; - -static volatile bool ProfRunning=false; - -static bool _registeredName( const char* name ) -{ - for( vector::const_iterator - iter = ProfModules.begin(), - end = ProfModules.end(); itername.compare( name ) == 0 ) - return true; - } - return false; -} - -void ProfilerRegisterSource(const char* Name, const void* buff, u32 sz) -{ - if( ProfRunning ) - EnterCriticalSection( &ProfModulesLock ); - - if( !_registeredName( Name ) ) - ProfModules.push_back( Module(Name, buff, sz) ); - - if( ProfRunning ) - LeaveCriticalSection( &ProfModulesLock ); -} - -void ProfilerRegisterSource(const char* Name, const void* function) -{ - if( ProfRunning ) - EnterCriticalSection( &ProfModulesLock ); - - if( !_registeredName( Name ) ) - ProfModules.push_back( Module(Name,function) ); - - if( ProfRunning ) - LeaveCriticalSection( &ProfModulesLock ); -} - -void ProfilerTerminateSource( const char* Name ) -{ - for( vector::const_iterator - iter = ProfModules.begin(), - end = ProfModules.end(); itername.compare( Name ) == 0 ) - { - ProfModules.erase( iter ); - break; - } - } -} - -static bool DispatchKnownModules( uint Eip ) -{ - bool retval = false; - EnterCriticalSection( &ProfModulesLock ); - - size_t i; - for(i=0;i::iterator iter=ProfUnknownHash.find(modulenam); - if (iter!=ProfUnknownHash.end()) - { - iter->second.ticks++; - return; - } - - Module tmp((sz==0) ? modulenam.c_str() : NULL, (void*)Eip); - tmp.ticks++; - - ProfUnknownHash.insert(MapType::value_type(modulenam, tmp)); -} - -int __stdcall ProfilerThread(void* nada) -{ - ProfUnknownHash.clear(); - u32 tick_count=0; - - while(ProfRunning) - { - Sleep(5); - - if (tick_count>500) - { - string rv="|"; - u32 subtotal=0; - for (size_t i=0;i lst; - for (MapType::iterator i=ProfUnknownHash.begin();i!=ProfUnknownHash.end();i++) - { - lst.push_back(i->second); - } - - sort(lst.begin(),lst.end()); - for (size_t i=0;i\n",rv.c_str()); - - tick_count=0; - - ProfUnknownHash.clear(); - } - - tick_count++; - - CONTEXT ctx; - ctx.ContextFlags = CONTEXT_FULL; - GetThreadContext(hEmuThread,&ctx); - - if( !DispatchKnownModules( ctx.Eip ) ) - { - MapUnknownSource( ctx.Eip ); - } - - if( hMtgsThread != NULL ) - { - GetThreadContext(hMtgsThread,&ctx); - if( DispatchKnownModules( ctx.Eip ) ) - continue; - } - } - - return -1; -} - -void ProfilerInit() -{ - if (ProfRunning) - return; - - //Console::Msg( "Profiler Thread Initializing..." ); - ProfRunning=true; - DuplicateHandle(GetCurrentProcess(), - GetCurrentThread(), - GetCurrentProcess(), - &(HANDLE)hEmuThread, - 0, - FALSE, - DUPLICATE_SAME_ACCESS); - - InitializeCriticalSection( &ProfModulesLock ); - - hProfThread=CreateThread(0,0,(LPTHREAD_START_ROUTINE)ProfilerThread,0,0,0); - SetThreadPriority(hProfThread,THREAD_PRIORITY_HIGHEST); - //Console::WriteLn( " Done!" ); -} - -void ProfilerTerm() -{ - //Console::Msg( "Profiler Terminating..." ); - if (!ProfRunning) - return; - - ProfRunning=false; - - if( hProfThread != NULL ) - { - ResumeThread(hProfThread); - WaitForSingleObject(hProfThread,INFINITE); - CloseHandle(hProfThread); - } - - if( hEmuThread != NULL ) - CloseHandle( hEmuThread ); - - if( hMtgsThread != NULL ) - CloseHandle( hMtgsThread ); - - DeleteCriticalSection( &ProfModulesLock ); - //Console::WriteLn( " Done!" ); -} - -void ProfilerSetEnabled(bool Enabled) -{ - if (!ProfRunning) - { - if( !Enabled ) return; - ProfilerInit(); - } - - if (Enabled) - ResumeThread(hProfThread); - else - SuspendThread(hProfThread); -} - -#endif + +#include "PrecompiledHeader.h" + +#ifndef _DEBUG + +#include "SamplProf.h" +#include +#include + +using namespace std; + +DWORD GetModuleFromPtr(IN void* ptr,OUT LPSTR lpFilename,IN DWORD nSize) +{ + MEMORY_BASIC_INFORMATION mbi; + VirtualQuery(ptr,&mbi,sizeof(mbi)); + return GetModuleFileName((HMODULE)mbi.AllocationBase,lpFilename,nSize); +} +struct Module +{ + uptr base; + uptr end; + uptr len; + string name; + u32 ticks; + + Module(const char* name, const void* ptr) + { + if (name!=0) + this->name=name; + FromAddress(ptr,name==0); + ticks=0; + } + Module(const char* name, const void* b, u32 s) + { + this->name=name; + FromValues(b,s); + ticks=0; + } + bool operator<(const Module &other) const + { + return ticks>other.ticks; + } + string ToString(u32 total_ticks) + { + return name + ": " + to_string(ticks*100/(float)total_ticks) + " "; + } + bool Inside(uptr val) { return val>=base && val<=end; } + void FromAddress(const void* ptr,bool getname) + { + char filename[512]; + char filename2[512]; + static const void* ptr_old=0; + + if (ptr_old==ptr) + return; + ptr_old=ptr; + + MEMORY_BASIC_INFORMATION mbi; + VirtualQuery(ptr,&mbi,sizeof(mbi)); + base=(u32)mbi.AllocationBase; + GetModuleFileName((HMODULE)mbi.AllocationBase,filename,512); + len=(u8*)mbi.BaseAddress-(u8*)mbi.AllocationBase+mbi.RegionSize; + + if (getname) + { + name=filename; + size_t last=name.find_last_of('\\'); + last=last==name.npos?0:last+1; + name=name.substr(last); + } + + for(;;) + { + VirtualQuery(((u8*)base)+len,&mbi,sizeof(mbi)); + if (!(mbi.Type&MEM_IMAGE)) + break; + + if (!GetModuleFileName((HMODULE)mbi.AllocationBase,filename2,512)) + break; + + if (strcmp(filename,filename2)!=0) + break; + len+=mbi.RegionSize; + } + + + end=base+len-1; + } + void FromValues(const void* b,u32 s) + { + base= (uptr)b; + len=s; + end=base+len-1; + } +}; + +typedef map MapType; + +static vector ProfModules; +static MapType ProfUnknownHash; + +static HANDLE hEmuThread = NULL; +static HANDLE hMtgsThread = NULL; +static HANDLE hProfThread = NULL; + +static CRITICAL_SECTION ProfModulesLock; + +static volatile bool ProfRunning=false; + +static bool _registeredName( const char* name ) +{ + for( vector::const_iterator + iter = ProfModules.begin(), + end = ProfModules.end(); itername.compare( name ) == 0 ) + return true; + } + return false; +} + +void ProfilerRegisterSource(const char* Name, const void* buff, u32 sz) +{ + if( ProfRunning ) + EnterCriticalSection( &ProfModulesLock ); + + if( !_registeredName( Name ) ) + ProfModules.push_back( Module(Name, buff, sz) ); + + if( ProfRunning ) + LeaveCriticalSection( &ProfModulesLock ); +} + +void ProfilerRegisterSource(const char* Name, const void* function) +{ + if( ProfRunning ) + EnterCriticalSection( &ProfModulesLock ); + + if( !_registeredName( Name ) ) + ProfModules.push_back( Module(Name,function) ); + + if( ProfRunning ) + LeaveCriticalSection( &ProfModulesLock ); +} + +void ProfilerTerminateSource( const char* Name ) +{ + for( vector::const_iterator + iter = ProfModules.begin(), + end = ProfModules.end(); itername.compare( Name ) == 0 ) + { + ProfModules.erase( iter ); + break; + } + } +} + +static bool DispatchKnownModules( uint Eip ) +{ + bool retval = false; + EnterCriticalSection( &ProfModulesLock ); + + size_t i; + for(i=0;i::iterator iter=ProfUnknownHash.find(modulenam); + if (iter!=ProfUnknownHash.end()) + { + iter->second.ticks++; + return; + } + + Module tmp((sz==0) ? modulenam.c_str() : NULL, (void*)Eip); + tmp.ticks++; + + ProfUnknownHash.insert(MapType::value_type(modulenam, tmp)); +} + +int __stdcall ProfilerThread(void* nada) +{ + ProfUnknownHash.clear(); + u32 tick_count=0; + + while(ProfRunning) + { + Sleep(5); + + if (tick_count>500) + { + string rv="|"; + u32 subtotal=0; + for (size_t i=0;i lst; + for (MapType::iterator i=ProfUnknownHash.begin();i!=ProfUnknownHash.end();i++) + { + lst.push_back(i->second); + } + + sort(lst.begin(),lst.end()); + for (size_t i=0;i\n",rv.c_str()); + + tick_count=0; + + ProfUnknownHash.clear(); + } + + tick_count++; + + CONTEXT ctx; + ctx.ContextFlags = CONTEXT_FULL; + GetThreadContext(hEmuThread,&ctx); + + if( !DispatchKnownModules( ctx.Eip ) ) + { + MapUnknownSource( ctx.Eip ); + } + + if( hMtgsThread != NULL ) + { + GetThreadContext(hMtgsThread,&ctx); + if( DispatchKnownModules( ctx.Eip ) ) + continue; + } + } + + return -1; +} + +void ProfilerInit() +{ + if (ProfRunning) + return; + + //Console::Msg( "Profiler Thread Initializing..." ); + ProfRunning=true; + DuplicateHandle(GetCurrentProcess(), + GetCurrentThread(), + GetCurrentProcess(), + &(HANDLE)hEmuThread, + 0, + FALSE, + DUPLICATE_SAME_ACCESS); + + InitializeCriticalSection( &ProfModulesLock ); + + hProfThread=CreateThread(0,0,(LPTHREAD_START_ROUTINE)ProfilerThread,0,0,0); + SetThreadPriority(hProfThread,THREAD_PRIORITY_HIGHEST); + //Console::WriteLn( " Done!" ); +} + +void ProfilerTerm() +{ + //Console::Msg( "Profiler Terminating..." ); + if (!ProfRunning) + return; + + ProfRunning=false; + + if( hProfThread != NULL ) + { + ResumeThread(hProfThread); + WaitForSingleObject(hProfThread,INFINITE); + CloseHandle(hProfThread); + } + + if( hEmuThread != NULL ) + CloseHandle( hEmuThread ); + + if( hMtgsThread != NULL ) + CloseHandle( hMtgsThread ); + + DeleteCriticalSection( &ProfModulesLock ); + //Console::WriteLn( " Done!" ); +} + +void ProfilerSetEnabled(bool Enabled) +{ + if (!ProfRunning) + { + if( !Enabled ) return; + ProfilerInit(); + } + + if (Enabled) + ResumeThread(hProfThread); + else + SuspendThread(hProfThread); +} + +#endif diff --git a/pcsx2/windows/VCprojects/vsprops/svnrev_template.h b/pcsx2/windows/VCprojects/vsprops/svnrev_template.h index afab6c4fd1..f2656ef1e8 100644 --- a/pcsx2/windows/VCprojects/vsprops/svnrev_template.h +++ b/pcsx2/windows/VCprojects/vsprops/svnrev_template.h @@ -1,18 +1,18 @@ -// svnrev_template.h --> svnrev.h -// -// This file acts as a template for the automatic SVN revision/version tag. -// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for -// whichever project is being compiled (as indicated by command line options -// passed to SubWCRev.exe during the project's pre-build step). -// -// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs -// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN -// installed on your system. If you do not have it installed, a generic template -// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not -// necessary. If you do not have it installed, everything will still compile -// fine except without the SVN revision tagged to the application/dll version. -// -// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org - -#define SVN_REV $WCREV$ +// svnrev_template.h --> svnrev.h +// +// This file acts as a template for the automatic SVN revision/version tag. +// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for +// whichever project is being compiled (as indicated by command line options +// passed to SubWCRev.exe during the project's pre-build step). +// +// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs +// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN +// installed on your system. If you do not have it installed, a generic template +// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not +// necessary. If you do not have it installed, everything will still compile +// fine except without the SVN revision tagged to the application/dll version. +// +// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV $WCREV$ #define SVN_MODS $WCMODS?1:0$ \ No newline at end of file diff --git a/pcsx2/windows/VCprojects/vsprops/svnrev_unknown.h b/pcsx2/windows/VCprojects/vsprops/svnrev_unknown.h index a2a3703186..4872e23b20 100644 --- a/pcsx2/windows/VCprojects/vsprops/svnrev_unknown.h +++ b/pcsx2/windows/VCprojects/vsprops/svnrev_unknown.h @@ -1,23 +1,23 @@ -// svnrev_genric.h --> svnrev.h -// -// This file acts as a placebo for people who do not have TortoiseSVN installed. -// It provides "empty" revision information to the Pcsx2 Playground projects in -// the absence of real revisions derived from the repository being built. -// -// This file does not affect application/dll builds in any significant manner, -// other than the lack of automatic revision tags inserted into the app (which -// is very convenient but hardly necessary). -// -// See svn_template.h for more information on how the process of revision -// templating works. -// -// If you would like to enable automatic revisin tagging, TortoiseSVN can be -// downloaded from http://tortoisesvn.tigris.org - -#define SVN_REV_UNKNOWN - -// The following defines are included so that code will still compile even if it -// doesn't check for the SVN_REV_UNKNOWN define. - -#define SVN_REV 0 +// svnrev_genric.h --> svnrev.h +// +// This file acts as a placebo for people who do not have TortoiseSVN installed. +// It provides "empty" revision information to the Pcsx2 Playground projects in +// the absence of real revisions derived from the repository being built. +// +// This file does not affect application/dll builds in any significant manner, +// other than the lack of automatic revision tags inserted into the app (which +// is very convenient but hardly necessary). +// +// See svn_template.h for more information on how the process of revision +// templating works. +// +// If you would like to enable automatic revisin tagging, TortoiseSVN can be +// downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV_UNKNOWN + +// The following defines are included so that code will still compile even if it +// doesn't check for the SVN_REV_UNKNOWN define. + +#define SVN_REV 0 #define SVN_MODS "" \ No newline at end of file diff --git a/pcsx2/windows/Win32.h b/pcsx2/windows/Win32.h index 7bff43adff..d2022f5f26 100644 --- a/pcsx2/windows/Win32.h +++ b/pcsx2/windows/Win32.h @@ -1,120 +1,120 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef _PCSX2_WIN32_H__ -#define _PCSX2_WIN32_H__ - -#include -#include - -#include "Misc.h" -#include "resource.h" - -#define COMPILEDATE __DATE__ - -// --->> Ini Configuration [ini.c] - -extern char g_WorkingFolder[g_MaxPath]; -extern const char* g_CustomConfigFile; - -bool LoadConfig(); -void SaveConfig(); - -// <<--- END Ini Configuration [ini.c] - -// --->> Patch Browser Stuff (in the event we ever use it - -void ListPatches (HWND hW); -int ReadPatch (HWND hW, char fileName[1024]); -char * lTrim (char *s); -BOOL Save_Patch_Proc( char * filename ); - -// <<--- END Patch Browser - -struct AppData -{ - HWND hWnd; // Main window handle - HINSTANCE hInstance; // Application instance - HMENU hMenu; // Main window menu -}; - -LRESULT WINAPI MainWndProc(HWND, UINT, WPARAM, LPARAM); -void CreateMainWindow(int nCmdShow); -void RunGui(); - -BOOL Pcsx2Configure(HWND hWnd); -void InitLanguages(); -char *GetLanguageNext(); -void CloseLanguages(); -void ChangeLanguage(char *lang); - -void SysRestorableReset(); - -void WinClose(); -void States_Load( const string& file, int num=-1 ); -void States_Save( const string& file, int num=-1 ); -void States_Load(int num); -void States_Save(int num); -void OnStates_LoadOther(); -void OnStates_SaveOther(); -int ParseCommandLine( int tokenCount, TCHAR *const *const tokens ); -void RunExecute( const char* elf_file, bool use_bios=false ); -void ExecuteCpu(); -void strcatz(char *dst, char *src); - -BOOL CALLBACK PatchBDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); -BOOL CALLBACK CpuDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); -BOOL CALLBACK AdvancedOptionsProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); -BOOL CALLBACK HacksProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); - -extern AppData gApp; -extern HWND hStatusWnd; -extern PcsxConfig winConfig; // local storage of the configuration options. -extern bool g_ReturnToGui; // set to exit the execution of the emulator and return control to the GUI -extern bool g_EmulationInProgress; // Set TRUE if a game is actively running (set to false on reset) - -extern int UseGui; -extern int nDisableSC; // screensaver -extern unsigned int langsMax; - -extern MemoryAlloc* g_RecoveryState; -extern MemoryAlloc* g_gsRecoveryState; -extern const char* g_pRunGSState; -extern int g_SaveGSStream; - - -// sets the contents of the Pcsx2 status bar... -extern void StatusBar_Notice( const std::string& text ); -extern void StatusBar_SetMsg( const std::string& text ); - -// Throws an exception based on the value returned from GetLastError. -// Performs an option return value success/fail check on hresult. -extern void StreamException_ThrowLastError( const string& streamname, HANDLE result=INVALID_HANDLE_VALUE ); - -// Throws an exception based on the given error code (usually taken from ANSI C's errno) -extern void StreamException_ThrowFromErrno( const string& streamname, errno_t errcode ); - -extern bool StreamException_LogFromErrno( const string& streamname, const char* action, errno_t result ); -extern bool StreamException_LogLastError( const string& streamname, const char* action, HANDLE result=INVALID_HANDLE_VALUE ); - -// Sets the NTFS compression flag for a directory or file. -// This function does not operate recursively. If the given directory -extern void NTFS_CompressFile( const char* file ); - -#endif - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef _PCSX2_WIN32_H__ +#define _PCSX2_WIN32_H__ + +#include +#include + +#include "Misc.h" +#include "resource.h" + +#define COMPILEDATE __DATE__ + +// --->> Ini Configuration [ini.c] + +extern char g_WorkingFolder[g_MaxPath]; +extern const char* g_CustomConfigFile; + +bool LoadConfig(); +void SaveConfig(); + +// <<--- END Ini Configuration [ini.c] + +// --->> Patch Browser Stuff (in the event we ever use it + +void ListPatches (HWND hW); +int ReadPatch (HWND hW, char fileName[1024]); +char * lTrim (char *s); +BOOL Save_Patch_Proc( char * filename ); + +// <<--- END Patch Browser + +struct AppData +{ + HWND hWnd; // Main window handle + HINSTANCE hInstance; // Application instance + HMENU hMenu; // Main window menu +}; + +LRESULT WINAPI MainWndProc(HWND, UINT, WPARAM, LPARAM); +void CreateMainWindow(int nCmdShow); +void RunGui(); + +BOOL Pcsx2Configure(HWND hWnd); +void InitLanguages(); +char *GetLanguageNext(); +void CloseLanguages(); +void ChangeLanguage(char *lang); + +void SysRestorableReset(); + +void WinClose(); +void States_Load( const string& file, int num=-1 ); +void States_Save( const string& file, int num=-1 ); +void States_Load(int num); +void States_Save(int num); +void OnStates_LoadOther(); +void OnStates_SaveOther(); +int ParseCommandLine( int tokenCount, TCHAR *const *const tokens ); +void RunExecute( const char* elf_file, bool use_bios=false ); +void ExecuteCpu(); +void strcatz(char *dst, char *src); + +BOOL CALLBACK PatchBDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); +BOOL CALLBACK CpuDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); +BOOL CALLBACK AdvancedOptionsProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); +BOOL CALLBACK HacksProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); + +extern AppData gApp; +extern HWND hStatusWnd; +extern PcsxConfig winConfig; // local storage of the configuration options. +extern bool g_ReturnToGui; // set to exit the execution of the emulator and return control to the GUI +extern bool g_EmulationInProgress; // Set TRUE if a game is actively running (set to false on reset) + +extern int UseGui; +extern int nDisableSC; // screensaver +extern unsigned int langsMax; + +extern MemoryAlloc* g_RecoveryState; +extern MemoryAlloc* g_gsRecoveryState; +extern const char* g_pRunGSState; +extern int g_SaveGSStream; + + +// sets the contents of the Pcsx2 status bar... +extern void StatusBar_Notice( const std::string& text ); +extern void StatusBar_SetMsg( const std::string& text ); + +// Throws an exception based on the value returned from GetLastError. +// Performs an option return value success/fail check on hresult. +extern void StreamException_ThrowLastError( const string& streamname, HANDLE result=INVALID_HANDLE_VALUE ); + +// Throws an exception based on the given error code (usually taken from ANSI C's errno) +extern void StreamException_ThrowFromErrno( const string& streamname, errno_t errcode ); + +extern bool StreamException_LogFromErrno( const string& streamname, const char* action, errno_t result ); +extern bool StreamException_LogLastError( const string& streamname, const char* action, HANDLE result=INVALID_HANDLE_VALUE ); + +// Sets the NTFS compression flag for a directory or file. +// This function does not operate recursively. If the given directory +extern void NTFS_CompressFile( const char* file ); + +#endif + diff --git a/pcsx2/windows/WinCompressNTFS.cpp b/pcsx2/windows/WinCompressNTFS.cpp index c0e7e7383e..997ed40db4 100644 --- a/pcsx2/windows/WinCompressNTFS.cpp +++ b/pcsx2/windows/WinCompressNTFS.cpp @@ -1,133 +1,133 @@ - - -#include "PrecompiledHeader.h" -#include "Win32.h" - -// Translates an Errno code into an exception. -void StreamException_ThrowFromErrno( const string& streamname, errno_t errcode ) -{ - if( errcode == 0 ) return; - - switch( errcode ) - { - case EINVAL: - throw Exception::InvalidArgument( "Invalid argument." ); - - case EACCES: // Access denied! - throw Exception::AccessDenied( streamname ); - - case EMFILE: // Too many open files! - throw Exception::CreateStream( streamname, "File handle allocation failure - Too many open files" ); - - case EEXIST: - throw Exception::CreateStream( streamname, "Cannot create - File already exists" ); - - case ENOENT: // File not found! - throw Exception::FileNotFound( streamname ); - - case EPIPE: - throw Exception::BadStream( streamname, "Broken pipe" ); - - case EBADF: - throw Exception::BadStream( streamname, "Bad file number" ); - - default: - throw Exception::Stream( streamname, - fmt_string( "General file/stream error occured [errno: %d]", errcode ) - ); - } -} - -void StreamException_ThrowLastError( const string& streamname, HANDLE result ) -{ - if( result != INVALID_HANDLE_VALUE ) return; - - int error = GetLastError(); - - switch( error ) - { - case ERROR_FILE_NOT_FOUND: - throw Exception::FileNotFound( streamname ); - - case ERROR_PATH_NOT_FOUND: - throw Exception::FileNotFound( streamname ); - - case ERROR_TOO_MANY_OPEN_FILES: - throw Exception::CreateStream( streamname, "File handle allocation failure - Too many open files " ); - - case ERROR_ACCESS_DENIED: - throw Exception::AccessDenied( streamname ); - - default: - { - throw Exception::Stream( streamname, - fmt_string( "General Win32 File/stream error [GetLastError: %d]", error ) - ); - } - } -} - -// returns TRUE if an error occurred. -bool StreamException_LogFromErrno( const string& streamname, const char* action, errno_t result ) -{ - try - { - StreamException_ThrowFromErrno( streamname, result ); - } - catch( Exception::Stream& ex ) - { - Console::Notice( "%s > %s", params action, ex.cMessage() ); - return true; - } - return false; -} - -// returns TRUE if an error occurred. -bool StreamException_LogLastError( const string& streamname, const char* action, HANDLE result ) -{ - try - { - StreamException_ThrowLastError( streamname, result ); - } - catch( Exception::Stream& ex ) - { - Console::Notice( "%s > %s", params action, ex.cMessage() ); - } - return false; -} - -// Exceptions thrown: None. Errors are logged to console. Failures are considered non-critical -void NTFS_CompressFile( const char* file ) -{ - bool isFile = Path::isFile( file ); - - const DWORD flags = isFile ? FILE_ATTRIBUTE_NORMAL : (FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_DIRECTORY); - - HANDLE bloated_crap = CreateFile( file, - FILE_GENERIC_WRITE | FILE_GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - flags, - NULL - ); - - // Fail silently -- non-compression of files and folders is not an errorable offense. - - if( !StreamException_LogLastError( file, "NTFS Compression Enable", bloated_crap ) ) - { - DWORD bytesReturned = 0; - DWORD compressMode = COMPRESSION_FORMAT_DEFAULT; - - BOOL result = DeviceIoControl( - bloated_crap, FSCTL_SET_COMPRESSION, - &compressMode, 2, NULL, 0, - &bytesReturned, NULL - ); - - if( !result ) - StreamException_LogLastError( file, "NTFS Compression Enable" ); - - CloseHandle( bloated_crap ); - } -} + + +#include "PrecompiledHeader.h" +#include "Win32.h" + +// Translates an Errno code into an exception. +void StreamException_ThrowFromErrno( const string& streamname, errno_t errcode ) +{ + if( errcode == 0 ) return; + + switch( errcode ) + { + case EINVAL: + throw Exception::InvalidArgument( "Invalid argument." ); + + case EACCES: // Access denied! + throw Exception::AccessDenied( streamname ); + + case EMFILE: // Too many open files! + throw Exception::CreateStream( streamname, "File handle allocation failure - Too many open files" ); + + case EEXIST: + throw Exception::CreateStream( streamname, "Cannot create - File already exists" ); + + case ENOENT: // File not found! + throw Exception::FileNotFound( streamname ); + + case EPIPE: + throw Exception::BadStream( streamname, "Broken pipe" ); + + case EBADF: + throw Exception::BadStream( streamname, "Bad file number" ); + + default: + throw Exception::Stream( streamname, + fmt_string( "General file/stream error occured [errno: %d]", errcode ) + ); + } +} + +void StreamException_ThrowLastError( const string& streamname, HANDLE result ) +{ + if( result != INVALID_HANDLE_VALUE ) return; + + int error = GetLastError(); + + switch( error ) + { + case ERROR_FILE_NOT_FOUND: + throw Exception::FileNotFound( streamname ); + + case ERROR_PATH_NOT_FOUND: + throw Exception::FileNotFound( streamname ); + + case ERROR_TOO_MANY_OPEN_FILES: + throw Exception::CreateStream( streamname, "File handle allocation failure - Too many open files " ); + + case ERROR_ACCESS_DENIED: + throw Exception::AccessDenied( streamname ); + + default: + { + throw Exception::Stream( streamname, + fmt_string( "General Win32 File/stream error [GetLastError: %d]", error ) + ); + } + } +} + +// returns TRUE if an error occurred. +bool StreamException_LogFromErrno( const string& streamname, const char* action, errno_t result ) +{ + try + { + StreamException_ThrowFromErrno( streamname, result ); + } + catch( Exception::Stream& ex ) + { + Console::Notice( "%s > %s", params action, ex.cMessage() ); + return true; + } + return false; +} + +// returns TRUE if an error occurred. +bool StreamException_LogLastError( const string& streamname, const char* action, HANDLE result ) +{ + try + { + StreamException_ThrowLastError( streamname, result ); + } + catch( Exception::Stream& ex ) + { + Console::Notice( "%s > %s", params action, ex.cMessage() ); + } + return false; +} + +// Exceptions thrown: None. Errors are logged to console. Failures are considered non-critical +void NTFS_CompressFile( const char* file ) +{ + bool isFile = Path::isFile( file ); + + const DWORD flags = isFile ? FILE_ATTRIBUTE_NORMAL : (FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_DIRECTORY); + + HANDLE bloated_crap = CreateFile( file, + FILE_GENERIC_WRITE | FILE_GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + flags, + NULL + ); + + // Fail silently -- non-compression of files and folders is not an errorable offense. + + if( !StreamException_LogLastError( file, "NTFS Compression Enable", bloated_crap ) ) + { + DWORD bytesReturned = 0; + DWORD compressMode = COMPRESSION_FORMAT_DEFAULT; + + BOOL result = DeviceIoControl( + bloated_crap, FSCTL_SET_COMPRESSION, + &compressMode, 2, NULL, 0, + &bytesReturned, NULL + ); + + if( !result ) + StreamException_LogLastError( file, "NTFS Compression Enable" ); + + CloseHandle( bloated_crap ); + } +} diff --git a/pcsx2/windows/WinConsole.cpp b/pcsx2/windows/WinConsole.cpp index f109ee7de0..ae7d114539 100644 --- a/pcsx2/windows/WinConsole.cpp +++ b/pcsx2/windows/WinConsole.cpp @@ -27,14 +27,14 @@ namespace Console static const int tbl_color_codes[] = { - 0 // black - , FOREGROUND_RED | FOREGROUND_INTENSITY - , FOREGROUND_GREEN | FOREGROUND_INTENSITY - , FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY - , FOREGROUND_BLUE | FOREGROUND_INTENSITY - , FOREGROUND_RED | FOREGROUND_BLUE - , FOREGROUND_GREEN | FOREGROUND_BLUE - , FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY + 0 // black + , FOREGROUND_RED | FOREGROUND_INTENSITY + , FOREGROUND_GREEN | FOREGROUND_INTENSITY + , FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY + , FOREGROUND_BLUE | FOREGROUND_INTENSITY + , FOREGROUND_RED | FOREGROUND_BLUE + , FOREGROUND_GREEN | FOREGROUND_BLUE + , FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY }; void SetTitle( const string& title ) diff --git a/pcsx2/windows/WinMain.cpp b/pcsx2/windows/WinMain.cpp index 2d406f771d..44a802b816 100644 --- a/pcsx2/windows/WinMain.cpp +++ b/pcsx2/windows/WinMain.cpp @@ -1,1161 +1,1161 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" -#include "win32.h" - -#include -#include -#include - -#include - -#include "Common.h" -#include "debugger.h" -#include "rdebugger.h" -#include "AboutDlg.h" -#include "McdsDlg.h" - -#include "Patch.h" -#include "cheats/cheats.h" - -#include "Paths.h" -#include "SamplProf.h" - -#include "implement.h" // pthreads-win32 defines for startup/shutdown - -unsigned int langsMax; - - -struct _langs { - TCHAR lang[256]; -}; - -_langs *langs = NULL; - -void strcatz(char *dst, char *src) -{ - int len = strlen(dst) + 1; - strcpy(dst + len, src); -} - -//2002-09-20 (Florin) -BOOL APIENTRY CmdlineProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);//forward def -//------------------- - -TESTRUNARGS g_TestRun; - -static const char* phelpmsg = - "pcsx2 [options] [file]\n\n" - "-cfg [file] {configuration file}\n" - "-efile [efile] {0 - reset, 1 - runcd (default), 2 - loadelf}\n" - "-help {display this help file}\n" - "-nogui {Don't use gui when launching}\n" - "-loadgs [file] {Loads a gsstate}\n" - "\n" - -#ifdef PCSX2_DEVBUILD - "Testing Options: \n" - "\t-frame [frame] {game will run up to this frame before exiting}\n" - "\t-image [name] {path and base name of image (do not include the .ext)}\n" - "\t-jpg {save images to jpg format}\n" - "\t-log [name] {log path to save log file in}\n" - "\t-logopt [hex] {log options in hex (see debug.h) }\n" - "\t-numimages [num] {after hitting frame, this many images will be captures every 20 frames}\n" - "\t-test {Triggers testing mode (only for dev builds)}\n" - "\n" -#endif - - "Load Plugins:\n" - "\t-cdvd [dllpath] {specify the dll load path of the CDVD plugin}\n" - "\t-gs [dllpath] {specify the dll load path of the GS plugin}\n" - "\t-spu [dllpath] {specify the dll load path of the SPU2 plugin}\n" - "\n"; - -/// This code is courtesy of http://alter.org.ua/en/docs/win/args/ -static PTCHAR* _CommandLineToArgv( const TCHAR *CmdLine, int* _argc ) -{ - PTCHAR* argv; - PTCHAR _argv; - ULONG len; - ULONG argc; - TCHAR a; - ULONG i, j; - - BOOLEAN in_QM; - BOOLEAN in_TEXT; - BOOLEAN in_SPACE; - - len = _tcslen( CmdLine ); - i = ((len+2)/2)*sizeof(PVOID) + sizeof(PVOID); - - argv = (PTCHAR*)GlobalAlloc(GMEM_FIXED, - i + (len+2)*sizeof(a)); - - _argv = (PTCHAR)(((PUCHAR)argv)+i); - - argc = 0; - argv[argc] = _argv; - in_QM = FALSE; - in_TEXT = FALSE; - in_SPACE = TRUE; - i = 0; - j = 0; - - while( a = CmdLine[i] ) { - if(in_QM) { - if(a == '\"') { - in_QM = FALSE; - } else { - _argv[j] = a; - j++; - } - } else { - switch(a) { - case '\"': - in_QM = TRUE; - in_TEXT = TRUE; - if(in_SPACE) { - argv[argc] = _argv+j; - argc++; - } - in_SPACE = FALSE; - break; - case ' ': - case '\t': - case '\n': - case '\r': - if(in_TEXT) { - _argv[j] = '\0'; - j++; - } - in_TEXT = FALSE; - in_SPACE = TRUE; - break; - default: - in_TEXT = TRUE; - if(in_SPACE) { - argv[argc] = _argv+j; - argc++; - } - _argv[j] = a; - j++; - in_SPACE = FALSE; - break; - } - } - i++; - } - _argv[j] = '\0'; - argv[argc] = NULL; - - (*_argc) = argc; - return argv; -} - -void WinClose() -{ - SysClose(); - - // Don't check Config.Profiler here -- the Profiler will know if it's running or not. - ProfilerTerm(); - - ReleasePlugins(); - Console::Close(); - - pthread_win32_process_detach_np(); - - SysShutdownDynarecs(); - SysShutdownMem(); -} - -BOOL SysLoggedSetLockPagesPrivilege ( HANDLE hProcess, BOOL bEnable); - -// Returns TRUE if the test run mode was activaated (game was run and has been exited) -static bool TestRunMode() -{ - if( IsDevBuild && (g_TestRun.enabled || g_TestRun.ptitle != NULL) ) - { - // run without ui - UseGui = 0; - PCSX2_MEM_PROTECT_BEGIN(); - RunExecute( g_TestRun.efile ? g_TestRun.ptitle : NULL ); - PCSX2_MEM_PROTECT_END(); - return true; - } - return false; -} - -void WinRun( int nCmdShow ) -{ - // Load the command line overrides for plugins. - // Back up the user's preferences in winConfig. - - memcpy( &winConfig, &Config, sizeof( PcsxConfig ) ); - - if( g_TestRun.pgsdll ) - { - _tcscpy_s( Config.GS, g_MaxPath, g_TestRun.pgsdll ); - Console::Notice( "* GS plugin override: \n\t%s\n", params Config.GS ); - } - if( g_TestRun.pcdvddll ) - { - _tcscpy_s( Config.CDVD, g_MaxPath, g_TestRun.pcdvddll ); - Console::Notice( "* CDVD plugin override: \n\t%s\n", params Config.CDVD ); - } - if( g_TestRun.pspudll ) - { - _tcscpy_s( Config.SPU2, g_MaxPath, g_TestRun.pspudll ); - Console::Notice( "* SPU2 plugin override: \n\t%s\n", params Config.SPU2 ); - } - - // [TODO] : Add the other plugin overrides here... - -#ifndef _DEBUG - if( Config.Profiler ) - ProfilerInit(); -#endif - - InitCPUTicks(); - - while (LoadPlugins() == -1) - { - if (Pcsx2Configure(NULL) == FALSE) return; - } - - if( TestRunMode() ) return; - -#ifdef PCSX2_DEVBUILD - if( g_pRunGSState ) { - LoadGSState(g_pRunGSState); - return; - } -#endif - - CreateMainWindow( nCmdShow ); - - if( Config.PsxOut ) - { - // output the help commands - Console::SetColor( Console::Color_White ); - - Console::WriteLn( "Hotkeys:" ); - - Console::WriteLn( - "\tF1 - save state\n" - "\t(Shift +) F2 - cycle states\n" - "\tF3 - load state" - ); - - DevCon::WriteLn( - //"\tF10 - dump performance counters\n" - "\tF11 - save GS state\n" - //"\tF12 - dump hardware registers" - ); - Console::ClearColor(); - } - - RunGui(); -} - -int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) -{ - char *lang; - int i; - - CreateDirectory(LOGS_DIR, NULL); - - InitCommonControls(); - pInstance=hInstance; - FirstShow=true; // this is used by cheats.cpp to search for stuff (broken?) - - pthread_win32_process_attach_np(); - - gApp.hInstance = hInstance; - gApp.hMenu = NULL; - gApp.hWnd = NULL; - -#ifdef ENABLE_NLS - bindtextdomain(PACKAGE, "Langs\\"); - textdomain(PACKAGE); -#endif - - memzero_obj(g_TestRun); - - _getcwd( g_WorkingFolder, g_MaxPath ); - - int argc; - TCHAR *const *const argv = _CommandLineToArgv( lpCmdLine, &argc ); - - if( argv == NULL ) - { - Msgbox::Alert( "A fatal error occured while attempting to parse the command line.\n" ); - return 2; - } - - switch( ParseCommandLine( argc, argv ) ) - { - case 1: // display help and exit: - printf( "%s", phelpmsg ); - MessageBox( NULL, phelpmsg, "Pcsx2 Help", MB_OK); - - case -1: // exit... - return 0; - } - - try - { - bool needsToConfig = !LoadConfig(); - - // Enumerate available translations - - if (needsToConfig || Config.Lang[0] == 0) { - strcpy(Config.Lang, "en_US"); - } - - langs = (_langs*)malloc(sizeof(_langs)); - strcpy(langs[0].lang, "en_US"); - InitLanguages(); i=1; - while ((lang = GetLanguageNext()) != NULL) { - langs = (_langs*)realloc(langs, sizeof(_langs)*(i+1)); - strcpy(langs[i].lang, lang); - i++; - } - CloseLanguages(); - langsMax = i; - - // automatically and always open the console for first-time uses (no ini file) - if(needsToConfig || Config.PsxOut ) - Console::Open(); - - // Important! Always allocate dynarecs before loading plugins, to give the dynarecs - // the best possible chance of claiming ideal memory space! - - SysInit(); - - if( needsToConfig ) - { - // Prompt the user for a valid configuration before starting the program. - Msgbox::Alert( _( "Pcsx2 needs to be configured." ) ); - Pcsx2Configure( NULL ); - LoadConfig(); // forces re-loading of language and stuff. - } - - if( Config.PsxOut ) - Console::Open(); - else - Console::Close(); - - WinRun( nCmdShow ); - } - catch( Exception::BaseException& ex ) - { - Msgbox::Alert( - "An unhandled or unrecoverable exception occurred, with the message:\n\n" - "%s" - "\n\nPcsx2 will now close. More details may be available via the emuLog.txt file.", params - ex.cMessage() - ); - } - catch( std::exception& ex ) - { - Msgbox::Alert( - "An unhandled or unrecoverable exception occurred, with the message:\n\n" - "%s" - "\n\nPcsx2 will now close. More details may be available via the emuLog.txt file.", params - ex.what() - ); - } - - WinClose(); - - return 0; -} - -static std::string str_Default( "default" ); - -void RunGui() -{ - MSG msg; - - PCSX2_MEM_PROTECT_BEGIN(); - - LoadPatch(str_Default); - - while( true ) - { - if( PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE) != 0 ) - { - if( msg.message == WM_QUIT ) return; - - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - Sleep(10); - } - - PCSX2_MEM_PROTECT_END(); -} - -BOOL Open_File_Proc( std::string& outstr ) -{ - OPENFILENAME ofn; - char szFileName[ g_MaxPath ]; - char szFileTitle[ g_MaxPath ]; - char * filter = "ELF Files (*.ELF)\0*.ELF\0ALL Files (*.*)\0*.*\0"; - - memzero_obj( szFileName ); - memzero_obj( szFileTitle ); - - ofn.lStructSize = sizeof( OPENFILENAME ); - ofn.hwndOwner = gApp.hWnd; - ofn.lpstrFilter = filter; - ofn.lpstrCustomFilter = NULL; - ofn.nMaxCustFilter = 0; - ofn.nFilterIndex = 1; - ofn.lpstrFile = szFileName; - ofn.nMaxFile = g_MaxPath; - ofn.lpstrInitialDir = NULL; - ofn.lpstrFileTitle = szFileTitle; - ofn.nMaxFileTitle = g_MaxPath; - ofn.lpstrTitle = NULL; - ofn.lpstrDefExt = "ELF"; - ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_EXPLORER; - - if (GetOpenFileName(&ofn)) { - struct stat buf; - - if (stat(szFileName, &buf) != 0) { - return FALSE; - } - - outstr = szFileName; - return TRUE; - } - - return FALSE; -} - -//2002-09-20 (Florin) -BOOL APIENTRY CmdlineProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case WM_INITDIALOG: - SetWindowText(hDlg, _("Program arguments")); - - Button_SetText(GetDlgItem(hDlg, IDOK), _("OK")); - Button_SetText(GetDlgItem(hDlg, IDCANCEL), _("Cancel")); - Static_SetText(GetDlgItem(hDlg, IDC_TEXT), _("Fill in the command line arguments for opened program:")); - Static_SetText(GetDlgItem(hDlg, IDC_TIP), _("Tip: If you don't know what to write\nleave it blank")); - - SetDlgItemText(hDlg, IDC_CMDLINE, args); - return TRUE; - - case WM_COMMAND: - if (LOWORD(wParam) == IDOK) - { - char tmp[256]; - - GetDlgItemText(hDlg, IDC_CMDLINE, tmp, 256); - - strcpy_s(args, 256, tmp); - - EndDialog(hDlg, TRUE); - } else if (LOWORD(wParam) == IDCANCEL) { - EndDialog(hDlg, TRUE); - } - return TRUE; - } - - return FALSE; -} - - -#ifdef PCSX2_DEVBUILD - -BOOL APIENTRY LogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { - int i; - switch (message) { - case WM_INITDIALOG: - for (i=0; i<32; i++) - if (varLog & (1<= ID_LANGS && LOWORD(wParam) <= (ID_LANGS + langsMax)) { - DestroyWindow(gApp.hWnd); - ChangeLanguage(langs[LOWORD(wParam) - ID_LANGS].lang); - CreateMainWindow(SW_SHOWNORMAL); - return TRUE; - } - } - return TRUE; - - case WM_DESTROY: - DeleteObject(hbitmap_background); - PostQuitMessage(0); - gApp.hWnd = NULL; - return FALSE; - - // Explicit handling of WM_CLOSE. - // This is Windows default behavior, but we handle it here sot hat we might add a - // user confirmation prompt prior to exit (someday!) - case WM_CLOSE: - DestroyWindow( hWnd ); - return TRUE; - - case WM_SYSCOMMAND: - if( nDisableSC && (wParam== SC_SCREENSAVE || wParam == SC_MONITORPOWER) ) { - return FALSE; - } - break; - } - - return DefWindowProc(hWnd, msg, wParam, lParam); -} - -int Slots[5] = { -1, -1, -1, -1, -1 }; - -void ResetMenuSlots() { - int i; - - for (i=0; i<5; i++) { - if (Slots[i] == -1) - EnableMenuItem(GetSubMenu(gApp.hMenu, 0), ID_FILE_STATES_LOAD_SLOT1+i, MF_GRAYED); - else - EnableMenuItem(GetSubMenu(gApp.hMenu, 0), ID_FILE_STATES_LOAD_SLOT1+i, MF_ENABLED); - } -} - -// fixme - this looks like the beginnings of a dynamic "list of valid saveslots" -// feature. Too bad it's never called and CheckState was old/dead code. -/*void UpdateMenuSlots() { - char str[g_MaxPath]; - int i; - - for (i=0; i<5; i++) { - sprintf_s (str, g_MaxPath, "sstates\\%8.8X.%3.3d", ElfCRC, i); - Slots[i] = CheckState(str); - } -}*/ - - -#define _ADDSUBMENU(menu, menun, string) \ - submenu[menun] = CreatePopupMenu(); \ - AppendMenu(menu, MF_STRING | MF_POPUP, (UINT)submenu[menun], string); - -#define ADDSUBMENU(menun, string) \ - _ADDSUBMENU(gApp.hMenu, menun, string); - -#define ADDSUBMENUS(submn, menun, string) \ - submenu[menun] = CreatePopupMenu(); \ - InsertMenu(submenu[submn], 0, MF_BYPOSITION | MF_STRING | MF_POPUP, (UINT)submenu[menun], string); - -#define ADDMENUITEM(menun, string, id) \ - item.fType = MFT_STRING; \ - item.fMask = MIIM_STATE | MIIM_TYPE | MIIM_ID; \ - item.fState = MFS_ENABLED; \ - item.wID = id; \ - sprintf(buf, string); \ - InsertMenuItem(submenu[menun], 0, TRUE, &item); - -#define ADDMENUITEMC(menun, string, id) \ - item.fType = MFT_STRING; \ - item.fMask = MIIM_STATE | MIIM_TYPE | MIIM_ID; \ - item.fState = MFS_ENABLED | MFS_CHECKED; \ - item.wID = id; \ - sprintf(buf, string); \ - InsertMenuItem(submenu[menun], 0, TRUE, &item); - -#define ADDSEPARATOR(menun) \ - item.fMask = MIIM_TYPE; \ - item.fType = MFT_SEPARATOR; \ - InsertMenuItem(submenu[menun], 0, TRUE, &item); - -void CreateMainMenu() { - MENUITEMINFO item; - HMENU submenu[5]; - char buf[256]; - int i; - - item.cbSize = sizeof(MENUITEMINFO); - item.dwTypeData = buf; - item.cch = 256; - - gApp.hMenu = CreateMenu(); - - //submenu = CreatePopupMenu(); - //AppendMenu(gApp.hMenu, MF_STRING | MF_POPUP, (UINT)submenu, _("&File")); - ADDSUBMENU(0, _("&File")); - ADDMENUITEM(0, _("E&xit"), ID_FILE_EXIT); - ADDSEPARATOR(0); - ADDSUBMENUS(0, 1, _("&States")); - ADDSEPARATOR(0); - ADDMENUITEM(0, _("&Open ELF File"), ID_FILEOPEN); - ADDMENUITEM(0, _("&Run CD/DVD"), ID_FILE_RUNCD); - ADDSUBMENUS(1, 3, _("&Save")); - ADDSUBMENUS(1, 2, _("&Load")); - ADDMENUITEM(2, _("&Other..."), ID_FILE_STATES_LOAD_OTHER); - ADDMENUITEM(2, _("Slot &4"), ID_FILE_STATES_LOAD_SLOT5); - ADDMENUITEM(2, _("Slot &3"), ID_FILE_STATES_LOAD_SLOT4); - ADDMENUITEM(2, _("Slot &2"), ID_FILE_STATES_LOAD_SLOT3); - ADDMENUITEM(2, _("Slot &1"), ID_FILE_STATES_LOAD_SLOT2); - ADDMENUITEM(2, _("Slot &0"), ID_FILE_STATES_LOAD_SLOT1); - ADDMENUITEM(3, _("&Other..."), ID_FILE_STATES_SAVE_OTHER); - ADDMENUITEM(3, _("Slot &4"), ID_FILE_STATES_SAVE_SLOT5); - ADDMENUITEM(3, _("Slot &3"), ID_FILE_STATES_SAVE_SLOT4); - ADDMENUITEM(3, _("Slot &2"), ID_FILE_STATES_SAVE_SLOT3); - ADDMENUITEM(3, _("Slot &1"), ID_FILE_STATES_SAVE_SLOT2); - ADDMENUITEM(3, _("Slot &0"), ID_FILE_STATES_SAVE_SLOT1); - - ADDSUBMENU(0, _("&Run")); - - ADDSUBMENUS(0, 1, _("&Process Priority")); - ADDMENUITEM(1, _("&Low"), ID_PROCESSLOW ); - ADDMENUITEM(1, _("High"), ID_PROCESSHIGH); - ADDMENUITEM(1, _("Normal"), ID_PROCESSNORMAL); - ADDMENUITEM(0,_("&Arguments"), ID_RUN_CMDLINE); - ADDMENUITEM(0,_("Re&set"), ID_RUN_RESET); - ADDMENUITEM(0,_("E&xecute"), ID_RUN_EXECUTE); - - ADDSUBMENU(0,_("&Config")); - ADDMENUITEM(0,_("Advanced"), ID_ADVANCED_OPTIONS); - ADDMENUITEM(0,_("Speed &Hacks"), ID_HACKS); - ADDMENUITEM(0,_("Gamefixes"), ID_GAMEFIXES); - ADDMENUITEM(0,_("&Patches"), ID_PATCHBROWSER); - ADDMENUITEM(0,_("C&pu"), ID_CONFIG_CPU); - ADDMENUITEM(0,_("&Memcards"), ID_CONFIG_MEMCARDS); - ADDSEPARATOR(0); - ADDMENUITEM(0,_("Fire&Wire"), ID_CONFIG_FW); - ADDMENUITEM(0,_("U&SB"), ID_CONFIG_USB); - ADDMENUITEM(0,_("D&ev9"), ID_CONFIG_DEV9); - ADDMENUITEM(0,_("C&dvdrom"), ID_CONFIG_CDVDROM); - ADDMENUITEM(0,_("&Sound"), ID_CONFIG_SOUND); - ADDMENUITEM(0,_("C&ontrollers"), ID_CONFIG_CONTROLLERS); - ADDMENUITEM(0,_("&Graphics"), ID_CONFIG_GRAPHICS); - ADDSEPARATOR(0); - ADDMENUITEM(0,_("&Configure"), ID_CONFIG_CONFIGURE); - - ADDSUBMENU(0,_("&Language")); - - for (i=langsMax-1; i>=0; i--) { - if (!strcmp(Config.Lang, langs[i].lang)) { - ADDMENUITEMC(0,ParseLang(langs[i].lang), ID_LANGS + i); - } else { - ADDMENUITEM(0,ParseLang(langs[i].lang), ID_LANGS + i); - } - } - -#ifdef PCSX2_DEVBUILD - ADDSUBMENU(0, _("&Debug")); - ADDMENUITEM(0,_("&Logging"), ID_DEBUG_LOGGING); - ADDMENUITEM(0,_("Memory Dump"), ID_DEBUG_MEMORY_DUMP); - ADDMENUITEM(0,_("&Remote Debugging"), ID_DEBUG_REMOTEDEBUGGING); - ADDMENUITEM(0,_("Enter &Debugger..."), ID_DEBUG_ENTERDEBUGGER); -#endif - - ADDSUBMENU(0, _("&Misc")); - ADDMENUITEM(0,_("Print cdvd &Info"), ID_CDVDPRINT); - ADDMENUITEM(0,_("Close GS Window on Esc"), ID_CLOSEGS); - ADDSEPARATOR(0); -#ifndef _DEBUG - ADDMENUITEM(0,_("Enable &Profiler"), ID_PROFILER); -#endif - ADDMENUITEM(0,_("Enable &Patches"), ID_PATCHES); - ADDMENUITEM(0,_("Enable &Console"), ID_CONSOLE); - ADDSEPARATOR(0); - ADDMENUITEM(0,_("Patch &Finder..."), ID_CHEAT_FINDER_SHOW); - ADDMENUITEM(0,_("Patch &Browser..."), ID_CHEAT_BROWSER_SHOW); - - - ADDSUBMENU(0, _("&Help")); - ADDMENUITEM(0,_("&Compatibility List..."), ID_HELP_HELP); - ADDMENUITEM(0,_("&About..."), ID_HELP_ABOUT); - - if( !IsDevBuild ) - EnableMenuItem(GetSubMenu(gApp.hMenu, 4), ID_DEBUG_LOGGING, MF_GRAYED); -} - -void CreateMainWindow(int nCmdShow) { - WNDCLASS wc; - HWND hWnd; - char buf[256]; - char COMPILER[20]=""; - BITMAP bm; - RECT rect; - int w, h; - - g_ReturnToGui = true; - -#ifdef _MSC_VER - sprintf(COMPILER, "(VC%d)", (_MSC_VER+100)/200);//hacky:) works for VC6 & VC.NET -#elif __BORLANDC__ - sprintf(COMPILER, "(BC)"); -#endif - /* Load Background Bitmap from the ressource */ - hbitmap_background = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(SPLASH_LOGO)); - - wc.lpszClassName = "PCSX2 Main"; - wc.lpfnWndProc = MainWndProc; - wc.style = 0; - wc.hInstance = gApp.hInstance; - wc.hIcon = LoadIcon(gApp.hInstance, MAKEINTRESOURCE(IDI_ICON)); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = (HBRUSH)(COLOR_MENUTEXT); - wc.lpszMenuName = 0; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - - RegisterClass(&wc); - GetObject(hbitmap_background, sizeof(bm), &bm); - - { - const char* pvm = "VTLB"; - -#ifdef PCSX2_DEVBUILD - sprintf(buf, _("PCSX2 %s - %s Compile Date - %s %s"), PCSX2_VERSION, pvm, COMPILEDATE, COMPILER); -#else - sprintf(buf, _("PCSX2 %s - %s"), PCSX2_VERSION, pvm); -#endif - } - - hWnd = CreateWindow( - "PCSX2 Main", - buf, WS_OVERLAPPED | WS_SYSMENU, - 20, 20, 320, 240, - NULL, NULL, - gApp.hInstance, NULL - ); - - gApp.hWnd = hWnd; - ResetMenuSlots(); - CreateMainMenu(); - - SetMenu(gApp.hWnd, gApp.hMenu); - if(Config.ThPriority==THREAD_PRIORITY_NORMAL) CheckMenuItem(gApp.hMenu,ID_PROCESSNORMAL,MF_CHECKED); - if(Config.ThPriority==THREAD_PRIORITY_HIGHEST) CheckMenuItem(gApp.hMenu,ID_PROCESSHIGH,MF_CHECKED); - if(Config.ThPriority==THREAD_PRIORITY_LOWEST) CheckMenuItem(gApp.hMenu,ID_PROCESSLOW,MF_CHECKED); - if(Config.PsxOut) CheckMenuItem(gApp.hMenu,ID_CONSOLE,MF_CHECKED); - if(Config.Patch) CheckMenuItem(gApp.hMenu,ID_PATCHES,MF_CHECKED); - if(Config.Profiler) CheckMenuItem(gApp.hMenu,ID_PROFILER,MF_CHECKED); - if(Config.cdvdPrint)CheckMenuItem(gApp.hMenu,ID_CDVDPRINT,MF_CHECKED); - if(Config.closeGSonEsc)CheckMenuItem(gApp.hMenu,ID_CLOSEGS,MF_CHECKED); - - hStatusWnd = CreateStatusWindow(WS_CHILD | WS_VISIBLE, "", hWnd, 100); - - w = bm.bmWidth; h = bm.bmHeight; - GetWindowRect(hStatusWnd, &rect); - h+= rect.bottom - rect.top; - GetMenuItemRect(hWnd, gApp.hMenu, 0, &rect); - h+= rect.bottom - rect.top; - MoveWindow(hWnd, 60, 60, w, h, TRUE); - SendMessage( hStatusWnd, WM_SIZE, 0, 0 ); - - StatusBar_SetMsg("F1 - save, F2 - next state, Shift+F2 - prev state, F3 - load, F8 - snapshot"); - - ShowWindow(hWnd, nCmdShow); - SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); -} - - -WIN32_FIND_DATA lFindData; -HANDLE lFind; -int lFirst; - -void InitLanguages() { - lFind = FindFirstFile("Langs\\*", &lFindData); - lFirst = 1; -} - -char *GetLanguageNext() { - for (;;) { - if (!strcmp(lFindData.cFileName, ".")) { - if (FindNextFile(lFind, &lFindData) == FALSE) - return NULL; - continue; - } - if (!strcmp(lFindData.cFileName, "..")) { - if (FindNextFile(lFind, &lFindData) == FALSE) - return NULL; - continue; - } - break; - } - if (lFirst == 0) { - if (FindNextFile(lFind, &lFindData) == FALSE) - return NULL; - } else lFirst = 0; - if (lFind==INVALID_HANDLE_VALUE) return NULL; - - return lFindData.cFileName; -} - -void CloseLanguages() { - if (lFind!=INVALID_HANDLE_VALUE) FindClose(lFind); -} - -void ChangeLanguage(char *lang) { - strcpy_s(Config.Lang, lang); - SaveConfig(); - LoadConfig(); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" +#include "win32.h" + +#include +#include +#include + +#include + +#include "Common.h" +#include "debugger.h" +#include "rdebugger.h" +#include "AboutDlg.h" +#include "McdsDlg.h" + +#include "Patch.h" +#include "cheats/cheats.h" + +#include "Paths.h" +#include "SamplProf.h" + +#include "implement.h" // pthreads-win32 defines for startup/shutdown + +unsigned int langsMax; + + +struct _langs { + TCHAR lang[256]; +}; + +_langs *langs = NULL; + +void strcatz(char *dst, char *src) +{ + int len = strlen(dst) + 1; + strcpy(dst + len, src); +} + +//2002-09-20 (Florin) +BOOL APIENTRY CmdlineProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);//forward def +//------------------- + +TESTRUNARGS g_TestRun; + +static const char* phelpmsg = + "pcsx2 [options] [file]\n\n" + "-cfg [file] {configuration file}\n" + "-efile [efile] {0 - reset, 1 - runcd (default), 2 - loadelf}\n" + "-help {display this help file}\n" + "-nogui {Don't use gui when launching}\n" + "-loadgs [file] {Loads a gsstate}\n" + "\n" + +#ifdef PCSX2_DEVBUILD + "Testing Options: \n" + "\t-frame [frame] {game will run up to this frame before exiting}\n" + "\t-image [name] {path and base name of image (do not include the .ext)}\n" + "\t-jpg {save images to jpg format}\n" + "\t-log [name] {log path to save log file in}\n" + "\t-logopt [hex] {log options in hex (see debug.h) }\n" + "\t-numimages [num] {after hitting frame, this many images will be captures every 20 frames}\n" + "\t-test {Triggers testing mode (only for dev builds)}\n" + "\n" +#endif + + "Load Plugins:\n" + "\t-cdvd [dllpath] {specify the dll load path of the CDVD plugin}\n" + "\t-gs [dllpath] {specify the dll load path of the GS plugin}\n" + "\t-spu [dllpath] {specify the dll load path of the SPU2 plugin}\n" + "\n"; + +/// This code is courtesy of http://alter.org.ua/en/docs/win/args/ +static PTCHAR* _CommandLineToArgv( const TCHAR *CmdLine, int* _argc ) +{ + PTCHAR* argv; + PTCHAR _argv; + ULONG len; + ULONG argc; + TCHAR a; + ULONG i, j; + + BOOLEAN in_QM; + BOOLEAN in_TEXT; + BOOLEAN in_SPACE; + + len = _tcslen( CmdLine ); + i = ((len+2)/2)*sizeof(PVOID) + sizeof(PVOID); + + argv = (PTCHAR*)GlobalAlloc(GMEM_FIXED, + i + (len+2)*sizeof(a)); + + _argv = (PTCHAR)(((PUCHAR)argv)+i); + + argc = 0; + argv[argc] = _argv; + in_QM = FALSE; + in_TEXT = FALSE; + in_SPACE = TRUE; + i = 0; + j = 0; + + while( a = CmdLine[i] ) { + if(in_QM) { + if(a == '\"') { + in_QM = FALSE; + } else { + _argv[j] = a; + j++; + } + } else { + switch(a) { + case '\"': + in_QM = TRUE; + in_TEXT = TRUE; + if(in_SPACE) { + argv[argc] = _argv+j; + argc++; + } + in_SPACE = FALSE; + break; + case ' ': + case '\t': + case '\n': + case '\r': + if(in_TEXT) { + _argv[j] = '\0'; + j++; + } + in_TEXT = FALSE; + in_SPACE = TRUE; + break; + default: + in_TEXT = TRUE; + if(in_SPACE) { + argv[argc] = _argv+j; + argc++; + } + _argv[j] = a; + j++; + in_SPACE = FALSE; + break; + } + } + i++; + } + _argv[j] = '\0'; + argv[argc] = NULL; + + (*_argc) = argc; + return argv; +} + +void WinClose() +{ + SysClose(); + + // Don't check Config.Profiler here -- the Profiler will know if it's running or not. + ProfilerTerm(); + + ReleasePlugins(); + Console::Close(); + + pthread_win32_process_detach_np(); + + SysShutdownDynarecs(); + SysShutdownMem(); +} + +BOOL SysLoggedSetLockPagesPrivilege ( HANDLE hProcess, BOOL bEnable); + +// Returns TRUE if the test run mode was activaated (game was run and has been exited) +static bool TestRunMode() +{ + if( IsDevBuild && (g_TestRun.enabled || g_TestRun.ptitle != NULL) ) + { + // run without ui + UseGui = 0; + PCSX2_MEM_PROTECT_BEGIN(); + RunExecute( g_TestRun.efile ? g_TestRun.ptitle : NULL ); + PCSX2_MEM_PROTECT_END(); + return true; + } + return false; +} + +void WinRun( int nCmdShow ) +{ + // Load the command line overrides for plugins. + // Back up the user's preferences in winConfig. + + memcpy( &winConfig, &Config, sizeof( PcsxConfig ) ); + + if( g_TestRun.pgsdll ) + { + _tcscpy_s( Config.GS, g_MaxPath, g_TestRun.pgsdll ); + Console::Notice( "* GS plugin override: \n\t%s\n", params Config.GS ); + } + if( g_TestRun.pcdvddll ) + { + _tcscpy_s( Config.CDVD, g_MaxPath, g_TestRun.pcdvddll ); + Console::Notice( "* CDVD plugin override: \n\t%s\n", params Config.CDVD ); + } + if( g_TestRun.pspudll ) + { + _tcscpy_s( Config.SPU2, g_MaxPath, g_TestRun.pspudll ); + Console::Notice( "* SPU2 plugin override: \n\t%s\n", params Config.SPU2 ); + } + + // [TODO] : Add the other plugin overrides here... + +#ifndef _DEBUG + if( Config.Profiler ) + ProfilerInit(); +#endif + + InitCPUTicks(); + + while (LoadPlugins() == -1) + { + if (Pcsx2Configure(NULL) == FALSE) return; + } + + if( TestRunMode() ) return; + +#ifdef PCSX2_DEVBUILD + if( g_pRunGSState ) { + LoadGSState(g_pRunGSState); + return; + } +#endif + + CreateMainWindow( nCmdShow ); + + if( Config.PsxOut ) + { + // output the help commands + Console::SetColor( Console::Color_White ); + + Console::WriteLn( "Hotkeys:" ); + + Console::WriteLn( + "\tF1 - save state\n" + "\t(Shift +) F2 - cycle states\n" + "\tF3 - load state" + ); + + DevCon::WriteLn( + //"\tF10 - dump performance counters\n" + "\tF11 - save GS state\n" + //"\tF12 - dump hardware registers" + ); + Console::ClearColor(); + } + + RunGui(); +} + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + char *lang; + int i; + + CreateDirectory(LOGS_DIR, NULL); + + InitCommonControls(); + pInstance=hInstance; + FirstShow=true; // this is used by cheats.cpp to search for stuff (broken?) + + pthread_win32_process_attach_np(); + + gApp.hInstance = hInstance; + gApp.hMenu = NULL; + gApp.hWnd = NULL; + +#ifdef ENABLE_NLS + bindtextdomain(PACKAGE, "Langs\\"); + textdomain(PACKAGE); +#endif + + memzero_obj(g_TestRun); + + _getcwd( g_WorkingFolder, g_MaxPath ); + + int argc; + TCHAR *const *const argv = _CommandLineToArgv( lpCmdLine, &argc ); + + if( argv == NULL ) + { + Msgbox::Alert( "A fatal error occured while attempting to parse the command line.\n" ); + return 2; + } + + switch( ParseCommandLine( argc, argv ) ) + { + case 1: // display help and exit: + printf( "%s", phelpmsg ); + MessageBox( NULL, phelpmsg, "Pcsx2 Help", MB_OK); + + case -1: // exit... + return 0; + } + + try + { + bool needsToConfig = !LoadConfig(); + + // Enumerate available translations + + if (needsToConfig || Config.Lang[0] == 0) { + strcpy(Config.Lang, "en_US"); + } + + langs = (_langs*)malloc(sizeof(_langs)); + strcpy(langs[0].lang, "en_US"); + InitLanguages(); i=1; + while ((lang = GetLanguageNext()) != NULL) { + langs = (_langs*)realloc(langs, sizeof(_langs)*(i+1)); + strcpy(langs[i].lang, lang); + i++; + } + CloseLanguages(); + langsMax = i; + + // automatically and always open the console for first-time uses (no ini file) + if(needsToConfig || Config.PsxOut ) + Console::Open(); + + // Important! Always allocate dynarecs before loading plugins, to give the dynarecs + // the best possible chance of claiming ideal memory space! + + SysInit(); + + if( needsToConfig ) + { + // Prompt the user for a valid configuration before starting the program. + Msgbox::Alert( _( "Pcsx2 needs to be configured." ) ); + Pcsx2Configure( NULL ); + LoadConfig(); // forces re-loading of language and stuff. + } + + if( Config.PsxOut ) + Console::Open(); + else + Console::Close(); + + WinRun( nCmdShow ); + } + catch( Exception::BaseException& ex ) + { + Msgbox::Alert( + "An unhandled or unrecoverable exception occurred, with the message:\n\n" + "%s" + "\n\nPcsx2 will now close. More details may be available via the emuLog.txt file.", params + ex.cMessage() + ); + } + catch( std::exception& ex ) + { + Msgbox::Alert( + "An unhandled or unrecoverable exception occurred, with the message:\n\n" + "%s" + "\n\nPcsx2 will now close. More details may be available via the emuLog.txt file.", params + ex.what() + ); + } + + WinClose(); + + return 0; +} + +static std::string str_Default( "default" ); + +void RunGui() +{ + MSG msg; + + PCSX2_MEM_PROTECT_BEGIN(); + + LoadPatch(str_Default); + + while( true ) + { + if( PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE) != 0 ) + { + if( msg.message == WM_QUIT ) return; + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + Sleep(10); + } + + PCSX2_MEM_PROTECT_END(); +} + +BOOL Open_File_Proc( std::string& outstr ) +{ + OPENFILENAME ofn; + char szFileName[ g_MaxPath ]; + char szFileTitle[ g_MaxPath ]; + char * filter = "ELF Files (*.ELF)\0*.ELF\0ALL Files (*.*)\0*.*\0"; + + memzero_obj( szFileName ); + memzero_obj( szFileTitle ); + + ofn.lStructSize = sizeof( OPENFILENAME ); + ofn.hwndOwner = gApp.hWnd; + ofn.lpstrFilter = filter; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 1; + ofn.lpstrFile = szFileName; + ofn.nMaxFile = g_MaxPath; + ofn.lpstrInitialDir = NULL; + ofn.lpstrFileTitle = szFileTitle; + ofn.nMaxFileTitle = g_MaxPath; + ofn.lpstrTitle = NULL; + ofn.lpstrDefExt = "ELF"; + ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_EXPLORER; + + if (GetOpenFileName(&ofn)) { + struct stat buf; + + if (stat(szFileName, &buf) != 0) { + return FALSE; + } + + outstr = szFileName; + return TRUE; + } + + return FALSE; +} + +//2002-09-20 (Florin) +BOOL APIENTRY CmdlineProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + SetWindowText(hDlg, _("Program arguments")); + + Button_SetText(GetDlgItem(hDlg, IDOK), _("OK")); + Button_SetText(GetDlgItem(hDlg, IDCANCEL), _("Cancel")); + Static_SetText(GetDlgItem(hDlg, IDC_TEXT), _("Fill in the command line arguments for opened program:")); + Static_SetText(GetDlgItem(hDlg, IDC_TIP), _("Tip: If you don't know what to write\nleave it blank")); + + SetDlgItemText(hDlg, IDC_CMDLINE, args); + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) + { + char tmp[256]; + + GetDlgItemText(hDlg, IDC_CMDLINE, tmp, 256); + + strcpy_s(args, 256, tmp); + + EndDialog(hDlg, TRUE); + } else if (LOWORD(wParam) == IDCANCEL) { + EndDialog(hDlg, TRUE); + } + return TRUE; + } + + return FALSE; +} + + +#ifdef PCSX2_DEVBUILD + +BOOL APIENTRY LogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { + int i; + switch (message) { + case WM_INITDIALOG: + for (i=0; i<32; i++) + if (varLog & (1<= ID_LANGS && LOWORD(wParam) <= (ID_LANGS + langsMax)) { + DestroyWindow(gApp.hWnd); + ChangeLanguage(langs[LOWORD(wParam) - ID_LANGS].lang); + CreateMainWindow(SW_SHOWNORMAL); + return TRUE; + } + } + return TRUE; + + case WM_DESTROY: + DeleteObject(hbitmap_background); + PostQuitMessage(0); + gApp.hWnd = NULL; + return FALSE; + + // Explicit handling of WM_CLOSE. + // This is Windows default behavior, but we handle it here sot hat we might add a + // user confirmation prompt prior to exit (someday!) + case WM_CLOSE: + DestroyWindow( hWnd ); + return TRUE; + + case WM_SYSCOMMAND: + if( nDisableSC && (wParam== SC_SCREENSAVE || wParam == SC_MONITORPOWER) ) { + return FALSE; + } + break; + } + + return DefWindowProc(hWnd, msg, wParam, lParam); +} + +int Slots[5] = { -1, -1, -1, -1, -1 }; + +void ResetMenuSlots() { + int i; + + for (i=0; i<5; i++) { + if (Slots[i] == -1) + EnableMenuItem(GetSubMenu(gApp.hMenu, 0), ID_FILE_STATES_LOAD_SLOT1+i, MF_GRAYED); + else + EnableMenuItem(GetSubMenu(gApp.hMenu, 0), ID_FILE_STATES_LOAD_SLOT1+i, MF_ENABLED); + } +} + +// fixme - this looks like the beginnings of a dynamic "list of valid saveslots" +// feature. Too bad it's never called and CheckState was old/dead code. +/*void UpdateMenuSlots() { + char str[g_MaxPath]; + int i; + + for (i=0; i<5; i++) { + sprintf_s (str, g_MaxPath, "sstates\\%8.8X.%3.3d", ElfCRC, i); + Slots[i] = CheckState(str); + } +}*/ + + +#define _ADDSUBMENU(menu, menun, string) \ + submenu[menun] = CreatePopupMenu(); \ + AppendMenu(menu, MF_STRING | MF_POPUP, (UINT)submenu[menun], string); + +#define ADDSUBMENU(menun, string) \ + _ADDSUBMENU(gApp.hMenu, menun, string); + +#define ADDSUBMENUS(submn, menun, string) \ + submenu[menun] = CreatePopupMenu(); \ + InsertMenu(submenu[submn], 0, MF_BYPOSITION | MF_STRING | MF_POPUP, (UINT)submenu[menun], string); + +#define ADDMENUITEM(menun, string, id) \ + item.fType = MFT_STRING; \ + item.fMask = MIIM_STATE | MIIM_TYPE | MIIM_ID; \ + item.fState = MFS_ENABLED; \ + item.wID = id; \ + sprintf(buf, string); \ + InsertMenuItem(submenu[menun], 0, TRUE, &item); + +#define ADDMENUITEMC(menun, string, id) \ + item.fType = MFT_STRING; \ + item.fMask = MIIM_STATE | MIIM_TYPE | MIIM_ID; \ + item.fState = MFS_ENABLED | MFS_CHECKED; \ + item.wID = id; \ + sprintf(buf, string); \ + InsertMenuItem(submenu[menun], 0, TRUE, &item); + +#define ADDSEPARATOR(menun) \ + item.fMask = MIIM_TYPE; \ + item.fType = MFT_SEPARATOR; \ + InsertMenuItem(submenu[menun], 0, TRUE, &item); + +void CreateMainMenu() { + MENUITEMINFO item; + HMENU submenu[5]; + char buf[256]; + int i; + + item.cbSize = sizeof(MENUITEMINFO); + item.dwTypeData = buf; + item.cch = 256; + + gApp.hMenu = CreateMenu(); + + //submenu = CreatePopupMenu(); + //AppendMenu(gApp.hMenu, MF_STRING | MF_POPUP, (UINT)submenu, _("&File")); + ADDSUBMENU(0, _("&File")); + ADDMENUITEM(0, _("E&xit"), ID_FILE_EXIT); + ADDSEPARATOR(0); + ADDSUBMENUS(0, 1, _("&States")); + ADDSEPARATOR(0); + ADDMENUITEM(0, _("&Open ELF File"), ID_FILEOPEN); + ADDMENUITEM(0, _("&Run CD/DVD"), ID_FILE_RUNCD); + ADDSUBMENUS(1, 3, _("&Save")); + ADDSUBMENUS(1, 2, _("&Load")); + ADDMENUITEM(2, _("&Other..."), ID_FILE_STATES_LOAD_OTHER); + ADDMENUITEM(2, _("Slot &4"), ID_FILE_STATES_LOAD_SLOT5); + ADDMENUITEM(2, _("Slot &3"), ID_FILE_STATES_LOAD_SLOT4); + ADDMENUITEM(2, _("Slot &2"), ID_FILE_STATES_LOAD_SLOT3); + ADDMENUITEM(2, _("Slot &1"), ID_FILE_STATES_LOAD_SLOT2); + ADDMENUITEM(2, _("Slot &0"), ID_FILE_STATES_LOAD_SLOT1); + ADDMENUITEM(3, _("&Other..."), ID_FILE_STATES_SAVE_OTHER); + ADDMENUITEM(3, _("Slot &4"), ID_FILE_STATES_SAVE_SLOT5); + ADDMENUITEM(3, _("Slot &3"), ID_FILE_STATES_SAVE_SLOT4); + ADDMENUITEM(3, _("Slot &2"), ID_FILE_STATES_SAVE_SLOT3); + ADDMENUITEM(3, _("Slot &1"), ID_FILE_STATES_SAVE_SLOT2); + ADDMENUITEM(3, _("Slot &0"), ID_FILE_STATES_SAVE_SLOT1); + + ADDSUBMENU(0, _("&Run")); + + ADDSUBMENUS(0, 1, _("&Process Priority")); + ADDMENUITEM(1, _("&Low"), ID_PROCESSLOW ); + ADDMENUITEM(1, _("High"), ID_PROCESSHIGH); + ADDMENUITEM(1, _("Normal"), ID_PROCESSNORMAL); + ADDMENUITEM(0,_("&Arguments"), ID_RUN_CMDLINE); + ADDMENUITEM(0,_("Re&set"), ID_RUN_RESET); + ADDMENUITEM(0,_("E&xecute"), ID_RUN_EXECUTE); + + ADDSUBMENU(0,_("&Config")); + ADDMENUITEM(0,_("Advanced"), ID_ADVANCED_OPTIONS); + ADDMENUITEM(0,_("Speed &Hacks"), ID_HACKS); + ADDMENUITEM(0,_("Gamefixes"), ID_GAMEFIXES); + ADDMENUITEM(0,_("&Patches"), ID_PATCHBROWSER); + ADDMENUITEM(0,_("C&pu"), ID_CONFIG_CPU); + ADDMENUITEM(0,_("&Memcards"), ID_CONFIG_MEMCARDS); + ADDSEPARATOR(0); + ADDMENUITEM(0,_("Fire&Wire"), ID_CONFIG_FW); + ADDMENUITEM(0,_("U&SB"), ID_CONFIG_USB); + ADDMENUITEM(0,_("D&ev9"), ID_CONFIG_DEV9); + ADDMENUITEM(0,_("C&dvdrom"), ID_CONFIG_CDVDROM); + ADDMENUITEM(0,_("&Sound"), ID_CONFIG_SOUND); + ADDMENUITEM(0,_("C&ontrollers"), ID_CONFIG_CONTROLLERS); + ADDMENUITEM(0,_("&Graphics"), ID_CONFIG_GRAPHICS); + ADDSEPARATOR(0); + ADDMENUITEM(0,_("&Configure"), ID_CONFIG_CONFIGURE); + + ADDSUBMENU(0,_("&Language")); + + for (i=langsMax-1; i>=0; i--) { + if (!strcmp(Config.Lang, langs[i].lang)) { + ADDMENUITEMC(0,ParseLang(langs[i].lang), ID_LANGS + i); + } else { + ADDMENUITEM(0,ParseLang(langs[i].lang), ID_LANGS + i); + } + } + +#ifdef PCSX2_DEVBUILD + ADDSUBMENU(0, _("&Debug")); + ADDMENUITEM(0,_("&Logging"), ID_DEBUG_LOGGING); + ADDMENUITEM(0,_("Memory Dump"), ID_DEBUG_MEMORY_DUMP); + ADDMENUITEM(0,_("&Remote Debugging"), ID_DEBUG_REMOTEDEBUGGING); + ADDMENUITEM(0,_("Enter &Debugger..."), ID_DEBUG_ENTERDEBUGGER); +#endif + + ADDSUBMENU(0, _("&Misc")); + ADDMENUITEM(0,_("Print cdvd &Info"), ID_CDVDPRINT); + ADDMENUITEM(0,_("Close GS Window on Esc"), ID_CLOSEGS); + ADDSEPARATOR(0); +#ifndef _DEBUG + ADDMENUITEM(0,_("Enable &Profiler"), ID_PROFILER); +#endif + ADDMENUITEM(0,_("Enable &Patches"), ID_PATCHES); + ADDMENUITEM(0,_("Enable &Console"), ID_CONSOLE); + ADDSEPARATOR(0); + ADDMENUITEM(0,_("Patch &Finder..."), ID_CHEAT_FINDER_SHOW); + ADDMENUITEM(0,_("Patch &Browser..."), ID_CHEAT_BROWSER_SHOW); + + + ADDSUBMENU(0, _("&Help")); + ADDMENUITEM(0,_("&Compatibility List..."), ID_HELP_HELP); + ADDMENUITEM(0,_("&About..."), ID_HELP_ABOUT); + + if( !IsDevBuild ) + EnableMenuItem(GetSubMenu(gApp.hMenu, 4), ID_DEBUG_LOGGING, MF_GRAYED); +} + +void CreateMainWindow(int nCmdShow) { + WNDCLASS wc; + HWND hWnd; + char buf[256]; + char COMPILER[20]=""; + BITMAP bm; + RECT rect; + int w, h; + + g_ReturnToGui = true; + +#ifdef _MSC_VER + sprintf(COMPILER, "(VC%d)", (_MSC_VER+100)/200);//hacky:) works for VC6 & VC.NET +#elif __BORLANDC__ + sprintf(COMPILER, "(BC)"); +#endif + /* Load Background Bitmap from the ressource */ + hbitmap_background = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(SPLASH_LOGO)); + + wc.lpszClassName = "PCSX2 Main"; + wc.lpfnWndProc = MainWndProc; + wc.style = 0; + wc.hInstance = gApp.hInstance; + wc.hIcon = LoadIcon(gApp.hInstance, MAKEINTRESOURCE(IDI_ICON)); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_MENUTEXT); + wc.lpszMenuName = 0; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + + RegisterClass(&wc); + GetObject(hbitmap_background, sizeof(bm), &bm); + + { + const char* pvm = "VTLB"; + +#ifdef PCSX2_DEVBUILD + sprintf(buf, _("PCSX2 %s - %s Compile Date - %s %s"), PCSX2_VERSION, pvm, COMPILEDATE, COMPILER); +#else + sprintf(buf, _("PCSX2 %s - %s"), PCSX2_VERSION, pvm); +#endif + } + + hWnd = CreateWindow( + "PCSX2 Main", + buf, WS_OVERLAPPED | WS_SYSMENU, + 20, 20, 320, 240, + NULL, NULL, + gApp.hInstance, NULL + ); + + gApp.hWnd = hWnd; + ResetMenuSlots(); + CreateMainMenu(); + + SetMenu(gApp.hWnd, gApp.hMenu); + if(Config.ThPriority==THREAD_PRIORITY_NORMAL) CheckMenuItem(gApp.hMenu,ID_PROCESSNORMAL,MF_CHECKED); + if(Config.ThPriority==THREAD_PRIORITY_HIGHEST) CheckMenuItem(gApp.hMenu,ID_PROCESSHIGH,MF_CHECKED); + if(Config.ThPriority==THREAD_PRIORITY_LOWEST) CheckMenuItem(gApp.hMenu,ID_PROCESSLOW,MF_CHECKED); + if(Config.PsxOut) CheckMenuItem(gApp.hMenu,ID_CONSOLE,MF_CHECKED); + if(Config.Patch) CheckMenuItem(gApp.hMenu,ID_PATCHES,MF_CHECKED); + if(Config.Profiler) CheckMenuItem(gApp.hMenu,ID_PROFILER,MF_CHECKED); + if(Config.cdvdPrint)CheckMenuItem(gApp.hMenu,ID_CDVDPRINT,MF_CHECKED); + if(Config.closeGSonEsc)CheckMenuItem(gApp.hMenu,ID_CLOSEGS,MF_CHECKED); + + hStatusWnd = CreateStatusWindow(WS_CHILD | WS_VISIBLE, "", hWnd, 100); + + w = bm.bmWidth; h = bm.bmHeight; + GetWindowRect(hStatusWnd, &rect); + h+= rect.bottom - rect.top; + GetMenuItemRect(hWnd, gApp.hMenu, 0, &rect); + h+= rect.bottom - rect.top; + MoveWindow(hWnd, 60, 60, w, h, TRUE); + SendMessage( hStatusWnd, WM_SIZE, 0, 0 ); + + StatusBar_SetMsg("F1 - save, F2 - next state, Shift+F2 - prev state, F3 - load, F8 - snapshot"); + + ShowWindow(hWnd, nCmdShow); + SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); +} + + +WIN32_FIND_DATA lFindData; +HANDLE lFind; +int lFirst; + +void InitLanguages() { + lFind = FindFirstFile("Langs\\*", &lFindData); + lFirst = 1; +} + +char *GetLanguageNext() { + for (;;) { + if (!strcmp(lFindData.cFileName, ".")) { + if (FindNextFile(lFind, &lFindData) == FALSE) + return NULL; + continue; + } + if (!strcmp(lFindData.cFileName, "..")) { + if (FindNextFile(lFind, &lFindData) == FALSE) + return NULL; + continue; + } + break; + } + if (lFirst == 0) { + if (FindNextFile(lFind, &lFindData) == FALSE) + return NULL; + } else lFirst = 0; + if (lFind==INVALID_HANDLE_VALUE) return NULL; + + return lFindData.cFileName; +} + +void CloseLanguages() { + if (lFind!=INVALID_HANDLE_VALUE) FindClose(lFind); +} + +void ChangeLanguage(char *lang) { + strcpy_s(Config.Lang, lang); + SaveConfig(); + LoadConfig(); +} diff --git a/pcsx2/windows/WinSysExec.cpp b/pcsx2/windows/WinSysExec.cpp index c9bb289a34..ed760f4017 100644 --- a/pcsx2/windows/WinSysExec.cpp +++ b/pcsx2/windows/WinSysExec.cpp @@ -1,835 +1,835 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" -#include "win32.h" - -#include -#include - -#include "Common.h" -//#include "PsxCommon.h" -#include "VUmicro.h" - -#include "iR5900.h" - -int UseGui = 1; -int nDisableSC = 0; // screensaver - -MemoryAlloc* g_RecoveryState = NULL; -MemoryAlloc* g_gsRecoveryState = NULL; - - -bool g_ReturnToGui = false; // set to exit the execution of the emulator and return control to the GUI -bool g_EmulationInProgress = false; // Set TRUE if a game is actively running (set to false on reset) - -// This instance is not modified by command line overrides so -// that command line plugins and stuff won't be saved into the -// user's conf file accidentally. -PcsxConfig winConfig; // local storage of the configuration options. - -HWND hStatusWnd = NULL; -AppData gApp; - -const char* g_pRunGSState = NULL; - - -#define CmdSwitchIs( text ) ( stricmp( command, text ) == 0 ) - -// For issuing notices to both the status bar and the console at the same time. -// Single-line text only please! Mutli-line msgs should be directed to the -// console directly, thanks. -void StatusBar_Notice( const std::string& text ) -{ - // mirror output to the console! - Console::Status( text.c_str() ); - - // don't try this in GCC folks! - SendMessage(hStatusWnd, SB_SETTEXT, 0, (LPARAM)text.c_str() ); -} - -// Sets the status bar message without mirroring the output to the console. -void StatusBar_SetMsg( const std::string& text ) -{ - // don't try this in GCC folks! - SendMessage(hStatusWnd, SB_SETTEXT, 0, (LPARAM)text.c_str() ); -} - -// returns 1 if the user requested help (show help and exit) -// returns zero on success. -// returns -1 on failure (bad command line argument) -int ParseCommandLine( int tokenCount, TCHAR *const *const tokens ) -{ - int tidx = 0; - g_TestRun.efile = 0; - - while( tidx < tokenCount ) - { - const TCHAR* command = tokens[tidx++]; - - if( command[0] != '-' ) - { - g_TestRun.ptitle = command; - printf("opening file %s\n", command); - continue; - } - - // jump past the '-' switch char, and skip if this is a dud switch: - command++; - if( command[0] == 0 ) continue; - - if( CmdSwitchIs( "help" ) ) - { - return -1; - } - else if( CmdSwitchIs( "nogui" ) ) { - UseGui = 0; - } -#ifdef PCSX2_DEVBUILD - else if( CmdSwitchIs( "jpg" ) ) { - g_TestRun.jpgcapture = 1; - } -#endif - else - { - const TCHAR* param; - if( tidx >= tokenCount ) break; - - // None of the parameter-less toggles flagged. - // Check for switches that require one or more parameters here: - - param = tokens[tidx++]; - - if( CmdSwitchIs( "cfg" ) ) { - g_CustomConfigFile = param; - } - - else if( CmdSwitchIs( "efile" ) ) { - g_TestRun.efile = !!atoi( param ); - } - else if( CmdSwitchIs( "loadgs" ) ) { - g_pRunGSState = param; - } - - // Options to configure plugins: - - else if( CmdSwitchIs( "gs" ) ) { - g_TestRun.pgsdll = param; - } - else if( CmdSwitchIs( "cdvd" ) ) { - g_TestRun.pcdvddll = param; - } - else if( CmdSwitchIs( "spu" ) ) { - g_TestRun.pspudll = param; - } - -#ifdef PCSX2_DEVBUILD - else if( CmdSwitchIs( "image" ) ) { - g_TestRun.pimagename = param; - } - else if( CmdSwitchIs( "log" ) ) { - g_TestRun.plogname = param; - } - else if( CmdSwitchIs( "logopt" ) ) { - if( param[0] == '0' && param[1] == 'x' ) param += 2; - sscanf(param, "%x", &varLog); - } - else if( CmdSwitchIs( "frame" ) ) { - g_TestRun.frame = atoi( param ); - } - else if( CmdSwitchIs( "numimages" ) ) { - g_TestRun.numimages = atoi( param ); - } -#endif - } - } - return 0; -} - -void SysPrintf(const char *fmt, ...) -{ - va_list list; - char msg[512]; - - va_start(list,fmt); - vsprintf_s(msg,fmt,list); - msg[511] = '\0'; - va_end(list); - - Console::Write( msg ); -} - -static void __fastcall KeyEvent(keyEvent* ev); - -__forceinline void SysUpdate() { - - keyEvent* ev1 = PAD1keyEvent(); - keyEvent* ev2 = PAD2keyEvent(); - - KeyEvent( (ev1 != NULL) ? ev1 : ev2); -} - -static void TryRecoverFromGsState() -{ - if( g_gsRecoveryState != NULL ) - { - s32 dummylen; - - memLoadingState eddie( *g_gsRecoveryState ); - eddie.FreezePlugin( "GS", gsSafeFreeze ); - eddie.Freeze( dummylen ); // reads the length value recorded earlier. - eddie.gsFreeze(); - } -} - -void ExecuteCpu() -{ - // Make sure any left-over recovery states are cleaned up. - safe_delete( g_RecoveryState ); - - // Just in case they weren't initialized earlier (no harm in calling this multiple times) - if (OpenPlugins(NULL) == -1) return; - - // this needs to be called for every new game! - // (note: sometimes launching games through bios will give a crc of 0) - - if( GSsetGameCRC != NULL ) - GSsetGameCRC(ElfCRC, g_ZeroGSOptions); - - TryRecoverFromGsState(); - - safe_delete( g_gsRecoveryState ); - - // ... and hide the window. Ugly thing. - - ShowWindow( gApp.hWnd, SW_HIDE ); - - g_EmulationInProgress = true; - g_ReturnToGui = false; - - // Optimization: We hardcode two versions of the EE here -- one for recs and one for ints. - // This is because recs are performance critical, and being able to inline them into the - // function here helps a small bit (not much but every small bit counts!). - - timeBeginPeriod( 1 ); - - if( CHECK_EEREC ) - { - while( !g_ReturnToGui ) - { - recExecute(); - SysUpdate(); - } - } - else - { - while( !g_ReturnToGui ) - { - Cpu->Execute(); - SysUpdate(); - } - } - - timeEndPeriod( 1 ); - - ShowWindow( gApp.hWnd, SW_SHOW ); - SetForegroundWindow( gApp.hWnd ); -} - -// Runs and ELF image directly (ISO or ELF program or BIN) -// Used by Run::FromCD and such -void RunExecute( const char* elf_file, bool use_bios ) -{ - SetThreadPriority(GetCurrentThread(), Config.ThPriority); - SetPriorityClass(GetCurrentProcess(), Config.ThPriority == THREAD_PRIORITY_HIGHEST ? ABOVE_NORMAL_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS); - nDisableSC = 1; - - try - { - cpuReset(); - } - catch( Exception::BaseException& ex ) - { - Msgbox::Alert( ex.cMessage() ); - return; - } - - if (OpenPlugins(g_TestRun.ptitle) == -1) - return; - - if( elf_file == NULL ) - { - if(g_RecoveryState != NULL) - { - try - { - memLoadingState( *g_RecoveryState ).FreezeAll(); - } - catch( std::runtime_error& ex ) - { - Msgbox::Alert( - "Gamestate recovery failed. Your game progress will be lost (sorry!)\n" - "\nError: %s\n", params ex.what() ); - - // Take the user back to the GUI... - safe_delete( g_RecoveryState ); - ClosePlugins(); - return; - } - } - else if( g_gsRecoveryState == NULL ) - { - // Not recovering a state, so need to execute the bios and load the ELF information. - // (note: gsRecoveries are done from ExecuteCpu) - - // if the elf_file is null we use the CDVD elf file. - // But if the elf_file is an empty string then we boot the bios instead. - - char ename[g_MaxPath]; - ename[0] = 0; - if( !use_bios ) - GetPS2ElfName( ename ); - - loadElfFile( ename ); - } - } - else - { - // Custom ELF specified (not using CDVD). - // Run the BIOS and load the ELF. - - loadElfFile( elf_file ); - } - - ExecuteCpu(); -} - -class RecoveryMemSavingState : public memSavingState, Sealed -{ -public: - virtual ~RecoveryMemSavingState() { } - RecoveryMemSavingState() : memSavingState( *g_RecoveryState ) - { - } - - void gsFreeze() - { - if( g_gsRecoveryState != NULL ) - { - // just copy the data from src to dst. - // the normal savestate doesn't expect a length prefix for internal structures, - // so don't copy that part. - const u32 pluginlen = *((u32*)g_gsRecoveryState->GetPtr()); - const u32 gslen = *((u32*)g_gsRecoveryState->GetPtr(pluginlen+4)); - memcpy( m_memory.GetPtr(m_idx), g_gsRecoveryState->GetPtr(pluginlen+8), gslen ); - m_idx += gslen; - } - else - memSavingState::gsFreeze(); - } - - void FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) ) - { - if( (freezer == gsSafeFreeze) && (g_gsRecoveryState != NULL) ) - { - // Gs data is already in memory, so just copy from src to dest: - // length of the GS data is stored as the first u32, so use that to run the copy: - const u32 len = *((u32*)g_gsRecoveryState->GetPtr()); - memcpy( m_memory.GetPtr(m_idx), g_gsRecoveryState->GetPtr(), len+4 ); - m_idx += len+4; - } - else - memSavingState::FreezePlugin( name, freezer ); - } -}; - -class RecoveryZipSavingState : public gzSavingState, Sealed -{ -public: - virtual ~RecoveryZipSavingState() { } - RecoveryZipSavingState( const string& filename ) : gzSavingState( filename ) - { - } - - void gsFreeze() - { - if( g_gsRecoveryState != NULL ) - { - // read data from the gsRecoveryState allocation instead of the GS, since the gs - // info was invalidated when the plugin was shut down. - - // the normal savestate doesn't expect a length prefix for internal structures, - // so don't copy that part. - - u32& pluginlen = *((u32*)g_gsRecoveryState->GetPtr(0)); - u32& gslen = *((u32*)g_gsRecoveryState->GetPtr(pluginlen+4)); - gzwrite( m_file, g_gsRecoveryState->GetPtr(pluginlen+4), gslen ); - } - else - gzSavingState::gsFreeze(); - } - - void FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) ) - { - if( (freezer == gsSafeFreeze) && (g_gsRecoveryState != NULL) ) - { - // Gs data is already in memory, so just copy from there into the gzip file. - // length of the GS data is stored as the first u32, so use that to run the copy: - u32& len = *((u32*)g_gsRecoveryState->GetPtr()); - gzwrite( m_file, g_gsRecoveryState->GetPtr(), len+4 ); - } - else - gzSavingState::FreezePlugin( name, freezer ); - } -}; - -void States_Load( const string& file, int num ) -{ - if( !Path::isFile( file ) ) - { - Console::Notice( "Saveslot %d is empty.", params num ); - return; - } - - try - { - char Text[g_MaxPath]; - gzLoadingState joe( file ); // this'll throw an StateLoadError_Recoverable. - - // Make sure the cpu and plugins are ready to be state-ified! - cpuReset(); - OpenPlugins( NULL ); - - joe.FreezeAll(); - - if( num != -1 ) - sprintf (Text, _("*PCSX2*: Loaded State %d"), num); - else - sprintf (Text, _("*PCSX2*: Loaded State %s"), file); - - StatusBar_Notice( Text ); - - if( GSsetGameCRC != NULL ) - GSsetGameCRC(ElfCRC, g_ZeroGSOptions); - } - catch( Exception::StateLoadError_Recoverable& ex) - { - if( num != -1 ) - Console::Notice( "Could not load savestate from slot %d.\n\n%s", params num, ex.cMessage() ); - else - Console::Notice( "Could not load savestate file: %s.\n\n%s", params file, ex.cMessage() ); - - // At this point the cpu hasn't been reset, so we can return - // control to the user safely... (that's why we use a console notice instead of a popup) - - return; - } - catch( Exception::BaseException& ex ) - { - // The emulation state is ruined. Might as well give them a popup and start the gui. - - string message; - - if( num != -1 ) - ssprintf( message, - "Encountered an error while loading savestate from slot %d.\n", num ); - else - ssprintf( message, - "Encountered an error while loading savestate from file: %s.\n", file ); - - if( g_EmulationInProgress ) - message += "Since the savestate load was incomplete, the emulator has been reset.\n"; - - message += "\nError: " + ex.Message(); - - Msgbox::Alert( message.c_str() ); - SysClose(); - return; - } - - // Start emulating! - ExecuteCpu(); -} - -void States_Save( const string& file, int num ) -{ - try - { - string text; - RecoveryZipSavingState( file ).FreezeAll(); - if( num != -1 ) - ssprintf( text, _( "State saved to slot %d" ), num ); - else - ssprintf( text, _( "State saved to file: %s" ), file ); - - StatusBar_Notice( text ); - } - catch( Exception::BaseException& ex ) - { - string message; - - if( num != -1 ) - ssprintf( message, "An error occurred while trying to save to slot %d\n", num ); - else - ssprintf( message, "An error occurred while trying to save to file: %s\n", file ); - - message += "Your emulation state has not been saved!\n\nError: " + ex.Message(); - - Console::Error( message.c_str() ); - } -} - -void States_Load(int num) -{ - States_Load( SaveState::GetFilename( num ), num ); -} - -void States_Save(int num) -{ - if( g_RecoveryState != NULL ) - { - // State is already saved into memory, and the emulator (and in-progress flag) - // have likely been cleared out. So save from the Recovery buffer instead of - // doing a "standard" save: - - string text; - SaveState::GetFilename( text, num ); - gzFile fileptr = gzopen( text.c_str(), "wb" ); - if( fileptr == NULL ) - { - Msgbox::Alert( _("File permissions error while trying to save to slot %d"), params num ); - return; - } - gzwrite( fileptr, &g_SaveVersion, sizeof( u32 ) ); - gzwrite( fileptr, g_RecoveryState->GetPtr(), g_RecoveryState->GetSizeInBytes() ); - gzclose( fileptr ); - return; - } - - if( !g_EmulationInProgress ) - { - Msgbox::Alert( "You need to start a game first before you can save it's state." ); - return; - } - - States_Save( SaveState::GetFilename( num ), num ); -} - -void OnStates_LoadOther() -{ - OPENFILENAME ofn; - char szFileName[g_MaxPath]; - char szFileTitle[g_MaxPath]; - char szFilter[g_MaxPath]; - - memzero_obj( szFileName ); - memzero_obj( szFileTitle ); - - strcpy(szFilter, _("PCSX2 State Format")); - strcatz(szFilter, "*.*;*.*"); - - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = gApp.hWnd; - ofn.lpstrFilter = szFilter; - ofn.lpstrCustomFilter = NULL; - ofn.nMaxCustFilter = 0; - ofn.nFilterIndex = 1; - ofn.lpstrFile = szFileName; - ofn.nMaxFile = g_MaxPath; - ofn.lpstrInitialDir = NULL; - ofn.lpstrFileTitle = szFileTitle; - ofn.nMaxFileTitle = g_MaxPath; - ofn.lpstrTitle = NULL; - ofn.lpstrDefExt = "EXE"; - ofn.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_EXPLORER; - - if (GetOpenFileName ((LPOPENFILENAME)&ofn)) - States_Load( szFileName ); -} - -void OnStates_SaveOther() -{ - OPENFILENAME ofn; - char szFileName[g_MaxPath]; - char szFileTitle[g_MaxPath]; - char szFilter[g_MaxPath]; - - memzero_obj( szFileName ); - memzero_obj( szFileTitle ); - - strcpy(szFilter, _("PCSX2 State Format")); - strcatz(szFilter, "*.*;*.*"); - - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = gApp.hWnd; - ofn.lpstrFilter = szFilter; - ofn.lpstrCustomFilter = NULL; - ofn.nMaxCustFilter = 0; - ofn.nFilterIndex = 1; - ofn.lpstrFile = szFileName; - ofn.nMaxFile = g_MaxPath; - ofn.lpstrInitialDir = NULL; - ofn.lpstrFileTitle = szFileTitle; - ofn.nMaxFileTitle = g_MaxPath; - ofn.lpstrTitle = NULL; - ofn.lpstrDefExt = "EXE"; - ofn.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_EXPLORER; - - if (GetOpenFileName ((LPOPENFILENAME)&ofn)) - States_Save( szFileName ); -} - -class JustGsSavingState : public memSavingState, Sealed -{ -public: - virtual ~JustGsSavingState() { } - JustGsSavingState() : memSavingState( *g_gsRecoveryState ) - { - } - - // This special override saves the gs info to m_idx+4, and then goes back and - // writes in the length of data saved. - void gsFreeze() - { - int oldmidx = m_idx; - m_idx += 4; - memSavingState::gsFreeze(); - if( IsSaving() ) - { - s32& len = *((s32*)m_memory.GetPtr( oldmidx )); - len = (m_idx - oldmidx)-4; - } - } -}; - -static int shiftkey = 0; -static void __fastcall KeyEvent(keyEvent* ev) -{ - if (ev == NULL) return; - if (ev->evt == KEYRELEASE) { - switch (ev->key) { - case VK_SHIFT: shiftkey = 0; break; - } - GSkeyEvent(ev); return; - } - if (ev->evt != KEYPRESS) - return; - - //some pad plugins don't give a key released event for shift, so this is needed - //shiftkey = GetKeyState(VK_SHIFT)&0x8000; - //Well SSXPad breaks with your code, thats why my code worked and your makes reg dumping impossible - //So i suggest you fix the plugins that dont. - - switch (ev->key) { - case VK_SHIFT: shiftkey = 1; break; - - case VK_F1: case VK_F2: case VK_F3: case VK_F4: - case VK_F5: case VK_F6: case VK_F7: case VK_F8: - case VK_F9: case VK_F10: case VK_F11: case VK_F12: - try - { - ProcessFKeys(ev->key-VK_F1 + 1, shiftkey); - } - catch( Exception::CpuStateShutdown& ) - { - // Woops! Something was unrecoverable. Bummer. - // Let's give the user a RunGui! - - g_EmulationInProgress = false; - g_ReturnToGui = true; - } - break; - - case VK_ESCAPE: -#ifdef PCSX2_DEVBUILD - if( g_SaveGSStream >= 3 ) { - // gs state - g_SaveGSStream = 4; - break; - } -#endif - - g_ReturnToGui = true; - if( CHECK_ESCAPE_HACK ) - { - //PostMessage(GetForegroundWindow(), WM_CLOSE, 0, 0); - DestroyWindow( gApp.hWnd ); - } - else - { - if( !UseGui ) { - // not using GUI and user just quit, so exit - WinClose(); - } - - if( Config.closeGSonEsc ) - { - safe_delete( g_gsRecoveryState ); - safe_delete( g_RecoveryState ); - g_gsRecoveryState = new MemoryAlloc(); - JustGsSavingState eddie; - eddie.FreezePlugin( "GS", gsSafeFreeze ) ; - eddie.gsFreeze(); - PluginsResetGS(); - } - - ClosePlugins(); - nDisableSC = 0; - } - break; - - default: - GSkeyEvent(ev); - break; - } -} - -static bool sinit=false; - - -void SysRestorableReset() -{ - // already reset? and saved? - if( !g_EmulationInProgress ) return; - if( g_RecoveryState != NULL ) return; - - try - { - g_RecoveryState = new MemoryAlloc( "Memory Savestate Recovery" ); - RecoveryMemSavingState().FreezeAll(); - safe_delete( g_gsRecoveryState ); - g_EmulationInProgress = false; - } - catch( Exception::RuntimeError& ex ) - { - Msgbox::Alert( - "Pcsx2 gamestate recovery failed. Some options may have been reverted to protect your game's state.\n" - "Error: %s", params ex.cMessage() ); - safe_delete( g_RecoveryState ); - } -} - -void SysReset() -{ - if (!sinit) return; - - // fixme - this code sets the statusbar but never returns control to the window message pump - // so the status bar won't receive the WM_PAINT messages needed to update itself anyway. - // Oops! (air) - - StatusBar_Notice(_("Resetting...")); - Console::SetTitle(_("Resetting...")); - - g_EmulationInProgress = false; - safe_delete( g_RecoveryState ); - safe_delete( g_gsRecoveryState ); - ResetPlugins(); - - ElfCRC = 0; - - // Note : No need to call cpuReset() here. It gets called automatically before the - // emulator resumes execution. - - StatusBar_Notice(_("Ready")); - Console::SetTitle(_("*PCSX2* Emulation state is reset.")); -} - -bool SysInit() -{ - if( sinit ) return true; - sinit = true; - - CreateDirectory(MEMCARDS_DIR, NULL); - CreateDirectory(SSTATES_DIR, NULL); - - // Set the compression attribute on the Memcards folder. - // Memcards generally compress very well via NTFS compression. - - NTFS_CompressFile( MEMCARDS_DIR ); - - if( IsDevBuild && emuLog == NULL && g_TestRun.plogname != NULL ) - emuLog = fopen(g_TestRun.plogname, "w"); - - if( emuLog == NULL ) - emuLog = fopen(LOGS_DIR "\\emuLog.txt","w"); - - PCSX2_MEM_PROTECT_BEGIN(); - SysDetect(); - if( !SysAllocateMem() ) - return false; // critical memory allocation failure; - - SysAllocateDynarecs(); - PCSX2_MEM_PROTECT_END(); - - return true; -} - -// completely shuts down the emulator's cpu state, and unloads all plugins from memory. -void SysClose() { - if (!sinit) return; - cpuShutdown(); - ClosePlugins(); - ReleasePlugins(); - sinit=false; -} - - -static const char *err = N_("Error Loading Symbol"); -static int errval; - -void *SysLoadLibrary(const char *lib) { - return LoadLibrary(lib); -} - -void *SysLoadSym(void *lib, const char *sym) { - void *tmp = GetProcAddress((HINSTANCE)lib, sym); - if (tmp == NULL) errval = GetLastError(); - else errval = 0; - return tmp; -} - -const char *SysLibError() { - if( errval ) - { - static char perr[4096]; - - FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,NULL,GetLastError(),NULL,perr,4095,NULL); - - errval = 0; - return _(perr); - } - return NULL; -} - -void SysCloseLibrary(void *lib) { - FreeLibrary((HINSTANCE)lib); -} - -void *SysMmap(uptr base, u32 size) { - void *mem; - - mem = VirtualAlloc((void*)base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); - return mem; -} - -void SysMunmap(uptr base, u32 size) -{ - if( base == NULL ) return; - VirtualFree((void*)base, size, MEM_DECOMMIT); - VirtualFree((void*)base, 0, MEM_RELEASE); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" +#include "win32.h" + +#include +#include + +#include "Common.h" +//#include "PsxCommon.h" +#include "VUmicro.h" + +#include "iR5900.h" + +int UseGui = 1; +int nDisableSC = 0; // screensaver + +MemoryAlloc* g_RecoveryState = NULL; +MemoryAlloc* g_gsRecoveryState = NULL; + + +bool g_ReturnToGui = false; // set to exit the execution of the emulator and return control to the GUI +bool g_EmulationInProgress = false; // Set TRUE if a game is actively running (set to false on reset) + +// This instance is not modified by command line overrides so +// that command line plugins and stuff won't be saved into the +// user's conf file accidentally. +PcsxConfig winConfig; // local storage of the configuration options. + +HWND hStatusWnd = NULL; +AppData gApp; + +const char* g_pRunGSState = NULL; + + +#define CmdSwitchIs( text ) ( stricmp( command, text ) == 0 ) + +// For issuing notices to both the status bar and the console at the same time. +// Single-line text only please! Mutli-line msgs should be directed to the +// console directly, thanks. +void StatusBar_Notice( const std::string& text ) +{ + // mirror output to the console! + Console::Status( text.c_str() ); + + // don't try this in GCC folks! + SendMessage(hStatusWnd, SB_SETTEXT, 0, (LPARAM)text.c_str() ); +} + +// Sets the status bar message without mirroring the output to the console. +void StatusBar_SetMsg( const std::string& text ) +{ + // don't try this in GCC folks! + SendMessage(hStatusWnd, SB_SETTEXT, 0, (LPARAM)text.c_str() ); +} + +// returns 1 if the user requested help (show help and exit) +// returns zero on success. +// returns -1 on failure (bad command line argument) +int ParseCommandLine( int tokenCount, TCHAR *const *const tokens ) +{ + int tidx = 0; + g_TestRun.efile = 0; + + while( tidx < tokenCount ) + { + const TCHAR* command = tokens[tidx++]; + + if( command[0] != '-' ) + { + g_TestRun.ptitle = command; + printf("opening file %s\n", command); + continue; + } + + // jump past the '-' switch char, and skip if this is a dud switch: + command++; + if( command[0] == 0 ) continue; + + if( CmdSwitchIs( "help" ) ) + { + return -1; + } + else if( CmdSwitchIs( "nogui" ) ) { + UseGui = 0; + } +#ifdef PCSX2_DEVBUILD + else if( CmdSwitchIs( "jpg" ) ) { + g_TestRun.jpgcapture = 1; + } +#endif + else + { + const TCHAR* param; + if( tidx >= tokenCount ) break; + + // None of the parameter-less toggles flagged. + // Check for switches that require one or more parameters here: + + param = tokens[tidx++]; + + if( CmdSwitchIs( "cfg" ) ) { + g_CustomConfigFile = param; + } + + else if( CmdSwitchIs( "efile" ) ) { + g_TestRun.efile = !!atoi( param ); + } + else if( CmdSwitchIs( "loadgs" ) ) { + g_pRunGSState = param; + } + + // Options to configure plugins: + + else if( CmdSwitchIs( "gs" ) ) { + g_TestRun.pgsdll = param; + } + else if( CmdSwitchIs( "cdvd" ) ) { + g_TestRun.pcdvddll = param; + } + else if( CmdSwitchIs( "spu" ) ) { + g_TestRun.pspudll = param; + } + +#ifdef PCSX2_DEVBUILD + else if( CmdSwitchIs( "image" ) ) { + g_TestRun.pimagename = param; + } + else if( CmdSwitchIs( "log" ) ) { + g_TestRun.plogname = param; + } + else if( CmdSwitchIs( "logopt" ) ) { + if( param[0] == '0' && param[1] == 'x' ) param += 2; + sscanf(param, "%x", &varLog); + } + else if( CmdSwitchIs( "frame" ) ) { + g_TestRun.frame = atoi( param ); + } + else if( CmdSwitchIs( "numimages" ) ) { + g_TestRun.numimages = atoi( param ); + } +#endif + } + } + return 0; +} + +void SysPrintf(const char *fmt, ...) +{ + va_list list; + char msg[512]; + + va_start(list,fmt); + vsprintf_s(msg,fmt,list); + msg[511] = '\0'; + va_end(list); + + Console::Write( msg ); +} + +static void __fastcall KeyEvent(keyEvent* ev); + +__forceinline void SysUpdate() { + + keyEvent* ev1 = PAD1keyEvent(); + keyEvent* ev2 = PAD2keyEvent(); + + KeyEvent( (ev1 != NULL) ? ev1 : ev2); +} + +static void TryRecoverFromGsState() +{ + if( g_gsRecoveryState != NULL ) + { + s32 dummylen; + + memLoadingState eddie( *g_gsRecoveryState ); + eddie.FreezePlugin( "GS", gsSafeFreeze ); + eddie.Freeze( dummylen ); // reads the length value recorded earlier. + eddie.gsFreeze(); + } +} + +void ExecuteCpu() +{ + // Make sure any left-over recovery states are cleaned up. + safe_delete( g_RecoveryState ); + + // Just in case they weren't initialized earlier (no harm in calling this multiple times) + if (OpenPlugins(NULL) == -1) return; + + // this needs to be called for every new game! + // (note: sometimes launching games through bios will give a crc of 0) + + if( GSsetGameCRC != NULL ) + GSsetGameCRC(ElfCRC, g_ZeroGSOptions); + + TryRecoverFromGsState(); + + safe_delete( g_gsRecoveryState ); + + // ... and hide the window. Ugly thing. + + ShowWindow( gApp.hWnd, SW_HIDE ); + + g_EmulationInProgress = true; + g_ReturnToGui = false; + + // Optimization: We hardcode two versions of the EE here -- one for recs and one for ints. + // This is because recs are performance critical, and being able to inline them into the + // function here helps a small bit (not much but every small bit counts!). + + timeBeginPeriod( 1 ); + + if( CHECK_EEREC ) + { + while( !g_ReturnToGui ) + { + recExecute(); + SysUpdate(); + } + } + else + { + while( !g_ReturnToGui ) + { + Cpu->Execute(); + SysUpdate(); + } + } + + timeEndPeriod( 1 ); + + ShowWindow( gApp.hWnd, SW_SHOW ); + SetForegroundWindow( gApp.hWnd ); +} + +// Runs and ELF image directly (ISO or ELF program or BIN) +// Used by Run::FromCD and such +void RunExecute( const char* elf_file, bool use_bios ) +{ + SetThreadPriority(GetCurrentThread(), Config.ThPriority); + SetPriorityClass(GetCurrentProcess(), Config.ThPriority == THREAD_PRIORITY_HIGHEST ? ABOVE_NORMAL_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS); + nDisableSC = 1; + + try + { + cpuReset(); + } + catch( Exception::BaseException& ex ) + { + Msgbox::Alert( ex.cMessage() ); + return; + } + + if (OpenPlugins(g_TestRun.ptitle) == -1) + return; + + if( elf_file == NULL ) + { + if(g_RecoveryState != NULL) + { + try + { + memLoadingState( *g_RecoveryState ).FreezeAll(); + } + catch( std::runtime_error& ex ) + { + Msgbox::Alert( + "Gamestate recovery failed. Your game progress will be lost (sorry!)\n" + "\nError: %s\n", params ex.what() ); + + // Take the user back to the GUI... + safe_delete( g_RecoveryState ); + ClosePlugins(); + return; + } + } + else if( g_gsRecoveryState == NULL ) + { + // Not recovering a state, so need to execute the bios and load the ELF information. + // (note: gsRecoveries are done from ExecuteCpu) + + // if the elf_file is null we use the CDVD elf file. + // But if the elf_file is an empty string then we boot the bios instead. + + char ename[g_MaxPath]; + ename[0] = 0; + if( !use_bios ) + GetPS2ElfName( ename ); + + loadElfFile( ename ); + } + } + else + { + // Custom ELF specified (not using CDVD). + // Run the BIOS and load the ELF. + + loadElfFile( elf_file ); + } + + ExecuteCpu(); +} + +class RecoveryMemSavingState : public memSavingState, Sealed +{ +public: + virtual ~RecoveryMemSavingState() { } + RecoveryMemSavingState() : memSavingState( *g_RecoveryState ) + { + } + + void gsFreeze() + { + if( g_gsRecoveryState != NULL ) + { + // just copy the data from src to dst. + // the normal savestate doesn't expect a length prefix for internal structures, + // so don't copy that part. + const u32 pluginlen = *((u32*)g_gsRecoveryState->GetPtr()); + const u32 gslen = *((u32*)g_gsRecoveryState->GetPtr(pluginlen+4)); + memcpy( m_memory.GetPtr(m_idx), g_gsRecoveryState->GetPtr(pluginlen+8), gslen ); + m_idx += gslen; + } + else + memSavingState::gsFreeze(); + } + + void FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) ) + { + if( (freezer == gsSafeFreeze) && (g_gsRecoveryState != NULL) ) + { + // Gs data is already in memory, so just copy from src to dest: + // length of the GS data is stored as the first u32, so use that to run the copy: + const u32 len = *((u32*)g_gsRecoveryState->GetPtr()); + memcpy( m_memory.GetPtr(m_idx), g_gsRecoveryState->GetPtr(), len+4 ); + m_idx += len+4; + } + else + memSavingState::FreezePlugin( name, freezer ); + } +}; + +class RecoveryZipSavingState : public gzSavingState, Sealed +{ +public: + virtual ~RecoveryZipSavingState() { } + RecoveryZipSavingState( const string& filename ) : gzSavingState( filename ) + { + } + + void gsFreeze() + { + if( g_gsRecoveryState != NULL ) + { + // read data from the gsRecoveryState allocation instead of the GS, since the gs + // info was invalidated when the plugin was shut down. + + // the normal savestate doesn't expect a length prefix for internal structures, + // so don't copy that part. + + u32& pluginlen = *((u32*)g_gsRecoveryState->GetPtr(0)); + u32& gslen = *((u32*)g_gsRecoveryState->GetPtr(pluginlen+4)); + gzwrite( m_file, g_gsRecoveryState->GetPtr(pluginlen+4), gslen ); + } + else + gzSavingState::gsFreeze(); + } + + void FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) ) + { + if( (freezer == gsSafeFreeze) && (g_gsRecoveryState != NULL) ) + { + // Gs data is already in memory, so just copy from there into the gzip file. + // length of the GS data is stored as the first u32, so use that to run the copy: + u32& len = *((u32*)g_gsRecoveryState->GetPtr()); + gzwrite( m_file, g_gsRecoveryState->GetPtr(), len+4 ); + } + else + gzSavingState::FreezePlugin( name, freezer ); + } +}; + +void States_Load( const string& file, int num ) +{ + if( !Path::isFile( file ) ) + { + Console::Notice( "Saveslot %d is empty.", params num ); + return; + } + + try + { + char Text[g_MaxPath]; + gzLoadingState joe( file ); // this'll throw an StateLoadError_Recoverable. + + // Make sure the cpu and plugins are ready to be state-ified! + cpuReset(); + OpenPlugins( NULL ); + + joe.FreezeAll(); + + if( num != -1 ) + sprintf (Text, _("*PCSX2*: Loaded State %d"), num); + else + sprintf (Text, _("*PCSX2*: Loaded State %s"), file); + + StatusBar_Notice( Text ); + + if( GSsetGameCRC != NULL ) + GSsetGameCRC(ElfCRC, g_ZeroGSOptions); + } + catch( Exception::StateLoadError_Recoverable& ex) + { + if( num != -1 ) + Console::Notice( "Could not load savestate from slot %d.\n\n%s", params num, ex.cMessage() ); + else + Console::Notice( "Could not load savestate file: %s.\n\n%s", params file, ex.cMessage() ); + + // At this point the cpu hasn't been reset, so we can return + // control to the user safely... (that's why we use a console notice instead of a popup) + + return; + } + catch( Exception::BaseException& ex ) + { + // The emulation state is ruined. Might as well give them a popup and start the gui. + + string message; + + if( num != -1 ) + ssprintf( message, + "Encountered an error while loading savestate from slot %d.\n", num ); + else + ssprintf( message, + "Encountered an error while loading savestate from file: %s.\n", file ); + + if( g_EmulationInProgress ) + message += "Since the savestate load was incomplete, the emulator has been reset.\n"; + + message += "\nError: " + ex.Message(); + + Msgbox::Alert( message.c_str() ); + SysClose(); + return; + } + + // Start emulating! + ExecuteCpu(); +} + +void States_Save( const string& file, int num ) +{ + try + { + string text; + RecoveryZipSavingState( file ).FreezeAll(); + if( num != -1 ) + ssprintf( text, _( "State saved to slot %d" ), num ); + else + ssprintf( text, _( "State saved to file: %s" ), file ); + + StatusBar_Notice( text ); + } + catch( Exception::BaseException& ex ) + { + string message; + + if( num != -1 ) + ssprintf( message, "An error occurred while trying to save to slot %d\n", num ); + else + ssprintf( message, "An error occurred while trying to save to file: %s\n", file ); + + message += "Your emulation state has not been saved!\n\nError: " + ex.Message(); + + Console::Error( message.c_str() ); + } +} + +void States_Load(int num) +{ + States_Load( SaveState::GetFilename( num ), num ); +} + +void States_Save(int num) +{ + if( g_RecoveryState != NULL ) + { + // State is already saved into memory, and the emulator (and in-progress flag) + // have likely been cleared out. So save from the Recovery buffer instead of + // doing a "standard" save: + + string text; + SaveState::GetFilename( text, num ); + gzFile fileptr = gzopen( text.c_str(), "wb" ); + if( fileptr == NULL ) + { + Msgbox::Alert( _("File permissions error while trying to save to slot %d"), params num ); + return; + } + gzwrite( fileptr, &g_SaveVersion, sizeof( u32 ) ); + gzwrite( fileptr, g_RecoveryState->GetPtr(), g_RecoveryState->GetSizeInBytes() ); + gzclose( fileptr ); + return; + } + + if( !g_EmulationInProgress ) + { + Msgbox::Alert( "You need to start a game first before you can save it's state." ); + return; + } + + States_Save( SaveState::GetFilename( num ), num ); +} + +void OnStates_LoadOther() +{ + OPENFILENAME ofn; + char szFileName[g_MaxPath]; + char szFileTitle[g_MaxPath]; + char szFilter[g_MaxPath]; + + memzero_obj( szFileName ); + memzero_obj( szFileTitle ); + + strcpy(szFilter, _("PCSX2 State Format")); + strcatz(szFilter, "*.*;*.*"); + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = gApp.hWnd; + ofn.lpstrFilter = szFilter; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 1; + ofn.lpstrFile = szFileName; + ofn.nMaxFile = g_MaxPath; + ofn.lpstrInitialDir = NULL; + ofn.lpstrFileTitle = szFileTitle; + ofn.nMaxFileTitle = g_MaxPath; + ofn.lpstrTitle = NULL; + ofn.lpstrDefExt = "EXE"; + ofn.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_EXPLORER; + + if (GetOpenFileName ((LPOPENFILENAME)&ofn)) + States_Load( szFileName ); +} + +void OnStates_SaveOther() +{ + OPENFILENAME ofn; + char szFileName[g_MaxPath]; + char szFileTitle[g_MaxPath]; + char szFilter[g_MaxPath]; + + memzero_obj( szFileName ); + memzero_obj( szFileTitle ); + + strcpy(szFilter, _("PCSX2 State Format")); + strcatz(szFilter, "*.*;*.*"); + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = gApp.hWnd; + ofn.lpstrFilter = szFilter; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 1; + ofn.lpstrFile = szFileName; + ofn.nMaxFile = g_MaxPath; + ofn.lpstrInitialDir = NULL; + ofn.lpstrFileTitle = szFileTitle; + ofn.nMaxFileTitle = g_MaxPath; + ofn.lpstrTitle = NULL; + ofn.lpstrDefExt = "EXE"; + ofn.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_EXPLORER; + + if (GetOpenFileName ((LPOPENFILENAME)&ofn)) + States_Save( szFileName ); +} + +class JustGsSavingState : public memSavingState, Sealed +{ +public: + virtual ~JustGsSavingState() { } + JustGsSavingState() : memSavingState( *g_gsRecoveryState ) + { + } + + // This special override saves the gs info to m_idx+4, and then goes back and + // writes in the length of data saved. + void gsFreeze() + { + int oldmidx = m_idx; + m_idx += 4; + memSavingState::gsFreeze(); + if( IsSaving() ) + { + s32& len = *((s32*)m_memory.GetPtr( oldmidx )); + len = (m_idx - oldmidx)-4; + } + } +}; + +static int shiftkey = 0; +static void __fastcall KeyEvent(keyEvent* ev) +{ + if (ev == NULL) return; + if (ev->evt == KEYRELEASE) { + switch (ev->key) { + case VK_SHIFT: shiftkey = 0; break; + } + GSkeyEvent(ev); return; + } + if (ev->evt != KEYPRESS) + return; + + //some pad plugins don't give a key released event for shift, so this is needed + //shiftkey = GetKeyState(VK_SHIFT)&0x8000; + //Well SSXPad breaks with your code, thats why my code worked and your makes reg dumping impossible + //So i suggest you fix the plugins that dont. + + switch (ev->key) { + case VK_SHIFT: shiftkey = 1; break; + + case VK_F1: case VK_F2: case VK_F3: case VK_F4: + case VK_F5: case VK_F6: case VK_F7: case VK_F8: + case VK_F9: case VK_F10: case VK_F11: case VK_F12: + try + { + ProcessFKeys(ev->key-VK_F1 + 1, shiftkey); + } + catch( Exception::CpuStateShutdown& ) + { + // Woops! Something was unrecoverable. Bummer. + // Let's give the user a RunGui! + + g_EmulationInProgress = false; + g_ReturnToGui = true; + } + break; + + case VK_ESCAPE: +#ifdef PCSX2_DEVBUILD + if( g_SaveGSStream >= 3 ) { + // gs state + g_SaveGSStream = 4; + break; + } +#endif + + g_ReturnToGui = true; + if( CHECK_ESCAPE_HACK ) + { + //PostMessage(GetForegroundWindow(), WM_CLOSE, 0, 0); + DestroyWindow( gApp.hWnd ); + } + else + { + if( !UseGui ) { + // not using GUI and user just quit, so exit + WinClose(); + } + + if( Config.closeGSonEsc ) + { + safe_delete( g_gsRecoveryState ); + safe_delete( g_RecoveryState ); + g_gsRecoveryState = new MemoryAlloc(); + JustGsSavingState eddie; + eddie.FreezePlugin( "GS", gsSafeFreeze ) ; + eddie.gsFreeze(); + PluginsResetGS(); + } + + ClosePlugins(); + nDisableSC = 0; + } + break; + + default: + GSkeyEvent(ev); + break; + } +} + +static bool sinit=false; + + +void SysRestorableReset() +{ + // already reset? and saved? + if( !g_EmulationInProgress ) return; + if( g_RecoveryState != NULL ) return; + + try + { + g_RecoveryState = new MemoryAlloc( "Memory Savestate Recovery" ); + RecoveryMemSavingState().FreezeAll(); + safe_delete( g_gsRecoveryState ); + g_EmulationInProgress = false; + } + catch( Exception::RuntimeError& ex ) + { + Msgbox::Alert( + "Pcsx2 gamestate recovery failed. Some options may have been reverted to protect your game's state.\n" + "Error: %s", params ex.cMessage() ); + safe_delete( g_RecoveryState ); + } +} + +void SysReset() +{ + if (!sinit) return; + + // fixme - this code sets the statusbar but never returns control to the window message pump + // so the status bar won't receive the WM_PAINT messages needed to update itself anyway. + // Oops! (air) + + StatusBar_Notice(_("Resetting...")); + Console::SetTitle(_("Resetting...")); + + g_EmulationInProgress = false; + safe_delete( g_RecoveryState ); + safe_delete( g_gsRecoveryState ); + ResetPlugins(); + + ElfCRC = 0; + + // Note : No need to call cpuReset() here. It gets called automatically before the + // emulator resumes execution. + + StatusBar_Notice(_("Ready")); + Console::SetTitle(_("*PCSX2* Emulation state is reset.")); +} + +bool SysInit() +{ + if( sinit ) return true; + sinit = true; + + CreateDirectory(MEMCARDS_DIR, NULL); + CreateDirectory(SSTATES_DIR, NULL); + + // Set the compression attribute on the Memcards folder. + // Memcards generally compress very well via NTFS compression. + + NTFS_CompressFile( MEMCARDS_DIR ); + + if( IsDevBuild && emuLog == NULL && g_TestRun.plogname != NULL ) + emuLog = fopen(g_TestRun.plogname, "w"); + + if( emuLog == NULL ) + emuLog = fopen(LOGS_DIR "\\emuLog.txt","w"); + + PCSX2_MEM_PROTECT_BEGIN(); + SysDetect(); + if( !SysAllocateMem() ) + return false; // critical memory allocation failure; + + SysAllocateDynarecs(); + PCSX2_MEM_PROTECT_END(); + + return true; +} + +// completely shuts down the emulator's cpu state, and unloads all plugins from memory. +void SysClose() { + if (!sinit) return; + cpuShutdown(); + ClosePlugins(); + ReleasePlugins(); + sinit=false; +} + + +static const char *err = N_("Error Loading Symbol"); +static int errval; + +void *SysLoadLibrary(const char *lib) { + return LoadLibrary(lib); +} + +void *SysLoadSym(void *lib, const char *sym) { + void *tmp = GetProcAddress((HINSTANCE)lib, sym); + if (tmp == NULL) errval = GetLastError(); + else errval = 0; + return tmp; +} + +const char *SysLibError() { + if( errval ) + { + static char perr[4096]; + + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,NULL,GetLastError(),NULL,perr,4095,NULL); + + errval = 0; + return _(perr); + } + return NULL; +} + +void SysCloseLibrary(void *lib) { + FreeLibrary((HINSTANCE)lib); +} + +void *SysMmap(uptr base, u32 size) { + void *mem; + + mem = VirtualAlloc((void*)base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + return mem; +} + +void SysMunmap(uptr base, u32 size) +{ + if( base == NULL ) return; + VirtualFree((void*)base, size, MEM_DECOMMIT); + VirtualFree((void*)base, 0, MEM_RELEASE); +} diff --git a/pcsx2/windows/WinThreads.cpp b/pcsx2/windows/WinThreads.cpp index a47d3c3d25..94ff95796c 100644 --- a/pcsx2/windows/WinThreads.cpp +++ b/pcsx2/windows/WinThreads.cpp @@ -1,152 +1,152 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "System.h" -#include "Threading.h" -#include "ix86/ix86.h" - -#ifdef _WIN32 -#include "implement.h" // win32 pthreads implementations. -#endif - -namespace Threading -{ - void CountLogicalCores( int LogicalCoresPerPhysicalCPU, int PhysicalCoresPerPhysicalCPU ) - { - DWORD vProcessCPUs; - DWORD vSystemCPUs; - - cpuinfo.LogicalCores = 1; - - if( !GetProcessAffinityMask (GetCurrentProcess (), - &vProcessCPUs, &vSystemCPUs) ) return; - - int CPUs = 0; - DWORD bit; - - for (bit = 1; bit != 0; bit <<= 1) - { - if (vSystemCPUs & bit) - CPUs++; - } - - cpuinfo.LogicalCores = CPUs; - if( LogicalCoresPerPhysicalCPU > CPUs) // for 1-socket HTT-disabled machines - LogicalCoresPerPhysicalCPU = CPUs; - - cpuinfo.PhysicalCores = ( CPUs / LogicalCoresPerPhysicalCPU ) * PhysicalCoresPerPhysicalCPU; - ptw32_smp_system = ( cpuinfo.LogicalCores > 1 ) ? TRUE : FALSE; - } - - __forceinline void Timeslice() - { - Sleep(0); - } - - // For use in spin/wait loops, Acts as a hint to Intel CPUs and should, in theory - // improve performance and reduce cpu power consumption. - __forceinline void SpinWait() - { - __asm { pause }; - } - - void* Thread::_internal_callback( void* itsme ) - { - jASSUME( itsme != NULL ); - - Thread& owner = *((Thread*)itsme); - pthread_win32_thread_attach_np(); - - try - { - owner.m_returncode = owner.Callback(); - } - catch( std::exception& ex ) - { - Console::Error( "Thread terminated abnormally with error:\n\t%s", params ex.what() ); - owner.m_returncode = -1; - } - - owner.m_terminated = true; - pthread_win32_thread_detach_np(); - - return NULL; - } - - // Note: assuming multicore is safer because it forces the interlocked routines to use - // the LOCK prefix. The prefix works on single core CPUs fine (but is slow), but not - // having the LOCK prefix is very bad indeed. - - ////////////////////////////////////////////////////////////////////// - // Win32 versions of InterlockedExchange. - // These are much faster than the Win32 Kernel versions thanks to inlining. - - __forceinline long pcsx2_InterlockedExchange( volatile long* target, long srcval ) - { - // Use the pthreads-win32 implementation... - return ptw32_InterlockedExchange( target, srcval ); - } - - __forceinline long pcsx2_InterlockedCompareExchange( volatile long* target, long srcval, long comp ) - { - // Use the pthreads-win32 implementation... - return ptw32_InterlockedCompareExchange( target, srcval, comp ); - } - - __forceinline long pcsx2_InterlockedExchangeAdd( volatile long* target, long srcval ) - { - long result; - - // Use our own implementation... - // Pcsx2 won't use threads unless it's a multicore cpu, so no need to use - // the optimized single-core method. - - if( true ) //ptw32_smp_system ) - { - __asm - { - //PUSH ecx - mov ecx,dword ptr [target] - mov eax,dword ptr [srcval] - lock xadd dword ptr [ecx],eax - mov dword ptr [result], eax - //POP ecx - } - } - else - { - __asm - { - //PUSH ecx - //PUSH edx - mov ecx,dword ptr [target] - //L1: - mov eax,dword ptr [srcval] - xadd dword ptr [ecx],eax - //jnz L1 - mov dword ptr [result], eax - //POP edx - //POP ecx - } - } - return result; - } -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "System.h" +#include "Threading.h" +#include "ix86/ix86.h" + +#ifdef _WIN32 +#include "implement.h" // win32 pthreads implementations. +#endif + +namespace Threading +{ + void CountLogicalCores( int LogicalCoresPerPhysicalCPU, int PhysicalCoresPerPhysicalCPU ) + { + DWORD vProcessCPUs; + DWORD vSystemCPUs; + + cpuinfo.LogicalCores = 1; + + if( !GetProcessAffinityMask (GetCurrentProcess (), + &vProcessCPUs, &vSystemCPUs) ) return; + + int CPUs = 0; + DWORD bit; + + for (bit = 1; bit != 0; bit <<= 1) + { + if (vSystemCPUs & bit) + CPUs++; + } + + cpuinfo.LogicalCores = CPUs; + if( LogicalCoresPerPhysicalCPU > CPUs) // for 1-socket HTT-disabled machines + LogicalCoresPerPhysicalCPU = CPUs; + + cpuinfo.PhysicalCores = ( CPUs / LogicalCoresPerPhysicalCPU ) * PhysicalCoresPerPhysicalCPU; + ptw32_smp_system = ( cpuinfo.LogicalCores > 1 ) ? TRUE : FALSE; + } + + __forceinline void Timeslice() + { + Sleep(0); + } + + // For use in spin/wait loops, Acts as a hint to Intel CPUs and should, in theory + // improve performance and reduce cpu power consumption. + __forceinline void SpinWait() + { + __asm { pause }; + } + + void* Thread::_internal_callback( void* itsme ) + { + jASSUME( itsme != NULL ); + + Thread& owner = *((Thread*)itsme); + pthread_win32_thread_attach_np(); + + try + { + owner.m_returncode = owner.Callback(); + } + catch( std::exception& ex ) + { + Console::Error( "Thread terminated abnormally with error:\n\t%s", params ex.what() ); + owner.m_returncode = -1; + } + + owner.m_terminated = true; + pthread_win32_thread_detach_np(); + + return NULL; + } + + // Note: assuming multicore is safer because it forces the interlocked routines to use + // the LOCK prefix. The prefix works on single core CPUs fine (but is slow), but not + // having the LOCK prefix is very bad indeed. + + ////////////////////////////////////////////////////////////////////// + // Win32 versions of InterlockedExchange. + // These are much faster than the Win32 Kernel versions thanks to inlining. + + __forceinline long pcsx2_InterlockedExchange( volatile long* target, long srcval ) + { + // Use the pthreads-win32 implementation... + return ptw32_InterlockedExchange( target, srcval ); + } + + __forceinline long pcsx2_InterlockedCompareExchange( volatile long* target, long srcval, long comp ) + { + // Use the pthreads-win32 implementation... + return ptw32_InterlockedCompareExchange( target, srcval, comp ); + } + + __forceinline long pcsx2_InterlockedExchangeAdd( volatile long* target, long srcval ) + { + long result; + + // Use our own implementation... + // Pcsx2 won't use threads unless it's a multicore cpu, so no need to use + // the optimized single-core method. + + if( true ) //ptw32_smp_system ) + { + __asm + { + //PUSH ecx + mov ecx,dword ptr [target] + mov eax,dword ptr [srcval] + lock xadd dword ptr [ecx],eax + mov dword ptr [result], eax + //POP ecx + } + } + else + { + __asm + { + //PUSH ecx + //PUSH edx + mov ecx,dword ptr [target] + //L1: + mov eax,dword ptr [srcval] + xadd dword ptr [ecx],eax + //jnz L1 + mov dword ptr [result], eax + //POP edx + //POP ecx + } + } + return result; + } +} diff --git a/pcsx2/windows/WinVM.cpp b/pcsx2/windows/WinVM.cpp index b80b02d1a1..af9acd316c 100644 --- a/pcsx2/windows/WinVM.cpp +++ b/pcsx2/windows/WinVM.cpp @@ -1,470 +1,470 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" -#include "win32.h" - - -#ifdef PCSX2_VIRTUAL_MEM - -// virtual memory/privileges -#include "ntsecapi.h" - -static wchar_t s_szUserName[255]; - -LRESULT WINAPI UserNameProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { - switch(uMsg) { - case WM_INITDIALOG: - SetWindowPos(hDlg, HWND_TOPMOST, 200, 100, 0, 0, SWP_NOSIZE); - return TRUE; - - case WM_COMMAND: - switch(wParam) { - case IDOK: - { - wchar_t str[255]; - GetWindowTextW(GetDlgItem(hDlg, IDC_USER_NAME), str, 255); - swprintf(s_szUserName, 255, L"%hs", &str); - EndDialog(hDlg, TRUE ); - return TRUE; - } - - case IDCANCEL: - EndDialog(hDlg, FALSE ); - return TRUE; - } - break; - } - return FALSE; -} - -BOOL InitLsaString( - PLSA_UNICODE_STRING pLsaString, - LPCWSTR pwszString -) -{ - DWORD dwLen = 0; - - if (NULL == pLsaString) - return FALSE; - - if (NULL != pwszString) - { - dwLen = wcslen(pwszString); - if (dwLen > 0x7ffe) // String is too large - return FALSE; - } - - // Store the string. - pLsaString->Buffer = (WCHAR *)pwszString; - pLsaString->Length = (USHORT)dwLen * sizeof(WCHAR); - pLsaString->MaximumLength= (USHORT)(dwLen+1) * sizeof(WCHAR); - - return TRUE; -} - -PLSA_TRANSLATED_SID2 GetSIDInformation (LPWSTR AccountName,LSA_HANDLE PolicyHandle) -{ - LSA_UNICODE_STRING lucName; - PLSA_TRANSLATED_SID2 ltsTranslatedSID; - PLSA_REFERENCED_DOMAIN_LIST lrdlDomainList; - //LSA_TRUST_INFORMATION myDomain; - NTSTATUS ntsResult; - PWCHAR DomainString = NULL; - - // Initialize an LSA_UNICODE_STRING with the name. - if (!InitLsaString(&lucName, AccountName)) - { - wprintf(L"Failed InitLsaString\n"); - return NULL; - } - - ntsResult = LsaLookupNames2( - PolicyHandle, // handle to a Policy object - 0, - 1, // number of names to look up - &lucName, // pointer to an array of names - &lrdlDomainList, // receives domain information - <sTranslatedSID // receives relative SIDs - ); - if (0 != ntsResult) - { - wprintf(L"Failed LsaLookupNames - %lu \n", - LsaNtStatusToWinError(ntsResult)); - return NULL; - } - - // Get the domain the account resides in. -// myDomain = lrdlDomainList->Domains[ltsTranslatedSID->DomainIndex]; -// DomainString = (PWCHAR) LocalAlloc(LPTR, myDomain.Name.Length + 1); -// wcsncpy(DomainString, myDomain.Name.Buffer, myDomain.Name.Length); - - // Display the relative Id. -// wprintf(L"Relative Id is %lu in domain %ws.\n", -// ltsTranslatedSID->RelativeId, -// DomainString); - - LsaFreeMemory(lrdlDomainList); - - return ltsTranslatedSID; -} - -BOOL AddPrivileges(PSID AccountSID, LSA_HANDLE PolicyHandle, BOOL bAdd) -{ - LSA_UNICODE_STRING lucPrivilege; - NTSTATUS ntsResult; - - // Create an LSA_UNICODE_STRING for the privilege name(s). - if (!InitLsaString(&lucPrivilege, L"SeLockMemoryPrivilege")) - { - wprintf(L"Failed InitLsaString\n"); - return FALSE; - } - - if( bAdd ) { - ntsResult = LsaAddAccountRights( - PolicyHandle, // An open policy handle. - AccountSID, // The target SID. - &lucPrivilege, // The privilege(s). - 1 // Number of privileges. - ); - } - else { - ntsResult = LsaRemoveAccountRights( - PolicyHandle, // An open policy handle. - AccountSID, // The target SID - FALSE, - &lucPrivilege, // The privilege(s). - 1 // Number of privileges. - ); - } - - if (ntsResult == 0) - { - wprintf(L"Privilege added.\n"); - } - else - { - int err = LsaNtStatusToWinError(ntsResult); - char str[255]; - _snprintf(str, 255, "Privilege was not added - %lu \n", LsaNtStatusToWinError(ntsResult)); - MessageBox(NULL, str, "Privilege error", MB_OK); - return FALSE; - } - - return TRUE; -} - -#define TARGET_SYSTEM_NAME L"mysystem" -LSA_HANDLE GetPolicyHandle() -{ - LSA_OBJECT_ATTRIBUTES ObjectAttributes; - WCHAR SystemName[] = TARGET_SYSTEM_NAME; - USHORT SystemNameLength; - LSA_UNICODE_STRING lusSystemName; - NTSTATUS ntsResult; - LSA_HANDLE lsahPolicyHandle; - - // Object attributes are reserved, so initialize to zeroes. - ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes)); - - //Initialize an LSA_UNICODE_STRING to the server name. - SystemNameLength = wcslen(SystemName); - lusSystemName.Buffer = SystemName; - lusSystemName.Length = SystemNameLength * sizeof(WCHAR); - lusSystemName.MaximumLength = (SystemNameLength+1) * sizeof(WCHAR); - - // Get a handle to the Policy object. - ntsResult = LsaOpenPolicy( - NULL, //Name of the target system. - &ObjectAttributes, //Object attributes. - POLICY_ALL_ACCESS, //Desired access permissions. - &lsahPolicyHandle //Receives the policy handle. - ); - - if (ntsResult != 0) - { - // An error occurred. Display it as a win32 error code. - wprintf(L"OpenPolicy returned %lu\n", - LsaNtStatusToWinError(ntsResult)); - return NULL; - } - return lsahPolicyHandle; -} - - -/***************************************************************** - LoggedSetLockPagesPrivilege: a function to obtain, if possible, or - release the privilege of locking physical pages. - - Inputs: - - HANDLE hProcess: Handle for the process for which the - privilege is needed - - BOOL bEnable: Enable (TRUE) or disable? - - Return value: TRUE indicates success, FALSE failure. - -*****************************************************************/ -BOOL SysLoggedSetLockPagesPrivilege ( HANDLE hProcess, BOOL bEnable) -{ - struct { - u32 Count; - LUID_AND_ATTRIBUTES Privilege [1]; - } Info; - - HANDLE Token; - BOOL Result; - - // Open the token. - - Result = OpenProcessToken ( hProcess, - TOKEN_ADJUST_PRIVILEGES, - & Token); - - if( Result != TRUE ) { - Console::Error( "VirtualMemory Error > Cannot open process token." ); - return FALSE; - } - - // Enable or disable? - - Info.Count = 1; - if( bEnable ) - { - Info.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED; - } - else - { - Info.Privilege[0].Attributes = SE_PRIVILEGE_REMOVED; - } - - // Get the LUID. - Result = LookupPrivilegeValue ( NULL, - SE_LOCK_MEMORY_NAME, - &(Info.Privilege[0].Luid)); - - if( Result != TRUE ) - { - Console::Error( "VirtualMemory Error > Cannot get privilege value for %s.", params SE_LOCK_MEMORY_NAME ); - return FALSE; - } - - // Adjust the privilege. - - Result = AdjustTokenPrivileges ( Token, FALSE, - (PTOKEN_PRIVILEGES) &Info, - 0, NULL, NULL); - - // Check the result. - if( Result != TRUE ) - { - Console::Error( "VirtualMemory Error > Cannot adjust token privileges, error %u.", params GetLastError() ); - return FALSE; - } - else - { - if( GetLastError() != ERROR_SUCCESS ) - { - - BOOL bSuc = FALSE; - LSA_HANDLE policy; - PLSA_TRANSLATED_SID2 ltsTranslatedSID; - -// if( !DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_USERNAME), gApp.hWnd, (DLGPROC)UserNameProc) ) -// return FALSE; - DWORD len = sizeof(s_szUserName); - GetUserNameW(s_szUserName, &len); - - policy = GetPolicyHandle(); - - if( policy != NULL ) { - - ltsTranslatedSID = GetSIDInformation(s_szUserName, policy); - - if( ltsTranslatedSID != NULL ) { - bSuc = AddPrivileges(ltsTranslatedSID->Sid, policy, bEnable); - LsaFreeMemory(ltsTranslatedSID); - } - - LsaClose(policy); - } - - if( bSuc ) { - // Get the LUID. - LookupPrivilegeValue ( NULL, SE_LOCK_MEMORY_NAME, &(Info.Privilege[0].Luid)); - - bSuc = AdjustTokenPrivileges ( Token, FALSE, (PTOKEN_PRIVILEGES) &Info, 0, NULL, NULL); - } - - if( bSuc ) { - if( MessageBox(NULL, "PCSX2 just changed your SE_LOCK_MEMORY privilege in order to gain access to physical memory.\n" - "Log off/on and run pcsx2 again. Do you want to log off?\n", - "Privilege changed query", MB_YESNO) == IDYES ) { - ExitWindows(EWX_LOGOFF, 0); - } - } - else { - MessageBox(NULL, "Failed adding SE_LOCK_MEMORY privilege, please check the local policy.\n" - "Go to security settings->Local Policies->User Rights. There should be a \"Lock pages in memory\".\n" - "Add your user to that and log off/on. This enables pcsx2 to run at real-time by allocating physical memory.\n" - "Also can try Control Panel->Local Security Policy->... (this does not work on Windows XP Home)\n" - "(zerofrog)\n", "Virtual Memory Access Denied", MB_OK); - return FALSE; - } - } - } - - CloseHandle( Token ); - - return TRUE; -} - -static u32 s_dwPageSize = 0; -int SysPhysicalAlloc(u32 size, PSMEMORYBLOCK* pblock) -{ -//#ifdef WIN32_FILE_MAPPING -// assert(0); -//#endif - ULONG_PTR NumberOfPagesInitial; // initial number of pages requested - int PFNArraySize; // memory to request for PFN array - BOOL bResult; - - assert( pblock != NULL ); - memset(pblock, 0, sizeof(PSMEMORYBLOCK)); - - if( s_dwPageSize == 0 ) { - SYSTEM_INFO sSysInfo; // useful system information - GetSystemInfo(&sSysInfo); // fill the system information structure - s_dwPageSize = sSysInfo.dwPageSize; - - if( s_dwPageSize != 0x1000 ) { - Msgbox::Alert("Error! OS page size must be 4Kb!\n" - "If for some reason the OS cannot have 4Kb pages, then run the TLB build."); - return -1; - } - } - - // Calculate the number of pages of memory to request. - pblock->NumberPages = (size+s_dwPageSize-1)/s_dwPageSize; - PFNArraySize = pblock->NumberPages * sizeof (ULONG_PTR); - - pblock->aPFNs = (uptr*)HeapAlloc (GetProcessHeap (), 0, PFNArraySize); - - if (pblock->aPFNs == NULL) { - Console::Error("Failed to allocate on heap."); - goto eCleanupAndExit; - } - - // Allocate the physical memory. - NumberOfPagesInitial = pblock->NumberPages; - bResult = AllocateUserPhysicalPages( GetCurrentProcess(), (PULONG_PTR)&pblock->NumberPages, (PULONG_PTR)pblock->aPFNs ); - - if( bResult != TRUE ) - { - Console::Error("Virtual Memory Error %u > Cannot allocate physical pages.", params GetLastError() ); - goto eCleanupAndExit; - } - - if( NumberOfPagesInitial != pblock->NumberPages ) - { - Console::Error("Virtual Memory > Physical allocation failed!\n\tAllocated only %p of %p pages.", params pblock->NumberPages, NumberOfPagesInitial ); - goto eCleanupAndExit; - } - - pblock->aVFNs = (uptr*)HeapAlloc(GetProcessHeap(), 0, PFNArraySize); - - return 0; - -eCleanupAndExit: - SysPhysicalFree(pblock); - return -1; -} - -void SysPhysicalFree(PSMEMORYBLOCK* pblock) -{ - assert( pblock != NULL ); - - // Free the physical pages. - FreeUserPhysicalPages( GetCurrentProcess(), (PULONG_PTR)&pblock->NumberPages, (PULONG_PTR)pblock->aPFNs ); - - if( pblock->aPFNs != NULL ) HeapFree(GetProcessHeap(), 0, pblock->aPFNs); - if( pblock->aVFNs != NULL ) HeapFree(GetProcessHeap(), 0, pblock->aVFNs); - memset(pblock, 0, sizeof(PSMEMORYBLOCK)); -} - -int SysVirtualPhyAlloc(void* base, u32 size, PSMEMORYBLOCK* pblock) -{ - BOOL bResult; - int i; - - LPVOID lpMemReserved = VirtualAlloc( base, size, MEM_RESERVE | MEM_PHYSICAL, PAGE_READWRITE ); - if( lpMemReserved == NULL || base != lpMemReserved ) - { - Console::WriteLn("VirtualMemory Error %d > Cannot reserve memory at 0x%8.8x(%x).", params base, lpMemReserved, GetLastError()); - goto eCleanupAndExit; - } - - // Map the physical memory into the window. - bResult = MapUserPhysicalPages( base, (ULONG_PTR)pblock->NumberPages, (PULONG_PTR)pblock->aPFNs ); - - for(i = 0; i < pblock->NumberPages; ++i) - pblock->aVFNs[i] = (uptr)base + 0x1000*i; - - if( bResult != TRUE ) - { - Console::WriteLn("VirtualMemory Error %u > MapUserPhysicalPages failed to map.", params GetLastError() ); - goto eCleanupAndExit; - } - - return 0; - -eCleanupAndExit: - SysVirtualFree(base, size); - return -1; -} - -void SysVirtualFree(void* lpMemReserved, u32 size) -{ - // unmap - if( MapUserPhysicalPages( lpMemReserved, (size+s_dwPageSize-1)/s_dwPageSize, NULL ) != TRUE ) - { - Console::WriteLn("VirtualMemory Error %u > MapUserPhysicalPages failed to unmap", params GetLastError() ); - return; - } - - // Free virtual memory. - VirtualFree( lpMemReserved, 0, MEM_RELEASE ); -} - -int SysMapUserPhysicalPages(void* Addr, uptr NumPages, uptr* pfn, int pageoffset) -{ - BOOL bResult = MapUserPhysicalPages(Addr, NumPages, (PULONG_PTR)(pfn+pageoffset)); - -#ifdef _DEBUG - //if( !bResult ) - //__Log("Failed to map user pages: 0x%x:0x%x, error = %d\n", Addr, NumPages, GetLastError()); -#endif - - return bResult; -} - -#else - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" +#include "win32.h" + + +#ifdef PCSX2_VIRTUAL_MEM + +// virtual memory/privileges +#include "ntsecapi.h" + +static wchar_t s_szUserName[255]; + +LRESULT WINAPI UserNameProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + SetWindowPos(hDlg, HWND_TOPMOST, 200, 100, 0, 0, SWP_NOSIZE); + return TRUE; + + case WM_COMMAND: + switch(wParam) { + case IDOK: + { + wchar_t str[255]; + GetWindowTextW(GetDlgItem(hDlg, IDC_USER_NAME), str, 255); + swprintf(s_szUserName, 255, L"%hs", &str); + EndDialog(hDlg, TRUE ); + return TRUE; + } + + case IDCANCEL: + EndDialog(hDlg, FALSE ); + return TRUE; + } + break; + } + return FALSE; +} + +BOOL InitLsaString( + PLSA_UNICODE_STRING pLsaString, + LPCWSTR pwszString +) +{ + DWORD dwLen = 0; + + if (NULL == pLsaString) + return FALSE; + + if (NULL != pwszString) + { + dwLen = wcslen(pwszString); + if (dwLen > 0x7ffe) // String is too large + return FALSE; + } + + // Store the string. + pLsaString->Buffer = (WCHAR *)pwszString; + pLsaString->Length = (USHORT)dwLen * sizeof(WCHAR); + pLsaString->MaximumLength= (USHORT)(dwLen+1) * sizeof(WCHAR); + + return TRUE; +} + +PLSA_TRANSLATED_SID2 GetSIDInformation (LPWSTR AccountName,LSA_HANDLE PolicyHandle) +{ + LSA_UNICODE_STRING lucName; + PLSA_TRANSLATED_SID2 ltsTranslatedSID; + PLSA_REFERENCED_DOMAIN_LIST lrdlDomainList; + //LSA_TRUST_INFORMATION myDomain; + NTSTATUS ntsResult; + PWCHAR DomainString = NULL; + + // Initialize an LSA_UNICODE_STRING with the name. + if (!InitLsaString(&lucName, AccountName)) + { + wprintf(L"Failed InitLsaString\n"); + return NULL; + } + + ntsResult = LsaLookupNames2( + PolicyHandle, // handle to a Policy object + 0, + 1, // number of names to look up + &lucName, // pointer to an array of names + &lrdlDomainList, // receives domain information + <sTranslatedSID // receives relative SIDs + ); + if (0 != ntsResult) + { + wprintf(L"Failed LsaLookupNames - %lu \n", + LsaNtStatusToWinError(ntsResult)); + return NULL; + } + + // Get the domain the account resides in. +// myDomain = lrdlDomainList->Domains[ltsTranslatedSID->DomainIndex]; +// DomainString = (PWCHAR) LocalAlloc(LPTR, myDomain.Name.Length + 1); +// wcsncpy(DomainString, myDomain.Name.Buffer, myDomain.Name.Length); + + // Display the relative Id. +// wprintf(L"Relative Id is %lu in domain %ws.\n", +// ltsTranslatedSID->RelativeId, +// DomainString); + + LsaFreeMemory(lrdlDomainList); + + return ltsTranslatedSID; +} + +BOOL AddPrivileges(PSID AccountSID, LSA_HANDLE PolicyHandle, BOOL bAdd) +{ + LSA_UNICODE_STRING lucPrivilege; + NTSTATUS ntsResult; + + // Create an LSA_UNICODE_STRING for the privilege name(s). + if (!InitLsaString(&lucPrivilege, L"SeLockMemoryPrivilege")) + { + wprintf(L"Failed InitLsaString\n"); + return FALSE; + } + + if( bAdd ) { + ntsResult = LsaAddAccountRights( + PolicyHandle, // An open policy handle. + AccountSID, // The target SID. + &lucPrivilege, // The privilege(s). + 1 // Number of privileges. + ); + } + else { + ntsResult = LsaRemoveAccountRights( + PolicyHandle, // An open policy handle. + AccountSID, // The target SID + FALSE, + &lucPrivilege, // The privilege(s). + 1 // Number of privileges. + ); + } + + if (ntsResult == 0) + { + wprintf(L"Privilege added.\n"); + } + else + { + int err = LsaNtStatusToWinError(ntsResult); + char str[255]; + _snprintf(str, 255, "Privilege was not added - %lu \n", LsaNtStatusToWinError(ntsResult)); + MessageBox(NULL, str, "Privilege error", MB_OK); + return FALSE; + } + + return TRUE; +} + +#define TARGET_SYSTEM_NAME L"mysystem" +LSA_HANDLE GetPolicyHandle() +{ + LSA_OBJECT_ATTRIBUTES ObjectAttributes; + WCHAR SystemName[] = TARGET_SYSTEM_NAME; + USHORT SystemNameLength; + LSA_UNICODE_STRING lusSystemName; + NTSTATUS ntsResult; + LSA_HANDLE lsahPolicyHandle; + + // Object attributes are reserved, so initialize to zeroes. + ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes)); + + //Initialize an LSA_UNICODE_STRING to the server name. + SystemNameLength = wcslen(SystemName); + lusSystemName.Buffer = SystemName; + lusSystemName.Length = SystemNameLength * sizeof(WCHAR); + lusSystemName.MaximumLength = (SystemNameLength+1) * sizeof(WCHAR); + + // Get a handle to the Policy object. + ntsResult = LsaOpenPolicy( + NULL, //Name of the target system. + &ObjectAttributes, //Object attributes. + POLICY_ALL_ACCESS, //Desired access permissions. + &lsahPolicyHandle //Receives the policy handle. + ); + + if (ntsResult != 0) + { + // An error occurred. Display it as a win32 error code. + wprintf(L"OpenPolicy returned %lu\n", + LsaNtStatusToWinError(ntsResult)); + return NULL; + } + return lsahPolicyHandle; +} + + +/***************************************************************** + LoggedSetLockPagesPrivilege: a function to obtain, if possible, or + release the privilege of locking physical pages. + + Inputs: + + HANDLE hProcess: Handle for the process for which the + privilege is needed + + BOOL bEnable: Enable (TRUE) or disable? + + Return value: TRUE indicates success, FALSE failure. + +*****************************************************************/ +BOOL SysLoggedSetLockPagesPrivilege ( HANDLE hProcess, BOOL bEnable) +{ + struct { + u32 Count; + LUID_AND_ATTRIBUTES Privilege [1]; + } Info; + + HANDLE Token; + BOOL Result; + + // Open the token. + + Result = OpenProcessToken ( hProcess, + TOKEN_ADJUST_PRIVILEGES, + & Token); + + if( Result != TRUE ) { + Console::Error( "VirtualMemory Error > Cannot open process token." ); + return FALSE; + } + + // Enable or disable? + + Info.Count = 1; + if( bEnable ) + { + Info.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED; + } + else + { + Info.Privilege[0].Attributes = SE_PRIVILEGE_REMOVED; + } + + // Get the LUID. + Result = LookupPrivilegeValue ( NULL, + SE_LOCK_MEMORY_NAME, + &(Info.Privilege[0].Luid)); + + if( Result != TRUE ) + { + Console::Error( "VirtualMemory Error > Cannot get privilege value for %s.", params SE_LOCK_MEMORY_NAME ); + return FALSE; + } + + // Adjust the privilege. + + Result = AdjustTokenPrivileges ( Token, FALSE, + (PTOKEN_PRIVILEGES) &Info, + 0, NULL, NULL); + + // Check the result. + if( Result != TRUE ) + { + Console::Error( "VirtualMemory Error > Cannot adjust token privileges, error %u.", params GetLastError() ); + return FALSE; + } + else + { + if( GetLastError() != ERROR_SUCCESS ) + { + + BOOL bSuc = FALSE; + LSA_HANDLE policy; + PLSA_TRANSLATED_SID2 ltsTranslatedSID; + +// if( !DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_USERNAME), gApp.hWnd, (DLGPROC)UserNameProc) ) +// return FALSE; + DWORD len = sizeof(s_szUserName); + GetUserNameW(s_szUserName, &len); + + policy = GetPolicyHandle(); + + if( policy != NULL ) { + + ltsTranslatedSID = GetSIDInformation(s_szUserName, policy); + + if( ltsTranslatedSID != NULL ) { + bSuc = AddPrivileges(ltsTranslatedSID->Sid, policy, bEnable); + LsaFreeMemory(ltsTranslatedSID); + } + + LsaClose(policy); + } + + if( bSuc ) { + // Get the LUID. + LookupPrivilegeValue ( NULL, SE_LOCK_MEMORY_NAME, &(Info.Privilege[0].Luid)); + + bSuc = AdjustTokenPrivileges ( Token, FALSE, (PTOKEN_PRIVILEGES) &Info, 0, NULL, NULL); + } + + if( bSuc ) { + if( MessageBox(NULL, "PCSX2 just changed your SE_LOCK_MEMORY privilege in order to gain access to physical memory.\n" + "Log off/on and run pcsx2 again. Do you want to log off?\n", + "Privilege changed query", MB_YESNO) == IDYES ) { + ExitWindows(EWX_LOGOFF, 0); + } + } + else { + MessageBox(NULL, "Failed adding SE_LOCK_MEMORY privilege, please check the local policy.\n" + "Go to security settings->Local Policies->User Rights. There should be a \"Lock pages in memory\".\n" + "Add your user to that and log off/on. This enables pcsx2 to run at real-time by allocating physical memory.\n" + "Also can try Control Panel->Local Security Policy->... (this does not work on Windows XP Home)\n" + "(zerofrog)\n", "Virtual Memory Access Denied", MB_OK); + return FALSE; + } + } + } + + CloseHandle( Token ); + + return TRUE; +} + +static u32 s_dwPageSize = 0; +int SysPhysicalAlloc(u32 size, PSMEMORYBLOCK* pblock) +{ +//#ifdef WIN32_FILE_MAPPING +// assert(0); +//#endif + ULONG_PTR NumberOfPagesInitial; // initial number of pages requested + int PFNArraySize; // memory to request for PFN array + BOOL bResult; + + assert( pblock != NULL ); + memset(pblock, 0, sizeof(PSMEMORYBLOCK)); + + if( s_dwPageSize == 0 ) { + SYSTEM_INFO sSysInfo; // useful system information + GetSystemInfo(&sSysInfo); // fill the system information structure + s_dwPageSize = sSysInfo.dwPageSize; + + if( s_dwPageSize != 0x1000 ) { + Msgbox::Alert("Error! OS page size must be 4Kb!\n" + "If for some reason the OS cannot have 4Kb pages, then run the TLB build."); + return -1; + } + } + + // Calculate the number of pages of memory to request. + pblock->NumberPages = (size+s_dwPageSize-1)/s_dwPageSize; + PFNArraySize = pblock->NumberPages * sizeof (ULONG_PTR); + + pblock->aPFNs = (uptr*)HeapAlloc (GetProcessHeap (), 0, PFNArraySize); + + if (pblock->aPFNs == NULL) { + Console::Error("Failed to allocate on heap."); + goto eCleanupAndExit; + } + + // Allocate the physical memory. + NumberOfPagesInitial = pblock->NumberPages; + bResult = AllocateUserPhysicalPages( GetCurrentProcess(), (PULONG_PTR)&pblock->NumberPages, (PULONG_PTR)pblock->aPFNs ); + + if( bResult != TRUE ) + { + Console::Error("Virtual Memory Error %u > Cannot allocate physical pages.", params GetLastError() ); + goto eCleanupAndExit; + } + + if( NumberOfPagesInitial != pblock->NumberPages ) + { + Console::Error("Virtual Memory > Physical allocation failed!\n\tAllocated only %p of %p pages.", params pblock->NumberPages, NumberOfPagesInitial ); + goto eCleanupAndExit; + } + + pblock->aVFNs = (uptr*)HeapAlloc(GetProcessHeap(), 0, PFNArraySize); + + return 0; + +eCleanupAndExit: + SysPhysicalFree(pblock); + return -1; +} + +void SysPhysicalFree(PSMEMORYBLOCK* pblock) +{ + assert( pblock != NULL ); + + // Free the physical pages. + FreeUserPhysicalPages( GetCurrentProcess(), (PULONG_PTR)&pblock->NumberPages, (PULONG_PTR)pblock->aPFNs ); + + if( pblock->aPFNs != NULL ) HeapFree(GetProcessHeap(), 0, pblock->aPFNs); + if( pblock->aVFNs != NULL ) HeapFree(GetProcessHeap(), 0, pblock->aVFNs); + memset(pblock, 0, sizeof(PSMEMORYBLOCK)); +} + +int SysVirtualPhyAlloc(void* base, u32 size, PSMEMORYBLOCK* pblock) +{ + BOOL bResult; + int i; + + LPVOID lpMemReserved = VirtualAlloc( base, size, MEM_RESERVE | MEM_PHYSICAL, PAGE_READWRITE ); + if( lpMemReserved == NULL || base != lpMemReserved ) + { + Console::WriteLn("VirtualMemory Error %d > Cannot reserve memory at 0x%8.8x(%x).", params base, lpMemReserved, GetLastError()); + goto eCleanupAndExit; + } + + // Map the physical memory into the window. + bResult = MapUserPhysicalPages( base, (ULONG_PTR)pblock->NumberPages, (PULONG_PTR)pblock->aPFNs ); + + for(i = 0; i < pblock->NumberPages; ++i) + pblock->aVFNs[i] = (uptr)base + 0x1000*i; + + if( bResult != TRUE ) + { + Console::WriteLn("VirtualMemory Error %u > MapUserPhysicalPages failed to map.", params GetLastError() ); + goto eCleanupAndExit; + } + + return 0; + +eCleanupAndExit: + SysVirtualFree(base, size); + return -1; +} + +void SysVirtualFree(void* lpMemReserved, u32 size) +{ + // unmap + if( MapUserPhysicalPages( lpMemReserved, (size+s_dwPageSize-1)/s_dwPageSize, NULL ) != TRUE ) + { + Console::WriteLn("VirtualMemory Error %u > MapUserPhysicalPages failed to unmap", params GetLastError() ); + return; + } + + // Free virtual memory. + VirtualFree( lpMemReserved, 0, MEM_RELEASE ); +} + +int SysMapUserPhysicalPages(void* Addr, uptr NumPages, uptr* pfn, int pageoffset) +{ + BOOL bResult = MapUserPhysicalPages(Addr, NumPages, (PULONG_PTR)(pfn+pageoffset)); + +#ifdef _DEBUG + //if( !bResult ) + //__Log("Failed to map user pages: 0x%x:0x%x, error = %d\n", Addr, NumPages, GetLastError()); +#endif + + return bResult; +} + +#else + +#endif diff --git a/pcsx2/windows/afxresmw.h b/pcsx2/windows/afxresmw.h index 2e5a124bb3..b0078b1dfb 100644 --- a/pcsx2/windows/afxresmw.h +++ b/pcsx2/windows/afxresmw.h @@ -1,23 +1,23 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 Team - * Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) - * - * 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 -#include - -#define IDC_STATIC (-1) +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 Team + * Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) + * + * 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 +#include + +#define IDC_STATIC (-1) diff --git a/pcsx2/windows/cheats/browser.cpp b/pcsx2/windows/cheats/browser.cpp index 3a40fa22ea..919d48b066 100644 --- a/pcsx2/windows/cheats/browser.cpp +++ b/pcsx2/windows/cheats/browser.cpp @@ -1,1129 +1,1129 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" -#include "../Win32.h" - -#include -#include - -using namespace std; - -#include "../cheatscpp.h" - -#include "PS2Edefs.h" -#include "Memory.h" -#include "Elfheader.h" -#include "cheats.h" -#include "../../patch.h" - -HWND hWndBrowser; - - -/// ADDED CODE /// -void CreateListBox(HWND hWnd) -{ - // Setting the ListView style - LRESULT lStyle = SendMessage(GetDlgItem(hWnd,IDC_PATCHES), LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); - SendMessage(GetDlgItem(hWnd,IDC_PATCHES), LVM_SETEXTENDEDLISTVIEWSTYLE, 0, lStyle | LVS_EX_FULLROWSELECT); - - // Adding colummns to the ListView - LVCOLUMN cols[7]={ - {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,70,"Address",0,0,0}, - {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,35,"CPU",1,0,0}, - {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,70,"Data",2,0,0}, - {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,50,"Enabled",3,0,0}, - {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,45,"Group",4,0,0}, - {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,80,"PlaceToPatch",5,0,0}, - {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,50,"Type",6,0,0} - }; - - ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),0,&cols[0]); - ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),1,&cols[1]); - ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),2,&cols[2]); - ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),3,&cols[3]); - ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),4,&cols[4]); - ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),5,&cols[5]); - ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),6,&cols[6]); -} - -void RefreshListBox(HWND hWnd) -{ - // First delete all items - ListView_DeleteAllItems(GetDlgItem(hWnd,IDC_PATCHES)); - - char Address[100], CPU[100], Data[100], Enabled[100], Group[100], PlaceToPatch[100], Type[100]; - - LVITEM item[7]={ - {LVIF_TEXT|LVIF_STATE,0,0,0,0,Address,0,0,0,0}, - {LVIF_TEXT|LVIF_STATE,0,1,0,0,CPU,0,0,0,0}, - {LVIF_TEXT|LVIF_STATE,0,2,0,0,Data,0,0,0,0}, - {LVIF_TEXT|LVIF_STATE,0,3,0,0,Enabled,0,0,0,0}, - {LVIF_TEXT|LVIF_STATE,0,4,0,0,Group,0,0,0,0}, - {LVIF_TEXT|LVIF_STATE,0,5,0,0,PlaceToPatch,0,0,0,0}, - {LVIF_TEXT|LVIF_STATE,0,6,0,0,Type,0,0,0,0} - }; - - char datatype[4][10]={"byte", "short", "word", "double"}; - char cpucore[2][10]={"EE", "IOP"}; - - // Adding items - for (int i = patchnumber-1; i >= 0; i--) - { - sprintf(Address, "0x%.8x", patch[i].addr); - sprintf(CPU, "%s", cpucore[patch[i].cpu-1]); - sprintf(Data, "0x%.8x", patch[i].data); - sprintf(Enabled, "%s", patch[i].enabled?"Yes":"No"); - sprintf(Group, "%d", patch[i].group); - sprintf(PlaceToPatch, "%d", patch[i].placetopatch); - sprintf(Type, "%s", datatype[patch[i].type-1]); - - ListView_InsertItem(GetDlgItem(hWnd,IDC_PATCHES),&item[0]); - ListView_SetItem(GetDlgItem(hWnd,IDC_PATCHES),&item[1]); - ListView_SetItem(GetDlgItem(hWnd,IDC_PATCHES),&item[2]); - ListView_SetItem(GetDlgItem(hWnd,IDC_PATCHES),&item[3]); - ListView_SetItem(GetDlgItem(hWnd,IDC_PATCHES),&item[4]); - ListView_SetItem(GetDlgItem(hWnd,IDC_PATCHES),&item[5]); - ListView_SetItem(GetDlgItem(hWnd,IDC_PATCHES),&item[6]); - } -} - - -// Decryption code for GS2v3-4/GS5 from maxconvert 0.71 -unsigned char gsv3_bseeds1[256] = { -0x6E, 0x3C, 0x01, 0x30, 0x45, 0xDA, 0xA1, 0x77, 0x6A, 0x41, 0xFC, 0xC6, 0x00, 0xEA, 0x2F, 0x23, -0xD9, 0x6F, 0x79, 0x39, 0x7E, 0xCC, 0x9A, 0x4E, 0x1E, 0xF4, 0xA7, 0x3D, 0x05, 0x75, 0xD0, 0x36, -0x9E, 0x8D, 0xF8, 0x8B, 0x96, 0x7A, 0xBF, 0x49, 0x62, 0x4F, 0x2A, 0xB8, 0xAF, 0x60, 0x80, 0x0D, -0x99, 0x89, 0xA9, 0xED, 0xB6, 0xD5, 0x7B, 0x54, 0x56, 0x65, 0x5C, 0xB3, 0xD3, 0x11, 0xDF, 0x27, -0x10, 0x71, 0x91, 0x3E, 0x25, 0x52, 0x46, 0x15, 0x3A, 0x31, 0x51, 0x81, 0xC5, 0xB1, 0xBE, 0x43, -0x95, 0x7C, 0x83, 0x53, 0x38, 0x88, 0x21, 0x4C, 0x9B, 0x7F, 0x90, 0xB9, 0xDB, 0x55, 0x33, 0xB7, -0xAD, 0x61, 0xD8, 0xE1, 0xE4, 0x20, 0xDC, 0x5F, 0xA4, 0x67, 0x26, 0x97, 0x2E, 0xAC, 0x7D, 0x24, -0xBD, 0x22, 0x04, 0x6C, 0xC0, 0x73, 0xE0, 0x32, 0x0C, 0xA3, 0xEE, 0x2B, 0xA0, 0x8A, 0x5B, 0xF3, -0xA6, 0xD1, 0x68, 0x8E, 0xAE, 0xC7, 0x9C, 0x82, 0xB4, 0xF9, 0xF6, 0xC4, 0x1B, 0xAB, 0x57, 0xCE, -0xEF, 0x69, 0xF7, 0x74, 0xFF, 0xA2, 0x6D, 0xF5, 0xB2, 0x0A, 0x37, 0x1F, 0xEC, 0x06, 0x5D, 0x0F, -0xB0, 0x08, 0xD7, 0xE3, 0x85, 0x58, 0x1A, 0x9F, 0x1D, 0x84, 0xE9, 0xEB, 0x0E, 0x66, 0x64, 0x40, -0x4A, 0x44, 0x35, 0x92, 0x3B, 0x86, 0xF0, 0xF2, 0xAA, 0x47, 0xCB, 0x02, 0xB5, 0xDD, 0xD2, 0x13, -0x16, 0x07, 0xC2, 0xE5, 0x17, 0xA5, 0x5E, 0xCA, 0xD6, 0xC9, 0x87, 0x2D, 0xC1, 0xCD, 0x76, 0x50, -0x1C, 0xE2, 0x8F, 0x29, 0xD4, 0xDE, 0xA8, 0xE7, 0x14, 0xFB, 0xC3, 0xE6, 0xFD, 0x5A, 0x48, 0xCF, -0x98, 0x42, 0x63, 0x4D, 0xBB, 0xE8, 0x70, 0xF1, 0x12, 0x78, 0x0B, 0xFA, 0xBA, 0x18, 0x93, 0x9D, -0x6B, 0x28, 0x2C, 0x09, 0x59, 0xFE, 0xC8, 0x34, 0x03, 0x94, 0x72, 0x8C, 0x3F, 0x4B, 0x19, 0xBC -}; - -unsigned char gsv3_bseeds2[25] = { 0x12, 0x18, 0x07, 0x0A, 0x17, 0x16, 0x10, 0x00, -0x05, 0x0D, 0x04, 0x02, 0x09, 0x08, 0x0E, 0x0F, 0x13, 0x11, 0x01, 0x15, -0x03, 0x06, 0x0C, 0x0B, 0x14 -}; - -unsigned char gsv3_bseeds3[64] = {0x1D, 0x01, 0x33, 0x0B, 0x23, 0x22, 0x2C, 0x24, -0x0E, 0x2A, 0x2D, 0x0F, 0x2B, 0x20, 0x08, 0x34, 0x17, 0x1B, 0x36, 0x0C, -0x12, 0x1F, 0x35, 0x27, 0x0A, 0x31, 0x11, 0x05, 0x1E, 0x32, 0x14, 0x02, -0x21, 0x03, 0x04, 0x0D, 0x09, 0x16, 0x2E, 0x1A, 0x26, 0x25, 0x2F, 0x07, -0x1C, 0x29, 0x18, 0x30, 0x10, 0x15, 0x13, 0x19, 0x06, 0x38, 0x28, 0x00, -0x37, 0x48, 0x48, 0x7F, 0x45, 0x45, 0x45, 0x7F -}; - -unsigned char gsv3_bseeds4[64] = { 0x10, 0x01, 0x18, 0x3C, 0x33, 0x29, 0x00, 0x06, -0x07, 0x02, 0x04, 0x13, 0x0B, 0x28, 0x15, 0x08, 0x1F, 0x3E, 0x0C, 0x05, -0x11, 0x1D, 0x1E, 0x27, 0x1A, 0x17, 0x38, 0x23, 0x2D, 0x37, 0x03, 0x2C, -0x2A, 0x1B, 0x22, 0x39, 0x25, 0x14, 0x24, 0x34, 0x20, 0x2F, 0x36, 0x3F, -0x3A, 0x0E, 0x0F, 0x2B, 0x32, 0x31, 0x21, 0x12, 0x26, 0x35, 0x30, 0x3B, -0x09, 0x19, 0x16, 0x0D, 0x0A, 0x2E, 0x3D, 0x1C -}; - -unsigned short gsv3_hseeds[4] = { 0x6C27, 0x1D38, 0x7FE1, 0x0000}; - -unsigned char gsv3_bseeds101[256] = { -0x0C, 0x02, 0xBB, 0xF8, 0x72, 0x1C, 0x9D, 0xC1, 0xA1, 0xF3, 0x99, 0xEA, 0x78, 0x2F, 0xAC, 0x9F, -0x40, 0x3D, 0xE8, 0xBF, 0xD8, 0x47, 0xC0, 0xC4, 0xED, 0xFE, 0xA6, 0x8C, 0xD0, 0xA8, 0x18, 0x9B, -0x65, 0x56, 0x71, 0x0F, 0x6F, 0x44, 0x6A, 0x3F, 0xF1, 0xD3, 0x2A, 0x7B, 0xF2, 0xCB, 0x6C, 0x0E, -0x03, 0x49, 0x77, 0x5E, 0xF7, 0xB2, 0x1F, 0x9A, 0x54, 0x13, 0x48, 0xB4, 0x01, 0x1B, 0x43, 0xFC, -0xAF, 0x09, 0xE1, 0x4F, 0xB1, 0x04, 0x46, 0xB9, 0xDE, 0x27, 0xB0, 0xFD, 0x57, 0xE3, 0x17, 0x29, -0xCF, 0x4A, 0x45, 0x53, 0x37, 0x5D, 0x38, 0x8E, 0xA5, 0xF4, 0xDD, 0x7E, 0x3A, 0x9E, 0xC6, 0x67, -0x2D, 0x61, 0x28, 0xE2, 0xAE, 0x39, 0xAD, 0x69, 0x82, 0x91, 0x08, 0xF0, 0x73, 0x96, 0x00, 0x11, -0xE6, 0x41, 0xFA, 0x75, 0x93, 0x1D, 0xCE, 0x07, 0xE9, 0x12, 0x25, 0x36, 0x51, 0x6E, 0x14, 0x59, -0x2E, 0x4B, 0x87, 0x52, 0xA9, 0xA4, 0xB5, 0xCA, 0x55, 0x31, 0x7D, 0x23, 0xFB, 0x21, 0x83, 0xD2, -0x5A, 0x42, 0xB3, 0xEE, 0xF9, 0x50, 0x24, 0x6B, 0xE0, 0x30, 0x16, 0x58, 0x86, 0xEF, 0x20, 0xA7, -0x7C, 0x06, 0x95, 0x79, 0x68, 0xC5, 0x80, 0x1A, 0xD6, 0x32, 0xB8, 0x8D, 0x6D, 0x60, 0x84, 0x2C, -0xA0, 0x4D, 0x98, 0x3B, 0x88, 0xBC, 0x34, 0x5F, 0x2B, 0x5B, 0xEC, 0xE4, 0xFF, 0x70, 0x4E, 0x26, -0x74, 0xCC, 0xC2, 0xDA, 0x8B, 0x4C, 0x0B, 0x85, 0xF6, 0xC9, 0xC7, 0xBA, 0x15, 0xCD, 0x8F, 0xDF, -0x1E, 0x81, 0xBE, 0x3C, 0xD4, 0x35, 0xC8, 0xA2, 0x62, 0x10, 0x05, 0x5C, 0x66, 0xBD, 0xD5, 0x3E, -0x76, 0x63, 0xD1, 0xA3, 0x64, 0xC3, 0xDB, 0xD7, 0xE5, 0xAA, 0x0D, 0xAB, 0x9C, 0x33, 0x7A, 0x90, -0xB6, 0xE7, 0xB7, 0x7F, 0x19, 0x97, 0x8A, 0x92, 0x22, 0x89, 0xEB, 0xD9, 0x0A, 0xDC, 0xF5, 0x94 -}; - - -u8 DecryptGS2v3(u32* address, u32* value, u8 ctrl) -{ - u32 command = *address & 0xFE000000; - u32 tmp = 0, tmp2 = 0, mask = 0, i = 0; - u8 bmask[4], flag; - u8 encFlag = (*address >> 25) & 0x7; - - if(ctrl > 0) - { - switch(ctrl) - { - case 2: - { - *address ^= (gsv3_hseeds[1] << 2); - *value ^= (gsv3_hseeds[1] << 13); - for(i = 0; i < 0x40; i++) - { - if(i < 32) - { - flag = (*value >> i) & 1; - } - else - { - flag = (*address >> (i - 32)) & 1; - } - - if(flag > 0) - { - if(gsv3_bseeds4[i] < 32) - { - tmp2 |= (1 << gsv3_bseeds4[i]); - } - else - { - tmp |= (1 << (gsv3_bseeds4[i] - 32)); - } - } - } - - *address = tmp ^ (gsv3_hseeds[2] << 3); - *value = tmp2 ^ gsv3_hseeds[2]; - break; - } - - case 4: - { - tmp = *address ^ (gsv3_hseeds[1] << 3); - bmask[0] = gsv3_bseeds1[(tmp >> 24) & 0xFF]; - bmask[1] = gsv3_bseeds1[(tmp >> 16) & 0xFF]; - bmask[2] = gsv3_bseeds1[(tmp >> 8) & 0xFF]; - bmask[3] = gsv3_bseeds1[tmp & 0xFF]; - tmp = (bmask[0] << 24) | (bmask[1] << 16) | (bmask[2] << 8) | bmask[3]; - *address = tmp ^ (gsv3_hseeds[2] << 16); - - tmp = *value ^ (gsv3_hseeds[1] << 9); - bmask[0] = gsv3_bseeds1[(tmp >> 24) & 0xFF]; - bmask[1] = gsv3_bseeds1[(tmp >> 16) & 0xFF]; - bmask[2] = gsv3_bseeds1[(tmp >> 8) & 0xFF]; - bmask[3] = gsv3_bseeds1[tmp & 0xFF]; - tmp = (bmask[0] << 24) | (bmask[1] << 16) | (bmask[2] << 8) | bmask[3]; - *value = tmp ^ (gsv3_hseeds[2] << 5); - break; - } - } - return 0; - } - - if(command >= 0x30000000 && command <= 0x6FFFFFFF) - { - if(encFlag == 1 || encFlag == 2) - { - ctrl = 2; - } - else if (encFlag == 3 || encFlag == 4) - { - ctrl = 4; - } - } - - switch(encFlag) - { - case 0: - { - break; - } - - case 1: - { - tmp = *address & 0x01FFFFFF; - tmp = tmp ^ (gsv3_hseeds[1] << 8); - mask = 0; - for(i = 0; i < 25; i++) - { - mask |= ((tmp & (1 << i)) >> i) << gsv3_bseeds2[i]; - } - tmp = mask ^ gsv3_hseeds[2]; - tmp |= command; - *address = tmp & 0xF1FFFFFF; - break; - } - - case 2: - { - if(encFlag == 2) - { - tmp = *address & 0x01FFFFFF; - *address = tmp ^ (gsv3_hseeds[1] << 1); - *value ^= (gsv3_hseeds[1] << 16); - tmp = 0; - tmp2 = 0; - for(i = 0; i < 0x39; i++) - { - if(i < 32) - { - flag = (*value >> i) & 1; - } - else - { - flag = (*address >> (i - 32)) & 1; - } - - if(flag > 0) - { - if(gsv3_bseeds3[i] < 32) - { - tmp2 |= (1 << gsv3_bseeds3[i]); - } - else - { - tmp |= (1 << (gsv3_bseeds3[i] - 32)); - } - } - } - *address = ((tmp ^ (gsv3_hseeds[2] << 8)) | command) & 0xF1FFFFFF; - *value = tmp2 ^ gsv3_hseeds[2]; - } - break; - } - - case 3: - { - tmp = *address ^ (gsv3_hseeds[1] << 8); - bmask[0] = gsv3_bseeds1[(tmp >> 8) & 0xFF]; - bmask[1] = gsv3_bseeds1[(tmp & 0xFF)]; - tmp = (tmp & 0xFFFF0000) ; - tmp |= (bmask[0] ^ (bmask[1] << 8)) ; - tmp ^= (gsv3_hseeds[2] << 4); - *address = tmp & 0xF1FFFFFF; - break; - } - - case 4: - { - tmp = *address ^ (gsv3_hseeds[1] << 8); - bmask[0] = gsv3_bseeds1[(tmp >> 8) & 0xFF]; - bmask[1] = gsv3_bseeds1[(tmp & 0xFF)]; - tmp = (tmp & 0xFFFF0000) ; - tmp |= (bmask[1] | (bmask[0] << 8)) ; - tmp ^= (gsv3_hseeds[2] << 4); - tmp2 = *address ^ (gsv3_hseeds[1] << 3); - *address = tmp & 0xF1FFFFFF; - tmp = *value ^ (gsv3_hseeds[1] << 9); - bmask[0] = gsv3_bseeds1[(tmp >> 24) & 0xFF]; - bmask[1] = gsv3_bseeds1[(tmp >> 16) & 0xFF]; - bmask[2] = gsv3_bseeds1[(tmp >> 8) & 0xFF]; - bmask[3] = gsv3_bseeds1[tmp & 0xFF]; - tmp = (bmask[0] << 24) | (bmask[1] << 16) | (bmask[2] << 8) | bmask[3]; - *value = tmp ^ (gsv3_hseeds[2] << 5); - break; - } - - case 5: - case 6: - case 7: - default: - break; - } - - return ctrl; - -} - -struct Cheat -{ - unsigned int address, value; -}; - -int ParseCheats(char *cur, std::vector &Cheats, HWND hWnd) -{ - // Parse the text and put the cheats to the vector - while(*cur!=NULL){ - Cheat C; - - // if there is endline advance 2 chars - if(*cur==0x0d && *(cur+1)==0x0a) - cur+=2; - // check if new start is null - if(*cur==NULL) - break; - - // get address and value and insert in the vector - int ret = sscanf(cur, "%X %X", &C.address, &C.value); - if(ret != 2) - { - MessageBox(hWnd,"Code conversion is probably wrong.","Error",0); - return 0; - } - Cheats.insert(Cheats.end(), C); - cur+=17; - } - return 1; -} - - -// Callback for the GameShark2 v3-4 cheat dialog -BOOL CALLBACK AddGS(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) -{ - int wmId,wmEvent; - static HWND hParent; - - switch(uMsg) - { - - case WM_PAINT: - return FALSE; - case WM_INITDIALOG: - hParent=(HWND)lParam; - break; - case WM_COMMAND: - wmId = LOWORD(wParam); - wmEvent = HIWORD(wParam); - // Parse the menu selections: - switch (wmId) - { - case IDCANCEL: - EndDialog(hWnd,1); - break; - - case IDC_CONVERT: // Convert the code - { - std::vector Cheats; - char chepa[256]; - - // Set ready text to false - SetWindowText(GetDlgItem(hWnd,IDC_READY), "0"); - - // Get the text from the edit control and load it - GetWindowText(GetDlgItem(hWnd,IDC_ADDR),chepa,256); - - // Parsing the cheats - ParseCheats(chepa, Cheats, hWnd); - - int control = 0; - *chepa=0; - // Decrypt multiline code - for(unsigned int i=0;i Cheats; - char ready[2], chepa[256]; - - // Check if we are ready to add first - GetWindowText(GetDlgItem(hWnd,IDC_READY),ready,2); - if(ready[0] == '0') - { - MessageBox(hWnd, "First convert the code.", "Error", 0); - break; - } - - // Get the text from the edit control and load it - GetWindowText(GetDlgItem(hWnd,IDC_CONVERTEDCODE),chepa,256); - - // Parsing the cheats - int ret = ParseCheats(chepa, Cheats, hWnd); - - if(ret == 1) - { - // Adding cheats - for(unsigned int i=0;i Cheats; - char chepa[256]; - - // Get the text from the edit control and load it - GetWindowText(GetDlgItem(hWnd,IDC_ADDR),chepa,256); - - if(strlen(chepa) == 0) - { - MessageBox(hWnd, "Add some cheats.", "Error", 0); - break; - } - - // Parsing the cheats - int ret = ParseCheats(chepa, Cheats, hWnd); - - if(ret == 1) - { - // Adding cheats - for(unsigned int i=0;i +#include + +using namespace std; + +#include "../cheatscpp.h" + +#include "PS2Edefs.h" +#include "Memory.h" +#include "Elfheader.h" +#include "cheats.h" +#include "../../patch.h" + +HWND hWndBrowser; + + +/// ADDED CODE /// +void CreateListBox(HWND hWnd) +{ + // Setting the ListView style + LRESULT lStyle = SendMessage(GetDlgItem(hWnd,IDC_PATCHES), LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); + SendMessage(GetDlgItem(hWnd,IDC_PATCHES), LVM_SETEXTENDEDLISTVIEWSTYLE, 0, lStyle | LVS_EX_FULLROWSELECT); + + // Adding colummns to the ListView + LVCOLUMN cols[7]={ + {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,70,"Address",0,0,0}, + {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,35,"CPU",1,0,0}, + {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,70,"Data",2,0,0}, + {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,50,"Enabled",3,0,0}, + {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,45,"Group",4,0,0}, + {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,80,"PlaceToPatch",5,0,0}, + {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,50,"Type",6,0,0} + }; + + ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),0,&cols[0]); + ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),1,&cols[1]); + ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),2,&cols[2]); + ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),3,&cols[3]); + ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),4,&cols[4]); + ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),5,&cols[5]); + ListView_InsertColumn(GetDlgItem(hWnd,IDC_PATCHES),6,&cols[6]); +} + +void RefreshListBox(HWND hWnd) +{ + // First delete all items + ListView_DeleteAllItems(GetDlgItem(hWnd,IDC_PATCHES)); + + char Address[100], CPU[100], Data[100], Enabled[100], Group[100], PlaceToPatch[100], Type[100]; + + LVITEM item[7]={ + {LVIF_TEXT|LVIF_STATE,0,0,0,0,Address,0,0,0,0}, + {LVIF_TEXT|LVIF_STATE,0,1,0,0,CPU,0,0,0,0}, + {LVIF_TEXT|LVIF_STATE,0,2,0,0,Data,0,0,0,0}, + {LVIF_TEXT|LVIF_STATE,0,3,0,0,Enabled,0,0,0,0}, + {LVIF_TEXT|LVIF_STATE,0,4,0,0,Group,0,0,0,0}, + {LVIF_TEXT|LVIF_STATE,0,5,0,0,PlaceToPatch,0,0,0,0}, + {LVIF_TEXT|LVIF_STATE,0,6,0,0,Type,0,0,0,0} + }; + + char datatype[4][10]={"byte", "short", "word", "double"}; + char cpucore[2][10]={"EE", "IOP"}; + + // Adding items + for (int i = patchnumber-1; i >= 0; i--) + { + sprintf(Address, "0x%.8x", patch[i].addr); + sprintf(CPU, "%s", cpucore[patch[i].cpu-1]); + sprintf(Data, "0x%.8x", patch[i].data); + sprintf(Enabled, "%s", patch[i].enabled?"Yes":"No"); + sprintf(Group, "%d", patch[i].group); + sprintf(PlaceToPatch, "%d", patch[i].placetopatch); + sprintf(Type, "%s", datatype[patch[i].type-1]); + + ListView_InsertItem(GetDlgItem(hWnd,IDC_PATCHES),&item[0]); + ListView_SetItem(GetDlgItem(hWnd,IDC_PATCHES),&item[1]); + ListView_SetItem(GetDlgItem(hWnd,IDC_PATCHES),&item[2]); + ListView_SetItem(GetDlgItem(hWnd,IDC_PATCHES),&item[3]); + ListView_SetItem(GetDlgItem(hWnd,IDC_PATCHES),&item[4]); + ListView_SetItem(GetDlgItem(hWnd,IDC_PATCHES),&item[5]); + ListView_SetItem(GetDlgItem(hWnd,IDC_PATCHES),&item[6]); + } +} + + +// Decryption code for GS2v3-4/GS5 from maxconvert 0.71 +unsigned char gsv3_bseeds1[256] = { +0x6E, 0x3C, 0x01, 0x30, 0x45, 0xDA, 0xA1, 0x77, 0x6A, 0x41, 0xFC, 0xC6, 0x00, 0xEA, 0x2F, 0x23, +0xD9, 0x6F, 0x79, 0x39, 0x7E, 0xCC, 0x9A, 0x4E, 0x1E, 0xF4, 0xA7, 0x3D, 0x05, 0x75, 0xD0, 0x36, +0x9E, 0x8D, 0xF8, 0x8B, 0x96, 0x7A, 0xBF, 0x49, 0x62, 0x4F, 0x2A, 0xB8, 0xAF, 0x60, 0x80, 0x0D, +0x99, 0x89, 0xA9, 0xED, 0xB6, 0xD5, 0x7B, 0x54, 0x56, 0x65, 0x5C, 0xB3, 0xD3, 0x11, 0xDF, 0x27, +0x10, 0x71, 0x91, 0x3E, 0x25, 0x52, 0x46, 0x15, 0x3A, 0x31, 0x51, 0x81, 0xC5, 0xB1, 0xBE, 0x43, +0x95, 0x7C, 0x83, 0x53, 0x38, 0x88, 0x21, 0x4C, 0x9B, 0x7F, 0x90, 0xB9, 0xDB, 0x55, 0x33, 0xB7, +0xAD, 0x61, 0xD8, 0xE1, 0xE4, 0x20, 0xDC, 0x5F, 0xA4, 0x67, 0x26, 0x97, 0x2E, 0xAC, 0x7D, 0x24, +0xBD, 0x22, 0x04, 0x6C, 0xC0, 0x73, 0xE0, 0x32, 0x0C, 0xA3, 0xEE, 0x2B, 0xA0, 0x8A, 0x5B, 0xF3, +0xA6, 0xD1, 0x68, 0x8E, 0xAE, 0xC7, 0x9C, 0x82, 0xB4, 0xF9, 0xF6, 0xC4, 0x1B, 0xAB, 0x57, 0xCE, +0xEF, 0x69, 0xF7, 0x74, 0xFF, 0xA2, 0x6D, 0xF5, 0xB2, 0x0A, 0x37, 0x1F, 0xEC, 0x06, 0x5D, 0x0F, +0xB0, 0x08, 0xD7, 0xE3, 0x85, 0x58, 0x1A, 0x9F, 0x1D, 0x84, 0xE9, 0xEB, 0x0E, 0x66, 0x64, 0x40, +0x4A, 0x44, 0x35, 0x92, 0x3B, 0x86, 0xF0, 0xF2, 0xAA, 0x47, 0xCB, 0x02, 0xB5, 0xDD, 0xD2, 0x13, +0x16, 0x07, 0xC2, 0xE5, 0x17, 0xA5, 0x5E, 0xCA, 0xD6, 0xC9, 0x87, 0x2D, 0xC1, 0xCD, 0x76, 0x50, +0x1C, 0xE2, 0x8F, 0x29, 0xD4, 0xDE, 0xA8, 0xE7, 0x14, 0xFB, 0xC3, 0xE6, 0xFD, 0x5A, 0x48, 0xCF, +0x98, 0x42, 0x63, 0x4D, 0xBB, 0xE8, 0x70, 0xF1, 0x12, 0x78, 0x0B, 0xFA, 0xBA, 0x18, 0x93, 0x9D, +0x6B, 0x28, 0x2C, 0x09, 0x59, 0xFE, 0xC8, 0x34, 0x03, 0x94, 0x72, 0x8C, 0x3F, 0x4B, 0x19, 0xBC +}; + +unsigned char gsv3_bseeds2[25] = { 0x12, 0x18, 0x07, 0x0A, 0x17, 0x16, 0x10, 0x00, +0x05, 0x0D, 0x04, 0x02, 0x09, 0x08, 0x0E, 0x0F, 0x13, 0x11, 0x01, 0x15, +0x03, 0x06, 0x0C, 0x0B, 0x14 +}; + +unsigned char gsv3_bseeds3[64] = {0x1D, 0x01, 0x33, 0x0B, 0x23, 0x22, 0x2C, 0x24, +0x0E, 0x2A, 0x2D, 0x0F, 0x2B, 0x20, 0x08, 0x34, 0x17, 0x1B, 0x36, 0x0C, +0x12, 0x1F, 0x35, 0x27, 0x0A, 0x31, 0x11, 0x05, 0x1E, 0x32, 0x14, 0x02, +0x21, 0x03, 0x04, 0x0D, 0x09, 0x16, 0x2E, 0x1A, 0x26, 0x25, 0x2F, 0x07, +0x1C, 0x29, 0x18, 0x30, 0x10, 0x15, 0x13, 0x19, 0x06, 0x38, 0x28, 0x00, +0x37, 0x48, 0x48, 0x7F, 0x45, 0x45, 0x45, 0x7F +}; + +unsigned char gsv3_bseeds4[64] = { 0x10, 0x01, 0x18, 0x3C, 0x33, 0x29, 0x00, 0x06, +0x07, 0x02, 0x04, 0x13, 0x0B, 0x28, 0x15, 0x08, 0x1F, 0x3E, 0x0C, 0x05, +0x11, 0x1D, 0x1E, 0x27, 0x1A, 0x17, 0x38, 0x23, 0x2D, 0x37, 0x03, 0x2C, +0x2A, 0x1B, 0x22, 0x39, 0x25, 0x14, 0x24, 0x34, 0x20, 0x2F, 0x36, 0x3F, +0x3A, 0x0E, 0x0F, 0x2B, 0x32, 0x31, 0x21, 0x12, 0x26, 0x35, 0x30, 0x3B, +0x09, 0x19, 0x16, 0x0D, 0x0A, 0x2E, 0x3D, 0x1C +}; + +unsigned short gsv3_hseeds[4] = { 0x6C27, 0x1D38, 0x7FE1, 0x0000}; + +unsigned char gsv3_bseeds101[256] = { +0x0C, 0x02, 0xBB, 0xF8, 0x72, 0x1C, 0x9D, 0xC1, 0xA1, 0xF3, 0x99, 0xEA, 0x78, 0x2F, 0xAC, 0x9F, +0x40, 0x3D, 0xE8, 0xBF, 0xD8, 0x47, 0xC0, 0xC4, 0xED, 0xFE, 0xA6, 0x8C, 0xD0, 0xA8, 0x18, 0x9B, +0x65, 0x56, 0x71, 0x0F, 0x6F, 0x44, 0x6A, 0x3F, 0xF1, 0xD3, 0x2A, 0x7B, 0xF2, 0xCB, 0x6C, 0x0E, +0x03, 0x49, 0x77, 0x5E, 0xF7, 0xB2, 0x1F, 0x9A, 0x54, 0x13, 0x48, 0xB4, 0x01, 0x1B, 0x43, 0xFC, +0xAF, 0x09, 0xE1, 0x4F, 0xB1, 0x04, 0x46, 0xB9, 0xDE, 0x27, 0xB0, 0xFD, 0x57, 0xE3, 0x17, 0x29, +0xCF, 0x4A, 0x45, 0x53, 0x37, 0x5D, 0x38, 0x8E, 0xA5, 0xF4, 0xDD, 0x7E, 0x3A, 0x9E, 0xC6, 0x67, +0x2D, 0x61, 0x28, 0xE2, 0xAE, 0x39, 0xAD, 0x69, 0x82, 0x91, 0x08, 0xF0, 0x73, 0x96, 0x00, 0x11, +0xE6, 0x41, 0xFA, 0x75, 0x93, 0x1D, 0xCE, 0x07, 0xE9, 0x12, 0x25, 0x36, 0x51, 0x6E, 0x14, 0x59, +0x2E, 0x4B, 0x87, 0x52, 0xA9, 0xA4, 0xB5, 0xCA, 0x55, 0x31, 0x7D, 0x23, 0xFB, 0x21, 0x83, 0xD2, +0x5A, 0x42, 0xB3, 0xEE, 0xF9, 0x50, 0x24, 0x6B, 0xE0, 0x30, 0x16, 0x58, 0x86, 0xEF, 0x20, 0xA7, +0x7C, 0x06, 0x95, 0x79, 0x68, 0xC5, 0x80, 0x1A, 0xD6, 0x32, 0xB8, 0x8D, 0x6D, 0x60, 0x84, 0x2C, +0xA0, 0x4D, 0x98, 0x3B, 0x88, 0xBC, 0x34, 0x5F, 0x2B, 0x5B, 0xEC, 0xE4, 0xFF, 0x70, 0x4E, 0x26, +0x74, 0xCC, 0xC2, 0xDA, 0x8B, 0x4C, 0x0B, 0x85, 0xF6, 0xC9, 0xC7, 0xBA, 0x15, 0xCD, 0x8F, 0xDF, +0x1E, 0x81, 0xBE, 0x3C, 0xD4, 0x35, 0xC8, 0xA2, 0x62, 0x10, 0x05, 0x5C, 0x66, 0xBD, 0xD5, 0x3E, +0x76, 0x63, 0xD1, 0xA3, 0x64, 0xC3, 0xDB, 0xD7, 0xE5, 0xAA, 0x0D, 0xAB, 0x9C, 0x33, 0x7A, 0x90, +0xB6, 0xE7, 0xB7, 0x7F, 0x19, 0x97, 0x8A, 0x92, 0x22, 0x89, 0xEB, 0xD9, 0x0A, 0xDC, 0xF5, 0x94 +}; + + +u8 DecryptGS2v3(u32* address, u32* value, u8 ctrl) +{ + u32 command = *address & 0xFE000000; + u32 tmp = 0, tmp2 = 0, mask = 0, i = 0; + u8 bmask[4], flag; + u8 encFlag = (*address >> 25) & 0x7; + + if(ctrl > 0) + { + switch(ctrl) + { + case 2: + { + *address ^= (gsv3_hseeds[1] << 2); + *value ^= (gsv3_hseeds[1] << 13); + for(i = 0; i < 0x40; i++) + { + if(i < 32) + { + flag = (*value >> i) & 1; + } + else + { + flag = (*address >> (i - 32)) & 1; + } + + if(flag > 0) + { + if(gsv3_bseeds4[i] < 32) + { + tmp2 |= (1 << gsv3_bseeds4[i]); + } + else + { + tmp |= (1 << (gsv3_bseeds4[i] - 32)); + } + } + } + + *address = tmp ^ (gsv3_hseeds[2] << 3); + *value = tmp2 ^ gsv3_hseeds[2]; + break; + } + + case 4: + { + tmp = *address ^ (gsv3_hseeds[1] << 3); + bmask[0] = gsv3_bseeds1[(tmp >> 24) & 0xFF]; + bmask[1] = gsv3_bseeds1[(tmp >> 16) & 0xFF]; + bmask[2] = gsv3_bseeds1[(tmp >> 8) & 0xFF]; + bmask[3] = gsv3_bseeds1[tmp & 0xFF]; + tmp = (bmask[0] << 24) | (bmask[1] << 16) | (bmask[2] << 8) | bmask[3]; + *address = tmp ^ (gsv3_hseeds[2] << 16); + + tmp = *value ^ (gsv3_hseeds[1] << 9); + bmask[0] = gsv3_bseeds1[(tmp >> 24) & 0xFF]; + bmask[1] = gsv3_bseeds1[(tmp >> 16) & 0xFF]; + bmask[2] = gsv3_bseeds1[(tmp >> 8) & 0xFF]; + bmask[3] = gsv3_bseeds1[tmp & 0xFF]; + tmp = (bmask[0] << 24) | (bmask[1] << 16) | (bmask[2] << 8) | bmask[3]; + *value = tmp ^ (gsv3_hseeds[2] << 5); + break; + } + } + return 0; + } + + if(command >= 0x30000000 && command <= 0x6FFFFFFF) + { + if(encFlag == 1 || encFlag == 2) + { + ctrl = 2; + } + else if (encFlag == 3 || encFlag == 4) + { + ctrl = 4; + } + } + + switch(encFlag) + { + case 0: + { + break; + } + + case 1: + { + tmp = *address & 0x01FFFFFF; + tmp = tmp ^ (gsv3_hseeds[1] << 8); + mask = 0; + for(i = 0; i < 25; i++) + { + mask |= ((tmp & (1 << i)) >> i) << gsv3_bseeds2[i]; + } + tmp = mask ^ gsv3_hseeds[2]; + tmp |= command; + *address = tmp & 0xF1FFFFFF; + break; + } + + case 2: + { + if(encFlag == 2) + { + tmp = *address & 0x01FFFFFF; + *address = tmp ^ (gsv3_hseeds[1] << 1); + *value ^= (gsv3_hseeds[1] << 16); + tmp = 0; + tmp2 = 0; + for(i = 0; i < 0x39; i++) + { + if(i < 32) + { + flag = (*value >> i) & 1; + } + else + { + flag = (*address >> (i - 32)) & 1; + } + + if(flag > 0) + { + if(gsv3_bseeds3[i] < 32) + { + tmp2 |= (1 << gsv3_bseeds3[i]); + } + else + { + tmp |= (1 << (gsv3_bseeds3[i] - 32)); + } + } + } + *address = ((tmp ^ (gsv3_hseeds[2] << 8)) | command) & 0xF1FFFFFF; + *value = tmp2 ^ gsv3_hseeds[2]; + } + break; + } + + case 3: + { + tmp = *address ^ (gsv3_hseeds[1] << 8); + bmask[0] = gsv3_bseeds1[(tmp >> 8) & 0xFF]; + bmask[1] = gsv3_bseeds1[(tmp & 0xFF)]; + tmp = (tmp & 0xFFFF0000) ; + tmp |= (bmask[0] ^ (bmask[1] << 8)) ; + tmp ^= (gsv3_hseeds[2] << 4); + *address = tmp & 0xF1FFFFFF; + break; + } + + case 4: + { + tmp = *address ^ (gsv3_hseeds[1] << 8); + bmask[0] = gsv3_bseeds1[(tmp >> 8) & 0xFF]; + bmask[1] = gsv3_bseeds1[(tmp & 0xFF)]; + tmp = (tmp & 0xFFFF0000) ; + tmp |= (bmask[1] | (bmask[0] << 8)) ; + tmp ^= (gsv3_hseeds[2] << 4); + tmp2 = *address ^ (gsv3_hseeds[1] << 3); + *address = tmp & 0xF1FFFFFF; + tmp = *value ^ (gsv3_hseeds[1] << 9); + bmask[0] = gsv3_bseeds1[(tmp >> 24) & 0xFF]; + bmask[1] = gsv3_bseeds1[(tmp >> 16) & 0xFF]; + bmask[2] = gsv3_bseeds1[(tmp >> 8) & 0xFF]; + bmask[3] = gsv3_bseeds1[tmp & 0xFF]; + tmp = (bmask[0] << 24) | (bmask[1] << 16) | (bmask[2] << 8) | bmask[3]; + *value = tmp ^ (gsv3_hseeds[2] << 5); + break; + } + + case 5: + case 6: + case 7: + default: + break; + } + + return ctrl; + +} + +struct Cheat +{ + unsigned int address, value; +}; + +int ParseCheats(char *cur, std::vector &Cheats, HWND hWnd) +{ + // Parse the text and put the cheats to the vector + while(*cur!=NULL){ + Cheat C; + + // if there is endline advance 2 chars + if(*cur==0x0d && *(cur+1)==0x0a) + cur+=2; + // check if new start is null + if(*cur==NULL) + break; + + // get address and value and insert in the vector + int ret = sscanf(cur, "%X %X", &C.address, &C.value); + if(ret != 2) + { + MessageBox(hWnd,"Code conversion is probably wrong.","Error",0); + return 0; + } + Cheats.insert(Cheats.end(), C); + cur+=17; + } + return 1; +} + + +// Callback for the GameShark2 v3-4 cheat dialog +BOOL CALLBACK AddGS(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + int wmId,wmEvent; + static HWND hParent; + + switch(uMsg) + { + + case WM_PAINT: + return FALSE; + case WM_INITDIALOG: + hParent=(HWND)lParam; + break; + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case IDCANCEL: + EndDialog(hWnd,1); + break; + + case IDC_CONVERT: // Convert the code + { + std::vector Cheats; + char chepa[256]; + + // Set ready text to false + SetWindowText(GetDlgItem(hWnd,IDC_READY), "0"); + + // Get the text from the edit control and load it + GetWindowText(GetDlgItem(hWnd,IDC_ADDR),chepa,256); + + // Parsing the cheats + ParseCheats(chepa, Cheats, hWnd); + + int control = 0; + *chepa=0; + // Decrypt multiline code + for(unsigned int i=0;i Cheats; + char ready[2], chepa[256]; + + // Check if we are ready to add first + GetWindowText(GetDlgItem(hWnd,IDC_READY),ready,2); + if(ready[0] == '0') + { + MessageBox(hWnd, "First convert the code.", "Error", 0); + break; + } + + // Get the text from the edit control and load it + GetWindowText(GetDlgItem(hWnd,IDC_CONVERTEDCODE),chepa,256); + + // Parsing the cheats + int ret = ParseCheats(chepa, Cheats, hWnd); + + if(ret == 1) + { + // Adding cheats + for(unsigned int i=0;i Cheats; + char chepa[256]; + + // Get the text from the edit control and load it + GetWindowText(GetDlgItem(hWnd,IDC_ADDR),chepa,256); + + if(strlen(chepa) == 0) + { + MessageBox(hWnd, "Add some cheats.", "Error", 0); + break; + } + + // Parsing the cheats + int ret = ParseCheats(chepa, Cheats, hWnd); + + if(ret == 1) + { + // Adding cheats + for(unsigned int i=0;i -#include - -#include "PS2Edefs.h" -#include "Memory.h" -#include "IopMem.h" - -#include "cheats.h" -#include "../../patch.h" - -class result -{ -public: - u32 address; - result(u32 addr): - address(addr) - { - } -}; - -char *sizenames[4]={"char","short","word","double"}; - -char mtext[100]; - -HINSTANCE pInstance; - -int TSelect; - -bool Unsigned; -int Source; -int Compare; -int Size; -int CompareTo; - -u64 CompareValue; - -std::vector results; - -//int mresults; - -bool FirstSearch; - -bool FirstShow; - -char olds[Ps2MemSize::Base]; - -char tn[100]; -char to[100]; -char tv[100]; - -u8 *mptr[2]; - -int msize[2]={0x02000000,0x00200000}; - -int lticks; - -HWND hWndFinder; - -LVCOLUMN cols[3]={ - {LVCF_TEXT|LVCF_WIDTH,0,60,"Address",0,0,0}, - {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,60,"Old V",1,0,0}, - {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,60,"New V",2,0,0} -}; - -LVITEM item[3]={ - {LVIF_TEXT|LVIF_STATE,0,0,0,0,tn,0,0,0,0}, - {LVIF_TEXT|LVIF_STATE,0,1,0,0,to,0,0,0,0}, - {LVIF_TEXT|LVIF_STATE,0,2,0,0,tv,0,0,0,0} -}; - -void DoEvents() -{ - MSG msg; - while(PeekMessage(&msg,0,0,0,PM_REMOVE)!=0) - DispatchMessage(&msg); -} - -void UpdateStatus() -{ - int nticks=GetTickCount(); - if((nticks-lticks)>250) - { - int nshown=ListView_GetItemCount(GetDlgItem(hWndFinder,IDC_RESULTS)); - sprintf(mtext,"%d matches found (%d shown).",results.size(),nshown); - SetWindowText(GetDlgItem(hWndFinder,IDC_MATCHES),mtext); - lticks=nticks; - DoEvents(); - } -} - -void SearchReset() -{ - memcpy(olds,mptr[Source],msize[Source]); - FirstSearch=true; - - results.clear(); - -} - -int AddResult(u32 addr) -{ - result nr=result(addr); - results.push_back(nr); - return 1; -} - -bool CompareAny(u64 val,u64 cto) -{ - - if(Unsigned) - { - switch(Size) - { - case 0: - val=(u8)val; - cto=(u8)cto; - break; - case 1: - val=(u16)val; - cto=(u16)cto; - break; - case 2: - val=(u32)val; - cto=(u32)cto; - break; - case 3: - break; - default:return false; - } - switch(Compare) - { - case 0: /* EQ */ - return val==cto; - case 1: /* GT */ - return val> cto; - case 2: /* LT */ - return val< cto; - case 3: /* GE */ - return val>=cto; - case 4: /* LE */ - return val<=cto; - default:/* NE */ - return val!=cto; - } - } - else - { - switch(Size) - { - case 0: - val=(s8)val; - cto=(s8)cto; - break; - case 1: - val=(s16)val; - cto=(s16)cto; - break; - case 2: - val=(s32)val; - cto=(s32)cto; - break; - case 3: - break; - default:return false; - } - switch(Compare) - { - case 0: /* EQ */ - return (s64)val==(s64)cto; - case 1: /* GT */ - return (s64)val> (s64)cto; - case 2: /* LT */ - return (s64)val< (s64)cto; - case 3: /* GE */ - return (s64)val>=(s64)cto; - case 4: /* LE */ - return (s64)val<=(s64)cto; - default:/* NE */ - return (s64)val!=(s64)cto; - } - } -} - -void SearchFirst() -{ - int MSize=1< oldr=std::vector(results); - - results.clear(); - - for(i=0;i", - Source?"IOP":"EE", - tn, - sizenames[Size]); - - SetWindowText(GetDlgItem(hWnd,IDC_ADDR),tn); - SetWindowText(GetDlgItem(hWnd,IDC_VALUE),tv); - SetWindowText(GetDlgItem(hWnd,IDC_NAME),to); - - break; - } - } - - - break; - case WM_COMMAND: - wmId = LOWORD(wParam); - wmEvent = HIWORD(wParam); - // Parse the menu selections: - switch (wmId) - { - case IDCANCEL: - EndDialog(hWnd,1); - break; - - case IDOK: - GetWindowText(GetDlgItem(hWnd,IDC_VALUE),tv,100); - value=_atoi64(tv); - AddPatch(1,Source+1,results[Selected].address,Size+1,value); - - EndDialog(hWnd,1); - break; - - - default: - return FALSE; - } - break; - default: - return FALSE; - } - return TRUE; -} - -void AddCheat(HINSTANCE hInstance, HWND hParent) -{ - INT_PTR retret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_ADD),hParent,(DLGPROC)AddCheatProc,(LPARAM)hParent); -} - -void AddResults(HWND hWnd) -{ - int i,mresults; - u64 sizemask=(1<<(1<32768) { - mresults=32768; - } - - ListView_DeleteAllItems(GetDlgItem(hWnd,IDC_RESULTS)); - - for(i=0;i32768) { - sprintf(mtext,"%d matches found (32768 shown).",results.size()); - SetWindowText(GetDlgItem(hWnd,IDC_MATCHES),mtext); - } - else { - sprintf(mtext,"%d matches found.",results.size()); - SetWindowText(GetDlgItem(hWnd,IDC_MATCHES),mtext); - } - -} - -BOOL CALLBACK FinderProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) -{ - int wmId,wmEvent; - LRESULT lStyle; - - switch(uMsg) - { - - case WM_PAINT: - INIT_CHECK(IDC_UNSIGNED,Unsigned); - return FALSE; - - case WM_INITDIALOG: - mptr[0]=psM; - mptr[1]=psxM; - - hWndFinder=hWnd; - - ENABLE_CONTROL(IDC_VALUE,false); - - GROUP_INIT(IDC_EE,Source); - GROUP_SELECT(IDC_EE); - GROUP_SELECT(IDC_IOP); - - GROUP_INIT(IDC_OLD,CompareTo); - GROUP_SELECT(IDC_OLD); - GROUP_SELECT(IDC_SET); - ENABLE_CONTROL(IDC_VALUE,(CompareTo!=0)); - - GROUP_INIT(IDC_EQ,Compare); - GROUP_SELECT(IDC_EQ); - GROUP_SELECT(IDC_GT); - GROUP_SELECT(IDC_LT); - GROUP_SELECT(IDC_GE); - GROUP_SELECT(IDC_LE); - GROUP_SELECT(IDC_NE); - - GROUP_INIT(IDC_8B,Size); - GROUP_SELECT(IDC_8B); - GROUP_SELECT(IDC_16B); - GROUP_SELECT(IDC_32B); - GROUP_SELECT(IDC_64B); - - INIT_CHECK(IDC_UNSIGNED,Unsigned); - - //Listview Init - lStyle = SendMessage(GetDlgItem(hWnd,IDC_RESULTS), LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); - SendMessage(GetDlgItem(hWnd,IDC_RESULTS), LVM_SETEXTENDEDLISTVIEWSTYLE, 0, lStyle | LVS_EX_FULLROWSELECT); - - ListView_InsertColumn(GetDlgItem(hWnd,IDC_RESULTS),0,&cols[0]); - ListView_InsertColumn(GetDlgItem(hWnd,IDC_RESULTS),1,&cols[1]); - ListView_InsertColumn(GetDlgItem(hWnd,IDC_RESULTS),2,&cols[2]); - - if(FirstShow) - { - SearchReset(); - SetWindowText(GetDlgItem(hWnd,IDC_MATCHES),"ready to search."); - FirstShow=false; - } - else { - AddResults(hWnd); - } - - break; - case WM_COMMAND: - wmId = LOWORD(wParam); - wmEvent = HIWORD(wParam); - // Parse the menu selections: - switch (wmId) - { - case IDCANCEL: - EndDialog(hWnd,1); - break; - - case IDC_ADD: - AddCheat(pInstance,hWnd); - break; - - case IDC_RESET: - ENABLE_CONTROL(IDC_EE, true); - ENABLE_CONTROL(IDC_IOP, true); - ENABLE_CONTROL(IDC_STATUS, true); - ENABLE_CONTROL(IDC_UNSIGNED,true); - ENABLE_CONTROL(IDC_8B, true); - ENABLE_CONTROL(IDC_16B, true); - ENABLE_CONTROL(IDC_32B, true); - ENABLE_CONTROL(IDC_64B, true); - SetWindowText(GetDlgItem(hWnd,IDC_MATCHES),"ready to search."); - SearchReset(); - ListView_DeleteAllItems(GetDlgItem(hWnd,IDC_RESULTS)); - break; - - case IDC_SEARCH: - GetWindowText(GetDlgItem(hWnd,IDC_VALUE),mtext,100); - CompareValue=atoi(mtext); - ENABLE_CONTROL(IDC_SEARCH, false); - ENABLE_CONTROL(IDC_RESET, false); - ENABLE_CONTROL(IDC_ADD, false); - ENABLE_CONTROL(IDCANCEL, false); - if(FirstSearch) { - ENABLE_CONTROL(IDC_EE, false); - ENABLE_CONTROL(IDC_IOP, false); - ENABLE_CONTROL(IDC_STATUS, false); - ENABLE_CONTROL(IDC_UNSIGNED,false); - ENABLE_CONTROL(IDC_8B, false); - ENABLE_CONTROL(IDC_16B, false); - ENABLE_CONTROL(IDC_32B, false); - ENABLE_CONTROL(IDC_64B, false); - SearchFirst(); - } - else SearchMore(); - - AddResults(hWnd); - - memcpy(olds,mptr[Source],msize[Source]); - - ENABLE_CONTROL(IDC_SEARCH, true); - ENABLE_CONTROL(IDC_RESET, true); - ENABLE_CONTROL(IDC_ADD, true); - ENABLE_CONTROL(IDCANCEL, true); - - break; - - HANDLE_CHECK(IDC_UNSIGNED,Unsigned); - - HANDLE_GROUP_ITEM(IDC_EE); - HANDLE_GROUP_ITEM(IDC_IOP); - BEGIN_GROUP_HANDLER(IDC_EE,Source); - GROUP_SELECT(IDC_EE); - GROUP_SELECT(IDC_IOP); - break; - - HANDLE_GROUP_ITEM(IDC_OLD); - HANDLE_GROUP_ITEM(IDC_SET); - BEGIN_GROUP_HANDLER(IDC_OLD,CompareTo); - GROUP_SELECT(IDC_OLD); - GROUP_SELECT(IDC_SET); - ENABLE_CONTROL(IDC_VALUE,(CompareTo!=0)); - break; - - HANDLE_GROUP_ITEM(IDC_EQ); - HANDLE_GROUP_ITEM(IDC_GT); - HANDLE_GROUP_ITEM(IDC_LT); - HANDLE_GROUP_ITEM(IDC_GE); - HANDLE_GROUP_ITEM(IDC_LE); - HANDLE_GROUP_ITEM(IDC_NE); - BEGIN_GROUP_HANDLER(IDC_EQ,Compare); - GROUP_SELECT(IDC_EQ); - GROUP_SELECT(IDC_GT); - GROUP_SELECT(IDC_LT); - GROUP_SELECT(IDC_GE); - GROUP_SELECT(IDC_LE); - GROUP_SELECT(IDC_NE); - break; - - HANDLE_GROUP_ITEM(IDC_8B); - HANDLE_GROUP_ITEM(IDC_16B); - HANDLE_GROUP_ITEM(IDC_32B); - HANDLE_GROUP_ITEM(IDC_64B); - BEGIN_GROUP_HANDLER(IDC_8B,Size); - GROUP_SELECT(IDC_8B); - GROUP_SELECT(IDC_16B); - GROUP_SELECT(IDC_32B); - GROUP_SELECT(IDC_64B); - break; - - default: - return FALSE; - } - break; - default: - return FALSE; - } - return TRUE; -} - -void ShowFinder(HINSTANCE hInstance, HWND hParent) -{ - INT_PTR ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_FINDER),hParent,(DLGPROC)FinderProc,1); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" +#include "../Win32.h" + +#include +#include + +#include "PS2Edefs.h" +#include "Memory.h" +#include "IopMem.h" + +#include "cheats.h" +#include "../../patch.h" + +class result +{ +public: + u32 address; + result(u32 addr): + address(addr) + { + } +}; + +char *sizenames[4]={"char","short","word","double"}; + +char mtext[100]; + +HINSTANCE pInstance; + +int TSelect; + +bool Unsigned; +int Source; +int Compare; +int Size; +int CompareTo; + +u64 CompareValue; + +std::vector results; + +//int mresults; + +bool FirstSearch; + +bool FirstShow; + +char olds[Ps2MemSize::Base]; + +char tn[100]; +char to[100]; +char tv[100]; + +u8 *mptr[2]; + +int msize[2]={0x02000000,0x00200000}; + +int lticks; + +HWND hWndFinder; + +LVCOLUMN cols[3]={ + {LVCF_TEXT|LVCF_WIDTH,0,60,"Address",0,0,0}, + {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,60,"Old V",1,0,0}, + {LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM,0,60,"New V",2,0,0} +}; + +LVITEM item[3]={ + {LVIF_TEXT|LVIF_STATE,0,0,0,0,tn,0,0,0,0}, + {LVIF_TEXT|LVIF_STATE,0,1,0,0,to,0,0,0,0}, + {LVIF_TEXT|LVIF_STATE,0,2,0,0,tv,0,0,0,0} +}; + +void DoEvents() +{ + MSG msg; + while(PeekMessage(&msg,0,0,0,PM_REMOVE)!=0) + DispatchMessage(&msg); +} + +void UpdateStatus() +{ + int nticks=GetTickCount(); + if((nticks-lticks)>250) + { + int nshown=ListView_GetItemCount(GetDlgItem(hWndFinder,IDC_RESULTS)); + sprintf(mtext,"%d matches found (%d shown).",results.size(),nshown); + SetWindowText(GetDlgItem(hWndFinder,IDC_MATCHES),mtext); + lticks=nticks; + DoEvents(); + } +} + +void SearchReset() +{ + memcpy(olds,mptr[Source],msize[Source]); + FirstSearch=true; + + results.clear(); + +} + +int AddResult(u32 addr) +{ + result nr=result(addr); + results.push_back(nr); + return 1; +} + +bool CompareAny(u64 val,u64 cto) +{ + + if(Unsigned) + { + switch(Size) + { + case 0: + val=(u8)val; + cto=(u8)cto; + break; + case 1: + val=(u16)val; + cto=(u16)cto; + break; + case 2: + val=(u32)val; + cto=(u32)cto; + break; + case 3: + break; + default:return false; + } + switch(Compare) + { + case 0: /* EQ */ + return val==cto; + case 1: /* GT */ + return val> cto; + case 2: /* LT */ + return val< cto; + case 3: /* GE */ + return val>=cto; + case 4: /* LE */ + return val<=cto; + default:/* NE */ + return val!=cto; + } + } + else + { + switch(Size) + { + case 0: + val=(s8)val; + cto=(s8)cto; + break; + case 1: + val=(s16)val; + cto=(s16)cto; + break; + case 2: + val=(s32)val; + cto=(s32)cto; + break; + case 3: + break; + default:return false; + } + switch(Compare) + { + case 0: /* EQ */ + return (s64)val==(s64)cto; + case 1: /* GT */ + return (s64)val> (s64)cto; + case 2: /* LT */ + return (s64)val< (s64)cto; + case 3: /* GE */ + return (s64)val>=(s64)cto; + case 4: /* LE */ + return (s64)val<=(s64)cto; + default:/* NE */ + return (s64)val!=(s64)cto; + } + } +} + +void SearchFirst() +{ + int MSize=1< oldr=std::vector(results); + + results.clear(); + + for(i=0;i", + Source?"IOP":"EE", + tn, + sizenames[Size]); + + SetWindowText(GetDlgItem(hWnd,IDC_ADDR),tn); + SetWindowText(GetDlgItem(hWnd,IDC_VALUE),tv); + SetWindowText(GetDlgItem(hWnd,IDC_NAME),to); + + break; + } + } + + + break; + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case IDCANCEL: + EndDialog(hWnd,1); + break; + + case IDOK: + GetWindowText(GetDlgItem(hWnd,IDC_VALUE),tv,100); + value=_atoi64(tv); + AddPatch(1,Source+1,results[Selected].address,Size+1,value); + + EndDialog(hWnd,1); + break; + + + default: + return FALSE; + } + break; + default: + return FALSE; + } + return TRUE; +} + +void AddCheat(HINSTANCE hInstance, HWND hParent) +{ + INT_PTR retret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_ADD),hParent,(DLGPROC)AddCheatProc,(LPARAM)hParent); +} + +void AddResults(HWND hWnd) +{ + int i,mresults; + u64 sizemask=(1<<(1<32768) { + mresults=32768; + } + + ListView_DeleteAllItems(GetDlgItem(hWnd,IDC_RESULTS)); + + for(i=0;i32768) { + sprintf(mtext,"%d matches found (32768 shown).",results.size()); + SetWindowText(GetDlgItem(hWnd,IDC_MATCHES),mtext); + } + else { + sprintf(mtext,"%d matches found.",results.size()); + SetWindowText(GetDlgItem(hWnd,IDC_MATCHES),mtext); + } + +} + +BOOL CALLBACK FinderProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + int wmId,wmEvent; + LRESULT lStyle; + + switch(uMsg) + { + + case WM_PAINT: + INIT_CHECK(IDC_UNSIGNED,Unsigned); + return FALSE; + + case WM_INITDIALOG: + mptr[0]=psM; + mptr[1]=psxM; + + hWndFinder=hWnd; + + ENABLE_CONTROL(IDC_VALUE,false); + + GROUP_INIT(IDC_EE,Source); + GROUP_SELECT(IDC_EE); + GROUP_SELECT(IDC_IOP); + + GROUP_INIT(IDC_OLD,CompareTo); + GROUP_SELECT(IDC_OLD); + GROUP_SELECT(IDC_SET); + ENABLE_CONTROL(IDC_VALUE,(CompareTo!=0)); + + GROUP_INIT(IDC_EQ,Compare); + GROUP_SELECT(IDC_EQ); + GROUP_SELECT(IDC_GT); + GROUP_SELECT(IDC_LT); + GROUP_SELECT(IDC_GE); + GROUP_SELECT(IDC_LE); + GROUP_SELECT(IDC_NE); + + GROUP_INIT(IDC_8B,Size); + GROUP_SELECT(IDC_8B); + GROUP_SELECT(IDC_16B); + GROUP_SELECT(IDC_32B); + GROUP_SELECT(IDC_64B); + + INIT_CHECK(IDC_UNSIGNED,Unsigned); + + //Listview Init + lStyle = SendMessage(GetDlgItem(hWnd,IDC_RESULTS), LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); + SendMessage(GetDlgItem(hWnd,IDC_RESULTS), LVM_SETEXTENDEDLISTVIEWSTYLE, 0, lStyle | LVS_EX_FULLROWSELECT); + + ListView_InsertColumn(GetDlgItem(hWnd,IDC_RESULTS),0,&cols[0]); + ListView_InsertColumn(GetDlgItem(hWnd,IDC_RESULTS),1,&cols[1]); + ListView_InsertColumn(GetDlgItem(hWnd,IDC_RESULTS),2,&cols[2]); + + if(FirstShow) + { + SearchReset(); + SetWindowText(GetDlgItem(hWnd,IDC_MATCHES),"ready to search."); + FirstShow=false; + } + else { + AddResults(hWnd); + } + + break; + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case IDCANCEL: + EndDialog(hWnd,1); + break; + + case IDC_ADD: + AddCheat(pInstance,hWnd); + break; + + case IDC_RESET: + ENABLE_CONTROL(IDC_EE, true); + ENABLE_CONTROL(IDC_IOP, true); + ENABLE_CONTROL(IDC_STATUS, true); + ENABLE_CONTROL(IDC_UNSIGNED,true); + ENABLE_CONTROL(IDC_8B, true); + ENABLE_CONTROL(IDC_16B, true); + ENABLE_CONTROL(IDC_32B, true); + ENABLE_CONTROL(IDC_64B, true); + SetWindowText(GetDlgItem(hWnd,IDC_MATCHES),"ready to search."); + SearchReset(); + ListView_DeleteAllItems(GetDlgItem(hWnd,IDC_RESULTS)); + break; + + case IDC_SEARCH: + GetWindowText(GetDlgItem(hWnd,IDC_VALUE),mtext,100); + CompareValue=atoi(mtext); + ENABLE_CONTROL(IDC_SEARCH, false); + ENABLE_CONTROL(IDC_RESET, false); + ENABLE_CONTROL(IDC_ADD, false); + ENABLE_CONTROL(IDCANCEL, false); + if(FirstSearch) { + ENABLE_CONTROL(IDC_EE, false); + ENABLE_CONTROL(IDC_IOP, false); + ENABLE_CONTROL(IDC_STATUS, false); + ENABLE_CONTROL(IDC_UNSIGNED,false); + ENABLE_CONTROL(IDC_8B, false); + ENABLE_CONTROL(IDC_16B, false); + ENABLE_CONTROL(IDC_32B, false); + ENABLE_CONTROL(IDC_64B, false); + SearchFirst(); + } + else SearchMore(); + + AddResults(hWnd); + + memcpy(olds,mptr[Source],msize[Source]); + + ENABLE_CONTROL(IDC_SEARCH, true); + ENABLE_CONTROL(IDC_RESET, true); + ENABLE_CONTROL(IDC_ADD, true); + ENABLE_CONTROL(IDCANCEL, true); + + break; + + HANDLE_CHECK(IDC_UNSIGNED,Unsigned); + + HANDLE_GROUP_ITEM(IDC_EE); + HANDLE_GROUP_ITEM(IDC_IOP); + BEGIN_GROUP_HANDLER(IDC_EE,Source); + GROUP_SELECT(IDC_EE); + GROUP_SELECT(IDC_IOP); + break; + + HANDLE_GROUP_ITEM(IDC_OLD); + HANDLE_GROUP_ITEM(IDC_SET); + BEGIN_GROUP_HANDLER(IDC_OLD,CompareTo); + GROUP_SELECT(IDC_OLD); + GROUP_SELECT(IDC_SET); + ENABLE_CONTROL(IDC_VALUE,(CompareTo!=0)); + break; + + HANDLE_GROUP_ITEM(IDC_EQ); + HANDLE_GROUP_ITEM(IDC_GT); + HANDLE_GROUP_ITEM(IDC_LT); + HANDLE_GROUP_ITEM(IDC_GE); + HANDLE_GROUP_ITEM(IDC_LE); + HANDLE_GROUP_ITEM(IDC_NE); + BEGIN_GROUP_HANDLER(IDC_EQ,Compare); + GROUP_SELECT(IDC_EQ); + GROUP_SELECT(IDC_GT); + GROUP_SELECT(IDC_LT); + GROUP_SELECT(IDC_GE); + GROUP_SELECT(IDC_LE); + GROUP_SELECT(IDC_NE); + break; + + HANDLE_GROUP_ITEM(IDC_8B); + HANDLE_GROUP_ITEM(IDC_16B); + HANDLE_GROUP_ITEM(IDC_32B); + HANDLE_GROUP_ITEM(IDC_64B); + BEGIN_GROUP_HANDLER(IDC_8B,Size); + GROUP_SELECT(IDC_8B); + GROUP_SELECT(IDC_16B); + GROUP_SELECT(IDC_32B); + GROUP_SELECT(IDC_64B); + break; + + default: + return FALSE; + } + break; + default: + return FALSE; + } + return TRUE; +} + +void ShowFinder(HINSTANCE hInstance, HWND hParent) +{ + INT_PTR ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_FINDER),hParent,(DLGPROC)FinderProc,1); +} diff --git a/pcsx2/windows/cheats/cheats.h b/pcsx2/windows/cheats/cheats.h index edc5a9641e..a5dcda8ddb 100644 --- a/pcsx2/windows/cheats/cheats.h +++ b/pcsx2/windows/cheats/cheats.h @@ -1,39 +1,39 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef CHEATS_H_INCLUDED -#define CHEATS_H_INCLUDED - -#ifndef __cplusplus -//typedef enum ebool -//{ -// false, -// true -//} bool; -#define bool unsigned __int8 -#define false 0 -#define true 1 -#endif - -extern HINSTANCE pInstance; -extern bool FirstShow; - -void AddCheat(HINSTANCE hInstance, HWND hParent); -void ShowFinder(HINSTANCE hInstance, HWND hParent); -void ShowCheats(HINSTANCE hInstance, HWND hParent); - -#endif//CHEATS_H_INCLUDED +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef CHEATS_H_INCLUDED +#define CHEATS_H_INCLUDED + +#ifndef __cplusplus +//typedef enum ebool +//{ +// false, +// true +//} bool; +#define bool unsigned __int8 +#define false 0 +#define true 1 +#endif + +extern HINSTANCE pInstance; +extern bool FirstShow; + +void AddCheat(HINSTANCE hInstance, HWND hParent); +void ShowFinder(HINSTANCE hInstance, HWND hParent); +void ShowCheats(HINSTANCE hInstance, HWND hParent); + +#endif//CHEATS_H_INCLUDED diff --git a/pcsx2/windows/ini.cpp b/pcsx2/windows/ini.cpp index 52c82cb160..137ec6a4b1 100644 --- a/pcsx2/windows/ini.cpp +++ b/pcsx2/windows/ini.cpp @@ -1,346 +1,346 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2003 Pcsx2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "PrecompiledHeader.h" -#include "win32.h" - -#include "Common.h" -#include "Paths.h" - -static const u32 IniVersion = 100; - -const char* g_CustomConfigFile; -char g_WorkingFolder[g_MaxPath]; // Working folder at application startup - -// Returns TRUE if the user has invoked the -cfg command line option. -static bool hasCustomConfig() -{ - return (g_CustomConfigFile != NULL) && (g_CustomConfigFile[0] != 0); -} - -// Returns the FULL (absolute) path and filename of the configuration file. -static void GetConfigFilename( string& dest ) -{ - if( hasCustomConfig() ) - { - // Load a user-specified configuration. - // If the configuration isn't found, fail outright (see below) - - Path::Combine( dest, g_WorkingFolder, g_CustomConfigFile ); - } - else - { - // use the ini relative to the application's working directory. - // Our current working directory can change, so we use the one we detected - // at startup: - - Path::Combine( dest, g_WorkingFolder, CONFIG_DIR "\\pcsx2.ini" ); - } -} - -class IniFile -{ -protected: - string m_filename; - string m_section; - -public: - virtual ~IniFile() {} - IniFile() : m_filename(), m_section("Misc") - { - GetConfigFilename( m_filename ); - } - - void SetCurrentSection( const string& newsection ) - { - m_section = newsection; - } - - virtual void Entry( const string& var, string& value, const string& defvalue=string() )=0; - virtual void Entry( const string& var, char (&value)[g_MaxPath], const string& defvalue=string() )=0; - virtual void Entry( const string& var, int& value, const int defvalue=0 )=0; - virtual void Entry( const string& var, uint& value, const uint defvalue=0 )=0; - virtual void Entry( const string& var, bool& value, const bool defvalue=0 )=0; - virtual void EnumEntry( const string& var, int& value, const char* const* enumArray, const int defvalue=0 )=0; - - void DoConfig( PcsxConfig& Conf ) - { - SetCurrentSection( "Misc" ); - - Entry( "Patching", Conf.Patch, false ); - Entry( "GameFixes", Conf.GameFixes); -#ifdef PCSX2_DEVBUILD - Entry( "DevLogFlags", varLog ); -#endif - - //interface - SetCurrentSection( "Interface" ); - Entry( "Bios", Conf.Bios ); - Entry( "Language", Conf.Lang ); - Entry( "PluginsDir", Conf.PluginsDir, DEFAULT_PLUGINS_DIR ); - Entry( "BiosDir", Conf.BiosDir, DEFAULT_BIOS_DIR ); - Entry( "CloseGsOnEscape", Conf.closeGSonEsc, true ); - - SetCurrentSection( "Console" ); - Entry( "ConsoleWindow", Conf.PsxOut, true ); - Entry( "Profiler", Conf.Profiler, false ); - Entry( "CdvdVerbose", Conf.cdvdPrint, false ); - - Entry( "ThreadPriority", Conf.ThPriority, THREAD_PRIORITY_NORMAL ); - Entry( "Memorycard1", Conf.Mcd1, MEMCARDS_DIR "\\" DEFAULT_MEMCARD1 ); - Entry( "Memorycard2", Conf.Mcd2, MEMCARDS_DIR "\\" DEFAULT_MEMCARD2 ); - - SetCurrentSection( "Framelimiter" ); - Entry( "CustomFps", Conf.CustomFps ); - Entry( "FrameskipMode", Conf.CustomFrameSkip ); - Entry( "ConsecutiveFramesToRender", Conf.CustomConsecutiveFrames ); - Entry( "ConsecutiveFramesToSkip", Conf.CustomConsecutiveSkip ); - - // Plugins are saved from the winConfig struct. - // It contains the user config settings and not the - // runtime cmdline overrides. - - SetCurrentSection( "Plugins" ); - - Entry( "GS", Conf.GS ); - Entry( "SPU2", Conf.SPU2 ); - Entry( "CDVD", Conf.CDVD ); - Entry( "PAD1", Conf.PAD1 ); - Entry( "PAD2", Conf.PAD2 ); - Entry( "DEV9", Conf.DEV9 ); - Entry( "USB", Conf.USB ); - Entry( "FW", Conf.FW ); - - //cpu - SetCurrentSection( "Cpu" ); - Entry( "Options", Conf.Options, PCSX2_EEREC|PCSX2_VU0REC|PCSX2_VU1REC|PCSX2_GSMULTITHREAD|PCSX2_FRAMELIMIT_LIMIT ); - Entry( "sseMXCSR", Conf.sseMXCSR, DEFAULT_sseMXCSR ); - Entry( "sseVUMXCSR", Conf.sseVUMXCSR, DEFAULT_sseVUMXCSR ); - Entry( "eeOptions", Conf.eeOptions, DEFAULT_eeOptions ); - Entry( "vuOptions", Conf.vuOptions, DEFAULT_vuOptions ); - Entry( "SpeedHacks", Conf.Hacks ); - } -}; - -class IniFileLoader : public IniFile -{ -protected: - MemoryAlloc m_workspace; - -public: - virtual ~IniFileLoader() {} - IniFileLoader() : IniFile(), - m_workspace( 4096, "IniFileLoader Workspace" ) - { - } - - void Entry( const string& var, string& value, const string& defvalue=string() ) - { - int retval = GetPrivateProfileString( - m_section.c_str(), var.c_str(), defvalue.c_str(), m_workspace.GetPtr(), m_workspace.GetLength(), m_filename.c_str() - ); - - if( retval >= m_workspace.GetLength() - 2 ) - Console::Notice( "Loadini Warning > Possible truncated value on key '%hs'", params &var ); - value = m_workspace.GetPtr(); - } - - void Entry( const string& var, char (&value)[g_MaxPath], const string& defvalue=string() ) - { - int retval = GetPrivateProfileString( - m_section.c_str(), var.c_str(), defvalue.c_str(), value, sizeof( value ), m_filename.c_str() - ); - - if( retval >= sizeof(value) - 2 ) - Console::Notice( "Loadini Warning > Possible truncated value on key '%hs'", params &var ); - } - - void Entry( const string& var, int& value, const int defvalue=0 ) - { - string retval; - Entry( var, retval, to_string( defvalue ) ); - value = atoi( retval.c_str() ); - } - - void Entry( const string& var, uint& value, const uint defvalue=0 ) - { - string retval; - Entry( var, retval, to_string( defvalue ) ); - value = atoi( retval.c_str() ); - } - - void Entry( const string& var, bool& value, const bool defvalue=false ) - { - string retval; - Entry( var, retval, defvalue ? "enabled" : "disabled" ); - value = (retval == "enabled"); - } - - void EnumEntry( const string& var, int& value, const char* const* enumArray, const int defvalue=0 ) - { - string retval; - Entry( var, retval, enumArray[defvalue] ); - - int i=0; - while( enumArray[i] != NULL && ( retval != enumArray[i] ) ) i++; - - if( enumArray[i] == NULL ) - { - Console::Notice( "Loadini Warning > Unrecognized value '%hs' on key '%hs'\n\tUsing the default setting of '%s'.", - params &retval, &var, enumArray[defvalue] ); - value = defvalue; - } - else - value = i; - } - -}; - -class IniFileSaver : public IniFile -{ -public: - virtual ~IniFileSaver() {} - IniFileSaver() : IniFile() - { - char versionStr[20]; - _itoa( IniVersion, versionStr, 10 ); - WritePrivateProfileString( "Misc", "IniVersion", versionStr, m_filename.c_str() ); - } - - void Entry( const string& var, const string& value, const string& defvalue=string() ) - { - WritePrivateProfileString( m_section.c_str(), var.c_str(), value.c_str(), m_filename.c_str() ); - } - - void Entry( const string& var, string& value, const string& defvalue=string() ) - { - WritePrivateProfileString( m_section.c_str(), var.c_str(), value.c_str(), m_filename.c_str() ); - } - - void Entry( const string& var, char (&value)[g_MaxPath], const string& defvalue=string() ) - { - WritePrivateProfileString( m_section.c_str(), var.c_str(), value, m_filename.c_str() ); - } - - void Entry( const string& var, int& value, const int defvalue=0 ) - { - Entry( var, to_string( value ) ); - } - - void Entry( const string& var, uint& value, const uint defvalue=0 ) - { - Entry( var, to_string( value ) ); - } - - void Entry( const string& var, bool& value, const bool defvalue=false ) - { - Entry( var, value ? "enabled" : "disabled" ); - } - - void EnumEntry( const string& var, int& value, const char* const* enumArray, const int defvalue=0 ) - { - Entry( var, enumArray[value] ); - } -}; - -bool LoadConfig() -{ - string szIniFile; - bool status = true; - - GetConfigFilename( szIniFile ); - - if( !Path::Exists( szIniFile ) ) - { - if( hasCustomConfig() ) - { - // using custom config, so fail outright: - throw Exception::FileNotFound( - "User-specified configuration file not found:\n\t%s\n\nPCSX2 will now exit." - ); - } - - // standard mode operation. Create the directory. - CreateDirectory( "inis", NULL ); - status = false; // inform caller that we're not configured. - } - else - { - // sanity check to make sure the user doesn't have some kind of - // crazy ass setup... why not! - - if( Path::isDirectory( szIniFile ) ) - throw Exception::Stream( - "Cannot open or create the Pcsx2 ini file because a directory of\n" - "the same name already exists! Please delete it or reinstall Pcsx2\n" - "fresh and try again." - ); - - // Ini Version check! ----> - // If the user's ini is old, give them a friendly warning that says they should - // probably delete it. - - char versionStr[20]; - u32 version; - - GetPrivateProfileString( "Misc", "IniVersion", NULL, versionStr, 20, szIniFile.c_str() ); - version = atoi( versionStr ); - if( version < IniVersion ) - { - // Warn the user of a version mismatch. - Msgbox::Alert( - "Configuration versions do not match. Pcsx2 may be unstable.\n" - "If you experience problems, delete the pcsx2-pg.ini file from the ini dir." - ); - - // save the new version -- gets rid of the warning on subsequent startups - _itoa( IniVersion, versionStr, 10 ); - WritePrivateProfileString( "Misc", "IniVersion", versionStr, szIniFile.c_str() ); - } - } - - IniFileLoader().DoConfig( Config ); - -#ifdef ENABLE_NLS - { - string text; - extern int _nl_msg_cat_cntr; - ssprintf(text, "LANGUAGE=%s", Config.Lang); - gettext_putenv(text.c_str()); - } -#endif - - return status; -} - -void SaveConfig() -{ - PcsxConfig tmpConf = Config; - - strcpy( tmpConf.GS, winConfig.GS ); - strcpy( tmpConf.SPU2, winConfig.SPU2 ); - strcpy( tmpConf.CDVD, winConfig.CDVD ); - strcpy( tmpConf.PAD1, winConfig.PAD1 ); - strcpy( tmpConf.PAD2, winConfig.PAD2 ); - strcpy( tmpConf.DEV9, winConfig.DEV9 ); - strcpy( tmpConf.USB, winConfig.USB ); - strcpy( tmpConf.FW, winConfig.FW ); - - IniFileSaver().DoConfig( tmpConf ); -} - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2003 Pcsx2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "PrecompiledHeader.h" +#include "win32.h" + +#include "Common.h" +#include "Paths.h" + +static const u32 IniVersion = 100; + +const char* g_CustomConfigFile; +char g_WorkingFolder[g_MaxPath]; // Working folder at application startup + +// Returns TRUE if the user has invoked the -cfg command line option. +static bool hasCustomConfig() +{ + return (g_CustomConfigFile != NULL) && (g_CustomConfigFile[0] != 0); +} + +// Returns the FULL (absolute) path and filename of the configuration file. +static void GetConfigFilename( string& dest ) +{ + if( hasCustomConfig() ) + { + // Load a user-specified configuration. + // If the configuration isn't found, fail outright (see below) + + Path::Combine( dest, g_WorkingFolder, g_CustomConfigFile ); + } + else + { + // use the ini relative to the application's working directory. + // Our current working directory can change, so we use the one we detected + // at startup: + + Path::Combine( dest, g_WorkingFolder, CONFIG_DIR "\\pcsx2.ini" ); + } +} + +class IniFile +{ +protected: + string m_filename; + string m_section; + +public: + virtual ~IniFile() {} + IniFile() : m_filename(), m_section("Misc") + { + GetConfigFilename( m_filename ); + } + + void SetCurrentSection( const string& newsection ) + { + m_section = newsection; + } + + virtual void Entry( const string& var, string& value, const string& defvalue=string() )=0; + virtual void Entry( const string& var, char (&value)[g_MaxPath], const string& defvalue=string() )=0; + virtual void Entry( const string& var, int& value, const int defvalue=0 )=0; + virtual void Entry( const string& var, uint& value, const uint defvalue=0 )=0; + virtual void Entry( const string& var, bool& value, const bool defvalue=0 )=0; + virtual void EnumEntry( const string& var, int& value, const char* const* enumArray, const int defvalue=0 )=0; + + void DoConfig( PcsxConfig& Conf ) + { + SetCurrentSection( "Misc" ); + + Entry( "Patching", Conf.Patch, false ); + Entry( "GameFixes", Conf.GameFixes); +#ifdef PCSX2_DEVBUILD + Entry( "DevLogFlags", varLog ); +#endif + + //interface + SetCurrentSection( "Interface" ); + Entry( "Bios", Conf.Bios ); + Entry( "Language", Conf.Lang ); + Entry( "PluginsDir", Conf.PluginsDir, DEFAULT_PLUGINS_DIR ); + Entry( "BiosDir", Conf.BiosDir, DEFAULT_BIOS_DIR ); + Entry( "CloseGsOnEscape", Conf.closeGSonEsc, true ); + + SetCurrentSection( "Console" ); + Entry( "ConsoleWindow", Conf.PsxOut, true ); + Entry( "Profiler", Conf.Profiler, false ); + Entry( "CdvdVerbose", Conf.cdvdPrint, false ); + + Entry( "ThreadPriority", Conf.ThPriority, THREAD_PRIORITY_NORMAL ); + Entry( "Memorycard1", Conf.Mcd1, MEMCARDS_DIR "\\" DEFAULT_MEMCARD1 ); + Entry( "Memorycard2", Conf.Mcd2, MEMCARDS_DIR "\\" DEFAULT_MEMCARD2 ); + + SetCurrentSection( "Framelimiter" ); + Entry( "CustomFps", Conf.CustomFps ); + Entry( "FrameskipMode", Conf.CustomFrameSkip ); + Entry( "ConsecutiveFramesToRender", Conf.CustomConsecutiveFrames ); + Entry( "ConsecutiveFramesToSkip", Conf.CustomConsecutiveSkip ); + + // Plugins are saved from the winConfig struct. + // It contains the user config settings and not the + // runtime cmdline overrides. + + SetCurrentSection( "Plugins" ); + + Entry( "GS", Conf.GS ); + Entry( "SPU2", Conf.SPU2 ); + Entry( "CDVD", Conf.CDVD ); + Entry( "PAD1", Conf.PAD1 ); + Entry( "PAD2", Conf.PAD2 ); + Entry( "DEV9", Conf.DEV9 ); + Entry( "USB", Conf.USB ); + Entry( "FW", Conf.FW ); + + //cpu + SetCurrentSection( "Cpu" ); + Entry( "Options", Conf.Options, PCSX2_EEREC|PCSX2_VU0REC|PCSX2_VU1REC|PCSX2_GSMULTITHREAD|PCSX2_FRAMELIMIT_LIMIT ); + Entry( "sseMXCSR", Conf.sseMXCSR, DEFAULT_sseMXCSR ); + Entry( "sseVUMXCSR", Conf.sseVUMXCSR, DEFAULT_sseVUMXCSR ); + Entry( "eeOptions", Conf.eeOptions, DEFAULT_eeOptions ); + Entry( "vuOptions", Conf.vuOptions, DEFAULT_vuOptions ); + Entry( "SpeedHacks", Conf.Hacks ); + } +}; + +class IniFileLoader : public IniFile +{ +protected: + MemoryAlloc m_workspace; + +public: + virtual ~IniFileLoader() {} + IniFileLoader() : IniFile(), + m_workspace( 4096, "IniFileLoader Workspace" ) + { + } + + void Entry( const string& var, string& value, const string& defvalue=string() ) + { + int retval = GetPrivateProfileString( + m_section.c_str(), var.c_str(), defvalue.c_str(), m_workspace.GetPtr(), m_workspace.GetLength(), m_filename.c_str() + ); + + if( retval >= m_workspace.GetLength() - 2 ) + Console::Notice( "Loadini Warning > Possible truncated value on key '%hs'", params &var ); + value = m_workspace.GetPtr(); + } + + void Entry( const string& var, char (&value)[g_MaxPath], const string& defvalue=string() ) + { + int retval = GetPrivateProfileString( + m_section.c_str(), var.c_str(), defvalue.c_str(), value, sizeof( value ), m_filename.c_str() + ); + + if( retval >= sizeof(value) - 2 ) + Console::Notice( "Loadini Warning > Possible truncated value on key '%hs'", params &var ); + } + + void Entry( const string& var, int& value, const int defvalue=0 ) + { + string retval; + Entry( var, retval, to_string( defvalue ) ); + value = atoi( retval.c_str() ); + } + + void Entry( const string& var, uint& value, const uint defvalue=0 ) + { + string retval; + Entry( var, retval, to_string( defvalue ) ); + value = atoi( retval.c_str() ); + } + + void Entry( const string& var, bool& value, const bool defvalue=false ) + { + string retval; + Entry( var, retval, defvalue ? "enabled" : "disabled" ); + value = (retval == "enabled"); + } + + void EnumEntry( const string& var, int& value, const char* const* enumArray, const int defvalue=0 ) + { + string retval; + Entry( var, retval, enumArray[defvalue] ); + + int i=0; + while( enumArray[i] != NULL && ( retval != enumArray[i] ) ) i++; + + if( enumArray[i] == NULL ) + { + Console::Notice( "Loadini Warning > Unrecognized value '%hs' on key '%hs'\n\tUsing the default setting of '%s'.", + params &retval, &var, enumArray[defvalue] ); + value = defvalue; + } + else + value = i; + } + +}; + +class IniFileSaver : public IniFile +{ +public: + virtual ~IniFileSaver() {} + IniFileSaver() : IniFile() + { + char versionStr[20]; + _itoa( IniVersion, versionStr, 10 ); + WritePrivateProfileString( "Misc", "IniVersion", versionStr, m_filename.c_str() ); + } + + void Entry( const string& var, const string& value, const string& defvalue=string() ) + { + WritePrivateProfileString( m_section.c_str(), var.c_str(), value.c_str(), m_filename.c_str() ); + } + + void Entry( const string& var, string& value, const string& defvalue=string() ) + { + WritePrivateProfileString( m_section.c_str(), var.c_str(), value.c_str(), m_filename.c_str() ); + } + + void Entry( const string& var, char (&value)[g_MaxPath], const string& defvalue=string() ) + { + WritePrivateProfileString( m_section.c_str(), var.c_str(), value, m_filename.c_str() ); + } + + void Entry( const string& var, int& value, const int defvalue=0 ) + { + Entry( var, to_string( value ) ); + } + + void Entry( const string& var, uint& value, const uint defvalue=0 ) + { + Entry( var, to_string( value ) ); + } + + void Entry( const string& var, bool& value, const bool defvalue=false ) + { + Entry( var, value ? "enabled" : "disabled" ); + } + + void EnumEntry( const string& var, int& value, const char* const* enumArray, const int defvalue=0 ) + { + Entry( var, enumArray[value] ); + } +}; + +bool LoadConfig() +{ + string szIniFile; + bool status = true; + + GetConfigFilename( szIniFile ); + + if( !Path::Exists( szIniFile ) ) + { + if( hasCustomConfig() ) + { + // using custom config, so fail outright: + throw Exception::FileNotFound( + "User-specified configuration file not found:\n\t%s\n\nPCSX2 will now exit." + ); + } + + // standard mode operation. Create the directory. + CreateDirectory( "inis", NULL ); + status = false; // inform caller that we're not configured. + } + else + { + // sanity check to make sure the user doesn't have some kind of + // crazy ass setup... why not! + + if( Path::isDirectory( szIniFile ) ) + throw Exception::Stream( + "Cannot open or create the Pcsx2 ini file because a directory of\n" + "the same name already exists! Please delete it or reinstall Pcsx2\n" + "fresh and try again." + ); + + // Ini Version check! ----> + // If the user's ini is old, give them a friendly warning that says they should + // probably delete it. + + char versionStr[20]; + u32 version; + + GetPrivateProfileString( "Misc", "IniVersion", NULL, versionStr, 20, szIniFile.c_str() ); + version = atoi( versionStr ); + if( version < IniVersion ) + { + // Warn the user of a version mismatch. + Msgbox::Alert( + "Configuration versions do not match. Pcsx2 may be unstable.\n" + "If you experience problems, delete the pcsx2-pg.ini file from the ini dir." + ); + + // save the new version -- gets rid of the warning on subsequent startups + _itoa( IniVersion, versionStr, 10 ); + WritePrivateProfileString( "Misc", "IniVersion", versionStr, szIniFile.c_str() ); + } + } + + IniFileLoader().DoConfig( Config ); + +#ifdef ENABLE_NLS + { + string text; + extern int _nl_msg_cat_cntr; + ssprintf(text, "LANGUAGE=%s", Config.Lang); + gettext_putenv(text.c_str()); + } +#endif + + return status; +} + +void SaveConfig() +{ + PcsxConfig tmpConf = Config; + + strcpy( tmpConf.GS, winConfig.GS ); + strcpy( tmpConf.SPU2, winConfig.SPU2 ); + strcpy( tmpConf.CDVD, winConfig.CDVD ); + strcpy( tmpConf.PAD1, winConfig.PAD1 ); + strcpy( tmpConf.PAD2, winConfig.PAD2 ); + strcpy( tmpConf.DEV9, winConfig.DEV9 ); + strcpy( tmpConf.USB, winConfig.USB ); + strcpy( tmpConf.FW, winConfig.FW ); + + IniFileSaver().DoConfig( tmpConf ); +} + diff --git a/pcsx2/windows/libs/libintlmsc.h b/pcsx2/windows/libs/libintlmsc.h index 25a96a998d..5c0cdf6b28 100644 --- a/pcsx2/windows/libs/libintlmsc.h +++ b/pcsx2/windows/libs/libintlmsc.h @@ -1,116 +1,116 @@ -/* This file is part of a Windows32 DLL Interface to: - GNU gettext - internationalization aids - Copyright (C) 1996, 1998 Free Software Foundation, Inc. - - This file was written by Franco Bez - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2, 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 Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser 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. */ - -/* REPLACEMENT FOR ORIGINAL LIBINTL.H for use with Windows32 */ - -#if !defined(__LIBINTL_H_INCLUDED) -#define __LIBINTL_H_INCLUDED - -#if defined(__cplusplus) -extern "C" { -#endif - -/* See if we allready know what we want static or dll linkage or none at all*/ -#if defined DONT_USE_GETTEXT || ( defined USE_SAFE_GETTEXT_DLL && defined USE_GETTEXT_STATIC ) || ( defined USE_GETTEXT_DLL && defined USE_SAFE_GETTEXT_DLL ) || ( defined USE_GETTEXT_DLL && defined USE_GETTEXT_STATIC ) -/* TWO IS HARDLY POSSIBLE */ -#undef USE_GETTEXT_DLL -#undef USE_GETTEXT_STATIC -#undef USE_SAFE_GETTEXT_DLL -#endif /* MORE THAN ONE - OR NONE AT ALL */ - -#if !defined USE_GETTEXT_DLL && !defined USE_SAFE_GETTEXT_DLL && !defined USE_GETTEXT_STATIC && !defined DONT_USE_GETTEXT -/* not explicitly defined so try to guess it - - if GNUC is used - we use static linkage by default - because at the moment this is the only plattform - for which a static lib is available - else we use the DLL built with GNUC */ -# if defined __GNUC__ -# define USE_GETTEXT_STATIC -# else -# define USE_GETTEXT_DLL -# endif /* __GNUC__ */ -#endif /* NONE */ - -/* NOW ONLY ONE OF - DONT_USE_GETTEXT , USE_GETTEXT_DLL , USE_SAFE_GETTEXT_DLL , USE_GETTEXT_STATIC - IS DEFINED */ - -#if defined USE_GETTEXT_DLL -/* exported functions in DLL gnu_gettext.dll - you should link with import library - -lgnu_gettext (for mingw32) OR gnu_gettext.lib (MSVC) */ -__declspec(dllimport) char *gettext(const char *__msgid); -__declspec(dllimport) char *dgettext(const char *__domainname,const char *__msgid); -__declspec(dllimport) char *dcgettext(const char *__domainname,const char *__msgid, int __category); -__declspec(dllimport) char *textdomain(const char *__domainname); -__declspec(dllimport) char *bindtextdomain(const char *__domainname,const char *__dirname); -/* calling _putenv from within the DLL */ -__declspec(dllexport) int gettext_putenv(const char *envstring); -#endif /* DLL */ - -#if defined USE_SAFE_GETTEXT_DLL -/* Uses DLL gnu_gettext.dll ONLY if present, otherwise NO translation will take place - you should link with "safe_gettext_dll.o -lstdc++" see README for safe_gettext_dll for Details */ -/* The safe gettext functions */ -extern char *gettext(const char *szMsgId); -extern char *dgettext(const char *szDomain,const char *szMsgId); -extern char *dcgettext(const char *szDomain,const char *szMsgId,int iCategory); -extern char *textdomain(const char *szDomain); -extern char *bindtextdomain(const char *szDomain,const char *szDirectory); -/* calling _putenv from within the DLL */ -extern int gettext_putenv(const char *envstring); -#endif /* SAFE DLL */ - -#if defined USE_GETTEXT_STATIC -/* exported functions in static library libintl.a - and supporting macros - you should link with -lintl (mingw32) */ -extern char *gettext__(const char *__msgid); -extern char *dgettext__(const char *__domainname,const char *__msgid); -extern char *dcgettext__(const char *__domainname,const char *__msgid, int __category); -extern char *textdomain__(const char *__domainname); -extern char *bindtextdomain__(const char *__domainname,const char *__dirname); -#define gettext(szMsgId) gettext__(szMsgId) -#define dgettext(szDomain,szMsgId) dgettext__(szDomain,szMsgId) -#define dcgettext(szDomain,szMsgId,iCategory) dcgettext__(szDomain,szMsgId,iCategory) -#define textdomain(szDomain) textdomain__(szDomain) -#define bindtextdomain(szDomain,szDirectory) bindtextdomain__(szDomain,szDirectory) -// dummy - for static linkage - calling _putenv from within the DLL -#define gettext_putenv(a) _putenv(a) -#endif /* STATIC */ - -#if defined DONT_USE_GETTEXT -/* DON'T USE GETTEXT AT ALL - MAKROS TO MAKE CODE COMPILE WELL, BUT GETTEXT WILL NOT BE USESD -*/ -# define gettext(Msgid) (Msgid) -# define dgettext(Domainname, Msgid) (Msgid) -# define dcgettext(Domainname, Msgid, Category) (Msgid) -# define textdomain(Domainname) ((char *) Domainname) -# define bindtextdomain(Domainname, Dirname) ((char *) Dirname) -// dummy - for static linkage - calling _putenv from within the DLL -# define gettext_putenv(a) _putenv(a) -#endif /* DON'T USE AT ALL */ - -#if defined(__cplusplus) -} /* extern "C" */ -#endif - -#endif /*!defined(__LIBINTL_H_INCLUDED)*/ +/* This file is part of a Windows32 DLL Interface to: + GNU gettext - internationalization aids + Copyright (C) 1996, 1998 Free Software Foundation, Inc. + + This file was written by Franco Bez + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2, 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser 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. */ + +/* REPLACEMENT FOR ORIGINAL LIBINTL.H for use with Windows32 */ + +#if !defined(__LIBINTL_H_INCLUDED) +#define __LIBINTL_H_INCLUDED + +#if defined(__cplusplus) +extern "C" { +#endif + +/* See if we allready know what we want static or dll linkage or none at all*/ +#if defined DONT_USE_GETTEXT || ( defined USE_SAFE_GETTEXT_DLL && defined USE_GETTEXT_STATIC ) || ( defined USE_GETTEXT_DLL && defined USE_SAFE_GETTEXT_DLL ) || ( defined USE_GETTEXT_DLL && defined USE_GETTEXT_STATIC ) +/* TWO IS HARDLY POSSIBLE */ +#undef USE_GETTEXT_DLL +#undef USE_GETTEXT_STATIC +#undef USE_SAFE_GETTEXT_DLL +#endif /* MORE THAN ONE - OR NONE AT ALL */ + +#if !defined USE_GETTEXT_DLL && !defined USE_SAFE_GETTEXT_DLL && !defined USE_GETTEXT_STATIC && !defined DONT_USE_GETTEXT +/* not explicitly defined so try to guess it - + if GNUC is used - we use static linkage by default + because at the moment this is the only plattform + for which a static lib is available + else we use the DLL built with GNUC */ +# if defined __GNUC__ +# define USE_GETTEXT_STATIC +# else +# define USE_GETTEXT_DLL +# endif /* __GNUC__ */ +#endif /* NONE */ + +/* NOW ONLY ONE OF + DONT_USE_GETTEXT , USE_GETTEXT_DLL , USE_SAFE_GETTEXT_DLL , USE_GETTEXT_STATIC + IS DEFINED */ + +#if defined USE_GETTEXT_DLL +/* exported functions in DLL gnu_gettext.dll + you should link with import library + -lgnu_gettext (for mingw32) OR gnu_gettext.lib (MSVC) */ +__declspec(dllimport) char *gettext(const char *__msgid); +__declspec(dllimport) char *dgettext(const char *__domainname,const char *__msgid); +__declspec(dllimport) char *dcgettext(const char *__domainname,const char *__msgid, int __category); +__declspec(dllimport) char *textdomain(const char *__domainname); +__declspec(dllimport) char *bindtextdomain(const char *__domainname,const char *__dirname); +/* calling _putenv from within the DLL */ +__declspec(dllexport) int gettext_putenv(const char *envstring); +#endif /* DLL */ + +#if defined USE_SAFE_GETTEXT_DLL +/* Uses DLL gnu_gettext.dll ONLY if present, otherwise NO translation will take place + you should link with "safe_gettext_dll.o -lstdc++" see README for safe_gettext_dll for Details */ +/* The safe gettext functions */ +extern char *gettext(const char *szMsgId); +extern char *dgettext(const char *szDomain,const char *szMsgId); +extern char *dcgettext(const char *szDomain,const char *szMsgId,int iCategory); +extern char *textdomain(const char *szDomain); +extern char *bindtextdomain(const char *szDomain,const char *szDirectory); +/* calling _putenv from within the DLL */ +extern int gettext_putenv(const char *envstring); +#endif /* SAFE DLL */ + +#if defined USE_GETTEXT_STATIC +/* exported functions in static library libintl.a + and supporting macros + you should link with -lintl (mingw32) */ +extern char *gettext__(const char *__msgid); +extern char *dgettext__(const char *__domainname,const char *__msgid); +extern char *dcgettext__(const char *__domainname,const char *__msgid, int __category); +extern char *textdomain__(const char *__domainname); +extern char *bindtextdomain__(const char *__domainname,const char *__dirname); +#define gettext(szMsgId) gettext__(szMsgId) +#define dgettext(szDomain,szMsgId) dgettext__(szDomain,szMsgId) +#define dcgettext(szDomain,szMsgId,iCategory) dcgettext__(szDomain,szMsgId,iCategory) +#define textdomain(szDomain) textdomain__(szDomain) +#define bindtextdomain(szDomain,szDirectory) bindtextdomain__(szDomain,szDirectory) +// dummy - for static linkage - calling _putenv from within the DLL +#define gettext_putenv(a) _putenv(a) +#endif /* STATIC */ + +#if defined DONT_USE_GETTEXT +/* DON'T USE GETTEXT AT ALL + MAKROS TO MAKE CODE COMPILE WELL, BUT GETTEXT WILL NOT BE USESD +*/ +# define gettext(Msgid) (Msgid) +# define dgettext(Domainname, Msgid) (Msgid) +# define dcgettext(Domainname, Msgid, Category) (Msgid) +# define textdomain(Domainname) ((char *) Domainname) +# define bindtextdomain(Domainname, Dirname) ((char *) Dirname) +// dummy - for static linkage - calling _putenv from within the DLL +# define gettext_putenv(a) _putenv(a) +#endif /* DON'T USE AT ALL */ + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +#endif /*!defined(__LIBINTL_H_INCLUDED)*/ diff --git a/pcsx2/windows/memzero.h b/pcsx2/windows/memzero.h index c204fbc32a..7f7ddc71af 100644 --- a/pcsx2/windows/memzero.h +++ b/pcsx2/windows/memzero.h @@ -1,598 +1,598 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef _WIN_MEMZERO_H_ -#define _WIN_MEMZERO_H_ - -// These functions are meant for memset operations of constant length only. -// For dynamic length clears, use the C-compiler provided memset instead. - -// MemZero Code Strategies: -// I use a trick to help the MSVC compiler optimize it's asm code better. The compiler -// won't optimize local variables very well because it insists in storing them on the -// stack and then loading them out of the stack when I use them from inline ASM, and -// it won't allow me to use template parameters in inline asm code either. But I can -// assign the template parameters to enums, and then use the enums from asm code. -// Yeah, silly, but it works. :D (air) - -// All methods defined in this header use template in combination with the aforementioned -// enumerations to generate very efficient and compact inlined code. These optimized -// memsets work on the theory that most uses of memset involve static arrays and -// structures, which are constant in size, thus allowing us to generate optimal compile- -// time code for each use of the function. - -// Notes on XMM0's "storage" area (_xmm_backup): -// Unfortunately there's no way to guarantee alignment for this variable. If I use the -// __declspec(aligned(16)) decorator, MSVC fails to inline the function since stack -// alignment requires prep work. And for the same reason it's not possible to check the -// alignment of the stack at compile time, so I'm forced to use movups to store and -// retrieve xmm0. - - -// This is an implementation of the memzero_ptr fast memset routine (for zero-clears only). -template< size_t bytes > -static __forceinline void memzero_ptr( void *dest ) -{ - if( bytes == 0 ) return; - - // This function only works on 32-bit alignments. For anything else we just fall back - // on the compiler-provided implementation of memset... - - if( (bytes & 0x3) != 0 ) - { - memset( dest, 0, bytes ); - return; - } - - enum - { - remainder = bytes & 127, - bytes128 = bytes / 128 - }; - - // Initial check -- if the length is not a multiple of 16 then fall back on - // using rep movsd methods. Handling these unaligned clears in a more efficient - // manner isn't necessary in pcsx2 (meaning they aren't used in speed-critical - // scenarios). - - if( (bytes & 0xf) == 0 ) - { - u64 _xmm_backup[2]; - - if( ((uptr)dest & 0xf) != 0 ) - { - // UNALIGNED COPY MODE. - // For unaligned copies we have a threshold of at least 128 vectors. Anything - // less and it's probably better off just falling back on the rep movsd. - if( bytes128 > 128 ) - { - __asm - { - movups _xmm_backup,xmm0; - mov ecx,dest - pxor xmm0,xmm0 - mov eax,bytes128 - - align 16 - - _loop_6: - movups [ecx],xmm0; - movups [ecx+0x10],xmm0; - movups [ecx+0x20],xmm0; - movups [ecx+0x30],xmm0; - movups [ecx+0x40],xmm0; - movups [ecx+0x50],xmm0; - movups [ecx+0x60],xmm0; - movups [ecx+0x70],xmm0; - sub ecx,-128 - dec eax; - jnz _loop_6; - } - if( remainder != 0 ) - { - // Copy the remainder in reverse (using the decrementing eax as our indexer) - __asm - { - mov eax, remainder - - _loop_5: - movups [ecx+eax],xmm0; - sub eax,16; - jnz _loop_5; - } - } - __asm - { - movups xmm0,[_xmm_backup]; - } - return; - } - } - else if( bytes128 > 48 ) - { - // ALIGNED COPY MODE - // Data is aligned and the size of data is large enough to merit a nice - // fancy chunk of unrolled goodness: - - __asm - { - movups _xmm_backup,xmm0; - mov ecx,dest - pxor xmm0,xmm0 - mov eax,bytes128 - - align 16 - - _loop_8: - movaps [ecx],xmm0; - movaps [ecx+0x10],xmm0; - movaps [ecx+0x20],xmm0; - movaps [ecx+0x30],xmm0; - movaps [ecx+0x40],xmm0; - movaps [ecx+0x50],xmm0; - movaps [ecx+0x60],xmm0; - movaps [ecx+0x70],xmm0; - sub ecx,-128 - dec eax; - jnz _loop_8; - } - if( remainder != 0 ) - { - // Copy the remainder in reverse (using the decrementing eax as our indexer) - __asm - { - mov eax, remainder - - _loop_10: - movaps [ecx+eax],xmm0; - sub eax,16; - jnz _loop_10; - } - } - __asm - { - movups xmm0,[_xmm_backup]; - } - return; - } - } - - // This function only works on 32-bit alignments. - jASSUME( (bytes & 0x3) == 0 ); - jASSUME( ((uptr)dest & 0x3) == 0 ); - - enum - { - remdat = bytes>>2 - }; - - // This case statement handles 5 special-case sizes (small blocks) - // in addition to the generic large block that uses rep stosd. - - switch( remdat ) - { - case 1: - *(u32*)dest = 0; - return; - - case 2: - *(u64*)dest = 0; - return; - - case 3: - __asm - { - cld; - mov edi, dest - xor eax, eax - stosd - stosd - stosd - } - return; - - case 4: - __asm - { - cld; - mov edi, dest - xor eax, eax - stosd - stosd - stosd - stosd - } - return; - - case 5: - __asm - { - cld; - mov edi, dest - xor eax, eax - stosd - stosd - stosd - stosd - stosd - } - return; - - default: - __asm - { - cld; - mov ecx, remdat - mov edi, dest - xor eax, eax - rep stosd - } - return; - } -} - -// An optimized memset for 8 bit destination data. -template< u8 data, size_t bytes > -static __forceinline void memset_8( void *dest ) -{ - if( bytes == 0 ) return; - - if( (bytes & 0x3) != 0 ) - { - // unaligned data length. No point in doing an optimized inline version (too complicated!) - // So fall back on the compiler implementation: - - memset( dest, data, bytes ); - return; - } - - //u64 _xmm_backup[2]; - - /*static const size_t remainder = bytes & 127; - static const size_t bytes128 = bytes / 128; - if( bytes128 > 32 ) - { - // This function only works on 128-bit alignments. - jASSUME( (bytes & 0xf) == 0 ); - jASSUME( ((uptr)dest & 0xf) == 0 ); - - __asm - { - movups _xmm_backup,xmm0; - mov eax,bytes128 - mov ecx,dest - movss xmm0,data - - align 16 - - _loop_8: - movaps [ecx],xmm0; - movaps [ecx+0x10],xmm0; - movaps [ecx+0x20],xmm0; - movaps [ecx+0x30],xmm0; - movaps [ecx+0x40],xmm0; - movaps [ecx+0x50],xmm0; - movaps [ecx+0x60],xmm0; - movaps [ecx+0x70],xmm0; - sub ecx,-128 - dec eax; - jnz _loop_8; - } - if( remainder != 0 ) - { - // Copy the remainder in reverse (using the decrementing eax as our indexer) - __asm - { - mov eax, remainder - - _loop_10: - movaps [ecx+eax],xmm0; - sub eax,16; - jnz _loop_10; - } - } - __asm - { - movups xmm0,[_xmm_backup]; - } - }*/ - - // This function only works on 32-bit alignments of data copied. - jASSUME( (bytes & 0x3) == 0 ); - - enum - { - remdat = bytes>>2, - data32 = data + (data<<8) + (data<<16) + (data<<24) - }; - - // macro to execute the x86/32 "stosd" copies. - switch( remdat ) - { - case 1: - *(u32*)dest = data32; - return; - - case 2: - ((u32*)dest)[0] = data32; - ((u32*)dest)[1] = data32; - return; - - case 3: - __asm - { - cld; - mov edi, dest; - mov eax, data32; - stosd; - stosd; - stosd; - } - return; - - case 4: - __asm - { - cld; - mov edi, dest; - mov eax, data32; - stosd; - stosd; - stosd; - stosd; - } - return; - - case 5: - __asm - { - cld; - mov edi, dest; - mov eax, data32; - stosd; - stosd; - stosd; - stosd; - stosd; - } - return; - - default: - __asm - { - cld; - mov ecx, remdat; - mov edi, dest; - mov eax, data32; - rep stosd; - } - return; - } -} - -template< u16 data, size_t bytes > -static __forceinline void memset_16( void *dest ) -{ - if( bytes == 0 ) return; - - if( (bytes & 0x1) != 0 ) - throw Exception::LogicError( "Invalid parameter passed to memset_16 - data length is not a multiple of 16 or 32 bits." ); - - if( (bytes & 0x3) != 0 ) - { - // Unaligned data length. No point in doing an optimized inline version (too complicated with - // remainders and such). - - _memset16_unaligned( dest, data, bytes ); - return; - } - - //u64 _xmm_backup[2]; - - // This function only works on 32-bit alignments of data copied. - jASSUME( (bytes & 0x3) == 0 ); - - enum - { - remdat = bytes>>2, - data32 = data + (data<<16) - }; - - // macro to execute the x86/32 "stosd" copies. - switch( remdat ) - { - case 1: - *(u32*)dest = data32; - return; - - case 2: - ((u32*)dest)[0] = data32; - ((u32*)dest)[1] = data32; - return; - - case 3: - __asm - { - cld; - mov edi, dest; - mov eax, data32; - stosd; - stosd; - stosd; - } - return; - - case 4: - __asm - { - cld; - mov edi, dest; - mov eax, data32; - stosd; - stosd; - stosd; - stosd; - } - return; - - case 5: - __asm - { - cld; - mov edi, dest; - mov eax, data32; - stosd; - stosd; - stosd; - stosd; - stosd; - } - return; - - default: - __asm - { - cld; - mov ecx, remdat; - mov edi, dest; - mov eax, data32; - rep stosd; - } - return - } -} - -template< u32 data, size_t bytes > -static __forceinline void memset_32( void *dest ) -{ - if( bytes == 0 ) return; - - if( (bytes & 0x3) != 0 ) - throw Exception::LogicError( "Invalid parameter passed to memset_32 - data length is not a multiple of 32 bits." ); - - - //u64 _xmm_backup[2]; - - // This function only works on 32-bit alignments of data copied. - // If the data length is not a factor of 32 bits, the C++ optimizing compiler will - // probably just generate mysteriously broken code in Release builds. ;) - - jASSUME( (bytes & 0x3) == 0 ); - - enum - { - remdat = bytes>>2, - data32 = data - }; - - // macro to execute the x86/32 "stosd" copies. - switch( remdat ) - { - case 1: - *(u32*)dest = data32; - return; - - case 2: - ((u32*)dest)[0] = data32; - ((u32*)dest)[1] = data32; - return; - - case 3: - __asm - { - cld; - mov edi, dest; - mov eax, data32; - stosd; - stosd; - stosd; - } - return; - - case 4: - __asm - { - cld; - mov edi, dest; - mov eax, data32; - stosd; - stosd; - stosd; - stosd; - } - return; - - case 5: - __asm - { - cld; - mov edi, dest; - mov eax, data32; - stosd; - stosd; - stosd; - stosd; - stosd; - } - return; - - default: - __asm - { - cld; - mov ecx, remdat; - mov edi, dest; - mov eax, data32; - rep stosd; - } - return - } -} - -// This method can clear any object-like entity -- which is anything that is not a pointer. -// Structures, static arrays, etc. No need to include sizeof() crap, this does it automatically -// for you! -template< typename T > -static __forceinline void memzero_obj( T& object ) -{ - memzero_ptr( &object ); -} - -// This method clears an object with the given 8 bit value. -template< u8 data, typename T > -static __forceinline void memset8_obj( T& object ) -{ - memset_8( &object ); -} - -// This method clears an object with the given 16 bit value. -template< u16 data, typename T > -static __forceinline void memset16_obj( T& object ) -{ - memset_16( &object ); -} - -// This method clears an object with the given 32 bit value. -template< u32 data, typename T > -static __forceinline void memset32_obj( T& object ) -{ - memset_32( &object ); -} - -#endif - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef _WIN_MEMZERO_H_ +#define _WIN_MEMZERO_H_ + +// These functions are meant for memset operations of constant length only. +// For dynamic length clears, use the C-compiler provided memset instead. + +// MemZero Code Strategies: +// I use a trick to help the MSVC compiler optimize it's asm code better. The compiler +// won't optimize local variables very well because it insists in storing them on the +// stack and then loading them out of the stack when I use them from inline ASM, and +// it won't allow me to use template parameters in inline asm code either. But I can +// assign the template parameters to enums, and then use the enums from asm code. +// Yeah, silly, but it works. :D (air) + +// All methods defined in this header use template in combination with the aforementioned +// enumerations to generate very efficient and compact inlined code. These optimized +// memsets work on the theory that most uses of memset involve static arrays and +// structures, which are constant in size, thus allowing us to generate optimal compile- +// time code for each use of the function. + +// Notes on XMM0's "storage" area (_xmm_backup): +// Unfortunately there's no way to guarantee alignment for this variable. If I use the +// __declspec(aligned(16)) decorator, MSVC fails to inline the function since stack +// alignment requires prep work. And for the same reason it's not possible to check the +// alignment of the stack at compile time, so I'm forced to use movups to store and +// retrieve xmm0. + + +// This is an implementation of the memzero_ptr fast memset routine (for zero-clears only). +template< size_t bytes > +static __forceinline void memzero_ptr( void *dest ) +{ + if( bytes == 0 ) return; + + // This function only works on 32-bit alignments. For anything else we just fall back + // on the compiler-provided implementation of memset... + + if( (bytes & 0x3) != 0 ) + { + memset( dest, 0, bytes ); + return; + } + + enum + { + remainder = bytes & 127, + bytes128 = bytes / 128 + }; + + // Initial check -- if the length is not a multiple of 16 then fall back on + // using rep movsd methods. Handling these unaligned clears in a more efficient + // manner isn't necessary in pcsx2 (meaning they aren't used in speed-critical + // scenarios). + + if( (bytes & 0xf) == 0 ) + { + u64 _xmm_backup[2]; + + if( ((uptr)dest & 0xf) != 0 ) + { + // UNALIGNED COPY MODE. + // For unaligned copies we have a threshold of at least 128 vectors. Anything + // less and it's probably better off just falling back on the rep movsd. + if( bytes128 > 128 ) + { + __asm + { + movups _xmm_backup,xmm0; + mov ecx,dest + pxor xmm0,xmm0 + mov eax,bytes128 + + align 16 + + _loop_6: + movups [ecx],xmm0; + movups [ecx+0x10],xmm0; + movups [ecx+0x20],xmm0; + movups [ecx+0x30],xmm0; + movups [ecx+0x40],xmm0; + movups [ecx+0x50],xmm0; + movups [ecx+0x60],xmm0; + movups [ecx+0x70],xmm0; + sub ecx,-128 + dec eax; + jnz _loop_6; + } + if( remainder != 0 ) + { + // Copy the remainder in reverse (using the decrementing eax as our indexer) + __asm + { + mov eax, remainder + + _loop_5: + movups [ecx+eax],xmm0; + sub eax,16; + jnz _loop_5; + } + } + __asm + { + movups xmm0,[_xmm_backup]; + } + return; + } + } + else if( bytes128 > 48 ) + { + // ALIGNED COPY MODE + // Data is aligned and the size of data is large enough to merit a nice + // fancy chunk of unrolled goodness: + + __asm + { + movups _xmm_backup,xmm0; + mov ecx,dest + pxor xmm0,xmm0 + mov eax,bytes128 + + align 16 + + _loop_8: + movaps [ecx],xmm0; + movaps [ecx+0x10],xmm0; + movaps [ecx+0x20],xmm0; + movaps [ecx+0x30],xmm0; + movaps [ecx+0x40],xmm0; + movaps [ecx+0x50],xmm0; + movaps [ecx+0x60],xmm0; + movaps [ecx+0x70],xmm0; + sub ecx,-128 + dec eax; + jnz _loop_8; + } + if( remainder != 0 ) + { + // Copy the remainder in reverse (using the decrementing eax as our indexer) + __asm + { + mov eax, remainder + + _loop_10: + movaps [ecx+eax],xmm0; + sub eax,16; + jnz _loop_10; + } + } + __asm + { + movups xmm0,[_xmm_backup]; + } + return; + } + } + + // This function only works on 32-bit alignments. + jASSUME( (bytes & 0x3) == 0 ); + jASSUME( ((uptr)dest & 0x3) == 0 ); + + enum + { + remdat = bytes>>2 + }; + + // This case statement handles 5 special-case sizes (small blocks) + // in addition to the generic large block that uses rep stosd. + + switch( remdat ) + { + case 1: + *(u32*)dest = 0; + return; + + case 2: + *(u64*)dest = 0; + return; + + case 3: + __asm + { + cld; + mov edi, dest + xor eax, eax + stosd + stosd + stosd + } + return; + + case 4: + __asm + { + cld; + mov edi, dest + xor eax, eax + stosd + stosd + stosd + stosd + } + return; + + case 5: + __asm + { + cld; + mov edi, dest + xor eax, eax + stosd + stosd + stosd + stosd + stosd + } + return; + + default: + __asm + { + cld; + mov ecx, remdat + mov edi, dest + xor eax, eax + rep stosd + } + return; + } +} + +// An optimized memset for 8 bit destination data. +template< u8 data, size_t bytes > +static __forceinline void memset_8( void *dest ) +{ + if( bytes == 0 ) return; + + if( (bytes & 0x3) != 0 ) + { + // unaligned data length. No point in doing an optimized inline version (too complicated!) + // So fall back on the compiler implementation: + + memset( dest, data, bytes ); + return; + } + + //u64 _xmm_backup[2]; + + /*static const size_t remainder = bytes & 127; + static const size_t bytes128 = bytes / 128; + if( bytes128 > 32 ) + { + // This function only works on 128-bit alignments. + jASSUME( (bytes & 0xf) == 0 ); + jASSUME( ((uptr)dest & 0xf) == 0 ); + + __asm + { + movups _xmm_backup,xmm0; + mov eax,bytes128 + mov ecx,dest + movss xmm0,data + + align 16 + + _loop_8: + movaps [ecx],xmm0; + movaps [ecx+0x10],xmm0; + movaps [ecx+0x20],xmm0; + movaps [ecx+0x30],xmm0; + movaps [ecx+0x40],xmm0; + movaps [ecx+0x50],xmm0; + movaps [ecx+0x60],xmm0; + movaps [ecx+0x70],xmm0; + sub ecx,-128 + dec eax; + jnz _loop_8; + } + if( remainder != 0 ) + { + // Copy the remainder in reverse (using the decrementing eax as our indexer) + __asm + { + mov eax, remainder + + _loop_10: + movaps [ecx+eax],xmm0; + sub eax,16; + jnz _loop_10; + } + } + __asm + { + movups xmm0,[_xmm_backup]; + } + }*/ + + // This function only works on 32-bit alignments of data copied. + jASSUME( (bytes & 0x3) == 0 ); + + enum + { + remdat = bytes>>2, + data32 = data + (data<<8) + (data<<16) + (data<<24) + }; + + // macro to execute the x86/32 "stosd" copies. + switch( remdat ) + { + case 1: + *(u32*)dest = data32; + return; + + case 2: + ((u32*)dest)[0] = data32; + ((u32*)dest)[1] = data32; + return; + + case 3: + __asm + { + cld; + mov edi, dest; + mov eax, data32; + stosd; + stosd; + stosd; + } + return; + + case 4: + __asm + { + cld; + mov edi, dest; + mov eax, data32; + stosd; + stosd; + stosd; + stosd; + } + return; + + case 5: + __asm + { + cld; + mov edi, dest; + mov eax, data32; + stosd; + stosd; + stosd; + stosd; + stosd; + } + return; + + default: + __asm + { + cld; + mov ecx, remdat; + mov edi, dest; + mov eax, data32; + rep stosd; + } + return; + } +} + +template< u16 data, size_t bytes > +static __forceinline void memset_16( void *dest ) +{ + if( bytes == 0 ) return; + + if( (bytes & 0x1) != 0 ) + throw Exception::LogicError( "Invalid parameter passed to memset_16 - data length is not a multiple of 16 or 32 bits." ); + + if( (bytes & 0x3) != 0 ) + { + // Unaligned data length. No point in doing an optimized inline version (too complicated with + // remainders and such). + + _memset16_unaligned( dest, data, bytes ); + return; + } + + //u64 _xmm_backup[2]; + + // This function only works on 32-bit alignments of data copied. + jASSUME( (bytes & 0x3) == 0 ); + + enum + { + remdat = bytes>>2, + data32 = data + (data<<16) + }; + + // macro to execute the x86/32 "stosd" copies. + switch( remdat ) + { + case 1: + *(u32*)dest = data32; + return; + + case 2: + ((u32*)dest)[0] = data32; + ((u32*)dest)[1] = data32; + return; + + case 3: + __asm + { + cld; + mov edi, dest; + mov eax, data32; + stosd; + stosd; + stosd; + } + return; + + case 4: + __asm + { + cld; + mov edi, dest; + mov eax, data32; + stosd; + stosd; + stosd; + stosd; + } + return; + + case 5: + __asm + { + cld; + mov edi, dest; + mov eax, data32; + stosd; + stosd; + stosd; + stosd; + stosd; + } + return; + + default: + __asm + { + cld; + mov ecx, remdat; + mov edi, dest; + mov eax, data32; + rep stosd; + } + return + } +} + +template< u32 data, size_t bytes > +static __forceinline void memset_32( void *dest ) +{ + if( bytes == 0 ) return; + + if( (bytes & 0x3) != 0 ) + throw Exception::LogicError( "Invalid parameter passed to memset_32 - data length is not a multiple of 32 bits." ); + + + //u64 _xmm_backup[2]; + + // This function only works on 32-bit alignments of data copied. + // If the data length is not a factor of 32 bits, the C++ optimizing compiler will + // probably just generate mysteriously broken code in Release builds. ;) + + jASSUME( (bytes & 0x3) == 0 ); + + enum + { + remdat = bytes>>2, + data32 = data + }; + + // macro to execute the x86/32 "stosd" copies. + switch( remdat ) + { + case 1: + *(u32*)dest = data32; + return; + + case 2: + ((u32*)dest)[0] = data32; + ((u32*)dest)[1] = data32; + return; + + case 3: + __asm + { + cld; + mov edi, dest; + mov eax, data32; + stosd; + stosd; + stosd; + } + return; + + case 4: + __asm + { + cld; + mov edi, dest; + mov eax, data32; + stosd; + stosd; + stosd; + stosd; + } + return; + + case 5: + __asm + { + cld; + mov edi, dest; + mov eax, data32; + stosd; + stosd; + stosd; + stosd; + stosd; + } + return; + + default: + __asm + { + cld; + mov ecx, remdat; + mov edi, dest; + mov eax, data32; + rep stosd; + } + return + } +} + +// This method can clear any object-like entity -- which is anything that is not a pointer. +// Structures, static arrays, etc. No need to include sizeof() crap, this does it automatically +// for you! +template< typename T > +static __forceinline void memzero_obj( T& object ) +{ + memzero_ptr( &object ); +} + +// This method clears an object with the given 8 bit value. +template< u8 data, typename T > +static __forceinline void memset8_obj( T& object ) +{ + memset_8( &object ); +} + +// This method clears an object with the given 16 bit value. +template< u16 data, typename T > +static __forceinline void memset16_obj( T& object ) +{ + memset_16( &object ); +} + +// This method clears an object with the given 32 bit value. +template< u32 data, typename T > +static __forceinline void memset32_obj( T& object ) +{ + memset_32( &object ); +} + +#endif + diff --git a/pcsx2/windows/pthreads/attr.c b/pcsx2/windows/pthreads/attr.c index 0d0b5600ab..a9d55f4a4b 100644 --- a/pcsx2/windows/pthreads/attr.c +++ b/pcsx2/windows/pthreads/attr.c @@ -1,53 +1,53 @@ -/* - * attr.c - * - * Description: - * This translation unit agregates operations on thread attribute objects. - * It is used for inline optimisation. - * - * The included modules are used separately when static executable sizes - * must be minimised. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -#include "pthread_attr_init.c" -#include "pthread_attr_destroy.c" -#include "pthread_attr_getdetachstate.c" -#include "pthread_attr_setdetachstate.c" -#include "pthread_attr_getstackaddr.c" -#include "pthread_attr_setstackaddr.c" -#include "pthread_attr_getstacksize.c" -#include "pthread_attr_setstacksize.c" -#include "pthread_attr_getscope.c" -#include "pthread_attr_setscope.c" +/* + * attr.c + * + * Description: + * This translation unit agregates operations on thread attribute objects. + * It is used for inline optimisation. + * + * The included modules are used separately when static executable sizes + * must be minimised. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +#include "pthread_attr_init.c" +#include "pthread_attr_destroy.c" +#include "pthread_attr_getdetachstate.c" +#include "pthread_attr_setdetachstate.c" +#include "pthread_attr_getstackaddr.c" +#include "pthread_attr_setstackaddr.c" +#include "pthread_attr_getstacksize.c" +#include "pthread_attr_setstacksize.c" +#include "pthread_attr_getscope.c" +#include "pthread_attr_setscope.c" diff --git a/pcsx2/windows/pthreads/barrier.c b/pcsx2/windows/pthreads/barrier.c index f95f4bde98..41b950cd12 100644 --- a/pcsx2/windows/pthreads/barrier.c +++ b/pcsx2/windows/pthreads/barrier.c @@ -1,47 +1,47 @@ -/* - * barrier.c - * - * Description: - * This translation unit implements barrier primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -#include "pthread_barrier_init.c" -#include "pthread_barrier_destroy.c" -#include "pthread_barrier_wait.c" -#include "pthread_barrierattr_init.c" -#include "pthread_barrierattr_destroy.c" -#include "pthread_barrierattr_getpshared.c" -#include "pthread_barrierattr_setpshared.c" +/* + * barrier.c + * + * Description: + * This translation unit implements barrier primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +#include "pthread_barrier_init.c" +#include "pthread_barrier_destroy.c" +#include "pthread_barrier_wait.c" +#include "pthread_barrierattr_init.c" +#include "pthread_barrierattr_destroy.c" +#include "pthread_barrierattr_getpshared.c" +#include "pthread_barrierattr_setpshared.c" diff --git a/pcsx2/windows/pthreads/cancel.c b/pcsx2/windows/pthreads/cancel.c index 28cf4ebc5e..1bd14ebe65 100644 --- a/pcsx2/windows/pthreads/cancel.c +++ b/pcsx2/windows/pthreads/cancel.c @@ -1,44 +1,44 @@ -/* - * cancel.c - * - * Description: - * POSIX thread functions related to thread cancellation. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -#include "pthread_setcancelstate.c" -#include "pthread_setcanceltype.c" -#include "pthread_testcancel.c" -#include "pthread_cancel.c" +/* + * cancel.c + * + * Description: + * POSIX thread functions related to thread cancellation. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +#include "pthread_setcancelstate.c" +#include "pthread_setcanceltype.c" +#include "pthread_testcancel.c" +#include "pthread_cancel.c" diff --git a/pcsx2/windows/pthreads/cleanup.c b/pcsx2/windows/pthreads/cleanup.c index 8f65c5ee5d..381d1e87c8 100644 --- a/pcsx2/windows/pthreads/cleanup.c +++ b/pcsx2/windows/pthreads/cleanup.c @@ -1,148 +1,148 @@ -/* - * cleanup.c - * - * Description: - * This translation unit implements routines associated - * with cleaning up threads. - * - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -/* - * The functions ptw32_pop_cleanup and ptw32_push_cleanup - * are implemented here for applications written in C with no - * SEH or C++ destructor support. - */ - -ptw32_cleanup_t * -ptw32_pop_cleanup (int execute) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function pops the most recently pushed cleanup - * handler. If execute is nonzero, then the cleanup handler - * is executed if non-null. - * - * PARAMETERS - * execute - * if nonzero, execute the cleanup handler - * - * - * DESCRIPTION - * This function pops the most recently pushed cleanup - * handler. If execute is nonzero, then the cleanup handler - * is executed if non-null. - * NOTE: specify 'execute' as nonzero to avoid duplication - * of common cleanup code. - * - * RESULTS - * N/A - * - * ------------------------------------------------------ - */ -{ - ptw32_cleanup_t *cleanup; - - cleanup = (ptw32_cleanup_t *) pthread_getspecific (ptw32_cleanupKey); - - if (cleanup != NULL) - { - if (execute && (cleanup->routine != NULL)) - { - - (*cleanup->routine) (cleanup->arg); - - } - - pthread_setspecific (ptw32_cleanupKey, (void *) cleanup->prev); - - } - - return (cleanup); - -} /* ptw32_pop_cleanup */ - - -void -ptw32_push_cleanup (ptw32_cleanup_t * cleanup, - ptw32_cleanup_callback_t routine, void *arg) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function pushes a new cleanup handler onto the thread's stack - * of cleanup handlers. Each cleanup handler pushed onto the stack is - * popped and invoked with the argument 'arg' when - * a) the thread exits by calling 'pthread_exit', - * b) when the thread acts on a cancellation request, - * c) or when the thread calls pthread_cleanup_pop with a nonzero - * 'execute' argument - * - * PARAMETERS - * cleanup - * a pointer to an instance of pthread_cleanup_t, - * - * routine - * pointer to a cleanup handler, - * - * arg - * parameter to be passed to the cleanup handler - * - * - * DESCRIPTION - * This function pushes a new cleanup handler onto the thread's stack - * of cleanup handlers. Each cleanup handler pushed onto the stack is - * popped and invoked with the argument 'arg' when - * a) the thread exits by calling 'pthread_exit', - * b) when the thread acts on a cancellation request, - * c) or when the thrad calls pthread_cleanup_pop with a nonzero - * 'execute' argument - * NOTE: pthread_push_cleanup, ptw32_pop_cleanup must be paired - * in the same lexical scope. - * - * RESULTS - * pthread_cleanup_t * - * pointer to the previous cleanup - * - * ------------------------------------------------------ - */ -{ - cleanup->routine = routine; - cleanup->arg = arg; - - cleanup->prev = (ptw32_cleanup_t *) pthread_getspecific (ptw32_cleanupKey); - - pthread_setspecific (ptw32_cleanupKey, (void *) cleanup); - -} /* ptw32_push_cleanup */ +/* + * cleanup.c + * + * Description: + * This translation unit implements routines associated + * with cleaning up threads. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +/* + * The functions ptw32_pop_cleanup and ptw32_push_cleanup + * are implemented here for applications written in C with no + * SEH or C++ destructor support. + */ + +ptw32_cleanup_t * +ptw32_pop_cleanup (int execute) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function pops the most recently pushed cleanup + * handler. If execute is nonzero, then the cleanup handler + * is executed if non-null. + * + * PARAMETERS + * execute + * if nonzero, execute the cleanup handler + * + * + * DESCRIPTION + * This function pops the most recently pushed cleanup + * handler. If execute is nonzero, then the cleanup handler + * is executed if non-null. + * NOTE: specify 'execute' as nonzero to avoid duplication + * of common cleanup code. + * + * RESULTS + * N/A + * + * ------------------------------------------------------ + */ +{ + ptw32_cleanup_t *cleanup; + + cleanup = (ptw32_cleanup_t *) pthread_getspecific (ptw32_cleanupKey); + + if (cleanup != NULL) + { + if (execute && (cleanup->routine != NULL)) + { + + (*cleanup->routine) (cleanup->arg); + + } + + pthread_setspecific (ptw32_cleanupKey, (void *) cleanup->prev); + + } + + return (cleanup); + +} /* ptw32_pop_cleanup */ + + +void +ptw32_push_cleanup (ptw32_cleanup_t * cleanup, + ptw32_cleanup_callback_t routine, void *arg) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function pushes a new cleanup handler onto the thread's stack + * of cleanup handlers. Each cleanup handler pushed onto the stack is + * popped and invoked with the argument 'arg' when + * a) the thread exits by calling 'pthread_exit', + * b) when the thread acts on a cancellation request, + * c) or when the thread calls pthread_cleanup_pop with a nonzero + * 'execute' argument + * + * PARAMETERS + * cleanup + * a pointer to an instance of pthread_cleanup_t, + * + * routine + * pointer to a cleanup handler, + * + * arg + * parameter to be passed to the cleanup handler + * + * + * DESCRIPTION + * This function pushes a new cleanup handler onto the thread's stack + * of cleanup handlers. Each cleanup handler pushed onto the stack is + * popped and invoked with the argument 'arg' when + * a) the thread exits by calling 'pthread_exit', + * b) when the thread acts on a cancellation request, + * c) or when the thrad calls pthread_cleanup_pop with a nonzero + * 'execute' argument + * NOTE: pthread_push_cleanup, ptw32_pop_cleanup must be paired + * in the same lexical scope. + * + * RESULTS + * pthread_cleanup_t * + * pointer to the previous cleanup + * + * ------------------------------------------------------ + */ +{ + cleanup->routine = routine; + cleanup->arg = arg; + + cleanup->prev = (ptw32_cleanup_t *) pthread_getspecific (ptw32_cleanupKey); + + pthread_setspecific (ptw32_cleanupKey, (void *) cleanup); + +} /* ptw32_push_cleanup */ diff --git a/pcsx2/windows/pthreads/condvar.c b/pcsx2/windows/pthreads/condvar.c index 449235c5ad..704f4d7931 100644 --- a/pcsx2/windows/pthreads/condvar.c +++ b/pcsx2/windows/pthreads/condvar.c @@ -1,50 +1,50 @@ -/* - * condvar.c - * - * Description: - * This translation unit implements condition variables and their primitives. - * - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - */ - -#include "pthread.h" -#include "implement.h" - -#include "ptw32_cond_check_need_init.c" -#include "pthread_condattr_init.c" -#include "pthread_condattr_destroy.c" -#include "pthread_condattr_getpshared.c" -#include "pthread_condattr_setpshared.c" -#include "pthread_cond_init.c" -#include "pthread_cond_destroy.c" -#include "pthread_cond_wait.c" -#include "pthread_cond_signal.c" +/* + * condvar.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + */ + +#include "pthread.h" +#include "implement.h" + +#include "ptw32_cond_check_need_init.c" +#include "pthread_condattr_init.c" +#include "pthread_condattr_destroy.c" +#include "pthread_condattr_getpshared.c" +#include "pthread_condattr_setpshared.c" +#include "pthread_cond_init.c" +#include "pthread_cond_destroy.c" +#include "pthread_cond_wait.c" +#include "pthread_cond_signal.c" diff --git a/pcsx2/windows/pthreads/config.h b/pcsx2/windows/pthreads/config.h index 2ea14f16c0..b2115698e5 100644 --- a/pcsx2/windows/pthreads/config.h +++ b/pcsx2/windows/pthreads/config.h @@ -1,134 +1,134 @@ -/* config.h */ - -#ifndef PTW32_CONFIG_H -#define PTW32_CONFIG_H - -/********************************************************************* - * Defaults: see target specific redefinitions below. - *********************************************************************/ - -/* We're building the pthreads-win32 library */ -#define PTW32_BUILD - -/* Do we know about the C type sigset_t? */ -#undef HAVE_SIGSET_T - -/* Define if you have the header file. */ -#define HAVE_SIGNAL_H - -/* Define if you have the Borland TASM32 or compatible assembler. */ -#undef HAVE_TASM32 - -/* Define if you don't have Win32 DuplicateHandle. (eg. WinCE) */ -#undef NEED_DUPLICATEHANDLE - -/* Define if you don't have Win32 _beginthreadex. (eg. WinCE) */ -#undef NEED_CREATETHREAD - -/* Define if you don't have Win32 errno. (eg. WinCE) */ -#undef NEED_ERRNO - -/* Define if you don't have Win32 calloc. (eg. WinCE) */ -#undef NEED_CALLOC - -/* Define if you don't have Win32 ftime. (eg. WinCE) */ -#undef NEED_FTIME - -/* Define if you don't have Win32 semaphores. (eg. WinCE 2.1 or earlier) */ -#undef NEED_SEM - -/* Define if you need to convert string parameters to unicode. (eg. WinCE) */ -#undef NEED_UNICODE_CONSTS - -/* Define if your C (not C++) compiler supports "inline" functions. */ -#define HAVE_C_INLINE - -/* Do we know about type mode_t? */ -#undef HAVE_MODE_T - -/* Define if you have the timespec struct */ -#undef HAVE_STRUCT_TIMESPEC - -/* Define if you don't have the GetProcessAffinityMask() */ -#undef NEED_PROCESS_AFFINITY_MASK - -/* -# ---------------------------------------------------------------------- -# The library can be built with some alternative behaviour to better -# facilitate development of applications on Win32 that will be ported -# to other POSIX systems. -# -# Nothing described here will make the library non-compliant and strictly -# compliant applications will not be affected in any way, but -# applications that make assumptions that POSIX does not guarantee are -# not strictly compliant and may fail or misbehave with some settings. -# -# PTW32_THREAD_ID_REUSE_INCREMENT -# Purpose: -# POSIX says that applications should assume that thread IDs can be -# recycled. However, Solaris (and some other systems) use a [very large] -# sequence number as the thread ID, which provides virtual uniqueness. -# This provides a very high but finite level of safety for applications -# that are not meticulous in tracking thread lifecycles e.g. applications -# that call functions which target detached threads without some form of -# thread exit synchronisation. -# -# Usage: -# Set to any value in the range: 0 <= value < 2^wordsize. -# Set to 0 to emulate reusable thread ID behaviour like Linux or *BSD. -# Set to 1 for unique thread IDs like Solaris (this is the default). -# Set to some factor of 2^wordsize to emulate smaller word size types -# (i.e. will wrap sooner). This might be useful to emulate some embedded -# systems. -# -# define PTW32_THREAD_ID_REUSE_INCREMENT 0 -# -# ---------------------------------------------------------------------- - */ -#undef PTW32_THREAD_ID_REUSE_INCREMENT - - -/********************************************************************* - * Target specific groups - * - * If you find that these are incorrect or incomplete please report it - * to the pthreads-win32 maintainer. Thanks. - *********************************************************************/ -#ifdef WINCE -#define NEED_DUPLICATEHANDLE -#define NEED_CREATETHREAD -#define NEED_ERRNO -#define NEED_CALLOC -#define NEED_FTIME -//#define NEED_SEM -#define NEED_UNICODE_CONSTS -#define NEED_PROCESS_AFFINITY_MASK -#endif - -#ifdef _UWIN -#define HAVE_MODE_T -#define HAVE_STRUCT_TIMESPEC -#endif - -#ifdef __GNUC__ -#define HAVE_C_INLINE -#endif - -#ifdef __MINGW32__ -#define HAVE_MODE_T -#endif - -#ifdef __BORLANDC__ -#endif - -#ifdef __WATCOMC__ -#endif - -#ifdef __DMC__ -#define HAVE_SIGNAL_H -#define HAVE_C_INLINE -#endif - - - -#endif +/* config.h */ + +#ifndef PTW32_CONFIG_H +#define PTW32_CONFIG_H + +/********************************************************************* + * Defaults: see target specific redefinitions below. + *********************************************************************/ + +/* We're building the pthreads-win32 library */ +#define PTW32_BUILD + +/* Do we know about the C type sigset_t? */ +#undef HAVE_SIGSET_T + +/* Define if you have the header file. */ +#define HAVE_SIGNAL_H + +/* Define if you have the Borland TASM32 or compatible assembler. */ +#undef HAVE_TASM32 + +/* Define if you don't have Win32 DuplicateHandle. (eg. WinCE) */ +#undef NEED_DUPLICATEHANDLE + +/* Define if you don't have Win32 _beginthreadex. (eg. WinCE) */ +#undef NEED_CREATETHREAD + +/* Define if you don't have Win32 errno. (eg. WinCE) */ +#undef NEED_ERRNO + +/* Define if you don't have Win32 calloc. (eg. WinCE) */ +#undef NEED_CALLOC + +/* Define if you don't have Win32 ftime. (eg. WinCE) */ +#undef NEED_FTIME + +/* Define if you don't have Win32 semaphores. (eg. WinCE 2.1 or earlier) */ +#undef NEED_SEM + +/* Define if you need to convert string parameters to unicode. (eg. WinCE) */ +#undef NEED_UNICODE_CONSTS + +/* Define if your C (not C++) compiler supports "inline" functions. */ +#define HAVE_C_INLINE + +/* Do we know about type mode_t? */ +#undef HAVE_MODE_T + +/* Define if you have the timespec struct */ +#undef HAVE_STRUCT_TIMESPEC + +/* Define if you don't have the GetProcessAffinityMask() */ +#undef NEED_PROCESS_AFFINITY_MASK + +/* +# ---------------------------------------------------------------------- +# The library can be built with some alternative behaviour to better +# facilitate development of applications on Win32 that will be ported +# to other POSIX systems. +# +# Nothing described here will make the library non-compliant and strictly +# compliant applications will not be affected in any way, but +# applications that make assumptions that POSIX does not guarantee are +# not strictly compliant and may fail or misbehave with some settings. +# +# PTW32_THREAD_ID_REUSE_INCREMENT +# Purpose: +# POSIX says that applications should assume that thread IDs can be +# recycled. However, Solaris (and some other systems) use a [very large] +# sequence number as the thread ID, which provides virtual uniqueness. +# This provides a very high but finite level of safety for applications +# that are not meticulous in tracking thread lifecycles e.g. applications +# that call functions which target detached threads without some form of +# thread exit synchronisation. +# +# Usage: +# Set to any value in the range: 0 <= value < 2^wordsize. +# Set to 0 to emulate reusable thread ID behaviour like Linux or *BSD. +# Set to 1 for unique thread IDs like Solaris (this is the default). +# Set to some factor of 2^wordsize to emulate smaller word size types +# (i.e. will wrap sooner). This might be useful to emulate some embedded +# systems. +# +# define PTW32_THREAD_ID_REUSE_INCREMENT 0 +# +# ---------------------------------------------------------------------- + */ +#undef PTW32_THREAD_ID_REUSE_INCREMENT + + +/********************************************************************* + * Target specific groups + * + * If you find that these are incorrect or incomplete please report it + * to the pthreads-win32 maintainer. Thanks. + *********************************************************************/ +#ifdef WINCE +#define NEED_DUPLICATEHANDLE +#define NEED_CREATETHREAD +#define NEED_ERRNO +#define NEED_CALLOC +#define NEED_FTIME +//#define NEED_SEM +#define NEED_UNICODE_CONSTS +#define NEED_PROCESS_AFFINITY_MASK +#endif + +#ifdef _UWIN +#define HAVE_MODE_T +#define HAVE_STRUCT_TIMESPEC +#endif + +#ifdef __GNUC__ +#define HAVE_C_INLINE +#endif + +#ifdef __MINGW32__ +#define HAVE_MODE_T +#endif + +#ifdef __BORLANDC__ +#endif + +#ifdef __WATCOMC__ +#endif + +#ifdef __DMC__ +#define HAVE_SIGNAL_H +#define HAVE_C_INLINE +#endif + + + +#endif diff --git a/pcsx2/windows/pthreads/create.c b/pcsx2/windows/pthreads/create.c index 78ea45ea8f..9e9388b20c 100644 --- a/pcsx2/windows/pthreads/create.c +++ b/pcsx2/windows/pthreads/create.c @@ -1,305 +1,305 @@ -/* - * create.c - * - * Description: - * This translation unit implements routines associated with spawning a new - * thread. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" -#ifndef _UWIN -#include -#endif - -int -pthread_create (pthread_t * tid, - const pthread_attr_t * attr, - void *(*start) (void *), void *arg) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function creates a thread running the start function, - * passing it the parameter value, 'arg'. The 'attr' - * argument specifies optional creation attributes. - * The identity of the new thread is returned - * via 'tid', which should not be NULL. - * - * PARAMETERS - * tid - * pointer to an instance of pthread_t - * - * attr - * optional pointer to an instance of pthread_attr_t - * - * start - * pointer to the starting routine for the new thread - * - * arg - * optional parameter passed to 'start' - * - * - * DESCRIPTION - * This function creates a thread running the start function, - * passing it the parameter value, 'arg'. The 'attr' - * argument specifies optional creation attributes. - * The identity of the new thread is returned - * via 'tid', which should not be the NULL pointer. - * - * RESULTS - * 0 successfully created thread, - * EINVAL attr invalid, - * EAGAIN insufficient resources. - * - * ------------------------------------------------------ - */ -{ - pthread_t thread; - ptw32_thread_t * tp; - register pthread_attr_t a; - HANDLE threadH = 0; - int result = EAGAIN; - int run = PTW32_TRUE; - ThreadParms *parms = NULL; - long stackSize; - int priority; - pthread_t self; - - /* - * Before doing anything, check that tid can be stored through - * without invoking a memory protection error (segfault). - * Make sure that the assignment below can't be optimised out by the compiler. - * This is assured by conditionally assigning *tid again at the end. - */ - tid->x = 0; - - if (attr != NULL) - { - a = *attr; - } - else - { - a = NULL; - } - - if ((thread = ptw32_new ()).p == NULL) - { - goto FAIL0; - } - - tp = (ptw32_thread_t *) thread.p; - - priority = tp->sched_priority; - - if ((parms = (ThreadParms *) malloc (sizeof (*parms))) == NULL) - { - goto FAIL0; - } - - parms->tid = thread; - parms->start = start; - parms->arg = arg; - -#if defined(HAVE_SIGSET_T) - - /* - * Threads inherit their initial sigmask from their creator thread. - */ - self = pthread_self(); - tp->sigmask = ((ptw32_thread_t *)self.p)->sigmask; - -#endif /* HAVE_SIGSET_T */ - - - if (a != NULL) - { - stackSize = a->stacksize; - tp->detachState = a->detachstate; - priority = a->param.sched_priority; - -#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) - /* WinCE */ -#else - /* Everything else */ - - /* - * Thread priority must be set to a valid system level - * without altering the value set by pthread_attr_setschedparam(). - */ - - /* - * PTHREAD_EXPLICIT_SCHED is the default because Win32 threads - * don't inherit their creator's priority. They are started with - * THREAD_PRIORITY_NORMAL (win32 value). The result of not supplying - * an 'attr' arg to pthread_create() is equivalent to defaulting to - * PTHREAD_EXPLICIT_SCHED and priority THREAD_PRIORITY_NORMAL. - */ - if (PTHREAD_INHERIT_SCHED == a->inheritsched) - { - /* - * If the thread that called pthread_create() is a Win32 thread - * then the inherited priority could be the result of a temporary - * system adjustment. This is not the case for POSIX threads. - */ -#if ! defined(HAVE_SIGSET_T) - self = pthread_self (); -#endif - priority = ((ptw32_thread_t *) self.p)->sched_priority; - } - -#endif - - } - else - { - /* - * Default stackSize - */ - stackSize = PTHREAD_STACK_MIN; - } - - tp->state = run ? PThreadStateInitial : PThreadStateSuspended; - - tp->keys = NULL; - - /* - * Threads must be started in suspended mode and resumed if necessary - * after _beginthreadex returns us the handle. Otherwise we set up a - * race condition between the creating and the created threads. - * Note that we also retain a local copy of the handle for use - * by us in case thread.p->threadH gets NULLed later but before we've - * finished with it here. - */ - -#if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__) - - tp->threadH = - threadH = - (HANDLE) _beginthreadex ((void *) NULL, /* No security info */ - (unsigned) stackSize, /* default stack size */ - ptw32_threadStart, - parms, - (unsigned) - CREATE_SUSPENDED, - (unsigned *) &(tp->thread)); - - if (threadH != 0) - { - if (a != NULL) - { - (void) ptw32_setthreadpriority (thread, SCHED_OTHER, priority); - } - - if (run) - { - ResumeThread (threadH); - } - } - -#else /* __MINGW32__ && ! __MSVCRT__ */ - - /* - * This lock will force pthread_threadStart() to wait until we have - * the thread handle and have set the priority. - */ - (void) pthread_mutex_lock (&tp->cancelLock); - - tp->threadH = - threadH = - (HANDLE) _beginthread (ptw32_threadStart, (unsigned) stackSize, /* default stack size */ - parms); - - /* - * Make the return code match _beginthreadex's. - */ - if (threadH == (HANDLE) - 1L) - { - tp->threadH = threadH = 0; - } - else - { - if (!run) - { - /* - * beginthread does not allow for create flags, so we do it now. - * Note that beginthread itself creates the thread in SUSPENDED - * mode, and then calls ResumeThread to start it. - */ - SuspendThread (threadH); - } - - if (a != NULL) - { - (void) ptw32_setthreadpriority (thread, SCHED_OTHER, priority); - } - } - - (void) pthread_mutex_unlock (&tp->cancelLock); - -#endif /* __MINGW32__ && ! __MSVCRT__ */ - - result = (threadH != 0) ? 0 : EAGAIN; - - /* - * Fall Through Intentionally - */ - - /* - * ------------ - * Failure Code - * ------------ - */ - -FAIL0: - if (result != 0) - { - - ptw32_threadDestroy (thread); - tp = NULL; - - if (parms != NULL) - { - free (parms); - } - } - else - { - *tid = thread; - } - -#ifdef _UWIN - if (result == 0) - pthread_count++; -#endif - return (result); - -} /* pthread_create */ +/* + * create.c + * + * Description: + * This translation unit implements routines associated with spawning a new + * thread. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#ifndef _UWIN +#include +#endif + +int +pthread_create (pthread_t * tid, + const pthread_attr_t * attr, + void *(*start) (void *), void *arg) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function creates a thread running the start function, + * passing it the parameter value, 'arg'. The 'attr' + * argument specifies optional creation attributes. + * The identity of the new thread is returned + * via 'tid', which should not be NULL. + * + * PARAMETERS + * tid + * pointer to an instance of pthread_t + * + * attr + * optional pointer to an instance of pthread_attr_t + * + * start + * pointer to the starting routine for the new thread + * + * arg + * optional parameter passed to 'start' + * + * + * DESCRIPTION + * This function creates a thread running the start function, + * passing it the parameter value, 'arg'. The 'attr' + * argument specifies optional creation attributes. + * The identity of the new thread is returned + * via 'tid', which should not be the NULL pointer. + * + * RESULTS + * 0 successfully created thread, + * EINVAL attr invalid, + * EAGAIN insufficient resources. + * + * ------------------------------------------------------ + */ +{ + pthread_t thread; + ptw32_thread_t * tp; + register pthread_attr_t a; + HANDLE threadH = 0; + int result = EAGAIN; + int run = PTW32_TRUE; + ThreadParms *parms = NULL; + long stackSize; + int priority; + pthread_t self; + + /* + * Before doing anything, check that tid can be stored through + * without invoking a memory protection error (segfault). + * Make sure that the assignment below can't be optimised out by the compiler. + * This is assured by conditionally assigning *tid again at the end. + */ + tid->x = 0; + + if (attr != NULL) + { + a = *attr; + } + else + { + a = NULL; + } + + if ((thread = ptw32_new ()).p == NULL) + { + goto FAIL0; + } + + tp = (ptw32_thread_t *) thread.p; + + priority = tp->sched_priority; + + if ((parms = (ThreadParms *) malloc (sizeof (*parms))) == NULL) + { + goto FAIL0; + } + + parms->tid = thread; + parms->start = start; + parms->arg = arg; + +#if defined(HAVE_SIGSET_T) + + /* + * Threads inherit their initial sigmask from their creator thread. + */ + self = pthread_self(); + tp->sigmask = ((ptw32_thread_t *)self.p)->sigmask; + +#endif /* HAVE_SIGSET_T */ + + + if (a != NULL) + { + stackSize = a->stacksize; + tp->detachState = a->detachstate; + priority = a->param.sched_priority; + +#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) + /* WinCE */ +#else + /* Everything else */ + + /* + * Thread priority must be set to a valid system level + * without altering the value set by pthread_attr_setschedparam(). + */ + + /* + * PTHREAD_EXPLICIT_SCHED is the default because Win32 threads + * don't inherit their creator's priority. They are started with + * THREAD_PRIORITY_NORMAL (win32 value). The result of not supplying + * an 'attr' arg to pthread_create() is equivalent to defaulting to + * PTHREAD_EXPLICIT_SCHED and priority THREAD_PRIORITY_NORMAL. + */ + if (PTHREAD_INHERIT_SCHED == a->inheritsched) + { + /* + * If the thread that called pthread_create() is a Win32 thread + * then the inherited priority could be the result of a temporary + * system adjustment. This is not the case for POSIX threads. + */ +#if ! defined(HAVE_SIGSET_T) + self = pthread_self (); +#endif + priority = ((ptw32_thread_t *) self.p)->sched_priority; + } + +#endif + + } + else + { + /* + * Default stackSize + */ + stackSize = PTHREAD_STACK_MIN; + } + + tp->state = run ? PThreadStateInitial : PThreadStateSuspended; + + tp->keys = NULL; + + /* + * Threads must be started in suspended mode and resumed if necessary + * after _beginthreadex returns us the handle. Otherwise we set up a + * race condition between the creating and the created threads. + * Note that we also retain a local copy of the handle for use + * by us in case thread.p->threadH gets NULLed later but before we've + * finished with it here. + */ + +#if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__) + + tp->threadH = + threadH = + (HANDLE) _beginthreadex ((void *) NULL, /* No security info */ + (unsigned) stackSize, /* default stack size */ + ptw32_threadStart, + parms, + (unsigned) + CREATE_SUSPENDED, + (unsigned *) &(tp->thread)); + + if (threadH != 0) + { + if (a != NULL) + { + (void) ptw32_setthreadpriority (thread, SCHED_OTHER, priority); + } + + if (run) + { + ResumeThread (threadH); + } + } + +#else /* __MINGW32__ && ! __MSVCRT__ */ + + /* + * This lock will force pthread_threadStart() to wait until we have + * the thread handle and have set the priority. + */ + (void) pthread_mutex_lock (&tp->cancelLock); + + tp->threadH = + threadH = + (HANDLE) _beginthread (ptw32_threadStart, (unsigned) stackSize, /* default stack size */ + parms); + + /* + * Make the return code match _beginthreadex's. + */ + if (threadH == (HANDLE) - 1L) + { + tp->threadH = threadH = 0; + } + else + { + if (!run) + { + /* + * beginthread does not allow for create flags, so we do it now. + * Note that beginthread itself creates the thread in SUSPENDED + * mode, and then calls ResumeThread to start it. + */ + SuspendThread (threadH); + } + + if (a != NULL) + { + (void) ptw32_setthreadpriority (thread, SCHED_OTHER, priority); + } + } + + (void) pthread_mutex_unlock (&tp->cancelLock); + +#endif /* __MINGW32__ && ! __MSVCRT__ */ + + result = (threadH != 0) ? 0 : EAGAIN; + + /* + * Fall Through Intentionally + */ + + /* + * ------------ + * Failure Code + * ------------ + */ + +FAIL0: + if (result != 0) + { + + ptw32_threadDestroy (thread); + tp = NULL; + + if (parms != NULL) + { + free (parms); + } + } + else + { + *tid = thread; + } + +#ifdef _UWIN + if (result == 0) + pthread_count++; +#endif + return (result); + +} /* pthread_create */ diff --git a/pcsx2/windows/pthreads/dll.c b/pcsx2/windows/pthreads/dll.c index 067c98f0dd..c1cd4e96e2 100644 --- a/pcsx2/windows/pthreads/dll.c +++ b/pcsx2/windows/pthreads/dll.c @@ -1,92 +1,92 @@ -/* - * dll.c - * - * Description: - * This translation unit implements DLL initialisation. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#ifndef PTW32_STATIC_LIB - -#include "pthread.h" -#include "implement.h" - -#ifdef _MSC_VER -/* - * lpvReserved yields an unreferenced formal parameter; - * ignore it - */ -#pragma warning( disable : 4100 ) -#endif - -#ifdef __cplusplus -/* - * Dear c++: Please don't mangle this name. -thanks - */ -extern "C" -#endif /* __cplusplus */ - BOOL WINAPI -DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved) -{ - BOOL result = PTW32_TRUE; - - switch (fdwReason) - { - - case DLL_PROCESS_ATTACH: - result = pthread_win32_process_attach_np (); - break; - - case DLL_THREAD_ATTACH: - /* - * A thread is being created - */ - result = pthread_win32_thread_attach_np (); - break; - - case DLL_THREAD_DETACH: - /* - * A thread is exiting cleanly - */ - result = pthread_win32_thread_detach_np (); - break; - - case DLL_PROCESS_DETACH: - (void) pthread_win32_thread_detach_np (); - result = pthread_win32_process_detach_np (); - break; - } - - return (result); - -} /* DllMain */ - -#endif /* PTW32_STATIC_LIB */ +/* + * dll.c + * + * Description: + * This translation unit implements DLL initialisation. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef PTW32_STATIC_LIB + +#include "pthread.h" +#include "implement.h" + +#ifdef _MSC_VER +/* + * lpvReserved yields an unreferenced formal parameter; + * ignore it + */ +#pragma warning( disable : 4100 ) +#endif + +#ifdef __cplusplus +/* + * Dear c++: Please don't mangle this name. -thanks + */ +extern "C" +#endif /* __cplusplus */ + BOOL WINAPI +DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved) +{ + BOOL result = PTW32_TRUE; + + switch (fdwReason) + { + + case DLL_PROCESS_ATTACH: + result = pthread_win32_process_attach_np (); + break; + + case DLL_THREAD_ATTACH: + /* + * A thread is being created + */ + result = pthread_win32_thread_attach_np (); + break; + + case DLL_THREAD_DETACH: + /* + * A thread is exiting cleanly + */ + result = pthread_win32_thread_detach_np (); + break; + + case DLL_PROCESS_DETACH: + (void) pthread_win32_thread_detach_np (); + result = pthread_win32_process_detach_np (); + break; + } + + return (result); + +} /* DllMain */ + +#endif /* PTW32_STATIC_LIB */ diff --git a/pcsx2/windows/pthreads/errno.c b/pcsx2/windows/pthreads/errno.c index 11fdd8af42..9998bb8d53 100644 --- a/pcsx2/windows/pthreads/errno.c +++ b/pcsx2/windows/pthreads/errno.c @@ -1,94 +1,94 @@ -/* - * errno.c - * - * Description: - * This translation unit implements routines associated with spawning a new - * thread. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#if defined(NEED_ERRNO) - -#include "pthread.h" -#include "implement.h" - -static int reallyBad = ENOMEM; - -/* - * Re-entrant errno. - * - * Each thread has it's own errno variable in pthread_t. - * - * The benefit of using the pthread_t structure - * instead of another TSD key is TSD keys are limited - * on Win32 to 64 per process. Secondly, to implement - * it properly without using pthread_t you'd need - * to dynamically allocate an int on starting the thread - * and store it manually into TLS and then ensure that you free - * it on thread termination. We get all that for free - * by simply storing the errno on the pthread_t structure. - * - * MSVC and Mingw32 already have their own thread-safe errno. - * - * #if defined( _REENTRANT ) || defined( _MT ) - * #define errno *_errno() - * - * int *_errno( void ); - * #else - * extern int errno; - * #endif - * - */ - -int * -_errno (void) -{ - pthread_t self; - int *result; - - if ((self = pthread_self ()) == NULL) - { - /* - * Yikes! unable to allocate a thread! - * Throw an exception? return an error? - */ - result = &reallyBad; - } - else - { - result = &(self->ptErrno); - } - - return (result); - -} /* _errno */ - -#endif /* (NEED_ERRNO) */ +/* + * errno.c + * + * Description: + * This translation unit implements routines associated with spawning a new + * thread. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if defined(NEED_ERRNO) + +#include "pthread.h" +#include "implement.h" + +static int reallyBad = ENOMEM; + +/* + * Re-entrant errno. + * + * Each thread has it's own errno variable in pthread_t. + * + * The benefit of using the pthread_t structure + * instead of another TSD key is TSD keys are limited + * on Win32 to 64 per process. Secondly, to implement + * it properly without using pthread_t you'd need + * to dynamically allocate an int on starting the thread + * and store it manually into TLS and then ensure that you free + * it on thread termination. We get all that for free + * by simply storing the errno on the pthread_t structure. + * + * MSVC and Mingw32 already have their own thread-safe errno. + * + * #if defined( _REENTRANT ) || defined( _MT ) + * #define errno *_errno() + * + * int *_errno( void ); + * #else + * extern int errno; + * #endif + * + */ + +int * +_errno (void) +{ + pthread_t self; + int *result; + + if ((self = pthread_self ()) == NULL) + { + /* + * Yikes! unable to allocate a thread! + * Throw an exception? return an error? + */ + result = &reallyBad; + } + else + { + result = &(self->ptErrno); + } + + return (result); + +} /* _errno */ + +#endif /* (NEED_ERRNO) */ diff --git a/pcsx2/windows/pthreads/exit.c b/pcsx2/windows/pthreads/exit.c index 28c7196f2a..7eb9671bb9 100644 --- a/pcsx2/windows/pthreads/exit.c +++ b/pcsx2/windows/pthreads/exit.c @@ -1,44 +1,44 @@ -/* - * exit.c - * - * Description: - * This translation unit implements routines associated with exiting from - * a thread. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" -#ifndef _UWIN -# include -#endif - -#include "pthread_exit.c" +/* + * exit.c + * + * Description: + * This translation unit implements routines associated with exiting from + * a thread. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#ifndef _UWIN +# include +#endif + +#include "pthread_exit.c" diff --git a/pcsx2/windows/pthreads/fork.c b/pcsx2/windows/pthreads/fork.c index 97d9ec23ae..8a29550caf 100644 --- a/pcsx2/windows/pthreads/fork.c +++ b/pcsx2/windows/pthreads/fork.c @@ -1,39 +1,39 @@ -/* - * fork.c - * - * Description: - * Implementation of fork() for POSIX threads. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - - -#include "pthread.h" -#include "implement.h" +/* + * fork.c + * + * Description: + * Implementation of fork() for POSIX threads. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#include "pthread.h" +#include "implement.h" diff --git a/pcsx2/windows/pthreads/global.c b/pcsx2/windows/pthreads/global.c index 8d8a245d6a..c521d89615 100644 --- a/pcsx2/windows/pthreads/global.c +++ b/pcsx2/windows/pthreads/global.c @@ -1,117 +1,117 @@ -/* - * global.c - * - * Description: - * This translation unit instantiates data associated with the implementation - * as a whole. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int ptw32_processInitialized = PTW32_FALSE; -ptw32_thread_t * ptw32_threadReuseTop = PTW32_THREAD_REUSE_EMPTY; -ptw32_thread_t * ptw32_threadReuseBottom = PTW32_THREAD_REUSE_EMPTY; -pthread_key_t ptw32_selfThreadKey = NULL; -pthread_key_t ptw32_cleanupKey = NULL; -pthread_cond_t ptw32_cond_list_head = NULL; -pthread_cond_t ptw32_cond_list_tail = NULL; - -int ptw32_concurrency = 0; - -/* What features have been auto-detaected */ -int ptw32_features = 0; - -BOOL ptw32_smp_system = PTW32_TRUE; /* Safer if assumed true initially. */ - -#if 0 -/* - * Function pointer to InterlockedCompareExchange if it exists, otherwise - * it will be set at runtime to a substitute local version with the same - * functionality but may be architecture specific. - */ -PTW32_INTERLOCKED_LONG - (WINAPI * ptw32_interlocked_compare_exchange) (PTW32_INTERLOCKED_LPLONG, - PTW32_INTERLOCKED_LONG, - PTW32_INTERLOCKED_LONG) = - NULL; -#endif - -/* - * Function pointer to QueueUserAPCEx if it exists, otherwise - * it will be set at runtime to a substitute routine which cannot unblock - * blocked threads. - */ -DWORD (*ptw32_register_cancelation) (PAPCFUNC, HANDLE, DWORD) = NULL; - -/* - * Global lock for managing pthread_t struct reuse. - */ -CRITICAL_SECTION ptw32_thread_reuse_lock; - -/* - * Global lock for testing internal state of statically declared mutexes. - */ -CRITICAL_SECTION ptw32_mutex_test_init_lock; - -/* - * Global lock for testing internal state of PTHREAD_COND_INITIALIZER - * created condition variables. - */ -CRITICAL_SECTION ptw32_cond_test_init_lock; - -/* - * Global lock for testing internal state of PTHREAD_RWLOCK_INITIALIZER - * created read/write locks. - */ -CRITICAL_SECTION ptw32_rwlock_test_init_lock; - -/* - * Global lock for testing internal state of PTHREAD_SPINLOCK_INITIALIZER - * created spin locks. - */ -CRITICAL_SECTION ptw32_spinlock_test_init_lock; - -/* - * Global lock for condition variable linked list. The list exists - * to wake up CVs when a WM_TIMECHANGE message arrives. See - * w32_TimeChangeHandler.c. - */ -CRITICAL_SECTION ptw32_cond_list_lock; - -#ifdef _UWIN -/* - * Keep a count of the number of threads. - */ -int pthread_count = 0; -#endif +/* + * global.c + * + * Description: + * This translation unit instantiates data associated with the implementation + * as a whole. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int ptw32_processInitialized = PTW32_FALSE; +ptw32_thread_t * ptw32_threadReuseTop = PTW32_THREAD_REUSE_EMPTY; +ptw32_thread_t * ptw32_threadReuseBottom = PTW32_THREAD_REUSE_EMPTY; +pthread_key_t ptw32_selfThreadKey = NULL; +pthread_key_t ptw32_cleanupKey = NULL; +pthread_cond_t ptw32_cond_list_head = NULL; +pthread_cond_t ptw32_cond_list_tail = NULL; + +int ptw32_concurrency = 0; + +/* What features have been auto-detaected */ +int ptw32_features = 0; + +BOOL ptw32_smp_system = PTW32_TRUE; /* Safer if assumed true initially. */ + +#if 0 +/* + * Function pointer to InterlockedCompareExchange if it exists, otherwise + * it will be set at runtime to a substitute local version with the same + * functionality but may be architecture specific. + */ +PTW32_INTERLOCKED_LONG + (WINAPI * ptw32_interlocked_compare_exchange) (PTW32_INTERLOCKED_LPLONG, + PTW32_INTERLOCKED_LONG, + PTW32_INTERLOCKED_LONG) = + NULL; +#endif + +/* + * Function pointer to QueueUserAPCEx if it exists, otherwise + * it will be set at runtime to a substitute routine which cannot unblock + * blocked threads. + */ +DWORD (*ptw32_register_cancelation) (PAPCFUNC, HANDLE, DWORD) = NULL; + +/* + * Global lock for managing pthread_t struct reuse. + */ +CRITICAL_SECTION ptw32_thread_reuse_lock; + +/* + * Global lock for testing internal state of statically declared mutexes. + */ +CRITICAL_SECTION ptw32_mutex_test_init_lock; + +/* + * Global lock for testing internal state of PTHREAD_COND_INITIALIZER + * created condition variables. + */ +CRITICAL_SECTION ptw32_cond_test_init_lock; + +/* + * Global lock for testing internal state of PTHREAD_RWLOCK_INITIALIZER + * created read/write locks. + */ +CRITICAL_SECTION ptw32_rwlock_test_init_lock; + +/* + * Global lock for testing internal state of PTHREAD_SPINLOCK_INITIALIZER + * created spin locks. + */ +CRITICAL_SECTION ptw32_spinlock_test_init_lock; + +/* + * Global lock for condition variable linked list. The list exists + * to wake up CVs when a WM_TIMECHANGE message arrives. See + * w32_TimeChangeHandler.c. + */ +CRITICAL_SECTION ptw32_cond_list_lock; + +#ifdef _UWIN +/* + * Keep a count of the number of threads. + */ +int pthread_count = 0; +#endif diff --git a/pcsx2/windows/pthreads/implement.h b/pcsx2/windows/pthreads/implement.h index 9652583fe2..bb3a5deeb3 100644 --- a/pcsx2/windows/pthreads/implement.h +++ b/pcsx2/windows/pthreads/implement.h @@ -1,717 +1,717 @@ -/* - * implement.h - * - * Definitions that don't need to be public. - * - * Keeps all the internals out of pthread.h - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#ifndef _IMPLEMENT_H -#define _IMPLEMENT_H - -#ifdef _WIN32_WINNT -#undef _WIN32_WINNT -#endif -#define _WIN32_WINNT 0x400 - -#include - -/* - * In case windows.h doesn't define it (e.g. WinCE perhaps) - */ -#ifdef WINCE -typedef VOID (APIENTRY *PAPCFUNC)(DWORD dwParam); -#endif - -/* - * note: ETIMEDOUT is correctly defined in winsock.h - */ -#include - -/* - * In case ETIMEDOUT hasn't been defined above somehow. - */ -#ifndef ETIMEDOUT -# define ETIMEDOUT 10060 /* This is the value in winsock.h. */ -#endif - -#if !defined(malloc) -#include -#endif - -#if !defined(INT_MAX) -#include -#endif - -/* use local include files during development */ -#include "semaphore.h" -#include "sched.h" - -#if defined(HAVE_C_INLINE) || defined(__cplusplus) -#define INLINE __forceinline -#else -#define INLINE -#endif - -#if defined (__MINGW32__) || (_MSC_VER >= 1300) -#define PTW32_INTERLOCKED_LONG long -#define PTW32_INTERLOCKED_LPLONG long* -#else -#define PTW32_INTERLOCKED_LONG PVOID -#define PTW32_INTERLOCKED_LPLONG PVOID* -#endif - -#if defined(__MINGW32__) -#include -#elif defined(__BORLANDC__) -#define int64_t ULONGLONG -#else -#define int64_t _int64 -#endif - -typedef enum -{ - /* - * This enumeration represents the state of the thread; - * The thread is still "alive" if the numeric value of the - * state is greater or equal "PThreadStateRunning". - */ - PThreadStateInitial = 0, /* Thread not running */ - PThreadStateRunning, /* Thread alive & kicking */ - PThreadStateSuspended, /* Thread alive but suspended */ - PThreadStateCancelPending, /* Thread alive but is */ - /* has cancelation pending. */ - PThreadStateCanceling, /* Thread alive but is */ - /* in the process of terminating */ - /* due to a cancellation request */ - PThreadStateException, /* Thread alive but exiting */ - /* due to an exception */ - PThreadStateLast -} -PThreadState; - - -typedef struct ptw32_thread_t_ ptw32_thread_t; - -struct ptw32_thread_t_ -{ -#ifdef _UWIN - DWORD dummy[5]; -#endif - DWORD thread; - HANDLE threadH; /* Win32 thread handle - POSIX thread is invalid if threadH == 0 */ - pthread_t ptHandle; /* This thread's permanent pthread_t handle */ - ptw32_thread_t * prevReuse; /* Links threads on reuse stack */ - volatile PThreadState state; - void *exitStatus; - void *parms; - int ptErrno; - int detachState; - pthread_mutex_t threadLock; /* Used for serialised access to public thread state */ - int sched_priority; /* As set, not as currently is */ - pthread_mutex_t cancelLock; /* Used for async-cancel safety */ - int cancelState; - int cancelType; - HANDLE cancelEvent; -#ifdef __CLEANUP_C - jmp_buf start_mark; -#endif /* __CLEANUP_C */ -#if HAVE_SIGSET_T - sigset_t sigmask; -#endif /* HAVE_SIGSET_T */ - int implicit:1; - void *keys; - void *nextAssoc; -}; - - -/* - * Special value to mark attribute objects as valid. - */ -#define PTW32_ATTR_VALID ((unsigned long) 0xC4C0FFEE) - -struct pthread_attr_t_ -{ - unsigned long valid; - void *stackaddr; - size_t stacksize; - int detachstate; - struct sched_param param; - int inheritsched; - int contentionscope; -#if HAVE_SIGSET_T - sigset_t sigmask; -#endif /* HAVE_SIGSET_T */ -}; - - -/* - * ==================== - * ==================== - * Semaphores, Mutexes and Condition Variables - * ==================== - * ==================== - */ - -struct sem_t_ -{ - int value; - pthread_mutex_t lock; - HANDLE sem; -#ifdef NEED_SEM - int leftToUnblock; -#endif -}; - -#define PTW32_OBJECT_AUTO_INIT ((void *) -1) -#define PTW32_OBJECT_INVALID NULL - -struct pthread_mutex_t_ -{ - LONG lock_idx; /* Provides exclusive access to mutex state - via the Interlocked* mechanism. - 0: unlocked/free. - 1: locked - no other waiters. - -1: locked - with possible other waiters. - */ - int recursive_count; /* Number of unlocks a thread needs to perform - before the lock is released (recursive - mutexes only). */ - int kind; /* Mutex type. */ - pthread_t ownerThread; - HANDLE event; /* Mutex release notification to waiting - threads. */ -}; - -struct pthread_mutexattr_t_ -{ - int pshared; - int kind; -}; - -/* - * Possible values, other than PTW32_OBJECT_INVALID, - * for the "interlock" element in a spinlock. - * - * In this implementation, when a spinlock is initialised, - * the number of cpus available to the process is checked. - * If there is only one cpu then "interlock" is set equal to - * PTW32_SPIN_USE_MUTEX and u.mutex is a initialised mutex. - * If the number of cpus is greater than 1 then "interlock" - * is set equal to PTW32_SPIN_UNLOCKED and the number is - * stored in u.cpus. This arrangement allows the spinlock - * routines to attempt an InterlockedCompareExchange on "interlock" - * immediately and, if that fails, to try the inferior mutex. - * - * "u.cpus" isn't used for anything yet, but could be used at - * some point to optimise spinlock behaviour. - */ -#define PTW32_SPIN_UNLOCKED (1) -#define PTW32_SPIN_LOCKED (2) -#define PTW32_SPIN_USE_MUTEX (3) - -struct pthread_spinlock_t_ -{ - long interlock; /* Locking element for multi-cpus. */ - union - { - int cpus; /* No. of cpus if multi cpus, or */ - pthread_mutex_t mutex; /* mutex if single cpu. */ - } u; -}; - -struct pthread_barrier_t_ -{ - unsigned int nCurrentBarrierHeight; - unsigned int nInitialBarrierHeight; - int iStep; - int pshared; - sem_t semBarrierBreeched[2]; -}; - -struct pthread_barrierattr_t_ -{ - int pshared; -}; - -struct pthread_key_t_ -{ - DWORD key; - void (*destructor) (void *); - pthread_mutex_t keyLock; - void *threads; -}; - - -typedef struct ThreadParms ThreadParms; -typedef struct ThreadKeyAssoc ThreadKeyAssoc; - -struct ThreadParms -{ - pthread_t tid; - void *(*start) (void *); - void *arg; -}; - - -struct pthread_cond_t_ -{ - long nWaitersBlocked; /* Number of threads blocked */ - long nWaitersGone; /* Number of threads timed out */ - long nWaitersToUnblock; /* Number of threads to unblock */ - sem_t semBlockQueue; /* Queue up threads waiting for the */ - /* condition to become signalled */ - sem_t semBlockLock; /* Semaphore that guards access to */ - /* | waiters blocked count/block queue */ - /* +-> Mandatory Sync.LEVEL-1 */ - pthread_mutex_t mtxUnblockLock; /* Mutex that guards access to */ - /* | waiters (to)unblock(ed) counts */ - /* +-> Optional* Sync.LEVEL-2 */ - pthread_cond_t next; /* Doubly linked list */ - pthread_cond_t prev; -}; - - -struct pthread_condattr_t_ -{ - int pshared; -}; - -#define PTW32_RWLOCK_MAGIC 0xfacade2 - -struct pthread_rwlock_t_ -{ - pthread_mutex_t mtxExclusiveAccess; - pthread_mutex_t mtxSharedAccessCompleted; - pthread_cond_t cndSharedAccessCompleted; - int nSharedAccessCount; - int nExclusiveAccessCount; - int nCompletedSharedAccessCount; - int nMagic; -}; - -struct pthread_rwlockattr_t_ -{ - int pshared; -}; - -/* - * MCS lock queue node - see ptw32_MCS_lock.c - */ -struct ptw32_mcs_node_t_ -{ - struct ptw32_mcs_node_t_ **lock; /* ptr to tail of queue */ - struct ptw32_mcs_node_t_ *next; /* ptr to successor in queue */ - LONG readyFlag; /* set after lock is released by - predecessor */ - LONG nextFlag; /* set after 'next' ptr is set by - successor */ -}; - -typedef struct ptw32_mcs_node_t_ ptw32_mcs_local_node_t; -typedef struct ptw32_mcs_node_t_ *ptw32_mcs_lock_t; - - -struct ThreadKeyAssoc -{ - /* - * Purpose: - * This structure creates an association between a thread and a key. - * It is used to implement the implicit invocation of a user defined - * destroy routine for thread specific data registered by a user upon - * exiting a thread. - * - * Graphically, the arrangement is as follows, where: - * - * K - Key with destructor - * (head of chain is key->threads) - * T - Thread that has called pthread_setspecific(Kn) - * (head of chain is thread->keys) - * A - Association. Each association is a node at the - * intersection of two doubly-linked lists. - * - * T1 T2 T3 - * | | | - * | | | - * K1 -----+-----A-----A-----> - * | | | - * | | | - * K2 -----A-----A-----+-----> - * | | | - * | | | - * K3 -----A-----+-----A-----> - * | | | - * | | | - * V V V - * - * Access to the association is guarded by two locks: the key's - * general lock (guarding the row) and the thread's general - * lock (guarding the column). This avoids the need for a - * dedicated lock for each association, which not only consumes - * more handles but requires that: before the lock handle can - * be released - both the key must be deleted and the thread - * must have called the destructor. The two-lock arrangement - * allows the resources to be freed as soon as either thread or - * key is concluded. - * - * To avoid deadlock: whenever both locks are required, the key - * and thread locks are always acquired in the order: key lock - * then thread lock. An exception to this exists when a thread - * calls the destructors, however this is done carefully to - * avoid deadlock. - * - * An association is created when a thread first calls - * pthread_setspecific() on a key that has a specified - * destructor. - * - * An association is destroyed either immediately after the - * thread calls the key destructor function on thread exit, or - * when the key is deleted. - * - * Attributes: - * thread - * reference to the thread that owns the - * association. This is actually the pointer to the - * thread struct itself. Since the association is - * destroyed before the thread exits, this can never - * point to a different logical thread to the one that - * created the assoc, i.e. after thread struct reuse. - * - * key - * reference to the key that owns the association. - * - * nextKey - * The pthread_t->keys attribute is the head of a - * chain of associations that runs through the nextKey - * link. This chain provides the 1 to many relationship - * between a pthread_t and all pthread_key_t on which - * it called pthread_setspecific. - * - * prevKey - * Similarly. - * - * nextThread - * The pthread_key_t->threads attribute is the head of - * a chain of assoctiations that runs through the - * nextThreads link. This chain provides the 1 to many - * relationship between a pthread_key_t and all the - * PThreads that have called pthread_setspecific for - * this pthread_key_t. - * - * prevThread - * Similarly. - * - * Notes: - * 1) As soon as either the key or the thread is no longer - * referencing the association, it can be destroyed. The - * association will be removed from both chains. - * - * 2) Under WIN32, an association is only created by - * pthread_setspecific if the user provided a - * destroyRoutine when they created the key. - * - * - */ - ptw32_thread_t * thread; - pthread_key_t key; - ThreadKeyAssoc *nextKey; - ThreadKeyAssoc *nextThread; - ThreadKeyAssoc *prevKey; - ThreadKeyAssoc *prevThread; -}; - - -#ifdef __CLEANUP_SEH -/* - * -------------------------------------------------------------- - * MAKE_SOFTWARE_EXCEPTION - * This macro constructs a software exception code following - * the same format as the standard Win32 error codes as defined - * in WINERROR.H - * Values are 32 bit values layed out as follows: - * - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +---+-+-+-----------------------+-------------------------------+ - * |Sev|C|R| Facility | Code | - * +---+-+-+-----------------------+-------------------------------+ - * - * Severity Values: - */ -#define SE_SUCCESS 0x00 -#define SE_INFORMATION 0x01 -#define SE_WARNING 0x02 -#define SE_ERROR 0x03 - -#define MAKE_SOFTWARE_EXCEPTION( _severity, _facility, _exception ) \ -( (DWORD) ( ( (_severity) << 30 ) | /* Severity code */ \ - ( 1 << 29 ) | /* MS=0, User=1 */ \ - ( 0 << 28 ) | /* Reserved */ \ - ( (_facility) << 16 ) | /* Facility Code */ \ - ( (_exception) << 0 ) /* Exception Code */ \ - ) ) - -/* - * We choose one specific Facility/Error code combination to - * identify our software exceptions vs. WIN32 exceptions. - * We store our actual component and error code within - * the optional information array. - */ -#define EXCEPTION_PTW32_SERVICES \ - MAKE_SOFTWARE_EXCEPTION( SE_ERROR, \ - PTW32_SERVICES_FACILITY, \ - PTW32_SERVICES_ERROR ) - -#define PTW32_SERVICES_FACILITY 0xBAD -#define PTW32_SERVICES_ERROR 0xDEED - -#endif /* __CLEANUP_SEH */ - -/* - * Services available through EXCEPTION_PTW32_SERVICES - * and also used [as parameters to ptw32_throw()] as - * generic exception selectors. - */ - -#define PTW32_EPS_EXIT (1) -#define PTW32_EPS_CANCEL (2) - - -/* Useful macros */ -#define PTW32_MAX(a,b) ((a)<(b)?(b):(a)) -#define PTW32_MIN(a,b) ((a)>(b)?(b):(a)) - - -#if 0 -/* Declared in global.c */ -extern PTW32_INTERLOCKED_LONG (WINAPI * - ptw32_interlocked_compare_exchange) - (PTW32_INTERLOCKED_LPLONG, PTW32_INTERLOCKED_LONG, PTW32_INTERLOCKED_LONG); -#endif - -/* Declared in pthread_cancel.c */ -extern DWORD (*ptw32_register_cancelation) (PAPCFUNC, HANDLE, DWORD); - -/* Thread Reuse stack bottom marker. Must not be NULL or any valid pointer to memory. */ -#define PTW32_THREAD_REUSE_EMPTY ((ptw32_thread_t *) 1) - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - -extern int ptw32_processInitialized; -extern ptw32_thread_t * ptw32_threadReuseTop; -extern ptw32_thread_t * ptw32_threadReuseBottom; -extern pthread_key_t ptw32_selfThreadKey; -extern pthread_key_t ptw32_cleanupKey; -extern pthread_cond_t ptw32_cond_list_head; -extern pthread_cond_t ptw32_cond_list_tail; - -extern int ptw32_mutex_default_kind; - -extern int ptw32_concurrency; - -extern int ptw32_features; - -extern BOOL ptw32_smp_system; /* True: SMP system, False: Uni-processor system */ - -extern CRITICAL_SECTION ptw32_thread_reuse_lock; -extern CRITICAL_SECTION ptw32_mutex_test_init_lock; -extern CRITICAL_SECTION ptw32_cond_list_lock; -extern CRITICAL_SECTION ptw32_cond_test_init_lock; -extern CRITICAL_SECTION ptw32_rwlock_test_init_lock; -extern CRITICAL_SECTION ptw32_spinlock_test_init_lock; - -#ifdef _UWIN -extern int pthread_count; -#endif - - -/* - * ===================== - * ===================== - * Forward Declarations - * ===================== - * ===================== - */ - - int ptw32_is_attr (const pthread_attr_t * attr); - - int ptw32_cond_check_need_init (pthread_cond_t * cond); - int ptw32_mutex_check_need_init (pthread_mutex_t * mutex); - int ptw32_rwlock_check_need_init (pthread_rwlock_t * rwlock); - - PTW32_INTERLOCKED_LONG WINAPI - ptw32_InterlockedCompareExchange (volatile PTW32_INTERLOCKED_LPLONG location, - PTW32_INTERLOCKED_LONG value, - PTW32_INTERLOCKED_LONG comparand); - - LONG WINAPI - ptw32_InterlockedExchange (volatile PTW32_INTERLOCKED_LPLONG location, - LONG value); - - DWORD - ptw32_RegisterCancelation (PAPCFUNC callback, - HANDLE threadH, DWORD callback_arg); - - int ptw32_processInitialize (void); - - void ptw32_processTerminate (void); - - void ptw32_threadDestroy (pthread_t tid); - - void ptw32_pop_cleanup_all (int execute); - - pthread_t ptw32_new (void); - - pthread_t ptw32_threadReusePop (void); - - void ptw32_threadReusePush (pthread_t thread); - - int ptw32_getprocessors (int *count); - - int ptw32_setthreadpriority (pthread_t thread, int policy, int priority); - - void ptw32_rwlock_cancelwrwait (void *arg); - -#if ! defined (__MINGW32__) || defined (__MSVCRT__) - unsigned __stdcall -#else - void -#endif - ptw32_threadStart (void *vthreadParms); - - void ptw32_callUserDestroyRoutines (pthread_t thread); - - int ptw32_tkAssocCreate (ptw32_thread_t * thread, pthread_key_t key); - - void ptw32_tkAssocDestroy (ThreadKeyAssoc * assoc); - - int ptw32_semwait (sem_t * sem); - - DWORD ptw32_relmillisecs (const struct timespec * abstime); - - void ptw32_mcs_lock_acquire (ptw32_mcs_lock_t * lock, ptw32_mcs_local_node_t * node); - - void ptw32_mcs_lock_release (ptw32_mcs_local_node_t * node); - - // added to remove some warnings (air) - int ptw32_spinlock_check_need_init (pthread_spinlock_t * lock); - -#ifdef NEED_FTIME - void ptw32_timespec_to_filetime (const struct timespec *ts, FILETIME * ft); - void ptw32_filetime_to_timespec (const FILETIME * ft, struct timespec *ts); -#endif - -/* Declared in misc.c */ -#ifdef NEED_CALLOC -#define calloc(n, s) ptw32_calloc(n, s) - void *ptw32_calloc (size_t n, size_t s); -#endif - -/* Declared in private.c */ - void ptw32_throw (DWORD exception); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - - -#ifdef _UWIN_ -# ifdef _MT -# ifdef __cplusplus -extern "C" -{ -# endif - _CRTIMP unsigned long __cdecl _beginthread (void (__cdecl *) (void *), - unsigned, void *); - _CRTIMP void __cdecl _endthread (void); - _CRTIMP unsigned long __cdecl _beginthreadex (void *, unsigned, - unsigned (__stdcall *) (void *), - void *, unsigned, unsigned *); - _CRTIMP void __cdecl _endthreadex (unsigned); -# ifdef __cplusplus -} -# endif -# endif -#else -# include -#endif - - -/* - * Defaults. Could be overridden when building the inlined version of the dll. - * See ptw32_InterlockedCompareExchange.c - */ -// Default to inlining the pthreads versions... (air) -#ifndef PTW32_INTERLOCKED_COMPARE_EXCHANGE -#define PTW32_INTERLOCKED_COMPARE_EXCHANGE ptw32_InterlockedCompareExchange -#endif - -#ifndef PTW32_INTERLOCKED_EXCHANGE -#define PTW32_INTERLOCKED_EXCHANGE ptw32_InterlockedExchange -#endif - - -/* - * Check for old and new versions of cygwin. See the FAQ file: - * - * Question 1 - How do I get pthreads-win32 to link under Cygwin or Mingw32? - * - * Patch by Anders Norlander - */ -#if defined(__CYGWIN32__) || defined(__CYGWIN__) || defined(NEED_CREATETHREAD) - -/* - * Macro uses args so we can cast start_proc to LPTHREAD_START_ROUTINE - * in order to avoid warnings because of return type - */ - -#define _beginthreadex(security, \ - stack_size, \ - start_proc, \ - arg, \ - flags, \ - pid) \ - CreateThread(security, \ - stack_size, \ - (LPTHREAD_START_ROUTINE) start_proc, \ - arg, \ - flags, \ - pid) - -#define _endthreadex ExitThread - -#endif /* __CYGWIN32__ || __CYGWIN__ || NEED_CREATETHREAD */ - - -#endif /* _IMPLEMENT_H */ +/* + * implement.h + * + * Definitions that don't need to be public. + * + * Keeps all the internals out of pthread.h + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef _IMPLEMENT_H +#define _IMPLEMENT_H + +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif +#define _WIN32_WINNT 0x400 + +#include + +/* + * In case windows.h doesn't define it (e.g. WinCE perhaps) + */ +#ifdef WINCE +typedef VOID (APIENTRY *PAPCFUNC)(DWORD dwParam); +#endif + +/* + * note: ETIMEDOUT is correctly defined in winsock.h + */ +#include + +/* + * In case ETIMEDOUT hasn't been defined above somehow. + */ +#ifndef ETIMEDOUT +# define ETIMEDOUT 10060 /* This is the value in winsock.h. */ +#endif + +#if !defined(malloc) +#include +#endif + +#if !defined(INT_MAX) +#include +#endif + +/* use local include files during development */ +#include "semaphore.h" +#include "sched.h" + +#if defined(HAVE_C_INLINE) || defined(__cplusplus) +#define INLINE __forceinline +#else +#define INLINE +#endif + +#if defined (__MINGW32__) || (_MSC_VER >= 1300) +#define PTW32_INTERLOCKED_LONG long +#define PTW32_INTERLOCKED_LPLONG long* +#else +#define PTW32_INTERLOCKED_LONG PVOID +#define PTW32_INTERLOCKED_LPLONG PVOID* +#endif + +#if defined(__MINGW32__) +#include +#elif defined(__BORLANDC__) +#define int64_t ULONGLONG +#else +#define int64_t _int64 +#endif + +typedef enum +{ + /* + * This enumeration represents the state of the thread; + * The thread is still "alive" if the numeric value of the + * state is greater or equal "PThreadStateRunning". + */ + PThreadStateInitial = 0, /* Thread not running */ + PThreadStateRunning, /* Thread alive & kicking */ + PThreadStateSuspended, /* Thread alive but suspended */ + PThreadStateCancelPending, /* Thread alive but is */ + /* has cancelation pending. */ + PThreadStateCanceling, /* Thread alive but is */ + /* in the process of terminating */ + /* due to a cancellation request */ + PThreadStateException, /* Thread alive but exiting */ + /* due to an exception */ + PThreadStateLast +} +PThreadState; + + +typedef struct ptw32_thread_t_ ptw32_thread_t; + +struct ptw32_thread_t_ +{ +#ifdef _UWIN + DWORD dummy[5]; +#endif + DWORD thread; + HANDLE threadH; /* Win32 thread handle - POSIX thread is invalid if threadH == 0 */ + pthread_t ptHandle; /* This thread's permanent pthread_t handle */ + ptw32_thread_t * prevReuse; /* Links threads on reuse stack */ + volatile PThreadState state; + void *exitStatus; + void *parms; + int ptErrno; + int detachState; + pthread_mutex_t threadLock; /* Used for serialised access to public thread state */ + int sched_priority; /* As set, not as currently is */ + pthread_mutex_t cancelLock; /* Used for async-cancel safety */ + int cancelState; + int cancelType; + HANDLE cancelEvent; +#ifdef __CLEANUP_C + jmp_buf start_mark; +#endif /* __CLEANUP_C */ +#if HAVE_SIGSET_T + sigset_t sigmask; +#endif /* HAVE_SIGSET_T */ + int implicit:1; + void *keys; + void *nextAssoc; +}; + + +/* + * Special value to mark attribute objects as valid. + */ +#define PTW32_ATTR_VALID ((unsigned long) 0xC4C0FFEE) + +struct pthread_attr_t_ +{ + unsigned long valid; + void *stackaddr; + size_t stacksize; + int detachstate; + struct sched_param param; + int inheritsched; + int contentionscope; +#if HAVE_SIGSET_T + sigset_t sigmask; +#endif /* HAVE_SIGSET_T */ +}; + + +/* + * ==================== + * ==================== + * Semaphores, Mutexes and Condition Variables + * ==================== + * ==================== + */ + +struct sem_t_ +{ + int value; + pthread_mutex_t lock; + HANDLE sem; +#ifdef NEED_SEM + int leftToUnblock; +#endif +}; + +#define PTW32_OBJECT_AUTO_INIT ((void *) -1) +#define PTW32_OBJECT_INVALID NULL + +struct pthread_mutex_t_ +{ + LONG lock_idx; /* Provides exclusive access to mutex state + via the Interlocked* mechanism. + 0: unlocked/free. + 1: locked - no other waiters. + -1: locked - with possible other waiters. + */ + int recursive_count; /* Number of unlocks a thread needs to perform + before the lock is released (recursive + mutexes only). */ + int kind; /* Mutex type. */ + pthread_t ownerThread; + HANDLE event; /* Mutex release notification to waiting + threads. */ +}; + +struct pthread_mutexattr_t_ +{ + int pshared; + int kind; +}; + +/* + * Possible values, other than PTW32_OBJECT_INVALID, + * for the "interlock" element in a spinlock. + * + * In this implementation, when a spinlock is initialised, + * the number of cpus available to the process is checked. + * If there is only one cpu then "interlock" is set equal to + * PTW32_SPIN_USE_MUTEX and u.mutex is a initialised mutex. + * If the number of cpus is greater than 1 then "interlock" + * is set equal to PTW32_SPIN_UNLOCKED and the number is + * stored in u.cpus. This arrangement allows the spinlock + * routines to attempt an InterlockedCompareExchange on "interlock" + * immediately and, if that fails, to try the inferior mutex. + * + * "u.cpus" isn't used for anything yet, but could be used at + * some point to optimise spinlock behaviour. + */ +#define PTW32_SPIN_UNLOCKED (1) +#define PTW32_SPIN_LOCKED (2) +#define PTW32_SPIN_USE_MUTEX (3) + +struct pthread_spinlock_t_ +{ + long interlock; /* Locking element for multi-cpus. */ + union + { + int cpus; /* No. of cpus if multi cpus, or */ + pthread_mutex_t mutex; /* mutex if single cpu. */ + } u; +}; + +struct pthread_barrier_t_ +{ + unsigned int nCurrentBarrierHeight; + unsigned int nInitialBarrierHeight; + int iStep; + int pshared; + sem_t semBarrierBreeched[2]; +}; + +struct pthread_barrierattr_t_ +{ + int pshared; +}; + +struct pthread_key_t_ +{ + DWORD key; + void (*destructor) (void *); + pthread_mutex_t keyLock; + void *threads; +}; + + +typedef struct ThreadParms ThreadParms; +typedef struct ThreadKeyAssoc ThreadKeyAssoc; + +struct ThreadParms +{ + pthread_t tid; + void *(*start) (void *); + void *arg; +}; + + +struct pthread_cond_t_ +{ + long nWaitersBlocked; /* Number of threads blocked */ + long nWaitersGone; /* Number of threads timed out */ + long nWaitersToUnblock; /* Number of threads to unblock */ + sem_t semBlockQueue; /* Queue up threads waiting for the */ + /* condition to become signalled */ + sem_t semBlockLock; /* Semaphore that guards access to */ + /* | waiters blocked count/block queue */ + /* +-> Mandatory Sync.LEVEL-1 */ + pthread_mutex_t mtxUnblockLock; /* Mutex that guards access to */ + /* | waiters (to)unblock(ed) counts */ + /* +-> Optional* Sync.LEVEL-2 */ + pthread_cond_t next; /* Doubly linked list */ + pthread_cond_t prev; +}; + + +struct pthread_condattr_t_ +{ + int pshared; +}; + +#define PTW32_RWLOCK_MAGIC 0xfacade2 + +struct pthread_rwlock_t_ +{ + pthread_mutex_t mtxExclusiveAccess; + pthread_mutex_t mtxSharedAccessCompleted; + pthread_cond_t cndSharedAccessCompleted; + int nSharedAccessCount; + int nExclusiveAccessCount; + int nCompletedSharedAccessCount; + int nMagic; +}; + +struct pthread_rwlockattr_t_ +{ + int pshared; +}; + +/* + * MCS lock queue node - see ptw32_MCS_lock.c + */ +struct ptw32_mcs_node_t_ +{ + struct ptw32_mcs_node_t_ **lock; /* ptr to tail of queue */ + struct ptw32_mcs_node_t_ *next; /* ptr to successor in queue */ + LONG readyFlag; /* set after lock is released by + predecessor */ + LONG nextFlag; /* set after 'next' ptr is set by + successor */ +}; + +typedef struct ptw32_mcs_node_t_ ptw32_mcs_local_node_t; +typedef struct ptw32_mcs_node_t_ *ptw32_mcs_lock_t; + + +struct ThreadKeyAssoc +{ + /* + * Purpose: + * This structure creates an association between a thread and a key. + * It is used to implement the implicit invocation of a user defined + * destroy routine for thread specific data registered by a user upon + * exiting a thread. + * + * Graphically, the arrangement is as follows, where: + * + * K - Key with destructor + * (head of chain is key->threads) + * T - Thread that has called pthread_setspecific(Kn) + * (head of chain is thread->keys) + * A - Association. Each association is a node at the + * intersection of two doubly-linked lists. + * + * T1 T2 T3 + * | | | + * | | | + * K1 -----+-----A-----A-----> + * | | | + * | | | + * K2 -----A-----A-----+-----> + * | | | + * | | | + * K3 -----A-----+-----A-----> + * | | | + * | | | + * V V V + * + * Access to the association is guarded by two locks: the key's + * general lock (guarding the row) and the thread's general + * lock (guarding the column). This avoids the need for a + * dedicated lock for each association, which not only consumes + * more handles but requires that: before the lock handle can + * be released - both the key must be deleted and the thread + * must have called the destructor. The two-lock arrangement + * allows the resources to be freed as soon as either thread or + * key is concluded. + * + * To avoid deadlock: whenever both locks are required, the key + * and thread locks are always acquired in the order: key lock + * then thread lock. An exception to this exists when a thread + * calls the destructors, however this is done carefully to + * avoid deadlock. + * + * An association is created when a thread first calls + * pthread_setspecific() on a key that has a specified + * destructor. + * + * An association is destroyed either immediately after the + * thread calls the key destructor function on thread exit, or + * when the key is deleted. + * + * Attributes: + * thread + * reference to the thread that owns the + * association. This is actually the pointer to the + * thread struct itself. Since the association is + * destroyed before the thread exits, this can never + * point to a different logical thread to the one that + * created the assoc, i.e. after thread struct reuse. + * + * key + * reference to the key that owns the association. + * + * nextKey + * The pthread_t->keys attribute is the head of a + * chain of associations that runs through the nextKey + * link. This chain provides the 1 to many relationship + * between a pthread_t and all pthread_key_t on which + * it called pthread_setspecific. + * + * prevKey + * Similarly. + * + * nextThread + * The pthread_key_t->threads attribute is the head of + * a chain of assoctiations that runs through the + * nextThreads link. This chain provides the 1 to many + * relationship between a pthread_key_t and all the + * PThreads that have called pthread_setspecific for + * this pthread_key_t. + * + * prevThread + * Similarly. + * + * Notes: + * 1) As soon as either the key or the thread is no longer + * referencing the association, it can be destroyed. The + * association will be removed from both chains. + * + * 2) Under WIN32, an association is only created by + * pthread_setspecific if the user provided a + * destroyRoutine when they created the key. + * + * + */ + ptw32_thread_t * thread; + pthread_key_t key; + ThreadKeyAssoc *nextKey; + ThreadKeyAssoc *nextThread; + ThreadKeyAssoc *prevKey; + ThreadKeyAssoc *prevThread; +}; + + +#ifdef __CLEANUP_SEH +/* + * -------------------------------------------------------------- + * MAKE_SOFTWARE_EXCEPTION + * This macro constructs a software exception code following + * the same format as the standard Win32 error codes as defined + * in WINERROR.H + * Values are 32 bit values layed out as follows: + * + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +---+-+-+-----------------------+-------------------------------+ + * |Sev|C|R| Facility | Code | + * +---+-+-+-----------------------+-------------------------------+ + * + * Severity Values: + */ +#define SE_SUCCESS 0x00 +#define SE_INFORMATION 0x01 +#define SE_WARNING 0x02 +#define SE_ERROR 0x03 + +#define MAKE_SOFTWARE_EXCEPTION( _severity, _facility, _exception ) \ +( (DWORD) ( ( (_severity) << 30 ) | /* Severity code */ \ + ( 1 << 29 ) | /* MS=0, User=1 */ \ + ( 0 << 28 ) | /* Reserved */ \ + ( (_facility) << 16 ) | /* Facility Code */ \ + ( (_exception) << 0 ) /* Exception Code */ \ + ) ) + +/* + * We choose one specific Facility/Error code combination to + * identify our software exceptions vs. WIN32 exceptions. + * We store our actual component and error code within + * the optional information array. + */ +#define EXCEPTION_PTW32_SERVICES \ + MAKE_SOFTWARE_EXCEPTION( SE_ERROR, \ + PTW32_SERVICES_FACILITY, \ + PTW32_SERVICES_ERROR ) + +#define PTW32_SERVICES_FACILITY 0xBAD +#define PTW32_SERVICES_ERROR 0xDEED + +#endif /* __CLEANUP_SEH */ + +/* + * Services available through EXCEPTION_PTW32_SERVICES + * and also used [as parameters to ptw32_throw()] as + * generic exception selectors. + */ + +#define PTW32_EPS_EXIT (1) +#define PTW32_EPS_CANCEL (2) + + +/* Useful macros */ +#define PTW32_MAX(a,b) ((a)<(b)?(b):(a)) +#define PTW32_MIN(a,b) ((a)>(b)?(b):(a)) + + +#if 0 +/* Declared in global.c */ +extern PTW32_INTERLOCKED_LONG (WINAPI * + ptw32_interlocked_compare_exchange) + (PTW32_INTERLOCKED_LPLONG, PTW32_INTERLOCKED_LONG, PTW32_INTERLOCKED_LONG); +#endif + +/* Declared in pthread_cancel.c */ +extern DWORD (*ptw32_register_cancelation) (PAPCFUNC, HANDLE, DWORD); + +/* Thread Reuse stack bottom marker. Must not be NULL or any valid pointer to memory. */ +#define PTW32_THREAD_REUSE_EMPTY ((ptw32_thread_t *) 1) + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +extern int ptw32_processInitialized; +extern ptw32_thread_t * ptw32_threadReuseTop; +extern ptw32_thread_t * ptw32_threadReuseBottom; +extern pthread_key_t ptw32_selfThreadKey; +extern pthread_key_t ptw32_cleanupKey; +extern pthread_cond_t ptw32_cond_list_head; +extern pthread_cond_t ptw32_cond_list_tail; + +extern int ptw32_mutex_default_kind; + +extern int ptw32_concurrency; + +extern int ptw32_features; + +extern BOOL ptw32_smp_system; /* True: SMP system, False: Uni-processor system */ + +extern CRITICAL_SECTION ptw32_thread_reuse_lock; +extern CRITICAL_SECTION ptw32_mutex_test_init_lock; +extern CRITICAL_SECTION ptw32_cond_list_lock; +extern CRITICAL_SECTION ptw32_cond_test_init_lock; +extern CRITICAL_SECTION ptw32_rwlock_test_init_lock; +extern CRITICAL_SECTION ptw32_spinlock_test_init_lock; + +#ifdef _UWIN +extern int pthread_count; +#endif + + +/* + * ===================== + * ===================== + * Forward Declarations + * ===================== + * ===================== + */ + + int ptw32_is_attr (const pthread_attr_t * attr); + + int ptw32_cond_check_need_init (pthread_cond_t * cond); + int ptw32_mutex_check_need_init (pthread_mutex_t * mutex); + int ptw32_rwlock_check_need_init (pthread_rwlock_t * rwlock); + + PTW32_INTERLOCKED_LONG WINAPI + ptw32_InterlockedCompareExchange (volatile PTW32_INTERLOCKED_LPLONG location, + PTW32_INTERLOCKED_LONG value, + PTW32_INTERLOCKED_LONG comparand); + + LONG WINAPI + ptw32_InterlockedExchange (volatile PTW32_INTERLOCKED_LPLONG location, + LONG value); + + DWORD + ptw32_RegisterCancelation (PAPCFUNC callback, + HANDLE threadH, DWORD callback_arg); + + int ptw32_processInitialize (void); + + void ptw32_processTerminate (void); + + void ptw32_threadDestroy (pthread_t tid); + + void ptw32_pop_cleanup_all (int execute); + + pthread_t ptw32_new (void); + + pthread_t ptw32_threadReusePop (void); + + void ptw32_threadReusePush (pthread_t thread); + + int ptw32_getprocessors (int *count); + + int ptw32_setthreadpriority (pthread_t thread, int policy, int priority); + + void ptw32_rwlock_cancelwrwait (void *arg); + +#if ! defined (__MINGW32__) || defined (__MSVCRT__) + unsigned __stdcall +#else + void +#endif + ptw32_threadStart (void *vthreadParms); + + void ptw32_callUserDestroyRoutines (pthread_t thread); + + int ptw32_tkAssocCreate (ptw32_thread_t * thread, pthread_key_t key); + + void ptw32_tkAssocDestroy (ThreadKeyAssoc * assoc); + + int ptw32_semwait (sem_t * sem); + + DWORD ptw32_relmillisecs (const struct timespec * abstime); + + void ptw32_mcs_lock_acquire (ptw32_mcs_lock_t * lock, ptw32_mcs_local_node_t * node); + + void ptw32_mcs_lock_release (ptw32_mcs_local_node_t * node); + + // added to remove some warnings (air) + int ptw32_spinlock_check_need_init (pthread_spinlock_t * lock); + +#ifdef NEED_FTIME + void ptw32_timespec_to_filetime (const struct timespec *ts, FILETIME * ft); + void ptw32_filetime_to_timespec (const FILETIME * ft, struct timespec *ts); +#endif + +/* Declared in misc.c */ +#ifdef NEED_CALLOC +#define calloc(n, s) ptw32_calloc(n, s) + void *ptw32_calloc (size_t n, size_t s); +#endif + +/* Declared in private.c */ + void ptw32_throw (DWORD exception); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#ifdef _UWIN_ +# ifdef _MT +# ifdef __cplusplus +extern "C" +{ +# endif + _CRTIMP unsigned long __cdecl _beginthread (void (__cdecl *) (void *), + unsigned, void *); + _CRTIMP void __cdecl _endthread (void); + _CRTIMP unsigned long __cdecl _beginthreadex (void *, unsigned, + unsigned (__stdcall *) (void *), + void *, unsigned, unsigned *); + _CRTIMP void __cdecl _endthreadex (unsigned); +# ifdef __cplusplus +} +# endif +# endif +#else +# include +#endif + + +/* + * Defaults. Could be overridden when building the inlined version of the dll. + * See ptw32_InterlockedCompareExchange.c + */ +// Default to inlining the pthreads versions... (air) +#ifndef PTW32_INTERLOCKED_COMPARE_EXCHANGE +#define PTW32_INTERLOCKED_COMPARE_EXCHANGE ptw32_InterlockedCompareExchange +#endif + +#ifndef PTW32_INTERLOCKED_EXCHANGE +#define PTW32_INTERLOCKED_EXCHANGE ptw32_InterlockedExchange +#endif + + +/* + * Check for old and new versions of cygwin. See the FAQ file: + * + * Question 1 - How do I get pthreads-win32 to link under Cygwin or Mingw32? + * + * Patch by Anders Norlander + */ +#if defined(__CYGWIN32__) || defined(__CYGWIN__) || defined(NEED_CREATETHREAD) + +/* + * Macro uses args so we can cast start_proc to LPTHREAD_START_ROUTINE + * in order to avoid warnings because of return type + */ + +#define _beginthreadex(security, \ + stack_size, \ + start_proc, \ + arg, \ + flags, \ + pid) \ + CreateThread(security, \ + stack_size, \ + (LPTHREAD_START_ROUTINE) start_proc, \ + arg, \ + flags, \ + pid) + +#define _endthreadex ExitThread + +#endif /* __CYGWIN32__ || __CYGWIN__ || NEED_CREATETHREAD */ + + +#endif /* _IMPLEMENT_H */ diff --git a/pcsx2/windows/pthreads/misc.c b/pcsx2/windows/pthreads/misc.c index 5853569a70..06d1d21374 100644 --- a/pcsx2/windows/pthreads/misc.c +++ b/pcsx2/windows/pthreads/misc.c @@ -1,50 +1,50 @@ -/* - * misc.c - * - * Description: - * This translation unit implements miscellaneous thread functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -#include "pthread_kill.c" -#include "pthread_once.c" -#include "pthread_self.c" -#include "pthread_equal.c" -#include "pthread_setconcurrency.c" -#include "pthread_getconcurrency.c" -#include "ptw32_new.c" -#include "ptw32_calloc.c" -#include "ptw32_reuse.c" -#include "w32_CancelableWait.c" +/* + * misc.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +#include "pthread_kill.c" +#include "pthread_once.c" +#include "pthread_self.c" +#include "pthread_equal.c" +#include "pthread_setconcurrency.c" +#include "pthread_getconcurrency.c" +#include "ptw32_new.c" +#include "ptw32_calloc.c" +#include "ptw32_reuse.c" +#include "w32_CancelableWait.c" diff --git a/pcsx2/windows/pthreads/mutex.c b/pcsx2/windows/pthreads/mutex.c index c199901db5..2e60dabe4c 100644 --- a/pcsx2/windows/pthreads/mutex.c +++ b/pcsx2/windows/pthreads/mutex.c @@ -1,59 +1,59 @@ -/* - * mutex.c - * - * Description: - * This translation unit implements mutual exclusion (mutex) primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#ifndef _UWIN -# include -#endif -#ifndef NEED_FTIME -#include -#endif -#include "pthread.h" -#include "implement.h" - - -#include "ptw32_mutex_check_need_init.c" -#include "pthread_mutex_init.c" -#include "pthread_mutex_destroy.c" -#include "pthread_mutexattr_init.c" -#include "pthread_mutexattr_destroy.c" -#include "pthread_mutexattr_getpshared.c" -#include "pthread_mutexattr_setpshared.c" -#include "pthread_mutexattr_settype.c" -#include "pthread_mutexattr_gettype.c" -#include "pthread_mutex_lock.c" -#include "pthread_mutex_timedlock.c" -#include "pthread_mutex_unlock.c" -#include "pthread_mutex_trylock.c" +/* + * mutex.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef _UWIN +# include +#endif +#ifndef NEED_FTIME +#include +#endif +#include "pthread.h" +#include "implement.h" + + +#include "ptw32_mutex_check_need_init.c" +#include "pthread_mutex_init.c" +#include "pthread_mutex_destroy.c" +#include "pthread_mutexattr_init.c" +#include "pthread_mutexattr_destroy.c" +#include "pthread_mutexattr_getpshared.c" +#include "pthread_mutexattr_setpshared.c" +#include "pthread_mutexattr_settype.c" +#include "pthread_mutexattr_gettype.c" +#include "pthread_mutex_lock.c" +#include "pthread_mutex_timedlock.c" +#include "pthread_mutex_unlock.c" +#include "pthread_mutex_trylock.c" diff --git a/pcsx2/windows/pthreads/need_errno.h b/pcsx2/windows/pthreads/need_errno.h index d523135756..2609f8d6b2 100644 --- a/pcsx2/windows/pthreads/need_errno.h +++ b/pcsx2/windows/pthreads/need_errno.h @@ -1,132 +1,132 @@ -/*** -* errno.h - system wide error numbers (set by system calls) -* -* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. -* -* Purpose: -* This file defines the system-wide error numbers (set by -* system calls). Conforms to the XENIX standard. Extended -* for compatibility with Uniforum standard. -* [System V] -* -* [Public] -* -****/ - -#if _MSC_VER > 1000 -#pragma once -#endif - -#ifndef _INC_ERRNO -#define _INC_ERRNO - -#if !defined(_WIN32) && !defined(_MAC) -#error ERROR: Only Mac or Win32 targets supported! -#endif - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - - -/* Define _CRTIMP */ - -#ifndef _CRTIMP -#ifdef _DLL -#define _CRTIMP __declspec(dllimport) -#else /* ndef _DLL */ -#define _CRTIMP -#endif /* _DLL */ -#endif /* _CRTIMP */ - - -/* Define __cdecl for non-Microsoft compilers */ - -#if ( !defined(_MSC_VER) && !defined(__cdecl) ) -#define __cdecl -#endif - -/* Define _CRTAPI1 (for compatibility with the NT SDK) */ - -#ifndef _CRTAPI1 -#if _MSC_VER >= 800 && _M_IX86 >= 300 -#define _CRTAPI1 __cdecl -#else -#define _CRTAPI1 -#endif -#endif - - -/* declare reference to errno */ - -#if (defined(_MT) || defined(_MD) || defined(_DLL)) && !defined(_MAC) -_CRTIMP extern int * __cdecl _errno(void); -#define errno (*_errno()) -#else /* ndef _MT && ndef _MD && ndef _DLL */ -_CRTIMP extern int errno; -#endif /* _MT || _MD || _DLL */ - -/* Error Codes */ - -#define EPERM 1 -#define ENOENT 2 -#define ESRCH 3 -#define EINTR 4 -#define EIO 5 -#define ENXIO 6 -#define E2BIG 7 -#define ENOEXEC 8 -#define EBADF 9 -#define ECHILD 10 -#define EAGAIN 11 -#define ENOMEM 12 -#define EACCES 13 -#define EFAULT 14 -#define EBUSY 16 -#define EEXIST 17 -#define EXDEV 18 -#define ENODEV 19 -#define ENOTDIR 20 -#define EISDIR 21 -#define EINVAL 22 -#define ENFILE 23 -#define EMFILE 24 -#define ENOTTY 25 -#define EFBIG 27 -#define ENOSPC 28 -#define ESPIPE 29 -#define EROFS 30 -#define EMLINK 31 -#define EPIPE 32 -#define EDOM 33 -#define ERANGE 34 -#define EDEADLK 36 - -/* defined differently in winsock.h on WinCE */ -#ifndef ENAMETOOLONG -#define ENAMETOOLONG 38 -#endif - -#define ENOLCK 39 -#define ENOSYS 40 - -/* defined differently in winsock.h on WinCE */ -#ifndef ENOTEMPTY -#define ENOTEMPTY 41 -#endif - -#define EILSEQ 42 - -/* - * Support EDEADLOCK for compatibiity with older MS-C versions. - */ -#define EDEADLOCK EDEADLK - -#ifdef __cplusplus -} -#endif - -#endif /* _INC_ERRNO */ +/*** +* errno.h - system wide error numbers (set by system calls) +* +* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. +* +* Purpose: +* This file defines the system-wide error numbers (set by +* system calls). Conforms to the XENIX standard. Extended +* for compatibility with Uniforum standard. +* [System V] +* +* [Public] +* +****/ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#ifndef _INC_ERRNO +#define _INC_ERRNO + +#if !defined(_WIN32) && !defined(_MAC) +#error ERROR: Only Mac or Win32 targets supported! +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + + +/* Define _CRTIMP */ + +#ifndef _CRTIMP +#ifdef _DLL +#define _CRTIMP __declspec(dllimport) +#else /* ndef _DLL */ +#define _CRTIMP +#endif /* _DLL */ +#endif /* _CRTIMP */ + + +/* Define __cdecl for non-Microsoft compilers */ + +#if ( !defined(_MSC_VER) && !defined(__cdecl) ) +#define __cdecl +#endif + +/* Define _CRTAPI1 (for compatibility with the NT SDK) */ + +#ifndef _CRTAPI1 +#if _MSC_VER >= 800 && _M_IX86 >= 300 +#define _CRTAPI1 __cdecl +#else +#define _CRTAPI1 +#endif +#endif + + +/* declare reference to errno */ + +#if (defined(_MT) || defined(_MD) || defined(_DLL)) && !defined(_MAC) +_CRTIMP extern int * __cdecl _errno(void); +#define errno (*_errno()) +#else /* ndef _MT && ndef _MD && ndef _DLL */ +_CRTIMP extern int errno; +#endif /* _MT || _MD || _DLL */ + +/* Error Codes */ + +#define EPERM 1 +#define ENOENT 2 +#define ESRCH 3 +#define EINTR 4 +#define EIO 5 +#define ENXIO 6 +#define E2BIG 7 +#define ENOEXEC 8 +#define EBADF 9 +#define ECHILD 10 +#define EAGAIN 11 +#define ENOMEM 12 +#define EACCES 13 +#define EFAULT 14 +#define EBUSY 16 +#define EEXIST 17 +#define EXDEV 18 +#define ENODEV 19 +#define ENOTDIR 20 +#define EISDIR 21 +#define EINVAL 22 +#define ENFILE 23 +#define EMFILE 24 +#define ENOTTY 25 +#define EFBIG 27 +#define ENOSPC 28 +#define ESPIPE 29 +#define EROFS 30 +#define EMLINK 31 +#define EPIPE 32 +#define EDOM 33 +#define ERANGE 34 +#define EDEADLK 36 + +/* defined differently in winsock.h on WinCE */ +#ifndef ENAMETOOLONG +#define ENAMETOOLONG 38 +#endif + +#define ENOLCK 39 +#define ENOSYS 40 + +/* defined differently in winsock.h on WinCE */ +#ifndef ENOTEMPTY +#define ENOTEMPTY 41 +#endif + +#define EILSEQ 42 + +/* + * Support EDEADLOCK for compatibiity with older MS-C versions. + */ +#define EDEADLOCK EDEADLK + +#ifdef __cplusplus +} +#endif + +#endif /* _INC_ERRNO */ diff --git a/pcsx2/windows/pthreads/nonportable.c b/pcsx2/windows/pthreads/nonportable.c index d1b0976507..6c2a990aa7 100644 --- a/pcsx2/windows/pthreads/nonportable.c +++ b/pcsx2/windows/pthreads/nonportable.c @@ -1,46 +1,46 @@ -/* - * nonportable.c - * - * Description: - * This translation unit implements non-portable thread functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -#include "pthread_mutexattr_setkind_np.c" -#include "pthread_mutexattr_getkind_np.c" -#include "pthread_getw32threadhandle_np.c" -#include "pthread_delay_np.c" -#include "pthread_num_processors_np.c" -#include "pthread_win32_attach_detach_np.c" -#include "pthread_timechange_handler_np.c" +/* + * nonportable.c + * + * Description: + * This translation unit implements non-portable thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +#include "pthread_mutexattr_setkind_np.c" +#include "pthread_mutexattr_getkind_np.c" +#include "pthread_getw32threadhandle_np.c" +#include "pthread_delay_np.c" +#include "pthread_num_processors_np.c" +#include "pthread_win32_attach_detach_np.c" +#include "pthread_timechange_handler_np.c" diff --git a/pcsx2/windows/pthreads/private.c b/pcsx2/windows/pthreads/private.c index 3755ef4d56..7e311b10ea 100644 --- a/pcsx2/windows/pthreads/private.c +++ b/pcsx2/windows/pthreads/private.c @@ -1,57 +1,57 @@ -/* - * private.c - * - * Description: - * This translation unit implements routines which are private to - * the implementation and may be used throughout it. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -/* Must be first to define HAVE_INLINABLE_INTERLOCKED_CMPXCHG */ -#include "ptw32_InterlockedCompareExchange.c" - -#include "ptw32_MCS_lock.c" -#include "ptw32_is_attr.c" -#include "ptw32_processInitialize.c" -#include "ptw32_processTerminate.c" -#include "ptw32_threadStart.c" -#include "ptw32_threadDestroy.c" -#include "ptw32_tkAssocCreate.c" -#include "ptw32_tkAssocDestroy.c" -#include "ptw32_callUserDestroyRoutines.c" -#include "ptw32_semwait.c" -#include "ptw32_timespec.c" -#include "ptw32_relmillisecs.c" -#include "ptw32_throw.c" -#include "ptw32_getprocessors.c" +/* + * private.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* Must be first to define HAVE_INLINABLE_INTERLOCKED_CMPXCHG */ +#include "ptw32_InterlockedCompareExchange.c" + +#include "ptw32_MCS_lock.c" +#include "ptw32_is_attr.c" +#include "ptw32_processInitialize.c" +#include "ptw32_processTerminate.c" +#include "ptw32_threadStart.c" +#include "ptw32_threadDestroy.c" +#include "ptw32_tkAssocCreate.c" +#include "ptw32_tkAssocDestroy.c" +#include "ptw32_callUserDestroyRoutines.c" +#include "ptw32_semwait.c" +#include "ptw32_timespec.c" +#include "ptw32_relmillisecs.c" +#include "ptw32_throw.c" +#include "ptw32_getprocessors.c" diff --git a/pcsx2/windows/pthreads/pthread.h b/pcsx2/windows/pthreads/pthread.h index 7cca67585a..d33a9b14a8 100644 --- a/pcsx2/windows/pthreads/pthread.h +++ b/pcsx2/windows/pthreads/pthread.h @@ -1,1388 +1,1388 @@ -/* This is an implementation of the threads API of POSIX 1003.1-2001. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#if !defined( PTHREAD_H ) -#define PTHREAD_H - -/* - * See the README file for an explanation of the pthreads-win32 version - * numbering scheme and how the DLL is named etc. - */ -#define PTW32_VERSION 2,8,0,0 -#define PTW32_VERSION_STRING "2, 8, 0, 0\0" - -/* There are three implementations of cancel cleanup. - * Note that pthread.h is included in both application - * compilation units and also internally for the library. - * The code here and within the library aims to work - * for all reasonable combinations of environments. - * - * The three implementations are: - * - * WIN32 SEH - * C - * C++ - * - * Please note that exiting a push/pop block via - * "return", "exit", "break", or "continue" will - * lead to different behaviour amongst applications - * depending upon whether the library was built - * using SEH, C++, or C. For example, a library built - * with SEH will call the cleanup routine, while both - * C++ and C built versions will not. - */ - -/* - * Define defaults for cleanup code. - * Note: Unless the build explicitly defines one of the following, then - * we default to standard C style cleanup. This style uses setjmp/longjmp - * in the cancelation and thread exit implementations and therefore won't - * do stack unwinding if linked to applications that have it (e.g. - * C++ apps). This is currently consistent with most/all commercial Unix - * POSIX threads implementations. - */ -#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C ) -# define __CLEANUP_C -#endif - -#if defined( __CLEANUP_SEH ) && ( !defined( _MSC_VER ) && !defined(PTW32_RC_MSC)) -#error ERROR [__FILE__, line __LINE__]: SEH is not supported for this compiler. -#endif - -/* - * Stop here if we are being included by the resource compiler. - */ -#ifndef RC_INVOKED - -#undef PTW32_LEVEL - -#if defined(_POSIX_SOURCE) -#define PTW32_LEVEL 0 -/* Early POSIX */ -#endif - -#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 -#undef PTW32_LEVEL -#define PTW32_LEVEL 1 -/* Include 1b, 1c and 1d */ -#endif - -#if defined(INCLUDE_NP) -#undef PTW32_LEVEL -#define PTW32_LEVEL 2 -/* Include Non-Portable extensions */ -#endif - -#define PTW32_LEVEL_MAX 3 - -#if !defined(PTW32_LEVEL) -#define PTW32_LEVEL PTW32_LEVEL_MAX -/* Include everything */ -#endif - -#ifdef _UWIN -# define HAVE_STRUCT_TIMESPEC 1 -# define HAVE_SIGNAL_H 1 -# undef HAVE_CONFIG_H -# pragma comment(lib, "pthread") -#endif - -/* - * ------------------------------------------------------------- - * - * - * Module: pthread.h - * - * Purpose: - * Provides an implementation of PThreads based upon the - * standard: - * - * POSIX 1003.1-2001 - * and - * The Single Unix Specification version 3 - * - * (these two are equivalent) - * - * in order to enhance code portability between Windows, - * various commercial Unix implementations, and Linux. - * - * See the ANNOUNCE file for a full list of conforming - * routines and defined constants, and a list of missing - * routines and constants not defined in this implementation. - * - * Authors: - * There have been many contributors to this library. - * The initial implementation was contributed by - * John Bossom, and several others have provided major - * sections or revisions of parts of the implementation. - * Often significant effort has been contributed to - * find and fix important bugs and other problems to - * improve the reliability of the library, which sometimes - * is not reflected in the amount of code which changed as - * result. - * As much as possible, the contributors are acknowledged - * in the ChangeLog file in the source code distribution - * where their changes are noted in detail. - * - * Contributors are listed in the CONTRIBUTORS file. - * - * As usual, all bouquets go to the contributors, and all - * brickbats go to the project maintainer. - * - * Maintainer: - * The code base for this project is coordinated and - * eventually pre-tested, packaged, and made available by - * - * Ross Johnson - * - * QA Testers: - * Ultimately, the library is tested in the real world by - * a host of competent and demanding scientists and - * engineers who report bugs and/or provide solutions - * which are then fixed or incorporated into subsequent - * versions of the library. Each time a bug is fixed, a - * test case is written to prove the fix and ensure - * that later changes to the code don't reintroduce the - * same error. The number of test cases is slowly growing - * and therefore so is the code reliability. - * - * Compliance: - * See the file ANNOUNCE for the list of implemented - * and not-implemented routines and defined options. - * Of course, these are all defined is this file as well. - * - * Web site: - * The source code and other information about this library - * are available from - * - * http://sources.redhat.com/pthreads-win32/ - * - * ------------------------------------------------------------- - */ - -/* Try to avoid including windows.h */ -#if defined(__MINGW32__) && defined(__cplusplus) -#define PTW32_INCLUDE_WINDOWS_H -#endif - -#ifdef PTW32_INCLUDE_WINDOWS_H -#include -#endif - -#if defined(_MSC_VER) && _MSC_VER < 1300 || defined(__DMC__) -/* - * VC++6.0 or early compiler's header has no DWORD_PTR type. - */ -typedef unsigned long DWORD_PTR; -#endif -/* - * ----------------- - * autoconf switches - * ----------------- - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#ifndef NEED_FTIME -#include -#else /* NEED_FTIME */ -/* use native WIN32 time API */ -#endif /* NEED_FTIME */ - -#if HAVE_SIGNAL_H -#include -#endif /* HAVE_SIGNAL_H */ - -#include -#include - -/* - * Boolean values to make us independent of system includes. - */ -enum { - PTW32_FALSE = 0, - PTW32_TRUE = (! PTW32_FALSE) -}; - -/* - * This is a duplicate of what is in the autoconf config.h, - * which is only used when building the pthread-win32 libraries. - */ - -#ifndef PTW32_CONFIG_H -# if defined(WINCE) -# define NEED_ERRNO -# define NEED_SEM -# endif -# if defined(_UWIN) || defined(__MINGW32__) -# define HAVE_MODE_T -# endif -#endif - -/* - * - */ - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX -#ifdef NEED_ERRNO -#include "need_errno.h" -#else -#include -#endif -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -/* - * Several systems don't define some error numbers. - */ -#ifndef ENOTSUP -# define ENOTSUP 48 /* This is the value in Solaris. */ -#endif - -#ifndef ETIMEDOUT -# define ETIMEDOUT 10060 /* This is the value in winsock.h. */ -#endif - -#ifndef ENOSYS -# define ENOSYS 140 /* Semi-arbitrary value */ -#endif - -#ifndef EDEADLK -# ifdef EDEADLOCK -# define EDEADLK EDEADLOCK -# else -# define EDEADLK 36 /* This is the value in MSVC. */ -# endif -#endif - -#include - -/* - * To avoid including windows.h we define only those things that we - * actually need from it. - */ -#ifndef PTW32_INCLUDE_WINDOWS_H -#ifndef HANDLE -# define PTW32__HANDLE_DEF -# define HANDLE void * -#endif -#ifndef DWORD -# define PTW32__DWORD_DEF -# define DWORD unsigned long -#endif -#endif - -#ifndef HAVE_STRUCT_TIMESPEC -#define HAVE_STRUCT_TIMESPEC 1 -struct timespec { - long tv_sec; - long tv_nsec; -}; -#endif /* HAVE_STRUCT_TIMESPEC */ - -#ifndef SIG_BLOCK -#define SIG_BLOCK 0 -#endif /* SIG_BLOCK */ - -#ifndef SIG_UNBLOCK -#define SIG_UNBLOCK 1 -#endif /* SIG_UNBLOCK */ - -#ifndef SIG_SETMASK -#define SIG_SETMASK 2 -#endif /* SIG_SETMASK */ - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - -/* - * ------------------------------------------------------------- - * - * POSIX 1003.1-2001 Options - * ========================= - * - * Options are normally set in , which is not provided - * with pthreads-win32. - * - * For conformance with the Single Unix Specification (version 3), all of the - * options below are defined, and have a value of either -1 (not supported) - * or 200112L (supported). - * - * These options can neither be left undefined nor have a value of 0, because - * either indicates that sysconf(), which is not implemented, may be used at - * runtime to check the status of the option. - * - * _POSIX_THREADS (== 200112L) - * If == 200112L, you can use threads - * - * _POSIX_THREAD_ATTR_STACKSIZE (== 200112L) - * If == 200112L, you can control the size of a thread's - * stack - * pthread_attr_getstacksize - * pthread_attr_setstacksize - * - * _POSIX_THREAD_ATTR_STACKADDR (== -1) - * If == 200112L, you can allocate and control a thread's - * stack. If not supported, the following functions - * will return ENOSYS, indicating they are not - * supported: - * pthread_attr_getstackaddr - * pthread_attr_setstackaddr - * - * _POSIX_THREAD_PRIORITY_SCHEDULING (== -1) - * If == 200112L, you can use realtime scheduling. - * This option indicates that the behaviour of some - * implemented functions conforms to the additional TPS - * requirements in the standard. E.g. rwlocks favour - * writers over readers when threads have equal priority. - * - * _POSIX_THREAD_PRIO_INHERIT (== -1) - * If == 200112L, you can create priority inheritance - * mutexes. - * pthread_mutexattr_getprotocol + - * pthread_mutexattr_setprotocol + - * - * _POSIX_THREAD_PRIO_PROTECT (== -1) - * If == 200112L, you can create priority ceiling mutexes - * Indicates the availability of: - * pthread_mutex_getprioceiling - * pthread_mutex_setprioceiling - * pthread_mutexattr_getprioceiling - * pthread_mutexattr_getprotocol + - * pthread_mutexattr_setprioceiling - * pthread_mutexattr_setprotocol + - * - * _POSIX_THREAD_PROCESS_SHARED (== -1) - * If set, you can create mutexes and condition - * variables that can be shared with another - * process.If set, indicates the availability - * of: - * pthread_mutexattr_getpshared - * pthread_mutexattr_setpshared - * pthread_condattr_getpshared - * pthread_condattr_setpshared - * - * _POSIX_THREAD_SAFE_FUNCTIONS (== 200112L) - * If == 200112L you can use the special *_r library - * functions that provide thread-safe behaviour - * - * _POSIX_READER_WRITER_LOCKS (== 200112L) - * If == 200112L, you can use read/write locks - * - * _POSIX_SPIN_LOCKS (== 200112L) - * If == 200112L, you can use spin locks - * - * _POSIX_BARRIERS (== 200112L) - * If == 200112L, you can use barriers - * - * + These functions provide both 'inherit' and/or - * 'protect' protocol, based upon these macro - * settings. - * - * ------------------------------------------------------------- - */ - -/* - * POSIX Options - */ -#undef _POSIX_THREADS -#define _POSIX_THREADS 200112L - -#undef _POSIX_READER_WRITER_LOCKS -#define _POSIX_READER_WRITER_LOCKS 200112L - -#undef _POSIX_SPIN_LOCKS -#define _POSIX_SPIN_LOCKS 200112L - -#undef _POSIX_BARRIERS -#define _POSIX_BARRIERS 200112L - -#undef _POSIX_THREAD_SAFE_FUNCTIONS -#define _POSIX_THREAD_SAFE_FUNCTIONS 200112L - -#undef _POSIX_THREAD_ATTR_STACKSIZE -#define _POSIX_THREAD_ATTR_STACKSIZE 200112L - -/* - * The following options are not supported - */ -#undef _POSIX_THREAD_ATTR_STACKADDR -#define _POSIX_THREAD_ATTR_STACKADDR -1 - -#undef _POSIX_THREAD_PRIO_INHERIT -#define _POSIX_THREAD_PRIO_INHERIT -1 - -#undef _POSIX_THREAD_PRIO_PROTECT -#define _POSIX_THREAD_PRIO_PROTECT -1 - -/* TPS is not fully supported. */ -#undef _POSIX_THREAD_PRIORITY_SCHEDULING -#define _POSIX_THREAD_PRIORITY_SCHEDULING -1 - -#undef _POSIX_THREAD_PROCESS_SHARED -#define _POSIX_THREAD_PROCESS_SHARED -1 - - -/* - * POSIX 1003.1-2001 Limits - * =========================== - * - * These limits are normally set in , which is not provided with - * pthreads-win32. - * - * PTHREAD_DESTRUCTOR_ITERATIONS - * Maximum number of attempts to destroy - * a thread's thread-specific data on - * termination (must be at least 4) - * - * PTHREAD_KEYS_MAX - * Maximum number of thread-specific data keys - * available per process (must be at least 128) - * - * PTHREAD_STACK_MIN - * Minimum supported stack size for a thread - * - * PTHREAD_THREADS_MAX - * Maximum number of threads supported per - * process (must be at least 64). - * - * SEM_NSEMS_MAX - * The maximum number of semaphores a process can have. - * (must be at least 256) - * - * SEM_VALUE_MAX - * The maximum value a semaphore can have. - * (must be at least 32767) - * - */ -#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS -#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 - -#undef PTHREAD_DESTRUCTOR_ITERATIONS -#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS - -#undef _POSIX_THREAD_KEYS_MAX -#define _POSIX_THREAD_KEYS_MAX 128 - -#undef PTHREAD_KEYS_MAX -#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX - -#undef PTHREAD_STACK_MIN -#define PTHREAD_STACK_MIN 0 - -#undef _POSIX_THREAD_THREADS_MAX -#define _POSIX_THREAD_THREADS_MAX 64 - - /* Arbitrary value */ -#undef PTHREAD_THREADS_MAX -#define PTHREAD_THREADS_MAX 2019 - -#undef _POSIX_SEM_NSEMS_MAX -#define _POSIX_SEM_NSEMS_MAX 256 - - /* Arbitrary value */ -#undef SEM_NSEMS_MAX -#define SEM_NSEMS_MAX 1024 - -#undef _POSIX_SEM_VALUE_MAX -#define _POSIX_SEM_VALUE_MAX 32767 - -#undef SEM_VALUE_MAX -#define SEM_VALUE_MAX INT_MAX - - -#if __GNUC__ && ! defined (__declspec) -# error Please upgrade your GNU compiler to one that supports __declspec. -#endif - -/* - * When building the DLL code, you should define PTW32_BUILD so that - * the variables/functions are exported correctly. When using the DLL, - * do NOT define PTW32_BUILD, and then the variables/functions will - * be imported correctly. - */ -#ifndef PTW32_STATIC_LIB -# ifdef PTW32_BUILD -# define PTW32_DLLPORT __declspec (dllexport) -# else -# define PTW32_DLLPORT __declspec (dllimport) -# endif -#else -# define PTW32_DLLPORT -#endif - -/* - * The Open Watcom C/C++ compiler uses a non-standard calling convention - * that passes function args in registers unless __cdecl is explicitly specified - * in exposed function prototypes. - * - * We force all calls to cdecl even though this could slow Watcom code down - * slightly. If you know that the Watcom compiler will be used to build both - * the DLL and application, then you can probably define this as a null string. - * Remember that pthread.h (this file) is used for both the DLL and application builds. - */ -#define PTW32_CDECL __cdecl - -#if defined(_UWIN) && PTW32_LEVEL >= PTW32_LEVEL_MAX -# include -#else -/* - * Generic handle type - intended to extend uniqueness beyond - * that available with a simple pointer. It should scale for either - * IA-32 or IA-64. - */ -typedef struct _ptw32_handle_t { - void * p; /* Pointer to actual object */ - unsigned int x; /* Extra information - reuse count etc */ - -#ifdef __cplusplus - // Added support for various operators so that the struct is - // more pthreads-compliant in behavior. (air) - const bool operator ==( const void* rightside ) - { - return p == rightside; - } - - const bool operator !=( const void* rightside ) - { - return p != rightside; - } - - bool operator =( void* rightside ) - { - p = rightside; - } -#endif - -} ptw32_handle_t; - -typedef ptw32_handle_t pthread_t; -typedef struct pthread_attr_t_ * pthread_attr_t; -typedef struct pthread_once_t_ pthread_once_t; -typedef struct pthread_key_t_ * pthread_key_t; -typedef struct pthread_mutex_t_ * pthread_mutex_t; -typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t; -typedef struct pthread_cond_t_ * pthread_cond_t; -typedef struct pthread_condattr_t_ * pthread_condattr_t; -#endif -typedef struct pthread_rwlock_t_ * pthread_rwlock_t; -typedef struct pthread_rwlockattr_t_ * pthread_rwlockattr_t; -typedef struct pthread_spinlock_t_ * pthread_spinlock_t; -typedef struct pthread_barrier_t_ * pthread_barrier_t; -typedef struct pthread_barrierattr_t_ * pthread_barrierattr_t; - -/* - * ==================== - * ==================== - * POSIX Threads - * ==================== - * ==================== - */ - -enum { -/* - * pthread_attr_{get,set}detachstate - */ - PTHREAD_CREATE_JOINABLE = 0, /* Default */ - PTHREAD_CREATE_DETACHED = 1, - -/* - * pthread_attr_{get,set}inheritsched - */ - PTHREAD_INHERIT_SCHED = 0, - PTHREAD_EXPLICIT_SCHED = 1, /* Default */ - -/* - * pthread_{get,set}scope - */ - PTHREAD_SCOPE_PROCESS = 0, - PTHREAD_SCOPE_SYSTEM = 1, /* Default */ - -/* - * pthread_setcancelstate paramters - */ - PTHREAD_CANCEL_ENABLE = 0, /* Default */ - PTHREAD_CANCEL_DISABLE = 1, - -/* - * pthread_setcanceltype parameters - */ - PTHREAD_CANCEL_ASYNCHRONOUS = 0, - PTHREAD_CANCEL_DEFERRED = 1, /* Default */ - -/* - * pthread_mutexattr_{get,set}pshared - * pthread_condattr_{get,set}pshared - */ - PTHREAD_PROCESS_PRIVATE = 0, - PTHREAD_PROCESS_SHARED = 1, - -/* - * pthread_barrier_wait - */ - PTHREAD_BARRIER_SERIAL_THREAD = -1 -}; - -/* - * ==================== - * ==================== - * Cancelation - * ==================== - * ==================== - */ -#define PTHREAD_CANCELED ((void *) -1) - - -/* - * ==================== - * ==================== - * Once Key - * ==================== - * ==================== - */ -#define PTHREAD_ONCE_INIT { PTW32_FALSE, 0, 0, 0} - -struct pthread_once_t_ -{ - int done; /* indicates if user function has been executed */ - void * lock; - int reserved1; - int reserved2; -}; - - -/* - * ==================== - * ==================== - * Object initialisers - * ==================== - * ==================== - */ -#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) -1) -#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t) -2) -#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t) -3) - -/* - * Compatibility with LinuxThreads - */ -#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER -#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER - -#define PTHREAD_COND_INITIALIZER ((pthread_cond_t) -1) - -#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) -1) - -#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t) -1) - - -/* - * Mutex types. - */ -enum -{ - /* Compatibility with LinuxThreads */ - PTHREAD_MUTEX_FAST_NP, - PTHREAD_MUTEX_RECURSIVE_NP, - PTHREAD_MUTEX_ERRORCHECK_NP, - PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP, - PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP, - /* For compatibility with POSIX */ - PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP, - PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, - PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, - PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL -}; - - -typedef struct ptw32_cleanup_t ptw32_cleanup_t; - -#if defined(_MSC_VER) -/* Disable MSVC 'anachronism used' warning */ -#pragma warning( disable : 4229 ) -#endif - -typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *); - -#if defined(_MSC_VER) -#pragma warning( default : 4229 ) -#endif - -struct ptw32_cleanup_t -{ - ptw32_cleanup_callback_t routine; - void *arg; - struct ptw32_cleanup_t *prev; -}; - -#ifdef __CLEANUP_SEH - /* - * WIN32 SEH version of cancel cleanup. - */ - -#define pthread_cleanup_push( _rout, _arg ) \ - { \ - ptw32_cleanup_t _cleanup; \ - \ - _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \ - _cleanup.arg = (_arg); \ - __try \ - { \ - -#define pthread_cleanup_pop( _execute ) \ - } \ - __finally \ - { \ - if( _execute || AbnormalTermination()) \ - { \ - (*(_cleanup.routine))( _cleanup.arg ); \ - } \ - } \ - } - -#else /* __CLEANUP_SEH */ - -#ifdef __CLEANUP_C - - /* - * C implementation of PThreads cancel cleanup - */ - -#define pthread_cleanup_push( _rout, _arg ) \ - { \ - ptw32_cleanup_t _cleanup; \ - \ - ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \ - -#define pthread_cleanup_pop( _execute ) \ - (void) ptw32_pop_cleanup( _execute ); \ - } - -#else /* __CLEANUP_C */ - -#ifdef __CLEANUP_CXX - - /* - * C++ version of cancel cleanup. - * - John E. Bossom. - */ - - class PThreadCleanup { - /* - * PThreadCleanup - * - * Purpose - * This class is a C++ helper class that is - * used to implement pthread_cleanup_push/ - * pthread_cleanup_pop. - * The destructor of this class automatically - * pops the pushed cleanup routine regardless - * of how the code exits the scope - * (i.e. such as by an exception) - */ - ptw32_cleanup_callback_t cleanUpRout; - void * obj; - int executeIt; - - public: - PThreadCleanup() : - cleanUpRout( 0 ), - obj( 0 ), - executeIt( 0 ) - /* - * No cleanup performed - */ - { - } - - PThreadCleanup( - ptw32_cleanup_callback_t routine, - void * arg ) : - cleanUpRout( routine ), - obj( arg ), - executeIt( 1 ) - /* - * Registers a cleanup routine for 'arg' - */ - { - } - - ~PThreadCleanup() - { - if ( executeIt && ((void *) cleanUpRout != (void *) 0) ) - { - (void) (*cleanUpRout)( obj ); - } - } - - void execute( int exec ) - { - executeIt = exec; - } - }; - - /* - * C++ implementation of PThreads cancel cleanup; - * This implementation takes advantage of a helper - * class who's destructor automatically calls the - * cleanup routine if we exit our scope weirdly - */ -#define pthread_cleanup_push( _rout, _arg ) \ - { \ - PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \ - (void *) (_arg) ); - -#define pthread_cleanup_pop( _execute ) \ - cleanup.execute( _execute ); \ - } - -#else - -#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. - -#endif /* __CLEANUP_CXX */ - -#endif /* __CLEANUP_C */ - -#endif /* __CLEANUP_SEH */ - -/* - * =============== - * =============== - * Methods - * =============== - * =============== - */ - -/* - * PThread Attribute Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getdetachstate (const pthread_attr_t * attr, - int *detachstate); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstackaddr (const pthread_attr_t * attr, - void **stackaddr); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstacksize (const pthread_attr_t * attr, - size_t * stacksize); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setdetachstate (pthread_attr_t * attr, - int detachstate); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstackaddr (pthread_attr_t * attr, - void *stackaddr); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstacksize (pthread_attr_t * attr, - size_t stacksize); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedparam (const pthread_attr_t *attr, - struct sched_param *param); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedparam (pthread_attr_t *attr, - const struct sched_param *param); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedpolicy (pthread_attr_t *, - int); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedpolicy (pthread_attr_t *, - int *); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setinheritsched(pthread_attr_t * attr, - int inheritsched); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getinheritsched(pthread_attr_t * attr, - int * inheritsched); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setscope (pthread_attr_t *, - int); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getscope (const pthread_attr_t *, - int *); - -/* - * PThread Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid, - const pthread_attr_t * attr, - void *(*start) (void *), - void *arg); - -PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid); - -PTW32_DLLPORT int PTW32_CDECL pthread_equal (pthread_t t1, - pthread_t t2); - -PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr); - -PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread, - void **value_ptr); - -PTW32_DLLPORT pthread_t PTW32_CDECL pthread_self (void); - -PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread); - -PTW32_DLLPORT int PTW32_CDECL pthread_setcancelstate (int state, - int *oldstate); - -PTW32_DLLPORT int PTW32_CDECL pthread_setcanceltype (int type, - int *oldtype); - -PTW32_DLLPORT void PTW32_CDECL pthread_testcancel (void); - -PTW32_DLLPORT int PTW32_CDECL pthread_once (pthread_once_t * once_control, - void (*init_routine) (void)); - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX -PTW32_DLLPORT ptw32_cleanup_t * PTW32_CDECL ptw32_pop_cleanup (int execute); - -PTW32_DLLPORT void PTW32_CDECL ptw32_push_cleanup (ptw32_cleanup_t * cleanup, - void (*routine) (void *), - void *arg); -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -/* - * Thread Specific Data Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_key_create (pthread_key_t * key, - void (*destructor) (void *)); - -PTW32_DLLPORT int PTW32_CDECL pthread_key_delete (pthread_key_t key); - -PTW32_DLLPORT int PTW32_CDECL pthread_setspecific (pthread_key_t key, - const void *value); - -PTW32_DLLPORT void * PTW32_CDECL pthread_getspecific (pthread_key_t key); - - -/* - * Mutex Attribute Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_init (pthread_mutexattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_destroy (pthread_mutexattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getpshared (const pthread_mutexattr_t - * attr, - int *pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, - int pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind); -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind); - -/* - * Barrier Attribute Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_init (pthread_barrierattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_destroy (pthread_barrierattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_getpshared (const pthread_barrierattr_t - * attr, - int *pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, - int pshared); - -/* - * Mutex Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex, - const pthread_mutexattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t *mutex, - const struct timespec *abstime); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex); - -/* - * Spinlock Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_spin_init (pthread_spinlock_t * lock, int pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_spin_destroy (pthread_spinlock_t * lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_spin_lock (pthread_spinlock_t * lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_spin_trylock (pthread_spinlock_t * lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_spin_unlock (pthread_spinlock_t * lock); - -/* - * Barrier Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_barrier_init (pthread_barrier_t * barrier, - const pthread_barrierattr_t * attr, - unsigned int count); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrier_destroy (pthread_barrier_t * barrier); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrier_wait (pthread_barrier_t * barrier); - -/* - * Condition Variable Attribute Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_condattr_init (pthread_condattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_condattr_destroy (pthread_condattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_condattr_getpshared (const pthread_condattr_t * attr, - int *pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_condattr_setpshared (pthread_condattr_t * attr, - int pshared); - -/* - * Condition Variable Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_cond_init (pthread_cond_t * cond, - const pthread_condattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_destroy (pthread_cond_t * cond); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_wait (pthread_cond_t * cond, - pthread_mutex_t * mutex); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_timedwait (pthread_cond_t * cond, - pthread_mutex_t * mutex, - const struct timespec *abstime); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_signal (pthread_cond_t * cond); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_broadcast (pthread_cond_t * cond); - -/* - * Scheduling - */ -PTW32_DLLPORT int PTW32_CDECL pthread_setschedparam (pthread_t thread, - int policy, - const struct sched_param *param); - -PTW32_DLLPORT int PTW32_CDECL pthread_getschedparam (pthread_t thread, - int *policy, - struct sched_param *param); - -PTW32_DLLPORT int PTW32_CDECL pthread_setconcurrency (int); - -PTW32_DLLPORT int PTW32_CDECL pthread_getconcurrency (void); - -/* - * Read-Write Lock Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_init(pthread_rwlock_t *lock, - const pthread_rwlockattr_t *attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_destroy(pthread_rwlock_t *lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_tryrdlock(pthread_rwlock_t *); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_trywrlock(pthread_rwlock_t *); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_rdlock(pthread_rwlock_t *lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedrdlock(pthread_rwlock_t *lock, - const struct timespec *abstime); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_wrlock(pthread_rwlock_t *lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedwrlock(pthread_rwlock_t *lock, - const struct timespec *abstime); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_unlock(pthread_rwlock_t *lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_init (pthread_rwlockattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, - int *pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, - int pshared); - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 - -/* - * Signal Functions. Should be defined in but MSVC and MinGW32 - * already have signal.h that don't define these. - */ -PTW32_DLLPORT int PTW32_CDECL pthread_kill(pthread_t thread, int sig); - -/* - * Non-portable functions - */ - -/* - * Compatibility with Linux. - */ -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, - int kind); -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, - int *kind); - -/* - * Possibly supported by other POSIX threads implementations - */ -PTW32_DLLPORT int PTW32_CDECL pthread_delay_np (struct timespec * interval); -PTW32_DLLPORT int PTW32_CDECL pthread_num_processors_np(void); - -/* - * Useful if an application wants to statically link - * the lib rather than load the DLL at run-time. - */ -PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_attach_np(void); -PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_detach_np(void); -PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_attach_np(void); -PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_detach_np(void); - -/* - * Features that are auto-detected at load/run time. - */ -PTW32_DLLPORT int PTW32_CDECL pthread_win32_test_features_np(int); -enum ptw32_features { - PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE = 0x0001, /* System provides it. */ - PTW32_ALERTABLE_ASYNC_CANCEL = 0x0002 /* Can cancel blocked threads. */ -}; - -/* - * Register a system time change with the library. - * Causes the library to perform various functions - * in response to the change. Should be called whenever - * the application's top level window receives a - * WM_TIMECHANGE message. It can be passed directly to - * pthread_create() as a new thread if desired. - */ -PTW32_DLLPORT void * PTW32_CDECL pthread_timechange_handler_np(void *); - -#endif /*PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 */ - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX - -/* - * Returns the Win32 HANDLE for the POSIX thread. - */ -PTW32_DLLPORT HANDLE PTW32_CDECL pthread_getw32threadhandle_np(pthread_t thread); - - -/* - * Protected Methods - * - * This function blocks until the given WIN32 handle - * is signaled or pthread_cancel had been called. - * This function allows the caller to hook into the - * PThreads cancel mechanism. It is implemented using - * - * WaitForMultipleObjects - * - * on 'waitHandle' and a manually reset WIN32 Event - * used to implement pthread_cancel. The 'timeout' - * argument to TimedWait is simply passed to - * WaitForMultipleObjects. - */ -PTW32_DLLPORT int PTW32_CDECL pthreadCancelableWait (HANDLE waitHandle); -PTW32_DLLPORT int PTW32_CDECL pthreadCancelableTimedWait (HANDLE waitHandle, - DWORD timeout); - -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -/* - * Thread-Safe C Runtime Library Mappings. - */ -#ifndef _UWIN -# if defined(NEED_ERRNO) - PTW32_DLLPORT int * PTW32_CDECL _errno( void ); -# else -# ifndef errno -# if (defined(_MT) || defined(_DLL)) - __declspec(dllimport) extern int * __cdecl _errno(void); -# define errno (*_errno()) -# endif -# endif -# endif -#endif - -/* - * WIN32 C runtime library had been made thread-safe - * without affecting the user interface. Provide - * mappings from the UNIX thread-safe versions to - * the standard C runtime library calls. - * Only provide function mappings for functions that - * actually exist on WIN32. - */ - -#if !defined(__MINGW32__) -#define strtok_r( _s, _sep, _lasts ) \ - ( *(_lasts) = strtok( (_s), (_sep) ) ) -#endif /* !__MINGW32__ */ - -#define asctime_r( _tm, _buf ) \ - ( strcpy( (_buf), asctime( (_tm) ) ), \ - (_buf) ) - -#define ctime_r( _clock, _buf ) \ - ( strcpy( (_buf), ctime( (_clock) ) ), \ - (_buf) ) - -#define gmtime_r( _clock, _result ) \ - ( *(_result) = *gmtime( (_clock) ), \ - (_result) ) - -#define localtime_r( _clock, _result ) \ - ( *(_result) = *localtime( (_clock) ), \ - (_result) ) - -#define rand_r( _seed ) \ - ( _seed == _seed? rand() : rand() ) - - -/* - * Some compiler environments don't define some things. - */ -#if defined(__BORLANDC__) -# define _ftime ftime -# define _timeb timeb -#endif - -#ifdef __cplusplus - -/* - * Internal exceptions - */ -class ptw32_exception {}; -class ptw32_exception_cancel : public ptw32_exception {}; -class ptw32_exception_exit : public ptw32_exception {}; - -#endif - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX - -/* FIXME: This is only required if the library was built using SEH */ -/* - * Get internal SEH tag - */ -PTW32_DLLPORT DWORD PTW32_CDECL ptw32_get_exception_services_code(void); - -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -#ifndef PTW32_BUILD - -#ifdef __CLEANUP_SEH - -/* - * Redefine the SEH __except keyword to ensure that applications - * propagate our internal exceptions up to the library's internal handlers. - */ -#define __except( E ) \ - __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \ - ? EXCEPTION_CONTINUE_SEARCH : ( E ) ) - -#endif /* __CLEANUP_SEH */ - -#ifdef __CLEANUP_CXX - -/* - * Redefine the C++ catch keyword to ensure that applications - * propagate our internal exceptions up to the library's internal handlers. - */ -#ifdef _MSC_VER - /* - * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll' - * if you want Pthread-Win32 cancelation and pthread_exit to work. - */ - -#ifndef PtW32NoCatchWarn - -#pragma message("Specify \"/DPtW32NoCatchWarn\" compiler flag to skip this message.") -#pragma message("------------------------------------------------------------------") -#pragma message("When compiling applications with MSVC++ and C++ exception handling:") -#pragma message(" Replace any 'catch( ... )' in routines called from POSIX threads") -#pragma message(" with 'PtW32CatchAll' or 'CATCHALL' if you want POSIX thread") -#pragma message(" cancelation and pthread_exit to work. For example:") -#pragma message("") -#pragma message(" #ifdef PtW32CatchAll") -#pragma message(" PtW32CatchAll") -#pragma message(" #else") -#pragma message(" catch(...)") -#pragma message(" #endif") -#pragma message(" {") -#pragma message(" /* Catchall block processing */") -#pragma message(" }") -#pragma message("------------------------------------------------------------------") - -#endif - -#define PtW32CatchAll \ - catch( ptw32_exception & ) { throw; } \ - catch( ... ) - -#else /* _MSC_VER */ - -#define catch( E ) \ - catch( ptw32_exception & ) { throw; } \ - catch( E ) - -#endif /* _MSC_VER */ - -#endif /* __CLEANUP_CXX */ - -#endif /* ! PTW32_BUILD */ - -#ifdef __cplusplus -} /* End of extern "C" */ -#endif /* __cplusplus */ - -#ifdef PTW32__HANDLE_DEF -# undef HANDLE -#endif -#ifdef PTW32__DWORD_DEF -# undef DWORD -#endif - -#undef PTW32_LEVEL -#undef PTW32_LEVEL_MAX - -#endif /* ! RC_INVOKED */ - -#endif /* PTHREAD_H */ +/* This is an implementation of the threads API of POSIX 1003.1-2001. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if !defined( PTHREAD_H ) +#define PTHREAD_H + +/* + * See the README file for an explanation of the pthreads-win32 version + * numbering scheme and how the DLL is named etc. + */ +#define PTW32_VERSION 2,8,0,0 +#define PTW32_VERSION_STRING "2, 8, 0, 0\0" + +/* There are three implementations of cancel cleanup. + * Note that pthread.h is included in both application + * compilation units and also internally for the library. + * The code here and within the library aims to work + * for all reasonable combinations of environments. + * + * The three implementations are: + * + * WIN32 SEH + * C + * C++ + * + * Please note that exiting a push/pop block via + * "return", "exit", "break", or "continue" will + * lead to different behaviour amongst applications + * depending upon whether the library was built + * using SEH, C++, or C. For example, a library built + * with SEH will call the cleanup routine, while both + * C++ and C built versions will not. + */ + +/* + * Define defaults for cleanup code. + * Note: Unless the build explicitly defines one of the following, then + * we default to standard C style cleanup. This style uses setjmp/longjmp + * in the cancelation and thread exit implementations and therefore won't + * do stack unwinding if linked to applications that have it (e.g. + * C++ apps). This is currently consistent with most/all commercial Unix + * POSIX threads implementations. + */ +#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C ) +# define __CLEANUP_C +#endif + +#if defined( __CLEANUP_SEH ) && ( !defined( _MSC_VER ) && !defined(PTW32_RC_MSC)) +#error ERROR [__FILE__, line __LINE__]: SEH is not supported for this compiler. +#endif + +/* + * Stop here if we are being included by the resource compiler. + */ +#ifndef RC_INVOKED + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + +#ifdef _UWIN +# define HAVE_STRUCT_TIMESPEC 1 +# define HAVE_SIGNAL_H 1 +# undef HAVE_CONFIG_H +# pragma comment(lib, "pthread") +#endif + +/* + * ------------------------------------------------------------- + * + * + * Module: pthread.h + * + * Purpose: + * Provides an implementation of PThreads based upon the + * standard: + * + * POSIX 1003.1-2001 + * and + * The Single Unix Specification version 3 + * + * (these two are equivalent) + * + * in order to enhance code portability between Windows, + * various commercial Unix implementations, and Linux. + * + * See the ANNOUNCE file for a full list of conforming + * routines and defined constants, and a list of missing + * routines and constants not defined in this implementation. + * + * Authors: + * There have been many contributors to this library. + * The initial implementation was contributed by + * John Bossom, and several others have provided major + * sections or revisions of parts of the implementation. + * Often significant effort has been contributed to + * find and fix important bugs and other problems to + * improve the reliability of the library, which sometimes + * is not reflected in the amount of code which changed as + * result. + * As much as possible, the contributors are acknowledged + * in the ChangeLog file in the source code distribution + * where their changes are noted in detail. + * + * Contributors are listed in the CONTRIBUTORS file. + * + * As usual, all bouquets go to the contributors, and all + * brickbats go to the project maintainer. + * + * Maintainer: + * The code base for this project is coordinated and + * eventually pre-tested, packaged, and made available by + * + * Ross Johnson + * + * QA Testers: + * Ultimately, the library is tested in the real world by + * a host of competent and demanding scientists and + * engineers who report bugs and/or provide solutions + * which are then fixed or incorporated into subsequent + * versions of the library. Each time a bug is fixed, a + * test case is written to prove the fix and ensure + * that later changes to the code don't reintroduce the + * same error. The number of test cases is slowly growing + * and therefore so is the code reliability. + * + * Compliance: + * See the file ANNOUNCE for the list of implemented + * and not-implemented routines and defined options. + * Of course, these are all defined is this file as well. + * + * Web site: + * The source code and other information about this library + * are available from + * + * http://sources.redhat.com/pthreads-win32/ + * + * ------------------------------------------------------------- + */ + +/* Try to avoid including windows.h */ +#if defined(__MINGW32__) && defined(__cplusplus) +#define PTW32_INCLUDE_WINDOWS_H +#endif + +#ifdef PTW32_INCLUDE_WINDOWS_H +#include +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1300 || defined(__DMC__) +/* + * VC++6.0 or early compiler's header has no DWORD_PTR type. + */ +typedef unsigned long DWORD_PTR; +#endif +/* + * ----------------- + * autoconf switches + * ----------------- + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#ifndef NEED_FTIME +#include +#else /* NEED_FTIME */ +/* use native WIN32 time API */ +#endif /* NEED_FTIME */ + +#if HAVE_SIGNAL_H +#include +#endif /* HAVE_SIGNAL_H */ + +#include +#include + +/* + * Boolean values to make us independent of system includes. + */ +enum { + PTW32_FALSE = 0, + PTW32_TRUE = (! PTW32_FALSE) +}; + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#ifndef PTW32_CONFIG_H +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#ifdef NEED_ERRNO +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Several systems don't define some error numbers. + */ +#ifndef ENOTSUP +# define ENOTSUP 48 /* This is the value in Solaris. */ +#endif + +#ifndef ETIMEDOUT +# define ETIMEDOUT 10060 /* This is the value in winsock.h. */ +#endif + +#ifndef ENOSYS +# define ENOSYS 140 /* Semi-arbitrary value */ +#endif + +#ifndef EDEADLK +# ifdef EDEADLOCK +# define EDEADLK EDEADLOCK +# else +# define EDEADLK 36 /* This is the value in MSVC. */ +# endif +#endif + +#include + +/* + * To avoid including windows.h we define only those things that we + * actually need from it. + */ +#ifndef PTW32_INCLUDE_WINDOWS_H +#ifndef HANDLE +# define PTW32__HANDLE_DEF +# define HANDLE void * +#endif +#ifndef DWORD +# define PTW32__DWORD_DEF +# define DWORD unsigned long +#endif +#endif + +#ifndef HAVE_STRUCT_TIMESPEC +#define HAVE_STRUCT_TIMESPEC 1 +struct timespec { + long tv_sec; + long tv_nsec; +}; +#endif /* HAVE_STRUCT_TIMESPEC */ + +#ifndef SIG_BLOCK +#define SIG_BLOCK 0 +#endif /* SIG_BLOCK */ + +#ifndef SIG_UNBLOCK +#define SIG_UNBLOCK 1 +#endif /* SIG_UNBLOCK */ + +#ifndef SIG_SETMASK +#define SIG_SETMASK 2 +#endif /* SIG_SETMASK */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* + * ------------------------------------------------------------- + * + * POSIX 1003.1-2001 Options + * ========================= + * + * Options are normally set in , which is not provided + * with pthreads-win32. + * + * For conformance with the Single Unix Specification (version 3), all of the + * options below are defined, and have a value of either -1 (not supported) + * or 200112L (supported). + * + * These options can neither be left undefined nor have a value of 0, because + * either indicates that sysconf(), which is not implemented, may be used at + * runtime to check the status of the option. + * + * _POSIX_THREADS (== 200112L) + * If == 200112L, you can use threads + * + * _POSIX_THREAD_ATTR_STACKSIZE (== 200112L) + * If == 200112L, you can control the size of a thread's + * stack + * pthread_attr_getstacksize + * pthread_attr_setstacksize + * + * _POSIX_THREAD_ATTR_STACKADDR (== -1) + * If == 200112L, you can allocate and control a thread's + * stack. If not supported, the following functions + * will return ENOSYS, indicating they are not + * supported: + * pthread_attr_getstackaddr + * pthread_attr_setstackaddr + * + * _POSIX_THREAD_PRIORITY_SCHEDULING (== -1) + * If == 200112L, you can use realtime scheduling. + * This option indicates that the behaviour of some + * implemented functions conforms to the additional TPS + * requirements in the standard. E.g. rwlocks favour + * writers over readers when threads have equal priority. + * + * _POSIX_THREAD_PRIO_INHERIT (== -1) + * If == 200112L, you can create priority inheritance + * mutexes. + * pthread_mutexattr_getprotocol + + * pthread_mutexattr_setprotocol + + * + * _POSIX_THREAD_PRIO_PROTECT (== -1) + * If == 200112L, you can create priority ceiling mutexes + * Indicates the availability of: + * pthread_mutex_getprioceiling + * pthread_mutex_setprioceiling + * pthread_mutexattr_getprioceiling + * pthread_mutexattr_getprotocol + + * pthread_mutexattr_setprioceiling + * pthread_mutexattr_setprotocol + + * + * _POSIX_THREAD_PROCESS_SHARED (== -1) + * If set, you can create mutexes and condition + * variables that can be shared with another + * process.If set, indicates the availability + * of: + * pthread_mutexattr_getpshared + * pthread_mutexattr_setpshared + * pthread_condattr_getpshared + * pthread_condattr_setpshared + * + * _POSIX_THREAD_SAFE_FUNCTIONS (== 200112L) + * If == 200112L you can use the special *_r library + * functions that provide thread-safe behaviour + * + * _POSIX_READER_WRITER_LOCKS (== 200112L) + * If == 200112L, you can use read/write locks + * + * _POSIX_SPIN_LOCKS (== 200112L) + * If == 200112L, you can use spin locks + * + * _POSIX_BARRIERS (== 200112L) + * If == 200112L, you can use barriers + * + * + These functions provide both 'inherit' and/or + * 'protect' protocol, based upon these macro + * settings. + * + * ------------------------------------------------------------- + */ + +/* + * POSIX Options + */ +#undef _POSIX_THREADS +#define _POSIX_THREADS 200112L + +#undef _POSIX_READER_WRITER_LOCKS +#define _POSIX_READER_WRITER_LOCKS 200112L + +#undef _POSIX_SPIN_LOCKS +#define _POSIX_SPIN_LOCKS 200112L + +#undef _POSIX_BARRIERS +#define _POSIX_BARRIERS 200112L + +#undef _POSIX_THREAD_SAFE_FUNCTIONS +#define _POSIX_THREAD_SAFE_FUNCTIONS 200112L + +#undef _POSIX_THREAD_ATTR_STACKSIZE +#define _POSIX_THREAD_ATTR_STACKSIZE 200112L + +/* + * The following options are not supported + */ +#undef _POSIX_THREAD_ATTR_STACKADDR +#define _POSIX_THREAD_ATTR_STACKADDR -1 + +#undef _POSIX_THREAD_PRIO_INHERIT +#define _POSIX_THREAD_PRIO_INHERIT -1 + +#undef _POSIX_THREAD_PRIO_PROTECT +#define _POSIX_THREAD_PRIO_PROTECT -1 + +/* TPS is not fully supported. */ +#undef _POSIX_THREAD_PRIORITY_SCHEDULING +#define _POSIX_THREAD_PRIORITY_SCHEDULING -1 + +#undef _POSIX_THREAD_PROCESS_SHARED +#define _POSIX_THREAD_PROCESS_SHARED -1 + + +/* + * POSIX 1003.1-2001 Limits + * =========================== + * + * These limits are normally set in , which is not provided with + * pthreads-win32. + * + * PTHREAD_DESTRUCTOR_ITERATIONS + * Maximum number of attempts to destroy + * a thread's thread-specific data on + * termination (must be at least 4) + * + * PTHREAD_KEYS_MAX + * Maximum number of thread-specific data keys + * available per process (must be at least 128) + * + * PTHREAD_STACK_MIN + * Minimum supported stack size for a thread + * + * PTHREAD_THREADS_MAX + * Maximum number of threads supported per + * process (must be at least 64). + * + * SEM_NSEMS_MAX + * The maximum number of semaphores a process can have. + * (must be at least 256) + * + * SEM_VALUE_MAX + * The maximum value a semaphore can have. + * (must be at least 32767) + * + */ +#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 + +#undef PTHREAD_DESTRUCTOR_ITERATIONS +#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS + +#undef _POSIX_THREAD_KEYS_MAX +#define _POSIX_THREAD_KEYS_MAX 128 + +#undef PTHREAD_KEYS_MAX +#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX + +#undef PTHREAD_STACK_MIN +#define PTHREAD_STACK_MIN 0 + +#undef _POSIX_THREAD_THREADS_MAX +#define _POSIX_THREAD_THREADS_MAX 64 + + /* Arbitrary value */ +#undef PTHREAD_THREADS_MAX +#define PTHREAD_THREADS_MAX 2019 + +#undef _POSIX_SEM_NSEMS_MAX +#define _POSIX_SEM_NSEMS_MAX 256 + + /* Arbitrary value */ +#undef SEM_NSEMS_MAX +#define SEM_NSEMS_MAX 1024 + +#undef _POSIX_SEM_VALUE_MAX +#define _POSIX_SEM_VALUE_MAX 32767 + +#undef SEM_VALUE_MAX +#define SEM_VALUE_MAX INT_MAX + + +#if __GNUC__ && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the DLL code, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the DLL, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#ifndef PTW32_STATIC_LIB +# ifdef PTW32_BUILD +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * The Open Watcom C/C++ compiler uses a non-standard calling convention + * that passes function args in registers unless __cdecl is explicitly specified + * in exposed function prototypes. + * + * We force all calls to cdecl even though this could slow Watcom code down + * slightly. If you know that the Watcom compiler will be used to build both + * the DLL and application, then you can probably define this as a null string. + * Remember that pthread.h (this file) is used for both the DLL and application builds. + */ +#define PTW32_CDECL __cdecl + +#if defined(_UWIN) && PTW32_LEVEL >= PTW32_LEVEL_MAX +# include +#else +/* + * Generic handle type - intended to extend uniqueness beyond + * that available with a simple pointer. It should scale for either + * IA-32 or IA-64. + */ +typedef struct _ptw32_handle_t { + void * p; /* Pointer to actual object */ + unsigned int x; /* Extra information - reuse count etc */ + +#ifdef __cplusplus + // Added support for various operators so that the struct is + // more pthreads-compliant in behavior. (air) + const bool operator ==( const void* rightside ) + { + return p == rightside; + } + + const bool operator !=( const void* rightside ) + { + return p != rightside; + } + + bool operator =( void* rightside ) + { + p = rightside; + } +#endif + +} ptw32_handle_t; + +typedef ptw32_handle_t pthread_t; +typedef struct pthread_attr_t_ * pthread_attr_t; +typedef struct pthread_once_t_ pthread_once_t; +typedef struct pthread_key_t_ * pthread_key_t; +typedef struct pthread_mutex_t_ * pthread_mutex_t; +typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t; +typedef struct pthread_cond_t_ * pthread_cond_t; +typedef struct pthread_condattr_t_ * pthread_condattr_t; +#endif +typedef struct pthread_rwlock_t_ * pthread_rwlock_t; +typedef struct pthread_rwlockattr_t_ * pthread_rwlockattr_t; +typedef struct pthread_spinlock_t_ * pthread_spinlock_t; +typedef struct pthread_barrier_t_ * pthread_barrier_t; +typedef struct pthread_barrierattr_t_ * pthread_barrierattr_t; + +/* + * ==================== + * ==================== + * POSIX Threads + * ==================== + * ==================== + */ + +enum { +/* + * pthread_attr_{get,set}detachstate + */ + PTHREAD_CREATE_JOINABLE = 0, /* Default */ + PTHREAD_CREATE_DETACHED = 1, + +/* + * pthread_attr_{get,set}inheritsched + */ + PTHREAD_INHERIT_SCHED = 0, + PTHREAD_EXPLICIT_SCHED = 1, /* Default */ + +/* + * pthread_{get,set}scope + */ + PTHREAD_SCOPE_PROCESS = 0, + PTHREAD_SCOPE_SYSTEM = 1, /* Default */ + +/* + * pthread_setcancelstate paramters + */ + PTHREAD_CANCEL_ENABLE = 0, /* Default */ + PTHREAD_CANCEL_DISABLE = 1, + +/* + * pthread_setcanceltype parameters + */ + PTHREAD_CANCEL_ASYNCHRONOUS = 0, + PTHREAD_CANCEL_DEFERRED = 1, /* Default */ + +/* + * pthread_mutexattr_{get,set}pshared + * pthread_condattr_{get,set}pshared + */ + PTHREAD_PROCESS_PRIVATE = 0, + PTHREAD_PROCESS_SHARED = 1, + +/* + * pthread_barrier_wait + */ + PTHREAD_BARRIER_SERIAL_THREAD = -1 +}; + +/* + * ==================== + * ==================== + * Cancelation + * ==================== + * ==================== + */ +#define PTHREAD_CANCELED ((void *) -1) + + +/* + * ==================== + * ==================== + * Once Key + * ==================== + * ==================== + */ +#define PTHREAD_ONCE_INIT { PTW32_FALSE, 0, 0, 0} + +struct pthread_once_t_ +{ + int done; /* indicates if user function has been executed */ + void * lock; + int reserved1; + int reserved2; +}; + + +/* + * ==================== + * ==================== + * Object initialisers + * ==================== + * ==================== + */ +#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) -1) +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t) -2) +#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t) -3) + +/* + * Compatibility with LinuxThreads + */ +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER +#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER + +#define PTHREAD_COND_INITIALIZER ((pthread_cond_t) -1) + +#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) -1) + +#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t) -1) + + +/* + * Mutex types. + */ +enum +{ + /* Compatibility with LinuxThreads */ + PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP, + /* For compatibility with POSIX */ + PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL +}; + + +typedef struct ptw32_cleanup_t ptw32_cleanup_t; + +#if defined(_MSC_VER) +/* Disable MSVC 'anachronism used' warning */ +#pragma warning( disable : 4229 ) +#endif + +typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *); + +#if defined(_MSC_VER) +#pragma warning( default : 4229 ) +#endif + +struct ptw32_cleanup_t +{ + ptw32_cleanup_callback_t routine; + void *arg; + struct ptw32_cleanup_t *prev; +}; + +#ifdef __CLEANUP_SEH + /* + * WIN32 SEH version of cancel cleanup. + */ + +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + ptw32_cleanup_t _cleanup; \ + \ + _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \ + _cleanup.arg = (_arg); \ + __try \ + { \ + +#define pthread_cleanup_pop( _execute ) \ + } \ + __finally \ + { \ + if( _execute || AbnormalTermination()) \ + { \ + (*(_cleanup.routine))( _cleanup.arg ); \ + } \ + } \ + } + +#else /* __CLEANUP_SEH */ + +#ifdef __CLEANUP_C + + /* + * C implementation of PThreads cancel cleanup + */ + +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + ptw32_cleanup_t _cleanup; \ + \ + ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \ + +#define pthread_cleanup_pop( _execute ) \ + (void) ptw32_pop_cleanup( _execute ); \ + } + +#else /* __CLEANUP_C */ + +#ifdef __CLEANUP_CXX + + /* + * C++ version of cancel cleanup. + * - John E. Bossom. + */ + + class PThreadCleanup { + /* + * PThreadCleanup + * + * Purpose + * This class is a C++ helper class that is + * used to implement pthread_cleanup_push/ + * pthread_cleanup_pop. + * The destructor of this class automatically + * pops the pushed cleanup routine regardless + * of how the code exits the scope + * (i.e. such as by an exception) + */ + ptw32_cleanup_callback_t cleanUpRout; + void * obj; + int executeIt; + + public: + PThreadCleanup() : + cleanUpRout( 0 ), + obj( 0 ), + executeIt( 0 ) + /* + * No cleanup performed + */ + { + } + + PThreadCleanup( + ptw32_cleanup_callback_t routine, + void * arg ) : + cleanUpRout( routine ), + obj( arg ), + executeIt( 1 ) + /* + * Registers a cleanup routine for 'arg' + */ + { + } + + ~PThreadCleanup() + { + if ( executeIt && ((void *) cleanUpRout != (void *) 0) ) + { + (void) (*cleanUpRout)( obj ); + } + } + + void execute( int exec ) + { + executeIt = exec; + } + }; + + /* + * C++ implementation of PThreads cancel cleanup; + * This implementation takes advantage of a helper + * class who's destructor automatically calls the + * cleanup routine if we exit our scope weirdly + */ +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \ + (void *) (_arg) ); + +#define pthread_cleanup_pop( _execute ) \ + cleanup.execute( _execute ); \ + } + +#else + +#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. + +#endif /* __CLEANUP_CXX */ + +#endif /* __CLEANUP_C */ + +#endif /* __CLEANUP_SEH */ + +/* + * =============== + * =============== + * Methods + * =============== + * =============== + */ + +/* + * PThread Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getdetachstate (const pthread_attr_t * attr, + int *detachstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstackaddr (const pthread_attr_t * attr, + void **stackaddr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstacksize (const pthread_attr_t * attr, + size_t * stacksize); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setdetachstate (pthread_attr_t * attr, + int detachstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstackaddr (pthread_attr_t * attr, + void *stackaddr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstacksize (pthread_attr_t * attr, + size_t stacksize); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedparam (const pthread_attr_t *attr, + struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedparam (pthread_attr_t *attr, + const struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedpolicy (pthread_attr_t *, + int); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedpolicy (pthread_attr_t *, + int *); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setinheritsched(pthread_attr_t * attr, + int inheritsched); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getinheritsched(pthread_attr_t * attr, + int * inheritsched); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setscope (pthread_attr_t *, + int); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getscope (const pthread_attr_t *, + int *); + +/* + * PThread Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid, + const pthread_attr_t * attr, + void *(*start) (void *), + void *arg); + +PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid); + +PTW32_DLLPORT int PTW32_CDECL pthread_equal (pthread_t t1, + pthread_t t2); + +PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr); + +PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread, + void **value_ptr); + +PTW32_DLLPORT pthread_t PTW32_CDECL pthread_self (void); + +PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread); + +PTW32_DLLPORT int PTW32_CDECL pthread_setcancelstate (int state, + int *oldstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_setcanceltype (int type, + int *oldtype); + +PTW32_DLLPORT void PTW32_CDECL pthread_testcancel (void); + +PTW32_DLLPORT int PTW32_CDECL pthread_once (pthread_once_t * once_control, + void (*init_routine) (void)); + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +PTW32_DLLPORT ptw32_cleanup_t * PTW32_CDECL ptw32_pop_cleanup (int execute); + +PTW32_DLLPORT void PTW32_CDECL ptw32_push_cleanup (ptw32_cleanup_t * cleanup, + void (*routine) (void *), + void *arg); +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Thread Specific Data Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_key_create (pthread_key_t * key, + void (*destructor) (void *)); + +PTW32_DLLPORT int PTW32_CDECL pthread_key_delete (pthread_key_t key); + +PTW32_DLLPORT int PTW32_CDECL pthread_setspecific (pthread_key_t key, + const void *value); + +PTW32_DLLPORT void * PTW32_CDECL pthread_getspecific (pthread_key_t key); + + +/* + * Mutex Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_init (pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_destroy (pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getpshared (const pthread_mutexattr_t + * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, + int pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind); + +/* + * Barrier Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_init (pthread_barrierattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_destroy (pthread_barrierattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_getpshared (const pthread_barrierattr_t + * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, + int pshared); + +/* + * Mutex Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex, + const pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t *mutex, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex); + +/* + * Spinlock Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_spin_init (pthread_spinlock_t * lock, int pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_destroy (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_lock (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_trylock (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_unlock (pthread_spinlock_t * lock); + +/* + * Barrier Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_init (pthread_barrier_t * barrier, + const pthread_barrierattr_t * attr, + unsigned int count); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_destroy (pthread_barrier_t * barrier); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_wait (pthread_barrier_t * barrier); + +/* + * Condition Variable Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_init (pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_destroy (pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_getpshared (const pthread_condattr_t * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_setpshared (pthread_condattr_t * attr, + int pshared); + +/* + * Condition Variable Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_cond_init (pthread_cond_t * cond, + const pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_destroy (pthread_cond_t * cond); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_wait (pthread_cond_t * cond, + pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_timedwait (pthread_cond_t * cond, + pthread_mutex_t * mutex, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_signal (pthread_cond_t * cond); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_broadcast (pthread_cond_t * cond); + +/* + * Scheduling + */ +PTW32_DLLPORT int PTW32_CDECL pthread_setschedparam (pthread_t thread, + int policy, + const struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_getschedparam (pthread_t thread, + int *policy, + struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_setconcurrency (int); + +PTW32_DLLPORT int PTW32_CDECL pthread_getconcurrency (void); + +/* + * Read-Write Lock Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_init(pthread_rwlock_t *lock, + const pthread_rwlockattr_t *attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_destroy(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_tryrdlock(pthread_rwlock_t *); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_trywrlock(pthread_rwlock_t *); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_rdlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedrdlock(pthread_rwlock_t *lock, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_wrlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedwrlock(pthread_rwlock_t *lock, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_unlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_init (pthread_rwlockattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, + int pshared); + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 + +/* + * Signal Functions. Should be defined in but MSVC and MinGW32 + * already have signal.h that don't define these. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_kill(pthread_t thread, int sig); + +/* + * Non-portable functions + */ + +/* + * Compatibility with Linux. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, + int kind); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, + int *kind); + +/* + * Possibly supported by other POSIX threads implementations + */ +PTW32_DLLPORT int PTW32_CDECL pthread_delay_np (struct timespec * interval); +PTW32_DLLPORT int PTW32_CDECL pthread_num_processors_np(void); + +/* + * Useful if an application wants to statically link + * the lib rather than load the DLL at run-time. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_attach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_detach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_attach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_detach_np(void); + +/* + * Features that are auto-detected at load/run time. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_win32_test_features_np(int); +enum ptw32_features { + PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE = 0x0001, /* System provides it. */ + PTW32_ALERTABLE_ASYNC_CANCEL = 0x0002 /* Can cancel blocked threads. */ +}; + +/* + * Register a system time change with the library. + * Causes the library to perform various functions + * in response to the change. Should be called whenever + * the application's top level window receives a + * WM_TIMECHANGE message. It can be passed directly to + * pthread_create() as a new thread if desired. + */ +PTW32_DLLPORT void * PTW32_CDECL pthread_timechange_handler_np(void *); + +#endif /*PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX + +/* + * Returns the Win32 HANDLE for the POSIX thread. + */ +PTW32_DLLPORT HANDLE PTW32_CDECL pthread_getw32threadhandle_np(pthread_t thread); + + +/* + * Protected Methods + * + * This function blocks until the given WIN32 handle + * is signaled or pthread_cancel had been called. + * This function allows the caller to hook into the + * PThreads cancel mechanism. It is implemented using + * + * WaitForMultipleObjects + * + * on 'waitHandle' and a manually reset WIN32 Event + * used to implement pthread_cancel. The 'timeout' + * argument to TimedWait is simply passed to + * WaitForMultipleObjects. + */ +PTW32_DLLPORT int PTW32_CDECL pthreadCancelableWait (HANDLE waitHandle); +PTW32_DLLPORT int PTW32_CDECL pthreadCancelableTimedWait (HANDLE waitHandle, + DWORD timeout); + +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Thread-Safe C Runtime Library Mappings. + */ +#ifndef _UWIN +# if defined(NEED_ERRNO) + PTW32_DLLPORT int * PTW32_CDECL _errno( void ); +# else +# ifndef errno +# if (defined(_MT) || defined(_DLL)) + __declspec(dllimport) extern int * __cdecl _errno(void); +# define errno (*_errno()) +# endif +# endif +# endif +#endif + +/* + * WIN32 C runtime library had been made thread-safe + * without affecting the user interface. Provide + * mappings from the UNIX thread-safe versions to + * the standard C runtime library calls. + * Only provide function mappings for functions that + * actually exist on WIN32. + */ + +#if !defined(__MINGW32__) +#define strtok_r( _s, _sep, _lasts ) \ + ( *(_lasts) = strtok( (_s), (_sep) ) ) +#endif /* !__MINGW32__ */ + +#define asctime_r( _tm, _buf ) \ + ( strcpy( (_buf), asctime( (_tm) ) ), \ + (_buf) ) + +#define ctime_r( _clock, _buf ) \ + ( strcpy( (_buf), ctime( (_clock) ) ), \ + (_buf) ) + +#define gmtime_r( _clock, _result ) \ + ( *(_result) = *gmtime( (_clock) ), \ + (_result) ) + +#define localtime_r( _clock, _result ) \ + ( *(_result) = *localtime( (_clock) ), \ + (_result) ) + +#define rand_r( _seed ) \ + ( _seed == _seed? rand() : rand() ) + + +/* + * Some compiler environments don't define some things. + */ +#if defined(__BORLANDC__) +# define _ftime ftime +# define _timeb timeb +#endif + +#ifdef __cplusplus + +/* + * Internal exceptions + */ +class ptw32_exception {}; +class ptw32_exception_cancel : public ptw32_exception {}; +class ptw32_exception_exit : public ptw32_exception {}; + +#endif + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX + +/* FIXME: This is only required if the library was built using SEH */ +/* + * Get internal SEH tag + */ +PTW32_DLLPORT DWORD PTW32_CDECL ptw32_get_exception_services_code(void); + +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#ifndef PTW32_BUILD + +#ifdef __CLEANUP_SEH + +/* + * Redefine the SEH __except keyword to ensure that applications + * propagate our internal exceptions up to the library's internal handlers. + */ +#define __except( E ) \ + __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \ + ? EXCEPTION_CONTINUE_SEARCH : ( E ) ) + +#endif /* __CLEANUP_SEH */ + +#ifdef __CLEANUP_CXX + +/* + * Redefine the C++ catch keyword to ensure that applications + * propagate our internal exceptions up to the library's internal handlers. + */ +#ifdef _MSC_VER + /* + * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll' + * if you want Pthread-Win32 cancelation and pthread_exit to work. + */ + +#ifndef PtW32NoCatchWarn + +#pragma message("Specify \"/DPtW32NoCatchWarn\" compiler flag to skip this message.") +#pragma message("------------------------------------------------------------------") +#pragma message("When compiling applications with MSVC++ and C++ exception handling:") +#pragma message(" Replace any 'catch( ... )' in routines called from POSIX threads") +#pragma message(" with 'PtW32CatchAll' or 'CATCHALL' if you want POSIX thread") +#pragma message(" cancelation and pthread_exit to work. For example:") +#pragma message("") +#pragma message(" #ifdef PtW32CatchAll") +#pragma message(" PtW32CatchAll") +#pragma message(" #else") +#pragma message(" catch(...)") +#pragma message(" #endif") +#pragma message(" {") +#pragma message(" /* Catchall block processing */") +#pragma message(" }") +#pragma message("------------------------------------------------------------------") + +#endif + +#define PtW32CatchAll \ + catch( ptw32_exception & ) { throw; } \ + catch( ... ) + +#else /* _MSC_VER */ + +#define catch( E ) \ + catch( ptw32_exception & ) { throw; } \ + catch( E ) + +#endif /* _MSC_VER */ + +#endif /* __CLEANUP_CXX */ + +#endif /* ! PTW32_BUILD */ + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#ifdef PTW32__HANDLE_DEF +# undef HANDLE +#endif +#ifdef PTW32__DWORD_DEF +# undef DWORD +#endif + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* ! RC_INVOKED */ + +#endif /* PTHREAD_H */ diff --git a/pcsx2/windows/pthreads/pthread_attr_destroy.c b/pcsx2/windows/pthreads/pthread_attr_destroy.c index 0ae40b5552..8b3e04c536 100644 --- a/pcsx2/windows/pthreads/pthread_attr_destroy.c +++ b/pcsx2/windows/pthreads/pthread_attr_destroy.c @@ -1,79 +1,79 @@ -/* - * pthread_attr_destroy.c - * - * Description: - * This translation unit implements operations on thread attribute objects. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_attr_destroy (pthread_attr_t * attr) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Destroys a thread attributes object. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_attr_t - * - * - * DESCRIPTION - * Destroys a thread attributes object. - * - * NOTES: - * 1) Does not affect threads created with 'attr'. - * - * RESULTS - * 0 successfully destroyed attr, - * EINVAL 'attr' is invalid. - * - * ------------------------------------------------------ - */ -{ - if (ptw32_is_attr (attr) != 0) - { - return EINVAL; - } - - /* - * Set the attribute object to a specific invalid value. - */ - (*attr)->valid = 0; - free (*attr); - *attr = NULL; - - return 0; -} +/* + * pthread_attr_destroy.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_attr_destroy (pthread_attr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Destroys a thread attributes object. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * + * DESCRIPTION + * Destroys a thread attributes object. + * + * NOTES: + * 1) Does not affect threads created with 'attr'. + * + * RESULTS + * 0 successfully destroyed attr, + * EINVAL 'attr' is invalid. + * + * ------------------------------------------------------ + */ +{ + if (ptw32_is_attr (attr) != 0) + { + return EINVAL; + } + + /* + * Set the attribute object to a specific invalid value. + */ + (*attr)->valid = 0; + free (*attr); + *attr = NULL; + + return 0; +} diff --git a/pcsx2/windows/pthreads/pthread_attr_getdetachstate.c b/pcsx2/windows/pthreads/pthread_attr_getdetachstate.c index 45eb4f254c..978f288494 100644 --- a/pcsx2/windows/pthreads/pthread_attr_getdetachstate.c +++ b/pcsx2/windows/pthreads/pthread_attr_getdetachstate.c @@ -1,87 +1,87 @@ -/* - * pthread_attr_getdetachstate.c - * - * Description: - * This translation unit implements operations on thread attribute objects. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_attr_getdetachstate (const pthread_attr_t * attr, int *detachstate) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function determines whether threads created with - * 'attr' will run detached. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_attr_t - * - * detachstate - * pointer to an integer into which is returned one - * of: - * - * PTHREAD_CREATE_JOINABLE - * Thread ID is valid, must be joined - * - * PTHREAD_CREATE_DETACHED - * Thread ID is invalid, cannot be joined, - * canceled, or modified - * - * - * DESCRIPTION - * This function determines whether threads created with - * 'attr' will run detached. - * - * NOTES: - * 1) You cannot join or cancel detached threads. - * - * RESULTS - * 0 successfully retrieved detach state, - * EINVAL 'attr' is invalid - * - * ------------------------------------------------------ - */ -{ - if (ptw32_is_attr (attr) != 0 || detachstate == NULL) - { - *detachstate = PTHREAD_CREATE_DETACHED; - return EINVAL; - } - - *detachstate = (*attr)->detachstate; - return 0; -} +/* + * pthread_attr_getdetachstate.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_attr_getdetachstate (const pthread_attr_t * attr, int *detachstate) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function determines whether threads created with + * 'attr' will run detached. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * detachstate + * pointer to an integer into which is returned one + * of: + * + * PTHREAD_CREATE_JOINABLE + * Thread ID is valid, must be joined + * + * PTHREAD_CREATE_DETACHED + * Thread ID is invalid, cannot be joined, + * canceled, or modified + * + * + * DESCRIPTION + * This function determines whether threads created with + * 'attr' will run detached. + * + * NOTES: + * 1) You cannot join or cancel detached threads. + * + * RESULTS + * 0 successfully retrieved detach state, + * EINVAL 'attr' is invalid + * + * ------------------------------------------------------ + */ +{ + if (ptw32_is_attr (attr) != 0 || detachstate == NULL) + { + *detachstate = PTHREAD_CREATE_DETACHED; + return EINVAL; + } + + *detachstate = (*attr)->detachstate; + return 0; +} diff --git a/pcsx2/windows/pthreads/pthread_attr_getinheritsched.c b/pcsx2/windows/pthreads/pthread_attr_getinheritsched.c index e9901f7933..5085077a66 100644 --- a/pcsx2/windows/pthreads/pthread_attr_getinheritsched.c +++ b/pcsx2/windows/pthreads/pthread_attr_getinheritsched.c @@ -1,51 +1,51 @@ -/* - * pthread_attr_getinheritsched.c - * - * Description: - * POSIX thread functions that deal with thread scheduling. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" -#include "sched.h" - -int -pthread_attr_getinheritsched (pthread_attr_t * attr, int *inheritsched) -{ - if (ptw32_is_attr (attr) != 0 || inheritsched == NULL) - { - return EINVAL; - } - - *inheritsched = (*attr)->inheritsched; - return 0; -} +/* + * pthread_attr_getinheritsched.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +pthread_attr_getinheritsched (pthread_attr_t * attr, int *inheritsched) +{ + if (ptw32_is_attr (attr) != 0 || inheritsched == NULL) + { + return EINVAL; + } + + *inheritsched = (*attr)->inheritsched; + return 0; +} diff --git a/pcsx2/windows/pthreads/pthread_attr_getschedparam.c b/pcsx2/windows/pthreads/pthread_attr_getschedparam.c index 7ec68cbcdf..ab89b2241a 100644 --- a/pcsx2/windows/pthreads/pthread_attr_getschedparam.c +++ b/pcsx2/windows/pthreads/pthread_attr_getschedparam.c @@ -1,52 +1,52 @@ -/* - * pthread_attr_getschedparam.c - * - * Description: - * POSIX thread functions that deal with thread scheduling. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" -#include "sched.h" - -int -pthread_attr_getschedparam (const pthread_attr_t * attr, - struct sched_param *param) -{ - if (ptw32_is_attr (attr) != 0 || param == NULL) - { - return EINVAL; - } - - memcpy (param, &(*attr)->param, sizeof (*param)); - return 0; -} +/* + * pthread_attr_getschedparam.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +pthread_attr_getschedparam (const pthread_attr_t * attr, + struct sched_param *param) +{ + if (ptw32_is_attr (attr) != 0 || param == NULL) + { + return EINVAL; + } + + memcpy (param, &(*attr)->param, sizeof (*param)); + return 0; +} diff --git a/pcsx2/windows/pthreads/pthread_attr_getschedpolicy.c b/pcsx2/windows/pthreads/pthread_attr_getschedpolicy.c index ccd91fd39e..04adbd5c64 100644 --- a/pcsx2/windows/pthreads/pthread_attr_getschedpolicy.c +++ b/pcsx2/windows/pthreads/pthread_attr_getschedpolicy.c @@ -1,61 +1,61 @@ -/* - * pthread_attr_getschedpolicy.c - * - * Description: - * POSIX thread functions that deal with thread scheduling. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" -#include "sched.h" - -int -pthread_attr_getschedpolicy (pthread_attr_t * attr, int *policy) -{ - if (ptw32_is_attr (attr) != 0 || policy == NULL) - { - return EINVAL; - } - - /* - * Validate the policy arg. - * Check that a policy constant wasn't passed rather than &policy. - */ - if (policy <= (int *) SCHED_MAX) - { - return EINVAL; - } - - *policy = SCHED_OTHER; - - return 0; -} +/* + * pthread_attr_getschedpolicy.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +pthread_attr_getschedpolicy (pthread_attr_t * attr, int *policy) +{ + if (ptw32_is_attr (attr) != 0 || policy == NULL) + { + return EINVAL; + } + + /* + * Validate the policy arg. + * Check that a policy constant wasn't passed rather than &policy. + */ + if (policy <= (int *) SCHED_MAX) + { + return EINVAL; + } + + *policy = SCHED_OTHER; + + return 0; +} diff --git a/pcsx2/windows/pthreads/pthread_attr_getscope.c b/pcsx2/windows/pthreads/pthread_attr_getscope.c index d0ca1cd346..3c863821ed 100644 --- a/pcsx2/windows/pthreads/pthread_attr_getscope.c +++ b/pcsx2/windows/pthreads/pthread_attr_getscope.c @@ -1,54 +1,54 @@ -/* - * pthread_attr_getscope.c - * - * Description: - * This translation unit implements operations on thread attribute objects. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -/* ignore warning "unreferenced formal parameter" */ -#ifdef _MSC_VER -#pragma warning( disable : 4100 ) -#endif - -int -pthread_attr_getscope (const pthread_attr_t * attr, int *contentionscope) -{ -#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING - *contentionscope = (*attr)->contentionscope; - return 0; -#else - return ENOSYS; -#endif -} +/* + * pthread_attr_getscope.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* ignore warning "unreferenced formal parameter" */ +#ifdef _MSC_VER +#pragma warning( disable : 4100 ) +#endif + +int +pthread_attr_getscope (const pthread_attr_t * attr, int *contentionscope) +{ +#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING + *contentionscope = (*attr)->contentionscope; + return 0; +#else + return ENOSYS; +#endif +} diff --git a/pcsx2/windows/pthreads/pthread_attr_getstackaddr.c b/pcsx2/windows/pthreads/pthread_attr_getstackaddr.c index 41bf16299a..9b5595928b 100644 --- a/pcsx2/windows/pthreads/pthread_attr_getstackaddr.c +++ b/pcsx2/windows/pthreads/pthread_attr_getstackaddr.c @@ -1,97 +1,97 @@ -/* - * pthread_attr_getstackaddr.c - * - * Description: - * This translation unit implements operations on thread attribute objects. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -/* ignore warning "unreferenced formal parameter" */ -#ifdef _MSC_VER -#pragma warning( disable : 4100 ) -#endif - -int -pthread_attr_getstackaddr (const pthread_attr_t * attr, void **stackaddr) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function determines the address of the stack - * on which threads created with 'attr' will run. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_attr_t - * - * stackaddr - * pointer into which is returned the stack address. - * - * - * DESCRIPTION - * This function determines the address of the stack - * on which threads created with 'attr' will run. - * - * NOTES: - * 1) Function supported only if this macro is - * defined: - * - * _POSIX_THREAD_ATTR_STACKADDR - * - * 2) Create only one thread for each stack - * address.. - * - * RESULTS - * 0 successfully retreived stack address, - * EINVAL 'attr' is invalid - * ENOSYS function not supported - * - * ------------------------------------------------------ - */ -{ -#if defined( _POSIX_THREAD_ATTR_STACKADDR ) - - if (ptw32_is_attr (attr) != 0) - { - return EINVAL; - } - - *stackaddr = (*attr)->stackaddr; - return 0; - -#else - - return ENOSYS; - -#endif /* _POSIX_THREAD_ATTR_STACKADDR */ -} +/* + * pthread_attr_getstackaddr.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* ignore warning "unreferenced formal parameter" */ +#ifdef _MSC_VER +#pragma warning( disable : 4100 ) +#endif + +int +pthread_attr_getstackaddr (const pthread_attr_t * attr, void **stackaddr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function determines the address of the stack + * on which threads created with 'attr' will run. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * stackaddr + * pointer into which is returned the stack address. + * + * + * DESCRIPTION + * This function determines the address of the stack + * on which threads created with 'attr' will run. + * + * NOTES: + * 1) Function supported only if this macro is + * defined: + * + * _POSIX_THREAD_ATTR_STACKADDR + * + * 2) Create only one thread for each stack + * address.. + * + * RESULTS + * 0 successfully retreived stack address, + * EINVAL 'attr' is invalid + * ENOSYS function not supported + * + * ------------------------------------------------------ + */ +{ +#if defined( _POSIX_THREAD_ATTR_STACKADDR ) + + if (ptw32_is_attr (attr) != 0) + { + return EINVAL; + } + + *stackaddr = (*attr)->stackaddr; + return 0; + +#else + + return ENOSYS; + +#endif /* _POSIX_THREAD_ATTR_STACKADDR */ +} diff --git a/pcsx2/windows/pthreads/pthread_attr_getstacksize.c b/pcsx2/windows/pthreads/pthread_attr_getstacksize.c index 9b4cbedbda..da8db636c8 100644 --- a/pcsx2/windows/pthreads/pthread_attr_getstacksize.c +++ b/pcsx2/windows/pthreads/pthread_attr_getstacksize.c @@ -1,100 +1,100 @@ -/* - * pthread_attr_getstacksize.c - * - * Description: - * This translation unit implements operations on thread attribute objects. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -/* ignore warning "unreferenced formal parameter" */ -#ifdef _MSC_VER -#pragma warning( disable : 4100 ) -#endif - -int -pthread_attr_getstacksize (const pthread_attr_t * attr, size_t * stacksize) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function determines the size of the stack on - * which threads created with 'attr' will run. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_attr_t - * - * stacksize - * pointer to size_t into which is returned the - * stack size, in bytes. - * - * - * DESCRIPTION - * This function determines the size of the stack on - * which threads created with 'attr' will run. - * - * NOTES: - * 1) Function supported only if this macro is - * defined: - * - * _POSIX_THREAD_ATTR_STACKSIZE - * - * 2) Use on newly created attributes object to - * find the default stack size. - * - * RESULTS - * 0 successfully retrieved stack size, - * EINVAL 'attr' is invalid - * ENOSYS function not supported - * - * ------------------------------------------------------ - */ -{ -#ifdef _POSIX_THREAD_ATTR_STACKSIZE - - if (ptw32_is_attr (attr) != 0) - { - return EINVAL; - } - - /* Everything is okay. */ - *stacksize = (*attr)->stacksize; - return 0; - -#else - - return ENOSYS; - -#endif /* _POSIX_THREAD_ATTR_STACKSIZE */ - -} +/* + * pthread_attr_getstacksize.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* ignore warning "unreferenced formal parameter" */ +#ifdef _MSC_VER +#pragma warning( disable : 4100 ) +#endif + +int +pthread_attr_getstacksize (const pthread_attr_t * attr, size_t * stacksize) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function determines the size of the stack on + * which threads created with 'attr' will run. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * stacksize + * pointer to size_t into which is returned the + * stack size, in bytes. + * + * + * DESCRIPTION + * This function determines the size of the stack on + * which threads created with 'attr' will run. + * + * NOTES: + * 1) Function supported only if this macro is + * defined: + * + * _POSIX_THREAD_ATTR_STACKSIZE + * + * 2) Use on newly created attributes object to + * find the default stack size. + * + * RESULTS + * 0 successfully retrieved stack size, + * EINVAL 'attr' is invalid + * ENOSYS function not supported + * + * ------------------------------------------------------ + */ +{ +#ifdef _POSIX_THREAD_ATTR_STACKSIZE + + if (ptw32_is_attr (attr) != 0) + { + return EINVAL; + } + + /* Everything is okay. */ + *stacksize = (*attr)->stacksize; + return 0; + +#else + + return ENOSYS; + +#endif /* _POSIX_THREAD_ATTR_STACKSIZE */ + +} diff --git a/pcsx2/windows/pthreads/pthread_attr_init.c b/pcsx2/windows/pthreads/pthread_attr_init.c index bf13449f70..6c10bd3e7f 100644 --- a/pcsx2/windows/pthreads/pthread_attr_init.c +++ b/pcsx2/windows/pthreads/pthread_attr_init.c @@ -1,117 +1,117 @@ -/* - * pthread_attr_init.c - * - * Description: - * This translation unit implements operations on thread attribute objects. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_attr_init (pthread_attr_t * attr) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Initializes a thread attributes object with default - * attributes. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_attr_t - * - * - * DESCRIPTION - * Initializes a thread attributes object with default - * attributes. - * - * NOTES: - * 1) Used to define thread attributes - * - * RESULTS - * 0 successfully initialized attr, - * ENOMEM insufficient memory for attr. - * - * ------------------------------------------------------ - */ -{ - pthread_attr_t attr_result; - - if (attr == NULL) - { - /* This is disallowed. */ - return EINVAL; - } - - attr_result = (pthread_attr_t) malloc (sizeof (*attr_result)); - - if (attr_result == NULL) - { - return ENOMEM; - } - -#ifdef _POSIX_THREAD_ATTR_STACKSIZE - /* - * Default to zero size. Unless changed explicitly this - * will allow Win32 to set the size to that of the - * main thread. - */ - attr_result->stacksize = 0; -#endif - -#ifdef _POSIX_THREAD_ATTR_STACKADDR - /* FIXME: Set this to something sensible when we support it. */ - attr_result->stackaddr = NULL; -#endif - - attr_result->detachstate = PTHREAD_CREATE_JOINABLE; - -#if HAVE_SIGSET_T - memset (&(attr_result->sigmask), 0, sizeof (sigset_t)); -#endif /* HAVE_SIGSET_T */ - - /* - * Win32 sets new threads to THREAD_PRIORITY_NORMAL and - * not to that of the parent thread. We choose to default to - * this arrangement. - */ - attr_result->param.sched_priority = THREAD_PRIORITY_NORMAL; - attr_result->inheritsched = PTHREAD_EXPLICIT_SCHED; - attr_result->contentionscope = PTHREAD_SCOPE_SYSTEM; - - attr_result->valid = PTW32_ATTR_VALID; - - *attr = attr_result; - - return 0; -} +/* + * pthread_attr_init.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_attr_init (pthread_attr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Initializes a thread attributes object with default + * attributes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * + * DESCRIPTION + * Initializes a thread attributes object with default + * attributes. + * + * NOTES: + * 1) Used to define thread attributes + * + * RESULTS + * 0 successfully initialized attr, + * ENOMEM insufficient memory for attr. + * + * ------------------------------------------------------ + */ +{ + pthread_attr_t attr_result; + + if (attr == NULL) + { + /* This is disallowed. */ + return EINVAL; + } + + attr_result = (pthread_attr_t) malloc (sizeof (*attr_result)); + + if (attr_result == NULL) + { + return ENOMEM; + } + +#ifdef _POSIX_THREAD_ATTR_STACKSIZE + /* + * Default to zero size. Unless changed explicitly this + * will allow Win32 to set the size to that of the + * main thread. + */ + attr_result->stacksize = 0; +#endif + +#ifdef _POSIX_THREAD_ATTR_STACKADDR + /* FIXME: Set this to something sensible when we support it. */ + attr_result->stackaddr = NULL; +#endif + + attr_result->detachstate = PTHREAD_CREATE_JOINABLE; + +#if HAVE_SIGSET_T + memset (&(attr_result->sigmask), 0, sizeof (sigset_t)); +#endif /* HAVE_SIGSET_T */ + + /* + * Win32 sets new threads to THREAD_PRIORITY_NORMAL and + * not to that of the parent thread. We choose to default to + * this arrangement. + */ + attr_result->param.sched_priority = THREAD_PRIORITY_NORMAL; + attr_result->inheritsched = PTHREAD_EXPLICIT_SCHED; + attr_result->contentionscope = PTHREAD_SCOPE_SYSTEM; + + attr_result->valid = PTW32_ATTR_VALID; + + *attr = attr_result; + + return 0; +} diff --git a/pcsx2/windows/pthreads/pthread_attr_setdetachstate.c b/pcsx2/windows/pthreads/pthread_attr_setdetachstate.c index d96c20c92a..784642a807 100644 --- a/pcsx2/windows/pthreads/pthread_attr_setdetachstate.c +++ b/pcsx2/windows/pthreads/pthread_attr_setdetachstate.c @@ -1,91 +1,91 @@ -/* - * pthread_attr_setdetachstate.c - * - * Description: - * This translation unit implements operations on thread attribute objects. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_attr_setdetachstate (pthread_attr_t * attr, int detachstate) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function specifies whether threads created with - * 'attr' will run detached. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_attr_t - * - * detachstate - * an integer containing one of: - * - * PTHREAD_CREATE_JOINABLE - * Thread ID is valid, must be joined - * - * PTHREAD_CREATE_DETACHED - * Thread ID is invalid, cannot be joined, - * canceled, or modified - * - * - * DESCRIPTION - * This function specifies whether threads created with - * 'attr' will run detached. - * - * NOTES: - * 1) You cannot join or cancel detached threads. - * - * RESULTS - * 0 successfully set detach state, - * EINVAL 'attr' or 'detachstate' is invalid - * - * ------------------------------------------------------ - */ -{ - if (ptw32_is_attr (attr) != 0) - { - return EINVAL; - } - - if (detachstate != PTHREAD_CREATE_JOINABLE && - detachstate != PTHREAD_CREATE_DETACHED) - { - return EINVAL; - } - - (*attr)->detachstate = detachstate; - return 0; -} +/* + * pthread_attr_setdetachstate.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_attr_setdetachstate (pthread_attr_t * attr, int detachstate) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function specifies whether threads created with + * 'attr' will run detached. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * detachstate + * an integer containing one of: + * + * PTHREAD_CREATE_JOINABLE + * Thread ID is valid, must be joined + * + * PTHREAD_CREATE_DETACHED + * Thread ID is invalid, cannot be joined, + * canceled, or modified + * + * + * DESCRIPTION + * This function specifies whether threads created with + * 'attr' will run detached. + * + * NOTES: + * 1) You cannot join or cancel detached threads. + * + * RESULTS + * 0 successfully set detach state, + * EINVAL 'attr' or 'detachstate' is invalid + * + * ------------------------------------------------------ + */ +{ + if (ptw32_is_attr (attr) != 0) + { + return EINVAL; + } + + if (detachstate != PTHREAD_CREATE_JOINABLE && + detachstate != PTHREAD_CREATE_DETACHED) + { + return EINVAL; + } + + (*attr)->detachstate = detachstate; + return 0; +} diff --git a/pcsx2/windows/pthreads/pthread_attr_setinheritsched.c b/pcsx2/windows/pthreads/pthread_attr_setinheritsched.c index 8f92559a45..e0a407a3b7 100644 --- a/pcsx2/windows/pthreads/pthread_attr_setinheritsched.c +++ b/pcsx2/windows/pthreads/pthread_attr_setinheritsched.c @@ -1,57 +1,57 @@ -/* - * pthread_attr_setinheritsched.c - * - * Description: - * POSIX thread functions that deal with thread scheduling. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" -#include "sched.h" - -int -pthread_attr_setinheritsched (pthread_attr_t * attr, int inheritsched) -{ - if (ptw32_is_attr (attr) != 0) - { - return EINVAL; - } - - if (PTHREAD_INHERIT_SCHED != inheritsched - && PTHREAD_EXPLICIT_SCHED != inheritsched) - { - return EINVAL; - } - - (*attr)->inheritsched = inheritsched; - return 0; -} +/* + * pthread_attr_setinheritsched.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +pthread_attr_setinheritsched (pthread_attr_t * attr, int inheritsched) +{ + if (ptw32_is_attr (attr) != 0) + { + return EINVAL; + } + + if (PTHREAD_INHERIT_SCHED != inheritsched + && PTHREAD_EXPLICIT_SCHED != inheritsched) + { + return EINVAL; + } + + (*attr)->inheritsched = inheritsched; + return 0; +} diff --git a/pcsx2/windows/pthreads/pthread_attr_setschedparam.c b/pcsx2/windows/pthreads/pthread_attr_setschedparam.c index cf380577db..f246bfae7a 100644 --- a/pcsx2/windows/pthreads/pthread_attr_setschedparam.c +++ b/pcsx2/windows/pthreads/pthread_attr_setschedparam.c @@ -1,63 +1,63 @@ -/* - * pthread_attr_setschedparam.c - * - * Description: - * POSIX thread functions that deal with thread scheduling. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" -#include "sched.h" - -int -pthread_attr_setschedparam (pthread_attr_t * attr, - const struct sched_param *param) -{ - int priority; - - if (ptw32_is_attr (attr) != 0 || param == NULL) - { - return EINVAL; - } - - priority = param->sched_priority; - - /* Validate priority level. */ - if (priority < sched_get_priority_min (SCHED_OTHER) || - priority > sched_get_priority_max (SCHED_OTHER)) - { - return EINVAL; - } - - memcpy (&(*attr)->param, param, sizeof (*param)); - return 0; -} +/* + * pthread_attr_setschedparam.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +pthread_attr_setschedparam (pthread_attr_t * attr, + const struct sched_param *param) +{ + int priority; + + if (ptw32_is_attr (attr) != 0 || param == NULL) + { + return EINVAL; + } + + priority = param->sched_priority; + + /* Validate priority level. */ + if (priority < sched_get_priority_min (SCHED_OTHER) || + priority > sched_get_priority_max (SCHED_OTHER)) + { + return EINVAL; + } + + memcpy (&(*attr)->param, param, sizeof (*param)); + return 0; +} diff --git a/pcsx2/windows/pthreads/pthread_attr_setschedpolicy.c b/pcsx2/windows/pthreads/pthread_attr_setschedpolicy.c index 3a1ed6679b..45ff165973 100644 --- a/pcsx2/windows/pthreads/pthread_attr_setschedpolicy.c +++ b/pcsx2/windows/pthreads/pthread_attr_setschedpolicy.c @@ -1,55 +1,55 @@ -/* - * pthread_attr_setschedpolicy.c - * - * Description: - * POSIX thread functions that deal with thread scheduling. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" -#include "sched.h" - -int -pthread_attr_setschedpolicy (pthread_attr_t * attr, int policy) -{ - if (ptw32_is_attr (attr) != 0) - { - return EINVAL; - } - - if (policy != SCHED_OTHER) - { - return ENOTSUP; - } - - return 0; -} +/* + * pthread_attr_setschedpolicy.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +pthread_attr_setschedpolicy (pthread_attr_t * attr, int policy) +{ + if (ptw32_is_attr (attr) != 0) + { + return EINVAL; + } + + if (policy != SCHED_OTHER) + { + return ENOTSUP; + } + + return 0; +} diff --git a/pcsx2/windows/pthreads/pthread_attr_setscope.c b/pcsx2/windows/pthreads/pthread_attr_setscope.c index 9892034f89..9cef423b25 100644 --- a/pcsx2/windows/pthreads/pthread_attr_setscope.c +++ b/pcsx2/windows/pthreads/pthread_attr_setscope.c @@ -1,62 +1,62 @@ -/* - * pthread_attr_setscope.c - * - * Description: - * This translation unit implements operations on thread attribute objects. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -/* ignore warning "unreferenced formal parameter" */ -#ifdef _MSC_VER -#pragma warning( disable : 4100 ) -#endif - -int -pthread_attr_setscope (pthread_attr_t * attr, int contentionscope) -{ -#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING - switch (contentionscope) - { - case PTHREAD_SCOPE_SYSTEM: - (*attr)->contentionscope = contentionscope; - return 0; - case PTHREAD_SCOPE_PROCESS: - return ENOTSUP; - default: - return EINVAL; - } -#else - return ENOSYS; -#endif -} +/* + * pthread_attr_setscope.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* ignore warning "unreferenced formal parameter" */ +#ifdef _MSC_VER +#pragma warning( disable : 4100 ) +#endif + +int +pthread_attr_setscope (pthread_attr_t * attr, int contentionscope) +{ +#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING + switch (contentionscope) + { + case PTHREAD_SCOPE_SYSTEM: + (*attr)->contentionscope = contentionscope; + return 0; + case PTHREAD_SCOPE_PROCESS: + return ENOTSUP; + default: + return EINVAL; + } +#else + return ENOSYS; +#endif +} diff --git a/pcsx2/windows/pthreads/pthread_attr_setstackaddr.c b/pcsx2/windows/pthreads/pthread_attr_setstackaddr.c index ce35f31cf7..96a8320971 100644 --- a/pcsx2/windows/pthreads/pthread_attr_setstackaddr.c +++ b/pcsx2/windows/pthreads/pthread_attr_setstackaddr.c @@ -1,97 +1,97 @@ -/* - * pthread_attr_setstackaddr.c - * - * Description: - * This translation unit implements operations on thread attribute objects. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_attr_setstackaddr (pthread_attr_t * attr, void *stackaddr) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Threads created with 'attr' will run on the stack - * starting at 'stackaddr'. - * Stack must be at least PTHREAD_STACK_MIN bytes. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_attr_t - * - * stacksize - * stack size, in bytes. - * - * - * DESCRIPTION - * Threads created with 'attr' will run on the stack - * starting at 'stackaddr'. - * Stack must be at least PTHREAD_STACK_MIN bytes. - * - * NOTES: - * 1) Function supported only if this macro is - * defined: - * - * _POSIX_THREAD_ATTR_STACKADDR - * - * 2) Create only one thread for each stack - * address.. - * - * 3) Ensure that stackaddr is aligned. - * - * RESULTS - * 0 successfully set stack address, - * EINVAL 'attr' is invalid - * ENOSYS function not supported - * - * ------------------------------------------------------ - */ -{ -#if defined( _POSIX_THREAD_ATTR_STACKADDR ) - - if (ptw32_is_attr (attr) != 0) - { - return EINVAL; - } - - (*attr)->stackaddr = stackaddr; - return 0; - -#else - - return ENOSYS; - -#endif /* _POSIX_THREAD_ATTR_STACKADDR */ -} +/* + * pthread_attr_setstackaddr.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_attr_setstackaddr (pthread_attr_t * attr, void *stackaddr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Threads created with 'attr' will run on the stack + * starting at 'stackaddr'. + * Stack must be at least PTHREAD_STACK_MIN bytes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * stacksize + * stack size, in bytes. + * + * + * DESCRIPTION + * Threads created with 'attr' will run on the stack + * starting at 'stackaddr'. + * Stack must be at least PTHREAD_STACK_MIN bytes. + * + * NOTES: + * 1) Function supported only if this macro is + * defined: + * + * _POSIX_THREAD_ATTR_STACKADDR + * + * 2) Create only one thread for each stack + * address.. + * + * 3) Ensure that stackaddr is aligned. + * + * RESULTS + * 0 successfully set stack address, + * EINVAL 'attr' is invalid + * ENOSYS function not supported + * + * ------------------------------------------------------ + */ +{ +#if defined( _POSIX_THREAD_ATTR_STACKADDR ) + + if (ptw32_is_attr (attr) != 0) + { + return EINVAL; + } + + (*attr)->stackaddr = stackaddr; + return 0; + +#else + + return ENOSYS; + +#endif /* _POSIX_THREAD_ATTR_STACKADDR */ +} diff --git a/pcsx2/windows/pthreads/pthread_attr_setstacksize.c b/pcsx2/windows/pthreads/pthread_attr_setstacksize.c index f1bc263692..9df46afc47 100644 --- a/pcsx2/windows/pthreads/pthread_attr_setstacksize.c +++ b/pcsx2/windows/pthreads/pthread_attr_setstacksize.c @@ -1,110 +1,110 @@ -/* - * pthread_attr_setstacksize.c - * - * Description: - * This translation unit implements operations on thread attribute objects. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_attr_setstacksize (pthread_attr_t * attr, size_t stacksize) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function specifies the size of the stack on - * which threads created with 'attr' will run. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_attr_t - * - * stacksize - * stack size, in bytes. - * - * - * DESCRIPTION - * This function specifies the size of the stack on - * which threads created with 'attr' will run. - * - * NOTES: - * 1) Function supported only if this macro is - * defined: - * - * _POSIX_THREAD_ATTR_STACKSIZE - * - * 2) Find the default first (using - * pthread_attr_getstacksize), then increase - * by multiplying. - * - * 3) Only use if thread needs more than the - * default. - * - * RESULTS - * 0 successfully set stack size, - * EINVAL 'attr' is invalid or stacksize too - * small or too big. - * ENOSYS function not supported - * - * ------------------------------------------------------ - */ -{ -#ifdef _POSIX_THREAD_ATTR_STACKSIZE - -#if PTHREAD_STACK_MIN > 0 - - /* Verify that the stack size is within range. */ - if (stacksize < PTHREAD_STACK_MIN) - { - return EINVAL; - } - -#endif - - if (ptw32_is_attr (attr) != 0) - { - return EINVAL; - } - - /* Everything is okay. */ - (*attr)->stacksize = stacksize; - return 0; - -#else - - return ENOSYS; - -#endif /* _POSIX_THREAD_ATTR_STACKSIZE */ - -} +/* + * pthread_attr_setstacksize.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_attr_setstacksize (pthread_attr_t * attr, size_t stacksize) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function specifies the size of the stack on + * which threads created with 'attr' will run. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * stacksize + * stack size, in bytes. + * + * + * DESCRIPTION + * This function specifies the size of the stack on + * which threads created with 'attr' will run. + * + * NOTES: + * 1) Function supported only if this macro is + * defined: + * + * _POSIX_THREAD_ATTR_STACKSIZE + * + * 2) Find the default first (using + * pthread_attr_getstacksize), then increase + * by multiplying. + * + * 3) Only use if thread needs more than the + * default. + * + * RESULTS + * 0 successfully set stack size, + * EINVAL 'attr' is invalid or stacksize too + * small or too big. + * ENOSYS function not supported + * + * ------------------------------------------------------ + */ +{ +#ifdef _POSIX_THREAD_ATTR_STACKSIZE + +#if PTHREAD_STACK_MIN > 0 + + /* Verify that the stack size is within range. */ + if (stacksize < PTHREAD_STACK_MIN) + { + return EINVAL; + } + +#endif + + if (ptw32_is_attr (attr) != 0) + { + return EINVAL; + } + + /* Everything is okay. */ + (*attr)->stacksize = stacksize; + return 0; + +#else + + return ENOSYS; + +#endif /* _POSIX_THREAD_ATTR_STACKSIZE */ + +} diff --git a/pcsx2/windows/pthreads/pthread_barrier_destroy.c b/pcsx2/windows/pthreads/pthread_barrier_destroy.c index bfff3181d6..9302ba7975 100644 --- a/pcsx2/windows/pthreads/pthread_barrier_destroy.c +++ b/pcsx2/windows/pthreads/pthread_barrier_destroy.c @@ -1,67 +1,67 @@ -/* - * pthread_barrier_destroy.c - * - * Description: - * This translation unit implements barrier primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_barrier_destroy (pthread_barrier_t * barrier) -{ - int result = 0; - pthread_barrier_t b; - - if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID) - { - return EINVAL; - } - - b = *barrier; - *barrier = NULL; - - if (0 == (result = sem_destroy (&(b->semBarrierBreeched[0])))) - { - if (0 == (result = sem_destroy (&(b->semBarrierBreeched[1])))) - { - (void) free (b); - return 0; - } - (void) sem_init (&(b->semBarrierBreeched[0]), b->pshared, 0); - } - - *barrier = b; - return (result); -} +/* + * pthread_barrier_destroy.c + * + * Description: + * This translation unit implements barrier primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_barrier_destroy (pthread_barrier_t * barrier) +{ + int result = 0; + pthread_barrier_t b; + + if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID) + { + return EINVAL; + } + + b = *barrier; + *barrier = NULL; + + if (0 == (result = sem_destroy (&(b->semBarrierBreeched[0])))) + { + if (0 == (result = sem_destroy (&(b->semBarrierBreeched[1])))) + { + (void) free (b); + return 0; + } + (void) sem_init (&(b->semBarrierBreeched[0]), b->pshared, 0); + } + + *barrier = b; + return (result); +} diff --git a/pcsx2/windows/pthreads/pthread_barrier_init.c b/pcsx2/windows/pthreads/pthread_barrier_init.c index b588e73b31..dc1b50c6f7 100644 --- a/pcsx2/windows/pthreads/pthread_barrier_init.c +++ b/pcsx2/windows/pthreads/pthread_barrier_init.c @@ -1,81 +1,81 @@ -/* - * pthread_barrier_init.c - * - * Description: - * This translation unit implements barrier primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_barrier_init (pthread_barrier_t * barrier, - const pthread_barrierattr_t * attr, unsigned int count) -{ - pthread_barrier_t b; - - if (barrier == NULL || count == 0) - { - return EINVAL; - } - - if (NULL != (b = (pthread_barrier_t) calloc (1, sizeof (*b)))) - { - b->pshared = (attr != NULL && *attr != NULL - ? (*attr)->pshared : PTHREAD_PROCESS_PRIVATE); - - b->nCurrentBarrierHeight = b->nInitialBarrierHeight = count; - b->iStep = 0; - - /* - * Two semaphores are used in the same way as two stepping - * stones might be used in crossing a stream. Once all - * threads are safely on one stone, the other stone can - * be moved ahead, and the threads can start moving to it. - * If some threads decide to eat their lunch before moving - * then the other threads have to wait. - */ - if (0 == sem_init (&(b->semBarrierBreeched[0]), b->pshared, 0)) - { - if (0 == sem_init (&(b->semBarrierBreeched[1]), b->pshared, 0)) - { - *barrier = b; - return 0; - } - (void) sem_destroy (&(b->semBarrierBreeched[0])); - } - (void) free (b); - } - - return ENOMEM; -} +/* + * pthread_barrier_init.c + * + * Description: + * This translation unit implements barrier primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_barrier_init (pthread_barrier_t * barrier, + const pthread_barrierattr_t * attr, unsigned int count) +{ + pthread_barrier_t b; + + if (barrier == NULL || count == 0) + { + return EINVAL; + } + + if (NULL != (b = (pthread_barrier_t) calloc (1, sizeof (*b)))) + { + b->pshared = (attr != NULL && *attr != NULL + ? (*attr)->pshared : PTHREAD_PROCESS_PRIVATE); + + b->nCurrentBarrierHeight = b->nInitialBarrierHeight = count; + b->iStep = 0; + + /* + * Two semaphores are used in the same way as two stepping + * stones might be used in crossing a stream. Once all + * threads are safely on one stone, the other stone can + * be moved ahead, and the threads can start moving to it. + * If some threads decide to eat their lunch before moving + * then the other threads have to wait. + */ + if (0 == sem_init (&(b->semBarrierBreeched[0]), b->pshared, 0)) + { + if (0 == sem_init (&(b->semBarrierBreeched[1]), b->pshared, 0)) + { + *barrier = b; + return 0; + } + (void) sem_destroy (&(b->semBarrierBreeched[0])); + } + (void) free (b); + } + + return ENOMEM; +} diff --git a/pcsx2/windows/pthreads/pthread_barrier_wait.c b/pcsx2/windows/pthreads/pthread_barrier_wait.c index cb9a08ee07..01ae29766e 100644 --- a/pcsx2/windows/pthreads/pthread_barrier_wait.c +++ b/pcsx2/windows/pthreads/pthread_barrier_wait.c @@ -1,99 +1,99 @@ -/* - * pthread_barrier_wait.c - * - * Description: - * This translation unit implements barrier primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_barrier_wait (pthread_barrier_t * barrier) -{ - int result; - int step; - pthread_barrier_t b; - - if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID) - { - return EINVAL; - } - - b = *barrier; - step = b->iStep; - - if (0 == InterlockedDecrement ((long *) &(b->nCurrentBarrierHeight))) - { - /* Must be done before posting the semaphore. */ - b->nCurrentBarrierHeight = b->nInitialBarrierHeight; - - /* - * There is no race condition between the semaphore wait and post - * because we are using two alternating semas and all threads have - * entered barrier_wait and checked nCurrentBarrierHeight before this - * barrier's sema can be posted. Any threads that have not quite - * entered sem_wait below when the multiple_post has completed - * will nevertheless continue through the semaphore (barrier) - * and will not be left stranded. - */ - result = (b->nInitialBarrierHeight > 1 - ? sem_post_multiple (&(b->semBarrierBreeched[step]), - b->nInitialBarrierHeight - 1) : 0); - } - else - { - /* - * Use the non-cancelable version of sem_wait(). - */ - result = ptw32_semwait (&(b->semBarrierBreeched[step])); - } - - /* - * The first thread across will be the PTHREAD_BARRIER_SERIAL_THREAD. - * This also sets up the alternate semaphore as the next barrier. - */ - if (0 == result) - { - result = ((PTW32_INTERLOCKED_LONG) step == - PTW32_INTERLOCKED_COMPARE_EXCHANGE ((PTW32_INTERLOCKED_LPLONG) - & (b->iStep), - (PTW32_INTERLOCKED_LONG) - (1L - step), - (PTW32_INTERLOCKED_LONG) - step) ? - PTHREAD_BARRIER_SERIAL_THREAD : 0); - } - - return (result); -} +/* + * pthread_barrier_wait.c + * + * Description: + * This translation unit implements barrier primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_barrier_wait (pthread_barrier_t * barrier) +{ + int result; + int step; + pthread_barrier_t b; + + if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID) + { + return EINVAL; + } + + b = *barrier; + step = b->iStep; + + if (0 == InterlockedDecrement ((long *) &(b->nCurrentBarrierHeight))) + { + /* Must be done before posting the semaphore. */ + b->nCurrentBarrierHeight = b->nInitialBarrierHeight; + + /* + * There is no race condition between the semaphore wait and post + * because we are using two alternating semas and all threads have + * entered barrier_wait and checked nCurrentBarrierHeight before this + * barrier's sema can be posted. Any threads that have not quite + * entered sem_wait below when the multiple_post has completed + * will nevertheless continue through the semaphore (barrier) + * and will not be left stranded. + */ + result = (b->nInitialBarrierHeight > 1 + ? sem_post_multiple (&(b->semBarrierBreeched[step]), + b->nInitialBarrierHeight - 1) : 0); + } + else + { + /* + * Use the non-cancelable version of sem_wait(). + */ + result = ptw32_semwait (&(b->semBarrierBreeched[step])); + } + + /* + * The first thread across will be the PTHREAD_BARRIER_SERIAL_THREAD. + * This also sets up the alternate semaphore as the next barrier. + */ + if (0 == result) + { + result = ((PTW32_INTERLOCKED_LONG) step == + PTW32_INTERLOCKED_COMPARE_EXCHANGE ((PTW32_INTERLOCKED_LPLONG) + & (b->iStep), + (PTW32_INTERLOCKED_LONG) + (1L - step), + (PTW32_INTERLOCKED_LONG) + step) ? + PTHREAD_BARRIER_SERIAL_THREAD : 0); + } + + return (result); +} diff --git a/pcsx2/windows/pthreads/pthread_barrierattr_destroy.c b/pcsx2/windows/pthreads/pthread_barrierattr_destroy.c index aabfc5fca1..5ab662e3f4 100644 --- a/pcsx2/windows/pthreads/pthread_barrierattr_destroy.c +++ b/pcsx2/windows/pthreads/pthread_barrierattr_destroy.c @@ -1,83 +1,83 @@ -/* - * pthread_barrier_attr_destroy.c - * - * Description: - * This translation unit implements barrier primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_barrierattr_destroy (pthread_barrierattr_t * attr) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Destroys a barrier attributes object. The object can - * no longer be used. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_barrierattr_t - * - * - * DESCRIPTION - * Destroys a barrier attributes object. The object can - * no longer be used. - * - * NOTES: - * 1) Does not affect barrieres created using 'attr' - * - * RESULTS - * 0 successfully released attr, - * EINVAL 'attr' is invalid. - * - * ------------------------------------------------------ - */ -{ - int result = 0; - - if (attr == NULL || *attr == NULL) - { - result = EINVAL; - } - else - { - pthread_barrierattr_t ba = *attr; - - *attr = NULL; - free (ba); - } - - return (result); -} /* pthread_barrierattr_destroy */ +/* + * pthread_barrier_attr_destroy.c + * + * Description: + * This translation unit implements barrier primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_barrierattr_destroy (pthread_barrierattr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Destroys a barrier attributes object. The object can + * no longer be used. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_barrierattr_t + * + * + * DESCRIPTION + * Destroys a barrier attributes object. The object can + * no longer be used. + * + * NOTES: + * 1) Does not affect barrieres created using 'attr' + * + * RESULTS + * 0 successfully released attr, + * EINVAL 'attr' is invalid. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + + if (attr == NULL || *attr == NULL) + { + result = EINVAL; + } + else + { + pthread_barrierattr_t ba = *attr; + + *attr = NULL; + free (ba); + } + + return (result); +} /* pthread_barrierattr_destroy */ diff --git a/pcsx2/windows/pthreads/pthread_barrierattr_getpshared.c b/pcsx2/windows/pthreads/pthread_barrierattr_getpshared.c index 93f7d41815..44c467e2bf 100644 --- a/pcsx2/windows/pthreads/pthread_barrierattr_getpshared.c +++ b/pcsx2/windows/pthreads/pthread_barrierattr_getpshared.c @@ -1,95 +1,95 @@ -/* - * pthread_barrier_attr_getpshared.c - * - * Description: - * This translation unit implements barrier primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_barrierattr_getpshared (const pthread_barrierattr_t * attr, - int *pshared) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Determine whether barriers created with 'attr' can be - * shared between processes. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_barrierattr_t - * - * pshared - * will be set to one of: - * - * PTHREAD_PROCESS_SHARED - * May be shared if in shared memory - * - * PTHREAD_PROCESS_PRIVATE - * Cannot be shared. - * - * - * DESCRIPTION - * Mutexes creatd with 'attr' can be shared between - * processes if pthread_barrier_t variable is allocated - * in memory shared by these processes. - * NOTES: - * 1) pshared barriers MUST be allocated in shared - * memory. - * 2) The following macro is defined if shared barriers - * are supported: - * _POSIX_THREAD_PROCESS_SHARED - * - * RESULTS - * 0 successfully retrieved attribute, - * EINVAL 'attr' is invalid, - * - * ------------------------------------------------------ - */ -{ - int result; - - if ((attr != NULL && *attr != NULL) && (pshared != NULL)) - { - *pshared = (*attr)->pshared; - result = 0; - } - else - { - result = EINVAL; - } - - return (result); -} /* pthread_barrierattr_getpshared */ +/* + * pthread_barrier_attr_getpshared.c + * + * Description: + * This translation unit implements barrier primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_barrierattr_getpshared (const pthread_barrierattr_t * attr, + int *pshared) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Determine whether barriers created with 'attr' can be + * shared between processes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_barrierattr_t + * + * pshared + * will be set to one of: + * + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory + * + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. + * + * + * DESCRIPTION + * Mutexes creatd with 'attr' can be shared between + * processes if pthread_barrier_t variable is allocated + * in memory shared by these processes. + * NOTES: + * 1) pshared barriers MUST be allocated in shared + * memory. + * 2) The following macro is defined if shared barriers + * are supported: + * _POSIX_THREAD_PROCESS_SHARED + * + * RESULTS + * 0 successfully retrieved attribute, + * EINVAL 'attr' is invalid, + * + * ------------------------------------------------------ + */ +{ + int result; + + if ((attr != NULL && *attr != NULL) && (pshared != NULL)) + { + *pshared = (*attr)->pshared; + result = 0; + } + else + { + result = EINVAL; + } + + return (result); +} /* pthread_barrierattr_getpshared */ diff --git a/pcsx2/windows/pthreads/pthread_barrierattr_init.c b/pcsx2/windows/pthreads/pthread_barrierattr_init.c index 1b880f1b2b..342f8b0c69 100644 --- a/pcsx2/windows/pthreads/pthread_barrierattr_init.c +++ b/pcsx2/windows/pthreads/pthread_barrierattr_init.c @@ -1,85 +1,85 @@ -/* - * pthread_barrier_attr_init.c - * - * Description: - * This translation unit implements barrier primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_barrierattr_init (pthread_barrierattr_t * attr) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Initializes a barrier attributes object with default - * attributes. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_barrierattr_t - * - * - * DESCRIPTION - * Initializes a barrier attributes object with default - * attributes. - * - * NOTES: - * 1) Used to define barrier types - * - * RESULTS - * 0 successfully initialized attr, - * ENOMEM insufficient memory for attr. - * - * ------------------------------------------------------ - */ -{ - pthread_barrierattr_t ba; - int result = 0; - - ba = (pthread_barrierattr_t) calloc (1, sizeof (*ba)); - - if (ba == NULL) - { - result = ENOMEM; - } - else - { - ba->pshared = PTHREAD_PROCESS_PRIVATE; - } - - *attr = ba; - - return (result); -} /* pthread_barrierattr_init */ +/* + * pthread_barrier_attr_init.c + * + * Description: + * This translation unit implements barrier primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_barrierattr_init (pthread_barrierattr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Initializes a barrier attributes object with default + * attributes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_barrierattr_t + * + * + * DESCRIPTION + * Initializes a barrier attributes object with default + * attributes. + * + * NOTES: + * 1) Used to define barrier types + * + * RESULTS + * 0 successfully initialized attr, + * ENOMEM insufficient memory for attr. + * + * ------------------------------------------------------ + */ +{ + pthread_barrierattr_t ba; + int result = 0; + + ba = (pthread_barrierattr_t) calloc (1, sizeof (*ba)); + + if (ba == NULL) + { + result = ENOMEM; + } + else + { + ba->pshared = PTHREAD_PROCESS_PRIVATE; + } + + *attr = ba; + + return (result); +} /* pthread_barrierattr_init */ diff --git a/pcsx2/windows/pthreads/pthread_barrierattr_setpshared.c b/pcsx2/windows/pthreads/pthread_barrierattr_setpshared.c index 0ab999227d..08c6fde30b 100644 --- a/pcsx2/windows/pthreads/pthread_barrierattr_setpshared.c +++ b/pcsx2/windows/pthreads/pthread_barrierattr_setpshared.c @@ -1,119 +1,119 @@ -/* - * pthread_barrier_attr_setpshared.c - * - * Description: - * This translation unit implements barrier primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, int pshared) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Barriers created with 'attr' can be shared between - * processes if pthread_barrier_t variable is allocated - * in memory shared by these processes. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_barrierattr_t - * - * pshared - * must be one of: - * - * PTHREAD_PROCESS_SHARED - * May be shared if in shared memory - * - * PTHREAD_PROCESS_PRIVATE - * Cannot be shared. - * - * DESCRIPTION - * Mutexes creatd with 'attr' can be shared between - * processes if pthread_barrier_t variable is allocated - * in memory shared by these processes. - * - * NOTES: - * 1) pshared barriers MUST be allocated in shared - * memory. - * - * 2) The following macro is defined if shared barriers - * are supported: - * _POSIX_THREAD_PROCESS_SHARED - * - * RESULTS - * 0 successfully set attribute, - * EINVAL 'attr' or pshared is invalid, - * ENOSYS PTHREAD_PROCESS_SHARED not supported, - * - * ------------------------------------------------------ - */ -{ - int result; - - if ((attr != NULL && *attr != NULL) && - ((pshared == PTHREAD_PROCESS_SHARED) || - (pshared == PTHREAD_PROCESS_PRIVATE))) - { - if (pshared == PTHREAD_PROCESS_SHARED) - { - -#if !defined( _POSIX_THREAD_PROCESS_SHARED ) - - result = ENOSYS; - pshared = PTHREAD_PROCESS_PRIVATE; - -#else - - result = 0; - -#endif /* _POSIX_THREAD_PROCESS_SHARED */ - - } - else - { - result = 0; - } - - (*attr)->pshared = pshared; - } - else - { - result = EINVAL; - } - - return (result); - -} /* pthread_barrierattr_setpshared */ +/* + * pthread_barrier_attr_setpshared.c + * + * Description: + * This translation unit implements barrier primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, int pshared) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Barriers created with 'attr' can be shared between + * processes if pthread_barrier_t variable is allocated + * in memory shared by these processes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_barrierattr_t + * + * pshared + * must be one of: + * + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory + * + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. + * + * DESCRIPTION + * Mutexes creatd with 'attr' can be shared between + * processes if pthread_barrier_t variable is allocated + * in memory shared by these processes. + * + * NOTES: + * 1) pshared barriers MUST be allocated in shared + * memory. + * + * 2) The following macro is defined if shared barriers + * are supported: + * _POSIX_THREAD_PROCESS_SHARED + * + * RESULTS + * 0 successfully set attribute, + * EINVAL 'attr' or pshared is invalid, + * ENOSYS PTHREAD_PROCESS_SHARED not supported, + * + * ------------------------------------------------------ + */ +{ + int result; + + if ((attr != NULL && *attr != NULL) && + ((pshared == PTHREAD_PROCESS_SHARED) || + (pshared == PTHREAD_PROCESS_PRIVATE))) + { + if (pshared == PTHREAD_PROCESS_SHARED) + { + +#if !defined( _POSIX_THREAD_PROCESS_SHARED ) + + result = ENOSYS; + pshared = PTHREAD_PROCESS_PRIVATE; + +#else + + result = 0; + +#endif /* _POSIX_THREAD_PROCESS_SHARED */ + + } + else + { + result = 0; + } + + (*attr)->pshared = pshared; + } + else + { + result = EINVAL; + } + + return (result); + +} /* pthread_barrierattr_setpshared */ diff --git a/pcsx2/windows/pthreads/pthread_cancel.c b/pcsx2/windows/pthreads/pthread_cancel.c index d0b79879a9..1118977ee5 100644 --- a/pcsx2/windows/pthreads/pthread_cancel.c +++ b/pcsx2/windows/pthreads/pthread_cancel.c @@ -1,223 +1,223 @@ -/* - * pthread_cancel.c - * - * Description: - * POSIX thread functions related to thread cancellation. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -#if defined(_M_IX86) || defined(_X86_) -#define PTW32_PROGCTR(Context) ((Context).Eip) -#endif - -#if defined (_M_IA64) -#define PTW32_PROGCTR(Context) ((Context).StIIP) -#endif - -#if defined(_MIPS_) -#define PTW32_PROGCTR(Context) ((Context).Fir) -#endif - -#if defined(_ALPHA_) -#define PTW32_PROGCTR(Context) ((Context).Fir) -#endif - -#if defined(_PPC_) -#define PTW32_PROGCTR(Context) ((Context).Iar) -#endif - -#if defined(_AMD64_) -#define PTW32_PROGCTR(Context) ((Context).Rip) -#endif - -#if !defined(PTW32_PROGCTR) -#error Module contains CPU-specific code; modify and recompile. -#endif - -static void -ptw32_cancel_self (void) -{ - ptw32_throw (PTW32_EPS_CANCEL); - - /* Never reached */ -} - -static void CALLBACK -ptw32_cancel_callback (DWORD unused) -{ - ptw32_throw (PTW32_EPS_CANCEL); - - /* Never reached */ -} - -/* - * ptw32_RegisterCancelation() - - * Must have args of same type as QueueUserAPCEx because this function - * is a substitute for QueueUserAPCEx if it's not available. - */ -DWORD -ptw32_RegisterCancelation (PAPCFUNC unused1, HANDLE threadH, DWORD unused2) -{ - CONTEXT context; - - context.ContextFlags = CONTEXT_CONTROL; - GetThreadContext (threadH, &context); - PTW32_PROGCTR (context) = (DWORD_PTR) ptw32_cancel_self; - SetThreadContext (threadH, &context); - return 0; -} - -int -pthread_cancel (pthread_t thread) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function requests cancellation of 'thread'. - * - * PARAMETERS - * thread - * reference to an instance of pthread_t - * - * - * DESCRIPTION - * This function requests cancellation of 'thread'. - * NOTE: cancellation is asynchronous; use pthread_join to - * wait for termination of 'thread' if necessary. - * - * RESULTS - * 0 successfully requested cancellation, - * ESRCH no thread found corresponding to 'thread', - * ENOMEM implicit self thread create failed. - * ------------------------------------------------------ - */ -{ - int result; - int cancel_self; - pthread_t self; - ptw32_thread_t * tp; - - result = pthread_kill (thread, 0); - - if (0 != result) - { - return result; - } - - if ((self = pthread_self ()).p == NULL) - { - return ENOMEM; - }; - - /* - * FIXME!! - * - * Can a thread cancel itself? - * - * The standard doesn't - * specify an error to be returned if the target - * thread is itself. - * - * If it may, then we need to ensure that a thread can't - * deadlock itself trying to cancel itself asyncronously - * (pthread_cancel is required to be an async-cancel - * safe function). - */ - cancel_self = pthread_equal (thread, self); - - tp = (ptw32_thread_t *) thread.p; - - /* - * Lock for async-cancel safety. - */ - (void) pthread_mutex_lock (&tp->cancelLock); - - if (tp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS - && tp->cancelState == PTHREAD_CANCEL_ENABLE - && tp->state < PThreadStateCanceling) - { - if (cancel_self) - { - tp->state = PThreadStateCanceling; - tp->cancelState = PTHREAD_CANCEL_DISABLE; - - (void) pthread_mutex_unlock (&tp->cancelLock); - ptw32_throw (PTW32_EPS_CANCEL); - - /* Never reached */ - } - else - { - HANDLE threadH = tp->threadH; - - SuspendThread (threadH); - - if (WaitForSingleObject (threadH, 0) == WAIT_TIMEOUT) - { - tp->state = PThreadStateCanceling; - tp->cancelState = PTHREAD_CANCEL_DISABLE; - /* - * If alertdrv and QueueUserAPCEx is available then the following - * will result in a call to QueueUserAPCEx with the args given, otherwise - * this will result in a call to ptw32_RegisterCancelation and only - * the threadH arg will be used. - */ - ptw32_register_cancelation (ptw32_cancel_callback, threadH, 0); - (void) pthread_mutex_unlock (&tp->cancelLock); - ResumeThread (threadH); - } - } - } - else - { - /* - * Set for deferred cancellation. - */ - if (tp->state < PThreadStateCancelPending) - { - tp->state = PThreadStateCancelPending; - if (!SetEvent (tp->cancelEvent)) - { - result = ESRCH; - } - } - else if (tp->state >= PThreadStateCanceling) - { - result = ESRCH; - } - - (void) pthread_mutex_unlock (&tp->cancelLock); - } - - return (result); -} +/* + * pthread_cancel.c + * + * Description: + * POSIX thread functions related to thread cancellation. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +#if defined(_M_IX86) || defined(_X86_) +#define PTW32_PROGCTR(Context) ((Context).Eip) +#endif + +#if defined (_M_IA64) +#define PTW32_PROGCTR(Context) ((Context).StIIP) +#endif + +#if defined(_MIPS_) +#define PTW32_PROGCTR(Context) ((Context).Fir) +#endif + +#if defined(_ALPHA_) +#define PTW32_PROGCTR(Context) ((Context).Fir) +#endif + +#if defined(_PPC_) +#define PTW32_PROGCTR(Context) ((Context).Iar) +#endif + +#if defined(_AMD64_) +#define PTW32_PROGCTR(Context) ((Context).Rip) +#endif + +#if !defined(PTW32_PROGCTR) +#error Module contains CPU-specific code; modify and recompile. +#endif + +static void +ptw32_cancel_self (void) +{ + ptw32_throw (PTW32_EPS_CANCEL); + + /* Never reached */ +} + +static void CALLBACK +ptw32_cancel_callback (DWORD unused) +{ + ptw32_throw (PTW32_EPS_CANCEL); + + /* Never reached */ +} + +/* + * ptw32_RegisterCancelation() - + * Must have args of same type as QueueUserAPCEx because this function + * is a substitute for QueueUserAPCEx if it's not available. + */ +DWORD +ptw32_RegisterCancelation (PAPCFUNC unused1, HANDLE threadH, DWORD unused2) +{ + CONTEXT context; + + context.ContextFlags = CONTEXT_CONTROL; + GetThreadContext (threadH, &context); + PTW32_PROGCTR (context) = (DWORD_PTR) ptw32_cancel_self; + SetThreadContext (threadH, &context); + return 0; +} + +int +pthread_cancel (pthread_t thread) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function requests cancellation of 'thread'. + * + * PARAMETERS + * thread + * reference to an instance of pthread_t + * + * + * DESCRIPTION + * This function requests cancellation of 'thread'. + * NOTE: cancellation is asynchronous; use pthread_join to + * wait for termination of 'thread' if necessary. + * + * RESULTS + * 0 successfully requested cancellation, + * ESRCH no thread found corresponding to 'thread', + * ENOMEM implicit self thread create failed. + * ------------------------------------------------------ + */ +{ + int result; + int cancel_self; + pthread_t self; + ptw32_thread_t * tp; + + result = pthread_kill (thread, 0); + + if (0 != result) + { + return result; + } + + if ((self = pthread_self ()).p == NULL) + { + return ENOMEM; + }; + + /* + * FIXME!! + * + * Can a thread cancel itself? + * + * The standard doesn't + * specify an error to be returned if the target + * thread is itself. + * + * If it may, then we need to ensure that a thread can't + * deadlock itself trying to cancel itself asyncronously + * (pthread_cancel is required to be an async-cancel + * safe function). + */ + cancel_self = pthread_equal (thread, self); + + tp = (ptw32_thread_t *) thread.p; + + /* + * Lock for async-cancel safety. + */ + (void) pthread_mutex_lock (&tp->cancelLock); + + if (tp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS + && tp->cancelState == PTHREAD_CANCEL_ENABLE + && tp->state < PThreadStateCanceling) + { + if (cancel_self) + { + tp->state = PThreadStateCanceling; + tp->cancelState = PTHREAD_CANCEL_DISABLE; + + (void) pthread_mutex_unlock (&tp->cancelLock); + ptw32_throw (PTW32_EPS_CANCEL); + + /* Never reached */ + } + else + { + HANDLE threadH = tp->threadH; + + SuspendThread (threadH); + + if (WaitForSingleObject (threadH, 0) == WAIT_TIMEOUT) + { + tp->state = PThreadStateCanceling; + tp->cancelState = PTHREAD_CANCEL_DISABLE; + /* + * If alertdrv and QueueUserAPCEx is available then the following + * will result in a call to QueueUserAPCEx with the args given, otherwise + * this will result in a call to ptw32_RegisterCancelation and only + * the threadH arg will be used. + */ + ptw32_register_cancelation (ptw32_cancel_callback, threadH, 0); + (void) pthread_mutex_unlock (&tp->cancelLock); + ResumeThread (threadH); + } + } + } + else + { + /* + * Set for deferred cancellation. + */ + if (tp->state < PThreadStateCancelPending) + { + tp->state = PThreadStateCancelPending; + if (!SetEvent (tp->cancelEvent)) + { + result = ESRCH; + } + } + else if (tp->state >= PThreadStateCanceling) + { + result = ESRCH; + } + + (void) pthread_mutex_unlock (&tp->cancelLock); + } + + return (result); +} diff --git a/pcsx2/windows/pthreads/pthread_cond_destroy.c b/pcsx2/windows/pthreads/pthread_cond_destroy.c index 8d016af1ea..3d29ffc405 100644 --- a/pcsx2/windows/pthreads/pthread_cond_destroy.c +++ b/pcsx2/windows/pthreads/pthread_cond_destroy.c @@ -1,244 +1,244 @@ -/* - * pthread_cond_destroy.c - * - * Description: - * This translation unit implements condition variables and their primitives. - * - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -int -pthread_cond_destroy (pthread_cond_t * cond) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function destroys a condition variable - * - * - * PARAMETERS - * cond - * pointer to an instance of pthread_cond_t - * - * - * DESCRIPTION - * This function destroys a condition variable. - * - * NOTES: - * 1) A condition variable can be destroyed - * immediately after all the threads that - * are blocked on it are awakened. e.g. - * - * struct list { - * pthread_mutex_t lm; - * ... - * } - * - * struct elt { - * key k; - * int busy; - * pthread_cond_t notbusy; - * ... - * } - * - * - * struct elt * - * list_find(struct list *lp, key k) - * { - * struct elt *ep; - * - * pthread_mutex_lock(&lp->lm); - * while ((ep = find_elt(l,k) != NULL) && ep->busy) - * pthread_cond_wait(&ep->notbusy, &lp->lm); - * if (ep != NULL) - * ep->busy = 1; - * pthread_mutex_unlock(&lp->lm); - * return(ep); - * } - * - * delete_elt(struct list *lp, struct elt *ep) - * { - * pthread_mutex_lock(&lp->lm); - * assert(ep->busy); - * ... remove ep from list ... - * ep->busy = 0; - * (A) pthread_cond_broadcast(&ep->notbusy); - * pthread_mutex_unlock(&lp->lm); - * (B) pthread_cond_destroy(&rp->notbusy); - * free(ep); - * } - * - * In this example, the condition variable - * and its list element may be freed (line B) - * immediately after all threads waiting for - * it are awakened (line A), since the mutex - * and the code ensure that no other thread - * can touch the element to be deleted. - * - * RESULTS - * 0 successfully released condition variable, - * EINVAL 'cond' is invalid, - * EBUSY 'cond' is in use, - * - * ------------------------------------------------------ - */ -{ - pthread_cond_t cv; - int result = 0, result1 = 0, result2 = 0; - - /* - * Assuming any race condition here is harmless. - */ - if (cond == NULL || *cond == NULL) - { - return EINVAL; - } - - if (*cond != PTHREAD_COND_INITIALIZER) - { - EnterCriticalSection (&ptw32_cond_list_lock); - - cv = *cond; - - /* - * Close the gate; this will synchronize this thread with - * all already signaled waiters to let them retract their - * waiter status - SEE NOTE 1 ABOVE!!! - */ - if (sem_wait (&(cv->semBlockLock)) != 0) - { - return errno; - } - - /* - * !TRY! lock mtxUnblockLock; try will detect busy condition - * and will not cause a deadlock with respect to concurrent - * signal/broadcast. - */ - if ((result = pthread_mutex_trylock (&(cv->mtxUnblockLock))) != 0) - { - (void) sem_post (&(cv->semBlockLock)); - return result; - } - - /* - * Check whether cv is still busy (still has waiters) - */ - if (cv->nWaitersBlocked > cv->nWaitersGone) - { - if (sem_post (&(cv->semBlockLock)) != 0) - { - result = errno; - } - result1 = pthread_mutex_unlock (&(cv->mtxUnblockLock)); - result2 = EBUSY; - } - else - { - /* - * Now it is safe to destroy - */ - *cond = NULL; - - if (sem_destroy (&(cv->semBlockLock)) != 0) - { - result = errno; - } - if (sem_destroy (&(cv->semBlockQueue)) != 0) - { - result1 = errno; - } - if ((result2 = pthread_mutex_unlock (&(cv->mtxUnblockLock))) == 0) - { - result2 = pthread_mutex_destroy (&(cv->mtxUnblockLock)); - } - - /* Unlink the CV from the list */ - - if (ptw32_cond_list_head == cv) - { - ptw32_cond_list_head = cv->next; - } - else - { - cv->prev->next = cv->next; - } - - if (ptw32_cond_list_tail == cv) - { - ptw32_cond_list_tail = cv->prev; - } - else - { - cv->next->prev = cv->prev; - } - - (void) free (cv); - } - - LeaveCriticalSection (&ptw32_cond_list_lock); - } - else - { - /* - * See notes in ptw32_cond_check_need_init() above also. - */ - EnterCriticalSection (&ptw32_cond_test_init_lock); - - /* - * Check again. - */ - if (*cond == PTHREAD_COND_INITIALIZER) - { - /* - * This is all we need to do to destroy a statically - * initialised cond that has not yet been used (initialised). - * If we get to here, another thread waiting to initialise - * this cond will get an EINVAL. That's OK. - */ - *cond = NULL; - } - else - { - /* - * The cv has been initialised while we were waiting - * so assume it's in use. - */ - result = EBUSY; - } - - LeaveCriticalSection (&ptw32_cond_test_init_lock); - } - - return ((result != 0) ? result : ((result1 != 0) ? result1 : result2)); -} +/* + * pthread_cond_destroy.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +int +pthread_cond_destroy (pthread_cond_t * cond) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function destroys a condition variable + * + * + * PARAMETERS + * cond + * pointer to an instance of pthread_cond_t + * + * + * DESCRIPTION + * This function destroys a condition variable. + * + * NOTES: + * 1) A condition variable can be destroyed + * immediately after all the threads that + * are blocked on it are awakened. e.g. + * + * struct list { + * pthread_mutex_t lm; + * ... + * } + * + * struct elt { + * key k; + * int busy; + * pthread_cond_t notbusy; + * ... + * } + * + * + * struct elt * + * list_find(struct list *lp, key k) + * { + * struct elt *ep; + * + * pthread_mutex_lock(&lp->lm); + * while ((ep = find_elt(l,k) != NULL) && ep->busy) + * pthread_cond_wait(&ep->notbusy, &lp->lm); + * if (ep != NULL) + * ep->busy = 1; + * pthread_mutex_unlock(&lp->lm); + * return(ep); + * } + * + * delete_elt(struct list *lp, struct elt *ep) + * { + * pthread_mutex_lock(&lp->lm); + * assert(ep->busy); + * ... remove ep from list ... + * ep->busy = 0; + * (A) pthread_cond_broadcast(&ep->notbusy); + * pthread_mutex_unlock(&lp->lm); + * (B) pthread_cond_destroy(&rp->notbusy); + * free(ep); + * } + * + * In this example, the condition variable + * and its list element may be freed (line B) + * immediately after all threads waiting for + * it are awakened (line A), since the mutex + * and the code ensure that no other thread + * can touch the element to be deleted. + * + * RESULTS + * 0 successfully released condition variable, + * EINVAL 'cond' is invalid, + * EBUSY 'cond' is in use, + * + * ------------------------------------------------------ + */ +{ + pthread_cond_t cv; + int result = 0, result1 = 0, result2 = 0; + + /* + * Assuming any race condition here is harmless. + */ + if (cond == NULL || *cond == NULL) + { + return EINVAL; + } + + if (*cond != PTHREAD_COND_INITIALIZER) + { + EnterCriticalSection (&ptw32_cond_list_lock); + + cv = *cond; + + /* + * Close the gate; this will synchronize this thread with + * all already signaled waiters to let them retract their + * waiter status - SEE NOTE 1 ABOVE!!! + */ + if (sem_wait (&(cv->semBlockLock)) != 0) + { + return errno; + } + + /* + * !TRY! lock mtxUnblockLock; try will detect busy condition + * and will not cause a deadlock with respect to concurrent + * signal/broadcast. + */ + if ((result = pthread_mutex_trylock (&(cv->mtxUnblockLock))) != 0) + { + (void) sem_post (&(cv->semBlockLock)); + return result; + } + + /* + * Check whether cv is still busy (still has waiters) + */ + if (cv->nWaitersBlocked > cv->nWaitersGone) + { + if (sem_post (&(cv->semBlockLock)) != 0) + { + result = errno; + } + result1 = pthread_mutex_unlock (&(cv->mtxUnblockLock)); + result2 = EBUSY; + } + else + { + /* + * Now it is safe to destroy + */ + *cond = NULL; + + if (sem_destroy (&(cv->semBlockLock)) != 0) + { + result = errno; + } + if (sem_destroy (&(cv->semBlockQueue)) != 0) + { + result1 = errno; + } + if ((result2 = pthread_mutex_unlock (&(cv->mtxUnblockLock))) == 0) + { + result2 = pthread_mutex_destroy (&(cv->mtxUnblockLock)); + } + + /* Unlink the CV from the list */ + + if (ptw32_cond_list_head == cv) + { + ptw32_cond_list_head = cv->next; + } + else + { + cv->prev->next = cv->next; + } + + if (ptw32_cond_list_tail == cv) + { + ptw32_cond_list_tail = cv->prev; + } + else + { + cv->next->prev = cv->prev; + } + + (void) free (cv); + } + + LeaveCriticalSection (&ptw32_cond_list_lock); + } + else + { + /* + * See notes in ptw32_cond_check_need_init() above also. + */ + EnterCriticalSection (&ptw32_cond_test_init_lock); + + /* + * Check again. + */ + if (*cond == PTHREAD_COND_INITIALIZER) + { + /* + * This is all we need to do to destroy a statically + * initialised cond that has not yet been used (initialised). + * If we get to here, another thread waiting to initialise + * this cond will get an EINVAL. That's OK. + */ + *cond = NULL; + } + else + { + /* + * The cv has been initialised while we were waiting + * so assume it's in use. + */ + result = EBUSY; + } + + LeaveCriticalSection (&ptw32_cond_test_init_lock); + } + + return ((result != 0) ? result : ((result1 != 0) ? result1 : result2)); +} diff --git a/pcsx2/windows/pthreads/pthread_cond_init.c b/pcsx2/windows/pthreads/pthread_cond_init.c index e78c5f6f79..85e8387f51 100644 --- a/pcsx2/windows/pthreads/pthread_cond_init.c +++ b/pcsx2/windows/pthreads/pthread_cond_init.c @@ -1,170 +1,170 @@ -/* - * pthread_cond_init.c - * - * Description: - * This translation unit implements condition variables and their primitives. - * - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function initializes a condition variable. - * - * PARAMETERS - * cond - * pointer to an instance of pthread_cond_t - * - * attr - * specifies optional creation attributes. - * - * - * DESCRIPTION - * This function initializes a condition variable. - * - * RESULTS - * 0 successfully created condition variable, - * EINVAL 'attr' is invalid, - * EAGAIN insufficient resources (other than - * memory, - * ENOMEM insufficient memory, - * EBUSY 'cond' is already initialized, - * - * ------------------------------------------------------ - */ -{ - int result; - pthread_cond_t cv = NULL; - - if (cond == NULL) - { - return EINVAL; - } - -#ifdef PTW32_STATIC_LIB - // This allos for C++ static initializers to function without crashes. (air) - pthread_win32_process_attach_np(); -#endif - - if ((attr != NULL && *attr != NULL) && - ((*attr)->pshared == PTHREAD_PROCESS_SHARED)) - { - /* - * Creating condition variable that can be shared between - * processes. - */ - result = ENOSYS; - goto DONE; - } - - cv = (pthread_cond_t) calloc (1, sizeof (*cv)); - - if (cv == NULL) - { - result = ENOMEM; - goto DONE; - } - - cv->nWaitersBlocked = 0; - cv->nWaitersToUnblock = 0; - cv->nWaitersGone = 0; - - if (sem_init (&(cv->semBlockLock), 0, 1) != 0) - { - result = errno; - goto FAIL0; - } - - if (sem_init (&(cv->semBlockQueue), 0, 0) != 0) - { - result = errno; - goto FAIL1; - } - - if ((result = pthread_mutex_init (&(cv->mtxUnblockLock), 0)) != 0) - { - goto FAIL2; - } - - result = 0; - - goto DONE; - - /* - * ------------- - * Failed... - * ------------- - */ -FAIL2: - (void) sem_destroy (&(cv->semBlockQueue)); - -FAIL1: - (void) sem_destroy (&(cv->semBlockLock)); - -FAIL0: - (void) free (cv); - cv = NULL; - -DONE: - if (0 == result) - { - EnterCriticalSection (&ptw32_cond_list_lock); - - cv->next = NULL; - cv->prev = ptw32_cond_list_tail; - - if (ptw32_cond_list_tail != NULL) - { - ptw32_cond_list_tail->next = cv; - } - - ptw32_cond_list_tail = cv; - - if (ptw32_cond_list_head == NULL) - { - ptw32_cond_list_head = cv; - } - - LeaveCriticalSection (&ptw32_cond_list_lock); - } - - *cond = cv; - - return result; - -} /* pthread_cond_init */ +/* + * pthread_cond_init.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function initializes a condition variable. + * + * PARAMETERS + * cond + * pointer to an instance of pthread_cond_t + * + * attr + * specifies optional creation attributes. + * + * + * DESCRIPTION + * This function initializes a condition variable. + * + * RESULTS + * 0 successfully created condition variable, + * EINVAL 'attr' is invalid, + * EAGAIN insufficient resources (other than + * memory, + * ENOMEM insufficient memory, + * EBUSY 'cond' is already initialized, + * + * ------------------------------------------------------ + */ +{ + int result; + pthread_cond_t cv = NULL; + + if (cond == NULL) + { + return EINVAL; + } + +#ifdef PTW32_STATIC_LIB + // This allos for C++ static initializers to function without crashes. (air) + pthread_win32_process_attach_np(); +#endif + + if ((attr != NULL && *attr != NULL) && + ((*attr)->pshared == PTHREAD_PROCESS_SHARED)) + { + /* + * Creating condition variable that can be shared between + * processes. + */ + result = ENOSYS; + goto DONE; + } + + cv = (pthread_cond_t) calloc (1, sizeof (*cv)); + + if (cv == NULL) + { + result = ENOMEM; + goto DONE; + } + + cv->nWaitersBlocked = 0; + cv->nWaitersToUnblock = 0; + cv->nWaitersGone = 0; + + if (sem_init (&(cv->semBlockLock), 0, 1) != 0) + { + result = errno; + goto FAIL0; + } + + if (sem_init (&(cv->semBlockQueue), 0, 0) != 0) + { + result = errno; + goto FAIL1; + } + + if ((result = pthread_mutex_init (&(cv->mtxUnblockLock), 0)) != 0) + { + goto FAIL2; + } + + result = 0; + + goto DONE; + + /* + * ------------- + * Failed... + * ------------- + */ +FAIL2: + (void) sem_destroy (&(cv->semBlockQueue)); + +FAIL1: + (void) sem_destroy (&(cv->semBlockLock)); + +FAIL0: + (void) free (cv); + cv = NULL; + +DONE: + if (0 == result) + { + EnterCriticalSection (&ptw32_cond_list_lock); + + cv->next = NULL; + cv->prev = ptw32_cond_list_tail; + + if (ptw32_cond_list_tail != NULL) + { + ptw32_cond_list_tail->next = cv; + } + + ptw32_cond_list_tail = cv; + + if (ptw32_cond_list_head == NULL) + { + ptw32_cond_list_head = cv; + } + + LeaveCriticalSection (&ptw32_cond_list_lock); + } + + *cond = cv; + + return result; + +} /* pthread_cond_init */ diff --git a/pcsx2/windows/pthreads/pthread_cond_signal.c b/pcsx2/windows/pthreads/pthread_cond_signal.c index e147831d41..2b4f6d4d44 100644 --- a/pcsx2/windows/pthreads/pthread_cond_signal.c +++ b/pcsx2/windows/pthreads/pthread_cond_signal.c @@ -1,231 +1,231 @@ -/* - * pthread_cond_signal.c - * - * Description: - * This translation unit implements condition variables and their primitives. - * - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * ------------------------------------------------------------- - * Algorithm: - * See the comments at the top of pthread_cond_wait.c. - */ - -#include "pthread.h" -#include "implement.h" - -static INLINE int -ptw32_cond_unblock (pthread_cond_t * cond, int unblockAll) - /* - * Notes. - * - * Does not use the external mutex for synchronisation, - * therefore semBlockLock is needed. - * mtxUnblockLock is for LEVEL-2 synch. LEVEL-2 is the - * state where the external mutex is not necessarily locked by - * any thread, ie. between cond_wait unlocking and re-acquiring - * the lock after having been signaled or a timeout or - * cancellation. - * - * Uses the following CV elements: - * nWaitersBlocked - * nWaitersToUnblock - * nWaitersGone - * mtxUnblockLock - * semBlockLock - * semBlockQueue - */ -{ - int result; - pthread_cond_t cv; - int nSignalsToIssue; - - if (cond == NULL || *cond == NULL) - { - return EINVAL; - } - - cv = *cond; - - /* - * No-op if the CV is static and hasn't been initialised yet. - * Assuming that any race condition is harmless. - */ - if (cv == PTHREAD_COND_INITIALIZER) - { - return 0; - } - - if ((result = pthread_mutex_lock (&(cv->mtxUnblockLock))) != 0) - { - return result; - } - - if (0 != cv->nWaitersToUnblock) - { - if (0 == cv->nWaitersBlocked) - { - return pthread_mutex_unlock (&(cv->mtxUnblockLock)); - } - if (unblockAll) - { - cv->nWaitersToUnblock += (nSignalsToIssue = cv->nWaitersBlocked); - cv->nWaitersBlocked = 0; - } - else - { - nSignalsToIssue = 1; - cv->nWaitersToUnblock++; - cv->nWaitersBlocked--; - } - } - else if (cv->nWaitersBlocked > cv->nWaitersGone) - { - /* Use the non-cancellable version of sem_wait() */ - if (ptw32_semwait (&(cv->semBlockLock)) != 0) - { - result = errno; - (void) pthread_mutex_unlock (&(cv->mtxUnblockLock)); - return result; - } - if (0 != cv->nWaitersGone) - { - cv->nWaitersBlocked -= cv->nWaitersGone; - cv->nWaitersGone = 0; - } - if (unblockAll) - { - nSignalsToIssue = cv->nWaitersToUnblock = cv->nWaitersBlocked; - cv->nWaitersBlocked = 0; - } - else - { - nSignalsToIssue = cv->nWaitersToUnblock = 1; - cv->nWaitersBlocked--; - } - } - else - { - return pthread_mutex_unlock (&(cv->mtxUnblockLock)); - } - - if ((result = pthread_mutex_unlock (&(cv->mtxUnblockLock))) == 0) - { - if (sem_post_multiple (&(cv->semBlockQueue), nSignalsToIssue) != 0) - { - result = errno; - } - } - - return result; - -} /* ptw32_cond_unblock */ - -int -pthread_cond_signal (pthread_cond_t * cond) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function signals a condition variable, waking - * one waiting thread. - * If SCHED_FIFO or SCHED_RR policy threads are waiting - * the highest priority waiter is awakened; otherwise, - * an unspecified waiter is awakened. - * - * PARAMETERS - * cond - * pointer to an instance of pthread_cond_t - * - * - * DESCRIPTION - * This function signals a condition variable, waking - * one waiting thread. - * If SCHED_FIFO or SCHED_RR policy threads are waiting - * the highest priority waiter is awakened; otherwise, - * an unspecified waiter is awakened. - * - * NOTES: - * - * 1) Use when any waiter can respond and only one need - * respond (all waiters being equal). - * - * RESULTS - * 0 successfully signaled condition, - * EINVAL 'cond' is invalid, - * - * ------------------------------------------------------ - */ -{ - /* - * The '0'(FALSE) unblockAll arg means unblock ONE waiter. - */ - return (ptw32_cond_unblock (cond, 0)); - -} /* pthread_cond_signal */ - -int -pthread_cond_broadcast (pthread_cond_t * cond) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function broadcasts the condition variable, - * waking all current waiters. - * - * PARAMETERS - * cond - * pointer to an instance of pthread_cond_t - * - * - * DESCRIPTION - * This function signals a condition variable, waking - * all waiting threads. - * - * NOTES: - * - * 1) Use when more than one waiter may respond to - * predicate change or if any waiting thread may - * not be able to respond - * - * RESULTS - * 0 successfully signalled condition to all - * waiting threads, - * EINVAL 'cond' is invalid - * ENOSPC a required resource has been exhausted, - * - * ------------------------------------------------------ - */ -{ - /* - * The TRUE unblockAll arg means unblock ALL waiters. - */ - return (ptw32_cond_unblock (cond, PTW32_TRUE)); - -} /* pthread_cond_broadcast */ +/* + * pthread_cond_signal.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * ------------------------------------------------------------- + * Algorithm: + * See the comments at the top of pthread_cond_wait.c. + */ + +#include "pthread.h" +#include "implement.h" + +static INLINE int +ptw32_cond_unblock (pthread_cond_t * cond, int unblockAll) + /* + * Notes. + * + * Does not use the external mutex for synchronisation, + * therefore semBlockLock is needed. + * mtxUnblockLock is for LEVEL-2 synch. LEVEL-2 is the + * state where the external mutex is not necessarily locked by + * any thread, ie. between cond_wait unlocking and re-acquiring + * the lock after having been signaled or a timeout or + * cancellation. + * + * Uses the following CV elements: + * nWaitersBlocked + * nWaitersToUnblock + * nWaitersGone + * mtxUnblockLock + * semBlockLock + * semBlockQueue + */ +{ + int result; + pthread_cond_t cv; + int nSignalsToIssue; + + if (cond == NULL || *cond == NULL) + { + return EINVAL; + } + + cv = *cond; + + /* + * No-op if the CV is static and hasn't been initialised yet. + * Assuming that any race condition is harmless. + */ + if (cv == PTHREAD_COND_INITIALIZER) + { + return 0; + } + + if ((result = pthread_mutex_lock (&(cv->mtxUnblockLock))) != 0) + { + return result; + } + + if (0 != cv->nWaitersToUnblock) + { + if (0 == cv->nWaitersBlocked) + { + return pthread_mutex_unlock (&(cv->mtxUnblockLock)); + } + if (unblockAll) + { + cv->nWaitersToUnblock += (nSignalsToIssue = cv->nWaitersBlocked); + cv->nWaitersBlocked = 0; + } + else + { + nSignalsToIssue = 1; + cv->nWaitersToUnblock++; + cv->nWaitersBlocked--; + } + } + else if (cv->nWaitersBlocked > cv->nWaitersGone) + { + /* Use the non-cancellable version of sem_wait() */ + if (ptw32_semwait (&(cv->semBlockLock)) != 0) + { + result = errno; + (void) pthread_mutex_unlock (&(cv->mtxUnblockLock)); + return result; + } + if (0 != cv->nWaitersGone) + { + cv->nWaitersBlocked -= cv->nWaitersGone; + cv->nWaitersGone = 0; + } + if (unblockAll) + { + nSignalsToIssue = cv->nWaitersToUnblock = cv->nWaitersBlocked; + cv->nWaitersBlocked = 0; + } + else + { + nSignalsToIssue = cv->nWaitersToUnblock = 1; + cv->nWaitersBlocked--; + } + } + else + { + return pthread_mutex_unlock (&(cv->mtxUnblockLock)); + } + + if ((result = pthread_mutex_unlock (&(cv->mtxUnblockLock))) == 0) + { + if (sem_post_multiple (&(cv->semBlockQueue), nSignalsToIssue) != 0) + { + result = errno; + } + } + + return result; + +} /* ptw32_cond_unblock */ + +int +pthread_cond_signal (pthread_cond_t * cond) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function signals a condition variable, waking + * one waiting thread. + * If SCHED_FIFO or SCHED_RR policy threads are waiting + * the highest priority waiter is awakened; otherwise, + * an unspecified waiter is awakened. + * + * PARAMETERS + * cond + * pointer to an instance of pthread_cond_t + * + * + * DESCRIPTION + * This function signals a condition variable, waking + * one waiting thread. + * If SCHED_FIFO or SCHED_RR policy threads are waiting + * the highest priority waiter is awakened; otherwise, + * an unspecified waiter is awakened. + * + * NOTES: + * + * 1) Use when any waiter can respond and only one need + * respond (all waiters being equal). + * + * RESULTS + * 0 successfully signaled condition, + * EINVAL 'cond' is invalid, + * + * ------------------------------------------------------ + */ +{ + /* + * The '0'(FALSE) unblockAll arg means unblock ONE waiter. + */ + return (ptw32_cond_unblock (cond, 0)); + +} /* pthread_cond_signal */ + +int +pthread_cond_broadcast (pthread_cond_t * cond) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function broadcasts the condition variable, + * waking all current waiters. + * + * PARAMETERS + * cond + * pointer to an instance of pthread_cond_t + * + * + * DESCRIPTION + * This function signals a condition variable, waking + * all waiting threads. + * + * NOTES: + * + * 1) Use when more than one waiter may respond to + * predicate change or if any waiting thread may + * not be able to respond + * + * RESULTS + * 0 successfully signalled condition to all + * waiting threads, + * EINVAL 'cond' is invalid + * ENOSPC a required resource has been exhausted, + * + * ------------------------------------------------------ + */ +{ + /* + * The TRUE unblockAll arg means unblock ALL waiters. + */ + return (ptw32_cond_unblock (cond, PTW32_TRUE)); + +} /* pthread_cond_broadcast */ diff --git a/pcsx2/windows/pthreads/pthread_cond_wait.c b/pcsx2/windows/pthreads/pthread_cond_wait.c index e33713bb46..5511c5844c 100644 --- a/pcsx2/windows/pthreads/pthread_cond_wait.c +++ b/pcsx2/windows/pthreads/pthread_cond_wait.c @@ -1,567 +1,567 @@ -/* - * pthread_cond_wait.c - * - * Description: - * This translation unit implements condition variables and their primitives. - * - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * ------------------------------------------------------------- - * Algorithm: - * The algorithm used in this implementation is that developed by - * Alexander Terekhov in colaboration with Louis Thomas. The bulk - * of the discussion is recorded in the file README.CV, which contains - * several generations of both colaborators original algorithms. The final - * algorithm used here is the one referred to as - * - * Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL - * - * presented below in pseudo-code as it appeared: - * - * - * given: - * semBlockLock - bin.semaphore - * semBlockQueue - semaphore - * mtxExternal - mutex or CS - * mtxUnblockLock - mutex or CS - * nWaitersGone - int - * nWaitersBlocked - int - * nWaitersToUnblock - int - * - * wait( timeout ) { - * - * [auto: register int result ] // error checking omitted - * [auto: register int nSignalsWasLeft ] - * [auto: register int nWaitersWasGone ] - * - * sem_wait( semBlockLock ); - * nWaitersBlocked++; - * sem_post( semBlockLock ); - * - * unlock( mtxExternal ); - * bTimedOut = sem_wait( semBlockQueue,timeout ); - * - * lock( mtxUnblockLock ); - * if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) { - * if ( bTimeout ) { // timeout (or canceled) - * if ( 0 != nWaitersBlocked ) { - * nWaitersBlocked--; - * } - * else { - * nWaitersGone++; // count spurious wakeups. - * } - * } - * if ( 0 == --nWaitersToUnblock ) { - * if ( 0 != nWaitersBlocked ) { - * sem_post( semBlockLock ); // open the gate. - * nSignalsWasLeft = 0; // do not open the gate - * // below again. - * } - * else if ( 0 != (nWaitersWasGone = nWaitersGone) ) { - * nWaitersGone = 0; - * } - * } - * } - * else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or - * // spurious semaphore :-) - * sem_wait( semBlockLock ); - * nWaitersBlocked -= nWaitersGone; // something is going on here - * // - test of timeouts? :-) - * sem_post( semBlockLock ); - * nWaitersGone = 0; - * } - * unlock( mtxUnblockLock ); - * - * if ( 1 == nSignalsWasLeft ) { - * if ( 0 != nWaitersWasGone ) { - * // sem_adjust( semBlockQueue,-nWaitersWasGone ); - * while ( nWaitersWasGone-- ) { - * sem_wait( semBlockQueue ); // better now than spurious later - * } - * } sem_post( semBlockLock ); // open the gate - * } - * - * lock( mtxExternal ); - * - * return ( bTimedOut ) ? ETIMEOUT : 0; - * } - * - * signal(bAll) { - * - * [auto: register int result ] - * [auto: register int nSignalsToIssue] - * - * lock( mtxUnblockLock ); - * - * if ( 0 != nWaitersToUnblock ) { // the gate is closed!!! - * if ( 0 == nWaitersBlocked ) { // NO-OP - * return unlock( mtxUnblockLock ); - * } - * if (bAll) { - * nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked; - * nWaitersBlocked = 0; - * } - * else { - * nSignalsToIssue = 1; - * nWaitersToUnblock++; - * nWaitersBlocked--; - * } - * } - * else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION! - * sem_wait( semBlockLock ); // close the gate - * if ( 0 != nWaitersGone ) { - * nWaitersBlocked -= nWaitersGone; - * nWaitersGone = 0; - * } - * if (bAll) { - * nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked; - * nWaitersBlocked = 0; - * } - * else { - * nSignalsToIssue = nWaitersToUnblock = 1; - * nWaitersBlocked--; - * } - * } - * else { // NO-OP - * return unlock( mtxUnblockLock ); - * } - * - * unlock( mtxUnblockLock ); - * sem_post( semBlockQueue,nSignalsToIssue ); - * return result; - * } - * ------------------------------------------------------------- - * - * Algorithm 9 / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL - * - * presented below in pseudo-code; basically 8a... - * ...BUT W/O "spurious wakes" prevention: - * - * - * given: - * semBlockLock - bin.semaphore - * semBlockQueue - semaphore - * mtxExternal - mutex or CS - * mtxUnblockLock - mutex or CS - * nWaitersGone - int - * nWaitersBlocked - int - * nWaitersToUnblock - int - * - * wait( timeout ) { - * - * [auto: register int result ] // error checking omitted - * [auto: register int nSignalsWasLeft ] - * - * sem_wait( semBlockLock ); - * ++nWaitersBlocked; - * sem_post( semBlockLock ); - * - * unlock( mtxExternal ); - * bTimedOut = sem_wait( semBlockQueue,timeout ); - * - * lock( mtxUnblockLock ); - * if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) { - * --nWaitersToUnblock; - * } - * else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or - * // spurious semaphore :-) - * sem_wait( semBlockLock ); - * nWaitersBlocked -= nWaitersGone; // something is going on here - * // - test of timeouts? :-) - * sem_post( semBlockLock ); - * nWaitersGone = 0; - * } - * unlock( mtxUnblockLock ); - * - * if ( 1 == nSignalsWasLeft ) { - * sem_post( semBlockLock ); // open the gate - * } - * - * lock( mtxExternal ); - * - * return ( bTimedOut ) ? ETIMEOUT : 0; - * } - * - * signal(bAll) { - * - * [auto: register int result ] - * [auto: register int nSignalsToIssue] - * - * lock( mtxUnblockLock ); - * - * if ( 0 != nWaitersToUnblock ) { // the gate is closed!!! - * if ( 0 == nWaitersBlocked ) { // NO-OP - * return unlock( mtxUnblockLock ); - * } - * if (bAll) { - * nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked; - * nWaitersBlocked = 0; - * } - * else { - * nSignalsToIssue = 1; - * ++nWaitersToUnblock; - * --nWaitersBlocked; - * } - * } - * else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION! - * sem_wait( semBlockLock ); // close the gate - * if ( 0 != nWaitersGone ) { - * nWaitersBlocked -= nWaitersGone; - * nWaitersGone = 0; - * } - * if (bAll) { - * nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked; - * nWaitersBlocked = 0; - * } - * else { - * nSignalsToIssue = nWaitersToUnblock = 1; - * --nWaitersBlocked; - * } - * } - * else { // NO-OP - * return unlock( mtxUnblockLock ); - * } - * - * unlock( mtxUnblockLock ); - * sem_post( semBlockQueue,nSignalsToIssue ); - * return result; - * } - * ------------------------------------------------------------- - * - */ - -#include "pthread.h" -#include "implement.h" - -/* - * Arguments for cond_wait_cleanup, since we can only pass a - * single void * to it. - */ -typedef struct -{ - pthread_mutex_t *mutexPtr; - pthread_cond_t cv; - int *resultPtr; -} ptw32_cond_wait_cleanup_args_t; - -static void PTW32_CDECL -ptw32_cond_wait_cleanup (void *args) -{ - ptw32_cond_wait_cleanup_args_t *cleanup_args = - (ptw32_cond_wait_cleanup_args_t *) args; - pthread_cond_t cv = cleanup_args->cv; - int *resultPtr = cleanup_args->resultPtr; - int nSignalsWasLeft; - int result; - - /* - * Whether we got here as a result of signal/broadcast or because of - * timeout on wait or thread cancellation we indicate that we are no - * longer waiting. The waiter is responsible for adjusting waiters - * (to)unblock(ed) counts (protected by unblock lock). - */ - if ((result = pthread_mutex_lock (&(cv->mtxUnblockLock))) != 0) - { - *resultPtr = result; - return; - } - - if (0 != (nSignalsWasLeft = cv->nWaitersToUnblock)) - { - --(cv->nWaitersToUnblock); - } - else if (INT_MAX / 2 == ++(cv->nWaitersGone)) - { - /* Use the non-cancellable version of sem_wait() */ - if (ptw32_semwait (&(cv->semBlockLock)) != 0) - { - *resultPtr = errno; - /* - * This is a fatal error for this CV, - * so we deliberately don't unlock - * cv->mtxUnblockLock before returning. - */ - return; - } - cv->nWaitersBlocked -= cv->nWaitersGone; - if (sem_post (&(cv->semBlockLock)) != 0) - { - *resultPtr = errno; - /* - * This is a fatal error for this CV, - * so we deliberately don't unlock - * cv->mtxUnblockLock before returning. - */ - return; - } - cv->nWaitersGone = 0; - } - - if ((result = pthread_mutex_unlock (&(cv->mtxUnblockLock))) != 0) - { - *resultPtr = result; - return; - } - - if (1 == nSignalsWasLeft) - { - if (sem_post (&(cv->semBlockLock)) != 0) - { - *resultPtr = errno; - return; - } - } - - /* - * XSH: Upon successful return, the mutex has been locked and is owned - * by the calling thread. - */ - if ((result = pthread_mutex_lock (cleanup_args->mutexPtr)) != 0) - { - *resultPtr = result; - } -} /* ptw32_cond_wait_cleanup */ - -static INLINE int -ptw32_cond_timedwait (pthread_cond_t * cond, - pthread_mutex_t * mutex, const struct timespec *abstime) -{ - int result = 0; - pthread_cond_t cv; - ptw32_cond_wait_cleanup_args_t cleanup_args; - - if (cond == NULL || *cond == NULL) - { - return EINVAL; - } - - /* - * We do a quick check to see if we need to do more work - * to initialise a static condition variable. We check - * again inside the guarded section of ptw32_cond_check_need_init() - * to avoid race conditions. - */ - if (*cond == PTHREAD_COND_INITIALIZER) - { - result = ptw32_cond_check_need_init (cond); - } - - if (result != 0 && result != EBUSY) - { - return result; - } - - cv = *cond; - - /* Thread can be cancelled in sem_wait() but this is OK */ - if (sem_wait (&(cv->semBlockLock)) != 0) - { - return errno; - } - - ++(cv->nWaitersBlocked); - - if (sem_post (&(cv->semBlockLock)) != 0) - { - return errno; - } - - /* - * Setup this waiter cleanup handler - */ - cleanup_args.mutexPtr = mutex; - cleanup_args.cv = cv; - cleanup_args.resultPtr = &result; - -#ifdef _MSC_VER -#pragma inline_depth(0) -#endif - pthread_cleanup_push (ptw32_cond_wait_cleanup, (void *) &cleanup_args); - - /* - * Now we can release 'mutex' and... - */ - if ((result = pthread_mutex_unlock (mutex)) == 0) - { - - /* - * ...wait to be awakened by - * pthread_cond_signal, or - * pthread_cond_broadcast, or - * timeout, or - * thread cancellation - * - * Note: - * - * sem_timedwait is a cancellation point, - * hence providing the mechanism for making - * pthread_cond_wait a cancellation point. - * We use the cleanup mechanism to ensure we - * re-lock the mutex and adjust (to)unblock(ed) waiters - * counts if we are cancelled, timed out or signalled. - */ - if (sem_timedwait (&(cv->semBlockQueue), abstime) != 0) - { - result = errno; - } - } - - /* - * Always cleanup - */ - pthread_cleanup_pop (1); -#ifdef _MSC_VER -#pragma inline_depth() -#endif - - /* - * "result" can be modified by the cleanup handler. - */ - return result; - -} /* ptw32_cond_timedwait */ - - -int -pthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function waits on a condition variable until - * awakened by a signal or broadcast. - * - * Caller MUST be holding the mutex lock; the - * lock is released and the caller is blocked waiting - * on 'cond'. When 'cond' is signaled, the mutex - * is re-acquired before returning to the caller. - * - * PARAMETERS - * cond - * pointer to an instance of pthread_cond_t - * - * mutex - * pointer to an instance of pthread_mutex_t - * - * - * DESCRIPTION - * This function waits on a condition variable until - * awakened by a signal or broadcast. - * - * NOTES: - * - * 1) The function must be called with 'mutex' LOCKED - * by the calling thread, or undefined behaviour - * will result. - * - * 2) This routine atomically releases 'mutex' and causes - * the calling thread to block on the condition variable. - * The blocked thread may be awakened by - * pthread_cond_signal or - * pthread_cond_broadcast. - * - * Upon successful completion, the 'mutex' has been locked and - * is owned by the calling thread. - * - * - * RESULTS - * 0 caught condition; mutex released, - * EINVAL 'cond' or 'mutex' is invalid, - * EINVAL different mutexes for concurrent waits, - * EINVAL mutex is not held by the calling thread, - * - * ------------------------------------------------------ - */ -{ - /* - * The NULL abstime arg means INFINITE waiting. - */ - return (ptw32_cond_timedwait (cond, mutex, NULL)); - -} /* pthread_cond_wait */ - - -int -pthread_cond_timedwait (pthread_cond_t * cond, - pthread_mutex_t * mutex, - const struct timespec *abstime) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function waits on a condition variable either until - * awakened by a signal or broadcast; or until the time - * specified by abstime passes. - * - * PARAMETERS - * cond - * pointer to an instance of pthread_cond_t - * - * mutex - * pointer to an instance of pthread_mutex_t - * - * abstime - * pointer to an instance of (const struct timespec) - * - * - * DESCRIPTION - * This function waits on a condition variable either until - * awakened by a signal or broadcast; or until the time - * specified by abstime passes. - * - * NOTES: - * 1) The function must be called with 'mutex' LOCKED - * by the calling thread, or undefined behaviour - * will result. - * - * 2) This routine atomically releases 'mutex' and causes - * the calling thread to block on the condition variable. - * The blocked thread may be awakened by - * pthread_cond_signal or - * pthread_cond_broadcast. - * - * - * RESULTS - * 0 caught condition; mutex released, - * EINVAL 'cond', 'mutex', or abstime is invalid, - * EINVAL different mutexes for concurrent waits, - * EINVAL mutex is not held by the calling thread, - * ETIMEDOUT abstime ellapsed before cond was signaled. - * - * ------------------------------------------------------ - */ -{ - if (abstime == NULL) - { - return EINVAL; - } - - return (ptw32_cond_timedwait (cond, mutex, abstime)); - -} /* pthread_cond_timedwait */ +/* + * pthread_cond_wait.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * ------------------------------------------------------------- + * Algorithm: + * The algorithm used in this implementation is that developed by + * Alexander Terekhov in colaboration with Louis Thomas. The bulk + * of the discussion is recorded in the file README.CV, which contains + * several generations of both colaborators original algorithms. The final + * algorithm used here is the one referred to as + * + * Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL + * + * presented below in pseudo-code as it appeared: + * + * + * given: + * semBlockLock - bin.semaphore + * semBlockQueue - semaphore + * mtxExternal - mutex or CS + * mtxUnblockLock - mutex or CS + * nWaitersGone - int + * nWaitersBlocked - int + * nWaitersToUnblock - int + * + * wait( timeout ) { + * + * [auto: register int result ] // error checking omitted + * [auto: register int nSignalsWasLeft ] + * [auto: register int nWaitersWasGone ] + * + * sem_wait( semBlockLock ); + * nWaitersBlocked++; + * sem_post( semBlockLock ); + * + * unlock( mtxExternal ); + * bTimedOut = sem_wait( semBlockQueue,timeout ); + * + * lock( mtxUnblockLock ); + * if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) { + * if ( bTimeout ) { // timeout (or canceled) + * if ( 0 != nWaitersBlocked ) { + * nWaitersBlocked--; + * } + * else { + * nWaitersGone++; // count spurious wakeups. + * } + * } + * if ( 0 == --nWaitersToUnblock ) { + * if ( 0 != nWaitersBlocked ) { + * sem_post( semBlockLock ); // open the gate. + * nSignalsWasLeft = 0; // do not open the gate + * // below again. + * } + * else if ( 0 != (nWaitersWasGone = nWaitersGone) ) { + * nWaitersGone = 0; + * } + * } + * } + * else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or + * // spurious semaphore :-) + * sem_wait( semBlockLock ); + * nWaitersBlocked -= nWaitersGone; // something is going on here + * // - test of timeouts? :-) + * sem_post( semBlockLock ); + * nWaitersGone = 0; + * } + * unlock( mtxUnblockLock ); + * + * if ( 1 == nSignalsWasLeft ) { + * if ( 0 != nWaitersWasGone ) { + * // sem_adjust( semBlockQueue,-nWaitersWasGone ); + * while ( nWaitersWasGone-- ) { + * sem_wait( semBlockQueue ); // better now than spurious later + * } + * } sem_post( semBlockLock ); // open the gate + * } + * + * lock( mtxExternal ); + * + * return ( bTimedOut ) ? ETIMEOUT : 0; + * } + * + * signal(bAll) { + * + * [auto: register int result ] + * [auto: register int nSignalsToIssue] + * + * lock( mtxUnblockLock ); + * + * if ( 0 != nWaitersToUnblock ) { // the gate is closed!!! + * if ( 0 == nWaitersBlocked ) { // NO-OP + * return unlock( mtxUnblockLock ); + * } + * if (bAll) { + * nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked; + * nWaitersBlocked = 0; + * } + * else { + * nSignalsToIssue = 1; + * nWaitersToUnblock++; + * nWaitersBlocked--; + * } + * } + * else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION! + * sem_wait( semBlockLock ); // close the gate + * if ( 0 != nWaitersGone ) { + * nWaitersBlocked -= nWaitersGone; + * nWaitersGone = 0; + * } + * if (bAll) { + * nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked; + * nWaitersBlocked = 0; + * } + * else { + * nSignalsToIssue = nWaitersToUnblock = 1; + * nWaitersBlocked--; + * } + * } + * else { // NO-OP + * return unlock( mtxUnblockLock ); + * } + * + * unlock( mtxUnblockLock ); + * sem_post( semBlockQueue,nSignalsToIssue ); + * return result; + * } + * ------------------------------------------------------------- + * + * Algorithm 9 / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL + * + * presented below in pseudo-code; basically 8a... + * ...BUT W/O "spurious wakes" prevention: + * + * + * given: + * semBlockLock - bin.semaphore + * semBlockQueue - semaphore + * mtxExternal - mutex or CS + * mtxUnblockLock - mutex or CS + * nWaitersGone - int + * nWaitersBlocked - int + * nWaitersToUnblock - int + * + * wait( timeout ) { + * + * [auto: register int result ] // error checking omitted + * [auto: register int nSignalsWasLeft ] + * + * sem_wait( semBlockLock ); + * ++nWaitersBlocked; + * sem_post( semBlockLock ); + * + * unlock( mtxExternal ); + * bTimedOut = sem_wait( semBlockQueue,timeout ); + * + * lock( mtxUnblockLock ); + * if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) { + * --nWaitersToUnblock; + * } + * else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or + * // spurious semaphore :-) + * sem_wait( semBlockLock ); + * nWaitersBlocked -= nWaitersGone; // something is going on here + * // - test of timeouts? :-) + * sem_post( semBlockLock ); + * nWaitersGone = 0; + * } + * unlock( mtxUnblockLock ); + * + * if ( 1 == nSignalsWasLeft ) { + * sem_post( semBlockLock ); // open the gate + * } + * + * lock( mtxExternal ); + * + * return ( bTimedOut ) ? ETIMEOUT : 0; + * } + * + * signal(bAll) { + * + * [auto: register int result ] + * [auto: register int nSignalsToIssue] + * + * lock( mtxUnblockLock ); + * + * if ( 0 != nWaitersToUnblock ) { // the gate is closed!!! + * if ( 0 == nWaitersBlocked ) { // NO-OP + * return unlock( mtxUnblockLock ); + * } + * if (bAll) { + * nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked; + * nWaitersBlocked = 0; + * } + * else { + * nSignalsToIssue = 1; + * ++nWaitersToUnblock; + * --nWaitersBlocked; + * } + * } + * else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION! + * sem_wait( semBlockLock ); // close the gate + * if ( 0 != nWaitersGone ) { + * nWaitersBlocked -= nWaitersGone; + * nWaitersGone = 0; + * } + * if (bAll) { + * nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked; + * nWaitersBlocked = 0; + * } + * else { + * nSignalsToIssue = nWaitersToUnblock = 1; + * --nWaitersBlocked; + * } + * } + * else { // NO-OP + * return unlock( mtxUnblockLock ); + * } + * + * unlock( mtxUnblockLock ); + * sem_post( semBlockQueue,nSignalsToIssue ); + * return result; + * } + * ------------------------------------------------------------- + * + */ + +#include "pthread.h" +#include "implement.h" + +/* + * Arguments for cond_wait_cleanup, since we can only pass a + * single void * to it. + */ +typedef struct +{ + pthread_mutex_t *mutexPtr; + pthread_cond_t cv; + int *resultPtr; +} ptw32_cond_wait_cleanup_args_t; + +static void PTW32_CDECL +ptw32_cond_wait_cleanup (void *args) +{ + ptw32_cond_wait_cleanup_args_t *cleanup_args = + (ptw32_cond_wait_cleanup_args_t *) args; + pthread_cond_t cv = cleanup_args->cv; + int *resultPtr = cleanup_args->resultPtr; + int nSignalsWasLeft; + int result; + + /* + * Whether we got here as a result of signal/broadcast or because of + * timeout on wait or thread cancellation we indicate that we are no + * longer waiting. The waiter is responsible for adjusting waiters + * (to)unblock(ed) counts (protected by unblock lock). + */ + if ((result = pthread_mutex_lock (&(cv->mtxUnblockLock))) != 0) + { + *resultPtr = result; + return; + } + + if (0 != (nSignalsWasLeft = cv->nWaitersToUnblock)) + { + --(cv->nWaitersToUnblock); + } + else if (INT_MAX / 2 == ++(cv->nWaitersGone)) + { + /* Use the non-cancellable version of sem_wait() */ + if (ptw32_semwait (&(cv->semBlockLock)) != 0) + { + *resultPtr = errno; + /* + * This is a fatal error for this CV, + * so we deliberately don't unlock + * cv->mtxUnblockLock before returning. + */ + return; + } + cv->nWaitersBlocked -= cv->nWaitersGone; + if (sem_post (&(cv->semBlockLock)) != 0) + { + *resultPtr = errno; + /* + * This is a fatal error for this CV, + * so we deliberately don't unlock + * cv->mtxUnblockLock before returning. + */ + return; + } + cv->nWaitersGone = 0; + } + + if ((result = pthread_mutex_unlock (&(cv->mtxUnblockLock))) != 0) + { + *resultPtr = result; + return; + } + + if (1 == nSignalsWasLeft) + { + if (sem_post (&(cv->semBlockLock)) != 0) + { + *resultPtr = errno; + return; + } + } + + /* + * XSH: Upon successful return, the mutex has been locked and is owned + * by the calling thread. + */ + if ((result = pthread_mutex_lock (cleanup_args->mutexPtr)) != 0) + { + *resultPtr = result; + } +} /* ptw32_cond_wait_cleanup */ + +static INLINE int +ptw32_cond_timedwait (pthread_cond_t * cond, + pthread_mutex_t * mutex, const struct timespec *abstime) +{ + int result = 0; + pthread_cond_t cv; + ptw32_cond_wait_cleanup_args_t cleanup_args; + + if (cond == NULL || *cond == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static condition variable. We check + * again inside the guarded section of ptw32_cond_check_need_init() + * to avoid race conditions. + */ + if (*cond == PTHREAD_COND_INITIALIZER) + { + result = ptw32_cond_check_need_init (cond); + } + + if (result != 0 && result != EBUSY) + { + return result; + } + + cv = *cond; + + /* Thread can be cancelled in sem_wait() but this is OK */ + if (sem_wait (&(cv->semBlockLock)) != 0) + { + return errno; + } + + ++(cv->nWaitersBlocked); + + if (sem_post (&(cv->semBlockLock)) != 0) + { + return errno; + } + + /* + * Setup this waiter cleanup handler + */ + cleanup_args.mutexPtr = mutex; + cleanup_args.cv = cv; + cleanup_args.resultPtr = &result; + +#ifdef _MSC_VER +#pragma inline_depth(0) +#endif + pthread_cleanup_push (ptw32_cond_wait_cleanup, (void *) &cleanup_args); + + /* + * Now we can release 'mutex' and... + */ + if ((result = pthread_mutex_unlock (mutex)) == 0) + { + + /* + * ...wait to be awakened by + * pthread_cond_signal, or + * pthread_cond_broadcast, or + * timeout, or + * thread cancellation + * + * Note: + * + * sem_timedwait is a cancellation point, + * hence providing the mechanism for making + * pthread_cond_wait a cancellation point. + * We use the cleanup mechanism to ensure we + * re-lock the mutex and adjust (to)unblock(ed) waiters + * counts if we are cancelled, timed out or signalled. + */ + if (sem_timedwait (&(cv->semBlockQueue), abstime) != 0) + { + result = errno; + } + } + + /* + * Always cleanup + */ + pthread_cleanup_pop (1); +#ifdef _MSC_VER +#pragma inline_depth() +#endif + + /* + * "result" can be modified by the cleanup handler. + */ + return result; + +} /* ptw32_cond_timedwait */ + + +int +pthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function waits on a condition variable until + * awakened by a signal or broadcast. + * + * Caller MUST be holding the mutex lock; the + * lock is released and the caller is blocked waiting + * on 'cond'. When 'cond' is signaled, the mutex + * is re-acquired before returning to the caller. + * + * PARAMETERS + * cond + * pointer to an instance of pthread_cond_t + * + * mutex + * pointer to an instance of pthread_mutex_t + * + * + * DESCRIPTION + * This function waits on a condition variable until + * awakened by a signal or broadcast. + * + * NOTES: + * + * 1) The function must be called with 'mutex' LOCKED + * by the calling thread, or undefined behaviour + * will result. + * + * 2) This routine atomically releases 'mutex' and causes + * the calling thread to block on the condition variable. + * The blocked thread may be awakened by + * pthread_cond_signal or + * pthread_cond_broadcast. + * + * Upon successful completion, the 'mutex' has been locked and + * is owned by the calling thread. + * + * + * RESULTS + * 0 caught condition; mutex released, + * EINVAL 'cond' or 'mutex' is invalid, + * EINVAL different mutexes for concurrent waits, + * EINVAL mutex is not held by the calling thread, + * + * ------------------------------------------------------ + */ +{ + /* + * The NULL abstime arg means INFINITE waiting. + */ + return (ptw32_cond_timedwait (cond, mutex, NULL)); + +} /* pthread_cond_wait */ + + +int +pthread_cond_timedwait (pthread_cond_t * cond, + pthread_mutex_t * mutex, + const struct timespec *abstime) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function waits on a condition variable either until + * awakened by a signal or broadcast; or until the time + * specified by abstime passes. + * + * PARAMETERS + * cond + * pointer to an instance of pthread_cond_t + * + * mutex + * pointer to an instance of pthread_mutex_t + * + * abstime + * pointer to an instance of (const struct timespec) + * + * + * DESCRIPTION + * This function waits on a condition variable either until + * awakened by a signal or broadcast; or until the time + * specified by abstime passes. + * + * NOTES: + * 1) The function must be called with 'mutex' LOCKED + * by the calling thread, or undefined behaviour + * will result. + * + * 2) This routine atomically releases 'mutex' and causes + * the calling thread to block on the condition variable. + * The blocked thread may be awakened by + * pthread_cond_signal or + * pthread_cond_broadcast. + * + * + * RESULTS + * 0 caught condition; mutex released, + * EINVAL 'cond', 'mutex', or abstime is invalid, + * EINVAL different mutexes for concurrent waits, + * EINVAL mutex is not held by the calling thread, + * ETIMEDOUT abstime ellapsed before cond was signaled. + * + * ------------------------------------------------------ + */ +{ + if (abstime == NULL) + { + return EINVAL; + } + + return (ptw32_cond_timedwait (cond, mutex, abstime)); + +} /* pthread_cond_timedwait */ diff --git a/pcsx2/windows/pthreads/pthread_condattr_destroy.c b/pcsx2/windows/pthreads/pthread_condattr_destroy.c index 2ca11b4edf..58a14828fd 100644 --- a/pcsx2/windows/pthreads/pthread_condattr_destroy.c +++ b/pcsx2/windows/pthreads/pthread_condattr_destroy.c @@ -1,86 +1,86 @@ -/* - * condvar_attr_destroy.c - * - * Description: - * This translation unit implements condition variables and their primitives. - * - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_condattr_destroy (pthread_condattr_t * attr) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Destroys a condition variable attributes object. - * The object can no longer be used. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_condattr_t - * - * - * DESCRIPTION - * Destroys a condition variable attributes object. - * The object can no longer be used. - * - * NOTES: - * 1) Does not affect condition variables created - * using 'attr' - * - * RESULTS - * 0 successfully released attr, - * EINVAL 'attr' is invalid. - * - * ------------------------------------------------------ - */ -{ - int result = 0; - - if (attr == NULL || *attr == NULL) - { - result = EINVAL; - } - else - { - (void) free (*attr); - - *attr = NULL; - result = 0; - } - - return result; - -} /* pthread_condattr_destroy */ +/* + * condvar_attr_destroy.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_condattr_destroy (pthread_condattr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Destroys a condition variable attributes object. + * The object can no longer be used. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_condattr_t + * + * + * DESCRIPTION + * Destroys a condition variable attributes object. + * The object can no longer be used. + * + * NOTES: + * 1) Does not affect condition variables created + * using 'attr' + * + * RESULTS + * 0 successfully released attr, + * EINVAL 'attr' is invalid. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + + if (attr == NULL || *attr == NULL) + { + result = EINVAL; + } + else + { + (void) free (*attr); + + *attr = NULL; + result = 0; + } + + return result; + +} /* pthread_condattr_destroy */ diff --git a/pcsx2/windows/pthreads/pthread_condattr_getpshared.c b/pcsx2/windows/pthreads/pthread_condattr_getpshared.c index b7b854fb44..a0ac6d8829 100644 --- a/pcsx2/windows/pthreads/pthread_condattr_getpshared.c +++ b/pcsx2/windows/pthreads/pthread_condattr_getpshared.c @@ -1,97 +1,97 @@ -/* - * pthread_condattr_getpshared.c - * - * Description: - * This translation unit implements condition variables and their primitives. - * - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_condattr_getpshared (const pthread_condattr_t * attr, int *pshared) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Determine whether condition variables created with 'attr' - * can be shared between processes. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_condattr_t - * - * pshared - * will be set to one of: - * - * PTHREAD_PROCESS_SHARED - * May be shared if in shared memory - * - * PTHREAD_PROCESS_PRIVATE - * Cannot be shared. - * - * - * DESCRIPTION - * Condition Variables created with 'attr' can be shared - * between processes if pthread_cond_t variable is allocated - * in memory shared by these processes. - * NOTES: - * 1) pshared condition variables MUST be allocated in - * shared memory. - * - * 2) The following macro is defined if shared mutexes - * are supported: - * _POSIX_THREAD_PROCESS_SHARED - * - * RESULTS - * 0 successfully retrieved attribute, - * EINVAL 'attr' or 'pshared' is invalid, - * - * ------------------------------------------------------ - */ -{ - int result; - - if ((attr != NULL && *attr != NULL) && (pshared != NULL)) - { - *pshared = (*attr)->pshared; - result = 0; - } - else - { - result = EINVAL; - } - - return result; - -} /* pthread_condattr_getpshared */ +/* + * pthread_condattr_getpshared.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_condattr_getpshared (const pthread_condattr_t * attr, int *pshared) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Determine whether condition variables created with 'attr' + * can be shared between processes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_condattr_t + * + * pshared + * will be set to one of: + * + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory + * + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. + * + * + * DESCRIPTION + * Condition Variables created with 'attr' can be shared + * between processes if pthread_cond_t variable is allocated + * in memory shared by these processes. + * NOTES: + * 1) pshared condition variables MUST be allocated in + * shared memory. + * + * 2) The following macro is defined if shared mutexes + * are supported: + * _POSIX_THREAD_PROCESS_SHARED + * + * RESULTS + * 0 successfully retrieved attribute, + * EINVAL 'attr' or 'pshared' is invalid, + * + * ------------------------------------------------------ + */ +{ + int result; + + if ((attr != NULL && *attr != NULL) && (pshared != NULL)) + { + *pshared = (*attr)->pshared; + result = 0; + } + else + { + result = EINVAL; + } + + return result; + +} /* pthread_condattr_getpshared */ diff --git a/pcsx2/windows/pthreads/pthread_condattr_init.c b/pcsx2/windows/pthreads/pthread_condattr_init.c index da79e21958..5987878e0c 100644 --- a/pcsx2/windows/pthreads/pthread_condattr_init.c +++ b/pcsx2/windows/pthreads/pthread_condattr_init.c @@ -1,87 +1,87 @@ -/* - * pthread_condattr_init.c - * - * Description: - * This translation unit implements condition variables and their primitives. - * - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_condattr_init (pthread_condattr_t * attr) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Initializes a condition variable attributes object - * with default attributes. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_condattr_t - * - * - * DESCRIPTION - * Initializes a condition variable attributes object - * with default attributes. - * - * NOTES: - * 1) Use to define condition variable types - * 2) It is up to the application to ensure - * that it doesn't re-init an attribute - * without destroying it first. Otherwise - * a memory leak is created. - * - * RESULTS - * 0 successfully initialized attr, - * ENOMEM insufficient memory for attr. - * - * ------------------------------------------------------ - */ -{ - pthread_condattr_t attr_result; - int result = 0; - - attr_result = (pthread_condattr_t) calloc (1, sizeof (*attr_result)); - - if (attr_result == NULL) - { - result = ENOMEM; - } - - *attr = attr_result; - - return result; - -} /* pthread_condattr_init */ +/* + * pthread_condattr_init.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_condattr_init (pthread_condattr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Initializes a condition variable attributes object + * with default attributes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_condattr_t + * + * + * DESCRIPTION + * Initializes a condition variable attributes object + * with default attributes. + * + * NOTES: + * 1) Use to define condition variable types + * 2) It is up to the application to ensure + * that it doesn't re-init an attribute + * without destroying it first. Otherwise + * a memory leak is created. + * + * RESULTS + * 0 successfully initialized attr, + * ENOMEM insufficient memory for attr. + * + * ------------------------------------------------------ + */ +{ + pthread_condattr_t attr_result; + int result = 0; + + attr_result = (pthread_condattr_t) calloc (1, sizeof (*attr_result)); + + if (attr_result == NULL) + { + result = ENOMEM; + } + + *attr = attr_result; + + return result; + +} /* pthread_condattr_init */ diff --git a/pcsx2/windows/pthreads/pthread_condattr_setpshared.c b/pcsx2/windows/pthreads/pthread_condattr_setpshared.c index b8b2213266..954fb38299 100644 --- a/pcsx2/windows/pthreads/pthread_condattr_setpshared.c +++ b/pcsx2/windows/pthreads/pthread_condattr_setpshared.c @@ -1,117 +1,117 @@ -/* - * pthread_condattr_setpshared.c - * - * Description: - * This translation unit implements condition variables and their primitives. - * - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_condattr_setpshared (pthread_condattr_t * attr, int pshared) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Mutexes created with 'attr' can be shared between - * processes if pthread_mutex_t variable is allocated - * in memory shared by these processes. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_mutexattr_t - * - * pshared - * must be one of: - * - * PTHREAD_PROCESS_SHARED - * May be shared if in shared memory - * - * PTHREAD_PROCESS_PRIVATE - * Cannot be shared. - * - * DESCRIPTION - * Mutexes creatd with 'attr' can be shared between - * processes if pthread_mutex_t variable is allocated - * in memory shared by these processes. - * - * NOTES: - * 1) pshared mutexes MUST be allocated in shared - * memory. - * - * 2) The following macro is defined if shared mutexes - * are supported: - * _POSIX_THREAD_PROCESS_SHARED - * - * RESULTS - * 0 successfully set attribute, - * EINVAL 'attr' or pshared is invalid, - * ENOSYS PTHREAD_PROCESS_SHARED not supported, - * - * ------------------------------------------------------ - */ -{ - int result; - - if ((attr != NULL && *attr != NULL) - && ((pshared == PTHREAD_PROCESS_SHARED) - || (pshared == PTHREAD_PROCESS_PRIVATE))) - { - if (pshared == PTHREAD_PROCESS_SHARED) - { - -#if !defined( _POSIX_THREAD_PROCESS_SHARED ) - result = ENOSYS; - pshared = PTHREAD_PROCESS_PRIVATE; -#else - result = 0; - -#endif /* _POSIX_THREAD_PROCESS_SHARED */ - - } - else - { - result = 0; - } - - (*attr)->pshared = pshared; - } - else - { - result = EINVAL; - } - - return result; - -} /* pthread_condattr_setpshared */ +/* + * pthread_condattr_setpshared.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_condattr_setpshared (pthread_condattr_t * attr, int pshared) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Mutexes created with 'attr' can be shared between + * processes if pthread_mutex_t variable is allocated + * in memory shared by these processes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_mutexattr_t + * + * pshared + * must be one of: + * + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory + * + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. + * + * DESCRIPTION + * Mutexes creatd with 'attr' can be shared between + * processes if pthread_mutex_t variable is allocated + * in memory shared by these processes. + * + * NOTES: + * 1) pshared mutexes MUST be allocated in shared + * memory. + * + * 2) The following macro is defined if shared mutexes + * are supported: + * _POSIX_THREAD_PROCESS_SHARED + * + * RESULTS + * 0 successfully set attribute, + * EINVAL 'attr' or pshared is invalid, + * ENOSYS PTHREAD_PROCESS_SHARED not supported, + * + * ------------------------------------------------------ + */ +{ + int result; + + if ((attr != NULL && *attr != NULL) + && ((pshared == PTHREAD_PROCESS_SHARED) + || (pshared == PTHREAD_PROCESS_PRIVATE))) + { + if (pshared == PTHREAD_PROCESS_SHARED) + { + +#if !defined( _POSIX_THREAD_PROCESS_SHARED ) + result = ENOSYS; + pshared = PTHREAD_PROCESS_PRIVATE; +#else + result = 0; + +#endif /* _POSIX_THREAD_PROCESS_SHARED */ + + } + else + { + result = 0; + } + + (*attr)->pshared = pshared; + } + else + { + result = EINVAL; + } + + return result; + +} /* pthread_condattr_setpshared */ diff --git a/pcsx2/windows/pthreads/pthread_delay_np.c b/pcsx2/windows/pthreads/pthread_delay_np.c index 628cb780a1..7fe9ae0166 100644 --- a/pcsx2/windows/pthreads/pthread_delay_np.c +++ b/pcsx2/windows/pthreads/pthread_delay_np.c @@ -1,171 +1,171 @@ -/* - * pthreads_delay_np.c - * - * Description: - * This translation unit implements non-portable thread functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -/* - * pthread_delay_np - * - * DESCRIPTION - * - * This routine causes a thread to delay execution for a specific period of time. - * This period ends at the current time plus the specified interval. The routine - * will not return before the end of the period is reached, but may return an - * arbitrary amount of time after the period has gone by. This can be due to - * system load, thread priorities, and system timer granularity. - * - * Specifying an interval of zero (0) seconds and zero (0) nanoseconds is - * allowed and can be used to force the thread to give up the processor or to - * deliver a pending cancelation request. - * - * The timespec structure contains the following two fields: - * - * tv_sec is an integer number of seconds. - * tv_nsec is an integer number of nanoseconds. - * - * Return Values - * - * If an error condition occurs, this routine returns an integer value indicating - * the type of error. Possible return values are as follows: - * - * 0 - * Successful completion. - * [EINVAL] - * The value specified by interval is invalid. - * - * Example - * - * The following code segment would wait for 5 and 1/2 seconds - * - * struct timespec tsWait; - * int intRC; - * - * tsWait.tv_sec = 5; - * tsWait.tv_nsec = 500000000L; - * intRC = pthread_delay_np(&tsWait); - */ -int -pthread_delay_np (struct timespec *interval) -{ - DWORD wait_time; - DWORD secs_in_millisecs; - DWORD millisecs; - DWORD status; - pthread_t self; - ptw32_thread_t * sp; - - if (interval == NULL) - { - return EINVAL; - } - - if (interval->tv_sec == 0L && interval->tv_nsec == 0L) - { - pthread_testcancel (); - Sleep (0); - pthread_testcancel (); - return (0); - } - - /* convert secs to millisecs */ - secs_in_millisecs = interval->tv_sec * 1000L; - - /* convert nanosecs to millisecs (rounding up) */ - millisecs = (interval->tv_nsec + 999999L) / 1000000L; - -#if defined(__WATCOMC__) -#pragma disable_message (124) -#endif - - /* - * Most compilers will issue a warning 'comparison always 0' - * because the variable type is unsigned, but we need to keep this - * for some reason I can't recall now. - */ - if (0 > (wait_time = secs_in_millisecs + millisecs)) - { - return EINVAL; - } - -#if defined(__WATCOMC__) -#pragma enable_message (124) -#endif - - if (NULL == (self = pthread_self ()).p) - { - return ENOMEM; - } - - sp = (ptw32_thread_t *) self.p; - - if (sp->cancelState == PTHREAD_CANCEL_ENABLE) - { - /* - * Async cancelation won't catch us until wait_time is up. - * Deferred cancelation will cancel us immediately. - */ - if (WAIT_OBJECT_0 == - (status = WaitForSingleObject (sp->cancelEvent, wait_time))) - { - /* - * Canceling! - */ - (void) pthread_mutex_lock (&sp->cancelLock); - if (sp->state < PThreadStateCanceling) - { - sp->state = PThreadStateCanceling; - sp->cancelState = PTHREAD_CANCEL_DISABLE; - (void) pthread_mutex_unlock (&sp->cancelLock); - - ptw32_throw (PTW32_EPS_CANCEL); - } - - (void) pthread_mutex_unlock (&sp->cancelLock); - return ESRCH; - } - else if (status != WAIT_TIMEOUT) - { - return EINVAL; - } - } - else - { - Sleep (wait_time); - } - - return (0); -} +/* + * pthreads_delay_np.c + * + * Description: + * This translation unit implements non-portable thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* + * pthread_delay_np + * + * DESCRIPTION + * + * This routine causes a thread to delay execution for a specific period of time. + * This period ends at the current time plus the specified interval. The routine + * will not return before the end of the period is reached, but may return an + * arbitrary amount of time after the period has gone by. This can be due to + * system load, thread priorities, and system timer granularity. + * + * Specifying an interval of zero (0) seconds and zero (0) nanoseconds is + * allowed and can be used to force the thread to give up the processor or to + * deliver a pending cancelation request. + * + * The timespec structure contains the following two fields: + * + * tv_sec is an integer number of seconds. + * tv_nsec is an integer number of nanoseconds. + * + * Return Values + * + * If an error condition occurs, this routine returns an integer value indicating + * the type of error. Possible return values are as follows: + * + * 0 + * Successful completion. + * [EINVAL] + * The value specified by interval is invalid. + * + * Example + * + * The following code segment would wait for 5 and 1/2 seconds + * + * struct timespec tsWait; + * int intRC; + * + * tsWait.tv_sec = 5; + * tsWait.tv_nsec = 500000000L; + * intRC = pthread_delay_np(&tsWait); + */ +int +pthread_delay_np (struct timespec *interval) +{ + DWORD wait_time; + DWORD secs_in_millisecs; + DWORD millisecs; + DWORD status; + pthread_t self; + ptw32_thread_t * sp; + + if (interval == NULL) + { + return EINVAL; + } + + if (interval->tv_sec == 0L && interval->tv_nsec == 0L) + { + pthread_testcancel (); + Sleep (0); + pthread_testcancel (); + return (0); + } + + /* convert secs to millisecs */ + secs_in_millisecs = interval->tv_sec * 1000L; + + /* convert nanosecs to millisecs (rounding up) */ + millisecs = (interval->tv_nsec + 999999L) / 1000000L; + +#if defined(__WATCOMC__) +#pragma disable_message (124) +#endif + + /* + * Most compilers will issue a warning 'comparison always 0' + * because the variable type is unsigned, but we need to keep this + * for some reason I can't recall now. + */ + if (0 > (wait_time = secs_in_millisecs + millisecs)) + { + return EINVAL; + } + +#if defined(__WATCOMC__) +#pragma enable_message (124) +#endif + + if (NULL == (self = pthread_self ()).p) + { + return ENOMEM; + } + + sp = (ptw32_thread_t *) self.p; + + if (sp->cancelState == PTHREAD_CANCEL_ENABLE) + { + /* + * Async cancelation won't catch us until wait_time is up. + * Deferred cancelation will cancel us immediately. + */ + if (WAIT_OBJECT_0 == + (status = WaitForSingleObject (sp->cancelEvent, wait_time))) + { + /* + * Canceling! + */ + (void) pthread_mutex_lock (&sp->cancelLock); + if (sp->state < PThreadStateCanceling) + { + sp->state = PThreadStateCanceling; + sp->cancelState = PTHREAD_CANCEL_DISABLE; + (void) pthread_mutex_unlock (&sp->cancelLock); + + ptw32_throw (PTW32_EPS_CANCEL); + } + + (void) pthread_mutex_unlock (&sp->cancelLock); + return ESRCH; + } + else if (status != WAIT_TIMEOUT) + { + return EINVAL; + } + } + else + { + Sleep (wait_time); + } + + return (0); +} diff --git a/pcsx2/windows/pthreads/pthread_detach.c b/pcsx2/windows/pthreads/pthread_detach.c index 3dbe2bb26a..00fb6adfb6 100644 --- a/pcsx2/windows/pthreads/pthread_detach.c +++ b/pcsx2/windows/pthreads/pthread_detach.c @@ -1,139 +1,139 @@ -/* - * pthread_detach.c - * - * Description: - * This translation unit implements functions related to thread - * synchronisation. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -/* - * Not needed yet, but defining it should indicate clashes with build target - * environment that should be fixed. - */ -#include - - -int -pthread_detach (pthread_t thread) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function detaches the given thread. - * - * PARAMETERS - * thread - * an instance of a pthread_t - * - * - * DESCRIPTION - * This function detaches the given thread. You may use it to - * detach the main thread or to detach a joinable thread. - * NOTE: detached threads cannot be joined; - * storage is freed immediately on termination. - * - * RESULTS - * 0 successfully detached the thread, - * EINVAL thread is not a joinable thread, - * ENOSPC a required resource has been exhausted, - * ESRCH no thread could be found for 'thread', - * - * ------------------------------------------------------ - */ -{ - int result; - BOOL destroyIt = PTW32_FALSE; - ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; - - EnterCriticalSection (&ptw32_thread_reuse_lock); - - if (NULL == tp - || thread.x != tp->ptHandle.x) - { - result = ESRCH; - } - else if (PTHREAD_CREATE_DETACHED == tp->detachState) - { - result = EINVAL; - } - else - { - /* - * Joinable ptw32_thread_t structs are not scavenged until - * a join or detach is done. The thread may have exited already, - * but all of the state and locks etc are still there. - */ - result = 0; - - if (pthread_mutex_lock (&tp->cancelLock) == 0) - { - if (tp->state != PThreadStateLast) - { - tp->detachState = PTHREAD_CREATE_DETACHED; - } - else if (tp->detachState != PTHREAD_CREATE_DETACHED) - { - /* - * Thread is joinable and has exited or is exiting. - */ - destroyIt = PTW32_TRUE; - } - (void) pthread_mutex_unlock (&tp->cancelLock); - } - else - { - /* cancelLock shouldn't fail, but if it does ... */ - result = ESRCH; - } - } - - LeaveCriticalSection (&ptw32_thread_reuse_lock); - - if (result == 0) - { - /* Thread is joinable */ - - if (destroyIt) - { - /* The thread has exited or is exiting but has not been joined or - * detached. Need to wait in case it's still exiting. - */ - (void) WaitForSingleObject(tp->threadH, INFINITE); - ptw32_threadDestroy (thread); - } - } - - return (result); - -} /* pthread_detach */ +/* + * pthread_detach.c + * + * Description: + * This translation unit implements functions related to thread + * synchronisation. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* + * Not needed yet, but defining it should indicate clashes with build target + * environment that should be fixed. + */ +#include + + +int +pthread_detach (pthread_t thread) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function detaches the given thread. + * + * PARAMETERS + * thread + * an instance of a pthread_t + * + * + * DESCRIPTION + * This function detaches the given thread. You may use it to + * detach the main thread or to detach a joinable thread. + * NOTE: detached threads cannot be joined; + * storage is freed immediately on termination. + * + * RESULTS + * 0 successfully detached the thread, + * EINVAL thread is not a joinable thread, + * ENOSPC a required resource has been exhausted, + * ESRCH no thread could be found for 'thread', + * + * ------------------------------------------------------ + */ +{ + int result; + BOOL destroyIt = PTW32_FALSE; + ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; + + EnterCriticalSection (&ptw32_thread_reuse_lock); + + if (NULL == tp + || thread.x != tp->ptHandle.x) + { + result = ESRCH; + } + else if (PTHREAD_CREATE_DETACHED == tp->detachState) + { + result = EINVAL; + } + else + { + /* + * Joinable ptw32_thread_t structs are not scavenged until + * a join or detach is done. The thread may have exited already, + * but all of the state and locks etc are still there. + */ + result = 0; + + if (pthread_mutex_lock (&tp->cancelLock) == 0) + { + if (tp->state != PThreadStateLast) + { + tp->detachState = PTHREAD_CREATE_DETACHED; + } + else if (tp->detachState != PTHREAD_CREATE_DETACHED) + { + /* + * Thread is joinable and has exited or is exiting. + */ + destroyIt = PTW32_TRUE; + } + (void) pthread_mutex_unlock (&tp->cancelLock); + } + else + { + /* cancelLock shouldn't fail, but if it does ... */ + result = ESRCH; + } + } + + LeaveCriticalSection (&ptw32_thread_reuse_lock); + + if (result == 0) + { + /* Thread is joinable */ + + if (destroyIt) + { + /* The thread has exited or is exiting but has not been joined or + * detached. Need to wait in case it's still exiting. + */ + (void) WaitForSingleObject(tp->threadH, INFINITE); + ptw32_threadDestroy (thread); + } + } + + return (result); + +} /* pthread_detach */ diff --git a/pcsx2/windows/pthreads/pthread_equal.c b/pcsx2/windows/pthreads/pthread_equal.c index 129bbb48ba..f96372edb8 100644 --- a/pcsx2/windows/pthreads/pthread_equal.c +++ b/pcsx2/windows/pthreads/pthread_equal.c @@ -1,76 +1,76 @@ -/* - * pthread_equal.c - * - * Description: - * This translation unit implements miscellaneous thread functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_equal (pthread_t t1, pthread_t t2) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function returns nonzero if t1 and t2 are equal, else - * returns nonzero - * - * PARAMETERS - * t1, - * t2 - * thread IDs - * - * - * DESCRIPTION - * This function returns nonzero if t1 and t2 are equal, else - * returns zero. - * - * RESULTS - * non-zero if t1 and t2 refer to the same thread, - * 0 t1 and t2 do not refer to the same thread - * - * ------------------------------------------------------ - */ -{ - int result; - - /* - * We also accept NULL == NULL - treating NULL as a thread - * for this special case, because there is no error that we can return. - */ - result = ( t1.p == t2.p && t1.x == t2.x ); - - return (result); - -} /* pthread_equal */ +/* + * pthread_equal.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_equal (pthread_t t1, pthread_t t2) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function returns nonzero if t1 and t2 are equal, else + * returns nonzero + * + * PARAMETERS + * t1, + * t2 + * thread IDs + * + * + * DESCRIPTION + * This function returns nonzero if t1 and t2 are equal, else + * returns zero. + * + * RESULTS + * non-zero if t1 and t2 refer to the same thread, + * 0 t1 and t2 do not refer to the same thread + * + * ------------------------------------------------------ + */ +{ + int result; + + /* + * We also accept NULL == NULL - treating NULL as a thread + * for this special case, because there is no error that we can return. + */ + result = ( t1.p == t2.p && t1.x == t2.x ); + + return (result); + +} /* pthread_equal */ diff --git a/pcsx2/windows/pthreads/pthread_exit.c b/pcsx2/windows/pthreads/pthread_exit.c index b401fb2e85..a4903129b6 100644 --- a/pcsx2/windows/pthreads/pthread_exit.c +++ b/pcsx2/windows/pthreads/pthread_exit.c @@ -1,106 +1,106 @@ -/* - * pthread_exit.c - * - * Description: - * This translation unit implements routines associated with exiting from - * a thread. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" -#ifndef _UWIN -//# include -#endif - -void -pthread_exit (void *value_ptr) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function terminates the calling thread, returning - * the value 'value_ptr' to any joining thread. - * - * PARAMETERS - * value_ptr - * a generic data value (i.e. not the address of a value) - * - * - * DESCRIPTION - * This function terminates the calling thread, returning - * the value 'value_ptr' to any joining thread. - * NOTE: thread should be joinable. - * - * RESULTS - * N/A - * - * ------------------------------------------------------ - */ -{ - ptw32_thread_t * sp; - - /* - * Don't use pthread_self() to avoid creating an implicit POSIX thread handle - * unnecessarily. - */ - sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); - -#ifdef _UWIN - if (--pthread_count <= 0) - exit ((int) value_ptr); -#endif - - if (NULL == sp) - { - /* - * A POSIX thread handle was never created. I.e. this is a - * Win32 thread that has never called a pthreads-win32 routine that - * required a POSIX handle. - * - * Implicit POSIX handles are cleaned up in ptw32_throw() now. - */ - -#if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__) - _endthreadex ((unsigned) value_ptr); -#else - _endthread (); -#endif - - /* Never reached */ - } - - sp->exitStatus = value_ptr; - - ptw32_throw (PTW32_EPS_EXIT); - - /* Never reached. */ - -} +/* + * pthread_exit.c + * + * Description: + * This translation unit implements routines associated with exiting from + * a thread. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#ifndef _UWIN +//# include +#endif + +void +pthread_exit (void *value_ptr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function terminates the calling thread, returning + * the value 'value_ptr' to any joining thread. + * + * PARAMETERS + * value_ptr + * a generic data value (i.e. not the address of a value) + * + * + * DESCRIPTION + * This function terminates the calling thread, returning + * the value 'value_ptr' to any joining thread. + * NOTE: thread should be joinable. + * + * RESULTS + * N/A + * + * ------------------------------------------------------ + */ +{ + ptw32_thread_t * sp; + + /* + * Don't use pthread_self() to avoid creating an implicit POSIX thread handle + * unnecessarily. + */ + sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); + +#ifdef _UWIN + if (--pthread_count <= 0) + exit ((int) value_ptr); +#endif + + if (NULL == sp) + { + /* + * A POSIX thread handle was never created. I.e. this is a + * Win32 thread that has never called a pthreads-win32 routine that + * required a POSIX handle. + * + * Implicit POSIX handles are cleaned up in ptw32_throw() now. + */ + +#if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__) + _endthreadex ((unsigned) value_ptr); +#else + _endthread (); +#endif + + /* Never reached */ + } + + sp->exitStatus = value_ptr; + + ptw32_throw (PTW32_EPS_EXIT); + + /* Never reached. */ + +} diff --git a/pcsx2/windows/pthreads/pthread_getconcurrency.c b/pcsx2/windows/pthreads/pthread_getconcurrency.c index 52430c6f8a..cf9e9c85c2 100644 --- a/pcsx2/windows/pthreads/pthread_getconcurrency.c +++ b/pcsx2/windows/pthreads/pthread_getconcurrency.c @@ -1,45 +1,45 @@ -/* - * pthread_getconcurrency.c - * - * Description: - * This translation unit implements miscellaneous thread functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_getconcurrency (void) -{ - return ptw32_concurrency; -} +/* + * pthread_getconcurrency.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_getconcurrency (void) +{ + return ptw32_concurrency; +} diff --git a/pcsx2/windows/pthreads/pthread_getschedparam.c b/pcsx2/windows/pthreads/pthread_getschedparam.c index 997978f07c..0afcfb74a9 100644 --- a/pcsx2/windows/pthreads/pthread_getschedparam.c +++ b/pcsx2/windows/pthreads/pthread_getschedparam.c @@ -1,75 +1,75 @@ -/* - * sched_getschedparam.c - * - * Description: - * POSIX thread functions that deal with thread scheduling. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" -#include "sched.h" - -int -pthread_getschedparam (pthread_t thread, int *policy, - struct sched_param *param) -{ - int result; - - /* Validate the thread id. */ - result = pthread_kill (thread, 0); - if (0 != result) - { - return result; - } - - /* - * Validate the policy and param args. - * Check that a policy constant wasn't passed rather than &policy. - */ - if (policy <= (int *) SCHED_MAX || param == NULL) - { - return EINVAL; - } - - /* Fill out the policy. */ - *policy = SCHED_OTHER; - - /* - * This function must return the priority value set by - * the most recent pthread_setschedparam() or pthread_create() - * for the target thread. It must not return the actual thread - * priority as altered by any system priority adjustments etc. - */ - param->sched_priority = ((ptw32_thread_t *)thread.p)->sched_priority; - - return 0; -} +/* + * sched_getschedparam.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +pthread_getschedparam (pthread_t thread, int *policy, + struct sched_param *param) +{ + int result; + + /* Validate the thread id. */ + result = pthread_kill (thread, 0); + if (0 != result) + { + return result; + } + + /* + * Validate the policy and param args. + * Check that a policy constant wasn't passed rather than &policy. + */ + if (policy <= (int *) SCHED_MAX || param == NULL) + { + return EINVAL; + } + + /* Fill out the policy. */ + *policy = SCHED_OTHER; + + /* + * This function must return the priority value set by + * the most recent pthread_setschedparam() or pthread_create() + * for the target thread. It must not return the actual thread + * priority as altered by any system priority adjustments etc. + */ + param->sched_priority = ((ptw32_thread_t *)thread.p)->sched_priority; + + return 0; +} diff --git a/pcsx2/windows/pthreads/pthread_getspecific.c b/pcsx2/windows/pthreads/pthread_getspecific.c index 13e3a69011..b05ff410ac 100644 --- a/pcsx2/windows/pthreads/pthread_getspecific.c +++ b/pcsx2/windows/pthreads/pthread_getspecific.c @@ -1,84 +1,84 @@ -/* - * pthread_getspecific.c - * - * Description: - * POSIX thread functions which implement thread-specific data (TSD). - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -void * -pthread_getspecific (pthread_key_t key) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function returns the current value of key in the - * calling thread. If no value has been set for 'key' in - * the thread, NULL is returned. - * - * PARAMETERS - * key - * an instance of pthread_key_t - * - * - * DESCRIPTION - * This function returns the current value of key in the - * calling thread. If no value has been set for 'key' in - * the thread, NULL is returned. - * - * RESULTS - * key value or NULL on failure - * - * ------------------------------------------------------ - */ -{ - void * ptr; - - if (key == NULL) - { - ptr = NULL; - } - else - { - int lasterror = GetLastError (); - int lastWSAerror = WSAGetLastError (); - - ptr = TlsGetValue (key->key); - - SetLastError (lasterror); - WSASetLastError (lastWSAerror); - } - - return ptr; -} +/* + * pthread_getspecific.c + * + * Description: + * POSIX thread functions which implement thread-specific data (TSD). + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +void * +pthread_getspecific (pthread_key_t key) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function returns the current value of key in the + * calling thread. If no value has been set for 'key' in + * the thread, NULL is returned. + * + * PARAMETERS + * key + * an instance of pthread_key_t + * + * + * DESCRIPTION + * This function returns the current value of key in the + * calling thread. If no value has been set for 'key' in + * the thread, NULL is returned. + * + * RESULTS + * key value or NULL on failure + * + * ------------------------------------------------------ + */ +{ + void * ptr; + + if (key == NULL) + { + ptr = NULL; + } + else + { + int lasterror = GetLastError (); + int lastWSAerror = WSAGetLastError (); + + ptr = TlsGetValue (key->key); + + SetLastError (lasterror); + WSASetLastError (lastWSAerror); + } + + return ptr; +} diff --git a/pcsx2/windows/pthreads/pthread_getw32threadhandle_np.c b/pcsx2/windows/pthreads/pthread_getw32threadhandle_np.c index 66bcff3256..9d22def3b4 100644 --- a/pcsx2/windows/pthreads/pthread_getw32threadhandle_np.c +++ b/pcsx2/windows/pthreads/pthread_getw32threadhandle_np.c @@ -1,53 +1,53 @@ -/* - * pthread_getw32threadhandle_np.c - * - * Description: - * This translation unit implements non-portable thread functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -/* - * pthread_getw32threadhandle_np() - * - * Returns the win32 thread handle that the POSIX - * thread "thread" is running as. - * - * Applications can use the win32 handle to set - * win32 specific attributes of the thread. - */ -HANDLE -pthread_getw32threadhandle_np (pthread_t thread) -{ - return ((ptw32_thread_t *)thread.p)->threadH; -} +/* + * pthread_getw32threadhandle_np.c + * + * Description: + * This translation unit implements non-portable thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* + * pthread_getw32threadhandle_np() + * + * Returns the win32 thread handle that the POSIX + * thread "thread" is running as. + * + * Applications can use the win32 handle to set + * win32 specific attributes of the thread. + */ +HANDLE +pthread_getw32threadhandle_np (pthread_t thread) +{ + return ((ptw32_thread_t *)thread.p)->threadH; +} diff --git a/pcsx2/windows/pthreads/pthread_join.c b/pcsx2/windows/pthreads/pthread_join.c index be6640b8c3..8237b6cf77 100644 --- a/pcsx2/windows/pthreads/pthread_join.c +++ b/pcsx2/windows/pthreads/pthread_join.c @@ -1,154 +1,154 @@ -/* - * pthread_join.c - * - * Description: - * This translation unit implements functions related to thread - * synchronisation. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -/* - * Not needed yet, but defining it should indicate clashes with build target - * environment that should be fixed. - */ -#include - - -int -pthread_join (pthread_t thread, void **value_ptr) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function waits for 'thread' to terminate and - * returns the thread's exit value if 'value_ptr' is not - * NULL. This also detaches the thread on successful - * completion. - * - * PARAMETERS - * thread - * an instance of pthread_t - * - * value_ptr - * pointer to an instance of pointer to void - * - * - * DESCRIPTION - * This function waits for 'thread' to terminate and - * returns the thread's exit value if 'value_ptr' is not - * NULL. This also detaches the thread on successful - * completion. - * NOTE: detached threads cannot be joined or canceled - * - * RESULTS - * 0 'thread' has completed - * EINVAL thread is not a joinable thread, - * ESRCH no thread could be found with ID 'thread', - * ENOENT thread couldn't find it's own valid handle, - * EDEADLK attempt to join thread with self - * - * ------------------------------------------------------ - */ -{ - int result; - pthread_t self; - ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; - - EnterCriticalSection (&ptw32_thread_reuse_lock); - - if (NULL == tp - || thread.x != tp->ptHandle.x) - { - result = ESRCH; - } - else if (PTHREAD_CREATE_DETACHED == tp->detachState) - { - result = EINVAL; - } - else - { - result = 0; - } - - LeaveCriticalSection (&ptw32_thread_reuse_lock); - - if (result == 0) - { - /* - * The target thread is joinable and can't be reused before we join it. - */ - self = pthread_self(); - - if (NULL == self.p) - { - result = ENOENT; - } - else if (pthread_equal (self, thread)) - { - result = EDEADLK; - } - else - { - /* - * Pthread_join is a cancelation point. - * If we are canceled then our target thread must not be - * detached (destroyed). This is guarranteed because - * pthreadCancelableWait will not return if we - * are canceled. - */ - result = pthreadCancelableWait (tp->threadH); - - if (0 == result) - { - if (value_ptr != NULL) - { - *value_ptr = tp->exitStatus; - } - - /* - * The result of making multiple simultaneous calls to - * pthread_join() or pthread_detach() specifying the same - * target is undefined. - */ - result = pthread_detach (thread); - } - else - { - result = ESRCH; - } - } - } - - return (result); - -} /* pthread_join */ +/* + * pthread_join.c + * + * Description: + * This translation unit implements functions related to thread + * synchronisation. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* + * Not needed yet, but defining it should indicate clashes with build target + * environment that should be fixed. + */ +#include + + +int +pthread_join (pthread_t thread, void **value_ptr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function waits for 'thread' to terminate and + * returns the thread's exit value if 'value_ptr' is not + * NULL. This also detaches the thread on successful + * completion. + * + * PARAMETERS + * thread + * an instance of pthread_t + * + * value_ptr + * pointer to an instance of pointer to void + * + * + * DESCRIPTION + * This function waits for 'thread' to terminate and + * returns the thread's exit value if 'value_ptr' is not + * NULL. This also detaches the thread on successful + * completion. + * NOTE: detached threads cannot be joined or canceled + * + * RESULTS + * 0 'thread' has completed + * EINVAL thread is not a joinable thread, + * ESRCH no thread could be found with ID 'thread', + * ENOENT thread couldn't find it's own valid handle, + * EDEADLK attempt to join thread with self + * + * ------------------------------------------------------ + */ +{ + int result; + pthread_t self; + ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; + + EnterCriticalSection (&ptw32_thread_reuse_lock); + + if (NULL == tp + || thread.x != tp->ptHandle.x) + { + result = ESRCH; + } + else if (PTHREAD_CREATE_DETACHED == tp->detachState) + { + result = EINVAL; + } + else + { + result = 0; + } + + LeaveCriticalSection (&ptw32_thread_reuse_lock); + + if (result == 0) + { + /* + * The target thread is joinable and can't be reused before we join it. + */ + self = pthread_self(); + + if (NULL == self.p) + { + result = ENOENT; + } + else if (pthread_equal (self, thread)) + { + result = EDEADLK; + } + else + { + /* + * Pthread_join is a cancelation point. + * If we are canceled then our target thread must not be + * detached (destroyed). This is guarranteed because + * pthreadCancelableWait will not return if we + * are canceled. + */ + result = pthreadCancelableWait (tp->threadH); + + if (0 == result) + { + if (value_ptr != NULL) + { + *value_ptr = tp->exitStatus; + } + + /* + * The result of making multiple simultaneous calls to + * pthread_join() or pthread_detach() specifying the same + * target is undefined. + */ + result = pthread_detach (thread); + } + else + { + result = ESRCH; + } + } + } + + return (result); + +} /* pthread_join */ diff --git a/pcsx2/windows/pthreads/pthread_key_create.c b/pcsx2/windows/pthreads/pthread_key_create.c index b3b410ac9f..5e278c2ca7 100644 --- a/pcsx2/windows/pthreads/pthread_key_create.c +++ b/pcsx2/windows/pthreads/pthread_key_create.c @@ -1,108 +1,108 @@ -/* - * pthread_key_create.c - * - * Description: - * POSIX thread functions which implement thread-specific data (TSD). - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -/* TLS_OUT_OF_INDEXES not defined on WinCE */ -#ifndef TLS_OUT_OF_INDEXES -#define TLS_OUT_OF_INDEXES 0xffffffff -#endif - -int -pthread_key_create (pthread_key_t * key, void (*destructor) (void *)) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function creates a thread-specific data key visible - * to all threads. All existing and new threads have a value - * NULL for key until set using pthread_setspecific. When any - * thread with a non-NULL value for key terminates, 'destructor' - * is called with key's current value for that thread. - * - * PARAMETERS - * key - * pointer to an instance of pthread_key_t - * - * - * DESCRIPTION - * This function creates a thread-specific data key visible - * to all threads. All existing and new threads have a value - * NULL for key until set using pthread_setspecific. When any - * thread with a non-NULL value for key terminates, 'destructor' - * is called with key's current value for that thread. - * - * RESULTS - * 0 successfully created semaphore, - * EAGAIN insufficient resources or PTHREAD_KEYS_MAX - * exceeded, - * ENOMEM insufficient memory to create the key, - * - * ------------------------------------------------------ - */ -{ - int result = 0; - pthread_key_t newkey; - - if ((newkey = (pthread_key_t) calloc (1, sizeof (*newkey))) == NULL) - { - result = ENOMEM; - } - else if ((newkey->key = TlsAlloc ()) == TLS_OUT_OF_INDEXES) - { - result = EAGAIN; - - free (newkey); - newkey = NULL; - } - else if (destructor != NULL) - { - /* - * Have to manage associations between thread and key; - * Therefore, need a lock that allows multiple threads - * to gain exclusive access to the key->threads list. - * - * The mutex will only be created when it is first locked. - */ - newkey->keyLock = PTHREAD_MUTEX_INITIALIZER; - newkey->destructor = destructor; - } - - *key = newkey; - - return (result); -} +/* + * pthread_key_create.c + * + * Description: + * POSIX thread functions which implement thread-specific data (TSD). + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +/* TLS_OUT_OF_INDEXES not defined on WinCE */ +#ifndef TLS_OUT_OF_INDEXES +#define TLS_OUT_OF_INDEXES 0xffffffff +#endif + +int +pthread_key_create (pthread_key_t * key, void (*destructor) (void *)) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function creates a thread-specific data key visible + * to all threads. All existing and new threads have a value + * NULL for key until set using pthread_setspecific. When any + * thread with a non-NULL value for key terminates, 'destructor' + * is called with key's current value for that thread. + * + * PARAMETERS + * key + * pointer to an instance of pthread_key_t + * + * + * DESCRIPTION + * This function creates a thread-specific data key visible + * to all threads. All existing and new threads have a value + * NULL for key until set using pthread_setspecific. When any + * thread with a non-NULL value for key terminates, 'destructor' + * is called with key's current value for that thread. + * + * RESULTS + * 0 successfully created semaphore, + * EAGAIN insufficient resources or PTHREAD_KEYS_MAX + * exceeded, + * ENOMEM insufficient memory to create the key, + * + * ------------------------------------------------------ + */ +{ + int result = 0; + pthread_key_t newkey; + + if ((newkey = (pthread_key_t) calloc (1, sizeof (*newkey))) == NULL) + { + result = ENOMEM; + } + else if ((newkey->key = TlsAlloc ()) == TLS_OUT_OF_INDEXES) + { + result = EAGAIN; + + free (newkey); + newkey = NULL; + } + else if (destructor != NULL) + { + /* + * Have to manage associations between thread and key; + * Therefore, need a lock that allows multiple threads + * to gain exclusive access to the key->threads list. + * + * The mutex will only be created when it is first locked. + */ + newkey->keyLock = PTHREAD_MUTEX_INITIALIZER; + newkey->destructor = destructor; + } + + *key = newkey; + + return (result); +} diff --git a/pcsx2/windows/pthreads/pthread_key_delete.c b/pcsx2/windows/pthreads/pthread_key_delete.c index c6acc11576..7da9b2fb6d 100644 --- a/pcsx2/windows/pthreads/pthread_key_delete.c +++ b/pcsx2/windows/pthreads/pthread_key_delete.c @@ -1,133 +1,133 @@ -/* - * pthread_key_delete.c - * - * Description: - * POSIX thread functions which implement thread-specific data (TSD). - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_key_delete (pthread_key_t key) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function deletes a thread-specific data key. This - * does not change the value of the thread specific data key - * for any thread and does not run the key's destructor - * in any thread so it should be used with caution. - * - * PARAMETERS - * key - * pointer to an instance of pthread_key_t - * - * - * DESCRIPTION - * This function deletes a thread-specific data key. This - * does not change the value of the thread specific data key - * for any thread and does not run the key's destructor - * in any thread so it should be used with caution. - * - * RESULTS - * 0 successfully deleted the key, - * EINVAL key is invalid, - * - * ------------------------------------------------------ - */ -{ - int result = 0; - - if (key != NULL) - { - if (key->threads != NULL && - key->destructor != NULL && - pthread_mutex_lock (&(key->keyLock)) == 0) - { - ThreadKeyAssoc *assoc; - /* - * Run through all Thread<-->Key associations - * for this key. - * - * While we hold at least one of the locks guarding - * the assoc, we know that the assoc pointed to by - * key->threads is valid. - */ - while ((assoc = (ThreadKeyAssoc *) key->threads) != NULL) - { - ptw32_thread_t * thread = assoc->thread; - - if (assoc == NULL) - { - /* Finished */ - break; - } - - if (pthread_mutex_lock (&(thread->threadLock)) == 0) - { - /* - * Since we are starting at the head of the key's threads - * chain, this will also point key->threads at the next assoc. - * While we hold key->keyLock, no other thread can insert - * a new assoc via pthread_setspecific. - */ - ptw32_tkAssocDestroy (assoc); - (void) pthread_mutex_unlock (&(thread->threadLock)); - } - else - { - /* Thread or lock is no longer valid? */ - ptw32_tkAssocDestroy (assoc); - } - } - pthread_mutex_unlock (&(key->keyLock)); - } - - TlsFree (key->key); - if (key->destructor != NULL) - { - /* A thread could be holding the keyLock */ - while (EBUSY == pthread_mutex_destroy (&(key->keyLock))) - { - Sleep(1); // Ugly. - } - } - -#if defined( _DEBUG ) - memset ((char *) key, 0, sizeof (*key)); -#endif - free (key); - } - - return (result); -} +/* + * pthread_key_delete.c + * + * Description: + * POSIX thread functions which implement thread-specific data (TSD). + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_key_delete (pthread_key_t key) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function deletes a thread-specific data key. This + * does not change the value of the thread specific data key + * for any thread and does not run the key's destructor + * in any thread so it should be used with caution. + * + * PARAMETERS + * key + * pointer to an instance of pthread_key_t + * + * + * DESCRIPTION + * This function deletes a thread-specific data key. This + * does not change the value of the thread specific data key + * for any thread and does not run the key's destructor + * in any thread so it should be used with caution. + * + * RESULTS + * 0 successfully deleted the key, + * EINVAL key is invalid, + * + * ------------------------------------------------------ + */ +{ + int result = 0; + + if (key != NULL) + { + if (key->threads != NULL && + key->destructor != NULL && + pthread_mutex_lock (&(key->keyLock)) == 0) + { + ThreadKeyAssoc *assoc; + /* + * Run through all Thread<-->Key associations + * for this key. + * + * While we hold at least one of the locks guarding + * the assoc, we know that the assoc pointed to by + * key->threads is valid. + */ + while ((assoc = (ThreadKeyAssoc *) key->threads) != NULL) + { + ptw32_thread_t * thread = assoc->thread; + + if (assoc == NULL) + { + /* Finished */ + break; + } + + if (pthread_mutex_lock (&(thread->threadLock)) == 0) + { + /* + * Since we are starting at the head of the key's threads + * chain, this will also point key->threads at the next assoc. + * While we hold key->keyLock, no other thread can insert + * a new assoc via pthread_setspecific. + */ + ptw32_tkAssocDestroy (assoc); + (void) pthread_mutex_unlock (&(thread->threadLock)); + } + else + { + /* Thread or lock is no longer valid? */ + ptw32_tkAssocDestroy (assoc); + } + } + pthread_mutex_unlock (&(key->keyLock)); + } + + TlsFree (key->key); + if (key->destructor != NULL) + { + /* A thread could be holding the keyLock */ + while (EBUSY == pthread_mutex_destroy (&(key->keyLock))) + { + Sleep(1); // Ugly. + } + } + +#if defined( _DEBUG ) + memset ((char *) key, 0, sizeof (*key)); +#endif + free (key); + } + + return (result); +} diff --git a/pcsx2/windows/pthreads/pthread_kill.c b/pcsx2/windows/pthreads/pthread_kill.c index 89d73fa85e..7de3fe2aa7 100644 --- a/pcsx2/windows/pthreads/pthread_kill.c +++ b/pcsx2/windows/pthreads/pthread_kill.c @@ -1,102 +1,102 @@ -/* - * pthread_kill.c - * - * Description: - * This translation unit implements the pthread_kill routine. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -/* - * Not needed yet, but defining it should indicate clashes with build target - * environment that should be fixed. - */ -#include - -int -pthread_kill (pthread_t thread, int sig) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function requests that a signal be delivered to the - * specified thread. If sig is zero, error checking is - * performed but no signal is actually sent such that this - * function can be used to check for a valid thread ID. - * - * PARAMETERS - * thread reference to an instances of pthread_t - * sig signal. Currently only a value of 0 is supported. - * - * - * DESCRIPTION - * This function requests that a signal be delivered to the - * specified thread. If sig is zero, error checking is - * performed but no signal is actually sent such that this - * function can be used to check for a valid thread ID. - * - * RESULTS - * ESRCH the thread is not a valid thread ID, - * EINVAL the value of the signal is invalid - * or unsupported. - * 0 the signal was successfully sent. - * - * ------------------------------------------------------ - */ -{ - int result = 0; - ptw32_thread_t * tp; - - EnterCriticalSection (&ptw32_thread_reuse_lock); - - tp = (ptw32_thread_t *) thread.p; - - if (NULL == tp - || thread.x != tp->ptHandle.x - || NULL == tp->threadH) - { - result = ESRCH; - } - - LeaveCriticalSection (&ptw32_thread_reuse_lock); - - if (0 == result && 0 != sig) - { - /* - * Currently does not support any signals. - */ - result = EINVAL; - } - - return result; - -} /* pthread_kill */ +/* + * pthread_kill.c + * + * Description: + * This translation unit implements the pthread_kill routine. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* + * Not needed yet, but defining it should indicate clashes with build target + * environment that should be fixed. + */ +#include + +int +pthread_kill (pthread_t thread, int sig) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function requests that a signal be delivered to the + * specified thread. If sig is zero, error checking is + * performed but no signal is actually sent such that this + * function can be used to check for a valid thread ID. + * + * PARAMETERS + * thread reference to an instances of pthread_t + * sig signal. Currently only a value of 0 is supported. + * + * + * DESCRIPTION + * This function requests that a signal be delivered to the + * specified thread. If sig is zero, error checking is + * performed but no signal is actually sent such that this + * function can be used to check for a valid thread ID. + * + * RESULTS + * ESRCH the thread is not a valid thread ID, + * EINVAL the value of the signal is invalid + * or unsupported. + * 0 the signal was successfully sent. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + ptw32_thread_t * tp; + + EnterCriticalSection (&ptw32_thread_reuse_lock); + + tp = (ptw32_thread_t *) thread.p; + + if (NULL == tp + || thread.x != tp->ptHandle.x + || NULL == tp->threadH) + { + result = ESRCH; + } + + LeaveCriticalSection (&ptw32_thread_reuse_lock); + + if (0 == result && 0 != sig) + { + /* + * Currently does not support any signals. + */ + result = EINVAL; + } + + return result; + +} /* pthread_kill */ diff --git a/pcsx2/windows/pthreads/pthread_mutex_destroy.c b/pcsx2/windows/pthreads/pthread_mutex_destroy.c index 105f1109f6..95509b3df6 100644 --- a/pcsx2/windows/pthreads/pthread_mutex_destroy.c +++ b/pcsx2/windows/pthreads/pthread_mutex_destroy.c @@ -1,146 +1,146 @@ -/* - * pthread_mutex_destroy.c - * - * Description: - * This translation unit implements mutual exclusion (mutex) primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_mutex_destroy (pthread_mutex_t * mutex) -{ - int result = 0; - pthread_mutex_t mx; - - /* - * Let the system deal with invalid pointers. - */ - - /* - * Check to see if we have something to delete. - */ - if (*mutex < PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) - { - mx = *mutex; - - result = pthread_mutex_trylock (&mx); - - /* - * If trylock succeeded and the mutex is not recursively locked it - * can be destroyed. - */ - if (result == 0) - { - if (mx->kind != PTHREAD_MUTEX_RECURSIVE || 1 == mx->recursive_count) - { - /* - * FIXME!!! - * The mutex isn't held by another thread but we could still - * be too late invalidating the mutex below since another thread - * may already have entered mutex_lock and the check for a valid - * *mutex != NULL. - * - * Note that this would be an unusual situation because it is not - * common that mutexes are destroyed while they are still in - * use by other threads. - */ - *mutex = NULL; - - result = pthread_mutex_unlock (&mx); - - if (result == 0) - { - if (!CloseHandle (mx->event)) - { - *mutex = mx; - result = EINVAL; - } - else - { - free (mx); - } - } - else - { - /* - * Restore the mutex before we return the error. - */ - *mutex = mx; - } - } - else /* mx->recursive_count > 1 */ - { - /* - * The mutex must be recursive and already locked by us (this thread). - */ - mx->recursive_count--; /* Undo effect of pthread_mutex_trylock() above */ - result = EBUSY; - } - } - } - else - { - /* - * See notes in ptw32_mutex_check_need_init() above also. - */ - EnterCriticalSection (&ptw32_mutex_test_init_lock); - - /* - * Check again. - */ - if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) - { - /* - * This is all we need to do to destroy a statically - * initialised mutex that has not yet been used (initialised). - * If we get to here, another thread - * waiting to initialise this mutex will get an EINVAL. - */ - *mutex = NULL; - } - else - { - /* - * The mutex has been initialised while we were waiting - * so assume it's in use. - */ - result = EBUSY; - } - - LeaveCriticalSection (&ptw32_mutex_test_init_lock); - } - - return (result); -} +/* + * pthread_mutex_destroy.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutex_destroy (pthread_mutex_t * mutex) +{ + int result = 0; + pthread_mutex_t mx; + + /* + * Let the system deal with invalid pointers. + */ + + /* + * Check to see if we have something to delete. + */ + if (*mutex < PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) + { + mx = *mutex; + + result = pthread_mutex_trylock (&mx); + + /* + * If trylock succeeded and the mutex is not recursively locked it + * can be destroyed. + */ + if (result == 0) + { + if (mx->kind != PTHREAD_MUTEX_RECURSIVE || 1 == mx->recursive_count) + { + /* + * FIXME!!! + * The mutex isn't held by another thread but we could still + * be too late invalidating the mutex below since another thread + * may already have entered mutex_lock and the check for a valid + * *mutex != NULL. + * + * Note that this would be an unusual situation because it is not + * common that mutexes are destroyed while they are still in + * use by other threads. + */ + *mutex = NULL; + + result = pthread_mutex_unlock (&mx); + + if (result == 0) + { + if (!CloseHandle (mx->event)) + { + *mutex = mx; + result = EINVAL; + } + else + { + free (mx); + } + } + else + { + /* + * Restore the mutex before we return the error. + */ + *mutex = mx; + } + } + else /* mx->recursive_count > 1 */ + { + /* + * The mutex must be recursive and already locked by us (this thread). + */ + mx->recursive_count--; /* Undo effect of pthread_mutex_trylock() above */ + result = EBUSY; + } + } + } + else + { + /* + * See notes in ptw32_mutex_check_need_init() above also. + */ + EnterCriticalSection (&ptw32_mutex_test_init_lock); + + /* + * Check again. + */ + if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) + { + /* + * This is all we need to do to destroy a statically + * initialised mutex that has not yet been used (initialised). + * If we get to here, another thread + * waiting to initialise this mutex will get an EINVAL. + */ + *mutex = NULL; + } + else + { + /* + * The mutex has been initialised while we were waiting + * so assume it's in use. + */ + result = EBUSY; + } + + LeaveCriticalSection (&ptw32_mutex_test_init_lock); + } + + return (result); +} diff --git a/pcsx2/windows/pthreads/pthread_mutex_init.c b/pcsx2/windows/pthreads/pthread_mutex_init.c index 57119c76eb..2f2cf92304 100644 --- a/pcsx2/windows/pthreads/pthread_mutex_init.c +++ b/pcsx2/windows/pthreads/pthread_mutex_init.c @@ -1,109 +1,109 @@ -/* - * pthread_mutex_init.c - * - * Description: - * This translation unit implements mutual exclusion (mutex) primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t * attr) -{ - int result = 0; - pthread_mutex_t mx; - - if (mutex == NULL) - { - return EINVAL; - } - -#ifdef PTW32_STATIC_LIB - // This allos for C++ static initializers to function without crashes. (air) - pthread_win32_process_attach_np(); -#endif - - if (attr != NULL - && *attr != NULL && (*attr)->pshared == PTHREAD_PROCESS_SHARED) - { - /* - * Creating mutex that can be shared between - * processes. - */ -#if _POSIX_THREAD_PROCESS_SHARED >= 0 - - /* - * Not implemented yet. - */ - -#error ERROR [__FILE__, line __LINE__]: Process shared mutexes are not supported yet. - -#else - - return ENOSYS; - -#endif /* _POSIX_THREAD_PROCESS_SHARED */ - - } - - mx = (pthread_mutex_t) calloc (1, sizeof (*mx)); - - if (mx == NULL) - { - result = ENOMEM; - } - else - { - mx->lock_idx = 0; - mx->recursive_count = 0; - mx->kind = (attr == NULL || *attr == NULL - ? PTHREAD_MUTEX_DEFAULT : (*attr)->kind); - mx->ownerThread.p = NULL; - - mx->event = CreateEvent (NULL, PTW32_FALSE, /* manual reset = No */ - PTW32_FALSE, /* initial state = not signaled */ - NULL); /* event name */ - - if (0 == mx->event) - { - result = ENOSPC; - free (mx); - mx = NULL; - } - } - - *mutex = mx; - - return (result); -} +/* + * pthread_mutex_init.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t * attr) +{ + int result = 0; + pthread_mutex_t mx; + + if (mutex == NULL) + { + return EINVAL; + } + +#ifdef PTW32_STATIC_LIB + // This allos for C++ static initializers to function without crashes. (air) + pthread_win32_process_attach_np(); +#endif + + if (attr != NULL + && *attr != NULL && (*attr)->pshared == PTHREAD_PROCESS_SHARED) + { + /* + * Creating mutex that can be shared between + * processes. + */ +#if _POSIX_THREAD_PROCESS_SHARED >= 0 + + /* + * Not implemented yet. + */ + +#error ERROR [__FILE__, line __LINE__]: Process shared mutexes are not supported yet. + +#else + + return ENOSYS; + +#endif /* _POSIX_THREAD_PROCESS_SHARED */ + + } + + mx = (pthread_mutex_t) calloc (1, sizeof (*mx)); + + if (mx == NULL) + { + result = ENOMEM; + } + else + { + mx->lock_idx = 0; + mx->recursive_count = 0; + mx->kind = (attr == NULL || *attr == NULL + ? PTHREAD_MUTEX_DEFAULT : (*attr)->kind); + mx->ownerThread.p = NULL; + + mx->event = CreateEvent (NULL, PTW32_FALSE, /* manual reset = No */ + PTW32_FALSE, /* initial state = not signaled */ + NULL); /* event name */ + + if (0 == mx->event) + { + result = ENOSPC; + free (mx); + mx = NULL; + } + } + + *mutex = mx; + + return (result); +} diff --git a/pcsx2/windows/pthreads/pthread_mutex_lock.c b/pcsx2/windows/pthreads/pthread_mutex_lock.c index 2e4da24dd7..4ca5c252fe 100644 --- a/pcsx2/windows/pthreads/pthread_mutex_lock.c +++ b/pcsx2/windows/pthreads/pthread_mutex_lock.c @@ -1,139 +1,139 @@ -/* - * pthread_mutex_lock.c - * - * Description: - * This translation unit implements mutual exclusion (mutex) primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#ifndef _UWIN -//# include -#endif -#include "pthread.h" -#include "implement.h" - -int -pthread_mutex_lock (pthread_mutex_t * mutex) -{ - int result = 0; - pthread_mutex_t mx; - - /* - * Let the system deal with invalid pointers. - */ - if (*mutex == NULL) - { - return EINVAL; - } - - /* - * We do a quick check to see if we need to do more work - * to initialise a static mutex. We check - * again inside the guarded section of ptw32_mutex_check_need_init() - * to avoid race conditions. - */ - if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) - { - if ((result = ptw32_mutex_check_need_init (mutex)) != 0) - { - return (result); - } - } - - mx = *mutex; - - if (mx->kind == PTHREAD_MUTEX_NORMAL) - { - if ((LONG) PTW32_INTERLOCKED_EXCHANGE( - (LPLONG) &mx->lock_idx, - (LONG) 1) != 0) - { - while ((LONG) PTW32_INTERLOCKED_EXCHANGE( - (LPLONG) &mx->lock_idx, - (LONG) -1) != 0) - { - if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) - { - result = EINVAL; - break; - } - } - } - } - else - { - pthread_t self = pthread_self(); - - if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE( - (PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, - (PTW32_INTERLOCKED_LONG) 1, - (PTW32_INTERLOCKED_LONG) 0) == 0) - { - mx->recursive_count = 1; - mx->ownerThread = self; - } - else - { - if (pthread_equal (mx->ownerThread, self)) - { - if (mx->kind == PTHREAD_MUTEX_RECURSIVE) - { - mx->recursive_count++; - } - else - { - result = EDEADLK; - } - } - else - { - while ((LONG) PTW32_INTERLOCKED_EXCHANGE( - (LPLONG) &mx->lock_idx, - (LONG) -1) != 0) - { - if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) - { - result = EINVAL; - break; - } - } - - if (0 == result) - { - mx->recursive_count = 1; - mx->ownerThread = self; - } - } - } - } - - return (result); -} +/* + * pthread_mutex_lock.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef _UWIN +//# include +#endif +#include "pthread.h" +#include "implement.h" + +int +pthread_mutex_lock (pthread_mutex_t * mutex) +{ + int result = 0; + pthread_mutex_t mx; + + /* + * Let the system deal with invalid pointers. + */ + if (*mutex == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static mutex. We check + * again inside the guarded section of ptw32_mutex_check_need_init() + * to avoid race conditions. + */ + if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) + { + if ((result = ptw32_mutex_check_need_init (mutex)) != 0) + { + return (result); + } + } + + mx = *mutex; + + if (mx->kind == PTHREAD_MUTEX_NORMAL) + { + if ((LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) 1) != 0) + { + while ((LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) -1) != 0) + { + if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) + { + result = EINVAL; + break; + } + } + } + } + else + { + pthread_t self = pthread_self(); + + if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE( + (PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1, + (PTW32_INTERLOCKED_LONG) 0) == 0) + { + mx->recursive_count = 1; + mx->ownerThread = self; + } + else + { + if (pthread_equal (mx->ownerThread, self)) + { + if (mx->kind == PTHREAD_MUTEX_RECURSIVE) + { + mx->recursive_count++; + } + else + { + result = EDEADLK; + } + } + else + { + while ((LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) -1) != 0) + { + if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) + { + result = EINVAL; + break; + } + } + + if (0 == result) + { + mx->recursive_count = 1; + mx->ownerThread = self; + } + } + } + } + + return (result); +} diff --git a/pcsx2/windows/pthreads/pthread_mutex_timedlock.c b/pcsx2/windows/pthreads/pthread_mutex_timedlock.c index ad373ba419..a2385522d5 100644 --- a/pcsx2/windows/pthreads/pthread_mutex_timedlock.c +++ b/pcsx2/windows/pthreads/pthread_mutex_timedlock.c @@ -1,196 +1,196 @@ -/* - * pthread_mutex_timedlock.c - * - * Description: - * This translation unit implements mutual exclusion (mutex) primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -static INLINE int -ptw32_timed_eventwait (HANDLE event, const struct timespec *abstime) - /* - * ------------------------------------------------------ - * DESCRIPTION - * This function waits on an event until signaled or until - * abstime passes. - * If abstime has passed when this routine is called then - * it returns a result to indicate this. - * - * If 'abstime' is a NULL pointer then this function will - * block until it can successfully decrease the value or - * until interrupted by a signal. - * - * This routine is not a cancelation point. - * - * RESULTS - * 0 successfully signaled, - * ETIMEDOUT abstime passed - * EINVAL 'event' is not a valid event, - * - * ------------------------------------------------------ - */ -{ - - DWORD milliseconds; - DWORD status; - - if (event == NULL) - { - return EINVAL; - } - else - { - if (abstime == NULL) - { - milliseconds = INFINITE; - } - else - { - /* - * Calculate timeout as milliseconds from current system time. - */ - milliseconds = ptw32_relmillisecs (abstime); - } - - status = WaitForSingleObject (event, milliseconds); - - if (status == WAIT_OBJECT_0) - { - return 0; - } - else if (status == WAIT_TIMEOUT) - { - return ETIMEDOUT; - } - else - { - return EINVAL; - } - } - - return 0; - -} /* ptw32_timed_semwait */ - - -int -pthread_mutex_timedlock (pthread_mutex_t * mutex, - const struct timespec *abstime) -{ - int result; - pthread_mutex_t mx; - - /* - * Let the system deal with invalid pointers. - */ - - /* - * We do a quick check to see if we need to do more work - * to initialise a static mutex. We check - * again inside the guarded section of ptw32_mutex_check_need_init() - * to avoid race conditions. - */ - if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) - { - if ((result = ptw32_mutex_check_need_init (mutex)) != 0) - { - return (result); - } - } - - mx = *mutex; - - if (mx->kind == PTHREAD_MUTEX_NORMAL) - { - if ((LONG) PTW32_INTERLOCKED_EXCHANGE( - (LPLONG) &mx->lock_idx, - (LONG) 1) != 0) - { - while ((LONG) PTW32_INTERLOCKED_EXCHANGE( - (LPLONG) &mx->lock_idx, - (LONG) -1) != 0) - { - if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) - { - return result; - } - } - } - } - else - { - pthread_t self = pthread_self(); - - if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE( - (PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, - (PTW32_INTERLOCKED_LONG) 1, - (PTW32_INTERLOCKED_LONG) 0) == 0) - { - mx->recursive_count = 1; - mx->ownerThread = self; - } - else - { - if (pthread_equal (mx->ownerThread, self)) - { - if (mx->kind == PTHREAD_MUTEX_RECURSIVE) - { - mx->recursive_count++; - } - else - { - return EDEADLK; - } - } - else - { - while ((LONG) PTW32_INTERLOCKED_EXCHANGE( - (LPLONG) &mx->lock_idx, - (LONG) -1) != 0) - { - if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) - { - return result; - } - } - - mx->recursive_count = 1; - mx->ownerThread = self; - } - } - } - - return 0; -} +/* + * pthread_mutex_timedlock.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +static INLINE int +ptw32_timed_eventwait (HANDLE event, const struct timespec *abstime) + /* + * ------------------------------------------------------ + * DESCRIPTION + * This function waits on an event until signaled or until + * abstime passes. + * If abstime has passed when this routine is called then + * it returns a result to indicate this. + * + * If 'abstime' is a NULL pointer then this function will + * block until it can successfully decrease the value or + * until interrupted by a signal. + * + * This routine is not a cancelation point. + * + * RESULTS + * 0 successfully signaled, + * ETIMEDOUT abstime passed + * EINVAL 'event' is not a valid event, + * + * ------------------------------------------------------ + */ +{ + + DWORD milliseconds; + DWORD status; + + if (event == NULL) + { + return EINVAL; + } + else + { + if (abstime == NULL) + { + milliseconds = INFINITE; + } + else + { + /* + * Calculate timeout as milliseconds from current system time. + */ + milliseconds = ptw32_relmillisecs (abstime); + } + + status = WaitForSingleObject (event, milliseconds); + + if (status == WAIT_OBJECT_0) + { + return 0; + } + else if (status == WAIT_TIMEOUT) + { + return ETIMEDOUT; + } + else + { + return EINVAL; + } + } + + return 0; + +} /* ptw32_timed_semwait */ + + +int +pthread_mutex_timedlock (pthread_mutex_t * mutex, + const struct timespec *abstime) +{ + int result; + pthread_mutex_t mx; + + /* + * Let the system deal with invalid pointers. + */ + + /* + * We do a quick check to see if we need to do more work + * to initialise a static mutex. We check + * again inside the guarded section of ptw32_mutex_check_need_init() + * to avoid race conditions. + */ + if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) + { + if ((result = ptw32_mutex_check_need_init (mutex)) != 0) + { + return (result); + } + } + + mx = *mutex; + + if (mx->kind == PTHREAD_MUTEX_NORMAL) + { + if ((LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) 1) != 0) + { + while ((LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) -1) != 0) + { + if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) + { + return result; + } + } + } + } + else + { + pthread_t self = pthread_self(); + + if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE( + (PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1, + (PTW32_INTERLOCKED_LONG) 0) == 0) + { + mx->recursive_count = 1; + mx->ownerThread = self; + } + else + { + if (pthread_equal (mx->ownerThread, self)) + { + if (mx->kind == PTHREAD_MUTEX_RECURSIVE) + { + mx->recursive_count++; + } + else + { + return EDEADLK; + } + } + else + { + while ((LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) -1) != 0) + { + if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) + { + return result; + } + } + + mx->recursive_count = 1; + mx->ownerThread = self; + } + } + } + + return 0; +} diff --git a/pcsx2/windows/pthreads/pthread_mutex_trylock.c b/pcsx2/windows/pthreads/pthread_mutex_trylock.c index 048869c966..50e8bc65cc 100644 --- a/pcsx2/windows/pthreads/pthread_mutex_trylock.c +++ b/pcsx2/windows/pthreads/pthread_mutex_trylock.c @@ -1,92 +1,92 @@ -/* - * pthread_mutex_trylock.c - * - * Description: - * This translation unit implements mutual exclusion (mutex) primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_mutex_trylock (pthread_mutex_t * mutex) -{ - int result = 0; - pthread_mutex_t mx; - - /* - * Let the system deal with invalid pointers. - */ - - /* - * We do a quick check to see if we need to do more work - * to initialise a static mutex. We check - * again inside the guarded section of ptw32_mutex_check_need_init() - * to avoid race conditions. - */ - if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) - { - if ((result = ptw32_mutex_check_need_init (mutex)) != 0) - { - return (result); - } - } - - mx = *mutex; - - if (0 == (LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE ( - (PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, - (PTW32_INTERLOCKED_LONG) 1, - (PTW32_INTERLOCKED_LONG) 0)) - { - if (mx->kind != PTHREAD_MUTEX_NORMAL) - { - mx->recursive_count = 1; - mx->ownerThread = pthread_self (); - } - } - else - { - if (mx->kind == PTHREAD_MUTEX_RECURSIVE && - pthread_equal (mx->ownerThread, pthread_self ())) - { - mx->recursive_count++; - } - else - { - result = EBUSY; - } - } - - return (result); -} +/* + * pthread_mutex_trylock.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutex_trylock (pthread_mutex_t * mutex) +{ + int result = 0; + pthread_mutex_t mx; + + /* + * Let the system deal with invalid pointers. + */ + + /* + * We do a quick check to see if we need to do more work + * to initialise a static mutex. We check + * again inside the guarded section of ptw32_mutex_check_need_init() + * to avoid race conditions. + */ + if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) + { + if ((result = ptw32_mutex_check_need_init (mutex)) != 0) + { + return (result); + } + } + + mx = *mutex; + + if (0 == (LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE ( + (PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1, + (PTW32_INTERLOCKED_LONG) 0)) + { + if (mx->kind != PTHREAD_MUTEX_NORMAL) + { + mx->recursive_count = 1; + mx->ownerThread = pthread_self (); + } + } + else + { + if (mx->kind == PTHREAD_MUTEX_RECURSIVE && + pthread_equal (mx->ownerThread, pthread_self ())) + { + mx->recursive_count++; + } + else + { + result = EBUSY; + } + } + + return (result); +} diff --git a/pcsx2/windows/pthreads/pthread_mutex_unlock.c b/pcsx2/windows/pthreads/pthread_mutex_unlock.c index ab8ec6500a..9ebe4e3781 100644 --- a/pcsx2/windows/pthreads/pthread_mutex_unlock.c +++ b/pcsx2/windows/pthreads/pthread_mutex_unlock.c @@ -1,119 +1,119 @@ -/* - * pthread_mutex_unlock.c - * - * Description: - * This translation unit implements mutual exclusion (mutex) primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_mutex_unlock (pthread_mutex_t * mutex) -{ - int result = 0; - pthread_mutex_t mx; - - /* - * Let the system deal with invalid pointers. - */ - - mx = *mutex; - - /* - * If the thread calling us holds the mutex then there is no - * race condition. If another thread holds the - * lock then we shouldn't be in here. - */ - if (mx < PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) - { - if (mx->kind == PTHREAD_MUTEX_NORMAL) - { - LONG idx; - - idx = (LONG) PTW32_INTERLOCKED_EXCHANGE ((LPLONG) &mx->lock_idx, - (LONG) 0); - if (idx != 0) - { - if (idx < 0) - { - /* - * Someone may be waiting on that mutex. - */ - if (SetEvent (mx->event) == 0) - { - result = EINVAL; - } - } - } - else - { - /* - * Was not locked (so can't be owned by us). - */ - result = EPERM; - } - } - else - { - if (pthread_equal (mx->ownerThread, pthread_self ())) - { - if (mx->kind != PTHREAD_MUTEX_RECURSIVE - || 0 == --mx->recursive_count) - { - mx->ownerThread.p = NULL; - - if ((LONG) PTW32_INTERLOCKED_EXCHANGE ((LPLONG) &mx->lock_idx, - (LONG) 0) < 0) - { - /* Someone may be waiting on that mutex */ - if (SetEvent (mx->event) == 0) - { - result = EINVAL; - } - } - } - } - else - { - result = EPERM; - } - } - } - else - { - result = EINVAL; - } - - return (result); -} +/* + * pthread_mutex_unlock.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutex_unlock (pthread_mutex_t * mutex) +{ + int result = 0; + pthread_mutex_t mx; + + /* + * Let the system deal with invalid pointers. + */ + + mx = *mutex; + + /* + * If the thread calling us holds the mutex then there is no + * race condition. If another thread holds the + * lock then we shouldn't be in here. + */ + if (mx < PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) + { + if (mx->kind == PTHREAD_MUTEX_NORMAL) + { + LONG idx; + + idx = (LONG) PTW32_INTERLOCKED_EXCHANGE ((LPLONG) &mx->lock_idx, + (LONG) 0); + if (idx != 0) + { + if (idx < 0) + { + /* + * Someone may be waiting on that mutex. + */ + if (SetEvent (mx->event) == 0) + { + result = EINVAL; + } + } + } + else + { + /* + * Was not locked (so can't be owned by us). + */ + result = EPERM; + } + } + else + { + if (pthread_equal (mx->ownerThread, pthread_self ())) + { + if (mx->kind != PTHREAD_MUTEX_RECURSIVE + || 0 == --mx->recursive_count) + { + mx->ownerThread.p = NULL; + + if ((LONG) PTW32_INTERLOCKED_EXCHANGE ((LPLONG) &mx->lock_idx, + (LONG) 0) < 0) + { + /* Someone may be waiting on that mutex */ + if (SetEvent (mx->event) == 0) + { + result = EINVAL; + } + } + } + } + else + { + result = EPERM; + } + } + } + else + { + result = EINVAL; + } + + return (result); +} diff --git a/pcsx2/windows/pthreads/pthread_mutexattr_destroy.c b/pcsx2/windows/pthreads/pthread_mutexattr_destroy.c index 5821f41396..9d424bfa28 100644 --- a/pcsx2/windows/pthreads/pthread_mutexattr_destroy.c +++ b/pcsx2/windows/pthreads/pthread_mutexattr_destroy.c @@ -1,83 +1,83 @@ -/* - * pthread_mutexattr_destroy.c - * - * Description: - * This translation unit implements mutual exclusion (mutex) primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_mutexattr_destroy (pthread_mutexattr_t * attr) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Destroys a mutex attributes object. The object can - * no longer be used. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_mutexattr_t - * - * - * DESCRIPTION - * Destroys a mutex attributes object. The object can - * no longer be used. - * - * NOTES: - * 1) Does not affect mutexes created using 'attr' - * - * RESULTS - * 0 successfully released attr, - * EINVAL 'attr' is invalid. - * - * ------------------------------------------------------ - */ -{ - int result = 0; - - if (attr == NULL || *attr == NULL) - { - result = EINVAL; - } - else - { - pthread_mutexattr_t ma = *attr; - - *attr = NULL; - free (ma); - } - - return (result); -} /* pthread_mutexattr_destroy */ +/* + * pthread_mutexattr_destroy.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutexattr_destroy (pthread_mutexattr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Destroys a mutex attributes object. The object can + * no longer be used. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_mutexattr_t + * + * + * DESCRIPTION + * Destroys a mutex attributes object. The object can + * no longer be used. + * + * NOTES: + * 1) Does not affect mutexes created using 'attr' + * + * RESULTS + * 0 successfully released attr, + * EINVAL 'attr' is invalid. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + + if (attr == NULL || *attr == NULL) + { + result = EINVAL; + } + else + { + pthread_mutexattr_t ma = *attr; + + *attr = NULL; + free (ma); + } + + return (result); +} /* pthread_mutexattr_destroy */ diff --git a/pcsx2/windows/pthreads/pthread_mutexattr_getkind_np.c b/pcsx2/windows/pthreads/pthread_mutexattr_getkind_np.c index 51508fe753..2d82ec6bc7 100644 --- a/pcsx2/windows/pthreads/pthread_mutexattr_getkind_np.c +++ b/pcsx2/windows/pthreads/pthread_mutexattr_getkind_np.c @@ -1,44 +1,44 @@ -/* - * pthread_mutexattr_getkind_np.c - * - * Description: - * This translation unit implements non-portable thread functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -int -pthread_mutexattr_getkind_np (pthread_mutexattr_t * attr, int *kind) -{ - return pthread_mutexattr_gettype (attr, kind); -} +/* + * pthread_mutexattr_getkind_np.c + * + * Description: + * This translation unit implements non-portable thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +int +pthread_mutexattr_getkind_np (pthread_mutexattr_t * attr, int *kind) +{ + return pthread_mutexattr_gettype (attr, kind); +} diff --git a/pcsx2/windows/pthreads/pthread_mutexattr_getpshared.c b/pcsx2/windows/pthreads/pthread_mutexattr_getpshared.c index 64d195254e..42f9589c51 100644 --- a/pcsx2/windows/pthreads/pthread_mutexattr_getpshared.c +++ b/pcsx2/windows/pthreads/pthread_mutexattr_getpshared.c @@ -1,95 +1,95 @@ -/* - * pthread_mutexattr_getpshared.c - * - * Description: - * This translation unit implements mutual exclusion (mutex) primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_mutexattr_getpshared (const pthread_mutexattr_t * attr, int *pshared) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Determine whether mutexes created with 'attr' can be - * shared between processes. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_mutexattr_t - * - * pshared - * will be set to one of: - * - * PTHREAD_PROCESS_SHARED - * May be shared if in shared memory - * - * PTHREAD_PROCESS_PRIVATE - * Cannot be shared. - * - * - * DESCRIPTION - * Mutexes creatd with 'attr' can be shared between - * processes if pthread_mutex_t variable is allocated - * in memory shared by these processes. - * NOTES: - * 1) pshared mutexes MUST be allocated in shared - * memory. - * 2) The following macro is defined if shared mutexes - * are supported: - * _POSIX_THREAD_PROCESS_SHARED - * - * RESULTS - * 0 successfully retrieved attribute, - * EINVAL 'attr' is invalid, - * - * ------------------------------------------------------ - */ -{ - int result; - - if ((attr != NULL && *attr != NULL) && (pshared != NULL)) - { - *pshared = (*attr)->pshared; - result = 0; - } - else - { - result = EINVAL; - } - - return (result); - -} /* pthread_mutexattr_getpshared */ +/* + * pthread_mutexattr_getpshared.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutexattr_getpshared (const pthread_mutexattr_t * attr, int *pshared) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Determine whether mutexes created with 'attr' can be + * shared between processes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_mutexattr_t + * + * pshared + * will be set to one of: + * + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory + * + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. + * + * + * DESCRIPTION + * Mutexes creatd with 'attr' can be shared between + * processes if pthread_mutex_t variable is allocated + * in memory shared by these processes. + * NOTES: + * 1) pshared mutexes MUST be allocated in shared + * memory. + * 2) The following macro is defined if shared mutexes + * are supported: + * _POSIX_THREAD_PROCESS_SHARED + * + * RESULTS + * 0 successfully retrieved attribute, + * EINVAL 'attr' is invalid, + * + * ------------------------------------------------------ + */ +{ + int result; + + if ((attr != NULL && *attr != NULL) && (pshared != NULL)) + { + *pshared = (*attr)->pshared; + result = 0; + } + else + { + result = EINVAL; + } + + return (result); + +} /* pthread_mutexattr_getpshared */ diff --git a/pcsx2/windows/pthreads/pthread_mutexattr_gettype.c b/pcsx2/windows/pthreads/pthread_mutexattr_gettype.c index f05bb68fc0..b60ca30bf0 100644 --- a/pcsx2/windows/pthreads/pthread_mutexattr_gettype.c +++ b/pcsx2/windows/pthreads/pthread_mutexattr_gettype.c @@ -1,56 +1,56 @@ -/* - * pthread_mutexattr_gettype.c - * - * Description: - * This translation unit implements mutual exclusion (mutex) primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind) -{ - int result = 0; - - if (attr != NULL && *attr != NULL && kind != NULL) - { - *kind = (*attr)->kind; - } - else - { - result = EINVAL; - } - - return (result); -} +/* + * pthread_mutexattr_gettype.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind) +{ + int result = 0; + + if (attr != NULL && *attr != NULL && kind != NULL) + { + *kind = (*attr)->kind; + } + else + { + result = EINVAL; + } + + return (result); +} diff --git a/pcsx2/windows/pthreads/pthread_mutexattr_init.c b/pcsx2/windows/pthreads/pthread_mutexattr_init.c index 3e7a1a27e9..d2797ff248 100644 --- a/pcsx2/windows/pthreads/pthread_mutexattr_init.c +++ b/pcsx2/windows/pthreads/pthread_mutexattr_init.c @@ -1,86 +1,86 @@ -/* - * pthread_mutexattr_init.c - * - * Description: - * This translation unit implements mutual exclusion (mutex) primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_mutexattr_init (pthread_mutexattr_t * attr) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Initializes a mutex attributes object with default - * attributes. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_mutexattr_t - * - * - * DESCRIPTION - * Initializes a mutex attributes object with default - * attributes. - * - * NOTES: - * 1) Used to define mutex types - * - * RESULTS - * 0 successfully initialized attr, - * ENOMEM insufficient memory for attr. - * - * ------------------------------------------------------ - */ -{ - int result = 0; - pthread_mutexattr_t ma; - - ma = (pthread_mutexattr_t) calloc (1, sizeof (*ma)); - - if (ma == NULL) - { - result = ENOMEM; - } - else - { - ma->pshared = PTHREAD_PROCESS_PRIVATE; - ma->kind = PTHREAD_MUTEX_DEFAULT; - } - - *attr = ma; - - return (result); -} /* pthread_mutexattr_init */ +/* + * pthread_mutexattr_init.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutexattr_init (pthread_mutexattr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Initializes a mutex attributes object with default + * attributes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_mutexattr_t + * + * + * DESCRIPTION + * Initializes a mutex attributes object with default + * attributes. + * + * NOTES: + * 1) Used to define mutex types + * + * RESULTS + * 0 successfully initialized attr, + * ENOMEM insufficient memory for attr. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + pthread_mutexattr_t ma; + + ma = (pthread_mutexattr_t) calloc (1, sizeof (*ma)); + + if (ma == NULL) + { + result = ENOMEM; + } + else + { + ma->pshared = PTHREAD_PROCESS_PRIVATE; + ma->kind = PTHREAD_MUTEX_DEFAULT; + } + + *attr = ma; + + return (result); +} /* pthread_mutexattr_init */ diff --git a/pcsx2/windows/pthreads/pthread_mutexattr_setkind_np.c b/pcsx2/windows/pthreads/pthread_mutexattr_setkind_np.c index 25549ddea9..faa936658f 100644 --- a/pcsx2/windows/pthreads/pthread_mutexattr_setkind_np.c +++ b/pcsx2/windows/pthreads/pthread_mutexattr_setkind_np.c @@ -1,44 +1,44 @@ -/* - * pthread_mutexattr_setkind_np.c - * - * Description: - * This translation unit implements non-portable thread functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -int -pthread_mutexattr_setkind_np (pthread_mutexattr_t * attr, int kind) -{ - return pthread_mutexattr_settype (attr, kind); -} +/* + * pthread_mutexattr_setkind_np.c + * + * Description: + * This translation unit implements non-portable thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +int +pthread_mutexattr_setkind_np (pthread_mutexattr_t * attr, int kind) +{ + return pthread_mutexattr_settype (attr, kind); +} diff --git a/pcsx2/windows/pthreads/pthread_mutexattr_setpshared.c b/pcsx2/windows/pthreads/pthread_mutexattr_setpshared.c index 7ca78d10b4..cfa6f71994 100644 --- a/pcsx2/windows/pthreads/pthread_mutexattr_setpshared.c +++ b/pcsx2/windows/pthreads/pthread_mutexattr_setpshared.c @@ -1,119 +1,119 @@ -/* - * pthread_mutexattr_setpshared.c - * - * Description: - * This translation unit implements mutual exclusion (mutex) primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, int pshared) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Mutexes created with 'attr' can be shared between - * processes if pthread_mutex_t variable is allocated - * in memory shared by these processes. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_mutexattr_t - * - * pshared - * must be one of: - * - * PTHREAD_PROCESS_SHARED - * May be shared if in shared memory - * - * PTHREAD_PROCESS_PRIVATE - * Cannot be shared. - * - * DESCRIPTION - * Mutexes creatd with 'attr' can be shared between - * processes if pthread_mutex_t variable is allocated - * in memory shared by these processes. - * - * NOTES: - * 1) pshared mutexes MUST be allocated in shared - * memory. - * - * 2) The following macro is defined if shared mutexes - * are supported: - * _POSIX_THREAD_PROCESS_SHARED - * - * RESULTS - * 0 successfully set attribute, - * EINVAL 'attr' or pshared is invalid, - * ENOSYS PTHREAD_PROCESS_SHARED not supported, - * - * ------------------------------------------------------ - */ -{ - int result; - - if ((attr != NULL && *attr != NULL) && - ((pshared == PTHREAD_PROCESS_SHARED) || - (pshared == PTHREAD_PROCESS_PRIVATE))) - { - if (pshared == PTHREAD_PROCESS_SHARED) - { - -#if !defined( _POSIX_THREAD_PROCESS_SHARED ) - - result = ENOSYS; - pshared = PTHREAD_PROCESS_PRIVATE; - -#else - - result = 0; - -#endif /* _POSIX_THREAD_PROCESS_SHARED */ - - } - else - { - result = 0; - } - - (*attr)->pshared = pshared; - } - else - { - result = EINVAL; - } - - return (result); - -} /* pthread_mutexattr_setpshared */ +/* + * pthread_mutexattr_setpshared.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, int pshared) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Mutexes created with 'attr' can be shared between + * processes if pthread_mutex_t variable is allocated + * in memory shared by these processes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_mutexattr_t + * + * pshared + * must be one of: + * + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory + * + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. + * + * DESCRIPTION + * Mutexes creatd with 'attr' can be shared between + * processes if pthread_mutex_t variable is allocated + * in memory shared by these processes. + * + * NOTES: + * 1) pshared mutexes MUST be allocated in shared + * memory. + * + * 2) The following macro is defined if shared mutexes + * are supported: + * _POSIX_THREAD_PROCESS_SHARED + * + * RESULTS + * 0 successfully set attribute, + * EINVAL 'attr' or pshared is invalid, + * ENOSYS PTHREAD_PROCESS_SHARED not supported, + * + * ------------------------------------------------------ + */ +{ + int result; + + if ((attr != NULL && *attr != NULL) && + ((pshared == PTHREAD_PROCESS_SHARED) || + (pshared == PTHREAD_PROCESS_PRIVATE))) + { + if (pshared == PTHREAD_PROCESS_SHARED) + { + +#if !defined( _POSIX_THREAD_PROCESS_SHARED ) + + result = ENOSYS; + pshared = PTHREAD_PROCESS_PRIVATE; + +#else + + result = 0; + +#endif /* _POSIX_THREAD_PROCESS_SHARED */ + + } + else + { + result = 0; + } + + (*attr)->pshared = pshared; + } + else + { + result = EINVAL; + } + + return (result); + +} /* pthread_mutexattr_setpshared */ diff --git a/pcsx2/windows/pthreads/pthread_mutexattr_settype.c b/pcsx2/windows/pthreads/pthread_mutexattr_settype.c index 62f77ba2ae..8365daf65d 100644 --- a/pcsx2/windows/pthreads/pthread_mutexattr_settype.c +++ b/pcsx2/windows/pthreads/pthread_mutexattr_settype.c @@ -1,143 +1,143 @@ -/* - * pthread_mutexattr_settype.c - * - * Description: - * This translation unit implements mutual exclusion (mutex) primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind) - /* - * ------------------------------------------------------ - * - * DOCPUBLIC - * The pthread_mutexattr_settype() and - * pthread_mutexattr_gettype() functions respectively set and - * get the mutex type attribute. This attribute is set in the - * type parameter to these functions. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_mutexattr_t - * - * type - * must be one of: - * - * PTHREAD_MUTEX_DEFAULT - * - * PTHREAD_MUTEX_NORMAL - * - * PTHREAD_MUTEX_ERRORCHECK - * - * PTHREAD_MUTEX_RECURSIVE - * - * DESCRIPTION - * The pthread_mutexattr_settype() and - * pthread_mutexattr_gettype() functions respectively set and - * get the mutex type attribute. This attribute is set in the - * type parameter to these functions. The default value of the - * type attribute is PTHREAD_MUTEX_DEFAULT. - * - * The type of mutex is contained in the type attribute of the - * mutex attributes. Valid mutex types include: - * - * PTHREAD_MUTEX_NORMAL - * This type of mutex does not detect deadlock. A - * thread attempting to relock this mutex without - * first unlocking it will deadlock. Attempting to - * unlock a mutex locked by a different thread - * results in undefined behavior. Attempting to - * unlock an unlocked mutex results in undefined - * behavior. - * - * PTHREAD_MUTEX_ERRORCHECK - * This type of mutex provides error checking. A - * thread attempting to relock this mutex without - * first unlocking it will return with an error. A - * thread attempting to unlock a mutex which another - * thread has locked will return with an error. A - * thread attempting to unlock an unlocked mutex will - * return with an error. - * - * PTHREAD_MUTEX_DEFAULT - * Same as PTHREAD_MUTEX_NORMAL. - * - * PTHREAD_MUTEX_RECURSIVE - * A thread attempting to relock this mutex without - * first unlocking it will succeed in locking the - * mutex. The relocking deadlock which can occur with - * mutexes of type PTHREAD_MUTEX_NORMAL cannot occur - * with this type of mutex. Multiple locks of this - * mutex require the same number of unlocks to - * release the mutex before another thread can - * acquire the mutex. A thread attempting to unlock a - * mutex which another thread has locked will return - * with an error. A thread attempting to unlock an - * unlocked mutex will return with an error. This - * type of mutex is only supported for mutexes whose - * process shared attribute is - * PTHREAD_PROCESS_PRIVATE. - * - * RESULTS - * 0 successfully set attribute, - * EINVAL 'attr' or 'type' is invalid, - * - * ------------------------------------------------------ - */ -{ - int result = 0; - - if ((attr != NULL && *attr != NULL)) - { - switch (kind) - { - case PTHREAD_MUTEX_FAST_NP: - case PTHREAD_MUTEX_RECURSIVE_NP: - case PTHREAD_MUTEX_ERRORCHECK_NP: - (*attr)->kind = kind; - break; - default: - result = EINVAL; - break; - } - } - else - { - result = EINVAL; - } - - return (result); -} /* pthread_mutexattr_settype */ +/* + * pthread_mutexattr_settype.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind) + /* + * ------------------------------------------------------ + * + * DOCPUBLIC + * The pthread_mutexattr_settype() and + * pthread_mutexattr_gettype() functions respectively set and + * get the mutex type attribute. This attribute is set in the + * type parameter to these functions. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_mutexattr_t + * + * type + * must be one of: + * + * PTHREAD_MUTEX_DEFAULT + * + * PTHREAD_MUTEX_NORMAL + * + * PTHREAD_MUTEX_ERRORCHECK + * + * PTHREAD_MUTEX_RECURSIVE + * + * DESCRIPTION + * The pthread_mutexattr_settype() and + * pthread_mutexattr_gettype() functions respectively set and + * get the mutex type attribute. This attribute is set in the + * type parameter to these functions. The default value of the + * type attribute is PTHREAD_MUTEX_DEFAULT. + * + * The type of mutex is contained in the type attribute of the + * mutex attributes. Valid mutex types include: + * + * PTHREAD_MUTEX_NORMAL + * This type of mutex does not detect deadlock. A + * thread attempting to relock this mutex without + * first unlocking it will deadlock. Attempting to + * unlock a mutex locked by a different thread + * results in undefined behavior. Attempting to + * unlock an unlocked mutex results in undefined + * behavior. + * + * PTHREAD_MUTEX_ERRORCHECK + * This type of mutex provides error checking. A + * thread attempting to relock this mutex without + * first unlocking it will return with an error. A + * thread attempting to unlock a mutex which another + * thread has locked will return with an error. A + * thread attempting to unlock an unlocked mutex will + * return with an error. + * + * PTHREAD_MUTEX_DEFAULT + * Same as PTHREAD_MUTEX_NORMAL. + * + * PTHREAD_MUTEX_RECURSIVE + * A thread attempting to relock this mutex without + * first unlocking it will succeed in locking the + * mutex. The relocking deadlock which can occur with + * mutexes of type PTHREAD_MUTEX_NORMAL cannot occur + * with this type of mutex. Multiple locks of this + * mutex require the same number of unlocks to + * release the mutex before another thread can + * acquire the mutex. A thread attempting to unlock a + * mutex which another thread has locked will return + * with an error. A thread attempting to unlock an + * unlocked mutex will return with an error. This + * type of mutex is only supported for mutexes whose + * process shared attribute is + * PTHREAD_PROCESS_PRIVATE. + * + * RESULTS + * 0 successfully set attribute, + * EINVAL 'attr' or 'type' is invalid, + * + * ------------------------------------------------------ + */ +{ + int result = 0; + + if ((attr != NULL && *attr != NULL)) + { + switch (kind) + { + case PTHREAD_MUTEX_FAST_NP: + case PTHREAD_MUTEX_RECURSIVE_NP: + case PTHREAD_MUTEX_ERRORCHECK_NP: + (*attr)->kind = kind; + break; + default: + result = EINVAL; + break; + } + } + else + { + result = EINVAL; + } + + return (result); +} /* pthread_mutexattr_settype */ diff --git a/pcsx2/windows/pthreads/pthread_num_processors_np.c b/pcsx2/windows/pthreads/pthread_num_processors_np.c index 897a1b260a..3067d117d3 100644 --- a/pcsx2/windows/pthreads/pthread_num_processors_np.c +++ b/pcsx2/windows/pthreads/pthread_num_processors_np.c @@ -1,56 +1,56 @@ -/* - * pthread_num_processors_np.c - * - * Description: - * This translation unit implements non-portable thread functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -/* - * pthread_num_processors_np() - * - * Get the number of CPUs available to the process. - */ -int -pthread_num_processors_np (void) -{ - int count; - - if (ptw32_getprocessors (&count) != 0) - { - count = 1; - } - - return (count); -} +/* + * pthread_num_processors_np.c + * + * Description: + * This translation unit implements non-portable thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* + * pthread_num_processors_np() + * + * Get the number of CPUs available to the process. + */ +int +pthread_num_processors_np (void) +{ + int count; + + if (ptw32_getprocessors (&count) != 0) + { + count = 1; + } + + return (count); +} diff --git a/pcsx2/windows/pthreads/pthread_once.c b/pcsx2/windows/pthreads/pthread_once.c index 19e63b4124..96d45f2974 100644 --- a/pcsx2/windows/pthreads/pthread_once.c +++ b/pcsx2/windows/pthreads/pthread_once.c @@ -1,86 +1,86 @@ -/* - * pthread_once.c - * - * Description: - * This translation unit implements miscellaneous thread functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -static void PTW32_CDECL -ptw32_once_on_init_cancel (void * arg) -{ - /* when the initting thread is cancelled we have to release the lock */ - ptw32_mcs_local_node_t *node = (ptw32_mcs_local_node_t *)arg; - ptw32_mcs_lock_release(node); -} - -int -pthread_once (pthread_once_t * once_control, void (*init_routine) (void)) -{ - if (once_control == NULL || init_routine == NULL) - { - return EINVAL; - } - - if (!InterlockedExchangeAdd((LPLONG)&once_control->done, 0)) /* MBR fence */ - { - ptw32_mcs_local_node_t node; - - ptw32_mcs_lock_acquire((ptw32_mcs_lock_t *)&once_control->lock, &node); - - if (!once_control->done) - { - -#ifdef _MSC_VER -#pragma inline_depth(0) -#endif - - pthread_cleanup_push(ptw32_once_on_init_cancel, (void *)&node); - (*init_routine)(); - pthread_cleanup_pop(0); - -#ifdef _MSC_VER -#pragma inline_depth() -#endif - - once_control->done = PTW32_TRUE; - } - - ptw32_mcs_lock_release(&node); - } - - return 0; - -} /* pthread_once */ +/* + * pthread_once.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +static void PTW32_CDECL +ptw32_once_on_init_cancel (void * arg) +{ + /* when the initting thread is cancelled we have to release the lock */ + ptw32_mcs_local_node_t *node = (ptw32_mcs_local_node_t *)arg; + ptw32_mcs_lock_release(node); +} + +int +pthread_once (pthread_once_t * once_control, void (*init_routine) (void)) +{ + if (once_control == NULL || init_routine == NULL) + { + return EINVAL; + } + + if (!InterlockedExchangeAdd((LPLONG)&once_control->done, 0)) /* MBR fence */ + { + ptw32_mcs_local_node_t node; + + ptw32_mcs_lock_acquire((ptw32_mcs_lock_t *)&once_control->lock, &node); + + if (!once_control->done) + { + +#ifdef _MSC_VER +#pragma inline_depth(0) +#endif + + pthread_cleanup_push(ptw32_once_on_init_cancel, (void *)&node); + (*init_routine)(); + pthread_cleanup_pop(0); + +#ifdef _MSC_VER +#pragma inline_depth() +#endif + + once_control->done = PTW32_TRUE; + } + + ptw32_mcs_lock_release(&node); + } + + return 0; + +} /* pthread_once */ diff --git a/pcsx2/windows/pthreads/pthread_rwlock_destroy.c b/pcsx2/windows/pthreads/pthread_rwlock_destroy.c index 7b6a6deb68..5a747ede06 100644 --- a/pcsx2/windows/pthreads/pthread_rwlock_destroy.c +++ b/pcsx2/windows/pthreads/pthread_rwlock_destroy.c @@ -1,143 +1,143 @@ -/* - * pthread_rwlock_destroy.c - * - * Description: - * This translation unit implements read/write lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include -#include - -#include "pthread.h" -#include "implement.h" - -int -pthread_rwlock_destroy (pthread_rwlock_t * rwlock) -{ - pthread_rwlock_t rwl; - int result = 0, result1 = 0, result2 = 0; - - if (rwlock == NULL || *rwlock == NULL) - { - return EINVAL; - } - - if (*rwlock != PTHREAD_RWLOCK_INITIALIZER) - { - rwl = *rwlock; - - if (rwl->nMagic != PTW32_RWLOCK_MAGIC) - { - return EINVAL; - } - - if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0) - { - return result; - } - - if ((result = - pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) - { - (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); - return result; - } - - /* - * Check whether any threads own/wait for the lock (wait for ex.access); - * report "BUSY" if so. - */ - if (rwl->nExclusiveAccessCount > 0 - || rwl->nSharedAccessCount > rwl->nCompletedSharedAccessCount) - { - result = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted)); - result1 = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); - result2 = EBUSY; - } - else - { - rwl->nMagic = 0; - - if ((result = - pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) - { - pthread_mutex_unlock (&rwl->mtxExclusiveAccess); - return result; - } - - if ((result = - pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))) != 0) - { - return result; - } - - *rwlock = NULL; /* Invalidate rwlock before anything else */ - result = pthread_cond_destroy (&(rwl->cndSharedAccessCompleted)); - result1 = pthread_mutex_destroy (&(rwl->mtxSharedAccessCompleted)); - result2 = pthread_mutex_destroy (&(rwl->mtxExclusiveAccess)); - (void) free (rwl); - } - } - else - { - /* - * See notes in ptw32_rwlock_check_need_init() above also. - */ - EnterCriticalSection (&ptw32_rwlock_test_init_lock); - - /* - * Check again. - */ - if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) - { - /* - * This is all we need to do to destroy a statically - * initialised rwlock that has not yet been used (initialised). - * If we get to here, another thread - * waiting to initialise this rwlock will get an EINVAL. - */ - *rwlock = NULL; - } - else - { - /* - * The rwlock has been initialised while we were waiting - * so assume it's in use. - */ - result = EBUSY; - } - - LeaveCriticalSection (&ptw32_rwlock_test_init_lock); - } - - return ((result != 0) ? result : ((result1 != 0) ? result1 : result2)); -} +/* + * pthread_rwlock_destroy.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlock_destroy (pthread_rwlock_t * rwlock) +{ + pthread_rwlock_t rwl; + int result = 0, result1 = 0, result2 = 0; + + if (rwlock == NULL || *rwlock == NULL) + { + return EINVAL; + } + + if (*rwlock != PTHREAD_RWLOCK_INITIALIZER) + { + rwl = *rwlock; + + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) + { + return EINVAL; + } + + if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0) + { + return result; + } + + if ((result = + pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + + /* + * Check whether any threads own/wait for the lock (wait for ex.access); + * report "BUSY" if so. + */ + if (rwl->nExclusiveAccessCount > 0 + || rwl->nSharedAccessCount > rwl->nCompletedSharedAccessCount) + { + result = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted)); + result1 = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + result2 = EBUSY; + } + else + { + rwl->nMagic = 0; + + if ((result = + pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + pthread_mutex_unlock (&rwl->mtxExclusiveAccess); + return result; + } + + if ((result = + pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))) != 0) + { + return result; + } + + *rwlock = NULL; /* Invalidate rwlock before anything else */ + result = pthread_cond_destroy (&(rwl->cndSharedAccessCompleted)); + result1 = pthread_mutex_destroy (&(rwl->mtxSharedAccessCompleted)); + result2 = pthread_mutex_destroy (&(rwl->mtxExclusiveAccess)); + (void) free (rwl); + } + } + else + { + /* + * See notes in ptw32_rwlock_check_need_init() above also. + */ + EnterCriticalSection (&ptw32_rwlock_test_init_lock); + + /* + * Check again. + */ + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + { + /* + * This is all we need to do to destroy a statically + * initialised rwlock that has not yet been used (initialised). + * If we get to here, another thread + * waiting to initialise this rwlock will get an EINVAL. + */ + *rwlock = NULL; + } + else + { + /* + * The rwlock has been initialised while we were waiting + * so assume it's in use. + */ + result = EBUSY; + } + + LeaveCriticalSection (&ptw32_rwlock_test_init_lock); + } + + return ((result != 0) ? result : ((result1 != 0) ? result1 : result2)); +} diff --git a/pcsx2/windows/pthreads/pthread_rwlock_init.c b/pcsx2/windows/pthreads/pthread_rwlock_init.c index 476fe25ac7..c2e827c6a1 100644 --- a/pcsx2/windows/pthreads/pthread_rwlock_init.c +++ b/pcsx2/windows/pthreads/pthread_rwlock_init.c @@ -1,115 +1,115 @@ -/* - * pthread_rwlock_init.c - * - * Description: - * This translation unit implements read/write lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include -#include - -#include "pthread.h" -#include "implement.h" - -int -pthread_rwlock_init (pthread_rwlock_t * rwlock, - const pthread_rwlockattr_t * attr) -{ - int result; - pthread_rwlock_t rwl = 0; - - if (rwlock == NULL) - { - return EINVAL; - } - -#ifdef PTW32_STATIC_LIB - // This allos for C++ static initializers to function without crashes. (air) - pthread_win32_process_attach_np(); -#endif - - if (attr != NULL && *attr != NULL) - { - result = EINVAL; /* Not supported */ - goto DONE; - } - - rwl = (pthread_rwlock_t) calloc (1, sizeof (*rwl)); - - if (rwl == NULL) - { - result = ENOMEM; - goto DONE; - } - - rwl->nSharedAccessCount = 0; - rwl->nExclusiveAccessCount = 0; - rwl->nCompletedSharedAccessCount = 0; - - result = pthread_mutex_init (&rwl->mtxExclusiveAccess, NULL); - if (result != 0) - { - goto FAIL0; - } - - result = pthread_mutex_init (&rwl->mtxSharedAccessCompleted, NULL); - if (result != 0) - { - goto FAIL1; - } - - result = pthread_cond_init (&rwl->cndSharedAccessCompleted, NULL); - if (result != 0) - { - goto FAIL2; - } - - rwl->nMagic = PTW32_RWLOCK_MAGIC; - - result = 0; - goto DONE; - -FAIL2: - (void) pthread_mutex_destroy (&(rwl->mtxSharedAccessCompleted)); - -FAIL1: - (void) pthread_mutex_destroy (&(rwl->mtxExclusiveAccess)); - -FAIL0: - (void) free (rwl); - rwl = NULL; - -DONE: - *rwlock = rwl; - - return result; -} +/* + * pthread_rwlock_init.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlock_init (pthread_rwlock_t * rwlock, + const pthread_rwlockattr_t * attr) +{ + int result; + pthread_rwlock_t rwl = 0; + + if (rwlock == NULL) + { + return EINVAL; + } + +#ifdef PTW32_STATIC_LIB + // This allos for C++ static initializers to function without crashes. (air) + pthread_win32_process_attach_np(); +#endif + + if (attr != NULL && *attr != NULL) + { + result = EINVAL; /* Not supported */ + goto DONE; + } + + rwl = (pthread_rwlock_t) calloc (1, sizeof (*rwl)); + + if (rwl == NULL) + { + result = ENOMEM; + goto DONE; + } + + rwl->nSharedAccessCount = 0; + rwl->nExclusiveAccessCount = 0; + rwl->nCompletedSharedAccessCount = 0; + + result = pthread_mutex_init (&rwl->mtxExclusiveAccess, NULL); + if (result != 0) + { + goto FAIL0; + } + + result = pthread_mutex_init (&rwl->mtxSharedAccessCompleted, NULL); + if (result != 0) + { + goto FAIL1; + } + + result = pthread_cond_init (&rwl->cndSharedAccessCompleted, NULL); + if (result != 0) + { + goto FAIL2; + } + + rwl->nMagic = PTW32_RWLOCK_MAGIC; + + result = 0; + goto DONE; + +FAIL2: + (void) pthread_mutex_destroy (&(rwl->mtxSharedAccessCompleted)); + +FAIL1: + (void) pthread_mutex_destroy (&(rwl->mtxExclusiveAccess)); + +FAIL0: + (void) free (rwl); + rwl = NULL; + +DONE: + *rwlock = rwl; + + return result; +} diff --git a/pcsx2/windows/pthreads/pthread_rwlock_rdlock.c b/pcsx2/windows/pthreads/pthread_rwlock_rdlock.c index 3c493ea975..dba63ddfb5 100644 --- a/pcsx2/windows/pthreads/pthread_rwlock_rdlock.c +++ b/pcsx2/windows/pthreads/pthread_rwlock_rdlock.c @@ -1,103 +1,103 @@ -/* - * pthread_rwlock_rdlock.c - * - * Description: - * This translation unit implements read/write lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include -#include - -#include "pthread.h" -#include "implement.h" - -int -pthread_rwlock_rdlock (pthread_rwlock_t * rwlock) -{ - int result; - pthread_rwlock_t rwl; - - if (rwlock == NULL || *rwlock == NULL) - { - return EINVAL; - } - - /* - * We do a quick check to see if we need to do more work - * to initialise a static rwlock. We check - * again inside the guarded section of ptw32_rwlock_check_need_init() - * to avoid race conditions. - */ - if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) - { - result = ptw32_rwlock_check_need_init (rwlock); - - if (result != 0 && result != EBUSY) - { - return result; - } - } - - rwl = *rwlock; - - if (rwl->nMagic != PTW32_RWLOCK_MAGIC) - { - return EINVAL; - } - - if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0) - { - return result; - } - - if (++rwl->nSharedAccessCount == INT_MAX) - { - if ((result = - pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) - { - (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); - return result; - } - - rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; - rwl->nCompletedSharedAccessCount = 0; - - if ((result = - pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) - { - (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); - return result; - } - } - - return (pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))); -} +/* + * pthread_rwlock_rdlock.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlock_rdlock (pthread_rwlock_t * rwlock) +{ + int result; + pthread_rwlock_t rwl; + + if (rwlock == NULL || *rwlock == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static rwlock. We check + * again inside the guarded section of ptw32_rwlock_check_need_init() + * to avoid race conditions. + */ + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + { + result = ptw32_rwlock_check_need_init (rwlock); + + if (result != 0 && result != EBUSY) + { + return result; + } + } + + rwl = *rwlock; + + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) + { + return EINVAL; + } + + if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0) + { + return result; + } + + if (++rwl->nSharedAccessCount == INT_MAX) + { + if ((result = + pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + + if ((result = + pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + } + + return (pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))); +} diff --git a/pcsx2/windows/pthreads/pthread_rwlock_timedrdlock.c b/pcsx2/windows/pthreads/pthread_rwlock_timedrdlock.c index 92373eaf8f..93489502e1 100644 --- a/pcsx2/windows/pthreads/pthread_rwlock_timedrdlock.c +++ b/pcsx2/windows/pthreads/pthread_rwlock_timedrdlock.c @@ -1,110 +1,110 @@ -/* - * pthread_rwlock_timedrdlock.c - * - * Description: - * This translation unit implements read/write lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include -#include - -#include "pthread.h" -#include "implement.h" - -int -pthread_rwlock_timedrdlock (pthread_rwlock_t * rwlock, - const struct timespec *abstime) -{ - int result; - pthread_rwlock_t rwl; - - if (rwlock == NULL || *rwlock == NULL) - { - return EINVAL; - } - - /* - * We do a quick check to see if we need to do more work - * to initialise a static rwlock. We check - * again inside the guarded section of ptw32_rwlock_check_need_init() - * to avoid race conditions. - */ - if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) - { - result = ptw32_rwlock_check_need_init (rwlock); - - if (result != 0 && result != EBUSY) - { - return result; - } - } - - rwl = *rwlock; - - if (rwl->nMagic != PTW32_RWLOCK_MAGIC) - { - return EINVAL; - } - - if ((result = - pthread_mutex_timedlock (&(rwl->mtxExclusiveAccess), abstime)) != 0) - { - return result; - } - - if (++rwl->nSharedAccessCount == INT_MAX) - { - if ((result = - pthread_mutex_timedlock (&(rwl->mtxSharedAccessCompleted), - abstime)) != 0) - { - if (result == ETIMEDOUT) - { - ++rwl->nCompletedSharedAccessCount; - } - (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); - return result; - } - - rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; - rwl->nCompletedSharedAccessCount = 0; - - if ((result = - pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) - { - (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); - return result; - } - } - - return (pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))); -} +/* + * pthread_rwlock_timedrdlock.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlock_timedrdlock (pthread_rwlock_t * rwlock, + const struct timespec *abstime) +{ + int result; + pthread_rwlock_t rwl; + + if (rwlock == NULL || *rwlock == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static rwlock. We check + * again inside the guarded section of ptw32_rwlock_check_need_init() + * to avoid race conditions. + */ + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + { + result = ptw32_rwlock_check_need_init (rwlock); + + if (result != 0 && result != EBUSY) + { + return result; + } + } + + rwl = *rwlock; + + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) + { + return EINVAL; + } + + if ((result = + pthread_mutex_timedlock (&(rwl->mtxExclusiveAccess), abstime)) != 0) + { + return result; + } + + if (++rwl->nSharedAccessCount == INT_MAX) + { + if ((result = + pthread_mutex_timedlock (&(rwl->mtxSharedAccessCompleted), + abstime)) != 0) + { + if (result == ETIMEDOUT) + { + ++rwl->nCompletedSharedAccessCount; + } + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + + if ((result = + pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + } + + return (pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))); +} diff --git a/pcsx2/windows/pthreads/pthread_rwlock_timedwrlock.c b/pcsx2/windows/pthreads/pthread_rwlock_timedwrlock.c index ca5e53728d..e7d1be2575 100644 --- a/pcsx2/windows/pthreads/pthread_rwlock_timedwrlock.c +++ b/pcsx2/windows/pthreads/pthread_rwlock_timedwrlock.c @@ -1,140 +1,140 @@ -/* - * pthread_rwlock_timedwrlock.c - * - * Description: - * This translation unit implements read/write lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include -#include - -#include "pthread.h" -#include "implement.h" - -int -pthread_rwlock_timedwrlock (pthread_rwlock_t * rwlock, - const struct timespec *abstime) -{ - int result; - pthread_rwlock_t rwl; - - if (rwlock == NULL || *rwlock == NULL) - { - return EINVAL; - } - - /* - * We do a quick check to see if we need to do more work - * to initialise a static rwlock. We check - * again inside the guarded section of ptw32_rwlock_check_need_init() - * to avoid race conditions. - */ - if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) - { - result = ptw32_rwlock_check_need_init (rwlock); - - if (result != 0 && result != EBUSY) - { - return result; - } - } - - rwl = *rwlock; - - if (rwl->nMagic != PTW32_RWLOCK_MAGIC) - { - return EINVAL; - } - - if ((result = - pthread_mutex_timedlock (&(rwl->mtxExclusiveAccess), abstime)) != 0) - { - return result; - } - - if ((result = - pthread_mutex_timedlock (&(rwl->mtxSharedAccessCompleted), - abstime)) != 0) - { - (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); - return result; - } - - if (rwl->nExclusiveAccessCount == 0) - { - if (rwl->nCompletedSharedAccessCount > 0) - { - rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; - rwl->nCompletedSharedAccessCount = 0; - } - - if (rwl->nSharedAccessCount > 0) - { - rwl->nCompletedSharedAccessCount = -rwl->nSharedAccessCount; - - /* - * This routine may be a cancelation point - * according to POSIX 1003.1j section 18.1.2. - */ -#ifdef _MSC_VER -#pragma inline_depth(0) -#endif - pthread_cleanup_push (ptw32_rwlock_cancelwrwait, (void *) rwl); - - do - { - result = - pthread_cond_timedwait (&(rwl->cndSharedAccessCompleted), - &(rwl->mtxSharedAccessCompleted), - abstime); - } - while (result == 0 && rwl->nCompletedSharedAccessCount < 0); - - pthread_cleanup_pop ((result != 0) ? 1 : 0); -#ifdef _MSC_VER -#pragma inline_depth() -#endif - - if (result == 0) - { - rwl->nSharedAccessCount = 0; - } - } - } - - if (result == 0) - { - rwl->nExclusiveAccessCount++; - } - - return result; -} +/* + * pthread_rwlock_timedwrlock.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlock_timedwrlock (pthread_rwlock_t * rwlock, + const struct timespec *abstime) +{ + int result; + pthread_rwlock_t rwl; + + if (rwlock == NULL || *rwlock == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static rwlock. We check + * again inside the guarded section of ptw32_rwlock_check_need_init() + * to avoid race conditions. + */ + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + { + result = ptw32_rwlock_check_need_init (rwlock); + + if (result != 0 && result != EBUSY) + { + return result; + } + } + + rwl = *rwlock; + + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) + { + return EINVAL; + } + + if ((result = + pthread_mutex_timedlock (&(rwl->mtxExclusiveAccess), abstime)) != 0) + { + return result; + } + + if ((result = + pthread_mutex_timedlock (&(rwl->mtxSharedAccessCompleted), + abstime)) != 0) + { + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + + if (rwl->nExclusiveAccessCount == 0) + { + if (rwl->nCompletedSharedAccessCount > 0) + { + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + } + + if (rwl->nSharedAccessCount > 0) + { + rwl->nCompletedSharedAccessCount = -rwl->nSharedAccessCount; + + /* + * This routine may be a cancelation point + * according to POSIX 1003.1j section 18.1.2. + */ +#ifdef _MSC_VER +#pragma inline_depth(0) +#endif + pthread_cleanup_push (ptw32_rwlock_cancelwrwait, (void *) rwl); + + do + { + result = + pthread_cond_timedwait (&(rwl->cndSharedAccessCompleted), + &(rwl->mtxSharedAccessCompleted), + abstime); + } + while (result == 0 && rwl->nCompletedSharedAccessCount < 0); + + pthread_cleanup_pop ((result != 0) ? 1 : 0); +#ifdef _MSC_VER +#pragma inline_depth() +#endif + + if (result == 0) + { + rwl->nSharedAccessCount = 0; + } + } + } + + if (result == 0) + { + rwl->nExclusiveAccessCount++; + } + + return result; +} diff --git a/pcsx2/windows/pthreads/pthread_rwlock_tryrdlock.c b/pcsx2/windows/pthreads/pthread_rwlock_tryrdlock.c index fbca91043d..308900d141 100644 --- a/pcsx2/windows/pthreads/pthread_rwlock_tryrdlock.c +++ b/pcsx2/windows/pthreads/pthread_rwlock_tryrdlock.c @@ -1,103 +1,103 @@ -/* - * pthread_rwlock_tryrdlock.c - * - * Description: - * This translation unit implements read/write lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include -#include - -#include "pthread.h" -#include "implement.h" - -int -pthread_rwlock_tryrdlock (pthread_rwlock_t * rwlock) -{ - int result; - pthread_rwlock_t rwl; - - if (rwlock == NULL || *rwlock == NULL) - { - return EINVAL; - } - - /* - * We do a quick check to see if we need to do more work - * to initialise a static rwlock. We check - * again inside the guarded section of ptw32_rwlock_check_need_init() - * to avoid race conditions. - */ - if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) - { - result = ptw32_rwlock_check_need_init (rwlock); - - if (result != 0 && result != EBUSY) - { - return result; - } - } - - rwl = *rwlock; - - if (rwl->nMagic != PTW32_RWLOCK_MAGIC) - { - return EINVAL; - } - - if ((result = pthread_mutex_trylock (&(rwl->mtxExclusiveAccess))) != 0) - { - return result; - } - - if (++rwl->nSharedAccessCount == INT_MAX) - { - if ((result = - pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) - { - (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); - return result; - } - - rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; - rwl->nCompletedSharedAccessCount = 0; - - if ((result = - pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) - { - (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); - return result; - } - } - - return (pthread_mutex_unlock (&rwl->mtxExclusiveAccess)); -} +/* + * pthread_rwlock_tryrdlock.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlock_tryrdlock (pthread_rwlock_t * rwlock) +{ + int result; + pthread_rwlock_t rwl; + + if (rwlock == NULL || *rwlock == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static rwlock. We check + * again inside the guarded section of ptw32_rwlock_check_need_init() + * to avoid race conditions. + */ + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + { + result = ptw32_rwlock_check_need_init (rwlock); + + if (result != 0 && result != EBUSY) + { + return result; + } + } + + rwl = *rwlock; + + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) + { + return EINVAL; + } + + if ((result = pthread_mutex_trylock (&(rwl->mtxExclusiveAccess))) != 0) + { + return result; + } + + if (++rwl->nSharedAccessCount == INT_MAX) + { + if ((result = + pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + + if ((result = + pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + } + + return (pthread_mutex_unlock (&rwl->mtxExclusiveAccess)); +} diff --git a/pcsx2/windows/pthreads/pthread_rwlock_trywrlock.c b/pcsx2/windows/pthreads/pthread_rwlock_trywrlock.c index e17adb38c3..8ba8b5dad9 100644 --- a/pcsx2/windows/pthreads/pthread_rwlock_trywrlock.c +++ b/pcsx2/windows/pthreads/pthread_rwlock_trywrlock.c @@ -1,123 +1,123 @@ -/* - * pthread_rwlock_trywrlock.c - * - * Description: - * This translation unit implements read/write lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include -#include - -#include "pthread.h" -#include "implement.h" - -int -pthread_rwlock_trywrlock (pthread_rwlock_t * rwlock) -{ - int result, result1; - pthread_rwlock_t rwl; - - if (rwlock == NULL || *rwlock == NULL) - { - return EINVAL; - } - - /* - * We do a quick check to see if we need to do more work - * to initialise a static rwlock. We check - * again inside the guarded section of ptw32_rwlock_check_need_init() - * to avoid race conditions. - */ - if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) - { - result = ptw32_rwlock_check_need_init (rwlock); - - if (result != 0 && result != EBUSY) - { - return result; - } - } - - rwl = *rwlock; - - if (rwl->nMagic != PTW32_RWLOCK_MAGIC) - { - return EINVAL; - } - - if ((result = pthread_mutex_trylock (&(rwl->mtxExclusiveAccess))) != 0) - { - return result; - } - - if ((result = - pthread_mutex_trylock (&(rwl->mtxSharedAccessCompleted))) != 0) - { - result1 = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); - return ((result1 != 0) ? result1 : result); - } - - if (rwl->nExclusiveAccessCount == 0) - { - if (rwl->nCompletedSharedAccessCount > 0) - { - rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; - rwl->nCompletedSharedAccessCount = 0; - } - - if (rwl->nSharedAccessCount > 0) - { - if ((result = - pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) - { - (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); - return result; - } - - if ((result = - pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))) == 0) - { - result = EBUSY; - } - } - else - { - rwl->nExclusiveAccessCount = 1; - } - } - else - { - result = EBUSY; - } - - return result; -} +/* + * pthread_rwlock_trywrlock.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlock_trywrlock (pthread_rwlock_t * rwlock) +{ + int result, result1; + pthread_rwlock_t rwl; + + if (rwlock == NULL || *rwlock == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static rwlock. We check + * again inside the guarded section of ptw32_rwlock_check_need_init() + * to avoid race conditions. + */ + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + { + result = ptw32_rwlock_check_need_init (rwlock); + + if (result != 0 && result != EBUSY) + { + return result; + } + } + + rwl = *rwlock; + + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) + { + return EINVAL; + } + + if ((result = pthread_mutex_trylock (&(rwl->mtxExclusiveAccess))) != 0) + { + return result; + } + + if ((result = + pthread_mutex_trylock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + result1 = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return ((result1 != 0) ? result1 : result); + } + + if (rwl->nExclusiveAccessCount == 0) + { + if (rwl->nCompletedSharedAccessCount > 0) + { + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + } + + if (rwl->nSharedAccessCount > 0) + { + if ((result = + pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + + if ((result = + pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))) == 0) + { + result = EBUSY; + } + } + else + { + rwl->nExclusiveAccessCount = 1; + } + } + else + { + result = EBUSY; + } + + return result; +} diff --git a/pcsx2/windows/pthreads/pthread_rwlock_unlock.c b/pcsx2/windows/pthreads/pthread_rwlock_unlock.c index 2a5c84b892..776c996fea 100644 --- a/pcsx2/windows/pthreads/pthread_rwlock_unlock.c +++ b/pcsx2/windows/pthreads/pthread_rwlock_unlock.c @@ -1,94 +1,94 @@ -/* - * pthread_rwlock_unlock.c - * - * Description: - * This translation unit implements read/write lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include -#include - -#include "pthread.h" -#include "implement.h" - -int -pthread_rwlock_unlock (pthread_rwlock_t * rwlock) -{ - int result, result1; - pthread_rwlock_t rwl; - - if (rwlock == NULL || *rwlock == NULL) - { - return (EINVAL); - } - - if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) - { - /* - * Assume any race condition here is harmless. - */ - return 0; - } - - rwl = *rwlock; - - if (rwl->nMagic != PTW32_RWLOCK_MAGIC) - { - return EINVAL; - } - - if (rwl->nExclusiveAccessCount == 0) - { - if ((result = - pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) - { - return result; - } - - if (++rwl->nCompletedSharedAccessCount == 0) - { - result = pthread_cond_signal (&(rwl->cndSharedAccessCompleted)); - } - - result1 = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted)); - } - else - { - rwl->nExclusiveAccessCount--; - - result = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted)); - result1 = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); - - } - - return ((result != 0) ? result : result1); -} +/* + * pthread_rwlock_unlock.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlock_unlock (pthread_rwlock_t * rwlock) +{ + int result, result1; + pthread_rwlock_t rwl; + + if (rwlock == NULL || *rwlock == NULL) + { + return (EINVAL); + } + + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + { + /* + * Assume any race condition here is harmless. + */ + return 0; + } + + rwl = *rwlock; + + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) + { + return EINVAL; + } + + if (rwl->nExclusiveAccessCount == 0) + { + if ((result = + pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + return result; + } + + if (++rwl->nCompletedSharedAccessCount == 0) + { + result = pthread_cond_signal (&(rwl->cndSharedAccessCompleted)); + } + + result1 = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted)); + } + else + { + rwl->nExclusiveAccessCount--; + + result = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted)); + result1 = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + + } + + return ((result != 0) ? result : result1); +} diff --git a/pcsx2/windows/pthreads/pthread_rwlock_wrlock.c b/pcsx2/windows/pthreads/pthread_rwlock_wrlock.c index 789c5aa00e..a097040441 100644 --- a/pcsx2/windows/pthreads/pthread_rwlock_wrlock.c +++ b/pcsx2/windows/pthreads/pthread_rwlock_wrlock.c @@ -1,134 +1,134 @@ -/* - * pthread_rwlock_wrlock.c - * - * Description: - * This translation unit implements read/write lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include -#include - -#include "pthread.h" -#include "implement.h" - -int -pthread_rwlock_wrlock (pthread_rwlock_t * rwlock) -{ - int result; - pthread_rwlock_t rwl; - - if (rwlock == NULL || *rwlock == NULL) - { - return EINVAL; - } - - /* - * We do a quick check to see if we need to do more work - * to initialise a static rwlock. We check - * again inside the guarded section of ptw32_rwlock_check_need_init() - * to avoid race conditions. - */ - if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) - { - result = ptw32_rwlock_check_need_init (rwlock); - - if (result != 0 && result != EBUSY) - { - return result; - } - } - - rwl = *rwlock; - - if (rwl->nMagic != PTW32_RWLOCK_MAGIC) - { - return EINVAL; - } - - if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0) - { - return result; - } - - if ((result = pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) - { - (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); - return result; - } - - if (rwl->nExclusiveAccessCount == 0) - { - if (rwl->nCompletedSharedAccessCount > 0) - { - rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; - rwl->nCompletedSharedAccessCount = 0; - } - - if (rwl->nSharedAccessCount > 0) - { - rwl->nCompletedSharedAccessCount = -rwl->nSharedAccessCount; - - /* - * This routine may be a cancelation point - * according to POSIX 1003.1j section 18.1.2. - */ -#ifdef _MSC_VER -#pragma inline_depth(0) -#endif - pthread_cleanup_push (ptw32_rwlock_cancelwrwait, (void *) rwl); - - do - { - result = pthread_cond_wait (&(rwl->cndSharedAccessCompleted), - &(rwl->mtxSharedAccessCompleted)); - } - while (result == 0 && rwl->nCompletedSharedAccessCount < 0); - - pthread_cleanup_pop ((result != 0) ? 1 : 0); -#ifdef _MSC_VER -#pragma inline_depth() -#endif - - if (result == 0) - { - rwl->nSharedAccessCount = 0; - } - } - } - - if (result == 0) - { - rwl->nExclusiveAccessCount++; - } - - return result; -} +/* + * pthread_rwlock_wrlock.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlock_wrlock (pthread_rwlock_t * rwlock) +{ + int result; + pthread_rwlock_t rwl; + + if (rwlock == NULL || *rwlock == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static rwlock. We check + * again inside the guarded section of ptw32_rwlock_check_need_init() + * to avoid race conditions. + */ + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + { + result = ptw32_rwlock_check_need_init (rwlock); + + if (result != 0 && result != EBUSY) + { + return result; + } + } + + rwl = *rwlock; + + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) + { + return EINVAL; + } + + if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0) + { + return result; + } + + if ((result = pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + + if (rwl->nExclusiveAccessCount == 0) + { + if (rwl->nCompletedSharedAccessCount > 0) + { + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + } + + if (rwl->nSharedAccessCount > 0) + { + rwl->nCompletedSharedAccessCount = -rwl->nSharedAccessCount; + + /* + * This routine may be a cancelation point + * according to POSIX 1003.1j section 18.1.2. + */ +#ifdef _MSC_VER +#pragma inline_depth(0) +#endif + pthread_cleanup_push (ptw32_rwlock_cancelwrwait, (void *) rwl); + + do + { + result = pthread_cond_wait (&(rwl->cndSharedAccessCompleted), + &(rwl->mtxSharedAccessCompleted)); + } + while (result == 0 && rwl->nCompletedSharedAccessCount < 0); + + pthread_cleanup_pop ((result != 0) ? 1 : 0); +#ifdef _MSC_VER +#pragma inline_depth() +#endif + + if (result == 0) + { + rwl->nSharedAccessCount = 0; + } + } + } + + if (result == 0) + { + rwl->nExclusiveAccessCount++; + } + + return result; +} diff --git a/pcsx2/windows/pthreads/pthread_rwlockattr_destroy.c b/pcsx2/windows/pthreads/pthread_rwlockattr_destroy.c index c1971b5a15..0fcbe84053 100644 --- a/pcsx2/windows/pthreads/pthread_rwlockattr_destroy.c +++ b/pcsx2/windows/pthreads/pthread_rwlockattr_destroy.c @@ -1,85 +1,85 @@ -/* - * pthread_rwlockattr_destroy.c - * - * Description: - * This translation unit implements read/write lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include -#include - -#include "pthread.h" -#include "implement.h" - -int -pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Destroys a rwlock attributes object. The object can - * no longer be used. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_rwlockattr_t - * - * - * DESCRIPTION - * Destroys a rwlock attributes object. The object can - * no longer be used. - * - * NOTES: - * 1) Does not affect rwlockss created using 'attr' - * - * RESULTS - * 0 successfully released attr, - * EINVAL 'attr' is invalid. - * - * ------------------------------------------------------ - */ -{ - int result = 0; - - if (attr == NULL || *attr == NULL) - { - result = EINVAL; - } - else - { - pthread_rwlockattr_t rwa = *attr; - - *attr = NULL; - free (rwa); - } - - return (result); -} /* pthread_rwlockattr_destroy */ +/* + * pthread_rwlockattr_destroy.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Destroys a rwlock attributes object. The object can + * no longer be used. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_rwlockattr_t + * + * + * DESCRIPTION + * Destroys a rwlock attributes object. The object can + * no longer be used. + * + * NOTES: + * 1) Does not affect rwlockss created using 'attr' + * + * RESULTS + * 0 successfully released attr, + * EINVAL 'attr' is invalid. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + + if (attr == NULL || *attr == NULL) + { + result = EINVAL; + } + else + { + pthread_rwlockattr_t rwa = *attr; + + *attr = NULL; + free (rwa); + } + + return (result); +} /* pthread_rwlockattr_destroy */ diff --git a/pcsx2/windows/pthreads/pthread_rwlockattr_getpshared.c b/pcsx2/windows/pthreads/pthread_rwlockattr_getpshared.c index 098e925436..abfe63f257 100644 --- a/pcsx2/windows/pthreads/pthread_rwlockattr_getpshared.c +++ b/pcsx2/windows/pthreads/pthread_rwlockattr_getpshared.c @@ -1,98 +1,98 @@ -/* - * pthread_rwlockattr_getpshared.c - * - * Description: - * This translation unit implements read/write lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include -#include - -#include "pthread.h" -#include "implement.h" - -int -pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, - int *pshared) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Determine whether rwlocks created with 'attr' can be - * shared between processes. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_rwlockattr_t - * - * pshared - * will be set to one of: - * - * PTHREAD_PROCESS_SHARED - * May be shared if in shared memory - * - * PTHREAD_PROCESS_PRIVATE - * Cannot be shared. - * - * - * DESCRIPTION - * Rwlocks creatd with 'attr' can be shared between - * processes if pthread_rwlock_t variable is allocated - * in memory shared by these processes. - * NOTES: - * 1) pshared rwlocks MUST be allocated in shared - * memory. - * 2) The following macro is defined if shared rwlocks - * are supported: - * _POSIX_THREAD_PROCESS_SHARED - * - * RESULTS - * 0 successfully retrieved attribute, - * EINVAL 'attr' is invalid, - * - * ------------------------------------------------------ - */ -{ - int result; - - if ((attr != NULL && *attr != NULL) && (pshared != NULL)) - { - *pshared = (*attr)->pshared; - result = 0; - } - else - { - result = EINVAL; - } - - return (result); - -} /* pthread_rwlockattr_getpshared */ +/* + * pthread_rwlockattr_getpshared.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, + int *pshared) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Determine whether rwlocks created with 'attr' can be + * shared between processes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_rwlockattr_t + * + * pshared + * will be set to one of: + * + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory + * + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. + * + * + * DESCRIPTION + * Rwlocks creatd with 'attr' can be shared between + * processes if pthread_rwlock_t variable is allocated + * in memory shared by these processes. + * NOTES: + * 1) pshared rwlocks MUST be allocated in shared + * memory. + * 2) The following macro is defined if shared rwlocks + * are supported: + * _POSIX_THREAD_PROCESS_SHARED + * + * RESULTS + * 0 successfully retrieved attribute, + * EINVAL 'attr' is invalid, + * + * ------------------------------------------------------ + */ +{ + int result; + + if ((attr != NULL && *attr != NULL) && (pshared != NULL)) + { + *pshared = (*attr)->pshared; + result = 0; + } + else + { + result = EINVAL; + } + + return (result); + +} /* pthread_rwlockattr_getpshared */ diff --git a/pcsx2/windows/pthreads/pthread_rwlockattr_init.c b/pcsx2/windows/pthreads/pthread_rwlockattr_init.c index 31261185c5..feb8e94073 100644 --- a/pcsx2/windows/pthreads/pthread_rwlockattr_init.c +++ b/pcsx2/windows/pthreads/pthread_rwlockattr_init.c @@ -1,84 +1,84 @@ -/* - * pthread_rwlockattr_init.c - * - * Description: - * This translation unit implements read/write lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include -#include - -#include "pthread.h" -#include "implement.h" - -int -pthread_rwlockattr_init (pthread_rwlockattr_t * attr) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Initializes a rwlock attributes object with default - * attributes. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_rwlockattr_t - * - * - * DESCRIPTION - * Initializes a rwlock attributes object with default - * attributes. - * - * RESULTS - * 0 successfully initialized attr, - * ENOMEM insufficient memory for attr. - * - * ------------------------------------------------------ - */ -{ - int result = 0; - pthread_rwlockattr_t rwa; - - rwa = (pthread_rwlockattr_t) calloc (1, sizeof (*rwa)); - - if (rwa == NULL) - { - result = ENOMEM; - } - else - { - rwa->pshared = PTHREAD_PROCESS_PRIVATE; - } - - *attr = rwa; - - return (result); -} /* pthread_rwlockattr_init */ +/* + * pthread_rwlockattr_init.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlockattr_init (pthread_rwlockattr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Initializes a rwlock attributes object with default + * attributes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_rwlockattr_t + * + * + * DESCRIPTION + * Initializes a rwlock attributes object with default + * attributes. + * + * RESULTS + * 0 successfully initialized attr, + * ENOMEM insufficient memory for attr. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + pthread_rwlockattr_t rwa; + + rwa = (pthread_rwlockattr_t) calloc (1, sizeof (*rwa)); + + if (rwa == NULL) + { + result = ENOMEM; + } + else + { + rwa->pshared = PTHREAD_PROCESS_PRIVATE; + } + + *attr = rwa; + + return (result); +} /* pthread_rwlockattr_init */ diff --git a/pcsx2/windows/pthreads/pthread_rwlockattr_setpshared.c b/pcsx2/windows/pthreads/pthread_rwlockattr_setpshared.c index b0c8160b13..316532cb26 100644 --- a/pcsx2/windows/pthreads/pthread_rwlockattr_setpshared.c +++ b/pcsx2/windows/pthreads/pthread_rwlockattr_setpshared.c @@ -1,121 +1,121 @@ -/* - * pthread_rwlockattr_setpshared.c - * - * Description: - * This translation unit implements read/write lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include -#include - -#include "pthread.h" -#include "implement.h" - -int -pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, int pshared) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Rwlocks created with 'attr' can be shared between - * processes if pthread_rwlock_t variable is allocated - * in memory shared by these processes. - * - * PARAMETERS - * attr - * pointer to an instance of pthread_rwlockattr_t - * - * pshared - * must be one of: - * - * PTHREAD_PROCESS_SHARED - * May be shared if in shared memory - * - * PTHREAD_PROCESS_PRIVATE - * Cannot be shared. - * - * DESCRIPTION - * Rwlocks creatd with 'attr' can be shared between - * processes if pthread_rwlock_t variable is allocated - * in memory shared by these processes. - * - * NOTES: - * 1) pshared rwlocks MUST be allocated in shared - * memory. - * - * 2) The following macro is defined if shared rwlocks - * are supported: - * _POSIX_THREAD_PROCESS_SHARED - * - * RESULTS - * 0 successfully set attribute, - * EINVAL 'attr' or pshared is invalid, - * ENOSYS PTHREAD_PROCESS_SHARED not supported, - * - * ------------------------------------------------------ - */ -{ - int result; - - if ((attr != NULL && *attr != NULL) && - ((pshared == PTHREAD_PROCESS_SHARED) || - (pshared == PTHREAD_PROCESS_PRIVATE))) - { - if (pshared == PTHREAD_PROCESS_SHARED) - { - -#if !defined( _POSIX_THREAD_PROCESS_SHARED ) - - result = ENOSYS; - pshared = PTHREAD_PROCESS_PRIVATE; - -#else - - result = 0; - -#endif /* _POSIX_THREAD_PROCESS_SHARED */ - - } - else - { - result = 0; - } - - (*attr)->pshared = pshared; - } - else - { - result = EINVAL; - } - - return (result); - -} /* pthread_rwlockattr_setpshared */ +/* + * pthread_rwlockattr_setpshared.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, int pshared) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Rwlocks created with 'attr' can be shared between + * processes if pthread_rwlock_t variable is allocated + * in memory shared by these processes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_rwlockattr_t + * + * pshared + * must be one of: + * + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory + * + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. + * + * DESCRIPTION + * Rwlocks creatd with 'attr' can be shared between + * processes if pthread_rwlock_t variable is allocated + * in memory shared by these processes. + * + * NOTES: + * 1) pshared rwlocks MUST be allocated in shared + * memory. + * + * 2) The following macro is defined if shared rwlocks + * are supported: + * _POSIX_THREAD_PROCESS_SHARED + * + * RESULTS + * 0 successfully set attribute, + * EINVAL 'attr' or pshared is invalid, + * ENOSYS PTHREAD_PROCESS_SHARED not supported, + * + * ------------------------------------------------------ + */ +{ + int result; + + if ((attr != NULL && *attr != NULL) && + ((pshared == PTHREAD_PROCESS_SHARED) || + (pshared == PTHREAD_PROCESS_PRIVATE))) + { + if (pshared == PTHREAD_PROCESS_SHARED) + { + +#if !defined( _POSIX_THREAD_PROCESS_SHARED ) + + result = ENOSYS; + pshared = PTHREAD_PROCESS_PRIVATE; + +#else + + result = 0; + +#endif /* _POSIX_THREAD_PROCESS_SHARED */ + + } + else + { + result = 0; + } + + (*attr)->pshared = pshared; + } + else + { + result = EINVAL; + } + + return (result); + +} /* pthread_rwlockattr_setpshared */ diff --git a/pcsx2/windows/pthreads/pthread_self.c b/pcsx2/windows/pthreads/pthread_self.c index fb2899cdac..d72a0971d0 100644 --- a/pcsx2/windows/pthreads/pthread_self.c +++ b/pcsx2/windows/pthreads/pthread_self.c @@ -1,138 +1,138 @@ -/* - * pthread_self.c - * - * Description: - * This translation unit implements miscellaneous thread functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -pthread_t -pthread_self (void) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function returns a reference to the current running - * thread. - * - * PARAMETERS - * N/A - * - * - * DESCRIPTION - * This function returns a reference to the current running - * thread. - * - * RESULTS - * pthread_t reference to the current thread - * - * ------------------------------------------------------ - */ -{ - pthread_t self; - pthread_t nil = {NULL, 0}; - ptw32_thread_t * sp; - -#ifdef _UWIN - if (!ptw32_selfThreadKey) - return nil; -#endif - - sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); - - if (sp != NULL) - { - self = sp->ptHandle; - } - else - { - /* - * Need to create an implicit 'self' for the currently - * executing thread. - */ - self = ptw32_new (); - sp = (ptw32_thread_t *) self.p; - - if (sp != NULL) - { - /* - * This is a non-POSIX thread which has chosen to call - * a POSIX threads function for some reason. We assume that - * it isn't joinable, but we do assume that it's - * (deferred) cancelable. - */ - sp->implicit = 1; - sp->detachState = PTHREAD_CREATE_DETACHED; - sp->thread = GetCurrentThreadId (); - -#ifdef NEED_DUPLICATEHANDLE - /* - * DuplicateHandle does not exist on WinCE. - * - * NOTE: - * GetCurrentThread only returns a pseudo-handle - * which is only valid in the current thread context. - * Therefore, you should not pass the handle to - * other threads for whatever purpose. - */ - sp->threadH = GetCurrentThread (); -#else - if (!DuplicateHandle (GetCurrentProcess (), - GetCurrentThread (), - GetCurrentProcess (), - &sp->threadH, - 0, FALSE, DUPLICATE_SAME_ACCESS)) - { - /* - * Should not do this, but we have no alternative if - * we can't get a Win32 thread handle. - * Thread structs are never freed. - */ - ptw32_threadReusePush (self); - return nil; - } -#endif - - /* - * No need to explicitly serialise access to sched_priority - * because the new handle is not yet public. - */ - sp->sched_priority = GetThreadPriority (sp->threadH); - - pthread_setspecific (ptw32_selfThreadKey, (void *) sp); - } - } - - return (self); - -} /* pthread_self */ +/* + * pthread_self.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +pthread_t +pthread_self (void) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function returns a reference to the current running + * thread. + * + * PARAMETERS + * N/A + * + * + * DESCRIPTION + * This function returns a reference to the current running + * thread. + * + * RESULTS + * pthread_t reference to the current thread + * + * ------------------------------------------------------ + */ +{ + pthread_t self; + pthread_t nil = {NULL, 0}; + ptw32_thread_t * sp; + +#ifdef _UWIN + if (!ptw32_selfThreadKey) + return nil; +#endif + + sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); + + if (sp != NULL) + { + self = sp->ptHandle; + } + else + { + /* + * Need to create an implicit 'self' for the currently + * executing thread. + */ + self = ptw32_new (); + sp = (ptw32_thread_t *) self.p; + + if (sp != NULL) + { + /* + * This is a non-POSIX thread which has chosen to call + * a POSIX threads function for some reason. We assume that + * it isn't joinable, but we do assume that it's + * (deferred) cancelable. + */ + sp->implicit = 1; + sp->detachState = PTHREAD_CREATE_DETACHED; + sp->thread = GetCurrentThreadId (); + +#ifdef NEED_DUPLICATEHANDLE + /* + * DuplicateHandle does not exist on WinCE. + * + * NOTE: + * GetCurrentThread only returns a pseudo-handle + * which is only valid in the current thread context. + * Therefore, you should not pass the handle to + * other threads for whatever purpose. + */ + sp->threadH = GetCurrentThread (); +#else + if (!DuplicateHandle (GetCurrentProcess (), + GetCurrentThread (), + GetCurrentProcess (), + &sp->threadH, + 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + /* + * Should not do this, but we have no alternative if + * we can't get a Win32 thread handle. + * Thread structs are never freed. + */ + ptw32_threadReusePush (self); + return nil; + } +#endif + + /* + * No need to explicitly serialise access to sched_priority + * because the new handle is not yet public. + */ + sp->sched_priority = GetThreadPriority (sp->threadH); + + pthread_setspecific (ptw32_selfThreadKey, (void *) sp); + } + } + + return (self); + +} /* pthread_self */ diff --git a/pcsx2/windows/pthreads/pthread_setcancelstate.c b/pcsx2/windows/pthreads/pthread_setcancelstate.c index d3efaae082..002cfe5e42 100644 --- a/pcsx2/windows/pthreads/pthread_setcancelstate.c +++ b/pcsx2/windows/pthreads/pthread_setcancelstate.c @@ -1,124 +1,124 @@ -/* - * pthread_setcancelstate.c - * - * Description: - * POSIX thread functions related to thread cancellation. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_setcancelstate (int state, int *oldstate) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function atomically sets the calling thread's - * cancelability state to 'state' and returns the previous - * cancelability state at the location referenced by - * 'oldstate' - * - * PARAMETERS - * state, - * oldstate - * PTHREAD_CANCEL_ENABLE - * cancellation is enabled, - * - * PTHREAD_CANCEL_DISABLE - * cancellation is disabled - * - * - * DESCRIPTION - * This function atomically sets the calling thread's - * cancelability state to 'state' and returns the previous - * cancelability state at the location referenced by - * 'oldstate'. - * - * NOTES: - * 1) Use to disable cancellation around 'atomic' code that - * includes cancellation points - * - * COMPATIBILITY ADDITIONS - * If 'oldstate' is NULL then the previous state is not returned - * but the function still succeeds. (Solaris) - * - * RESULTS - * 0 successfully set cancelability type, - * EINVAL 'state' is invalid - * - * ------------------------------------------------------ - */ -{ - int result = 0; - pthread_t self = pthread_self (); - ptw32_thread_t * sp = (ptw32_thread_t *) self.p; - - if (sp == NULL - || (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE)) - { - return EINVAL; - } - - /* - * Lock for async-cancel safety. - */ - (void) pthread_mutex_lock (&sp->cancelLock); - - if (oldstate != NULL) - { - *oldstate = sp->cancelState; - } - - sp->cancelState = state; - - /* - * Check if there is a pending asynchronous cancel - */ - if (state == PTHREAD_CANCEL_ENABLE - && sp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS - && WaitForSingleObject (sp->cancelEvent, 0) == WAIT_OBJECT_0) - { - sp->state = PThreadStateCanceling; - sp->cancelState = PTHREAD_CANCEL_DISABLE; - ResetEvent (sp->cancelEvent); - (void) pthread_mutex_unlock (&sp->cancelLock); - ptw32_throw (PTW32_EPS_CANCEL); - - /* Never reached */ - } - - (void) pthread_mutex_unlock (&sp->cancelLock); - - return (result); - -} /* pthread_setcancelstate */ +/* + * pthread_setcancelstate.c + * + * Description: + * POSIX thread functions related to thread cancellation. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_setcancelstate (int state, int *oldstate) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function atomically sets the calling thread's + * cancelability state to 'state' and returns the previous + * cancelability state at the location referenced by + * 'oldstate' + * + * PARAMETERS + * state, + * oldstate + * PTHREAD_CANCEL_ENABLE + * cancellation is enabled, + * + * PTHREAD_CANCEL_DISABLE + * cancellation is disabled + * + * + * DESCRIPTION + * This function atomically sets the calling thread's + * cancelability state to 'state' and returns the previous + * cancelability state at the location referenced by + * 'oldstate'. + * + * NOTES: + * 1) Use to disable cancellation around 'atomic' code that + * includes cancellation points + * + * COMPATIBILITY ADDITIONS + * If 'oldstate' is NULL then the previous state is not returned + * but the function still succeeds. (Solaris) + * + * RESULTS + * 0 successfully set cancelability type, + * EINVAL 'state' is invalid + * + * ------------------------------------------------------ + */ +{ + int result = 0; + pthread_t self = pthread_self (); + ptw32_thread_t * sp = (ptw32_thread_t *) self.p; + + if (sp == NULL + || (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE)) + { + return EINVAL; + } + + /* + * Lock for async-cancel safety. + */ + (void) pthread_mutex_lock (&sp->cancelLock); + + if (oldstate != NULL) + { + *oldstate = sp->cancelState; + } + + sp->cancelState = state; + + /* + * Check if there is a pending asynchronous cancel + */ + if (state == PTHREAD_CANCEL_ENABLE + && sp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS + && WaitForSingleObject (sp->cancelEvent, 0) == WAIT_OBJECT_0) + { + sp->state = PThreadStateCanceling; + sp->cancelState = PTHREAD_CANCEL_DISABLE; + ResetEvent (sp->cancelEvent); + (void) pthread_mutex_unlock (&sp->cancelLock); + ptw32_throw (PTW32_EPS_CANCEL); + + /* Never reached */ + } + + (void) pthread_mutex_unlock (&sp->cancelLock); + + return (result); + +} /* pthread_setcancelstate */ diff --git a/pcsx2/windows/pthreads/pthread_setcanceltype.c b/pcsx2/windows/pthreads/pthread_setcanceltype.c index 558ddc43e5..3fb3f0e49b 100644 --- a/pcsx2/windows/pthreads/pthread_setcanceltype.c +++ b/pcsx2/windows/pthreads/pthread_setcanceltype.c @@ -1,125 +1,125 @@ -/* - * pthread_setcanceltype.c - * - * Description: - * POSIX thread functions related to thread cancellation. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_setcanceltype (int type, int *oldtype) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function atomically sets the calling thread's - * cancelability type to 'type' and returns the previous - * cancelability type at the location referenced by - * 'oldtype' - * - * PARAMETERS - * type, - * oldtype - * PTHREAD_CANCEL_DEFERRED - * only deferred cancelation is allowed, - * - * PTHREAD_CANCEL_ASYNCHRONOUS - * Asynchronous cancellation is allowed - * - * - * DESCRIPTION - * This function atomically sets the calling thread's - * cancelability type to 'type' and returns the previous - * cancelability type at the location referenced by - * 'oldtype' - * - * NOTES: - * 1) Use with caution; most code is not safe for use - * with asynchronous cancelability. - * - * COMPATIBILITY ADDITIONS - * If 'oldtype' is NULL then the previous type is not returned - * but the function still succeeds. (Solaris) - * - * RESULTS - * 0 successfully set cancelability type, - * EINVAL 'type' is invalid - * - * ------------------------------------------------------ - */ -{ - int result = 0; - pthread_t self = pthread_self (); - ptw32_thread_t * sp = (ptw32_thread_t *) self.p; - - if (sp == NULL - || (type != PTHREAD_CANCEL_DEFERRED - && type != PTHREAD_CANCEL_ASYNCHRONOUS)) - { - return EINVAL; - } - - /* - * Lock for async-cancel safety. - */ - (void) pthread_mutex_lock (&sp->cancelLock); - - if (oldtype != NULL) - { - *oldtype = sp->cancelType; - } - - sp->cancelType = type; - - /* - * Check if there is a pending asynchronous cancel - */ - if (sp->cancelState == PTHREAD_CANCEL_ENABLE - && type == PTHREAD_CANCEL_ASYNCHRONOUS - && WaitForSingleObject (sp->cancelEvent, 0) == WAIT_OBJECT_0) - { - sp->state = PThreadStateCanceling; - sp->cancelState = PTHREAD_CANCEL_DISABLE; - ResetEvent (sp->cancelEvent); - (void) pthread_mutex_unlock (&sp->cancelLock); - ptw32_throw (PTW32_EPS_CANCEL); - - /* Never reached */ - } - - (void) pthread_mutex_unlock (&sp->cancelLock); - - return (result); - -} /* pthread_setcanceltype */ +/* + * pthread_setcanceltype.c + * + * Description: + * POSIX thread functions related to thread cancellation. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_setcanceltype (int type, int *oldtype) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function atomically sets the calling thread's + * cancelability type to 'type' and returns the previous + * cancelability type at the location referenced by + * 'oldtype' + * + * PARAMETERS + * type, + * oldtype + * PTHREAD_CANCEL_DEFERRED + * only deferred cancelation is allowed, + * + * PTHREAD_CANCEL_ASYNCHRONOUS + * Asynchronous cancellation is allowed + * + * + * DESCRIPTION + * This function atomically sets the calling thread's + * cancelability type to 'type' and returns the previous + * cancelability type at the location referenced by + * 'oldtype' + * + * NOTES: + * 1) Use with caution; most code is not safe for use + * with asynchronous cancelability. + * + * COMPATIBILITY ADDITIONS + * If 'oldtype' is NULL then the previous type is not returned + * but the function still succeeds. (Solaris) + * + * RESULTS + * 0 successfully set cancelability type, + * EINVAL 'type' is invalid + * + * ------------------------------------------------------ + */ +{ + int result = 0; + pthread_t self = pthread_self (); + ptw32_thread_t * sp = (ptw32_thread_t *) self.p; + + if (sp == NULL + || (type != PTHREAD_CANCEL_DEFERRED + && type != PTHREAD_CANCEL_ASYNCHRONOUS)) + { + return EINVAL; + } + + /* + * Lock for async-cancel safety. + */ + (void) pthread_mutex_lock (&sp->cancelLock); + + if (oldtype != NULL) + { + *oldtype = sp->cancelType; + } + + sp->cancelType = type; + + /* + * Check if there is a pending asynchronous cancel + */ + if (sp->cancelState == PTHREAD_CANCEL_ENABLE + && type == PTHREAD_CANCEL_ASYNCHRONOUS + && WaitForSingleObject (sp->cancelEvent, 0) == WAIT_OBJECT_0) + { + sp->state = PThreadStateCanceling; + sp->cancelState = PTHREAD_CANCEL_DISABLE; + ResetEvent (sp->cancelEvent); + (void) pthread_mutex_unlock (&sp->cancelLock); + ptw32_throw (PTW32_EPS_CANCEL); + + /* Never reached */ + } + + (void) pthread_mutex_unlock (&sp->cancelLock); + + return (result); + +} /* pthread_setcanceltype */ diff --git a/pcsx2/windows/pthreads/pthread_setconcurrency.c b/pcsx2/windows/pthreads/pthread_setconcurrency.c index b1693da1ff..f62346f8e5 100644 --- a/pcsx2/windows/pthreads/pthread_setconcurrency.c +++ b/pcsx2/windows/pthreads/pthread_setconcurrency.c @@ -1,53 +1,53 @@ -/* - * pthread_setconcurrency.c - * - * Description: - * This translation unit implements miscellaneous thread functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_setconcurrency (int level) -{ - if (level < 0) - { - return EINVAL; - } - else - { - ptw32_concurrency = level; - return 0; - } -} +/* + * pthread_setconcurrency.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_setconcurrency (int level) +{ + if (level < 0) + { + return EINVAL; + } + else + { + ptw32_concurrency = level; + return 0; + } +} diff --git a/pcsx2/windows/pthreads/pthread_setschedparam.c b/pcsx2/windows/pthreads/pthread_setschedparam.c index 0e705bb6c1..a122eaca66 100644 --- a/pcsx2/windows/pthreads/pthread_setschedparam.c +++ b/pcsx2/windows/pthreads/pthread_setschedparam.c @@ -1,125 +1,125 @@ -/* - * sched_setschedparam.c - * - * Description: - * POSIX thread functions that deal with thread scheduling. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" -#include "sched.h" - -int -pthread_setschedparam (pthread_t thread, int policy, - const struct sched_param *param) -{ - int result; - - /* Validate the thread id. */ - result = pthread_kill (thread, 0); - if (0 != result) - { - return result; - } - - /* Validate the scheduling policy. */ - if (policy < SCHED_MIN || policy > SCHED_MAX) - { - return EINVAL; - } - - /* Ensure the policy is SCHED_OTHER. */ - if (policy != SCHED_OTHER) - { - return ENOTSUP; - } - - return (ptw32_setthreadpriority (thread, policy, param->sched_priority)); -} - - -int -ptw32_setthreadpriority (pthread_t thread, int policy, int priority) -{ - int prio; - int result; - ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; - - prio = priority; - - /* Validate priority level. */ - if (prio < sched_get_priority_min (policy) || - prio > sched_get_priority_max (policy)) - { - return EINVAL; - } - -#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) -/* WinCE */ -#else -/* Everything else */ - - if (THREAD_PRIORITY_IDLE < prio && THREAD_PRIORITY_LOWEST > prio) - { - prio = THREAD_PRIORITY_LOWEST; - } - else if (THREAD_PRIORITY_TIME_CRITICAL > prio - && THREAD_PRIORITY_HIGHEST < prio) - { - prio = THREAD_PRIORITY_HIGHEST; - } - -#endif - - result = pthread_mutex_lock (&tp->threadLock); - - if (0 == result) - { - /* If this fails, the current priority is unchanged. */ - if (0 == SetThreadPriority (tp->threadH, prio)) - { - result = EINVAL; - } - else - { - /* - * Must record the thread's sched_priority as given, - * not as finally adjusted. - */ - tp->sched_priority = priority; - } - - (void) pthread_mutex_unlock (&tp->threadLock); - } - - return result; -} +/* + * sched_setschedparam.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +pthread_setschedparam (pthread_t thread, int policy, + const struct sched_param *param) +{ + int result; + + /* Validate the thread id. */ + result = pthread_kill (thread, 0); + if (0 != result) + { + return result; + } + + /* Validate the scheduling policy. */ + if (policy < SCHED_MIN || policy > SCHED_MAX) + { + return EINVAL; + } + + /* Ensure the policy is SCHED_OTHER. */ + if (policy != SCHED_OTHER) + { + return ENOTSUP; + } + + return (ptw32_setthreadpriority (thread, policy, param->sched_priority)); +} + + +int +ptw32_setthreadpriority (pthread_t thread, int policy, int priority) +{ + int prio; + int result; + ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; + + prio = priority; + + /* Validate priority level. */ + if (prio < sched_get_priority_min (policy) || + prio > sched_get_priority_max (policy)) + { + return EINVAL; + } + +#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) +/* WinCE */ +#else +/* Everything else */ + + if (THREAD_PRIORITY_IDLE < prio && THREAD_PRIORITY_LOWEST > prio) + { + prio = THREAD_PRIORITY_LOWEST; + } + else if (THREAD_PRIORITY_TIME_CRITICAL > prio + && THREAD_PRIORITY_HIGHEST < prio) + { + prio = THREAD_PRIORITY_HIGHEST; + } + +#endif + + result = pthread_mutex_lock (&tp->threadLock); + + if (0 == result) + { + /* If this fails, the current priority is unchanged. */ + if (0 == SetThreadPriority (tp->threadH, prio)) + { + result = EINVAL; + } + else + { + /* + * Must record the thread's sched_priority as given, + * not as finally adjusted. + */ + tp->sched_priority = priority; + } + + (void) pthread_mutex_unlock (&tp->threadLock); + } + + return result; +} diff --git a/pcsx2/windows/pthreads/pthread_setspecific.c b/pcsx2/windows/pthreads/pthread_setspecific.c index c3fcc299a1..f06b696166 100644 --- a/pcsx2/windows/pthreads/pthread_setspecific.c +++ b/pcsx2/windows/pthreads/pthread_setspecific.c @@ -1,168 +1,168 @@ -/* - * pthread_setspecific.c - * - * Description: - * POSIX thread functions which implement thread-specific data (TSD). - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_setspecific (pthread_key_t key, const void *value) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function sets the value of the thread specific - * key in the calling thread. - * - * PARAMETERS - * key - * an instance of pthread_key_t - * value - * the value to set key to - * - * - * DESCRIPTION - * This function sets the value of the thread specific - * key in the calling thread. - * - * RESULTS - * 0 successfully set value - * EAGAIN could not set value - * ENOENT SERIOUS!! - * - * ------------------------------------------------------ - */ -{ - pthread_t self; - int result = 0; - - if (key != ptw32_selfThreadKey) - { - /* - * Using pthread_self will implicitly create - * an instance of pthread_t for the current - * thread if one wasn't explicitly created - */ - self = pthread_self (); - if (self.p == NULL) - { - return ENOENT; - } - } - else - { - /* - * Resolve catch-22 of registering thread with selfThread - * key - */ - ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); - - if (sp == NULL) - { - if (value == NULL) - { - return ENOENT; - } - self = *((pthread_t *) value); - } - else - { - self = sp->ptHandle; - } - } - - result = 0; - - if (key != NULL) - { - if (self.p != NULL && key->destructor != NULL && value != NULL) - { - /* - * Only require associations if we have to - * call user destroy routine. - * Don't need to locate an existing association - * when setting data to NULL for WIN32 since the - * data is stored with the operating system; not - * on the association; setting assoc to NULL short - * circuits the search. - */ - ThreadKeyAssoc *assoc; - - if (pthread_mutex_lock(&(key->keyLock)) == 0) - { - ptw32_thread_t * sp = (ptw32_thread_t *) self.p; - - (void) pthread_mutex_lock(&(sp->threadLock)); - - assoc = (ThreadKeyAssoc *) sp->keys; - /* - * Locate existing association - */ - while (assoc != NULL) - { - if (assoc->key == key) - { - /* - * Association already exists - */ - break; - } - assoc = assoc->nextKey; - } - - /* - * create an association if not found - */ - if (assoc == NULL) - { - result = ptw32_tkAssocCreate (sp, key); - } - - (void) pthread_mutex_unlock(&(sp->threadLock)); - } - (void) pthread_mutex_unlock(&(key->keyLock)); - } - - if (result == 0) - { - if (!TlsSetValue (key->key, (LPVOID) value)) - { - result = EAGAIN; - } - } - } - - return (result); -} /* pthread_setspecific */ +/* + * pthread_setspecific.c + * + * Description: + * POSIX thread functions which implement thread-specific data (TSD). + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_setspecific (pthread_key_t key, const void *value) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function sets the value of the thread specific + * key in the calling thread. + * + * PARAMETERS + * key + * an instance of pthread_key_t + * value + * the value to set key to + * + * + * DESCRIPTION + * This function sets the value of the thread specific + * key in the calling thread. + * + * RESULTS + * 0 successfully set value + * EAGAIN could not set value + * ENOENT SERIOUS!! + * + * ------------------------------------------------------ + */ +{ + pthread_t self; + int result = 0; + + if (key != ptw32_selfThreadKey) + { + /* + * Using pthread_self will implicitly create + * an instance of pthread_t for the current + * thread if one wasn't explicitly created + */ + self = pthread_self (); + if (self.p == NULL) + { + return ENOENT; + } + } + else + { + /* + * Resolve catch-22 of registering thread with selfThread + * key + */ + ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); + + if (sp == NULL) + { + if (value == NULL) + { + return ENOENT; + } + self = *((pthread_t *) value); + } + else + { + self = sp->ptHandle; + } + } + + result = 0; + + if (key != NULL) + { + if (self.p != NULL && key->destructor != NULL && value != NULL) + { + /* + * Only require associations if we have to + * call user destroy routine. + * Don't need to locate an existing association + * when setting data to NULL for WIN32 since the + * data is stored with the operating system; not + * on the association; setting assoc to NULL short + * circuits the search. + */ + ThreadKeyAssoc *assoc; + + if (pthread_mutex_lock(&(key->keyLock)) == 0) + { + ptw32_thread_t * sp = (ptw32_thread_t *) self.p; + + (void) pthread_mutex_lock(&(sp->threadLock)); + + assoc = (ThreadKeyAssoc *) sp->keys; + /* + * Locate existing association + */ + while (assoc != NULL) + { + if (assoc->key == key) + { + /* + * Association already exists + */ + break; + } + assoc = assoc->nextKey; + } + + /* + * create an association if not found + */ + if (assoc == NULL) + { + result = ptw32_tkAssocCreate (sp, key); + } + + (void) pthread_mutex_unlock(&(sp->threadLock)); + } + (void) pthread_mutex_unlock(&(key->keyLock)); + } + + if (result == 0) + { + if (!TlsSetValue (key->key, (LPVOID) value)) + { + result = EAGAIN; + } + } + } + + return (result); +} /* pthread_setspecific */ diff --git a/pcsx2/windows/pthreads/pthread_spin_destroy.c b/pcsx2/windows/pthreads/pthread_spin_destroy.c index 80f248258a..8fe22674da 100644 --- a/pcsx2/windows/pthreads/pthread_spin_destroy.c +++ b/pcsx2/windows/pthreads/pthread_spin_destroy.c @@ -1,112 +1,112 @@ -/* - * pthread_spin_destroy.c - * - * Description: - * This translation unit implements spin lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_spin_destroy (pthread_spinlock_t * lock) -{ - register pthread_spinlock_t s; - int result = 0; - - if (lock == NULL || *lock == NULL) - { - return EINVAL; - } - - if ((s = *lock) != PTHREAD_SPINLOCK_INITIALIZER) - { - if (s->interlock == PTW32_SPIN_USE_MUTEX) - { - result = pthread_mutex_destroy (&(s->u.mutex)); - } - else if ((PTW32_INTERLOCKED_LONG) PTW32_SPIN_UNLOCKED != - PTW32_INTERLOCKED_COMPARE_EXCHANGE ((PTW32_INTERLOCKED_LPLONG) - & (s->interlock), - (PTW32_INTERLOCKED_LONG) - PTW32_OBJECT_INVALID, - (PTW32_INTERLOCKED_LONG) - PTW32_SPIN_UNLOCKED)) - { - result = EINVAL; - } - - if (0 == result) - { - /* - * We are relying on the application to ensure that all other threads - * have finished with the spinlock before destroying it. - */ - *lock = NULL; - (void) free (s); - } - } - else - { - /* - * See notes in ptw32_spinlock_check_need_init() above also. - */ - EnterCriticalSection (&ptw32_spinlock_test_init_lock); - - /* - * Check again. - */ - if (*lock == PTHREAD_SPINLOCK_INITIALIZER) - { - /* - * This is all we need to do to destroy a statically - * initialised spinlock that has not yet been used (initialised). - * If we get to here, another thread - * waiting to initialise this mutex will get an EINVAL. - */ - *lock = NULL; - } - else - { - /* - * The spinlock has been initialised while we were waiting - * so assume it's in use. - */ - result = EBUSY; - } - - LeaveCriticalSection (&ptw32_spinlock_test_init_lock); - } - - return (result); -} +/* + * pthread_spin_destroy.c + * + * Description: + * This translation unit implements spin lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_spin_destroy (pthread_spinlock_t * lock) +{ + register pthread_spinlock_t s; + int result = 0; + + if (lock == NULL || *lock == NULL) + { + return EINVAL; + } + + if ((s = *lock) != PTHREAD_SPINLOCK_INITIALIZER) + { + if (s->interlock == PTW32_SPIN_USE_MUTEX) + { + result = pthread_mutex_destroy (&(s->u.mutex)); + } + else if ((PTW32_INTERLOCKED_LONG) PTW32_SPIN_UNLOCKED != + PTW32_INTERLOCKED_COMPARE_EXCHANGE ((PTW32_INTERLOCKED_LPLONG) + & (s->interlock), + (PTW32_INTERLOCKED_LONG) + PTW32_OBJECT_INVALID, + (PTW32_INTERLOCKED_LONG) + PTW32_SPIN_UNLOCKED)) + { + result = EINVAL; + } + + if (0 == result) + { + /* + * We are relying on the application to ensure that all other threads + * have finished with the spinlock before destroying it. + */ + *lock = NULL; + (void) free (s); + } + } + else + { + /* + * See notes in ptw32_spinlock_check_need_init() above also. + */ + EnterCriticalSection (&ptw32_spinlock_test_init_lock); + + /* + * Check again. + */ + if (*lock == PTHREAD_SPINLOCK_INITIALIZER) + { + /* + * This is all we need to do to destroy a statically + * initialised spinlock that has not yet been used (initialised). + * If we get to here, another thread + * waiting to initialise this mutex will get an EINVAL. + */ + *lock = NULL; + } + else + { + /* + * The spinlock has been initialised while we were waiting + * so assume it's in use. + */ + result = EBUSY; + } + + LeaveCriticalSection (&ptw32_spinlock_test_init_lock); + } + + return (result); +} diff --git a/pcsx2/windows/pthreads/pthread_spin_init.c b/pcsx2/windows/pthreads/pthread_spin_init.c index 949d77409a..b9467b83e6 100644 --- a/pcsx2/windows/pthreads/pthread_spin_init.c +++ b/pcsx2/windows/pthreads/pthread_spin_init.c @@ -1,131 +1,131 @@ -/* - * pthread_spin_init.c - * - * Description: - * This translation unit implements spin lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_spin_init (pthread_spinlock_t * lock, int pshared) -{ - pthread_spinlock_t s; - int cpus = 0; - int result = 0; - - if (lock == NULL) - { - return EINVAL; - } - -#ifdef PTW32_STATIC_LIB - // This allos for C++ static initializers to function without crashes. (air) - pthread_win32_process_attach_np(); -#endif - -// Optimized this so that it doesn't do cpu count checks needlessly. (air) -#if _POSIX_THREAD_PROCESS_SHARED >= 0 - /* - * Not implemented yet. - */ - - if (0 != ptw32_getprocessors (&cpus)) - { - cpus = 1; - } - - if (cpus > 1) - { - if (pshared == PTHREAD_PROCESS_SHARED) - { - /* - * Creating spinlock that can be shared between - * processes. - */ - -#error ERROR [__FILE__, line __LINE__]: Process shared spin locks are not supported yet. - - - } - } - -#else - - if (pshared == PTHREAD_PROCESS_SHARED) - return ENOSYS; - -#endif /* _POSIX_THREAD_PROCESS_SHARED */ - - s = (pthread_spinlock_t) calloc (1, sizeof (*s)); - - if (s == NULL) - { - return ENOMEM; - } - - if (cpus > 1) - { - s->u.cpus = cpus; - s->interlock = PTW32_SPIN_UNLOCKED; - } - else - { - pthread_mutexattr_t ma; - result = pthread_mutexattr_init (&ma); - - if (0 == result) - { - ma->pshared = pshared; - result = pthread_mutex_init (&(s->u.mutex), &ma); - if (0 == result) - { - s->interlock = PTW32_SPIN_USE_MUTEX; - } - } - (void) pthread_mutexattr_destroy (&ma); - } - - if (0 == result) - { - *lock = s; - } - else - { - (void) free (s); - *lock = NULL; - } - - return (result); -} +/* + * pthread_spin_init.c + * + * Description: + * This translation unit implements spin lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_spin_init (pthread_spinlock_t * lock, int pshared) +{ + pthread_spinlock_t s; + int cpus = 0; + int result = 0; + + if (lock == NULL) + { + return EINVAL; + } + +#ifdef PTW32_STATIC_LIB + // This allos for C++ static initializers to function without crashes. (air) + pthread_win32_process_attach_np(); +#endif + +// Optimized this so that it doesn't do cpu count checks needlessly. (air) +#if _POSIX_THREAD_PROCESS_SHARED >= 0 + /* + * Not implemented yet. + */ + + if (0 != ptw32_getprocessors (&cpus)) + { + cpus = 1; + } + + if (cpus > 1) + { + if (pshared == PTHREAD_PROCESS_SHARED) + { + /* + * Creating spinlock that can be shared between + * processes. + */ + +#error ERROR [__FILE__, line __LINE__]: Process shared spin locks are not supported yet. + + + } + } + +#else + + if (pshared == PTHREAD_PROCESS_SHARED) + return ENOSYS; + +#endif /* _POSIX_THREAD_PROCESS_SHARED */ + + s = (pthread_spinlock_t) calloc (1, sizeof (*s)); + + if (s == NULL) + { + return ENOMEM; + } + + if (cpus > 1) + { + s->u.cpus = cpus; + s->interlock = PTW32_SPIN_UNLOCKED; + } + else + { + pthread_mutexattr_t ma; + result = pthread_mutexattr_init (&ma); + + if (0 == result) + { + ma->pshared = pshared; + result = pthread_mutex_init (&(s->u.mutex), &ma); + if (0 == result) + { + s->interlock = PTW32_SPIN_USE_MUTEX; + } + } + (void) pthread_mutexattr_destroy (&ma); + } + + if (0 == result) + { + *lock = s; + } + else + { + (void) free (s); + *lock = NULL; + } + + return (result); +} diff --git a/pcsx2/windows/pthreads/pthread_spin_lock.c b/pcsx2/windows/pthreads/pthread_spin_lock.c index 7e9bd2edae..90b3abee47 100644 --- a/pcsx2/windows/pthreads/pthread_spin_lock.c +++ b/pcsx2/windows/pthreads/pthread_spin_lock.c @@ -1,83 +1,83 @@ -/* - * pthread_spin_lock.c - * - * Description: - * This translation unit implements spin lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_spin_lock (pthread_spinlock_t * lock) -{ - register pthread_spinlock_t s; - - if (NULL == lock || NULL == *lock) - { - return (EINVAL); - } - - if (*lock == PTHREAD_SPINLOCK_INITIALIZER) - { - int result; - - if ((result = ptw32_spinlock_check_need_init (lock)) != 0) - { - return (result); - } - } - - s = *lock; - - while ((PTW32_INTERLOCKED_LONG) PTW32_SPIN_LOCKED == - PTW32_INTERLOCKED_COMPARE_EXCHANGE ((PTW32_INTERLOCKED_LPLONG) & - (s->interlock), - (PTW32_INTERLOCKED_LONG) - PTW32_SPIN_LOCKED, - (PTW32_INTERLOCKED_LONG) - PTW32_SPIN_UNLOCKED)) - { - } - - if (s->interlock == PTW32_SPIN_LOCKED) - { - return 0; - } - else if (s->interlock == PTW32_SPIN_USE_MUTEX) - { - return pthread_mutex_lock (&(s->u.mutex)); - } - - return EINVAL; -} +/* + * pthread_spin_lock.c + * + * Description: + * This translation unit implements spin lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_spin_lock (pthread_spinlock_t * lock) +{ + register pthread_spinlock_t s; + + if (NULL == lock || NULL == *lock) + { + return (EINVAL); + } + + if (*lock == PTHREAD_SPINLOCK_INITIALIZER) + { + int result; + + if ((result = ptw32_spinlock_check_need_init (lock)) != 0) + { + return (result); + } + } + + s = *lock; + + while ((PTW32_INTERLOCKED_LONG) PTW32_SPIN_LOCKED == + PTW32_INTERLOCKED_COMPARE_EXCHANGE ((PTW32_INTERLOCKED_LPLONG) & + (s->interlock), + (PTW32_INTERLOCKED_LONG) + PTW32_SPIN_LOCKED, + (PTW32_INTERLOCKED_LONG) + PTW32_SPIN_UNLOCKED)) + { + } + + if (s->interlock == PTW32_SPIN_LOCKED) + { + return 0; + } + else if (s->interlock == PTW32_SPIN_USE_MUTEX) + { + return pthread_mutex_lock (&(s->u.mutex)); + } + + return EINVAL; +} diff --git a/pcsx2/windows/pthreads/pthread_spin_trylock.c b/pcsx2/windows/pthreads/pthread_spin_trylock.c index caba165fb3..c601a191fe 100644 --- a/pcsx2/windows/pthreads/pthread_spin_trylock.c +++ b/pcsx2/windows/pthreads/pthread_spin_trylock.c @@ -1,80 +1,80 @@ -/* - * pthread_spin_trylock.c - * - * Description: - * This translation unit implements spin lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_spin_trylock (pthread_spinlock_t * lock) -{ - register pthread_spinlock_t s; - - if (NULL == lock || NULL == *lock) - { - return (EINVAL); - } - - if (*lock == PTHREAD_SPINLOCK_INITIALIZER) - { - int result; - - if ((result = ptw32_spinlock_check_need_init (lock)) != 0) - { - return (result); - } - } - - s = *lock; - - switch ((long) - PTW32_INTERLOCKED_COMPARE_EXCHANGE ((PTW32_INTERLOCKED_LPLONG) & - (s->interlock), - (PTW32_INTERLOCKED_LONG) - PTW32_SPIN_LOCKED, - (PTW32_INTERLOCKED_LONG) - PTW32_SPIN_UNLOCKED)) - { - case PTW32_SPIN_UNLOCKED: - return 0; - case PTW32_SPIN_LOCKED: - return EBUSY; - case PTW32_SPIN_USE_MUTEX: - return pthread_mutex_trylock (&(s->u.mutex)); - } - - return EINVAL; -} +/* + * pthread_spin_trylock.c + * + * Description: + * This translation unit implements spin lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_spin_trylock (pthread_spinlock_t * lock) +{ + register pthread_spinlock_t s; + + if (NULL == lock || NULL == *lock) + { + return (EINVAL); + } + + if (*lock == PTHREAD_SPINLOCK_INITIALIZER) + { + int result; + + if ((result = ptw32_spinlock_check_need_init (lock)) != 0) + { + return (result); + } + } + + s = *lock; + + switch ((long) + PTW32_INTERLOCKED_COMPARE_EXCHANGE ((PTW32_INTERLOCKED_LPLONG) & + (s->interlock), + (PTW32_INTERLOCKED_LONG) + PTW32_SPIN_LOCKED, + (PTW32_INTERLOCKED_LONG) + PTW32_SPIN_UNLOCKED)) + { + case PTW32_SPIN_UNLOCKED: + return 0; + case PTW32_SPIN_LOCKED: + return EBUSY; + case PTW32_SPIN_USE_MUTEX: + return pthread_mutex_trylock (&(s->u.mutex)); + } + + return EINVAL; +} diff --git a/pcsx2/windows/pthreads/pthread_spin_unlock.c b/pcsx2/windows/pthreads/pthread_spin_unlock.c index c14781669d..67bc2c218d 100644 --- a/pcsx2/windows/pthreads/pthread_spin_unlock.c +++ b/pcsx2/windows/pthreads/pthread_spin_unlock.c @@ -1,75 +1,75 @@ -/* - * pthread_spin_unlock.c - * - * Description: - * This translation unit implements spin lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -pthread_spin_unlock (pthread_spinlock_t * lock) -{ - register pthread_spinlock_t s; - - if (NULL == lock || NULL == *lock) - { - return (EINVAL); - } - - s = *lock; - - if (s == PTHREAD_SPINLOCK_INITIALIZER) - { - return EPERM; - } - - switch ((long) - PTW32_INTERLOCKED_COMPARE_EXCHANGE ((PTW32_INTERLOCKED_LPLONG) & - (s->interlock), - (PTW32_INTERLOCKED_LONG) - PTW32_SPIN_UNLOCKED, - (PTW32_INTERLOCKED_LONG) - PTW32_SPIN_LOCKED)) - { - case PTW32_SPIN_LOCKED: - return 0; - case PTW32_SPIN_UNLOCKED: - return EPERM; - case PTW32_SPIN_USE_MUTEX: - return pthread_mutex_unlock (&(s->u.mutex)); - } - - return EINVAL; -} +/* + * pthread_spin_unlock.c + * + * Description: + * This translation unit implements spin lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_spin_unlock (pthread_spinlock_t * lock) +{ + register pthread_spinlock_t s; + + if (NULL == lock || NULL == *lock) + { + return (EINVAL); + } + + s = *lock; + + if (s == PTHREAD_SPINLOCK_INITIALIZER) + { + return EPERM; + } + + switch ((long) + PTW32_INTERLOCKED_COMPARE_EXCHANGE ((PTW32_INTERLOCKED_LPLONG) & + (s->interlock), + (PTW32_INTERLOCKED_LONG) + PTW32_SPIN_UNLOCKED, + (PTW32_INTERLOCKED_LONG) + PTW32_SPIN_LOCKED)) + { + case PTW32_SPIN_LOCKED: + return 0; + case PTW32_SPIN_UNLOCKED: + return EPERM; + case PTW32_SPIN_USE_MUTEX: + return pthread_mutex_unlock (&(s->u.mutex)); + } + + return EINVAL; +} diff --git a/pcsx2/windows/pthreads/pthread_testcancel.c b/pcsx2/windows/pthreads/pthread_testcancel.c index 10a846e15a..ad7cdb9944 100644 --- a/pcsx2/windows/pthreads/pthread_testcancel.c +++ b/pcsx2/windows/pthreads/pthread_testcancel.c @@ -1,102 +1,102 @@ -/* - * pthread_testcancel.c - * - * Description: - * POSIX thread functions related to thread cancellation. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -void -pthread_testcancel (void) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function creates a deferred cancellation point - * in the calling thread. The call has no effect if the - * current cancelability state is - * PTHREAD_CANCEL_DISABLE - * - * PARAMETERS - * N/A - * - * - * DESCRIPTION - * This function creates a deferred cancellation point - * in the calling thread. The call has no effect if the - * current cancelability state is - * PTHREAD_CANCEL_DISABLE - * - * NOTES: - * 1) Cancellation is asynchronous. Use pthread_join - * to wait for termination of thread if necessary - * - * RESULTS - * N/A - * - * ------------------------------------------------------ - */ -{ - pthread_t self = pthread_self (); - ptw32_thread_t * sp = (ptw32_thread_t *) self.p; - - if (sp == NULL) - { - return; - } - - /* - * Pthread_cancel() will have set sp->state to PThreadStateCancelPending - * and set an event, so no need to enter kernel space if - * sp->state != PThreadStateCancelPending - that only slows us down. - */ - if (sp->state != PThreadStateCancelPending) - { - return; - } - - (void) pthread_mutex_lock (&sp->cancelLock); - - if (sp->cancelState != PTHREAD_CANCEL_DISABLE) - { - ResetEvent(sp->cancelEvent); - sp->state = PThreadStateCanceling; - (void) pthread_mutex_unlock (&sp->cancelLock); - sp->cancelState = PTHREAD_CANCEL_DISABLE; - (void) pthread_mutex_unlock (&sp->cancelLock); - ptw32_throw (PTW32_EPS_CANCEL); - } - - (void) pthread_mutex_unlock (&sp->cancelLock); -} /* pthread_testcancel */ +/* + * pthread_testcancel.c + * + * Description: + * POSIX thread functions related to thread cancellation. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +void +pthread_testcancel (void) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function creates a deferred cancellation point + * in the calling thread. The call has no effect if the + * current cancelability state is + * PTHREAD_CANCEL_DISABLE + * + * PARAMETERS + * N/A + * + * + * DESCRIPTION + * This function creates a deferred cancellation point + * in the calling thread. The call has no effect if the + * current cancelability state is + * PTHREAD_CANCEL_DISABLE + * + * NOTES: + * 1) Cancellation is asynchronous. Use pthread_join + * to wait for termination of thread if necessary + * + * RESULTS + * N/A + * + * ------------------------------------------------------ + */ +{ + pthread_t self = pthread_self (); + ptw32_thread_t * sp = (ptw32_thread_t *) self.p; + + if (sp == NULL) + { + return; + } + + /* + * Pthread_cancel() will have set sp->state to PThreadStateCancelPending + * and set an event, so no need to enter kernel space if + * sp->state != PThreadStateCancelPending - that only slows us down. + */ + if (sp->state != PThreadStateCancelPending) + { + return; + } + + (void) pthread_mutex_lock (&sp->cancelLock); + + if (sp->cancelState != PTHREAD_CANCEL_DISABLE) + { + ResetEvent(sp->cancelEvent); + sp->state = PThreadStateCanceling; + (void) pthread_mutex_unlock (&sp->cancelLock); + sp->cancelState = PTHREAD_CANCEL_DISABLE; + (void) pthread_mutex_unlock (&sp->cancelLock); + ptw32_throw (PTW32_EPS_CANCEL); + } + + (void) pthread_mutex_unlock (&sp->cancelLock); +} /* pthread_testcancel */ diff --git a/pcsx2/windows/pthreads/pthread_timechange_handler_np.c b/pcsx2/windows/pthreads/pthread_timechange_handler_np.c index 99a4d61d59..7d8170a3ff 100644 --- a/pcsx2/windows/pthreads/pthread_timechange_handler_np.c +++ b/pcsx2/windows/pthreads/pthread_timechange_handler_np.c @@ -1,107 +1,107 @@ -/* - * pthread_timechange_handler_np.c - * - * Description: - * This translation unit implements miscellaneous thread functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -/* - * Notes on handling system time adjustments (especially negative ones). - * --------------------------------------------------------------------- - * - * This solution was suggested by Alexander Terekhov, but any errors - * in the implementation are mine - [Ross Johnson] - * - * 1) The problem: threads doing a timedwait on a CV may expect to timeout - * at a specific absolute time according to a system timer. If the - * system clock is adjusted backwards then those threads sleep longer than - * expected. Also, pthreads-win32 converts absolute times to intervals in - * order to make use of the underlying Win32, and so waiting threads may - * awake before their proper abstimes. - * - * 2) We aren't able to distinquish between threads on timed or untimed waits, - * so we wake them all at the time of the adjustment so that they can - * re-evaluate their conditions and re-compute their timeouts. - * - * 3) We rely on correctly written applications for this to work. Specifically, - * they must be able to deal properly with spurious wakeups. That is, - * they must re-test their condition upon wakeup and wait again if - * the condition is not satisfied. - */ - -void * -pthread_timechange_handler_np (void *arg) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * Broadcasts all CVs to force re-evaluation and - * new timeouts if required. - * - * PARAMETERS - * NONE - * - * - * DESCRIPTION - * Broadcasts all CVs to force re-evaluation and - * new timeouts if required. - * - * This routine may be passed directly to pthread_create() - * as a new thread in order to run asynchronously. - * - * - * RESULTS - * 0 successfully broadcast all CVs - * EAGAIN Not all CVs were broadcast - * - * ------------------------------------------------------ - */ -{ - int result = 0; - pthread_cond_t cv; - - EnterCriticalSection (&ptw32_cond_list_lock); - - cv = ptw32_cond_list_head; - - while (cv != NULL && 0 == result) - { - result = pthread_cond_broadcast (&cv); - cv = cv->next; - } - - LeaveCriticalSection (&ptw32_cond_list_lock); - - return (void *) (result != 0 ? EAGAIN : 0); -} +/* + * pthread_timechange_handler_np.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* + * Notes on handling system time adjustments (especially negative ones). + * --------------------------------------------------------------------- + * + * This solution was suggested by Alexander Terekhov, but any errors + * in the implementation are mine - [Ross Johnson] + * + * 1) The problem: threads doing a timedwait on a CV may expect to timeout + * at a specific absolute time according to a system timer. If the + * system clock is adjusted backwards then those threads sleep longer than + * expected. Also, pthreads-win32 converts absolute times to intervals in + * order to make use of the underlying Win32, and so waiting threads may + * awake before their proper abstimes. + * + * 2) We aren't able to distinquish between threads on timed or untimed waits, + * so we wake them all at the time of the adjustment so that they can + * re-evaluate their conditions and re-compute their timeouts. + * + * 3) We rely on correctly written applications for this to work. Specifically, + * they must be able to deal properly with spurious wakeups. That is, + * they must re-test their condition upon wakeup and wait again if + * the condition is not satisfied. + */ + +void * +pthread_timechange_handler_np (void *arg) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Broadcasts all CVs to force re-evaluation and + * new timeouts if required. + * + * PARAMETERS + * NONE + * + * + * DESCRIPTION + * Broadcasts all CVs to force re-evaluation and + * new timeouts if required. + * + * This routine may be passed directly to pthread_create() + * as a new thread in order to run asynchronously. + * + * + * RESULTS + * 0 successfully broadcast all CVs + * EAGAIN Not all CVs were broadcast + * + * ------------------------------------------------------ + */ +{ + int result = 0; + pthread_cond_t cv; + + EnterCriticalSection (&ptw32_cond_list_lock); + + cv = ptw32_cond_list_head; + + while (cv != NULL && 0 == result) + { + result = pthread_cond_broadcast (&cv); + cv = cv->next; + } + + LeaveCriticalSection (&ptw32_cond_list_lock); + + return (void *) (result != 0 ? EAGAIN : 0); +} diff --git a/pcsx2/windows/pthreads/pthread_win32_attach_detach_np.c b/pcsx2/windows/pthreads/pthread_win32_attach_detach_np.c index 0e25b07d80..ebd6b59f94 100644 --- a/pcsx2/windows/pthreads/pthread_win32_attach_detach_np.c +++ b/pcsx2/windows/pthreads/pthread_win32_attach_detach_np.c @@ -1,310 +1,310 @@ -/* - * pthread_win32_attach_detach_np.c - * - * Description: - * This translation unit implements non-portable thread functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -/* - * Handle to kernel32.dll - */ -static HINSTANCE ptw32_h_kernel32; - -/* - * Handle to quserex.dll - */ -static HINSTANCE ptw32_h_quserex; - -BOOL -pthread_win32_process_attach_np () -{ - BOOL result = TRUE; - DWORD_PTR vProcessCPUs; - DWORD_PTR vSystemCPUs; - - if( ptw32_processInitialized ) return TRUE; - - result = ptw32_processInitialize (); - -#ifdef _UWIN - pthread_count++; -#endif - - ptw32_features = 0; - - -#if defined(NEED_PROCESS_AFFINITY_MASK) - - ptw32_smp_system = PTW32_FALSE; - -#else - - if (GetProcessAffinityMask (GetCurrentProcess (), - &vProcessCPUs, &vSystemCPUs)) - { - int CPUs = 0; - DWORD_PTR bit; - - for (bit = 1; bit != 0; bit <<= 1) - { - if (vSystemCPUs & bit) - { - CPUs++; - } - } - ptw32_smp_system = (CPUs > 1); - } - else - { - ptw32_smp_system = PTW32_FALSE; - } - -#endif - -#if 0 - -#ifdef WINCE - - /* - * Load COREDLL and try to get address of InterlockedCompareExchange - */ - ptw32_h_kernel32 = LoadLibrary (TEXT ("COREDLL.DLL")); - -#else - - /* - * Load KERNEL32 and try to get address of InterlockedCompareExchange - */ - ptw32_h_kernel32 = LoadLibrary (TEXT ("KERNEL32.DLL")); - -#endif - -// We're only using pthreads' inline version of InterlockedExchange - ptw32_interlocked_compare_exchange = - (PTW32_INTERLOCKED_LONG (WINAPI *) - (PTW32_INTERLOCKED_LPLONG, PTW32_INTERLOCKED_LONG, - PTW32_INTERLOCKED_LONG)) -#if defined(NEED_UNICODE_CONSTS) - GetProcAddress (ptw32_h_kernel32, - (const TCHAR *) TEXT ("InterlockedCompareExchange")); -#else - GetProcAddress (ptw32_h_kernel32, (LPCSTR) "InterlockedCompareExchange"); -#endif - - if (ptw32_interlocked_compare_exchange == NULL) - { - ptw32_interlocked_compare_exchange = ptw32_InterlockedCompareExchange; - - /* - * If InterlockedCompareExchange is not being used, then free - * the kernel32.dll handle now, rather than leaving it until - * DLL_PROCESS_DETACH. - * - * Note: this is not a pedantic exercise in freeing unused - * resources! It is a work-around for a bug in Windows 95 - * (see microsoft knowledge base article, Q187684) which - * does Bad Things when FreeLibrary is called within - * the DLL_PROCESS_DETACH code, in certain situations. - * Since w95 just happens to be a platform which does not - * provide InterlockedCompareExchange, the bug will be - * effortlessly avoided. - */ - (void) FreeLibrary (ptw32_h_kernel32); - ptw32_h_kernel32 = 0; - } - else - { - ptw32_features |= PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE; - } - -#endif - - /* - * Load QUSEREX.DLL and try to get address of QueueUserAPCEx - */ - ptw32_h_quserex = LoadLibrary (TEXT ("QUSEREX.DLL")); - - if (ptw32_h_quserex != NULL) - { - ptw32_register_cancelation = (DWORD (*)(PAPCFUNC, HANDLE, DWORD)) -#if defined(NEED_UNICODE_CONSTS) - GetProcAddress (ptw32_h_quserex, - (const TCHAR *) TEXT ("QueueUserAPCEx")); -#else - GetProcAddress (ptw32_h_quserex, (LPCSTR) "QueueUserAPCEx"); -#endif - } - - if (NULL == ptw32_register_cancelation) - { - ptw32_register_cancelation = ptw32_RegisterCancelation; - - if (ptw32_h_quserex != NULL) - { - (void) FreeLibrary (ptw32_h_quserex); - } - ptw32_h_quserex = 0; - } - else - { - /* Initialise QueueUserAPCEx */ - BOOL (*queue_user_apc_ex_init) (VOID); - - queue_user_apc_ex_init = (BOOL (*)(VOID)) -#if defined(NEED_UNICODE_CONSTS) - GetProcAddress (ptw32_h_quserex, - (const TCHAR *) TEXT ("QueueUserAPCEx_Init")); -#else - GetProcAddress (ptw32_h_quserex, (LPCSTR) "QueueUserAPCEx_Init"); -#endif - - if (queue_user_apc_ex_init == NULL || !queue_user_apc_ex_init ()) - { - ptw32_register_cancelation = ptw32_RegisterCancelation; - - (void) FreeLibrary (ptw32_h_quserex); - ptw32_h_quserex = 0; - } - } - - if (ptw32_h_quserex) - { - ptw32_features |= PTW32_ALERTABLE_ASYNC_CANCEL; - } - - return result; -} - - -BOOL -pthread_win32_process_detach_np () -{ - if (ptw32_processInitialized) - { - ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); - - if (sp != NULL) - { - /* - * Detached threads have their resources automatically - * cleaned up upon exit (others must be 'joined'). - */ - if (sp->detachState == PTHREAD_CREATE_DETACHED) - { - ptw32_threadDestroy (sp->ptHandle); - TlsSetValue (ptw32_selfThreadKey->key, NULL); - } - } - - /* - * The DLL is being unmapped from the process's address space - */ - ptw32_processTerminate (); - - if (ptw32_h_quserex) - { - /* Close QueueUserAPCEx */ - BOOL (*queue_user_apc_ex_fini) (VOID); - - queue_user_apc_ex_fini = (BOOL (*)(VOID)) -#if defined(NEED_UNICODE_CONSTS) - GetProcAddress (ptw32_h_quserex, - (const TCHAR *) TEXT ("QueueUserAPCEx_Fini")); -#else - GetProcAddress (ptw32_h_quserex, (LPCSTR) "QueueUserAPCEx_Fini"); -#endif - - if (queue_user_apc_ex_fini != NULL) - { - (void) queue_user_apc_ex_fini (); - } - (void) FreeLibrary (ptw32_h_quserex); - } - - if (ptw32_h_kernel32) - { - (void) FreeLibrary (ptw32_h_kernel32); - } - } - - return TRUE; -} - -BOOL -pthread_win32_thread_attach_np () -{ - return TRUE; -} - -BOOL -pthread_win32_thread_detach_np () -{ - if (ptw32_processInitialized) - { - /* - * Don't use pthread_self() - to avoid creating an implicit POSIX thread handle - * unnecessarily. - */ - ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); - - if (sp != NULL) // otherwise Win32 thread with no implicit POSIX handle. - { - ptw32_callUserDestroyRoutines (sp->ptHandle); - - (void) pthread_mutex_lock (&sp->cancelLock); - sp->state = PThreadStateLast; - /* - * If the thread is joinable at this point then it MUST be joined - * or detached explicitly by the application. - */ - (void) pthread_mutex_unlock (&sp->cancelLock); - - if (sp->detachState == PTHREAD_CREATE_DETACHED) - { - ptw32_threadDestroy (sp->ptHandle); - - TlsSetValue (ptw32_selfThreadKey->key, NULL); - } - } - } - - return TRUE; -} - -BOOL -pthread_win32_test_features_np (int feature_mask) -{ - return ((ptw32_features & feature_mask) == feature_mask); -} +/* + * pthread_win32_attach_detach_np.c + * + * Description: + * This translation unit implements non-portable thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* + * Handle to kernel32.dll + */ +static HINSTANCE ptw32_h_kernel32; + +/* + * Handle to quserex.dll + */ +static HINSTANCE ptw32_h_quserex; + +BOOL +pthread_win32_process_attach_np () +{ + BOOL result = TRUE; + DWORD_PTR vProcessCPUs; + DWORD_PTR vSystemCPUs; + + if( ptw32_processInitialized ) return TRUE; + + result = ptw32_processInitialize (); + +#ifdef _UWIN + pthread_count++; +#endif + + ptw32_features = 0; + + +#if defined(NEED_PROCESS_AFFINITY_MASK) + + ptw32_smp_system = PTW32_FALSE; + +#else + + if (GetProcessAffinityMask (GetCurrentProcess (), + &vProcessCPUs, &vSystemCPUs)) + { + int CPUs = 0; + DWORD_PTR bit; + + for (bit = 1; bit != 0; bit <<= 1) + { + if (vSystemCPUs & bit) + { + CPUs++; + } + } + ptw32_smp_system = (CPUs > 1); + } + else + { + ptw32_smp_system = PTW32_FALSE; + } + +#endif + +#if 0 + +#ifdef WINCE + + /* + * Load COREDLL and try to get address of InterlockedCompareExchange + */ + ptw32_h_kernel32 = LoadLibrary (TEXT ("COREDLL.DLL")); + +#else + + /* + * Load KERNEL32 and try to get address of InterlockedCompareExchange + */ + ptw32_h_kernel32 = LoadLibrary (TEXT ("KERNEL32.DLL")); + +#endif + +// We're only using pthreads' inline version of InterlockedExchange + ptw32_interlocked_compare_exchange = + (PTW32_INTERLOCKED_LONG (WINAPI *) + (PTW32_INTERLOCKED_LPLONG, PTW32_INTERLOCKED_LONG, + PTW32_INTERLOCKED_LONG)) +#if defined(NEED_UNICODE_CONSTS) + GetProcAddress (ptw32_h_kernel32, + (const TCHAR *) TEXT ("InterlockedCompareExchange")); +#else + GetProcAddress (ptw32_h_kernel32, (LPCSTR) "InterlockedCompareExchange"); +#endif + + if (ptw32_interlocked_compare_exchange == NULL) + { + ptw32_interlocked_compare_exchange = ptw32_InterlockedCompareExchange; + + /* + * If InterlockedCompareExchange is not being used, then free + * the kernel32.dll handle now, rather than leaving it until + * DLL_PROCESS_DETACH. + * + * Note: this is not a pedantic exercise in freeing unused + * resources! It is a work-around for a bug in Windows 95 + * (see microsoft knowledge base article, Q187684) which + * does Bad Things when FreeLibrary is called within + * the DLL_PROCESS_DETACH code, in certain situations. + * Since w95 just happens to be a platform which does not + * provide InterlockedCompareExchange, the bug will be + * effortlessly avoided. + */ + (void) FreeLibrary (ptw32_h_kernel32); + ptw32_h_kernel32 = 0; + } + else + { + ptw32_features |= PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE; + } + +#endif + + /* + * Load QUSEREX.DLL and try to get address of QueueUserAPCEx + */ + ptw32_h_quserex = LoadLibrary (TEXT ("QUSEREX.DLL")); + + if (ptw32_h_quserex != NULL) + { + ptw32_register_cancelation = (DWORD (*)(PAPCFUNC, HANDLE, DWORD)) +#if defined(NEED_UNICODE_CONSTS) + GetProcAddress (ptw32_h_quserex, + (const TCHAR *) TEXT ("QueueUserAPCEx")); +#else + GetProcAddress (ptw32_h_quserex, (LPCSTR) "QueueUserAPCEx"); +#endif + } + + if (NULL == ptw32_register_cancelation) + { + ptw32_register_cancelation = ptw32_RegisterCancelation; + + if (ptw32_h_quserex != NULL) + { + (void) FreeLibrary (ptw32_h_quserex); + } + ptw32_h_quserex = 0; + } + else + { + /* Initialise QueueUserAPCEx */ + BOOL (*queue_user_apc_ex_init) (VOID); + + queue_user_apc_ex_init = (BOOL (*)(VOID)) +#if defined(NEED_UNICODE_CONSTS) + GetProcAddress (ptw32_h_quserex, + (const TCHAR *) TEXT ("QueueUserAPCEx_Init")); +#else + GetProcAddress (ptw32_h_quserex, (LPCSTR) "QueueUserAPCEx_Init"); +#endif + + if (queue_user_apc_ex_init == NULL || !queue_user_apc_ex_init ()) + { + ptw32_register_cancelation = ptw32_RegisterCancelation; + + (void) FreeLibrary (ptw32_h_quserex); + ptw32_h_quserex = 0; + } + } + + if (ptw32_h_quserex) + { + ptw32_features |= PTW32_ALERTABLE_ASYNC_CANCEL; + } + + return result; +} + + +BOOL +pthread_win32_process_detach_np () +{ + if (ptw32_processInitialized) + { + ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); + + if (sp != NULL) + { + /* + * Detached threads have their resources automatically + * cleaned up upon exit (others must be 'joined'). + */ + if (sp->detachState == PTHREAD_CREATE_DETACHED) + { + ptw32_threadDestroy (sp->ptHandle); + TlsSetValue (ptw32_selfThreadKey->key, NULL); + } + } + + /* + * The DLL is being unmapped from the process's address space + */ + ptw32_processTerminate (); + + if (ptw32_h_quserex) + { + /* Close QueueUserAPCEx */ + BOOL (*queue_user_apc_ex_fini) (VOID); + + queue_user_apc_ex_fini = (BOOL (*)(VOID)) +#if defined(NEED_UNICODE_CONSTS) + GetProcAddress (ptw32_h_quserex, + (const TCHAR *) TEXT ("QueueUserAPCEx_Fini")); +#else + GetProcAddress (ptw32_h_quserex, (LPCSTR) "QueueUserAPCEx_Fini"); +#endif + + if (queue_user_apc_ex_fini != NULL) + { + (void) queue_user_apc_ex_fini (); + } + (void) FreeLibrary (ptw32_h_quserex); + } + + if (ptw32_h_kernel32) + { + (void) FreeLibrary (ptw32_h_kernel32); + } + } + + return TRUE; +} + +BOOL +pthread_win32_thread_attach_np () +{ + return TRUE; +} + +BOOL +pthread_win32_thread_detach_np () +{ + if (ptw32_processInitialized) + { + /* + * Don't use pthread_self() - to avoid creating an implicit POSIX thread handle + * unnecessarily. + */ + ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); + + if (sp != NULL) // otherwise Win32 thread with no implicit POSIX handle. + { + ptw32_callUserDestroyRoutines (sp->ptHandle); + + (void) pthread_mutex_lock (&sp->cancelLock); + sp->state = PThreadStateLast; + /* + * If the thread is joinable at this point then it MUST be joined + * or detached explicitly by the application. + */ + (void) pthread_mutex_unlock (&sp->cancelLock); + + if (sp->detachState == PTHREAD_CREATE_DETACHED) + { + ptw32_threadDestroy (sp->ptHandle); + + TlsSetValue (ptw32_selfThreadKey->key, NULL); + } + } + } + + return TRUE; +} + +BOOL +pthread_win32_test_features_np (int feature_mask) +{ + return ((ptw32_features & feature_mask) == feature_mask); +} diff --git a/pcsx2/windows/pthreads/ptw32_InterlockedCompareExchange.c b/pcsx2/windows/pthreads/ptw32_InterlockedCompareExchange.c index 0ddabc952c..909aa9b7d5 100644 --- a/pcsx2/windows/pthreads/ptw32_InterlockedCompareExchange.c +++ b/pcsx2/windows/pthreads/ptw32_InterlockedCompareExchange.c @@ -1,303 +1,303 @@ -/* - * ptw32_InterlockedCompareExchange.c - * - * Description: - * This translation unit implements routines which are private to - * the implementation and may be used throughout it. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -/* - * ptw32_InterlockedCompareExchange -- - * - * Originally needed because W9x doesn't support InterlockedCompareExchange. - * We now use this version wherever possible so we can inline it. - */ - -INLINE PTW32_INTERLOCKED_LONG WINAPI -ptw32_InterlockedCompareExchange (volatile PTW32_INTERLOCKED_LPLONG location, - PTW32_INTERLOCKED_LONG value, - PTW32_INTERLOCKED_LONG comparand) -{ - -#if defined(__WATCOMC__) -/* Don't report that result is not assigned a value before being referenced */ -#pragma disable_message (200) -#endif - - PTW32_INTERLOCKED_LONG result; - - /* - * Using the LOCK prefix on uni-processor machines is significantly slower - * and it is not necessary. The overhead of the conditional below is - * negligible in comparison. Since an optimised DLL will inline this - * routine, this will be faster than calling the system supplied - * Interlocked routine, which appears to avoid the LOCK prefix on - * uniprocessor systems. So one DLL works for all systems. - */ - if (1) //ptw32_smp_system) - -/* *INDENT-OFF* */ - -#if defined(_M_IX86) || defined(_X86_) - -#if defined(_MSC_VER) || defined(__WATCOMC__) || (defined(__BORLANDC__) && defined(HAVE_TASM32)) -#define HAVE_INLINABLE_INTERLOCKED_CMPXCHG - { - _asm { - //PUSH ecx - //PUSH edx - MOV ecx,dword ptr [location] - MOV edx,dword ptr [value] - MOV eax,dword ptr [comparand] - LOCK CMPXCHG dword ptr [ecx],edx - MOV dword ptr [result], eax - //POP edx - //POP ecx - } - } - else - { - _asm { - //PUSH ecx - //PUSH edx - MOV ecx,dword ptr [location] - MOV edx,dword ptr [value] - MOV eax,dword ptr [comparand] - CMPXCHG dword ptr [ecx],edx - MOV dword ptr [result], eax - //POP edx - //POP ecx - } - } - -#elif defined(__GNUC__) -#define HAVE_INLINABLE_INTERLOCKED_CMPXCHG - - { - __asm__ __volatile__ - ( - "lock\n\t" - "cmpxchgl %2,%1" /* if (EAX == [location]) */ - /* [location] = value */ - /* else */ - /* EAX = [location] */ - :"=a" (result) - :"m" (*location), "r" (value), "a" (comparand)); - } - else - { - __asm__ __volatile__ - ( - "cmpxchgl %2,%1" /* if (EAX == [location]) */ - /* [location] = value */ - /* else */ - /* EAX = [location] */ - :"=a" (result) - :"m" (*location), "r" (value), "a" (comparand)); - } - -#endif - -#else - - /* - * If execution gets to here then we're running on a currently - * unsupported processor or compiler. - */ - - result = 0; - -#endif - -/* *INDENT-ON* */ - - return result; - -#if defined(__WATCOMC__) -#pragma enable_message (200) -#endif - -} - -/* - * ptw32_InterlockedExchange -- - * - * We now use this version wherever possible so we can inline it. - */ - -INLINE LONG WINAPI -ptw32_InterlockedExchange (volatile PTW32_INTERLOCKED_LPLONG location, - LONG value) -{ - -#if defined(__WATCOMC__) -/* Don't report that result is not assigned a value before being referenced */ -#pragma disable_message (200) -#endif - - LONG result; - - /* - * The XCHG instruction always locks the bus with or without the - * LOCKED prefix. This makes it significantly slower than CMPXCHG on - * uni-processor machines. The Windows InterlockedExchange function - * is nearly 3 times faster than the XCHG instruction, so this routine - * is not yet very useful for speeding up pthreads. - */ - if (1) //ptw32_smp_system) - -/* *INDENT-OFF* */ - -#if defined(_M_IX86) || defined(_X86_) - -#if defined(_MSC_VER) || defined(__WATCOMC__) || (defined(__BORLANDC__) && defined(HAVE_TASM32)) -#define HAVE_INLINABLE_INTERLOCKED_XCHG - - { - _asm { - //PUSH ecx - MOV ecx,dword ptr [location] - MOV eax,dword ptr [value] - XCHG dword ptr [ecx],eax - MOV dword ptr [result], eax - //POP ecx - } - } - else - { - /* - * Faster version of XCHG for uni-processor systems because - * it doesn't lock the bus. If an interrupt or context switch - * occurs between the MOV and the CMPXCHG then the value in - * 'location' may have changed, in which case we will loop - * back to do the MOV again. - * - * FIXME! Need memory barriers for the MOV+CMPXCHG combo? - * - * Tests show that this routine has almost identical timing - * to Win32's InterlockedExchange(), which is much faster than - * using the inlined 'xchg' instruction above, so it's probably - * doing something similar to this (on UP systems). - * - * Can we do without the PUSH/POP instructions? - */ - _asm { - //PUSH ecx - //PUSH edx - MOV ecx,dword ptr [location] - MOV edx,dword ptr [value] -L1: MOV eax,dword ptr [ecx] - CMPXCHG dword ptr [ecx],edx - JNZ L1 - MOV dword ptr [result], eax - //POP edx - //POP ecx - } - } - -#elif defined(__GNUC__) -#define HAVE_INLINABLE_INTERLOCKED_XCHG - - { - __asm__ __volatile__ - ( - "xchgl %2,%1" - :"=r" (result) - :"m" (*location), "0" (value)); - } - else - { - /* - * Faster version of XCHG for uni-processor systems because - * it doesn't lock the bus. If an interrupt or context switch - * occurs between the movl and the cmpxchgl then the value in - * 'location' may have changed, in which case we will loop - * back to do the movl again. - * - * FIXME! Need memory barriers for the MOV+CMPXCHG combo? - * - * Tests show that this routine has almost identical timing - * to Win32's InterlockedExchange(), which is much faster than - * using the an inlined 'xchg' instruction, so it's probably - * doing something similar to this (on UP systems). - */ - __asm__ __volatile__ - ( - "0:\n\t" - "movl %1,%%eax\n\t" - "cmpxchgl %2,%1\n\t" - "jnz 0b" - :"=&a" (result) - :"m" (*location), "r" (value)); - } - -#endif - -#else - - /* - * If execution gets to here then we're running on a currently - * unsupported processor or compiler. - */ - - result = 0; - -#endif - -/* *INDENT-ON* */ - - return result; - -#if defined(__WATCOMC__) -#pragma enable_message (200) -#endif - -} - - -#if 1 - -#if defined(PTW32_BUILD_INLINED) && defined(HAVE_INLINABLE_INTERLOCKED_CMPXCHG) -#undef PTW32_INTERLOCKED_COMPARE_EXCHANGE -#define PTW32_INTERLOCKED_COMPARE_EXCHANGE ptw32_InterlockedCompareExchange -#endif - -#if defined(PTW32_BUILD_INLINED) && defined(HAVE_INLINABLE_INTERLOCKED_XCHG) -#undef PTW32_INTERLOCKED_EXCHANGE -#define PTW32_INTERLOCKED_EXCHANGE ptw32_InterlockedExchange -#endif - -#endif +/* + * ptw32_InterlockedCompareExchange.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +/* + * ptw32_InterlockedCompareExchange -- + * + * Originally needed because W9x doesn't support InterlockedCompareExchange. + * We now use this version wherever possible so we can inline it. + */ + +INLINE PTW32_INTERLOCKED_LONG WINAPI +ptw32_InterlockedCompareExchange (volatile PTW32_INTERLOCKED_LPLONG location, + PTW32_INTERLOCKED_LONG value, + PTW32_INTERLOCKED_LONG comparand) +{ + +#if defined(__WATCOMC__) +/* Don't report that result is not assigned a value before being referenced */ +#pragma disable_message (200) +#endif + + PTW32_INTERLOCKED_LONG result; + + /* + * Using the LOCK prefix on uni-processor machines is significantly slower + * and it is not necessary. The overhead of the conditional below is + * negligible in comparison. Since an optimised DLL will inline this + * routine, this will be faster than calling the system supplied + * Interlocked routine, which appears to avoid the LOCK prefix on + * uniprocessor systems. So one DLL works for all systems. + */ + if (1) //ptw32_smp_system) + +/* *INDENT-OFF* */ + +#if defined(_M_IX86) || defined(_X86_) + +#if defined(_MSC_VER) || defined(__WATCOMC__) || (defined(__BORLANDC__) && defined(HAVE_TASM32)) +#define HAVE_INLINABLE_INTERLOCKED_CMPXCHG + { + _asm { + //PUSH ecx + //PUSH edx + MOV ecx,dword ptr [location] + MOV edx,dword ptr [value] + MOV eax,dword ptr [comparand] + LOCK CMPXCHG dword ptr [ecx],edx + MOV dword ptr [result], eax + //POP edx + //POP ecx + } + } + else + { + _asm { + //PUSH ecx + //PUSH edx + MOV ecx,dword ptr [location] + MOV edx,dword ptr [value] + MOV eax,dword ptr [comparand] + CMPXCHG dword ptr [ecx],edx + MOV dword ptr [result], eax + //POP edx + //POP ecx + } + } + +#elif defined(__GNUC__) +#define HAVE_INLINABLE_INTERLOCKED_CMPXCHG + + { + __asm__ __volatile__ + ( + "lock\n\t" + "cmpxchgl %2,%1" /* if (EAX == [location]) */ + /* [location] = value */ + /* else */ + /* EAX = [location] */ + :"=a" (result) + :"m" (*location), "r" (value), "a" (comparand)); + } + else + { + __asm__ __volatile__ + ( + "cmpxchgl %2,%1" /* if (EAX == [location]) */ + /* [location] = value */ + /* else */ + /* EAX = [location] */ + :"=a" (result) + :"m" (*location), "r" (value), "a" (comparand)); + } + +#endif + +#else + + /* + * If execution gets to here then we're running on a currently + * unsupported processor or compiler. + */ + + result = 0; + +#endif + +/* *INDENT-ON* */ + + return result; + +#if defined(__WATCOMC__) +#pragma enable_message (200) +#endif + +} + +/* + * ptw32_InterlockedExchange -- + * + * We now use this version wherever possible so we can inline it. + */ + +INLINE LONG WINAPI +ptw32_InterlockedExchange (volatile PTW32_INTERLOCKED_LPLONG location, + LONG value) +{ + +#if defined(__WATCOMC__) +/* Don't report that result is not assigned a value before being referenced */ +#pragma disable_message (200) +#endif + + LONG result; + + /* + * The XCHG instruction always locks the bus with or without the + * LOCKED prefix. This makes it significantly slower than CMPXCHG on + * uni-processor machines. The Windows InterlockedExchange function + * is nearly 3 times faster than the XCHG instruction, so this routine + * is not yet very useful for speeding up pthreads. + */ + if (1) //ptw32_smp_system) + +/* *INDENT-OFF* */ + +#if defined(_M_IX86) || defined(_X86_) + +#if defined(_MSC_VER) || defined(__WATCOMC__) || (defined(__BORLANDC__) && defined(HAVE_TASM32)) +#define HAVE_INLINABLE_INTERLOCKED_XCHG + + { + _asm { + //PUSH ecx + MOV ecx,dword ptr [location] + MOV eax,dword ptr [value] + XCHG dword ptr [ecx],eax + MOV dword ptr [result], eax + //POP ecx + } + } + else + { + /* + * Faster version of XCHG for uni-processor systems because + * it doesn't lock the bus. If an interrupt or context switch + * occurs between the MOV and the CMPXCHG then the value in + * 'location' may have changed, in which case we will loop + * back to do the MOV again. + * + * FIXME! Need memory barriers for the MOV+CMPXCHG combo? + * + * Tests show that this routine has almost identical timing + * to Win32's InterlockedExchange(), which is much faster than + * using the inlined 'xchg' instruction above, so it's probably + * doing something similar to this (on UP systems). + * + * Can we do without the PUSH/POP instructions? + */ + _asm { + //PUSH ecx + //PUSH edx + MOV ecx,dword ptr [location] + MOV edx,dword ptr [value] +L1: MOV eax,dword ptr [ecx] + CMPXCHG dword ptr [ecx],edx + JNZ L1 + MOV dword ptr [result], eax + //POP edx + //POP ecx + } + } + +#elif defined(__GNUC__) +#define HAVE_INLINABLE_INTERLOCKED_XCHG + + { + __asm__ __volatile__ + ( + "xchgl %2,%1" + :"=r" (result) + :"m" (*location), "0" (value)); + } + else + { + /* + * Faster version of XCHG for uni-processor systems because + * it doesn't lock the bus. If an interrupt or context switch + * occurs between the movl and the cmpxchgl then the value in + * 'location' may have changed, in which case we will loop + * back to do the movl again. + * + * FIXME! Need memory barriers for the MOV+CMPXCHG combo? + * + * Tests show that this routine has almost identical timing + * to Win32's InterlockedExchange(), which is much faster than + * using the an inlined 'xchg' instruction, so it's probably + * doing something similar to this (on UP systems). + */ + __asm__ __volatile__ + ( + "0:\n\t" + "movl %1,%%eax\n\t" + "cmpxchgl %2,%1\n\t" + "jnz 0b" + :"=&a" (result) + :"m" (*location), "r" (value)); + } + +#endif + +#else + + /* + * If execution gets to here then we're running on a currently + * unsupported processor or compiler. + */ + + result = 0; + +#endif + +/* *INDENT-ON* */ + + return result; + +#if defined(__WATCOMC__) +#pragma enable_message (200) +#endif + +} + + +#if 1 + +#if defined(PTW32_BUILD_INLINED) && defined(HAVE_INLINABLE_INTERLOCKED_CMPXCHG) +#undef PTW32_INTERLOCKED_COMPARE_EXCHANGE +#define PTW32_INTERLOCKED_COMPARE_EXCHANGE ptw32_InterlockedCompareExchange +#endif + +#if defined(PTW32_BUILD_INLINED) && defined(HAVE_INLINABLE_INTERLOCKED_XCHG) +#undef PTW32_INTERLOCKED_EXCHANGE +#define PTW32_INTERLOCKED_EXCHANGE ptw32_InterlockedExchange +#endif + +#endif diff --git a/pcsx2/windows/pthreads/ptw32_MCS_lock.c b/pcsx2/windows/pthreads/ptw32_MCS_lock.c index 414e04bdc6..6b797c546f 100644 --- a/pcsx2/windows/pthreads/ptw32_MCS_lock.c +++ b/pcsx2/windows/pthreads/ptw32_MCS_lock.c @@ -1,210 +1,210 @@ -/* - * ptw32_MCS_lock.c - * - * Description: - * This translation unit implements queue-based locks. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -/* - * About MCS locks: - * - * MCS locks are queue-based locks, where the queue nodes are local to the - * thread. The 'lock' is nothing more than a global pointer that points to - * the last node in the queue, or is NULL if the queue is empty. - * - * Originally designed for use as spin locks requiring no kernel resources - * for synchronisation or blocking, the implementation below has adapted - * the MCS spin lock for use as a general mutex that will suspend threads - * when there is lock contention. - * - * Because the queue nodes are thread-local, most of the memory read/write - * operations required to add or remove nodes from the queue do not trigger - * cache-coherence updates. - * - * Like 'named' mutexes, MCS locks consume system resources transiently - - * they are able to acquire and free resources automatically - but MCS - * locks do not require any unique 'name' to identify the lock to all - * threads using it. - * - * Usage of MCS locks: - * - * - you need a global ptw32_mcs_lock_t instance initialised to 0 or NULL. - * - you need a local thread-scope ptw32_mcs_local_node_t instance, which - * may serve several different locks but you need at least one node for - * every lock held concurrently by a thread. - * - * E.g.: - * - * ptw32_mcs_lock_t lock1 = 0; - * ptw32_mcs_lock_t lock2 = 0; - * - * void *mythread(void *arg) - * { - * ptw32_mcs_local_node_t node; - * - * ptw32_mcs_acquire (&lock1, &node); - * ptw32_mcs_release (&node); - * - * ptw32_mcs_acquire (&lock2, &node); - * ptw32_mcs_release (&node); - * { - * ptw32_mcs_local_node_t nodex; - * - * ptw32_mcs_acquire (&lock1, &node); - * ptw32_mcs_acquire (&lock2, &nodex); - * - * ptw32_mcs_release (&nodex); - * ptw32_mcs_release (&node); - * } - * return (void *)0; - * } - */ - -#include "pthread.h" -#include "implement.h" - -/* - * ptw32_mcs_flag_set -- notify another thread about an event. - * - * Set event if an event handle has been stored in the flag, and - * set flag to -1 otherwise. Note that -1 cannot be a valid handle value. - */ -INLINE void -ptw32_mcs_flag_set (LONG * flag) -{ - HANDLE e = (HANDLE)PTW32_INTERLOCKED_COMPARE_EXCHANGE( - (PTW32_INTERLOCKED_LPLONG)flag, - (PTW32_INTERLOCKED_LONG)-1, - (PTW32_INTERLOCKED_LONG)0); - if ((HANDLE)0 != e) - { - /* another thread has already stored an event handle in the flag */ - SetEvent(e); - } -} - -/* - * ptw32_mcs_flag_set -- wait for notification from another. - * - * Store an event handle in the flag and wait on it if the flag has not been - * set, and proceed without creating an event otherwise. - */ -INLINE void -ptw32_mcs_flag_wait (LONG * flag) -{ - if (0 == InterlockedExchangeAdd((LPLONG)flag, 0)) /* MBR fence */ - { - /* the flag is not set. create event. */ - - HANDLE e = CreateEvent(NULL, PTW32_FALSE, PTW32_FALSE, NULL); - - if (0 == PTW32_INTERLOCKED_COMPARE_EXCHANGE( - (PTW32_INTERLOCKED_LPLONG)flag, - (PTW32_INTERLOCKED_LONG)e, - (PTW32_INTERLOCKED_LONG)0)) - { - /* stored handle in the flag. wait on it now. */ - WaitForSingleObject(e, INFINITE); - } - - CloseHandle(e); - } -} - -/* - * ptw32_mcs_lock_acquire -- acquire an MCS lock. - * - * See: - * J. M. Mellor-Crummey and M. L. Scott. - * Algorithms for Scalable Synchronization on Shared-Memory Multiprocessors. - * ACM Transactions on Computer Systems, 9(1):21-65, Feb. 1991. - */ -INLINE void -ptw32_mcs_lock_acquire (ptw32_mcs_lock_t * lock, ptw32_mcs_local_node_t * node) -{ - ptw32_mcs_local_node_t *pred; - - node->lock = lock; - node->nextFlag = 0; - node->readyFlag = 0; - node->next = 0; /* initially, no successor */ - - /* queue for the lock */ - pred = (ptw32_mcs_local_node_t *)PTW32_INTERLOCKED_EXCHANGE((LPLONG)lock, - (LONG)node); - - if (0 != pred) - { - /* the lock was not free. link behind predecessor. */ - pred->next = node; - ptw32_mcs_flag_set(&pred->nextFlag); - ptw32_mcs_flag_wait(&node->readyFlag); - } -} - -/* - * ptw32_mcs_lock_release -- release an MCS lock. - * - * See: - * J. M. Mellor-Crummey and M. L. Scott. - * Algorithms for Scalable Synchronization on Shared-Memory Multiprocessors. - * ACM Transactions on Computer Systems, 9(1):21-65, Feb. 1991. - */ -INLINE void -ptw32_mcs_lock_release (ptw32_mcs_local_node_t * node) -{ - ptw32_mcs_lock_t *lock = node->lock; - ptw32_mcs_local_node_t *next = (ptw32_mcs_local_node_t *) - InterlockedExchangeAdd((LPLONG)&node->next, 0); /* MBR fence */ - - if (0 == next) - { - /* no known successor */ - - if (node == (ptw32_mcs_local_node_t *) - PTW32_INTERLOCKED_COMPARE_EXCHANGE((PTW32_INTERLOCKED_LPLONG)lock, - (PTW32_INTERLOCKED_LONG)0, - (PTW32_INTERLOCKED_LONG)node)) - { - /* no successor, lock is free now */ - return; - } - - /* wait for successor */ - ptw32_mcs_flag_wait(&node->nextFlag); - next = (ptw32_mcs_local_node_t *) - InterlockedExchangeAdd((LPLONG)&node->next, 0); /* MBR fence */ - } - - /* pass the lock */ - ptw32_mcs_flag_set(&next->readyFlag); -} +/* + * ptw32_MCS_lock.c + * + * Description: + * This translation unit implements queue-based locks. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* + * About MCS locks: + * + * MCS locks are queue-based locks, where the queue nodes are local to the + * thread. The 'lock' is nothing more than a global pointer that points to + * the last node in the queue, or is NULL if the queue is empty. + * + * Originally designed for use as spin locks requiring no kernel resources + * for synchronisation or blocking, the implementation below has adapted + * the MCS spin lock for use as a general mutex that will suspend threads + * when there is lock contention. + * + * Because the queue nodes are thread-local, most of the memory read/write + * operations required to add or remove nodes from the queue do not trigger + * cache-coherence updates. + * + * Like 'named' mutexes, MCS locks consume system resources transiently - + * they are able to acquire and free resources automatically - but MCS + * locks do not require any unique 'name' to identify the lock to all + * threads using it. + * + * Usage of MCS locks: + * + * - you need a global ptw32_mcs_lock_t instance initialised to 0 or NULL. + * - you need a local thread-scope ptw32_mcs_local_node_t instance, which + * may serve several different locks but you need at least one node for + * every lock held concurrently by a thread. + * + * E.g.: + * + * ptw32_mcs_lock_t lock1 = 0; + * ptw32_mcs_lock_t lock2 = 0; + * + * void *mythread(void *arg) + * { + * ptw32_mcs_local_node_t node; + * + * ptw32_mcs_acquire (&lock1, &node); + * ptw32_mcs_release (&node); + * + * ptw32_mcs_acquire (&lock2, &node); + * ptw32_mcs_release (&node); + * { + * ptw32_mcs_local_node_t nodex; + * + * ptw32_mcs_acquire (&lock1, &node); + * ptw32_mcs_acquire (&lock2, &nodex); + * + * ptw32_mcs_release (&nodex); + * ptw32_mcs_release (&node); + * } + * return (void *)0; + * } + */ + +#include "pthread.h" +#include "implement.h" + +/* + * ptw32_mcs_flag_set -- notify another thread about an event. + * + * Set event if an event handle has been stored in the flag, and + * set flag to -1 otherwise. Note that -1 cannot be a valid handle value. + */ +INLINE void +ptw32_mcs_flag_set (LONG * flag) +{ + HANDLE e = (HANDLE)PTW32_INTERLOCKED_COMPARE_EXCHANGE( + (PTW32_INTERLOCKED_LPLONG)flag, + (PTW32_INTERLOCKED_LONG)-1, + (PTW32_INTERLOCKED_LONG)0); + if ((HANDLE)0 != e) + { + /* another thread has already stored an event handle in the flag */ + SetEvent(e); + } +} + +/* + * ptw32_mcs_flag_set -- wait for notification from another. + * + * Store an event handle in the flag and wait on it if the flag has not been + * set, and proceed without creating an event otherwise. + */ +INLINE void +ptw32_mcs_flag_wait (LONG * flag) +{ + if (0 == InterlockedExchangeAdd((LPLONG)flag, 0)) /* MBR fence */ + { + /* the flag is not set. create event. */ + + HANDLE e = CreateEvent(NULL, PTW32_FALSE, PTW32_FALSE, NULL); + + if (0 == PTW32_INTERLOCKED_COMPARE_EXCHANGE( + (PTW32_INTERLOCKED_LPLONG)flag, + (PTW32_INTERLOCKED_LONG)e, + (PTW32_INTERLOCKED_LONG)0)) + { + /* stored handle in the flag. wait on it now. */ + WaitForSingleObject(e, INFINITE); + } + + CloseHandle(e); + } +} + +/* + * ptw32_mcs_lock_acquire -- acquire an MCS lock. + * + * See: + * J. M. Mellor-Crummey and M. L. Scott. + * Algorithms for Scalable Synchronization on Shared-Memory Multiprocessors. + * ACM Transactions on Computer Systems, 9(1):21-65, Feb. 1991. + */ +INLINE void +ptw32_mcs_lock_acquire (ptw32_mcs_lock_t * lock, ptw32_mcs_local_node_t * node) +{ + ptw32_mcs_local_node_t *pred; + + node->lock = lock; + node->nextFlag = 0; + node->readyFlag = 0; + node->next = 0; /* initially, no successor */ + + /* queue for the lock */ + pred = (ptw32_mcs_local_node_t *)PTW32_INTERLOCKED_EXCHANGE((LPLONG)lock, + (LONG)node); + + if (0 != pred) + { + /* the lock was not free. link behind predecessor. */ + pred->next = node; + ptw32_mcs_flag_set(&pred->nextFlag); + ptw32_mcs_flag_wait(&node->readyFlag); + } +} + +/* + * ptw32_mcs_lock_release -- release an MCS lock. + * + * See: + * J. M. Mellor-Crummey and M. L. Scott. + * Algorithms for Scalable Synchronization on Shared-Memory Multiprocessors. + * ACM Transactions on Computer Systems, 9(1):21-65, Feb. 1991. + */ +INLINE void +ptw32_mcs_lock_release (ptw32_mcs_local_node_t * node) +{ + ptw32_mcs_lock_t *lock = node->lock; + ptw32_mcs_local_node_t *next = (ptw32_mcs_local_node_t *) + InterlockedExchangeAdd((LPLONG)&node->next, 0); /* MBR fence */ + + if (0 == next) + { + /* no known successor */ + + if (node == (ptw32_mcs_local_node_t *) + PTW32_INTERLOCKED_COMPARE_EXCHANGE((PTW32_INTERLOCKED_LPLONG)lock, + (PTW32_INTERLOCKED_LONG)0, + (PTW32_INTERLOCKED_LONG)node)) + { + /* no successor, lock is free now */ + return; + } + + /* wait for successor */ + ptw32_mcs_flag_wait(&node->nextFlag); + next = (ptw32_mcs_local_node_t *) + InterlockedExchangeAdd((LPLONG)&node->next, 0); /* MBR fence */ + } + + /* pass the lock */ + ptw32_mcs_flag_set(&next->readyFlag); +} diff --git a/pcsx2/windows/pthreads/ptw32_callUserDestroyRoutines.c b/pcsx2/windows/pthreads/ptw32_callUserDestroyRoutines.c index 48ea23cf31..a583f188d9 100644 --- a/pcsx2/windows/pthreads/ptw32_callUserDestroyRoutines.c +++ b/pcsx2/windows/pthreads/ptw32_callUserDestroyRoutines.c @@ -1,220 +1,220 @@ -/* - * ptw32_callUserDestroyRoutines.c - * - * Description: - * This translation unit implements routines which are private to - * the implementation and may be used throughout it. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -#ifdef __cplusplus -# if ! defined (_MSC_VER) && ! (defined(__GNUC__) && __GNUC__ < 3) && ! defined(__WATCOMC__) -using - std::terminate; -# endif -#endif - -void -ptw32_callUserDestroyRoutines (pthread_t thread) - /* - * ------------------------------------------------------------------- - * DOCPRIVATE - * - * This the routine runs through all thread keys and calls - * the destroy routines on the user's data for the current thread. - * It simulates the behaviour of POSIX Threads. - * - * PARAMETERS - * thread - * an instance of pthread_t - * - * RETURNS - * N/A - * ------------------------------------------------------------------- - */ -{ - ThreadKeyAssoc * assoc; - - if (thread.p != NULL) - { - int assocsRemaining; - int iterations = 0; - ptw32_thread_t * sp = (ptw32_thread_t *) thread.p; - - /* - * Run through all Thread<-->Key associations - * for the current thread. - * - * Do this process at most PTHREAD_DESTRUCTOR_ITERATIONS times. - */ - do - { - assocsRemaining = 0; - iterations++; - - (void) pthread_mutex_lock(&(sp->threadLock)); - /* - * The pointer to the next assoc is stored in the thread struct so that - * the assoc destructor in pthread_key_delete can adjust it - * if it deletes this assoc. This can happen if we fail to acquire - * both locks below, and are forced to release all of our locks, - * leaving open the opportunity for pthread_key_delete to get in - * before us. - */ - sp->nextAssoc = sp->keys; - (void) pthread_mutex_unlock(&(sp->threadLock)); - - for (;;) - { - void * value; - pthread_key_t k; - void (*destructor) (void *); - - /* - * First we need to serialise with pthread_key_delete by locking - * both assoc guards, but in the reverse order to our convention, - * so we must be careful to avoid deadlock. - */ - (void) pthread_mutex_lock(&(sp->threadLock)); - - if ((assoc = (ThreadKeyAssoc *)sp->nextAssoc) == NULL) - { - /* Finished */ - pthread_mutex_unlock(&(sp->threadLock)); - break; - } - else - { - /* - * assoc->key must be valid because assoc can't change or be - * removed from our chain while we hold at least one lock. If - * the assoc was on our key chain then the key has not been - * deleted yet. - * - * Now try to acquire the second lock without deadlocking. - * If we fail, we need to relinquish the first lock and the - * processor and then try to acquire them all again. - */ - if (pthread_mutex_trylock(&(assoc->key->keyLock)) == EBUSY) - { - pthread_mutex_unlock(&(sp->threadLock)); - Sleep(1); // Ugly but necessary to avoid priority effects. - /* - * Go around again. - * If pthread_key_delete has removed this assoc in the meantime, - * sp->nextAssoc will point to a new assoc. - */ - continue; - } - } - - /* We now hold both locks */ - - sp->nextAssoc = assoc->nextKey; - - /* - * Key still active; pthread_key_delete - * will block on these same mutexes before - * it can release actual key; therefore, - * key is valid and we can call the destroy - * routine; - */ - k = assoc->key; - destructor = k->destructor; - value = TlsGetValue(k->key); - TlsSetValue (k->key, NULL); - - // Every assoc->key exists and has a destructor - if (value != NULL && iterations <= PTHREAD_DESTRUCTOR_ITERATIONS) - { - /* - * Unlock both locks before the destructor runs. - * POSIX says pthread_key_delete can be run from destructors, - * and that probably includes with this key as target. - * pthread_setspecific can also be run from destructors and - * also needs to be able to access the assocs. - */ - (void) pthread_mutex_unlock(&(sp->threadLock)); - (void) pthread_mutex_unlock(&(k->keyLock)); - - assocsRemaining++; - -#ifdef __cplusplus - - try - { - /* - * Run the caller's cleanup routine. - */ - destructor (value); - } - catch (...) - { - /* - * A system unexpected exception has occurred - * running the user's destructor. - * We get control back within this block in case - * the application has set up it's own terminate - * handler. Since we are leaving the thread we - * should not get any internal pthreads - * exceptions. - */ - terminate (); - } - -#else /* __cplusplus */ - - /* - * Run the caller's cleanup routine. - */ - destructor (value); - -#endif /* __cplusplus */ - - } - else - { - /* - * Remove association from both the key and thread chains - * and reclaim it's memory resources. - */ - ptw32_tkAssocDestroy (assoc); - (void) pthread_mutex_unlock(&(sp->threadLock)); - (void) pthread_mutex_unlock(&(k->keyLock)); - } - } - } - while (assocsRemaining); - } -} /* ptw32_callUserDestroyRoutines */ +/* + * ptw32_callUserDestroyRoutines.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +#ifdef __cplusplus +# if ! defined (_MSC_VER) && ! (defined(__GNUC__) && __GNUC__ < 3) && ! defined(__WATCOMC__) +using + std::terminate; +# endif +#endif + +void +ptw32_callUserDestroyRoutines (pthread_t thread) + /* + * ------------------------------------------------------------------- + * DOCPRIVATE + * + * This the routine runs through all thread keys and calls + * the destroy routines on the user's data for the current thread. + * It simulates the behaviour of POSIX Threads. + * + * PARAMETERS + * thread + * an instance of pthread_t + * + * RETURNS + * N/A + * ------------------------------------------------------------------- + */ +{ + ThreadKeyAssoc * assoc; + + if (thread.p != NULL) + { + int assocsRemaining; + int iterations = 0; + ptw32_thread_t * sp = (ptw32_thread_t *) thread.p; + + /* + * Run through all Thread<-->Key associations + * for the current thread. + * + * Do this process at most PTHREAD_DESTRUCTOR_ITERATIONS times. + */ + do + { + assocsRemaining = 0; + iterations++; + + (void) pthread_mutex_lock(&(sp->threadLock)); + /* + * The pointer to the next assoc is stored in the thread struct so that + * the assoc destructor in pthread_key_delete can adjust it + * if it deletes this assoc. This can happen if we fail to acquire + * both locks below, and are forced to release all of our locks, + * leaving open the opportunity for pthread_key_delete to get in + * before us. + */ + sp->nextAssoc = sp->keys; + (void) pthread_mutex_unlock(&(sp->threadLock)); + + for (;;) + { + void * value; + pthread_key_t k; + void (*destructor) (void *); + + /* + * First we need to serialise with pthread_key_delete by locking + * both assoc guards, but in the reverse order to our convention, + * so we must be careful to avoid deadlock. + */ + (void) pthread_mutex_lock(&(sp->threadLock)); + + if ((assoc = (ThreadKeyAssoc *)sp->nextAssoc) == NULL) + { + /* Finished */ + pthread_mutex_unlock(&(sp->threadLock)); + break; + } + else + { + /* + * assoc->key must be valid because assoc can't change or be + * removed from our chain while we hold at least one lock. If + * the assoc was on our key chain then the key has not been + * deleted yet. + * + * Now try to acquire the second lock without deadlocking. + * If we fail, we need to relinquish the first lock and the + * processor and then try to acquire them all again. + */ + if (pthread_mutex_trylock(&(assoc->key->keyLock)) == EBUSY) + { + pthread_mutex_unlock(&(sp->threadLock)); + Sleep(1); // Ugly but necessary to avoid priority effects. + /* + * Go around again. + * If pthread_key_delete has removed this assoc in the meantime, + * sp->nextAssoc will point to a new assoc. + */ + continue; + } + } + + /* We now hold both locks */ + + sp->nextAssoc = assoc->nextKey; + + /* + * Key still active; pthread_key_delete + * will block on these same mutexes before + * it can release actual key; therefore, + * key is valid and we can call the destroy + * routine; + */ + k = assoc->key; + destructor = k->destructor; + value = TlsGetValue(k->key); + TlsSetValue (k->key, NULL); + + // Every assoc->key exists and has a destructor + if (value != NULL && iterations <= PTHREAD_DESTRUCTOR_ITERATIONS) + { + /* + * Unlock both locks before the destructor runs. + * POSIX says pthread_key_delete can be run from destructors, + * and that probably includes with this key as target. + * pthread_setspecific can also be run from destructors and + * also needs to be able to access the assocs. + */ + (void) pthread_mutex_unlock(&(sp->threadLock)); + (void) pthread_mutex_unlock(&(k->keyLock)); + + assocsRemaining++; + +#ifdef __cplusplus + + try + { + /* + * Run the caller's cleanup routine. + */ + destructor (value); + } + catch (...) + { + /* + * A system unexpected exception has occurred + * running the user's destructor. + * We get control back within this block in case + * the application has set up it's own terminate + * handler. Since we are leaving the thread we + * should not get any internal pthreads + * exceptions. + */ + terminate (); + } + +#else /* __cplusplus */ + + /* + * Run the caller's cleanup routine. + */ + destructor (value); + +#endif /* __cplusplus */ + + } + else + { + /* + * Remove association from both the key and thread chains + * and reclaim it's memory resources. + */ + ptw32_tkAssocDestroy (assoc); + (void) pthread_mutex_unlock(&(sp->threadLock)); + (void) pthread_mutex_unlock(&(k->keyLock)); + } + } + } + while (assocsRemaining); + } +} /* ptw32_callUserDestroyRoutines */ diff --git a/pcsx2/windows/pthreads/ptw32_calloc.c b/pcsx2/windows/pthreads/ptw32_calloc.c index 5389335c1e..eea7c74828 100644 --- a/pcsx2/windows/pthreads/ptw32_calloc.c +++ b/pcsx2/windows/pthreads/ptw32_calloc.c @@ -1,56 +1,56 @@ -/* - * ptw32_calloc.c - * - * Description: - * This translation unit implements miscellaneous thread functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -#ifdef NEED_CALLOC -void * -ptw32_calloc (size_t n, size_t s) -{ - unsigned int m = n * s; - void *p; - - p = malloc (m); - if (p == NULL) - return NULL; - - memset (p, 0, m); - - return p; -} -#endif +/* + * ptw32_calloc.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +#ifdef NEED_CALLOC +void * +ptw32_calloc (size_t n, size_t s) +{ + unsigned int m = n * s; + void *p; + + p = malloc (m); + if (p == NULL) + return NULL; + + memset (p, 0, m); + + return p; +} +#endif diff --git a/pcsx2/windows/pthreads/ptw32_cond_check_need_init.c b/pcsx2/windows/pthreads/ptw32_cond_check_need_init.c index d4e1634fba..31359ad3fd 100644 --- a/pcsx2/windows/pthreads/ptw32_cond_check_need_init.c +++ b/pcsx2/windows/pthreads/ptw32_cond_check_need_init.c @@ -1,94 +1,94 @@ -/* - * ptw32_cond_check_need_init.c - * - * Description: - * This translation unit implements condition variables and their primitives. - * - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -INLINE int -ptw32_cond_check_need_init (pthread_cond_t * cond) -{ - int result = 0; - - /* - * The following guarded test is specifically for statically - * initialised condition variables (via PTHREAD_OBJECT_INITIALIZER). - * - * Note that by not providing this synchronisation we risk - * introducing race conditions into applications which are - * correctly written. - * - * Approach - * -------- - * We know that static condition variables will not be PROCESS_SHARED - * so we can serialise access to internal state using - * Win32 Critical Sections rather than Win32 Mutexes. - * - * If using a single global lock slows applications down too much, - * multiple global locks could be created and hashed on some random - * value associated with each mutex, the pointer perhaps. At a guess, - * a good value for the optimal number of global locks might be - * the number of processors + 1. - * - */ - EnterCriticalSection (&ptw32_cond_test_init_lock); - - /* - * We got here possibly under race - * conditions. Check again inside the critical section. - * If a static cv has been destroyed, the application can - * re-initialise it only by calling pthread_cond_init() - * explicitly. - */ - if (*cond == PTHREAD_COND_INITIALIZER) - { - result = pthread_cond_init (cond, NULL); - } - else if (*cond == NULL) - { - /* - * The cv has been destroyed while we were waiting to - * initialise it, so the operation that caused the - * auto-initialisation should fail. - */ - result = EINVAL; - } - - LeaveCriticalSection (&ptw32_cond_test_init_lock); - - return result; -} +/* + * ptw32_cond_check_need_init.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +INLINE int +ptw32_cond_check_need_init (pthread_cond_t * cond) +{ + int result = 0; + + /* + * The following guarded test is specifically for statically + * initialised condition variables (via PTHREAD_OBJECT_INITIALIZER). + * + * Note that by not providing this synchronisation we risk + * introducing race conditions into applications which are + * correctly written. + * + * Approach + * -------- + * We know that static condition variables will not be PROCESS_SHARED + * so we can serialise access to internal state using + * Win32 Critical Sections rather than Win32 Mutexes. + * + * If using a single global lock slows applications down too much, + * multiple global locks could be created and hashed on some random + * value associated with each mutex, the pointer perhaps. At a guess, + * a good value for the optimal number of global locks might be + * the number of processors + 1. + * + */ + EnterCriticalSection (&ptw32_cond_test_init_lock); + + /* + * We got here possibly under race + * conditions. Check again inside the critical section. + * If a static cv has been destroyed, the application can + * re-initialise it only by calling pthread_cond_init() + * explicitly. + */ + if (*cond == PTHREAD_COND_INITIALIZER) + { + result = pthread_cond_init (cond, NULL); + } + else if (*cond == NULL) + { + /* + * The cv has been destroyed while we were waiting to + * initialise it, so the operation that caused the + * auto-initialisation should fail. + */ + result = EINVAL; + } + + LeaveCriticalSection (&ptw32_cond_test_init_lock); + + return result; +} diff --git a/pcsx2/windows/pthreads/ptw32_getprocessors.c b/pcsx2/windows/pthreads/ptw32_getprocessors.c index 7772ec7fbf..e60c3143f9 100644 --- a/pcsx2/windows/pthreads/ptw32_getprocessors.c +++ b/pcsx2/windows/pthreads/ptw32_getprocessors.c @@ -1,91 +1,91 @@ -/* - * ptw32_getprocessors.c - * - * Description: - * This translation unit implements routines which are private to - * the implementation and may be used throughout it. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -/* - * ptw32_getprocessors() - * - * Get the number of CPUs available to the process. - * - * If the available number of CPUs is 1 then pthread_spin_lock() - * will block rather than spin if the lock is already owned. - * - * pthread_spin_init() calls this routine when initialising - * a spinlock. If the number of available processors changes - * (after a call to SetProcessAffinityMask()) then only - * newly initialised spinlocks will notice. - */ -int -ptw32_getprocessors (int *count) -{ - DWORD_PTR vProcessCPUs; - DWORD_PTR vSystemCPUs; - int result = 0; - -#if defined(NEED_PROCESS_AFFINITY_MASK) - - *count = 1; - -#else - - if (GetProcessAffinityMask (GetCurrentProcess (), - &vProcessCPUs, &vSystemCPUs)) - { - DWORD_PTR bit; - int CPUs = 0; - - for (bit = 1; bit != 0; bit <<= 1) - { - if (vProcessCPUs & bit) - { - CPUs++; - } - } - *count = CPUs; - } - else - { - result = EAGAIN; - } - -#endif - - return (result); -} +/* + * ptw32_getprocessors.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +/* + * ptw32_getprocessors() + * + * Get the number of CPUs available to the process. + * + * If the available number of CPUs is 1 then pthread_spin_lock() + * will block rather than spin if the lock is already owned. + * + * pthread_spin_init() calls this routine when initialising + * a spinlock. If the number of available processors changes + * (after a call to SetProcessAffinityMask()) then only + * newly initialised spinlocks will notice. + */ +int +ptw32_getprocessors (int *count) +{ + DWORD_PTR vProcessCPUs; + DWORD_PTR vSystemCPUs; + int result = 0; + +#if defined(NEED_PROCESS_AFFINITY_MASK) + + *count = 1; + +#else + + if (GetProcessAffinityMask (GetCurrentProcess (), + &vProcessCPUs, &vSystemCPUs)) + { + DWORD_PTR bit; + int CPUs = 0; + + for (bit = 1; bit != 0; bit <<= 1) + { + if (vProcessCPUs & bit) + { + CPUs++; + } + } + *count = CPUs; + } + else + { + result = EAGAIN; + } + +#endif + + return (result); +} diff --git a/pcsx2/windows/pthreads/ptw32_is_attr.c b/pcsx2/windows/pthreads/ptw32_is_attr.c index fc6fd6b8a6..36395f81f0 100644 --- a/pcsx2/windows/pthreads/ptw32_is_attr.c +++ b/pcsx2/windows/pthreads/ptw32_is_attr.c @@ -1,47 +1,47 @@ -/* - * ptw32_is_attr.c - * - * Description: - * This translation unit implements operations on thread attribute objects. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -int -ptw32_is_attr (const pthread_attr_t * attr) -{ - /* Return 0 if the attr object is valid, non-zero otherwise. */ - - return (attr == NULL || - *attr == NULL || (*attr)->valid != PTW32_ATTR_VALID); -} +/* + * ptw32_is_attr.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +int +ptw32_is_attr (const pthread_attr_t * attr) +{ + /* Return 0 if the attr object is valid, non-zero otherwise. */ + + return (attr == NULL || + *attr == NULL || (*attr)->valid != PTW32_ATTR_VALID); +} diff --git a/pcsx2/windows/pthreads/ptw32_mutex_check_need_init.c b/pcsx2/windows/pthreads/ptw32_mutex_check_need_init.c index 4ab3e7e3c9..35ec366bde 100644 --- a/pcsx2/windows/pthreads/ptw32_mutex_check_need_init.c +++ b/pcsx2/windows/pthreads/ptw32_mutex_check_need_init.c @@ -1,112 +1,112 @@ -/* - * ptw32_mutex_check_need_init.c - * - * Description: - * This translation unit implements mutual exclusion (mutex) primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -static struct pthread_mutexattr_t_ ptw32_recursive_mutexattr_s = - {PTHREAD_PROCESS_PRIVATE, PTHREAD_MUTEX_RECURSIVE}; -static struct pthread_mutexattr_t_ ptw32_errorcheck_mutexattr_s = - {PTHREAD_PROCESS_PRIVATE, PTHREAD_MUTEX_ERRORCHECK}; -static pthread_mutexattr_t ptw32_recursive_mutexattr = &ptw32_recursive_mutexattr_s; -static pthread_mutexattr_t ptw32_errorcheck_mutexattr = &ptw32_errorcheck_mutexattr_s; - - -INLINE int -ptw32_mutex_check_need_init (pthread_mutex_t * mutex) -{ - register int result = 0; - register pthread_mutex_t mtx; - - /* - * The following guarded test is specifically for statically - * initialised mutexes (via PTHREAD_MUTEX_INITIALIZER). - * - * Note that by not providing this synchronisation we risk - * introducing race conditions into applications which are - * correctly written. - * - * Approach - * -------- - * We know that static mutexes will not be PROCESS_SHARED - * so we can serialise access to internal state using - * Win32 Critical Sections rather than Win32 Mutexes. - * - * If using a single global lock slows applications down too much, - * multiple global locks could be created and hashed on some random - * value associated with each mutex, the pointer perhaps. At a guess, - * a good value for the optimal number of global locks might be - * the number of processors + 1. - * - */ - EnterCriticalSection (&ptw32_mutex_test_init_lock); - - /* - * We got here possibly under race - * conditions. Check again inside the critical section - * and only initialise if the mutex is valid (not been destroyed). - * If a static mutex has been destroyed, the application can - * re-initialise it only by calling pthread_mutex_init() - * explicitly. - */ - mtx = *mutex; - - if (mtx == PTHREAD_MUTEX_INITIALIZER) - { - result = pthread_mutex_init (mutex, NULL); - } - else if (mtx == PTHREAD_RECURSIVE_MUTEX_INITIALIZER) - { - result = pthread_mutex_init (mutex, &ptw32_recursive_mutexattr); - } - else if (mtx == PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) - { - result = pthread_mutex_init (mutex, &ptw32_errorcheck_mutexattr); - } - else if (mtx == NULL) - { - /* - * The mutex has been destroyed while we were waiting to - * initialise it, so the operation that caused the - * auto-initialisation should fail. - */ - result = EINVAL; - } - - LeaveCriticalSection (&ptw32_mutex_test_init_lock); - - return (result); -} +/* + * ptw32_mutex_check_need_init.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +static struct pthread_mutexattr_t_ ptw32_recursive_mutexattr_s = + {PTHREAD_PROCESS_PRIVATE, PTHREAD_MUTEX_RECURSIVE}; +static struct pthread_mutexattr_t_ ptw32_errorcheck_mutexattr_s = + {PTHREAD_PROCESS_PRIVATE, PTHREAD_MUTEX_ERRORCHECK}; +static pthread_mutexattr_t ptw32_recursive_mutexattr = &ptw32_recursive_mutexattr_s; +static pthread_mutexattr_t ptw32_errorcheck_mutexattr = &ptw32_errorcheck_mutexattr_s; + + +INLINE int +ptw32_mutex_check_need_init (pthread_mutex_t * mutex) +{ + register int result = 0; + register pthread_mutex_t mtx; + + /* + * The following guarded test is specifically for statically + * initialised mutexes (via PTHREAD_MUTEX_INITIALIZER). + * + * Note that by not providing this synchronisation we risk + * introducing race conditions into applications which are + * correctly written. + * + * Approach + * -------- + * We know that static mutexes will not be PROCESS_SHARED + * so we can serialise access to internal state using + * Win32 Critical Sections rather than Win32 Mutexes. + * + * If using a single global lock slows applications down too much, + * multiple global locks could be created and hashed on some random + * value associated with each mutex, the pointer perhaps. At a guess, + * a good value for the optimal number of global locks might be + * the number of processors + 1. + * + */ + EnterCriticalSection (&ptw32_mutex_test_init_lock); + + /* + * We got here possibly under race + * conditions. Check again inside the critical section + * and only initialise if the mutex is valid (not been destroyed). + * If a static mutex has been destroyed, the application can + * re-initialise it only by calling pthread_mutex_init() + * explicitly. + */ + mtx = *mutex; + + if (mtx == PTHREAD_MUTEX_INITIALIZER) + { + result = pthread_mutex_init (mutex, NULL); + } + else if (mtx == PTHREAD_RECURSIVE_MUTEX_INITIALIZER) + { + result = pthread_mutex_init (mutex, &ptw32_recursive_mutexattr); + } + else if (mtx == PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) + { + result = pthread_mutex_init (mutex, &ptw32_errorcheck_mutexattr); + } + else if (mtx == NULL) + { + /* + * The mutex has been destroyed while we were waiting to + * initialise it, so the operation that caused the + * auto-initialisation should fail. + */ + result = EINVAL; + } + + LeaveCriticalSection (&ptw32_mutex_test_init_lock); + + return (result); +} diff --git a/pcsx2/windows/pthreads/ptw32_new.c b/pcsx2/windows/pthreads/ptw32_new.c index fa4c15dc88..281256741b 100644 --- a/pcsx2/windows/pthreads/ptw32_new.c +++ b/pcsx2/windows/pthreads/ptw32_new.c @@ -1,91 +1,91 @@ -/* - * ptw32_new.c - * - * Description: - * This translation unit implements miscellaneous thread functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -pthread_t -ptw32_new (void) -{ - pthread_t t; - pthread_t nil = {NULL, 0}; - ptw32_thread_t * tp; - - /* - * If there's a reusable pthread_t then use it. - */ - t = ptw32_threadReusePop (); - - if (NULL != t.p) - { - tp = (ptw32_thread_t *) t.p; - } - else - { - /* No reuse threads available */ - tp = (ptw32_thread_t *) calloc (1, sizeof(ptw32_thread_t)); - - if (tp == NULL) - { - return nil; - } - - /* ptHandle.p needs to point to it's parent ptw32_thread_t. */ - t.p = tp->ptHandle.p = tp; - t.x = tp->ptHandle.x = 0; - } - - /* Set default state. */ - tp->sched_priority = THREAD_PRIORITY_NORMAL; - tp->detachState = PTHREAD_CREATE_JOINABLE; - tp->cancelState = PTHREAD_CANCEL_ENABLE; - tp->cancelType = PTHREAD_CANCEL_DEFERRED; - tp->cancelLock = PTHREAD_MUTEX_INITIALIZER; - tp->threadLock = PTHREAD_MUTEX_INITIALIZER; - tp->cancelEvent = CreateEvent (0, (int) PTW32_TRUE, /* manualReset */ - (int) PTW32_FALSE, /* setSignaled */ - NULL); - - if (tp->cancelEvent == NULL) - { - ptw32_threadReusePush (tp->ptHandle); - return nil; - } - - return t; - -} +/* + * ptw32_new.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +pthread_t +ptw32_new (void) +{ + pthread_t t; + pthread_t nil = {NULL, 0}; + ptw32_thread_t * tp; + + /* + * If there's a reusable pthread_t then use it. + */ + t = ptw32_threadReusePop (); + + if (NULL != t.p) + { + tp = (ptw32_thread_t *) t.p; + } + else + { + /* No reuse threads available */ + tp = (ptw32_thread_t *) calloc (1, sizeof(ptw32_thread_t)); + + if (tp == NULL) + { + return nil; + } + + /* ptHandle.p needs to point to it's parent ptw32_thread_t. */ + t.p = tp->ptHandle.p = tp; + t.x = tp->ptHandle.x = 0; + } + + /* Set default state. */ + tp->sched_priority = THREAD_PRIORITY_NORMAL; + tp->detachState = PTHREAD_CREATE_JOINABLE; + tp->cancelState = PTHREAD_CANCEL_ENABLE; + tp->cancelType = PTHREAD_CANCEL_DEFERRED; + tp->cancelLock = PTHREAD_MUTEX_INITIALIZER; + tp->threadLock = PTHREAD_MUTEX_INITIALIZER; + tp->cancelEvent = CreateEvent (0, (int) PTW32_TRUE, /* manualReset */ + (int) PTW32_FALSE, /* setSignaled */ + NULL); + + if (tp->cancelEvent == NULL) + { + ptw32_threadReusePush (tp->ptHandle); + return nil; + } + + return t; + +} diff --git a/pcsx2/windows/pthreads/ptw32_processInitialize.c b/pcsx2/windows/pthreads/ptw32_processInitialize.c index 075e03a4da..d13b0226f0 100644 --- a/pcsx2/windows/pthreads/ptw32_processInitialize.c +++ b/pcsx2/windows/pthreads/ptw32_processInitialize.c @@ -1,102 +1,102 @@ -/* - * ptw32_processInitialize.c - * - * Description: - * This translation unit implements routines which are private to - * the implementation and may be used throughout it. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -ptw32_processInitialize (void) - /* - * ------------------------------------------------------ - * DOCPRIVATE - * This function performs process wide initialization for - * the pthread library. - * - * PARAMETERS - * N/A - * - * DESCRIPTION - * This function performs process wide initialization for - * the pthread library. - * If successful, this routine sets the global variable - * ptw32_processInitialized to TRUE. - * - * RESULTS - * TRUE if successful, - * FALSE otherwise - * - * ------------------------------------------------------ - */ -{ - if (ptw32_processInitialized) - { - /* - * Ignore if already initialized. this is useful for - * programs that uses a non-dll pthread - * library. Such programs must call ptw32_processInitialize() explicitly, - * since this initialization routine is automatically called only when - * the dll is loaded. - */ - return PTW32_TRUE; - } - - ptw32_processInitialized = PTW32_TRUE; - - /* - * Initialize Keys - */ - if ((pthread_key_create (&ptw32_selfThreadKey, NULL) != 0) || - (pthread_key_create (&ptw32_cleanupKey, NULL) != 0)) - { - - ptw32_processTerminate (); - } - - /* - * Set up the global locks. - */ - InitializeCriticalSection (&ptw32_thread_reuse_lock); - InitializeCriticalSection (&ptw32_mutex_test_init_lock); - InitializeCriticalSection (&ptw32_cond_list_lock); - InitializeCriticalSection (&ptw32_cond_test_init_lock); - InitializeCriticalSection (&ptw32_rwlock_test_init_lock); - InitializeCriticalSection (&ptw32_spinlock_test_init_lock); - - return (ptw32_processInitialized); - -} /* processInitialize */ +/* + * ptw32_processInitialize.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +ptw32_processInitialize (void) + /* + * ------------------------------------------------------ + * DOCPRIVATE + * This function performs process wide initialization for + * the pthread library. + * + * PARAMETERS + * N/A + * + * DESCRIPTION + * This function performs process wide initialization for + * the pthread library. + * If successful, this routine sets the global variable + * ptw32_processInitialized to TRUE. + * + * RESULTS + * TRUE if successful, + * FALSE otherwise + * + * ------------------------------------------------------ + */ +{ + if (ptw32_processInitialized) + { + /* + * Ignore if already initialized. this is useful for + * programs that uses a non-dll pthread + * library. Such programs must call ptw32_processInitialize() explicitly, + * since this initialization routine is automatically called only when + * the dll is loaded. + */ + return PTW32_TRUE; + } + + ptw32_processInitialized = PTW32_TRUE; + + /* + * Initialize Keys + */ + if ((pthread_key_create (&ptw32_selfThreadKey, NULL) != 0) || + (pthread_key_create (&ptw32_cleanupKey, NULL) != 0)) + { + + ptw32_processTerminate (); + } + + /* + * Set up the global locks. + */ + InitializeCriticalSection (&ptw32_thread_reuse_lock); + InitializeCriticalSection (&ptw32_mutex_test_init_lock); + InitializeCriticalSection (&ptw32_cond_list_lock); + InitializeCriticalSection (&ptw32_cond_test_init_lock); + InitializeCriticalSection (&ptw32_rwlock_test_init_lock); + InitializeCriticalSection (&ptw32_spinlock_test_init_lock); + + return (ptw32_processInitialized); + +} /* processInitialize */ diff --git a/pcsx2/windows/pthreads/ptw32_processTerminate.c b/pcsx2/windows/pthreads/ptw32_processTerminate.c index dd641bc409..d2dfa7a247 100644 --- a/pcsx2/windows/pthreads/ptw32_processTerminate.c +++ b/pcsx2/windows/pthreads/ptw32_processTerminate.c @@ -1,114 +1,114 @@ -/* - * ptw32_processTerminate.c - * - * Description: - * This translation unit implements routines which are private to - * the implementation and may be used throughout it. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -void -ptw32_processTerminate (void) - /* - * ------------------------------------------------------ - * DOCPRIVATE - * This function performs process wide termination for - * the pthread library. - * - * PARAMETERS - * N/A - * - * DESCRIPTION - * This function performs process wide termination for - * the pthread library. - * This routine sets the global variable - * ptw32_processInitialized to FALSE - * - * RESULTS - * N/A - * - * ------------------------------------------------------ - */ -{ - if (ptw32_processInitialized) - { - ptw32_thread_t * tp, * tpNext; - - if (ptw32_selfThreadKey != NULL) - { - /* - * Release ptw32_selfThreadKey - */ - pthread_key_delete (ptw32_selfThreadKey); - - ptw32_selfThreadKey = NULL; - } - - if (ptw32_cleanupKey != NULL) - { - /* - * Release ptw32_cleanupKey - */ - pthread_key_delete (ptw32_cleanupKey); - - ptw32_cleanupKey = NULL; - } - - EnterCriticalSection (&ptw32_thread_reuse_lock); - - tp = ptw32_threadReuseTop; - while (tp != PTW32_THREAD_REUSE_EMPTY) - { - tpNext = tp->prevReuse; - free (tp); - tp = tpNext; - } - - LeaveCriticalSection (&ptw32_thread_reuse_lock); - - /* - * Destroy the global locks and other objects. - */ - DeleteCriticalSection (&ptw32_spinlock_test_init_lock); - DeleteCriticalSection (&ptw32_rwlock_test_init_lock); - DeleteCriticalSection (&ptw32_cond_test_init_lock); - DeleteCriticalSection (&ptw32_cond_list_lock); - DeleteCriticalSection (&ptw32_mutex_test_init_lock); - DeleteCriticalSection (&ptw32_thread_reuse_lock); - - ptw32_processInitialized = PTW32_FALSE; - } - -} /* processTerminate */ +/* + * ptw32_processTerminate.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +void +ptw32_processTerminate (void) + /* + * ------------------------------------------------------ + * DOCPRIVATE + * This function performs process wide termination for + * the pthread library. + * + * PARAMETERS + * N/A + * + * DESCRIPTION + * This function performs process wide termination for + * the pthread library. + * This routine sets the global variable + * ptw32_processInitialized to FALSE + * + * RESULTS + * N/A + * + * ------------------------------------------------------ + */ +{ + if (ptw32_processInitialized) + { + ptw32_thread_t * tp, * tpNext; + + if (ptw32_selfThreadKey != NULL) + { + /* + * Release ptw32_selfThreadKey + */ + pthread_key_delete (ptw32_selfThreadKey); + + ptw32_selfThreadKey = NULL; + } + + if (ptw32_cleanupKey != NULL) + { + /* + * Release ptw32_cleanupKey + */ + pthread_key_delete (ptw32_cleanupKey); + + ptw32_cleanupKey = NULL; + } + + EnterCriticalSection (&ptw32_thread_reuse_lock); + + tp = ptw32_threadReuseTop; + while (tp != PTW32_THREAD_REUSE_EMPTY) + { + tpNext = tp->prevReuse; + free (tp); + tp = tpNext; + } + + LeaveCriticalSection (&ptw32_thread_reuse_lock); + + /* + * Destroy the global locks and other objects. + */ + DeleteCriticalSection (&ptw32_spinlock_test_init_lock); + DeleteCriticalSection (&ptw32_rwlock_test_init_lock); + DeleteCriticalSection (&ptw32_cond_test_init_lock); + DeleteCriticalSection (&ptw32_cond_list_lock); + DeleteCriticalSection (&ptw32_mutex_test_init_lock); + DeleteCriticalSection (&ptw32_thread_reuse_lock); + + ptw32_processInitialized = PTW32_FALSE; + } + +} /* processTerminate */ diff --git a/pcsx2/windows/pthreads/ptw32_relmillisecs.c b/pcsx2/windows/pthreads/ptw32_relmillisecs.c index b6dc2dad82..01db362313 100644 --- a/pcsx2/windows/pthreads/ptw32_relmillisecs.c +++ b/pcsx2/windows/pthreads/ptw32_relmillisecs.c @@ -1,120 +1,120 @@ -/* - * ptw32_relmillisecs.c - * - * Description: - * This translation unit implements miscellaneous thread functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#ifndef _UWIN -//#include -#endif -#include "pthread.h" -#include "implement.h" -#ifndef NEED_FTIME -#include -#endif - - -INLINE DWORD -ptw32_relmillisecs (const struct timespec * abstime) -{ - const int64_t NANOSEC_PER_MILLISEC = 1000000; - const int64_t MILLISEC_PER_SEC = 1000; - DWORD milliseconds; - int64_t tmpAbsMilliseconds; - int64_t tmpCurrMilliseconds; -#ifdef NEED_FTIME - struct timespec currSysTime; - FILETIME ft; - SYSTEMTIME st; -#else /* ! NEED_FTIME */ - struct _timeb currSysTime; -#endif /* NEED_FTIME */ - - - /* - * Calculate timeout as milliseconds from current system time. - */ - - /* - * subtract current system time from abstime in a way that checks - * that abstime is never in the past, or is never equivalent to the - * defined INFINITE value (0xFFFFFFFF). - * - * Assume all integers are unsigned, i.e. cannot test if less than 0. - */ - tmpAbsMilliseconds = (int64_t)abstime->tv_sec * MILLISEC_PER_SEC; - tmpAbsMilliseconds += ((int64_t)abstime->tv_nsec + (NANOSEC_PER_MILLISEC/2)) / NANOSEC_PER_MILLISEC; - - /* get current system time */ - -#ifdef NEED_FTIME - - GetSystemTime(&st); - SystemTimeToFileTime(&st, &ft); - /* - * GetSystemTimeAsFileTime(&ft); would be faster, - * but it does not exist on WinCE - */ - - ptw32_filetime_to_timespec(&ft, &currSysTime); - - tmpCurrMilliseconds = (int64_t)currSysTime.tv_sec * MILLISEC_PER_SEC; - tmpCurrMilliseconds += ((int64_t)currSysTime.tv_nsec + (NANOSEC_PER_MILLISEC/2)) - / NANOSEC_PER_MILLISEC; - -#else /* ! NEED_FTIME */ - - _ftime64_s(&currSysTime); - - tmpCurrMilliseconds = (int64_t) currSysTime.time * MILLISEC_PER_SEC; - tmpCurrMilliseconds += (int64_t) currSysTime.millitm; - -#endif /* NEED_FTIME */ - - if (tmpAbsMilliseconds > tmpCurrMilliseconds) - { - milliseconds = (DWORD) (tmpAbsMilliseconds - tmpCurrMilliseconds); - if (milliseconds == INFINITE) - { - /* Timeouts must be finite */ - milliseconds--; - } - } - else - { - /* The abstime given is in the past */ - milliseconds = 0; - } - - return milliseconds; -} +/* + * ptw32_relmillisecs.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef _UWIN +//#include +#endif +#include "pthread.h" +#include "implement.h" +#ifndef NEED_FTIME +#include +#endif + + +INLINE DWORD +ptw32_relmillisecs (const struct timespec * abstime) +{ + const int64_t NANOSEC_PER_MILLISEC = 1000000; + const int64_t MILLISEC_PER_SEC = 1000; + DWORD milliseconds; + int64_t tmpAbsMilliseconds; + int64_t tmpCurrMilliseconds; +#ifdef NEED_FTIME + struct timespec currSysTime; + FILETIME ft; + SYSTEMTIME st; +#else /* ! NEED_FTIME */ + struct _timeb currSysTime; +#endif /* NEED_FTIME */ + + + /* + * Calculate timeout as milliseconds from current system time. + */ + + /* + * subtract current system time from abstime in a way that checks + * that abstime is never in the past, or is never equivalent to the + * defined INFINITE value (0xFFFFFFFF). + * + * Assume all integers are unsigned, i.e. cannot test if less than 0. + */ + tmpAbsMilliseconds = (int64_t)abstime->tv_sec * MILLISEC_PER_SEC; + tmpAbsMilliseconds += ((int64_t)abstime->tv_nsec + (NANOSEC_PER_MILLISEC/2)) / NANOSEC_PER_MILLISEC; + + /* get current system time */ + +#ifdef NEED_FTIME + + GetSystemTime(&st); + SystemTimeToFileTime(&st, &ft); + /* + * GetSystemTimeAsFileTime(&ft); would be faster, + * but it does not exist on WinCE + */ + + ptw32_filetime_to_timespec(&ft, &currSysTime); + + tmpCurrMilliseconds = (int64_t)currSysTime.tv_sec * MILLISEC_PER_SEC; + tmpCurrMilliseconds += ((int64_t)currSysTime.tv_nsec + (NANOSEC_PER_MILLISEC/2)) + / NANOSEC_PER_MILLISEC; + +#else /* ! NEED_FTIME */ + + _ftime64_s(&currSysTime); + + tmpCurrMilliseconds = (int64_t) currSysTime.time * MILLISEC_PER_SEC; + tmpCurrMilliseconds += (int64_t) currSysTime.millitm; + +#endif /* NEED_FTIME */ + + if (tmpAbsMilliseconds > tmpCurrMilliseconds) + { + milliseconds = (DWORD) (tmpAbsMilliseconds - tmpCurrMilliseconds); + if (milliseconds == INFINITE) + { + /* Timeouts must be finite */ + milliseconds--; + } + } + else + { + /* The abstime given is in the past */ + milliseconds = 0; + } + + return milliseconds; +} diff --git a/pcsx2/windows/pthreads/ptw32_reuse.c b/pcsx2/windows/pthreads/ptw32_reuse.c index 950759be37..0e86984967 100644 --- a/pcsx2/windows/pthreads/ptw32_reuse.c +++ b/pcsx2/windows/pthreads/ptw32_reuse.c @@ -1,147 +1,147 @@ -/* - * ptw32_threadReuse.c - * - * Description: - * This translation unit implements miscellaneous thread functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -/* - * How it works: - * A pthread_t is a struct (2x32 bit scalar types on IA-32, 2x64 bit on IA-64) - * which is normally passed/returned by value to/from pthreads routines. - * Applications are therefore storing a copy of the struct as it is at that - * time. - * - * The original pthread_t struct plus all copies of it contain the address of - * the thread state struct ptw32_thread_t_ (p), plus a reuse counter (x). Each - * ptw32_thread_t contains the original copy of it's pthread_t. - * Once malloced, a ptw32_thread_t_ struct is not freed until the process exits. - * - * The thread reuse stack is a simple LILO stack managed through a singly - * linked list element in the ptw32_thread_t. - * - * Each time a thread is destroyed, the ptw32_thread_t address is pushed onto the - * reuse stack after it's ptHandle's reuse counter has been incremented. - * - * The following can now be said from this: - * - two pthread_t's are identical if their ptw32_thread_t reference pointers - * are equal and their reuse counters are equal. That is, - * - * equal = (a.p == b.p && a.x == b.x) - * - * - a pthread_t copy refers to a destroyed thread if the reuse counter in - * the copy is not equal to the reuse counter in the original. - * - * threadDestroyed = (copy.x != ((ptw32_thread_t *)copy.p)->ptHandle.x) - * - */ - -/* - * Pop a clean pthread_t struct off the reuse stack. - */ -pthread_t -ptw32_threadReusePop (void) -{ - pthread_t t = {NULL, 0}; - - EnterCriticalSection (&ptw32_thread_reuse_lock); - - if (PTW32_THREAD_REUSE_EMPTY != ptw32_threadReuseTop) - { - ptw32_thread_t * tp; - - tp = ptw32_threadReuseTop; - - ptw32_threadReuseTop = tp->prevReuse; - - if (PTW32_THREAD_REUSE_EMPTY == ptw32_threadReuseTop) - { - ptw32_threadReuseBottom = PTW32_THREAD_REUSE_EMPTY; - } - - tp->prevReuse = NULL; - - t = tp->ptHandle; - } - - LeaveCriticalSection (&ptw32_thread_reuse_lock); - - return t; - -} - -/* - * Push a clean pthread_t struct onto the reuse stack. - * Must be re-initialised when reused. - * All object elements (mutexes, events etc) must have been either - * detroyed before this, or never initialised. - */ -void -ptw32_threadReusePush (pthread_t thread) -{ - ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; - pthread_t t; - - EnterCriticalSection (&ptw32_thread_reuse_lock); - - t = tp->ptHandle; - memset(tp, 0, sizeof(ptw32_thread_t)); - - /* Must restore the original POSIX handle that we just wiped. */ - tp->ptHandle = t; - - /* Bump the reuse counter now */ -#ifdef PTW32_THREAD_ID_REUSE_INCREMENT - tp->ptHandle.x += PTW32_THREAD_ID_REUSE_INCREMENT; -#else - tp->ptHandle.x++; -#endif - - tp->prevReuse = PTW32_THREAD_REUSE_EMPTY; - - if (PTW32_THREAD_REUSE_EMPTY != ptw32_threadReuseBottom) - { - ptw32_threadReuseBottom->prevReuse = tp; - } - else - { - ptw32_threadReuseTop = tp; - } - - ptw32_threadReuseBottom = tp; - - LeaveCriticalSection (&ptw32_thread_reuse_lock); -} +/* + * ptw32_threadReuse.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +/* + * How it works: + * A pthread_t is a struct (2x32 bit scalar types on IA-32, 2x64 bit on IA-64) + * which is normally passed/returned by value to/from pthreads routines. + * Applications are therefore storing a copy of the struct as it is at that + * time. + * + * The original pthread_t struct plus all copies of it contain the address of + * the thread state struct ptw32_thread_t_ (p), plus a reuse counter (x). Each + * ptw32_thread_t contains the original copy of it's pthread_t. + * Once malloced, a ptw32_thread_t_ struct is not freed until the process exits. + * + * The thread reuse stack is a simple LILO stack managed through a singly + * linked list element in the ptw32_thread_t. + * + * Each time a thread is destroyed, the ptw32_thread_t address is pushed onto the + * reuse stack after it's ptHandle's reuse counter has been incremented. + * + * The following can now be said from this: + * - two pthread_t's are identical if their ptw32_thread_t reference pointers + * are equal and their reuse counters are equal. That is, + * + * equal = (a.p == b.p && a.x == b.x) + * + * - a pthread_t copy refers to a destroyed thread if the reuse counter in + * the copy is not equal to the reuse counter in the original. + * + * threadDestroyed = (copy.x != ((ptw32_thread_t *)copy.p)->ptHandle.x) + * + */ + +/* + * Pop a clean pthread_t struct off the reuse stack. + */ +pthread_t +ptw32_threadReusePop (void) +{ + pthread_t t = {NULL, 0}; + + EnterCriticalSection (&ptw32_thread_reuse_lock); + + if (PTW32_THREAD_REUSE_EMPTY != ptw32_threadReuseTop) + { + ptw32_thread_t * tp; + + tp = ptw32_threadReuseTop; + + ptw32_threadReuseTop = tp->prevReuse; + + if (PTW32_THREAD_REUSE_EMPTY == ptw32_threadReuseTop) + { + ptw32_threadReuseBottom = PTW32_THREAD_REUSE_EMPTY; + } + + tp->prevReuse = NULL; + + t = tp->ptHandle; + } + + LeaveCriticalSection (&ptw32_thread_reuse_lock); + + return t; + +} + +/* + * Push a clean pthread_t struct onto the reuse stack. + * Must be re-initialised when reused. + * All object elements (mutexes, events etc) must have been either + * detroyed before this, or never initialised. + */ +void +ptw32_threadReusePush (pthread_t thread) +{ + ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; + pthread_t t; + + EnterCriticalSection (&ptw32_thread_reuse_lock); + + t = tp->ptHandle; + memset(tp, 0, sizeof(ptw32_thread_t)); + + /* Must restore the original POSIX handle that we just wiped. */ + tp->ptHandle = t; + + /* Bump the reuse counter now */ +#ifdef PTW32_THREAD_ID_REUSE_INCREMENT + tp->ptHandle.x += PTW32_THREAD_ID_REUSE_INCREMENT; +#else + tp->ptHandle.x++; +#endif + + tp->prevReuse = PTW32_THREAD_REUSE_EMPTY; + + if (PTW32_THREAD_REUSE_EMPTY != ptw32_threadReuseBottom) + { + ptw32_threadReuseBottom->prevReuse = tp; + } + else + { + ptw32_threadReuseTop = tp; + } + + ptw32_threadReuseBottom = tp; + + LeaveCriticalSection (&ptw32_thread_reuse_lock); +} diff --git a/pcsx2/windows/pthreads/ptw32_rwlock_cancelwrwait.c b/pcsx2/windows/pthreads/ptw32_rwlock_cancelwrwait.c index 7649a3eb1e..a057bd1d72 100644 --- a/pcsx2/windows/pthreads/ptw32_rwlock_cancelwrwait.c +++ b/pcsx2/windows/pthreads/ptw32_rwlock_cancelwrwait.c @@ -1,50 +1,50 @@ -/* - * ptw32_rwlock_cancelwrwait.c - * - * Description: - * This translation unit implements read/write lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -void -ptw32_rwlock_cancelwrwait (void *arg) -{ - pthread_rwlock_t rwl = (pthread_rwlock_t) arg; - - rwl->nSharedAccessCount = -rwl->nCompletedSharedAccessCount; - rwl->nCompletedSharedAccessCount = 0; - - (void) pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted)); - (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); -} +/* + * ptw32_rwlock_cancelwrwait.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +void +ptw32_rwlock_cancelwrwait (void *arg) +{ + pthread_rwlock_t rwl = (pthread_rwlock_t) arg; + + rwl->nSharedAccessCount = -rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + + (void) pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted)); + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); +} diff --git a/pcsx2/windows/pthreads/ptw32_rwlock_check_need_init.c b/pcsx2/windows/pthreads/ptw32_rwlock_check_need_init.c index f615e7c766..ea2561eefb 100644 --- a/pcsx2/windows/pthreads/ptw32_rwlock_check_need_init.c +++ b/pcsx2/windows/pthreads/ptw32_rwlock_check_need_init.c @@ -1,93 +1,93 @@ -/* - * pthread_rwlock_check_need_init.c - * - * Description: - * This translation unit implements read/write lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -INLINE int -ptw32_rwlock_check_need_init (pthread_rwlock_t * rwlock) -{ - int result = 0; - - /* - * The following guarded test is specifically for statically - * initialised rwlocks (via PTHREAD_RWLOCK_INITIALIZER). - * - * Note that by not providing this synchronisation we risk - * introducing race conditions into applications which are - * correctly written. - * - * Approach - * -------- - * We know that static rwlocks will not be PROCESS_SHARED - * so we can serialise access to internal state using - * Win32 Critical Sections rather than Win32 Mutexes. - * - * If using a single global lock slows applications down too much, - * multiple global locks could be created and hashed on some random - * value associated with each mutex, the pointer perhaps. At a guess, - * a good value for the optimal number of global locks might be - * the number of processors + 1. - * - */ - EnterCriticalSection (&ptw32_rwlock_test_init_lock); - - /* - * We got here possibly under race - * conditions. Check again inside the critical section - * and only initialise if the rwlock is valid (not been destroyed). - * If a static rwlock has been destroyed, the application can - * re-initialise it only by calling pthread_rwlock_init() - * explicitly. - */ - if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) - { - result = pthread_rwlock_init (rwlock, NULL); - } - else if (*rwlock == NULL) - { - /* - * The rwlock has been destroyed while we were waiting to - * initialise it, so the operation that caused the - * auto-initialisation should fail. - */ - result = EINVAL; - } - - LeaveCriticalSection (&ptw32_rwlock_test_init_lock); - - return result; -} +/* + * pthread_rwlock_check_need_init.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +INLINE int +ptw32_rwlock_check_need_init (pthread_rwlock_t * rwlock) +{ + int result = 0; + + /* + * The following guarded test is specifically for statically + * initialised rwlocks (via PTHREAD_RWLOCK_INITIALIZER). + * + * Note that by not providing this synchronisation we risk + * introducing race conditions into applications which are + * correctly written. + * + * Approach + * -------- + * We know that static rwlocks will not be PROCESS_SHARED + * so we can serialise access to internal state using + * Win32 Critical Sections rather than Win32 Mutexes. + * + * If using a single global lock slows applications down too much, + * multiple global locks could be created and hashed on some random + * value associated with each mutex, the pointer perhaps. At a guess, + * a good value for the optimal number of global locks might be + * the number of processors + 1. + * + */ + EnterCriticalSection (&ptw32_rwlock_test_init_lock); + + /* + * We got here possibly under race + * conditions. Check again inside the critical section + * and only initialise if the rwlock is valid (not been destroyed). + * If a static rwlock has been destroyed, the application can + * re-initialise it only by calling pthread_rwlock_init() + * explicitly. + */ + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + { + result = pthread_rwlock_init (rwlock, NULL); + } + else if (*rwlock == NULL) + { + /* + * The rwlock has been destroyed while we were waiting to + * initialise it, so the operation that caused the + * auto-initialisation should fail. + */ + result = EINVAL; + } + + LeaveCriticalSection (&ptw32_rwlock_test_init_lock); + + return result; +} diff --git a/pcsx2/windows/pthreads/ptw32_semwait.c b/pcsx2/windows/pthreads/ptw32_semwait.c index 209c8a6e75..8b23d11d62 100644 --- a/pcsx2/windows/pthreads/ptw32_semwait.c +++ b/pcsx2/windows/pthreads/ptw32_semwait.c @@ -1,118 +1,118 @@ -/* - * ptw32_semwait.c - * - * Description: - * This translation unit implements mutual exclusion (mutex) primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#ifndef _UWIN -//# include -#endif -#include "pthread.h" -#include "implement.h" - - -int -ptw32_semwait (sem_t * sem) - /* - * ------------------------------------------------------ - * DESCRIPTION - * This function waits on a POSIX semaphore. If the - * semaphore value is greater than zero, it decreases - * its value by one. If the semaphore value is zero, then - * the calling thread (or process) is blocked until it can - * successfully decrease the value. - * - * Unlike sem_wait(), this routine is non-cancelable. - * - * RESULTS - * 0 successfully decreased semaphore, - * -1 failed, error in errno. - * ERRNO - * EINVAL 'sem' is not a valid semaphore, - * ENOSYS semaphores are not supported, - * EINTR the function was interrupted by a signal, - * EDEADLK a deadlock condition was detected. - * - * ------------------------------------------------------ - */ -{ - int result = 0; - sem_t s = *sem; - - if (s == NULL) - { - result = EINVAL; - } - else - { - if ((result = pthread_mutex_lock (&s->lock)) == 0) - { - int v = --s->value; - - (void) pthread_mutex_unlock (&s->lock); - - if (v < 0) - { - /* Must wait */ - if (WaitForSingleObject (s->sem, INFINITE) == WAIT_OBJECT_0) - { -#ifdef NEED_SEM - if (pthread_mutex_lock (&s->lock) == 0) - { - if (s->leftToUnblock > 0) - { - --s->leftToUnblock; - SetEvent(s->sem); - } - (void) pthread_mutex_unlock (&s->lock); - } -#endif - return 0; - } - } - else - { - return 0; - } - } - } - - if (result != 0) - { - errno = result; - return -1; - } - - return 0; - -} /* ptw32_semwait */ +/* + * ptw32_semwait.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef _UWIN +//# include +#endif +#include "pthread.h" +#include "implement.h" + + +int +ptw32_semwait (sem_t * sem) + /* + * ------------------------------------------------------ + * DESCRIPTION + * This function waits on a POSIX semaphore. If the + * semaphore value is greater than zero, it decreases + * its value by one. If the semaphore value is zero, then + * the calling thread (or process) is blocked until it can + * successfully decrease the value. + * + * Unlike sem_wait(), this routine is non-cancelable. + * + * RESULTS + * 0 successfully decreased semaphore, + * -1 failed, error in errno. + * ERRNO + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, + * EINTR the function was interrupted by a signal, + * EDEADLK a deadlock condition was detected. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + sem_t s = *sem; + + if (s == NULL) + { + result = EINVAL; + } + else + { + if ((result = pthread_mutex_lock (&s->lock)) == 0) + { + int v = --s->value; + + (void) pthread_mutex_unlock (&s->lock); + + if (v < 0) + { + /* Must wait */ + if (WaitForSingleObject (s->sem, INFINITE) == WAIT_OBJECT_0) + { +#ifdef NEED_SEM + if (pthread_mutex_lock (&s->lock) == 0) + { + if (s->leftToUnblock > 0) + { + --s->leftToUnblock; + SetEvent(s->sem); + } + (void) pthread_mutex_unlock (&s->lock); + } +#endif + return 0; + } + } + else + { + return 0; + } + } + } + + if (result != 0) + { + errno = result; + return -1; + } + + return 0; + +} /* ptw32_semwait */ diff --git a/pcsx2/windows/pthreads/ptw32_spinlock_check_need_init.c b/pcsx2/windows/pthreads/ptw32_spinlock_check_need_init.c index dcc8b98d5f..bf45bc397a 100644 --- a/pcsx2/windows/pthreads/ptw32_spinlock_check_need_init.c +++ b/pcsx2/windows/pthreads/ptw32_spinlock_check_need_init.c @@ -1,81 +1,81 @@ -/* - * ptw32_spinlock_check_need_init.c - * - * Description: - * This translation unit implements spin lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -INLINE int -ptw32_spinlock_check_need_init (pthread_spinlock_t * lock) -{ - int result = 0; - - /* - * The following guarded test is specifically for statically - * initialised spinlocks (via PTHREAD_SPINLOCK_INITIALIZER). - * - * Note that by not providing this synchronisation we risk - * introducing race conditions into applications which are - * correctly written. - */ - EnterCriticalSection (&ptw32_spinlock_test_init_lock); - - /* - * We got here possibly under race - * conditions. Check again inside the critical section - * and only initialise if the spinlock is valid (not been destroyed). - * If a static spinlock has been destroyed, the application can - * re-initialise it only by calling pthread_spin_init() - * explicitly. - */ - if (*lock == PTHREAD_SPINLOCK_INITIALIZER) - { - result = pthread_spin_init (lock, PTHREAD_PROCESS_PRIVATE); - } - else if (*lock == NULL) - { - /* - * The spinlock has been destroyed while we were waiting to - * initialise it, so the operation that caused the - * auto-initialisation should fail. - */ - result = EINVAL; - } - - LeaveCriticalSection (&ptw32_spinlock_test_init_lock); - - return (result); -} +/* + * ptw32_spinlock_check_need_init.c + * + * Description: + * This translation unit implements spin lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +INLINE int +ptw32_spinlock_check_need_init (pthread_spinlock_t * lock) +{ + int result = 0; + + /* + * The following guarded test is specifically for statically + * initialised spinlocks (via PTHREAD_SPINLOCK_INITIALIZER). + * + * Note that by not providing this synchronisation we risk + * introducing race conditions into applications which are + * correctly written. + */ + EnterCriticalSection (&ptw32_spinlock_test_init_lock); + + /* + * We got here possibly under race + * conditions. Check again inside the critical section + * and only initialise if the spinlock is valid (not been destroyed). + * If a static spinlock has been destroyed, the application can + * re-initialise it only by calling pthread_spin_init() + * explicitly. + */ + if (*lock == PTHREAD_SPINLOCK_INITIALIZER) + { + result = pthread_spin_init (lock, PTHREAD_PROCESS_PRIVATE); + } + else if (*lock == NULL) + { + /* + * The spinlock has been destroyed while we were waiting to + * initialise it, so the operation that caused the + * auto-initialisation should fail. + */ + result = EINVAL; + } + + LeaveCriticalSection (&ptw32_spinlock_test_init_lock); + + return (result); +} diff --git a/pcsx2/windows/pthreads/ptw32_threadDestroy.c b/pcsx2/windows/pthreads/ptw32_threadDestroy.c index a88a2b0b81..eb9abfc61c 100644 --- a/pcsx2/windows/pthreads/ptw32_threadDestroy.c +++ b/pcsx2/windows/pthreads/ptw32_threadDestroy.c @@ -1,82 +1,82 @@ -/* - * ptw32_threadDestroy.c - * - * Description: - * This translation unit implements routines which are private to - * the implementation and may be used throughout it. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -void -ptw32_threadDestroy (pthread_t thread) -{ - ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; - ptw32_thread_t threadCopy; - - if (tp != NULL) - { - /* - * Copy thread state so that the thread can be atomically NULLed. - */ - memcpy (&threadCopy, tp, sizeof (threadCopy)); - - /* - * Thread ID structs are never freed. They're NULLed and reused. - * This also sets the thread to PThreadStateInitial (invalid). - */ - ptw32_threadReusePush (thread); - - /* Now work on the copy. */ - if (threadCopy.cancelEvent != NULL) - { - CloseHandle (threadCopy.cancelEvent); - } - - (void) pthread_mutex_destroy(&threadCopy.cancelLock); - (void) pthread_mutex_destroy(&threadCopy.threadLock); - -#if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__) - /* - * See documentation for endthread vs endthreadex. - */ - if (threadCopy.threadH != 0) - { - CloseHandle (threadCopy.threadH); - } -#endif - - } -} /* ptw32_threadDestroy */ - +/* + * ptw32_threadDestroy.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +void +ptw32_threadDestroy (pthread_t thread) +{ + ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; + ptw32_thread_t threadCopy; + + if (tp != NULL) + { + /* + * Copy thread state so that the thread can be atomically NULLed. + */ + memcpy (&threadCopy, tp, sizeof (threadCopy)); + + /* + * Thread ID structs are never freed. They're NULLed and reused. + * This also sets the thread to PThreadStateInitial (invalid). + */ + ptw32_threadReusePush (thread); + + /* Now work on the copy. */ + if (threadCopy.cancelEvent != NULL) + { + CloseHandle (threadCopy.cancelEvent); + } + + (void) pthread_mutex_destroy(&threadCopy.cancelLock); + (void) pthread_mutex_destroy(&threadCopy.threadLock); + +#if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__) + /* + * See documentation for endthread vs endthreadex. + */ + if (threadCopy.threadH != 0) + { + CloseHandle (threadCopy.threadH); + } +#endif + + } +} /* ptw32_threadDestroy */ + diff --git a/pcsx2/windows/pthreads/ptw32_threadStart.c b/pcsx2/windows/pthreads/ptw32_threadStart.c index fbee09dcf2..5c0fe0e857 100644 --- a/pcsx2/windows/pthreads/ptw32_threadStart.c +++ b/pcsx2/windows/pthreads/ptw32_threadStart.c @@ -1,360 +1,360 @@ -/* - * ptw32_threadStart.c - * - * Description: - * This translation unit implements routines which are private to - * the implementation and may be used throughout it. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -#ifdef __CLEANUP_SEH - -static DWORD -ExceptionFilter (EXCEPTION_POINTERS * ep, DWORD * ei) -{ - switch (ep->ExceptionRecord->ExceptionCode) - { - case EXCEPTION_PTW32_SERVICES: - { - DWORD param; - DWORD numParams = ep->ExceptionRecord->NumberParameters; - - numParams = (numParams > 3) ? 3 : numParams; - - for (param = 0; param < numParams; param++) - { - ei[param] = ep->ExceptionRecord->ExceptionInformation[param]; - } - - return EXCEPTION_EXECUTE_HANDLER; - break; - } - default: - { - /* - * A system unexpected exception has occurred running the user's - * routine. We need to cleanup before letting the exception - * out of thread scope. - */ - pthread_t self = pthread_self (); - - (void) pthread_mutex_destroy (&((ptw32_thread_t *)self.p)->cancelLock); - ptw32_callUserDestroyRoutines (self); - - return EXCEPTION_CONTINUE_SEARCH; - break; - } - } -} - -#elif defined(__CLEANUP_CXX) - -#if defined(_MSC_VER) -# include -#elif defined(__WATCOMC__) -# include -# include -typedef terminate_handler - terminate_function; -#else -# if defined(__GNUC__) && __GNUC__ < 3 -# include -# else -# include -using - std::terminate_handler; -using - std::terminate; -using - std::set_terminate; -# endif -typedef terminate_handler - terminate_function; -#endif - -static terminate_function - ptw32_oldTerminate; - -void -ptw32_terminate () -{ - set_terminate (ptw32_oldTerminate); - (void) pthread_win32_thread_detach_np (); - terminate (); -} - -#endif - -#if ! defined (__MINGW32__) || (defined (__MSVCRT__) && ! defined (__DMC__)) -unsigned - __stdcall -#else -void -#endif -ptw32_threadStart (void *vthreadParms) -{ - ThreadParms * threadParms = (ThreadParms *) vthreadParms; - pthread_t self; - ptw32_thread_t * sp; - void *(*start) (void *); - void * arg; - -#ifdef __CLEANUP_SEH - DWORD - ei[] = { 0, 0, 0 }; -#endif - -#ifdef __CLEANUP_C - int setjmp_rc; -#endif - - void * status = (void *) 0; - - self = threadParms->tid; - sp = (ptw32_thread_t *) self.p; - start = threadParms->start; - arg = threadParms->arg; - - free (threadParms); - -#if defined (__MINGW32__) && ! defined (__MSVCRT__) - /* - * beginthread does not return the thread id and is running - * before it returns us the thread handle, and so we do it here. - */ - sp->thread = GetCurrentThreadId (); - /* - * Here we're using cancelLock as a general-purpose lock - * to make the new thread wait until the creating thread - * has the new handle. - */ - if (pthread_mutex_lock (&sp->cancelLock) == 0) - { - (void) pthread_mutex_unlock (&sp->cancelLock); - } -#endif - - pthread_setspecific (ptw32_selfThreadKey, sp); - - sp->state = PThreadStateRunning; - -#ifdef __CLEANUP_SEH - - __try - { - /* - * Run the caller's routine; - */ - status = sp->exitStatus = (*start) (arg); - -#ifdef _UWIN - if (--pthread_count <= 0) - exit (0); -#endif - - } - __except (ExceptionFilter (GetExceptionInformation (), ei)) - { - switch (ei[0]) - { - case PTW32_EPS_CANCEL: - status = sp->exitStatus = PTHREAD_CANCELED; -#ifdef _UWIN - if (--pthread_count <= 0) - exit (0); -#endif - break; - case PTW32_EPS_EXIT: - status = sp->exitStatus; - break; - default: - status = sp->exitStatus = PTHREAD_CANCELED; - break; - } - } - -#else /* __CLEANUP_SEH */ - -#ifdef __CLEANUP_C - - setjmp_rc = setjmp (sp->start_mark); - - if (0 == setjmp_rc) - { - - /* - * Run the caller's routine; - */ - status = sp->exitStatus = (*start) (arg); - } - else - { - switch (setjmp_rc) - { - case PTW32_EPS_CANCEL: - status = sp->exitStatus = PTHREAD_CANCELED; - break; - case PTW32_EPS_EXIT: - status = sp->exitStatus; - break; - default: - status = sp->exitStatus = PTHREAD_CANCELED; - break; - } - } - -#else /* __CLEANUP_C */ - -#ifdef __CLEANUP_CXX - - ptw32_oldTerminate = set_terminate (&ptw32_terminate); - - try - { - /* - * Run the caller's routine in a nested try block so that we - * can run the user's terminate function, which may call - * pthread_exit() or be canceled. - */ - try - { - status = sp->exitStatus = (*start) (arg); - } - catch (ptw32_exception &) - { - /* - * Pass these through to the outer block. - */ - throw; - } - catch (...) - { - /* - * We want to run the user's terminate function if supplied. - * That function may call pthread_exit() or be canceled, which will - * be handled by the outer try block. - * - * ptw32_terminate() will be called if there is no user - * supplied function. - */ - - terminate_function - term_func = set_terminate (0); - set_terminate (term_func); - - if (term_func != 0) - { - term_func (); - } - - throw; - } - } - catch (ptw32_exception_cancel &) - { - /* - * Thread was canceled. - */ - status = sp->exitStatus = PTHREAD_CANCELED; - } - catch (ptw32_exception_exit &) - { - /* - * Thread was exited via pthread_exit(). - */ - status = sp->exitStatus; - } - catch (...) - { - /* - * A system unexpected exception has occurred running the user's - * terminate routine. We get control back within this block - cleanup - * and release the exception out of thread scope. - */ - status = sp->exitStatus = PTHREAD_CANCELED; - (void) pthread_mutex_lock (&sp->cancelLock); - sp->state = PThreadStateException; - (void) pthread_mutex_unlock (&sp->cancelLock); - (void) pthread_win32_thread_detach_np (); - (void) set_terminate (ptw32_oldTerminate); - throw; - - /* - * Never reached. - */ - } - - (void) set_terminate (ptw32_oldTerminate); - -#else - -#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. - -#endif /* __CLEANUP_CXX */ -#endif /* __CLEANUP_C */ -#endif /* __CLEANUP_SEH */ - -#if defined(PTW32_STATIC_LIB) - /* - * We need to cleanup the pthread now if we have - * been statically linked, in which case the cleanup - * in dllMain won't get done. Joinable threads will - * only be partially cleaned up and must be fully cleaned - * up by pthread_join() or pthread_detach(). - * - * Note: if this library has been statically linked, - * implicitly created pthreads (those created - * for Win32 threads which have called pthreads routines) - * must be cleaned up explicitly by the application - * (by calling pthread_win32_thread_detach_np()). - * For the dll, dllMain will do the cleanup automatically. - */ - (void) pthread_win32_thread_detach_np (); -#endif - -#if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__) - _endthreadex ((unsigned) status); -#else - _endthread (); -#endif - - /* - * Never reached. - */ - -#if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__) - return (unsigned) status; -#endif - -} /* ptw32_threadStart */ +/* + * ptw32_threadStart.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +#ifdef __CLEANUP_SEH + +static DWORD +ExceptionFilter (EXCEPTION_POINTERS * ep, DWORD * ei) +{ + switch (ep->ExceptionRecord->ExceptionCode) + { + case EXCEPTION_PTW32_SERVICES: + { + DWORD param; + DWORD numParams = ep->ExceptionRecord->NumberParameters; + + numParams = (numParams > 3) ? 3 : numParams; + + for (param = 0; param < numParams; param++) + { + ei[param] = ep->ExceptionRecord->ExceptionInformation[param]; + } + + return EXCEPTION_EXECUTE_HANDLER; + break; + } + default: + { + /* + * A system unexpected exception has occurred running the user's + * routine. We need to cleanup before letting the exception + * out of thread scope. + */ + pthread_t self = pthread_self (); + + (void) pthread_mutex_destroy (&((ptw32_thread_t *)self.p)->cancelLock); + ptw32_callUserDestroyRoutines (self); + + return EXCEPTION_CONTINUE_SEARCH; + break; + } + } +} + +#elif defined(__CLEANUP_CXX) + +#if defined(_MSC_VER) +# include +#elif defined(__WATCOMC__) +# include +# include +typedef terminate_handler + terminate_function; +#else +# if defined(__GNUC__) && __GNUC__ < 3 +# include +# else +# include +using + std::terminate_handler; +using + std::terminate; +using + std::set_terminate; +# endif +typedef terminate_handler + terminate_function; +#endif + +static terminate_function + ptw32_oldTerminate; + +void +ptw32_terminate () +{ + set_terminate (ptw32_oldTerminate); + (void) pthread_win32_thread_detach_np (); + terminate (); +} + +#endif + +#if ! defined (__MINGW32__) || (defined (__MSVCRT__) && ! defined (__DMC__)) +unsigned + __stdcall +#else +void +#endif +ptw32_threadStart (void *vthreadParms) +{ + ThreadParms * threadParms = (ThreadParms *) vthreadParms; + pthread_t self; + ptw32_thread_t * sp; + void *(*start) (void *); + void * arg; + +#ifdef __CLEANUP_SEH + DWORD + ei[] = { 0, 0, 0 }; +#endif + +#ifdef __CLEANUP_C + int setjmp_rc; +#endif + + void * status = (void *) 0; + + self = threadParms->tid; + sp = (ptw32_thread_t *) self.p; + start = threadParms->start; + arg = threadParms->arg; + + free (threadParms); + +#if defined (__MINGW32__) && ! defined (__MSVCRT__) + /* + * beginthread does not return the thread id and is running + * before it returns us the thread handle, and so we do it here. + */ + sp->thread = GetCurrentThreadId (); + /* + * Here we're using cancelLock as a general-purpose lock + * to make the new thread wait until the creating thread + * has the new handle. + */ + if (pthread_mutex_lock (&sp->cancelLock) == 0) + { + (void) pthread_mutex_unlock (&sp->cancelLock); + } +#endif + + pthread_setspecific (ptw32_selfThreadKey, sp); + + sp->state = PThreadStateRunning; + +#ifdef __CLEANUP_SEH + + __try + { + /* + * Run the caller's routine; + */ + status = sp->exitStatus = (*start) (arg); + +#ifdef _UWIN + if (--pthread_count <= 0) + exit (0); +#endif + + } + __except (ExceptionFilter (GetExceptionInformation (), ei)) + { + switch (ei[0]) + { + case PTW32_EPS_CANCEL: + status = sp->exitStatus = PTHREAD_CANCELED; +#ifdef _UWIN + if (--pthread_count <= 0) + exit (0); +#endif + break; + case PTW32_EPS_EXIT: + status = sp->exitStatus; + break; + default: + status = sp->exitStatus = PTHREAD_CANCELED; + break; + } + } + +#else /* __CLEANUP_SEH */ + +#ifdef __CLEANUP_C + + setjmp_rc = setjmp (sp->start_mark); + + if (0 == setjmp_rc) + { + + /* + * Run the caller's routine; + */ + status = sp->exitStatus = (*start) (arg); + } + else + { + switch (setjmp_rc) + { + case PTW32_EPS_CANCEL: + status = sp->exitStatus = PTHREAD_CANCELED; + break; + case PTW32_EPS_EXIT: + status = sp->exitStatus; + break; + default: + status = sp->exitStatus = PTHREAD_CANCELED; + break; + } + } + +#else /* __CLEANUP_C */ + +#ifdef __CLEANUP_CXX + + ptw32_oldTerminate = set_terminate (&ptw32_terminate); + + try + { + /* + * Run the caller's routine in a nested try block so that we + * can run the user's terminate function, which may call + * pthread_exit() or be canceled. + */ + try + { + status = sp->exitStatus = (*start) (arg); + } + catch (ptw32_exception &) + { + /* + * Pass these through to the outer block. + */ + throw; + } + catch (...) + { + /* + * We want to run the user's terminate function if supplied. + * That function may call pthread_exit() or be canceled, which will + * be handled by the outer try block. + * + * ptw32_terminate() will be called if there is no user + * supplied function. + */ + + terminate_function + term_func = set_terminate (0); + set_terminate (term_func); + + if (term_func != 0) + { + term_func (); + } + + throw; + } + } + catch (ptw32_exception_cancel &) + { + /* + * Thread was canceled. + */ + status = sp->exitStatus = PTHREAD_CANCELED; + } + catch (ptw32_exception_exit &) + { + /* + * Thread was exited via pthread_exit(). + */ + status = sp->exitStatus; + } + catch (...) + { + /* + * A system unexpected exception has occurred running the user's + * terminate routine. We get control back within this block - cleanup + * and release the exception out of thread scope. + */ + status = sp->exitStatus = PTHREAD_CANCELED; + (void) pthread_mutex_lock (&sp->cancelLock); + sp->state = PThreadStateException; + (void) pthread_mutex_unlock (&sp->cancelLock); + (void) pthread_win32_thread_detach_np (); + (void) set_terminate (ptw32_oldTerminate); + throw; + + /* + * Never reached. + */ + } + + (void) set_terminate (ptw32_oldTerminate); + +#else + +#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. + +#endif /* __CLEANUP_CXX */ +#endif /* __CLEANUP_C */ +#endif /* __CLEANUP_SEH */ + +#if defined(PTW32_STATIC_LIB) + /* + * We need to cleanup the pthread now if we have + * been statically linked, in which case the cleanup + * in dllMain won't get done. Joinable threads will + * only be partially cleaned up and must be fully cleaned + * up by pthread_join() or pthread_detach(). + * + * Note: if this library has been statically linked, + * implicitly created pthreads (those created + * for Win32 threads which have called pthreads routines) + * must be cleaned up explicitly by the application + * (by calling pthread_win32_thread_detach_np()). + * For the dll, dllMain will do the cleanup automatically. + */ + (void) pthread_win32_thread_detach_np (); +#endif + +#if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__) + _endthreadex ((unsigned) status); +#else + _endthread (); +#endif + + /* + * Never reached. + */ + +#if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__) + return (unsigned) status; +#endif + +} /* ptw32_threadStart */ diff --git a/pcsx2/windows/pthreads/ptw32_throw.c b/pcsx2/windows/pthreads/ptw32_throw.c index cc9ee86639..493f4e4dc1 100644 --- a/pcsx2/windows/pthreads/ptw32_throw.c +++ b/pcsx2/windows/pthreads/ptw32_throw.c @@ -1,167 +1,167 @@ -/* - * ptw32_throw.c - * - * Description: - * This translation unit implements routines which are private to - * the implementation and may be used throughout it. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - -/* - * ptw32_throw - * - * All canceled and explicitly exited POSIX threads go through - * here. This routine knows how to exit both POSIX initiated threads and - * 'implicit' POSIX threads for each of the possible language modes (C, - * C++, and SEH). - */ -void -ptw32_throw (DWORD exception) -{ - /* - * Don't use pthread_self() to avoid creating an implicit POSIX thread handle - * unnecessarily. - */ - ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); - -#ifdef __CLEANUP_SEH - DWORD exceptionInformation[3]; -#endif - - if (exception != PTW32_EPS_CANCEL && exception != PTW32_EPS_EXIT) - { - /* Should never enter here */ - exit (1); - } - - if (NULL == sp || sp->implicit) - { - /* - * We're inside a non-POSIX initialised Win32 thread - * so there is no point to jump or throw back to. Just do an - * explicit thread exit here after cleaning up POSIX - * residue (i.e. cleanup handlers, POSIX thread handle etc). - */ - unsigned exitCode = 0; - - switch (exception) - { - case PTW32_EPS_CANCEL: - exitCode = (unsigned) PTHREAD_CANCELED; - break; - case PTW32_EPS_EXIT: - exitCode = (unsigned) sp->exitStatus;; - break; - } - -#if defined(PTW32_STATIC_LIB) - - pthread_win32_thread_detach_np (); - -#endif - -#if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__) - _endthreadex (exitCode); -#else - _endthread (); -#endif - - } - -#ifdef __CLEANUP_SEH - - - exceptionInformation[0] = (DWORD) (exception); - exceptionInformation[1] = (DWORD) (0); - exceptionInformation[2] = (DWORD) (0); - - RaiseException (EXCEPTION_PTW32_SERVICES, 0, 3, exceptionInformation); - -#else /* __CLEANUP_SEH */ - -#ifdef __CLEANUP_C - - ptw32_pop_cleanup_all (1); - longjmp (sp->start_mark, exception); - -#else /* __CLEANUP_C */ - -#ifdef __CLEANUP_CXX - - switch (exception) - { - case PTW32_EPS_CANCEL: - throw ptw32_exception_cancel (); - break; - case PTW32_EPS_EXIT: - throw ptw32_exception_exit (); - break; - } - -#else - -#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. - -#endif /* __CLEANUP_CXX */ - -#endif /* __CLEANUP_C */ - -#endif /* __CLEANUP_SEH */ - - /* Never reached */ -} - - -void -ptw32_pop_cleanup_all (int execute) -{ - while (NULL != ptw32_pop_cleanup (execute)) - { - } -} - - -DWORD -ptw32_get_exception_services_code (void) -{ -#ifdef __CLEANUP_SEH - - return EXCEPTION_PTW32_SERVICES; - -#else - - return (DWORD) NULL; - -#endif -} +/* + * ptw32_throw.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* + * ptw32_throw + * + * All canceled and explicitly exited POSIX threads go through + * here. This routine knows how to exit both POSIX initiated threads and + * 'implicit' POSIX threads for each of the possible language modes (C, + * C++, and SEH). + */ +void +ptw32_throw (DWORD exception) +{ + /* + * Don't use pthread_self() to avoid creating an implicit POSIX thread handle + * unnecessarily. + */ + ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); + +#ifdef __CLEANUP_SEH + DWORD exceptionInformation[3]; +#endif + + if (exception != PTW32_EPS_CANCEL && exception != PTW32_EPS_EXIT) + { + /* Should never enter here */ + exit (1); + } + + if (NULL == sp || sp->implicit) + { + /* + * We're inside a non-POSIX initialised Win32 thread + * so there is no point to jump or throw back to. Just do an + * explicit thread exit here after cleaning up POSIX + * residue (i.e. cleanup handlers, POSIX thread handle etc). + */ + unsigned exitCode = 0; + + switch (exception) + { + case PTW32_EPS_CANCEL: + exitCode = (unsigned) PTHREAD_CANCELED; + break; + case PTW32_EPS_EXIT: + exitCode = (unsigned) sp->exitStatus;; + break; + } + +#if defined(PTW32_STATIC_LIB) + + pthread_win32_thread_detach_np (); + +#endif + +#if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__) + _endthreadex (exitCode); +#else + _endthread (); +#endif + + } + +#ifdef __CLEANUP_SEH + + + exceptionInformation[0] = (DWORD) (exception); + exceptionInformation[1] = (DWORD) (0); + exceptionInformation[2] = (DWORD) (0); + + RaiseException (EXCEPTION_PTW32_SERVICES, 0, 3, exceptionInformation); + +#else /* __CLEANUP_SEH */ + +#ifdef __CLEANUP_C + + ptw32_pop_cleanup_all (1); + longjmp (sp->start_mark, exception); + +#else /* __CLEANUP_C */ + +#ifdef __CLEANUP_CXX + + switch (exception) + { + case PTW32_EPS_CANCEL: + throw ptw32_exception_cancel (); + break; + case PTW32_EPS_EXIT: + throw ptw32_exception_exit (); + break; + } + +#else + +#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. + +#endif /* __CLEANUP_CXX */ + +#endif /* __CLEANUP_C */ + +#endif /* __CLEANUP_SEH */ + + /* Never reached */ +} + + +void +ptw32_pop_cleanup_all (int execute) +{ + while (NULL != ptw32_pop_cleanup (execute)) + { + } +} + + +DWORD +ptw32_get_exception_services_code (void) +{ +#ifdef __CLEANUP_SEH + + return EXCEPTION_PTW32_SERVICES; + +#else + + return (DWORD) NULL; + +#endif +} diff --git a/pcsx2/windows/pthreads/ptw32_timespec.c b/pcsx2/windows/pthreads/ptw32_timespec.c index 629be1572f..6a2cb565a7 100644 --- a/pcsx2/windows/pthreads/ptw32_timespec.c +++ b/pcsx2/windows/pthreads/ptw32_timespec.c @@ -1,83 +1,83 @@ -/* - * ptw32_timespec.c - * - * Description: - * This translation unit implements routines which are private to - * the implementation and may be used throughout it. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -#ifdef NEED_FTIME - -/* - * time between jan 1, 1601 and jan 1, 1970 in units of 100 nanoseconds - */ -#define PTW32_TIMESPEC_TO_FILETIME_OFFSET \ - ( ((LONGLONG) 27111902 << 32) + (LONGLONG) 3577643008 ) - -INLINE void -ptw32_timespec_to_filetime (const struct timespec *ts, FILETIME * ft) - /* - * ------------------------------------------------------------------- - * converts struct timespec - * where the time is expressed in seconds and nanoseconds from Jan 1, 1970. - * into FILETIME (as set by GetSystemTimeAsFileTime), where the time is - * expressed in 100 nanoseconds from Jan 1, 1601, - * ------------------------------------------------------------------- - */ -{ - *(LONGLONG *) ft = ts->tv_sec * 10000000 - + (ts->tv_nsec + 50) / 100 + PTW32_TIMESPEC_TO_FILETIME_OFFSET; -} - -INLINE void -ptw32_filetime_to_timespec (const FILETIME * ft, struct timespec *ts) - /* - * ------------------------------------------------------------------- - * converts FILETIME (as set by GetSystemTimeAsFileTime), where the time is - * expressed in 100 nanoseconds from Jan 1, 1601, - * into struct timespec - * where the time is expressed in seconds and nanoseconds from Jan 1, 1970. - * ------------------------------------------------------------------- - */ -{ - ts->tv_sec = - (int) ((*(LONGLONG *) ft - PTW32_TIMESPEC_TO_FILETIME_OFFSET) / 10000000); - ts->tv_nsec = - (int) ((*(LONGLONG *) ft - PTW32_TIMESPEC_TO_FILETIME_OFFSET - - ((LONGLONG) ts->tv_sec * (LONGLONG) 10000000)) * 100); -} - -#endif /* NEED_FTIME */ +/* + * ptw32_timespec.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +#ifdef NEED_FTIME + +/* + * time between jan 1, 1601 and jan 1, 1970 in units of 100 nanoseconds + */ +#define PTW32_TIMESPEC_TO_FILETIME_OFFSET \ + ( ((LONGLONG) 27111902 << 32) + (LONGLONG) 3577643008 ) + +INLINE void +ptw32_timespec_to_filetime (const struct timespec *ts, FILETIME * ft) + /* + * ------------------------------------------------------------------- + * converts struct timespec + * where the time is expressed in seconds and nanoseconds from Jan 1, 1970. + * into FILETIME (as set by GetSystemTimeAsFileTime), where the time is + * expressed in 100 nanoseconds from Jan 1, 1601, + * ------------------------------------------------------------------- + */ +{ + *(LONGLONG *) ft = ts->tv_sec * 10000000 + + (ts->tv_nsec + 50) / 100 + PTW32_TIMESPEC_TO_FILETIME_OFFSET; +} + +INLINE void +ptw32_filetime_to_timespec (const FILETIME * ft, struct timespec *ts) + /* + * ------------------------------------------------------------------- + * converts FILETIME (as set by GetSystemTimeAsFileTime), where the time is + * expressed in 100 nanoseconds from Jan 1, 1601, + * into struct timespec + * where the time is expressed in seconds and nanoseconds from Jan 1, 1970. + * ------------------------------------------------------------------- + */ +{ + ts->tv_sec = + (int) ((*(LONGLONG *) ft - PTW32_TIMESPEC_TO_FILETIME_OFFSET) / 10000000); + ts->tv_nsec = + (int) ((*(LONGLONG *) ft - PTW32_TIMESPEC_TO_FILETIME_OFFSET - + ((LONGLONG) ts->tv_sec * (LONGLONG) 10000000)) * 100); +} + +#endif /* NEED_FTIME */ diff --git a/pcsx2/windows/pthreads/ptw32_tkAssocCreate.c b/pcsx2/windows/pthreads/ptw32_tkAssocCreate.c index 411c9cd88e..5ba24bbf71 100644 --- a/pcsx2/windows/pthreads/ptw32_tkAssocCreate.c +++ b/pcsx2/windows/pthreads/ptw32_tkAssocCreate.c @@ -1,118 +1,118 @@ -/* - * ptw32_tkAssocCreate.c - * - * Description: - * This translation unit implements routines which are private to - * the implementation and may be used throughout it. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -int -ptw32_tkAssocCreate (ptw32_thread_t * sp, pthread_key_t key) - /* - * ------------------------------------------------------------------- - * This routine creates an association that - * is unique for the given (thread,key) combination.The association - * is referenced by both the thread and the key. - * This association allows us to determine what keys the - * current thread references and what threads a given key - * references. - * See the detailed description - * at the beginning of this file for further details. - * - * Notes: - * 1) New associations are pushed to the beginning of the - * chain so that the internal ptw32_selfThreadKey association - * is always last, thus allowing selfThreadExit to - * be implicitly called last by pthread_exit. - * 2) - * - * Parameters: - * thread - * current running thread. - * key - * key on which to create an association. - * Returns: - * 0 - if successful, - * ENOMEM - not enough memory to create assoc or other object - * EINVAL - an internal error occurred - * ENOSYS - an internal error occurred - * ------------------------------------------------------------------- - */ -{ - ThreadKeyAssoc *assoc; - - /* - * Have to create an association and add it - * to both the key and the thread. - * - * Both key->keyLock and thread->threadLock are locked on - * entry to this routine. - */ - assoc = (ThreadKeyAssoc *) calloc (1, sizeof (*assoc)); - - if (assoc == NULL) - { - return ENOMEM; - } - - assoc->thread = sp; - assoc->key = key; - - /* - * Register assoc with key - */ - assoc->prevThread = NULL; - assoc->nextThread = (ThreadKeyAssoc *) key->threads; - if (assoc->nextThread != NULL) - { - assoc->nextThread->prevThread = assoc; - } - key->threads = (void *) assoc; - - /* - * Register assoc with thread - */ - assoc->prevKey = NULL; - assoc->nextKey = (ThreadKeyAssoc *) sp->keys; - if (assoc->nextKey != NULL) - { - assoc->nextKey->prevKey = assoc; - } - sp->keys = (void *) assoc; - - return (0); - -} /* ptw32_tkAssocCreate */ +/* + * ptw32_tkAssocCreate.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +ptw32_tkAssocCreate (ptw32_thread_t * sp, pthread_key_t key) + /* + * ------------------------------------------------------------------- + * This routine creates an association that + * is unique for the given (thread,key) combination.The association + * is referenced by both the thread and the key. + * This association allows us to determine what keys the + * current thread references and what threads a given key + * references. + * See the detailed description + * at the beginning of this file for further details. + * + * Notes: + * 1) New associations are pushed to the beginning of the + * chain so that the internal ptw32_selfThreadKey association + * is always last, thus allowing selfThreadExit to + * be implicitly called last by pthread_exit. + * 2) + * + * Parameters: + * thread + * current running thread. + * key + * key on which to create an association. + * Returns: + * 0 - if successful, + * ENOMEM - not enough memory to create assoc or other object + * EINVAL - an internal error occurred + * ENOSYS - an internal error occurred + * ------------------------------------------------------------------- + */ +{ + ThreadKeyAssoc *assoc; + + /* + * Have to create an association and add it + * to both the key and the thread. + * + * Both key->keyLock and thread->threadLock are locked on + * entry to this routine. + */ + assoc = (ThreadKeyAssoc *) calloc (1, sizeof (*assoc)); + + if (assoc == NULL) + { + return ENOMEM; + } + + assoc->thread = sp; + assoc->key = key; + + /* + * Register assoc with key + */ + assoc->prevThread = NULL; + assoc->nextThread = (ThreadKeyAssoc *) key->threads; + if (assoc->nextThread != NULL) + { + assoc->nextThread->prevThread = assoc; + } + key->threads = (void *) assoc; + + /* + * Register assoc with thread + */ + assoc->prevKey = NULL; + assoc->nextKey = (ThreadKeyAssoc *) sp->keys; + if (assoc->nextKey != NULL) + { + assoc->nextKey->prevKey = assoc; + } + sp->keys = (void *) assoc; + + return (0); + +} /* ptw32_tkAssocCreate */ diff --git a/pcsx2/windows/pthreads/ptw32_tkAssocDestroy.c b/pcsx2/windows/pthreads/ptw32_tkAssocDestroy.c index d50178fede..a7842ea87d 100644 --- a/pcsx2/windows/pthreads/ptw32_tkAssocDestroy.c +++ b/pcsx2/windows/pthreads/ptw32_tkAssocDestroy.c @@ -1,114 +1,114 @@ -/* - * ptw32_tkAssocDestroy.c - * - * Description: - * This translation unit implements routines which are private to - * the implementation and may be used throughout it. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -void -ptw32_tkAssocDestroy (ThreadKeyAssoc * assoc) - /* - * ------------------------------------------------------------------- - * This routine releases all resources for the given ThreadKeyAssoc - * once it is no longer being referenced - * ie) either the key or thread has stopped referencing it. - * - * Parameters: - * assoc - * an instance of ThreadKeyAssoc. - * Returns: - * N/A - * ------------------------------------------------------------------- - */ -{ - - /* - * Both key->keyLock and thread->threadLock are locked on - * entry to this routine. - */ - if (assoc != NULL) - { - ThreadKeyAssoc * prev, * next; - - /* Remove assoc from thread's keys chain */ - prev = assoc->prevKey; - next = assoc->nextKey; - if (prev != NULL) - { - prev->nextKey = next; - } - if (next != NULL) - { - next->prevKey = prev; - } - - if (assoc->thread->keys == assoc) - { - /* We're at the head of the thread's keys chain */ - assoc->thread->keys = next; - } - if (assoc->thread->nextAssoc == assoc) - { - /* - * Thread is exiting and we're deleting the assoc to be processed next. - * Hand thread the assoc after this one. - */ - assoc->thread->nextAssoc = next; - } - - /* Remove assoc from key's threads chain */ - prev = assoc->prevThread; - next = assoc->nextThread; - if (prev != NULL) - { - prev->nextThread = next; - } - if (next != NULL) - { - next->prevThread = prev; - } - - if (assoc->key->threads == assoc) - { - /* We're at the head of the key's threads chain */ - assoc->key->threads = next; - } - - free (assoc); - } - -} /* ptw32_tkAssocDestroy */ +/* + * ptw32_tkAssocDestroy.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +void +ptw32_tkAssocDestroy (ThreadKeyAssoc * assoc) + /* + * ------------------------------------------------------------------- + * This routine releases all resources for the given ThreadKeyAssoc + * once it is no longer being referenced + * ie) either the key or thread has stopped referencing it. + * + * Parameters: + * assoc + * an instance of ThreadKeyAssoc. + * Returns: + * N/A + * ------------------------------------------------------------------- + */ +{ + + /* + * Both key->keyLock and thread->threadLock are locked on + * entry to this routine. + */ + if (assoc != NULL) + { + ThreadKeyAssoc * prev, * next; + + /* Remove assoc from thread's keys chain */ + prev = assoc->prevKey; + next = assoc->nextKey; + if (prev != NULL) + { + prev->nextKey = next; + } + if (next != NULL) + { + next->prevKey = prev; + } + + if (assoc->thread->keys == assoc) + { + /* We're at the head of the thread's keys chain */ + assoc->thread->keys = next; + } + if (assoc->thread->nextAssoc == assoc) + { + /* + * Thread is exiting and we're deleting the assoc to be processed next. + * Hand thread the assoc after this one. + */ + assoc->thread->nextAssoc = next; + } + + /* Remove assoc from key's threads chain */ + prev = assoc->prevThread; + next = assoc->nextThread; + if (prev != NULL) + { + prev->nextThread = next; + } + if (next != NULL) + { + next->prevThread = prev; + } + + if (assoc->key->threads == assoc) + { + /* We're at the head of the key's threads chain */ + assoc->key->threads = next; + } + + free (assoc); + } + +} /* ptw32_tkAssocDestroy */ diff --git a/pcsx2/windows/pthreads/rwlock.c b/pcsx2/windows/pthreads/rwlock.c index 85d39c75b4..4a3cd2594c 100644 --- a/pcsx2/windows/pthreads/rwlock.c +++ b/pcsx2/windows/pthreads/rwlock.c @@ -1,51 +1,51 @@ -/* - * rwlock.c - * - * Description: - * This translation unit implements read/write lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "ptw32_rwlock_check_need_init.c" -#include "ptw32_rwlock_cancelwrwait.c" -#include "pthread_rwlock_init.c" -#include "pthread_rwlock_destroy.c" -#include "pthread_rwlockattr_init.c" -#include "pthread_rwlockattr_destroy.c" -#include "pthread_rwlockattr_getpshared.c" -#include "pthread_rwlockattr_setpshared.c" -#include "pthread_rwlock_rdlock.c" -#include "pthread_rwlock_timedrdlock.c" -#include "pthread_rwlock_wrlock.c" -#include "pthread_rwlock_timedwrlock.c" -#include "pthread_rwlock_unlock.c" -#include "pthread_rwlock_tryrdlock.c" -#include "pthread_rwlock_trywrlock.c" +/* + * rwlock.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "ptw32_rwlock_check_need_init.c" +#include "ptw32_rwlock_cancelwrwait.c" +#include "pthread_rwlock_init.c" +#include "pthread_rwlock_destroy.c" +#include "pthread_rwlockattr_init.c" +#include "pthread_rwlockattr_destroy.c" +#include "pthread_rwlockattr_getpshared.c" +#include "pthread_rwlockattr_setpshared.c" +#include "pthread_rwlock_rdlock.c" +#include "pthread_rwlock_timedrdlock.c" +#include "pthread_rwlock_wrlock.c" +#include "pthread_rwlock_timedwrlock.c" +#include "pthread_rwlock_unlock.c" +#include "pthread_rwlock_tryrdlock.c" +#include "pthread_rwlock_trywrlock.c" diff --git a/pcsx2/windows/pthreads/sched.c b/pcsx2/windows/pthreads/sched.c index ec90e85f38..ed30ea7b24 100644 --- a/pcsx2/windows/pthreads/sched.c +++ b/pcsx2/windows/pthreads/sched.c @@ -1,53 +1,53 @@ -/* - * sched.c - * - * Description: - * POSIX thread functions that deal with thread scheduling. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" -#include "sched.h" - -#include "pthread_attr_setschedpolicy.c" -#include "pthread_attr_getschedpolicy.c" -#include "pthread_attr_setschedparam.c" -#include "pthread_attr_getschedparam.c" -#include "pthread_attr_setinheritsched.c" -#include "pthread_attr_getinheritsched.c" -#include "pthread_setschedparam.c" -#include "pthread_getschedparam.c" -#include "sched_get_priority_max.c" -#include "sched_get_priority_min.c" -#include "sched_setscheduler.c" -#include "sched_getscheduler.c" -#include "sched_yield.c" +/* + * sched.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +#include "pthread_attr_setschedpolicy.c" +#include "pthread_attr_getschedpolicy.c" +#include "pthread_attr_setschedparam.c" +#include "pthread_attr_getschedparam.c" +#include "pthread_attr_setinheritsched.c" +#include "pthread_attr_getinheritsched.c" +#include "pthread_setschedparam.c" +#include "pthread_getschedparam.c" +#include "sched_get_priority_max.c" +#include "sched_get_priority_min.c" +#include "sched_setscheduler.c" +#include "sched_getscheduler.c" +#include "sched_yield.c" diff --git a/pcsx2/windows/pthreads/sched.h b/pcsx2/windows/pthreads/sched.h index 10ecb5d7ea..dfb8e934af 100644 --- a/pcsx2/windows/pthreads/sched.h +++ b/pcsx2/windows/pthreads/sched.h @@ -1,178 +1,178 @@ -/* - * Module: sched.h - * - * Purpose: - * Provides an implementation of POSIX realtime extensions - * as defined in - * - * POSIX 1003.1b-1993 (POSIX.1b) - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ -#ifndef _SCHED_H -#define _SCHED_H - -#undef PTW32_LEVEL - -#if defined(_POSIX_SOURCE) -#define PTW32_LEVEL 0 -/* Early POSIX */ -#endif - -#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 -#undef PTW32_LEVEL -#define PTW32_LEVEL 1 -/* Include 1b, 1c and 1d */ -#endif - -#if defined(INCLUDE_NP) -#undef PTW32_LEVEL -#define PTW32_LEVEL 2 -/* Include Non-Portable extensions */ -#endif - -#define PTW32_LEVEL_MAX 3 - -#if !defined(PTW32_LEVEL) -#define PTW32_LEVEL PTW32_LEVEL_MAX -/* Include everything */ -#endif - - -#if __GNUC__ && ! defined (__declspec) -# error Please upgrade your GNU compiler to one that supports __declspec. -#endif - -/* - * When building the DLL code, you should define PTW32_BUILD so that - * the variables/functions are exported correctly. When using the DLL, - * do NOT define PTW32_BUILD, and then the variables/functions will - * be imported correctly. - */ -#ifndef PTW32_STATIC_LIB -# ifdef PTW32_BUILD -# define PTW32_DLLPORT __declspec (dllexport) -# else -# define PTW32_DLLPORT __declspec (dllimport) -# endif -#else -# define PTW32_DLLPORT -#endif - -/* - * This is a duplicate of what is in the autoconf config.h, - * which is only used when building the pthread-win32 libraries. - */ - -#ifndef PTW32_CONFIG_H -# if defined(WINCE) -# define NEED_ERRNO -# define NEED_SEM -# endif -# if defined(_UWIN) || defined(__MINGW32__) -# define HAVE_MODE_T -# endif -#endif - -/* - * - */ - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX -#ifdef NEED_ERRNO -#include "need_errno.h" -#else -#include -#endif -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -#if defined(__MINGW32__) || defined(_UWIN) -#if PTW32_LEVEL >= PTW32_LEVEL_MAX -/* For pid_t */ -# include -/* Required by Unix 98 */ -# include -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ -#else -typedef int pid_t; -#endif - -/* Thread scheduling policies */ - -enum { - SCHED_OTHER = 0, - SCHED_FIFO, - SCHED_RR, - SCHED_MIN = SCHED_OTHER, - SCHED_MAX = SCHED_RR -}; - -struct sched_param { - int sched_priority; -}; - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - -PTW32_DLLPORT int __cdecl sched_yield (void); - -PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy); - -PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy); - -PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy); - -PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid); - -/* - * Note that this macro returns ENOTSUP rather than - * ENOSYS as might be expected. However, returning ENOSYS - * should mean that sched_get_priority_{min,max} are - * not implemented as well as sched_rr_get_interval. - * This is not the case, since we just don't support - * round-robin scheduling. Therefore I have chosen to - * return the same value as sched_setscheduler when - * SCHED_RR is passed to it. - */ -#define sched_rr_get_interval(_pid, _interval) \ - ( errno = ENOTSUP, (int) -1 ) - - -#ifdef __cplusplus -} /* End of extern "C" */ -#endif /* __cplusplus */ - -#undef PTW32_LEVEL -#undef PTW32_LEVEL_MAX - -#endif /* !_SCHED_H */ - +/* + * Module: sched.h + * + * Purpose: + * Provides an implementation of POSIX realtime extensions + * as defined in + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef _SCHED_H +#define _SCHED_H + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + + +#if __GNUC__ && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the DLL code, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the DLL, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#ifndef PTW32_STATIC_LIB +# ifdef PTW32_BUILD +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#ifndef PTW32_CONFIG_H +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#ifdef NEED_ERRNO +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#if defined(__MINGW32__) || defined(_UWIN) +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +/* For pid_t */ +# include +/* Required by Unix 98 */ +# include +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ +#else +typedef int pid_t; +#endif + +/* Thread scheduling policies */ + +enum { + SCHED_OTHER = 0, + SCHED_FIFO, + SCHED_RR, + SCHED_MIN = SCHED_OTHER, + SCHED_MAX = SCHED_RR +}; + +struct sched_param { + int sched_priority; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +PTW32_DLLPORT int __cdecl sched_yield (void); + +PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy); + +PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy); + +PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy); + +PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid); + +/* + * Note that this macro returns ENOTSUP rather than + * ENOSYS as might be expected. However, returning ENOSYS + * should mean that sched_get_priority_{min,max} are + * not implemented as well as sched_rr_get_interval. + * This is not the case, since we just don't support + * round-robin scheduling. Therefore I have chosen to + * return the same value as sched_setscheduler when + * SCHED_RR is passed to it. + */ +#define sched_rr_get_interval(_pid, _interval) \ + ( errno = ENOTSUP, (int) -1 ) + + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* !_SCHED_H */ + diff --git a/pcsx2/windows/pthreads/sched_get_priority_max.c b/pcsx2/windows/pthreads/sched_get_priority_max.c index b69f82e21d..cabf2320a7 100644 --- a/pcsx2/windows/pthreads/sched_get_priority_max.c +++ b/pcsx2/windows/pthreads/sched_get_priority_max.c @@ -1,134 +1,134 @@ -/* - * sched_get_priority_max.c - * - * Description: - * POSIX thread functions that deal with thread scheduling. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" -#include "sched.h" - -/* - * On Windows98, THREAD_PRIORITY_LOWEST is (-2) and - * THREAD_PRIORITY_HIGHEST is 2, and everything works just fine. - * - * On WinCE 3.0, it so happen that THREAD_PRIORITY_LOWEST is 5 - * and THREAD_PRIORITY_HIGHEST is 1 (yes, I know, it is funny: - * highest priority use smaller numbers) and the following happens: - * - * sched_get_priority_min() returns 5 - * sched_get_priority_max() returns 1 - * - * The following table shows the base priority levels for combinations - * of priority class and priority value in Win32. - * - * Process Priority Class Thread Priority Level - * ----------------------------------------------------------------- - * 1 IDLE_PRIORITY_CLASS THREAD_PRIORITY_IDLE - * 1 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE - * 1 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE - * 1 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE - * 1 HIGH_PRIORITY_CLASS THREAD_PRIORITY_IDLE - * 2 IDLE_PRIORITY_CLASS THREAD_PRIORITY_LOWEST - * 3 IDLE_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL - * 4 IDLE_PRIORITY_CLASS THREAD_PRIORITY_NORMAL - * 4 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST - * 5 IDLE_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL - * 5 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL - * 5 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST - * 6 IDLE_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST - * 6 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL - * 6 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL - * 7 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL - * 7 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL - * 7 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST - * 8 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST - * 8 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL - * 8 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL - * 8 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST - * 9 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST - * 9 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL - * 9 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL - * 10 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL - * 10 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL - * 11 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST - * 11 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL - * 11 HIGH_PRIORITY_CLASS THREAD_PRIORITY_LOWEST - * 12 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST - * 12 HIGH_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL - * 13 HIGH_PRIORITY_CLASS THREAD_PRIORITY_NORMAL - * 14 HIGH_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL - * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST - * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL - * 15 IDLE_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL - * 15 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL - * 15 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL - * 15 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL - * 16 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_IDLE - * 17 REALTIME_PRIORITY_CLASS -7 - * 18 REALTIME_PRIORITY_CLASS -6 - * 19 REALTIME_PRIORITY_CLASS -5 - * 20 REALTIME_PRIORITY_CLASS -4 - * 21 REALTIME_PRIORITY_CLASS -3 - * 22 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_LOWEST - * 23 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL - * 24 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_NORMAL - * 25 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL - * 26 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST - * 27 REALTIME_PRIORITY_CLASS 3 - * 28 REALTIME_PRIORITY_CLASS 4 - * 29 REALTIME_PRIORITY_CLASS 5 - * 30 REALTIME_PRIORITY_CLASS 6 - * 31 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL - * - * Windows NT: Values -7, -6, -5, -4, -3, 3, 4, 5, and 6 are not supported. - */ - - -int -sched_get_priority_max (int policy) -{ - if (policy < SCHED_MIN || policy > SCHED_MAX) - { - errno = EINVAL; - return -1; - } - -#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) - /* WinCE? */ - return PTW32_MAX (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL); -#else - /* This is independent of scheduling policy in Win32. */ - return PTW32_MAX (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL); -#endif -} +/* + * sched_get_priority_max.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +/* + * On Windows98, THREAD_PRIORITY_LOWEST is (-2) and + * THREAD_PRIORITY_HIGHEST is 2, and everything works just fine. + * + * On WinCE 3.0, it so happen that THREAD_PRIORITY_LOWEST is 5 + * and THREAD_PRIORITY_HIGHEST is 1 (yes, I know, it is funny: + * highest priority use smaller numbers) and the following happens: + * + * sched_get_priority_min() returns 5 + * sched_get_priority_max() returns 1 + * + * The following table shows the base priority levels for combinations + * of priority class and priority value in Win32. + * + * Process Priority Class Thread Priority Level + * ----------------------------------------------------------------- + * 1 IDLE_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 HIGH_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 2 IDLE_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 3 IDLE_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 4 IDLE_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 4 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 5 IDLE_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 5 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 5 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 6 IDLE_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 6 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 6 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 7 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 7 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 7 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 8 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 8 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 8 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 8 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 9 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 9 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 9 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 10 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 10 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 11 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 11 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 11 HIGH_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 12 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 12 HIGH_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 13 HIGH_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 14 HIGH_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 IDLE_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 16 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 17 REALTIME_PRIORITY_CLASS -7 + * 18 REALTIME_PRIORITY_CLASS -6 + * 19 REALTIME_PRIORITY_CLASS -5 + * 20 REALTIME_PRIORITY_CLASS -4 + * 21 REALTIME_PRIORITY_CLASS -3 + * 22 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 23 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 24 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 25 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 26 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 27 REALTIME_PRIORITY_CLASS 3 + * 28 REALTIME_PRIORITY_CLASS 4 + * 29 REALTIME_PRIORITY_CLASS 5 + * 30 REALTIME_PRIORITY_CLASS 6 + * 31 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * + * Windows NT: Values -7, -6, -5, -4, -3, 3, 4, 5, and 6 are not supported. + */ + + +int +sched_get_priority_max (int policy) +{ + if (policy < SCHED_MIN || policy > SCHED_MAX) + { + errno = EINVAL; + return -1; + } + +#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) + /* WinCE? */ + return PTW32_MAX (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL); +#else + /* This is independent of scheduling policy in Win32. */ + return PTW32_MAX (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL); +#endif +} diff --git a/pcsx2/windows/pthreads/sched_get_priority_min.c b/pcsx2/windows/pthreads/sched_get_priority_min.c index 3c6d24aa4c..9c4f8591e5 100644 --- a/pcsx2/windows/pthreads/sched_get_priority_min.c +++ b/pcsx2/windows/pthreads/sched_get_priority_min.c @@ -1,135 +1,135 @@ -/* - * sched_get_priority_min.c - * - * Description: - * POSIX thread functions that deal with thread scheduling. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" -#include "sched.h" - -/* - * On Windows98, THREAD_PRIORITY_LOWEST is (-2) and - * THREAD_PRIORITY_HIGHEST is 2, and everything works just fine. - * - * On WinCE 3.0, it so happen that THREAD_PRIORITY_LOWEST is 5 - * and THREAD_PRIORITY_HIGHEST is 1 (yes, I know, it is funny: - * highest priority use smaller numbers) and the following happens: - * - * sched_get_priority_min() returns 5 - * sched_get_priority_max() returns 1 - * - * The following table shows the base priority levels for combinations - * of priority class and priority value in Win32. - * - * Process Priority Class Thread Priority Level - * ----------------------------------------------------------------- - * 1 IDLE_PRIORITY_CLASS THREAD_PRIORITY_IDLE - * 1 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE - * 1 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE - * 1 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE - * 1 HIGH_PRIORITY_CLASS THREAD_PRIORITY_IDLE - * 2 IDLE_PRIORITY_CLASS THREAD_PRIORITY_LOWEST - * 3 IDLE_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL - * 4 IDLE_PRIORITY_CLASS THREAD_PRIORITY_NORMAL - * 4 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST - * 5 IDLE_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL - * 5 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL - * 5 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST - * 6 IDLE_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST - * 6 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL - * 6 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL - * 7 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL - * 7 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL - * 7 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST - * 8 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST - * 8 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL - * 8 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL - * 8 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST - * 9 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST - * 9 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL - * 9 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL - * 10 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL - * 10 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL - * 11 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST - * 11 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL - * 11 HIGH_PRIORITY_CLASS THREAD_PRIORITY_LOWEST - * 12 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST - * 12 HIGH_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL - * 13 HIGH_PRIORITY_CLASS THREAD_PRIORITY_NORMAL - * 14 HIGH_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL - * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST - * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL - * 15 IDLE_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL - * 15 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL - * 15 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL - * 15 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL - * 16 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_IDLE - * 17 REALTIME_PRIORITY_CLASS -7 - * 18 REALTIME_PRIORITY_CLASS -6 - * 19 REALTIME_PRIORITY_CLASS -5 - * 20 REALTIME_PRIORITY_CLASS -4 - * 21 REALTIME_PRIORITY_CLASS -3 - * 22 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_LOWEST - * 23 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL - * 24 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_NORMAL - * 25 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL - * 26 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST - * 27 REALTIME_PRIORITY_CLASS 3 - * 28 REALTIME_PRIORITY_CLASS 4 - * 29 REALTIME_PRIORITY_CLASS 5 - * 30 REALTIME_PRIORITY_CLASS 6 - * 31 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL - * - * Windows NT: Values -7, -6, -5, -4, -3, 3, 4, 5, and 6 are not supported. - * - */ - - -int -sched_get_priority_min (int policy) -{ - if (policy < SCHED_MIN || policy > SCHED_MAX) - { - errno = EINVAL; - return -1; - } - -#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) - /* WinCE? */ - return PTW32_MIN (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL); -#else - /* This is independent of scheduling policy in Win32. */ - return PTW32_MIN (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL); -#endif -} +/* + * sched_get_priority_min.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +/* + * On Windows98, THREAD_PRIORITY_LOWEST is (-2) and + * THREAD_PRIORITY_HIGHEST is 2, and everything works just fine. + * + * On WinCE 3.0, it so happen that THREAD_PRIORITY_LOWEST is 5 + * and THREAD_PRIORITY_HIGHEST is 1 (yes, I know, it is funny: + * highest priority use smaller numbers) and the following happens: + * + * sched_get_priority_min() returns 5 + * sched_get_priority_max() returns 1 + * + * The following table shows the base priority levels for combinations + * of priority class and priority value in Win32. + * + * Process Priority Class Thread Priority Level + * ----------------------------------------------------------------- + * 1 IDLE_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 HIGH_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 2 IDLE_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 3 IDLE_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 4 IDLE_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 4 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 5 IDLE_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 5 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 5 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 6 IDLE_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 6 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 6 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 7 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 7 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 7 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 8 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 8 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 8 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 8 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 9 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 9 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 9 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 10 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 10 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 11 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 11 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 11 HIGH_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 12 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 12 HIGH_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 13 HIGH_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 14 HIGH_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 IDLE_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 16 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 17 REALTIME_PRIORITY_CLASS -7 + * 18 REALTIME_PRIORITY_CLASS -6 + * 19 REALTIME_PRIORITY_CLASS -5 + * 20 REALTIME_PRIORITY_CLASS -4 + * 21 REALTIME_PRIORITY_CLASS -3 + * 22 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 23 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 24 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 25 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 26 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 27 REALTIME_PRIORITY_CLASS 3 + * 28 REALTIME_PRIORITY_CLASS 4 + * 29 REALTIME_PRIORITY_CLASS 5 + * 30 REALTIME_PRIORITY_CLASS 6 + * 31 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * + * Windows NT: Values -7, -6, -5, -4, -3, 3, 4, 5, and 6 are not supported. + * + */ + + +int +sched_get_priority_min (int policy) +{ + if (policy < SCHED_MIN || policy > SCHED_MAX) + { + errno = EINVAL; + return -1; + } + +#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) + /* WinCE? */ + return PTW32_MIN (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL); +#else + /* This is independent of scheduling policy in Win32. */ + return PTW32_MIN (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL); +#endif +} diff --git a/pcsx2/windows/pthreads/sched_getscheduler.c b/pcsx2/windows/pthreads/sched_getscheduler.c index 1f0957cbf4..9bc819e476 100644 --- a/pcsx2/windows/pthreads/sched_getscheduler.c +++ b/pcsx2/windows/pthreads/sched_getscheduler.c @@ -1,69 +1,69 @@ -/* - * sched_getscheduler.c - * - * Description: - * POSIX thread functions that deal with thread scheduling. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" -#include "sched.h" - -int -sched_getscheduler (pid_t pid) -{ - /* - * Win32 only has one policy which we call SCHED_OTHER. - * However, we try to provide other valid side-effects - * such as EPERM and ESRCH errors. - */ - if (0 != pid) - { - int selfPid = (int) GetCurrentProcessId (); - - if (pid != selfPid) - { - HANDLE h = - OpenProcess (PROCESS_QUERY_INFORMATION, PTW32_FALSE, (DWORD) pid); - - if (NULL == h) - { - errno = - (GetLastError () == - (0xFF & ERROR_ACCESS_DENIED)) ? EPERM : ESRCH; - return -1; - } - } - } - - return SCHED_OTHER; -} +/* + * sched_getscheduler.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +sched_getscheduler (pid_t pid) +{ + /* + * Win32 only has one policy which we call SCHED_OTHER. + * However, we try to provide other valid side-effects + * such as EPERM and ESRCH errors. + */ + if (0 != pid) + { + int selfPid = (int) GetCurrentProcessId (); + + if (pid != selfPid) + { + HANDLE h = + OpenProcess (PROCESS_QUERY_INFORMATION, PTW32_FALSE, (DWORD) pid); + + if (NULL == h) + { + errno = + (GetLastError () == + (0xFF & ERROR_ACCESS_DENIED)) ? EPERM : ESRCH; + return -1; + } + } + } + + return SCHED_OTHER; +} diff --git a/pcsx2/windows/pthreads/sched_setscheduler.c b/pcsx2/windows/pthreads/sched_setscheduler.c index 06f77901af..4e060c7e55 100644 --- a/pcsx2/windows/pthreads/sched_setscheduler.c +++ b/pcsx2/windows/pthreads/sched_setscheduler.c @@ -1,81 +1,81 @@ -/* - * sched_setscheduler.c - * - * Description: - * POSIX thread functions that deal with thread scheduling. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" -#include "sched.h" - -int -sched_setscheduler (pid_t pid, int policy) -{ - /* - * Win32 only has one policy which we call SCHED_OTHER. - * However, we try to provide other valid side-effects - * such as EPERM and ESRCH errors. Choosing to check - * for a valid policy last allows us to get the most value out - * of this function. - */ - if (0 != pid) - { - int selfPid = (int) GetCurrentProcessId (); - - if (pid != selfPid) - { - HANDLE h = - OpenProcess (PROCESS_SET_INFORMATION, PTW32_FALSE, (DWORD) pid); - - if (NULL == h) - { - errno = - (GetLastError () == - (0xFF & ERROR_ACCESS_DENIED)) ? EPERM : ESRCH; - return -1; - } - } - } - - if (SCHED_OTHER != policy) - { - errno = ENOSYS; - return -1; - } - - /* - * Don't set anything because there is nothing to set. - * Just return the current (the only possible) value. - */ - return SCHED_OTHER; -} +/* + * sched_setscheduler.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +sched_setscheduler (pid_t pid, int policy) +{ + /* + * Win32 only has one policy which we call SCHED_OTHER. + * However, we try to provide other valid side-effects + * such as EPERM and ESRCH errors. Choosing to check + * for a valid policy last allows us to get the most value out + * of this function. + */ + if (0 != pid) + { + int selfPid = (int) GetCurrentProcessId (); + + if (pid != selfPid) + { + HANDLE h = + OpenProcess (PROCESS_SET_INFORMATION, PTW32_FALSE, (DWORD) pid); + + if (NULL == h) + { + errno = + (GetLastError () == + (0xFF & ERROR_ACCESS_DENIED)) ? EPERM : ESRCH; + return -1; + } + } + } + + if (SCHED_OTHER != policy) + { + errno = ENOSYS; + return -1; + } + + /* + * Don't set anything because there is nothing to set. + * Just return the current (the only possible) value. + */ + return SCHED_OTHER; +} diff --git a/pcsx2/windows/pthreads/sched_yield.c b/pcsx2/windows/pthreads/sched_yield.c index 4220cc67fc..6ac5ed9263 100644 --- a/pcsx2/windows/pthreads/sched_yield.c +++ b/pcsx2/windows/pthreads/sched_yield.c @@ -1,71 +1,71 @@ -/* - * sched_yield.c - * - * Description: - * POSIX thread functions that deal with thread scheduling. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" -#include "sched.h" - -int -sched_yield (void) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function indicates that the calling thread is - * willing to give up some time slices to other threads. - * - * PARAMETERS - * N/A - * - * - * DESCRIPTION - * This function indicates that the calling thread is - * willing to give up some time slices to other threads. - * NOTE: Since this is part of POSIX 1003.1b - * (realtime extensions), it is defined as returning - * -1 if an error occurs and sets errno to the actual - * error. - * - * RESULTS - * 0 successfully created semaphore, - * ENOSYS sched_yield not supported, - * - * ------------------------------------------------------ - */ -{ - Sleep (0); - - return 0; -} +/* + * sched_yield.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +sched_yield (void) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function indicates that the calling thread is + * willing to give up some time slices to other threads. + * + * PARAMETERS + * N/A + * + * + * DESCRIPTION + * This function indicates that the calling thread is + * willing to give up some time slices to other threads. + * NOTE: Since this is part of POSIX 1003.1b + * (realtime extensions), it is defined as returning + * -1 if an error occurs and sets errno to the actual + * error. + * + * RESULTS + * 0 successfully created semaphore, + * ENOSYS sched_yield not supported, + * + * ------------------------------------------------------ + */ +{ + Sleep (0); + + return 0; +} diff --git a/pcsx2/windows/pthreads/sem_close.c b/pcsx2/windows/pthreads/sem_close.c index c778befac1..2f95c87857 100644 --- a/pcsx2/windows/pthreads/sem_close.c +++ b/pcsx2/windows/pthreads/sem_close.c @@ -1,58 +1,58 @@ -/* - * ------------------------------------------------------------- - * - * Module: sem_close.c - * - * Purpose: - * Semaphores aren't actually part of the PThreads standard. - * They are defined by the POSIX Standard: - * - * POSIX 1003.1b-1993 (POSIX.1b) - * - * ------------------------------------------------------------- - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "semaphore.h" -#include "implement.h" - -/* ignore warning "unreferenced formal parameter" */ -#ifdef _MSC_VER -#pragma warning( disable : 4100 ) -#endif - -int -sem_close (sem_t * sem) -{ - errno = ENOSYS; - return -1; -} /* sem_close */ +/* + * ------------------------------------------------------------- + * + * Module: sem_close.c + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + +/* ignore warning "unreferenced formal parameter" */ +#ifdef _MSC_VER +#pragma warning( disable : 4100 ) +#endif + +int +sem_close (sem_t * sem) +{ + errno = ENOSYS; + return -1; +} /* sem_close */ diff --git a/pcsx2/windows/pthreads/sem_destroy.c b/pcsx2/windows/pthreads/sem_destroy.c index e2bdf86ca8..6c98e80b93 100644 --- a/pcsx2/windows/pthreads/sem_destroy.c +++ b/pcsx2/windows/pthreads/sem_destroy.c @@ -1,144 +1,144 @@ -/* - * ------------------------------------------------------------- - * - * Module: sem_destroy.c - * - * Purpose: - * Semaphores aren't actually part of the PThreads standard. - * They are defined by the POSIX Standard: - * - * POSIX 1003.1b-1993 (POSIX.1b) - * - * ------------------------------------------------------------- - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "semaphore.h" -#include "implement.h" - - -int -sem_destroy (sem_t * sem) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function destroys an unnamed semaphore. - * - * PARAMETERS - * sem - * pointer to an instance of sem_t - * - * DESCRIPTION - * This function destroys an unnamed semaphore. - * - * RESULTS - * 0 successfully destroyed semaphore, - * -1 failed, error in errno - * ERRNO - * EINVAL 'sem' is not a valid semaphore, - * ENOSYS semaphores are not supported, - * EBUSY threads (or processes) are currently - * blocked on 'sem' - * - * ------------------------------------------------------ - */ -{ - int result = 0; - sem_t s = NULL; - - if (sem == NULL || *sem == NULL) - { - result = EINVAL; - } - else - { - s = *sem; - - if ((result = pthread_mutex_lock (&s->lock)) == 0) - { - if (s->value < 0) - { - (void) pthread_mutex_unlock (&s->lock); - result = EBUSY; - } - else - { - /* There are no threads currently blocked on this semaphore. */ - - if (!CloseHandle (s->sem)) - { - (void) pthread_mutex_unlock (&s->lock); - result = EINVAL; - } - else - { - /* - * Invalidate the semaphore handle when we have the lock. - * Other sema operations should test this after acquiring the lock - * to check that the sema is still valid, i.e. before performing any - * operations. This may only be necessary before the sema op routine - * returns so that the routine can return EINVAL - e.g. if setting - * s->value to SEM_VALUE_MAX below does force a fall-through. - */ - *sem = NULL; - - /* Prevent anyone else actually waiting on or posting this sema. - */ - s->value = SEM_VALUE_MAX; - - (void) pthread_mutex_unlock (&s->lock); - - do - { - /* Give other threads a chance to run and exit any sema op - * routines. Due to the SEM_VALUE_MAX value, if sem_post or - * sem_wait were blocked by us they should fall through. - */ - Sleep(0); - } - while (pthread_mutex_destroy (&s->lock) == EBUSY); - } - } - } - } - - if (result != 0) - { - errno = result; - return -1; - } - - free (s); - - return 0; - -} /* sem_destroy */ +/* + * ------------------------------------------------------------- + * + * Module: sem_destroy.c + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + + +int +sem_destroy (sem_t * sem) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function destroys an unnamed semaphore. + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * DESCRIPTION + * This function destroys an unnamed semaphore. + * + * RESULTS + * 0 successfully destroyed semaphore, + * -1 failed, error in errno + * ERRNO + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, + * EBUSY threads (or processes) are currently + * blocked on 'sem' + * + * ------------------------------------------------------ + */ +{ + int result = 0; + sem_t s = NULL; + + if (sem == NULL || *sem == NULL) + { + result = EINVAL; + } + else + { + s = *sem; + + if ((result = pthread_mutex_lock (&s->lock)) == 0) + { + if (s->value < 0) + { + (void) pthread_mutex_unlock (&s->lock); + result = EBUSY; + } + else + { + /* There are no threads currently blocked on this semaphore. */ + + if (!CloseHandle (s->sem)) + { + (void) pthread_mutex_unlock (&s->lock); + result = EINVAL; + } + else + { + /* + * Invalidate the semaphore handle when we have the lock. + * Other sema operations should test this after acquiring the lock + * to check that the sema is still valid, i.e. before performing any + * operations. This may only be necessary before the sema op routine + * returns so that the routine can return EINVAL - e.g. if setting + * s->value to SEM_VALUE_MAX below does force a fall-through. + */ + *sem = NULL; + + /* Prevent anyone else actually waiting on or posting this sema. + */ + s->value = SEM_VALUE_MAX; + + (void) pthread_mutex_unlock (&s->lock); + + do + { + /* Give other threads a chance to run and exit any sema op + * routines. Due to the SEM_VALUE_MAX value, if sem_post or + * sem_wait were blocked by us they should fall through. + */ + Sleep(0); + } + while (pthread_mutex_destroy (&s->lock) == EBUSY); + } + } + } + } + + if (result != 0) + { + errno = result; + return -1; + } + + free (s); + + return 0; + +} /* sem_destroy */ diff --git a/pcsx2/windows/pthreads/sem_getvalue.c b/pcsx2/windows/pthreads/sem_getvalue.c index 233635b139..baafb02cf0 100644 --- a/pcsx2/windows/pthreads/sem_getvalue.c +++ b/pcsx2/windows/pthreads/sem_getvalue.c @@ -1,110 +1,110 @@ -/* - * ------------------------------------------------------------- - * - * Module: sem_getvalue.c - * - * Purpose: - * Semaphores aren't actually part of PThreads. - * They are defined by the POSIX Standard: - * - * POSIX 1003.1-2001 - * - * ------------------------------------------------------------- - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "semaphore.h" -#include "implement.h" - - -int -sem_getvalue (sem_t * sem, int *sval) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function stores the current count value of the - * semaphore. - * RESULTS - * - * Return value - * - * 0 sval has been set. - * -1 failed, error in errno - * - * in global errno - * - * EINVAL 'sem' is not a valid semaphore, - * ENOSYS this function is not supported, - * - * - * PARAMETERS - * - * sem pointer to an instance of sem_t - * - * sval pointer to int. - * - * DESCRIPTION - * This function stores the current count value of the semaphore - * pointed to by sem in the int pointed to by sval. - */ -{ - if (sem == NULL || *sem == NULL || sval == NULL) - { - errno = EINVAL; - return -1; - } - else - { - long value; - register sem_t s = *sem; - int result = 0; - - if ((result = pthread_mutex_lock(&s->lock)) == 0) - { - /* See sem_destroy.c - */ - if (*sem == NULL) - { - (void) pthread_mutex_unlock (&s->lock); - errno = EINVAL; - return -1; - } - - value = s->value; - (void) pthread_mutex_unlock(&s->lock); - *sval = value; - } - - return result; - } - -} /* sem_getvalue */ +/* + * ------------------------------------------------------------- + * + * Module: sem_getvalue.c + * + * Purpose: + * Semaphores aren't actually part of PThreads. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1-2001 + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + + +int +sem_getvalue (sem_t * sem, int *sval) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function stores the current count value of the + * semaphore. + * RESULTS + * + * Return value + * + * 0 sval has been set. + * -1 failed, error in errno + * + * in global errno + * + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS this function is not supported, + * + * + * PARAMETERS + * + * sem pointer to an instance of sem_t + * + * sval pointer to int. + * + * DESCRIPTION + * This function stores the current count value of the semaphore + * pointed to by sem in the int pointed to by sval. + */ +{ + if (sem == NULL || *sem == NULL || sval == NULL) + { + errno = EINVAL; + return -1; + } + else + { + long value; + register sem_t s = *sem; + int result = 0; + + if ((result = pthread_mutex_lock(&s->lock)) == 0) + { + /* See sem_destroy.c + */ + if (*sem == NULL) + { + (void) pthread_mutex_unlock (&s->lock); + errno = EINVAL; + return -1; + } + + value = s->value; + (void) pthread_mutex_unlock(&s->lock); + *sval = value; + } + + return result; + } + +} /* sem_getvalue */ diff --git a/pcsx2/windows/pthreads/sem_init.c b/pcsx2/windows/pthreads/sem_init.c index 8e5e3f3902..02acd90f11 100644 --- a/pcsx2/windows/pthreads/sem_init.c +++ b/pcsx2/windows/pthreads/sem_init.c @@ -1,169 +1,169 @@ -/* - * ------------------------------------------------------------- - * - * Module: sem_init.c - * - * Purpose: - * Semaphores aren't actually part of PThreads. - * They are defined by the POSIX Standard: - * - * POSIX 1003.1-2001 - * - * ------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "semaphore.h" -#include "implement.h" - -int -sem_init (sem_t * sem, int pshared, unsigned int value) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function initializes a semaphore. The - * initial value of the semaphore is 'value' - * - * PARAMETERS - * sem - * pointer to an instance of sem_t - * - * pshared - * if zero, this semaphore may only be shared between - * threads in the same process. - * if nonzero, the semaphore can be shared between - * processes - * - * value - * initial value of the semaphore counter - * - * DESCRIPTION - * This function initializes a semaphore. The - * initial value of the semaphore is set to 'value'. - * - * RESULTS - * 0 successfully created semaphore, - * -1 failed, error in errno - * ERRNO - * EINVAL 'sem' is not a valid semaphore, or - * 'value' >= SEM_VALUE_MAX - * ENOMEM out of memory, - * ENOSPC a required resource has been exhausted, - * ENOSYS semaphores are not supported, - * EPERM the process lacks appropriate privilege - * - * ------------------------------------------------------ - */ -{ - int result = 0; - sem_t s = NULL; - - if (pshared != 0) - { - /* - * Creating a semaphore that can be shared between - * processes - */ - result = EPERM; - } - else if (value > (unsigned int)SEM_VALUE_MAX) - { - result = EINVAL; - } - else - { - s = (sem_t) calloc (1, sizeof (*s)); - - if (NULL == s) - { - result = ENOMEM; - } - else - { - - s->value = value; - if (pthread_mutex_init(&s->lock, NULL) == 0) - { - -#ifdef NEED_SEM - - s->sem = CreateEvent (NULL, - PTW32_FALSE, /* auto (not manual) reset */ - PTW32_FALSE, /* initial state is unset */ - NULL); - - if (0 == s->sem) - { - free (s); - (void) pthread_mutex_destroy(&s->lock); - result = ENOSPC; - } - else - { - s->leftToUnblock = 0; - } - -#else /* NEED_SEM */ - - if ((s->sem = CreateSemaphore (NULL, /* Always NULL */ - (long) 0, /* Force threads to wait */ - (long) SEM_VALUE_MAX, /* Maximum value */ - NULL)) == 0) /* Name */ - { - (void) pthread_mutex_destroy(&s->lock); - result = ENOSPC; - } - -#endif /* NEED_SEM */ - - } - else - { - result = ENOSPC; - } - - if (result != 0) - { - free(s); - } - } - } - - if (result != 0) - { - errno = result; - return -1; - } - - *sem = s; - - return 0; - -} /* sem_init */ +/* + * ------------------------------------------------------------- + * + * Module: sem_init.c + * + * Purpose: + * Semaphores aren't actually part of PThreads. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1-2001 + * + * ------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + +int +sem_init (sem_t * sem, int pshared, unsigned int value) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function initializes a semaphore. The + * initial value of the semaphore is 'value' + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * pshared + * if zero, this semaphore may only be shared between + * threads in the same process. + * if nonzero, the semaphore can be shared between + * processes + * + * value + * initial value of the semaphore counter + * + * DESCRIPTION + * This function initializes a semaphore. The + * initial value of the semaphore is set to 'value'. + * + * RESULTS + * 0 successfully created semaphore, + * -1 failed, error in errno + * ERRNO + * EINVAL 'sem' is not a valid semaphore, or + * 'value' >= SEM_VALUE_MAX + * ENOMEM out of memory, + * ENOSPC a required resource has been exhausted, + * ENOSYS semaphores are not supported, + * EPERM the process lacks appropriate privilege + * + * ------------------------------------------------------ + */ +{ + int result = 0; + sem_t s = NULL; + + if (pshared != 0) + { + /* + * Creating a semaphore that can be shared between + * processes + */ + result = EPERM; + } + else if (value > (unsigned int)SEM_VALUE_MAX) + { + result = EINVAL; + } + else + { + s = (sem_t) calloc (1, sizeof (*s)); + + if (NULL == s) + { + result = ENOMEM; + } + else + { + + s->value = value; + if (pthread_mutex_init(&s->lock, NULL) == 0) + { + +#ifdef NEED_SEM + + s->sem = CreateEvent (NULL, + PTW32_FALSE, /* auto (not manual) reset */ + PTW32_FALSE, /* initial state is unset */ + NULL); + + if (0 == s->sem) + { + free (s); + (void) pthread_mutex_destroy(&s->lock); + result = ENOSPC; + } + else + { + s->leftToUnblock = 0; + } + +#else /* NEED_SEM */ + + if ((s->sem = CreateSemaphore (NULL, /* Always NULL */ + (long) 0, /* Force threads to wait */ + (long) SEM_VALUE_MAX, /* Maximum value */ + NULL)) == 0) /* Name */ + { + (void) pthread_mutex_destroy(&s->lock); + result = ENOSPC; + } + +#endif /* NEED_SEM */ + + } + else + { + result = ENOSPC; + } + + if (result != 0) + { + free(s); + } + } + } + + if (result != 0) + { + errno = result; + return -1; + } + + *sem = s; + + return 0; + +} /* sem_init */ diff --git a/pcsx2/windows/pthreads/sem_open.c b/pcsx2/windows/pthreads/sem_open.c index 3e2d6688f7..bf48c831ca 100644 --- a/pcsx2/windows/pthreads/sem_open.c +++ b/pcsx2/windows/pthreads/sem_open.c @@ -1,58 +1,58 @@ -/* - * ------------------------------------------------------------- - * - * Module: sem_open.c - * - * Purpose: - * Semaphores aren't actually part of the PThreads standard. - * They are defined by the POSIX Standard: - * - * POSIX 1003.1b-1993 (POSIX.1b) - * - * ------------------------------------------------------------- - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "semaphore.h" -#include "implement.h" - -/* ignore warning "unreferenced formal parameter" */ -#ifdef _MSC_VER -#pragma warning( disable : 4100 ) -#endif - -int -sem_open (const char *name, int oflag, mode_t mode, unsigned int value) -{ - errno = ENOSYS; - return -1; -} /* sem_open */ +/* + * ------------------------------------------------------------- + * + * Module: sem_open.c + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + +/* ignore warning "unreferenced formal parameter" */ +#ifdef _MSC_VER +#pragma warning( disable : 4100 ) +#endif + +int +sem_open (const char *name, int oflag, mode_t mode, unsigned int value) +{ + errno = ENOSYS; + return -1; +} /* sem_open */ diff --git a/pcsx2/windows/pthreads/sem_post.c b/pcsx2/windows/pthreads/sem_post.c index 9449cb2b7d..c7a7a3cf90 100644 --- a/pcsx2/windows/pthreads/sem_post.c +++ b/pcsx2/windows/pthreads/sem_post.c @@ -1,128 +1,128 @@ -/* - * ------------------------------------------------------------- - * - * Module: sem_post.c - * - * Purpose: - * Semaphores aren't actually part of the PThreads standard. - * They are defined by the POSIX Standard: - * - * POSIX 1003.1b-1993 (POSIX.1b) - * - * ------------------------------------------------------------- - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "semaphore.h" -#include "implement.h" - - -int -sem_post (sem_t * sem) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function posts a wakeup to a semaphore. - * - * PARAMETERS - * sem - * pointer to an instance of sem_t - * - * DESCRIPTION - * This function posts a wakeup to a semaphore. If there - * are waiting threads (or processes), one is awakened; - * otherwise, the semaphore value is incremented by one. - * - * RESULTS - * 0 successfully posted semaphore, - * -1 failed, error in errno - * ERRNO - * EINVAL 'sem' is not a valid semaphore, - * ENOSYS semaphores are not supported, - * ERANGE semaphore count is too big - * - * ------------------------------------------------------ - */ -{ - int result = 0; - sem_t s = *sem; - - if (s == NULL) - { - result = EINVAL; - } - else if ((result = pthread_mutex_lock (&s->lock)) == 0) - { - /* See sem_destroy.c - */ - if (*sem == NULL) - { - (void) pthread_mutex_unlock (&s->lock); - result = EINVAL; - return -1; - } - - if (s->value < SEM_VALUE_MAX) - { -#ifdef NEED_SEM - if (++s->value <= 0 - && !SetEvent(s->sem)) - { - s->value--; - result = EINVAL; - } -#else - if (++s->value <= 0 - && !ReleaseSemaphore (s->sem, 1, NULL)) - { - s->value--; - result = EINVAL; - } -#endif /* NEED_SEM */ - } - else - { - result = ERANGE; - } - - (void) pthread_mutex_unlock (&s->lock); - } - - if (result != 0) - { - errno = result; - return -1; - } - - return 0; - -} /* sem_post */ +/* + * ------------------------------------------------------------- + * + * Module: sem_post.c + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + + +int +sem_post (sem_t * sem) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function posts a wakeup to a semaphore. + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * DESCRIPTION + * This function posts a wakeup to a semaphore. If there + * are waiting threads (or processes), one is awakened; + * otherwise, the semaphore value is incremented by one. + * + * RESULTS + * 0 successfully posted semaphore, + * -1 failed, error in errno + * ERRNO + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, + * ERANGE semaphore count is too big + * + * ------------------------------------------------------ + */ +{ + int result = 0; + sem_t s = *sem; + + if (s == NULL) + { + result = EINVAL; + } + else if ((result = pthread_mutex_lock (&s->lock)) == 0) + { + /* See sem_destroy.c + */ + if (*sem == NULL) + { + (void) pthread_mutex_unlock (&s->lock); + result = EINVAL; + return -1; + } + + if (s->value < SEM_VALUE_MAX) + { +#ifdef NEED_SEM + if (++s->value <= 0 + && !SetEvent(s->sem)) + { + s->value--; + result = EINVAL; + } +#else + if (++s->value <= 0 + && !ReleaseSemaphore (s->sem, 1, NULL)) + { + s->value--; + result = EINVAL; + } +#endif /* NEED_SEM */ + } + else + { + result = ERANGE; + } + + (void) pthread_mutex_unlock (&s->lock); + } + + if (result != 0) + { + errno = result; + return -1; + } + + return 0; + +} /* sem_post */ diff --git a/pcsx2/windows/pthreads/sem_post_multiple.c b/pcsx2/windows/pthreads/sem_post_multiple.c index 0784bc46bf..3d1e4ef286 100644 --- a/pcsx2/windows/pthreads/sem_post_multiple.c +++ b/pcsx2/windows/pthreads/sem_post_multiple.c @@ -1,142 +1,142 @@ -/* - * ------------------------------------------------------------- - * - * Module: sem_post_multiple.c - * - * Purpose: - * Semaphores aren't actually part of the PThreads standard. - * They are defined by the POSIX Standard: - * - * POSIX 1003.1b-1993 (POSIX.1b) - * - * ------------------------------------------------------------- - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "semaphore.h" -#include "implement.h" - - -int -sem_post_multiple (sem_t * sem, int count) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function posts multiple wakeups to a semaphore. - * - * PARAMETERS - * sem - * pointer to an instance of sem_t - * - * count - * counter, must be greater than zero. - * - * DESCRIPTION - * This function posts multiple wakeups to a semaphore. If there - * are waiting threads (or processes), n <= count are awakened; - * the semaphore value is incremented by count - n. - * - * RESULTS - * 0 successfully posted semaphore, - * -1 failed, error in errno - * ERRNO - * EINVAL 'sem' is not a valid semaphore - * or count is less than or equal to zero. - * ERANGE semaphore count is too big - * - * ------------------------------------------------------ - */ -{ - int result = 0; - long waiters; - sem_t s = *sem; - - if (s == NULL || count <= 0) - { - result = EINVAL; - } - else if ((result = pthread_mutex_lock (&s->lock)) == 0) - { - /* See sem_destroy.c - */ - if (*sem == NULL) - { - (void) pthread_mutex_unlock (&s->lock); - result = EINVAL; - return -1; - } - - if (s->value <= (SEM_VALUE_MAX - count)) - { - waiters = -s->value; - s->value += count; - if (waiters > 0) - { -#ifdef NEED_SEM - if (SetEvent(s->sem)) - { - waiters--; - s->leftToUnblock += count - 1; - if (s->leftToUnblock > waiters) - { - s->leftToUnblock = waiters; - } - } -#else - if (ReleaseSemaphore (s->sem, (waiters<=count)?waiters:count, 0)) - { - /* No action */ - } -#endif - else - { - s->value -= count; - result = EINVAL; - } - } - } - else - { - result = ERANGE; - } - (void) pthread_mutex_unlock (&s->lock); - } - - if (result != 0) - { - errno = result; - return -1; - } - - return 0; - -} /* sem_post_multiple */ +/* + * ------------------------------------------------------------- + * + * Module: sem_post_multiple.c + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + + +int +sem_post_multiple (sem_t * sem, int count) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function posts multiple wakeups to a semaphore. + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * count + * counter, must be greater than zero. + * + * DESCRIPTION + * This function posts multiple wakeups to a semaphore. If there + * are waiting threads (or processes), n <= count are awakened; + * the semaphore value is incremented by count - n. + * + * RESULTS + * 0 successfully posted semaphore, + * -1 failed, error in errno + * ERRNO + * EINVAL 'sem' is not a valid semaphore + * or count is less than or equal to zero. + * ERANGE semaphore count is too big + * + * ------------------------------------------------------ + */ +{ + int result = 0; + long waiters; + sem_t s = *sem; + + if (s == NULL || count <= 0) + { + result = EINVAL; + } + else if ((result = pthread_mutex_lock (&s->lock)) == 0) + { + /* See sem_destroy.c + */ + if (*sem == NULL) + { + (void) pthread_mutex_unlock (&s->lock); + result = EINVAL; + return -1; + } + + if (s->value <= (SEM_VALUE_MAX - count)) + { + waiters = -s->value; + s->value += count; + if (waiters > 0) + { +#ifdef NEED_SEM + if (SetEvent(s->sem)) + { + waiters--; + s->leftToUnblock += count - 1; + if (s->leftToUnblock > waiters) + { + s->leftToUnblock = waiters; + } + } +#else + if (ReleaseSemaphore (s->sem, (waiters<=count)?waiters:count, 0)) + { + /* No action */ + } +#endif + else + { + s->value -= count; + result = EINVAL; + } + } + } + else + { + result = ERANGE; + } + (void) pthread_mutex_unlock (&s->lock); + } + + if (result != 0) + { + errno = result; + return -1; + } + + return 0; + +} /* sem_post_multiple */ diff --git a/pcsx2/windows/pthreads/sem_timedwait.c b/pcsx2/windows/pthreads/sem_timedwait.c index 684ecd10d0..52146b478e 100644 --- a/pcsx2/windows/pthreads/sem_timedwait.c +++ b/pcsx2/windows/pthreads/sem_timedwait.c @@ -1,238 +1,238 @@ -/* - * ------------------------------------------------------------- - * - * Module: sem_timedwait.c - * - * Purpose: - * Semaphores aren't actually part of the PThreads standard. - * They are defined by the POSIX Standard: - * - * POSIX 1003.1b-1993 (POSIX.1b) - * - * ------------------------------------------------------------- - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "semaphore.h" -#include "implement.h" - - -typedef struct { - sem_t sem; - int * resultPtr; -} sem_timedwait_cleanup_args_t; - - -static void PTW32_CDECL -ptw32_sem_timedwait_cleanup (void * args) -{ - sem_timedwait_cleanup_args_t * a = (sem_timedwait_cleanup_args_t *)args; - sem_t s = a->sem; - - if (pthread_mutex_lock (&s->lock) == 0) - { - /* - * We either timed out or were cancelled. - * If someone has posted between then and now we try to take the semaphore. - * Otherwise the semaphore count may be wrong after we - * return. In the case of a cancellation, it is as if we - * were cancelled just before we return (after taking the semaphore) - * which is ok. - */ - if (WaitForSingleObject(s->sem, 0) == WAIT_OBJECT_0) - { - /* We got the semaphore on the second attempt */ - *(a->resultPtr) = 0; - } - else - { - /* Indicate we're no longer waiting */ - s->value++; -#ifdef NEED_SEM - if (s->value > 0) - { - s->leftToUnblock = 0; - } -#else - /* - * Don't release the W32 sema, it doesn't need adjustment - * because it doesn't record the number of waiters. - */ -#endif - } - (void) pthread_mutex_unlock (&s->lock); - } -} - - -int -sem_timedwait (sem_t * sem, const struct timespec *abstime) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function waits on a semaphore possibly until - * 'abstime' time. - * - * PARAMETERS - * sem - * pointer to an instance of sem_t - * - * abstime - * pointer to an instance of struct timespec - * - * DESCRIPTION - * This function waits on a semaphore. If the - * semaphore value is greater than zero, it decreases - * its value by one. If the semaphore value is zero, then - * the calling thread (or process) is blocked until it can - * successfully decrease the value or until interrupted by - * a signal. - * - * If 'abstime' is a NULL pointer then this function will - * block until it can successfully decrease the value or - * until interrupted by a signal. - * - * RESULTS - * 0 successfully decreased semaphore, - * -1 failed, error in errno - * ERRNO - * EINVAL 'sem' is not a valid semaphore, - * ENOSYS semaphores are not supported, - * EINTR the function was interrupted by a signal, - * EDEADLK a deadlock condition was detected. - * ETIMEDOUT abstime elapsed before success. - * - * ------------------------------------------------------ - */ -{ - int result = 0; - sem_t s = *sem; - - pthread_testcancel(); - - if (sem == NULL) - { - result = EINVAL; - } - else - { - DWORD milliseconds; - - if (abstime == NULL) - { - milliseconds = INFINITE; - } - else - { - /* - * Calculate timeout as milliseconds from current system time. - */ - milliseconds = ptw32_relmillisecs (abstime); - } - - if ((result = pthread_mutex_lock (&s->lock)) == 0) - { - int v; - - /* See sem_destroy.c - */ - if (*sem == NULL) - { - (void) pthread_mutex_unlock (&s->lock); - errno = EINVAL; - return -1; - } - - v = --s->value; - (void) pthread_mutex_unlock (&s->lock); - - if (v < 0) - { -#ifdef NEED_SEM - int timedout; -#endif - sem_timedwait_cleanup_args_t cleanup_args; - - cleanup_args.sem = s; - cleanup_args.resultPtr = &result; - -#ifdef _MSC_VER -#pragma inline_depth(0) -#endif - /* Must wait */ - pthread_cleanup_push(ptw32_sem_timedwait_cleanup, (void *) &cleanup_args); -#ifdef NEED_SEM - timedout = -#endif - result = pthreadCancelableTimedWait (s->sem, milliseconds); - pthread_cleanup_pop(result); -#ifdef _MSC_VER -#pragma inline_depth() -#endif - -#ifdef NEED_SEM - - if (!timedout && pthread_mutex_lock (&s->lock) == 0) - { - if (*sem == NULL) - { - (void) pthread_mutex_unlock (&s->lock); - errno = EINVAL; - return -1; - } - - if (s->leftToUnblock > 0) - { - --s->leftToUnblock; - SetEvent(s->sem); - } - (void) pthread_mutex_unlock (&s->lock); - } - -#endif /* NEED_SEM */ - - } - } - - } - - if (result != 0) - { - - errno = result; - return -1; - - } - - return 0; - -} /* sem_timedwait */ +/* + * ------------------------------------------------------------- + * + * Module: sem_timedwait.c + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + + +typedef struct { + sem_t sem; + int * resultPtr; +} sem_timedwait_cleanup_args_t; + + +static void PTW32_CDECL +ptw32_sem_timedwait_cleanup (void * args) +{ + sem_timedwait_cleanup_args_t * a = (sem_timedwait_cleanup_args_t *)args; + sem_t s = a->sem; + + if (pthread_mutex_lock (&s->lock) == 0) + { + /* + * We either timed out or were cancelled. + * If someone has posted between then and now we try to take the semaphore. + * Otherwise the semaphore count may be wrong after we + * return. In the case of a cancellation, it is as if we + * were cancelled just before we return (after taking the semaphore) + * which is ok. + */ + if (WaitForSingleObject(s->sem, 0) == WAIT_OBJECT_0) + { + /* We got the semaphore on the second attempt */ + *(a->resultPtr) = 0; + } + else + { + /* Indicate we're no longer waiting */ + s->value++; +#ifdef NEED_SEM + if (s->value > 0) + { + s->leftToUnblock = 0; + } +#else + /* + * Don't release the W32 sema, it doesn't need adjustment + * because it doesn't record the number of waiters. + */ +#endif + } + (void) pthread_mutex_unlock (&s->lock); + } +} + + +int +sem_timedwait (sem_t * sem, const struct timespec *abstime) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function waits on a semaphore possibly until + * 'abstime' time. + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * abstime + * pointer to an instance of struct timespec + * + * DESCRIPTION + * This function waits on a semaphore. If the + * semaphore value is greater than zero, it decreases + * its value by one. If the semaphore value is zero, then + * the calling thread (or process) is blocked until it can + * successfully decrease the value or until interrupted by + * a signal. + * + * If 'abstime' is a NULL pointer then this function will + * block until it can successfully decrease the value or + * until interrupted by a signal. + * + * RESULTS + * 0 successfully decreased semaphore, + * -1 failed, error in errno + * ERRNO + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, + * EINTR the function was interrupted by a signal, + * EDEADLK a deadlock condition was detected. + * ETIMEDOUT abstime elapsed before success. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + sem_t s = *sem; + + pthread_testcancel(); + + if (sem == NULL) + { + result = EINVAL; + } + else + { + DWORD milliseconds; + + if (abstime == NULL) + { + milliseconds = INFINITE; + } + else + { + /* + * Calculate timeout as milliseconds from current system time. + */ + milliseconds = ptw32_relmillisecs (abstime); + } + + if ((result = pthread_mutex_lock (&s->lock)) == 0) + { + int v; + + /* See sem_destroy.c + */ + if (*sem == NULL) + { + (void) pthread_mutex_unlock (&s->lock); + errno = EINVAL; + return -1; + } + + v = --s->value; + (void) pthread_mutex_unlock (&s->lock); + + if (v < 0) + { +#ifdef NEED_SEM + int timedout; +#endif + sem_timedwait_cleanup_args_t cleanup_args; + + cleanup_args.sem = s; + cleanup_args.resultPtr = &result; + +#ifdef _MSC_VER +#pragma inline_depth(0) +#endif + /* Must wait */ + pthread_cleanup_push(ptw32_sem_timedwait_cleanup, (void *) &cleanup_args); +#ifdef NEED_SEM + timedout = +#endif + result = pthreadCancelableTimedWait (s->sem, milliseconds); + pthread_cleanup_pop(result); +#ifdef _MSC_VER +#pragma inline_depth() +#endif + +#ifdef NEED_SEM + + if (!timedout && pthread_mutex_lock (&s->lock) == 0) + { + if (*sem == NULL) + { + (void) pthread_mutex_unlock (&s->lock); + errno = EINVAL; + return -1; + } + + if (s->leftToUnblock > 0) + { + --s->leftToUnblock; + SetEvent(s->sem); + } + (void) pthread_mutex_unlock (&s->lock); + } + +#endif /* NEED_SEM */ + + } + } + + } + + if (result != 0) + { + + errno = result; + return -1; + + } + + return 0; + +} /* sem_timedwait */ diff --git a/pcsx2/windows/pthreads/sem_trywait.c b/pcsx2/windows/pthreads/sem_trywait.c index a9169c00b4..63614ba2b8 100644 --- a/pcsx2/windows/pthreads/sem_trywait.c +++ b/pcsx2/windows/pthreads/sem_trywait.c @@ -1,117 +1,117 @@ -/* - * ------------------------------------------------------------- - * - * Module: sem_trywait.c - * - * Purpose: - * Semaphores aren't actually part of the PThreads standard. - * They are defined by the POSIX Standard: - * - * POSIX 1003.1b-1993 (POSIX.1b) - * - * ------------------------------------------------------------- - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "semaphore.h" -#include "implement.h" - - -int -sem_trywait (sem_t * sem) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function tries to wait on a semaphore. - * - * PARAMETERS - * sem - * pointer to an instance of sem_t - * - * DESCRIPTION - * This function tries to wait on a semaphore. If the - * semaphore value is greater than zero, it decreases - * its value by one. If the semaphore value is zero, then - * this function returns immediately with the error EAGAIN - * - * RESULTS - * 0 successfully decreased semaphore, - * -1 failed, error in errno - * ERRNO - * EAGAIN the semaphore was already locked, - * EINVAL 'sem' is not a valid semaphore, - * ENOTSUP sem_trywait is not supported, - * EINTR the function was interrupted by a signal, - * EDEADLK a deadlock condition was detected. - * - * ------------------------------------------------------ - */ -{ - int result = 0; - sem_t s = *sem; - - if (s == NULL) - { - result = EINVAL; - } - else if ((result = pthread_mutex_lock (&s->lock)) == 0) - { - /* See sem_destroy.c - */ - if (*sem == NULL) - { - (void) pthread_mutex_unlock (&s->lock); - errno = EINVAL; - return -1; - } - - if (s->value > 0) - { - s->value--; - } - else - { - result = EAGAIN; - } - - (void) pthread_mutex_unlock (&s->lock); - } - - if (result != 0) - { - errno = result; - return -1; - } - - return 0; - -} /* sem_trywait */ +/* + * ------------------------------------------------------------- + * + * Module: sem_trywait.c + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + + +int +sem_trywait (sem_t * sem) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function tries to wait on a semaphore. + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * DESCRIPTION + * This function tries to wait on a semaphore. If the + * semaphore value is greater than zero, it decreases + * its value by one. If the semaphore value is zero, then + * this function returns immediately with the error EAGAIN + * + * RESULTS + * 0 successfully decreased semaphore, + * -1 failed, error in errno + * ERRNO + * EAGAIN the semaphore was already locked, + * EINVAL 'sem' is not a valid semaphore, + * ENOTSUP sem_trywait is not supported, + * EINTR the function was interrupted by a signal, + * EDEADLK a deadlock condition was detected. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + sem_t s = *sem; + + if (s == NULL) + { + result = EINVAL; + } + else if ((result = pthread_mutex_lock (&s->lock)) == 0) + { + /* See sem_destroy.c + */ + if (*sem == NULL) + { + (void) pthread_mutex_unlock (&s->lock); + errno = EINVAL; + return -1; + } + + if (s->value > 0) + { + s->value--; + } + else + { + result = EAGAIN; + } + + (void) pthread_mutex_unlock (&s->lock); + } + + if (result != 0) + { + errno = result; + return -1; + } + + return 0; + +} /* sem_trywait */ diff --git a/pcsx2/windows/pthreads/sem_unlink.c b/pcsx2/windows/pthreads/sem_unlink.c index 27aed87794..a6c6f81b0f 100644 --- a/pcsx2/windows/pthreads/sem_unlink.c +++ b/pcsx2/windows/pthreads/sem_unlink.c @@ -1,58 +1,58 @@ -/* - * ------------------------------------------------------------- - * - * Module: sem_unlink.c - * - * Purpose: - * Semaphores aren't actually part of the PThreads standard. - * They are defined by the POSIX Standard: - * - * POSIX 1003.1b-1993 (POSIX.1b) - * - * ------------------------------------------------------------- - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "semaphore.h" -#include "implement.h" - -/* ignore warning "unreferenced formal parameter" */ -#ifdef _MSC_VER -#pragma warning( disable : 4100 ) -#endif - -int -sem_unlink (const char *name) -{ - errno = ENOSYS; - return -1; -} /* sem_unlink */ +/* + * ------------------------------------------------------------- + * + * Module: sem_unlink.c + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + +/* ignore warning "unreferenced formal parameter" */ +#ifdef _MSC_VER +#pragma warning( disable : 4100 ) +#endif + +int +sem_unlink (const char *name) +{ + errno = ENOSYS; + return -1; +} /* sem_unlink */ diff --git a/pcsx2/windows/pthreads/sem_wait.c b/pcsx2/windows/pthreads/sem_wait.c index a501504fbd..d39d2b4b65 100644 --- a/pcsx2/windows/pthreads/sem_wait.c +++ b/pcsx2/windows/pthreads/sem_wait.c @@ -1,187 +1,187 @@ -/* - * ------------------------------------------------------------- - * - * Module: sem_wait.c - * - * Purpose: - * Semaphores aren't actually part of the PThreads standard. - * They are defined by the POSIX Standard: - * - * POSIX 1003.1b-1993 (POSIX.1b) - * - * ------------------------------------------------------------- - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "semaphore.h" -#include "implement.h" - - -static void PTW32_CDECL -ptw32_sem_wait_cleanup(void * sem) -{ - sem_t s = (sem_t) sem; - - if (pthread_mutex_lock (&s->lock) == 0) - { - /* - * If sema is destroyed do nothing, otherwise:- - * If the sema is posted between us being cancelled and us locking - * the sema again above then we need to consume that post but cancel - * anyway. If we don't get the semaphore we indicate that we're no - * longer waiting. - */ - if (*((sem_t *)sem) != NULL && !(WaitForSingleObject(s->sem, 0) == WAIT_OBJECT_0)) - { - ++s->value; -#ifdef NEED_SEM - if (s->value > 0) - { - s->leftToUnblock = 0; - } -#else - /* - * Don't release the W32 sema, it doesn't need adjustment - * because it doesn't record the number of waiters. - */ -#endif /* NEED_SEM */ - } - (void) pthread_mutex_unlock (&s->lock); - } -} - -int -sem_wait (sem_t * sem) - /* - * ------------------------------------------------------ - * DOCPUBLIC - * This function waits on a semaphore. - * - * PARAMETERS - * sem - * pointer to an instance of sem_t - * - * DESCRIPTION - * This function waits on a semaphore. If the - * semaphore value is greater than zero, it decreases - * its value by one. If the semaphore value is zero, then - * the calling thread (or process) is blocked until it can - * successfully decrease the value or until interrupted by - * a signal. - * - * RESULTS - * 0 successfully decreased semaphore, - * -1 failed, error in errno - * ERRNO - * EINVAL 'sem' is not a valid semaphore, - * ENOSYS semaphores are not supported, - * EINTR the function was interrupted by a signal, - * EDEADLK a deadlock condition was detected. - * - * ------------------------------------------------------ - */ -{ - int result = 0; - sem_t s = *sem; - - pthread_testcancel(); - - if (s == NULL) - { - result = EINVAL; - } - else - { - if ((result = pthread_mutex_lock (&s->lock)) == 0) - { - int v; - - /* See sem_destroy.c - */ - if (*sem == NULL) - { - (void) pthread_mutex_unlock (&s->lock); - errno = EINVAL; - return -1; - } - - v = --s->value; - (void) pthread_mutex_unlock (&s->lock); - - if (v < 0) - { -#ifdef _MSC_VER -#pragma inline_depth(0) -#endif - /* Must wait */ - pthread_cleanup_push(ptw32_sem_wait_cleanup, (void *) s); - result = pthreadCancelableWait (s->sem); - /* Cleanup if we're canceled or on any other error */ - pthread_cleanup_pop(result); -#ifdef _MSC_VER -#pragma inline_depth() -#endif - } -#ifdef NEED_SEM - - if (!result && pthread_mutex_lock (&s->lock) == 0) - { - if (*sem == NULL) - { - (void) pthread_mutex_unlock (&s->lock); - errno = EINVAL; - return -1; - } - - if (s->leftToUnblock > 0) - { - --s->leftToUnblock; - SetEvent(s->sem); - } - (void) pthread_mutex_unlock (&s->lock); - } - -#endif /* NEED_SEM */ - - } - - } - - if (result != 0) - { - errno = result; - return -1; - } - - return 0; - -} /* sem_wait */ +/* + * ------------------------------------------------------------- + * + * Module: sem_wait.c + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + + +static void PTW32_CDECL +ptw32_sem_wait_cleanup(void * sem) +{ + sem_t s = (sem_t) sem; + + if (pthread_mutex_lock (&s->lock) == 0) + { + /* + * If sema is destroyed do nothing, otherwise:- + * If the sema is posted between us being cancelled and us locking + * the sema again above then we need to consume that post but cancel + * anyway. If we don't get the semaphore we indicate that we're no + * longer waiting. + */ + if (*((sem_t *)sem) != NULL && !(WaitForSingleObject(s->sem, 0) == WAIT_OBJECT_0)) + { + ++s->value; +#ifdef NEED_SEM + if (s->value > 0) + { + s->leftToUnblock = 0; + } +#else + /* + * Don't release the W32 sema, it doesn't need adjustment + * because it doesn't record the number of waiters. + */ +#endif /* NEED_SEM */ + } + (void) pthread_mutex_unlock (&s->lock); + } +} + +int +sem_wait (sem_t * sem) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function waits on a semaphore. + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * DESCRIPTION + * This function waits on a semaphore. If the + * semaphore value is greater than zero, it decreases + * its value by one. If the semaphore value is zero, then + * the calling thread (or process) is blocked until it can + * successfully decrease the value or until interrupted by + * a signal. + * + * RESULTS + * 0 successfully decreased semaphore, + * -1 failed, error in errno + * ERRNO + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, + * EINTR the function was interrupted by a signal, + * EDEADLK a deadlock condition was detected. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + sem_t s = *sem; + + pthread_testcancel(); + + if (s == NULL) + { + result = EINVAL; + } + else + { + if ((result = pthread_mutex_lock (&s->lock)) == 0) + { + int v; + + /* See sem_destroy.c + */ + if (*sem == NULL) + { + (void) pthread_mutex_unlock (&s->lock); + errno = EINVAL; + return -1; + } + + v = --s->value; + (void) pthread_mutex_unlock (&s->lock); + + if (v < 0) + { +#ifdef _MSC_VER +#pragma inline_depth(0) +#endif + /* Must wait */ + pthread_cleanup_push(ptw32_sem_wait_cleanup, (void *) s); + result = pthreadCancelableWait (s->sem); + /* Cleanup if we're canceled or on any other error */ + pthread_cleanup_pop(result); +#ifdef _MSC_VER +#pragma inline_depth() +#endif + } +#ifdef NEED_SEM + + if (!result && pthread_mutex_lock (&s->lock) == 0) + { + if (*sem == NULL) + { + (void) pthread_mutex_unlock (&s->lock); + errno = EINVAL; + return -1; + } + + if (s->leftToUnblock > 0) + { + --s->leftToUnblock; + SetEvent(s->sem); + } + (void) pthread_mutex_unlock (&s->lock); + } + +#endif /* NEED_SEM */ + + } + + } + + if (result != 0) + { + errno = result; + return -1; + } + + return 0; + +} /* sem_wait */ diff --git a/pcsx2/windows/pthreads/semaphore.c b/pcsx2/windows/pthreads/semaphore.c index 0a5131f41d..6b2b10e857 100644 --- a/pcsx2/windows/pthreads/semaphore.c +++ b/pcsx2/windows/pthreads/semaphore.c @@ -1,69 +1,69 @@ -/* - * ------------------------------------------------------------- - * - * Module: semaphore.c - * - * Purpose: - * Concatenated version of separate modules to allow - * inlining optimisation, which it is assumed can only - * be effective within a single module. - * - * Semaphores aren't actually part of the PThreads standard. - * They are defined by the POSIX Standard: - * - * POSIX 1003.1b-1993 (POSIX.1b) - * - * ------------------------------------------------------------- - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#ifndef NEED_FTIME -# include -#endif - -#include - -#include "pthread.h" -#include "semaphore.h" -#include "implement.h" - - -#include "sem_init.c" -#include "sem_destroy.c" -#include "sem_trywait.c" -#include "sem_wait.c" -#include "sem_timedwait.c" -#include "sem_post.c" -#include "sem_post_multiple.c" -#include "sem_getvalue.c" -#include "sem_open.c" -#include "sem_close.c" -#include "sem_unlink.c" +/* + * ------------------------------------------------------------- + * + * Module: semaphore.c + * + * Purpose: + * Concatenated version of separate modules to allow + * inlining optimisation, which it is assumed can only + * be effective within a single module. + * + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef NEED_FTIME +# include +#endif + +#include + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + + +#include "sem_init.c" +#include "sem_destroy.c" +#include "sem_trywait.c" +#include "sem_wait.c" +#include "sem_timedwait.c" +#include "sem_post.c" +#include "sem_post_multiple.c" +#include "sem_getvalue.c" +#include "sem_open.c" +#include "sem_close.c" +#include "sem_unlink.c" diff --git a/pcsx2/windows/pthreads/semaphore.h b/pcsx2/windows/pthreads/semaphore.h index ea42ce3703..a3330a6388 100644 --- a/pcsx2/windows/pthreads/semaphore.h +++ b/pcsx2/windows/pthreads/semaphore.h @@ -1,166 +1,166 @@ -/* - * Module: semaphore.h - * - * Purpose: - * Semaphores aren't actually part of the PThreads standard. - * They are defined by the POSIX Standard: - * - * POSIX 1003.1b-1993 (POSIX.1b) - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ -#if !defined( SEMAPHORE_H ) -#define SEMAPHORE_H - -#undef PTW32_LEVEL - -#if defined(_POSIX_SOURCE) -#define PTW32_LEVEL 0 -/* Early POSIX */ -#endif - -#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 -#undef PTW32_LEVEL -#define PTW32_LEVEL 1 -/* Include 1b, 1c and 1d */ -#endif - -#if defined(INCLUDE_NP) -#undef PTW32_LEVEL -#define PTW32_LEVEL 2 -/* Include Non-Portable extensions */ -#endif - -#define PTW32_LEVEL_MAX 3 - -#if !defined(PTW32_LEVEL) -#define PTW32_LEVEL PTW32_LEVEL_MAX -/* Include everything */ -#endif - -#if __GNUC__ && ! defined (__declspec) -# error Please upgrade your GNU compiler to one that supports __declspec. -#endif - -/* - * When building the DLL code, you should define PTW32_BUILD so that - * the variables/functions are exported correctly. When using the DLL, - * do NOT define PTW32_BUILD, and then the variables/functions will - * be imported correctly. - */ -#ifndef PTW32_STATIC_LIB -# ifdef PTW32_BUILD -# define PTW32_DLLPORT __declspec (dllexport) -# else -# define PTW32_DLLPORT __declspec (dllimport) -# endif -#else -# define PTW32_DLLPORT -#endif - -/* - * This is a duplicate of what is in the autoconf config.h, - * which is only used when building the pthread-win32 libraries. - */ - -#ifndef PTW32_CONFIG_H -# if defined(WINCE) -# define NEED_ERRNO -# define NEED_SEM -# endif -# if defined(_UWIN) || defined(__MINGW32__) -# define HAVE_MODE_T -# endif -#endif - -/* - * - */ - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX -#ifdef NEED_ERRNO -#include "need_errno.h" -#else -#include -#endif -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -#define _POSIX_SEMAPHORES - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - -#ifndef HAVE_MODE_T -typedef unsigned int mode_t; -#endif - - -typedef struct sem_t_ * sem_t; - -PTW32_DLLPORT int __cdecl sem_init (sem_t * sem, - int pshared, - unsigned int value); - -PTW32_DLLPORT int __cdecl sem_destroy (sem_t * sem); - -PTW32_DLLPORT int __cdecl sem_trywait (sem_t * sem); - -PTW32_DLLPORT int __cdecl sem_wait (sem_t * sem); - -PTW32_DLLPORT int __cdecl sem_timedwait (sem_t * sem, - const struct timespec * abstime); - -PTW32_DLLPORT int __cdecl sem_post (sem_t * sem); - -PTW32_DLLPORT int __cdecl sem_post_multiple (sem_t * sem, - int count); - -PTW32_DLLPORT int __cdecl sem_open (const char * name, - int oflag, - mode_t mode, - unsigned int value); - -PTW32_DLLPORT int __cdecl sem_close (sem_t * sem); - -PTW32_DLLPORT int __cdecl sem_unlink (const char * name); - -PTW32_DLLPORT int __cdecl sem_getvalue (sem_t * sem, - int * sval); - -#ifdef __cplusplus -} /* End of extern "C" */ -#endif /* __cplusplus */ - -#undef PTW32_LEVEL -#undef PTW32_LEVEL_MAX - -#endif /* !SEMAPHORE_H */ +/* + * Module: semaphore.h + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#if !defined( SEMAPHORE_H ) +#define SEMAPHORE_H + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + +#if __GNUC__ && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the DLL code, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the DLL, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#ifndef PTW32_STATIC_LIB +# ifdef PTW32_BUILD +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#ifndef PTW32_CONFIG_H +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#ifdef NEED_ERRNO +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#define _POSIX_SEMAPHORES + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#ifndef HAVE_MODE_T +typedef unsigned int mode_t; +#endif + + +typedef struct sem_t_ * sem_t; + +PTW32_DLLPORT int __cdecl sem_init (sem_t * sem, + int pshared, + unsigned int value); + +PTW32_DLLPORT int __cdecl sem_destroy (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_trywait (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_wait (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_timedwait (sem_t * sem, + const struct timespec * abstime); + +PTW32_DLLPORT int __cdecl sem_post (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_post_multiple (sem_t * sem, + int count); + +PTW32_DLLPORT int __cdecl sem_open (const char * name, + int oflag, + mode_t mode, + unsigned int value); + +PTW32_DLLPORT int __cdecl sem_close (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_unlink (const char * name); + +PTW32_DLLPORT int __cdecl sem_getvalue (sem_t * sem, + int * sval); + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* !SEMAPHORE_H */ diff --git a/pcsx2/windows/pthreads/signal.c b/pcsx2/windows/pthreads/signal.c index b95b3eac3c..8f56c48b53 100644 --- a/pcsx2/windows/pthreads/signal.c +++ b/pcsx2/windows/pthreads/signal.c @@ -1,179 +1,179 @@ -/* - * signal.c - * - * Description: - * Thread-aware signal functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -/* - * Possible future strategy for implementing pthread_kill() - * ======================================================== - * - * Win32 does not implement signals. - * Signals are simply software interrupts. - * pthread_kill() asks the system to deliver a specified - * signal (interrupt) to a specified thread in the same - * process. - * Signals are always asynchronous (no deferred signals). - * Pthread-win32 has an async cancelation mechanism. - * A similar system can be written to deliver signals - * within the same process (on ix86 processors at least). - * - * Each thread maintains information about which - * signals it will respond to. Handler routines - * are set on a per-process basis - not per-thread. - * When signalled, a thread will check it's sigmask - * and, if the signal is not being ignored, call the - * handler routine associated with the signal. The - * thread must then (except for some signals) return to - * the point where it was interrupted. - * - * Ideally the system itself would check the target thread's - * mask before possibly needlessly bothering the thread - * itself. This could be done by pthread_kill(), that is, - * in the signaling thread since it has access to - * all pthread_t structures. It could also retrieve - * the handler routine address to minimise the target - * threads response overhead. This may also simplify - * serialisation of the access to the per-thread signal - * structures. - * - * pthread_kill() eventually calls a routine similar to - * ptw32_cancel_thread() which manipulates the target - * threads processor context to cause the thread to - * run the handler launcher routine. pthread_kill() must - * save the target threads current context so that the - * handler launcher routine can restore the context after - * the signal handler has returned. Some handlers will not - * return, eg. the default SIGKILL handler may simply - * call pthread_exit(). - * - * The current context is saved in the target threads - * pthread_t structure. - */ - -#include "pthread.h" -#include "implement.h" - -#if HAVE_SIGSET_T - -static void -ptw32_signal_thread () -{ -} - -static void -ptw32_signal_callhandler () -{ -} - -int -pthread_sigmask (int how, sigset_t const *set, sigset_t * oset) -{ - pthread_t thread = pthread_self (); - - if (thread.p == NULL) - { - return ENOENT; - } - - /* Validate the `how' argument. */ - if (set != NULL) - { - switch (how) - { - case SIG_BLOCK: - break; - case SIG_UNBLOCK: - break; - case SIG_SETMASK: - break; - default: - /* Invalid `how' argument. */ - return EINVAL; - } - } - - /* Copy the old mask before modifying it. */ - if (oset != NULL) - { - memcpy (oset, &(thread.p->sigmask), sizeof (sigset_t)); - } - - if (set != NULL) - { - unsigned int i; - - /* FIXME: this code assumes that sigmask is an even multiple of - the size of a long integer. */ - - unsigned long *src = (unsigned long const *) set; - unsigned long *dest = (unsigned long *) &(thread.p->sigmask); - - switch (how) - { - case SIG_BLOCK: - for (i = 0; i < (sizeof (sigset_t) / sizeof (unsigned long)); i++) - { - /* OR the bit field longword-wise. */ - *dest++ |= *src++; - } - break; - case SIG_UNBLOCK: - for (i = 0; i < (sizeof (sigset_t) / sizeof (unsigned long)); i++) - { - /* XOR the bitfield longword-wise. */ - *dest++ ^= *src++; - } - case SIG_SETMASK: - /* Replace the whole sigmask. */ - memcpy (&(thread.p->sigmask), set, sizeof (sigset_t)); - break; - } - } - - return 0; -} - -int -sigwait (const sigset_t * set, int *sig) -{ - /* This routine is a cancellation point */ - pthread_test_cancel(); -} - -int -sigaction (int signum, const struct sigaction *act, struct sigaction *oldact) -{ -} - -#endif /* HAVE_SIGSET_T */ +/* + * signal.c + * + * Description: + * Thread-aware signal functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* + * Possible future strategy for implementing pthread_kill() + * ======================================================== + * + * Win32 does not implement signals. + * Signals are simply software interrupts. + * pthread_kill() asks the system to deliver a specified + * signal (interrupt) to a specified thread in the same + * process. + * Signals are always asynchronous (no deferred signals). + * Pthread-win32 has an async cancelation mechanism. + * A similar system can be written to deliver signals + * within the same process (on ix86 processors at least). + * + * Each thread maintains information about which + * signals it will respond to. Handler routines + * are set on a per-process basis - not per-thread. + * When signalled, a thread will check it's sigmask + * and, if the signal is not being ignored, call the + * handler routine associated with the signal. The + * thread must then (except for some signals) return to + * the point where it was interrupted. + * + * Ideally the system itself would check the target thread's + * mask before possibly needlessly bothering the thread + * itself. This could be done by pthread_kill(), that is, + * in the signaling thread since it has access to + * all pthread_t structures. It could also retrieve + * the handler routine address to minimise the target + * threads response overhead. This may also simplify + * serialisation of the access to the per-thread signal + * structures. + * + * pthread_kill() eventually calls a routine similar to + * ptw32_cancel_thread() which manipulates the target + * threads processor context to cause the thread to + * run the handler launcher routine. pthread_kill() must + * save the target threads current context so that the + * handler launcher routine can restore the context after + * the signal handler has returned. Some handlers will not + * return, eg. the default SIGKILL handler may simply + * call pthread_exit(). + * + * The current context is saved in the target threads + * pthread_t structure. + */ + +#include "pthread.h" +#include "implement.h" + +#if HAVE_SIGSET_T + +static void +ptw32_signal_thread () +{ +} + +static void +ptw32_signal_callhandler () +{ +} + +int +pthread_sigmask (int how, sigset_t const *set, sigset_t * oset) +{ + pthread_t thread = pthread_self (); + + if (thread.p == NULL) + { + return ENOENT; + } + + /* Validate the `how' argument. */ + if (set != NULL) + { + switch (how) + { + case SIG_BLOCK: + break; + case SIG_UNBLOCK: + break; + case SIG_SETMASK: + break; + default: + /* Invalid `how' argument. */ + return EINVAL; + } + } + + /* Copy the old mask before modifying it. */ + if (oset != NULL) + { + memcpy (oset, &(thread.p->sigmask), sizeof (sigset_t)); + } + + if (set != NULL) + { + unsigned int i; + + /* FIXME: this code assumes that sigmask is an even multiple of + the size of a long integer. */ + + unsigned long *src = (unsigned long const *) set; + unsigned long *dest = (unsigned long *) &(thread.p->sigmask); + + switch (how) + { + case SIG_BLOCK: + for (i = 0; i < (sizeof (sigset_t) / sizeof (unsigned long)); i++) + { + /* OR the bit field longword-wise. */ + *dest++ |= *src++; + } + break; + case SIG_UNBLOCK: + for (i = 0; i < (sizeof (sigset_t) / sizeof (unsigned long)); i++) + { + /* XOR the bitfield longword-wise. */ + *dest++ ^= *src++; + } + case SIG_SETMASK: + /* Replace the whole sigmask. */ + memcpy (&(thread.p->sigmask), set, sizeof (sigset_t)); + break; + } + } + + return 0; +} + +int +sigwait (const sigset_t * set, int *sig) +{ + /* This routine is a cancellation point */ + pthread_test_cancel(); +} + +int +sigaction (int signum, const struct sigaction *act, struct sigaction *oldact) +{ +} + +#endif /* HAVE_SIGSET_T */ diff --git a/pcsx2/windows/pthreads/spin.c b/pcsx2/windows/pthreads/spin.c index 92b9bed9d4..41b5aa5251 100644 --- a/pcsx2/windows/pthreads/spin.c +++ b/pcsx2/windows/pthreads/spin.c @@ -1,46 +1,46 @@ -/* - * spin.c - * - * Description: - * This translation unit implements spin lock primitives. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -#include "ptw32_spinlock_check_need_init.c" -#include "pthread_spin_init.c" -#include "pthread_spin_destroy.c" -#include "pthread_spin_lock.c" -#include "pthread_spin_unlock.c" -#include "pthread_spin_trylock.c" +/* + * spin.c + * + * Description: + * This translation unit implements spin lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +#include "ptw32_spinlock_check_need_init.c" +#include "pthread_spin_init.c" +#include "pthread_spin_destroy.c" +#include "pthread_spin_lock.c" +#include "pthread_spin_unlock.c" +#include "pthread_spin_trylock.c" diff --git a/pcsx2/windows/pthreads/sync.c b/pcsx2/windows/pthreads/sync.c index 03c9881910..5e56fa9a1f 100644 --- a/pcsx2/windows/pthreads/sync.c +++ b/pcsx2/windows/pthreads/sync.c @@ -1,43 +1,43 @@ -/* - * sync.c - * - * Description: - * This translation unit implements functions related to thread - * synchronisation. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -#include "pthread_detach.c" -#include "pthread_join.c" +/* + * sync.c + * + * Description: + * This translation unit implements functions related to thread + * synchronisation. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +#include "pthread_detach.c" +#include "pthread_join.c" diff --git a/pcsx2/windows/pthreads/tsd.c b/pcsx2/windows/pthreads/tsd.c index ef49d4e475..ed44fe6cb4 100644 --- a/pcsx2/windows/pthreads/tsd.c +++ b/pcsx2/windows/pthreads/tsd.c @@ -1,44 +1,44 @@ -/* - * tsd.c - * - * Description: - * POSIX thread functions which implement thread-specific data (TSD). - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -#include "pthread_key_create.c" -#include "pthread_key_delete.c" -#include "pthread_setspecific.c" -#include "pthread_getspecific.c" +/* + * tsd.c + * + * Description: + * POSIX thread functions which implement thread-specific data (TSD). + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +#include "pthread_key_create.c" +#include "pthread_key_delete.c" +#include "pthread_setspecific.c" +#include "pthread_getspecific.c" diff --git a/pcsx2/windows/pthreads/w32_CancelableWait.c b/pcsx2/windows/pthreads/w32_CancelableWait.c index 7fa54ecdd6..97e15aa310 100644 --- a/pcsx2/windows/pthreads/w32_CancelableWait.c +++ b/pcsx2/windows/pthreads/w32_CancelableWait.c @@ -1,160 +1,160 @@ -/* - * w32_CancelableWait.c - * - * Description: - * This translation unit implements miscellaneous thread functions. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include "pthread.h" -#include "implement.h" - - -static INLINE int -ptw32_cancelable_wait (HANDLE waitHandle, DWORD timeout) - /* - * ------------------------------------------------------------------- - * This provides an extra hook into the pthread_cancel - * mechanism that will allow you to wait on a Windows handle and make it a - * cancellation point. This function blocks until the given WIN32 handle is - * signaled or pthread_cancel has been called. It is implemented using - * WaitForMultipleObjects on 'waitHandle' and a manually reset WIN32 - * event used to implement pthread_cancel. - * - * Given this hook it would be possible to implement more of the cancellation - * points. - * ------------------------------------------------------------------- - */ -{ - int result; - pthread_t self; - ptw32_thread_t * sp; - HANDLE handles[2]; - DWORD nHandles = 1; - DWORD status; - - handles[0] = waitHandle; - - self = pthread_self(); - sp = (ptw32_thread_t *) self.p; - - if (sp != NULL) - { - /* - * Get cancelEvent handle - */ - if (sp->cancelState == PTHREAD_CANCEL_ENABLE) - { - - if ((handles[1] = sp->cancelEvent) != NULL) - { - nHandles++; - } - } - } - else - { - handles[1] = NULL; - } - - status = WaitForMultipleObjects (nHandles, handles, PTW32_FALSE, timeout); - - switch (status - WAIT_OBJECT_0) - { - case 0: - /* - * Got the handle. - * In the event that both handles are signalled, the smallest index - * value (us) is returned. As it has been arranged, this ensures that - * we don't drop a signal that we should act on (i.e. semaphore, - * mutex, or condition variable etc). - */ - result = 0; - break; - - case 1: - /* - * Got cancel request. - * In the event that both handles are signaled, the cancel will - * be ignored (see case 0 comment). - */ - ResetEvent (handles[1]); - - if (sp != NULL) - { - /* - * Should handle POSIX and implicit POSIX threads.. - * Make sure we haven't been async-canceled in the meantime. - */ - (void) pthread_mutex_lock (&sp->cancelLock); - if (sp->state < PThreadStateCanceling) - { - sp->state = PThreadStateCanceling; - sp->cancelState = PTHREAD_CANCEL_DISABLE; - (void) pthread_mutex_unlock (&sp->cancelLock); - ptw32_throw (PTW32_EPS_CANCEL); - - /* Never reached */ - } - (void) pthread_mutex_unlock (&sp->cancelLock); - } - - /* Should never get to here. */ - result = EINVAL; - break; - - default: - if (status == WAIT_TIMEOUT) - { - result = ETIMEDOUT; - } - else - { - result = EINVAL; - } - break; - } - - return (result); - -} /* CancelableWait */ - -int -pthreadCancelableWait (HANDLE waitHandle) -{ - return (ptw32_cancelable_wait (waitHandle, INFINITE)); -} - -int -pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout) -{ - return (ptw32_cancelable_wait (waitHandle, timeout)); -} +/* + * w32_CancelableWait.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +static INLINE int +ptw32_cancelable_wait (HANDLE waitHandle, DWORD timeout) + /* + * ------------------------------------------------------------------- + * This provides an extra hook into the pthread_cancel + * mechanism that will allow you to wait on a Windows handle and make it a + * cancellation point. This function blocks until the given WIN32 handle is + * signaled or pthread_cancel has been called. It is implemented using + * WaitForMultipleObjects on 'waitHandle' and a manually reset WIN32 + * event used to implement pthread_cancel. + * + * Given this hook it would be possible to implement more of the cancellation + * points. + * ------------------------------------------------------------------- + */ +{ + int result; + pthread_t self; + ptw32_thread_t * sp; + HANDLE handles[2]; + DWORD nHandles = 1; + DWORD status; + + handles[0] = waitHandle; + + self = pthread_self(); + sp = (ptw32_thread_t *) self.p; + + if (sp != NULL) + { + /* + * Get cancelEvent handle + */ + if (sp->cancelState == PTHREAD_CANCEL_ENABLE) + { + + if ((handles[1] = sp->cancelEvent) != NULL) + { + nHandles++; + } + } + } + else + { + handles[1] = NULL; + } + + status = WaitForMultipleObjects (nHandles, handles, PTW32_FALSE, timeout); + + switch (status - WAIT_OBJECT_0) + { + case 0: + /* + * Got the handle. + * In the event that both handles are signalled, the smallest index + * value (us) is returned. As it has been arranged, this ensures that + * we don't drop a signal that we should act on (i.e. semaphore, + * mutex, or condition variable etc). + */ + result = 0; + break; + + case 1: + /* + * Got cancel request. + * In the event that both handles are signaled, the cancel will + * be ignored (see case 0 comment). + */ + ResetEvent (handles[1]); + + if (sp != NULL) + { + /* + * Should handle POSIX and implicit POSIX threads.. + * Make sure we haven't been async-canceled in the meantime. + */ + (void) pthread_mutex_lock (&sp->cancelLock); + if (sp->state < PThreadStateCanceling) + { + sp->state = PThreadStateCanceling; + sp->cancelState = PTHREAD_CANCEL_DISABLE; + (void) pthread_mutex_unlock (&sp->cancelLock); + ptw32_throw (PTW32_EPS_CANCEL); + + /* Never reached */ + } + (void) pthread_mutex_unlock (&sp->cancelLock); + } + + /* Should never get to here. */ + result = EINVAL; + break; + + default: + if (status == WAIT_TIMEOUT) + { + result = ETIMEDOUT; + } + else + { + result = EINVAL; + } + break; + } + + return (result); + +} /* CancelableWait */ + +int +pthreadCancelableWait (HANDLE waitHandle) +{ + return (ptw32_cancelable_wait (waitHandle, INFINITE)); +} + +int +pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout) +{ + return (ptw32_cancelable_wait (waitHandle, timeout)); +} diff --git a/pcsx2/windows/resource.h b/pcsx2/windows/resource.h index 04acc2f078..764d13cc99 100644 --- a/pcsx2/windows/resource.h +++ b/pcsx2/windows/resource.h @@ -1,736 +1,736 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by pcsx2.rc -// -#define IDDEFAULT 3 -#define IDD_CONFIG 101 -#define IDD_MCDCONF 102 -#define IDD_BPEXEC 103 -#define ABOUT_DIALOG 104 -#define IDD_BPCNT 105 -#define IDD_DEBUG 108 -#define IDI_ICON 108 -#define IDD_MEMORY 110 -#define IDD_VU0REGS 111 -#define IDD_JUMP 112 -#define SPLASH_LOGO 113 -#define IDD_VU0INTEGER 113 -#define IDD_GPREGS 114 -#define IDD_CP0REGS 115 -#define IDD_CP1REGS 116 -#define IDD_VU1INTEGER 117 -#define IDD_VU1REGS 118 -#define IDD_LOGGING 119 -#define IDD_CMDLINE 120 -#define IDD_RDEBUGPARAMS 121 -#define ID_DEBUG_REMOTEDEBUGGING 122 -#define IDD_RDEBUG 123 -#define IDD_DIALOGBAR 124 -#define IDD_IOP_DEBUG 125 -#define IDD_CPUDLG 126 -#define IDD_ADVANCED 127 -#define IDD_IOPREGS 128 -#define IDD_USERNAME 129 -#define IDB_PS2SILVER 132 -#define IDD_CHEATS 133 -#define IDD_GAMEFIXES 134 -#define IDD_HACKS 135 -#define IDD_DUMP 136 -#define IDD_DUMPMEM 137 -#define IDD_PATCHBROWSER 138 -#define IDD_ADVANCED_OPTIONS 140 -#define IDD_FINDER 174 -#define IDD_ADD 175 -#define IDD_ADDGS 176 -#define IDD_EDITPATCH 177 -#define IDD_ADDRAW 178 -#define IDD_PNACHWRITER 179 -#define IDC_MEM_SCROLL 1001 -#define IDC_EXECBP 1001 -#define IDC_CNTBP 1002 -#define IDC_MCD2 1004 -#define IDC_VU0_VF00 1005 -#define IDC_MCD1 1005 -#define IDC_VU0_VF01 1006 -#define IDC_MCDSEL1 1006 -#define IDC_VU0_VF02 1007 -#define IDC_MCDSEL2 1007 -#define IDC_VU0_VF03 1008 -#define IDC_LOADICO1 1008 -#define IDC_VU0_VF04 1009 -#define IDC_SAVE1 1009 -#define IDC_DEBUG_DISASM 1010 -#define IDC_VU0_VF05 1010 -#define IDC_LOADICO2 1010 -#define IDC_VU0_VF06 1011 -#define IDC_SAVE2 1011 -#define IDC_VU0_VF07 1012 -#define IDC_VU0_VF08 1013 -#define IDC_PCSX_ABOUT_TEXT 1014 -#define IDC_VU0_VF09 1014 -#define IDC_CPU 1015 -#define IDC_VU0_VF10 1015 -#define IDC_VU0_VF11 1016 -#define IDC_ENABLED 1016 -#define IDC_VU0_VF12 1017 -#define IDC_PLACETOPATCH 1017 -#define IDC_VU0_VF13 1018 -#define IDC_TYPE 1018 -#define IDC_VU0_VF14 1019 -#define IDC_CP07 1020 -#define IDC_VU0_VF15 1020 -#define IDC_VU0_VF16 1021 -#define IDC_VU0_VF17 1022 -#define IDC_VU0_VF18 1023 -#define IDC_VU0_VF19 1024 -#define IDC_VU0_VF20 1025 -#define IDC_VU0_VF21 1026 -#define IDC_VU0_VF22 1027 -#define IDC_VU0_VF23 1028 -#define IDC_DEBUG_CLOSE 1029 -#define IDC_VU0_VF24 1029 -#define IDC_DEBUG_STEP 1030 -#define IDC_VU0_VF25 1030 -#define IDC_DEBUG_SKIP 1031 -#define IDC_VU0_VF26 1031 -#define IDC_DEBUG_GO 1032 -#define IDC_VU0_VF27 1032 -#define IDC_DEBUG_BP_EXEC 1033 -#define IDC_VU0_VF28 1033 -#define IDC_CP021 1034 -#define IDC_DEBUG_SCROLL 1034 -#define IDC_VU0_VF29 1034 -#define IDC_CP022 1035 -#define IDC_DEBUG_RESETTOPC 1035 -#define IDC_VU0_VF30 1035 -#define IDC_CP023 1036 -#define IDC_FPU_ACC 1036 -#define IDC_DEBUG_JUMP 1036 -#define IDC_MEMORY_CLOSE 1036 -#define IDC_VU0_VF31 1036 -#define IDC_CP024 1037 -#define IDC_MEMORY_ADDR 1037 -#define IDC_DEBUG_LOG 1037 -#define IDC_CP025 1038 -#define IDC_MEMORY_DUMP 1038 -#define IDC_DEBUG_BP_COUNT 1038 -#define IDC_VU0_VI00 1038 -#define IDC_DEBUG_L1 1039 -#define IDC_VU0_VI01 1039 -#define IDC_ADDRESS_PATCH 1039 -#define IDC_DEBUG_L2 1040 -#define IDC_VU0_VI02 1040 -#define IDC_DATA_PATCH 1040 -#define IDC_DEBUG_L3 1041 -#define IDC_VU0_VI03 1041 -#define IDC_FRAMEMCD1 1041 -#define IDC_DEBUG_L4 1042 -#define IDC_VU0_VI04 1042 -#define IDC_FRAMEMCD2 1042 -#define IDC_DEBUG_L5 1043 -#define IDC_VU0_VI05 1043 -#define IDC_CP031 1044 -#define IDC_DEBUG_L6 1044 -#define IDC_VU0_VI06 1044 -#define IDC_DEBUG_L7 1045 -#define IDC_VU0_VI07 1045 -#define IDC_DEBUG_L8 1046 -#define IDC_VU0_VI08 1046 -#define IDC_DEBUG_L9 1047 -#define IDC_GPR0 1047 -#define IDC_VU0_VI09 1047 -#define IDC_DEBUG_L10 1048 -#define IDC_GPR1 1048 -#define IDC_VU0_VI10 1048 -#define IDC_DEBUG_L11 1049 -#define IDC_GPR2 1049 -#define IDC_VU0_VI11 1049 -#define IDC_DEBUG_L12 1050 -#define IDC_GPR3 1050 -#define IDC_VU0_VI12 1050 -#define IDC_DEBUG_L13 1051 -#define IDC_GPR4 1051 -#define IDC_VU0_VI13 1051 -#define IDC_DEBUG_L14 1052 -#define IDC_GPR5 1052 -#define IDC_LISTGS 1052 -#define IDC_VU0_VI14 1052 -#define IDC_DEBUG_L15 1053 -#define IDC_GPR6 1053 -#define IDC_VU0_VI15 1053 -#define IDC_LISTSPU2 1053 -#define IDC_DEBUG_L16 1054 -#define IDC_GPR7 1054 -#define IDC_VU0_VI16 1054 -#define IDC_LISTCDVD 1054 -#define IDC_DEBUG_L17 1055 -#define IDC_GPR8 1055 -#define IDC_LISTBIOS 1055 -#define IDC_VU0_VI17 1055 -#define IDC_DEBUG_L18 1056 -#define IDC_GPR9 1056 -#define IDC_CONFIGGS 1056 -#define IDC_VU0_VI18 1056 -#define IDC_DEBUG_L19 1057 -#define IDC_GPR10 1057 -#define IDC_TESTGS 1057 -#define IDC_VU0_VI19 1057 -#define IDC_DEBUG_L20 1058 -#define IDC_ABOUTGS 1058 -#define IDC_VU0_VI20 1058 -#define IDC_DEBUG_L21 1059 -#define IDC_VU0_VI21 1059 -#define IDC_CONFIGSPU2 1059 -#define IDC_DEBUG_L22 1060 -#define IDC_VU0_VI22 1060 -#define IDC_TESTSPU2 1060 -#define IDC_DEBUG_L23 1061 -#define IDC_VU0_VI23 1061 -#define IDC_ABOUTSPU2 1061 -#define IDC_DEBUG_L24 1062 -#define IDC_VU0_VI24 1062 -#define IDC_CONFIGCDVD 1062 -#define IDC_DEBUG_L25 1063 -#define IDC_GPR11 1063 -#define IDC_VU0_VI25 1063 -#define IDC_TESTCDVD 1063 -#define IDC_DEBUG_L26 1064 -#define IDC_VU0_VI26 1064 -#define IDC_ABOUTCDVD 1064 -#define IDC_DEBUG_L27 1065 -#define IDC_VU0_VI27 1065 -#define IDC_LISTDEV9 1065 -#define IDC_DEBUG_L28 1066 -#define IDC_LISTPAD1 1066 -#define IDC_VU0_VI28 1066 -#define IDC_DEBUG_L29 1067 -#define IDC_CONFIGPAD1 1067 -#define IDC_VU0_VI29 1067 -#define IDC_DEBUG_R1 1068 -#define IDC_GPR12 1068 -#define IDC_TESTPAD1 1068 -#define IDC_VU0_VI30 1068 -#define IDC_DEBUG_R2 1069 -#define IDC_GPR13 1069 -#define IDC_ABOUTPAD1 1069 -#define IDC_VU0_VI31 1069 -#define IDC_DEBUG_R3 1070 -#define IDC_GPR14 1070 -#define IDC_LISTPAD2 1070 -#define IDC_VU0_ACC 1070 -#define IDC_DEBUG_R4 1071 -#define IDC_GPR15 1071 -#define IDC_CONFIGPAD2 1071 -#define IDC_VU1_VF00 1071 -#define IDC_DEBUG_R5 1072 -#define IDC_GPR16 1072 -#define IDC_TESTPAD2 1072 -#define IDC_VU1_VF01 1072 -#define IDC_DEBUG_R6 1073 -#define IDC_GPR17 1073 -#define IDC_ABOUTPAD2 1073 -#define IDC_VU1_VF02 1073 -#define IDC_DEBUG_R7 1074 -#define IDC_GPR18 1074 -#define IDC_VU1_VF03 1074 -#define IDC_CONFIGDEV9 1074 -#define IDC_DEBUG_R8 1075 -#define IDC_GPR19 1075 -#define IDC_VU1_VF04 1075 -#define IDC_TESTDEV9 1075 -#define IDC_DEBUG_R9 1076 -#define IDC_GPR20 1076 -#define IDC_VU1_VF05 1076 -#define IDC_ABOUTDEV9 1076 -#define IDC_DEBUG_R10 1077 -#define IDC_GPR21 1077 -#define IDC_VU1_VF06 1077 -#define IDC_LISTUSB 1077 -#define IDC_DEBUG_R11 1078 -#define IDC_GPR22 1078 -#define IDC_VU1_VF07 1078 -#define IDC_CONFIGUSB 1078 -#define IDC_DEBUG_R12 1079 -#define IDC_GPR23 1079 -#define IDC_VU1_VF08 1079 -#define IDC_TESTUSB 1079 -#define IDC_DEBUG_R13 1080 -#define IDC_GPR24 1080 -#define IDC_VU1_VF09 1080 -#define IDC_ABOUTUSB 1080 -#define IDC_DEBUG_R14 1081 -#define IDC_GPR25 1081 -#define IDC_VU1_VF10 1081 -#define IDC_LISTFW 1081 -#define IDC_DEBUG_R15 1082 -#define IDC_GPR26 1082 -#define IDC_VU1_VF11 1082 -#define IDC_CONFIGFW 1082 -#define IDC_DEBUG_R16 1083 -#define IDC_GPR27 1083 -#define IDC_VU1_VF12 1083 -#define IDC_TESTFW 1083 -#define IDC_DEBUG_R17 1084 -#define IDC_GPR28 1084 -#define IDC_VU1_VF13 1084 -#define IDC_ABOUTFW 1084 -#define IDC_DEBUG_R18 1085 -#define IDC_GPR29 1085 -#define IDC_VU1_VF14 1085 -#define IDC_DEBUG_R19 1086 -#define IDC_GPR30 1086 -#define IDC_VU1_VF15 1086 -#define IDC_DEBUG_R20 1087 -#define IDC_GPR31 1087 -#define IDC_VU1_VF16 1087 -#define IDC_DEBUG_R21 1088 -#define IDC_VU1_VF17 1088 -#define IDC_DEBUG_R22 1089 -#define IDC_GPR_PC 1089 -#define IDC_VU1_VF18 1089 -#define IDC_DEBUG_R23 1090 -#define IDC_VU1_VF19 1090 -#define IDC_DEBUG_R24 1091 -#define IDC_GPR_HI 1091 -#define IDC_VU1_VF20 1091 -#define IDC_DEBUG_R25 1092 -#define IDC_GPR_LO 1092 -#define IDC_VU1_VF21 1092 -#define IDC_CP00 1093 -#define IDC_DEBUG_R26 1093 -#define IDC_VU1_VF22 1093 -#define IDC_CP01 1094 -#define IDC_DEBUG_R27 1094 -#define IDC_VU1_VF23 1094 -#define IDC_CP02 1095 -#define IDC_DEBUG_R28 1095 -#define IDC_VU1_VF24 1095 -#define IDC_CP03 1096 -#define IDC_DEBUG_R29 1096 -#define IDC_VU1_VF25 1096 -#define IDC_CP04 1097 -#define IDC_DEBUG_DUMP 1097 -#define IDC_JUMP_PC 1097 -#define IDC_VU1_VF26 1097 -#define IDC_CP05 1098 -#define IDC_DUMP_END 1098 -#define IDC_VU1_VF27 1098 -#define IDC_DEBUG_LOGGING 1098 -#define IDC_DEBUG_MEMORY 1098 -#define IDC_CP06 1099 -#define IDC_DUMP_FNAME 1099 -#define IDC_DEBUG_BP_CLEAR 1099 -#define IDC_VU1_VF28 1099 -#define IDC_CP08 1100 -#define IDC_VU1_VF29 1100 -#define IDC_DUMP_ENDIOP 1100 -#define IDC_CP09 1101 -#define IDC_VU1_VF30 1101 -#define IDC_DUMP_FNAMEIOP 1101 -#define IDC_CP010 1102 -#define IDC_VU1_VF31 1102 -#define IDC_CP011 1103 -#define IDC_VU1_VI00 1103 -#define IDC_CP012 1104 -#define IDC_VU1_VI01 1104 -#define IDC_CP013 1105 -#define IDC_VU1_VI02 1105 -#define IDC_CP014 1106 -#define IDC_VU1_VI03 1106 -#define IDC_CP015 1107 -#define IDC_VU1_VI04 1107 -#define IDC_CP016 1108 -#define IDC_VU1_VI05 1108 -#define IDC_CP017 1109 -#define IDC_VU1_VI06 1109 -#define IDC_CP018 1110 -#define IDC_VU1_VI07 1110 -#define IDC_CP019 1111 -#define IDC_VU1_VI08 1111 -#define IDC_CP020 1112 -#define IDC_VU1_VI09 1112 -#define IDC_CP026 1113 -#define IDC_VU1_VI10 1113 -#define IDC_CP027 1114 -#define IDC_VU1_VI11 1114 -#define IDC_CP028 1115 -#define IDC_VU1_VI12 1115 -#define IDC_CP029 1116 -#define IDC_VU1_VI13 1116 -#define IDC_CP030 1117 -#define IDC_VU1_VI14 1117 -#define IDC_FP0 1118 -#define IDC_VU1_VI15 1118 -#define IDC_FP1 1119 -#define IDC_VU1_VI16 1119 -#define IDC_FP2 1120 -#define IDC_VU1_VI17 1120 -#define IDC_FP3 1121 -#define IDC_VU1_VI18 1121 -#define IDC_FP4 1122 -#define IDC_VU1_VI19 1122 -#define IDC_FP5 1123 -#define IDC_VU1_VI20 1123 -#define IDC_FP6 1124 -#define IDC_VU1_VI21 1124 -#define IDC_FP7 1125 -#define IDC_VU1_VI22 1125 -#define IDC_FP8 1126 -#define IDC_VU1_VI23 1126 -#define IDC_FP9 1127 -#define IDC_VU1_VI24 1127 -#define IDC_FP10 1128 -#define IDC_VU1_VI25 1128 -#define IDC_FP11 1129 -#define IDC_VU1_VI26 1129 -#define IDC_FP12 1130 -#define IDC_VU1_VI27 1130 -#define IDC_FP13 1131 -#define IDC_VU1_VI28 1131 -#define IDC_FP14 1132 -#define IDC_VU1_VI29 1132 -#define IDC_FP15 1133 -#define IDC_VU1_VI30 1133 -#define IDC_FP16 1134 -#define IDC_VU1_VI31 1134 -#define IDC_FP17 1135 -#define IDC_VU1_ACC 1135 -#define IDC_FP18 1136 -#define IDC_FP19 1137 -#define IDC_FP20 1138 -#define IDC_FP21 1139 -#define IDC_FP22 1140 -#define IDC_FP23 1141 -#define IDC_FP24 1142 -#define IDC_FP25 1143 -#define IDC_FP26 1144 -#define IDC_FP27 1145 -#define IDC_FP28 1146 -#define IDC_FP29 1147 -#define IDC_FP30 1148 -#define IDC_FP31 1149 -#define IDC_FCR0 1150 -#define IDC_FCR31 1151 -#define IDC_CMDLINE 1155 -#define IDC_PORT 1157 -#define IDC_COMMUNICATION 1158 -#define IDC_CLEAR 1160 -#define IDC_DEBUGBIOS 1161 -#define IDC_EEPC 1162 -#define IDC_IOPPC 1163 -#define IDC_PCSX_ABOUT_GREETS 1163 -#define IDC_PCSX_ABOUT_AUTHORS 1164 -#define IDC_EECYCLE 1164 -#define IDC_GRAPHICS 1165 -#define IDC_IOPCYCLE 1165 -#define IDC_SOUND 1166 -#define IDC_FIRSTCONTROLLER 1167 -#define IDC_SECONDCONTROLLER 1168 -#define IDC_CDVDROM 1169 -#define IDC_BIOS 1170 -#define IDC_DEV9 1171 -#define IDC_DUMP_START 1172 -#define IDC_TIP 1172 -#define IDC_USB 1172 -#define IDC_TEXT 1173 -#define IDC_DUMP_STARTIOP 1173 -#define IDC_CPUOP 1175 -#define IDC_DEBUGEE 1176 -#define IDC_DEBUGIOP 1177 -#define IDC_STOPAT 1178 -#define IDC_STOPAFTER 1179 -#define IDC_PATCH 1180 -#define IDC_LOGS 1186 -#define IDC_DUMPMEM_FNAME 1188 -#define IDC_DUMPMEM_END 1189 -#define IDC_DUMPMEM_START 1190 -#define IDC_DUMPRAW 1191 -#define IDC_DEBUG_DISASM_IOP 1193 -#define IDC_DEBUG_SCROLL_IOP 1194 -#define IDC_EXITPB 1196 -#define IDC_VENDORNAME 1197 -#define IDC_FAMILYNAME 1198 -#define IDC_CPUSPEEDNAME 1199 -#define IDC_FEATURESNAME 1200 -#define IDC_VENDORINPUT 1201 -#define IDC_FAMILYINPUT 1202 -#define IDC_CPUSPEEDINPUT 1203 -#define IDC_FEATURESINPUT 1204 -#define IDC_REGCACHING 1208 -#define IDC_ADVRESET 1214 -#define IDC_SYNCHACK 1217 -#define IDC_SPU2HACK 1218 -#define IDC_SYNCHACK2 1218 -#define IDC_SYNCHACK3 1219 -#define IDC_IOPGPR0 1220 -#define IDC_IOPGPR1 1221 -#define IDC_IOPGPR2 1222 -#define IDC_IOPGPR16 1223 -#define IDC_IOPGPR17 1224 -#define IDC_IOPGPR18 1225 -#define IDC_IOPGPR19 1226 -#define IDC_IOPGPR20 1227 -#define IDC_IOPGPR21 1228 -#define IDC_IOPGPR22 1229 -#define IDC_IOPGPR23 1230 -#define IDC_IOPGPR24 1231 -#define IDC_IOPGPR25 1232 -#define IDC_IOPGPR26 1233 -#define IDC_IOPGPR27 1234 -#define IDC_IOPGPR28 1235 -#define IDC_IOPGPR29 1236 -#define IDC_IOPGPR30 1237 -#define IDC_IOPGPR31 1238 -#define IDC_IOPGPR_LO 1239 -#define IDC_IOPGPR_HI 1240 -#define IDC_IOPGPR_PC 1241 -#define IDC_IOPGPR15 1242 -#define IDC_IOPGPR14 1243 -#define IDC_IOPGPR13 1244 -#define IDC_IOPGPR12 1245 -#define IDC_IOPGPR11 1246 -#define IDC_IOPGPR10 1247 -#define IDC_IOPGPR9 1248 -#define IDC_IOPGPR8 1249 -#define IDC_IOPGPR7 1250 -#define IDC_IOPGPR6 1251 -#define IDC_IOPGPR5 1252 -#define IDC_IOPGPR4 1253 -#define IDC_BIOSDIR 1254 -#define IDC_IOPGPR3 1254 -#define IDC_PLUGINSDIR 1255 -#define IDC_USER_NAME 1257 -#define IDC_CPU_GSMULTI 1259 -#define IDC_PS2SILVER_RECT 1259 -#define IDC_CPU_EEREC 1262 -#define IDC_CPU_VU1REC 1263 -#define IDC_CPU_VU0REC 1264 -#define IDC_CPU_FL_NORMAL 1265 -#define IDC_CPU_FL_LIMIT 1266 -#define IDC_CPU_FL_SKIP 1267 -#define IDC_CPU_FL_SKIPVU 1268 -#define IDC_CPU_VUGROUP 1269 -#define IDC_GROUPS 1272 -#define IDC_PATCHES 1273 -#define IDC_DEBUG_STEP_EE 1274 -#define IDC_DEBUG_STEP_OVER 1275 -#define IDC_CUSTOMFPS 1275 -#define IDC_DEBUG_RUN_TO_CURSOR 1276 -#define IDC_CUSTOM_FPS 1276 -#define IDC_DEBUG_STEP_TO_CURSOR 1277 -#define IDC_ENABLEBUTTON 1277 -#define IDC_CUSTOM_FRAMESKIP 1277 -#define IDC_DEBUG_BREAK 1278 -#define IDC_ADDGS 1278 -#define IDC_CONVERTEDCODE 1278 -#define IDC_CUSTOM_CONSECUTIVE_FRAMES 1278 -#define IDC_VU_OVERFLOWHACK 1278 -#define IDC_HACKDESC 1279 -#define IDC_CONVERT 1279 -#define IDC_EDITPATCH 1279 -#define IDC_FRAMESKIP_LABEL1 1279 -#define IDC_READY 1280 -#define IDC_ADDPATCH 1280 -#define IDC_FRAMESKIP_LABEL2 1280 -#define IDC_GROUP 1281 -#define IDC_ADDRAW 1281 -#define IDC_FRAMESKIP_LABEL3 1281 -#define IDC_DATA 1282 -#define IDC_PNACHWRITER 1282 -#define IDC_CUSTOM_CONSECUTIVE_SKIP 1282 -#define IDC_PNACHWRITER2 1283 -#define IDC_SKIPMPEG 1283 -#define IDC_FRAMESKIP_LABEL4 1283 -#define IDC_SPIN1 1284 -#define IDC_FRAMESKIP_LABEL5 1284 -#define IDC_FRAMESKIP_LABEL6 1285 -#define IDC_SAVE 1286 -#define IDC_CRC 1287 -#define IDC_COMMENT 1288 -#define IDC_GAMETITLE 1289 -#define IDC_FASTMEMORY 1290 -#define IDC_ZEROGS 1291 -#define IDC_ROUND1 1292 -#define IDC_ROUND2 1293 -#define IDC_PATH3HACK 1294 -#define IDC_VUNANMODE 1295 -#define IDC_TREE1 1297 -#define IDC_TREE2 1298 -#define IDC_ICON1 1299 -#define IDC_ICON2 1300 -#define IDC_EE_CHECK1 1300 -#define IDC_EE_CHECK2 1301 -#define IDC_GAMEFIX2 1301 -#define IDC_VU_CHECK1 1302 -#define IDC_VU_FLAGS 1302 -#define IDC_GAMEFIX3 1302 -#define IDC_FRAMELIMIT_OPTIONS 1303 -#define IDC_VU_CHECK2 1303 -#define IDC_GAMEFIX4 1303 -#define IDC_SOUNDHACK2 1304 -#define IDC_ESCHACK 1304 -#define IDC_VU_CHECK3 1304 -#define IDC_GAMEFIX5 1304 -#define IDC_GAMEFIX1 1304 -#define IDC_EE_ROUNDMODE0 1305 -#define IDC_EE_ROUNDMODE1 1306 -#define IDC_EE_ROUNDMODE2 1307 -#define IDC_EE_ROUNDMODE3 1308 -#define IDC_EESYNC_DEFAULT 1308 -#define IDC_VU_CHECK4 1309 -#define IDC_EESYNC1 1309 -#define IDC_EESYNC2 1310 -#define IDC_VU_ROUNDMODE0 1311 -#define IDC_EESYNC3 1311 -#define IDC_VU_ROUNDMODE1 1312 -#define IDC_IOPSYNC 1312 -#define IDC_VU_ROUNDMODE2 1313 -#define IDC_CHECK2 1313 -#define IDC_WAITCYCLES 1313 -#define IDC_VU_ROUNDMODE3 1314 -#define IDC_VU_CLAMPMODE0 1315 -#define IDC_VU_CLAMPMODE1 1316 -#define IDC_VU_CLAMPMODE2 1317 -#define IDC_VU_CLAMPMODE3 1318 -#define IDC_EE_CLAMPMODE0 1319 -#define IDC_EE_CLAMPMODE1 1320 -#define IDC_EE_CLAMPMODE2 1321 -#define IDC_CPULOG 1500 -#define IDC_MEMLOG 1501 -#define IDC_HWLOG 1502 -#define IDC_DMALOG 1503 -#define IDC_BIOSLOG 1504 -#define IDC_ELFLOG 1505 -#define IDC_FPULOG 1506 -#define IDC_MMILOG 1507 -#define IDC_VU0LOG 1508 -#define IDC_COP0LOG 1509 -#define IDC_VIFLOG 1510 -#define IDC_SPRLOG 1511 -#define IDC_GIFLOG 1512 -#define IDC_SIFLOG 1513 -#define IDC_IPULOG 1514 -#define IDC_VUMICROLOG 1515 -#define IDC_RPCSERVICES 1516 -#define IDC_IOPLOG 1520 -#define IDC_IOPMEMLOG 1521 -#define IDC_IOPHWLOG 1522 -#define IDC_IOPBIOSLOG 1523 -#define IDC_IOPDMALOG 1524 -#define IDC_IOPPADLOG 1525 -#define IDC_IOPCDRLOG 1527 -#define IDC_IOPCNTLOG 1529 -#define IDC_EECNTLOG 1530 -#define IDC_SYMLOG 1531 -#define IDC_STDOUTPUTLOG 1532 -#define IDC_SEARCH 1701 -#define IDC_VALUE 1702 -#define IDC_OLD 1703 -#define IDC_SET 1704 -#define IDC_EQ 1705 -#define IDC_GT 1706 -#define IDC_LT 1707 -#define IDC_GE 1708 -#define IDC_LE 1709 -#define IDC_NE 1710 -#define IDC_EE 1711 -#define IDC_IOP 1712 -#define IDC_RESET 1713 -#define IDC_ADD 1714 -#define IDC_STATUS 1716 -#define IDC_FW 1716 -#define IDC_FRAMELIMIT 1716 -#define IDC_ADDRESS 1716 -#define IDC_UNSIGNED 1717 -#define IDC_8B 1718 -#define IDC_16B 1719 -#define IDC_32B 1720 -#define IDC_64B 1721 -#define IDC_RESULTS 1722 -#define IDC_NAME 1723 -#define IDC_ADDR 1725 -#define IDC_MATCHES 1726 -#define ID_FILEOPEN 40001 -#define ID_DEBUG_MEMORY_DUMP 40002 -#define ID_FILE_EXIT 40003 -#define ID_RUN_EXECUTE 40004 -#define ID_RUN_RESET 40005 -#define ID_HELP_ABOUT 40006 -#define ID_CONFIG_CONFIGURE 40007 -#define ID_CONFIG_CPU 40008 -#define ID_CONFIG_GRAPHICS 40009 -#define ID_CONFIG_CONTROLLERS 40010 -#define ID_DEBUG_LOGGING 40011 -#define ID_CONFIG_SOUND 40012 -#define ID_CONFIG_CDVDROM 40013 -#define ID_RUN_CMDLINE 40014 -#define ID_FILE_RUNCD 40015 -#define ID_DEBUG_ENTERDEBUGGER 40016 -#define ID_CONFIG_DEV9 40017 -#define ID_FILE_STATES_LOAD_SLOT1 40018 -#define ID_FILE_STATES_LOAD_SLOT2 40019 -#define ID_FILE_STATES_LOAD_SLOT3 40020 -#define ID_FILE_STATES_LOAD_SLOT4 40021 -#define ID_FILE_STATES_LOAD_SLOT5 40022 -#define ID_FILE_STATES_LOAD_OTHER 40023 -#define ID_FILE_STATES_SAVE_SLOT1 40024 -#define ID_FILE_STATES_SAVE_SLOT2 40025 -#define ID_FILE_STATES_SAVE_SLOT3 40026 -#define ID_FILE_STATES_SAVE_SLOT4 40027 -#define ID_FILE_STATES_SAVE_SLOT5 40028 -#define ID_FILE_STATES_SAVE_OTHER 40029 -#define ID_CONFIG_FW 40030 -#define ID_CONFIG_USB 40031 -#define ID_CONFIG_MEMCARDS 40032 -#define IDC_FORMAT1 40033 -#define IDC_FORMAT2 40034 -#define IDC_LIST1 40035 -#define IDC_LIST2 40036 -#define IDC_RELOAD1 40037 -#define IDC_RELOAD2 40038 -#define IDC_COPYTO2 40039 -#define IDC_COPYTO1 40040 -#define IDC_PASTE 40041 -#define IDC_DELETE1 40042 -#define IDC_DELETE2 40043 -#define ID_PATCHBROWSER 40044 -#define ID_NEWPATCH 40045 -#define IDC_NEWPATCH 40045 -#define IDC_PATCHTEXT 40046 -#define IDC_SAVEPATCH 40047 -#define IDC_REFRESHPATCHLIST 40048 -#define IDC_PATCHCRCLIST 40049 -#define IDC_PATCHNAMELIST 40050 -#define IDC_GAMENAMESEARCH 40051 -#define IDC_SEARCHPATCHTEXT 40052 -#define ID_PROCESSLOW 40053 -#define ID_PROCESSNORMAL 40054 -#define ID_PROCESSHIGH 40055 -#define ID_CONSOLE 40056 -#define ID_PATCHES 40057 -#define ID_CONFIG_ADVANCED 40058 -#define ID_INTERLACEHACK 40059 -#define ID_SAFECNTS 40060 -#define ID_SPU2HACK 40061 -#define ID_VSYNCRATE 40062 -#define ID_HELP_HELP 40063 -#define ID_PROFILER 40066 -#define ID_CDVDPRINT 40067 -#define ID_CLOSEGS 40070 -#define ID_CHEAT_FINDER_SHOW 40100 -#define ID_CHEAT_BROWSER_SHOW 40101 -#define ID_HACKS 40102 -#define ID_GAMEFIXES 40103 -#define ID_ADVANCED_OPTIONS 40104 -#define ID_LANGS 50000 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 141 -#define _APS_NEXT_COMMAND_VALUE 40018 -#define _APS_NEXT_CONTROL_VALUE 1314 -#define _APS_NEXT_SYMED_VALUE 104 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by pcsx2.rc +// +#define IDDEFAULT 3 +#define IDD_CONFIG 101 +#define IDD_MCDCONF 102 +#define IDD_BPEXEC 103 +#define ABOUT_DIALOG 104 +#define IDD_BPCNT 105 +#define IDD_DEBUG 108 +#define IDI_ICON 108 +#define IDD_MEMORY 110 +#define IDD_VU0REGS 111 +#define IDD_JUMP 112 +#define SPLASH_LOGO 113 +#define IDD_VU0INTEGER 113 +#define IDD_GPREGS 114 +#define IDD_CP0REGS 115 +#define IDD_CP1REGS 116 +#define IDD_VU1INTEGER 117 +#define IDD_VU1REGS 118 +#define IDD_LOGGING 119 +#define IDD_CMDLINE 120 +#define IDD_RDEBUGPARAMS 121 +#define ID_DEBUG_REMOTEDEBUGGING 122 +#define IDD_RDEBUG 123 +#define IDD_DIALOGBAR 124 +#define IDD_IOP_DEBUG 125 +#define IDD_CPUDLG 126 +#define IDD_ADVANCED 127 +#define IDD_IOPREGS 128 +#define IDD_USERNAME 129 +#define IDB_PS2SILVER 132 +#define IDD_CHEATS 133 +#define IDD_GAMEFIXES 134 +#define IDD_HACKS 135 +#define IDD_DUMP 136 +#define IDD_DUMPMEM 137 +#define IDD_PATCHBROWSER 138 +#define IDD_ADVANCED_OPTIONS 140 +#define IDD_FINDER 174 +#define IDD_ADD 175 +#define IDD_ADDGS 176 +#define IDD_EDITPATCH 177 +#define IDD_ADDRAW 178 +#define IDD_PNACHWRITER 179 +#define IDC_MEM_SCROLL 1001 +#define IDC_EXECBP 1001 +#define IDC_CNTBP 1002 +#define IDC_MCD2 1004 +#define IDC_VU0_VF00 1005 +#define IDC_MCD1 1005 +#define IDC_VU0_VF01 1006 +#define IDC_MCDSEL1 1006 +#define IDC_VU0_VF02 1007 +#define IDC_MCDSEL2 1007 +#define IDC_VU0_VF03 1008 +#define IDC_LOADICO1 1008 +#define IDC_VU0_VF04 1009 +#define IDC_SAVE1 1009 +#define IDC_DEBUG_DISASM 1010 +#define IDC_VU0_VF05 1010 +#define IDC_LOADICO2 1010 +#define IDC_VU0_VF06 1011 +#define IDC_SAVE2 1011 +#define IDC_VU0_VF07 1012 +#define IDC_VU0_VF08 1013 +#define IDC_PCSX_ABOUT_TEXT 1014 +#define IDC_VU0_VF09 1014 +#define IDC_CPU 1015 +#define IDC_VU0_VF10 1015 +#define IDC_VU0_VF11 1016 +#define IDC_ENABLED 1016 +#define IDC_VU0_VF12 1017 +#define IDC_PLACETOPATCH 1017 +#define IDC_VU0_VF13 1018 +#define IDC_TYPE 1018 +#define IDC_VU0_VF14 1019 +#define IDC_CP07 1020 +#define IDC_VU0_VF15 1020 +#define IDC_VU0_VF16 1021 +#define IDC_VU0_VF17 1022 +#define IDC_VU0_VF18 1023 +#define IDC_VU0_VF19 1024 +#define IDC_VU0_VF20 1025 +#define IDC_VU0_VF21 1026 +#define IDC_VU0_VF22 1027 +#define IDC_VU0_VF23 1028 +#define IDC_DEBUG_CLOSE 1029 +#define IDC_VU0_VF24 1029 +#define IDC_DEBUG_STEP 1030 +#define IDC_VU0_VF25 1030 +#define IDC_DEBUG_SKIP 1031 +#define IDC_VU0_VF26 1031 +#define IDC_DEBUG_GO 1032 +#define IDC_VU0_VF27 1032 +#define IDC_DEBUG_BP_EXEC 1033 +#define IDC_VU0_VF28 1033 +#define IDC_CP021 1034 +#define IDC_DEBUG_SCROLL 1034 +#define IDC_VU0_VF29 1034 +#define IDC_CP022 1035 +#define IDC_DEBUG_RESETTOPC 1035 +#define IDC_VU0_VF30 1035 +#define IDC_CP023 1036 +#define IDC_FPU_ACC 1036 +#define IDC_DEBUG_JUMP 1036 +#define IDC_MEMORY_CLOSE 1036 +#define IDC_VU0_VF31 1036 +#define IDC_CP024 1037 +#define IDC_MEMORY_ADDR 1037 +#define IDC_DEBUG_LOG 1037 +#define IDC_CP025 1038 +#define IDC_MEMORY_DUMP 1038 +#define IDC_DEBUG_BP_COUNT 1038 +#define IDC_VU0_VI00 1038 +#define IDC_DEBUG_L1 1039 +#define IDC_VU0_VI01 1039 +#define IDC_ADDRESS_PATCH 1039 +#define IDC_DEBUG_L2 1040 +#define IDC_VU0_VI02 1040 +#define IDC_DATA_PATCH 1040 +#define IDC_DEBUG_L3 1041 +#define IDC_VU0_VI03 1041 +#define IDC_FRAMEMCD1 1041 +#define IDC_DEBUG_L4 1042 +#define IDC_VU0_VI04 1042 +#define IDC_FRAMEMCD2 1042 +#define IDC_DEBUG_L5 1043 +#define IDC_VU0_VI05 1043 +#define IDC_CP031 1044 +#define IDC_DEBUG_L6 1044 +#define IDC_VU0_VI06 1044 +#define IDC_DEBUG_L7 1045 +#define IDC_VU0_VI07 1045 +#define IDC_DEBUG_L8 1046 +#define IDC_VU0_VI08 1046 +#define IDC_DEBUG_L9 1047 +#define IDC_GPR0 1047 +#define IDC_VU0_VI09 1047 +#define IDC_DEBUG_L10 1048 +#define IDC_GPR1 1048 +#define IDC_VU0_VI10 1048 +#define IDC_DEBUG_L11 1049 +#define IDC_GPR2 1049 +#define IDC_VU0_VI11 1049 +#define IDC_DEBUG_L12 1050 +#define IDC_GPR3 1050 +#define IDC_VU0_VI12 1050 +#define IDC_DEBUG_L13 1051 +#define IDC_GPR4 1051 +#define IDC_VU0_VI13 1051 +#define IDC_DEBUG_L14 1052 +#define IDC_GPR5 1052 +#define IDC_LISTGS 1052 +#define IDC_VU0_VI14 1052 +#define IDC_DEBUG_L15 1053 +#define IDC_GPR6 1053 +#define IDC_VU0_VI15 1053 +#define IDC_LISTSPU2 1053 +#define IDC_DEBUG_L16 1054 +#define IDC_GPR7 1054 +#define IDC_VU0_VI16 1054 +#define IDC_LISTCDVD 1054 +#define IDC_DEBUG_L17 1055 +#define IDC_GPR8 1055 +#define IDC_LISTBIOS 1055 +#define IDC_VU0_VI17 1055 +#define IDC_DEBUG_L18 1056 +#define IDC_GPR9 1056 +#define IDC_CONFIGGS 1056 +#define IDC_VU0_VI18 1056 +#define IDC_DEBUG_L19 1057 +#define IDC_GPR10 1057 +#define IDC_TESTGS 1057 +#define IDC_VU0_VI19 1057 +#define IDC_DEBUG_L20 1058 +#define IDC_ABOUTGS 1058 +#define IDC_VU0_VI20 1058 +#define IDC_DEBUG_L21 1059 +#define IDC_VU0_VI21 1059 +#define IDC_CONFIGSPU2 1059 +#define IDC_DEBUG_L22 1060 +#define IDC_VU0_VI22 1060 +#define IDC_TESTSPU2 1060 +#define IDC_DEBUG_L23 1061 +#define IDC_VU0_VI23 1061 +#define IDC_ABOUTSPU2 1061 +#define IDC_DEBUG_L24 1062 +#define IDC_VU0_VI24 1062 +#define IDC_CONFIGCDVD 1062 +#define IDC_DEBUG_L25 1063 +#define IDC_GPR11 1063 +#define IDC_VU0_VI25 1063 +#define IDC_TESTCDVD 1063 +#define IDC_DEBUG_L26 1064 +#define IDC_VU0_VI26 1064 +#define IDC_ABOUTCDVD 1064 +#define IDC_DEBUG_L27 1065 +#define IDC_VU0_VI27 1065 +#define IDC_LISTDEV9 1065 +#define IDC_DEBUG_L28 1066 +#define IDC_LISTPAD1 1066 +#define IDC_VU0_VI28 1066 +#define IDC_DEBUG_L29 1067 +#define IDC_CONFIGPAD1 1067 +#define IDC_VU0_VI29 1067 +#define IDC_DEBUG_R1 1068 +#define IDC_GPR12 1068 +#define IDC_TESTPAD1 1068 +#define IDC_VU0_VI30 1068 +#define IDC_DEBUG_R2 1069 +#define IDC_GPR13 1069 +#define IDC_ABOUTPAD1 1069 +#define IDC_VU0_VI31 1069 +#define IDC_DEBUG_R3 1070 +#define IDC_GPR14 1070 +#define IDC_LISTPAD2 1070 +#define IDC_VU0_ACC 1070 +#define IDC_DEBUG_R4 1071 +#define IDC_GPR15 1071 +#define IDC_CONFIGPAD2 1071 +#define IDC_VU1_VF00 1071 +#define IDC_DEBUG_R5 1072 +#define IDC_GPR16 1072 +#define IDC_TESTPAD2 1072 +#define IDC_VU1_VF01 1072 +#define IDC_DEBUG_R6 1073 +#define IDC_GPR17 1073 +#define IDC_ABOUTPAD2 1073 +#define IDC_VU1_VF02 1073 +#define IDC_DEBUG_R7 1074 +#define IDC_GPR18 1074 +#define IDC_VU1_VF03 1074 +#define IDC_CONFIGDEV9 1074 +#define IDC_DEBUG_R8 1075 +#define IDC_GPR19 1075 +#define IDC_VU1_VF04 1075 +#define IDC_TESTDEV9 1075 +#define IDC_DEBUG_R9 1076 +#define IDC_GPR20 1076 +#define IDC_VU1_VF05 1076 +#define IDC_ABOUTDEV9 1076 +#define IDC_DEBUG_R10 1077 +#define IDC_GPR21 1077 +#define IDC_VU1_VF06 1077 +#define IDC_LISTUSB 1077 +#define IDC_DEBUG_R11 1078 +#define IDC_GPR22 1078 +#define IDC_VU1_VF07 1078 +#define IDC_CONFIGUSB 1078 +#define IDC_DEBUG_R12 1079 +#define IDC_GPR23 1079 +#define IDC_VU1_VF08 1079 +#define IDC_TESTUSB 1079 +#define IDC_DEBUG_R13 1080 +#define IDC_GPR24 1080 +#define IDC_VU1_VF09 1080 +#define IDC_ABOUTUSB 1080 +#define IDC_DEBUG_R14 1081 +#define IDC_GPR25 1081 +#define IDC_VU1_VF10 1081 +#define IDC_LISTFW 1081 +#define IDC_DEBUG_R15 1082 +#define IDC_GPR26 1082 +#define IDC_VU1_VF11 1082 +#define IDC_CONFIGFW 1082 +#define IDC_DEBUG_R16 1083 +#define IDC_GPR27 1083 +#define IDC_VU1_VF12 1083 +#define IDC_TESTFW 1083 +#define IDC_DEBUG_R17 1084 +#define IDC_GPR28 1084 +#define IDC_VU1_VF13 1084 +#define IDC_ABOUTFW 1084 +#define IDC_DEBUG_R18 1085 +#define IDC_GPR29 1085 +#define IDC_VU1_VF14 1085 +#define IDC_DEBUG_R19 1086 +#define IDC_GPR30 1086 +#define IDC_VU1_VF15 1086 +#define IDC_DEBUG_R20 1087 +#define IDC_GPR31 1087 +#define IDC_VU1_VF16 1087 +#define IDC_DEBUG_R21 1088 +#define IDC_VU1_VF17 1088 +#define IDC_DEBUG_R22 1089 +#define IDC_GPR_PC 1089 +#define IDC_VU1_VF18 1089 +#define IDC_DEBUG_R23 1090 +#define IDC_VU1_VF19 1090 +#define IDC_DEBUG_R24 1091 +#define IDC_GPR_HI 1091 +#define IDC_VU1_VF20 1091 +#define IDC_DEBUG_R25 1092 +#define IDC_GPR_LO 1092 +#define IDC_VU1_VF21 1092 +#define IDC_CP00 1093 +#define IDC_DEBUG_R26 1093 +#define IDC_VU1_VF22 1093 +#define IDC_CP01 1094 +#define IDC_DEBUG_R27 1094 +#define IDC_VU1_VF23 1094 +#define IDC_CP02 1095 +#define IDC_DEBUG_R28 1095 +#define IDC_VU1_VF24 1095 +#define IDC_CP03 1096 +#define IDC_DEBUG_R29 1096 +#define IDC_VU1_VF25 1096 +#define IDC_CP04 1097 +#define IDC_DEBUG_DUMP 1097 +#define IDC_JUMP_PC 1097 +#define IDC_VU1_VF26 1097 +#define IDC_CP05 1098 +#define IDC_DUMP_END 1098 +#define IDC_VU1_VF27 1098 +#define IDC_DEBUG_LOGGING 1098 +#define IDC_DEBUG_MEMORY 1098 +#define IDC_CP06 1099 +#define IDC_DUMP_FNAME 1099 +#define IDC_DEBUG_BP_CLEAR 1099 +#define IDC_VU1_VF28 1099 +#define IDC_CP08 1100 +#define IDC_VU1_VF29 1100 +#define IDC_DUMP_ENDIOP 1100 +#define IDC_CP09 1101 +#define IDC_VU1_VF30 1101 +#define IDC_DUMP_FNAMEIOP 1101 +#define IDC_CP010 1102 +#define IDC_VU1_VF31 1102 +#define IDC_CP011 1103 +#define IDC_VU1_VI00 1103 +#define IDC_CP012 1104 +#define IDC_VU1_VI01 1104 +#define IDC_CP013 1105 +#define IDC_VU1_VI02 1105 +#define IDC_CP014 1106 +#define IDC_VU1_VI03 1106 +#define IDC_CP015 1107 +#define IDC_VU1_VI04 1107 +#define IDC_CP016 1108 +#define IDC_VU1_VI05 1108 +#define IDC_CP017 1109 +#define IDC_VU1_VI06 1109 +#define IDC_CP018 1110 +#define IDC_VU1_VI07 1110 +#define IDC_CP019 1111 +#define IDC_VU1_VI08 1111 +#define IDC_CP020 1112 +#define IDC_VU1_VI09 1112 +#define IDC_CP026 1113 +#define IDC_VU1_VI10 1113 +#define IDC_CP027 1114 +#define IDC_VU1_VI11 1114 +#define IDC_CP028 1115 +#define IDC_VU1_VI12 1115 +#define IDC_CP029 1116 +#define IDC_VU1_VI13 1116 +#define IDC_CP030 1117 +#define IDC_VU1_VI14 1117 +#define IDC_FP0 1118 +#define IDC_VU1_VI15 1118 +#define IDC_FP1 1119 +#define IDC_VU1_VI16 1119 +#define IDC_FP2 1120 +#define IDC_VU1_VI17 1120 +#define IDC_FP3 1121 +#define IDC_VU1_VI18 1121 +#define IDC_FP4 1122 +#define IDC_VU1_VI19 1122 +#define IDC_FP5 1123 +#define IDC_VU1_VI20 1123 +#define IDC_FP6 1124 +#define IDC_VU1_VI21 1124 +#define IDC_FP7 1125 +#define IDC_VU1_VI22 1125 +#define IDC_FP8 1126 +#define IDC_VU1_VI23 1126 +#define IDC_FP9 1127 +#define IDC_VU1_VI24 1127 +#define IDC_FP10 1128 +#define IDC_VU1_VI25 1128 +#define IDC_FP11 1129 +#define IDC_VU1_VI26 1129 +#define IDC_FP12 1130 +#define IDC_VU1_VI27 1130 +#define IDC_FP13 1131 +#define IDC_VU1_VI28 1131 +#define IDC_FP14 1132 +#define IDC_VU1_VI29 1132 +#define IDC_FP15 1133 +#define IDC_VU1_VI30 1133 +#define IDC_FP16 1134 +#define IDC_VU1_VI31 1134 +#define IDC_FP17 1135 +#define IDC_VU1_ACC 1135 +#define IDC_FP18 1136 +#define IDC_FP19 1137 +#define IDC_FP20 1138 +#define IDC_FP21 1139 +#define IDC_FP22 1140 +#define IDC_FP23 1141 +#define IDC_FP24 1142 +#define IDC_FP25 1143 +#define IDC_FP26 1144 +#define IDC_FP27 1145 +#define IDC_FP28 1146 +#define IDC_FP29 1147 +#define IDC_FP30 1148 +#define IDC_FP31 1149 +#define IDC_FCR0 1150 +#define IDC_FCR31 1151 +#define IDC_CMDLINE 1155 +#define IDC_PORT 1157 +#define IDC_COMMUNICATION 1158 +#define IDC_CLEAR 1160 +#define IDC_DEBUGBIOS 1161 +#define IDC_EEPC 1162 +#define IDC_IOPPC 1163 +#define IDC_PCSX_ABOUT_GREETS 1163 +#define IDC_PCSX_ABOUT_AUTHORS 1164 +#define IDC_EECYCLE 1164 +#define IDC_GRAPHICS 1165 +#define IDC_IOPCYCLE 1165 +#define IDC_SOUND 1166 +#define IDC_FIRSTCONTROLLER 1167 +#define IDC_SECONDCONTROLLER 1168 +#define IDC_CDVDROM 1169 +#define IDC_BIOS 1170 +#define IDC_DEV9 1171 +#define IDC_DUMP_START 1172 +#define IDC_TIP 1172 +#define IDC_USB 1172 +#define IDC_TEXT 1173 +#define IDC_DUMP_STARTIOP 1173 +#define IDC_CPUOP 1175 +#define IDC_DEBUGEE 1176 +#define IDC_DEBUGIOP 1177 +#define IDC_STOPAT 1178 +#define IDC_STOPAFTER 1179 +#define IDC_PATCH 1180 +#define IDC_LOGS 1186 +#define IDC_DUMPMEM_FNAME 1188 +#define IDC_DUMPMEM_END 1189 +#define IDC_DUMPMEM_START 1190 +#define IDC_DUMPRAW 1191 +#define IDC_DEBUG_DISASM_IOP 1193 +#define IDC_DEBUG_SCROLL_IOP 1194 +#define IDC_EXITPB 1196 +#define IDC_VENDORNAME 1197 +#define IDC_FAMILYNAME 1198 +#define IDC_CPUSPEEDNAME 1199 +#define IDC_FEATURESNAME 1200 +#define IDC_VENDORINPUT 1201 +#define IDC_FAMILYINPUT 1202 +#define IDC_CPUSPEEDINPUT 1203 +#define IDC_FEATURESINPUT 1204 +#define IDC_REGCACHING 1208 +#define IDC_ADVRESET 1214 +#define IDC_SYNCHACK 1217 +#define IDC_SPU2HACK 1218 +#define IDC_SYNCHACK2 1218 +#define IDC_SYNCHACK3 1219 +#define IDC_IOPGPR0 1220 +#define IDC_IOPGPR1 1221 +#define IDC_IOPGPR2 1222 +#define IDC_IOPGPR16 1223 +#define IDC_IOPGPR17 1224 +#define IDC_IOPGPR18 1225 +#define IDC_IOPGPR19 1226 +#define IDC_IOPGPR20 1227 +#define IDC_IOPGPR21 1228 +#define IDC_IOPGPR22 1229 +#define IDC_IOPGPR23 1230 +#define IDC_IOPGPR24 1231 +#define IDC_IOPGPR25 1232 +#define IDC_IOPGPR26 1233 +#define IDC_IOPGPR27 1234 +#define IDC_IOPGPR28 1235 +#define IDC_IOPGPR29 1236 +#define IDC_IOPGPR30 1237 +#define IDC_IOPGPR31 1238 +#define IDC_IOPGPR_LO 1239 +#define IDC_IOPGPR_HI 1240 +#define IDC_IOPGPR_PC 1241 +#define IDC_IOPGPR15 1242 +#define IDC_IOPGPR14 1243 +#define IDC_IOPGPR13 1244 +#define IDC_IOPGPR12 1245 +#define IDC_IOPGPR11 1246 +#define IDC_IOPGPR10 1247 +#define IDC_IOPGPR9 1248 +#define IDC_IOPGPR8 1249 +#define IDC_IOPGPR7 1250 +#define IDC_IOPGPR6 1251 +#define IDC_IOPGPR5 1252 +#define IDC_IOPGPR4 1253 +#define IDC_BIOSDIR 1254 +#define IDC_IOPGPR3 1254 +#define IDC_PLUGINSDIR 1255 +#define IDC_USER_NAME 1257 +#define IDC_CPU_GSMULTI 1259 +#define IDC_PS2SILVER_RECT 1259 +#define IDC_CPU_EEREC 1262 +#define IDC_CPU_VU1REC 1263 +#define IDC_CPU_VU0REC 1264 +#define IDC_CPU_FL_NORMAL 1265 +#define IDC_CPU_FL_LIMIT 1266 +#define IDC_CPU_FL_SKIP 1267 +#define IDC_CPU_FL_SKIPVU 1268 +#define IDC_CPU_VUGROUP 1269 +#define IDC_GROUPS 1272 +#define IDC_PATCHES 1273 +#define IDC_DEBUG_STEP_EE 1274 +#define IDC_DEBUG_STEP_OVER 1275 +#define IDC_CUSTOMFPS 1275 +#define IDC_DEBUG_RUN_TO_CURSOR 1276 +#define IDC_CUSTOM_FPS 1276 +#define IDC_DEBUG_STEP_TO_CURSOR 1277 +#define IDC_ENABLEBUTTON 1277 +#define IDC_CUSTOM_FRAMESKIP 1277 +#define IDC_DEBUG_BREAK 1278 +#define IDC_ADDGS 1278 +#define IDC_CONVERTEDCODE 1278 +#define IDC_CUSTOM_CONSECUTIVE_FRAMES 1278 +#define IDC_VU_OVERFLOWHACK 1278 +#define IDC_HACKDESC 1279 +#define IDC_CONVERT 1279 +#define IDC_EDITPATCH 1279 +#define IDC_FRAMESKIP_LABEL1 1279 +#define IDC_READY 1280 +#define IDC_ADDPATCH 1280 +#define IDC_FRAMESKIP_LABEL2 1280 +#define IDC_GROUP 1281 +#define IDC_ADDRAW 1281 +#define IDC_FRAMESKIP_LABEL3 1281 +#define IDC_DATA 1282 +#define IDC_PNACHWRITER 1282 +#define IDC_CUSTOM_CONSECUTIVE_SKIP 1282 +#define IDC_PNACHWRITER2 1283 +#define IDC_SKIPMPEG 1283 +#define IDC_FRAMESKIP_LABEL4 1283 +#define IDC_SPIN1 1284 +#define IDC_FRAMESKIP_LABEL5 1284 +#define IDC_FRAMESKIP_LABEL6 1285 +#define IDC_SAVE 1286 +#define IDC_CRC 1287 +#define IDC_COMMENT 1288 +#define IDC_GAMETITLE 1289 +#define IDC_FASTMEMORY 1290 +#define IDC_ZEROGS 1291 +#define IDC_ROUND1 1292 +#define IDC_ROUND2 1293 +#define IDC_PATH3HACK 1294 +#define IDC_VUNANMODE 1295 +#define IDC_TREE1 1297 +#define IDC_TREE2 1298 +#define IDC_ICON1 1299 +#define IDC_ICON2 1300 +#define IDC_EE_CHECK1 1300 +#define IDC_EE_CHECK2 1301 +#define IDC_GAMEFIX2 1301 +#define IDC_VU_CHECK1 1302 +#define IDC_VU_FLAGS 1302 +#define IDC_GAMEFIX3 1302 +#define IDC_FRAMELIMIT_OPTIONS 1303 +#define IDC_VU_CHECK2 1303 +#define IDC_GAMEFIX4 1303 +#define IDC_SOUNDHACK2 1304 +#define IDC_ESCHACK 1304 +#define IDC_VU_CHECK3 1304 +#define IDC_GAMEFIX5 1304 +#define IDC_GAMEFIX1 1304 +#define IDC_EE_ROUNDMODE0 1305 +#define IDC_EE_ROUNDMODE1 1306 +#define IDC_EE_ROUNDMODE2 1307 +#define IDC_EE_ROUNDMODE3 1308 +#define IDC_EESYNC_DEFAULT 1308 +#define IDC_VU_CHECK4 1309 +#define IDC_EESYNC1 1309 +#define IDC_EESYNC2 1310 +#define IDC_VU_ROUNDMODE0 1311 +#define IDC_EESYNC3 1311 +#define IDC_VU_ROUNDMODE1 1312 +#define IDC_IOPSYNC 1312 +#define IDC_VU_ROUNDMODE2 1313 +#define IDC_CHECK2 1313 +#define IDC_WAITCYCLES 1313 +#define IDC_VU_ROUNDMODE3 1314 +#define IDC_VU_CLAMPMODE0 1315 +#define IDC_VU_CLAMPMODE1 1316 +#define IDC_VU_CLAMPMODE2 1317 +#define IDC_VU_CLAMPMODE3 1318 +#define IDC_EE_CLAMPMODE0 1319 +#define IDC_EE_CLAMPMODE1 1320 +#define IDC_EE_CLAMPMODE2 1321 +#define IDC_CPULOG 1500 +#define IDC_MEMLOG 1501 +#define IDC_HWLOG 1502 +#define IDC_DMALOG 1503 +#define IDC_BIOSLOG 1504 +#define IDC_ELFLOG 1505 +#define IDC_FPULOG 1506 +#define IDC_MMILOG 1507 +#define IDC_VU0LOG 1508 +#define IDC_COP0LOG 1509 +#define IDC_VIFLOG 1510 +#define IDC_SPRLOG 1511 +#define IDC_GIFLOG 1512 +#define IDC_SIFLOG 1513 +#define IDC_IPULOG 1514 +#define IDC_VUMICROLOG 1515 +#define IDC_RPCSERVICES 1516 +#define IDC_IOPLOG 1520 +#define IDC_IOPMEMLOG 1521 +#define IDC_IOPHWLOG 1522 +#define IDC_IOPBIOSLOG 1523 +#define IDC_IOPDMALOG 1524 +#define IDC_IOPPADLOG 1525 +#define IDC_IOPCDRLOG 1527 +#define IDC_IOPCNTLOG 1529 +#define IDC_EECNTLOG 1530 +#define IDC_SYMLOG 1531 +#define IDC_STDOUTPUTLOG 1532 +#define IDC_SEARCH 1701 +#define IDC_VALUE 1702 +#define IDC_OLD 1703 +#define IDC_SET 1704 +#define IDC_EQ 1705 +#define IDC_GT 1706 +#define IDC_LT 1707 +#define IDC_GE 1708 +#define IDC_LE 1709 +#define IDC_NE 1710 +#define IDC_EE 1711 +#define IDC_IOP 1712 +#define IDC_RESET 1713 +#define IDC_ADD 1714 +#define IDC_STATUS 1716 +#define IDC_FW 1716 +#define IDC_FRAMELIMIT 1716 +#define IDC_ADDRESS 1716 +#define IDC_UNSIGNED 1717 +#define IDC_8B 1718 +#define IDC_16B 1719 +#define IDC_32B 1720 +#define IDC_64B 1721 +#define IDC_RESULTS 1722 +#define IDC_NAME 1723 +#define IDC_ADDR 1725 +#define IDC_MATCHES 1726 +#define ID_FILEOPEN 40001 +#define ID_DEBUG_MEMORY_DUMP 40002 +#define ID_FILE_EXIT 40003 +#define ID_RUN_EXECUTE 40004 +#define ID_RUN_RESET 40005 +#define ID_HELP_ABOUT 40006 +#define ID_CONFIG_CONFIGURE 40007 +#define ID_CONFIG_CPU 40008 +#define ID_CONFIG_GRAPHICS 40009 +#define ID_CONFIG_CONTROLLERS 40010 +#define ID_DEBUG_LOGGING 40011 +#define ID_CONFIG_SOUND 40012 +#define ID_CONFIG_CDVDROM 40013 +#define ID_RUN_CMDLINE 40014 +#define ID_FILE_RUNCD 40015 +#define ID_DEBUG_ENTERDEBUGGER 40016 +#define ID_CONFIG_DEV9 40017 +#define ID_FILE_STATES_LOAD_SLOT1 40018 +#define ID_FILE_STATES_LOAD_SLOT2 40019 +#define ID_FILE_STATES_LOAD_SLOT3 40020 +#define ID_FILE_STATES_LOAD_SLOT4 40021 +#define ID_FILE_STATES_LOAD_SLOT5 40022 +#define ID_FILE_STATES_LOAD_OTHER 40023 +#define ID_FILE_STATES_SAVE_SLOT1 40024 +#define ID_FILE_STATES_SAVE_SLOT2 40025 +#define ID_FILE_STATES_SAVE_SLOT3 40026 +#define ID_FILE_STATES_SAVE_SLOT4 40027 +#define ID_FILE_STATES_SAVE_SLOT5 40028 +#define ID_FILE_STATES_SAVE_OTHER 40029 +#define ID_CONFIG_FW 40030 +#define ID_CONFIG_USB 40031 +#define ID_CONFIG_MEMCARDS 40032 +#define IDC_FORMAT1 40033 +#define IDC_FORMAT2 40034 +#define IDC_LIST1 40035 +#define IDC_LIST2 40036 +#define IDC_RELOAD1 40037 +#define IDC_RELOAD2 40038 +#define IDC_COPYTO2 40039 +#define IDC_COPYTO1 40040 +#define IDC_PASTE 40041 +#define IDC_DELETE1 40042 +#define IDC_DELETE2 40043 +#define ID_PATCHBROWSER 40044 +#define ID_NEWPATCH 40045 +#define IDC_NEWPATCH 40045 +#define IDC_PATCHTEXT 40046 +#define IDC_SAVEPATCH 40047 +#define IDC_REFRESHPATCHLIST 40048 +#define IDC_PATCHCRCLIST 40049 +#define IDC_PATCHNAMELIST 40050 +#define IDC_GAMENAMESEARCH 40051 +#define IDC_SEARCHPATCHTEXT 40052 +#define ID_PROCESSLOW 40053 +#define ID_PROCESSNORMAL 40054 +#define ID_PROCESSHIGH 40055 +#define ID_CONSOLE 40056 +#define ID_PATCHES 40057 +#define ID_CONFIG_ADVANCED 40058 +#define ID_INTERLACEHACK 40059 +#define ID_SAFECNTS 40060 +#define ID_SPU2HACK 40061 +#define ID_VSYNCRATE 40062 +#define ID_HELP_HELP 40063 +#define ID_PROFILER 40066 +#define ID_CDVDPRINT 40067 +#define ID_CLOSEGS 40070 +#define ID_CHEAT_FINDER_SHOW 40100 +#define ID_CHEAT_BROWSER_SHOW 40101 +#define ID_HACKS 40102 +#define ID_GAMEFIXES 40103 +#define ID_ADVANCED_OPTIONS 40104 +#define ID_LANGS 50000 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 141 +#define _APS_NEXT_COMMAND_VALUE 40018 +#define _APS_NEXT_CONTROL_VALUE 1314 +#define _APS_NEXT_SYMED_VALUE 104 +#endif +#endif diff --git a/pcsx2/x86/BaseblockEx.cpp b/pcsx2/x86/BaseblockEx.cpp index e48c5eee71..28614b4c28 100644 --- a/pcsx2/x86/BaseblockEx.cpp +++ b/pcsx2/x86/BaseblockEx.cpp @@ -1,149 +1,149 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" -#include "BaseblockEx.h" - -#include - -using namespace std; - -struct BASEBLOCKS -{ - // 0 - ee, 1 - iop - void Add(BASEBLOCKEX*); - void Remove(BASEBLOCKEX*); - int Get(u32 startpc); - void Reset(); - - BASEBLOCKEX** GetAll(int* pnum); - - vector blocks; -}; - -void BASEBLOCKS::Add(BASEBLOCKEX* pex) -{ - assert( pex != NULL ); - - switch(blocks.size()) { - case 0: - blocks.push_back(pex); - return; - case 1: - assert( blocks.front()->startpc != pex->startpc ); - - if( blocks.front()->startpc < pex->startpc ) { - blocks.push_back(pex); - } - else blocks.insert(blocks.begin(), pex); - - return; - - default: - { - int imin = 0, imax = blocks.size(), imid; - - while(imin < imax) { - imid = (imin+imax)>>1; - - if( blocks[imid]->startpc > pex->startpc ) imax = imid; - else imin = imid+1; - } - - assert( imin == blocks.size() || blocks[imin]->startpc > pex->startpc ); - if( imin > 0 ) assert( blocks[imin-1]->startpc < pex->startpc ); - blocks.insert(blocks.begin()+imin, pex); - - return; - } - } -} - -int BASEBLOCKS::Get(u32 startpc) -{ - switch(blocks.size()) { - case 1: - return 0; - case 2: - return blocks.front()->startpc < startpc; - - default: - { - int imin = 0, imax = blocks.size()-1, imid; - - while(imin < imax) { - imid = (imin+imax)>>1; - - if( blocks[imid]->startpc > startpc ) imax = imid; - else if( blocks[imid]->startpc == startpc ) return imid; - else imin = imid+1; - } - - assert( blocks[imin]->startpc == startpc ); - return imin; - } - } -} - -void BASEBLOCKS::Remove(BASEBLOCKEX* pex) -{ - assert( pex != NULL ); - int i = Get(pex->startpc); - assert( blocks[i] == pex ); - blocks.erase(blocks.begin()+i); -} - -void BASEBLOCKS::Reset() -{ - blocks.resize(0); - blocks.reserve(512); -} - -BASEBLOCKEX** BASEBLOCKS::GetAll(int* pnum) -{ - assert( pnum != NULL ); - *pnum = blocks.size(); - return &blocks[0]; -} - -static BASEBLOCKS s_vecBaseBlocksEx[2]; - -void AddBaseBlockEx(BASEBLOCKEX* pex, int cpu) -{ - s_vecBaseBlocksEx[cpu].Add(pex); -} - -BASEBLOCKEX* GetBaseBlockEx(u32 startpc, int cpu) -{ - return s_vecBaseBlocksEx[cpu].blocks[s_vecBaseBlocksEx[cpu].Get(startpc)]; -} - -void RemoveBaseBlockEx(BASEBLOCKEX* pex, int cpu) -{ - s_vecBaseBlocksEx[cpu].Remove(pex); -} - -void ResetBaseBlockEx(int cpu) -{ - s_vecBaseBlocksEx[cpu].Reset(); -} - -BASEBLOCKEX** GetAllBaseBlocks(int* pnum, int cpu) -{ - return s_vecBaseBlocksEx[cpu].GetAll(pnum); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" +#include "BaseblockEx.h" + +#include + +using namespace std; + +struct BASEBLOCKS +{ + // 0 - ee, 1 - iop + void Add(BASEBLOCKEX*); + void Remove(BASEBLOCKEX*); + int Get(u32 startpc); + void Reset(); + + BASEBLOCKEX** GetAll(int* pnum); + + vector blocks; +}; + +void BASEBLOCKS::Add(BASEBLOCKEX* pex) +{ + assert( pex != NULL ); + + switch(blocks.size()) { + case 0: + blocks.push_back(pex); + return; + case 1: + assert( blocks.front()->startpc != pex->startpc ); + + if( blocks.front()->startpc < pex->startpc ) { + blocks.push_back(pex); + } + else blocks.insert(blocks.begin(), pex); + + return; + + default: + { + int imin = 0, imax = blocks.size(), imid; + + while(imin < imax) { + imid = (imin+imax)>>1; + + if( blocks[imid]->startpc > pex->startpc ) imax = imid; + else imin = imid+1; + } + + assert( imin == blocks.size() || blocks[imin]->startpc > pex->startpc ); + if( imin > 0 ) assert( blocks[imin-1]->startpc < pex->startpc ); + blocks.insert(blocks.begin()+imin, pex); + + return; + } + } +} + +int BASEBLOCKS::Get(u32 startpc) +{ + switch(blocks.size()) { + case 1: + return 0; + case 2: + return blocks.front()->startpc < startpc; + + default: + { + int imin = 0, imax = blocks.size()-1, imid; + + while(imin < imax) { + imid = (imin+imax)>>1; + + if( blocks[imid]->startpc > startpc ) imax = imid; + else if( blocks[imid]->startpc == startpc ) return imid; + else imin = imid+1; + } + + assert( blocks[imin]->startpc == startpc ); + return imin; + } + } +} + +void BASEBLOCKS::Remove(BASEBLOCKEX* pex) +{ + assert( pex != NULL ); + int i = Get(pex->startpc); + assert( blocks[i] == pex ); + blocks.erase(blocks.begin()+i); +} + +void BASEBLOCKS::Reset() +{ + blocks.resize(0); + blocks.reserve(512); +} + +BASEBLOCKEX** BASEBLOCKS::GetAll(int* pnum) +{ + assert( pnum != NULL ); + *pnum = blocks.size(); + return &blocks[0]; +} + +static BASEBLOCKS s_vecBaseBlocksEx[2]; + +void AddBaseBlockEx(BASEBLOCKEX* pex, int cpu) +{ + s_vecBaseBlocksEx[cpu].Add(pex); +} + +BASEBLOCKEX* GetBaseBlockEx(u32 startpc, int cpu) +{ + return s_vecBaseBlocksEx[cpu].blocks[s_vecBaseBlocksEx[cpu].Get(startpc)]; +} + +void RemoveBaseBlockEx(BASEBLOCKEX* pex, int cpu) +{ + s_vecBaseBlocksEx[cpu].Remove(pex); +} + +void ResetBaseBlockEx(int cpu) +{ + s_vecBaseBlocksEx[cpu].Reset(); +} + +BASEBLOCKEX** GetAllBaseBlocks(int* pnum, int cpu) +{ + return s_vecBaseBlocksEx[cpu].GetAll(pnum); +} diff --git a/pcsx2/x86/BaseblockEx.h b/pcsx2/x86/BaseblockEx.h index c3502262f2..044d5606d5 100644 --- a/pcsx2/x86/BaseblockEx.h +++ b/pcsx2/x86/BaseblockEx.h @@ -1,77 +1,77 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef _BASEBLOCKEX_H_ -#define _BASEBLOCKEX_H_ - -// used to keep block information -#define BLOCKTYPE_STARTPC 4 // startpc offset -#define BLOCKTYPE_DELAYSLOT 1 // if bit set, delay slot - -// Every potential jump point in the PS2's addressable memory has a BASEBLOCK -// associated with it. So that means a BASEBLOCK for every 4 bytes of PS2 -// addressable memory. Yay! -struct BASEBLOCK -{ - u32 m_pFnptr : 28; - u32 uType : 4; - u32 startpc; - - const uptr GetFnptr() const { return ((u32)m_pFnptr)<<4; } - void SetFnptr( uptr ptr ) - { - // 16 byte alignments only, please! - jASSUME( (ptr & 0xf) == 0 ); - m_pFnptr = ptr>>4; - } -}; - -// extra block info (only valid for start of fn) -// The only "important" piece of information is size. Startpc is used as a debug/check -// var to make sure the baseblock is sane. (and it's used for some FFX hack involving -// a big snake in a sewer, but no one knows if the hack is relevant anymore). -struct BASEBLOCKEX -{ - u16 size; // size in dwords - u16 dummy; - u32 startpc; // for debugging? - -#ifdef PCSX2_DEVBUILD - u32 visited; // number of times called - LARGE_INTEGER ltime; // regs it assumes to have set already -#endif - -}; - -// This is an asinine macro that bases indexing on sizeof(BASEBLOCK) for no reason. (air) -#define GET_BLOCKTYPE(b) ((b)->Type) -#define PC_GETBLOCK_(x, reclut) ((BASEBLOCK*)(reclut[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) - -// This is needed because of the retarded GETBLOCK macro above. -C_ASSERT( sizeof(BASEBLOCK) == 8 ); - -// 0 - ee, 1 - iop -extern void AddBaseBlockEx(BASEBLOCKEX*, int cpu); -extern void RemoveBaseBlockEx(BASEBLOCKEX*, int cpu); -extern BASEBLOCKEX* GetBaseBlockEx(u32 startpc, int cpu); -extern void ResetBaseBlockEx(int cpu); - -extern BASEBLOCKEX** GetAllBaseBlocks(int* pnum, int cpu); - - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef _BASEBLOCKEX_H_ +#define _BASEBLOCKEX_H_ + +// used to keep block information +#define BLOCKTYPE_STARTPC 4 // startpc offset +#define BLOCKTYPE_DELAYSLOT 1 // if bit set, delay slot + +// Every potential jump point in the PS2's addressable memory has a BASEBLOCK +// associated with it. So that means a BASEBLOCK for every 4 bytes of PS2 +// addressable memory. Yay! +struct BASEBLOCK +{ + u32 m_pFnptr : 28; + u32 uType : 4; + u32 startpc; + + const uptr GetFnptr() const { return ((u32)m_pFnptr)<<4; } + void SetFnptr( uptr ptr ) + { + // 16 byte alignments only, please! + jASSUME( (ptr & 0xf) == 0 ); + m_pFnptr = ptr>>4; + } +}; + +// extra block info (only valid for start of fn) +// The only "important" piece of information is size. Startpc is used as a debug/check +// var to make sure the baseblock is sane. (and it's used for some FFX hack involving +// a big snake in a sewer, but no one knows if the hack is relevant anymore). +struct BASEBLOCKEX +{ + u16 size; // size in dwords + u16 dummy; + u32 startpc; // for debugging? + +#ifdef PCSX2_DEVBUILD + u32 visited; // number of times called + LARGE_INTEGER ltime; // regs it assumes to have set already +#endif + +}; + +// This is an asinine macro that bases indexing on sizeof(BASEBLOCK) for no reason. (air) +#define GET_BLOCKTYPE(b) ((b)->Type) +#define PC_GETBLOCK_(x, reclut) ((BASEBLOCK*)(reclut[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) + +// This is needed because of the retarded GETBLOCK macro above. +C_ASSERT( sizeof(BASEBLOCK) == 8 ); + +// 0 - ee, 1 - iop +extern void AddBaseBlockEx(BASEBLOCKEX*, int cpu); +extern void RemoveBaseBlockEx(BASEBLOCKEX*, int cpu); +extern BASEBLOCKEX* GetBaseBlockEx(u32 startpc, int cpu); +extern void ResetBaseBlockEx(int cpu); + +extern BASEBLOCKEX** GetAllBaseBlocks(int* pnum, int cpu); + + #endif \ No newline at end of file diff --git a/pcsx2/x86/Makefile.am b/pcsx2/x86/Makefile.am index c63319eac3..34e34cb5c9 100644 --- a/pcsx2/x86/Makefile.am +++ b/pcsx2/x86/Makefile.am @@ -1,22 +1,22 @@ -INCLUDES = -I@srcdir@/../ -I@srcdir@/../common/ -I@srcdir@/../IPU/ -noinst_LIBRARIES = libx86recomp.a - -# have to add the sources instead of making a library since the linking is complicated - -archfiles = ix86-32/iR5900-32.cpp ix86-32/iR5900AritImm.cpp ix86-32/iR5900Jump.cpp \ -ix86-32/iR5900Move.cpp ix86-32/iR5900Shift.cpp ix86-32/iR5900Arit.cpp ix86-32/iR5900Branch.cpp \ -ix86-32/iR5900LoadStore.cpp ix86-32/iR5900MultDiv.cpp ix86-32/iCore-32.cpp ix86-32/aR5900-32.S \ -ix86-32/iR5900Templates.cpp ix86-32/recVTLB.cpp - -libx86recomp_a_SOURCES = \ -BaseblockEx.cpp iCOP0.cpp iCOP2.cpp iCore.cpp iFPU.cpp iGS.cpp iHw.cpp iIPU.cpp iMMI.cpp iPsxHw.cpp iPsxMem.cpp \ -iR3000A.cpp iR3000Atables.cpp iR5900CoissuedLoadStore.cpp iR5900Misc.cpp iVU0micro.cpp iVU1micro.cpp iVUmicro.cpp \ -iVUmicroLower.cpp iVUmicroUpper.cpp iVUzerorec.cpp iVif.cpp ir5900tables.cpp fast_routines.S aR3000A.S aVUzerorec.S aVif.S $(archfiles) - -libx86recomp_a_SOURCES += \ -BaseblockEx.h iCOP0.h iCore.h iFPU.h iMMI.h iR3000A.h iR5900.h iR5900Arit.h iR5900AritImm.h iR5900Branch.h iR5900Jump.h \ -iR5900LoadStore.h iR5900Move.h iR5900MultDiv.h iR5900Shift.h iVUmicro.h iVUops.h iVUzerorec.h - -libx86recomp_a_DEPENDENCIES = ix86/libix86.a - +INCLUDES = -I@srcdir@/../ -I@srcdir@/../common/ -I@srcdir@/../IPU/ +noinst_LIBRARIES = libx86recomp.a + +# have to add the sources instead of making a library since the linking is complicated + +archfiles = ix86-32/iR5900-32.cpp ix86-32/iR5900AritImm.cpp ix86-32/iR5900Jump.cpp \ +ix86-32/iR5900Move.cpp ix86-32/iR5900Shift.cpp ix86-32/iR5900Arit.cpp ix86-32/iR5900Branch.cpp \ +ix86-32/iR5900LoadStore.cpp ix86-32/iR5900MultDiv.cpp ix86-32/iCore-32.cpp ix86-32/aR5900-32.S \ +ix86-32/iR5900Templates.cpp ix86-32/recVTLB.cpp + +libx86recomp_a_SOURCES = \ +BaseblockEx.cpp iCOP0.cpp iCOP2.cpp iCore.cpp iFPU.cpp iGS.cpp iHw.cpp iIPU.cpp iMMI.cpp iPsxHw.cpp iPsxMem.cpp \ +iR3000A.cpp iR3000Atables.cpp iR5900CoissuedLoadStore.cpp iR5900Misc.cpp iVU0micro.cpp iVU1micro.cpp iVUmicro.cpp \ +iVUmicroLower.cpp iVUmicroUpper.cpp iVUzerorec.cpp iVif.cpp ir5900tables.cpp fast_routines.S aR3000A.S aVUzerorec.S aVif.S $(archfiles) + +libx86recomp_a_SOURCES += \ +BaseblockEx.h iCOP0.h iCore.h iFPU.h iMMI.h iR3000A.h iR5900.h iR5900Arit.h iR5900AritImm.h iR5900Branch.h iR5900Jump.h \ +iR5900LoadStore.h iR5900Move.h iR5900MultDiv.h iR5900Shift.h iVUmicro.h iVUops.h iVUzerorec.h + +libx86recomp_a_DEPENDENCIES = ix86/libix86.a + SUBDIRS = ix86 \ No newline at end of file diff --git a/pcsx2/x86/fast_routines.cpp b/pcsx2/x86/fast_routines.cpp index c9ab4fc55d..c561a0e0ab 100644 --- a/pcsx2/x86/fast_routines.cpp +++ b/pcsx2/x86/fast_routines.cpp @@ -1,884 +1,884 @@ -/****************************************************************************** - - Copyright (c) 2001 Advanced Micro Devices, Inc. - - LIMITATION OF LIABILITY: THE MATERIALS ARE PROVIDED *AS IS* WITHOUT ANY - EXPRESS OR IMPLIED WARRANTY OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, - NONINFRINGEMENT OF THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY - PARTICULAR PURPOSE. IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY - DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, - BUSINESS INTERRUPTION, LOSS OF INFORMATION) ARISING OUT OF THE USE OF OR - INABILITY TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY - OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE EXCLUSION OR LIMITATION - OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY - NOT APPLY TO YOU. - - AMD does not assume any responsibility for any errors which may appear in the - Materials nor any responsibility to support or update the Materials. AMD retains - the right to make changes to its test specifications at any time, without notice. - - NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any - further information, software, technical information, know-how, or show-how - available to you. - - So that all may benefit from your experience, please report any problems - or suggestions about this software to 3dsdk.support@amd.com - - AMD Developer Technologies, M/S 585 - Advanced Micro Devices, Inc. - 5900 E. Ben White Blvd. - Austin, TX 78741 - 3dsdk.support@amd.com -******************************************************************************/ - -#include "PrecompiledHeader.h" - -#ifdef _MSC_VER -#pragma warning(disable:4414) -#endif - -/***************************************************************************** -MEMCPY_AMD.CPP -******************************************************************************/ - -// Very optimized memcpy() routine for AMD Athlon and Duron family. -// This code uses any of FOUR different basic copy methods, depending -// on the transfer size. -// NOTE: Since this code uses MOVNTQ (also known as "Non-Temporal MOV" or -// "Streaming Store"), and also uses the software prefetch instructions, -// be sure you're running on Athlon/Duron or other recent CPU before calling! - -#define TINY_BLOCK_COPY 64 // upper limit for movsd type copy -// The smallest copy uses the X86 "movsd" instruction, in an optimized -// form which is an "unrolled loop". - -#define IN_CACHE_COPY 2 * 1024 // upper limit for movq/movq copy w/SW prefetch -// Next is a copy that uses the MMX registers to copy 8 bytes at a time, -// also using the "unrolled loop" optimization. This code uses -// the software prefetch instruction to get the data into the cache. - -#define UNCACHED_COPY 4 * 1024 // upper limit for movq/movntq w/SW prefetch -// For larger blocks, which will spill beyond the cache, it's faster to -// use the Streaming Store instruction MOVNTQ. This write instruction -// bypasses the cache and writes straight to main memory. This code also -// uses the software prefetch instruction to pre-read the data. -// USE 64 * 1024 FOR THIS VALUE IF YOU'RE ALWAYS FILLING A "CLEAN CACHE" - -#define BLOCK_PREFETCH_COPY infinity // no limit for movq/movntq w/block prefetch -#define CACHEBLOCK 80h // number of 64-byte blocks (cache lines) for block prefetch -// For the largest size blocks, a special technique called Block Prefetch -// can be used to accelerate the read operations. Block Prefetch reads -// one address per cache line, for a series of cache lines, in a short loop. -// This is faster than using software prefetch. The technique is great for -// getting maximum read bandwidth, especially in DDR memory systems. - -#include "Misc.h" - -// Inline assembly syntax for use with Visual C++ - -#if defined(_MSC_VER) - -#ifdef _DEBUG -extern u8 g_globalMMXSaved; - -void checkregs() -{ - if( g_EEFreezeRegs ) assert( g_globalMMXSaved ); -} -#endif - - -PCSX2_ALIGNED16( static u8 _xmm_backup[16*2] ); -PCSX2_ALIGNED16( static u8 _mmx_backup[8*4] ); - -static __declspec(naked) void __fastcall _memcpy_raz_usrc(void *dest, const void *src, size_t bytes) -{ - // MOVSRC = opcode used to read. I use the same code for the aligned version, with a different define :) - #define MOVSRC movdqu - #define MOVDST movdqa - - __asm - { - //Reads before reads, to avoid stalls - mov eax,[esp+4]; - //Make sure to save xmm0, it must be preserved ... - movaps [_xmm_backup],xmm0; - - //if >=128 bytes use 128 byte unrolled loop - //i use cmp ..,127 + jna because 127 is encodable using the simm8 form - cmp eax,127; - jna _loop_1; - - //since this is a common branch target it could be good to align it -- no idea if it has any effect :p - align 16 - - //128 byte unrolled loop -_loop_8: - - MOVSRC xmm0,[edx+0x00]; //read first to avoid read-after-write stalls - MOVDST [ecx+0x00],xmm0; //then write :p - MOVSRC xmm0,[edx+0x10]; - MOVDST [ecx+0x10],xmm0; - sub edx,-128; //edx won't be used for a while, so update it here. sub/-128 for simm8 encoding - sub ecx,-128; //ecx won't be used for a while, so update it here. sub/-128 for simm8 encoding - - MOVSRC xmm0,[edx+0x20-128]; - MOVDST [ecx+0x20-128],xmm0; - MOVSRC xmm0,[edx+0x30-128]; - MOVDST [ecx+0x30-128],xmm0; - add eax,-128; //eax won't be used for a while, so update it here. add/-128 for simm8 encoding - - MOVSRC xmm0,[edx+0x40-128]; - MOVDST [ecx+0x40-128],xmm0; - MOVSRC xmm0,[edx+0x50-128]; - MOVDST [ecx+0x50-128],xmm0; - - MOVSRC xmm0,[edx+0x60-128]; - MOVDST [ecx+0x60-128],xmm0; - MOVSRC xmm0,[edx+0x70-128]; - MOVDST [ecx+0x70-128],xmm0; - - //127~ja, 127 is encodable as simm8 :) - cmp eax,127; - ja _loop_8; - - //direct copy for 0~7 qwords - //in order to avoid the inc/dec of all 3 registers - //i use negative relative addressing from the top of the buffers - //[top-current index] - -_loop_1: - //prepare the regs for 'negative relative addressing' - add edx,eax; - add ecx,eax; - neg eax; - jz cleanup; //exit if nothing to do - -_loop_1_inner: - MOVSRC xmm0,[edx+eax]; - MOVDST [ecx+eax],xmm0; - - add eax,16; //while the offset is still negative we have data to copy - js _loop_1_inner; - - //done ! -cleanup: - //restore xmm and exit ~) - movaps xmm0,[_xmm_backup]; - ret 4; - } - #undef MOVSRC - #undef MOVDST -} - - -static __declspec(naked) void __fastcall _memcpy_raz_udst(void *dest, const void *src, size_t bytes) -{ - // MOVDST = opcode used to read. I use the same code for the aligned version, with a different define :) - #define MOVSRC movaps - #define MOVDST movups - __asm - { - //Reads before reads, to avoid stalls - mov eax,[esp+4]; - //Make sure to save xmm0, it must be preserved ... - movaps [_xmm_backup],xmm0; - - //if >=128 bytes use 128 byte unrolled loop - //i use cmp ..,127 + jna because 127 is encodable using the simm8 form - cmp eax,127; - jna _loop_1; - - //since this is a common branch target it could be good to align it -- no idea if it has any effect :p - align 16 - - //128 byte unrolled loop -_loop_8: - - MOVSRC xmm0,[edx+0x00]; //read first to avoid read-after-write stalls - MOVDST [ecx+0x00],xmm0; //then write :p - MOVSRC xmm0,[edx+0x10]; - MOVDST [ecx+0x10],xmm0; - sub edx,-128; //edx won't be used for a while, so update it here. sub/-128 for simm8 encoding - sub ecx,-128; //ecx won't be used for a while, so update it here. sub/-128 for simm8 encoding - - MOVSRC xmm0,[edx+0x20-128]; - MOVDST [ecx+0x20-128],xmm0; - MOVSRC xmm0,[edx+0x30-128]; - MOVDST [ecx+0x30-128],xmm0; - add eax,-128; //eax won't be used for a while, so update it here. add/-128 for simm8 encoding - - MOVSRC xmm0,[edx+0x40-128]; - MOVDST [ecx+0x40-128],xmm0; - MOVSRC xmm0,[edx+0x50-128]; - MOVDST [ecx+0x50-128],xmm0; - - MOVSRC xmm0,[edx+0x60-128]; - MOVDST [ecx+0x60-128],xmm0; - MOVSRC xmm0,[edx+0x70-128]; - MOVDST [ecx+0x70-128],xmm0; - - //127~ja, 127 is encodable as simm8 :) - cmp eax,127; - ja _loop_8; - - //direct copy for 0~7 qwords - //in order to avoid the inc/dec of all 3 registers - //i use negative relative addressing from the top of the buffers - //[top-current index] - -_loop_1: - //prepare the regs for 'negative relative addressing' - add edx,eax; - add ecx,eax; - neg eax; - jz cleanup; //exit if nothing to do - -_loop_1_inner: - MOVSRC xmm0,[edx+eax]; - movaps [ecx+eax],xmm0; - - add eax,16; //while the offset is still negative we have data to copy - js _loop_1_inner; - - //done ! -cleanup: - //restore xmm and exit ~) - movaps xmm0,[_xmm_backup]; - ret 4; - } - #undef MOVSRC - #undef MOVDST -} - -// Custom memcpy, only for 16 byte aligned stuff (used for mtgs) -// This function is optimized for medium-small transfer sizes (<2048, >=128). No prefetching is -// used since the reads are linear and the cache logic can predict em :) -// *OBSOLETE* -- memcpy_amd_ has been optimized and is now faster. -__declspec(naked) void __fastcall memcpy_raz_(void *dest, const void *src, size_t bytes) -{ - // Code Implementation Notes: - // Uses a forward copy, in 128 byte blocks, and then does the remaining in 16 byte blocks :) - - // MOVSRC = opcode used to read. I use the same code for the unaligned version, with a different define :) - #define MOVSRC movaps - #define MOVDST movaps - __asm - { - //Reads before reads, to avoid stalls - mov eax,[esp+4]; - //Make sure to save xmm0, it must be preserved ... - movaps [_xmm_backup],xmm0; - - //if >=128 bytes use 128 byte unrolled loop - //i use cmp ..,127 + jna because 127 is encodable using the simm8 form - cmp eax,127; - jna _loop_1; - - //since this is a common branch target it could be good to align it -- no idea if it has any effect :p - align 16 - - //128 byte unrolled loop -_loop_8: - - MOVSRC xmm0,[edx+0x00]; //read first to avoid read-after-write stalls - MOVDST [ecx+0x00],xmm0; //then write :p - MOVSRC xmm0,[edx+0x10]; - MOVDST [ecx+0x10],xmm0; - sub edx,-128; //edx won't be used for a while, so update it here. sub/-128 for simm8 encoding - sub ecx,-128; //ecx won't be used for a while, so update it here. sub/-128 for simm8 encoding - - MOVSRC xmm0,[edx+0x20-128]; - MOVDST [ecx+0x20-128],xmm0; - MOVSRC xmm0,[edx+0x30-128]; - MOVDST [ecx+0x30-128],xmm0; - add eax,-128; //eax won't be used for a while, so update it here. add/-128 for simm8 encoding - - MOVSRC xmm0,[edx+0x40-128]; - MOVDST [ecx+0x40-128],xmm0; - MOVSRC xmm0,[edx+0x50-128]; - MOVDST [ecx+0x50-128],xmm0; - - MOVSRC xmm0,[edx+0x60-128]; - MOVDST [ecx+0x60-128],xmm0; - MOVSRC xmm0,[edx+0x70-128]; - MOVDST [ecx+0x70-128],xmm0; - - //127~ja, 127 is encodable as simm8 :) - cmp eax,127; - ja _loop_8; - - //direct copy for 0~7 qwords - //in order to avoid the inc/dec of all 3 registers - //i use negative relative addressing from the top of the buffers - //[top-current index] - -_loop_1: - //prepare the regs for 'negative relative addressing' - add edx,eax; - add ecx,eax; - neg eax; - jz cleanup; //exit if nothing to do - -_loop_1_inner: - MOVSRC xmm0,[edx+eax]; - MOVDST [ecx+eax],xmm0; - - add eax,16; //while the offset is still negative we have data to copy - js _loop_1_inner; - - //done ! -cleanup: - //restore xmm and exit ~) - movaps xmm0,[_xmm_backup]; - ret 4; - } - #undef MOVSRC - #undef MOVDST -} - -// This memcpy routine is for use in situations where the source buffer's alignment is indeterminate. -__forceinline void __fastcall memcpy_raz_usrc(void *dest, const void *src, size_t bytes) -{ - if( ((uptr)src & 0xf) == 0 ) - memcpy_raz_( dest, src, bytes ); - else - _memcpy_raz_usrc( dest, src, bytes ); -} - -// This memcpy routine is for use in situations where the destination buffer's alignment is indeterminate. -__forceinline void __fastcall memcpy_raz_udst(void *dest, const void *src, size_t bytes) -{ - if( ((uptr)dest & 0xf) == 0 ) - memcpy_raz_( dest, src, bytes ); - else - _memcpy_raz_udst( dest, src, bytes ); -} - - -////////////////////////////////////////////////////////////////////////// -// Fast memcpy as coded by AMD, and thn improved by air. -// -// This routine preserves mmx registers! It's the complete real deal! -__declspec(naked) void __fastcall memcpy_amd_(void *dest, const void *src, size_t n) -{ - __asm - { - push edi - push esi - - mov edi, ecx ; destination - mov esi, edx ; source - mov ecx, [esp+12] ; number of bytes to copy - mov eax, ecx ; keep a copy of count - - cld - cmp eax, TINY_BLOCK_COPY - jb $memcpy_ic_3 ; tiny? skip mmx copy - - cmp eax, 32*1024 ; don't align between 32k-64k because - jbe $memcpy_do_align ; it appears to be slower - cmp eax, 64*1024 - jbe $memcpy_align_done -$memcpy_do_align: - mov eax, 8 ; a trick that's faster than rep movsb... - sub eax, edi ; align destination to qword - and eax, 111b ; get the low bits - sub ecx, eax ; update copy count - neg eax ; set up to jump into the array - add eax, offset $memcpy_align_done - jmp eax ; jump to array of movsb's - -align 4 - movsb - movsb - movsb - movsb - movsb - movsb - movsb - movsb - -$memcpy_align_done: ; destination is dword aligned - mov eax, ecx ; number of bytes left to copy - shr eax, 6 ; get 64-byte block count - jz $memcpy_ic_2 ; finish the last few bytes - - cmp eax, IN_CACHE_COPY/64 ; too big 4 cache? use uncached copy - jae $memcpy_uc_test - - movq [_mmx_backup+0x00],mm0 - movq [_mmx_backup+0x08],mm1 - movq [_mmx_backup+0x10],mm2 - movq [_mmx_backup+0x18],mm3 - -// This is small block copy that uses the MMX registers to copy 8 bytes -// at a time. It uses the "unrolled loop" optimization, and also uses -// the software prefetch instruction to get the data into the cache. -align 16 -$memcpy_ic_1: ; 64-byte block copies, in-cache copy - - prefetchnta [esi + (200*64/34+192)] ; start reading ahead - - movq mm0, [esi+0] ; read 64 bits - movq mm1, [esi+8] - movq [edi+0], mm0 ; write 64 bits - movq [edi+8], mm1 ; note: the normal movq writes the - movq mm2, [esi+16] ; data to cache; a cache line will be - movq mm3, [esi+24] ; allocated as needed, to store the data - movq [edi+16], mm2 - movq [edi+24], mm3 - movq mm0, [esi+32] - movq mm1, [esi+40] - movq [edi+32], mm0 - movq [edi+40], mm1 - movq mm2, [esi+48] - movq mm3, [esi+56] - movq [edi+48], mm2 - movq [edi+56], mm3 - - add esi, 64 ; update source pointer - add edi, 64 ; update destination pointer - dec eax ; count down - jnz $memcpy_ic_1 ; last 64-byte block? - - movq mm0,[_mmx_backup+0x00] - movq mm1,[_mmx_backup+0x08] - movq mm2,[_mmx_backup+0x10] - movq mm3,[_mmx_backup+0x18] - -$memcpy_ic_2: - mov eax, ecx ; has valid low 6 bits of the byte count -$memcpy_ic_3: - shr eax, 2 ; dword count - and eax, 1111b ; only look at the "remainder" bits - neg eax ; set up to jump into the array - add eax, offset $memcpy_last_few - jmp eax ; jump to array of movsd's - -$memcpy_uc_test: - /*cmp ecx, UNCACHED_COPY/64 ; big enough? use block prefetch copy - jae $memcpy_bp_1 -$memcpy_64_test:*/ - or eax, eax ; tail end of block prefetch will jump here - jz $memcpy_ic_2 ; no more 64-byte blocks left - -// For larger blocks, which will spill beyond the cache, it's faster to -// use the Streaming Store instruction MOVNTQ. This write instruction -// bypasses the cache and writes straight to main memory. This code also -// uses the software prefetch instruction to pre-read the data. - - movq [_mmx_backup+0x00],mm0 - movq [_mmx_backup+0x08],mm1 - movq [_mmx_backup+0x10],mm2 - -align 16 -$memcpy_uc_1: ; 64-byte blocks, uncached copy - - prefetchnta [esi + (200*64/34+192)] ; start reading ahead - - movq mm0,[esi+0] ; read 64 bits - add edi,64 ; update destination pointer - movq mm1,[esi+8] - add esi,64 ; update source pointer - movq mm2,[esi-48] - movntq [edi-64], mm0 ; write 64 bits, bypassing the cache - movq mm0,[esi-40] ; note: movntq also prevents the CPU - movntq [edi-56], mm1 ; from READING the destination address - movq mm1,[esi-32] ; into the cache, only to be over-written - movntq [edi-48], mm2 ; so that also helps performance - movq mm2,[esi-24] - movntq [edi-40], mm0 - movq mm0,[esi-16] - movntq [edi-32], mm1 - movq mm1,[esi-8] - movntq [edi-24], mm2 - movntq [edi-16], mm0 - dec eax - movntq [edi-8], mm1 - jnz $memcpy_uc_1 ; last 64-byte block? - - movq mm0,[_mmx_backup+0x00] - movq mm1,[_mmx_backup+0x08] - movq mm2,[_mmx_backup+0x10] - - jmp $memcpy_ic_2 ; almost done (not needed because large copy below was removed) - -// For the largest size blocks, a special technique called Block Prefetch -// can be used to accelerate the read operations. Block Prefetch reads -// one address per cache line, for a series of cache lines, in a short loop. -// This is faster than using software prefetch. The technique is great for -// getting maximum read bandwidth, especially in DDR memory systems. - -// Note: Pcsx2 rarely invokes large copies, so this mode has been disabled to -// help keep the code cache footprint of memcpy_fast to a minimum. -/* -$memcpy_bp_1: ; large blocks, block prefetch copy - - cmp ecx, CACHEBLOCK ; big enough to run another prefetch loop? - jl $memcpy_64_test ; no, back to regular uncached copy - - mov eax, CACHEBLOCK / 2 ; block prefetch loop, unrolled 2X - add esi, CACHEBLOCK * 64 ; move to the top of the block -align 16 -$memcpy_bp_2: - mov edx, [esi-64] ; grab one address per cache line - mov edx, [esi-128] ; grab one address per cache line - sub esi, 128 ; go reverse order to suppress HW prefetcher - dec eax ; count down the cache lines - jnz $memcpy_bp_2 ; keep grabbing more lines into cache - - mov eax, CACHEBLOCK ; now that it's in cache, do the copy -align 16 -$memcpy_bp_3: - movq mm0, [esi ] ; read 64 bits - movq mm1, [esi+ 8] - movq mm2, [esi+16] - movq mm3, [esi+24] - movq mm4, [esi+32] - movq mm5, [esi+40] - movq mm6, [esi+48] - movq mm7, [esi+56] - add esi, 64 ; update source pointer - movntq [edi ], mm0 ; write 64 bits, bypassing cache - movntq [edi+ 8], mm1 ; note: movntq also prevents the CPU - movntq [edi+16], mm2 ; from READING the destination address - movntq [edi+24], mm3 ; into the cache, only to be over-written, - movntq [edi+32], mm4 ; so that also helps performance - movntq [edi+40], mm5 - movntq [edi+48], mm6 - movntq [edi+56], mm7 - add edi, 64 ; update dest pointer - - dec eax ; count down - - jnz $memcpy_bp_3 ; keep copying - sub ecx, CACHEBLOCK ; update the 64-byte block count - jmp $memcpy_bp_1 ; keep processing chunks -*/ - -// The smallest copy uses the X86 "movsd" instruction, in an optimized -// form which is an "unrolled loop". Then it handles the last few bytes. -align 4 - movsd - movsd ; perform last 1-15 dword copies - movsd - movsd - movsd - movsd - movsd - movsd - movsd - movsd ; perform last 1-7 dword copies - movsd - movsd - movsd - movsd - movsd - movsd - -$memcpy_last_few: ; dword aligned from before movsd's - mov eax, ecx ; has valid low 2 bits of the byte count - and eax, 11b ; the last few cows must come home - jz $memcpy_final ; no more, let's leave - rep movsb ; the last 1, 2, or 3 bytes - -$memcpy_final: - emms ; clean up the MMX state - sfence ; flush the write buffer - //mov eax, [dest] ; ret value = destination pointer - - pop esi - pop edi - - ret 4 - } -} - -// mmx mem-compare implementation, size has to be a multiple of 8 -// returns 0 is equal, nonzero value if not equal -// ~10 times faster than standard memcmp -// (zerofrog) -u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) -{ - assert( (cmpsize&7) == 0 ); - - __asm { - push esi - mov ecx, cmpsize - mov edx, src1 - mov esi, src2 - - cmp ecx, 32 - jl Done4 - - // custom test first 8 to make sure things are ok - movq mm0, [esi] - movq mm1, [esi+8] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pand mm0, mm1 - movq mm2, [esi+16] - pmovmskb eax, mm0 - movq mm3, [esi+24] - - // check if eq - cmp eax, 0xff - je NextComp - mov eax, 1 - jmp End - -NextComp: - pcmpeqd mm2, [edx+16] - pcmpeqd mm3, [edx+24] - pand mm2, mm3 - pmovmskb eax, mm2 - - sub ecx, 32 - add esi, 32 - add edx, 32 - - // check if eq - cmp eax, 0xff - je ContinueTest - mov eax, 1 - jmp End - - cmp ecx, 64 - jl Done8 - -Cmp8: - movq mm0, [esi] - movq mm1, [esi+8] - movq mm2, [esi+16] - movq mm3, [esi+24] - movq mm4, [esi+32] - movq mm5, [esi+40] - movq mm6, [esi+48] - movq mm7, [esi+56] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pcmpeqd mm2, [edx+16] - pcmpeqd mm3, [edx+24] - pand mm0, mm1 - pcmpeqd mm4, [edx+32] - pand mm0, mm2 - pcmpeqd mm5, [edx+40] - pand mm0, mm3 - pcmpeqd mm6, [edx+48] - pand mm0, mm4 - pcmpeqd mm7, [edx+56] - pand mm0, mm5 - pand mm0, mm6 - pand mm0, mm7 - pmovmskb eax, mm0 - - // check if eq - cmp eax, 0xff - je Continue - mov eax, 1 - jmp End - -Continue: - sub ecx, 64 - add esi, 64 - add edx, 64 -ContinueTest: - cmp ecx, 64 - jge Cmp8 - -Done8: - test ecx, 0x20 - jz Done4 - movq mm0, [esi] - movq mm1, [esi+8] - movq mm2, [esi+16] - movq mm3, [esi+24] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pcmpeqd mm2, [edx+16] - pcmpeqd mm3, [edx+24] - pand mm0, mm1 - pand mm0, mm2 - pand mm0, mm3 - pmovmskb eax, mm0 - sub ecx, 32 - add esi, 32 - add edx, 32 - - // check if eq - cmp eax, 0xff - je Done4 - mov eax, 1 - jmp End - -Done4: - cmp ecx, 24 - jne Done2 - movq mm0, [esi] - movq mm1, [esi+8] - movq mm2, [esi+16] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pcmpeqd mm2, [edx+16] - pand mm0, mm1 - pand mm0, mm2 - pmovmskb eax, mm0 - - // check if eq - cmp eax, 0xff - setne al - jmp End - -Done2: - cmp ecx, 16 - jne Done1 - - movq mm0, [esi] - movq mm1, [esi+8] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pand mm0, mm1 - pmovmskb eax, mm0 - - // check if eq - cmp eax, 0xff - setne al - jmp End - -Done1: - cmp ecx, 8 - jne Done - - mov eax, [esi] - mov esi, [esi+4] - cmp eax, [edx] - je Next - mov eax, 1 - jmp End - -Next: - cmp esi, [edx+4] - setne al - jmp End - -Done: - xor eax, eax - -End: - pop esi - emms - } -} - - -// returns the xor of all elements, cmpsize has to be mult of 8 -void memxor_mmx(void* dst, const void* src1, int cmpsize) -{ - FreezeMMXRegs(1); - assert( (cmpsize&7) == 0 ); - - __asm { - mov ecx, cmpsize - mov eax, src1 - mov edx, dst - - cmp ecx, 64 - jl Setup4 - - movq mm0, [eax] - movq mm1, [eax+8] - movq mm2, [eax+16] - movq mm3, [eax+24] - movq mm4, [eax+32] - movq mm5, [eax+40] - movq mm6, [eax+48] - movq mm7, [eax+56] - sub ecx, 64 - add eax, 64 - cmp ecx, 64 - jl End8 - -Cmp8: - pxor mm0, [eax] - pxor mm1, [eax+8] - pxor mm2, [eax+16] - pxor mm3, [eax+24] - pxor mm4, [eax+32] - pxor mm5, [eax+40] - pxor mm6, [eax+48] - pxor mm7, [eax+56] - - sub ecx, 64 - add eax, 64 - cmp ecx, 64 - jge Cmp8 - -End8: - pxor mm0, mm4 - pxor mm1, mm5 - pxor mm2, mm6 - pxor mm3, mm7 - - cmp ecx, 32 - jl End4 - pxor mm0, [eax] - pxor mm1, [eax+8] - pxor mm2, [eax+16] - pxor mm3, [eax+24] - sub ecx, 32 - add eax, 32 - jmp End4 - -Setup4: - cmp ecx, 32 - jl Setup2 - - movq mm0, [eax] - movq mm1, [eax+8] - movq mm2, [eax+16] - movq mm3, [eax+24] - sub ecx, 32 - add eax, 32 - -End4: - pxor mm0, mm2 - pxor mm1, mm3 - - cmp ecx, 16 - jl End2 - pxor mm0, [eax] - pxor mm1, [eax+8] - sub ecx, 16 - add eax, 16 - jmp End2 - -Setup2: - cmp ecx, 16 - jl Setup1 - - movq mm0, [eax] - movq mm1, [eax+8] - sub ecx, 16 - add eax, 16 - -End2: - pxor mm0, mm1 - - cmp ecx, 8 - jl End1 - pxor mm0, [eax] -End1: - movq [edx], mm0 - jmp End - -Setup1: - movq mm0, [eax] - movq [edx], mm0 -End: - emms - } - FreezeMMXRegs(0); -} - -#endif +/****************************************************************************** + + Copyright (c) 2001 Advanced Micro Devices, Inc. + + LIMITATION OF LIABILITY: THE MATERIALS ARE PROVIDED *AS IS* WITHOUT ANY + EXPRESS OR IMPLIED WARRANTY OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, + NONINFRINGEMENT OF THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY + PARTICULAR PURPOSE. IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY + DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, + BUSINESS INTERRUPTION, LOSS OF INFORMATION) ARISING OUT OF THE USE OF OR + INABILITY TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY + OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE EXCLUSION OR LIMITATION + OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY + NOT APPLY TO YOU. + + AMD does not assume any responsibility for any errors which may appear in the + Materials nor any responsibility to support or update the Materials. AMD retains + the right to make changes to its test specifications at any time, without notice. + + NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any + further information, software, technical information, know-how, or show-how + available to you. + + So that all may benefit from your experience, please report any problems + or suggestions about this software to 3dsdk.support@amd.com + + AMD Developer Technologies, M/S 585 + Advanced Micro Devices, Inc. + 5900 E. Ben White Blvd. + Austin, TX 78741 + 3dsdk.support@amd.com +******************************************************************************/ + +#include "PrecompiledHeader.h" + +#ifdef _MSC_VER +#pragma warning(disable:4414) +#endif + +/***************************************************************************** +MEMCPY_AMD.CPP +******************************************************************************/ + +// Very optimized memcpy() routine for AMD Athlon and Duron family. +// This code uses any of FOUR different basic copy methods, depending +// on the transfer size. +// NOTE: Since this code uses MOVNTQ (also known as "Non-Temporal MOV" or +// "Streaming Store"), and also uses the software prefetch instructions, +// be sure you're running on Athlon/Duron or other recent CPU before calling! + +#define TINY_BLOCK_COPY 64 // upper limit for movsd type copy +// The smallest copy uses the X86 "movsd" instruction, in an optimized +// form which is an "unrolled loop". + +#define IN_CACHE_COPY 2 * 1024 // upper limit for movq/movq copy w/SW prefetch +// Next is a copy that uses the MMX registers to copy 8 bytes at a time, +// also using the "unrolled loop" optimization. This code uses +// the software prefetch instruction to get the data into the cache. + +#define UNCACHED_COPY 4 * 1024 // upper limit for movq/movntq w/SW prefetch +// For larger blocks, which will spill beyond the cache, it's faster to +// use the Streaming Store instruction MOVNTQ. This write instruction +// bypasses the cache and writes straight to main memory. This code also +// uses the software prefetch instruction to pre-read the data. +// USE 64 * 1024 FOR THIS VALUE IF YOU'RE ALWAYS FILLING A "CLEAN CACHE" + +#define BLOCK_PREFETCH_COPY infinity // no limit for movq/movntq w/block prefetch +#define CACHEBLOCK 80h // number of 64-byte blocks (cache lines) for block prefetch +// For the largest size blocks, a special technique called Block Prefetch +// can be used to accelerate the read operations. Block Prefetch reads +// one address per cache line, for a series of cache lines, in a short loop. +// This is faster than using software prefetch. The technique is great for +// getting maximum read bandwidth, especially in DDR memory systems. + +#include "Misc.h" + +// Inline assembly syntax for use with Visual C++ + +#if defined(_MSC_VER) + +#ifdef _DEBUG +extern u8 g_globalMMXSaved; + +void checkregs() +{ + if( g_EEFreezeRegs ) assert( g_globalMMXSaved ); +} +#endif + + +PCSX2_ALIGNED16( static u8 _xmm_backup[16*2] ); +PCSX2_ALIGNED16( static u8 _mmx_backup[8*4] ); + +static __declspec(naked) void __fastcall _memcpy_raz_usrc(void *dest, const void *src, size_t bytes) +{ + // MOVSRC = opcode used to read. I use the same code for the aligned version, with a different define :) + #define MOVSRC movdqu + #define MOVDST movdqa + + __asm + { + //Reads before reads, to avoid stalls + mov eax,[esp+4]; + //Make sure to save xmm0, it must be preserved ... + movaps [_xmm_backup],xmm0; + + //if >=128 bytes use 128 byte unrolled loop + //i use cmp ..,127 + jna because 127 is encodable using the simm8 form + cmp eax,127; + jna _loop_1; + + //since this is a common branch target it could be good to align it -- no idea if it has any effect :p + align 16 + + //128 byte unrolled loop +_loop_8: + + MOVSRC xmm0,[edx+0x00]; //read first to avoid read-after-write stalls + MOVDST [ecx+0x00],xmm0; //then write :p + MOVSRC xmm0,[edx+0x10]; + MOVDST [ecx+0x10],xmm0; + sub edx,-128; //edx won't be used for a while, so update it here. sub/-128 for simm8 encoding + sub ecx,-128; //ecx won't be used for a while, so update it here. sub/-128 for simm8 encoding + + MOVSRC xmm0,[edx+0x20-128]; + MOVDST [ecx+0x20-128],xmm0; + MOVSRC xmm0,[edx+0x30-128]; + MOVDST [ecx+0x30-128],xmm0; + add eax,-128; //eax won't be used for a while, so update it here. add/-128 for simm8 encoding + + MOVSRC xmm0,[edx+0x40-128]; + MOVDST [ecx+0x40-128],xmm0; + MOVSRC xmm0,[edx+0x50-128]; + MOVDST [ecx+0x50-128],xmm0; + + MOVSRC xmm0,[edx+0x60-128]; + MOVDST [ecx+0x60-128],xmm0; + MOVSRC xmm0,[edx+0x70-128]; + MOVDST [ecx+0x70-128],xmm0; + + //127~ja, 127 is encodable as simm8 :) + cmp eax,127; + ja _loop_8; + + //direct copy for 0~7 qwords + //in order to avoid the inc/dec of all 3 registers + //i use negative relative addressing from the top of the buffers + //[top-current index] + +_loop_1: + //prepare the regs for 'negative relative addressing' + add edx,eax; + add ecx,eax; + neg eax; + jz cleanup; //exit if nothing to do + +_loop_1_inner: + MOVSRC xmm0,[edx+eax]; + MOVDST [ecx+eax],xmm0; + + add eax,16; //while the offset is still negative we have data to copy + js _loop_1_inner; + + //done ! +cleanup: + //restore xmm and exit ~) + movaps xmm0,[_xmm_backup]; + ret 4; + } + #undef MOVSRC + #undef MOVDST +} + + +static __declspec(naked) void __fastcall _memcpy_raz_udst(void *dest, const void *src, size_t bytes) +{ + // MOVDST = opcode used to read. I use the same code for the aligned version, with a different define :) + #define MOVSRC movaps + #define MOVDST movups + __asm + { + //Reads before reads, to avoid stalls + mov eax,[esp+4]; + //Make sure to save xmm0, it must be preserved ... + movaps [_xmm_backup],xmm0; + + //if >=128 bytes use 128 byte unrolled loop + //i use cmp ..,127 + jna because 127 is encodable using the simm8 form + cmp eax,127; + jna _loop_1; + + //since this is a common branch target it could be good to align it -- no idea if it has any effect :p + align 16 + + //128 byte unrolled loop +_loop_8: + + MOVSRC xmm0,[edx+0x00]; //read first to avoid read-after-write stalls + MOVDST [ecx+0x00],xmm0; //then write :p + MOVSRC xmm0,[edx+0x10]; + MOVDST [ecx+0x10],xmm0; + sub edx,-128; //edx won't be used for a while, so update it here. sub/-128 for simm8 encoding + sub ecx,-128; //ecx won't be used for a while, so update it here. sub/-128 for simm8 encoding + + MOVSRC xmm0,[edx+0x20-128]; + MOVDST [ecx+0x20-128],xmm0; + MOVSRC xmm0,[edx+0x30-128]; + MOVDST [ecx+0x30-128],xmm0; + add eax,-128; //eax won't be used for a while, so update it here. add/-128 for simm8 encoding + + MOVSRC xmm0,[edx+0x40-128]; + MOVDST [ecx+0x40-128],xmm0; + MOVSRC xmm0,[edx+0x50-128]; + MOVDST [ecx+0x50-128],xmm0; + + MOVSRC xmm0,[edx+0x60-128]; + MOVDST [ecx+0x60-128],xmm0; + MOVSRC xmm0,[edx+0x70-128]; + MOVDST [ecx+0x70-128],xmm0; + + //127~ja, 127 is encodable as simm8 :) + cmp eax,127; + ja _loop_8; + + //direct copy for 0~7 qwords + //in order to avoid the inc/dec of all 3 registers + //i use negative relative addressing from the top of the buffers + //[top-current index] + +_loop_1: + //prepare the regs for 'negative relative addressing' + add edx,eax; + add ecx,eax; + neg eax; + jz cleanup; //exit if nothing to do + +_loop_1_inner: + MOVSRC xmm0,[edx+eax]; + movaps [ecx+eax],xmm0; + + add eax,16; //while the offset is still negative we have data to copy + js _loop_1_inner; + + //done ! +cleanup: + //restore xmm and exit ~) + movaps xmm0,[_xmm_backup]; + ret 4; + } + #undef MOVSRC + #undef MOVDST +} + +// Custom memcpy, only for 16 byte aligned stuff (used for mtgs) +// This function is optimized for medium-small transfer sizes (<2048, >=128). No prefetching is +// used since the reads are linear and the cache logic can predict em :) +// *OBSOLETE* -- memcpy_amd_ has been optimized and is now faster. +__declspec(naked) void __fastcall memcpy_raz_(void *dest, const void *src, size_t bytes) +{ + // Code Implementation Notes: + // Uses a forward copy, in 128 byte blocks, and then does the remaining in 16 byte blocks :) + + // MOVSRC = opcode used to read. I use the same code for the unaligned version, with a different define :) + #define MOVSRC movaps + #define MOVDST movaps + __asm + { + //Reads before reads, to avoid stalls + mov eax,[esp+4]; + //Make sure to save xmm0, it must be preserved ... + movaps [_xmm_backup],xmm0; + + //if >=128 bytes use 128 byte unrolled loop + //i use cmp ..,127 + jna because 127 is encodable using the simm8 form + cmp eax,127; + jna _loop_1; + + //since this is a common branch target it could be good to align it -- no idea if it has any effect :p + align 16 + + //128 byte unrolled loop +_loop_8: + + MOVSRC xmm0,[edx+0x00]; //read first to avoid read-after-write stalls + MOVDST [ecx+0x00],xmm0; //then write :p + MOVSRC xmm0,[edx+0x10]; + MOVDST [ecx+0x10],xmm0; + sub edx,-128; //edx won't be used for a while, so update it here. sub/-128 for simm8 encoding + sub ecx,-128; //ecx won't be used for a while, so update it here. sub/-128 for simm8 encoding + + MOVSRC xmm0,[edx+0x20-128]; + MOVDST [ecx+0x20-128],xmm0; + MOVSRC xmm0,[edx+0x30-128]; + MOVDST [ecx+0x30-128],xmm0; + add eax,-128; //eax won't be used for a while, so update it here. add/-128 for simm8 encoding + + MOVSRC xmm0,[edx+0x40-128]; + MOVDST [ecx+0x40-128],xmm0; + MOVSRC xmm0,[edx+0x50-128]; + MOVDST [ecx+0x50-128],xmm0; + + MOVSRC xmm0,[edx+0x60-128]; + MOVDST [ecx+0x60-128],xmm0; + MOVSRC xmm0,[edx+0x70-128]; + MOVDST [ecx+0x70-128],xmm0; + + //127~ja, 127 is encodable as simm8 :) + cmp eax,127; + ja _loop_8; + + //direct copy for 0~7 qwords + //in order to avoid the inc/dec of all 3 registers + //i use negative relative addressing from the top of the buffers + //[top-current index] + +_loop_1: + //prepare the regs for 'negative relative addressing' + add edx,eax; + add ecx,eax; + neg eax; + jz cleanup; //exit if nothing to do + +_loop_1_inner: + MOVSRC xmm0,[edx+eax]; + MOVDST [ecx+eax],xmm0; + + add eax,16; //while the offset is still negative we have data to copy + js _loop_1_inner; + + //done ! +cleanup: + //restore xmm and exit ~) + movaps xmm0,[_xmm_backup]; + ret 4; + } + #undef MOVSRC + #undef MOVDST +} + +// This memcpy routine is for use in situations where the source buffer's alignment is indeterminate. +__forceinline void __fastcall memcpy_raz_usrc(void *dest, const void *src, size_t bytes) +{ + if( ((uptr)src & 0xf) == 0 ) + memcpy_raz_( dest, src, bytes ); + else + _memcpy_raz_usrc( dest, src, bytes ); +} + +// This memcpy routine is for use in situations where the destination buffer's alignment is indeterminate. +__forceinline void __fastcall memcpy_raz_udst(void *dest, const void *src, size_t bytes) +{ + if( ((uptr)dest & 0xf) == 0 ) + memcpy_raz_( dest, src, bytes ); + else + _memcpy_raz_udst( dest, src, bytes ); +} + + +////////////////////////////////////////////////////////////////////////// +// Fast memcpy as coded by AMD, and thn improved by air. +// +// This routine preserves mmx registers! It's the complete real deal! +__declspec(naked) void __fastcall memcpy_amd_(void *dest, const void *src, size_t n) +{ + __asm + { + push edi + push esi + + mov edi, ecx ; destination + mov esi, edx ; source + mov ecx, [esp+12] ; number of bytes to copy + mov eax, ecx ; keep a copy of count + + cld + cmp eax, TINY_BLOCK_COPY + jb $memcpy_ic_3 ; tiny? skip mmx copy + + cmp eax, 32*1024 ; don't align between 32k-64k because + jbe $memcpy_do_align ; it appears to be slower + cmp eax, 64*1024 + jbe $memcpy_align_done +$memcpy_do_align: + mov eax, 8 ; a trick that's faster than rep movsb... + sub eax, edi ; align destination to qword + and eax, 111b ; get the low bits + sub ecx, eax ; update copy count + neg eax ; set up to jump into the array + add eax, offset $memcpy_align_done + jmp eax ; jump to array of movsb's + +align 4 + movsb + movsb + movsb + movsb + movsb + movsb + movsb + movsb + +$memcpy_align_done: ; destination is dword aligned + mov eax, ecx ; number of bytes left to copy + shr eax, 6 ; get 64-byte block count + jz $memcpy_ic_2 ; finish the last few bytes + + cmp eax, IN_CACHE_COPY/64 ; too big 4 cache? use uncached copy + jae $memcpy_uc_test + + movq [_mmx_backup+0x00],mm0 + movq [_mmx_backup+0x08],mm1 + movq [_mmx_backup+0x10],mm2 + movq [_mmx_backup+0x18],mm3 + +// This is small block copy that uses the MMX registers to copy 8 bytes +// at a time. It uses the "unrolled loop" optimization, and also uses +// the software prefetch instruction to get the data into the cache. +align 16 +$memcpy_ic_1: ; 64-byte block copies, in-cache copy + + prefetchnta [esi + (200*64/34+192)] ; start reading ahead + + movq mm0, [esi+0] ; read 64 bits + movq mm1, [esi+8] + movq [edi+0], mm0 ; write 64 bits + movq [edi+8], mm1 ; note: the normal movq writes the + movq mm2, [esi+16] ; data to cache; a cache line will be + movq mm3, [esi+24] ; allocated as needed, to store the data + movq [edi+16], mm2 + movq [edi+24], mm3 + movq mm0, [esi+32] + movq mm1, [esi+40] + movq [edi+32], mm0 + movq [edi+40], mm1 + movq mm2, [esi+48] + movq mm3, [esi+56] + movq [edi+48], mm2 + movq [edi+56], mm3 + + add esi, 64 ; update source pointer + add edi, 64 ; update destination pointer + dec eax ; count down + jnz $memcpy_ic_1 ; last 64-byte block? + + movq mm0,[_mmx_backup+0x00] + movq mm1,[_mmx_backup+0x08] + movq mm2,[_mmx_backup+0x10] + movq mm3,[_mmx_backup+0x18] + +$memcpy_ic_2: + mov eax, ecx ; has valid low 6 bits of the byte count +$memcpy_ic_3: + shr eax, 2 ; dword count + and eax, 1111b ; only look at the "remainder" bits + neg eax ; set up to jump into the array + add eax, offset $memcpy_last_few + jmp eax ; jump to array of movsd's + +$memcpy_uc_test: + /*cmp ecx, UNCACHED_COPY/64 ; big enough? use block prefetch copy + jae $memcpy_bp_1 +$memcpy_64_test:*/ + or eax, eax ; tail end of block prefetch will jump here + jz $memcpy_ic_2 ; no more 64-byte blocks left + +// For larger blocks, which will spill beyond the cache, it's faster to +// use the Streaming Store instruction MOVNTQ. This write instruction +// bypasses the cache and writes straight to main memory. This code also +// uses the software prefetch instruction to pre-read the data. + + movq [_mmx_backup+0x00],mm0 + movq [_mmx_backup+0x08],mm1 + movq [_mmx_backup+0x10],mm2 + +align 16 +$memcpy_uc_1: ; 64-byte blocks, uncached copy + + prefetchnta [esi + (200*64/34+192)] ; start reading ahead + + movq mm0,[esi+0] ; read 64 bits + add edi,64 ; update destination pointer + movq mm1,[esi+8] + add esi,64 ; update source pointer + movq mm2,[esi-48] + movntq [edi-64], mm0 ; write 64 bits, bypassing the cache + movq mm0,[esi-40] ; note: movntq also prevents the CPU + movntq [edi-56], mm1 ; from READING the destination address + movq mm1,[esi-32] ; into the cache, only to be over-written + movntq [edi-48], mm2 ; so that also helps performance + movq mm2,[esi-24] + movntq [edi-40], mm0 + movq mm0,[esi-16] + movntq [edi-32], mm1 + movq mm1,[esi-8] + movntq [edi-24], mm2 + movntq [edi-16], mm0 + dec eax + movntq [edi-8], mm1 + jnz $memcpy_uc_1 ; last 64-byte block? + + movq mm0,[_mmx_backup+0x00] + movq mm1,[_mmx_backup+0x08] + movq mm2,[_mmx_backup+0x10] + + jmp $memcpy_ic_2 ; almost done (not needed because large copy below was removed) + +// For the largest size blocks, a special technique called Block Prefetch +// can be used to accelerate the read operations. Block Prefetch reads +// one address per cache line, for a series of cache lines, in a short loop. +// This is faster than using software prefetch. The technique is great for +// getting maximum read bandwidth, especially in DDR memory systems. + +// Note: Pcsx2 rarely invokes large copies, so this mode has been disabled to +// help keep the code cache footprint of memcpy_fast to a minimum. +/* +$memcpy_bp_1: ; large blocks, block prefetch copy + + cmp ecx, CACHEBLOCK ; big enough to run another prefetch loop? + jl $memcpy_64_test ; no, back to regular uncached copy + + mov eax, CACHEBLOCK / 2 ; block prefetch loop, unrolled 2X + add esi, CACHEBLOCK * 64 ; move to the top of the block +align 16 +$memcpy_bp_2: + mov edx, [esi-64] ; grab one address per cache line + mov edx, [esi-128] ; grab one address per cache line + sub esi, 128 ; go reverse order to suppress HW prefetcher + dec eax ; count down the cache lines + jnz $memcpy_bp_2 ; keep grabbing more lines into cache + + mov eax, CACHEBLOCK ; now that it's in cache, do the copy +align 16 +$memcpy_bp_3: + movq mm0, [esi ] ; read 64 bits + movq mm1, [esi+ 8] + movq mm2, [esi+16] + movq mm3, [esi+24] + movq mm4, [esi+32] + movq mm5, [esi+40] + movq mm6, [esi+48] + movq mm7, [esi+56] + add esi, 64 ; update source pointer + movntq [edi ], mm0 ; write 64 bits, bypassing cache + movntq [edi+ 8], mm1 ; note: movntq also prevents the CPU + movntq [edi+16], mm2 ; from READING the destination address + movntq [edi+24], mm3 ; into the cache, only to be over-written, + movntq [edi+32], mm4 ; so that also helps performance + movntq [edi+40], mm5 + movntq [edi+48], mm6 + movntq [edi+56], mm7 + add edi, 64 ; update dest pointer + + dec eax ; count down + + jnz $memcpy_bp_3 ; keep copying + sub ecx, CACHEBLOCK ; update the 64-byte block count + jmp $memcpy_bp_1 ; keep processing chunks +*/ + +// The smallest copy uses the X86 "movsd" instruction, in an optimized +// form which is an "unrolled loop". Then it handles the last few bytes. +align 4 + movsd + movsd ; perform last 1-15 dword copies + movsd + movsd + movsd + movsd + movsd + movsd + movsd + movsd ; perform last 1-7 dword copies + movsd + movsd + movsd + movsd + movsd + movsd + +$memcpy_last_few: ; dword aligned from before movsd's + mov eax, ecx ; has valid low 2 bits of the byte count + and eax, 11b ; the last few cows must come home + jz $memcpy_final ; no more, let's leave + rep movsb ; the last 1, 2, or 3 bytes + +$memcpy_final: + emms ; clean up the MMX state + sfence ; flush the write buffer + //mov eax, [dest] ; ret value = destination pointer + + pop esi + pop edi + + ret 4 + } +} + +// mmx mem-compare implementation, size has to be a multiple of 8 +// returns 0 is equal, nonzero value if not equal +// ~10 times faster than standard memcmp +// (zerofrog) +u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) +{ + assert( (cmpsize&7) == 0 ); + + __asm { + push esi + mov ecx, cmpsize + mov edx, src1 + mov esi, src2 + + cmp ecx, 32 + jl Done4 + + // custom test first 8 to make sure things are ok + movq mm0, [esi] + movq mm1, [esi+8] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pand mm0, mm1 + movq mm2, [esi+16] + pmovmskb eax, mm0 + movq mm3, [esi+24] + + // check if eq + cmp eax, 0xff + je NextComp + mov eax, 1 + jmp End + +NextComp: + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm2, mm3 + pmovmskb eax, mm2 + + sub ecx, 32 + add esi, 32 + add edx, 32 + + // check if eq + cmp eax, 0xff + je ContinueTest + mov eax, 1 + jmp End + + cmp ecx, 64 + jl Done8 + +Cmp8: + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + movq mm3, [esi+24] + movq mm4, [esi+32] + movq mm5, [esi+40] + movq mm6, [esi+48] + movq mm7, [esi+56] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm0, mm1 + pcmpeqd mm4, [edx+32] + pand mm0, mm2 + pcmpeqd mm5, [edx+40] + pand mm0, mm3 + pcmpeqd mm6, [edx+48] + pand mm0, mm4 + pcmpeqd mm7, [edx+56] + pand mm0, mm5 + pand mm0, mm6 + pand mm0, mm7 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + je Continue + mov eax, 1 + jmp End + +Continue: + sub ecx, 64 + add esi, 64 + add edx, 64 +ContinueTest: + cmp ecx, 64 + jge Cmp8 + +Done8: + test ecx, 0x20 + jz Done4 + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + movq mm3, [esi+24] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm0, mm1 + pand mm0, mm2 + pand mm0, mm3 + pmovmskb eax, mm0 + sub ecx, 32 + add esi, 32 + add edx, 32 + + // check if eq + cmp eax, 0xff + je Done4 + mov eax, 1 + jmp End + +Done4: + cmp ecx, 24 + jne Done2 + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pand mm0, mm1 + pand mm0, mm2 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + setne al + jmp End + +Done2: + cmp ecx, 16 + jne Done1 + + movq mm0, [esi] + movq mm1, [esi+8] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pand mm0, mm1 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + setne al + jmp End + +Done1: + cmp ecx, 8 + jne Done + + mov eax, [esi] + mov esi, [esi+4] + cmp eax, [edx] + je Next + mov eax, 1 + jmp End + +Next: + cmp esi, [edx+4] + setne al + jmp End + +Done: + xor eax, eax + +End: + pop esi + emms + } +} + + +// returns the xor of all elements, cmpsize has to be mult of 8 +void memxor_mmx(void* dst, const void* src1, int cmpsize) +{ + FreezeMMXRegs(1); + assert( (cmpsize&7) == 0 ); + + __asm { + mov ecx, cmpsize + mov eax, src1 + mov edx, dst + + cmp ecx, 64 + jl Setup4 + + movq mm0, [eax] + movq mm1, [eax+8] + movq mm2, [eax+16] + movq mm3, [eax+24] + movq mm4, [eax+32] + movq mm5, [eax+40] + movq mm6, [eax+48] + movq mm7, [eax+56] + sub ecx, 64 + add eax, 64 + cmp ecx, 64 + jl End8 + +Cmp8: + pxor mm0, [eax] + pxor mm1, [eax+8] + pxor mm2, [eax+16] + pxor mm3, [eax+24] + pxor mm4, [eax+32] + pxor mm5, [eax+40] + pxor mm6, [eax+48] + pxor mm7, [eax+56] + + sub ecx, 64 + add eax, 64 + cmp ecx, 64 + jge Cmp8 + +End8: + pxor mm0, mm4 + pxor mm1, mm5 + pxor mm2, mm6 + pxor mm3, mm7 + + cmp ecx, 32 + jl End4 + pxor mm0, [eax] + pxor mm1, [eax+8] + pxor mm2, [eax+16] + pxor mm3, [eax+24] + sub ecx, 32 + add eax, 32 + jmp End4 + +Setup4: + cmp ecx, 32 + jl Setup2 + + movq mm0, [eax] + movq mm1, [eax+8] + movq mm2, [eax+16] + movq mm3, [eax+24] + sub ecx, 32 + add eax, 32 + +End4: + pxor mm0, mm2 + pxor mm1, mm3 + + cmp ecx, 16 + jl End2 + pxor mm0, [eax] + pxor mm1, [eax+8] + sub ecx, 16 + add eax, 16 + jmp End2 + +Setup2: + cmp ecx, 16 + jl Setup1 + + movq mm0, [eax] + movq mm1, [eax+8] + sub ecx, 16 + add eax, 16 + +End2: + pxor mm0, mm1 + + cmp ecx, 8 + jl End1 + pxor mm0, [eax] +End1: + movq [edx], mm0 + jmp End + +Setup1: + movq mm0, [eax] + movq [edx], mm0 +End: + emms + } + FreezeMMXRegs(0); +} + +#endif diff --git a/pcsx2/x86/iCOP0.cpp b/pcsx2/x86/iCOP0.cpp index 99a46aec79..d634dbc059 100644 --- a/pcsx2/x86/iCOP0.cpp +++ b/pcsx2/x86/iCOP0.cpp @@ -1,404 +1,404 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -// Important Note to Future Developers: -// None of the COP0 instructions are really critical performance items, -// so don't waste time converting any more them into recompiled code -// unless it can make them nicely compact. Calling the C versions will -// suffice. - -#include "PrecompiledHeader.h" - -#include "Common.h" -#include "R5900OpcodeTables.h" -#include "ix86/ix86.h" -#include "iR5900.h" -#include "iCOP0.h" - -namespace Interp = R5900::Interpreter::OpcodeImpl::COP0; - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl { -namespace COP0 { - -/********************************************************* -* COP0 opcodes * -* * -*********************************************************/ - -// emits "setup" code for a COP0 branch test. The instruction immediately following -// this should be a conditional Jump -- JZ or JNZ normally. -static void _setupBranchTest() -{ - _eeFlushAllUnused(); - - // COP0 branch conditionals are based on the following equation: - // (((psHu16(DMAC_STAT) & psHu16(DMAC_PCR)) & 0x3ff) == (psHu16(DMAC_PCR) & 0x3ff)) - // BC0F checks if the statement is false, BC0T checks if the statement is true. - - // note: We only want to compare the 16 bit values of DMAC_STAT and PCR. - // But using 32-bit loads here is ok (and faster), because we mask off - // everything except the lower 10 bits away. - - MOV32MtoR( EAX, (uptr)&psHu32(DMAC_STAT) ); - XOR32MtoR( EAX, (uptr)&psHu32(DMAC_PCR) ); - AND32ItoR( EAX, 0x3ff ); -} - -void recBC0F() -{ - _setupBranchTest(); - recDoBranchImm(JNZ32(0)); -} - -void recBC0T() -{ - _setupBranchTest(); - recDoBranchImm(JZ32(0)); -} - -void recBC0FL() -{ - _setupBranchTest(); - recDoBranchImm_Likely(JNZ32(0)); -} - -void recBC0TL() -{ - _setupBranchTest(); - recDoBranchImm_Likely(JZ32(0)); -} - -void recTLBR() { recCall( Interp::TLBR, -1 ); } -void recTLBP() { recCall( Interp::TLBP, -1 ); } -void recTLBWI() { recCall( Interp::TLBWI, -1 ); } -void recTLBWR() { recCall( Interp::TLBWR, -1 ); } - -void recERET() -{ - recBranchCall( Interp::ERET ); -} - -void recEI() -{ - // must branch after enabling interrupts, so that anything - // pending gets triggered properly. - recBranchCall( Interp::EI ); -} - -void recDI() -{ - // No need to branch after disabling interrupts... - - iFlushCall(0); - - MOV32MtoR( EAX, (uptr)&cpuRegs.cycle ); - MOV32RtoM( (uptr)&g_nextBranchCycle, EAX ); - - CALLFunc( (uptr)Interp::DI ); -} - - -#ifndef CP0_RECOMPILE - -REC_SYS( MFC0 ); -REC_SYS( MTC0 ); - -#else - -void recMFC0( void ) -{ - int mmreg; - - if ( ! _Rt_ ) return; - - if( _Rd_ == 9 ) { - MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); - MOV32RtoR(EAX,ECX); - SUB32MtoR(EAX, (uptr)&s_iLastCOP0Cycle); - ADD32RtoM((uptr)&cpuRegs.CP0.n.Count, EAX); - MOV32RtoM((uptr)&s_iLastCOP0Cycle, ECX); - MOV32MtoR( EAX, (uptr)&cpuRegs.CP0.r[ _Rd_ ] ); - - _deleteEEreg(_Rt_, 0); - MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0],EAX); - - if(EEINST_ISLIVE1(_Rt_)) { - CDQ(); - MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[1], EDX); - } - else EEINST_RESETHASLIVE1(_Rt_); - return; - } - if( _Rd_ == 25 ) { - - _deleteEEreg(_Rt_, 0); - switch(_Imm_ & 0x3F){ - case 0: - MOV32MtoR(EAX, (uptr)&cpuRegs.PERF.n.pccr); - - break; - case 1: - // check if needs to be incremented - MOV32MtoR(ECX, (uptr)&cpuRegs.PERF.n.pccr); - MOV32MtoR(EAX, (uptr)&cpuRegs.PERF.n.pcr0); - AND32ItoR(ECX, 0x800003E0); - - CMP32ItoR(ECX, 0x80000020); - j8Ptr[0] = JNE8(0); - - MOV32MtoR(EDX, (uptr)&cpuRegs.cycle); - SUB32MtoR(EAX, (uptr)&s_iLastPERFCycle[0]); - ADD32RtoR(EAX, EDX); - MOV32RtoM((uptr)&s_iLastPERFCycle[0], EDX); - MOV32RtoM((uptr)&cpuRegs.PERF.n.pcr0, EAX); - - x86SetJ8(j8Ptr[0]); - break; - case 3: - // check if needs to be incremented - MOV32MtoR(ECX, (uptr)&cpuRegs.PERF.n.pccr); - MOV32MtoR(EAX, (uptr)&cpuRegs.PERF.n.pcr1); - AND32ItoR(ECX, 0x800F8000); - - CMP32ItoR(ECX, 0x80008000); - j8Ptr[0] = JNE8(0); - - MOV32MtoR(EDX, (uptr)&cpuRegs.cycle); - SUB32MtoR(EAX, (uptr)&s_iLastPERFCycle[1]); - ADD32RtoR(EAX, EDX); - MOV32RtoM((uptr)&s_iLastPERFCycle[1], EDX); - MOV32RtoM((uptr)&cpuRegs.PERF.n.pcr1, EAX); - - x86SetJ8(j8Ptr[0]); - - break; - } - - MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0],EAX); - - if(EEINST_ISLIVE1(_Rt_)) { - CDQ(); - MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[1], EDX); - } - else EEINST_RESETHASLIVE1(_Rt_); - -#ifdef PCSX2_DEVBUILD - COP0_LOG("MFC0 PCCR = %x PCR0 = %x PCR1 = %x IMM= %x\n", - cpuRegs.PERF.n.pccr, cpuRegs.PERF.n.pcr0, cpuRegs.PERF.n.pcr1, _Imm_ & 0x3F); -#endif - return; - } - else if( _Rd_ == 24){ - COP0_LOG("MFC0 Breakpoint debug Registers code = %x\n", cpuRegs.code & 0x3FF); - return; - } - _eeOnWriteReg(_Rt_, 1); - - if( EEINST_ISLIVE1(_Rt_) ) { - _deleteEEreg(_Rt_, 0); - MOV32MtoR(EAX, (uptr)&cpuRegs.CP0.r[ _Rd_ ]); - CDQ(); - MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0], EAX); - MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[1], EDX); - } - else { - EEINST_RESETHASLIVE1(_Rt_); - - if( (mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE)) >= 0 ) { - MOVDMtoMMX(mmreg, (uptr)&cpuRegs.CP0.r[ _Rd_ ]); - SetMMXstate(); - } - else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ)) >= 0) { - - if( EEINST_ISLIVE2(_Rt_) ) { - if( xmmregs[mmreg].mode & MODE_WRITE ) { - SSE_MOVHPS_XMM_to_M64((uptr)&cpuRegs.GPR.r[_Rt_].UL[2], mmreg); - } - xmmregs[mmreg].inuse = 0; - - MOV32MtoR(EAX, (uptr)&cpuRegs.CP0.r[ _Rd_ ]); - MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0],EAX); - } - else { - SSE_MOVLPS_M64_to_XMM(mmreg, (uptr)&cpuRegs.CP0.r[ _Rd_ ]); - } - } - else { - MOV32MtoR(EAX, (uptr)&cpuRegs.CP0.r[ _Rd_ ]); - if(_Rd_ == 12) AND32ItoR(EAX, 0xf0c79c1f); - MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0],EAX); - if(EEINST_ISLIVE1(_Rt_)) { - CDQ(); - MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[1], EDX); - } - else { - EEINST_RESETHASLIVE1(_Rt_); - } - } - } -} - -void updatePCCR() -{ - // read the old pccr and update pcr0/1 - MOV32MtoR(EAX, (uptr)&cpuRegs.PERF.n.pccr); - MOV32RtoR(EDX, EAX); - MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); - - AND32ItoR(EAX, 0x800003E0); - CMP32ItoR(EAX, 0x80000020); - j8Ptr[0] = JNE8(0); - MOV32MtoR(EAX, (uptr)&s_iLastPERFCycle[0]); - ADD32RtoM((uptr)&cpuRegs.PERF.n.pcr0, ECX); - SUB32RtoM((uptr)&cpuRegs.PERF.n.pcr0, EAX); - x86SetJ8(j8Ptr[0]); - - AND32ItoR(EDX, 0x800F8000); - CMP32ItoR(EDX, 0x80008000); - j8Ptr[0] = JNE8(0); - MOV32MtoR(EAX, (uptr)&s_iLastPERFCycle[1]); - ADD32RtoM((uptr)&cpuRegs.PERF.n.pcr1, ECX); - SUB32RtoM((uptr)&cpuRegs.PERF.n.pcr1, EAX); - x86SetJ8(j8Ptr[0]); -} - -void recMTC0() -{ - if( GPR_IS_CONST1(_Rt_) ) { - switch (_Rd_) { - case 12: - iFlushCall(FLUSH_NODESTROY); - //_flushCachedRegs(); //NOTE: necessary? - _callFunctionArg1((uptr)WriteCP0Status, MEM_CONSTTAG, g_cpuConstRegs[_Rt_].UL[0]); - break; - case 9: - MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); - MOV32RtoM((uptr)&s_iLastCOP0Cycle, ECX); - MOV32ItoM((uptr)&cpuRegs.CP0.r[9], g_cpuConstRegs[_Rt_].UL[0]); - break; - case 25: - COP0_LOG("MTC0 PCCR = %x PCR0 = %x PCR1 = %x IMM= %x\n", - cpuRegs.PERF.n.pccr, cpuRegs.PERF.n.pcr0, cpuRegs.PERF.n.pcr1, _Imm_ & 0x3F); - switch(_Imm_ & 0x3F){ - case 0: - - updatePCCR(); - MOV32ItoM((uptr)&cpuRegs.PERF.n.pccr, g_cpuConstRegs[_Rt_].UL[0]); - - // update the cycles - MOV32RtoM((uptr)&s_iLastPERFCycle[0], ECX); - MOV32RtoM((uptr)&s_iLastPERFCycle[1], ECX); - break; - case 1: - MOV32MtoR(EAX, (uptr)&cpuRegs.cycle); - MOV32ItoM((uptr)&cpuRegs.PERF.n.pcr0, g_cpuConstRegs[_Rt_].UL[0]); - MOV32RtoM((uptr)&s_iLastPERFCycle[0], EAX); - break; - case 3: - MOV32MtoR(EAX, (uptr)&cpuRegs.cycle); - MOV32ItoM((uptr)&cpuRegs.PERF.n.pcr1, g_cpuConstRegs[_Rt_].UL[0]); - MOV32RtoM((uptr)&s_iLastPERFCycle[1], EAX); - break; - } - break; - case 24: - COP0_LOG("MTC0 Breakpoint debug Registers code = %x\n", cpuRegs.code & 0x3FF); - break; - default: - MOV32ItoM((uptr)&cpuRegs.CP0.r[_Rd_], g_cpuConstRegs[_Rt_].UL[0]); - break; - } - } - else { - switch (_Rd_) { - case 12: - iFlushCall(FLUSH_NODESTROY); - //_flushCachedRegs(); //NOTE: necessary? - _callFunctionArg1((uptr)WriteCP0Status, MEM_GPRTAG|_Rt_, 0); - break; - case 9: - MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); - _eeMoveGPRtoM((uptr)&cpuRegs.CP0.r[9], _Rt_); - MOV32RtoM((uptr)&s_iLastCOP0Cycle, ECX); - break; - case 25: - COP0_LOG("MTC0 PCCR = %x PCR0 = %x PCR1 = %x IMM= %x\n", - cpuRegs.PERF.n.pccr, cpuRegs.PERF.n.pcr0, cpuRegs.PERF.n.pcr1, _Imm_ & 0x3F); - switch(_Imm_ & 0x3F){ - case 0: - updatePCCR(); - _eeMoveGPRtoM((uptr)&cpuRegs.PERF.n.pccr, _Rt_); - - // update the cycles - MOV32RtoM((uptr)&s_iLastPERFCycle[0], ECX); - MOV32RtoM((uptr)&s_iLastPERFCycle[1], ECX); - break; - case 1: - MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); - _eeMoveGPRtoM((uptr)&cpuRegs.PERF.n.pcr0, _Rt_); - MOV32RtoM((uptr)&s_iLastPERFCycle[0], ECX); - break; - case 3: - MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); - _eeMoveGPRtoM((uptr)&cpuRegs.PERF.n.pcr1, _Rt_); - MOV32RtoM((uptr)&s_iLastPERFCycle[1], ECX); - break; - } - break; - case 24: - COP0_LOG("MTC0 Breakpoint debug Registers code = %x\n", cpuRegs.code & 0x3FF); - break; - default: - _eeMoveGPRtoM((uptr)&cpuRegs.CP0.r[_Rd_], _Rt_); - break; - } - } -} -#endif - - -/*void rec(COP0) { -} - -void rec(BC0F) { -} - -void rec(BC0T) { -} - -void rec(BC0FL) { -} - -void rec(BC0TL) { -} - -void rec(TLBR) { -} - -void rec(TLBWI) { -} - -void rec(TLBWR) { -} - -void rec(TLBP) { -}*/ - -}}}} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +// Important Note to Future Developers: +// None of the COP0 instructions are really critical performance items, +// so don't waste time converting any more them into recompiled code +// unless it can make them nicely compact. Calling the C versions will +// suffice. + +#include "PrecompiledHeader.h" + +#include "Common.h" +#include "R5900OpcodeTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "iCOP0.h" + +namespace Interp = R5900::Interpreter::OpcodeImpl::COP0; + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl { +namespace COP0 { + +/********************************************************* +* COP0 opcodes * +* * +*********************************************************/ + +// emits "setup" code for a COP0 branch test. The instruction immediately following +// this should be a conditional Jump -- JZ or JNZ normally. +static void _setupBranchTest() +{ + _eeFlushAllUnused(); + + // COP0 branch conditionals are based on the following equation: + // (((psHu16(DMAC_STAT) & psHu16(DMAC_PCR)) & 0x3ff) == (psHu16(DMAC_PCR) & 0x3ff)) + // BC0F checks if the statement is false, BC0T checks if the statement is true. + + // note: We only want to compare the 16 bit values of DMAC_STAT and PCR. + // But using 32-bit loads here is ok (and faster), because we mask off + // everything except the lower 10 bits away. + + MOV32MtoR( EAX, (uptr)&psHu32(DMAC_STAT) ); + XOR32MtoR( EAX, (uptr)&psHu32(DMAC_PCR) ); + AND32ItoR( EAX, 0x3ff ); +} + +void recBC0F() +{ + _setupBranchTest(); + recDoBranchImm(JNZ32(0)); +} + +void recBC0T() +{ + _setupBranchTest(); + recDoBranchImm(JZ32(0)); +} + +void recBC0FL() +{ + _setupBranchTest(); + recDoBranchImm_Likely(JNZ32(0)); +} + +void recBC0TL() +{ + _setupBranchTest(); + recDoBranchImm_Likely(JZ32(0)); +} + +void recTLBR() { recCall( Interp::TLBR, -1 ); } +void recTLBP() { recCall( Interp::TLBP, -1 ); } +void recTLBWI() { recCall( Interp::TLBWI, -1 ); } +void recTLBWR() { recCall( Interp::TLBWR, -1 ); } + +void recERET() +{ + recBranchCall( Interp::ERET ); +} + +void recEI() +{ + // must branch after enabling interrupts, so that anything + // pending gets triggered properly. + recBranchCall( Interp::EI ); +} + +void recDI() +{ + // No need to branch after disabling interrupts... + + iFlushCall(0); + + MOV32MtoR( EAX, (uptr)&cpuRegs.cycle ); + MOV32RtoM( (uptr)&g_nextBranchCycle, EAX ); + + CALLFunc( (uptr)Interp::DI ); +} + + +#ifndef CP0_RECOMPILE + +REC_SYS( MFC0 ); +REC_SYS( MTC0 ); + +#else + +void recMFC0( void ) +{ + int mmreg; + + if ( ! _Rt_ ) return; + + if( _Rd_ == 9 ) { + MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); + MOV32RtoR(EAX,ECX); + SUB32MtoR(EAX, (uptr)&s_iLastCOP0Cycle); + ADD32RtoM((uptr)&cpuRegs.CP0.n.Count, EAX); + MOV32RtoM((uptr)&s_iLastCOP0Cycle, ECX); + MOV32MtoR( EAX, (uptr)&cpuRegs.CP0.r[ _Rd_ ] ); + + _deleteEEreg(_Rt_, 0); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0],EAX); + + if(EEINST_ISLIVE1(_Rt_)) { + CDQ(); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[1], EDX); + } + else EEINST_RESETHASLIVE1(_Rt_); + return; + } + if( _Rd_ == 25 ) { + + _deleteEEreg(_Rt_, 0); + switch(_Imm_ & 0x3F){ + case 0: + MOV32MtoR(EAX, (uptr)&cpuRegs.PERF.n.pccr); + + break; + case 1: + // check if needs to be incremented + MOV32MtoR(ECX, (uptr)&cpuRegs.PERF.n.pccr); + MOV32MtoR(EAX, (uptr)&cpuRegs.PERF.n.pcr0); + AND32ItoR(ECX, 0x800003E0); + + CMP32ItoR(ECX, 0x80000020); + j8Ptr[0] = JNE8(0); + + MOV32MtoR(EDX, (uptr)&cpuRegs.cycle); + SUB32MtoR(EAX, (uptr)&s_iLastPERFCycle[0]); + ADD32RtoR(EAX, EDX); + MOV32RtoM((uptr)&s_iLastPERFCycle[0], EDX); + MOV32RtoM((uptr)&cpuRegs.PERF.n.pcr0, EAX); + + x86SetJ8(j8Ptr[0]); + break; + case 3: + // check if needs to be incremented + MOV32MtoR(ECX, (uptr)&cpuRegs.PERF.n.pccr); + MOV32MtoR(EAX, (uptr)&cpuRegs.PERF.n.pcr1); + AND32ItoR(ECX, 0x800F8000); + + CMP32ItoR(ECX, 0x80008000); + j8Ptr[0] = JNE8(0); + + MOV32MtoR(EDX, (uptr)&cpuRegs.cycle); + SUB32MtoR(EAX, (uptr)&s_iLastPERFCycle[1]); + ADD32RtoR(EAX, EDX); + MOV32RtoM((uptr)&s_iLastPERFCycle[1], EDX); + MOV32RtoM((uptr)&cpuRegs.PERF.n.pcr1, EAX); + + x86SetJ8(j8Ptr[0]); + + break; + } + + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0],EAX); + + if(EEINST_ISLIVE1(_Rt_)) { + CDQ(); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[1], EDX); + } + else EEINST_RESETHASLIVE1(_Rt_); + +#ifdef PCSX2_DEVBUILD + COP0_LOG("MFC0 PCCR = %x PCR0 = %x PCR1 = %x IMM= %x\n", + cpuRegs.PERF.n.pccr, cpuRegs.PERF.n.pcr0, cpuRegs.PERF.n.pcr1, _Imm_ & 0x3F); +#endif + return; + } + else if( _Rd_ == 24){ + COP0_LOG("MFC0 Breakpoint debug Registers code = %x\n", cpuRegs.code & 0x3FF); + return; + } + _eeOnWriteReg(_Rt_, 1); + + if( EEINST_ISLIVE1(_Rt_) ) { + _deleteEEreg(_Rt_, 0); + MOV32MtoR(EAX, (uptr)&cpuRegs.CP0.r[ _Rd_ ]); + CDQ(); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0], EAX); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[1], EDX); + } + else { + EEINST_RESETHASLIVE1(_Rt_); + + if( (mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE)) >= 0 ) { + MOVDMtoMMX(mmreg, (uptr)&cpuRegs.CP0.r[ _Rd_ ]); + SetMMXstate(); + } + else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ)) >= 0) { + + if( EEINST_ISLIVE2(_Rt_) ) { + if( xmmregs[mmreg].mode & MODE_WRITE ) { + SSE_MOVHPS_XMM_to_M64((uptr)&cpuRegs.GPR.r[_Rt_].UL[2], mmreg); + } + xmmregs[mmreg].inuse = 0; + + MOV32MtoR(EAX, (uptr)&cpuRegs.CP0.r[ _Rd_ ]); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0],EAX); + } + else { + SSE_MOVLPS_M64_to_XMM(mmreg, (uptr)&cpuRegs.CP0.r[ _Rd_ ]); + } + } + else { + MOV32MtoR(EAX, (uptr)&cpuRegs.CP0.r[ _Rd_ ]); + if(_Rd_ == 12) AND32ItoR(EAX, 0xf0c79c1f); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0],EAX); + if(EEINST_ISLIVE1(_Rt_)) { + CDQ(); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[1], EDX); + } + else { + EEINST_RESETHASLIVE1(_Rt_); + } + } + } +} + +void updatePCCR() +{ + // read the old pccr and update pcr0/1 + MOV32MtoR(EAX, (uptr)&cpuRegs.PERF.n.pccr); + MOV32RtoR(EDX, EAX); + MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); + + AND32ItoR(EAX, 0x800003E0); + CMP32ItoR(EAX, 0x80000020); + j8Ptr[0] = JNE8(0); + MOV32MtoR(EAX, (uptr)&s_iLastPERFCycle[0]); + ADD32RtoM((uptr)&cpuRegs.PERF.n.pcr0, ECX); + SUB32RtoM((uptr)&cpuRegs.PERF.n.pcr0, EAX); + x86SetJ8(j8Ptr[0]); + + AND32ItoR(EDX, 0x800F8000); + CMP32ItoR(EDX, 0x80008000); + j8Ptr[0] = JNE8(0); + MOV32MtoR(EAX, (uptr)&s_iLastPERFCycle[1]); + ADD32RtoM((uptr)&cpuRegs.PERF.n.pcr1, ECX); + SUB32RtoM((uptr)&cpuRegs.PERF.n.pcr1, EAX); + x86SetJ8(j8Ptr[0]); +} + +void recMTC0() +{ + if( GPR_IS_CONST1(_Rt_) ) { + switch (_Rd_) { + case 12: + iFlushCall(FLUSH_NODESTROY); + //_flushCachedRegs(); //NOTE: necessary? + _callFunctionArg1((uptr)WriteCP0Status, MEM_CONSTTAG, g_cpuConstRegs[_Rt_].UL[0]); + break; + case 9: + MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); + MOV32RtoM((uptr)&s_iLastCOP0Cycle, ECX); + MOV32ItoM((uptr)&cpuRegs.CP0.r[9], g_cpuConstRegs[_Rt_].UL[0]); + break; + case 25: + COP0_LOG("MTC0 PCCR = %x PCR0 = %x PCR1 = %x IMM= %x\n", + cpuRegs.PERF.n.pccr, cpuRegs.PERF.n.pcr0, cpuRegs.PERF.n.pcr1, _Imm_ & 0x3F); + switch(_Imm_ & 0x3F){ + case 0: + + updatePCCR(); + MOV32ItoM((uptr)&cpuRegs.PERF.n.pccr, g_cpuConstRegs[_Rt_].UL[0]); + + // update the cycles + MOV32RtoM((uptr)&s_iLastPERFCycle[0], ECX); + MOV32RtoM((uptr)&s_iLastPERFCycle[1], ECX); + break; + case 1: + MOV32MtoR(EAX, (uptr)&cpuRegs.cycle); + MOV32ItoM((uptr)&cpuRegs.PERF.n.pcr0, g_cpuConstRegs[_Rt_].UL[0]); + MOV32RtoM((uptr)&s_iLastPERFCycle[0], EAX); + break; + case 3: + MOV32MtoR(EAX, (uptr)&cpuRegs.cycle); + MOV32ItoM((uptr)&cpuRegs.PERF.n.pcr1, g_cpuConstRegs[_Rt_].UL[0]); + MOV32RtoM((uptr)&s_iLastPERFCycle[1], EAX); + break; + } + break; + case 24: + COP0_LOG("MTC0 Breakpoint debug Registers code = %x\n", cpuRegs.code & 0x3FF); + break; + default: + MOV32ItoM((uptr)&cpuRegs.CP0.r[_Rd_], g_cpuConstRegs[_Rt_].UL[0]); + break; + } + } + else { + switch (_Rd_) { + case 12: + iFlushCall(FLUSH_NODESTROY); + //_flushCachedRegs(); //NOTE: necessary? + _callFunctionArg1((uptr)WriteCP0Status, MEM_GPRTAG|_Rt_, 0); + break; + case 9: + MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); + _eeMoveGPRtoM((uptr)&cpuRegs.CP0.r[9], _Rt_); + MOV32RtoM((uptr)&s_iLastCOP0Cycle, ECX); + break; + case 25: + COP0_LOG("MTC0 PCCR = %x PCR0 = %x PCR1 = %x IMM= %x\n", + cpuRegs.PERF.n.pccr, cpuRegs.PERF.n.pcr0, cpuRegs.PERF.n.pcr1, _Imm_ & 0x3F); + switch(_Imm_ & 0x3F){ + case 0: + updatePCCR(); + _eeMoveGPRtoM((uptr)&cpuRegs.PERF.n.pccr, _Rt_); + + // update the cycles + MOV32RtoM((uptr)&s_iLastPERFCycle[0], ECX); + MOV32RtoM((uptr)&s_iLastPERFCycle[1], ECX); + break; + case 1: + MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); + _eeMoveGPRtoM((uptr)&cpuRegs.PERF.n.pcr0, _Rt_); + MOV32RtoM((uptr)&s_iLastPERFCycle[0], ECX); + break; + case 3: + MOV32MtoR(ECX, (uptr)&cpuRegs.cycle); + _eeMoveGPRtoM((uptr)&cpuRegs.PERF.n.pcr1, _Rt_); + MOV32RtoM((uptr)&s_iLastPERFCycle[1], ECX); + break; + } + break; + case 24: + COP0_LOG("MTC0 Breakpoint debug Registers code = %x\n", cpuRegs.code & 0x3FF); + break; + default: + _eeMoveGPRtoM((uptr)&cpuRegs.CP0.r[_Rd_], _Rt_); + break; + } + } +} +#endif + + +/*void rec(COP0) { +} + +void rec(BC0F) { +} + +void rec(BC0T) { +} + +void rec(BC0FL) { +} + +void rec(BC0TL) { +} + +void rec(TLBR) { +} + +void rec(TLBWI) { +} + +void rec(TLBWR) { +} + +void rec(TLBP) { +}*/ + +}}}} diff --git a/pcsx2/x86/iCOP0.h b/pcsx2/x86/iCOP0.h index 9112cb3898..9b513575cc 100644 --- a/pcsx2/x86/iCOP0.h +++ b/pcsx2/x86/iCOP0.h @@ -1,49 +1,49 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __iCOP0_H__ -#define __iCOP0_H__ - -#include "COP0.h" - -/********************************************************* -* COP0 opcodes * -* * -*********************************************************/ - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl { -namespace COP0 -{ - void recMFC0( void ); - void recMTC0( void ); - void recBC0F( void ); - void recBC0T( void ); - void recBC0FL( void ); - void recBC0TL( void ); - void recTLBR( void ); - void recTLBWI( void ); - void recTLBWR( void ); - void recTLBP( void ); - void recERET( void ); - void recDI( void ); - void recEI( void ); - -}}}} -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __iCOP0_H__ +#define __iCOP0_H__ + +#include "COP0.h" + +/********************************************************* +* COP0 opcodes * +* * +*********************************************************/ + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl { +namespace COP0 +{ + void recMFC0( void ); + void recMTC0( void ); + void recBC0F( void ); + void recBC0T( void ); + void recBC0FL( void ); + void recBC0TL( void ); + void recTLBR( void ); + void recTLBWI( void ); + void recTLBWR( void ); + void recTLBP( void ); + void recERET( void ); + void recDI( void ); + void recEI( void ); + +}}}} +#endif diff --git a/pcsx2/x86/iCOP2.cpp b/pcsx2/x86/iCOP2.cpp index 7ed6f7e322..55329d6782 100644 --- a/pcsx2/x86/iCOP2.cpp +++ b/pcsx2/x86/iCOP2.cpp @@ -1,721 +1,721 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "R5900OpcodeTables.h" -#include "ix86/ix86.h" -#include "iR5900.h" - -#include "Common.h" -#include "DebugTools/Debug.h" -#include "R5900.h" -#include "R5900OpcodeTables.h" -#include "VUmicro.h" -#include "iVUmicro.h" - -extern void _vu0WaitMicro(); - -#define _Ft_ _Rt_ -#define _Fs_ _Rd_ -#define _Fd_ _Sa_ - -#define _Fsf_ ((cpuRegs.code >> 21) & 0x03) -#define _Ftf_ ((cpuRegs.code >> 23) & 0x03) -#define _Cc_ (cpuRegs.code & 0x03) - -void recCop2BranchCall( void (*func)() ) -{ - SetFPUstate(); - recBranchCall( func ); - _freeX86regs(); -} - -#define REC_COP2_FUNC( f ) \ - void rec##f(s32 info) \ - { \ - Console::Notice("Warning > cop2 "#f" called"); \ - recCop2BranchCall( f ); \ - } - -#define INTERPRETATE_COP2_FUNC(f) \ -void recV##f(s32 info) { \ - MOV32ItoM((uptr)&cpuRegs.code, cpuRegs.code); \ - MOV32ItoM((uptr)&cpuRegs.pc, pc); \ - iFlushCall(FLUSH_EVERYTHING); \ - CALLFunc((uptr)V##f); \ - _freeX86regs(); \ -} - -#define REC_COP2_VU0(f) \ -void recV##f( s32 info ) { \ - recVUMI_##f( &VU0, info ); \ -} - -#define REC_COP2_VU0_Q(f) \ -void recV##f( s32 info ) { \ - recVUMI_##f( &VU0, info ); \ -} - -void rec_C2UNK( s32 info ) -{ - Console::Error("Cop2 bad opcode: %x", params cpuRegs.code); -} - -void _vuRegs_C2UNK(VURegs * VU, _VURegsNum *VUregsn) -{ - Console::Error("Cop2 bad _vuRegs code:%x", params cpuRegs.code); -} - -void recCOP2(s32 info); -void recCOP2_SPECIAL(s32 info); -void recCOP2_BC2(s32 info); -void recCOP2_SPECIAL2(s32 info); - -static void recCFC2(s32 info) -{ - int mmreg; - - if (cpuRegs.code & 1) - { - iFlushCall(FLUSH_NOCONST); - CALLFunc((uptr)_vu0WaitMicro); - } - - if(!_Rt_) return; - - _deleteGPRtoXMMreg(_Rt_, 2); - mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_WRITE); - - if( mmreg >= 0 ) - { - if( _Fs_ >= 16 ) - { - MOVDMtoMMX(mmreg, (uptr)&VU0.VI[ _Fs_ ].UL); - if( EEINST_ISLIVE1(_Rt_) ) - { - _signExtendGPRtoMMX(mmreg, _Rt_, 0); - } - else - { - EEINST_RESETHASLIVE1(_Rt_); - } - } - else - { - MOVDMtoMMX(mmreg, (uptr)&VU0.VI[ _Fs_ ].UL); - } - SetMMXstate(); - } - else - { - MOV32MtoR(EAX, (uptr)&VU0.VI[ _Fs_ ].UL); - MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0],EAX); - - if(EEINST_ISLIVE1(_Rt_)) - { - if( _Fs_ < 16 ) - { - // no sign extending - MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[1],0); - } - else - { - CDQ(); - MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[1], EDX); - } - } - else - { - EEINST_RESETHASLIVE1(_Rt_); - } - } - - _eeOnWriteReg(_Rt_, 1); -} - -static void recCTC2(s32 info) -{ - if (cpuRegs.code & 1) { - iFlushCall(FLUSH_NOCONST); - CALLFunc((uptr)_vu0WaitMicro); - } - - if(!_Fs_) return; - - if( GPR_IS_CONST1(_Rt_) ) - { - switch(_Fs_) { - case REG_MAC_FLAG: // read-only - case REG_TPC: // read-only - case REG_VPU_STAT: // read-only - break; - case REG_FBRST: - if( g_cpuConstRegs[_Rt_].UL[0] & 0x202 ) - iFlushCall(FLUSH_FREE_TEMPX86); - - _deleteX86reg(X86TYPE_VI, REG_FBRST, 2); - - if( g_cpuConstRegs[_Rt_].UL[0] & 2 ) - CALLFunc((uptr)vu0ResetRegs); - if( g_cpuConstRegs[_Rt_].UL[0] & 0x200 ) - CALLFunc((uptr)vu1ResetRegs); - MOV16ItoM((uptr)&VU0.VI[REG_FBRST].UL,g_cpuConstRegs[_Rt_].UL[0]&0x0c0c); - break; - case REG_CMSAR1: // REG_CMSAR1 - iFlushCall(FLUSH_NOCONST);// since CALLFunc - assert( _checkX86reg(X86TYPE_VI, REG_VPU_STAT, 0) < 0 && - _checkX86reg(X86TYPE_VI, REG_TPC, 0) < 0 ); - // Execute VU1 Micro SubRoutine - _callFunctionArg1((uptr)vu1ExecMicro, MEM_CONSTTAG, g_cpuConstRegs[_Rt_].UL[0]&0xffff); - break; - default: - { - if( _Fs_ < 16 ) - assert( (g_cpuConstRegs[_Rt_].UL[0]&0xffff0000)==0); - - // a lot of games have vu0 spinning on some integer - // then they modify the register and expect vu0 to stop spinning within 10 cycles (donald duck) - - // Use vu0ExecMicro instead because it properly stalls for already-running micro - // instructions, and also sets the nextBranchCycle as needed. (air) - - MOV32ItoM((uptr)&VU0.VI[_Fs_].UL,g_cpuConstRegs[_Rt_].UL[0]); - //PUSH32I( -1 ); - iFlushCall(FLUSH_NOCONST); - CALLFunc((uptr)CpuVU0.ExecuteBlock); - //CALLFunc((uptr)vu0ExecMicro); - //ADD32ItoR( ESP, 4 ); - break; - } - } - } - else - { - switch(_Fs_) { - case REG_MAC_FLAG: // read-only - case REG_TPC: // read-only - case REG_VPU_STAT: // read-only - break; - case REG_FBRST: - iFlushCall(FLUSH_FREE_TEMPX86); - assert( _checkX86reg(X86TYPE_VI, REG_FBRST, 0) < 0 ); - - _eeMoveGPRtoR(EAX, _Rt_); - - TEST32ItoR(EAX,0x2); - j8Ptr[0] = JZ8(0); - CALLFunc((uptr)vu0ResetRegs); - _eeMoveGPRtoR(EAX, _Rt_); - x86SetJ8(j8Ptr[0]); - - TEST32ItoR(EAX,0x200); - j8Ptr[0] = JZ8(0); - CALLFunc((uptr)vu1ResetRegs); - _eeMoveGPRtoR(EAX, _Rt_); - x86SetJ8(j8Ptr[0]); - - AND32ItoR(EAX,0x0C0C); - MOV16RtoM((uptr)&VU0.VI[REG_FBRST].UL,EAX); - break; - case REG_CMSAR1: // REG_CMSAR1 - iFlushCall(FLUSH_NOCONST); - _eeMoveGPRtoR(EAX, _Rt_); - _callFunctionArg1((uptr)vu1ExecMicro, MEM_X86TAG|EAX, 0); // Execute VU1 Micro SubRoutine - break; - default: - _eeMoveGPRtoM((uptr)&VU0.VI[_Fs_].UL,_Rt_); - - // a lot of games have vu0 spinning on some integer - // then they modify the register and expect vu0 to stop spinning within 10 cycles (donald duck) - iFlushCall(FLUSH_NOCONST); - break; - } - } -} - -static void recQMFC2(s32 info) -{ - int t0reg, fsreg; - - if (cpuRegs.code & 1) - { - iFlushCall(FLUSH_NOCONST); - CALLFunc((uptr)_vu0WaitMicro); - } - - if(!_Rt_) return; - - _deleteMMXreg(MMX_GPR+_Rt_, 2); - _deleteX86reg(X86TYPE_GPR, _Rt_, 2); - _eeOnWriteReg(_Rt_, 0); - - // could 'borrow' the reg - fsreg = _checkXMMreg(XMMTYPE_VFREG, _Fs_, MODE_READ); - - if( fsreg >= 0 ) { - if( xmmregs[fsreg].mode & MODE_WRITE ) - { - _xmmregs temp; - - t0reg = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); - SSEX_MOVDQA_XMM_to_XMM(t0reg, fsreg); - - // change regs - temp = xmmregs[t0reg]; - xmmregs[t0reg] = xmmregs[fsreg]; - xmmregs[fsreg] = temp; - } - else - { - // swap regs - t0reg = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); - - xmmregs[fsreg] = xmmregs[t0reg]; - xmmregs[t0reg].inuse = 0; - } - } - else { - t0reg = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); - - if( t0reg >= 0 ) - SSE_MOVAPS_M128_to_XMM( t0reg, (uptr)&VU0.VF[_Fs_].UD[0]); - else - _recMove128MtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0], (uptr)&VU0.VF[_Fs_].UL[0]); - } - - _clearNeededXMMregs(); -} - -static void recQMTC2(s32 info) -{ - int mmreg; - - if (cpuRegs.code & 1) { - iFlushCall(FLUSH_NOCONST); - CALLFunc((uptr)_vu0WaitMicro); - } - - if (!_Fs_) return; - - mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ); - - if( mmreg >= 0) { - int fsreg = _checkXMMreg(XMMTYPE_VFREG, _Fs_, MODE_WRITE); - int flag = ((xmmregs[mmreg].mode&MODE_WRITE) && (g_pCurInstInfo->regs[_Rt_]&(EEINST_LIVE0|EEINST_LIVE1|EEINST_LIVE2))); - - if( fsreg >= 0 ) { - - if (flag) { - SSE_MOVAPS_XMM_to_XMM(fsreg, mmreg); - } - else { - // swap regs - xmmregs[mmreg] = xmmregs[fsreg]; - xmmregs[mmreg].mode = MODE_WRITE; - xmmregs[fsreg].inuse = 0; - g_xmmtypes[mmreg] = XMMT_FPS; - } - } - else { - if (flag) SSE_MOVAPS_XMM_to_M128((uptr)&cpuRegs.GPR.r[_Rt_], mmreg); - - // swap regs - xmmregs[mmreg].type = XMMTYPE_VFREG; - xmmregs[mmreg].VU = 0; - xmmregs[mmreg].reg = _Fs_; - xmmregs[mmreg].mode = MODE_WRITE; - g_xmmtypes[mmreg] = XMMT_FPS; - } - } - else { - int fsreg = _allocVFtoXMMreg(&VU0, -1, _Fs_, MODE_WRITE); - - if( fsreg >= 0 ) { - mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_READ); - - if( mmreg >= 0) { - SetMMXstate(); - SSE2_MOVQ2DQ_MM_to_XMM(fsreg, mmreg); - SSE_MOVHPS_M64_to_XMM(fsreg, (uptr)&cpuRegs.GPR.r[_Rt_].UL[2]); - } - else { - if( GPR_IS_CONST1( _Rt_ ) ) { - assert( _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ) == -1 ); - _flushConstReg(_Rt_); - } - - SSE_MOVAPS_M128_to_XMM(fsreg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); - } - } - else { - _deleteEEreg(_Rt_, 0); - _recMove128MtoM((uptr)&VU0.VF[_Fs_].UL[0], (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); - } - } - - _clearNeededXMMregs(); -} - -// Removed _cop2AnalyzeOp because it was outdated and unreliable (And currently unused). -// A new version should be rebuilt using the SuperVU's AnalyzeOp as a reference. (air) - -////////////////////////////////////////////////////////////////////////// -// BC2: Instructions -////////////////////////////////////////////////////////////////////////// -//REC_COP2_FUNC(BC2F); -//REC_COP2_FUNC(BC2T); -//REC_COP2_FUNC(BC2FL); -//REC_COP2_FUNC(BC2TL); - -using namespace R5900::Dynarec; - -static void _setupBranchTest() -{ - _eeFlushAllUnused(); - - // COP2 branch conditionals are based on the following equation: - // ((VU0.VI[REG_VPU_STAT].US[0] >> 8) & 1) - // BC2F checks if the statement is false, BC2T checks if the statement is true. - - MOV32MtoR( EAX, (uptr)&VU0.VI[REG_VPU_STAT].UL ); - TEST32ItoR( EAX, 0x100 ); -} - -void recBC2F( s32 info ) -{ - _setupBranchTest(); - recDoBranchImm(JNZ32(0)); -} - -void recBC2T( s32 info ) -{ - _setupBranchTest(); - recDoBranchImm(JZ32(0)); -} - -void recBC2FL( s32 info ) -{ - _setupBranchTest(); - recDoBranchImm_Likely(JNZ32(0)); -} - -void recBC2TL( s32 info ) -{ - _setupBranchTest(); - recDoBranchImm_Likely(JZ32(0)); -} - - -////////////////////////////////////////////////////////////////////////// -// Special1 instructions -////////////////////////////////////////////////////////////////////////// -//TODO: redirect all the opcodes to the ivu0micro same functions -REC_COP2_VU0(IADD); -REC_COP2_VU0(IADDI); -REC_COP2_VU0(ISUB); -REC_COP2_VU0(IOR); -REC_COP2_VU0(IAND); -REC_COP2_VU0(OPMSUB); -REC_COP2_VU0(MADDq); -REC_COP2_VU0(MADDi); -REC_COP2_VU0(MSUBq); -REC_COP2_VU0(MSUBi); -REC_COP2_VU0(SUBi); -REC_COP2_VU0(SUBq); -REC_COP2_VU0(MULi); -REC_COP2_VU0(MULq); -REC_COP2_VU0(MAXi); -REC_COP2_VU0(MINIi); -REC_COP2_VU0(MUL); -REC_COP2_VU0(MAX); -REC_COP2_VU0(MADD); -REC_COP2_VU0(MSUB); - -REC_COP2_VU0(MINIx); -REC_COP2_VU0(MINIy); -REC_COP2_VU0(MINIz); -REC_COP2_VU0(MINIw); - -REC_COP2_VU0(MAXx); -REC_COP2_VU0(MAXy); -REC_COP2_VU0(MAXz); -REC_COP2_VU0(MAXw); - -REC_COP2_VU0(MULx); -REC_COP2_VU0(MULy); -REC_COP2_VU0(MULz); -REC_COP2_VU0(MULw); - -REC_COP2_VU0(ADD); -REC_COP2_VU0(ADDi); -REC_COP2_VU0(ADDq); -REC_COP2_VU0(ADDx); -REC_COP2_VU0(ADDy); -REC_COP2_VU0(ADDz); -REC_COP2_VU0(ADDw); - -REC_COP2_VU0(SUBx); -REC_COP2_VU0(SUBy); -REC_COP2_VU0(SUBz); -REC_COP2_VU0(SUBw); - -REC_COP2_VU0(MADDx); -REC_COP2_VU0(MADDy); -REC_COP2_VU0(MADDz); -REC_COP2_VU0(MADDw); - -REC_COP2_VU0(MSUBx); -REC_COP2_VU0(MSUBy); -REC_COP2_VU0(MSUBz); -REC_COP2_VU0(MSUBw); - -REC_COP2_VU0(SUB); -REC_COP2_VU0(MINI); - -////////////////////////////////////////////////////////////////////////// -// Special2 instructions -////////////////////////////////////////////////////////////////////////// - -REC_COP2_VU0(CLIP); -REC_COP2_VU0(LQI); -REC_COP2_VU0(SQI); -REC_COP2_VU0(LQD); -REC_COP2_VU0(SQD); -REC_COP2_VU0(MTIR); -REC_COP2_VU0(MFIR); -REC_COP2_VU0(ILWR); -REC_COP2_VU0(ISWR); -REC_COP2_VU0(RINIT); -REC_COP2_VU0(RXOR); -REC_COP2_VU0(RNEXT); -REC_COP2_VU0(RGET); - -REC_COP2_VU0(ITOF0); -REC_COP2_VU0(ITOF4); -REC_COP2_VU0(ITOF12); -REC_COP2_VU0(ITOF15); -REC_COP2_VU0(FTOI0); -REC_COP2_VU0(FTOI4); -REC_COP2_VU0(FTOI12); -REC_COP2_VU0(FTOI15); -REC_COP2_VU0(MADDA); -REC_COP2_VU0(MSUBA); -REC_COP2_VU0(MADDAi); -REC_COP2_VU0(MADDAq); -REC_COP2_VU0(MADDAx); -REC_COP2_VU0(MADDAy); -REC_COP2_VU0(MADDAz); -REC_COP2_VU0(MADDAw); -REC_COP2_VU0(MSUBAi); -REC_COP2_VU0(MSUBAq); -REC_COP2_VU0(MSUBAx); -REC_COP2_VU0(MSUBAy); -REC_COP2_VU0(MSUBAz); -REC_COP2_VU0(MSUBAw); -REC_COP2_VU0(ADDAi); -REC_COP2_VU0(ADDA); -REC_COP2_VU0(SUBA); -REC_COP2_VU0(MULA); -REC_COP2_VU0(ADDAq); -REC_COP2_VU0(ADDAx); -REC_COP2_VU0(ADDAy); -REC_COP2_VU0(ADDAz); -REC_COP2_VU0(ADDAw); -REC_COP2_VU0(SUBAi); -REC_COP2_VU0(SUBAq); -REC_COP2_VU0(SUBAx); -REC_COP2_VU0(SUBAy); -REC_COP2_VU0(SUBAz); -REC_COP2_VU0(SUBAw); -REC_COP2_VU0(MULAi); -REC_COP2_VU0(MULAq); -REC_COP2_VU0(MULAx); -REC_COP2_VU0(MULAy); -REC_COP2_VU0(MULAz); -REC_COP2_VU0(MULAw); -REC_COP2_VU0(OPMULA); -REC_COP2_VU0(MOVE); -REC_COP2_VU0_Q(DIV); -REC_COP2_VU0_Q(SQRT); -REC_COP2_VU0_Q(RSQRT); -REC_COP2_VU0(MR32); -REC_COP2_VU0(ABS); - -void recVNOP(s32 info){} -void recVWAITQ(s32 info){} -INTERPRETATE_COP2_FUNC(CALLMS); -INTERPRETATE_COP2_FUNC(CALLMSR); - -void _vuRegsCOP2_SPECIAL(VURegs * VU, _VURegsNum *VUregsn); -void _vuRegsCOP2_SPECIAL2(VURegs * VU, _VURegsNum *VUregsn); - -// information -void _vuRegsQMFC2(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->VFread0 = _Fs_; - VUregsn->VFr0xyzw= 0xf; -} - -void _vuRegsCFC2(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->VIread = 1<<_Fs_; -} - -void _vuRegsQMTC2(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->VFwrite = _Fs_; - VUregsn->VFwxyzw= 0xf; -} - -void _vuRegsCTC2(VURegs * VU, _VURegsNum *VUregsn) { - VUregsn->VIwrite = 1<<_Fs_; -} - -void (*_vuRegsCOP2t[32])(VURegs * VU, _VURegsNum *VUregsn) = { - _vuRegs_C2UNK, _vuRegsQMFC2, _vuRegsCFC2, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegsQMTC2, _vuRegsCTC2, _vuRegs_C2UNK, - _vuRegsNOP, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegs_C2UNK, - _vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL, - _vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL, -}; - -void (*_vuRegsCOP2SPECIAL1t[64])(VURegs * VU, _VURegsNum *VUregsn) = { - _vuRegsADDx, _vuRegsADDy, _vuRegsADDz, _vuRegsADDw, _vuRegsSUBx, _vuRegsSUBy, _vuRegsSUBz, _vuRegsSUBw, - _vuRegsMADDx, _vuRegsMADDy, _vuRegsMADDz, _vuRegsMADDw, _vuRegsMSUBx, _vuRegsMSUBy, _vuRegsMSUBz, _vuRegsMSUBw, - _vuRegsMAXx, _vuRegsMAXy, _vuRegsMAXz, _vuRegsMAXw, _vuRegsMINIx, _vuRegsMINIy, _vuRegsMINIz, _vuRegsMINIw, - _vuRegsMULx, _vuRegsMULy, _vuRegsMULz, _vuRegsMULw, _vuRegsMULq, _vuRegsMAXi, _vuRegsMULi, _vuRegsMINIi, - _vuRegsADDq, _vuRegsMADDq, _vuRegsADDi, _vuRegsMADDi, _vuRegsSUBq, _vuRegsMSUBq, _vuRegsSUBi, _vuRegsMSUBi, - _vuRegsADD, _vuRegsMADD, _vuRegsMUL, _vuRegsMAX, _vuRegsSUB, _vuRegsMSUB, _vuRegsOPMSUB, _vuRegsMINI, - _vuRegsIADD, _vuRegsISUB, _vuRegsIADDI, _vuRegs_C2UNK, _vuRegsIAND, _vuRegsIOR, _vuRegs_C2UNK, _vuRegs_C2UNK, - _vuRegsNOP, _vuRegsNOP, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegsCOP2_SPECIAL2,_vuRegsCOP2_SPECIAL2,_vuRegsCOP2_SPECIAL2,_vuRegsCOP2_SPECIAL2, -}; - -void (*_vuRegsCOP2SPECIAL2t[128])(VURegs * VU, _VURegsNum *VUregsn) = { - _vuRegsADDAx ,_vuRegsADDAy ,_vuRegsADDAz ,_vuRegsADDAw ,_vuRegsSUBAx ,_vuRegsSUBAy ,_vuRegsSUBAz ,_vuRegsSUBAw, - _vuRegsMADDAx ,_vuRegsMADDAy ,_vuRegsMADDAz ,_vuRegsMADDAw ,_vuRegsMSUBAx ,_vuRegsMSUBAy ,_vuRegsMSUBAz ,_vuRegsMSUBAw, - _vuRegsITOF0 ,_vuRegsITOF4 ,_vuRegsITOF12 ,_vuRegsITOF15 ,_vuRegsFTOI0 ,_vuRegsFTOI4 ,_vuRegsFTOI12 ,_vuRegsFTOI15, - _vuRegsMULAx ,_vuRegsMULAy ,_vuRegsMULAz ,_vuRegsMULAw ,_vuRegsMULAq ,_vuRegsABS ,_vuRegsMULAi ,_vuRegsCLIP, - _vuRegsADDAq ,_vuRegsMADDAq ,_vuRegsADDAi ,_vuRegsMADDAi ,_vuRegsSUBAq ,_vuRegsMSUBAq ,_vuRegsSUBAi ,_vuRegsMSUBAi, - _vuRegsADDA ,_vuRegsMADDA ,_vuRegsMULA ,_vuRegs_C2UNK ,_vuRegsSUBA ,_vuRegsMSUBA ,_vuRegsOPMULA ,_vuRegsNOP, - _vuRegsMOVE ,_vuRegsMR32 ,_vuRegs_C2UNK ,_vuRegs_C2UNK ,_vuRegsLQI ,_vuRegsSQI ,_vuRegsLQD ,_vuRegsSQD, - _vuRegsDIV ,_vuRegsSQRT ,_vuRegsRSQRT ,_vuRegsWAITQ ,_vuRegsMTIR ,_vuRegsMFIR ,_vuRegsILWR ,_vuRegsISWR, - _vuRegsRNEXT ,_vuRegsRGET ,_vuRegsRINIT ,_vuRegsRXOR ,_vuRegs_C2UNK ,_vuRegs_C2UNK ,_vuRegs_C2UNK ,_vuRegs_C2UNK, - _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, - _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, - _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, - _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, - _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, - _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, - _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, -}; - -void _vuRegsCOP22(VURegs * VU, _VURegsNum *VUregsn) -{ - _vuRegsCOP2t[_Rs_](VU, VUregsn); -} - -void _vuRegsCOP2_SPECIAL(VURegs * VU, _VURegsNum *VUregsn) -{ - _vuRegsCOP2SPECIAL1t[_Funct_](VU, VUregsn); -} - -void _vuRegsCOP2_SPECIAL2(VURegs * VU, _VURegsNum *VUregsn) -{ - int opc=(cpuRegs.code & 0x3) | ((cpuRegs.code >> 4) & 0x7c); - _vuRegsCOP2SPECIAL2t[opc](VU, VUregsn); -} - -// recompilation -void (*recCOP2t[32])(s32 info) = { - rec_C2UNK, recQMFC2, recCFC2, rec_C2UNK, rec_C2UNK, recQMTC2, recCTC2, rec_C2UNK, - recCOP2_BC2, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, - recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL, - recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL, -}; - -void (*recCOP2_BC2t[32])(s32 info) = { - recBC2F, recBC2T, recBC2FL, recBC2TL, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, - rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, - rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, - rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, -}; - -void (*recCOP2SPECIAL1t[64])(s32 info) = { - recVADDx, recVADDy, recVADDz, recVADDw, recVSUBx, recVSUBy, recVSUBz, recVSUBw, - recVMADDx, recVMADDy, recVMADDz, recVMADDw, recVMSUBx, recVMSUBy, recVMSUBz, recVMSUBw, - recVMAXx, recVMAXy, recVMAXz, recVMAXw, recVMINIx, recVMINIy, recVMINIz, recVMINIw, - recVMULx, recVMULy, recVMULz, recVMULw, recVMULq, recVMAXi, recVMULi, recVMINIi, - recVADDq, recVMADDq, recVADDi, recVMADDi, recVSUBq, recVMSUBq, recVSUBi, recVMSUBi, - recVADD, recVMADD, recVMUL, recVMAX, recVSUB, recVMSUB, recVOPMSUB, recVMINI, - recVIADD, recVISUB, recVIADDI, rec_C2UNK, recVIAND, recVIOR, rec_C2UNK, rec_C2UNK, - recVCALLMS, recVCALLMSR, rec_C2UNK, rec_C2UNK, recCOP2_SPECIAL2,recCOP2_SPECIAL2,recCOP2_SPECIAL2,recCOP2_SPECIAL2, -}; - -void (*recCOP2SPECIAL2t[128])(s32 info) = { - recVADDAx ,recVADDAy ,recVADDAz ,recVADDAw ,recVSUBAx ,recVSUBAy ,recVSUBAz ,recVSUBAw, - recVMADDAx ,recVMADDAy ,recVMADDAz ,recVMADDAw ,recVMSUBAx ,recVMSUBAy ,recVMSUBAz ,recVMSUBAw, - recVITOF0 ,recVITOF4 ,recVITOF12 ,recVITOF15 ,recVFTOI0 ,recVFTOI4 ,recVFTOI12 ,recVFTOI15, - recVMULAx ,recVMULAy ,recVMULAz ,recVMULAw ,recVMULAq ,recVABS ,recVMULAi ,recVCLIP, - recVADDAq ,recVMADDAq ,recVADDAi ,recVMADDAi ,recVSUBAq ,recVMSUBAq ,recVSUBAi ,recVMSUBAi, - recVADDA ,recVMADDA ,recVMULA ,rec_C2UNK ,recVSUBA ,recVMSUBA ,recVOPMULA ,recVNOP, - recVMOVE ,recVMR32 ,rec_C2UNK ,rec_C2UNK ,recVLQI ,recVSQI ,recVLQD ,recVSQD, - recVDIV ,recVSQRT ,recVRSQRT ,recVWAITQ ,recVMTIR ,recVMFIR ,recVILWR ,recVISWR, - recVRNEXT ,recVRGET ,recVRINIT ,recVRXOR ,rec_C2UNK ,rec_C2UNK ,rec_C2UNK ,rec_C2UNK, - rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, - rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, - rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, - rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, - rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, - rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, - rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, -}; - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl -{ - void recCOP2() - { - VU0.code = cpuRegs.code; - - g_pCurInstInfo->vuregs.pipe = 0xff; // to notify eeVURecompileCode that COP2 - s32 info = eeVURecompileCode(&VU0, &g_pCurInstInfo->vuregs); - - info |= PROCESS_VU_COP2; - info |= PROCESS_VU_UPDATEFLAGS; - - recCOP2t[_Rs_]( info ); - - _freeX86regs(); - } -}}} - -void recCOP2_SPECIAL(s32 info ) -{ - recCOP2SPECIAL1t[_Funct_]( info ); -} - -void recCOP2_BC2(s32 info) -{ - recCOP2_BC2t[_Rt_](info); -} - -void recCOP2_SPECIAL2(s32 info) -{ - int opc=(cpuRegs.code & 0x3) | ((cpuRegs.code >> 4) & 0x7c); - recCOP2SPECIAL2t[opc](info); -} - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "R5900OpcodeTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + +#include "Common.h" +#include "DebugTools/Debug.h" +#include "R5900.h" +#include "R5900OpcodeTables.h" +#include "VUmicro.h" +#include "iVUmicro.h" + +extern void _vu0WaitMicro(); + +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +#define _Fsf_ ((cpuRegs.code >> 21) & 0x03) +#define _Ftf_ ((cpuRegs.code >> 23) & 0x03) +#define _Cc_ (cpuRegs.code & 0x03) + +void recCop2BranchCall( void (*func)() ) +{ + SetFPUstate(); + recBranchCall( func ); + _freeX86regs(); +} + +#define REC_COP2_FUNC( f ) \ + void rec##f(s32 info) \ + { \ + Console::Notice("Warning > cop2 "#f" called"); \ + recCop2BranchCall( f ); \ + } + +#define INTERPRETATE_COP2_FUNC(f) \ +void recV##f(s32 info) { \ + MOV32ItoM((uptr)&cpuRegs.code, cpuRegs.code); \ + MOV32ItoM((uptr)&cpuRegs.pc, pc); \ + iFlushCall(FLUSH_EVERYTHING); \ + CALLFunc((uptr)V##f); \ + _freeX86regs(); \ +} + +#define REC_COP2_VU0(f) \ +void recV##f( s32 info ) { \ + recVUMI_##f( &VU0, info ); \ +} + +#define REC_COP2_VU0_Q(f) \ +void recV##f( s32 info ) { \ + recVUMI_##f( &VU0, info ); \ +} + +void rec_C2UNK( s32 info ) +{ + Console::Error("Cop2 bad opcode: %x", params cpuRegs.code); +} + +void _vuRegs_C2UNK(VURegs * VU, _VURegsNum *VUregsn) +{ + Console::Error("Cop2 bad _vuRegs code:%x", params cpuRegs.code); +} + +void recCOP2(s32 info); +void recCOP2_SPECIAL(s32 info); +void recCOP2_BC2(s32 info); +void recCOP2_SPECIAL2(s32 info); + +static void recCFC2(s32 info) +{ + int mmreg; + + if (cpuRegs.code & 1) + { + iFlushCall(FLUSH_NOCONST); + CALLFunc((uptr)_vu0WaitMicro); + } + + if(!_Rt_) return; + + _deleteGPRtoXMMreg(_Rt_, 2); + mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_WRITE); + + if( mmreg >= 0 ) + { + if( _Fs_ >= 16 ) + { + MOVDMtoMMX(mmreg, (uptr)&VU0.VI[ _Fs_ ].UL); + if( EEINST_ISLIVE1(_Rt_) ) + { + _signExtendGPRtoMMX(mmreg, _Rt_, 0); + } + else + { + EEINST_RESETHASLIVE1(_Rt_); + } + } + else + { + MOVDMtoMMX(mmreg, (uptr)&VU0.VI[ _Fs_ ].UL); + } + SetMMXstate(); + } + else + { + MOV32MtoR(EAX, (uptr)&VU0.VI[ _Fs_ ].UL); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0],EAX); + + if(EEINST_ISLIVE1(_Rt_)) + { + if( _Fs_ < 16 ) + { + // no sign extending + MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[1],0); + } + else + { + CDQ(); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[1], EDX); + } + } + else + { + EEINST_RESETHASLIVE1(_Rt_); + } + } + + _eeOnWriteReg(_Rt_, 1); +} + +static void recCTC2(s32 info) +{ + if (cpuRegs.code & 1) { + iFlushCall(FLUSH_NOCONST); + CALLFunc((uptr)_vu0WaitMicro); + } + + if(!_Fs_) return; + + if( GPR_IS_CONST1(_Rt_) ) + { + switch(_Fs_) { + case REG_MAC_FLAG: // read-only + case REG_TPC: // read-only + case REG_VPU_STAT: // read-only + break; + case REG_FBRST: + if( g_cpuConstRegs[_Rt_].UL[0] & 0x202 ) + iFlushCall(FLUSH_FREE_TEMPX86); + + _deleteX86reg(X86TYPE_VI, REG_FBRST, 2); + + if( g_cpuConstRegs[_Rt_].UL[0] & 2 ) + CALLFunc((uptr)vu0ResetRegs); + if( g_cpuConstRegs[_Rt_].UL[0] & 0x200 ) + CALLFunc((uptr)vu1ResetRegs); + MOV16ItoM((uptr)&VU0.VI[REG_FBRST].UL,g_cpuConstRegs[_Rt_].UL[0]&0x0c0c); + break; + case REG_CMSAR1: // REG_CMSAR1 + iFlushCall(FLUSH_NOCONST);// since CALLFunc + assert( _checkX86reg(X86TYPE_VI, REG_VPU_STAT, 0) < 0 && + _checkX86reg(X86TYPE_VI, REG_TPC, 0) < 0 ); + // Execute VU1 Micro SubRoutine + _callFunctionArg1((uptr)vu1ExecMicro, MEM_CONSTTAG, g_cpuConstRegs[_Rt_].UL[0]&0xffff); + break; + default: + { + if( _Fs_ < 16 ) + assert( (g_cpuConstRegs[_Rt_].UL[0]&0xffff0000)==0); + + // a lot of games have vu0 spinning on some integer + // then they modify the register and expect vu0 to stop spinning within 10 cycles (donald duck) + + // Use vu0ExecMicro instead because it properly stalls for already-running micro + // instructions, and also sets the nextBranchCycle as needed. (air) + + MOV32ItoM((uptr)&VU0.VI[_Fs_].UL,g_cpuConstRegs[_Rt_].UL[0]); + //PUSH32I( -1 ); + iFlushCall(FLUSH_NOCONST); + CALLFunc((uptr)CpuVU0.ExecuteBlock); + //CALLFunc((uptr)vu0ExecMicro); + //ADD32ItoR( ESP, 4 ); + break; + } + } + } + else + { + switch(_Fs_) { + case REG_MAC_FLAG: // read-only + case REG_TPC: // read-only + case REG_VPU_STAT: // read-only + break; + case REG_FBRST: + iFlushCall(FLUSH_FREE_TEMPX86); + assert( _checkX86reg(X86TYPE_VI, REG_FBRST, 0) < 0 ); + + _eeMoveGPRtoR(EAX, _Rt_); + + TEST32ItoR(EAX,0x2); + j8Ptr[0] = JZ8(0); + CALLFunc((uptr)vu0ResetRegs); + _eeMoveGPRtoR(EAX, _Rt_); + x86SetJ8(j8Ptr[0]); + + TEST32ItoR(EAX,0x200); + j8Ptr[0] = JZ8(0); + CALLFunc((uptr)vu1ResetRegs); + _eeMoveGPRtoR(EAX, _Rt_); + x86SetJ8(j8Ptr[0]); + + AND32ItoR(EAX,0x0C0C); + MOV16RtoM((uptr)&VU0.VI[REG_FBRST].UL,EAX); + break; + case REG_CMSAR1: // REG_CMSAR1 + iFlushCall(FLUSH_NOCONST); + _eeMoveGPRtoR(EAX, _Rt_); + _callFunctionArg1((uptr)vu1ExecMicro, MEM_X86TAG|EAX, 0); // Execute VU1 Micro SubRoutine + break; + default: + _eeMoveGPRtoM((uptr)&VU0.VI[_Fs_].UL,_Rt_); + + // a lot of games have vu0 spinning on some integer + // then they modify the register and expect vu0 to stop spinning within 10 cycles (donald duck) + iFlushCall(FLUSH_NOCONST); + break; + } + } +} + +static void recQMFC2(s32 info) +{ + int t0reg, fsreg; + + if (cpuRegs.code & 1) + { + iFlushCall(FLUSH_NOCONST); + CALLFunc((uptr)_vu0WaitMicro); + } + + if(!_Rt_) return; + + _deleteMMXreg(MMX_GPR+_Rt_, 2); + _deleteX86reg(X86TYPE_GPR, _Rt_, 2); + _eeOnWriteReg(_Rt_, 0); + + // could 'borrow' the reg + fsreg = _checkXMMreg(XMMTYPE_VFREG, _Fs_, MODE_READ); + + if( fsreg >= 0 ) { + if( xmmregs[fsreg].mode & MODE_WRITE ) + { + _xmmregs temp; + + t0reg = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); + SSEX_MOVDQA_XMM_to_XMM(t0reg, fsreg); + + // change regs + temp = xmmregs[t0reg]; + xmmregs[t0reg] = xmmregs[fsreg]; + xmmregs[fsreg] = temp; + } + else + { + // swap regs + t0reg = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); + + xmmregs[fsreg] = xmmregs[t0reg]; + xmmregs[t0reg].inuse = 0; + } + } + else { + t0reg = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); + + if( t0reg >= 0 ) + SSE_MOVAPS_M128_to_XMM( t0reg, (uptr)&VU0.VF[_Fs_].UD[0]); + else + _recMove128MtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0], (uptr)&VU0.VF[_Fs_].UL[0]); + } + + _clearNeededXMMregs(); +} + +static void recQMTC2(s32 info) +{ + int mmreg; + + if (cpuRegs.code & 1) { + iFlushCall(FLUSH_NOCONST); + CALLFunc((uptr)_vu0WaitMicro); + } + + if (!_Fs_) return; + + mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ); + + if( mmreg >= 0) { + int fsreg = _checkXMMreg(XMMTYPE_VFREG, _Fs_, MODE_WRITE); + int flag = ((xmmregs[mmreg].mode&MODE_WRITE) && (g_pCurInstInfo->regs[_Rt_]&(EEINST_LIVE0|EEINST_LIVE1|EEINST_LIVE2))); + + if( fsreg >= 0 ) { + + if (flag) { + SSE_MOVAPS_XMM_to_XMM(fsreg, mmreg); + } + else { + // swap regs + xmmregs[mmreg] = xmmregs[fsreg]; + xmmregs[mmreg].mode = MODE_WRITE; + xmmregs[fsreg].inuse = 0; + g_xmmtypes[mmreg] = XMMT_FPS; + } + } + else { + if (flag) SSE_MOVAPS_XMM_to_M128((uptr)&cpuRegs.GPR.r[_Rt_], mmreg); + + // swap regs + xmmregs[mmreg].type = XMMTYPE_VFREG; + xmmregs[mmreg].VU = 0; + xmmregs[mmreg].reg = _Fs_; + xmmregs[mmreg].mode = MODE_WRITE; + g_xmmtypes[mmreg] = XMMT_FPS; + } + } + else { + int fsreg = _allocVFtoXMMreg(&VU0, -1, _Fs_, MODE_WRITE); + + if( fsreg >= 0 ) { + mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_READ); + + if( mmreg >= 0) { + SetMMXstate(); + SSE2_MOVQ2DQ_MM_to_XMM(fsreg, mmreg); + SSE_MOVHPS_M64_to_XMM(fsreg, (uptr)&cpuRegs.GPR.r[_Rt_].UL[2]); + } + else { + if( GPR_IS_CONST1( _Rt_ ) ) { + assert( _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ) == -1 ); + _flushConstReg(_Rt_); + } + + SSE_MOVAPS_M128_to_XMM(fsreg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + } + } + else { + _deleteEEreg(_Rt_, 0); + _recMove128MtoM((uptr)&VU0.VF[_Fs_].UL[0], (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); + } + } + + _clearNeededXMMregs(); +} + +// Removed _cop2AnalyzeOp because it was outdated and unreliable (And currently unused). +// A new version should be rebuilt using the SuperVU's AnalyzeOp as a reference. (air) + +////////////////////////////////////////////////////////////////////////// +// BC2: Instructions +////////////////////////////////////////////////////////////////////////// +//REC_COP2_FUNC(BC2F); +//REC_COP2_FUNC(BC2T); +//REC_COP2_FUNC(BC2FL); +//REC_COP2_FUNC(BC2TL); + +using namespace R5900::Dynarec; + +static void _setupBranchTest() +{ + _eeFlushAllUnused(); + + // COP2 branch conditionals are based on the following equation: + // ((VU0.VI[REG_VPU_STAT].US[0] >> 8) & 1) + // BC2F checks if the statement is false, BC2T checks if the statement is true. + + MOV32MtoR( EAX, (uptr)&VU0.VI[REG_VPU_STAT].UL ); + TEST32ItoR( EAX, 0x100 ); +} + +void recBC2F( s32 info ) +{ + _setupBranchTest(); + recDoBranchImm(JNZ32(0)); +} + +void recBC2T( s32 info ) +{ + _setupBranchTest(); + recDoBranchImm(JZ32(0)); +} + +void recBC2FL( s32 info ) +{ + _setupBranchTest(); + recDoBranchImm_Likely(JNZ32(0)); +} + +void recBC2TL( s32 info ) +{ + _setupBranchTest(); + recDoBranchImm_Likely(JZ32(0)); +} + + +////////////////////////////////////////////////////////////////////////// +// Special1 instructions +////////////////////////////////////////////////////////////////////////// +//TODO: redirect all the opcodes to the ivu0micro same functions +REC_COP2_VU0(IADD); +REC_COP2_VU0(IADDI); +REC_COP2_VU0(ISUB); +REC_COP2_VU0(IOR); +REC_COP2_VU0(IAND); +REC_COP2_VU0(OPMSUB); +REC_COP2_VU0(MADDq); +REC_COP2_VU0(MADDi); +REC_COP2_VU0(MSUBq); +REC_COP2_VU0(MSUBi); +REC_COP2_VU0(SUBi); +REC_COP2_VU0(SUBq); +REC_COP2_VU0(MULi); +REC_COP2_VU0(MULq); +REC_COP2_VU0(MAXi); +REC_COP2_VU0(MINIi); +REC_COP2_VU0(MUL); +REC_COP2_VU0(MAX); +REC_COP2_VU0(MADD); +REC_COP2_VU0(MSUB); + +REC_COP2_VU0(MINIx); +REC_COP2_VU0(MINIy); +REC_COP2_VU0(MINIz); +REC_COP2_VU0(MINIw); + +REC_COP2_VU0(MAXx); +REC_COP2_VU0(MAXy); +REC_COP2_VU0(MAXz); +REC_COP2_VU0(MAXw); + +REC_COP2_VU0(MULx); +REC_COP2_VU0(MULy); +REC_COP2_VU0(MULz); +REC_COP2_VU0(MULw); + +REC_COP2_VU0(ADD); +REC_COP2_VU0(ADDi); +REC_COP2_VU0(ADDq); +REC_COP2_VU0(ADDx); +REC_COP2_VU0(ADDy); +REC_COP2_VU0(ADDz); +REC_COP2_VU0(ADDw); + +REC_COP2_VU0(SUBx); +REC_COP2_VU0(SUBy); +REC_COP2_VU0(SUBz); +REC_COP2_VU0(SUBw); + +REC_COP2_VU0(MADDx); +REC_COP2_VU0(MADDy); +REC_COP2_VU0(MADDz); +REC_COP2_VU0(MADDw); + +REC_COP2_VU0(MSUBx); +REC_COP2_VU0(MSUBy); +REC_COP2_VU0(MSUBz); +REC_COP2_VU0(MSUBw); + +REC_COP2_VU0(SUB); +REC_COP2_VU0(MINI); + +////////////////////////////////////////////////////////////////////////// +// Special2 instructions +////////////////////////////////////////////////////////////////////////// + +REC_COP2_VU0(CLIP); +REC_COP2_VU0(LQI); +REC_COP2_VU0(SQI); +REC_COP2_VU0(LQD); +REC_COP2_VU0(SQD); +REC_COP2_VU0(MTIR); +REC_COP2_VU0(MFIR); +REC_COP2_VU0(ILWR); +REC_COP2_VU0(ISWR); +REC_COP2_VU0(RINIT); +REC_COP2_VU0(RXOR); +REC_COP2_VU0(RNEXT); +REC_COP2_VU0(RGET); + +REC_COP2_VU0(ITOF0); +REC_COP2_VU0(ITOF4); +REC_COP2_VU0(ITOF12); +REC_COP2_VU0(ITOF15); +REC_COP2_VU0(FTOI0); +REC_COP2_VU0(FTOI4); +REC_COP2_VU0(FTOI12); +REC_COP2_VU0(FTOI15); +REC_COP2_VU0(MADDA); +REC_COP2_VU0(MSUBA); +REC_COP2_VU0(MADDAi); +REC_COP2_VU0(MADDAq); +REC_COP2_VU0(MADDAx); +REC_COP2_VU0(MADDAy); +REC_COP2_VU0(MADDAz); +REC_COP2_VU0(MADDAw); +REC_COP2_VU0(MSUBAi); +REC_COP2_VU0(MSUBAq); +REC_COP2_VU0(MSUBAx); +REC_COP2_VU0(MSUBAy); +REC_COP2_VU0(MSUBAz); +REC_COP2_VU0(MSUBAw); +REC_COP2_VU0(ADDAi); +REC_COP2_VU0(ADDA); +REC_COP2_VU0(SUBA); +REC_COP2_VU0(MULA); +REC_COP2_VU0(ADDAq); +REC_COP2_VU0(ADDAx); +REC_COP2_VU0(ADDAy); +REC_COP2_VU0(ADDAz); +REC_COP2_VU0(ADDAw); +REC_COP2_VU0(SUBAi); +REC_COP2_VU0(SUBAq); +REC_COP2_VU0(SUBAx); +REC_COP2_VU0(SUBAy); +REC_COP2_VU0(SUBAz); +REC_COP2_VU0(SUBAw); +REC_COP2_VU0(MULAi); +REC_COP2_VU0(MULAq); +REC_COP2_VU0(MULAx); +REC_COP2_VU0(MULAy); +REC_COP2_VU0(MULAz); +REC_COP2_VU0(MULAw); +REC_COP2_VU0(OPMULA); +REC_COP2_VU0(MOVE); +REC_COP2_VU0_Q(DIV); +REC_COP2_VU0_Q(SQRT); +REC_COP2_VU0_Q(RSQRT); +REC_COP2_VU0(MR32); +REC_COP2_VU0(ABS); + +void recVNOP(s32 info){} +void recVWAITQ(s32 info){} +INTERPRETATE_COP2_FUNC(CALLMS); +INTERPRETATE_COP2_FUNC(CALLMSR); + +void _vuRegsCOP2_SPECIAL(VURegs * VU, _VURegsNum *VUregsn); +void _vuRegsCOP2_SPECIAL2(VURegs * VU, _VURegsNum *VUregsn); + +// information +void _vuRegsQMFC2(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->VFread0 = _Fs_; + VUregsn->VFr0xyzw= 0xf; +} + +void _vuRegsCFC2(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->VIread = 1<<_Fs_; +} + +void _vuRegsQMTC2(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->VFwrite = _Fs_; + VUregsn->VFwxyzw= 0xf; +} + +void _vuRegsCTC2(VURegs * VU, _VURegsNum *VUregsn) { + VUregsn->VIwrite = 1<<_Fs_; +} + +void (*_vuRegsCOP2t[32])(VURegs * VU, _VURegsNum *VUregsn) = { + _vuRegs_C2UNK, _vuRegsQMFC2, _vuRegsCFC2, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegsQMTC2, _vuRegsCTC2, _vuRegs_C2UNK, + _vuRegsNOP, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegs_C2UNK, + _vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL, + _vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL,_vuRegsCOP2_SPECIAL, +}; + +void (*_vuRegsCOP2SPECIAL1t[64])(VURegs * VU, _VURegsNum *VUregsn) = { + _vuRegsADDx, _vuRegsADDy, _vuRegsADDz, _vuRegsADDw, _vuRegsSUBx, _vuRegsSUBy, _vuRegsSUBz, _vuRegsSUBw, + _vuRegsMADDx, _vuRegsMADDy, _vuRegsMADDz, _vuRegsMADDw, _vuRegsMSUBx, _vuRegsMSUBy, _vuRegsMSUBz, _vuRegsMSUBw, + _vuRegsMAXx, _vuRegsMAXy, _vuRegsMAXz, _vuRegsMAXw, _vuRegsMINIx, _vuRegsMINIy, _vuRegsMINIz, _vuRegsMINIw, + _vuRegsMULx, _vuRegsMULy, _vuRegsMULz, _vuRegsMULw, _vuRegsMULq, _vuRegsMAXi, _vuRegsMULi, _vuRegsMINIi, + _vuRegsADDq, _vuRegsMADDq, _vuRegsADDi, _vuRegsMADDi, _vuRegsSUBq, _vuRegsMSUBq, _vuRegsSUBi, _vuRegsMSUBi, + _vuRegsADD, _vuRegsMADD, _vuRegsMUL, _vuRegsMAX, _vuRegsSUB, _vuRegsMSUB, _vuRegsOPMSUB, _vuRegsMINI, + _vuRegsIADD, _vuRegsISUB, _vuRegsIADDI, _vuRegs_C2UNK, _vuRegsIAND, _vuRegsIOR, _vuRegs_C2UNK, _vuRegs_C2UNK, + _vuRegsNOP, _vuRegsNOP, _vuRegs_C2UNK, _vuRegs_C2UNK, _vuRegsCOP2_SPECIAL2,_vuRegsCOP2_SPECIAL2,_vuRegsCOP2_SPECIAL2,_vuRegsCOP2_SPECIAL2, +}; + +void (*_vuRegsCOP2SPECIAL2t[128])(VURegs * VU, _VURegsNum *VUregsn) = { + _vuRegsADDAx ,_vuRegsADDAy ,_vuRegsADDAz ,_vuRegsADDAw ,_vuRegsSUBAx ,_vuRegsSUBAy ,_vuRegsSUBAz ,_vuRegsSUBAw, + _vuRegsMADDAx ,_vuRegsMADDAy ,_vuRegsMADDAz ,_vuRegsMADDAw ,_vuRegsMSUBAx ,_vuRegsMSUBAy ,_vuRegsMSUBAz ,_vuRegsMSUBAw, + _vuRegsITOF0 ,_vuRegsITOF4 ,_vuRegsITOF12 ,_vuRegsITOF15 ,_vuRegsFTOI0 ,_vuRegsFTOI4 ,_vuRegsFTOI12 ,_vuRegsFTOI15, + _vuRegsMULAx ,_vuRegsMULAy ,_vuRegsMULAz ,_vuRegsMULAw ,_vuRegsMULAq ,_vuRegsABS ,_vuRegsMULAi ,_vuRegsCLIP, + _vuRegsADDAq ,_vuRegsMADDAq ,_vuRegsADDAi ,_vuRegsMADDAi ,_vuRegsSUBAq ,_vuRegsMSUBAq ,_vuRegsSUBAi ,_vuRegsMSUBAi, + _vuRegsADDA ,_vuRegsMADDA ,_vuRegsMULA ,_vuRegs_C2UNK ,_vuRegsSUBA ,_vuRegsMSUBA ,_vuRegsOPMULA ,_vuRegsNOP, + _vuRegsMOVE ,_vuRegsMR32 ,_vuRegs_C2UNK ,_vuRegs_C2UNK ,_vuRegsLQI ,_vuRegsSQI ,_vuRegsLQD ,_vuRegsSQD, + _vuRegsDIV ,_vuRegsSQRT ,_vuRegsRSQRT ,_vuRegsWAITQ ,_vuRegsMTIR ,_vuRegsMFIR ,_vuRegsILWR ,_vuRegsISWR, + _vuRegsRNEXT ,_vuRegsRGET ,_vuRegsRINIT ,_vuRegsRXOR ,_vuRegs_C2UNK ,_vuRegs_C2UNK ,_vuRegs_C2UNK ,_vuRegs_C2UNK, + _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, + _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, + _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, + _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, + _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, + _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, + _vuRegs_C2UNK ,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK,_vuRegs_C2UNK, +}; + +void _vuRegsCOP22(VURegs * VU, _VURegsNum *VUregsn) +{ + _vuRegsCOP2t[_Rs_](VU, VUregsn); +} + +void _vuRegsCOP2_SPECIAL(VURegs * VU, _VURegsNum *VUregsn) +{ + _vuRegsCOP2SPECIAL1t[_Funct_](VU, VUregsn); +} + +void _vuRegsCOP2_SPECIAL2(VURegs * VU, _VURegsNum *VUregsn) +{ + int opc=(cpuRegs.code & 0x3) | ((cpuRegs.code >> 4) & 0x7c); + _vuRegsCOP2SPECIAL2t[opc](VU, VUregsn); +} + +// recompilation +void (*recCOP2t[32])(s32 info) = { + rec_C2UNK, recQMFC2, recCFC2, rec_C2UNK, rec_C2UNK, recQMTC2, recCTC2, rec_C2UNK, + recCOP2_BC2, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, + recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL, + recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL,recCOP2_SPECIAL, +}; + +void (*recCOP2_BC2t[32])(s32 info) = { + recBC2F, recBC2T, recBC2FL, recBC2TL, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, + rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, + rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, + rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, rec_C2UNK, +}; + +void (*recCOP2SPECIAL1t[64])(s32 info) = { + recVADDx, recVADDy, recVADDz, recVADDw, recVSUBx, recVSUBy, recVSUBz, recVSUBw, + recVMADDx, recVMADDy, recVMADDz, recVMADDw, recVMSUBx, recVMSUBy, recVMSUBz, recVMSUBw, + recVMAXx, recVMAXy, recVMAXz, recVMAXw, recVMINIx, recVMINIy, recVMINIz, recVMINIw, + recVMULx, recVMULy, recVMULz, recVMULw, recVMULq, recVMAXi, recVMULi, recVMINIi, + recVADDq, recVMADDq, recVADDi, recVMADDi, recVSUBq, recVMSUBq, recVSUBi, recVMSUBi, + recVADD, recVMADD, recVMUL, recVMAX, recVSUB, recVMSUB, recVOPMSUB, recVMINI, + recVIADD, recVISUB, recVIADDI, rec_C2UNK, recVIAND, recVIOR, rec_C2UNK, rec_C2UNK, + recVCALLMS, recVCALLMSR, rec_C2UNK, rec_C2UNK, recCOP2_SPECIAL2,recCOP2_SPECIAL2,recCOP2_SPECIAL2,recCOP2_SPECIAL2, +}; + +void (*recCOP2SPECIAL2t[128])(s32 info) = { + recVADDAx ,recVADDAy ,recVADDAz ,recVADDAw ,recVSUBAx ,recVSUBAy ,recVSUBAz ,recVSUBAw, + recVMADDAx ,recVMADDAy ,recVMADDAz ,recVMADDAw ,recVMSUBAx ,recVMSUBAy ,recVMSUBAz ,recVMSUBAw, + recVITOF0 ,recVITOF4 ,recVITOF12 ,recVITOF15 ,recVFTOI0 ,recVFTOI4 ,recVFTOI12 ,recVFTOI15, + recVMULAx ,recVMULAy ,recVMULAz ,recVMULAw ,recVMULAq ,recVABS ,recVMULAi ,recVCLIP, + recVADDAq ,recVMADDAq ,recVADDAi ,recVMADDAi ,recVSUBAq ,recVMSUBAq ,recVSUBAi ,recVMSUBAi, + recVADDA ,recVMADDA ,recVMULA ,rec_C2UNK ,recVSUBA ,recVMSUBA ,recVOPMULA ,recVNOP, + recVMOVE ,recVMR32 ,rec_C2UNK ,rec_C2UNK ,recVLQI ,recVSQI ,recVLQD ,recVSQD, + recVDIV ,recVSQRT ,recVRSQRT ,recVWAITQ ,recVMTIR ,recVMFIR ,recVILWR ,recVISWR, + recVRNEXT ,recVRGET ,recVRINIT ,recVRXOR ,rec_C2UNK ,rec_C2UNK ,rec_C2UNK ,rec_C2UNK, + rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, + rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, + rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, + rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, + rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, + rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, + rec_C2UNK ,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK,rec_C2UNK, +}; + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl +{ + void recCOP2() + { + VU0.code = cpuRegs.code; + + g_pCurInstInfo->vuregs.pipe = 0xff; // to notify eeVURecompileCode that COP2 + s32 info = eeVURecompileCode(&VU0, &g_pCurInstInfo->vuregs); + + info |= PROCESS_VU_COP2; + info |= PROCESS_VU_UPDATEFLAGS; + + recCOP2t[_Rs_]( info ); + + _freeX86regs(); + } +}}} + +void recCOP2_SPECIAL(s32 info ) +{ + recCOP2SPECIAL1t[_Funct_]( info ); +} + +void recCOP2_BC2(s32 info) +{ + recCOP2_BC2t[_Rt_](info); +} + +void recCOP2_SPECIAL2(s32 info) +{ + int opc=(cpuRegs.code & 0x3) | ((cpuRegs.code >> 4) & 0x7c); + recCOP2SPECIAL2t[opc](info); +} + diff --git a/pcsx2/x86/iCore.cpp b/pcsx2/x86/iCore.cpp index c82dfb74c0..5255beb11b 100644 --- a/pcsx2/x86/iCore.cpp +++ b/pcsx2/x86/iCore.cpp @@ -1,1206 +1,1206 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Misc.h" -#include "iR5900.h" -#include "Vif.h" -#include "VU.h" -#include "ix86/ix86.h" -#include "R3000A.h" - -u16 g_x86AllocCounter = 0; -u16 g_xmmAllocCounter = 0; - -EEINST* g_pCurInstInfo = NULL; - -u32 g_cpuRegHasLive1 = 0, g_cpuPrevRegHasLive1 = 0; // set if upper 32 bits are live -u32 g_cpuRegHasSignExt = 0, g_cpuPrevRegHasSignExt = 0; // set if upper 32 bits are the sign extension of the lower integer - -// used to make sure regs don't get changed while in recompiler -// use FreezeMMXRegs, FreezeXMMRegs -u32 g_recWriteback = 0; - -#ifdef _DEBUG -char g_globalXMMLocked = 0; -#endif - -_xmmregs xmmregs[XMMREGS], s_saveXMMregs[XMMREGS]; - -// X86 caching -_x86regs x86regs[X86REGS], s_saveX86regs[X86REGS]; - -#include -using namespace std; - -//void _eeSetLoadStoreReg(int gprreg, u32 offset, int x86reg) -//{ -// int regs[2] = {ESI, EDI}; -// -// int i = _checkX86reg(X86TYPE_MEMOFFSET, gprreg, MODE_WRITE); -// if( i < 0 ) { -// for(i = 0; i < 2; ++i) { -// if( !x86regs[regs[i]].inuse ) break; -// } -// -// assert( i < 2 ); -// i = regs[i]; -// } -// -// if( i != x86reg ) MOV32RtoR(x86reg, i); -// x86regs[i].extra = offset; -//} - -//int _eeGeLoadStoreReg(int gprreg, int* poffset) -//{ -// int i = _checkX86reg(X86TYPE_MEMOFFSET, gprreg, MODE_READ); -// if( i >= 0 ) return -1; -// -// if( poffset ) *poffset = x86regs[i].extra; -// return i; -//} - -// XMM Caching -#define VU_VFx_ADDR(x) (uptr)&VU->VF[x].UL[0] -#define VU_ACCx_ADDR (uptr)&VU->ACC.UL[0] - -static int s_xmmchecknext = 0; - -void _initXMMregs() { - memzero_obj( xmmregs ); - g_xmmAllocCounter = 0; - s_xmmchecknext = 0; -} - -__forceinline void* _XMMGetAddr(int type, int reg, VURegs *VU) -{ - switch (type) { - case XMMTYPE_VFREG: - return (void*)VU_VFx_ADDR(reg); - - case XMMTYPE_ACC: - return (void*)VU_ACCx_ADDR; - - case XMMTYPE_GPRREG: - if( reg < 32 ) - assert( !(g_cpuHasConstReg & (1<regs[xmmregs[i].reg] & (EEINST_LIVE0|EEINST_LIVE1|EEINST_LIVE2)) ) { - _freeXMMreg(i); - return i; - } - } - } - - // check for future xmm usage - for (i=0; iregs[xmmregs[i].reg] & EEINST_XMM) ) { - _freeXMMreg(i); - return i; - } - } - } - - tempi = -1; - bestcount = 0xffff; - for (i=0; i= 0 ) { - // requested specific reg, so return that instead - if( i != xmmreg ) { - if( xmmregs[i].mode & MODE_READ ) readfromreg = i; - //if( xmmregs[i].mode & MODE_WRITE ) mode |= MODE_WRITE; - mode |= xmmregs[i].mode&MODE_WRITE; - xmmregs[i].inuse = 0; - break; - } - } - - xmmregs[i].needed = 1; - - if( !(xmmregs[i].mode & MODE_READ) && (mode&MODE_READ) ) { - SSE_MOVAPS_M128_to_XMM(i, VU_VFx_ADDR(vfreg)); - xmmregs[i].mode |= MODE_READ; - } - - g_xmmtypes[i] = XMMT_FPS; - xmmregs[i].counter = g_xmmAllocCounter++; // update counter - xmmregs[i].mode|= mode; - return i; - } - - if (xmmreg == -1) - xmmreg = _getFreeXMMreg(); - else - _freeXMMreg(xmmreg); - - g_xmmtypes[xmmreg] = XMMT_FPS; - xmmregs[xmmreg].inuse = 1; - xmmregs[xmmreg].type = XMMTYPE_VFREG; - xmmregs[xmmreg].reg = vfreg; - xmmregs[xmmreg].mode = mode; - xmmregs[xmmreg].needed = 1; - xmmregs[xmmreg].VU = XMM_CONV_VU(VU); - xmmregs[xmmreg].counter = g_xmmAllocCounter++; - if (mode & MODE_READ) { - if( readfromreg >= 0 ) SSE_MOVAPS_XMM_to_XMM(xmmreg, readfromreg); - else SSE_MOVAPS_M128_to_XMM(xmmreg, VU_VFx_ADDR(xmmregs[xmmreg].reg)); - } - - return xmmreg; -} - -int _checkXMMreg(int type, int reg, int mode) -{ - int i; - - for (i=0; i= 0 ) { - // requested specific reg, so return that instead - if( i != xmmreg ) { - if( xmmregs[i].mode & MODE_READ ) readfromreg = i; - //if( xmmregs[i].mode & MODE_WRITE ) mode |= MODE_WRITE; - mode |= xmmregs[i].mode&MODE_WRITE; - xmmregs[i].inuse = 0; - break; - } - } - - if( !(xmmregs[i].mode & MODE_READ) && (mode&MODE_READ)) { - SSE_MOVAPS_M128_to_XMM(i, VU_ACCx_ADDR); - xmmregs[i].mode |= MODE_READ; - } - - g_xmmtypes[i] = XMMT_FPS; - xmmregs[i].counter = g_xmmAllocCounter++; // update counter - xmmregs[i].needed = 1; - xmmregs[i].mode|= mode; - return i; - } - - if (xmmreg == -1) - xmmreg = _getFreeXMMreg(); - else - _freeXMMreg(xmmreg); - - g_xmmtypes[xmmreg] = XMMT_FPS; - xmmregs[xmmreg].inuse = 1; - xmmregs[xmmreg].type = XMMTYPE_ACC; - xmmregs[xmmreg].mode = mode; - xmmregs[xmmreg].needed = 1; - xmmregs[xmmreg].VU = XMM_CONV_VU(VU); - xmmregs[xmmreg].counter = g_xmmAllocCounter++; - xmmregs[xmmreg].reg = 0; - - if (mode & MODE_READ) - { - if( readfromreg >= 0 ) - SSE_MOVAPS_XMM_to_XMM(xmmreg, readfromreg); - else - SSE_MOVAPS_M128_to_XMM(xmmreg, VU_ACCx_ADDR); - } - - return xmmreg; -} - -int _allocFPtoXMMreg(int xmmreg, int fpreg, int mode) { - int i; - - for (i=0; i= 0 ) - { - // transfer - SetMMXstate(); - SSE2_MOVQ2DQ_MM_to_XMM(xmmreg, mmxreg); - SSE2_PUNPCKLQDQ_XMM_to_XMM(xmmreg, xmmreg); - SSE2_PUNPCKHQDQ_M128_to_XMM(xmmreg, (u32)&cpuRegs.GPR.r[gprreg].UL[0]); - - if (mmxregs[mmxreg].mode & MODE_WRITE ) - { - // instead of setting to write, just flush to mem - if (!(mode & MODE_WRITE)) - { - SetMMXstate(); - MOVQRtoM((u32)&cpuRegs.GPR.r[gprreg].UL[0], mmxreg); - } - //xmmregs[xmmreg].mode |= MODE_WRITE; - } - - // don't flush - mmxregs[mmxreg].inuse = 0; - } - else - SSEX_MOVDQA_M128_to_XMM(xmmreg, (uptr)&cpuRegs.GPR.r[gprreg].UL[0]); - } - } - else - _deleteMMXreg(MMX_GPR+gprreg, 0); - - return xmmreg; -} - -int _allocFPACCtoXMMreg(int xmmreg, int mode) -{ - int i; - - for (i=0; iregs[xmmregs[i].reg]&EEINST_USED) ) { - return 1; - } - } - } - return 0; -} - -void _moveXMMreg(int xmmreg) -{ - int i; - if( !xmmregs[xmmreg].inuse ) return; - - for (i=0; iregs[gprreg] & EEINST_XMM ) return _allocGPRtoXMMreg(-1, gprreg, mode); - - return _checkXMMreg(XMMTYPE_GPRREG, gprreg, mode); -} - -int _allocCheckFPUtoXMM(EEINST* pinst, int fpureg, int mode) -{ - if( pinst->fpuregs[fpureg] & EEINST_XMM ) return _allocFPtoXMMreg(-1, fpureg, mode); - - return _checkXMMreg(XMMTYPE_FPREG, fpureg, mode); -} - -int _allocCheckGPRtoX86(EEINST* pinst, int gprreg, int mode) -{ - if( pinst->regs[gprreg] & EEINST_USED ) - return _allocX86reg(-1, X86TYPE_GPR, gprreg, mode); - - return _checkX86reg(X86TYPE_GPR, gprreg, mode); -} - -void _recClearInst(EEINST* pinst) -{ - memzero_obj( *pinst ); - memset8_obj( pinst->regs ); - memset8_obj( pinst->fpuregs ); -} - -// returns nonzero value if reg has been written between [startpc, endpc-4] -u32 _recIsRegWritten(EEINST* pinst, int size, u8 xmmtype, u8 reg) -{ - u32 i, inst = 1; - - while(size-- > 0) { - for(i = 0; i < ARRAYSIZE(pinst->writeType); ++i) { - if ((pinst->writeType[i] == xmmtype) && (pinst->writeReg[i] == reg)) - return inst; - } - ++inst; - pinst++; - } - - return 0; -} - -u32 _recIsRegUsed(EEINST* pinst, int size, u8 xmmtype, u8 reg) -{ - u32 i, inst = 1; - while(size-- > 0) { - for(i = 0; i < ARRAYSIZE(pinst->writeType); ++i) { - if( pinst->writeType[i] == xmmtype && pinst->writeReg[i] == reg ) - return inst; - } - for(i = 0; i < ARRAYSIZE(pinst->readType); ++i) { - if( pinst->readType[i] == xmmtype && pinst->readReg[i] == reg ) - return inst; - } - ++inst; - pinst++; - } - - return 0; -} - -void _recFillRegister(EEINST& pinst, int type, int reg, int write) -{ - u32 i = 0; - if (write ) { - for(i = 0; i < ARRAYSIZE(pinst.writeType); ++i) { - if( pinst.writeType[i] == XMMTYPE_TEMP ) { - pinst.writeType[i] = type; - pinst.writeReg[i] = reg; - return; - } - } - assert(0); - } - else { - for(i = 0; i < ARRAYSIZE(pinst.readType); ++i) { - if( pinst.readType[i] == XMMTYPE_TEMP ) { - pinst.readType[i] = type; - pinst.readReg[i] = reg; - return; - } - } - assert(0); - } -} - -void SetMMXstate() { - x86FpuState = MMX_STATE; -} - -//////////////////////////////////////////////////// -//#include "R3000A.h" -//#include "PsxCounters.h" -//#include "PsxMem.h" -//extern tIPU_BP g_BP; - -#if 0 -extern u32 psxdump; -extern void iDumpPsxRegisters(u32 startpc, u32 temp); -extern Counter counters[6]; -extern int rdram_devices; // put 8 for TOOL and 2 for PS2 and PSX -extern int rdram_sdevid; -#endif - -void iDumpRegisters(u32 startpc, u32 temp) -{ -// [TODO] fixme : this code is broken and has no labels. Needs a rewrite to be useful. - -#if 0 - - int i; - const char* pstr;// = temp ? "t" : ""; - const u32 dmacs[] = {0x8000, 0x9000, 0xa000, 0xb000, 0xb400, 0xc000, 0xc400, 0xc800, 0xd000, 0xd400 }; - const char* psymb; - - if (temp) - pstr = "t"; - else - pstr = ""; - - psymb = disR5900GetSym(startpc); - - if( psymb != NULL ) - __Log("%sreg(%s): %x %x c:%x\n", pstr, psymb, startpc, cpuRegs.interrupt, cpuRegs.cycle); - else - __Log("%sreg: %x %x c:%x\n", pstr, startpc, cpuRegs.interrupt, cpuRegs.cycle); - for(i = 1; i < 32; ++i) __Log("%s: %x_%x_%x_%x\n", disRNameGPR[i], cpuRegs.GPR.r[i].UL[3], cpuRegs.GPR.r[i].UL[2], cpuRegs.GPR.r[i].UL[1], cpuRegs.GPR.r[i].UL[0]); - //for(i = 0; i < 32; i+=4) __Log("cp%d: %x_%x_%x_%x\n", i, cpuRegs.CP0.r[i], cpuRegs.CP0.r[i+1], cpuRegs.CP0.r[i+2], cpuRegs.CP0.r[i+3]); - //for(i = 0; i < 32; ++i) __Log("%sf%d: %f %x\n", pstr, i, fpuRegs.fpr[i].f, fpuRegs.fprc[i]); - //for(i = 1; i < 32; ++i) __Log("%svf%d: %f %f %f %f, vi: %x\n", pstr, i, VU0.VF[i].F[3], VU0.VF[i].F[2], VU0.VF[i].F[1], VU0.VF[i].F[0], VU0.VI[i].UL); - for(i = 0; i < 32; ++i) __Log("%sf%d: %x %x\n", pstr, i, fpuRegs.fpr[i].UL, fpuRegs.fprc[i]); - for(i = 1; i < 32; ++i) __Log("%svf%d: %x %x %x %x, vi: %x\n", pstr, i, VU0.VF[i].UL[3], VU0.VF[i].UL[2], VU0.VF[i].UL[1], VU0.VF[i].UL[0], VU0.VI[i].UL); - __Log("%svfACC: %x %x %x %x\n", pstr, VU0.ACC.UL[3], VU0.ACC.UL[2], VU0.ACC.UL[1], VU0.ACC.UL[0]); - __Log("%sLO: %x_%x_%x_%x, HI: %x_%x_%x_%x\n", pstr, cpuRegs.LO.UL[3], cpuRegs.LO.UL[2], cpuRegs.LO.UL[1], cpuRegs.LO.UL[0], - cpuRegs.HI.UL[3], cpuRegs.HI.UL[2], cpuRegs.HI.UL[1], cpuRegs.HI.UL[0]); - __Log("%sCycle: %x %x, Count: %x\n", pstr, cpuRegs.cycle, g_nextBranchCycle, cpuRegs.CP0.n.Count); - iDumpPsxRegisters(psxRegs.pc, temp); - - __Log("f410,30,40: %x %x %x, %d %d\n", psHu32(0xf410), psHu32(0xf430), psHu32(0xf440), rdram_sdevid, rdram_devices); - __Log("cyc11: %x %x; vu0: %x, vu1: %x\n", cpuRegs.sCycle[1], cpuRegs.eCycle[1], VU0.cycle, VU1.cycle); - - __Log("%scounters: %x %x; psx: %x %x\n", pstr, nextsCounter, nextCounter, psxNextsCounter, psxNextCounter); - for(i = 0; i < 4; ++i) { - __Log("eetimer%d: count: %x mode: %x target: %x %x; %x %x; %x %x %x %x\n", i, - counters[i].count, counters[i].mode, counters[i].target, counters[i].hold, counters[i].rate, - counters[i].interrupt, counters[i].Cycle, counters[i].sCycle, counters[i].CycleT, counters[i].sCycleT); - } - __Log("VIF0_STAT = %x, VIF1_STAT = %x\n", psHu32(0x3800), psHu32(0x3C00)); - __Log("ipu %x %x %x %x; bp: %x %x %x %x\n", psHu32(0x2000), psHu32(0x2010), psHu32(0x2020), psHu32(0x2030), g_BP.BP, g_BP.bufferhasnew, g_BP.FP, g_BP.IFC); - __Log("gif: %x %x %x\n", psHu32(0x3000), psHu32(0x3010), psHu32(0x3020)); - for(i = 0; i < ARRAYSIZE(dmacs); ++i) { - DMACh* p = (DMACh*)(PS2MEM_HW+dmacs[i]); - __Log("dma%d c%x m%x q%x t%x s%x\n", i, p->chcr, p->madr, p->qwc, p->tadr, p->sadr); - } - __Log("dmac %x %x %x %x\n", psHu32(DMAC_CTRL), psHu32(DMAC_STAT), psHu32(DMAC_RBSR), psHu32(DMAC_RBOR)); - __Log("intc %x %x\n", psHu32(INTC_STAT), psHu32(INTC_MASK)); - __Log("sif: %x %x %x %x %x\n", psHu32(0xf200), psHu32(0xf220), psHu32(0xf230), psHu32(0xf240), psHu32(0xf260)); -#endif -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Misc.h" +#include "iR5900.h" +#include "Vif.h" +#include "VU.h" +#include "ix86/ix86.h" +#include "R3000A.h" + +u16 g_x86AllocCounter = 0; +u16 g_xmmAllocCounter = 0; + +EEINST* g_pCurInstInfo = NULL; + +u32 g_cpuRegHasLive1 = 0, g_cpuPrevRegHasLive1 = 0; // set if upper 32 bits are live +u32 g_cpuRegHasSignExt = 0, g_cpuPrevRegHasSignExt = 0; // set if upper 32 bits are the sign extension of the lower integer + +// used to make sure regs don't get changed while in recompiler +// use FreezeMMXRegs, FreezeXMMRegs +u32 g_recWriteback = 0; + +#ifdef _DEBUG +char g_globalXMMLocked = 0; +#endif + +_xmmregs xmmregs[XMMREGS], s_saveXMMregs[XMMREGS]; + +// X86 caching +_x86regs x86regs[X86REGS], s_saveX86regs[X86REGS]; + +#include +using namespace std; + +//void _eeSetLoadStoreReg(int gprreg, u32 offset, int x86reg) +//{ +// int regs[2] = {ESI, EDI}; +// +// int i = _checkX86reg(X86TYPE_MEMOFFSET, gprreg, MODE_WRITE); +// if( i < 0 ) { +// for(i = 0; i < 2; ++i) { +// if( !x86regs[regs[i]].inuse ) break; +// } +// +// assert( i < 2 ); +// i = regs[i]; +// } +// +// if( i != x86reg ) MOV32RtoR(x86reg, i); +// x86regs[i].extra = offset; +//} + +//int _eeGeLoadStoreReg(int gprreg, int* poffset) +//{ +// int i = _checkX86reg(X86TYPE_MEMOFFSET, gprreg, MODE_READ); +// if( i >= 0 ) return -1; +// +// if( poffset ) *poffset = x86regs[i].extra; +// return i; +//} + +// XMM Caching +#define VU_VFx_ADDR(x) (uptr)&VU->VF[x].UL[0] +#define VU_ACCx_ADDR (uptr)&VU->ACC.UL[0] + +static int s_xmmchecknext = 0; + +void _initXMMregs() { + memzero_obj( xmmregs ); + g_xmmAllocCounter = 0; + s_xmmchecknext = 0; +} + +__forceinline void* _XMMGetAddr(int type, int reg, VURegs *VU) +{ + switch (type) { + case XMMTYPE_VFREG: + return (void*)VU_VFx_ADDR(reg); + + case XMMTYPE_ACC: + return (void*)VU_ACCx_ADDR; + + case XMMTYPE_GPRREG: + if( reg < 32 ) + assert( !(g_cpuHasConstReg & (1<regs[xmmregs[i].reg] & (EEINST_LIVE0|EEINST_LIVE1|EEINST_LIVE2)) ) { + _freeXMMreg(i); + return i; + } + } + } + + // check for future xmm usage + for (i=0; iregs[xmmregs[i].reg] & EEINST_XMM) ) { + _freeXMMreg(i); + return i; + } + } + } + + tempi = -1; + bestcount = 0xffff; + for (i=0; i= 0 ) { + // requested specific reg, so return that instead + if( i != xmmreg ) { + if( xmmregs[i].mode & MODE_READ ) readfromreg = i; + //if( xmmregs[i].mode & MODE_WRITE ) mode |= MODE_WRITE; + mode |= xmmregs[i].mode&MODE_WRITE; + xmmregs[i].inuse = 0; + break; + } + } + + xmmregs[i].needed = 1; + + if( !(xmmregs[i].mode & MODE_READ) && (mode&MODE_READ) ) { + SSE_MOVAPS_M128_to_XMM(i, VU_VFx_ADDR(vfreg)); + xmmregs[i].mode |= MODE_READ; + } + + g_xmmtypes[i] = XMMT_FPS; + xmmregs[i].counter = g_xmmAllocCounter++; // update counter + xmmregs[i].mode|= mode; + return i; + } + + if (xmmreg == -1) + xmmreg = _getFreeXMMreg(); + else + _freeXMMreg(xmmreg); + + g_xmmtypes[xmmreg] = XMMT_FPS; + xmmregs[xmmreg].inuse = 1; + xmmregs[xmmreg].type = XMMTYPE_VFREG; + xmmregs[xmmreg].reg = vfreg; + xmmregs[xmmreg].mode = mode; + xmmregs[xmmreg].needed = 1; + xmmregs[xmmreg].VU = XMM_CONV_VU(VU); + xmmregs[xmmreg].counter = g_xmmAllocCounter++; + if (mode & MODE_READ) { + if( readfromreg >= 0 ) SSE_MOVAPS_XMM_to_XMM(xmmreg, readfromreg); + else SSE_MOVAPS_M128_to_XMM(xmmreg, VU_VFx_ADDR(xmmregs[xmmreg].reg)); + } + + return xmmreg; +} + +int _checkXMMreg(int type, int reg, int mode) +{ + int i; + + for (i=0; i= 0 ) { + // requested specific reg, so return that instead + if( i != xmmreg ) { + if( xmmregs[i].mode & MODE_READ ) readfromreg = i; + //if( xmmregs[i].mode & MODE_WRITE ) mode |= MODE_WRITE; + mode |= xmmregs[i].mode&MODE_WRITE; + xmmregs[i].inuse = 0; + break; + } + } + + if( !(xmmregs[i].mode & MODE_READ) && (mode&MODE_READ)) { + SSE_MOVAPS_M128_to_XMM(i, VU_ACCx_ADDR); + xmmregs[i].mode |= MODE_READ; + } + + g_xmmtypes[i] = XMMT_FPS; + xmmregs[i].counter = g_xmmAllocCounter++; // update counter + xmmregs[i].needed = 1; + xmmregs[i].mode|= mode; + return i; + } + + if (xmmreg == -1) + xmmreg = _getFreeXMMreg(); + else + _freeXMMreg(xmmreg); + + g_xmmtypes[xmmreg] = XMMT_FPS; + xmmregs[xmmreg].inuse = 1; + xmmregs[xmmreg].type = XMMTYPE_ACC; + xmmregs[xmmreg].mode = mode; + xmmregs[xmmreg].needed = 1; + xmmregs[xmmreg].VU = XMM_CONV_VU(VU); + xmmregs[xmmreg].counter = g_xmmAllocCounter++; + xmmregs[xmmreg].reg = 0; + + if (mode & MODE_READ) + { + if( readfromreg >= 0 ) + SSE_MOVAPS_XMM_to_XMM(xmmreg, readfromreg); + else + SSE_MOVAPS_M128_to_XMM(xmmreg, VU_ACCx_ADDR); + } + + return xmmreg; +} + +int _allocFPtoXMMreg(int xmmreg, int fpreg, int mode) { + int i; + + for (i=0; i= 0 ) + { + // transfer + SetMMXstate(); + SSE2_MOVQ2DQ_MM_to_XMM(xmmreg, mmxreg); + SSE2_PUNPCKLQDQ_XMM_to_XMM(xmmreg, xmmreg); + SSE2_PUNPCKHQDQ_M128_to_XMM(xmmreg, (u32)&cpuRegs.GPR.r[gprreg].UL[0]); + + if (mmxregs[mmxreg].mode & MODE_WRITE ) + { + // instead of setting to write, just flush to mem + if (!(mode & MODE_WRITE)) + { + SetMMXstate(); + MOVQRtoM((u32)&cpuRegs.GPR.r[gprreg].UL[0], mmxreg); + } + //xmmregs[xmmreg].mode |= MODE_WRITE; + } + + // don't flush + mmxregs[mmxreg].inuse = 0; + } + else + SSEX_MOVDQA_M128_to_XMM(xmmreg, (uptr)&cpuRegs.GPR.r[gprreg].UL[0]); + } + } + else + _deleteMMXreg(MMX_GPR+gprreg, 0); + + return xmmreg; +} + +int _allocFPACCtoXMMreg(int xmmreg, int mode) +{ + int i; + + for (i=0; iregs[xmmregs[i].reg]&EEINST_USED) ) { + return 1; + } + } + } + return 0; +} + +void _moveXMMreg(int xmmreg) +{ + int i; + if( !xmmregs[xmmreg].inuse ) return; + + for (i=0; iregs[gprreg] & EEINST_XMM ) return _allocGPRtoXMMreg(-1, gprreg, mode); + + return _checkXMMreg(XMMTYPE_GPRREG, gprreg, mode); +} + +int _allocCheckFPUtoXMM(EEINST* pinst, int fpureg, int mode) +{ + if( pinst->fpuregs[fpureg] & EEINST_XMM ) return _allocFPtoXMMreg(-1, fpureg, mode); + + return _checkXMMreg(XMMTYPE_FPREG, fpureg, mode); +} + +int _allocCheckGPRtoX86(EEINST* pinst, int gprreg, int mode) +{ + if( pinst->regs[gprreg] & EEINST_USED ) + return _allocX86reg(-1, X86TYPE_GPR, gprreg, mode); + + return _checkX86reg(X86TYPE_GPR, gprreg, mode); +} + +void _recClearInst(EEINST* pinst) +{ + memzero_obj( *pinst ); + memset8_obj( pinst->regs ); + memset8_obj( pinst->fpuregs ); +} + +// returns nonzero value if reg has been written between [startpc, endpc-4] +u32 _recIsRegWritten(EEINST* pinst, int size, u8 xmmtype, u8 reg) +{ + u32 i, inst = 1; + + while(size-- > 0) { + for(i = 0; i < ARRAYSIZE(pinst->writeType); ++i) { + if ((pinst->writeType[i] == xmmtype) && (pinst->writeReg[i] == reg)) + return inst; + } + ++inst; + pinst++; + } + + return 0; +} + +u32 _recIsRegUsed(EEINST* pinst, int size, u8 xmmtype, u8 reg) +{ + u32 i, inst = 1; + while(size-- > 0) { + for(i = 0; i < ARRAYSIZE(pinst->writeType); ++i) { + if( pinst->writeType[i] == xmmtype && pinst->writeReg[i] == reg ) + return inst; + } + for(i = 0; i < ARRAYSIZE(pinst->readType); ++i) { + if( pinst->readType[i] == xmmtype && pinst->readReg[i] == reg ) + return inst; + } + ++inst; + pinst++; + } + + return 0; +} + +void _recFillRegister(EEINST& pinst, int type, int reg, int write) +{ + u32 i = 0; + if (write ) { + for(i = 0; i < ARRAYSIZE(pinst.writeType); ++i) { + if( pinst.writeType[i] == XMMTYPE_TEMP ) { + pinst.writeType[i] = type; + pinst.writeReg[i] = reg; + return; + } + } + assert(0); + } + else { + for(i = 0; i < ARRAYSIZE(pinst.readType); ++i) { + if( pinst.readType[i] == XMMTYPE_TEMP ) { + pinst.readType[i] = type; + pinst.readReg[i] = reg; + return; + } + } + assert(0); + } +} + +void SetMMXstate() { + x86FpuState = MMX_STATE; +} + +//////////////////////////////////////////////////// +//#include "R3000A.h" +//#include "PsxCounters.h" +//#include "PsxMem.h" +//extern tIPU_BP g_BP; + +#if 0 +extern u32 psxdump; +extern void iDumpPsxRegisters(u32 startpc, u32 temp); +extern Counter counters[6]; +extern int rdram_devices; // put 8 for TOOL and 2 for PS2 and PSX +extern int rdram_sdevid; +#endif + +void iDumpRegisters(u32 startpc, u32 temp) +{ +// [TODO] fixme : this code is broken and has no labels. Needs a rewrite to be useful. + +#if 0 + + int i; + const char* pstr;// = temp ? "t" : ""; + const u32 dmacs[] = {0x8000, 0x9000, 0xa000, 0xb000, 0xb400, 0xc000, 0xc400, 0xc800, 0xd000, 0xd400 }; + const char* psymb; + + if (temp) + pstr = "t"; + else + pstr = ""; + + psymb = disR5900GetSym(startpc); + + if( psymb != NULL ) + __Log("%sreg(%s): %x %x c:%x\n", pstr, psymb, startpc, cpuRegs.interrupt, cpuRegs.cycle); + else + __Log("%sreg: %x %x c:%x\n", pstr, startpc, cpuRegs.interrupt, cpuRegs.cycle); + for(i = 1; i < 32; ++i) __Log("%s: %x_%x_%x_%x\n", disRNameGPR[i], cpuRegs.GPR.r[i].UL[3], cpuRegs.GPR.r[i].UL[2], cpuRegs.GPR.r[i].UL[1], cpuRegs.GPR.r[i].UL[0]); + //for(i = 0; i < 32; i+=4) __Log("cp%d: %x_%x_%x_%x\n", i, cpuRegs.CP0.r[i], cpuRegs.CP0.r[i+1], cpuRegs.CP0.r[i+2], cpuRegs.CP0.r[i+3]); + //for(i = 0; i < 32; ++i) __Log("%sf%d: %f %x\n", pstr, i, fpuRegs.fpr[i].f, fpuRegs.fprc[i]); + //for(i = 1; i < 32; ++i) __Log("%svf%d: %f %f %f %f, vi: %x\n", pstr, i, VU0.VF[i].F[3], VU0.VF[i].F[2], VU0.VF[i].F[1], VU0.VF[i].F[0], VU0.VI[i].UL); + for(i = 0; i < 32; ++i) __Log("%sf%d: %x %x\n", pstr, i, fpuRegs.fpr[i].UL, fpuRegs.fprc[i]); + for(i = 1; i < 32; ++i) __Log("%svf%d: %x %x %x %x, vi: %x\n", pstr, i, VU0.VF[i].UL[3], VU0.VF[i].UL[2], VU0.VF[i].UL[1], VU0.VF[i].UL[0], VU0.VI[i].UL); + __Log("%svfACC: %x %x %x %x\n", pstr, VU0.ACC.UL[3], VU0.ACC.UL[2], VU0.ACC.UL[1], VU0.ACC.UL[0]); + __Log("%sLO: %x_%x_%x_%x, HI: %x_%x_%x_%x\n", pstr, cpuRegs.LO.UL[3], cpuRegs.LO.UL[2], cpuRegs.LO.UL[1], cpuRegs.LO.UL[0], + cpuRegs.HI.UL[3], cpuRegs.HI.UL[2], cpuRegs.HI.UL[1], cpuRegs.HI.UL[0]); + __Log("%sCycle: %x %x, Count: %x\n", pstr, cpuRegs.cycle, g_nextBranchCycle, cpuRegs.CP0.n.Count); + iDumpPsxRegisters(psxRegs.pc, temp); + + __Log("f410,30,40: %x %x %x, %d %d\n", psHu32(0xf410), psHu32(0xf430), psHu32(0xf440), rdram_sdevid, rdram_devices); + __Log("cyc11: %x %x; vu0: %x, vu1: %x\n", cpuRegs.sCycle[1], cpuRegs.eCycle[1], VU0.cycle, VU1.cycle); + + __Log("%scounters: %x %x; psx: %x %x\n", pstr, nextsCounter, nextCounter, psxNextsCounter, psxNextCounter); + for(i = 0; i < 4; ++i) { + __Log("eetimer%d: count: %x mode: %x target: %x %x; %x %x; %x %x %x %x\n", i, + counters[i].count, counters[i].mode, counters[i].target, counters[i].hold, counters[i].rate, + counters[i].interrupt, counters[i].Cycle, counters[i].sCycle, counters[i].CycleT, counters[i].sCycleT); + } + __Log("VIF0_STAT = %x, VIF1_STAT = %x\n", psHu32(0x3800), psHu32(0x3C00)); + __Log("ipu %x %x %x %x; bp: %x %x %x %x\n", psHu32(0x2000), psHu32(0x2010), psHu32(0x2020), psHu32(0x2030), g_BP.BP, g_BP.bufferhasnew, g_BP.FP, g_BP.IFC); + __Log("gif: %x %x %x\n", psHu32(0x3000), psHu32(0x3010), psHu32(0x3020)); + for(i = 0; i < ARRAYSIZE(dmacs); ++i) { + DMACh* p = (DMACh*)(PS2MEM_HW+dmacs[i]); + __Log("dma%d c%x m%x q%x t%x s%x\n", i, p->chcr, p->madr, p->qwc, p->tadr, p->sadr); + } + __Log("dmac %x %x %x %x\n", psHu32(DMAC_CTRL), psHu32(DMAC_STAT), psHu32(DMAC_RBSR), psHu32(DMAC_RBOR)); + __Log("intc %x %x\n", psHu32(INTC_STAT), psHu32(INTC_MASK)); + __Log("sif: %x %x %x %x %x\n", psHu32(0xf200), psHu32(0xf220), psHu32(0xf230), psHu32(0xf240), psHu32(0xf260)); +#endif +} diff --git a/pcsx2/x86/iCore.h b/pcsx2/x86/iCore.h index b0d28d884f..18bb25c137 100644 --- a/pcsx2/x86/iCore.h +++ b/pcsx2/x86/iCore.h @@ -1,429 +1,429 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef _PCSX2_CORE_RECOMPILER_ -#define _PCSX2_CORE_RECOMPILER_ - -#include "ix86/ix86.h" -#include "iVUmicro.h" - -// Namespace Note : iCore32 contains all of the Register Allocation logic, in addition to a handful -// of utility functions for emitting frequent code. - -//////////////////////////////////////////////////////////////////////////////// -// Shared Register allocation flags (apply to X86, XMM, MMX, etc). - -#define MODE_READ 1 -#define MODE_WRITE 2 -#define MODE_READHALF 4 // read only low 64 bits -#define MODE_VUXY 0x8 // vector only has xy valid (real zw are in mem), not the same as MODE_READHALF -#define MODE_VUZ 0x10 // z only doesn't work for now -#define MODE_VUXYZ (MODE_VUZ|MODE_VUXY) // vector only has xyz valid (real w is in memory) -#define MODE_NOFLUSH 0x20 // can't flush reg to mem -#define MODE_NOFRAME 0x40 // when allocating x86regs, don't use ebp reg -#define MODE_8BITREG 0x80 // when allocating x86regs, use only eax, ecx, edx, and ebx - -#define PROCESS_EE_MMX 0x01 -#define PROCESS_EE_XMM 0x02 - -// currently only used in FPU -#define PROCESS_EE_S 0x04 // S is valid, otherwise take from mem -#define PROCESS_EE_T 0x08 // T is valid, otherwise take from mem - -// not used in VU recs -#define PROCESS_EE_MODEWRITES 0x10 // if s is a reg, set if not in cpuRegs -#define PROCESS_EE_MODEWRITET 0x20 // if t is a reg, set if not in cpuRegs -#define PROCESS_EE_LO 0x40 // lo reg is valid -#define PROCESS_EE_HI 0x80 // hi reg is valid -#define PROCESS_EE_ACC 0x40 // acc reg is valid - -// used in VU recs -#define PROCESS_VU_UPDATEFLAGS 0x10 -#define PROCESS_VU_SUPER 0x40 // set if using supervu recompilation -#define PROCESS_VU_COP2 0x80 // simple cop2 - -#define EEREC_S (((info)>>8)&0xf) -#define EEREC_T (((info)>>12)&0xf) -#define EEREC_D (((info)>>16)&0xf) -#define EEREC_LO (((info)>>20)&0xf) -#define EEREC_HI (((info)>>24)&0xf) -#define EEREC_ACC (((info)>>20)&0xf) -#define EEREC_TEMP (((info)>>24)&0xf) -#define VUREC_FMAC ((info)&0x80000000) - -#define PROCESS_EE_SET_S(reg) ((reg)<<8) -#define PROCESS_EE_SET_T(reg) ((reg)<<12) -#define PROCESS_EE_SET_D(reg) ((reg)<<16) -#define PROCESS_EE_SET_LO(reg) ((reg)<<20) -#define PROCESS_EE_SET_HI(reg) ((reg)<<24) -#define PROCESS_EE_SET_ACC(reg) ((reg)<<20) - -#define PROCESS_VU_SET_ACC(reg) PROCESS_EE_SET_ACC(reg) -#define PROCESS_VU_SET_TEMP(reg) ((reg)<<24) - -#define PROCESS_VU_SET_FMAC() 0x80000000 - -// special info not related to above flags -#define PROCESS_CONSTS 1 -#define PROCESS_CONSTT 2 - -//////////////////////////////////////////////////////////////////////////////// -// X86 (32-bit) Register Allocation Tools - -#define X86TYPE_TEMP 0 -#define X86TYPE_GPR 1 -#define X86TYPE_VI 2 -#define X86TYPE_MEMOFFSET 3 -#define X86TYPE_VIMEMOFFSET 4 -#define X86TYPE_VUQREAD 5 -#define X86TYPE_VUPREAD 6 -#define X86TYPE_VUQWRITE 7 -#define X86TYPE_VUPWRITE 8 -#define X86TYPE_PSX 9 -#define X86TYPE_PCWRITEBACK 10 -#define X86TYPE_VUJUMP 12 // jump from random mem (g_recWriteback) -#define X86TYPE_VITEMP 13 -#define X86TYPE_FNARG 14 // function parameter, max is 4 - -#define X86TYPE_VU1 0x80 - -#define X86_ISVI(type) ((type&~X86TYPE_VU1) == X86TYPE_VI) - -struct _x86regs { - u8 inuse; - u8 reg; // value of 0 - not used - u8 mode; - u8 needed; - u8 type; // X86TYPE_ - u16 counter; - u32 extra; // extra info assoc with the reg -}; - -extern _x86regs x86regs[X86REGS], s_saveX86regs[X86REGS]; - -uptr _x86GetAddr(int type, int reg); -void _initX86regs(); -int _getFreeX86reg(int mode); -int _allocX86reg(int x86reg, int type, int reg, int mode); -void _deleteX86reg(int type, int reg, int flush); -int _checkX86reg(int type, int reg, int mode); -void _addNeededX86reg(int type, int reg); -void _clearNeededX86regs(); -void _freeX86reg(int x86reg); -void _flushX86regs(); -void _freeX86regs(); -void _freeX86tempregs(); -u8 _hasFreeX86reg(); -void _flushCachedRegs(); -void _flushConstRegs(); -void _flushConstReg(int reg); - -//////////////////////////////////////////////////////////////////////////////// -// XMM (128-bit) Register Allocation Tools - -#define XMM_CONV_VU(VU) (VU==&VU1) - -#define XMMTYPE_TEMP 0 // has to be 0 -#define XMMTYPE_VFREG 1 -#define XMMTYPE_ACC 2 -#define XMMTYPE_FPREG 3 -#define XMMTYPE_FPACC 4 -#define XMMTYPE_GPRREG 5 - -// lo and hi regs -#define XMMGPR_LO 33 -#define XMMGPR_HI 32 -#define XMMFPU_ACC 32 - -struct _xmmregs { - u8 inuse; - u8 reg; - u8 type; - u8 mode; - u8 needed; - u8 VU; // 0 = VU0, 1 = VU1 - u16 counter; -}; - -void _initXMMregs(); -int _getFreeXMMreg(); -int _allocTempXMMreg(XMMSSEType type, int xmmreg); -int _allocVFtoXMMreg(VURegs *VU, int xmmreg, int vfreg, int mode); -int _allocFPtoXMMreg(int xmmreg, int fpreg, int mode); -int _allocGPRtoXMMreg(int xmmreg, int gprreg, int mode); -int _allocACCtoXMMreg(VURegs *VU, int xmmreg, int mode); -int _allocFPACCtoXMMreg(int xmmreg, int mode); -int _checkXMMreg(int type, int reg, int mode); -void _addNeededVFtoXMMreg(int vfreg); -void _addNeededACCtoXMMreg(); -void _addNeededFPtoXMMreg(int fpreg); -void _addNeededFPACCtoXMMreg(); -void _addNeededGPRtoXMMreg(int gprreg); -void _clearNeededXMMregs(); -void _deleteVFtoXMMreg(int reg, int vu, int flush); -void _deleteACCtoXMMreg(int vu, int flush); -void _deleteGPRtoXMMreg(int reg, int flush); -void _deleteFPtoXMMreg(int reg, int flush); -void _freeXMMreg(int xmmreg); -void _moveXMMreg(int xmmreg); // instead of freeing, moves it to a diff location -void _flushXMMregs(); -u8 _hasFreeXMMreg(); -void _freeXMMregs(); -int _getNumXMMwrite(); - -// uses MEM_MMXTAG/MEM_XMMTAG to differentiate between the regs -void _recPushReg(int mmreg); -void _signExtendSFtoM(u32 mem); - -// returns new index of reg, lower 32 bits already in mmx -// shift is used when the data is in the top bits of the mmx reg to begin with -// a negative shift is for sign extension -int _signExtendXMMtoM(u32 to, x86SSERegType from, int candestroy); // returns true if reg destroyed - -// Defines for passing register info - -// only valid during writes. If write128, then upper 64bits are in an mmxreg -// (mmreg&0xf). Constant is used from gprreg ((mmreg>>16)&0x1f) -#define MEM_EECONSTTAG 0x0100 // argument is a GPR and comes from g_cpuConstRegs -#define MEM_PSXCONSTTAG 0x0200 -#define MEM_MEMORYTAG 0x0400 -#define MEM_MMXTAG 0x0800 // mmreg is mmxreg -#define MEM_XMMTAG 0x8000 // mmreg is xmmreg -#define MEM_X86TAG 0x4000 // ignored most of the time -#define MEM_GPRTAG 0x2000 // argument is a GPR reg -#define MEM_CONSTTAG 0x1000 // argument is a const - -#define IS_EECONSTREG(reg) (reg>=0&&((reg)&MEM_EECONSTTAG)) -#define IS_PSXCONSTREG(reg) (reg>=0&&((reg)&MEM_PSXCONSTTAG)) -#define IS_MMXREG(reg) (reg>=0&&((reg)&MEM_MMXTAG)) -#define IS_XMMREG(reg) (reg>=0&&((reg)&MEM_XMMTAG)) - -// fixme - these 4 are only called for u32 registers; should the reg>=0 really be there? -#define IS_X86REG(reg) (reg>=0&&((reg)&MEM_X86TAG)) -#define IS_GPRREG(reg) (reg>=0&&((reg)&MEM_GPRTAG)) -#define IS_CONSTREG(reg) (reg>=0&&((reg)&MEM_CONSTTAG)) -#define IS_MEMORYREG(reg) (reg>=0&&((reg)&MEM_MEMORYTAG)) - -////////////////////// -// Instruction Info // -////////////////////// -#define EEINST_LIVE0 1 // if var is ever used (read or write) -#define EEINST_LIVE1 2 // if cur var's next 32 bits are needed -#define EEINST_LIVE2 4 // if cur var's next 64 bits are needed -#define EEINST_LASTUSE 8 // if var isn't written/read anymore -#define EEINST_MMX 0x10 // var will be used in mmx ops -#define EEINST_XMM 0x20 // var will be used in xmm ops (takes precedence -#define EEINST_USED 0x40 - -#define EEINSTINFO_COP1 1 -#define EEINSTINFO_COP2 2 -#ifdef PCSX2_VM_COISSUE -#define EEINSTINFO_NOREC 4 // if set, inst is recompiled alone -#define EEINSTINFO_COREC 8 // if set, inst is recompiled with another similar inst -#endif -#define EEINSTINFO_MMX EEINST_MMX -#define EEINSTINFO_XMM EEINST_XMM - -struct EEINST -{ - u8 regs[34]; // includes HI/LO (HI=32, LO=33) - u8 fpuregs[33]; // ACC=32 - u8 info; // extra info, if 1 inst is COP1, 2 inst is COP2. Also uses EEINST_MMX|EEINST_XMM - - // uses XMMTYPE_ flags; if type == XMMTYPE_TEMP, not used - u8 writeType[3], writeReg[3]; // reg written in this inst, 0 if no reg - u8 readType[4], readReg[4]; - - // valid if info & EEINSTINFO_COP2 - int cycle; // cycle of inst (at offset from block) - _VURegsNum vuregs; - - u8 numpeeps; // number of peephole optimizations -}; - -extern EEINST* g_pCurInstInfo; // info for the cur instruction -extern void _recClearInst(EEINST* pinst); - -// returns the number of insts + 1 until written (0 if not written) -extern u32 _recIsRegWritten(EEINST* pinst, int size, u8 xmmtype, u8 reg); -// returns the number of insts + 1 until used (0 if not used) -extern u32 _recIsRegUsed(EEINST* pinst, int size, u8 xmmtype, u8 reg); -extern void _recFillRegister(EEINST& pinst, int type, int reg, int write); - -#define EEINST_ISLIVE64(reg) (g_pCurInstInfo->regs[reg] & (EEINST_LIVE0|EEINST_LIVE1)) -#define EEINST_ISLIVEXMM(reg) (g_pCurInstInfo->regs[reg] & (EEINST_LIVE0|EEINST_LIVE1|EEINST_LIVE2)) -#define EEINST_ISLIVE1(reg) (g_pCurInstInfo->regs[reg] & EEINST_LIVE1) -#define EEINST_ISLIVE2(reg) (g_pCurInstInfo->regs[reg] & EEINST_LIVE2) - -#define FPUINST_ISLIVE(reg) (g_pCurInstInfo->fpuregs[reg] & EEINST_LIVE0) -#define FPUINST_LASTUSE(reg) (g_pCurInstInfo->fpuregs[reg] & EEINST_LASTUSE) - -// if set, then the variable at this inst really has its upper 32 bits valid -// The difference between EEINST_LIVE1 is that the latter is used in back propagation -// The former is set at recompile time. -#define EEINST_RESETHASLIVE1(reg) { if( (reg) < 32 ) g_cpuRegHasLive1 &= ~(1<<(reg)); } -#define EEINST_HASLIVE1(reg) (g_cpuPrevRegHasLive1&(1<<(reg))) - -#define EEINST_SETSIGNEXT(reg) { if( (reg) < 32 ) g_cpuRegHasSignExt |= (1<<(reg)); } -#define EEINST_RESETSIGNEXT(reg) { if( (reg) < 32 ) g_cpuRegHasSignExt &= ~(1<<(reg)); } -#define EEINST_ISSIGNEXT(reg) (g_cpuPrevRegHasSignExt&(1<<(reg))) - -extern u32 g_recWriteback; // used for jumps (VUrec mess!) -extern u32 g_cpuRegHasLive1, g_cpuPrevRegHasLive1; -extern u32 g_cpuRegHasSignExt, g_cpuPrevRegHasSignExt; - -extern _xmmregs xmmregs[XMMREGS], s_saveXMMregs[XMMREGS]; - -extern u16 g_x86AllocCounter; -extern u16 g_xmmAllocCounter; - -#ifdef _DEBUG -extern char g_globalXMMLocked; -#endif - -// allocates only if later insts use XMM, otherwise checks -int _allocCheckGPRtoXMM(EEINST* pinst, int gprreg, int mode); -int _allocCheckFPUtoXMM(EEINST* pinst, int fpureg, int mode); - -// allocates only if later insts use this register -int _allocCheckGPRtoX86(EEINST* pinst, int gprreg, int mode); - -//////////////////////////////////////////////////////////////////////////////// -// MMX (64-bit) Register Allocation Tools - -#define FPU_STATE 0 -#define MMX_STATE 1 - -void SetMMXstate(); -void SetFPUstate(); - -// max is 0x7f, when 0x80 is set, need to flush reg -#define MMX_GET_CACHE(ptr, index) ((u8*)ptr)[index] -#define MMX_SET_CACHE(ptr, ind3, ind2, ind1, ind0) ((u32*)ptr)[0] = (ind3<<24)|(ind2<<16)|(ind1<<8)|ind0; -#define MMX_GPR 0 -#define MMX_HI XMMGPR_HI -#define MMX_LO XMMGPR_LO -#define MMX_FPUACC 34 -#define MMX_FPU 64 -#define MMX_COP0 96 -#define MMX_TEMP 0x7f - -#define MMX_IS32BITS(x) (((x)>=MMX_FPU&&(x)= MMX_GPR && (x) < MMX_GPR+34) - -struct _mmxregs { - u8 inuse; - u8 reg; // value of 0 - not used - u8 mode; - u8 needed; - u16 counter; -}; - -void _initMMXregs(); -int _getFreeMMXreg(); -int _allocMMXreg(int MMXreg, int reg, int mode); -void _addNeededMMXreg(int reg); -int _checkMMXreg(int reg, int mode); -void _clearNeededMMXregs(); -void _deleteMMXreg(int reg, int flush); -void _freeMMXreg(int mmxreg); -void _moveMMXreg(int mmxreg); // instead of freeing, moves it to a diff location -void _flushMMXregs(); -u8 _hasFreeMMXreg(); -void _freeMMXregs(); -int _getNumMMXwrite(); - -int _signExtendMtoMMX(x86MMXRegType to, u32 mem); -int _signExtendGPRMMXtoMMX(x86MMXRegType to, u32 gprreg, x86MMXRegType from, u32 gprfromreg); -int _allocCheckGPRtoMMX(EEINST* pinst, int reg, int mode); - -void _recMove128RmOffsettoM(u32 to, u32 offset); -void _recMove128MtoRmOffset(u32 offset, u32 from); - -// returns new index of reg, lower 32 bits already in mmx -// shift is used when the data is in the top bits of the mmx reg to begin with -// a negative shift is for sign extension -extern int _signExtendGPRtoMMX(x86MMXRegType to, u32 gprreg, int shift); - -extern _mmxregs mmxregs[MMXREGS], s_saveMMXregs[MMXREGS]; -extern u16 x86FpuState, iCWstate; - -extern void iDumpRegisters(u32 startpc, u32 temp); - -////////////////////////////////////////////////////////////////////////// -// iFlushCall / _psxFlushCall Parameters - -// Flushing vs. Freeing, as understood by Air (I could be wrong still....) - -// "Freeing" registers means that the contents of the registers are flushed to memory. -// This is good for any sort of C code function that plans to modify the actual -// registers. When the Recs resume, they'll reload the registers with values saved -// as needed. (similar to a "FreezeXMMRegs") - -// "Flushing" means that in addition to the standard free (which is actually a flush) -// the register allocations are additionally wiped. This should only be necessary if -// the code being called is going to modify register allocations -- ie, be doing -// some kind of recompiling of its own. - -#define FLUSH_CACHED_REGS 1 -#define FLUSH_FLUSH_XMM 2 -#define FLUSH_FREE_XMM 4 // both flushes and frees -#define FLUSH_FLUSH_MMX 8 -#define FLUSH_FREE_MMX 16 // both flushes and frees -#define FLUSH_FLUSH_ALLX86 32 // flush x86 -#define FLUSH_FREE_TEMPX86 64 // flush and free temporary x86 regs -#define FLUSH_FREE_ALLX86 128 // free all x86 regs -#define FLUSH_FREE_VU0 0x100 // free all vu0 related regs - -#define FLUSH_EVERYTHING 0xfff -// no freeing, used when callee won't destroy mmx/xmm regs -#define FLUSH_NODESTROY (FLUSH_CACHED_REGS|FLUSH_FLUSH_XMM|FLUSH_FLUSH_MMX|FLUSH_FLUSH_ALLX86) -// used when regs aren't going to be changed be callee -#define FLUSH_NOCONST (FLUSH_FREE_XMM|FLUSH_FREE_MMX|FLUSH_FREE_TEMPX86) - - -////////////////////////////////////////////////////////////////////////// -// Utility Functions -- that should probably be part of the Emitter. - -// see MEM_X defines for argX format -extern void _callPushArg(u32 arg, uptr argmem); /// X86ARG is ignored for 32bit recs -extern void _callFunctionArg1(uptr fn, u32 arg1, uptr arg1mem); -extern void _callFunctionArg2(uptr fn, u32 arg1, u32 arg2, uptr arg1mem, uptr arg2mem); -extern void _callFunctionArg3(uptr fn, u32 arg1, u32 arg2, u32 arg3, uptr arg1mem, uptr arg2mem, uptr arg3mem); - -// Moves 128 bits of data using EAX/EDX (used by iCOP2 only currently) -extern void _recMove128MtoM(u32 to, u32 from); - -// op = 0, and -// op = 1, or -// op = 2, xor -// op = 3, nor (the 32bit versoins only do OR) -extern void LogicalOpRtoR(x86MMXRegType to, x86MMXRegType from, int op); -extern void LogicalOpMtoR(x86MMXRegType to, u32 from, int op); - -extern void LogicalOp32RtoM(uptr to, x86IntRegType from, int op); -extern void LogicalOp32MtoR(x86IntRegType to, uptr from, int op); -extern void LogicalOp32ItoR(x86IntRegType to, u32 from, int op); -extern void LogicalOp32ItoM(uptr to, u32 from, int op); - -#ifdef ARITHMETICIMM_RECOMPILE -extern void LogicalOpRtoR(x86MMXRegType to, x86MMXRegType from, int op); -extern void LogicalOpMtoR(x86MMXRegType to, u32 from, int op); -#endif - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef _PCSX2_CORE_RECOMPILER_ +#define _PCSX2_CORE_RECOMPILER_ + +#include "ix86/ix86.h" +#include "iVUmicro.h" + +// Namespace Note : iCore32 contains all of the Register Allocation logic, in addition to a handful +// of utility functions for emitting frequent code. + +//////////////////////////////////////////////////////////////////////////////// +// Shared Register allocation flags (apply to X86, XMM, MMX, etc). + +#define MODE_READ 1 +#define MODE_WRITE 2 +#define MODE_READHALF 4 // read only low 64 bits +#define MODE_VUXY 0x8 // vector only has xy valid (real zw are in mem), not the same as MODE_READHALF +#define MODE_VUZ 0x10 // z only doesn't work for now +#define MODE_VUXYZ (MODE_VUZ|MODE_VUXY) // vector only has xyz valid (real w is in memory) +#define MODE_NOFLUSH 0x20 // can't flush reg to mem +#define MODE_NOFRAME 0x40 // when allocating x86regs, don't use ebp reg +#define MODE_8BITREG 0x80 // when allocating x86regs, use only eax, ecx, edx, and ebx + +#define PROCESS_EE_MMX 0x01 +#define PROCESS_EE_XMM 0x02 + +// currently only used in FPU +#define PROCESS_EE_S 0x04 // S is valid, otherwise take from mem +#define PROCESS_EE_T 0x08 // T is valid, otherwise take from mem + +// not used in VU recs +#define PROCESS_EE_MODEWRITES 0x10 // if s is a reg, set if not in cpuRegs +#define PROCESS_EE_MODEWRITET 0x20 // if t is a reg, set if not in cpuRegs +#define PROCESS_EE_LO 0x40 // lo reg is valid +#define PROCESS_EE_HI 0x80 // hi reg is valid +#define PROCESS_EE_ACC 0x40 // acc reg is valid + +// used in VU recs +#define PROCESS_VU_UPDATEFLAGS 0x10 +#define PROCESS_VU_SUPER 0x40 // set if using supervu recompilation +#define PROCESS_VU_COP2 0x80 // simple cop2 + +#define EEREC_S (((info)>>8)&0xf) +#define EEREC_T (((info)>>12)&0xf) +#define EEREC_D (((info)>>16)&0xf) +#define EEREC_LO (((info)>>20)&0xf) +#define EEREC_HI (((info)>>24)&0xf) +#define EEREC_ACC (((info)>>20)&0xf) +#define EEREC_TEMP (((info)>>24)&0xf) +#define VUREC_FMAC ((info)&0x80000000) + +#define PROCESS_EE_SET_S(reg) ((reg)<<8) +#define PROCESS_EE_SET_T(reg) ((reg)<<12) +#define PROCESS_EE_SET_D(reg) ((reg)<<16) +#define PROCESS_EE_SET_LO(reg) ((reg)<<20) +#define PROCESS_EE_SET_HI(reg) ((reg)<<24) +#define PROCESS_EE_SET_ACC(reg) ((reg)<<20) + +#define PROCESS_VU_SET_ACC(reg) PROCESS_EE_SET_ACC(reg) +#define PROCESS_VU_SET_TEMP(reg) ((reg)<<24) + +#define PROCESS_VU_SET_FMAC() 0x80000000 + +// special info not related to above flags +#define PROCESS_CONSTS 1 +#define PROCESS_CONSTT 2 + +//////////////////////////////////////////////////////////////////////////////// +// X86 (32-bit) Register Allocation Tools + +#define X86TYPE_TEMP 0 +#define X86TYPE_GPR 1 +#define X86TYPE_VI 2 +#define X86TYPE_MEMOFFSET 3 +#define X86TYPE_VIMEMOFFSET 4 +#define X86TYPE_VUQREAD 5 +#define X86TYPE_VUPREAD 6 +#define X86TYPE_VUQWRITE 7 +#define X86TYPE_VUPWRITE 8 +#define X86TYPE_PSX 9 +#define X86TYPE_PCWRITEBACK 10 +#define X86TYPE_VUJUMP 12 // jump from random mem (g_recWriteback) +#define X86TYPE_VITEMP 13 +#define X86TYPE_FNARG 14 // function parameter, max is 4 + +#define X86TYPE_VU1 0x80 + +#define X86_ISVI(type) ((type&~X86TYPE_VU1) == X86TYPE_VI) + +struct _x86regs { + u8 inuse; + u8 reg; // value of 0 - not used + u8 mode; + u8 needed; + u8 type; // X86TYPE_ + u16 counter; + u32 extra; // extra info assoc with the reg +}; + +extern _x86regs x86regs[X86REGS], s_saveX86regs[X86REGS]; + +uptr _x86GetAddr(int type, int reg); +void _initX86regs(); +int _getFreeX86reg(int mode); +int _allocX86reg(int x86reg, int type, int reg, int mode); +void _deleteX86reg(int type, int reg, int flush); +int _checkX86reg(int type, int reg, int mode); +void _addNeededX86reg(int type, int reg); +void _clearNeededX86regs(); +void _freeX86reg(int x86reg); +void _flushX86regs(); +void _freeX86regs(); +void _freeX86tempregs(); +u8 _hasFreeX86reg(); +void _flushCachedRegs(); +void _flushConstRegs(); +void _flushConstReg(int reg); + +//////////////////////////////////////////////////////////////////////////////// +// XMM (128-bit) Register Allocation Tools + +#define XMM_CONV_VU(VU) (VU==&VU1) + +#define XMMTYPE_TEMP 0 // has to be 0 +#define XMMTYPE_VFREG 1 +#define XMMTYPE_ACC 2 +#define XMMTYPE_FPREG 3 +#define XMMTYPE_FPACC 4 +#define XMMTYPE_GPRREG 5 + +// lo and hi regs +#define XMMGPR_LO 33 +#define XMMGPR_HI 32 +#define XMMFPU_ACC 32 + +struct _xmmregs { + u8 inuse; + u8 reg; + u8 type; + u8 mode; + u8 needed; + u8 VU; // 0 = VU0, 1 = VU1 + u16 counter; +}; + +void _initXMMregs(); +int _getFreeXMMreg(); +int _allocTempXMMreg(XMMSSEType type, int xmmreg); +int _allocVFtoXMMreg(VURegs *VU, int xmmreg, int vfreg, int mode); +int _allocFPtoXMMreg(int xmmreg, int fpreg, int mode); +int _allocGPRtoXMMreg(int xmmreg, int gprreg, int mode); +int _allocACCtoXMMreg(VURegs *VU, int xmmreg, int mode); +int _allocFPACCtoXMMreg(int xmmreg, int mode); +int _checkXMMreg(int type, int reg, int mode); +void _addNeededVFtoXMMreg(int vfreg); +void _addNeededACCtoXMMreg(); +void _addNeededFPtoXMMreg(int fpreg); +void _addNeededFPACCtoXMMreg(); +void _addNeededGPRtoXMMreg(int gprreg); +void _clearNeededXMMregs(); +void _deleteVFtoXMMreg(int reg, int vu, int flush); +void _deleteACCtoXMMreg(int vu, int flush); +void _deleteGPRtoXMMreg(int reg, int flush); +void _deleteFPtoXMMreg(int reg, int flush); +void _freeXMMreg(int xmmreg); +void _moveXMMreg(int xmmreg); // instead of freeing, moves it to a diff location +void _flushXMMregs(); +u8 _hasFreeXMMreg(); +void _freeXMMregs(); +int _getNumXMMwrite(); + +// uses MEM_MMXTAG/MEM_XMMTAG to differentiate between the regs +void _recPushReg(int mmreg); +void _signExtendSFtoM(u32 mem); + +// returns new index of reg, lower 32 bits already in mmx +// shift is used when the data is in the top bits of the mmx reg to begin with +// a negative shift is for sign extension +int _signExtendXMMtoM(u32 to, x86SSERegType from, int candestroy); // returns true if reg destroyed + +// Defines for passing register info + +// only valid during writes. If write128, then upper 64bits are in an mmxreg +// (mmreg&0xf). Constant is used from gprreg ((mmreg>>16)&0x1f) +#define MEM_EECONSTTAG 0x0100 // argument is a GPR and comes from g_cpuConstRegs +#define MEM_PSXCONSTTAG 0x0200 +#define MEM_MEMORYTAG 0x0400 +#define MEM_MMXTAG 0x0800 // mmreg is mmxreg +#define MEM_XMMTAG 0x8000 // mmreg is xmmreg +#define MEM_X86TAG 0x4000 // ignored most of the time +#define MEM_GPRTAG 0x2000 // argument is a GPR reg +#define MEM_CONSTTAG 0x1000 // argument is a const + +#define IS_EECONSTREG(reg) (reg>=0&&((reg)&MEM_EECONSTTAG)) +#define IS_PSXCONSTREG(reg) (reg>=0&&((reg)&MEM_PSXCONSTTAG)) +#define IS_MMXREG(reg) (reg>=0&&((reg)&MEM_MMXTAG)) +#define IS_XMMREG(reg) (reg>=0&&((reg)&MEM_XMMTAG)) + +// fixme - these 4 are only called for u32 registers; should the reg>=0 really be there? +#define IS_X86REG(reg) (reg>=0&&((reg)&MEM_X86TAG)) +#define IS_GPRREG(reg) (reg>=0&&((reg)&MEM_GPRTAG)) +#define IS_CONSTREG(reg) (reg>=0&&((reg)&MEM_CONSTTAG)) +#define IS_MEMORYREG(reg) (reg>=0&&((reg)&MEM_MEMORYTAG)) + +////////////////////// +// Instruction Info // +////////////////////// +#define EEINST_LIVE0 1 // if var is ever used (read or write) +#define EEINST_LIVE1 2 // if cur var's next 32 bits are needed +#define EEINST_LIVE2 4 // if cur var's next 64 bits are needed +#define EEINST_LASTUSE 8 // if var isn't written/read anymore +#define EEINST_MMX 0x10 // var will be used in mmx ops +#define EEINST_XMM 0x20 // var will be used in xmm ops (takes precedence +#define EEINST_USED 0x40 + +#define EEINSTINFO_COP1 1 +#define EEINSTINFO_COP2 2 +#ifdef PCSX2_VM_COISSUE +#define EEINSTINFO_NOREC 4 // if set, inst is recompiled alone +#define EEINSTINFO_COREC 8 // if set, inst is recompiled with another similar inst +#endif +#define EEINSTINFO_MMX EEINST_MMX +#define EEINSTINFO_XMM EEINST_XMM + +struct EEINST +{ + u8 regs[34]; // includes HI/LO (HI=32, LO=33) + u8 fpuregs[33]; // ACC=32 + u8 info; // extra info, if 1 inst is COP1, 2 inst is COP2. Also uses EEINST_MMX|EEINST_XMM + + // uses XMMTYPE_ flags; if type == XMMTYPE_TEMP, not used + u8 writeType[3], writeReg[3]; // reg written in this inst, 0 if no reg + u8 readType[4], readReg[4]; + + // valid if info & EEINSTINFO_COP2 + int cycle; // cycle of inst (at offset from block) + _VURegsNum vuregs; + + u8 numpeeps; // number of peephole optimizations +}; + +extern EEINST* g_pCurInstInfo; // info for the cur instruction +extern void _recClearInst(EEINST* pinst); + +// returns the number of insts + 1 until written (0 if not written) +extern u32 _recIsRegWritten(EEINST* pinst, int size, u8 xmmtype, u8 reg); +// returns the number of insts + 1 until used (0 if not used) +extern u32 _recIsRegUsed(EEINST* pinst, int size, u8 xmmtype, u8 reg); +extern void _recFillRegister(EEINST& pinst, int type, int reg, int write); + +#define EEINST_ISLIVE64(reg) (g_pCurInstInfo->regs[reg] & (EEINST_LIVE0|EEINST_LIVE1)) +#define EEINST_ISLIVEXMM(reg) (g_pCurInstInfo->regs[reg] & (EEINST_LIVE0|EEINST_LIVE1|EEINST_LIVE2)) +#define EEINST_ISLIVE1(reg) (g_pCurInstInfo->regs[reg] & EEINST_LIVE1) +#define EEINST_ISLIVE2(reg) (g_pCurInstInfo->regs[reg] & EEINST_LIVE2) + +#define FPUINST_ISLIVE(reg) (g_pCurInstInfo->fpuregs[reg] & EEINST_LIVE0) +#define FPUINST_LASTUSE(reg) (g_pCurInstInfo->fpuregs[reg] & EEINST_LASTUSE) + +// if set, then the variable at this inst really has its upper 32 bits valid +// The difference between EEINST_LIVE1 is that the latter is used in back propagation +// The former is set at recompile time. +#define EEINST_RESETHASLIVE1(reg) { if( (reg) < 32 ) g_cpuRegHasLive1 &= ~(1<<(reg)); } +#define EEINST_HASLIVE1(reg) (g_cpuPrevRegHasLive1&(1<<(reg))) + +#define EEINST_SETSIGNEXT(reg) { if( (reg) < 32 ) g_cpuRegHasSignExt |= (1<<(reg)); } +#define EEINST_RESETSIGNEXT(reg) { if( (reg) < 32 ) g_cpuRegHasSignExt &= ~(1<<(reg)); } +#define EEINST_ISSIGNEXT(reg) (g_cpuPrevRegHasSignExt&(1<<(reg))) + +extern u32 g_recWriteback; // used for jumps (VUrec mess!) +extern u32 g_cpuRegHasLive1, g_cpuPrevRegHasLive1; +extern u32 g_cpuRegHasSignExt, g_cpuPrevRegHasSignExt; + +extern _xmmregs xmmregs[XMMREGS], s_saveXMMregs[XMMREGS]; + +extern u16 g_x86AllocCounter; +extern u16 g_xmmAllocCounter; + +#ifdef _DEBUG +extern char g_globalXMMLocked; +#endif + +// allocates only if later insts use XMM, otherwise checks +int _allocCheckGPRtoXMM(EEINST* pinst, int gprreg, int mode); +int _allocCheckFPUtoXMM(EEINST* pinst, int fpureg, int mode); + +// allocates only if later insts use this register +int _allocCheckGPRtoX86(EEINST* pinst, int gprreg, int mode); + +//////////////////////////////////////////////////////////////////////////////// +// MMX (64-bit) Register Allocation Tools + +#define FPU_STATE 0 +#define MMX_STATE 1 + +void SetMMXstate(); +void SetFPUstate(); + +// max is 0x7f, when 0x80 is set, need to flush reg +#define MMX_GET_CACHE(ptr, index) ((u8*)ptr)[index] +#define MMX_SET_CACHE(ptr, ind3, ind2, ind1, ind0) ((u32*)ptr)[0] = (ind3<<24)|(ind2<<16)|(ind1<<8)|ind0; +#define MMX_GPR 0 +#define MMX_HI XMMGPR_HI +#define MMX_LO XMMGPR_LO +#define MMX_FPUACC 34 +#define MMX_FPU 64 +#define MMX_COP0 96 +#define MMX_TEMP 0x7f + +#define MMX_IS32BITS(x) (((x)>=MMX_FPU&&(x)= MMX_GPR && (x) < MMX_GPR+34) + +struct _mmxregs { + u8 inuse; + u8 reg; // value of 0 - not used + u8 mode; + u8 needed; + u16 counter; +}; + +void _initMMXregs(); +int _getFreeMMXreg(); +int _allocMMXreg(int MMXreg, int reg, int mode); +void _addNeededMMXreg(int reg); +int _checkMMXreg(int reg, int mode); +void _clearNeededMMXregs(); +void _deleteMMXreg(int reg, int flush); +void _freeMMXreg(int mmxreg); +void _moveMMXreg(int mmxreg); // instead of freeing, moves it to a diff location +void _flushMMXregs(); +u8 _hasFreeMMXreg(); +void _freeMMXregs(); +int _getNumMMXwrite(); + +int _signExtendMtoMMX(x86MMXRegType to, u32 mem); +int _signExtendGPRMMXtoMMX(x86MMXRegType to, u32 gprreg, x86MMXRegType from, u32 gprfromreg); +int _allocCheckGPRtoMMX(EEINST* pinst, int reg, int mode); + +void _recMove128RmOffsettoM(u32 to, u32 offset); +void _recMove128MtoRmOffset(u32 offset, u32 from); + +// returns new index of reg, lower 32 bits already in mmx +// shift is used when the data is in the top bits of the mmx reg to begin with +// a negative shift is for sign extension +extern int _signExtendGPRtoMMX(x86MMXRegType to, u32 gprreg, int shift); + +extern _mmxregs mmxregs[MMXREGS], s_saveMMXregs[MMXREGS]; +extern u16 x86FpuState, iCWstate; + +extern void iDumpRegisters(u32 startpc, u32 temp); + +////////////////////////////////////////////////////////////////////////// +// iFlushCall / _psxFlushCall Parameters + +// Flushing vs. Freeing, as understood by Air (I could be wrong still....) + +// "Freeing" registers means that the contents of the registers are flushed to memory. +// This is good for any sort of C code function that plans to modify the actual +// registers. When the Recs resume, they'll reload the registers with values saved +// as needed. (similar to a "FreezeXMMRegs") + +// "Flushing" means that in addition to the standard free (which is actually a flush) +// the register allocations are additionally wiped. This should only be necessary if +// the code being called is going to modify register allocations -- ie, be doing +// some kind of recompiling of its own. + +#define FLUSH_CACHED_REGS 1 +#define FLUSH_FLUSH_XMM 2 +#define FLUSH_FREE_XMM 4 // both flushes and frees +#define FLUSH_FLUSH_MMX 8 +#define FLUSH_FREE_MMX 16 // both flushes and frees +#define FLUSH_FLUSH_ALLX86 32 // flush x86 +#define FLUSH_FREE_TEMPX86 64 // flush and free temporary x86 regs +#define FLUSH_FREE_ALLX86 128 // free all x86 regs +#define FLUSH_FREE_VU0 0x100 // free all vu0 related regs + +#define FLUSH_EVERYTHING 0xfff +// no freeing, used when callee won't destroy mmx/xmm regs +#define FLUSH_NODESTROY (FLUSH_CACHED_REGS|FLUSH_FLUSH_XMM|FLUSH_FLUSH_MMX|FLUSH_FLUSH_ALLX86) +// used when regs aren't going to be changed be callee +#define FLUSH_NOCONST (FLUSH_FREE_XMM|FLUSH_FREE_MMX|FLUSH_FREE_TEMPX86) + + +////////////////////////////////////////////////////////////////////////// +// Utility Functions -- that should probably be part of the Emitter. + +// see MEM_X defines for argX format +extern void _callPushArg(u32 arg, uptr argmem); /// X86ARG is ignored for 32bit recs +extern void _callFunctionArg1(uptr fn, u32 arg1, uptr arg1mem); +extern void _callFunctionArg2(uptr fn, u32 arg1, u32 arg2, uptr arg1mem, uptr arg2mem); +extern void _callFunctionArg3(uptr fn, u32 arg1, u32 arg2, u32 arg3, uptr arg1mem, uptr arg2mem, uptr arg3mem); + +// Moves 128 bits of data using EAX/EDX (used by iCOP2 only currently) +extern void _recMove128MtoM(u32 to, u32 from); + +// op = 0, and +// op = 1, or +// op = 2, xor +// op = 3, nor (the 32bit versoins only do OR) +extern void LogicalOpRtoR(x86MMXRegType to, x86MMXRegType from, int op); +extern void LogicalOpMtoR(x86MMXRegType to, u32 from, int op); + +extern void LogicalOp32RtoM(uptr to, x86IntRegType from, int op); +extern void LogicalOp32MtoR(x86IntRegType to, uptr from, int op); +extern void LogicalOp32ItoR(x86IntRegType to, u32 from, int op); +extern void LogicalOp32ItoM(uptr to, u32 from, int op); + +#ifdef ARITHMETICIMM_RECOMPILE +extern void LogicalOpRtoR(x86MMXRegType to, x86MMXRegType from, int op); +extern void LogicalOpMtoR(x86MMXRegType to, u32 from, int op); +#endif + +#endif diff --git a/pcsx2/x86/iFPU.cpp b/pcsx2/x86/iFPU.cpp index 8bb8a9452b..07167cd64e 100644 --- a/pcsx2/x86/iFPU.cpp +++ b/pcsx2/x86/iFPU.cpp @@ -1,1733 +1,1733 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "R5900OpcodeTables.h" -#include "ix86/ix86.h" -#include "iR5900.h" -#include "iFPU.h" - -extern PCSX2_ALIGNED16_DECL(u32 g_minvals[4]); -extern PCSX2_ALIGNED16_DECL(u32 g_maxvals[4]); - -//------------------------------------------------------------------ -// Misc... -//------------------------------------------------------------------ -//static u32 _mxcsr = 0x7F80; -//static u32 _mxcsrs; -static u32 fpucw = 0x007f; -static u32 fpucws = 0; - -void SaveCW(int type) { - if (iCWstate & type) return; - - if (type == 2) { -// SSE_STMXCSR((uptr)&_mxcsrs); -// SSE_LDMXCSR((uptr)&_mxcsr); - } else { - FNSTCW( (uptr)&fpucws ); - FLDCW( (uptr)&fpucw ); - } - iCWstate|= type; -} - -void LoadCW() { - if (iCWstate == 0) return; - - if (iCWstate & 2) { - //SSE_LDMXCSR((uptr)&_mxcsrs); - } - if (iCWstate & 1) { - FLDCW( (uptr)&fpucws ); - } - iCWstate = 0; -} - -//------------------------------------------------------------------ -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl { -namespace COP1 { - -//------------------------------------------------------------------ -// Helper Macros -//------------------------------------------------------------------ -#define _Ft_ _Rt_ -#define _Fs_ _Rd_ -#define _Fd_ _Sa_ - -// FCR31 Flags -#define FPUflagC 0X00800000 -#define FPUflagI 0X00020000 -#define FPUflagD 0X00010000 -#define FPUflagO 0X00008000 -#define FPUflagU 0X00004000 -#define FPUflagSI 0X00000040 -#define FPUflagSD 0X00000020 -#define FPUflagSO 0X00000010 -#define FPUflagSU 0X00000008 - -#define FPU_ADD_SUB_HACK 1 // Add/Sub opcodes produce more ps2-like results if set to 1 - -static u32 PCSX2_ALIGNED16(s_neg[4]) = { 0x80000000, 0xffffffff, 0xffffffff, 0xffffffff }; -static u32 PCSX2_ALIGNED16(s_pos[4]) = { 0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff }; - -#define REC_FPUBRANCH(f) \ - void f(); \ - void rec##f() { \ - MOV32ItoM((uptr)&cpuRegs.code, cpuRegs.code); \ - MOV32ItoM((uptr)&cpuRegs.pc, pc); \ - iFlushCall(FLUSH_EVERYTHING); \ - CALLFunc((uptr)R5900::Interpreter::OpcodeImpl::COP1::f); \ - branch = 2; \ -} - -#define REC_FPUFUNC(f) \ - void f(); \ - void rec##f() { \ - MOV32ItoM((uptr)&cpuRegs.code, cpuRegs.code); \ - MOV32ItoM((uptr)&cpuRegs.pc, pc); \ - iFlushCall(FLUSH_EVERYTHING); \ - CALLFunc((uptr)R5900::Interpreter::OpcodeImpl::COP1::f); \ -} -//------------------------------------------------------------------ - -//------------------------------------------------------------------ -// *FPU Opcodes!* -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// CFC1 / CTC1 -//------------------------------------------------------------------ -void recCFC1(void) -{ - if ( !_Rt_ || ( (_Fs_ != 0) && (_Fs_ != 31) ) ) return; - - _eeOnWriteReg(_Rt_, 1); - - MOV32MtoR( EAX, (uptr)&fpuRegs.fprc[ _Fs_ ] ); - _deleteEEreg(_Rt_, 0); - - if(EEINST_ISLIVE1(_Rt_)) - { - CDQ( ); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); - } - else - { - EEINST_RESETHASLIVE1(_Rt_); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - } -} - -void recCTC1( void ) -{ - if ( _Fs_ != 31 ) return; - - if ( GPR_IS_CONST1(_Rt_) ) - { - MOV32ItoM((uptr)&fpuRegs.fprc[ _Fs_ ], g_cpuConstRegs[_Rt_].UL[0]); - } - else - { - int mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ); - - if( mmreg >= 0 ) - { - SSEX_MOVD_XMM_to_M32((uptr)&fpuRegs.fprc[ _Fs_ ], mmreg); - } - - else - { - mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_READ); - - if ( mmreg >= 0 ) - { - MOVDMMXtoM((uptr)&fpuRegs.fprc[ _Fs_ ], mmreg); - SetMMXstate(); - } - else - { - _deleteGPRtoXMMreg(_Rt_, 1); - _deleteMMXreg(MMX_GPR+_Rt_, 1); - - MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - MOV32RtoM( (uptr)&fpuRegs.fprc[ _Fs_ ], EAX ); - } - } - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// MFC1 -//------------------------------------------------------------------ - -void recMFC1(void) -{ - int regt, regs; - if ( ! _Rt_ ) return; - - _eeOnWriteReg(_Rt_, 1); - - regs = _checkXMMreg(XMMTYPE_FPREG, _Fs_, MODE_READ); - - if( regs >= 0 ) - { - _deleteGPRtoXMMreg(_Rt_, 2); - regt = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); - - if( regt >= 0 ) - { - SSE2_MOVDQ2Q_XMM_to_MM(regt, regs); - - if(EEINST_ISLIVE1(_Rt_)) - _signExtendGPRtoMMX(regt, _Rt_, 0); - else - EEINST_RESETHASLIVE1(_Rt_); - } - else - { - if(EEINST_ISLIVE1(_Rt_)) - { - _signExtendXMMtoM((uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], regs, 0); - } - else - { - EEINST_RESETHASLIVE1(_Rt_); - SSE_MOVSS_XMM_to_M32((uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], regs); - } - } - } - else - { - regs = _checkMMXreg(MMX_FPU+_Fs_, MODE_READ); - - if( regs >= 0 ) - { - // convert to mmx reg - mmxregs[regs].reg = MMX_GPR+_Rt_; - mmxregs[regs].mode |= MODE_READ|MODE_WRITE; - _signExtendGPRtoMMX(regs, _Rt_, 0); - } - else - { - regt = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ); - - if( regt >= 0 ) - { - if( xmmregs[regt].mode & MODE_WRITE ) - { - SSE_MOVHPS_XMM_to_M64((uptr)&cpuRegs.GPR.r[_Rt_].UL[2], regt); - } - xmmregs[regt].inuse = 0; - } - - _deleteEEreg(_Rt_, 0); - MOV32MtoR( EAX, (uptr)&fpuRegs.fpr[ _Fs_ ].UL ); - - if(EEINST_ISLIVE1(_Rt_)) - { - CDQ( ); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); - } - else - { - EEINST_RESETHASLIVE1(_Rt_); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - } - } - } -} - -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// MTC1 -//------------------------------------------------------------------ -void recMTC1(void) -{ - if( GPR_IS_CONST1(_Rt_) ) - { - _deleteFPtoXMMreg(_Fs_, 0); - MOV32ItoM((uptr)&fpuRegs.fpr[ _Fs_ ].UL, g_cpuConstRegs[_Rt_].UL[0]); - } - else - { - int mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ); - - if( mmreg >= 0 ) - { - if( g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE ) - { - // transfer the reg directly - _deleteGPRtoXMMreg(_Rt_, 2); - _deleteFPtoXMMreg(_Fs_, 2); - _allocFPtoXMMreg(mmreg, _Fs_, MODE_WRITE); - } - else - { - int mmreg2 = _allocCheckFPUtoXMM(g_pCurInstInfo, _Fs_, MODE_WRITE); - - if( mmreg2 >= 0 ) - SSE_MOVSS_XMM_to_XMM(mmreg2, mmreg); - else - SSE_MOVSS_XMM_to_M32((uptr)&fpuRegs.fpr[ _Fs_ ].UL, mmreg); - } - } - else - { - int mmreg2; - - mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_READ); - mmreg2 = _allocCheckFPUtoXMM(g_pCurInstInfo, _Fs_, MODE_WRITE); - - if( mmreg >= 0 ) - { - if( mmreg2 >= 0 ) - { - SetMMXstate(); - SSE2_MOVQ2DQ_MM_to_XMM(mmreg2, mmreg); - } - else - { - SetMMXstate(); - MOVDMMXtoM((uptr)&fpuRegs.fpr[ _Fs_ ].UL, mmreg); - } - } - else - { - if( mmreg2 >= 0 ) - { - SSE_MOVSS_M32_to_XMM(mmreg2, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); - } - else - { - MOV32MtoR(EAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); - MOV32RtoM((uptr)&fpuRegs.fpr[ _Fs_ ].UL, EAX); - } - } - } - } -} -//------------------------------------------------------------------ - - -#ifndef FPU_RECOMPILE // If FPU_RECOMPILE is not defined, then use the interpreter opcodes. (CFC1, CTC1, MFC1, and MTC1 are special because they work specifically with the EE rec so they're defined above) - -REC_FPUFUNC(ABS_S); -REC_FPUFUNC(ADD_S); -REC_FPUFUNC(ADDA_S); -REC_FPUBRANCH(BC1F); -REC_FPUBRANCH(BC1T); -REC_FPUBRANCH(BC1FL); -REC_FPUBRANCH(BC1TL); -REC_FPUFUNC(C_EQ); -REC_FPUFUNC(C_F); -REC_FPUFUNC(C_LE); -REC_FPUFUNC(C_LT); -REC_FPUFUNC(CVT_S); -REC_FPUFUNC(CVT_W); -REC_FPUFUNC(DIV_S); -REC_FPUFUNC(MAX_S); -REC_FPUFUNC(MIN_S); -REC_FPUFUNC(MADD_S); -REC_FPUFUNC(MADDA_S); -REC_FPUFUNC(MOV_S); -REC_FPUFUNC(MSUB_S); -REC_FPUFUNC(MSUBA_S); -REC_FPUFUNC(MUL_S); -REC_FPUFUNC(MULA_S); -REC_FPUFUNC(NEG_S); -REC_FPUFUNC(SUB_S); -REC_FPUFUNC(SUBA_S); -REC_FPUFUNC(SQRT_S); -REC_FPUFUNC(RSQRT_S); - -#else // FPU_RECOMPILE - -//------------------------------------------------------------------ -// Clamp Functions (Converts NaN's and Infinities to Normal Numbers) -//------------------------------------------------------------------ -void fpuFloat(int regd) { // +/-NaN -> +fMax, +Inf -> +fMax, -Inf -> -fMax - if (CHECK_FPU_OVERFLOW && !CHECK_FPUCLAMPHACK) { // Tekken 5 doesn't like clamping infinities. - SSE_MINSS_M32_to_XMM(regd, (uptr)&g_maxvals[0]); // MIN() must be before MAX()! So that NaN's become +Maximum - SSE_MAXSS_M32_to_XMM(regd, (uptr)&g_minvals[0]); - } -} - -PCSX2_ALIGNED16(u64 FPU_FLOAT_TEMP[2]); -void fpuFloat2(int regd) { // +NaN -> +fMax, -NaN -> -fMax, +Inf -> +fMax, -Inf -> -fMax - if (CHECK_FPU_OVERFLOW && !CHECK_FPUCLAMPHACK) { // Tekken 5 doesn't like clamping infinities. - int t1reg = _allocTempXMMreg(XMMT_FPS, -1); - if (t1reg >= 0) { - SSE_MOVSS_XMM_to_XMM(t1reg, regd); - SSE_ANDPS_M128_to_XMM(t1reg, (uptr)&s_neg[0]); - SSE_MINSS_M32_to_XMM(regd, (uptr)&g_maxvals[0]); - SSE_MAXSS_M32_to_XMM(regd, (uptr)&g_minvals[0]); - SSE_ORPS_XMM_to_XMM(regd, t1reg); - _freeXMMreg(t1reg); - } - else { - Console::Error("fpuFloat2() allocation error"); - t1reg = (regd == 0) ? 1 : 0; // get a temp reg thats not regd - SSE_MOVAPS_XMM_to_M128( (uptr)&FPU_FLOAT_TEMP[0], t1reg ); // backup data in t1reg to a temp address - SSE_MOVSS_XMM_to_XMM(t1reg, regd); - SSE_ANDPS_M128_to_XMM(t1reg, (uptr)&s_neg[0]); - SSE_MINSS_M32_to_XMM(regd, (uptr)&g_maxvals[0]); - SSE_MAXSS_M32_to_XMM(regd, (uptr)&g_minvals[0]); - SSE_ORPS_XMM_to_XMM(regd, t1reg); - SSE_MOVAPS_M128_to_XMM( t1reg, (uptr)&FPU_FLOAT_TEMP[0] ); // restore t1reg data - } - } -} - -void ClampValues(int regd) { - fpuFloat(regd); -} - -void ClampValues2(int regd) { - if (CHECK_FPUCLAMPHACK) { // Fixes Tekken 5 ( Makes NaN equal 0, infinities stay the same ) - int t5reg = _allocTempXMMreg(XMMT_FPS, -1); - - SSE_XORPS_XMM_to_XMM(t5reg, t5reg); - SSE_CMPORDSS_XMM_to_XMM(t5reg, regd); - - SSE_ANDPS_XMM_to_XMM(regd, t5reg); - - /* --- Its odd but tekken dosn't like Infinities to be clamped. --- */ - //SSE_MINSS_M32_to_XMM(regd, (uptr)&g_maxvals[0]); - //SSE_MAXSS_M32_to_XMM(regd, (uptr)&g_minvals[0]); - - _freeXMMreg(t5reg); - } - else fpuFloat(regd); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ABS XMM -//------------------------------------------------------------------ -void recABS_S_xmm(int info) -{ - if( info & PROCESS_EE_S ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - else SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); - - SSE_ANDPS_M128_to_XMM(EEREC_D, (uptr)&s_pos[0]); - //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags - - if (CHECK_FPU_OVERFLOW) // Only need to do positive clamp, since EEREC_D is positive - SSE_MINSS_M32_to_XMM(EEREC_D, (uptr)&g_maxvals[0]); -} - -FPURECOMPILE_CONSTCODE(ABS_S, XMMINFO_WRITED|XMMINFO_READS); -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// FPU_ADD_SUB (Used to mimic PS2's FPU add/sub behavior) -//------------------------------------------------------------------ -// Compliant IEEE FPU uses, in computations, uses additional "guard" bits to the right of the mantissa -// but EE-FPU doesn't. Substraction (and addition of positive and negative) may shift the mantissa left, -// causing those bits to appear in the result; this function masks out the bits of the mantissa that will -// get shifted right to the guard bits to ensure that the guard bits are empty. -// The difference of the exponents = the amount that the smaller operand will be shifted right by. -// Modification - the PS2 uses a single guard bit? (Coded by Nneeve) -//------------------------------------------------------------------ -void FPU_ADD_SUB(int regd, int regt, int issub) -{ - int tempecx = _allocX86reg(ECX, X86TYPE_TEMP, 0, 0); //receives regd - int temp2 = _allocX86reg(-1, X86TYPE_TEMP, 0, 0); //receives regt - int xmmtemp = _allocTempXMMreg(XMMT_FPS, -1); //temporary for anding with regd/regt - - if (tempecx != ECX) { Console::Error("FPU: ADD/SUB Allocation Error!"); tempecx = ECX;} - if (temp2 == -1) { Console::Error("FPU: ADD/SUB Allocation Error!"); temp2 = EAX;} - if (xmmtemp == -1) { Console::Error("FPU: ADD/SUB Allocation Error!"); xmmtemp = XMM0;} - - SSE2_MOVD_XMM_to_R(tempecx, regd); - SSE2_MOVD_XMM_to_R(temp2, regt); - - //mask the exponents - SHR32ItoR(tempecx, 23); - SHR32ItoR(temp2, 23); - AND32ItoR(tempecx, 0xff); - AND32ItoR(temp2, 0xff); - - SUB32RtoR(tempecx, temp2); //tempecx = exponent difference - CMP32ItoR(tempecx, 25); - j8Ptr[0] = JGE8(0); - CMP32ItoR(tempecx, 0); - j8Ptr[1] = JG8(0); - j8Ptr[2] = JE8(0); - CMP32ItoR(tempecx, -25); - j8Ptr[3] = JLE8(0); - - //diff = -24 .. -1 , expd < expt - NEG32R(tempecx); - DEC32R(tempecx); - MOV32ItoR(temp2, 0xffffffff); - SHL32CLtoR(temp2); //temp2 = 0xffffffff << tempecx - SSE2_MOVD_R_to_XMM(xmmtemp, temp2); - SSE_ANDPS_XMM_to_XMM(regd, xmmtemp); - if (issub) - SSE_SUBSS_XMM_to_XMM(regd, regt); - else - SSE_ADDSS_XMM_to_XMM(regd, regt); - j8Ptr[4] = JMP8(0); - - x86SetJ8(j8Ptr[0]); - //diff = 25 .. 255 , expt < expd - SSE_MOVAPS_XMM_to_XMM(xmmtemp, regt); - SSE_ANDPS_M128_to_XMM(xmmtemp, (uptr)s_neg); - if (issub) - SSE_SUBSS_XMM_to_XMM(regd, xmmtemp); - else - SSE_ADDSS_XMM_to_XMM(regd, xmmtemp); - j8Ptr[5] = JMP8(0); - - x86SetJ8(j8Ptr[1]); - //diff = 1 .. 24, expt < expd - DEC32R(tempecx); - MOV32ItoR(temp2, 0xffffffff); - SHL32CLtoR(temp2); //temp2 = 0xffffffff << tempecx - SSE2_MOVD_R_to_XMM(xmmtemp, temp2); - SSE_ANDPS_XMM_to_XMM(xmmtemp, regt); - if (issub) - SSE_SUBSS_XMM_to_XMM(regd, xmmtemp); - else - SSE_ADDSS_XMM_to_XMM(regd, xmmtemp); - j8Ptr[6] = JMP8(0); - - x86SetJ8(j8Ptr[3]); - //diff = -255 .. -25, expd < expt - SSE_ANDPS_M128_to_XMM(regd, (uptr)s_neg); - if (issub) - SSE_SUBSS_XMM_to_XMM(regd, regt); - else - SSE_ADDSS_XMM_to_XMM(regd, regt); - j8Ptr[7] = JMP8(0); - - x86SetJ8(j8Ptr[2]); - //diff == 0 - if (issub) - SSE_SUBSS_XMM_to_XMM(regd, regt); - else - SSE_ADDSS_XMM_to_XMM(regd, regt); - - x86SetJ8(j8Ptr[4]); - x86SetJ8(j8Ptr[5]); - x86SetJ8(j8Ptr[6]); - x86SetJ8(j8Ptr[7]); - - _freeXMMreg(xmmtemp); - _freeX86reg(temp2); - _freeX86reg(tempecx); -} - -void FPU_ADD(int regd, int regt) { - if (FPU_ADD_SUB_HACK) FPU_ADD_SUB(regd, regt, 0); - else SSE_ADDSS_XMM_to_XMM(regd, regt); -} - -void FPU_SUB(int regd, int regt) { - if (FPU_ADD_SUB_HACK) FPU_ADD_SUB(regd, regt, 1); - else SSE_SUBSS_XMM_to_XMM(regd, regt); -} - - -//------------------------------------------------------------------ -// CommutativeOp XMM (used for ADD, MUL, MAX, and MIN opcodes) -//------------------------------------------------------------------ -static void (*recComOpXMM_to_XMM[] )(x86SSERegType, x86SSERegType) = { - FPU_ADD, SSE_MULSS_XMM_to_XMM, SSE_MAXSS_XMM_to_XMM, SSE_MINSS_XMM_to_XMM }; - -//static void (*recComOpM32_to_XMM[] )(x86SSERegType, uptr) = { -// SSE_ADDSS_M32_to_XMM, SSE_MULSS_M32_to_XMM, SSE_MAXSS_M32_to_XMM, SSE_MINSS_M32_to_XMM }; - -int recCommutativeOp(int info, int regd, int op) -{ - int t0reg = _allocTempXMMreg(XMMT_FPS, -1); - //if (t0reg == -1) {SysPrintf("FPU: CommutativeOp Allocation Error!\n");} - - switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { - case PROCESS_EE_S: - if (regd == EEREC_S) { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); - if (CHECK_FPU_EXTRA_OVERFLOW /*&& !CHECK_FPUCLAMPHACK */ || (op >= 2)) { fpuFloat2(regd); fpuFloat2(t0reg); } - recComOpXMM_to_XMM[op](regd, t0reg); - } - else { - SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Ft_]); - if (CHECK_FPU_EXTRA_OVERFLOW || (op >= 2)) { fpuFloat2(regd); fpuFloat2(EEREC_S); } - recComOpXMM_to_XMM[op](regd, EEREC_S); - } - break; - case PROCESS_EE_T: - if (regd == EEREC_T) { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); - if (CHECK_FPU_EXTRA_OVERFLOW || (op >= 2)) { fpuFloat2(regd); fpuFloat2(t0reg); } - recComOpXMM_to_XMM[op](regd, t0reg); - } - else { - SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); - if (CHECK_FPU_EXTRA_OVERFLOW || (op >= 2)) { fpuFloat2(regd); fpuFloat2(EEREC_T); } - recComOpXMM_to_XMM[op](regd, EEREC_T); - } - break; - case (PROCESS_EE_S|PROCESS_EE_T): - if (regd == EEREC_T) { - if (CHECK_FPU_EXTRA_OVERFLOW || (op >= 2)) { fpuFloat2(regd); fpuFloat2(EEREC_S); } - recComOpXMM_to_XMM[op](regd, EEREC_S); - } - else { - SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); - if (CHECK_FPU_EXTRA_OVERFLOW || (op >= 2)) { fpuFloat2(regd); fpuFloat2(EEREC_T); } - recComOpXMM_to_XMM[op](regd, EEREC_T); - } - break; - default: - Console::Status("FPU: recCommutativeOp case 4"); - SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); - if (CHECK_FPU_EXTRA_OVERFLOW || (op >= 2)) { fpuFloat2(regd); fpuFloat2(t0reg); } - recComOpXMM_to_XMM[op](regd, t0reg); - break; - } - - _freeXMMreg(t0reg); - return regd; -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ADD XMM -//------------------------------------------------------------------ -void recADD_S_xmm(int info) -{ - //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags - ClampValues2(recCommutativeOp(info, EEREC_D, 0)); - //REC_FPUOP(ADD_S); -} - -FPURECOMPILE_CONSTCODE(ADD_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); - -void recADDA_S_xmm(int info) -{ - //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags - ClampValues(recCommutativeOp(info, EEREC_ACC, 0)); -} - -FPURECOMPILE_CONSTCODE(ADDA_S, XMMINFO_WRITEACC|XMMINFO_READS|XMMINFO_READT); -//------------------------------------------------------------------ - -//------------------------------------------------------------------ -// BC1x XMM -//------------------------------------------------------------------ - -static void _setupBranchTest() -{ - _eeFlushAllUnused(); - - // COP1 branch conditionals are based on the following equation: - // (fpuRegs.fprc[31] & 0x00800000) - // BC2F checks if the statement is false, BC2T checks if the statement is true. - - MOV32MtoR(EAX, (uptr)&fpuRegs.fprc[31]); - TEST32ItoR(EAX, FPUflagC); -} - -void recBC1F( void ) -{ - _setupBranchTest(); - recDoBranchImm(JNZ32(0)); -} - -void recBC1T( void ) -{ - _setupBranchTest(); - recDoBranchImm(JZ32(0)); -} - -void recBC1FL( void ) -{ - _setupBranchTest(); - recDoBranchImm_Likely(JNZ32(0)); -} - -void recBC1TL( void ) -{ - _setupBranchTest(); - recDoBranchImm_Likely(JZ32(0)); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// C.x.S XMM -//------------------------------------------------------------------ -void recC_EQ_xmm(int info) -{ - int tempReg; - int t0reg; - - //SysPrintf("recC_EQ_xmm()\n"); - - switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { - case PROCESS_EE_S: - SSE_MINSS_M32_to_XMM(EEREC_S, (uptr)&g_maxvals[0]); - t0reg = _allocTempXMMreg(XMMT_FPS, -1); - if (t0reg >= 0) { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); - SSE_MINSS_M32_to_XMM(t0reg, (uptr)&g_maxvals[0]); - SSE_UCOMISS_XMM_to_XMM(EEREC_S, t0reg); - _freeXMMreg(t0reg); - } - else SSE_UCOMISS_M32_to_XMM(EEREC_S, (uptr)&fpuRegs.fpr[_Ft_]); - break; - case PROCESS_EE_T: - SSE_MINSS_M32_to_XMM(EEREC_T, (uptr)&g_maxvals[0]); - t0reg = _allocTempXMMreg(XMMT_FPS, -1); - if (t0reg >= 0) { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); - SSE_MINSS_M32_to_XMM(t0reg, (uptr)&g_maxvals[0]); - SSE_UCOMISS_XMM_to_XMM(t0reg, EEREC_T); - _freeXMMreg(t0reg); - } - else SSE_UCOMISS_M32_to_XMM(EEREC_T, (uptr)&fpuRegs.fpr[_Fs_]); - break; - case (PROCESS_EE_S|PROCESS_EE_T): - SSE_MINSS_M32_to_XMM(EEREC_S, (uptr)&g_maxvals[0]); - SSE_MINSS_M32_to_XMM(EEREC_T, (uptr)&g_maxvals[0]); - SSE_UCOMISS_XMM_to_XMM(EEREC_S, EEREC_T); - break; - default: - Console::Status("recC_EQ_xmm: Default"); - tempReg = _allocX86reg(-1, X86TYPE_TEMP, 0, 0); - if (tempReg < 0) {Console::Error("FPU: DIV Allocation Error!"); tempReg = EAX;} - MOV32MtoR(tempReg, (uptr)&fpuRegs.fpr[_Fs_]); - CMP32MtoR(tempReg, (uptr)&fpuRegs.fpr[_Ft_]); - - j8Ptr[0] = JZ8(0); - AND32ItoM( (uptr)&fpuRegs.fprc[31], ~FPUflagC ); - j8Ptr[1] = JMP8(0); - x86SetJ8(j8Ptr[0]); - OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagC); - x86SetJ8(j8Ptr[1]); - - if (tempReg >= 0) _freeX86reg(tempReg); - return; - } - - j8Ptr[0] = JZ8(0); - AND32ItoM( (uptr)&fpuRegs.fprc[31], ~FPUflagC ); - j8Ptr[1] = JMP8(0); - x86SetJ8(j8Ptr[0]); - OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagC); - x86SetJ8(j8Ptr[1]); -} - -FPURECOMPILE_CONSTCODE(C_EQ, XMMINFO_READS|XMMINFO_READT); -//REC_FPUFUNC(C_EQ); - -void recC_F() -{ - AND32ItoM( (uptr)&fpuRegs.fprc[31], ~FPUflagC ); -} -//REC_FPUFUNC(C_F); - -void recC_LE_xmm(int info ) -{ - int tempReg; //tempX86reg - int t0reg; //tempXMMreg - - //SysPrintf("recC_LE_xmm()\n"); - - switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { - case PROCESS_EE_S: - SSE_MINSS_M32_to_XMM(EEREC_S, (uptr)&g_maxvals[0]); - t0reg = _allocTempXMMreg(XMMT_FPS, -1); - if (t0reg >= 0) { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); - SSE_MINSS_M32_to_XMM(t0reg, (uptr)&g_maxvals[0]); - SSE_UCOMISS_XMM_to_XMM(EEREC_S, t0reg); - _freeXMMreg(t0reg); - } - else SSE_UCOMISS_M32_to_XMM(EEREC_S, (uptr)&fpuRegs.fpr[_Ft_]); - break; - case PROCESS_EE_T: - SSE_MINSS_M32_to_XMM(EEREC_T, (uptr)&g_maxvals[0]); - t0reg = _allocTempXMMreg(XMMT_FPS, -1); - if (t0reg >= 0) { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); - SSE_MINSS_M32_to_XMM(t0reg, (uptr)&g_maxvals[0]); - SSE_UCOMISS_XMM_to_XMM(t0reg, EEREC_T); - _freeXMMreg(t0reg); - } - else { - SSE_UCOMISS_M32_to_XMM(EEREC_T, (uptr)&fpuRegs.fpr[_Fs_]); - - j8Ptr[0] = JAE8(0); - AND32ItoM( (uptr)&fpuRegs.fprc[31], ~FPUflagC ); - j8Ptr[1] = JMP8(0); - x86SetJ8(j8Ptr[0]); - OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagC); - x86SetJ8(j8Ptr[1]); - return; - } - break; - case (PROCESS_EE_S|PROCESS_EE_T): - SSE_MINSS_M32_to_XMM(EEREC_S, (uptr)&g_maxvals[0]); - SSE_MINSS_M32_to_XMM(EEREC_T, (uptr)&g_maxvals[0]); - SSE_UCOMISS_XMM_to_XMM(EEREC_S, EEREC_T); - break; - default: // Untested and incorrect, but this case is never reached AFAIK (cottonvibes) - Console::Status("recC_LE_xmm: Default"); - tempReg = _allocX86reg(-1, X86TYPE_TEMP, 0, 0); - if (tempReg < 0) {Console::Error("FPU: DIV Allocation Error!"); tempReg = EAX;} - MOV32MtoR(tempReg, (uptr)&fpuRegs.fpr[_Fs_]); - CMP32MtoR(tempReg, (uptr)&fpuRegs.fpr[_Ft_]); - - j8Ptr[0] = JLE8(0); - AND32ItoM( (uptr)&fpuRegs.fprc[31], ~FPUflagC ); - j8Ptr[1] = JMP8(0); - x86SetJ8(j8Ptr[0]); - OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagC); - x86SetJ8(j8Ptr[1]); - - if (tempReg >= 0) _freeX86reg(tempReg); - return; - } - - j8Ptr[0] = JBE8(0); - AND32ItoM( (uptr)&fpuRegs.fprc[31], ~FPUflagC ); - j8Ptr[1] = JMP8(0); - x86SetJ8(j8Ptr[0]); - OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagC); - x86SetJ8(j8Ptr[1]); -} - -FPURECOMPILE_CONSTCODE(C_LE, XMMINFO_READS|XMMINFO_READT); -//REC_FPUFUNC(C_LE); - -void recC_LT_xmm(int info) -{ - int tempReg; - int t0reg; - - //SysPrintf("recC_LT_xmm()\n"); - - switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { - case PROCESS_EE_S: - SSE_MINSS_M32_to_XMM(EEREC_S, (uptr)&g_maxvals[0]); - t0reg = _allocTempXMMreg(XMMT_FPS, -1); - if (t0reg >= 0) { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); - SSE_MINSS_M32_to_XMM(t0reg, (uptr)&g_maxvals[0]); - SSE_UCOMISS_XMM_to_XMM(EEREC_S, t0reg); - _freeXMMreg(t0reg); - } - else SSE_UCOMISS_M32_to_XMM(EEREC_S, (uptr)&fpuRegs.fpr[_Ft_]); - break; - case PROCESS_EE_T: - SSE_MINSS_M32_to_XMM(EEREC_T, (uptr)&g_maxvals[0]); - t0reg = _allocTempXMMreg(XMMT_FPS, -1); - if (t0reg >= 0) { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); - SSE_MINSS_M32_to_XMM(t0reg, (uptr)&g_maxvals[0]); - SSE_UCOMISS_XMM_to_XMM(t0reg, EEREC_T); - _freeXMMreg(t0reg); - } - else { - SSE_UCOMISS_M32_to_XMM(EEREC_T, (uptr)&fpuRegs.fpr[_Fs_]); - - j8Ptr[0] = JA8(0); - AND32ItoM( (uptr)&fpuRegs.fprc[31], ~FPUflagC ); - j8Ptr[1] = JMP8(0); - x86SetJ8(j8Ptr[0]); - OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagC); - x86SetJ8(j8Ptr[1]); - return; - } - break; - case (PROCESS_EE_S|PROCESS_EE_T): - // Makes NaNs and +Infinity be +maximum; -Infinity stays - // the same, but this is okay for a Compare operation. - // Note: This fixes a crash in Rule of Rose. - SSE_MINSS_M32_to_XMM(EEREC_S, (uptr)&g_maxvals[0]); - SSE_MINSS_M32_to_XMM(EEREC_T, (uptr)&g_maxvals[0]); - SSE_UCOMISS_XMM_to_XMM(EEREC_S, EEREC_T); - break; - default: - Console::Status("recC_LT_xmm: Default"); - tempReg = _allocX86reg(-1, X86TYPE_TEMP, 0, 0); - if (tempReg < 0) {Console::Error("FPU: DIV Allocation Error!"); tempReg = EAX;} - MOV32MtoR(tempReg, (uptr)&fpuRegs.fpr[_Fs_]); - CMP32MtoR(tempReg, (uptr)&fpuRegs.fpr[_Ft_]); - - j8Ptr[0] = JL8(0); - AND32ItoM( (uptr)&fpuRegs.fprc[31], ~FPUflagC ); - j8Ptr[1] = JMP8(0); - x86SetJ8(j8Ptr[0]); - OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagC); - x86SetJ8(j8Ptr[1]); - - if (tempReg >= 0) _freeX86reg(tempReg); - return; - } - - j8Ptr[0] = JB8(0); - AND32ItoM( (uptr)&fpuRegs.fprc[31], ~FPUflagC ); - j8Ptr[1] = JMP8(0); - x86SetJ8(j8Ptr[0]); - OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagC); - x86SetJ8(j8Ptr[1]); -} - -FPURECOMPILE_CONSTCODE(C_LT, XMMINFO_READS|XMMINFO_READT); -//REC_FPUFUNC(C_LT); -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// CVT.x XMM -//------------------------------------------------------------------ -void recCVT_S_xmm(int info) -{ - if( !(info&PROCESS_EE_S) || (EEREC_D != EEREC_S && !(info&PROCESS_EE_MODEWRITES)) ) { - SSE_CVTSI2SS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); - } - else { - SSE2_CVTDQ2PS_XMM_to_XMM(EEREC_D, EEREC_S); - } -} - -FPURECOMPILE_CONSTCODE(CVT_S, XMMINFO_WRITED|XMMINFO_READS); - -void recCVT_W() -{ - int regs = _checkXMMreg(XMMTYPE_FPREG, _Fs_, MODE_READ); - - if( regs >= 0 ) - { - if (CHECK_FPU_EXTRA_OVERFLOW) fpuFloat2(regs); - SSE_CVTTSS2SI_XMM_to_R32(EAX, regs); - SSE_MOVMSKPS_XMM_to_R32(EDX, regs); //extract the signs - AND32ItoR(EDX,1); //keep only LSB - } - else - { - SSE_CVTTSS2SI_M32_to_R32(EAX, (uptr)&fpuRegs.fpr[ _Fs_ ]); - MOV32MtoR(EDX, (uptr)&fpuRegs.fpr[ _Fs_ ]); - SHR32ItoR(EDX, 31); //mov sign to lsb - } - - //kill register allocation for dst because we write directly to fpuRegs.fpr[_Fd_] - _deleteFPtoXMMreg(_Fd_, 2); - - ADD32ItoR(EDX, 0x7FFFFFFF); //0x7FFFFFFF if positive, 0x8000 0000 if negative - - CMP32ItoR(EAX, 0x80000000); //If the result is indefinitive - CMOVE32RtoR(EAX, EDX); //Saturate it - - //Write the result - MOV32RtoM((uptr)&fpuRegs.fpr[_Fd_], EAX); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// DIV XMM -//------------------------------------------------------------------ -void recDIVhelper1(int regd, int regt) // Sets flags -{ - u8 *pjmp1, *pjmp2; - u32 *ajmp32, *bjmp32; - int t1reg = _allocTempXMMreg(XMMT_FPS, -1); - int tempReg = _allocX86reg(-1, X86TYPE_TEMP, 0, 0); - //if (t1reg == -1) {Console::Error("FPU: DIV Allocation Error!");} - if (tempReg == -1) {Console::Error("FPU: DIV Allocation Error!"); tempReg = EAX;} - - AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagI|FPUflagD)); // Clear I and D flags - - /*--- Check for divide by zero ---*/ - SSE_XORPS_XMM_to_XMM(t1reg, t1reg); - SSE_CMPEQSS_XMM_to_XMM(t1reg, regt); - SSE_MOVMSKPS_XMM_to_R32(tempReg, t1reg); - AND32ItoR(tempReg, 1); //Check sign (if regt == zero, sign will be set) - ajmp32 = JZ32(0); //Skip if not set - - /*--- Check for 0/0 ---*/ - SSE_XORPS_XMM_to_XMM(t1reg, t1reg); - SSE_CMPEQSS_XMM_to_XMM(t1reg, regd); - SSE_MOVMSKPS_XMM_to_R32(tempReg, t1reg); - AND32ItoR(tempReg, 1); //Check sign (if regd == zero, sign will be set) - pjmp1 = JZ8(0); //Skip if not set - OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagI|FPUflagSI); // Set I and SI flags ( 0/0 ) - pjmp2 = JMP8(0); - x86SetJ8(pjmp1); //x/0 but not 0/0 - OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagD|FPUflagSD); // Set D and SD flags ( x/0 ) - x86SetJ8(pjmp2); - - /*--- Make regd +/- Maximum ---*/ - SSE_XORPS_XMM_to_XMM(regd, regt); // Make regd Positive or Negative - SSE_ANDPS_M128_to_XMM(regd, (uptr)&s_neg[0]); // Get the sign bit - SSE_ORPS_M128_to_XMM(regd, (uptr)&g_maxvals[0]); // regd = +/- Maximum - //SSE_MOVSS_M32_to_XMM(regd, (uptr)&g_maxvals[0]); - bjmp32 = JMP32(0); - - x86SetJ32(ajmp32); - - /*--- Normal Divide ---*/ - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(regt); } - SSE_DIVSS_XMM_to_XMM(regd, regt); - - ClampValues(regd); - x86SetJ32(bjmp32); - - _freeXMMreg(t1reg); - _freeX86reg(tempReg); -} - -void recDIVhelper2(int regd, int regt) // Doesn't sets flags -{ - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(regt); } - SSE_DIVSS_XMM_to_XMM(regd, regt); - ClampValues(regd); -} - -void recDIV_S_xmm(int info) -{ - static u32 PCSX2_ALIGNED16(roundmode_temp[4]) = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; - int roundmodeFlag = 0; - int t0reg = _allocTempXMMreg(XMMT_FPS, -1); - //if (t0reg == -1) {Console::Error("FPU: DIV Allocation Error!");} - //SysPrintf("DIV\n"); - - if ((g_sseMXCSR & 0x00006000) != 0x00000000) { // Set roundmode to nearest if it isn't already - //SysPrintf("div to nearest\n"); - roundmode_temp[0] = (g_sseMXCSR & 0xFFFF9FFF); // Set new roundmode - roundmode_temp[1] = g_sseMXCSR; // Backup old Roundmode - SSE_LDMXCSR ((uptr)&roundmode_temp[0]); // Recompile Roundmode Change - roundmodeFlag = 1; - } - - switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { - case PROCESS_EE_S: - //SysPrintf("FPU: DIV case 1\n"); - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); - if (CHECK_FPU_EXTRA_FLAGS) recDIVhelper1(EEREC_D, t0reg); - else recDIVhelper2(EEREC_D, t0reg); - break; - case PROCESS_EE_T: - //SysPrintf("FPU: DIV case 2\n"); - if (EEREC_D == EEREC_T) { - SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_T); - SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); - if (CHECK_FPU_EXTRA_FLAGS) recDIVhelper1(EEREC_D, t0reg); - else recDIVhelper2(EEREC_D, t0reg); - } - else { - SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); - if (CHECK_FPU_EXTRA_FLAGS) recDIVhelper1(EEREC_D, EEREC_T); - else recDIVhelper2(EEREC_D, EEREC_T); - } - break; - case (PROCESS_EE_S|PROCESS_EE_T): - //SysPrintf("FPU: DIV case 3\n"); - if (EEREC_D == EEREC_T) { - SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_T); - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - if (CHECK_FPU_EXTRA_FLAGS) recDIVhelper1(EEREC_D, t0reg); - else recDIVhelper2(EEREC_D, t0reg); - } - else { - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - if (CHECK_FPU_EXTRA_FLAGS) recDIVhelper1(EEREC_D, EEREC_T); - else recDIVhelper2(EEREC_D, EEREC_T); - } - break; - default: - //SysPrintf("FPU: DIV case 4\n"); - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); - SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); - if (CHECK_FPU_EXTRA_FLAGS) recDIVhelper1(EEREC_D, t0reg); - else recDIVhelper2(EEREC_D, t0reg); - break; - } - if (roundmodeFlag == 1) { // Set roundmode back if it was changed - SSE_LDMXCSR ((uptr)&roundmode_temp[1]); - } - _freeXMMreg(t0reg); -} - -FPURECOMPILE_CONSTCODE(DIV_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// MADD XMM -//------------------------------------------------------------------ -void recMADDtemp(int info, int regd) -{ - int t1reg; - int t0reg = _allocTempXMMreg(XMMT_FPS, -1); - - switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { - case PROCESS_EE_S: - if(regd == EEREC_S) { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(t0reg); } - SSE_MULSS_XMM_to_XMM(regd, t0reg); - if (info & PROCESS_EE_ACC) { - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(EEREC_ACC); fpuFloat(regd); } - FPU_ADD(regd, EEREC_ACC); - } - else { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(EEREC_ACC); fpuFloat(t0reg); } - FPU_ADD(regd, t0reg); - } - } - else if (regd == EEREC_ACC){ - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(EEREC_S); fpuFloat2(t0reg); } - SSE_MULSS_XMM_to_XMM(t0reg, EEREC_S); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_ADD(regd, t0reg); - } - else { - SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Ft_]); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_S); } - SSE_MULSS_XMM_to_XMM(regd, EEREC_S); - if (info & PROCESS_EE_ACC) { - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(EEREC_ACC); fpuFloat(regd); } - FPU_ADD(regd, EEREC_ACC); - } - else { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(EEREC_ACC); fpuFloat(t0reg); } - FPU_ADD(regd, t0reg); - } - } - break; - case PROCESS_EE_T: - if(regd == EEREC_T) { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(t0reg); } - SSE_MULSS_XMM_to_XMM(regd, t0reg); - if (info & PROCESS_EE_ACC) { - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(EEREC_ACC); fpuFloat(regd); } - FPU_ADD(regd, EEREC_ACC); - } - else { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(EEREC_ACC); fpuFloat(t0reg); } - FPU_ADD(regd, t0reg); - } - } - else if (regd == EEREC_ACC){ - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(EEREC_T); fpuFloat2(t0reg); } - SSE_MULSS_XMM_to_XMM(t0reg, EEREC_T); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_ADD(regd, t0reg); - } - else { - SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_T); } - SSE_MULSS_XMM_to_XMM(regd, EEREC_T); - if (info & PROCESS_EE_ACC) { - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(EEREC_ACC); fpuFloat(regd); } - FPU_ADD(regd, EEREC_ACC); - } - else { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(EEREC_ACC); fpuFloat(t0reg); } - FPU_ADD(regd, t0reg); - } - } - break; - case (PROCESS_EE_S|PROCESS_EE_T): - if(regd == EEREC_S) { - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_T); } - SSE_MULSS_XMM_to_XMM(regd, EEREC_T); - if (info & PROCESS_EE_ACC) { - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(EEREC_ACC); } - FPU_ADD(regd, EEREC_ACC); - } - else { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_ADD(regd, t0reg); - } - } - else if(regd == EEREC_T) { - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_S); } - SSE_MULSS_XMM_to_XMM(regd, EEREC_S); - if (info & PROCESS_EE_ACC) { - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(EEREC_ACC); } - FPU_ADD(regd, EEREC_ACC); - } - else { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_ADD(regd, t0reg); - } - } - else if(regd == EEREC_ACC) { - SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_S); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(t0reg); fpuFloat2(EEREC_T); } - SSE_MULSS_XMM_to_XMM(t0reg, EEREC_T); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_ADD(regd, t0reg); - } - else { - SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_T); } - SSE_MULSS_XMM_to_XMM(regd, EEREC_T); - if (info & PROCESS_EE_ACC) { - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(EEREC_ACC); } - FPU_ADD(regd, EEREC_ACC); - } - else { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_ADD(regd, t0reg); - } - } - break; - default: - if(regd == EEREC_ACC){ - t1reg = _allocTempXMMreg(XMMT_FPS, -1); - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); - SSE_MOVSS_M32_to_XMM(t1reg, (uptr)&fpuRegs.fpr[_Ft_]); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(t0reg); fpuFloat2(t1reg); } - SSE_MULSS_XMM_to_XMM(t0reg, t1reg); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_ADD(regd, t0reg); - _freeXMMreg(t1reg); - } - else - { - SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(t0reg); } - SSE_MULSS_XMM_to_XMM(regd, t0reg); - if (info & PROCESS_EE_ACC) { - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(EEREC_ACC); } - FPU_ADD(regd, EEREC_ACC); - } - else { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_ADD(regd, t0reg); - } - } - break; - } - - ClampValues(regd); - _freeXMMreg(t0reg); -} - -void recMADD_S_xmm(int info) -{ - //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags - recMADDtemp(info, EEREC_D); -} - -FPURECOMPILE_CONSTCODE(MADD_S, XMMINFO_WRITED|XMMINFO_READACC|XMMINFO_READS|XMMINFO_READT); - -void recMADDA_S_xmm(int info) -{ - //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags - recMADDtemp(info, EEREC_ACC); -} - -FPURECOMPILE_CONSTCODE(MADDA_S, XMMINFO_WRITEACC|XMMINFO_READACC|XMMINFO_READS|XMMINFO_READT); -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// MAX / MIN XMM -//------------------------------------------------------------------ -void recMAX_S_xmm(int info) -{ - //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags - recCommutativeOp(info, EEREC_D, 2); -} - -FPURECOMPILE_CONSTCODE(MAX_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); - -void recMIN_S_xmm(int info) -{ - //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags - recCommutativeOp(info, EEREC_D, 3); -} - -FPURECOMPILE_CONSTCODE(MIN_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// MOV XMM -//------------------------------------------------------------------ -void recMOV_S_xmm(int info) -{ - if( info & PROCESS_EE_S ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - else SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); -} - -FPURECOMPILE_CONSTCODE(MOV_S, XMMINFO_WRITED|XMMINFO_READS); -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// MSUB XMM -//------------------------------------------------------------------ -void recMSUBtemp(int info, int regd) -{ -int t1reg; - int t0reg = _allocTempXMMreg(XMMT_FPS, -1); - - switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { - case PROCESS_EE_S: - if(regd == EEREC_S) { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(t0reg); } - SSE_MULSS_XMM_to_XMM(regd, t0reg); - if (info & PROCESS_EE_ACC) { SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_ACC); } - else { SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); } - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_SUB(t0reg, regd); - SSE_MOVSS_XMM_to_XMM(regd, t0reg); - } - else if (regd == EEREC_ACC){ - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(EEREC_S); fpuFloat2(t0reg); } - SSE_MULSS_XMM_to_XMM(t0reg, EEREC_S); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_SUB(regd, t0reg); - } - else { - SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Ft_]); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_S); } - SSE_MULSS_XMM_to_XMM(regd, EEREC_S); - if (info & PROCESS_EE_ACC) { SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_ACC); } - else { SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); } - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_SUB(t0reg, regd); - SSE_MOVSS_XMM_to_XMM(regd, t0reg); - } - break; - case PROCESS_EE_T: - if(regd == EEREC_T) { - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(t0reg); } - SSE_MULSS_XMM_to_XMM(regd, t0reg); - if (info & PROCESS_EE_ACC) { SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_ACC); } - else { SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); } - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_SUB(t0reg, regd); - SSE_MOVSS_XMM_to_XMM(regd, t0reg); - } - else if (regd == EEREC_ACC){ - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(EEREC_T); fpuFloat2(t0reg); } - SSE_MULSS_XMM_to_XMM(t0reg, EEREC_T); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_SUB(regd, t0reg); - } - else { - SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_T); } - SSE_MULSS_XMM_to_XMM(regd, EEREC_T); - if (info & PROCESS_EE_ACC) { SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_ACC); } - else { SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); } - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_SUB(t0reg, regd); - SSE_MOVSS_XMM_to_XMM(regd, t0reg); - } - break; - case (PROCESS_EE_S|PROCESS_EE_T): - if(regd == EEREC_S) { - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_T); } - SSE_MULSS_XMM_to_XMM(regd, EEREC_T); - if (info & PROCESS_EE_ACC) { SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_ACC); } - else { SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); } - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_SUB(t0reg, regd); - SSE_MOVSS_XMM_to_XMM(regd, t0reg); - } - else if(regd == EEREC_T) { - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_S); } - SSE_MULSS_XMM_to_XMM(regd, EEREC_S); - if (info & PROCESS_EE_ACC) { SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_ACC); } - else { SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); } - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_SUB(t0reg, regd); - SSE_MOVSS_XMM_to_XMM(regd, t0reg); - } - else if(regd == EEREC_ACC) { - SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_S); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(t0reg); fpuFloat2(EEREC_T); } - SSE_MULSS_XMM_to_XMM(t0reg, EEREC_T); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_SUB(regd, t0reg); - } - else { - SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_T); } - SSE_MULSS_XMM_to_XMM(regd, EEREC_T); - if (info & PROCESS_EE_ACC) { SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_ACC); } - else { SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); } - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_SUB(t0reg, regd); - SSE_MOVSS_XMM_to_XMM(regd, t0reg); - } - break; - default: - if(regd == EEREC_ACC){ - t1reg = _allocTempXMMreg(XMMT_FPS, -1); - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); - SSE_MOVSS_M32_to_XMM(t1reg, (uptr)&fpuRegs.fpr[_Ft_]); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(t0reg); fpuFloat2(t1reg); } - SSE_MULSS_XMM_to_XMM(t0reg, t1reg); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_SUB(regd, t0reg); - _freeXMMreg(t1reg); - } - else - { - SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(t0reg); } - SSE_MULSS_XMM_to_XMM(regd, t0reg); - if (info & PROCESS_EE_ACC) { SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_ACC); } - else { SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); } - if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } - FPU_SUB(t0reg, regd); - SSE_MOVSS_XMM_to_XMM(regd, t0reg); - } - break; - } - - ClampValues(regd); - _freeXMMreg(t0reg); - -} - -void recMSUB_S_xmm(int info) -{ - //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags - recMSUBtemp(info, EEREC_D); -} - -FPURECOMPILE_CONSTCODE(MSUB_S, XMMINFO_WRITED|XMMINFO_READACC|XMMINFO_READS|XMMINFO_READT); - -void recMSUBA_S_xmm(int info) -{ - //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags - recMSUBtemp(info, EEREC_ACC); -} - -FPURECOMPILE_CONSTCODE(MSUBA_S, XMMINFO_WRITEACC|XMMINFO_READACC|XMMINFO_READS|XMMINFO_READT); -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// MUL XMM -//------------------------------------------------------------------ -void recMUL_S_xmm(int info) -{ - //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags - ClampValues(recCommutativeOp(info, EEREC_D, 1)); -} - -FPURECOMPILE_CONSTCODE(MUL_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); - -void recMULA_S_xmm(int info) -{ - //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags - ClampValues(recCommutativeOp(info, EEREC_ACC, 1)); -} - -FPURECOMPILE_CONSTCODE(MULA_S, XMMINFO_WRITEACC|XMMINFO_READS|XMMINFO_READT); -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// NEG XMM -//------------------------------------------------------------------ -void recNEG_S_xmm(int info) { - if( info & PROCESS_EE_S ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - else SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); - - //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags - SSE_XORPS_M128_to_XMM(EEREC_D, (uptr)&s_neg[0]); - ClampValues(EEREC_D); -} - -FPURECOMPILE_CONSTCODE(NEG_S, XMMINFO_WRITED|XMMINFO_READS); -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// SUB XMM -//------------------------------------------------------------------ -void recSUBhelper(int regd, int regt) -{ - if (CHECK_FPU_EXTRA_OVERFLOW /*&& !CHECK_FPUCLAMPHACK*/) { fpuFloat2(regd); fpuFloat2(regt); } - FPU_SUB(regd, regt); -} - -void recSUBop(int info, int regd) -{ - int t0reg = _allocTempXMMreg(XMMT_FPS, -1); - //if (t0reg == -1) {SysPrintf("FPU: SUB Allocation Error!\n");} - - //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags - - switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { - case PROCESS_EE_S: - //SysPrintf("FPU: SUB case 1\n"); - if (regd != EEREC_S) SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); - recSUBhelper(regd, t0reg); - break; - case PROCESS_EE_T: - //SysPrintf("FPU: SUB case 2\n"); - if (regd == EEREC_T) { - SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_T); - SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); - recSUBhelper(regd, t0reg); - } - else { - SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); - recSUBhelper(regd, EEREC_T); - } - break; - case (PROCESS_EE_S|PROCESS_EE_T): - //SysPrintf("FPU: SUB case 3\n"); - if (regd == EEREC_T) { - SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_T); - SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); - recSUBhelper(regd, t0reg); - } - else { - SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); - recSUBhelper(regd, EEREC_T); - } - break; - default: - Console::Notice("FPU: SUB case 4"); - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); - SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); - recSUBhelper(regd, t0reg); - break; - } - - ClampValues2(regd); - _freeXMMreg(t0reg); -} - -void recSUB_S_xmm(int info) -{ - recSUBop(info, EEREC_D); -} - -FPURECOMPILE_CONSTCODE(SUB_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); - - -void recSUBA_S_xmm(int info) -{ - recSUBop(info, EEREC_ACC); -} - -FPURECOMPILE_CONSTCODE(SUBA_S, XMMINFO_WRITEACC|XMMINFO_READS|XMMINFO_READT); -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// SQRT XMM -//------------------------------------------------------------------ -void recSQRT_S_xmm(int info) -{ - u8* pjmp; - static u32 PCSX2_ALIGNED16(roundmode_temp[4]) = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; - int roundmodeFlag = 0; - //SysPrintf("FPU: SQRT\n"); - - if ((g_sseMXCSR & 0x00006000) != 0x00000000) { // Set roundmode to nearest if it isn't already - //SysPrintf("sqrt to nearest\n"); - roundmode_temp[0] = (g_sseMXCSR & 0xFFFF9FFF); // Set new roundmode - roundmode_temp[1] = g_sseMXCSR; // Backup old Roundmode - SSE_LDMXCSR ((uptr)&roundmode_temp[0]); // Recompile Roundmode Change - roundmodeFlag = 1; - } - - if( info & PROCESS_EE_T ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_T); - else SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Ft_]); - - if (CHECK_FPU_EXTRA_FLAGS) { - int tempReg = _allocX86reg(-1, X86TYPE_TEMP, 0, 0); - if (tempReg == -1) {Console::Error("FPU: SQRT Allocation Error!"); tempReg = EAX;} - - AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagI|FPUflagD)); // Clear I and D flags - - /*--- Check for negative SQRT ---*/ - SSE_MOVMSKPS_XMM_to_R32(tempReg, EEREC_D); - AND32ItoR(tempReg, 1); //Check sign - pjmp = JZ8(0); //Skip if none are - OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagI|FPUflagSI); // Set I and SI flags - SSE_ANDPS_M128_to_XMM(EEREC_D, (uptr)&s_pos[0]); // Make EEREC_D Positive - x86SetJ8(pjmp); - - _freeX86reg(tempReg); - } - else SSE_ANDPS_M128_to_XMM(EEREC_D, (uptr)&s_pos[0]); // Make EEREC_D Positive - - if (CHECK_FPU_OVERFLOW) SSE_MINSS_M32_to_XMM(EEREC_D, (uptr)&g_maxvals[0]);// Only need to do positive clamp, since EEREC_D is positive - SSE_SQRTSS_XMM_to_XMM(EEREC_D, EEREC_D); - if (CHECK_FPU_EXTRA_OVERFLOW) ClampValues(EEREC_D); // Shouldn't need to clamp again since SQRT of a number will always be smaller than the original number, doing it just incase :/ - - if (roundmodeFlag == 1) { // Set roundmode back if it was changed - SSE_LDMXCSR ((uptr)&roundmode_temp[1]); - } -} - -FPURECOMPILE_CONSTCODE(SQRT_S, XMMINFO_WRITED|XMMINFO_READT); -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// RSQRT XMM -//------------------------------------------------------------------ -void recRSQRThelper1(int regd, int t0reg) // Preforms the RSQRT function when regd <- Fs and t0reg <- Ft (Sets correct flags) -{ - u8 *pjmp1, *pjmp2; - u32 *pjmp32; - int t1reg = _allocTempXMMreg(XMMT_FPS, -1); - int tempReg = _allocX86reg(-1, X86TYPE_TEMP, 0, 0); - //if (t1reg == -1) {Console::Error("FPU: RSQRT Allocation Error!");} - if (tempReg == -1) {Console::Error("FPU: RSQRT Allocation Error!"); tempReg = EAX;} - - AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagI|FPUflagD)); // Clear I and D flags - - /*--- Check for zero ---*/ - SSE_XORPS_XMM_to_XMM(t1reg, t1reg); - SSE_CMPEQSS_XMM_to_XMM(t1reg, t0reg); - SSE_MOVMSKPS_XMM_to_R32(tempReg, t1reg); - AND32ItoR(tempReg, 1); //Check sign (if t0reg == zero, sign will be set) - pjmp1 = JZ8(0); //Skip if not set - OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagD|FPUflagSD); // Set D and SD flags - SSE_XORPS_XMM_to_XMM(regd, t0reg); // Make regd Positive or Negative - SSE_ANDPS_M128_to_XMM(regd, (uptr)&s_neg[0]); // Get the sign bit - SSE_ORPS_M128_to_XMM(regd, (uptr)&g_maxvals[0]); // regd = +/- Maximum - pjmp32 = JMP32(0); - x86SetJ8(pjmp1); - - /*--- Check for negative SQRT ---*/ - SSE_MOVMSKPS_XMM_to_R32(tempReg, t0reg); - AND32ItoR(tempReg, 1); //Check sign - pjmp2 = JZ8(0); //Skip if not set - OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagI|FPUflagSI); // Set I and SI flags - SSE_ANDPS_M128_to_XMM(t0reg, (uptr)&s_pos[0]); // Make t0reg Positive - x86SetJ8(pjmp2); - - if (CHECK_FPU_EXTRA_OVERFLOW) { - SSE_MINSS_M32_to_XMM(t0reg, (uptr)&g_maxvals[0]); // Only need to do positive clamp, since t0reg is positive - fpuFloat2(regd); - } - - SSE_SQRTSS_XMM_to_XMM(t0reg, t0reg); - SSE_DIVSS_XMM_to_XMM(regd, t0reg); - - ClampValues(regd); - x86SetJ32(pjmp32); - - _freeXMMreg(t1reg); - _freeX86reg(tempReg); -} - -void recRSQRThelper2(int regd, int t0reg) // Preforms the RSQRT function when regd <- Fs and t0reg <- Ft (Doesn't set flags) -{ - SSE_ANDPS_M128_to_XMM(t0reg, (uptr)&s_pos[0]); // Make t0reg Positive - if (CHECK_FPU_EXTRA_OVERFLOW) { - SSE_MINSS_M32_to_XMM(t0reg, (uptr)&g_maxvals[0]); // Only need to do positive clamp, since t0reg is positive - fpuFloat2(regd); - } - SSE_SQRTSS_XMM_to_XMM(t0reg, t0reg); - SSE_DIVSS_XMM_to_XMM(regd, t0reg); - ClampValues(regd); -} - -void recRSQRT_S_xmm(int info) -{ - int t0reg = _allocTempXMMreg(XMMT_FPS, -1); - //if (t0reg == -1) {Console::Error("FPU: RSQRT Allocation Error!");} - //SysPrintf("FPU: RSQRT\n"); - - switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { - case PROCESS_EE_S: - //SysPrintf("FPU: RSQRT case 1\n"); - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); - if (CHECK_FPU_EXTRA_FLAGS) recRSQRThelper1(EEREC_D, t0reg); - else recRSQRThelper2(EEREC_D, t0reg); - break; - case PROCESS_EE_T: - //SysPrintf("FPU: RSQRT case 2\n"); - SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_T); - SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); - if (CHECK_FPU_EXTRA_FLAGS) recRSQRThelper1(EEREC_D, t0reg); - else recRSQRThelper2(EEREC_D, t0reg); - break; - case (PROCESS_EE_S|PROCESS_EE_T): - //SysPrintf("FPU: RSQRT case 3\n"); - SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_T); - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - if (CHECK_FPU_EXTRA_FLAGS) recRSQRThelper1(EEREC_D, t0reg); - else recRSQRThelper2(EEREC_D, t0reg); - break; - default: - //SysPrintf("FPU: RSQRT case 4\n"); - SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); - SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); - if (CHECK_FPU_EXTRA_FLAGS) recRSQRThelper1(EEREC_D, t0reg); - else recRSQRThelper2(EEREC_D, t0reg); - break; - } - _freeXMMreg(t0reg); -} - -FPURECOMPILE_CONSTCODE(RSQRT_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); - -#endif // FPU_RECOMPILE - -} } } } +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "R5900OpcodeTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "iFPU.h" + +extern PCSX2_ALIGNED16_DECL(u32 g_minvals[4]); +extern PCSX2_ALIGNED16_DECL(u32 g_maxvals[4]); + +//------------------------------------------------------------------ +// Misc... +//------------------------------------------------------------------ +//static u32 _mxcsr = 0x7F80; +//static u32 _mxcsrs; +static u32 fpucw = 0x007f; +static u32 fpucws = 0; + +void SaveCW(int type) { + if (iCWstate & type) return; + + if (type == 2) { +// SSE_STMXCSR((uptr)&_mxcsrs); +// SSE_LDMXCSR((uptr)&_mxcsr); + } else { + FNSTCW( (uptr)&fpucws ); + FLDCW( (uptr)&fpucw ); + } + iCWstate|= type; +} + +void LoadCW() { + if (iCWstate == 0) return; + + if (iCWstate & 2) { + //SSE_LDMXCSR((uptr)&_mxcsrs); + } + if (iCWstate & 1) { + FLDCW( (uptr)&fpucws ); + } + iCWstate = 0; +} + +//------------------------------------------------------------------ +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl { +namespace COP1 { + +//------------------------------------------------------------------ +// Helper Macros +//------------------------------------------------------------------ +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +// FCR31 Flags +#define FPUflagC 0X00800000 +#define FPUflagI 0X00020000 +#define FPUflagD 0X00010000 +#define FPUflagO 0X00008000 +#define FPUflagU 0X00004000 +#define FPUflagSI 0X00000040 +#define FPUflagSD 0X00000020 +#define FPUflagSO 0X00000010 +#define FPUflagSU 0X00000008 + +#define FPU_ADD_SUB_HACK 1 // Add/Sub opcodes produce more ps2-like results if set to 1 + +static u32 PCSX2_ALIGNED16(s_neg[4]) = { 0x80000000, 0xffffffff, 0xffffffff, 0xffffffff }; +static u32 PCSX2_ALIGNED16(s_pos[4]) = { 0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff }; + +#define REC_FPUBRANCH(f) \ + void f(); \ + void rec##f() { \ + MOV32ItoM((uptr)&cpuRegs.code, cpuRegs.code); \ + MOV32ItoM((uptr)&cpuRegs.pc, pc); \ + iFlushCall(FLUSH_EVERYTHING); \ + CALLFunc((uptr)R5900::Interpreter::OpcodeImpl::COP1::f); \ + branch = 2; \ +} + +#define REC_FPUFUNC(f) \ + void f(); \ + void rec##f() { \ + MOV32ItoM((uptr)&cpuRegs.code, cpuRegs.code); \ + MOV32ItoM((uptr)&cpuRegs.pc, pc); \ + iFlushCall(FLUSH_EVERYTHING); \ + CALLFunc((uptr)R5900::Interpreter::OpcodeImpl::COP1::f); \ +} +//------------------------------------------------------------------ + +//------------------------------------------------------------------ +// *FPU Opcodes!* +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// CFC1 / CTC1 +//------------------------------------------------------------------ +void recCFC1(void) +{ + if ( !_Rt_ || ( (_Fs_ != 0) && (_Fs_ != 31) ) ) return; + + _eeOnWriteReg(_Rt_, 1); + + MOV32MtoR( EAX, (uptr)&fpuRegs.fprc[ _Fs_ ] ); + _deleteEEreg(_Rt_, 0); + + if(EEINST_ISLIVE1(_Rt_)) + { + CDQ( ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); + } + else + { + EEINST_RESETHASLIVE1(_Rt_); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + } +} + +void recCTC1( void ) +{ + if ( _Fs_ != 31 ) return; + + if ( GPR_IS_CONST1(_Rt_) ) + { + MOV32ItoM((uptr)&fpuRegs.fprc[ _Fs_ ], g_cpuConstRegs[_Rt_].UL[0]); + } + else + { + int mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ); + + if( mmreg >= 0 ) + { + SSEX_MOVD_XMM_to_M32((uptr)&fpuRegs.fprc[ _Fs_ ], mmreg); + } + + else + { + mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_READ); + + if ( mmreg >= 0 ) + { + MOVDMMXtoM((uptr)&fpuRegs.fprc[ _Fs_ ], mmreg); + SetMMXstate(); + } + else + { + _deleteGPRtoXMMreg(_Rt_, 1); + _deleteMMXreg(MMX_GPR+_Rt_, 1); + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + MOV32RtoM( (uptr)&fpuRegs.fprc[ _Fs_ ], EAX ); + } + } + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// MFC1 +//------------------------------------------------------------------ + +void recMFC1(void) +{ + int regt, regs; + if ( ! _Rt_ ) return; + + _eeOnWriteReg(_Rt_, 1); + + regs = _checkXMMreg(XMMTYPE_FPREG, _Fs_, MODE_READ); + + if( regs >= 0 ) + { + _deleteGPRtoXMMreg(_Rt_, 2); + regt = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); + + if( regt >= 0 ) + { + SSE2_MOVDQ2Q_XMM_to_MM(regt, regs); + + if(EEINST_ISLIVE1(_Rt_)) + _signExtendGPRtoMMX(regt, _Rt_, 0); + else + EEINST_RESETHASLIVE1(_Rt_); + } + else + { + if(EEINST_ISLIVE1(_Rt_)) + { + _signExtendXMMtoM((uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], regs, 0); + } + else + { + EEINST_RESETHASLIVE1(_Rt_); + SSE_MOVSS_XMM_to_M32((uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], regs); + } + } + } + else + { + regs = _checkMMXreg(MMX_FPU+_Fs_, MODE_READ); + + if( regs >= 0 ) + { + // convert to mmx reg + mmxregs[regs].reg = MMX_GPR+_Rt_; + mmxregs[regs].mode |= MODE_READ|MODE_WRITE; + _signExtendGPRtoMMX(regs, _Rt_, 0); + } + else + { + regt = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ); + + if( regt >= 0 ) + { + if( xmmregs[regt].mode & MODE_WRITE ) + { + SSE_MOVHPS_XMM_to_M64((uptr)&cpuRegs.GPR.r[_Rt_].UL[2], regt); + } + xmmregs[regt].inuse = 0; + } + + _deleteEEreg(_Rt_, 0); + MOV32MtoR( EAX, (uptr)&fpuRegs.fpr[ _Fs_ ].UL ); + + if(EEINST_ISLIVE1(_Rt_)) + { + CDQ( ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); + } + else + { + EEINST_RESETHASLIVE1(_Rt_); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + } + } + } +} + +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// MTC1 +//------------------------------------------------------------------ +void recMTC1(void) +{ + if( GPR_IS_CONST1(_Rt_) ) + { + _deleteFPtoXMMreg(_Fs_, 0); + MOV32ItoM((uptr)&fpuRegs.fpr[ _Fs_ ].UL, g_cpuConstRegs[_Rt_].UL[0]); + } + else + { + int mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ); + + if( mmreg >= 0 ) + { + if( g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE ) + { + // transfer the reg directly + _deleteGPRtoXMMreg(_Rt_, 2); + _deleteFPtoXMMreg(_Fs_, 2); + _allocFPtoXMMreg(mmreg, _Fs_, MODE_WRITE); + } + else + { + int mmreg2 = _allocCheckFPUtoXMM(g_pCurInstInfo, _Fs_, MODE_WRITE); + + if( mmreg2 >= 0 ) + SSE_MOVSS_XMM_to_XMM(mmreg2, mmreg); + else + SSE_MOVSS_XMM_to_M32((uptr)&fpuRegs.fpr[ _Fs_ ].UL, mmreg); + } + } + else + { + int mmreg2; + + mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_READ); + mmreg2 = _allocCheckFPUtoXMM(g_pCurInstInfo, _Fs_, MODE_WRITE); + + if( mmreg >= 0 ) + { + if( mmreg2 >= 0 ) + { + SetMMXstate(); + SSE2_MOVQ2DQ_MM_to_XMM(mmreg2, mmreg); + } + else + { + SetMMXstate(); + MOVDMMXtoM((uptr)&fpuRegs.fpr[ _Fs_ ].UL, mmreg); + } + } + else + { + if( mmreg2 >= 0 ) + { + SSE_MOVSS_M32_to_XMM(mmreg2, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + } + else + { + MOV32MtoR(EAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + MOV32RtoM((uptr)&fpuRegs.fpr[ _Fs_ ].UL, EAX); + } + } + } + } +} +//------------------------------------------------------------------ + + +#ifndef FPU_RECOMPILE // If FPU_RECOMPILE is not defined, then use the interpreter opcodes. (CFC1, CTC1, MFC1, and MTC1 are special because they work specifically with the EE rec so they're defined above) + +REC_FPUFUNC(ABS_S); +REC_FPUFUNC(ADD_S); +REC_FPUFUNC(ADDA_S); +REC_FPUBRANCH(BC1F); +REC_FPUBRANCH(BC1T); +REC_FPUBRANCH(BC1FL); +REC_FPUBRANCH(BC1TL); +REC_FPUFUNC(C_EQ); +REC_FPUFUNC(C_F); +REC_FPUFUNC(C_LE); +REC_FPUFUNC(C_LT); +REC_FPUFUNC(CVT_S); +REC_FPUFUNC(CVT_W); +REC_FPUFUNC(DIV_S); +REC_FPUFUNC(MAX_S); +REC_FPUFUNC(MIN_S); +REC_FPUFUNC(MADD_S); +REC_FPUFUNC(MADDA_S); +REC_FPUFUNC(MOV_S); +REC_FPUFUNC(MSUB_S); +REC_FPUFUNC(MSUBA_S); +REC_FPUFUNC(MUL_S); +REC_FPUFUNC(MULA_S); +REC_FPUFUNC(NEG_S); +REC_FPUFUNC(SUB_S); +REC_FPUFUNC(SUBA_S); +REC_FPUFUNC(SQRT_S); +REC_FPUFUNC(RSQRT_S); + +#else // FPU_RECOMPILE + +//------------------------------------------------------------------ +// Clamp Functions (Converts NaN's and Infinities to Normal Numbers) +//------------------------------------------------------------------ +void fpuFloat(int regd) { // +/-NaN -> +fMax, +Inf -> +fMax, -Inf -> -fMax + if (CHECK_FPU_OVERFLOW && !CHECK_FPUCLAMPHACK) { // Tekken 5 doesn't like clamping infinities. + SSE_MINSS_M32_to_XMM(regd, (uptr)&g_maxvals[0]); // MIN() must be before MAX()! So that NaN's become +Maximum + SSE_MAXSS_M32_to_XMM(regd, (uptr)&g_minvals[0]); + } +} + +PCSX2_ALIGNED16(u64 FPU_FLOAT_TEMP[2]); +void fpuFloat2(int regd) { // +NaN -> +fMax, -NaN -> -fMax, +Inf -> +fMax, -Inf -> -fMax + if (CHECK_FPU_OVERFLOW && !CHECK_FPUCLAMPHACK) { // Tekken 5 doesn't like clamping infinities. + int t1reg = _allocTempXMMreg(XMMT_FPS, -1); + if (t1reg >= 0) { + SSE_MOVSS_XMM_to_XMM(t1reg, regd); + SSE_ANDPS_M128_to_XMM(t1reg, (uptr)&s_neg[0]); + SSE_MINSS_M32_to_XMM(regd, (uptr)&g_maxvals[0]); + SSE_MAXSS_M32_to_XMM(regd, (uptr)&g_minvals[0]); + SSE_ORPS_XMM_to_XMM(regd, t1reg); + _freeXMMreg(t1reg); + } + else { + Console::Error("fpuFloat2() allocation error"); + t1reg = (regd == 0) ? 1 : 0; // get a temp reg thats not regd + SSE_MOVAPS_XMM_to_M128( (uptr)&FPU_FLOAT_TEMP[0], t1reg ); // backup data in t1reg to a temp address + SSE_MOVSS_XMM_to_XMM(t1reg, regd); + SSE_ANDPS_M128_to_XMM(t1reg, (uptr)&s_neg[0]); + SSE_MINSS_M32_to_XMM(regd, (uptr)&g_maxvals[0]); + SSE_MAXSS_M32_to_XMM(regd, (uptr)&g_minvals[0]); + SSE_ORPS_XMM_to_XMM(regd, t1reg); + SSE_MOVAPS_M128_to_XMM( t1reg, (uptr)&FPU_FLOAT_TEMP[0] ); // restore t1reg data + } + } +} + +void ClampValues(int regd) { + fpuFloat(regd); +} + +void ClampValues2(int regd) { + if (CHECK_FPUCLAMPHACK) { // Fixes Tekken 5 ( Makes NaN equal 0, infinities stay the same ) + int t5reg = _allocTempXMMreg(XMMT_FPS, -1); + + SSE_XORPS_XMM_to_XMM(t5reg, t5reg); + SSE_CMPORDSS_XMM_to_XMM(t5reg, regd); + + SSE_ANDPS_XMM_to_XMM(regd, t5reg); + + /* --- Its odd but tekken dosn't like Infinities to be clamped. --- */ + //SSE_MINSS_M32_to_XMM(regd, (uptr)&g_maxvals[0]); + //SSE_MAXSS_M32_to_XMM(regd, (uptr)&g_minvals[0]); + + _freeXMMreg(t5reg); + } + else fpuFloat(regd); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ABS XMM +//------------------------------------------------------------------ +void recABS_S_xmm(int info) +{ + if( info & PROCESS_EE_S ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + else SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); + + SSE_ANDPS_M128_to_XMM(EEREC_D, (uptr)&s_pos[0]); + //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags + + if (CHECK_FPU_OVERFLOW) // Only need to do positive clamp, since EEREC_D is positive + SSE_MINSS_M32_to_XMM(EEREC_D, (uptr)&g_maxvals[0]); +} + +FPURECOMPILE_CONSTCODE(ABS_S, XMMINFO_WRITED|XMMINFO_READS); +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// FPU_ADD_SUB (Used to mimic PS2's FPU add/sub behavior) +//------------------------------------------------------------------ +// Compliant IEEE FPU uses, in computations, uses additional "guard" bits to the right of the mantissa +// but EE-FPU doesn't. Substraction (and addition of positive and negative) may shift the mantissa left, +// causing those bits to appear in the result; this function masks out the bits of the mantissa that will +// get shifted right to the guard bits to ensure that the guard bits are empty. +// The difference of the exponents = the amount that the smaller operand will be shifted right by. +// Modification - the PS2 uses a single guard bit? (Coded by Nneeve) +//------------------------------------------------------------------ +void FPU_ADD_SUB(int regd, int regt, int issub) +{ + int tempecx = _allocX86reg(ECX, X86TYPE_TEMP, 0, 0); //receives regd + int temp2 = _allocX86reg(-1, X86TYPE_TEMP, 0, 0); //receives regt + int xmmtemp = _allocTempXMMreg(XMMT_FPS, -1); //temporary for anding with regd/regt + + if (tempecx != ECX) { Console::Error("FPU: ADD/SUB Allocation Error!"); tempecx = ECX;} + if (temp2 == -1) { Console::Error("FPU: ADD/SUB Allocation Error!"); temp2 = EAX;} + if (xmmtemp == -1) { Console::Error("FPU: ADD/SUB Allocation Error!"); xmmtemp = XMM0;} + + SSE2_MOVD_XMM_to_R(tempecx, regd); + SSE2_MOVD_XMM_to_R(temp2, regt); + + //mask the exponents + SHR32ItoR(tempecx, 23); + SHR32ItoR(temp2, 23); + AND32ItoR(tempecx, 0xff); + AND32ItoR(temp2, 0xff); + + SUB32RtoR(tempecx, temp2); //tempecx = exponent difference + CMP32ItoR(tempecx, 25); + j8Ptr[0] = JGE8(0); + CMP32ItoR(tempecx, 0); + j8Ptr[1] = JG8(0); + j8Ptr[2] = JE8(0); + CMP32ItoR(tempecx, -25); + j8Ptr[3] = JLE8(0); + + //diff = -24 .. -1 , expd < expt + NEG32R(tempecx); + DEC32R(tempecx); + MOV32ItoR(temp2, 0xffffffff); + SHL32CLtoR(temp2); //temp2 = 0xffffffff << tempecx + SSE2_MOVD_R_to_XMM(xmmtemp, temp2); + SSE_ANDPS_XMM_to_XMM(regd, xmmtemp); + if (issub) + SSE_SUBSS_XMM_to_XMM(regd, regt); + else + SSE_ADDSS_XMM_to_XMM(regd, regt); + j8Ptr[4] = JMP8(0); + + x86SetJ8(j8Ptr[0]); + //diff = 25 .. 255 , expt < expd + SSE_MOVAPS_XMM_to_XMM(xmmtemp, regt); + SSE_ANDPS_M128_to_XMM(xmmtemp, (uptr)s_neg); + if (issub) + SSE_SUBSS_XMM_to_XMM(regd, xmmtemp); + else + SSE_ADDSS_XMM_to_XMM(regd, xmmtemp); + j8Ptr[5] = JMP8(0); + + x86SetJ8(j8Ptr[1]); + //diff = 1 .. 24, expt < expd + DEC32R(tempecx); + MOV32ItoR(temp2, 0xffffffff); + SHL32CLtoR(temp2); //temp2 = 0xffffffff << tempecx + SSE2_MOVD_R_to_XMM(xmmtemp, temp2); + SSE_ANDPS_XMM_to_XMM(xmmtemp, regt); + if (issub) + SSE_SUBSS_XMM_to_XMM(regd, xmmtemp); + else + SSE_ADDSS_XMM_to_XMM(regd, xmmtemp); + j8Ptr[6] = JMP8(0); + + x86SetJ8(j8Ptr[3]); + //diff = -255 .. -25, expd < expt + SSE_ANDPS_M128_to_XMM(regd, (uptr)s_neg); + if (issub) + SSE_SUBSS_XMM_to_XMM(regd, regt); + else + SSE_ADDSS_XMM_to_XMM(regd, regt); + j8Ptr[7] = JMP8(0); + + x86SetJ8(j8Ptr[2]); + //diff == 0 + if (issub) + SSE_SUBSS_XMM_to_XMM(regd, regt); + else + SSE_ADDSS_XMM_to_XMM(regd, regt); + + x86SetJ8(j8Ptr[4]); + x86SetJ8(j8Ptr[5]); + x86SetJ8(j8Ptr[6]); + x86SetJ8(j8Ptr[7]); + + _freeXMMreg(xmmtemp); + _freeX86reg(temp2); + _freeX86reg(tempecx); +} + +void FPU_ADD(int regd, int regt) { + if (FPU_ADD_SUB_HACK) FPU_ADD_SUB(regd, regt, 0); + else SSE_ADDSS_XMM_to_XMM(regd, regt); +} + +void FPU_SUB(int regd, int regt) { + if (FPU_ADD_SUB_HACK) FPU_ADD_SUB(regd, regt, 1); + else SSE_SUBSS_XMM_to_XMM(regd, regt); +} + + +//------------------------------------------------------------------ +// CommutativeOp XMM (used for ADD, MUL, MAX, and MIN opcodes) +//------------------------------------------------------------------ +static void (*recComOpXMM_to_XMM[] )(x86SSERegType, x86SSERegType) = { + FPU_ADD, SSE_MULSS_XMM_to_XMM, SSE_MAXSS_XMM_to_XMM, SSE_MINSS_XMM_to_XMM }; + +//static void (*recComOpM32_to_XMM[] )(x86SSERegType, uptr) = { +// SSE_ADDSS_M32_to_XMM, SSE_MULSS_M32_to_XMM, SSE_MAXSS_M32_to_XMM, SSE_MINSS_M32_to_XMM }; + +int recCommutativeOp(int info, int regd, int op) +{ + int t0reg = _allocTempXMMreg(XMMT_FPS, -1); + //if (t0reg == -1) {SysPrintf("FPU: CommutativeOp Allocation Error!\n");} + + switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { + case PROCESS_EE_S: + if (regd == EEREC_S) { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + if (CHECK_FPU_EXTRA_OVERFLOW /*&& !CHECK_FPUCLAMPHACK */ || (op >= 2)) { fpuFloat2(regd); fpuFloat2(t0reg); } + recComOpXMM_to_XMM[op](regd, t0reg); + } + else { + SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Ft_]); + if (CHECK_FPU_EXTRA_OVERFLOW || (op >= 2)) { fpuFloat2(regd); fpuFloat2(EEREC_S); } + recComOpXMM_to_XMM[op](regd, EEREC_S); + } + break; + case PROCESS_EE_T: + if (regd == EEREC_T) { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); + if (CHECK_FPU_EXTRA_OVERFLOW || (op >= 2)) { fpuFloat2(regd); fpuFloat2(t0reg); } + recComOpXMM_to_XMM[op](regd, t0reg); + } + else { + SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); + if (CHECK_FPU_EXTRA_OVERFLOW || (op >= 2)) { fpuFloat2(regd); fpuFloat2(EEREC_T); } + recComOpXMM_to_XMM[op](regd, EEREC_T); + } + break; + case (PROCESS_EE_S|PROCESS_EE_T): + if (regd == EEREC_T) { + if (CHECK_FPU_EXTRA_OVERFLOW || (op >= 2)) { fpuFloat2(regd); fpuFloat2(EEREC_S); } + recComOpXMM_to_XMM[op](regd, EEREC_S); + } + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + if (CHECK_FPU_EXTRA_OVERFLOW || (op >= 2)) { fpuFloat2(regd); fpuFloat2(EEREC_T); } + recComOpXMM_to_XMM[op](regd, EEREC_T); + } + break; + default: + Console::Status("FPU: recCommutativeOp case 4"); + SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + if (CHECK_FPU_EXTRA_OVERFLOW || (op >= 2)) { fpuFloat2(regd); fpuFloat2(t0reg); } + recComOpXMM_to_XMM[op](regd, t0reg); + break; + } + + _freeXMMreg(t0reg); + return regd; +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ADD XMM +//------------------------------------------------------------------ +void recADD_S_xmm(int info) +{ + //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags + ClampValues2(recCommutativeOp(info, EEREC_D, 0)); + //REC_FPUOP(ADD_S); +} + +FPURECOMPILE_CONSTCODE(ADD_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); + +void recADDA_S_xmm(int info) +{ + //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags + ClampValues(recCommutativeOp(info, EEREC_ACC, 0)); +} + +FPURECOMPILE_CONSTCODE(ADDA_S, XMMINFO_WRITEACC|XMMINFO_READS|XMMINFO_READT); +//------------------------------------------------------------------ + +//------------------------------------------------------------------ +// BC1x XMM +//------------------------------------------------------------------ + +static void _setupBranchTest() +{ + _eeFlushAllUnused(); + + // COP1 branch conditionals are based on the following equation: + // (fpuRegs.fprc[31] & 0x00800000) + // BC2F checks if the statement is false, BC2T checks if the statement is true. + + MOV32MtoR(EAX, (uptr)&fpuRegs.fprc[31]); + TEST32ItoR(EAX, FPUflagC); +} + +void recBC1F( void ) +{ + _setupBranchTest(); + recDoBranchImm(JNZ32(0)); +} + +void recBC1T( void ) +{ + _setupBranchTest(); + recDoBranchImm(JZ32(0)); +} + +void recBC1FL( void ) +{ + _setupBranchTest(); + recDoBranchImm_Likely(JNZ32(0)); +} + +void recBC1TL( void ) +{ + _setupBranchTest(); + recDoBranchImm_Likely(JZ32(0)); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// C.x.S XMM +//------------------------------------------------------------------ +void recC_EQ_xmm(int info) +{ + int tempReg; + int t0reg; + + //SysPrintf("recC_EQ_xmm()\n"); + + switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { + case PROCESS_EE_S: + SSE_MINSS_M32_to_XMM(EEREC_S, (uptr)&g_maxvals[0]); + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + if (t0reg >= 0) { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + SSE_MINSS_M32_to_XMM(t0reg, (uptr)&g_maxvals[0]); + SSE_UCOMISS_XMM_to_XMM(EEREC_S, t0reg); + _freeXMMreg(t0reg); + } + else SSE_UCOMISS_M32_to_XMM(EEREC_S, (uptr)&fpuRegs.fpr[_Ft_]); + break; + case PROCESS_EE_T: + SSE_MINSS_M32_to_XMM(EEREC_T, (uptr)&g_maxvals[0]); + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + if (t0reg >= 0) { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); + SSE_MINSS_M32_to_XMM(t0reg, (uptr)&g_maxvals[0]); + SSE_UCOMISS_XMM_to_XMM(t0reg, EEREC_T); + _freeXMMreg(t0reg); + } + else SSE_UCOMISS_M32_to_XMM(EEREC_T, (uptr)&fpuRegs.fpr[_Fs_]); + break; + case (PROCESS_EE_S|PROCESS_EE_T): + SSE_MINSS_M32_to_XMM(EEREC_S, (uptr)&g_maxvals[0]); + SSE_MINSS_M32_to_XMM(EEREC_T, (uptr)&g_maxvals[0]); + SSE_UCOMISS_XMM_to_XMM(EEREC_S, EEREC_T); + break; + default: + Console::Status("recC_EQ_xmm: Default"); + tempReg = _allocX86reg(-1, X86TYPE_TEMP, 0, 0); + if (tempReg < 0) {Console::Error("FPU: DIV Allocation Error!"); tempReg = EAX;} + MOV32MtoR(tempReg, (uptr)&fpuRegs.fpr[_Fs_]); + CMP32MtoR(tempReg, (uptr)&fpuRegs.fpr[_Ft_]); + + j8Ptr[0] = JZ8(0); + AND32ItoM( (uptr)&fpuRegs.fprc[31], ~FPUflagC ); + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagC); + x86SetJ8(j8Ptr[1]); + + if (tempReg >= 0) _freeX86reg(tempReg); + return; + } + + j8Ptr[0] = JZ8(0); + AND32ItoM( (uptr)&fpuRegs.fprc[31], ~FPUflagC ); + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagC); + x86SetJ8(j8Ptr[1]); +} + +FPURECOMPILE_CONSTCODE(C_EQ, XMMINFO_READS|XMMINFO_READT); +//REC_FPUFUNC(C_EQ); + +void recC_F() +{ + AND32ItoM( (uptr)&fpuRegs.fprc[31], ~FPUflagC ); +} +//REC_FPUFUNC(C_F); + +void recC_LE_xmm(int info ) +{ + int tempReg; //tempX86reg + int t0reg; //tempXMMreg + + //SysPrintf("recC_LE_xmm()\n"); + + switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { + case PROCESS_EE_S: + SSE_MINSS_M32_to_XMM(EEREC_S, (uptr)&g_maxvals[0]); + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + if (t0reg >= 0) { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + SSE_MINSS_M32_to_XMM(t0reg, (uptr)&g_maxvals[0]); + SSE_UCOMISS_XMM_to_XMM(EEREC_S, t0reg); + _freeXMMreg(t0reg); + } + else SSE_UCOMISS_M32_to_XMM(EEREC_S, (uptr)&fpuRegs.fpr[_Ft_]); + break; + case PROCESS_EE_T: + SSE_MINSS_M32_to_XMM(EEREC_T, (uptr)&g_maxvals[0]); + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + if (t0reg >= 0) { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); + SSE_MINSS_M32_to_XMM(t0reg, (uptr)&g_maxvals[0]); + SSE_UCOMISS_XMM_to_XMM(t0reg, EEREC_T); + _freeXMMreg(t0reg); + } + else { + SSE_UCOMISS_M32_to_XMM(EEREC_T, (uptr)&fpuRegs.fpr[_Fs_]); + + j8Ptr[0] = JAE8(0); + AND32ItoM( (uptr)&fpuRegs.fprc[31], ~FPUflagC ); + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagC); + x86SetJ8(j8Ptr[1]); + return; + } + break; + case (PROCESS_EE_S|PROCESS_EE_T): + SSE_MINSS_M32_to_XMM(EEREC_S, (uptr)&g_maxvals[0]); + SSE_MINSS_M32_to_XMM(EEREC_T, (uptr)&g_maxvals[0]); + SSE_UCOMISS_XMM_to_XMM(EEREC_S, EEREC_T); + break; + default: // Untested and incorrect, but this case is never reached AFAIK (cottonvibes) + Console::Status("recC_LE_xmm: Default"); + tempReg = _allocX86reg(-1, X86TYPE_TEMP, 0, 0); + if (tempReg < 0) {Console::Error("FPU: DIV Allocation Error!"); tempReg = EAX;} + MOV32MtoR(tempReg, (uptr)&fpuRegs.fpr[_Fs_]); + CMP32MtoR(tempReg, (uptr)&fpuRegs.fpr[_Ft_]); + + j8Ptr[0] = JLE8(0); + AND32ItoM( (uptr)&fpuRegs.fprc[31], ~FPUflagC ); + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagC); + x86SetJ8(j8Ptr[1]); + + if (tempReg >= 0) _freeX86reg(tempReg); + return; + } + + j8Ptr[0] = JBE8(0); + AND32ItoM( (uptr)&fpuRegs.fprc[31], ~FPUflagC ); + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagC); + x86SetJ8(j8Ptr[1]); +} + +FPURECOMPILE_CONSTCODE(C_LE, XMMINFO_READS|XMMINFO_READT); +//REC_FPUFUNC(C_LE); + +void recC_LT_xmm(int info) +{ + int tempReg; + int t0reg; + + //SysPrintf("recC_LT_xmm()\n"); + + switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { + case PROCESS_EE_S: + SSE_MINSS_M32_to_XMM(EEREC_S, (uptr)&g_maxvals[0]); + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + if (t0reg >= 0) { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + SSE_MINSS_M32_to_XMM(t0reg, (uptr)&g_maxvals[0]); + SSE_UCOMISS_XMM_to_XMM(EEREC_S, t0reg); + _freeXMMreg(t0reg); + } + else SSE_UCOMISS_M32_to_XMM(EEREC_S, (uptr)&fpuRegs.fpr[_Ft_]); + break; + case PROCESS_EE_T: + SSE_MINSS_M32_to_XMM(EEREC_T, (uptr)&g_maxvals[0]); + t0reg = _allocTempXMMreg(XMMT_FPS, -1); + if (t0reg >= 0) { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); + SSE_MINSS_M32_to_XMM(t0reg, (uptr)&g_maxvals[0]); + SSE_UCOMISS_XMM_to_XMM(t0reg, EEREC_T); + _freeXMMreg(t0reg); + } + else { + SSE_UCOMISS_M32_to_XMM(EEREC_T, (uptr)&fpuRegs.fpr[_Fs_]); + + j8Ptr[0] = JA8(0); + AND32ItoM( (uptr)&fpuRegs.fprc[31], ~FPUflagC ); + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagC); + x86SetJ8(j8Ptr[1]); + return; + } + break; + case (PROCESS_EE_S|PROCESS_EE_T): + // Makes NaNs and +Infinity be +maximum; -Infinity stays + // the same, but this is okay for a Compare operation. + // Note: This fixes a crash in Rule of Rose. + SSE_MINSS_M32_to_XMM(EEREC_S, (uptr)&g_maxvals[0]); + SSE_MINSS_M32_to_XMM(EEREC_T, (uptr)&g_maxvals[0]); + SSE_UCOMISS_XMM_to_XMM(EEREC_S, EEREC_T); + break; + default: + Console::Status("recC_LT_xmm: Default"); + tempReg = _allocX86reg(-1, X86TYPE_TEMP, 0, 0); + if (tempReg < 0) {Console::Error("FPU: DIV Allocation Error!"); tempReg = EAX;} + MOV32MtoR(tempReg, (uptr)&fpuRegs.fpr[_Fs_]); + CMP32MtoR(tempReg, (uptr)&fpuRegs.fpr[_Ft_]); + + j8Ptr[0] = JL8(0); + AND32ItoM( (uptr)&fpuRegs.fprc[31], ~FPUflagC ); + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagC); + x86SetJ8(j8Ptr[1]); + + if (tempReg >= 0) _freeX86reg(tempReg); + return; + } + + j8Ptr[0] = JB8(0); + AND32ItoM( (uptr)&fpuRegs.fprc[31], ~FPUflagC ); + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagC); + x86SetJ8(j8Ptr[1]); +} + +FPURECOMPILE_CONSTCODE(C_LT, XMMINFO_READS|XMMINFO_READT); +//REC_FPUFUNC(C_LT); +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// CVT.x XMM +//------------------------------------------------------------------ +void recCVT_S_xmm(int info) +{ + if( !(info&PROCESS_EE_S) || (EEREC_D != EEREC_S && !(info&PROCESS_EE_MODEWRITES)) ) { + SSE_CVTSI2SS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); + } + else { + SSE2_CVTDQ2PS_XMM_to_XMM(EEREC_D, EEREC_S); + } +} + +FPURECOMPILE_CONSTCODE(CVT_S, XMMINFO_WRITED|XMMINFO_READS); + +void recCVT_W() +{ + int regs = _checkXMMreg(XMMTYPE_FPREG, _Fs_, MODE_READ); + + if( regs >= 0 ) + { + if (CHECK_FPU_EXTRA_OVERFLOW) fpuFloat2(regs); + SSE_CVTTSS2SI_XMM_to_R32(EAX, regs); + SSE_MOVMSKPS_XMM_to_R32(EDX, regs); //extract the signs + AND32ItoR(EDX,1); //keep only LSB + } + else + { + SSE_CVTTSS2SI_M32_to_R32(EAX, (uptr)&fpuRegs.fpr[ _Fs_ ]); + MOV32MtoR(EDX, (uptr)&fpuRegs.fpr[ _Fs_ ]); + SHR32ItoR(EDX, 31); //mov sign to lsb + } + + //kill register allocation for dst because we write directly to fpuRegs.fpr[_Fd_] + _deleteFPtoXMMreg(_Fd_, 2); + + ADD32ItoR(EDX, 0x7FFFFFFF); //0x7FFFFFFF if positive, 0x8000 0000 if negative + + CMP32ItoR(EAX, 0x80000000); //If the result is indefinitive + CMOVE32RtoR(EAX, EDX); //Saturate it + + //Write the result + MOV32RtoM((uptr)&fpuRegs.fpr[_Fd_], EAX); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// DIV XMM +//------------------------------------------------------------------ +void recDIVhelper1(int regd, int regt) // Sets flags +{ + u8 *pjmp1, *pjmp2; + u32 *ajmp32, *bjmp32; + int t1reg = _allocTempXMMreg(XMMT_FPS, -1); + int tempReg = _allocX86reg(-1, X86TYPE_TEMP, 0, 0); + //if (t1reg == -1) {Console::Error("FPU: DIV Allocation Error!");} + if (tempReg == -1) {Console::Error("FPU: DIV Allocation Error!"); tempReg = EAX;} + + AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagI|FPUflagD)); // Clear I and D flags + + /*--- Check for divide by zero ---*/ + SSE_XORPS_XMM_to_XMM(t1reg, t1reg); + SSE_CMPEQSS_XMM_to_XMM(t1reg, regt); + SSE_MOVMSKPS_XMM_to_R32(tempReg, t1reg); + AND32ItoR(tempReg, 1); //Check sign (if regt == zero, sign will be set) + ajmp32 = JZ32(0); //Skip if not set + + /*--- Check for 0/0 ---*/ + SSE_XORPS_XMM_to_XMM(t1reg, t1reg); + SSE_CMPEQSS_XMM_to_XMM(t1reg, regd); + SSE_MOVMSKPS_XMM_to_R32(tempReg, t1reg); + AND32ItoR(tempReg, 1); //Check sign (if regd == zero, sign will be set) + pjmp1 = JZ8(0); //Skip if not set + OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagI|FPUflagSI); // Set I and SI flags ( 0/0 ) + pjmp2 = JMP8(0); + x86SetJ8(pjmp1); //x/0 but not 0/0 + OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagD|FPUflagSD); // Set D and SD flags ( x/0 ) + x86SetJ8(pjmp2); + + /*--- Make regd +/- Maximum ---*/ + SSE_XORPS_XMM_to_XMM(regd, regt); // Make regd Positive or Negative + SSE_ANDPS_M128_to_XMM(regd, (uptr)&s_neg[0]); // Get the sign bit + SSE_ORPS_M128_to_XMM(regd, (uptr)&g_maxvals[0]); // regd = +/- Maximum + //SSE_MOVSS_M32_to_XMM(regd, (uptr)&g_maxvals[0]); + bjmp32 = JMP32(0); + + x86SetJ32(ajmp32); + + /*--- Normal Divide ---*/ + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(regt); } + SSE_DIVSS_XMM_to_XMM(regd, regt); + + ClampValues(regd); + x86SetJ32(bjmp32); + + _freeXMMreg(t1reg); + _freeX86reg(tempReg); +} + +void recDIVhelper2(int regd, int regt) // Doesn't sets flags +{ + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(regt); } + SSE_DIVSS_XMM_to_XMM(regd, regt); + ClampValues(regd); +} + +void recDIV_S_xmm(int info) +{ + static u32 PCSX2_ALIGNED16(roundmode_temp[4]) = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; + int roundmodeFlag = 0; + int t0reg = _allocTempXMMreg(XMMT_FPS, -1); + //if (t0reg == -1) {Console::Error("FPU: DIV Allocation Error!");} + //SysPrintf("DIV\n"); + + if ((g_sseMXCSR & 0x00006000) != 0x00000000) { // Set roundmode to nearest if it isn't already + //SysPrintf("div to nearest\n"); + roundmode_temp[0] = (g_sseMXCSR & 0xFFFF9FFF); // Set new roundmode + roundmode_temp[1] = g_sseMXCSR; // Backup old Roundmode + SSE_LDMXCSR ((uptr)&roundmode_temp[0]); // Recompile Roundmode Change + roundmodeFlag = 1; + } + + switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { + case PROCESS_EE_S: + //SysPrintf("FPU: DIV case 1\n"); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + if (CHECK_FPU_EXTRA_FLAGS) recDIVhelper1(EEREC_D, t0reg); + else recDIVhelper2(EEREC_D, t0reg); + break; + case PROCESS_EE_T: + //SysPrintf("FPU: DIV case 2\n"); + if (EEREC_D == EEREC_T) { + SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_T); + SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); + if (CHECK_FPU_EXTRA_FLAGS) recDIVhelper1(EEREC_D, t0reg); + else recDIVhelper2(EEREC_D, t0reg); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); + if (CHECK_FPU_EXTRA_FLAGS) recDIVhelper1(EEREC_D, EEREC_T); + else recDIVhelper2(EEREC_D, EEREC_T); + } + break; + case (PROCESS_EE_S|PROCESS_EE_T): + //SysPrintf("FPU: DIV case 3\n"); + if (EEREC_D == EEREC_T) { + SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_T); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + if (CHECK_FPU_EXTRA_FLAGS) recDIVhelper1(EEREC_D, t0reg); + else recDIVhelper2(EEREC_D, t0reg); + } + else { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + if (CHECK_FPU_EXTRA_FLAGS) recDIVhelper1(EEREC_D, EEREC_T); + else recDIVhelper2(EEREC_D, EEREC_T); + } + break; + default: + //SysPrintf("FPU: DIV case 4\n"); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); + if (CHECK_FPU_EXTRA_FLAGS) recDIVhelper1(EEREC_D, t0reg); + else recDIVhelper2(EEREC_D, t0reg); + break; + } + if (roundmodeFlag == 1) { // Set roundmode back if it was changed + SSE_LDMXCSR ((uptr)&roundmode_temp[1]); + } + _freeXMMreg(t0reg); +} + +FPURECOMPILE_CONSTCODE(DIV_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// MADD XMM +//------------------------------------------------------------------ +void recMADDtemp(int info, int regd) +{ + int t1reg; + int t0reg = _allocTempXMMreg(XMMT_FPS, -1); + + switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { + case PROCESS_EE_S: + if(regd == EEREC_S) { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(t0reg); } + SSE_MULSS_XMM_to_XMM(regd, t0reg); + if (info & PROCESS_EE_ACC) { + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(EEREC_ACC); fpuFloat(regd); } + FPU_ADD(regd, EEREC_ACC); + } + else { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(EEREC_ACC); fpuFloat(t0reg); } + FPU_ADD(regd, t0reg); + } + } + else if (regd == EEREC_ACC){ + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(EEREC_S); fpuFloat2(t0reg); } + SSE_MULSS_XMM_to_XMM(t0reg, EEREC_S); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_ADD(regd, t0reg); + } + else { + SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Ft_]); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_S); } + SSE_MULSS_XMM_to_XMM(regd, EEREC_S); + if (info & PROCESS_EE_ACC) { + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(EEREC_ACC); fpuFloat(regd); } + FPU_ADD(regd, EEREC_ACC); + } + else { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(EEREC_ACC); fpuFloat(t0reg); } + FPU_ADD(regd, t0reg); + } + } + break; + case PROCESS_EE_T: + if(regd == EEREC_T) { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(t0reg); } + SSE_MULSS_XMM_to_XMM(regd, t0reg); + if (info & PROCESS_EE_ACC) { + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(EEREC_ACC); fpuFloat(regd); } + FPU_ADD(regd, EEREC_ACC); + } + else { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(EEREC_ACC); fpuFloat(t0reg); } + FPU_ADD(regd, t0reg); + } + } + else if (regd == EEREC_ACC){ + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(EEREC_T); fpuFloat2(t0reg); } + SSE_MULSS_XMM_to_XMM(t0reg, EEREC_T); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_ADD(regd, t0reg); + } + else { + SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_T); } + SSE_MULSS_XMM_to_XMM(regd, EEREC_T); + if (info & PROCESS_EE_ACC) { + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(EEREC_ACC); fpuFloat(regd); } + FPU_ADD(regd, EEREC_ACC); + } + else { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(EEREC_ACC); fpuFloat(t0reg); } + FPU_ADD(regd, t0reg); + } + } + break; + case (PROCESS_EE_S|PROCESS_EE_T): + if(regd == EEREC_S) { + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_T); } + SSE_MULSS_XMM_to_XMM(regd, EEREC_T); + if (info & PROCESS_EE_ACC) { + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(EEREC_ACC); } + FPU_ADD(regd, EEREC_ACC); + } + else { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_ADD(regd, t0reg); + } + } + else if(regd == EEREC_T) { + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_S); } + SSE_MULSS_XMM_to_XMM(regd, EEREC_S); + if (info & PROCESS_EE_ACC) { + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(EEREC_ACC); } + FPU_ADD(regd, EEREC_ACC); + } + else { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_ADD(regd, t0reg); + } + } + else if(regd == EEREC_ACC) { + SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_S); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(t0reg); fpuFloat2(EEREC_T); } + SSE_MULSS_XMM_to_XMM(t0reg, EEREC_T); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_ADD(regd, t0reg); + } + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_T); } + SSE_MULSS_XMM_to_XMM(regd, EEREC_T); + if (info & PROCESS_EE_ACC) { + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(EEREC_ACC); } + FPU_ADD(regd, EEREC_ACC); + } + else { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_ADD(regd, t0reg); + } + } + break; + default: + if(regd == EEREC_ACC){ + t1reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); + SSE_MOVSS_M32_to_XMM(t1reg, (uptr)&fpuRegs.fpr[_Ft_]); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(t0reg); fpuFloat2(t1reg); } + SSE_MULSS_XMM_to_XMM(t0reg, t1reg); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_ADD(regd, t0reg); + _freeXMMreg(t1reg); + } + else + { + SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(t0reg); } + SSE_MULSS_XMM_to_XMM(regd, t0reg); + if (info & PROCESS_EE_ACC) { + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(EEREC_ACC); } + FPU_ADD(regd, EEREC_ACC); + } + else { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_ADD(regd, t0reg); + } + } + break; + } + + ClampValues(regd); + _freeXMMreg(t0reg); +} + +void recMADD_S_xmm(int info) +{ + //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags + recMADDtemp(info, EEREC_D); +} + +FPURECOMPILE_CONSTCODE(MADD_S, XMMINFO_WRITED|XMMINFO_READACC|XMMINFO_READS|XMMINFO_READT); + +void recMADDA_S_xmm(int info) +{ + //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags + recMADDtemp(info, EEREC_ACC); +} + +FPURECOMPILE_CONSTCODE(MADDA_S, XMMINFO_WRITEACC|XMMINFO_READACC|XMMINFO_READS|XMMINFO_READT); +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// MAX / MIN XMM +//------------------------------------------------------------------ +void recMAX_S_xmm(int info) +{ + //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags + recCommutativeOp(info, EEREC_D, 2); +} + +FPURECOMPILE_CONSTCODE(MAX_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); + +void recMIN_S_xmm(int info) +{ + //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags + recCommutativeOp(info, EEREC_D, 3); +} + +FPURECOMPILE_CONSTCODE(MIN_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// MOV XMM +//------------------------------------------------------------------ +void recMOV_S_xmm(int info) +{ + if( info & PROCESS_EE_S ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + else SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); +} + +FPURECOMPILE_CONSTCODE(MOV_S, XMMINFO_WRITED|XMMINFO_READS); +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// MSUB XMM +//------------------------------------------------------------------ +void recMSUBtemp(int info, int regd) +{ +int t1reg; + int t0reg = _allocTempXMMreg(XMMT_FPS, -1); + + switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { + case PROCESS_EE_S: + if(regd == EEREC_S) { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(t0reg); } + SSE_MULSS_XMM_to_XMM(regd, t0reg); + if (info & PROCESS_EE_ACC) { SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_ACC); } + else { SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); } + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_SUB(t0reg, regd); + SSE_MOVSS_XMM_to_XMM(regd, t0reg); + } + else if (regd == EEREC_ACC){ + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(EEREC_S); fpuFloat2(t0reg); } + SSE_MULSS_XMM_to_XMM(t0reg, EEREC_S); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_SUB(regd, t0reg); + } + else { + SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Ft_]); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_S); } + SSE_MULSS_XMM_to_XMM(regd, EEREC_S); + if (info & PROCESS_EE_ACC) { SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_ACC); } + else { SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); } + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_SUB(t0reg, regd); + SSE_MOVSS_XMM_to_XMM(regd, t0reg); + } + break; + case PROCESS_EE_T: + if(regd == EEREC_T) { + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(t0reg); } + SSE_MULSS_XMM_to_XMM(regd, t0reg); + if (info & PROCESS_EE_ACC) { SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_ACC); } + else { SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); } + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_SUB(t0reg, regd); + SSE_MOVSS_XMM_to_XMM(regd, t0reg); + } + else if (regd == EEREC_ACC){ + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(EEREC_T); fpuFloat2(t0reg); } + SSE_MULSS_XMM_to_XMM(t0reg, EEREC_T); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_SUB(regd, t0reg); + } + else { + SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_T); } + SSE_MULSS_XMM_to_XMM(regd, EEREC_T); + if (info & PROCESS_EE_ACC) { SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_ACC); } + else { SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); } + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_SUB(t0reg, regd); + SSE_MOVSS_XMM_to_XMM(regd, t0reg); + } + break; + case (PROCESS_EE_S|PROCESS_EE_T): + if(regd == EEREC_S) { + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_T); } + SSE_MULSS_XMM_to_XMM(regd, EEREC_T); + if (info & PROCESS_EE_ACC) { SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_ACC); } + else { SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); } + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_SUB(t0reg, regd); + SSE_MOVSS_XMM_to_XMM(regd, t0reg); + } + else if(regd == EEREC_T) { + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_S); } + SSE_MULSS_XMM_to_XMM(regd, EEREC_S); + if (info & PROCESS_EE_ACC) { SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_ACC); } + else { SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); } + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_SUB(t0reg, regd); + SSE_MOVSS_XMM_to_XMM(regd, t0reg); + } + else if(regd == EEREC_ACC) { + SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_S); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(t0reg); fpuFloat2(EEREC_T); } + SSE_MULSS_XMM_to_XMM(t0reg, EEREC_T); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_SUB(regd, t0reg); + } + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(EEREC_T); } + SSE_MULSS_XMM_to_XMM(regd, EEREC_T); + if (info & PROCESS_EE_ACC) { SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_ACC); } + else { SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); } + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_SUB(t0reg, regd); + SSE_MOVSS_XMM_to_XMM(regd, t0reg); + } + break; + default: + if(regd == EEREC_ACC){ + t1reg = _allocTempXMMreg(XMMT_FPS, -1); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Fs_]); + SSE_MOVSS_M32_to_XMM(t1reg, (uptr)&fpuRegs.fpr[_Ft_]); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(t0reg); fpuFloat2(t1reg); } + SSE_MULSS_XMM_to_XMM(t0reg, t1reg); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_SUB(regd, t0reg); + _freeXMMreg(t1reg); + } + else + { + SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat2(regd); fpuFloat2(t0reg); } + SSE_MULSS_XMM_to_XMM(regd, t0reg); + if (info & PROCESS_EE_ACC) { SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_ACC); } + else { SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.ACC); } + if (CHECK_FPU_EXTRA_OVERFLOW) { fpuFloat(regd); fpuFloat(t0reg); } + FPU_SUB(t0reg, regd); + SSE_MOVSS_XMM_to_XMM(regd, t0reg); + } + break; + } + + ClampValues(regd); + _freeXMMreg(t0reg); + +} + +void recMSUB_S_xmm(int info) +{ + //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags + recMSUBtemp(info, EEREC_D); +} + +FPURECOMPILE_CONSTCODE(MSUB_S, XMMINFO_WRITED|XMMINFO_READACC|XMMINFO_READS|XMMINFO_READT); + +void recMSUBA_S_xmm(int info) +{ + //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags + recMSUBtemp(info, EEREC_ACC); +} + +FPURECOMPILE_CONSTCODE(MSUBA_S, XMMINFO_WRITEACC|XMMINFO_READACC|XMMINFO_READS|XMMINFO_READT); +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// MUL XMM +//------------------------------------------------------------------ +void recMUL_S_xmm(int info) +{ + //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags + ClampValues(recCommutativeOp(info, EEREC_D, 1)); +} + +FPURECOMPILE_CONSTCODE(MUL_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); + +void recMULA_S_xmm(int info) +{ + //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags + ClampValues(recCommutativeOp(info, EEREC_ACC, 1)); +} + +FPURECOMPILE_CONSTCODE(MULA_S, XMMINFO_WRITEACC|XMMINFO_READS|XMMINFO_READT); +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// NEG XMM +//------------------------------------------------------------------ +void recNEG_S_xmm(int info) { + if( info & PROCESS_EE_S ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + else SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); + + //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags + SSE_XORPS_M128_to_XMM(EEREC_D, (uptr)&s_neg[0]); + ClampValues(EEREC_D); +} + +FPURECOMPILE_CONSTCODE(NEG_S, XMMINFO_WRITED|XMMINFO_READS); +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// SUB XMM +//------------------------------------------------------------------ +void recSUBhelper(int regd, int regt) +{ + if (CHECK_FPU_EXTRA_OVERFLOW /*&& !CHECK_FPUCLAMPHACK*/) { fpuFloat2(regd); fpuFloat2(regt); } + FPU_SUB(regd, regt); +} + +void recSUBop(int info, int regd) +{ + int t0reg = _allocTempXMMreg(XMMT_FPS, -1); + //if (t0reg == -1) {SysPrintf("FPU: SUB Allocation Error!\n");} + + //AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagO|FPUflagU)); // Clear O and U flags + + switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { + case PROCESS_EE_S: + //SysPrintf("FPU: SUB case 1\n"); + if (regd != EEREC_S) SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + recSUBhelper(regd, t0reg); + break; + case PROCESS_EE_T: + //SysPrintf("FPU: SUB case 2\n"); + if (regd == EEREC_T) { + SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_T); + SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); + recSUBhelper(regd, t0reg); + } + else { + SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); + recSUBhelper(regd, EEREC_T); + } + break; + case (PROCESS_EE_S|PROCESS_EE_T): + //SysPrintf("FPU: SUB case 3\n"); + if (regd == EEREC_T) { + SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_T); + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + recSUBhelper(regd, t0reg); + } + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + recSUBhelper(regd, EEREC_T); + } + break; + default: + Console::Notice("FPU: SUB case 4"); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + SSE_MOVSS_M32_to_XMM(regd, (uptr)&fpuRegs.fpr[_Fs_]); + recSUBhelper(regd, t0reg); + break; + } + + ClampValues2(regd); + _freeXMMreg(t0reg); +} + +void recSUB_S_xmm(int info) +{ + recSUBop(info, EEREC_D); +} + +FPURECOMPILE_CONSTCODE(SUB_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); + + +void recSUBA_S_xmm(int info) +{ + recSUBop(info, EEREC_ACC); +} + +FPURECOMPILE_CONSTCODE(SUBA_S, XMMINFO_WRITEACC|XMMINFO_READS|XMMINFO_READT); +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// SQRT XMM +//------------------------------------------------------------------ +void recSQRT_S_xmm(int info) +{ + u8* pjmp; + static u32 PCSX2_ALIGNED16(roundmode_temp[4]) = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; + int roundmodeFlag = 0; + //SysPrintf("FPU: SQRT\n"); + + if ((g_sseMXCSR & 0x00006000) != 0x00000000) { // Set roundmode to nearest if it isn't already + //SysPrintf("sqrt to nearest\n"); + roundmode_temp[0] = (g_sseMXCSR & 0xFFFF9FFF); // Set new roundmode + roundmode_temp[1] = g_sseMXCSR; // Backup old Roundmode + SSE_LDMXCSR ((uptr)&roundmode_temp[0]); // Recompile Roundmode Change + roundmodeFlag = 1; + } + + if( info & PROCESS_EE_T ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_T); + else SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Ft_]); + + if (CHECK_FPU_EXTRA_FLAGS) { + int tempReg = _allocX86reg(-1, X86TYPE_TEMP, 0, 0); + if (tempReg == -1) {Console::Error("FPU: SQRT Allocation Error!"); tempReg = EAX;} + + AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagI|FPUflagD)); // Clear I and D flags + + /*--- Check for negative SQRT ---*/ + SSE_MOVMSKPS_XMM_to_R32(tempReg, EEREC_D); + AND32ItoR(tempReg, 1); //Check sign + pjmp = JZ8(0); //Skip if none are + OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagI|FPUflagSI); // Set I and SI flags + SSE_ANDPS_M128_to_XMM(EEREC_D, (uptr)&s_pos[0]); // Make EEREC_D Positive + x86SetJ8(pjmp); + + _freeX86reg(tempReg); + } + else SSE_ANDPS_M128_to_XMM(EEREC_D, (uptr)&s_pos[0]); // Make EEREC_D Positive + + if (CHECK_FPU_OVERFLOW) SSE_MINSS_M32_to_XMM(EEREC_D, (uptr)&g_maxvals[0]);// Only need to do positive clamp, since EEREC_D is positive + SSE_SQRTSS_XMM_to_XMM(EEREC_D, EEREC_D); + if (CHECK_FPU_EXTRA_OVERFLOW) ClampValues(EEREC_D); // Shouldn't need to clamp again since SQRT of a number will always be smaller than the original number, doing it just incase :/ + + if (roundmodeFlag == 1) { // Set roundmode back if it was changed + SSE_LDMXCSR ((uptr)&roundmode_temp[1]); + } +} + +FPURECOMPILE_CONSTCODE(SQRT_S, XMMINFO_WRITED|XMMINFO_READT); +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// RSQRT XMM +//------------------------------------------------------------------ +void recRSQRThelper1(int regd, int t0reg) // Preforms the RSQRT function when regd <- Fs and t0reg <- Ft (Sets correct flags) +{ + u8 *pjmp1, *pjmp2; + u32 *pjmp32; + int t1reg = _allocTempXMMreg(XMMT_FPS, -1); + int tempReg = _allocX86reg(-1, X86TYPE_TEMP, 0, 0); + //if (t1reg == -1) {Console::Error("FPU: RSQRT Allocation Error!");} + if (tempReg == -1) {Console::Error("FPU: RSQRT Allocation Error!"); tempReg = EAX;} + + AND32ItoM((uptr)&fpuRegs.fprc[31], ~(FPUflagI|FPUflagD)); // Clear I and D flags + + /*--- Check for zero ---*/ + SSE_XORPS_XMM_to_XMM(t1reg, t1reg); + SSE_CMPEQSS_XMM_to_XMM(t1reg, t0reg); + SSE_MOVMSKPS_XMM_to_R32(tempReg, t1reg); + AND32ItoR(tempReg, 1); //Check sign (if t0reg == zero, sign will be set) + pjmp1 = JZ8(0); //Skip if not set + OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagD|FPUflagSD); // Set D and SD flags + SSE_XORPS_XMM_to_XMM(regd, t0reg); // Make regd Positive or Negative + SSE_ANDPS_M128_to_XMM(regd, (uptr)&s_neg[0]); // Get the sign bit + SSE_ORPS_M128_to_XMM(regd, (uptr)&g_maxvals[0]); // regd = +/- Maximum + pjmp32 = JMP32(0); + x86SetJ8(pjmp1); + + /*--- Check for negative SQRT ---*/ + SSE_MOVMSKPS_XMM_to_R32(tempReg, t0reg); + AND32ItoR(tempReg, 1); //Check sign + pjmp2 = JZ8(0); //Skip if not set + OR32ItoM((uptr)&fpuRegs.fprc[31], FPUflagI|FPUflagSI); // Set I and SI flags + SSE_ANDPS_M128_to_XMM(t0reg, (uptr)&s_pos[0]); // Make t0reg Positive + x86SetJ8(pjmp2); + + if (CHECK_FPU_EXTRA_OVERFLOW) { + SSE_MINSS_M32_to_XMM(t0reg, (uptr)&g_maxvals[0]); // Only need to do positive clamp, since t0reg is positive + fpuFloat2(regd); + } + + SSE_SQRTSS_XMM_to_XMM(t0reg, t0reg); + SSE_DIVSS_XMM_to_XMM(regd, t0reg); + + ClampValues(regd); + x86SetJ32(pjmp32); + + _freeXMMreg(t1reg); + _freeX86reg(tempReg); +} + +void recRSQRThelper2(int regd, int t0reg) // Preforms the RSQRT function when regd <- Fs and t0reg <- Ft (Doesn't set flags) +{ + SSE_ANDPS_M128_to_XMM(t0reg, (uptr)&s_pos[0]); // Make t0reg Positive + if (CHECK_FPU_EXTRA_OVERFLOW) { + SSE_MINSS_M32_to_XMM(t0reg, (uptr)&g_maxvals[0]); // Only need to do positive clamp, since t0reg is positive + fpuFloat2(regd); + } + SSE_SQRTSS_XMM_to_XMM(t0reg, t0reg); + SSE_DIVSS_XMM_to_XMM(regd, t0reg); + ClampValues(regd); +} + +void recRSQRT_S_xmm(int info) +{ + int t0reg = _allocTempXMMreg(XMMT_FPS, -1); + //if (t0reg == -1) {Console::Error("FPU: RSQRT Allocation Error!");} + //SysPrintf("FPU: RSQRT\n"); + + switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { + case PROCESS_EE_S: + //SysPrintf("FPU: RSQRT case 1\n"); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + if (CHECK_FPU_EXTRA_FLAGS) recRSQRThelper1(EEREC_D, t0reg); + else recRSQRThelper2(EEREC_D, t0reg); + break; + case PROCESS_EE_T: + //SysPrintf("FPU: RSQRT case 2\n"); + SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_T); + SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); + if (CHECK_FPU_EXTRA_FLAGS) recRSQRThelper1(EEREC_D, t0reg); + else recRSQRThelper2(EEREC_D, t0reg); + break; + case (PROCESS_EE_S|PROCESS_EE_T): + //SysPrintf("FPU: RSQRT case 3\n"); + SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_T); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + if (CHECK_FPU_EXTRA_FLAGS) recRSQRThelper1(EEREC_D, t0reg); + else recRSQRThelper2(EEREC_D, t0reg); + break; + default: + //SysPrintf("FPU: RSQRT case 4\n"); + SSE_MOVSS_M32_to_XMM(t0reg, (uptr)&fpuRegs.fpr[_Ft_]); + SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Fs_]); + if (CHECK_FPU_EXTRA_FLAGS) recRSQRThelper1(EEREC_D, t0reg); + else recRSQRThelper2(EEREC_D, t0reg); + break; + } + _freeXMMreg(t0reg); +} + +FPURECOMPILE_CONSTCODE(RSQRT_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); + +#endif // FPU_RECOMPILE + +} } } } diff --git a/pcsx2/x86/iFPU.h b/pcsx2/x86/iFPU.h index f0872aa92d..c3a114a813 100644 --- a/pcsx2/x86/iFPU.h +++ b/pcsx2/x86/iFPU.h @@ -1,71 +1,71 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __IFPU_H__ -#define __IFPU_H__ - -namespace R5900 { -namespace Dynarec { - - void SaveCW(); - void LoadCW(); - - namespace OpcodeImpl { - namespace COP1 - { - void recMFC1( void ); - void recCFC1( void ); - void recMTC1( void ); - void recCTC1( void ); - void recCOP1_BC1( void ); - void recCOP1_S( void ); - void recCOP1_W( void ); - void recC_EQ( void ); - void recC_F( void ); - void recC_LT( void ); - void recC_LE( void ); - void recADD_S( void ); - void recSUB_S( void ); - void recMUL_S( void ); - void recDIV_S( void ); - void recSQRT_S( void ); - void recABS_S( void ); - void recMOV_S( void ); - void recNEG_S( void ); - void recRSQRT_S( void ); - void recADDA_S( void ); - void recSUBA_S( void ); - void recMULA_S( void ); - void recMADD_S( void ); - void recMSUB_S( void ); - void recMADDA_S( void ); - void recMSUBA_S( void ); - void recCVT_S( void ); - void recCVT_W( void ); - void recMAX_S( void ); - void recMIN_S( void ); - void recBC1F( void ); - void recBC1T( void ); - void recBC1FL( void ); - void recBC1TL( void ); - } } -} } - -#endif - - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __IFPU_H__ +#define __IFPU_H__ + +namespace R5900 { +namespace Dynarec { + + void SaveCW(); + void LoadCW(); + + namespace OpcodeImpl { + namespace COP1 + { + void recMFC1( void ); + void recCFC1( void ); + void recMTC1( void ); + void recCTC1( void ); + void recCOP1_BC1( void ); + void recCOP1_S( void ); + void recCOP1_W( void ); + void recC_EQ( void ); + void recC_F( void ); + void recC_LT( void ); + void recC_LE( void ); + void recADD_S( void ); + void recSUB_S( void ); + void recMUL_S( void ); + void recDIV_S( void ); + void recSQRT_S( void ); + void recABS_S( void ); + void recMOV_S( void ); + void recNEG_S( void ); + void recRSQRT_S( void ); + void recADDA_S( void ); + void recSUBA_S( void ); + void recMULA_S( void ); + void recMADD_S( void ); + void recMSUB_S( void ); + void recMADDA_S( void ); + void recMSUBA_S( void ); + void recCVT_S( void ); + void recCVT_W( void ); + void recMAX_S( void ); + void recMIN_S( void ); + void recBC1F( void ); + void recBC1T( void ); + void recBC1FL( void ); + void recBC1TL( void ); + } } +} } + +#endif + + diff --git a/pcsx2/x86/iGS.cpp b/pcsx2/x86/iGS.cpp index 22e669225f..68639c1b27 100644 --- a/pcsx2/x86/iGS.cpp +++ b/pcsx2/x86/iGS.cpp @@ -1,299 +1,299 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "VU.h" - -#include "ix86/ix86.h" -#include "iR5900.h" - -#include "GS.h" -#include "DebugTools/Debug.h" - -extern u8 g_RealGSMem[0x2000]; -#define PS2GS_BASE(mem) (g_RealGSMem+(mem&0x13ff)) - -// __thiscall -- Calling Convention Notes. - -// ** MSVC passes the pointer to the object as ECX. Other parameters are passed normally -// (_cdecl style). Stack is cleaned by the callee. - -// ** GCC works just like a __cdecl, except the pointer to the object is pushed onto the -// stack last (passed as the first parameter). Caller cleans up the stack. - -// The GCC code below is untested. Hope it works. :| (air) - - -// Used to send 8, 16, and 32 bit values to the MTGS. -static void __fastcall _rec_mtgs_Send32orSmaller( GS_RINGTYPE ringtype, u32 mem, int mmreg ) -{ - iFlushCall(0); - - PUSH32I( 0 ); - _callPushArg( mmreg, 0 ); - PUSH32I( mem&0x13ff ); - PUSH32I( ringtype ); - -#ifdef _MSC_VER - MOV32ItoR( ECX, (uptr)mtgsThread ); - CALLFunc( mtgsThread->FnPtr_SimplePacket() ); -#else // GCC --> - PUSH32I( (uptr)mtgsThread ); - CALLFunc( mtgsThread->FnPtr_SimplePacket() ); - ADD32ItoR( ESP, 20 ); -#endif -} - -// Used to send 64 and 128 bit values to the MTGS (called twice for 128's, which -// is why it doesn't call iFlushCall) -static void __fastcall _rec_mtgs_Send64( uptr gsbase, u32 mem, int mmreg ) -{ - PUSH32M( gsbase+4 ); - PUSH32M( gsbase ); - PUSH32I( mem&0x13ff ); - PUSH32I( GS_RINGTYPE_MEMWRITE64 ); - -#ifdef _MSC_VER - MOV32ItoR( ECX, (uptr)mtgsThread ); - CALLFunc( mtgsThread->FnPtr_SimplePacket() ); -#else // GCC --> - PUSH32I( (uptr)mtgsThread ); - CALLFunc( mtgsThread->FnPtr_SimplePacket() ); - ADD32ItoR( ESP, 20 ); -#endif - -} - -void gsConstWrite8(u32 mem, int mmreg) -{ - switch (mem&~3) { - case 0x12001000: // GS_CSR - _eeMoveMMREGtoR(EAX, mmreg); - iFlushCall(0); - MOV32MtoR(ECX, (uptr)&CSRw); - AND32ItoR(EAX, 0xff<<(mem&3)*8); - AND32ItoR(ECX, ~(0xff<<(mem&3)*8)); - OR32ItoR(EAX, ECX); - _callFunctionArg1((uptr)gsCSRwrite, EAX|MEM_X86TAG, 0); - break; - default: - _eeWriteConstMem8( (uptr)PS2GS_BASE(mem), mmreg ); - - if( mtgsThread != NULL ) - _rec_mtgs_Send32orSmaller( GS_RINGTYPE_MEMWRITE8, mem, mmreg ); - - break; - } -} - -void gsConstWrite16(u32 mem, int mmreg) -{ - switch (mem&~3) { - - case 0x12000010: // GS_SMODE1 - case 0x12000020: // GS_SMODE2 - // SMODE1 and SMODE2 fall back on the gsWrite library. - iFlushCall(0); - _callFunctionArg2((uptr)gsWrite16, MEM_CONSTTAG, mmreg, mem, 0 ); - break; - - case 0x12001000: // GS_CSR - - assert( !(mem&2) ); - _eeMoveMMREGtoR(EAX, mmreg); - iFlushCall(0); - - MOV32MtoR(ECX, (uptr)&CSRw); - AND32ItoR(EAX, 0xffff<<(mem&2)*8); - AND32ItoR(ECX, ~(0xffff<<(mem&2)*8)); - OR32ItoR(EAX, ECX); - _callFunctionArg1((uptr)gsCSRwrite, EAX|MEM_X86TAG, 0); - break; - - default: - _eeWriteConstMem16( (uptr)PS2GS_BASE(mem), mmreg ); - - if( mtgsThread != NULL ) - _rec_mtgs_Send32orSmaller( GS_RINGTYPE_MEMWRITE16, mem, mmreg ); - - break; - } -} - -// (value&0x1f00)|0x6000 -void gsConstWriteIMR(int mmreg) -{ - const u32 mem = 0x12001010; - if( mmreg & MEM_XMMTAG ) { - SSE2_MOVD_XMM_to_M32((uptr)PS2GS_BASE(mem), mmreg&0xf); - AND32ItoM((uptr)PS2GS_BASE(mem), 0x1f00); - OR32ItoM((uptr)PS2GS_BASE(mem), 0x6000); - } - else if( mmreg & MEM_MMXTAG ) { - SetMMXstate(); - MOVDMMXtoM((uptr)PS2GS_BASE(mem), mmreg&0xf); - AND32ItoM((uptr)PS2GS_BASE(mem), 0x1f00); - OR32ItoM((uptr)PS2GS_BASE(mem), 0x6000); - } - else if( mmreg & MEM_EECONSTTAG ) { - MOV32ItoM( (uptr)PS2GS_BASE(mem), (g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]&0x1f00)|0x6000); - } - else { - AND32ItoR(mmreg, 0x1f00); - OR32ItoR(mmreg, 0x6000); - MOV32RtoM( (uptr)PS2GS_BASE(mem), mmreg ); - } - - // IMR doesn't need to be updated in MTGS mode -} - -void gsConstWrite32(u32 mem, int mmreg) { - - switch (mem) { - - case 0x12000010: // GS_SMODE1 - case 0x12000020: // GS_SMODE2 - // SMODE1 and SMODE2 fall back on the gsWrite library. - iFlushCall(0); - _callFunctionArg2((uptr)gsWrite32, MEM_CONSTTAG, mmreg, mem, 0 ); - break; - - case 0x12001000: // GS_CSR - iFlushCall(0); - _callFunctionArg1((uptr)gsCSRwrite, mmreg, 0); - break; - - case 0x12001010: // GS_IMR - gsConstWriteIMR(mmreg); - break; - default: - _eeWriteConstMem32( (uptr)PS2GS_BASE(mem), mmreg ); - - if( mtgsThread != NULL ) - _rec_mtgs_Send32orSmaller( GS_RINGTYPE_MEMWRITE32, mem, mmreg ); - - break; - } -} - -void gsConstWrite64(u32 mem, int mmreg) -{ - switch (mem) { - case 0x12000010: // GS_SMODE1 - case 0x12000020: // GS_SMODE2 - // SMODE1 and SMODE2 fall back on the gsWrite library. - // the low 32 bit dword is all the SMODE regs care about. - iFlushCall(0); - _callFunctionArg2((uptr)gsWrite32, MEM_CONSTTAG, mmreg, mem, 0 ); - break; - - case 0x12001000: // GS_CSR - iFlushCall(0); - _callFunctionArg1((uptr)gsCSRwrite, mmreg, 0); - break; - - case 0x12001010: // GS_IMR - gsConstWriteIMR(mmreg); - break; - - default: - _eeWriteConstMem64((uptr)PS2GS_BASE(mem), mmreg); - - if( mtgsThread != NULL ) - { - iFlushCall( 0 ); - _rec_mtgs_Send64( (uptr)PS2GS_BASE(mem), mem, mmreg ); - } - - break; - } -} - -void gsConstWrite128(u32 mem, int mmreg) -{ - switch (mem) { - case 0x12000010: // GS_SMODE1 - case 0x12000020: // GS_SMODE2 - // SMODE1 and SMODE2 fall back on the gsWrite library. - // the low 32 bit dword is all the SMODE regs care about. - iFlushCall(0); - _callFunctionArg2((uptr)gsWrite32, MEM_CONSTTAG, mmreg, mem, 0 ); - break; - - case 0x12001000: // GS_CSR - iFlushCall(0); - _callFunctionArg1((uptr)gsCSRwrite, mmreg, 0); - break; - - case 0x12001010: // GS_IMR - // (value&0x1f00)|0x6000 - gsConstWriteIMR(mmreg); - break; - - default: - _eeWriteConstMem128( (uptr)PS2GS_BASE(mem), mmreg); - - if( mtgsThread != NULL ) - { - iFlushCall(0); - _rec_mtgs_Send64( (uptr)PS2GS_BASE(mem), mem, mmreg ); - _rec_mtgs_Send64( (uptr)PS2GS_BASE(mem)+8, mem+8, mmreg ); - } - - break; - } -} - -int gsConstRead8(u32 x86reg, u32 mem, u32 sign) -{ - GIF_LOG("GS read 8 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem); - _eeReadConstMem8(x86reg, (uptr)PS2GS_BASE(mem), sign); - return 0; -} - -int gsConstRead16(u32 x86reg, u32 mem, u32 sign) -{ - GIF_LOG("GS read 16 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem); - _eeReadConstMem16(x86reg, (uptr)PS2GS_BASE(mem), sign); - return 0; -} - -int gsConstRead32(u32 x86reg, u32 mem) -{ - GIF_LOG("GS read 32 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem); - _eeReadConstMem32(x86reg, (uptr)PS2GS_BASE(mem)); - return 0; -} - -void gsConstRead64(u32 mem, int mmreg) -{ - GIF_LOG("GS read 64 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem); - if( IS_XMMREG(mmreg) ) SSE_MOVLPS_M64_to_XMM(mmreg&0xff, (uptr)PS2GS_BASE(mem)); - else { - MOVQMtoR(mmreg, (uptr)PS2GS_BASE(mem)); - SetMMXstate(); - } -} - -void gsConstRead128(u32 mem, int xmmreg) -{ - GIF_LOG("GS read 128 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem); - _eeReadConstMem128( xmmreg, (uptr)PS2GS_BASE(mem)); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "VU.h" + +#include "ix86/ix86.h" +#include "iR5900.h" + +#include "GS.h" +#include "DebugTools/Debug.h" + +extern u8 g_RealGSMem[0x2000]; +#define PS2GS_BASE(mem) (g_RealGSMem+(mem&0x13ff)) + +// __thiscall -- Calling Convention Notes. + +// ** MSVC passes the pointer to the object as ECX. Other parameters are passed normally +// (_cdecl style). Stack is cleaned by the callee. + +// ** GCC works just like a __cdecl, except the pointer to the object is pushed onto the +// stack last (passed as the first parameter). Caller cleans up the stack. + +// The GCC code below is untested. Hope it works. :| (air) + + +// Used to send 8, 16, and 32 bit values to the MTGS. +static void __fastcall _rec_mtgs_Send32orSmaller( GS_RINGTYPE ringtype, u32 mem, int mmreg ) +{ + iFlushCall(0); + + PUSH32I( 0 ); + _callPushArg( mmreg, 0 ); + PUSH32I( mem&0x13ff ); + PUSH32I( ringtype ); + +#ifdef _MSC_VER + MOV32ItoR( ECX, (uptr)mtgsThread ); + CALLFunc( mtgsThread->FnPtr_SimplePacket() ); +#else // GCC --> + PUSH32I( (uptr)mtgsThread ); + CALLFunc( mtgsThread->FnPtr_SimplePacket() ); + ADD32ItoR( ESP, 20 ); +#endif +} + +// Used to send 64 and 128 bit values to the MTGS (called twice for 128's, which +// is why it doesn't call iFlushCall) +static void __fastcall _rec_mtgs_Send64( uptr gsbase, u32 mem, int mmreg ) +{ + PUSH32M( gsbase+4 ); + PUSH32M( gsbase ); + PUSH32I( mem&0x13ff ); + PUSH32I( GS_RINGTYPE_MEMWRITE64 ); + +#ifdef _MSC_VER + MOV32ItoR( ECX, (uptr)mtgsThread ); + CALLFunc( mtgsThread->FnPtr_SimplePacket() ); +#else // GCC --> + PUSH32I( (uptr)mtgsThread ); + CALLFunc( mtgsThread->FnPtr_SimplePacket() ); + ADD32ItoR( ESP, 20 ); +#endif + +} + +void gsConstWrite8(u32 mem, int mmreg) +{ + switch (mem&~3) { + case 0x12001000: // GS_CSR + _eeMoveMMREGtoR(EAX, mmreg); + iFlushCall(0); + MOV32MtoR(ECX, (uptr)&CSRw); + AND32ItoR(EAX, 0xff<<(mem&3)*8); + AND32ItoR(ECX, ~(0xff<<(mem&3)*8)); + OR32ItoR(EAX, ECX); + _callFunctionArg1((uptr)gsCSRwrite, EAX|MEM_X86TAG, 0); + break; + default: + _eeWriteConstMem8( (uptr)PS2GS_BASE(mem), mmreg ); + + if( mtgsThread != NULL ) + _rec_mtgs_Send32orSmaller( GS_RINGTYPE_MEMWRITE8, mem, mmreg ); + + break; + } +} + +void gsConstWrite16(u32 mem, int mmreg) +{ + switch (mem&~3) { + + case 0x12000010: // GS_SMODE1 + case 0x12000020: // GS_SMODE2 + // SMODE1 and SMODE2 fall back on the gsWrite library. + iFlushCall(0); + _callFunctionArg2((uptr)gsWrite16, MEM_CONSTTAG, mmreg, mem, 0 ); + break; + + case 0x12001000: // GS_CSR + + assert( !(mem&2) ); + _eeMoveMMREGtoR(EAX, mmreg); + iFlushCall(0); + + MOV32MtoR(ECX, (uptr)&CSRw); + AND32ItoR(EAX, 0xffff<<(mem&2)*8); + AND32ItoR(ECX, ~(0xffff<<(mem&2)*8)); + OR32ItoR(EAX, ECX); + _callFunctionArg1((uptr)gsCSRwrite, EAX|MEM_X86TAG, 0); + break; + + default: + _eeWriteConstMem16( (uptr)PS2GS_BASE(mem), mmreg ); + + if( mtgsThread != NULL ) + _rec_mtgs_Send32orSmaller( GS_RINGTYPE_MEMWRITE16, mem, mmreg ); + + break; + } +} + +// (value&0x1f00)|0x6000 +void gsConstWriteIMR(int mmreg) +{ + const u32 mem = 0x12001010; + if( mmreg & MEM_XMMTAG ) { + SSE2_MOVD_XMM_to_M32((uptr)PS2GS_BASE(mem), mmreg&0xf); + AND32ItoM((uptr)PS2GS_BASE(mem), 0x1f00); + OR32ItoM((uptr)PS2GS_BASE(mem), 0x6000); + } + else if( mmreg & MEM_MMXTAG ) { + SetMMXstate(); + MOVDMMXtoM((uptr)PS2GS_BASE(mem), mmreg&0xf); + AND32ItoM((uptr)PS2GS_BASE(mem), 0x1f00); + OR32ItoM((uptr)PS2GS_BASE(mem), 0x6000); + } + else if( mmreg & MEM_EECONSTTAG ) { + MOV32ItoM( (uptr)PS2GS_BASE(mem), (g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]&0x1f00)|0x6000); + } + else { + AND32ItoR(mmreg, 0x1f00); + OR32ItoR(mmreg, 0x6000); + MOV32RtoM( (uptr)PS2GS_BASE(mem), mmreg ); + } + + // IMR doesn't need to be updated in MTGS mode +} + +void gsConstWrite32(u32 mem, int mmreg) { + + switch (mem) { + + case 0x12000010: // GS_SMODE1 + case 0x12000020: // GS_SMODE2 + // SMODE1 and SMODE2 fall back on the gsWrite library. + iFlushCall(0); + _callFunctionArg2((uptr)gsWrite32, MEM_CONSTTAG, mmreg, mem, 0 ); + break; + + case 0x12001000: // GS_CSR + iFlushCall(0); + _callFunctionArg1((uptr)gsCSRwrite, mmreg, 0); + break; + + case 0x12001010: // GS_IMR + gsConstWriteIMR(mmreg); + break; + default: + _eeWriteConstMem32( (uptr)PS2GS_BASE(mem), mmreg ); + + if( mtgsThread != NULL ) + _rec_mtgs_Send32orSmaller( GS_RINGTYPE_MEMWRITE32, mem, mmreg ); + + break; + } +} + +void gsConstWrite64(u32 mem, int mmreg) +{ + switch (mem) { + case 0x12000010: // GS_SMODE1 + case 0x12000020: // GS_SMODE2 + // SMODE1 and SMODE2 fall back on the gsWrite library. + // the low 32 bit dword is all the SMODE regs care about. + iFlushCall(0); + _callFunctionArg2((uptr)gsWrite32, MEM_CONSTTAG, mmreg, mem, 0 ); + break; + + case 0x12001000: // GS_CSR + iFlushCall(0); + _callFunctionArg1((uptr)gsCSRwrite, mmreg, 0); + break; + + case 0x12001010: // GS_IMR + gsConstWriteIMR(mmreg); + break; + + default: + _eeWriteConstMem64((uptr)PS2GS_BASE(mem), mmreg); + + if( mtgsThread != NULL ) + { + iFlushCall( 0 ); + _rec_mtgs_Send64( (uptr)PS2GS_BASE(mem), mem, mmreg ); + } + + break; + } +} + +void gsConstWrite128(u32 mem, int mmreg) +{ + switch (mem) { + case 0x12000010: // GS_SMODE1 + case 0x12000020: // GS_SMODE2 + // SMODE1 and SMODE2 fall back on the gsWrite library. + // the low 32 bit dword is all the SMODE regs care about. + iFlushCall(0); + _callFunctionArg2((uptr)gsWrite32, MEM_CONSTTAG, mmreg, mem, 0 ); + break; + + case 0x12001000: // GS_CSR + iFlushCall(0); + _callFunctionArg1((uptr)gsCSRwrite, mmreg, 0); + break; + + case 0x12001010: // GS_IMR + // (value&0x1f00)|0x6000 + gsConstWriteIMR(mmreg); + break; + + default: + _eeWriteConstMem128( (uptr)PS2GS_BASE(mem), mmreg); + + if( mtgsThread != NULL ) + { + iFlushCall(0); + _rec_mtgs_Send64( (uptr)PS2GS_BASE(mem), mem, mmreg ); + _rec_mtgs_Send64( (uptr)PS2GS_BASE(mem)+8, mem+8, mmreg ); + } + + break; + } +} + +int gsConstRead8(u32 x86reg, u32 mem, u32 sign) +{ + GIF_LOG("GS read 8 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem); + _eeReadConstMem8(x86reg, (uptr)PS2GS_BASE(mem), sign); + return 0; +} + +int gsConstRead16(u32 x86reg, u32 mem, u32 sign) +{ + GIF_LOG("GS read 16 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem); + _eeReadConstMem16(x86reg, (uptr)PS2GS_BASE(mem), sign); + return 0; +} + +int gsConstRead32(u32 x86reg, u32 mem) +{ + GIF_LOG("GS read 32 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem); + _eeReadConstMem32(x86reg, (uptr)PS2GS_BASE(mem)); + return 0; +} + +void gsConstRead64(u32 mem, int mmreg) +{ + GIF_LOG("GS read 64 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem); + if( IS_XMMREG(mmreg) ) SSE_MOVLPS_M64_to_XMM(mmreg&0xff, (uptr)PS2GS_BASE(mem)); + else { + MOVQMtoR(mmreg, (uptr)PS2GS_BASE(mem)); + SetMMXstate(); + } +} + +void gsConstRead128(u32 mem, int xmmreg) +{ + GIF_LOG("GS read 128 %8.8lx (%8.8x), at %8.8lx\n", (uptr)PS2GS_BASE(mem), mem); + _eeReadConstMem128( xmmreg, (uptr)PS2GS_BASE(mem)); +} diff --git a/pcsx2/x86/iHw.cpp b/pcsx2/x86/iHw.cpp index fe5fe243cb..c4205d55ca 100644 --- a/pcsx2/x86/iHw.cpp +++ b/pcsx2/x86/iHw.cpp @@ -1,1157 +1,1157 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "iR5900.h" -#include "VUmicro.h" -#include "IopMem.h" - -// The full suite of hardware APIs: -#include "IPU/IPU.h" -#include "GS.h" -#include "Counters.h" -#include "Vif.h" -#include "VifDma.h" -#include "SPR.h" -#include "Sif.h" - - -extern int rdram_devices; // put 8 for TOOL and 2 for PS2 and PSX -extern int rdram_sdevid; -extern char sio_buffer[1024]; -extern int sio_count; - -int hwConstRead8(u32 x86reg, u32 mem, u32 sign) -{ - if( mem >= 0x10000000 && mem < 0x10008000 ) - DevCon::WriteLn("hwRead8 to %x", params mem); - - if ((mem & 0xffffff0f) == 0x1000f200) { - if(mem == 0x1000f260) { - MMXONLY(if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf); - else) - XOR32RtoR(x86reg, x86reg); - return 0; - } - else if(mem == 0x1000F240) { - - _eeReadConstMem8(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff], sign); - //psHu32(mem) &= ~0x4000; - return 0; - } - } - - if (mem < 0x10010000) - { - _eeReadConstMem8(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff], sign); - } - else { - MMXONLY(if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf); - else ) - XOR32RtoR(x86reg, x86reg); - } - - return 0; -} - -#define CONSTREAD16_CALL(name) { \ - iFlushCall(0); \ - CALLFunc((uptr)name); \ - if( sign ) MOVSX32R16toR(EAX, EAX); \ - else MOVZX32R16toR(EAX, EAX); \ -} \ - -static u32 s_regreads[3] = {0x010200000, 0xbfff0000, 0xF0000102}; -int hwConstRead16(u32 x86reg, u32 mem, u32 sign) -{ - if( mem >= 0x10002000 && mem < 0x10008000 ) - DevCon::WriteLn("hwRead16 to %x", params mem); - - if( mem >= 0x10000000 && mem < 0x10002000 ) - EECNT_LOG("cnt read to %x\n", params mem); - - switch (mem) { - case 0x10000000: - PUSH32I(0); - CONSTREAD16_CALL(rcntRcount); - ADD32ItoR(ESP, 4); - return 1; - case 0x10000010: - _eeReadConstMem16(x86reg, (uptr)&counters[0].mode, sign); - return 0; - case 0x10000020: - _eeReadConstMem16(x86reg, (uptr)&counters[0].mode, sign); - return 0; - case 0x10000030: - _eeReadConstMem16(x86reg, (uptr)&counters[0].hold, sign); - return 0; - - case 0x10000800: - PUSH32I(1); - CONSTREAD16_CALL(rcntRcount); - ADD32ItoR(ESP, 4); - return 1; - - case 0x10000810: - _eeReadConstMem16(x86reg, (uptr)&counters[1].mode, sign); - return 0; - - case 0x10000820: - _eeReadConstMem16(x86reg, (uptr)&counters[1].target, sign); - return 0; - - case 0x10000830: - _eeReadConstMem16(x86reg, (uptr)&counters[1].hold, sign); - return 0; - - case 0x10001000: - PUSH32I(2); - CONSTREAD16_CALL(rcntRcount); - ADD32ItoR(ESP, 4); - return 1; - - case 0x10001010: - _eeReadConstMem16(x86reg, (uptr)&counters[2].mode, sign); - return 0; - - case 0x10001020: - _eeReadConstMem16(x86reg, (uptr)&counters[2].target, sign); - return 0; - - case 0x10001800: - PUSH32I(3); - CONSTREAD16_CALL(rcntRcount); - ADD32ItoR(ESP, 4); - return 1; - - case 0x10001810: - _eeReadConstMem16(x86reg, (uptr)&counters[3].mode, sign); - return 0; - - case 0x10001820: - _eeReadConstMem16(x86reg, (uptr)&counters[3].target, sign); - return 0; - - default: - if ((mem & 0xffffff0f) == 0x1000f200) { - if(mem == 0x1000f260) { - MMXONLY(if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf); - else ) - XOR32RtoR(x86reg, x86reg); - return 0; - } - else if(mem == 0x1000F240) { - - MMXONLY(if( IS_MMXREG(x86reg) ) { - MOVDMtoMMX(x86reg&0xf, (uptr)&PS2MEM_HW[(mem) & 0xffff] - 2); - PORMtoR(x86reg&0xf, (uptr)&s_regreads[0]); - PANDMtoR(x86reg&0xf, (uptr)&s_regreads[1]); - } - else ) - { - if( sign ) MOVSX32M16toR(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff]); - else MOVZX32M16toR(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff]); - - OR32ItoR(x86reg, 0x0102); - AND32ItoR(x86reg, ~0x4000); - } - return 0; - } - } - if (mem < 0x10010000) { - _eeReadConstMem16(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff], sign); - } - else { - MMXONLY(if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf); - else ) - XOR32RtoR(x86reg, x86reg); - } - - return 0; - } -} - -int hwContRead32_f440() -{ - if ((psHu32(0xf430) >> 6) & 0xF) - return 0; - else - switch ((psHu32(0xf430)>>16) & 0xFFF){//MCH_RICM: x:4|SA:12|x:5|SDEV:1|SOP:4|SBC:1|SDEV:5 - case 0x21://INIT - { - int ret = 0x1F * (rdram_sdevid < rdram_devices); - rdram_sdevid += (rdram_sdevid < rdram_devices); - return ret; - } - case 0x23://CNFGA - return 0x0D0D; //PVER=3 | MVER=16 | DBL=1 | REFBIT=5 - case 0x24://CNFGB - //0x0110 for PSX SVER=0 | CORG=8(5x9x7) | SPT=1 | DEVTYP=0 | BYTE=0 - return 0x0090; //SVER=0 | CORG=4(5x9x6) | SPT=1 | DEVTYP=0 | BYTE=0 - case 0x40://DEVID - return psHu32(0xf430) & 0x1F; // =SDEV - } - - return 0; -} - -int hwConstRead32(u32 x86reg, u32 mem) -{ - //IPU regs - if ((mem>=0x10002000) && (mem<0x10003000)) { - //return ipuConstRead32(x86reg, mem); - iFlushCall(0); - PUSH32I( mem ); - CALLFunc( (uptr)ipuRead32 ); - } - - switch (mem) { - case 0x10000000: - iFlushCall(0); - PUSH32I(0); - CALLFunc((uptr)rcntRcount); - EECNT_LOG("Counter 0 count read = %x\n", rcntRcount(0)); - ADD32ItoR(ESP, 4); - return 1; - case 0x10000010: - _eeReadConstMem32(x86reg, (uptr)&counters[0].mode); - EECNT_LOG("Counter 0 mode read = %x\n", counters[0].modeval); - return 0; - case 0x10000020: - _eeReadConstMem32(x86reg, (uptr)&counters[0].target); - EECNT_LOG("Counter 0 target read = %x\n", counters[0].target); - return 0; - case 0x10000030: - _eeReadConstMem32(x86reg, (uptr)&counters[0].hold); - return 0; - - case 0x10000800: - iFlushCall(0); - PUSH32I(1); - CALLFunc((uptr)rcntRcount); - EECNT_LOG("Counter 1 count read = %x\n", rcntRcount(1)); - ADD32ItoR(ESP, 4); - return 1; - case 0x10000810: - _eeReadConstMem32(x86reg, (uptr)&counters[1].mode); - EECNT_LOG("Counter 1 mode read = %x\n", counters[1].modeval); - return 0; - case 0x10000820: - _eeReadConstMem32(x86reg, (uptr)&counters[1].target); - EECNT_LOG("Counter 1 target read = %x\n", counters[1].target); - return 0; - case 0x10000830: - _eeReadConstMem32(x86reg, (uptr)&counters[1].hold); - return 0; - - case 0x10001000: - iFlushCall(0); - PUSH32I(2); - CALLFunc((uptr)rcntRcount); - EECNT_LOG("Counter 2 count read = %x\n", rcntRcount(2)); - ADD32ItoR(ESP, 4); - return 1; - case 0x10001010: - _eeReadConstMem32(x86reg, (uptr)&counters[2].mode); - EECNT_LOG("Counter 2 mode read = %x\n", counters[2].modeval); - return 0; - case 0x10001020: - _eeReadConstMem32(x86reg, (uptr)&counters[2].target); - EECNT_LOG("Counter 2 target read = %x\n", counters[2].target); - return 0; - case 0x10001030: - // fixme: Counters[2].hold and Counters[3].hold are never assigned values - // anywhere in Pcsx2. - _eeReadConstMem32(x86reg, (uptr)&counters[2].hold); - return 0; - - case 0x10001800: - iFlushCall(0); - PUSH32I(3); - CALLFunc((uptr)rcntRcount); - EECNT_LOG("Counter 3 count read = %x\n", rcntRcount(3)); - ADD32ItoR(ESP, 4); - return 1; - case 0x10001810: - _eeReadConstMem32(x86reg, (uptr)&counters[3].mode); - EECNT_LOG("Counter 3 mode read = %x\n", counters[3].modeval); - return 0; - case 0x10001820: - _eeReadConstMem32(x86reg, (uptr)&counters[3].target); - EECNT_LOG("Counter 3 target read = %x\n", counters[3].target); - return 0; - case 0x10001830: - // fixme: Counters[2].hold and Counters[3].hold are never assigned values - // anywhere in Pcsx2. - _eeReadConstMem32(x86reg, (uptr)&counters[3].hold); - return 0; - - case 0x1000f130: - case 0x1000f410: - case 0x1000f430: - if( IS_XMMREG(x86reg) ) SSEX_PXOR_XMM_to_XMM(x86reg&0xf, x86reg&0xf); - MMXONLY(else if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf);) - else XOR32RtoR(x86reg, x86reg); - return 0; - - case 0x1000f440: - iFlushCall(0); - CALLFunc((uptr)hwContRead32_f440); - return 1; - - case 0x1000f520: // DMAC_ENABLER - _eeReadConstMem32(x86reg, (uptr)&PS2MEM_HW[0xf590]); - return 0; - - default: - if ((mem & 0xffffff0f) == 0x1000f200) { - if(mem == 0x1000f260) { - if( IS_XMMREG(x86reg) ) SSEX_PXOR_XMM_to_XMM(x86reg&0xf, x86reg&0xf); - MMXONLY(else if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf);) - else XOR32RtoR(x86reg, x86reg); - return 0; - } - else if(mem == 0x1000F240) { - - if( IS_XMMREG(x86reg) ) { - SSEX_MOVD_M32_to_XMM(x86reg&0xf, (uptr)&PS2MEM_HW[(mem) & 0xffff]); - SSEX_POR_M128_to_XMM(x86reg&0xf, (uptr)&s_regreads[2]); - } - MMXONLY(else if( IS_MMXREG(x86reg) ) { - MOVDMtoMMX(x86reg&0xf, (uptr)&PS2MEM_HW[(mem) & 0xffff]); - PORMtoR(x86reg&0xf, (uptr)&s_regreads[2]); - }) - else { - MOV32MtoR(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff]); - OR32ItoR(x86reg, 0xF0000102); - } - return 0; - } - } - - if (mem < 0x10010000) { - _eeReadConstMem32(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff]); - } - else { - if( IS_XMMREG(x86reg) ) SSEX_PXOR_XMM_to_XMM(x86reg&0xf, x86reg&0xf); - MMXONLY(else if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf);) - else XOR32RtoR(x86reg, x86reg); - } - - return 0; - } -} - -void hwConstRead64(u32 mem, int mmreg) { - if ((mem>=0x10002000) && (mem<0x10003000)) { - ipuConstRead64(mem, mmreg); - return; - } - - if( IS_XMMREG(mmreg) ) SSE_MOVLPS_M64_to_XMM(mmreg&0xff, (uptr)PSM(mem)); - else { - MMXONLY(MOVQMtoR(mmreg, (uptr)PSM(mem)); - SetMMXstate();) - } -} - -PCSX2_ALIGNED16(u32 s_TempFIFO[4]); -void hwConstRead128(u32 mem, int xmmreg) { - - // fixme : This needs to be updated to use the new paged FIFO accessors. - /*if (mem >= 0x10004000 && mem < 0x10008000) { - iFlushCall(0); - PUSH32I((uptr)&s_TempFIFO[0]); - PUSH32I(mem); - CALLFunc((uptr)ReadFIFO); - ADD32ItoR(ESP, 8); - _eeReadConstMem128( xmmreg, (uptr)&s_TempFIFO[0]); - return; - }*/ - - _eeReadConstMem128( xmmreg, (uptr)PSM(mem)); -} - -// when writing imm -static void recDmaExecI8(void (*name)(), u32 mem, int mmreg) -{ - MOV8ItoM((uptr)&PS2MEM_HW[(mem) & 0xffff], g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]); - if( g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 1 ) { - TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1); - j8Ptr[6] = JZ8(0); - CALLFunc((uptr)name); - x86SetJ8( j8Ptr[6] ); - } -} - -static void recDmaExec8(void (*name)(), u32 mem, int mmreg) -{ - // Flushcall Note : DMA transfers are almost always "involved" operations - // that use memcpys and/or threading. Freeing all XMM and MMX regs is the - // best option. - - iFlushCall(FLUSH_NOCONST); - if( IS_EECONSTREG(mmreg) ) { - recDmaExecI8(name, mem, mmreg); - } - else { - _eeMoveMMREGtoR(EAX, mmreg); - _eeWriteConstMem8((uptr)&PS2MEM_HW[(mem) & 0xffff], mmreg); - - TEST8ItoR(EAX, 1); - j8Ptr[5] = JZ8(0); - TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1); - j8Ptr[6] = JZ8(0); - - CALLFunc((uptr)name); - - x86SetJ8( j8Ptr[5] ); - x86SetJ8( j8Ptr[6] ); - } -} - -static void __fastcall PrintDebug(u8 value) -{ - // Note: This is where the EE's diagonstic messages originate from (like the ones that - // start with hash # marks) - - if (value == '\n') { - sio_buffer[sio_count] = 0; - Console::WriteLn( Color_Cyan, sio_buffer ); - sio_count = 0; - } else { - if (sio_count < 1023) { - sio_buffer[sio_count++] = value; - } - } -} - -// fixme: this would be more optimal as a C++ template (with bit as the template parameter) -template< uint bit > -static void ConstWrite_ExecTimer( uptr func, u8 index, int mmreg) -{ - if( bit != 32 ) - { - if( !IS_EECONSTREG(mmreg) ) - { - if( bit == 8 ) MOVZX32R8toR(mmreg&0xf, mmreg&0xf); - else if( bit == 16 ) MOVZX32R16toR(mmreg&0xf, mmreg&0xf); - } - } - - // FlushCall Note : All counter functions are short and sweet, full flush not needed. - - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(index); - CALLFunc(func); - ADD32ItoR(ESP, 8); -} - -#define CONSTWRITE_TIMERS(bit) \ - case 0x10000000: ConstWrite_ExecTimer((uptr)&rcntWcount, 0, mmreg); break; \ - case 0x10000010: ConstWrite_ExecTimer((uptr)&rcntWmode, 0, mmreg); break; \ - case 0x10000020: ConstWrite_ExecTimer((uptr)&rcntWtarget, 0, mmreg); break; \ - case 0x10000030: ConstWrite_ExecTimer((uptr)&rcntWhold, 0, mmreg); break; \ - \ - case 0x10000800: ConstWrite_ExecTimer((uptr)&rcntWcount, 1, mmreg); break; \ - case 0x10000810: ConstWrite_ExecTimer((uptr)&rcntWmode, 1, mmreg); break; \ - case 0x10000820: ConstWrite_ExecTimer((uptr)&rcntWtarget, 1, mmreg); break; \ - case 0x10000830: ConstWrite_ExecTimer((uptr)&rcntWhold, 1, mmreg); break; \ - \ - case 0x10001000: ConstWrite_ExecTimer((uptr)&rcntWcount, 2, mmreg); break; \ - case 0x10001010: ConstWrite_ExecTimer((uptr)&rcntWmode, 2, mmreg); break; \ - case 0x10001020: ConstWrite_ExecTimer((uptr)&rcntWtarget, 2, mmreg); break; \ - \ - case 0x10001800: ConstWrite_ExecTimer((uptr)&rcntWcount, 3, mmreg); break; \ - case 0x10001810: ConstWrite_ExecTimer((uptr)&rcntWmode, 3, mmreg); break; \ - case 0x10001820: ConstWrite_ExecTimer((uptr)&rcntWtarget, 3, mmreg); break; \ - -void hwConstWrite8(u32 mem, int mmreg) -{ - switch (mem) { - CONSTWRITE_TIMERS(8) - - case 0x1000f180: - // Yay fastcall! - _eeMoveMMREGtoR( ECX, mmreg ); - iFlushCall(0); - CALLFunc((uptr)PrintDebug); - break; - - case 0x10008001: // dma0 - vif0 - recDmaExec8(dmaVIF0, mem, mmreg); - break; - - case 0x10009001: // dma1 - vif1 - recDmaExec8(dmaVIF1, mem, mmreg); - break; - - case 0x1000a001: // dma2 - gif - recDmaExec8(dmaGIF, mem, mmreg); - break; - - case 0x1000b001: // dma3 - fromIPU - recDmaExec8(dmaIPU0, mem, mmreg); - break; - - case 0x1000b401: // dma4 - toIPU - recDmaExec8(dmaIPU1, mem, mmreg); - break; - - case 0x1000c001: // dma5 - sif0 - //if (value == 0) psxSu32(0x30) = 0x40000; - recDmaExec8(dmaSIF0, mem, mmreg); - break; - - case 0x1000c401: // dma6 - sif1 - recDmaExec8(dmaSIF1, mem, mmreg); - break; - - case 0x1000c801: // dma7 - sif2 - recDmaExec8(dmaSIF2, mem, mmreg); - break; - - case 0x1000d001: // dma8 - fromSPR - recDmaExec8(dmaSPR0, mem, mmreg); - break; - - case 0x1000d401: // dma9 - toSPR - recDmaExec8(dmaSPR1, mem, mmreg); - break; - - case 0x1000f592: // DMAC_ENABLEW - _eeWriteConstMem8( (uptr)&PS2MEM_HW[0xf522], mmreg ); - _eeWriteConstMem8( (uptr)&PS2MEM_HW[0xf592], mmreg ); - break; - - default: - if ((mem & 0xffffff0f) == 0x1000f200) { - u32 at = mem & 0xf0; - switch(at) - { - case 0x00: - _eeWriteConstMem8( (uptr)&PS2MEM_HW[mem&0xffff], mmreg); - break; - case 0x40: - if( IS_EECONSTREG(mmreg) ) { - if( !(g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 0x100) ) { - AND32ItoM( (uptr)&PS2MEM_HW[mem&0xfffc], ~0x100); - } - } - else { - _eeMoveMMREGtoR(EAX, mmreg); - TEST16ItoR(EAX, 0x100); - j8Ptr[5] = JNZ8(0); - AND32ItoM( (uptr)&PS2MEM_HW[mem&0xfffc], ~0x100); - x86SetJ8(j8Ptr[5]); - } - break; - } - return; - } - assert( (mem&0xff0f) != 0xf200 ); - - switch(mem&~3) { - case 0x1000f130: - case 0x1000f410: - case 0x1000f430: - break; - default: - _eeWriteConstMem8((uptr)&PS2MEM_HW[mem&0xffff], mmreg); - } - - break; - } -} - -// Flushcall Note : DMA transfers are almost always "involved" operations -// that use memcpys and/or threading. Freeing all XMM and MMX regs is the -// best option (removes the need for FreezeXMMRegs()). But register -// allocation is such a mess right now that we can't do it (yet). - -static void recDmaExecI16( void (*name)(), u32 mem, int mmreg ) -{ - MOV16ItoM((uptr)&PS2MEM_HW[(mem) & 0xffff], g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]); - if( g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 0x100 ) { - TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1); - j8Ptr[6] = JZ8(0); - CALLFunc((uptr)name); - x86SetJ8( j8Ptr[6] ); - } -} - -static void recDmaExec16(void (*name)(), u32 mem, int mmreg) -{ - iFlushCall(0); - - if( IS_EECONSTREG(mmreg) ) { - recDmaExecI16(name, mem, mmreg); - } - else { - _eeMoveMMREGtoR(EAX, mmreg); - _eeWriteConstMem16((uptr)&PS2MEM_HW[(mem) & 0xffff], mmreg); - - TEST16ItoR(EAX, 0x100); - j8Ptr[5] = JZ8(0); - TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1); - j8Ptr[6] = JZ8(0); - - CALLFunc((uptr)name); - - x86SetJ8( j8Ptr[5] ); - x86SetJ8( j8Ptr[6] ); - } -} - -void hwConstWrite16(u32 mem, int mmreg) -{ - switch(mem) { - - CONSTWRITE_TIMERS(16) - - case 0x10008000: // dma0 - vif0 - recDmaExec16(dmaVIF0, mem, mmreg); - break; - - case 0x10009000: // dma1 - vif1 - chcr - recDmaExec16(dmaVIF1, mem, mmreg); - break; - - case 0x1000a000: // dma2 - gif - recDmaExec16(dmaGIF, mem, mmreg); - break; - case 0x1000b000: // dma3 - fromIPU - recDmaExec16(dmaIPU0, mem, mmreg); - break; - case 0x1000b400: // dma4 - toIPU - recDmaExec16(dmaIPU1, mem, mmreg); - break; - case 0x1000c000: // dma5 - sif0 - //if (value == 0) psxSu32(0x30) = 0x40000; - recDmaExec16(dmaSIF0, mem, mmreg); - break; - case 0x1000c002: - //? - break; - case 0x1000c400: // dma6 - sif1 - recDmaExec16(dmaSIF1, mem, mmreg); - break; - case 0x1000c800: // dma7 - sif2 - recDmaExec16(dmaSIF2, mem, mmreg); - break; - case 0x1000c802: - //? - break; - case 0x1000d000: // dma8 - fromSPR - recDmaExec16(dmaSPR0, mem, mmreg); - break; - case 0x1000d400: // dma9 - toSPR - recDmaExec16(dmaSPR1, mem, mmreg); - break; - case 0x1000f592: // DMAC_ENABLEW - _eeWriteConstMem16((uptr)&PS2MEM_HW[0xf522], mmreg); - _eeWriteConstMem16((uptr)&PS2MEM_HW[0xf592], mmreg); - break; - case 0x1000f130: - case 0x1000f410: - case 0x1000f430: - break; - default: - if ((mem & 0xffffff0f) == 0x1000f200) { - u32 at = mem & 0xf0; - switch(at) - { - case 0x00: - _eeWriteConstMem16((uptr)&PS2MEM_HW[mem&0xffff], mmreg); - break; - case 0x20: - _eeWriteConstMem16OP((uptr)&PS2MEM_HW[mem&0xffff], mmreg, 1); - break; - case 0x30: - if( IS_EECONSTREG(mmreg) ) { - AND16ItoM((uptr)&PS2MEM_HW[mem&0xffff], ~g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]); - } - else { - NOT32R(mmreg&0xf); - AND16RtoM((uptr)&PS2MEM_HW[mem&0xffff], mmreg&0xf); - } - break; - case 0x40: - if( IS_EECONSTREG(mmreg) ) { - if( !(g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 0x100) ) { - AND16ItoM((uptr)&PS2MEM_HW[mem&0xffff], ~0x100); - } - else { - OR16ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0x100); - } - } - else { - _eeMoveMMREGtoR(EAX, mmreg); - TEST16ItoR(EAX, 0x100); - j8Ptr[5] = JZ8(0); - OR16ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0x100); - j8Ptr[6] = JMP8(0); - - x86SetJ8( j8Ptr[5] ); - AND16ItoM((uptr)&PS2MEM_HW[mem&0xffff], ~0x100); - - x86SetJ8( j8Ptr[6] ); - } - - break; - case 0x60: - _eeWriteConstMem16((uptr)&PS2MEM_HW[mem&0xffff], 0); - break; - } - return; - } - - _eeWriteConstMem16((uptr)&PS2MEM_HW[mem&0xffff], mmreg); - } -} - -// when writing an Imm - -static void recDmaExecI( void (*name)(), u32 mem, int mmreg ) -{ - u32 c = g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]; - /* Keep the old tag if in chain mode and hw doesnt set it*/ - if( (c & 0xc) == 0x4 && (c&0xffff0000) == 0 ) { - MOV16ItoM((uptr)&PS2MEM_HW[(mem) & 0xffff], c); - } - else MOV32ItoM((uptr)&PS2MEM_HW[(mem) & 0xffff], c); - if( c & 0x100 ) { - TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1); - j8Ptr[6] = JZ8(0); - CALLFunc((uptr)name); - x86SetJ8( j8Ptr[6] ); - } -} - -static void recDmaExec( void (*name)(), u32 mem, int mmreg ) -{ - - iFlushCall(0); - - if( IS_EECONSTREG(mmreg) ) { - recDmaExecI(name, mem, mmreg); - } - else { - - // fixme: This is a lot of code to be injecting into the recompiler - // for every DMA transfer. It might actually be more efficient to - // set this up as a C function call instead (depends on how often - // the register is written without actually starting a DMA xfer). - - _eeMoveMMREGtoR(EAX, mmreg); - TEST32ItoR(EAX, 0xffff0000); - j8Ptr[6] = JNZ8(0); - MOV32RtoR(ECX, EAX); - AND32ItoR(ECX, 0xc); - CMP32ItoR(ECX, 4); - j8Ptr[7] = JNE8(0); - if( IS_XMMREG(mmreg) || IS_MMXREG(mmreg) ) { - MOV16RtoM((uptr)&PS2MEM_HW[(mem) & 0xffff], EAX); - } - else { - _eeWriteConstMem16((uptr)&PS2MEM_HW[(mem) & 0xffff], mmreg); - } - j8Ptr[8] = JMP8(0); - x86SetJ8(j8Ptr[6]); - x86SetJ8(j8Ptr[7]); - _eeWriteConstMem32((uptr)&PS2MEM_HW[(mem) & 0xffff], mmreg); - x86SetJ8(j8Ptr[8]); - - TEST16ItoR(EAX, 0x100); - j8Ptr[5] = JZ8(0); - TEST32ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1); - j8Ptr[6] = JZ8(0); - - CALLFunc((uptr)name); - x86SetJ8( j8Ptr[5] ); - x86SetJ8( j8Ptr[6] ); - } -} - - -void hwConstWrite32(u32 mem, int mmreg) -{ - //IPU regs - if ((mem>=0x10002000) && (mem<0x10003000)) { - //psHu32(mem) = value; - ipuConstWrite32(mem, mmreg); - return; - } - - if ((mem>=0x10003800) && (mem<0x10003c00)) { - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(mem); - CALLFunc((uptr)vif0Write32); - ADD32ItoR(ESP, 8); - return; - } - if ((mem>=0x10003c00) && (mem<0x10004000)) { - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(mem); - CALLFunc((uptr)vif1Write32); - ADD32ItoR(ESP, 8); - return; - } - - switch (mem) { - - CONSTWRITE_TIMERS(32) - - case GIF_CTRL: - - _eeMoveMMREGtoR(EAX, mmreg); - - iFlushCall(0); - TEST8ItoR(EAX, 1); - j8Ptr[5] = JZ8(0); - - // reset GS - CALLFunc((uptr)gsGIFReset); - j8Ptr[6] = JMP8(0); - - x86SetJ8( j8Ptr[5] ); - AND32I8toR(EAX, 8); - MOV32RtoM((uptr)&PS2MEM_HW[mem&0xffff], EAX); - - TEST16ItoR(EAX, 8); - j8Ptr[5] = JZ8(0); - OR8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], 8); - j8Ptr[7] = JMP8(0); - - x86SetJ8( j8Ptr[5] ); - AND8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], ~8); - x86SetJ8( j8Ptr[6] ); - x86SetJ8( j8Ptr[7] ); - return; - - case GIF_MODE: - _eeMoveMMREGtoR(EAX, mmreg); - _eeWriteConstMem32((uptr)&PS2MEM_HW[mem&0xffff], mmreg); - AND8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], ~5); - AND8ItoR(EAX, 5); - OR8RtoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], EAX); - return; - - case GIF_STAT: // stat is readonly - return; - - case 0x10008000: // dma0 - vif0 - recDmaExec(dmaVIF0, mem, mmreg); - break; - - case 0x10009000: // dma1 - vif1 - chcr - recDmaExec(dmaVIF1, mem, mmreg); - break; - - case 0x1000a000: // dma2 - gif - recDmaExec(dmaGIF, mem, mmreg); - break; - - case 0x1000b000: // dma3 - fromIPU - recDmaExec(dmaIPU0, mem, mmreg); - break; - case 0x1000b400: // dma4 - toIPU - recDmaExec(dmaIPU1, mem, mmreg); - break; - case 0x1000c000: // dma5 - sif0 - //if (value == 0) psxSu32(0x30) = 0x40000; - recDmaExec(dmaSIF0, mem, mmreg); - break; - - case 0x1000c400: // dma6 - sif1 - recDmaExec(dmaSIF1, mem, mmreg); - break; - - case 0x1000c800: // dma7 - sif2 - recDmaExec(dmaSIF2, mem, mmreg); - break; - - case 0x1000d000: // dma8 - fromSPR - recDmaExec(dmaSPR0, mem, mmreg); - break; - - case 0x1000d400: // dma9 - toSPR - recDmaExec(dmaSPR1, mem, mmreg); - break; - - case 0x1000e010: // DMAC_STAT - _eeMoveMMREGtoR(EAX, mmreg); - iFlushCall(0); - MOV32RtoR(ECX, EAX); - SHR32ItoR(EAX, 16); - NOT32R(ECX); - XOR16RtoM((uptr)&PS2MEM_HW[0xe012], EAX); - AND16RtoM((uptr)&PS2MEM_HW[0xe010], ECX); - - CALLFunc((uptr)cpuTestDMACInts); - break; - - case 0x1000f000: // INTC_STAT - _eeWriteConstMem32OP((uptr)&PS2MEM_HW[0xf000], mmreg, 2); - CALLFunc((uptr)cpuTestINTCInts); - break; - - case 0x1000f010: // INTC_MASK - _eeMoveMMREGtoR(EAX, mmreg); - iFlushCall(0); - XOR16RtoM((uptr)&PS2MEM_HW[0xf010], EAX); - CALLFunc((uptr)cpuTestINTCInts); - break; - - case 0x1000f130: - case 0x1000f410: - break; - - case 0x1000f430://MCH_RICM: x:4|SA:12|x:5|SDEV:1|SOP:4|SBC:1|SDEV:5 - - //if ((((value >> 16) & 0xFFF) == 0x21) && (((value >> 6) & 0xF) == 1) && (((psHu32(0xf440) >> 7) & 1) == 0))//INIT & SRP=0 - // rdram_sdevid = 0 - _eeMoveMMREGtoR(EAX, mmreg); - MOV32RtoR(EDX, EAX); - MOV32RtoR(ECX, EAX); - SHR32ItoR(EAX, 6); - SHR32ItoR(EDX, 16); - AND32ItoR(EAX, 0xf); - AND32ItoR(EDX, 0xfff); - CMP32ItoR(EAX, 1); - j8Ptr[5] = JNE8(0); - CMP32ItoR(EDX, 0x21); - j8Ptr[6] = JNE8(0); - - TEST32ItoM((uptr)&psHu32(0xf440), 0x80); - j8Ptr[7] = JNZ8(0); - - // if SIO repeater is cleared, reset sdevid - MOV32ItoM((uptr)&rdram_sdevid, 0); - - //kill the busy bit - x86SetJ8(j8Ptr[5]); - x86SetJ8(j8Ptr[6]); - x86SetJ8(j8Ptr[7]); - AND32ItoR(ECX, ~0x80000000); - MOV32RtoM((uptr)&psHu32(0xf430), ECX); - break; - - case 0x1000f440://MCH_DRD: - _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf440], mmreg); - break; - - case 0x1000f590: // DMAC_ENABLEW - _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf520], mmreg); - _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf590], mmreg); - return; - - default: - if ((mem & 0xffffff0f) == 0x1000f200) { - u32 at = mem & 0xf0; - switch(at) - { - case 0x00: - _eeWriteConstMem32((uptr)&PS2MEM_HW[mem&0xffff], mmreg); - break; - case 0x20: - _eeWriteConstMem32OP((uptr)&PS2MEM_HW[mem&0xffff], mmreg, 1); - break; - case 0x30: - _eeWriteConstMem32OP((uptr)&PS2MEM_HW[mem&0xffff], mmreg, 2); - break; - case 0x40: - if( IS_EECONSTREG(mmreg) ) { - if( !(g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 0x100) ) { - AND32ItoM( (uptr)&PS2MEM_HW[mem&0xfffc], ~0x100); - } - else { - OR32ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0x100); - } - } - else { - _eeMoveMMREGtoR(EAX, mmreg); - TEST32ItoR(EAX, 0x100); - j8Ptr[5] = JZ8(0); - OR32ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0x100); - j8Ptr[6] = JMP8(0); - - x86SetJ8( j8Ptr[5] ); - AND32ItoM((uptr)&PS2MEM_HW[mem&0xffff], ~0x100); - - x86SetJ8( j8Ptr[6] ); - } - - break; - case 0x60: - MOV32ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0); - break; - } - return; - } - - _eeWriteConstMem32((uptr)&PS2MEM_HW[mem&0xffff], mmreg); - break; - } -} - -void hwConstWrite64(u32 mem, int mmreg) -{ - if ((mem>=0x10002000) && (mem<=0x10002030)) { - ipuConstWrite64(mem, mmreg); - return; - } - - if ((mem>=0x10003800) && (mem<0x10003c00)) { - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(mem); - CALLFunc((uptr)vif0Write32); - ADD32ItoR(ESP, 8); - return; - } - if ((mem>=0x10003c00) && (mem<0x10004000)) { - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(mem); - CALLFunc((uptr)vif1Write32); - ADD32ItoR(ESP, 8); - return; - } - - switch (mem) { - case GIF_CTRL: - _eeMoveMMREGtoR(EAX, mmreg); - - iFlushCall(0); - TEST8ItoR(EAX, 1); - j8Ptr[5] = JZ8(0); - - // reset GS - CALLFunc((uptr)gsGIFReset); - j8Ptr[6] = JMP8(0); - - x86SetJ8( j8Ptr[5] ); - AND32I8toR(EAX, 8); - MOV32RtoM((uptr)&PS2MEM_HW[mem&0xffff], EAX); - - TEST16ItoR(EAX, 8); - j8Ptr[5] = JZ8(0); - OR8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], 8); - j8Ptr[7] = JMP8(0); - - x86SetJ8( j8Ptr[5] ); - AND8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], ~8); - x86SetJ8( j8Ptr[6] ); - x86SetJ8( j8Ptr[7] ); - return; - - case GIF_MODE: - _eeMoveMMREGtoR(EAX, mmreg); - _eeWriteConstMem32((uptr)&PS2MEM_HW[mem&0xffff], mmreg); - - AND8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], ~5); - AND8ItoR(EAX, 5); - OR8RtoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], EAX); - break; - - case GIF_STAT: // stat is readonly - return; - - case 0x1000a000: // dma2 - gif - recDmaExec(dmaGIF, mem, mmreg); - break; - - case 0x1000e010: // DMAC_STAT - _eeMoveMMREGtoR(EAX, mmreg); - - iFlushCall(0); - MOV32RtoR(ECX, EAX); - SHR32ItoR(EAX, 16); - NOT32R(ECX); - XOR16RtoM((uptr)&PS2MEM_HW[0xe012], EAX); - AND16RtoM((uptr)&PS2MEM_HW[0xe010], ECX); - - CALLFunc((uptr)cpuTestDMACInts); - break; - - case 0x1000f590: // DMAC_ENABLEW - _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf520], mmreg); - _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf590], mmreg); - break; - - case 0x1000f000: // INTC_STAT - _eeWriteConstMem32OP((uptr)&PS2MEM_HW[mem&0xffff], mmreg, 2); - CALLFunc((uptr)cpuTestINTCInts); - break; - - case 0x1000f010: // INTC_MASK - - _eeMoveMMREGtoR(EAX, mmreg); - - iFlushCall(0); - XOR16RtoM((uptr)&PS2MEM_HW[0xf010], EAX); - CALLFunc((uptr)cpuTestINTCInts); - break; - - case 0x1000f130: - case 0x1000f410: - case 0x1000f430: - break; - default: - - _eeWriteConstMem64((uptr)PSM(mem), mmreg); - break; - } -} - -void hwConstWrite128(u32 mem, int mmreg) -{ - // fixme : This needs to be updated to use the new paged FIFO accessors. - - /*if (mem >= 0x10004000 && mem < 0x10008000) { - _eeWriteConstMem128((uptr)&s_TempFIFO[0], mmreg); - iFlushCall(0); - PUSH32I((uptr)&s_TempFIFO[0]); - PUSH32I(mem); - CALLFunc((uptr)WriteFIFO); - ADD32ItoR(ESP, 8); - return; - }*/ - - switch (mem) { - case 0x1000f590: // DMAC_ENABLEW - _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf520], mmreg); - _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf590], mmreg); - break; - case 0x1000f130: - case 0x1000f410: - case 0x1000f430: - break; - - default: - - _eeWriteConstMem128((uptr)&PS2MEM_HW[mem&0xffff], mmreg); - break; - } -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "iR5900.h" +#include "VUmicro.h" +#include "IopMem.h" + +// The full suite of hardware APIs: +#include "IPU/IPU.h" +#include "GS.h" +#include "Counters.h" +#include "Vif.h" +#include "VifDma.h" +#include "SPR.h" +#include "Sif.h" + + +extern int rdram_devices; // put 8 for TOOL and 2 for PS2 and PSX +extern int rdram_sdevid; +extern char sio_buffer[1024]; +extern int sio_count; + +int hwConstRead8(u32 x86reg, u32 mem, u32 sign) +{ + if( mem >= 0x10000000 && mem < 0x10008000 ) + DevCon::WriteLn("hwRead8 to %x", params mem); + + if ((mem & 0xffffff0f) == 0x1000f200) { + if(mem == 0x1000f260) { + MMXONLY(if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf); + else) + XOR32RtoR(x86reg, x86reg); + return 0; + } + else if(mem == 0x1000F240) { + + _eeReadConstMem8(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff], sign); + //psHu32(mem) &= ~0x4000; + return 0; + } + } + + if (mem < 0x10010000) + { + _eeReadConstMem8(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff], sign); + } + else { + MMXONLY(if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf); + else ) + XOR32RtoR(x86reg, x86reg); + } + + return 0; +} + +#define CONSTREAD16_CALL(name) { \ + iFlushCall(0); \ + CALLFunc((uptr)name); \ + if( sign ) MOVSX32R16toR(EAX, EAX); \ + else MOVZX32R16toR(EAX, EAX); \ +} \ + +static u32 s_regreads[3] = {0x010200000, 0xbfff0000, 0xF0000102}; +int hwConstRead16(u32 x86reg, u32 mem, u32 sign) +{ + if( mem >= 0x10002000 && mem < 0x10008000 ) + DevCon::WriteLn("hwRead16 to %x", params mem); + + if( mem >= 0x10000000 && mem < 0x10002000 ) + EECNT_LOG("cnt read to %x\n", params mem); + + switch (mem) { + case 0x10000000: + PUSH32I(0); + CONSTREAD16_CALL(rcntRcount); + ADD32ItoR(ESP, 4); + return 1; + case 0x10000010: + _eeReadConstMem16(x86reg, (uptr)&counters[0].mode, sign); + return 0; + case 0x10000020: + _eeReadConstMem16(x86reg, (uptr)&counters[0].mode, sign); + return 0; + case 0x10000030: + _eeReadConstMem16(x86reg, (uptr)&counters[0].hold, sign); + return 0; + + case 0x10000800: + PUSH32I(1); + CONSTREAD16_CALL(rcntRcount); + ADD32ItoR(ESP, 4); + return 1; + + case 0x10000810: + _eeReadConstMem16(x86reg, (uptr)&counters[1].mode, sign); + return 0; + + case 0x10000820: + _eeReadConstMem16(x86reg, (uptr)&counters[1].target, sign); + return 0; + + case 0x10000830: + _eeReadConstMem16(x86reg, (uptr)&counters[1].hold, sign); + return 0; + + case 0x10001000: + PUSH32I(2); + CONSTREAD16_CALL(rcntRcount); + ADD32ItoR(ESP, 4); + return 1; + + case 0x10001010: + _eeReadConstMem16(x86reg, (uptr)&counters[2].mode, sign); + return 0; + + case 0x10001020: + _eeReadConstMem16(x86reg, (uptr)&counters[2].target, sign); + return 0; + + case 0x10001800: + PUSH32I(3); + CONSTREAD16_CALL(rcntRcount); + ADD32ItoR(ESP, 4); + return 1; + + case 0x10001810: + _eeReadConstMem16(x86reg, (uptr)&counters[3].mode, sign); + return 0; + + case 0x10001820: + _eeReadConstMem16(x86reg, (uptr)&counters[3].target, sign); + return 0; + + default: + if ((mem & 0xffffff0f) == 0x1000f200) { + if(mem == 0x1000f260) { + MMXONLY(if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf); + else ) + XOR32RtoR(x86reg, x86reg); + return 0; + } + else if(mem == 0x1000F240) { + + MMXONLY(if( IS_MMXREG(x86reg) ) { + MOVDMtoMMX(x86reg&0xf, (uptr)&PS2MEM_HW[(mem) & 0xffff] - 2); + PORMtoR(x86reg&0xf, (uptr)&s_regreads[0]); + PANDMtoR(x86reg&0xf, (uptr)&s_regreads[1]); + } + else ) + { + if( sign ) MOVSX32M16toR(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff]); + else MOVZX32M16toR(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff]); + + OR32ItoR(x86reg, 0x0102); + AND32ItoR(x86reg, ~0x4000); + } + return 0; + } + } + if (mem < 0x10010000) { + _eeReadConstMem16(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff], sign); + } + else { + MMXONLY(if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf); + else ) + XOR32RtoR(x86reg, x86reg); + } + + return 0; + } +} + +int hwContRead32_f440() +{ + if ((psHu32(0xf430) >> 6) & 0xF) + return 0; + else + switch ((psHu32(0xf430)>>16) & 0xFFF){//MCH_RICM: x:4|SA:12|x:5|SDEV:1|SOP:4|SBC:1|SDEV:5 + case 0x21://INIT + { + int ret = 0x1F * (rdram_sdevid < rdram_devices); + rdram_sdevid += (rdram_sdevid < rdram_devices); + return ret; + } + case 0x23://CNFGA + return 0x0D0D; //PVER=3 | MVER=16 | DBL=1 | REFBIT=5 + case 0x24://CNFGB + //0x0110 for PSX SVER=0 | CORG=8(5x9x7) | SPT=1 | DEVTYP=0 | BYTE=0 + return 0x0090; //SVER=0 | CORG=4(5x9x6) | SPT=1 | DEVTYP=0 | BYTE=0 + case 0x40://DEVID + return psHu32(0xf430) & 0x1F; // =SDEV + } + + return 0; +} + +int hwConstRead32(u32 x86reg, u32 mem) +{ + //IPU regs + if ((mem>=0x10002000) && (mem<0x10003000)) { + //return ipuConstRead32(x86reg, mem); + iFlushCall(0); + PUSH32I( mem ); + CALLFunc( (uptr)ipuRead32 ); + } + + switch (mem) { + case 0x10000000: + iFlushCall(0); + PUSH32I(0); + CALLFunc((uptr)rcntRcount); + EECNT_LOG("Counter 0 count read = %x\n", rcntRcount(0)); + ADD32ItoR(ESP, 4); + return 1; + case 0x10000010: + _eeReadConstMem32(x86reg, (uptr)&counters[0].mode); + EECNT_LOG("Counter 0 mode read = %x\n", counters[0].modeval); + return 0; + case 0x10000020: + _eeReadConstMem32(x86reg, (uptr)&counters[0].target); + EECNT_LOG("Counter 0 target read = %x\n", counters[0].target); + return 0; + case 0x10000030: + _eeReadConstMem32(x86reg, (uptr)&counters[0].hold); + return 0; + + case 0x10000800: + iFlushCall(0); + PUSH32I(1); + CALLFunc((uptr)rcntRcount); + EECNT_LOG("Counter 1 count read = %x\n", rcntRcount(1)); + ADD32ItoR(ESP, 4); + return 1; + case 0x10000810: + _eeReadConstMem32(x86reg, (uptr)&counters[1].mode); + EECNT_LOG("Counter 1 mode read = %x\n", counters[1].modeval); + return 0; + case 0x10000820: + _eeReadConstMem32(x86reg, (uptr)&counters[1].target); + EECNT_LOG("Counter 1 target read = %x\n", counters[1].target); + return 0; + case 0x10000830: + _eeReadConstMem32(x86reg, (uptr)&counters[1].hold); + return 0; + + case 0x10001000: + iFlushCall(0); + PUSH32I(2); + CALLFunc((uptr)rcntRcount); + EECNT_LOG("Counter 2 count read = %x\n", rcntRcount(2)); + ADD32ItoR(ESP, 4); + return 1; + case 0x10001010: + _eeReadConstMem32(x86reg, (uptr)&counters[2].mode); + EECNT_LOG("Counter 2 mode read = %x\n", counters[2].modeval); + return 0; + case 0x10001020: + _eeReadConstMem32(x86reg, (uptr)&counters[2].target); + EECNT_LOG("Counter 2 target read = %x\n", counters[2].target); + return 0; + case 0x10001030: + // fixme: Counters[2].hold and Counters[3].hold are never assigned values + // anywhere in Pcsx2. + _eeReadConstMem32(x86reg, (uptr)&counters[2].hold); + return 0; + + case 0x10001800: + iFlushCall(0); + PUSH32I(3); + CALLFunc((uptr)rcntRcount); + EECNT_LOG("Counter 3 count read = %x\n", rcntRcount(3)); + ADD32ItoR(ESP, 4); + return 1; + case 0x10001810: + _eeReadConstMem32(x86reg, (uptr)&counters[3].mode); + EECNT_LOG("Counter 3 mode read = %x\n", counters[3].modeval); + return 0; + case 0x10001820: + _eeReadConstMem32(x86reg, (uptr)&counters[3].target); + EECNT_LOG("Counter 3 target read = %x\n", counters[3].target); + return 0; + case 0x10001830: + // fixme: Counters[2].hold and Counters[3].hold are never assigned values + // anywhere in Pcsx2. + _eeReadConstMem32(x86reg, (uptr)&counters[3].hold); + return 0; + + case 0x1000f130: + case 0x1000f410: + case 0x1000f430: + if( IS_XMMREG(x86reg) ) SSEX_PXOR_XMM_to_XMM(x86reg&0xf, x86reg&0xf); + MMXONLY(else if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf);) + else XOR32RtoR(x86reg, x86reg); + return 0; + + case 0x1000f440: + iFlushCall(0); + CALLFunc((uptr)hwContRead32_f440); + return 1; + + case 0x1000f520: // DMAC_ENABLER + _eeReadConstMem32(x86reg, (uptr)&PS2MEM_HW[0xf590]); + return 0; + + default: + if ((mem & 0xffffff0f) == 0x1000f200) { + if(mem == 0x1000f260) { + if( IS_XMMREG(x86reg) ) SSEX_PXOR_XMM_to_XMM(x86reg&0xf, x86reg&0xf); + MMXONLY(else if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf);) + else XOR32RtoR(x86reg, x86reg); + return 0; + } + else if(mem == 0x1000F240) { + + if( IS_XMMREG(x86reg) ) { + SSEX_MOVD_M32_to_XMM(x86reg&0xf, (uptr)&PS2MEM_HW[(mem) & 0xffff]); + SSEX_POR_M128_to_XMM(x86reg&0xf, (uptr)&s_regreads[2]); + } + MMXONLY(else if( IS_MMXREG(x86reg) ) { + MOVDMtoMMX(x86reg&0xf, (uptr)&PS2MEM_HW[(mem) & 0xffff]); + PORMtoR(x86reg&0xf, (uptr)&s_regreads[2]); + }) + else { + MOV32MtoR(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff]); + OR32ItoR(x86reg, 0xF0000102); + } + return 0; + } + } + + if (mem < 0x10010000) { + _eeReadConstMem32(x86reg, (uptr)&PS2MEM_HW[(mem) & 0xffff]); + } + else { + if( IS_XMMREG(x86reg) ) SSEX_PXOR_XMM_to_XMM(x86reg&0xf, x86reg&0xf); + MMXONLY(else if( IS_MMXREG(x86reg) ) PXORRtoR(x86reg&0xf, x86reg&0xf);) + else XOR32RtoR(x86reg, x86reg); + } + + return 0; + } +} + +void hwConstRead64(u32 mem, int mmreg) { + if ((mem>=0x10002000) && (mem<0x10003000)) { + ipuConstRead64(mem, mmreg); + return; + } + + if( IS_XMMREG(mmreg) ) SSE_MOVLPS_M64_to_XMM(mmreg&0xff, (uptr)PSM(mem)); + else { + MMXONLY(MOVQMtoR(mmreg, (uptr)PSM(mem)); + SetMMXstate();) + } +} + +PCSX2_ALIGNED16(u32 s_TempFIFO[4]); +void hwConstRead128(u32 mem, int xmmreg) { + + // fixme : This needs to be updated to use the new paged FIFO accessors. + /*if (mem >= 0x10004000 && mem < 0x10008000) { + iFlushCall(0); + PUSH32I((uptr)&s_TempFIFO[0]); + PUSH32I(mem); + CALLFunc((uptr)ReadFIFO); + ADD32ItoR(ESP, 8); + _eeReadConstMem128( xmmreg, (uptr)&s_TempFIFO[0]); + return; + }*/ + + _eeReadConstMem128( xmmreg, (uptr)PSM(mem)); +} + +// when writing imm +static void recDmaExecI8(void (*name)(), u32 mem, int mmreg) +{ + MOV8ItoM((uptr)&PS2MEM_HW[(mem) & 0xffff], g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]); + if( g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 1 ) { + TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1); + j8Ptr[6] = JZ8(0); + CALLFunc((uptr)name); + x86SetJ8( j8Ptr[6] ); + } +} + +static void recDmaExec8(void (*name)(), u32 mem, int mmreg) +{ + // Flushcall Note : DMA transfers are almost always "involved" operations + // that use memcpys and/or threading. Freeing all XMM and MMX regs is the + // best option. + + iFlushCall(FLUSH_NOCONST); + if( IS_EECONSTREG(mmreg) ) { + recDmaExecI8(name, mem, mmreg); + } + else { + _eeMoveMMREGtoR(EAX, mmreg); + _eeWriteConstMem8((uptr)&PS2MEM_HW[(mem) & 0xffff], mmreg); + + TEST8ItoR(EAX, 1); + j8Ptr[5] = JZ8(0); + TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1); + j8Ptr[6] = JZ8(0); + + CALLFunc((uptr)name); + + x86SetJ8( j8Ptr[5] ); + x86SetJ8( j8Ptr[6] ); + } +} + +static void __fastcall PrintDebug(u8 value) +{ + // Note: This is where the EE's diagonstic messages originate from (like the ones that + // start with hash # marks) + + if (value == '\n') { + sio_buffer[sio_count] = 0; + Console::WriteLn( Color_Cyan, sio_buffer ); + sio_count = 0; + } else { + if (sio_count < 1023) { + sio_buffer[sio_count++] = value; + } + } +} + +// fixme: this would be more optimal as a C++ template (with bit as the template parameter) +template< uint bit > +static void ConstWrite_ExecTimer( uptr func, u8 index, int mmreg) +{ + if( bit != 32 ) + { + if( !IS_EECONSTREG(mmreg) ) + { + if( bit == 8 ) MOVZX32R8toR(mmreg&0xf, mmreg&0xf); + else if( bit == 16 ) MOVZX32R16toR(mmreg&0xf, mmreg&0xf); + } + } + + // FlushCall Note : All counter functions are short and sweet, full flush not needed. + + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(index); + CALLFunc(func); + ADD32ItoR(ESP, 8); +} + +#define CONSTWRITE_TIMERS(bit) \ + case 0x10000000: ConstWrite_ExecTimer((uptr)&rcntWcount, 0, mmreg); break; \ + case 0x10000010: ConstWrite_ExecTimer((uptr)&rcntWmode, 0, mmreg); break; \ + case 0x10000020: ConstWrite_ExecTimer((uptr)&rcntWtarget, 0, mmreg); break; \ + case 0x10000030: ConstWrite_ExecTimer((uptr)&rcntWhold, 0, mmreg); break; \ + \ + case 0x10000800: ConstWrite_ExecTimer((uptr)&rcntWcount, 1, mmreg); break; \ + case 0x10000810: ConstWrite_ExecTimer((uptr)&rcntWmode, 1, mmreg); break; \ + case 0x10000820: ConstWrite_ExecTimer((uptr)&rcntWtarget, 1, mmreg); break; \ + case 0x10000830: ConstWrite_ExecTimer((uptr)&rcntWhold, 1, mmreg); break; \ + \ + case 0x10001000: ConstWrite_ExecTimer((uptr)&rcntWcount, 2, mmreg); break; \ + case 0x10001010: ConstWrite_ExecTimer((uptr)&rcntWmode, 2, mmreg); break; \ + case 0x10001020: ConstWrite_ExecTimer((uptr)&rcntWtarget, 2, mmreg); break; \ + \ + case 0x10001800: ConstWrite_ExecTimer((uptr)&rcntWcount, 3, mmreg); break; \ + case 0x10001810: ConstWrite_ExecTimer((uptr)&rcntWmode, 3, mmreg); break; \ + case 0x10001820: ConstWrite_ExecTimer((uptr)&rcntWtarget, 3, mmreg); break; \ + +void hwConstWrite8(u32 mem, int mmreg) +{ + switch (mem) { + CONSTWRITE_TIMERS(8) + + case 0x1000f180: + // Yay fastcall! + _eeMoveMMREGtoR( ECX, mmreg ); + iFlushCall(0); + CALLFunc((uptr)PrintDebug); + break; + + case 0x10008001: // dma0 - vif0 + recDmaExec8(dmaVIF0, mem, mmreg); + break; + + case 0x10009001: // dma1 - vif1 + recDmaExec8(dmaVIF1, mem, mmreg); + break; + + case 0x1000a001: // dma2 - gif + recDmaExec8(dmaGIF, mem, mmreg); + break; + + case 0x1000b001: // dma3 - fromIPU + recDmaExec8(dmaIPU0, mem, mmreg); + break; + + case 0x1000b401: // dma4 - toIPU + recDmaExec8(dmaIPU1, mem, mmreg); + break; + + case 0x1000c001: // dma5 - sif0 + //if (value == 0) psxSu32(0x30) = 0x40000; + recDmaExec8(dmaSIF0, mem, mmreg); + break; + + case 0x1000c401: // dma6 - sif1 + recDmaExec8(dmaSIF1, mem, mmreg); + break; + + case 0x1000c801: // dma7 - sif2 + recDmaExec8(dmaSIF2, mem, mmreg); + break; + + case 0x1000d001: // dma8 - fromSPR + recDmaExec8(dmaSPR0, mem, mmreg); + break; + + case 0x1000d401: // dma9 - toSPR + recDmaExec8(dmaSPR1, mem, mmreg); + break; + + case 0x1000f592: // DMAC_ENABLEW + _eeWriteConstMem8( (uptr)&PS2MEM_HW[0xf522], mmreg ); + _eeWriteConstMem8( (uptr)&PS2MEM_HW[0xf592], mmreg ); + break; + + default: + if ((mem & 0xffffff0f) == 0x1000f200) { + u32 at = mem & 0xf0; + switch(at) + { + case 0x00: + _eeWriteConstMem8( (uptr)&PS2MEM_HW[mem&0xffff], mmreg); + break; + case 0x40: + if( IS_EECONSTREG(mmreg) ) { + if( !(g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 0x100) ) { + AND32ItoM( (uptr)&PS2MEM_HW[mem&0xfffc], ~0x100); + } + } + else { + _eeMoveMMREGtoR(EAX, mmreg); + TEST16ItoR(EAX, 0x100); + j8Ptr[5] = JNZ8(0); + AND32ItoM( (uptr)&PS2MEM_HW[mem&0xfffc], ~0x100); + x86SetJ8(j8Ptr[5]); + } + break; + } + return; + } + assert( (mem&0xff0f) != 0xf200 ); + + switch(mem&~3) { + case 0x1000f130: + case 0x1000f410: + case 0x1000f430: + break; + default: + _eeWriteConstMem8((uptr)&PS2MEM_HW[mem&0xffff], mmreg); + } + + break; + } +} + +// Flushcall Note : DMA transfers are almost always "involved" operations +// that use memcpys and/or threading. Freeing all XMM and MMX regs is the +// best option (removes the need for FreezeXMMRegs()). But register +// allocation is such a mess right now that we can't do it (yet). + +static void recDmaExecI16( void (*name)(), u32 mem, int mmreg ) +{ + MOV16ItoM((uptr)&PS2MEM_HW[(mem) & 0xffff], g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]); + if( g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 0x100 ) { + TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1); + j8Ptr[6] = JZ8(0); + CALLFunc((uptr)name); + x86SetJ8( j8Ptr[6] ); + } +} + +static void recDmaExec16(void (*name)(), u32 mem, int mmreg) +{ + iFlushCall(0); + + if( IS_EECONSTREG(mmreg) ) { + recDmaExecI16(name, mem, mmreg); + } + else { + _eeMoveMMREGtoR(EAX, mmreg); + _eeWriteConstMem16((uptr)&PS2MEM_HW[(mem) & 0xffff], mmreg); + + TEST16ItoR(EAX, 0x100); + j8Ptr[5] = JZ8(0); + TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1); + j8Ptr[6] = JZ8(0); + + CALLFunc((uptr)name); + + x86SetJ8( j8Ptr[5] ); + x86SetJ8( j8Ptr[6] ); + } +} + +void hwConstWrite16(u32 mem, int mmreg) +{ + switch(mem) { + + CONSTWRITE_TIMERS(16) + + case 0x10008000: // dma0 - vif0 + recDmaExec16(dmaVIF0, mem, mmreg); + break; + + case 0x10009000: // dma1 - vif1 - chcr + recDmaExec16(dmaVIF1, mem, mmreg); + break; + + case 0x1000a000: // dma2 - gif + recDmaExec16(dmaGIF, mem, mmreg); + break; + case 0x1000b000: // dma3 - fromIPU + recDmaExec16(dmaIPU0, mem, mmreg); + break; + case 0x1000b400: // dma4 - toIPU + recDmaExec16(dmaIPU1, mem, mmreg); + break; + case 0x1000c000: // dma5 - sif0 + //if (value == 0) psxSu32(0x30) = 0x40000; + recDmaExec16(dmaSIF0, mem, mmreg); + break; + case 0x1000c002: + //? + break; + case 0x1000c400: // dma6 - sif1 + recDmaExec16(dmaSIF1, mem, mmreg); + break; + case 0x1000c800: // dma7 - sif2 + recDmaExec16(dmaSIF2, mem, mmreg); + break; + case 0x1000c802: + //? + break; + case 0x1000d000: // dma8 - fromSPR + recDmaExec16(dmaSPR0, mem, mmreg); + break; + case 0x1000d400: // dma9 - toSPR + recDmaExec16(dmaSPR1, mem, mmreg); + break; + case 0x1000f592: // DMAC_ENABLEW + _eeWriteConstMem16((uptr)&PS2MEM_HW[0xf522], mmreg); + _eeWriteConstMem16((uptr)&PS2MEM_HW[0xf592], mmreg); + break; + case 0x1000f130: + case 0x1000f410: + case 0x1000f430: + break; + default: + if ((mem & 0xffffff0f) == 0x1000f200) { + u32 at = mem & 0xf0; + switch(at) + { + case 0x00: + _eeWriteConstMem16((uptr)&PS2MEM_HW[mem&0xffff], mmreg); + break; + case 0x20: + _eeWriteConstMem16OP((uptr)&PS2MEM_HW[mem&0xffff], mmreg, 1); + break; + case 0x30: + if( IS_EECONSTREG(mmreg) ) { + AND16ItoM((uptr)&PS2MEM_HW[mem&0xffff], ~g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]); + } + else { + NOT32R(mmreg&0xf); + AND16RtoM((uptr)&PS2MEM_HW[mem&0xffff], mmreg&0xf); + } + break; + case 0x40: + if( IS_EECONSTREG(mmreg) ) { + if( !(g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 0x100) ) { + AND16ItoM((uptr)&PS2MEM_HW[mem&0xffff], ~0x100); + } + else { + OR16ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0x100); + } + } + else { + _eeMoveMMREGtoR(EAX, mmreg); + TEST16ItoR(EAX, 0x100); + j8Ptr[5] = JZ8(0); + OR16ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0x100); + j8Ptr[6] = JMP8(0); + + x86SetJ8( j8Ptr[5] ); + AND16ItoM((uptr)&PS2MEM_HW[mem&0xffff], ~0x100); + + x86SetJ8( j8Ptr[6] ); + } + + break; + case 0x60: + _eeWriteConstMem16((uptr)&PS2MEM_HW[mem&0xffff], 0); + break; + } + return; + } + + _eeWriteConstMem16((uptr)&PS2MEM_HW[mem&0xffff], mmreg); + } +} + +// when writing an Imm + +static void recDmaExecI( void (*name)(), u32 mem, int mmreg ) +{ + u32 c = g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]; + /* Keep the old tag if in chain mode and hw doesnt set it*/ + if( (c & 0xc) == 0x4 && (c&0xffff0000) == 0 ) { + MOV16ItoM((uptr)&PS2MEM_HW[(mem) & 0xffff], c); + } + else MOV32ItoM((uptr)&PS2MEM_HW[(mem) & 0xffff], c); + if( c & 0x100 ) { + TEST8ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1); + j8Ptr[6] = JZ8(0); + CALLFunc((uptr)name); + x86SetJ8( j8Ptr[6] ); + } +} + +static void recDmaExec( void (*name)(), u32 mem, int mmreg ) +{ + + iFlushCall(0); + + if( IS_EECONSTREG(mmreg) ) { + recDmaExecI(name, mem, mmreg); + } + else { + + // fixme: This is a lot of code to be injecting into the recompiler + // for every DMA transfer. It might actually be more efficient to + // set this up as a C function call instead (depends on how often + // the register is written without actually starting a DMA xfer). + + _eeMoveMMREGtoR(EAX, mmreg); + TEST32ItoR(EAX, 0xffff0000); + j8Ptr[6] = JNZ8(0); + MOV32RtoR(ECX, EAX); + AND32ItoR(ECX, 0xc); + CMP32ItoR(ECX, 4); + j8Ptr[7] = JNE8(0); + if( IS_XMMREG(mmreg) || IS_MMXREG(mmreg) ) { + MOV16RtoM((uptr)&PS2MEM_HW[(mem) & 0xffff], EAX); + } + else { + _eeWriteConstMem16((uptr)&PS2MEM_HW[(mem) & 0xffff], mmreg); + } + j8Ptr[8] = JMP8(0); + x86SetJ8(j8Ptr[6]); + x86SetJ8(j8Ptr[7]); + _eeWriteConstMem32((uptr)&PS2MEM_HW[(mem) & 0xffff], mmreg); + x86SetJ8(j8Ptr[8]); + + TEST16ItoR(EAX, 0x100); + j8Ptr[5] = JZ8(0); + TEST32ItoM((uptr)&PS2MEM_HW[DMAC_CTRL&0xffff], 1); + j8Ptr[6] = JZ8(0); + + CALLFunc((uptr)name); + x86SetJ8( j8Ptr[5] ); + x86SetJ8( j8Ptr[6] ); + } +} + + +void hwConstWrite32(u32 mem, int mmreg) +{ + //IPU regs + if ((mem>=0x10002000) && (mem<0x10003000)) { + //psHu32(mem) = value; + ipuConstWrite32(mem, mmreg); + return; + } + + if ((mem>=0x10003800) && (mem<0x10003c00)) { + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(mem); + CALLFunc((uptr)vif0Write32); + ADD32ItoR(ESP, 8); + return; + } + if ((mem>=0x10003c00) && (mem<0x10004000)) { + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(mem); + CALLFunc((uptr)vif1Write32); + ADD32ItoR(ESP, 8); + return; + } + + switch (mem) { + + CONSTWRITE_TIMERS(32) + + case GIF_CTRL: + + _eeMoveMMREGtoR(EAX, mmreg); + + iFlushCall(0); + TEST8ItoR(EAX, 1); + j8Ptr[5] = JZ8(0); + + // reset GS + CALLFunc((uptr)gsGIFReset); + j8Ptr[6] = JMP8(0); + + x86SetJ8( j8Ptr[5] ); + AND32I8toR(EAX, 8); + MOV32RtoM((uptr)&PS2MEM_HW[mem&0xffff], EAX); + + TEST16ItoR(EAX, 8); + j8Ptr[5] = JZ8(0); + OR8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], 8); + j8Ptr[7] = JMP8(0); + + x86SetJ8( j8Ptr[5] ); + AND8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], ~8); + x86SetJ8( j8Ptr[6] ); + x86SetJ8( j8Ptr[7] ); + return; + + case GIF_MODE: + _eeMoveMMREGtoR(EAX, mmreg); + _eeWriteConstMem32((uptr)&PS2MEM_HW[mem&0xffff], mmreg); + AND8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], ~5); + AND8ItoR(EAX, 5); + OR8RtoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], EAX); + return; + + case GIF_STAT: // stat is readonly + return; + + case 0x10008000: // dma0 - vif0 + recDmaExec(dmaVIF0, mem, mmreg); + break; + + case 0x10009000: // dma1 - vif1 - chcr + recDmaExec(dmaVIF1, mem, mmreg); + break; + + case 0x1000a000: // dma2 - gif + recDmaExec(dmaGIF, mem, mmreg); + break; + + case 0x1000b000: // dma3 - fromIPU + recDmaExec(dmaIPU0, mem, mmreg); + break; + case 0x1000b400: // dma4 - toIPU + recDmaExec(dmaIPU1, mem, mmreg); + break; + case 0x1000c000: // dma5 - sif0 + //if (value == 0) psxSu32(0x30) = 0x40000; + recDmaExec(dmaSIF0, mem, mmreg); + break; + + case 0x1000c400: // dma6 - sif1 + recDmaExec(dmaSIF1, mem, mmreg); + break; + + case 0x1000c800: // dma7 - sif2 + recDmaExec(dmaSIF2, mem, mmreg); + break; + + case 0x1000d000: // dma8 - fromSPR + recDmaExec(dmaSPR0, mem, mmreg); + break; + + case 0x1000d400: // dma9 - toSPR + recDmaExec(dmaSPR1, mem, mmreg); + break; + + case 0x1000e010: // DMAC_STAT + _eeMoveMMREGtoR(EAX, mmreg); + iFlushCall(0); + MOV32RtoR(ECX, EAX); + SHR32ItoR(EAX, 16); + NOT32R(ECX); + XOR16RtoM((uptr)&PS2MEM_HW[0xe012], EAX); + AND16RtoM((uptr)&PS2MEM_HW[0xe010], ECX); + + CALLFunc((uptr)cpuTestDMACInts); + break; + + case 0x1000f000: // INTC_STAT + _eeWriteConstMem32OP((uptr)&PS2MEM_HW[0xf000], mmreg, 2); + CALLFunc((uptr)cpuTestINTCInts); + break; + + case 0x1000f010: // INTC_MASK + _eeMoveMMREGtoR(EAX, mmreg); + iFlushCall(0); + XOR16RtoM((uptr)&PS2MEM_HW[0xf010], EAX); + CALLFunc((uptr)cpuTestINTCInts); + break; + + case 0x1000f130: + case 0x1000f410: + break; + + case 0x1000f430://MCH_RICM: x:4|SA:12|x:5|SDEV:1|SOP:4|SBC:1|SDEV:5 + + //if ((((value >> 16) & 0xFFF) == 0x21) && (((value >> 6) & 0xF) == 1) && (((psHu32(0xf440) >> 7) & 1) == 0))//INIT & SRP=0 + // rdram_sdevid = 0 + _eeMoveMMREGtoR(EAX, mmreg); + MOV32RtoR(EDX, EAX); + MOV32RtoR(ECX, EAX); + SHR32ItoR(EAX, 6); + SHR32ItoR(EDX, 16); + AND32ItoR(EAX, 0xf); + AND32ItoR(EDX, 0xfff); + CMP32ItoR(EAX, 1); + j8Ptr[5] = JNE8(0); + CMP32ItoR(EDX, 0x21); + j8Ptr[6] = JNE8(0); + + TEST32ItoM((uptr)&psHu32(0xf440), 0x80); + j8Ptr[7] = JNZ8(0); + + // if SIO repeater is cleared, reset sdevid + MOV32ItoM((uptr)&rdram_sdevid, 0); + + //kill the busy bit + x86SetJ8(j8Ptr[5]); + x86SetJ8(j8Ptr[6]); + x86SetJ8(j8Ptr[7]); + AND32ItoR(ECX, ~0x80000000); + MOV32RtoM((uptr)&psHu32(0xf430), ECX); + break; + + case 0x1000f440://MCH_DRD: + _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf440], mmreg); + break; + + case 0x1000f590: // DMAC_ENABLEW + _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf520], mmreg); + _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf590], mmreg); + return; + + default: + if ((mem & 0xffffff0f) == 0x1000f200) { + u32 at = mem & 0xf0; + switch(at) + { + case 0x00: + _eeWriteConstMem32((uptr)&PS2MEM_HW[mem&0xffff], mmreg); + break; + case 0x20: + _eeWriteConstMem32OP((uptr)&PS2MEM_HW[mem&0xffff], mmreg, 1); + break; + case 0x30: + _eeWriteConstMem32OP((uptr)&PS2MEM_HW[mem&0xffff], mmreg, 2); + break; + case 0x40: + if( IS_EECONSTREG(mmreg) ) { + if( !(g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0] & 0x100) ) { + AND32ItoM( (uptr)&PS2MEM_HW[mem&0xfffc], ~0x100); + } + else { + OR32ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0x100); + } + } + else { + _eeMoveMMREGtoR(EAX, mmreg); + TEST32ItoR(EAX, 0x100); + j8Ptr[5] = JZ8(0); + OR32ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0x100); + j8Ptr[6] = JMP8(0); + + x86SetJ8( j8Ptr[5] ); + AND32ItoM((uptr)&PS2MEM_HW[mem&0xffff], ~0x100); + + x86SetJ8( j8Ptr[6] ); + } + + break; + case 0x60: + MOV32ItoM((uptr)&PS2MEM_HW[mem&0xffff], 0); + break; + } + return; + } + + _eeWriteConstMem32((uptr)&PS2MEM_HW[mem&0xffff], mmreg); + break; + } +} + +void hwConstWrite64(u32 mem, int mmreg) +{ + if ((mem>=0x10002000) && (mem<=0x10002030)) { + ipuConstWrite64(mem, mmreg); + return; + } + + if ((mem>=0x10003800) && (mem<0x10003c00)) { + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(mem); + CALLFunc((uptr)vif0Write32); + ADD32ItoR(ESP, 8); + return; + } + if ((mem>=0x10003c00) && (mem<0x10004000)) { + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(mem); + CALLFunc((uptr)vif1Write32); + ADD32ItoR(ESP, 8); + return; + } + + switch (mem) { + case GIF_CTRL: + _eeMoveMMREGtoR(EAX, mmreg); + + iFlushCall(0); + TEST8ItoR(EAX, 1); + j8Ptr[5] = JZ8(0); + + // reset GS + CALLFunc((uptr)gsGIFReset); + j8Ptr[6] = JMP8(0); + + x86SetJ8( j8Ptr[5] ); + AND32I8toR(EAX, 8); + MOV32RtoM((uptr)&PS2MEM_HW[mem&0xffff], EAX); + + TEST16ItoR(EAX, 8); + j8Ptr[5] = JZ8(0); + OR8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], 8); + j8Ptr[7] = JMP8(0); + + x86SetJ8( j8Ptr[5] ); + AND8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], ~8); + x86SetJ8( j8Ptr[6] ); + x86SetJ8( j8Ptr[7] ); + return; + + case GIF_MODE: + _eeMoveMMREGtoR(EAX, mmreg); + _eeWriteConstMem32((uptr)&PS2MEM_HW[mem&0xffff], mmreg); + + AND8ItoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], ~5); + AND8ItoR(EAX, 5); + OR8RtoM((uptr)&PS2MEM_HW[GIF_STAT&0xffff], EAX); + break; + + case GIF_STAT: // stat is readonly + return; + + case 0x1000a000: // dma2 - gif + recDmaExec(dmaGIF, mem, mmreg); + break; + + case 0x1000e010: // DMAC_STAT + _eeMoveMMREGtoR(EAX, mmreg); + + iFlushCall(0); + MOV32RtoR(ECX, EAX); + SHR32ItoR(EAX, 16); + NOT32R(ECX); + XOR16RtoM((uptr)&PS2MEM_HW[0xe012], EAX); + AND16RtoM((uptr)&PS2MEM_HW[0xe010], ECX); + + CALLFunc((uptr)cpuTestDMACInts); + break; + + case 0x1000f590: // DMAC_ENABLEW + _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf520], mmreg); + _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf590], mmreg); + break; + + case 0x1000f000: // INTC_STAT + _eeWriteConstMem32OP((uptr)&PS2MEM_HW[mem&0xffff], mmreg, 2); + CALLFunc((uptr)cpuTestINTCInts); + break; + + case 0x1000f010: // INTC_MASK + + _eeMoveMMREGtoR(EAX, mmreg); + + iFlushCall(0); + XOR16RtoM((uptr)&PS2MEM_HW[0xf010], EAX); + CALLFunc((uptr)cpuTestINTCInts); + break; + + case 0x1000f130: + case 0x1000f410: + case 0x1000f430: + break; + default: + + _eeWriteConstMem64((uptr)PSM(mem), mmreg); + break; + } +} + +void hwConstWrite128(u32 mem, int mmreg) +{ + // fixme : This needs to be updated to use the new paged FIFO accessors. + + /*if (mem >= 0x10004000 && mem < 0x10008000) { + _eeWriteConstMem128((uptr)&s_TempFIFO[0], mmreg); + iFlushCall(0); + PUSH32I((uptr)&s_TempFIFO[0]); + PUSH32I(mem); + CALLFunc((uptr)WriteFIFO); + ADD32ItoR(ESP, 8); + return; + }*/ + + switch (mem) { + case 0x1000f590: // DMAC_ENABLEW + _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf520], mmreg); + _eeWriteConstMem32((uptr)&PS2MEM_HW[0xf590], mmreg); + break; + case 0x1000f130: + case 0x1000f410: + case 0x1000f430: + break; + + default: + + _eeWriteConstMem128((uptr)&PS2MEM_HW[mem&0xffff], mmreg); + break; + } +} diff --git a/pcsx2/x86/iIPU.cpp b/pcsx2/x86/iIPU.cpp index 75bca3c25b..e1f1d429fc 100644 --- a/pcsx2/x86/iIPU.cpp +++ b/pcsx2/x86/iIPU.cpp @@ -1,203 +1,203 @@ -/* Pcsx2 - Pc Ps2 Emulator -* Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "iR5900.h" - -#include "IPU.h" - -/////////////////////////////////////////////////////////////////////// -// IPU Register Reads - -int ipuConstRead32(u32 x86reg, u32 mem) -{ - int workingreg, tempreg, tempreg2; - iFlushCall(0); - CALLFunc((u32)IPUProcessInterrupt); - - // if( !(x86reg&(MEM_XMMTAG|MEM_MMXTAG)) ) { - // if( x86reg == EAX ) { - // tempreg = ECX; - // tempreg2 = EDX; - // } - // else if( x86reg == ECX ) { - // tempreg = EAX; - // tempreg2 = EDX; - // } - // else if( x86reg == EDX ) { - // tempreg = EAX; - // tempreg2 = ECX; - // } - // - // workingreg = x86reg; - // } - // else { - workingreg = EAX; - tempreg = ECX; - tempreg2 = EDX; - // } - - switch (mem){ - - case 0x10002010: // IPU_CTRL - - MOV32MtoR(workingreg, (u32)&ipuRegs->ctrl._u32); - AND32ItoR(workingreg, ~0x3f0f); // save OFC - OR8MtoR(workingreg, (u32)&g_BP.IFC); - OR8MtoR(workingreg+4, (u32)&coded_block_pattern); // or ah, mem - - // MOV32MtoR(workingreg, (u32)&ipuRegs->ctrl._u32); - // AND32ItoR(workingreg, ~0x3fff); - // MOV32MtoR(tempreg, (u32)&g_nIPU0Data); - // MOV8MtoR(workingreg, (u32)&g_BP.IFC); - // - // CMP32ItoR(tempreg, 8); - // j8Ptr[5] = JLE8(0); - // MOV32ItoR(tempreg, 8); - // x86SetJ8( j8Ptr[5] ); - // SHL32ItoR(tempreg, 4); - // - // OR8MtoR(workingreg+4, (u32)&coded_block_pattern); // or ah, mem - // OR8RtoR(workingreg, tempreg); - -#ifdef _DEBUG - MOV32RtoM((u32)&ipuRegs->ctrl._u32, workingreg); -#endif - // NOTE: not updating ipuRegs->ctrl - // if( x86reg & MEM_XMMTAG ) SSE2_MOVD_R_to_XMM(x86reg&0xf, workingreg); - // else if( x86reg & MEM_MMXTAG ) MOVD32RtoMMX(x86reg&0xf, workingreg); - return 1; - - case 0x10002020: // IPU_BP - - assert( (u32)&g_BP.FP + 1 == (u32)&g_BP.bufferhasnew ); - - MOVZX32M8toR(workingreg, (u32)&g_BP.BP); - MOVZX32M8toR(tempreg, (u32)&g_BP.FP); - AND8ItoR(workingreg, 0x7f); - ADD8MtoR(tempreg, (u32)&g_BP.bufferhasnew); - MOV8MtoR(workingreg+4, (u32)&g_BP.IFC); - - SHL32ItoR(tempreg, 16); - OR32RtoR(workingreg, tempreg); - -#ifdef _DEBUG - MOV32RtoM((u32)&ipuRegs->ipubp, workingreg); -#endif - // NOTE: not updating ipuRegs->ipubp - // if( x86reg & MEM_XMMTAG ) SSE2_MOVD_R_to_XMM(x86reg&0xf, workingreg); - // else if( x86reg & MEM_MMXTAG ) MOVD32RtoMMX(x86reg&0xf, workingreg); - - return 1; - - default: - // ipu repeats every 0x100 - _eeReadConstMem32(x86reg, (u32)(((u8*)ipuRegs)+(mem&0xff))); - return 0; - } - - return 0; -} - -void ipuConstRead64(u32 mem, int mmreg) -{ - iFlushCall(0); - CALLFunc((u32)IPUProcessInterrupt); - - if( IS_XMMREG(mmreg) ) SSE_MOVLPS_M64_to_XMM(mmreg&0xff, (u32)(((u8*)ipuRegs)+(mem&0xff))); - else { - MOVQMtoR(mmreg, (u32)(((u8*)ipuRegs)+(mem&0xff))); - SetMMXstate(); - } -} - -/////////////////////////////////////////////////////////////////////// -// IPU Register Writes! - -void ipuConstWrite32(u32 mem, int mmreg) -{ - iFlushCall(0); - if( !(mmreg & (MEM_XMMTAG|MEM_MMXTAG|MEM_EECONSTTAG)) ) PUSH32R(mmreg); - CALLFunc((u32)IPUProcessInterrupt); - - switch (mem){ - case 0x10002000: // IPU_CMD - if( (mmreg & (MEM_XMMTAG|MEM_MMXTAG|MEM_EECONSTTAG)) ) _recPushReg(mmreg); - CALLFunc((u32)IPUCMD_WRITE); - ADD32ItoR(ESP, 4); - break; - case 0x10002010: // IPU_CTRL - if( mmreg & MEM_EECONSTTAG ) { - u32 c = g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]&0x47f30000; - - if( c & 0x40000000 ) { - CALLFunc((u32)ipuSoftReset); - } - else { - AND32ItoM((u32)&ipuRegs->ctrl._u32, 0x8000ffff); - OR32ItoM((u32)&ipuRegs->ctrl._u32, c); - } - } - else { - if( mmreg & MEM_XMMTAG ) SSE2_MOVD_XMM_to_R(EAX, mmreg&0xf); - else if( mmreg & MEM_MMXTAG ) MOVD32MMXtoR(EAX, mmreg&0xf); - else POP32R(EAX); - - MOV32MtoR(ECX, (u32)&ipuRegs->ctrl._u32); - AND32ItoR(EAX, 0x47f30000); - AND32ItoR(ECX, 0x8000ffff); - OR32RtoR(EAX, ECX); - MOV32RtoM((u32)&ipuRegs->ctrl._u32, EAX); - - TEST32ItoR(EAX, 0x40000000); - j8Ptr[5] = JZ8(0); - - // reset - CALLFunc((u32)ipuSoftReset); - - x86SetJ8( j8Ptr[5] ); - } - - break; - default: - if( !(mmreg & (MEM_XMMTAG|MEM_MMXTAG|MEM_EECONSTTAG)) ) POP32R(mmreg); - _eeWriteConstMem32((u32)((u8*)ipuRegs + (mem&0xfff)), mmreg); - break; - } -} - -void ipuConstWrite64(u32 mem, int mmreg) -{ - iFlushCall(0); - CALLFunc((u32)IPUProcessInterrupt); - - switch (mem){ - case 0x10002000: - _recPushReg(mmreg); - CALLFunc((u32)IPUCMD_WRITE); - ADD32ItoR(ESP, 4); - break; - - default: - _eeWriteConstMem64( (u32)((u8*)ipuRegs + (mem&0xfff)), mmreg); - break; - } -} +/* Pcsx2 - Pc Ps2 Emulator +* Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "iR5900.h" + +#include "IPU.h" + +/////////////////////////////////////////////////////////////////////// +// IPU Register Reads + +int ipuConstRead32(u32 x86reg, u32 mem) +{ + int workingreg, tempreg, tempreg2; + iFlushCall(0); + CALLFunc((u32)IPUProcessInterrupt); + + // if( !(x86reg&(MEM_XMMTAG|MEM_MMXTAG)) ) { + // if( x86reg == EAX ) { + // tempreg = ECX; + // tempreg2 = EDX; + // } + // else if( x86reg == ECX ) { + // tempreg = EAX; + // tempreg2 = EDX; + // } + // else if( x86reg == EDX ) { + // tempreg = EAX; + // tempreg2 = ECX; + // } + // + // workingreg = x86reg; + // } + // else { + workingreg = EAX; + tempreg = ECX; + tempreg2 = EDX; + // } + + switch (mem){ + + case 0x10002010: // IPU_CTRL + + MOV32MtoR(workingreg, (u32)&ipuRegs->ctrl._u32); + AND32ItoR(workingreg, ~0x3f0f); // save OFC + OR8MtoR(workingreg, (u32)&g_BP.IFC); + OR8MtoR(workingreg+4, (u32)&coded_block_pattern); // or ah, mem + + // MOV32MtoR(workingreg, (u32)&ipuRegs->ctrl._u32); + // AND32ItoR(workingreg, ~0x3fff); + // MOV32MtoR(tempreg, (u32)&g_nIPU0Data); + // MOV8MtoR(workingreg, (u32)&g_BP.IFC); + // + // CMP32ItoR(tempreg, 8); + // j8Ptr[5] = JLE8(0); + // MOV32ItoR(tempreg, 8); + // x86SetJ8( j8Ptr[5] ); + // SHL32ItoR(tempreg, 4); + // + // OR8MtoR(workingreg+4, (u32)&coded_block_pattern); // or ah, mem + // OR8RtoR(workingreg, tempreg); + +#ifdef _DEBUG + MOV32RtoM((u32)&ipuRegs->ctrl._u32, workingreg); +#endif + // NOTE: not updating ipuRegs->ctrl + // if( x86reg & MEM_XMMTAG ) SSE2_MOVD_R_to_XMM(x86reg&0xf, workingreg); + // else if( x86reg & MEM_MMXTAG ) MOVD32RtoMMX(x86reg&0xf, workingreg); + return 1; + + case 0x10002020: // IPU_BP + + assert( (u32)&g_BP.FP + 1 == (u32)&g_BP.bufferhasnew ); + + MOVZX32M8toR(workingreg, (u32)&g_BP.BP); + MOVZX32M8toR(tempreg, (u32)&g_BP.FP); + AND8ItoR(workingreg, 0x7f); + ADD8MtoR(tempreg, (u32)&g_BP.bufferhasnew); + MOV8MtoR(workingreg+4, (u32)&g_BP.IFC); + + SHL32ItoR(tempreg, 16); + OR32RtoR(workingreg, tempreg); + +#ifdef _DEBUG + MOV32RtoM((u32)&ipuRegs->ipubp, workingreg); +#endif + // NOTE: not updating ipuRegs->ipubp + // if( x86reg & MEM_XMMTAG ) SSE2_MOVD_R_to_XMM(x86reg&0xf, workingreg); + // else if( x86reg & MEM_MMXTAG ) MOVD32RtoMMX(x86reg&0xf, workingreg); + + return 1; + + default: + // ipu repeats every 0x100 + _eeReadConstMem32(x86reg, (u32)(((u8*)ipuRegs)+(mem&0xff))); + return 0; + } + + return 0; +} + +void ipuConstRead64(u32 mem, int mmreg) +{ + iFlushCall(0); + CALLFunc((u32)IPUProcessInterrupt); + + if( IS_XMMREG(mmreg) ) SSE_MOVLPS_M64_to_XMM(mmreg&0xff, (u32)(((u8*)ipuRegs)+(mem&0xff))); + else { + MOVQMtoR(mmreg, (u32)(((u8*)ipuRegs)+(mem&0xff))); + SetMMXstate(); + } +} + +/////////////////////////////////////////////////////////////////////// +// IPU Register Writes! + +void ipuConstWrite32(u32 mem, int mmreg) +{ + iFlushCall(0); + if( !(mmreg & (MEM_XMMTAG|MEM_MMXTAG|MEM_EECONSTTAG)) ) PUSH32R(mmreg); + CALLFunc((u32)IPUProcessInterrupt); + + switch (mem){ + case 0x10002000: // IPU_CMD + if( (mmreg & (MEM_XMMTAG|MEM_MMXTAG|MEM_EECONSTTAG)) ) _recPushReg(mmreg); + CALLFunc((u32)IPUCMD_WRITE); + ADD32ItoR(ESP, 4); + break; + case 0x10002010: // IPU_CTRL + if( mmreg & MEM_EECONSTTAG ) { + u32 c = g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]&0x47f30000; + + if( c & 0x40000000 ) { + CALLFunc((u32)ipuSoftReset); + } + else { + AND32ItoM((u32)&ipuRegs->ctrl._u32, 0x8000ffff); + OR32ItoM((u32)&ipuRegs->ctrl._u32, c); + } + } + else { + if( mmreg & MEM_XMMTAG ) SSE2_MOVD_XMM_to_R(EAX, mmreg&0xf); + else if( mmreg & MEM_MMXTAG ) MOVD32MMXtoR(EAX, mmreg&0xf); + else POP32R(EAX); + + MOV32MtoR(ECX, (u32)&ipuRegs->ctrl._u32); + AND32ItoR(EAX, 0x47f30000); + AND32ItoR(ECX, 0x8000ffff); + OR32RtoR(EAX, ECX); + MOV32RtoM((u32)&ipuRegs->ctrl._u32, EAX); + + TEST32ItoR(EAX, 0x40000000); + j8Ptr[5] = JZ8(0); + + // reset + CALLFunc((u32)ipuSoftReset); + + x86SetJ8( j8Ptr[5] ); + } + + break; + default: + if( !(mmreg & (MEM_XMMTAG|MEM_MMXTAG|MEM_EECONSTTAG)) ) POP32R(mmreg); + _eeWriteConstMem32((u32)((u8*)ipuRegs + (mem&0xfff)), mmreg); + break; + } +} + +void ipuConstWrite64(u32 mem, int mmreg) +{ + iFlushCall(0); + CALLFunc((u32)IPUProcessInterrupt); + + switch (mem){ + case 0x10002000: + _recPushReg(mmreg); + CALLFunc((u32)IPUCMD_WRITE); + ADD32ItoR(ESP, 4); + break; + + default: + _eeWriteConstMem64( (u32)((u8*)ipuRegs + (mem&0xfff)), mmreg); + break; + } +} diff --git a/pcsx2/x86/iMMI.cpp b/pcsx2/x86/iMMI.cpp index 82073394b7..37e92fa4bf 100644 --- a/pcsx2/x86/iMMI.cpp +++ b/pcsx2/x86/iMMI.cpp @@ -1,3413 +1,3413 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -/********************************************************* -* cached MMI opcodes * -* * -*********************************************************/ - -#include "PrecompiledHeader.h" - -#include "Common.h" -#include "R5900OpcodeTables.h" -#include "ix86/ix86.h" -#include "iR5900.h" -#include "iMMI.h" - -namespace Interp = R5900::Interpreter::OpcodeImpl::MMI; - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl { -namespace MMI -{ - -#ifndef MMI_RECOMPILE - -REC_FUNC_DEL( PLZCW, _Rd_ ); - -REC_FUNC_DEL( PMFHL, _Rd_ ); -REC_FUNC_DEL( PMTHL, _Rd_ ); - -REC_FUNC_DEL( PSRLW, _Rd_ ); -REC_FUNC_DEL( PSRLH, _Rd_ ); - -REC_FUNC_DEL( PSRAH, _Rd_ ); -REC_FUNC_DEL( PSRAW, _Rd_ ); - -REC_FUNC_DEL( PSLLH, _Rd_ ); -REC_FUNC_DEL( PSLLW, _Rd_ ); - -#else - -void recPLZCW() -{ - int regd = -1; - int regs = 0; - - if ( ! _Rd_ ) return; - - if( GPR_IS_CONST1(_Rs_) ) { - _eeOnWriteReg(_Rd_, 0); - _deleteEEreg(_Rd_, 0); - GPR_SET_CONST(_Rd_); - - for(regs = 0; regs < 2; ++regs) { - u32 val = g_cpuConstRegs[_Rs_].UL[regs]; - - if( val != 0 ) { - u32 setbit = val&0x80000000; - g_cpuConstRegs[_Rd_].UL[regs] = 0; - val <<= 1; - - while((val & 0x80000000) == setbit) { - g_cpuConstRegs[_Rd_].UL[regs]++; - val <<= 1; - } - } - else { - g_cpuConstRegs[_Rd_].UL[regs] = 31; - } - } - return; - } - - _eeOnWriteReg(_Rd_, 0); - - if( (regs = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ)) >= 0 ) { - SSE2_MOVD_XMM_to_R(EAX, regs); - regs |= MEM_XMMTAG; - } - else if( (regs = _checkMMXreg(MMX_GPR+_Rs_, MODE_READ)) >= 0 ) { - MOVD32MMXtoR(EAX, regs); - SetMMXstate(); - regs |= MEM_MMXTAG; - } - else { - MOV32MtoR(EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - regs = 0; - } - - if( EEINST_ISLIVE1(_Rd_) ) - _deleteEEreg(_Rd_, 0); - else { - if( (regd = _checkMMXreg(MMX_GPR+_Rd_, MODE_WRITE)) < 0 ) - _deleteEEreg(_Rd_, 0); - } - - // Count the number of leading bits (MSB) that match the sign bit, excluding the sign - // bit itself. - - // Strategy: If the sign bit is set, then negate the value. And that way the same - // bitcompare can be used for either bit status. but be warned! BSR returns undefined - // results if the EAX is zero, so we need to have special checks for zeros before - // using it. - - // --- first word --- - - MOV32ItoR(ECX,31); - TEST32RtoR(EAX, EAX); // TEST sets the sign flag accordingly. - u8* label_notSigned = JNS8(0); - NOT32R(EAX); - x86SetJ8(label_notSigned); - - BSRRtoR(EAX, EAX); - u8* label_Zeroed = JZ8(0); // If BSR sets the ZF, eax is "trash" - SUB32RtoR(ECX, EAX); - DEC32R(ECX); // PS2 doesn't count the first bit - - x86SetJ8(label_Zeroed); - if( EEINST_ISLIVE1(_Rd_) || regd < 0 ) { - MOV32RtoM((uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], ECX); - } - else { - SetMMXstate(); - MOVD32RtoMMX(regd, ECX); - } - - // second word - - if( EEINST_ISLIVE1(_Rd_) ) { - if( regs >= 0 && (regs & MEM_XMMTAG) ) { - SSE2_PSHUFD_XMM_to_XMM(regs&0xf, regs&0xf, 0x4e); - SSE2_MOVD_XMM_to_R(EAX, regs&0xf); - SSE2_PSHUFD_XMM_to_XMM(regs&0xf, regs&0xf, 0x4e); - } - else if( regs >= 0 && (regs & MEM_MMXTAG) ) { - PSHUFWRtoR(regs, regs, 0x4e); - MOVD32MMXtoR(EAX, regs&0xf); - PSHUFWRtoR(regs&0xf, regs&0xf, 0x4e); - SetMMXstate(); - } - else MOV32MtoR(EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); - - MOV32ItoR(ECX, 31); - TEST32RtoR(EAX, EAX); // TEST sets the sign flag accordingly. - label_notSigned = JNS8(0); - NOT32R(EAX); - x86SetJ8(label_notSigned); - - BSRRtoR(EAX, EAX); - u8* label_Zeroed = JZ8(0); // If BSR sets the ZF, eax is "trash" - SUB32RtoR(ECX, EAX); - DEC32R(ECX); // PS2 doesn't count the first bit - - x86SetJ8(label_Zeroed); - MOV32RtoM((uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], ECX); - } - else { - EEINST_RESETHASLIVE1(_Rd_); - } - - GPR_DEL_CONST(_Rd_); -} - -static u32 PCSX2_ALIGNED16(s_CmpMasks[]) = { 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff }; - -void recPMFHL() -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_WRITED|XMMINFO_READLO|XMMINFO_READHI) - - int t0reg; - - switch (_Sa_) { - case 0x00: // LW - - t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_HI, 0x88); - SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_LO, 0x88); - SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, t0reg); - - _freeXMMreg(t0reg); - break; - - case 0x01: // UW - t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_HI, 0xdd); - SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_LO, 0xdd); - SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - break; - - case 0x02: // SLW - // fall to interp - MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (uptr)&cpuRegs.pc, pc ); - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - _deleteEEreg(XMMGPR_LO, 1); - _deleteEEreg(XMMGPR_HI, 1); - iFlushCall(FLUSH_CACHED_REGS); // since calling CALLFunc - CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::MMI::PMFHL ); - break; - - case 0x03: // LH - t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSE2_PSHUFLW_XMM_to_XMM(t0reg, EEREC_HI, 0x88); - SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_LO, 0x88); - SSE2_PSHUFHW_XMM_to_XMM(t0reg, t0reg, 0x88); - SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0x88); - SSE2_PSRLDQ_I8_to_XMM(t0reg, 4); - SSE2_PSRLDQ_I8_to_XMM(EEREC_D, 4); - SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - break; - - case 0x04: // SH - if( EEREC_D == EEREC_HI ) { - SSE2_PACKSSDW_XMM_to_XMM(EEREC_D, EEREC_LO); - SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_D, 0x72); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_LO); - SSE2_PACKSSDW_XMM_to_XMM(EEREC_D, EEREC_HI); - - // shuffle so a1a0b1b0->a1b1a0b0 - SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_D, 0xd8); - } - break; - default: - Console::Error("PMFHL?? *pcsx2 head esplode!*"); - assert(0); - } - -CPU_SSE_XMMCACHE_END - - recCall( Interp::PMFHL, _Rd_ ); -} - -void recPMTHL() -{ - recCall( Interp::PMTHL, 0 ); -} - -// MMX helper routines -#define MMX_ALLOC_TEMP1(code) { \ - int t0reg; \ - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); \ - code; \ - _freeMMXreg(t0reg); \ -} \ - -#define MMX_ALLOC_TEMP2(code) { \ - int t0reg, t1reg; \ - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); \ - t1reg = _allocMMXreg(-1, MMX_TEMP, 0); \ - code; \ - _freeMMXreg(t0reg); \ - _freeMMXreg(t1reg); \ -} \ - -#define MMX_ALLOC_TEMP3(code) { \ - int t0reg, t1reg, t2reg; \ - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); \ - t1reg = _allocMMXreg(-1, MMX_TEMP, 0); \ - t2reg = _allocMMXreg(-1, MMX_TEMP, 0); \ - code; \ - _freeMMXreg(t0reg); \ - _freeMMXreg(t1reg); \ - _freeMMXreg(t2reg); \ -} \ - -#define MMX_ALLOC_TEMP4(code) { \ - int t0reg, t1reg, t2reg, t3reg; \ - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); \ - t1reg = _allocMMXreg(-1, MMX_TEMP, 0); \ - t2reg = _allocMMXreg(-1, MMX_TEMP, 0); \ - t3reg = _allocMMXreg(-1, MMX_TEMP, 0); \ - code; \ - _freeMMXreg(t0reg); \ - _freeMMXreg(t1reg); \ - _freeMMXreg(t2reg); \ - _freeMMXreg(t3reg); \ -} \ - -//////////////////////////////////////////////////// -void recPSRLH( void ) -{ - if ( !_Rd_ ) return; - - CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) - if( (_Sa_&0xf) == 0 ) { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - return; - } - - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PSRLW_I8_to_XMM(EEREC_D,_Sa_&0xf ); - CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP2( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PSRLWItoR( t0reg, _Sa_&0xf ); - PSRLWItoR( t1reg, _Sa_&0xf ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPSRLW( void ) -{ - if( !_Rd_ ) return; - - CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) - if( _Sa_ == 0 ) { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - return; - } - - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PSRLD_I8_to_XMM(EEREC_D,_Sa_ ); - CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP2( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PSRLDItoR( t0reg, _Sa_ ); - PSRLDItoR( t1reg, _Sa_ ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPSRAH( void ) -{ - if ( !_Rd_ ) return; - - CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) - if( (_Sa_&0xf) == 0 ) { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - return; - } - - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PSRAW_I8_to_XMM(EEREC_D,_Sa_&0xf ); - CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP2( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PSRAWItoR( t0reg, _Sa_&0xf ); - PSRAWItoR( t1reg, _Sa_&0xf ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPSRAW( void ) -{ - if ( !_Rd_ ) return; - - CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) - if( _Sa_ == 0 ) { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - return; - } - - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PSRAD_I8_to_XMM(EEREC_D,_Sa_ ); - CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP2( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PSRADItoR( t0reg, _Sa_ ); - PSRADItoR( t1reg, _Sa_ ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPSLLH( void ) -{ - if ( !_Rd_ ) return; - - CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) - if( (_Sa_&0xf) == 0 ) { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - return; - } - - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PSLLW_I8_to_XMM(EEREC_D,_Sa_&0xf ); - CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP2( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PSLLWItoR( t0reg, _Sa_&0xf ); - PSLLWItoR( t1reg, _Sa_&0xf ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPSLLW( void ) -{ - if ( !_Rd_ ) return; - - CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) - if( _Sa_ == 0 ) { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - return; - } - - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PSLLD_I8_to_XMM(EEREC_D,_Sa_ ); - CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP2( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PSLLDItoR( t0reg, _Sa_ ); - PSLLDItoR( t1reg, _Sa_ ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -/* -void recMADD( void ) -{ -} - -void recMADDU( void ) -{ -} - -void recPLZCW( void ) -{ -} -*/ - -#endif - -/********************************************************* -* MMI0 opcodes * -* * -*********************************************************/ -#ifndef MMI0_RECOMPILE - -REC_FUNC_DEL( PADDB, _Rd_); -REC_FUNC_DEL( PADDH, _Rd_); -REC_FUNC_DEL( PADDW, _Rd_); -REC_FUNC_DEL( PADDSB, _Rd_); -REC_FUNC_DEL( PADDSH, _Rd_); -REC_FUNC_DEL( PADDSW, _Rd_); -REC_FUNC_DEL( PSUBB, _Rd_); -REC_FUNC_DEL( PSUBH, _Rd_); -REC_FUNC_DEL( PSUBW, _Rd_); -REC_FUNC_DEL( PSUBSB, _Rd_); -REC_FUNC_DEL( PSUBSH, _Rd_); -REC_FUNC_DEL( PSUBSW, _Rd_); - -REC_FUNC_DEL( PMAXW, _Rd_); -REC_FUNC_DEL( PMAXH, _Rd_); - -REC_FUNC_DEL( PCGTW, _Rd_); -REC_FUNC_DEL( PCGTH, _Rd_); -REC_FUNC_DEL( PCGTB, _Rd_); - -REC_FUNC_DEL( PEXTLW, _Rd_); - -REC_FUNC_DEL( PPACW, _Rd_); -REC_FUNC_DEL( PEXTLH, _Rd_); -REC_FUNC_DEL( PPACH, _Rd_); -REC_FUNC_DEL( PEXTLB, _Rd_); -REC_FUNC_DEL( PPACB, _Rd_); -REC_FUNC_DEL( PEXT5, _Rd_); -REC_FUNC_DEL( PPAC5, _Rd_); - -#else - -//////////////////////////////////////////////////// -void recPMAXW() -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - int t0reg; - - if( EEREC_S == EEREC_T ) { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - return; - } - - t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); - SSE2_PCMPGTD_XMM_to_XMM(t0reg, EEREC_T); - - if( EEREC_D == EEREC_S ) { - SSEX_PAND_XMM_to_XMM(EEREC_D, t0reg); - SSEX_PANDN_XMM_to_XMM(t0reg, EEREC_T); - } - else if( EEREC_D == EEREC_T ) { - int t1reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_T); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSEX_PAND_XMM_to_XMM(EEREC_D, t0reg); - SSEX_PANDN_XMM_to_XMM(t0reg, t1reg); - _freeXMMreg(t1reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSEX_PAND_XMM_to_XMM(EEREC_D, t0reg); - SSEX_PANDN_XMM_to_XMM(t0reg, EEREC_T); - } - - SSEX_POR_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); -CPU_SSE_XMMCACHE_END - - recCall( Interp::PMAXW, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPPACW() -{ - if ( ! _Rd_ ) return; - -CPU_SSE_XMMCACHE_START(((_Rs_!=0)?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) - if( _Rs_ == 0 ) { - SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_T, 0x88); - SSE2_PSRLDQ_I8_to_XMM(EEREC_D, 8); - } - else { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - if( EEREC_D == EEREC_T ) { - SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_S, 0x88); - SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_T, 0x88); - SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } - else { - SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_T, 0x88); - SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_S, 0x88); - SSE2_PUNPCKLQDQ_XMM_to_XMM(t0reg, EEREC_D); - - // swap mmx regs.. don't ask - xmmregs[t0reg] = xmmregs[EEREC_D]; - xmmregs[EEREC_D].inuse = 0; - } - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - //Done - Refraction - Crude but quicker than int - MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[2]); //Copy this one cos it could get overwritten - - MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[2]); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[3], EAX); - MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[0]); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[2], EAX); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[1], ECX); //This is where we bring it back - MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); -} - -void recPPACH( void ) -{ - if (!_Rd_) return; - -CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) - if( _Rs_ == 0 ) { - SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_T, 0x88); - SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0x88); - SSE2_PSLLDQ_I8_to_XMM(EEREC_D, 4); - SSE2_PSRLDQ_I8_to_XMM(EEREC_D, 8); - } - else { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSE2_PSHUFLW_XMM_to_XMM(t0reg, EEREC_S, 0x88); - SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_T, 0x88); - SSE2_PSHUFHW_XMM_to_XMM(t0reg, t0reg, 0x88); - SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0x88); - - SSE2_PSRLDQ_I8_to_XMM(t0reg, 4); - SSE2_PSRLDQ_I8_to_XMM(EEREC_D, 4); - SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, t0reg); - - _freeXMMreg(t0reg); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - //Done - Refraction - Crude but quicker than int - MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[6]); - MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[7], EAX); - MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[6]); - MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[3], EAX); - MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[2]); - MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[5], EAX); - MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[2]); - MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[1], EAX); - MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[4]); - MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[6], EAX); - MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[4]); - MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[2], EAX); - MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[0]); - MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[4], EAX); - MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[0]); - MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[0], EAX); -} - -//////////////////////////////////////////////////// -void recPPACB() -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) - if( _Rs_ == 0 ) { - if( _hasFreeXMMreg() ) { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PSLLW_I8_to_XMM(EEREC_D, 8); - SSEX_PXOR_XMM_to_XMM(t0reg, t0reg); - SSE2_PSRLW_I8_to_XMM(EEREC_D, 8); - SSE2_PACKUSWB_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PSLLW_I8_to_XMM(EEREC_D, 8); - SSE2_PSRLW_I8_to_XMM(EEREC_D, 8); - SSE2_PACKUSWB_XMM_to_XMM(EEREC_D, EEREC_D); - SSE2_PSRLDQ_I8_to_XMM(EEREC_D, 8); - } - } - else { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PSLLW_I8_to_XMM(t0reg, 8); - SSE2_PSLLW_I8_to_XMM(EEREC_D, 8); - SSE2_PSRLW_I8_to_XMM(t0reg, 8); - SSE2_PSRLW_I8_to_XMM(EEREC_D, 8); - - SSE2_PACKUSWB_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } -CPU_SSE_XMMCACHE_END - - recCall( Interp::PPACB, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPEXT5() -{ - recCall( Interp::PEXT5, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPPAC5() -{ - recCall( Interp::PPAC5, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPMAXH( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D == EEREC_S ) SSE2_PMAXSW_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE2_PMAXSW_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PMAXSW_XMM_to_XMM(EEREC_D, EEREC_T); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - SSE_PMAXSW_MM_to_MM( t0reg, t1reg ); - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - SSE_PMAXSW_MM_to_MM( t2reg, t3reg); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t2reg); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPCGTB( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D != EEREC_T ) { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PCMPGTB_XMM_to_XMM(EEREC_D, EEREC_T); - } - else { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PCMPGTB_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - PCMPGTBRtoR( t0reg, t1reg ); - - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PCMPGTBRtoR( t2reg, t3reg); - - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t2reg); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPCGTH( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D != EEREC_T ) { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PCMPGTW_XMM_to_XMM(EEREC_D, EEREC_T); - } - else { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PCMPGTW_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - - PCMPGTWRtoR( t0reg, t1reg ); - PCMPGTWRtoR( t2reg, t3reg); - - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t2reg); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPCGTW( void ) -{ - //TODO:optimize RS | RT== 0 - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D != EEREC_T ) { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PCMPGTD_XMM_to_XMM(EEREC_D, EEREC_T); - } - else { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PCMPGTD_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - - PCMPGTDRtoR( t0reg, t1reg ); - PCMPGTDRtoR( t2reg, t3reg); - - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t2reg); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPADDSB( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D == EEREC_S ) SSE2_PADDSB_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE2_PADDSB_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PADDSB_XMM_to_XMM(EEREC_D, EEREC_T); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PADDSBRtoR( t0reg, t2reg); - PADDSBRtoR( t1reg, t3reg); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPADDSH( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D == EEREC_S ) SSE2_PADDSW_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE2_PADDSW_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PADDSW_XMM_to_XMM(EEREC_D, EEREC_T); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PADDSWRtoR( t0reg, t2reg); - PADDSWRtoR( t1reg, t3reg); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -//NOTE: check kh2 movies if changing this -void recPADDSW( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - int t1reg = _allocTempXMMreg(XMMT_INT, -1); - int t2reg = _allocTempXMMreg(XMMT_INT, -1); - int t3reg = _allocTempXMMreg(XMMT_INT, -1); - - if ( cpucaps.hasStreamingSIMD4Extensions ) { - SSE4_PMOVSXDQ_XMM_to_XMM(t0reg, EEREC_S); - SSE4_PMOVSXDQ_XMM_to_XMM(t1reg, EEREC_T); - SSE2_PADDQ_XMM_to_XMM(t0reg, t1reg); - SSE2_PSHUFD_XMM_to_XMM(t1reg, EEREC_S, 0x0e); - SSE2_PSHUFD_XMM_to_XMM(t2reg, EEREC_T, 0x0e); - SSE4_PMOVSXDQ_XMM_to_XMM(t1reg, t1reg); - SSE4_PMOVSXDQ_XMM_to_XMM(t2reg, t2reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); - SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_T); - SSE2_PXOR_XMM_to_XMM(t2reg, t2reg); - SSE2_PXOR_XMM_to_XMM(t3reg, t3reg); - SSE2_PCMPGTD_XMM_to_XMM(t2reg, t0reg); - SSE2_PCMPGTD_XMM_to_XMM(t3reg, t1reg); - SSE2_PUNPCKLDQ_XMM_to_XMM(t0reg, t2reg); - SSE2_PUNPCKLDQ_XMM_to_XMM(t1reg, t3reg); - SSE2_PADDQ_XMM_to_XMM(t0reg, t1reg); - SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_S); - SSE2_PUNPCKHDQ_XMM_to_XMM(t1reg, t2reg); - SSEX_MOVDQA_XMM_to_XMM(t2reg, EEREC_T); - SSE2_PUNPCKHDQ_XMM_to_XMM(t2reg, t3reg); - } - SSE2_PADDQ_XMM_to_XMM(t1reg, t2reg); - /* - t0reg = { Rs[0]+Rt[0], Rs[1]+Rt[1] } - t1reg = { Rs[2]+Rt[2], Rs[3]+Rt[3] } - */ - - SSEX_MOVDQA_XMM_to_XMM(t2reg, t0reg); - SSE_SHUFPS_XMM_to_XMM(t2reg, t1reg, 0xdd); - SSE2_PSRAD_I8_to_XMM(t2reg, 31); - /* - t2reg = { (Rs[0]+Rt[0]) < 0 ? 0xFFFFFFFF : 0, - (Rs[1]+Rt[1]) < 0 ? 0xFFFFFFFF : 0, - (Rs[2]+Rt[2]) < 0 ? 0xFFFFFFFF : 0, - (Rs[3]+Rt[3]) < 0 ? 0xFFFFFFFF : 0 } - */ - - SSE2_PSHUFD_XMM_to_XMM(t3reg, t2reg, 0x50); - SSE2_PXOR_XMM_to_XMM(t0reg, t3reg); - SSE2_PSRLQ_I8_to_XMM(t3reg, 63); - SSE2_PADDQ_XMM_to_XMM(t0reg, t3reg); - /* - t0reg = { abs(Rs[0]+Rt[0]), abs(Rs[1]+Rt[1]) } - */ - SSE2_PSHUFD_XMM_to_XMM(t3reg, t2reg, 0xfa); - SSE2_PXOR_XMM_to_XMM(t1reg, t3reg); - SSE2_PSRLQ_I8_to_XMM(t3reg, 63); - SSE2_PADDQ_XMM_to_XMM(t1reg, t3reg); - /* - t1reg = { abs(Rs[2]+Rt[2]), abs(Rs[3]+Rt[3]) } - */ - SSE2_PSLLQ_I8_to_XMM(t0reg, 1); - SSE2_PSLLQ_I8_to_XMM(t1reg, 1); - SSE2_PCMPEQB_XMM_to_XMM(t3reg, t3reg); - SSE2_PSRLD_I8_to_XMM(t3reg, 1); - SSE2_PXOR_XMM_to_XMM(t2reg, t3reg); - SSE_SHUFPS_XMM_to_XMM(t0reg, t1reg, 0xdd); - SSE2_PXOR_XMM_to_XMM(t1reg, t1reg); - SSE2_PCMPEQD_XMM_to_XMM(t1reg, t0reg); - /* - t1reg = { abs(Rs[0]+Rt[0]) > 0x7FFFFFFF ? 0 : 0xFFFFFFFF, - abs(Rs[1]+Rt[1]) > 0x7FFFFFFF ? 0 : 0xFFFFFFFF, - abs(Rs[2]+Rt[2]) > 0x7FFFFFFF ? 0 : 0xFFFFFFFF, - abs(Rs[3]+Rt[3]) > 0x7FFFFFFF ? 0 : 0xFFFFFFFF } - t2reg = { (Rs[0]+Rt[0]) < 0 ? 0x80000000 : 0x7FFFFFFF, - (Rs[1]+Rt[1]) < 0 ? 0x80000000 : 0x7FFFFFFF, - (Rs[2]+Rt[2]) < 0 ? 0x80000000 : 0x7FFFFFFF, - (Rs[3]+Rt[3]) < 0 ? 0x80000000 : 0x7FFFFFFF } - */ - if( EEREC_D == EEREC_S ) SSE2_PADDD_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE2_PADDD_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PADDD_XMM_to_XMM(EEREC_D, EEREC_T); - } - SSE2_PAND_XMM_to_XMM(EEREC_D, t1reg); - SSE2_PANDN_XMM_to_XMM(t1reg, t2reg); - SSE2_POR_XMM_to_XMM(EEREC_D, t1reg); - /* - Rd = { t1reg[0] ? Rs[0]+Rt[0] : t2reg[0], - t1reg[1] ? Rs[1]+Rt[1] : t2reg[1], - t1reg[2] ? Rs[2]+Rt[2] : t2reg[2], - t1reg[3] ? Rs[3]+Rt[3] : t2reg[3] } - */ - _freeXMMreg(t0reg); - _freeXMMreg(t1reg); - _freeXMMreg(t2reg); - _freeXMMreg(t3reg); -CPU_SSE_XMMCACHE_END - - if( _Rd_ ) _deleteEEreg(_Rd_, 0); - _deleteEEreg(_Rs_, 1); - _deleteEEreg(_Rt_, 1); - _flushConstRegs(); - - MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (uptr)&cpuRegs.pc, pc ); - CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::MMI::PADDSW ); -} - -//////////////////////////////////////////////////// -void recPSUBSB( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D == EEREC_S ) SSE2_PSUBSB_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PSUBSB_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PSUBSB_XMM_to_XMM(EEREC_D, EEREC_T); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PSUBSBRtoR( t0reg, t2reg); - PSUBSBRtoR( t1reg, t3reg); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPSUBSH( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D == EEREC_S ) SSE2_PSUBSW_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PSUBSW_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PSUBSW_XMM_to_XMM(EEREC_D, EEREC_T); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PSUBSWRtoR( t0reg, t2reg); - PSUBSWRtoR( t1reg, t3reg); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -//NOTE: check kh2 movies if changing this -void recPSUBSW( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - int t1reg = _allocTempXMMreg(XMMT_INT, -1); - int t2reg = _allocTempXMMreg(XMMT_INT, -1); - int t3reg = _allocTempXMMreg(XMMT_INT, -1); - - if ( cpucaps.hasStreamingSIMD4Extensions ) { - SSE4_PMOVSXDQ_XMM_to_XMM(t0reg, EEREC_S); - SSE4_PMOVSXDQ_XMM_to_XMM(t1reg, EEREC_T); - SSE2_PSUBQ_XMM_to_XMM(t0reg, t1reg); - SSE2_PSHUFD_XMM_to_XMM(t1reg, EEREC_S, 0x0e); - SSE2_PSHUFD_XMM_to_XMM(t2reg, EEREC_T, 0x0e); - SSE4_PMOVSXDQ_XMM_to_XMM(t1reg, t1reg); - SSE4_PMOVSXDQ_XMM_to_XMM(t2reg, t2reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); - SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_T); - SSE2_PXOR_XMM_to_XMM(t2reg, t2reg); - SSE2_PXOR_XMM_to_XMM(t3reg, t3reg); - SSE2_PCMPGTD_XMM_to_XMM(t2reg, t0reg); - SSE2_PCMPGTD_XMM_to_XMM(t3reg, t1reg); - SSE2_PUNPCKLDQ_XMM_to_XMM(t0reg, t2reg); - SSE2_PUNPCKLDQ_XMM_to_XMM(t1reg, t3reg); - SSE2_PSUBQ_XMM_to_XMM(t0reg, t1reg); - SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_S); - SSE2_PUNPCKHDQ_XMM_to_XMM(t1reg, t2reg); - SSEX_MOVDQA_XMM_to_XMM(t2reg, EEREC_T); - SSE2_PUNPCKHDQ_XMM_to_XMM(t2reg, t3reg); - } - SSE2_PSUBQ_XMM_to_XMM(t1reg, t2reg); - - SSEX_MOVDQA_XMM_to_XMM(t2reg, t0reg); - SSE_SHUFPS_XMM_to_XMM(t2reg, t1reg, 0xdd); - SSE2_PSRAD_I8_to_XMM(t2reg, 31); - - SSE2_PSHUFD_XMM_to_XMM(t3reg, t2reg, 0x50); - SSE2_PXOR_XMM_to_XMM(t0reg, t3reg); - SSE2_PSRLQ_I8_to_XMM(t3reg, 63); - SSE2_PADDQ_XMM_to_XMM(t0reg, t3reg); - SSE2_PSHUFD_XMM_to_XMM(t3reg, t2reg, 0xfa); - SSE2_PXOR_XMM_to_XMM(t1reg, t3reg); - SSE2_PSRLQ_I8_to_XMM(t3reg, 63); - SSE2_PADDQ_XMM_to_XMM(t1reg, t3reg); - SSE2_PSLLQ_I8_to_XMM(t0reg, 1); - SSE2_PSLLQ_I8_to_XMM(t1reg, 1); - SSE2_PCMPEQB_XMM_to_XMM(t3reg, t3reg); - SSE2_PSRLD_I8_to_XMM(t3reg, 1); - SSE2_PXOR_XMM_to_XMM(t2reg, t3reg); - SSE_SHUFPS_XMM_to_XMM(t0reg, t1reg, 0xdd); - SSE2_PXOR_XMM_to_XMM(t1reg, t1reg); - SSE2_PCMPEQD_XMM_to_XMM(t1reg, t0reg); - if( EEREC_D == EEREC_S ) SSE2_PSUBD_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) { - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PSUBD_XMM_to_XMM(EEREC_D, t0reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PSUBD_XMM_to_XMM(EEREC_D, EEREC_T); - } - SSE2_PAND_XMM_to_XMM(EEREC_D, t1reg); - SSE2_PANDN_XMM_to_XMM(t1reg, t2reg); - SSE2_POR_XMM_to_XMM(EEREC_D, t1reg); - _freeXMMreg(t0reg); - _freeXMMreg(t1reg); - _freeXMMreg(t2reg); - _freeXMMreg(t3reg); -CPU_SSE_XMMCACHE_END - - if( _Rd_ ) _deleteEEreg(_Rd_, 0); - _deleteEEreg(_Rs_, 1); - _deleteEEreg(_Rt_, 1); - _flushConstRegs(); - - MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (uptr)&cpuRegs.pc, pc ); - CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::MMI::PSUBSW ); -} - -//////////////////////////////////////////////////// -void recPADDB( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D == EEREC_S ) SSE2_PADDB_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE2_PADDB_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PADDB_XMM_to_XMM(EEREC_D, EEREC_T); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PADDBRtoR( t0reg, t2reg ); - PADDBRtoR( t1reg, t3reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPADDH( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|(_Rt_!=0?XMMINFO_READT:0)|XMMINFO_WRITED) - if( _Rs_ == 0 ) { - if( _Rt_ == 0 ) SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_D); - else SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - } - else if( _Rt_ == 0 ) { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - } - else { - if( EEREC_D == EEREC_S ) SSE2_PADDW_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE2_PADDW_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PADDW_XMM_to_XMM(EEREC_D, EEREC_T); - } - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PADDWRtoR( t0reg, t2reg ); - PADDWRtoR( t1reg, t3reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPADDW( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|(_Rt_!=0?XMMINFO_READT:0)|XMMINFO_WRITED) - if( _Rs_ == 0 ) { - if( _Rt_ == 0 ) SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_D); - else SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - } - else if( _Rt_ == 0 ) { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - } - else { - if( EEREC_D == EEREC_S ) SSE2_PADDD_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE2_PADDD_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PADDD_XMM_to_XMM(EEREC_D, EEREC_T); - } - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PADDDRtoR( t0reg, t2reg ); - PADDDRtoR( t1reg, t3reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPSUBB( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D == EEREC_S ) SSE2_PSUBB_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PSUBB_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PSUBB_XMM_to_XMM(EEREC_D, EEREC_T); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PSUBBRtoR( t0reg, t2reg ); - PSUBBRtoR( t1reg, t3reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPSUBH( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D == EEREC_S ) SSE2_PSUBW_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PSUBW_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PSUBW_XMM_to_XMM(EEREC_D, EEREC_T); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PSUBWRtoR( t0reg, t2reg ); - PSUBWRtoR( t1reg, t3reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPSUBW( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D == EEREC_S ) SSE2_PSUBD_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PSUBD_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PSUBD_XMM_to_XMM(EEREC_D, EEREC_T); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PSUBDRtoR( t0reg, t2reg); - PSUBDRtoR( t1reg, t3reg); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPEXTLW( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) - if( _Rs_ == 0 ) { - SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PSRLQ_I8_to_XMM(EEREC_D, 32); - } - else { - if( EEREC_D == EEREC_T ) SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, EEREC_S); - else if( EEREC_D == EEREC_S ) { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, EEREC_S); - } - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); - MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 3 ], EAX ); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 2 ], ECX ); - - MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EAX ); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], ECX ); -} - -void recPEXTLB( void ) -{ - if (!_Rd_) return; - -CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) - if( _Rs_ == 0 ) { - SSE2_PUNPCKLBW_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PSRLW_I8_to_XMM(EEREC_D, 8); - } - else { - if( EEREC_D == EEREC_T ) SSE2_PUNPCKLBW_XMM_to_XMM(EEREC_D, EEREC_S); - else if( EEREC_D == EEREC_S ) { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PUNPCKLBW_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PUNPCKLBW_XMM_to_XMM(EEREC_D, EEREC_S); - } - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - //Done - Refraction - Crude but quicker than int - //SysPrintf("PEXTLB\n"); - //Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[7]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[15], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[7]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[14], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[6]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[13], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[6]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[12], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[5]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[11], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[5]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[10], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[4]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[9], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[4]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[8], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[3]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[7], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[3]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[6], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[2]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[5], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[2]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[4], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[1]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[3], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[1]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[2], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[0]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[1], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[0]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[0], EAX); -} - -void recPEXTLH( void ) -{ - if (!_Rd_) return; - -CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) - if( _Rs_ == 0 ) { - SSE2_PUNPCKLWD_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PSRLD_I8_to_XMM(EEREC_D, 16); - } - else { - if( EEREC_D == EEREC_T ) SSE2_PUNPCKLWD_XMM_to_XMM(EEREC_D, EEREC_S); - else if( EEREC_D == EEREC_S ) { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PUNPCKLWD_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PUNPCKLWD_XMM_to_XMM(EEREC_D, EEREC_S); - } - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - //Done - Refraction - Crude but quicker than int - MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[3]); - MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[7], EAX); - MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[3]); - MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[6], EAX); - MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[2]); - MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[5], EAX); - MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[2]); - MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[4], EAX); - MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[1]); - MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[3], EAX); - MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[1]); - MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[2], EAX); - MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[0]); - MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[1], EAX); - MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[0]); - MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[0], EAX); -} - -#endif - -/********************************************************* -* MMI1 opcodes * -* * -*********************************************************/ -#ifndef MMI1_RECOMPILE - -REC_FUNC_DEL( PABSW, _Rd_); -REC_FUNC_DEL( PABSH, _Rd_); - -REC_FUNC_DEL( PMINW, _Rd_); -REC_FUNC_DEL( PADSBH, _Rd_); -REC_FUNC_DEL( PMINH, _Rd_); -REC_FUNC_DEL( PCEQB, _Rd_); -REC_FUNC_DEL( PCEQH, _Rd_); -REC_FUNC_DEL( PCEQW, _Rd_); - -REC_FUNC_DEL( PADDUB, _Rd_); -REC_FUNC_DEL( PADDUH, _Rd_); -REC_FUNC_DEL( PADDUW, _Rd_); - -REC_FUNC_DEL( PSUBUB, _Rd_); -REC_FUNC_DEL( PSUBUH, _Rd_); -REC_FUNC_DEL( PSUBUW, _Rd_); - -REC_FUNC_DEL( PEXTUW, _Rd_); -REC_FUNC_DEL( PEXTUH, _Rd_); -REC_FUNC_DEL( PEXTUB, _Rd_); -REC_FUNC_DEL( QFSRV, _Rd_); - -#else - -//////////////////////////////////////////////////// -PCSX2_ALIGNED16(int s_MaskHighBitD[4]) = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }; -PCSX2_ALIGNED16(int s_MaskHighBitW[4]) = { 0x80008000, 0x80008000, 0x80008000, 0x80008000 }; - -void recPABSW() -{ - if( !_Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PSRAD_I8_to_XMM(t0reg, 31); - SSEX_PXOR_XMM_to_XMM(EEREC_D, t0reg); - SSE2_PSUBD_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); -CPU_SSE_XMMCACHE_END - - _deleteEEreg(_Rt_, 1); - _deleteEEreg(_Rd_, 0); - _flushConstRegs(); - - MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (uptr)&cpuRegs.pc, pc ); - CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::MMI::PABSW ); -} - -//////////////////////////////////////////////////// -void recPABSH() -{ -if( !_Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PSRAW_I8_to_XMM(t0reg, 15); - SSEX_PXOR_XMM_to_XMM(EEREC_D, t0reg); - SSE2_PSUBW_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); -CPU_SSE_XMMCACHE_END - - _deleteEEreg(_Rt_, 1); - _deleteEEreg(_Rd_, 0); - _flushConstRegs(); - - MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (uptr)&cpuRegs.pc, pc ); - CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::MMI::PABSW ); -} - -//////////////////////////////////////////////////// -void recPMINW() -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - int t0reg; - - if( EEREC_S == EEREC_T ) { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - return; - } - - t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); - SSE2_PCMPGTD_XMM_to_XMM(t0reg, EEREC_S); - - if( EEREC_D == EEREC_S ) { - SSEX_PAND_XMM_to_XMM(EEREC_D, t0reg); - SSEX_PANDN_XMM_to_XMM(t0reg, EEREC_T); - } - else if( EEREC_D == EEREC_T ) { - int t1reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_T); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSEX_PAND_XMM_to_XMM(EEREC_D, t0reg); - SSEX_PANDN_XMM_to_XMM(t0reg, t1reg); - _freeXMMreg(t1reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSEX_PAND_XMM_to_XMM(EEREC_D, t0reg); - SSEX_PANDN_XMM_to_XMM(t0reg, EEREC_T); - } - - SSEX_POR_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); -CPU_SSE_XMMCACHE_END - - recCall( Interp::PMINW, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPADSBH() -{ -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - int t0reg; - - if( EEREC_S == EEREC_T ) { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PADDW_XMM_to_XMM(EEREC_D, EEREC_D); - // reset lower bits to 0s - SSE2_PSRLDQ_I8_to_XMM(EEREC_D, 8); - SSE2_PSLLDQ_I8_to_XMM(EEREC_D, 8); - return; - } - - t0reg = _allocTempXMMreg(XMMT_INT, -1); - - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); - - if( EEREC_D == EEREC_S ) { - SSE2_PADDW_XMM_to_XMM(t0reg, EEREC_S); - SSE2_PSUBW_XMM_to_XMM(EEREC_D, EEREC_T); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PSUBW_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PADDW_XMM_to_XMM(t0reg, EEREC_S); - } - - // t0reg - adds, EEREC_D - subs - SSE2_PSRLDQ_I8_to_XMM(t0reg, 8); - SSE_MOVLHPS_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - -CPU_SSE_XMMCACHE_END - - recCall( Interp::PADSBH, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPADDUW() -{ -CPU_SSE2_XMMCACHE_START((_Rs_?XMMINFO_READS:0)|(_Rt_?XMMINFO_READT:0)|XMMINFO_WRITED) - - if( _Rt_ == 0 ) { - if( _Rs_ == 0 ) { - SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_D); - } - else SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - } - else if( _Rs_ == 0 ) { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - } - else { - - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - int t1reg = _allocTempXMMreg(XMMT_INT, -1); - int t2reg = _allocTempXMMreg(XMMT_INT, -1); - - if( _hasFreeXMMreg() ) { - int t3reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_PXOR_XMM_to_XMM(t0reg, t0reg); - SSE2_MOVQ_XMM_to_XMM(t1reg, EEREC_S); - SSEX_MOVDQA_XMM_to_XMM(t2reg, EEREC_S); - if( EEREC_D != EEREC_T ) SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_T); - SSEX_MOVDQA_XMM_to_XMM(t3reg, EEREC_T); - SSE2_PUNPCKLDQ_XMM_to_XMM(t1reg, t0reg); - SSE2_PUNPCKHDQ_XMM_to_XMM(t2reg, t0reg); - SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, t0reg); - SSE2_PUNPCKHDQ_XMM_to_XMM(t3reg, t0reg); - SSE2_PADDQ_XMM_to_XMM(t1reg, EEREC_D); - SSE2_PADDQ_XMM_to_XMM(t2reg, t3reg); - _freeXMMreg(t3reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(t2reg, EEREC_S); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); - - SSE2_MOVQ_XMM_to_XMM(t1reg, EEREC_S); - SSE2_PSRLDQ_I8_to_XMM(t2reg, 8); - if( EEREC_D != EEREC_T ) SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PSRLDQ_I8_to_XMM(t0reg, 8); - SSE2_PSHUFD_XMM_to_XMM(t1reg, t1reg, 0xE8); - SSE2_PSHUFD_XMM_to_XMM(t2reg, t2reg, 0xE8); - SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_D, 0xE8); - SSE2_PSHUFD_XMM_to_XMM(t0reg, t0reg, 0xE8); - SSE2_PADDQ_XMM_to_XMM(t1reg, EEREC_D); - SSE2_PADDQ_XMM_to_XMM(t2reg, t0reg); - SSEX_PXOR_XMM_to_XMM(t0reg, t0reg); - } - - SSE2_PSHUFD_XMM_to_XMM(t1reg, t1reg, 0xd8); - SSE2_PSHUFD_XMM_to_XMM(t2reg, t2reg, 0xd8); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, t1reg); - SSE2_PUNPCKHQDQ_XMM_to_XMM(t1reg, t2reg); - SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, t2reg); - SSE2_PCMPGTD_XMM_to_XMM(t1reg, t0reg); - SSEX_POR_XMM_to_XMM(EEREC_D, t1reg); - - _freeXMMreg(t0reg); - _freeXMMreg(t1reg); - _freeXMMreg(t2reg); - } - -CPU_SSE_XMMCACHE_END - recCall( Interp::PADDUW, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPSUBUB() -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D == EEREC_S ) SSE2_PSUBUSB_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE2_PSUBUSB_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PSUBUSB_XMM_to_XMM(EEREC_D, EEREC_T); - } -CPU_SSE_XMMCACHE_END - - recCall( Interp::PSUBUB, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPSUBUH() -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D == EEREC_S ) SSE2_PSUBUSW_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE2_PSUBUSW_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PSUBUSW_XMM_to_XMM(EEREC_D, EEREC_T); - } -CPU_SSE_XMMCACHE_END - - recCall( Interp::PSUBUH, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPSUBUW() -{ - recCall( Interp::PSUBUW, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPEXTUH() -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) - if( _Rs_ == 0 ) { - SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PSRLD_I8_to_XMM(EEREC_D, 16); - } - else { - if( EEREC_D == EEREC_T ) SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, EEREC_S); - else if( EEREC_D == EEREC_S ) { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, EEREC_S); - } - } -CPU_SSE_XMMCACHE_END - - recCall( Interp::PEXTUH, _Rd_ ); -} - -//////////////////////////////////////////////////// -// Both Macros are 16 bytes so we can use a shift instead of a Mul instruction -#define QFSRVhelper0() { \ - ajmp[0] = JMP32(0); \ - x86Ptr += 11; \ -} - -#define QFSRVhelper(shift1, shift2) { \ - SSE2_PSRLDQ_I8_to_XMM(EEREC_D, shift1); \ - SSE2_PSLLDQ_I8_to_XMM(t0reg, shift2); \ - ajmp[shift1] = JMP32(0); \ - x86Ptr += 1; \ -} - -void recQFSRV() -{ - if ( !_Rd_ ) return; - //SysPrintf("recQFSRV()\n"); - - CPU_SSE2_XMMCACHE_START( XMMINFO_READS | XMMINFO_READT | XMMINFO_WRITED ) - - u32 *ajmp[16]; - int i, j; - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - - SSE2_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); - SSE2_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - - MOV32MtoR(EAX, (uptr)&cpuRegs.sa); - SHL32ItoR(EAX, 1); // Multiply SA bytes by 16 bytes (the amount of bytes in QFSRVhelper() macros) - AND32I8toR(EAX, 0xf0); // This can possibly be removed but keeping it incase theres garbage in SA (cottonvibes) - ADD32ItoEAX((uptr)x86Ptr + 7); // ADD32 = 5 bytes, JMPR = 2 bytes - JMPR(EAX); // Jumps to a QFSRVhelper() case below (a total of 16 different cases) - - // Case 0: - QFSRVhelper0(); - - // Cases 1 to 15: - for (i = 1, j = 15; i < 16; i++, j--) { - QFSRVhelper(i, j); - } - - // Set jump addresses for the JMP32's in QFSRVhelper() - for (i = 1; i < 16; i++) { - x86SetJ32(ajmp[i]); - } - - // Concatenate the regs after appropriate shifts have been made - SSE2_POR_XMM_to_XMM(EEREC_D, t0reg); - - x86SetJ32(ajmp[0]); // Case 0 jumps to here (to skip the POR) - _freeXMMreg(t0reg); - - CPU_SSE_XMMCACHE_END - //recCall( Interp::QFSRV, _Rd_ ); -} - - -void recPEXTUB( void ) -{ - if (!_Rd_) return; - -CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) - if( _Rs_ == 0 ) { - SSE2_PUNPCKHBW_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PSRLW_I8_to_XMM(EEREC_D, 8); - } - else { - if( EEREC_D == EEREC_T ) SSE2_PUNPCKHBW_XMM_to_XMM(EEREC_D, EEREC_S); - else if( EEREC_D == EEREC_S ) { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PUNPCKHBW_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PUNPCKHBW_XMM_to_XMM(EEREC_D, EEREC_S); - } - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - //Done - Refraction - Crude but faster than int - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[8]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[0], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[8]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[1], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[9]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[2], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[9]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[3], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[10]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[4], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[10]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[5], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[11]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[6], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[11]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[7], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[12]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[8], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[12]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[9], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[13]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[10], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[13]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[11], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[14]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[12], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[14]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[13], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[15]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[14], EAX); - MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[15]); - MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[15], EAX); -} - -//////////////////////////////////////////////////// -void recPEXTUW( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) - if( _Rs_ == 0 ) { - SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PSRLQ_I8_to_XMM(EEREC_D, 32); - } - else { - if( EEREC_D == EEREC_T ) SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_D, EEREC_S); - else if( EEREC_D == EEREC_S ) { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_D, EEREC_S); - } - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 2 ] ); - MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 2 ] ); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EAX ); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], ECX ); - - MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 3 ] ); - MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 3 ] ); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 3 ], EAX ); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 2 ], ECX ); -} - -//////////////////////////////////////////////////// -void recPMINH( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D == EEREC_S ) SSE2_PMINSW_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE2_PMINSW_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PMINSW_XMM_to_XMM(EEREC_D, EEREC_T); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - SSE_PMINSW_MM_to_MM( t0reg, t2reg ); - SSE_PMINSW_MM_to_MM( t1reg, t3reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPCEQB( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D == EEREC_S ) SSE2_PCMPEQB_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE2_PCMPEQB_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PCMPEQB_XMM_to_XMM(EEREC_D, EEREC_T); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PCMPEQBRtoR( t0reg, t2reg ); - PCMPEQBRtoR( t1reg, t3reg ); - - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPCEQH( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D == EEREC_S ) SSE2_PCMPEQW_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE2_PCMPEQW_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PCMPEQW_XMM_to_XMM(EEREC_D, EEREC_T); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PCMPEQWRtoR( t0reg, t2reg ); - PCMPEQWRtoR( t1reg, t3reg ); - - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPCEQW( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D == EEREC_S ) SSE2_PCMPEQD_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE2_PCMPEQD_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PCMPEQD_XMM_to_XMM(EEREC_D, EEREC_T); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PCMPEQDRtoR( t0reg, t2reg ); - PCMPEQDRtoR( t1reg, t3reg ); - - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPADDUB( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|(_Rt_?XMMINFO_READT:0)|XMMINFO_WRITED) - if( _Rt_ ) { - if( EEREC_D == EEREC_S ) SSE2_PADDUSB_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE2_PADDUSB_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PADDUSB_XMM_to_XMM(EEREC_D, EEREC_T); - } - } - else SSE2_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PADDUSBRtoR( t0reg, t2reg ); - PADDUSBRtoR( t1reg, t3reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPADDUH( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D == EEREC_S ) SSE2_PADDUSW_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE2_PADDUSW_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PADDUSW_XMM_to_XMM(EEREC_D, EEREC_T); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP4( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PADDUSWRtoR( t0reg, t2reg ); - PADDUSWRtoR( t1reg, t3reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -#endif -/********************************************************* -* MMI2 opcodes * -* * -*********************************************************/ -#ifndef MMI2_RECOMPILE - -REC_FUNC_DEL( PMFHI, _Rd_); -REC_FUNC_DEL( PMFLO, _Rd_); -REC_FUNC_DEL( PCPYLD, _Rd_); -REC_FUNC_DEL( PAND, _Rd_); -REC_FUNC_DEL( PXOR, _Rd_); - -REC_FUNC_DEL( PMADDW, _Rd_); -REC_FUNC_DEL( PSLLVW, _Rd_); -REC_FUNC_DEL( PSRLVW, _Rd_); -REC_FUNC_DEL( PMSUBW, _Rd_); -REC_FUNC_DEL( PINTH, _Rd_); -REC_FUNC_DEL( PMULTW, _Rd_); -REC_FUNC_DEL( PDIVW, _Rd_); -REC_FUNC_DEL( PMADDH, _Rd_); -REC_FUNC_DEL( PHMADH, _Rd_); -REC_FUNC_DEL( PMSUBH, _Rd_); -REC_FUNC_DEL( PHMSBH, _Rd_); -REC_FUNC_DEL( PEXEH, _Rd_); -REC_FUNC_DEL( PREVH, _Rd_); -REC_FUNC_DEL( PMULTH, _Rd_); -REC_FUNC_DEL( PDIVBW, _Rd_); -REC_FUNC_DEL( PEXEW, _Rd_); -REC_FUNC_DEL( PROT3W, _Rd_ ); - -#else - -//////////////////////////////////////////////////// -void recPMADDW() -{ - EEINST_SETSIGNEXT(_Rs_); - EEINST_SETSIGNEXT(_Rt_); - if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); - recCall( Interp::PMADDW, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPSLLVW() -{ - recCall( Interp::PSLLVW, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPSRLVW() -{ - recCall( Interp::PSRLVW, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPMSUBW() -{ - EEINST_SETSIGNEXT(_Rs_); - EEINST_SETSIGNEXT(_Rt_); - if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); -//CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED|XMMINFO_WRITELO|XMMINFO_WRITEHI|XMMINFO_READLO|XMMINFO_READHI) -// int t0reg = _allocTempXMMreg(XMMT_INT, -1); -// -// if( EEREC_D == EEREC_S ) SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_T); -// else if( EEREC_D == EEREC_T ) SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_S); -// else { -// SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); -// SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_T); -// } -// -// // add from LO/HI -// SSE_SHUFPS_XMM_to_XMM(EEREC_LO, EEREC_HI, 0x88); -// SSE2_PSHUFD_XMM_to_XMM(EEREC_LO, EEREC_LO, 0xd8); -// SSE2_PSUBQ_XMM_to_XMM(EEREC_LO, EEREC_D); -// -// // get the signs -// SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_LO); -// SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_LO); -// SSE2_PSRAD_I8_to_XMM(t0reg, 31); -// -// // interleave -// SSE2_PSHUFD_XMM_to_XMM(EEREC_LO, EEREC_LO, 0xd8); -// SSE2_PSHUFD_XMM_to_XMM(t0reg, t0reg, 0xd8); -// SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_LO); -// -// SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_LO, t0reg); -// SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_HI, t0reg); -// -// _freeXMMreg(t0reg); -//CPU_SSE_XMMCACHE_END - - recCall( Interp::PMSUBW, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPMULTW() -{ - EEINST_SETSIGNEXT(_Rs_); - EEINST_SETSIGNEXT(_Rt_); - if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); - recCall( Interp::PMULTW, _Rd_ ); -} -//////////////////////////////////////////////////// -void recPDIVW() -{ - EEINST_SETSIGNEXT(_Rs_); - EEINST_SETSIGNEXT(_Rt_); - recCall( Interp::PDIVW, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPDIVBW() -{ - recCall( Interp::PDIVBW, _Rd_ ); //-- -} - -//////////////////////////////////////////////////// -PCSX2_ALIGNED16(int s_mask1[4]) = {~0, 0, ~0, 0}; - -void recPHMADH() -{ -CPU_SSE2_XMMCACHE_START((_Rd_?XMMINFO_WRITED:0)|XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITELO|XMMINFO_WRITEHI) - int t0reg = _Rd_ ? EEREC_D : _allocTempXMMreg(XMMT_INT, -1); - - if( t0reg == EEREC_S ) { - - SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, EEREC_S); - - if( t0reg == EEREC_T ) { - SSE2_PMULHW_XMM_to_XMM(EEREC_LO, EEREC_T); - SSE2_PMULLW_XMM_to_XMM(t0reg, EEREC_T); - } - else { - SSE2_PMULLW_XMM_to_XMM(t0reg, EEREC_T); - SSE2_PMULHW_XMM_to_XMM(EEREC_LO, EEREC_T); - } - SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, t0reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); - SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, EEREC_T); - - SSE2_PMULLW_XMM_to_XMM(t0reg, EEREC_S); - SSE2_PMULHW_XMM_to_XMM(EEREC_LO, EEREC_S); - SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, t0reg); - } - - // 0-3 - SSE2_PUNPCKLWD_XMM_to_XMM(t0reg, EEREC_LO); - // 4-7 - SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_HI, EEREC_LO); - - SSE2_PSHUFD_XMM_to_XMM(t0reg, t0reg, 0xd8); // 0,2,1,3, L->H - SSE2_PSHUFD_XMM_to_XMM(EEREC_HI, EEREC_HI, 0xd8); // 4,6,5,7, L->H - SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, t0reg); - - SSE2_PUNPCKLQDQ_XMM_to_XMM(t0reg, EEREC_HI); - SSE2_PUNPCKHQDQ_XMM_to_XMM(EEREC_LO, EEREC_HI); - - SSE2_PADDD_XMM_to_XMM(EEREC_LO, t0reg); - - if( _Rd_ ) { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_LO); - } - - SSE2_PSHUFD_XMM_to_XMM(EEREC_HI, EEREC_LO, 0xf5); - - SSE2_PAND_M128_to_XMM(EEREC_LO, (uptr)s_mask1); - SSE2_PAND_M128_to_XMM(EEREC_HI, (uptr)s_mask1); - - if( !_Rd_ ) _freeXMMreg(t0reg); - -CPU_SSE_XMMCACHE_END - - recCall( Interp::PHMADH, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPMSUBH() -{ - CPU_SSE2_XMMCACHE_START((_Rd_?XMMINFO_WRITED:0)|XMMINFO_READS|XMMINFO_READT|XMMINFO_READLO|XMMINFO_READHI|XMMINFO_WRITELO|XMMINFO_WRITEHI) - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - int t1reg = _allocTempXMMreg(XMMT_INT, -1); - - if( !_Rd_ ) { - SSE2_PXOR_XMM_to_XMM(t0reg, t0reg); - SSE2_PSHUFD_XMM_to_XMM(t1reg, EEREC_S, 0xd8); //S0, S1, S4, S5, S2, S3, S6, S7 - SSE2_PUNPCKLWD_XMM_to_XMM(t1reg, t0reg); //S0, 0, S1, 0, S4, 0, S5, 0 - SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_T, 0xd8); //T0, T1, T4, T5, T2, T3, T6, T7 - SSE2_PUNPCKLWD_XMM_to_XMM(t0reg, t0reg); //T0, T0, T1, T1, T4, T4, T5, T5 - SSE2_PMADDWD_XMM_to_XMM(t0reg, t1reg); //S0*T0+0*T0, S1*T1+0*T1, S4*T4+0*T4, S5*T5+0*T5 - - SSE2_PSUBD_XMM_to_XMM(EEREC_LO, t0reg); - - SSE2_PXOR_XMM_to_XMM(t0reg, t0reg); - SSE2_PSHUFD_XMM_to_XMM(t1reg, EEREC_S, 0xd8); //S0, S1, S4, S5, S2, S3, S6, S7 - SSE2_PUNPCKHWD_XMM_to_XMM(t1reg, t0reg); //S2, 0, S3, 0, S6, 0, S7, 0 - SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_T, 0xd8); //T0, T1, T4, T5, T2, T3, T6, T7 - SSE2_PUNPCKHWD_XMM_to_XMM(t0reg, t0reg); //T2, T2, T3, T3, T6, T6, T7, T7 - SSE2_PMADDWD_XMM_to_XMM(t0reg, t1reg); //S2*T2+0*T2, S3*T3+0*T3, S6*T6+0*T6, S7*T7+0*T7 - - SSE2_PSUBD_XMM_to_XMM(EEREC_HI, t0reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); - SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_S); - - SSE2_PMULLW_XMM_to_XMM(t0reg, EEREC_T); - SSE2_PMULHW_XMM_to_XMM(t1reg, EEREC_T); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, t0reg); - - // 0-3 - SSE2_PUNPCKLWD_XMM_to_XMM(t0reg, t1reg); - // 4-7 - SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, t1reg); - SSEX_MOVDQA_XMM_to_XMM(t1reg, t0reg); - - // 0,1,4,5, L->H - SSE2_PUNPCKLQDQ_XMM_to_XMM(t0reg, EEREC_D); - // 2,3,6,7, L->H - SSE2_PUNPCKHQDQ_XMM_to_XMM(t1reg, EEREC_D); - - SSE2_PSUBD_XMM_to_XMM(EEREC_LO, t0reg); - SSE2_PSUBD_XMM_to_XMM(EEREC_HI, t1reg); - - // 0,2,4,6, L->H - SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_LO, 0x88); - SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_HI, 0x88); - SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, t0reg); - } - - _freeXMMreg(t0reg); - _freeXMMreg(t1reg); - -CPU_SSE_XMMCACHE_END - recCall( Interp::PMSUBH, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPHMSBH() -{ -CPU_SSE2_XMMCACHE_START((_Rd_?XMMINFO_WRITED:0)|XMMINFO_READS|XMMINFO_READT|XMMINFO_READLO|XMMINFO_READHI|XMMINFO_WRITELO|XMMINFO_WRITEHI) - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); - SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, EEREC_S); - - SSE2_PMULLW_XMM_to_XMM(t0reg, EEREC_T); - SSE2_PMULHW_XMM_to_XMM(EEREC_LO, EEREC_T); - SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, t0reg); - - // 0-3 - SSE2_PUNPCKLWD_XMM_to_XMM(t0reg, EEREC_LO); - // 4-7 - SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_HI, EEREC_LO); - - SSE2_PSHUFD_XMM_to_XMM(t0reg, t0reg, 0xd8); // 0,2,1,3, L->H - SSE2_PSHUFD_XMM_to_XMM(EEREC_HI, EEREC_HI, 0xd8); // 4,6,5,7, L->H - SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, t0reg); - - SSE2_PUNPCKLDQ_XMM_to_XMM(t0reg, EEREC_HI); - SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_LO, EEREC_HI); - - SSE2_PSUBD_XMM_to_XMM(EEREC_LO, t0reg); - - if( _Rd_ ) { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_LO); - } - - SSE2_PSHUFD_XMM_to_XMM(EEREC_HI, EEREC_LO, 0xf5); - - _freeXMMreg(t0reg); - -CPU_SSE_XMMCACHE_END - - recCall( Interp::PHMSBH, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPEXEH( void ) -{ - if (!_Rd_) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) - SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_T, 0xc6); - SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0xc6); -CPU_SSE_XMMCACHE_END - - recCall( Interp::PEXEH, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPREVH( void ) -{ - if (!_Rd_) return; - - -CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) - SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_T, 0x1B); - SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0x1B); -CPU_SSE_XMMCACHE_END - - recCall( Interp::PREVH, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPINTH( void ) -{ - if (!_Rd_) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - if( EEREC_D == EEREC_S ) { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSE_MOVHLPS_XMM_to_XMM(t0reg, EEREC_S); - if( EEREC_D != EEREC_T ) SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PUNPCKLWD_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } - else { - SSE_MOVLHPS_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, EEREC_S); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - //Done - Refraction - MOV16MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[4]); - MOV16MtoR( EBX, (uptr)&cpuRegs.GPR.r[_Rt_].US[1]); - MOV16MtoR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].US[2]); - MOV16MtoR( EDX, (uptr)&cpuRegs.GPR.r[_Rt_].US[0]); - - MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[1], EAX); - MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[2], EBX); - MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[4], ECX); - MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[0], EDX); - - MOV16MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[5]); - MOV16MtoR( EBX, (uptr)&cpuRegs.GPR.r[_Rs_].US[6]); - MOV16MtoR( ECX, (uptr)&cpuRegs.GPR.r[_Rs_].US[7]); - MOV16MtoR( EDX, (uptr)&cpuRegs.GPR.r[_Rt_].US[3]); - - MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[3], EAX); - MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[5], EBX); - MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[7], ECX); - MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[6], EDX); -} - -void recPEXEW( void ) -{ - if (!_Rd_) return; - -CPU_SSE_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) - SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_T, 0xc6); -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[2]); - MOV32MtoR( EBX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[1]); - MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); - MOV32MtoR( EDX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[3]); - - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[1], EBX); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[2], ECX); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[3], EDX); -} - -void recPROT3W( void ) -{ - if (!_Rd_) return; - -CPU_SSE_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) - SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_T, 0xc9); -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[1]); - MOV32MtoR( EBX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[2]); - MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); - MOV32MtoR( EDX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[3]); - - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[1], EBX); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[2], ECX); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[3], EDX); -} - -void recPMULTH( void ) -{ -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|(_Rd_?XMMINFO_WRITED:0)|XMMINFO_WRITELO|XMMINFO_WRITEHI) - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - - SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, EEREC_S); - SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_S); - - SSE2_PMULLW_XMM_to_XMM(EEREC_LO, EEREC_T); - SSE2_PMULHW_XMM_to_XMM(EEREC_HI, EEREC_T); - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_LO); - - // 0-3 - SSE2_PUNPCKLWD_XMM_to_XMM(EEREC_LO, EEREC_HI); - // 4-7 - SSE2_PUNPCKHWD_XMM_to_XMM(t0reg, EEREC_HI); - - if( _Rd_ ) { - // 0,2,4,6, L->H - SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_LO, 0x88); - SSE2_PSHUFD_XMM_to_XMM(EEREC_HI, t0reg, 0x88); - SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, EEREC_HI); - } - - SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_LO); - - // 0,1,4,5, L->H - SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_LO, t0reg); - // 2,3,6,7, L->H - SSE2_PUNPCKHQDQ_XMM_to_XMM(EEREC_HI, t0reg); - - _freeXMMreg(t0reg); -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - _deleteEEreg(XMMGPR_LO, 0); - _deleteEEreg(XMMGPR_HI, 0); - _deleteGPRtoXMMreg(_Rs_, 1); - _deleteGPRtoXMMreg(_Rt_, 1); - - if(!_Rt_ || !_Rs_) { - MOV32ItoM( (uptr)&cpuRegs.LO.UL[0], 0); - MOV32ItoM( (uptr)&cpuRegs.LO.UL[1], 0); - MOV32ItoM( (uptr)&cpuRegs.LO.UL[2], 0); - MOV32ItoM( (uptr)&cpuRegs.LO.UL[3], 0); - MOV32ItoM( (uptr)&cpuRegs.HI.UL[0], 0); - MOV32ItoM( (uptr)&cpuRegs.HI.UL[1], 0); - MOV32ItoM( (uptr)&cpuRegs.HI.UL[2], 0); - MOV32ItoM( (uptr)&cpuRegs.HI.UL[3], 0); - - if( _Rd_ ) { - MOV32ItoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[0], 0); - MOV32ItoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[1], 0); - MOV32ItoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[2], 0); - MOV32ItoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[3], 0); - } - return; - } - - //Done - Refraction - MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[0]); - MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[0]); - IMUL32RtoR( EAX, ECX); - MOV32RtoM( (uptr)&cpuRegs.LO.UL[0], EAX); - - MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[1]); - MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[1]); - IMUL32RtoR( EAX, ECX); - MOV32RtoM( (uptr)&cpuRegs.LO.UL[1], EAX); - - MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[2]); - MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[2]); - IMUL32RtoR( EAX, ECX); - MOV32RtoM( (uptr)&cpuRegs.HI.UL[0], EAX); - - MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[3]); - MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[3]); - IMUL32RtoR( EAX, ECX); - MOV32RtoM( (uptr)&cpuRegs.HI.UL[1], EAX); - - MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[4]); - MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[4]); - IMUL32RtoR( EAX, ECX); - MOV32RtoM( (uptr)&cpuRegs.LO.UL[2], EAX); - - MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[5]); - MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[5]); - IMUL32RtoR( EAX, ECX); - MOV32RtoM( (uptr)&cpuRegs.LO.UL[3], EAX); - - MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[6]); - MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[6]); - IMUL32RtoR( EAX, ECX); - MOV32RtoM( (uptr)&cpuRegs.HI.UL[2], EAX); - - MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[7]); - MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[7]); - IMUL32RtoR( EAX, ECX); - MOV32RtoM( (uptr)&cpuRegs.HI.UL[3], EAX); - - if (_Rd_) { - MOV32MtoR( EAX, (uptr)&cpuRegs.LO.UL[0]); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); - MOV32MtoR( EAX, (uptr)&cpuRegs.HI.UL[0]); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[1], EAX); - MOV32MtoR( EAX, (uptr)&cpuRegs.LO.UL[2]); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[2], EAX); - MOV32MtoR( EAX, (uptr)&cpuRegs.HI.UL[2]); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[3], EAX); - } -} - -void recPMFHI( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE_XMMCACHE_START(XMMINFO_WRITED|XMMINFO_READHI) - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_HI); -CPU_SSE_XMMCACHE_END - - MMX_ALLOC_TEMP2( - MOVQMtoR( t0reg, (uptr)&cpuRegs.HI.UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.HI.UD[ 1 ] ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPMFLO( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE_XMMCACHE_START(XMMINFO_WRITED|XMMINFO_READLO) - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_LO); -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP2( - MOVQMtoR( t0reg, (uptr)&cpuRegs.LO.UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.LO.UD[ 1 ] ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPAND( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE_XMMCACHE_START(XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT) - if( EEREC_D == EEREC_T ) { - SSEX_PAND_XMM_to_XMM(EEREC_D, EEREC_S); - } - else if( EEREC_D == EEREC_S ) { - SSEX_PAND_XMM_to_XMM(EEREC_D, EEREC_T); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSEX_PAND_XMM_to_XMM(EEREC_D, EEREC_T); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP2( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - PANDMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - PANDMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPXOR( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE_XMMCACHE_START(XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT) - if( EEREC_D == EEREC_T ) { - SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_S); - } - else if( EEREC_D == EEREC_S ) { - SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_T); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_T); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP2( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - PXORMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - PXORMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPCPYLD( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE_XMMCACHE_START(XMMINFO_WRITED|(( _Rs_== 0) ? 0:XMMINFO_READS)|XMMINFO_READT) - if( _Rs_ == 0 ) { - SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_T); - } - else { - if( EEREC_D == EEREC_T ) SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, EEREC_S); - else if( EEREC_S == EEREC_T ) SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_S, 0x44); - else if( EEREC_D == EEREC_S ) { - SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_D, 0x4e); - } - else { - SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, EEREC_S); - } - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP2( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t1reg ); - SetMMXstate(); - ) -} - -void recPMADDH( void ) -{ - CPU_SSE2_XMMCACHE_START((_Rd_?XMMINFO_WRITED:0)|XMMINFO_READS|XMMINFO_READT|XMMINFO_READLO|XMMINFO_READHI|XMMINFO_WRITELO|XMMINFO_WRITEHI) - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - int t1reg = _allocTempXMMreg(XMMT_INT, -1); - - if( !_Rd_ ) { - SSE2_PXOR_XMM_to_XMM(t0reg, t0reg); - SSE2_PSHUFD_XMM_to_XMM(t1reg, EEREC_S, 0xd8); //S0, S1, S4, S5, S2, S3, S6, S7 - SSE2_PUNPCKLWD_XMM_to_XMM(t1reg, t0reg); //S0, 0, S1, 0, S4, 0, S5, 0 - SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_T, 0xd8); //T0, T1, T4, T5, T2, T3, T6, T7 - SSE2_PUNPCKLWD_XMM_to_XMM(t0reg, t0reg); //T0, T0, T1, T1, T4, T4, T5, T5 - SSE2_PMADDWD_XMM_to_XMM(t0reg, t1reg); //S0*T0+0*T0, S1*T1+0*T1, S4*T4+0*T4, S5*T5+0*T5 - - SSE2_PADDD_XMM_to_XMM(EEREC_LO, t0reg); - - SSE2_PXOR_XMM_to_XMM(t0reg, t0reg); - SSE2_PSHUFD_XMM_to_XMM(t1reg, EEREC_S, 0xd8); //S0, S1, S4, S5, S2, S3, S6, S7 - SSE2_PUNPCKHWD_XMM_to_XMM(t1reg, t0reg); //S2, 0, S3, 0, S6, 0, S7, 0 - SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_T, 0xd8); //T0, T1, T4, T5, T2, T3, T6, T7 - SSE2_PUNPCKHWD_XMM_to_XMM(t0reg, t0reg); //T2, T2, T3, T3, T6, T6, T7, T7 - SSE2_PMADDWD_XMM_to_XMM(t0reg, t1reg); //S2*T2+0*T2, S3*T3+0*T3, S6*T6+0*T6, S7*T7+0*T7 - - SSE2_PADDD_XMM_to_XMM(EEREC_HI, t0reg); - } - else { - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); - SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_S); - - SSE2_PMULLW_XMM_to_XMM(t0reg, EEREC_T); - SSE2_PMULHW_XMM_to_XMM(t1reg, EEREC_T); - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, t0reg); - - // 0-3 - SSE2_PUNPCKLWD_XMM_to_XMM(t0reg, t1reg); - // 4-7 - SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, t1reg); - SSEX_MOVDQA_XMM_to_XMM(t1reg, t0reg); - - // 0,1,4,5, L->H - SSE2_PUNPCKLQDQ_XMM_to_XMM(t0reg, EEREC_D); - // 2,3,6,7, L->H - SSE2_PUNPCKHQDQ_XMM_to_XMM(t1reg, EEREC_D); - - SSE2_PADDD_XMM_to_XMM(EEREC_LO, t0reg); - SSE2_PADDD_XMM_to_XMM(EEREC_HI, t1reg); - - // 0,2,4,6, L->H - SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_LO, 0x88); - SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_HI, 0x88); - SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, t0reg); - } - - _freeXMMreg(t0reg); - _freeXMMreg(t1reg); - -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - _deleteEEreg(XMMGPR_LO, 1); - _deleteEEreg(XMMGPR_HI, 1); - _deleteGPRtoXMMreg(_Rs_, 1); - _deleteGPRtoXMMreg(_Rt_, 1); - - if(_Rt_ && _Rs_){ - - MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[0]); - MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[0]); - IMUL32RtoR( EAX, ECX); - ADD32RtoM( (uptr)&cpuRegs.LO.UL[0], EAX); - - MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[1]); - MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[1]); - IMUL32RtoR( EAX, ECX); - ADD32RtoM( (uptr)&cpuRegs.LO.UL[1], EAX); - - MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[2]); - MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[2]); - IMUL32RtoR( EAX, ECX); - ADD32RtoM( (uptr)&cpuRegs.HI.UL[0], EAX); - - MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[3]); - MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[3]); - IMUL32RtoR( EAX, ECX); - ADD32RtoM( (uptr)&cpuRegs.HI.UL[1], EAX); - - MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[4]); - MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[4]); - IMUL32RtoR( EAX, ECX); - ADD32RtoM( (uptr)&cpuRegs.LO.UL[2], EAX); - - MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[5]); - MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[5]); - IMUL32RtoR( EAX, ECX); - ADD32RtoM( (uptr)&cpuRegs.LO.UL[3], EAX); - - MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[6]); - MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[6]); - IMUL32RtoR( EAX, ECX); - ADD32RtoM( (uptr)&cpuRegs.HI.UL[2], EAX); - - MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[7]); - MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[7]); - IMUL32RtoR( EAX, ECX); - ADD32RtoM( (uptr)&cpuRegs.HI.UL[3], EAX); - - } - - if (_Rd_) { - MOV32MtoR( EAX, (uptr)&cpuRegs.LO.UL[0]); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); - MOV32MtoR( EAX, (uptr)&cpuRegs.HI.UL[0]); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[1], EAX); - MOV32MtoR( EAX, (uptr)&cpuRegs.LO.UL[2]); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[2], EAX); - MOV32MtoR( EAX, (uptr)&cpuRegs.HI.UL[2]); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[3], EAX); - } -} - -#endif -/********************************************************* -* MMI3 opcodes * -* * -*********************************************************/ -#ifndef MMI3_RECOMPILE - -REC_FUNC_DEL( PMADDUW, _Rd_); -REC_FUNC_DEL( PSRAVW, _Rd_); -REC_FUNC_DEL( PMTHI, _Rd_); -REC_FUNC_DEL( PMTLO, _Rd_); -REC_FUNC_DEL( PINTEH, _Rd_); -REC_FUNC_DEL( PMULTUW, _Rd_); -REC_FUNC_DEL( PDIVUW, _Rd_); -REC_FUNC_DEL( PCPYUD, _Rd_); -REC_FUNC_DEL( POR, _Rd_); -REC_FUNC_DEL( PNOR, _Rd_); -REC_FUNC_DEL( PCPYH, _Rd_); -REC_FUNC_DEL( PEXCW, _Rd_); -REC_FUNC_DEL( PEXCH, _Rd_); - -#else - -//////////////////////////////////////////////////// -//REC_FUNC( PSRAVW, _Rd_ ); - -void recPSRAVW( void ) -{ - MOV32ItoM( (uptr)&cpuRegs.code, (u32)cpuRegs.code ); - MOV32ItoM( (uptr)&cpuRegs.pc, (u32)pc ); - iFlushCall(FLUSH_EVERYTHING); - if( _Rd_ > 0 ) _deleteEEreg(_Rd_, 0); - CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::MMI::PSRAVW ); -} - - -//////////////////////////////////////////////////// -PCSX2_ALIGNED16(u32 s_tempPINTEH[4]) = {0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff }; - -void recPINTEH() -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START((_Rs_?XMMINFO_READS:0)|(_Rt_?XMMINFO_READT:0)|XMMINFO_WRITED) - - int t0reg = -1; - - if( _Rs_ == 0 ) { - if( _Rt_ == 0 ) { - SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_D); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - SSE2_PAND_M128_to_XMM(EEREC_D, (uptr)s_tempPINTEH); - } - } - else if( _Rt_ == 0 ) { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PSLLD_I8_to_XMM(EEREC_D, 16); - } - else { - if( EEREC_S == EEREC_T ) { - SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_S, 0xa0); - SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0xa0); - } - else if( EEREC_D == EEREC_T ) { - assert( EEREC_D != EEREC_S ); - t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSE2_PSLLD_I8_to_XMM(EEREC_D, 16); - SSE2_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); - SSE2_PSRLD_I8_to_XMM(EEREC_D, 16); - SSE2_PSLLD_I8_to_XMM(t0reg, 16); - SSE2_POR_XMM_to_XMM(EEREC_D, t0reg); - } - else { - t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSE2_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); - SSE2_PSLLD_I8_to_XMM(t0reg, 16); - SSE2_PSLLD_I8_to_XMM(EEREC_D, 16); - SSE2_PSRLD_I8_to_XMM(t0reg, 16); - SSE2_POR_XMM_to_XMM(EEREC_D, t0reg); - } - } - - if( t0reg >= 0 ) _freeXMMreg(t0reg); -CPU_SSE_XMMCACHE_END - - recCall( Interp::PINTEH, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPMULTUW() -{ -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED|XMMINFO_WRITELO|XMMINFO_WRITEHI) - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - EEINST_SETSIGNEXT(_Rs_); - EEINST_SETSIGNEXT(_Rt_); - if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); - - if( EEREC_D == EEREC_S ) SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_T); - } - - // get the signs - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_D); - SSE2_PSRAD_I8_to_XMM(t0reg, 31); - - // interleave - SSE2_PSHUFD_XMM_to_XMM(EEREC_LO, EEREC_D, 0xd8); - SSE2_PSHUFD_XMM_to_XMM(t0reg, t0reg, 0xd8); - SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_LO); - - SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_LO, t0reg); - SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_HI, t0reg); - - _freeXMMreg(t0reg); -CPU_SSE_XMMCACHE_END - recCall( Interp::PMULTUW, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPMADDUW() -{ -CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED|XMMINFO_WRITELO|XMMINFO_WRITEHI|XMMINFO_READLO|XMMINFO_READHI) - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - EEINST_SETSIGNEXT(_Rs_); - EEINST_SETSIGNEXT(_Rt_); - - if( EEREC_D == EEREC_S ) SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_T); - } - - // add from LO/HI - SSE2_PSHUFD_XMM_to_XMM(EEREC_LO, EEREC_LO, 0x88); - SSE2_PSHUFD_XMM_to_XMM(EEREC_HI, EEREC_HI, 0x88); - SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_LO, EEREC_HI); - SSE2_PADDQ_XMM_to_XMM(EEREC_D, EEREC_LO); - - // get the signs - SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_D); - SSE2_PSRAD_I8_to_XMM(t0reg, 31); - - // interleave - SSE2_PSHUFD_XMM_to_XMM(EEREC_LO, EEREC_D, 0xd8); - SSE2_PSHUFD_XMM_to_XMM(t0reg, t0reg, 0xd8); - SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_LO); - - SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_LO, t0reg); - SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_HI, t0reg); - - _freeXMMreg(t0reg); -CPU_SSE_XMMCACHE_END - - recCall( Interp::PMADDUW, _Rd_ ); -} - -//////////////////////////////////////////////////// -//do EEINST_SETSIGNEXT -void recPDIVUW() -{ - recCall( Interp::PDIVUW, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPEXCW() -{ - if (!_Rd_) return; - -CPU_SSE_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) - SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_T, 0xd8); -CPU_SSE_XMMCACHE_END - -recCall( Interp::PEXCW, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPEXCH( void ) -{ - if (!_Rd_) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) - SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_T, 0xd8); - SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0xd8); -CPU_SSE_XMMCACHE_END - - recCall( Interp::PEXCH, _Rd_ ); -} - -//////////////////////////////////////////////////// -void recPNOR( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|(_Rt_!=0?XMMINFO_READT:0)|XMMINFO_WRITED) - - if( _Rs_ == 0 ) { - if( _Rt_ == 0 ) { - SSE2_PCMPEQD_XMM_to_XMM( EEREC_D, EEREC_D ); - } - else { - if( EEREC_D == EEREC_T ) { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSE2_PCMPEQD_XMM_to_XMM( t0reg, t0reg); - SSEX_PXOR_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } - else { - SSE2_PCMPEQD_XMM_to_XMM( EEREC_D, EEREC_D ); - if( _Rt_ != 0 ) SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_T); - } - } - } - else if( _Rt_ == 0 ) { - if( EEREC_D == EEREC_S ) { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSE2_PCMPEQD_XMM_to_XMM( t0reg, t0reg); - SSEX_PXOR_XMM_to_XMM(EEREC_D, t0reg); - _freeXMMreg(t0reg); - } - else { - SSE2_PCMPEQD_XMM_to_XMM( EEREC_D, EEREC_D ); - SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_S); - } - } - else { - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - - if( EEREC_D == EEREC_S ) SSEX_POR_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSEX_POR_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - if( EEREC_S != EEREC_T ) SSEX_POR_XMM_to_XMM(EEREC_D, EEREC_T); - } - - SSE2_PCMPEQD_XMM_to_XMM( t0reg, t0reg ); - SSEX_PXOR_XMM_to_XMM( EEREC_D, t0reg ); - _freeXMMreg(t0reg); - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP3( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - PORMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - PORMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - PCMPEQDRtoR( t2reg, t2reg ); - PXORRtoR( t0reg, t2reg ); - PXORRtoR( t1reg, t2reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPMTHI( void ) -{ -CPU_SSE_XMMCACHE_START(XMMINFO_READS|XMMINFO_WRITEHI) - SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_S); -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(XMMGPR_HI, 0); - - MMX_ALLOC_TEMP2( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQRtoM( (uptr)&cpuRegs.HI.UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.HI.UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPMTLO( void ) -{ -CPU_SSE_XMMCACHE_START(XMMINFO_READS|XMMINFO_WRITELO) - SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, EEREC_S); -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(XMMGPR_LO, 0); - _deleteGPRtoXMMreg(_Rs_, 1); - - MMX_ALLOC_TEMP2( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQRtoM( (uptr)&cpuRegs.LO.UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.LO.UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPCPYUD( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE_XMMCACHE_START(XMMINFO_READS|(( _Rt_ == 0) ? 0:XMMINFO_READT)|XMMINFO_WRITED) - - if( _Rt_ == 0 ) { - if( EEREC_D == EEREC_S ) { - SSE2_PUNPCKHQDQ_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_D); - } - else { - SSE_MOVHLPS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_D); - } - } - else { - if( EEREC_D == EEREC_S ) SSE2_PUNPCKHQDQ_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) { - //TODO - SSE2_PUNPCKHQDQ_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_D, 0x4e); - } - else { - if( EEREC_S == EEREC_T ) { - SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_S, 0xee); - } - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - SSE2_PUNPCKHQDQ_XMM_to_XMM(EEREC_D, EEREC_T); - } - } - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP2( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPOR( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|(_Rt_!=0?XMMINFO_READT:0)|XMMINFO_WRITED) - - if( _Rs_ == 0 ) { - if( _Rt_ == 0 ) { - SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_D); - } - else SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - } - else if( _Rt_ == 0 ) { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - } - else { - if( EEREC_D == EEREC_S ) { - SSEX_POR_XMM_to_XMM(EEREC_D, EEREC_T); - } - else if( EEREC_D == EEREC_T ) { - SSEX_POR_XMM_to_XMM(EEREC_D, EEREC_S); - } - else { - if( _Rs_ == 0 ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - else if( _Rt_ == 0 ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); - if( EEREC_S != EEREC_T ) { - SSEX_POR_XMM_to_XMM(EEREC_D, EEREC_S); - } - } - } - } -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - MMX_ALLOC_TEMP2( - MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); - if ( _Rt_ != 0 ) - { - PORMtoR ( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - PORMtoR ( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - } - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); - MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); - SetMMXstate(); - ) -} - -//////////////////////////////////////////////////// -void recPCPYH( void ) -{ - if ( ! _Rd_ ) return; - -CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) - SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_T, 0); - SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0); -CPU_SSE_XMMCACHE_END - - _flushCachedRegs(); - _deleteEEreg(_Rd_, 0); - - //PUSH32R( EBX ); - MOVZX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - MOV32RtoR( ECX, EAX ); - SHL32ItoR( ECX, 16 ); - OR32RtoR( EAX, ECX ); - MOVZX32M16toR( EDX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); - MOV32RtoR( ECX, EDX ); - SHL32ItoR( ECX, 16 ); - OR32RtoR( EDX, ECX ); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EAX ); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 2 ], EDX ); - MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 3 ], EDX ); - //POP32R( EBX ); -} - -#endif // else MMI3_RECOMPILE - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +/********************************************************* +* cached MMI opcodes * +* * +*********************************************************/ + +#include "PrecompiledHeader.h" + +#include "Common.h" +#include "R5900OpcodeTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "iMMI.h" + +namespace Interp = R5900::Interpreter::OpcodeImpl::MMI; + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl { +namespace MMI +{ + +#ifndef MMI_RECOMPILE + +REC_FUNC_DEL( PLZCW, _Rd_ ); + +REC_FUNC_DEL( PMFHL, _Rd_ ); +REC_FUNC_DEL( PMTHL, _Rd_ ); + +REC_FUNC_DEL( PSRLW, _Rd_ ); +REC_FUNC_DEL( PSRLH, _Rd_ ); + +REC_FUNC_DEL( PSRAH, _Rd_ ); +REC_FUNC_DEL( PSRAW, _Rd_ ); + +REC_FUNC_DEL( PSLLH, _Rd_ ); +REC_FUNC_DEL( PSLLW, _Rd_ ); + +#else + +void recPLZCW() +{ + int regd = -1; + int regs = 0; + + if ( ! _Rd_ ) return; + + if( GPR_IS_CONST1(_Rs_) ) { + _eeOnWriteReg(_Rd_, 0); + _deleteEEreg(_Rd_, 0); + GPR_SET_CONST(_Rd_); + + for(regs = 0; regs < 2; ++regs) { + u32 val = g_cpuConstRegs[_Rs_].UL[regs]; + + if( val != 0 ) { + u32 setbit = val&0x80000000; + g_cpuConstRegs[_Rd_].UL[regs] = 0; + val <<= 1; + + while((val & 0x80000000) == setbit) { + g_cpuConstRegs[_Rd_].UL[regs]++; + val <<= 1; + } + } + else { + g_cpuConstRegs[_Rd_].UL[regs] = 31; + } + } + return; + } + + _eeOnWriteReg(_Rd_, 0); + + if( (regs = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ)) >= 0 ) { + SSE2_MOVD_XMM_to_R(EAX, regs); + regs |= MEM_XMMTAG; + } + else if( (regs = _checkMMXreg(MMX_GPR+_Rs_, MODE_READ)) >= 0 ) { + MOVD32MMXtoR(EAX, regs); + SetMMXstate(); + regs |= MEM_MMXTAG; + } + else { + MOV32MtoR(EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + regs = 0; + } + + if( EEINST_ISLIVE1(_Rd_) ) + _deleteEEreg(_Rd_, 0); + else { + if( (regd = _checkMMXreg(MMX_GPR+_Rd_, MODE_WRITE)) < 0 ) + _deleteEEreg(_Rd_, 0); + } + + // Count the number of leading bits (MSB) that match the sign bit, excluding the sign + // bit itself. + + // Strategy: If the sign bit is set, then negate the value. And that way the same + // bitcompare can be used for either bit status. but be warned! BSR returns undefined + // results if the EAX is zero, so we need to have special checks for zeros before + // using it. + + // --- first word --- + + MOV32ItoR(ECX,31); + TEST32RtoR(EAX, EAX); // TEST sets the sign flag accordingly. + u8* label_notSigned = JNS8(0); + NOT32R(EAX); + x86SetJ8(label_notSigned); + + BSRRtoR(EAX, EAX); + u8* label_Zeroed = JZ8(0); // If BSR sets the ZF, eax is "trash" + SUB32RtoR(ECX, EAX); + DEC32R(ECX); // PS2 doesn't count the first bit + + x86SetJ8(label_Zeroed); + if( EEINST_ISLIVE1(_Rd_) || regd < 0 ) { + MOV32RtoM((uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], ECX); + } + else { + SetMMXstate(); + MOVD32RtoMMX(regd, ECX); + } + + // second word + + if( EEINST_ISLIVE1(_Rd_) ) { + if( regs >= 0 && (regs & MEM_XMMTAG) ) { + SSE2_PSHUFD_XMM_to_XMM(regs&0xf, regs&0xf, 0x4e); + SSE2_MOVD_XMM_to_R(EAX, regs&0xf); + SSE2_PSHUFD_XMM_to_XMM(regs&0xf, regs&0xf, 0x4e); + } + else if( regs >= 0 && (regs & MEM_MMXTAG) ) { + PSHUFWRtoR(regs, regs, 0x4e); + MOVD32MMXtoR(EAX, regs&0xf); + PSHUFWRtoR(regs&0xf, regs&0xf, 0x4e); + SetMMXstate(); + } + else MOV32MtoR(EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + + MOV32ItoR(ECX, 31); + TEST32RtoR(EAX, EAX); // TEST sets the sign flag accordingly. + label_notSigned = JNS8(0); + NOT32R(EAX); + x86SetJ8(label_notSigned); + + BSRRtoR(EAX, EAX); + u8* label_Zeroed = JZ8(0); // If BSR sets the ZF, eax is "trash" + SUB32RtoR(ECX, EAX); + DEC32R(ECX); // PS2 doesn't count the first bit + + x86SetJ8(label_Zeroed); + MOV32RtoM((uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], ECX); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + } + + GPR_DEL_CONST(_Rd_); +} + +static u32 PCSX2_ALIGNED16(s_CmpMasks[]) = { 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff }; + +void recPMFHL() +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_WRITED|XMMINFO_READLO|XMMINFO_READHI) + + int t0reg; + + switch (_Sa_) { + case 0x00: // LW + + t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_HI, 0x88); + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_LO, 0x88); + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, t0reg); + + _freeXMMreg(t0reg); + break; + + case 0x01: // UW + t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_HI, 0xdd); + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_LO, 0xdd); + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + break; + + case 0x02: // SLW + // fall to interp + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + _deleteEEreg(XMMGPR_LO, 1); + _deleteEEreg(XMMGPR_HI, 1); + iFlushCall(FLUSH_CACHED_REGS); // since calling CALLFunc + CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::MMI::PMFHL ); + break; + + case 0x03: // LH + t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_PSHUFLW_XMM_to_XMM(t0reg, EEREC_HI, 0x88); + SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_LO, 0x88); + SSE2_PSHUFHW_XMM_to_XMM(t0reg, t0reg, 0x88); + SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0x88); + SSE2_PSRLDQ_I8_to_XMM(t0reg, 4); + SSE2_PSRLDQ_I8_to_XMM(EEREC_D, 4); + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + break; + + case 0x04: // SH + if( EEREC_D == EEREC_HI ) { + SSE2_PACKSSDW_XMM_to_XMM(EEREC_D, EEREC_LO); + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_D, 0x72); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_LO); + SSE2_PACKSSDW_XMM_to_XMM(EEREC_D, EEREC_HI); + + // shuffle so a1a0b1b0->a1b1a0b0 + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_D, 0xd8); + } + break; + default: + Console::Error("PMFHL?? *pcsx2 head esplode!*"); + assert(0); + } + +CPU_SSE_XMMCACHE_END + + recCall( Interp::PMFHL, _Rd_ ); +} + +void recPMTHL() +{ + recCall( Interp::PMTHL, 0 ); +} + +// MMX helper routines +#define MMX_ALLOC_TEMP1(code) { \ + int t0reg; \ + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + code; \ + _freeMMXreg(t0reg); \ +} \ + +#define MMX_ALLOC_TEMP2(code) { \ + int t0reg, t1reg; \ + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + t1reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + code; \ + _freeMMXreg(t0reg); \ + _freeMMXreg(t1reg); \ +} \ + +#define MMX_ALLOC_TEMP3(code) { \ + int t0reg, t1reg, t2reg; \ + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + t1reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + t2reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + code; \ + _freeMMXreg(t0reg); \ + _freeMMXreg(t1reg); \ + _freeMMXreg(t2reg); \ +} \ + +#define MMX_ALLOC_TEMP4(code) { \ + int t0reg, t1reg, t2reg, t3reg; \ + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + t1reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + t2reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + t3reg = _allocMMXreg(-1, MMX_TEMP, 0); \ + code; \ + _freeMMXreg(t0reg); \ + _freeMMXreg(t1reg); \ + _freeMMXreg(t2reg); \ + _freeMMXreg(t3reg); \ +} \ + +//////////////////////////////////////////////////// +void recPSRLH( void ) +{ + if ( !_Rd_ ) return; + + CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + if( (_Sa_&0xf) == 0 ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + return; + } + + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRLW_I8_to_XMM(EEREC_D,_Sa_&0xf ); + CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSRLWItoR( t0reg, _Sa_&0xf ); + PSRLWItoR( t1reg, _Sa_&0xf ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPSRLW( void ) +{ + if( !_Rd_ ) return; + + CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + if( _Sa_ == 0 ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + return; + } + + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRLD_I8_to_XMM(EEREC_D,_Sa_ ); + CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSRLDItoR( t0reg, _Sa_ ); + PSRLDItoR( t1reg, _Sa_ ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPSRAH( void ) +{ + if ( !_Rd_ ) return; + + CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + if( (_Sa_&0xf) == 0 ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + return; + } + + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRAW_I8_to_XMM(EEREC_D,_Sa_&0xf ); + CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSRAWItoR( t0reg, _Sa_&0xf ); + PSRAWItoR( t1reg, _Sa_&0xf ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPSRAW( void ) +{ + if ( !_Rd_ ) return; + + CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + if( _Sa_ == 0 ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + return; + } + + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRAD_I8_to_XMM(EEREC_D,_Sa_ ); + CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSRADItoR( t0reg, _Sa_ ); + PSRADItoR( t1reg, _Sa_ ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPSLLH( void ) +{ + if ( !_Rd_ ) return; + + CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + if( (_Sa_&0xf) == 0 ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + return; + } + + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSLLW_I8_to_XMM(EEREC_D,_Sa_&0xf ); + CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSLLWItoR( t0reg, _Sa_&0xf ); + PSLLWItoR( t1reg, _Sa_&0xf ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPSLLW( void ) +{ + if ( !_Rd_ ) return; + + CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + if( _Sa_ == 0 ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + return; + } + + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSLLD_I8_to_XMM(EEREC_D,_Sa_ ); + CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSLLDItoR( t0reg, _Sa_ ); + PSLLDItoR( t1reg, _Sa_ ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +/* +void recMADD( void ) +{ +} + +void recMADDU( void ) +{ +} + +void recPLZCW( void ) +{ +} +*/ + +#endif + +/********************************************************* +* MMI0 opcodes * +* * +*********************************************************/ +#ifndef MMI0_RECOMPILE + +REC_FUNC_DEL( PADDB, _Rd_); +REC_FUNC_DEL( PADDH, _Rd_); +REC_FUNC_DEL( PADDW, _Rd_); +REC_FUNC_DEL( PADDSB, _Rd_); +REC_FUNC_DEL( PADDSH, _Rd_); +REC_FUNC_DEL( PADDSW, _Rd_); +REC_FUNC_DEL( PSUBB, _Rd_); +REC_FUNC_DEL( PSUBH, _Rd_); +REC_FUNC_DEL( PSUBW, _Rd_); +REC_FUNC_DEL( PSUBSB, _Rd_); +REC_FUNC_DEL( PSUBSH, _Rd_); +REC_FUNC_DEL( PSUBSW, _Rd_); + +REC_FUNC_DEL( PMAXW, _Rd_); +REC_FUNC_DEL( PMAXH, _Rd_); + +REC_FUNC_DEL( PCGTW, _Rd_); +REC_FUNC_DEL( PCGTH, _Rd_); +REC_FUNC_DEL( PCGTB, _Rd_); + +REC_FUNC_DEL( PEXTLW, _Rd_); + +REC_FUNC_DEL( PPACW, _Rd_); +REC_FUNC_DEL( PEXTLH, _Rd_); +REC_FUNC_DEL( PPACH, _Rd_); +REC_FUNC_DEL( PEXTLB, _Rd_); +REC_FUNC_DEL( PPACB, _Rd_); +REC_FUNC_DEL( PEXT5, _Rd_); +REC_FUNC_DEL( PPAC5, _Rd_); + +#else + +//////////////////////////////////////////////////// +void recPMAXW() +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + int t0reg; + + if( EEREC_S == EEREC_T ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + return; + } + + t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSE2_PCMPGTD_XMM_to_XMM(t0reg, EEREC_T); + + if( EEREC_D == EEREC_S ) { + SSEX_PAND_XMM_to_XMM(EEREC_D, t0reg); + SSEX_PANDN_XMM_to_XMM(t0reg, EEREC_T); + } + else if( EEREC_D == EEREC_T ) { + int t1reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSEX_PAND_XMM_to_XMM(EEREC_D, t0reg); + SSEX_PANDN_XMM_to_XMM(t0reg, t1reg); + _freeXMMreg(t1reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSEX_PAND_XMM_to_XMM(EEREC_D, t0reg); + SSEX_PANDN_XMM_to_XMM(t0reg, EEREC_T); + } + + SSEX_POR_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); +CPU_SSE_XMMCACHE_END + + recCall( Interp::PMAXW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPPACW() +{ + if ( ! _Rd_ ) return; + +CPU_SSE_XMMCACHE_START(((_Rs_!=0)?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_T, 0x88); + SSE2_PSRLDQ_I8_to_XMM(EEREC_D, 8); + } + else { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + if( EEREC_D == EEREC_T ) { + SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_S, 0x88); + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_T, 0x88); + SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_T, 0x88); + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_S, 0x88); + SSE2_PUNPCKLQDQ_XMM_to_XMM(t0reg, EEREC_D); + + // swap mmx regs.. don't ask + xmmregs[t0reg] = xmmregs[EEREC_D]; + xmmregs[EEREC_D].inuse = 0; + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + //Done - Refraction - Crude but quicker than int + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[2]); //Copy this one cos it could get overwritten + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[2]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[3], EAX); + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[0]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[2], EAX); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[1], ECX); //This is where we bring it back + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); +} + +void recPPACH( void ) +{ + if (!_Rd_) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_T, 0x88); + SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0x88); + SSE2_PSLLDQ_I8_to_XMM(EEREC_D, 4); + SSE2_PSRLDQ_I8_to_XMM(EEREC_D, 8); + } + else { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_PSHUFLW_XMM_to_XMM(t0reg, EEREC_S, 0x88); + SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_T, 0x88); + SSE2_PSHUFHW_XMM_to_XMM(t0reg, t0reg, 0x88); + SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0x88); + + SSE2_PSRLDQ_I8_to_XMM(t0reg, 4); + SSE2_PSRLDQ_I8_to_XMM(EEREC_D, 4); + SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, t0reg); + + _freeXMMreg(t0reg); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + //Done - Refraction - Crude but quicker than int + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[6]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[7], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[6]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[3], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[2]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[5], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[2]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[1], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[4]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[6], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[4]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[2], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[0]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[4], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[0]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[0], EAX); +} + +//////////////////////////////////////////////////// +void recPPACB() +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + if( _hasFreeXMMreg() ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSLLW_I8_to_XMM(EEREC_D, 8); + SSEX_PXOR_XMM_to_XMM(t0reg, t0reg); + SSE2_PSRLW_I8_to_XMM(EEREC_D, 8); + SSE2_PACKUSWB_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSLLW_I8_to_XMM(EEREC_D, 8); + SSE2_PSRLW_I8_to_XMM(EEREC_D, 8); + SSE2_PACKUSWB_XMM_to_XMM(EEREC_D, EEREC_D); + SSE2_PSRLDQ_I8_to_XMM(EEREC_D, 8); + } + } + else { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSLLW_I8_to_XMM(t0reg, 8); + SSE2_PSLLW_I8_to_XMM(EEREC_D, 8); + SSE2_PSRLW_I8_to_XMM(t0reg, 8); + SSE2_PSRLW_I8_to_XMM(EEREC_D, 8); + + SSE2_PACKUSWB_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } +CPU_SSE_XMMCACHE_END + + recCall( Interp::PPACB, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPEXT5() +{ + recCall( Interp::PEXT5, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPPAC5() +{ + recCall( Interp::PPAC5, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPMAXH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PMAXSW_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PMAXSW_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PMAXSW_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + SSE_PMAXSW_MM_to_MM( t0reg, t1reg ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + SSE_PMAXSW_MM_to_MM( t2reg, t3reg); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t2reg); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPCGTB( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D != EEREC_T ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PCMPGTB_XMM_to_XMM(EEREC_D, EEREC_T); + } + else { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PCMPGTB_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + PCMPGTBRtoR( t0reg, t1reg ); + + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PCMPGTBRtoR( t2reg, t3reg); + + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t2reg); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPCGTH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D != EEREC_T ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PCMPGTW_XMM_to_XMM(EEREC_D, EEREC_T); + } + else { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PCMPGTW_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + + PCMPGTWRtoR( t0reg, t1reg ); + PCMPGTWRtoR( t2reg, t3reg); + + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t2reg); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPCGTW( void ) +{ + //TODO:optimize RS | RT== 0 + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D != EEREC_T ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PCMPGTD_XMM_to_XMM(EEREC_D, EEREC_T); + } + else { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PCMPGTD_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + + PCMPGTDRtoR( t0reg, t1reg ); + PCMPGTDRtoR( t2reg, t3reg); + + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t2reg); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPADDSB( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PADDSB_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PADDSB_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PADDSB_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PADDSBRtoR( t0reg, t2reg); + PADDSBRtoR( t1reg, t3reg); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPADDSH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PADDSW_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PADDSW_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PADDSW_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PADDSWRtoR( t0reg, t2reg); + PADDSWRtoR( t1reg, t3reg); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +//NOTE: check kh2 movies if changing this +void recPADDSW( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + int t1reg = _allocTempXMMreg(XMMT_INT, -1); + int t2reg = _allocTempXMMreg(XMMT_INT, -1); + int t3reg = _allocTempXMMreg(XMMT_INT, -1); + + if ( cpucaps.hasStreamingSIMD4Extensions ) { + SSE4_PMOVSXDQ_XMM_to_XMM(t0reg, EEREC_S); + SSE4_PMOVSXDQ_XMM_to_XMM(t1reg, EEREC_T); + SSE2_PADDQ_XMM_to_XMM(t0reg, t1reg); + SSE2_PSHUFD_XMM_to_XMM(t1reg, EEREC_S, 0x0e); + SSE2_PSHUFD_XMM_to_XMM(t2reg, EEREC_T, 0x0e); + SSE4_PMOVSXDQ_XMM_to_XMM(t1reg, t1reg); + SSE4_PMOVSXDQ_XMM_to_XMM(t2reg, t2reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_T); + SSE2_PXOR_XMM_to_XMM(t2reg, t2reg); + SSE2_PXOR_XMM_to_XMM(t3reg, t3reg); + SSE2_PCMPGTD_XMM_to_XMM(t2reg, t0reg); + SSE2_PCMPGTD_XMM_to_XMM(t3reg, t1reg); + SSE2_PUNPCKLDQ_XMM_to_XMM(t0reg, t2reg); + SSE2_PUNPCKLDQ_XMM_to_XMM(t1reg, t3reg); + SSE2_PADDQ_XMM_to_XMM(t0reg, t1reg); + SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_S); + SSE2_PUNPCKHDQ_XMM_to_XMM(t1reg, t2reg); + SSEX_MOVDQA_XMM_to_XMM(t2reg, EEREC_T); + SSE2_PUNPCKHDQ_XMM_to_XMM(t2reg, t3reg); + } + SSE2_PADDQ_XMM_to_XMM(t1reg, t2reg); + /* + t0reg = { Rs[0]+Rt[0], Rs[1]+Rt[1] } + t1reg = { Rs[2]+Rt[2], Rs[3]+Rt[3] } + */ + + SSEX_MOVDQA_XMM_to_XMM(t2reg, t0reg); + SSE_SHUFPS_XMM_to_XMM(t2reg, t1reg, 0xdd); + SSE2_PSRAD_I8_to_XMM(t2reg, 31); + /* + t2reg = { (Rs[0]+Rt[0]) < 0 ? 0xFFFFFFFF : 0, + (Rs[1]+Rt[1]) < 0 ? 0xFFFFFFFF : 0, + (Rs[2]+Rt[2]) < 0 ? 0xFFFFFFFF : 0, + (Rs[3]+Rt[3]) < 0 ? 0xFFFFFFFF : 0 } + */ + + SSE2_PSHUFD_XMM_to_XMM(t3reg, t2reg, 0x50); + SSE2_PXOR_XMM_to_XMM(t0reg, t3reg); + SSE2_PSRLQ_I8_to_XMM(t3reg, 63); + SSE2_PADDQ_XMM_to_XMM(t0reg, t3reg); + /* + t0reg = { abs(Rs[0]+Rt[0]), abs(Rs[1]+Rt[1]) } + */ + SSE2_PSHUFD_XMM_to_XMM(t3reg, t2reg, 0xfa); + SSE2_PXOR_XMM_to_XMM(t1reg, t3reg); + SSE2_PSRLQ_I8_to_XMM(t3reg, 63); + SSE2_PADDQ_XMM_to_XMM(t1reg, t3reg); + /* + t1reg = { abs(Rs[2]+Rt[2]), abs(Rs[3]+Rt[3]) } + */ + SSE2_PSLLQ_I8_to_XMM(t0reg, 1); + SSE2_PSLLQ_I8_to_XMM(t1reg, 1); + SSE2_PCMPEQB_XMM_to_XMM(t3reg, t3reg); + SSE2_PSRLD_I8_to_XMM(t3reg, 1); + SSE2_PXOR_XMM_to_XMM(t2reg, t3reg); + SSE_SHUFPS_XMM_to_XMM(t0reg, t1reg, 0xdd); + SSE2_PXOR_XMM_to_XMM(t1reg, t1reg); + SSE2_PCMPEQD_XMM_to_XMM(t1reg, t0reg); + /* + t1reg = { abs(Rs[0]+Rt[0]) > 0x7FFFFFFF ? 0 : 0xFFFFFFFF, + abs(Rs[1]+Rt[1]) > 0x7FFFFFFF ? 0 : 0xFFFFFFFF, + abs(Rs[2]+Rt[2]) > 0x7FFFFFFF ? 0 : 0xFFFFFFFF, + abs(Rs[3]+Rt[3]) > 0x7FFFFFFF ? 0 : 0xFFFFFFFF } + t2reg = { (Rs[0]+Rt[0]) < 0 ? 0x80000000 : 0x7FFFFFFF, + (Rs[1]+Rt[1]) < 0 ? 0x80000000 : 0x7FFFFFFF, + (Rs[2]+Rt[2]) < 0 ? 0x80000000 : 0x7FFFFFFF, + (Rs[3]+Rt[3]) < 0 ? 0x80000000 : 0x7FFFFFFF } + */ + if( EEREC_D == EEREC_S ) SSE2_PADDD_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PADDD_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PADDD_XMM_to_XMM(EEREC_D, EEREC_T); + } + SSE2_PAND_XMM_to_XMM(EEREC_D, t1reg); + SSE2_PANDN_XMM_to_XMM(t1reg, t2reg); + SSE2_POR_XMM_to_XMM(EEREC_D, t1reg); + /* + Rd = { t1reg[0] ? Rs[0]+Rt[0] : t2reg[0], + t1reg[1] ? Rs[1]+Rt[1] : t2reg[1], + t1reg[2] ? Rs[2]+Rt[2] : t2reg[2], + t1reg[3] ? Rs[3]+Rt[3] : t2reg[3] } + */ + _freeXMMreg(t0reg); + _freeXMMreg(t1reg); + _freeXMMreg(t2reg); + _freeXMMreg(t3reg); +CPU_SSE_XMMCACHE_END + + if( _Rd_ ) _deleteEEreg(_Rd_, 0); + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + _flushConstRegs(); + + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::MMI::PADDSW ); +} + +//////////////////////////////////////////////////// +void recPSUBSB( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PSUBSB_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBSB_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBSB_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSUBSBRtoR( t0reg, t2reg); + PSUBSBRtoR( t1reg, t3reg); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPSUBSH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PSUBSW_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBSW_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBSW_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSUBSWRtoR( t0reg, t2reg); + PSUBSWRtoR( t1reg, t3reg); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +//NOTE: check kh2 movies if changing this +void recPSUBSW( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + int t1reg = _allocTempXMMreg(XMMT_INT, -1); + int t2reg = _allocTempXMMreg(XMMT_INT, -1); + int t3reg = _allocTempXMMreg(XMMT_INT, -1); + + if ( cpucaps.hasStreamingSIMD4Extensions ) { + SSE4_PMOVSXDQ_XMM_to_XMM(t0reg, EEREC_S); + SSE4_PMOVSXDQ_XMM_to_XMM(t1reg, EEREC_T); + SSE2_PSUBQ_XMM_to_XMM(t0reg, t1reg); + SSE2_PSHUFD_XMM_to_XMM(t1reg, EEREC_S, 0x0e); + SSE2_PSHUFD_XMM_to_XMM(t2reg, EEREC_T, 0x0e); + SSE4_PMOVSXDQ_XMM_to_XMM(t1reg, t1reg); + SSE4_PMOVSXDQ_XMM_to_XMM(t2reg, t2reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_T); + SSE2_PXOR_XMM_to_XMM(t2reg, t2reg); + SSE2_PXOR_XMM_to_XMM(t3reg, t3reg); + SSE2_PCMPGTD_XMM_to_XMM(t2reg, t0reg); + SSE2_PCMPGTD_XMM_to_XMM(t3reg, t1reg); + SSE2_PUNPCKLDQ_XMM_to_XMM(t0reg, t2reg); + SSE2_PUNPCKLDQ_XMM_to_XMM(t1reg, t3reg); + SSE2_PSUBQ_XMM_to_XMM(t0reg, t1reg); + SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_S); + SSE2_PUNPCKHDQ_XMM_to_XMM(t1reg, t2reg); + SSEX_MOVDQA_XMM_to_XMM(t2reg, EEREC_T); + SSE2_PUNPCKHDQ_XMM_to_XMM(t2reg, t3reg); + } + SSE2_PSUBQ_XMM_to_XMM(t1reg, t2reg); + + SSEX_MOVDQA_XMM_to_XMM(t2reg, t0reg); + SSE_SHUFPS_XMM_to_XMM(t2reg, t1reg, 0xdd); + SSE2_PSRAD_I8_to_XMM(t2reg, 31); + + SSE2_PSHUFD_XMM_to_XMM(t3reg, t2reg, 0x50); + SSE2_PXOR_XMM_to_XMM(t0reg, t3reg); + SSE2_PSRLQ_I8_to_XMM(t3reg, 63); + SSE2_PADDQ_XMM_to_XMM(t0reg, t3reg); + SSE2_PSHUFD_XMM_to_XMM(t3reg, t2reg, 0xfa); + SSE2_PXOR_XMM_to_XMM(t1reg, t3reg); + SSE2_PSRLQ_I8_to_XMM(t3reg, 63); + SSE2_PADDQ_XMM_to_XMM(t1reg, t3reg); + SSE2_PSLLQ_I8_to_XMM(t0reg, 1); + SSE2_PSLLQ_I8_to_XMM(t1reg, 1); + SSE2_PCMPEQB_XMM_to_XMM(t3reg, t3reg); + SSE2_PSRLD_I8_to_XMM(t3reg, 1); + SSE2_PXOR_XMM_to_XMM(t2reg, t3reg); + SSE_SHUFPS_XMM_to_XMM(t0reg, t1reg, 0xdd); + SSE2_PXOR_XMM_to_XMM(t1reg, t1reg); + SSE2_PCMPEQD_XMM_to_XMM(t1reg, t0reg); + if( EEREC_D == EEREC_S ) SSE2_PSUBD_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) { + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBD_XMM_to_XMM(EEREC_D, t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBD_XMM_to_XMM(EEREC_D, EEREC_T); + } + SSE2_PAND_XMM_to_XMM(EEREC_D, t1reg); + SSE2_PANDN_XMM_to_XMM(t1reg, t2reg); + SSE2_POR_XMM_to_XMM(EEREC_D, t1reg); + _freeXMMreg(t0reg); + _freeXMMreg(t1reg); + _freeXMMreg(t2reg); + _freeXMMreg(t3reg); +CPU_SSE_XMMCACHE_END + + if( _Rd_ ) _deleteEEreg(_Rd_, 0); + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + _flushConstRegs(); + + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::MMI::PSUBSW ); +} + +//////////////////////////////////////////////////// +void recPADDB( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PADDB_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PADDB_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PADDB_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PADDBRtoR( t0reg, t2reg ); + PADDBRtoR( t1reg, t3reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPADDH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|(_Rt_!=0?XMMINFO_READT:0)|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + if( _Rt_ == 0 ) SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_D); + else SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + } + else if( _Rt_ == 0 ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + if( EEREC_D == EEREC_S ) SSE2_PADDW_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PADDW_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PADDW_XMM_to_XMM(EEREC_D, EEREC_T); + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PADDWRtoR( t0reg, t2reg ); + PADDWRtoR( t1reg, t3reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPADDW( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|(_Rt_!=0?XMMINFO_READT:0)|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + if( _Rt_ == 0 ) SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_D); + else SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + } + else if( _Rt_ == 0 ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + if( EEREC_D == EEREC_S ) SSE2_PADDD_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PADDD_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PADDD_XMM_to_XMM(EEREC_D, EEREC_T); + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PADDDRtoR( t0reg, t2reg ); + PADDDRtoR( t1reg, t3reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPSUBB( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PSUBB_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBB_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBB_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSUBBRtoR( t0reg, t2reg ); + PSUBBRtoR( t1reg, t3reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPSUBH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PSUBW_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBW_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBW_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSUBWRtoR( t0reg, t2reg ); + PSUBWRtoR( t1reg, t3reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPSUBW( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PSUBD_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBD_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBD_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PSUBDRtoR( t0reg, t2reg); + PSUBDRtoR( t1reg, t3reg); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPEXTLW( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRLQ_I8_to_XMM(EEREC_D, 32); + } + else { + if( EEREC_D == EEREC_T ) SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, EEREC_S); + else if( EEREC_D == EEREC_S ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, EEREC_S); + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 3 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 2 ], ECX ); + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], ECX ); +} + +void recPEXTLB( void ) +{ + if (!_Rd_) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + SSE2_PUNPCKLBW_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRLW_I8_to_XMM(EEREC_D, 8); + } + else { + if( EEREC_D == EEREC_T ) SSE2_PUNPCKLBW_XMM_to_XMM(EEREC_D, EEREC_S); + else if( EEREC_D == EEREC_S ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKLBW_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKLBW_XMM_to_XMM(EEREC_D, EEREC_S); + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + //Done - Refraction - Crude but quicker than int + //SysPrintf("PEXTLB\n"); + //Rs = cpuRegs.GPR.r[_Rs_]; Rt = cpuRegs.GPR.r[_Rt_]; + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[7]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[15], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[7]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[14], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[6]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[13], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[6]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[12], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[5]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[11], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[5]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[10], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[4]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[9], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[4]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[8], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[3]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[7], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[3]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[6], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[2]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[5], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[2]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[4], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[1]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[3], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[1]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[2], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[0]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[1], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[0]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[0], EAX); +} + +void recPEXTLH( void ) +{ + if (!_Rd_) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + SSE2_PUNPCKLWD_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRLD_I8_to_XMM(EEREC_D, 16); + } + else { + if( EEREC_D == EEREC_T ) SSE2_PUNPCKLWD_XMM_to_XMM(EEREC_D, EEREC_S); + else if( EEREC_D == EEREC_S ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKLWD_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKLWD_XMM_to_XMM(EEREC_D, EEREC_S); + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + //Done - Refraction - Crude but quicker than int + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[3]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[7], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[3]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[6], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[2]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[5], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[2]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[4], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[1]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[3], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[1]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[2], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[0]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[1], EAX); + MOV16MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].US[0]); + MOV16RtoM((uptr)&cpuRegs.GPR.r[_Rd_].US[0], EAX); +} + +#endif + +/********************************************************* +* MMI1 opcodes * +* * +*********************************************************/ +#ifndef MMI1_RECOMPILE + +REC_FUNC_DEL( PABSW, _Rd_); +REC_FUNC_DEL( PABSH, _Rd_); + +REC_FUNC_DEL( PMINW, _Rd_); +REC_FUNC_DEL( PADSBH, _Rd_); +REC_FUNC_DEL( PMINH, _Rd_); +REC_FUNC_DEL( PCEQB, _Rd_); +REC_FUNC_DEL( PCEQH, _Rd_); +REC_FUNC_DEL( PCEQW, _Rd_); + +REC_FUNC_DEL( PADDUB, _Rd_); +REC_FUNC_DEL( PADDUH, _Rd_); +REC_FUNC_DEL( PADDUW, _Rd_); + +REC_FUNC_DEL( PSUBUB, _Rd_); +REC_FUNC_DEL( PSUBUH, _Rd_); +REC_FUNC_DEL( PSUBUW, _Rd_); + +REC_FUNC_DEL( PEXTUW, _Rd_); +REC_FUNC_DEL( PEXTUH, _Rd_); +REC_FUNC_DEL( PEXTUB, _Rd_); +REC_FUNC_DEL( QFSRV, _Rd_); + +#else + +//////////////////////////////////////////////////// +PCSX2_ALIGNED16(int s_MaskHighBitD[4]) = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }; +PCSX2_ALIGNED16(int s_MaskHighBitW[4]) = { 0x80008000, 0x80008000, 0x80008000, 0x80008000 }; + +void recPABSW() +{ + if( !_Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRAD_I8_to_XMM(t0reg, 31); + SSEX_PXOR_XMM_to_XMM(EEREC_D, t0reg); + SSE2_PSUBD_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); +CPU_SSE_XMMCACHE_END + + _deleteEEreg(_Rt_, 1); + _deleteEEreg(_Rd_, 0); + _flushConstRegs(); + + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::MMI::PABSW ); +} + +//////////////////////////////////////////////////// +void recPABSH() +{ +if( !_Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRAW_I8_to_XMM(t0reg, 15); + SSEX_PXOR_XMM_to_XMM(EEREC_D, t0reg); + SSE2_PSUBW_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); +CPU_SSE_XMMCACHE_END + + _deleteEEreg(_Rt_, 1); + _deleteEEreg(_Rd_, 0); + _flushConstRegs(); + + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::MMI::PABSW ); +} + +//////////////////////////////////////////////////// +void recPMINW() +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + int t0reg; + + if( EEREC_S == EEREC_T ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + return; + } + + t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSE2_PCMPGTD_XMM_to_XMM(t0reg, EEREC_S); + + if( EEREC_D == EEREC_S ) { + SSEX_PAND_XMM_to_XMM(EEREC_D, t0reg); + SSEX_PANDN_XMM_to_XMM(t0reg, EEREC_T); + } + else if( EEREC_D == EEREC_T ) { + int t1reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSEX_PAND_XMM_to_XMM(EEREC_D, t0reg); + SSEX_PANDN_XMM_to_XMM(t0reg, t1reg); + _freeXMMreg(t1reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSEX_PAND_XMM_to_XMM(EEREC_D, t0reg); + SSEX_PANDN_XMM_to_XMM(t0reg, EEREC_T); + } + + SSEX_POR_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); +CPU_SSE_XMMCACHE_END + + recCall( Interp::PMINW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPADSBH() +{ +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + int t0reg; + + if( EEREC_S == EEREC_T ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PADDW_XMM_to_XMM(EEREC_D, EEREC_D); + // reset lower bits to 0s + SSE2_PSRLDQ_I8_to_XMM(EEREC_D, 8); + SSE2_PSLLDQ_I8_to_XMM(EEREC_D, 8); + return; + } + + t0reg = _allocTempXMMreg(XMMT_INT, -1); + + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + + if( EEREC_D == EEREC_S ) { + SSE2_PADDW_XMM_to_XMM(t0reg, EEREC_S); + SSE2_PSUBW_XMM_to_XMM(EEREC_D, EEREC_T); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBW_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PADDW_XMM_to_XMM(t0reg, EEREC_S); + } + + // t0reg - adds, EEREC_D - subs + SSE2_PSRLDQ_I8_to_XMM(t0reg, 8); + SSE_MOVLHPS_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + +CPU_SSE_XMMCACHE_END + + recCall( Interp::PADSBH, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPADDUW() +{ +CPU_SSE2_XMMCACHE_START((_Rs_?XMMINFO_READS:0)|(_Rt_?XMMINFO_READT:0)|XMMINFO_WRITED) + + if( _Rt_ == 0 ) { + if( _Rs_ == 0 ) { + SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_D); + } + else SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + } + else if( _Rs_ == 0 ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + } + else { + + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + int t1reg = _allocTempXMMreg(XMMT_INT, -1); + int t2reg = _allocTempXMMreg(XMMT_INT, -1); + + if( _hasFreeXMMreg() ) { + int t3reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_PXOR_XMM_to_XMM(t0reg, t0reg); + SSE2_MOVQ_XMM_to_XMM(t1reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(t2reg, EEREC_S); + if( EEREC_D != EEREC_T ) SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(t3reg, EEREC_T); + SSE2_PUNPCKLDQ_XMM_to_XMM(t1reg, t0reg); + SSE2_PUNPCKHDQ_XMM_to_XMM(t2reg, t0reg); + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, t0reg); + SSE2_PUNPCKHDQ_XMM_to_XMM(t3reg, t0reg); + SSE2_PADDQ_XMM_to_XMM(t1reg, EEREC_D); + SSE2_PADDQ_XMM_to_XMM(t2reg, t3reg); + _freeXMMreg(t3reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(t2reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + + SSE2_MOVQ_XMM_to_XMM(t1reg, EEREC_S); + SSE2_PSRLDQ_I8_to_XMM(t2reg, 8); + if( EEREC_D != EEREC_T ) SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRLDQ_I8_to_XMM(t0reg, 8); + SSE2_PSHUFD_XMM_to_XMM(t1reg, t1reg, 0xE8); + SSE2_PSHUFD_XMM_to_XMM(t2reg, t2reg, 0xE8); + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_D, 0xE8); + SSE2_PSHUFD_XMM_to_XMM(t0reg, t0reg, 0xE8); + SSE2_PADDQ_XMM_to_XMM(t1reg, EEREC_D); + SSE2_PADDQ_XMM_to_XMM(t2reg, t0reg); + SSEX_PXOR_XMM_to_XMM(t0reg, t0reg); + } + + SSE2_PSHUFD_XMM_to_XMM(t1reg, t1reg, 0xd8); + SSE2_PSHUFD_XMM_to_XMM(t2reg, t2reg, 0xd8); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, t1reg); + SSE2_PUNPCKHQDQ_XMM_to_XMM(t1reg, t2reg); + SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, t2reg); + SSE2_PCMPGTD_XMM_to_XMM(t1reg, t0reg); + SSEX_POR_XMM_to_XMM(EEREC_D, t1reg); + + _freeXMMreg(t0reg); + _freeXMMreg(t1reg); + _freeXMMreg(t2reg); + } + +CPU_SSE_XMMCACHE_END + recCall( Interp::PADDUW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPSUBUB() +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PSUBUSB_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PSUBUSB_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBUSB_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + recCall( Interp::PSUBUB, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPSUBUH() +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PSUBUSW_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PSUBUSW_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSUBUSW_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + recCall( Interp::PSUBUH, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPSUBUW() +{ + recCall( Interp::PSUBUW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPEXTUH() +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRLD_I8_to_XMM(EEREC_D, 16); + } + else { + if( EEREC_D == EEREC_T ) SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, EEREC_S); + else if( EEREC_D == EEREC_S ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, EEREC_S); + } + } +CPU_SSE_XMMCACHE_END + + recCall( Interp::PEXTUH, _Rd_ ); +} + +//////////////////////////////////////////////////// +// Both Macros are 16 bytes so we can use a shift instead of a Mul instruction +#define QFSRVhelper0() { \ + ajmp[0] = JMP32(0); \ + x86Ptr += 11; \ +} + +#define QFSRVhelper(shift1, shift2) { \ + SSE2_PSRLDQ_I8_to_XMM(EEREC_D, shift1); \ + SSE2_PSLLDQ_I8_to_XMM(t0reg, shift2); \ + ajmp[shift1] = JMP32(0); \ + x86Ptr += 1; \ +} + +void recQFSRV() +{ + if ( !_Rd_ ) return; + //SysPrintf("recQFSRV()\n"); + + CPU_SSE2_XMMCACHE_START( XMMINFO_READS | XMMINFO_READT | XMMINFO_WRITED ) + + u32 *ajmp[16]; + int i, j; + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + + SSE2_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSE2_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + + MOV32MtoR(EAX, (uptr)&cpuRegs.sa); + SHL32ItoR(EAX, 1); // Multiply SA bytes by 16 bytes (the amount of bytes in QFSRVhelper() macros) + AND32I8toR(EAX, 0xf0); // This can possibly be removed but keeping it incase theres garbage in SA (cottonvibes) + ADD32ItoEAX((uptr)x86Ptr + 7); // ADD32 = 5 bytes, JMPR = 2 bytes + JMPR(EAX); // Jumps to a QFSRVhelper() case below (a total of 16 different cases) + + // Case 0: + QFSRVhelper0(); + + // Cases 1 to 15: + for (i = 1, j = 15; i < 16; i++, j--) { + QFSRVhelper(i, j); + } + + // Set jump addresses for the JMP32's in QFSRVhelper() + for (i = 1; i < 16; i++) { + x86SetJ32(ajmp[i]); + } + + // Concatenate the regs after appropriate shifts have been made + SSE2_POR_XMM_to_XMM(EEREC_D, t0reg); + + x86SetJ32(ajmp[0]); // Case 0 jumps to here (to skip the POR) + _freeXMMreg(t0reg); + + CPU_SSE_XMMCACHE_END + //recCall( Interp::QFSRV, _Rd_ ); +} + + +void recPEXTUB( void ) +{ + if (!_Rd_) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + SSE2_PUNPCKHBW_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRLW_I8_to_XMM(EEREC_D, 8); + } + else { + if( EEREC_D == EEREC_T ) SSE2_PUNPCKHBW_XMM_to_XMM(EEREC_D, EEREC_S); + else if( EEREC_D == EEREC_S ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKHBW_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKHBW_XMM_to_XMM(EEREC_D, EEREC_S); + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + //Done - Refraction - Crude but faster than int + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[8]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[0], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[8]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[1], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[9]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[2], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[9]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[3], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[10]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[4], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[10]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[5], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[11]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[6], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[11]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[7], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[12]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[8], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[12]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[9], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[13]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[10], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[13]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[11], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[14]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[12], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[14]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[13], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UC[15]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[14], EAX); + MOV8MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UC[15]); + MOV8RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UC[15], EAX); +} + +//////////////////////////////////////////////////// +void recPEXTUW( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|XMMINFO_READT|XMMINFO_WRITED) + if( _Rs_ == 0 ) { + SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSRLQ_I8_to_XMM(EEREC_D, 32); + } + else { + if( EEREC_D == EEREC_T ) SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_D, EEREC_S); + else if( EEREC_D == EEREC_S ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_D, EEREC_S); + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 2 ] ); + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 2 ] ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], ECX ); + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UL[ 3 ] ); + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UL[ 3 ] ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 3 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 2 ], ECX ); +} + +//////////////////////////////////////////////////// +void recPMINH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PMINSW_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PMINSW_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PMINSW_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + SSE_PMINSW_MM_to_MM( t0reg, t2reg ); + SSE_PMINSW_MM_to_MM( t1reg, t3reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPCEQB( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PCMPEQB_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PCMPEQB_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PCMPEQB_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PCMPEQBRtoR( t0reg, t2reg ); + PCMPEQBRtoR( t1reg, t3reg ); + + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPCEQH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PCMPEQW_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PCMPEQW_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PCMPEQW_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PCMPEQWRtoR( t0reg, t2reg ); + PCMPEQWRtoR( t1reg, t3reg ); + + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPCEQW( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PCMPEQD_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PCMPEQD_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PCMPEQD_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PCMPEQDRtoR( t0reg, t2reg ); + PCMPEQDRtoR( t1reg, t3reg ); + + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPADDUB( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|(_Rt_?XMMINFO_READT:0)|XMMINFO_WRITED) + if( _Rt_ ) { + if( EEREC_D == EEREC_S ) SSE2_PADDUSB_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PADDUSB_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PADDUSB_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + else SSE2_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PADDUSBRtoR( t0reg, t2reg ); + PADDUSBRtoR( t1reg, t3reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPADDUH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) SSE2_PADDUSW_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PADDUSW_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PADDUSW_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP4( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t2reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQMtoR( t3reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PADDUSWRtoR( t0reg, t2reg ); + PADDUSWRtoR( t1reg, t3reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +#endif +/********************************************************* +* MMI2 opcodes * +* * +*********************************************************/ +#ifndef MMI2_RECOMPILE + +REC_FUNC_DEL( PMFHI, _Rd_); +REC_FUNC_DEL( PMFLO, _Rd_); +REC_FUNC_DEL( PCPYLD, _Rd_); +REC_FUNC_DEL( PAND, _Rd_); +REC_FUNC_DEL( PXOR, _Rd_); + +REC_FUNC_DEL( PMADDW, _Rd_); +REC_FUNC_DEL( PSLLVW, _Rd_); +REC_FUNC_DEL( PSRLVW, _Rd_); +REC_FUNC_DEL( PMSUBW, _Rd_); +REC_FUNC_DEL( PINTH, _Rd_); +REC_FUNC_DEL( PMULTW, _Rd_); +REC_FUNC_DEL( PDIVW, _Rd_); +REC_FUNC_DEL( PMADDH, _Rd_); +REC_FUNC_DEL( PHMADH, _Rd_); +REC_FUNC_DEL( PMSUBH, _Rd_); +REC_FUNC_DEL( PHMSBH, _Rd_); +REC_FUNC_DEL( PEXEH, _Rd_); +REC_FUNC_DEL( PREVH, _Rd_); +REC_FUNC_DEL( PMULTH, _Rd_); +REC_FUNC_DEL( PDIVBW, _Rd_); +REC_FUNC_DEL( PEXEW, _Rd_); +REC_FUNC_DEL( PROT3W, _Rd_ ); + +#else + +//////////////////////////////////////////////////// +void recPMADDW() +{ + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); + recCall( Interp::PMADDW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPSLLVW() +{ + recCall( Interp::PSLLVW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPSRLVW() +{ + recCall( Interp::PSRLVW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPMSUBW() +{ + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); +//CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED|XMMINFO_WRITELO|XMMINFO_WRITEHI|XMMINFO_READLO|XMMINFO_READHI) +// int t0reg = _allocTempXMMreg(XMMT_INT, -1); +// +// if( EEREC_D == EEREC_S ) SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_T); +// else if( EEREC_D == EEREC_T ) SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_S); +// else { +// SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); +// SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_T); +// } +// +// // add from LO/HI +// SSE_SHUFPS_XMM_to_XMM(EEREC_LO, EEREC_HI, 0x88); +// SSE2_PSHUFD_XMM_to_XMM(EEREC_LO, EEREC_LO, 0xd8); +// SSE2_PSUBQ_XMM_to_XMM(EEREC_LO, EEREC_D); +// +// // get the signs +// SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_LO); +// SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_LO); +// SSE2_PSRAD_I8_to_XMM(t0reg, 31); +// +// // interleave +// SSE2_PSHUFD_XMM_to_XMM(EEREC_LO, EEREC_LO, 0xd8); +// SSE2_PSHUFD_XMM_to_XMM(t0reg, t0reg, 0xd8); +// SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_LO); +// +// SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_LO, t0reg); +// SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_HI, t0reg); +// +// _freeXMMreg(t0reg); +//CPU_SSE_XMMCACHE_END + + recCall( Interp::PMSUBW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPMULTW() +{ + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); + recCall( Interp::PMULTW, _Rd_ ); +} +//////////////////////////////////////////////////// +void recPDIVW() +{ + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + recCall( Interp::PDIVW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPDIVBW() +{ + recCall( Interp::PDIVBW, _Rd_ ); //-- +} + +//////////////////////////////////////////////////// +PCSX2_ALIGNED16(int s_mask1[4]) = {~0, 0, ~0, 0}; + +void recPHMADH() +{ +CPU_SSE2_XMMCACHE_START((_Rd_?XMMINFO_WRITED:0)|XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITELO|XMMINFO_WRITEHI) + int t0reg = _Rd_ ? EEREC_D : _allocTempXMMreg(XMMT_INT, -1); + + if( t0reg == EEREC_S ) { + + SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, EEREC_S); + + if( t0reg == EEREC_T ) { + SSE2_PMULHW_XMM_to_XMM(EEREC_LO, EEREC_T); + SSE2_PMULLW_XMM_to_XMM(t0reg, EEREC_T); + } + else { + SSE2_PMULLW_XMM_to_XMM(t0reg, EEREC_T); + SSE2_PMULHW_XMM_to_XMM(EEREC_LO, EEREC_T); + } + SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, EEREC_T); + + SSE2_PMULLW_XMM_to_XMM(t0reg, EEREC_S); + SSE2_PMULHW_XMM_to_XMM(EEREC_LO, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, t0reg); + } + + // 0-3 + SSE2_PUNPCKLWD_XMM_to_XMM(t0reg, EEREC_LO); + // 4-7 + SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_HI, EEREC_LO); + + SSE2_PSHUFD_XMM_to_XMM(t0reg, t0reg, 0xd8); // 0,2,1,3, L->H + SSE2_PSHUFD_XMM_to_XMM(EEREC_HI, EEREC_HI, 0xd8); // 4,6,5,7, L->H + SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, t0reg); + + SSE2_PUNPCKLQDQ_XMM_to_XMM(t0reg, EEREC_HI); + SSE2_PUNPCKHQDQ_XMM_to_XMM(EEREC_LO, EEREC_HI); + + SSE2_PADDD_XMM_to_XMM(EEREC_LO, t0reg); + + if( _Rd_ ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_LO); + } + + SSE2_PSHUFD_XMM_to_XMM(EEREC_HI, EEREC_LO, 0xf5); + + SSE2_PAND_M128_to_XMM(EEREC_LO, (uptr)s_mask1); + SSE2_PAND_M128_to_XMM(EEREC_HI, (uptr)s_mask1); + + if( !_Rd_ ) _freeXMMreg(t0reg); + +CPU_SSE_XMMCACHE_END + + recCall( Interp::PHMADH, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPMSUBH() +{ + CPU_SSE2_XMMCACHE_START((_Rd_?XMMINFO_WRITED:0)|XMMINFO_READS|XMMINFO_READT|XMMINFO_READLO|XMMINFO_READHI|XMMINFO_WRITELO|XMMINFO_WRITEHI) + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + int t1reg = _allocTempXMMreg(XMMT_INT, -1); + + if( !_Rd_ ) { + SSE2_PXOR_XMM_to_XMM(t0reg, t0reg); + SSE2_PSHUFD_XMM_to_XMM(t1reg, EEREC_S, 0xd8); //S0, S1, S4, S5, S2, S3, S6, S7 + SSE2_PUNPCKLWD_XMM_to_XMM(t1reg, t0reg); //S0, 0, S1, 0, S4, 0, S5, 0 + SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_T, 0xd8); //T0, T1, T4, T5, T2, T3, T6, T7 + SSE2_PUNPCKLWD_XMM_to_XMM(t0reg, t0reg); //T0, T0, T1, T1, T4, T4, T5, T5 + SSE2_PMADDWD_XMM_to_XMM(t0reg, t1reg); //S0*T0+0*T0, S1*T1+0*T1, S4*T4+0*T4, S5*T5+0*T5 + + SSE2_PSUBD_XMM_to_XMM(EEREC_LO, t0reg); + + SSE2_PXOR_XMM_to_XMM(t0reg, t0reg); + SSE2_PSHUFD_XMM_to_XMM(t1reg, EEREC_S, 0xd8); //S0, S1, S4, S5, S2, S3, S6, S7 + SSE2_PUNPCKHWD_XMM_to_XMM(t1reg, t0reg); //S2, 0, S3, 0, S6, 0, S7, 0 + SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_T, 0xd8); //T0, T1, T4, T5, T2, T3, T6, T7 + SSE2_PUNPCKHWD_XMM_to_XMM(t0reg, t0reg); //T2, T2, T3, T3, T6, T6, T7, T7 + SSE2_PMADDWD_XMM_to_XMM(t0reg, t1reg); //S2*T2+0*T2, S3*T3+0*T3, S6*T6+0*T6, S7*T7+0*T7 + + SSE2_PSUBD_XMM_to_XMM(EEREC_HI, t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_S); + + SSE2_PMULLW_XMM_to_XMM(t0reg, EEREC_T); + SSE2_PMULHW_XMM_to_XMM(t1reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, t0reg); + + // 0-3 + SSE2_PUNPCKLWD_XMM_to_XMM(t0reg, t1reg); + // 4-7 + SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, t1reg); + SSEX_MOVDQA_XMM_to_XMM(t1reg, t0reg); + + // 0,1,4,5, L->H + SSE2_PUNPCKLQDQ_XMM_to_XMM(t0reg, EEREC_D); + // 2,3,6,7, L->H + SSE2_PUNPCKHQDQ_XMM_to_XMM(t1reg, EEREC_D); + + SSE2_PSUBD_XMM_to_XMM(EEREC_LO, t0reg); + SSE2_PSUBD_XMM_to_XMM(EEREC_HI, t1reg); + + // 0,2,4,6, L->H + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_LO, 0x88); + SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_HI, 0x88); + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, t0reg); + } + + _freeXMMreg(t0reg); + _freeXMMreg(t1reg); + +CPU_SSE_XMMCACHE_END + recCall( Interp::PMSUBH, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPHMSBH() +{ +CPU_SSE2_XMMCACHE_START((_Rd_?XMMINFO_WRITED:0)|XMMINFO_READS|XMMINFO_READT|XMMINFO_READLO|XMMINFO_READHI|XMMINFO_WRITELO|XMMINFO_WRITEHI) + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, EEREC_S); + + SSE2_PMULLW_XMM_to_XMM(t0reg, EEREC_T); + SSE2_PMULHW_XMM_to_XMM(EEREC_LO, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, t0reg); + + // 0-3 + SSE2_PUNPCKLWD_XMM_to_XMM(t0reg, EEREC_LO); + // 4-7 + SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_HI, EEREC_LO); + + SSE2_PSHUFD_XMM_to_XMM(t0reg, t0reg, 0xd8); // 0,2,1,3, L->H + SSE2_PSHUFD_XMM_to_XMM(EEREC_HI, EEREC_HI, 0xd8); // 4,6,5,7, L->H + SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, t0reg); + + SSE2_PUNPCKLDQ_XMM_to_XMM(t0reg, EEREC_HI); + SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_LO, EEREC_HI); + + SSE2_PSUBD_XMM_to_XMM(EEREC_LO, t0reg); + + if( _Rd_ ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_LO); + } + + SSE2_PSHUFD_XMM_to_XMM(EEREC_HI, EEREC_LO, 0xf5); + + _freeXMMreg(t0reg); + +CPU_SSE_XMMCACHE_END + + recCall( Interp::PHMSBH, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPEXEH( void ) +{ + if (!_Rd_) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_T, 0xc6); + SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0xc6); +CPU_SSE_XMMCACHE_END + + recCall( Interp::PEXEH, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPREVH( void ) +{ + if (!_Rd_) return; + + +CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_T, 0x1B); + SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0x1B); +CPU_SSE_XMMCACHE_END + + recCall( Interp::PREVH, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPINTH( void ) +{ + if (!_Rd_) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + if( EEREC_D == EEREC_S ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE_MOVHLPS_XMM_to_XMM(t0reg, EEREC_S); + if( EEREC_D != EEREC_T ) SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKLWD_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSE_MOVLHPS_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, EEREC_S); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + //Done - Refraction + MOV16MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[4]); + MOV16MtoR( EBX, (uptr)&cpuRegs.GPR.r[_Rt_].US[1]); + MOV16MtoR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].US[2]); + MOV16MtoR( EDX, (uptr)&cpuRegs.GPR.r[_Rt_].US[0]); + + MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[1], EAX); + MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[2], EBX); + MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[4], ECX); + MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[0], EDX); + + MOV16MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].US[5]); + MOV16MtoR( EBX, (uptr)&cpuRegs.GPR.r[_Rs_].US[6]); + MOV16MtoR( ECX, (uptr)&cpuRegs.GPR.r[_Rs_].US[7]); + MOV16MtoR( EDX, (uptr)&cpuRegs.GPR.r[_Rt_].US[3]); + + MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[3], EAX); + MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[5], EBX); + MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[7], ECX); + MOV16RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].US[6], EDX); +} + +void recPEXEW( void ) +{ + if (!_Rd_) return; + +CPU_SSE_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_T, 0xc6); +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[2]); + MOV32MtoR( EBX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[1]); + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); + MOV32MtoR( EDX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[3]); + + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[1], EBX); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[2], ECX); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[3], EDX); +} + +void recPROT3W( void ) +{ + if (!_Rd_) return; + +CPU_SSE_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED) + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_T, 0xc9); +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MOV32MtoR( EAX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[1]); + MOV32MtoR( EBX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[2]); + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[0]); + MOV32MtoR( EDX, (uptr)&cpuRegs.GPR.r[_Rt_].UL[3]); + + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[1], EBX); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[2], ECX); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[3], EDX); +} + +void recPMULTH( void ) +{ +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|(_Rd_?XMMINFO_WRITED:0)|XMMINFO_WRITELO|XMMINFO_WRITEHI) + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + + SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_S); + + SSE2_PMULLW_XMM_to_XMM(EEREC_LO, EEREC_T); + SSE2_PMULHW_XMM_to_XMM(EEREC_HI, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_LO); + + // 0-3 + SSE2_PUNPCKLWD_XMM_to_XMM(EEREC_LO, EEREC_HI); + // 4-7 + SSE2_PUNPCKHWD_XMM_to_XMM(t0reg, EEREC_HI); + + if( _Rd_ ) { + // 0,2,4,6, L->H + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_LO, 0x88); + SSE2_PSHUFD_XMM_to_XMM(EEREC_HI, t0reg, 0x88); + SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, EEREC_HI); + } + + SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_LO); + + // 0,1,4,5, L->H + SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_LO, t0reg); + // 2,3,6,7, L->H + SSE2_PUNPCKHQDQ_XMM_to_XMM(EEREC_HI, t0reg); + + _freeXMMreg(t0reg); +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + _deleteEEreg(XMMGPR_LO, 0); + _deleteEEreg(XMMGPR_HI, 0); + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 1); + + if(!_Rt_ || !_Rs_) { + MOV32ItoM( (uptr)&cpuRegs.LO.UL[0], 0); + MOV32ItoM( (uptr)&cpuRegs.LO.UL[1], 0); + MOV32ItoM( (uptr)&cpuRegs.LO.UL[2], 0); + MOV32ItoM( (uptr)&cpuRegs.LO.UL[3], 0); + MOV32ItoM( (uptr)&cpuRegs.HI.UL[0], 0); + MOV32ItoM( (uptr)&cpuRegs.HI.UL[1], 0); + MOV32ItoM( (uptr)&cpuRegs.HI.UL[2], 0); + MOV32ItoM( (uptr)&cpuRegs.HI.UL[3], 0); + + if( _Rd_ ) { + MOV32ItoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[0], 0); + MOV32ItoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[1], 0); + MOV32ItoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[2], 0); + MOV32ItoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[3], 0); + } + return; + } + + //Done - Refraction + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[0]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[0]); + IMUL32RtoR( EAX, ECX); + MOV32RtoM( (uptr)&cpuRegs.LO.UL[0], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[1]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[1]); + IMUL32RtoR( EAX, ECX); + MOV32RtoM( (uptr)&cpuRegs.LO.UL[1], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[2]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[2]); + IMUL32RtoR( EAX, ECX); + MOV32RtoM( (uptr)&cpuRegs.HI.UL[0], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[3]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[3]); + IMUL32RtoR( EAX, ECX); + MOV32RtoM( (uptr)&cpuRegs.HI.UL[1], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[4]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[4]); + IMUL32RtoR( EAX, ECX); + MOV32RtoM( (uptr)&cpuRegs.LO.UL[2], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[5]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[5]); + IMUL32RtoR( EAX, ECX); + MOV32RtoM( (uptr)&cpuRegs.LO.UL[3], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[6]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[6]); + IMUL32RtoR( EAX, ECX); + MOV32RtoM( (uptr)&cpuRegs.HI.UL[2], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[7]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[7]); + IMUL32RtoR( EAX, ECX); + MOV32RtoM( (uptr)&cpuRegs.HI.UL[3], EAX); + + if (_Rd_) { + MOV32MtoR( EAX, (uptr)&cpuRegs.LO.UL[0]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); + MOV32MtoR( EAX, (uptr)&cpuRegs.HI.UL[0]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[1], EAX); + MOV32MtoR( EAX, (uptr)&cpuRegs.LO.UL[2]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[2], EAX); + MOV32MtoR( EAX, (uptr)&cpuRegs.HI.UL[2]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[3], EAX); + } +} + +void recPMFHI( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE_XMMCACHE_START(XMMINFO_WRITED|XMMINFO_READHI) + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_HI); +CPU_SSE_XMMCACHE_END + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.HI.UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.HI.UD[ 1 ] ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPMFLO( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE_XMMCACHE_START(XMMINFO_WRITED|XMMINFO_READLO) + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_LO); +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.LO.UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.LO.UD[ 1 ] ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPAND( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE_XMMCACHE_START(XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT) + if( EEREC_D == EEREC_T ) { + SSEX_PAND_XMM_to_XMM(EEREC_D, EEREC_S); + } + else if( EEREC_D == EEREC_S ) { + SSEX_PAND_XMM_to_XMM(EEREC_D, EEREC_T); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSEX_PAND_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + PANDMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + PANDMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPXOR( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE_XMMCACHE_START(XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT) + if( EEREC_D == EEREC_T ) { + SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_S); + } + else if( EEREC_D == EEREC_S ) { + SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_T); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_T); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + PXORMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + PXORMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPCPYLD( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE_XMMCACHE_START(XMMINFO_WRITED|(( _Rs_== 0) ? 0:XMMINFO_READS)|XMMINFO_READT) + if( _Rs_ == 0 ) { + SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_T); + } + else { + if( EEREC_D == EEREC_T ) SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, EEREC_S); + else if( EEREC_S == EEREC_T ) SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_S, 0x44); + else if( EEREC_D == EEREC_S ) { + SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_D, 0x4e); + } + else { + SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PUNPCKLQDQ_XMM_to_XMM(EEREC_D, EEREC_S); + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t1reg ); + SetMMXstate(); + ) +} + +void recPMADDH( void ) +{ + CPU_SSE2_XMMCACHE_START((_Rd_?XMMINFO_WRITED:0)|XMMINFO_READS|XMMINFO_READT|XMMINFO_READLO|XMMINFO_READHI|XMMINFO_WRITELO|XMMINFO_WRITEHI) + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + int t1reg = _allocTempXMMreg(XMMT_INT, -1); + + if( !_Rd_ ) { + SSE2_PXOR_XMM_to_XMM(t0reg, t0reg); + SSE2_PSHUFD_XMM_to_XMM(t1reg, EEREC_S, 0xd8); //S0, S1, S4, S5, S2, S3, S6, S7 + SSE2_PUNPCKLWD_XMM_to_XMM(t1reg, t0reg); //S0, 0, S1, 0, S4, 0, S5, 0 + SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_T, 0xd8); //T0, T1, T4, T5, T2, T3, T6, T7 + SSE2_PUNPCKLWD_XMM_to_XMM(t0reg, t0reg); //T0, T0, T1, T1, T4, T4, T5, T5 + SSE2_PMADDWD_XMM_to_XMM(t0reg, t1reg); //S0*T0+0*T0, S1*T1+0*T1, S4*T4+0*T4, S5*T5+0*T5 + + SSE2_PADDD_XMM_to_XMM(EEREC_LO, t0reg); + + SSE2_PXOR_XMM_to_XMM(t0reg, t0reg); + SSE2_PSHUFD_XMM_to_XMM(t1reg, EEREC_S, 0xd8); //S0, S1, S4, S5, S2, S3, S6, S7 + SSE2_PUNPCKHWD_XMM_to_XMM(t1reg, t0reg); //S2, 0, S3, 0, S6, 0, S7, 0 + SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_T, 0xd8); //T0, T1, T4, T5, T2, T3, T6, T7 + SSE2_PUNPCKHWD_XMM_to_XMM(t0reg, t0reg); //T2, T2, T3, T3, T6, T6, T7, T7 + SSE2_PMADDWD_XMM_to_XMM(t0reg, t1reg); //S2*T2+0*T2, S3*T3+0*T3, S6*T6+0*T6, S7*T7+0*T7 + + SSE2_PADDD_XMM_to_XMM(EEREC_HI, t0reg); + } + else { + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_S); + + SSE2_PMULLW_XMM_to_XMM(t0reg, EEREC_T); + SSE2_PMULHW_XMM_to_XMM(t1reg, EEREC_T); + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, t0reg); + + // 0-3 + SSE2_PUNPCKLWD_XMM_to_XMM(t0reg, t1reg); + // 4-7 + SSE2_PUNPCKHWD_XMM_to_XMM(EEREC_D, t1reg); + SSEX_MOVDQA_XMM_to_XMM(t1reg, t0reg); + + // 0,1,4,5, L->H + SSE2_PUNPCKLQDQ_XMM_to_XMM(t0reg, EEREC_D); + // 2,3,6,7, L->H + SSE2_PUNPCKHQDQ_XMM_to_XMM(t1reg, EEREC_D); + + SSE2_PADDD_XMM_to_XMM(EEREC_LO, t0reg); + SSE2_PADDD_XMM_to_XMM(EEREC_HI, t1reg); + + // 0,2,4,6, L->H + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_LO, 0x88); + SSE2_PSHUFD_XMM_to_XMM(t0reg, EEREC_HI, 0x88); + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_D, t0reg); + } + + _freeXMMreg(t0reg); + _freeXMMreg(t1reg); + +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + _deleteEEreg(XMMGPR_LO, 1); + _deleteEEreg(XMMGPR_HI, 1); + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 1); + + if(_Rt_ && _Rs_){ + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[0]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[0]); + IMUL32RtoR( EAX, ECX); + ADD32RtoM( (uptr)&cpuRegs.LO.UL[0], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[1]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[1]); + IMUL32RtoR( EAX, ECX); + ADD32RtoM( (uptr)&cpuRegs.LO.UL[1], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[2]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[2]); + IMUL32RtoR( EAX, ECX); + ADD32RtoM( (uptr)&cpuRegs.HI.UL[0], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[3]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[3]); + IMUL32RtoR( EAX, ECX); + ADD32RtoM( (uptr)&cpuRegs.HI.UL[1], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[4]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[4]); + IMUL32RtoR( EAX, ECX); + ADD32RtoM( (uptr)&cpuRegs.LO.UL[2], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[5]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[5]); + IMUL32RtoR( EAX, ECX); + ADD32RtoM( (uptr)&cpuRegs.LO.UL[3], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[6]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[6]); + IMUL32RtoR( EAX, ECX); + ADD32RtoM( (uptr)&cpuRegs.HI.UL[2], EAX); + + MOVSX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[_Rs_].SS[7]); + MOVSX32M16toR( ECX, (uptr)&cpuRegs.GPR.r[_Rt_].SS[7]); + IMUL32RtoR( EAX, ECX); + ADD32RtoM( (uptr)&cpuRegs.HI.UL[3], EAX); + + } + + if (_Rd_) { + MOV32MtoR( EAX, (uptr)&cpuRegs.LO.UL[0]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); + MOV32MtoR( EAX, (uptr)&cpuRegs.HI.UL[0]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[1], EAX); + MOV32MtoR( EAX, (uptr)&cpuRegs.LO.UL[2]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[2], EAX); + MOV32MtoR( EAX, (uptr)&cpuRegs.HI.UL[2]); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[_Rd_].UL[3], EAX); + } +} + +#endif +/********************************************************* +* MMI3 opcodes * +* * +*********************************************************/ +#ifndef MMI3_RECOMPILE + +REC_FUNC_DEL( PMADDUW, _Rd_); +REC_FUNC_DEL( PSRAVW, _Rd_); +REC_FUNC_DEL( PMTHI, _Rd_); +REC_FUNC_DEL( PMTLO, _Rd_); +REC_FUNC_DEL( PINTEH, _Rd_); +REC_FUNC_DEL( PMULTUW, _Rd_); +REC_FUNC_DEL( PDIVUW, _Rd_); +REC_FUNC_DEL( PCPYUD, _Rd_); +REC_FUNC_DEL( POR, _Rd_); +REC_FUNC_DEL( PNOR, _Rd_); +REC_FUNC_DEL( PCPYH, _Rd_); +REC_FUNC_DEL( PEXCW, _Rd_); +REC_FUNC_DEL( PEXCH, _Rd_); + +#else + +//////////////////////////////////////////////////// +//REC_FUNC( PSRAVW, _Rd_ ); + +void recPSRAVW( void ) +{ + MOV32ItoM( (uptr)&cpuRegs.code, (u32)cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, (u32)pc ); + iFlushCall(FLUSH_EVERYTHING); + if( _Rd_ > 0 ) _deleteEEreg(_Rd_, 0); + CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::MMI::PSRAVW ); +} + + +//////////////////////////////////////////////////// +PCSX2_ALIGNED16(u32 s_tempPINTEH[4]) = {0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff }; + +void recPINTEH() +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START((_Rs_?XMMINFO_READS:0)|(_Rt_?XMMINFO_READT:0)|XMMINFO_WRITED) + + int t0reg = -1; + + if( _Rs_ == 0 ) { + if( _Rt_ == 0 ) { + SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_D); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + SSE2_PAND_M128_to_XMM(EEREC_D, (uptr)s_tempPINTEH); + } + } + else if( _Rt_ == 0 ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSLLD_I8_to_XMM(EEREC_D, 16); + } + else { + if( EEREC_S == EEREC_T ) { + SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_S, 0xa0); + SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0xa0); + } + else if( EEREC_D == EEREC_T ) { + assert( EEREC_D != EEREC_S ); + t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_PSLLD_I8_to_XMM(EEREC_D, 16); + SSE2_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); + SSE2_PSRLD_I8_to_XMM(EEREC_D, 16); + SSE2_PSLLD_I8_to_XMM(t0reg, 16); + SSE2_POR_XMM_to_XMM(EEREC_D, t0reg); + } + else { + t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); + SSE2_PSLLD_I8_to_XMM(t0reg, 16); + SSE2_PSLLD_I8_to_XMM(EEREC_D, 16); + SSE2_PSRLD_I8_to_XMM(t0reg, 16); + SSE2_POR_XMM_to_XMM(EEREC_D, t0reg); + } + } + + if( t0reg >= 0 ) _freeXMMreg(t0reg); +CPU_SSE_XMMCACHE_END + + recCall( Interp::PINTEH, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPMULTUW() +{ +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED|XMMINFO_WRITELO|XMMINFO_WRITEHI) + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); + + if( EEREC_D == EEREC_S ) SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_T); + } + + // get the signs + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_D); + SSE2_PSRAD_I8_to_XMM(t0reg, 31); + + // interleave + SSE2_PSHUFD_XMM_to_XMM(EEREC_LO, EEREC_D, 0xd8); + SSE2_PSHUFD_XMM_to_XMM(t0reg, t0reg, 0xd8); + SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_LO); + + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_LO, t0reg); + SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_HI, t0reg); + + _freeXMMreg(t0reg); +CPU_SSE_XMMCACHE_END + recCall( Interp::PMULTUW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPMADDUW() +{ +CPU_SSE2_XMMCACHE_START(XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED|XMMINFO_WRITELO|XMMINFO_WRITEHI|XMMINFO_READLO|XMMINFO_READHI) + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + + if( EEREC_D == EEREC_S ) SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PMULUDQ_XMM_to_XMM(EEREC_D, EEREC_T); + } + + // add from LO/HI + SSE2_PSHUFD_XMM_to_XMM(EEREC_LO, EEREC_LO, 0x88); + SSE2_PSHUFD_XMM_to_XMM(EEREC_HI, EEREC_HI, 0x88); + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_LO, EEREC_HI); + SSE2_PADDQ_XMM_to_XMM(EEREC_D, EEREC_LO); + + // get the signs + SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_D); + SSE2_PSRAD_I8_to_XMM(t0reg, 31); + + // interleave + SSE2_PSHUFD_XMM_to_XMM(EEREC_LO, EEREC_D, 0xd8); + SSE2_PSHUFD_XMM_to_XMM(t0reg, t0reg, 0xd8); + SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_LO); + + SSE2_PUNPCKLDQ_XMM_to_XMM(EEREC_LO, t0reg); + SSE2_PUNPCKHDQ_XMM_to_XMM(EEREC_HI, t0reg); + + _freeXMMreg(t0reg); +CPU_SSE_XMMCACHE_END + + recCall( Interp::PMADDUW, _Rd_ ); +} + +//////////////////////////////////////////////////// +//do EEINST_SETSIGNEXT +void recPDIVUW() +{ + recCall( Interp::PDIVUW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPEXCW() +{ + if (!_Rd_) return; + +CPU_SSE_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_T, 0xd8); +CPU_SSE_XMMCACHE_END + +recCall( Interp::PEXCW, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPEXCH( void ) +{ + if (!_Rd_) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_T, 0xd8); + SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0xd8); +CPU_SSE_XMMCACHE_END + + recCall( Interp::PEXCH, _Rd_ ); +} + +//////////////////////////////////////////////////// +void recPNOR( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|(_Rt_!=0?XMMINFO_READT:0)|XMMINFO_WRITED) + + if( _Rs_ == 0 ) { + if( _Rt_ == 0 ) { + SSE2_PCMPEQD_XMM_to_XMM( EEREC_D, EEREC_D ); + } + else { + if( EEREC_D == EEREC_T ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_PCMPEQD_XMM_to_XMM( t0reg, t0reg); + SSEX_PXOR_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSE2_PCMPEQD_XMM_to_XMM( EEREC_D, EEREC_D ); + if( _Rt_ != 0 ) SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + } + else if( _Rt_ == 0 ) { + if( EEREC_D == EEREC_S ) { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_PCMPEQD_XMM_to_XMM( t0reg, t0reg); + SSEX_PXOR_XMM_to_XMM(EEREC_D, t0reg); + _freeXMMreg(t0reg); + } + else { + SSE2_PCMPEQD_XMM_to_XMM( EEREC_D, EEREC_D ); + SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_S); + } + } + else { + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + + if( EEREC_D == EEREC_S ) SSEX_POR_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSEX_POR_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + if( EEREC_S != EEREC_T ) SSEX_POR_XMM_to_XMM(EEREC_D, EEREC_T); + } + + SSE2_PCMPEQD_XMM_to_XMM( t0reg, t0reg ); + SSEX_PXOR_XMM_to_XMM( EEREC_D, t0reg ); + _freeXMMreg(t0reg); + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP3( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + PORMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + PORMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + PCMPEQDRtoR( t2reg, t2reg ); + PXORRtoR( t0reg, t2reg ); + PXORRtoR( t1reg, t2reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPMTHI( void ) +{ +CPU_SSE_XMMCACHE_START(XMMINFO_READS|XMMINFO_WRITEHI) + SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_S); +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(XMMGPR_HI, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQRtoM( (uptr)&cpuRegs.HI.UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.HI.UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPMTLO( void ) +{ +CPU_SSE_XMMCACHE_START(XMMINFO_READS|XMMINFO_WRITELO) + SSEX_MOVDQA_XMM_to_XMM(EEREC_LO, EEREC_S); +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(XMMGPR_LO, 0); + _deleteGPRtoXMMreg(_Rs_, 1); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQRtoM( (uptr)&cpuRegs.LO.UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.LO.UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPCPYUD( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE_XMMCACHE_START(XMMINFO_READS|(( _Rt_ == 0) ? 0:XMMINFO_READT)|XMMINFO_WRITED) + + if( _Rt_ == 0 ) { + if( EEREC_D == EEREC_S ) { + SSE2_PUNPCKHQDQ_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_D); + } + else { + SSE_MOVHLPS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_MOVQ_XMM_to_XMM(EEREC_D, EEREC_D); + } + } + else { + if( EEREC_D == EEREC_S ) SSE2_PUNPCKHQDQ_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) { + //TODO + SSE2_PUNPCKHQDQ_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_D, 0x4e); + } + else { + if( EEREC_S == EEREC_T ) { + SSE2_PSHUFD_XMM_to_XMM(EEREC_D, EEREC_S, 0xee); + } + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + SSE2_PUNPCKHQDQ_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPOR( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE_XMMCACHE_START((_Rs_!=0?XMMINFO_READS:0)|(_Rt_!=0?XMMINFO_READT:0)|XMMINFO_WRITED) + + if( _Rs_ == 0 ) { + if( _Rt_ == 0 ) { + SSEX_PXOR_XMM_to_XMM(EEREC_D, EEREC_D); + } + else SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + } + else if( _Rt_ == 0 ) { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + if( EEREC_D == EEREC_S ) { + SSEX_POR_XMM_to_XMM(EEREC_D, EEREC_T); + } + else if( EEREC_D == EEREC_T ) { + SSEX_POR_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + if( _Rs_ == 0 ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + else if( _Rt_ == 0 ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); + if( EEREC_S != EEREC_T ) { + SSEX_POR_XMM_to_XMM(EEREC_D, EEREC_S); + } + } + } + } +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + MMX_ALLOC_TEMP2( + MOVQMtoR( t0reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQMtoR( t1reg, (uptr)&cpuRegs.GPR.r[ _Rs_ ].UD[ 1 ] ); + if ( _Rt_ != 0 ) + { + PORMtoR ( t0reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + PORMtoR ( t1reg, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + } + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], t0reg ); + MOVQRtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UD[ 1 ], t1reg ); + SetMMXstate(); + ) +} + +//////////////////////////////////////////////////// +void recPCPYH( void ) +{ + if ( ! _Rd_ ) return; + +CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) + SSE2_PSHUFLW_XMM_to_XMM(EEREC_D, EEREC_T, 0); + SSE2_PSHUFHW_XMM_to_XMM(EEREC_D, EEREC_D, 0); +CPU_SSE_XMMCACHE_END + + _flushCachedRegs(); + _deleteEEreg(_Rd_, 0); + + //PUSH32R( EBX ); + MOVZX32M16toR( EAX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + MOV32RtoR( ECX, EAX ); + SHL32ItoR( ECX, 16 ); + OR32RtoR( EAX, ECX ); + MOVZX32M16toR( EDX, (uptr)&cpuRegs.GPR.r[ _Rt_ ].UD[ 1 ] ); + MOV32RtoR( ECX, EDX ); + SHL32ItoR( ECX, 16 ); + OR32RtoR( EDX, ECX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EAX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 2 ], EDX ); + MOV32RtoM( (uptr)&cpuRegs.GPR.r[ _Rd_ ].UL[ 3 ], EDX ); + //POP32R( EBX ); +} + +#endif // else MMI3_RECOMPILE + } } } } \ No newline at end of file diff --git a/pcsx2/x86/iMMI.h b/pcsx2/x86/iMMI.h index b57fe1d9f9..c08705a5e1 100644 --- a/pcsx2/x86/iMMI.h +++ b/pcsx2/x86/iMMI.h @@ -1,147 +1,147 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -//btw, nice box ya got there ! -/********************************************************* -* MMI opcodes * -* * -*********************************************************/ -#ifndef __IMMI_H__ -#define __IMMI_H__ - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl { - - // These are instructions contained the MMI "opcode space" but are not - // actually MMI instructions. They are just specialized versions of standard - // instructions that "fit" into the second pipeline of the EE. - - void recMADD1(); - void recMADDU1(); - void recMADD(); - void recMADDU(); - - void recMTHI1(); - void recMTLO1(); - void recMFHI1(); - void recMFLO1(); - void recMULT1(); - void recMULTU1(); - void recDIV1(); - void recDIVU1(); - -namespace MMI -{ - void recPLZCW(); - void recMMI0(); - void recMMI1(); - void recMMI2(); - void recMMI3(); - void recPMFHL(); - void recPMTHL(); - void recPMAXW(); - void recPMINW(); - void recPPACW(); - void recPEXTLH(); - void recPPACH(); - void recPEXTLB(); - void recPPACB(); - void recPEXT5(); - void recPPAC5(); - void recPABSW(); - void recPADSBH(); - void recPABSH(); - void recPADDUW(); - void recPSUBUW(); - void recPSUBUH(); - void recPEXTUH(); - void recPSUBUB(); - void recPEXTUB(); - void recQFSRV(); - void recPMADDW(); - void recPSLLVW(); - void recPSRLVW(); - void recPMSUBW(); - void recPINTH(); - void recPMULTW(); - void recPDIVW(); - void recPMADDH(); - void recPHMADH(); - void recPMSUBH(); - void recPHMSBH(); - void recPEXEH(); - void recPREVH(); - void recPMULTH(); - void recPDIVBW(); - void recPEXEW(); - void recPROT3W(); - void recPMADDUW(); - void recPSRAVW(); - void recPINTEH(); - void recPMULTUW(); - void recPDIVUW(); - void recPEXCH(); - void recPEXCW(); - - void recPSRLH(); - void recPSRLW(); - void recPSRAH(); - void recPSRAW(); - void recPSLLH(); - void recPSLLW(); - void recPMAXH(); - void recPCGTB(); - void recPCGTH(); - void recPCGTW(); - void recPADDSB(); - void recPADDSH(); - void recPADDSW(); - void recPSUBSB(); - void recPSUBSH(); - void recPSUBSW(); - void recPADDB(); - void recPADDH(); - void recPADDW(); - void recPSUBB(); - void recPSUBH(); - void recPSUBW(); - void recPEXTLW(); - void recPEXTUW(); - void recPMINH(); - void recPCEQB(); - void recPCEQH(); - void recPCEQW(); - void recPADDUB(); - void recPADDUH(); - void recPMFHI(); - void recPMFLO(); - void recPAND(); - void recPXOR(); - void recPCPYLD(); - void recPNOR(); - void recPMTHI(); - void recPMTLO(); - void recPCPYUD(); - void recPOR(); - void recPCPYH(); - -} } } } - -#endif - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +//btw, nice box ya got there ! +/********************************************************* +* MMI opcodes * +* * +*********************************************************/ +#ifndef __IMMI_H__ +#define __IMMI_H__ + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl { + + // These are instructions contained the MMI "opcode space" but are not + // actually MMI instructions. They are just specialized versions of standard + // instructions that "fit" into the second pipeline of the EE. + + void recMADD1(); + void recMADDU1(); + void recMADD(); + void recMADDU(); + + void recMTHI1(); + void recMTLO1(); + void recMFHI1(); + void recMFLO1(); + void recMULT1(); + void recMULTU1(); + void recDIV1(); + void recDIVU1(); + +namespace MMI +{ + void recPLZCW(); + void recMMI0(); + void recMMI1(); + void recMMI2(); + void recMMI3(); + void recPMFHL(); + void recPMTHL(); + void recPMAXW(); + void recPMINW(); + void recPPACW(); + void recPEXTLH(); + void recPPACH(); + void recPEXTLB(); + void recPPACB(); + void recPEXT5(); + void recPPAC5(); + void recPABSW(); + void recPADSBH(); + void recPABSH(); + void recPADDUW(); + void recPSUBUW(); + void recPSUBUH(); + void recPEXTUH(); + void recPSUBUB(); + void recPEXTUB(); + void recQFSRV(); + void recPMADDW(); + void recPSLLVW(); + void recPSRLVW(); + void recPMSUBW(); + void recPINTH(); + void recPMULTW(); + void recPDIVW(); + void recPMADDH(); + void recPHMADH(); + void recPMSUBH(); + void recPHMSBH(); + void recPEXEH(); + void recPREVH(); + void recPMULTH(); + void recPDIVBW(); + void recPEXEW(); + void recPROT3W(); + void recPMADDUW(); + void recPSRAVW(); + void recPINTEH(); + void recPMULTUW(); + void recPDIVUW(); + void recPEXCH(); + void recPEXCW(); + + void recPSRLH(); + void recPSRLW(); + void recPSRAH(); + void recPSRAW(); + void recPSLLH(); + void recPSLLW(); + void recPMAXH(); + void recPCGTB(); + void recPCGTH(); + void recPCGTW(); + void recPADDSB(); + void recPADDSH(); + void recPADDSW(); + void recPSUBSB(); + void recPSUBSH(); + void recPSUBSW(); + void recPADDB(); + void recPADDH(); + void recPADDW(); + void recPSUBB(); + void recPSUBH(); + void recPSUBW(); + void recPEXTLW(); + void recPEXTUW(); + void recPMINH(); + void recPCEQB(); + void recPCEQH(); + void recPCEQW(); + void recPADDUB(); + void recPADDUH(); + void recPMFHI(); + void recPMFLO(); + void recPAND(); + void recPXOR(); + void recPCPYLD(); + void recPNOR(); + void recPMTHI(); + void recPMTLO(); + void recPCPYUD(); + void recPOR(); + void recPCPYH(); + +} } } } + +#endif + diff --git a/pcsx2/x86/iPsxHw.cpp b/pcsx2/x86/iPsxHw.cpp index 7ffcf6ad63..98dc1ad8bf 100644 --- a/pcsx2/x86/iPsxHw.cpp +++ b/pcsx2/x86/iPsxHw.cpp @@ -1,1179 +1,1179 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "PsxCommon.h" -#include "iR5900.h" - -extern int g_pbufi; -extern s8 g_pbuf[1024]; - -#define CONSTREAD8_CALL(name) { \ - iFlushCall(0); \ - CALLFunc((uptr)name); \ - if( sign ) MOVSX32R8toR(EAX, EAX); \ - else MOVZX32R8toR(EAX, EAX); \ -} \ - -static u32 s_16 = 0x10; - -int psxHwConstRead8(u32 x86reg, u32 add, u32 sign) { - - if (add >= 0x1f801600 && add < 0x1f801700) { - PUSH32I(add); - CONSTREAD8_CALL(USBread8); - // since calling from different dll, esp already changed - return 1; - } - - switch (add) { - case 0x1f801040: - CONSTREAD8_CALL(sioRead8); - return 1; - // case 0x1f801050: hard = serial_read8(); break;//for use of serial port ignore for now - -#ifdef PCSX2_DEVBUILD - case 0x1f801100: - case 0x1f801104: - case 0x1f801108: - case 0x1f801110: - case 0x1f801114: - case 0x1f801118: - case 0x1f801120: - case 0x1f801124: - case 0x1f801128: - case 0x1f801480: - case 0x1f801484: - case 0x1f801488: - case 0x1f801490: - case 0x1f801494: - case 0x1f801498: - case 0x1f8014a0: - case 0x1f8014a4: - case 0x1f8014a8: - SysPrintf("8bit counter read %x\n", add); - _eeReadConstMem8(x86reg, (uptr)&psxH[(add) & 0xffff], sign); - return 0; -#endif - - case 0x1f80146e: // DEV9_R_REV - PUSH32I(add); - CONSTREAD8_CALL(DEV9read8); - return 1; - - case 0x1f801800: CONSTREAD8_CALL(cdrRead0); return 1; - case 0x1f801801: CONSTREAD8_CALL(cdrRead1); return 1; - case 0x1f801802: CONSTREAD8_CALL(cdrRead2); return 1; - case 0x1f801803: CONSTREAD8_CALL(cdrRead3); return 1; - - case 0x1f803100: // PS/EE/IOP conf related - if( IS_XMMREG(x86reg) ) SSEX_MOVD_M32_to_XMM(x86reg&0xf, (uptr)&s_16); - MMXONLY(else if( IS_MMXREG(x86reg) ) MOVDMtoMMX(x86reg&0xf, (uptr)&s_16);) - else MOV32ItoR(x86reg, 0x10); - return 0; - - case 0x1F808264: //sio2 serial data feed/fifo_out - CONSTREAD8_CALL(sio2_fifoOut); - return 1; - - default: - _eeReadConstMem8(x86reg, (uptr)&psxH[(add) & 0xffff], sign); - return 0; - } -} - -#define CONSTREAD16_CALL(name) { \ - iFlushCall(0); \ - CALLFunc((uptr)name); \ - if( sign ) MOVSX32R16toR(EAX, EAX); \ - else MOVZX32R16toR(EAX, EAX); \ -} \ - -void psxConstReadCounterMode16(int x86reg, int index, int sign) -{ - if( IS_MMXREG(x86reg) ) { - MMXONLY(MOV16MtoR(ECX, (uptr)&psxCounters[index].mode); - MOVDMtoMMX(x86reg&0xf, (uptr)&psxCounters[index].mode - 2);) - } - else { - if( sign ) MOVSX32M16toR(ECX, (uptr)&psxCounters[index].mode); - else MOVZX32M16toR(ECX, (uptr)&psxCounters[index].mode); - - MOV32RtoR(x86reg, ECX); - } - - AND16ItoR(ECX, ~0x1800); - OR16ItoR(ECX, 0x400); - MOV16RtoM((uptr)&psxCounters[index].mode, ECX); -} - -int psxHwConstRead16(u32 x86reg, u32 add, u32 sign) { - if (add >= 0x1f801600 && add < 0x1f801700) { - PUSH32I(add); - CONSTREAD16_CALL(USBread16); - return 1; - } - - switch (add) { - - case 0x1f801040: - iFlushCall(0); - CALLFunc((uptr)sioRead8); - PUSHR(EAX); - CALLFunc((uptr)sioRead8); - POPR(ECX); - AND32ItoR(ECX, 0xff); - SHL32ItoR(EAX, 8); - OR32RtoR(EAX, ECX); - if( sign ) MOVSX32R16toR(EAX, EAX); - else MOVZX32R16toR(EAX, EAX); - return 1; - - case 0x1f801044: - _eeReadConstMem16(x86reg, (uptr)&sio.StatReg, sign); - return 0; - - case 0x1f801048: - _eeReadConstMem16(x86reg, (uptr)&sio.ModeReg, sign); - return 0; - - case 0x1f80104a: - _eeReadConstMem16(x86reg, (uptr)&sio.CtrlReg, sign); - return 0; - - case 0x1f80104e: - _eeReadConstMem16(x86reg, (uptr)&sio.BaudReg, sign); - return 0; - - // counters[0] - case 0x1f801100: - PUSH32I(0); - CONSTREAD16_CALL(psxRcntRcount16); - ADD32ItoR(ESP, 4); - return 1; - case 0x1f801104: - psxConstReadCounterMode16(x86reg, 0, sign); - return 0; - - case 0x1f801108: - _eeReadConstMem16(x86reg, (uptr)&psxCounters[0].target, sign); - return 0; - - // counters[1] - case 0x1f801110: - PUSH32I(1); - CONSTREAD16_CALL(psxRcntRcount16); - ADD32ItoR(ESP, 4); - return 1; - case 0x1f801114: - psxConstReadCounterMode16(x86reg, 1, sign); - return 0; - - case 0x1f801118: - _eeReadConstMem16(x86reg, (uptr)&psxCounters[1].target, sign); - return 0; - - // counters[2] - case 0x1f801120: - PUSH32I(2); - CONSTREAD16_CALL(psxRcntRcount16); - ADD32ItoR(ESP, 4); - return 1; - case 0x1f801124: - psxConstReadCounterMode16(x86reg, 2, sign); - return 0; - - case 0x1f801128: - _eeReadConstMem16(x86reg, (uptr)&psxCounters[2].target, sign); - return 0; - - case 0x1f80146e: // DEV9_R_REV - PUSH32I(add); - CONSTREAD16_CALL(DEV9read16); - return 1; - - // counters[3] - case 0x1f801480: - PUSH32I(3); - CONSTREAD16_CALL(psxRcntRcount32); - ADD32ItoR(ESP, 4); - return 1; - - case 0x1f801484: - psxConstReadCounterMode16(x86reg, 3, sign); - return 0; - - case 0x1f801488: - _eeReadConstMem16(x86reg, (uptr)&psxCounters[3].target, sign); - return 0; - - // counters[4] - case 0x1f801490: - PUSH32I(4); - CONSTREAD16_CALL(psxRcntRcount32); - ADD32ItoR(ESP, 4); - return 1; - - case 0x1f801494: - psxConstReadCounterMode16(x86reg, 4, sign); - return 0; - - case 0x1f801498: - _eeReadConstMem16(x86reg, (uptr)&psxCounters[4].target, sign); - return 0; - - // counters[5] - case 0x1f8014a0: - PUSH32I(5); - CONSTREAD16_CALL(psxRcntRcount32); - ADD32ItoR(ESP, 4); - return 1; - - case 0x1f8014a4: - psxConstReadCounterMode16(x86reg, 5, sign); - return 0; - - case 0x1f8014a8: - _eeReadConstMem16(x86reg, (uptr)&psxCounters[5].target, sign); - return 0; - - default: - if (add>=0x1f801c00 && add<0x1f801e00) { - - PUSH32I(add); - CONSTREAD16_CALL(SPU2read); - return 1; - } else { - _eeReadConstMem16(x86reg, (uptr)&psxH[(add) & 0xffff], sign); - return 0; - } - } -} - -void psxConstReadCounterMode32(int x86reg, int index) -{ - if( IS_MMXREG(x86reg) ) { - MMXONLY(MOV16MtoR(ECX, (uptr)&psxCounters[index].mode); - MOVDMtoMMX(x86reg&0xf, (uptr)&psxCounters[index].mode);) - } - else { - MOVZX32M16toR(ECX, (uptr)&psxCounters[index].mode); - MOV32RtoR(x86reg, ECX); - } - - //AND16ItoR(ECX, ~0x1800); - //OR16ItoR(ECX, 0x400); - //MOV16RtoM((uptr)&psxCounters[index].mode, ECX); -} - -static u32 s_tempsio; -int psxHwConstRead32(u32 x86reg, u32 add) { - if (add >= 0x1f801600 && add < 0x1f801700) { - iFlushCall(0); - PUSH32I(add); - CALLFunc((uptr)USBread32); - return 1; - } - if (add >= 0x1f808400 && add <= 0x1f808550) {//the size is a complete guess.. - iFlushCall(0); - PUSH32I(add); - CALLFunc((uptr)FWread32); - return 1; - } - - switch (add) { - case 0x1f801040: - iFlushCall(0); - CALLFunc((uptr)sioRead8); - AND32ItoR(EAX, 0xff); - MOV32RtoM((uptr)&s_tempsio, EAX); - CALLFunc((uptr)sioRead8); - AND32ItoR(EAX, 0xff); - SHL32ItoR(EAX, 8); - OR32RtoM((uptr)&s_tempsio, EAX); - - // 3rd - CALLFunc((uptr)sioRead8); - AND32ItoR(EAX, 0xff); - SHL32ItoR(EAX, 16); - OR32RtoM((uptr)&s_tempsio, EAX); - - // 4th - CALLFunc((uptr)sioRead8); - SHL32ItoR(EAX, 24); - OR32MtoR(EAX, (uptr)&s_tempsio); - return 1; - - //case 0x1f801050: hard = serial_read32(); break;//serial port - case 0x1f801078: - PSXHW_LOG("ICTRL 32bit read %x\n", psxHu32(0x1078)); - _eeReadConstMem32(x86reg, (uptr)&psxH[add&0xffff]); - MOV32ItoM((uptr)&psxH[add&0xffff], 0); - return 0; - - // counters[0] - case 0x1f801100: - iFlushCall(0); - PUSH32I(0); - CALLFunc((uptr)psxRcntRcount16); - ADD32ItoR(ESP, 4); - return 1; - case 0x1f801104: - psxConstReadCounterMode32(x86reg, 0); - return 0; - - case 0x1f801108: - _eeReadConstMem32(x86reg, (uptr)&psxCounters[0].target); - return 0; - - // counters[1] - case 0x1f801110: - iFlushCall(0); - PUSH32I(1); - CALLFunc((uptr)psxRcntRcount16); - ADD32ItoR(ESP, 4); - return 1; - case 0x1f801114: - psxConstReadCounterMode32(x86reg, 1); - return 0; - - case 0x1f801118: - _eeReadConstMem32(x86reg, (uptr)&psxCounters[1].target); - return 0; - - // counters[2] - case 0x1f801120: - iFlushCall(0); - PUSH32I(2); - CALLFunc((uptr)psxRcntRcount16); - ADD32ItoR(ESP, 4); - return 1; - case 0x1f801124: - psxConstReadCounterMode32(x86reg, 2); - return 0; - - case 0x1f801128: - _eeReadConstMem32(x86reg, (uptr)&psxCounters[2].target); - return 0; - - // counters[3] - case 0x1f801480: - iFlushCall(0); - PUSH32I(3); - CALLFunc((uptr)psxRcntRcount32); - ADD32ItoR(ESP, 4); - return 1; - - case 0x1f801484: - psxConstReadCounterMode32(x86reg, 3); - return 0; - - case 0x1f801488: - _eeReadConstMem32(x86reg, (uptr)&psxCounters[3].target); - return 0; - - // counters[4] - case 0x1f801490: - iFlushCall(0); - PUSH32I(4); - CALLFunc((uptr)psxRcntRcount32); - ADD32ItoR(ESP, 4); - return 1; - - case 0x1f801494: - psxConstReadCounterMode32(x86reg, 4); - return 0; - - case 0x1f801498: - _eeReadConstMem32(x86reg, (uptr)&psxCounters[4].target); - return 0; - - // counters[5] - case 0x1f8014a0: - iFlushCall(0); - PUSH32I(5); - CALLFunc((uptr)psxRcntRcount32); - ADD32ItoR(ESP, 4); - return 1; - - case 0x1f8014a4: - psxConstReadCounterMode32(x86reg, 5); - return 0; - - case 0x1f8014a8: - _eeReadConstMem32(x86reg, (uptr)&psxCounters[5].target); - return 0; - - case 0x1F808200: - case 0x1F808204: - case 0x1F808208: - case 0x1F80820C: - case 0x1F808210: - case 0x1F808214: - case 0x1F808218: - case 0x1F80821C: - case 0x1F808220: - case 0x1F808224: - case 0x1F808228: - case 0x1F80822C: - case 0x1F808230: - case 0x1F808234: - case 0x1F808238: - case 0x1F80823C: - iFlushCall(0); - PUSH32I((add-0x1F808200)/4); - CALLFunc((uptr)sio2_getSend3); - ADD32ItoR(ESP, 4); - return 1; - - case 0x1F808240: - case 0x1F808248: - case 0x1F808250: - case 0x1F80825C: - iFlushCall(0); - PUSH32I((add-0x1F808240)/8); - CALLFunc((uptr)sio2_getSend1); - ADD32ItoR(ESP, 4); - return 1; - - case 0x1F808244: - case 0x1F80824C: - case 0x1F808254: - case 0x1F808258: - iFlushCall(0); - PUSH32I((add-0x1F808244)/8); - CALLFunc((uptr)sio2_getSend2); - ADD32ItoR(ESP, 4); - return 1; - - case 0x1F808268: - iFlushCall(0); - CALLFunc((uptr)sio2_getCtrl); - return 1; - - case 0x1F80826C: - iFlushCall(0); - CALLFunc((uptr)sio2_getRecv1); - return 1; - - case 0x1F808270: - iFlushCall(0); - CALLFunc((uptr)sio2_getRecv2); - return 1; - - case 0x1F808274: - iFlushCall(0); - CALLFunc((uptr)sio2_getRecv3); - return 1; - - case 0x1F808278: - iFlushCall(0); - CALLFunc((uptr)sio2_get8278); - return 1; - - case 0x1F80827C: - iFlushCall(0); - CALLFunc((uptr)sio2_get827C); - return 1; - - case 0x1F808280: - iFlushCall(0); - CALLFunc((uptr)sio2_getIntr); - return 1; - - case 0x1F801C00: - iFlushCall(0); - PUSH32I(0); - CALLFunc((uptr)SPU2ReadMemAddr); - return 1; - - case 0x1F801500: - iFlushCall(0); - PUSH32I(1); - CALLFunc((uptr)SPU2ReadMemAddr); - return 1; - - default: - _eeReadConstMem32(x86reg, (uptr)&psxH[(add) & 0xffff]); - return 0; - } -} - -#define CONSTWRITE_CALL(name) { \ - _recPushReg(mmreg); \ - iFlushCall(0); \ - CALLFunc((uptr)name); \ - ADD32ItoR(ESP, 4); \ -} \ - -void Write8PrintBuffer(u8 value) -{ - if (value == '\r') return; - if (value == '\n' || g_pbufi >= 1023) { - g_pbuf[g_pbufi++] = 0; g_pbufi = 0; - SysPrintf("%s\n", g_pbuf); return; - } - g_pbuf[g_pbufi++] = value; -} - -void psxHwConstWrite8(u32 add, int mmreg) -{ - if (add >= 0x1f801600 && add < 0x1f801700) { - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(add); - CALLFunc((uptr)USBwrite8); - return; - } - - switch (add) { - case 0x1f801040: - CONSTWRITE_CALL(sioWrite8); break; - //case 0x1f801050: serial_write8(value); break;//serial port - case 0x1f801100: - case 0x1f801104: - case 0x1f801108: - case 0x1f801110: - case 0x1f801114: - case 0x1f801118: - case 0x1f801120: - case 0x1f801124: - case 0x1f801128: - case 0x1f801480: - case 0x1f801484: - case 0x1f801488: - case 0x1f801490: - case 0x1f801494: - case 0x1f801498: - case 0x1f8014a0: - case 0x1f8014a4: - case 0x1f8014a8: - SysPrintf("8bit counter write %x\n", add); - _eeWriteConstMem8((uptr)&psxH[(add) & 0xffff], mmreg); - return; - case 0x1f801800: CONSTWRITE_CALL(cdrWrite0); break; - case 0x1f801801: CONSTWRITE_CALL(cdrWrite1); break; - case 0x1f801802: CONSTWRITE_CALL(cdrWrite2); break; - case 0x1f801803: CONSTWRITE_CALL(cdrWrite3); break; - case 0x1f80380c: CONSTWRITE_CALL(Write8PrintBuffer); break; - case 0x1F808260: CONSTWRITE_CALL(sio2_serialIn); break; - - default: - _eeWriteConstMem8((uptr)&psxH[(add) & 0xffff], mmreg); - return; - } -} - -void psxHwConstWrite16(u32 add, int mmreg) { - if (add >= 0x1f801600 && add < 0x1f801700) { - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(add); - CALLFunc((uptr)USBwrite16); - return; - } - - switch (add) { - case 0x1f801040: - _recPushReg(mmreg); - iFlushCall(0); - CALLFunc((uptr)sioWrite8); - ADD32ItoR(ESP, 1); - CALLFunc((uptr)sioWrite8); - ADD32ItoR(ESP, 3); - return; - case 0x1f801044: - return; - case 0x1f801048: - _eeWriteConstMem16((uptr)&sio.ModeReg, mmreg); - return; - case 0x1f80104a: // control register - CONSTWRITE_CALL(sioWriteCtrl16); - return; - case 0x1f80104e: // baudrate register - _eeWriteConstMem16((uptr)&sio.BaudReg, mmreg); - return; - - case 0x1f801070: - _eeWriteConstMem16OP((uptr)&psxHu32(0x1070), mmreg, 0); // AND operation - return; - - case 0x1f801074: - _eeWriteConstMem16((uptr)&psxHu32(0x1074), mmreg); - iFlushCall(0); - CALLFunc( (uptr)&iopTestIntc ); - return; - - case 0x1f801078: - //According to pSXAuthor this allways becomes 1 on write, but MHPB won't boot if value is not writen ;p - _eeWriteConstMem16((uptr)&psxHu32(0x1078), mmreg); - iFlushCall(0); - CALLFunc( (uptr)&iopTestIntc ); - return; - - // counters[0] - case 0x1f801100: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(0); - CALLFunc((uptr)psxRcntWcount16); - ADD32ItoR(ESP, 8); - return; - case 0x1f801104: - CONSTWRITE_CALL(psxRcnt0Wmode); - return; - case 0x1f801108: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(0); - CALLFunc((uptr)psxRcntWtarget16); - ADD32ItoR(ESP, 8); - return; - - // counters[1] - case 0x1f801110: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(1); - CALLFunc((uptr)psxRcntWcount16); - ADD32ItoR(ESP, 8); - return; - - case 0x1f801114: - CONSTWRITE_CALL(psxRcnt1Wmode); - return; - - case 0x1f801118: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(1); - CALLFunc((uptr)psxRcntWtarget16); - ADD32ItoR(ESP, 8); - return; - - // counters[2] - case 0x1f801120: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(2); - CALLFunc((uptr)psxRcntWcount16); - ADD32ItoR(ESP, 8); - return; - - case 0x1f801124: - CONSTWRITE_CALL(psxRcnt2Wmode); - return; - - case 0x1f801128: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(2); - CALLFunc((uptr)psxRcntWtarget16); - ADD32ItoR(ESP, 8); - return; - - // counters[3] - case 0x1f801480: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(3); - CALLFunc((uptr)psxRcntWcount32); - ADD32ItoR(ESP, 8); - return; - - case 0x1f801484: - CONSTWRITE_CALL(psxRcnt3Wmode); - return; - - case 0x1f801488: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(3); - CALLFunc((uptr)psxRcntWtarget32); - ADD32ItoR(ESP, 8); - return; - - // counters[4] - case 0x1f801490: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(4); - CALLFunc((uptr)psxRcntWcount32); - ADD32ItoR(ESP, 8); - return; - - case 0x1f801494: - CONSTWRITE_CALL(psxRcnt4Wmode); - return; - - case 0x1f801498: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(4); - CALLFunc((uptr)psxRcntWtarget32); - ADD32ItoR(ESP, 8); - return; - - // counters[5] - case 0x1f8014a0: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(5); - CALLFunc((uptr)psxRcntWcount32); - ADD32ItoR(ESP, 8); - return; - - case 0x1f8014a4: - CONSTWRITE_CALL(psxRcnt5Wmode); - return; - - case 0x1f8014a8: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(5); - CALLFunc((uptr)psxRcntWtarget32); - ADD32ItoR(ESP, 8); - return; - - default: - if (add>=0x1f801c00 && add<0x1f801e00) { - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(add); - CALLFunc((uptr)SPU2write); - // leave esp alone - return; - } - - _eeWriteConstMem16((uptr)&psxH[(add) & 0xffff], mmreg); - return; - } -} - -#define recDmaExec(n) { \ - iFlushCall(0); \ - if( n > 6 ) TEST32ItoM((uptr)&HW_DMA_PCR2, 8 << (((n<<2)-28)&0x1f)); \ - else TEST32ItoM((uptr)&HW_DMA_PCR, 8 << (((n<<2))&0x1f)); \ - j8Ptr[5] = JZ8(0); \ - MOV32MtoR(EAX, (uptr)&HW_DMA##n##_CHCR); \ - TEST32ItoR(EAX, 0x01000000); \ - j8Ptr[6] = JZ8(0); \ - \ - _callFunctionArg3((uptr)psxDma##n, MEM_MEMORYTAG, MEM_MEMORYTAG, MEM_X86TAG, (uptr)&HW_DMA##n##_MADR, (uptr)&HW_DMA##n##_BCR, EAX); \ - \ - x86SetJ8( j8Ptr[5] ); \ - x86SetJ8( j8Ptr[6] ); \ -} \ - -#define CONSTWRITE_CALL32(name) { \ - iFlushCall(0); \ - _recPushReg(mmreg); \ - CALLFunc((uptr)name); \ - ADD32ItoR(ESP, 4); \ -} \ - -void psxHwConstWrite32(u32 add, int mmreg) -{ - if (add >= 0x1f801600 && add < 0x1f801700) { - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(add); - CALLFunc((uptr)USBwrite32); - return; - } - if (add >= 0x1f808400 && add <= 0x1f808550) { - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(add); - CALLFunc((uptr)FWwrite32); - return; - } - - switch (add) { - case 0x1f801040: - _recPushReg(mmreg); - iFlushCall(0); - CALLFunc((uptr)sioWrite8); - ADD32ItoR(ESP, 1); - CALLFunc((uptr)sioWrite8); - ADD32ItoR(ESP, 1); - CALLFunc((uptr)sioWrite8); - ADD32ItoR(ESP, 1); - CALLFunc((uptr)sioWrite8); - ADD32ItoR(ESP, 1); - return; - - case 0x1f801070: - _eeWriteConstMem32OP((uptr)&psxHu32(0x1070), mmreg, 0); // and - return; - - case 0x1f801074: - _eeWriteConstMem32((uptr)&psxHu32(0x1074), mmreg); - iFlushCall(0); - CALLFunc( (uptr)&iopTestIntc ); - return; - - case 0x1f801078: - //According to pSXAuthor this allways becomes 1 on write, but MHPB won't boot if value is not writen ;p - _eeWriteConstMem32((uptr)&psxHu32(0x1078), mmreg); - iFlushCall(0); - CALLFunc( (uptr)&iopTestIntc ); - return; - -// case 0x1f801088: -// HW_DMA0_CHCR = value; // DMA0 chcr (MDEC in DMA) -//// DmaExec(0); -// return; - -// case 0x1f801098: -// HW_DMA1_CHCR = value; // DMA1 chcr (MDEC out DMA) -//// DmaExec(1); -// return; - - case 0x1f8010a8: - _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); - recDmaExec(2); - return; - - case 0x1f8010b8: - _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); - recDmaExec(3); - return; - - case 0x1f8010c8: - _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); - recDmaExec(4); - return; - - case 0x1f8010e8: - _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); - recDmaExec(6); - return; - - case 0x1f801508: - _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); - recDmaExec(7); - return; - - case 0x1f801518: - _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); - recDmaExec(8); - return; - - case 0x1f801528: - _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); - recDmaExec(9); - return; - - case 0x1f801538: - _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); - recDmaExec(10); - return; - - case 0x1f801548: - _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); - recDmaExec(11); - return; - - case 0x1f801558: - _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); - recDmaExec(12); - return; - - case 0x1f8010f4: - case 0x1f801574: - { - // u32 tmp = (~value) & HW_DMA_ICR; - _eeMoveMMREGtoR(EAX, mmreg); - MOV32RtoR(ECX, EAX); - NOT32R(ECX); - AND32MtoR(ECX, (uptr)&psxH[(add) & 0xffff]); - - // HW_DMA_ICR = ((tmp ^ value) & 0xffffff) ^ tmp; - XOR32RtoR(EAX, ECX); - AND32ItoR(EAX, 0xffffff); - XOR32RtoR(EAX, ECX); - MOV32RtoM((uptr)&psxH[(add) & 0xffff], EAX); - return; - } - - // counters[0] - case 0x1f801100: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(0); - CALLFunc((uptr)psxRcntWcount16); - ADD32ItoR(ESP, 8); - return; - case 0x1f801104: - CONSTWRITE_CALL32(psxRcnt0Wmode); - return; - case 0x1f801108: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(0); - CALLFunc((uptr)psxRcntWtarget16); - ADD32ItoR(ESP, 8); - return; - - // counters[1] - case 0x1f801110: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(1); - CALLFunc((uptr)psxRcntWcount16); - ADD32ItoR(ESP, 8); - return; - - case 0x1f801114: - CONSTWRITE_CALL32(psxRcnt1Wmode); - return; - - case 0x1f801118: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(1); - CALLFunc((uptr)psxRcntWtarget16); - ADD32ItoR(ESP, 8); - return; - - // counters[2] - case 0x1f801120: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(2); - CALLFunc((uptr)psxRcntWcount16); - ADD32ItoR(ESP, 8); - return; - - case 0x1f801124: - CONSTWRITE_CALL32(psxRcnt2Wmode); - return; - - case 0x1f801128: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(2); - CALLFunc((uptr)psxRcntWtarget16); - ADD32ItoR(ESP, 8); - return; - - // counters[3] - case 0x1f801480: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(3); - CALLFunc((uptr)psxRcntWcount32); - ADD32ItoR(ESP, 8); - return; - - case 0x1f801484: - CONSTWRITE_CALL32(psxRcnt3Wmode); - return; - - case 0x1f801488: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(3); - CALLFunc((uptr)psxRcntWtarget32); - ADD32ItoR(ESP, 8); - return; - - // counters[4] - case 0x1f801490: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(4); - CALLFunc((uptr)psxRcntWcount32); - ADD32ItoR(ESP, 8); - return; - - case 0x1f801494: - CONSTWRITE_CALL32(psxRcnt4Wmode); - return; - - case 0x1f801498: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(4); - CALLFunc((uptr)psxRcntWtarget32); - ADD32ItoR(ESP, 8); - return; - - // counters[5] - case 0x1f8014a0: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(5); - CALLFunc((uptr)psxRcntWcount32); - ADD32ItoR(ESP, 8); - return; - - case 0x1f8014a4: - CONSTWRITE_CALL32(psxRcnt5Wmode); - return; - - case 0x1f8014a8: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(5); - CALLFunc((uptr)psxRcntWtarget32); - ADD32ItoR(ESP, 8); - return; - - case 0x1f8014c0: - SysPrintf("RTC_HOLDMODE 32bit write\n"); - break; - - case 0x1F808200: - case 0x1F808204: - case 0x1F808208: - case 0x1F80820C: - case 0x1F808210: - case 0x1F808214: - case 0x1F808218: - case 0x1F80821C: - case 0x1F808220: - case 0x1F808224: - case 0x1F808228: - case 0x1F80822C: - case 0x1F808230: - case 0x1F808234: - case 0x1F808238: - case 0x1F80823C: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I((add-0x1F808200)/4); - CALLFunc((uptr)sio2_setSend3); - ADD32ItoR(ESP, 8); - return; - - case 0x1F808240: - case 0x1F808248: - case 0x1F808250: - case 0x1F808258: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I((add-0x1F808240)/8); - CALLFunc((uptr)sio2_setSend1); - ADD32ItoR(ESP, 8); - return; - - case 0x1F808244: - case 0x1F80824C: - case 0x1F808254: - case 0x1F80825C: - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I((add-0x1F808244)/8); - CALLFunc((uptr)sio2_setSend2); - ADD32ItoR(ESP, 8); - return; - - case 0x1F808268: CONSTWRITE_CALL32(sio2_setCtrl); return; - case 0x1F808278: CONSTWRITE_CALL32(sio2_set8278); return; - case 0x1F80827C: CONSTWRITE_CALL32(sio2_set827C); return; - case 0x1F808280: CONSTWRITE_CALL32(sio2_setIntr); return; - - case 0x1F8010C0: - _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(0); - CALLFunc((uptr)SPU2WriteMemAddr); - return; - - case 0x1F801500: - _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); - _recPushReg(mmreg); - iFlushCall(0); - PUSH32I(1); - CALLFunc((uptr)SPU2WriteMemAddr); - return; - default: - _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); - return; - } -} - -int psxHw4ConstRead8(u32 x86reg, u32 add, u32 sign) { - switch (add) { - case 0x1f402004: CONSTREAD8_CALL((uptr)cdvdRead04); return 1; - case 0x1f402005: CONSTREAD8_CALL((uptr)cdvdRead05); return 1; - case 0x1f402006: CONSTREAD8_CALL((uptr)cdvdRead06); return 1; - case 0x1f402007: CONSTREAD8_CALL((uptr)cdvdRead07); return 1; - case 0x1f402008: CONSTREAD8_CALL((uptr)cdvdRead08); return 1; - case 0x1f40200A: CONSTREAD8_CALL((uptr)cdvdRead0A); return 1; - case 0x1f40200B: CONSTREAD8_CALL((uptr)cdvdRead0B); return 1; - case 0x1f40200C: CONSTREAD8_CALL((uptr)cdvdRead0C); return 1; - case 0x1f40200D: CONSTREAD8_CALL((uptr)cdvdRead0D); return 1; - case 0x1f40200E: CONSTREAD8_CALL((uptr)cdvdRead0E); return 1; - case 0x1f40200F: CONSTREAD8_CALL((uptr)cdvdRead0F); return 1; - case 0x1f402013: CONSTREAD8_CALL((uptr)cdvdRead13); return 1; - case 0x1f402015: CONSTREAD8_CALL((uptr)cdvdRead15); return 1; - case 0x1f402016: CONSTREAD8_CALL((uptr)cdvdRead16); return 1; - case 0x1f402017: CONSTREAD8_CALL((uptr)cdvdRead17); return 1; - case 0x1f402018: CONSTREAD8_CALL((uptr)cdvdRead18); return 1; - case 0x1f402020: CONSTREAD8_CALL((uptr)cdvdRead20); return 1; - case 0x1f402021: CONSTREAD8_CALL((uptr)cdvdRead21); return 1; - case 0x1f402022: CONSTREAD8_CALL((uptr)cdvdRead22); return 1; - case 0x1f402023: CONSTREAD8_CALL((uptr)cdvdRead23); return 1; - case 0x1f402024: CONSTREAD8_CALL((uptr)cdvdRead24); return 1; - case 0x1f402028: CONSTREAD8_CALL((uptr)cdvdRead28); return 1; - case 0x1f402029: CONSTREAD8_CALL((uptr)cdvdRead29); return 1; - case 0x1f40202A: CONSTREAD8_CALL((uptr)cdvdRead2A); return 1; - case 0x1f40202B: CONSTREAD8_CALL((uptr)cdvdRead2B); return 1; - case 0x1f40202C: CONSTREAD8_CALL((uptr)cdvdRead2C); return 1; - case 0x1f402030: CONSTREAD8_CALL((uptr)cdvdRead30); return 1; - case 0x1f402031: CONSTREAD8_CALL((uptr)cdvdRead31); return 1; - case 0x1f402032: CONSTREAD8_CALL((uptr)cdvdRead32); return 1; - case 0x1f402033: CONSTREAD8_CALL((uptr)cdvdRead33); return 1; - case 0x1f402034: CONSTREAD8_CALL((uptr)cdvdRead34); return 1; - case 0x1f402038: CONSTREAD8_CALL((uptr)cdvdRead38); return 1; - case 0x1f402039: CONSTREAD8_CALL((uptr)cdvdRead39); return 1; - case 0x1f40203A: CONSTREAD8_CALL((uptr)cdvdRead3A); return 1; - default: - Console::Notice("*Unknown 8bit read at address %lx", params add); - XOR32RtoR(x86reg, x86reg); - return 0; - } -} - -void psxHw4ConstWrite8(u32 add, int mmreg) { - switch (add) { - case 0x1f402004: CONSTWRITE_CALL(cdvdWrite04); return; - case 0x1f402005: CONSTWRITE_CALL(cdvdWrite05); return; - case 0x1f402006: CONSTWRITE_CALL(cdvdWrite06); return; - case 0x1f402007: CONSTWRITE_CALL(cdvdWrite07); return; - case 0x1f402008: CONSTWRITE_CALL(cdvdWrite08); return; - case 0x1f40200A: CONSTWRITE_CALL(cdvdWrite0A); return; - case 0x1f40200F: CONSTWRITE_CALL(cdvdWrite0F); return; - case 0x1f402014: CONSTWRITE_CALL(cdvdWrite14); return; - case 0x1f402016: - MMXONLY(_freeMMXregs();) - CONSTWRITE_CALL(cdvdWrite16); - return; - case 0x1f402017: CONSTWRITE_CALL(cdvdWrite17); return; - case 0x1f402018: CONSTWRITE_CALL(cdvdWrite18); return; - case 0x1f40203A: CONSTWRITE_CALL(cdvdWrite3A); return; - default: - Console::Notice("*Unknown 8bit write at address %lx", params add); - return; - } -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "PsxCommon.h" +#include "iR5900.h" + +extern int g_pbufi; +extern s8 g_pbuf[1024]; + +#define CONSTREAD8_CALL(name) { \ + iFlushCall(0); \ + CALLFunc((uptr)name); \ + if( sign ) MOVSX32R8toR(EAX, EAX); \ + else MOVZX32R8toR(EAX, EAX); \ +} \ + +static u32 s_16 = 0x10; + +int psxHwConstRead8(u32 x86reg, u32 add, u32 sign) { + + if (add >= 0x1f801600 && add < 0x1f801700) { + PUSH32I(add); + CONSTREAD8_CALL(USBread8); + // since calling from different dll, esp already changed + return 1; + } + + switch (add) { + case 0x1f801040: + CONSTREAD8_CALL(sioRead8); + return 1; + // case 0x1f801050: hard = serial_read8(); break;//for use of serial port ignore for now + +#ifdef PCSX2_DEVBUILD + case 0x1f801100: + case 0x1f801104: + case 0x1f801108: + case 0x1f801110: + case 0x1f801114: + case 0x1f801118: + case 0x1f801120: + case 0x1f801124: + case 0x1f801128: + case 0x1f801480: + case 0x1f801484: + case 0x1f801488: + case 0x1f801490: + case 0x1f801494: + case 0x1f801498: + case 0x1f8014a0: + case 0x1f8014a4: + case 0x1f8014a8: + SysPrintf("8bit counter read %x\n", add); + _eeReadConstMem8(x86reg, (uptr)&psxH[(add) & 0xffff], sign); + return 0; +#endif + + case 0x1f80146e: // DEV9_R_REV + PUSH32I(add); + CONSTREAD8_CALL(DEV9read8); + return 1; + + case 0x1f801800: CONSTREAD8_CALL(cdrRead0); return 1; + case 0x1f801801: CONSTREAD8_CALL(cdrRead1); return 1; + case 0x1f801802: CONSTREAD8_CALL(cdrRead2); return 1; + case 0x1f801803: CONSTREAD8_CALL(cdrRead3); return 1; + + case 0x1f803100: // PS/EE/IOP conf related + if( IS_XMMREG(x86reg) ) SSEX_MOVD_M32_to_XMM(x86reg&0xf, (uptr)&s_16); + MMXONLY(else if( IS_MMXREG(x86reg) ) MOVDMtoMMX(x86reg&0xf, (uptr)&s_16);) + else MOV32ItoR(x86reg, 0x10); + return 0; + + case 0x1F808264: //sio2 serial data feed/fifo_out + CONSTREAD8_CALL(sio2_fifoOut); + return 1; + + default: + _eeReadConstMem8(x86reg, (uptr)&psxH[(add) & 0xffff], sign); + return 0; + } +} + +#define CONSTREAD16_CALL(name) { \ + iFlushCall(0); \ + CALLFunc((uptr)name); \ + if( sign ) MOVSX32R16toR(EAX, EAX); \ + else MOVZX32R16toR(EAX, EAX); \ +} \ + +void psxConstReadCounterMode16(int x86reg, int index, int sign) +{ + if( IS_MMXREG(x86reg) ) { + MMXONLY(MOV16MtoR(ECX, (uptr)&psxCounters[index].mode); + MOVDMtoMMX(x86reg&0xf, (uptr)&psxCounters[index].mode - 2);) + } + else { + if( sign ) MOVSX32M16toR(ECX, (uptr)&psxCounters[index].mode); + else MOVZX32M16toR(ECX, (uptr)&psxCounters[index].mode); + + MOV32RtoR(x86reg, ECX); + } + + AND16ItoR(ECX, ~0x1800); + OR16ItoR(ECX, 0x400); + MOV16RtoM((uptr)&psxCounters[index].mode, ECX); +} + +int psxHwConstRead16(u32 x86reg, u32 add, u32 sign) { + if (add >= 0x1f801600 && add < 0x1f801700) { + PUSH32I(add); + CONSTREAD16_CALL(USBread16); + return 1; + } + + switch (add) { + + case 0x1f801040: + iFlushCall(0); + CALLFunc((uptr)sioRead8); + PUSHR(EAX); + CALLFunc((uptr)sioRead8); + POPR(ECX); + AND32ItoR(ECX, 0xff); + SHL32ItoR(EAX, 8); + OR32RtoR(EAX, ECX); + if( sign ) MOVSX32R16toR(EAX, EAX); + else MOVZX32R16toR(EAX, EAX); + return 1; + + case 0x1f801044: + _eeReadConstMem16(x86reg, (uptr)&sio.StatReg, sign); + return 0; + + case 0x1f801048: + _eeReadConstMem16(x86reg, (uptr)&sio.ModeReg, sign); + return 0; + + case 0x1f80104a: + _eeReadConstMem16(x86reg, (uptr)&sio.CtrlReg, sign); + return 0; + + case 0x1f80104e: + _eeReadConstMem16(x86reg, (uptr)&sio.BaudReg, sign); + return 0; + + // counters[0] + case 0x1f801100: + PUSH32I(0); + CONSTREAD16_CALL(psxRcntRcount16); + ADD32ItoR(ESP, 4); + return 1; + case 0x1f801104: + psxConstReadCounterMode16(x86reg, 0, sign); + return 0; + + case 0x1f801108: + _eeReadConstMem16(x86reg, (uptr)&psxCounters[0].target, sign); + return 0; + + // counters[1] + case 0x1f801110: + PUSH32I(1); + CONSTREAD16_CALL(psxRcntRcount16); + ADD32ItoR(ESP, 4); + return 1; + case 0x1f801114: + psxConstReadCounterMode16(x86reg, 1, sign); + return 0; + + case 0x1f801118: + _eeReadConstMem16(x86reg, (uptr)&psxCounters[1].target, sign); + return 0; + + // counters[2] + case 0x1f801120: + PUSH32I(2); + CONSTREAD16_CALL(psxRcntRcount16); + ADD32ItoR(ESP, 4); + return 1; + case 0x1f801124: + psxConstReadCounterMode16(x86reg, 2, sign); + return 0; + + case 0x1f801128: + _eeReadConstMem16(x86reg, (uptr)&psxCounters[2].target, sign); + return 0; + + case 0x1f80146e: // DEV9_R_REV + PUSH32I(add); + CONSTREAD16_CALL(DEV9read16); + return 1; + + // counters[3] + case 0x1f801480: + PUSH32I(3); + CONSTREAD16_CALL(psxRcntRcount32); + ADD32ItoR(ESP, 4); + return 1; + + case 0x1f801484: + psxConstReadCounterMode16(x86reg, 3, sign); + return 0; + + case 0x1f801488: + _eeReadConstMem16(x86reg, (uptr)&psxCounters[3].target, sign); + return 0; + + // counters[4] + case 0x1f801490: + PUSH32I(4); + CONSTREAD16_CALL(psxRcntRcount32); + ADD32ItoR(ESP, 4); + return 1; + + case 0x1f801494: + psxConstReadCounterMode16(x86reg, 4, sign); + return 0; + + case 0x1f801498: + _eeReadConstMem16(x86reg, (uptr)&psxCounters[4].target, sign); + return 0; + + // counters[5] + case 0x1f8014a0: + PUSH32I(5); + CONSTREAD16_CALL(psxRcntRcount32); + ADD32ItoR(ESP, 4); + return 1; + + case 0x1f8014a4: + psxConstReadCounterMode16(x86reg, 5, sign); + return 0; + + case 0x1f8014a8: + _eeReadConstMem16(x86reg, (uptr)&psxCounters[5].target, sign); + return 0; + + default: + if (add>=0x1f801c00 && add<0x1f801e00) { + + PUSH32I(add); + CONSTREAD16_CALL(SPU2read); + return 1; + } else { + _eeReadConstMem16(x86reg, (uptr)&psxH[(add) & 0xffff], sign); + return 0; + } + } +} + +void psxConstReadCounterMode32(int x86reg, int index) +{ + if( IS_MMXREG(x86reg) ) { + MMXONLY(MOV16MtoR(ECX, (uptr)&psxCounters[index].mode); + MOVDMtoMMX(x86reg&0xf, (uptr)&psxCounters[index].mode);) + } + else { + MOVZX32M16toR(ECX, (uptr)&psxCounters[index].mode); + MOV32RtoR(x86reg, ECX); + } + + //AND16ItoR(ECX, ~0x1800); + //OR16ItoR(ECX, 0x400); + //MOV16RtoM((uptr)&psxCounters[index].mode, ECX); +} + +static u32 s_tempsio; +int psxHwConstRead32(u32 x86reg, u32 add) { + if (add >= 0x1f801600 && add < 0x1f801700) { + iFlushCall(0); + PUSH32I(add); + CALLFunc((uptr)USBread32); + return 1; + } + if (add >= 0x1f808400 && add <= 0x1f808550) {//the size is a complete guess.. + iFlushCall(0); + PUSH32I(add); + CALLFunc((uptr)FWread32); + return 1; + } + + switch (add) { + case 0x1f801040: + iFlushCall(0); + CALLFunc((uptr)sioRead8); + AND32ItoR(EAX, 0xff); + MOV32RtoM((uptr)&s_tempsio, EAX); + CALLFunc((uptr)sioRead8); + AND32ItoR(EAX, 0xff); + SHL32ItoR(EAX, 8); + OR32RtoM((uptr)&s_tempsio, EAX); + + // 3rd + CALLFunc((uptr)sioRead8); + AND32ItoR(EAX, 0xff); + SHL32ItoR(EAX, 16); + OR32RtoM((uptr)&s_tempsio, EAX); + + // 4th + CALLFunc((uptr)sioRead8); + SHL32ItoR(EAX, 24); + OR32MtoR(EAX, (uptr)&s_tempsio); + return 1; + + //case 0x1f801050: hard = serial_read32(); break;//serial port + case 0x1f801078: + PSXHW_LOG("ICTRL 32bit read %x\n", psxHu32(0x1078)); + _eeReadConstMem32(x86reg, (uptr)&psxH[add&0xffff]); + MOV32ItoM((uptr)&psxH[add&0xffff], 0); + return 0; + + // counters[0] + case 0x1f801100: + iFlushCall(0); + PUSH32I(0); + CALLFunc((uptr)psxRcntRcount16); + ADD32ItoR(ESP, 4); + return 1; + case 0x1f801104: + psxConstReadCounterMode32(x86reg, 0); + return 0; + + case 0x1f801108: + _eeReadConstMem32(x86reg, (uptr)&psxCounters[0].target); + return 0; + + // counters[1] + case 0x1f801110: + iFlushCall(0); + PUSH32I(1); + CALLFunc((uptr)psxRcntRcount16); + ADD32ItoR(ESP, 4); + return 1; + case 0x1f801114: + psxConstReadCounterMode32(x86reg, 1); + return 0; + + case 0x1f801118: + _eeReadConstMem32(x86reg, (uptr)&psxCounters[1].target); + return 0; + + // counters[2] + case 0x1f801120: + iFlushCall(0); + PUSH32I(2); + CALLFunc((uptr)psxRcntRcount16); + ADD32ItoR(ESP, 4); + return 1; + case 0x1f801124: + psxConstReadCounterMode32(x86reg, 2); + return 0; + + case 0x1f801128: + _eeReadConstMem32(x86reg, (uptr)&psxCounters[2].target); + return 0; + + // counters[3] + case 0x1f801480: + iFlushCall(0); + PUSH32I(3); + CALLFunc((uptr)psxRcntRcount32); + ADD32ItoR(ESP, 4); + return 1; + + case 0x1f801484: + psxConstReadCounterMode32(x86reg, 3); + return 0; + + case 0x1f801488: + _eeReadConstMem32(x86reg, (uptr)&psxCounters[3].target); + return 0; + + // counters[4] + case 0x1f801490: + iFlushCall(0); + PUSH32I(4); + CALLFunc((uptr)psxRcntRcount32); + ADD32ItoR(ESP, 4); + return 1; + + case 0x1f801494: + psxConstReadCounterMode32(x86reg, 4); + return 0; + + case 0x1f801498: + _eeReadConstMem32(x86reg, (uptr)&psxCounters[4].target); + return 0; + + // counters[5] + case 0x1f8014a0: + iFlushCall(0); + PUSH32I(5); + CALLFunc((uptr)psxRcntRcount32); + ADD32ItoR(ESP, 4); + return 1; + + case 0x1f8014a4: + psxConstReadCounterMode32(x86reg, 5); + return 0; + + case 0x1f8014a8: + _eeReadConstMem32(x86reg, (uptr)&psxCounters[5].target); + return 0; + + case 0x1F808200: + case 0x1F808204: + case 0x1F808208: + case 0x1F80820C: + case 0x1F808210: + case 0x1F808214: + case 0x1F808218: + case 0x1F80821C: + case 0x1F808220: + case 0x1F808224: + case 0x1F808228: + case 0x1F80822C: + case 0x1F808230: + case 0x1F808234: + case 0x1F808238: + case 0x1F80823C: + iFlushCall(0); + PUSH32I((add-0x1F808200)/4); + CALLFunc((uptr)sio2_getSend3); + ADD32ItoR(ESP, 4); + return 1; + + case 0x1F808240: + case 0x1F808248: + case 0x1F808250: + case 0x1F80825C: + iFlushCall(0); + PUSH32I((add-0x1F808240)/8); + CALLFunc((uptr)sio2_getSend1); + ADD32ItoR(ESP, 4); + return 1; + + case 0x1F808244: + case 0x1F80824C: + case 0x1F808254: + case 0x1F808258: + iFlushCall(0); + PUSH32I((add-0x1F808244)/8); + CALLFunc((uptr)sio2_getSend2); + ADD32ItoR(ESP, 4); + return 1; + + case 0x1F808268: + iFlushCall(0); + CALLFunc((uptr)sio2_getCtrl); + return 1; + + case 0x1F80826C: + iFlushCall(0); + CALLFunc((uptr)sio2_getRecv1); + return 1; + + case 0x1F808270: + iFlushCall(0); + CALLFunc((uptr)sio2_getRecv2); + return 1; + + case 0x1F808274: + iFlushCall(0); + CALLFunc((uptr)sio2_getRecv3); + return 1; + + case 0x1F808278: + iFlushCall(0); + CALLFunc((uptr)sio2_get8278); + return 1; + + case 0x1F80827C: + iFlushCall(0); + CALLFunc((uptr)sio2_get827C); + return 1; + + case 0x1F808280: + iFlushCall(0); + CALLFunc((uptr)sio2_getIntr); + return 1; + + case 0x1F801C00: + iFlushCall(0); + PUSH32I(0); + CALLFunc((uptr)SPU2ReadMemAddr); + return 1; + + case 0x1F801500: + iFlushCall(0); + PUSH32I(1); + CALLFunc((uptr)SPU2ReadMemAddr); + return 1; + + default: + _eeReadConstMem32(x86reg, (uptr)&psxH[(add) & 0xffff]); + return 0; + } +} + +#define CONSTWRITE_CALL(name) { \ + _recPushReg(mmreg); \ + iFlushCall(0); \ + CALLFunc((uptr)name); \ + ADD32ItoR(ESP, 4); \ +} \ + +void Write8PrintBuffer(u8 value) +{ + if (value == '\r') return; + if (value == '\n' || g_pbufi >= 1023) { + g_pbuf[g_pbufi++] = 0; g_pbufi = 0; + SysPrintf("%s\n", g_pbuf); return; + } + g_pbuf[g_pbufi++] = value; +} + +void psxHwConstWrite8(u32 add, int mmreg) +{ + if (add >= 0x1f801600 && add < 0x1f801700) { + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(add); + CALLFunc((uptr)USBwrite8); + return; + } + + switch (add) { + case 0x1f801040: + CONSTWRITE_CALL(sioWrite8); break; + //case 0x1f801050: serial_write8(value); break;//serial port + case 0x1f801100: + case 0x1f801104: + case 0x1f801108: + case 0x1f801110: + case 0x1f801114: + case 0x1f801118: + case 0x1f801120: + case 0x1f801124: + case 0x1f801128: + case 0x1f801480: + case 0x1f801484: + case 0x1f801488: + case 0x1f801490: + case 0x1f801494: + case 0x1f801498: + case 0x1f8014a0: + case 0x1f8014a4: + case 0x1f8014a8: + SysPrintf("8bit counter write %x\n", add); + _eeWriteConstMem8((uptr)&psxH[(add) & 0xffff], mmreg); + return; + case 0x1f801800: CONSTWRITE_CALL(cdrWrite0); break; + case 0x1f801801: CONSTWRITE_CALL(cdrWrite1); break; + case 0x1f801802: CONSTWRITE_CALL(cdrWrite2); break; + case 0x1f801803: CONSTWRITE_CALL(cdrWrite3); break; + case 0x1f80380c: CONSTWRITE_CALL(Write8PrintBuffer); break; + case 0x1F808260: CONSTWRITE_CALL(sio2_serialIn); break; + + default: + _eeWriteConstMem8((uptr)&psxH[(add) & 0xffff], mmreg); + return; + } +} + +void psxHwConstWrite16(u32 add, int mmreg) { + if (add >= 0x1f801600 && add < 0x1f801700) { + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(add); + CALLFunc((uptr)USBwrite16); + return; + } + + switch (add) { + case 0x1f801040: + _recPushReg(mmreg); + iFlushCall(0); + CALLFunc((uptr)sioWrite8); + ADD32ItoR(ESP, 1); + CALLFunc((uptr)sioWrite8); + ADD32ItoR(ESP, 3); + return; + case 0x1f801044: + return; + case 0x1f801048: + _eeWriteConstMem16((uptr)&sio.ModeReg, mmreg); + return; + case 0x1f80104a: // control register + CONSTWRITE_CALL(sioWriteCtrl16); + return; + case 0x1f80104e: // baudrate register + _eeWriteConstMem16((uptr)&sio.BaudReg, mmreg); + return; + + case 0x1f801070: + _eeWriteConstMem16OP((uptr)&psxHu32(0x1070), mmreg, 0); // AND operation + return; + + case 0x1f801074: + _eeWriteConstMem16((uptr)&psxHu32(0x1074), mmreg); + iFlushCall(0); + CALLFunc( (uptr)&iopTestIntc ); + return; + + case 0x1f801078: + //According to pSXAuthor this allways becomes 1 on write, but MHPB won't boot if value is not writen ;p + _eeWriteConstMem16((uptr)&psxHu32(0x1078), mmreg); + iFlushCall(0); + CALLFunc( (uptr)&iopTestIntc ); + return; + + // counters[0] + case 0x1f801100: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(0); + CALLFunc((uptr)psxRcntWcount16); + ADD32ItoR(ESP, 8); + return; + case 0x1f801104: + CONSTWRITE_CALL(psxRcnt0Wmode); + return; + case 0x1f801108: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(0); + CALLFunc((uptr)psxRcntWtarget16); + ADD32ItoR(ESP, 8); + return; + + // counters[1] + case 0x1f801110: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(1); + CALLFunc((uptr)psxRcntWcount16); + ADD32ItoR(ESP, 8); + return; + + case 0x1f801114: + CONSTWRITE_CALL(psxRcnt1Wmode); + return; + + case 0x1f801118: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(1); + CALLFunc((uptr)psxRcntWtarget16); + ADD32ItoR(ESP, 8); + return; + + // counters[2] + case 0x1f801120: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(2); + CALLFunc((uptr)psxRcntWcount16); + ADD32ItoR(ESP, 8); + return; + + case 0x1f801124: + CONSTWRITE_CALL(psxRcnt2Wmode); + return; + + case 0x1f801128: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(2); + CALLFunc((uptr)psxRcntWtarget16); + ADD32ItoR(ESP, 8); + return; + + // counters[3] + case 0x1f801480: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(3); + CALLFunc((uptr)psxRcntWcount32); + ADD32ItoR(ESP, 8); + return; + + case 0x1f801484: + CONSTWRITE_CALL(psxRcnt3Wmode); + return; + + case 0x1f801488: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(3); + CALLFunc((uptr)psxRcntWtarget32); + ADD32ItoR(ESP, 8); + return; + + // counters[4] + case 0x1f801490: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(4); + CALLFunc((uptr)psxRcntWcount32); + ADD32ItoR(ESP, 8); + return; + + case 0x1f801494: + CONSTWRITE_CALL(psxRcnt4Wmode); + return; + + case 0x1f801498: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(4); + CALLFunc((uptr)psxRcntWtarget32); + ADD32ItoR(ESP, 8); + return; + + // counters[5] + case 0x1f8014a0: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(5); + CALLFunc((uptr)psxRcntWcount32); + ADD32ItoR(ESP, 8); + return; + + case 0x1f8014a4: + CONSTWRITE_CALL(psxRcnt5Wmode); + return; + + case 0x1f8014a8: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(5); + CALLFunc((uptr)psxRcntWtarget32); + ADD32ItoR(ESP, 8); + return; + + default: + if (add>=0x1f801c00 && add<0x1f801e00) { + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(add); + CALLFunc((uptr)SPU2write); + // leave esp alone + return; + } + + _eeWriteConstMem16((uptr)&psxH[(add) & 0xffff], mmreg); + return; + } +} + +#define recDmaExec(n) { \ + iFlushCall(0); \ + if( n > 6 ) TEST32ItoM((uptr)&HW_DMA_PCR2, 8 << (((n<<2)-28)&0x1f)); \ + else TEST32ItoM((uptr)&HW_DMA_PCR, 8 << (((n<<2))&0x1f)); \ + j8Ptr[5] = JZ8(0); \ + MOV32MtoR(EAX, (uptr)&HW_DMA##n##_CHCR); \ + TEST32ItoR(EAX, 0x01000000); \ + j8Ptr[6] = JZ8(0); \ + \ + _callFunctionArg3((uptr)psxDma##n, MEM_MEMORYTAG, MEM_MEMORYTAG, MEM_X86TAG, (uptr)&HW_DMA##n##_MADR, (uptr)&HW_DMA##n##_BCR, EAX); \ + \ + x86SetJ8( j8Ptr[5] ); \ + x86SetJ8( j8Ptr[6] ); \ +} \ + +#define CONSTWRITE_CALL32(name) { \ + iFlushCall(0); \ + _recPushReg(mmreg); \ + CALLFunc((uptr)name); \ + ADD32ItoR(ESP, 4); \ +} \ + +void psxHwConstWrite32(u32 add, int mmreg) +{ + if (add >= 0x1f801600 && add < 0x1f801700) { + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(add); + CALLFunc((uptr)USBwrite32); + return; + } + if (add >= 0x1f808400 && add <= 0x1f808550) { + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(add); + CALLFunc((uptr)FWwrite32); + return; + } + + switch (add) { + case 0x1f801040: + _recPushReg(mmreg); + iFlushCall(0); + CALLFunc((uptr)sioWrite8); + ADD32ItoR(ESP, 1); + CALLFunc((uptr)sioWrite8); + ADD32ItoR(ESP, 1); + CALLFunc((uptr)sioWrite8); + ADD32ItoR(ESP, 1); + CALLFunc((uptr)sioWrite8); + ADD32ItoR(ESP, 1); + return; + + case 0x1f801070: + _eeWriteConstMem32OP((uptr)&psxHu32(0x1070), mmreg, 0); // and + return; + + case 0x1f801074: + _eeWriteConstMem32((uptr)&psxHu32(0x1074), mmreg); + iFlushCall(0); + CALLFunc( (uptr)&iopTestIntc ); + return; + + case 0x1f801078: + //According to pSXAuthor this allways becomes 1 on write, but MHPB won't boot if value is not writen ;p + _eeWriteConstMem32((uptr)&psxHu32(0x1078), mmreg); + iFlushCall(0); + CALLFunc( (uptr)&iopTestIntc ); + return; + +// case 0x1f801088: +// HW_DMA0_CHCR = value; // DMA0 chcr (MDEC in DMA) +//// DmaExec(0); +// return; + +// case 0x1f801098: +// HW_DMA1_CHCR = value; // DMA1 chcr (MDEC out DMA) +//// DmaExec(1); +// return; + + case 0x1f8010a8: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(2); + return; + + case 0x1f8010b8: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(3); + return; + + case 0x1f8010c8: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(4); + return; + + case 0x1f8010e8: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(6); + return; + + case 0x1f801508: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(7); + return; + + case 0x1f801518: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(8); + return; + + case 0x1f801528: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(9); + return; + + case 0x1f801538: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(10); + return; + + case 0x1f801548: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(11); + return; + + case 0x1f801558: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + recDmaExec(12); + return; + + case 0x1f8010f4: + case 0x1f801574: + { + // u32 tmp = (~value) & HW_DMA_ICR; + _eeMoveMMREGtoR(EAX, mmreg); + MOV32RtoR(ECX, EAX); + NOT32R(ECX); + AND32MtoR(ECX, (uptr)&psxH[(add) & 0xffff]); + + // HW_DMA_ICR = ((tmp ^ value) & 0xffffff) ^ tmp; + XOR32RtoR(EAX, ECX); + AND32ItoR(EAX, 0xffffff); + XOR32RtoR(EAX, ECX); + MOV32RtoM((uptr)&psxH[(add) & 0xffff], EAX); + return; + } + + // counters[0] + case 0x1f801100: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(0); + CALLFunc((uptr)psxRcntWcount16); + ADD32ItoR(ESP, 8); + return; + case 0x1f801104: + CONSTWRITE_CALL32(psxRcnt0Wmode); + return; + case 0x1f801108: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(0); + CALLFunc((uptr)psxRcntWtarget16); + ADD32ItoR(ESP, 8); + return; + + // counters[1] + case 0x1f801110: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(1); + CALLFunc((uptr)psxRcntWcount16); + ADD32ItoR(ESP, 8); + return; + + case 0x1f801114: + CONSTWRITE_CALL32(psxRcnt1Wmode); + return; + + case 0x1f801118: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(1); + CALLFunc((uptr)psxRcntWtarget16); + ADD32ItoR(ESP, 8); + return; + + // counters[2] + case 0x1f801120: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(2); + CALLFunc((uptr)psxRcntWcount16); + ADD32ItoR(ESP, 8); + return; + + case 0x1f801124: + CONSTWRITE_CALL32(psxRcnt2Wmode); + return; + + case 0x1f801128: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(2); + CALLFunc((uptr)psxRcntWtarget16); + ADD32ItoR(ESP, 8); + return; + + // counters[3] + case 0x1f801480: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(3); + CALLFunc((uptr)psxRcntWcount32); + ADD32ItoR(ESP, 8); + return; + + case 0x1f801484: + CONSTWRITE_CALL32(psxRcnt3Wmode); + return; + + case 0x1f801488: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(3); + CALLFunc((uptr)psxRcntWtarget32); + ADD32ItoR(ESP, 8); + return; + + // counters[4] + case 0x1f801490: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(4); + CALLFunc((uptr)psxRcntWcount32); + ADD32ItoR(ESP, 8); + return; + + case 0x1f801494: + CONSTWRITE_CALL32(psxRcnt4Wmode); + return; + + case 0x1f801498: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(4); + CALLFunc((uptr)psxRcntWtarget32); + ADD32ItoR(ESP, 8); + return; + + // counters[5] + case 0x1f8014a0: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(5); + CALLFunc((uptr)psxRcntWcount32); + ADD32ItoR(ESP, 8); + return; + + case 0x1f8014a4: + CONSTWRITE_CALL32(psxRcnt5Wmode); + return; + + case 0x1f8014a8: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(5); + CALLFunc((uptr)psxRcntWtarget32); + ADD32ItoR(ESP, 8); + return; + + case 0x1f8014c0: + SysPrintf("RTC_HOLDMODE 32bit write\n"); + break; + + case 0x1F808200: + case 0x1F808204: + case 0x1F808208: + case 0x1F80820C: + case 0x1F808210: + case 0x1F808214: + case 0x1F808218: + case 0x1F80821C: + case 0x1F808220: + case 0x1F808224: + case 0x1F808228: + case 0x1F80822C: + case 0x1F808230: + case 0x1F808234: + case 0x1F808238: + case 0x1F80823C: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I((add-0x1F808200)/4); + CALLFunc((uptr)sio2_setSend3); + ADD32ItoR(ESP, 8); + return; + + case 0x1F808240: + case 0x1F808248: + case 0x1F808250: + case 0x1F808258: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I((add-0x1F808240)/8); + CALLFunc((uptr)sio2_setSend1); + ADD32ItoR(ESP, 8); + return; + + case 0x1F808244: + case 0x1F80824C: + case 0x1F808254: + case 0x1F80825C: + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I((add-0x1F808244)/8); + CALLFunc((uptr)sio2_setSend2); + ADD32ItoR(ESP, 8); + return; + + case 0x1F808268: CONSTWRITE_CALL32(sio2_setCtrl); return; + case 0x1F808278: CONSTWRITE_CALL32(sio2_set8278); return; + case 0x1F80827C: CONSTWRITE_CALL32(sio2_set827C); return; + case 0x1F808280: CONSTWRITE_CALL32(sio2_setIntr); return; + + case 0x1F8010C0: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(0); + CALLFunc((uptr)SPU2WriteMemAddr); + return; + + case 0x1F801500: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + _recPushReg(mmreg); + iFlushCall(0); + PUSH32I(1); + CALLFunc((uptr)SPU2WriteMemAddr); + return; + default: + _eeWriteConstMem32((uptr)&psxH[(add) & 0xffff], mmreg); + return; + } +} + +int psxHw4ConstRead8(u32 x86reg, u32 add, u32 sign) { + switch (add) { + case 0x1f402004: CONSTREAD8_CALL((uptr)cdvdRead04); return 1; + case 0x1f402005: CONSTREAD8_CALL((uptr)cdvdRead05); return 1; + case 0x1f402006: CONSTREAD8_CALL((uptr)cdvdRead06); return 1; + case 0x1f402007: CONSTREAD8_CALL((uptr)cdvdRead07); return 1; + case 0x1f402008: CONSTREAD8_CALL((uptr)cdvdRead08); return 1; + case 0x1f40200A: CONSTREAD8_CALL((uptr)cdvdRead0A); return 1; + case 0x1f40200B: CONSTREAD8_CALL((uptr)cdvdRead0B); return 1; + case 0x1f40200C: CONSTREAD8_CALL((uptr)cdvdRead0C); return 1; + case 0x1f40200D: CONSTREAD8_CALL((uptr)cdvdRead0D); return 1; + case 0x1f40200E: CONSTREAD8_CALL((uptr)cdvdRead0E); return 1; + case 0x1f40200F: CONSTREAD8_CALL((uptr)cdvdRead0F); return 1; + case 0x1f402013: CONSTREAD8_CALL((uptr)cdvdRead13); return 1; + case 0x1f402015: CONSTREAD8_CALL((uptr)cdvdRead15); return 1; + case 0x1f402016: CONSTREAD8_CALL((uptr)cdvdRead16); return 1; + case 0x1f402017: CONSTREAD8_CALL((uptr)cdvdRead17); return 1; + case 0x1f402018: CONSTREAD8_CALL((uptr)cdvdRead18); return 1; + case 0x1f402020: CONSTREAD8_CALL((uptr)cdvdRead20); return 1; + case 0x1f402021: CONSTREAD8_CALL((uptr)cdvdRead21); return 1; + case 0x1f402022: CONSTREAD8_CALL((uptr)cdvdRead22); return 1; + case 0x1f402023: CONSTREAD8_CALL((uptr)cdvdRead23); return 1; + case 0x1f402024: CONSTREAD8_CALL((uptr)cdvdRead24); return 1; + case 0x1f402028: CONSTREAD8_CALL((uptr)cdvdRead28); return 1; + case 0x1f402029: CONSTREAD8_CALL((uptr)cdvdRead29); return 1; + case 0x1f40202A: CONSTREAD8_CALL((uptr)cdvdRead2A); return 1; + case 0x1f40202B: CONSTREAD8_CALL((uptr)cdvdRead2B); return 1; + case 0x1f40202C: CONSTREAD8_CALL((uptr)cdvdRead2C); return 1; + case 0x1f402030: CONSTREAD8_CALL((uptr)cdvdRead30); return 1; + case 0x1f402031: CONSTREAD8_CALL((uptr)cdvdRead31); return 1; + case 0x1f402032: CONSTREAD8_CALL((uptr)cdvdRead32); return 1; + case 0x1f402033: CONSTREAD8_CALL((uptr)cdvdRead33); return 1; + case 0x1f402034: CONSTREAD8_CALL((uptr)cdvdRead34); return 1; + case 0x1f402038: CONSTREAD8_CALL((uptr)cdvdRead38); return 1; + case 0x1f402039: CONSTREAD8_CALL((uptr)cdvdRead39); return 1; + case 0x1f40203A: CONSTREAD8_CALL((uptr)cdvdRead3A); return 1; + default: + Console::Notice("*Unknown 8bit read at address %lx", params add); + XOR32RtoR(x86reg, x86reg); + return 0; + } +} + +void psxHw4ConstWrite8(u32 add, int mmreg) { + switch (add) { + case 0x1f402004: CONSTWRITE_CALL(cdvdWrite04); return; + case 0x1f402005: CONSTWRITE_CALL(cdvdWrite05); return; + case 0x1f402006: CONSTWRITE_CALL(cdvdWrite06); return; + case 0x1f402007: CONSTWRITE_CALL(cdvdWrite07); return; + case 0x1f402008: CONSTWRITE_CALL(cdvdWrite08); return; + case 0x1f40200A: CONSTWRITE_CALL(cdvdWrite0A); return; + case 0x1f40200F: CONSTWRITE_CALL(cdvdWrite0F); return; + case 0x1f402014: CONSTWRITE_CALL(cdvdWrite14); return; + case 0x1f402016: + MMXONLY(_freeMMXregs();) + CONSTWRITE_CALL(cdvdWrite16); + return; + case 0x1f402017: CONSTWRITE_CALL(cdvdWrite17); return; + case 0x1f402018: CONSTWRITE_CALL(cdvdWrite18); return; + case 0x1f40203A: CONSTWRITE_CALL(cdvdWrite3A); return; + default: + Console::Notice("*Unknown 8bit write at address %lx", params add); + return; + } +} diff --git a/pcsx2/x86/iPsxMem.cpp b/pcsx2/x86/iPsxMem.cpp index f6201a2164..4b14aaeb23 100644 --- a/pcsx2/x86/iPsxMem.cpp +++ b/pcsx2/x86/iPsxMem.cpp @@ -1,871 +1,871 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "PsxCommon.h" -#include "iR3000A.h" -#include "VU.h" - - -extern int g_psxWriteOk; -extern u32 g_psxMaxRecMem; -static u32 writectrl; - -#ifdef PCSX2_VIRTUAL_MEM - -#ifdef _DEBUG - -#define ASSERT_WRITEOK \ -{ \ - __asm cmp g_psxWriteOk, 1 \ - __asm je WriteOk \ - __asm int 10 \ -} \ -WriteOk: \ - -#else -#define ASSERT_WRITEOK -#endif - -__declspec(naked) void psxRecMemRead8() -{ - __asm { - mov edx, ecx - shr edx, 16 - cmp dx, 0x1f80 - je hwread - cmp dx, 0x1f40 - je hw4read - cmp dx, 0x1000 - je devread - cmp dx, 0x1f00 - je spuread - } - - ASSERT_WRITEOK - - __asm { -memread: - // rom reads, has to be PS2MEM_BASE_ - mov eax, dword ptr [ecx+PS2MEM_BASE_] - ret - -hwread: - cmp cx, 0x1000 - jb memread - - push ecx - call psxHwRead8 - add esp, 4 - ret - -hw4read: - push ecx - call psxHw4Read8 - add esp, 4 - ret - -devread: - push ecx - call DEV9read8 - // stack already incremented - ret - -spuread: - push ecx - call SPU2read - // stack already incremented - ret - } -} - -int psxRecMemConstRead8(u32 x86reg, u32 mem, u32 sign) -{ - u32 t = (mem >> 16) & 0x1fff; - - switch(t) { - case 0x1f80: - return psxHwConstRead8(x86reg, mem&0x1fffffff, sign); - -#ifdef _DEBUG - case 0x1d00: assert(0); -#endif - - case 0x1f40: - return psxHw4ConstRead8(x86reg, mem&0x1fffffff, sign); - - case 0x1000: - PUSH32I(mem&0x1fffffff); - CALLFunc((uptr)DEV9read8); - if( sign ) MOVSX32R8toR(x86reg, EAX); - else MOVZX32R8toR(x86reg, EAX); - return 0; - - default: - _eeReadConstMem8(x86reg, (u32)PSXM(mem), sign); - return 0; - } -} - -__declspec(naked) void psxRecMemRead16() -{ - __asm { - mov edx, ecx - shr edx, 16 - cmp dx, 0x1f80 - je hwread - cmp dx, 0x1f90 - je spuread - cmp dx, 0x1d00 - je sifread - cmp dx, 0x1000 - je devread - } - - ASSERT_WRITEOK - - __asm { -memread: - // rom reads, has to be PS2MEM_BASE_ - mov eax, dword ptr [ecx+PS2MEM_BASE_] - ret - -hwread: - cmp cx, 0x1000 - jb memread - - push ecx - call psxHwRead16 - add esp, 4 - ret - -sifread: - mov edx, ecx - and edx, 0xf0 - cmp dl, 0x60 - je Sif60 - - - mov eax, dword ptr [edx+PS2MEM_BASE_+0x1000f200] - - cmp dl, 0x40 - jne End - - // 0x40 - or eax, 2 - jmp End -Sif60: - xor eax, eax - jmp End - -spuread: - push ecx - call SPU2read - // stack already incremented - -End: - ret - -devread: - push ecx - call DEV9read16 - // stack already incremented - ret - } -} - -int psxRecMemConstRead16(u32 x86reg, u32 mem, u32 sign) -{ - u32 t = (mem >> 16) & 0x1fff; - - switch(t) { - case 0x1f80: return psxHwConstRead16(x86reg, mem&0x1fffffff, sign); - - case 0x1d00: - - switch(mem & 0xF0) - { - case 0x40: - _eeReadConstMem16(x86reg, (u32)PS2MEM_HW+0xF240, sign); - OR32ItoR(x86reg, 0x0002); - break; - case 0x60: - XOR32RtoR(x86reg, x86reg); - break; - default: - _eeReadConstMem16(x86reg, (u32)PS2MEM_HW+0xf200+(mem&0xf0), sign); - break; - } - return 0; - - case 0x1f90: - PUSH32I(mem&0x1fffffff); - CALLFunc((uptr)SPU2read); - if( sign ) MOVSX32R16toR(x86reg, EAX); - else MOVZX32R16toR(x86reg, EAX); - return 0; - - case 0x1000: - PUSH32I(mem&0x1fffffff); - CALLFunc((uptr)DEV9read16); - if( sign ) MOVSX32R16toR(x86reg, EAX); - else MOVZX32R16toR(x86reg, EAX); - return 0; - - default: - assert( g_psxWriteOk ); - _eeReadConstMem16(x86reg, (u32)PSXM(mem), sign); - return 0; - } - - return 0; -} - -__declspec(naked) void psxRecMemRead32() -{ - __asm { - mov edx, ecx - shr edx, 16 - cmp dx, 0x1f80 - je hwread - cmp dx, 0x1d00 - je sifread - cmp dx, 0x1000 - je devread - cmp ecx, 0x1ffe0130 - je WriteCtrlRead - } - - ASSERT_WRITEOK - - __asm { -memread: - // rom reads, has to be PS2MEM_BASE_ - mov eax, dword ptr [ecx+PS2MEM_BASE_] - ret - -hwread: - cmp cx, 0x1000 - jb memread - - push ecx - call psxHwRead32 - add esp, 4 - ret - -sifread: - mov edx, ecx - and edx, 0xf0 - cmp dl, 0x60 - je Sif60 - - // do the read from ps2 mem - mov eax, dword ptr [edx+PS2MEM_BASE_+0x1000f200] - - cmp dl, 0x40 - jne End - - // 0x40 - or eax, 0xf0000002 - jmp End -Sif60: - xor eax, eax -End: - ret - -devread: - push ecx - call DEV9read32 - // stack already incremented - ret - -WriteCtrlRead: - mov eax, writectrl - ret - } -} - -int psxRecMemConstRead32(u32 x86reg, u32 mem) -{ - u32 t = (mem >> 16) & 0x1fff; - - switch(t) { - case 0x1f80: return psxHwConstRead32(x86reg, mem&0x1fffffff); - - case 0x1d00: - switch(mem & 0xF0) - { - case 0x40: - _eeReadConstMem32(x86reg, (u32)PS2MEM_HW+0xF240); - OR32ItoR(x86reg, 0xf0000002); - break; - case 0x60: - XOR32RtoR(x86reg, x86reg); - break; - default: - _eeReadConstMem32(x86reg, (u32)PS2MEM_HW+0xf200+(mem&0xf0)); - break; - } - return 0; - - case 0x1000: - PUSH32I(mem&0x1fffffff); - CALLFunc((uptr)DEV9read32); - return 1; - - default: - if( mem == 0xfffe0130 ) - MOV32MtoR(x86reg, (uptr)&writectrl); - else { - XOR32RtoR(x86reg, x86reg); - CMP32ItoM((uptr)&g_psxWriteOk, 0); - CMOVNE32MtoR(x86reg, (u32)PSXM(mem)); - } - - return 0; - } -} - -__declspec(naked) void psxRecMemWrite8() -{ - __asm { - mov edx, ecx - shr edx, 16 - cmp dx, 0x1f80 - je hwwrite - cmp dx, 0x1f40 - je hw4write - cmp dx, 0x1000 - je devwrite - } - - ASSERT_WRITEOK - - __asm { -memwrite: - // rom writes, has to be PS2MEM_BASE_ - mov byte ptr [ecx+PS2MEM_BASE_], al - ret - -hwwrite: - cmp cx, 0x1000 - jb memwrite - - push eax - push ecx - call psxHwWrite8 - add esp, 8 - ret - -hw4write: - push eax - push ecx - call psxHw4Write8 - add esp, 8 - ret - -devwrite: - push eax - push ecx - call DEV9write8 - // stack alwritey incremented - ret - } -} - -int psxRecMemConstWrite8(u32 mem, int mmreg) -{ - u32 t = (mem >> 16) & 0x1fff; - - switch(t) { - case 0x1f80: - psxHwConstWrite8(mem&0x1fffffff, mmreg); - return 0; - case 0x1f40: - psxHw4ConstWrite8(mem&0x1fffffff, mmreg); - return 0; - - case 0x1d00: - assert(0); - _eeWriteConstMem8((u32)(PS2MEM_HW+0xf200+(mem&0xff)), mmreg); - return 0; - - case 0x1000: - _recPushReg(mmreg); - PUSH32I(mem&0x1fffffff); - CALLFunc((uptr)DEV9write8); - return 0; - - default: - _eeWriteConstMem8((u32)PSXM(mem), mmreg); - return 1; - } -} - -__declspec(naked) void psxRecMemWrite16() -{ - __asm { - mov edx, ecx - shr edx, 16 - cmp dx, 0x1f80 - je hwwrite - cmp dx, 0x1f90 - je spuwrite - cmp dx, 0x1d00 - je sifwrite - cmp dx, 0x1000 - je devwrite - cmp dx, 0x1600 - je ignorewrite - } - - ASSERT_WRITEOK - - __asm { -memwrite: - // rom writes, has to be PS2MEM_BASE_ - mov word ptr [ecx+PS2MEM_BASE_], ax - ret - -hwwrite: - cmp cx, 0x1000 - jb memwrite - - push eax - push ecx - call psxHwWrite16 - add esp, 8 - ret - -sifwrite: - mov edx, ecx - and edx, 0xf0 - cmp dl, 0x60 - je Sif60 - cmp dl, 0x40 - je Sif40 - - mov word ptr [edx+PS2MEM_BASE_+0x1000f200], ax - ret - -Sif40: - mov bx, word ptr [edx+PS2MEM_BASE_+0x1000f200] - test ax, 0xa0 - jz Sif40_2 - // psHu16(0x1000F240) &= ~0xF000; - // psHu16(0x1000F240) |= 0x2000; - and bx, 0x0fff - or bx, 0x2000 - -Sif40_2: - // if(psHu16(0x1000F240) & temp) psHu16(0x1000F240) &= ~temp; - // else psHu16(0x1000F240) |= temp; - and ax, 0xf0 - test bx, ax - jz Sif40_3 - - not ax - and bx, ax - jmp Sif40_4 -Sif40_3: - or bx, ax -Sif40_4: - mov word ptr [edx+PS2MEM_BASE_+0x1000f200], bx - ret - -Sif60: - mov word ptr [edx+PS2MEM_BASE_+0x1000f200], 0 - ret - -spuwrite: - push eax - push ecx - call SPU2write - // stack alwritey incremented - ret - -devwrite: - push eax - push ecx - call DEV9write16 - // stack alwritey incremented - ret - -ignorewrite: - ret - } -} - -int psxRecMemConstWrite16(u32 mem, int mmreg) -{ - u32 t = (mem >> 16) & 0x1fff; - switch(t) { - case 0x1600: - //HACK: DEV9 VM crash fix - return 0; - case 0x1f80: - psxHwConstWrite16(mem&0x1fffffff, mmreg); - return 0; - - case 0x1d00: - switch (mem & 0xf0) { - case 0x10: - // write to ps2 mem - _eeWriteConstMem16((u32)(PS2MEM_HW+0xf210), mmreg); - return 0; - case 0x40: - { - // delete x86reg - _eeMoveMMREGtoR(EAX, mmreg); - - assert( mmreg != EBX ); - MOV16MtoR(EBX, (u32)PS2MEM_HW+0xf240); - TEST16ItoR(EAX, 0xa0); - j8Ptr[0] = JZ8(0); - - AND16ItoR(EBX, 0x0fff); - OR16ItoR(EBX, 0x2000); - - x86SetJ8(j8Ptr[0]); - - AND16ItoR(EAX, 0xf0); - TEST16RtoR(EAX, 0xf0); - j8Ptr[0] = JZ8(0); - - NOT32R(EAX); - AND16RtoR(EBX, EAX); - j8Ptr[1] = JMP8(0); - - x86SetJ8(j8Ptr[0]); - OR16RtoR(EBX, EAX); - - x86SetJ8(j8Ptr[1]); - - MOV16RtoM((u32)PS2MEM_HW+0xf240, EBX); - - return 0; - } - case 0x60: - MOV32ItoM((u32)(PS2MEM_HW+0xf260), 0); - return 0; - default: - assert(0); - } - return 0; - - case 0x1f90: - _recPushReg(mmreg); - PUSH32I(mem&0x1fffffff); - CALLFunc((uptr)SPU2write); - return 0; - - case 0x1000: - _recPushReg(mmreg); - PUSH32I(mem&0x1fffffff); - CALLFunc((uptr)DEV9write16); - return 0; - - default: - _eeWriteConstMem16((u32)PSXM(mem), mmreg); - return 1; - } -} - -__declspec(naked) void psxRecMemWrite32() -{ - __asm { - mov edx, ecx - shr edx, 16 - cmp dx, 0x1f80 - je hwwrite - cmp dx, 0x1d00 - je sifwrite - cmp dx, 0x1000 - je devwrite - cmp dx, 0x1ffe - je WriteCtrl - } - - __asm { - // rom writes, has to be PS2MEM_BASE_ - test g_psxWriteOk, 1 - jz endwrite - -memwrite: - mov dword ptr [ecx+PS2MEM_BASE_], eax -endwrite: - ret - -hwwrite: - cmp cx, 0x1000 - jb memwrite - - push eax - push ecx - call psxHwWrite32 - add esp, 8 - ret - -sifwrite: - mov edx, ecx - and edx, 0xf0 - cmp dl, 0x60 - je Sif60 - cmp dl, 0x40 - je Sif40 - cmp dl, 0x30 - je Sif30 - cmp dl, 0x20 - je Sif20 - - mov dword ptr [edx+PS2MEM_BASE_+0x1000f200], eax - ret - -Sif40: - mov bx, word ptr [edx+PS2MEM_BASE_+0x1000f200] - test ax, 0xa0 - jz Sif40_2 - // psHu16(0x1000F240) &= ~0xF000; - // psHu16(0x1000F240) |= 0x2000; - and bx, 0x0fff - or bx, 0x2000 - -Sif40_2: - // if(psHu16(0x1000F240) & temp) psHu16(0x1000F240) &= ~temp; - // else psHu16(0x1000F240) |= temp; - and ax, 0xf0 - test bx, ax - jz Sif40_3 - - not ax - and bx, ax - jmp Sif40_4 -Sif40_3: - or bx, ax -Sif40_4: - mov word ptr [edx+PS2MEM_BASE_+0x1000f200], bx - ret - -Sif30: - or dword ptr [edx+PS2MEM_BASE_+0x1000f200], eax - ret -Sif20: - not eax - and dword ptr [edx+PS2MEM_BASE_+0x1000f200], eax - ret -Sif60: - mov dword ptr [edx+PS2MEM_BASE_+0x1000f200], 0 - ret - -devwrite: - push eax - push ecx - call DEV9write32 - // stack alwritey incremented - ret - -WriteCtrl: - cmp ecx, 0x1ffe0130 - jne End - - mov writectrl, eax - - cmp eax, 0x800 - je SetWriteNotOk - cmp eax, 0x804 - je SetWriteNotOk - cmp eax, 0xc00 - je SetWriteNotOk - cmp eax, 0xc04 - je SetWriteNotOk - cmp eax, 0xcc0 - je SetWriteNotOk - cmp eax, 0xcc4 - je SetWriteNotOk - cmp eax, 0x0c4 - je SetWriteNotOk - - // test ok - cmp eax, 0x1e988 - je SetWriteOk - cmp eax, 0x1edd8 - je SetWriteOk - -End: - ret - -SetWriteNotOk: - mov g_psxWriteOk, 0 - ret -SetWriteOk: - mov g_psxWriteOk, 1 - ret - } -} - -int psxRecMemConstWrite32(u32 mem, int mmreg) -{ - u32 t = (mem >> 16) & 0x1fff; - switch(t) { - case 0x1f80: - psxHwConstWrite32(mem&0x1fffffff, mmreg); - return 0; - - case 0x1d00: - switch (mem & 0xf0) { - case 0x10: - // write to ps2 mem - _eeWriteConstMem32((u32)PS2MEM_HW+0xf210, mmreg); - return 0; - case 0x20: - // write to ps2 mem - // delete x86reg - if( IS_PSXCONSTREG(mmreg) ) { - AND32ItoM((u32)PS2MEM_HW+0xf220, ~g_psxConstRegs[(mmreg>>16)&0x1f]); - } - else { - NOT32R(mmreg); - AND32RtoM((u32)PS2MEM_HW+0xf220, mmreg); - } - return 0; - case 0x30: - // write to ps2 mem - _eeWriteConstMem32OP((u32)PS2MEM_HW+0xf230, mmreg, 1); - return 0; - case 0x40: - { - // delete x86reg - assert( mmreg != EBX ); - - _eeMoveMMREGtoR(EAX, mmreg); - - MOV16MtoR(EBX, (u32)PS2MEM_HW+0xf240); - TEST16ItoR(EAX, 0xa0); - j8Ptr[0] = JZ8(0); - - AND16ItoR(EBX, 0x0fff); - OR16ItoR(EBX, 0x2000); - - x86SetJ8(j8Ptr[0]); - - AND16ItoR(EAX, 0xf0); - TEST16RtoR(EAX, 0xf0); - j8Ptr[0] = JZ8(0); - - NOT32R(EAX); - AND16RtoR(EBX, EAX); - j8Ptr[1] = JMP8(0); - - x86SetJ8(j8Ptr[0]); - OR16RtoR(EBX, EAX); - - x86SetJ8(j8Ptr[1]); - - MOV16RtoM((u32)PS2MEM_HW+0xf240, EBX); - - return 0; - } - case 0x60: - MOV32ItoM((u32)(PS2MEM_HW+0xf260), 0); - return 0; - default: - assert(0); - } - return 0; - - case 0x1000: - _recPushReg(mmreg); - PUSH32I(mem&0x1fffffff); - CALLFunc((uptr)DEV9write32); - return 0; - - case 0x1ffe: - if( mem == 0xfffe0130 ) { - u8* ptrs[9]; - - _eeWriteConstMem32((uptr)&writectrl, mmreg); - - if( IS_PSXCONSTREG(mmreg) ) { - switch (g_psxConstRegs[(mmreg>>16)&0x1f]) { - case 0x800: case 0x804: - case 0xc00: case 0xc04: - case 0xcc0: case 0xcc4: - case 0x0c4: - MOV32ItoM((uptr)&g_psxWriteOk, 0); - break; - case 0x1e988: - case 0x1edd8: - MOV32ItoM((uptr)&g_psxWriteOk, 1); - break; - default: - assert(0); - } - } - else { - // not ok - CMP32ItoR(mmreg, 0x800); - ptrs[0] = JE8(0); - CMP32ItoR(mmreg, 0x804); - ptrs[1] = JE8(0); - CMP32ItoR(mmreg, 0xc00); - ptrs[2] = JE8(0); - CMP32ItoR(mmreg, 0xc04); - ptrs[3] = JE8(0); - CMP32ItoR(mmreg, 0xcc0); - ptrs[4] = JE8(0); - CMP32ItoR(mmreg, 0xcc4); - ptrs[5] = JE8(0); - CMP32ItoR(mmreg, 0x0c4); - ptrs[6] = JE8(0); - - // ok - CMP32ItoR(mmreg, 0x1e988); - ptrs[7] = JE8(0); - CMP32ItoR(mmreg, 0x1edd8); - ptrs[8] = JE8(0); - - x86SetJ8(ptrs[0]); - x86SetJ8(ptrs[1]); - x86SetJ8(ptrs[2]); - x86SetJ8(ptrs[3]); - x86SetJ8(ptrs[4]); - x86SetJ8(ptrs[5]); - x86SetJ8(ptrs[6]); - MOV32ItoM((uptr)&g_psxWriteOk, 0); - ptrs[0] = JMP8(0); - - x86SetJ8(ptrs[7]); - x86SetJ8(ptrs[8]); - MOV32ItoM((uptr)&g_psxWriteOk, 1); - - x86SetJ8(ptrs[0]); - } - } - return 0; - - default: - TEST8ItoM((uptr)&g_psxWriteOk, 1); - j8Ptr[0] = JZ8(0); - _eeWriteConstMem32((u32)PSXM(mem), mmreg); - x86SetJ8(j8Ptr[0]); - return 1; - } -} - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "PsxCommon.h" +#include "iR3000A.h" +#include "VU.h" + + +extern int g_psxWriteOk; +extern u32 g_psxMaxRecMem; +static u32 writectrl; + +#ifdef PCSX2_VIRTUAL_MEM + +#ifdef _DEBUG + +#define ASSERT_WRITEOK \ +{ \ + __asm cmp g_psxWriteOk, 1 \ + __asm je WriteOk \ + __asm int 10 \ +} \ +WriteOk: \ + +#else +#define ASSERT_WRITEOK +#endif + +__declspec(naked) void psxRecMemRead8() +{ + __asm { + mov edx, ecx + shr edx, 16 + cmp dx, 0x1f80 + je hwread + cmp dx, 0x1f40 + je hw4read + cmp dx, 0x1000 + je devread + cmp dx, 0x1f00 + je spuread + } + + ASSERT_WRITEOK + + __asm { +memread: + // rom reads, has to be PS2MEM_BASE_ + mov eax, dword ptr [ecx+PS2MEM_BASE_] + ret + +hwread: + cmp cx, 0x1000 + jb memread + + push ecx + call psxHwRead8 + add esp, 4 + ret + +hw4read: + push ecx + call psxHw4Read8 + add esp, 4 + ret + +devread: + push ecx + call DEV9read8 + // stack already incremented + ret + +spuread: + push ecx + call SPU2read + // stack already incremented + ret + } +} + +int psxRecMemConstRead8(u32 x86reg, u32 mem, u32 sign) +{ + u32 t = (mem >> 16) & 0x1fff; + + switch(t) { + case 0x1f80: + return psxHwConstRead8(x86reg, mem&0x1fffffff, sign); + +#ifdef _DEBUG + case 0x1d00: assert(0); +#endif + + case 0x1f40: + return psxHw4ConstRead8(x86reg, mem&0x1fffffff, sign); + + case 0x1000: + PUSH32I(mem&0x1fffffff); + CALLFunc((uptr)DEV9read8); + if( sign ) MOVSX32R8toR(x86reg, EAX); + else MOVZX32R8toR(x86reg, EAX); + return 0; + + default: + _eeReadConstMem8(x86reg, (u32)PSXM(mem), sign); + return 0; + } +} + +__declspec(naked) void psxRecMemRead16() +{ + __asm { + mov edx, ecx + shr edx, 16 + cmp dx, 0x1f80 + je hwread + cmp dx, 0x1f90 + je spuread + cmp dx, 0x1d00 + je sifread + cmp dx, 0x1000 + je devread + } + + ASSERT_WRITEOK + + __asm { +memread: + // rom reads, has to be PS2MEM_BASE_ + mov eax, dword ptr [ecx+PS2MEM_BASE_] + ret + +hwread: + cmp cx, 0x1000 + jb memread + + push ecx + call psxHwRead16 + add esp, 4 + ret + +sifread: + mov edx, ecx + and edx, 0xf0 + cmp dl, 0x60 + je Sif60 + + + mov eax, dword ptr [edx+PS2MEM_BASE_+0x1000f200] + + cmp dl, 0x40 + jne End + + // 0x40 + or eax, 2 + jmp End +Sif60: + xor eax, eax + jmp End + +spuread: + push ecx + call SPU2read + // stack already incremented + +End: + ret + +devread: + push ecx + call DEV9read16 + // stack already incremented + ret + } +} + +int psxRecMemConstRead16(u32 x86reg, u32 mem, u32 sign) +{ + u32 t = (mem >> 16) & 0x1fff; + + switch(t) { + case 0x1f80: return psxHwConstRead16(x86reg, mem&0x1fffffff, sign); + + case 0x1d00: + + switch(mem & 0xF0) + { + case 0x40: + _eeReadConstMem16(x86reg, (u32)PS2MEM_HW+0xF240, sign); + OR32ItoR(x86reg, 0x0002); + break; + case 0x60: + XOR32RtoR(x86reg, x86reg); + break; + default: + _eeReadConstMem16(x86reg, (u32)PS2MEM_HW+0xf200+(mem&0xf0), sign); + break; + } + return 0; + + case 0x1f90: + PUSH32I(mem&0x1fffffff); + CALLFunc((uptr)SPU2read); + if( sign ) MOVSX32R16toR(x86reg, EAX); + else MOVZX32R16toR(x86reg, EAX); + return 0; + + case 0x1000: + PUSH32I(mem&0x1fffffff); + CALLFunc((uptr)DEV9read16); + if( sign ) MOVSX32R16toR(x86reg, EAX); + else MOVZX32R16toR(x86reg, EAX); + return 0; + + default: + assert( g_psxWriteOk ); + _eeReadConstMem16(x86reg, (u32)PSXM(mem), sign); + return 0; + } + + return 0; +} + +__declspec(naked) void psxRecMemRead32() +{ + __asm { + mov edx, ecx + shr edx, 16 + cmp dx, 0x1f80 + je hwread + cmp dx, 0x1d00 + je sifread + cmp dx, 0x1000 + je devread + cmp ecx, 0x1ffe0130 + je WriteCtrlRead + } + + ASSERT_WRITEOK + + __asm { +memread: + // rom reads, has to be PS2MEM_BASE_ + mov eax, dword ptr [ecx+PS2MEM_BASE_] + ret + +hwread: + cmp cx, 0x1000 + jb memread + + push ecx + call psxHwRead32 + add esp, 4 + ret + +sifread: + mov edx, ecx + and edx, 0xf0 + cmp dl, 0x60 + je Sif60 + + // do the read from ps2 mem + mov eax, dword ptr [edx+PS2MEM_BASE_+0x1000f200] + + cmp dl, 0x40 + jne End + + // 0x40 + or eax, 0xf0000002 + jmp End +Sif60: + xor eax, eax +End: + ret + +devread: + push ecx + call DEV9read32 + // stack already incremented + ret + +WriteCtrlRead: + mov eax, writectrl + ret + } +} + +int psxRecMemConstRead32(u32 x86reg, u32 mem) +{ + u32 t = (mem >> 16) & 0x1fff; + + switch(t) { + case 0x1f80: return psxHwConstRead32(x86reg, mem&0x1fffffff); + + case 0x1d00: + switch(mem & 0xF0) + { + case 0x40: + _eeReadConstMem32(x86reg, (u32)PS2MEM_HW+0xF240); + OR32ItoR(x86reg, 0xf0000002); + break; + case 0x60: + XOR32RtoR(x86reg, x86reg); + break; + default: + _eeReadConstMem32(x86reg, (u32)PS2MEM_HW+0xf200+(mem&0xf0)); + break; + } + return 0; + + case 0x1000: + PUSH32I(mem&0x1fffffff); + CALLFunc((uptr)DEV9read32); + return 1; + + default: + if( mem == 0xfffe0130 ) + MOV32MtoR(x86reg, (uptr)&writectrl); + else { + XOR32RtoR(x86reg, x86reg); + CMP32ItoM((uptr)&g_psxWriteOk, 0); + CMOVNE32MtoR(x86reg, (u32)PSXM(mem)); + } + + return 0; + } +} + +__declspec(naked) void psxRecMemWrite8() +{ + __asm { + mov edx, ecx + shr edx, 16 + cmp dx, 0x1f80 + je hwwrite + cmp dx, 0x1f40 + je hw4write + cmp dx, 0x1000 + je devwrite + } + + ASSERT_WRITEOK + + __asm { +memwrite: + // rom writes, has to be PS2MEM_BASE_ + mov byte ptr [ecx+PS2MEM_BASE_], al + ret + +hwwrite: + cmp cx, 0x1000 + jb memwrite + + push eax + push ecx + call psxHwWrite8 + add esp, 8 + ret + +hw4write: + push eax + push ecx + call psxHw4Write8 + add esp, 8 + ret + +devwrite: + push eax + push ecx + call DEV9write8 + // stack alwritey incremented + ret + } +} + +int psxRecMemConstWrite8(u32 mem, int mmreg) +{ + u32 t = (mem >> 16) & 0x1fff; + + switch(t) { + case 0x1f80: + psxHwConstWrite8(mem&0x1fffffff, mmreg); + return 0; + case 0x1f40: + psxHw4ConstWrite8(mem&0x1fffffff, mmreg); + return 0; + + case 0x1d00: + assert(0); + _eeWriteConstMem8((u32)(PS2MEM_HW+0xf200+(mem&0xff)), mmreg); + return 0; + + case 0x1000: + _recPushReg(mmreg); + PUSH32I(mem&0x1fffffff); + CALLFunc((uptr)DEV9write8); + return 0; + + default: + _eeWriteConstMem8((u32)PSXM(mem), mmreg); + return 1; + } +} + +__declspec(naked) void psxRecMemWrite16() +{ + __asm { + mov edx, ecx + shr edx, 16 + cmp dx, 0x1f80 + je hwwrite + cmp dx, 0x1f90 + je spuwrite + cmp dx, 0x1d00 + je sifwrite + cmp dx, 0x1000 + je devwrite + cmp dx, 0x1600 + je ignorewrite + } + + ASSERT_WRITEOK + + __asm { +memwrite: + // rom writes, has to be PS2MEM_BASE_ + mov word ptr [ecx+PS2MEM_BASE_], ax + ret + +hwwrite: + cmp cx, 0x1000 + jb memwrite + + push eax + push ecx + call psxHwWrite16 + add esp, 8 + ret + +sifwrite: + mov edx, ecx + and edx, 0xf0 + cmp dl, 0x60 + je Sif60 + cmp dl, 0x40 + je Sif40 + + mov word ptr [edx+PS2MEM_BASE_+0x1000f200], ax + ret + +Sif40: + mov bx, word ptr [edx+PS2MEM_BASE_+0x1000f200] + test ax, 0xa0 + jz Sif40_2 + // psHu16(0x1000F240) &= ~0xF000; + // psHu16(0x1000F240) |= 0x2000; + and bx, 0x0fff + or bx, 0x2000 + +Sif40_2: + // if(psHu16(0x1000F240) & temp) psHu16(0x1000F240) &= ~temp; + // else psHu16(0x1000F240) |= temp; + and ax, 0xf0 + test bx, ax + jz Sif40_3 + + not ax + and bx, ax + jmp Sif40_4 +Sif40_3: + or bx, ax +Sif40_4: + mov word ptr [edx+PS2MEM_BASE_+0x1000f200], bx + ret + +Sif60: + mov word ptr [edx+PS2MEM_BASE_+0x1000f200], 0 + ret + +spuwrite: + push eax + push ecx + call SPU2write + // stack alwritey incremented + ret + +devwrite: + push eax + push ecx + call DEV9write16 + // stack alwritey incremented + ret + +ignorewrite: + ret + } +} + +int psxRecMemConstWrite16(u32 mem, int mmreg) +{ + u32 t = (mem >> 16) & 0x1fff; + switch(t) { + case 0x1600: + //HACK: DEV9 VM crash fix + return 0; + case 0x1f80: + psxHwConstWrite16(mem&0x1fffffff, mmreg); + return 0; + + case 0x1d00: + switch (mem & 0xf0) { + case 0x10: + // write to ps2 mem + _eeWriteConstMem16((u32)(PS2MEM_HW+0xf210), mmreg); + return 0; + case 0x40: + { + // delete x86reg + _eeMoveMMREGtoR(EAX, mmreg); + + assert( mmreg != EBX ); + MOV16MtoR(EBX, (u32)PS2MEM_HW+0xf240); + TEST16ItoR(EAX, 0xa0); + j8Ptr[0] = JZ8(0); + + AND16ItoR(EBX, 0x0fff); + OR16ItoR(EBX, 0x2000); + + x86SetJ8(j8Ptr[0]); + + AND16ItoR(EAX, 0xf0); + TEST16RtoR(EAX, 0xf0); + j8Ptr[0] = JZ8(0); + + NOT32R(EAX); + AND16RtoR(EBX, EAX); + j8Ptr[1] = JMP8(0); + + x86SetJ8(j8Ptr[0]); + OR16RtoR(EBX, EAX); + + x86SetJ8(j8Ptr[1]); + + MOV16RtoM((u32)PS2MEM_HW+0xf240, EBX); + + return 0; + } + case 0x60: + MOV32ItoM((u32)(PS2MEM_HW+0xf260), 0); + return 0; + default: + assert(0); + } + return 0; + + case 0x1f90: + _recPushReg(mmreg); + PUSH32I(mem&0x1fffffff); + CALLFunc((uptr)SPU2write); + return 0; + + case 0x1000: + _recPushReg(mmreg); + PUSH32I(mem&0x1fffffff); + CALLFunc((uptr)DEV9write16); + return 0; + + default: + _eeWriteConstMem16((u32)PSXM(mem), mmreg); + return 1; + } +} + +__declspec(naked) void psxRecMemWrite32() +{ + __asm { + mov edx, ecx + shr edx, 16 + cmp dx, 0x1f80 + je hwwrite + cmp dx, 0x1d00 + je sifwrite + cmp dx, 0x1000 + je devwrite + cmp dx, 0x1ffe + je WriteCtrl + } + + __asm { + // rom writes, has to be PS2MEM_BASE_ + test g_psxWriteOk, 1 + jz endwrite + +memwrite: + mov dword ptr [ecx+PS2MEM_BASE_], eax +endwrite: + ret + +hwwrite: + cmp cx, 0x1000 + jb memwrite + + push eax + push ecx + call psxHwWrite32 + add esp, 8 + ret + +sifwrite: + mov edx, ecx + and edx, 0xf0 + cmp dl, 0x60 + je Sif60 + cmp dl, 0x40 + je Sif40 + cmp dl, 0x30 + je Sif30 + cmp dl, 0x20 + je Sif20 + + mov dword ptr [edx+PS2MEM_BASE_+0x1000f200], eax + ret + +Sif40: + mov bx, word ptr [edx+PS2MEM_BASE_+0x1000f200] + test ax, 0xa0 + jz Sif40_2 + // psHu16(0x1000F240) &= ~0xF000; + // psHu16(0x1000F240) |= 0x2000; + and bx, 0x0fff + or bx, 0x2000 + +Sif40_2: + // if(psHu16(0x1000F240) & temp) psHu16(0x1000F240) &= ~temp; + // else psHu16(0x1000F240) |= temp; + and ax, 0xf0 + test bx, ax + jz Sif40_3 + + not ax + and bx, ax + jmp Sif40_4 +Sif40_3: + or bx, ax +Sif40_4: + mov word ptr [edx+PS2MEM_BASE_+0x1000f200], bx + ret + +Sif30: + or dword ptr [edx+PS2MEM_BASE_+0x1000f200], eax + ret +Sif20: + not eax + and dword ptr [edx+PS2MEM_BASE_+0x1000f200], eax + ret +Sif60: + mov dword ptr [edx+PS2MEM_BASE_+0x1000f200], 0 + ret + +devwrite: + push eax + push ecx + call DEV9write32 + // stack alwritey incremented + ret + +WriteCtrl: + cmp ecx, 0x1ffe0130 + jne End + + mov writectrl, eax + + cmp eax, 0x800 + je SetWriteNotOk + cmp eax, 0x804 + je SetWriteNotOk + cmp eax, 0xc00 + je SetWriteNotOk + cmp eax, 0xc04 + je SetWriteNotOk + cmp eax, 0xcc0 + je SetWriteNotOk + cmp eax, 0xcc4 + je SetWriteNotOk + cmp eax, 0x0c4 + je SetWriteNotOk + + // test ok + cmp eax, 0x1e988 + je SetWriteOk + cmp eax, 0x1edd8 + je SetWriteOk + +End: + ret + +SetWriteNotOk: + mov g_psxWriteOk, 0 + ret +SetWriteOk: + mov g_psxWriteOk, 1 + ret + } +} + +int psxRecMemConstWrite32(u32 mem, int mmreg) +{ + u32 t = (mem >> 16) & 0x1fff; + switch(t) { + case 0x1f80: + psxHwConstWrite32(mem&0x1fffffff, mmreg); + return 0; + + case 0x1d00: + switch (mem & 0xf0) { + case 0x10: + // write to ps2 mem + _eeWriteConstMem32((u32)PS2MEM_HW+0xf210, mmreg); + return 0; + case 0x20: + // write to ps2 mem + // delete x86reg + if( IS_PSXCONSTREG(mmreg) ) { + AND32ItoM((u32)PS2MEM_HW+0xf220, ~g_psxConstRegs[(mmreg>>16)&0x1f]); + } + else { + NOT32R(mmreg); + AND32RtoM((u32)PS2MEM_HW+0xf220, mmreg); + } + return 0; + case 0x30: + // write to ps2 mem + _eeWriteConstMem32OP((u32)PS2MEM_HW+0xf230, mmreg, 1); + return 0; + case 0x40: + { + // delete x86reg + assert( mmreg != EBX ); + + _eeMoveMMREGtoR(EAX, mmreg); + + MOV16MtoR(EBX, (u32)PS2MEM_HW+0xf240); + TEST16ItoR(EAX, 0xa0); + j8Ptr[0] = JZ8(0); + + AND16ItoR(EBX, 0x0fff); + OR16ItoR(EBX, 0x2000); + + x86SetJ8(j8Ptr[0]); + + AND16ItoR(EAX, 0xf0); + TEST16RtoR(EAX, 0xf0); + j8Ptr[0] = JZ8(0); + + NOT32R(EAX); + AND16RtoR(EBX, EAX); + j8Ptr[1] = JMP8(0); + + x86SetJ8(j8Ptr[0]); + OR16RtoR(EBX, EAX); + + x86SetJ8(j8Ptr[1]); + + MOV16RtoM((u32)PS2MEM_HW+0xf240, EBX); + + return 0; + } + case 0x60: + MOV32ItoM((u32)(PS2MEM_HW+0xf260), 0); + return 0; + default: + assert(0); + } + return 0; + + case 0x1000: + _recPushReg(mmreg); + PUSH32I(mem&0x1fffffff); + CALLFunc((uptr)DEV9write32); + return 0; + + case 0x1ffe: + if( mem == 0xfffe0130 ) { + u8* ptrs[9]; + + _eeWriteConstMem32((uptr)&writectrl, mmreg); + + if( IS_PSXCONSTREG(mmreg) ) { + switch (g_psxConstRegs[(mmreg>>16)&0x1f]) { + case 0x800: case 0x804: + case 0xc00: case 0xc04: + case 0xcc0: case 0xcc4: + case 0x0c4: + MOV32ItoM((uptr)&g_psxWriteOk, 0); + break; + case 0x1e988: + case 0x1edd8: + MOV32ItoM((uptr)&g_psxWriteOk, 1); + break; + default: + assert(0); + } + } + else { + // not ok + CMP32ItoR(mmreg, 0x800); + ptrs[0] = JE8(0); + CMP32ItoR(mmreg, 0x804); + ptrs[1] = JE8(0); + CMP32ItoR(mmreg, 0xc00); + ptrs[2] = JE8(0); + CMP32ItoR(mmreg, 0xc04); + ptrs[3] = JE8(0); + CMP32ItoR(mmreg, 0xcc0); + ptrs[4] = JE8(0); + CMP32ItoR(mmreg, 0xcc4); + ptrs[5] = JE8(0); + CMP32ItoR(mmreg, 0x0c4); + ptrs[6] = JE8(0); + + // ok + CMP32ItoR(mmreg, 0x1e988); + ptrs[7] = JE8(0); + CMP32ItoR(mmreg, 0x1edd8); + ptrs[8] = JE8(0); + + x86SetJ8(ptrs[0]); + x86SetJ8(ptrs[1]); + x86SetJ8(ptrs[2]); + x86SetJ8(ptrs[3]); + x86SetJ8(ptrs[4]); + x86SetJ8(ptrs[5]); + x86SetJ8(ptrs[6]); + MOV32ItoM((uptr)&g_psxWriteOk, 0); + ptrs[0] = JMP8(0); + + x86SetJ8(ptrs[7]); + x86SetJ8(ptrs[8]); + MOV32ItoM((uptr)&g_psxWriteOk, 1); + + x86SetJ8(ptrs[0]); + } + } + return 0; + + default: + TEST8ItoM((uptr)&g_psxWriteOk, 1); + j8Ptr[0] = JZ8(0); + _eeWriteConstMem32((u32)PSXM(mem), mmreg); + x86SetJ8(j8Ptr[0]); + return 1; + } +} + +#endif diff --git a/pcsx2/x86/iR3000A.cpp b/pcsx2/x86/iR3000A.cpp index 84a8b5330e..268e0a593b 100644 --- a/pcsx2/x86/iR3000A.cpp +++ b/pcsx2/x86/iR3000A.cpp @@ -1,1541 +1,1541 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -// recompiler reworked to add dynamic linking Jan06 -// and added reg caching, const propagation, block analysis Jun06 -// zerofrog(@gmail.com) - - -#include "PrecompiledHeader.h" - -#include - -#ifndef _WIN32 -#include -#endif - -#include "PsxCommon.h" -#include "VU.h" - -#include "ix86/ix86.h" -#include "iCore.h" -#include "iR3000A.h" - -#include "SamplProf.h" - -extern u32 g_psxNextBranchCycle; -extern void psxBREAK(); -extern void zeroEx(); - -u32 g_psxMaxRecMem = 0; -u32 s_psxrecblocks[] = {0}; - -//Using assembly code from an external file. -#ifdef __LINUX__ -extern "C" { -#endif -void psxRecRecompile(u32 startpc); -#ifdef __LINUX__ -} -#endif - -uptr *psxRecLUT; - -#define PSX_NUMBLOCKS (1<<12) -#define MAPBASE 0x48000000 -#define RECMEM_SIZE (8*1024*1024) - -#define PSX_MEMMASK 0x5fffffff // mask when comparing two pcs - -// R3000A statics -int psxreclog = 0; - -static u8 *recMem = NULL; // the recompiled blocks will be here -static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here -static BASEBLOCK *recROM = NULL; // and here -static BASEBLOCK *recROM1 = NULL; // also here -static BASEBLOCKEX *recBlocks = NULL; -static u8 *recPtr = NULL; -u32 psxpc; // recompiler psxpc -int psxbranch; // set for branch -u32 g_iopCyclePenalty; - -static EEINST* s_pInstCache = NULL; -static u32 s_nInstCacheSize = 0; - -static BASEBLOCK* s_pCurBlock = NULL; -static BASEBLOCKEX* s_pCurBlockEx = NULL; - -#if defined(_MSC_VER) && !defined(__x86_64__) -static BASEBLOCK* s_pDispatchBlock = NULL; -#endif - -static u32 s_nEndBlock = 0; // what psxpc the current block ends - -static u32 s_nNextBlock = 0; // next free block in recBlocks - -static u32 s_ConstGPRreg; -static u32 s_saveConstGPRreg = 0, s_saveHasConstReg = 0, s_saveFlushedConstReg = 0; -static EEINST* s_psaveInstInfo = NULL; - -u32 s_psxBlockCycles = 0; // cycles of current block recompiling -static u32 s_savenBlockCycles = 0; - -static void iPsxBranchTest(u32 newpc, u32 cpuBranch); -void psxRecompileNextInstruction(int delayslot); - -extern void (*rpsxBSC[64])(); -extern void (*rpsxBSC_co[64])(); -void rpsxpropBSC(EEINST* prev, EEINST* pinst); - -#ifdef _DEBUG -u32 psxdump = 0; -#else -#define psxdump 0 -#endif - -#define PSX_GETBLOCK(x) PC_GETBLOCK_(x, psxRecLUT) - -#define PSXREC_CLEARM(mem) { \ - if ((mem) < g_psxMaxRecMem && psxRecLUT[(mem) >> 16]) { \ - BASEBLOCK* p = PSX_GETBLOCK(mem); \ - if( *(u32*)p ) psxRecClearMem(p); \ - } \ -} \ - -BASEBLOCKEX* PSX_GETBLOCKEX(BASEBLOCK* p) -{ -// BASEBLOCKEX* pex = *(BASEBLOCKEX**)(p+1); -// if( pex >= recBlocks && pex < recBlocks+PSX_NUMBLOCKS ) -// return pex; - - // otherwise, use the sorted list - return GetBaseBlockEx(p->startpc, 1); -} - -//////////////////////////////////////////////////// -#ifdef _DEBUG -using namespace R3000A; -static void iIopDumpBlock( int startpc, u8 * ptr ) -{ - FILE *f; - char filename[ g_MaxPath ]; -#ifdef __LINUX__ - char command[256]; -#endif - u32 i, j; - EEINST* pcur; - u8 used[34]; - int numused, count; - - SysPrintf( "dump1 %x:%x, %x\n", startpc, psxpc, psxRegs.cycle ); -#ifdef _WIN32 - CreateDirectory("dumps", NULL); - sprintf_s( filename, g_MaxPath, "dumps\\psxdump%.8X.txt", startpc); -#else - mkdir("dumps", 0755); - sprintf( filename, "dumps/psxdump%.8X.txt", startpc); -#endif - - fflush( stdout ); - - f = fopen( filename, "w" ); - assert( f != NULL ); - for ( i = startpc; i < s_nEndBlock; i += 4 ) { - fprintf( f, "%s\n", disR3000Fasm( *(u32*)PSXM( i ), i ) ); - } - - // write the instruction info - fprintf(f, "\n\nlive0 - %x, lastuse - %x used - %x\n", EEINST_LIVE0, EEINST_LASTUSE, EEINST_USED); - - memzero_obj(used); - numused = 0; - for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { - if( s_pInstCache->regs[i] & EEINST_USED ) { - used[i] = 1; - numused++; - } - } - - fprintf(f, " "); - for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { - if( used[i] ) fprintf(f, "%2d ", i); - } - fprintf(f, "\n"); - - fprintf(f, " "); - for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { - if( used[i] ) fprintf(f, "%s ", disRNameGPR[i]); - } - fprintf(f, "\n"); - - pcur = s_pInstCache+1; - for( i = 0; i < (s_nEndBlock-startpc)/4; ++i, ++pcur) { - fprintf(f, "%2d: %2.2x ", i+1, pcur->info); - - count = 1; - for(j = 0; j < ARRAYSIZE(s_pInstCache->regs); j++) { - if( used[j] ) { - fprintf(f, "%2.2x%s", pcur->regs[j], ((count%8)&&count tempdump", filename ); - system( command ); - sprintf(command, "mv tempdump %s", filename); - system(command); - f = fopen( filename, "a+" ); -#endif -} -#endif - -u8 _psxLoadWritesRs(u32 tempcode) -{ - switch(tempcode>>26) { - case 32: case 33: case 34: case 35: case 36: case 37: case 38: - return ((tempcode>>21)&0x1f)==((tempcode>>16)&0x1f); // rs==rt - } - return 0; -} - -u8 _psxIsLoadStore(u32 tempcode) -{ - switch(tempcode>>26) { - case 32: case 33: case 34: case 35: case 36: case 37: case 38: - // 4 byte stores - case 40: case 41: case 42: case 43: case 46: - return 1; - } - return 0; -} - -void _psxFlushAllUnused() -{ - int i; - for(i = 0; i < 34; ++i) { - if( psxpc < s_nEndBlock ) { - if( (g_pCurInstInfo[1].regs[i]&EEINST_USED) ) - continue; - } - else if( (g_pCurInstInfo[0].regs[i]&EEINST_USED) ) - continue; - - if( i < 32 && PSX_IS_CONST1(i) ) _psxFlushConstReg(i); - else { - _deleteX86reg(X86TYPE_PSX, i, 1); - } - } -} - -int _psxFlushUnusedConstReg() -{ - int i; - for(i = 1; i < 32; ++i) { - if( (g_psxHasConstReg & (1< 0 ); - - // make sure right GPR was saved - assert( g_psxHasConstReg == s_saveHasConstReg || (g_psxHasConstReg ^ s_saveHasConstReg) == (1<>26) == 9 ) { - //ADDIU, call bios -#ifdef _DEBUG - MOV32ItoM( (uptr)&psxRegs.code, psxRegs.code ); - MOV32ItoM( (uptr)&psxRegs.pc, psxpc ); - _psxFlushCall(FLUSH_NODESTROY); - CALLFunc((uptr)zeroEx); -#endif - // Bios Call: Force the IOP to do a Branch Test ASAP. - // Important! This helps prevent game freeze-ups during boot-up and stage loads. - // Note: Fixes to cdvd have removed the need for this code. - //MOV32MtoR( EAX, (uptr)&psxRegs.cycle ); - //MOV32RtoM( (uptr)&g_psxNextBranchCycle, EAX ); - } - return; - } - - // for now, don't support xmm - PSX_CHECK_SAVE_REG(_Rt_); - - _deleteX86reg(X86TYPE_PSX, _Rs_, 1); - _deleteX86reg(X86TYPE_PSX, _Rt_, 0); - - if( PSX_IS_CONST1(_Rs_) ) { - PSX_SET_CONST(_Rt_); - constcode(); - return; - } - - noconstcode(0); - PSX_DEL_CONST(_Rt_); -} - -// rd = rt op sa -void psxRecompileCodeConst2(R3000AFNPTR constcode, R3000AFNPTR_INFO noconstcode) -{ - if ( ! _Rd_ ) return; - - // for now, don't support xmm - PSX_CHECK_SAVE_REG(_Rd_); - - _deleteX86reg(X86TYPE_PSX, _Rt_, 1); - _deleteX86reg(X86TYPE_PSX, _Rd_, 0); - - if( PSX_IS_CONST1(_Rt_) ) { - PSX_SET_CONST(_Rd_); - constcode(); - return; - } - - noconstcode(0); - PSX_DEL_CONST(_Rd_); -} - -// rd = rt MULT rs (SPECIAL) -void psxRecompileCodeConst3(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode, R3000AFNPTR_INFO consttcode, R3000AFNPTR_INFO noconstcode, int LOHI) -{ - _deleteX86reg(X86TYPE_PSX, _Rs_, 1); - _deleteX86reg(X86TYPE_PSX, _Rt_, 1); - - if( LOHI ) { - _deleteX86reg(X86TYPE_PSX, PSX_HI, 1); - _deleteX86reg(X86TYPE_PSX, PSX_LO, 1); - } - - if( PSX_IS_CONST2(_Rs_, _Rt_) ) { - constcode(); - return; - } - - if( PSX_IS_CONST1(_Rs_) ) { - constscode(0); - return; - } - - if( PSX_IS_CONST1(_Rt_) ) { - consttcode(0); - return; - } - - noconstcode(0); -} - -static u8* m_recBlockAlloc = NULL; - -static const uint m_recBlockAllocSize = - (((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK)) - + (PSX_NUMBLOCKS*sizeof(BASEBLOCKEX)); // recBlocks - -static void recAlloc() -{ - // Note: the VUrec depends on being able to grab an allocation below the 0x10000000 line, - // so we give the EErec an address above that to try first as it's basemem address, hence - // the 0x28000000 pick (0x20000000 is picked by the EE) - - if( recMem == NULL ) - recMem = (u8*)SysMmapEx( 0x28000000, RECMEM_SIZE, 0, "recAlloc(R3000a)" ); - - if( recMem == NULL ) - throw Exception::OutOfMemory( "R3000a Init > failed to allocate memory for the recompiler." ); - - if( psxRecLUT == NULL ) - psxRecLUT = (uptr*) malloc(0x010000 * sizeof(uptr)); - - // Goal: Allocate BASEBLOCKs for every possible branch target in IOP memory. - // Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are - // always 4 bytes long). - - if( m_recBlockAlloc == NULL ) - m_recBlockAlloc = (u8*)_aligned_malloc( m_recBlockAllocSize, 4096 ); - - if( m_recBlockAlloc == NULL ) - throw Exception::OutOfMemory( "R3000a Init > Failed to allocate memory for baseblock lookup tables." ); - - u8* curpos = m_recBlockAlloc; - recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::IopRam / 4) * sizeof(BASEBLOCK); - recROM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom / 4) * sizeof(BASEBLOCK); - recROM1 = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom1 / 4) * sizeof(BASEBLOCK); - recBlocks = (BASEBLOCKEX*)curpos; // curpos += sizeof(BASEBLOCKEX)*EE_NUMBLOCKS; - - if( s_pInstCache == NULL ) - { - s_nInstCacheSize = 128; - s_pInstCache = (EEINST*)malloc( sizeof(EEINST) * s_nInstCacheSize ); - } - - if( s_pInstCache == NULL ) - throw Exception::OutOfMemory( "R3000a Init > Failed to allocate memory for pInstCache." ); - - ProfilerRegisterSource( "IOPRec", recMem, RECMEM_SIZE ); -} - -void recResetIOP() -{ - // calling recResetIOP without first calling recInit is bad mojo. - jASSUME( psxRecLUT != NULL ); - jASSUME( recMem != NULL ); - jASSUME( m_recBlockAlloc != NULL ); - - DbgCon::Status( "iR3000A > Resetting recompiler memory and structures!" ); - - memzero_ptr<0x010000 * sizeof(uptr)>( psxRecLUT ); - memset_8<0xcd,RECMEM_SIZE>( recMem ); - memzero_ptr( m_recBlockAlloc ); - - // We're only mapping 20 pages here in 4 places. - // 0x80 comes from : (Ps2MemSize::IopRam / 0x10000) * 4 - for (int i=0; i<0x80; i++) - { - psxRecLUT[i + 0x0000] = (uptr)&recRAM[(i & 0x1f) << 14]; - psxRecLUT[i + 0x8000] = (uptr)&recRAM[(i & 0x1f) << 14]; - psxRecLUT[i + 0xa000] = (uptr)&recRAM[(i & 0x1f) << 14]; - } - - for (int i=0; i<(Ps2MemSize::Rom / 0x10000); i++) - { - psxRecLUT[i + 0x1fc0] = (uptr)&recROM[i << 14]; - psxRecLUT[i + 0x9fc0] = (uptr)&recROM[i << 14]; - psxRecLUT[i + 0xbfc0] = (uptr)&recROM[i << 14]; - } - - for (int i=0; i<(Ps2MemSize::Rom1 / 0x10000); i++) - { - psxRecLUT[i + 0x1e00] = (uptr)&recROM1[i << 14]; - psxRecLUT[i + 0x9e00] = (uptr)&recROM1[i << 14]; - psxRecLUT[i + 0xbe00] = (uptr)&recROM1[i << 14]; - } - - if( s_pInstCache ) - memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize ); - - ResetBaseBlockEx(1); - g_psxMaxRecMem = 0; - - recPtr = recMem; - psxbranch = 0; -} - -static void recShutdown() -{ - ProfilerTerminateSource( "IOPRec" ); - - SafeSysMunmap(recMem, RECMEM_SIZE); - safe_aligned_free( m_recBlockAlloc ); - - safe_free(psxRecLUT); - safe_free( s_pInstCache ); - s_nInstCacheSize = 0; - - x86Shutdown(); -} - -#pragma warning(disable:4731) // frame pointer register 'ebp' modified by inline assembly code - -static u32 s_uSaveESP = 0; - -static __forceinline void R3000AExecute() -{ -#ifdef _DEBUG - u8* fnptr; - u32 oldesi; -/*#else - R3000AFNPTR pfn;*/ -#endif - - BASEBLOCK* pblock; - - pblock = PSX_GETBLOCK(psxRegs.pc); - - if ( !pblock->GetFnptr() || (pblock->startpc&PSX_MEMMASK) != (psxRegs.pc&PSX_MEMMASK) ) { - psxRecRecompile(psxRegs.pc); - } - - assert( pblock->GetFnptr() != 0 ); - -#ifdef _DEBUG - - fnptr = (u8*)pblock->GetFnptr(); - -#ifdef _MSC_VER - - __asm { - // save data - mov oldesi, esi; - mov s_uSaveESP, esp; - sub s_uSaveESP, 8; - push ebp; - - call fnptr; // jump into function - // restore data - pop ebp; - mov esi, oldesi; - } - -#else // linux - - __asm__("movl %%esi, %0\n" - "movl %%esp, %1\n" - "sub $8, %%esp\n" - "push %%ebp\n" - "call *%2\n" - "pop %%ebp\n" - "movl %0, %%esi\n" : "=m"(oldesi), "=m"(s_uSaveESP) : "c"(fnptr) : ); -#endif // _MSC_VER - -#else - ((R3000AFNPTR)pblock->GetFnptr())(); -#endif -} - -u32 g_psxlastpc = 0; - -#if defined(_MSC_VER) - -static u32 g_temp; - -// jumped to when invalid psxpc address -__declspec(naked,noreturn) void psxDispatcher() -{ - // EDX contains the current psxpc to jump to, stack contains the jump addr to modify - __asm push edx - - // calc PSX_GETBLOCK - s_pDispatchBlock = PSX_GETBLOCK(psxRegs.pc); - - __asm { - mov eax, s_pDispatchBlock - - // check if startpc&PSX_MEMMASK == psxRegs.pc&PSX_MEMMASK - mov ecx, psxRegs.pc - mov edx, [eax+BLOCKTYPE_STARTPC]; - and ecx, PSX_MEMMASK // remove higher bits - and edx, PSX_MEMMASK - cmp ecx, edx - je CheckPtr - - // recompile - push psxRegs.pc // psxpc - call psxRecRecompile - add esp, 4 // pop old param - mov eax, s_pDispatchBlock -CheckPtr: - mov eax, dword ptr [eax] - } - -#ifdef _DEBUG - __asm mov g_temp, eax - assert( g_temp ); -#endif - - __asm { - //and eax, 0x0fffffff - shl eax,4 - mov edx, eax - pop ecx // x86Ptr to mod - sub edx, ecx - sub edx, 4 - mov dword ptr [ecx], edx - - jmp eax - } -} - -__declspec(naked,noreturn) void psxDispatcherClear() -{ - // EDX contains the current psxpc - __asm mov psxRegs.pc, edx - __asm push edx - - // calc PSX_GETBLOCK - s_pDispatchBlock = PSX_GETBLOCK(psxRegs.pc); - - if( (s_pDispatchBlock->startpc&PSX_MEMMASK) == (psxRegs.pc&PSX_MEMMASK) ) { - assert( s_pDispatchBlock->GetFnptr() != 0 ); - - // already modded the code, jump to the new place - __asm { - pop edx - add esp, 4 // ignore stack - mov eax, s_pDispatchBlock - mov eax, dword ptr [eax] - //and eax, 0x0fffffff - shl eax,4 - jmp eax - } - } - - __asm { - call psxRecRecompile - add esp, 4 // pop old param - mov eax, s_pDispatchBlock - mov eax, dword ptr [eax] - - pop ecx // old fnptr - - //and eax, 0x0fffffff - shl eax,4 - mov byte ptr [ecx], 0xe9 // jmp32 - mov edx, eax - sub edx, ecx - sub edx, 5 - mov dword ptr [ecx+1], edx - - jmp eax - } -} - -// called when jumping to variable psxpc address -__declspec(naked,noreturn) void psxDispatcherReg() -{ - __asm { - //s_pDispatchBlock = PSX_GETBLOCK(psxRegs.pc); - mov edx, psxRegs.pc - mov ecx, edx - } - - __asm { - shr edx, 14 - and edx, 0xfffffffc - add edx, psxRecLUT - mov edx, dword ptr [edx] - - mov eax, ecx - and eax, 0xfffc - // edx += 2*eax - shl eax, 1 - add edx, eax - - // check if startpc == psxRegs.pc - mov eax, ecx - cmp eax, dword ptr [edx+BLOCKTYPE_STARTPC] - jne recomp - - mov eax, dword ptr [edx] - } - -#ifdef _DEBUG - __asm mov g_temp, eax - assert( g_temp ); -#endif - - __asm { - //and eax, 0x0fffffff - shl eax,4 - jmp eax // fnptr - -recomp: - sub esp, 8 - mov dword ptr [esp+4], edx - mov dword ptr [esp], ecx - call psxRecRecompile - mov edx, dword ptr [esp+4] - add esp, 8 - - mov eax, dword ptr [edx] - //and eax, 0x0fffffff - shl eax,4 - jmp eax // fnptr - } -} - -#else // _MSC_VER -// Linux uses an assembly version of these routines. -#ifdef __LINUX__ -extern "C" { -#endif -void psxDispatcher(); -void psxDispatcherClear(); -void psxDispatcherReg(); -#ifdef __LINUX__ -} -#endif - -#endif // _MSC_VER - -static void recClear(u32 Addr, u32 Size) -{ - u32 i; - for(i = 0; i < Size; ++i, Addr+=4) { - PSXREC_CLEARM(Addr); - } -} - -#define IOP_MIN_BLOCK_BYTES 15 - -void rpsxMemConstClear(u32 mem) -{ - // NOTE! This assumes recLUT never changes its mapping - if( !psxRecLUT[mem>>16] ) - return; - - CMP32ItoM((uptr)PSX_GETBLOCK(mem), 0); - j8Ptr[6] = JE8(0); - - _callFunctionArg1((uptr)psxRecClearMem, MEM_CONSTTAG, (uptr)PSX_GETBLOCK(mem)); - x86SetJ8(j8Ptr[6]); -} - -void psxRecClearMem(BASEBLOCK* p) -{ - BASEBLOCKEX* pexblock; - BASEBLOCK* pstart; - int lastdelay; - - assert( p != NULL ); - - if( p->uType & BLOCKTYPE_DELAYSLOT ) { - psxRecClearMem(p-1); - if( p->GetFnptr() == 0 ) - return; - } - - assert( p->GetFnptr() != 0 ); - assert( p->startpc ); - - x86Ptr = (u8*)p->GetFnptr(); - - // there is a small problem: mem can be ored with 0xa<<28 or 0x8<<28, and don't know which - MOV32ItoR(EDX, p->startpc); - assert( (uptr)x86Ptr <= 0xffffffff ); - PUSH32I((uptr)x86Ptr); - JMP32((uptr)psxDispatcherClear - ( (uptr)x86Ptr + 5 )); - assert( x86Ptr == (u8*)p->GetFnptr() + IOP_MIN_BLOCK_BYTES ); - - pstart = PSX_GETBLOCK(p->startpc); - pexblock = PSX_GETBLOCKEX(pstart); - assert( pexblock->startpc == pstart->startpc ); - - // don't delete if last is delay - lastdelay = pexblock->size; - if( pstart[pexblock->size-1].uType & BLOCKTYPE_DELAYSLOT ) { - assert( pstart[pexblock->size-1].GetFnptr() != pstart->GetFnptr() ); - if( pstart[pexblock->size-1].GetFnptr() != 0 ) { - pstart[pexblock->size-1].uType = 0; - --lastdelay; - } - } - - memset(pstart, 0, lastdelay*sizeof(BASEBLOCK)); - - RemoveBaseBlockEx(pexblock, 1); - pexblock->size = 0; - pexblock->startpc = 0; -} - -void psxSetBranchReg(u32 reg) -{ - psxbranch = 1; - - if( reg != 0xffffffff ) { - _allocX86reg(ESI, X86TYPE_PCWRITEBACK, 0, MODE_WRITE); - _psxMoveGPRtoR(ESI, reg); - - psxRecompileNextInstruction(1); - - if( x86regs[ESI].inuse ) { - assert( x86regs[ESI].type == X86TYPE_PCWRITEBACK ); - MOV32RtoM((uptr)&psxRegs.pc, ESI); - x86regs[ESI].inuse = 0; - } - else { - MOV32MtoR(EAX, (uptr)&g_recWriteback); - MOV32RtoM((uptr)&psxRegs.pc, EAX); - } - } - - _psxFlushCall(FLUSH_EVERYTHING); - iPsxBranchTest(0xffffffff, 1); - - JMP32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 5 )); -} - -void psxSetBranchImm( u32 imm ) -{ - u32* ptr; - psxbranch = 1; - assert( imm ); - - // end the current block - MOV32ItoM( (uptr)&psxRegs.pc, imm ); - _psxFlushCall(FLUSH_EVERYTHING); - iPsxBranchTest(imm, imm <= psxpc); - - MOV32ItoR(EDX, 0); - ptr = (u32*)(x86Ptr-4); - *ptr = (uptr)JMP32((uptr)psxDispatcher - ( (uptr)x86Ptr + 5 )); -} - -//fixme : this is all a huge hack, we base the counter advancements on the average an opcode should take (wtf?) -// If that wasn't bad enough we have default values like 9/8 which will get cast to int later -// (yeah, that means all sync code couldn't have worked to beginn with) -// So for now these are new settings that work. -// (rama) - -static u32 psxScaleBlockCycles() -{ - return s_psxBlockCycles * (CHECK_IOP_CYCLERATE ? 2 : 1); -} - -static void iPsxBranchTest(u32 newpc, u32 cpuBranch) -{ - u32 blockCycles = psxScaleBlockCycles(); - - MOV32MtoR(ECX, (uptr)&psxRegs.cycle); - MOV32MtoR(EAX, (uptr)&psxCycleEE); - ADD32ItoR(ECX, blockCycles); - SUB32ItoR(EAX, blockCycles*8); - MOV32RtoM((uptr)&psxRegs.cycle, ECX); // update cycles - MOV32RtoM((uptr)&psxCycleEE, EAX); - - j8Ptr[2] = JG8( 0 ); // jump if psxCycleEE > 0 - - RET2(); // returns control to the EE - - // Continue onward with branching here: - x86SetJ8( j8Ptr[2] ); - - // check if should branch - SUB32MtoR(ECX, (uptr)&g_psxNextBranchCycle); - j8Ptr[0] = JS8( 0 ); - - CALLFunc((uptr)psxBranchTest); - - if( newpc != 0xffffffff ) - { - CMP32ItoM((uptr)&psxRegs.pc, newpc); - JNE32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 6 )); - } - - // Skip branch jump target here: - x86SetJ8( j8Ptr[0] ); -} - -static int *s_pCode; - -#if !defined(_MSC_VER) -static void checkcodefn() -{ - int pctemp; - -#ifdef _MSC_VER - __asm mov pctemp, eax; -#else - __asm__("movl %%eax, %0" : : "m"(pctemp) ); -#endif - SysPrintf("iop code changed! %x\n", pctemp); -} -#endif - -void rpsxSYSCALL() -{ - MOV32ItoM( (uptr)&psxRegs.code, psxRegs.code ); - MOV32ItoM((uptr)&psxRegs.pc, psxpc - 4); - _psxFlushCall(FLUSH_NODESTROY); - - _callFunctionArg2((uptr)psxException, MEM_CONSTTAG, MEM_CONSTTAG, 0x20, psxbranch==1); - - CMP32ItoM((uptr)&psxRegs.pc, psxpc-4); - j8Ptr[0] = JE8(0); - - ADD32ItoM((uptr)&psxRegs.cycle, psxScaleBlockCycles() ); - SUB32ItoM((uptr)&psxCycleEE, psxScaleBlockCycles()*8 ); - JMP32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 5 )); - - // jump target for skipping blockCycle updates - x86SetJ8(j8Ptr[0]); - - //if (!psxbranch) psxbranch = 2; -} - -void rpsxBREAK() -{ - MOV32ItoM( (uptr)&psxRegs.code, psxRegs.code ); - MOV32ItoM((uptr)&psxRegs.pc, psxpc - 4); - _psxFlushCall(FLUSH_NODESTROY); - - _callFunctionArg2((uptr)psxBREAK, MEM_CONSTTAG, MEM_CONSTTAG, 0x24, psxbranch==1); - - CMP32ItoM((uptr)&psxRegs.pc, psxpc-4); - j8Ptr[0] = JE8(0); - ADD32ItoM((uptr)&psxRegs.cycle, psxScaleBlockCycles() ); - SUB32ItoM((uptr)&psxCycleEE, psxScaleBlockCycles()*8 ); - JMP32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 5 )); - x86SetJ8(j8Ptr[0]); - - //if (!psxbranch) psxbranch = 2; -} - -u32 psxRecompileCodeSafe(u32 temppc) -{ - BASEBLOCK* pblock = PSX_GETBLOCK(temppc); - - if( pblock->GetFnptr() != 0 && pblock->startpc != s_pCurBlock->startpc ) { - if( psxpc == pblock->startpc ) - return 0; - } - - return 1; -} - -void psxRecompileNextInstruction(int delayslot) -{ - static u8 s_bFlushReg = 1; - - BASEBLOCK* pblock = PSX_GETBLOCK(psxpc); - - // need *ppblock != s_pCurBlock because of branches - if( pblock->GetFnptr() != 0 && pblock->startpc != s_pCurBlock->startpc ) { - - if( !delayslot && psxpc == pblock->startpc ) { - // code already in place, so jump to it and exit recomp - assert( PSX_GETBLOCKEX(pblock)->startpc == pblock->startpc ); - - _psxFlushCall(FLUSH_EVERYTHING); - MOV32ItoM((uptr)&psxRegs.pc, psxpc); - -// if( pexblock->pOldFnptr ) { -// // code already in place, so jump to it and exit recomp -// JMP32((uptr)pexblock->pOldFnptr - ((uptr)x86Ptr + 5)); -// branch = 3; -// return; -// } - - JMP32((uptr)pblock->GetFnptr() - ((uptr)x86Ptr + 5)); - psxbranch = 3; - return; - } - else { - - if( !(delayslot && pblock->startpc == psxpc) ) { - u8* oldX86 = x86Ptr; - //__Log("clear block %x\n", pblock->startpc); - psxRecClearMem(pblock); - x86Ptr = oldX86; - if( delayslot ) - SysPrintf("delay slot %x\n", psxpc); - } - } - } - - if( delayslot ) - pblock->uType = BLOCKTYPE_DELAYSLOT; - -#ifdef _DEBUG - MOV32ItoR(EAX, psxpc); -#endif - - s_pCode = (int *)PSXM( psxpc ); - assert(s_pCode); - - psxRegs.code = *(int *)s_pCode; - s_psxBlockCycles++; - psxpc += 4; - -//#ifdef _DEBUG -// CMP32ItoM((uptr)s_pCode, psxRegs.code); -// j8Ptr[0] = JE8(0); -// MOV32ItoR(EAX, psxpc); -// CALLFunc((uptr)checkcodefn); -// x86SetJ8( j8Ptr[ 0 ] ); -//#endif - - - g_pCurInstInfo++; - -#ifdef PCSX2_VM_COISSUE - assert( g_pCurInstInfo->info & EEINSTINFO_COREC ); -#endif - - g_iopCyclePenalty = 0; - rpsxBSC[ psxRegs.code >> 26 ](); - s_psxBlockCycles += g_iopCyclePenalty; - - if( !delayslot ) { - if( s_bFlushReg ) { - //_psxFlushUnusedConstReg(); - } - else s_bFlushReg = 1; - } - else s_bFlushReg = 1; - - _clearNeededX86regs(); -} - -static void recExecute() { - for (;;) R3000AExecute(); -} - -static s32 recExecuteBlock( s32 eeCycles ) -{ - psxBreak = 0; - psxCycleEE = eeCycles; - R3000AExecute(); - return psxBreak + psxCycleEE; -} - -#include "IopHw.h" - -void iDumpPsxRegisters(u32 startpc, u32 temp) -{ -// [TODO] fixme : thie code is broken and has no labels. Needs a rewrite to be useful. - -#if 0 - int i; - const char* pstr = temp ? "t" : ""; - - __Log("%spsxreg: %x %x ra:%x k0: %x %x\n", pstr, startpc, psxRegs.cycle, psxRegs.GPR.n.ra, psxRegs.GPR.n.k0, *(int*)PSXM(0x13c128)); - for(i = 0; i < 34; i+=2) __Log("%spsx%s: %x %x\n", pstr, disRNameGPR[i], psxRegs.GPR.r[i], psxRegs.GPR.r[i+1]); - __Log("%scycle: %x %x %x; counters %x %x\n", pstr, psxRegs.cycle, g_psxNextBranchCycle, EEsCycle, - psxNextsCounter, psxNextCounter); - - __Log("psxdma%d c%x b%x m%x t%x\n", 2, HW_DMA2_CHCR, HW_DMA2_BCR, HW_DMA2_MADR, HW_DMA2_TADR); - __Log("psxdma%d c%x b%x m%x\n", 3, HW_DMA3_CHCR, HW_DMA3_BCR, HW_DMA3_MADR); - __Log("psxdma%d c%x b%x m%x t%x\n", 4, HW_DMA4_CHCR, HW_DMA4_BCR, HW_DMA4_MADR, HW_DMA4_TADR); - __Log("psxdma%d c%x b%x m%x\n", 6, HW_DMA6_CHCR, HW_DMA6_BCR, HW_DMA6_MADR); - __Log("psxdma%d c%x b%x m%x\n", 7, HW_DMA7_CHCR, HW_DMA7_BCR, HW_DMA7_MADR); - __Log("psxdma%d c%x b%x m%x\n", 8, HW_DMA8_CHCR, HW_DMA8_BCR, HW_DMA8_MADR); - __Log("psxdma%d c%x b%x m%x t%x\n", 9, HW_DMA9_CHCR, HW_DMA9_BCR, HW_DMA9_MADR, HW_DMA9_TADR); - __Log("psxdma%d c%x b%x m%x\n", 10, HW_DMA10_CHCR, HW_DMA10_BCR, HW_DMA10_MADR); - __Log("psxdma%d c%x b%x m%x\n", 11, HW_DMA11_CHCR, HW_DMA11_BCR, HW_DMA11_MADR); - __Log("psxdma%d c%x b%x m%x\n", 12, HW_DMA12_CHCR, HW_DMA12_BCR, HW_DMA12_MADR); - for(i = 0; i < 7; ++i) - __Log("%scounter%d: mode %x count %I64x rate %x scycle %x target %I64x\n", pstr, i, psxCounters[i].mode, psxCounters[i].count, psxCounters[i].rate, psxCounters[i].sCycleT, psxCounters[i].target); -#endif -} - -void iDumpPsxRegisters(u32 startpc); - -#ifdef _DEBUG -static void printfn() -{ - static int lastrec = 0; - static int curcount = 0; - const int skip = 0; - - //*(int*)PSXM(0x27990) = 1; // enables cdvd bios output for scph10000 - - if( psxRegs.cycle == 0x113a1be5 ) { -// FILE* tempf = fopen("tempdmciop.txt", "wb"); -// fwrite(PSXM(0), 0x200000, 1, tempf); -// fclose(tempf); - //psxdump |= 2; - } - -// if( psxRegs.cycle == 0x114152d8 ) { -// psxRegs.GPR.n.s0 = 0x55000; -// } - - if( (psxdump&2) && lastrec != g_psxlastpc ) { - curcount++; - - if( curcount > skip ) { - iDumpPsxRegisters(g_psxlastpc, 1); - curcount = 0; - } - - lastrec = g_psxlastpc; - } -} -#endif - -void psxRecRecompile(u32 startpc) -{ - u32 i; - u32 branchTo; - u32 willbranch3 = 0; - u32* ptr; - -#ifdef _DEBUG - //psxdump |= 4; - if( psxdump & 4 ) - iDumpPsxRegisters(startpc, 0); -#endif - - assert( startpc ); - - // if recPtr reached the mem limit reset whole mem - if (((uptr)recPtr - (uptr)recMem) >= (RECMEM_SIZE - 0x10000)) { - DevCon::WriteLn("IOP Recompiler data reset"); - recResetIOP(); - } - - s_pCurBlock = PSX_GETBLOCK(startpc); - - if( s_pCurBlock->GetFnptr() ) { - // clear if already taken - assert( s_pCurBlock->startpc < startpc ); - psxRecClearMem(s_pCurBlock); - } - - if( s_pCurBlock->startpc == startpc ) { - s_pCurBlockEx = PSX_GETBLOCKEX(s_pCurBlock); - assert( s_pCurBlockEx->startpc == startpc ); - } - else { - s_pCurBlockEx = NULL; - for(i = 0; i < PSX_NUMBLOCKS; ++i) { - if( recBlocks[(i+s_nNextBlock)%PSX_NUMBLOCKS].size == 0 ) { - s_pCurBlockEx = recBlocks+(i+s_nNextBlock)%PSX_NUMBLOCKS; - s_nNextBlock = (i+s_nNextBlock+1)%PSX_NUMBLOCKS; - break; - } - } - - if( s_pCurBlockEx == NULL ) { - DevCon::WriteLn("IOP Recompiler data reset"); - recResetIOP(); - s_nNextBlock = 0; - s_pCurBlockEx = recBlocks; - } - - s_pCurBlockEx->startpc = startpc; - } - - x86SetPtr( recPtr ); - x86Align(16); - recPtr = x86Ptr; - - psxbranch = 0; - - s_pCurBlock->startpc = startpc; - s_pCurBlock->SetFnptr( (uptr)x86Ptr ); - s_psxBlockCycles = 0; - - // reset recomp state variables - psxpc = startpc; - s_saveConstGPRreg = 0; - g_psxHasConstReg = g_psxFlushedConstReg = 1; - - _initX86regs(); - -#ifdef _DEBUG - // for debugging purposes - MOV32ItoM((uptr)&g_psxlastpc, psxpc); - CALLFunc((uptr)printfn); -#endif - - // go until the next branch - i = startpc; - s_nEndBlock = 0xffffffff; - - while(1) { - BASEBLOCK* pblock = PSX_GETBLOCK(i); - if( pblock->GetFnptr() != 0 && pblock->startpc != s_pCurBlock->startpc ) { - - if( i == pblock->startpc ) { - // branch = 3 - willbranch3 = 1; - s_nEndBlock = i; - break; - } - } - - psxRegs.code = *(int *)PSXM(i); - - switch(psxRegs.code >> 26) { - case 0: // special - - if( _Funct_ == 8 || _Funct_ == 9 ) { // JR, JALR - s_nEndBlock = i + 8; - goto StartRecomp; - } - - break; - case 1: // regimm - - if( _Rt_ == 0 || _Rt_ == 1 || _Rt_ == 16 || _Rt_ == 17 ) { - - branchTo = _Imm_ * 4 + i + 4; - if( branchTo > startpc && branchTo < i ) s_nEndBlock = branchTo; - else s_nEndBlock = i+8; - - goto StartRecomp; - } - - break; - - case 2: // J - case 3: // JAL - s_nEndBlock = i + 8; - goto StartRecomp; - - // branches - case 4: case 5: case 6: case 7: - - branchTo = _Imm_ * 4 + i + 4; - if( branchTo > startpc && branchTo < i ) s_nEndBlock = branchTo; - else s_nEndBlock = i+8; - - goto StartRecomp; - } - - i += 4; - } - -StartRecomp: - - // rec info // - { - EEINST* pcur; - - if( s_nInstCacheSize < (s_nEndBlock-startpc)/4+1 ) { - free(s_pInstCache); - s_nInstCacheSize = (s_nEndBlock-startpc)/4+10; - s_pInstCache = (EEINST*)malloc(sizeof(EEINST)*s_nInstCacheSize); - assert( s_pInstCache != NULL ); - } - - pcur = s_pInstCache + (s_nEndBlock-startpc)/4; - _recClearInst(pcur); - pcur->info = 0; - - for(i = s_nEndBlock; i > startpc; i -= 4 ) { - psxRegs.code = *(int *)PSXM(i-4); - pcur[-1] = pcur[0]; - rpsxpropBSC(pcur-1, pcur); - pcur--; - } - } - -#ifdef _DEBUG - // dump code - for(i = 0; i < ARRAYSIZE(s_psxrecblocks); ++i) { - if( startpc == s_psxrecblocks[i] ) { - iIopDumpBlock(startpc, recPtr); - } - } - - if( (psxdump & 1) ) - iIopDumpBlock(startpc, recPtr); -#endif - - g_pCurInstInfo = s_pInstCache; - while (!psxbranch && psxpc < s_nEndBlock) { - psxRecompileNextInstruction(0); - } - -#ifdef _DEBUG - if( (psxdump & 1) ) - iIopDumpBlock(startpc, recPtr); -#endif - - assert( (psxpc-startpc)>>2 <= 0xffff ); - s_pCurBlockEx->size = (psxpc-startpc)>>2; - - for(i = 1; i < (u32)s_pCurBlockEx->size-1; ++i) { - s_pCurBlock[i].SetFnptr( s_pCurBlock->GetFnptr() ); - s_pCurBlock[i].startpc = s_pCurBlock->startpc; - } - - // don't overwrite if delay slot - if( i < (u32)s_pCurBlockEx->size && !(s_pCurBlock[i].uType & BLOCKTYPE_DELAYSLOT) ) { - s_pCurBlock[i].SetFnptr( s_pCurBlock->GetFnptr() ); - s_pCurBlock[i].startpc = s_pCurBlock->startpc; - } - - // set the block ptr - AddBaseBlockEx(s_pCurBlockEx, 1); - - if( !(psxpc&0x10000000) ) - g_psxMaxRecMem = std::max( (psxpc&~0xa0000000), g_psxMaxRecMem ); - - if( psxbranch == 2 ) { - _psxFlushCall(FLUSH_EVERYTHING); - - iPsxBranchTest(0xffffffff, 1); - - JMP32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 5 )); - } - else { - assert( psxbranch != 3 ); - if( psxbranch ) assert( !willbranch3 ); - else - { - ADD32ItoM((uptr)&psxRegs.cycle, psxScaleBlockCycles() ); - SUB32ItoM((uptr)&psxCycleEE, psxScaleBlockCycles()*8 ); - } - - if( willbranch3 ) { - BASEBLOCK* pblock = PSX_GETBLOCK(s_nEndBlock); - assert( psxpc == s_nEndBlock ); - _psxFlushCall(FLUSH_EVERYTHING); - MOV32ItoM((uptr)&psxRegs.pc, psxpc); - JMP32((uptr)pblock->GetFnptr() - ((uptr)x86Ptr + 5)); - psxbranch = 3; - } - else if( !psxbranch ) { - // didn't branch, but had to stop - MOV32ItoM( (uptr)&psxRegs.pc, psxpc ); - - _psxFlushCall(FLUSH_EVERYTHING); - - ptr = JMP32(0); - //JMP32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 5 )); - } - } - - assert( x86Ptr >= (u8*)s_pCurBlock->GetFnptr() + IOP_MIN_BLOCK_BYTES ); - assert( x86Ptr < recMem+RECMEM_SIZE ); - - recPtr = x86Ptr; - - assert( (g_psxHasConstReg&g_psxFlushedConstReg) == g_psxHasConstReg ); - - if( !psxbranch ) { - BASEBLOCK* pcurblock = s_pCurBlock; - u32 nEndBlock = s_nEndBlock; - s_pCurBlock = PSX_GETBLOCK(psxpc); - assert( ptr != NULL ); - - if( s_pCurBlock->startpc != psxpc ){ - psxRecRecompile(psxpc); - } - - // could have reset - if( pcurblock->startpc == startpc ) { - assert( pcurblock->GetFnptr() ); - assert( s_pCurBlock->startpc == nEndBlock ); - *ptr = (u32)((uptr)s_pCurBlock->GetFnptr() - ( (uptr)ptr + 4 )); - } - else { - psxRecRecompile(startpc); - assert( pcurblock->GetFnptr() != 0 ); - } - } - else - assert( s_pCurBlock->GetFnptr() != 0 ); -} - -R3000Acpu psxRec = { - recAlloc, - recResetIOP, - recExecute, - recExecuteBlock, - recClear, - recShutdown -}; - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +// recompiler reworked to add dynamic linking Jan06 +// and added reg caching, const propagation, block analysis Jun06 +// zerofrog(@gmail.com) + + +#include "PrecompiledHeader.h" + +#include + +#ifndef _WIN32 +#include +#endif + +#include "PsxCommon.h" +#include "VU.h" + +#include "ix86/ix86.h" +#include "iCore.h" +#include "iR3000A.h" + +#include "SamplProf.h" + +extern u32 g_psxNextBranchCycle; +extern void psxBREAK(); +extern void zeroEx(); + +u32 g_psxMaxRecMem = 0; +u32 s_psxrecblocks[] = {0}; + +//Using assembly code from an external file. +#ifdef __LINUX__ +extern "C" { +#endif +void psxRecRecompile(u32 startpc); +#ifdef __LINUX__ +} +#endif + +uptr *psxRecLUT; + +#define PSX_NUMBLOCKS (1<<12) +#define MAPBASE 0x48000000 +#define RECMEM_SIZE (8*1024*1024) + +#define PSX_MEMMASK 0x5fffffff // mask when comparing two pcs + +// R3000A statics +int psxreclog = 0; + +static u8 *recMem = NULL; // the recompiled blocks will be here +static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here +static BASEBLOCK *recROM = NULL; // and here +static BASEBLOCK *recROM1 = NULL; // also here +static BASEBLOCKEX *recBlocks = NULL; +static u8 *recPtr = NULL; +u32 psxpc; // recompiler psxpc +int psxbranch; // set for branch +u32 g_iopCyclePenalty; + +static EEINST* s_pInstCache = NULL; +static u32 s_nInstCacheSize = 0; + +static BASEBLOCK* s_pCurBlock = NULL; +static BASEBLOCKEX* s_pCurBlockEx = NULL; + +#if defined(_MSC_VER) && !defined(__x86_64__) +static BASEBLOCK* s_pDispatchBlock = NULL; +#endif + +static u32 s_nEndBlock = 0; // what psxpc the current block ends + +static u32 s_nNextBlock = 0; // next free block in recBlocks + +static u32 s_ConstGPRreg; +static u32 s_saveConstGPRreg = 0, s_saveHasConstReg = 0, s_saveFlushedConstReg = 0; +static EEINST* s_psaveInstInfo = NULL; + +u32 s_psxBlockCycles = 0; // cycles of current block recompiling +static u32 s_savenBlockCycles = 0; + +static void iPsxBranchTest(u32 newpc, u32 cpuBranch); +void psxRecompileNextInstruction(int delayslot); + +extern void (*rpsxBSC[64])(); +extern void (*rpsxBSC_co[64])(); +void rpsxpropBSC(EEINST* prev, EEINST* pinst); + +#ifdef _DEBUG +u32 psxdump = 0; +#else +#define psxdump 0 +#endif + +#define PSX_GETBLOCK(x) PC_GETBLOCK_(x, psxRecLUT) + +#define PSXREC_CLEARM(mem) { \ + if ((mem) < g_psxMaxRecMem && psxRecLUT[(mem) >> 16]) { \ + BASEBLOCK* p = PSX_GETBLOCK(mem); \ + if( *(u32*)p ) psxRecClearMem(p); \ + } \ +} \ + +BASEBLOCKEX* PSX_GETBLOCKEX(BASEBLOCK* p) +{ +// BASEBLOCKEX* pex = *(BASEBLOCKEX**)(p+1); +// if( pex >= recBlocks && pex < recBlocks+PSX_NUMBLOCKS ) +// return pex; + + // otherwise, use the sorted list + return GetBaseBlockEx(p->startpc, 1); +} + +//////////////////////////////////////////////////// +#ifdef _DEBUG +using namespace R3000A; +static void iIopDumpBlock( int startpc, u8 * ptr ) +{ + FILE *f; + char filename[ g_MaxPath ]; +#ifdef __LINUX__ + char command[256]; +#endif + u32 i, j; + EEINST* pcur; + u8 used[34]; + int numused, count; + + SysPrintf( "dump1 %x:%x, %x\n", startpc, psxpc, psxRegs.cycle ); +#ifdef _WIN32 + CreateDirectory("dumps", NULL); + sprintf_s( filename, g_MaxPath, "dumps\\psxdump%.8X.txt", startpc); +#else + mkdir("dumps", 0755); + sprintf( filename, "dumps/psxdump%.8X.txt", startpc); +#endif + + fflush( stdout ); + + f = fopen( filename, "w" ); + assert( f != NULL ); + for ( i = startpc; i < s_nEndBlock; i += 4 ) { + fprintf( f, "%s\n", disR3000Fasm( *(u32*)PSXM( i ), i ) ); + } + + // write the instruction info + fprintf(f, "\n\nlive0 - %x, lastuse - %x used - %x\n", EEINST_LIVE0, EEINST_LASTUSE, EEINST_USED); + + memzero_obj(used); + numused = 0; + for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { + if( s_pInstCache->regs[i] & EEINST_USED ) { + used[i] = 1; + numused++; + } + } + + fprintf(f, " "); + for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { + if( used[i] ) fprintf(f, "%2d ", i); + } + fprintf(f, "\n"); + + fprintf(f, " "); + for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { + if( used[i] ) fprintf(f, "%s ", disRNameGPR[i]); + } + fprintf(f, "\n"); + + pcur = s_pInstCache+1; + for( i = 0; i < (s_nEndBlock-startpc)/4; ++i, ++pcur) { + fprintf(f, "%2d: %2.2x ", i+1, pcur->info); + + count = 1; + for(j = 0; j < ARRAYSIZE(s_pInstCache->regs); j++) { + if( used[j] ) { + fprintf(f, "%2.2x%s", pcur->regs[j], ((count%8)&&count tempdump", filename ); + system( command ); + sprintf(command, "mv tempdump %s", filename); + system(command); + f = fopen( filename, "a+" ); +#endif +} +#endif + +u8 _psxLoadWritesRs(u32 tempcode) +{ + switch(tempcode>>26) { + case 32: case 33: case 34: case 35: case 36: case 37: case 38: + return ((tempcode>>21)&0x1f)==((tempcode>>16)&0x1f); // rs==rt + } + return 0; +} + +u8 _psxIsLoadStore(u32 tempcode) +{ + switch(tempcode>>26) { + case 32: case 33: case 34: case 35: case 36: case 37: case 38: + // 4 byte stores + case 40: case 41: case 42: case 43: case 46: + return 1; + } + return 0; +} + +void _psxFlushAllUnused() +{ + int i; + for(i = 0; i < 34; ++i) { + if( psxpc < s_nEndBlock ) { + if( (g_pCurInstInfo[1].regs[i]&EEINST_USED) ) + continue; + } + else if( (g_pCurInstInfo[0].regs[i]&EEINST_USED) ) + continue; + + if( i < 32 && PSX_IS_CONST1(i) ) _psxFlushConstReg(i); + else { + _deleteX86reg(X86TYPE_PSX, i, 1); + } + } +} + +int _psxFlushUnusedConstReg() +{ + int i; + for(i = 1; i < 32; ++i) { + if( (g_psxHasConstReg & (1< 0 ); + + // make sure right GPR was saved + assert( g_psxHasConstReg == s_saveHasConstReg || (g_psxHasConstReg ^ s_saveHasConstReg) == (1<>26) == 9 ) { + //ADDIU, call bios +#ifdef _DEBUG + MOV32ItoM( (uptr)&psxRegs.code, psxRegs.code ); + MOV32ItoM( (uptr)&psxRegs.pc, psxpc ); + _psxFlushCall(FLUSH_NODESTROY); + CALLFunc((uptr)zeroEx); +#endif + // Bios Call: Force the IOP to do a Branch Test ASAP. + // Important! This helps prevent game freeze-ups during boot-up and stage loads. + // Note: Fixes to cdvd have removed the need for this code. + //MOV32MtoR( EAX, (uptr)&psxRegs.cycle ); + //MOV32RtoM( (uptr)&g_psxNextBranchCycle, EAX ); + } + return; + } + + // for now, don't support xmm + PSX_CHECK_SAVE_REG(_Rt_); + + _deleteX86reg(X86TYPE_PSX, _Rs_, 1); + _deleteX86reg(X86TYPE_PSX, _Rt_, 0); + + if( PSX_IS_CONST1(_Rs_) ) { + PSX_SET_CONST(_Rt_); + constcode(); + return; + } + + noconstcode(0); + PSX_DEL_CONST(_Rt_); +} + +// rd = rt op sa +void psxRecompileCodeConst2(R3000AFNPTR constcode, R3000AFNPTR_INFO noconstcode) +{ + if ( ! _Rd_ ) return; + + // for now, don't support xmm + PSX_CHECK_SAVE_REG(_Rd_); + + _deleteX86reg(X86TYPE_PSX, _Rt_, 1); + _deleteX86reg(X86TYPE_PSX, _Rd_, 0); + + if( PSX_IS_CONST1(_Rt_) ) { + PSX_SET_CONST(_Rd_); + constcode(); + return; + } + + noconstcode(0); + PSX_DEL_CONST(_Rd_); +} + +// rd = rt MULT rs (SPECIAL) +void psxRecompileCodeConst3(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode, R3000AFNPTR_INFO consttcode, R3000AFNPTR_INFO noconstcode, int LOHI) +{ + _deleteX86reg(X86TYPE_PSX, _Rs_, 1); + _deleteX86reg(X86TYPE_PSX, _Rt_, 1); + + if( LOHI ) { + _deleteX86reg(X86TYPE_PSX, PSX_HI, 1); + _deleteX86reg(X86TYPE_PSX, PSX_LO, 1); + } + + if( PSX_IS_CONST2(_Rs_, _Rt_) ) { + constcode(); + return; + } + + if( PSX_IS_CONST1(_Rs_) ) { + constscode(0); + return; + } + + if( PSX_IS_CONST1(_Rt_) ) { + consttcode(0); + return; + } + + noconstcode(0); +} + +static u8* m_recBlockAlloc = NULL; + +static const uint m_recBlockAllocSize = + (((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK)) + + (PSX_NUMBLOCKS*sizeof(BASEBLOCKEX)); // recBlocks + +static void recAlloc() +{ + // Note: the VUrec depends on being able to grab an allocation below the 0x10000000 line, + // so we give the EErec an address above that to try first as it's basemem address, hence + // the 0x28000000 pick (0x20000000 is picked by the EE) + + if( recMem == NULL ) + recMem = (u8*)SysMmapEx( 0x28000000, RECMEM_SIZE, 0, "recAlloc(R3000a)" ); + + if( recMem == NULL ) + throw Exception::OutOfMemory( "R3000a Init > failed to allocate memory for the recompiler." ); + + if( psxRecLUT == NULL ) + psxRecLUT = (uptr*) malloc(0x010000 * sizeof(uptr)); + + // Goal: Allocate BASEBLOCKs for every possible branch target in IOP memory. + // Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are + // always 4 bytes long). + + if( m_recBlockAlloc == NULL ) + m_recBlockAlloc = (u8*)_aligned_malloc( m_recBlockAllocSize, 4096 ); + + if( m_recBlockAlloc == NULL ) + throw Exception::OutOfMemory( "R3000a Init > Failed to allocate memory for baseblock lookup tables." ); + + u8* curpos = m_recBlockAlloc; + recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::IopRam / 4) * sizeof(BASEBLOCK); + recROM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom / 4) * sizeof(BASEBLOCK); + recROM1 = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom1 / 4) * sizeof(BASEBLOCK); + recBlocks = (BASEBLOCKEX*)curpos; // curpos += sizeof(BASEBLOCKEX)*EE_NUMBLOCKS; + + if( s_pInstCache == NULL ) + { + s_nInstCacheSize = 128; + s_pInstCache = (EEINST*)malloc( sizeof(EEINST) * s_nInstCacheSize ); + } + + if( s_pInstCache == NULL ) + throw Exception::OutOfMemory( "R3000a Init > Failed to allocate memory for pInstCache." ); + + ProfilerRegisterSource( "IOPRec", recMem, RECMEM_SIZE ); +} + +void recResetIOP() +{ + // calling recResetIOP without first calling recInit is bad mojo. + jASSUME( psxRecLUT != NULL ); + jASSUME( recMem != NULL ); + jASSUME( m_recBlockAlloc != NULL ); + + DbgCon::Status( "iR3000A > Resetting recompiler memory and structures!" ); + + memzero_ptr<0x010000 * sizeof(uptr)>( psxRecLUT ); + memset_8<0xcd,RECMEM_SIZE>( recMem ); + memzero_ptr( m_recBlockAlloc ); + + // We're only mapping 20 pages here in 4 places. + // 0x80 comes from : (Ps2MemSize::IopRam / 0x10000) * 4 + for (int i=0; i<0x80; i++) + { + psxRecLUT[i + 0x0000] = (uptr)&recRAM[(i & 0x1f) << 14]; + psxRecLUT[i + 0x8000] = (uptr)&recRAM[(i & 0x1f) << 14]; + psxRecLUT[i + 0xa000] = (uptr)&recRAM[(i & 0x1f) << 14]; + } + + for (int i=0; i<(Ps2MemSize::Rom / 0x10000); i++) + { + psxRecLUT[i + 0x1fc0] = (uptr)&recROM[i << 14]; + psxRecLUT[i + 0x9fc0] = (uptr)&recROM[i << 14]; + psxRecLUT[i + 0xbfc0] = (uptr)&recROM[i << 14]; + } + + for (int i=0; i<(Ps2MemSize::Rom1 / 0x10000); i++) + { + psxRecLUT[i + 0x1e00] = (uptr)&recROM1[i << 14]; + psxRecLUT[i + 0x9e00] = (uptr)&recROM1[i << 14]; + psxRecLUT[i + 0xbe00] = (uptr)&recROM1[i << 14]; + } + + if( s_pInstCache ) + memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize ); + + ResetBaseBlockEx(1); + g_psxMaxRecMem = 0; + + recPtr = recMem; + psxbranch = 0; +} + +static void recShutdown() +{ + ProfilerTerminateSource( "IOPRec" ); + + SafeSysMunmap(recMem, RECMEM_SIZE); + safe_aligned_free( m_recBlockAlloc ); + + safe_free(psxRecLUT); + safe_free( s_pInstCache ); + s_nInstCacheSize = 0; + + x86Shutdown(); +} + +#pragma warning(disable:4731) // frame pointer register 'ebp' modified by inline assembly code + +static u32 s_uSaveESP = 0; + +static __forceinline void R3000AExecute() +{ +#ifdef _DEBUG + u8* fnptr; + u32 oldesi; +/*#else + R3000AFNPTR pfn;*/ +#endif + + BASEBLOCK* pblock; + + pblock = PSX_GETBLOCK(psxRegs.pc); + + if ( !pblock->GetFnptr() || (pblock->startpc&PSX_MEMMASK) != (psxRegs.pc&PSX_MEMMASK) ) { + psxRecRecompile(psxRegs.pc); + } + + assert( pblock->GetFnptr() != 0 ); + +#ifdef _DEBUG + + fnptr = (u8*)pblock->GetFnptr(); + +#ifdef _MSC_VER + + __asm { + // save data + mov oldesi, esi; + mov s_uSaveESP, esp; + sub s_uSaveESP, 8; + push ebp; + + call fnptr; // jump into function + // restore data + pop ebp; + mov esi, oldesi; + } + +#else // linux + + __asm__("movl %%esi, %0\n" + "movl %%esp, %1\n" + "sub $8, %%esp\n" + "push %%ebp\n" + "call *%2\n" + "pop %%ebp\n" + "movl %0, %%esi\n" : "=m"(oldesi), "=m"(s_uSaveESP) : "c"(fnptr) : ); +#endif // _MSC_VER + +#else + ((R3000AFNPTR)pblock->GetFnptr())(); +#endif +} + +u32 g_psxlastpc = 0; + +#if defined(_MSC_VER) + +static u32 g_temp; + +// jumped to when invalid psxpc address +__declspec(naked,noreturn) void psxDispatcher() +{ + // EDX contains the current psxpc to jump to, stack contains the jump addr to modify + __asm push edx + + // calc PSX_GETBLOCK + s_pDispatchBlock = PSX_GETBLOCK(psxRegs.pc); + + __asm { + mov eax, s_pDispatchBlock + + // check if startpc&PSX_MEMMASK == psxRegs.pc&PSX_MEMMASK + mov ecx, psxRegs.pc + mov edx, [eax+BLOCKTYPE_STARTPC]; + and ecx, PSX_MEMMASK // remove higher bits + and edx, PSX_MEMMASK + cmp ecx, edx + je CheckPtr + + // recompile + push psxRegs.pc // psxpc + call psxRecRecompile + add esp, 4 // pop old param + mov eax, s_pDispatchBlock +CheckPtr: + mov eax, dword ptr [eax] + } + +#ifdef _DEBUG + __asm mov g_temp, eax + assert( g_temp ); +#endif + + __asm { + //and eax, 0x0fffffff + shl eax,4 + mov edx, eax + pop ecx // x86Ptr to mod + sub edx, ecx + sub edx, 4 + mov dword ptr [ecx], edx + + jmp eax + } +} + +__declspec(naked,noreturn) void psxDispatcherClear() +{ + // EDX contains the current psxpc + __asm mov psxRegs.pc, edx + __asm push edx + + // calc PSX_GETBLOCK + s_pDispatchBlock = PSX_GETBLOCK(psxRegs.pc); + + if( (s_pDispatchBlock->startpc&PSX_MEMMASK) == (psxRegs.pc&PSX_MEMMASK) ) { + assert( s_pDispatchBlock->GetFnptr() != 0 ); + + // already modded the code, jump to the new place + __asm { + pop edx + add esp, 4 // ignore stack + mov eax, s_pDispatchBlock + mov eax, dword ptr [eax] + //and eax, 0x0fffffff + shl eax,4 + jmp eax + } + } + + __asm { + call psxRecRecompile + add esp, 4 // pop old param + mov eax, s_pDispatchBlock + mov eax, dword ptr [eax] + + pop ecx // old fnptr + + //and eax, 0x0fffffff + shl eax,4 + mov byte ptr [ecx], 0xe9 // jmp32 + mov edx, eax + sub edx, ecx + sub edx, 5 + mov dword ptr [ecx+1], edx + + jmp eax + } +} + +// called when jumping to variable psxpc address +__declspec(naked,noreturn) void psxDispatcherReg() +{ + __asm { + //s_pDispatchBlock = PSX_GETBLOCK(psxRegs.pc); + mov edx, psxRegs.pc + mov ecx, edx + } + + __asm { + shr edx, 14 + and edx, 0xfffffffc + add edx, psxRecLUT + mov edx, dword ptr [edx] + + mov eax, ecx + and eax, 0xfffc + // edx += 2*eax + shl eax, 1 + add edx, eax + + // check if startpc == psxRegs.pc + mov eax, ecx + cmp eax, dword ptr [edx+BLOCKTYPE_STARTPC] + jne recomp + + mov eax, dword ptr [edx] + } + +#ifdef _DEBUG + __asm mov g_temp, eax + assert( g_temp ); +#endif + + __asm { + //and eax, 0x0fffffff + shl eax,4 + jmp eax // fnptr + +recomp: + sub esp, 8 + mov dword ptr [esp+4], edx + mov dword ptr [esp], ecx + call psxRecRecompile + mov edx, dword ptr [esp+4] + add esp, 8 + + mov eax, dword ptr [edx] + //and eax, 0x0fffffff + shl eax,4 + jmp eax // fnptr + } +} + +#else // _MSC_VER +// Linux uses an assembly version of these routines. +#ifdef __LINUX__ +extern "C" { +#endif +void psxDispatcher(); +void psxDispatcherClear(); +void psxDispatcherReg(); +#ifdef __LINUX__ +} +#endif + +#endif // _MSC_VER + +static void recClear(u32 Addr, u32 Size) +{ + u32 i; + for(i = 0; i < Size; ++i, Addr+=4) { + PSXREC_CLEARM(Addr); + } +} + +#define IOP_MIN_BLOCK_BYTES 15 + +void rpsxMemConstClear(u32 mem) +{ + // NOTE! This assumes recLUT never changes its mapping + if( !psxRecLUT[mem>>16] ) + return; + + CMP32ItoM((uptr)PSX_GETBLOCK(mem), 0); + j8Ptr[6] = JE8(0); + + _callFunctionArg1((uptr)psxRecClearMem, MEM_CONSTTAG, (uptr)PSX_GETBLOCK(mem)); + x86SetJ8(j8Ptr[6]); +} + +void psxRecClearMem(BASEBLOCK* p) +{ + BASEBLOCKEX* pexblock; + BASEBLOCK* pstart; + int lastdelay; + + assert( p != NULL ); + + if( p->uType & BLOCKTYPE_DELAYSLOT ) { + psxRecClearMem(p-1); + if( p->GetFnptr() == 0 ) + return; + } + + assert( p->GetFnptr() != 0 ); + assert( p->startpc ); + + x86Ptr = (u8*)p->GetFnptr(); + + // there is a small problem: mem can be ored with 0xa<<28 or 0x8<<28, and don't know which + MOV32ItoR(EDX, p->startpc); + assert( (uptr)x86Ptr <= 0xffffffff ); + PUSH32I((uptr)x86Ptr); + JMP32((uptr)psxDispatcherClear - ( (uptr)x86Ptr + 5 )); + assert( x86Ptr == (u8*)p->GetFnptr() + IOP_MIN_BLOCK_BYTES ); + + pstart = PSX_GETBLOCK(p->startpc); + pexblock = PSX_GETBLOCKEX(pstart); + assert( pexblock->startpc == pstart->startpc ); + + // don't delete if last is delay + lastdelay = pexblock->size; + if( pstart[pexblock->size-1].uType & BLOCKTYPE_DELAYSLOT ) { + assert( pstart[pexblock->size-1].GetFnptr() != pstart->GetFnptr() ); + if( pstart[pexblock->size-1].GetFnptr() != 0 ) { + pstart[pexblock->size-1].uType = 0; + --lastdelay; + } + } + + memset(pstart, 0, lastdelay*sizeof(BASEBLOCK)); + + RemoveBaseBlockEx(pexblock, 1); + pexblock->size = 0; + pexblock->startpc = 0; +} + +void psxSetBranchReg(u32 reg) +{ + psxbranch = 1; + + if( reg != 0xffffffff ) { + _allocX86reg(ESI, X86TYPE_PCWRITEBACK, 0, MODE_WRITE); + _psxMoveGPRtoR(ESI, reg); + + psxRecompileNextInstruction(1); + + if( x86regs[ESI].inuse ) { + assert( x86regs[ESI].type == X86TYPE_PCWRITEBACK ); + MOV32RtoM((uptr)&psxRegs.pc, ESI); + x86regs[ESI].inuse = 0; + } + else { + MOV32MtoR(EAX, (uptr)&g_recWriteback); + MOV32RtoM((uptr)&psxRegs.pc, EAX); + } + } + + _psxFlushCall(FLUSH_EVERYTHING); + iPsxBranchTest(0xffffffff, 1); + + JMP32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 5 )); +} + +void psxSetBranchImm( u32 imm ) +{ + u32* ptr; + psxbranch = 1; + assert( imm ); + + // end the current block + MOV32ItoM( (uptr)&psxRegs.pc, imm ); + _psxFlushCall(FLUSH_EVERYTHING); + iPsxBranchTest(imm, imm <= psxpc); + + MOV32ItoR(EDX, 0); + ptr = (u32*)(x86Ptr-4); + *ptr = (uptr)JMP32((uptr)psxDispatcher - ( (uptr)x86Ptr + 5 )); +} + +//fixme : this is all a huge hack, we base the counter advancements on the average an opcode should take (wtf?) +// If that wasn't bad enough we have default values like 9/8 which will get cast to int later +// (yeah, that means all sync code couldn't have worked to beginn with) +// So for now these are new settings that work. +// (rama) + +static u32 psxScaleBlockCycles() +{ + return s_psxBlockCycles * (CHECK_IOP_CYCLERATE ? 2 : 1); +} + +static void iPsxBranchTest(u32 newpc, u32 cpuBranch) +{ + u32 blockCycles = psxScaleBlockCycles(); + + MOV32MtoR(ECX, (uptr)&psxRegs.cycle); + MOV32MtoR(EAX, (uptr)&psxCycleEE); + ADD32ItoR(ECX, blockCycles); + SUB32ItoR(EAX, blockCycles*8); + MOV32RtoM((uptr)&psxRegs.cycle, ECX); // update cycles + MOV32RtoM((uptr)&psxCycleEE, EAX); + + j8Ptr[2] = JG8( 0 ); // jump if psxCycleEE > 0 + + RET2(); // returns control to the EE + + // Continue onward with branching here: + x86SetJ8( j8Ptr[2] ); + + // check if should branch + SUB32MtoR(ECX, (uptr)&g_psxNextBranchCycle); + j8Ptr[0] = JS8( 0 ); + + CALLFunc((uptr)psxBranchTest); + + if( newpc != 0xffffffff ) + { + CMP32ItoM((uptr)&psxRegs.pc, newpc); + JNE32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 6 )); + } + + // Skip branch jump target here: + x86SetJ8( j8Ptr[0] ); +} + +static int *s_pCode; + +#if !defined(_MSC_VER) +static void checkcodefn() +{ + int pctemp; + +#ifdef _MSC_VER + __asm mov pctemp, eax; +#else + __asm__("movl %%eax, %0" : : "m"(pctemp) ); +#endif + SysPrintf("iop code changed! %x\n", pctemp); +} +#endif + +void rpsxSYSCALL() +{ + MOV32ItoM( (uptr)&psxRegs.code, psxRegs.code ); + MOV32ItoM((uptr)&psxRegs.pc, psxpc - 4); + _psxFlushCall(FLUSH_NODESTROY); + + _callFunctionArg2((uptr)psxException, MEM_CONSTTAG, MEM_CONSTTAG, 0x20, psxbranch==1); + + CMP32ItoM((uptr)&psxRegs.pc, psxpc-4); + j8Ptr[0] = JE8(0); + + ADD32ItoM((uptr)&psxRegs.cycle, psxScaleBlockCycles() ); + SUB32ItoM((uptr)&psxCycleEE, psxScaleBlockCycles()*8 ); + JMP32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 5 )); + + // jump target for skipping blockCycle updates + x86SetJ8(j8Ptr[0]); + + //if (!psxbranch) psxbranch = 2; +} + +void rpsxBREAK() +{ + MOV32ItoM( (uptr)&psxRegs.code, psxRegs.code ); + MOV32ItoM((uptr)&psxRegs.pc, psxpc - 4); + _psxFlushCall(FLUSH_NODESTROY); + + _callFunctionArg2((uptr)psxBREAK, MEM_CONSTTAG, MEM_CONSTTAG, 0x24, psxbranch==1); + + CMP32ItoM((uptr)&psxRegs.pc, psxpc-4); + j8Ptr[0] = JE8(0); + ADD32ItoM((uptr)&psxRegs.cycle, psxScaleBlockCycles() ); + SUB32ItoM((uptr)&psxCycleEE, psxScaleBlockCycles()*8 ); + JMP32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 5 )); + x86SetJ8(j8Ptr[0]); + + //if (!psxbranch) psxbranch = 2; +} + +u32 psxRecompileCodeSafe(u32 temppc) +{ + BASEBLOCK* pblock = PSX_GETBLOCK(temppc); + + if( pblock->GetFnptr() != 0 && pblock->startpc != s_pCurBlock->startpc ) { + if( psxpc == pblock->startpc ) + return 0; + } + + return 1; +} + +void psxRecompileNextInstruction(int delayslot) +{ + static u8 s_bFlushReg = 1; + + BASEBLOCK* pblock = PSX_GETBLOCK(psxpc); + + // need *ppblock != s_pCurBlock because of branches + if( pblock->GetFnptr() != 0 && pblock->startpc != s_pCurBlock->startpc ) { + + if( !delayslot && psxpc == pblock->startpc ) { + // code already in place, so jump to it and exit recomp + assert( PSX_GETBLOCKEX(pblock)->startpc == pblock->startpc ); + + _psxFlushCall(FLUSH_EVERYTHING); + MOV32ItoM((uptr)&psxRegs.pc, psxpc); + +// if( pexblock->pOldFnptr ) { +// // code already in place, so jump to it and exit recomp +// JMP32((uptr)pexblock->pOldFnptr - ((uptr)x86Ptr + 5)); +// branch = 3; +// return; +// } + + JMP32((uptr)pblock->GetFnptr() - ((uptr)x86Ptr + 5)); + psxbranch = 3; + return; + } + else { + + if( !(delayslot && pblock->startpc == psxpc) ) { + u8* oldX86 = x86Ptr; + //__Log("clear block %x\n", pblock->startpc); + psxRecClearMem(pblock); + x86Ptr = oldX86; + if( delayslot ) + SysPrintf("delay slot %x\n", psxpc); + } + } + } + + if( delayslot ) + pblock->uType = BLOCKTYPE_DELAYSLOT; + +#ifdef _DEBUG + MOV32ItoR(EAX, psxpc); +#endif + + s_pCode = (int *)PSXM( psxpc ); + assert(s_pCode); + + psxRegs.code = *(int *)s_pCode; + s_psxBlockCycles++; + psxpc += 4; + +//#ifdef _DEBUG +// CMP32ItoM((uptr)s_pCode, psxRegs.code); +// j8Ptr[0] = JE8(0); +// MOV32ItoR(EAX, psxpc); +// CALLFunc((uptr)checkcodefn); +// x86SetJ8( j8Ptr[ 0 ] ); +//#endif + + + g_pCurInstInfo++; + +#ifdef PCSX2_VM_COISSUE + assert( g_pCurInstInfo->info & EEINSTINFO_COREC ); +#endif + + g_iopCyclePenalty = 0; + rpsxBSC[ psxRegs.code >> 26 ](); + s_psxBlockCycles += g_iopCyclePenalty; + + if( !delayslot ) { + if( s_bFlushReg ) { + //_psxFlushUnusedConstReg(); + } + else s_bFlushReg = 1; + } + else s_bFlushReg = 1; + + _clearNeededX86regs(); +} + +static void recExecute() { + for (;;) R3000AExecute(); +} + +static s32 recExecuteBlock( s32 eeCycles ) +{ + psxBreak = 0; + psxCycleEE = eeCycles; + R3000AExecute(); + return psxBreak + psxCycleEE; +} + +#include "IopHw.h" + +void iDumpPsxRegisters(u32 startpc, u32 temp) +{ +// [TODO] fixme : thie code is broken and has no labels. Needs a rewrite to be useful. + +#if 0 + int i; + const char* pstr = temp ? "t" : ""; + + __Log("%spsxreg: %x %x ra:%x k0: %x %x\n", pstr, startpc, psxRegs.cycle, psxRegs.GPR.n.ra, psxRegs.GPR.n.k0, *(int*)PSXM(0x13c128)); + for(i = 0; i < 34; i+=2) __Log("%spsx%s: %x %x\n", pstr, disRNameGPR[i], psxRegs.GPR.r[i], psxRegs.GPR.r[i+1]); + __Log("%scycle: %x %x %x; counters %x %x\n", pstr, psxRegs.cycle, g_psxNextBranchCycle, EEsCycle, + psxNextsCounter, psxNextCounter); + + __Log("psxdma%d c%x b%x m%x t%x\n", 2, HW_DMA2_CHCR, HW_DMA2_BCR, HW_DMA2_MADR, HW_DMA2_TADR); + __Log("psxdma%d c%x b%x m%x\n", 3, HW_DMA3_CHCR, HW_DMA3_BCR, HW_DMA3_MADR); + __Log("psxdma%d c%x b%x m%x t%x\n", 4, HW_DMA4_CHCR, HW_DMA4_BCR, HW_DMA4_MADR, HW_DMA4_TADR); + __Log("psxdma%d c%x b%x m%x\n", 6, HW_DMA6_CHCR, HW_DMA6_BCR, HW_DMA6_MADR); + __Log("psxdma%d c%x b%x m%x\n", 7, HW_DMA7_CHCR, HW_DMA7_BCR, HW_DMA7_MADR); + __Log("psxdma%d c%x b%x m%x\n", 8, HW_DMA8_CHCR, HW_DMA8_BCR, HW_DMA8_MADR); + __Log("psxdma%d c%x b%x m%x t%x\n", 9, HW_DMA9_CHCR, HW_DMA9_BCR, HW_DMA9_MADR, HW_DMA9_TADR); + __Log("psxdma%d c%x b%x m%x\n", 10, HW_DMA10_CHCR, HW_DMA10_BCR, HW_DMA10_MADR); + __Log("psxdma%d c%x b%x m%x\n", 11, HW_DMA11_CHCR, HW_DMA11_BCR, HW_DMA11_MADR); + __Log("psxdma%d c%x b%x m%x\n", 12, HW_DMA12_CHCR, HW_DMA12_BCR, HW_DMA12_MADR); + for(i = 0; i < 7; ++i) + __Log("%scounter%d: mode %x count %I64x rate %x scycle %x target %I64x\n", pstr, i, psxCounters[i].mode, psxCounters[i].count, psxCounters[i].rate, psxCounters[i].sCycleT, psxCounters[i].target); +#endif +} + +void iDumpPsxRegisters(u32 startpc); + +#ifdef _DEBUG +static void printfn() +{ + static int lastrec = 0; + static int curcount = 0; + const int skip = 0; + + //*(int*)PSXM(0x27990) = 1; // enables cdvd bios output for scph10000 + + if( psxRegs.cycle == 0x113a1be5 ) { +// FILE* tempf = fopen("tempdmciop.txt", "wb"); +// fwrite(PSXM(0), 0x200000, 1, tempf); +// fclose(tempf); + //psxdump |= 2; + } + +// if( psxRegs.cycle == 0x114152d8 ) { +// psxRegs.GPR.n.s0 = 0x55000; +// } + + if( (psxdump&2) && lastrec != g_psxlastpc ) { + curcount++; + + if( curcount > skip ) { + iDumpPsxRegisters(g_psxlastpc, 1); + curcount = 0; + } + + lastrec = g_psxlastpc; + } +} +#endif + +void psxRecRecompile(u32 startpc) +{ + u32 i; + u32 branchTo; + u32 willbranch3 = 0; + u32* ptr; + +#ifdef _DEBUG + //psxdump |= 4; + if( psxdump & 4 ) + iDumpPsxRegisters(startpc, 0); +#endif + + assert( startpc ); + + // if recPtr reached the mem limit reset whole mem + if (((uptr)recPtr - (uptr)recMem) >= (RECMEM_SIZE - 0x10000)) { + DevCon::WriteLn("IOP Recompiler data reset"); + recResetIOP(); + } + + s_pCurBlock = PSX_GETBLOCK(startpc); + + if( s_pCurBlock->GetFnptr() ) { + // clear if already taken + assert( s_pCurBlock->startpc < startpc ); + psxRecClearMem(s_pCurBlock); + } + + if( s_pCurBlock->startpc == startpc ) { + s_pCurBlockEx = PSX_GETBLOCKEX(s_pCurBlock); + assert( s_pCurBlockEx->startpc == startpc ); + } + else { + s_pCurBlockEx = NULL; + for(i = 0; i < PSX_NUMBLOCKS; ++i) { + if( recBlocks[(i+s_nNextBlock)%PSX_NUMBLOCKS].size == 0 ) { + s_pCurBlockEx = recBlocks+(i+s_nNextBlock)%PSX_NUMBLOCKS; + s_nNextBlock = (i+s_nNextBlock+1)%PSX_NUMBLOCKS; + break; + } + } + + if( s_pCurBlockEx == NULL ) { + DevCon::WriteLn("IOP Recompiler data reset"); + recResetIOP(); + s_nNextBlock = 0; + s_pCurBlockEx = recBlocks; + } + + s_pCurBlockEx->startpc = startpc; + } + + x86SetPtr( recPtr ); + x86Align(16); + recPtr = x86Ptr; + + psxbranch = 0; + + s_pCurBlock->startpc = startpc; + s_pCurBlock->SetFnptr( (uptr)x86Ptr ); + s_psxBlockCycles = 0; + + // reset recomp state variables + psxpc = startpc; + s_saveConstGPRreg = 0; + g_psxHasConstReg = g_psxFlushedConstReg = 1; + + _initX86regs(); + +#ifdef _DEBUG + // for debugging purposes + MOV32ItoM((uptr)&g_psxlastpc, psxpc); + CALLFunc((uptr)printfn); +#endif + + // go until the next branch + i = startpc; + s_nEndBlock = 0xffffffff; + + while(1) { + BASEBLOCK* pblock = PSX_GETBLOCK(i); + if( pblock->GetFnptr() != 0 && pblock->startpc != s_pCurBlock->startpc ) { + + if( i == pblock->startpc ) { + // branch = 3 + willbranch3 = 1; + s_nEndBlock = i; + break; + } + } + + psxRegs.code = *(int *)PSXM(i); + + switch(psxRegs.code >> 26) { + case 0: // special + + if( _Funct_ == 8 || _Funct_ == 9 ) { // JR, JALR + s_nEndBlock = i + 8; + goto StartRecomp; + } + + break; + case 1: // regimm + + if( _Rt_ == 0 || _Rt_ == 1 || _Rt_ == 16 || _Rt_ == 17 ) { + + branchTo = _Imm_ * 4 + i + 4; + if( branchTo > startpc && branchTo < i ) s_nEndBlock = branchTo; + else s_nEndBlock = i+8; + + goto StartRecomp; + } + + break; + + case 2: // J + case 3: // JAL + s_nEndBlock = i + 8; + goto StartRecomp; + + // branches + case 4: case 5: case 6: case 7: + + branchTo = _Imm_ * 4 + i + 4; + if( branchTo > startpc && branchTo < i ) s_nEndBlock = branchTo; + else s_nEndBlock = i+8; + + goto StartRecomp; + } + + i += 4; + } + +StartRecomp: + + // rec info // + { + EEINST* pcur; + + if( s_nInstCacheSize < (s_nEndBlock-startpc)/4+1 ) { + free(s_pInstCache); + s_nInstCacheSize = (s_nEndBlock-startpc)/4+10; + s_pInstCache = (EEINST*)malloc(sizeof(EEINST)*s_nInstCacheSize); + assert( s_pInstCache != NULL ); + } + + pcur = s_pInstCache + (s_nEndBlock-startpc)/4; + _recClearInst(pcur); + pcur->info = 0; + + for(i = s_nEndBlock; i > startpc; i -= 4 ) { + psxRegs.code = *(int *)PSXM(i-4); + pcur[-1] = pcur[0]; + rpsxpropBSC(pcur-1, pcur); + pcur--; + } + } + +#ifdef _DEBUG + // dump code + for(i = 0; i < ARRAYSIZE(s_psxrecblocks); ++i) { + if( startpc == s_psxrecblocks[i] ) { + iIopDumpBlock(startpc, recPtr); + } + } + + if( (psxdump & 1) ) + iIopDumpBlock(startpc, recPtr); +#endif + + g_pCurInstInfo = s_pInstCache; + while (!psxbranch && psxpc < s_nEndBlock) { + psxRecompileNextInstruction(0); + } + +#ifdef _DEBUG + if( (psxdump & 1) ) + iIopDumpBlock(startpc, recPtr); +#endif + + assert( (psxpc-startpc)>>2 <= 0xffff ); + s_pCurBlockEx->size = (psxpc-startpc)>>2; + + for(i = 1; i < (u32)s_pCurBlockEx->size-1; ++i) { + s_pCurBlock[i].SetFnptr( s_pCurBlock->GetFnptr() ); + s_pCurBlock[i].startpc = s_pCurBlock->startpc; + } + + // don't overwrite if delay slot + if( i < (u32)s_pCurBlockEx->size && !(s_pCurBlock[i].uType & BLOCKTYPE_DELAYSLOT) ) { + s_pCurBlock[i].SetFnptr( s_pCurBlock->GetFnptr() ); + s_pCurBlock[i].startpc = s_pCurBlock->startpc; + } + + // set the block ptr + AddBaseBlockEx(s_pCurBlockEx, 1); + + if( !(psxpc&0x10000000) ) + g_psxMaxRecMem = std::max( (psxpc&~0xa0000000), g_psxMaxRecMem ); + + if( psxbranch == 2 ) { + _psxFlushCall(FLUSH_EVERYTHING); + + iPsxBranchTest(0xffffffff, 1); + + JMP32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 5 )); + } + else { + assert( psxbranch != 3 ); + if( psxbranch ) assert( !willbranch3 ); + else + { + ADD32ItoM((uptr)&psxRegs.cycle, psxScaleBlockCycles() ); + SUB32ItoM((uptr)&psxCycleEE, psxScaleBlockCycles()*8 ); + } + + if( willbranch3 ) { + BASEBLOCK* pblock = PSX_GETBLOCK(s_nEndBlock); + assert( psxpc == s_nEndBlock ); + _psxFlushCall(FLUSH_EVERYTHING); + MOV32ItoM((uptr)&psxRegs.pc, psxpc); + JMP32((uptr)pblock->GetFnptr() - ((uptr)x86Ptr + 5)); + psxbranch = 3; + } + else if( !psxbranch ) { + // didn't branch, but had to stop + MOV32ItoM( (uptr)&psxRegs.pc, psxpc ); + + _psxFlushCall(FLUSH_EVERYTHING); + + ptr = JMP32(0); + //JMP32((uptr)psxDispatcherReg - ( (uptr)x86Ptr + 5 )); + } + } + + assert( x86Ptr >= (u8*)s_pCurBlock->GetFnptr() + IOP_MIN_BLOCK_BYTES ); + assert( x86Ptr < recMem+RECMEM_SIZE ); + + recPtr = x86Ptr; + + assert( (g_psxHasConstReg&g_psxFlushedConstReg) == g_psxHasConstReg ); + + if( !psxbranch ) { + BASEBLOCK* pcurblock = s_pCurBlock; + u32 nEndBlock = s_nEndBlock; + s_pCurBlock = PSX_GETBLOCK(psxpc); + assert( ptr != NULL ); + + if( s_pCurBlock->startpc != psxpc ){ + psxRecRecompile(psxpc); + } + + // could have reset + if( pcurblock->startpc == startpc ) { + assert( pcurblock->GetFnptr() ); + assert( s_pCurBlock->startpc == nEndBlock ); + *ptr = (u32)((uptr)s_pCurBlock->GetFnptr() - ( (uptr)ptr + 4 )); + } + else { + psxRecRecompile(startpc); + assert( pcurblock->GetFnptr() != 0 ); + } + } + else + assert( s_pCurBlock->GetFnptr() != 0 ); +} + +R3000Acpu psxRec = { + recAlloc, + recResetIOP, + recExecute, + recExecuteBlock, + recClear, + recShutdown +}; + diff --git a/pcsx2/x86/iR3000A.h b/pcsx2/x86/iR3000A.h index 5fe1a61afb..b012c73cc4 100644 --- a/pcsx2/x86/iR3000A.h +++ b/pcsx2/x86/iR3000A.h @@ -1,141 +1,141 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef _R3000A_SUPERREC_ -#define _R3000A_SUPERREC_ - -#include "R3000A.h" -#include "iCore.h" -#include "BaseblockEx.h" - -// Cycle penalties for particularly slow instructions. -static const int psxInstCycles_Mult = 7; -static const int psxInstCycles_Div = 40; - -// Currently unused (iop mod incomplete) -static const int psxInstCycles_Peephole_Store = 0; -static const int psxInstCycles_Store = 0; -static const int psxInstCycles_Load = 0; - -// to be consistent with EE -#define PSX_HI XMMGPR_HI -#define PSX_LO XMMGPR_LO - -extern uptr *psxRecLUT; - -u8 _psxLoadWritesRs(u32 tempcode); -u8 _psxIsLoadStore(u32 tempcode); - -void _psxFlushAllUnused(); -int _psxFlushUnusedConstReg(); -void _psxFlushCachedRegs(); -void _psxFlushConstReg(int reg); -void _psxFlushConstRegs(); - -void _psxDeleteReg(int reg, int flush); -void _psxFlushCall(int flushtype); - -void _psxOnWriteReg(int reg); - -void _psxMoveGPRtoR(x86IntRegType to, int fromgpr); -void _psxMoveGPRtoM(u32 to, int fromgpr); -void _psxMoveGPRtoRm(x86IntRegType to, int fromgpr); - -void PSX_CHECK_SAVE_REG(int reg); - -extern u32 psxpc; // recompiler pc -extern int psxbranch; // set for branch -extern u32 g_iopCyclePenalty; - -void psxSaveBranchState(); -void psxLoadBranchState(); - -void psxSetBranchReg(u32 reg); -void psxSetBranchImm( u32 imm ); -void psxRecompileNextInstruction(int delayslot); -void psxRecClearMem(BASEBLOCK* p); - -//////////////////////////////////////////////////////////////////// -// IOP Constant Propagation Defines, Vars, and API - From here down! - -#define PSX_IS_CONST1(reg) ((reg)<32 && (g_psxHasConstReg&(1<<(reg)))) -#define PSX_IS_CONST2(reg1, reg2) ((g_psxHasConstReg&(1<<(reg1)))&&(g_psxHasConstReg&(1<<(reg2)))) -#define PSX_SET_CONST(reg) { \ - if( (reg) < 32 ) { \ - g_psxHasConstReg |= (1<<(reg)); \ - g_psxFlushedConstReg &= ~(1<<(reg)); \ - } \ -} - -#define PSX_DEL_CONST(reg) { \ - if( (reg) < 32 ) g_psxHasConstReg &= ~(1<<(reg)); \ -} - -extern u32 g_psxConstRegs[32]; -extern u32 g_psxHasConstReg, g_psxFlushedConstReg; - -typedef void (*R3000AFNPTR)(); -typedef void (*R3000AFNPTR_INFO)(int info); - -// -// non mmx/xmm version, slower -// -// rd = rs op rt -#define PSXRECOMPILE_CONSTCODE0(fn) \ -void rpsx##fn(void) \ -{ \ - psxRecompileCodeConst0(rpsx##fn##_const, rpsx##fn##_consts, rpsx##fn##_constt, rpsx##fn##_); \ -} - -// rt = rs op imm16 -#define PSXRECOMPILE_CONSTCODE1(fn) \ -void rpsx##fn(void) \ -{ \ - psxRecompileCodeConst1(rpsx##fn##_const, rpsx##fn##_); \ -} - -// rd = rt op sa -#define PSXRECOMPILE_CONSTCODE2(fn) \ -void rpsx##fn(void) \ -{ \ - psxRecompileCodeConst2(rpsx##fn##_const, rpsx##fn##_); \ -} - -// [lo,hi] = rt op rs -#define PSXRECOMPILE_CONSTCODE3(fn, LOHI) \ -void rpsx##fn(void) \ -{ \ - psxRecompileCodeConst3(rpsx##fn##_const, rpsx##fn##_consts, rpsx##fn##_constt, rpsx##fn##_, LOHI); \ -} - -#define PSXRECOMPILE_CONSTCODE3_PENALTY(fn, LOHI, cycles) \ -void rpsx##fn(void) \ -{ \ - psxRecompileCodeConst3(rpsx##fn##_const, rpsx##fn##_consts, rpsx##fn##_constt, rpsx##fn##_, LOHI); \ - g_iopCyclePenalty = cycles; \ -} - -// rd = rs op rt -void psxRecompileCodeConst0(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode, R3000AFNPTR_INFO consttcode, R3000AFNPTR_INFO noconstcode); -// rt = rs op imm16 -void psxRecompileCodeConst1(R3000AFNPTR constcode, R3000AFNPTR_INFO noconstcode); -// rd = rt op sa -void psxRecompileCodeConst2(R3000AFNPTR constcode, R3000AFNPTR_INFO noconstcode); -// [lo,hi] = rt op rs -void psxRecompileCodeConst3(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode, R3000AFNPTR_INFO consttcode, R3000AFNPTR_INFO noconstcode, int LOHI); - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef _R3000A_SUPERREC_ +#define _R3000A_SUPERREC_ + +#include "R3000A.h" +#include "iCore.h" +#include "BaseblockEx.h" + +// Cycle penalties for particularly slow instructions. +static const int psxInstCycles_Mult = 7; +static const int psxInstCycles_Div = 40; + +// Currently unused (iop mod incomplete) +static const int psxInstCycles_Peephole_Store = 0; +static const int psxInstCycles_Store = 0; +static const int psxInstCycles_Load = 0; + +// to be consistent with EE +#define PSX_HI XMMGPR_HI +#define PSX_LO XMMGPR_LO + +extern uptr *psxRecLUT; + +u8 _psxLoadWritesRs(u32 tempcode); +u8 _psxIsLoadStore(u32 tempcode); + +void _psxFlushAllUnused(); +int _psxFlushUnusedConstReg(); +void _psxFlushCachedRegs(); +void _psxFlushConstReg(int reg); +void _psxFlushConstRegs(); + +void _psxDeleteReg(int reg, int flush); +void _psxFlushCall(int flushtype); + +void _psxOnWriteReg(int reg); + +void _psxMoveGPRtoR(x86IntRegType to, int fromgpr); +void _psxMoveGPRtoM(u32 to, int fromgpr); +void _psxMoveGPRtoRm(x86IntRegType to, int fromgpr); + +void PSX_CHECK_SAVE_REG(int reg); + +extern u32 psxpc; // recompiler pc +extern int psxbranch; // set for branch +extern u32 g_iopCyclePenalty; + +void psxSaveBranchState(); +void psxLoadBranchState(); + +void psxSetBranchReg(u32 reg); +void psxSetBranchImm( u32 imm ); +void psxRecompileNextInstruction(int delayslot); +void psxRecClearMem(BASEBLOCK* p); + +//////////////////////////////////////////////////////////////////// +// IOP Constant Propagation Defines, Vars, and API - From here down! + +#define PSX_IS_CONST1(reg) ((reg)<32 && (g_psxHasConstReg&(1<<(reg)))) +#define PSX_IS_CONST2(reg1, reg2) ((g_psxHasConstReg&(1<<(reg1)))&&(g_psxHasConstReg&(1<<(reg2)))) +#define PSX_SET_CONST(reg) { \ + if( (reg) < 32 ) { \ + g_psxHasConstReg |= (1<<(reg)); \ + g_psxFlushedConstReg &= ~(1<<(reg)); \ + } \ +} + +#define PSX_DEL_CONST(reg) { \ + if( (reg) < 32 ) g_psxHasConstReg &= ~(1<<(reg)); \ +} + +extern u32 g_psxConstRegs[32]; +extern u32 g_psxHasConstReg, g_psxFlushedConstReg; + +typedef void (*R3000AFNPTR)(); +typedef void (*R3000AFNPTR_INFO)(int info); + +// +// non mmx/xmm version, slower +// +// rd = rs op rt +#define PSXRECOMPILE_CONSTCODE0(fn) \ +void rpsx##fn(void) \ +{ \ + psxRecompileCodeConst0(rpsx##fn##_const, rpsx##fn##_consts, rpsx##fn##_constt, rpsx##fn##_); \ +} + +// rt = rs op imm16 +#define PSXRECOMPILE_CONSTCODE1(fn) \ +void rpsx##fn(void) \ +{ \ + psxRecompileCodeConst1(rpsx##fn##_const, rpsx##fn##_); \ +} + +// rd = rt op sa +#define PSXRECOMPILE_CONSTCODE2(fn) \ +void rpsx##fn(void) \ +{ \ + psxRecompileCodeConst2(rpsx##fn##_const, rpsx##fn##_); \ +} + +// [lo,hi] = rt op rs +#define PSXRECOMPILE_CONSTCODE3(fn, LOHI) \ +void rpsx##fn(void) \ +{ \ + psxRecompileCodeConst3(rpsx##fn##_const, rpsx##fn##_consts, rpsx##fn##_constt, rpsx##fn##_, LOHI); \ +} + +#define PSXRECOMPILE_CONSTCODE3_PENALTY(fn, LOHI, cycles) \ +void rpsx##fn(void) \ +{ \ + psxRecompileCodeConst3(rpsx##fn##_const, rpsx##fn##_consts, rpsx##fn##_constt, rpsx##fn##_, LOHI); \ + g_iopCyclePenalty = cycles; \ +} + +// rd = rs op rt +void psxRecompileCodeConst0(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode, R3000AFNPTR_INFO consttcode, R3000AFNPTR_INFO noconstcode); +// rt = rs op imm16 +void psxRecompileCodeConst1(R3000AFNPTR constcode, R3000AFNPTR_INFO noconstcode); +// rd = rt op sa +void psxRecompileCodeConst2(R3000AFNPTR constcode, R3000AFNPTR_INFO noconstcode); +// [lo,hi] = rt op rs +void psxRecompileCodeConst3(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode, R3000AFNPTR_INFO consttcode, R3000AFNPTR_INFO noconstcode, int LOHI); + +#endif diff --git a/pcsx2/x86/iR3000Atables.cpp b/pcsx2/x86/iR3000Atables.cpp index d6f49b4ae2..fef6d4ab27 100644 --- a/pcsx2/x86/iR3000Atables.cpp +++ b/pcsx2/x86/iR3000Atables.cpp @@ -1,2030 +1,2030 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" -#include - -#include "PsxCommon.h" -#include "ix86/ix86.h" -#include "iR3000A.h" -#include "IopMem.h" -#include "IopDma.h" - -extern int g_psxWriteOk; -extern u32 g_psxMaxRecMem; - -// R3000A instruction implementation -#define REC_FUNC(f) \ -static void rpsx##f() { \ - MOV32ItoM((uptr)&psxRegs.code, (u32)psxRegs.code); \ - _psxFlushCall(FLUSH_EVERYTHING); \ - CALLFunc((uptr)psx##f); \ - PSX_DEL_CONST(_Rt_); \ -/* branch = 2; */\ -} - -extern void psxLWL(); -extern void psxLWR(); -extern void psxSWL(); -extern void psxSWR(); - -//// -void rpsxADDIU_const() -{ - g_psxConstRegs[_Rt_] = g_psxConstRegs[_Rs_] + _Imm_; -} - -// adds a constant to sreg and puts into dreg -void rpsxADDconst(int dreg, int sreg, u32 off, int info) -{ - if (sreg) { - if (sreg == dreg) { - ADD32ItoM((uptr)&psxRegs.GPR.r[dreg], off); - } else { - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[sreg]); - if (off) ADD32ItoR(EAX, off); - MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], EAX); - } - } - else { - MOV32ItoM((uptr)&psxRegs.GPR.r[dreg], off); - } -} - -void rpsxADDIU_(int info) -{ - // Rt = Rs + Im - if (!_Rt_) return; - rpsxADDconst(_Rt_, _Rs_, _Imm_, info); -} - -PSXRECOMPILE_CONSTCODE1(ADDIU); - -void rpsxADDI() { rpsxADDIU(); } - -//// SLTI -void rpsxSLTI_const() -{ - g_psxConstRegs[_Rt_] = *(int*)&g_psxConstRegs[_Rs_] < _Imm_; -} - -void rpsxSLTconst(int info, int dreg, int sreg, int imm) -{ - XOR32RtoR(EAX, EAX); - CMP32ItoM((uptr)&psxRegs.GPR.r[sreg], imm); - SETL8R(EAX); - MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], EAX); -} - -void rpsxSLTI_(int info) { rpsxSLTconst(info, _Rt_, _Rs_, _Imm_); } - -PSXRECOMPILE_CONSTCODE1(SLTI); - -//// SLTIU -void rpsxSLTIU_const() -{ - g_psxConstRegs[_Rt_] = g_psxConstRegs[_Rs_] < _ImmU_; -} - -void rpsxSLTUconst(int info, int dreg, int sreg, int imm) -{ - XOR32RtoR(EAX, EAX); - CMP32ItoM((uptr)&psxRegs.GPR.r[sreg], imm); - SETB8R(EAX); - MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], EAX); -} - -void rpsxSLTIU_(int info) { rpsxSLTUconst(info, _Rt_, _Rs_, (s32)_Imm_); } - -PSXRECOMPILE_CONSTCODE1(SLTIU); - -//// ANDI -void rpsxANDI_const() -{ - g_psxConstRegs[_Rt_] = g_psxConstRegs[_Rs_] & _ImmU_; -} - -void rpsxANDconst(int info, int dreg, int sreg, u32 imm) -{ - if (imm) { - if (sreg == dreg) { - AND32ItoM((uptr)&psxRegs.GPR.r[dreg], imm); - } else { - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[sreg]); - AND32ItoR(EAX, imm); - MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], EAX); - } - } else { - MOV32ItoM((uptr)&psxRegs.GPR.r[dreg], 0); - } -} - -void rpsxANDI_(int info) { rpsxANDconst(info, _Rt_, _Rs_, _ImmU_); } - -PSXRECOMPILE_CONSTCODE1(ANDI); - -//// ORI -void rpsxORI_const() -{ - g_psxConstRegs[_Rt_] = g_psxConstRegs[_Rs_] | _ImmU_; -} - -void rpsxORconst(int info, int dreg, int sreg, u32 imm) -{ - if (imm) { - if (sreg == dreg) { - OR32ItoM((uptr)&psxRegs.GPR.r[dreg], imm); - } - else { - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[sreg]); - OR32ItoR (EAX, imm); - MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], EAX); - } - } - else { - if( dreg != sreg ) { - MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[sreg]); - MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], ECX); - } - } -} - -void rpsxORI_(int info) { rpsxORconst(info, _Rt_, _Rs_, _ImmU_); } - -PSXRECOMPILE_CONSTCODE1(ORI); - -void rpsxXORI_const() -{ - g_psxConstRegs[_Rt_] = g_psxConstRegs[_Rs_] ^ _ImmU_; -} - -void rpsxXORconst(int info, int dreg, int sreg, u32 imm) -{ - if( imm == 0xffffffff ) { - if( dreg == sreg ) { - NOT32M((uptr)&psxRegs.GPR.r[dreg]); - } - else { - MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[sreg]); - NOT32R(ECX); - MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], ECX); - } - } - else if (imm) { - - if (sreg == dreg) { - XOR32ItoM((uptr)&psxRegs.GPR.r[dreg], imm); - } - else { - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[sreg]); - XOR32ItoR(EAX, imm); - MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], EAX); - } - } - else { - if( dreg != sreg ) { - MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[sreg]); - MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], ECX); - } - } -} - -void rpsxXORI_(int info) { rpsxXORconst(info, _Rt_, _Rs_, _ImmU_); } - -PSXRECOMPILE_CONSTCODE1(XORI); - -void rpsxLUI() -{ - if(!_Rt_) return; - _psxOnWriteReg(_Rt_); - _psxDeleteReg(_Rt_, 0); - PSX_SET_CONST(_Rt_); - g_psxConstRegs[_Rt_] = psxRegs.code << 16; -} - -void rpsxADDU_const() -{ - g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rs_] + g_psxConstRegs[_Rt_]; -} - -void rpsxADDU_consts(int info) { rpsxADDconst(_Rd_, _Rt_, g_psxConstRegs[_Rs_], info); } -void rpsxADDU_constt(int info) -{ - info |= PROCESS_EE_SET_S(EEREC_T); - rpsxADDconst(_Rd_, _Rs_, g_psxConstRegs[_Rt_], info); -} - -void rpsxADDU_(int info) -{ - if (_Rs_ && _Rt_) { - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); - ADD32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); - } else if (_Rs_) { - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); - } else if (_Rt_) { - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); - } else { - XOR32RtoR(EAX, EAX); - } - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); -} - -PSXRECOMPILE_CONSTCODE0(ADDU); - -void rpsxADD() { rpsxADDU(); } - - -void rpsxSUBU_const() -{ - g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rs_] - g_psxConstRegs[_Rt_]; -} - -void rpsxSUBU_consts(int info) -{ - MOV32ItoR(EAX, g_psxConstRegs[_Rs_]); - SUB32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); -} - -void rpsxSUBU_constt(int info) { rpsxADDconst(_Rd_, _Rs_, -(int)g_psxConstRegs[_Rt_], info); } - -void rpsxSUBU_(int info) -{ - // Rd = Rs - Rt - if (!_Rd_) return; - - if( _Rd_ == _Rs_ ) { - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); - SUB32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); - } - else { - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); - SUB32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); - } -} - -PSXRECOMPILE_CONSTCODE0(SUBU); - -void rpsxSUB() { rpsxSUBU(); } - -void rpsxLogicalOp(int info, int op) -{ - if( _Rd_ == _Rs_ || _Rd_ == _Rt_ ) { - int vreg = _Rd_ == _Rs_ ? _Rt_ : _Rs_; - MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[vreg]); - LogicalOp32RtoM((uptr)&psxRegs.GPR.r[_Rd_], ECX, op); - if( op == 3 ) - NOT32M((uptr)&psxRegs.GPR.r[_Rd_]); - } - else { - MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]); - LogicalOp32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rt_], op); - if( op == 3 ) - NOT32R(ECX); - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], ECX); - } -} - -void rpsxAND_const() -{ - g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rs_] & g_psxConstRegs[_Rt_]; -} - -void rpsxAND_consts(int info) { rpsxANDconst(info, _Rd_, _Rt_, g_psxConstRegs[_Rs_]); } -void rpsxAND_constt(int info) { rpsxANDconst(info, _Rd_, _Rs_, g_psxConstRegs[_Rt_]); } -void rpsxAND_(int info) { rpsxLogicalOp(info, 0); } - -PSXRECOMPILE_CONSTCODE0(AND); - -void rpsxOR_const() -{ - g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rs_] | g_psxConstRegs[_Rt_]; -} - -void rpsxOR_consts(int info) { rpsxORconst(info, _Rd_, _Rt_, g_psxConstRegs[_Rs_]); } -void rpsxOR_constt(int info) { rpsxORconst(info, _Rd_, _Rs_, g_psxConstRegs[_Rt_]); } -void rpsxOR_(int info) { rpsxLogicalOp(info, 1); } - -PSXRECOMPILE_CONSTCODE0(OR); - -//// XOR -void rpsxXOR_const() -{ - g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rs_] ^ g_psxConstRegs[_Rt_]; -} - -void rpsxXOR_consts(int info) { rpsxXORconst(info, _Rd_, _Rt_, g_psxConstRegs[_Rs_]); } -void rpsxXOR_constt(int info) { rpsxXORconst(info, _Rd_, _Rs_, g_psxConstRegs[_Rt_]); } -void rpsxXOR_(int info) { rpsxLogicalOp(info, 2); } - -PSXRECOMPILE_CONSTCODE0(XOR); - -//// NOR -void rpsxNOR_const() -{ - g_psxConstRegs[_Rd_] = ~(g_psxConstRegs[_Rs_] | g_psxConstRegs[_Rt_]); -} - -void rpsxNORconst(int info, int dreg, int sreg, u32 imm) -{ - if( imm ) { - if( dreg == sreg ) { - OR32ItoM((uptr)&psxRegs.GPR.r[dreg], imm); - NOT32M((uptr)&psxRegs.GPR.r[dreg]); - } - else { - MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[sreg]); - OR32ItoR(ECX, imm); - NOT32R(ECX); - MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], ECX); - } - } - else { - if( dreg == sreg ) { - NOT32M((uptr)&psxRegs.GPR.r[dreg]); - } - else { - MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[sreg]); - NOT32R(ECX); - MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], ECX); - } - } -} - -void rpsxNOR_consts(int info) { rpsxNORconst(info, _Rd_, _Rt_, g_psxConstRegs[_Rs_]); } -void rpsxNOR_constt(int info) { rpsxNORconst(info, _Rd_, _Rs_, g_psxConstRegs[_Rt_]); } -void rpsxNOR_(int info) { rpsxLogicalOp(info, 3); } - -PSXRECOMPILE_CONSTCODE0(NOR); - -//// SLT -void rpsxSLT_const() -{ - g_psxConstRegs[_Rd_] = *(int*)&g_psxConstRegs[_Rs_] < *(int*)&g_psxConstRegs[_Rt_]; -} - -void rpsxSLT_consts(int info) -{ - XOR32RtoR(EAX, EAX); - CMP32ItoM((uptr)&psxRegs.GPR.r[_Rt_], g_psxConstRegs[_Rs_]); - SETG8R(EAX); - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); -} - -void rpsxSLT_constt(int info) { rpsxSLTconst(info, _Rd_, _Rs_, g_psxConstRegs[_Rt_]); } -void rpsxSLT_(int info) -{ - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); - CMP32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); - SETL8R (EAX); - AND32ItoR(EAX, 0xff); - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); -} - -PSXRECOMPILE_CONSTCODE0(SLT); - -//// SLTU -void rpsxSLTU_const() -{ - g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rs_] < g_psxConstRegs[_Rt_]; -} - -void rpsxSLTU_consts(int info) -{ - XOR32RtoR(EAX, EAX); - CMP32ItoM((uptr)&psxRegs.GPR.r[_Rt_], g_psxConstRegs[_Rs_]); - SETA8R(EAX); - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); -} - -void rpsxSLTU_constt(int info) { rpsxSLTUconst(info, _Rd_, _Rs_, g_psxConstRegs[_Rt_]); } -void rpsxSLTU_(int info) -{ - // Rd = Rs < Rt (unsigned) - if (!_Rd_) return; - - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); - CMP32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); - SBB32RtoR(EAX, EAX); - NEG32R (EAX); - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); -} - -PSXRECOMPILE_CONSTCODE0(SLTU); - -//// MULT -void rpsxMULT_const() -{ - u64 res = (s64)((s64)*(int*)&g_psxConstRegs[_Rs_] * (s64)*(int*)&g_psxConstRegs[_Rt_]); - - MOV32ItoM((uptr)&psxRegs.GPR.n.hi, (u32)((res >> 32) & 0xffffffff)); - MOV32ItoM((uptr)&psxRegs.GPR.n.lo, (u32)(res & 0xffffffff)); -} - -void rpsxMULTsuperconst(int info, int sreg, int imm, int sign) -{ - // Lo/Hi = Rs * Rt (signed) - MOV32ItoR(EAX, imm); - if( sign ) IMUL32M ((uptr)&psxRegs.GPR.r[sreg]); - else MUL32M ((uptr)&psxRegs.GPR.r[sreg]); - MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); - MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EDX); -} - -void rpsxMULTsuper(int info, int sign) -{ - // Lo/Hi = Rs * Rt (signed) - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); - if( sign ) IMUL32M ((uptr)&psxRegs.GPR.r[_Rt_]); - else MUL32M ((uptr)&psxRegs.GPR.r[_Rt_]); - MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); - MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EDX); -} - -void rpsxMULT_consts(int info) { rpsxMULTsuperconst(info, _Rt_, g_psxConstRegs[_Rs_], 1); } -void rpsxMULT_constt(int info) { rpsxMULTsuperconst(info, _Rs_, g_psxConstRegs[_Rt_], 1); } -void rpsxMULT_(int info) { rpsxMULTsuper(info, 1); } - -PSXRECOMPILE_CONSTCODE3_PENALTY(MULT, 1, psxInstCycles_Mult); - -//// MULTU -void rpsxMULTU_const() -{ - u64 res = (u64)((u64)g_psxConstRegs[_Rs_] * (u64)g_psxConstRegs[_Rt_]); - - MOV32ItoM((uptr)&psxRegs.GPR.n.hi, (u32)((res >> 32) & 0xffffffff)); - MOV32ItoM((uptr)&psxRegs.GPR.n.lo, (u32)(res & 0xffffffff)); -} - -void rpsxMULTU_consts(int info) { rpsxMULTsuperconst(info, _Rt_, g_psxConstRegs[_Rs_], 0); } -void rpsxMULTU_constt(int info) { rpsxMULTsuperconst(info, _Rs_, g_psxConstRegs[_Rt_], 0); } -void rpsxMULTU_(int info) { rpsxMULTsuper(info, 0); } - -PSXRECOMPILE_CONSTCODE3_PENALTY(MULTU, 1, psxInstCycles_Mult); - -//// DIV -void rpsxDIV_const() -{ - u32 lo, hi; - - if (g_psxConstRegs[_Rt_] != 0) { - lo = *(int*)&g_psxConstRegs[_Rs_] / *(int*)&g_psxConstRegs[_Rt_]; - hi = *(int*)&g_psxConstRegs[_Rs_] % *(int*)&g_psxConstRegs[_Rt_]; - MOV32ItoM((uptr)&psxRegs.GPR.n.hi, hi); - MOV32ItoM((uptr)&psxRegs.GPR.n.lo, lo); - } -} - -void rpsxDIVsuperconsts(int info, int sign) -{ - u32 imm = g_psxConstRegs[_Rs_]; - - if( imm ) { - // Lo/Hi = Rs / Rt (signed) - MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rt_]); - CMP32ItoR(ECX, 0); - j8Ptr[0] = JE8(0); - MOV32ItoR(EAX, imm); - - - if( sign ) { - CDQ(); - IDIV32R (ECX); - } - else { - XOR32RtoR( EDX, EDX ); - DIV32R(ECX); - } - - - MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); - MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EDX); - x86SetJ8(j8Ptr[0]); - } - else { - XOR32RtoR(EAX, EAX); - MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EAX); - MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); - } -} - -void rpsxDIVsuperconstt(int info, int sign) -{ - u32 imm = g_psxConstRegs[_Rt_]; - - if( imm ) { - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); - MOV32ItoR(ECX, imm); - //CDQ(); - - if( sign ) { - CDQ(); - IDIV32R (ECX); - } - else { - XOR32RtoR( EDX, EDX ); - DIV32R(ECX); - } - - - MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); - MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EDX); - } -} - -void rpsxDIVsuper(int info, int sign) -{ - // Lo/Hi = Rs / Rt (signed) - MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rt_]); - CMP32ItoR(ECX, 0); - j8Ptr[0] = JE8(0); - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); - - if( sign ) { - CDQ(); - IDIV32R (ECX); - } - else { - XOR32RtoR( EDX, EDX ); - DIV32R(ECX); - } - - MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); - MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EDX); - x86SetJ8(j8Ptr[0]); -} - -void rpsxDIV_consts(int info) { rpsxDIVsuperconsts(info, 1); } -void rpsxDIV_constt(int info) { rpsxDIVsuperconstt(info, 1); } -void rpsxDIV_(int info) { rpsxDIVsuper(info, 1); } - -PSXRECOMPILE_CONSTCODE3_PENALTY(DIV, 1, psxInstCycles_Div); - -//// DIVU -void rpsxDIVU_const() -{ - u32 lo, hi; - - if (g_psxConstRegs[_Rt_] != 0) { - lo = g_psxConstRegs[_Rs_] / g_psxConstRegs[_Rt_]; - hi = g_psxConstRegs[_Rs_] % g_psxConstRegs[_Rt_]; - MOV32ItoM((uptr)&psxRegs.GPR.n.hi, hi); - MOV32ItoM((uptr)&psxRegs.GPR.n.lo, lo); - } -} - -void rpsxDIVU_consts(int info) { rpsxDIVsuperconsts(info, 0); } -void rpsxDIVU_constt(int info) { rpsxDIVsuperconstt(info, 0); } -void rpsxDIVU_(int info) { rpsxDIVsuper(info, 0); } - -PSXRECOMPILE_CONSTCODE3_PENALTY(DIVU, 1, psxInstCycles_Div); - -//// LoadStores -#ifdef PCSX2_VIRTUAL_MEM - -// VM load store functions (fastest) - -//#define REC_SLOWREAD -//#define REC_SLOWWRITE - -int _psxPrepareReg(int gprreg) -{ - return 0; -} - -static u32 s_nAddMemOffset = 0; - -static __forceinline void SET_HWLOC_R3000A() { - x86SetJ8(j8Ptr[0]); - SHR32ItoR(ECX, 3); - if( s_nAddMemOffset ) ADD32ItoR(ECX, s_nAddMemOffset); -} - -int rpsxSetMemLocation(int regs, int mmreg) -{ - s_nAddMemOffset = 0; - MOV32MtoR( ECX, (int)&psxRegs.GPR.r[ regs ] ); - - if ( _Imm_ != 0 ) ADD32ItoR( ECX, _Imm_ ); - - SHL32ItoR(ECX, 3); - j8Ptr[0] = JS8(0); - SHR32ItoR(ECX, 3); - AND32ItoR(ECX, 0x1fffff); // 2Mb - return 1; -} - -void recLoad32(u32 bit, u32 sign) -{ - int mmreg = -1; - -#ifdef REC_SLOWREAD - _psxFlushConstReg(_Rs_); -#else - if( PSX_IS_CONST1( _Rs_ ) ) { - // do const processing - int ineax = 0; - - _psxOnWriteReg(_Rt_); - mmreg = EAX; - - switch(bit) { - case 8: ineax = psxRecMemConstRead8(mmreg, g_psxConstRegs[_Rs_]+_Imm_, sign); break; - case 16: - assert( (g_psxConstRegs[_Rs_]+_Imm_) % 2 == 0 ); - ineax = psxRecMemConstRead16(mmreg, g_psxConstRegs[_Rs_]+_Imm_, sign); - break; - case 32: - assert( (g_psxConstRegs[_Rs_]+_Imm_) % 4 == 0 ); - ineax = psxRecMemConstRead32(mmreg, g_psxConstRegs[_Rs_]+_Imm_); - break; - } - - if( _Rt_ ) MOV32RtoM( (int)&psxRegs.GPR.r[ _Rt_ ], EAX ); - } - else -#endif - { - int dohw; - int mmregs = _psxPrepareReg(_Rs_); - - _psxOnWriteReg(_Rt_); - _psxDeleteReg(_Rt_, 0); - - dohw = rpsxSetMemLocation(_Rs_, mmregs); - - switch(bit) { - case 8: - if( sign ) MOVSX32Rm8toROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset); - else MOVZX32Rm8toROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset); - break; - case 16: - if( sign ) MOVSX32Rm16toROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset); - else MOVZX32Rm16toROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset); - break; - case 32: - MOV32RmtoROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset); - break; - } - - if( dohw ) { - j8Ptr[1] = JMP8(0); - - SET_HWLOC_R3000A(); - - switch(bit) { - case 8: - CALLFunc( (int)psxRecMemRead8 ); - if( sign ) MOVSX32R8toR(EAX, EAX); - else MOVZX32R8toR(EAX, EAX); - break; - case 16: - CALLFunc( (int)psxRecMemRead16 ); - if( sign ) MOVSX32R16toR(EAX, EAX); - else MOVZX32R16toR(EAX, EAX); - break; - case 32: - CALLFunc( (int)psxRecMemRead32 ); - break; - } - - x86SetJ8(j8Ptr[1]); - } - - if( _Rt_ ) - MOV32RtoM( (int)&psxRegs.GPR.r[ _Rt_ ], EAX ); - } -} - -void rpsxLB() { recLoad32(8, 1); } -void rpsxLBU() { recLoad32(8, 0); } -void rpsxLH() { recLoad32(16, 1); } -void rpsxLHU() { recLoad32(16, 0); } -void rpsxLW() { recLoad32(32, 0); } - -extern void rpsxMemConstClear(u32 mem); - -// check if mem is executable, and clear it -__declspec(naked) void rpsxWriteMemClear() -{ - _asm { - mov edx, ecx - shr edx, 14 - and dl, 0xfc - add edx, psxRecLUT - test dword ptr [edx], 0xffffffff - jnz Clear32 - ret -Clear32: - // recLUT[mem>>16] + (mem&0xfffc) - mov edx, dword ptr [edx] - mov eax, ecx - and eax, 0xfffc - // edx += 2*eax - shl eax, 1 - add edx, eax - cmp dword ptr [edx], 0 - je ClearRet - sub esp, 4 - mov dword ptr [esp], edx - call psxRecClearMem - add esp, 4 -ClearRet: - ret - } -} - -extern u32 s_psxBlockCycles; -void recStore(int bit) -{ -#ifdef REC_SLOWWRITE - _psxFlushConstReg(_Rs_); -#else - if( PSX_IS_CONST1( _Rs_ ) ) { - u8* pjmpok; - u32 addr = g_psxConstRegs[_Rs_]+_Imm_; - int doclear = 0; - - if( !(addr & 0x10000000) ) { - // check g_psxWriteOk - CMP32ItoM((uptr)&g_psxWriteOk, 0); - pjmpok = JE8(0); - } - - switch(bit) { - case 8: - if( PSX_IS_CONST1(_Rt_) ) doclear = psxRecMemConstWrite8(addr, MEM_PSXCONSTTAG|(_Rt_<<16)); - else { - _psxMoveGPRtoR(EAX, _Rt_); - doclear = psxRecMemConstWrite8(addr, EAX); - } - - break; - - case 16: - assert( (addr)%2 == 0 ); - if( PSX_IS_CONST1(_Rt_) ) doclear = psxRecMemConstWrite16(addr, MEM_PSXCONSTTAG|(_Rt_<<16)); - else { - _psxMoveGPRtoR(EAX, _Rt_); - doclear = psxRecMemConstWrite16(addr, EAX); - } - - break; - - case 32: - assert( (addr)%4 == 0 ); - if( PSX_IS_CONST1(_Rt_) ) doclear = psxRecMemConstWrite32(addr, MEM_PSXCONSTTAG|(_Rt_<<16)); - else { - _psxMoveGPRtoR(EAX, _Rt_); - doclear = psxRecMemConstWrite32(addr, EAX); - } - - break; - } - - if( !(addr & 0x10000000) ) { - if( doclear ) rpsxMemConstClear((addr)&~3); - x86SetJ8(pjmpok); - } - } - else -#endif - { - int dohw; - int mmregs = _psxPrepareReg(_Rs_); - dohw = rpsxSetMemLocation(_Rs_, mmregs); - - CMP32ItoM((uptr)&g_psxWriteOk, 0); - u8* pjmpok = JE8(0); - - if( PSX_IS_CONST1( _Rt_ ) ) { - switch(bit) { - case 8: MOV8ItoRmOffset(ECX, g_psxConstRegs[_Rt_], PS2MEM_PSX_+s_nAddMemOffset); break; - case 16: MOV16ItoRmOffset(ECX, g_psxConstRegs[_Rt_], PS2MEM_PSX_+s_nAddMemOffset); break; - case 32: MOV32ItoRmOffset(ECX, g_psxConstRegs[_Rt_], PS2MEM_PSX_+s_nAddMemOffset); break; - } - } - else { - switch(bit) { - case 8: - MOV8MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); - MOV8RtoRmOffset(ECX, EAX, PS2MEM_PSX_+s_nAddMemOffset); - break; - - case 16: - MOV16MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); - MOV16RtoRmOffset(ECX, EAX, PS2MEM_PSX_+s_nAddMemOffset); - break; - - case 32: - MOV32MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); - MOV32RtoRmOffset(ECX, EAX, PS2MEM_PSX_+s_nAddMemOffset); - break; - } - } - - if( s_nAddMemOffset ) ADD32ItoR(ECX, s_nAddMemOffset); - CMP32MtoR(ECX, (uptr)&g_psxMaxRecMem); - - j8Ptr[1] = JAE8(0); - - if( bit < 32 ) AND8ItoR(ECX, 0xfc); - CALLFunc((u32)rpsxWriteMemClear); - - if( dohw ) { - j8Ptr[2] = JMP8(0); - - SET_HWLOC_R3000A(); - - if( PSX_IS_CONST1(_Rt_) ) { - switch(bit) { - case 8: MOV8ItoR(EAX, g_psxConstRegs[_Rt_]); break; - case 16: MOV16ItoR(EAX, g_psxConstRegs[_Rt_]); break; - case 32: MOV32ItoR(EAX, g_psxConstRegs[_Rt_]); break; - } - } - else { - switch(bit) { - case 8: MOV8MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); break; - case 16: MOV16MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); break; - case 32: MOV32MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); break; - } - } - - if( s_nAddMemOffset != 0 ) ADD32ItoR(ECX, s_nAddMemOffset); - - // some type of hardware write - switch(bit) { - case 8: CALLFunc( (int)psxRecMemWrite8 ); break; - case 16: CALLFunc( (int)psxRecMemWrite16 ); break; - case 32: CALLFunc( (int)psxRecMemWrite32 ); break; - } - - x86SetJ8(j8Ptr[2]); - } - - x86SetJ8(j8Ptr[1]); - x86SetJ8(pjmpok); - } -} - -void rpsxSB() { recStore(8); } -void rpsxSH() { recStore(16); } -void rpsxSW() { recStore(32); } - -REC_FUNC(LWL); -REC_FUNC(LWR); -REC_FUNC(SWL); -REC_FUNC(SWR); - -#else - -// TLB loadstore functions (slower -REC_FUNC(LWL); -REC_FUNC(LWR); -REC_FUNC(SWL); -REC_FUNC(SWR); - -static void rpsxLB() -{ - _psxDeleteReg(_Rs_, 1); - _psxOnWriteReg(_Rt_); - _psxDeleteReg(_Rt_, 0); - - MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); - if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); - _callFunctionArg1((uptr)psxMemRead8, X86ARG1|MEM_X86TAG, 0); - if (_Rt_) { - MOVSX32R8toR(EAX, EAX); - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); - } - PSX_DEL_CONST(_Rt_); -} - -static void rpsxLBU() -{ - _psxDeleteReg(_Rs_, 1); - _psxOnWriteReg(_Rt_); - _psxDeleteReg(_Rt_, 0); - - MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); - if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); - _callFunctionArg1((uptr)psxMemRead8, X86ARG1|MEM_X86TAG, 0); - if (_Rt_) { - MOVZX32R8toR(EAX, EAX); - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); - } - PSX_DEL_CONST(_Rt_); -} - -static void rpsxLH() -{ - _psxDeleteReg(_Rs_, 1); - _psxOnWriteReg(_Rt_); - _psxDeleteReg(_Rt_, 0); - - MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); - if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); - _callFunctionArg1((uptr)psxMemRead16, X86ARG1|MEM_X86TAG, 0); - if (_Rt_) { - MOVSX32R16toR(EAX, EAX); - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); - } - PSX_DEL_CONST(_Rt_); -} - -static void rpsxLHU() -{ - _psxDeleteReg(_Rs_, 1); - _psxOnWriteReg(_Rt_); - _psxDeleteReg(_Rt_, 0); - - MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); - if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); - _callFunctionArg1((uptr)psxMemRead16, X86ARG1|MEM_X86TAG, 0); - if (_Rt_) { - MOVZX32R16toR(EAX, EAX); - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); - } - PSX_DEL_CONST(_Rt_); -} - -static void rpsxLW() -{ - _psxDeleteReg(_Rs_, 1); - _psxOnWriteReg(_Rt_); - _psxDeleteReg(_Rt_, 0); - - _psxFlushCall(FLUSH_EVERYTHING); - MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); - if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); - -#ifndef TLB_DEBUG_MEM - TEST32ItoR(X86ARG1, 0x10000000); - j8Ptr[0] = JZ8(0); -#endif - - _callFunctionArg1((uptr)psxMemRead32, X86ARG1|MEM_X86TAG, 0); - if (_Rt_) { - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); - } -#ifndef TLB_DEBUG_MEM - j8Ptr[1] = JMP8(0); - x86SetJ8(j8Ptr[0]); - - // read from psM directly - AND32ItoR(X86ARG1, 0x1fffff); - ADD32ItoR(X86ARG1, (uptr)psxM); - - MOV32RmtoR( X86ARG1, X86ARG1 ); - MOV32RtoM( (uptr)&psxRegs.GPR.r[_Rt_], X86ARG1); - - x86SetJ8(j8Ptr[1]); -#endif - PSX_DEL_CONST(_Rt_); -} - -static void rpsxSB() -{ - _psxDeleteReg(_Rs_, 1); - _psxDeleteReg(_Rt_, 1); - - MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); - if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); - _callFunctionArg2((uptr)psxMemWrite8, X86ARG1|MEM_X86TAG, MEM_MEMORYTAG, 0, (uptr)&psxRegs.GPR.r[_Rt_]); -} - -static void rpsxSH() -{ - _psxDeleteReg(_Rs_, 1); - _psxDeleteReg(_Rt_, 1); - - MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); - if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); - _callFunctionArg2((uptr)psxMemWrite16, X86ARG1|MEM_X86TAG, MEM_MEMORYTAG, 0, (uptr)&psxRegs.GPR.r[_Rt_]); -} - -static void rpsxSW() -{ - _psxDeleteReg(_Rs_, 1); - _psxDeleteReg(_Rt_, 1); - - MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); - if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); - _callFunctionArg2((uptr)psxMemWrite32, X86ARG1|MEM_X86TAG, MEM_MEMORYTAG, 0, (uptr)&psxRegs.GPR.r[_Rt_]); -} - -#endif // end load store - -//// SLL -void rpsxSLL_const() -{ - g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rt_] << _Sa_; -} - -// shifttype: 0 - sll, 1 - srl, 2 - sra -void rpsxShiftConst(int info, int rdreg, int rtreg, int imm, int shifttype) -{ - imm &= 0x1f; - if (imm) { - if( rdreg == rtreg ) { - switch(shifttype) { - case 0: SHL32ItoM((uptr)&psxRegs.GPR.r[rdreg], imm); break; - case 1: SHR32ItoM((uptr)&psxRegs.GPR.r[rdreg], imm); break; - case 2: SAR32ItoM((uptr)&psxRegs.GPR.r[rdreg], imm); break; - } - } - else { - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[rtreg]); - switch(shifttype) { - case 0: SHL32ItoR(EAX, imm); break; - case 1: SHR32ItoR(EAX, imm); break; - case 2: SAR32ItoR(EAX, imm); break; - } - MOV32RtoM((uptr)&psxRegs.GPR.r[rdreg], EAX); - } - } - else { - if( rdreg != rtreg ) { - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[rtreg]); - MOV32RtoM((uptr)&psxRegs.GPR.r[rdreg], EAX); - } - } -} - -void rpsxSLL_(int info) { rpsxShiftConst(info, _Rd_, _Rt_, _Sa_, 0); } -PSXRECOMPILE_CONSTCODE2(SLL); - -//// SRL -void rpsxSRL_const() -{ - g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rt_] >> _Sa_; -} - -void rpsxSRL_(int info) { rpsxShiftConst(info, _Rd_, _Rt_, _Sa_, 1); } -PSXRECOMPILE_CONSTCODE2(SRL); - -//// SRA -void rpsxSRA_const() -{ - g_psxConstRegs[_Rd_] = *(int*)&g_psxConstRegs[_Rt_] >> _Sa_; -} - -void rpsxSRA_(int info) { rpsxShiftConst(info, _Rd_, _Rt_, _Sa_, 2); } -PSXRECOMPILE_CONSTCODE2(SRA); - -//// SLLV -void rpsxSLLV_const() -{ - g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rt_] << (g_psxConstRegs[_Rs_]&0x1f); -} - -void rpsxShiftVconsts(int info, int shifttype) -{ - rpsxShiftConst(info, _Rd_, _Rt_, g_psxConstRegs[_Rs_], shifttype); -} - -void rpsxShiftVconstt(int info, int shifttype) -{ - MOV32ItoR(EAX, g_psxConstRegs[_Rt_]); - MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]); - switch(shifttype) { - case 0: SHL32CLtoR(EAX); break; - case 1: SHR32CLtoR(EAX); break; - case 2: SAR32CLtoR(EAX); break; - } - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); -} - -void rpsxSLLV_consts(int info) { rpsxShiftVconsts(info, 0); } -void rpsxSLLV_constt(int info) { rpsxShiftVconstt(info, 0); } -void rpsxSLLV_(int info) -{ - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); - MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]); - SHL32CLtoR(EAX); - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); -} - -PSXRECOMPILE_CONSTCODE0(SLLV); - -//// SRLV -void rpsxSRLV_const() -{ - g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rt_] >> (g_psxConstRegs[_Rs_]&0x1f); -} - -void rpsxSRLV_consts(int info) { rpsxShiftVconsts(info, 1); } -void rpsxSRLV_constt(int info) { rpsxShiftVconstt(info, 1); } -void rpsxSRLV_(int info) -{ - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); - MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]); - SHR32CLtoR(EAX); - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); -} - -PSXRECOMPILE_CONSTCODE0(SRLV); - -//// SRAV -void rpsxSRAV_const() -{ - g_psxConstRegs[_Rd_] = *(int*)&g_psxConstRegs[_Rt_] >> (g_psxConstRegs[_Rs_]&0x1f); -} - -void rpsxSRAV_consts(int info) { rpsxShiftVconsts(info, 2); } -void rpsxSRAV_constt(int info) { rpsxShiftVconstt(info, 2); } -void rpsxSRAV_(int info) -{ - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); - MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]); - SAR32CLtoR(EAX); - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); -} - -PSXRECOMPILE_CONSTCODE0(SRAV); - -extern void rpsxSYSCALL(); -extern void rpsxBREAK(); - -void rpsxMFHI() -{ - if (!_Rd_) return; - - _psxOnWriteReg(_Rd_); - _psxDeleteReg(_Rd_, 0); - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.n.hi); - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); -} - -void rpsxMTHI() -{ - if( PSX_IS_CONST1(_Rs_) ) { - MOV32ItoM((uptr)&psxRegs.GPR.n.hi, g_psxConstRegs[_Rs_]); - } - else { - _psxDeleteReg(_Rs_, 1); - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); - MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EAX); - } -} - -void rpsxMFLO() -{ - if (!_Rd_) return; - - _psxOnWriteReg(_Rd_); - _psxDeleteReg(_Rd_, 0); - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.n.lo); - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); -} - -void rpsxMTLO() -{ - if( PSX_IS_CONST1(_Rs_) ) { - MOV32ItoM((uptr)&psxRegs.GPR.n.hi, g_psxConstRegs[_Rs_]); - } - else { - _psxDeleteReg(_Rs_, 1); - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); - MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); - } -} - -void rpsxJ() -{ - // j target - u32 newpc = _Target_ * 4 + (psxpc & 0xf0000000); - psxRecompileNextInstruction(1); - psxSetBranchImm(newpc); -} - -void rpsxJAL() -{ - u32 newpc = (_Target_ << 2) + ( psxpc & 0xf0000000 ); - _psxDeleteReg(31, 0); - PSX_SET_CONST(31); - g_psxConstRegs[31] = psxpc + 4; - - psxRecompileNextInstruction(1); - psxSetBranchImm(newpc); -} - -void rpsxJR() -{ - psxSetBranchReg(_Rs_); -} - -void rpsxJALR() -{ - // jalr Rs - _allocX86reg(ESI, X86TYPE_PCWRITEBACK, 0, MODE_WRITE); - _psxMoveGPRtoR(ESI, _Rs_); - - if ( _Rd_ ) - { - _psxDeleteReg(_Rd_, 0); - PSX_SET_CONST(_Rd_); - g_psxConstRegs[_Rd_] = psxpc + 4; - } - - psxRecompileNextInstruction(1); - - if( x86regs[ESI].inuse ) { - assert( x86regs[ESI].type == X86TYPE_PCWRITEBACK ); - MOV32RtoM((uptr)&psxRegs.pc, ESI); - x86regs[ESI].inuse = 0; - } - else { - MOV32MtoR(EAX, (uptr)&g_recWriteback); - MOV32RtoM((uptr)&psxRegs.pc, EAX); - } - - psxSetBranchReg(0xffffffff); -} - -//// BEQ -static void* s_pbranchjmp; -static u32 s_do32 = 0; - -#define JUMPVALID(pjmp) (( x86Ptr - (u8*)pjmp ) <= 0x80) - -void rpsxSetBranchEQ(int info, int process) -{ - if( process & PROCESS_CONSTS ) { - CMP32ItoM( (uptr)&psxRegs.GPR.r[ _Rt_ ], g_psxConstRegs[_Rs_] ); - if( s_do32 ) s_pbranchjmp = JNE32( 0 ); - else s_pbranchjmp = JNE8( 0 ); - } - else if( process & PROCESS_CONSTT ) { - CMP32ItoM( (uptr)&psxRegs.GPR.r[ _Rs_ ], g_psxConstRegs[_Rt_] ); - if( s_do32 ) s_pbranchjmp = JNE32( 0 ); - else s_pbranchjmp = JNE8( 0 ); - } - else { - MOV32MtoR( EAX, (uptr)&psxRegs.GPR.r[ _Rs_ ] ); - CMP32MtoR( EAX, (uptr)&psxRegs.GPR.r[ _Rt_ ] ); - if( s_do32 ) s_pbranchjmp = JNE32( 0 ); - else s_pbranchjmp = JNE8( 0 ); - } -} - -void rpsxBEQ_const() -{ - u32 branchTo; - - if( g_psxConstRegs[_Rs_] == g_psxConstRegs[_Rt_] ) - branchTo = ((s32)_Imm_ * 4) + psxpc; - else - branchTo = psxpc+4; - - psxRecompileNextInstruction(1); - psxSetBranchImm( branchTo ); -} - -void rpsxBEQ_process(int info, int process) -{ - u32 branchTo = ((s32)_Imm_ * 4) + psxpc; - - if ( _Rs_ == _Rt_ ) - { - psxRecompileNextInstruction(1); - psxSetBranchImm( branchTo ); - } - else - { - _psxFlushAllUnused(); - u8* prevx86 = x86Ptr; - s_do32 = 0; - psxSaveBranchState(); - - rpsxSetBranchEQ(info, process); - - psxRecompileNextInstruction(1); - psxSetBranchImm(branchTo); - - if( JUMPVALID(s_pbranchjmp) ) { - x86SetJ8A( (u8*)s_pbranchjmp ); - } - else { - x86Ptr = prevx86; - s_do32 = 1; - psxpc -= 4; - psxRegs.code = *(u32*)PSXM( psxpc - 4 ); - psxLoadBranchState(); - rpsxSetBranchEQ(info, process); - psxRecompileNextInstruction(1); - psxSetBranchImm(branchTo); - x86SetJ32A( (u32*)s_pbranchjmp ); - } - - // recopy the next inst - psxpc -= 4; - psxLoadBranchState(); - psxRecompileNextInstruction(1); - - psxSetBranchImm(psxpc); - } -} - -void rpsxBEQ_(int info) { rpsxBEQ_process(info, 0); } -void rpsxBEQ_consts(int info) { rpsxBEQ_process(info, PROCESS_CONSTS); } -void rpsxBEQ_constt(int info) { rpsxBEQ_process(info, PROCESS_CONSTT); } -PSXRECOMPILE_CONSTCODE3(BEQ, 0); - -//// BNE -void rpsxBNE_const() -{ - u32 branchTo; - - if( g_psxConstRegs[_Rs_] != g_psxConstRegs[_Rt_] ) - branchTo = ((s32)_Imm_ * 4) + psxpc; - else - branchTo = psxpc+4; - - psxRecompileNextInstruction(1); - psxSetBranchImm( branchTo ); -} - -void rpsxBNE_process(int info, int process) -{ - u32 branchTo = ((s32)_Imm_ * 4) + psxpc; - - if ( _Rs_ == _Rt_ ) - { - psxRecompileNextInstruction(1); - psxSetBranchImm(psxpc); - return; - } - - _psxFlushAllUnused(); - u8* prevx86 = x86Ptr; - s_do32 = 0; - rpsxSetBranchEQ(info, process); - - psxSaveBranchState(); - psxRecompileNextInstruction(1); - psxSetBranchImm(psxpc); - - if( JUMPVALID(s_pbranchjmp) ) { - x86SetJ8A( (u8*)s_pbranchjmp ); - } - else { - x86Ptr = prevx86; - s_do32 = 1; - psxpc -= 4; - psxRegs.code = *(u32*)PSXM( psxpc - 4 ); - psxLoadBranchState(); - rpsxSetBranchEQ(info, process); - psxRecompileNextInstruction(1); - psxSetBranchImm(psxpc); - x86SetJ32A( (u32*)s_pbranchjmp ); - } - - // recopy the next inst - psxpc -= 4; - psxLoadBranchState(); - psxRecompileNextInstruction(1); - - psxSetBranchImm(branchTo); -} - -void rpsxBNE_(int info) { rpsxBNE_process(info, 0); } -void rpsxBNE_consts(int info) { rpsxBNE_process(info, PROCESS_CONSTS); } -void rpsxBNE_constt(int info) { rpsxBNE_process(info, PROCESS_CONSTT); } -PSXRECOMPILE_CONSTCODE3(BNE, 0); - -//// BLTZ -void rpsxBLTZ() -{ - // Branch if Rs < 0 - u32 branchTo = (s32)_Imm_ * 4 + psxpc; - - _psxFlushAllUnused(); - - if( PSX_IS_CONST1(_Rs_) ) { - if( (int)g_psxConstRegs[_Rs_] >= 0 ) - branchTo = psxpc+4; - - psxRecompileNextInstruction(1); - psxSetBranchImm( branchTo ); - return; - } - - CMP32ItoM((uptr)&psxRegs.GPR.r[_Rs_], 0); - u8* prevx86 = x86Ptr; - u8* pjmp = JL8(0); - - psxSaveBranchState(); - psxRecompileNextInstruction(1); - - psxSetBranchImm(psxpc); - - if( JUMPVALID(pjmp) ) { - x86SetJ8A( pjmp ); - } - else { - x86Ptr = prevx86; - psxpc -= 4; - psxRegs.code = *(u32*)PSXM( psxpc - 4 ); - psxLoadBranchState(); - u32* pjmp32 = JL32(0); - psxRecompileNextInstruction(1); - psxSetBranchImm(psxpc); - x86SetJ32A( pjmp32 ); - } - - // recopy the next inst - psxpc -= 4; - psxLoadBranchState(); - psxRecompileNextInstruction(1); - - psxSetBranchImm(branchTo); -} - -//// BGEZ -void rpsxBGEZ() -{ - u32 branchTo = ((s32)_Imm_ * 4) + psxpc; - - _psxFlushAllUnused(); - - if( PSX_IS_CONST1(_Rs_) ) { - if ( (int)g_psxConstRegs[_Rs_] < 0 ) - branchTo = psxpc+4; - - psxRecompileNextInstruction(1); - psxSetBranchImm( branchTo ); - return; - } - - CMP32ItoM((uptr)&psxRegs.GPR.r[_Rs_], 0); - u8* prevx86 = x86Ptr; - u8* pjmp = JGE8(0); - - psxSaveBranchState(); - psxRecompileNextInstruction(1); - - psxSetBranchImm(psxpc); - - if( JUMPVALID(pjmp) ) { - x86SetJ8A( pjmp ); - } - else { - x86Ptr = prevx86; - psxpc -= 4; - psxRegs.code = *(u32*)PSXM( psxpc - 4 ); - psxLoadBranchState(); - u32* pjmp32 = JGE32(0); - psxRecompileNextInstruction(1); - psxSetBranchImm(psxpc); - x86SetJ32A( pjmp32 ); - } - - // recopy the next inst - psxpc -= 4; - psxLoadBranchState(); - psxRecompileNextInstruction(1); - - psxSetBranchImm(branchTo); -} - -//// BLTZAL -void rpsxBLTZAL() -{ - // Branch if Rs < 0 - u32 branchTo = (s32)_Imm_ * 4 + psxpc; - - _psxFlushConstReg(31); - _psxDeleteReg(31, 0); - _psxFlushAllUnused(); - - if( PSX_IS_CONST1(_Rs_) ) { - if( (int)g_psxConstRegs[_Rs_] >= 0 ) - branchTo = psxpc+4; - else { - PSX_SET_CONST(_Rt_); - g_psxConstRegs[31] = psxpc+4; - } - - psxRecompileNextInstruction(1); - psxSetBranchImm( branchTo ); - return; - } - - CMP32ItoM((uptr)&psxRegs.GPR.r[_Rs_], 0); - u8* prevx86 = x86Ptr; - u8* pjmp = JL8(0); - - psxSaveBranchState(); - - MOV32ItoM((uptr)&psxRegs.GPR.r[31], psxpc+4); - psxRecompileNextInstruction(1); - - psxSetBranchImm(psxpc); - - if( JUMPVALID(pjmp) ) { - x86SetJ8A( pjmp ); - } - else { - x86Ptr = prevx86; - psxpc -= 4; - psxRegs.code = *(u32*)PSXM( psxpc - 4 ); - psxLoadBranchState(); - u32* pjmp32 = JL32(0); - MOV32ItoM((uptr)&psxRegs.GPR.r[31], psxpc+4); - psxRecompileNextInstruction(1); - psxSetBranchImm(psxpc); - x86SetJ32A( pjmp32 ); - } - - // recopy the next inst - psxpc -= 4; - psxLoadBranchState(); - psxRecompileNextInstruction(1); - - psxSetBranchImm(branchTo); -} - -//// BGEZAL -void rpsxBGEZAL() -{ - u32 branchTo = ((s32)_Imm_ * 4) + psxpc; - - _psxFlushConstReg(31); - _psxDeleteReg(31, 0); - _psxFlushAllUnused(); - - if( PSX_IS_CONST1(_Rs_) ) { - if( g_psxConstRegs[_Rs_] < 0 ) - branchTo = psxpc+4; - else MOV32ItoM((uptr)&psxRegs.GPR.r[31], psxpc+4); - - psxRecompileNextInstruction(1); - psxSetBranchImm( branchTo ); - return; - } - - CMP32ItoM((uptr)&psxRegs.GPR.r[_Rs_], 0); - u8* prevx86 = x86Ptr; - u8* pjmp = JGE8(0); - - MOV32ItoM((uptr)&psxRegs.GPR.r[31], psxpc+4); - - psxSaveBranchState(); - psxRecompileNextInstruction(1); - - psxSetBranchImm(psxpc); - - if( JUMPVALID(pjmp) ) { - x86SetJ8A( pjmp ); - } - else { - x86Ptr = prevx86; - psxpc -= 4; - psxRegs.code = *(u32*)PSXM( psxpc - 4 ); - psxLoadBranchState(); - u32* pjmp32 = JGE32(0); - MOV32ItoM((uptr)&psxRegs.GPR.r[31], psxpc+4); - psxRecompileNextInstruction(1); - psxSetBranchImm(psxpc); - x86SetJ32A( pjmp32 ); - } - - // recopy the next inst - psxpc -= 4; - psxLoadBranchState(); - psxRecompileNextInstruction(1); - - psxSetBranchImm(branchTo); -} - -//// BLEZ -void rpsxBLEZ() -{ - // Branch if Rs <= 0 - u32 branchTo = (s32)_Imm_ * 4 + psxpc; - - _psxFlushAllUnused(); - - if( PSX_IS_CONST1(_Rs_) ) { - if( (int)g_psxConstRegs[_Rs_] > 0 ) - branchTo = psxpc+4; - - psxRecompileNextInstruction(1); - psxSetBranchImm( branchTo ); - return; - } - - _psxDeleteReg(_Rs_, 1); - _clearNeededX86regs(); - - CMP32ItoM((uptr)&psxRegs.GPR.r[_Rs_], 0); - u8* prevx86 = x86Ptr; - u8* pjmp = JLE8(0); - - psxSaveBranchState(); - psxRecompileNextInstruction(1); - psxSetBranchImm(psxpc); - - if( JUMPVALID(pjmp) ) { - x86SetJ8A( pjmp ); - } - else { - x86Ptr = prevx86; - psxpc -= 4; - psxRegs.code = *(u32*)PSXM( psxpc - 4 ); - psxLoadBranchState(); - u32* pjmp32 = JLE32(0); - psxRecompileNextInstruction(1); - psxSetBranchImm(psxpc); - x86SetJ32A( pjmp32 ); - } - - psxpc -= 4; - psxLoadBranchState(); - psxRecompileNextInstruction(1); - psxSetBranchImm(branchTo); -} - -//// BGTZ -void rpsxBGTZ() -{ - // Branch if Rs > 0 - u32 branchTo = (s32)_Imm_ * 4 + psxpc; - - _psxFlushAllUnused(); - - if( PSX_IS_CONST1(_Rs_) ) { - if( (int)g_psxConstRegs[_Rs_] <= 0 ) - branchTo = psxpc+4; - - psxRecompileNextInstruction(1); - psxSetBranchImm( branchTo ); - return; - } - - _psxDeleteReg(_Rs_, 1); - _clearNeededX86regs(); - - CMP32ItoM((uptr)&psxRegs.GPR.r[_Rs_], 0); - u8* prevx86 = x86Ptr; - u8* pjmp = JG8(0); - - psxSaveBranchState(); - psxRecompileNextInstruction(1); - psxSetBranchImm(psxpc); - - if( JUMPVALID(pjmp) ) { - x86SetJ8A( pjmp ); - } - else { - x86Ptr = prevx86; - psxpc -= 4; - psxRegs.code = *(u32*)PSXM( psxpc - 4 ); - psxLoadBranchState(); - u32* pjmp32 = JG32(0); - psxRecompileNextInstruction(1); - psxSetBranchImm(psxpc); - x86SetJ32A( pjmp32 ); - } - - psxpc -= 4; - psxLoadBranchState(); - psxRecompileNextInstruction(1); - psxSetBranchImm(branchTo); -} - -void rpsxMFC0() -{ - // Rt = Cop0->Rd - if (!_Rt_) return; - - _psxOnWriteReg(_Rt_); - MOV32MtoR(EAX, (uptr)&psxRegs.CP0.r[_Rd_]); - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); -} - -void rpsxCFC0() -{ - // Rt = Cop0->Rd - if (!_Rt_) return; - - _psxOnWriteReg(_Rt_); - MOV32MtoR(EAX, (uptr)&psxRegs.CP0.r[_Rd_]); - MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); -} - -void rpsxMTC0() -{ - // Cop0->Rd = Rt - if( PSX_IS_CONST1(_Rt_) ) { - MOV32ItoM((uptr)&psxRegs.CP0.r[_Rd_], g_psxConstRegs[_Rt_]); - } - else { - _psxDeleteReg(_Rt_, 1); - MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); - MOV32RtoM((uptr)&psxRegs.CP0.r[_Rd_], EAX); - } -} - -void rpsxCTC0() -{ - // Cop0->Rd = Rt - rpsxMTC0(); -} - -void rpsxRFE() -{ - MOV32MtoR(EAX, (uptr)&psxRegs.CP0.n.Status); - MOV32RtoR(ECX, EAX); - AND32ItoR(EAX, 0xfffffff0); - AND32ItoR(ECX, 0x3c); - SHR32ItoR(ECX, 2); - OR32RtoR (EAX, ECX); - MOV32RtoM((uptr)&psxRegs.CP0.n.Status, EAX); - - // Test the IOP's INTC status, so that any pending ints get raised. - - _psxFlushCall(0); - CALLFunc( (uptr)&iopTestIntc ); -} - -// R3000A tables -extern void (*rpsxBSC[64])(); -extern void (*rpsxSPC[64])(); -extern void (*rpsxREG[32])(); -extern void (*rpsxCP0[32])(); -extern void (*rpsxCP2[64])(); -extern void (*rpsxCP2BSC[32])(); - -static void rpsxSPECIAL() { rpsxSPC[_Funct_](); } -static void rpsxREGIMM() { rpsxREG[_Rt_](); } -static void rpsxCOP0() { rpsxCP0[_Rs_](); } -//static void rpsxBASIC() { rpsxCP2BSC[_Rs_](); } - -static void rpsxNULL() { - SysPrintf("psxUNK: %8.8x\n", psxRegs.code); -} - -void (*rpsxBSC[64])() = { - rpsxSPECIAL, rpsxREGIMM, rpsxJ , rpsxJAL , rpsxBEQ , rpsxBNE , rpsxBLEZ, rpsxBGTZ, - rpsxADDI , rpsxADDIU , rpsxSLTI, rpsxSLTIU, rpsxANDI, rpsxORI , rpsxXORI, rpsxLUI , - rpsxCOP0 , rpsxNULL , rpsxNULL, rpsxNULL , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, - rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, - rpsxLB , rpsxLH , rpsxLWL , rpsxLW , rpsxLBU , rpsxLHU , rpsxLWR , rpsxNULL, - rpsxSB , rpsxSH , rpsxSWL , rpsxSW , rpsxNULL, rpsxNULL, rpsxSWR , rpsxNULL, - rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, - rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL -}; - -void (*rpsxSPC[64])() = { - rpsxSLL , rpsxNULL, rpsxSRL , rpsxSRA , rpsxSLLV , rpsxNULL , rpsxSRLV, rpsxSRAV, - rpsxJR , rpsxJALR, rpsxNULL, rpsxNULL, rpsxSYSCALL, rpsxBREAK, rpsxNULL, rpsxNULL, - rpsxMFHI, rpsxMTHI, rpsxMFLO, rpsxMTLO, rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL, - rpsxMULT, rpsxMULTU, rpsxDIV, rpsxDIVU, rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL, - rpsxADD , rpsxADDU, rpsxSUB , rpsxSUBU, rpsxAND , rpsxOR , rpsxXOR , rpsxNOR , - rpsxNULL, rpsxNULL, rpsxSLT , rpsxSLTU, rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL, - rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL, - rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL -}; - -void (*rpsxREG[32])() = { - rpsxBLTZ , rpsxBGEZ , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, - rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, - rpsxBLTZAL, rpsxBGEZAL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, - rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL -}; - -void (*rpsxCP0[32])() = { - rpsxMFC0, rpsxNULL, rpsxCFC0, rpsxNULL, rpsxMTC0, rpsxNULL, rpsxCTC0, rpsxNULL, - rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, - rpsxRFE , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, - rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL -}; - -// coissued insts -void (*rpsxBSC_co[64] )() = { - rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, - rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, - rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, - rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, - rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, - rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, - rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, - rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, -}; - -//////////////////////////////////////////////// -// Back-Prob Function Tables - Gathering Info // -//////////////////////////////////////////////// -#define rpsxpropSetRead(reg) { \ - if( !(pinst->regs[reg] & EEINST_USED) ) \ - pinst->regs[reg] |= EEINST_LASTUSE; \ - prev->regs[reg] |= EEINST_LIVE0|EEINST_USED; \ - pinst->regs[reg] |= EEINST_USED; \ - _recFillRegister(*pinst, XMMTYPE_GPRREG, reg, 0); \ -} \ - -#define rpsxpropSetWrite(reg) { \ - prev->regs[reg] &= ~EEINST_LIVE0; \ - if( !(pinst->regs[reg] & EEINST_USED) ) \ - pinst->regs[reg] |= EEINST_LASTUSE; \ - pinst->regs[reg] |= EEINST_USED; \ - prev->regs[reg] |= EEINST_USED; \ - _recFillRegister(*pinst, XMMTYPE_GPRREG, reg, 1); \ -} - -void rpsxpropBSC(EEINST* prev, EEINST* pinst); -void rpsxpropSPECIAL(EEINST* prev, EEINST* pinst); -void rpsxpropREGIMM(EEINST* prev, EEINST* pinst); -void rpsxpropCP0(EEINST* prev, EEINST* pinst); -void rpsxpropCP2(EEINST* prev, EEINST* pinst); - -//SPECIAL, REGIMM, J , JAL , BEQ , BNE , BLEZ, BGTZ, -//ADDI , ADDIU , SLTI, SLTIU, ANDI, ORI , XORI, LUI , -//COP0 , NULL , COP2, NULL , NULL, NULL, NULL, NULL, -//NULL , NULL , NULL, NULL , NULL, NULL, NULL, NULL, -//LB , LH , LWL , LW , LBU , LHU , LWR , NULL, -//SB , SH , SWL , SW , NULL, NULL, SWR , NULL, -//NULL , NULL , NULL, NULL , NULL, NULL, NULL, NULL, -//NULL , NULL , NULL, NULL , NULL, NULL, NULL, NULL -void rpsxpropBSC(EEINST* prev, EEINST* pinst) -{ - switch(psxRegs.code >> 26) { - case 0: rpsxpropSPECIAL(prev, pinst); break; - case 1: rpsxpropREGIMM(prev, pinst); break; - case 2: // j - break; - case 3: // jal - rpsxpropSetWrite(31); - break; - case 4: // beq - case 5: // bne - rpsxpropSetRead(_Rs_); - rpsxpropSetRead(_Rt_); - break; - - case 6: // blez - case 7: // bgtz - rpsxpropSetRead(_Rs_); - break; - - case 15: // lui - rpsxpropSetWrite(_Rt_); - break; - - case 16: rpsxpropCP0(prev, pinst); break; - case 18: assert(0); break; - - // stores - case 40: case 41: case 42: case 43: case 46: - rpsxpropSetRead(_Rt_); - rpsxpropSetRead(_Rs_); - break; - - default: - rpsxpropSetWrite(_Rt_); - rpsxpropSetRead(_Rs_); - break; - } -} - -//SLL , NULL, SRL , SRA , SLLV , NULL , SRLV, SRAV, -//JR , JALR, NULL, NULL, SYSCALL, BREAK, NULL, NULL, -//MFHI, MTHI, MFLO, MTLO, NULL , NULL , NULL, NULL, -//MULT, MULTU, DIV, DIVU, NULL , NULL , NULL, NULL, -//ADD , ADDU, SUB , SUBU, AND , OR , XOR , NOR , -//NULL, NULL, SLT , SLTU, NULL , NULL , NULL, NULL, -//NULL, NULL, NULL, NULL, NULL , NULL , NULL, NULL, -//NULL, NULL, NULL, NULL, NULL , NULL , NULL, NULL -void rpsxpropSPECIAL(EEINST* prev, EEINST* pinst) -{ - switch(_Funct_) { - case 0: // SLL - case 2: // SRL - case 3: // SRA - rpsxpropSetWrite(_Rd_); - rpsxpropSetRead(_Rt_); - break; - - case 8: // JR - rpsxpropSetRead(_Rs_); - break; - case 9: // JALR - rpsxpropSetWrite(_Rd_); - rpsxpropSetRead(_Rs_); - break; - - case 12: // syscall - case 13: // break - _recClearInst(prev); - prev->info = 0; - break; - case 15: // sync - break; - - case 16: // mfhi - rpsxpropSetWrite(_Rd_); - rpsxpropSetRead(PSX_HI); - break; - case 17: // mthi - rpsxpropSetWrite(PSX_HI); - rpsxpropSetRead(_Rs_); - break; - case 18: // mflo - rpsxpropSetWrite(_Rd_); - rpsxpropSetRead(PSX_LO); - break; - case 19: // mtlo - rpsxpropSetWrite(PSX_LO); - rpsxpropSetRead(_Rs_); - break; - - case 24: // mult - case 25: // multu - case 26: // div - case 27: // divu - rpsxpropSetWrite(PSX_LO); - rpsxpropSetWrite(PSX_HI); - rpsxpropSetRead(_Rs_); - rpsxpropSetRead(_Rt_); - break; - - case 32: // add - case 33: // addu - case 34: // sub - case 35: // subu - rpsxpropSetWrite(_Rd_); - if( _Rs_ ) rpsxpropSetRead(_Rs_); - if( _Rt_ ) rpsxpropSetRead(_Rt_); - break; - - default: - rpsxpropSetWrite(_Rd_); - rpsxpropSetRead(_Rs_); - rpsxpropSetRead(_Rt_); - break; - } -} - -//BLTZ , BGEZ , NULL, NULL, NULL, NULL, NULL, NULL, -//NULL , NULL , NULL, NULL, NULL, NULL, NULL, NULL, -//BLTZAL, BGEZAL, NULL, NULL, NULL, NULL, NULL, NULL, -//NULL , NULL , NULL, NULL, NULL, NULL, NULL, NULL -void rpsxpropREGIMM(EEINST* prev, EEINST* pinst) -{ - switch(_Rt_) { - case 0: // bltz - case 1: // bgez - rpsxpropSetRead(_Rs_); - break; - - case 16: // bltzal - case 17: // bgezal - // do not write 31 - rpsxpropSetRead(_Rs_); - break; - - jNO_DEFAULT - } -} - -//MFC0, NULL, CFC0, NULL, MTC0, NULL, CTC0, NULL, -//NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -//RFE , NULL, NULL, NULL, NULL, NULL, NULL, NULL, -//NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL -void rpsxpropCP0(EEINST* prev, EEINST* pinst) -{ - switch(_Rs_) { - case 0: // mfc0 - case 2: // cfc0 - rpsxpropSetWrite(_Rt_); - break; - - case 4: // mtc0 - case 6: // ctc0 - rpsxpropSetRead(_Rt_); - break; - case 16: // rfe - break; - - jNO_DEFAULT - } -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" +#include + +#include "PsxCommon.h" +#include "ix86/ix86.h" +#include "iR3000A.h" +#include "IopMem.h" +#include "IopDma.h" + +extern int g_psxWriteOk; +extern u32 g_psxMaxRecMem; + +// R3000A instruction implementation +#define REC_FUNC(f) \ +static void rpsx##f() { \ + MOV32ItoM((uptr)&psxRegs.code, (u32)psxRegs.code); \ + _psxFlushCall(FLUSH_EVERYTHING); \ + CALLFunc((uptr)psx##f); \ + PSX_DEL_CONST(_Rt_); \ +/* branch = 2; */\ +} + +extern void psxLWL(); +extern void psxLWR(); +extern void psxSWL(); +extern void psxSWR(); + +//// +void rpsxADDIU_const() +{ + g_psxConstRegs[_Rt_] = g_psxConstRegs[_Rs_] + _Imm_; +} + +// adds a constant to sreg and puts into dreg +void rpsxADDconst(int dreg, int sreg, u32 off, int info) +{ + if (sreg) { + if (sreg == dreg) { + ADD32ItoM((uptr)&psxRegs.GPR.r[dreg], off); + } else { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[sreg]); + if (off) ADD32ItoR(EAX, off); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], EAX); + } + } + else { + MOV32ItoM((uptr)&psxRegs.GPR.r[dreg], off); + } +} + +void rpsxADDIU_(int info) +{ + // Rt = Rs + Im + if (!_Rt_) return; + rpsxADDconst(_Rt_, _Rs_, _Imm_, info); +} + +PSXRECOMPILE_CONSTCODE1(ADDIU); + +void rpsxADDI() { rpsxADDIU(); } + +//// SLTI +void rpsxSLTI_const() +{ + g_psxConstRegs[_Rt_] = *(int*)&g_psxConstRegs[_Rs_] < _Imm_; +} + +void rpsxSLTconst(int info, int dreg, int sreg, int imm) +{ + XOR32RtoR(EAX, EAX); + CMP32ItoM((uptr)&psxRegs.GPR.r[sreg], imm); + SETL8R(EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], EAX); +} + +void rpsxSLTI_(int info) { rpsxSLTconst(info, _Rt_, _Rs_, _Imm_); } + +PSXRECOMPILE_CONSTCODE1(SLTI); + +//// SLTIU +void rpsxSLTIU_const() +{ + g_psxConstRegs[_Rt_] = g_psxConstRegs[_Rs_] < _ImmU_; +} + +void rpsxSLTUconst(int info, int dreg, int sreg, int imm) +{ + XOR32RtoR(EAX, EAX); + CMP32ItoM((uptr)&psxRegs.GPR.r[sreg], imm); + SETB8R(EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], EAX); +} + +void rpsxSLTIU_(int info) { rpsxSLTUconst(info, _Rt_, _Rs_, (s32)_Imm_); } + +PSXRECOMPILE_CONSTCODE1(SLTIU); + +//// ANDI +void rpsxANDI_const() +{ + g_psxConstRegs[_Rt_] = g_psxConstRegs[_Rs_] & _ImmU_; +} + +void rpsxANDconst(int info, int dreg, int sreg, u32 imm) +{ + if (imm) { + if (sreg == dreg) { + AND32ItoM((uptr)&psxRegs.GPR.r[dreg], imm); + } else { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[sreg]); + AND32ItoR(EAX, imm); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], EAX); + } + } else { + MOV32ItoM((uptr)&psxRegs.GPR.r[dreg], 0); + } +} + +void rpsxANDI_(int info) { rpsxANDconst(info, _Rt_, _Rs_, _ImmU_); } + +PSXRECOMPILE_CONSTCODE1(ANDI); + +//// ORI +void rpsxORI_const() +{ + g_psxConstRegs[_Rt_] = g_psxConstRegs[_Rs_] | _ImmU_; +} + +void rpsxORconst(int info, int dreg, int sreg, u32 imm) +{ + if (imm) { + if (sreg == dreg) { + OR32ItoM((uptr)&psxRegs.GPR.r[dreg], imm); + } + else { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[sreg]); + OR32ItoR (EAX, imm); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], EAX); + } + } + else { + if( dreg != sreg ) { + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[sreg]); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], ECX); + } + } +} + +void rpsxORI_(int info) { rpsxORconst(info, _Rt_, _Rs_, _ImmU_); } + +PSXRECOMPILE_CONSTCODE1(ORI); + +void rpsxXORI_const() +{ + g_psxConstRegs[_Rt_] = g_psxConstRegs[_Rs_] ^ _ImmU_; +} + +void rpsxXORconst(int info, int dreg, int sreg, u32 imm) +{ + if( imm == 0xffffffff ) { + if( dreg == sreg ) { + NOT32M((uptr)&psxRegs.GPR.r[dreg]); + } + else { + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[sreg]); + NOT32R(ECX); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], ECX); + } + } + else if (imm) { + + if (sreg == dreg) { + XOR32ItoM((uptr)&psxRegs.GPR.r[dreg], imm); + } + else { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[sreg]); + XOR32ItoR(EAX, imm); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], EAX); + } + } + else { + if( dreg != sreg ) { + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[sreg]); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], ECX); + } + } +} + +void rpsxXORI_(int info) { rpsxXORconst(info, _Rt_, _Rs_, _ImmU_); } + +PSXRECOMPILE_CONSTCODE1(XORI); + +void rpsxLUI() +{ + if(!_Rt_) return; + _psxOnWriteReg(_Rt_); + _psxDeleteReg(_Rt_, 0); + PSX_SET_CONST(_Rt_); + g_psxConstRegs[_Rt_] = psxRegs.code << 16; +} + +void rpsxADDU_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rs_] + g_psxConstRegs[_Rt_]; +} + +void rpsxADDU_consts(int info) { rpsxADDconst(_Rd_, _Rt_, g_psxConstRegs[_Rs_], info); } +void rpsxADDU_constt(int info) +{ + info |= PROCESS_EE_SET_S(EEREC_T); + rpsxADDconst(_Rd_, _Rs_, g_psxConstRegs[_Rt_], info); +} + +void rpsxADDU_(int info) +{ + if (_Rs_ && _Rt_) { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + ADD32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + } else if (_Rs_) { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + } else if (_Rt_) { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + } else { + XOR32RtoR(EAX, EAX); + } + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +PSXRECOMPILE_CONSTCODE0(ADDU); + +void rpsxADD() { rpsxADDU(); } + + +void rpsxSUBU_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rs_] - g_psxConstRegs[_Rt_]; +} + +void rpsxSUBU_consts(int info) +{ + MOV32ItoR(EAX, g_psxConstRegs[_Rs_]); + SUB32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +void rpsxSUBU_constt(int info) { rpsxADDconst(_Rd_, _Rs_, -(int)g_psxConstRegs[_Rt_], info); } + +void rpsxSUBU_(int info) +{ + // Rd = Rs - Rt + if (!_Rd_) return; + + if( _Rd_ == _Rs_ ) { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + SUB32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); + } + else { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + SUB32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); + } +} + +PSXRECOMPILE_CONSTCODE0(SUBU); + +void rpsxSUB() { rpsxSUBU(); } + +void rpsxLogicalOp(int info, int op) +{ + if( _Rd_ == _Rs_ || _Rd_ == _Rt_ ) { + int vreg = _Rd_ == _Rs_ ? _Rt_ : _Rs_; + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[vreg]); + LogicalOp32RtoM((uptr)&psxRegs.GPR.r[_Rd_], ECX, op); + if( op == 3 ) + NOT32M((uptr)&psxRegs.GPR.r[_Rd_]); + } + else { + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]); + LogicalOp32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rt_], op); + if( op == 3 ) + NOT32R(ECX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], ECX); + } +} + +void rpsxAND_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rs_] & g_psxConstRegs[_Rt_]; +} + +void rpsxAND_consts(int info) { rpsxANDconst(info, _Rd_, _Rt_, g_psxConstRegs[_Rs_]); } +void rpsxAND_constt(int info) { rpsxANDconst(info, _Rd_, _Rs_, g_psxConstRegs[_Rt_]); } +void rpsxAND_(int info) { rpsxLogicalOp(info, 0); } + +PSXRECOMPILE_CONSTCODE0(AND); + +void rpsxOR_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rs_] | g_psxConstRegs[_Rt_]; +} + +void rpsxOR_consts(int info) { rpsxORconst(info, _Rd_, _Rt_, g_psxConstRegs[_Rs_]); } +void rpsxOR_constt(int info) { rpsxORconst(info, _Rd_, _Rs_, g_psxConstRegs[_Rt_]); } +void rpsxOR_(int info) { rpsxLogicalOp(info, 1); } + +PSXRECOMPILE_CONSTCODE0(OR); + +//// XOR +void rpsxXOR_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rs_] ^ g_psxConstRegs[_Rt_]; +} + +void rpsxXOR_consts(int info) { rpsxXORconst(info, _Rd_, _Rt_, g_psxConstRegs[_Rs_]); } +void rpsxXOR_constt(int info) { rpsxXORconst(info, _Rd_, _Rs_, g_psxConstRegs[_Rt_]); } +void rpsxXOR_(int info) { rpsxLogicalOp(info, 2); } + +PSXRECOMPILE_CONSTCODE0(XOR); + +//// NOR +void rpsxNOR_const() +{ + g_psxConstRegs[_Rd_] = ~(g_psxConstRegs[_Rs_] | g_psxConstRegs[_Rt_]); +} + +void rpsxNORconst(int info, int dreg, int sreg, u32 imm) +{ + if( imm ) { + if( dreg == sreg ) { + OR32ItoM((uptr)&psxRegs.GPR.r[dreg], imm); + NOT32M((uptr)&psxRegs.GPR.r[dreg]); + } + else { + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[sreg]); + OR32ItoR(ECX, imm); + NOT32R(ECX); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], ECX); + } + } + else { + if( dreg == sreg ) { + NOT32M((uptr)&psxRegs.GPR.r[dreg]); + } + else { + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[sreg]); + NOT32R(ECX); + MOV32RtoM((uptr)&psxRegs.GPR.r[dreg], ECX); + } + } +} + +void rpsxNOR_consts(int info) { rpsxNORconst(info, _Rd_, _Rt_, g_psxConstRegs[_Rs_]); } +void rpsxNOR_constt(int info) { rpsxNORconst(info, _Rd_, _Rs_, g_psxConstRegs[_Rt_]); } +void rpsxNOR_(int info) { rpsxLogicalOp(info, 3); } + +PSXRECOMPILE_CONSTCODE0(NOR); + +//// SLT +void rpsxSLT_const() +{ + g_psxConstRegs[_Rd_] = *(int*)&g_psxConstRegs[_Rs_] < *(int*)&g_psxConstRegs[_Rt_]; +} + +void rpsxSLT_consts(int info) +{ + XOR32RtoR(EAX, EAX); + CMP32ItoM((uptr)&psxRegs.GPR.r[_Rt_], g_psxConstRegs[_Rs_]); + SETG8R(EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +void rpsxSLT_constt(int info) { rpsxSLTconst(info, _Rd_, _Rs_, g_psxConstRegs[_Rt_]); } +void rpsxSLT_(int info) +{ + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + CMP32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + SETL8R (EAX); + AND32ItoR(EAX, 0xff); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +PSXRECOMPILE_CONSTCODE0(SLT); + +//// SLTU +void rpsxSLTU_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rs_] < g_psxConstRegs[_Rt_]; +} + +void rpsxSLTU_consts(int info) +{ + XOR32RtoR(EAX, EAX); + CMP32ItoM((uptr)&psxRegs.GPR.r[_Rt_], g_psxConstRegs[_Rs_]); + SETA8R(EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +void rpsxSLTU_constt(int info) { rpsxSLTUconst(info, _Rd_, _Rs_, g_psxConstRegs[_Rt_]); } +void rpsxSLTU_(int info) +{ + // Rd = Rs < Rt (unsigned) + if (!_Rd_) return; + + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + CMP32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + SBB32RtoR(EAX, EAX); + NEG32R (EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +PSXRECOMPILE_CONSTCODE0(SLTU); + +//// MULT +void rpsxMULT_const() +{ + u64 res = (s64)((s64)*(int*)&g_psxConstRegs[_Rs_] * (s64)*(int*)&g_psxConstRegs[_Rt_]); + + MOV32ItoM((uptr)&psxRegs.GPR.n.hi, (u32)((res >> 32) & 0xffffffff)); + MOV32ItoM((uptr)&psxRegs.GPR.n.lo, (u32)(res & 0xffffffff)); +} + +void rpsxMULTsuperconst(int info, int sreg, int imm, int sign) +{ + // Lo/Hi = Rs * Rt (signed) + MOV32ItoR(EAX, imm); + if( sign ) IMUL32M ((uptr)&psxRegs.GPR.r[sreg]); + else MUL32M ((uptr)&psxRegs.GPR.r[sreg]); + MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EDX); +} + +void rpsxMULTsuper(int info, int sign) +{ + // Lo/Hi = Rs * Rt (signed) + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + if( sign ) IMUL32M ((uptr)&psxRegs.GPR.r[_Rt_]); + else MUL32M ((uptr)&psxRegs.GPR.r[_Rt_]); + MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EDX); +} + +void rpsxMULT_consts(int info) { rpsxMULTsuperconst(info, _Rt_, g_psxConstRegs[_Rs_], 1); } +void rpsxMULT_constt(int info) { rpsxMULTsuperconst(info, _Rs_, g_psxConstRegs[_Rt_], 1); } +void rpsxMULT_(int info) { rpsxMULTsuper(info, 1); } + +PSXRECOMPILE_CONSTCODE3_PENALTY(MULT, 1, psxInstCycles_Mult); + +//// MULTU +void rpsxMULTU_const() +{ + u64 res = (u64)((u64)g_psxConstRegs[_Rs_] * (u64)g_psxConstRegs[_Rt_]); + + MOV32ItoM((uptr)&psxRegs.GPR.n.hi, (u32)((res >> 32) & 0xffffffff)); + MOV32ItoM((uptr)&psxRegs.GPR.n.lo, (u32)(res & 0xffffffff)); +} + +void rpsxMULTU_consts(int info) { rpsxMULTsuperconst(info, _Rt_, g_psxConstRegs[_Rs_], 0); } +void rpsxMULTU_constt(int info) { rpsxMULTsuperconst(info, _Rs_, g_psxConstRegs[_Rt_], 0); } +void rpsxMULTU_(int info) { rpsxMULTsuper(info, 0); } + +PSXRECOMPILE_CONSTCODE3_PENALTY(MULTU, 1, psxInstCycles_Mult); + +//// DIV +void rpsxDIV_const() +{ + u32 lo, hi; + + if (g_psxConstRegs[_Rt_] != 0) { + lo = *(int*)&g_psxConstRegs[_Rs_] / *(int*)&g_psxConstRegs[_Rt_]; + hi = *(int*)&g_psxConstRegs[_Rs_] % *(int*)&g_psxConstRegs[_Rt_]; + MOV32ItoM((uptr)&psxRegs.GPR.n.hi, hi); + MOV32ItoM((uptr)&psxRegs.GPR.n.lo, lo); + } +} + +void rpsxDIVsuperconsts(int info, int sign) +{ + u32 imm = g_psxConstRegs[_Rs_]; + + if( imm ) { + // Lo/Hi = Rs / Rt (signed) + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rt_]); + CMP32ItoR(ECX, 0); + j8Ptr[0] = JE8(0); + MOV32ItoR(EAX, imm); + + + if( sign ) { + CDQ(); + IDIV32R (ECX); + } + else { + XOR32RtoR( EDX, EDX ); + DIV32R(ECX); + } + + + MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EDX); + x86SetJ8(j8Ptr[0]); + } + else { + XOR32RtoR(EAX, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); + } +} + +void rpsxDIVsuperconstt(int info, int sign) +{ + u32 imm = g_psxConstRegs[_Rt_]; + + if( imm ) { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + MOV32ItoR(ECX, imm); + //CDQ(); + + if( sign ) { + CDQ(); + IDIV32R (ECX); + } + else { + XOR32RtoR( EDX, EDX ); + DIV32R(ECX); + } + + + MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EDX); + } +} + +void rpsxDIVsuper(int info, int sign) +{ + // Lo/Hi = Rs / Rt (signed) + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rt_]); + CMP32ItoR(ECX, 0); + j8Ptr[0] = JE8(0); + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + + if( sign ) { + CDQ(); + IDIV32R (ECX); + } + else { + XOR32RtoR( EDX, EDX ); + DIV32R(ECX); + } + + MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EDX); + x86SetJ8(j8Ptr[0]); +} + +void rpsxDIV_consts(int info) { rpsxDIVsuperconsts(info, 1); } +void rpsxDIV_constt(int info) { rpsxDIVsuperconstt(info, 1); } +void rpsxDIV_(int info) { rpsxDIVsuper(info, 1); } + +PSXRECOMPILE_CONSTCODE3_PENALTY(DIV, 1, psxInstCycles_Div); + +//// DIVU +void rpsxDIVU_const() +{ + u32 lo, hi; + + if (g_psxConstRegs[_Rt_] != 0) { + lo = g_psxConstRegs[_Rs_] / g_psxConstRegs[_Rt_]; + hi = g_psxConstRegs[_Rs_] % g_psxConstRegs[_Rt_]; + MOV32ItoM((uptr)&psxRegs.GPR.n.hi, hi); + MOV32ItoM((uptr)&psxRegs.GPR.n.lo, lo); + } +} + +void rpsxDIVU_consts(int info) { rpsxDIVsuperconsts(info, 0); } +void rpsxDIVU_constt(int info) { rpsxDIVsuperconstt(info, 0); } +void rpsxDIVU_(int info) { rpsxDIVsuper(info, 0); } + +PSXRECOMPILE_CONSTCODE3_PENALTY(DIVU, 1, psxInstCycles_Div); + +//// LoadStores +#ifdef PCSX2_VIRTUAL_MEM + +// VM load store functions (fastest) + +//#define REC_SLOWREAD +//#define REC_SLOWWRITE + +int _psxPrepareReg(int gprreg) +{ + return 0; +} + +static u32 s_nAddMemOffset = 0; + +static __forceinline void SET_HWLOC_R3000A() { + x86SetJ8(j8Ptr[0]); + SHR32ItoR(ECX, 3); + if( s_nAddMemOffset ) ADD32ItoR(ECX, s_nAddMemOffset); +} + +int rpsxSetMemLocation(int regs, int mmreg) +{ + s_nAddMemOffset = 0; + MOV32MtoR( ECX, (int)&psxRegs.GPR.r[ regs ] ); + + if ( _Imm_ != 0 ) ADD32ItoR( ECX, _Imm_ ); + + SHL32ItoR(ECX, 3); + j8Ptr[0] = JS8(0); + SHR32ItoR(ECX, 3); + AND32ItoR(ECX, 0x1fffff); // 2Mb + return 1; +} + +void recLoad32(u32 bit, u32 sign) +{ + int mmreg = -1; + +#ifdef REC_SLOWREAD + _psxFlushConstReg(_Rs_); +#else + if( PSX_IS_CONST1( _Rs_ ) ) { + // do const processing + int ineax = 0; + + _psxOnWriteReg(_Rt_); + mmreg = EAX; + + switch(bit) { + case 8: ineax = psxRecMemConstRead8(mmreg, g_psxConstRegs[_Rs_]+_Imm_, sign); break; + case 16: + assert( (g_psxConstRegs[_Rs_]+_Imm_) % 2 == 0 ); + ineax = psxRecMemConstRead16(mmreg, g_psxConstRegs[_Rs_]+_Imm_, sign); + break; + case 32: + assert( (g_psxConstRegs[_Rs_]+_Imm_) % 4 == 0 ); + ineax = psxRecMemConstRead32(mmreg, g_psxConstRegs[_Rs_]+_Imm_); + break; + } + + if( _Rt_ ) MOV32RtoM( (int)&psxRegs.GPR.r[ _Rt_ ], EAX ); + } + else +#endif + { + int dohw; + int mmregs = _psxPrepareReg(_Rs_); + + _psxOnWriteReg(_Rt_); + _psxDeleteReg(_Rt_, 0); + + dohw = rpsxSetMemLocation(_Rs_, mmregs); + + switch(bit) { + case 8: + if( sign ) MOVSX32Rm8toROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset); + else MOVZX32Rm8toROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset); + break; + case 16: + if( sign ) MOVSX32Rm16toROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset); + else MOVZX32Rm16toROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset); + break; + case 32: + MOV32RmtoROffset(EAX, ECX, PS2MEM_PSX_+s_nAddMemOffset); + break; + } + + if( dohw ) { + j8Ptr[1] = JMP8(0); + + SET_HWLOC_R3000A(); + + switch(bit) { + case 8: + CALLFunc( (int)psxRecMemRead8 ); + if( sign ) MOVSX32R8toR(EAX, EAX); + else MOVZX32R8toR(EAX, EAX); + break; + case 16: + CALLFunc( (int)psxRecMemRead16 ); + if( sign ) MOVSX32R16toR(EAX, EAX); + else MOVZX32R16toR(EAX, EAX); + break; + case 32: + CALLFunc( (int)psxRecMemRead32 ); + break; + } + + x86SetJ8(j8Ptr[1]); + } + + if( _Rt_ ) + MOV32RtoM( (int)&psxRegs.GPR.r[ _Rt_ ], EAX ); + } +} + +void rpsxLB() { recLoad32(8, 1); } +void rpsxLBU() { recLoad32(8, 0); } +void rpsxLH() { recLoad32(16, 1); } +void rpsxLHU() { recLoad32(16, 0); } +void rpsxLW() { recLoad32(32, 0); } + +extern void rpsxMemConstClear(u32 mem); + +// check if mem is executable, and clear it +__declspec(naked) void rpsxWriteMemClear() +{ + _asm { + mov edx, ecx + shr edx, 14 + and dl, 0xfc + add edx, psxRecLUT + test dword ptr [edx], 0xffffffff + jnz Clear32 + ret +Clear32: + // recLUT[mem>>16] + (mem&0xfffc) + mov edx, dword ptr [edx] + mov eax, ecx + and eax, 0xfffc + // edx += 2*eax + shl eax, 1 + add edx, eax + cmp dword ptr [edx], 0 + je ClearRet + sub esp, 4 + mov dword ptr [esp], edx + call psxRecClearMem + add esp, 4 +ClearRet: + ret + } +} + +extern u32 s_psxBlockCycles; +void recStore(int bit) +{ +#ifdef REC_SLOWWRITE + _psxFlushConstReg(_Rs_); +#else + if( PSX_IS_CONST1( _Rs_ ) ) { + u8* pjmpok; + u32 addr = g_psxConstRegs[_Rs_]+_Imm_; + int doclear = 0; + + if( !(addr & 0x10000000) ) { + // check g_psxWriteOk + CMP32ItoM((uptr)&g_psxWriteOk, 0); + pjmpok = JE8(0); + } + + switch(bit) { + case 8: + if( PSX_IS_CONST1(_Rt_) ) doclear = psxRecMemConstWrite8(addr, MEM_PSXCONSTTAG|(_Rt_<<16)); + else { + _psxMoveGPRtoR(EAX, _Rt_); + doclear = psxRecMemConstWrite8(addr, EAX); + } + + break; + + case 16: + assert( (addr)%2 == 0 ); + if( PSX_IS_CONST1(_Rt_) ) doclear = psxRecMemConstWrite16(addr, MEM_PSXCONSTTAG|(_Rt_<<16)); + else { + _psxMoveGPRtoR(EAX, _Rt_); + doclear = psxRecMemConstWrite16(addr, EAX); + } + + break; + + case 32: + assert( (addr)%4 == 0 ); + if( PSX_IS_CONST1(_Rt_) ) doclear = psxRecMemConstWrite32(addr, MEM_PSXCONSTTAG|(_Rt_<<16)); + else { + _psxMoveGPRtoR(EAX, _Rt_); + doclear = psxRecMemConstWrite32(addr, EAX); + } + + break; + } + + if( !(addr & 0x10000000) ) { + if( doclear ) rpsxMemConstClear((addr)&~3); + x86SetJ8(pjmpok); + } + } + else +#endif + { + int dohw; + int mmregs = _psxPrepareReg(_Rs_); + dohw = rpsxSetMemLocation(_Rs_, mmregs); + + CMP32ItoM((uptr)&g_psxWriteOk, 0); + u8* pjmpok = JE8(0); + + if( PSX_IS_CONST1( _Rt_ ) ) { + switch(bit) { + case 8: MOV8ItoRmOffset(ECX, g_psxConstRegs[_Rt_], PS2MEM_PSX_+s_nAddMemOffset); break; + case 16: MOV16ItoRmOffset(ECX, g_psxConstRegs[_Rt_], PS2MEM_PSX_+s_nAddMemOffset); break; + case 32: MOV32ItoRmOffset(ECX, g_psxConstRegs[_Rt_], PS2MEM_PSX_+s_nAddMemOffset); break; + } + } + else { + switch(bit) { + case 8: + MOV8MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); + MOV8RtoRmOffset(ECX, EAX, PS2MEM_PSX_+s_nAddMemOffset); + break; + + case 16: + MOV16MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); + MOV16RtoRmOffset(ECX, EAX, PS2MEM_PSX_+s_nAddMemOffset); + break; + + case 32: + MOV32MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_PSX_+s_nAddMemOffset); + break; + } + } + + if( s_nAddMemOffset ) ADD32ItoR(ECX, s_nAddMemOffset); + CMP32MtoR(ECX, (uptr)&g_psxMaxRecMem); + + j8Ptr[1] = JAE8(0); + + if( bit < 32 ) AND8ItoR(ECX, 0xfc); + CALLFunc((u32)rpsxWriteMemClear); + + if( dohw ) { + j8Ptr[2] = JMP8(0); + + SET_HWLOC_R3000A(); + + if( PSX_IS_CONST1(_Rt_) ) { + switch(bit) { + case 8: MOV8ItoR(EAX, g_psxConstRegs[_Rt_]); break; + case 16: MOV16ItoR(EAX, g_psxConstRegs[_Rt_]); break; + case 32: MOV32ItoR(EAX, g_psxConstRegs[_Rt_]); break; + } + } + else { + switch(bit) { + case 8: MOV8MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); break; + case 16: MOV16MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); break; + case 32: MOV32MtoR(EAX, (int)&psxRegs.GPR.r[ _Rt_ ]); break; + } + } + + if( s_nAddMemOffset != 0 ) ADD32ItoR(ECX, s_nAddMemOffset); + + // some type of hardware write + switch(bit) { + case 8: CALLFunc( (int)psxRecMemWrite8 ); break; + case 16: CALLFunc( (int)psxRecMemWrite16 ); break; + case 32: CALLFunc( (int)psxRecMemWrite32 ); break; + } + + x86SetJ8(j8Ptr[2]); + } + + x86SetJ8(j8Ptr[1]); + x86SetJ8(pjmpok); + } +} + +void rpsxSB() { recStore(8); } +void rpsxSH() { recStore(16); } +void rpsxSW() { recStore(32); } + +REC_FUNC(LWL); +REC_FUNC(LWR); +REC_FUNC(SWL); +REC_FUNC(SWR); + +#else + +// TLB loadstore functions (slower +REC_FUNC(LWL); +REC_FUNC(LWR); +REC_FUNC(SWL); +REC_FUNC(SWR); + +static void rpsxLB() +{ + _psxDeleteReg(_Rs_, 1); + _psxOnWriteReg(_Rt_); + _psxDeleteReg(_Rt_, 0); + + MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); + _callFunctionArg1((uptr)psxMemRead8, X86ARG1|MEM_X86TAG, 0); + if (_Rt_) { + MOVSX32R8toR(EAX, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); + } + PSX_DEL_CONST(_Rt_); +} + +static void rpsxLBU() +{ + _psxDeleteReg(_Rs_, 1); + _psxOnWriteReg(_Rt_); + _psxDeleteReg(_Rt_, 0); + + MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); + _callFunctionArg1((uptr)psxMemRead8, X86ARG1|MEM_X86TAG, 0); + if (_Rt_) { + MOVZX32R8toR(EAX, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); + } + PSX_DEL_CONST(_Rt_); +} + +static void rpsxLH() +{ + _psxDeleteReg(_Rs_, 1); + _psxOnWriteReg(_Rt_); + _psxDeleteReg(_Rt_, 0); + + MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); + _callFunctionArg1((uptr)psxMemRead16, X86ARG1|MEM_X86TAG, 0); + if (_Rt_) { + MOVSX32R16toR(EAX, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); + } + PSX_DEL_CONST(_Rt_); +} + +static void rpsxLHU() +{ + _psxDeleteReg(_Rs_, 1); + _psxOnWriteReg(_Rt_); + _psxDeleteReg(_Rt_, 0); + + MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); + _callFunctionArg1((uptr)psxMemRead16, X86ARG1|MEM_X86TAG, 0); + if (_Rt_) { + MOVZX32R16toR(EAX, EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); + } + PSX_DEL_CONST(_Rt_); +} + +static void rpsxLW() +{ + _psxDeleteReg(_Rs_, 1); + _psxOnWriteReg(_Rt_); + _psxDeleteReg(_Rt_, 0); + + _psxFlushCall(FLUSH_EVERYTHING); + MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); + +#ifndef TLB_DEBUG_MEM + TEST32ItoR(X86ARG1, 0x10000000); + j8Ptr[0] = JZ8(0); +#endif + + _callFunctionArg1((uptr)psxMemRead32, X86ARG1|MEM_X86TAG, 0); + if (_Rt_) { + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); + } +#ifndef TLB_DEBUG_MEM + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + + // read from psM directly + AND32ItoR(X86ARG1, 0x1fffff); + ADD32ItoR(X86ARG1, (uptr)psxM); + + MOV32RmtoR( X86ARG1, X86ARG1 ); + MOV32RtoM( (uptr)&psxRegs.GPR.r[_Rt_], X86ARG1); + + x86SetJ8(j8Ptr[1]); +#endif + PSX_DEL_CONST(_Rt_); +} + +static void rpsxSB() +{ + _psxDeleteReg(_Rs_, 1); + _psxDeleteReg(_Rt_, 1); + + MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); + _callFunctionArg2((uptr)psxMemWrite8, X86ARG1|MEM_X86TAG, MEM_MEMORYTAG, 0, (uptr)&psxRegs.GPR.r[_Rt_]); +} + +static void rpsxSH() +{ + _psxDeleteReg(_Rs_, 1); + _psxDeleteReg(_Rt_, 1); + + MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); + _callFunctionArg2((uptr)psxMemWrite16, X86ARG1|MEM_X86TAG, MEM_MEMORYTAG, 0, (uptr)&psxRegs.GPR.r[_Rt_]); +} + +static void rpsxSW() +{ + _psxDeleteReg(_Rs_, 1); + _psxDeleteReg(_Rt_, 1); + + MOV32MtoR(X86ARG1, (uptr)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(X86ARG1, _Imm_); + _callFunctionArg2((uptr)psxMemWrite32, X86ARG1|MEM_X86TAG, MEM_MEMORYTAG, 0, (uptr)&psxRegs.GPR.r[_Rt_]); +} + +#endif // end load store + +//// SLL +void rpsxSLL_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rt_] << _Sa_; +} + +// shifttype: 0 - sll, 1 - srl, 2 - sra +void rpsxShiftConst(int info, int rdreg, int rtreg, int imm, int shifttype) +{ + imm &= 0x1f; + if (imm) { + if( rdreg == rtreg ) { + switch(shifttype) { + case 0: SHL32ItoM((uptr)&psxRegs.GPR.r[rdreg], imm); break; + case 1: SHR32ItoM((uptr)&psxRegs.GPR.r[rdreg], imm); break; + case 2: SAR32ItoM((uptr)&psxRegs.GPR.r[rdreg], imm); break; + } + } + else { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[rtreg]); + switch(shifttype) { + case 0: SHL32ItoR(EAX, imm); break; + case 1: SHR32ItoR(EAX, imm); break; + case 2: SAR32ItoR(EAX, imm); break; + } + MOV32RtoM((uptr)&psxRegs.GPR.r[rdreg], EAX); + } + } + else { + if( rdreg != rtreg ) { + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[rtreg]); + MOV32RtoM((uptr)&psxRegs.GPR.r[rdreg], EAX); + } + } +} + +void rpsxSLL_(int info) { rpsxShiftConst(info, _Rd_, _Rt_, _Sa_, 0); } +PSXRECOMPILE_CONSTCODE2(SLL); + +//// SRL +void rpsxSRL_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rt_] >> _Sa_; +} + +void rpsxSRL_(int info) { rpsxShiftConst(info, _Rd_, _Rt_, _Sa_, 1); } +PSXRECOMPILE_CONSTCODE2(SRL); + +//// SRA +void rpsxSRA_const() +{ + g_psxConstRegs[_Rd_] = *(int*)&g_psxConstRegs[_Rt_] >> _Sa_; +} + +void rpsxSRA_(int info) { rpsxShiftConst(info, _Rd_, _Rt_, _Sa_, 2); } +PSXRECOMPILE_CONSTCODE2(SRA); + +//// SLLV +void rpsxSLLV_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rt_] << (g_psxConstRegs[_Rs_]&0x1f); +} + +void rpsxShiftVconsts(int info, int shifttype) +{ + rpsxShiftConst(info, _Rd_, _Rt_, g_psxConstRegs[_Rs_], shifttype); +} + +void rpsxShiftVconstt(int info, int shifttype) +{ + MOV32ItoR(EAX, g_psxConstRegs[_Rt_]); + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]); + switch(shifttype) { + case 0: SHL32CLtoR(EAX); break; + case 1: SHR32CLtoR(EAX); break; + case 2: SAR32CLtoR(EAX); break; + } + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +void rpsxSLLV_consts(int info) { rpsxShiftVconsts(info, 0); } +void rpsxSLLV_constt(int info) { rpsxShiftVconstt(info, 0); } +void rpsxSLLV_(int info) +{ + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]); + SHL32CLtoR(EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +PSXRECOMPILE_CONSTCODE0(SLLV); + +//// SRLV +void rpsxSRLV_const() +{ + g_psxConstRegs[_Rd_] = g_psxConstRegs[_Rt_] >> (g_psxConstRegs[_Rs_]&0x1f); +} + +void rpsxSRLV_consts(int info) { rpsxShiftVconsts(info, 1); } +void rpsxSRLV_constt(int info) { rpsxShiftVconstt(info, 1); } +void rpsxSRLV_(int info) +{ + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]); + SHR32CLtoR(EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +PSXRECOMPILE_CONSTCODE0(SRLV); + +//// SRAV +void rpsxSRAV_const() +{ + g_psxConstRegs[_Rd_] = *(int*)&g_psxConstRegs[_Rt_] >> (g_psxConstRegs[_Rs_]&0x1f); +} + +void rpsxSRAV_consts(int info) { rpsxShiftVconsts(info, 2); } +void rpsxSRAV_constt(int info) { rpsxShiftVconstt(info, 2); } +void rpsxSRAV_(int info) +{ + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + MOV32MtoR(ECX, (uptr)&psxRegs.GPR.r[_Rs_]); + SAR32CLtoR(EAX); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +PSXRECOMPILE_CONSTCODE0(SRAV); + +extern void rpsxSYSCALL(); +extern void rpsxBREAK(); + +void rpsxMFHI() +{ + if (!_Rd_) return; + + _psxOnWriteReg(_Rd_); + _psxDeleteReg(_Rd_, 0); + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.n.hi); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +void rpsxMTHI() +{ + if( PSX_IS_CONST1(_Rs_) ) { + MOV32ItoM((uptr)&psxRegs.GPR.n.hi, g_psxConstRegs[_Rs_]); + } + else { + _psxDeleteReg(_Rs_, 1); + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + MOV32RtoM((uptr)&psxRegs.GPR.n.hi, EAX); + } +} + +void rpsxMFLO() +{ + if (!_Rd_) return; + + _psxOnWriteReg(_Rd_); + _psxDeleteReg(_Rd_, 0); + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.n.lo); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rd_], EAX); +} + +void rpsxMTLO() +{ + if( PSX_IS_CONST1(_Rs_) ) { + MOV32ItoM((uptr)&psxRegs.GPR.n.hi, g_psxConstRegs[_Rs_]); + } + else { + _psxDeleteReg(_Rs_, 1); + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rs_]); + MOV32RtoM((uptr)&psxRegs.GPR.n.lo, EAX); + } +} + +void rpsxJ() +{ + // j target + u32 newpc = _Target_ * 4 + (psxpc & 0xf0000000); + psxRecompileNextInstruction(1); + psxSetBranchImm(newpc); +} + +void rpsxJAL() +{ + u32 newpc = (_Target_ << 2) + ( psxpc & 0xf0000000 ); + _psxDeleteReg(31, 0); + PSX_SET_CONST(31); + g_psxConstRegs[31] = psxpc + 4; + + psxRecompileNextInstruction(1); + psxSetBranchImm(newpc); +} + +void rpsxJR() +{ + psxSetBranchReg(_Rs_); +} + +void rpsxJALR() +{ + // jalr Rs + _allocX86reg(ESI, X86TYPE_PCWRITEBACK, 0, MODE_WRITE); + _psxMoveGPRtoR(ESI, _Rs_); + + if ( _Rd_ ) + { + _psxDeleteReg(_Rd_, 0); + PSX_SET_CONST(_Rd_); + g_psxConstRegs[_Rd_] = psxpc + 4; + } + + psxRecompileNextInstruction(1); + + if( x86regs[ESI].inuse ) { + assert( x86regs[ESI].type == X86TYPE_PCWRITEBACK ); + MOV32RtoM((uptr)&psxRegs.pc, ESI); + x86regs[ESI].inuse = 0; + } + else { + MOV32MtoR(EAX, (uptr)&g_recWriteback); + MOV32RtoM((uptr)&psxRegs.pc, EAX); + } + + psxSetBranchReg(0xffffffff); +} + +//// BEQ +static void* s_pbranchjmp; +static u32 s_do32 = 0; + +#define JUMPVALID(pjmp) (( x86Ptr - (u8*)pjmp ) <= 0x80) + +void rpsxSetBranchEQ(int info, int process) +{ + if( process & PROCESS_CONSTS ) { + CMP32ItoM( (uptr)&psxRegs.GPR.r[ _Rt_ ], g_psxConstRegs[_Rs_] ); + if( s_do32 ) s_pbranchjmp = JNE32( 0 ); + else s_pbranchjmp = JNE8( 0 ); + } + else if( process & PROCESS_CONSTT ) { + CMP32ItoM( (uptr)&psxRegs.GPR.r[ _Rs_ ], g_psxConstRegs[_Rt_] ); + if( s_do32 ) s_pbranchjmp = JNE32( 0 ); + else s_pbranchjmp = JNE8( 0 ); + } + else { + MOV32MtoR( EAX, (uptr)&psxRegs.GPR.r[ _Rs_ ] ); + CMP32MtoR( EAX, (uptr)&psxRegs.GPR.r[ _Rt_ ] ); + if( s_do32 ) s_pbranchjmp = JNE32( 0 ); + else s_pbranchjmp = JNE8( 0 ); + } +} + +void rpsxBEQ_const() +{ + u32 branchTo; + + if( g_psxConstRegs[_Rs_] == g_psxConstRegs[_Rt_] ) + branchTo = ((s32)_Imm_ * 4) + psxpc; + else + branchTo = psxpc+4; + + psxRecompileNextInstruction(1); + psxSetBranchImm( branchTo ); +} + +void rpsxBEQ_process(int info, int process) +{ + u32 branchTo = ((s32)_Imm_ * 4) + psxpc; + + if ( _Rs_ == _Rt_ ) + { + psxRecompileNextInstruction(1); + psxSetBranchImm( branchTo ); + } + else + { + _psxFlushAllUnused(); + u8* prevx86 = x86Ptr; + s_do32 = 0; + psxSaveBranchState(); + + rpsxSetBranchEQ(info, process); + + psxRecompileNextInstruction(1); + psxSetBranchImm(branchTo); + + if( JUMPVALID(s_pbranchjmp) ) { + x86SetJ8A( (u8*)s_pbranchjmp ); + } + else { + x86Ptr = prevx86; + s_do32 = 1; + psxpc -= 4; + psxRegs.code = *(u32*)PSXM( psxpc - 4 ); + psxLoadBranchState(); + rpsxSetBranchEQ(info, process); + psxRecompileNextInstruction(1); + psxSetBranchImm(branchTo); + x86SetJ32A( (u32*)s_pbranchjmp ); + } + + // recopy the next inst + psxpc -= 4; + psxLoadBranchState(); + psxRecompileNextInstruction(1); + + psxSetBranchImm(psxpc); + } +} + +void rpsxBEQ_(int info) { rpsxBEQ_process(info, 0); } +void rpsxBEQ_consts(int info) { rpsxBEQ_process(info, PROCESS_CONSTS); } +void rpsxBEQ_constt(int info) { rpsxBEQ_process(info, PROCESS_CONSTT); } +PSXRECOMPILE_CONSTCODE3(BEQ, 0); + +//// BNE +void rpsxBNE_const() +{ + u32 branchTo; + + if( g_psxConstRegs[_Rs_] != g_psxConstRegs[_Rt_] ) + branchTo = ((s32)_Imm_ * 4) + psxpc; + else + branchTo = psxpc+4; + + psxRecompileNextInstruction(1); + psxSetBranchImm( branchTo ); +} + +void rpsxBNE_process(int info, int process) +{ + u32 branchTo = ((s32)_Imm_ * 4) + psxpc; + + if ( _Rs_ == _Rt_ ) + { + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + return; + } + + _psxFlushAllUnused(); + u8* prevx86 = x86Ptr; + s_do32 = 0; + rpsxSetBranchEQ(info, process); + + psxSaveBranchState(); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + + if( JUMPVALID(s_pbranchjmp) ) { + x86SetJ8A( (u8*)s_pbranchjmp ); + } + else { + x86Ptr = prevx86; + s_do32 = 1; + psxpc -= 4; + psxRegs.code = *(u32*)PSXM( psxpc - 4 ); + psxLoadBranchState(); + rpsxSetBranchEQ(info, process); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + x86SetJ32A( (u32*)s_pbranchjmp ); + } + + // recopy the next inst + psxpc -= 4; + psxLoadBranchState(); + psxRecompileNextInstruction(1); + + psxSetBranchImm(branchTo); +} + +void rpsxBNE_(int info) { rpsxBNE_process(info, 0); } +void rpsxBNE_consts(int info) { rpsxBNE_process(info, PROCESS_CONSTS); } +void rpsxBNE_constt(int info) { rpsxBNE_process(info, PROCESS_CONSTT); } +PSXRECOMPILE_CONSTCODE3(BNE, 0); + +//// BLTZ +void rpsxBLTZ() +{ + // Branch if Rs < 0 + u32 branchTo = (s32)_Imm_ * 4 + psxpc; + + _psxFlushAllUnused(); + + if( PSX_IS_CONST1(_Rs_) ) { + if( (int)g_psxConstRegs[_Rs_] >= 0 ) + branchTo = psxpc+4; + + psxRecompileNextInstruction(1); + psxSetBranchImm( branchTo ); + return; + } + + CMP32ItoM((uptr)&psxRegs.GPR.r[_Rs_], 0); + u8* prevx86 = x86Ptr; + u8* pjmp = JL8(0); + + psxSaveBranchState(); + psxRecompileNextInstruction(1); + + psxSetBranchImm(psxpc); + + if( JUMPVALID(pjmp) ) { + x86SetJ8A( pjmp ); + } + else { + x86Ptr = prevx86; + psxpc -= 4; + psxRegs.code = *(u32*)PSXM( psxpc - 4 ); + psxLoadBranchState(); + u32* pjmp32 = JL32(0); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + x86SetJ32A( pjmp32 ); + } + + // recopy the next inst + psxpc -= 4; + psxLoadBranchState(); + psxRecompileNextInstruction(1); + + psxSetBranchImm(branchTo); +} + +//// BGEZ +void rpsxBGEZ() +{ + u32 branchTo = ((s32)_Imm_ * 4) + psxpc; + + _psxFlushAllUnused(); + + if( PSX_IS_CONST1(_Rs_) ) { + if ( (int)g_psxConstRegs[_Rs_] < 0 ) + branchTo = psxpc+4; + + psxRecompileNextInstruction(1); + psxSetBranchImm( branchTo ); + return; + } + + CMP32ItoM((uptr)&psxRegs.GPR.r[_Rs_], 0); + u8* prevx86 = x86Ptr; + u8* pjmp = JGE8(0); + + psxSaveBranchState(); + psxRecompileNextInstruction(1); + + psxSetBranchImm(psxpc); + + if( JUMPVALID(pjmp) ) { + x86SetJ8A( pjmp ); + } + else { + x86Ptr = prevx86; + psxpc -= 4; + psxRegs.code = *(u32*)PSXM( psxpc - 4 ); + psxLoadBranchState(); + u32* pjmp32 = JGE32(0); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + x86SetJ32A( pjmp32 ); + } + + // recopy the next inst + psxpc -= 4; + psxLoadBranchState(); + psxRecompileNextInstruction(1); + + psxSetBranchImm(branchTo); +} + +//// BLTZAL +void rpsxBLTZAL() +{ + // Branch if Rs < 0 + u32 branchTo = (s32)_Imm_ * 4 + psxpc; + + _psxFlushConstReg(31); + _psxDeleteReg(31, 0); + _psxFlushAllUnused(); + + if( PSX_IS_CONST1(_Rs_) ) { + if( (int)g_psxConstRegs[_Rs_] >= 0 ) + branchTo = psxpc+4; + else { + PSX_SET_CONST(_Rt_); + g_psxConstRegs[31] = psxpc+4; + } + + psxRecompileNextInstruction(1); + psxSetBranchImm( branchTo ); + return; + } + + CMP32ItoM((uptr)&psxRegs.GPR.r[_Rs_], 0); + u8* prevx86 = x86Ptr; + u8* pjmp = JL8(0); + + psxSaveBranchState(); + + MOV32ItoM((uptr)&psxRegs.GPR.r[31], psxpc+4); + psxRecompileNextInstruction(1); + + psxSetBranchImm(psxpc); + + if( JUMPVALID(pjmp) ) { + x86SetJ8A( pjmp ); + } + else { + x86Ptr = prevx86; + psxpc -= 4; + psxRegs.code = *(u32*)PSXM( psxpc - 4 ); + psxLoadBranchState(); + u32* pjmp32 = JL32(0); + MOV32ItoM((uptr)&psxRegs.GPR.r[31], psxpc+4); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + x86SetJ32A( pjmp32 ); + } + + // recopy the next inst + psxpc -= 4; + psxLoadBranchState(); + psxRecompileNextInstruction(1); + + psxSetBranchImm(branchTo); +} + +//// BGEZAL +void rpsxBGEZAL() +{ + u32 branchTo = ((s32)_Imm_ * 4) + psxpc; + + _psxFlushConstReg(31); + _psxDeleteReg(31, 0); + _psxFlushAllUnused(); + + if( PSX_IS_CONST1(_Rs_) ) { + if( g_psxConstRegs[_Rs_] < 0 ) + branchTo = psxpc+4; + else MOV32ItoM((uptr)&psxRegs.GPR.r[31], psxpc+4); + + psxRecompileNextInstruction(1); + psxSetBranchImm( branchTo ); + return; + } + + CMP32ItoM((uptr)&psxRegs.GPR.r[_Rs_], 0); + u8* prevx86 = x86Ptr; + u8* pjmp = JGE8(0); + + MOV32ItoM((uptr)&psxRegs.GPR.r[31], psxpc+4); + + psxSaveBranchState(); + psxRecompileNextInstruction(1); + + psxSetBranchImm(psxpc); + + if( JUMPVALID(pjmp) ) { + x86SetJ8A( pjmp ); + } + else { + x86Ptr = prevx86; + psxpc -= 4; + psxRegs.code = *(u32*)PSXM( psxpc - 4 ); + psxLoadBranchState(); + u32* pjmp32 = JGE32(0); + MOV32ItoM((uptr)&psxRegs.GPR.r[31], psxpc+4); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + x86SetJ32A( pjmp32 ); + } + + // recopy the next inst + psxpc -= 4; + psxLoadBranchState(); + psxRecompileNextInstruction(1); + + psxSetBranchImm(branchTo); +} + +//// BLEZ +void rpsxBLEZ() +{ + // Branch if Rs <= 0 + u32 branchTo = (s32)_Imm_ * 4 + psxpc; + + _psxFlushAllUnused(); + + if( PSX_IS_CONST1(_Rs_) ) { + if( (int)g_psxConstRegs[_Rs_] > 0 ) + branchTo = psxpc+4; + + psxRecompileNextInstruction(1); + psxSetBranchImm( branchTo ); + return; + } + + _psxDeleteReg(_Rs_, 1); + _clearNeededX86regs(); + + CMP32ItoM((uptr)&psxRegs.GPR.r[_Rs_], 0); + u8* prevx86 = x86Ptr; + u8* pjmp = JLE8(0); + + psxSaveBranchState(); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + + if( JUMPVALID(pjmp) ) { + x86SetJ8A( pjmp ); + } + else { + x86Ptr = prevx86; + psxpc -= 4; + psxRegs.code = *(u32*)PSXM( psxpc - 4 ); + psxLoadBranchState(); + u32* pjmp32 = JLE32(0); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + x86SetJ32A( pjmp32 ); + } + + psxpc -= 4; + psxLoadBranchState(); + psxRecompileNextInstruction(1); + psxSetBranchImm(branchTo); +} + +//// BGTZ +void rpsxBGTZ() +{ + // Branch if Rs > 0 + u32 branchTo = (s32)_Imm_ * 4 + psxpc; + + _psxFlushAllUnused(); + + if( PSX_IS_CONST1(_Rs_) ) { + if( (int)g_psxConstRegs[_Rs_] <= 0 ) + branchTo = psxpc+4; + + psxRecompileNextInstruction(1); + psxSetBranchImm( branchTo ); + return; + } + + _psxDeleteReg(_Rs_, 1); + _clearNeededX86regs(); + + CMP32ItoM((uptr)&psxRegs.GPR.r[_Rs_], 0); + u8* prevx86 = x86Ptr; + u8* pjmp = JG8(0); + + psxSaveBranchState(); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + + if( JUMPVALID(pjmp) ) { + x86SetJ8A( pjmp ); + } + else { + x86Ptr = prevx86; + psxpc -= 4; + psxRegs.code = *(u32*)PSXM( psxpc - 4 ); + psxLoadBranchState(); + u32* pjmp32 = JG32(0); + psxRecompileNextInstruction(1); + psxSetBranchImm(psxpc); + x86SetJ32A( pjmp32 ); + } + + psxpc -= 4; + psxLoadBranchState(); + psxRecompileNextInstruction(1); + psxSetBranchImm(branchTo); +} + +void rpsxMFC0() +{ + // Rt = Cop0->Rd + if (!_Rt_) return; + + _psxOnWriteReg(_Rt_); + MOV32MtoR(EAX, (uptr)&psxRegs.CP0.r[_Rd_]); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); +} + +void rpsxCFC0() +{ + // Rt = Cop0->Rd + if (!_Rt_) return; + + _psxOnWriteReg(_Rt_); + MOV32MtoR(EAX, (uptr)&psxRegs.CP0.r[_Rd_]); + MOV32RtoM((uptr)&psxRegs.GPR.r[_Rt_], EAX); +} + +void rpsxMTC0() +{ + // Cop0->Rd = Rt + if( PSX_IS_CONST1(_Rt_) ) { + MOV32ItoM((uptr)&psxRegs.CP0.r[_Rd_], g_psxConstRegs[_Rt_]); + } + else { + _psxDeleteReg(_Rt_, 1); + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[_Rt_]); + MOV32RtoM((uptr)&psxRegs.CP0.r[_Rd_], EAX); + } +} + +void rpsxCTC0() +{ + // Cop0->Rd = Rt + rpsxMTC0(); +} + +void rpsxRFE() +{ + MOV32MtoR(EAX, (uptr)&psxRegs.CP0.n.Status); + MOV32RtoR(ECX, EAX); + AND32ItoR(EAX, 0xfffffff0); + AND32ItoR(ECX, 0x3c); + SHR32ItoR(ECX, 2); + OR32RtoR (EAX, ECX); + MOV32RtoM((uptr)&psxRegs.CP0.n.Status, EAX); + + // Test the IOP's INTC status, so that any pending ints get raised. + + _psxFlushCall(0); + CALLFunc( (uptr)&iopTestIntc ); +} + +// R3000A tables +extern void (*rpsxBSC[64])(); +extern void (*rpsxSPC[64])(); +extern void (*rpsxREG[32])(); +extern void (*rpsxCP0[32])(); +extern void (*rpsxCP2[64])(); +extern void (*rpsxCP2BSC[32])(); + +static void rpsxSPECIAL() { rpsxSPC[_Funct_](); } +static void rpsxREGIMM() { rpsxREG[_Rt_](); } +static void rpsxCOP0() { rpsxCP0[_Rs_](); } +//static void rpsxBASIC() { rpsxCP2BSC[_Rs_](); } + +static void rpsxNULL() { + SysPrintf("psxUNK: %8.8x\n", psxRegs.code); +} + +void (*rpsxBSC[64])() = { + rpsxSPECIAL, rpsxREGIMM, rpsxJ , rpsxJAL , rpsxBEQ , rpsxBNE , rpsxBLEZ, rpsxBGTZ, + rpsxADDI , rpsxADDIU , rpsxSLTI, rpsxSLTIU, rpsxANDI, rpsxORI , rpsxXORI, rpsxLUI , + rpsxCOP0 , rpsxNULL , rpsxNULL, rpsxNULL , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxLB , rpsxLH , rpsxLWL , rpsxLW , rpsxLBU , rpsxLHU , rpsxLWR , rpsxNULL, + rpsxSB , rpsxSH , rpsxSWL , rpsxSW , rpsxNULL, rpsxNULL, rpsxSWR , rpsxNULL, + rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL +}; + +void (*rpsxSPC[64])() = { + rpsxSLL , rpsxNULL, rpsxSRL , rpsxSRA , rpsxSLLV , rpsxNULL , rpsxSRLV, rpsxSRAV, + rpsxJR , rpsxJALR, rpsxNULL, rpsxNULL, rpsxSYSCALL, rpsxBREAK, rpsxNULL, rpsxNULL, + rpsxMFHI, rpsxMTHI, rpsxMFLO, rpsxMTLO, rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL, + rpsxMULT, rpsxMULTU, rpsxDIV, rpsxDIVU, rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL, + rpsxADD , rpsxADDU, rpsxSUB , rpsxSUBU, rpsxAND , rpsxOR , rpsxXOR , rpsxNOR , + rpsxNULL, rpsxNULL, rpsxSLT , rpsxSLTU, rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL +}; + +void (*rpsxREG[32])() = { + rpsxBLTZ , rpsxBGEZ , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxBLTZAL, rpsxBGEZAL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL , rpsxNULL , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL +}; + +void (*rpsxCP0[32])() = { + rpsxMFC0, rpsxNULL, rpsxCFC0, rpsxNULL, rpsxMTC0, rpsxNULL, rpsxCTC0, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxRFE , rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL +}; + +// coissued insts +void (*rpsxBSC_co[64] )() = { + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, + rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, rpsxNULL, +}; + +//////////////////////////////////////////////// +// Back-Prob Function Tables - Gathering Info // +//////////////////////////////////////////////// +#define rpsxpropSetRead(reg) { \ + if( !(pinst->regs[reg] & EEINST_USED) ) \ + pinst->regs[reg] |= EEINST_LASTUSE; \ + prev->regs[reg] |= EEINST_LIVE0|EEINST_USED; \ + pinst->regs[reg] |= EEINST_USED; \ + _recFillRegister(*pinst, XMMTYPE_GPRREG, reg, 0); \ +} \ + +#define rpsxpropSetWrite(reg) { \ + prev->regs[reg] &= ~EEINST_LIVE0; \ + if( !(pinst->regs[reg] & EEINST_USED) ) \ + pinst->regs[reg] |= EEINST_LASTUSE; \ + pinst->regs[reg] |= EEINST_USED; \ + prev->regs[reg] |= EEINST_USED; \ + _recFillRegister(*pinst, XMMTYPE_GPRREG, reg, 1); \ +} + +void rpsxpropBSC(EEINST* prev, EEINST* pinst); +void rpsxpropSPECIAL(EEINST* prev, EEINST* pinst); +void rpsxpropREGIMM(EEINST* prev, EEINST* pinst); +void rpsxpropCP0(EEINST* prev, EEINST* pinst); +void rpsxpropCP2(EEINST* prev, EEINST* pinst); + +//SPECIAL, REGIMM, J , JAL , BEQ , BNE , BLEZ, BGTZ, +//ADDI , ADDIU , SLTI, SLTIU, ANDI, ORI , XORI, LUI , +//COP0 , NULL , COP2, NULL , NULL, NULL, NULL, NULL, +//NULL , NULL , NULL, NULL , NULL, NULL, NULL, NULL, +//LB , LH , LWL , LW , LBU , LHU , LWR , NULL, +//SB , SH , SWL , SW , NULL, NULL, SWR , NULL, +//NULL , NULL , NULL, NULL , NULL, NULL, NULL, NULL, +//NULL , NULL , NULL, NULL , NULL, NULL, NULL, NULL +void rpsxpropBSC(EEINST* prev, EEINST* pinst) +{ + switch(psxRegs.code >> 26) { + case 0: rpsxpropSPECIAL(prev, pinst); break; + case 1: rpsxpropREGIMM(prev, pinst); break; + case 2: // j + break; + case 3: // jal + rpsxpropSetWrite(31); + break; + case 4: // beq + case 5: // bne + rpsxpropSetRead(_Rs_); + rpsxpropSetRead(_Rt_); + break; + + case 6: // blez + case 7: // bgtz + rpsxpropSetRead(_Rs_); + break; + + case 15: // lui + rpsxpropSetWrite(_Rt_); + break; + + case 16: rpsxpropCP0(prev, pinst); break; + case 18: assert(0); break; + + // stores + case 40: case 41: case 42: case 43: case 46: + rpsxpropSetRead(_Rt_); + rpsxpropSetRead(_Rs_); + break; + + default: + rpsxpropSetWrite(_Rt_); + rpsxpropSetRead(_Rs_); + break; + } +} + +//SLL , NULL, SRL , SRA , SLLV , NULL , SRLV, SRAV, +//JR , JALR, NULL, NULL, SYSCALL, BREAK, NULL, NULL, +//MFHI, MTHI, MFLO, MTLO, NULL , NULL , NULL, NULL, +//MULT, MULTU, DIV, DIVU, NULL , NULL , NULL, NULL, +//ADD , ADDU, SUB , SUBU, AND , OR , XOR , NOR , +//NULL, NULL, SLT , SLTU, NULL , NULL , NULL, NULL, +//NULL, NULL, NULL, NULL, NULL , NULL , NULL, NULL, +//NULL, NULL, NULL, NULL, NULL , NULL , NULL, NULL +void rpsxpropSPECIAL(EEINST* prev, EEINST* pinst) +{ + switch(_Funct_) { + case 0: // SLL + case 2: // SRL + case 3: // SRA + rpsxpropSetWrite(_Rd_); + rpsxpropSetRead(_Rt_); + break; + + case 8: // JR + rpsxpropSetRead(_Rs_); + break; + case 9: // JALR + rpsxpropSetWrite(_Rd_); + rpsxpropSetRead(_Rs_); + break; + + case 12: // syscall + case 13: // break + _recClearInst(prev); + prev->info = 0; + break; + case 15: // sync + break; + + case 16: // mfhi + rpsxpropSetWrite(_Rd_); + rpsxpropSetRead(PSX_HI); + break; + case 17: // mthi + rpsxpropSetWrite(PSX_HI); + rpsxpropSetRead(_Rs_); + break; + case 18: // mflo + rpsxpropSetWrite(_Rd_); + rpsxpropSetRead(PSX_LO); + break; + case 19: // mtlo + rpsxpropSetWrite(PSX_LO); + rpsxpropSetRead(_Rs_); + break; + + case 24: // mult + case 25: // multu + case 26: // div + case 27: // divu + rpsxpropSetWrite(PSX_LO); + rpsxpropSetWrite(PSX_HI); + rpsxpropSetRead(_Rs_); + rpsxpropSetRead(_Rt_); + break; + + case 32: // add + case 33: // addu + case 34: // sub + case 35: // subu + rpsxpropSetWrite(_Rd_); + if( _Rs_ ) rpsxpropSetRead(_Rs_); + if( _Rt_ ) rpsxpropSetRead(_Rt_); + break; + + default: + rpsxpropSetWrite(_Rd_); + rpsxpropSetRead(_Rs_); + rpsxpropSetRead(_Rt_); + break; + } +} + +//BLTZ , BGEZ , NULL, NULL, NULL, NULL, NULL, NULL, +//NULL , NULL , NULL, NULL, NULL, NULL, NULL, NULL, +//BLTZAL, BGEZAL, NULL, NULL, NULL, NULL, NULL, NULL, +//NULL , NULL , NULL, NULL, NULL, NULL, NULL, NULL +void rpsxpropREGIMM(EEINST* prev, EEINST* pinst) +{ + switch(_Rt_) { + case 0: // bltz + case 1: // bgez + rpsxpropSetRead(_Rs_); + break; + + case 16: // bltzal + case 17: // bgezal + // do not write 31 + rpsxpropSetRead(_Rs_); + break; + + jNO_DEFAULT + } +} + +//MFC0, NULL, CFC0, NULL, MTC0, NULL, CTC0, NULL, +//NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +//RFE , NULL, NULL, NULL, NULL, NULL, NULL, NULL, +//NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +void rpsxpropCP0(EEINST* prev, EEINST* pinst) +{ + switch(_Rs_) { + case 0: // mfc0 + case 2: // cfc0 + rpsxpropSetWrite(_Rt_); + break; + + case 4: // mtc0 + case 6: // ctc0 + rpsxpropSetRead(_Rt_); + break; + case 16: // rfe + break; + + jNO_DEFAULT + } +} diff --git a/pcsx2/x86/iR5900.h b/pcsx2/x86/iR5900.h index a33e1765f6..3dcae15a7c 100644 --- a/pcsx2/x86/iR5900.h +++ b/pcsx2/x86/iR5900.h @@ -1,316 +1,316 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __IR5900_H__ -#define __IR5900_H__ - -#include "R5900.h" -#include "VU.h" -#include "iCore.h" -#include "BaseblockEx.h" // needed for recClear and stuff - -// Yay! These work now! (air) -#define ARITHMETICIMM_RECOMPILE -#define ARITHMETIC_RECOMPILE -#define MULTDIV_RECOMPILE -#define SHIFT_RECOMPILE -#define BRANCH_RECOMPILE -#define JUMP_RECOMPILE -#define LOADSTORE_RECOMPILE -#define MOVE_RECOMPILE -#define MMI_RECOMPILE -#define MMI0_RECOMPILE -#define MMI1_RECOMPILE -#define MMI2_RECOMPILE -#define MMI3_RECOMPILE -#define FPU_RECOMPILE -#define CP0_RECOMPILE -#define CP2_RECOMPILE - -#define EE_CONST_PROP // rec2 - enables constant propagation (faster) - -#define PC_GETBLOCK(x) PC_GETBLOCK_(x, recLUT) - -extern u32 pc; -extern int branch; -extern uptr* recLUT; - -extern u32 maxrecmem; -extern u32 pc; // recompiler pc (also used by the SuperVU! .. why? (air)) -extern int branch; // set for branch (also used by the SuperVU! .. why? (air)) -extern u32 target; // branch target -extern u32 s_nBlockCycles; // cycles of current block recompiling -extern u32 s_saveConstGPRreg; -extern GPR_reg64 s_ConstGPRreg; - -#define REC_FUNC( f ) \ - void rec##f( void ) \ - { \ - MOV32ItoM( (uptr)&cpuRegs.code, (u32)cpuRegs.code ); \ - MOV32ItoM( (uptr)&cpuRegs.pc, (u32)pc ); \ - iFlushCall(FLUSH_EVERYTHING); \ - CALLFunc( (uptr)Interp::f ); \ - } - -#define REC_FUNC_DEL( f, delreg ) \ - void rec##f( void ) \ -{ \ - MOV32ItoM( (uptr)&cpuRegs.code, (u32)cpuRegs.code ); \ - MOV32ItoM( (uptr)&cpuRegs.pc, (u32)pc ); \ - iFlushCall(FLUSH_EVERYTHING); \ - if( (delreg) > 0 ) _deleteEEreg(delreg, 0); \ - CALLFunc( (uptr)Interp::f ); \ -} - -#define REC_SYS( f ) \ - void rec##f( void ) \ - { \ - MOV32ItoM( (uptr)&cpuRegs.code, (u32)cpuRegs.code ); \ - MOV32ItoM( (uptr)&cpuRegs.pc, (u32)pc ); \ - iFlushCall(FLUSH_EVERYTHING); \ - CALLFunc( (uptr)Interp::f ); \ - branch = 2; \ - } - - -// Used to clear recompiled code blocks during memory/dma write operations. -void recClearMem(BASEBLOCK* p); -void REC_CLEARM( u32 mem ); - -// used when processing branches -void SaveBranchState(); -void LoadBranchState(); - -void recompileNextInstruction(int delayslot); -void SetBranchReg( u32 reg ); -void SetBranchImm( u32 imm ); -u32 eeScaleBlockCycles(); - -void iFlushCall(int flushtype); -void recBranchCall( void (*func)() ); -void recCall( void (*func)(), int delreg ); - -// these are defined in iFPU.cpp -void LoadCW(); -void SaveCW(int type); - -extern void recExecute(); // same as recCpu.Execute(), but faster (can be inline'd) - -namespace R5900{ -namespace Dynarec { -extern void recDoBranchImm( u32* jmpSkip, bool isLikely = false ); -extern void recDoBranchImm_Likely( u32* jmpSkip ); -} } - -//////////////////////////////////////////////////////////////////// -// Constant Propagation - From here to the end of the header! - -#define GPR_IS_CONST1(reg) ((reg)<32 && (g_cpuHasConstReg&(1<<(reg)))) -#define GPR_IS_CONST2(reg1, reg2) ((g_cpuHasConstReg&(1<<(reg1)))&&(g_cpuHasConstReg&(1<<(reg2)))) -#define GPR_SET_CONST(reg) { \ - if( (reg) < 32 ) { \ - g_cpuHasConstReg |= (1<<(reg)); \ - g_cpuFlushedConstReg &= ~(1<<(reg)); \ - } \ -} - -#define GPR_DEL_CONST(reg) { \ - if( (reg) < 32 ) g_cpuHasConstReg &= ~(1<<(reg)); \ -} - -extern void (*recBSC_co[64])(); -extern PCSX2_ALIGNED16_DECL(GPR_reg64 g_cpuConstRegs[32]); -extern u32 g_cpuHasConstReg, g_cpuFlushedConstReg; - -// gets a memory pointer to the constant reg -u32* _eeGetConstReg(int reg); - -// finds where the GPR is stored and moves lower 32 bits to EAX -void _eeMoveGPRtoR(x86IntRegType to, int fromgpr); -void _eeMoveGPRtoM(u32 to, int fromgpr); -void _eeMoveGPRtoRm(x86IntRegType to, int fromgpr); - -void _eeFlushAllUnused(); -void _eeOnWriteReg(int reg, int signext); - -// totally deletes from const, xmm, and mmx entries -// if flush is 1, also flushes to memory -// if 0, only flushes if not an xmm reg (used when overwriting lower 64bits of reg) -void _deleteEEreg(int reg, int flush); - -// allocates memory on the instruction size and returns the pointer -u32* recAllocStackMem(int size, int align); - -void _vuRegsCOP22(VURegs * VU, _VURegsNum *VUregsn); - -////////////////////////////////////// -// Templates for code recompilation // -////////////////////////////////////// - -typedef void (*R5900FNPTR)(); -typedef void (*R5900FNPTR_INFO)(int info); - -#define EERECOMPILE_CODE0(fn, xmminfo) \ -void rec##fn(void) \ -{ \ - eeRecompileCode0(rec##fn##_const, rec##fn##_consts, rec##fn##_constt, rec##fn##_, xmminfo); \ -} - -#define EERECOMPILE_CODEX(codename, fn) \ -void rec##fn(void) \ -{ \ - codename(rec##fn##_const, rec##fn##_); \ -} - -// -// MMX/XMM caching helpers -// - -// rd = rs op rt -void eeRecompileCode0(R5900FNPTR constcode, R5900FNPTR_INFO constscode, R5900FNPTR_INFO consttcode, R5900FNPTR_INFO noconstcode, int xmminfo); -// rt = rs op imm16 -void eeRecompileCode1(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode); -// rd = rt op sa -void eeRecompileCode2(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode); -// rt op rs (SPECIAL) -void eeRecompileCode3(R5900FNPTR constcode, R5900FNPTR_INFO multicode); - -// -// non mmx/xmm version, slower -// -// rd = rs op rt -#define EERECOMPILE_CONSTCODE0(fn) \ -void rec##fn(void) \ -{ \ - eeRecompileCodeConst0(rec##fn##_const, rec##fn##_consts, rec##fn##_constt, rec##fn##_); \ -} \ - -// rt = rs op imm16 -#define EERECOMPILE_CONSTCODE1(fn) \ -void rec##fn(void) \ -{ \ - eeRecompileCodeConst1(rec##fn##_const, rec##fn##_); \ -} \ - -// rd = rt op sa -#define EERECOMPILE_CONSTCODE2(fn) \ -void rec##fn(void) \ -{ \ - eeRecompileCodeConst2(rec##fn##_const, rec##fn##_); \ -} \ - -// rd = rt op rs -#define EERECOMPILE_CONSTCODESPECIAL(fn, mult) \ -void rec##fn(void) \ -{ \ - eeRecompileCodeConstSPECIAL(rec##fn##_const, rec##fn##_, mult); \ -} \ - -// rd = rs op rt -void eeRecompileCodeConst0(R5900FNPTR constcode, R5900FNPTR_INFO constscode, R5900FNPTR_INFO consttcode, R5900FNPTR_INFO noconstcode); -// rt = rs op imm16 -void eeRecompileCodeConst1(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode); -// rd = rt op sa -void eeRecompileCodeConst2(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode); -// rd = rt MULT rs (SPECIAL) -void eeRecompileCodeConstSPECIAL(R5900FNPTR constcode, R5900FNPTR_INFO multicode, int MULT); - -// XMM caching helpers -#define XMMINFO_READLO 0x01 -#define XMMINFO_READHI 0x02 -#define XMMINFO_WRITELO 0x04 -#define XMMINFO_WRITEHI 0x08 -#define XMMINFO_WRITED 0x10 -#define XMMINFO_READD 0x20 -#define XMMINFO_READS 0x40 -#define XMMINFO_READT 0x80 -#define XMMINFO_READD_LO 0x100 // if set and XMMINFO_READD is set, reads only low 64 bits of D -#define XMMINFO_READACC 0x200 -#define XMMINFO_WRITEACC 0x400 - -#define CPU_SSE_XMMCACHE_START(xmminfo) \ - { \ - int info = eeRecompileCodeXMM(xmminfo); \ - -#define CPU_SSE2_XMMCACHE_START(xmminfo) \ - { \ - int info = eeRecompileCodeXMM(xmminfo); \ - -#define CPU_SSE_XMMCACHE_END \ - _clearNeededXMMregs(); \ - return; \ - } \ - -#define FPURECOMPILE_CONSTCODE(fn, xmminfo) \ -void rec##fn(void) \ -{ \ - eeFPURecompileCode(rec##fn##_xmm, R5900::Interpreter::OpcodeImpl::COP1::fn, xmminfo); \ -} - -// rd = rs op rt (all regs need to be in xmm) -int eeRecompileCodeXMM(int xmminfo); -void eeFPURecompileCode(R5900FNPTR_INFO xmmcode, R5900FNPTR fpucode, int xmminfo); - - -// For propagation of BSC stuff. -// Code implementations in ir5900tables.c -class BSCPropagate -{ -protected: - EEINST& prev; - EEINST& pinst; - -public: - BSCPropagate( EEINST& previous, EEINST& pinstance ); - - void rprop(); - -protected: - void rpropSPECIAL(); - void rpropREGIMM(); - void rpropCP0(); - void rpropCP1(); - void rpropCP2(); - void rpropMMI(); - void rpropMMI0(); - void rpropMMI1(); - void rpropMMI2(); - void rpropMMI3(); - - void rpropSetRead( int reg, int mask ); - void rpropSetFPURead( int reg, int mask ); - void rpropSetWrite( int reg, int mask ); - void rpropSetFPUWrite( int reg, int mask ); - - template< int mask > - void rpropSetRead( int reg ); - - template< int live > - void rpropSetWrite0( int reg, int mask ); - - void rpropSetFast( int write1, int read1, int read2, int mask ); - - template< int low, int hi > - void rpropSetLOHI( int write1, int read1, int read2, int mask ); - - template< int live > - void rpropSetFPUWrite0( int reg, int mask ); - -}; - -#endif // __IR5900_H__ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __IR5900_H__ +#define __IR5900_H__ + +#include "R5900.h" +#include "VU.h" +#include "iCore.h" +#include "BaseblockEx.h" // needed for recClear and stuff + +// Yay! These work now! (air) +#define ARITHMETICIMM_RECOMPILE +#define ARITHMETIC_RECOMPILE +#define MULTDIV_RECOMPILE +#define SHIFT_RECOMPILE +#define BRANCH_RECOMPILE +#define JUMP_RECOMPILE +#define LOADSTORE_RECOMPILE +#define MOVE_RECOMPILE +#define MMI_RECOMPILE +#define MMI0_RECOMPILE +#define MMI1_RECOMPILE +#define MMI2_RECOMPILE +#define MMI3_RECOMPILE +#define FPU_RECOMPILE +#define CP0_RECOMPILE +#define CP2_RECOMPILE + +#define EE_CONST_PROP // rec2 - enables constant propagation (faster) + +#define PC_GETBLOCK(x) PC_GETBLOCK_(x, recLUT) + +extern u32 pc; +extern int branch; +extern uptr* recLUT; + +extern u32 maxrecmem; +extern u32 pc; // recompiler pc (also used by the SuperVU! .. why? (air)) +extern int branch; // set for branch (also used by the SuperVU! .. why? (air)) +extern u32 target; // branch target +extern u32 s_nBlockCycles; // cycles of current block recompiling +extern u32 s_saveConstGPRreg; +extern GPR_reg64 s_ConstGPRreg; + +#define REC_FUNC( f ) \ + void rec##f( void ) \ + { \ + MOV32ItoM( (uptr)&cpuRegs.code, (u32)cpuRegs.code ); \ + MOV32ItoM( (uptr)&cpuRegs.pc, (u32)pc ); \ + iFlushCall(FLUSH_EVERYTHING); \ + CALLFunc( (uptr)Interp::f ); \ + } + +#define REC_FUNC_DEL( f, delreg ) \ + void rec##f( void ) \ +{ \ + MOV32ItoM( (uptr)&cpuRegs.code, (u32)cpuRegs.code ); \ + MOV32ItoM( (uptr)&cpuRegs.pc, (u32)pc ); \ + iFlushCall(FLUSH_EVERYTHING); \ + if( (delreg) > 0 ) _deleteEEreg(delreg, 0); \ + CALLFunc( (uptr)Interp::f ); \ +} + +#define REC_SYS( f ) \ + void rec##f( void ) \ + { \ + MOV32ItoM( (uptr)&cpuRegs.code, (u32)cpuRegs.code ); \ + MOV32ItoM( (uptr)&cpuRegs.pc, (u32)pc ); \ + iFlushCall(FLUSH_EVERYTHING); \ + CALLFunc( (uptr)Interp::f ); \ + branch = 2; \ + } + + +// Used to clear recompiled code blocks during memory/dma write operations. +void recClearMem(BASEBLOCK* p); +void REC_CLEARM( u32 mem ); + +// used when processing branches +void SaveBranchState(); +void LoadBranchState(); + +void recompileNextInstruction(int delayslot); +void SetBranchReg( u32 reg ); +void SetBranchImm( u32 imm ); +u32 eeScaleBlockCycles(); + +void iFlushCall(int flushtype); +void recBranchCall( void (*func)() ); +void recCall( void (*func)(), int delreg ); + +// these are defined in iFPU.cpp +void LoadCW(); +void SaveCW(int type); + +extern void recExecute(); // same as recCpu.Execute(), but faster (can be inline'd) + +namespace R5900{ +namespace Dynarec { +extern void recDoBranchImm( u32* jmpSkip, bool isLikely = false ); +extern void recDoBranchImm_Likely( u32* jmpSkip ); +} } + +//////////////////////////////////////////////////////////////////// +// Constant Propagation - From here to the end of the header! + +#define GPR_IS_CONST1(reg) ((reg)<32 && (g_cpuHasConstReg&(1<<(reg)))) +#define GPR_IS_CONST2(reg1, reg2) ((g_cpuHasConstReg&(1<<(reg1)))&&(g_cpuHasConstReg&(1<<(reg2)))) +#define GPR_SET_CONST(reg) { \ + if( (reg) < 32 ) { \ + g_cpuHasConstReg |= (1<<(reg)); \ + g_cpuFlushedConstReg &= ~(1<<(reg)); \ + } \ +} + +#define GPR_DEL_CONST(reg) { \ + if( (reg) < 32 ) g_cpuHasConstReg &= ~(1<<(reg)); \ +} + +extern void (*recBSC_co[64])(); +extern PCSX2_ALIGNED16_DECL(GPR_reg64 g_cpuConstRegs[32]); +extern u32 g_cpuHasConstReg, g_cpuFlushedConstReg; + +// gets a memory pointer to the constant reg +u32* _eeGetConstReg(int reg); + +// finds where the GPR is stored and moves lower 32 bits to EAX +void _eeMoveGPRtoR(x86IntRegType to, int fromgpr); +void _eeMoveGPRtoM(u32 to, int fromgpr); +void _eeMoveGPRtoRm(x86IntRegType to, int fromgpr); + +void _eeFlushAllUnused(); +void _eeOnWriteReg(int reg, int signext); + +// totally deletes from const, xmm, and mmx entries +// if flush is 1, also flushes to memory +// if 0, only flushes if not an xmm reg (used when overwriting lower 64bits of reg) +void _deleteEEreg(int reg, int flush); + +// allocates memory on the instruction size and returns the pointer +u32* recAllocStackMem(int size, int align); + +void _vuRegsCOP22(VURegs * VU, _VURegsNum *VUregsn); + +////////////////////////////////////// +// Templates for code recompilation // +////////////////////////////////////// + +typedef void (*R5900FNPTR)(); +typedef void (*R5900FNPTR_INFO)(int info); + +#define EERECOMPILE_CODE0(fn, xmminfo) \ +void rec##fn(void) \ +{ \ + eeRecompileCode0(rec##fn##_const, rec##fn##_consts, rec##fn##_constt, rec##fn##_, xmminfo); \ +} + +#define EERECOMPILE_CODEX(codename, fn) \ +void rec##fn(void) \ +{ \ + codename(rec##fn##_const, rec##fn##_); \ +} + +// +// MMX/XMM caching helpers +// + +// rd = rs op rt +void eeRecompileCode0(R5900FNPTR constcode, R5900FNPTR_INFO constscode, R5900FNPTR_INFO consttcode, R5900FNPTR_INFO noconstcode, int xmminfo); +// rt = rs op imm16 +void eeRecompileCode1(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode); +// rd = rt op sa +void eeRecompileCode2(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode); +// rt op rs (SPECIAL) +void eeRecompileCode3(R5900FNPTR constcode, R5900FNPTR_INFO multicode); + +// +// non mmx/xmm version, slower +// +// rd = rs op rt +#define EERECOMPILE_CONSTCODE0(fn) \ +void rec##fn(void) \ +{ \ + eeRecompileCodeConst0(rec##fn##_const, rec##fn##_consts, rec##fn##_constt, rec##fn##_); \ +} \ + +// rt = rs op imm16 +#define EERECOMPILE_CONSTCODE1(fn) \ +void rec##fn(void) \ +{ \ + eeRecompileCodeConst1(rec##fn##_const, rec##fn##_); \ +} \ + +// rd = rt op sa +#define EERECOMPILE_CONSTCODE2(fn) \ +void rec##fn(void) \ +{ \ + eeRecompileCodeConst2(rec##fn##_const, rec##fn##_); \ +} \ + +// rd = rt op rs +#define EERECOMPILE_CONSTCODESPECIAL(fn, mult) \ +void rec##fn(void) \ +{ \ + eeRecompileCodeConstSPECIAL(rec##fn##_const, rec##fn##_, mult); \ +} \ + +// rd = rs op rt +void eeRecompileCodeConst0(R5900FNPTR constcode, R5900FNPTR_INFO constscode, R5900FNPTR_INFO consttcode, R5900FNPTR_INFO noconstcode); +// rt = rs op imm16 +void eeRecompileCodeConst1(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode); +// rd = rt op sa +void eeRecompileCodeConst2(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode); +// rd = rt MULT rs (SPECIAL) +void eeRecompileCodeConstSPECIAL(R5900FNPTR constcode, R5900FNPTR_INFO multicode, int MULT); + +// XMM caching helpers +#define XMMINFO_READLO 0x01 +#define XMMINFO_READHI 0x02 +#define XMMINFO_WRITELO 0x04 +#define XMMINFO_WRITEHI 0x08 +#define XMMINFO_WRITED 0x10 +#define XMMINFO_READD 0x20 +#define XMMINFO_READS 0x40 +#define XMMINFO_READT 0x80 +#define XMMINFO_READD_LO 0x100 // if set and XMMINFO_READD is set, reads only low 64 bits of D +#define XMMINFO_READACC 0x200 +#define XMMINFO_WRITEACC 0x400 + +#define CPU_SSE_XMMCACHE_START(xmminfo) \ + { \ + int info = eeRecompileCodeXMM(xmminfo); \ + +#define CPU_SSE2_XMMCACHE_START(xmminfo) \ + { \ + int info = eeRecompileCodeXMM(xmminfo); \ + +#define CPU_SSE_XMMCACHE_END \ + _clearNeededXMMregs(); \ + return; \ + } \ + +#define FPURECOMPILE_CONSTCODE(fn, xmminfo) \ +void rec##fn(void) \ +{ \ + eeFPURecompileCode(rec##fn##_xmm, R5900::Interpreter::OpcodeImpl::COP1::fn, xmminfo); \ +} + +// rd = rs op rt (all regs need to be in xmm) +int eeRecompileCodeXMM(int xmminfo); +void eeFPURecompileCode(R5900FNPTR_INFO xmmcode, R5900FNPTR fpucode, int xmminfo); + + +// For propagation of BSC stuff. +// Code implementations in ir5900tables.c +class BSCPropagate +{ +protected: + EEINST& prev; + EEINST& pinst; + +public: + BSCPropagate( EEINST& previous, EEINST& pinstance ); + + void rprop(); + +protected: + void rpropSPECIAL(); + void rpropREGIMM(); + void rpropCP0(); + void rpropCP1(); + void rpropCP2(); + void rpropMMI(); + void rpropMMI0(); + void rpropMMI1(); + void rpropMMI2(); + void rpropMMI3(); + + void rpropSetRead( int reg, int mask ); + void rpropSetFPURead( int reg, int mask ); + void rpropSetWrite( int reg, int mask ); + void rpropSetFPUWrite( int reg, int mask ); + + template< int mask > + void rpropSetRead( int reg ); + + template< int live > + void rpropSetWrite0( int reg, int mask ); + + void rpropSetFast( int write1, int read1, int read2, int mask ); + + template< int low, int hi > + void rpropSetLOHI( int write1, int read1, int read2, int mask ); + + template< int live > + void rpropSetFPUWrite0( int reg, int mask ); + +}; + +#endif // __IR5900_H__ diff --git a/pcsx2/x86/iR5900Arit.h b/pcsx2/x86/iR5900Arit.h index e39d9bd460..bce084c164 100644 --- a/pcsx2/x86/iR5900Arit.h +++ b/pcsx2/x86/iR5900Arit.h @@ -1,46 +1,46 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __IR5900ARIT_H__ -#define __IR5900ARIT_H__ - -/********************************************************* -* Register arithmetic * -* Format: OP rd, rs, rt * -*********************************************************/ - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl -{ - void recADD( void ); - void recADDU( void ); - void recDADD( void ); - void recDADDU( void ); - void recSUB( void ); - void recSUBU( void ); - void recDSUB( void ); - void recDSUBU( void ); - void recAND( void ); - void recOR( void ); - void recXOR( void ); - void recNOR( void ); - void recSLT( void ); - void recSLTU( void ); -} } } -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __IR5900ARIT_H__ +#define __IR5900ARIT_H__ + +/********************************************************* +* Register arithmetic * +* Format: OP rd, rs, rt * +*********************************************************/ + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl +{ + void recADD( void ); + void recADDU( void ); + void recDADD( void ); + void recDADDU( void ); + void recSUB( void ); + void recSUBU( void ); + void recDSUB( void ); + void recDSUBU( void ); + void recAND( void ); + void recOR( void ); + void recXOR( void ); + void recNOR( void ); + void recSLT( void ); + void recSLTU( void ); +} } } +#endif diff --git a/pcsx2/x86/iR5900AritImm.h b/pcsx2/x86/iR5900AritImm.h index 0590cca572..79a6a292fb 100644 --- a/pcsx2/x86/iR5900AritImm.h +++ b/pcsx2/x86/iR5900AritImm.h @@ -1,42 +1,42 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __IR5900ARITIMM_H__ -#define __IR5900ARITIMM_H__ - -/********************************************************* -* Arithmetic with immediate operand * -* Format: OP rt, rs, immediate * -*********************************************************/ -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl { - - void recADDI( void ); - void recADDIU( void ); - void recDADDI( void ); - void recDADDIU( void ); - void recANDI( void ); - void recORI( void ); - void recXORI( void ); - - void recSLTI( void ); - void recSLTIU( void ); -} } } - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __IR5900ARITIMM_H__ +#define __IR5900ARITIMM_H__ + +/********************************************************* +* Arithmetic with immediate operand * +* Format: OP rt, rs, immediate * +*********************************************************/ +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl { + + void recADDI( void ); + void recADDIU( void ); + void recDADDI( void ); + void recDADDIU( void ); + void recANDI( void ); + void recORI( void ); + void recXORI( void ); + + void recSLTI( void ); + void recSLTIU( void ); +} } } + +#endif diff --git a/pcsx2/x86/iR5900Branch.h b/pcsx2/x86/iR5900Branch.h index 32a2d0c669..0c5ab7d511 100644 --- a/pcsx2/x86/iR5900Branch.h +++ b/pcsx2/x86/iR5900Branch.h @@ -1,49 +1,49 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __IR5900BRANCH_H__ -#define __IR5900BRANCH_H__ - -/********************************************************* -* Shift arithmetic with constant shift * -* Format: OP rd, rt, sa * -*********************************************************/ - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl { - - void recBEQ( void ); - void recBEQL( void ); - void recBNE( void ); - void recBNEL( void ); - void recBLTZ( void ); - void recBLTZL( void ); - void recBLTZAL( void ); - void recBLTZALL( void ); - void recBGTZ( void ); - void recBGTZL( void ); - void recBLEZ( void ); - void recBLEZL( void ); - void recBGEZ( void ); - void recBGEZL( void ); - void recBGEZAL( void ); - void recBGEZALL( void ); -} } } - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __IR5900BRANCH_H__ +#define __IR5900BRANCH_H__ + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl { + + void recBEQ( void ); + void recBEQL( void ); + void recBNE( void ); + void recBNEL( void ); + void recBLTZ( void ); + void recBLTZL( void ); + void recBLTZAL( void ); + void recBLTZALL( void ); + void recBGTZ( void ); + void recBGTZL( void ); + void recBLEZ( void ); + void recBLEZL( void ); + void recBGEZ( void ); + void recBGEZL( void ); + void recBGEZAL( void ); + void recBGEZALL( void ); +} } } + +#endif diff --git a/pcsx2/x86/iR5900CoissuedLoadStore.cpp b/pcsx2/x86/iR5900CoissuedLoadStore.cpp index a86800bb2b..84caeb20c2 100644 --- a/pcsx2/x86/iR5900CoissuedLoadStore.cpp +++ b/pcsx2/x86/iR5900CoissuedLoadStore.cpp @@ -1,1739 +1,1739 @@ -/* Pcsx2 - Pc Ps2 Emulator -* Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#ifdef PCSX2_VM_COISSUE - -#include "Common.h" -#include "R5900OpcodeTables.h" -#include "iR5900LoadStore.h" -#include "ix86/ix86.h" -#include "iR5900.h" - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl { - -#define _Imm_co_ (*(s16*)PSM(pc)) - -int _eePrepareReg_coX(int gprreg, int num) -{ - int mmreg = _eePrepareReg(gprreg); - - if( (mmreg&MEM_MMXTAG) && num == 7 ) { - if( mmxregs[mmreg&0xf].mode & MODE_WRITE ) { - MOVQRtoM((u32)&cpuRegs.GPR.r[gprreg], mmreg&0xf); - mmxregs[mmreg&0xf].mode &= ~MODE_WRITE; - mmxregs[mmreg&0xf].needed = 0; - } - } - - return mmreg; -} - -void recLoad32_co(u32 bit, u32 sign) -{ - int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); - int mmreg1 = -1, mmreg2 = -1; - -#ifdef REC_SLOWREAD - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - int ineax = 0; - u32 written = 0; - - _eeOnLoadWrite(_Rt_); - _eeOnLoadWrite(nextrt); - - if( bit == 32 ) { - mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); - if( mmreg1 >= 0 ) mmreg1 |= MEM_MMXTAG; - else mmreg1 = EBX; - - mmreg2 = _allocCheckGPRtoMMX(g_pCurInstInfo+1, nextrt, MODE_WRITE); - if( mmreg2 >= 0 ) mmreg2 |= MEM_MMXTAG; - else mmreg2 = EAX; - } - else { - _deleteEEreg(_Rt_, 0); - _deleteEEreg(nextrt, 0); - mmreg1 = EBX; - mmreg2 = EAX; - } - - // do const processing - switch(bit) { - case 8: - if( recMemConstRead8(mmreg1, g_cpuConstRegs[_Rs_].UL[0]+_Imm_, sign) ) { - if( mmreg1&MEM_MMXTAG ) mmxregs[mmreg1&0xf].inuse = 0; - if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); - written = 1; - } - ineax = recMemConstRead8(mmreg2, g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_, sign); - break; - case 16: - if( recMemConstRead16(mmreg1, g_cpuConstRegs[_Rs_].UL[0]+_Imm_, sign) ) { - if( mmreg1&MEM_MMXTAG ) mmxregs[mmreg1&0xf].inuse = 0; - if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); - written = 1; - } - ineax = recMemConstRead16(mmreg2, g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_, sign); - break; - case 32: - assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 ); - if( recMemConstRead32(mmreg1, g_cpuConstRegs[_Rs_].UL[0]+_Imm_) ) { - if( mmreg1&MEM_MMXTAG ) mmxregs[mmreg1&0xf].inuse = 0; - if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); - written = 1; - } - ineax = recMemConstRead32(mmreg2, g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_); - break; - } - - if( !written && _Rt_ ) { - if( mmreg1&MEM_MMXTAG ) { - assert( mmxregs[mmreg1&0xf].mode & MODE_WRITE ); - if( sign ) _signExtendGPRtoMMX(mmreg1&0xf, _Rt_, 32-bit); - else if( bit < 32 ) PSRLDItoR(mmreg1&0xf, 32-bit); - } - else recTransferX86ToReg(mmreg1, _Rt_, sign); - } - if( nextrt ) { - g_pCurInstInfo++; - if( !ineax && (mmreg2 & MEM_MMXTAG) ) { - assert( mmxregs[mmreg2&0xf].mode & MODE_WRITE ); - if( sign ) _signExtendGPRtoMMX(mmreg2&0xf, nextrt, 32-bit); - else if( bit < 32 ) PSRLDItoR(mmreg2&0xf, 32-bit); - } - else { - if( mmreg2&MEM_MMXTAG ) mmxregs[mmreg2&0xf].inuse = 0; - recTransferX86ToReg(mmreg2, nextrt, sign); - } - g_pCurInstInfo--; - } - } - else -#endif - { - int dohw; - int mmregs = _eePrepareReg(_Rs_); - assert( !REC_FORCEMMX ); - - _eeOnLoadWrite(_Rt_); - _eeOnLoadWrite(nextrt); - _deleteEEreg(_Rt_, 0); - _deleteEEreg(nextrt, 0); - - dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); - - switch(bit) { - case 8: - if( sign ) { - MOVSX32Rm8toROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset); - MOVSX32Rm8toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - } - else { - MOVZX32Rm8toROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset); - MOVZX32Rm8toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - } - break; - case 16: - if( sign ) { - MOVSX32Rm16toROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset); - MOVSX32Rm16toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - } - else { - MOVZX32Rm16toROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset); - MOVZX32Rm16toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - } - break; - case 32: - MOV32RmtoROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset); - MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - break; - } - - if ( _Rt_ ) recTransferX86ToReg(EBX, _Rt_, sign); - - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - switch(bit) { - case 8: - MOV32RtoM((u32)&s_tempaddr, ECX); - CALLFunc( (int)recMemRead8 ); - if( sign ) MOVSX32R8toR(EAX, EAX); - MOV32MtoR(ECX, (u32)&s_tempaddr); - if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); - - ADD32ItoR(ECX, _Imm_co_-_Imm_); - CALLFunc( (int)recMemRead8 ); - if( sign ) MOVSX32R8toR(EAX, EAX); - break; - case 16: - MOV32RtoM((u32)&s_tempaddr, ECX); - CALLFunc( (int)recMemRead16 ); - if( sign ) MOVSX32R16toR(EAX, EAX); - MOV32MtoR(ECX, (u32)&s_tempaddr); - if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); - - ADD32ItoR(ECX, _Imm_co_-_Imm_); - CALLFunc( (int)recMemRead16 ); - if( sign ) MOVSX32R16toR(EAX, EAX); - break; - case 32: - MOV32RtoM((u32)&s_tempaddr, ECX); - iMemRead32Check(); - CALLFunc( (int)recMemRead32 ); - MOV32MtoR(ECX, (u32)&s_tempaddr); - if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); - - ADD32ItoR(ECX, _Imm_co_-_Imm_); - iMemRead32Check(); - CALLFunc( (int)recMemRead32 ); - break; - } - - if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); - else x86SetJ8(j8Ptr[2]); - } - - if( nextrt ) { - g_pCurInstInfo++; - recTransferX86ToReg(EAX, nextrt, sign); - g_pCurInstInfo--; - } - } -} - -void recLB_co( void ) { recLoad32_co(8, 1); } -void recLBU_co( void ) { recLoad32_co(8, 0); } -void recLH_co( void ) { recLoad32_co(16, 1); } -void recLHU_co( void ) { recLoad32_co(16, 0); } -void recLW_co( void ) { recLoad32_co(32, 1); } -void recLWU_co( void ) { recLoad32_co(32, 0); } -void recLDL_co(void) { recLoad64(_Imm_-7, 0); } -void recLDR_co(void) { recLoad64(_Imm_, 0); } -void recLWL_co(void) { recLoad32(32, _Imm_-3, 1); } // paired with LWR -void recLWR_co(void) { recLoad32(32, _Imm_, 1); } // paired with LWL - -void recLD_co( void ) -{ -#ifdef REC_SLOWREAD - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - recLD(); - g_pCurInstInfo++; - cpuRegs.code = *(u32*)PSM(pc); - recLD(); - g_pCurInstInfo--; // incremented later - } - else -#endif - { - int dohw; - int mmregs = _eePrepareReg(_Rs_); - int mmreg1 = -1, mmreg2 = -1, t0reg = -1, t1reg = -1; - int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); - - if( _Rt_ ) _eeOnWriteReg(_Rt_, 0); - if( nextrt ) _eeOnWriteReg(nextrt, 0); - - if( _Rt_ ) { - mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); - if( mmreg1 < 0 ) { - mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE|MODE_READ); - if( mmreg1 >= 0 ) mmreg1 |= 0x8000; - } - - if( mmreg1 < 0 && _hasFreeMMXreg() ) mmreg1 = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE); - } - - if( nextrt ) { - mmreg2 = _allocCheckGPRtoMMX(g_pCurInstInfo+1, nextrt, MODE_WRITE); - if( mmreg2 < 0 ) { - mmreg2 = _allocCheckGPRtoXMM(g_pCurInstInfo+1, nextrt, MODE_WRITE|MODE_READ); - if( mmreg2 >= 0 ) mmreg2 |= 0x8000; - } - - if( mmreg2 < 0 && _hasFreeMMXreg() ) mmreg2 = _allocMMXreg(-1, MMX_GPR+nextrt, MODE_WRITE); - } - - if( mmreg1 < 0 || mmreg2 < 0 ) { - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - - if( mmreg1 < 0 && mmreg2 < 0 && _hasFreeMMXreg() ) { - t1reg = _allocMMXreg(-1, MMX_TEMP, 0); - } - else t1reg = t0reg; - } - - dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 1, 0); - - if( mmreg1 >= 0 ) { - if( mmreg1 & 0x8000 ) SSE_MOVLPSRmtoROffset(mmreg1&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); - else MOVQRmtoROffset(mmreg1, ECX, PS2MEM_BASE_+s_nAddMemOffset); - } - else { - if( _Rt_ ) { - MOVQRmtoROffset(t0reg, ECX, PS2MEM_BASE_+s_nAddMemOffset); - MOVQRtoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], t0reg); - } - } - - if( mmreg2 >= 0 ) { - if( mmreg2 & 0x8000 ) SSE_MOVLPSRmtoROffset(mmreg2&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - else MOVQRmtoROffset(mmreg2, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - } - else { - if( nextrt ) { - MOVQRmtoROffset(t1reg, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - MOVQRtoM((int)&cpuRegs.GPR.r[ nextrt ].UL[ 0 ], t1reg); - } - } - - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - MOV32RtoM((u32)&s_tempaddr, ECX); - - if( mmreg1 >= 0 ) { - PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - CALLFunc( (int)recMemRead64 ); - - if( mmreg1 & 0x8000 ) SSE_MOVLPS_M64_to_XMM(mmreg1&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); - else MOVQMtoR(mmreg1, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); - } - else { - if( _Rt_ ) { - _deleteEEreg(_Rt_, 0); - PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - } - else PUSH32I( (int)&retValues[0] ); - - CALLFunc( (int)recMemRead64 ); - } - - MOV32MtoR(ECX, (u32)&s_tempaddr); - - if( mmreg2 >= 0 ) { - MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[ nextrt ].UD[ 0 ], 0 ); - ADD32ItoR(ECX, _Imm_co_-_Imm_); - CALLFunc( (int)recMemRead64 ); - - if( mmreg2 & 0x8000 ) SSE_MOVLPS_M64_to_XMM(mmreg2&0xf, (int)&cpuRegs.GPR.r[ nextrt ].UD[ 0 ]); - else MOVQMtoR(mmreg2, (int)&cpuRegs.GPR.r[ nextrt ].UD[ 0 ]); - } - else { - if( nextrt ) { - _deleteEEreg(nextrt, 0); - MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[ nextrt ].UD[ 0 ], 0 ); - } - else MOV32ItoRmOffset(ESP, (int)&retValues[0], 0 ); - - ADD32ItoR(ECX, _Imm_co_-_Imm_); - CALLFunc( (int)recMemRead64 ); - } - - ADD32ItoR(ESP, 4); - - if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]); - else x86SetJ8A(j8Ptr[2]); - } - - if( mmreg1 < 0 || mmreg2 < 0 || !(mmreg1&0x8000) || !(mmreg2&0x8000) ) SetMMXstate(); - - if( t0reg >= 0 ) _freeMMXreg(t0reg); - if( t0reg != t1reg && t1reg >= 0 ) _freeMMXreg(t1reg); - - _clearNeededMMXregs(); - _clearNeededXMMregs(); - } -} - -void recLD_coX( int num ) -{ - int i; - int mmreg = -1; - int mmregs[XMMREGS]; - int nextrts[XMMREGS]; - - assert( num > 1 && num < XMMREGS ); - -#ifdef REC_SLOWREAD - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - recLD(); - - for(i = 0; i < num; ++i) { - g_pCurInstInfo++; - cpuRegs.code = *(u32*)PSM(pc+i*4); - recLD(); - } - - g_pCurInstInfo -= num; // incremented later - } - else -#endif - { - int dohw; - int mmregS = _eePrepareReg_coX(_Rs_, num); - - if( _Rt_ ) _eeOnWriteReg(_Rt_, 0); - for(i = 0; i < num; ++i) { - nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); - _eeOnWriteReg(nextrts[i], 0); - } - - if( _Rt_ ) { - mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); - if( mmreg < 0 ) { - mmreg = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE|MODE_READ); - if( mmreg >= 0 ) mmreg |= MEM_XMMTAG; - else mmreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE)|MEM_MMXTAG; - } - else mmreg |= MEM_MMXTAG; - } - - for(i = 0; i < num; ++i) { - mmregs[i] = _allocCheckGPRtoMMX(g_pCurInstInfo+i+1, nextrts[i], MODE_WRITE); - if( mmregs[i] < 0 ) { - mmregs[i] = _allocCheckGPRtoXMM(g_pCurInstInfo+i+1, nextrts[i], MODE_WRITE|MODE_READ); - if( mmregs[i] >= 0 ) mmregs[i] |= MEM_XMMTAG; - else mmregs[i] = _allocMMXreg(-1, MMX_GPR+nextrts[i], MODE_WRITE)|MEM_MMXTAG; - } - else mmregs[i] |= MEM_MMXTAG; - } - - dohw = recSetMemLocation(_Rs_, _Imm_, mmregS, 1, 0); - - if( mmreg >= 0 ) { - if( mmreg & MEM_XMMTAG ) SSE_MOVLPSRmtoROffset(mmreg&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); - else MOVQRmtoROffset(mmreg&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); - } - - for(i = 0; i < num; ++i) { - u32 off = PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_; - - if( mmregs[i] >= 0 ) { - if( mmregs[i] & MEM_XMMTAG ) SSE_MOVLPSRmtoROffset(mmregs[i]&0xf, ECX, off); - else MOVQRmtoROffset(mmregs[i]&0xf, ECX, off); - } - } - - if( dohw ) { - if( (s_bCachingMem & 2) || num > 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - MOV32RtoM((u32)&s_tempaddr, ECX); - - if( mmreg >= 0 ) { - PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - CALLFunc( (int)recMemRead64 ); - - if( mmreg & MEM_XMMTAG ) SSE_MOVLPS_M64_to_XMM(mmreg&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); - else MOVQMtoR(mmreg&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); - } - else { - PUSH32I( (int)&retValues[0] ); - CALLFunc( (int)recMemRead64 ); - } - - for(i = 0; i < num; ++i ) { - MOV32MtoR(ECX, (u32)&s_tempaddr); - ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-_Imm_); - - if( mmregs[i] >= 0 ) { - MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[nextrts[i]].UL[0], 0); - CALLFunc( (int)recMemRead64 ); - - if( mmregs[i] & MEM_XMMTAG ) SSE_MOVLPS_M64_to_XMM(mmregs[i]&0xf, (int)&cpuRegs.GPR.r[ nextrts[i] ].UD[ 0 ]); - else MOVQMtoR(mmregs[i]&0xf, (int)&cpuRegs.GPR.r[ nextrts[i] ].UD[ 0 ]); - } - else { - MOV32ItoRmOffset(ESP, (int)&retValues[0], 0); - CALLFunc( (int)recMemRead64 ); - } - } - - ADD32ItoR(ESP, 4); - - if( (s_bCachingMem & 2) || num > 2 ) x86SetJ32A(j32Ptr[4]); - else x86SetJ8A(j8Ptr[2]); - } - - _clearNeededMMXregs(); - _clearNeededXMMregs(); - } -} - -void recLQ_co( void ) -{ -#ifdef REC_SLOWREAD - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - recLQ(); - g_pCurInstInfo++; - cpuRegs.code = *(u32*)PSM(pc); - recLQ(); - g_pCurInstInfo--; // incremented later - } - else -#endif - { - int dohw; - int t0reg = -1; - int mmregs = _eePrepareReg(_Rs_); - - int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); - int mmreg1 = -1, mmreg2 = -1; - - if( _Rt_ ) { - _eeOnWriteReg(_Rt_, 0); - - if( _hasFreeMMXreg() ) { - mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); - if( mmreg1 >= 0 ) { - mmreg1 |= MEM_MMXTAG; - if( t0reg < 0 ) t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - } - } - else _deleteMMXreg(MMX_GPR+_Rt_, 2); - - if( mmreg1 < 0 ) { - mmreg1 = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); - if( mmreg1 >= 0 ) mmreg1 |= MEM_XMMTAG; - } - } - - if( nextrt ) { - _eeOnWriteReg(nextrt, 0); - - if( _hasFreeMMXreg() ) { - mmreg2 = _allocCheckGPRtoMMX(g_pCurInstInfo+1, nextrt, MODE_WRITE); - if( mmreg2 >= 0 ) { - mmreg2 |= MEM_MMXTAG; - if( t0reg < 0 ) t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - } - } - else _deleteMMXreg(MMX_GPR+nextrt, 2); - - if( mmreg2 < 0 ) { - mmreg2 = _allocGPRtoXMMreg(-1, nextrt, MODE_WRITE); - if( mmreg2 >= 0 ) mmreg2 |= MEM_XMMTAG; - } - } - - dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0); - - if( _Rt_ ) { - if( mmreg1 >= 0 && (mmreg1 & MEM_MMXTAG) ) { - MOVQRmtoROffset(t0reg, ECX, PS2MEM_BASE_+s_nAddMemOffset+8); - MOVQRmtoROffset(mmreg1&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); - MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_].UL[2], t0reg); - } - else if( mmreg1 >= 0 && (mmreg1 & MEM_XMMTAG) ) { - SSEX_MOVDQARmtoROffset(mmreg1&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); - } - else { - _recMove128RmOffsettoM((u32)&cpuRegs.GPR.r[_Rt_].UL[0], PS2MEM_BASE_+s_nAddMemOffset); - } - } - - if( nextrt ) { - if( mmreg2 >= 0 && (mmreg2 & MEM_MMXTAG) ) { - MOVQRmtoROffset(t0reg, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+8); - MOVQRmtoROffset(mmreg2&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - MOVQRtoM((u32)&cpuRegs.GPR.r[nextrt].UL[2], t0reg); - } - else if( mmreg2 >= 0 && (mmreg2 & MEM_XMMTAG) ) { - SSEX_MOVDQARmtoROffset(mmreg2&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - } - else { - _recMove128RmOffsettoM((u32)&cpuRegs.GPR.r[nextrt].UL[0], PS2MEM_BASE_+s_nAddMemOffset); - } - } - - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - MOV32RtoM((u32)&s_tempaddr, ECX); - if( _Rt_ ) PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - else PUSH32I( (int)&retValues[0] ); - CALLFunc( (int)recMemRead128 ); - - MOV32MtoR(ECX, (u32)&s_tempaddr); - if( nextrt ) MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[nextrt].UL[0], 0); - else MOV32ItoRmOffset(ESP, (int)&retValues[0], 0); - ADD32ItoR(ECX, _Imm_co_-_Imm_); - CALLFunc( (int)recMemRead128 ); - - if( _Rt_) { - if( mmreg1 >= 0 && (mmreg1 & MEM_MMXTAG) ) MOVQMtoR(mmreg1&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); - else if( mmreg1 >= 0 && (mmreg1 & MEM_XMMTAG) ) SSEX_MOVDQA_M128_to_XMM(mmreg1&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - } - if( nextrt ) { - if( mmreg2 >= 0 && (mmreg2 & MEM_MMXTAG) ) MOVQMtoR(mmreg2&0xf, (int)&cpuRegs.GPR.r[ nextrt ].UL[ 0 ]); - else if( mmreg2 >= 0 && (mmreg2 & MEM_XMMTAG) ) SSEX_MOVDQA_M128_to_XMM(mmreg2&0xf, (int)&cpuRegs.GPR.r[ nextrt ].UL[ 0 ] ); - } - ADD32ItoR(ESP, 4); - - if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); - else x86SetJ8(j8Ptr[2]); - } - - if( t0reg >= 0 ) _freeMMXreg(t0reg); - } -} - -// coissues more than 2 LQs -void recLQ_coX(int num) -{ - int i; - int mmreg = -1; - int mmregs[XMMREGS]; - int nextrts[XMMREGS]; - - assert( num > 1 && num < XMMREGS ); - -#ifdef REC_SLOWREAD - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - recLQ(); - - for(i = 0; i < num; ++i) { - g_pCurInstInfo++; - cpuRegs.code = *(u32*)PSM(pc+i*4); - recLQ(); - } - - g_pCurInstInfo -= num; // incremented later - } - else -#endif - { - int dohw; - int mmregS = _eePrepareReg_coX(_Rs_, num); - - - if( _Rt_ ) _deleteMMXreg(MMX_GPR+_Rt_, 2); - for(i = 0; i < num; ++i) { - nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); - if( nextrts[i] ) _deleteMMXreg(MMX_GPR+nextrts[i], 2); - } - - if( _Rt_ ) { - _eeOnWriteReg(_Rt_, 0); - mmreg = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); - } - - for(i = 0; i < num; ++i) { - if( nextrts[i] ) { - _eeOnWriteReg(nextrts[i], 0); - mmregs[i] = _allocGPRtoXMMreg(-1, nextrts[i], MODE_WRITE); - } - else mmregs[i] = -1; - } - - dohw = recSetMemLocation(_Rs_, _Imm_, mmregS, 2, 1); - - if( _Rt_ ) SSEX_MOVDQARmtoROffset(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset); - - for(i = 0; i < num; ++i) { - u32 off = s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_; - if( nextrts[i] ) SSEX_MOVDQARmtoROffset(mmregs[i], ECX, PS2MEM_BASE_+off&~0xf); - } - - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - MOV32RtoM((u32)&s_tempaddr, ECX); - - if( _Rt_ ) PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - else PUSH32I( (int)&retValues[0] ); - CALLFunc( (int)recMemRead128 ); - if( _Rt_) SSEX_MOVDQA_M128_to_XMM(mmreg, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - - for(i = 0; i < num; ++i) { - MOV32MtoR(ECX, (u32)&s_tempaddr); - ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-_Imm_); - - if( nextrts[i] ) MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[nextrts[i]].UL[0], 0); - else MOV32ItoRmOffset(ESP, (int)&retValues[0], 0); - CALLFunc( (int)recMemRead128 ); - if( nextrts[i] ) SSEX_MOVDQA_M128_to_XMM(mmregs[i], (int)&cpuRegs.GPR.r[ nextrts[i] ].UL[ 0 ] ); - } - - ADD32ItoR(ESP, 4); - - if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]); - else x86SetJ8A(j8Ptr[2]); - } - } -} - -void recStore_co(int bit, int align) -{ - int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); - -#ifdef REC_SLOWWRITE - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - u32 addr = g_cpuConstRegs[_Rs_].UL[0]+_Imm_; - u32 coaddr = g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_; - int mmreg, t0reg = -1, mmreg2; - int doclear = 0; - - switch(bit) { - case 8: - if( GPR_IS_CONST1(_Rt_) ) doclear |= recMemConstWrite8(addr, MEM_EECONSTTAG|(_Rt_<<16)); - else { - _eeMoveGPRtoR(EAX, _Rt_); - doclear |= recMemConstWrite8(addr, EAX); - } - if( GPR_IS_CONST1(nextrt) ) doclear |= recMemConstWrite8(coaddr, MEM_EECONSTTAG|(nextrt<<16)); - else { - _eeMoveGPRtoR(EAX, nextrt); - doclear |= recMemConstWrite8(coaddr, EAX); - } - break; - case 16: - assert( (addr)%2 == 0 ); - assert( (coaddr)%2 == 0 ); - - if( GPR_IS_CONST1(_Rt_) ) doclear |= recMemConstWrite16(addr, MEM_EECONSTTAG|(_Rt_<<16)); - else { - _eeMoveGPRtoR(EAX, _Rt_); - doclear |= recMemConstWrite16(addr, EAX); - } - - if( GPR_IS_CONST1(nextrt) ) doclear |= recMemConstWrite16(coaddr, MEM_EECONSTTAG|(nextrt<<16)); - else { - _eeMoveGPRtoR(EAX, nextrt); - doclear |= recMemConstWrite16(coaddr, EAX); - } - break; - case 32: - assert( (addr)%4 == 0 ); - if( GPR_IS_CONST1(_Rt_) ) doclear = recMemConstWrite32(addr, MEM_EECONSTTAG|(_Rt_<<16)); - else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ)) >= 0 ) { - doclear = recMemConstWrite32(addr, mmreg|MEM_XMMTAG|(_Rt_<<16)); - } - else if( (mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_READ)) >= 0 ) { - doclear = recMemConstWrite32(addr, mmreg|MEM_MMXTAG|(_Rt_<<16)); - } - else { - _eeMoveGPRtoR(EAX, _Rt_); - doclear = recMemConstWrite32(addr, EAX); - } - - if( GPR_IS_CONST1(nextrt) ) doclear |= recMemConstWrite32(coaddr, MEM_EECONSTTAG|(nextrt<<16)); - else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, nextrt, MODE_READ)) >= 0 ) { - doclear |= recMemConstWrite32(coaddr, mmreg|MEM_XMMTAG|(nextrt<<16)); - } - else if( (mmreg = _checkMMXreg(MMX_GPR+nextrt, MODE_READ)) >= 0 ) { - doclear |= recMemConstWrite32(coaddr, mmreg|MEM_MMXTAG|(nextrt<<16)); - } - else { - _eeMoveGPRtoR(EAX, nextrt); - doclear |= recMemConstWrite32(coaddr, EAX); - } - - break; - case 64: - { - int mask = align ? ~7 : ~0; - //assert( (addr)%8 == 0 ); - - if( GPR_IS_CONST1(_Rt_) ) mmreg = MEM_EECONSTTAG|(_Rt_<<16); - else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ)) >= 0 ) { - mmreg |= MEM_XMMTAG|(_Rt_<<16); - } - else mmreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ)|MEM_MMXTAG|(_Rt_<<16); - - if( GPR_IS_CONST1(nextrt) ) mmreg2 = MEM_EECONSTTAG|(nextrt<<16); - else if( (mmreg2 = _checkXMMreg(XMMTYPE_GPRREG, nextrt, MODE_READ)) >= 0 ) { - mmreg2 |= MEM_XMMTAG|(nextrt<<16); - } - else mmreg2 = _allocMMXreg(-1, MMX_GPR+nextrt, MODE_READ)|MEM_MMXTAG|(nextrt<<16); - - doclear = recMemConstWrite64((addr)&mask, mmreg); - doclear |= recMemConstWrite64((coaddr)&mask, mmreg2); - doclear <<= 1; - break; - } - case 128: - assert( (addr)%16 == 0 ); - - mmreg = _eePrepConstWrite128(_Rt_); - mmreg2 = _eePrepConstWrite128(nextrt); - doclear = recMemConstWrite128((addr)&~15, mmreg); - doclear |= recMemConstWrite128((coaddr)&~15, mmreg2); - doclear <<= 2; - break; - } - - if( doclear ) { - u8* ptr; - CMP32ItoM((u32)&maxrecmem, g_cpuConstRegs[_Rs_].UL[0]+(_Imm_ < _Imm_co_ ? _Imm_ : _Imm_co_)); - ptr = JB8(0); - recMemConstClear((addr)&~(doclear*4-1), doclear); - recMemConstClear((coaddr)&~(doclear*4-1), doclear); - x86SetJ8A(ptr); - } - } - else -#endif - { - int dohw; - int mmregs = _eePrepareReg(_Rs_); - int off = _Imm_co_-_Imm_; - dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, align ? bit/64 : 0, bit==128); - - recStore_raw(g_pCurInstInfo, bit, EAX, _Rt_, s_nAddMemOffset); - recStore_raw(g_pCurInstInfo+1, bit, EBX, nextrt, s_nAddMemOffset+off); - - // clear the writes, do only one camera (with the lowest addr) - if( off < 0 ) ADD32ItoR(ECX, s_nAddMemOffset+off); - else if( s_nAddMemOffset ) ADD32ItoR(ECX, s_nAddMemOffset); - CMP32MtoR(ECX, (u32)&maxrecmem); - - if( s_bCachingMem & 2 ) j32Ptr[5] = JAE32(0); - else j8Ptr[1] = JAE8(0); - - MOV32RtoM((u32)&s_tempaddr, ECX); - - if( bit < 32 ) AND8ItoR(ECX, 0xfc); - if( bit <= 32 ) CALLFunc((uptr)recWriteMemClear32); - else if( bit == 64 ) CALLFunc((uptr)recWriteMemClear64); - else CALLFunc((uptr)recWriteMemClear128); - - MOV32MtoR(ECX, (u32)&s_tempaddr); - if( off < 0 ) ADD32ItoR(ECX, -off); - else ADD32ItoR(ECX, off); - - if( bit < 32 ) AND8ItoR(ECX, 0xfc); - if( bit <= 32 ) CALLFunc((uptr)recWriteMemClear32); - else if( bit == 64 ) CALLFunc((uptr)recWriteMemClear64); - else CALLFunc((uptr)recWriteMemClear128); - - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - MOV32RtoM((u32)&s_tempaddr, ECX); - recStore_call(bit, _Rt_, s_nAddMemOffset); - MOV32MtoR(ECX, (u32)&s_tempaddr); - recStore_call(bit, nextrt, s_nAddMemOffset+_Imm_co_-_Imm_); - - if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); - else x86SetJ8(j8Ptr[2]); - } - - if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[5]); - else x86SetJ8(j8Ptr[1]); - } - - _clearNeededMMXregs(); // needed since allocing - _clearNeededXMMregs(); // needed since allocing -} - -void recSB_co( void ) { recStore_co(8, 1); } -void recSH_co( void ) { recStore_co(16, 1); } -void recSW_co( void ) { recStore_co(32, 1); } -void recSD_co( void ) { recStore_co(64, 1); } -void recSQ_co( void ) { recStore_co(128, 1); } - -void recSWL_co(void) { recStore(32, _Imm_-3, 0); } -void recSWR_co(void) { recStore(32, _Imm_, 0); } -void recSDL_co(void) { recStore(64, _Imm_-7, 0); } -void recSDR_co(void) { recStore(64, _Imm_, 0); } - -// coissues more than 2 SDs -void recSD_coX(int num, int align) -{ - int i; - int mmreg = -1; - int nextrts[XMMREGS]; - u32 mask = align ? ~7 : ~0; - - assert( num > 1 && num < XMMREGS ); - - for(i = 0; i < num; ++i) { - nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); - } - -#ifdef REC_SLOWWRITE - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - int minimm = _Imm_; - int t0reg = -1; - int doclear = 0; - - if( GPR_IS_CONST1(_Rt_) ) mmreg = MEM_EECONSTTAG|(_Rt_<<16); - else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ)) >= 0 ) { - mmreg |= MEM_XMMTAG|(_Rt_<<16); - } - else mmreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ)|MEM_MMXTAG|(_Rt_<<16); - doclear |= recMemConstWrite64((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&mask, mmreg); - - for(i = 0; i < num; ++i) { - int imm = (*(s16*)PSM(pc+i*4)); - if( minimm > imm ) minimm = imm; - - if( GPR_IS_CONST1(nextrts[i]) ) mmreg = MEM_EECONSTTAG|(nextrts[i]<<16); - else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, nextrts[i], MODE_READ)) >= 0 ) { - mmreg |= MEM_XMMTAG|(nextrts[i]<<16); - } - else mmreg = _allocMMXreg(-1, MMX_GPR+nextrts[i], MODE_READ)|MEM_MMXTAG|(nextrts[i]<<16); - doclear |= recMemConstWrite64((g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4)))&mask, mmreg); - } - - if( doclear ) { - u32* ptr; - CMP32ItoM((u32)&maxrecmem, g_cpuConstRegs[_Rs_].UL[0]+minimm); - ptr = JB32(0); - recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~7, 4); - - for(i = 0; i < num; ++i) { - recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4)))&~7, 2); - } - x86SetJ32A(ptr); - } - } - else -#endif - { - int dohw; - int mmregs = _eePrepareReg_coX(_Rs_, num); - int minoff = 0; - - dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, align, 1); - - recStore_raw(g_pCurInstInfo, 64, EAX, _Rt_, s_nAddMemOffset); - - for(i = 0; i < num; ++i) { - recStore_raw(g_pCurInstInfo+i+1, 64, EAX, nextrts[i], s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); - } - - // clear the writes - minoff = _Imm_; - for(i = 0; i < num; ++i) { - if( minoff > (*(s16*)PSM(pc+i*4)) ) minoff = (*(s16*)PSM(pc+i*4)); - } - - if( s_nAddMemOffset || minoff != _Imm_ ) ADD32ItoR(ECX, s_nAddMemOffset+minoff-_Imm_); - CMP32MtoR(ECX, (u32)&maxrecmem); - if( s_bCachingMem & 2 ) j32Ptr[5] = JAE32(0); - else j8Ptr[1] = JAE8(0); - - MOV32RtoM((u32)&s_tempaddr, ECX); - if( minoff != _Imm_ ) ADD32ItoR(ECX, _Imm_-minoff); - CALLFunc((uptr)recWriteMemClear64); - - for(i = 0; i < num; ++i) { - MOV32MtoR(ECX, (u32)&s_tempaddr); - if( minoff != (*(s16*)PSM(pc+i*4)) ) ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-minoff); - CALLFunc((uptr)recWriteMemClear64); - } - - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - MOV32RtoM((u32)&s_tempaddr, ECX); - recStore_call(64, _Rt_, s_nAddMemOffset); - for(i = 0; i < num; ++i) { - MOV32MtoR(ECX, (u32)&s_tempaddr); - recStore_call(64, nextrts[i], s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); - } - - if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); - else x86SetJ8(j8Ptr[2]); - } - - if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[5]); - else x86SetJ8(j8Ptr[1]); - - _clearNeededMMXregs(); // needed since allocing - _clearNeededXMMregs(); // needed since allocing - } -} - -// coissues more than 2 SQs -void recSQ_coX(int num) -{ - int i; - int mmreg = -1; - int nextrts[XMMREGS]; - - assert( num > 1 && num < XMMREGS ); - - for(i = 0; i < num; ++i) { - nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); - } - -#ifdef REC_SLOWWRITE - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - int minimm = _Imm_; - int t0reg = -1; - int doclear = 0; - - mmreg = _eePrepConstWrite128(_Rt_); - doclear |= recMemConstWrite128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg); - - for(i = 0; i < num; ++i) { - int imm = (*(s16*)PSM(pc+i*4)); - if( minimm > imm ) minimm = imm; - - mmreg = _eePrepConstWrite128(nextrts[i]); - doclear |= recMemConstWrite128((g_cpuConstRegs[_Rs_].UL[0]+imm)&~15, mmreg); - } - - if( doclear ) { - u32* ptr; - CMP32ItoM((u32)&maxrecmem, g_cpuConstRegs[_Rs_].UL[0]+minimm); - ptr = JB32(0); - recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, 4); - - for(i = 0; i < num; ++i) { - recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4)))&~15, 4); - } - x86SetJ32A(ptr); - } - } - else -#endif - { - int dohw; - int mmregs = _eePrepareReg_coX(_Rs_, num); - int minoff = 0; - - dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 1); - - recStore_raw(g_pCurInstInfo, 128, EAX, _Rt_, s_nAddMemOffset); - - for(i = 0; i < num; ++i) { - recStore_raw(g_pCurInstInfo+i+1, 128, EAX, nextrts[i], s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); - } - - // clear the writes - minoff = _Imm_; - for(i = 0; i < num; ++i) { - if( minoff > (*(s16*)PSM(pc+i*4)) ) minoff = (*(s16*)PSM(pc+i*4)); - } - - if( s_nAddMemOffset || minoff != _Imm_ ) ADD32ItoR(ECX, s_nAddMemOffset+minoff-_Imm_); - CMP32MtoR(ECX, (u32)&maxrecmem); - if( s_bCachingMem & 2 ) j32Ptr[5] = JAE32(0); - else j8Ptr[1] = JAE8(0); - - MOV32RtoM((u32)&s_tempaddr, ECX); - if( minoff != _Imm_ ) ADD32ItoR(ECX, _Imm_-minoff); - CALLFunc((uptr)recWriteMemClear128); - - for(i = 0; i < num; ++i) { - MOV32MtoR(ECX, (u32)&s_tempaddr); - if( minoff != (*(s16*)PSM(pc+i*4)) ) ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-minoff); - CALLFunc((uptr)recWriteMemClear128); - } - - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - MOV32RtoM((u32)&s_tempaddr, ECX); - recStore_call(128, _Rt_, s_nAddMemOffset); - for(i = 0; i < num; ++i) { - MOV32MtoR(ECX, (u32)&s_tempaddr); - recStore_call(128, nextrts[i], s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); - } - - if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); - else x86SetJ8(j8Ptr[2]); - } - - if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[5]); - else x86SetJ8(j8Ptr[1]); - - _clearNeededMMXregs(); // needed since allocing - _clearNeededXMMregs(); // needed since allocing - } -} - -void recLWC1_co( void ) -{ - int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); - -#ifdef REC_SLOWREAD - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - u32 written = 0; - int ineax, mmreg1, mmreg2; - - mmreg1 = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE); - if( mmreg1 >= 0 ) mmreg1 |= MEM_XMMTAG; - else mmreg1 = EBX; - - mmreg2 = _allocCheckFPUtoXMM(g_pCurInstInfo+1, nextrt, MODE_WRITE); - if( mmreg2 >= 0 ) mmreg2 |= MEM_XMMTAG; - else mmreg2 = EAX; - - assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 ); - if( recMemConstRead32(mmreg1, g_cpuConstRegs[_Rs_].UL[0]+_Imm_) ) { - if( mmreg1&MEM_XMMTAG ) xmmregs[mmreg1&0xf].inuse = 0; - MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EBX ); - written = 1; - } - ineax = recMemConstRead32(mmreg2, g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_); - - if( !written ) { - if( !(mmreg1&MEM_XMMTAG) ) MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EBX ); - } - - if( ineax || !(mmreg2 & MEM_XMMTAG) ) { - if( mmreg2&MEM_XMMTAG ) xmmregs[mmreg2&0xf].inuse = 0; - MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EAX ); - } - } - else -#endif - { - int dohw; - int regt, regtnext; - int mmregs = _eePrepareReg(_Rs_); - - _deleteMMXreg(MMX_FPU+_Rt_, 2); - regt = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE); - regtnext = _allocCheckFPUtoXMM(g_pCurInstInfo+1, nextrt, MODE_WRITE); - - dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); - - if( regt >= 0 ) { - SSEX_MOVD_RmOffset_to_XMM(regt, ECX, PS2MEM_BASE_+s_nAddMemOffset); - } - else { - MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); - MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); - } - - if( regtnext >= 0 ) { - SSEX_MOVD_RmOffset_to_XMM(regtnext, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - } - else { - MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EAX ); - } - - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - PUSH32R(ECX); - CALLFunc( (int)recMemRead32 ); - POP32R(ECX); - - if( regt >= 0 ) { - SSE2_MOVD_R_to_XMM(regt, EAX); - } - else { - MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); - } - - ADD32ItoR(ECX, _Imm_co_-_Imm_); - CALLFunc( (int)recMemRead32 ); - - if( regtnext >= 0 ) { - SSE2_MOVD_R_to_XMM(regtnext, EAX); - } - else { - MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EAX ); - } - - if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]); - else x86SetJ8A(j8Ptr[2]); - } - } -} - -void recLWC1_coX(int num) -{ - int i; - int mmreg = -1; - int mmregs[XMMREGS]; - int nextrts[XMMREGS]; - - assert( num > 1 && num < XMMREGS ); - -#ifdef REC_SLOWREAD - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - int ineax; - u32 written = 0; - mmreg = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE); - if( mmreg >= 0 ) mmreg |= MEM_XMMTAG; - else mmreg = EAX; - - assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 ); - if( recMemConstRead32(mmreg, g_cpuConstRegs[_Rs_].UL[0]+_Imm_) ) { - if( mmreg&MEM_XMMTAG ) xmmregs[mmreg&0xf].inuse = 0; - MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EBX ); - written = 1; - } - else if( !IS_XMMREG(mmreg) ) MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); - - // recompile two at a time - for(i = 0; i < num-1; i += 2) { - nextrts[0] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); - nextrts[1] = ((*(u32*)(PSM(pc+i*4+4)) >> 16) & 0x1F); - - written = 0; - mmregs[0] = _allocCheckFPUtoXMM(g_pCurInstInfo+i+1, nextrts[0], MODE_WRITE); - if( mmregs[0] >= 0 ) mmregs[0] |= MEM_XMMTAG; - else mmregs[0] = EBX; - - mmregs[1] = _allocCheckFPUtoXMM(g_pCurInstInfo+i+2, nextrts[1], MODE_WRITE); - if( mmregs[1] >= 0 ) mmregs[1] |= MEM_XMMTAG; - else mmregs[1] = EAX; - - assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 ); - if( recMemConstRead32(mmregs[0], g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4))) ) { - if( mmregs[0]&MEM_XMMTAG ) xmmregs[mmregs[0]&0xf].inuse = 0; - MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[0] ].UL, EBX ); - written = 1; - } - ineax = recMemConstRead32(mmregs[1], g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4+4))); - - if( !written ) { - if( !(mmregs[0]&MEM_XMMTAG) ) MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[0] ].UL, EBX ); - } - - if( ineax || !(mmregs[1] & MEM_XMMTAG) ) { - if( mmregs[1]&MEM_XMMTAG ) xmmregs[mmregs[1]&0xf].inuse = 0; - MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[1] ].UL, EAX ); - } - } - - if( i < num ) { - // one left - int nextrt = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); - - mmreg = _allocCheckFPUtoXMM(g_pCurInstInfo+i+1, nextrt, MODE_WRITE); - if( mmreg >= 0 ) mmreg |= MEM_XMMTAG; - else mmreg = EAX; - - assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 ); - if( recMemConstRead32(mmreg, g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4))) ) { - if( mmreg&MEM_XMMTAG ) xmmregs[mmreg&0xf].inuse = 0; - MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EBX ); - written = 1; - } - else if( !IS_XMMREG(mmreg) ) MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EAX ); - } - } - else -#endif - { - int dohw; - int mmregS = _eePrepareReg_coX(_Rs_, num); - - - _deleteMMXreg(MMX_FPU+_Rt_, 2); - for(i = 0; i < num; ++i) { - nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); - _deleteMMXreg(MMX_FPU+nextrts[i], 2); - } - - mmreg = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE); - - for(i = 0; i < num; ++i) { - mmregs[i] = _allocCheckFPUtoXMM(g_pCurInstInfo+i+1, nextrts[i], MODE_WRITE); - } - - dohw = recSetMemLocation(_Rs_, _Imm_, mmregS, 0, 1); - - if( mmreg >= 0 ) { - SSEX_MOVD_RmOffset_to_XMM(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset); - } - else { - MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); - MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); - } - - for(i = 0; i < num; ++i) { - if( mmregs[i] >= 0 ) { - SSEX_MOVD_RmOffset_to_XMM(mmregs[i], ECX, PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); - } - else { - MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); - MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[i] ].UL, EAX ); - } - } - - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - MOV32RtoM((u32)&s_tempaddr, ECX); - CALLFunc( (int)recMemRead32 ); - - if( mmreg >= 0 ) SSE2_MOVD_R_to_XMM(mmreg, EAX); - else MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); - - for(i = 0; i < num; ++i) { - MOV32MtoR(ECX, (u32)&s_tempaddr); - ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-_Imm_); - CALLFunc( (int)recMemRead32 ); - - if( mmregs[i] >= 0 ) SSE2_MOVD_R_to_XMM(mmregs[i], EAX); - else MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[i] ].UL, EAX ); - } - - if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]); - else x86SetJ8A(j8Ptr[2]); - } - } -} - -void recSWC1_co( void ) -{ - int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); - -#ifdef REC_SLOWWRITE - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - int mmreg; - assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)%4 == 0 ); - - mmreg = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ); - if( mmreg >= 0 ) mmreg |= MEM_XMMTAG|(_Rt_<<16); - else { - MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); - mmreg = EAX; - } - recMemConstWrite32(g_cpuConstRegs[_Rs_].UL[0]+_Imm_, mmreg); - - mmreg = _checkXMMreg(XMMTYPE_FPREG, nextrt, MODE_READ); - if( mmreg >= 0 ) mmreg |= MEM_XMMTAG|(nextrt<<16); - else { - MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrt ].UL); - mmreg = EAX; - } - recMemConstWrite32(g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_, mmreg); - } - else -#endif - { - int dohw; - int mmregs = _eePrepareReg(_Rs_); - - int mmreg1, mmreg2; - assert( _checkMMXreg(MMX_FPU+_Rt_, MODE_READ) == -1 ); - assert( _checkMMXreg(MMX_FPU+nextrt, MODE_READ) == -1 ); - - mmreg1 = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ); - mmreg2 = _checkXMMreg(XMMTYPE_FPREG, nextrt, MODE_READ); - - dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); - - if(mmreg1 >= 0 ) { - if( mmreg2 >= 0 ) { - SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset); - SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - } - else { - MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrt ].UL); - SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset); - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - } - } - else { - if( mmreg2 >= 0 ) { - MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); - SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); - } - else { - MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); - MOV32MtoR(EDX, (int)&fpuRegs.fpr[ nextrt ].UL); - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); - MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - } - } - - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - MOV32RtoM((u32)&s_tempaddr, ECX); - - // some type of hardware write - if( mmreg1 >= 0) SSE2_MOVD_XMM_to_R(EAX, mmreg1); - else MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); - CALLFunc( (int)recMemWrite32 ); - - MOV32MtoR(ECX, (u32)&s_tempaddr); - ADD32ItoR(ECX, _Imm_co_-_Imm_); - if( mmreg2 >= 0) SSE2_MOVD_XMM_to_R(EAX, mmreg2); - else MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrt ].UL); - CALLFunc( (int)recMemWrite32 ); - - if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]); - else x86SetJ8A(j8Ptr[2]); - } - } -} - -void recSWC1_coX(int num) -{ - int i; - int mmreg = -1; - int mmregs[XMMREGS]; - int nextrts[XMMREGS]; - - assert( num > 1 && num < XMMREGS ); - - for(i = 0; i < num; ++i) { - nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); - } - -#ifdef REC_SLOWWRITE - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)%4 == 0 ); - - mmreg = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ); - if( mmreg >= 0 ) mmreg |= MEM_XMMTAG|(_Rt_<<16); - else { - MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); - mmreg = EAX; - } - recMemConstWrite32(g_cpuConstRegs[_Rs_].UL[0]+_Imm_, mmreg); - - for(i = 0; i < num; ++i) { - mmreg = _checkXMMreg(XMMTYPE_FPREG, nextrts[i], MODE_READ); - if( mmreg >= 0 ) mmreg |= MEM_XMMTAG|(nextrts[i]<<16); - else { - MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrts[i] ].UL); - mmreg = EAX; - } - recMemConstWrite32(g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4)), mmreg); - } - } - else -#endif - { - int dohw; - int mmregS = _eePrepareReg_coX(_Rs_, num); - - assert( _checkMMXreg(MMX_FPU+_Rt_, MODE_READ) == -1 ); - mmreg = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ); - - for(i = 0; i < num; ++i) { - assert( _checkMMXreg(MMX_FPU+nextrts[i], MODE_READ) == -1 ); - mmregs[i] = _checkXMMreg(XMMTYPE_FPREG, nextrts[i], MODE_READ); - } - - dohw = recSetMemLocation(_Rs_, _Imm_, mmregS, 0, 1); - - if( mmreg >= 0) { - SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg, PS2MEM_BASE_+s_nAddMemOffset); - } - else { - MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); - } - - for(i = 0; i < num; ++i) { - if( mmregs[i] >= 0) { - SSEX_MOVD_XMM_to_RmOffset(ECX, mmregs[i], PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); - } - else { - MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrts[i] ].UL); - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); - } - } - - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - MOV32RtoM((u32)&s_tempaddr, ECX); - - // some type of hardware write - if( mmreg >= 0) SSE2_MOVD_XMM_to_R(EAX, mmreg); - else MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); - CALLFunc( (int)recMemWrite32 ); - - for(i = 0; i < num; ++i) { - MOV32MtoR(ECX, (u32)&s_tempaddr); - ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-_Imm_); - if( mmregs[i] >= 0 && (xmmregs[mmregs[i]].mode&MODE_WRITE) ) SSE2_MOVD_XMM_to_R(EAX, mmregs[i]); - else MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrts[i] ].UL); - CALLFunc( (int)recMemWrite32 ); - } - - if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]); - else x86SetJ8A(j8Ptr[2]); - } - } -} - -void recLQC2_co( void ) -{ - int mmreg1 = -1, mmreg2 = -1, t0reg = -1; - int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); - -#ifdef REC_SLOWREAD - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 16 == 0 ); - - if( _Ft_ ) mmreg1 = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_WRITE); - else t0reg = _allocTempXMMreg(XMMT_FPS, -1); - recMemConstRead128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg1 >= 0 ? mmreg1 : t0reg); - - if( nextrt ) mmreg2 = _allocVFtoXMMreg(&VU0, -1, nextrt, MODE_WRITE); - else if( t0reg < 0 ) t0reg = _allocTempXMMreg(XMMT_FPS, -1); - recMemConstRead128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_)&~15, mmreg2 >= 0 ? mmreg2 : t0reg); - - if( t0reg >= 0 ) _freeXMMreg(t0reg); - } - else -#endif - { - u8* rawreadptr; - int dohw; - int mmregs = _eePrepareReg(_Rs_); - - if( _Ft_ ) mmreg1 = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_WRITE); - if( nextrt ) mmreg2 = _allocVFtoXMMreg(&VU0, -1, nextrt, MODE_WRITE); - - dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0); - - rawreadptr = x86Ptr; - if( mmreg1 >= 0 ) SSEX_MOVDQARmtoROffset(mmreg1, ECX, PS2MEM_BASE_+s_nAddMemOffset); - if( mmreg2 >= 0 ) SSEX_MOVDQARmtoROffset(mmreg2, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - - if( dohw ) { - j8Ptr[1] = JMP8(0); - SET_HWLOC_R5900(); - - // check if writing to VUs - CMP32ItoR(ECX, 0x11000000); - JAE8(rawreadptr - (x86Ptr+2)); - - MOV32RtoM((u32)&s_tempaddr, ECX); - - if( _Ft_ ) PUSH32I( (int)&VU0.VF[_Ft_].UD[0] ); - else PUSH32I( (int)&retValues[0] ); - CALLFunc( (int)recMemRead128 ); - - if( mmreg1 >= 0 ) SSEX_MOVDQA_M128_to_XMM(mmreg1, (int)&VU0.VF[_Ft_].UD[0] ); - - MOV32MtoR(ECX, (u32)&s_tempaddr); - ADD32ItoR(ECX, _Imm_co_-_Imm_); - - if( nextrt ) MOV32ItoRmOffset(ESP, (int)&VU0.VF[nextrt].UD[0], 0 ); - else MOV32ItoRmOffset(ESP, (int)&retValues[0], 0 ); - CALLFunc( (int)recMemRead128 ); - - if( mmreg2 >= 0 ) SSEX_MOVDQA_M128_to_XMM(mmreg2, (int)&VU0.VF[nextrt].UD[0] ); - - ADD32ItoR(ESP, 4); - x86SetJ8(j8Ptr[1]); - } - } - - _clearNeededXMMregs(); // needed since allocing -} - -void recSQC2_co( void ) -{ - int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); - int mmreg1, mmreg2; - -#ifdef REC_SLOWWRITE - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)%16 == 0 ); - - mmreg1 = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_READ)|MEM_XMMTAG; - mmreg2 = _allocVFtoXMMreg(&VU0, -1, nextrt, MODE_READ)|MEM_XMMTAG; - recMemConstWrite128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg1); - recMemConstWrite128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_)&~15, mmreg2); - } - else -#endif - { - u8* rawreadptr; - int dohw; - int mmregs = _eePrepareReg(_Rs_); - - mmreg1 = _checkXMMreg(XMMTYPE_VFREG, _Ft_, MODE_READ); - mmreg2 = _checkXMMreg(XMMTYPE_VFREG, nextrt, MODE_READ); - - dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0); - - rawreadptr = x86Ptr; - - if( mmreg1 >= 0 ) { - SSEX_MOVDQARtoRmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset); - } - else { - if( _hasFreeXMMreg() ) { - mmreg1 = _allocTempXMMreg(XMMT_FPS, -1); - SSEX_MOVDQA_M128_to_XMM(mmreg1, (int)&VU0.VF[_Ft_].UD[0]); - SSEX_MOVDQARtoRmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset); - _freeXMMreg(mmreg1); - } - else if( _hasFreeMMXreg() ) { - mmreg1 = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQMtoR(mmreg1, (int)&VU0.VF[_Ft_].UD[0]); - MOVQRtoRmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset); - MOVQMtoR(mmreg1, (int)&VU0.VF[_Ft_].UL[2]); - MOVQRtoRmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset+8); - SetMMXstate(); - _freeMMXreg(mmreg1); - } - else { - MOV32MtoR(EAX, (int)&VU0.VF[_Ft_].UL[0]); - MOV32MtoR(EDX, (int)&VU0.VF[_Ft_].UL[1]); - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); - MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+4); - MOV32MtoR(EAX, (int)&VU0.VF[_Ft_].UL[2]); - MOV32MtoR(EDX, (int)&VU0.VF[_Ft_].UL[3]); - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+8); - MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+12); - } - } - - if( mmreg2 >= 0 ) { - SSEX_MOVDQARtoRmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - } - else { - if( _hasFreeXMMreg() ) { - mmreg2 = _allocTempXMMreg(XMMT_FPS, -1); - SSEX_MOVDQA_M128_to_XMM(mmreg2, (int)&VU0.VF[nextrt].UD[0]); - SSEX_MOVDQARtoRmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - _freeXMMreg(mmreg2); - } - else if( _hasFreeMMXreg() ) { - mmreg2 = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQMtoR(mmreg2, (int)&VU0.VF[nextrt].UD[0]); - MOVQRtoRmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - MOVQMtoR(mmreg2, (int)&VU0.VF[nextrt].UL[2]); - MOVQRtoRmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+8); - SetMMXstate(); - _freeMMXreg(mmreg2); - } - else { - MOV32MtoR(EAX, (int)&VU0.VF[nextrt].UL[0]); - MOV32MtoR(EDX, (int)&VU0.VF[nextrt].UL[1]); - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); - MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+4); - MOV32MtoR(EAX, (int)&VU0.VF[nextrt].UL[2]); - MOV32MtoR(EDX, (int)&VU0.VF[nextrt].UL[3]); - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+8); - MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+12); - } - } - - if( dohw ) { - j8Ptr[1] = JMP8(0); - - SET_HWLOC_R5900(); - - // check if writing to VUs - CMP32ItoR(ECX, 0x11000000); - JAE8(rawreadptr - (x86Ptr+2)); - - // some type of hardware write - if( mmreg1 >= 0) { - if( xmmregs[mmreg1].mode & MODE_WRITE ) { - SSEX_MOVDQA_XMM_to_M128((int)&VU0.VF[_Ft_].UD[0], mmreg1); - } - } - - MOV32RtoM((u32)&s_tempaddr, ECX); - - MOV32ItoR(EAX, (int)&VU0.VF[_Ft_].UD[0]); - CALLFunc( (int)recMemWrite128 ); - - if( mmreg2 >= 0) { - if( xmmregs[mmreg2].mode & MODE_WRITE ) { - SSEX_MOVDQA_XMM_to_M128((int)&VU0.VF[nextrt].UD[0], mmreg2); - } - } - - MOV32MtoR(ECX, (u32)&s_tempaddr); - ADD32ItoR(ECX, _Imm_co_-_Imm_); - - MOV32ItoR(EAX, (int)&VU0.VF[nextrt].UD[0]); - CALLFunc( (int)recMemWrite128 ); - - x86SetJ8A(j8Ptr[1]); - } - } -} - -#endif // PCSX2_VM_COISSUE +/* Pcsx2 - Pc Ps2 Emulator +* Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#ifdef PCSX2_VM_COISSUE + +#include "Common.h" +#include "R5900OpcodeTables.h" +#include "iR5900LoadStore.h" +#include "ix86/ix86.h" +#include "iR5900.h" + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl { + +#define _Imm_co_ (*(s16*)PSM(pc)) + +int _eePrepareReg_coX(int gprreg, int num) +{ + int mmreg = _eePrepareReg(gprreg); + + if( (mmreg&MEM_MMXTAG) && num == 7 ) { + if( mmxregs[mmreg&0xf].mode & MODE_WRITE ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[gprreg], mmreg&0xf); + mmxregs[mmreg&0xf].mode &= ~MODE_WRITE; + mmxregs[mmreg&0xf].needed = 0; + } + } + + return mmreg; +} + +void recLoad32_co(u32 bit, u32 sign) +{ + int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); + int mmreg1 = -1, mmreg2 = -1; + +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + int ineax = 0; + u32 written = 0; + + _eeOnLoadWrite(_Rt_); + _eeOnLoadWrite(nextrt); + + if( bit == 32 ) { + mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( mmreg1 >= 0 ) mmreg1 |= MEM_MMXTAG; + else mmreg1 = EBX; + + mmreg2 = _allocCheckGPRtoMMX(g_pCurInstInfo+1, nextrt, MODE_WRITE); + if( mmreg2 >= 0 ) mmreg2 |= MEM_MMXTAG; + else mmreg2 = EAX; + } + else { + _deleteEEreg(_Rt_, 0); + _deleteEEreg(nextrt, 0); + mmreg1 = EBX; + mmreg2 = EAX; + } + + // do const processing + switch(bit) { + case 8: + if( recMemConstRead8(mmreg1, g_cpuConstRegs[_Rs_].UL[0]+_Imm_, sign) ) { + if( mmreg1&MEM_MMXTAG ) mmxregs[mmreg1&0xf].inuse = 0; + if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); + written = 1; + } + ineax = recMemConstRead8(mmreg2, g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_, sign); + break; + case 16: + if( recMemConstRead16(mmreg1, g_cpuConstRegs[_Rs_].UL[0]+_Imm_, sign) ) { + if( mmreg1&MEM_MMXTAG ) mmxregs[mmreg1&0xf].inuse = 0; + if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); + written = 1; + } + ineax = recMemConstRead16(mmreg2, g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_, sign); + break; + case 32: + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 ); + if( recMemConstRead32(mmreg1, g_cpuConstRegs[_Rs_].UL[0]+_Imm_) ) { + if( mmreg1&MEM_MMXTAG ) mmxregs[mmreg1&0xf].inuse = 0; + if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); + written = 1; + } + ineax = recMemConstRead32(mmreg2, g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_); + break; + } + + if( !written && _Rt_ ) { + if( mmreg1&MEM_MMXTAG ) { + assert( mmxregs[mmreg1&0xf].mode & MODE_WRITE ); + if( sign ) _signExtendGPRtoMMX(mmreg1&0xf, _Rt_, 32-bit); + else if( bit < 32 ) PSRLDItoR(mmreg1&0xf, 32-bit); + } + else recTransferX86ToReg(mmreg1, _Rt_, sign); + } + if( nextrt ) { + g_pCurInstInfo++; + if( !ineax && (mmreg2 & MEM_MMXTAG) ) { + assert( mmxregs[mmreg2&0xf].mode & MODE_WRITE ); + if( sign ) _signExtendGPRtoMMX(mmreg2&0xf, nextrt, 32-bit); + else if( bit < 32 ) PSRLDItoR(mmreg2&0xf, 32-bit); + } + else { + if( mmreg2&MEM_MMXTAG ) mmxregs[mmreg2&0xf].inuse = 0; + recTransferX86ToReg(mmreg2, nextrt, sign); + } + g_pCurInstInfo--; + } + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + assert( !REC_FORCEMMX ); + + _eeOnLoadWrite(_Rt_); + _eeOnLoadWrite(nextrt); + _deleteEEreg(_Rt_, 0); + _deleteEEreg(nextrt, 0); + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); + + switch(bit) { + case 8: + if( sign ) { + MOVSX32Rm8toROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOVSX32Rm8toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + else { + MOVZX32Rm8toROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOVZX32Rm8toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + break; + case 16: + if( sign ) { + MOVSX32Rm16toROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOVSX32Rm16toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + else { + MOVZX32Rm16toROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOVZX32Rm16toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + break; + case 32: + MOV32RmtoROffset(EBX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + break; + } + + if ( _Rt_ ) recTransferX86ToReg(EBX, _Rt_, sign); + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + switch(bit) { + case 8: + MOV32RtoM((u32)&s_tempaddr, ECX); + CALLFunc( (int)recMemRead8 ); + if( sign ) MOVSX32R8toR(EAX, EAX); + MOV32MtoR(ECX, (u32)&s_tempaddr); + if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); + + ADD32ItoR(ECX, _Imm_co_-_Imm_); + CALLFunc( (int)recMemRead8 ); + if( sign ) MOVSX32R8toR(EAX, EAX); + break; + case 16: + MOV32RtoM((u32)&s_tempaddr, ECX); + CALLFunc( (int)recMemRead16 ); + if( sign ) MOVSX32R16toR(EAX, EAX); + MOV32MtoR(ECX, (u32)&s_tempaddr); + if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); + + ADD32ItoR(ECX, _Imm_co_-_Imm_); + CALLFunc( (int)recMemRead16 ); + if( sign ) MOVSX32R16toR(EAX, EAX); + break; + case 32: + MOV32RtoM((u32)&s_tempaddr, ECX); + iMemRead32Check(); + CALLFunc( (int)recMemRead32 ); + MOV32MtoR(ECX, (u32)&s_tempaddr); + if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); + + ADD32ItoR(ECX, _Imm_co_-_Imm_); + iMemRead32Check(); + CALLFunc( (int)recMemRead32 ); + break; + } + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + + if( nextrt ) { + g_pCurInstInfo++; + recTransferX86ToReg(EAX, nextrt, sign); + g_pCurInstInfo--; + } + } +} + +void recLB_co( void ) { recLoad32_co(8, 1); } +void recLBU_co( void ) { recLoad32_co(8, 0); } +void recLH_co( void ) { recLoad32_co(16, 1); } +void recLHU_co( void ) { recLoad32_co(16, 0); } +void recLW_co( void ) { recLoad32_co(32, 1); } +void recLWU_co( void ) { recLoad32_co(32, 0); } +void recLDL_co(void) { recLoad64(_Imm_-7, 0); } +void recLDR_co(void) { recLoad64(_Imm_, 0); } +void recLWL_co(void) { recLoad32(32, _Imm_-3, 1); } // paired with LWR +void recLWR_co(void) { recLoad32(32, _Imm_, 1); } // paired with LWL + +void recLD_co( void ) +{ +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + recLD(); + g_pCurInstInfo++; + cpuRegs.code = *(u32*)PSM(pc); + recLD(); + g_pCurInstInfo--; // incremented later + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + int mmreg1 = -1, mmreg2 = -1, t0reg = -1, t1reg = -1; + int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); + + if( _Rt_ ) _eeOnWriteReg(_Rt_, 0); + if( nextrt ) _eeOnWriteReg(nextrt, 0); + + if( _Rt_ ) { + mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( mmreg1 < 0 ) { + mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE|MODE_READ); + if( mmreg1 >= 0 ) mmreg1 |= 0x8000; + } + + if( mmreg1 < 0 && _hasFreeMMXreg() ) mmreg1 = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE); + } + + if( nextrt ) { + mmreg2 = _allocCheckGPRtoMMX(g_pCurInstInfo+1, nextrt, MODE_WRITE); + if( mmreg2 < 0 ) { + mmreg2 = _allocCheckGPRtoXMM(g_pCurInstInfo+1, nextrt, MODE_WRITE|MODE_READ); + if( mmreg2 >= 0 ) mmreg2 |= 0x8000; + } + + if( mmreg2 < 0 && _hasFreeMMXreg() ) mmreg2 = _allocMMXreg(-1, MMX_GPR+nextrt, MODE_WRITE); + } + + if( mmreg1 < 0 || mmreg2 < 0 ) { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + if( mmreg1 < 0 && mmreg2 < 0 && _hasFreeMMXreg() ) { + t1reg = _allocMMXreg(-1, MMX_TEMP, 0); + } + else t1reg = t0reg; + } + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 1, 0); + + if( mmreg1 >= 0 ) { + if( mmreg1 & 0x8000 ) SSE_MOVLPSRmtoROffset(mmreg1&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); + else MOVQRmtoROffset(mmreg1, ECX, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + if( _Rt_ ) { + MOVQRmtoROffset(t0reg, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], t0reg); + } + } + + if( mmreg2 >= 0 ) { + if( mmreg2 & 0x8000 ) SSE_MOVLPSRmtoROffset(mmreg2&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + else MOVQRmtoROffset(mmreg2, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + else { + if( nextrt ) { + MOVQRmtoROffset(t1reg, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + MOVQRtoM((int)&cpuRegs.GPR.r[ nextrt ].UL[ 0 ], t1reg); + } + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + + if( mmreg1 >= 0 ) { + PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + CALLFunc( (int)recMemRead64 ); + + if( mmreg1 & 0x8000 ) SSE_MOVLPS_M64_to_XMM(mmreg1&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); + else MOVQMtoR(mmreg1, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); + } + else { + if( _Rt_ ) { + _deleteEEreg(_Rt_, 0); + PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + } + else PUSH32I( (int)&retValues[0] ); + + CALLFunc( (int)recMemRead64 ); + } + + MOV32MtoR(ECX, (u32)&s_tempaddr); + + if( mmreg2 >= 0 ) { + MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[ nextrt ].UD[ 0 ], 0 ); + ADD32ItoR(ECX, _Imm_co_-_Imm_); + CALLFunc( (int)recMemRead64 ); + + if( mmreg2 & 0x8000 ) SSE_MOVLPS_M64_to_XMM(mmreg2&0xf, (int)&cpuRegs.GPR.r[ nextrt ].UD[ 0 ]); + else MOVQMtoR(mmreg2, (int)&cpuRegs.GPR.r[ nextrt ].UD[ 0 ]); + } + else { + if( nextrt ) { + _deleteEEreg(nextrt, 0); + MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[ nextrt ].UD[ 0 ], 0 ); + } + else MOV32ItoRmOffset(ESP, (int)&retValues[0], 0 ); + + ADD32ItoR(ECX, _Imm_co_-_Imm_); + CALLFunc( (int)recMemRead64 ); + } + + ADD32ItoR(ESP, 4); + + if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]); + else x86SetJ8A(j8Ptr[2]); + } + + if( mmreg1 < 0 || mmreg2 < 0 || !(mmreg1&0x8000) || !(mmreg2&0x8000) ) SetMMXstate(); + + if( t0reg >= 0 ) _freeMMXreg(t0reg); + if( t0reg != t1reg && t1reg >= 0 ) _freeMMXreg(t1reg); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + } +} + +void recLD_coX( int num ) +{ + int i; + int mmreg = -1; + int mmregs[XMMREGS]; + int nextrts[XMMREGS]; + + assert( num > 1 && num < XMMREGS ); + +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + recLD(); + + for(i = 0; i < num; ++i) { + g_pCurInstInfo++; + cpuRegs.code = *(u32*)PSM(pc+i*4); + recLD(); + } + + g_pCurInstInfo -= num; // incremented later + } + else +#endif + { + int dohw; + int mmregS = _eePrepareReg_coX(_Rs_, num); + + if( _Rt_ ) _eeOnWriteReg(_Rt_, 0); + for(i = 0; i < num; ++i) { + nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); + _eeOnWriteReg(nextrts[i], 0); + } + + if( _Rt_ ) { + mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( mmreg < 0 ) { + mmreg = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE|MODE_READ); + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG; + else mmreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE)|MEM_MMXTAG; + } + else mmreg |= MEM_MMXTAG; + } + + for(i = 0; i < num; ++i) { + mmregs[i] = _allocCheckGPRtoMMX(g_pCurInstInfo+i+1, nextrts[i], MODE_WRITE); + if( mmregs[i] < 0 ) { + mmregs[i] = _allocCheckGPRtoXMM(g_pCurInstInfo+i+1, nextrts[i], MODE_WRITE|MODE_READ); + if( mmregs[i] >= 0 ) mmregs[i] |= MEM_XMMTAG; + else mmregs[i] = _allocMMXreg(-1, MMX_GPR+nextrts[i], MODE_WRITE)|MEM_MMXTAG; + } + else mmregs[i] |= MEM_MMXTAG; + } + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregS, 1, 0); + + if( mmreg >= 0 ) { + if( mmreg & MEM_XMMTAG ) SSE_MOVLPSRmtoROffset(mmreg&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); + else MOVQRmtoROffset(mmreg&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); + } + + for(i = 0; i < num; ++i) { + u32 off = PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_; + + if( mmregs[i] >= 0 ) { + if( mmregs[i] & MEM_XMMTAG ) SSE_MOVLPSRmtoROffset(mmregs[i]&0xf, ECX, off); + else MOVQRmtoROffset(mmregs[i]&0xf, ECX, off); + } + } + + if( dohw ) { + if( (s_bCachingMem & 2) || num > 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + + if( mmreg >= 0 ) { + PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + CALLFunc( (int)recMemRead64 ); + + if( mmreg & MEM_XMMTAG ) SSE_MOVLPS_M64_to_XMM(mmreg&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); + else MOVQMtoR(mmreg&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); + } + else { + PUSH32I( (int)&retValues[0] ); + CALLFunc( (int)recMemRead64 ); + } + + for(i = 0; i < num; ++i ) { + MOV32MtoR(ECX, (u32)&s_tempaddr); + ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-_Imm_); + + if( mmregs[i] >= 0 ) { + MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[nextrts[i]].UL[0], 0); + CALLFunc( (int)recMemRead64 ); + + if( mmregs[i] & MEM_XMMTAG ) SSE_MOVLPS_M64_to_XMM(mmregs[i]&0xf, (int)&cpuRegs.GPR.r[ nextrts[i] ].UD[ 0 ]); + else MOVQMtoR(mmregs[i]&0xf, (int)&cpuRegs.GPR.r[ nextrts[i] ].UD[ 0 ]); + } + else { + MOV32ItoRmOffset(ESP, (int)&retValues[0], 0); + CALLFunc( (int)recMemRead64 ); + } + } + + ADD32ItoR(ESP, 4); + + if( (s_bCachingMem & 2) || num > 2 ) x86SetJ32A(j32Ptr[4]); + else x86SetJ8A(j8Ptr[2]); + } + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + } +} + +void recLQ_co( void ) +{ +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + recLQ(); + g_pCurInstInfo++; + cpuRegs.code = *(u32*)PSM(pc); + recLQ(); + g_pCurInstInfo--; // incremented later + } + else +#endif + { + int dohw; + int t0reg = -1; + int mmregs = _eePrepareReg(_Rs_); + + int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); + int mmreg1 = -1, mmreg2 = -1; + + if( _Rt_ ) { + _eeOnWriteReg(_Rt_, 0); + + if( _hasFreeMMXreg() ) { + mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( mmreg1 >= 0 ) { + mmreg1 |= MEM_MMXTAG; + if( t0reg < 0 ) t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + } + } + else _deleteMMXreg(MMX_GPR+_Rt_, 2); + + if( mmreg1 < 0 ) { + mmreg1 = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); + if( mmreg1 >= 0 ) mmreg1 |= MEM_XMMTAG; + } + } + + if( nextrt ) { + _eeOnWriteReg(nextrt, 0); + + if( _hasFreeMMXreg() ) { + mmreg2 = _allocCheckGPRtoMMX(g_pCurInstInfo+1, nextrt, MODE_WRITE); + if( mmreg2 >= 0 ) { + mmreg2 |= MEM_MMXTAG; + if( t0reg < 0 ) t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + } + } + else _deleteMMXreg(MMX_GPR+nextrt, 2); + + if( mmreg2 < 0 ) { + mmreg2 = _allocGPRtoXMMreg(-1, nextrt, MODE_WRITE); + if( mmreg2 >= 0 ) mmreg2 |= MEM_XMMTAG; + } + } + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0); + + if( _Rt_ ) { + if( mmreg1 >= 0 && (mmreg1 & MEM_MMXTAG) ) { + MOVQRmtoROffset(t0reg, ECX, PS2MEM_BASE_+s_nAddMemOffset+8); + MOVQRmtoROffset(mmreg1&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_].UL[2], t0reg); + } + else if( mmreg1 >= 0 && (mmreg1 & MEM_XMMTAG) ) { + SSEX_MOVDQARmtoROffset(mmreg1&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + _recMove128RmOffsettoM((u32)&cpuRegs.GPR.r[_Rt_].UL[0], PS2MEM_BASE_+s_nAddMemOffset); + } + } + + if( nextrt ) { + if( mmreg2 >= 0 && (mmreg2 & MEM_MMXTAG) ) { + MOVQRmtoROffset(t0reg, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+8); + MOVQRmtoROffset(mmreg2&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + MOVQRtoM((u32)&cpuRegs.GPR.r[nextrt].UL[2], t0reg); + } + else if( mmreg2 >= 0 && (mmreg2 & MEM_XMMTAG) ) { + SSEX_MOVDQARmtoROffset(mmreg2&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + else { + _recMove128RmOffsettoM((u32)&cpuRegs.GPR.r[nextrt].UL[0], PS2MEM_BASE_+s_nAddMemOffset); + } + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + if( _Rt_ ) PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + else PUSH32I( (int)&retValues[0] ); + CALLFunc( (int)recMemRead128 ); + + MOV32MtoR(ECX, (u32)&s_tempaddr); + if( nextrt ) MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[nextrt].UL[0], 0); + else MOV32ItoRmOffset(ESP, (int)&retValues[0], 0); + ADD32ItoR(ECX, _Imm_co_-_Imm_); + CALLFunc( (int)recMemRead128 ); + + if( _Rt_) { + if( mmreg1 >= 0 && (mmreg1 & MEM_MMXTAG) ) MOVQMtoR(mmreg1&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + else if( mmreg1 >= 0 && (mmreg1 & MEM_XMMTAG) ) SSEX_MOVDQA_M128_to_XMM(mmreg1&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + if( nextrt ) { + if( mmreg2 >= 0 && (mmreg2 & MEM_MMXTAG) ) MOVQMtoR(mmreg2&0xf, (int)&cpuRegs.GPR.r[ nextrt ].UL[ 0 ]); + else if( mmreg2 >= 0 && (mmreg2 & MEM_XMMTAG) ) SSEX_MOVDQA_M128_to_XMM(mmreg2&0xf, (int)&cpuRegs.GPR.r[ nextrt ].UL[ 0 ] ); + } + ADD32ItoR(ESP, 4); + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + + if( t0reg >= 0 ) _freeMMXreg(t0reg); + } +} + +// coissues more than 2 LQs +void recLQ_coX(int num) +{ + int i; + int mmreg = -1; + int mmregs[XMMREGS]; + int nextrts[XMMREGS]; + + assert( num > 1 && num < XMMREGS ); + +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + recLQ(); + + for(i = 0; i < num; ++i) { + g_pCurInstInfo++; + cpuRegs.code = *(u32*)PSM(pc+i*4); + recLQ(); + } + + g_pCurInstInfo -= num; // incremented later + } + else +#endif + { + int dohw; + int mmregS = _eePrepareReg_coX(_Rs_, num); + + + if( _Rt_ ) _deleteMMXreg(MMX_GPR+_Rt_, 2); + for(i = 0; i < num; ++i) { + nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); + if( nextrts[i] ) _deleteMMXreg(MMX_GPR+nextrts[i], 2); + } + + if( _Rt_ ) { + _eeOnWriteReg(_Rt_, 0); + mmreg = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); + } + + for(i = 0; i < num; ++i) { + if( nextrts[i] ) { + _eeOnWriteReg(nextrts[i], 0); + mmregs[i] = _allocGPRtoXMMreg(-1, nextrts[i], MODE_WRITE); + } + else mmregs[i] = -1; + } + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregS, 2, 1); + + if( _Rt_ ) SSEX_MOVDQARmtoROffset(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset); + + for(i = 0; i < num; ++i) { + u32 off = s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_; + if( nextrts[i] ) SSEX_MOVDQARmtoROffset(mmregs[i], ECX, PS2MEM_BASE_+off&~0xf); + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + + if( _Rt_ ) PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + else PUSH32I( (int)&retValues[0] ); + CALLFunc( (int)recMemRead128 ); + if( _Rt_) SSEX_MOVDQA_M128_to_XMM(mmreg, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + + for(i = 0; i < num; ++i) { + MOV32MtoR(ECX, (u32)&s_tempaddr); + ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-_Imm_); + + if( nextrts[i] ) MOV32ItoRmOffset(ESP, (int)&cpuRegs.GPR.r[nextrts[i]].UL[0], 0); + else MOV32ItoRmOffset(ESP, (int)&retValues[0], 0); + CALLFunc( (int)recMemRead128 ); + if( nextrts[i] ) SSEX_MOVDQA_M128_to_XMM(mmregs[i], (int)&cpuRegs.GPR.r[ nextrts[i] ].UL[ 0 ] ); + } + + ADD32ItoR(ESP, 4); + + if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]); + else x86SetJ8A(j8Ptr[2]); + } + } +} + +void recStore_co(int bit, int align) +{ + int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); + +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + u32 addr = g_cpuConstRegs[_Rs_].UL[0]+_Imm_; + u32 coaddr = g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_; + int mmreg, t0reg = -1, mmreg2; + int doclear = 0; + + switch(bit) { + case 8: + if( GPR_IS_CONST1(_Rt_) ) doclear |= recMemConstWrite8(addr, MEM_EECONSTTAG|(_Rt_<<16)); + else { + _eeMoveGPRtoR(EAX, _Rt_); + doclear |= recMemConstWrite8(addr, EAX); + } + if( GPR_IS_CONST1(nextrt) ) doclear |= recMemConstWrite8(coaddr, MEM_EECONSTTAG|(nextrt<<16)); + else { + _eeMoveGPRtoR(EAX, nextrt); + doclear |= recMemConstWrite8(coaddr, EAX); + } + break; + case 16: + assert( (addr)%2 == 0 ); + assert( (coaddr)%2 == 0 ); + + if( GPR_IS_CONST1(_Rt_) ) doclear |= recMemConstWrite16(addr, MEM_EECONSTTAG|(_Rt_<<16)); + else { + _eeMoveGPRtoR(EAX, _Rt_); + doclear |= recMemConstWrite16(addr, EAX); + } + + if( GPR_IS_CONST1(nextrt) ) doclear |= recMemConstWrite16(coaddr, MEM_EECONSTTAG|(nextrt<<16)); + else { + _eeMoveGPRtoR(EAX, nextrt); + doclear |= recMemConstWrite16(coaddr, EAX); + } + break; + case 32: + assert( (addr)%4 == 0 ); + if( GPR_IS_CONST1(_Rt_) ) doclear = recMemConstWrite32(addr, MEM_EECONSTTAG|(_Rt_<<16)); + else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ)) >= 0 ) { + doclear = recMemConstWrite32(addr, mmreg|MEM_XMMTAG|(_Rt_<<16)); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_READ)) >= 0 ) { + doclear = recMemConstWrite32(addr, mmreg|MEM_MMXTAG|(_Rt_<<16)); + } + else { + _eeMoveGPRtoR(EAX, _Rt_); + doclear = recMemConstWrite32(addr, EAX); + } + + if( GPR_IS_CONST1(nextrt) ) doclear |= recMemConstWrite32(coaddr, MEM_EECONSTTAG|(nextrt<<16)); + else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, nextrt, MODE_READ)) >= 0 ) { + doclear |= recMemConstWrite32(coaddr, mmreg|MEM_XMMTAG|(nextrt<<16)); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+nextrt, MODE_READ)) >= 0 ) { + doclear |= recMemConstWrite32(coaddr, mmreg|MEM_MMXTAG|(nextrt<<16)); + } + else { + _eeMoveGPRtoR(EAX, nextrt); + doclear |= recMemConstWrite32(coaddr, EAX); + } + + break; + case 64: + { + int mask = align ? ~7 : ~0; + //assert( (addr)%8 == 0 ); + + if( GPR_IS_CONST1(_Rt_) ) mmreg = MEM_EECONSTTAG|(_Rt_<<16); + else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ)) >= 0 ) { + mmreg |= MEM_XMMTAG|(_Rt_<<16); + } + else mmreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ)|MEM_MMXTAG|(_Rt_<<16); + + if( GPR_IS_CONST1(nextrt) ) mmreg2 = MEM_EECONSTTAG|(nextrt<<16); + else if( (mmreg2 = _checkXMMreg(XMMTYPE_GPRREG, nextrt, MODE_READ)) >= 0 ) { + mmreg2 |= MEM_XMMTAG|(nextrt<<16); + } + else mmreg2 = _allocMMXreg(-1, MMX_GPR+nextrt, MODE_READ)|MEM_MMXTAG|(nextrt<<16); + + doclear = recMemConstWrite64((addr)&mask, mmreg); + doclear |= recMemConstWrite64((coaddr)&mask, mmreg2); + doclear <<= 1; + break; + } + case 128: + assert( (addr)%16 == 0 ); + + mmreg = _eePrepConstWrite128(_Rt_); + mmreg2 = _eePrepConstWrite128(nextrt); + doclear = recMemConstWrite128((addr)&~15, mmreg); + doclear |= recMemConstWrite128((coaddr)&~15, mmreg2); + doclear <<= 2; + break; + } + + if( doclear ) { + u8* ptr; + CMP32ItoM((u32)&maxrecmem, g_cpuConstRegs[_Rs_].UL[0]+(_Imm_ < _Imm_co_ ? _Imm_ : _Imm_co_)); + ptr = JB8(0); + recMemConstClear((addr)&~(doclear*4-1), doclear); + recMemConstClear((coaddr)&~(doclear*4-1), doclear); + x86SetJ8A(ptr); + } + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + int off = _Imm_co_-_Imm_; + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, align ? bit/64 : 0, bit==128); + + recStore_raw(g_pCurInstInfo, bit, EAX, _Rt_, s_nAddMemOffset); + recStore_raw(g_pCurInstInfo+1, bit, EBX, nextrt, s_nAddMemOffset+off); + + // clear the writes, do only one camera (with the lowest addr) + if( off < 0 ) ADD32ItoR(ECX, s_nAddMemOffset+off); + else if( s_nAddMemOffset ) ADD32ItoR(ECX, s_nAddMemOffset); + CMP32MtoR(ECX, (u32)&maxrecmem); + + if( s_bCachingMem & 2 ) j32Ptr[5] = JAE32(0); + else j8Ptr[1] = JAE8(0); + + MOV32RtoM((u32)&s_tempaddr, ECX); + + if( bit < 32 ) AND8ItoR(ECX, 0xfc); + if( bit <= 32 ) CALLFunc((uptr)recWriteMemClear32); + else if( bit == 64 ) CALLFunc((uptr)recWriteMemClear64); + else CALLFunc((uptr)recWriteMemClear128); + + MOV32MtoR(ECX, (u32)&s_tempaddr); + if( off < 0 ) ADD32ItoR(ECX, -off); + else ADD32ItoR(ECX, off); + + if( bit < 32 ) AND8ItoR(ECX, 0xfc); + if( bit <= 32 ) CALLFunc((uptr)recWriteMemClear32); + else if( bit == 64 ) CALLFunc((uptr)recWriteMemClear64); + else CALLFunc((uptr)recWriteMemClear128); + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + recStore_call(bit, _Rt_, s_nAddMemOffset); + MOV32MtoR(ECX, (u32)&s_tempaddr); + recStore_call(bit, nextrt, s_nAddMemOffset+_Imm_co_-_Imm_); + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[5]); + else x86SetJ8(j8Ptr[1]); + } + + _clearNeededMMXregs(); // needed since allocing + _clearNeededXMMregs(); // needed since allocing +} + +void recSB_co( void ) { recStore_co(8, 1); } +void recSH_co( void ) { recStore_co(16, 1); } +void recSW_co( void ) { recStore_co(32, 1); } +void recSD_co( void ) { recStore_co(64, 1); } +void recSQ_co( void ) { recStore_co(128, 1); } + +void recSWL_co(void) { recStore(32, _Imm_-3, 0); } +void recSWR_co(void) { recStore(32, _Imm_, 0); } +void recSDL_co(void) { recStore(64, _Imm_-7, 0); } +void recSDR_co(void) { recStore(64, _Imm_, 0); } + +// coissues more than 2 SDs +void recSD_coX(int num, int align) +{ + int i; + int mmreg = -1; + int nextrts[XMMREGS]; + u32 mask = align ? ~7 : ~0; + + assert( num > 1 && num < XMMREGS ); + + for(i = 0; i < num; ++i) { + nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); + } + +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + int minimm = _Imm_; + int t0reg = -1; + int doclear = 0; + + if( GPR_IS_CONST1(_Rt_) ) mmreg = MEM_EECONSTTAG|(_Rt_<<16); + else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ)) >= 0 ) { + mmreg |= MEM_XMMTAG|(_Rt_<<16); + } + else mmreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ)|MEM_MMXTAG|(_Rt_<<16); + doclear |= recMemConstWrite64((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&mask, mmreg); + + for(i = 0; i < num; ++i) { + int imm = (*(s16*)PSM(pc+i*4)); + if( minimm > imm ) minimm = imm; + + if( GPR_IS_CONST1(nextrts[i]) ) mmreg = MEM_EECONSTTAG|(nextrts[i]<<16); + else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, nextrts[i], MODE_READ)) >= 0 ) { + mmreg |= MEM_XMMTAG|(nextrts[i]<<16); + } + else mmreg = _allocMMXreg(-1, MMX_GPR+nextrts[i], MODE_READ)|MEM_MMXTAG|(nextrts[i]<<16); + doclear |= recMemConstWrite64((g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4)))&mask, mmreg); + } + + if( doclear ) { + u32* ptr; + CMP32ItoM((u32)&maxrecmem, g_cpuConstRegs[_Rs_].UL[0]+minimm); + ptr = JB32(0); + recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~7, 4); + + for(i = 0; i < num; ++i) { + recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4)))&~7, 2); + } + x86SetJ32A(ptr); + } + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg_coX(_Rs_, num); + int minoff = 0; + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, align, 1); + + recStore_raw(g_pCurInstInfo, 64, EAX, _Rt_, s_nAddMemOffset); + + for(i = 0; i < num; ++i) { + recStore_raw(g_pCurInstInfo+i+1, 64, EAX, nextrts[i], s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); + } + + // clear the writes + minoff = _Imm_; + for(i = 0; i < num; ++i) { + if( minoff > (*(s16*)PSM(pc+i*4)) ) minoff = (*(s16*)PSM(pc+i*4)); + } + + if( s_nAddMemOffset || minoff != _Imm_ ) ADD32ItoR(ECX, s_nAddMemOffset+minoff-_Imm_); + CMP32MtoR(ECX, (u32)&maxrecmem); + if( s_bCachingMem & 2 ) j32Ptr[5] = JAE32(0); + else j8Ptr[1] = JAE8(0); + + MOV32RtoM((u32)&s_tempaddr, ECX); + if( minoff != _Imm_ ) ADD32ItoR(ECX, _Imm_-minoff); + CALLFunc((uptr)recWriteMemClear64); + + for(i = 0; i < num; ++i) { + MOV32MtoR(ECX, (u32)&s_tempaddr); + if( minoff != (*(s16*)PSM(pc+i*4)) ) ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-minoff); + CALLFunc((uptr)recWriteMemClear64); + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + recStore_call(64, _Rt_, s_nAddMemOffset); + for(i = 0; i < num; ++i) { + MOV32MtoR(ECX, (u32)&s_tempaddr); + recStore_call(64, nextrts[i], s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); + } + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[5]); + else x86SetJ8(j8Ptr[1]); + + _clearNeededMMXregs(); // needed since allocing + _clearNeededXMMregs(); // needed since allocing + } +} + +// coissues more than 2 SQs +void recSQ_coX(int num) +{ + int i; + int mmreg = -1; + int nextrts[XMMREGS]; + + assert( num > 1 && num < XMMREGS ); + + for(i = 0; i < num; ++i) { + nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); + } + +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + int minimm = _Imm_; + int t0reg = -1; + int doclear = 0; + + mmreg = _eePrepConstWrite128(_Rt_); + doclear |= recMemConstWrite128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg); + + for(i = 0; i < num; ++i) { + int imm = (*(s16*)PSM(pc+i*4)); + if( minimm > imm ) minimm = imm; + + mmreg = _eePrepConstWrite128(nextrts[i]); + doclear |= recMemConstWrite128((g_cpuConstRegs[_Rs_].UL[0]+imm)&~15, mmreg); + } + + if( doclear ) { + u32* ptr; + CMP32ItoM((u32)&maxrecmem, g_cpuConstRegs[_Rs_].UL[0]+minimm); + ptr = JB32(0); + recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, 4); + + for(i = 0; i < num; ++i) { + recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4)))&~15, 4); + } + x86SetJ32A(ptr); + } + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg_coX(_Rs_, num); + int minoff = 0; + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 1); + + recStore_raw(g_pCurInstInfo, 128, EAX, _Rt_, s_nAddMemOffset); + + for(i = 0; i < num; ++i) { + recStore_raw(g_pCurInstInfo+i+1, 128, EAX, nextrts[i], s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); + } + + // clear the writes + minoff = _Imm_; + for(i = 0; i < num; ++i) { + if( minoff > (*(s16*)PSM(pc+i*4)) ) minoff = (*(s16*)PSM(pc+i*4)); + } + + if( s_nAddMemOffset || minoff != _Imm_ ) ADD32ItoR(ECX, s_nAddMemOffset+minoff-_Imm_); + CMP32MtoR(ECX, (u32)&maxrecmem); + if( s_bCachingMem & 2 ) j32Ptr[5] = JAE32(0); + else j8Ptr[1] = JAE8(0); + + MOV32RtoM((u32)&s_tempaddr, ECX); + if( minoff != _Imm_ ) ADD32ItoR(ECX, _Imm_-minoff); + CALLFunc((uptr)recWriteMemClear128); + + for(i = 0; i < num; ++i) { + MOV32MtoR(ECX, (u32)&s_tempaddr); + if( minoff != (*(s16*)PSM(pc+i*4)) ) ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-minoff); + CALLFunc((uptr)recWriteMemClear128); + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + recStore_call(128, _Rt_, s_nAddMemOffset); + for(i = 0; i < num; ++i) { + MOV32MtoR(ECX, (u32)&s_tempaddr); + recStore_call(128, nextrts[i], s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); + } + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[5]); + else x86SetJ8(j8Ptr[1]); + + _clearNeededMMXregs(); // needed since allocing + _clearNeededXMMregs(); // needed since allocing + } +} + +void recLWC1_co( void ) +{ + int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); + +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + u32 written = 0; + int ineax, mmreg1, mmreg2; + + mmreg1 = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( mmreg1 >= 0 ) mmreg1 |= MEM_XMMTAG; + else mmreg1 = EBX; + + mmreg2 = _allocCheckFPUtoXMM(g_pCurInstInfo+1, nextrt, MODE_WRITE); + if( mmreg2 >= 0 ) mmreg2 |= MEM_XMMTAG; + else mmreg2 = EAX; + + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 ); + if( recMemConstRead32(mmreg1, g_cpuConstRegs[_Rs_].UL[0]+_Imm_) ) { + if( mmreg1&MEM_XMMTAG ) xmmregs[mmreg1&0xf].inuse = 0; + MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EBX ); + written = 1; + } + ineax = recMemConstRead32(mmreg2, g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_); + + if( !written ) { + if( !(mmreg1&MEM_XMMTAG) ) MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EBX ); + } + + if( ineax || !(mmreg2 & MEM_XMMTAG) ) { + if( mmreg2&MEM_XMMTAG ) xmmregs[mmreg2&0xf].inuse = 0; + MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EAX ); + } + } + else +#endif + { + int dohw; + int regt, regtnext; + int mmregs = _eePrepareReg(_Rs_); + + _deleteMMXreg(MMX_FPU+_Rt_, 2); + regt = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE); + regtnext = _allocCheckFPUtoXMM(g_pCurInstInfo+1, nextrt, MODE_WRITE); + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); + + if( regt >= 0 ) { + SSEX_MOVD_RmOffset_to_XMM(regt, ECX, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); + } + + if( regtnext >= 0 ) { + SSEX_MOVD_RmOffset_to_XMM(regtnext, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + else { + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EAX ); + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + PUSH32R(ECX); + CALLFunc( (int)recMemRead32 ); + POP32R(ECX); + + if( regt >= 0 ) { + SSE2_MOVD_R_to_XMM(regt, EAX); + } + else { + MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); + } + + ADD32ItoR(ECX, _Imm_co_-_Imm_); + CALLFunc( (int)recMemRead32 ); + + if( regtnext >= 0 ) { + SSE2_MOVD_R_to_XMM(regtnext, EAX); + } + else { + MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EAX ); + } + + if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]); + else x86SetJ8A(j8Ptr[2]); + } + } +} + +void recLWC1_coX(int num) +{ + int i; + int mmreg = -1; + int mmregs[XMMREGS]; + int nextrts[XMMREGS]; + + assert( num > 1 && num < XMMREGS ); + +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + int ineax; + u32 written = 0; + mmreg = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG; + else mmreg = EAX; + + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 ); + if( recMemConstRead32(mmreg, g_cpuConstRegs[_Rs_].UL[0]+_Imm_) ) { + if( mmreg&MEM_XMMTAG ) xmmregs[mmreg&0xf].inuse = 0; + MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EBX ); + written = 1; + } + else if( !IS_XMMREG(mmreg) ) MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); + + // recompile two at a time + for(i = 0; i < num-1; i += 2) { + nextrts[0] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); + nextrts[1] = ((*(u32*)(PSM(pc+i*4+4)) >> 16) & 0x1F); + + written = 0; + mmregs[0] = _allocCheckFPUtoXMM(g_pCurInstInfo+i+1, nextrts[0], MODE_WRITE); + if( mmregs[0] >= 0 ) mmregs[0] |= MEM_XMMTAG; + else mmregs[0] = EBX; + + mmregs[1] = _allocCheckFPUtoXMM(g_pCurInstInfo+i+2, nextrts[1], MODE_WRITE); + if( mmregs[1] >= 0 ) mmregs[1] |= MEM_XMMTAG; + else mmregs[1] = EAX; + + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 ); + if( recMemConstRead32(mmregs[0], g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4))) ) { + if( mmregs[0]&MEM_XMMTAG ) xmmregs[mmregs[0]&0xf].inuse = 0; + MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[0] ].UL, EBX ); + written = 1; + } + ineax = recMemConstRead32(mmregs[1], g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4+4))); + + if( !written ) { + if( !(mmregs[0]&MEM_XMMTAG) ) MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[0] ].UL, EBX ); + } + + if( ineax || !(mmregs[1] & MEM_XMMTAG) ) { + if( mmregs[1]&MEM_XMMTAG ) xmmregs[mmregs[1]&0xf].inuse = 0; + MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[1] ].UL, EAX ); + } + } + + if( i < num ) { + // one left + int nextrt = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); + + mmreg = _allocCheckFPUtoXMM(g_pCurInstInfo+i+1, nextrt, MODE_WRITE); + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG; + else mmreg = EAX; + + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 ); + if( recMemConstRead32(mmreg, g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4))) ) { + if( mmreg&MEM_XMMTAG ) xmmregs[mmreg&0xf].inuse = 0; + MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EBX ); + written = 1; + } + else if( !IS_XMMREG(mmreg) ) MOV32RtoM( (int)&fpuRegs.fpr[ nextrt ].UL, EAX ); + } + } + else +#endif + { + int dohw; + int mmregS = _eePrepareReg_coX(_Rs_, num); + + + _deleteMMXreg(MMX_FPU+_Rt_, 2); + for(i = 0; i < num; ++i) { + nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); + _deleteMMXreg(MMX_FPU+nextrts[i], 2); + } + + mmreg = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE); + + for(i = 0; i < num; ++i) { + mmregs[i] = _allocCheckFPUtoXMM(g_pCurInstInfo+i+1, nextrts[i], MODE_WRITE); + } + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregS, 0, 1); + + if( mmreg >= 0 ) { + SSEX_MOVD_RmOffset_to_XMM(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); + } + + for(i = 0; i < num; ++i) { + if( mmregs[i] >= 0 ) { + SSEX_MOVD_RmOffset_to_XMM(mmregs[i], ECX, PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); + } + else { + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); + MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[i] ].UL, EAX ); + } + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + CALLFunc( (int)recMemRead32 ); + + if( mmreg >= 0 ) SSE2_MOVD_R_to_XMM(mmreg, EAX); + else MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); + + for(i = 0; i < num; ++i) { + MOV32MtoR(ECX, (u32)&s_tempaddr); + ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-_Imm_); + CALLFunc( (int)recMemRead32 ); + + if( mmregs[i] >= 0 ) SSE2_MOVD_R_to_XMM(mmregs[i], EAX); + else MOV32RtoM( (int)&fpuRegs.fpr[ nextrts[i] ].UL, EAX ); + } + + if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]); + else x86SetJ8A(j8Ptr[2]); + } + } +} + +void recSWC1_co( void ) +{ + int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); + +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + int mmreg; + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)%4 == 0 ); + + mmreg = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ); + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG|(_Rt_<<16); + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + mmreg = EAX; + } + recMemConstWrite32(g_cpuConstRegs[_Rs_].UL[0]+_Imm_, mmreg); + + mmreg = _checkXMMreg(XMMTYPE_FPREG, nextrt, MODE_READ); + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG|(nextrt<<16); + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrt ].UL); + mmreg = EAX; + } + recMemConstWrite32(g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_, mmreg); + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + + int mmreg1, mmreg2; + assert( _checkMMXreg(MMX_FPU+_Rt_, MODE_READ) == -1 ); + assert( _checkMMXreg(MMX_FPU+nextrt, MODE_READ) == -1 ); + + mmreg1 = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ); + mmreg2 = _checkXMMreg(XMMTYPE_FPREG, nextrt, MODE_READ); + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); + + if(mmreg1 >= 0 ) { + if( mmreg2 >= 0 ) { + SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset); + SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrt ].UL); + SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + } + else { + if( mmreg2 >= 0 ) { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + MOV32MtoR(EDX, (int)&fpuRegs.fpr[ nextrt ].UL); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + + // some type of hardware write + if( mmreg1 >= 0) SSE2_MOVD_XMM_to_R(EAX, mmreg1); + else MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + CALLFunc( (int)recMemWrite32 ); + + MOV32MtoR(ECX, (u32)&s_tempaddr); + ADD32ItoR(ECX, _Imm_co_-_Imm_); + if( mmreg2 >= 0) SSE2_MOVD_XMM_to_R(EAX, mmreg2); + else MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrt ].UL); + CALLFunc( (int)recMemWrite32 ); + + if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]); + else x86SetJ8A(j8Ptr[2]); + } + } +} + +void recSWC1_coX(int num) +{ + int i; + int mmreg = -1; + int mmregs[XMMREGS]; + int nextrts[XMMREGS]; + + assert( num > 1 && num < XMMREGS ); + + for(i = 0; i < num; ++i) { + nextrts[i] = ((*(u32*)(PSM(pc+i*4)) >> 16) & 0x1F); + } + +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)%4 == 0 ); + + mmreg = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ); + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG|(_Rt_<<16); + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + mmreg = EAX; + } + recMemConstWrite32(g_cpuConstRegs[_Rs_].UL[0]+_Imm_, mmreg); + + for(i = 0; i < num; ++i) { + mmreg = _checkXMMreg(XMMTYPE_FPREG, nextrts[i], MODE_READ); + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG|(nextrts[i]<<16); + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrts[i] ].UL); + mmreg = EAX; + } + recMemConstWrite32(g_cpuConstRegs[_Rs_].UL[0]+(*(s16*)PSM(pc+i*4)), mmreg); + } + } + else +#endif + { + int dohw; + int mmregS = _eePrepareReg_coX(_Rs_, num); + + assert( _checkMMXreg(MMX_FPU+_Rt_, MODE_READ) == -1 ); + mmreg = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ); + + for(i = 0; i < num; ++i) { + assert( _checkMMXreg(MMX_FPU+nextrts[i], MODE_READ) == -1 ); + mmregs[i] = _checkXMMreg(XMMTYPE_FPREG, nextrts[i], MODE_READ); + } + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregS, 0, 1); + + if( mmreg >= 0) { + SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); + } + + for(i = 0; i < num; ++i) { + if( mmregs[i] >= 0) { + SSEX_MOVD_XMM_to_RmOffset(ECX, mmregs[i], PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); + } + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrts[i] ].UL); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+(*(s16*)PSM(pc+i*4))-_Imm_); + } + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + MOV32RtoM((u32)&s_tempaddr, ECX); + + // some type of hardware write + if( mmreg >= 0) SSE2_MOVD_XMM_to_R(EAX, mmreg); + else MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + CALLFunc( (int)recMemWrite32 ); + + for(i = 0; i < num; ++i) { + MOV32MtoR(ECX, (u32)&s_tempaddr); + ADD32ItoR(ECX, (*(s16*)PSM(pc+i*4))-_Imm_); + if( mmregs[i] >= 0 && (xmmregs[mmregs[i]].mode&MODE_WRITE) ) SSE2_MOVD_XMM_to_R(EAX, mmregs[i]); + else MOV32MtoR(EAX, (int)&fpuRegs.fpr[ nextrts[i] ].UL); + CALLFunc( (int)recMemWrite32 ); + } + + if( s_bCachingMem & 2 ) x86SetJ32A(j32Ptr[4]); + else x86SetJ8A(j8Ptr[2]); + } + } +} + +void recLQC2_co( void ) +{ + int mmreg1 = -1, mmreg2 = -1, t0reg = -1; + int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); + +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 16 == 0 ); + + if( _Ft_ ) mmreg1 = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_WRITE); + else t0reg = _allocTempXMMreg(XMMT_FPS, -1); + recMemConstRead128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg1 >= 0 ? mmreg1 : t0reg); + + if( nextrt ) mmreg2 = _allocVFtoXMMreg(&VU0, -1, nextrt, MODE_WRITE); + else if( t0reg < 0 ) t0reg = _allocTempXMMreg(XMMT_FPS, -1); + recMemConstRead128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_)&~15, mmreg2 >= 0 ? mmreg2 : t0reg); + + if( t0reg >= 0 ) _freeXMMreg(t0reg); + } + else +#endif + { + u8* rawreadptr; + int dohw; + int mmregs = _eePrepareReg(_Rs_); + + if( _Ft_ ) mmreg1 = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_WRITE); + if( nextrt ) mmreg2 = _allocVFtoXMMreg(&VU0, -1, nextrt, MODE_WRITE); + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0); + + rawreadptr = x86Ptr; + if( mmreg1 >= 0 ) SSEX_MOVDQARmtoROffset(mmreg1, ECX, PS2MEM_BASE_+s_nAddMemOffset); + if( mmreg2 >= 0 ) SSEX_MOVDQARmtoROffset(mmreg2, ECX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + + if( dohw ) { + j8Ptr[1] = JMP8(0); + SET_HWLOC_R5900(); + + // check if writing to VUs + CMP32ItoR(ECX, 0x11000000); + JAE8(rawreadptr - (x86Ptr+2)); + + MOV32RtoM((u32)&s_tempaddr, ECX); + + if( _Ft_ ) PUSH32I( (int)&VU0.VF[_Ft_].UD[0] ); + else PUSH32I( (int)&retValues[0] ); + CALLFunc( (int)recMemRead128 ); + + if( mmreg1 >= 0 ) SSEX_MOVDQA_M128_to_XMM(mmreg1, (int)&VU0.VF[_Ft_].UD[0] ); + + MOV32MtoR(ECX, (u32)&s_tempaddr); + ADD32ItoR(ECX, _Imm_co_-_Imm_); + + if( nextrt ) MOV32ItoRmOffset(ESP, (int)&VU0.VF[nextrt].UD[0], 0 ); + else MOV32ItoRmOffset(ESP, (int)&retValues[0], 0 ); + CALLFunc( (int)recMemRead128 ); + + if( mmreg2 >= 0 ) SSEX_MOVDQA_M128_to_XMM(mmreg2, (int)&VU0.VF[nextrt].UD[0] ); + + ADD32ItoR(ESP, 4); + x86SetJ8(j8Ptr[1]); + } + } + + _clearNeededXMMregs(); // needed since allocing +} + +void recSQC2_co( void ) +{ + int nextrt = ((*(u32*)(PSM(pc)) >> 16) & 0x1F); + int mmreg1, mmreg2; + +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)%16 == 0 ); + + mmreg1 = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_READ)|MEM_XMMTAG; + mmreg2 = _allocVFtoXMMreg(&VU0, -1, nextrt, MODE_READ)|MEM_XMMTAG; + recMemConstWrite128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg1); + recMemConstWrite128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_co_)&~15, mmreg2); + } + else +#endif + { + u8* rawreadptr; + int dohw; + int mmregs = _eePrepareReg(_Rs_); + + mmreg1 = _checkXMMreg(XMMTYPE_VFREG, _Ft_, MODE_READ); + mmreg2 = _checkXMMreg(XMMTYPE_VFREG, nextrt, MODE_READ); + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0); + + rawreadptr = x86Ptr; + + if( mmreg1 >= 0 ) { + SSEX_MOVDQARtoRmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + if( _hasFreeXMMreg() ) { + mmreg1 = _allocTempXMMreg(XMMT_FPS, -1); + SSEX_MOVDQA_M128_to_XMM(mmreg1, (int)&VU0.VF[_Ft_].UD[0]); + SSEX_MOVDQARtoRmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset); + _freeXMMreg(mmreg1); + } + else if( _hasFreeMMXreg() ) { + mmreg1 = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(mmreg1, (int)&VU0.VF[_Ft_].UD[0]); + MOVQRtoRmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset); + MOVQMtoR(mmreg1, (int)&VU0.VF[_Ft_].UL[2]); + MOVQRtoRmOffset(ECX, mmreg1, PS2MEM_BASE_+s_nAddMemOffset+8); + SetMMXstate(); + _freeMMXreg(mmreg1); + } + else { + MOV32MtoR(EAX, (int)&VU0.VF[_Ft_].UL[0]); + MOV32MtoR(EDX, (int)&VU0.VF[_Ft_].UL[1]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+4); + MOV32MtoR(EAX, (int)&VU0.VF[_Ft_].UL[2]); + MOV32MtoR(EDX, (int)&VU0.VF[_Ft_].UL[3]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+8); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+12); + } + } + + if( mmreg2 >= 0 ) { + SSEX_MOVDQARtoRmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + } + else { + if( _hasFreeXMMreg() ) { + mmreg2 = _allocTempXMMreg(XMMT_FPS, -1); + SSEX_MOVDQA_M128_to_XMM(mmreg2, (int)&VU0.VF[nextrt].UD[0]); + SSEX_MOVDQARtoRmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + _freeXMMreg(mmreg2); + } + else if( _hasFreeMMXreg() ) { + mmreg2 = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(mmreg2, (int)&VU0.VF[nextrt].UD[0]); + MOVQRtoRmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + MOVQMtoR(mmreg2, (int)&VU0.VF[nextrt].UL[2]); + MOVQRtoRmOffset(ECX, mmreg2, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+8); + SetMMXstate(); + _freeMMXreg(mmreg2); + } + else { + MOV32MtoR(EAX, (int)&VU0.VF[nextrt].UL[0]); + MOV32MtoR(EDX, (int)&VU0.VF[nextrt].UL[1]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+4); + MOV32MtoR(EAX, (int)&VU0.VF[nextrt].UL[2]); + MOV32MtoR(EDX, (int)&VU0.VF[nextrt].UL[3]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+8); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+_Imm_co_-_Imm_+12); + } + } + + if( dohw ) { + j8Ptr[1] = JMP8(0); + + SET_HWLOC_R5900(); + + // check if writing to VUs + CMP32ItoR(ECX, 0x11000000); + JAE8(rawreadptr - (x86Ptr+2)); + + // some type of hardware write + if( mmreg1 >= 0) { + if( xmmregs[mmreg1].mode & MODE_WRITE ) { + SSEX_MOVDQA_XMM_to_M128((int)&VU0.VF[_Ft_].UD[0], mmreg1); + } + } + + MOV32RtoM((u32)&s_tempaddr, ECX); + + MOV32ItoR(EAX, (int)&VU0.VF[_Ft_].UD[0]); + CALLFunc( (int)recMemWrite128 ); + + if( mmreg2 >= 0) { + if( xmmregs[mmreg2].mode & MODE_WRITE ) { + SSEX_MOVDQA_XMM_to_M128((int)&VU0.VF[nextrt].UD[0], mmreg2); + } + } + + MOV32MtoR(ECX, (u32)&s_tempaddr); + ADD32ItoR(ECX, _Imm_co_-_Imm_); + + MOV32ItoR(EAX, (int)&VU0.VF[nextrt].UD[0]); + CALLFunc( (int)recMemWrite128 ); + + x86SetJ8A(j8Ptr[1]); + } + } +} + +#endif // PCSX2_VM_COISSUE diff --git a/pcsx2/x86/iR5900Jump.h b/pcsx2/x86/iR5900Jump.h index a7f2472206..1c8e413c60 100644 --- a/pcsx2/x86/iR5900Jump.h +++ b/pcsx2/x86/iR5900Jump.h @@ -1,37 +1,37 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __IR5900JUMP_H__ -#define __IR5900JUMP_H__ - -/********************************************************* -* Jump to target * -* Format: OP target * -*********************************************************/ - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl { - - void recJ( void ); - void recJAL( void ); - void recJR( void ); - void recJALR( void ); -} } } - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __IR5900JUMP_H__ +#define __IR5900JUMP_H__ + +/********************************************************* +* Jump to target * +* Format: OP target * +*********************************************************/ + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl { + + void recJ( void ); + void recJAL( void ); + void recJR( void ); + void recJALR( void ); +} } } + +#endif diff --git a/pcsx2/x86/iR5900LoadStore.h b/pcsx2/x86/iR5900LoadStore.h index ed15fd2446..91298d1dab 100644 --- a/pcsx2/x86/iR5900LoadStore.h +++ b/pcsx2/x86/iR5900LoadStore.h @@ -1,95 +1,95 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __IR5900LOADSTORE_H__ -#define __IR5900LOADSTORE_H__ -/********************************************************* -* Load and store for GPR * -* Format: OP rt, offset(base) * -*********************************************************/ - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl { - - void recLB( void ); - void recLBU( void ); - void recLH( void ); - void recLHU( void ); - void recLW( void ); - void recLWU( void ); - void recLWL( void ); - void recLWR( void ); - void recLD( void ); - void recLDR( void ); - void recLDL( void ); - void recLQ( void ); - void recSB( void ); - void recSH( void ); - void recSW( void ); - void recSWL( void ); - void recSWR( void ); - void recSD( void ); - void recSDL( void ); - void recSDR( void ); - void recSQ( void ); - void recLWC1( void ); - void recSWC1( void ); - void recLQC2( void ); - void recSQC2( void ); - -// coissues -#ifdef PCSX2_VM_COISSUE - void recLB_co( void ); - void recLBU_co( void ); - void recLH_co( void ); - void recLHU_co( void ); - void recLW_co( void ); - void recLWU_co( void ); - void recLWL_co( void ); - void recLWR_co( void ); - void recLD_co( void ); - void recLDR_co( void ); - void recLDL_co( void ); - void recLQ_co( void ); - void recSB_co( void ); - void recSH_co( void ); - void recSW_co( void ); - void recSWL_co( void ); - void recSWR_co( void ); - void recSD_co( void ); - void recSDL_co( void ); - void recSDR_co( void ); - void recSQ_co( void ); - void recLWC1_co( void ); - void recSWC1_co( void ); - void recLQC2_co( void ); - void recSQC2_co( void ); - - // coissue-X - void recLD_coX(int num); - void recLQ_coX(int num); - void recLWC1_coX(int num); - void recSD_coX(int num, int align); - void recSQ_coX(int num); - void recSWC1_coX(int num); -#endif - -} } } - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __IR5900LOADSTORE_H__ +#define __IR5900LOADSTORE_H__ +/********************************************************* +* Load and store for GPR * +* Format: OP rt, offset(base) * +*********************************************************/ + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl { + + void recLB( void ); + void recLBU( void ); + void recLH( void ); + void recLHU( void ); + void recLW( void ); + void recLWU( void ); + void recLWL( void ); + void recLWR( void ); + void recLD( void ); + void recLDR( void ); + void recLDL( void ); + void recLQ( void ); + void recSB( void ); + void recSH( void ); + void recSW( void ); + void recSWL( void ); + void recSWR( void ); + void recSD( void ); + void recSDL( void ); + void recSDR( void ); + void recSQ( void ); + void recLWC1( void ); + void recSWC1( void ); + void recLQC2( void ); + void recSQC2( void ); + +// coissues +#ifdef PCSX2_VM_COISSUE + void recLB_co( void ); + void recLBU_co( void ); + void recLH_co( void ); + void recLHU_co( void ); + void recLW_co( void ); + void recLWU_co( void ); + void recLWL_co( void ); + void recLWR_co( void ); + void recLD_co( void ); + void recLDR_co( void ); + void recLDL_co( void ); + void recLQ_co( void ); + void recSB_co( void ); + void recSH_co( void ); + void recSW_co( void ); + void recSWL_co( void ); + void recSWR_co( void ); + void recSD_co( void ); + void recSDL_co( void ); + void recSDR_co( void ); + void recSQ_co( void ); + void recLWC1_co( void ); + void recSWC1_co( void ); + void recLQC2_co( void ); + void recSQC2_co( void ); + + // coissue-X + void recLD_coX(int num); + void recLQ_coX(int num); + void recLWC1_coX(int num); + void recSD_coX(int num, int align); + void recSQ_coX(int num); + void recSWC1_coX(int num); +#endif + +} } } + +#endif diff --git a/pcsx2/x86/iR5900Misc.cpp b/pcsx2/x86/iR5900Misc.cpp index cd5eda0607..1580c54658 100644 --- a/pcsx2/x86/iR5900Misc.cpp +++ b/pcsx2/x86/iR5900Misc.cpp @@ -1,252 +1,252 @@ -#include "PrecompiledHeader.h" - -#include "Common.h" -#include "iR5900.h" -#include "R5900OpcodeTables.h" - - -namespace R5900 { -namespace Dynarec { - -// R5900 branch hepler! -// Recompiles code for a branch test and/or skip, complete with delay slot -// handling. Note, for "likely" branches use iDoBranchImm_Likely instead, which -// handles delay slots differently. -// Parameters: -// jmpSkip - This parameter is the result of the appropriate J32 instruction -// (usually JZ32 or JNZ32). -void recDoBranchImm( u32* jmpSkip, bool isLikely ) -{ - // All R5900 branches use this format: - const u32 branchTo = ((s32)_Imm_ * 4) + pc; - - // First up is the Branch Taken Path : Save the recompiler's state, compile the - // DelaySlot, and issue a BranchTest insertion. The state is reloaded below for - // the "did not branch" path (maintains consts, register allocations, and other optimizations). - - SaveBranchState(); - recompileNextInstruction(1); - SetBranchImm(branchTo); - - // Jump target when the branch is *not* taken, skips the branchtest code - // insertion above. - x86SetJ32(jmpSkip); - - // if it's a likely branch then we'll need to skip the delay slot here, since - // MIPS cancels the delay slot instruction when branches aren't taken. - LoadBranchState(); - if( !isLikely ) - { - pc -= 4; // instruction rewinder for delay slot, if non-likely. - recompileNextInstruction(1); - } - SetBranchImm(pc); // start a new recompiled block. -} - -void recDoBranchImm_Likely( u32* jmpSkip ) -{ - recDoBranchImm( jmpSkip, true ); -} - -namespace OpcodeImpl { - -//////////////////////////////////////////////////// -//static void recCACHE( void ) { -// MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); -// MOV32ItoM( (uptr)&cpuRegs.pc, pc ); -// iFlushCall(FLUSH_EVERYTHING); -// CALLFunc( (uptr)CACHE ); -// //branch = 2; -// -// CMP32ItoM((int)&cpuRegs.pc, pc); -// j8Ptr[0] = JE8(0); -// RET(); -// x86SetJ8(j8Ptr[0]); -//} - - -void recPREF( void ) -{ -} - -void recSYNC( void ) -{ -} - -void recMFSA( void ) -{ - int mmreg; - if (!_Rd_) return; - - mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_WRITE); - if( mmreg >= 0 ) { - SSE_MOVLPS_M64_to_XMM(mmreg, (uptr)&cpuRegs.sa); - } - else if( (mmreg = _checkMMXreg(MMX_GPR+_Rd_, MODE_WRITE)) >= 0 ) { - MOVDMtoMMX(mmreg, (uptr)&cpuRegs.sa); - SetMMXstate(); - } - else { - MOV32MtoR(EAX, (u32)&cpuRegs.sa); - _deleteEEreg(_Rd_, 0); - MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); - MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[1], 0); - } -} - -void recMTSA( void ) -{ - if( GPR_IS_CONST1(_Rs_) ) { - MOV32ItoM((uptr)&cpuRegs.sa, g_cpuConstRegs[_Rs_].UL[0] ); - } - else { - int mmreg; - - if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ)) >= 0 ) { - SSE_MOVSS_XMM_to_M32((uptr)&cpuRegs.sa, mmreg); - } - else if( (mmreg = _checkMMXreg(MMX_GPR+_Rs_, MODE_READ)) >= 0 ) { - MOVDMMXtoM((uptr)&cpuRegs.sa, mmreg); - SetMMXstate(); - } - else { - MOV32MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[0]); - MOV32RtoM((uptr)&cpuRegs.sa, EAX); - } - } -} - -void recMTSAB( void ) -{ - if( GPR_IS_CONST1(_Rs_) ) { - MOV32ItoM((uptr)&cpuRegs.sa, ((g_cpuConstRegs[_Rs_].UL[0] & 0xF) ^ (_Imm_ & 0xF)) << 3); - } - else { - _eeMoveGPRtoR(EAX, _Rs_); - AND32ItoR(EAX, 0xF); - XOR32ItoR(EAX, _Imm_&0xf); - SHL32ItoR(EAX, 3); - MOV32RtoM((uptr)&cpuRegs.sa, EAX); - } -} - -void recMTSAH( void ) -{ - if( GPR_IS_CONST1(_Rs_) ) { - MOV32ItoM((uptr)&cpuRegs.sa, ((g_cpuConstRegs[_Rs_].UL[0] & 0x7) ^ (_Imm_ & 0x7)) << 4); - } - else { - _eeMoveGPRtoR(EAX, _Rs_); - AND32ItoR(EAX, 0x7); - XOR32ItoR(EAX, _Imm_&0x7); - SHL32ItoR(EAX, 4); - MOV32RtoM((uptr)&cpuRegs.sa, EAX); - } -} - - //////////////////////////////////////////////////// - void recNULL( void ) - { - Console::Error("EE: Unimplemented op %x", params cpuRegs.code); - } - - //////////////////////////////////////////////////// - void recUnknown() - { - // TODO : Unknown ops should throw an exception. - Console::Error("EE: Unrecognized op %x", params cpuRegs.code); - } - - void recMMI_Unknown() - { - // TODO : Unknown ops should throw an exception. - Console::Error("EE: Unrecognized MMI op %x", params cpuRegs.code); - } - - void recCOP0_Unknown() - { - // TODO : Unknown ops should throw an exception. - Console::Error("EE: Unrecognized COP0 op %x", params cpuRegs.code); - } - - void recCOP1_Unknown() - { - // TODO : Unknown ops should throw an exception. - Console::Error("EE: Unrecognized FPU/COP1 op %x", params cpuRegs.code); - } - - /********************************************************** - * UNHANDLED YET OPCODES - * - **********************************************************/ - - void recCACHE() - { - MOV32ItoM( (uptr)&cpuRegs.code, (u32)cpuRegs.code ); - MOV32ItoM( (uptr)&cpuRegs.pc, (u32)pc ); - iFlushCall(FLUSH_EVERYTHING); - CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::CACHE ); - branch = 2; - } - - void recTGE( void ) - { - recBranchCall( R5900::Interpreter::OpcodeImpl::TGE ); - } - - void recTGEU( void ) - { - recBranchCall( R5900::Interpreter::OpcodeImpl::TGEU ); - } - - void recTLT( void ) - { - recBranchCall( R5900::Interpreter::OpcodeImpl::TLT ); - } - - void recTLTU( void ) - { - recBranchCall( R5900::Interpreter::OpcodeImpl::TLTU ); - } - - void recTEQ( void ) - { - recBranchCall( R5900::Interpreter::OpcodeImpl::TEQ ); - } - - void recTNE( void ) - { - recBranchCall( R5900::Interpreter::OpcodeImpl::TNE ); - } - - void recTGEI( void ) - { - recBranchCall( R5900::Interpreter::OpcodeImpl::TGEI ); - } - - void recTGEIU( void ) - { - recBranchCall( R5900::Interpreter::OpcodeImpl::TGEIU ); - } - - void recTLTI( void ) - { - recBranchCall( R5900::Interpreter::OpcodeImpl::TLTI ); - } - - void recTLTIU( void ) - { - recBranchCall( R5900::Interpreter::OpcodeImpl::TLTIU ); - } - - void recTEQI( void ) - { - recBranchCall( R5900::Interpreter::OpcodeImpl::TEQI ); - } - - void recTNEI( void ) - { - recBranchCall( R5900::Interpreter::OpcodeImpl::TNEI ); - } - -} }} // end Namespace R5900::Dynarec::OpcodeImpl +#include "PrecompiledHeader.h" + +#include "Common.h" +#include "iR5900.h" +#include "R5900OpcodeTables.h" + + +namespace R5900 { +namespace Dynarec { + +// R5900 branch hepler! +// Recompiles code for a branch test and/or skip, complete with delay slot +// handling. Note, for "likely" branches use iDoBranchImm_Likely instead, which +// handles delay slots differently. +// Parameters: +// jmpSkip - This parameter is the result of the appropriate J32 instruction +// (usually JZ32 or JNZ32). +void recDoBranchImm( u32* jmpSkip, bool isLikely ) +{ + // All R5900 branches use this format: + const u32 branchTo = ((s32)_Imm_ * 4) + pc; + + // First up is the Branch Taken Path : Save the recompiler's state, compile the + // DelaySlot, and issue a BranchTest insertion. The state is reloaded below for + // the "did not branch" path (maintains consts, register allocations, and other optimizations). + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + // Jump target when the branch is *not* taken, skips the branchtest code + // insertion above. + x86SetJ32(jmpSkip); + + // if it's a likely branch then we'll need to skip the delay slot here, since + // MIPS cancels the delay slot instruction when branches aren't taken. + LoadBranchState(); + if( !isLikely ) + { + pc -= 4; // instruction rewinder for delay slot, if non-likely. + recompileNextInstruction(1); + } + SetBranchImm(pc); // start a new recompiled block. +} + +void recDoBranchImm_Likely( u32* jmpSkip ) +{ + recDoBranchImm( jmpSkip, true ); +} + +namespace OpcodeImpl { + +//////////////////////////////////////////////////// +//static void recCACHE( void ) { +// MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); +// MOV32ItoM( (uptr)&cpuRegs.pc, pc ); +// iFlushCall(FLUSH_EVERYTHING); +// CALLFunc( (uptr)CACHE ); +// //branch = 2; +// +// CMP32ItoM((int)&cpuRegs.pc, pc); +// j8Ptr[0] = JE8(0); +// RET(); +// x86SetJ8(j8Ptr[0]); +//} + + +void recPREF( void ) +{ +} + +void recSYNC( void ) +{ +} + +void recMFSA( void ) +{ + int mmreg; + if (!_Rd_) return; + + mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_WRITE); + if( mmreg >= 0 ) { + SSE_MOVLPS_M64_to_XMM(mmreg, (uptr)&cpuRegs.sa); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+_Rd_, MODE_WRITE)) >= 0 ) { + MOVDMtoMMX(mmreg, (uptr)&cpuRegs.sa); + SetMMXstate(); + } + else { + MOV32MtoR(EAX, (u32)&cpuRegs.sa); + _deleteEEreg(_Rd_, 0); + MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX); + MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[1], 0); + } +} + +void recMTSA( void ) +{ + if( GPR_IS_CONST1(_Rs_) ) { + MOV32ItoM((uptr)&cpuRegs.sa, g_cpuConstRegs[_Rs_].UL[0] ); + } + else { + int mmreg; + + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ)) >= 0 ) { + SSE_MOVSS_XMM_to_M32((uptr)&cpuRegs.sa, mmreg); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+_Rs_, MODE_READ)) >= 0 ) { + MOVDMMXtoM((uptr)&cpuRegs.sa, mmreg); + SetMMXstate(); + } + else { + MOV32MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[0]); + MOV32RtoM((uptr)&cpuRegs.sa, EAX); + } + } +} + +void recMTSAB( void ) +{ + if( GPR_IS_CONST1(_Rs_) ) { + MOV32ItoM((uptr)&cpuRegs.sa, ((g_cpuConstRegs[_Rs_].UL[0] & 0xF) ^ (_Imm_ & 0xF)) << 3); + } + else { + _eeMoveGPRtoR(EAX, _Rs_); + AND32ItoR(EAX, 0xF); + XOR32ItoR(EAX, _Imm_&0xf); + SHL32ItoR(EAX, 3); + MOV32RtoM((uptr)&cpuRegs.sa, EAX); + } +} + +void recMTSAH( void ) +{ + if( GPR_IS_CONST1(_Rs_) ) { + MOV32ItoM((uptr)&cpuRegs.sa, ((g_cpuConstRegs[_Rs_].UL[0] & 0x7) ^ (_Imm_ & 0x7)) << 4); + } + else { + _eeMoveGPRtoR(EAX, _Rs_); + AND32ItoR(EAX, 0x7); + XOR32ItoR(EAX, _Imm_&0x7); + SHL32ItoR(EAX, 4); + MOV32RtoM((uptr)&cpuRegs.sa, EAX); + } +} + + //////////////////////////////////////////////////// + void recNULL( void ) + { + Console::Error("EE: Unimplemented op %x", params cpuRegs.code); + } + + //////////////////////////////////////////////////// + void recUnknown() + { + // TODO : Unknown ops should throw an exception. + Console::Error("EE: Unrecognized op %x", params cpuRegs.code); + } + + void recMMI_Unknown() + { + // TODO : Unknown ops should throw an exception. + Console::Error("EE: Unrecognized MMI op %x", params cpuRegs.code); + } + + void recCOP0_Unknown() + { + // TODO : Unknown ops should throw an exception. + Console::Error("EE: Unrecognized COP0 op %x", params cpuRegs.code); + } + + void recCOP1_Unknown() + { + // TODO : Unknown ops should throw an exception. + Console::Error("EE: Unrecognized FPU/COP1 op %x", params cpuRegs.code); + } + + /********************************************************** + * UNHANDLED YET OPCODES + * + **********************************************************/ + + void recCACHE() + { + MOV32ItoM( (uptr)&cpuRegs.code, (u32)cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, (u32)pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::CACHE ); + branch = 2; + } + + void recTGE( void ) + { + recBranchCall( R5900::Interpreter::OpcodeImpl::TGE ); + } + + void recTGEU( void ) + { + recBranchCall( R5900::Interpreter::OpcodeImpl::TGEU ); + } + + void recTLT( void ) + { + recBranchCall( R5900::Interpreter::OpcodeImpl::TLT ); + } + + void recTLTU( void ) + { + recBranchCall( R5900::Interpreter::OpcodeImpl::TLTU ); + } + + void recTEQ( void ) + { + recBranchCall( R5900::Interpreter::OpcodeImpl::TEQ ); + } + + void recTNE( void ) + { + recBranchCall( R5900::Interpreter::OpcodeImpl::TNE ); + } + + void recTGEI( void ) + { + recBranchCall( R5900::Interpreter::OpcodeImpl::TGEI ); + } + + void recTGEIU( void ) + { + recBranchCall( R5900::Interpreter::OpcodeImpl::TGEIU ); + } + + void recTLTI( void ) + { + recBranchCall( R5900::Interpreter::OpcodeImpl::TLTI ); + } + + void recTLTIU( void ) + { + recBranchCall( R5900::Interpreter::OpcodeImpl::TLTIU ); + } + + void recTEQI( void ) + { + recBranchCall( R5900::Interpreter::OpcodeImpl::TEQI ); + } + + void recTNEI( void ) + { + recBranchCall( R5900::Interpreter::OpcodeImpl::TNEI ); + } + +} }} // end Namespace R5900::Dynarec::OpcodeImpl diff --git a/pcsx2/x86/iR5900Move.h b/pcsx2/x86/iR5900Move.h index 9129edcc72..e772276ace 100644 --- a/pcsx2/x86/iR5900Move.h +++ b/pcsx2/x86/iR5900Move.h @@ -1,35 +1,35 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __IR5900MOVE_H__ -#define __IR5900MOVE_H__ - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl { - - void recLUI( void ); - void recMFLO( void ); - void recMFHI( void ); - void recMTLO( void ); - void recMTHI( void ); - void recMOVN( void ); - void recMOVZ( void ); -} } } - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __IR5900MOVE_H__ +#define __IR5900MOVE_H__ + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl { + + void recLUI( void ); + void recMFLO( void ); + void recMFHI( void ); + void recMTLO( void ); + void recMTHI( void ); + void recMOVN( void ); + void recMOVZ( void ); +} } } + +#endif diff --git a/pcsx2/x86/iR5900MultDiv.h b/pcsx2/x86/iR5900MultDiv.h index 361dcafa8a..5b358b9c82 100644 --- a/pcsx2/x86/iR5900MultDiv.h +++ b/pcsx2/x86/iR5900MultDiv.h @@ -1,37 +1,37 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __IR5900MULTDIV_H__ -#define __IR5900MULTDIV_H__ - -/********************************************************* -* Register mult/div & Register trap logic * -* Format: OP rs, rt * -*********************************************************/ - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl { - - void recMULT( void ); - void recMULTU( void ); - void recDIV( void ); - void recDIVU( void ); -} } } - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __IR5900MULTDIV_H__ +#define __IR5900MULTDIV_H__ + +/********************************************************* +* Register mult/div & Register trap logic * +* Format: OP rs, rt * +*********************************************************/ + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl { + + void recMULT( void ); + void recMULTU( void ); + void recDIV( void ); + void recDIVU( void ); +} } } + +#endif diff --git a/pcsx2/x86/iR5900Shift.h b/pcsx2/x86/iR5900Shift.h index e688d2d1f4..6ff48ac433 100644 --- a/pcsx2/x86/iR5900Shift.h +++ b/pcsx2/x86/iR5900Shift.h @@ -1,49 +1,49 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#ifndef __IR5900SHIFT_H__ -#define __IR5900SHIFT_H__ - -/********************************************************* -* Shift arithmetic with constant shift * -* Format: OP rd, rt, sa * -*********************************************************/ - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl { - - void recSLL( void ); - void recSRL( void ); - void recSRA( void ); - void recDSLL( void ); - void recDSRL( void ); - void recDSRA( void ); - void recDSLL32( void ); - void recDSRL32( void ); - void recDSRA32( void ); - - void recSLLV( void ); - void recSRLV( void ); - void recSRAV( void ); - void recDSLLV( void ); - void recDSRLV( void ); - void recDSRAV( void ); -} } } - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#ifndef __IR5900SHIFT_H__ +#define __IR5900SHIFT_H__ + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl { + + void recSLL( void ); + void recSRL( void ); + void recSRA( void ); + void recDSLL( void ); + void recDSRL( void ); + void recDSRA( void ); + void recDSLL32( void ); + void recDSRL32( void ); + void recDSRA32( void ); + + void recSLLV( void ); + void recSRLV( void ); + void recSRAV( void ); + void recDSLLV( void ); + void recDSRLV( void ); + void recDSRAV( void ); +} } } + +#endif diff --git a/pcsx2/x86/iVU0micro.cpp b/pcsx2/x86/iVU0micro.cpp index baf28fee47..add519770d 100644 --- a/pcsx2/x86/iVU0micro.cpp +++ b/pcsx2/x86/iVU0micro.cpp @@ -1,76 +1,76 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "ix86/ix86.h" -#include "iR5900.h" -#include "VUmicro.h" -#include "iVUzerorec.h" - -namespace VU0micro -{ - void recAlloc() - { - SuperVUAlloc(0); - } - - void __fastcall recClear(u32 Addr, u32 Size) - { - SuperVUClear(Addr, Size, 0); // Size should be a multiple of 8 bytes! - } - - void recShutdown() - { - SuperVUDestroy( 0 ); - } - - static void recReset() - { - SuperVUReset(0); - - // these shouldn't be needed, but shouldn't hurt anything either. - x86FpuState = FPU_STATE; - iCWstate = 0; - } - - static void recStep() - { - } - - static void recExecuteBlock() - { - if((VU0.VI[REG_VPU_STAT].UL & 1) == 0) - return; - - FreezeXMMRegs(1); - SuperVUExecuteProgram(VU0.VI[ REG_TPC ].UL & 0xfff, 0); - FreezeXMMRegs(0); - } -} - -using namespace VU0micro; - -const VUmicroCpu recVU0 = -{ - recReset -, recStep -, recExecuteBlock -, recClear -}; +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "VUmicro.h" +#include "iVUzerorec.h" + +namespace VU0micro +{ + void recAlloc() + { + SuperVUAlloc(0); + } + + void __fastcall recClear(u32 Addr, u32 Size) + { + SuperVUClear(Addr, Size, 0); // Size should be a multiple of 8 bytes! + } + + void recShutdown() + { + SuperVUDestroy( 0 ); + } + + static void recReset() + { + SuperVUReset(0); + + // these shouldn't be needed, but shouldn't hurt anything either. + x86FpuState = FPU_STATE; + iCWstate = 0; + } + + static void recStep() + { + } + + static void recExecuteBlock() + { + if((VU0.VI[REG_VPU_STAT].UL & 1) == 0) + return; + + FreezeXMMRegs(1); + SuperVUExecuteProgram(VU0.VI[ REG_TPC ].UL & 0xfff, 0); + FreezeXMMRegs(0); + } +} + +using namespace VU0micro; + +const VUmicroCpu recVU0 = +{ + recReset +, recStep +, recExecuteBlock +, recClear +}; diff --git a/pcsx2/x86/iVU1micro.cpp b/pcsx2/x86/iVU1micro.cpp index 13768673d7..cfd1efc8af 100644 --- a/pcsx2/x86/iVU1micro.cpp +++ b/pcsx2/x86/iVU1micro.cpp @@ -1,135 +1,135 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include - -#include "Common.h" -#include "R5900OpcodeTables.h" -#include "ix86/ix86.h" -#include "iR5900.h" -#include "VUmicro.h" -#include "iVUzerorec.h" - -#ifdef _DEBUG -extern u32 vudump; -#endif - -namespace VU1micro -{ - void recAlloc() - { - SuperVUAlloc(1); - } - - void __fastcall recClear( u32 Addr, u32 Size ) - { - assert( (Addr&7) == 0 ); - SuperVUClear(Addr, Size, 1); // Size should be a multiple of 8 bytes! - } - - void recShutdown() - { - SuperVUDestroy( 1 ); - } - - // commented out because I'm not sure it actually works anymore with SuperVU (air) - /*static void iVU1DumpBlock() - { - FILE *f; - char filename[ g_MaxPath ]; - u32 *mem; - u32 i; - - #ifdef _WIN32 - CreateDirectory("dumps", NULL); - sprintf_s( filename, g_MaxPath, "dumps\\vu%.4X.txt", VU1.VI[ REG_TPC ].UL ); - #else - mkdir("dumps", 0755); - sprintf( filename, "dumps/vu%.4X.txt", VU1.VI[ REG_TPC ].UL ); - #endif - SysPrintf( "dump1 %x => %x (%s)\n", VU1.VI[ REG_TPC ].UL, pc, filename ); - - f = fopen( filename, "wb" ); - for ( i = VU1.VI[REG_TPC].UL; i < pc; i += 8 ) { - char* pstr; - mem = (u32*)&VU1.Micro[i]; - - pstr = disVU1MicroUF( mem[1], i+4 ); - fprintf(f, "%x: %-40s ", i, pstr); - - pstr = disVU1MicroLF( mem[0], i ); - fprintf(f, "%s\n", pstr); - } - fclose( f ); - }*/ - - static void recReset() - { - SuperVUReset(1); - - // these shouldn't be needed, but shouldn't hurt anything either. - x86FpuState = FPU_STATE; - iCWstate = 0; - } - - static void recStep() - { - } - - static void recExecuteBlock(void) - { - #ifdef _DEBUG - static u32 vuprogcount = 0; - vuprogcount++; - if( vudump & 8 ) __Log("start vu1: %x %x\n", VU1.VI[ REG_TPC ].UL, vuprogcount); - #endif - - if((VU0.VI[REG_VPU_STAT].UL & 0x100) == 0){ - //SysPrintf("Execute block VU1, VU1 not busy\n"); - return; - } - - if (VU1.VI[REG_TPC].UL >= VU1.maxmicro) - { - Console::Error("VU1 memory overflow!!: %x", params VU1.VI[REG_TPC].UL); - /*VU0.VI[REG_VPU_STAT].UL&= ~0x100; - VU1.cycle++; - return;*/ - } - - assert( (VU1.VI[ REG_TPC ].UL&7) == 0 ); - - FreezeXMMRegs(1); - do { // while loop needed since not always will return finished - SuperVUExecuteProgram(VU1.VI[ REG_TPC ].UL & 0x3fff, 1); - } while( VU0.VI[ REG_VPU_STAT ].UL&0x100 ); - FreezeXMMRegs(0); - } -} - -using namespace VU1micro; - -const VUmicroCpu recVU1 = -{ - recReset -, recStep -, recExecuteBlock -, recClear -}; +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include + +#include "Common.h" +#include "R5900OpcodeTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "VUmicro.h" +#include "iVUzerorec.h" + +#ifdef _DEBUG +extern u32 vudump; +#endif + +namespace VU1micro +{ + void recAlloc() + { + SuperVUAlloc(1); + } + + void __fastcall recClear( u32 Addr, u32 Size ) + { + assert( (Addr&7) == 0 ); + SuperVUClear(Addr, Size, 1); // Size should be a multiple of 8 bytes! + } + + void recShutdown() + { + SuperVUDestroy( 1 ); + } + + // commented out because I'm not sure it actually works anymore with SuperVU (air) + /*static void iVU1DumpBlock() + { + FILE *f; + char filename[ g_MaxPath ]; + u32 *mem; + u32 i; + + #ifdef _WIN32 + CreateDirectory("dumps", NULL); + sprintf_s( filename, g_MaxPath, "dumps\\vu%.4X.txt", VU1.VI[ REG_TPC ].UL ); + #else + mkdir("dumps", 0755); + sprintf( filename, "dumps/vu%.4X.txt", VU1.VI[ REG_TPC ].UL ); + #endif + SysPrintf( "dump1 %x => %x (%s)\n", VU1.VI[ REG_TPC ].UL, pc, filename ); + + f = fopen( filename, "wb" ); + for ( i = VU1.VI[REG_TPC].UL; i < pc; i += 8 ) { + char* pstr; + mem = (u32*)&VU1.Micro[i]; + + pstr = disVU1MicroUF( mem[1], i+4 ); + fprintf(f, "%x: %-40s ", i, pstr); + + pstr = disVU1MicroLF( mem[0], i ); + fprintf(f, "%s\n", pstr); + } + fclose( f ); + }*/ + + static void recReset() + { + SuperVUReset(1); + + // these shouldn't be needed, but shouldn't hurt anything either. + x86FpuState = FPU_STATE; + iCWstate = 0; + } + + static void recStep() + { + } + + static void recExecuteBlock(void) + { + #ifdef _DEBUG + static u32 vuprogcount = 0; + vuprogcount++; + if( vudump & 8 ) __Log("start vu1: %x %x\n", VU1.VI[ REG_TPC ].UL, vuprogcount); + #endif + + if((VU0.VI[REG_VPU_STAT].UL & 0x100) == 0){ + //SysPrintf("Execute block VU1, VU1 not busy\n"); + return; + } + + if (VU1.VI[REG_TPC].UL >= VU1.maxmicro) + { + Console::Error("VU1 memory overflow!!: %x", params VU1.VI[REG_TPC].UL); + /*VU0.VI[REG_VPU_STAT].UL&= ~0x100; + VU1.cycle++; + return;*/ + } + + assert( (VU1.VI[ REG_TPC ].UL&7) == 0 ); + + FreezeXMMRegs(1); + do { // while loop needed since not always will return finished + SuperVUExecuteProgram(VU1.VI[ REG_TPC ].UL & 0x3fff, 1); + } while( VU0.VI[ REG_VPU_STAT ].UL&0x100 ); + FreezeXMMRegs(0); + } +} + +using namespace VU1micro; + +const VUmicroCpu recVU1 = +{ + recReset +, recStep +, recExecuteBlock +, recClear +}; diff --git a/pcsx2/x86/iVUmicro.cpp b/pcsx2/x86/iVUmicro.cpp index 749c5e9d32..f586931cda 100644 --- a/pcsx2/x86/iVUmicro.cpp +++ b/pcsx2/x86/iVUmicro.cpp @@ -1,1713 +1,1713 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "PrecompiledHeader.h" - -#include "Common.h" -#include "GS.h" -#include "R5900OpcodeTables.h" -#include "ix86/ix86.h" -#include "iR5900.h" -#include "iMMI.h" -#include "iFPU.h" -#include "iCOP0.h" -#include "VUmicro.h" -#include "VUflags.h" -#include "iVUmicro.h" -#include "iVUops.h" -#include "iVUzerorec.h" - -#ifdef _WIN32 -#pragma warning(disable:4244) -#pragma warning(disable:4761) -#endif -//------------------------------------------------------------------ - -// fixme - VUmicro should really use its own static vars for pc and branch. -// Sharing with the EE's copies of pc and branch is not cool! (air) - -//------------------------------------------------------------------ -// Helper Macros -//------------------------------------------------------------------ -#define _Ft_ (( VU->code >> 16) & 0x1F) // The rt part of the instruction register -#define _Fs_ (( VU->code >> 11) & 0x1F) // The rd part of the instruction register -#define _Fd_ (( VU->code >> 6) & 0x1F) // The sa part of the instruction register - -#define _X (( VU->code>>24) & 0x1) -#define _Y (( VU->code>>23) & 0x1) -#define _Z (( VU->code>>22) & 0x1) -#define _W (( VU->code>>21) & 0x1) - -#define _XYZW_SS (_X+_Y+_Z+_W==1) - -#define _Fsf_ (( VU->code >> 21) & 0x03) -#define _Ftf_ (( VU->code >> 23) & 0x03) - -#define _Imm11_ (s32)(VU->code & 0x400 ? 0xfffffc00 | (VU->code & 0x3ff) : VU->code & 0x3ff) -#define _UImm11_ (s32)(VU->code & 0x7ff) - -#define VU_VFx_ADDR(x) (uptr)&VU->VF[x].UL[0] -#define VU_VFy_ADDR(x) (uptr)&VU->VF[x].UL[1] -#define VU_VFz_ADDR(x) (uptr)&VU->VF[x].UL[2] -#define VU_VFw_ADDR(x) (uptr)&VU->VF[x].UL[3] - -#define VU_REGR_ADDR (uptr)&VU->VI[REG_R] -#define VU_REGQ_ADDR (uptr)&VU->VI[REG_Q] -#define VU_REGMAC_ADDR (uptr)&VU->VI[REG_MAC_FLAG] - -#define VU_VI_ADDR(x, read) GetVIAddr(VU, x, read, info) - -#define VU_ACCx_ADDR (uptr)&VU->ACC.UL[0] -#define VU_ACCy_ADDR (uptr)&VU->ACC.UL[1] -#define VU_ACCz_ADDR (uptr)&VU->ACC.UL[2] -#define VU_ACCw_ADDR (uptr)&VU->ACC.UL[3] - -#define _X_Y_Z_W ((( VU->code >> 21 ) & 0xF ) ) -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// Global Variables -//------------------------------------------------------------------ -int g_VuNanHandling = 0; -int vucycle; - -PCSX2_ALIGNED16(float s_fones[8]) = {1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f}; -PCSX2_ALIGNED16(u32 s_mask[4]) = {0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff}; -PCSX2_ALIGNED16(u32 s_expmask[4]) = {0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000}; -PCSX2_ALIGNED16(u32 g_minvals[4]) = {0xff7fffff, 0xff7fffff, 0xff7fffff, 0xff7fffff}; -PCSX2_ALIGNED16(u32 g_maxvals[4]) = {0x7f7fffff, 0x7f7fffff, 0x7f7fffff, 0x7f7fffff}; -PCSX2_ALIGNED16(u32 const_clip[8]) = {0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, - 0x80000000, 0x80000000, 0x80000000, 0x80000000}; -PCSX2_ALIGNED(64, u32 g_ones[4]) = {0x00000001, 0x00000001, 0x00000001, 0x00000001}; -PCSX2_ALIGNED16(u32 g_minvals_XYZW[16][4]) = -{ - { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }, //0000 - { 0xffffffff, 0xffffffff, 0xffffffff, 0xff7fffff }, //0001 - { 0xffffffff, 0xffffffff, 0xff7fffff, 0xffffffff }, //0010 - { 0xffffffff, 0xffffffff, 0xff7fffff, 0xff7fffff }, //0011 - { 0xffffffff, 0xff7fffff, 0xffffffff, 0xffffffff }, //0100 - { 0xffffffff, 0xff7fffff, 0xffffffff, 0xff7fffff }, //0101 - { 0xffffffff, 0xff7fffff, 0xff7fffff, 0xffffffff }, //0110 - { 0xffffffff, 0xff7fffff, 0xff7fffff, 0xff7fffff }, //0111 - { 0xff7fffff, 0xffffffff, 0xffffffff, 0xffffffff }, //1000 - { 0xff7fffff, 0xffffffff, 0xffffffff, 0xff7fffff }, //1001 - { 0xff7fffff, 0xffffffff, 0xff7fffff, 0xffffffff }, //1010 - { 0xff7fffff, 0xffffffff, 0xff7fffff, 0xff7fffff }, //1011 - { 0xff7fffff, 0xff7fffff, 0xffffffff, 0xffffffff }, //1100 - { 0xff7fffff, 0xff7fffff, 0xffffffff, 0xff7fffff }, //1101 - { 0xff7fffff, 0xff7fffff, 0xff7fffff, 0xffffffff }, //1110 - { 0xff7fffff, 0xff7fffff, 0xff7fffff, 0xff7fffff }, //1111 -}; -PCSX2_ALIGNED16(u32 g_maxvals_XYZW[16][4])= -{ - { 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff }, //0000 - { 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7f7fffff }, //0001 - { 0x7fffffff, 0x7fffffff, 0x7f7fffff, 0x7fffffff }, //0010 - { 0x7fffffff, 0x7fffffff, 0x7f7fffff, 0x7f7fffff }, //0011 - { 0x7fffffff, 0x7f7fffff, 0x7fffffff, 0x7fffffff }, //0100 - { 0x7fffffff, 0x7f7fffff, 0x7fffffff, 0x7f7fffff }, //0101 - { 0x7fffffff, 0x7f7fffff, 0x7f7fffff, 0x7fffffff }, //0110 - { 0x7fffffff, 0x7f7fffff, 0x7f7fffff, 0x7f7fffff }, //0111 - { 0x7f7fffff, 0x7fffffff, 0x7fffffff, 0x7fffffff }, //1000 - { 0x7f7fffff, 0x7fffffff, 0x7fffffff, 0x7f7fffff }, //1001 - { 0x7f7fffff, 0x7fffffff, 0x7f7fffff, 0x7fffffff }, //1010 - { 0x7f7fffff, 0x7fffffff, 0x7f7fffff, 0x7f7fffff }, //1011 - { 0x7f7fffff, 0x7f7fffff, 0x7fffffff, 0x7fffffff }, //1100 - { 0x7f7fffff, 0x7f7fffff, 0x7fffffff, 0x7f7fffff }, //1101 - { 0x7f7fffff, 0x7f7fffff, 0x7f7fffff, 0x7fffffff }, //1110 - { 0x7f7fffff, 0x7f7fffff, 0x7f7fffff, 0x7f7fffff }, //1111 -}; -//------------------------------------------------------------------ - -//------------------------------------------------------------------ -// VU Pipeline/Test Stalls/Analyzing Functions -//------------------------------------------------------------------ -void _recvuFMACflush(VURegs * VU) { - int i; - - for (i=0; i<8; i++) { - if (VU->fmac[i].enable == 0) continue; - - if ((vucycle - VU->fmac[i].sCycle) >= VU->fmac[i].Cycle) { -// VUM_LOG("flushing FMAC pipe[%d]\n", i); - VU->fmac[i].enable = 0; - } - } -} - -void _recvuFDIVflush(VURegs * VU) { - if (VU->fdiv.enable == 0) return; - - if ((vucycle - VU->fdiv.sCycle) >= VU->fdiv.Cycle) { -// SysPrintf("flushing FDIV pipe\n"); - VU->fdiv.enable = 0; - } -} - -void _recvuEFUflush(VURegs * VU) { - if (VU->efu.enable == 0) return; - - if ((vucycle - VU->efu.sCycle) >= VU->efu.Cycle) { -// SysPrintf("flushing FDIV pipe\n"); - VU->efu.enable = 0; - } -} - -void _recvuTestPipes(VURegs * VU) { - _recvuFMACflush(VU); - _recvuFDIVflush(VU); - _recvuEFUflush(VU); -} - -void _recvuFMACTestStall(VURegs * VU, int reg, int xyzw) { - int cycle; - int i; - u32 mask = 0; - - for (i=0; i<8; i++) { - if (VU->fmac[i].enable == 0) continue; - if (VU->fmac[i].reg == reg && (VU->fmac[i].xyzw & xyzw)) break; - } - - if (i == 8) return; - - // do a perchannel delay - // old code -// cycle = VU->fmac[i].Cycle - (vucycle - VU->fmac[i].sCycle); - - // new code - mask = 4; // w -// if( VU->fmac[i].xyzw & 1 ) mask = 4; // w -// else if( VU->fmac[i].xyzw & 2 ) mask = 3; // z -// else if( VU->fmac[i].xyzw & 4 ) mask = 2; // y -// else { -// assert(VU->fmac[i].xyzw & 8 ); -// mask = 1; // x -// } - -// mask = 0; -// if( VU->fmac[i].xyzw & 1 ) mask++; // w -// else if( VU->fmac[i].xyzw & 2 ) mask++; // z -// else if( VU->fmac[i].xyzw & 4 ) mask++; // y -// else if( VU->fmac[i].xyzw & 8 ) mask++; // x - - assert( (int)VU->fmac[i].sCycle < (int)vucycle ); - cycle = 0; - if( vucycle - VU->fmac[i].sCycle < mask ) - cycle = mask - (vucycle - VU->fmac[i].sCycle); - - VU->fmac[i].enable = 0; - vucycle+= cycle; - _recvuTestPipes(VU); -} - -void _recvuFMACAdd(VURegs * VU, int reg, int xyzw) { - int i; - - /* find a free fmac pipe */ - for (i=0; i<8; i++) { - if (VU->fmac[i].enable == 1) continue; - break; - } - - if (i==8) SysPrintf("*PCSX2*: error , out of fmacs\n"); -// VUM_LOG("adding FMAC pipe[%d]; reg %d\n", i, reg); - - VU->fmac[i].enable = 1; - VU->fmac[i].sCycle = vucycle; - VU->fmac[i].Cycle = 3; - VU->fmac[i].xyzw = xyzw; - VU->fmac[i].reg = reg; -} - -void _recvuFDIVAdd(VURegs * VU, int cycles) { -// SysPrintf("adding FDIV pipe\n"); - VU->fdiv.enable = 1; - VU->fdiv.sCycle = vucycle; - VU->fdiv.Cycle = cycles; -} - -void _recvuEFUAdd(VURegs * VU, int cycles) { -// SysPrintf("adding EFU pipe\n"); - VU->efu.enable = 1; - VU->efu.sCycle = vucycle; - VU->efu.Cycle = cycles; -} - -void _recvuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn) { - - if( VUregsn->VFread0 && (VUregsn->VFread0 == VUregsn->VFread1) ) { - _recvuFMACTestStall(VU, VUregsn->VFread0, VUregsn->VFr0xyzw|VUregsn->VFr1xyzw); - } - else { - if (VUregsn->VFread0) _recvuFMACTestStall(VU, VUregsn->VFread0, VUregsn->VFr0xyzw); - if (VUregsn->VFread1) _recvuFMACTestStall(VU, VUregsn->VFread1, VUregsn->VFr1xyzw); - } -} - -void _recvuAddFMACStalls(VURegs * VU, _VURegsNum *VUregsn) { - - if (VUregsn->VFwrite) _recvuFMACAdd(VU, VUregsn->VFwrite, VUregsn->VFwxyzw); - else if (VUregsn->VIwrite & (1 << REG_CLIP_FLAG)) _recvuFMACAdd(VU, -REG_CLIP_FLAG, 0); // REG_CLIP_FLAG pipe - else _recvuFMACAdd(VU, 0, 0); -} - -void _recvuFlushFDIV(VURegs * VU) { - int cycle; - - if (VU->fdiv.enable == 0) return; - - cycle = VU->fdiv.Cycle - (vucycle - VU->fdiv.sCycle); -// SysPrintf("waiting FDIV pipe %d\n", cycle); - VU->fdiv.enable = 0; - vucycle+= cycle; -} - -void _recvuFlushEFU(VURegs * VU) { - int cycle; - - if (VU->efu.enable == 0) return; - - cycle = VU->efu.Cycle - (vucycle - VU->efu.sCycle); -// SysPrintf("waiting FDIV pipe %d\n", cycle); - VU->efu.enable = 0; - vucycle+= cycle; -} - -void _recvuTestFDIVStalls(VURegs * VU, _VURegsNum *VUregsn) { -// _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn); - _recvuFlushFDIV(VU); -} - -void _recvuTestEFUStalls(VURegs * VU, _VURegsNum *VUregsn) { -// _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn); - _recvuFlushEFU(VU); -} - -void _recvuAddFDIVStalls(VURegs * VU, _VURegsNum *VUregsn) { -// _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn); - if (VUregsn->VIwrite & (1 << REG_Q)) { - _recvuFDIVAdd(VU, VUregsn->cycles); - } -} - -void _recvuAddEFUStalls(VURegs * VU, _VURegsNum *VUregsn) { -// _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn); - if (VUregsn->VIwrite & (1 << REG_P)) { - _recvuEFUAdd(VU, VUregsn->cycles); - } -} - -void _recvuTestUpperStalls(VURegs * VU, _VURegsNum *VUregsn) { - switch (VUregsn->pipe) { - case VUPIPE_FMAC: _recvuTestFMACStalls(VU, VUregsn); break; - } -} - -void _recvuTestLowerStalls(VURegs * VU, _VURegsNum *VUregsn) { - switch (VUregsn->pipe) { - case VUPIPE_FMAC: _recvuTestFMACStalls(VU, VUregsn); break; - case VUPIPE_FDIV: _recvuTestFDIVStalls(VU, VUregsn); break; - case VUPIPE_EFU: _recvuTestEFUStalls(VU, VUregsn); break; - } -} - -void _recvuAddUpperStalls(VURegs * VU, _VURegsNum *VUregsn) { - switch (VUregsn->pipe) { - case VUPIPE_FMAC: _recvuAddFMACStalls(VU, VUregsn); break; - } -} - -void _recvuAddLowerStalls(VURegs * VU, _VURegsNum *VUregsn) { - switch (VUregsn->pipe) { - case VUPIPE_FMAC: _recvuAddFMACStalls(VU, VUregsn); break; - case VUPIPE_FDIV: _recvuAddFDIVStalls(VU, VUregsn); break; - case VUPIPE_EFU: _recvuAddEFUStalls(VU, VUregsn); break; - } -} - -void SuperVUAnalyzeOp(VURegs *VU, _vuopinfo *info, _VURegsNum* pCodeRegs) -{ - _VURegsNum* lregs; - _VURegsNum* uregs; - int *ptr; - - lregs = pCodeRegs; - uregs = pCodeRegs+1; - - ptr = (int*)&VU->Micro[pc]; - pc += 8; - - if (ptr[1] & 0x40000000) { // EOP - branch |= 8; - } - - VU->code = ptr[1]; - if (VU == &VU1) VU1regs_UPPER_OPCODE[VU->code & 0x3f](uregs); - else VU0regs_UPPER_OPCODE[VU->code & 0x3f](uregs); - - _recvuTestUpperStalls(VU, uregs); - switch(VU->code & 0x3f) { - case 0x10: case 0x11: case 0x12: case 0x13: - case 0x14: case 0x15: case 0x16: case 0x17: - case 0x1d: case 0x1f: - case 0x2b: case 0x2f: - break; - - case 0x3c: - switch ((VU->code >> 6) & 0x1f) { - case 0x4: case 0x5: - break; - default: - info->statusflag = 4; - info->macflag = 4; - break; - } - break; - case 0x3d: - switch ((VU->code >> 6) & 0x1f) { - case 0x4: case 0x5: case 0x7: - break; - default: - info->statusflag = 4; - info->macflag = 4; - break; - } - break; - case 0x3e: - switch ((VU->code >> 6) & 0x1f) { - case 0x4: case 0x5: - break; - default: - info->statusflag = 4; - info->macflag = 4; - break; - } - break; - case 0x3f: - switch ((VU->code >> 6) & 0x1f) { - case 0x4: case 0x5: case 0x7: case 0xb: - break; - default: - info->statusflag = 4; - info->macflag = 4; - break; - } - break; - - default: - info->statusflag = 4; - info->macflag = 4; - break; - } - - if (uregs->VIread & (1 << REG_Q)) { info->q |= 2; } - if (uregs->VIread & (1 << REG_P)) { info->p |= 2; assert( VU == &VU1 ); } - - // check upper flags - if (ptr[1] & 0x80000000) { // I flag - info->cycle = vucycle; - memzero_obj(*lregs); - } - else { - - VU->code = ptr[0]; - if (VU == &VU1) VU1regs_LOWER_OPCODE[VU->code >> 25](lregs); - else VU0regs_LOWER_OPCODE[VU->code >> 25](lregs); - - _recvuTestLowerStalls(VU, lregs); - info->cycle = vucycle; - - if (lregs->pipe == VUPIPE_BRANCH) { - branch |= 1; - } - - if (lregs->VIwrite & (1 << REG_Q)) { - info->q |= 4; - info->cycles = lregs->cycles; - info->pqinst = (VU->code&2)>>1; // rsqrt is 2 - } - else if (lregs->pipe == VUPIPE_FDIV) { - info->q |= 8|1; - info->pqinst = 0; - } - - if (lregs->VIwrite & (1 << REG_P)) { - assert( VU == &VU1 ); - info->p |= 4; - info->cycles = lregs->cycles; - - switch( VU->code & 0xff ) { - case 0xfd: info->pqinst = 0; break; //eatan - case 0x7c: info->pqinst = 0; break; //eatanxy - case 0x7d: info->pqinst = 0; break; //eatanzy - case 0xfe: info->pqinst = 1; break; //eexp - case 0xfc: info->pqinst = 2; break; //esin - case 0x3f: info->pqinst = 3; break; //erleng - case 0x3e: info->pqinst = 4; break; //eleng - case 0x3d: info->pqinst = 4; break; //ersadd - case 0xbd: info->pqinst = 4; break; //ersqrt - case 0xbe: info->pqinst = 5; break; //ercpr - case 0xbc: info->pqinst = 5; break; //esqrt - case 0x7e: info->pqinst = 5; break; //esum - case 0x3c: info->pqinst = 6; break; //esadd - default: assert(0); - } - } - else if (lregs->pipe == VUPIPE_EFU) { - info->p |= 8|1; - } - - if (lregs->VIread & (1 << REG_STATUS_FLAG)) info->statusflag|= VUOP_READ; - if (lregs->VIread & (1 << REG_MAC_FLAG)) info->macflag|= VUOP_READ; - - if (lregs->VIwrite & (1 << REG_STATUS_FLAG)) info->statusflag|= VUOP_WRITE; - if (lregs->VIwrite & (1 << REG_MAC_FLAG)) info->macflag|= VUOP_WRITE; - - if (lregs->VIread & (1 << REG_Q)) { info->q |= 2; } - if (lregs->VIread & (1 << REG_P)) { info->p |= 2; assert( VU == &VU1 ); } - - _recvuAddLowerStalls(VU, lregs); - } - - _recvuAddUpperStalls(VU, uregs); - _recvuTestPipes(VU); - - vucycle++; -} - -int eeVURecompileCode(VURegs *VU, _VURegsNum* regs) -{ - int info = 0; - int vfread0=-1, vfread1 = -1, vfwrite = -1, vfacc = -1, vftemp=-1; - - assert( regs != NULL ); - - if( regs->VFread0 ) _addNeededVFtoXMMreg(regs->VFread0); - if( regs->VFread1 ) _addNeededVFtoXMMreg(regs->VFread1); - if( regs->VFwrite ) _addNeededVFtoXMMreg(regs->VFwrite); - if( regs->VIread & (1<VIread & (1<VFread0 ) vfread0 = _allocVFtoXMMreg(VU, -1, regs->VFread0, MODE_READ); - else if( regs->VIread & (1<VFread1 ) vfread1 = _allocVFtoXMMreg(VU, -1, regs->VFread1, MODE_READ); - else if( (regs->VIread & (1<VFr1xyzw != 0xff) vfread1 = _allocVFtoXMMreg(VU, -1, 0, MODE_READ); - - if( regs->VIread & (1<VIwrite&(1<VIwrite & (1<VFwxyzw != 0xf?MODE_READ:0)); - } - - if( regs->VFwrite ) { - assert( !(regs->VIwrite&(1<VFwrite, MODE_WRITE|(regs->VFwxyzw != 0xf?MODE_READ:0)); - } - - if( vfacc>= 0 ) info |= PROCESS_EE_SET_ACC(vfacc); - if( vfwrite >= 0 ) { - if( regs->VFwrite == _Ft_ && vfread1 < 0 ) { - info |= PROCESS_EE_SET_T(vfwrite); - } - else { - assert( regs->VFwrite == _Fd_ ); - info |= PROCESS_EE_SET_D(vfwrite); - } - } - - if( vfread0 >= 0 ) info |= PROCESS_EE_SET_S(vfread0); - if( vfread1 >= 0 ) info |= PROCESS_EE_SET_T(vfread1); - - vftemp = _allocTempXMMreg(XMMT_FPS, -1); - info |= PROCESS_VU_SET_TEMP(vftemp); - - if( regs->VIwrite & (1 << REG_CLIP_FLAG) ) { - // CLIP inst, need two extra temp registers, put it EEREC_D and EEREC_ACC - int t1reg = _allocTempXMMreg(XMMT_FPS, -1); - int t2reg = _allocTempXMMreg(XMMT_FPS, -1); - - info |= PROCESS_EE_SET_D(t1reg); - info |= PROCESS_EE_SET_ACC(t2reg); - - _freeXMMreg(t1reg); // don't need - _freeXMMreg(t2reg); // don't need - } - else if( regs->VIwrite & (1<VI[reg].UL; - - if( read != 1 ) { - if( reg == REG_MAC_FLAG ) return (uptr)&VU->macflag; - if( reg == REG_CLIP_FLAG ) return (uptr)&VU->clipflag; - if( reg == REG_STATUS_FLAG ) return (uptr)&VU->statusflag; - if( reg == REG_Q ) return (uptr)&VU->q; - if( reg == REG_P ) return (uptr)&VU->p; - } - - return (uptr)&VU->VI[reg].UL; -} - -// gets a temp reg that is not EEREC_TEMP -int _vuGetTempXMMreg(int info) -{ - int t1reg = -1; - - if( _hasFreeXMMreg() ) { - t1reg = _allocTempXMMreg(XMMT_FPS, -1); - - if( t1reg == EEREC_TEMP ) { - if( _hasFreeXMMreg() ) { - int t = _allocTempXMMreg(XMMT_FPS, -1); - _freeXMMreg(t1reg); - t1reg = t; - } - else { - _freeXMMreg(t1reg); - t1reg = -1; - } - } - } - - return t1reg; -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// Misc VU Reg Flipping/Merging Functions -//------------------------------------------------------------------ -void _unpackVF_xyzw(int dstreg, int srcreg, int xyzw) -{ - switch (xyzw) { - case 0: SSE2_PSHUFD_XMM_to_XMM(dstreg, srcreg, 0x00); break; - case 1: SSE2_PSHUFD_XMM_to_XMM(dstreg, srcreg, 0x55); break; - case 2: SSE2_PSHUFD_XMM_to_XMM(dstreg, srcreg, 0xaa); break; - case 3: SSE2_PSHUFD_XMM_to_XMM(dstreg, srcreg, 0xff); break; - } -} - -void _unpackVFSS_xyzw(int dstreg, int srcreg, int xyzw) -{ - switch (xyzw) { - case 0: SSE_MOVSS_XMM_to_XMM(dstreg, srcreg); break; - case 1: if ( cpucaps.hasStreamingSIMD4Extensions ) SSE4_INSERTPS_XMM_to_XMM(dstreg, srcreg, _MM_MK_INSERTPS_NDX(1, 0, 0)); - else SSE2_PSHUFLW_XMM_to_XMM(dstreg, srcreg, 0xee); - break; - case 2: SSE_MOVHLPS_XMM_to_XMM(dstreg, srcreg); break; - case 3: if ( cpucaps.hasStreamingSIMD4Extensions ) SSE4_INSERTPS_XMM_to_XMM(dstreg, srcreg, _MM_MK_INSERTPS_NDX(3, 0, 0)); - else { SSE_MOVHLPS_XMM_to_XMM(dstreg, srcreg); SSE2_PSHUFLW_XMM_to_XMM(dstreg, dstreg, 0xee); } - break; - } -} - -void _vuFlipRegSS(VURegs * VU, int reg) -{ - assert( _XYZW_SS ); - if( _Y ) SSE2_PSHUFLW_XMM_to_XMM(reg, reg, 0x4e); - else if( _Z ) SSE_SHUFPS_XMM_to_XMM(reg, reg, 0xc6); - else if( _W ) SSE_SHUFPS_XMM_to_XMM(reg, reg, 0x27); -} - -void _vuFlipRegSS_xyzw(int reg, int xyzw) -{ - switch ( xyzw ) { - case 1: SSE2_PSHUFLW_XMM_to_XMM(reg, reg, 0x4e); break; - case 2: SSE_SHUFPS_XMM_to_XMM(reg, reg, 0xc6); break; - case 3: SSE_SHUFPS_XMM_to_XMM(reg, reg, 0x27); break; - } -} - -void _vuMoveSS(VURegs * VU, int dstreg, int srcreg) -{ - assert( _XYZW_SS ); - if( _Y ) _unpackVFSS_xyzw(dstreg, srcreg, 1); - else if( _Z ) _unpackVFSS_xyzw(dstreg, srcreg, 2); - else if( _W ) _unpackVFSS_xyzw(dstreg, srcreg, 3); - else _unpackVFSS_xyzw(dstreg, srcreg, 0); -} - -// 1 - src, 0 - dest wzyx -void VU_MERGE0(int dest, int src) { // 0000s -} -void VU_MERGE1(int dest, int src) { // 1000 - SSE_MOVHLPS_XMM_to_XMM(src, dest); - SSE_SHUFPS_XMM_to_XMM(dest, src, 0xc4); -} -void VU_MERGE1b(int dest, int src) { // 1000s - SSE_SHUFPS_XMM_to_XMM(src, src, 0x27); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x27); - SSE_MOVSS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, src, 0x27); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x27); -} -void VU_MERGE2(int dest, int src) { // 0100 - SSE_MOVHLPS_XMM_to_XMM(src, dest); - SSE_SHUFPS_XMM_to_XMM(dest, src, 0x64); -} -void VU_MERGE2b(int dest, int src) { // 0100s - SSE_SHUFPS_XMM_to_XMM(src, src, 0xC6); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xC6); - SSE_MOVSS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, src, 0xC6); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xC6); -} -void VU_MERGE3(int dest, int src) { // 1100s - SSE_SHUFPS_XMM_to_XMM(dest, src, 0xe4); -} -void VU_MERGE4(int dest, int src) { // 0010 - SSE_MOVSS_XMM_to_XMM(src, dest); - SSE2_MOVSD_XMM_to_XMM(dest, src); -} -void VU_MERGE4b(int dest, int src) { // 0010s - SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); - SSE_MOVSS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); -} -void VU_MERGE5(int dest, int src) { // 1010 - SSE_SHUFPS_XMM_to_XMM(dest, src, 0xd8); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xd8); -} -void VU_MERGE5b(int dest, int src) { // 1010s - SSE_SHUFPS_XMM_to_XMM(src, src, 0x27); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x27); - SSE_MOVSS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, src, 0x27); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x27); - SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); - SSE_MOVSS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); -} -void VU_MERGE6(int dest, int src) { // 0110 - SSE_SHUFPS_XMM_to_XMM(dest, src, 0x9c); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x78); -} -void VU_MERGE6b(int dest, int src) { // 0110s - SSE_SHUFPS_XMM_to_XMM(src, src, 0xC6); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xC6); - SSE_MOVSS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, src, 0xC6); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xC6); - SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); - SSE_MOVSS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); -} -void VU_MERGE7(int dest, int src) { // 1110 - SSE_MOVSS_XMM_to_XMM(src, dest); - SSE_MOVAPS_XMM_to_XMM(dest, src); -} -void VU_MERGE7b(int dest, int src) { // 1110s - SSE_SHUFPS_XMM_to_XMM(dest, src, 0xe4); - SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); - SSE_MOVSS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); -} -void VU_MERGE8(int dest, int src) { // 0001s - SSE_MOVSS_XMM_to_XMM(dest, src); -} -void VU_MERGE9(int dest, int src) { // 1001 - SSE_SHUFPS_XMM_to_XMM(dest, src, 0xc9); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xd2); -} -void VU_MERGE9b(int dest, int src) { // 1001s - SSE_MOVSS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, src, 0x27); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x27); - SSE_MOVSS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, src, 0x27); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x27); -} -void VU_MERGE10(int dest, int src) { // 0101 - SSE_SHUFPS_XMM_to_XMM(dest, src, 0x8d); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x72); -} -void VU_MERGE10b(int dest, int src) { // 0101s - SSE_MOVSS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, src, 0xC6); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xC6); - SSE_MOVSS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, src, 0xC6); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xC6); -} -void VU_MERGE11(int dest, int src) { // 1101s - SSE_MOVSS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(dest, src, 0xe4); -} -void VU_MERGE12(int dest, int src) { // 0011 - SSE2_MOVSD_XMM_to_XMM(dest, src); -} -void VU_MERGE13(int dest, int src) { // 1011 - SSE_MOVHLPS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, dest, 0x64); - SSE_MOVAPS_XMM_to_XMM(dest, src); -} -void VU_MERGE13b(int dest, int src) { // 1011s - SSE_MOVSS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, src, 0x27); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x27); - SSE_MOVSS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, src, 0x27); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x27); - SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); - SSE_MOVSS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); -} -void VU_MERGE14(int dest, int src) { // 0111 - SSE_MOVHLPS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, dest, 0xc4); - SSE_MOVAPS_XMM_to_XMM(dest, src); -} -void VU_MERGE14b(int dest, int src) { // 0111s - SSE_MOVSS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); - SSE_MOVSS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); - SSE_SHUFPS_XMM_to_XMM(src, src, 0xC6); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xC6); - SSE_MOVSS_XMM_to_XMM(dest, src); - SSE_SHUFPS_XMM_to_XMM(src, src, 0xC6); - SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xC6); -} -void VU_MERGE15(int dest, int src) { // 1111s - SSE_MOVAPS_XMM_to_XMM(dest, src); -} - -typedef void (*VUMERGEFN)(int dest, int src); - -static VUMERGEFN s_VuMerge[16] = { - VU_MERGE0, VU_MERGE1, VU_MERGE2, VU_MERGE3, - VU_MERGE4, VU_MERGE5, VU_MERGE6, VU_MERGE7, - VU_MERGE8, VU_MERGE9, VU_MERGE10, VU_MERGE11, - VU_MERGE12, VU_MERGE13, VU_MERGE14, VU_MERGE15 }; - -static VUMERGEFN s_VuMerge2[16] = { - VU_MERGE0, VU_MERGE1b, VU_MERGE2b, VU_MERGE3, - VU_MERGE4b, VU_MERGE5b, VU_MERGE6b, VU_MERGE7b, - VU_MERGE8, VU_MERGE9b, VU_MERGE10b, VU_MERGE11, - VU_MERGE12, VU_MERGE13b, VU_MERGE14b, VU_MERGE15 }; - -// Modifies the Source Reg! -void VU_MERGE_REGS_CUSTOM(int dest, int src, int xyzw) { - xyzw &= 0xf; - if ( (dest != src) && (xyzw != 0) ) { - if ( cpucaps.hasStreamingSIMD4Extensions && (xyzw != 0x8) && (xyzw != 0xf) ) { - xyzw = ((xyzw & 1) << 3) | ((xyzw & 2) << 1) | ((xyzw & 4) >> 1) | ((xyzw & 8) >> 3); - SSE4_BLENDPS_XMM_to_XMM(dest, src, xyzw); - } - else s_VuMerge[xyzw](dest, src); - } -} -// Doesn't Modify the Source Reg! (ToDo: s_VuMerge2() has room for optimization) -void VU_MERGE_REGS_SAFE(int dest, int src, int xyzw) { - xyzw &= 0xf; - if ( (dest != src) && (xyzw != 0) ) { - if ( cpucaps.hasStreamingSIMD4Extensions && (xyzw != 0x8) && (xyzw != 0xf) ) { - xyzw = ((xyzw & 1) << 3) | ((xyzw & 2) << 1) | ((xyzw & 4) >> 1) | ((xyzw & 8) >> 3); - SSE4_BLENDPS_XMM_to_XMM(dest, src, xyzw); - } - else s_VuMerge2[xyzw](dest, src); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// Misc VU Reg Clamping/Overflow Functions -//------------------------------------------------------------------ -#define CLAMP_NORMAL_SSE4(n) \ - SSE_MOVAPS_XMM_to_XMM(regTemp, regd);\ - SSE4_PMINUD_M128_to_XMM(regd, (uptr)&g_minvals_XYZW[n][0]);\ - SSE2_PSUBD_XMM_to_XMM(regTemp, regd);\ - SSE2_PCMPGTD_M128_to_XMM(regTemp, (uptr)&g_ones[0]);\ - SSE4_PMINSD_M128_to_XMM(regd, (uptr)&g_maxvals_XYZW[n][0]);\ - SSE2_PSLLD_I8_to_XMM(regTemp, 31);\ - SSE_XORPS_XMM_to_XMM(regd, regTemp); - -#define CLAMP_SIGN_SSE4(n) \ - SSE4_PMINSD_M128_to_XMM(regd, (uptr)&g_maxvals_XYZW[n][0]);\ - SSE4_PMINUD_M128_to_XMM(regd, (uptr)&g_minvals_XYZW[n][0]); - -void vFloat0(int regd, int regTemp) { } //0000 -void vFloat1(int regd, int regTemp) { //1000 - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); -} -void vFloat1b(int regd, int regTemp) { //1000 //regTemp is Modified - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_NORMAL_SSE4(1); - } - else { - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - } -} -void vFloat1c(int regd, int regTemp) { //1000 - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_SIGN_SSE4(1); - } - else { - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_ORPS_XMM_to_XMM(regd, regTemp); - } -} -void vFloat2(int regd, int regTemp) { //0100 - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); -} -void vFloat2b(int regd, int regTemp) { //0100 //regTemp is Modified - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_NORMAL_SSE4(2); - } - else { - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - } -} -void vFloat2c(int regd, int regTemp) { //0100 - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_SIGN_SSE4(2); - } - else { - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE_ORPS_XMM_to_XMM(regd, regTemp); - } -} -void vFloat3(int regd, int regTemp) { //1100 - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x36); -} -void vFloat3b(int regd, int regTemp) { //1100 //regTemp is Modified - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_NORMAL_SSE4(3); - } - else { - SSE2_MOVSD_XMM_to_XMM(regTemp, regd); - SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); - SSE2_MOVSD_XMM_to_XMM(regd, regTemp); - } -} -void vFloat3c(int regd, int regTemp) { //1100 - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_SIGN_SSE4(3); - } - else { - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x36); - SSE_ORPS_XMM_to_XMM(regd, regTemp); - } -} -void vFloat4(int regd, int regTemp) { //0010 - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); -} -void vFloat4b(int regd, int regTemp) { //0010 //regTemp is Modified - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_NORMAL_SSE4(4); - } - else { - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - } -} -void vFloat4c(int regd, int regTemp) { //0010 - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_SIGN_SSE4(4); - } - else { - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE_ORPS_XMM_to_XMM(regd, regTemp); - } -} -void vFloat5(int regd, int regTemp) { //1010 - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x2d); -} -void vFloat5b(int regd, int regTemp) { //1010 //regTemp is Modified - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_NORMAL_SSE4(5); - } - else { - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x2d); - } -} -void vFloat5c(int regd, int regTemp) { //1010 - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_SIGN_SSE4(5); - } - else { - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x2d); - SSE_ORPS_XMM_to_XMM(regd, regTemp); - } -} -void vFloat6(int regd, int regTemp) { //0110 - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc9); -} -void vFloat6b(int regd, int regTemp) { //0110 //regTemp is Modified - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_NORMAL_SSE4(6); - } - else { - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc9); - } -} -void vFloat6c(int regd, int regTemp) { //0110 - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_SIGN_SSE4(6); - } - else { - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc9); - SSE_ORPS_XMM_to_XMM(regd, regTemp); - } -} -void vFloat7(int regd, int regTemp) { //1110 - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x39); -} -void vFloat7_useEAX(int regd, int regTemp) { //1110 //EAX is Modified - SSE2_MOVD_XMM_to_R(EAX, regd); - SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); - if ( cpucaps.hasStreamingSIMD4Extensions ) - SSE4_PINSRD_R32_to_XMM(regd, EAX, 0x00); - else { - SSE_PINSRW_R32_to_XMM(regd, EAX, 0); - SHR32ItoR(EAX, 16); - SSE_PINSRW_R32_to_XMM(regd, EAX, 1); - } -} -void vFloat7b(int regd, int regTemp) { //1110 //regTemp is Modified - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_NORMAL_SSE4(7); - } - else { - SSE_MOVSS_XMM_to_XMM(regTemp, regd); - SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); - SSE_MOVSS_XMM_to_XMM(regd, regTemp); - } -} -void vFloat7c(int regd, int regTemp) { //1110 - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_SIGN_SSE4(7); - } - else { - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x39); - SSE_ORPS_XMM_to_XMM(regd, regTemp); - } -} -void vFloat7c_useEAX(int regd, int regTemp) { //1110 //EAX is Modified - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_SIGN_SSE4(7); - } - else { - SSE2_MOVD_XMM_to_R(EAX, regd); - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); - SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); - SSE_ORPS_XMM_to_XMM(regd, regTemp); - SSE2_MOVD_R_to_XMM(regTemp, EAX); - SSE_MOVSS_XMM_to_XMM(regd, regTemp); - } -} -void vFloat8(int regd, int regTemp) { //0001 - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); -} -void vFloat8b(int regd, int regTemp) { //0001 //regTemp is Modified - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_NORMAL_SSE4(8); - } - else { - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - } -} -void vFloat8c(int regd, int regTemp) { //0001 - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_SIGN_SSE4(8); - } - else { - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_ORPS_XMM_to_XMM(regd, regTemp); - } -} -void vFloat9(int regd, int regTemp) { //1001 - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); -} -void vFloat9b(int regd, int regTemp) { //1001 //regTemp is Modified - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_NORMAL_SSE4(9); - } - else { - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - } -} -void vFloat9c(int regd, int regTemp) { //1001 - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_SIGN_SSE4(9); - } - else { - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_ORPS_XMM_to_XMM(regd, regTemp); - } -} -void vFloat10(int regd, int regTemp) { //0101 - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); -} -void vFloat10b(int regd, int regTemp) { //0101 //regTemp is Modified - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_NORMAL_SSE4(10); - } - else { - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - } -} -void vFloat10c(int regd, int regTemp) { //0101 - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_SIGN_SSE4(10); - } - else { - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE_ORPS_XMM_to_XMM(regd, regTemp); - } -} -void vFloat11(int regd, int regTemp) { //1101 - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x36); -} -void vFloat11_useEAX(int regd, int regTemp) { //1101 //EAX is Modified - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE2_MOVD_XMM_to_R(EAX, regd); - SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); - if ( cpucaps.hasStreamingSIMD4Extensions ) - SSE4_PINSRD_R32_to_XMM(regd, EAX, 0x00); - else { - SSE_PINSRW_R32_to_XMM(regd, EAX, 0); - SHR32ItoR(EAX, 16); - SSE_PINSRW_R32_to_XMM(regd, EAX, 1); - } - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); -} -void vFloat11b(int regd, int regTemp) { //1101 //regTemp is Modified - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_NORMAL_SSE4(11); - } - else { - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); - SSE_MOVSS_XMM_to_XMM(regTemp, regd); - SSE2_MOVSD_XMM_to_XMM(regd, regTemp); - } -} -void vFloat11c(int regd, int regTemp) { //1101 - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_SIGN_SSE4(11); - } - else { - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x36); - SSE_ORPS_XMM_to_XMM(regd, regTemp); - } -} -void vFloat11c_useEAX(int regd, int regTemp) { //1101 // EAX is modified - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_SIGN_SSE4(11); - } - else { - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE2_MOVD_XMM_to_R(EAX, regTemp); - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); - SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); - SSE_ORPS_XMM_to_XMM(regTemp, regd); - SSE2_MOVD_R_to_XMM(regd, EAX); - SSE_MOVLHPS_XMM_to_XMM(regd, regTemp); - SSE_SHUFPS_XMM_to_XMM(regd, regTemp, 0xe2); - } -} -void vFloat12(int regd, int regTemp) { //0011 - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); -} -void vFloat12b(int regd, int regTemp) { //0011 //regTemp is Modified - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_NORMAL_SSE4(12); - } - else { - SSE_MOVHLPS_XMM_to_XMM(regTemp, regd); - SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); - SSE2_PUNPCKLQDQ_XMM_to_XMM(regd, regTemp); - } -} -void vFloat12c(int regd, int regTemp) { //0011 - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_SIGN_SSE4(12); - } - else { - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE_ORPS_XMM_to_XMM(regd, regTemp); - } -} -void vFloat13(int regd, int regTemp) { //1011 - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x2d); -} -void vFloat13_useEAX(int regd, int regTemp) { //1011 // EAX is modified - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE2_MOVD_XMM_to_R(EAX, regd); - SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); - if ( cpucaps.hasStreamingSIMD4Extensions ) - SSE4_PINSRD_R32_to_XMM(regd, EAX, 0x00); - else { - SSE_PINSRW_R32_to_XMM(regd, EAX, 0); - SHR32ItoR(EAX, 16); - SSE_PINSRW_R32_to_XMM(regd, EAX, 1); - } - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); -} -void vFloat13b(int regd, int regTemp) { //1011 //regTemp is Modified - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_NORMAL_SSE4(13); - } - else { - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); - SSE_MOVHLPS_XMM_to_XMM(regTemp, regd); - SSE_SHUFPS_XMM_to_XMM(regd, regTemp, 0x64); - } -} -void vFloat13c(int regd, int regTemp) { //1011 - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_SIGN_SSE4(13); - } - else { - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x2d); - SSE_ORPS_XMM_to_XMM(regd, regTemp); - } -} -void vFloat13c_useEAX(int regd, int regTemp) { //1011 // EAX is modified - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_SIGN_SSE4(13); - } - else { - SSE2_PSHUFD_XMM_to_XMM(regTemp, regd, 0xd2); - SSE2_MOVD_XMM_to_R(EAX, regTemp); - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); - SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); - SSE_ORPS_XMM_to_XMM(regd, regTemp); - SSE2_MOVD_R_to_XMM(regTemp, EAX); - SSE_SHUFPS_XMM_to_XMM(regTemp, regd, 0xf0); - SSE_SHUFPS_XMM_to_XMM(regd, regTemp, 0x84); - } -} -void vFloat14(int regd, int regTemp) { //0111 - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc9); -} -void vFloat14_useEAX(int regd, int regTemp) { //0111 // EAX is modified - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE2_MOVD_XMM_to_R(EAX, regd); - SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); - if ( cpucaps.hasStreamingSIMD4Extensions ) - SSE4_PINSRD_R32_to_XMM(regd, EAX, 0x00); - else { - SSE_PINSRW_R32_to_XMM(regd, EAX, 0); - SHR32ItoR(EAX, 16); - SSE_PINSRW_R32_to_XMM(regd, EAX, 1); - } - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); -} -void vFloat14b(int regd, int regTemp) { //0111 //regTemp is Modified - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_NORMAL_SSE4(14); - } - else { - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); - SSE_MOVHLPS_XMM_to_XMM(regTemp, regd); - SSE_SHUFPS_XMM_to_XMM(regd, regTemp, 0xc4); - } -} -void vFloat14c(int regd, int regTemp) { //0111 - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_SIGN_SSE4(14); - } - else { - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); - SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc9); - SSE_ORPS_XMM_to_XMM(regd, regTemp); - } -} -void vFloat14c_useEAX(int regd, int regTemp) { //0111 // EAX is modified - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_SIGN_SSE4(14); - } - else { - SSE2_PSHUFD_XMM_to_XMM(regTemp, regd, 0x93); - SSE2_MOVD_XMM_to_R(EAX, regTemp); - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); - SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); - SSE_ORPS_XMM_to_XMM(regd, regTemp); - SSE2_MOVD_R_to_XMM(regTemp, EAX); - SSE_SHUFPS_XMM_to_XMM(regTemp, regd, 0xa0); - SSE_SHUFPS_XMM_to_XMM(regd, regTemp, 0x24); - } -} -void vFloat15(int regd, int regTemp) { //1111 - SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); -} -void vFloat15b(int regd, int regTemp) { //1111 - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_NORMAL_SSE4(15); - } - else { - SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); - SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); - } -} -void vFloat15c(int regd, int regTemp) { //1111 - if ( cpucaps.hasStreamingSIMD4Extensions ) { - CLAMP_SIGN_SSE4(15); - } - else { - SSE_MOVAPS_XMM_to_XMM(regTemp, regd); - SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); - SSE_MINPS_M128_to_XMM(regd, (uptr)&g_maxvals[0]); - SSE_MAXPS_M128_to_XMM(regd, (uptr)&g_minvals[0]); - SSE_ORPS_XMM_to_XMM(regd, regTemp); - } -} - -vFloat vFloats1[16] = { //regTemp is not modified - vFloat0, vFloat1, vFloat2, vFloat3, - vFloat4, vFloat5, vFloat6, vFloat7, - vFloat8, vFloat9, vFloat10, vFloat11, - vFloat12, vFloat13, vFloat14, vFloat15 }; - -vFloat vFloats1_useEAX[16] = { //regTemp is not modified but EAX is used - vFloat0, vFloat1, vFloat2, vFloat3, - vFloat4, vFloat5, vFloat6, vFloat7_useEAX, - vFloat8, vFloat9, vFloat10, vFloat11_useEAX, - vFloat12, vFloat13_useEAX, vFloat14_useEAX, vFloat15 }; - -vFloat vFloats2[16] = { //regTemp is modified - vFloat0, vFloat1, vFloat2, vFloat3b, - vFloat4, vFloat5b, vFloat6b, vFloat7b, - vFloat8, vFloat9b, vFloat10b, vFloat11b, - vFloat12b, vFloat13b, vFloat14b, vFloat15 }; - -vFloat vFloats2_MUL_MADD[16] = { //regTemp is modified (Faster than vFloats2 if dealing with Denormals and using SSE4) - vFloat0, vFloat1b, vFloat2b, vFloat3b, - vFloat4b, vFloat5b, vFloat6b, vFloat7b, - vFloat8b, vFloat9b, vFloat10b, vFloat11b, - vFloat12b, vFloat13b, vFloat14b, vFloat15b }; - -vFloat vFloats4[16] = { //regTemp is modified - vFloat0, vFloat1c, vFloat2c, vFloat3c, - vFloat4c, vFloat5c, vFloat6c, vFloat7c, - vFloat8c, vFloat9c, vFloat10c, vFloat11c, - vFloat1c, vFloat13c, vFloat14c, vFloat15c }; - -vFloat vFloats4_useEAX[16] = { //regTemp is modified and EAX is used - vFloat0, vFloat1c, vFloat2c, vFloat3c, - vFloat4c, vFloat5c, vFloat6c, vFloat7c_useEAX, - vFloat8c, vFloat9c, vFloat10c, vFloat11c_useEAX, - vFloat1c, vFloat13c_useEAX, vFloat14c_useEAX, vFloat15c }; - -//------------------------------------------------------------------ -// Clamping Functions (wrapper for vFloat* functions) -// vuFloat : "normal" clamping -// vuFloat_useEAX : "normal" clamping (faster but EAX is modified) -// vuFloat2 : "normal" clamping (fastest but regTemp is modified) -// vuFloat3 : "preserve sign" clamping for pointer -// vuFloat4 : "preserve sign" clamping (regTemp is modified; *FASTEST* on SSE4 CPUs) -// vuFloat4_useEAX : "preserve sign" clamping (faster but regTemp and EAX are modified) -// vuFloat5 : wrapper function for vuFloat2 and vuFloat4 -// vuFloat5_useEAX : wrapper function for vuFloat2 and vuFloat4_useEAX -// vuFloatExtra : for debugging -// -// Notice 1: vuFloat*_useEAX may be slower on AMD CPUs, which have independent execution pipeline for -// vector and scalar instructions (need checks) -// Notice 2: recVUMI_MUL_xyzw_toD and recVUMI_MADD_xyzw_toD use vFloats directly! -//------------------------------------------------------------------ - -// Clamps +/-NaN to +fMax and +/-Inf to +/-fMax (doesn't use any temp regs) -void vuFloat( int info, int regd, int XYZW) { - if( CHECK_VU_OVERFLOW ) { - /*if ( (XYZW != 0) && (XYZW != 8) && (XYZW != 0xF) ) { - int t1reg = _vuGetTempXMMreg(info); - if (t1reg >= 0) { - vuFloat2( regd, t1reg, XYZW ); - _freeXMMreg( t1reg ); - return; - } - }*/ - //vuFloatExtra(regd, XYZW); - vFloats1[XYZW](regd, regd); - } -} - -// Clamps +/-NaN to +fMax and +/-Inf to +/-fMax (uses EAX as a temp register; faster but **destroys EAX**) -void vuFloat_useEAX( int info, int regd, int XYZW) { - if( CHECK_VU_OVERFLOW ) { - vFloats1_useEAX[XYZW](regd, regd); - } -} - -// Clamps +/-NaN to +fMax and +/-Inf to +/-fMax (uses a temp reg) -void vuFloat2(int regd, int regTemp, int XYZW) { - if( CHECK_VU_OVERFLOW ) { - //vuFloatExtra(regd, XYZW); - vFloats2[XYZW](regd, regTemp); - } -} - -// Clamps +/-NaN and +/-Inf to +/-fMax (uses a temp reg) -void vuFloat4(int regd, int regTemp, int XYZW) { - if( CHECK_VU_OVERFLOW ) { - vFloats4[XYZW](regd, regTemp); - } -} - -// Clamps +/-NaN and +/-Inf to +/-fMax (uses a temp reg, and uses EAX as a temp register; faster but **destroys EAX**) -void vuFloat4_useEAX(int regd, int regTemp, int XYZW) { - if( CHECK_VU_OVERFLOW ) { - vFloats4_useEAX[XYZW](regd, regTemp); - } -} - -// Uses vuFloat4 or vuFloat2 depending on the CHECK_VU_SIGN_OVERFLOW setting -void vuFloat5(int regd, int regTemp, int XYZW) { - if (CHECK_VU_SIGN_OVERFLOW) { - vuFloat4(regd, regTemp, XYZW); - } - else vuFloat2(regd, regTemp, XYZW); -} - -// Uses vuFloat4_useEAX or vuFloat2 depending on the CHECK_VU_SIGN_OVERFLOW setting (uses EAX as a temp register; faster but **destoroyes EAX**) -void vuFloat5_useEAX(int regd, int regTemp, int XYZW) { - if (CHECK_VU_SIGN_OVERFLOW) { - vuFloat4_useEAX(regd, regTemp, XYZW); - } - else vuFloat2(regd, regTemp, XYZW); -} - -// Clamps +/-infs to +/-fMax, and +/-NaNs to +/-fMax -void vuFloat3(uptr x86ptr) { - u8* pjmp; - - if( CHECK_VU_OVERFLOW ) { - CMP32ItoM(x86ptr, 0x7f800000 ); - pjmp = JL8(0); // Signed Comparison - MOV32ItoM(x86ptr, 0x7f7fffff ); - x86SetJ8(pjmp); - - CMP32ItoM(x86ptr, 0xff800000 ); - pjmp = JB8(0); // Unsigned Comparison - MOV32ItoM(x86ptr, 0xff7fffff ); - x86SetJ8(pjmp); - } -} - -PCSX2_ALIGNED16(u64 vuFloatData[2]); -PCSX2_ALIGNED16(u64 vuFloatData2[2]); -// Makes NaN == 0, Infinities stay the same; Very Slow - Use only for debugging -void vuFloatExtra( int regd, int XYZW) { - int t1reg = (regd == 0) ? (regd + 1) : (regd - 1); - int t2reg = (regd <= 1) ? (regd + 2) : (regd - 2); - SSE_MOVAPS_XMM_to_M128( (uptr)vuFloatData, t1reg ); - SSE_MOVAPS_XMM_to_M128( (uptr)vuFloatData2, t2reg ); - - SSE_XORPS_XMM_to_XMM(t1reg, t1reg); - SSE_CMPORDPS_XMM_to_XMM(t1reg, regd); - SSE_MOVAPS_XMM_to_XMM(t2reg, regd); - SSE_ANDPS_XMM_to_XMM(t2reg, t1reg); - VU_MERGE_REGS_CUSTOM(regd, t2reg, XYZW); - - SSE_MOVAPS_M128_to_XMM( t1reg, (uptr)vuFloatData ); - SSE_MOVAPS_M128_to_XMM( t2reg, (uptr)vuFloatData2 ); -} - -static PCSX2_ALIGNED16(u32 tempRegX[]) = {0x00000000, 0x00000000, 0x00000000, 0x00000000}; - -// Called by testWhenOverflow() function -void testPrintOverflow() { - tempRegX[0] &= 0xff800000; - tempRegX[1] &= 0xff800000; - tempRegX[2] &= 0xff800000; - tempRegX[3] &= 0xff800000; - if ( (tempRegX[0] == 0x7f800000) || (tempRegX[1] == 0x7f800000) || (tempRegX[2] == 0x7f800000) || (tempRegX[3] == 0x7f800000) ) - SysPrintf( "VU OVERFLOW!: Changing to +Fmax!!!!!!!!!!!!\n" ); - if ( (tempRegX[0] == 0xff800000) || (tempRegX[1] == 0xff800000) || (tempRegX[2] == 0xff800000) || (tempRegX[3] == 0xff800000) ) - SysPrintf( "VU OVERFLOW!: Changing to -Fmax!!!!!!!!!!!!\n" ); -} - -// Outputs to the console when overflow has occured. -void testWhenOverflow(int info, int regd, int t0reg) { - SSE_MOVAPS_XMM_to_M128((uptr)tempRegX, regd); - CALLFunc((uptr)testPrintOverflow); -} - -// Sets NaN Mode, used by Patches (currently does nothing) -void SetVUNanMode(int mode) -{ - g_VuNanHandling = mode; - if ( mode ) SysPrintf("enabling vunan mode"); +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "PrecompiledHeader.h" + +#include "Common.h" +#include "GS.h" +#include "R5900OpcodeTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "iMMI.h" +#include "iFPU.h" +#include "iCOP0.h" +#include "VUmicro.h" +#include "VUflags.h" +#include "iVUmicro.h" +#include "iVUops.h" +#include "iVUzerorec.h" + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif +//------------------------------------------------------------------ + +// fixme - VUmicro should really use its own static vars for pc and branch. +// Sharing with the EE's copies of pc and branch is not cool! (air) + +//------------------------------------------------------------------ +// Helper Macros +//------------------------------------------------------------------ +#define _Ft_ (( VU->code >> 16) & 0x1F) // The rt part of the instruction register +#define _Fs_ (( VU->code >> 11) & 0x1F) // The rd part of the instruction register +#define _Fd_ (( VU->code >> 6) & 0x1F) // The sa part of the instruction register + +#define _X (( VU->code>>24) & 0x1) +#define _Y (( VU->code>>23) & 0x1) +#define _Z (( VU->code>>22) & 0x1) +#define _W (( VU->code>>21) & 0x1) + +#define _XYZW_SS (_X+_Y+_Z+_W==1) + +#define _Fsf_ (( VU->code >> 21) & 0x03) +#define _Ftf_ (( VU->code >> 23) & 0x03) + +#define _Imm11_ (s32)(VU->code & 0x400 ? 0xfffffc00 | (VU->code & 0x3ff) : VU->code & 0x3ff) +#define _UImm11_ (s32)(VU->code & 0x7ff) + +#define VU_VFx_ADDR(x) (uptr)&VU->VF[x].UL[0] +#define VU_VFy_ADDR(x) (uptr)&VU->VF[x].UL[1] +#define VU_VFz_ADDR(x) (uptr)&VU->VF[x].UL[2] +#define VU_VFw_ADDR(x) (uptr)&VU->VF[x].UL[3] + +#define VU_REGR_ADDR (uptr)&VU->VI[REG_R] +#define VU_REGQ_ADDR (uptr)&VU->VI[REG_Q] +#define VU_REGMAC_ADDR (uptr)&VU->VI[REG_MAC_FLAG] + +#define VU_VI_ADDR(x, read) GetVIAddr(VU, x, read, info) + +#define VU_ACCx_ADDR (uptr)&VU->ACC.UL[0] +#define VU_ACCy_ADDR (uptr)&VU->ACC.UL[1] +#define VU_ACCz_ADDR (uptr)&VU->ACC.UL[2] +#define VU_ACCw_ADDR (uptr)&VU->ACC.UL[3] + +#define _X_Y_Z_W ((( VU->code >> 21 ) & 0xF ) ) +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// Global Variables +//------------------------------------------------------------------ +int g_VuNanHandling = 0; +int vucycle; + +PCSX2_ALIGNED16(float s_fones[8]) = {1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f}; +PCSX2_ALIGNED16(u32 s_mask[4]) = {0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff}; +PCSX2_ALIGNED16(u32 s_expmask[4]) = {0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000}; +PCSX2_ALIGNED16(u32 g_minvals[4]) = {0xff7fffff, 0xff7fffff, 0xff7fffff, 0xff7fffff}; +PCSX2_ALIGNED16(u32 g_maxvals[4]) = {0x7f7fffff, 0x7f7fffff, 0x7f7fffff, 0x7f7fffff}; +PCSX2_ALIGNED16(u32 const_clip[8]) = {0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, + 0x80000000, 0x80000000, 0x80000000, 0x80000000}; +PCSX2_ALIGNED(64, u32 g_ones[4]) = {0x00000001, 0x00000001, 0x00000001, 0x00000001}; +PCSX2_ALIGNED16(u32 g_minvals_XYZW[16][4]) = +{ + { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }, //0000 + { 0xffffffff, 0xffffffff, 0xffffffff, 0xff7fffff }, //0001 + { 0xffffffff, 0xffffffff, 0xff7fffff, 0xffffffff }, //0010 + { 0xffffffff, 0xffffffff, 0xff7fffff, 0xff7fffff }, //0011 + { 0xffffffff, 0xff7fffff, 0xffffffff, 0xffffffff }, //0100 + { 0xffffffff, 0xff7fffff, 0xffffffff, 0xff7fffff }, //0101 + { 0xffffffff, 0xff7fffff, 0xff7fffff, 0xffffffff }, //0110 + { 0xffffffff, 0xff7fffff, 0xff7fffff, 0xff7fffff }, //0111 + { 0xff7fffff, 0xffffffff, 0xffffffff, 0xffffffff }, //1000 + { 0xff7fffff, 0xffffffff, 0xffffffff, 0xff7fffff }, //1001 + { 0xff7fffff, 0xffffffff, 0xff7fffff, 0xffffffff }, //1010 + { 0xff7fffff, 0xffffffff, 0xff7fffff, 0xff7fffff }, //1011 + { 0xff7fffff, 0xff7fffff, 0xffffffff, 0xffffffff }, //1100 + { 0xff7fffff, 0xff7fffff, 0xffffffff, 0xff7fffff }, //1101 + { 0xff7fffff, 0xff7fffff, 0xff7fffff, 0xffffffff }, //1110 + { 0xff7fffff, 0xff7fffff, 0xff7fffff, 0xff7fffff }, //1111 +}; +PCSX2_ALIGNED16(u32 g_maxvals_XYZW[16][4])= +{ + { 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff }, //0000 + { 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7f7fffff }, //0001 + { 0x7fffffff, 0x7fffffff, 0x7f7fffff, 0x7fffffff }, //0010 + { 0x7fffffff, 0x7fffffff, 0x7f7fffff, 0x7f7fffff }, //0011 + { 0x7fffffff, 0x7f7fffff, 0x7fffffff, 0x7fffffff }, //0100 + { 0x7fffffff, 0x7f7fffff, 0x7fffffff, 0x7f7fffff }, //0101 + { 0x7fffffff, 0x7f7fffff, 0x7f7fffff, 0x7fffffff }, //0110 + { 0x7fffffff, 0x7f7fffff, 0x7f7fffff, 0x7f7fffff }, //0111 + { 0x7f7fffff, 0x7fffffff, 0x7fffffff, 0x7fffffff }, //1000 + { 0x7f7fffff, 0x7fffffff, 0x7fffffff, 0x7f7fffff }, //1001 + { 0x7f7fffff, 0x7fffffff, 0x7f7fffff, 0x7fffffff }, //1010 + { 0x7f7fffff, 0x7fffffff, 0x7f7fffff, 0x7f7fffff }, //1011 + { 0x7f7fffff, 0x7f7fffff, 0x7fffffff, 0x7fffffff }, //1100 + { 0x7f7fffff, 0x7f7fffff, 0x7fffffff, 0x7f7fffff }, //1101 + { 0x7f7fffff, 0x7f7fffff, 0x7f7fffff, 0x7fffffff }, //1110 + { 0x7f7fffff, 0x7f7fffff, 0x7f7fffff, 0x7f7fffff }, //1111 +}; +//------------------------------------------------------------------ + +//------------------------------------------------------------------ +// VU Pipeline/Test Stalls/Analyzing Functions +//------------------------------------------------------------------ +void _recvuFMACflush(VURegs * VU) { + int i; + + for (i=0; i<8; i++) { + if (VU->fmac[i].enable == 0) continue; + + if ((vucycle - VU->fmac[i].sCycle) >= VU->fmac[i].Cycle) { +// VUM_LOG("flushing FMAC pipe[%d]\n", i); + VU->fmac[i].enable = 0; + } + } +} + +void _recvuFDIVflush(VURegs * VU) { + if (VU->fdiv.enable == 0) return; + + if ((vucycle - VU->fdiv.sCycle) >= VU->fdiv.Cycle) { +// SysPrintf("flushing FDIV pipe\n"); + VU->fdiv.enable = 0; + } +} + +void _recvuEFUflush(VURegs * VU) { + if (VU->efu.enable == 0) return; + + if ((vucycle - VU->efu.sCycle) >= VU->efu.Cycle) { +// SysPrintf("flushing FDIV pipe\n"); + VU->efu.enable = 0; + } +} + +void _recvuTestPipes(VURegs * VU) { + _recvuFMACflush(VU); + _recvuFDIVflush(VU); + _recvuEFUflush(VU); +} + +void _recvuFMACTestStall(VURegs * VU, int reg, int xyzw) { + int cycle; + int i; + u32 mask = 0; + + for (i=0; i<8; i++) { + if (VU->fmac[i].enable == 0) continue; + if (VU->fmac[i].reg == reg && (VU->fmac[i].xyzw & xyzw)) break; + } + + if (i == 8) return; + + // do a perchannel delay + // old code +// cycle = VU->fmac[i].Cycle - (vucycle - VU->fmac[i].sCycle); + + // new code + mask = 4; // w +// if( VU->fmac[i].xyzw & 1 ) mask = 4; // w +// else if( VU->fmac[i].xyzw & 2 ) mask = 3; // z +// else if( VU->fmac[i].xyzw & 4 ) mask = 2; // y +// else { +// assert(VU->fmac[i].xyzw & 8 ); +// mask = 1; // x +// } + +// mask = 0; +// if( VU->fmac[i].xyzw & 1 ) mask++; // w +// else if( VU->fmac[i].xyzw & 2 ) mask++; // z +// else if( VU->fmac[i].xyzw & 4 ) mask++; // y +// else if( VU->fmac[i].xyzw & 8 ) mask++; // x + + assert( (int)VU->fmac[i].sCycle < (int)vucycle ); + cycle = 0; + if( vucycle - VU->fmac[i].sCycle < mask ) + cycle = mask - (vucycle - VU->fmac[i].sCycle); + + VU->fmac[i].enable = 0; + vucycle+= cycle; + _recvuTestPipes(VU); +} + +void _recvuFMACAdd(VURegs * VU, int reg, int xyzw) { + int i; + + /* find a free fmac pipe */ + for (i=0; i<8; i++) { + if (VU->fmac[i].enable == 1) continue; + break; + } + + if (i==8) SysPrintf("*PCSX2*: error , out of fmacs\n"); +// VUM_LOG("adding FMAC pipe[%d]; reg %d\n", i, reg); + + VU->fmac[i].enable = 1; + VU->fmac[i].sCycle = vucycle; + VU->fmac[i].Cycle = 3; + VU->fmac[i].xyzw = xyzw; + VU->fmac[i].reg = reg; +} + +void _recvuFDIVAdd(VURegs * VU, int cycles) { +// SysPrintf("adding FDIV pipe\n"); + VU->fdiv.enable = 1; + VU->fdiv.sCycle = vucycle; + VU->fdiv.Cycle = cycles; +} + +void _recvuEFUAdd(VURegs * VU, int cycles) { +// SysPrintf("adding EFU pipe\n"); + VU->efu.enable = 1; + VU->efu.sCycle = vucycle; + VU->efu.Cycle = cycles; +} + +void _recvuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn) { + + if( VUregsn->VFread0 && (VUregsn->VFread0 == VUregsn->VFread1) ) { + _recvuFMACTestStall(VU, VUregsn->VFread0, VUregsn->VFr0xyzw|VUregsn->VFr1xyzw); + } + else { + if (VUregsn->VFread0) _recvuFMACTestStall(VU, VUregsn->VFread0, VUregsn->VFr0xyzw); + if (VUregsn->VFread1) _recvuFMACTestStall(VU, VUregsn->VFread1, VUregsn->VFr1xyzw); + } +} + +void _recvuAddFMACStalls(VURegs * VU, _VURegsNum *VUregsn) { + + if (VUregsn->VFwrite) _recvuFMACAdd(VU, VUregsn->VFwrite, VUregsn->VFwxyzw); + else if (VUregsn->VIwrite & (1 << REG_CLIP_FLAG)) _recvuFMACAdd(VU, -REG_CLIP_FLAG, 0); // REG_CLIP_FLAG pipe + else _recvuFMACAdd(VU, 0, 0); +} + +void _recvuFlushFDIV(VURegs * VU) { + int cycle; + + if (VU->fdiv.enable == 0) return; + + cycle = VU->fdiv.Cycle - (vucycle - VU->fdiv.sCycle); +// SysPrintf("waiting FDIV pipe %d\n", cycle); + VU->fdiv.enable = 0; + vucycle+= cycle; +} + +void _recvuFlushEFU(VURegs * VU) { + int cycle; + + if (VU->efu.enable == 0) return; + + cycle = VU->efu.Cycle - (vucycle - VU->efu.sCycle); +// SysPrintf("waiting FDIV pipe %d\n", cycle); + VU->efu.enable = 0; + vucycle+= cycle; +} + +void _recvuTestFDIVStalls(VURegs * VU, _VURegsNum *VUregsn) { +// _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn); + _recvuFlushFDIV(VU); +} + +void _recvuTestEFUStalls(VURegs * VU, _VURegsNum *VUregsn) { +// _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn); + _recvuFlushEFU(VU); +} + +void _recvuAddFDIVStalls(VURegs * VU, _VURegsNum *VUregsn) { +// _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn); + if (VUregsn->VIwrite & (1 << REG_Q)) { + _recvuFDIVAdd(VU, VUregsn->cycles); + } +} + +void _recvuAddEFUStalls(VURegs * VU, _VURegsNum *VUregsn) { +// _vuTestFMACStalls(VURegs * VU, _VURegsNum *VUregsn); + if (VUregsn->VIwrite & (1 << REG_P)) { + _recvuEFUAdd(VU, VUregsn->cycles); + } +} + +void _recvuTestUpperStalls(VURegs * VU, _VURegsNum *VUregsn) { + switch (VUregsn->pipe) { + case VUPIPE_FMAC: _recvuTestFMACStalls(VU, VUregsn); break; + } +} + +void _recvuTestLowerStalls(VURegs * VU, _VURegsNum *VUregsn) { + switch (VUregsn->pipe) { + case VUPIPE_FMAC: _recvuTestFMACStalls(VU, VUregsn); break; + case VUPIPE_FDIV: _recvuTestFDIVStalls(VU, VUregsn); break; + case VUPIPE_EFU: _recvuTestEFUStalls(VU, VUregsn); break; + } +} + +void _recvuAddUpperStalls(VURegs * VU, _VURegsNum *VUregsn) { + switch (VUregsn->pipe) { + case VUPIPE_FMAC: _recvuAddFMACStalls(VU, VUregsn); break; + } +} + +void _recvuAddLowerStalls(VURegs * VU, _VURegsNum *VUregsn) { + switch (VUregsn->pipe) { + case VUPIPE_FMAC: _recvuAddFMACStalls(VU, VUregsn); break; + case VUPIPE_FDIV: _recvuAddFDIVStalls(VU, VUregsn); break; + case VUPIPE_EFU: _recvuAddEFUStalls(VU, VUregsn); break; + } +} + +void SuperVUAnalyzeOp(VURegs *VU, _vuopinfo *info, _VURegsNum* pCodeRegs) +{ + _VURegsNum* lregs; + _VURegsNum* uregs; + int *ptr; + + lregs = pCodeRegs; + uregs = pCodeRegs+1; + + ptr = (int*)&VU->Micro[pc]; + pc += 8; + + if (ptr[1] & 0x40000000) { // EOP + branch |= 8; + } + + VU->code = ptr[1]; + if (VU == &VU1) VU1regs_UPPER_OPCODE[VU->code & 0x3f](uregs); + else VU0regs_UPPER_OPCODE[VU->code & 0x3f](uregs); + + _recvuTestUpperStalls(VU, uregs); + switch(VU->code & 0x3f) { + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1d: case 0x1f: + case 0x2b: case 0x2f: + break; + + case 0x3c: + switch ((VU->code >> 6) & 0x1f) { + case 0x4: case 0x5: + break; + default: + info->statusflag = 4; + info->macflag = 4; + break; + } + break; + case 0x3d: + switch ((VU->code >> 6) & 0x1f) { + case 0x4: case 0x5: case 0x7: + break; + default: + info->statusflag = 4; + info->macflag = 4; + break; + } + break; + case 0x3e: + switch ((VU->code >> 6) & 0x1f) { + case 0x4: case 0x5: + break; + default: + info->statusflag = 4; + info->macflag = 4; + break; + } + break; + case 0x3f: + switch ((VU->code >> 6) & 0x1f) { + case 0x4: case 0x5: case 0x7: case 0xb: + break; + default: + info->statusflag = 4; + info->macflag = 4; + break; + } + break; + + default: + info->statusflag = 4; + info->macflag = 4; + break; + } + + if (uregs->VIread & (1 << REG_Q)) { info->q |= 2; } + if (uregs->VIread & (1 << REG_P)) { info->p |= 2; assert( VU == &VU1 ); } + + // check upper flags + if (ptr[1] & 0x80000000) { // I flag + info->cycle = vucycle; + memzero_obj(*lregs); + } + else { + + VU->code = ptr[0]; + if (VU == &VU1) VU1regs_LOWER_OPCODE[VU->code >> 25](lregs); + else VU0regs_LOWER_OPCODE[VU->code >> 25](lregs); + + _recvuTestLowerStalls(VU, lregs); + info->cycle = vucycle; + + if (lregs->pipe == VUPIPE_BRANCH) { + branch |= 1; + } + + if (lregs->VIwrite & (1 << REG_Q)) { + info->q |= 4; + info->cycles = lregs->cycles; + info->pqinst = (VU->code&2)>>1; // rsqrt is 2 + } + else if (lregs->pipe == VUPIPE_FDIV) { + info->q |= 8|1; + info->pqinst = 0; + } + + if (lregs->VIwrite & (1 << REG_P)) { + assert( VU == &VU1 ); + info->p |= 4; + info->cycles = lregs->cycles; + + switch( VU->code & 0xff ) { + case 0xfd: info->pqinst = 0; break; //eatan + case 0x7c: info->pqinst = 0; break; //eatanxy + case 0x7d: info->pqinst = 0; break; //eatanzy + case 0xfe: info->pqinst = 1; break; //eexp + case 0xfc: info->pqinst = 2; break; //esin + case 0x3f: info->pqinst = 3; break; //erleng + case 0x3e: info->pqinst = 4; break; //eleng + case 0x3d: info->pqinst = 4; break; //ersadd + case 0xbd: info->pqinst = 4; break; //ersqrt + case 0xbe: info->pqinst = 5; break; //ercpr + case 0xbc: info->pqinst = 5; break; //esqrt + case 0x7e: info->pqinst = 5; break; //esum + case 0x3c: info->pqinst = 6; break; //esadd + default: assert(0); + } + } + else if (lregs->pipe == VUPIPE_EFU) { + info->p |= 8|1; + } + + if (lregs->VIread & (1 << REG_STATUS_FLAG)) info->statusflag|= VUOP_READ; + if (lregs->VIread & (1 << REG_MAC_FLAG)) info->macflag|= VUOP_READ; + + if (lregs->VIwrite & (1 << REG_STATUS_FLAG)) info->statusflag|= VUOP_WRITE; + if (lregs->VIwrite & (1 << REG_MAC_FLAG)) info->macflag|= VUOP_WRITE; + + if (lregs->VIread & (1 << REG_Q)) { info->q |= 2; } + if (lregs->VIread & (1 << REG_P)) { info->p |= 2; assert( VU == &VU1 ); } + + _recvuAddLowerStalls(VU, lregs); + } + + _recvuAddUpperStalls(VU, uregs); + _recvuTestPipes(VU); + + vucycle++; +} + +int eeVURecompileCode(VURegs *VU, _VURegsNum* regs) +{ + int info = 0; + int vfread0=-1, vfread1 = -1, vfwrite = -1, vfacc = -1, vftemp=-1; + + assert( regs != NULL ); + + if( regs->VFread0 ) _addNeededVFtoXMMreg(regs->VFread0); + if( regs->VFread1 ) _addNeededVFtoXMMreg(regs->VFread1); + if( regs->VFwrite ) _addNeededVFtoXMMreg(regs->VFwrite); + if( regs->VIread & (1<VIread & (1<VFread0 ) vfread0 = _allocVFtoXMMreg(VU, -1, regs->VFread0, MODE_READ); + else if( regs->VIread & (1<VFread1 ) vfread1 = _allocVFtoXMMreg(VU, -1, regs->VFread1, MODE_READ); + else if( (regs->VIread & (1<VFr1xyzw != 0xff) vfread1 = _allocVFtoXMMreg(VU, -1, 0, MODE_READ); + + if( regs->VIread & (1<VIwrite&(1<VIwrite & (1<VFwxyzw != 0xf?MODE_READ:0)); + } + + if( regs->VFwrite ) { + assert( !(regs->VIwrite&(1<VFwrite, MODE_WRITE|(regs->VFwxyzw != 0xf?MODE_READ:0)); + } + + if( vfacc>= 0 ) info |= PROCESS_EE_SET_ACC(vfacc); + if( vfwrite >= 0 ) { + if( regs->VFwrite == _Ft_ && vfread1 < 0 ) { + info |= PROCESS_EE_SET_T(vfwrite); + } + else { + assert( regs->VFwrite == _Fd_ ); + info |= PROCESS_EE_SET_D(vfwrite); + } + } + + if( vfread0 >= 0 ) info |= PROCESS_EE_SET_S(vfread0); + if( vfread1 >= 0 ) info |= PROCESS_EE_SET_T(vfread1); + + vftemp = _allocTempXMMreg(XMMT_FPS, -1); + info |= PROCESS_VU_SET_TEMP(vftemp); + + if( regs->VIwrite & (1 << REG_CLIP_FLAG) ) { + // CLIP inst, need two extra temp registers, put it EEREC_D and EEREC_ACC + int t1reg = _allocTempXMMreg(XMMT_FPS, -1); + int t2reg = _allocTempXMMreg(XMMT_FPS, -1); + + info |= PROCESS_EE_SET_D(t1reg); + info |= PROCESS_EE_SET_ACC(t2reg); + + _freeXMMreg(t1reg); // don't need + _freeXMMreg(t2reg); // don't need + } + else if( regs->VIwrite & (1<VI[reg].UL; + + if( read != 1 ) { + if( reg == REG_MAC_FLAG ) return (uptr)&VU->macflag; + if( reg == REG_CLIP_FLAG ) return (uptr)&VU->clipflag; + if( reg == REG_STATUS_FLAG ) return (uptr)&VU->statusflag; + if( reg == REG_Q ) return (uptr)&VU->q; + if( reg == REG_P ) return (uptr)&VU->p; + } + + return (uptr)&VU->VI[reg].UL; +} + +// gets a temp reg that is not EEREC_TEMP +int _vuGetTempXMMreg(int info) +{ + int t1reg = -1; + + if( _hasFreeXMMreg() ) { + t1reg = _allocTempXMMreg(XMMT_FPS, -1); + + if( t1reg == EEREC_TEMP ) { + if( _hasFreeXMMreg() ) { + int t = _allocTempXMMreg(XMMT_FPS, -1); + _freeXMMreg(t1reg); + t1reg = t; + } + else { + _freeXMMreg(t1reg); + t1reg = -1; + } + } + } + + return t1reg; +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// Misc VU Reg Flipping/Merging Functions +//------------------------------------------------------------------ +void _unpackVF_xyzw(int dstreg, int srcreg, int xyzw) +{ + switch (xyzw) { + case 0: SSE2_PSHUFD_XMM_to_XMM(dstreg, srcreg, 0x00); break; + case 1: SSE2_PSHUFD_XMM_to_XMM(dstreg, srcreg, 0x55); break; + case 2: SSE2_PSHUFD_XMM_to_XMM(dstreg, srcreg, 0xaa); break; + case 3: SSE2_PSHUFD_XMM_to_XMM(dstreg, srcreg, 0xff); break; + } +} + +void _unpackVFSS_xyzw(int dstreg, int srcreg, int xyzw) +{ + switch (xyzw) { + case 0: SSE_MOVSS_XMM_to_XMM(dstreg, srcreg); break; + case 1: if ( cpucaps.hasStreamingSIMD4Extensions ) SSE4_INSERTPS_XMM_to_XMM(dstreg, srcreg, _MM_MK_INSERTPS_NDX(1, 0, 0)); + else SSE2_PSHUFLW_XMM_to_XMM(dstreg, srcreg, 0xee); + break; + case 2: SSE_MOVHLPS_XMM_to_XMM(dstreg, srcreg); break; + case 3: if ( cpucaps.hasStreamingSIMD4Extensions ) SSE4_INSERTPS_XMM_to_XMM(dstreg, srcreg, _MM_MK_INSERTPS_NDX(3, 0, 0)); + else { SSE_MOVHLPS_XMM_to_XMM(dstreg, srcreg); SSE2_PSHUFLW_XMM_to_XMM(dstreg, dstreg, 0xee); } + break; + } +} + +void _vuFlipRegSS(VURegs * VU, int reg) +{ + assert( _XYZW_SS ); + if( _Y ) SSE2_PSHUFLW_XMM_to_XMM(reg, reg, 0x4e); + else if( _Z ) SSE_SHUFPS_XMM_to_XMM(reg, reg, 0xc6); + else if( _W ) SSE_SHUFPS_XMM_to_XMM(reg, reg, 0x27); +} + +void _vuFlipRegSS_xyzw(int reg, int xyzw) +{ + switch ( xyzw ) { + case 1: SSE2_PSHUFLW_XMM_to_XMM(reg, reg, 0x4e); break; + case 2: SSE_SHUFPS_XMM_to_XMM(reg, reg, 0xc6); break; + case 3: SSE_SHUFPS_XMM_to_XMM(reg, reg, 0x27); break; + } +} + +void _vuMoveSS(VURegs * VU, int dstreg, int srcreg) +{ + assert( _XYZW_SS ); + if( _Y ) _unpackVFSS_xyzw(dstreg, srcreg, 1); + else if( _Z ) _unpackVFSS_xyzw(dstreg, srcreg, 2); + else if( _W ) _unpackVFSS_xyzw(dstreg, srcreg, 3); + else _unpackVFSS_xyzw(dstreg, srcreg, 0); +} + +// 1 - src, 0 - dest wzyx +void VU_MERGE0(int dest, int src) { // 0000s +} +void VU_MERGE1(int dest, int src) { // 1000 + SSE_MOVHLPS_XMM_to_XMM(src, dest); + SSE_SHUFPS_XMM_to_XMM(dest, src, 0xc4); +} +void VU_MERGE1b(int dest, int src) { // 1000s + SSE_SHUFPS_XMM_to_XMM(src, src, 0x27); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x27); + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, src, 0x27); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x27); +} +void VU_MERGE2(int dest, int src) { // 0100 + SSE_MOVHLPS_XMM_to_XMM(src, dest); + SSE_SHUFPS_XMM_to_XMM(dest, src, 0x64); +} +void VU_MERGE2b(int dest, int src) { // 0100s + SSE_SHUFPS_XMM_to_XMM(src, src, 0xC6); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xC6); + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, src, 0xC6); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xC6); +} +void VU_MERGE3(int dest, int src) { // 1100s + SSE_SHUFPS_XMM_to_XMM(dest, src, 0xe4); +} +void VU_MERGE4(int dest, int src) { // 0010 + SSE_MOVSS_XMM_to_XMM(src, dest); + SSE2_MOVSD_XMM_to_XMM(dest, src); +} +void VU_MERGE4b(int dest, int src) { // 0010s + SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); +} +void VU_MERGE5(int dest, int src) { // 1010 + SSE_SHUFPS_XMM_to_XMM(dest, src, 0xd8); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xd8); +} +void VU_MERGE5b(int dest, int src) { // 1010s + SSE_SHUFPS_XMM_to_XMM(src, src, 0x27); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x27); + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, src, 0x27); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x27); + SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); +} +void VU_MERGE6(int dest, int src) { // 0110 + SSE_SHUFPS_XMM_to_XMM(dest, src, 0x9c); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x78); +} +void VU_MERGE6b(int dest, int src) { // 0110s + SSE_SHUFPS_XMM_to_XMM(src, src, 0xC6); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xC6); + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, src, 0xC6); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xC6); + SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); +} +void VU_MERGE7(int dest, int src) { // 1110 + SSE_MOVSS_XMM_to_XMM(src, dest); + SSE_MOVAPS_XMM_to_XMM(dest, src); +} +void VU_MERGE7b(int dest, int src) { // 1110s + SSE_SHUFPS_XMM_to_XMM(dest, src, 0xe4); + SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); +} +void VU_MERGE8(int dest, int src) { // 0001s + SSE_MOVSS_XMM_to_XMM(dest, src); +} +void VU_MERGE9(int dest, int src) { // 1001 + SSE_SHUFPS_XMM_to_XMM(dest, src, 0xc9); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xd2); +} +void VU_MERGE9b(int dest, int src) { // 1001s + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, src, 0x27); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x27); + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, src, 0x27); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x27); +} +void VU_MERGE10(int dest, int src) { // 0101 + SSE_SHUFPS_XMM_to_XMM(dest, src, 0x8d); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x72); +} +void VU_MERGE10b(int dest, int src) { // 0101s + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, src, 0xC6); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xC6); + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, src, 0xC6); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xC6); +} +void VU_MERGE11(int dest, int src) { // 1101s + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(dest, src, 0xe4); +} +void VU_MERGE12(int dest, int src) { // 0011 + SSE2_MOVSD_XMM_to_XMM(dest, src); +} +void VU_MERGE13(int dest, int src) { // 1011 + SSE_MOVHLPS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, dest, 0x64); + SSE_MOVAPS_XMM_to_XMM(dest, src); +} +void VU_MERGE13b(int dest, int src) { // 1011s + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, src, 0x27); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x27); + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, src, 0x27); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0x27); + SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); +} +void VU_MERGE14(int dest, int src) { // 0111 + SSE_MOVHLPS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, dest, 0xc4); + SSE_MOVAPS_XMM_to_XMM(dest, src); +} +void VU_MERGE14b(int dest, int src) { // 0111s + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, src, 0xE1); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xE1); + SSE_SHUFPS_XMM_to_XMM(src, src, 0xC6); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xC6); + SSE_MOVSS_XMM_to_XMM(dest, src); + SSE_SHUFPS_XMM_to_XMM(src, src, 0xC6); + SSE_SHUFPS_XMM_to_XMM(dest, dest, 0xC6); +} +void VU_MERGE15(int dest, int src) { // 1111s + SSE_MOVAPS_XMM_to_XMM(dest, src); +} + +typedef void (*VUMERGEFN)(int dest, int src); + +static VUMERGEFN s_VuMerge[16] = { + VU_MERGE0, VU_MERGE1, VU_MERGE2, VU_MERGE3, + VU_MERGE4, VU_MERGE5, VU_MERGE6, VU_MERGE7, + VU_MERGE8, VU_MERGE9, VU_MERGE10, VU_MERGE11, + VU_MERGE12, VU_MERGE13, VU_MERGE14, VU_MERGE15 }; + +static VUMERGEFN s_VuMerge2[16] = { + VU_MERGE0, VU_MERGE1b, VU_MERGE2b, VU_MERGE3, + VU_MERGE4b, VU_MERGE5b, VU_MERGE6b, VU_MERGE7b, + VU_MERGE8, VU_MERGE9b, VU_MERGE10b, VU_MERGE11, + VU_MERGE12, VU_MERGE13b, VU_MERGE14b, VU_MERGE15 }; + +// Modifies the Source Reg! +void VU_MERGE_REGS_CUSTOM(int dest, int src, int xyzw) { + xyzw &= 0xf; + if ( (dest != src) && (xyzw != 0) ) { + if ( cpucaps.hasStreamingSIMD4Extensions && (xyzw != 0x8) && (xyzw != 0xf) ) { + xyzw = ((xyzw & 1) << 3) | ((xyzw & 2) << 1) | ((xyzw & 4) >> 1) | ((xyzw & 8) >> 3); + SSE4_BLENDPS_XMM_to_XMM(dest, src, xyzw); + } + else s_VuMerge[xyzw](dest, src); + } +} +// Doesn't Modify the Source Reg! (ToDo: s_VuMerge2() has room for optimization) +void VU_MERGE_REGS_SAFE(int dest, int src, int xyzw) { + xyzw &= 0xf; + if ( (dest != src) && (xyzw != 0) ) { + if ( cpucaps.hasStreamingSIMD4Extensions && (xyzw != 0x8) && (xyzw != 0xf) ) { + xyzw = ((xyzw & 1) << 3) | ((xyzw & 2) << 1) | ((xyzw & 4) >> 1) | ((xyzw & 8) >> 3); + SSE4_BLENDPS_XMM_to_XMM(dest, src, xyzw); + } + else s_VuMerge2[xyzw](dest, src); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// Misc VU Reg Clamping/Overflow Functions +//------------------------------------------------------------------ +#define CLAMP_NORMAL_SSE4(n) \ + SSE_MOVAPS_XMM_to_XMM(regTemp, regd);\ + SSE4_PMINUD_M128_to_XMM(regd, (uptr)&g_minvals_XYZW[n][0]);\ + SSE2_PSUBD_XMM_to_XMM(regTemp, regd);\ + SSE2_PCMPGTD_M128_to_XMM(regTemp, (uptr)&g_ones[0]);\ + SSE4_PMINSD_M128_to_XMM(regd, (uptr)&g_maxvals_XYZW[n][0]);\ + SSE2_PSLLD_I8_to_XMM(regTemp, 31);\ + SSE_XORPS_XMM_to_XMM(regd, regTemp); + +#define CLAMP_SIGN_SSE4(n) \ + SSE4_PMINSD_M128_to_XMM(regd, (uptr)&g_maxvals_XYZW[n][0]);\ + SSE4_PMINUD_M128_to_XMM(regd, (uptr)&g_minvals_XYZW[n][0]); + +void vFloat0(int regd, int regTemp) { } //0000 +void vFloat1(int regd, int regTemp) { //1000 + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); +} +void vFloat1b(int regd, int regTemp) { //1000 //regTemp is Modified + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_NORMAL_SSE4(1); + } + else { + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + } +} +void vFloat1c(int regd, int regTemp) { //1000 + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_SIGN_SSE4(1); + } + else { + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_ORPS_XMM_to_XMM(regd, regTemp); + } +} +void vFloat2(int regd, int regTemp) { //0100 + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); +} +void vFloat2b(int regd, int regTemp) { //0100 //regTemp is Modified + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_NORMAL_SSE4(2); + } + else { + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + } +} +void vFloat2c(int regd, int regTemp) { //0100 + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_SIGN_SSE4(2); + } + else { + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE_ORPS_XMM_to_XMM(regd, regTemp); + } +} +void vFloat3(int regd, int regTemp) { //1100 + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x36); +} +void vFloat3b(int regd, int regTemp) { //1100 //regTemp is Modified + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_NORMAL_SSE4(3); + } + else { + SSE2_MOVSD_XMM_to_XMM(regTemp, regd); + SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); + SSE2_MOVSD_XMM_to_XMM(regd, regTemp); + } +} +void vFloat3c(int regd, int regTemp) { //1100 + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_SIGN_SSE4(3); + } + else { + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x36); + SSE_ORPS_XMM_to_XMM(regd, regTemp); + } +} +void vFloat4(int regd, int regTemp) { //0010 + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); +} +void vFloat4b(int regd, int regTemp) { //0010 //regTemp is Modified + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_NORMAL_SSE4(4); + } + else { + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + } +} +void vFloat4c(int regd, int regTemp) { //0010 + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_SIGN_SSE4(4); + } + else { + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE_ORPS_XMM_to_XMM(regd, regTemp); + } +} +void vFloat5(int regd, int regTemp) { //1010 + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x2d); +} +void vFloat5b(int regd, int regTemp) { //1010 //regTemp is Modified + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_NORMAL_SSE4(5); + } + else { + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x2d); + } +} +void vFloat5c(int regd, int regTemp) { //1010 + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_SIGN_SSE4(5); + } + else { + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x2d); + SSE_ORPS_XMM_to_XMM(regd, regTemp); + } +} +void vFloat6(int regd, int regTemp) { //0110 + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc9); +} +void vFloat6b(int regd, int regTemp) { //0110 //regTemp is Modified + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_NORMAL_SSE4(6); + } + else { + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc9); + } +} +void vFloat6c(int regd, int regTemp) { //0110 + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_SIGN_SSE4(6); + } + else { + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc9); + SSE_ORPS_XMM_to_XMM(regd, regTemp); + } +} +void vFloat7(int regd, int regTemp) { //1110 + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x39); +} +void vFloat7_useEAX(int regd, int regTemp) { //1110 //EAX is Modified + SSE2_MOVD_XMM_to_R(EAX, regd); + SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); + if ( cpucaps.hasStreamingSIMD4Extensions ) + SSE4_PINSRD_R32_to_XMM(regd, EAX, 0x00); + else { + SSE_PINSRW_R32_to_XMM(regd, EAX, 0); + SHR32ItoR(EAX, 16); + SSE_PINSRW_R32_to_XMM(regd, EAX, 1); + } +} +void vFloat7b(int regd, int regTemp) { //1110 //regTemp is Modified + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_NORMAL_SSE4(7); + } + else { + SSE_MOVSS_XMM_to_XMM(regTemp, regd); + SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); + SSE_MOVSS_XMM_to_XMM(regd, regTemp); + } +} +void vFloat7c(int regd, int regTemp) { //1110 + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_SIGN_SSE4(7); + } + else { + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x39); + SSE_ORPS_XMM_to_XMM(regd, regTemp); + } +} +void vFloat7c_useEAX(int regd, int regTemp) { //1110 //EAX is Modified + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_SIGN_SSE4(7); + } + else { + SSE2_MOVD_XMM_to_R(EAX, regd); + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); + SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); + SSE_ORPS_XMM_to_XMM(regd, regTemp); + SSE2_MOVD_R_to_XMM(regTemp, EAX); + SSE_MOVSS_XMM_to_XMM(regd, regTemp); + } +} +void vFloat8(int regd, int regTemp) { //0001 + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); +} +void vFloat8b(int regd, int regTemp) { //0001 //regTemp is Modified + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_NORMAL_SSE4(8); + } + else { + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + } +} +void vFloat8c(int regd, int regTemp) { //0001 + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_SIGN_SSE4(8); + } + else { + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_ORPS_XMM_to_XMM(regd, regTemp); + } +} +void vFloat9(int regd, int regTemp) { //1001 + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); +} +void vFloat9b(int regd, int regTemp) { //1001 //regTemp is Modified + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_NORMAL_SSE4(9); + } + else { + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + } +} +void vFloat9c(int regd, int regTemp) { //1001 + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_SIGN_SSE4(9); + } + else { + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_ORPS_XMM_to_XMM(regd, regTemp); + } +} +void vFloat10(int regd, int regTemp) { //0101 + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); +} +void vFloat10b(int regd, int regTemp) { //0101 //regTemp is Modified + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_NORMAL_SSE4(10); + } + else { + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + } +} +void vFloat10c(int regd, int regTemp) { //0101 + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_SIGN_SSE4(10); + } + else { + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE_ORPS_XMM_to_XMM(regd, regTemp); + } +} +void vFloat11(int regd, int regTemp) { //1101 + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x36); +} +void vFloat11_useEAX(int regd, int regTemp) { //1101 //EAX is Modified + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE2_MOVD_XMM_to_R(EAX, regd); + SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); + if ( cpucaps.hasStreamingSIMD4Extensions ) + SSE4_PINSRD_R32_to_XMM(regd, EAX, 0x00); + else { + SSE_PINSRW_R32_to_XMM(regd, EAX, 0); + SHR32ItoR(EAX, 16); + SSE_PINSRW_R32_to_XMM(regd, EAX, 1); + } + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); +} +void vFloat11b(int regd, int regTemp) { //1101 //regTemp is Modified + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_NORMAL_SSE4(11); + } + else { + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); + SSE_MOVSS_XMM_to_XMM(regTemp, regd); + SSE2_MOVSD_XMM_to_XMM(regd, regTemp); + } +} +void vFloat11c(int regd, int regTemp) { //1101 + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_SIGN_SSE4(11); + } + else { + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x36); + SSE_ORPS_XMM_to_XMM(regd, regTemp); + } +} +void vFloat11c_useEAX(int regd, int regTemp) { //1101 // EAX is modified + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_SIGN_SSE4(11); + } + else { + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE2_MOVD_XMM_to_R(EAX, regTemp); + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); + SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); + SSE_ORPS_XMM_to_XMM(regTemp, regd); + SSE2_MOVD_R_to_XMM(regd, EAX); + SSE_MOVLHPS_XMM_to_XMM(regd, regTemp); + SSE_SHUFPS_XMM_to_XMM(regd, regTemp, 0xe2); + } +} +void vFloat12(int regd, int regTemp) { //0011 + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); +} +void vFloat12b(int regd, int regTemp) { //0011 //regTemp is Modified + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_NORMAL_SSE4(12); + } + else { + SSE_MOVHLPS_XMM_to_XMM(regTemp, regd); + SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); + SSE2_PUNPCKLQDQ_XMM_to_XMM(regd, regTemp); + } +} +void vFloat12c(int regd, int regTemp) { //0011 + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_SIGN_SSE4(12); + } + else { + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE_ORPS_XMM_to_XMM(regd, regTemp); + } +} +void vFloat13(int regd, int regTemp) { //1011 + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x2d); +} +void vFloat13_useEAX(int regd, int regTemp) { //1011 // EAX is modified + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE2_MOVD_XMM_to_R(EAX, regd); + SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); + if ( cpucaps.hasStreamingSIMD4Extensions ) + SSE4_PINSRD_R32_to_XMM(regd, EAX, 0x00); + else { + SSE_PINSRW_R32_to_XMM(regd, EAX, 0); + SHR32ItoR(EAX, 16); + SSE_PINSRW_R32_to_XMM(regd, EAX, 1); + } + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); +} +void vFloat13b(int regd, int regTemp) { //1011 //regTemp is Modified + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_NORMAL_SSE4(13); + } + else { + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); + SSE_MOVHLPS_XMM_to_XMM(regTemp, regd); + SSE_SHUFPS_XMM_to_XMM(regd, regTemp, 0x64); + } +} +void vFloat13c(int regd, int regTemp) { //1011 + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_SIGN_SSE4(13); + } + else { + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x2d); + SSE_ORPS_XMM_to_XMM(regd, regTemp); + } +} +void vFloat13c_useEAX(int regd, int regTemp) { //1011 // EAX is modified + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_SIGN_SSE4(13); + } + else { + SSE2_PSHUFD_XMM_to_XMM(regTemp, regd, 0xd2); + SSE2_MOVD_XMM_to_R(EAX, regTemp); + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); + SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); + SSE_ORPS_XMM_to_XMM(regd, regTemp); + SSE2_MOVD_R_to_XMM(regTemp, EAX); + SSE_SHUFPS_XMM_to_XMM(regTemp, regd, 0xf0); + SSE_SHUFPS_XMM_to_XMM(regd, regTemp, 0x84); + } +} +void vFloat14(int regd, int regTemp) { //0111 + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc9); +} +void vFloat14_useEAX(int regd, int regTemp) { //0111 // EAX is modified + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE2_MOVD_XMM_to_R(EAX, regd); + SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); + if ( cpucaps.hasStreamingSIMD4Extensions ) + SSE4_PINSRD_R32_to_XMM(regd, EAX, 0x00); + else { + SSE_PINSRW_R32_to_XMM(regd, EAX, 0); + SHR32ItoR(EAX, 16); + SSE_PINSRW_R32_to_XMM(regd, EAX, 1); + } + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); +} +void vFloat14b(int regd, int regTemp) { //0111 //regTemp is Modified + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_NORMAL_SSE4(14); + } + else { + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); + SSE_MOVHLPS_XMM_to_XMM(regTemp, regd); + SSE_SHUFPS_XMM_to_XMM(regd, regTemp, 0xc4); + } +} +void vFloat14c(int regd, int regTemp) { //0111 + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_SIGN_SSE4(14); + } + else { + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE2_PSHUFLW_XMM_to_XMM(regd, regd, 0x4e); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc6); + SSE_MINSS_M32_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXSS_M32_to_XMM(regd, (uptr)g_minvals); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0xc9); + SSE_ORPS_XMM_to_XMM(regd, regTemp); + } +} +void vFloat14c_useEAX(int regd, int regTemp) { //0111 // EAX is modified + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_SIGN_SSE4(14); + } + else { + SSE2_PSHUFD_XMM_to_XMM(regTemp, regd, 0x93); + SSE2_MOVD_XMM_to_R(EAX, regTemp); + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); + SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); + SSE_ORPS_XMM_to_XMM(regd, regTemp); + SSE2_MOVD_R_to_XMM(regTemp, EAX); + SSE_SHUFPS_XMM_to_XMM(regTemp, regd, 0xa0); + SSE_SHUFPS_XMM_to_XMM(regd, regTemp, 0x24); + } +} +void vFloat15(int regd, int regTemp) { //1111 + SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); +} +void vFloat15b(int regd, int regTemp) { //1111 + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_NORMAL_SSE4(15); + } + else { + SSE_MINPS_M128_to_XMM(regd, (uptr)g_maxvals); + SSE_MAXPS_M128_to_XMM(regd, (uptr)g_minvals); + } +} +void vFloat15c(int regd, int regTemp) { //1111 + if ( cpucaps.hasStreamingSIMD4Extensions ) { + CLAMP_SIGN_SSE4(15); + } + else { + SSE_MOVAPS_XMM_to_XMM(regTemp, regd); + SSE_ANDPS_M128_to_XMM(regTemp, (uptr)&const_clip[4]); + SSE_MINPS_M128_to_XMM(regd, (uptr)&g_maxvals[0]); + SSE_MAXPS_M128_to_XMM(regd, (uptr)&g_minvals[0]); + SSE_ORPS_XMM_to_XMM(regd, regTemp); + } +} + +vFloat vFloats1[16] = { //regTemp is not modified + vFloat0, vFloat1, vFloat2, vFloat3, + vFloat4, vFloat5, vFloat6, vFloat7, + vFloat8, vFloat9, vFloat10, vFloat11, + vFloat12, vFloat13, vFloat14, vFloat15 }; + +vFloat vFloats1_useEAX[16] = { //regTemp is not modified but EAX is used + vFloat0, vFloat1, vFloat2, vFloat3, + vFloat4, vFloat5, vFloat6, vFloat7_useEAX, + vFloat8, vFloat9, vFloat10, vFloat11_useEAX, + vFloat12, vFloat13_useEAX, vFloat14_useEAX, vFloat15 }; + +vFloat vFloats2[16] = { //regTemp is modified + vFloat0, vFloat1, vFloat2, vFloat3b, + vFloat4, vFloat5b, vFloat6b, vFloat7b, + vFloat8, vFloat9b, vFloat10b, vFloat11b, + vFloat12b, vFloat13b, vFloat14b, vFloat15 }; + +vFloat vFloats2_MUL_MADD[16] = { //regTemp is modified (Faster than vFloats2 if dealing with Denormals and using SSE4) + vFloat0, vFloat1b, vFloat2b, vFloat3b, + vFloat4b, vFloat5b, vFloat6b, vFloat7b, + vFloat8b, vFloat9b, vFloat10b, vFloat11b, + vFloat12b, vFloat13b, vFloat14b, vFloat15b }; + +vFloat vFloats4[16] = { //regTemp is modified + vFloat0, vFloat1c, vFloat2c, vFloat3c, + vFloat4c, vFloat5c, vFloat6c, vFloat7c, + vFloat8c, vFloat9c, vFloat10c, vFloat11c, + vFloat1c, vFloat13c, vFloat14c, vFloat15c }; + +vFloat vFloats4_useEAX[16] = { //regTemp is modified and EAX is used + vFloat0, vFloat1c, vFloat2c, vFloat3c, + vFloat4c, vFloat5c, vFloat6c, vFloat7c_useEAX, + vFloat8c, vFloat9c, vFloat10c, vFloat11c_useEAX, + vFloat1c, vFloat13c_useEAX, vFloat14c_useEAX, vFloat15c }; + +//------------------------------------------------------------------ +// Clamping Functions (wrapper for vFloat* functions) +// vuFloat : "normal" clamping +// vuFloat_useEAX : "normal" clamping (faster but EAX is modified) +// vuFloat2 : "normal" clamping (fastest but regTemp is modified) +// vuFloat3 : "preserve sign" clamping for pointer +// vuFloat4 : "preserve sign" clamping (regTemp is modified; *FASTEST* on SSE4 CPUs) +// vuFloat4_useEAX : "preserve sign" clamping (faster but regTemp and EAX are modified) +// vuFloat5 : wrapper function for vuFloat2 and vuFloat4 +// vuFloat5_useEAX : wrapper function for vuFloat2 and vuFloat4_useEAX +// vuFloatExtra : for debugging +// +// Notice 1: vuFloat*_useEAX may be slower on AMD CPUs, which have independent execution pipeline for +// vector and scalar instructions (need checks) +// Notice 2: recVUMI_MUL_xyzw_toD and recVUMI_MADD_xyzw_toD use vFloats directly! +//------------------------------------------------------------------ + +// Clamps +/-NaN to +fMax and +/-Inf to +/-fMax (doesn't use any temp regs) +void vuFloat( int info, int regd, int XYZW) { + if( CHECK_VU_OVERFLOW ) { + /*if ( (XYZW != 0) && (XYZW != 8) && (XYZW != 0xF) ) { + int t1reg = _vuGetTempXMMreg(info); + if (t1reg >= 0) { + vuFloat2( regd, t1reg, XYZW ); + _freeXMMreg( t1reg ); + return; + } + }*/ + //vuFloatExtra(regd, XYZW); + vFloats1[XYZW](regd, regd); + } +} + +// Clamps +/-NaN to +fMax and +/-Inf to +/-fMax (uses EAX as a temp register; faster but **destroys EAX**) +void vuFloat_useEAX( int info, int regd, int XYZW) { + if( CHECK_VU_OVERFLOW ) { + vFloats1_useEAX[XYZW](regd, regd); + } +} + +// Clamps +/-NaN to +fMax and +/-Inf to +/-fMax (uses a temp reg) +void vuFloat2(int regd, int regTemp, int XYZW) { + if( CHECK_VU_OVERFLOW ) { + //vuFloatExtra(regd, XYZW); + vFloats2[XYZW](regd, regTemp); + } +} + +// Clamps +/-NaN and +/-Inf to +/-fMax (uses a temp reg) +void vuFloat4(int regd, int regTemp, int XYZW) { + if( CHECK_VU_OVERFLOW ) { + vFloats4[XYZW](regd, regTemp); + } +} + +// Clamps +/-NaN and +/-Inf to +/-fMax (uses a temp reg, and uses EAX as a temp register; faster but **destroys EAX**) +void vuFloat4_useEAX(int regd, int regTemp, int XYZW) { + if( CHECK_VU_OVERFLOW ) { + vFloats4_useEAX[XYZW](regd, regTemp); + } +} + +// Uses vuFloat4 or vuFloat2 depending on the CHECK_VU_SIGN_OVERFLOW setting +void vuFloat5(int regd, int regTemp, int XYZW) { + if (CHECK_VU_SIGN_OVERFLOW) { + vuFloat4(regd, regTemp, XYZW); + } + else vuFloat2(regd, regTemp, XYZW); +} + +// Uses vuFloat4_useEAX or vuFloat2 depending on the CHECK_VU_SIGN_OVERFLOW setting (uses EAX as a temp register; faster but **destoroyes EAX**) +void vuFloat5_useEAX(int regd, int regTemp, int XYZW) { + if (CHECK_VU_SIGN_OVERFLOW) { + vuFloat4_useEAX(regd, regTemp, XYZW); + } + else vuFloat2(regd, regTemp, XYZW); +} + +// Clamps +/-infs to +/-fMax, and +/-NaNs to +/-fMax +void vuFloat3(uptr x86ptr) { + u8* pjmp; + + if( CHECK_VU_OVERFLOW ) { + CMP32ItoM(x86ptr, 0x7f800000 ); + pjmp = JL8(0); // Signed Comparison + MOV32ItoM(x86ptr, 0x7f7fffff ); + x86SetJ8(pjmp); + + CMP32ItoM(x86ptr, 0xff800000 ); + pjmp = JB8(0); // Unsigned Comparison + MOV32ItoM(x86ptr, 0xff7fffff ); + x86SetJ8(pjmp); + } +} + +PCSX2_ALIGNED16(u64 vuFloatData[2]); +PCSX2_ALIGNED16(u64 vuFloatData2[2]); +// Makes NaN == 0, Infinities stay the same; Very Slow - Use only for debugging +void vuFloatExtra( int regd, int XYZW) { + int t1reg = (regd == 0) ? (regd + 1) : (regd - 1); + int t2reg = (regd <= 1) ? (regd + 2) : (regd - 2); + SSE_MOVAPS_XMM_to_M128( (uptr)vuFloatData, t1reg ); + SSE_MOVAPS_XMM_to_M128( (uptr)vuFloatData2, t2reg ); + + SSE_XORPS_XMM_to_XMM(t1reg, t1reg); + SSE_CMPORDPS_XMM_to_XMM(t1reg, regd); + SSE_MOVAPS_XMM_to_XMM(t2reg, regd); + SSE_ANDPS_XMM_to_XMM(t2reg, t1reg); + VU_MERGE_REGS_CUSTOM(regd, t2reg, XYZW); + + SSE_MOVAPS_M128_to_XMM( t1reg, (uptr)vuFloatData ); + SSE_MOVAPS_M128_to_XMM( t2reg, (uptr)vuFloatData2 ); +} + +static PCSX2_ALIGNED16(u32 tempRegX[]) = {0x00000000, 0x00000000, 0x00000000, 0x00000000}; + +// Called by testWhenOverflow() function +void testPrintOverflow() { + tempRegX[0] &= 0xff800000; + tempRegX[1] &= 0xff800000; + tempRegX[2] &= 0xff800000; + tempRegX[3] &= 0xff800000; + if ( (tempRegX[0] == 0x7f800000) || (tempRegX[1] == 0x7f800000) || (tempRegX[2] == 0x7f800000) || (tempRegX[3] == 0x7f800000) ) + SysPrintf( "VU OVERFLOW!: Changing to +Fmax!!!!!!!!!!!!\n" ); + if ( (tempRegX[0] == 0xff800000) || (tempRegX[1] == 0xff800000) || (tempRegX[2] == 0xff800000) || (tempRegX[3] == 0xff800000) ) + SysPrintf( "VU OVERFLOW!: Changing to -Fmax!!!!!!!!!!!!\n" ); +} + +// Outputs to the console when overflow has occured. +void testWhenOverflow(int info, int regd, int t0reg) { + SSE_MOVAPS_XMM_to_M128((uptr)tempRegX, regd); + CALLFunc((uptr)testPrintOverflow); +} + +// Sets NaN Mode, used by Patches (currently does nothing) +void SetVUNanMode(int mode) +{ + g_VuNanHandling = mode; + if ( mode ) SysPrintf("enabling vunan mode"); } \ No newline at end of file diff --git a/pcsx2/x86/iVUmicro.h b/pcsx2/x86/iVUmicro.h index 44cee593b7..92ce5453aa 100644 --- a/pcsx2/x86/iVUmicro.h +++ b/pcsx2/x86/iVUmicro.h @@ -1,289 +1,289 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2003 Pcsx2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __IVUMICRO_H__ -#define __IVUMICRO_H__ - -#include "VUmicro.h" - -extern u32 vudump; - -#define VU0_MEMSIZE 0x1000 -#define VU1_MEMSIZE 0x4000 - -void recResetVU0(); -void recExecuteVU0Block(); -void recClearVU0( u32 Addr, u32 Size ); - -void recVU1Init(); -void recVU1Shutdown(); -void recResetVU1(); -void recExecuteVU1Block(); -void recClearVU1( u32 Addr, u32 Size ); - - -u32 GetVIAddr(VURegs * VU, int reg, int read, int info); // returns the correct VI addr -void recUpdateFlags(VURegs * VU, int reg, int info); - -void _recvuTestPipes(VURegs * VU); -void _recvuFlushFDIV(VURegs * VU); -void _recvuTestUpperStalls(VURegs * VU, _VURegsNum *VUregsn); -void _recvuTestLowerStalls(VURegs * VU, _VURegsNum *VUregsn); -void _recvuAddUpperStalls(VURegs * VU, _VURegsNum *VUregsn); -void _recvuAddLowerStalls(VURegs * VU, _VURegsNum *VUregsn); - -#define VUOP_READ 2 -#define VUOP_WRITE 4 - -// save on mem -struct _vuopinfo { - int cycle; - int cycles; - u8 statusflag; - u8 macflag; - u8 clipflag; - u8 dummy; - u8 q; - u8 p; - u16 pqinst; // bit of instruction specifying index (srec only) -}; - -void SuperVUAnalyzeOp(VURegs *VU, _vuopinfo *info, _VURegsNum* pCodeRegs); -int eeVURecompileCode(VURegs *VU, _VURegsNum* regs); // allocates all the necessary regs and returns the indices -void VU1XGKICK_MTGSTransfer(u32 *pMem, u32 addr); // used for MTGS in XGKICK - -extern int vucycle; -typedef void (*vFloat)(int regd, int regTemp); -extern vFloat vFloats1[16]; -extern vFloat vFloats1_useEAX[16]; -extern vFloat vFloats2[16]; -extern vFloat vFloats2_MUL_MADD[16]; -extern vFloat vFloats4[16]; -extern vFloat vFloats4_useEAX[16]; -extern PCSX2_ALIGNED16(float s_fones[8]); -extern PCSX2_ALIGNED16(u32 s_mask[4]); -extern PCSX2_ALIGNED16(u32 s_expmask[4]); -extern PCSX2_ALIGNED16(u32 g_minvals[4]); -extern PCSX2_ALIGNED16(u32 g_maxvals[4]); -extern PCSX2_ALIGNED16(u32 const_clip[8]); - -u32 GetVIAddr(VURegs * VU, int reg, int read, int info); -int _vuGetTempXMMreg(int info); -void vuFloat(int info, int regd, int XYZW); -void vuFloat_useEAX(int regd, int regTemp, int XYZW); -void vuFloat2(int regd, int regTemp, int XYZW); -void vuFloat3(uptr x86ptr); -void vuFloat4(int regd, int regTemp, int XYZW); -void vuFloat4_useEAX(int regd, int regTemp, int XYZW); -void vuFloat5(int regd, int regTemp, int XYZW); -void vuFloat5_useEAX(int regd, int regTemp, int XYZW); -void _vuFlipRegSS(VURegs * VU, int reg); -void _vuFlipRegSS_xyzw(int reg, int xyzw); -void _vuMoveSS(VURegs * VU, int dstreg, int srcreg); -void _unpackVF_xyzw(int dstreg, int srcreg, int xyzw); -void _unpackVFSS_xyzw(int dstreg, int srcreg, int xyzw); -void VU_MERGE_REGS_CUSTOM(int dest, int src, int xyzw); -void VU_MERGE_REGS_SAFE(int dest, int src, int xyzw); -#define VU_MERGE_REGS(dest, src) { \ - VU_MERGE_REGS_CUSTOM(dest, src, _X_Y_Z_W); \ -} - -// use for allocating vi regs -#define ALLOCTEMPX86(mode) _allocX86reg(-1, X86TYPE_TEMP, 0, ((info&PROCESS_VU_SUPER)?0:MODE_NOFRAME)|mode) -#define ALLOCVI(vi, mode) _allocX86reg(-1, X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), vi, ((info&PROCESS_VU_SUPER)?0:MODE_NOFRAME)|mode) -#define ADD_VI_NEEDED(vi) _addNeededX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), vi); - -#define SWAP(x, y) *(u32*)&y ^= *(u32*)&x ^= *(u32*)&y ^= *(u32*)&x; - -/***************************************** - VU Micromode Upper instructions -*****************************************/ - -void recVUMI_ABS(VURegs *vuRegs, int info); -void recVUMI_ADD(VURegs *vuRegs, int info); -void recVUMI_ADDi(VURegs *vuRegs, int info); -void recVUMI_ADDq(VURegs *vuRegs, int info); -void recVUMI_ADDx(VURegs *vuRegs, int info); -void recVUMI_ADDy(VURegs *vuRegs, int info); -void recVUMI_ADDz(VURegs *vuRegs, int info); -void recVUMI_ADDw(VURegs *vuRegs, int info); -void recVUMI_ADDA(VURegs *vuRegs, int info); -void recVUMI_ADDAi(VURegs *vuRegs, int info); -void recVUMI_ADDAq(VURegs *vuRegs, int info); -void recVUMI_ADDAx(VURegs *vuRegs, int info); -void recVUMI_ADDAy(VURegs *vuRegs, int info); -void recVUMI_ADDAz(VURegs *vuRegs, int info); -void recVUMI_ADDAw(VURegs *vuRegs, int info); -void recVUMI_SUB(VURegs *vuRegs, int info); -void recVUMI_SUBi(VURegs *vuRegs, int info); -void recVUMI_SUBq(VURegs *vuRegs, int info); -void recVUMI_SUBx(VURegs *vuRegs, int info); -void recVUMI_SUBy(VURegs *vuRegs, int info); -void recVUMI_SUBz(VURegs *vuRegs, int info); -void recVUMI_SUBw(VURegs *vuRegs, int info); -void recVUMI_SUBA(VURegs *vuRegs, int info); -void recVUMI_SUBAi(VURegs *vuRegs, int info); -void recVUMI_SUBAq(VURegs *vuRegs, int info); -void recVUMI_SUBAx(VURegs *vuRegs, int info); -void recVUMI_SUBAy(VURegs *vuRegs, int info); -void recVUMI_SUBAz(VURegs *vuRegs, int info); -void recVUMI_SUBAw(VURegs *vuRegs, int info); -void recVUMI_MUL(VURegs *vuRegs, int info); -void recVUMI_MULi(VURegs *vuRegs, int info); -void recVUMI_MULq(VURegs *vuRegs, int info); -void recVUMI_MULx(VURegs *vuRegs, int info); -void recVUMI_MULy(VURegs *vuRegs, int info); -void recVUMI_MULz(VURegs *vuRegs, int info); -void recVUMI_MULw(VURegs *vuRegs, int info); -void recVUMI_MULA(VURegs *vuRegs, int info); -void recVUMI_MULAi(VURegs *vuRegs, int info); -void recVUMI_MULAq(VURegs *vuRegs, int info); -void recVUMI_MULAx(VURegs *vuRegs, int info); -void recVUMI_MULAy(VURegs *vuRegs, int info); -void recVUMI_MULAz(VURegs *vuRegs, int info); -void recVUMI_MULAw(VURegs *vuRegs, int info); -void recVUMI_MADD(VURegs *vuRegs, int info); -void recVUMI_MADDi(VURegs *vuRegs, int info); -void recVUMI_MADDq(VURegs *vuRegs, int info); -void recVUMI_MADDx(VURegs *vuRegs, int info); -void recVUMI_MADDy(VURegs *vuRegs, int info); -void recVUMI_MADDz(VURegs *vuRegs, int info); -void recVUMI_MADDw(VURegs *vuRegs, int info); -void recVUMI_MADDA(VURegs *vuRegs, int info); -void recVUMI_MADDAi(VURegs *vuRegs, int info); -void recVUMI_MADDAq(VURegs *vuRegs, int info); -void recVUMI_MADDAx(VURegs *vuRegs, int info); -void recVUMI_MADDAy(VURegs *vuRegs, int info); -void recVUMI_MADDAz(VURegs *vuRegs, int info); -void recVUMI_MADDAw(VURegs *vuRegs, int info); -void recVUMI_MSUB(VURegs *vuRegs, int info); -void recVUMI_MSUBi(VURegs *vuRegs, int info); -void recVUMI_MSUBq(VURegs *vuRegs, int info); -void recVUMI_MSUBx(VURegs *vuRegs, int info); -void recVUMI_MSUBy(VURegs *vuRegs, int info); -void recVUMI_MSUBz(VURegs *vuRegs, int info); -void recVUMI_MSUBw(VURegs *vuRegs, int info); -void recVUMI_MSUBA(VURegs *vuRegs, int info); -void recVUMI_MSUBAi(VURegs *vuRegs, int info); -void recVUMI_MSUBAq(VURegs *vuRegs, int info); -void recVUMI_MSUBAx(VURegs *vuRegs, int info); -void recVUMI_MSUBAy(VURegs *vuRegs, int info); -void recVUMI_MSUBAz(VURegs *vuRegs, int info); -void recVUMI_MSUBAw(VURegs *vuRegs, int info); -void recVUMI_MAX(VURegs *vuRegs, int info); -void recVUMI_MAXi(VURegs *vuRegs, int info); -void recVUMI_MAXx(VURegs *vuRegs, int info); -void recVUMI_MAXy(VURegs *vuRegs, int info); -void recVUMI_MAXz(VURegs *vuRegs, int info); -void recVUMI_MAXw(VURegs *vuRegs, int info); -void recVUMI_MINI(VURegs *vuRegs, int info); -void recVUMI_MINIi(VURegs *vuRegs, int info); -void recVUMI_MINIx(VURegs *vuRegs, int info); -void recVUMI_MINIy(VURegs *vuRegs, int info); -void recVUMI_MINIz(VURegs *vuRegs, int info); -void recVUMI_MINIw(VURegs *vuRegs, int info); -void recVUMI_OPMULA(VURegs *vuRegs, int info); -void recVUMI_OPMSUB(VURegs *vuRegs, int info); -void recVUMI_NOP(VURegs *vuRegs, int info); -void recVUMI_FTOI0(VURegs *vuRegs, int info); -void recVUMI_FTOI4(VURegs *vuRegs, int info); -void recVUMI_FTOI12(VURegs *vuRegs, int info); -void recVUMI_FTOI15(VURegs *vuRegs, int info); -void recVUMI_ITOF0(VURegs *vuRegs, int info); -void recVUMI_ITOF4(VURegs *vuRegs, int info); -void recVUMI_ITOF12(VURegs *vuRegs, int info); -void recVUMI_ITOF15(VURegs *vuRegs, int info); -void recVUMI_CLIP(VURegs *vuRegs, int info); - -/***************************************** - VU Micromode Lower instructions -*****************************************/ - -void recVUMI_DIV(VURegs *vuRegs, int info); -void recVUMI_SQRT(VURegs *vuRegs, int info); -void recVUMI_RSQRT(VURegs *vuRegs, int info); -void recVUMI_IADD(VURegs *vuRegs, int info); -void recVUMI_IADDI(VURegs *vuRegs, int info); -void recVUMI_IADDIU(VURegs *vuRegs, int info); -void recVUMI_IAND(VURegs *vuRegs, int info); -void recVUMI_IOR(VURegs *vuRegs, int info); -void recVUMI_ISUB(VURegs *vuRegs, int info); -void recVUMI_ISUBIU(VURegs *vuRegs, int info); -void recVUMI_MOVE(VURegs *vuRegs, int info); -void recVUMI_MFIR(VURegs *vuRegs, int info); -void recVUMI_MTIR(VURegs *vuRegs, int info); -void recVUMI_MR32(VURegs *vuRegs, int info); -void recVUMI_LQ(VURegs *vuRegs, int info); -void recVUMI_LQD(VURegs *vuRegs, int info); -void recVUMI_LQI(VURegs *vuRegs, int info); -void recVUMI_SQ(VURegs *vuRegs, int info); -void recVUMI_SQD(VURegs *vuRegs, int info); -void recVUMI_SQI(VURegs *vuRegs, int info); -void recVUMI_ILW(VURegs *vuRegs, int info); -void recVUMI_ISW(VURegs *vuRegs, int info); -void recVUMI_ILWR(VURegs *vuRegs, int info); -void recVUMI_ISWR(VURegs *vuRegs, int info); -void recVUMI_LOI(VURegs *vuRegs, int info); -void recVUMI_RINIT(VURegs *vuRegs, int info); -void recVUMI_RGET(VURegs *vuRegs, int info); -void recVUMI_RNEXT(VURegs *vuRegs, int info); -void recVUMI_RXOR(VURegs *vuRegs, int info); -void recVUMI_WAITQ(VURegs *vuRegs, int info); -void recVUMI_FSAND(VURegs *vuRegs, int info); -void recVUMI_FSEQ(VURegs *vuRegs, int info); -void recVUMI_FSOR(VURegs *vuRegs, int info); -void recVUMI_FSSET(VURegs *vuRegs, int info); -void recVUMI_FMAND(VURegs *vuRegs, int info); -void recVUMI_FMEQ(VURegs *vuRegs, int info); -void recVUMI_FMOR(VURegs *vuRegs, int info); -void recVUMI_FCAND(VURegs *vuRegs, int info); -void recVUMI_FCEQ(VURegs *vuRegs, int info); -void recVUMI_FCOR(VURegs *vuRegs, int info); -void recVUMI_FCSET(VURegs *vuRegs, int info); -void recVUMI_FCGET(VURegs *vuRegs, int info); -void recVUMI_IBEQ(VURegs *vuRegs, int info); -void recVUMI_IBGEZ(VURegs *vuRegs, int info); -void recVUMI_IBGTZ(VURegs *vuRegs, int info); -void recVUMI_IBLTZ(VURegs *vuRegs, int info); -void recVUMI_IBLEZ(VURegs *vuRegs, int info); -void recVUMI_IBNE(VURegs *vuRegs, int info); -void recVUMI_B(VURegs *vuRegs, int info); -void recVUMI_BAL(VURegs *vuRegs, int info); -void recVUMI_JR(VURegs *vuRegs, int info); -void recVUMI_JALR(VURegs *vuRegs, int info); -void recVUMI_MFP(VURegs *vuRegs, int info); -void recVUMI_WAITP(VURegs *vuRegs, int info); -void recVUMI_ESADD(VURegs *vuRegs, int info); -void recVUMI_ERSADD(VURegs *vuRegs, int info); -void recVUMI_ELENG(VURegs *vuRegs, int info); -void recVUMI_ERLENG(VURegs *vuRegs, int info); -void recVUMI_EATANxy(VURegs *vuRegs, int info); -void recVUMI_EATANxz(VURegs *vuRegs, int info); -void recVUMI_ESUM(VURegs *vuRegs, int info); -void recVUMI_ERCPR(VURegs *vuRegs, int info); -void recVUMI_ESQRT(VURegs *vuRegs, int info); -void recVUMI_ERSQRT(VURegs *vuRegs, int info); -void recVUMI_ESIN(VURegs *vuRegs, int info); -void recVUMI_EATAN(VURegs *vuRegs, int info); -void recVUMI_EEXP(VURegs *vuRegs, int info); -void recVUMI_XGKICK(VURegs *vuRegs, int info); -void recVUMI_XTOP(VURegs *vuRegs, int info); -void recVUMI_XITOP(VURegs *vuRegs, int info); -void recVUMI_XTOP( VURegs *VU , int info); - -#endif /* __IVUMICRO_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2003 Pcsx2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __IVUMICRO_H__ +#define __IVUMICRO_H__ + +#include "VUmicro.h" + +extern u32 vudump; + +#define VU0_MEMSIZE 0x1000 +#define VU1_MEMSIZE 0x4000 + +void recResetVU0(); +void recExecuteVU0Block(); +void recClearVU0( u32 Addr, u32 Size ); + +void recVU1Init(); +void recVU1Shutdown(); +void recResetVU1(); +void recExecuteVU1Block(); +void recClearVU1( u32 Addr, u32 Size ); + + +u32 GetVIAddr(VURegs * VU, int reg, int read, int info); // returns the correct VI addr +void recUpdateFlags(VURegs * VU, int reg, int info); + +void _recvuTestPipes(VURegs * VU); +void _recvuFlushFDIV(VURegs * VU); +void _recvuTestUpperStalls(VURegs * VU, _VURegsNum *VUregsn); +void _recvuTestLowerStalls(VURegs * VU, _VURegsNum *VUregsn); +void _recvuAddUpperStalls(VURegs * VU, _VURegsNum *VUregsn); +void _recvuAddLowerStalls(VURegs * VU, _VURegsNum *VUregsn); + +#define VUOP_READ 2 +#define VUOP_WRITE 4 + +// save on mem +struct _vuopinfo { + int cycle; + int cycles; + u8 statusflag; + u8 macflag; + u8 clipflag; + u8 dummy; + u8 q; + u8 p; + u16 pqinst; // bit of instruction specifying index (srec only) +}; + +void SuperVUAnalyzeOp(VURegs *VU, _vuopinfo *info, _VURegsNum* pCodeRegs); +int eeVURecompileCode(VURegs *VU, _VURegsNum* regs); // allocates all the necessary regs and returns the indices +void VU1XGKICK_MTGSTransfer(u32 *pMem, u32 addr); // used for MTGS in XGKICK + +extern int vucycle; +typedef void (*vFloat)(int regd, int regTemp); +extern vFloat vFloats1[16]; +extern vFloat vFloats1_useEAX[16]; +extern vFloat vFloats2[16]; +extern vFloat vFloats2_MUL_MADD[16]; +extern vFloat vFloats4[16]; +extern vFloat vFloats4_useEAX[16]; +extern PCSX2_ALIGNED16(float s_fones[8]); +extern PCSX2_ALIGNED16(u32 s_mask[4]); +extern PCSX2_ALIGNED16(u32 s_expmask[4]); +extern PCSX2_ALIGNED16(u32 g_minvals[4]); +extern PCSX2_ALIGNED16(u32 g_maxvals[4]); +extern PCSX2_ALIGNED16(u32 const_clip[8]); + +u32 GetVIAddr(VURegs * VU, int reg, int read, int info); +int _vuGetTempXMMreg(int info); +void vuFloat(int info, int regd, int XYZW); +void vuFloat_useEAX(int regd, int regTemp, int XYZW); +void vuFloat2(int regd, int regTemp, int XYZW); +void vuFloat3(uptr x86ptr); +void vuFloat4(int regd, int regTemp, int XYZW); +void vuFloat4_useEAX(int regd, int regTemp, int XYZW); +void vuFloat5(int regd, int regTemp, int XYZW); +void vuFloat5_useEAX(int regd, int regTemp, int XYZW); +void _vuFlipRegSS(VURegs * VU, int reg); +void _vuFlipRegSS_xyzw(int reg, int xyzw); +void _vuMoveSS(VURegs * VU, int dstreg, int srcreg); +void _unpackVF_xyzw(int dstreg, int srcreg, int xyzw); +void _unpackVFSS_xyzw(int dstreg, int srcreg, int xyzw); +void VU_MERGE_REGS_CUSTOM(int dest, int src, int xyzw); +void VU_MERGE_REGS_SAFE(int dest, int src, int xyzw); +#define VU_MERGE_REGS(dest, src) { \ + VU_MERGE_REGS_CUSTOM(dest, src, _X_Y_Z_W); \ +} + +// use for allocating vi regs +#define ALLOCTEMPX86(mode) _allocX86reg(-1, X86TYPE_TEMP, 0, ((info&PROCESS_VU_SUPER)?0:MODE_NOFRAME)|mode) +#define ALLOCVI(vi, mode) _allocX86reg(-1, X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), vi, ((info&PROCESS_VU_SUPER)?0:MODE_NOFRAME)|mode) +#define ADD_VI_NEEDED(vi) _addNeededX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), vi); + +#define SWAP(x, y) *(u32*)&y ^= *(u32*)&x ^= *(u32*)&y ^= *(u32*)&x; + +/***************************************** + VU Micromode Upper instructions +*****************************************/ + +void recVUMI_ABS(VURegs *vuRegs, int info); +void recVUMI_ADD(VURegs *vuRegs, int info); +void recVUMI_ADDi(VURegs *vuRegs, int info); +void recVUMI_ADDq(VURegs *vuRegs, int info); +void recVUMI_ADDx(VURegs *vuRegs, int info); +void recVUMI_ADDy(VURegs *vuRegs, int info); +void recVUMI_ADDz(VURegs *vuRegs, int info); +void recVUMI_ADDw(VURegs *vuRegs, int info); +void recVUMI_ADDA(VURegs *vuRegs, int info); +void recVUMI_ADDAi(VURegs *vuRegs, int info); +void recVUMI_ADDAq(VURegs *vuRegs, int info); +void recVUMI_ADDAx(VURegs *vuRegs, int info); +void recVUMI_ADDAy(VURegs *vuRegs, int info); +void recVUMI_ADDAz(VURegs *vuRegs, int info); +void recVUMI_ADDAw(VURegs *vuRegs, int info); +void recVUMI_SUB(VURegs *vuRegs, int info); +void recVUMI_SUBi(VURegs *vuRegs, int info); +void recVUMI_SUBq(VURegs *vuRegs, int info); +void recVUMI_SUBx(VURegs *vuRegs, int info); +void recVUMI_SUBy(VURegs *vuRegs, int info); +void recVUMI_SUBz(VURegs *vuRegs, int info); +void recVUMI_SUBw(VURegs *vuRegs, int info); +void recVUMI_SUBA(VURegs *vuRegs, int info); +void recVUMI_SUBAi(VURegs *vuRegs, int info); +void recVUMI_SUBAq(VURegs *vuRegs, int info); +void recVUMI_SUBAx(VURegs *vuRegs, int info); +void recVUMI_SUBAy(VURegs *vuRegs, int info); +void recVUMI_SUBAz(VURegs *vuRegs, int info); +void recVUMI_SUBAw(VURegs *vuRegs, int info); +void recVUMI_MUL(VURegs *vuRegs, int info); +void recVUMI_MULi(VURegs *vuRegs, int info); +void recVUMI_MULq(VURegs *vuRegs, int info); +void recVUMI_MULx(VURegs *vuRegs, int info); +void recVUMI_MULy(VURegs *vuRegs, int info); +void recVUMI_MULz(VURegs *vuRegs, int info); +void recVUMI_MULw(VURegs *vuRegs, int info); +void recVUMI_MULA(VURegs *vuRegs, int info); +void recVUMI_MULAi(VURegs *vuRegs, int info); +void recVUMI_MULAq(VURegs *vuRegs, int info); +void recVUMI_MULAx(VURegs *vuRegs, int info); +void recVUMI_MULAy(VURegs *vuRegs, int info); +void recVUMI_MULAz(VURegs *vuRegs, int info); +void recVUMI_MULAw(VURegs *vuRegs, int info); +void recVUMI_MADD(VURegs *vuRegs, int info); +void recVUMI_MADDi(VURegs *vuRegs, int info); +void recVUMI_MADDq(VURegs *vuRegs, int info); +void recVUMI_MADDx(VURegs *vuRegs, int info); +void recVUMI_MADDy(VURegs *vuRegs, int info); +void recVUMI_MADDz(VURegs *vuRegs, int info); +void recVUMI_MADDw(VURegs *vuRegs, int info); +void recVUMI_MADDA(VURegs *vuRegs, int info); +void recVUMI_MADDAi(VURegs *vuRegs, int info); +void recVUMI_MADDAq(VURegs *vuRegs, int info); +void recVUMI_MADDAx(VURegs *vuRegs, int info); +void recVUMI_MADDAy(VURegs *vuRegs, int info); +void recVUMI_MADDAz(VURegs *vuRegs, int info); +void recVUMI_MADDAw(VURegs *vuRegs, int info); +void recVUMI_MSUB(VURegs *vuRegs, int info); +void recVUMI_MSUBi(VURegs *vuRegs, int info); +void recVUMI_MSUBq(VURegs *vuRegs, int info); +void recVUMI_MSUBx(VURegs *vuRegs, int info); +void recVUMI_MSUBy(VURegs *vuRegs, int info); +void recVUMI_MSUBz(VURegs *vuRegs, int info); +void recVUMI_MSUBw(VURegs *vuRegs, int info); +void recVUMI_MSUBA(VURegs *vuRegs, int info); +void recVUMI_MSUBAi(VURegs *vuRegs, int info); +void recVUMI_MSUBAq(VURegs *vuRegs, int info); +void recVUMI_MSUBAx(VURegs *vuRegs, int info); +void recVUMI_MSUBAy(VURegs *vuRegs, int info); +void recVUMI_MSUBAz(VURegs *vuRegs, int info); +void recVUMI_MSUBAw(VURegs *vuRegs, int info); +void recVUMI_MAX(VURegs *vuRegs, int info); +void recVUMI_MAXi(VURegs *vuRegs, int info); +void recVUMI_MAXx(VURegs *vuRegs, int info); +void recVUMI_MAXy(VURegs *vuRegs, int info); +void recVUMI_MAXz(VURegs *vuRegs, int info); +void recVUMI_MAXw(VURegs *vuRegs, int info); +void recVUMI_MINI(VURegs *vuRegs, int info); +void recVUMI_MINIi(VURegs *vuRegs, int info); +void recVUMI_MINIx(VURegs *vuRegs, int info); +void recVUMI_MINIy(VURegs *vuRegs, int info); +void recVUMI_MINIz(VURegs *vuRegs, int info); +void recVUMI_MINIw(VURegs *vuRegs, int info); +void recVUMI_OPMULA(VURegs *vuRegs, int info); +void recVUMI_OPMSUB(VURegs *vuRegs, int info); +void recVUMI_NOP(VURegs *vuRegs, int info); +void recVUMI_FTOI0(VURegs *vuRegs, int info); +void recVUMI_FTOI4(VURegs *vuRegs, int info); +void recVUMI_FTOI12(VURegs *vuRegs, int info); +void recVUMI_FTOI15(VURegs *vuRegs, int info); +void recVUMI_ITOF0(VURegs *vuRegs, int info); +void recVUMI_ITOF4(VURegs *vuRegs, int info); +void recVUMI_ITOF12(VURegs *vuRegs, int info); +void recVUMI_ITOF15(VURegs *vuRegs, int info); +void recVUMI_CLIP(VURegs *vuRegs, int info); + +/***************************************** + VU Micromode Lower instructions +*****************************************/ + +void recVUMI_DIV(VURegs *vuRegs, int info); +void recVUMI_SQRT(VURegs *vuRegs, int info); +void recVUMI_RSQRT(VURegs *vuRegs, int info); +void recVUMI_IADD(VURegs *vuRegs, int info); +void recVUMI_IADDI(VURegs *vuRegs, int info); +void recVUMI_IADDIU(VURegs *vuRegs, int info); +void recVUMI_IAND(VURegs *vuRegs, int info); +void recVUMI_IOR(VURegs *vuRegs, int info); +void recVUMI_ISUB(VURegs *vuRegs, int info); +void recVUMI_ISUBIU(VURegs *vuRegs, int info); +void recVUMI_MOVE(VURegs *vuRegs, int info); +void recVUMI_MFIR(VURegs *vuRegs, int info); +void recVUMI_MTIR(VURegs *vuRegs, int info); +void recVUMI_MR32(VURegs *vuRegs, int info); +void recVUMI_LQ(VURegs *vuRegs, int info); +void recVUMI_LQD(VURegs *vuRegs, int info); +void recVUMI_LQI(VURegs *vuRegs, int info); +void recVUMI_SQ(VURegs *vuRegs, int info); +void recVUMI_SQD(VURegs *vuRegs, int info); +void recVUMI_SQI(VURegs *vuRegs, int info); +void recVUMI_ILW(VURegs *vuRegs, int info); +void recVUMI_ISW(VURegs *vuRegs, int info); +void recVUMI_ILWR(VURegs *vuRegs, int info); +void recVUMI_ISWR(VURegs *vuRegs, int info); +void recVUMI_LOI(VURegs *vuRegs, int info); +void recVUMI_RINIT(VURegs *vuRegs, int info); +void recVUMI_RGET(VURegs *vuRegs, int info); +void recVUMI_RNEXT(VURegs *vuRegs, int info); +void recVUMI_RXOR(VURegs *vuRegs, int info); +void recVUMI_WAITQ(VURegs *vuRegs, int info); +void recVUMI_FSAND(VURegs *vuRegs, int info); +void recVUMI_FSEQ(VURegs *vuRegs, int info); +void recVUMI_FSOR(VURegs *vuRegs, int info); +void recVUMI_FSSET(VURegs *vuRegs, int info); +void recVUMI_FMAND(VURegs *vuRegs, int info); +void recVUMI_FMEQ(VURegs *vuRegs, int info); +void recVUMI_FMOR(VURegs *vuRegs, int info); +void recVUMI_FCAND(VURegs *vuRegs, int info); +void recVUMI_FCEQ(VURegs *vuRegs, int info); +void recVUMI_FCOR(VURegs *vuRegs, int info); +void recVUMI_FCSET(VURegs *vuRegs, int info); +void recVUMI_FCGET(VURegs *vuRegs, int info); +void recVUMI_IBEQ(VURegs *vuRegs, int info); +void recVUMI_IBGEZ(VURegs *vuRegs, int info); +void recVUMI_IBGTZ(VURegs *vuRegs, int info); +void recVUMI_IBLTZ(VURegs *vuRegs, int info); +void recVUMI_IBLEZ(VURegs *vuRegs, int info); +void recVUMI_IBNE(VURegs *vuRegs, int info); +void recVUMI_B(VURegs *vuRegs, int info); +void recVUMI_BAL(VURegs *vuRegs, int info); +void recVUMI_JR(VURegs *vuRegs, int info); +void recVUMI_JALR(VURegs *vuRegs, int info); +void recVUMI_MFP(VURegs *vuRegs, int info); +void recVUMI_WAITP(VURegs *vuRegs, int info); +void recVUMI_ESADD(VURegs *vuRegs, int info); +void recVUMI_ERSADD(VURegs *vuRegs, int info); +void recVUMI_ELENG(VURegs *vuRegs, int info); +void recVUMI_ERLENG(VURegs *vuRegs, int info); +void recVUMI_EATANxy(VURegs *vuRegs, int info); +void recVUMI_EATANxz(VURegs *vuRegs, int info); +void recVUMI_ESUM(VURegs *vuRegs, int info); +void recVUMI_ERCPR(VURegs *vuRegs, int info); +void recVUMI_ESQRT(VURegs *vuRegs, int info); +void recVUMI_ERSQRT(VURegs *vuRegs, int info); +void recVUMI_ESIN(VURegs *vuRegs, int info); +void recVUMI_EATAN(VURegs *vuRegs, int info); +void recVUMI_EEXP(VURegs *vuRegs, int info); +void recVUMI_XGKICK(VURegs *vuRegs, int info); +void recVUMI_XTOP(VURegs *vuRegs, int info); +void recVUMI_XITOP(VURegs *vuRegs, int info); +void recVUMI_XTOP( VURegs *VU , int info); + +#endif /* __IVUMICRO_H__ */ diff --git a/pcsx2/x86/iVUmicroLower.cpp b/pcsx2/x86/iVUmicroLower.cpp index 673163da0e..72df7bdebd 100644 --- a/pcsx2/x86/iVUmicroLower.cpp +++ b/pcsx2/x86/iVUmicroLower.cpp @@ -1,1988 +1,1988 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "PrecompiledHeader.h" - -#include "Common.h" -#include "GS.h" -#include "R5900OpcodeTables.h" -#include "ix86/ix86.h" -#include "iR5900.h" -#include "iMMI.h" -#include "iFPU.h" -#include "iCOP0.h" -#include "VUmicro.h" -#include "VUflags.h" -#include "iVUmicro.h" -#include "iVUops.h" -#include "iVUzerorec.h" -//------------------------------------------------------------------ - -//------------------------------------------------------------------ -// Helper Macros -//------------------------------------------------------------------ -#define _Ft_ (( VU->code >> 16) & 0x1F) // The rt part of the instruction register -#define _Fs_ (( VU->code >> 11) & 0x1F) // The rd part of the instruction register -#define _Fd_ (( VU->code >> 6) & 0x1F) // The sa part of the instruction register - -#define _X (( VU->code>>24) & 0x1) -#define _Y (( VU->code>>23) & 0x1) -#define _Z (( VU->code>>22) & 0x1) -#define _W (( VU->code>>21) & 0x1) - -#define _XYZW_SS (_X+_Y+_Z+_W==1) - -#define _Fsf_ (( VU->code >> 21) & 0x03) -#define _Ftf_ (( VU->code >> 23) & 0x03) - -#define _Imm11_ (s32)(VU->code & 0x400 ? 0xfffffc00 | (VU->code & 0x3ff) : VU->code & 0x3ff) -#define _UImm11_ (s32)(VU->code & 0x7ff) - -#define VU_VFx_ADDR(x) (uptr)&VU->VF[x].UL[0] -#define VU_VFy_ADDR(x) (uptr)&VU->VF[x].UL[1] -#define VU_VFz_ADDR(x) (uptr)&VU->VF[x].UL[2] -#define VU_VFw_ADDR(x) (uptr)&VU->VF[x].UL[3] - -#define VU_REGR_ADDR (uptr)&VU->VI[REG_R] -#define VU_REGQ_ADDR (uptr)&VU->VI[REG_Q] -#define VU_REGMAC_ADDR (uptr)&VU->VI[REG_MAC_FLAG] - -#define VU_VI_ADDR(x, read) GetVIAddr(VU, x, read, info) - -#define VU_ACCx_ADDR (uptr)&VU->ACC.UL[0] -#define VU_ACCy_ADDR (uptr)&VU->ACC.UL[1] -#define VU_ACCz_ADDR (uptr)&VU->ACC.UL[2] -#define VU_ACCw_ADDR (uptr)&VU->ACC.UL[3] - -#define _X_Y_Z_W ((( VU->code >> 21 ) & 0xF ) ) - - -static const PCSX2_ALIGNED16(u32 VU_ONE[4]) = {0x3f800000, 0xffffffff, 0xffffffff, 0xffffffff}; -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// *VU Lower Instructions!* -// -// Note: * = Checked for errors by cottonvibes -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// DIV* -//------------------------------------------------------------------ -PCSX2_ALIGNED16(u64 DIV_TEMP_XMM[2]); -void recVUMI_DIV(VURegs *VU, int info) -{ - u8 *pjmp, *pjmp1; - u32 *ajmp32, *bjmp32; - - //SysPrintf("recVUMI_DIV()\n"); - AND32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0xFCF); // Clear D/I flags - - // FT can be zero here! so we need to check if its zero and set the correct flag. - SSE_XORPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); // Clear EEREC_TEMP - SSE_CMPEQPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); // Set all F's if each vector is zero - - SSE_MOVMSKPS_XMM_to_R32( EAX, EEREC_TEMP); // Move the sign bits of the previous calculation - - AND32ItoR( EAX, (1<<_Ftf_) ); // Grab "Is Zero" bits from the previous calculation - ajmp32 = JZ32(0); // Skip if none are - - SSE_XORPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); // Clear EEREC_TEMP - SSE_CMPEQPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); // Set all F's if each vector is zero - SSE_MOVMSKPS_XMM_to_R32(EAX, EEREC_TEMP); // Move the sign bits of the previous calculation - - AND32ItoR( EAX, (1<<_Fsf_) ); // Grab "Is Zero" bits from the previous calculation - pjmp = JZ8(0); - OR32ItoM( VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x410 ); // Set invalid flag (0/0) - pjmp1 = JMP8(0); - x86SetJ8(pjmp); - OR32ItoM( VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x820 ); // Zero divide (only when not 0/0) - x86SetJ8(pjmp1); - - _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); - - _vuFlipRegSS_xyzw(EEREC_T, _Ftf_); - SSE_XORPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); - _vuFlipRegSS_xyzw(EEREC_T, _Ftf_); - - SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); - SSE_ORPS_M128_to_XMM(EEREC_TEMP, (uptr)&g_maxvals[0]); // If division by zero, then EEREC_TEMP = +/- fmax - - bjmp32 = JMP32(0); - - x86SetJ32(ajmp32); - - if (CHECK_VU_EXTRA_OVERFLOW) { - vuFloat5_useEAX(EEREC_S, EEREC_TEMP, (1 << (3-_Fsf_))); - vuFloat5_useEAX(EEREC_T, EEREC_TEMP, (1 << (3-_Ftf_))); - } - - _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); - - _vuFlipRegSS_xyzw(EEREC_T, _Ftf_); - SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); - _vuFlipRegSS_xyzw(EEREC_T, _Ftf_); - - vuFloat_useEAX(info, EEREC_TEMP, 0x8); - - x86SetJ32(bjmp32); - - SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_Q, 0), EEREC_TEMP); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// SQRT* -//------------------------------------------------------------------ -void recVUMI_SQRT( VURegs *VU, int info ) -{ - u8* pjmp; - //SysPrintf("recVUMI_SQRT()\n"); - - _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, _Ftf_); - AND32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0xFCF); // Clear D/I flags - - /* Check for negative sqrt */ - SSE_MOVMSKPS_XMM_to_R32(EAX, EEREC_TEMP); - AND32ItoR(EAX, 1); //Check sign - pjmp = JZ8(0); //Skip if none are - OR32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x410); // Invalid Flag - Negative number sqrt - x86SetJ8(pjmp); - - SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)const_clip); // Do a cardinal sqrt - if (CHECK_VU_OVERFLOW) SSE_MINSS_M32_to_XMM(EEREC_TEMP, (uptr)g_maxvals); // Clamp infinities (only need to do positive clamp since EEREC_TEMP is positive) - SSE_SQRTSS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); - SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_Q, 0), EEREC_TEMP); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// RSQRT* -//------------------------------------------------------------------ -PCSX2_ALIGNED16(u64 RSQRT_TEMP_XMM[2]); -void recVUMI_RSQRT(VURegs *VU, int info) -{ - u8 *ajmp8, *bjmp8; - int t1reg, t1boolean; - //SysPrintf("recVUMI_RSQRT()\n"); - - _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, _Ftf_); - AND32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0xFCF); // Clear D/I flags - - /* Check for negative divide */ - SSE_MOVMSKPS_XMM_to_R32(EAX, EEREC_TEMP); - AND32ItoR(EAX, 1); //Check sign - ajmp8 = JZ8(0); //Skip if none are - OR32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x410); // Invalid Flag - Negative number sqrt - x86SetJ8(ajmp8); - - SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)const_clip); // Do a cardinal sqrt - if (CHECK_VU_OVERFLOW) SSE_MINSS_M32_to_XMM(EEREC_TEMP, (uptr)g_maxvals); // Clamp Infinities to Fmax - SSE_SQRTSS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); - - t1reg = _vuGetTempXMMreg(info); - if( t1reg < 0 ) { - for (t1reg = 0; ( (t1reg == EEREC_TEMP) || (t1reg == EEREC_S) ); t1reg++) - ; // Makes t1reg not be EEREC_TEMP or EEREC_S. - SSE_MOVAPS_XMM_to_M128( (uptr)&RSQRT_TEMP_XMM[0], t1reg ); // backup data in t1reg to a temp address - t1boolean = 1; - } - else t1boolean = 0; - - // Ft can still be zero here! so we need to check if its zero and set the correct flag. - SSE_XORPS_XMM_to_XMM(t1reg, t1reg); // Clear t1reg - SSE_CMPEQSS_XMM_to_XMM(t1reg, EEREC_TEMP); // Set all F's if each vector is zero - - SSE_MOVMSKPS_XMM_to_R32(EAX, t1reg); // Move the sign bits of the previous calculation - - AND32ItoR( EAX, 0x01 ); // Grab "Is Zero" bits from the previous calculation - ajmp8 = JZ8(0); // Skip if none are - OR32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x820); // Zero divide flag - - _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); - SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); - SSE_ORPS_M128_to_XMM(EEREC_TEMP, (uptr)&g_maxvals[0]); // EEREC_TEMP = +/-Max - SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_Q, 0), EEREC_TEMP); - bjmp8 = JMP8(0); - x86SetJ8(ajmp8); - - _unpackVFSS_xyzw(t1reg, EEREC_S, _Fsf_); - if (CHECK_VU_EXTRA_OVERFLOW) vuFloat_useEAX(info, t1reg, 0x8); // Clamp Infinities - SSE_DIVSS_XMM_to_XMM(t1reg, EEREC_TEMP); - vuFloat_useEAX(info, t1reg, 0x8); - SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_Q, 0), t1reg); - - x86SetJ8(bjmp8); - - if (t1boolean) SSE_MOVAPS_M128_to_XMM( t1reg, (uptr)&RSQRT_TEMP_XMM[0] ); // restore t1reg data - else _freeXMMreg(t1reg); // free t1reg -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// _addISIMMtoIT() - Used in IADDI, IADDIU, and ISUBIU instructions -//------------------------------------------------------------------ -void _addISIMMtoIT(VURegs *VU, s16 imm, int info) -{ - int fsreg = -1, ftreg; - if (_Ft_ == 0) return; - - if( _Fs_ == 0 ) { - ftreg = ALLOCVI(_Ft_, MODE_WRITE); - MOV32ItoR(ftreg, imm&0xffff); - return; - } - - ADD_VI_NEEDED(_Ft_); - fsreg = ALLOCVI(_Fs_, MODE_READ); - ftreg = ALLOCVI(_Ft_, MODE_WRITE); - - if ( _Ft_ == _Fs_ ) { - if (imm != 0 ) ADD16ItoR(ftreg, imm); - } - else { - if( imm ) { - LEA32RtoR(ftreg, fsreg, imm); - MOVZX32R16toR(ftreg, ftreg); - } - else MOV32RtoR(ftreg, fsreg); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// IADDI -//------------------------------------------------------------------ -void recVUMI_IADDI(VURegs *VU, int info) -{ - s16 imm; - - if ( _Ft_ == 0 ) return; - //SysPrintf("recVUMI_IADDI \n"); - imm = ( VU->code >> 6 ) & 0x1f; - imm = ( imm & 0x10 ? 0xfff0 : 0) | ( imm & 0xf ); - _addISIMMtoIT(VU, imm, info); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// IADDIU -//------------------------------------------------------------------ -void recVUMI_IADDIU(VURegs *VU, int info) -{ - s16 imm; - - if ( _Ft_ == 0 ) return; - //SysPrintf("recVUMI_IADDIU \n"); - imm = ( ( VU->code >> 10 ) & 0x7800 ) | ( VU->code & 0x7ff ); - _addISIMMtoIT(VU, imm, info); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// IADD -//------------------------------------------------------------------ -void recVUMI_IADD( VURegs *VU, int info ) -{ - int fdreg, fsreg = -1, ftreg = -1; - if ( _Fd_ == 0 ) return; - //SysPrintf("recVUMI_IADD \n"); - if ( ( _Ft_ == 0 ) && ( _Fs_ == 0 ) ) { - fdreg = ALLOCVI(_Fd_, MODE_WRITE); - XOR32RtoR(fdreg, fdreg); - return; - } - - ADD_VI_NEEDED(_Fs_); - ADD_VI_NEEDED(_Ft_); - fdreg = ALLOCVI(_Fd_, MODE_WRITE); - - if ( _Fs_ == 0 ) - { - if( (ftreg = _checkX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Ft_, MODE_READ)) >= 0 ) { - if( fdreg != ftreg ) MOV32RtoR(fdreg, ftreg); - } - else MOVZX32M16toR(fdreg, VU_VI_ADDR(_Ft_, 1)); - } - else if ( _Ft_ == 0 ) - { - if( (fsreg = _checkX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Fs_, MODE_READ)) >= 0 ) { - if( fdreg != fsreg ) MOV32RtoR(fdreg, fsreg); - } - else MOVZX32M16toR(fdreg, VU_VI_ADDR(_Fs_, 1)); - } - else { - //ADD_VI_NEEDED(_Ft_); - fsreg = ALLOCVI(_Fs_, MODE_READ); - ftreg = ALLOCVI(_Ft_, MODE_READ); - - if( fdreg == fsreg ) ADD32RtoR(fdreg, ftreg); - else if( fdreg == ftreg ) ADD32RtoR(fdreg, fsreg); - else LEA16RRtoR(fdreg, fsreg, ftreg); - MOVZX32R16toR(fdreg, fdreg); // neeed since don't know if fdreg's upper bits are 0 - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// IAND -//------------------------------------------------------------------ -void recVUMI_IAND( VURegs *VU, int info ) -{ - int fdreg, fsreg = -1, ftreg = -1; - if ( _Fd_ == 0 ) return; - //SysPrintf("recVUMI_IAND \n"); - if ( ( _Fs_ == 0 ) || ( _Ft_ == 0 ) ) { - fdreg = ALLOCVI(_Fd_, MODE_WRITE); - XOR32RtoR(fdreg, fdreg); - return; - } - - ADD_VI_NEEDED(_Fs_); - ADD_VI_NEEDED(_Ft_); - fdreg = ALLOCVI(_Fd_, MODE_WRITE); - - fsreg = ALLOCVI(_Fs_, MODE_READ); - ftreg = ALLOCVI(_Ft_, MODE_READ); - - if( fdreg == fsreg ) AND16RtoR(fdreg, ftreg); - else if( fdreg == ftreg ) AND16RtoR(fdreg, fsreg); - else { - MOV32RtoR(fdreg, ftreg); - AND32RtoR(fdreg, fsreg); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// IOR -//------------------------------------------------------------------ -void recVUMI_IOR( VURegs *VU, int info ) -{ - int fdreg, fsreg = -1, ftreg = -1; - if ( _Fd_ == 0 ) return; - //SysPrintf("recVUMI_IOR \n"); - if ( ( _Ft_ == 0 ) && ( _Fs_ == 0 ) ) { - fdreg = ALLOCVI(_Fd_, MODE_WRITE); - XOR32RtoR(fdreg, fdreg); - return; - } - - ADD_VI_NEEDED(_Fs_); - ADD_VI_NEEDED(_Ft_); - fdreg = ALLOCVI(_Fd_, MODE_WRITE); - - if ( _Fs_ == 0 ) - { - if( (ftreg = _checkX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Ft_, MODE_READ)) >= 0 ) { - if( fdreg != ftreg ) MOV32RtoR(fdreg, ftreg); - } - else MOVZX32M16toR(fdreg, VU_VI_ADDR(_Ft_, 1)); - } - else if ( _Ft_ == 0 ) - { - if( (fsreg = _checkX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Fs_, MODE_READ)) >= 0 ) { - if( fdreg != fsreg ) MOV32RtoR(fdreg, fsreg); - } - else MOVZX32M16toR(fdreg, VU_VI_ADDR(_Fs_, 1)); - } - else - { - fsreg = ALLOCVI(_Fs_, MODE_READ); - ftreg = ALLOCVI(_Ft_, MODE_READ); - - if( fdreg == fsreg ) OR16RtoR(fdreg, ftreg); - else if( fdreg == ftreg ) OR16RtoR(fdreg, fsreg); - else { - MOV32RtoR(fdreg, fsreg); - OR32RtoR(fdreg, ftreg); - } - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ISUB -//------------------------------------------------------------------ -void recVUMI_ISUB( VURegs *VU, int info ) -{ - int fdreg, fsreg = -1, ftreg = -1; - if ( _Fd_ == 0 ) return; - //SysPrintf("recVUMI_ISUB \n"); - if ( ( _Ft_ == 0 ) && ( _Fs_ == 0 ) ) { - fdreg = ALLOCVI(_Fd_, MODE_WRITE); - XOR32RtoR(fdreg, fdreg); - return; - } - - ADD_VI_NEEDED(_Fs_); - ADD_VI_NEEDED(_Ft_); - fdreg = ALLOCVI(_Fd_, MODE_WRITE); - - if ( _Fs_ == 0 ) - { - if( (ftreg = _checkX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Ft_, MODE_READ)) >= 0 ) { - if( fdreg != ftreg ) MOV32RtoR(fdreg, ftreg); - } - else MOVZX32M16toR(fdreg, VU_VI_ADDR(_Ft_, 1)); - NEG16R(fdreg); - } - else if ( _Ft_ == 0 ) - { - if( (fsreg = _checkX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Fs_, MODE_READ)) >= 0 ) { - if( fdreg != fsreg ) MOV32RtoR(fdreg, fsreg); - } - else MOVZX32M16toR(fdreg, VU_VI_ADDR(_Fs_, 1)); - } - else - { - fsreg = ALLOCVI(_Fs_, MODE_READ); - ftreg = ALLOCVI(_Ft_, MODE_READ); - - if( fdreg == fsreg ) SUB16RtoR(fdreg, ftreg); - else if( fdreg == ftreg ) { - SUB16RtoR(fdreg, fsreg); - NEG16R(fdreg); - } - else { - MOV32RtoR(fdreg, fsreg); - SUB16RtoR(fdreg, ftreg); - } - } -} -//------------------------------------------------------------------ - -//------------------------------------------------------------------ -// ISUBIU -//------------------------------------------------------------------ -void recVUMI_ISUBIU( VURegs *VU, int info ) -{ - s16 imm; - - if ( _Ft_ == 0 ) return; - //SysPrintf("recVUMI_ISUBIU \n"); - imm = ( ( VU->code >> 10 ) & 0x7800 ) | ( VU->code & 0x7ff ); - imm = -imm; - _addISIMMtoIT(VU, imm, info); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// MOVE* -//------------------------------------------------------------------ -void recVUMI_MOVE( VURegs *VU, int info ) -{ - if ( (_Ft_ == 0) || (_X_Y_Z_W == 0) ) return; - //SysPrintf("recVUMI_MOVE \n"); - if (_X_Y_Z_W == 0x8) SSE_MOVSS_XMM_to_XMM(EEREC_T, EEREC_S); - else if (_X_Y_Z_W == 0xf) SSE_MOVAPS_XMM_to_XMM(EEREC_T, EEREC_S); - else { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(EEREC_T, EEREC_TEMP); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// MFIR* -//------------------------------------------------------------------ -void recVUMI_MFIR( VURegs *VU, int info ) -{ - if ( (_Ft_ == 0) || (_X_Y_Z_W == 0) ) return; - //SysPrintf("recVUMI_MFIR \n"); - _deleteX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Fs_, 1); - - if( _XYZW_SS ) { - SSE2_MOVD_M32_to_XMM(EEREC_TEMP, VU_VI_ADDR(_Fs_, 1)-2); - _vuFlipRegSS(VU, EEREC_T); - SSE2_PSRAD_I8_to_XMM(EEREC_TEMP, 16); - SSE_MOVSS_XMM_to_XMM(EEREC_T, EEREC_TEMP); - _vuFlipRegSS(VU, EEREC_T); - } - else if (_X_Y_Z_W != 0xf) { - SSE2_MOVD_M32_to_XMM(EEREC_TEMP, VU_VI_ADDR(_Fs_, 1)-2); - SSE2_PSRAD_I8_to_XMM(EEREC_TEMP, 16); - SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0); - VU_MERGE_REGS(EEREC_T, EEREC_TEMP); - } - else { - SSE2_MOVD_M32_to_XMM(EEREC_T, VU_VI_ADDR(_Fs_, 1)-2); - SSE2_PSRAD_I8_to_XMM(EEREC_T, 16); - SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// MTIR* -//------------------------------------------------------------------ -void recVUMI_MTIR( VURegs *VU, int info ) -{ - if ( _Ft_ == 0 ) return; - //SysPrintf("recVUMI_MTIR \n"); - _deleteX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Ft_, 2); - - if( _Fsf_ == 0 ) { - SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(_Ft_, 0), EEREC_S); - } - else { - _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); - SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(_Ft_, 0), EEREC_TEMP); - } - - AND32ItoM(VU_VI_ADDR(_Ft_, 0), 0xffff); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// MR32* -//------------------------------------------------------------------ -void recVUMI_MR32( VURegs *VU, int info ) -{ - if ( (_Ft_ == 0) || (_X_Y_Z_W == 0) ) return; - //SysPrintf("recVUMI_MR32 \n"); - if (_X_Y_Z_W != 0xf) { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x39); - VU_MERGE_REGS(EEREC_T, EEREC_TEMP); - } - else { - SSE_MOVAPS_XMM_to_XMM(EEREC_T, EEREC_S); - SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0x39); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// _loadEAX() -// -// NOTE: If x86reg < 0, reads directly from offset -//------------------------------------------------------------------ -void _loadEAX(VURegs *VU, int x86reg, uptr offset, int info) -{ - assert( offset < 0x80000000 ); - - if( x86reg >= 0 ) { - switch(_X_Y_Z_W) { - case 3: // ZW - SSE_MOVHPS_RmOffset_to_XMM(EEREC_T, x86reg, offset+8); - break; - case 6: // YZ - SSE_SHUFPS_RmOffset_to_XMM(EEREC_T, x86reg, offset, 0x9c); - SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0x78); - break; - - case 8: // X - SSE_MOVSS_RmOffset_to_XMM(EEREC_TEMP, x86reg, offset); - SSE_MOVSS_XMM_to_XMM(EEREC_T, EEREC_TEMP); - break; - case 9: // XW - SSE_SHUFPS_RmOffset_to_XMM(EEREC_T, x86reg, offset, 0xc9); - SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0xd2); - break; - case 12: // XY - SSE_MOVLPS_RmOffset_to_XMM(EEREC_T, x86reg, offset); - break; - case 15: - if( VU == &VU1 ) SSE_MOVAPSRmtoROffset(EEREC_T, x86reg, offset); - else SSE_MOVUPSRmtoROffset(EEREC_T, x86reg, offset); - break; - default: - if( VU == &VU1 ) SSE_MOVAPSRmtoROffset(EEREC_TEMP, x86reg, offset); - else SSE_MOVUPSRmtoROffset(EEREC_TEMP, x86reg, offset); - - VU_MERGE_REGS(EEREC_T, EEREC_TEMP); - break; - } - } - else { - switch(_X_Y_Z_W) { - case 3: // ZW - SSE_MOVHPS_M64_to_XMM(EEREC_T, offset+8); - break; - case 6: // YZ - SSE_SHUFPS_M128_to_XMM(EEREC_T, offset, 0x9c); - SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0x78); - break; - case 8: // X - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, offset); - SSE_MOVSS_XMM_to_XMM(EEREC_T, EEREC_TEMP); - break; - case 9: // XW - SSE_SHUFPS_M128_to_XMM(EEREC_T, offset, 0xc9); - SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0xd2); - break; - case 12: // XY - SSE_MOVLPS_M64_to_XMM(EEREC_T, offset); - break; - case 15: - if( VU == &VU1 ) SSE_MOVAPS_M128_to_XMM(EEREC_T, offset); - else SSE_MOVUPS_M128_to_XMM(EEREC_T, offset); - break; - default: - if( VU == &VU1 ) SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, offset); - else SSE_MOVUPS_M128_to_XMM(EEREC_TEMP, offset); - VU_MERGE_REGS(EEREC_T, EEREC_TEMP); - break; - } - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// recVUTransformAddr() -//------------------------------------------------------------------ -int recVUTransformAddr(int x86reg, VURegs* VU, int vireg, int imm) -{ - u8* pjmp[2]; - if( x86reg == EAX ) { - if (imm) ADD32ItoR(x86reg, imm); - } - else { - if( imm ) LEA32RtoR(EAX, x86reg, imm); - else MOV32RtoR(EAX, x86reg); - } - - if( VU == &VU1 ) { - AND32ItoR(EAX, 0x3ff); // wrap around - SHL32ItoR(EAX, 4); - } - else { - - // VU0 has a somewhat interesting memory mapping: - // if addr >= 0x4000, reads VU1's VF regs and VI regs - // if addr < 0x4000, wrap around at 0x1000 - - CMP32ItoR(EAX, 0x400); - pjmp[0] = JL8(0); // if addr >= 0x4000, reads VU1's VF regs and VI regs - AND32ItoR(EAX, 0x43f); - pjmp[1] = JMP8(0); - x86SetJ8(pjmp[0]); - AND32ItoR(EAX, 0xff); // if addr < 0x4000, wrap around - x86SetJ8(pjmp[1]); - - SHL32ItoR(EAX, 4); // multiply by 16 (shift left by 4) - } - - return EAX; -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// LQ -//------------------------------------------------------------------ -void recVUMI_LQ(VURegs *VU, int info) -{ - s16 imm; - if ( _Ft_ == 0 ) return; - //SysPrintf("recVUMI_LQ \n"); - imm = (VU->code & 0x400) ? (VU->code & 0x3ff) | 0xfc00 : (VU->code & 0x3ff); - if (_Fs_ == 0) { - _loadEAX(VU, -1, (uptr)GET_VU_MEM(VU, (u32)imm*16), info); - } - else { - int fsreg = ALLOCVI(_Fs_, MODE_READ); - _loadEAX(VU, recVUTransformAddr(fsreg, VU, _Fs_, imm), (uptr)VU->Mem, info); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// LQD -//------------------------------------------------------------------ -void recVUMI_LQD( VURegs *VU, int info ) -{ - int fsreg; - //SysPrintf("recVUMI_LQD \n"); - if ( _Fs_ != 0 ) { - fsreg = ALLOCVI(_Fs_, MODE_READ|MODE_WRITE); - SUB16ItoR( fsreg, 1 ); - } - - if ( _Ft_ == 0 ) return; - - if ( _Fs_ == 0 ) _loadEAX(VU, -1, (uptr)VU->Mem, info); - else _loadEAX(VU, recVUTransformAddr(fsreg, VU, _Fs_, 0), (uptr)VU->Mem, info); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// LQI -//------------------------------------------------------------------ -void recVUMI_LQI(VURegs *VU, int info) -{ - int fsreg; - //SysPrintf("recVUMI_LQI \n"); - if ( _Ft_ == 0 ) { - if( _Fs_ != 0 ) { - if( (fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_WRITE|MODE_READ)) >= 0 ) { - ADD16ItoR(fsreg, 1); - } - else { - ADD16ItoM( VU_VI_ADDR( _Fs_, 0 ), 1 ); - } - } - return; - } - - if (_Fs_ == 0) { - _loadEAX(VU, -1, (uptr)VU->Mem, info); - } - else { - fsreg = ALLOCVI(_Fs_, MODE_READ|MODE_WRITE); - _loadEAX(VU, recVUTransformAddr(fsreg, VU, _Fs_, 0), (uptr)VU->Mem, info); - ADD16ItoR( fsreg, 1 ); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// _saveEAX() -//------------------------------------------------------------------ -void _saveEAX(VURegs *VU, int x86reg, uptr offset, int info) -{ - assert( offset < 0x80000000 ); - - if ( _Fs_ == 0 ) { - if ( _XYZW_SS ) { - u32 c = _W ? 0x3f800000 : 0; - if ( x86reg >= 0 ) MOV32ItoRmOffset(x86reg, c, offset+(_W?12:(_Z?8:(_Y?4:0)))); - else MOV32ItoM(offset+(_W?12:(_Z?8:(_Y?4:0))), c); - } - else { - if ( x86reg >= 0 ) { - if ( _X ) MOV32ItoRmOffset(x86reg, 0x00000000, offset); - if ( _Y ) MOV32ItoRmOffset(x86reg, 0x00000000, offset+4); - if ( _Z ) MOV32ItoRmOffset(x86reg, 0x00000000, offset+8); - if ( _W ) MOV32ItoRmOffset(x86reg, 0x3f800000, offset+12); - } - else { - if ( _X ) MOV32ItoM(offset, 0x00000000); - if ( _Y ) MOV32ItoM(offset+4, 0x00000000); - if ( _Z ) MOV32ItoM(offset+8, 0x00000000); - if ( _W ) MOV32ItoM(offset+12, 0x3f800000); - } - } - return; - } - - switch ( _X_Y_Z_W ) { - case 1: // W - SSE2_PSHUFD_XMM_to_XMM(EEREC_TEMP, EEREC_S, 0x27); - if ( x86reg >= 0 ) SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+12); - else SSE_MOVSS_XMM_to_M32(offset+12, EEREC_TEMP); - break; - case 2: // Z - SSE_MOVHLPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - if ( x86reg >= 0 ) SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+8); - else SSE_MOVSS_XMM_to_M32(offset+8, EEREC_TEMP); - break; - case 3: // ZW - if ( x86reg >= 0 ) SSE_MOVHPS_XMM_to_RmOffset(x86reg, EEREC_S, offset+8); - else SSE_MOVHPS_XMM_to_M64(offset+8, EEREC_S); - break; - case 4: // Y - SSE2_PSHUFLW_XMM_to_XMM(EEREC_TEMP, EEREC_S, 0x4e); - if ( x86reg >= 0 ) SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+4); - else SSE_MOVSS_XMM_to_M32(offset+4, EEREC_TEMP); - break; - case 5: // YW - SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0xB1); - SSE_MOVHLPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - if ( x86reg >= 0 ) { - SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_S, offset+4); - SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+12); - } - else { - SSE_MOVSS_XMM_to_M32(offset+4, EEREC_S); - SSE_MOVSS_XMM_to_M32(offset+12, EEREC_TEMP); - } - SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0xB1); - break; - case 6: // YZ - SSE2_PSHUFD_XMM_to_XMM(EEREC_TEMP, EEREC_S, 0xc9); - if ( x86reg >= 0 ) SSE_MOVLPS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+4); - else SSE_MOVLPS_XMM_to_M64(offset+4, EEREC_TEMP); - break; - case 7: // YZW - SSE2_PSHUFD_XMM_to_XMM(EEREC_TEMP, EEREC_S, 0x93); //ZYXW - if ( x86reg >= 0 ) { - SSE_MOVHPS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+4); - SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+12); - } - else { - SSE_MOVHPS_XMM_to_M64(offset+4, EEREC_TEMP); - SSE_MOVSS_XMM_to_M32(offset+12, EEREC_TEMP); - } - break; - case 8: // X - if ( x86reg >= 0 ) SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_S, offset); - else SSE_MOVSS_XMM_to_M32(offset, EEREC_S); - break; - case 9: // XW - SSE_MOVHLPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - if ( x86reg >= 0 ) SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_S, offset); - else SSE_MOVSS_XMM_to_M32(offset, EEREC_S); - - if ( cpucaps.hasStreamingSIMD3Extensions ) SSE3_MOVSLDUP_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); - else SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x55); - - if ( x86reg >= 0 ) SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+12); - else SSE_MOVSS_XMM_to_M32(offset+12, EEREC_TEMP); - - break; - case 10: //XZ - SSE_MOVHLPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - if ( x86reg >= 0 ) { - SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_S, offset); - SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+8); - } - else { - SSE_MOVSS_XMM_to_M32(offset, EEREC_S); - SSE_MOVSS_XMM_to_M32(offset+8, EEREC_TEMP); - } - break; - case 11: //XZW - if ( x86reg >= 0 ) { - SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_S, offset); - SSE_MOVHPS_XMM_to_RmOffset(x86reg, EEREC_S, offset+8); - } - else { - SSE_MOVSS_XMM_to_M32(offset, EEREC_S); - SSE_MOVHPS_XMM_to_M64(offset+8, EEREC_S); - } - break; - case 12: // XY - if ( x86reg >= 0 ) SSE_MOVLPS_XMM_to_RmOffset(x86reg, EEREC_S, offset+0); - else SSE_MOVLPS_XMM_to_M64(offset, EEREC_S); - break; - case 13: // XYW - SSE2_PSHUFD_XMM_to_XMM(EEREC_TEMP, EEREC_S, 0x4b); //YXZW - if ( x86reg >= 0 ) { - SSE_MOVHPS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+0); - SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+12); - } - else { - SSE_MOVHPS_XMM_to_M64(offset, EEREC_TEMP); - SSE_MOVSS_XMM_to_M32(offset+12, EEREC_TEMP); - } - break; - case 14: // XYZ - SSE_MOVHLPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - if ( x86reg >= 0 ) { - SSE_MOVLPS_XMM_to_RmOffset(x86reg, EEREC_S, offset+0); - SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+8); - } - else { - SSE_MOVLPS_XMM_to_M64(offset, EEREC_S); - SSE_MOVSS_XMM_to_M32(offset+8, EEREC_TEMP); - } - break; - case 15: // XYZW - if ( VU == &VU1 ) { - if( x86reg >= 0 ) SSE_MOVAPSRtoRmOffset(x86reg, EEREC_S, offset+0); - else SSE_MOVAPS_XMM_to_M128(offset, EEREC_S); - } - else { - if( x86reg >= 0 ) SSE_MOVUPSRtoRmOffset(x86reg, EEREC_S, offset+0); - else { - if( offset & 15 ) SSE_MOVUPS_XMM_to_M128(offset, EEREC_S); - else SSE_MOVAPS_XMM_to_M128(offset, EEREC_S); - } - } - break; - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// SQ -//------------------------------------------------------------------ -void recVUMI_SQ(VURegs *VU, int info) -{ - s16 imm; - //SysPrintf("recVUMI_SQ \n"); - imm = ( VU->code & 0x400) ? ( VU->code & 0x3ff) | 0xfc00 : ( VU->code & 0x3ff); - if ( _Ft_ == 0 ) _saveEAX(VU, -1, (uptr)GET_VU_MEM(VU, (int)imm * 16), info); - else { - int ftreg = ALLOCVI(_Ft_, MODE_READ); - _saveEAX(VU, recVUTransformAddr(ftreg, VU, _Ft_, imm), (uptr)VU->Mem, info); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// SQD -//------------------------------------------------------------------ -void recVUMI_SQD(VURegs *VU, int info) -{ - //SysPrintf("recVUMI_SQD \n"); - if (_Ft_ == 0) _saveEAX(VU, -1, (uptr)VU->Mem, info); - else { - int ftreg = ALLOCVI(_Ft_, MODE_READ|MODE_WRITE); - SUB16ItoR( ftreg, 1 ); - _saveEAX(VU, recVUTransformAddr(ftreg, VU, _Ft_, 0), (uptr)VU->Mem, info); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// SQI -//------------------------------------------------------------------ -void recVUMI_SQI(VURegs *VU, int info) -{ - //SysPrintf("recVUMI_SQI \n"); - if (_Ft_ == 0) _saveEAX(VU, -1, (uptr)VU->Mem, info); - else { - int ftreg = ALLOCVI(_Ft_, MODE_READ|MODE_WRITE); - _saveEAX(VU, recVUTransformAddr(ftreg, VU, _Ft_, 0), (uptr)VU->Mem, info); - ADD16ItoR( ftreg, 1 ); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ILW -//------------------------------------------------------------------ -void recVUMI_ILW(VURegs *VU, int info) -{ - int ftreg; - s16 imm, off; - - if ( ( _Ft_ == 0 ) || ( _X_Y_Z_W == 0 ) ) return; - //SysPrintf("recVUMI_ILW \n"); - imm = ( VU->code & 0x400) ? ( VU->code & 0x3ff) | 0xfc00 : ( VU->code & 0x3ff); - if (_X) off = 0; - else if (_Y) off = 4; - else if (_Z) off = 8; - else if (_W) off = 12; - - ADD_VI_NEEDED(_Fs_); - ftreg = ALLOCVI(_Ft_, MODE_WRITE); - - if ( _Fs_ == 0 ) { - MOVZX32M16toR( ftreg, (uptr)GET_VU_MEM(VU, (int)imm * 16 + off) ); - } - else { - int fsreg = ALLOCVI(_Fs_, MODE_READ); - MOV32RmtoROffset(ftreg, recVUTransformAddr(fsreg, VU, _Fs_, imm), (uptr)VU->Mem + off); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ISW -//------------------------------------------------------------------ -void recVUMI_ISW( VURegs *VU, int info ) -{ - s16 imm; - //SysPrintf("recVUMI_ISW \n"); - imm = ( VU->code & 0x400) ? ( VU->code & 0x3ff) | 0xfc00 : ( VU->code & 0x3ff); - - if (_Fs_ == 0) { - uptr off = (uptr)GET_VU_MEM(VU, (int)imm * 16); - int ftreg = ALLOCVI(_Ft_, MODE_READ); - - if (_X) MOV32RtoM(off, ftreg); - if (_Y) MOV32RtoM(off+4, ftreg); - if (_Z) MOV32RtoM(off+8, ftreg); - if (_W) MOV32RtoM(off+12, ftreg); - } - else { - int x86reg, fsreg, ftreg; - - ADD_VI_NEEDED(_Ft_); - fsreg = ALLOCVI(_Fs_, MODE_READ); - ftreg = ALLOCVI(_Ft_, MODE_READ); - - x86reg = recVUTransformAddr(fsreg, VU, _Fs_, imm); - - if (_X) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem); - if (_Y) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem+4); - if (_Z) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem+8); - if (_W) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem+12); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ILWR -//------------------------------------------------------------------ -void recVUMI_ILWR( VURegs *VU, int info ) -{ - int off, ftreg; - - if ( ( _Ft_ == 0 ) || ( _X_Y_Z_W == 0 ) ) return; - //SysPrintf("recVUMI_ILWR \n"); - if (_X) off = 0; - else if (_Y) off = 4; - else if (_Z) off = 8; - else if (_W) off = 12; - - ADD_VI_NEEDED(_Fs_); - ftreg = ALLOCVI(_Ft_, MODE_WRITE); - - if ( _Fs_ == 0 ) { - MOVZX32M16toR( ftreg, (uptr)VU->Mem + off ); - } - else { - int fsreg = ALLOCVI(_Fs_, MODE_READ); - MOVZX32Rm16toROffset(ftreg, recVUTransformAddr(fsreg, VU, _Fs_, 0), (uptr)VU->Mem + off); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ISWR -//------------------------------------------------------------------ -void recVUMI_ISWR( VURegs *VU, int info ) -{ - int ftreg; - //SysPrintf("recVUMI_ISWR \n"); - ADD_VI_NEEDED(_Fs_); - ftreg = ALLOCVI(_Ft_, MODE_READ); - - if (_Fs_ == 0) { - if (_X) MOV32RtoM((uptr)VU->Mem, ftreg); - if (_Y) MOV32RtoM((uptr)VU->Mem+4, ftreg); - if (_Z) MOV32RtoM((uptr)VU->Mem+8, ftreg); - if (_W) MOV32RtoM((uptr)VU->Mem+12, ftreg); - } - else { - int x86reg; - int fsreg = ALLOCVI(_Fs_, MODE_READ); - x86reg = recVUTransformAddr(fsreg, VU, _Fs_, 0); - - if (_X) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem); - if (_Y) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem+4); - if (_Z) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem+8); - if (_W) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem+12); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// RINIT* -//------------------------------------------------------------------ -void recVUMI_RINIT(VURegs *VU, int info) -{ - //SysPrintf("recVUMI_RINIT()\n"); - if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode & MODE_NOFLUSH) ) { - _deleteX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), REG_R, 2); - _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); - - SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)s_mask); - SSE_ORPS_M128_to_XMM(EEREC_TEMP, (uptr)VU_ONE); - SSE_MOVSS_XMM_to_M32(VU_REGR_ADDR, EEREC_TEMP); - } - else { - int rreg = ALLOCVI(REG_R, MODE_WRITE); - - if( xmmregs[EEREC_S].mode & MODE_WRITE ) { - SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); - xmmregs[EEREC_S].mode &= ~MODE_WRITE; - } - - MOV32MtoR( rreg, VU_VFx_ADDR( _Fs_ ) + 4 * _Fsf_ ); - AND32ItoR( rreg, 0x7fffff ); - OR32ItoR( rreg, 0x7f << 23 ); - - _deleteX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), REG_R, 1); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// RGET* -//------------------------------------------------------------------ -void recVUMI_RGET(VURegs *VU, int info) -{ - //SysPrintf("recVUMI_RGET()\n"); - if ( (_Ft_ == 0) || (_X_Y_Z_W == 0) ) return; - - _deleteX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), REG_R, 1); - - if (_X_Y_Z_W != 0xf) { - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, VU_REGR_ADDR); - SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0); - VU_MERGE_REGS(EEREC_T, EEREC_TEMP); - } - else { - SSE_MOVSS_M32_to_XMM(EEREC_T, VU_REGR_ADDR); - SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// RNEXT* -//------------------------------------------------------------------ -void recVUMI_RNEXT( VURegs *VU, int info ) -{ - int rreg, x86temp0, x86temp1; - //SysPrintf("recVUMI_RNEXT()\n"); - - rreg = ALLOCVI(REG_R, MODE_WRITE|MODE_READ); - - x86temp0 = ALLOCTEMPX86(0); - x86temp1 = ALLOCTEMPX86(0); - - // code from www.project-fao.org - //MOV32MtoR(rreg, VU_REGR_ADDR); - MOV32RtoR(x86temp0, rreg); - SHR32ItoR(x86temp0, 4); - AND32ItoR(x86temp0, 1); - - MOV32RtoR(x86temp1, rreg); - SHR32ItoR(x86temp1, 22); - AND32ItoR(x86temp1, 1); - - SHL32ItoR(rreg, 1); - XOR32RtoR(x86temp0, x86temp1); - XOR32RtoR(rreg, x86temp0); - AND32ItoR(rreg, 0x7fffff); - OR32ItoR(rreg, 0x3f800000); - - _freeX86reg(x86temp0); - _freeX86reg(x86temp1); - - if ( (_Ft_ == 0) || (_X_Y_Z_W == 0) ) { - _deleteX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), REG_R, 1); - return; - } - - recVUMI_RGET(VU, info); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// RXOR* -//------------------------------------------------------------------ -void recVUMI_RXOR( VURegs *VU, int info ) -{ - //SysPrintf("recVUMI_RXOR()\n"); - if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode & MODE_NOFLUSH) ) { - _deleteX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), REG_R, 1); - _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); - - SSE_XORPS_M128_to_XMM(EEREC_TEMP, VU_REGR_ADDR); - SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)s_mask); - SSE_ORPS_M128_to_XMM(EEREC_TEMP, (uptr)s_fones); - SSE_MOVSS_XMM_to_M32(VU_REGR_ADDR, EEREC_TEMP); - } - else { - int rreg = ALLOCVI(REG_R, MODE_WRITE|MODE_READ); - - if( xmmregs[EEREC_S].mode & MODE_WRITE ) { - SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); - xmmregs[EEREC_S].mode &= ~MODE_WRITE; - } - - XOR32MtoR( rreg, VU_VFx_ADDR( _Fs_ ) + 4 * _Fsf_ ); - AND32ItoR( rreg, 0x7fffff ); - OR32ItoR ( rreg, 0x3f800000 ); - - _deleteX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), REG_R, 1); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// WAITQ -//------------------------------------------------------------------ -void recVUMI_WAITQ( VURegs *VU, int info ) -{ - //SysPrintf("recVUMI_WAITQ \n"); -// if( info & PROCESS_VU_SUPER ) { -// //CALLFunc(waitqfn); -// SuperVUFlush(0, 1); -// } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// FSAND -//------------------------------------------------------------------ -void recVUMI_FSAND( VURegs *VU, int info ) -{ - int ftreg; - u16 imm; - //SysPrintf("recVUMI_FSAND \n"); - imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7ff); - if(_Ft_ == 0) return; - - ftreg = ALLOCVI(_Ft_, MODE_WRITE); - MOV32MtoR( ftreg, VU_VI_ADDR(REG_STATUS_FLAG, 1) ); - AND32ItoR( ftreg, imm ); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// FSEQ -//------------------------------------------------------------------ -void recVUMI_FSEQ( VURegs *VU, int info ) -{ - int ftreg; - u32 imm; - if ( _Ft_ == 0 ) return; - //SysPrintf("recVUMI_FSEQ \n"); - imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7ff); - - ftreg = ALLOCVI(_Ft_, MODE_WRITE); - - MOVZX32M16toR( EAX, VU_VI_ADDR(REG_STATUS_FLAG, 1) ); - XOR32RtoR(ftreg, ftreg); - - CMP16ItoR(EAX, imm); - SETE8R(ftreg); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// FSOR -//------------------------------------------------------------------ -void recVUMI_FSOR( VURegs *VU, int info ) -{ - int ftreg; - u32 imm; - if(_Ft_ == 0) return; - //SysPrintf("recVUMI_FSOR \n"); - imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7ff); - - ftreg = ALLOCVI(_Ft_, MODE_WRITE); - - MOVZX32M16toR( ftreg, VU_VI_ADDR(REG_STATUS_FLAG, 1) ); - OR32ItoR( ftreg, imm ); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// FSSET -//------------------------------------------------------------------ -void recVUMI_FSSET(VURegs *VU, int info) -{ - u32 writeaddr = VU_VI_ADDR(REG_STATUS_FLAG, 0); - u32 prevaddr = VU_VI_ADDR(REG_STATUS_FLAG, 2); - - u16 imm = 0; - //SysPrintf("recVUMI_FSSET \n"); - imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7FF); - - // keep the low 6 bits ONLY if the upper instruction is an fmac instruction (otherwise rewrite) - metal gear solid 3 - //if( (info & PROCESS_VU_SUPER) && VUREC_FMAC ) { - MOV32MtoR(EAX, prevaddr); - AND32ItoR(EAX, 0x3f); - if ((imm&0xfc0) != 0) OR32ItoR(EAX, imm & 0xFC0); - MOV32RtoM(writeaddr ? writeaddr : prevaddr, EAX); - //} - //else { - // MOV32ItoM(writeaddr ? writeaddr : prevaddr, imm&0xfc0); - //} -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// FMAND -//------------------------------------------------------------------ -void recVUMI_FMAND( VURegs *VU, int info ) -{ - int fsreg, ftreg; - if ( _Ft_ == 0 ) return; - //SysPrintf("recVUMI_FMAND \n"); - fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); - ftreg = ALLOCVI(_Ft_, MODE_WRITE);//|MODE_8BITREG); - - if( fsreg >= 0 ) { - if( ftreg != fsreg ) MOV32RtoR(ftreg, fsreg); - } - else MOV16MtoR(ftreg, VU_VI_ADDR(_Fs_, 1)); - - AND16MtoR( ftreg, VU_VI_ADDR(REG_MAC_FLAG, 1)); - //MOVZX32R16toR(ftreg, ftreg); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// FMEQ -//------------------------------------------------------------------ -void recVUMI_FMEQ( VURegs *VU, int info ) -{ - int ftreg, fsreg; - if ( _Ft_ == 0 ) return; - //SysPrintf("recVUMI_FMEQ \n"); - if( _Ft_ == _Fs_ ) { - ftreg = ALLOCVI(_Ft_, MODE_WRITE|MODE_READ);//|MODE_8BITREG); - - CMP16MtoR(ftreg, VU_VI_ADDR(REG_MAC_FLAG, 1)); - SETE8R(EAX); - MOVZX32R8toR(ftreg, EAX); - } - else { - ADD_VI_NEEDED(_Fs_); - fsreg = ALLOCVI(_Fs_, MODE_READ); - ftreg = ALLOCVI(_Ft_, MODE_WRITE|MODE_8BITREG); - - XOR32RtoR(ftreg, ftreg); - - CMP16MtoR(fsreg, VU_VI_ADDR(REG_MAC_FLAG, 1)); - SETE8R(ftreg); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// FMOR -//------------------------------------------------------------------ -void recVUMI_FMOR( VURegs *VU, int info ) -{ - int fsreg, ftreg; - if ( _Ft_ == 0 ) return; - //SysPrintf("recVUMI_FMOR \n"); - if( _Fs_ == 0 ) { - ftreg = ALLOCVI(_Ft_, MODE_WRITE);//|MODE_8BITREG); - MOVZX32M16toR( ftreg, VU_VI_ADDR(REG_MAC_FLAG, 1) ); - } - else if( _Ft_ == _Fs_ ) { - ftreg = ALLOCVI(_Ft_, MODE_WRITE);//|MODE_READ|MODE_8BITREG); - OR16MtoR( ftreg, VU_VI_ADDR(REG_MAC_FLAG, 1) ); - } - else { - fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); - ftreg = ALLOCVI(_Ft_, MODE_WRITE); - - MOVZX32M16toR( ftreg, VU_VI_ADDR(REG_MAC_FLAG, 1) ); - - if( fsreg >= 0 ) - OR16RtoR( ftreg, fsreg ); - else - OR16MtoR( ftreg, VU_VI_ADDR(_Fs_, 1) ); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// FCAND -//------------------------------------------------------------------ -void recVUMI_FCAND( VURegs *VU, int info ) -{ - int ftreg = ALLOCVI(1, MODE_WRITE|MODE_8BITREG); - //SysPrintf("recVUMI_FCAND \n"); - MOV32MtoR( EAX, VU_VI_ADDR(REG_CLIP_FLAG, 1) ); - XOR32RtoR( ftreg, ftreg ); - AND32ItoR( EAX, VU->code & 0xFFFFFF ); - - SETNZ8R(ftreg); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// FCEQ -//------------------------------------------------------------------ -void recVUMI_FCEQ( VURegs *VU, int info ) -{ - int ftreg = ALLOCVI(1, MODE_WRITE|MODE_8BITREG); - //SysPrintf("recVUMI_FCEQ \n"); - MOV32MtoR( EAX, VU_VI_ADDR(REG_CLIP_FLAG, 1) ); - AND32ItoR( EAX, 0xffffff ); - XOR32RtoR( ftreg, ftreg ); - CMP32ItoR( EAX, VU->code&0xffffff ); - - SETE8R(ftreg); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// FCOR -//------------------------------------------------------------------ -void recVUMI_FCOR( VURegs *VU, int info ) -{ - int ftreg = ALLOCVI(1, MODE_WRITE|MODE_8BITREG); - //SysPrintf("recVUMI_FCOR \n"); - MOV32MtoR( EAX, VU_VI_ADDR(REG_CLIP_FLAG, 1) ); - XOR32RtoR( ftreg, ftreg ); - OR32ItoR( EAX, VU->code ); - AND32ItoR( EAX, 0xffffff ); - CMP32ItoR( EAX, 0xffffff ); - - SETZ8R(ftreg); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// FCSET -//------------------------------------------------------------------ -void recVUMI_FCSET( VURegs *VU, int info ) -{ - u32 addr = VU_VI_ADDR(REG_CLIP_FLAG, 0); - //SysPrintf("recVUMI_FCSET \n"); - MOV32ItoM(addr ? addr : VU_VI_ADDR(REG_CLIP_FLAG, 2), VU->code&0xffffff ); - - if( !(info & (PROCESS_VU_SUPER|PROCESS_VU_COP2)) ) - MOV32ItoM( VU_VI_ADDR(REG_CLIP_FLAG, 1), VU->code&0xffffff ); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// FCGET -//------------------------------------------------------------------ -void recVUMI_FCGET( VURegs *VU, int info ) -{ - int ftreg; - if(_Ft_ == 0) return; - //SysPrintf("recVUMI_FCGET \n"); - ftreg = ALLOCVI(_Ft_, MODE_WRITE); - - MOV32MtoR(ftreg, VU_VI_ADDR(REG_CLIP_FLAG, 1)); - AND32ItoR(ftreg, 0x0fff); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// _recbranchAddr() -// -// NOTE: Due to static var dependencies, several SuperVU branch instructions -// are still located in iVUzerorec.cpp. -//------------------------------------------------------------------ - -//------------------------------------------------------------------ -// MFP* -//------------------------------------------------------------------ -void recVUMI_MFP(VURegs *VU, int info) -{ - if ( (_Ft_ == 0) || (_X_Y_Z_W == 0) ) return; - //SysPrintf("recVUMI_MFP \n"); - if( _XYZW_SS ) { - _vuFlipRegSS(VU, EEREC_T); - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, VU_VI_ADDR(REG_P, 1)); - SSE_MOVSS_XMM_to_XMM(EEREC_T, EEREC_TEMP); - _vuFlipRegSS(VU, EEREC_T); - } - else if (_X_Y_Z_W != 0xf) { - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, VU_VI_ADDR(REG_P, 1)); - SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0); - VU_MERGE_REGS(EEREC_T, EEREC_TEMP); - } - else { - SSE_MOVSS_M32_to_XMM(EEREC_T, VU_VI_ADDR(REG_P, 1)); - SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// WAITP -//------------------------------------------------------------------ -static PCSX2_ALIGNED16(float s_tempmem[4]); -void recVUMI_WAITP(VURegs *VU, int info) -{ - //SysPrintf("recVUMI_WAITP \n"); -// if( info & PROCESS_VU_SUPER ) -// SuperVUFlush(1, 1); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// vuSqSumXYZ()* -// -// NOTE: In all EFU insts, EEREC_D is a temp reg -//------------------------------------------------------------------ -void vuSqSumXYZ(int regd, int regs, int regtemp) // regd.x = x ^ 2 + y ^ 2 + z ^ 2 -{ - //SysPrintf("VU: SUMXYZ\n"); - if( cpucaps.hasStreamingSIMD4Extensions ) - { - SSE_MOVAPS_XMM_to_XMM(regd, regs); - if (CHECK_VU_EXTRA_OVERFLOW) vuFloat2(regd, regtemp, 0xf); - SSE4_DPPS_XMM_to_XMM(regd, regd, 0x71); - } - else - { - SSE_MOVAPS_XMM_to_XMM(regtemp, regs); - if (CHECK_VU_EXTRA_OVERFLOW) vuFloat2(regtemp, regd, 0xf); - SSE_MULPS_XMM_to_XMM(regtemp, regtemp); // xyzw ^ 2 - - if( cpucaps.hasStreamingSIMD3Extensions ) { - SSE3_HADDPS_XMM_to_XMM(regd, regtemp); - SSE_ADDPS_XMM_to_XMM(regd, regtemp); // regd.z = x ^ 2 + y ^ 2 + z ^ 2 - SSE_MOVHLPS_XMM_to_XMM(regd, regd); // regd.x = regd.z - } - else { - SSE_MOVSS_XMM_to_XMM(regd, regtemp); - SSE2_PSHUFLW_XMM_to_XMM(regtemp, regtemp, 0x4e); // wzyx -> wzxy - SSE_ADDSS_XMM_to_XMM(regd, regtemp); // x ^ 2 + y ^ 2 - SSE_SHUFPS_XMM_to_XMM(regtemp, regtemp, 0xD2); // wzxy -> wxyz - SSE_ADDSS_XMM_to_XMM(regd, regtemp); // x ^ 2 + y ^ 2 + z ^ 2 - } - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ESADD* -//------------------------------------------------------------------ -void recVUMI_ESADD( VURegs *VU, int info) -{ - //SysPrintf("VU: ESADD\n"); - assert( VU == &VU1 ); - if( EEREC_TEMP == EEREC_D ) { // special code to reset P ( FixMe: don't know if this is still needed! (cottonvibes) ) - Console::Notice("ESADD: Resetting P reg!!!\n"); - MOV32ItoM(VU_VI_ADDR(REG_P, 0), 0); - return; - } - vuSqSumXYZ(EEREC_D, EEREC_S, EEREC_TEMP); - if (CHECK_VU_OVERFLOW) SSE_MINSS_M32_to_XMM(EEREC_D, (uptr)g_maxvals); // Only need to do positive clamp since (x ^ 2 + y ^ 2 + z ^ 2) is positive - SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_D); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ERSADD* -//------------------------------------------------------------------ -void recVUMI_ERSADD( VURegs *VU, int info ) -{ - //SysPrintf("VU: ERSADD\n"); - assert( VU == &VU1 ); - vuSqSumXYZ(EEREC_D, EEREC_S, EEREC_TEMP); - // don't use RCPSS (very bad precision) - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)VU_ONE); - SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_D); - if (CHECK_VU_OVERFLOW) SSE_MINSS_M32_to_XMM(EEREC_TEMP, (uptr)g_maxvals); // Only need to do positive clamp since (x ^ 2 + y ^ 2 + z ^ 2) is positive - SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ELENG* -//------------------------------------------------------------------ -void recVUMI_ELENG( VURegs *VU, int info ) -{ - //SysPrintf("VU: ELENG\n"); - assert( VU == &VU1 ); - vuSqSumXYZ(EEREC_D, EEREC_S, EEREC_TEMP); - if (CHECK_VU_OVERFLOW) SSE_MINSS_M32_to_XMM(EEREC_D, (uptr)g_maxvals); // Only need to do positive clamp since (x ^ 2 + y ^ 2 + z ^ 2) is positive - SSE_SQRTSS_XMM_to_XMM(EEREC_D, EEREC_D); - SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_D); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ERLENG* -//------------------------------------------------------------------ -void recVUMI_ERLENG( VURegs *VU, int info ) -{ - //SysPrintf("VU: ERLENG\n"); - assert( VU == &VU1 ); - vuSqSumXYZ(EEREC_D, EEREC_S, EEREC_TEMP); - if (CHECK_VU_OVERFLOW) SSE_MINSS_M32_to_XMM(EEREC_D, (uptr)g_maxvals); // Only need to do positive clamp since (x ^ 2 + y ^ 2 + z ^ 2) is positive - SSE_SQRTSS_XMM_to_XMM(EEREC_D, EEREC_D); // regd <- sqrt(x^2 + y^2 + z^2) - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)VU_ONE); // temp <- 1 - SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_D); // temp = 1 / sqrt(x^2 + y^2 + z^2) - if (CHECK_VU_OVERFLOW) SSE_MINSS_M32_to_XMM(EEREC_TEMP, (uptr)g_maxvals); // Only need to do positive clamp - SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// EATANxy -//------------------------------------------------------------------ -void recVUMI_EATANxy( VURegs *VU, int info ) -{ - assert( VU == &VU1 ); - //SysPrintf("recVUMI_EATANxy \n"); - if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode&MODE_NOFLUSH) ) { - SSE_MOVLPS_XMM_to_M64((uptr)s_tempmem, EEREC_S); - FLD32((uptr)&s_tempmem[0]); - FLD32((uptr)&s_tempmem[1]); - } - else { - if( xmmregs[EEREC_S].mode & MODE_WRITE ) { - SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); - xmmregs[EEREC_S].mode &= ~MODE_WRITE; - } - - FLD32((uptr)&VU->VF[_Fs_].UL[0]); - FLD32((uptr)&VU->VF[_Fs_].UL[1]); - } - - FPATAN(); - FSTP32(VU_VI_ADDR(REG_P, 0)); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// EATANxz -//------------------------------------------------------------------ -void recVUMI_EATANxz( VURegs *VU, int info ) -{ - assert( VU == &VU1 ); - //SysPrintf("recVUMI_EATANxz \n"); - if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode&MODE_NOFLUSH) ) { - SSE_MOVLPS_XMM_to_M64((uptr)s_tempmem, EEREC_S); - FLD32((uptr)&s_tempmem[0]); - FLD32((uptr)&s_tempmem[2]); - } - else { - if( xmmregs[EEREC_S].mode & MODE_WRITE ) { - SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); - xmmregs[EEREC_S].mode &= ~MODE_WRITE; - } - - FLD32((uptr)&VU->VF[_Fs_].UL[0]); - FLD32((uptr)&VU->VF[_Fs_].UL[2]); - } - FPATAN(); - FSTP32(VU_VI_ADDR(REG_P, 0)); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ESUM* -//------------------------------------------------------------------ -void recVUMI_ESUM( VURegs *VU, int info ) -{ - //SysPrintf("VU: ESUM\n"); - assert( VU == &VU1 ); - - if( cpucaps.hasStreamingSIMD3Extensions ) { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) vuFloat_useEAX(info, EEREC_TEMP, 0xf); - SSE3_HADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); - SSE3_HADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); - } - else { - SSE_MOVHLPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); // z, w, z, w - SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); // z+x, w+y, z+z, w+w - SSE_UNPCKLPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); // z+x, z+x, w+y, w+y - SSE_MOVHLPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); // w+y, w+y, w+y, w+y - SSE_ADDSS_XMM_to_XMM(EEREC_TEMP, EEREC_D); // x+y+z+w, w+y, w+y, w+y - } - - vuFloat_useEAX(info, EEREC_TEMP, 8); - SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ERCPR* -//------------------------------------------------------------------ -void recVUMI_ERCPR( VURegs *VU, int info ) -{ - assert( VU == &VU1 ); - //SysPrintf("VU1: ERCPR\n"); - - // don't use RCPSS (very bad precision) - switch ( _Fsf_ ) { - case 0: //0001 - if (CHECK_VU_EXTRA_OVERFLOW) vuFloat5_useEAX(EEREC_S, EEREC_TEMP, 8); - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)VU_ONE); // temp <- 1 - SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - break; - case 1: //0010 - SSE2_PSHUFLW_XMM_to_XMM(EEREC_S, EEREC_S, 0x4e); - if (CHECK_VU_EXTRA_OVERFLOW) vuFloat5_useEAX(EEREC_S, EEREC_TEMP, 8); - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)VU_ONE); // temp <- 1 - SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE2_PSHUFLW_XMM_to_XMM(EEREC_S, EEREC_S, 0x4e); - break; - case 2: //0100 - SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0xc6); - if (CHECK_VU_EXTRA_OVERFLOW) vuFloat5_useEAX(EEREC_S, EEREC_TEMP, 8); - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)VU_ONE); // temp <- 1 - SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0xc6); - break; - case 3: //1000 - SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0x27); - if (CHECK_VU_EXTRA_OVERFLOW) vuFloat5_useEAX(EEREC_S, EEREC_TEMP, 8); - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)VU_ONE); // temp <- 1 - SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0x27); - break; - } - - vuFloat_useEAX(info, EEREC_TEMP, 8); - SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ESQRT* -//------------------------------------------------------------------ -void recVUMI_ESQRT( VURegs *VU, int info ) -{ - assert( VU == &VU1 ); - - //SysPrintf("VU1: ESQRT\n"); - _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); - SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)const_clip); // abs(x) - if (CHECK_VU_OVERFLOW) SSE_MINSS_M32_to_XMM(EEREC_TEMP, (uptr)g_maxvals); // Only need to do positive clamp - SSE_SQRTSS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); - - SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ERSQRT* -//------------------------------------------------------------------ -void recVUMI_ERSQRT( VURegs *VU, int info ) -{ - int t1reg = _vuGetTempXMMreg(info); - - assert( VU == &VU1 ); - //SysPrintf("VU1: ERSQRT\n"); - - _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); - SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)const_clip); // abs(x) - SSE_MINSS_M32_to_XMM(EEREC_TEMP, (uptr)g_maxvals); // Clamp Infinities to Fmax - SSE_SQRTSS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); // SQRT(abs(x)) - - if( t1reg >= 0 ) - { - SSE_MOVSS_M32_to_XMM(t1reg, (uptr)VU_ONE); - SSE_DIVSS_XMM_to_XMM(t1reg, EEREC_TEMP); - vuFloat_useEAX(info, t1reg, 8); - SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), t1reg); - _freeXMMreg(t1reg); - } - else - { - SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)VU_ONE); - SSE_DIVSS_M32_to_XMM(EEREC_TEMP, VU_VI_ADDR(REG_P, 0)); - vuFloat_useEAX(info, EEREC_TEMP, 8); - SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ESIN -//------------------------------------------------------------------ -void recVUMI_ESIN( VURegs *VU, int info ) -{ - assert( VU == &VU1 ); - - //SysPrintf("recVUMI_ESIN \n"); - if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode&MODE_NOFLUSH) ) { - switch(_Fsf_) { - case 0: SSE_MOVSS_XMM_to_M32((uptr)s_tempmem, EEREC_S); - case 1: SSE_MOVLPS_XMM_to_M64((uptr)s_tempmem, EEREC_S); - default: SSE_MOVHPS_XMM_to_M64((uptr)&s_tempmem[2], EEREC_S); - } - FLD32((uptr)&s_tempmem[_Fsf_]); - } - else { - if( xmmregs[EEREC_S].mode & MODE_WRITE ) { - SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); - xmmregs[EEREC_S].mode &= ~MODE_WRITE; - } - - FLD32((uptr)&VU->VF[_Fs_].UL[_Fsf_]); - } - - FSIN(); - FSTP32(VU_VI_ADDR(REG_P, 0)); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// EATAN -//------------------------------------------------------------------ -void recVUMI_EATAN( VURegs *VU, int info ) -{ - assert( VU == &VU1 ); - - //SysPrintf("recVUMI_EATAN \n"); - if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode&MODE_NOFLUSH) ) { - switch(_Fsf_) { - case 0: SSE_MOVSS_XMM_to_M32((uptr)s_tempmem, EEREC_S); - case 1: SSE_MOVLPS_XMM_to_M64((uptr)s_tempmem, EEREC_S); - default: SSE_MOVHPS_XMM_to_M64((uptr)&s_tempmem[2], EEREC_S); - } - FLD32((uptr)&s_tempmem[_Fsf_]); - } - else { - if( xmmregs[EEREC_S].mode & MODE_WRITE ) { - SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); - xmmregs[EEREC_S].mode &= ~MODE_WRITE; - } - } - - FLD1(); - FLD32((uptr)&VU->VF[_Fs_].UL[_Fsf_]); - FPATAN(); - FSTP32(VU_VI_ADDR(REG_P, 0)); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// EEXP -//------------------------------------------------------------------ -void recVUMI_EEXP( VURegs *VU, int info ) -{ - assert( VU == &VU1 ); - //SysPrintf("recVUMI_EEXP \n"); - FLDL2E(); - - if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode&MODE_NOFLUSH) ) { - switch(_Fsf_) { - case 0: SSE_MOVSS_XMM_to_M32((uptr)s_tempmem, EEREC_S); - case 1: SSE_MOVLPS_XMM_to_M64((uptr)s_tempmem, EEREC_S); - default: SSE_MOVHPS_XMM_to_M64((uptr)&s_tempmem[2], EEREC_S); - } - FMUL32((uptr)&s_tempmem[_Fsf_]); - } - else { - if( xmmregs[EEREC_S].mode & MODE_WRITE ) { - SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); - xmmregs[EEREC_S].mode &= ~MODE_WRITE; - } - - FMUL32((uptr)&VU->VF[_Fs_].UL[_Fsf_]); - } - - // basically do 2^(log_2(e) * val) - FLD(0); - FRNDINT(); - FXCH(1); - FSUB32Rto0(1); - F2XM1(); - FLD1(); - FADD320toR(1); - FSCALE(); - FSTP(1); - - FSTP32(VU_VI_ADDR(REG_P, 0)); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// XITOP -//------------------------------------------------------------------ -void recVUMI_XITOP( VURegs *VU, int info ) -{ - int ftreg; - if (_Ft_ == 0) return; - //SysPrintf("recVUMI_XITOP \n"); - ftreg = ALLOCVI(_Ft_, MODE_WRITE); - MOVZX32M16toR( ftreg, (uptr)&VU->vifRegs->itop ); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// XTOP -//------------------------------------------------------------------ -void recVUMI_XTOP( VURegs *VU, int info ) -{ - int ftreg; - if ( _Ft_ == 0 ) return; - //SysPrintf("recVUMI_XTOP \n"); - ftreg = ALLOCVI(_Ft_, MODE_WRITE); - MOVZX32M16toR( ftreg, (uptr)&VU->vifRegs->top ); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// VU1XGKICK_MTGSTransfer() - Called by ivuZerorec.cpp -//------------------------------------------------------------------ -void VU1XGKICK_MTGSTransfer(u32 *pMem, u32 addr) -{ - u32 size; - u32* data = (u32*)((u8*)pMem + (addr&0x3fff)); - - // fixme: The gifTagDummy function in the MTGS (called by PrepDataPacket) has a - // hack that aborts the packet if it goes past the end of VU1 memory. - // Chances are this should be a "loops around memory" situation, and the packet - // should be continued starting at addr zero (0). - - size = mtgsThread->PrepDataPacket( GIF_PATH_1, data, (0x4000-(addr&0x3fff)) >> 4); - jASSUME( size > 0 ); - - //if( size > 0 ) - { - u8* pmem = mtgsThread->GetDataPacketPtr(); - memcpy_aligned(pmem, (u8*)pMem+addr, size<<4); - mtgsThread->SendDataPacket(); - } -} -//------------------------------------------------------------------ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "PrecompiledHeader.h" + +#include "Common.h" +#include "GS.h" +#include "R5900OpcodeTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "iMMI.h" +#include "iFPU.h" +#include "iCOP0.h" +#include "VUmicro.h" +#include "VUflags.h" +#include "iVUmicro.h" +#include "iVUops.h" +#include "iVUzerorec.h" +//------------------------------------------------------------------ + +//------------------------------------------------------------------ +// Helper Macros +//------------------------------------------------------------------ +#define _Ft_ (( VU->code >> 16) & 0x1F) // The rt part of the instruction register +#define _Fs_ (( VU->code >> 11) & 0x1F) // The rd part of the instruction register +#define _Fd_ (( VU->code >> 6) & 0x1F) // The sa part of the instruction register + +#define _X (( VU->code>>24) & 0x1) +#define _Y (( VU->code>>23) & 0x1) +#define _Z (( VU->code>>22) & 0x1) +#define _W (( VU->code>>21) & 0x1) + +#define _XYZW_SS (_X+_Y+_Z+_W==1) + +#define _Fsf_ (( VU->code >> 21) & 0x03) +#define _Ftf_ (( VU->code >> 23) & 0x03) + +#define _Imm11_ (s32)(VU->code & 0x400 ? 0xfffffc00 | (VU->code & 0x3ff) : VU->code & 0x3ff) +#define _UImm11_ (s32)(VU->code & 0x7ff) + +#define VU_VFx_ADDR(x) (uptr)&VU->VF[x].UL[0] +#define VU_VFy_ADDR(x) (uptr)&VU->VF[x].UL[1] +#define VU_VFz_ADDR(x) (uptr)&VU->VF[x].UL[2] +#define VU_VFw_ADDR(x) (uptr)&VU->VF[x].UL[3] + +#define VU_REGR_ADDR (uptr)&VU->VI[REG_R] +#define VU_REGQ_ADDR (uptr)&VU->VI[REG_Q] +#define VU_REGMAC_ADDR (uptr)&VU->VI[REG_MAC_FLAG] + +#define VU_VI_ADDR(x, read) GetVIAddr(VU, x, read, info) + +#define VU_ACCx_ADDR (uptr)&VU->ACC.UL[0] +#define VU_ACCy_ADDR (uptr)&VU->ACC.UL[1] +#define VU_ACCz_ADDR (uptr)&VU->ACC.UL[2] +#define VU_ACCw_ADDR (uptr)&VU->ACC.UL[3] + +#define _X_Y_Z_W ((( VU->code >> 21 ) & 0xF ) ) + + +static const PCSX2_ALIGNED16(u32 VU_ONE[4]) = {0x3f800000, 0xffffffff, 0xffffffff, 0xffffffff}; +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// *VU Lower Instructions!* +// +// Note: * = Checked for errors by cottonvibes +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// DIV* +//------------------------------------------------------------------ +PCSX2_ALIGNED16(u64 DIV_TEMP_XMM[2]); +void recVUMI_DIV(VURegs *VU, int info) +{ + u8 *pjmp, *pjmp1; + u32 *ajmp32, *bjmp32; + + //SysPrintf("recVUMI_DIV()\n"); + AND32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0xFCF); // Clear D/I flags + + // FT can be zero here! so we need to check if its zero and set the correct flag. + SSE_XORPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); // Clear EEREC_TEMP + SSE_CMPEQPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); // Set all F's if each vector is zero + + SSE_MOVMSKPS_XMM_to_R32( EAX, EEREC_TEMP); // Move the sign bits of the previous calculation + + AND32ItoR( EAX, (1<<_Ftf_) ); // Grab "Is Zero" bits from the previous calculation + ajmp32 = JZ32(0); // Skip if none are + + SSE_XORPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); // Clear EEREC_TEMP + SSE_CMPEQPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); // Set all F's if each vector is zero + SSE_MOVMSKPS_XMM_to_R32(EAX, EEREC_TEMP); // Move the sign bits of the previous calculation + + AND32ItoR( EAX, (1<<_Fsf_) ); // Grab "Is Zero" bits from the previous calculation + pjmp = JZ8(0); + OR32ItoM( VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x410 ); // Set invalid flag (0/0) + pjmp1 = JMP8(0); + x86SetJ8(pjmp); + OR32ItoM( VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x820 ); // Zero divide (only when not 0/0) + x86SetJ8(pjmp1); + + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); + + _vuFlipRegSS_xyzw(EEREC_T, _Ftf_); + SSE_XORPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + _vuFlipRegSS_xyzw(EEREC_T, _Ftf_); + + SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); + SSE_ORPS_M128_to_XMM(EEREC_TEMP, (uptr)&g_maxvals[0]); // If division by zero, then EEREC_TEMP = +/- fmax + + bjmp32 = JMP32(0); + + x86SetJ32(ajmp32); + + if (CHECK_VU_EXTRA_OVERFLOW) { + vuFloat5_useEAX(EEREC_S, EEREC_TEMP, (1 << (3-_Fsf_))); + vuFloat5_useEAX(EEREC_T, EEREC_TEMP, (1 << (3-_Ftf_))); + } + + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); + + _vuFlipRegSS_xyzw(EEREC_T, _Ftf_); + SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + _vuFlipRegSS_xyzw(EEREC_T, _Ftf_); + + vuFloat_useEAX(info, EEREC_TEMP, 0x8); + + x86SetJ32(bjmp32); + + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_Q, 0), EEREC_TEMP); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// SQRT* +//------------------------------------------------------------------ +void recVUMI_SQRT( VURegs *VU, int info ) +{ + u8* pjmp; + //SysPrintf("recVUMI_SQRT()\n"); + + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, _Ftf_); + AND32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0xFCF); // Clear D/I flags + + /* Check for negative sqrt */ + SSE_MOVMSKPS_XMM_to_R32(EAX, EEREC_TEMP); + AND32ItoR(EAX, 1); //Check sign + pjmp = JZ8(0); //Skip if none are + OR32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x410); // Invalid Flag - Negative number sqrt + x86SetJ8(pjmp); + + SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)const_clip); // Do a cardinal sqrt + if (CHECK_VU_OVERFLOW) SSE_MINSS_M32_to_XMM(EEREC_TEMP, (uptr)g_maxvals); // Clamp infinities (only need to do positive clamp since EEREC_TEMP is positive) + SSE_SQRTSS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_Q, 0), EEREC_TEMP); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// RSQRT* +//------------------------------------------------------------------ +PCSX2_ALIGNED16(u64 RSQRT_TEMP_XMM[2]); +void recVUMI_RSQRT(VURegs *VU, int info) +{ + u8 *ajmp8, *bjmp8; + int t1reg, t1boolean; + //SysPrintf("recVUMI_RSQRT()\n"); + + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, _Ftf_); + AND32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0xFCF); // Clear D/I flags + + /* Check for negative divide */ + SSE_MOVMSKPS_XMM_to_R32(EAX, EEREC_TEMP); + AND32ItoR(EAX, 1); //Check sign + ajmp8 = JZ8(0); //Skip if none are + OR32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x410); // Invalid Flag - Negative number sqrt + x86SetJ8(ajmp8); + + SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)const_clip); // Do a cardinal sqrt + if (CHECK_VU_OVERFLOW) SSE_MINSS_M32_to_XMM(EEREC_TEMP, (uptr)g_maxvals); // Clamp Infinities to Fmax + SSE_SQRTSS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + + t1reg = _vuGetTempXMMreg(info); + if( t1reg < 0 ) { + for (t1reg = 0; ( (t1reg == EEREC_TEMP) || (t1reg == EEREC_S) ); t1reg++) + ; // Makes t1reg not be EEREC_TEMP or EEREC_S. + SSE_MOVAPS_XMM_to_M128( (uptr)&RSQRT_TEMP_XMM[0], t1reg ); // backup data in t1reg to a temp address + t1boolean = 1; + } + else t1boolean = 0; + + // Ft can still be zero here! so we need to check if its zero and set the correct flag. + SSE_XORPS_XMM_to_XMM(t1reg, t1reg); // Clear t1reg + SSE_CMPEQSS_XMM_to_XMM(t1reg, EEREC_TEMP); // Set all F's if each vector is zero + + SSE_MOVMSKPS_XMM_to_R32(EAX, t1reg); // Move the sign bits of the previous calculation + + AND32ItoR( EAX, 0x01 ); // Grab "Is Zero" bits from the previous calculation + ajmp8 = JZ8(0); // Skip if none are + OR32ItoM(VU_VI_ADDR(REG_STATUS_FLAG, 2), 0x820); // Zero divide flag + + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); + SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); + SSE_ORPS_M128_to_XMM(EEREC_TEMP, (uptr)&g_maxvals[0]); // EEREC_TEMP = +/-Max + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_Q, 0), EEREC_TEMP); + bjmp8 = JMP8(0); + x86SetJ8(ajmp8); + + _unpackVFSS_xyzw(t1reg, EEREC_S, _Fsf_); + if (CHECK_VU_EXTRA_OVERFLOW) vuFloat_useEAX(info, t1reg, 0x8); // Clamp Infinities + SSE_DIVSS_XMM_to_XMM(t1reg, EEREC_TEMP); + vuFloat_useEAX(info, t1reg, 0x8); + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_Q, 0), t1reg); + + x86SetJ8(bjmp8); + + if (t1boolean) SSE_MOVAPS_M128_to_XMM( t1reg, (uptr)&RSQRT_TEMP_XMM[0] ); // restore t1reg data + else _freeXMMreg(t1reg); // free t1reg +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// _addISIMMtoIT() - Used in IADDI, IADDIU, and ISUBIU instructions +//------------------------------------------------------------------ +void _addISIMMtoIT(VURegs *VU, s16 imm, int info) +{ + int fsreg = -1, ftreg; + if (_Ft_ == 0) return; + + if( _Fs_ == 0 ) { + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + MOV32ItoR(ftreg, imm&0xffff); + return; + } + + ADD_VI_NEEDED(_Ft_); + fsreg = ALLOCVI(_Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + + if ( _Ft_ == _Fs_ ) { + if (imm != 0 ) ADD16ItoR(ftreg, imm); + } + else { + if( imm ) { + LEA32RtoR(ftreg, fsreg, imm); + MOVZX32R16toR(ftreg, ftreg); + } + else MOV32RtoR(ftreg, fsreg); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// IADDI +//------------------------------------------------------------------ +void recVUMI_IADDI(VURegs *VU, int info) +{ + s16 imm; + + if ( _Ft_ == 0 ) return; + //SysPrintf("recVUMI_IADDI \n"); + imm = ( VU->code >> 6 ) & 0x1f; + imm = ( imm & 0x10 ? 0xfff0 : 0) | ( imm & 0xf ); + _addISIMMtoIT(VU, imm, info); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// IADDIU +//------------------------------------------------------------------ +void recVUMI_IADDIU(VURegs *VU, int info) +{ + s16 imm; + + if ( _Ft_ == 0 ) return; + //SysPrintf("recVUMI_IADDIU \n"); + imm = ( ( VU->code >> 10 ) & 0x7800 ) | ( VU->code & 0x7ff ); + _addISIMMtoIT(VU, imm, info); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// IADD +//------------------------------------------------------------------ +void recVUMI_IADD( VURegs *VU, int info ) +{ + int fdreg, fsreg = -1, ftreg = -1; + if ( _Fd_ == 0 ) return; + //SysPrintf("recVUMI_IADD \n"); + if ( ( _Ft_ == 0 ) && ( _Fs_ == 0 ) ) { + fdreg = ALLOCVI(_Fd_, MODE_WRITE); + XOR32RtoR(fdreg, fdreg); + return; + } + + ADD_VI_NEEDED(_Fs_); + ADD_VI_NEEDED(_Ft_); + fdreg = ALLOCVI(_Fd_, MODE_WRITE); + + if ( _Fs_ == 0 ) + { + if( (ftreg = _checkX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Ft_, MODE_READ)) >= 0 ) { + if( fdreg != ftreg ) MOV32RtoR(fdreg, ftreg); + } + else MOVZX32M16toR(fdreg, VU_VI_ADDR(_Ft_, 1)); + } + else if ( _Ft_ == 0 ) + { + if( (fsreg = _checkX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Fs_, MODE_READ)) >= 0 ) { + if( fdreg != fsreg ) MOV32RtoR(fdreg, fsreg); + } + else MOVZX32M16toR(fdreg, VU_VI_ADDR(_Fs_, 1)); + } + else { + //ADD_VI_NEEDED(_Ft_); + fsreg = ALLOCVI(_Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_READ); + + if( fdreg == fsreg ) ADD32RtoR(fdreg, ftreg); + else if( fdreg == ftreg ) ADD32RtoR(fdreg, fsreg); + else LEA16RRtoR(fdreg, fsreg, ftreg); + MOVZX32R16toR(fdreg, fdreg); // neeed since don't know if fdreg's upper bits are 0 + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// IAND +//------------------------------------------------------------------ +void recVUMI_IAND( VURegs *VU, int info ) +{ + int fdreg, fsreg = -1, ftreg = -1; + if ( _Fd_ == 0 ) return; + //SysPrintf("recVUMI_IAND \n"); + if ( ( _Fs_ == 0 ) || ( _Ft_ == 0 ) ) { + fdreg = ALLOCVI(_Fd_, MODE_WRITE); + XOR32RtoR(fdreg, fdreg); + return; + } + + ADD_VI_NEEDED(_Fs_); + ADD_VI_NEEDED(_Ft_); + fdreg = ALLOCVI(_Fd_, MODE_WRITE); + + fsreg = ALLOCVI(_Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_READ); + + if( fdreg == fsreg ) AND16RtoR(fdreg, ftreg); + else if( fdreg == ftreg ) AND16RtoR(fdreg, fsreg); + else { + MOV32RtoR(fdreg, ftreg); + AND32RtoR(fdreg, fsreg); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// IOR +//------------------------------------------------------------------ +void recVUMI_IOR( VURegs *VU, int info ) +{ + int fdreg, fsreg = -1, ftreg = -1; + if ( _Fd_ == 0 ) return; + //SysPrintf("recVUMI_IOR \n"); + if ( ( _Ft_ == 0 ) && ( _Fs_ == 0 ) ) { + fdreg = ALLOCVI(_Fd_, MODE_WRITE); + XOR32RtoR(fdreg, fdreg); + return; + } + + ADD_VI_NEEDED(_Fs_); + ADD_VI_NEEDED(_Ft_); + fdreg = ALLOCVI(_Fd_, MODE_WRITE); + + if ( _Fs_ == 0 ) + { + if( (ftreg = _checkX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Ft_, MODE_READ)) >= 0 ) { + if( fdreg != ftreg ) MOV32RtoR(fdreg, ftreg); + } + else MOVZX32M16toR(fdreg, VU_VI_ADDR(_Ft_, 1)); + } + else if ( _Ft_ == 0 ) + { + if( (fsreg = _checkX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Fs_, MODE_READ)) >= 0 ) { + if( fdreg != fsreg ) MOV32RtoR(fdreg, fsreg); + } + else MOVZX32M16toR(fdreg, VU_VI_ADDR(_Fs_, 1)); + } + else + { + fsreg = ALLOCVI(_Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_READ); + + if( fdreg == fsreg ) OR16RtoR(fdreg, ftreg); + else if( fdreg == ftreg ) OR16RtoR(fdreg, fsreg); + else { + MOV32RtoR(fdreg, fsreg); + OR32RtoR(fdreg, ftreg); + } + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ISUB +//------------------------------------------------------------------ +void recVUMI_ISUB( VURegs *VU, int info ) +{ + int fdreg, fsreg = -1, ftreg = -1; + if ( _Fd_ == 0 ) return; + //SysPrintf("recVUMI_ISUB \n"); + if ( ( _Ft_ == 0 ) && ( _Fs_ == 0 ) ) { + fdreg = ALLOCVI(_Fd_, MODE_WRITE); + XOR32RtoR(fdreg, fdreg); + return; + } + + ADD_VI_NEEDED(_Fs_); + ADD_VI_NEEDED(_Ft_); + fdreg = ALLOCVI(_Fd_, MODE_WRITE); + + if ( _Fs_ == 0 ) + { + if( (ftreg = _checkX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Ft_, MODE_READ)) >= 0 ) { + if( fdreg != ftreg ) MOV32RtoR(fdreg, ftreg); + } + else MOVZX32M16toR(fdreg, VU_VI_ADDR(_Ft_, 1)); + NEG16R(fdreg); + } + else if ( _Ft_ == 0 ) + { + if( (fsreg = _checkX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Fs_, MODE_READ)) >= 0 ) { + if( fdreg != fsreg ) MOV32RtoR(fdreg, fsreg); + } + else MOVZX32M16toR(fdreg, VU_VI_ADDR(_Fs_, 1)); + } + else + { + fsreg = ALLOCVI(_Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_READ); + + if( fdreg == fsreg ) SUB16RtoR(fdreg, ftreg); + else if( fdreg == ftreg ) { + SUB16RtoR(fdreg, fsreg); + NEG16R(fdreg); + } + else { + MOV32RtoR(fdreg, fsreg); + SUB16RtoR(fdreg, ftreg); + } + } +} +//------------------------------------------------------------------ + +//------------------------------------------------------------------ +// ISUBIU +//------------------------------------------------------------------ +void recVUMI_ISUBIU( VURegs *VU, int info ) +{ + s16 imm; + + if ( _Ft_ == 0 ) return; + //SysPrintf("recVUMI_ISUBIU \n"); + imm = ( ( VU->code >> 10 ) & 0x7800 ) | ( VU->code & 0x7ff ); + imm = -imm; + _addISIMMtoIT(VU, imm, info); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// MOVE* +//------------------------------------------------------------------ +void recVUMI_MOVE( VURegs *VU, int info ) +{ + if ( (_Ft_ == 0) || (_X_Y_Z_W == 0) ) return; + //SysPrintf("recVUMI_MOVE \n"); + if (_X_Y_Z_W == 0x8) SSE_MOVSS_XMM_to_XMM(EEREC_T, EEREC_S); + else if (_X_Y_Z_W == 0xf) SSE_MOVAPS_XMM_to_XMM(EEREC_T, EEREC_S); + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// MFIR* +//------------------------------------------------------------------ +void recVUMI_MFIR( VURegs *VU, int info ) +{ + if ( (_Ft_ == 0) || (_X_Y_Z_W == 0) ) return; + //SysPrintf("recVUMI_MFIR \n"); + _deleteX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Fs_, 1); + + if( _XYZW_SS ) { + SSE2_MOVD_M32_to_XMM(EEREC_TEMP, VU_VI_ADDR(_Fs_, 1)-2); + _vuFlipRegSS(VU, EEREC_T); + SSE2_PSRAD_I8_to_XMM(EEREC_TEMP, 16); + SSE_MOVSS_XMM_to_XMM(EEREC_T, EEREC_TEMP); + _vuFlipRegSS(VU, EEREC_T); + } + else if (_X_Y_Z_W != 0xf) { + SSE2_MOVD_M32_to_XMM(EEREC_TEMP, VU_VI_ADDR(_Fs_, 1)-2); + SSE2_PSRAD_I8_to_XMM(EEREC_TEMP, 16); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0); + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + } + else { + SSE2_MOVD_M32_to_XMM(EEREC_T, VU_VI_ADDR(_Fs_, 1)-2); + SSE2_PSRAD_I8_to_XMM(EEREC_T, 16); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// MTIR* +//------------------------------------------------------------------ +void recVUMI_MTIR( VURegs *VU, int info ) +{ + if ( _Ft_ == 0 ) return; + //SysPrintf("recVUMI_MTIR \n"); + _deleteX86reg(X86TYPE_VI|((VU==&VU1)?X86TYPE_VU1:0), _Ft_, 2); + + if( _Fsf_ == 0 ) { + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(_Ft_, 0), EEREC_S); + } + else { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(_Ft_, 0), EEREC_TEMP); + } + + AND32ItoM(VU_VI_ADDR(_Ft_, 0), 0xffff); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// MR32* +//------------------------------------------------------------------ +void recVUMI_MR32( VURegs *VU, int info ) +{ + if ( (_Ft_ == 0) || (_X_Y_Z_W == 0) ) return; + //SysPrintf("recVUMI_MR32 \n"); + if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x39); + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + } + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_T, EEREC_S); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0x39); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// _loadEAX() +// +// NOTE: If x86reg < 0, reads directly from offset +//------------------------------------------------------------------ +void _loadEAX(VURegs *VU, int x86reg, uptr offset, int info) +{ + assert( offset < 0x80000000 ); + + if( x86reg >= 0 ) { + switch(_X_Y_Z_W) { + case 3: // ZW + SSE_MOVHPS_RmOffset_to_XMM(EEREC_T, x86reg, offset+8); + break; + case 6: // YZ + SSE_SHUFPS_RmOffset_to_XMM(EEREC_T, x86reg, offset, 0x9c); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0x78); + break; + + case 8: // X + SSE_MOVSS_RmOffset_to_XMM(EEREC_TEMP, x86reg, offset); + SSE_MOVSS_XMM_to_XMM(EEREC_T, EEREC_TEMP); + break; + case 9: // XW + SSE_SHUFPS_RmOffset_to_XMM(EEREC_T, x86reg, offset, 0xc9); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0xd2); + break; + case 12: // XY + SSE_MOVLPS_RmOffset_to_XMM(EEREC_T, x86reg, offset); + break; + case 15: + if( VU == &VU1 ) SSE_MOVAPSRmtoROffset(EEREC_T, x86reg, offset); + else SSE_MOVUPSRmtoROffset(EEREC_T, x86reg, offset); + break; + default: + if( VU == &VU1 ) SSE_MOVAPSRmtoROffset(EEREC_TEMP, x86reg, offset); + else SSE_MOVUPSRmtoROffset(EEREC_TEMP, x86reg, offset); + + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + break; + } + } + else { + switch(_X_Y_Z_W) { + case 3: // ZW + SSE_MOVHPS_M64_to_XMM(EEREC_T, offset+8); + break; + case 6: // YZ + SSE_SHUFPS_M128_to_XMM(EEREC_T, offset, 0x9c); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0x78); + break; + case 8: // X + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, offset); + SSE_MOVSS_XMM_to_XMM(EEREC_T, EEREC_TEMP); + break; + case 9: // XW + SSE_SHUFPS_M128_to_XMM(EEREC_T, offset, 0xc9); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0xd2); + break; + case 12: // XY + SSE_MOVLPS_M64_to_XMM(EEREC_T, offset); + break; + case 15: + if( VU == &VU1 ) SSE_MOVAPS_M128_to_XMM(EEREC_T, offset); + else SSE_MOVUPS_M128_to_XMM(EEREC_T, offset); + break; + default: + if( VU == &VU1 ) SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, offset); + else SSE_MOVUPS_M128_to_XMM(EEREC_TEMP, offset); + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + break; + } + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// recVUTransformAddr() +//------------------------------------------------------------------ +int recVUTransformAddr(int x86reg, VURegs* VU, int vireg, int imm) +{ + u8* pjmp[2]; + if( x86reg == EAX ) { + if (imm) ADD32ItoR(x86reg, imm); + } + else { + if( imm ) LEA32RtoR(EAX, x86reg, imm); + else MOV32RtoR(EAX, x86reg); + } + + if( VU == &VU1 ) { + AND32ItoR(EAX, 0x3ff); // wrap around + SHL32ItoR(EAX, 4); + } + else { + + // VU0 has a somewhat interesting memory mapping: + // if addr >= 0x4000, reads VU1's VF regs and VI regs + // if addr < 0x4000, wrap around at 0x1000 + + CMP32ItoR(EAX, 0x400); + pjmp[0] = JL8(0); // if addr >= 0x4000, reads VU1's VF regs and VI regs + AND32ItoR(EAX, 0x43f); + pjmp[1] = JMP8(0); + x86SetJ8(pjmp[0]); + AND32ItoR(EAX, 0xff); // if addr < 0x4000, wrap around + x86SetJ8(pjmp[1]); + + SHL32ItoR(EAX, 4); // multiply by 16 (shift left by 4) + } + + return EAX; +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// LQ +//------------------------------------------------------------------ +void recVUMI_LQ(VURegs *VU, int info) +{ + s16 imm; + if ( _Ft_ == 0 ) return; + //SysPrintf("recVUMI_LQ \n"); + imm = (VU->code & 0x400) ? (VU->code & 0x3ff) | 0xfc00 : (VU->code & 0x3ff); + if (_Fs_ == 0) { + _loadEAX(VU, -1, (uptr)GET_VU_MEM(VU, (u32)imm*16), info); + } + else { + int fsreg = ALLOCVI(_Fs_, MODE_READ); + _loadEAX(VU, recVUTransformAddr(fsreg, VU, _Fs_, imm), (uptr)VU->Mem, info); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// LQD +//------------------------------------------------------------------ +void recVUMI_LQD( VURegs *VU, int info ) +{ + int fsreg; + //SysPrintf("recVUMI_LQD \n"); + if ( _Fs_ != 0 ) { + fsreg = ALLOCVI(_Fs_, MODE_READ|MODE_WRITE); + SUB16ItoR( fsreg, 1 ); + } + + if ( _Ft_ == 0 ) return; + + if ( _Fs_ == 0 ) _loadEAX(VU, -1, (uptr)VU->Mem, info); + else _loadEAX(VU, recVUTransformAddr(fsreg, VU, _Fs_, 0), (uptr)VU->Mem, info); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// LQI +//------------------------------------------------------------------ +void recVUMI_LQI(VURegs *VU, int info) +{ + int fsreg; + //SysPrintf("recVUMI_LQI \n"); + if ( _Ft_ == 0 ) { + if( _Fs_ != 0 ) { + if( (fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_WRITE|MODE_READ)) >= 0 ) { + ADD16ItoR(fsreg, 1); + } + else { + ADD16ItoM( VU_VI_ADDR( _Fs_, 0 ), 1 ); + } + } + return; + } + + if (_Fs_ == 0) { + _loadEAX(VU, -1, (uptr)VU->Mem, info); + } + else { + fsreg = ALLOCVI(_Fs_, MODE_READ|MODE_WRITE); + _loadEAX(VU, recVUTransformAddr(fsreg, VU, _Fs_, 0), (uptr)VU->Mem, info); + ADD16ItoR( fsreg, 1 ); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// _saveEAX() +//------------------------------------------------------------------ +void _saveEAX(VURegs *VU, int x86reg, uptr offset, int info) +{ + assert( offset < 0x80000000 ); + + if ( _Fs_ == 0 ) { + if ( _XYZW_SS ) { + u32 c = _W ? 0x3f800000 : 0; + if ( x86reg >= 0 ) MOV32ItoRmOffset(x86reg, c, offset+(_W?12:(_Z?8:(_Y?4:0)))); + else MOV32ItoM(offset+(_W?12:(_Z?8:(_Y?4:0))), c); + } + else { + if ( x86reg >= 0 ) { + if ( _X ) MOV32ItoRmOffset(x86reg, 0x00000000, offset); + if ( _Y ) MOV32ItoRmOffset(x86reg, 0x00000000, offset+4); + if ( _Z ) MOV32ItoRmOffset(x86reg, 0x00000000, offset+8); + if ( _W ) MOV32ItoRmOffset(x86reg, 0x3f800000, offset+12); + } + else { + if ( _X ) MOV32ItoM(offset, 0x00000000); + if ( _Y ) MOV32ItoM(offset+4, 0x00000000); + if ( _Z ) MOV32ItoM(offset+8, 0x00000000); + if ( _W ) MOV32ItoM(offset+12, 0x3f800000); + } + } + return; + } + + switch ( _X_Y_Z_W ) { + case 1: // W + SSE2_PSHUFD_XMM_to_XMM(EEREC_TEMP, EEREC_S, 0x27); + if ( x86reg >= 0 ) SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+12); + else SSE_MOVSS_XMM_to_M32(offset+12, EEREC_TEMP); + break; + case 2: // Z + SSE_MOVHLPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if ( x86reg >= 0 ) SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+8); + else SSE_MOVSS_XMM_to_M32(offset+8, EEREC_TEMP); + break; + case 3: // ZW + if ( x86reg >= 0 ) SSE_MOVHPS_XMM_to_RmOffset(x86reg, EEREC_S, offset+8); + else SSE_MOVHPS_XMM_to_M64(offset+8, EEREC_S); + break; + case 4: // Y + SSE2_PSHUFLW_XMM_to_XMM(EEREC_TEMP, EEREC_S, 0x4e); + if ( x86reg >= 0 ) SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+4); + else SSE_MOVSS_XMM_to_M32(offset+4, EEREC_TEMP); + break; + case 5: // YW + SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0xB1); + SSE_MOVHLPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if ( x86reg >= 0 ) { + SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_S, offset+4); + SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+12); + } + else { + SSE_MOVSS_XMM_to_M32(offset+4, EEREC_S); + SSE_MOVSS_XMM_to_M32(offset+12, EEREC_TEMP); + } + SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0xB1); + break; + case 6: // YZ + SSE2_PSHUFD_XMM_to_XMM(EEREC_TEMP, EEREC_S, 0xc9); + if ( x86reg >= 0 ) SSE_MOVLPS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+4); + else SSE_MOVLPS_XMM_to_M64(offset+4, EEREC_TEMP); + break; + case 7: // YZW + SSE2_PSHUFD_XMM_to_XMM(EEREC_TEMP, EEREC_S, 0x93); //ZYXW + if ( x86reg >= 0 ) { + SSE_MOVHPS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+4); + SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+12); + } + else { + SSE_MOVHPS_XMM_to_M64(offset+4, EEREC_TEMP); + SSE_MOVSS_XMM_to_M32(offset+12, EEREC_TEMP); + } + break; + case 8: // X + if ( x86reg >= 0 ) SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_S, offset); + else SSE_MOVSS_XMM_to_M32(offset, EEREC_S); + break; + case 9: // XW + SSE_MOVHLPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if ( x86reg >= 0 ) SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_S, offset); + else SSE_MOVSS_XMM_to_M32(offset, EEREC_S); + + if ( cpucaps.hasStreamingSIMD3Extensions ) SSE3_MOVSLDUP_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + else SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x55); + + if ( x86reg >= 0 ) SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+12); + else SSE_MOVSS_XMM_to_M32(offset+12, EEREC_TEMP); + + break; + case 10: //XZ + SSE_MOVHLPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if ( x86reg >= 0 ) { + SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_S, offset); + SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+8); + } + else { + SSE_MOVSS_XMM_to_M32(offset, EEREC_S); + SSE_MOVSS_XMM_to_M32(offset+8, EEREC_TEMP); + } + break; + case 11: //XZW + if ( x86reg >= 0 ) { + SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_S, offset); + SSE_MOVHPS_XMM_to_RmOffset(x86reg, EEREC_S, offset+8); + } + else { + SSE_MOVSS_XMM_to_M32(offset, EEREC_S); + SSE_MOVHPS_XMM_to_M64(offset+8, EEREC_S); + } + break; + case 12: // XY + if ( x86reg >= 0 ) SSE_MOVLPS_XMM_to_RmOffset(x86reg, EEREC_S, offset+0); + else SSE_MOVLPS_XMM_to_M64(offset, EEREC_S); + break; + case 13: // XYW + SSE2_PSHUFD_XMM_to_XMM(EEREC_TEMP, EEREC_S, 0x4b); //YXZW + if ( x86reg >= 0 ) { + SSE_MOVHPS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+0); + SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+12); + } + else { + SSE_MOVHPS_XMM_to_M64(offset, EEREC_TEMP); + SSE_MOVSS_XMM_to_M32(offset+12, EEREC_TEMP); + } + break; + case 14: // XYZ + SSE_MOVHLPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if ( x86reg >= 0 ) { + SSE_MOVLPS_XMM_to_RmOffset(x86reg, EEREC_S, offset+0); + SSE_MOVSS_XMM_to_RmOffset(x86reg, EEREC_TEMP, offset+8); + } + else { + SSE_MOVLPS_XMM_to_M64(offset, EEREC_S); + SSE_MOVSS_XMM_to_M32(offset+8, EEREC_TEMP); + } + break; + case 15: // XYZW + if ( VU == &VU1 ) { + if( x86reg >= 0 ) SSE_MOVAPSRtoRmOffset(x86reg, EEREC_S, offset+0); + else SSE_MOVAPS_XMM_to_M128(offset, EEREC_S); + } + else { + if( x86reg >= 0 ) SSE_MOVUPSRtoRmOffset(x86reg, EEREC_S, offset+0); + else { + if( offset & 15 ) SSE_MOVUPS_XMM_to_M128(offset, EEREC_S); + else SSE_MOVAPS_XMM_to_M128(offset, EEREC_S); + } + } + break; + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// SQ +//------------------------------------------------------------------ +void recVUMI_SQ(VURegs *VU, int info) +{ + s16 imm; + //SysPrintf("recVUMI_SQ \n"); + imm = ( VU->code & 0x400) ? ( VU->code & 0x3ff) | 0xfc00 : ( VU->code & 0x3ff); + if ( _Ft_ == 0 ) _saveEAX(VU, -1, (uptr)GET_VU_MEM(VU, (int)imm * 16), info); + else { + int ftreg = ALLOCVI(_Ft_, MODE_READ); + _saveEAX(VU, recVUTransformAddr(ftreg, VU, _Ft_, imm), (uptr)VU->Mem, info); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// SQD +//------------------------------------------------------------------ +void recVUMI_SQD(VURegs *VU, int info) +{ + //SysPrintf("recVUMI_SQD \n"); + if (_Ft_ == 0) _saveEAX(VU, -1, (uptr)VU->Mem, info); + else { + int ftreg = ALLOCVI(_Ft_, MODE_READ|MODE_WRITE); + SUB16ItoR( ftreg, 1 ); + _saveEAX(VU, recVUTransformAddr(ftreg, VU, _Ft_, 0), (uptr)VU->Mem, info); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// SQI +//------------------------------------------------------------------ +void recVUMI_SQI(VURegs *VU, int info) +{ + //SysPrintf("recVUMI_SQI \n"); + if (_Ft_ == 0) _saveEAX(VU, -1, (uptr)VU->Mem, info); + else { + int ftreg = ALLOCVI(_Ft_, MODE_READ|MODE_WRITE); + _saveEAX(VU, recVUTransformAddr(ftreg, VU, _Ft_, 0), (uptr)VU->Mem, info); + ADD16ItoR( ftreg, 1 ); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ILW +//------------------------------------------------------------------ +void recVUMI_ILW(VURegs *VU, int info) +{ + int ftreg; + s16 imm, off; + + if ( ( _Ft_ == 0 ) || ( _X_Y_Z_W == 0 ) ) return; + //SysPrintf("recVUMI_ILW \n"); + imm = ( VU->code & 0x400) ? ( VU->code & 0x3ff) | 0xfc00 : ( VU->code & 0x3ff); + if (_X) off = 0; + else if (_Y) off = 4; + else if (_Z) off = 8; + else if (_W) off = 12; + + ADD_VI_NEEDED(_Fs_); + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + + if ( _Fs_ == 0 ) { + MOVZX32M16toR( ftreg, (uptr)GET_VU_MEM(VU, (int)imm * 16 + off) ); + } + else { + int fsreg = ALLOCVI(_Fs_, MODE_READ); + MOV32RmtoROffset(ftreg, recVUTransformAddr(fsreg, VU, _Fs_, imm), (uptr)VU->Mem + off); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ISW +//------------------------------------------------------------------ +void recVUMI_ISW( VURegs *VU, int info ) +{ + s16 imm; + //SysPrintf("recVUMI_ISW \n"); + imm = ( VU->code & 0x400) ? ( VU->code & 0x3ff) | 0xfc00 : ( VU->code & 0x3ff); + + if (_Fs_ == 0) { + uptr off = (uptr)GET_VU_MEM(VU, (int)imm * 16); + int ftreg = ALLOCVI(_Ft_, MODE_READ); + + if (_X) MOV32RtoM(off, ftreg); + if (_Y) MOV32RtoM(off+4, ftreg); + if (_Z) MOV32RtoM(off+8, ftreg); + if (_W) MOV32RtoM(off+12, ftreg); + } + else { + int x86reg, fsreg, ftreg; + + ADD_VI_NEEDED(_Ft_); + fsreg = ALLOCVI(_Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_READ); + + x86reg = recVUTransformAddr(fsreg, VU, _Fs_, imm); + + if (_X) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem); + if (_Y) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem+4); + if (_Z) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem+8); + if (_W) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem+12); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ILWR +//------------------------------------------------------------------ +void recVUMI_ILWR( VURegs *VU, int info ) +{ + int off, ftreg; + + if ( ( _Ft_ == 0 ) || ( _X_Y_Z_W == 0 ) ) return; + //SysPrintf("recVUMI_ILWR \n"); + if (_X) off = 0; + else if (_Y) off = 4; + else if (_Z) off = 8; + else if (_W) off = 12; + + ADD_VI_NEEDED(_Fs_); + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + + if ( _Fs_ == 0 ) { + MOVZX32M16toR( ftreg, (uptr)VU->Mem + off ); + } + else { + int fsreg = ALLOCVI(_Fs_, MODE_READ); + MOVZX32Rm16toROffset(ftreg, recVUTransformAddr(fsreg, VU, _Fs_, 0), (uptr)VU->Mem + off); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ISWR +//------------------------------------------------------------------ +void recVUMI_ISWR( VURegs *VU, int info ) +{ + int ftreg; + //SysPrintf("recVUMI_ISWR \n"); + ADD_VI_NEEDED(_Fs_); + ftreg = ALLOCVI(_Ft_, MODE_READ); + + if (_Fs_ == 0) { + if (_X) MOV32RtoM((uptr)VU->Mem, ftreg); + if (_Y) MOV32RtoM((uptr)VU->Mem+4, ftreg); + if (_Z) MOV32RtoM((uptr)VU->Mem+8, ftreg); + if (_W) MOV32RtoM((uptr)VU->Mem+12, ftreg); + } + else { + int x86reg; + int fsreg = ALLOCVI(_Fs_, MODE_READ); + x86reg = recVUTransformAddr(fsreg, VU, _Fs_, 0); + + if (_X) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem); + if (_Y) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem+4); + if (_Z) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem+8); + if (_W) MOV32RtoRmOffset(x86reg, ftreg, (uptr)VU->Mem+12); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// RINIT* +//------------------------------------------------------------------ +void recVUMI_RINIT(VURegs *VU, int info) +{ + //SysPrintf("recVUMI_RINIT()\n"); + if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode & MODE_NOFLUSH) ) { + _deleteX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), REG_R, 2); + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); + + SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)s_mask); + SSE_ORPS_M128_to_XMM(EEREC_TEMP, (uptr)VU_ONE); + SSE_MOVSS_XMM_to_M32(VU_REGR_ADDR, EEREC_TEMP); + } + else { + int rreg = ALLOCVI(REG_R, MODE_WRITE); + + if( xmmregs[EEREC_S].mode & MODE_WRITE ) { + SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); + xmmregs[EEREC_S].mode &= ~MODE_WRITE; + } + + MOV32MtoR( rreg, VU_VFx_ADDR( _Fs_ ) + 4 * _Fsf_ ); + AND32ItoR( rreg, 0x7fffff ); + OR32ItoR( rreg, 0x7f << 23 ); + + _deleteX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), REG_R, 1); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// RGET* +//------------------------------------------------------------------ +void recVUMI_RGET(VURegs *VU, int info) +{ + //SysPrintf("recVUMI_RGET()\n"); + if ( (_Ft_ == 0) || (_X_Y_Z_W == 0) ) return; + + _deleteX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), REG_R, 1); + + if (_X_Y_Z_W != 0xf) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, VU_REGR_ADDR); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0); + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_T, VU_REGR_ADDR); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// RNEXT* +//------------------------------------------------------------------ +void recVUMI_RNEXT( VURegs *VU, int info ) +{ + int rreg, x86temp0, x86temp1; + //SysPrintf("recVUMI_RNEXT()\n"); + + rreg = ALLOCVI(REG_R, MODE_WRITE|MODE_READ); + + x86temp0 = ALLOCTEMPX86(0); + x86temp1 = ALLOCTEMPX86(0); + + // code from www.project-fao.org + //MOV32MtoR(rreg, VU_REGR_ADDR); + MOV32RtoR(x86temp0, rreg); + SHR32ItoR(x86temp0, 4); + AND32ItoR(x86temp0, 1); + + MOV32RtoR(x86temp1, rreg); + SHR32ItoR(x86temp1, 22); + AND32ItoR(x86temp1, 1); + + SHL32ItoR(rreg, 1); + XOR32RtoR(x86temp0, x86temp1); + XOR32RtoR(rreg, x86temp0); + AND32ItoR(rreg, 0x7fffff); + OR32ItoR(rreg, 0x3f800000); + + _freeX86reg(x86temp0); + _freeX86reg(x86temp1); + + if ( (_Ft_ == 0) || (_X_Y_Z_W == 0) ) { + _deleteX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), REG_R, 1); + return; + } + + recVUMI_RGET(VU, info); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// RXOR* +//------------------------------------------------------------------ +void recVUMI_RXOR( VURegs *VU, int info ) +{ + //SysPrintf("recVUMI_RXOR()\n"); + if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode & MODE_NOFLUSH) ) { + _deleteX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), REG_R, 1); + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); + + SSE_XORPS_M128_to_XMM(EEREC_TEMP, VU_REGR_ADDR); + SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)s_mask); + SSE_ORPS_M128_to_XMM(EEREC_TEMP, (uptr)s_fones); + SSE_MOVSS_XMM_to_M32(VU_REGR_ADDR, EEREC_TEMP); + } + else { + int rreg = ALLOCVI(REG_R, MODE_WRITE|MODE_READ); + + if( xmmregs[EEREC_S].mode & MODE_WRITE ) { + SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); + xmmregs[EEREC_S].mode &= ~MODE_WRITE; + } + + XOR32MtoR( rreg, VU_VFx_ADDR( _Fs_ ) + 4 * _Fsf_ ); + AND32ItoR( rreg, 0x7fffff ); + OR32ItoR ( rreg, 0x3f800000 ); + + _deleteX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), REG_R, 1); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// WAITQ +//------------------------------------------------------------------ +void recVUMI_WAITQ( VURegs *VU, int info ) +{ + //SysPrintf("recVUMI_WAITQ \n"); +// if( info & PROCESS_VU_SUPER ) { +// //CALLFunc(waitqfn); +// SuperVUFlush(0, 1); +// } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// FSAND +//------------------------------------------------------------------ +void recVUMI_FSAND( VURegs *VU, int info ) +{ + int ftreg; + u16 imm; + //SysPrintf("recVUMI_FSAND \n"); + imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7ff); + if(_Ft_ == 0) return; + + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + MOV32MtoR( ftreg, VU_VI_ADDR(REG_STATUS_FLAG, 1) ); + AND32ItoR( ftreg, imm ); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// FSEQ +//------------------------------------------------------------------ +void recVUMI_FSEQ( VURegs *VU, int info ) +{ + int ftreg; + u32 imm; + if ( _Ft_ == 0 ) return; + //SysPrintf("recVUMI_FSEQ \n"); + imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7ff); + + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + + MOVZX32M16toR( EAX, VU_VI_ADDR(REG_STATUS_FLAG, 1) ); + XOR32RtoR(ftreg, ftreg); + + CMP16ItoR(EAX, imm); + SETE8R(ftreg); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// FSOR +//------------------------------------------------------------------ +void recVUMI_FSOR( VURegs *VU, int info ) +{ + int ftreg; + u32 imm; + if(_Ft_ == 0) return; + //SysPrintf("recVUMI_FSOR \n"); + imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7ff); + + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + + MOVZX32M16toR( ftreg, VU_VI_ADDR(REG_STATUS_FLAG, 1) ); + OR32ItoR( ftreg, imm ); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// FSSET +//------------------------------------------------------------------ +void recVUMI_FSSET(VURegs *VU, int info) +{ + u32 writeaddr = VU_VI_ADDR(REG_STATUS_FLAG, 0); + u32 prevaddr = VU_VI_ADDR(REG_STATUS_FLAG, 2); + + u16 imm = 0; + //SysPrintf("recVUMI_FSSET \n"); + imm = (((VU->code >> 21 ) & 0x1) << 11) | (VU->code & 0x7FF); + + // keep the low 6 bits ONLY if the upper instruction is an fmac instruction (otherwise rewrite) - metal gear solid 3 + //if( (info & PROCESS_VU_SUPER) && VUREC_FMAC ) { + MOV32MtoR(EAX, prevaddr); + AND32ItoR(EAX, 0x3f); + if ((imm&0xfc0) != 0) OR32ItoR(EAX, imm & 0xFC0); + MOV32RtoM(writeaddr ? writeaddr : prevaddr, EAX); + //} + //else { + // MOV32ItoM(writeaddr ? writeaddr : prevaddr, imm&0xfc0); + //} +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// FMAND +//------------------------------------------------------------------ +void recVUMI_FMAND( VURegs *VU, int info ) +{ + int fsreg, ftreg; + if ( _Ft_ == 0 ) return; + //SysPrintf("recVUMI_FMAND \n"); + fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_WRITE);//|MODE_8BITREG); + + if( fsreg >= 0 ) { + if( ftreg != fsreg ) MOV32RtoR(ftreg, fsreg); + } + else MOV16MtoR(ftreg, VU_VI_ADDR(_Fs_, 1)); + + AND16MtoR( ftreg, VU_VI_ADDR(REG_MAC_FLAG, 1)); + //MOVZX32R16toR(ftreg, ftreg); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// FMEQ +//------------------------------------------------------------------ +void recVUMI_FMEQ( VURegs *VU, int info ) +{ + int ftreg, fsreg; + if ( _Ft_ == 0 ) return; + //SysPrintf("recVUMI_FMEQ \n"); + if( _Ft_ == _Fs_ ) { + ftreg = ALLOCVI(_Ft_, MODE_WRITE|MODE_READ);//|MODE_8BITREG); + + CMP16MtoR(ftreg, VU_VI_ADDR(REG_MAC_FLAG, 1)); + SETE8R(EAX); + MOVZX32R8toR(ftreg, EAX); + } + else { + ADD_VI_NEEDED(_Fs_); + fsreg = ALLOCVI(_Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_WRITE|MODE_8BITREG); + + XOR32RtoR(ftreg, ftreg); + + CMP16MtoR(fsreg, VU_VI_ADDR(REG_MAC_FLAG, 1)); + SETE8R(ftreg); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// FMOR +//------------------------------------------------------------------ +void recVUMI_FMOR( VURegs *VU, int info ) +{ + int fsreg, ftreg; + if ( _Ft_ == 0 ) return; + //SysPrintf("recVUMI_FMOR \n"); + if( _Fs_ == 0 ) { + ftreg = ALLOCVI(_Ft_, MODE_WRITE);//|MODE_8BITREG); + MOVZX32M16toR( ftreg, VU_VI_ADDR(REG_MAC_FLAG, 1) ); + } + else if( _Ft_ == _Fs_ ) { + ftreg = ALLOCVI(_Ft_, MODE_WRITE);//|MODE_READ|MODE_8BITREG); + OR16MtoR( ftreg, VU_VI_ADDR(REG_MAC_FLAG, 1) ); + } + else { + fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + + MOVZX32M16toR( ftreg, VU_VI_ADDR(REG_MAC_FLAG, 1) ); + + if( fsreg >= 0 ) + OR16RtoR( ftreg, fsreg ); + else + OR16MtoR( ftreg, VU_VI_ADDR(_Fs_, 1) ); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// FCAND +//------------------------------------------------------------------ +void recVUMI_FCAND( VURegs *VU, int info ) +{ + int ftreg = ALLOCVI(1, MODE_WRITE|MODE_8BITREG); + //SysPrintf("recVUMI_FCAND \n"); + MOV32MtoR( EAX, VU_VI_ADDR(REG_CLIP_FLAG, 1) ); + XOR32RtoR( ftreg, ftreg ); + AND32ItoR( EAX, VU->code & 0xFFFFFF ); + + SETNZ8R(ftreg); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// FCEQ +//------------------------------------------------------------------ +void recVUMI_FCEQ( VURegs *VU, int info ) +{ + int ftreg = ALLOCVI(1, MODE_WRITE|MODE_8BITREG); + //SysPrintf("recVUMI_FCEQ \n"); + MOV32MtoR( EAX, VU_VI_ADDR(REG_CLIP_FLAG, 1) ); + AND32ItoR( EAX, 0xffffff ); + XOR32RtoR( ftreg, ftreg ); + CMP32ItoR( EAX, VU->code&0xffffff ); + + SETE8R(ftreg); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// FCOR +//------------------------------------------------------------------ +void recVUMI_FCOR( VURegs *VU, int info ) +{ + int ftreg = ALLOCVI(1, MODE_WRITE|MODE_8BITREG); + //SysPrintf("recVUMI_FCOR \n"); + MOV32MtoR( EAX, VU_VI_ADDR(REG_CLIP_FLAG, 1) ); + XOR32RtoR( ftreg, ftreg ); + OR32ItoR( EAX, VU->code ); + AND32ItoR( EAX, 0xffffff ); + CMP32ItoR( EAX, 0xffffff ); + + SETZ8R(ftreg); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// FCSET +//------------------------------------------------------------------ +void recVUMI_FCSET( VURegs *VU, int info ) +{ + u32 addr = VU_VI_ADDR(REG_CLIP_FLAG, 0); + //SysPrintf("recVUMI_FCSET \n"); + MOV32ItoM(addr ? addr : VU_VI_ADDR(REG_CLIP_FLAG, 2), VU->code&0xffffff ); + + if( !(info & (PROCESS_VU_SUPER|PROCESS_VU_COP2)) ) + MOV32ItoM( VU_VI_ADDR(REG_CLIP_FLAG, 1), VU->code&0xffffff ); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// FCGET +//------------------------------------------------------------------ +void recVUMI_FCGET( VURegs *VU, int info ) +{ + int ftreg; + if(_Ft_ == 0) return; + //SysPrintf("recVUMI_FCGET \n"); + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + + MOV32MtoR(ftreg, VU_VI_ADDR(REG_CLIP_FLAG, 1)); + AND32ItoR(ftreg, 0x0fff); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// _recbranchAddr() +// +// NOTE: Due to static var dependencies, several SuperVU branch instructions +// are still located in iVUzerorec.cpp. +//------------------------------------------------------------------ + +//------------------------------------------------------------------ +// MFP* +//------------------------------------------------------------------ +void recVUMI_MFP(VURegs *VU, int info) +{ + if ( (_Ft_ == 0) || (_X_Y_Z_W == 0) ) return; + //SysPrintf("recVUMI_MFP \n"); + if( _XYZW_SS ) { + _vuFlipRegSS(VU, EEREC_T); + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, VU_VI_ADDR(REG_P, 1)); + SSE_MOVSS_XMM_to_XMM(EEREC_T, EEREC_TEMP); + _vuFlipRegSS(VU, EEREC_T); + } + else if (_X_Y_Z_W != 0xf) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, VU_VI_ADDR(REG_P, 1)); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0); + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_T, VU_VI_ADDR(REG_P, 1)); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// WAITP +//------------------------------------------------------------------ +static PCSX2_ALIGNED16(float s_tempmem[4]); +void recVUMI_WAITP(VURegs *VU, int info) +{ + //SysPrintf("recVUMI_WAITP \n"); +// if( info & PROCESS_VU_SUPER ) +// SuperVUFlush(1, 1); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// vuSqSumXYZ()* +// +// NOTE: In all EFU insts, EEREC_D is a temp reg +//------------------------------------------------------------------ +void vuSqSumXYZ(int regd, int regs, int regtemp) // regd.x = x ^ 2 + y ^ 2 + z ^ 2 +{ + //SysPrintf("VU: SUMXYZ\n"); + if( cpucaps.hasStreamingSIMD4Extensions ) + { + SSE_MOVAPS_XMM_to_XMM(regd, regs); + if (CHECK_VU_EXTRA_OVERFLOW) vuFloat2(regd, regtemp, 0xf); + SSE4_DPPS_XMM_to_XMM(regd, regd, 0x71); + } + else + { + SSE_MOVAPS_XMM_to_XMM(regtemp, regs); + if (CHECK_VU_EXTRA_OVERFLOW) vuFloat2(regtemp, regd, 0xf); + SSE_MULPS_XMM_to_XMM(regtemp, regtemp); // xyzw ^ 2 + + if( cpucaps.hasStreamingSIMD3Extensions ) { + SSE3_HADDPS_XMM_to_XMM(regd, regtemp); + SSE_ADDPS_XMM_to_XMM(regd, regtemp); // regd.z = x ^ 2 + y ^ 2 + z ^ 2 + SSE_MOVHLPS_XMM_to_XMM(regd, regd); // regd.x = regd.z + } + else { + SSE_MOVSS_XMM_to_XMM(regd, regtemp); + SSE2_PSHUFLW_XMM_to_XMM(regtemp, regtemp, 0x4e); // wzyx -> wzxy + SSE_ADDSS_XMM_to_XMM(regd, regtemp); // x ^ 2 + y ^ 2 + SSE_SHUFPS_XMM_to_XMM(regtemp, regtemp, 0xD2); // wzxy -> wxyz + SSE_ADDSS_XMM_to_XMM(regd, regtemp); // x ^ 2 + y ^ 2 + z ^ 2 + } + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ESADD* +//------------------------------------------------------------------ +void recVUMI_ESADD( VURegs *VU, int info) +{ + //SysPrintf("VU: ESADD\n"); + assert( VU == &VU1 ); + if( EEREC_TEMP == EEREC_D ) { // special code to reset P ( FixMe: don't know if this is still needed! (cottonvibes) ) + Console::Notice("ESADD: Resetting P reg!!!\n"); + MOV32ItoM(VU_VI_ADDR(REG_P, 0), 0); + return; + } + vuSqSumXYZ(EEREC_D, EEREC_S, EEREC_TEMP); + if (CHECK_VU_OVERFLOW) SSE_MINSS_M32_to_XMM(EEREC_D, (uptr)g_maxvals); // Only need to do positive clamp since (x ^ 2 + y ^ 2 + z ^ 2) is positive + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_D); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ERSADD* +//------------------------------------------------------------------ +void recVUMI_ERSADD( VURegs *VU, int info ) +{ + //SysPrintf("VU: ERSADD\n"); + assert( VU == &VU1 ); + vuSqSumXYZ(EEREC_D, EEREC_S, EEREC_TEMP); + // don't use RCPSS (very bad precision) + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)VU_ONE); + SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_D); + if (CHECK_VU_OVERFLOW) SSE_MINSS_M32_to_XMM(EEREC_TEMP, (uptr)g_maxvals); // Only need to do positive clamp since (x ^ 2 + y ^ 2 + z ^ 2) is positive + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ELENG* +//------------------------------------------------------------------ +void recVUMI_ELENG( VURegs *VU, int info ) +{ + //SysPrintf("VU: ELENG\n"); + assert( VU == &VU1 ); + vuSqSumXYZ(EEREC_D, EEREC_S, EEREC_TEMP); + if (CHECK_VU_OVERFLOW) SSE_MINSS_M32_to_XMM(EEREC_D, (uptr)g_maxvals); // Only need to do positive clamp since (x ^ 2 + y ^ 2 + z ^ 2) is positive + SSE_SQRTSS_XMM_to_XMM(EEREC_D, EEREC_D); + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_D); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ERLENG* +//------------------------------------------------------------------ +void recVUMI_ERLENG( VURegs *VU, int info ) +{ + //SysPrintf("VU: ERLENG\n"); + assert( VU == &VU1 ); + vuSqSumXYZ(EEREC_D, EEREC_S, EEREC_TEMP); + if (CHECK_VU_OVERFLOW) SSE_MINSS_M32_to_XMM(EEREC_D, (uptr)g_maxvals); // Only need to do positive clamp since (x ^ 2 + y ^ 2 + z ^ 2) is positive + SSE_SQRTSS_XMM_to_XMM(EEREC_D, EEREC_D); // regd <- sqrt(x^2 + y^2 + z^2) + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)VU_ONE); // temp <- 1 + SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_D); // temp = 1 / sqrt(x^2 + y^2 + z^2) + if (CHECK_VU_OVERFLOW) SSE_MINSS_M32_to_XMM(EEREC_TEMP, (uptr)g_maxvals); // Only need to do positive clamp + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// EATANxy +//------------------------------------------------------------------ +void recVUMI_EATANxy( VURegs *VU, int info ) +{ + assert( VU == &VU1 ); + //SysPrintf("recVUMI_EATANxy \n"); + if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode&MODE_NOFLUSH) ) { + SSE_MOVLPS_XMM_to_M64((uptr)s_tempmem, EEREC_S); + FLD32((uptr)&s_tempmem[0]); + FLD32((uptr)&s_tempmem[1]); + } + else { + if( xmmregs[EEREC_S].mode & MODE_WRITE ) { + SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); + xmmregs[EEREC_S].mode &= ~MODE_WRITE; + } + + FLD32((uptr)&VU->VF[_Fs_].UL[0]); + FLD32((uptr)&VU->VF[_Fs_].UL[1]); + } + + FPATAN(); + FSTP32(VU_VI_ADDR(REG_P, 0)); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// EATANxz +//------------------------------------------------------------------ +void recVUMI_EATANxz( VURegs *VU, int info ) +{ + assert( VU == &VU1 ); + //SysPrintf("recVUMI_EATANxz \n"); + if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode&MODE_NOFLUSH) ) { + SSE_MOVLPS_XMM_to_M64((uptr)s_tempmem, EEREC_S); + FLD32((uptr)&s_tempmem[0]); + FLD32((uptr)&s_tempmem[2]); + } + else { + if( xmmregs[EEREC_S].mode & MODE_WRITE ) { + SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); + xmmregs[EEREC_S].mode &= ~MODE_WRITE; + } + + FLD32((uptr)&VU->VF[_Fs_].UL[0]); + FLD32((uptr)&VU->VF[_Fs_].UL[2]); + } + FPATAN(); + FSTP32(VU_VI_ADDR(REG_P, 0)); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ESUM* +//------------------------------------------------------------------ +void recVUMI_ESUM( VURegs *VU, int info ) +{ + //SysPrintf("VU: ESUM\n"); + assert( VU == &VU1 ); + + if( cpucaps.hasStreamingSIMD3Extensions ) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) vuFloat_useEAX(info, EEREC_TEMP, 0xf); + SSE3_HADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + SSE3_HADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + } + else { + SSE_MOVHLPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); // z, w, z, w + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); // z+x, w+y, z+z, w+w + SSE_UNPCKLPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); // z+x, z+x, w+y, w+y + SSE_MOVHLPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); // w+y, w+y, w+y, w+y + SSE_ADDSS_XMM_to_XMM(EEREC_TEMP, EEREC_D); // x+y+z+w, w+y, w+y, w+y + } + + vuFloat_useEAX(info, EEREC_TEMP, 8); + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ERCPR* +//------------------------------------------------------------------ +void recVUMI_ERCPR( VURegs *VU, int info ) +{ + assert( VU == &VU1 ); + //SysPrintf("VU1: ERCPR\n"); + + // don't use RCPSS (very bad precision) + switch ( _Fsf_ ) { + case 0: //0001 + if (CHECK_VU_EXTRA_OVERFLOW) vuFloat5_useEAX(EEREC_S, EEREC_TEMP, 8); + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)VU_ONE); // temp <- 1 + SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + break; + case 1: //0010 + SSE2_PSHUFLW_XMM_to_XMM(EEREC_S, EEREC_S, 0x4e); + if (CHECK_VU_EXTRA_OVERFLOW) vuFloat5_useEAX(EEREC_S, EEREC_TEMP, 8); + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)VU_ONE); // temp <- 1 + SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE2_PSHUFLW_XMM_to_XMM(EEREC_S, EEREC_S, 0x4e); + break; + case 2: //0100 + SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0xc6); + if (CHECK_VU_EXTRA_OVERFLOW) vuFloat5_useEAX(EEREC_S, EEREC_TEMP, 8); + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)VU_ONE); // temp <- 1 + SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0xc6); + break; + case 3: //1000 + SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0x27); + if (CHECK_VU_EXTRA_OVERFLOW) vuFloat5_useEAX(EEREC_S, EEREC_TEMP, 8); + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)VU_ONE); // temp <- 1 + SSE_DIVSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SHUFPS_XMM_to_XMM(EEREC_S, EEREC_S, 0x27); + break; + } + + vuFloat_useEAX(info, EEREC_TEMP, 8); + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ESQRT* +//------------------------------------------------------------------ +void recVUMI_ESQRT( VURegs *VU, int info ) +{ + assert( VU == &VU1 ); + + //SysPrintf("VU1: ESQRT\n"); + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); + SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)const_clip); // abs(x) + if (CHECK_VU_OVERFLOW) SSE_MINSS_M32_to_XMM(EEREC_TEMP, (uptr)g_maxvals); // Only need to do positive clamp + SSE_SQRTSS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ERSQRT* +//------------------------------------------------------------------ +void recVUMI_ERSQRT( VURegs *VU, int info ) +{ + int t1reg = _vuGetTempXMMreg(info); + + assert( VU == &VU1 ); + //SysPrintf("VU1: ERSQRT\n"); + + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_S, _Fsf_); + SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)const_clip); // abs(x) + SSE_MINSS_M32_to_XMM(EEREC_TEMP, (uptr)g_maxvals); // Clamp Infinities to Fmax + SSE_SQRTSS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); // SQRT(abs(x)) + + if( t1reg >= 0 ) + { + SSE_MOVSS_M32_to_XMM(t1reg, (uptr)VU_ONE); + SSE_DIVSS_XMM_to_XMM(t1reg, EEREC_TEMP); + vuFloat_useEAX(info, t1reg, 8); + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), t1reg); + _freeXMMreg(t1reg); + } + else + { + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)VU_ONE); + SSE_DIVSS_M32_to_XMM(EEREC_TEMP, VU_VI_ADDR(REG_P, 0)); + vuFloat_useEAX(info, EEREC_TEMP, 8); + SSE_MOVSS_XMM_to_M32(VU_VI_ADDR(REG_P, 0), EEREC_TEMP); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ESIN +//------------------------------------------------------------------ +void recVUMI_ESIN( VURegs *VU, int info ) +{ + assert( VU == &VU1 ); + + //SysPrintf("recVUMI_ESIN \n"); + if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode&MODE_NOFLUSH) ) { + switch(_Fsf_) { + case 0: SSE_MOVSS_XMM_to_M32((uptr)s_tempmem, EEREC_S); + case 1: SSE_MOVLPS_XMM_to_M64((uptr)s_tempmem, EEREC_S); + default: SSE_MOVHPS_XMM_to_M64((uptr)&s_tempmem[2], EEREC_S); + } + FLD32((uptr)&s_tempmem[_Fsf_]); + } + else { + if( xmmregs[EEREC_S].mode & MODE_WRITE ) { + SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); + xmmregs[EEREC_S].mode &= ~MODE_WRITE; + } + + FLD32((uptr)&VU->VF[_Fs_].UL[_Fsf_]); + } + + FSIN(); + FSTP32(VU_VI_ADDR(REG_P, 0)); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// EATAN +//------------------------------------------------------------------ +void recVUMI_EATAN( VURegs *VU, int info ) +{ + assert( VU == &VU1 ); + + //SysPrintf("recVUMI_EATAN \n"); + if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode&MODE_NOFLUSH) ) { + switch(_Fsf_) { + case 0: SSE_MOVSS_XMM_to_M32((uptr)s_tempmem, EEREC_S); + case 1: SSE_MOVLPS_XMM_to_M64((uptr)s_tempmem, EEREC_S); + default: SSE_MOVHPS_XMM_to_M64((uptr)&s_tempmem[2], EEREC_S); + } + FLD32((uptr)&s_tempmem[_Fsf_]); + } + else { + if( xmmregs[EEREC_S].mode & MODE_WRITE ) { + SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); + xmmregs[EEREC_S].mode &= ~MODE_WRITE; + } + } + + FLD1(); + FLD32((uptr)&VU->VF[_Fs_].UL[_Fsf_]); + FPATAN(); + FSTP32(VU_VI_ADDR(REG_P, 0)); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// EEXP +//------------------------------------------------------------------ +void recVUMI_EEXP( VURegs *VU, int info ) +{ + assert( VU == &VU1 ); + //SysPrintf("recVUMI_EEXP \n"); + FLDL2E(); + + if( (xmmregs[EEREC_S].mode & MODE_WRITE) && (xmmregs[EEREC_S].mode&MODE_NOFLUSH) ) { + switch(_Fsf_) { + case 0: SSE_MOVSS_XMM_to_M32((uptr)s_tempmem, EEREC_S); + case 1: SSE_MOVLPS_XMM_to_M64((uptr)s_tempmem, EEREC_S); + default: SSE_MOVHPS_XMM_to_M64((uptr)&s_tempmem[2], EEREC_S); + } + FMUL32((uptr)&s_tempmem[_Fsf_]); + } + else { + if( xmmregs[EEREC_S].mode & MODE_WRITE ) { + SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[_Fs_], EEREC_S); + xmmregs[EEREC_S].mode &= ~MODE_WRITE; + } + + FMUL32((uptr)&VU->VF[_Fs_].UL[_Fsf_]); + } + + // basically do 2^(log_2(e) * val) + FLD(0); + FRNDINT(); + FXCH(1); + FSUB32Rto0(1); + F2XM1(); + FLD1(); + FADD320toR(1); + FSCALE(); + FSTP(1); + + FSTP32(VU_VI_ADDR(REG_P, 0)); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// XITOP +//------------------------------------------------------------------ +void recVUMI_XITOP( VURegs *VU, int info ) +{ + int ftreg; + if (_Ft_ == 0) return; + //SysPrintf("recVUMI_XITOP \n"); + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + MOVZX32M16toR( ftreg, (uptr)&VU->vifRegs->itop ); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// XTOP +//------------------------------------------------------------------ +void recVUMI_XTOP( VURegs *VU, int info ) +{ + int ftreg; + if ( _Ft_ == 0 ) return; + //SysPrintf("recVUMI_XTOP \n"); + ftreg = ALLOCVI(_Ft_, MODE_WRITE); + MOVZX32M16toR( ftreg, (uptr)&VU->vifRegs->top ); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// VU1XGKICK_MTGSTransfer() - Called by ivuZerorec.cpp +//------------------------------------------------------------------ +void VU1XGKICK_MTGSTransfer(u32 *pMem, u32 addr) +{ + u32 size; + u32* data = (u32*)((u8*)pMem + (addr&0x3fff)); + + // fixme: The gifTagDummy function in the MTGS (called by PrepDataPacket) has a + // hack that aborts the packet if it goes past the end of VU1 memory. + // Chances are this should be a "loops around memory" situation, and the packet + // should be continued starting at addr zero (0). + + size = mtgsThread->PrepDataPacket( GIF_PATH_1, data, (0x4000-(addr&0x3fff)) >> 4); + jASSUME( size > 0 ); + + //if( size > 0 ) + { + u8* pmem = mtgsThread->GetDataPacketPtr(); + memcpy_aligned(pmem, (u8*)pMem+addr, size<<4); + mtgsThread->SendDataPacket(); + } +} +//------------------------------------------------------------------ diff --git a/pcsx2/x86/iVUmicroUpper.cpp b/pcsx2/x86/iVUmicroUpper.cpp index a8ccda8204..6cc983ca2c 100644 --- a/pcsx2/x86/iVUmicroUpper.cpp +++ b/pcsx2/x86/iVUmicroUpper.cpp @@ -1,3214 +1,3214 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "PrecompiledHeader.h" - -#include "Common.h" -#include "GS.h" -#include "R5900OpcodeTables.h" -#include "ix86/ix86.h" -#include "iR5900.h" -#include "iMMI.h" -#include "iFPU.h" -#include "iCOP0.h" -#include "VUmicro.h" -#include "VUflags.h" -#include "iVUmicro.h" -#include "iVUops.h" -#include "iVUzerorec.h" -//------------------------------------------------------------------ -#define MINMAXFIX 1 -//------------------------------------------------------------------ -// Helper Macros -//------------------------------------------------------------------ -#define _Ft_ (( VU->code >> 16) & 0x1F) // The rt part of the instruction register -#define _Fs_ (( VU->code >> 11) & 0x1F) // The rd part of the instruction register -#define _Fd_ (( VU->code >> 6) & 0x1F) // The sa part of the instruction register - -#define _X (( VU->code>>24) & 0x1) -#define _Y (( VU->code>>23) & 0x1) -#define _Z (( VU->code>>22) & 0x1) -#define _W (( VU->code>>21) & 0x1) - -#define _XYZW_SS (_X+_Y+_Z+_W==1) - -#define _Fsf_ (( VU->code >> 21) & 0x03) -#define _Ftf_ (( VU->code >> 23) & 0x03) - -#define _Imm11_ (s32)(VU->code & 0x400 ? 0xfffffc00 | (VU->code & 0x3ff) : VU->code & 0x3ff) -#define _UImm11_ (s32)(VU->code & 0x7ff) - -#define VU_VFx_ADDR(x) (uptr)&VU->VF[x].UL[0] -#define VU_VFy_ADDR(x) (uptr)&VU->VF[x].UL[1] -#define VU_VFz_ADDR(x) (uptr)&VU->VF[x].UL[2] -#define VU_VFw_ADDR(x) (uptr)&VU->VF[x].UL[3] - -#define VU_REGR_ADDR (uptr)&VU->VI[REG_R] -#define VU_REGQ_ADDR (uptr)&VU->VI[REG_Q] -#define VU_REGMAC_ADDR (uptr)&VU->VI[REG_MAC_FLAG] - -#define VU_VI_ADDR(x, read) GetVIAddr(VU, x, read, info) - -#define VU_ACCx_ADDR (uptr)&VU->ACC.UL[0] -#define VU_ACCy_ADDR (uptr)&VU->ACC.UL[1] -#define VU_ACCz_ADDR (uptr)&VU->ACC.UL[2] -#define VU_ACCw_ADDR (uptr)&VU->ACC.UL[3] - -#define _X_Y_Z_W ((( VU->code >> 21 ) & 0xF ) ) -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// Global Variables -//------------------------------------------------------------------ -static const PCSX2_ALIGNED16(int SSEmovMask[ 16 ][ 4 ]) = -{ - { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF }, - { 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000 }, - { 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF }, - { 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000 }, - { 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF }, - { 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 }, - { 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }, - { 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 }, - { 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF }, - { 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000 }, - { 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF }, - { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000 }, - { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF }, - { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 }, - { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF } -}; - -static const PCSX2_ALIGNED16(u32 const_abs_table[16][4]) = -{ - { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }, //0000 - { 0xffffffff, 0xffffffff, 0xffffffff, 0x7fffffff }, //0001 - { 0xffffffff, 0xffffffff, 0x7fffffff, 0xffffffff }, //0010 - { 0xffffffff, 0xffffffff, 0x7fffffff, 0x7fffffff }, //0011 - { 0xffffffff, 0x7fffffff, 0xffffffff, 0xffffffff }, //0100 - { 0xffffffff, 0x7fffffff, 0xffffffff, 0x7fffffff }, //0101 - { 0xffffffff, 0x7fffffff, 0x7fffffff, 0xffffffff }, //0110 - { 0xffffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff }, //0111 - { 0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff }, //1000 - { 0x7fffffff, 0xffffffff, 0xffffffff, 0x7fffffff }, //1001 - { 0x7fffffff, 0xffffffff, 0x7fffffff, 0xffffffff }, //1010 - { 0x7fffffff, 0xffffffff, 0x7fffffff, 0x7fffffff }, //1011 - { 0x7fffffff, 0x7fffffff, 0xffffffff, 0xffffffff }, //1100 - { 0x7fffffff, 0x7fffffff, 0xffffffff, 0x7fffffff }, //1101 - { 0x7fffffff, 0x7fffffff, 0x7fffffff, 0xffffffff }, //1110 - { 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff }, //1111 -}; - -static const PCSX2_ALIGNED16(float recMult_float_to_int4[4]) = { 16.0, 16.0, 16.0, 16.0 }; -static const PCSX2_ALIGNED16(float recMult_float_to_int12[4]) = { 4096.0, 4096.0, 4096.0, 4096.0 }; -static const PCSX2_ALIGNED16(float recMult_float_to_int15[4]) = { 32768.0, 32768.0, 32768.0, 32768.0 }; - -static const PCSX2_ALIGNED16(float recMult_int_to_float4[4]) = { 0.0625f, 0.0625f, 0.0625f, 0.0625f }; -static const PCSX2_ALIGNED16(float recMult_int_to_float12[4]) = { 0.000244140625, 0.000244140625, 0.000244140625, 0.000244140625 }; -static const PCSX2_ALIGNED16(float recMult_int_to_float15[4]) = { 0.000030517578125, 0.000030517578125, 0.000030517578125, 0.000030517578125 }; - -static const PCSX2_ALIGNED16(u32 VU_Underflow_Mask1[4]) = {0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000}; -static const PCSX2_ALIGNED16(u32 VU_Underflow_Mask2[4]) = {0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff}; -static const PCSX2_ALIGNED16(u32 VU_Zero_Mask[4]) = {0x00000000, 0x00000000, 0x00000000, 0x00000000}; -static const PCSX2_ALIGNED16(u32 VU_Zero_Helper_Mask[4]) = {0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff}; -static const PCSX2_ALIGNED16(u32 VU_Signed_Zero_Mask[4]) = {0x80000000, 0x80000000, 0x80000000, 0x80000000}; -static const PCSX2_ALIGNED16(u32 VU_Pos_Infinity[4]) = {0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000}; -static const PCSX2_ALIGNED16(u32 VU_Neg_Infinity[4]) = {0xff800000, 0xff800000, 0xff800000, 0xff800000}; -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// recUpdateFlags() - Computes the flags for the Upper Opcodes -// -// Note: Computes under/overflow flags if CHECK_VU_EXTRA_FLAGS is 1 -//------------------------------------------------------------------ -PCSX2_ALIGNED16(u64 TEMPXMMData[2]); -void recUpdateFlags(VURegs * VU, int reg, int info) -{ - static u8 *pjmp, *pjmp2; - static u32 *pjmp32; - static u32 macaddr, stataddr, prevstataddr; - static int x86macflag, x86statflag, x86temp; - static int t1reg, t1regBoolean; - static const int flipMask[16] = {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}; - - if( !(info & PROCESS_VU_UPDATEFLAGS) ) return; - - //SysPrintf ("recUpdateFlags\n"); - - macaddr = VU_VI_ADDR(REG_MAC_FLAG, 0); - stataddr = VU_VI_ADDR(REG_STATUS_FLAG, 0); // write address - prevstataddr = VU_VI_ADDR(REG_STATUS_FLAG, 2); // previous address - - if( stataddr == 0 ) stataddr = prevstataddr; - if( macaddr == 0 ) { - SysPrintf( "VU ALLOCATION WARNING: Using Mac Flag Previous Address!\n" ); - macaddr = VU_VI_ADDR(REG_MAC_FLAG, 2); - } - - x86macflag = ALLOCTEMPX86(0); - x86statflag = ALLOCTEMPX86(0); - - if (reg == EEREC_TEMP) { - t1reg = _vuGetTempXMMreg(info); - if (t1reg < 0) { - //SysPrintf( "VU ALLOCATION ERROR: Temp reg can't be allocated!!!!\n" ); - t1reg = (reg == 0) ? 1 : 0; // Make t1reg != reg - SSE_MOVAPS_XMM_to_M128( (uptr)TEMPXMMData, t1reg ); // Backup data to temp address - t1regBoolean = 1; - } - else t1regBoolean = 0; - } - else { - t1reg = EEREC_TEMP; - t1regBoolean = 2; - } - - SSE_SHUFPS_XMM_to_XMM(reg, reg, 0x1B); // Flip wzyx to xyzw - MOV32MtoR(x86statflag, prevstataddr); // Load the previous status in to x86statflag - AND16ItoR(x86statflag, 0xff0); // Keep Sticky and D/I flags - - - if (CHECK_VU_EXTRA_FLAGS) { // Checks all flags - - x86temp = ALLOCTEMPX86(0); - - //-------------------------Check for Overflow flags------------------------------ - - //SSE_XORPS_XMM_to_XMM(t1reg, t1reg); // Clear t1reg - //SSE_CMPUNORDPS_XMM_to_XMM(t1reg, reg); // If reg == NaN then set Vector to 0xFFFFFFFF - - //SSE_MOVAPS_XMM_to_XMM(t1reg, reg); - //SSE_MINPS_M128_to_XMM(t1reg, (uptr)g_maxvals); - //SSE_MAXPS_M128_to_XMM(t1reg, (uptr)g_minvals); - //SSE_CMPNEPS_XMM_to_XMM(t1reg, reg); // If they're not equal, then overflow has occured - - SSE_MOVAPS_XMM_to_XMM(t1reg, reg); - SSE_ANDPS_M128_to_XMM(t1reg, (uptr)VU_Zero_Helper_Mask); - SSE_CMPEQPS_M128_to_XMM(t1reg, (uptr)VU_Pos_Infinity); // If infinity, then overflow has occured (NaN's don't report as overflow) - - SSE_MOVMSKPS_XMM_to_R32(x86macflag, t1reg); // Move the sign bits of the previous calculation - - AND16ItoR(x86macflag, _X_Y_Z_W ); // Grab "Has Overflowed" bits from the previous calculation (also make sure we're only grabbing from the XYZW being modified) - pjmp = JZ8(0); // Skip if none are - OR16ItoR(x86statflag, 0x208); // OS, O flags - SHL16ItoR(x86macflag, 12); - if (_XYZW_SS) pjmp32 = JMP32(0); // Skip Underflow Check - x86SetJ8(pjmp); - - //-------------------------Check for Underflow flags------------------------------ - - SSE_MOVAPS_XMM_to_XMM(t1reg, reg); // t1reg <- reg - - SSE_ANDPS_M128_to_XMM(t1reg, (uptr)&VU_Underflow_Mask1[ 0 ]); - SSE_CMPEQPS_M128_to_XMM(t1reg, (uptr)&VU_Zero_Mask[ 0 ]); // If (t1reg == zero exponent) then set Vector to 0xFFFFFFFF - - SSE_ANDPS_XMM_to_XMM(t1reg, reg); - SSE_ANDPS_M128_to_XMM(t1reg, (uptr)&VU_Underflow_Mask2[ 0 ]); - SSE_CMPNEPS_M128_to_XMM(t1reg, (uptr)&VU_Zero_Mask[ 0 ]); // If (t1reg != zero mantisa) then set Vector to 0xFFFFFFFF - - SSE_MOVMSKPS_XMM_to_R32(EAX, t1reg); // Move the sign bits of the previous calculation - - AND16ItoR(EAX, _X_Y_Z_W ); // Grab "Has Underflowed" bits from the previous calculation - pjmp = JZ8(0); // Skip if none are - OR16ItoR(x86statflag, 0x104); // US, U flags - SHL16ItoR(EAX, 8); - OR32RtoR(x86macflag, EAX); - x86SetJ8(pjmp); - - //-------------------------Optional Code: Denormals Are Zero------------------------------ - if (CHECK_VU_UNDERFLOW) { // Sets underflow/denormals to zero - SSE_ANDNPS_XMM_to_XMM(t1reg, reg); // t1reg = !t1reg & reg (t1reg = denormals are positive zero) - VU_MERGE_REGS_SAFE(t1reg, reg, (15 - flipMask[_X_Y_Z_W])); // Send t1reg the vectors that shouldn't be modified (since reg was flipped, we need a mask to get the unmodified vectors) - // Now we have Denormals are Positive Zero in t1reg; the next two lines take Signed Zero into account - SSE_ANDPS_M128_to_XMM(reg, (uptr)&VU_Signed_Zero_Mask[ 0 ]); // Only keep the sign bit for each vector - SSE_ORPS_XMM_to_XMM(reg, t1reg); // Denormals are Signed Zero, and unmodified vectors stay the same! - } - - if (_XYZW_SS) x86SetJ32(pjmp32); // If we skipped the Underflow Flag Checking (when we had an Overflow), return here - - vuFloat2(reg, t1reg, flipMask[_X_Y_Z_W]); // Clamp overflowed vectors that were modified (remember reg's vectors have been flipped, so have to use a flipmask) - - //-------------------------Check for Signed flags------------------------------ - - // The following code makes sure the Signed Bit isn't set with Negative Zero - SSE_XORPS_XMM_to_XMM(t1reg, t1reg); // Clear t1reg - SSE_CMPEQPS_XMM_to_XMM(t1reg, reg); // Set all F's if each vector is zero - SSE_MOVMSKPS_XMM_to_R32(x86temp, t1reg); // Used for Zero Flag Calculation - SSE_ANDNPS_XMM_to_XMM(t1reg, reg); - - SSE_MOVMSKPS_XMM_to_R32(EAX, t1reg); // Move the sign bits of the t1reg - - AND16ItoR(EAX, _X_Y_Z_W ); // Grab "Is Signed" bits from the previous calculation - pjmp = JZ8(0); // Skip if none are - OR16ItoR(x86statflag, 0x82); // SS, S flags - SHL16ItoR(EAX, 4); - OR32RtoR(x86macflag, EAX); - if (_XYZW_SS) pjmp2 = JMP8(0); // If negative and not Zero, we can skip the Zero Flag checking - x86SetJ8(pjmp); - - //-------------------------Check for Zero flags------------------------------ - - AND16ItoR(x86temp, _X_Y_Z_W ); // Grab "Is Zero" bits from the previous calculation - pjmp = JZ8(0); // Skip if none are - OR16ItoR(x86statflag, 0x41); // ZS, Z flags - OR32RtoR(x86macflag, x86temp); - x86SetJ8(pjmp); - - _freeX86reg(x86temp); - } - else { // Only Checks for Sign and Zero Flags - - vuFloat2(reg, t1reg, flipMask[_X_Y_Z_W]); // Clamp overflowed vectors that were modified (remember reg's vectors have been flipped, so have to use a flipmask) - - //-------------------------Check for Signed flags------------------------------ - - // The following code makes sure the Signed Bit isn't set with Negative Zero - SSE_XORPS_XMM_to_XMM(t1reg, t1reg); // Clear t1reg - SSE_CMPEQPS_XMM_to_XMM(t1reg, reg); // Set all F's if each vector is zero - SSE_MOVMSKPS_XMM_to_R32(EAX, t1reg); // Used for Zero Flag Calculation - SSE_ANDNPS_XMM_to_XMM(t1reg, reg); - - SSE_MOVMSKPS_XMM_to_R32(x86macflag, t1reg); // Move the sign bits of the t1reg - - AND16ItoR(x86macflag, _X_Y_Z_W ); // Grab "Is Signed" bits from the previous calculation - pjmp = JZ8(0); // Skip if none are - OR16ItoR(x86statflag, 0x82); // SS, S flags - SHL16ItoR(x86macflag, 4); - if (_XYZW_SS) pjmp2 = JMP8(0); // If negative and not Zero, we can skip the Zero Flag checking - x86SetJ8(pjmp); - - //-------------------------Check for Zero flags------------------------------ - - AND16ItoR(EAX, _X_Y_Z_W ); // Grab "Is Zero" bits from the previous calculation - pjmp = JZ8(0); // Skip if none are - OR16ItoR(x86statflag, 0x41); // ZS, Z flags - OR32RtoR(x86macflag, EAX); - x86SetJ8(pjmp); - } - //-------------------------Finally: Send the Flags to the Mac Flag Address------------------------------ - - if (_XYZW_SS) x86SetJ8(pjmp2); // If we skipped the Zero Flag Checking, return here - - if (t1regBoolean == 2) SSE_SHUFPS_XMM_to_XMM(reg, reg, 0x1B); // Flip back reg to wzyx (have to do this because reg != EEREC_TEMP) - else if (t1regBoolean == 1) SSE_MOVAPS_M128_to_XMM( t1reg, (uptr)TEMPXMMData ); // Restore data from temo address - else _freeXMMreg(t1reg); // Free temp reg - - MOV16RtoM(macaddr, x86macflag); - MOV16RtoM(stataddr, x86statflag); - - _freeX86reg(x86macflag); - _freeX86reg(x86statflag); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// Custom VU ADD/SUB routines by Nneeve -// -// Note: See FPU_ADD_SUB() for more info on what this is doing. -//------------------------------------------------------------------ -static PCSX2_ALIGNED16(u32 VU_addsuband[2][4]); -static PCSX2_ALIGNED16(u32 VU_addsub_reg[2][4]); -static u32 ecx_temp_loc; - -void VU_ADD_SUB(u32 regd, u32 regt, int is_sub, int info) -{ - u8 *localptr[4][8]; - int temp1 = _allocX86reg(ECX, X86TYPE_TEMP, 0, 0); //receives regd - int temp2 = ALLOCTEMPX86(0); - - SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsub_reg[0][0], regd); - SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsub_reg[1][0], regt); - - SSE2_PCMPEQB_XMM_to_XMM(regd, regd); - SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsuband[0][0], regd); - SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsuband[1][0], regd); - SSE_MOVAPS_M128_to_XMM(regd, (uptr)&VU_addsub_reg[0][0]); - - SSE2_PSLLD_I8_to_XMM(regd, 1); - SSE2_PSLLD_I8_to_XMM(regt, 1); - - SSE2_PSRLD_I8_to_XMM(regd, 24); - SSE2_PSRLD_I8_to_XMM(regt, 24); - - SSE2_PSUBD_XMM_to_XMM(regd, regt); - -#define PERFORM(i) \ - \ - SSE_PEXTRW_XMM_to_R32(temp1, regd, i*2); \ - MOVSX32R16toR(temp1, temp1); \ - CMP32ItoR(temp1, 25);\ - localptr[i][0] = JGE8(0);\ - CMP32ItoR(temp1, 0);\ - localptr[i][1] = JG8(0);\ - localptr[i][2] = JE8(0);\ - CMP32ItoR(temp1, -25);\ - localptr[i][3] = JLE8(0);\ - \ - NEG32R(temp1); \ - DEC32R(temp1);\ - MOV32ItoR(temp2, 0xffffffff); \ - SHL32CLtoR(temp2); \ - MOV32RtoM((uptr)&VU_addsuband[0][i], temp2);\ - localptr[i][4] = JMP8(0);\ - \ - x86SetJ8(localptr[i][0]);\ - MOV32ItoM((uptr)&VU_addsuband[1][i], 0x80000000);\ - localptr[i][5] = JMP8(0);\ - \ - x86SetJ8(localptr[i][1]);\ - DEC32R(temp1);\ - MOV32ItoR(temp2, 0xffffffff);\ - SHL32CLtoR(temp2); \ - MOV32RtoM((uptr)&VU_addsuband[1][i], temp2);\ - localptr[i][6] = JMP8(0);\ - \ - x86SetJ8(localptr[i][3]);\ - MOV32ItoM((uptr)&VU_addsuband[0][i], 0x80000000);\ - localptr[i][7] = JMP8(0);\ - \ - x86SetJ8(localptr[i][2]);\ - \ - x86SetJ8(localptr[i][4]);\ - x86SetJ8(localptr[i][5]);\ - x86SetJ8(localptr[i][6]);\ - x86SetJ8(localptr[i][7]); - - PERFORM(0); - PERFORM(1); - PERFORM(2); - PERFORM(3); -#undef PERFORM - - SSE_MOVAPS_M128_to_XMM(regd, (uptr)&VU_addsub_reg[0][0]); - SSE_MOVAPS_M128_to_XMM(regt, (uptr)&VU_addsub_reg[1][0]); - - SSE_ANDPS_M128_to_XMM(regd, (uptr)&VU_addsuband[0][0]); - SSE_ANDPS_M128_to_XMM(regt, (uptr)&VU_addsuband[1][0]); - - if (is_sub) SSE_SUBPS_XMM_to_XMM(regd, regt); - else SSE_ADDPS_XMM_to_XMM(regd, regt); - - SSE_MOVAPS_M128_to_XMM(regt, (uptr)&VU_addsub_reg[1][0]); - - _freeX86reg(temp1); - _freeX86reg(temp2); -} - -void VU_ADD_SUB_SSE4(u32 regd, u32 regt, int is_sub, int info) -{ - u8 *localptr[4][8]; - int temp1 = _allocX86reg(ECX, X86TYPE_TEMP, 0, 0); //receives regd - int temp2 = ALLOCTEMPX86(0); - - SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsub_reg[0][0], regd); - SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsub_reg[1][0], regt); - - SSE2_PSLLD_I8_to_XMM(regd, 1); - SSE2_PSLLD_I8_to_XMM(regt, 1); - - SSE2_PSRLD_I8_to_XMM(regd, 24); - SSE2_PSRLD_I8_to_XMM(regt, 24); - - SSE2_PSUBD_XMM_to_XMM(regd, regt); - -#define PERFORM_SSE4(i) \ - \ - SSE_PEXTRW_XMM_to_R32(temp1, regd, i*2); \ - MOVSX32R16toR(temp1, temp1); \ - CMP32ItoR(temp1, 25);\ - localptr[i][0] = JGE8(0);\ - CMP32ItoR(temp1, 0);\ - localptr[i][1] = JG8(0);\ - localptr[i][2] = JE8(0);\ - CMP32ItoR(temp1, -25);\ - localptr[i][3] = JLE8(0);\ - \ - NEG32R(temp1); \ - DEC32R(temp1);\ - MOV32ItoR(temp2, 0xffffffff); \ - SHL32CLtoR(temp2); \ - SSE4_PINSRD_R32_to_XMM(regd, temp2, i); \ - localptr[i][4] = JMP8(0);\ - \ - x86SetJ8(localptr[i][0]);\ - MOV32ItoR(temp2, 0xffffffff); \ - SSE4_PINSRD_R32_to_XMM(regd, temp2, i); \ - SHL32ItoR(temp2, 31); \ - SSE4_PINSRD_R32_to_XMM(regt, temp2, i); \ - localptr[i][5] = JMP8(0);\ - \ - x86SetJ8(localptr[i][1]);\ - DEC32R(temp1);\ - MOV32ItoR(temp2, 0xffffffff);\ - SSE4_PINSRD_R32_to_XMM(regd, temp2, i); \ - SHL32CLtoR(temp2); \ - SSE4_PINSRD_R32_to_XMM(regt, temp2, i); \ - localptr[i][6] = JMP8(0);\ - \ - x86SetJ8(localptr[i][3]);\ - MOV32ItoR(temp2, 0x80000000); \ - SSE4_PINSRD_R32_to_XMM(regd, temp2, i); \ - localptr[i][7] = JMP8(0);\ - \ - x86SetJ8(localptr[i][2]);\ - \ - x86SetJ8(localptr[i][4]);\ - x86SetJ8(localptr[i][5]);\ - x86SetJ8(localptr[i][6]);\ - x86SetJ8(localptr[i][7]); - - SSE2_PCMPEQB_XMM_to_XMM(regt, regt); - PERFORM_SSE4(0); - PERFORM_SSE4(1); - PERFORM_SSE4(2); - PERFORM_SSE4(3); -#undef PERFORM_SSE4 - - SSE_ANDPS_M128_to_XMM(regd, (uptr)&VU_addsub_reg[0][0]); //regd contains mask - SSE_ANDPS_M128_to_XMM(regt, (uptr)&VU_addsub_reg[1][0]); //regt contains mask - - if (is_sub) SSE_SUBPS_XMM_to_XMM(regd, regt); - else SSE_ADDPS_XMM_to_XMM(regd, regt); - - SSE_MOVAPS_M128_to_XMM(regt, (uptr)&VU_addsub_reg[1][0]); - - _freeX86reg(temp1); - _freeX86reg(temp2); -} - -void VU_ADD_SUB_SS(u32 regd, u32 regt, int is_sub, int is_mem, int info) -{ - u8 *localptr[8]; - u32 addrt = regt; //for case is_mem - int temp1 = _allocX86reg(ECX, X86TYPE_TEMP, 0, 0); //receives regd //_allocX86reg(ECX, X86TYPE_TEMP, 0, ((info&PROCESS_VU_SUPER)?0:MODE_NOFRAME)|mode); - int temp2 = ALLOCTEMPX86(0); - - SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsub_reg[0][0], regd); - if (!is_mem) SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsub_reg[1][0], regt); - - SSE2_MOVD_XMM_to_R(temp1, regd); - SHR32ItoR(temp1, 23); - - if (is_mem) { - MOV32MtoR(temp2, addrt); - MOV32RtoM((uptr)&VU_addsub_reg[1][0], temp2); - SHR32ItoR(temp2, 23); - } - else { - SSE2_MOVD_XMM_to_R(temp2, regt); - SHR32ItoR(temp2, 23); - } - - AND32ItoR(temp1, 0xff); - AND32ItoR(temp2, 0xff); - - SUB32RtoR(temp1, temp2); //temp1 = exponent difference - - CMP32ItoR(temp1, 25); - localptr[0] = JGE8(0); - CMP32ItoR(temp1, 0); - localptr[1] = JG8(0); - localptr[2] = JE8(0); - CMP32ItoR(temp1, -25); - localptr[3] = JLE8(0); - - NEG32R(temp1); - DEC32R(temp1); - MOV32ItoR(temp2, 0xffffffff); - SHL32CLtoR(temp2); - SSE2_PCMPEQB_XMM_to_XMM(regd, regd); - if (is_mem) { - SSE_PINSRW_R32_to_XMM(regd, temp2, 0); - SHR32ItoR(temp2, 16); - SSE_PINSRW_R32_to_XMM(regd, temp2, 1); - } - else { - SSE2_MOVD_R_to_XMM(regt, temp2); - SSE_MOVSS_XMM_to_XMM(regd, regt); - SSE2_PCMPEQB_XMM_to_XMM(regt, regt); - } - localptr[4] = JMP8(0); - - x86SetJ8(localptr[0]); - MOV32ItoR(temp2, 0x80000000); - if (is_mem) - AND32RtoM((uptr)&VU_addsub_reg[1][0], temp2); - else { - SSE2_PCMPEQB_XMM_to_XMM(regt, regt); - SSE2_MOVD_R_to_XMM(regd, temp2); - SSE_MOVSS_XMM_to_XMM(regt, regd); - } - SSE2_PCMPEQB_XMM_to_XMM(regd, regd); - localptr[5] = JMP8(0); - - x86SetJ8(localptr[1]); - DEC32R(temp1); - MOV32ItoR(temp2, 0xffffffff); - SHL32CLtoR(temp2); - if (is_mem) - AND32RtoM((uptr)&VU_addsub_reg[1][0], temp2); - else { - SSE2_PCMPEQB_XMM_to_XMM(regt, regt); - SSE2_MOVD_R_to_XMM(regd, temp2); - SSE_MOVSS_XMM_to_XMM(regt, regd); - } - SSE2_PCMPEQB_XMM_to_XMM(regd, regd); - localptr[6] = JMP8(0); - - x86SetJ8(localptr[3]); - MOV32ItoR(temp2, 0x80000000); - SSE2_PCMPEQB_XMM_to_XMM(regd, regd); - if (is_mem) { - SSE_PINSRW_R32_to_XMM(regd, temp2, 0); - SHR32ItoR(temp2, 16); - SSE_PINSRW_R32_to_XMM(regd, temp2, 1); - } - else { - SSE2_MOVD_R_to_XMM(regt, temp2); - SSE_MOVSS_XMM_to_XMM(regd, regt); - SSE2_PCMPEQB_XMM_to_XMM(regt, regt); - } - localptr[7] = JMP8(0); - - x86SetJ8(localptr[2]); - x86SetJ8(localptr[4]); - x86SetJ8(localptr[5]); - x86SetJ8(localptr[6]); - x86SetJ8(localptr[7]); - - if (is_mem) - { - SSE_ANDPS_M128_to_XMM(regd, (uptr)&VU_addsub_reg[0][0]); //regd contains mask - - if (is_sub) SSE_SUBSS_M32_to_XMM(regd, (uptr)&VU_addsub_reg[1][0]); - else SSE_ADDSS_M32_to_XMM(regd, (uptr)&VU_addsub_reg[1][0]); - } - else - { - SSE_ANDPS_M128_to_XMM(regd, (uptr)&VU_addsub_reg[0][0]); //regd contains mask - SSE_ANDPS_M128_to_XMM(regt, (uptr)&VU_addsub_reg[1][0]); //regt contains mask - - if (is_sub) SSE_SUBSS_XMM_to_XMM(regd, regt); - else SSE_ADDSS_XMM_to_XMM(regd, regt); - - SSE_MOVAPS_M128_to_XMM(regt, (uptr)&VU_addsub_reg[1][0]); - } - - _freeX86reg(temp1); - _freeX86reg(temp2); -} - -void VU_ADD_SUB_SS_SSE4(u32 regd, u32 regt, int is_sub, int is_mem, int info) -{ - u8 *localptr[8]; - u32 addrt = regt; //for case is_mem - int temp1 = _allocX86reg(ECX, X86TYPE_TEMP, 0, 0); //receives regd //_allocX86reg(ECX, X86TYPE_TEMP, 0, ((info&PROCESS_VU_SUPER)?0:MODE_NOFRAME)|mode); - int temp2 = ALLOCTEMPX86(0); - - SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsub_reg[0][0], regd); - if (!is_mem) SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsub_reg[1][0], regt); - - SSE2_MOVD_XMM_to_R(temp1, regd); - SHR32ItoR(temp1, 23); - - if (is_mem) { - MOV32MtoR(temp2, addrt); - MOV32RtoM((uptr)&VU_addsub_reg[1][0], temp2); - SHR32ItoR(temp2, 23); - } - else { - SSE2_MOVD_XMM_to_R(temp2, regt); - SHR32ItoR(temp2, 23); - } - - AND32ItoR(temp1, 0xff); - AND32ItoR(temp2, 0xff); - - SUB32RtoR(temp1, temp2); //temp1 = exponent difference - - CMP32ItoR(temp1, 25); - localptr[0] = JGE8(0); - CMP32ItoR(temp1, 0); - localptr[1] = JG8(0); - localptr[2] = JE8(0); - CMP32ItoR(temp1, -25); - localptr[3] = JLE8(0); - - NEG32R(temp1); - DEC32R(temp1); - MOV32ItoR(temp2, 0xffffffff); - SHL32CLtoR(temp2); - SSE2_PCMPEQB_XMM_to_XMM(regd, regd); - SSE4_PINSRD_R32_to_XMM(regd, temp2, 0); - if (!is_mem) - SSE2_PCMPEQB_XMM_to_XMM(regt, regt); - localptr[4] = JMP8(0); - - x86SetJ8(localptr[0]); - MOV32ItoR(temp2, 0x80000000); - if (is_mem) - AND32RtoM((uptr)&VU_addsub_reg[1][0], temp2); - else { - SSE2_PCMPEQB_XMM_to_XMM(regt, regt); - SSE4_PINSRD_R32_to_XMM(regt, temp2, 0); - } - SSE2_PCMPEQB_XMM_to_XMM(regd, regd); - localptr[5] = JMP8(0); - - x86SetJ8(localptr[1]); - DEC32R(temp1); - MOV32ItoR(temp2, 0xffffffff); - SHL32CLtoR(temp2); - if (is_mem) - AND32RtoM((uptr)&VU_addsub_reg[1][0], temp2); - else { - SSE2_PCMPEQB_XMM_to_XMM(regt, regt); - SSE4_PINSRD_R32_to_XMM(regt, temp2, 0); - } - SSE2_PCMPEQB_XMM_to_XMM(regd, regd); - localptr[6] = JMP8(0); - - x86SetJ8(localptr[3]); - MOV32ItoR(temp2, 0x80000000); - SSE2_PCMPEQB_XMM_to_XMM(regd, regd); - SSE4_PINSRD_R32_to_XMM(regd, temp2, 0); - if (!is_mem) - SSE2_PCMPEQB_XMM_to_XMM(regt, regt); - localptr[7] = JMP8(0); - - x86SetJ8(localptr[2]); - x86SetJ8(localptr[4]); - x86SetJ8(localptr[5]); - x86SetJ8(localptr[6]); - x86SetJ8(localptr[7]); - - if (is_mem) - { - SSE_ANDPS_M128_to_XMM(regd, (uptr)&VU_addsub_reg[0][0]); //regd contains mask - - if (is_sub) SSE_SUBSS_M32_to_XMM(regd, (uptr)&VU_addsub_reg[1][0]); - else SSE_ADDSS_M32_to_XMM(regd, (uptr)&VU_addsub_reg[1][0]); - } - else - { - SSE_ANDPS_M128_to_XMM(regd, (uptr)&VU_addsub_reg[0][0]); //regd contains mask - SSE_ANDPS_M128_to_XMM(regt, (uptr)&VU_addsub_reg[1][0]); //regt contains mask - - if (is_sub) SSE_SUBSS_XMM_to_XMM(regd, regt); - else SSE_ADDSS_XMM_to_XMM(regd, regt); - - SSE_MOVAPS_M128_to_XMM(regt, (uptr)&VU_addsub_reg[1][0]); - } - - _freeX86reg(temp1); - _freeX86reg(temp2); -} - -void SSE_ADDPS_XMM_to_XMM_custom(int info, int regd, int regt) { - if (CHECK_VUADDSUBHACK) { - if ( cpucaps.hasStreamingSIMD4Extensions ) - VU_ADD_SUB_SSE4(regd, regt, 0, info); - else - VU_ADD_SUB(regd, regt, 0, info); - } - else SSE_ADDPS_XMM_to_XMM(regd, regt); -} -void SSE_SUBPS_XMM_to_XMM_custom(int info, int regd, int regt) { - if (CHECK_VUADDSUBHACK) { - if ( cpucaps.hasStreamingSIMD4Extensions ) - VU_ADD_SUB_SSE4(regd, regt, 1, info); - else - VU_ADD_SUB(regd, regt, 1, info); - } - else SSE_SUBPS_XMM_to_XMM(regd, regt); -} -void SSE_ADDSS_XMM_to_XMM_custom(int info, int regd, int regt) { - if (CHECK_VUADDSUBHACK) { - if ( cpucaps.hasStreamingSIMD4Extensions ) - VU_ADD_SUB_SS_SSE4(regd, regt, 0, 0, info); - else - VU_ADD_SUB_SS(regd, regt, 0, 0, info); - } - else SSE_ADDSS_XMM_to_XMM(regd, regt); -} -void SSE_SUBSS_XMM_to_XMM_custom(int info, int regd, int regt) { - if (CHECK_VUADDSUBHACK) { - if ( cpucaps.hasStreamingSIMD4Extensions ) - VU_ADD_SUB_SS_SSE4(regd, regt, 1, 0, info); - else - VU_ADD_SUB_SS(regd, regt, 1, 0, info); - } - else SSE_SUBSS_XMM_to_XMM(regd, regt); -} -void SSE_ADDSS_M32_to_XMM_custom(int info, int regd, int regt) { - if (CHECK_VUADDSUBHACK) { - if ( cpucaps.hasStreamingSIMD4Extensions ) - VU_ADD_SUB_SS_SSE4(regd, regt, 0, 1, info); - else - VU_ADD_SUB_SS(regd, regt, 0, 1, info); - } - else SSE_ADDSS_M32_to_XMM(regd, regt); -} -void SSE_SUBSS_M32_to_XMM_custom(int info, int regd, int regt) { - if (CHECK_VUADDSUBHACK) { - if ( cpucaps.hasStreamingSIMD4Extensions ) - VU_ADD_SUB_SS_SSE4(regd, regt, 1, 1, info); - else - VU_ADD_SUB_SS(regd, regt, 1, 1, info); - } - else SSE_SUBSS_M32_to_XMM(regd, regt); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// *VU Upper Instructions!* -// -// Note: * = Checked for errors by cottonvibes -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ABS* -//------------------------------------------------------------------ -void recVUMI_ABS(VURegs *VU, int info) -{ - //SysPrintf("recVUMI_ABS()\n"); - if ( (_Ft_ == 0) || (_X_Y_Z_W == 0) ) return; - - if ((_X_Y_Z_W == 0x8) || (_X_Y_Z_W == 0xf)) { - VU_MERGE_REGS(EEREC_T, EEREC_S); - SSE_ANDPS_M128_to_XMM(EEREC_T, (uptr)&const_abs_table[ _X_Y_Z_W ][ 0 ] ); - } - else { // Use a temp reg because VU_MERGE_REGS() modifies source reg! - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_abs_table[ _X_Y_Z_W ][ 0 ] ); - VU_MERGE_REGS(EEREC_T, EEREC_TEMP); - } -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ADD*, ADD_iq*, ADD_xyzw* -//------------------------------------------------------------------ -PCSX2_ALIGNED16(float s_two[4]) = {0,0,0,2}; -void recVUMI_ADD(VURegs *VU, int info) -{ - //SysPrintf("recVUMI_ADD()\n"); - if ( _X_Y_Z_W == 0 ) goto flagUpdate; // Don't do anything and just clear flags - if ( !_Fd_ ) info = (info & ~PROCESS_EE_SET_D(0xf)) | PROCESS_EE_SET_D(EEREC_TEMP); - - if ( _Fs_ == 0 && _Ft_ == 0 ) { // if adding VF00 with VF00, then the result is always 0,0,0,2 - if ( _X_Y_Z_W != 0xf ) { - SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, (uptr)s_two); - VU_MERGE_REGS(EEREC_D, EEREC_TEMP); - } - else SSE_MOVAPS_M128_to_XMM(EEREC_D, (uptr)s_two); - } - else { - if (CHECK_VU_EXTRA_OVERFLOW) { - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, _X_Y_Z_W ); - } - if( _X_Y_Z_W == 8 ) { // If only adding x, then we can do a Scalar Add - if (EEREC_D == EEREC_S) SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_T); - else if (EEREC_D == EEREC_T) SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_T); - } - } - else if (_X_Y_Z_W != 0xf) { // If xyzw != 1111, then we have to use a temp reg - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); - VU_MERGE_REGS(EEREC_D, EEREC_TEMP); - } - else { // All xyzw being modified (xyzw == 1111) - if (EEREC_D == EEREC_S) SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_T); - else if (EEREC_D == EEREC_T) SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_T); - } - } - } -flagUpdate: - recUpdateFlags(VU, EEREC_D, info); -} - -void recVUMI_ADD_iq(VURegs *VU, uptr addr, int info) -{ - //SysPrintf("recVUMI_ADD_iq()\n"); - if ( _X_Y_Z_W == 0 ) goto flagUpdate; - if ( !_Fd_ ) info = (info & ~PROCESS_EE_SET_D(0xf)) | PROCESS_EE_SET_D(EEREC_TEMP); - if (CHECK_VU_EXTRA_OVERFLOW) { - vuFloat3(addr); - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - } - - if ( _XYZW_SS ) { - if ( EEREC_D == EEREC_TEMP ) { - _vuFlipRegSS(VU, EEREC_S); - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_ADDSS_M32_to_XMM(EEREC_D, addr); - _vuFlipRegSS(VU, EEREC_S); - _vuFlipRegSS(VU, EEREC_D); // have to flip over EEREC_D for computing flags! - } - else if ( EEREC_D == EEREC_S ) { - _vuFlipRegSS(VU, EEREC_D); - SSE_ADDSS_M32_to_XMM(EEREC_D, addr); - _vuFlipRegSS(VU, EEREC_D); - } - else { - if ( _X ) { - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_ADDSS_M32_to_XMM_custom(info, EEREC_D, addr); - } - else { - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); - SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); - SSE_ADDPS_XMM_to_XMM_custom(info, EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(EEREC_D, EEREC_TEMP); - } - } - } - else { - if ( (_X_Y_Z_W != 0xf) || (EEREC_D == EEREC_S) || (EEREC_D == EEREC_TEMP) ) { - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); - SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); - } - - if (_X_Y_Z_W != 0xf) { - SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(EEREC_D, EEREC_TEMP); - } - else { - if ( EEREC_D == EEREC_TEMP ) SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); - else if ( EEREC_D == EEREC_S ) SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); - else { - SSE_MOVSS_M32_to_XMM(EEREC_D, addr); - SSE_SHUFPS_XMM_to_XMM(EEREC_D, EEREC_D, 0x00); - SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); - } - } - } -flagUpdate: - recUpdateFlags(VU, EEREC_D, info); -} - -void recVUMI_ADD_xyzw(VURegs *VU, int xyzw, int info) -{ - //SysPrintf("recVUMI_ADD_xyzw()\n"); - if ( _X_Y_Z_W == 0 ) goto flagUpdate; - if ( !_Fd_ ) info = (info & ~PROCESS_EE_SET_D(0xf)) | PROCESS_EE_SET_D(EEREC_TEMP); - if (CHECK_VU_EXTRA_OVERFLOW) { - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, ( 1 << (3 - xyzw) ) ); - } - - if ( _Ft_ == 0 && xyzw < 3 ) { // just move since adding zero - if ( _X_Y_Z_W == 0x8 ) { VU_MERGE_REGS(EEREC_D, EEREC_S); } - else if ( _X_Y_Z_W != 0xf ) { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(EEREC_D, EEREC_TEMP); - } - else SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); - } - else if ( _X_Y_Z_W == 8 && (EEREC_D != EEREC_TEMP) ) { - if ( xyzw == 0 ) { - if ( EEREC_D == EEREC_T ) SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_T); - } - } - else { - _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); - } - } - else if( _Fs_ == 0 && !_W ) { // just move - _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); - VU_MERGE_REGS(EEREC_D, EEREC_TEMP); - } - else { - if ( _X_Y_Z_W != 0xf ) { - _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); - SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(EEREC_D, EEREC_TEMP); - } - else { - if( EEREC_D == EEREC_TEMP ) { _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); } - else if( EEREC_D == EEREC_S ) { _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); } - else { _unpackVF_xyzw(EEREC_D, EEREC_T, xyzw); SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); } - } - } -flagUpdate: - recUpdateFlags(VU, EEREC_D, info); -} - -void recVUMI_ADDi(VURegs *VU, int info) { recVUMI_ADD_iq(VU, VU_VI_ADDR(REG_I, 1), info); } -void recVUMI_ADDq(VURegs *VU, int info) { recVUMI_ADD_iq(VU, VU_REGQ_ADDR, info); } -void recVUMI_ADDx(VURegs *VU, int info) { recVUMI_ADD_xyzw(VU, 0, info); } -void recVUMI_ADDy(VURegs *VU, int info) { recVUMI_ADD_xyzw(VU, 1, info); } -void recVUMI_ADDz(VURegs *VU, int info) { recVUMI_ADD_xyzw(VU, 2, info); } -void recVUMI_ADDw(VURegs *VU, int info) { recVUMI_ADD_xyzw(VU, 3, info); } -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ADDA*, ADDA_iq*, ADDA_xyzw* -//------------------------------------------------------------------ -void recVUMI_ADDA(VURegs *VU, int info) -{ - //SysPrintf("recVUMI_ADDA()\n"); - if ( _X_Y_Z_W == 0 ) goto flagUpdate; - if (CHECK_VU_EXTRA_OVERFLOW) { - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, _X_Y_Z_W ); - } - - if( _X_Y_Z_W == 8 ) { - if (EEREC_ACC == EEREC_S) SSE_ADDSS_XMM_to_XMM(EEREC_ACC, EEREC_T); // Can this case happen? (cottonvibes) - else if (EEREC_ACC == EEREC_T) SSE_ADDSS_XMM_to_XMM(EEREC_ACC, EEREC_S); // Can this case happen? - else { - SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); - SSE_ADDSS_XMM_to_XMM(EEREC_ACC, EEREC_T); - } - } - else if (_X_Y_Z_W != 0xf) { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); - - VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); - } - else { - if( EEREC_ACC == EEREC_S ) SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_T); // Can this case happen? - else if( EEREC_ACC == EEREC_T ) SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_S); // Can this case happen? - else { - SSE_MOVAPS_XMM_to_XMM(EEREC_ACC, EEREC_S); - SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_T); - } - } -flagUpdate: - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_ADDA_iq(VURegs *VU, uptr addr, int info) -{ - //SysPrintf("recVUMI_ADDA_iq()\n"); - if ( _X_Y_Z_W == 0 ) goto flagUpdate; - if (CHECK_VU_EXTRA_OVERFLOW) { - vuFloat3(addr); - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - } - - if( _XYZW_SS ) { - assert( EEREC_ACC != EEREC_TEMP ); - if( EEREC_ACC == EEREC_S ) { - _vuFlipRegSS(VU, EEREC_ACC); - SSE_ADDSS_M32_to_XMM(EEREC_ACC, addr); - _vuFlipRegSS(VU, EEREC_ACC); - } - else { - if( _X ) { - SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); - SSE_ADDSS_M32_to_XMM(EEREC_ACC, addr); - } - else { - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); - SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); - SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); - } - } - } - else { - if( _X_Y_Z_W != 0xf || EEREC_ACC == EEREC_S ) { - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); - SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); - } - - if (_X_Y_Z_W != 0xf) { - SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); - } - else { - if( EEREC_ACC == EEREC_S ) SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); - else { - SSE_MOVSS_M32_to_XMM(EEREC_ACC, addr); - SSE_SHUFPS_XMM_to_XMM(EEREC_ACC, EEREC_ACC, 0x00); - SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_S); - } - } - } -flagUpdate: - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_ADDA_xyzw(VURegs *VU, int xyzw, int info) -{ - //SysPrintf("recVUMI_ADDA_xyzw()\n"); - if ( _X_Y_Z_W == 0 ) goto flagUpdate; - if (CHECK_VU_EXTRA_OVERFLOW) { - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, ( 1 << (3 - xyzw) ) ); - } - - if( _X_Y_Z_W == 8 ) { - assert( EEREC_ACC != EEREC_T ); - if( xyzw == 0 ) { - SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); - SSE_ADDSS_XMM_to_XMM(EEREC_ACC, EEREC_T); - } - else { - _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); - if( _Fs_ == 0 ) { - SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); - } - else { - SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); - SSE_ADDSS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); - } - } - } - else { - if( _X_Y_Z_W != 0xf || EEREC_ACC == EEREC_S ) - _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); - - if (_X_Y_Z_W != 0xf) { - SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); - } - else { - if( EEREC_ACC == EEREC_S ) SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); - else { - _unpackVF_xyzw(EEREC_ACC, EEREC_T, xyzw); - SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_S); - } - } - } -flagUpdate: - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_ADDAi(VURegs *VU, int info) { recVUMI_ADDA_iq(VU, VU_VI_ADDR(REG_I, 1), info); } -void recVUMI_ADDAq(VURegs *VU, int info) { recVUMI_ADDA_iq(VU, VU_REGQ_ADDR, info); } -void recVUMI_ADDAx(VURegs *VU, int info) { recVUMI_ADDA_xyzw(VU, 0, info); } -void recVUMI_ADDAy(VURegs *VU, int info) { recVUMI_ADDA_xyzw(VU, 1, info); } -void recVUMI_ADDAz(VURegs *VU, int info) { recVUMI_ADDA_xyzw(VU, 2, info); } -void recVUMI_ADDAw(VURegs *VU, int info) { recVUMI_ADDA_xyzw(VU, 3, info); } -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// SUB*, SUB_iq*, SUB_xyzw* -//------------------------------------------------------------------ -void recVUMI_SUB(VURegs *VU, int info) -{ - //SysPrintf("recVUMI_SUB()\n"); - if ( _X_Y_Z_W == 0 ) goto flagUpdate; - if ( !_Fd_ ) info = (info & ~PROCESS_EE_SET_D(0xf)) | PROCESS_EE_SET_D(EEREC_TEMP); - - if( EEREC_S == EEREC_T ) { - if (_X_Y_Z_W != 0xf) SSE_ANDPS_M128_to_XMM(EEREC_D, (uptr)&SSEmovMask[15-_X_Y_Z_W][0]); - else SSE_XORPS_XMM_to_XMM(EEREC_D, EEREC_D); - } - else if( _X_Y_Z_W == 8 ) { - if (CHECK_VU_EXTRA_OVERFLOW) { - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, _X_Y_Z_W ); - } - if (EEREC_D == EEREC_S) { - if (_Ft_) SSE_SUBSS_XMM_to_XMM(EEREC_D, EEREC_T); - } - else if (EEREC_D == EEREC_T) { - if (_Ft_) { - SSE_MOVSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_SUBSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); - } - else SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - } - else { - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - if (_Ft_) SSE_SUBSS_XMM_to_XMM(EEREC_D, EEREC_T); - } - } - else { - if (CHECK_VU_EXTRA_OVERFLOW) { - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, _X_Y_Z_W ); - } - if (_X_Y_Z_W != 0xf) { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - if( ( _Ft_ > 0 ) || _W ) SSE_SUBPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); - - VU_MERGE_REGS(EEREC_D, EEREC_TEMP); - } - else { - if (EEREC_D == EEREC_S) SSE_SUBPS_XMM_to_XMM(EEREC_D, EEREC_T); - else if (EEREC_D == EEREC_T) { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_SUBPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); - SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); - } - else { - SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_SUBPS_XMM_to_XMM(EEREC_D, EEREC_T); - } - } - } -flagUpdate: - recUpdateFlags(VU, EEREC_D, info); -} - -void recVUMI_SUB_iq(VURegs *VU, uptr addr, int info) -{ - //SysPrintf("recVUMI_SUB_iq()\n"); - if ( _X_Y_Z_W == 0 ) goto flagUpdate; - if (CHECK_VU_EXTRA_OVERFLOW) { - vuFloat3(addr); - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - } - if ( !_Fd_ ) info = (info & ~PROCESS_EE_SET_D(0xf)) | PROCESS_EE_SET_D(EEREC_TEMP); - - if( _XYZW_SS ) { - if( EEREC_D == EEREC_TEMP ) { - _vuFlipRegSS(VU, EEREC_S); - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_SUBSS_M32_to_XMM(EEREC_D, addr); - _vuFlipRegSS(VU, EEREC_S); - _vuFlipRegSS(VU, EEREC_D); - } - else if( EEREC_D == EEREC_S ) { - _vuFlipRegSS(VU, EEREC_D); - SSE_SUBSS_M32_to_XMM(EEREC_D, addr); - _vuFlipRegSS(VU, EEREC_D); - } - else { - if( _X ) { - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_SUBSS_M32_to_XMM(EEREC_D, addr); - } - else { - _vuMoveSS(VU, EEREC_TEMP, EEREC_S); - _vuFlipRegSS(VU, EEREC_D); - SSE_SUBSS_M32_to_XMM(EEREC_TEMP, addr); - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); - _vuFlipRegSS(VU, EEREC_D); - } - } - } - else { - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); - SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); - - if (_X_Y_Z_W != 0xf) { - int t1reg = _vuGetTempXMMreg(info); - - if( t1reg >= 0 ) { - SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_S); - SSE_SUBPS_XMM_to_XMM(t1reg, EEREC_TEMP); - - VU_MERGE_REGS(EEREC_D, t1reg); - _freeXMMreg(t1reg); - } - else { - // negate - SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); - SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(EEREC_D, EEREC_TEMP); - } - } - else { - if( EEREC_D == EEREC_TEMP ) { - SSE_XORPS_M128_to_XMM(EEREC_D, (uptr)&const_clip[4]); - SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); - } - else { - SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_SUBPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); - } - } - } -flagUpdate: - recUpdateFlags(VU, EEREC_D, info); -} - -void recVUMI_SUB_xyzw(VURegs *VU, int xyzw, int info) -{ - //SysPrintf("recVUMI_SUB_xyzw()\n"); - if ( _X_Y_Z_W == 0 ) goto flagUpdate; - if ( !_Fd_ ) info = (info & ~PROCESS_EE_SET_D(0xf)) | PROCESS_EE_SET_D(EEREC_TEMP); - if (CHECK_VU_EXTRA_OVERFLOW) { - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, ( 1 << (3 - xyzw) ) ); - } - - if ( _X_Y_Z_W == 8 ) { - if ( (xyzw == 0) && (_Ft_ == _Fs_) ) { - SSE_ANDPS_M128_to_XMM(EEREC_D, (uptr)&SSEmovMask[7][0]); - } - else if ( EEREC_D == EEREC_TEMP ) { - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - if ( (_Ft_ > 0) || (xyzw == 3) ) { - _vuFlipRegSS_xyzw(EEREC_T, xyzw); - SSE_SUBSS_XMM_to_XMM(EEREC_D, EEREC_T); - _vuFlipRegSS_xyzw(EEREC_T, xyzw); - } - } - else { - if ( (_Ft_ > 0) || (xyzw == 3) ) { - _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_SUBSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); - } - else SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - } - } - else { - _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); - - if (_X_Y_Z_W != 0xf) { - int t1reg = _vuGetTempXMMreg(info); - - if( t1reg >= 0 ) { - SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_S); - SSE_SUBPS_XMM_to_XMM(t1reg, EEREC_TEMP); - - VU_MERGE_REGS(EEREC_D, t1reg); - _freeXMMreg(t1reg); - } - else { - // negate - SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); - SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(EEREC_D, EEREC_TEMP); - } - } - else { - if( EEREC_D == EEREC_TEMP ) { - SSE_XORPS_M128_to_XMM(EEREC_D, (uptr)&const_clip[4]); - SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); - } - else { - SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_SUBPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); - } - } - } -flagUpdate: - recUpdateFlags(VU, EEREC_D, info); -} - -void recVUMI_SUBi(VURegs *VU, int info) { recVUMI_SUB_iq(VU, VU_VI_ADDR(REG_I, 1), info); } -void recVUMI_SUBq(VURegs *VU, int info) { recVUMI_SUB_iq(VU, VU_REGQ_ADDR, info); } -void recVUMI_SUBx(VURegs *VU, int info) { recVUMI_SUB_xyzw(VU, 0, info); } -void recVUMI_SUBy(VURegs *VU, int info) { recVUMI_SUB_xyzw(VU, 1, info); } -void recVUMI_SUBz(VURegs *VU, int info) { recVUMI_SUB_xyzw(VU, 2, info); } -void recVUMI_SUBw(VURegs *VU, int info) { recVUMI_SUB_xyzw(VU, 3, info); } -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// SUBA*, SUBA_iq, SUBA_xyzw -//------------------------------------------------------------------ -void recVUMI_SUBA(VURegs *VU, int info) -{ - //SysPrintf("recVUMI_SUBA()\n"); - if ( _X_Y_Z_W == 0 ) goto flagUpdate; - if (CHECK_VU_EXTRA_OVERFLOW) { - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, _X_Y_Z_W ); - } - - if( EEREC_S == EEREC_T ) { - if (_X_Y_Z_W != 0xf) SSE_ANDPS_M128_to_XMM(EEREC_ACC, (uptr)&SSEmovMask[15-_X_Y_Z_W][0]); - else SSE_XORPS_XMM_to_XMM(EEREC_ACC, EEREC_ACC); - } - else if( _X_Y_Z_W == 8 ) { - if (EEREC_ACC == EEREC_S) SSE_SUBSS_XMM_to_XMM(EEREC_ACC, EEREC_T); - else if (EEREC_ACC == EEREC_T) { - SSE_MOVSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_SUBSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); - SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); - } - else { - SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); - SSE_SUBSS_XMM_to_XMM(EEREC_ACC, EEREC_T); - } - } - else if (_X_Y_Z_W != 0xf) { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_SUBPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); - - VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); - } - else { - if( EEREC_ACC == EEREC_S ) SSE_SUBPS_XMM_to_XMM(EEREC_ACC, EEREC_T); - else if( EEREC_ACC == EEREC_T ) { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_SUBPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); - SSE_MOVAPS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); - } - else { - SSE_MOVAPS_XMM_to_XMM(EEREC_ACC, EEREC_S); - SSE_SUBPS_XMM_to_XMM(EEREC_ACC, EEREC_T); - } - } -flagUpdate: - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_SUBA_iq(VURegs *VU, uptr addr, int info) -{ - //SysPrintf ("recVUMI_SUBA_iq \n"); - if (CHECK_VU_EXTRA_OVERFLOW) { - vuFloat3(addr); - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - } - - if( _XYZW_SS ) { - if( EEREC_ACC == EEREC_S ) { - _vuFlipRegSS(VU, EEREC_ACC); - SSE_SUBSS_M32_to_XMM(EEREC_ACC, addr); - _vuFlipRegSS(VU, EEREC_ACC); - } - else { - if( _X ) { - SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); - SSE_SUBSS_M32_to_XMM(EEREC_ACC, addr); - } - else { - _vuMoveSS(VU, EEREC_TEMP, EEREC_S); - _vuFlipRegSS(VU, EEREC_ACC); - SSE_SUBSS_M32_to_XMM(EEREC_TEMP, addr); - SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); - _vuFlipRegSS(VU, EEREC_ACC); - } - } - } - else { - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); - SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); - - if (_X_Y_Z_W != 0xf) { - int t1reg = _vuGetTempXMMreg(info); - - if( t1reg >= 0 ) { - SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_S); - SSE_SUBPS_XMM_to_XMM(t1reg, EEREC_TEMP); - - VU_MERGE_REGS(EEREC_ACC, t1reg); - _freeXMMreg(t1reg); - } - else { - // negate - SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); - SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); - } - } - else { - SSE_MOVAPS_XMM_to_XMM(EEREC_ACC, EEREC_S); - SSE_SUBPS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); - } - } - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_SUBA_xyzw(VURegs *VU, int xyzw, int info) -{ - //SysPrintf ("recVUMI_SUBA_xyzw \n"); - if (CHECK_VU_EXTRA_OVERFLOW) { - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, ( 1 << (3 - xyzw) ) ); - } - - if( _X_Y_Z_W == 8 ) { - if( xyzw == 0 ) { - SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); - SSE_SUBSS_XMM_to_XMM(EEREC_ACC, EEREC_T); - } - else { - _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); - SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); - SSE_SUBSS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); - } - } - else { - _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); - - if (_X_Y_Z_W != 0xf) { - int t1reg = _vuGetTempXMMreg(info); - - if( t1reg >= 0 ) { - SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_S); - SSE_SUBPS_XMM_to_XMM(t1reg, EEREC_TEMP); - - VU_MERGE_REGS(EEREC_ACC, t1reg); - _freeXMMreg(t1reg); - } - else { - // negate - SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); - SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); - } - } - else { - SSE_MOVAPS_XMM_to_XMM(EEREC_ACC, EEREC_S); - SSE_SUBPS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); - } - } - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_SUBAi(VURegs *VU, int info) { recVUMI_SUBA_iq(VU, VU_VI_ADDR(REG_I, 1), info); } -void recVUMI_SUBAq(VURegs *VU, int info) { recVUMI_SUBA_iq(VU, VU_REGQ_ADDR, info); } -void recVUMI_SUBAx(VURegs *VU, int info) { recVUMI_SUBA_xyzw(VU, 0, info); } -void recVUMI_SUBAy(VURegs *VU, int info) { recVUMI_SUBA_xyzw(VU, 1, info); } -void recVUMI_SUBAz(VURegs *VU, int info) { recVUMI_SUBA_xyzw(VU, 2, info); } -void recVUMI_SUBAw(VURegs *VU, int info) { recVUMI_SUBA_xyzw(VU, 3, info); } -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// MUL -//------------------------------------------------------------------ -void recVUMI_MUL_toD(VURegs *VU, int regd, int info) -{ - //SysPrintf ("recVUMI_MUL_toD \n"); - if (CHECK_VU_EXTRA_OVERFLOW) { - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, _X_Y_Z_W ); - } - - if (_X_Y_Z_W == 1 && (_Ft_ == 0 || _Fs_==0) ) { // W - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, _Ft_ ? EEREC_T : EEREC_S); - VU_MERGE_REGS(regd, EEREC_TEMP); - } - else if( _Fd_ == _Fs_ && _Fs_ == _Ft_ && _XYZW_SS ) { - _vuFlipRegSS(VU, EEREC_D); - SSE_MULSS_XMM_to_XMM(EEREC_D, EEREC_D); - _vuFlipRegSS(VU, EEREC_D); - } - else if( _X_Y_Z_W == 8 ) { - if (regd == EEREC_S) SSE_MULSS_XMM_to_XMM(regd, EEREC_T); - else if (regd == EEREC_T) SSE_MULSS_XMM_to_XMM(regd, EEREC_S); - else { - SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); - SSE_MULSS_XMM_to_XMM(regd, EEREC_T); - } - } - else if (_X_Y_Z_W != 0xf) { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); - - VU_MERGE_REGS(regd, EEREC_TEMP); - } - else { - if (regd == EEREC_S) SSE_MULPS_XMM_to_XMM(regd, EEREC_T); - else if (regd == EEREC_T) SSE_MULPS_XMM_to_XMM(regd, EEREC_S); - else { - SSE_MOVAPS_XMM_to_XMM(regd, EEREC_S); - SSE_MULPS_XMM_to_XMM(regd, EEREC_T); - } - } -} - -void recVUMI_MUL_iq_toD(VURegs *VU, uptr addr, int regd, int info) -{ - //SysPrintf ("recVUMI_MUL_iq_toD \n"); - if (CHECK_VU_EXTRA_OVERFLOW) { - vuFloat3(addr); - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - } - - if( _XYZW_SS ) { - if( regd == EEREC_TEMP ) { - _vuFlipRegSS(VU, EEREC_S); - SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); - SSE_MULSS_M32_to_XMM(regd, addr); - _vuFlipRegSS(VU, EEREC_S); - } - else if( regd == EEREC_S ) { - _vuFlipRegSS(VU, regd); - SSE_MULSS_M32_to_XMM(regd, addr); - _vuFlipRegSS(VU, regd); - } - else { - if( _X ) { - SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); - SSE_MULSS_M32_to_XMM(regd, addr); - } - else { - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); - SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); - SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(regd, EEREC_TEMP); - } - } - } - else { - if( _X_Y_Z_W != 0xf || regd == EEREC_TEMP || regd == EEREC_S ) { - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); - SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); - } - - if (_X_Y_Z_W != 0xf) { - SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(regd, EEREC_TEMP); - } - else { - if( regd == EEREC_TEMP ) SSE_MULPS_XMM_to_XMM(regd, EEREC_S); - else if (regd == EEREC_S) SSE_MULPS_XMM_to_XMM(regd, EEREC_TEMP); - else { - SSE_MOVSS_M32_to_XMM(regd, addr); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x00); - SSE_MULPS_XMM_to_XMM(regd, EEREC_S); - } - } - } -} - -void recVUMI_MUL_xyzw_toD(VURegs *VU, int xyzw, int regd, int info) -{ - //SysPrintf ("recVUMI_MUL_xyzw_toD \n"); - if (CHECK_VU_EXTRA_OVERFLOW) { - if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, ( 1 << (3 - xyzw) ) ); - } - if (_Fs_) { // This is needed for alot of games; so always clamp this operand - if (CHECK_VU_SIGN_OVERFLOW) vFloats4_useEAX[_X_Y_Z_W]( EEREC_S, EEREC_TEMP ); // Always clamp EEREC_S, regardless if CHECK_VU_OVERFLOW is set - else vFloats2_MUL_MADD[_X_Y_Z_W]( EEREC_S, EEREC_TEMP ); // Always clamp EEREC_S, regardless if CHECK_VU_OVERFLOW is set - } - if( _Ft_ == 0 ) { - if( xyzw < 3 ) { - if (_X_Y_Z_W != 0xf) { - SSE_XORPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); - VU_MERGE_REGS(regd, EEREC_TEMP); - } - else SSE_XORPS_XMM_to_XMM(regd, regd); - } - else { - assert(xyzw==3); - if (_X_Y_Z_W != 0xf) { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(regd, EEREC_TEMP); - } - else SSE_MOVAPS_XMM_to_XMM(regd, EEREC_S); - } - } - else if( _X_Y_Z_W == 8 ) { - if( regd == EEREC_TEMP ) { - _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); - SSE_MULSS_XMM_to_XMM(regd, EEREC_S); - } - else { - if( xyzw == 0 ) { - if( regd == EEREC_T ) { - SSE_MULSS_XMM_to_XMM(regd, EEREC_S); - } - else { - SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); - SSE_MULSS_XMM_to_XMM(regd, EEREC_T); - } - } - else { - _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); - SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); - SSE_MULSS_XMM_to_XMM(regd, EEREC_TEMP); - } - } - } - else { - if( _X_Y_Z_W != 0xf || regd == EEREC_TEMP || regd == EEREC_S ) - _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); - - if (_X_Y_Z_W != 0xf) { - SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(regd, EEREC_TEMP); - } - else { - if( regd == EEREC_TEMP ) SSE_MULPS_XMM_to_XMM(regd, EEREC_S); - else if (regd == EEREC_S) SSE_MULPS_XMM_to_XMM(regd, EEREC_TEMP); - else { - _unpackVF_xyzw(regd, EEREC_T, xyzw); - SSE_MULPS_XMM_to_XMM(regd, EEREC_S); - } - } - } -} - -void recVUMI_MUL(VURegs *VU, int info) -{ - //SysPrintf ("recVUMI_MUL \n"); - if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); - recVUMI_MUL_toD(VU, EEREC_D, info); - recUpdateFlags(VU, EEREC_D, info); -} - -void recVUMI_MUL_iq(VURegs *VU, int addr, int info) -{ - //SysPrintf ("recVUMI_MUL_iq \n"); - if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); - recVUMI_MUL_iq_toD(VU, addr, EEREC_D, info); - recUpdateFlags(VU, EEREC_D, info); - // spacefisherman needs overflow checking on MULi.z -} - -void recVUMI_MUL_xyzw(VURegs *VU, int xyzw, int info) -{ - //SysPrintf ("recVUMI_MUL_xyzw \n"); - if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); - recVUMI_MUL_xyzw_toD(VU, xyzw, EEREC_D, info); - recUpdateFlags(VU, EEREC_D, info); -} - -void recVUMI_MULi(VURegs *VU, int info) { recVUMI_MUL_iq(VU, VU_VI_ADDR(REG_I, 1), info); } -void recVUMI_MULq(VURegs *VU, int info) { recVUMI_MUL_iq(VU, VU_REGQ_ADDR, info); } -void recVUMI_MULx(VURegs *VU, int info) { recVUMI_MUL_xyzw(VU, 0, info); } -void recVUMI_MULy(VURegs *VU, int info) { recVUMI_MUL_xyzw(VU, 1, info); } -void recVUMI_MULz(VURegs *VU, int info) { recVUMI_MUL_xyzw(VU, 2, info); } -void recVUMI_MULw(VURegs *VU, int info) { recVUMI_MUL_xyzw(VU, 3, info); } -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// MULA -//------------------------------------------------------------------ -void recVUMI_MULA( VURegs *VU, int info ) -{ - //SysPrintf ("recVUMI_MULA \n"); - recVUMI_MUL_toD(VU, EEREC_ACC, info); - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_MULA_iq(VURegs *VU, int addr, int info) -{ - //SysPrintf ("recVUMI_MULA_iq \n"); - recVUMI_MUL_iq_toD(VU, addr, EEREC_ACC, info); - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_MULA_xyzw(VURegs *VU, int xyzw, int info) -{ - //SysPrintf ("recVUMI_MULA_xyzw \n"); - recVUMI_MUL_xyzw_toD(VU, xyzw, EEREC_ACC, info); - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_MULAi(VURegs *VU, int info) { recVUMI_MULA_iq(VU, VU_VI_ADDR(REG_I, 1), info); } -void recVUMI_MULAq(VURegs *VU, int info) { recVUMI_MULA_iq(VU, VU_REGQ_ADDR, info); } -void recVUMI_MULAx(VURegs *VU, int info) { recVUMI_MULA_xyzw(VU, 0, info); } -void recVUMI_MULAy(VURegs *VU, int info) { recVUMI_MULA_xyzw(VU, 1, info); } -void recVUMI_MULAz(VURegs *VU, int info) { recVUMI_MULA_xyzw(VU, 2, info); } -void recVUMI_MULAw(VURegs *VU, int info) { recVUMI_MULA_xyzw(VU, 3, info); } -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// MADD -//------------------------------------------------------------------ -void recVUMI_MADD_toD(VURegs *VU, int regd, int info) -{ - //SysPrintf ("recVUMI_MADD_toD \n"); - if (CHECK_VU_EXTRA_OVERFLOW) { - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, _X_Y_Z_W ); - vuFloat5_useEAX( EEREC_ACC, EEREC_TEMP, _X_Y_Z_W ); - } - - if( _X_Y_Z_W == 8 ) { - if( regd == EEREC_ACC ) { - SSE_MOVSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_MULSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, 8); } - SSE_ADDSS_XMM_to_XMM(regd, EEREC_TEMP); - } - else if (regd == EEREC_T) { - SSE_MULSS_XMM_to_XMM(regd, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, 8); } - SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); - } - else if (regd == EEREC_S) { - SSE_MULSS_XMM_to_XMM(regd, EEREC_T); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, 8); } - SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); - } - else { - SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); - SSE_MULSS_XMM_to_XMM(regd, EEREC_T); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, 8); } - SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); - } - } - else if (_X_Y_Z_W != 0xf) { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } - SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); - - VU_MERGE_REGS(regd, EEREC_TEMP); - } - else { - if( regd == EEREC_ACC ) { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } - SSE_ADDPS_XMM_to_XMM(regd, EEREC_TEMP); - } - else if (regd == EEREC_T) { - SSE_MULPS_XMM_to_XMM(regd, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } - SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); - } - else if (regd == EEREC_S) { - SSE_MULPS_XMM_to_XMM(regd, EEREC_T); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } - SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); - } - else { - SSE_MOVAPS_XMM_to_XMM(regd, EEREC_S); - SSE_MULPS_XMM_to_XMM(regd, EEREC_T); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } - SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); - } - } -} - -void recVUMI_MADD_iq_toD(VURegs *VU, uptr addr, int regd, int info) -{ - //SysPrintf ("recVUMI_MADD_iq_toD \n"); - if (CHECK_VU_EXTRA_OVERFLOW) { - vuFloat3(addr); - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - vuFloat5_useEAX( EEREC_ACC, EEREC_TEMP, _X_Y_Z_W ); - } - - if( _X_Y_Z_W == 8 ) { - if( regd == EEREC_ACC ) { - if( _Fs_ == 0 ) { - // add addr to w - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_ADDSS_M32_to_XMM(regd, addr); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - } - else { - assert( EEREC_TEMP < XMMREGS ); - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); - SSE_MULSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, 8); } - SSE_ADDSS_XMM_to_XMM(regd, EEREC_TEMP); - } - } - else if( regd == EEREC_S ) { - SSE_MULSS_M32_to_XMM(regd, addr); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } - SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); - } - else { - SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); - SSE_MULSS_M32_to_XMM(regd, addr); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } - SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); - } - } - else { - if( _Fs_ == 0 ) { - // add addr to w - if( _W ) { - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - SSE_ADDSS_M32_to_XMM(regd, addr); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); - } - - return; - } - - if( _X_Y_Z_W != 0xf || regd == EEREC_ACC || regd == EEREC_TEMP || regd == EEREC_S ) { - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); - SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); - } - - if (_X_Y_Z_W != 0xf) { - SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } - SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); - - VU_MERGE_REGS(regd, EEREC_TEMP); - } - else { - if( regd == EEREC_ACC ) { - SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } - SSE_ADDPS_XMM_to_XMM(regd, EEREC_TEMP); - } - else if( regd == EEREC_S ) { - SSE_MULPS_XMM_to_XMM(regd, EEREC_TEMP); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } - SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); - } - else if( regd == EEREC_TEMP ) { - SSE_MULPS_XMM_to_XMM(regd, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } - SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); - } - else { - SSE_MOVSS_M32_to_XMM(regd, addr); - SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x00); - SSE_MULPS_XMM_to_XMM(regd, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } - SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); - } - } - } -} - -void recVUMI_MADD_xyzw_toD(VURegs *VU, int xyzw, int regd, int info) -{ - //SysPrintf ("recVUMI_MADD_xyzw_toD \n"); - if (CHECK_VU_EXTRA_OVERFLOW) { - if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, ( 1 << (3 - xyzw) ) ); - vuFloat5_useEAX( EEREC_ACC, EEREC_TEMP, _X_Y_Z_W ); - } - if (_Fs_) { // This is needed for alot of games; so always clamp this operand - if (CHECK_VU_SIGN_OVERFLOW) vFloats4_useEAX[_X_Y_Z_W]( EEREC_S, EEREC_TEMP ); // Always clamp EEREC_S, regardless if CHECK_VU_OVERFLOW is set - else vFloats2_MUL_MADD[_X_Y_Z_W]( EEREC_S, EEREC_TEMP ); // Always clamp EEREC_S, regardless if CHECK_VU_OVERFLOW is set - } - if( _Ft_ == 0 ) { - - if( xyzw == 3 ) { - // just add - if( _X_Y_Z_W == 8 ) { - if( regd == EEREC_S ) SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); - else { - SSE_MOVSS_XMM_to_XMM(regd, EEREC_ACC); - SSE_ADDSS_XMM_to_XMM(regd, EEREC_S); - } - } - else { - if( _X_Y_Z_W != 0xf ) { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); - - VU_MERGE_REGS(regd, EEREC_TEMP); - } - else { - if( regd == EEREC_S ) SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); - else { - SSE_MOVAPS_XMM_to_XMM(regd, EEREC_ACC); - SSE_ADDPS_XMM_to_XMM(regd, EEREC_S); - } - } - } - } - else { - // just move acc to regd - if( _X_Y_Z_W != 0xf ) { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); - VU_MERGE_REGS(regd, EEREC_TEMP); - } - else SSE_MOVAPS_XMM_to_XMM(regd, EEREC_ACC); - } - - return; - } - - if( _X_Y_Z_W == 8 ) { - _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); - - if( regd == EEREC_ACC ) { - SSE_MULSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, 8); } - SSE_ADDSS_XMM_to_XMM(regd, EEREC_TEMP); - } - else if( regd == EEREC_S ) { - SSE_MULSS_XMM_to_XMM(regd, EEREC_TEMP); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, 8); } - SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); - } - else if( regd == EEREC_TEMP ) { - SSE_MULSS_XMM_to_XMM(regd, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, 8); } - SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); - } - else { - SSE_MOVSS_XMM_to_XMM(regd, EEREC_ACC); - SSE_MULSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, 8); } - SSE_ADDSS_XMM_to_XMM(regd, EEREC_TEMP); - } - } - else { - if( _X_Y_Z_W != 0xf || regd == EEREC_ACC || regd == EEREC_TEMP || regd == EEREC_S ) { - _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); - } - - if (_X_Y_Z_W != 0xf) { - SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } - SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); - - VU_MERGE_REGS(regd, EEREC_TEMP); - } - else { - if( regd == EEREC_ACC ) { - SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } - SSE_ADDPS_XMM_to_XMM(regd, EEREC_TEMP); - } - else if( regd == EEREC_S ) { - SSE_MULPS_XMM_to_XMM(regd, EEREC_TEMP); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } - SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); - } - else if( regd == EEREC_TEMP ) { - SSE_MULPS_XMM_to_XMM(regd, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } - SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); - } - else { - _unpackVF_xyzw(regd, EEREC_T, xyzw); - SSE_MULPS_XMM_to_XMM(regd, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } - SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); - } - } - } -} - -void recVUMI_MADD(VURegs *VU, int info) -{ - //SysPrintf ("recVUMI_MADD \n"); - if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); - recVUMI_MADD_toD(VU, EEREC_D, info); - recUpdateFlags(VU, EEREC_D, info); -} - -void recVUMI_MADD_iq(VURegs *VU, int addr, int info) -{ - //SysPrintf ("recVUMI_MADD_iq \n"); - if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); - recVUMI_MADD_iq_toD(VU, addr, EEREC_D, info); - recUpdateFlags(VU, EEREC_D, info); -} - -void recVUMI_MADD_xyzw(VURegs *VU, int xyzw, int info) -{ - //SysPrintf ("recVUMI_MADD_xyzw \n"); - if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); - recVUMI_MADD_xyzw_toD(VU, xyzw, EEREC_D, info); - recUpdateFlags(VU, EEREC_D, info); - // super bust-a-move arrows needs overflow clamping -} - -void recVUMI_MADDi(VURegs *VU, int info) { recVUMI_MADD_iq(VU, VU_VI_ADDR(REG_I, 1), info); } -void recVUMI_MADDq(VURegs *VU, int info) { recVUMI_MADD_iq(VU, VU_REGQ_ADDR, info); } -void recVUMI_MADDx(VURegs *VU, int info) { recVUMI_MADD_xyzw(VU, 0, info); } -void recVUMI_MADDy(VURegs *VU, int info) { recVUMI_MADD_xyzw(VU, 1, info); } -void recVUMI_MADDz(VURegs *VU, int info) { recVUMI_MADD_xyzw(VU, 2, info); } -void recVUMI_MADDw(VURegs *VU, int info) { recVUMI_MADD_xyzw(VU, 3, info); } -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// MADDA -//------------------------------------------------------------------ -void recVUMI_MADDA( VURegs *VU, int info ) -{ - //SysPrintf ("recVUMI_MADDA \n"); - recVUMI_MADD_toD(VU, EEREC_ACC, info); - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_MADDAi( VURegs *VU , int info) -{ - //SysPrintf ("recVUMI_MADDAi \n"); - recVUMI_MADD_iq_toD( VU, VU_VI_ADDR(REG_I, 1), EEREC_ACC, info); - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_MADDAq( VURegs *VU , int info) -{ - //SysPrintf ("recVUMI_MADDAq \n"); - recVUMI_MADD_iq_toD( VU, VU_REGQ_ADDR, EEREC_ACC, info); - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_MADDAx( VURegs *VU , int info) -{ - //SysPrintf ("recVUMI_MADDAx \n"); - recVUMI_MADD_xyzw_toD(VU, 0, EEREC_ACC, info); - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_MADDAy( VURegs *VU , int info) -{ - //SysPrintf ("recVUMI_MADDAy \n"); - recVUMI_MADD_xyzw_toD(VU, 1, EEREC_ACC, info); - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_MADDAz( VURegs *VU , int info) -{ - //SysPrintf ("recVUMI_MADDAz \n"); - recVUMI_MADD_xyzw_toD(VU, 2, EEREC_ACC, info); - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_MADDAw( VURegs *VU , int info) -{ - //SysPrintf ("recVUMI_MADDAw \n"); - recVUMI_MADD_xyzw_toD(VU, 3, EEREC_ACC, info); - recUpdateFlags(VU, EEREC_ACC, info); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// MSUB -//------------------------------------------------------------------ -void recVUMI_MSUB_toD(VURegs *VU, int regd, int info) -{ - //SysPrintf ("recVUMI_MSUB_toD \n"); - if (CHECK_VU_EXTRA_OVERFLOW) { - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - if (_Ft_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - vuFloat5_useEAX( EEREC_ACC, EEREC_TEMP, _X_Y_Z_W ); - } - - if (_X_Y_Z_W != 0xf) { - int t1reg = _vuGetTempXMMreg(info); - - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } - - if( t1reg >= 0 ) { - SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_ACC); - SSE_SUBPS_XMM_to_XMM(t1reg, EEREC_TEMP); - - VU_MERGE_REGS(regd, t1reg); - _freeXMMreg(t1reg); - } - else { - SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); - SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); - VU_MERGE_REGS(regd, EEREC_TEMP); - } - } - else { - if( regd == EEREC_S ) { - assert( regd != EEREC_ACC ); - SSE_MULPS_XMM_to_XMM(regd, EEREC_T); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } - SSE_SUBPS_XMM_to_XMM(regd, EEREC_ACC); - SSE_XORPS_M128_to_XMM(regd, (uptr)&const_clip[4]); - } - else if( regd == EEREC_T ) { - assert( regd != EEREC_ACC ); - SSE_MULPS_XMM_to_XMM(regd, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } - SSE_SUBPS_XMM_to_XMM(regd, EEREC_ACC); - SSE_XORPS_M128_to_XMM(regd, (uptr)&const_clip[4]); - } - else if( regd == EEREC_TEMP ) { - SSE_MOVAPS_XMM_to_XMM(regd, EEREC_S); - SSE_MULPS_XMM_to_XMM(regd, EEREC_T); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } - SSE_SUBPS_XMM_to_XMM(regd, EEREC_ACC); - SSE_XORPS_M128_to_XMM(regd, (uptr)&const_clip[4]); - } - else { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_MOVAPS_XMM_to_XMM(regd, EEREC_ACC); - SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } - SSE_SUBPS_XMM_to_XMM(regd, EEREC_TEMP); - } - } -} - -void recVUMI_MSUB_temp_toD(VURegs *VU, int regd, int info) -{ - //SysPrintf ("recVUMI_MSUB_temp_toD \n"); - if (CHECK_VU_EXTRA_OVERFLOW) { - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); - vuFloat5_useEAX( EEREC_ACC, EEREC_TEMP, _X_Y_Z_W ); - } - - if (_X_Y_Z_W != 0xf) { - int t1reg = _vuGetTempXMMreg(info); - - SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } - - if( t1reg >= 0 ) { - SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_ACC); - SSE_SUBPS_XMM_to_XMM(t1reg, EEREC_TEMP); - - if ( regd != EEREC_TEMP ) { VU_MERGE_REGS(regd, t1reg); } - else SSE_MOVAPS_XMM_to_XMM(regd, t1reg); - - _freeXMMreg(t1reg); - } - else { - SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); - SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); - VU_MERGE_REGS(regd, EEREC_TEMP); - } - } - else { - if( regd == EEREC_ACC ) { - SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } - SSE_SUBPS_XMM_to_XMM(regd, EEREC_TEMP); - } - else if( regd == EEREC_S ) { - SSE_MULPS_XMM_to_XMM(regd, EEREC_TEMP); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } - SSE_SUBPS_XMM_to_XMM(regd, EEREC_ACC); - SSE_XORPS_M128_to_XMM(regd, (uptr)&const_clip[4]); - } - else if( regd == EEREC_TEMP ) { - SSE_MULPS_XMM_to_XMM(regd, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } - SSE_SUBPS_XMM_to_XMM(regd, EEREC_ACC); - SSE_XORPS_M128_to_XMM(regd, (uptr)&const_clip[4]); - } - else { - SSE_MOVAPS_XMM_to_XMM(regd, EEREC_ACC); - SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } - SSE_SUBPS_XMM_to_XMM(regd, EEREC_TEMP); - } - } -} - -void recVUMI_MSUB_iq_toD(VURegs *VU, int regd, int addr, int info) -{ - //SysPrintf ("recVUMI_MSUB_iq_toD \n"); - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); - SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); - recVUMI_MSUB_temp_toD(VU, regd, info); -} - -void recVUMI_MSUB_xyzw_toD(VURegs *VU, int regd, int xyzw, int info) -{ - //SysPrintf ("recVUMI_MSUB_xyzw_toD \n"); - _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); - recVUMI_MSUB_temp_toD(VU, regd, info); -} - -void recVUMI_MSUB(VURegs *VU, int info) -{ - //SysPrintf ("recVUMI_MSUB \n"); - if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); - recVUMI_MSUB_toD(VU, EEREC_D, info); - recUpdateFlags(VU, EEREC_D, info); -} - -void recVUMI_MSUB_iq(VURegs *VU, int addr, int info) -{ - //SysPrintf ("recVUMI_MSUB_iq \n"); - if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); - recVUMI_MSUB_iq_toD(VU, EEREC_D, addr, info); - recUpdateFlags(VU, EEREC_D, info); -} - -void recVUMI_MSUBi(VURegs *VU, int info) { recVUMI_MSUB_iq(VU, VU_VI_ADDR(REG_I, 1), info); } -void recVUMI_MSUBq(VURegs *VU, int info) { recVUMI_MSUB_iq(VU, VU_REGQ_ADDR, info); } -void recVUMI_MSUBx(VURegs *VU, int info) -{ - //SysPrintf ("recVUMI_MSUBx \n"); - if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); - recVUMI_MSUB_xyzw_toD(VU, EEREC_D, 0, info); - recUpdateFlags(VU, EEREC_D, info); -} - -void recVUMI_MSUBy(VURegs *VU, int info) -{ - //SysPrintf ("recVUMI_MSUBy \n"); - if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); - recVUMI_MSUB_xyzw_toD(VU, EEREC_D, 1, info); - recUpdateFlags(VU, EEREC_D, info); -} - -void recVUMI_MSUBz(VURegs *VU, int info) -{ - //SysPrintf ("recVUMI_MSUBz \n"); - if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); - recVUMI_MSUB_xyzw_toD(VU, EEREC_D, 2, info); - recUpdateFlags(VU, EEREC_D, info); -} - -void recVUMI_MSUBw(VURegs *VU, int info) -{ - //SysPrintf ("recVUMI_MSUBw \n"); - if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); - recVUMI_MSUB_xyzw_toD(VU, EEREC_D, 3, info); - recUpdateFlags(VU, EEREC_D, info); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// MSUBA -//------------------------------------------------------------------ -void recVUMI_MSUBA( VURegs *VU, int info ) -{ - //SysPrintf ("recVUMI_MSUBA \n"); - recVUMI_MSUB_toD(VU, EEREC_ACC, info); - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_MSUBAi( VURegs *VU, int info ) -{ - //SysPrintf ("recVUMI_MSUBAi \n"); - recVUMI_MSUB_iq_toD( VU, EEREC_ACC, VU_VI_ADDR(REG_I, 1), info ); - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_MSUBAq( VURegs *VU, int info ) -{ - //SysPrintf ("recVUMI_MSUBAq \n"); - recVUMI_MSUB_iq_toD( VU, EEREC_ACC, VU_REGQ_ADDR, info ); - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_MSUBAx( VURegs *VU, int info ) -{ - //SysPrintf ("recVUMI_MSUBAx \n"); - recVUMI_MSUB_xyzw_toD(VU, EEREC_ACC, 0, info); - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_MSUBAy( VURegs *VU, int info ) -{ - //SysPrintf ("recVUMI_MSUBAy \n"); - recVUMI_MSUB_xyzw_toD(VU, EEREC_ACC, 1, info); - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_MSUBAz( VURegs *VU, int info ) -{ - //SysPrintf ("recVUMI_MSUBAz \n"); - recVUMI_MSUB_xyzw_toD(VU, EEREC_ACC, 2, info); - recUpdateFlags(VU, EEREC_ACC, info); -} - -void recVUMI_MSUBAw( VURegs *VU, int info ) -{ - //SysPrintf ("recVUMI_MSUBAw \n"); - recVUMI_MSUB_xyzw_toD(VU, EEREC_ACC, 3, info); - recUpdateFlags(VU, EEREC_ACC, info); -} -//------------------------------------------------------------------ - - -static const u32 PCSX2_ALIGNED16(special_mask[4]) = {0xffffffff, 0x80000000, 0xffffffff, 0x80000000}; -static const u32 PCSX2_ALIGNED16(special_mask2[4]) = {0, 0x40000000, 0, 0x40000000}; - -u32 PCSX2_ALIGNED16(temp_loc[4]); -u32 PCSX2_ALIGNED16(temp_loc2[4]); - -//MAX/MINI are non-arithmetic operations that implicitly support numbers with the EXP field being 0 ("denormals"). -// -//As such, they are sometimes used for integer move and (positive!) integer max/min, knowing that integers that -//represent denormals will not be flushed to 0. -// -//As such, this implementation performs a non-arithmetic operation that supports "denormals" and "infs/nans". -//There might be an easier way to do it but here, MAX/MIN is performed with PMAXPD/PMINPD. -//Fake double-precision numbers are constructed by copying the sign of the original numbers, clearing the upper 32 bits, -//setting the 62nd bit to 1 (to ensure double-precision number is "normalized") and having the lower 32bits -//being the same as the original number. - -void MINMAXlogical(VURegs *VU, int info, int min, int mode, uptr addr = 0, int xyzw = 0) -//mode1 = iq, mode2 = xyzw, mode0 = normal -{ - int t1regbool = 0; - int t1reg = _vuGetTempXMMreg(info); - if (t1reg < 0) - { - t1regbool = 1; - for (t1reg = 0; ( (t1reg == EEREC_D) || (t1reg == EEREC_S) || (mode != 1 && t1reg == EEREC_T) - || (t1reg == EEREC_TEMP) ); t1reg++); // Find unused reg (For first temp reg) - SSE_MOVAPS_XMM_to_M128((uptr)temp_loc, t1reg); // Backup t1reg XMM reg - } - int t2regbool = -1; - int t2reg = EEREC_TEMP; - if (EEREC_TEMP == EEREC_D || EEREC_TEMP == EEREC_S || (mode != 1 && EEREC_TEMP == EEREC_T)) - { - t2regbool = 0; - t2reg = _vuGetTempXMMreg(info); - if (t2reg < 0) - { - t2regbool = 1; - for (t2reg = 0; ( (t2reg == EEREC_D) || (t2reg == EEREC_S) || (mode != 1 && t2reg == EEREC_T) || - (t2reg == t1reg) || (t2reg == EEREC_TEMP) ); t2reg++); // Find unused reg (For second temp reg) - SSE_MOVAPS_XMM_to_M128((uptr)temp_loc2, t2reg); // Backup t2reg XMM reg - } - } - - if (_X || _Y) - { - SSE2_PSHUFD_XMM_to_XMM(t1reg, EEREC_S, 0x50); - SSE2_PAND_M128_to_XMM(t1reg, (uptr)special_mask); - SSE2_POR_M128_to_XMM(t1reg, (uptr)special_mask2); - if (mode == 0) - SSE2_PSHUFD_XMM_to_XMM(t2reg, EEREC_T, 0x50); - else if (mode == 1) - { - SSE2_MOVD_M32_to_XMM(t2reg, addr); - SSE2_PSHUFD_XMM_to_XMM(t2reg, t2reg, 0x00); - } - else if (mode == 2) - _unpackVF_xyzw(t2reg, EEREC_T, xyzw); - SSE2_PAND_M128_to_XMM(t2reg, (uptr)special_mask); - SSE2_POR_M128_to_XMM(t2reg, (uptr)special_mask2); - if (min) - SSE2_MINPD_XMM_to_XMM(t1reg, t2reg); - else - SSE2_MAXPD_XMM_to_XMM(t1reg, t2reg); - SSE2_PSHUFD_XMM_to_XMM(t1reg, t1reg, 0x88); - VU_MERGE_REGS_CUSTOM(EEREC_D, t1reg, 0xc & _X_Y_Z_W); - } - - if (_Z || _W) - { - SSE2_PSHUFD_XMM_to_XMM(t1reg, EEREC_S, 0xfa); - SSE2_PAND_M128_to_XMM(t1reg, (uptr)special_mask); - SSE2_POR_M128_to_XMM(t1reg, (uptr)special_mask2); - if (mode == 0) - SSE2_PSHUFD_XMM_to_XMM(t2reg, EEREC_T, 0xfa); - else if (mode == 1) - { - SSE2_MOVD_M32_to_XMM(t2reg, addr); - SSE2_PSHUFD_XMM_to_XMM(t2reg, t2reg, 0x00); - } - else if (mode == 2) - _unpackVF_xyzw(t2reg, EEREC_T, xyzw); - SSE2_PAND_M128_to_XMM(t2reg, (uptr)special_mask); - SSE2_POR_M128_to_XMM(t2reg, (uptr)special_mask2); - if (min) - SSE2_MINPD_XMM_to_XMM(t1reg, t2reg); - else - SSE2_MAXPD_XMM_to_XMM(t1reg, t2reg); - SSE2_PSHUFD_XMM_to_XMM(t1reg, t1reg, 0x88); - VU_MERGE_REGS_CUSTOM(EEREC_D, t1reg, 0x3 & _X_Y_Z_W); - } - - if (t1regbool == 0) - _freeXMMreg(t1reg); - else if (t1regbool == 1) - SSE_MOVAPS_M128_to_XMM(t1reg, (uptr)temp_loc); // Restore t1reg XMM reg - if (t2regbool == 0) - _freeXMMreg(t2reg); - else if (t2regbool == 1) - SSE_MOVAPS_M128_to_XMM(t2reg, (uptr)temp_loc2); // Restore t2reg XMM reg -} - -//------------------------------------------------------------------ -// MAX -//------------------------------------------------------------------ - -void recVUMI_MAX(VURegs *VU, int info) -{ - if ( _Fd_ == 0 ) return; - //SysPrintf ("recVUMI_MAX \n"); - - if (MINMAXFIX) - MINMAXlogical(VU, info, 0, 0); - else - { - - if (_Fs_) vuFloat4_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); // Always do Preserved Sign Clamping - if (_Ft_) vuFloat4_useEAX( EEREC_T, EEREC_TEMP, _X_Y_Z_W ); - - if( _X_Y_Z_W == 8 ) { - if (EEREC_D == EEREC_S) SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_T); - else if (EEREC_D == EEREC_T) SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_T); - } - } - else if (_X_Y_Z_W != 0xf) { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_MAXPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); - - VU_MERGE_REGS(EEREC_D, EEREC_TEMP); - } - else { - if( EEREC_D == EEREC_S ) SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_T); - } - } - } -} - -void recVUMI_MAX_iq(VURegs *VU, uptr addr, int info) -{ - if ( _Fd_ == 0 ) return; - //SysPrintf ("recVUMI_MAX_iq \n"); - - if (MINMAXFIX) - MINMAXlogical(VU, info, 0, 1, addr); - else - { - if (_Fs_) vuFloat4_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); // Always do Preserved Sign Clamping - vuFloat3(addr); - - if( _XYZW_SS ) { - if( EEREC_D == EEREC_TEMP ) { - _vuFlipRegSS(VU, EEREC_S); - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_MAXSS_M32_to_XMM(EEREC_D, addr); - _vuFlipRegSS(VU, EEREC_S); - - // have to flip over EEREC_D if computing flags! - //if( (info & PROCESS_VU_UPDATEFLAGS) ) - _vuFlipRegSS(VU, EEREC_D); - } - else if( EEREC_D == EEREC_S ) { - _vuFlipRegSS(VU, EEREC_D); - SSE_MAXSS_M32_to_XMM(EEREC_D, addr); - _vuFlipRegSS(VU, EEREC_D); - } - else { - if( _X ) { - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_MAXSS_M32_to_XMM(EEREC_D, addr); - } - else { - _vuMoveSS(VU, EEREC_TEMP, EEREC_S); - _vuFlipRegSS(VU, EEREC_D); - SSE_MAXSS_M32_to_XMM(EEREC_TEMP, addr); - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); - _vuFlipRegSS(VU, EEREC_D); - } - } - } - else if (_X_Y_Z_W != 0xf) { - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); - SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); - SSE_MAXPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(EEREC_D, EEREC_TEMP); - } - else { - if(EEREC_D == EEREC_S) { - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); - SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); - SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); - } - else { - SSE_MOVSS_M32_to_XMM(EEREC_D, addr); - SSE_SHUFPS_XMM_to_XMM(EEREC_D, EEREC_D, 0x00); - SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_S); - } - } - } -} - -void recVUMI_MAX_xyzw(VURegs *VU, int xyzw, int info) -{ - if ( _Fd_ == 0 ) return; - //SysPrintf ("recVUMI_MAX_xyzw \n"); - - if (_Fs_ == 0 && _Ft_ == 0) - { - if( _X_Y_Z_W == 8 && (EEREC_D != EEREC_TEMP)) { - if( xyzw < 3 ) { - SSE_XORPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); - } - else { - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)s_fones); - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); - } - } - else if (_X_Y_Z_W != 0xf) { - if( xyzw < 3 ) { - if( _X_Y_Z_W & 1 ) SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, (uptr)&VU->VF[0].UL[0]); // w included, so insert the whole reg - else SSE_XORPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); // w not included, can zero out - } - else SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, (uptr)s_fones); - VU_MERGE_REGS(EEREC_D, EEREC_TEMP); - } - else { - if( xyzw < 3 ) SSE_XORPS_XMM_to_XMM(EEREC_D, EEREC_D); - else SSE_MOVAPS_M128_to_XMM(EEREC_D, (uptr)s_fones); - } - return; - } - - if (MINMAXFIX) - MINMAXlogical(VU, info, 0, 2, 0, xyzw); - else - { - if (_Fs_) vuFloat4_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); // Always do Preserved Sign Clamping - if (_Ft_) vuFloat4_useEAX( EEREC_T, EEREC_TEMP, ( 1 << (3 - xyzw) ) ); - - if( _X_Y_Z_W == 8 && (EEREC_D != EEREC_TEMP)) { - if( xyzw == 0 ) { - if( EEREC_D == EEREC_S ) SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_T); - } - } - else { - _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); - } - } - else if (_X_Y_Z_W != 0xf) { - _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); - SSE_MAXPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(EEREC_D, EEREC_TEMP); - } - else { - if (EEREC_D == EEREC_S) { - _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); - SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); - } - else { - _unpackVF_xyzw(EEREC_D, EEREC_T, xyzw); - SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_S); - } - } - } -} - -void recVUMI_MAXi(VURegs *VU, int info) { recVUMI_MAX_iq(VU, VU_VI_ADDR(REG_I, 1), info); } -void recVUMI_MAXx(VURegs *VU, int info) { recVUMI_MAX_xyzw(VU, 0, info); } -void recVUMI_MAXy(VURegs *VU, int info) { recVUMI_MAX_xyzw(VU, 1, info); } -void recVUMI_MAXz(VURegs *VU, int info) { recVUMI_MAX_xyzw(VU, 2, info); } -void recVUMI_MAXw(VURegs *VU, int info) { recVUMI_MAX_xyzw(VU, 3, info); } -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// MINI -//------------------------------------------------------------------ -void recVUMI_MINI(VURegs *VU, int info) -{ - if ( _Fd_ == 0 ) return; - //SysPrintf ("recVUMI_MINI\n"); - - if (MINMAXFIX) - MINMAXlogical(VU, info, 1, 0); - else - { - - if (_Fs_) vuFloat4_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); // Always do Preserved Sign Clamping - if (_Ft_) vuFloat4_useEAX( EEREC_T, EEREC_TEMP, _X_Y_Z_W ); - - if( _X_Y_Z_W == 8 ) { - if (EEREC_D == EEREC_S) SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_T); - else if (EEREC_D == EEREC_T) SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_T); - } - } - else if (_X_Y_Z_W != 0xf) { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_MINPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); - - VU_MERGE_REGS(EEREC_D, EEREC_TEMP); - } - else { - if( EEREC_D == EEREC_S ) { - //ClampUnordered(EEREC_T, EEREC_TEMP, 0); // need for GT4 vu0rec - SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_T); - } - else if( EEREC_D == EEREC_T ) { - //ClampUnordered(EEREC_S, EEREC_TEMP, 0); // need for GT4 vu0rec - SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_S); - } - else { - SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_T); - } - } - } -} - -void recVUMI_MINI_iq(VURegs *VU, uptr addr, int info) -{ - if ( _Fd_ == 0 ) return; - //SysPrintf ("recVUMI_MINI_iq \n"); - - if (MINMAXFIX) - MINMAXlogical(VU, info, 1, 1, addr); - else - { - - if (_Fs_) vuFloat4_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); // Always do Preserved Sign Clamping - vuFloat3(addr); - - if( _XYZW_SS ) { - if( EEREC_D == EEREC_TEMP ) { - _vuFlipRegSS(VU, EEREC_S); - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_MINSS_M32_to_XMM(EEREC_D, addr); - _vuFlipRegSS(VU, EEREC_S); - - // have to flip over EEREC_D if computing flags! - //if( (info & PROCESS_VU_UPDATEFLAGS) ) - _vuFlipRegSS(VU, EEREC_D); - } - else if( EEREC_D == EEREC_S ) { - _vuFlipRegSS(VU, EEREC_D); - SSE_MINSS_M32_to_XMM(EEREC_D, addr); - _vuFlipRegSS(VU, EEREC_D); - } - else { - if( _X ) { - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_MINSS_M32_to_XMM(EEREC_D, addr); - } - else { - _vuMoveSS(VU, EEREC_TEMP, EEREC_S); - _vuFlipRegSS(VU, EEREC_D); - SSE_MINSS_M32_to_XMM(EEREC_TEMP, addr); - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); - _vuFlipRegSS(VU, EEREC_D); - } - } - } - else if (_X_Y_Z_W != 0xf) { - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); - SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); - SSE_MINPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(EEREC_D, EEREC_TEMP); - } - else { - if(EEREC_D == EEREC_S) { - SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); - SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); - SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); - } - else { - SSE_MOVSS_M32_to_XMM(EEREC_D, addr); - SSE_SHUFPS_XMM_to_XMM(EEREC_D, EEREC_D, 0x00); - SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_S); - } - } - } -} - -void recVUMI_MINI_xyzw(VURegs *VU, int xyzw, int info) -{ - if ( _Fd_ == 0 ) return; - //SysPrintf ("recVUMI_MINI_xyzw \n"); - - if (MINMAXFIX) - MINMAXlogical(VU, info, 1, 2, 0, xyzw); - else - { - if (_Fs_) vuFloat4_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); // Always do Preserved Sign Clamping - if (_Ft_) vuFloat4_useEAX( EEREC_T, EEREC_TEMP, ( 1 << (3 - xyzw) ) ); - - if( _X_Y_Z_W == 8 && (EEREC_D != EEREC_TEMP)) { - if( xyzw == 0 ) { - if( EEREC_D == EEREC_S ) SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_S); - else { - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_T); - } - } - else { - _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); - SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); - SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); - } - } - else if (_X_Y_Z_W != 0xf) { - _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); - SSE_MINPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - VU_MERGE_REGS(EEREC_D, EEREC_TEMP); - } - else { - if (EEREC_D == EEREC_S) { - _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); - SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); - } - else { - _unpackVF_xyzw(EEREC_D, EEREC_T, xyzw); - SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_S); - } - } - } -} - -void recVUMI_MINIi(VURegs *VU, int info) { recVUMI_MINI_iq(VU, VU_VI_ADDR(REG_I, 1), info); } -void recVUMI_MINIx(VURegs *VU, int info) { recVUMI_MINI_xyzw(VU, 0, info); } -void recVUMI_MINIy(VURegs *VU, int info) { recVUMI_MINI_xyzw(VU, 1, info); } -void recVUMI_MINIz(VURegs *VU, int info) { recVUMI_MINI_xyzw(VU, 2, info); } -void recVUMI_MINIw(VURegs *VU, int info) { recVUMI_MINI_xyzw(VU, 3, info); } -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// OPMULA -//------------------------------------------------------------------ -void recVUMI_OPMULA( VURegs *VU, int info ) -{ - //SysPrintf ("recVUMI_OPMULA \n"); - if (CHECK_VU_EXTRA_OVERFLOW) { - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, 0xE); - if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, 0xE); - } - - SSE_MOVAPS_XMM_to_XMM( EEREC_TEMP, EEREC_S ); - SSE_SHUFPS_XMM_to_XMM( EEREC_T, EEREC_T, 0xD2 ); // EEREC_T = WYXZ - SSE_SHUFPS_XMM_to_XMM( EEREC_TEMP, EEREC_TEMP, 0xC9 ); // EEREC_TEMP = WXZY - SSE_MULPS_XMM_to_XMM( EEREC_TEMP, EEREC_T ); - - VU_MERGE_REGS_CUSTOM(EEREC_ACC, EEREC_TEMP, 14); - - // revert EEREC_T - if( EEREC_T != EEREC_ACC ) - SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0xC9); - - recUpdateFlags(VU, EEREC_ACC, info); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// OPMSUB -//------------------------------------------------------------------ -void recVUMI_OPMSUB( VURegs *VU, int info ) -{ - //SysPrintf ("recVUMI_OPMSUB \n"); - if (CHECK_VU_EXTRA_OVERFLOW) { - if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, 0xE); - if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, 0xE); - } - - if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0xD2); // EEREC_T = WYXZ - SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0xC9); // EEREC_TEMP = WXZY - SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); - - // negate and add - SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); - SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); - VU_MERGE_REGS_CUSTOM(EEREC_D, EEREC_TEMP, 14); - - // revert EEREC_T - if( EEREC_T != EEREC_D ) SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0xC9); - - recUpdateFlags(VU, EEREC_D, info); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// NOP -//------------------------------------------------------------------ -void recVUMI_NOP( VURegs *VU, int info ) -{ - //SysPrintf ("recVUMI_NOP \n"); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// recVUMI_FTOI_Saturate() - Saturates result from FTOI Instructions -//------------------------------------------------------------------ -static const PCSX2_ALIGNED16(int rec_const_0x8000000[4]) = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }; - -void recVUMI_FTOI_Saturate(int rec_s, int rec_t, int rec_tmp1, int rec_tmp2) -{ - //SysPrintf ("recVUMI_FTOI_Saturate \n"); - //Duplicate the xor'd sign bit to the whole value - //FFFF FFFF for positive, 0 for negative - SSE_MOVAPS_XMM_to_XMM(rec_tmp1, rec_s); - SSE2_PXOR_M128_to_XMM(rec_tmp1, (uptr)&const_clip[4]); - SSE2_PSRAD_I8_to_XMM(rec_tmp1, 31); - - //Create mask: 0 where !=8000 0000 - SSE_MOVAPS_XMM_to_XMM(rec_tmp2, rec_t); - SSE2_PCMPEQD_M128_to_XMM(rec_tmp2, (uptr)&const_clip[4]); - - //AND the mask w/ the edit values - SSE_ANDPS_XMM_to_XMM(rec_tmp1, rec_tmp2); - - //if v==8000 0000 && positive -> 8000 0000 + FFFF FFFF -> 7FFF FFFF - //if v==8000 0000 && negative -> 8000 0000 + 0 -> 8000 0000 - //if v!=8000 0000 -> v+0 (masked from the and) - - //Add the values as needed - SSE2_PADDD_XMM_to_XMM(rec_t, rec_tmp1); -} -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// FTOI 0/4/12/15 -//------------------------------------------------------------------ -static PCSX2_ALIGNED16(float FTIO_Temp1[4]) = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; -static PCSX2_ALIGNED16(float FTIO_Temp2[4]) = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; -void recVUMI_FTOI0(VURegs *VU, int info) -{ - int t1reg, t2reg; // Temp XMM regs - - if ( _Ft_ == 0 ) return; - - //SysPrintf ("recVUMI_FTOI0 \n"); - - if (_X_Y_Z_W != 0xf) { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - vuFloat_useEAX( info, EEREC_TEMP, 0xf ); // Clamp Infs and NaNs to pos/neg fmax (NaNs always to positive fmax) - SSE2_CVTTPS2DQ_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); - - t1reg = _vuGetTempXMMreg(info); - - if( t1reg >= 0 ) { // If theres a temp XMM reg available - for (t2reg = 0; ( (t2reg == EEREC_S) || (t2reg == EEREC_T) || (t2reg == EEREC_TEMP) || (t2reg == t1reg) ); t2reg++) - ; // Find unused reg (For second temp reg) - SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t2reg); // Backup XMM reg - - recVUMI_FTOI_Saturate(EEREC_S, EEREC_TEMP, t1reg, t2reg); // Saturate if Float->Int conversion returned illegal result - - SSE_MOVAPS_M128_to_XMM(t2reg, (uptr)FTIO_Temp1); // Restore XMM reg - _freeXMMreg(t1reg); // Free temp reg - } - else { // No temp reg available - for (t1reg = 0; ( (t1reg == EEREC_S) || (t1reg == EEREC_T) || (t1reg == EEREC_TEMP) ); t1reg++) - ; // Find unused reg (For first temp reg) - SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t1reg); // Backup t1reg XMM reg - - for (t2reg = 0; ( (t2reg == EEREC_S) || (t2reg == EEREC_T) || (t2reg == EEREC_TEMP) || (t2reg == t1reg) ); t2reg++) - ; // Find unused reg (For second temp reg) - SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp2, t2reg); // Backup t2reg XMM reg - - recVUMI_FTOI_Saturate(EEREC_S, EEREC_TEMP, t1reg, t2reg); // Saturate if Float->Int conversion returned illegal result - - SSE_MOVAPS_M128_to_XMM(t1reg, (uptr)FTIO_Temp1); // Restore t1reg XMM reg - SSE_MOVAPS_M128_to_XMM(t2reg, (uptr)FTIO_Temp2); // Restore t2reg XMM reg - } - - VU_MERGE_REGS(EEREC_T, EEREC_TEMP); - } - else { - if (EEREC_T != EEREC_S) { - SSE_MOVAPS_XMM_to_XMM(EEREC_T, EEREC_S); - vuFloat_useEAX( info, EEREC_T, 0xf ); // Clamp Infs and NaNs to pos/neg fmax (NaNs always to positive fmax) - SSE2_CVTTPS2DQ_XMM_to_XMM(EEREC_T, EEREC_T); - - t1reg = _vuGetTempXMMreg(info); - - if( t1reg >= 0 ) { // If theres a temp XMM reg available - recVUMI_FTOI_Saturate(EEREC_S, EEREC_T, EEREC_TEMP, t1reg); // Saturate if Float->Int conversion returned illegal result - _freeXMMreg(t1reg); // Free temp reg - } - else { // No temp reg available - for (t1reg = 0; ( (t1reg == EEREC_S) || (t1reg == EEREC_T) || (t1reg == EEREC_TEMP) ); t1reg++) - ; // Find unused reg - SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t1reg); // Backup t1reg XMM reg - - recVUMI_FTOI_Saturate(EEREC_S, EEREC_T, EEREC_TEMP, t1reg); // Saturate if Float->Int conversion returned illegal result - - SSE_MOVAPS_M128_to_XMM(t1reg, (uptr)FTIO_Temp1); // Restore t1reg XMM reg - } - } - else { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - vuFloat_useEAX( info, EEREC_TEMP, 0xf ); // Clamp Infs and NaNs to pos/neg fmax (NaNs always to positive fmax) - SSE2_CVTTPS2DQ_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); - - t1reg = _vuGetTempXMMreg(info); - - if( t1reg >= 0 ) { // If theres a temp XMM reg available - for (t2reg = 0; ( (t2reg == EEREC_S) || (t2reg == EEREC_T) || (t2reg == EEREC_TEMP) || (t2reg == t1reg)); t2reg++) - ; // Find unused reg (For second temp reg) - SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t2reg); // Backup XMM reg - - recVUMI_FTOI_Saturate(EEREC_S, EEREC_TEMP, t1reg, t2reg); // Saturate if Float->Int conversion returned illegal result - - SSE_MOVAPS_M128_to_XMM(t2reg, (uptr)FTIO_Temp1); // Restore XMM reg - _freeXMMreg(t1reg); // Free temp reg - } - else { // No temp reg available - for (t1reg = 0; ( (t1reg == EEREC_S) || (t1reg == EEREC_T) || (t1reg == EEREC_TEMP) ); t1reg++) - ; // Find unused reg (For first temp reg) - SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t1reg); // Backup t1reg XMM reg - - for (t2reg = 0; ( (t2reg == EEREC_S) || (t2reg == EEREC_T) || (t2reg == EEREC_TEMP) || (t2reg == t1reg) ); t2reg++) - ; // Find unused reg (For second temp reg) - SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp2, t2reg); // Backup t2reg XMM reg - - recVUMI_FTOI_Saturate(EEREC_S, EEREC_TEMP, t1reg, t2reg); // Saturate if Float->Int conversion returned illegal result - - SSE_MOVAPS_M128_to_XMM(t1reg, (uptr)FTIO_Temp1); // Restore t1reg XMM reg - SSE_MOVAPS_M128_to_XMM(t2reg, (uptr)FTIO_Temp2); // Restore t2reg XMM reg - } - - SSE_MOVAPS_XMM_to_XMM(EEREC_T, EEREC_TEMP); - } - } -} - -void recVUMI_FTOIX(VURegs *VU, int addr, int info) -{ - int t1reg, t2reg; // Temp XMM regs - - if ( _Ft_ == 0 ) return; - - //SysPrintf ("recVUMI_FTOIX \n"); - if (_X_Y_Z_W != 0xf) { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_MULPS_M128_to_XMM(EEREC_TEMP, addr); - vuFloat_useEAX( info, EEREC_TEMP, 0xf ); // Clamp Infs and NaNs to pos/neg fmax (NaNs always to positive fmax) - SSE2_CVTTPS2DQ_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); - - t1reg = _vuGetTempXMMreg(info); - - if( t1reg >= 0 ) { // If theres a temp XMM reg available - for (t2reg = 0; ( (t2reg == EEREC_S) || (t2reg == EEREC_T) || (t2reg == EEREC_TEMP) || (t2reg == t1reg)); t2reg++) - ; // Find unused reg (For second temp reg) - SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t2reg); // Backup XMM reg - - recVUMI_FTOI_Saturate(EEREC_S, EEREC_TEMP, t1reg, t2reg); // Saturate if Float->Int conversion returned illegal result - - SSE_MOVAPS_M128_to_XMM(t2reg, (uptr)FTIO_Temp1); // Restore XMM reg - _freeXMMreg(t1reg); // Free temp reg - } - else { // No temp reg available - for (t1reg = 0; ( (t1reg == EEREC_S) || (t1reg == EEREC_T) || (t1reg == EEREC_TEMP) ); t1reg++) - ; // Find unused reg (For first temp reg) - SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t1reg); // Backup t1reg XMM reg - - for (t2reg = 0; ( (t2reg == EEREC_S) || (t2reg == EEREC_T) || (t2reg == EEREC_TEMP) || (t2reg == t1reg) ); t2reg++) - ; // Find unused reg (For second temp reg) - SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp2, t2reg); // Backup t2reg XMM reg - - recVUMI_FTOI_Saturate(EEREC_S, EEREC_TEMP, t1reg, t2reg); // Saturate if Float->Int conversion returned illegal result - - SSE_MOVAPS_M128_to_XMM(t1reg, (uptr)FTIO_Temp1); // Restore t1reg XMM reg - SSE_MOVAPS_M128_to_XMM(t2reg, (uptr)FTIO_Temp2); // Restore t2reg XMM reg - } - - VU_MERGE_REGS(EEREC_T, EEREC_TEMP); - } - else { - if (EEREC_T != EEREC_S) { - SSE_MOVAPS_XMM_to_XMM(EEREC_T, EEREC_S); - SSE_MULPS_M128_to_XMM(EEREC_T, addr); - vuFloat_useEAX( info, EEREC_T, 0xf ); // Clamp Infs and NaNs to pos/neg fmax (NaNs always to positive fmax) - SSE2_CVTTPS2DQ_XMM_to_XMM(EEREC_T, EEREC_T); - - t1reg = _vuGetTempXMMreg(info); - - if( t1reg >= 0 ) { // If theres a temp XMM reg available - recVUMI_FTOI_Saturate(EEREC_S, EEREC_T, EEREC_TEMP, t1reg); // Saturate if Float->Int conversion returned illegal result - _freeXMMreg(t1reg); // Free temp reg - } - else { // No temp reg available - for (t1reg = 0; ( (t1reg == EEREC_S) || (t1reg == EEREC_T) || (t1reg == EEREC_TEMP) ); t1reg++) - ; // Find unused reg - SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t1reg); // Backup t1reg XMM reg - - recVUMI_FTOI_Saturate(EEREC_S, EEREC_T, EEREC_TEMP, t1reg); // Saturate if Float->Int conversion returned illegal result - - SSE_MOVAPS_M128_to_XMM(t1reg, (uptr)FTIO_Temp1); // Restore t1reg XMM reg - } - } - else { - SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_MULPS_M128_to_XMM(EEREC_TEMP, addr); - vuFloat_useEAX( info, EEREC_TEMP, 0xf ); // Clamp Infs and NaNs to pos/neg fmax (NaNs always to positive fmax) - SSE2_CVTTPS2DQ_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); - - t1reg = _vuGetTempXMMreg(info); - - if( t1reg >= 0 ) { // If theres a temp XMM reg available - for (t2reg = 0; ( (t2reg == EEREC_S) || (t2reg == EEREC_T) || (t2reg == EEREC_TEMP) || (t2reg == t1reg)); t2reg++) - ; // Find unused reg (For second temp reg) - SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t2reg); // Backup XMM reg - - recVUMI_FTOI_Saturate(EEREC_S, EEREC_TEMP, t1reg, t2reg); // Saturate if Float->Int conversion returned illegal result - - SSE_MOVAPS_M128_to_XMM(t2reg, (uptr)FTIO_Temp1); // Restore XMM reg - _freeXMMreg(t1reg); // Free temp reg - } - else { // No temp reg available - for (t1reg = 0; ( (t1reg == EEREC_S) || (t1reg == EEREC_T) || (t1reg == EEREC_TEMP) ); t1reg++) - ; // Find unused reg (For first temp reg) - SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t1reg); // Backup t1reg XMM reg - - for (t2reg = 0; ( (t2reg == EEREC_S) || (t2reg == EEREC_T) || (t2reg == EEREC_TEMP) || (t2reg == t1reg) ); t2reg++) - ; // Find unused reg (For second temp reg) - SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp2, t2reg); // Backup t2reg XMM reg - - recVUMI_FTOI_Saturate(EEREC_S, EEREC_TEMP, t1reg, t2reg); // Saturate if Float->Int conversion returned illegal result - - SSE_MOVAPS_M128_to_XMM(t1reg, (uptr)FTIO_Temp1); // Restore t1reg XMM reg - SSE_MOVAPS_M128_to_XMM(t2reg, (uptr)FTIO_Temp2); // Restore t2reg XMM reg - } - - SSE_MOVAPS_XMM_to_XMM(EEREC_T, EEREC_TEMP); - } - } -} - -void recVUMI_FTOI4( VURegs *VU, int info ) { recVUMI_FTOIX(VU, (uptr)&recMult_float_to_int4[0], info); } -void recVUMI_FTOI12( VURegs *VU, int info ) { recVUMI_FTOIX(VU, (uptr)&recMult_float_to_int12[0], info); } -void recVUMI_FTOI15( VURegs *VU, int info ) { recVUMI_FTOIX(VU, (uptr)&recMult_float_to_int15[0], info); } -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// ITOF 0/4/12/15 -//------------------------------------------------------------------ -void recVUMI_ITOF0( VURegs *VU, int info ) -{ - if ( _Ft_ == 0 ) return; - - //SysPrintf ("recVUMI_ITOF0 \n"); - if (_X_Y_Z_W != 0xf) { - SSE2_CVTDQ2PS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - vuFloat_useEAX( info, EEREC_TEMP, 15); // Clamp infinities - VU_MERGE_REGS(EEREC_T, EEREC_TEMP); - xmmregs[EEREC_T].mode |= MODE_WRITE; - } - else { - SSE2_CVTDQ2PS_XMM_to_XMM(EEREC_T, EEREC_S); - vuFloat2(EEREC_T, EEREC_TEMP, 15); // Clamp infinities - } -} - -void recVUMI_ITOFX(VURegs *VU, int addr, int info) -{ - if ( _Ft_ == 0 ) return; - - //SysPrintf ("recVUMI_ITOFX \n"); - if (_X_Y_Z_W != 0xf) { - SSE2_CVTDQ2PS_XMM_to_XMM(EEREC_TEMP, EEREC_S); - SSE_MULPS_M128_to_XMM(EEREC_TEMP, addr); - vuFloat_useEAX( info, EEREC_TEMP, 15); // Clamp infinities - VU_MERGE_REGS(EEREC_T, EEREC_TEMP); - xmmregs[EEREC_T].mode |= MODE_WRITE; - } - else { - SSE2_CVTDQ2PS_XMM_to_XMM(EEREC_T, EEREC_S); - SSE_MULPS_M128_to_XMM(EEREC_T, addr); - vuFloat2(EEREC_T, EEREC_TEMP, 15); // Clamp infinities - } -} - -void recVUMI_ITOF4( VURegs *VU, int info ) { recVUMI_ITOFX(VU, (uptr)&recMult_int_to_float4[0], info); } -void recVUMI_ITOF12( VURegs *VU, int info ) { recVUMI_ITOFX(VU, (uptr)&recMult_int_to_float12[0], info); } -void recVUMI_ITOF15( VURegs *VU, int info ) { recVUMI_ITOFX(VU, (uptr)&recMult_int_to_float15[0], info); } -//------------------------------------------------------------------ - - -//------------------------------------------------------------------ -// CLIP -//------------------------------------------------------------------ -void recVUMI_CLIP(VURegs *VU, int info) -{ - int t1reg = EEREC_D; - int t2reg = EEREC_ACC; - int x86temp1, x86temp2; - - u32 clipaddr = VU_VI_ADDR(REG_CLIP_FLAG, 0); - u32 prevclipaddr = VU_VI_ADDR(REG_CLIP_FLAG, 2); - - if( clipaddr == 0 ) { // battle star has a clip right before fcset - SysPrintf("skipping vu clip\n"); - return; - } - - //Flush the clip flag before processing, incase of double clip commands (GoW) - - if( prevclipaddr != (uptr)&VU->VI[REG_CLIP_FLAG] ) { - MOV32MtoR(EAX, prevclipaddr); - MOV32RtoM((uptr)&VU->VI[REG_CLIP_FLAG], EAX); - } - - assert( clipaddr != 0 ); - assert( t1reg != t2reg && t1reg != EEREC_TEMP && t2reg != EEREC_TEMP ); - - x86temp1 = ALLOCTEMPX86(MODE_8BITREG); - x86temp2 = ALLOCTEMPX86(MODE_8BITREG); - - //if ( (x86temp1 == 0) || (x86temp2 == 0) ) SysPrintf("VU CLIP Allocation Error: EAX being allocated! \n"); - - _freeXMMreg(t1reg); // These should have been freed at allocation in eeVURecompileCode() - _freeXMMreg(t2reg); // but if they've been used since then, then free them. (just doing this incase :p (cottonvibes)) - - if( _Ft_ == 0 ) { - SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, (uptr)&s_fones[0]); // all 1s - SSE_MOVAPS_M128_to_XMM(t1reg, (uptr)&s_fones[4]); - } - else { - _unpackVF_xyzw(EEREC_TEMP, EEREC_T, 3); - SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[0]); - SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_TEMP); - SSE_ORPS_M128_to_XMM(t1reg, (uptr)&const_clip[4]); - } - - MOV32MtoR(EAX, prevclipaddr); - - SSE_CMPNLEPS_XMM_to_XMM(t1reg, EEREC_S); //-w, -z, -y, -x - SSE_CMPLTPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); //+w, +z, +y, +x - - SHL32ItoR(EAX, 6); - - SSE_MOVAPS_XMM_to_XMM(t2reg, EEREC_TEMP); //t2 = +w, +z, +y, +x - SSE_UNPCKLPS_XMM_to_XMM(EEREC_TEMP, t1reg); //EEREC_TEMP = -y,+y,-x,+x - SSE_UNPCKHPS_XMM_to_XMM(t2reg, t1reg); //t2reg = -w,+w,-z,+z - SSE_MOVMSKPS_XMM_to_R32(x86temp2, EEREC_TEMP); // -y,+y,-x,+x - SSE_MOVMSKPS_XMM_to_R32(x86temp1, t2reg); // -w,+w,-z,+z - - AND8ItoR(x86temp1, 0x3); - SHL8ItoR(x86temp1, 4); - OR8RtoR(EAX, x86temp1); - AND8ItoR(x86temp2, 0xf); - OR8RtoR(EAX, x86temp2); - AND32ItoR(EAX, 0xffffff); - - MOV32RtoM(clipaddr, EAX); - - if (( !(info & (PROCESS_VU_SUPER|PROCESS_VU_COP2)) ) ) //Instantly update the flag if its called from elsewhere (unlikely, but ok) - MOV32RtoM((uptr)&VU->VI[REG_CLIP_FLAG], EAX); - - _freeX86reg(x86temp1); - _freeX86reg(x86temp2); +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "PrecompiledHeader.h" + +#include "Common.h" +#include "GS.h" +#include "R5900OpcodeTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "iMMI.h" +#include "iFPU.h" +#include "iCOP0.h" +#include "VUmicro.h" +#include "VUflags.h" +#include "iVUmicro.h" +#include "iVUops.h" +#include "iVUzerorec.h" +//------------------------------------------------------------------ +#define MINMAXFIX 1 +//------------------------------------------------------------------ +// Helper Macros +//------------------------------------------------------------------ +#define _Ft_ (( VU->code >> 16) & 0x1F) // The rt part of the instruction register +#define _Fs_ (( VU->code >> 11) & 0x1F) // The rd part of the instruction register +#define _Fd_ (( VU->code >> 6) & 0x1F) // The sa part of the instruction register + +#define _X (( VU->code>>24) & 0x1) +#define _Y (( VU->code>>23) & 0x1) +#define _Z (( VU->code>>22) & 0x1) +#define _W (( VU->code>>21) & 0x1) + +#define _XYZW_SS (_X+_Y+_Z+_W==1) + +#define _Fsf_ (( VU->code >> 21) & 0x03) +#define _Ftf_ (( VU->code >> 23) & 0x03) + +#define _Imm11_ (s32)(VU->code & 0x400 ? 0xfffffc00 | (VU->code & 0x3ff) : VU->code & 0x3ff) +#define _UImm11_ (s32)(VU->code & 0x7ff) + +#define VU_VFx_ADDR(x) (uptr)&VU->VF[x].UL[0] +#define VU_VFy_ADDR(x) (uptr)&VU->VF[x].UL[1] +#define VU_VFz_ADDR(x) (uptr)&VU->VF[x].UL[2] +#define VU_VFw_ADDR(x) (uptr)&VU->VF[x].UL[3] + +#define VU_REGR_ADDR (uptr)&VU->VI[REG_R] +#define VU_REGQ_ADDR (uptr)&VU->VI[REG_Q] +#define VU_REGMAC_ADDR (uptr)&VU->VI[REG_MAC_FLAG] + +#define VU_VI_ADDR(x, read) GetVIAddr(VU, x, read, info) + +#define VU_ACCx_ADDR (uptr)&VU->ACC.UL[0] +#define VU_ACCy_ADDR (uptr)&VU->ACC.UL[1] +#define VU_ACCz_ADDR (uptr)&VU->ACC.UL[2] +#define VU_ACCw_ADDR (uptr)&VU->ACC.UL[3] + +#define _X_Y_Z_W ((( VU->code >> 21 ) & 0xF ) ) +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// Global Variables +//------------------------------------------------------------------ +static const PCSX2_ALIGNED16(int SSEmovMask[ 16 ][ 4 ]) = +{ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF }, + { 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000 }, + { 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF }, + { 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000 }, + { 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF }, + { 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 }, + { 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }, + { 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 }, + { 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF }, + { 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000 }, + { 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF }, + { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000 }, + { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF }, + { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 }, + { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF } +}; + +static const PCSX2_ALIGNED16(u32 const_abs_table[16][4]) = +{ + { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }, //0000 + { 0xffffffff, 0xffffffff, 0xffffffff, 0x7fffffff }, //0001 + { 0xffffffff, 0xffffffff, 0x7fffffff, 0xffffffff }, //0010 + { 0xffffffff, 0xffffffff, 0x7fffffff, 0x7fffffff }, //0011 + { 0xffffffff, 0x7fffffff, 0xffffffff, 0xffffffff }, //0100 + { 0xffffffff, 0x7fffffff, 0xffffffff, 0x7fffffff }, //0101 + { 0xffffffff, 0x7fffffff, 0x7fffffff, 0xffffffff }, //0110 + { 0xffffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff }, //0111 + { 0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff }, //1000 + { 0x7fffffff, 0xffffffff, 0xffffffff, 0x7fffffff }, //1001 + { 0x7fffffff, 0xffffffff, 0x7fffffff, 0xffffffff }, //1010 + { 0x7fffffff, 0xffffffff, 0x7fffffff, 0x7fffffff }, //1011 + { 0x7fffffff, 0x7fffffff, 0xffffffff, 0xffffffff }, //1100 + { 0x7fffffff, 0x7fffffff, 0xffffffff, 0x7fffffff }, //1101 + { 0x7fffffff, 0x7fffffff, 0x7fffffff, 0xffffffff }, //1110 + { 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff }, //1111 +}; + +static const PCSX2_ALIGNED16(float recMult_float_to_int4[4]) = { 16.0, 16.0, 16.0, 16.0 }; +static const PCSX2_ALIGNED16(float recMult_float_to_int12[4]) = { 4096.0, 4096.0, 4096.0, 4096.0 }; +static const PCSX2_ALIGNED16(float recMult_float_to_int15[4]) = { 32768.0, 32768.0, 32768.0, 32768.0 }; + +static const PCSX2_ALIGNED16(float recMult_int_to_float4[4]) = { 0.0625f, 0.0625f, 0.0625f, 0.0625f }; +static const PCSX2_ALIGNED16(float recMult_int_to_float12[4]) = { 0.000244140625, 0.000244140625, 0.000244140625, 0.000244140625 }; +static const PCSX2_ALIGNED16(float recMult_int_to_float15[4]) = { 0.000030517578125, 0.000030517578125, 0.000030517578125, 0.000030517578125 }; + +static const PCSX2_ALIGNED16(u32 VU_Underflow_Mask1[4]) = {0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000}; +static const PCSX2_ALIGNED16(u32 VU_Underflow_Mask2[4]) = {0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff}; +static const PCSX2_ALIGNED16(u32 VU_Zero_Mask[4]) = {0x00000000, 0x00000000, 0x00000000, 0x00000000}; +static const PCSX2_ALIGNED16(u32 VU_Zero_Helper_Mask[4]) = {0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff}; +static const PCSX2_ALIGNED16(u32 VU_Signed_Zero_Mask[4]) = {0x80000000, 0x80000000, 0x80000000, 0x80000000}; +static const PCSX2_ALIGNED16(u32 VU_Pos_Infinity[4]) = {0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000}; +static const PCSX2_ALIGNED16(u32 VU_Neg_Infinity[4]) = {0xff800000, 0xff800000, 0xff800000, 0xff800000}; +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// recUpdateFlags() - Computes the flags for the Upper Opcodes +// +// Note: Computes under/overflow flags if CHECK_VU_EXTRA_FLAGS is 1 +//------------------------------------------------------------------ +PCSX2_ALIGNED16(u64 TEMPXMMData[2]); +void recUpdateFlags(VURegs * VU, int reg, int info) +{ + static u8 *pjmp, *pjmp2; + static u32 *pjmp32; + static u32 macaddr, stataddr, prevstataddr; + static int x86macflag, x86statflag, x86temp; + static int t1reg, t1regBoolean; + static const int flipMask[16] = {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}; + + if( !(info & PROCESS_VU_UPDATEFLAGS) ) return; + + //SysPrintf ("recUpdateFlags\n"); + + macaddr = VU_VI_ADDR(REG_MAC_FLAG, 0); + stataddr = VU_VI_ADDR(REG_STATUS_FLAG, 0); // write address + prevstataddr = VU_VI_ADDR(REG_STATUS_FLAG, 2); // previous address + + if( stataddr == 0 ) stataddr = prevstataddr; + if( macaddr == 0 ) { + SysPrintf( "VU ALLOCATION WARNING: Using Mac Flag Previous Address!\n" ); + macaddr = VU_VI_ADDR(REG_MAC_FLAG, 2); + } + + x86macflag = ALLOCTEMPX86(0); + x86statflag = ALLOCTEMPX86(0); + + if (reg == EEREC_TEMP) { + t1reg = _vuGetTempXMMreg(info); + if (t1reg < 0) { + //SysPrintf( "VU ALLOCATION ERROR: Temp reg can't be allocated!!!!\n" ); + t1reg = (reg == 0) ? 1 : 0; // Make t1reg != reg + SSE_MOVAPS_XMM_to_M128( (uptr)TEMPXMMData, t1reg ); // Backup data to temp address + t1regBoolean = 1; + } + else t1regBoolean = 0; + } + else { + t1reg = EEREC_TEMP; + t1regBoolean = 2; + } + + SSE_SHUFPS_XMM_to_XMM(reg, reg, 0x1B); // Flip wzyx to xyzw + MOV32MtoR(x86statflag, prevstataddr); // Load the previous status in to x86statflag + AND16ItoR(x86statflag, 0xff0); // Keep Sticky and D/I flags + + + if (CHECK_VU_EXTRA_FLAGS) { // Checks all flags + + x86temp = ALLOCTEMPX86(0); + + //-------------------------Check for Overflow flags------------------------------ + + //SSE_XORPS_XMM_to_XMM(t1reg, t1reg); // Clear t1reg + //SSE_CMPUNORDPS_XMM_to_XMM(t1reg, reg); // If reg == NaN then set Vector to 0xFFFFFFFF + + //SSE_MOVAPS_XMM_to_XMM(t1reg, reg); + //SSE_MINPS_M128_to_XMM(t1reg, (uptr)g_maxvals); + //SSE_MAXPS_M128_to_XMM(t1reg, (uptr)g_minvals); + //SSE_CMPNEPS_XMM_to_XMM(t1reg, reg); // If they're not equal, then overflow has occured + + SSE_MOVAPS_XMM_to_XMM(t1reg, reg); + SSE_ANDPS_M128_to_XMM(t1reg, (uptr)VU_Zero_Helper_Mask); + SSE_CMPEQPS_M128_to_XMM(t1reg, (uptr)VU_Pos_Infinity); // If infinity, then overflow has occured (NaN's don't report as overflow) + + SSE_MOVMSKPS_XMM_to_R32(x86macflag, t1reg); // Move the sign bits of the previous calculation + + AND16ItoR(x86macflag, _X_Y_Z_W ); // Grab "Has Overflowed" bits from the previous calculation (also make sure we're only grabbing from the XYZW being modified) + pjmp = JZ8(0); // Skip if none are + OR16ItoR(x86statflag, 0x208); // OS, O flags + SHL16ItoR(x86macflag, 12); + if (_XYZW_SS) pjmp32 = JMP32(0); // Skip Underflow Check + x86SetJ8(pjmp); + + //-------------------------Check for Underflow flags------------------------------ + + SSE_MOVAPS_XMM_to_XMM(t1reg, reg); // t1reg <- reg + + SSE_ANDPS_M128_to_XMM(t1reg, (uptr)&VU_Underflow_Mask1[ 0 ]); + SSE_CMPEQPS_M128_to_XMM(t1reg, (uptr)&VU_Zero_Mask[ 0 ]); // If (t1reg == zero exponent) then set Vector to 0xFFFFFFFF + + SSE_ANDPS_XMM_to_XMM(t1reg, reg); + SSE_ANDPS_M128_to_XMM(t1reg, (uptr)&VU_Underflow_Mask2[ 0 ]); + SSE_CMPNEPS_M128_to_XMM(t1reg, (uptr)&VU_Zero_Mask[ 0 ]); // If (t1reg != zero mantisa) then set Vector to 0xFFFFFFFF + + SSE_MOVMSKPS_XMM_to_R32(EAX, t1reg); // Move the sign bits of the previous calculation + + AND16ItoR(EAX, _X_Y_Z_W ); // Grab "Has Underflowed" bits from the previous calculation + pjmp = JZ8(0); // Skip if none are + OR16ItoR(x86statflag, 0x104); // US, U flags + SHL16ItoR(EAX, 8); + OR32RtoR(x86macflag, EAX); + x86SetJ8(pjmp); + + //-------------------------Optional Code: Denormals Are Zero------------------------------ + if (CHECK_VU_UNDERFLOW) { // Sets underflow/denormals to zero + SSE_ANDNPS_XMM_to_XMM(t1reg, reg); // t1reg = !t1reg & reg (t1reg = denormals are positive zero) + VU_MERGE_REGS_SAFE(t1reg, reg, (15 - flipMask[_X_Y_Z_W])); // Send t1reg the vectors that shouldn't be modified (since reg was flipped, we need a mask to get the unmodified vectors) + // Now we have Denormals are Positive Zero in t1reg; the next two lines take Signed Zero into account + SSE_ANDPS_M128_to_XMM(reg, (uptr)&VU_Signed_Zero_Mask[ 0 ]); // Only keep the sign bit for each vector + SSE_ORPS_XMM_to_XMM(reg, t1reg); // Denormals are Signed Zero, and unmodified vectors stay the same! + } + + if (_XYZW_SS) x86SetJ32(pjmp32); // If we skipped the Underflow Flag Checking (when we had an Overflow), return here + + vuFloat2(reg, t1reg, flipMask[_X_Y_Z_W]); // Clamp overflowed vectors that were modified (remember reg's vectors have been flipped, so have to use a flipmask) + + //-------------------------Check for Signed flags------------------------------ + + // The following code makes sure the Signed Bit isn't set with Negative Zero + SSE_XORPS_XMM_to_XMM(t1reg, t1reg); // Clear t1reg + SSE_CMPEQPS_XMM_to_XMM(t1reg, reg); // Set all F's if each vector is zero + SSE_MOVMSKPS_XMM_to_R32(x86temp, t1reg); // Used for Zero Flag Calculation + SSE_ANDNPS_XMM_to_XMM(t1reg, reg); + + SSE_MOVMSKPS_XMM_to_R32(EAX, t1reg); // Move the sign bits of the t1reg + + AND16ItoR(EAX, _X_Y_Z_W ); // Grab "Is Signed" bits from the previous calculation + pjmp = JZ8(0); // Skip if none are + OR16ItoR(x86statflag, 0x82); // SS, S flags + SHL16ItoR(EAX, 4); + OR32RtoR(x86macflag, EAX); + if (_XYZW_SS) pjmp2 = JMP8(0); // If negative and not Zero, we can skip the Zero Flag checking + x86SetJ8(pjmp); + + //-------------------------Check for Zero flags------------------------------ + + AND16ItoR(x86temp, _X_Y_Z_W ); // Grab "Is Zero" bits from the previous calculation + pjmp = JZ8(0); // Skip if none are + OR16ItoR(x86statflag, 0x41); // ZS, Z flags + OR32RtoR(x86macflag, x86temp); + x86SetJ8(pjmp); + + _freeX86reg(x86temp); + } + else { // Only Checks for Sign and Zero Flags + + vuFloat2(reg, t1reg, flipMask[_X_Y_Z_W]); // Clamp overflowed vectors that were modified (remember reg's vectors have been flipped, so have to use a flipmask) + + //-------------------------Check for Signed flags------------------------------ + + // The following code makes sure the Signed Bit isn't set with Negative Zero + SSE_XORPS_XMM_to_XMM(t1reg, t1reg); // Clear t1reg + SSE_CMPEQPS_XMM_to_XMM(t1reg, reg); // Set all F's if each vector is zero + SSE_MOVMSKPS_XMM_to_R32(EAX, t1reg); // Used for Zero Flag Calculation + SSE_ANDNPS_XMM_to_XMM(t1reg, reg); + + SSE_MOVMSKPS_XMM_to_R32(x86macflag, t1reg); // Move the sign bits of the t1reg + + AND16ItoR(x86macflag, _X_Y_Z_W ); // Grab "Is Signed" bits from the previous calculation + pjmp = JZ8(0); // Skip if none are + OR16ItoR(x86statflag, 0x82); // SS, S flags + SHL16ItoR(x86macflag, 4); + if (_XYZW_SS) pjmp2 = JMP8(0); // If negative and not Zero, we can skip the Zero Flag checking + x86SetJ8(pjmp); + + //-------------------------Check for Zero flags------------------------------ + + AND16ItoR(EAX, _X_Y_Z_W ); // Grab "Is Zero" bits from the previous calculation + pjmp = JZ8(0); // Skip if none are + OR16ItoR(x86statflag, 0x41); // ZS, Z flags + OR32RtoR(x86macflag, EAX); + x86SetJ8(pjmp); + } + //-------------------------Finally: Send the Flags to the Mac Flag Address------------------------------ + + if (_XYZW_SS) x86SetJ8(pjmp2); // If we skipped the Zero Flag Checking, return here + + if (t1regBoolean == 2) SSE_SHUFPS_XMM_to_XMM(reg, reg, 0x1B); // Flip back reg to wzyx (have to do this because reg != EEREC_TEMP) + else if (t1regBoolean == 1) SSE_MOVAPS_M128_to_XMM( t1reg, (uptr)TEMPXMMData ); // Restore data from temo address + else _freeXMMreg(t1reg); // Free temp reg + + MOV16RtoM(macaddr, x86macflag); + MOV16RtoM(stataddr, x86statflag); + + _freeX86reg(x86macflag); + _freeX86reg(x86statflag); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// Custom VU ADD/SUB routines by Nneeve +// +// Note: See FPU_ADD_SUB() for more info on what this is doing. +//------------------------------------------------------------------ +static PCSX2_ALIGNED16(u32 VU_addsuband[2][4]); +static PCSX2_ALIGNED16(u32 VU_addsub_reg[2][4]); +static u32 ecx_temp_loc; + +void VU_ADD_SUB(u32 regd, u32 regt, int is_sub, int info) +{ + u8 *localptr[4][8]; + int temp1 = _allocX86reg(ECX, X86TYPE_TEMP, 0, 0); //receives regd + int temp2 = ALLOCTEMPX86(0); + + SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsub_reg[0][0], regd); + SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsub_reg[1][0], regt); + + SSE2_PCMPEQB_XMM_to_XMM(regd, regd); + SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsuband[0][0], regd); + SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsuband[1][0], regd); + SSE_MOVAPS_M128_to_XMM(regd, (uptr)&VU_addsub_reg[0][0]); + + SSE2_PSLLD_I8_to_XMM(regd, 1); + SSE2_PSLLD_I8_to_XMM(regt, 1); + + SSE2_PSRLD_I8_to_XMM(regd, 24); + SSE2_PSRLD_I8_to_XMM(regt, 24); + + SSE2_PSUBD_XMM_to_XMM(regd, regt); + +#define PERFORM(i) \ + \ + SSE_PEXTRW_XMM_to_R32(temp1, regd, i*2); \ + MOVSX32R16toR(temp1, temp1); \ + CMP32ItoR(temp1, 25);\ + localptr[i][0] = JGE8(0);\ + CMP32ItoR(temp1, 0);\ + localptr[i][1] = JG8(0);\ + localptr[i][2] = JE8(0);\ + CMP32ItoR(temp1, -25);\ + localptr[i][3] = JLE8(0);\ + \ + NEG32R(temp1); \ + DEC32R(temp1);\ + MOV32ItoR(temp2, 0xffffffff); \ + SHL32CLtoR(temp2); \ + MOV32RtoM((uptr)&VU_addsuband[0][i], temp2);\ + localptr[i][4] = JMP8(0);\ + \ + x86SetJ8(localptr[i][0]);\ + MOV32ItoM((uptr)&VU_addsuband[1][i], 0x80000000);\ + localptr[i][5] = JMP8(0);\ + \ + x86SetJ8(localptr[i][1]);\ + DEC32R(temp1);\ + MOV32ItoR(temp2, 0xffffffff);\ + SHL32CLtoR(temp2); \ + MOV32RtoM((uptr)&VU_addsuband[1][i], temp2);\ + localptr[i][6] = JMP8(0);\ + \ + x86SetJ8(localptr[i][3]);\ + MOV32ItoM((uptr)&VU_addsuband[0][i], 0x80000000);\ + localptr[i][7] = JMP8(0);\ + \ + x86SetJ8(localptr[i][2]);\ + \ + x86SetJ8(localptr[i][4]);\ + x86SetJ8(localptr[i][5]);\ + x86SetJ8(localptr[i][6]);\ + x86SetJ8(localptr[i][7]); + + PERFORM(0); + PERFORM(1); + PERFORM(2); + PERFORM(3); +#undef PERFORM + + SSE_MOVAPS_M128_to_XMM(regd, (uptr)&VU_addsub_reg[0][0]); + SSE_MOVAPS_M128_to_XMM(regt, (uptr)&VU_addsub_reg[1][0]); + + SSE_ANDPS_M128_to_XMM(regd, (uptr)&VU_addsuband[0][0]); + SSE_ANDPS_M128_to_XMM(regt, (uptr)&VU_addsuband[1][0]); + + if (is_sub) SSE_SUBPS_XMM_to_XMM(regd, regt); + else SSE_ADDPS_XMM_to_XMM(regd, regt); + + SSE_MOVAPS_M128_to_XMM(regt, (uptr)&VU_addsub_reg[1][0]); + + _freeX86reg(temp1); + _freeX86reg(temp2); +} + +void VU_ADD_SUB_SSE4(u32 regd, u32 regt, int is_sub, int info) +{ + u8 *localptr[4][8]; + int temp1 = _allocX86reg(ECX, X86TYPE_TEMP, 0, 0); //receives regd + int temp2 = ALLOCTEMPX86(0); + + SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsub_reg[0][0], regd); + SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsub_reg[1][0], regt); + + SSE2_PSLLD_I8_to_XMM(regd, 1); + SSE2_PSLLD_I8_to_XMM(regt, 1); + + SSE2_PSRLD_I8_to_XMM(regd, 24); + SSE2_PSRLD_I8_to_XMM(regt, 24); + + SSE2_PSUBD_XMM_to_XMM(regd, regt); + +#define PERFORM_SSE4(i) \ + \ + SSE_PEXTRW_XMM_to_R32(temp1, regd, i*2); \ + MOVSX32R16toR(temp1, temp1); \ + CMP32ItoR(temp1, 25);\ + localptr[i][0] = JGE8(0);\ + CMP32ItoR(temp1, 0);\ + localptr[i][1] = JG8(0);\ + localptr[i][2] = JE8(0);\ + CMP32ItoR(temp1, -25);\ + localptr[i][3] = JLE8(0);\ + \ + NEG32R(temp1); \ + DEC32R(temp1);\ + MOV32ItoR(temp2, 0xffffffff); \ + SHL32CLtoR(temp2); \ + SSE4_PINSRD_R32_to_XMM(regd, temp2, i); \ + localptr[i][4] = JMP8(0);\ + \ + x86SetJ8(localptr[i][0]);\ + MOV32ItoR(temp2, 0xffffffff); \ + SSE4_PINSRD_R32_to_XMM(regd, temp2, i); \ + SHL32ItoR(temp2, 31); \ + SSE4_PINSRD_R32_to_XMM(regt, temp2, i); \ + localptr[i][5] = JMP8(0);\ + \ + x86SetJ8(localptr[i][1]);\ + DEC32R(temp1);\ + MOV32ItoR(temp2, 0xffffffff);\ + SSE4_PINSRD_R32_to_XMM(regd, temp2, i); \ + SHL32CLtoR(temp2); \ + SSE4_PINSRD_R32_to_XMM(regt, temp2, i); \ + localptr[i][6] = JMP8(0);\ + \ + x86SetJ8(localptr[i][3]);\ + MOV32ItoR(temp2, 0x80000000); \ + SSE4_PINSRD_R32_to_XMM(regd, temp2, i); \ + localptr[i][7] = JMP8(0);\ + \ + x86SetJ8(localptr[i][2]);\ + \ + x86SetJ8(localptr[i][4]);\ + x86SetJ8(localptr[i][5]);\ + x86SetJ8(localptr[i][6]);\ + x86SetJ8(localptr[i][7]); + + SSE2_PCMPEQB_XMM_to_XMM(regt, regt); + PERFORM_SSE4(0); + PERFORM_SSE4(1); + PERFORM_SSE4(2); + PERFORM_SSE4(3); +#undef PERFORM_SSE4 + + SSE_ANDPS_M128_to_XMM(regd, (uptr)&VU_addsub_reg[0][0]); //regd contains mask + SSE_ANDPS_M128_to_XMM(regt, (uptr)&VU_addsub_reg[1][0]); //regt contains mask + + if (is_sub) SSE_SUBPS_XMM_to_XMM(regd, regt); + else SSE_ADDPS_XMM_to_XMM(regd, regt); + + SSE_MOVAPS_M128_to_XMM(regt, (uptr)&VU_addsub_reg[1][0]); + + _freeX86reg(temp1); + _freeX86reg(temp2); +} + +void VU_ADD_SUB_SS(u32 regd, u32 regt, int is_sub, int is_mem, int info) +{ + u8 *localptr[8]; + u32 addrt = regt; //for case is_mem + int temp1 = _allocX86reg(ECX, X86TYPE_TEMP, 0, 0); //receives regd //_allocX86reg(ECX, X86TYPE_TEMP, 0, ((info&PROCESS_VU_SUPER)?0:MODE_NOFRAME)|mode); + int temp2 = ALLOCTEMPX86(0); + + SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsub_reg[0][0], regd); + if (!is_mem) SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsub_reg[1][0], regt); + + SSE2_MOVD_XMM_to_R(temp1, regd); + SHR32ItoR(temp1, 23); + + if (is_mem) { + MOV32MtoR(temp2, addrt); + MOV32RtoM((uptr)&VU_addsub_reg[1][0], temp2); + SHR32ItoR(temp2, 23); + } + else { + SSE2_MOVD_XMM_to_R(temp2, regt); + SHR32ItoR(temp2, 23); + } + + AND32ItoR(temp1, 0xff); + AND32ItoR(temp2, 0xff); + + SUB32RtoR(temp1, temp2); //temp1 = exponent difference + + CMP32ItoR(temp1, 25); + localptr[0] = JGE8(0); + CMP32ItoR(temp1, 0); + localptr[1] = JG8(0); + localptr[2] = JE8(0); + CMP32ItoR(temp1, -25); + localptr[3] = JLE8(0); + + NEG32R(temp1); + DEC32R(temp1); + MOV32ItoR(temp2, 0xffffffff); + SHL32CLtoR(temp2); + SSE2_PCMPEQB_XMM_to_XMM(regd, regd); + if (is_mem) { + SSE_PINSRW_R32_to_XMM(regd, temp2, 0); + SHR32ItoR(temp2, 16); + SSE_PINSRW_R32_to_XMM(regd, temp2, 1); + } + else { + SSE2_MOVD_R_to_XMM(regt, temp2); + SSE_MOVSS_XMM_to_XMM(regd, regt); + SSE2_PCMPEQB_XMM_to_XMM(regt, regt); + } + localptr[4] = JMP8(0); + + x86SetJ8(localptr[0]); + MOV32ItoR(temp2, 0x80000000); + if (is_mem) + AND32RtoM((uptr)&VU_addsub_reg[1][0], temp2); + else { + SSE2_PCMPEQB_XMM_to_XMM(regt, regt); + SSE2_MOVD_R_to_XMM(regd, temp2); + SSE_MOVSS_XMM_to_XMM(regt, regd); + } + SSE2_PCMPEQB_XMM_to_XMM(regd, regd); + localptr[5] = JMP8(0); + + x86SetJ8(localptr[1]); + DEC32R(temp1); + MOV32ItoR(temp2, 0xffffffff); + SHL32CLtoR(temp2); + if (is_mem) + AND32RtoM((uptr)&VU_addsub_reg[1][0], temp2); + else { + SSE2_PCMPEQB_XMM_to_XMM(regt, regt); + SSE2_MOVD_R_to_XMM(regd, temp2); + SSE_MOVSS_XMM_to_XMM(regt, regd); + } + SSE2_PCMPEQB_XMM_to_XMM(regd, regd); + localptr[6] = JMP8(0); + + x86SetJ8(localptr[3]); + MOV32ItoR(temp2, 0x80000000); + SSE2_PCMPEQB_XMM_to_XMM(regd, regd); + if (is_mem) { + SSE_PINSRW_R32_to_XMM(regd, temp2, 0); + SHR32ItoR(temp2, 16); + SSE_PINSRW_R32_to_XMM(regd, temp2, 1); + } + else { + SSE2_MOVD_R_to_XMM(regt, temp2); + SSE_MOVSS_XMM_to_XMM(regd, regt); + SSE2_PCMPEQB_XMM_to_XMM(regt, regt); + } + localptr[7] = JMP8(0); + + x86SetJ8(localptr[2]); + x86SetJ8(localptr[4]); + x86SetJ8(localptr[5]); + x86SetJ8(localptr[6]); + x86SetJ8(localptr[7]); + + if (is_mem) + { + SSE_ANDPS_M128_to_XMM(regd, (uptr)&VU_addsub_reg[0][0]); //regd contains mask + + if (is_sub) SSE_SUBSS_M32_to_XMM(regd, (uptr)&VU_addsub_reg[1][0]); + else SSE_ADDSS_M32_to_XMM(regd, (uptr)&VU_addsub_reg[1][0]); + } + else + { + SSE_ANDPS_M128_to_XMM(regd, (uptr)&VU_addsub_reg[0][0]); //regd contains mask + SSE_ANDPS_M128_to_XMM(regt, (uptr)&VU_addsub_reg[1][0]); //regt contains mask + + if (is_sub) SSE_SUBSS_XMM_to_XMM(regd, regt); + else SSE_ADDSS_XMM_to_XMM(regd, regt); + + SSE_MOVAPS_M128_to_XMM(regt, (uptr)&VU_addsub_reg[1][0]); + } + + _freeX86reg(temp1); + _freeX86reg(temp2); +} + +void VU_ADD_SUB_SS_SSE4(u32 regd, u32 regt, int is_sub, int is_mem, int info) +{ + u8 *localptr[8]; + u32 addrt = regt; //for case is_mem + int temp1 = _allocX86reg(ECX, X86TYPE_TEMP, 0, 0); //receives regd //_allocX86reg(ECX, X86TYPE_TEMP, 0, ((info&PROCESS_VU_SUPER)?0:MODE_NOFRAME)|mode); + int temp2 = ALLOCTEMPX86(0); + + SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsub_reg[0][0], regd); + if (!is_mem) SSE_MOVAPS_XMM_to_M128((uptr)&VU_addsub_reg[1][0], regt); + + SSE2_MOVD_XMM_to_R(temp1, regd); + SHR32ItoR(temp1, 23); + + if (is_mem) { + MOV32MtoR(temp2, addrt); + MOV32RtoM((uptr)&VU_addsub_reg[1][0], temp2); + SHR32ItoR(temp2, 23); + } + else { + SSE2_MOVD_XMM_to_R(temp2, regt); + SHR32ItoR(temp2, 23); + } + + AND32ItoR(temp1, 0xff); + AND32ItoR(temp2, 0xff); + + SUB32RtoR(temp1, temp2); //temp1 = exponent difference + + CMP32ItoR(temp1, 25); + localptr[0] = JGE8(0); + CMP32ItoR(temp1, 0); + localptr[1] = JG8(0); + localptr[2] = JE8(0); + CMP32ItoR(temp1, -25); + localptr[3] = JLE8(0); + + NEG32R(temp1); + DEC32R(temp1); + MOV32ItoR(temp2, 0xffffffff); + SHL32CLtoR(temp2); + SSE2_PCMPEQB_XMM_to_XMM(regd, regd); + SSE4_PINSRD_R32_to_XMM(regd, temp2, 0); + if (!is_mem) + SSE2_PCMPEQB_XMM_to_XMM(regt, regt); + localptr[4] = JMP8(0); + + x86SetJ8(localptr[0]); + MOV32ItoR(temp2, 0x80000000); + if (is_mem) + AND32RtoM((uptr)&VU_addsub_reg[1][0], temp2); + else { + SSE2_PCMPEQB_XMM_to_XMM(regt, regt); + SSE4_PINSRD_R32_to_XMM(regt, temp2, 0); + } + SSE2_PCMPEQB_XMM_to_XMM(regd, regd); + localptr[5] = JMP8(0); + + x86SetJ8(localptr[1]); + DEC32R(temp1); + MOV32ItoR(temp2, 0xffffffff); + SHL32CLtoR(temp2); + if (is_mem) + AND32RtoM((uptr)&VU_addsub_reg[1][0], temp2); + else { + SSE2_PCMPEQB_XMM_to_XMM(regt, regt); + SSE4_PINSRD_R32_to_XMM(regt, temp2, 0); + } + SSE2_PCMPEQB_XMM_to_XMM(regd, regd); + localptr[6] = JMP8(0); + + x86SetJ8(localptr[3]); + MOV32ItoR(temp2, 0x80000000); + SSE2_PCMPEQB_XMM_to_XMM(regd, regd); + SSE4_PINSRD_R32_to_XMM(regd, temp2, 0); + if (!is_mem) + SSE2_PCMPEQB_XMM_to_XMM(regt, regt); + localptr[7] = JMP8(0); + + x86SetJ8(localptr[2]); + x86SetJ8(localptr[4]); + x86SetJ8(localptr[5]); + x86SetJ8(localptr[6]); + x86SetJ8(localptr[7]); + + if (is_mem) + { + SSE_ANDPS_M128_to_XMM(regd, (uptr)&VU_addsub_reg[0][0]); //regd contains mask + + if (is_sub) SSE_SUBSS_M32_to_XMM(regd, (uptr)&VU_addsub_reg[1][0]); + else SSE_ADDSS_M32_to_XMM(regd, (uptr)&VU_addsub_reg[1][0]); + } + else + { + SSE_ANDPS_M128_to_XMM(regd, (uptr)&VU_addsub_reg[0][0]); //regd contains mask + SSE_ANDPS_M128_to_XMM(regt, (uptr)&VU_addsub_reg[1][0]); //regt contains mask + + if (is_sub) SSE_SUBSS_XMM_to_XMM(regd, regt); + else SSE_ADDSS_XMM_to_XMM(regd, regt); + + SSE_MOVAPS_M128_to_XMM(regt, (uptr)&VU_addsub_reg[1][0]); + } + + _freeX86reg(temp1); + _freeX86reg(temp2); +} + +void SSE_ADDPS_XMM_to_XMM_custom(int info, int regd, int regt) { + if (CHECK_VUADDSUBHACK) { + if ( cpucaps.hasStreamingSIMD4Extensions ) + VU_ADD_SUB_SSE4(regd, regt, 0, info); + else + VU_ADD_SUB(regd, regt, 0, info); + } + else SSE_ADDPS_XMM_to_XMM(regd, regt); +} +void SSE_SUBPS_XMM_to_XMM_custom(int info, int regd, int regt) { + if (CHECK_VUADDSUBHACK) { + if ( cpucaps.hasStreamingSIMD4Extensions ) + VU_ADD_SUB_SSE4(regd, regt, 1, info); + else + VU_ADD_SUB(regd, regt, 1, info); + } + else SSE_SUBPS_XMM_to_XMM(regd, regt); +} +void SSE_ADDSS_XMM_to_XMM_custom(int info, int regd, int regt) { + if (CHECK_VUADDSUBHACK) { + if ( cpucaps.hasStreamingSIMD4Extensions ) + VU_ADD_SUB_SS_SSE4(regd, regt, 0, 0, info); + else + VU_ADD_SUB_SS(regd, regt, 0, 0, info); + } + else SSE_ADDSS_XMM_to_XMM(regd, regt); +} +void SSE_SUBSS_XMM_to_XMM_custom(int info, int regd, int regt) { + if (CHECK_VUADDSUBHACK) { + if ( cpucaps.hasStreamingSIMD4Extensions ) + VU_ADD_SUB_SS_SSE4(regd, regt, 1, 0, info); + else + VU_ADD_SUB_SS(regd, regt, 1, 0, info); + } + else SSE_SUBSS_XMM_to_XMM(regd, regt); +} +void SSE_ADDSS_M32_to_XMM_custom(int info, int regd, int regt) { + if (CHECK_VUADDSUBHACK) { + if ( cpucaps.hasStreamingSIMD4Extensions ) + VU_ADD_SUB_SS_SSE4(regd, regt, 0, 1, info); + else + VU_ADD_SUB_SS(regd, regt, 0, 1, info); + } + else SSE_ADDSS_M32_to_XMM(regd, regt); +} +void SSE_SUBSS_M32_to_XMM_custom(int info, int regd, int regt) { + if (CHECK_VUADDSUBHACK) { + if ( cpucaps.hasStreamingSIMD4Extensions ) + VU_ADD_SUB_SS_SSE4(regd, regt, 1, 1, info); + else + VU_ADD_SUB_SS(regd, regt, 1, 1, info); + } + else SSE_SUBSS_M32_to_XMM(regd, regt); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// *VU Upper Instructions!* +// +// Note: * = Checked for errors by cottonvibes +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ABS* +//------------------------------------------------------------------ +void recVUMI_ABS(VURegs *VU, int info) +{ + //SysPrintf("recVUMI_ABS()\n"); + if ( (_Ft_ == 0) || (_X_Y_Z_W == 0) ) return; + + if ((_X_Y_Z_W == 0x8) || (_X_Y_Z_W == 0xf)) { + VU_MERGE_REGS(EEREC_T, EEREC_S); + SSE_ANDPS_M128_to_XMM(EEREC_T, (uptr)&const_abs_table[ _X_Y_Z_W ][ 0 ] ); + } + else { // Use a temp reg because VU_MERGE_REGS() modifies source reg! + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_abs_table[ _X_Y_Z_W ][ 0 ] ); + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + } +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ADD*, ADD_iq*, ADD_xyzw* +//------------------------------------------------------------------ +PCSX2_ALIGNED16(float s_two[4]) = {0,0,0,2}; +void recVUMI_ADD(VURegs *VU, int info) +{ + //SysPrintf("recVUMI_ADD()\n"); + if ( _X_Y_Z_W == 0 ) goto flagUpdate; // Don't do anything and just clear flags + if ( !_Fd_ ) info = (info & ~PROCESS_EE_SET_D(0xf)) | PROCESS_EE_SET_D(EEREC_TEMP); + + if ( _Fs_ == 0 && _Ft_ == 0 ) { // if adding VF00 with VF00, then the result is always 0,0,0,2 + if ( _X_Y_Z_W != 0xf ) { + SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, (uptr)s_two); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else SSE_MOVAPS_M128_to_XMM(EEREC_D, (uptr)s_two); + } + else { + if (CHECK_VU_EXTRA_OVERFLOW) { + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, _X_Y_Z_W ); + } + if( _X_Y_Z_W == 8 ) { // If only adding x, then we can do a Scalar Add + if (EEREC_D == EEREC_S) SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_T); + else if (EEREC_D == EEREC_T) SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + else if (_X_Y_Z_W != 0xf) { // If xyzw != 1111, then we have to use a temp reg + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { // All xyzw being modified (xyzw == 1111) + if (EEREC_D == EEREC_S) SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_T); + else if (EEREC_D == EEREC_T) SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + } +flagUpdate: + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_ADD_iq(VURegs *VU, uptr addr, int info) +{ + //SysPrintf("recVUMI_ADD_iq()\n"); + if ( _X_Y_Z_W == 0 ) goto flagUpdate; + if ( !_Fd_ ) info = (info & ~PROCESS_EE_SET_D(0xf)) | PROCESS_EE_SET_D(EEREC_TEMP); + if (CHECK_VU_EXTRA_OVERFLOW) { + vuFloat3(addr); + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + } + + if ( _XYZW_SS ) { + if ( EEREC_D == EEREC_TEMP ) { + _vuFlipRegSS(VU, EEREC_S); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_ADDSS_M32_to_XMM(EEREC_D, addr); + _vuFlipRegSS(VU, EEREC_S); + _vuFlipRegSS(VU, EEREC_D); // have to flip over EEREC_D for computing flags! + } + else if ( EEREC_D == EEREC_S ) { + _vuFlipRegSS(VU, EEREC_D); + SSE_ADDSS_M32_to_XMM(EEREC_D, addr); + _vuFlipRegSS(VU, EEREC_D); + } + else { + if ( _X ) { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_ADDSS_M32_to_XMM_custom(info, EEREC_D, addr); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + SSE_ADDPS_XMM_to_XMM_custom(info, EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + } + } + else { + if ( (_X_Y_Z_W != 0xf) || (EEREC_D == EEREC_S) || (EEREC_D == EEREC_TEMP) ) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + } + + if (_X_Y_Z_W != 0xf) { + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if ( EEREC_D == EEREC_TEMP ) SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); + else if ( EEREC_D == EEREC_S ) SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + else { + SSE_MOVSS_M32_to_XMM(EEREC_D, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_D, EEREC_D, 0x00); + SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + } + } +flagUpdate: + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_ADD_xyzw(VURegs *VU, int xyzw, int info) +{ + //SysPrintf("recVUMI_ADD_xyzw()\n"); + if ( _X_Y_Z_W == 0 ) goto flagUpdate; + if ( !_Fd_ ) info = (info & ~PROCESS_EE_SET_D(0xf)) | PROCESS_EE_SET_D(EEREC_TEMP); + if (CHECK_VU_EXTRA_OVERFLOW) { + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, ( 1 << (3 - xyzw) ) ); + } + + if ( _Ft_ == 0 && xyzw < 3 ) { // just move since adding zero + if ( _X_Y_Z_W == 0x8 ) { VU_MERGE_REGS(EEREC_D, EEREC_S); } + else if ( _X_Y_Z_W != 0xf ) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + else if ( _X_Y_Z_W == 8 && (EEREC_D != EEREC_TEMP) ) { + if ( xyzw == 0 ) { + if ( EEREC_D == EEREC_T ) SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + else { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_ADDSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + } + else if( _Fs_ == 0 && !_W ) { // just move + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if ( _X_Y_Z_W != 0xf ) { + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if( EEREC_D == EEREC_TEMP ) { _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); } + else if( EEREC_D == EEREC_S ) { _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); } + else { _unpackVF_xyzw(EEREC_D, EEREC_T, xyzw); SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); } + } + } +flagUpdate: + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_ADDi(VURegs *VU, int info) { recVUMI_ADD_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_ADDq(VURegs *VU, int info) { recVUMI_ADD_iq(VU, VU_REGQ_ADDR, info); } +void recVUMI_ADDx(VURegs *VU, int info) { recVUMI_ADD_xyzw(VU, 0, info); } +void recVUMI_ADDy(VURegs *VU, int info) { recVUMI_ADD_xyzw(VU, 1, info); } +void recVUMI_ADDz(VURegs *VU, int info) { recVUMI_ADD_xyzw(VU, 2, info); } +void recVUMI_ADDw(VURegs *VU, int info) { recVUMI_ADD_xyzw(VU, 3, info); } +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ADDA*, ADDA_iq*, ADDA_xyzw* +//------------------------------------------------------------------ +void recVUMI_ADDA(VURegs *VU, int info) +{ + //SysPrintf("recVUMI_ADDA()\n"); + if ( _X_Y_Z_W == 0 ) goto flagUpdate; + if (CHECK_VU_EXTRA_OVERFLOW) { + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, _X_Y_Z_W ); + } + + if( _X_Y_Z_W == 8 ) { + if (EEREC_ACC == EEREC_S) SSE_ADDSS_XMM_to_XMM(EEREC_ACC, EEREC_T); // Can this case happen? (cottonvibes) + else if (EEREC_ACC == EEREC_T) SSE_ADDSS_XMM_to_XMM(EEREC_ACC, EEREC_S); // Can this case happen? + else { + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_ADDSS_XMM_to_XMM(EEREC_ACC, EEREC_T); + } + } + else if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + + VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); + } + else { + if( EEREC_ACC == EEREC_S ) SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_T); // Can this case happen? + else if( EEREC_ACC == EEREC_T ) SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_S); // Can this case happen? + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_T); + } + } +flagUpdate: + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_ADDA_iq(VURegs *VU, uptr addr, int info) +{ + //SysPrintf("recVUMI_ADDA_iq()\n"); + if ( _X_Y_Z_W == 0 ) goto flagUpdate; + if (CHECK_VU_EXTRA_OVERFLOW) { + vuFloat3(addr); + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + } + + if( _XYZW_SS ) { + assert( EEREC_ACC != EEREC_TEMP ); + if( EEREC_ACC == EEREC_S ) { + _vuFlipRegSS(VU, EEREC_ACC); + SSE_ADDSS_M32_to_XMM(EEREC_ACC, addr); + _vuFlipRegSS(VU, EEREC_ACC); + } + else { + if( _X ) { + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_ADDSS_M32_to_XMM(EEREC_ACC, addr); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); + } + } + } + else { + if( _X_Y_Z_W != 0xf || EEREC_ACC == EEREC_S ) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + } + + if (_X_Y_Z_W != 0xf) { + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); + } + else { + if( EEREC_ACC == EEREC_S ) SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + else { + SSE_MOVSS_M32_to_XMM(EEREC_ACC, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_ACC, EEREC_ACC, 0x00); + SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_S); + } + } + } +flagUpdate: + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_ADDA_xyzw(VURegs *VU, int xyzw, int info) +{ + //SysPrintf("recVUMI_ADDA_xyzw()\n"); + if ( _X_Y_Z_W == 0 ) goto flagUpdate; + if (CHECK_VU_EXTRA_OVERFLOW) { + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, ( 1 << (3 - xyzw) ) ); + } + + if( _X_Y_Z_W == 8 ) { + assert( EEREC_ACC != EEREC_T ); + if( xyzw == 0 ) { + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_ADDSS_XMM_to_XMM(EEREC_ACC, EEREC_T); + } + else { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); + if( _Fs_ == 0 ) { + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + } + else { + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_ADDSS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + } + } + } + else { + if( _X_Y_Z_W != 0xf || EEREC_ACC == EEREC_S ) + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + + if (_X_Y_Z_W != 0xf) { + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); + } + else { + if( EEREC_ACC == EEREC_S ) SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + else { + _unpackVF_xyzw(EEREC_ACC, EEREC_T, xyzw); + SSE_ADDPS_XMM_to_XMM(EEREC_ACC, EEREC_S); + } + } + } +flagUpdate: + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_ADDAi(VURegs *VU, int info) { recVUMI_ADDA_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_ADDAq(VURegs *VU, int info) { recVUMI_ADDA_iq(VU, VU_REGQ_ADDR, info); } +void recVUMI_ADDAx(VURegs *VU, int info) { recVUMI_ADDA_xyzw(VU, 0, info); } +void recVUMI_ADDAy(VURegs *VU, int info) { recVUMI_ADDA_xyzw(VU, 1, info); } +void recVUMI_ADDAz(VURegs *VU, int info) { recVUMI_ADDA_xyzw(VU, 2, info); } +void recVUMI_ADDAw(VURegs *VU, int info) { recVUMI_ADDA_xyzw(VU, 3, info); } +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// SUB*, SUB_iq*, SUB_xyzw* +//------------------------------------------------------------------ +void recVUMI_SUB(VURegs *VU, int info) +{ + //SysPrintf("recVUMI_SUB()\n"); + if ( _X_Y_Z_W == 0 ) goto flagUpdate; + if ( !_Fd_ ) info = (info & ~PROCESS_EE_SET_D(0xf)) | PROCESS_EE_SET_D(EEREC_TEMP); + + if( EEREC_S == EEREC_T ) { + if (_X_Y_Z_W != 0xf) SSE_ANDPS_M128_to_XMM(EEREC_D, (uptr)&SSEmovMask[15-_X_Y_Z_W][0]); + else SSE_XORPS_XMM_to_XMM(EEREC_D, EEREC_D); + } + else if( _X_Y_Z_W == 8 ) { + if (CHECK_VU_EXTRA_OVERFLOW) { + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, _X_Y_Z_W ); + } + if (EEREC_D == EEREC_S) { + if (_Ft_) SSE_SUBSS_XMM_to_XMM(EEREC_D, EEREC_T); + } + else if (EEREC_D == EEREC_T) { + if (_Ft_) { + SSE_MOVSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SUBSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + else SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + if (_Ft_) SSE_SUBSS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + else { + if (CHECK_VU_EXTRA_OVERFLOW) { + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, _X_Y_Z_W ); + } + if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if( ( _Ft_ > 0 ) || _W ) SSE_SUBPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if (EEREC_D == EEREC_S) SSE_SUBPS_XMM_to_XMM(EEREC_D, EEREC_T); + else if (EEREC_D == EEREC_T) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SUBPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_SUBPS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + } +flagUpdate: + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_SUB_iq(VURegs *VU, uptr addr, int info) +{ + //SysPrintf("recVUMI_SUB_iq()\n"); + if ( _X_Y_Z_W == 0 ) goto flagUpdate; + if (CHECK_VU_EXTRA_OVERFLOW) { + vuFloat3(addr); + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + } + if ( !_Fd_ ) info = (info & ~PROCESS_EE_SET_D(0xf)) | PROCESS_EE_SET_D(EEREC_TEMP); + + if( _XYZW_SS ) { + if( EEREC_D == EEREC_TEMP ) { + _vuFlipRegSS(VU, EEREC_S); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_SUBSS_M32_to_XMM(EEREC_D, addr); + _vuFlipRegSS(VU, EEREC_S); + _vuFlipRegSS(VU, EEREC_D); + } + else if( EEREC_D == EEREC_S ) { + _vuFlipRegSS(VU, EEREC_D); + SSE_SUBSS_M32_to_XMM(EEREC_D, addr); + _vuFlipRegSS(VU, EEREC_D); + } + else { + if( _X ) { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_SUBSS_M32_to_XMM(EEREC_D, addr); + } + else { + _vuMoveSS(VU, EEREC_TEMP, EEREC_S); + _vuFlipRegSS(VU, EEREC_D); + SSE_SUBSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + _vuFlipRegSS(VU, EEREC_D); + } + } + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + + if (_X_Y_Z_W != 0xf) { + int t1reg = _vuGetTempXMMreg(info); + + if( t1reg >= 0 ) { + SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_S); + SSE_SUBPS_XMM_to_XMM(t1reg, EEREC_TEMP); + + VU_MERGE_REGS(EEREC_D, t1reg); + _freeXMMreg(t1reg); + } + else { + // negate + SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + } + else { + if( EEREC_D == EEREC_TEMP ) { + SSE_XORPS_M128_to_XMM(EEREC_D, (uptr)&const_clip[4]); + SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_SUBPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + } + } +flagUpdate: + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_SUB_xyzw(VURegs *VU, int xyzw, int info) +{ + //SysPrintf("recVUMI_SUB_xyzw()\n"); + if ( _X_Y_Z_W == 0 ) goto flagUpdate; + if ( !_Fd_ ) info = (info & ~PROCESS_EE_SET_D(0xf)) | PROCESS_EE_SET_D(EEREC_TEMP); + if (CHECK_VU_EXTRA_OVERFLOW) { + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, ( 1 << (3 - xyzw) ) ); + } + + if ( _X_Y_Z_W == 8 ) { + if ( (xyzw == 0) && (_Ft_ == _Fs_) ) { + SSE_ANDPS_M128_to_XMM(EEREC_D, (uptr)&SSEmovMask[7][0]); + } + else if ( EEREC_D == EEREC_TEMP ) { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + if ( (_Ft_ > 0) || (xyzw == 3) ) { + _vuFlipRegSS_xyzw(EEREC_T, xyzw); + SSE_SUBSS_XMM_to_XMM(EEREC_D, EEREC_T); + _vuFlipRegSS_xyzw(EEREC_T, xyzw); + } + } + else { + if ( (_Ft_ > 0) || (xyzw == 3) ) { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_SUBSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + else SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + } + } + else { + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + + if (_X_Y_Z_W != 0xf) { + int t1reg = _vuGetTempXMMreg(info); + + if( t1reg >= 0 ) { + SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_S); + SSE_SUBPS_XMM_to_XMM(t1reg, EEREC_TEMP); + + VU_MERGE_REGS(EEREC_D, t1reg); + _freeXMMreg(t1reg); + } + else { + // negate + SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + } + else { + if( EEREC_D == EEREC_TEMP ) { + SSE_XORPS_M128_to_XMM(EEREC_D, (uptr)&const_clip[4]); + SSE_ADDPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_SUBPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + } + } +flagUpdate: + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_SUBi(VURegs *VU, int info) { recVUMI_SUB_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_SUBq(VURegs *VU, int info) { recVUMI_SUB_iq(VU, VU_REGQ_ADDR, info); } +void recVUMI_SUBx(VURegs *VU, int info) { recVUMI_SUB_xyzw(VU, 0, info); } +void recVUMI_SUBy(VURegs *VU, int info) { recVUMI_SUB_xyzw(VU, 1, info); } +void recVUMI_SUBz(VURegs *VU, int info) { recVUMI_SUB_xyzw(VU, 2, info); } +void recVUMI_SUBw(VURegs *VU, int info) { recVUMI_SUB_xyzw(VU, 3, info); } +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// SUBA*, SUBA_iq, SUBA_xyzw +//------------------------------------------------------------------ +void recVUMI_SUBA(VURegs *VU, int info) +{ + //SysPrintf("recVUMI_SUBA()\n"); + if ( _X_Y_Z_W == 0 ) goto flagUpdate; + if (CHECK_VU_EXTRA_OVERFLOW) { + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, _X_Y_Z_W ); + } + + if( EEREC_S == EEREC_T ) { + if (_X_Y_Z_W != 0xf) SSE_ANDPS_M128_to_XMM(EEREC_ACC, (uptr)&SSEmovMask[15-_X_Y_Z_W][0]); + else SSE_XORPS_XMM_to_XMM(EEREC_ACC, EEREC_ACC); + } + else if( _X_Y_Z_W == 8 ) { + if (EEREC_ACC == EEREC_S) SSE_SUBSS_XMM_to_XMM(EEREC_ACC, EEREC_T); + else if (EEREC_ACC == EEREC_T) { + SSE_MOVSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SUBSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + } + else { + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_SUBSS_XMM_to_XMM(EEREC_ACC, EEREC_T); + } + } + else if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SUBPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + + VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); + } + else { + if( EEREC_ACC == EEREC_S ) SSE_SUBPS_XMM_to_XMM(EEREC_ACC, EEREC_T); + else if( EEREC_ACC == EEREC_T ) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SUBPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + SSE_MOVAPS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + } + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_SUBPS_XMM_to_XMM(EEREC_ACC, EEREC_T); + } + } +flagUpdate: + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_SUBA_iq(VURegs *VU, uptr addr, int info) +{ + //SysPrintf ("recVUMI_SUBA_iq \n"); + if (CHECK_VU_EXTRA_OVERFLOW) { + vuFloat3(addr); + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + } + + if( _XYZW_SS ) { + if( EEREC_ACC == EEREC_S ) { + _vuFlipRegSS(VU, EEREC_ACC); + SSE_SUBSS_M32_to_XMM(EEREC_ACC, addr); + _vuFlipRegSS(VU, EEREC_ACC); + } + else { + if( _X ) { + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_SUBSS_M32_to_XMM(EEREC_ACC, addr); + } + else { + _vuMoveSS(VU, EEREC_TEMP, EEREC_S); + _vuFlipRegSS(VU, EEREC_ACC); + SSE_SUBSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + _vuFlipRegSS(VU, EEREC_ACC); + } + } + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + + if (_X_Y_Z_W != 0xf) { + int t1reg = _vuGetTempXMMreg(info); + + if( t1reg >= 0 ) { + SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_S); + SSE_SUBPS_XMM_to_XMM(t1reg, EEREC_TEMP); + + VU_MERGE_REGS(EEREC_ACC, t1reg); + _freeXMMreg(t1reg); + } + else { + // negate + SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); + } + } + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_SUBPS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + } + } + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_SUBA_xyzw(VURegs *VU, int xyzw, int info) +{ + //SysPrintf ("recVUMI_SUBA_xyzw \n"); + if (CHECK_VU_EXTRA_OVERFLOW) { + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, ( 1 << (3 - xyzw) ) ); + } + + if( _X_Y_Z_W == 8 ) { + if( xyzw == 0 ) { + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_SUBSS_XMM_to_XMM(EEREC_ACC, EEREC_T); + } + else { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_MOVSS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_SUBSS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + } + } + else { + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + + if (_X_Y_Z_W != 0xf) { + int t1reg = _vuGetTempXMMreg(info); + + if( t1reg >= 0 ) { + SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_S); + SSE_SUBPS_XMM_to_XMM(t1reg, EEREC_TEMP); + + VU_MERGE_REGS(EEREC_ACC, t1reg); + _freeXMMreg(t1reg); + } + else { + // negate + SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_ACC, EEREC_TEMP); + } + } + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_ACC, EEREC_S); + SSE_SUBPS_XMM_to_XMM(EEREC_ACC, EEREC_TEMP); + } + } + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_SUBAi(VURegs *VU, int info) { recVUMI_SUBA_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_SUBAq(VURegs *VU, int info) { recVUMI_SUBA_iq(VU, VU_REGQ_ADDR, info); } +void recVUMI_SUBAx(VURegs *VU, int info) { recVUMI_SUBA_xyzw(VU, 0, info); } +void recVUMI_SUBAy(VURegs *VU, int info) { recVUMI_SUBA_xyzw(VU, 1, info); } +void recVUMI_SUBAz(VURegs *VU, int info) { recVUMI_SUBA_xyzw(VU, 2, info); } +void recVUMI_SUBAw(VURegs *VU, int info) { recVUMI_SUBA_xyzw(VU, 3, info); } +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// MUL +//------------------------------------------------------------------ +void recVUMI_MUL_toD(VURegs *VU, int regd, int info) +{ + //SysPrintf ("recVUMI_MUL_toD \n"); + if (CHECK_VU_EXTRA_OVERFLOW) { + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, _X_Y_Z_W ); + } + + if (_X_Y_Z_W == 1 && (_Ft_ == 0 || _Fs_==0) ) { // W + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, _Ft_ ? EEREC_T : EEREC_S); + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else if( _Fd_ == _Fs_ && _Fs_ == _Ft_ && _XYZW_SS ) { + _vuFlipRegSS(VU, EEREC_D); + SSE_MULSS_XMM_to_XMM(EEREC_D, EEREC_D); + _vuFlipRegSS(VU, EEREC_D); + } + else if( _X_Y_Z_W == 8 ) { + if (regd == EEREC_S) SSE_MULSS_XMM_to_XMM(regd, EEREC_T); + else if (regd == EEREC_T) SSE_MULSS_XMM_to_XMM(regd, EEREC_S); + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + SSE_MULSS_XMM_to_XMM(regd, EEREC_T); + } + } + else if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else { + if (regd == EEREC_S) SSE_MULPS_XMM_to_XMM(regd, EEREC_T); + else if (regd == EEREC_T) SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + else { + SSE_MOVAPS_XMM_to_XMM(regd, EEREC_S); + SSE_MULPS_XMM_to_XMM(regd, EEREC_T); + } + } +} + +void recVUMI_MUL_iq_toD(VURegs *VU, uptr addr, int regd, int info) +{ + //SysPrintf ("recVUMI_MUL_iq_toD \n"); + if (CHECK_VU_EXTRA_OVERFLOW) { + vuFloat3(addr); + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + } + + if( _XYZW_SS ) { + if( regd == EEREC_TEMP ) { + _vuFlipRegSS(VU, EEREC_S); + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + SSE_MULSS_M32_to_XMM(regd, addr); + _vuFlipRegSS(VU, EEREC_S); + } + else if( regd == EEREC_S ) { + _vuFlipRegSS(VU, regd); + SSE_MULSS_M32_to_XMM(regd, addr); + _vuFlipRegSS(VU, regd); + } + else { + if( _X ) { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + SSE_MULSS_M32_to_XMM(regd, addr); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(regd, EEREC_TEMP); + } + } + } + else { + if( _X_Y_Z_W != 0xf || regd == EEREC_TEMP || regd == EEREC_S ) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + } + + if (_X_Y_Z_W != 0xf) { + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else { + if( regd == EEREC_TEMP ) SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + else if (regd == EEREC_S) SSE_MULPS_XMM_to_XMM(regd, EEREC_TEMP); + else { + SSE_MOVSS_M32_to_XMM(regd, addr); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x00); + SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + } + } + } +} + +void recVUMI_MUL_xyzw_toD(VURegs *VU, int xyzw, int regd, int info) +{ + //SysPrintf ("recVUMI_MUL_xyzw_toD \n"); + if (CHECK_VU_EXTRA_OVERFLOW) { + if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, ( 1 << (3 - xyzw) ) ); + } + if (_Fs_) { // This is needed for alot of games; so always clamp this operand + if (CHECK_VU_SIGN_OVERFLOW) vFloats4_useEAX[_X_Y_Z_W]( EEREC_S, EEREC_TEMP ); // Always clamp EEREC_S, regardless if CHECK_VU_OVERFLOW is set + else vFloats2_MUL_MADD[_X_Y_Z_W]( EEREC_S, EEREC_TEMP ); // Always clamp EEREC_S, regardless if CHECK_VU_OVERFLOW is set + } + if( _Ft_ == 0 ) { + if( xyzw < 3 ) { + if (_X_Y_Z_W != 0xf) { + SSE_XORPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else SSE_XORPS_XMM_to_XMM(regd, regd); + } + else { + assert(xyzw==3); + if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else SSE_MOVAPS_XMM_to_XMM(regd, EEREC_S); + } + } + else if( _X_Y_Z_W == 8 ) { + if( regd == EEREC_TEMP ) { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_MULSS_XMM_to_XMM(regd, EEREC_S); + } + else { + if( xyzw == 0 ) { + if( regd == EEREC_T ) { + SSE_MULSS_XMM_to_XMM(regd, EEREC_S); + } + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + SSE_MULSS_XMM_to_XMM(regd, EEREC_T); + } + } + else { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + SSE_MULSS_XMM_to_XMM(regd, EEREC_TEMP); + } + } + } + else { + if( _X_Y_Z_W != 0xf || regd == EEREC_TEMP || regd == EEREC_S ) + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + + if (_X_Y_Z_W != 0xf) { + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else { + if( regd == EEREC_TEMP ) SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + else if (regd == EEREC_S) SSE_MULPS_XMM_to_XMM(regd, EEREC_TEMP); + else { + _unpackVF_xyzw(regd, EEREC_T, xyzw); + SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + } + } + } +} + +void recVUMI_MUL(VURegs *VU, int info) +{ + //SysPrintf ("recVUMI_MUL \n"); + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MUL_toD(VU, EEREC_D, info); + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_MUL_iq(VURegs *VU, int addr, int info) +{ + //SysPrintf ("recVUMI_MUL_iq \n"); + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MUL_iq_toD(VU, addr, EEREC_D, info); + recUpdateFlags(VU, EEREC_D, info); + // spacefisherman needs overflow checking on MULi.z +} + +void recVUMI_MUL_xyzw(VURegs *VU, int xyzw, int info) +{ + //SysPrintf ("recVUMI_MUL_xyzw \n"); + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MUL_xyzw_toD(VU, xyzw, EEREC_D, info); + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_MULi(VURegs *VU, int info) { recVUMI_MUL_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_MULq(VURegs *VU, int info) { recVUMI_MUL_iq(VU, VU_REGQ_ADDR, info); } +void recVUMI_MULx(VURegs *VU, int info) { recVUMI_MUL_xyzw(VU, 0, info); } +void recVUMI_MULy(VURegs *VU, int info) { recVUMI_MUL_xyzw(VU, 1, info); } +void recVUMI_MULz(VURegs *VU, int info) { recVUMI_MUL_xyzw(VU, 2, info); } +void recVUMI_MULw(VURegs *VU, int info) { recVUMI_MUL_xyzw(VU, 3, info); } +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// MULA +//------------------------------------------------------------------ +void recVUMI_MULA( VURegs *VU, int info ) +{ + //SysPrintf ("recVUMI_MULA \n"); + recVUMI_MUL_toD(VU, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MULA_iq(VURegs *VU, int addr, int info) +{ + //SysPrintf ("recVUMI_MULA_iq \n"); + recVUMI_MUL_iq_toD(VU, addr, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MULA_xyzw(VURegs *VU, int xyzw, int info) +{ + //SysPrintf ("recVUMI_MULA_xyzw \n"); + recVUMI_MUL_xyzw_toD(VU, xyzw, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MULAi(VURegs *VU, int info) { recVUMI_MULA_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_MULAq(VURegs *VU, int info) { recVUMI_MULA_iq(VU, VU_REGQ_ADDR, info); } +void recVUMI_MULAx(VURegs *VU, int info) { recVUMI_MULA_xyzw(VU, 0, info); } +void recVUMI_MULAy(VURegs *VU, int info) { recVUMI_MULA_xyzw(VU, 1, info); } +void recVUMI_MULAz(VURegs *VU, int info) { recVUMI_MULA_xyzw(VU, 2, info); } +void recVUMI_MULAw(VURegs *VU, int info) { recVUMI_MULA_xyzw(VU, 3, info); } +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// MADD +//------------------------------------------------------------------ +void recVUMI_MADD_toD(VURegs *VU, int regd, int info) +{ + //SysPrintf ("recVUMI_MADD_toD \n"); + if (CHECK_VU_EXTRA_OVERFLOW) { + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, _X_Y_Z_W ); + vuFloat5_useEAX( EEREC_ACC, EEREC_TEMP, _X_Y_Z_W ); + } + + if( _X_Y_Z_W == 8 ) { + if( regd == EEREC_ACC ) { + SSE_MOVSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MULSS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, 8); } + SSE_ADDSS_XMM_to_XMM(regd, EEREC_TEMP); + } + else if (regd == EEREC_T) { + SSE_MULSS_XMM_to_XMM(regd, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, 8); } + SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + } + else if (regd == EEREC_S) { + SSE_MULSS_XMM_to_XMM(regd, EEREC_T); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, 8); } + SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + } + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + SSE_MULSS_XMM_to_XMM(regd, EEREC_T); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, 8); } + SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + } + } + else if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); + + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else { + if( regd == EEREC_ACC ) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } + SSE_ADDPS_XMM_to_XMM(regd, EEREC_TEMP); + } + else if (regd == EEREC_T) { + SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } + SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + } + else if (regd == EEREC_S) { + SSE_MULPS_XMM_to_XMM(regd, EEREC_T); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } + SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + } + else { + SSE_MOVAPS_XMM_to_XMM(regd, EEREC_S); + SSE_MULPS_XMM_to_XMM(regd, EEREC_T); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } + SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + } + } +} + +void recVUMI_MADD_iq_toD(VURegs *VU, uptr addr, int regd, int info) +{ + //SysPrintf ("recVUMI_MADD_iq_toD \n"); + if (CHECK_VU_EXTRA_OVERFLOW) { + vuFloat3(addr); + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + vuFloat5_useEAX( EEREC_ACC, EEREC_TEMP, _X_Y_Z_W ); + } + + if( _X_Y_Z_W == 8 ) { + if( regd == EEREC_ACC ) { + if( _Fs_ == 0 ) { + // add addr to w + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_ADDSS_M32_to_XMM(regd, addr); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + } + else { + assert( EEREC_TEMP < XMMREGS ); + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_MULSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, 8); } + SSE_ADDSS_XMM_to_XMM(regd, EEREC_TEMP); + } + } + else if( regd == EEREC_S ) { + SSE_MULSS_M32_to_XMM(regd, addr); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } + SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + } + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_S); + SSE_MULSS_M32_to_XMM(regd, addr); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } + SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + } + } + else { + if( _Fs_ == 0 ) { + // add addr to w + if( _W ) { + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + SSE_ADDSS_M32_to_XMM(regd, addr); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x27); + } + + return; + } + + if( _X_Y_Z_W != 0xf || regd == EEREC_ACC || regd == EEREC_TEMP || regd == EEREC_S ) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + } + + if (_X_Y_Z_W != 0xf) { + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); + + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else { + if( regd == EEREC_ACC ) { + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } + SSE_ADDPS_XMM_to_XMM(regd, EEREC_TEMP); + } + else if( regd == EEREC_S ) { + SSE_MULPS_XMM_to_XMM(regd, EEREC_TEMP); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } + SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + } + else if( regd == EEREC_TEMP ) { + SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } + SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + } + else { + SSE_MOVSS_M32_to_XMM(regd, addr); + SSE_SHUFPS_XMM_to_XMM(regd, regd, 0x00); + SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } + SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + } + } + } +} + +void recVUMI_MADD_xyzw_toD(VURegs *VU, int xyzw, int regd, int info) +{ + //SysPrintf ("recVUMI_MADD_xyzw_toD \n"); + if (CHECK_VU_EXTRA_OVERFLOW) { + if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, ( 1 << (3 - xyzw) ) ); + vuFloat5_useEAX( EEREC_ACC, EEREC_TEMP, _X_Y_Z_W ); + } + if (_Fs_) { // This is needed for alot of games; so always clamp this operand + if (CHECK_VU_SIGN_OVERFLOW) vFloats4_useEAX[_X_Y_Z_W]( EEREC_S, EEREC_TEMP ); // Always clamp EEREC_S, regardless if CHECK_VU_OVERFLOW is set + else vFloats2_MUL_MADD[_X_Y_Z_W]( EEREC_S, EEREC_TEMP ); // Always clamp EEREC_S, regardless if CHECK_VU_OVERFLOW is set + } + if( _Ft_ == 0 ) { + + if( xyzw == 3 ) { + // just add + if( _X_Y_Z_W == 8 ) { + if( regd == EEREC_S ) SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_ACC); + SSE_ADDSS_XMM_to_XMM(regd, EEREC_S); + } + } + else { + if( _X_Y_Z_W != 0xf ) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); + + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else { + if( regd == EEREC_S ) SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + else { + SSE_MOVAPS_XMM_to_XMM(regd, EEREC_ACC); + SSE_ADDPS_XMM_to_XMM(regd, EEREC_S); + } + } + } + } + else { + // just move acc to regd + if( _X_Y_Z_W != 0xf ) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else SSE_MOVAPS_XMM_to_XMM(regd, EEREC_ACC); + } + + return; + } + + if( _X_Y_Z_W == 8 ) { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); + + if( regd == EEREC_ACC ) { + SSE_MULSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, 8); } + SSE_ADDSS_XMM_to_XMM(regd, EEREC_TEMP); + } + else if( regd == EEREC_S ) { + SSE_MULSS_XMM_to_XMM(regd, EEREC_TEMP); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, 8); } + SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + } + else if( regd == EEREC_TEMP ) { + SSE_MULSS_XMM_to_XMM(regd, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, 8); } + SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC); + } + else { + SSE_MOVSS_XMM_to_XMM(regd, EEREC_ACC); + SSE_MULSS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, 8); } + SSE_ADDSS_XMM_to_XMM(regd, EEREC_TEMP); + } + } + else { + if( _X_Y_Z_W != 0xf || regd == EEREC_ACC || regd == EEREC_TEMP || regd == EEREC_S ) { + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + } + + if (_X_Y_Z_W != 0xf) { + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); + + VU_MERGE_REGS(regd, EEREC_TEMP); + } + else { + if( regd == EEREC_ACC ) { + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } + SSE_ADDPS_XMM_to_XMM(regd, EEREC_TEMP); + } + else if( regd == EEREC_S ) { + SSE_MULPS_XMM_to_XMM(regd, EEREC_TEMP); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } + SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + } + else if( regd == EEREC_TEMP ) { + SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } + SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + } + else { + _unpackVF_xyzw(regd, EEREC_T, xyzw); + SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } + SSE_ADDPS_XMM_to_XMM(regd, EEREC_ACC); + } + } + } +} + +void recVUMI_MADD(VURegs *VU, int info) +{ + //SysPrintf ("recVUMI_MADD \n"); + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MADD_toD(VU, EEREC_D, info); + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_MADD_iq(VURegs *VU, int addr, int info) +{ + //SysPrintf ("recVUMI_MADD_iq \n"); + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MADD_iq_toD(VU, addr, EEREC_D, info); + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_MADD_xyzw(VURegs *VU, int xyzw, int info) +{ + //SysPrintf ("recVUMI_MADD_xyzw \n"); + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MADD_xyzw_toD(VU, xyzw, EEREC_D, info); + recUpdateFlags(VU, EEREC_D, info); + // super bust-a-move arrows needs overflow clamping +} + +void recVUMI_MADDi(VURegs *VU, int info) { recVUMI_MADD_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_MADDq(VURegs *VU, int info) { recVUMI_MADD_iq(VU, VU_REGQ_ADDR, info); } +void recVUMI_MADDx(VURegs *VU, int info) { recVUMI_MADD_xyzw(VU, 0, info); } +void recVUMI_MADDy(VURegs *VU, int info) { recVUMI_MADD_xyzw(VU, 1, info); } +void recVUMI_MADDz(VURegs *VU, int info) { recVUMI_MADD_xyzw(VU, 2, info); } +void recVUMI_MADDw(VURegs *VU, int info) { recVUMI_MADD_xyzw(VU, 3, info); } +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// MADDA +//------------------------------------------------------------------ +void recVUMI_MADDA( VURegs *VU, int info ) +{ + //SysPrintf ("recVUMI_MADDA \n"); + recVUMI_MADD_toD(VU, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MADDAi( VURegs *VU , int info) +{ + //SysPrintf ("recVUMI_MADDAi \n"); + recVUMI_MADD_iq_toD( VU, VU_VI_ADDR(REG_I, 1), EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MADDAq( VURegs *VU , int info) +{ + //SysPrintf ("recVUMI_MADDAq \n"); + recVUMI_MADD_iq_toD( VU, VU_REGQ_ADDR, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MADDAx( VURegs *VU , int info) +{ + //SysPrintf ("recVUMI_MADDAx \n"); + recVUMI_MADD_xyzw_toD(VU, 0, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MADDAy( VURegs *VU , int info) +{ + //SysPrintf ("recVUMI_MADDAy \n"); + recVUMI_MADD_xyzw_toD(VU, 1, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MADDAz( VURegs *VU , int info) +{ + //SysPrintf ("recVUMI_MADDAz \n"); + recVUMI_MADD_xyzw_toD(VU, 2, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MADDAw( VURegs *VU , int info) +{ + //SysPrintf ("recVUMI_MADDAw \n"); + recVUMI_MADD_xyzw_toD(VU, 3, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// MSUB +//------------------------------------------------------------------ +void recVUMI_MSUB_toD(VURegs *VU, int regd, int info) +{ + //SysPrintf ("recVUMI_MSUB_toD \n"); + if (CHECK_VU_EXTRA_OVERFLOW) { + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + if (_Ft_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + vuFloat5_useEAX( EEREC_ACC, EEREC_TEMP, _X_Y_Z_W ); + } + + if (_X_Y_Z_W != 0xf) { + int t1reg = _vuGetTempXMMreg(info); + + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } + + if( t1reg >= 0 ) { + SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_ACC); + SSE_SUBPS_XMM_to_XMM(t1reg, EEREC_TEMP); + + VU_MERGE_REGS(regd, t1reg); + _freeXMMreg(t1reg); + } + else { + SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); + VU_MERGE_REGS(regd, EEREC_TEMP); + } + } + else { + if( regd == EEREC_S ) { + assert( regd != EEREC_ACC ); + SSE_MULPS_XMM_to_XMM(regd, EEREC_T); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } + SSE_SUBPS_XMM_to_XMM(regd, EEREC_ACC); + SSE_XORPS_M128_to_XMM(regd, (uptr)&const_clip[4]); + } + else if( regd == EEREC_T ) { + assert( regd != EEREC_ACC ); + SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } + SSE_SUBPS_XMM_to_XMM(regd, EEREC_ACC); + SSE_XORPS_M128_to_XMM(regd, (uptr)&const_clip[4]); + } + else if( regd == EEREC_TEMP ) { + SSE_MOVAPS_XMM_to_XMM(regd, EEREC_S); + SSE_MULPS_XMM_to_XMM(regd, EEREC_T); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } + SSE_SUBPS_XMM_to_XMM(regd, EEREC_ACC); + SSE_XORPS_M128_to_XMM(regd, (uptr)&const_clip[4]); + } + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MOVAPS_XMM_to_XMM(regd, EEREC_ACC); + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } + SSE_SUBPS_XMM_to_XMM(regd, EEREC_TEMP); + } + } +} + +void recVUMI_MSUB_temp_toD(VURegs *VU, int regd, int info) +{ + //SysPrintf ("recVUMI_MSUB_temp_toD \n"); + if (CHECK_VU_EXTRA_OVERFLOW) { + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); + vuFloat5_useEAX( EEREC_ACC, EEREC_TEMP, _X_Y_Z_W ); + } + + if (_X_Y_Z_W != 0xf) { + int t1reg = _vuGetTempXMMreg(info); + + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } + + if( t1reg >= 0 ) { + SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_ACC); + SSE_SUBPS_XMM_to_XMM(t1reg, EEREC_TEMP); + + if ( regd != EEREC_TEMP ) { VU_MERGE_REGS(regd, t1reg); } + else SSE_MOVAPS_XMM_to_XMM(regd, t1reg); + + _freeXMMreg(t1reg); + } + else { + SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); + VU_MERGE_REGS(regd, EEREC_TEMP); + } + } + else { + if( regd == EEREC_ACC ) { + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } + SSE_SUBPS_XMM_to_XMM(regd, EEREC_TEMP); + } + else if( regd == EEREC_S ) { + SSE_MULPS_XMM_to_XMM(regd, EEREC_TEMP); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } + SSE_SUBPS_XMM_to_XMM(regd, EEREC_ACC); + SSE_XORPS_M128_to_XMM(regd, (uptr)&const_clip[4]); + } + else if( regd == EEREC_TEMP ) { + SSE_MULPS_XMM_to_XMM(regd, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, regd, _X_Y_Z_W ); } + SSE_SUBPS_XMM_to_XMM(regd, EEREC_ACC); + SSE_XORPS_M128_to_XMM(regd, (uptr)&const_clip[4]); + } + else { + SSE_MOVAPS_XMM_to_XMM(regd, EEREC_ACC); + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + if (CHECK_VU_EXTRA_OVERFLOW) { vuFloat_useEAX( info, EEREC_TEMP, _X_Y_Z_W ); } + SSE_SUBPS_XMM_to_XMM(regd, EEREC_TEMP); + } + } +} + +void recVUMI_MSUB_iq_toD(VURegs *VU, int regd, int addr, int info) +{ + //SysPrintf ("recVUMI_MSUB_iq_toD \n"); + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + recVUMI_MSUB_temp_toD(VU, regd, info); +} + +void recVUMI_MSUB_xyzw_toD(VURegs *VU, int regd, int xyzw, int info) +{ + //SysPrintf ("recVUMI_MSUB_xyzw_toD \n"); + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + recVUMI_MSUB_temp_toD(VU, regd, info); +} + +void recVUMI_MSUB(VURegs *VU, int info) +{ + //SysPrintf ("recVUMI_MSUB \n"); + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MSUB_toD(VU, EEREC_D, info); + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_MSUB_iq(VURegs *VU, int addr, int info) +{ + //SysPrintf ("recVUMI_MSUB_iq \n"); + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MSUB_iq_toD(VU, EEREC_D, addr, info); + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_MSUBi(VURegs *VU, int info) { recVUMI_MSUB_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_MSUBq(VURegs *VU, int info) { recVUMI_MSUB_iq(VU, VU_REGQ_ADDR, info); } +void recVUMI_MSUBx(VURegs *VU, int info) +{ + //SysPrintf ("recVUMI_MSUBx \n"); + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MSUB_xyzw_toD(VU, EEREC_D, 0, info); + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_MSUBy(VURegs *VU, int info) +{ + //SysPrintf ("recVUMI_MSUBy \n"); + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MSUB_xyzw_toD(VU, EEREC_D, 1, info); + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_MSUBz(VURegs *VU, int info) +{ + //SysPrintf ("recVUMI_MSUBz \n"); + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MSUB_xyzw_toD(VU, EEREC_D, 2, info); + recUpdateFlags(VU, EEREC_D, info); +} + +void recVUMI_MSUBw(VURegs *VU, int info) +{ + //SysPrintf ("recVUMI_MSUBw \n"); + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + recVUMI_MSUB_xyzw_toD(VU, EEREC_D, 3, info); + recUpdateFlags(VU, EEREC_D, info); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// MSUBA +//------------------------------------------------------------------ +void recVUMI_MSUBA( VURegs *VU, int info ) +{ + //SysPrintf ("recVUMI_MSUBA \n"); + recVUMI_MSUB_toD(VU, EEREC_ACC, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MSUBAi( VURegs *VU, int info ) +{ + //SysPrintf ("recVUMI_MSUBAi \n"); + recVUMI_MSUB_iq_toD( VU, EEREC_ACC, VU_VI_ADDR(REG_I, 1), info ); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MSUBAq( VURegs *VU, int info ) +{ + //SysPrintf ("recVUMI_MSUBAq \n"); + recVUMI_MSUB_iq_toD( VU, EEREC_ACC, VU_REGQ_ADDR, info ); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MSUBAx( VURegs *VU, int info ) +{ + //SysPrintf ("recVUMI_MSUBAx \n"); + recVUMI_MSUB_xyzw_toD(VU, EEREC_ACC, 0, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MSUBAy( VURegs *VU, int info ) +{ + //SysPrintf ("recVUMI_MSUBAy \n"); + recVUMI_MSUB_xyzw_toD(VU, EEREC_ACC, 1, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MSUBAz( VURegs *VU, int info ) +{ + //SysPrintf ("recVUMI_MSUBAz \n"); + recVUMI_MSUB_xyzw_toD(VU, EEREC_ACC, 2, info); + recUpdateFlags(VU, EEREC_ACC, info); +} + +void recVUMI_MSUBAw( VURegs *VU, int info ) +{ + //SysPrintf ("recVUMI_MSUBAw \n"); + recVUMI_MSUB_xyzw_toD(VU, EEREC_ACC, 3, info); + recUpdateFlags(VU, EEREC_ACC, info); +} +//------------------------------------------------------------------ + + +static const u32 PCSX2_ALIGNED16(special_mask[4]) = {0xffffffff, 0x80000000, 0xffffffff, 0x80000000}; +static const u32 PCSX2_ALIGNED16(special_mask2[4]) = {0, 0x40000000, 0, 0x40000000}; + +u32 PCSX2_ALIGNED16(temp_loc[4]); +u32 PCSX2_ALIGNED16(temp_loc2[4]); + +//MAX/MINI are non-arithmetic operations that implicitly support numbers with the EXP field being 0 ("denormals"). +// +//As such, they are sometimes used for integer move and (positive!) integer max/min, knowing that integers that +//represent denormals will not be flushed to 0. +// +//As such, this implementation performs a non-arithmetic operation that supports "denormals" and "infs/nans". +//There might be an easier way to do it but here, MAX/MIN is performed with PMAXPD/PMINPD. +//Fake double-precision numbers are constructed by copying the sign of the original numbers, clearing the upper 32 bits, +//setting the 62nd bit to 1 (to ensure double-precision number is "normalized") and having the lower 32bits +//being the same as the original number. + +void MINMAXlogical(VURegs *VU, int info, int min, int mode, uptr addr = 0, int xyzw = 0) +//mode1 = iq, mode2 = xyzw, mode0 = normal +{ + int t1regbool = 0; + int t1reg = _vuGetTempXMMreg(info); + if (t1reg < 0) + { + t1regbool = 1; + for (t1reg = 0; ( (t1reg == EEREC_D) || (t1reg == EEREC_S) || (mode != 1 && t1reg == EEREC_T) + || (t1reg == EEREC_TEMP) ); t1reg++); // Find unused reg (For first temp reg) + SSE_MOVAPS_XMM_to_M128((uptr)temp_loc, t1reg); // Backup t1reg XMM reg + } + int t2regbool = -1; + int t2reg = EEREC_TEMP; + if (EEREC_TEMP == EEREC_D || EEREC_TEMP == EEREC_S || (mode != 1 && EEREC_TEMP == EEREC_T)) + { + t2regbool = 0; + t2reg = _vuGetTempXMMreg(info); + if (t2reg < 0) + { + t2regbool = 1; + for (t2reg = 0; ( (t2reg == EEREC_D) || (t2reg == EEREC_S) || (mode != 1 && t2reg == EEREC_T) || + (t2reg == t1reg) || (t2reg == EEREC_TEMP) ); t2reg++); // Find unused reg (For second temp reg) + SSE_MOVAPS_XMM_to_M128((uptr)temp_loc2, t2reg); // Backup t2reg XMM reg + } + } + + if (_X || _Y) + { + SSE2_PSHUFD_XMM_to_XMM(t1reg, EEREC_S, 0x50); + SSE2_PAND_M128_to_XMM(t1reg, (uptr)special_mask); + SSE2_POR_M128_to_XMM(t1reg, (uptr)special_mask2); + if (mode == 0) + SSE2_PSHUFD_XMM_to_XMM(t2reg, EEREC_T, 0x50); + else if (mode == 1) + { + SSE2_MOVD_M32_to_XMM(t2reg, addr); + SSE2_PSHUFD_XMM_to_XMM(t2reg, t2reg, 0x00); + } + else if (mode == 2) + _unpackVF_xyzw(t2reg, EEREC_T, xyzw); + SSE2_PAND_M128_to_XMM(t2reg, (uptr)special_mask); + SSE2_POR_M128_to_XMM(t2reg, (uptr)special_mask2); + if (min) + SSE2_MINPD_XMM_to_XMM(t1reg, t2reg); + else + SSE2_MAXPD_XMM_to_XMM(t1reg, t2reg); + SSE2_PSHUFD_XMM_to_XMM(t1reg, t1reg, 0x88); + VU_MERGE_REGS_CUSTOM(EEREC_D, t1reg, 0xc & _X_Y_Z_W); + } + + if (_Z || _W) + { + SSE2_PSHUFD_XMM_to_XMM(t1reg, EEREC_S, 0xfa); + SSE2_PAND_M128_to_XMM(t1reg, (uptr)special_mask); + SSE2_POR_M128_to_XMM(t1reg, (uptr)special_mask2); + if (mode == 0) + SSE2_PSHUFD_XMM_to_XMM(t2reg, EEREC_T, 0xfa); + else if (mode == 1) + { + SSE2_MOVD_M32_to_XMM(t2reg, addr); + SSE2_PSHUFD_XMM_to_XMM(t2reg, t2reg, 0x00); + } + else if (mode == 2) + _unpackVF_xyzw(t2reg, EEREC_T, xyzw); + SSE2_PAND_M128_to_XMM(t2reg, (uptr)special_mask); + SSE2_POR_M128_to_XMM(t2reg, (uptr)special_mask2); + if (min) + SSE2_MINPD_XMM_to_XMM(t1reg, t2reg); + else + SSE2_MAXPD_XMM_to_XMM(t1reg, t2reg); + SSE2_PSHUFD_XMM_to_XMM(t1reg, t1reg, 0x88); + VU_MERGE_REGS_CUSTOM(EEREC_D, t1reg, 0x3 & _X_Y_Z_W); + } + + if (t1regbool == 0) + _freeXMMreg(t1reg); + else if (t1regbool == 1) + SSE_MOVAPS_M128_to_XMM(t1reg, (uptr)temp_loc); // Restore t1reg XMM reg + if (t2regbool == 0) + _freeXMMreg(t2reg); + else if (t2regbool == 1) + SSE_MOVAPS_M128_to_XMM(t2reg, (uptr)temp_loc2); // Restore t2reg XMM reg +} + +//------------------------------------------------------------------ +// MAX +//------------------------------------------------------------------ + +void recVUMI_MAX(VURegs *VU, int info) +{ + if ( _Fd_ == 0 ) return; + //SysPrintf ("recVUMI_MAX \n"); + + if (MINMAXFIX) + MINMAXlogical(VU, info, 0, 0); + else + { + + if (_Fs_) vuFloat4_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); // Always do Preserved Sign Clamping + if (_Ft_) vuFloat4_useEAX( EEREC_T, EEREC_TEMP, _X_Y_Z_W ); + + if( _X_Y_Z_W == 8 ) { + if (EEREC_D == EEREC_S) SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_T); + else if (EEREC_D == EEREC_T) SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + else if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MAXPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if( EEREC_D == EEREC_S ) SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + } +} + +void recVUMI_MAX_iq(VURegs *VU, uptr addr, int info) +{ + if ( _Fd_ == 0 ) return; + //SysPrintf ("recVUMI_MAX_iq \n"); + + if (MINMAXFIX) + MINMAXlogical(VU, info, 0, 1, addr); + else + { + if (_Fs_) vuFloat4_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); // Always do Preserved Sign Clamping + vuFloat3(addr); + + if( _XYZW_SS ) { + if( EEREC_D == EEREC_TEMP ) { + _vuFlipRegSS(VU, EEREC_S); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MAXSS_M32_to_XMM(EEREC_D, addr); + _vuFlipRegSS(VU, EEREC_S); + + // have to flip over EEREC_D if computing flags! + //if( (info & PROCESS_VU_UPDATEFLAGS) ) + _vuFlipRegSS(VU, EEREC_D); + } + else if( EEREC_D == EEREC_S ) { + _vuFlipRegSS(VU, EEREC_D); + SSE_MAXSS_M32_to_XMM(EEREC_D, addr); + _vuFlipRegSS(VU, EEREC_D); + } + else { + if( _X ) { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MAXSS_M32_to_XMM(EEREC_D, addr); + } + else { + _vuMoveSS(VU, EEREC_TEMP, EEREC_S); + _vuFlipRegSS(VU, EEREC_D); + SSE_MAXSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + _vuFlipRegSS(VU, EEREC_D); + } + } + } + else if (_X_Y_Z_W != 0xf) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + SSE_MAXPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if(EEREC_D == EEREC_S) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_D, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_D, EEREC_D, 0x00); + SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + } + } +} + +void recVUMI_MAX_xyzw(VURegs *VU, int xyzw, int info) +{ + if ( _Fd_ == 0 ) return; + //SysPrintf ("recVUMI_MAX_xyzw \n"); + + if (_Fs_ == 0 && _Ft_ == 0) + { + if( _X_Y_Z_W == 8 && (EEREC_D != EEREC_TEMP)) { + if( xyzw < 3 ) { + SSE_XORPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, (uptr)s_fones); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + } + else if (_X_Y_Z_W != 0xf) { + if( xyzw < 3 ) { + if( _X_Y_Z_W & 1 ) SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, (uptr)&VU->VF[0].UL[0]); // w included, so insert the whole reg + else SSE_XORPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); // w not included, can zero out + } + else SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, (uptr)s_fones); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if( xyzw < 3 ) SSE_XORPS_XMM_to_XMM(EEREC_D, EEREC_D); + else SSE_MOVAPS_M128_to_XMM(EEREC_D, (uptr)s_fones); + } + return; + } + + if (MINMAXFIX) + MINMAXlogical(VU, info, 0, 2, 0, xyzw); + else + { + if (_Fs_) vuFloat4_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); // Always do Preserved Sign Clamping + if (_Ft_) vuFloat4_useEAX( EEREC_T, EEREC_TEMP, ( 1 << (3 - xyzw) ) ); + + if( _X_Y_Z_W == 8 && (EEREC_D != EEREC_TEMP)) { + if( xyzw == 0 ) { + if( EEREC_D == EEREC_S ) SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + else { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MAXSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + } + else if (_X_Y_Z_W != 0xf) { + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_MAXPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if (EEREC_D == EEREC_S) { + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + else { + _unpackVF_xyzw(EEREC_D, EEREC_T, xyzw); + SSE_MAXPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + } + } +} + +void recVUMI_MAXi(VURegs *VU, int info) { recVUMI_MAX_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_MAXx(VURegs *VU, int info) { recVUMI_MAX_xyzw(VU, 0, info); } +void recVUMI_MAXy(VURegs *VU, int info) { recVUMI_MAX_xyzw(VU, 1, info); } +void recVUMI_MAXz(VURegs *VU, int info) { recVUMI_MAX_xyzw(VU, 2, info); } +void recVUMI_MAXw(VURegs *VU, int info) { recVUMI_MAX_xyzw(VU, 3, info); } +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// MINI +//------------------------------------------------------------------ +void recVUMI_MINI(VURegs *VU, int info) +{ + if ( _Fd_ == 0 ) return; + //SysPrintf ("recVUMI_MINI\n"); + + if (MINMAXFIX) + MINMAXlogical(VU, info, 1, 0); + else + { + + if (_Fs_) vuFloat4_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); // Always do Preserved Sign Clamping + if (_Ft_) vuFloat4_useEAX( EEREC_T, EEREC_TEMP, _X_Y_Z_W ); + + if( _X_Y_Z_W == 8 ) { + if (EEREC_D == EEREC_S) SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_T); + else if (EEREC_D == EEREC_T) SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + else if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MINPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if( EEREC_D == EEREC_S ) { + //ClampUnordered(EEREC_T, EEREC_TEMP, 0); // need for GT4 vu0rec + SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_T); + } + else if( EEREC_D == EEREC_T ) { + //ClampUnordered(EEREC_S, EEREC_TEMP, 0); // need for GT4 vu0rec + SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + } +} + +void recVUMI_MINI_iq(VURegs *VU, uptr addr, int info) +{ + if ( _Fd_ == 0 ) return; + //SysPrintf ("recVUMI_MINI_iq \n"); + + if (MINMAXFIX) + MINMAXlogical(VU, info, 1, 1, addr); + else + { + + if (_Fs_) vuFloat4_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); // Always do Preserved Sign Clamping + vuFloat3(addr); + + if( _XYZW_SS ) { + if( EEREC_D == EEREC_TEMP ) { + _vuFlipRegSS(VU, EEREC_S); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MINSS_M32_to_XMM(EEREC_D, addr); + _vuFlipRegSS(VU, EEREC_S); + + // have to flip over EEREC_D if computing flags! + //if( (info & PROCESS_VU_UPDATEFLAGS) ) + _vuFlipRegSS(VU, EEREC_D); + } + else if( EEREC_D == EEREC_S ) { + _vuFlipRegSS(VU, EEREC_D); + SSE_MINSS_M32_to_XMM(EEREC_D, addr); + _vuFlipRegSS(VU, EEREC_D); + } + else { + if( _X ) { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MINSS_M32_to_XMM(EEREC_D, addr); + } + else { + _vuMoveSS(VU, EEREC_TEMP, EEREC_S); + _vuFlipRegSS(VU, EEREC_D); + SSE_MINSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + _vuFlipRegSS(VU, EEREC_D); + } + } + } + else if (_X_Y_Z_W != 0xf) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + SSE_MINPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if(EEREC_D == EEREC_S) { + SSE_MOVSS_M32_to_XMM(EEREC_TEMP, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0x00); + SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + else { + SSE_MOVSS_M32_to_XMM(EEREC_D, addr); + SSE_SHUFPS_XMM_to_XMM(EEREC_D, EEREC_D, 0x00); + SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + } + } +} + +void recVUMI_MINI_xyzw(VURegs *VU, int xyzw, int info) +{ + if ( _Fd_ == 0 ) return; + //SysPrintf ("recVUMI_MINI_xyzw \n"); + + if (MINMAXFIX) + MINMAXlogical(VU, info, 1, 2, 0, xyzw); + else + { + if (_Fs_) vuFloat4_useEAX( EEREC_S, EEREC_TEMP, _X_Y_Z_W ); // Always do Preserved Sign Clamping + if (_Ft_) vuFloat4_useEAX( EEREC_T, EEREC_TEMP, ( 1 << (3 - xyzw) ) ); + + if( _X_Y_Z_W == 8 && (EEREC_D != EEREC_TEMP)) { + if( xyzw == 0 ) { + if( EEREC_D == EEREC_S ) SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_S); + else { + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_T); + } + } + else { + _unpackVFSS_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S); + SSE_MINSS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + } + else if (_X_Y_Z_W != 0xf) { + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_MINPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + VU_MERGE_REGS(EEREC_D, EEREC_TEMP); + } + else { + if (EEREC_D == EEREC_S) { + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, xyzw); + SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_TEMP); + } + else { + _unpackVF_xyzw(EEREC_D, EEREC_T, xyzw); + SSE_MINPS_XMM_to_XMM(EEREC_D, EEREC_S); + } + } + } +} + +void recVUMI_MINIi(VURegs *VU, int info) { recVUMI_MINI_iq(VU, VU_VI_ADDR(REG_I, 1), info); } +void recVUMI_MINIx(VURegs *VU, int info) { recVUMI_MINI_xyzw(VU, 0, info); } +void recVUMI_MINIy(VURegs *VU, int info) { recVUMI_MINI_xyzw(VU, 1, info); } +void recVUMI_MINIz(VURegs *VU, int info) { recVUMI_MINI_xyzw(VU, 2, info); } +void recVUMI_MINIw(VURegs *VU, int info) { recVUMI_MINI_xyzw(VU, 3, info); } +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// OPMULA +//------------------------------------------------------------------ +void recVUMI_OPMULA( VURegs *VU, int info ) +{ + //SysPrintf ("recVUMI_OPMULA \n"); + if (CHECK_VU_EXTRA_OVERFLOW) { + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, 0xE); + if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, 0xE); + } + + SSE_MOVAPS_XMM_to_XMM( EEREC_TEMP, EEREC_S ); + SSE_SHUFPS_XMM_to_XMM( EEREC_T, EEREC_T, 0xD2 ); // EEREC_T = WYXZ + SSE_SHUFPS_XMM_to_XMM( EEREC_TEMP, EEREC_TEMP, 0xC9 ); // EEREC_TEMP = WXZY + SSE_MULPS_XMM_to_XMM( EEREC_TEMP, EEREC_T ); + + VU_MERGE_REGS_CUSTOM(EEREC_ACC, EEREC_TEMP, 14); + + // revert EEREC_T + if( EEREC_T != EEREC_ACC ) + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0xC9); + + recUpdateFlags(VU, EEREC_ACC, info); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// OPMSUB +//------------------------------------------------------------------ +void recVUMI_OPMSUB( VURegs *VU, int info ) +{ + //SysPrintf ("recVUMI_OPMSUB \n"); + if (CHECK_VU_EXTRA_OVERFLOW) { + if (_Fs_) vuFloat5_useEAX( EEREC_S, EEREC_TEMP, 0xE); + if (_Ft_) vuFloat5_useEAX( EEREC_T, EEREC_TEMP, 0xE); + } + + if( !_Fd_ ) info |= PROCESS_EE_SET_D(EEREC_TEMP); + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0xD2); // EEREC_T = WYXZ + SSE_SHUFPS_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP, 0xC9); // EEREC_TEMP = WXZY + SSE_MULPS_XMM_to_XMM(EEREC_TEMP, EEREC_T); + + // negate and add + SSE_XORPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[4]); + SSE_ADDPS_XMM_to_XMM(EEREC_TEMP, EEREC_ACC); + VU_MERGE_REGS_CUSTOM(EEREC_D, EEREC_TEMP, 14); + + // revert EEREC_T + if( EEREC_T != EEREC_D ) SSE_SHUFPS_XMM_to_XMM(EEREC_T, EEREC_T, 0xC9); + + recUpdateFlags(VU, EEREC_D, info); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// NOP +//------------------------------------------------------------------ +void recVUMI_NOP( VURegs *VU, int info ) +{ + //SysPrintf ("recVUMI_NOP \n"); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// recVUMI_FTOI_Saturate() - Saturates result from FTOI Instructions +//------------------------------------------------------------------ +static const PCSX2_ALIGNED16(int rec_const_0x8000000[4]) = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }; + +void recVUMI_FTOI_Saturate(int rec_s, int rec_t, int rec_tmp1, int rec_tmp2) +{ + //SysPrintf ("recVUMI_FTOI_Saturate \n"); + //Duplicate the xor'd sign bit to the whole value + //FFFF FFFF for positive, 0 for negative + SSE_MOVAPS_XMM_to_XMM(rec_tmp1, rec_s); + SSE2_PXOR_M128_to_XMM(rec_tmp1, (uptr)&const_clip[4]); + SSE2_PSRAD_I8_to_XMM(rec_tmp1, 31); + + //Create mask: 0 where !=8000 0000 + SSE_MOVAPS_XMM_to_XMM(rec_tmp2, rec_t); + SSE2_PCMPEQD_M128_to_XMM(rec_tmp2, (uptr)&const_clip[4]); + + //AND the mask w/ the edit values + SSE_ANDPS_XMM_to_XMM(rec_tmp1, rec_tmp2); + + //if v==8000 0000 && positive -> 8000 0000 + FFFF FFFF -> 7FFF FFFF + //if v==8000 0000 && negative -> 8000 0000 + 0 -> 8000 0000 + //if v!=8000 0000 -> v+0 (masked from the and) + + //Add the values as needed + SSE2_PADDD_XMM_to_XMM(rec_t, rec_tmp1); +} +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// FTOI 0/4/12/15 +//------------------------------------------------------------------ +static PCSX2_ALIGNED16(float FTIO_Temp1[4]) = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; +static PCSX2_ALIGNED16(float FTIO_Temp2[4]) = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; +void recVUMI_FTOI0(VURegs *VU, int info) +{ + int t1reg, t2reg; // Temp XMM regs + + if ( _Ft_ == 0 ) return; + + //SysPrintf ("recVUMI_FTOI0 \n"); + + if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + vuFloat_useEAX( info, EEREC_TEMP, 0xf ); // Clamp Infs and NaNs to pos/neg fmax (NaNs always to positive fmax) + SSE2_CVTTPS2DQ_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + + t1reg = _vuGetTempXMMreg(info); + + if( t1reg >= 0 ) { // If theres a temp XMM reg available + for (t2reg = 0; ( (t2reg == EEREC_S) || (t2reg == EEREC_T) || (t2reg == EEREC_TEMP) || (t2reg == t1reg) ); t2reg++) + ; // Find unused reg (For second temp reg) + SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t2reg); // Backup XMM reg + + recVUMI_FTOI_Saturate(EEREC_S, EEREC_TEMP, t1reg, t2reg); // Saturate if Float->Int conversion returned illegal result + + SSE_MOVAPS_M128_to_XMM(t2reg, (uptr)FTIO_Temp1); // Restore XMM reg + _freeXMMreg(t1reg); // Free temp reg + } + else { // No temp reg available + for (t1reg = 0; ( (t1reg == EEREC_S) || (t1reg == EEREC_T) || (t1reg == EEREC_TEMP) ); t1reg++) + ; // Find unused reg (For first temp reg) + SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t1reg); // Backup t1reg XMM reg + + for (t2reg = 0; ( (t2reg == EEREC_S) || (t2reg == EEREC_T) || (t2reg == EEREC_TEMP) || (t2reg == t1reg) ); t2reg++) + ; // Find unused reg (For second temp reg) + SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp2, t2reg); // Backup t2reg XMM reg + + recVUMI_FTOI_Saturate(EEREC_S, EEREC_TEMP, t1reg, t2reg); // Saturate if Float->Int conversion returned illegal result + + SSE_MOVAPS_M128_to_XMM(t1reg, (uptr)FTIO_Temp1); // Restore t1reg XMM reg + SSE_MOVAPS_M128_to_XMM(t2reg, (uptr)FTIO_Temp2); // Restore t2reg XMM reg + } + + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + } + else { + if (EEREC_T != EEREC_S) { + SSE_MOVAPS_XMM_to_XMM(EEREC_T, EEREC_S); + vuFloat_useEAX( info, EEREC_T, 0xf ); // Clamp Infs and NaNs to pos/neg fmax (NaNs always to positive fmax) + SSE2_CVTTPS2DQ_XMM_to_XMM(EEREC_T, EEREC_T); + + t1reg = _vuGetTempXMMreg(info); + + if( t1reg >= 0 ) { // If theres a temp XMM reg available + recVUMI_FTOI_Saturate(EEREC_S, EEREC_T, EEREC_TEMP, t1reg); // Saturate if Float->Int conversion returned illegal result + _freeXMMreg(t1reg); // Free temp reg + } + else { // No temp reg available + for (t1reg = 0; ( (t1reg == EEREC_S) || (t1reg == EEREC_T) || (t1reg == EEREC_TEMP) ); t1reg++) + ; // Find unused reg + SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t1reg); // Backup t1reg XMM reg + + recVUMI_FTOI_Saturate(EEREC_S, EEREC_T, EEREC_TEMP, t1reg); // Saturate if Float->Int conversion returned illegal result + + SSE_MOVAPS_M128_to_XMM(t1reg, (uptr)FTIO_Temp1); // Restore t1reg XMM reg + } + } + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + vuFloat_useEAX( info, EEREC_TEMP, 0xf ); // Clamp Infs and NaNs to pos/neg fmax (NaNs always to positive fmax) + SSE2_CVTTPS2DQ_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + + t1reg = _vuGetTempXMMreg(info); + + if( t1reg >= 0 ) { // If theres a temp XMM reg available + for (t2reg = 0; ( (t2reg == EEREC_S) || (t2reg == EEREC_T) || (t2reg == EEREC_TEMP) || (t2reg == t1reg)); t2reg++) + ; // Find unused reg (For second temp reg) + SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t2reg); // Backup XMM reg + + recVUMI_FTOI_Saturate(EEREC_S, EEREC_TEMP, t1reg, t2reg); // Saturate if Float->Int conversion returned illegal result + + SSE_MOVAPS_M128_to_XMM(t2reg, (uptr)FTIO_Temp1); // Restore XMM reg + _freeXMMreg(t1reg); // Free temp reg + } + else { // No temp reg available + for (t1reg = 0; ( (t1reg == EEREC_S) || (t1reg == EEREC_T) || (t1reg == EEREC_TEMP) ); t1reg++) + ; // Find unused reg (For first temp reg) + SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t1reg); // Backup t1reg XMM reg + + for (t2reg = 0; ( (t2reg == EEREC_S) || (t2reg == EEREC_T) || (t2reg == EEREC_TEMP) || (t2reg == t1reg) ); t2reg++) + ; // Find unused reg (For second temp reg) + SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp2, t2reg); // Backup t2reg XMM reg + + recVUMI_FTOI_Saturate(EEREC_S, EEREC_TEMP, t1reg, t2reg); // Saturate if Float->Int conversion returned illegal result + + SSE_MOVAPS_M128_to_XMM(t1reg, (uptr)FTIO_Temp1); // Restore t1reg XMM reg + SSE_MOVAPS_M128_to_XMM(t2reg, (uptr)FTIO_Temp2); // Restore t2reg XMM reg + } + + SSE_MOVAPS_XMM_to_XMM(EEREC_T, EEREC_TEMP); + } + } +} + +void recVUMI_FTOIX(VURegs *VU, int addr, int info) +{ + int t1reg, t2reg; // Temp XMM regs + + if ( _Ft_ == 0 ) return; + + //SysPrintf ("recVUMI_FTOIX \n"); + if (_X_Y_Z_W != 0xf) { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MULPS_M128_to_XMM(EEREC_TEMP, addr); + vuFloat_useEAX( info, EEREC_TEMP, 0xf ); // Clamp Infs and NaNs to pos/neg fmax (NaNs always to positive fmax) + SSE2_CVTTPS2DQ_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + + t1reg = _vuGetTempXMMreg(info); + + if( t1reg >= 0 ) { // If theres a temp XMM reg available + for (t2reg = 0; ( (t2reg == EEREC_S) || (t2reg == EEREC_T) || (t2reg == EEREC_TEMP) || (t2reg == t1reg)); t2reg++) + ; // Find unused reg (For second temp reg) + SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t2reg); // Backup XMM reg + + recVUMI_FTOI_Saturate(EEREC_S, EEREC_TEMP, t1reg, t2reg); // Saturate if Float->Int conversion returned illegal result + + SSE_MOVAPS_M128_to_XMM(t2reg, (uptr)FTIO_Temp1); // Restore XMM reg + _freeXMMreg(t1reg); // Free temp reg + } + else { // No temp reg available + for (t1reg = 0; ( (t1reg == EEREC_S) || (t1reg == EEREC_T) || (t1reg == EEREC_TEMP) ); t1reg++) + ; // Find unused reg (For first temp reg) + SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t1reg); // Backup t1reg XMM reg + + for (t2reg = 0; ( (t2reg == EEREC_S) || (t2reg == EEREC_T) || (t2reg == EEREC_TEMP) || (t2reg == t1reg) ); t2reg++) + ; // Find unused reg (For second temp reg) + SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp2, t2reg); // Backup t2reg XMM reg + + recVUMI_FTOI_Saturate(EEREC_S, EEREC_TEMP, t1reg, t2reg); // Saturate if Float->Int conversion returned illegal result + + SSE_MOVAPS_M128_to_XMM(t1reg, (uptr)FTIO_Temp1); // Restore t1reg XMM reg + SSE_MOVAPS_M128_to_XMM(t2reg, (uptr)FTIO_Temp2); // Restore t2reg XMM reg + } + + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + } + else { + if (EEREC_T != EEREC_S) { + SSE_MOVAPS_XMM_to_XMM(EEREC_T, EEREC_S); + SSE_MULPS_M128_to_XMM(EEREC_T, addr); + vuFloat_useEAX( info, EEREC_T, 0xf ); // Clamp Infs and NaNs to pos/neg fmax (NaNs always to positive fmax) + SSE2_CVTTPS2DQ_XMM_to_XMM(EEREC_T, EEREC_T); + + t1reg = _vuGetTempXMMreg(info); + + if( t1reg >= 0 ) { // If theres a temp XMM reg available + recVUMI_FTOI_Saturate(EEREC_S, EEREC_T, EEREC_TEMP, t1reg); // Saturate if Float->Int conversion returned illegal result + _freeXMMreg(t1reg); // Free temp reg + } + else { // No temp reg available + for (t1reg = 0; ( (t1reg == EEREC_S) || (t1reg == EEREC_T) || (t1reg == EEREC_TEMP) ); t1reg++) + ; // Find unused reg + SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t1reg); // Backup t1reg XMM reg + + recVUMI_FTOI_Saturate(EEREC_S, EEREC_T, EEREC_TEMP, t1reg); // Saturate if Float->Int conversion returned illegal result + + SSE_MOVAPS_M128_to_XMM(t1reg, (uptr)FTIO_Temp1); // Restore t1reg XMM reg + } + } + else { + SSE_MOVAPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MULPS_M128_to_XMM(EEREC_TEMP, addr); + vuFloat_useEAX( info, EEREC_TEMP, 0xf ); // Clamp Infs and NaNs to pos/neg fmax (NaNs always to positive fmax) + SSE2_CVTTPS2DQ_XMM_to_XMM(EEREC_TEMP, EEREC_TEMP); + + t1reg = _vuGetTempXMMreg(info); + + if( t1reg >= 0 ) { // If theres a temp XMM reg available + for (t2reg = 0; ( (t2reg == EEREC_S) || (t2reg == EEREC_T) || (t2reg == EEREC_TEMP) || (t2reg == t1reg)); t2reg++) + ; // Find unused reg (For second temp reg) + SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t2reg); // Backup XMM reg + + recVUMI_FTOI_Saturate(EEREC_S, EEREC_TEMP, t1reg, t2reg); // Saturate if Float->Int conversion returned illegal result + + SSE_MOVAPS_M128_to_XMM(t2reg, (uptr)FTIO_Temp1); // Restore XMM reg + _freeXMMreg(t1reg); // Free temp reg + } + else { // No temp reg available + for (t1reg = 0; ( (t1reg == EEREC_S) || (t1reg == EEREC_T) || (t1reg == EEREC_TEMP) ); t1reg++) + ; // Find unused reg (For first temp reg) + SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp1, t1reg); // Backup t1reg XMM reg + + for (t2reg = 0; ( (t2reg == EEREC_S) || (t2reg == EEREC_T) || (t2reg == EEREC_TEMP) || (t2reg == t1reg) ); t2reg++) + ; // Find unused reg (For second temp reg) + SSE_MOVAPS_XMM_to_M128((uptr)FTIO_Temp2, t2reg); // Backup t2reg XMM reg + + recVUMI_FTOI_Saturate(EEREC_S, EEREC_TEMP, t1reg, t2reg); // Saturate if Float->Int conversion returned illegal result + + SSE_MOVAPS_M128_to_XMM(t1reg, (uptr)FTIO_Temp1); // Restore t1reg XMM reg + SSE_MOVAPS_M128_to_XMM(t2reg, (uptr)FTIO_Temp2); // Restore t2reg XMM reg + } + + SSE_MOVAPS_XMM_to_XMM(EEREC_T, EEREC_TEMP); + } + } +} + +void recVUMI_FTOI4( VURegs *VU, int info ) { recVUMI_FTOIX(VU, (uptr)&recMult_float_to_int4[0], info); } +void recVUMI_FTOI12( VURegs *VU, int info ) { recVUMI_FTOIX(VU, (uptr)&recMult_float_to_int12[0], info); } +void recVUMI_FTOI15( VURegs *VU, int info ) { recVUMI_FTOIX(VU, (uptr)&recMult_float_to_int15[0], info); } +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// ITOF 0/4/12/15 +//------------------------------------------------------------------ +void recVUMI_ITOF0( VURegs *VU, int info ) +{ + if ( _Ft_ == 0 ) return; + + //SysPrintf ("recVUMI_ITOF0 \n"); + if (_X_Y_Z_W != 0xf) { + SSE2_CVTDQ2PS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + vuFloat_useEAX( info, EEREC_TEMP, 15); // Clamp infinities + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + xmmregs[EEREC_T].mode |= MODE_WRITE; + } + else { + SSE2_CVTDQ2PS_XMM_to_XMM(EEREC_T, EEREC_S); + vuFloat2(EEREC_T, EEREC_TEMP, 15); // Clamp infinities + } +} + +void recVUMI_ITOFX(VURegs *VU, int addr, int info) +{ + if ( _Ft_ == 0 ) return; + + //SysPrintf ("recVUMI_ITOFX \n"); + if (_X_Y_Z_W != 0xf) { + SSE2_CVTDQ2PS_XMM_to_XMM(EEREC_TEMP, EEREC_S); + SSE_MULPS_M128_to_XMM(EEREC_TEMP, addr); + vuFloat_useEAX( info, EEREC_TEMP, 15); // Clamp infinities + VU_MERGE_REGS(EEREC_T, EEREC_TEMP); + xmmregs[EEREC_T].mode |= MODE_WRITE; + } + else { + SSE2_CVTDQ2PS_XMM_to_XMM(EEREC_T, EEREC_S); + SSE_MULPS_M128_to_XMM(EEREC_T, addr); + vuFloat2(EEREC_T, EEREC_TEMP, 15); // Clamp infinities + } +} + +void recVUMI_ITOF4( VURegs *VU, int info ) { recVUMI_ITOFX(VU, (uptr)&recMult_int_to_float4[0], info); } +void recVUMI_ITOF12( VURegs *VU, int info ) { recVUMI_ITOFX(VU, (uptr)&recMult_int_to_float12[0], info); } +void recVUMI_ITOF15( VURegs *VU, int info ) { recVUMI_ITOFX(VU, (uptr)&recMult_int_to_float15[0], info); } +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// CLIP +//------------------------------------------------------------------ +void recVUMI_CLIP(VURegs *VU, int info) +{ + int t1reg = EEREC_D; + int t2reg = EEREC_ACC; + int x86temp1, x86temp2; + + u32 clipaddr = VU_VI_ADDR(REG_CLIP_FLAG, 0); + u32 prevclipaddr = VU_VI_ADDR(REG_CLIP_FLAG, 2); + + if( clipaddr == 0 ) { // battle star has a clip right before fcset + SysPrintf("skipping vu clip\n"); + return; + } + + //Flush the clip flag before processing, incase of double clip commands (GoW) + + if( prevclipaddr != (uptr)&VU->VI[REG_CLIP_FLAG] ) { + MOV32MtoR(EAX, prevclipaddr); + MOV32RtoM((uptr)&VU->VI[REG_CLIP_FLAG], EAX); + } + + assert( clipaddr != 0 ); + assert( t1reg != t2reg && t1reg != EEREC_TEMP && t2reg != EEREC_TEMP ); + + x86temp1 = ALLOCTEMPX86(MODE_8BITREG); + x86temp2 = ALLOCTEMPX86(MODE_8BITREG); + + //if ( (x86temp1 == 0) || (x86temp2 == 0) ) SysPrintf("VU CLIP Allocation Error: EAX being allocated! \n"); + + _freeXMMreg(t1reg); // These should have been freed at allocation in eeVURecompileCode() + _freeXMMreg(t2reg); // but if they've been used since then, then free them. (just doing this incase :p (cottonvibes)) + + if( _Ft_ == 0 ) { + SSE_MOVAPS_M128_to_XMM(EEREC_TEMP, (uptr)&s_fones[0]); // all 1s + SSE_MOVAPS_M128_to_XMM(t1reg, (uptr)&s_fones[4]); + } + else { + _unpackVF_xyzw(EEREC_TEMP, EEREC_T, 3); + SSE_ANDPS_M128_to_XMM(EEREC_TEMP, (uptr)&const_clip[0]); + SSE_MOVAPS_XMM_to_XMM(t1reg, EEREC_TEMP); + SSE_ORPS_M128_to_XMM(t1reg, (uptr)&const_clip[4]); + } + + MOV32MtoR(EAX, prevclipaddr); + + SSE_CMPNLEPS_XMM_to_XMM(t1reg, EEREC_S); //-w, -z, -y, -x + SSE_CMPLTPS_XMM_to_XMM(EEREC_TEMP, EEREC_S); //+w, +z, +y, +x + + SHL32ItoR(EAX, 6); + + SSE_MOVAPS_XMM_to_XMM(t2reg, EEREC_TEMP); //t2 = +w, +z, +y, +x + SSE_UNPCKLPS_XMM_to_XMM(EEREC_TEMP, t1reg); //EEREC_TEMP = -y,+y,-x,+x + SSE_UNPCKHPS_XMM_to_XMM(t2reg, t1reg); //t2reg = -w,+w,-z,+z + SSE_MOVMSKPS_XMM_to_R32(x86temp2, EEREC_TEMP); // -y,+y,-x,+x + SSE_MOVMSKPS_XMM_to_R32(x86temp1, t2reg); // -w,+w,-z,+z + + AND8ItoR(x86temp1, 0x3); + SHL8ItoR(x86temp1, 4); + OR8RtoR(EAX, x86temp1); + AND8ItoR(x86temp2, 0xf); + OR8RtoR(EAX, x86temp2); + AND32ItoR(EAX, 0xffffff); + + MOV32RtoM(clipaddr, EAX); + + if (( !(info & (PROCESS_VU_SUPER|PROCESS_VU_COP2)) ) ) //Instantly update the flag if its called from elsewhere (unlikely, but ok) + MOV32RtoM((uptr)&VU->VI[REG_CLIP_FLAG], EAX); + + _freeX86reg(x86temp1); + _freeX86reg(x86temp2); } \ No newline at end of file diff --git a/pcsx2/x86/iVUops.h b/pcsx2/x86/iVUops.h index d4571bff93..f0f0302291 100644 --- a/pcsx2/x86/iVUops.h +++ b/pcsx2/x86/iVUops.h @@ -1,57 +1,57 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -#define REC_VUOP(VU, f) { \ - _freeXMMregs(/*&VU*/); \ - _freeMMXregs(); \ - SetFPUstate();) \ - MOV32ItoM((uptr)&VU.code, (u32)VU.code); \ - CALLFunc((uptr)VU##MI_##f); \ -} - -#define REC_VUOPs(VU, f) { \ - _freeXMMregs(); \ - _freeMMXregs(); \ - SetFPUstate();) \ - if (VU==&VU1) { \ - MOV32ItoM((uptr)&VU1.code, (u32)VU1.code); \ - CALLFunc((uptr)VU1MI_##f); \ - } \ - else { \ - MOV32ItoM((uptr)&VU0.code, (u32)VU0.code); \ - CALLFunc((uptr)VU0MI_##f); \ - } \ -} - -#define REC_VUOPFLAGS(VU, f) { \ - _freeXMMregs(/*&VU*/); \ - _freeMMXregs(); \ - SetFPUstate(); \ - MOV32ItoM((uptr)&VU.code, (u32)VU.code); \ - CALLFunc((uptr)VU##MI_##f); \ -} - -#define REC_VUBRANCH(VU, f) { \ - _freeXMMregs(/*&VU*/); \ - _freeMMXregs(); \ - SetFPUstate(); \ - MOV32ItoM((uptr)&VU.code, (u32)VU.code); \ - MOV32ItoM((uptr)&VU.VI[REG_TPC].UL, (u32)pc); \ - CALLFunc((uptr)VU##MI_##f); \ - branch = 1; \ -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +#define REC_VUOP(VU, f) { \ + _freeXMMregs(/*&VU*/); \ + _freeMMXregs(); \ + SetFPUstate();) \ + MOV32ItoM((uptr)&VU.code, (u32)VU.code); \ + CALLFunc((uptr)VU##MI_##f); \ +} + +#define REC_VUOPs(VU, f) { \ + _freeXMMregs(); \ + _freeMMXregs(); \ + SetFPUstate();) \ + if (VU==&VU1) { \ + MOV32ItoM((uptr)&VU1.code, (u32)VU1.code); \ + CALLFunc((uptr)VU1MI_##f); \ + } \ + else { \ + MOV32ItoM((uptr)&VU0.code, (u32)VU0.code); \ + CALLFunc((uptr)VU0MI_##f); \ + } \ +} + +#define REC_VUOPFLAGS(VU, f) { \ + _freeXMMregs(/*&VU*/); \ + _freeMMXregs(); \ + SetFPUstate(); \ + MOV32ItoM((uptr)&VU.code, (u32)VU.code); \ + CALLFunc((uptr)VU##MI_##f); \ +} + +#define REC_VUBRANCH(VU, f) { \ + _freeXMMregs(/*&VU*/); \ + _freeMMXregs(); \ + SetFPUstate(); \ + MOV32ItoM((uptr)&VU.code, (u32)VU.code); \ + MOV32ItoM((uptr)&VU.VI[REG_TPC].UL, (u32)pc); \ + CALLFunc((uptr)VU##MI_##f); \ + branch = 1; \ +} diff --git a/pcsx2/x86/iVUzerorec.cpp b/pcsx2/x86/iVUzerorec.cpp index d8f5d07a55..fd560b8d37 100644 --- a/pcsx2/x86/iVUzerorec.cpp +++ b/pcsx2/x86/iVUzerorec.cpp @@ -1,4141 +1,4141 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -// Super VU recompiler - author: zerofrog(@gmail.com) - -#include "PrecompiledHeader.h" - -#include -#include -#include -#include -#include - -#ifndef _WIN32 -#include -#endif - -#include "Common.h" - -#include "GS.h" -#include "R5900.h" -#include "VU.h" -#include "ix86/ix86.h" -#include "iR5900.h" - -#include "iVUzerorec.h" -#include "SamplProf.h" - -using namespace std; - -// temporary externs -extern void iDumpVU0Registers(); -extern void iDumpVU1Registers(); - -// SuperVURec optimization options, uncomment only for debugging purposes -#define SUPERVU_CACHING // vu programs are saved and queried via memcompare (should be no reason to disable this) -#define SUPERVU_WRITEBACKS // don't flush the writebacks after every block -#define SUPERVU_X86CACHING // use x86reg caching (faster) -#define SUPERVU_VIBRANCHDELAY // when integers are modified right before a branch that uses the integer, - // the old integer value is used in the branch - // fixes kh2 - -#define SUPERVU_PROPAGATEFLAGS // the correct behavior of VUs, for some reason superman breaks gfx with it on... - -#ifndef _DEBUG -#define SUPERVU_INTERCACHING // registers won't be flushed at block boundaries (faster) -#endif - -#define SUPERVU_CHECKCONDITION 0 // has to be 0!! - -#define VU_EXESIZE 0x00800000 - -#define _Imm11_ (s32)( (vucode & 0x400) ? (0xfffffc00 | (vucode & 0x3ff)) : (vucode & 0x3ff) ) -#define _UImm11_ (s32)(vucode & 0x7ff) - -#define _Ft_ ((VU->code >> 16) & 0x1F) // The rt part of the instruction register -#define _Fs_ ((VU->code >> 11) & 0x1F) // The rd part of the instruction register -#define _Fd_ ((VU->code >> 6) & 0x1F) // The sa part of the instruction register - -static const u32 QWaitTimes[] = { 6, 12 }; -static const u32 PWaitTimes[] = { 53, 43, 28, 23, 17, 11, 10 }; - -static u32 s_vuInfo; // info passed into rec insts - -static const u32 s_MemSize[2] = {VU0_MEMSIZE, VU1_MEMSIZE}; -static u8* s_recVUMem = NULL, *s_recVUPtr = NULL; - -// tables which are defined at the bottom of this massive file. -extern void (*recVU_UPPER_OPCODE[64])( VURegs* VU, s32 info ); -extern void (*recVU_LOWER_OPCODE[128])( VURegs* VU, s32 info ); - -#define INST_Q_READ 0x0001 // flush Q -#define INST_P_READ 0x0002 // flush P -#define INST_BRANCH_DELAY 0x0004 -#define INST_CLIP_WRITE 0x0040 // inst writes CLIP in the future -#define INST_STATUS_WRITE 0x0080 -#define INST_MAC_WRITE 0x0100 -#define INST_Q_WRITE 0x0200 -#define INST_CACHE_VI 0x0400 // write old vi value to s_VIBranchDelay - -// Let's tempt fate by defining two different constants with almost identical names -#define INST_DUMMY_ 0x8000 -#define INST_DUMMY 0x83c0 - -#define VFFREE_INVALID0 0x80000000 // (vffree[i]&0xf) is invalid - -#define FORIT(it, v) for(it = (v).begin(); it != (v).end(); ++(it)) - -#ifdef _DEBUG -u32 s_vucount=0; - -static u32 g_vu1lastrec = 0, skipparent = -1; -static u32 s_svulast = 0, s_vufnheader; -static u32 badaddrs[][2] = {0,0xffff}; -#endif - -union VURecRegs -{ - struct { - u16 reg; - u16 type; - }; - u32 id; -}; - -#define SUPERVU_XGKICKDELAY 1 // yes this is needed as default (wipeout) - -class VuBaseBlock; - -struct VuFunctionHeader -{ - struct RANGE - { - RANGE() : pmem(NULL) {} - - u16 start, size; - void* pmem; // all the mem - }; - - VuFunctionHeader() : pprogfunc(NULL), startpc(0xffffffff) {} - ~VuFunctionHeader() { - for(vector::iterator it = ranges.begin(); it != ranges.end(); ++it) { - free(it->pmem); - } - } - - // returns true if the checksum for the current mem is the same as this fn - bool IsSame(void* pmem); - - u32 startpc; - void* pprogfunc; - - vector ranges; -}; - -struct VuBlockHeader -{ - VuBaseBlock* pblock; - u32 delay; -}; - -// one vu inst (lower and upper) -class VuInstruction -{ -public: - VuInstruction() { memzero_obj(*this); nParentPc = -1; vicached = -1; } - - int nParentPc; // used for syncing with flag writes, -1 for no parent - - _vuopinfo info; - - _VURegsNum regs[2]; // [0] - lower, [1] - upper - u32 livevars[2]; // live variables right before this inst, [0] - inst, [1] - float - u32 addvars[2]; // live variables to add - u32 usedvars[2]; // set if var is used in the future including vars used in this inst - u32 keepvars[2]; - u16 pqcycles; // the number of cycles to stall if function writes to the regs - u16 type; // INST_ - - u32 pClipWrite, pMACWrite, pStatusWrite; // addrs to write the flags - u32 vffree[2]; - s8 vfwrite[2], vfread0[2], vfread1[2], vfacc[2]; - s8 vfflush[2]; // extra flush regs - s8 vicached; // if >= 0, then use the cached integer s_VIBranchDelay - - int SetCachedRegs(int upper, u32 vuxyz); - void Recompile(list::iterator& itinst, u32 vuxyz); -}; - -#define BLOCKTYPE_EOP 0x01 // at least one of the children of the block contains eop (or the block itself) -#define BLOCKTYPE_FUNCTION 0x02 -#define BLOCKTYPE_HASEOP 0x04 // last inst of block is an eop -#define BLOCKTYPE_MACFLAGS 0x08 -#define BLOCKTYPE_ANALYZED 0x40 -#define BLOCKTYPE_IGNORE 0x80 // special for recursive fns -#define BLOCKTYPE_ANALYZEDPARENT 0x100 - -// base block used when recompiling -class VuBaseBlock -{ -public: - typedef list LISTBLOCKS; - - VuBaseBlock(); - - // returns true if the leads to a EOP (ALL VU blocks must ret true) - void AssignVFRegs(); - void AssignVIRegs(int parent); - - list::iterator GetInstIterAtPc(int instpc); - void GetInstsAtPc(int instpc, list& listinsts); - - void Recompile(); - - u16 type; // BLOCKTYPE_ - u16 id; - u16 startpc; - u16 endpc; // first inst not in block - void* pcode; // x86 code pointer - void* pendcode; // end of the x86 code pointer - int cycles; - list insts; - list parents; - LISTBLOCKS blocks; // blocks branches to - u32* pChildJumps[4]; // addrs that need to be filled with the children's start addrs - // if highest bit is set, addr needs to be relational - u32 vuxyz; // corresponding bit is set if reg's xyz channels are used only - u32 vuxy; // corresponding bit is set if reg's xyz channels are used only - - _xmmregs startregs[XMMREGS], endregs[XMMREGS]; - int nStartx86, nEndx86; // indices into s_vecRegArray - - int allocX86Regs; - int prevFlagsOutOfBlock; -}; - -struct WRITEBACK -{ - WRITEBACK() : nParentPc(0), cycle(0) //, pStatusWrite(NULL), pMACWrite(NULL) - { - viwrite[0] = viwrite[1] = 0; - viread[0] = viread[1] = 0; - } - - void InitInst(VuInstruction* pinst, int cycle) const - { - u32 write = viwrite[0]|viwrite[1]; - pinst->type = ((write&(1<nParentPc = nParentPc; - pinst->info.cycle = cycle; - for(int i = 0; i < 2; ++i) { - pinst->regs[i].VIwrite = viwrite[i]; - pinst->regs[i].VIread = viread[i]; - } - } - - static int SortWritebacks(const WRITEBACK& w1, const WRITEBACK& w2) { - return w1.cycle < w2.cycle; - } - - int nParentPc; - int cycle; - u32 viwrite[2]; - u32 viread[2]; -}; - -struct VUPIPELINES -{ - fmacPipe fmac[8]; - fdivPipe fdiv; - efuPipe efu; - list< WRITEBACK > listWritebacks; -}; - -VuBaseBlock::VuBaseBlock() -{ - type = 0; endpc = 0; cycles = 0; pcode = NULL; id = 0; - memzero_obj(pChildJumps); - memzero_obj(startregs); - memzero_obj(endregs); - allocX86Regs = nStartx86 = nEndx86 = -1; - prevFlagsOutOfBlock = 0; -} - -#define SUPERVU_STACKSIZE 0x1000 - -static list s_listVUHeaders[2]; -static list* s_plistCachedHeaders[2] = {NULL, NULL}; -static VuFunctionHeader** recVUHeaders[2] = {NULL,NULL}; -static VuBlockHeader* recVUBlocks[2] = {NULL,NULL}; -static u8* recVUStack = NULL, *recVUStackPtr = NULL; -static vector<_x86regs> s_vecRegArray(128); - -static VURegs* VU = NULL; -static list s_listBlocks; -static u32 s_vu = 0; -static u32 s_UnconditionalDelay = 0; // 1 if there are two sequential branches and the last is unconditional -static u32 g_nLastBlockExecuted = 0; - -// Global functions -#ifdef __LINUX__ -extern "C" { -#endif -void* SuperVUGetProgram(u32 startpc, int vuindex); -void SuperVUCleanupProgram(u32 startpc, int vuindex); -#ifdef __LINUX__ -} -#endif -static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex); -static VuBaseBlock* SuperVUBuildBlocks(VuBaseBlock* parent, u32 startpc, const VUPIPELINES& pipes); -static void SuperVUInitLiveness(VuBaseBlock* pblock); -static void SuperVULivenessAnalysis(); -static void SuperVUEliminateDeadCode(); -static void SuperVUAssignRegs(); - -//void SuperVUFreeXMMreg(int xmmreg, int xmmtype, int reg); -#define SuperVUFreeXMMreg 0&& -void SuperVUFreeXMMregs(u32* livevars); - -static u32* SuperVUStaticAlloc(u32 size); -static void SuperVURecompile(); - -// allocate VU resources -void SuperVUAlloc(int vuindex) -{ - // The old -1 crap has been depreciated on this function. Please - // specify either 0 or 1, thanks. - jASSUME( vuindex >= 0 ); - - // upper 4 bits must be zero! - if( s_recVUMem == NULL ) - { - // upper 4 bits must be zero! - // Changed "first try base" to 0xb800000, since 0x0c000000 liked to fail a lot. (air) - s_recVUMem = SysMmapEx(0x0e000000, VU_EXESIZE, 0x10000000, "SuperVUAlloc"); - - if( s_recVUMem == NULL ) - { - throw Exception::OutOfMemory( - fmt_string( "SuperVU Error > failed to allocate recompiler memory (addr: 0x%x)", (u32)s_recVUMem ) - ); - } - - ProfilerRegisterSource( "VURec", s_recVUMem, VU_EXESIZE); - - if( recVUStack == NULL ) recVUStack = new u8[SUPERVU_STACKSIZE * 4]; - } - - if( vuindex >= 0 ) - { - jASSUME( s_recVUMem != NULL ); - - if( recVUHeaders[vuindex] == NULL ) - recVUHeaders[vuindex] = new VuFunctionHeader* [s_MemSize[vuindex]/8]; - if( recVUBlocks[vuindex] == NULL ) - recVUBlocks[vuindex] = new VuBlockHeader[s_MemSize[vuindex]/8]; - if( s_plistCachedHeaders[vuindex] == NULL ) - s_plistCachedHeaders[vuindex] = new list[s_MemSize[vuindex]/8]; - } -} - -// destroy VU resources -void SuperVUDestroy(int vuindex) -{ - list::iterator it; - - if( vuindex < 0 ) - { - SuperVUDestroy(0); - SuperVUDestroy(1); - ProfilerTerminateSource( "VURec" ); - SafeSysMunmap(s_recVUMem, VU_EXESIZE); - safe_delete_array( recVUStack ); - } - else - { - safe_delete_array( recVUHeaders[vuindex] ); - safe_delete_array( recVUBlocks[vuindex] ); - - if( s_plistCachedHeaders[vuindex] != NULL ) { - for(u32 j = 0; j < s_MemSize[vuindex]/8; ++j) { - FORIT(it, s_plistCachedHeaders[vuindex][j]) delete *it; - s_plistCachedHeaders[vuindex][j].clear(); - } - safe_delete_array( s_plistCachedHeaders[vuindex] ); - } - - FORIT(it, s_listVUHeaders[vuindex]) delete *it; - s_listVUHeaders[vuindex].clear(); - } -} - -// reset VU -void SuperVUReset(int vuindex) -{ -#ifdef _DEBUG - s_vucount = 0; -#endif - - if( s_recVUMem == NULL ) - return; - - //jASSUME( s_recVUMem != NULL ); - - if( vuindex < 0 ) - { - DbgCon::Status( "SuperVU reset > Resetting recompiler memory and structures." ); - - // Does this cause problems on VU recompiler resets? It could, if the VU works like - // the EE used to, and actually tries to re-enter the recBlock after issuing a clear. (air) - - //memset_8<0xcd, VU_EXESIZE>(s_recVUMem); - memzero_ptr(recVUStack); - - s_recVUPtr = s_recVUMem; - } - else - { - DbgCon::Status( "SuperVU reset [VU%d] > Resetting the recs and junk", params vuindex ); - list::iterator it; - if( recVUHeaders[vuindex] ) memset( recVUHeaders[vuindex], 0, sizeof(VuFunctionHeader*) * (s_MemSize[vuindex]/8) ); - if( recVUBlocks[vuindex] ) memset( recVUBlocks[vuindex], 0, sizeof(VuBlockHeader) * (s_MemSize[vuindex]/8) ); - - if( s_plistCachedHeaders[vuindex] != NULL ) { - for(u32 j = 0; j < s_MemSize[vuindex]/8; ++j) { - FORIT(it, s_plistCachedHeaders[vuindex][j]) delete *it; - s_plistCachedHeaders[vuindex][j].clear(); - } - } - - FORIT(it, s_listVUHeaders[vuindex]) delete *it; - s_listVUHeaders[vuindex].clear(); - } -} - -// clear the block and any joining blocks -void __fastcall SuperVUClear(u32 startpc, u32 size, int vuindex) -{ - vector::iterator itrange; - list::iterator it = s_listVUHeaders[vuindex].begin(); - u32 endpc = startpc+(size+(8-(size&7))); // Adding this code to ensure size is always a multiple of 8, it can be simplified to startpc+size if size is always a multiple of 8 (cottonvibes) - while( it != s_listVUHeaders[vuindex].end() ) { - - // for every fn, check if it has code in the range - FORIT(itrange, (*it)->ranges) { - if( startpc < (u32)itrange->start+itrange->size && itrange->start < endpc ) - break; - } - - if( itrange != (*it)->ranges.end() ) { - recVUHeaders[vuindex][(*it)->startpc/8] = NULL; -#ifdef SUPERVU_CACHING - list* plist = &s_plistCachedHeaders[vuindex][(*it)->startpc/8]; - plist->push_back(*it); - if( plist->size() > 10 ) { - // list is too big, delete - delete plist->front(); - plist->pop_front(); - } - it = s_listVUHeaders[vuindex].erase(it); -#else - delete *it; - it = s_listVUHeaders[vuindex].erase(it); -#endif - } - else ++it; - } -} - -static VuFunctionHeader* s_pFnHeader = NULL; -static VuBaseBlock* s_pCurBlock = NULL; -static VuInstruction* s_pCurInst = NULL; -static u32 s_StatusRead = 0, s_MACRead = 0, s_ClipRead = 0; // read addrs -static u32 s_PrevStatusWrite = 0, s_PrevMACWrite = 0, s_PrevClipWrite = 0, s_PrevIWrite = 0; -static u32 s_WriteToReadQ = 0; - -static u32 s_VIBranchDelay = 0; //Value of register to use in a vi branch delayed situation - - -u32 s_TotalVUCycles; // total cycles since start of program execution - - -u32 SuperVUGetVIAddr(int reg, int read) -{ - assert( s_pCurInst != NULL ); - - switch(reg) { - case REG_STATUS_FLAG: - { - u32 addr = (read==2) ? s_PrevStatusWrite : (read ? s_StatusRead : s_pCurInst->pStatusWrite); - assert(!read || addr != 0); - return addr; - } - case REG_MAC_FLAG: - { - return (read==2) ? s_PrevMACWrite : (read ? s_MACRead : s_pCurInst->pMACWrite); - } - case REG_CLIP_FLAG: - { - u32 addr = (read==2) ? s_PrevClipWrite : (read ? s_ClipRead : s_pCurInst->pClipWrite); - assert( !read || addr != 0 ); - return addr; - } - case REG_Q: return (read || s_WriteToReadQ) ? (uptr)&VU->VI[REG_Q] : (uptr)&VU->q; - case REG_P: return read ? (uptr)&VU->VI[REG_P] : (uptr)&VU->p; - case REG_I: return s_PrevIWrite; - } - -#ifdef SUPERVU_VIBRANCHDELAY - if( (read != 0) && (s_pCurInst->regs[0].pipe == VUPIPE_BRANCH) && (s_pCurInst->vicached >= 0) && (s_pCurInst->vicached == reg) ) { - return (uptr)&s_VIBranchDelay; // test for branch delays - } -#endif - - return (uptr)&VU->VI[reg]; -} - -void SuperVUDumpBlock(list& blocks, int vuindex) -{ - FILE *f; - char filename[ g_MaxPath ], str[256]; - u32 *mem; - u32 i; - -#ifdef _WIN32 - CreateDirectory("dumps", NULL); - sprintf_s( filename, g_MaxPath, "dumps\\svu%c_%.4X.txt", s_vu?'1':'0', s_pFnHeader->startpc ); -#else - mkdir("dumps", 0755); - sprintf( filename, "dumps/svu%c_%.4X.txt", s_vu?'1':'0', s_pFnHeader->startpc ); -#endif - //SysPrintf( "dump1 %x => %s\n", s_pFnHeader->startpc, filename ); - - f = fopen( filename, "w" ); - - fprintf(f, "Format: upper_inst lower_inst\ntype f:vf_live_vars vf_used_vars i:vi_live_vars vi_used_vars inst_cycle pq_inst\n"); - fprintf(f, "Type: %.2x - qread, %.2x - pread, %.2x - clip_write, %.2x - status_write\n" - "%.2x - mac_write, %.2x -qflush\n", - INST_Q_READ, INST_P_READ, INST_CLIP_WRITE, INST_STATUS_WRITE, INST_MAC_WRITE, INST_Q_WRITE); - fprintf(f, "XMM: Upper: read0 read1 write acc temp; Lower: read0 read1 write acc temp\n\n"); - - list::iterator itblock; - list::iterator itinst; - VuBaseBlock::LISTBLOCKS::iterator itchild; - - FORIT(itblock, blocks) { - fprintf(f, "block:%c %x-%x; children: ", ((*itblock)->type&BLOCKTYPE_HASEOP)?'*':' ', - (*itblock)->startpc, (*itblock)->endpc-8); - FORIT(itchild, (*itblock)->blocks) { - fprintf(f, "%x ", (*itchild)->startpc); - } - fprintf(f, "; vuxyz = %x, vuxy = %x\n", (*itblock)->vuxyz&(*itblock)->insts.front().usedvars[1], - (*itblock)->vuxy&(*itblock)->insts.front().usedvars[1]); - - itinst = (*itblock)->insts.begin(); - i = (*itblock)->startpc; - while(itinst != (*itblock)->insts.end() ) { - assert( i <= (*itblock)->endpc ); - if( itinst->type & INST_DUMMY ) { - if( itinst->nParentPc >= 0 && !(itinst->type&INST_DUMMY_)) { - // search for the parent - fprintf(f, "writeback 0x%x (%x)\n", itinst->type, itinst->nParentPc); - } - } - else { - mem = (u32*)&VU->Micro[i]; - char* pstr = disVU1MicroUF( mem[1], i+4 ); - fprintf(f, "%.4x: %-40s", i, pstr); - if( mem[1] & 0x80000000 ) fprintf(f, " I=%f(%.8x)\n", *(float*)mem, mem[0]); - else fprintf(f, "%s\n", disVU1MicroLF( mem[0], i )); - i += 8; - } - - ++itinst; - } - - fprintf(f, "\n"); - - _x86regs* pregs; - if( (*itblock)->nStartx86 >= 0 || (*itblock)->nEndx86 >= 0 ) { - fprintf(f, "X86: AX CX DX BX SP BP SI DI\n"); - } - - if( (*itblock)->nStartx86 >= 0 ) { - pregs = &s_vecRegArray[(*itblock)->nStartx86]; - fprintf(f, "STR: "); - for(i = 0; i < X86REGS; ++i) { - if( pregs[i].inuse ) fprintf(f, "%.2d ", pregs[i].reg); - else fprintf(f, "-1 "); - } - fprintf(f, "\n"); - } - - if( (*itblock)->nEndx86 >= 0 ) { - fprintf(f, "END: "); - pregs = &s_vecRegArray[(*itblock)->nEndx86]; - for(i = 0; i < X86REGS; ++i) { - if( pregs[i].inuse ) fprintf(f, "%.2d ", pregs[i].reg); - else fprintf(f, "-1 "); - } - fprintf(f, "\n"); - } - - itinst = (*itblock)->insts.begin(); - for ( i = (*itblock)->startpc; i < (*itblock)->endpc; ++itinst ) { - - if( itinst->type & INST_DUMMY ) { - } - else { - sprintf(str, "%.4x:%x f:%.8x_%.8x", i, itinst->type, itinst->livevars[1], itinst->usedvars[1]); - fprintf(f, "%-46s i:%.8x_%.8x c:%d pq:%d\n", str, - itinst->livevars[0], itinst->usedvars[0], (int)itinst->info.cycle, (int)itinst->pqcycles ); - - sprintf(str, "XMM r0:%d r1:%d w:%d a:%d t:%x;", - itinst->vfread0[1], itinst->vfread1[1], itinst->vfwrite[1], itinst->vfacc[1], itinst->vffree[1]); - fprintf(f, "%-46s r0:%d r1:%d w:%d a:%d t:%x\n", str, - itinst->vfread0[0], itinst->vfread1[0], itinst->vfwrite[0], itinst->vfacc[0], itinst->vffree[0]); - i += 8; - } - } - -#ifdef __LINUX__ - // dump the asm - if( (*itblock)->pcode != NULL ) { - char command[255]; - FILE* fasm = fopen( "mydump1", "wb" ); - //SysPrintf("writing: %x, %x\n", (*itblock)->startpc, (uptr)(*itblock)->pendcode - (uptr)(*itblock)->pcode); - fwrite( (*itblock)->pcode, 1, (uptr)(*itblock)->pendcode - (uptr)(*itblock)->pcode, fasm ); - fclose( fasm ); - sprintf( command, "objdump -D --target=binary --architecture=i386 -M intel mydump1 > tempdump"); - system( command ); - fasm = fopen("tempdump", "r"); - // read all of it and write it to f - fseek(fasm, 0, SEEK_END); - vector vbuffer(ftell(fasm)); - fseek(fasm, 0, SEEK_SET); - fread(&vbuffer[0], vbuffer.size(), 1, fasm); - - fprintf(f, "\n\n"); - fwrite(&vbuffer[0], vbuffer.size(), 1, f); - fclose(fasm); - } -#endif - - fprintf(f, "\n---------------\n"); - } - - fclose( f ); -} - -LARGE_INTEGER svubase, svufinal; -static u64 svutime; - -// uncomment to count svu exec time -//#define SUPERVU_COUNT - -// Private methods -void* SuperVUGetProgram(u32 startpc, int vuindex) -{ - assert( startpc < s_MemSize[vuindex] ); - assert( (startpc%8) == 0 ); - assert( recVUHeaders[vuindex] != NULL ); - VuFunctionHeader** pheader = &recVUHeaders[vuindex][startpc/8]; - - if( *pheader == NULL ) { -#ifdef _DEBUG -// if( vuindex ) VU1.VI[REG_TPC].UL = startpc; -// else VU0.VI[REG_TPC].UL = startpc; -// __Log("VU: %x\n", startpc); -// iDumpVU1Registers(); -// vudump |= 2; -#endif - - // measure run time - //QueryPerformanceCounter(&svubase); - -#ifdef SUPERVU_CACHING - void* pmem = (vuindex&1) ? VU1.Micro : VU0.Micro; - // check if program exists in cache - list::iterator it; - FORIT(it, s_plistCachedHeaders[vuindex][startpc/8]) { - if( (*it)->IsSame(pmem) ) { - // found, transfer to regular lists - void* pfn = (*it)->pprogfunc; - recVUHeaders[vuindex][startpc/8] = *it; - s_listVUHeaders[vuindex].push_back(*it); - s_plistCachedHeaders[vuindex][startpc/8].erase(it); - return pfn; - } - } -#endif - - *pheader = SuperVURecompileProgram(startpc, vuindex); - - if( *pheader == NULL ) { - assert( s_TotalVUCycles > 0 ); - if( vuindex ) VU1.VI[REG_TPC].UL = startpc; - else VU0.VI[REG_TPC].UL = startpc; - return (void*)SuperVUEndProgram; - } - - //QueryPerformanceCounter(&svufinal); - //svutime += (u32)(svufinal.QuadPart-svubase.QuadPart); - - assert( (*pheader)->pprogfunc != NULL ); - } - //else assert( (*pheader)->IsSame((vuindex&1) ? VU1.Micro : VU0.Micro) ); - - assert( (*pheader)->startpc == startpc ); - - return (*pheader)->pprogfunc; -} - -bool VuFunctionHeader::IsSame(void* pmem) -{ -#ifdef SUPERVU_CACHING - //u32 checksum[2]; - vector::iterator it; - FORIT(it, ranges) { - //memxor_mmx(checksum, (u8*)pmem+it->start, it->size); - //if( checksum[0] != it->checksum[0] || checksum[1] != it->checksum[1] ) - // return false; - // memcmp_mmx doesn't work on x86-64 machines -#if defined(_MSC_VER) - if( memcmp_mmx((u8*)pmem+it->start, it->pmem, it->size) ) -#else - if( memcmp((u8*)pmem+it->start, it->pmem, it->size) ) -#endif - return false; - } -#endif - return true; -} - -list::iterator VuBaseBlock::GetInstIterAtPc(int instpc) -{ - assert( instpc >= 0 ); - - u32 curpc = startpc; - list::iterator it; - for(it = insts.begin(); it != insts.end(); ++it) { - if( it->type & INST_DUMMY ) - continue; - - if( curpc == instpc ) - break; - curpc += 8; - } - - if( it != insts.end() ) - return it; - - assert( 0 ); - return insts.begin(); -} - -void VuBaseBlock::GetInstsAtPc(int instpc, list& listinsts) -{ - assert( instpc >= 0 ); - - listinsts.clear(); - - u32 curpc = startpc; - list::iterator it; - for(it = insts.begin(); it != insts.end(); ++it) { - if( it->type & INST_DUMMY ) - continue; - - if( curpc == instpc ) - break; - curpc += 8; - } - - if( it != insts.end() ) { - listinsts.push_back(&(*it)); - return; - } - - // look for the pc in other blocks - for(list::iterator itblock = s_listBlocks.begin(); itblock != s_listBlocks.end(); ++itblock) { - if( *itblock == this ) - continue; - - if( instpc >= (*itblock)->startpc && instpc < (*itblock)->endpc ) { - listinsts.push_back(&(*(*itblock)->GetInstIterAtPc(instpc))); - } - } - - assert(listinsts.size()>0); -} - -static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex) -{ - assert( vuindex < 2 ); - assert( s_recVUPtr != NULL ); - //SysPrintf("svu%c rec: %x\n", '0'+vuindex, startpc); - - // if recPtr reached the mem limit reset whole mem - if ( ( (uptr)s_recVUPtr - (uptr)s_recVUMem ) >= VU_EXESIZE-0x40000 ) { - //SysPrintf("SuperVU reset mem\n"); - SuperVUReset(0); - SuperVUReset(1); - SuperVUReset(-1); - if( s_TotalVUCycles > 0 ) { - // already executing, so return NULL - return NULL; - } - } - - list::iterator itblock; - - s_vu = vuindex; - VU = s_vu ? &VU1 : &VU0; - s_pFnHeader = new VuFunctionHeader(); - s_listVUHeaders[vuindex].push_back(s_pFnHeader); - s_pFnHeader->startpc = startpc; - - memset( recVUBlocks[s_vu], 0, sizeof(VuBlockHeader) * (s_MemSize[s_vu]/8) ); - - // analyze the global graph - s_listBlocks.clear(); - VUPIPELINES pipes; - memzero_obj(pipes.fmac); - memzero_obj(pipes.fdiv); - memzero_obj(pipes.efu); - SuperVUBuildBlocks(NULL, startpc, pipes); - - // fill parents - VuBaseBlock::LISTBLOCKS::iterator itchild; - FORIT(itblock, s_listBlocks) { - FORIT(itchild, (*itblock)->blocks) - (*itchild)->parents.push_back(*itblock); - - //(*itblock)->type &= ~(BLOCKTYPE_IGNORE|BLOCKTYPE_ANALYZED); - } - - assert( s_listBlocks.front()->startpc == startpc ); - s_listBlocks.front()->type |= BLOCKTYPE_FUNCTION; - - FORIT(itblock, s_listBlocks) { - SuperVUInitLiveness(*itblock); - } - - SuperVULivenessAnalysis(); - SuperVUEliminateDeadCode(); - SuperVUAssignRegs(); - -#ifdef _DEBUG - if( (s_vu && (vudump&1)) || (!s_vu && (vudump&16)) ) - SuperVUDumpBlock(s_listBlocks, s_vu); -#endif - - // code generation - x86SetPtr(s_recVUPtr); - branch = 0; - - SuperVURecompile(); - - s_recVUPtr = x86Ptr; - - // set the function's range - VuFunctionHeader::RANGE r; - s_pFnHeader->ranges.reserve(s_listBlocks.size()); - - FORIT(itblock, s_listBlocks) { - r.start = (*itblock)->startpc; - r.size = (*itblock)->endpc-(*itblock)->startpc; -#ifdef SUPERVU_CACHING - //memxor_mmx(r.checksum, &VU->Micro[r.start], r.size); - r.pmem = malloc(r.size); - memcpy_fast(r.pmem, &VU->Micro[r.start], r.size); -#endif - s_pFnHeader->ranges.push_back(r); - } - -#if defined(_DEBUG) && defined(__LINUX__) - // dump at the end to capture the actual code - if( (s_vu && (vudump&1)) || (!s_vu && (vudump&16)) ) - SuperVUDumpBlock(s_listBlocks, s_vu); -#endif - - // destroy - for(list::iterator itblock = s_listBlocks.begin(); itblock != s_listBlocks.end(); ++itblock) { - delete *itblock; - } - s_listBlocks.clear(); - - assert( s_recVUPtr < s_recVUMem+VU_EXESIZE ); - - return s_pFnHeader; -} - -static int _recbranchAddr(u32 vucode) { - s32 bpc = pc + (_Imm11_ << 3); -/* - if ( bpc < 0 ) { - SysPrintf("zerorec branch warning: bpc < 0 ( %x ); Using unsigned imm11\n", bpc); - bpc = pc + (_UImm11_ << 3); - }*/ - bpc &= (s_MemSize[s_vu]-1); - - return bpc; -} - -// return inst that flushes everything -static VuInstruction SuperVUFlushInst() -{ - VuInstruction inst; - // don't need to raed q/p - inst.type = INST_DUMMY_;//|INST_Q_READ|INST_P_READ; - return inst; -} - -void SuperVUAddWritebacks(VuBaseBlock* pblock, const list& listWritebacks) -{ -#ifdef SUPERVU_WRITEBACKS - // regardless of repetition, add the pipes (for selfloops) - list::const_iterator itwriteback = listWritebacks.begin(); - list::iterator itinst = pblock->insts.begin(), itinst2; - - while(itwriteback != listWritebacks.end()) { - if( itinst != pblock->insts.end() && (itinst->info.cycle < itwriteback->cycle || (itinst->type&INST_DUMMY) ) ) { - ++itinst; - continue; - } - - itinst2 = pblock->insts.insert(itinst, VuInstruction()); - itwriteback->InitInst(&(*itinst2), vucycle); - ++itwriteback; - } -#endif -} - -static VuBaseBlock* SuperVUBuildBlocks(VuBaseBlock* parent, u32 startpc, const VUPIPELINES& pipes) -{ - // check if block already exists - //SysPrintf("startpc %x\n", startpc); - startpc &= (s_vu ? 0x3fff : 0xfff); - VuBlockHeader* pbh = &recVUBlocks[s_vu][startpc/8]; - - if ( pbh->pblock != NULL ) { - - VuBaseBlock* pblock = pbh->pblock; - list::iterator itinst; - - if( pblock->startpc == startpc ) { - SuperVUAddWritebacks(pblock, pipes.listWritebacks); - return pblock; - } - - // have to divide the blocks, pnewblock is first block - assert( startpc > pblock->startpc ); - assert( startpc < pblock->endpc ); - - u32 dummyinst = (startpc-pblock->startpc)>>3; - - // count inst non-dummy insts - itinst = pblock->insts.begin(); - int cycleoff = 0; - - while(dummyinst > 0) { - if( itinst->type & INST_DUMMY ) - ++itinst; - else { - cycleoff = itinst->info.cycle; - ++itinst; - --dummyinst; - } - } - - // NOTE: still leaves insts with their writebacks in different blocks - while( itinst->type & INST_DUMMY ) - ++itinst; - - // the difference in cycles between dummy insts (naruto utlimate ninja) - int cyclediff = 0; - if( parent == pblock ) - cyclediff = itinst->info.cycle-cycleoff; - cycleoff = itinst->info.cycle; - - // new block - VuBaseBlock* pnewblock = new VuBaseBlock(); - s_listBlocks.push_back(pnewblock); - - pnewblock->startpc = startpc; - pnewblock->endpc = pblock->endpc; - pnewblock->cycles = pblock->cycles-cycleoff+cyclediff; - - pnewblock->blocks.splice(pnewblock->blocks.end(), pblock->blocks); - pnewblock->insts.splice(pnewblock->insts.end(), pblock->insts, itinst, pblock->insts.end()); - pnewblock->type = pblock->type; - - // any writebacks in the next 3 cycles also belong to original block -// for(itinst = pnewblock->insts.begin(); itinst != pnewblock->insts.end(); ) { -// if( (itinst->type & INST_DUMMY) && itinst->nParentPc >= 0 && itinst->nParentPc < (int)startpc ) { -// -// if( !(itinst->type & INST_Q_WRITE) ) -// pblock->insts.push_back(*itinst); -// itinst = pnewblock->insts.erase(itinst); -// continue; -// } -// -// ++itinst; -// } - - pbh = &recVUBlocks[s_vu][startpc/8]; - for(u32 inst = startpc; inst < pblock->endpc; inst += 8) { - if( pbh->pblock == pblock ) - pbh->pblock = pnewblock; - ++pbh; - } - - FORIT(itinst, pnewblock->insts) - itinst->info.cycle -= cycleoff; - - SuperVUAddWritebacks(pnewblock, pipes.listWritebacks); - - // old block - pblock->blocks.push_back(pnewblock); - pblock->endpc = startpc; - pblock->cycles = cycleoff; - pblock->type &= BLOCKTYPE_MACFLAGS; - //pblock->insts.push_back(SuperVUFlushInst()); //don't need - - return pnewblock; - } - - VuBaseBlock* pblock = new VuBaseBlock(); - s_listBlocks.push_back(pblock); - - int i = 0; - branch = 0; - pc = startpc; - pblock->startpc = startpc; - - // clear stalls (might be a prob) - memcpy(VU->fmac, pipes.fmac, sizeof(pipes.fmac)); - memcpy(&VU->fdiv, &pipes.fdiv, sizeof(pipes.fdiv)); - memcpy(&VU->efu, &pipes.efu, sizeof(pipes.efu)); -// memset(VU->fmac, 0, sizeof(VU->fmac)); -// memset(&VU->fdiv, 0, sizeof(VU->fdiv)); -// memset(&VU->efu, 0, sizeof(VU->efu)); - - vucycle = 0; - - u8 macflags = 0; - - list< WRITEBACK > listWritebacks; - list< WRITEBACK >::iterator itwriteback; - list::iterator itinst; - u32 hasSecondBranch = 0; - u32 needFullStatusFlag = 0; - -#ifdef SUPERVU_WRITEBACKS - listWritebacks = pipes.listWritebacks; -#endif - - // first analysis pass for status flags - while(1) { - u32* ptr = (u32*)&VU->Micro[pc]; - pc += 8; - int prevbranch = branch; - - if( ptr[1] & 0x40000000 ) - branch = 1; - - if( !(ptr[1] & 0x80000000) ) { // not I - switch( ptr[0]>>25 ) { - case 0x24: // jr - case 0x25: // jalr - case 0x20: // B - case 0x21: // BAL - case 0x28: // IBEQ - case 0x2f: // IBGEZ - case 0x2d: // IBGTZ - case 0x2e: // IBLEZ - case 0x2c: // IBLTZ - case 0x29: // IBNE - branch = 1; - break; - - case 0x14: // fseq - case 0x17: // fsor - //needFullStatusFlag = 2; - break; - - case 0x16: // fsand - if( (ptr[0]&0xc0) ) { - // sometimes full sticky bits are needed (simple series 2000 - oane chapara) - //SysPrintf("needSticky: %x-%x\n", s_pFnHeader->startpc, startpc); - needFullStatusFlag = 2; - } - break; - } - } - - if( prevbranch ) - break; - - if( pc >= s_MemSize[s_vu] ) { - Console::Error( "inf vu0 prog %x",params startpc); - break; - } - } - - // second full pass - pc = startpc; - branch = 0; - VuInstruction* pprevinst=NULL, *ppprevinst=NULL, *pinst = NULL; - - while(1) { - - if( pc == s_MemSize[s_vu] ) { - branch |= 8; - break; - } - - if( !branch && pbh->pblock != NULL ) { - pblock->blocks.push_back(pbh->pblock); - break; - } - - int prevbranch = branch; - - if( !prevbranch ) { - pbh->pblock = pblock; - } - else assert( prevbranch || pbh->pblock == NULL); - - pblock->insts.push_back(VuInstruction()); - - ppprevinst = pprevinst; - pprevinst = pinst; - pinst = &pblock->insts.back(); - SuperVUAnalyzeOp(VU, &pinst->info, pinst->regs); - -#ifdef SUPERVU_VIBRANCHDELAY - if( pinst->regs[0].pipe == VUPIPE_BRANCH && pblock->insts.size() > 1 ) { - - if( pprevinst != NULL && pprevinst->info.cycle+1==pinst->info.cycle && - (pprevinst->regs[0].pipe == VUPIPE_IALU||pprevinst->regs[0].pipe == VUPIPE_FMAC) && ((pprevinst->regs[0].VIwrite & pinst->regs[0].VIread) & 0xffff) - && !(pprevinst->regs[0].VIread&((1<Micro[pc-16]; - - // check for the previous instruction. If that has the same register used, then have a 2 cycle delay! - // (monsterhouse has sqi vi05, sqi vi05, ibeq vi05, vi03). The ibeq should read the vi05 before the first sqi - if( ppprevinst != NULL && ppprevinst->info.cycle+2==pinst->info.cycle && (ppprevinst->regs[0].pipe == VUPIPE_FMAC||ppprevinst->regs[0].pipe == VUPIPE_IALU) && - ((ppprevinst->regs[0].VIwrite & pinst->regs[0].VIread) & 0xffff) && - ((ppprevinst->regs[0].VIwrite & pinst->regs[0].VIread) & 0xffff) == ((ppprevinst->regs[0].VIwrite & pprevinst->regs[0].VIread) & 0xffff) && - !(ppprevinst->regs[0].VIread&((1<startpc); - - // ignore if prev instruction is ILW or ILWR (xenosaga 2) - lowercode = *(int*)&VU->Micro[pc-24]; - pdelayinst = ppprevinst; - } - - - //SysPrintf("vurec: %x\n", pc); - // ignore if prev instruction is ILW or ILWR (xenosaga 2) - if( (lowercode>>25) != 4 // ILW - && !((lowercode>>25) == 0x40 && (lowercode&0x3ff)==0x3fe) ) { // ILWR - - //SysPrintf("branchdelay: %x: %x\n", s_pFnHeader->startpc, pc-8); - - // share the same register - if (CHECK_VUBRANCHHACK) pinst->type |= INST_CACHE_VI; - else pdelayinst->type |= INST_CACHE_VI; - - // find the correct register - u32 mask = pdelayinst->regs[0].VIwrite & pinst->regs[0].VIread; - for(int i = 0; i < 16; ++i) { - if( mask & (1<vicached = i; - break; - } - } - - pinst->vicached = pdelayinst->vicached; - } - } - } -#endif - - if( prevbranch ) { - if( pinst->regs[0].pipe == VUPIPE_BRANCH ) - hasSecondBranch = 1; - pinst->type |= INST_BRANCH_DELAY; - } - - // check write back - for(itwriteback = listWritebacks.begin(); itwriteback != listWritebacks.end(); ) { - if( pinst->info.cycle >= itwriteback->cycle ) { - itinst = pblock->insts.insert(--pblock->insts.end(), VuInstruction()); - itwriteback->InitInst(&(*itinst), pinst->info.cycle); - itwriteback = listWritebacks.erase(itwriteback); - } - else ++itwriteback; - } - - // add new writebacks - WRITEBACK w; - const u32 allflags = (1<regs[j].VIwrite & allflags; - - if( pinst->info.macflag & VUOP_WRITE ) w.viwrite[1] |= (1<info.statusflag & VUOP_WRITE ) w.viwrite[1] |= (1<info.macflag|pinst->info.statusflag) & VUOP_READ ) - macflags = 1; - if( pinst->regs[0].VIread & ((1<regs[1].pipe == VUPIPE_FMAC && (pinst->regs[1].VFwrite==0&&!(pinst->regs[1].VIwrite&(1<regs[0].VIread |= (1<VIwrite |= lregs->VIwrite & (1<info.statusflag&VUOP_WRITE)&&!(pinst->regs[0].VIwrite&(1<regs[j].VIread & allflags; - - if( (pinst->regs[j].VIread&(1<regs[j].VIwrite&(1<regs[j].VIread &= ~(1<regs[j].VIread&(1<regs[j].VIwrite&(1<regs[j].VIread &= ~(1<regs[j].VIwrite &= ~allflags; - } - - if( pinst->info.macflag & VUOP_READ) w.viread[1] |= 1<info.statusflag & VUOP_READ) w.viread[1] |= 1<info.cycle+4; - listWritebacks.push_back(w); - } - - if( pinst->info.q&VUOP_READ ) pinst->type |= INST_Q_READ; - if( pinst->info.p&VUOP_READ ) pinst->type |= INST_P_READ; - - if( pinst->info.q&VUOP_WRITE ) { - pinst->pqcycles = QWaitTimes[pinst->info.pqinst]+1; - - memset(&w, 0, sizeof(w)); - w.nParentPc = pc-8; - w.cycle = pinst->info.cycle+pinst->pqcycles; - w.viwrite[0] = 1<info.p&VUOP_WRITE ) - pinst->pqcycles = PWaitTimes[pinst->info.pqinst]+1; - - if( prevbranch ) { - break; - } - - // make sure there is always a branch - // sensible soccer overflows on vu0, so increase the limit... - if( (s_vu==1 && i >= 0x799) || (s_vu==0 && i >= 0x201) ) { - Console::Error("VuRec base block doesn't terminate!"); - assert(0); - break; - } - - i++; - pbh++; - } - - if( macflags ) - pblock->type |= BLOCKTYPE_MACFLAGS; - - pblock->endpc = pc; - u32 lastpc = pc; - - pblock->cycles = vucycle; - -#ifdef SUPERVU_WRITEBACKS - if( !branch || (branch&8) ) -#endif - { - // flush writebacks - if( listWritebacks.size() > 0 ) { - listWritebacks.sort(WRITEBACK::SortWritebacks); - for(itwriteback = listWritebacks.begin(); itwriteback != listWritebacks.end(); ++itwriteback) { - if( itwriteback->viwrite[0] & (1<insts.push_back(VuInstruction()); - itwriteback->InitInst(&pblock->insts.back(), vucycle); - } - - listWritebacks.clear(); - } - } - - if( !branch ) - return pblock; - - if( branch & 8 ) { - // what if also a jump? - pblock->type |= BLOCKTYPE_EOP|BLOCKTYPE_HASEOP; - - // add an instruction to flush p and q (if written) - pblock->insts.push_back(SuperVUFlushInst()); - return pblock; - } - - // it is a (cond) branch or a jump - u32 vucode = *(u32*)(VU->Micro+lastpc-16); - int bpc = _recbranchAddr(vucode)-8; - - VUPIPELINES newpipes; - memcpy(newpipes.fmac, VU->fmac, sizeof(newpipes.fmac)); - memcpy(&newpipes.fdiv, &VU->fdiv, sizeof(newpipes.fdiv)); - memcpy(&newpipes.efu, &VU->efu, sizeof(newpipes.efu)); - - for(i = 0; i < 8; ++i) newpipes.fmac[i].sCycle -= vucycle; - newpipes.fdiv.sCycle -= vucycle; - newpipes.efu.sCycle -= vucycle; - - if( listWritebacks.size() > 0 ) { - // flush all when jumping, send down the pipe when in branching - bool bFlushWritebacks = (vucode>>25)==0x24||(vucode>>25)==0x25;//||(vucode>>25)==0x20||(vucode>>25)==0x21; - - listWritebacks.sort(WRITEBACK::SortWritebacks); - for(itwriteback = listWritebacks.begin(); itwriteback != listWritebacks.end(); ++itwriteback) { - if( itwriteback->viwrite[0] & (1<cycle < vucycle || bFlushWritebacks ) { - pblock->insts.push_back(VuInstruction()); - itwriteback->InitInst(&pblock->insts.back(), vucycle); - } - else { - newpipes.listWritebacks.push_back(*itwriteback); - newpipes.listWritebacks.back().cycle -= vucycle; - } - } - } - - if( newpipes.listWritebacks.size() > 0 ) // other blocks might read the mac flags - pblock->type |= BLOCKTYPE_MACFLAGS; - - u32 firstbranch = vucode>>25; - switch(firstbranch) { - case 0x24: // jr - pblock->type |= BLOCKTYPE_EOP; // jump out of procedure, since not returning, set EOP - pblock->insts.push_back(SuperVUFlushInst()); - firstbranch = 0xff; //Non-Conditional Jump - break; - - case 0x25: // jalr - { - // linking, so will return to procedure - pblock->insts.push_back(SuperVUFlushInst()); - - VuBaseBlock* pjumpblock = SuperVUBuildBlocks(pblock, lastpc, newpipes); - - // update pblock since could have changed - pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; - assert( pblock != NULL ); - - pblock->blocks.push_back(pjumpblock); - firstbranch = 0xff; //Non-Conditional Jump - break; - } - case 0x20: // B - { - VuBaseBlock* pbranchblock = SuperVUBuildBlocks(pblock, bpc, newpipes); - - // update pblock since could have changed - pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; - assert( pblock != NULL ); - - pblock->blocks.push_back(pbranchblock); - firstbranch = 0xff; //Non-Conditional Jump - break; - } - case 0x21: // BAL - { - VuBaseBlock* pbranchblock = SuperVUBuildBlocks(pblock, bpc, newpipes); - - // update pblock since could have changed - pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; - assert( pblock != NULL ); - pblock->blocks.push_back(pbranchblock); - firstbranch = 0xff; //Non-Conditional Jump - break; - } - case 0x28: // IBEQ - case 0x2f: // IBGEZ - case 0x2d: // IBGTZ - case 0x2e: // IBLEZ - case 0x2c: // IBLTZ - case 0x29: // IBNE - { - VuBaseBlock* pbranchblock = SuperVUBuildBlocks(pblock, bpc, newpipes); - - // update pblock since could have changed - pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; - assert( pblock != NULL ); - pblock->blocks.push_back(pbranchblock); - - // if has a second branch that is B or BAL, skip this - u32 secondbranch = (*(u32*)(VU->Micro+lastpc-8))>>25; - if( !hasSecondBranch || (secondbranch != 0x21 && secondbranch != 0x20) ) { - pbranchblock = SuperVUBuildBlocks(pblock, lastpc, newpipes); - - pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; - pblock->blocks.push_back(pbranchblock); - } - - break; - } - default: - assert(pblock->blocks.size() == 1); - break; - } - - pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; - -#ifdef SUPERVU_VIBRANCHDELAY -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///// NOTE! This could still be a hack for KH2/GoW, but until we know how it properly works, this will do for now./// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - if( hasSecondBranch && firstbranch != 0xff ) { //check the previous jump was conditional and there is a second branch -#else - if( hasSecondBranch) { -#endif - - u32 vucode = *(u32*)(VU->Micro+lastpc-8); - pc = lastpc; - int bpc = _recbranchAddr(vucode); - - switch(vucode>>25) { - case 0x24: // jr - Console::Error("svurec bad jr jump!"); - assert(0); - break; - - case 0x25: // jalr - { - Console::Error("svurec bad jalr jump!"); - assert(0); - break; - } - case 0x20: // B - { - VuBaseBlock* pbranchblock = SuperVUBuildBlocks(pblock, bpc, newpipes); - - // update pblock since could have changed - pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; - - pblock->blocks.push_back(pbranchblock); - break; - } - case 0x21: // BAL - { - VuBaseBlock* pbranchblock = SuperVUBuildBlocks(pblock, bpc, newpipes); - - // replace instead of pushing a new block - pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; - pblock->blocks.push_back(pbranchblock); - break; - } - case 0x28: // IBEQ - case 0x2f: // IBGEZ - case 0x2d: // IBGTZ - case 0x2e: // IBLEZ - case 0x2c: // IBLTZ - case 0x29: // IBNE - { - VuBaseBlock* pbranchblock = SuperVUBuildBlocks(pblock, bpc, newpipes); - - // update pblock since could have changed - pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; - pblock->blocks.push_back(pbranchblock); - - // only add the block if the previous branch doesn't include the next instruction (ie, if a direct jump) - if( firstbranch == 0x24 || firstbranch == 0x25 || firstbranch == 0x20 || firstbranch == 0x21 ) { - pbranchblock = SuperVUBuildBlocks(pblock, lastpc, newpipes); - - pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; - pblock->blocks.push_back(pbranchblock); - } - - break; - } - - jNO_DEFAULT; - } - } - - return recVUBlocks[s_vu][startpc/8].pblock; -} - -static void SuperVUInitLiveness(VuBaseBlock* pblock) -{ - list::iterator itinst, itnext; - - assert( pblock->insts.size() > 0 ); - - for(itinst = pblock->insts.begin(); itinst != pblock->insts.end(); ++itinst) { - - if( itinst->type & INST_DUMMY_ ) { - itinst->addvars[0] = itinst->addvars[1] = 0xffffffff; - itinst->livevars[0] = itinst->livevars[1] = 0xffffffff; - itinst->keepvars[0] = itinst->keepvars[1] = 0xffffffff; - itinst->usedvars[0] = itinst->usedvars[1] = 0; - } - else { - itinst->addvars[0] = itinst->regs[0].VIread | itinst->regs[1].VIread; - itinst->addvars[1] = (itinst->regs[0].VFread0 ? (1 << itinst->regs[0].VFread0) : 0) | - (itinst->regs[0].VFread1 ? (1 << itinst->regs[0].VFread1) : 0) | - (itinst->regs[1].VFread0 ? (1 << itinst->regs[1].VFread0) : 0) | - (itinst->regs[1].VFread1 ? (1 << itinst->regs[1].VFread1) : 0); - - // vf0 is not handled by VFread - if( !itinst->regs[0].VFread0 && (itinst->regs[0].VIread & (1<addvars[1] |= 1; - if( !itinst->regs[1].VFread0 && (itinst->regs[1].VIread & (1<addvars[1] |= 1; - if( !itinst->regs[0].VFread1 && (itinst->regs[0].VIread & (1<regs[0].VFr1xyzw != 0xff ) itinst->addvars[1] |= 1; - if( !itinst->regs[1].VFread1 && (itinst->regs[1].VIread & (1<regs[1].VFr1xyzw != 0xff ) itinst->addvars[1] |= 1; - - - u32 vfwrite = 0; - if( itinst->regs[0].VFwrite != 0 ) { - if( itinst->regs[0].VFwxyzw != 0xf ) itinst->addvars[1] |= 1<regs[0].VFwrite; - else vfwrite |= 1<regs[0].VFwrite; - } - if( itinst->regs[1].VFwrite != 0 ) { - if( itinst->regs[1].VFwxyzw != 0xf ) itinst->addvars[1] |= 1<regs[1].VFwrite; - else vfwrite |= 1<regs[1].VFwrite; - } - if( (itinst->regs[1].VIwrite & (1<regs[1].VFwxyzw != 0xf ) - itinst->addvars[1] |= 1<regs[0].VIwrite|itinst->regs[1].VIwrite); - - itinst->usedvars[0] = itinst->addvars[0]|viwrite; - itinst->usedvars[1] = itinst->addvars[1]|vfwrite; - -// itinst->addvars[0] &= ~viwrite; -// itinst->addvars[1] &= ~vfwrite; - itinst->keepvars[0] = ~viwrite; - itinst->keepvars[1] = ~vfwrite; - } - } - - itinst = --pblock->insts.end(); - while( itinst != pblock->insts.begin() ) { - itnext = itinst; --itnext; - - itnext->usedvars[0] |= itinst->usedvars[0]; - itnext->usedvars[1] |= itinst->usedvars[1]; - - itinst = itnext; - } -} - -u32 COMPUTE_LIVE(u32 R, u32 K, u32 L) -{ - u32 live = R | ((L)&(K)); - // special process mac and status flags - // only propagate liveness if doesn't write to the flag - if( !(L&(1<::reverse_iterator itblock; - list::iterator itinst, itnext; - VuBaseBlock::LISTBLOCKS::iterator itchild; - - u32 livevars[2]; - - do { - changed = FALSE; - for(itblock = s_listBlocks.rbegin(); itblock != s_listBlocks.rend(); ++itblock) { - - u32 newlive; - VuBaseBlock* pb = *itblock; - - // the last inst relies on the neighbor's insts - itinst = --pb->insts.end(); - - if( pb->blocks.size() > 0 ) { - livevars[0] = 0; livevars[1] = 0; - for( itchild = pb->blocks.begin(); itchild != pb->blocks.end(); ++itchild) { - VuInstruction& front = (*itchild)->insts.front(); - livevars[0] |= front.livevars[0]; - livevars[1] |= front.livevars[1]; - } - - newlive = COMPUTE_LIVE(itinst->addvars[0], itinst->keepvars[0], livevars[0]); - - // should propagate status flags whose parent insts are not in this block -// if( itinst->nParentPc >= 0 && (itinst->type & (INST_STATUS_WRITE|INST_MAC_WRITE)) ) -// newlive |= livevars[0]&((1<livevars[0] != newlive ) { - changed = TRUE; - itinst->livevars[0] = newlive; - } - - newlive = COMPUTE_LIVE(itinst->addvars[1], itinst->keepvars[1], livevars[1]); - if( itinst->livevars[1] != newlive ) { - changed = TRUE; - itinst->livevars[1] = newlive; - } - } - - while( itinst != pb->insts.begin() ) { - - itnext = itinst; --itnext; - - newlive = COMPUTE_LIVE(itnext->addvars[0], itnext->keepvars[0], itinst->livevars[0]); - - // should propagate status flags whose parent insts are not in this block -// if( itnext->nParentPc >= 0 && (itnext->type & (INST_STATUS_WRITE|INST_MAC_WRITE)) && !(itinst->type & (INST_STATUS_WRITE|INST_MAC_WRITE)) ) -// newlive |= itinst->livevars[0]&((1<livevars[0] != newlive ) { - changed = TRUE; - itnext->livevars[0] = newlive; - itnext->livevars[1] = COMPUTE_LIVE(itnext->addvars[1], itnext->keepvars[1], itinst->livevars[1]); - } - else { - newlive = COMPUTE_LIVE(itnext->addvars[1], itnext->keepvars[1], itinst->livevars[1]); - if( itnext->livevars[1] != newlive ) { - changed = TRUE; - itnext->livevars[1] = newlive; - } - } - - itinst = itnext; - } - -// if( (livevars[0] | itinst->livevars[0]) != itinst->livevars[0] ) { -// changed = TRUE; -// itinst->livevars[0] |= livevars[0]; -// } -// if( (livevars[1] | itinst->livevars[1]) != itinst->livevars[1] ) { -// changed = TRUE; -// itinst->livevars[1] |= livevars[1]; -// } -// -// while( itinst != pb->insts.begin() ) { -// -// itnext = itinst; --itnext; -// if( (itnext->livevars[0] | (itinst->livevars[0] & itnext->keepvars[0])) != itnext->livevars[0] ) { -// changed = TRUE; -// itnext->livevars[0] |= itinst->livevars[0] & itnext->keepvars[0]; -// itnext->livevars[1] |= itinst->livevars[1] & itnext->keepvars[1]; -// } -// else if( (itnext->livevars[1] | (itinst->livevars[1] & itnext->keepvars[1])) != itnext->livevars[1] ) { -// changed = TRUE; -// itnext->livevars[1] |= itinst->livevars[1] & itnext->keepvars[1]; -// } -// -// itinst = itnext; -// } - } - - } while(changed); -} - -static void SuperVUEliminateDeadCode() -{ - list::iterator itblock; - VuBaseBlock::LISTBLOCKS::iterator itchild; - list::iterator itinst, itnext; - list listParents; - list::iterator itparent; - - FORIT(itblock, s_listBlocks) { - -#ifdef _DEBUG - u32 startpc = (*itblock)->startpc; - u32 curpc = startpc; -#endif - - itnext = (*itblock)->insts.begin(); - itinst = itnext++; - while(itnext != (*itblock)->insts.end() ) { - if( itinst->type & (INST_CLIP_WRITE|INST_MAC_WRITE|INST_STATUS_WRITE) ) { - u32 live0 = itnext->livevars[0]; - if( itinst->nParentPc >= 0 && itnext->nParentPc >= 0 && itinst->nParentPc != itnext->nParentPc ) { // superman returns - // take the live vars from the next next inst - list::iterator itnextnext = itnext; ++itnextnext; - if( itnextnext != (*itblock)->insts.end() ) { - live0 = itnextnext->livevars[0]; - } - } - - itinst->regs[0].VIwrite &= live0; - itinst->regs[1].VIwrite &= live0; - - u32 viwrite = itinst->regs[0].VIwrite|itinst->regs[1].VIwrite; - - (*itblock)->GetInstsAtPc(itinst->nParentPc, listParents); - int removetype = 0; - - FORIT(itparent, listParents) { - VuInstruction* parent = *itparent; - - if( viwrite & (1<regs[0].VIwrite |= (itinst->regs[0].VIwrite&(1<regs[1].VIwrite |= (itinst->regs[1].VIwrite&(1<info.macflag && (itinst->type & INST_MAC_WRITE) ) { - if( !(viwrite&(1<info.macflag = 0; - // parent->regs[0].VIwrite &= ~(1<regs[1].VIwrite &= ~(1<regs[0].VIwrite & (1<regs[1].VIwrite & (1<regs[1].pipe == VUPIPE_FMAC && (parent->regs[1].VFwrite == 0&&!(parent->regs[1].VIwrite&(1<regs[0].VIwrite |= ((1<regs[1].VIwrite |= ((1<regs[0].VIwrite |= (itinst->regs[0].VIwrite&(1<regs[1].VIwrite |= (itinst->regs[1].VIwrite&(1<info.statusflag && (itinst->type & INST_STATUS_WRITE)) { - if( !(viwrite&(1<info.statusflag = 0; - // parent->regs[0].VIwrite &= ~(1<regs[1].VIwrite &= ~(1<regs[0].VIwrite & (1<regs[1].VIwrite & (1<regs[1].pipe == VUPIPE_FMAC && (parent->regs[1].VFwrite == 0&&!(parent->regs[1].VIwrite&(1<regs[0].VIwrite |= ((1<regs[1].VIwrite |= ((1<regs[0].VIwrite |= (itinst->regs[0].VIwrite&(1<regs[1].VIwrite |= (itinst->regs[1].VIwrite&(1<type &= ~removetype; - if( itinst->type == 0 ) { - itnext = (*itblock)->insts.erase(itinst); - itinst = itnext++; - continue; - } - } -#ifdef _DEBUG - else curpc += 8; -#endif - itinst = itnext; - ++itnext; - } - - if( itinst->type & INST_DUMMY ) { - // last inst with the children - u32 mask = 0; - for(itchild = (*itblock)->blocks.begin(); itchild != (*itblock)->blocks.end(); ++itchild) { - mask |= (*itchild)->insts.front().livevars[0]; - } - itinst->regs[0].VIwrite &= mask; - itinst->regs[1].VIwrite &= mask; - u32 viwrite = itinst->regs[0].VIwrite|itinst->regs[1].VIwrite; - - if( itinst->nParentPc >= 0 ) { - - (*itblock)->GetInstsAtPc(itinst->nParentPc, listParents); - int removetype = 0; - - FORIT(itparent, listParents) { - VuInstruction* parent = *itparent; - - if( viwrite & (1<regs[0].VIwrite |= (itinst->regs[0].VIwrite&(1<regs[1].VIwrite |= (itinst->regs[1].VIwrite&(1<info.macflag && (itinst->type & INST_MAC_WRITE) ) { - if( !(viwrite&(1<info.macflag = 0; -#ifndef SUPERVU_WRITEBACKS - assert( !(parent->regs[0].VIwrite & (1<regs[1].VIwrite & (1<regs[0].VIwrite |= (itinst->regs[0].VIwrite&(1<regs[1].VIwrite |= (itinst->regs[1].VIwrite&(1<info.statusflag && (itinst->type & INST_STATUS_WRITE)) { - if( !(viwrite&(1<info.statusflag = 0; -#ifndef SUPERVU_WRITEBACKS - assert( !(parent->regs[0].VIwrite & (1<regs[1].VIwrite & (1<regs[0].VIwrite |= (itinst->regs[0].VIwrite&(1<regs[1].VIwrite |= (itinst->regs[1].VIwrite&(1<type &= ~removetype; - if( itinst->type == 0 ) { - (*itblock)->insts.erase(itinst); - } - } - } - } -} - -void VuBaseBlock::AssignVFRegs() -{ - int i; - VuBaseBlock::LISTBLOCKS::iterator itchild; - list::iterator itblock; - list::iterator itinst, itnext, itinst2; - - // init the start regs - if( type & BLOCKTYPE_ANALYZED ) return; // nothing changed - memcpy(xmmregs, startregs, sizeof(xmmregs)); - - if( type & BLOCKTYPE_ANALYZED ) { - // check if changed - for(i = 0; i < XMMREGS; ++i) { - if( xmmregs[i].inuse != startregs[i].inuse ) - break; - if( xmmregs[i].inuse && (xmmregs[i].reg != startregs[i].reg || xmmregs[i].type != startregs[i].type) ) - break; - } - - if( i == XMMREGS ) return; // nothing changed - } - - u8* oldX86 = x86Ptr; - - FORIT(itinst, insts) { - - if( itinst->type & INST_DUMMY ) - continue; - - // reserve, go from upper to lower - int lastwrite = -1; - - for(i = 1; i >= 0; --i) { - _VURegsNum* regs = itinst->regs+i; - - // redo the counters so that the proper regs are released - for(int j = 0; j < XMMREGS; ++j) { - if( xmmregs[j].inuse ) { - if( xmmregs[j].type == XMMTYPE_VFREG ) { - int count = 0; - itinst2 = itinst; - - if( i ) { - if( itinst2->regs[0].VFread0 == xmmregs[j].reg || itinst2->regs[0].VFread1 == xmmregs[j].reg || itinst2->regs[0].VFwrite == xmmregs[j].reg ) { - itinst2 = insts.end(); - break; - } - else { - ++count; - ++itinst2; - } - } - - while(itinst2 != insts.end() ) { - if( itinst2->regs[0].VFread0 == xmmregs[j].reg || itinst2->regs[0].VFread1 == xmmregs[j].reg || itinst2->regs[0].VFwrite == xmmregs[j].reg || - itinst2->regs[1].VFread0 == xmmregs[j].reg || itinst2->regs[1].VFread1 == xmmregs[j].reg || itinst2->regs[1].VFwrite == xmmregs[j].reg) - break; - - ++count; - ++itinst2; - } - xmmregs[j].counter = 1000-count; - } - else { - assert( xmmregs[j].type == XMMTYPE_ACC ); - - int count = 0; - itinst2 = itinst; - - if( i ) ++itinst2; // acc isn't used in lower insts - - while(itinst2 != insts.end() ) { - assert( !((itinst2->regs[0].VIread|itinst2->regs[0].VIwrite) & (1<regs[1].VIread|itinst2->regs[1].VIwrite) & (1<VFread0 ) _addNeededVFtoXMMreg(regs->VFread0); - if( regs->VFread1 ) _addNeededVFtoXMMreg(regs->VFread1); - if( regs->VFwrite ) _addNeededVFtoXMMreg(regs->VFwrite); - if( regs->VIread & (1<VIread & (1<vfread0[i] = itinst->vfread1[i] = itinst->vfwrite[i] = itinst->vfacc[i] = -1; - itinst->vfflush[i] = -1; - - if( regs->VFread0 ) itinst->vfread0[i] = _allocVFtoXMMreg(VU, -1, regs->VFread0, 0); - else if( regs->VIread & (1<vfread0[i] = _allocVFtoXMMreg(VU, -1, 0, 0); - if( regs->VFread1 ) itinst->vfread1[i] = _allocVFtoXMMreg(VU, -1, regs->VFread1, 0); - else if( (regs->VIread & (1<VFr1xyzw != 0xff ) itinst->vfread1[i] = _allocVFtoXMMreg(VU, -1, 0, 0); - if( regs->VIread & (1<vfacc[i] = _allocACCtoXMMreg(VU, -1, 0); - - int reusereg = -1; // 0 - VFwrite, 1 - VFAcc - - if( regs->VFwrite ) { - assert( !(regs->VIwrite&(1<VFwxyzw == 0xf ) { - itinst->vfwrite[i] = _checkXMMreg(XMMTYPE_VFREG, regs->VFwrite, 0); - if( itinst->vfwrite[i] < 0 ) reusereg = 0; - } - else { - itinst->vfwrite[i] = _allocVFtoXMMreg(VU, -1, regs->VFwrite, 0); - } - } - else if( regs->VIwrite & (1<VFwxyzw == 0xf ) { - itinst->vfacc[i] = _checkXMMreg(XMMTYPE_ACC, 0, 0); - if( itinst->vfacc[i] < 0 ) reusereg = 1; - } - else { - itinst->vfacc[i] = _allocACCtoXMMreg(VU, -1, 0); - } - } - - if( reusereg >= 0 ) { - // reuse - itnext = itinst; itnext++; - - u8 type = reusereg ? XMMTYPE_ACC : XMMTYPE_VFREG; - u8 reg = reusereg ? 0 : regs->VFwrite; - - if( itinst->vfacc[i] >= 0 && lastwrite != itinst->vfacc[i] && - (itnext == insts.end() || ((regs->VIread&(1<usedvars[0]&(1<livevars[0]&(1<livevars[0]&(1<vfacc[i]); - xmmregs[itinst->vfacc[i]].inuse = 1; - xmmregs[itinst->vfacc[i]].reg = reg; - xmmregs[itinst->vfacc[i]].type = type; - xmmregs[itinst->vfacc[i]].mode = 0; - itinst->vfwrite[i] = itinst->vfacc[i]; - } - else if( itinst->vfread0[i] >= 0 && lastwrite != itinst->vfread0[i] && - (itnext == insts.end() || (regs->VFread0 > 0 && (!(itnext->usedvars[1]&(1<VFread0)) || !(itnext->livevars[1]&(1<VFread0))))) ) { - - if(itnext == insts.end() || (itnext->livevars[1]®s->VFread0)) _freeXMMreg(itinst->vfread0[i]); - xmmregs[itinst->vfread0[i]].inuse = 1; - xmmregs[itinst->vfread0[i]].reg = reg; - xmmregs[itinst->vfread0[i]].type = type; - xmmregs[itinst->vfread0[i]].mode = 0; - if( reusereg ) itinst->vfacc[i] = itinst->vfread0[i]; - else itinst->vfwrite[i] = itinst->vfread0[i]; - } - else if( itinst->vfread1[i] >= 0 && lastwrite != itinst->vfread1[i] && - (itnext == insts.end() || (regs->VFread1 > 0 && (!(itnext->usedvars[1]&(1<VFread1)) || !(itnext->livevars[1]&(1<VFread1))))) ) { - - if(itnext == insts.end() || (itnext->livevars[1]®s->VFread1)) _freeXMMreg(itinst->vfread1[i]); - xmmregs[itinst->vfread1[i]].inuse = 1; - xmmregs[itinst->vfread1[i]].reg = reg; - xmmregs[itinst->vfread1[i]].type = type; - xmmregs[itinst->vfread1[i]].mode = 0; - if( reusereg ) itinst->vfacc[i] = itinst->vfread1[i]; - else itinst->vfwrite[i] = itinst->vfread1[i]; - } - else { - if( reusereg ) itinst->vfacc[i] = _allocACCtoXMMreg(VU, -1, 0); - else itinst->vfwrite[i] = _allocVFtoXMMreg(VU, -1, regs->VFwrite, 0); - } - } - - if( itinst->vfwrite[i] >= 0 ) lastwrite = itinst->vfwrite[i]; - else if( itinst->vfacc[i] >= 0 ) lastwrite = itinst->vfacc[i]; - - // always alloc at least 1 temp reg - int free0 = (i||regs->VFwrite||regs->VFread0||regs->VFread1||(regs->VIwrite&(1<vfwrite[1] >= 0 && (itinst->vfread0[0]==itinst->vfwrite[1]||itinst->vfread1[0]==itinst->vfwrite[1]) ) { - itinst->vfflush[i] = _allocTempXMMreg(XMMT_FPS, -1); - } - - if( i == 1 && (regs->VIwrite & (1<VIwrite & (1<vfflush[i] >= 0 ) _freeXMMreg(itinst->vfflush[i]); - if( free0 >= 0 ) _freeXMMreg(free0); - - itinst->vffree[i] = (free0&0xf)|(free1<<8)|(free2<<16); - if( free0 == -1 ) itinst->vffree[i] |= VFFREE_INVALID0; - - _clearNeededXMMregs(); - } - } - - assert( x86Ptr == oldX86 ); - u32 analyzechildren = !(type&BLOCKTYPE_ANALYZED); - type |= BLOCKTYPE_ANALYZED; - - //memset(endregs, 0, sizeof(endregs)); - - if( analyzechildren ) { - FORIT(itchild, blocks) (*itchild)->AssignVFRegs(); - } -} - -struct MARKOVBLANKET -{ - list parents; - list children; -}; - -static MARKOVBLANKET s_markov; - -void VuBaseBlock::AssignVIRegs(int parent) -{ - const int maxregs = 6; - - if( parent ) { - if( (type&BLOCKTYPE_ANALYZEDPARENT) ) - return; - - type |= BLOCKTYPE_ANALYZEDPARENT; - s_markov.parents.push_back(this); - for(LISTBLOCKS::iterator it = blocks.begin(); it != blocks.end(); ++it) { - (*it)->AssignVIRegs(0); - } - return; - } - - if( (type&BLOCKTYPE_ANALYZED) ) - return; - - // child - assert( allocX86Regs == -1 ); - allocX86Regs = s_vecRegArray.size(); - s_vecRegArray.resize(allocX86Regs+X86REGS); - - _x86regs* pregs = &s_vecRegArray[allocX86Regs]; - memset(pregs, 0, sizeof(_x86regs)*X86REGS); - - assert( parents.size() > 0 ); - - list::iterator itparent; - u32 usedvars = insts.front().usedvars[0]; - u32 livevars = insts.front().livevars[0]; - - if( parents.size() > 0 ) { - u32 usedvars2 = 0xffffffff; - FORIT(itparent, parents) usedvars2 &= (*itparent)->insts.front().usedvars[0]; - usedvars |= usedvars2; - } - - usedvars &= livevars; - - // currently order doesn't matter - int num = 0; - - if( usedvars ) { - for(int i = 1; i < 16; ++i) { - if( usedvars & (1<= maxregs ) break; - } - } - } - - if( num < maxregs) { - livevars &= ~usedvars; - livevars &= insts.back().usedvars[0]; - - if( livevars ) { - for(int i = 1; i < 16; ++i) { - if( livevars & (1<= maxregs) break; - } - } - } - } - - s_markov.children.push_back(this); - type |= BLOCKTYPE_ANALYZED; - FORIT(itparent, parents) { - (*itparent)->AssignVIRegs(1); - } -} - -static void SuperVUAssignRegs() -{ - list::iterator itblock, itblock2; - - FORIT(itblock, s_listBlocks) (*itblock)->type &= ~BLOCKTYPE_ANALYZED; - s_listBlocks.front()->AssignVFRegs(); - - // VI assignments, find markov blanket for each node in the graph - // then allocate regs based on the commonly used ones -#ifdef SUPERVU_X86CACHING - FORIT(itblock, s_listBlocks) (*itblock)->type &= ~(BLOCKTYPE_ANALYZED|BLOCKTYPE_ANALYZEDPARENT); - s_vecRegArray.resize(0); - u8 usedregs[16]; - - // note: first block always has to start with no alloc regs - bool bfirst = true; - - FORIT(itblock, s_listBlocks) { - - if( !((*itblock)->type & BLOCKTYPE_ANALYZED) ) { - - if( (*itblock)->parents.size() == 0 ) { - (*itblock)->type |= BLOCKTYPE_ANALYZED; - bfirst = false; - continue; - } - - s_markov.children.clear(); - s_markov.parents.clear(); - (*itblock)->AssignVIRegs(0); - - // assign the regs - int regid = s_vecRegArray.size(); - s_vecRegArray.resize(regid+X86REGS); - - _x86regs* mergedx86 = &s_vecRegArray[regid]; - memset(mergedx86, 0, sizeof(_x86regs)*X86REGS); - - if( !bfirst ) { - *(u32*)usedregs = *((u32*)usedregs+1) = *((u32*)usedregs+2) = *((u32*)usedregs+3) = 0; - - FORIT(itblock2, s_markov.children) { - assert( (*itblock2)->allocX86Regs >= 0 ); - _x86regs* pregs = &s_vecRegArray[(*itblock2)->allocX86Regs]; - for(int i = 0; i < X86REGS; ++i) { - if( pregs[i].inuse && pregs[i].reg < 16) { - //assert( pregs[i].reg < 16); - usedregs[pregs[i].reg]++; - } - } - } - - int num = 1; - for(int i = 0; i < 16; ++i) { - if( usedregs[i] == s_markov.children.size() ) { - // use - mergedx86[num].inuse = 1; - mergedx86[num].reg = i; - mergedx86[num].type = (s_vu?X86TYPE_VU1:0)|X86TYPE_VI; - mergedx86[num].mode = MODE_READ; - if( ++num >= X86REGS ) - break; - if( num == ESP ) - ++num; - } - } - - FORIT(itblock2, s_markov.children) { - assert( (*itblock2)->nStartx86 == -1 ); - (*itblock2)->nStartx86 = regid; - } - - FORIT(itblock2, s_markov.parents) { - assert( (*itblock2)->nEndx86 == -1 ); - (*itblock2)->nEndx86 = regid; - } - } - - bfirst = false; - } - } -#endif -} - -////////////////// -// Recompilation -////////////////// - -// cycles in which the last Q,P regs were finished (written to VU->VI[]) -// the write occurs before the instruction is executed at that cycle -// compare with s_TotalVUCycles -// if less than 0, already flushed -int s_writeQ, s_writeP; - -// declare the saved registers -uptr s_vu1esp, s_callstack;//, s_vu1esp -uptr s_vu1ebp, s_vuebx, s_vuedi, s_vu1esi; - -static int s_recWriteQ, s_recWriteP; // wait times during recompilation -static int s_needFlush; // first bit - Q, second bit - P, third bit - Q has been written, fourth bit - P has been written - -static int s_JumpX86; -static int s_ScheduleXGKICK = 0, s_XGKICKReg = -1; - -void recVUMI_XGKICK_( VURegs *VU ); - -void SuperVUCleanupProgram(u32 startpc, int vuindex) -{ -#ifdef SUPERVU_COUNT - QueryPerformanceCounter(&svufinal); - svutime += (u32)(svufinal.QuadPart-svubase.QuadPart); -#endif - - assert( s_vu1esp == 0 ); - - VU = vuindex ? &VU1 : &VU0; - VU->cycle += s_TotalVUCycles; - if( (int)s_writeQ > 0 ) VU->VI[REG_Q] = VU->q; - if( (int)s_writeP > 0 ) { - assert(VU == &VU1); - VU1.VI[REG_P] = VU1.p; // only VU1 - } - - //memset(recVUStack, 0, SUPERVU_STACKSIZE * 4); - - // Clear allocation info to prevent bad data being used in other parts of pcsx2; doing this just incase (cottonvibes) - _initXMMregs(); - _initMMXregs(); - _initX86regs(); -} - -#if defined(_MSC_VER) - -// entry point of all vu programs from emulator calls -__declspec(naked) void SuperVUExecuteProgram(u32 startpc, int vuindex) -{ -#ifdef SUPERVU_COUNT - QueryPerformanceCounter(&svubase); -#endif - __asm { - mov eax, dword ptr [esp] - mov s_TotalVUCycles, 0 // necessary to be here! - add esp, 4 - mov s_callstack, eax - call SuperVUGetProgram - - // save cpu state - mov s_vu1ebp, ebp - mov s_vu1esi, esi // have to save even in Release - mov s_vuedi, edi // have to save even in Release - mov s_vuebx, ebx - } -#ifdef _DEBUG - __asm { - mov s_vu1esp, esp - } -#endif - - __asm { - //stmxcsr s_ssecsr - ldmxcsr g_sseVUMXCSR - - // init vars - mov s_writeQ, 0xffffffff - mov s_writeP, 0xffffffff - - jmp eax - } -} - -// exit point of all vu programs -__declspec(naked) static void SuperVUEndProgram() -{ - __asm { - // restore cpu state - ldmxcsr g_sseMXCSR - - mov ebp, s_vu1ebp - mov esi, s_vu1esi - mov edi, s_vuedi - mov ebx, s_vuebx - } - -#ifdef _DEBUG - __asm { - sub s_vu1esp, esp - } -#endif - - __asm { - call SuperVUCleanupProgram - jmp s_callstack // so returns correctly - } -} - -#endif - -// Flushes P/Q regs -void SuperVUFlush(int p, int wait) -{ - u8* pjmp[3]; - if( !(s_needFlush&(1<info.cycle < recwait ) return; - - if( recwait == 0 ) { - // write didn't happen this block - MOV32MtoR(EAX, p ? (uptr)&s_writeP : (uptr)&s_writeQ); - OR32RtoR(EAX, EAX); - pjmp[0] = JS8(0); - - if( s_pCurInst->info.cycle ) SUB32ItoR(EAX, s_pCurInst->info.cycle); - - // if writeQ <= total+offset - if( !wait ) { // only write back if time is up - CMP32MtoR(EAX, (uptr)&s_TotalVUCycles); - pjmp[1] = JG8(0); - } - else { - // add (writeQ-total-offset) to s_TotalVUCycles - // necessary? - CMP32MtoR(EAX, (uptr)&s_TotalVUCycles); - pjmp[2] = JLE8(0); - MOV32RtoM((uptr)&s_TotalVUCycles, EAX); - x86SetJ8(pjmp[2]); - } - } - else if( wait && s_pCurInst->info.cycle < recwait ) { - ADD32ItoM((uptr)&s_TotalVUCycles, recwait); - } - - MOV32MtoR(EAX, SuperVUGetVIAddr(p?REG_P:REG_Q, 0)); - MOV32ItoM(p ? (uptr)&s_writeP : (uptr)&s_writeQ, 0x80000000); - MOV32RtoM(SuperVUGetVIAddr(p?REG_P:REG_Q, 1), EAX); - - if( recwait == 0 ) { - if( !wait ) x86SetJ8(pjmp[1]); - x86SetJ8(pjmp[0]); - } - - if( wait || (!p && recwait == 0 && s_pCurInst->info.cycle >= 12) || (!p && recwait > 0 && s_pCurInst->info.cycle >= recwait ) ) - s_needFlush &= ~(1<::iterator itblock; - - FORIT(itblock, s_listBlocks) (*itblock)->type &= ~BLOCKTYPE_ANALYZED; - s_listBlocks.front()->Recompile(); - // make sure everything compiled - FORIT(itblock, s_listBlocks) assert( ((*itblock)->type & BLOCKTYPE_ANALYZED) && (*itblock)->pcode != NULL ); - - // link all blocks - FORIT(itblock, s_listBlocks) { - VuBaseBlock::LISTBLOCKS::iterator itchild; - - assert( (*itblock)->blocks.size() <= ARRAYSIZE((*itblock)->pChildJumps) ); - - int i = 0; - FORIT(itchild, (*itblock)->blocks) { - - if( (u32)(uptr)(*itblock)->pChildJumps[i] == 0xffffffff ) - continue; - - if( (*itblock)->pChildJumps[i] == NULL ) { - VuBaseBlock* pchild = *itchild; - - if( pchild->type & BLOCKTYPE_HASEOP) { - assert( pchild->blocks.size() == 0); - - AND32ItoM( (uptr)&VU0.VI[ REG_VPU_STAT ].UL, s_vu?~0x100:~0x001 ); // E flag - AND32ItoM( (uptr)&VU->vifRegs->stat, ~0x4 ); - - MOV32ItoM((uptr)&VU->VI[REG_TPC], pchild->endpc); - JMP32( (uptr)SuperVUEndProgram - ( (uptr)x86Ptr + 5 )); - } - // only other case is when there are two branches - else assert( (*itblock)->insts.back().regs[0].pipe == VUPIPE_BRANCH ); - - continue; - } - - if( (u32)(uptr)(*itblock)->pChildJumps[i] & 0x80000000 ) { - // relative - assert( (uptr)(*itblock)->pChildJumps[i] <= 0xffffffff); - (*itblock)->pChildJumps[i] = (u32*)((uptr)(*itblock)->pChildJumps[i] & 0x7fffffff); - *(*itblock)->pChildJumps[i] = (uptr)(*itchild)->pcode - ((uptr)(*itblock)->pChildJumps[i] + 4); - } - else *(*itblock)->pChildJumps[i] = (uptr)(*itchild)->pcode; - - ++i; - } - } - - s_pFnHeader->pprogfunc = s_listBlocks.front()->pcode; -} - -// debug - - -u32 s_saveecx, s_saveedx, s_saveebx, s_saveesi, s_saveedi, s_saveebp; -u32 g_curdebugvu; - -//float vuDouble(u32 f); - -#if defined(_MSC_VER) -__declspec(naked) static void svudispfn() -{ - __asm { - mov g_curdebugvu, eax - mov s_saveecx, ecx - mov s_saveedx, edx - mov s_saveebx, ebx - mov s_saveesi, esi - mov s_saveedi, edi - mov s_saveebp, ebp - } -#else -#ifdef __LINUX__ -extern "C" { -#endif -void svudispfn(); -#ifdef __LINUX__ -} -#endif - -void svudispfntemp() -{ -#endif - -#ifdef _DEBUG - static u32 i; - - if( ((vudump&8) && g_curdebugvu) || ((vudump&0x80) && !g_curdebugvu) ) { //&& g_vu1lastrec != g_vu1last ) { - - if( skipparent != g_vu1lastrec ) { - for(i = 0; i < ARRAYSIZE(badaddrs); ++i) { - if( s_svulast == badaddrs[i][1] && g_vu1lastrec == badaddrs[i][0] ) - break; - } - - if( i == ARRAYSIZE(badaddrs) ) - { - //static int curesp; - //__asm mov curesp, esp - //Console::WriteLn("tVU: %x %x %x", s_svulast, s_vucount, s_vufnheader); - if( g_curdebugvu ) iDumpVU1Registers(); - else iDumpVU0Registers(); - s_vucount++; - } - } - - g_vu1lastrec = s_svulast; - } -#endif - -#if defined(_MSC_VER) - __asm { - mov ecx, s_saveecx - mov edx, s_saveedx - mov ebx, s_saveebx - mov esi, s_saveesi - mov edi, s_saveedi - mov ebp, s_saveebp - ret - } -#endif -} - -// frees all regs taking into account the livevars -void SuperVUFreeXMMregs(u32* livevars) -{ - for(int i = 0; i < XMMREGS; ++i) { - if( xmmregs[i].inuse ) { - // same reg - if( (xmmregs[i].mode & MODE_WRITE) ) { - -#ifdef SUPERVU_INTERCACHING - if( xmmregs[i].type == XMMTYPE_VFREG ) { - if( !(livevars[1] & (1<VF[xmmregs[i].reg] : (uptr)&VU->ACC; - - if( xmmregs[i].mode & MODE_VUZ ) { - SSE_MOVHPS_XMM_to_M64(addr, (x86SSERegType)i); - SSE_SHUFPS_M128_to_XMM((x86SSERegType)i, addr, 0xc4); - } - else SSE_MOVHPS_M64_to_XMM((x86SSERegType)i, addr+8); - - xmmregs[i].mode &= ~MODE_VUXYZ; - } - - _freeXMMreg(i); - } - } - } - - //_freeXMMregs(); -} - -void SuperVUTestVU0Condition(u32 incstack) -{ - if( s_vu && !SUPERVU_CHECKCONDITION ) return; // vu0 only - - CMP32ItoM((uptr)&s_TotalVUCycles, 512); // sometimes games spin on vu0, so be careful with this value - // woody hangs if too high - - if( incstack ) { - u8* ptr = JB8(0); - - ADD32ItoR(ESP, incstack); - //CALLFunc((u32)timeout); - JMP32( (uptr)SuperVUEndProgram - ( (uptr)x86Ptr + 5 )); - - x86SetJ8(ptr); - } - else JAE32( (uptr)SuperVUEndProgram - ( (uptr)x86Ptr + 6 ) ); -} - -void VuBaseBlock::Recompile() -{ - if( type & BLOCKTYPE_ANALYZED ) return; - - x86Align(16); - pcode = x86Ptr; - -#ifdef _DEBUG - MOV32ItoM((uptr)&s_vufnheader, s_pFnHeader->startpc); - MOV32ItoM((uptr)&VU->VI[REG_TPC], startpc); - MOV32ItoM((uptr)&s_svulast, startpc); - list::iterator itparent; - for(itparent = parents.begin(); itparent != parents.end(); ++itparent) { - if( (*itparent)->blocks.size()==1 && (*itparent)->blocks.front()->startpc == startpc && - ((*itparent)->insts.size() < 2 || (----(*itparent)->insts.end())->regs[0].pipe != VUPIPE_BRANCH) ) { - MOV32ItoM((uptr)&skipparent, (*itparent)->startpc); - break; - } - } - - if( itparent == parents.end() ) MOV32ItoM((uptr)&skipparent, -1); - - MOV32ItoR(EAX, s_vu); - CALLFunc((uptr)svudispfn); -#endif - - s_pCurBlock = this; - s_needFlush = 3; - pc = startpc; - branch = 0; - s_recWriteQ = s_recWriteP = 0; - s_XGKICKReg = -1; - s_ScheduleXGKICK = 0; - - s_ClipRead = s_PrevClipWrite = (uptr)&VU->VI[REG_CLIP_FLAG]; - s_StatusRead = s_PrevStatusWrite = (uptr)&VU->VI[REG_STATUS_FLAG]; - s_MACRead = s_PrevMACWrite = (uptr)&VU->VI[REG_MAC_FLAG]; - s_PrevIWrite = (uptr)&VU->VI[REG_I]; - s_JumpX86 = 0; - s_UnconditionalDelay = 0; - - memcpy(xmmregs, startregs, sizeof(xmmregs)); -#ifdef SUPERVU_X86CACHING - if( nStartx86 >= 0 ) - memcpy(x86regs, &s_vecRegArray[nStartx86], sizeof(x86regs)); - else _initX86regs(); -#else - _initX86regs(); -#endif - - list::iterator itinst; - FORIT(itinst, insts) { - s_pCurInst = &(*itinst); - if( s_JumpX86 > 0 ) { - if( !x86regs[s_JumpX86].inuse ) { - // load - s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_READ); - } - x86regs[s_JumpX86].needed = 1; - } - - if( s_ScheduleXGKICK && s_XGKICKReg > 0 ) { - assert( x86regs[s_XGKICKReg].inuse ); - x86regs[s_XGKICKReg].needed = 1; - } - itinst->Recompile(itinst, vuxyz); - - if( s_ScheduleXGKICK > 0 ) { - if( s_ScheduleXGKICK-- == 1 ) { - recVUMI_XGKICK_(VU); - } - } - } - assert( pc == endpc ); - assert( s_ScheduleXGKICK == 0 ); - - // flush flags - if( s_PrevClipWrite != (uptr)&VU->VI[REG_CLIP_FLAG] ) { - MOV32MtoR(EAX, s_PrevClipWrite); - MOV32RtoM((uptr)&VU->VI[REG_CLIP_FLAG], EAX); - } - if( s_PrevStatusWrite != (uptr)&VU->VI[REG_STATUS_FLAG] ) { - MOV32MtoR(EAX, s_PrevStatusWrite); - MOV32RtoM((uptr)&VU->VI[REG_STATUS_FLAG], EAX); - } - if( s_PrevMACWrite != (uptr)&VU->VI[REG_MAC_FLAG] ) { - MOV32MtoR(EAX, s_PrevMACWrite); - MOV32RtoM((uptr)&VU->VI[REG_MAC_FLAG], EAX); - } -// if( s_StatusRead != (uptr)&VU->VI[REG_STATUS_FLAG] ) { -// // only lower 8 bits valid! -// MOVZX32M8toR(EAX, s_StatusRead); -// MOV32RtoM((uptr)&VU->VI[REG_STATUS_FLAG], EAX); -// } -// if( s_MACRead != (uptr)&VU->VI[REG_MAC_FLAG] ) { -// // only lower 8 bits valid! -// MOVZX32M8toR(EAX, s_MACRead); -// MOV32RtoM((uptr)&VU->VI[REG_MAC_FLAG], EAX); -// } - if( s_PrevIWrite != (uptr)&VU->VI[REG_I] ) { - MOV32ItoM((uptr)&VU->VI[REG_I], *(u32*)s_PrevIWrite); // never changes - } - - ADD32ItoM((uptr)&s_TotalVUCycles, cycles); - - // compute branches, jumps, eop - if( type & BLOCKTYPE_HASEOP ) { - // end - _freeXMMregs(); - _freeX86regs(); - AND32ItoM( (uptr)&VU0.VI[ REG_VPU_STAT ].UL, s_vu?~0x100:~0x001 ); // E flag - AND32ItoM( (uptr)&VU->vifRegs->stat, ~0x4 ); - if( !branch ) MOV32ItoM((uptr)&VU->VI[REG_TPC], endpc); - JMP32( (uptr)SuperVUEndProgram - ( (uptr)x86Ptr + 5 )); - } - else { - - u32 livevars[2] = {0}; - - list::iterator lastinst = GetInstIterAtPc(endpc-8); - lastinst++; - - if( lastinst != insts.end() ) { - livevars[0] = lastinst->livevars[0]; - livevars[1] = lastinst->livevars[1]; - } - else { - // take from children - if( blocks.size() > 0 ) { - LISTBLOCKS::iterator itchild; - FORIT(itchild, blocks) { - livevars[0] |= (*itchild)->insts.front().livevars[0]; - livevars[1] |= (*itchild)->insts.front().livevars[1]; - } - } - else { - livevars[0] = ~0; - livevars[1] = ~0; - } - } - - SuperVUFreeXMMregs(livevars); - - // get rid of any writes, otherwise _freeX86regs will write - x86regs[s_JumpX86].mode &= ~MODE_WRITE; - - if( branch == 1 ) { - if( !x86regs[s_JumpX86].inuse ) { - assert( x86regs[s_JumpX86].type == X86TYPE_VUJUMP ); - s_JumpX86 = 0xffffffff; // notify to jump from g_recWriteback - } - } - - // align VI regs -#ifdef SUPERVU_X86CACHING - if( nEndx86 >= 0 ) { - _x86regs* endx86 = &s_vecRegArray[nEndx86]; - for(int i = 0; i < X86REGS; ++i) { - if( endx86[i].inuse ) { - - if( s_JumpX86 == i && x86regs[s_JumpX86].inuse ) { - x86regs[s_JumpX86].inuse = 0; - x86regs[EAX].inuse = 1; - MOV32RtoR(EAX, s_JumpX86); - s_JumpX86 = EAX; - } - - if( x86regs[i].inuse ) { - if( x86regs[i].type == endx86[i].type && x86regs[i].reg == endx86[i].reg ) { - _freeX86reg(i); - // will continue to use it - continue; - } - - if( x86regs[i].type == (X86TYPE_VI|(s_vu?X86TYPE_VU1:0)) ) { -#ifdef SUPERVU_INTERCACHING - if( livevars[0] & (1<startpc); - - switch(branch) { - case 1: // branch, esi has new prog - - SuperVUTestVU0Condition(0); - - if( s_JumpX86 == 0xffffffff ) - JMP32M((uptr)&g_recWriteback); - else - JMPR(s_JumpX86); - - break; - case 4: // jalr - pChildJumps[0] = (u32*)0xffffffff; - // fall through - - case 0x10: // jump, esi has new vupc - { - _freeXMMregs(); - _freeX86regs(); - - SuperVUTestVU0Condition(8); - - // already onto stack - CALLFunc((uptr)SuperVUGetProgram); - ADD32ItoR(ESP, 8); - JMPR(EAX); - break; - } - - case 0x13: // jr with uncon branch, uncond branch takes precendence (dropship) - { -// s32 delta = (s32)(VU->code & 0x400 ? 0xfffffc00 | (VU->code & 0x3ff) : VU->code & 0x3ff) << 3; -// ADD32ItoRmOffset(ESP, delta, 0); - - ADD32ItoR(ESP, 8); // restore - pChildJumps[0] = (u32*)((uptr)JMP32(0)|0x80000000); - break; - } - case 0: - case 3: // unconditional branch - pChildJumps[s_UnconditionalDelay] = (u32*)((uptr)JMP32(0)|0x80000000); - break; - - default: - DevCon::Error("Bad branch %x\n", params branch); - assert(0); - break; - } - } - - pendcode = x86Ptr; - type |= BLOCKTYPE_ANALYZED; - - LISTBLOCKS::iterator itchild; - FORIT(itchild, blocks) { - (*itchild)->Recompile(); - } -} - -#define GET_VUXYZMODE(reg) 0//((vuxyz&(1<<(reg)))?MODE_VUXYZ:0) - -int VuInstruction::SetCachedRegs(int upper, u32 vuxyz) -{ - if( vfread0[upper] >= 0 ) { - SuperVUFreeXMMreg(vfread0[upper], XMMTYPE_VFREG, regs[upper].VFread0); - _allocVFtoXMMreg(VU, vfread0[upper], regs[upper].VFread0, MODE_READ|GET_VUXYZMODE(regs[upper].VFread0)); - } - if( vfread1[upper] >= 0 ) { - SuperVUFreeXMMreg(vfread1[upper], XMMTYPE_VFREG, regs[upper].VFread1); - _allocVFtoXMMreg(VU, vfread1[upper], regs[upper].VFread1, MODE_READ|GET_VUXYZMODE(regs[upper].VFread1)); - } - if( vfacc[upper] >= 0 && (regs[upper].VIread&(1<= 0 ) { - assert( regs[upper].VFwrite > 0); - SuperVUFreeXMMreg(vfwrite[upper], XMMTYPE_VFREG, regs[upper].VFwrite); - _allocVFtoXMMreg(VU, vfwrite[upper], regs[upper].VFwrite, - MODE_WRITE|(regs[upper].VFwxyzw != 0xf?MODE_READ:0)|GET_VUXYZMODE(regs[upper].VFwrite)); - } - if( vfacc[upper] >= 0 && (regs[upper].VIwrite&(1<= 0 ) info |= PROCESS_EE_SET_S(vfread0[upper]); - if( vfread1[upper] >= 0 ) info |= PROCESS_EE_SET_T(vfread1[upper]); - if( vfacc[upper] >= 0 ) info |= PROCESS_VU_SET_ACC(vfacc[upper]); - if( vfwrite[upper] >= 0 ) { - if( regs[upper].VFwrite == _Ft_ && vfread1[upper] < 0 ) { - info |= PROCESS_EE_SET_T(vfwrite[upper]); - } - else { - assert( regs[upper].VFwrite == _Fd_ ); - info |= PROCESS_EE_SET_D(vfwrite[upper]); - } - } - - if( !(vffree[upper]&VFFREE_INVALID0) ) { - SuperVUFreeXMMreg(vffree[upper]&0xf, XMMTYPE_TEMP, 0); - _allocTempXMMreg(XMMT_FPS, vffree[upper]&0xf); - } - info |= PROCESS_VU_SET_TEMP(vffree[upper]&0xf); - - if( vfflush[upper] >= 0 ) { - SuperVUFreeXMMreg(vfflush[upper], XMMTYPE_TEMP, 0); - _allocTempXMMreg(XMMT_FPS, vfflush[upper]); - } - - if( upper && (regs[upper].VIwrite & (1 << REG_CLIP_FLAG)) ) { - // CLIP inst, need two extra temp registers, put it EEREC_D and EEREC_ACC - assert( vfwrite[upper] == -1 ); - SuperVUFreeXMMreg((vffree[upper]>>8)&0xf, XMMTYPE_TEMP, 0); - _allocTempXMMreg(XMMT_FPS, (vffree[upper]>>8)&0xf); - info |= PROCESS_EE_SET_D((vffree[upper]>>8)&0xf); - - SuperVUFreeXMMreg((vffree[upper]>>16)&0xf, XMMTYPE_TEMP, 0); - _allocTempXMMreg(XMMT_FPS, (vffree[upper]>>16)&0xf); - info |= PROCESS_EE_SET_ACC((vffree[upper]>>16)&0xf); - - _freeXMMreg((vffree[upper]>>8)&0xf); // don't need anymore - _freeXMMreg((vffree[upper]>>16)&0xf); // don't need anymore - } - else if( regs[upper].VIwrite & (1<>8)&0xf, XMMTYPE_TEMP, 0); - _allocTempXMMreg(XMMT_FPS, (vffree[upper]>>8)&0xf); - info |= PROCESS_EE_SET_D((vffree[upper]>>8)&0xf); - _freeXMMreg((vffree[upper]>>8)&0xf); // don't need anymore - } - - if( vfflush[upper] >= 0 ) _freeXMMreg(vfflush[upper]); - if( !(vffree[upper]&VFFREE_INVALID0) ) - _freeXMMreg(vffree[upper]&0xf); // don't need anymore - - if( (regs[0].VIwrite|regs[1].VIwrite) & ((1<::iterator& itinst, u32 vuxyz) -{ - static PCSX2_ALIGNED16(VECTOR _VF); - static PCSX2_ALIGNED16(VECTOR _VFc); - u32 *ptr; - u8* pjmp; - int vfregstore=0; - - assert( s_pCurInst == this); - s_WriteToReadQ = 0; - - ptr = (u32*)&VU->Micro[ pc ]; - - if( type & INST_Q_READ ) - SuperVUFlush(0, (ptr[0] == 0x800003bf)||!!(regs[0].VIwrite & (1<startpc || nParentPc >= (int)pc) ) { - -// if( !s_vu ) { -// for(int j = 0; j < ARRAYSIZE(badaddrs); ++j) { -// if( badaddrs[j] == nParentPc ) -// goto NoParent; -// } -// } - - list::iterator itblock; - FORIT(itblock, s_listBlocks) { - if( nParentPc >= (*itblock)->startpc && nParentPc < (*itblock)->endpc ) { - pparentinst = &(*(*itblock)->GetInstIterAtPc(nParentPc)); - //if( !s_vu ) SysPrintf("%x ", nParentPc); - if( find(s_pCurBlock->parents.begin(), s_pCurBlock->parents.end(), *itblock) != s_pCurBlock->parents.end() ) - nParentCheckForExecution = (*itblock)->startpc; - break; - } - } - - assert( pparentinst != NULL ); - } -#endif - - if( type & INST_CLIP_WRITE ) { - if( nParentPc < s_pCurBlock->startpc || nParentPc >= (int)pc ) - // reading from out of this block, so already flushed to mem - s_ClipRead = (uptr)&VU->VI[REG_CLIP_FLAG]; - else { - s_ClipRead = s_pCurBlock->GetInstIterAtPc(nParentPc)->pClipWrite; - if (s_ClipRead == 0) SysPrintf("super ClipRead allocation error! \n"); - } - } - - // before modifying, check if they will ever be read - if( s_pCurBlock->type & BLOCKTYPE_MACFLAGS ) { - - u8 outofblock=0; - if( type & INST_STATUS_WRITE ) { - - if( nParentPc < s_pCurBlock->startpc || nParentPc >= (int)pc ) { - - // reading from out of this block, so already flushed to mem - if( pparentinst != NULL ) { //&& pparentinst->pStatusWrite != NULL ) { - - // might not have processed it yet, so reserve a mem loc - if( pparentinst->pStatusWrite == 0 ) { - pparentinst->pStatusWrite = (uptr)SuperVUStaticAlloc(4); - //MOV32ItoM(pparentinst->pStatusWrite, 0); - } - -// if( s_pCurBlock->prevFlagsOutOfBlock && s_StatusRead != NULL ) { -// // or instead since don't now which parent we came from -// MOV32MtoR(EAX, pparentinst->pStatusWrite); -// OR32RtoM(s_StatusRead, EAX); -// MOV32ItoM(pparentinst->pStatusWrite, 0); -// } - - if( nParentCheckForExecution >= 0 ) { - - // don't now which parent we came from, so have to check -// uptr tempstatus = (uptr)SuperVUStaticAlloc(4); -// if( s_StatusRead != NULL ) -// MOV32MtoR(EAX, s_StatusRead); -// else -// MOV32MtoR(EAX, (uptr)&VU->VI[REG_STATUS_FLAG]); -// s_StatusRead = tempstatus; - if( s_StatusRead == 0 ) - s_StatusRead = (uptr)&VU->VI[REG_STATUS_FLAG]; - - CMP32ItoM((uptr)&g_nLastBlockExecuted, nParentCheckForExecution); - u8* jptr = JNE8(0); - MOV32MtoR(EAX, pparentinst->pStatusWrite); - MOV32ItoM(pparentinst->pStatusWrite, 0); - MOV32RtoM(s_StatusRead, EAX); - x86SetJ8(jptr); - } - else { - uptr tempstatus = (uptr)SuperVUStaticAlloc(4); - MOV32MtoR(EAX, pparentinst->pStatusWrite); - MOV32RtoM(tempstatus, EAX); - MOV32ItoM(pparentinst->pStatusWrite, 0); - s_StatusRead = tempstatus; - } - - outofblock = 2; - } - else - s_StatusRead = (uptr)&VU->VI[REG_STATUS_FLAG]; - } - else { - s_StatusRead = s_pCurBlock->GetInstIterAtPc(nParentPc)->pStatusWrite; - if (s_StatusRead == 0) SysPrintf("super StatusRead allocation error! \n"); -// if( pc >= (u32)s_pCurBlock->endpc-8 ) { -// // towards the end, so variable might be leaded to another block (silent hill 4) -// uptr tempstatus = (uptr)SuperVUStaticAlloc(4); -// MOV32MtoR(EAX, s_StatusRead); -// MOV32RtoM(tempstatus, EAX); -// MOV32ItoM(s_StatusRead, 0); -// s_StatusRead = tempstatus; -// } - } - } - if( type & INST_MAC_WRITE ) { - - if( nParentPc < s_pCurBlock->startpc || nParentPc >= (int)pc ) { - // reading from out of this block, so already flushed to mem - - if( pparentinst != NULL ) {//&& pparentinst->pMACWrite != NULL ) { - // necessary for (katamari) - // towards the end, so variable might be leaked to another block (silent hill 4) - - // might not have processed it yet, so reserve a mem loc - if( pparentinst->pMACWrite == 0 ) { - pparentinst->pMACWrite = (uptr)SuperVUStaticAlloc(4); - //MOV32ItoM(pparentinst->pMACWrite, 0); - } - -// if( s_pCurBlock->prevFlagsOutOfBlock && s_MACRead != NULL ) { -// // or instead since don't now which parent we came from -// MOV32MtoR(EAX, pparentinst->pMACWrite); -// OR32RtoM(s_MACRead, EAX); -// MOV32ItoM(pparentinst->pMACWrite, 0); -// } - if( nParentCheckForExecution >= 0 ) { - - // don't now which parent we came from, so have to check -// uptr tempmac = (uptr)SuperVUStaticAlloc(4); -// if( s_MACRead != NULL ) -// MOV32MtoR(EAX, s_MACRead); -// else -// MOV32MtoR(EAX, (uptr)&VU->VI[REG_MAC_FLAG]); -// s_MACRead = tempmac; - - if( s_MACRead == 0 ) - s_MACRead = (uptr)&VU->VI[REG_MAC_FLAG]; - - CMP32ItoM((uptr)&g_nLastBlockExecuted, nParentCheckForExecution); - u8* jptr = JNE8(0); - MOV32MtoR(EAX, pparentinst->pMACWrite); - MOV32ItoM(pparentinst->pMACWrite, 0); - MOV32RtoM(s_MACRead, EAX); - x86SetJ8(jptr); - } - else { - uptr tempMAC = (uptr)SuperVUStaticAlloc(4); - MOV32MtoR(EAX, pparentinst->pMACWrite); - MOV32RtoM(tempMAC, EAX); - MOV32ItoM(pparentinst->pMACWrite, 0); - s_MACRead = tempMAC; - } - - outofblock = 2; - } - else - s_MACRead = (uptr)&VU->VI[REG_MAC_FLAG]; - -// if( pc >= (u32)s_pCurBlock->endpc-8 ) { -// // towards the end, so variable might be leaked to another block (silent hill 4) -// uptr tempMAC = (uptr)SuperVUStaticAlloc(4); -// MOV32MtoR(EAX, s_MACRead); -// MOV32RtoM(tempMAC, EAX); -// MOV32ItoM(s_MACRead, 0); -// s_MACRead = tempMAC; -// } - } - else { - s_MACRead = s_pCurBlock->GetInstIterAtPc(nParentPc)->pMACWrite; - } - } - - s_pCurBlock->prevFlagsOutOfBlock = outofblock; - } - else if( pparentinst != NULL) { - // make sure to reset the mac and status flags! (katamari) - if( pparentinst->pStatusWrite) - MOV32ItoM(pparentinst->pStatusWrite, 0); - if( pparentinst->pMACWrite) - MOV32ItoM(pparentinst->pMACWrite, 0); - } - - assert( s_ClipRead != 0 ); - assert( s_MACRead != 0 ); - assert( s_StatusRead != 0 ); - - return; - } - - s_pCurBlock->prevFlagsOutOfBlock = 0; - -#ifdef _DEBUG - MOV32ItoR(EAX, pc); -#endif - - assert( !(type & (INST_CLIP_WRITE|INST_STATUS_WRITE|INST_MAC_WRITE)) ); - pc += 8; - - list::const_iterator itinst2; - - if( (regs[0].VIwrite|regs[1].VIwrite) & ((1<type & BLOCKTYPE_MACFLAGS ) { - if( pMACWrite == 0 ) { - pMACWrite = (uptr)SuperVUStaticAlloc(4); - //MOV32ItoM(pMACWrite, 0); - } - if( pStatusWrite == 0 ) { - pStatusWrite = (uptr)SuperVUStaticAlloc(4); - //MOV32ItoM(pStatusWrite, 0); - } - } - else { - assert( s_StatusRead == (uptr)&VU->VI[REG_STATUS_FLAG] ); - assert( s_MACRead == (uptr)&VU->VI[REG_MAC_FLAG] ); - pMACWrite = s_MACRead; - pStatusWrite = s_StatusRead; - } - } - - if( (pClipWrite == 0) && ((regs[0].VIwrite|regs[1].VIwrite) & (1<insts.end() ) { - if( (itinst2->regs[0].VIread|itinst2->regs[0].VIwrite|itinst2->regs[1].VIread|itinst2->regs[1].VIwrite) && (1<flags, VUFLAG_MFLAGSET); - } - if (ptr[1] & 0x10000000) { // D flag - TEST32ItoM((uptr)&VU0.VI[REG_FBRST].UL, s_vu?0x400:0x004); - u8* ptr = JZ8(0); - OR32ItoM((uptr)&VU0.VI[REG_VPU_STAT].UL, s_vu?0x200:0x002); - _callFunctionArg1((uptr)hwIntcIrq, MEM_CONSTTAG, s_vu?INTC_VU1:INTC_VU0); - x86SetJ8(ptr); - } - if (ptr[1] & 0x08000000) { // T flag - TEST32ItoM((uptr)&VU0.VI[REG_FBRST].UL, s_vu?0x800:0x008); - u8* ptr = JZ8(0); - OR32ItoM((uptr)&VU0.VI[REG_VPU_STAT].UL, s_vu?0x400:0x004); - _callFunctionArg1((uptr)hwIntcIrq, MEM_CONSTTAG, s_vu?INTC_VU1:INTC_VU0); - x86SetJ8(ptr); - } - - // check upper flags - if (ptr[1] & 0x80000000) { // I flag - - assert( !(regs[0].VIwrite & ((1<code = ptr[1]; - s_vuInfo = SetCachedRegs(1, vuxyz); - if( s_JumpX86 > 0 ) x86regs[s_JumpX86].needed = 1; - if( s_ScheduleXGKICK && s_XGKICKReg > 0 ) x86regs[s_XGKICKReg].needed = 1; - - recVU_UPPER_OPCODE[ VU->code & 0x3f ]( VU, s_vuInfo ); - - s_PrevIWrite = (uptr)ptr; - _clearNeededXMMregs(); - _clearNeededX86regs(); - } - else { - if( regs[0].VIwrite & (1<insts.end()); - u32* codeptr2 = ptr+2; - - while(itinst2 != s_pCurBlock->insts.end() ) { - if( !(itinst2->type & INST_DUMMY) && ((itinst2->regs[0].VIwrite&(1<type & INST_Q_WRITE) && itinst2->nParentPc == pc-8 ) { - break; - } - if( itinst2->type & INST_Q_READ ) { - cacheq = 1; - break; - } - if( itinst2->type & INST_DUMMY ) { - ++itinst2; - continue; - } - codeptr2 += 2; - ++itinst2; - } - - if( itinst2 == s_pCurBlock->insts.end() ) - cacheq = 1; - - int x86temp = -1; - if( cacheq ) - x86temp = _allocX86reg(-1, X86TYPE_TEMP, 0, 0); - - // new is written so flush old - // if type & INST_Q_READ, already flushed - if( !(type & INST_Q_READ) && s_recWriteQ == 0 ) MOV32MtoR(EAX, (uptr)&s_writeQ); - - if( cacheq ) - MOV32MtoR(x86temp, (uptr)&s_TotalVUCycles); - - if( !(type & INST_Q_READ) ) { - if( s_recWriteQ == 0 ) { - OR32RtoR(EAX, EAX); - pjmp = JS8(0); - MOV32MtoR(EAX, SuperVUGetVIAddr(REG_Q, 0)); - MOV32RtoM(SuperVUGetVIAddr(REG_Q, 1), EAX); - x86SetJ8(pjmp); - } - else if( s_needFlush & 1 ) { - MOV32MtoR(EAX, SuperVUGetVIAddr(REG_Q, 0)); - MOV32RtoM(SuperVUGetVIAddr(REG_Q, 1), EAX); - s_needFlush &= ~1; - } - } - - // write new Q - if( cacheq ) { - assert(s_pCurInst->pqcycles>1); - ADD32ItoR(x86temp, s_pCurInst->info.cycle+s_pCurInst->pqcycles); - MOV32RtoM((uptr)&s_writeQ, x86temp); - s_needFlush |= 1; - } - else { - // won't be writing back - s_WriteToReadQ = 1; - s_needFlush &= ~1; - MOV32ItoM((uptr)&s_writeQ, 0x80000001); - } - - s_recWriteQ = s_pCurInst->info.cycle+s_pCurInst->pqcycles; - - if( x86temp >= 0 ) - _freeX86reg(x86temp); - } - - if( regs[0].VIwrite & (1<pqcycles>1); - ADD32ItoR(x86temp, s_pCurInst->info.cycle+s_pCurInst->pqcycles); - MOV32RtoM((uptr)&s_writeP, x86temp); - s_needFlush |= 2; - - s_recWriteP = s_pCurInst->info.cycle+s_pCurInst->pqcycles; - - _freeX86reg(x86temp); - } - - if( ptr[0] == 0x800003bf ) // waitq - SuperVUFlush(0, 1); - - if( ptr[0] == 0x800007bf ) // waitp - SuperVUFlush(1, 1); - -#ifdef PCSX2_DEVBUILD - if ( regs[1].VIread & regs[0].VIwrite & ~((1<startpc); - } -#endif - - u32 modewrite = 0; - if( vfwrite[1] >= 0 && xmmregs[vfwrite[1]].inuse && xmmregs[vfwrite[1]].type == XMMTYPE_VFREG && xmmregs[vfwrite[1]].reg == regs[1].VFwrite ) - modewrite = xmmregs[vfwrite[1]].mode & MODE_WRITE; - - VU->code = ptr[1]; - s_vuInfo = SetCachedRegs(1, vuxyz); - - if (vfwrite[1] >= 0) { - assert( regs[1].VFwrite > 0 ); - - if (vfwrite[0] == vfwrite[1]) { - //SysPrintf("*PCSX2*: Warning, VF write to the same reg in both lower/upper cycle %x\n", s_pCurBlock->startpc); - } - - if (vfread0[0] == vfwrite[1] || vfread1[0] == vfwrite[1] ) { - assert( regs[0].VFread0 == regs[1].VFwrite || regs[0].VFread1 == regs[1].VFwrite ); - assert( vfflush[0] >= 0 ); - if( modewrite ) { - SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[regs[1].VFwrite], (x86SSERegType)vfwrite[1]); - } - vfregstore = 1; - } - } - - if( s_JumpX86 > 0 ) x86regs[s_JumpX86].needed = 1; - if( s_ScheduleXGKICK && s_XGKICKReg > 0 ) x86regs[s_XGKICKReg].needed = 1; - - recVU_UPPER_OPCODE[ VU->code & 0x3f ]( VU, s_vuInfo ); - _clearNeededXMMregs(); - _clearNeededX86regs(); - - // necessary because status can be set by both upper and lower - if( regs[1].VIwrite & (1<code = ptr[0]; - s_vuInfo = SetCachedRegs(0, vuxyz); - - if( vfregstore ) { - // load - SSE_MOVAPS_M128_to_XMM(vfflush[0], (uptr)&VU->VF[regs[1].VFwrite]); - - assert( xmmregs[vfwrite[1]].mode & MODE_WRITE ); - - // replace with vfflush - if( _Fs_ == regs[1].VFwrite ) { - s_vuInfo &= ~PROCESS_EE_SET_S(0xf); - s_vuInfo |= PROCESS_EE_SET_S(vfflush[0]); - } - if( _Ft_ == regs[1].VFwrite ) { - s_vuInfo &= ~PROCESS_EE_SET_T(0xf); - s_vuInfo |= PROCESS_EE_SET_T(vfflush[0]); - } - - xmmregs[vfflush[0]].mode |= MODE_NOFLUSH|MODE_WRITE; // so that lower inst doesn't flush - } - - // notify vuinsts that upper inst is a fmac - if( regs[1].pipe == VUPIPE_FMAC ) - s_vuInfo |= PROCESS_VU_SET_FMAC(); - - if( s_JumpX86 > 0 ) x86regs[s_JumpX86].needed = 1; - if( s_ScheduleXGKICK && s_XGKICKReg > 0 ) x86regs[s_XGKICKReg].needed = 1; - -#ifdef SUPERVU_VIBRANCHDELAY - if ( type & INST_CACHE_VI ) { - assert( vicached >= 0 ); - int cachedreg = _allocX86reg(-1, X86TYPE_VI|(s_vu?X86TYPE_VU1:0), vicached, MODE_READ); - MOV32RtoM((uptr)&s_VIBranchDelay, cachedreg); - } -#endif - - // check if inst before branch and the write is the same as the read in the branch (wipeout) -// int oldreg=0; -// if( pc == s_pCurBlock->endpc-16 ) { -// itinst2 = itinst; ++itinst2; -// if( itinst2->regs[0].pipe == VUPIPE_BRANCH && (itinst->regs[0].VIwrite&itinst2->regs[0].VIread) ) { -// -// CALLFunc((u32)branchfn); -// assert( itinst->regs[0].VIwrite & 0xffff ); -// SysPrintf("vi write before branch\n"); -// for(s_CacheVIReg = 0; s_CacheVIReg < 16; ++s_CacheVIReg) { -// if( itinst->regs[0].VIwrite & (1<endpc-8 && s_CacheVIReg >= 0 ) { -// assert( s_CacheVIX86 > 0 && x86regs[s_CacheVIX86].inuse && x86regs[s_CacheVIX86].reg == s_CacheVIReg && x86regs[s_CacheVIX86].type == X86TYPE_VITEMP ); -// -// oldreg = _allocX86reg(-1, X86TYPE_VI|(s_vu?X86TYPE_VU1:0), s_CacheVIReg, MODE_READ); -// x86regs[s_CacheVIX86].needed = 1; -// assert( x86regs[oldreg].mode & MODE_WRITE ); -// -// x86regs[s_CacheVIX86].type = X86TYPE_VI|(s_vu?X86TYPE_VU1:0); -// x86regs[oldreg].type = X86TYPE_VITEMP; -// } - - recVU_LOWER_OPCODE[ VU->code >> 25 ]( VU, s_vuInfo ); - -// if( pc == s_pCurBlock->endpc-8 && s_CacheVIReg >= 0 ) { -// // revert -// x86regs[s_CacheVIX86].inuse = 0; -// x86regs[oldreg].type = X86TYPE_VI|(s_vu?X86TYPE_VU1:0); -// } - - _clearNeededXMMregs(); - _clearNeededX86regs(); - } - - // clip is always written so ok - if( (regs[0].VIwrite|regs[1].VIwrite) & (1<code); - int curjump = 0; - - if( s_pCurInst->type & INST_BRANCH_DELAY ) { - assert( (branch&0x17)!=0x10 && (branch&0x17)!=4 ); // no jump handlig for now - - if( (branch & 0x7) == 3 ) { - // previous was a direct jump - curjump = 1; - } - else if( branch & 1 ) curjump = 2; - } - - assert( s_JumpX86 > 0 ); - - if( (s_pCurBlock->type & BLOCKTYPE_HASEOP) || s_vu == 0 || SUPERVU_CHECKCONDITION) - MOV32ItoM(SuperVUGetVIAddr(REG_TPC, 0), bpc); - MOV32ItoR(s_JumpX86, 0); - s_pCurBlock->pChildJumps[curjump] = (u32*)x86Ptr-1; - - if( !(s_pCurInst->type & INST_BRANCH_DELAY) ) { - j8Ptr[1] = JMP8(0); - x86SetJ8( j8Ptr[ 0 ] ); - - if( (s_pCurBlock->type & BLOCKTYPE_HASEOP) || s_vu == 0 || SUPERVU_CHECKCONDITION ) - MOV32ItoM(SuperVUGetVIAddr(REG_TPC, 0), pc+8); - MOV32ItoR(s_JumpX86, 0); - s_pCurBlock->pChildJumps[curjump+1] = (u32*)x86Ptr-1; - - x86SetJ8( j8Ptr[ 1 ] ); - } - else - x86SetJ8( j8Ptr[ 0 ] ); - - branch |= 1; -} - -// supervu specific insts -void recVUMI_IBQ_prep() -{ - int fsreg, ftreg; - - if( _Fs_ == 0 ) { -#ifdef SUPERVU_VIBRANCHDELAY - if( s_pCurInst->vicached >= 0 && s_pCurInst->vicached == _Ft_ ) { - ftreg = -1; - } - else -#endif - { - ftreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Ft_, MODE_READ); - } - - s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); - - if( ftreg >= 0 ) { - CMP16ItoR( ftreg, 0 ); - } - else CMP16ItoM(SuperVUGetVIAddr(_Ft_, 1), 0); - } - else if( _Ft_ == 0 ) { -#ifdef SUPERVU_VIBRANCHDELAY - if( s_pCurInst->vicached >= 0 && s_pCurInst->vicached == _Fs_ ) { - fsreg = -1; - } - else -#endif - { - fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); - } - - s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); - - if( fsreg >= 0 ) { - CMP16ItoR( fsreg, 0 ); - } - else CMP16ItoM(SuperVUGetVIAddr(_Fs_, 1), 0); - - } - else { - _addNeededX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Ft_); - -#ifdef SUPERVU_VIBRANCHDELAY - if( s_pCurInst->vicached >= 0 && s_pCurInst->vicached == _Fs_ ) { - fsreg = -1; - } - else -#endif - { - fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); - } - -#ifdef SUPERVU_VIBRANCHDELAY - if( s_pCurInst->vicached >= 0 && s_pCurInst->vicached == _Ft_ ) { - ftreg = -1; - - if( fsreg <= 0 ) { - // allocate fsreg - if( s_pCurInst->vicached >= 0 && s_pCurInst->vicached == _Fs_ ) { - fsreg = _allocX86reg(-1, X86TYPE_TEMP, 0, MODE_READ|MODE_WRITE); - MOV32MtoR(fsreg, SuperVUGetVIAddr(_Fs_, 1)); - } - else - fsreg = _allocX86reg(-1, X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); - } - } - else -#endif - { - ftreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Ft_, MODE_READ); - } - - s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); - - if( fsreg >= 0 ) { - if( ftreg >= 0 ) { - CMP16RtoR( fsreg, ftreg ); - } - else CMP16MtoR(fsreg, SuperVUGetVIAddr(_Ft_, 1)); - } - else if( ftreg >= 0 ) { - CMP16MtoR(ftreg, SuperVUGetVIAddr(_Fs_, 1)); - } - else { - fsreg = _allocX86reg(-1, X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); - CMP16MtoR(fsreg, SuperVUGetVIAddr(_Ft_, 1)); - } - } -} - -void recVUMI_IBEQ( VURegs* vuu, s32 info ) -{ - recVUMI_IBQ_prep(); - j8Ptr[ 0 ] = JNE8( 0 ); - recVUMI_BranchHandle(); -} - -void recVUMI_IBGEZ( VURegs* vuu, s32 info ) -{ - int fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); - s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); - - if( fsreg >= 0 ) { - OR16RtoR(fsreg, fsreg); - j8Ptr[ 0 ] = JS8( 0 ); - } - else { - CMP16ItoM( SuperVUGetVIAddr(_Fs_, 1), 0x0 ); - j8Ptr[ 0 ] = JL8( 0 ); - } - - recVUMI_BranchHandle(); -} - -void recVUMI_IBGTZ( VURegs* vuu, s32 info ) -{ - int fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); - s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); - - if( fsreg >= 0 ) { - CMP16ItoR(fsreg, 0); - j8Ptr[ 0 ] = JLE8( 0 ); - } - else { - CMP16ItoM( SuperVUGetVIAddr(_Fs_, 1), 0x0 ); - j8Ptr[ 0 ] = JLE8( 0 ); - } - recVUMI_BranchHandle(); -} - -void recVUMI_IBLEZ( VURegs* vuu, s32 info ) -{ - int fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); - s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); - - if( fsreg >= 0 ) { - CMP16ItoR(fsreg, 0); - j8Ptr[ 0 ] = JG8( 0 ); - } - else { - CMP16ItoM( SuperVUGetVIAddr(_Fs_, 1), 0x0 ); - j8Ptr[ 0 ] = JG8( 0 ); - } - recVUMI_BranchHandle(); -} - -void recVUMI_IBLTZ( VURegs* vuu, s32 info ) -{ - int fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); - s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); - - if( fsreg >= 0 ) { - OR16RtoR(fsreg, fsreg); - j8Ptr[ 0 ] = JNS8( 0 ); - } - else { - CMP16ItoM( SuperVUGetVIAddr(_Fs_, 1), 0x0 ); - j8Ptr[ 0 ] = JGE8( 0 ); - } - recVUMI_BranchHandle(); -} - -void recVUMI_IBNE( VURegs* vuu, s32 info ) -{ - recVUMI_IBQ_prep(); - j8Ptr[ 0 ] = JE8( 0 ); - recVUMI_BranchHandle(); -} - -void recVUMI_B( VURegs* vuu, s32 info ) -{ - // supervu will take care of the rest - int bpc = _recbranchAddr(VU->code); - if( (s_pCurBlock->type & BLOCKTYPE_HASEOP) || s_vu == 0 || SUPERVU_CHECKCONDITION) - MOV32ItoM(SuperVUGetVIAddr(REG_TPC, 0), bpc); - - // loops to self, so check condition - if( bpc == s_pCurBlock->startpc && (s_vu == 0 || SUPERVU_CHECKCONDITION) ) { - SuperVUTestVU0Condition(0); - } - - if( s_pCurBlock->blocks.size() > 1 ) { - s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); - MOV32ItoR(s_JumpX86, 0); - s_pCurBlock->pChildJumps[(s_pCurInst->type & INST_BRANCH_DELAY)?1:0] = (u32*)x86Ptr-1; - s_UnconditionalDelay = 1; - } - - branch |= 3; -} - -void recVUMI_BAL( VURegs* vuu, s32 info ) -{ - int bpc = _recbranchAddr(VU->code); - if( (s_pCurBlock->type & BLOCKTYPE_HASEOP) || s_vu == 0 || SUPERVU_CHECKCONDITION ) - MOV32ItoM(SuperVUGetVIAddr(REG_TPC, 0), bpc); - - // loops to self, so check condition - if( bpc == s_pCurBlock->startpc && (s_vu == 0 || SUPERVU_CHECKCONDITION) ) { - SuperVUTestVU0Condition(0); - } - - if ( _Ft_ ) { - _deleteX86reg(X86TYPE_VI|(s_vu?X86TYPE_VU1:0), _Ft_, 2); - MOV16ItoM( SuperVUGetVIAddr(_Ft_, 0), (pc+8)>>3 ); - } - - if( s_pCurBlock->blocks.size() > 1 ) { - s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); - MOV32ItoR(s_JumpX86, 0); - s_pCurBlock->pChildJumps[(s_pCurInst->type & INST_BRANCH_DELAY)?1:0] = (u32*)x86Ptr-1; - s_UnconditionalDelay = 1; - } - - branch |= 3; -} - -void recVUMI_JR( VURegs* vuu, s32 info ) -{ - int fsreg = _allocX86reg(-1, X86TYPE_VI|(s_vu?X86TYPE_VU1:0), _Fs_, MODE_READ); - LEA32RStoR(EAX, fsreg, 3); - CWDE(); - - if( (s_pCurBlock->type & BLOCKTYPE_HASEOP) || s_vu == 0 ) MOV32RtoM(SuperVUGetVIAddr(REG_TPC, 0), EAX); - - if( !(s_pCurBlock->type & BLOCKTYPE_HASEOP) ) { - PUSH32I(s_vu); - PUSH32R(EAX); - } - branch |= 0x10; // 0x08 is reserved -} - -void recVUMI_JALR( VURegs* vuu, s32 info ) -{ - _addNeededX86reg(X86TYPE_VI|(s_vu?X86TYPE_VU1:0), _Ft_); - - int fsreg = _allocX86reg(-1, X86TYPE_VI|(s_vu?X86TYPE_VU1:0), _Fs_, MODE_READ); - LEA32RStoR(EAX, fsreg, 3); - CWDE(); // necessary, charlie and chocolate factory gives bad addrs, but graphics are ok - - if ( _Ft_ ) { - _deleteX86reg(X86TYPE_VI|(s_vu?X86TYPE_VU1:0), _Ft_, 2); - MOV16ItoM( SuperVUGetVIAddr(_Ft_, 0), (pc+8)>>3 ); - } - - if( (s_pCurBlock->type & BLOCKTYPE_HASEOP) || s_vu == 0 ) MOV32RtoM(SuperVUGetVIAddr(REG_TPC, 0), EAX); - - if( !(s_pCurBlock->type & BLOCKTYPE_HASEOP) ) { - PUSH32I(s_vu); - PUSH32R(EAX); - } - - branch |= 4; -} - -#ifdef SUPERVU_COUNT -void StopSVUCounter() -{ - QueryPerformanceCounter(&svufinal); - svutime += (u32)(svufinal.QuadPart-svubase.QuadPart); -} - -void StartSVUCounter() -{ - QueryPerformanceCounter(&svubase); -} -#endif - -#ifdef PCSX2_DEVBUILD -void vu1xgkick(u32* pMem, u32 addr) -{ - assert( addr < 0x4000 ); -#ifdef SUPERVU_COUNT - StopSVUCounter(); -#endif - - GSGIFTRANSFER1(pMem, addr); - -#ifdef SUPERVU_COUNT - StartSVUCounter(); -#endif -} -#endif - -void recVUMI_XGKICK_( VURegs *VU ) -{ - assert( s_XGKICKReg > 0 && x86regs[s_XGKICKReg].inuse && x86regs[s_XGKICKReg].type == X86TYPE_VITEMP); - - x86regs[s_XGKICKReg].inuse = 0; // so free doesn't flush - _freeX86regs(); - _freeXMMregs(); - - PUSH32R(s_XGKICKReg); - PUSH32I((uptr)VU->Mem); - - //CALLFunc((u32)countfn); - - if( mtgsThread != NULL ) { - CALLFunc((uptr)VU1XGKICK_MTGSTransfer); - ADD32ItoR(ESP, 8); - } - else { -#ifdef PCSX2_DEVBUILD - CALLFunc((uptr)vu1xgkick); - ADD32ItoR(ESP, 8); -#else - CALLFunc((uptr)GSgifTransfer1); -#endif - } - - s_ScheduleXGKICK = 0; -} - -void recVUMI_XGKICK( VURegs *VU, int info ) -{ - if( s_ScheduleXGKICK ) { - // second xgkick, so launch the first - recVUMI_XGKICK_(VU); - } - - int fsreg = _allocX86reg(X86ARG2, X86TYPE_VI|(s_vu?X86TYPE_VU1:0), _Fs_, MODE_READ); - _freeX86reg(fsreg); // flush - x86regs[fsreg].inuse = 1; - x86regs[fsreg].type = X86TYPE_VITEMP; - x86regs[fsreg].needed = 1; - x86regs[fsreg].mode = MODE_WRITE|MODE_READ; - SHL32ItoR(fsreg, 4); - AND32ItoR(fsreg, 0x3fff); - s_XGKICKReg = fsreg; - - if( !SUPERVU_XGKICKDELAY || pc == s_pCurBlock->endpc ) { - recVUMI_XGKICK_(VU); - } - else { - if( g_VUGameFixes & VUFIX_XGKICKDELAY2 ) - s_ScheduleXGKICK = min((u32)4, (s_pCurBlock->endpc-pc)/8); - else - s_ScheduleXGKICK = 2; - } -} - -void recVU_UPPER_FD_00( VURegs* VU, s32 info ); -void recVU_UPPER_FD_01( VURegs* VU, s32 info ); -void recVU_UPPER_FD_10( VURegs* VU, s32 info ); -void recVU_UPPER_FD_11( VURegs* VU, s32 info ); -void recVULowerOP( VURegs* VU, s32 info ); -void recVULowerOP_T3_00( VURegs* VU, s32 info ); -void recVULowerOP_T3_01( VURegs* VU, s32 info ); -void recVULowerOP_T3_10( VURegs* VU, s32 info ); -void recVULowerOP_T3_11( VURegs* VU, s32 info ); -void recVUunknown( VURegs* VU, s32 info ); - -void (*recVU_LOWER_OPCODE[128])( VURegs* VU, s32 info ) = { - recVUMI_LQ , recVUMI_SQ , recVUunknown , recVUunknown, - recVUMI_ILW , recVUMI_ISW , recVUunknown , recVUunknown, - recVUMI_IADDIU, recVUMI_ISUBIU, recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUMI_FCEQ , recVUMI_FCSET , recVUMI_FCAND, recVUMI_FCOR, /* 0x10 */ - recVUMI_FSEQ , recVUMI_FSSET , recVUMI_FSAND, recVUMI_FSOR, - recVUMI_FMEQ , recVUunknown , recVUMI_FMAND, recVUMI_FMOR, - recVUMI_FCGET , recVUunknown , recVUunknown , recVUunknown, - recVUMI_B , recVUMI_BAL , recVUunknown , recVUunknown, /* 0x20 */ - recVUMI_JR , recVUMI_JALR , recVUunknown , recVUunknown, - recVUMI_IBEQ , recVUMI_IBNE , recVUunknown , recVUunknown, - recVUMI_IBLTZ , recVUMI_IBGTZ , recVUMI_IBLEZ, recVUMI_IBGEZ, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, /* 0x30 */ - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVULowerOP , recVUunknown , recVUunknown , recVUunknown, /* 0x40*/ - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, /* 0x50 */ - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, /* 0x60 */ - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, /* 0x70 */ - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, -}; - -void (*recVULowerOP_T3_00_OPCODE[32])(VURegs* VU, s32 info) = { - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUMI_MOVE , recVUMI_LQI , recVUMI_DIV , recVUMI_MTIR, - recVUMI_RNEXT , recVUunknown , recVUunknown , recVUunknown, /* 0x10 */ - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUMI_MFP , recVUMI_XTOP , recVUMI_XGKICK, - recVUMI_ESADD , recVUMI_EATANxy, recVUMI_ESQRT, recVUMI_ESIN, -}; - -void (*recVULowerOP_T3_01_OPCODE[32])(VURegs* VU, s32 info) = { - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUMI_MR32 , recVUMI_SQI , recVUMI_SQRT , recVUMI_MFIR, - recVUMI_RGET , recVUunknown , recVUunknown , recVUunknown, /* 0x10 */ - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUMI_XITOP, recVUunknown, - recVUMI_ERSADD, recVUMI_EATANxz, recVUMI_ERSQRT, recVUMI_EATAN, -}; - -void (*recVULowerOP_T3_10_OPCODE[32])(VURegs* VU, s32 info) = { - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUMI_LQD , recVUMI_RSQRT, recVUMI_ILWR, - recVUMI_RINIT , recVUunknown , recVUunknown , recVUunknown, /* 0x10 */ - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUMI_ELENG , recVUMI_ESUM , recVUMI_ERCPR, recVUMI_EEXP, -}; - -void (*recVULowerOP_T3_11_OPCODE[32])(VURegs* VU, s32 info) = { - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUMI_SQD , recVUMI_WAITQ, recVUMI_ISWR, - recVUMI_RXOR , recVUunknown , recVUunknown , recVUunknown, /* 0x10 */ - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUMI_ERLENG, recVUunknown , recVUMI_WAITP, recVUunknown, -}; - -void (*recVULowerOP_OPCODE[64])(VURegs* VU, s32 info) = { - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, /* 0x10 */ - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, /* 0x20 */ - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUMI_IADD , recVUMI_ISUB , recVUMI_IADDI, recVUunknown, /* 0x30 */ - recVUMI_IAND , recVUMI_IOR , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVULowerOP_T3_00, recVULowerOP_T3_01, recVULowerOP_T3_10, recVULowerOP_T3_11, -}; - -void (*recVU_UPPER_OPCODE[64])(VURegs* VU, s32 info) = { - recVUMI_ADDx , recVUMI_ADDy , recVUMI_ADDz , recVUMI_ADDw, - recVUMI_SUBx , recVUMI_SUBy , recVUMI_SUBz , recVUMI_SUBw, - recVUMI_MADDx , recVUMI_MADDy , recVUMI_MADDz , recVUMI_MADDw, - recVUMI_MSUBx , recVUMI_MSUBy , recVUMI_MSUBz , recVUMI_MSUBw, - recVUMI_MAXx , recVUMI_MAXy , recVUMI_MAXz , recVUMI_MAXw, /* 0x10 */ - recVUMI_MINIx , recVUMI_MINIy , recVUMI_MINIz , recVUMI_MINIw, - recVUMI_MULx , recVUMI_MULy , recVUMI_MULz , recVUMI_MULw, - recVUMI_MULq , recVUMI_MAXi , recVUMI_MULi , recVUMI_MINIi, - recVUMI_ADDq , recVUMI_MADDq , recVUMI_ADDi , recVUMI_MADDi, /* 0x20 */ - recVUMI_SUBq , recVUMI_MSUBq , recVUMI_SUBi , recVUMI_MSUBi, - recVUMI_ADD , recVUMI_MADD , recVUMI_MUL , recVUMI_MAX, - recVUMI_SUB , recVUMI_MSUB , recVUMI_OPMSUB, recVUMI_MINI, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, /* 0x30 */ - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVUunknown , recVUunknown , recVUunknown , recVUunknown, - recVU_UPPER_FD_00, recVU_UPPER_FD_01, recVU_UPPER_FD_10, recVU_UPPER_FD_11, -}; - -void (*recVU_UPPER_FD_00_TABLE[32])(VURegs* VU, s32 info) = { - recVUMI_ADDAx, recVUMI_SUBAx , recVUMI_MADDAx, recVUMI_MSUBAx, - recVUMI_ITOF0, recVUMI_FTOI0, recVUMI_MULAx , recVUMI_MULAq , - recVUMI_ADDAq, recVUMI_SUBAq, recVUMI_ADDA , recVUMI_SUBA , - recVUunknown , recVUunknown , recVUunknown , recVUunknown , - recVUunknown , recVUunknown , recVUunknown , recVUunknown , - recVUunknown , recVUunknown , recVUunknown , recVUunknown , - recVUunknown , recVUunknown , recVUunknown , recVUunknown , - recVUunknown , recVUunknown , recVUunknown , recVUunknown , -}; - -void (*recVU_UPPER_FD_01_TABLE[32])(VURegs* VU, s32 info) = { - recVUMI_ADDAy , recVUMI_SUBAy , recVUMI_MADDAy, recVUMI_MSUBAy, - recVUMI_ITOF4 , recVUMI_FTOI4 , recVUMI_MULAy , recVUMI_ABS , - recVUMI_MADDAq, recVUMI_MSUBAq, recVUMI_MADDA , recVUMI_MSUBA , - recVUunknown , recVUunknown , recVUunknown , recVUunknown , - recVUunknown , recVUunknown , recVUunknown , recVUunknown , - recVUunknown , recVUunknown , recVUunknown , recVUunknown , - recVUunknown , recVUunknown , recVUunknown , recVUunknown , - recVUunknown , recVUunknown , recVUunknown , recVUunknown , -}; - -void (*recVU_UPPER_FD_10_TABLE[32])(VURegs* VU, s32 info) = { - recVUMI_ADDAz , recVUMI_SUBAz , recVUMI_MADDAz, recVUMI_MSUBAz, - recVUMI_ITOF12, recVUMI_FTOI12, recVUMI_MULAz , recVUMI_MULAi , - recVUMI_ADDAi, recVUMI_SUBAi , recVUMI_MULA , recVUMI_OPMULA, - recVUunknown , recVUunknown , recVUunknown , recVUunknown , - recVUunknown , recVUunknown , recVUunknown , recVUunknown , - recVUunknown , recVUunknown , recVUunknown , recVUunknown , - recVUunknown , recVUunknown , recVUunknown , recVUunknown , - recVUunknown , recVUunknown , recVUunknown , recVUunknown , -}; - -void (*recVU_UPPER_FD_11_TABLE[32])(VURegs* VU, s32 info) = { - recVUMI_ADDAw , recVUMI_SUBAw , recVUMI_MADDAw, recVUMI_MSUBAw, - recVUMI_ITOF15, recVUMI_FTOI15, recVUMI_MULAw , recVUMI_CLIP , - recVUMI_MADDAi, recVUMI_MSUBAi, recVUunknown , recVUMI_NOP , - recVUunknown , recVUunknown , recVUunknown , recVUunknown , - recVUunknown , recVUunknown , recVUunknown , recVUunknown , - recVUunknown , recVUunknown , recVUunknown , recVUunknown , - recVUunknown , recVUunknown , recVUunknown , recVUunknown , - recVUunknown , recVUunknown , recVUunknown , recVUunknown , -}; - -void recVU_UPPER_FD_00( VURegs* VU, s32 info ) -{ - recVU_UPPER_FD_00_TABLE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); -} - -void recVU_UPPER_FD_01( VURegs* VU, s32 info ) -{ - recVU_UPPER_FD_01_TABLE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); -} - -void recVU_UPPER_FD_10( VURegs* VU, s32 info ) -{ - recVU_UPPER_FD_10_TABLE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); -} - -void recVU_UPPER_FD_11( VURegs* VU, s32 info ) -{ - recVU_UPPER_FD_11_TABLE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); -} - -void recVULowerOP( VURegs* VU, s32 info ) -{ - recVULowerOP_OPCODE[ VU->code & 0x3f ]( VU, info ); -} - -void recVULowerOP_T3_00( VURegs* VU, s32 info ) -{ - recVULowerOP_T3_00_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); -} - -void recVULowerOP_T3_01( VURegs* VU, s32 info ) -{ - recVULowerOP_T3_01_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); -} - -void recVULowerOP_T3_10( VURegs* VU, s32 info ) -{ - recVULowerOP_T3_10_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); -} - -void recVULowerOP_T3_11( VURegs* VU, s32 info ) -{ - recVULowerOP_T3_11_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); -} - -void recVUunknown( VURegs* VU, s32 info ) -{ - SysPrintf("Unknown SVU micromode opcode called\n"); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +// Super VU recompiler - author: zerofrog(@gmail.com) + +#include "PrecompiledHeader.h" + +#include +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#endif + +#include "Common.h" + +#include "GS.h" +#include "R5900.h" +#include "VU.h" +#include "ix86/ix86.h" +#include "iR5900.h" + +#include "iVUzerorec.h" +#include "SamplProf.h" + +using namespace std; + +// temporary externs +extern void iDumpVU0Registers(); +extern void iDumpVU1Registers(); + +// SuperVURec optimization options, uncomment only for debugging purposes +#define SUPERVU_CACHING // vu programs are saved and queried via memcompare (should be no reason to disable this) +#define SUPERVU_WRITEBACKS // don't flush the writebacks after every block +#define SUPERVU_X86CACHING // use x86reg caching (faster) +#define SUPERVU_VIBRANCHDELAY // when integers are modified right before a branch that uses the integer, + // the old integer value is used in the branch + // fixes kh2 + +#define SUPERVU_PROPAGATEFLAGS // the correct behavior of VUs, for some reason superman breaks gfx with it on... + +#ifndef _DEBUG +#define SUPERVU_INTERCACHING // registers won't be flushed at block boundaries (faster) +#endif + +#define SUPERVU_CHECKCONDITION 0 // has to be 0!! + +#define VU_EXESIZE 0x00800000 + +#define _Imm11_ (s32)( (vucode & 0x400) ? (0xfffffc00 | (vucode & 0x3ff)) : (vucode & 0x3ff) ) +#define _UImm11_ (s32)(vucode & 0x7ff) + +#define _Ft_ ((VU->code >> 16) & 0x1F) // The rt part of the instruction register +#define _Fs_ ((VU->code >> 11) & 0x1F) // The rd part of the instruction register +#define _Fd_ ((VU->code >> 6) & 0x1F) // The sa part of the instruction register + +static const u32 QWaitTimes[] = { 6, 12 }; +static const u32 PWaitTimes[] = { 53, 43, 28, 23, 17, 11, 10 }; + +static u32 s_vuInfo; // info passed into rec insts + +static const u32 s_MemSize[2] = {VU0_MEMSIZE, VU1_MEMSIZE}; +static u8* s_recVUMem = NULL, *s_recVUPtr = NULL; + +// tables which are defined at the bottom of this massive file. +extern void (*recVU_UPPER_OPCODE[64])( VURegs* VU, s32 info ); +extern void (*recVU_LOWER_OPCODE[128])( VURegs* VU, s32 info ); + +#define INST_Q_READ 0x0001 // flush Q +#define INST_P_READ 0x0002 // flush P +#define INST_BRANCH_DELAY 0x0004 +#define INST_CLIP_WRITE 0x0040 // inst writes CLIP in the future +#define INST_STATUS_WRITE 0x0080 +#define INST_MAC_WRITE 0x0100 +#define INST_Q_WRITE 0x0200 +#define INST_CACHE_VI 0x0400 // write old vi value to s_VIBranchDelay + +// Let's tempt fate by defining two different constants with almost identical names +#define INST_DUMMY_ 0x8000 +#define INST_DUMMY 0x83c0 + +#define VFFREE_INVALID0 0x80000000 // (vffree[i]&0xf) is invalid + +#define FORIT(it, v) for(it = (v).begin(); it != (v).end(); ++(it)) + +#ifdef _DEBUG +u32 s_vucount=0; + +static u32 g_vu1lastrec = 0, skipparent = -1; +static u32 s_svulast = 0, s_vufnheader; +static u32 badaddrs[][2] = {0,0xffff}; +#endif + +union VURecRegs +{ + struct { + u16 reg; + u16 type; + }; + u32 id; +}; + +#define SUPERVU_XGKICKDELAY 1 // yes this is needed as default (wipeout) + +class VuBaseBlock; + +struct VuFunctionHeader +{ + struct RANGE + { + RANGE() : pmem(NULL) {} + + u16 start, size; + void* pmem; // all the mem + }; + + VuFunctionHeader() : pprogfunc(NULL), startpc(0xffffffff) {} + ~VuFunctionHeader() { + for(vector::iterator it = ranges.begin(); it != ranges.end(); ++it) { + free(it->pmem); + } + } + + // returns true if the checksum for the current mem is the same as this fn + bool IsSame(void* pmem); + + u32 startpc; + void* pprogfunc; + + vector ranges; +}; + +struct VuBlockHeader +{ + VuBaseBlock* pblock; + u32 delay; +}; + +// one vu inst (lower and upper) +class VuInstruction +{ +public: + VuInstruction() { memzero_obj(*this); nParentPc = -1; vicached = -1; } + + int nParentPc; // used for syncing with flag writes, -1 for no parent + + _vuopinfo info; + + _VURegsNum regs[2]; // [0] - lower, [1] - upper + u32 livevars[2]; // live variables right before this inst, [0] - inst, [1] - float + u32 addvars[2]; // live variables to add + u32 usedvars[2]; // set if var is used in the future including vars used in this inst + u32 keepvars[2]; + u16 pqcycles; // the number of cycles to stall if function writes to the regs + u16 type; // INST_ + + u32 pClipWrite, pMACWrite, pStatusWrite; // addrs to write the flags + u32 vffree[2]; + s8 vfwrite[2], vfread0[2], vfread1[2], vfacc[2]; + s8 vfflush[2]; // extra flush regs + s8 vicached; // if >= 0, then use the cached integer s_VIBranchDelay + + int SetCachedRegs(int upper, u32 vuxyz); + void Recompile(list::iterator& itinst, u32 vuxyz); +}; + +#define BLOCKTYPE_EOP 0x01 // at least one of the children of the block contains eop (or the block itself) +#define BLOCKTYPE_FUNCTION 0x02 +#define BLOCKTYPE_HASEOP 0x04 // last inst of block is an eop +#define BLOCKTYPE_MACFLAGS 0x08 +#define BLOCKTYPE_ANALYZED 0x40 +#define BLOCKTYPE_IGNORE 0x80 // special for recursive fns +#define BLOCKTYPE_ANALYZEDPARENT 0x100 + +// base block used when recompiling +class VuBaseBlock +{ +public: + typedef list LISTBLOCKS; + + VuBaseBlock(); + + // returns true if the leads to a EOP (ALL VU blocks must ret true) + void AssignVFRegs(); + void AssignVIRegs(int parent); + + list::iterator GetInstIterAtPc(int instpc); + void GetInstsAtPc(int instpc, list& listinsts); + + void Recompile(); + + u16 type; // BLOCKTYPE_ + u16 id; + u16 startpc; + u16 endpc; // first inst not in block + void* pcode; // x86 code pointer + void* pendcode; // end of the x86 code pointer + int cycles; + list insts; + list parents; + LISTBLOCKS blocks; // blocks branches to + u32* pChildJumps[4]; // addrs that need to be filled with the children's start addrs + // if highest bit is set, addr needs to be relational + u32 vuxyz; // corresponding bit is set if reg's xyz channels are used only + u32 vuxy; // corresponding bit is set if reg's xyz channels are used only + + _xmmregs startregs[XMMREGS], endregs[XMMREGS]; + int nStartx86, nEndx86; // indices into s_vecRegArray + + int allocX86Regs; + int prevFlagsOutOfBlock; +}; + +struct WRITEBACK +{ + WRITEBACK() : nParentPc(0), cycle(0) //, pStatusWrite(NULL), pMACWrite(NULL) + { + viwrite[0] = viwrite[1] = 0; + viread[0] = viread[1] = 0; + } + + void InitInst(VuInstruction* pinst, int cycle) const + { + u32 write = viwrite[0]|viwrite[1]; + pinst->type = ((write&(1<nParentPc = nParentPc; + pinst->info.cycle = cycle; + for(int i = 0; i < 2; ++i) { + pinst->regs[i].VIwrite = viwrite[i]; + pinst->regs[i].VIread = viread[i]; + } + } + + static int SortWritebacks(const WRITEBACK& w1, const WRITEBACK& w2) { + return w1.cycle < w2.cycle; + } + + int nParentPc; + int cycle; + u32 viwrite[2]; + u32 viread[2]; +}; + +struct VUPIPELINES +{ + fmacPipe fmac[8]; + fdivPipe fdiv; + efuPipe efu; + list< WRITEBACK > listWritebacks; +}; + +VuBaseBlock::VuBaseBlock() +{ + type = 0; endpc = 0; cycles = 0; pcode = NULL; id = 0; + memzero_obj(pChildJumps); + memzero_obj(startregs); + memzero_obj(endregs); + allocX86Regs = nStartx86 = nEndx86 = -1; + prevFlagsOutOfBlock = 0; +} + +#define SUPERVU_STACKSIZE 0x1000 + +static list s_listVUHeaders[2]; +static list* s_plistCachedHeaders[2] = {NULL, NULL}; +static VuFunctionHeader** recVUHeaders[2] = {NULL,NULL}; +static VuBlockHeader* recVUBlocks[2] = {NULL,NULL}; +static u8* recVUStack = NULL, *recVUStackPtr = NULL; +static vector<_x86regs> s_vecRegArray(128); + +static VURegs* VU = NULL; +static list s_listBlocks; +static u32 s_vu = 0; +static u32 s_UnconditionalDelay = 0; // 1 if there are two sequential branches and the last is unconditional +static u32 g_nLastBlockExecuted = 0; + +// Global functions +#ifdef __LINUX__ +extern "C" { +#endif +void* SuperVUGetProgram(u32 startpc, int vuindex); +void SuperVUCleanupProgram(u32 startpc, int vuindex); +#ifdef __LINUX__ +} +#endif +static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex); +static VuBaseBlock* SuperVUBuildBlocks(VuBaseBlock* parent, u32 startpc, const VUPIPELINES& pipes); +static void SuperVUInitLiveness(VuBaseBlock* pblock); +static void SuperVULivenessAnalysis(); +static void SuperVUEliminateDeadCode(); +static void SuperVUAssignRegs(); + +//void SuperVUFreeXMMreg(int xmmreg, int xmmtype, int reg); +#define SuperVUFreeXMMreg 0&& +void SuperVUFreeXMMregs(u32* livevars); + +static u32* SuperVUStaticAlloc(u32 size); +static void SuperVURecompile(); + +// allocate VU resources +void SuperVUAlloc(int vuindex) +{ + // The old -1 crap has been depreciated on this function. Please + // specify either 0 or 1, thanks. + jASSUME( vuindex >= 0 ); + + // upper 4 bits must be zero! + if( s_recVUMem == NULL ) + { + // upper 4 bits must be zero! + // Changed "first try base" to 0xb800000, since 0x0c000000 liked to fail a lot. (air) + s_recVUMem = SysMmapEx(0x0e000000, VU_EXESIZE, 0x10000000, "SuperVUAlloc"); + + if( s_recVUMem == NULL ) + { + throw Exception::OutOfMemory( + fmt_string( "SuperVU Error > failed to allocate recompiler memory (addr: 0x%x)", (u32)s_recVUMem ) + ); + } + + ProfilerRegisterSource( "VURec", s_recVUMem, VU_EXESIZE); + + if( recVUStack == NULL ) recVUStack = new u8[SUPERVU_STACKSIZE * 4]; + } + + if( vuindex >= 0 ) + { + jASSUME( s_recVUMem != NULL ); + + if( recVUHeaders[vuindex] == NULL ) + recVUHeaders[vuindex] = new VuFunctionHeader* [s_MemSize[vuindex]/8]; + if( recVUBlocks[vuindex] == NULL ) + recVUBlocks[vuindex] = new VuBlockHeader[s_MemSize[vuindex]/8]; + if( s_plistCachedHeaders[vuindex] == NULL ) + s_plistCachedHeaders[vuindex] = new list[s_MemSize[vuindex]/8]; + } +} + +// destroy VU resources +void SuperVUDestroy(int vuindex) +{ + list::iterator it; + + if( vuindex < 0 ) + { + SuperVUDestroy(0); + SuperVUDestroy(1); + ProfilerTerminateSource( "VURec" ); + SafeSysMunmap(s_recVUMem, VU_EXESIZE); + safe_delete_array( recVUStack ); + } + else + { + safe_delete_array( recVUHeaders[vuindex] ); + safe_delete_array( recVUBlocks[vuindex] ); + + if( s_plistCachedHeaders[vuindex] != NULL ) { + for(u32 j = 0; j < s_MemSize[vuindex]/8; ++j) { + FORIT(it, s_plistCachedHeaders[vuindex][j]) delete *it; + s_plistCachedHeaders[vuindex][j].clear(); + } + safe_delete_array( s_plistCachedHeaders[vuindex] ); + } + + FORIT(it, s_listVUHeaders[vuindex]) delete *it; + s_listVUHeaders[vuindex].clear(); + } +} + +// reset VU +void SuperVUReset(int vuindex) +{ +#ifdef _DEBUG + s_vucount = 0; +#endif + + if( s_recVUMem == NULL ) + return; + + //jASSUME( s_recVUMem != NULL ); + + if( vuindex < 0 ) + { + DbgCon::Status( "SuperVU reset > Resetting recompiler memory and structures." ); + + // Does this cause problems on VU recompiler resets? It could, if the VU works like + // the EE used to, and actually tries to re-enter the recBlock after issuing a clear. (air) + + //memset_8<0xcd, VU_EXESIZE>(s_recVUMem); + memzero_ptr(recVUStack); + + s_recVUPtr = s_recVUMem; + } + else + { + DbgCon::Status( "SuperVU reset [VU%d] > Resetting the recs and junk", params vuindex ); + list::iterator it; + if( recVUHeaders[vuindex] ) memset( recVUHeaders[vuindex], 0, sizeof(VuFunctionHeader*) * (s_MemSize[vuindex]/8) ); + if( recVUBlocks[vuindex] ) memset( recVUBlocks[vuindex], 0, sizeof(VuBlockHeader) * (s_MemSize[vuindex]/8) ); + + if( s_plistCachedHeaders[vuindex] != NULL ) { + for(u32 j = 0; j < s_MemSize[vuindex]/8; ++j) { + FORIT(it, s_plistCachedHeaders[vuindex][j]) delete *it; + s_plistCachedHeaders[vuindex][j].clear(); + } + } + + FORIT(it, s_listVUHeaders[vuindex]) delete *it; + s_listVUHeaders[vuindex].clear(); + } +} + +// clear the block and any joining blocks +void __fastcall SuperVUClear(u32 startpc, u32 size, int vuindex) +{ + vector::iterator itrange; + list::iterator it = s_listVUHeaders[vuindex].begin(); + u32 endpc = startpc+(size+(8-(size&7))); // Adding this code to ensure size is always a multiple of 8, it can be simplified to startpc+size if size is always a multiple of 8 (cottonvibes) + while( it != s_listVUHeaders[vuindex].end() ) { + + // for every fn, check if it has code in the range + FORIT(itrange, (*it)->ranges) { + if( startpc < (u32)itrange->start+itrange->size && itrange->start < endpc ) + break; + } + + if( itrange != (*it)->ranges.end() ) { + recVUHeaders[vuindex][(*it)->startpc/8] = NULL; +#ifdef SUPERVU_CACHING + list* plist = &s_plistCachedHeaders[vuindex][(*it)->startpc/8]; + plist->push_back(*it); + if( plist->size() > 10 ) { + // list is too big, delete + delete plist->front(); + plist->pop_front(); + } + it = s_listVUHeaders[vuindex].erase(it); +#else + delete *it; + it = s_listVUHeaders[vuindex].erase(it); +#endif + } + else ++it; + } +} + +static VuFunctionHeader* s_pFnHeader = NULL; +static VuBaseBlock* s_pCurBlock = NULL; +static VuInstruction* s_pCurInst = NULL; +static u32 s_StatusRead = 0, s_MACRead = 0, s_ClipRead = 0; // read addrs +static u32 s_PrevStatusWrite = 0, s_PrevMACWrite = 0, s_PrevClipWrite = 0, s_PrevIWrite = 0; +static u32 s_WriteToReadQ = 0; + +static u32 s_VIBranchDelay = 0; //Value of register to use in a vi branch delayed situation + + +u32 s_TotalVUCycles; // total cycles since start of program execution + + +u32 SuperVUGetVIAddr(int reg, int read) +{ + assert( s_pCurInst != NULL ); + + switch(reg) { + case REG_STATUS_FLAG: + { + u32 addr = (read==2) ? s_PrevStatusWrite : (read ? s_StatusRead : s_pCurInst->pStatusWrite); + assert(!read || addr != 0); + return addr; + } + case REG_MAC_FLAG: + { + return (read==2) ? s_PrevMACWrite : (read ? s_MACRead : s_pCurInst->pMACWrite); + } + case REG_CLIP_FLAG: + { + u32 addr = (read==2) ? s_PrevClipWrite : (read ? s_ClipRead : s_pCurInst->pClipWrite); + assert( !read || addr != 0 ); + return addr; + } + case REG_Q: return (read || s_WriteToReadQ) ? (uptr)&VU->VI[REG_Q] : (uptr)&VU->q; + case REG_P: return read ? (uptr)&VU->VI[REG_P] : (uptr)&VU->p; + case REG_I: return s_PrevIWrite; + } + +#ifdef SUPERVU_VIBRANCHDELAY + if( (read != 0) && (s_pCurInst->regs[0].pipe == VUPIPE_BRANCH) && (s_pCurInst->vicached >= 0) && (s_pCurInst->vicached == reg) ) { + return (uptr)&s_VIBranchDelay; // test for branch delays + } +#endif + + return (uptr)&VU->VI[reg]; +} + +void SuperVUDumpBlock(list& blocks, int vuindex) +{ + FILE *f; + char filename[ g_MaxPath ], str[256]; + u32 *mem; + u32 i; + +#ifdef _WIN32 + CreateDirectory("dumps", NULL); + sprintf_s( filename, g_MaxPath, "dumps\\svu%c_%.4X.txt", s_vu?'1':'0', s_pFnHeader->startpc ); +#else + mkdir("dumps", 0755); + sprintf( filename, "dumps/svu%c_%.4X.txt", s_vu?'1':'0', s_pFnHeader->startpc ); +#endif + //SysPrintf( "dump1 %x => %s\n", s_pFnHeader->startpc, filename ); + + f = fopen( filename, "w" ); + + fprintf(f, "Format: upper_inst lower_inst\ntype f:vf_live_vars vf_used_vars i:vi_live_vars vi_used_vars inst_cycle pq_inst\n"); + fprintf(f, "Type: %.2x - qread, %.2x - pread, %.2x - clip_write, %.2x - status_write\n" + "%.2x - mac_write, %.2x -qflush\n", + INST_Q_READ, INST_P_READ, INST_CLIP_WRITE, INST_STATUS_WRITE, INST_MAC_WRITE, INST_Q_WRITE); + fprintf(f, "XMM: Upper: read0 read1 write acc temp; Lower: read0 read1 write acc temp\n\n"); + + list::iterator itblock; + list::iterator itinst; + VuBaseBlock::LISTBLOCKS::iterator itchild; + + FORIT(itblock, blocks) { + fprintf(f, "block:%c %x-%x; children: ", ((*itblock)->type&BLOCKTYPE_HASEOP)?'*':' ', + (*itblock)->startpc, (*itblock)->endpc-8); + FORIT(itchild, (*itblock)->blocks) { + fprintf(f, "%x ", (*itchild)->startpc); + } + fprintf(f, "; vuxyz = %x, vuxy = %x\n", (*itblock)->vuxyz&(*itblock)->insts.front().usedvars[1], + (*itblock)->vuxy&(*itblock)->insts.front().usedvars[1]); + + itinst = (*itblock)->insts.begin(); + i = (*itblock)->startpc; + while(itinst != (*itblock)->insts.end() ) { + assert( i <= (*itblock)->endpc ); + if( itinst->type & INST_DUMMY ) { + if( itinst->nParentPc >= 0 && !(itinst->type&INST_DUMMY_)) { + // search for the parent + fprintf(f, "writeback 0x%x (%x)\n", itinst->type, itinst->nParentPc); + } + } + else { + mem = (u32*)&VU->Micro[i]; + char* pstr = disVU1MicroUF( mem[1], i+4 ); + fprintf(f, "%.4x: %-40s", i, pstr); + if( mem[1] & 0x80000000 ) fprintf(f, " I=%f(%.8x)\n", *(float*)mem, mem[0]); + else fprintf(f, "%s\n", disVU1MicroLF( mem[0], i )); + i += 8; + } + + ++itinst; + } + + fprintf(f, "\n"); + + _x86regs* pregs; + if( (*itblock)->nStartx86 >= 0 || (*itblock)->nEndx86 >= 0 ) { + fprintf(f, "X86: AX CX DX BX SP BP SI DI\n"); + } + + if( (*itblock)->nStartx86 >= 0 ) { + pregs = &s_vecRegArray[(*itblock)->nStartx86]; + fprintf(f, "STR: "); + for(i = 0; i < X86REGS; ++i) { + if( pregs[i].inuse ) fprintf(f, "%.2d ", pregs[i].reg); + else fprintf(f, "-1 "); + } + fprintf(f, "\n"); + } + + if( (*itblock)->nEndx86 >= 0 ) { + fprintf(f, "END: "); + pregs = &s_vecRegArray[(*itblock)->nEndx86]; + for(i = 0; i < X86REGS; ++i) { + if( pregs[i].inuse ) fprintf(f, "%.2d ", pregs[i].reg); + else fprintf(f, "-1 "); + } + fprintf(f, "\n"); + } + + itinst = (*itblock)->insts.begin(); + for ( i = (*itblock)->startpc; i < (*itblock)->endpc; ++itinst ) { + + if( itinst->type & INST_DUMMY ) { + } + else { + sprintf(str, "%.4x:%x f:%.8x_%.8x", i, itinst->type, itinst->livevars[1], itinst->usedvars[1]); + fprintf(f, "%-46s i:%.8x_%.8x c:%d pq:%d\n", str, + itinst->livevars[0], itinst->usedvars[0], (int)itinst->info.cycle, (int)itinst->pqcycles ); + + sprintf(str, "XMM r0:%d r1:%d w:%d a:%d t:%x;", + itinst->vfread0[1], itinst->vfread1[1], itinst->vfwrite[1], itinst->vfacc[1], itinst->vffree[1]); + fprintf(f, "%-46s r0:%d r1:%d w:%d a:%d t:%x\n", str, + itinst->vfread0[0], itinst->vfread1[0], itinst->vfwrite[0], itinst->vfacc[0], itinst->vffree[0]); + i += 8; + } + } + +#ifdef __LINUX__ + // dump the asm + if( (*itblock)->pcode != NULL ) { + char command[255]; + FILE* fasm = fopen( "mydump1", "wb" ); + //SysPrintf("writing: %x, %x\n", (*itblock)->startpc, (uptr)(*itblock)->pendcode - (uptr)(*itblock)->pcode); + fwrite( (*itblock)->pcode, 1, (uptr)(*itblock)->pendcode - (uptr)(*itblock)->pcode, fasm ); + fclose( fasm ); + sprintf( command, "objdump -D --target=binary --architecture=i386 -M intel mydump1 > tempdump"); + system( command ); + fasm = fopen("tempdump", "r"); + // read all of it and write it to f + fseek(fasm, 0, SEEK_END); + vector vbuffer(ftell(fasm)); + fseek(fasm, 0, SEEK_SET); + fread(&vbuffer[0], vbuffer.size(), 1, fasm); + + fprintf(f, "\n\n"); + fwrite(&vbuffer[0], vbuffer.size(), 1, f); + fclose(fasm); + } +#endif + + fprintf(f, "\n---------------\n"); + } + + fclose( f ); +} + +LARGE_INTEGER svubase, svufinal; +static u64 svutime; + +// uncomment to count svu exec time +//#define SUPERVU_COUNT + +// Private methods +void* SuperVUGetProgram(u32 startpc, int vuindex) +{ + assert( startpc < s_MemSize[vuindex] ); + assert( (startpc%8) == 0 ); + assert( recVUHeaders[vuindex] != NULL ); + VuFunctionHeader** pheader = &recVUHeaders[vuindex][startpc/8]; + + if( *pheader == NULL ) { +#ifdef _DEBUG +// if( vuindex ) VU1.VI[REG_TPC].UL = startpc; +// else VU0.VI[REG_TPC].UL = startpc; +// __Log("VU: %x\n", startpc); +// iDumpVU1Registers(); +// vudump |= 2; +#endif + + // measure run time + //QueryPerformanceCounter(&svubase); + +#ifdef SUPERVU_CACHING + void* pmem = (vuindex&1) ? VU1.Micro : VU0.Micro; + // check if program exists in cache + list::iterator it; + FORIT(it, s_plistCachedHeaders[vuindex][startpc/8]) { + if( (*it)->IsSame(pmem) ) { + // found, transfer to regular lists + void* pfn = (*it)->pprogfunc; + recVUHeaders[vuindex][startpc/8] = *it; + s_listVUHeaders[vuindex].push_back(*it); + s_plistCachedHeaders[vuindex][startpc/8].erase(it); + return pfn; + } + } +#endif + + *pheader = SuperVURecompileProgram(startpc, vuindex); + + if( *pheader == NULL ) { + assert( s_TotalVUCycles > 0 ); + if( vuindex ) VU1.VI[REG_TPC].UL = startpc; + else VU0.VI[REG_TPC].UL = startpc; + return (void*)SuperVUEndProgram; + } + + //QueryPerformanceCounter(&svufinal); + //svutime += (u32)(svufinal.QuadPart-svubase.QuadPart); + + assert( (*pheader)->pprogfunc != NULL ); + } + //else assert( (*pheader)->IsSame((vuindex&1) ? VU1.Micro : VU0.Micro) ); + + assert( (*pheader)->startpc == startpc ); + + return (*pheader)->pprogfunc; +} + +bool VuFunctionHeader::IsSame(void* pmem) +{ +#ifdef SUPERVU_CACHING + //u32 checksum[2]; + vector::iterator it; + FORIT(it, ranges) { + //memxor_mmx(checksum, (u8*)pmem+it->start, it->size); + //if( checksum[0] != it->checksum[0] || checksum[1] != it->checksum[1] ) + // return false; + // memcmp_mmx doesn't work on x86-64 machines +#if defined(_MSC_VER) + if( memcmp_mmx((u8*)pmem+it->start, it->pmem, it->size) ) +#else + if( memcmp((u8*)pmem+it->start, it->pmem, it->size) ) +#endif + return false; + } +#endif + return true; +} + +list::iterator VuBaseBlock::GetInstIterAtPc(int instpc) +{ + assert( instpc >= 0 ); + + u32 curpc = startpc; + list::iterator it; + for(it = insts.begin(); it != insts.end(); ++it) { + if( it->type & INST_DUMMY ) + continue; + + if( curpc == instpc ) + break; + curpc += 8; + } + + if( it != insts.end() ) + return it; + + assert( 0 ); + return insts.begin(); +} + +void VuBaseBlock::GetInstsAtPc(int instpc, list& listinsts) +{ + assert( instpc >= 0 ); + + listinsts.clear(); + + u32 curpc = startpc; + list::iterator it; + for(it = insts.begin(); it != insts.end(); ++it) { + if( it->type & INST_DUMMY ) + continue; + + if( curpc == instpc ) + break; + curpc += 8; + } + + if( it != insts.end() ) { + listinsts.push_back(&(*it)); + return; + } + + // look for the pc in other blocks + for(list::iterator itblock = s_listBlocks.begin(); itblock != s_listBlocks.end(); ++itblock) { + if( *itblock == this ) + continue; + + if( instpc >= (*itblock)->startpc && instpc < (*itblock)->endpc ) { + listinsts.push_back(&(*(*itblock)->GetInstIterAtPc(instpc))); + } + } + + assert(listinsts.size()>0); +} + +static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex) +{ + assert( vuindex < 2 ); + assert( s_recVUPtr != NULL ); + //SysPrintf("svu%c rec: %x\n", '0'+vuindex, startpc); + + // if recPtr reached the mem limit reset whole mem + if ( ( (uptr)s_recVUPtr - (uptr)s_recVUMem ) >= VU_EXESIZE-0x40000 ) { + //SysPrintf("SuperVU reset mem\n"); + SuperVUReset(0); + SuperVUReset(1); + SuperVUReset(-1); + if( s_TotalVUCycles > 0 ) { + // already executing, so return NULL + return NULL; + } + } + + list::iterator itblock; + + s_vu = vuindex; + VU = s_vu ? &VU1 : &VU0; + s_pFnHeader = new VuFunctionHeader(); + s_listVUHeaders[vuindex].push_back(s_pFnHeader); + s_pFnHeader->startpc = startpc; + + memset( recVUBlocks[s_vu], 0, sizeof(VuBlockHeader) * (s_MemSize[s_vu]/8) ); + + // analyze the global graph + s_listBlocks.clear(); + VUPIPELINES pipes; + memzero_obj(pipes.fmac); + memzero_obj(pipes.fdiv); + memzero_obj(pipes.efu); + SuperVUBuildBlocks(NULL, startpc, pipes); + + // fill parents + VuBaseBlock::LISTBLOCKS::iterator itchild; + FORIT(itblock, s_listBlocks) { + FORIT(itchild, (*itblock)->blocks) + (*itchild)->parents.push_back(*itblock); + + //(*itblock)->type &= ~(BLOCKTYPE_IGNORE|BLOCKTYPE_ANALYZED); + } + + assert( s_listBlocks.front()->startpc == startpc ); + s_listBlocks.front()->type |= BLOCKTYPE_FUNCTION; + + FORIT(itblock, s_listBlocks) { + SuperVUInitLiveness(*itblock); + } + + SuperVULivenessAnalysis(); + SuperVUEliminateDeadCode(); + SuperVUAssignRegs(); + +#ifdef _DEBUG + if( (s_vu && (vudump&1)) || (!s_vu && (vudump&16)) ) + SuperVUDumpBlock(s_listBlocks, s_vu); +#endif + + // code generation + x86SetPtr(s_recVUPtr); + branch = 0; + + SuperVURecompile(); + + s_recVUPtr = x86Ptr; + + // set the function's range + VuFunctionHeader::RANGE r; + s_pFnHeader->ranges.reserve(s_listBlocks.size()); + + FORIT(itblock, s_listBlocks) { + r.start = (*itblock)->startpc; + r.size = (*itblock)->endpc-(*itblock)->startpc; +#ifdef SUPERVU_CACHING + //memxor_mmx(r.checksum, &VU->Micro[r.start], r.size); + r.pmem = malloc(r.size); + memcpy_fast(r.pmem, &VU->Micro[r.start], r.size); +#endif + s_pFnHeader->ranges.push_back(r); + } + +#if defined(_DEBUG) && defined(__LINUX__) + // dump at the end to capture the actual code + if( (s_vu && (vudump&1)) || (!s_vu && (vudump&16)) ) + SuperVUDumpBlock(s_listBlocks, s_vu); +#endif + + // destroy + for(list::iterator itblock = s_listBlocks.begin(); itblock != s_listBlocks.end(); ++itblock) { + delete *itblock; + } + s_listBlocks.clear(); + + assert( s_recVUPtr < s_recVUMem+VU_EXESIZE ); + + return s_pFnHeader; +} + +static int _recbranchAddr(u32 vucode) { + s32 bpc = pc + (_Imm11_ << 3); +/* + if ( bpc < 0 ) { + SysPrintf("zerorec branch warning: bpc < 0 ( %x ); Using unsigned imm11\n", bpc); + bpc = pc + (_UImm11_ << 3); + }*/ + bpc &= (s_MemSize[s_vu]-1); + + return bpc; +} + +// return inst that flushes everything +static VuInstruction SuperVUFlushInst() +{ + VuInstruction inst; + // don't need to raed q/p + inst.type = INST_DUMMY_;//|INST_Q_READ|INST_P_READ; + return inst; +} + +void SuperVUAddWritebacks(VuBaseBlock* pblock, const list& listWritebacks) +{ +#ifdef SUPERVU_WRITEBACKS + // regardless of repetition, add the pipes (for selfloops) + list::const_iterator itwriteback = listWritebacks.begin(); + list::iterator itinst = pblock->insts.begin(), itinst2; + + while(itwriteback != listWritebacks.end()) { + if( itinst != pblock->insts.end() && (itinst->info.cycle < itwriteback->cycle || (itinst->type&INST_DUMMY) ) ) { + ++itinst; + continue; + } + + itinst2 = pblock->insts.insert(itinst, VuInstruction()); + itwriteback->InitInst(&(*itinst2), vucycle); + ++itwriteback; + } +#endif +} + +static VuBaseBlock* SuperVUBuildBlocks(VuBaseBlock* parent, u32 startpc, const VUPIPELINES& pipes) +{ + // check if block already exists + //SysPrintf("startpc %x\n", startpc); + startpc &= (s_vu ? 0x3fff : 0xfff); + VuBlockHeader* pbh = &recVUBlocks[s_vu][startpc/8]; + + if ( pbh->pblock != NULL ) { + + VuBaseBlock* pblock = pbh->pblock; + list::iterator itinst; + + if( pblock->startpc == startpc ) { + SuperVUAddWritebacks(pblock, pipes.listWritebacks); + return pblock; + } + + // have to divide the blocks, pnewblock is first block + assert( startpc > pblock->startpc ); + assert( startpc < pblock->endpc ); + + u32 dummyinst = (startpc-pblock->startpc)>>3; + + // count inst non-dummy insts + itinst = pblock->insts.begin(); + int cycleoff = 0; + + while(dummyinst > 0) { + if( itinst->type & INST_DUMMY ) + ++itinst; + else { + cycleoff = itinst->info.cycle; + ++itinst; + --dummyinst; + } + } + + // NOTE: still leaves insts with their writebacks in different blocks + while( itinst->type & INST_DUMMY ) + ++itinst; + + // the difference in cycles between dummy insts (naruto utlimate ninja) + int cyclediff = 0; + if( parent == pblock ) + cyclediff = itinst->info.cycle-cycleoff; + cycleoff = itinst->info.cycle; + + // new block + VuBaseBlock* pnewblock = new VuBaseBlock(); + s_listBlocks.push_back(pnewblock); + + pnewblock->startpc = startpc; + pnewblock->endpc = pblock->endpc; + pnewblock->cycles = pblock->cycles-cycleoff+cyclediff; + + pnewblock->blocks.splice(pnewblock->blocks.end(), pblock->blocks); + pnewblock->insts.splice(pnewblock->insts.end(), pblock->insts, itinst, pblock->insts.end()); + pnewblock->type = pblock->type; + + // any writebacks in the next 3 cycles also belong to original block +// for(itinst = pnewblock->insts.begin(); itinst != pnewblock->insts.end(); ) { +// if( (itinst->type & INST_DUMMY) && itinst->nParentPc >= 0 && itinst->nParentPc < (int)startpc ) { +// +// if( !(itinst->type & INST_Q_WRITE) ) +// pblock->insts.push_back(*itinst); +// itinst = pnewblock->insts.erase(itinst); +// continue; +// } +// +// ++itinst; +// } + + pbh = &recVUBlocks[s_vu][startpc/8]; + for(u32 inst = startpc; inst < pblock->endpc; inst += 8) { + if( pbh->pblock == pblock ) + pbh->pblock = pnewblock; + ++pbh; + } + + FORIT(itinst, pnewblock->insts) + itinst->info.cycle -= cycleoff; + + SuperVUAddWritebacks(pnewblock, pipes.listWritebacks); + + // old block + pblock->blocks.push_back(pnewblock); + pblock->endpc = startpc; + pblock->cycles = cycleoff; + pblock->type &= BLOCKTYPE_MACFLAGS; + //pblock->insts.push_back(SuperVUFlushInst()); //don't need + + return pnewblock; + } + + VuBaseBlock* pblock = new VuBaseBlock(); + s_listBlocks.push_back(pblock); + + int i = 0; + branch = 0; + pc = startpc; + pblock->startpc = startpc; + + // clear stalls (might be a prob) + memcpy(VU->fmac, pipes.fmac, sizeof(pipes.fmac)); + memcpy(&VU->fdiv, &pipes.fdiv, sizeof(pipes.fdiv)); + memcpy(&VU->efu, &pipes.efu, sizeof(pipes.efu)); +// memset(VU->fmac, 0, sizeof(VU->fmac)); +// memset(&VU->fdiv, 0, sizeof(VU->fdiv)); +// memset(&VU->efu, 0, sizeof(VU->efu)); + + vucycle = 0; + + u8 macflags = 0; + + list< WRITEBACK > listWritebacks; + list< WRITEBACK >::iterator itwriteback; + list::iterator itinst; + u32 hasSecondBranch = 0; + u32 needFullStatusFlag = 0; + +#ifdef SUPERVU_WRITEBACKS + listWritebacks = pipes.listWritebacks; +#endif + + // first analysis pass for status flags + while(1) { + u32* ptr = (u32*)&VU->Micro[pc]; + pc += 8; + int prevbranch = branch; + + if( ptr[1] & 0x40000000 ) + branch = 1; + + if( !(ptr[1] & 0x80000000) ) { // not I + switch( ptr[0]>>25 ) { + case 0x24: // jr + case 0x25: // jalr + case 0x20: // B + case 0x21: // BAL + case 0x28: // IBEQ + case 0x2f: // IBGEZ + case 0x2d: // IBGTZ + case 0x2e: // IBLEZ + case 0x2c: // IBLTZ + case 0x29: // IBNE + branch = 1; + break; + + case 0x14: // fseq + case 0x17: // fsor + //needFullStatusFlag = 2; + break; + + case 0x16: // fsand + if( (ptr[0]&0xc0) ) { + // sometimes full sticky bits are needed (simple series 2000 - oane chapara) + //SysPrintf("needSticky: %x-%x\n", s_pFnHeader->startpc, startpc); + needFullStatusFlag = 2; + } + break; + } + } + + if( prevbranch ) + break; + + if( pc >= s_MemSize[s_vu] ) { + Console::Error( "inf vu0 prog %x",params startpc); + break; + } + } + + // second full pass + pc = startpc; + branch = 0; + VuInstruction* pprevinst=NULL, *ppprevinst=NULL, *pinst = NULL; + + while(1) { + + if( pc == s_MemSize[s_vu] ) { + branch |= 8; + break; + } + + if( !branch && pbh->pblock != NULL ) { + pblock->blocks.push_back(pbh->pblock); + break; + } + + int prevbranch = branch; + + if( !prevbranch ) { + pbh->pblock = pblock; + } + else assert( prevbranch || pbh->pblock == NULL); + + pblock->insts.push_back(VuInstruction()); + + ppprevinst = pprevinst; + pprevinst = pinst; + pinst = &pblock->insts.back(); + SuperVUAnalyzeOp(VU, &pinst->info, pinst->regs); + +#ifdef SUPERVU_VIBRANCHDELAY + if( pinst->regs[0].pipe == VUPIPE_BRANCH && pblock->insts.size() > 1 ) { + + if( pprevinst != NULL && pprevinst->info.cycle+1==pinst->info.cycle && + (pprevinst->regs[0].pipe == VUPIPE_IALU||pprevinst->regs[0].pipe == VUPIPE_FMAC) && ((pprevinst->regs[0].VIwrite & pinst->regs[0].VIread) & 0xffff) + && !(pprevinst->regs[0].VIread&((1<Micro[pc-16]; + + // check for the previous instruction. If that has the same register used, then have a 2 cycle delay! + // (monsterhouse has sqi vi05, sqi vi05, ibeq vi05, vi03). The ibeq should read the vi05 before the first sqi + if( ppprevinst != NULL && ppprevinst->info.cycle+2==pinst->info.cycle && (ppprevinst->regs[0].pipe == VUPIPE_FMAC||ppprevinst->regs[0].pipe == VUPIPE_IALU) && + ((ppprevinst->regs[0].VIwrite & pinst->regs[0].VIread) & 0xffff) && + ((ppprevinst->regs[0].VIwrite & pinst->regs[0].VIread) & 0xffff) == ((ppprevinst->regs[0].VIwrite & pprevinst->regs[0].VIread) & 0xffff) && + !(ppprevinst->regs[0].VIread&((1<startpc); + + // ignore if prev instruction is ILW or ILWR (xenosaga 2) + lowercode = *(int*)&VU->Micro[pc-24]; + pdelayinst = ppprevinst; + } + + + //SysPrintf("vurec: %x\n", pc); + // ignore if prev instruction is ILW or ILWR (xenosaga 2) + if( (lowercode>>25) != 4 // ILW + && !((lowercode>>25) == 0x40 && (lowercode&0x3ff)==0x3fe) ) { // ILWR + + //SysPrintf("branchdelay: %x: %x\n", s_pFnHeader->startpc, pc-8); + + // share the same register + if (CHECK_VUBRANCHHACK) pinst->type |= INST_CACHE_VI; + else pdelayinst->type |= INST_CACHE_VI; + + // find the correct register + u32 mask = pdelayinst->regs[0].VIwrite & pinst->regs[0].VIread; + for(int i = 0; i < 16; ++i) { + if( mask & (1<vicached = i; + break; + } + } + + pinst->vicached = pdelayinst->vicached; + } + } + } +#endif + + if( prevbranch ) { + if( pinst->regs[0].pipe == VUPIPE_BRANCH ) + hasSecondBranch = 1; + pinst->type |= INST_BRANCH_DELAY; + } + + // check write back + for(itwriteback = listWritebacks.begin(); itwriteback != listWritebacks.end(); ) { + if( pinst->info.cycle >= itwriteback->cycle ) { + itinst = pblock->insts.insert(--pblock->insts.end(), VuInstruction()); + itwriteback->InitInst(&(*itinst), pinst->info.cycle); + itwriteback = listWritebacks.erase(itwriteback); + } + else ++itwriteback; + } + + // add new writebacks + WRITEBACK w; + const u32 allflags = (1<regs[j].VIwrite & allflags; + + if( pinst->info.macflag & VUOP_WRITE ) w.viwrite[1] |= (1<info.statusflag & VUOP_WRITE ) w.viwrite[1] |= (1<info.macflag|pinst->info.statusflag) & VUOP_READ ) + macflags = 1; + if( pinst->regs[0].VIread & ((1<regs[1].pipe == VUPIPE_FMAC && (pinst->regs[1].VFwrite==0&&!(pinst->regs[1].VIwrite&(1<regs[0].VIread |= (1<VIwrite |= lregs->VIwrite & (1<info.statusflag&VUOP_WRITE)&&!(pinst->regs[0].VIwrite&(1<regs[j].VIread & allflags; + + if( (pinst->regs[j].VIread&(1<regs[j].VIwrite&(1<regs[j].VIread &= ~(1<regs[j].VIread&(1<regs[j].VIwrite&(1<regs[j].VIread &= ~(1<regs[j].VIwrite &= ~allflags; + } + + if( pinst->info.macflag & VUOP_READ) w.viread[1] |= 1<info.statusflag & VUOP_READ) w.viread[1] |= 1<info.cycle+4; + listWritebacks.push_back(w); + } + + if( pinst->info.q&VUOP_READ ) pinst->type |= INST_Q_READ; + if( pinst->info.p&VUOP_READ ) pinst->type |= INST_P_READ; + + if( pinst->info.q&VUOP_WRITE ) { + pinst->pqcycles = QWaitTimes[pinst->info.pqinst]+1; + + memset(&w, 0, sizeof(w)); + w.nParentPc = pc-8; + w.cycle = pinst->info.cycle+pinst->pqcycles; + w.viwrite[0] = 1<info.p&VUOP_WRITE ) + pinst->pqcycles = PWaitTimes[pinst->info.pqinst]+1; + + if( prevbranch ) { + break; + } + + // make sure there is always a branch + // sensible soccer overflows on vu0, so increase the limit... + if( (s_vu==1 && i >= 0x799) || (s_vu==0 && i >= 0x201) ) { + Console::Error("VuRec base block doesn't terminate!"); + assert(0); + break; + } + + i++; + pbh++; + } + + if( macflags ) + pblock->type |= BLOCKTYPE_MACFLAGS; + + pblock->endpc = pc; + u32 lastpc = pc; + + pblock->cycles = vucycle; + +#ifdef SUPERVU_WRITEBACKS + if( !branch || (branch&8) ) +#endif + { + // flush writebacks + if( listWritebacks.size() > 0 ) { + listWritebacks.sort(WRITEBACK::SortWritebacks); + for(itwriteback = listWritebacks.begin(); itwriteback != listWritebacks.end(); ++itwriteback) { + if( itwriteback->viwrite[0] & (1<insts.push_back(VuInstruction()); + itwriteback->InitInst(&pblock->insts.back(), vucycle); + } + + listWritebacks.clear(); + } + } + + if( !branch ) + return pblock; + + if( branch & 8 ) { + // what if also a jump? + pblock->type |= BLOCKTYPE_EOP|BLOCKTYPE_HASEOP; + + // add an instruction to flush p and q (if written) + pblock->insts.push_back(SuperVUFlushInst()); + return pblock; + } + + // it is a (cond) branch or a jump + u32 vucode = *(u32*)(VU->Micro+lastpc-16); + int bpc = _recbranchAddr(vucode)-8; + + VUPIPELINES newpipes; + memcpy(newpipes.fmac, VU->fmac, sizeof(newpipes.fmac)); + memcpy(&newpipes.fdiv, &VU->fdiv, sizeof(newpipes.fdiv)); + memcpy(&newpipes.efu, &VU->efu, sizeof(newpipes.efu)); + + for(i = 0; i < 8; ++i) newpipes.fmac[i].sCycle -= vucycle; + newpipes.fdiv.sCycle -= vucycle; + newpipes.efu.sCycle -= vucycle; + + if( listWritebacks.size() > 0 ) { + // flush all when jumping, send down the pipe when in branching + bool bFlushWritebacks = (vucode>>25)==0x24||(vucode>>25)==0x25;//||(vucode>>25)==0x20||(vucode>>25)==0x21; + + listWritebacks.sort(WRITEBACK::SortWritebacks); + for(itwriteback = listWritebacks.begin(); itwriteback != listWritebacks.end(); ++itwriteback) { + if( itwriteback->viwrite[0] & (1<cycle < vucycle || bFlushWritebacks ) { + pblock->insts.push_back(VuInstruction()); + itwriteback->InitInst(&pblock->insts.back(), vucycle); + } + else { + newpipes.listWritebacks.push_back(*itwriteback); + newpipes.listWritebacks.back().cycle -= vucycle; + } + } + } + + if( newpipes.listWritebacks.size() > 0 ) // other blocks might read the mac flags + pblock->type |= BLOCKTYPE_MACFLAGS; + + u32 firstbranch = vucode>>25; + switch(firstbranch) { + case 0x24: // jr + pblock->type |= BLOCKTYPE_EOP; // jump out of procedure, since not returning, set EOP + pblock->insts.push_back(SuperVUFlushInst()); + firstbranch = 0xff; //Non-Conditional Jump + break; + + case 0x25: // jalr + { + // linking, so will return to procedure + pblock->insts.push_back(SuperVUFlushInst()); + + VuBaseBlock* pjumpblock = SuperVUBuildBlocks(pblock, lastpc, newpipes); + + // update pblock since could have changed + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + assert( pblock != NULL ); + + pblock->blocks.push_back(pjumpblock); + firstbranch = 0xff; //Non-Conditional Jump + break; + } + case 0x20: // B + { + VuBaseBlock* pbranchblock = SuperVUBuildBlocks(pblock, bpc, newpipes); + + // update pblock since could have changed + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + assert( pblock != NULL ); + + pblock->blocks.push_back(pbranchblock); + firstbranch = 0xff; //Non-Conditional Jump + break; + } + case 0x21: // BAL + { + VuBaseBlock* pbranchblock = SuperVUBuildBlocks(pblock, bpc, newpipes); + + // update pblock since could have changed + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + assert( pblock != NULL ); + pblock->blocks.push_back(pbranchblock); + firstbranch = 0xff; //Non-Conditional Jump + break; + } + case 0x28: // IBEQ + case 0x2f: // IBGEZ + case 0x2d: // IBGTZ + case 0x2e: // IBLEZ + case 0x2c: // IBLTZ + case 0x29: // IBNE + { + VuBaseBlock* pbranchblock = SuperVUBuildBlocks(pblock, bpc, newpipes); + + // update pblock since could have changed + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + assert( pblock != NULL ); + pblock->blocks.push_back(pbranchblock); + + // if has a second branch that is B or BAL, skip this + u32 secondbranch = (*(u32*)(VU->Micro+lastpc-8))>>25; + if( !hasSecondBranch || (secondbranch != 0x21 && secondbranch != 0x20) ) { + pbranchblock = SuperVUBuildBlocks(pblock, lastpc, newpipes); + + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + pblock->blocks.push_back(pbranchblock); + } + + break; + } + default: + assert(pblock->blocks.size() == 1); + break; + } + + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + +#ifdef SUPERVU_VIBRANCHDELAY +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +///// NOTE! This could still be a hack for KH2/GoW, but until we know how it properly works, this will do for now./// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + if( hasSecondBranch && firstbranch != 0xff ) { //check the previous jump was conditional and there is a second branch +#else + if( hasSecondBranch) { +#endif + + u32 vucode = *(u32*)(VU->Micro+lastpc-8); + pc = lastpc; + int bpc = _recbranchAddr(vucode); + + switch(vucode>>25) { + case 0x24: // jr + Console::Error("svurec bad jr jump!"); + assert(0); + break; + + case 0x25: // jalr + { + Console::Error("svurec bad jalr jump!"); + assert(0); + break; + } + case 0x20: // B + { + VuBaseBlock* pbranchblock = SuperVUBuildBlocks(pblock, bpc, newpipes); + + // update pblock since could have changed + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + + pblock->blocks.push_back(pbranchblock); + break; + } + case 0x21: // BAL + { + VuBaseBlock* pbranchblock = SuperVUBuildBlocks(pblock, bpc, newpipes); + + // replace instead of pushing a new block + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + pblock->blocks.push_back(pbranchblock); + break; + } + case 0x28: // IBEQ + case 0x2f: // IBGEZ + case 0x2d: // IBGTZ + case 0x2e: // IBLEZ + case 0x2c: // IBLTZ + case 0x29: // IBNE + { + VuBaseBlock* pbranchblock = SuperVUBuildBlocks(pblock, bpc, newpipes); + + // update pblock since could have changed + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + pblock->blocks.push_back(pbranchblock); + + // only add the block if the previous branch doesn't include the next instruction (ie, if a direct jump) + if( firstbranch == 0x24 || firstbranch == 0x25 || firstbranch == 0x20 || firstbranch == 0x21 ) { + pbranchblock = SuperVUBuildBlocks(pblock, lastpc, newpipes); + + pblock = recVUBlocks[s_vu][lastpc/8-2].pblock; + pblock->blocks.push_back(pbranchblock); + } + + break; + } + + jNO_DEFAULT; + } + } + + return recVUBlocks[s_vu][startpc/8].pblock; +} + +static void SuperVUInitLiveness(VuBaseBlock* pblock) +{ + list::iterator itinst, itnext; + + assert( pblock->insts.size() > 0 ); + + for(itinst = pblock->insts.begin(); itinst != pblock->insts.end(); ++itinst) { + + if( itinst->type & INST_DUMMY_ ) { + itinst->addvars[0] = itinst->addvars[1] = 0xffffffff; + itinst->livevars[0] = itinst->livevars[1] = 0xffffffff; + itinst->keepvars[0] = itinst->keepvars[1] = 0xffffffff; + itinst->usedvars[0] = itinst->usedvars[1] = 0; + } + else { + itinst->addvars[0] = itinst->regs[0].VIread | itinst->regs[1].VIread; + itinst->addvars[1] = (itinst->regs[0].VFread0 ? (1 << itinst->regs[0].VFread0) : 0) | + (itinst->regs[0].VFread1 ? (1 << itinst->regs[0].VFread1) : 0) | + (itinst->regs[1].VFread0 ? (1 << itinst->regs[1].VFread0) : 0) | + (itinst->regs[1].VFread1 ? (1 << itinst->regs[1].VFread1) : 0); + + // vf0 is not handled by VFread + if( !itinst->regs[0].VFread0 && (itinst->regs[0].VIread & (1<addvars[1] |= 1; + if( !itinst->regs[1].VFread0 && (itinst->regs[1].VIread & (1<addvars[1] |= 1; + if( !itinst->regs[0].VFread1 && (itinst->regs[0].VIread & (1<regs[0].VFr1xyzw != 0xff ) itinst->addvars[1] |= 1; + if( !itinst->regs[1].VFread1 && (itinst->regs[1].VIread & (1<regs[1].VFr1xyzw != 0xff ) itinst->addvars[1] |= 1; + + + u32 vfwrite = 0; + if( itinst->regs[0].VFwrite != 0 ) { + if( itinst->regs[0].VFwxyzw != 0xf ) itinst->addvars[1] |= 1<regs[0].VFwrite; + else vfwrite |= 1<regs[0].VFwrite; + } + if( itinst->regs[1].VFwrite != 0 ) { + if( itinst->regs[1].VFwxyzw != 0xf ) itinst->addvars[1] |= 1<regs[1].VFwrite; + else vfwrite |= 1<regs[1].VFwrite; + } + if( (itinst->regs[1].VIwrite & (1<regs[1].VFwxyzw != 0xf ) + itinst->addvars[1] |= 1<regs[0].VIwrite|itinst->regs[1].VIwrite); + + itinst->usedvars[0] = itinst->addvars[0]|viwrite; + itinst->usedvars[1] = itinst->addvars[1]|vfwrite; + +// itinst->addvars[0] &= ~viwrite; +// itinst->addvars[1] &= ~vfwrite; + itinst->keepvars[0] = ~viwrite; + itinst->keepvars[1] = ~vfwrite; + } + } + + itinst = --pblock->insts.end(); + while( itinst != pblock->insts.begin() ) { + itnext = itinst; --itnext; + + itnext->usedvars[0] |= itinst->usedvars[0]; + itnext->usedvars[1] |= itinst->usedvars[1]; + + itinst = itnext; + } +} + +u32 COMPUTE_LIVE(u32 R, u32 K, u32 L) +{ + u32 live = R | ((L)&(K)); + // special process mac and status flags + // only propagate liveness if doesn't write to the flag + if( !(L&(1<::reverse_iterator itblock; + list::iterator itinst, itnext; + VuBaseBlock::LISTBLOCKS::iterator itchild; + + u32 livevars[2]; + + do { + changed = FALSE; + for(itblock = s_listBlocks.rbegin(); itblock != s_listBlocks.rend(); ++itblock) { + + u32 newlive; + VuBaseBlock* pb = *itblock; + + // the last inst relies on the neighbor's insts + itinst = --pb->insts.end(); + + if( pb->blocks.size() > 0 ) { + livevars[0] = 0; livevars[1] = 0; + for( itchild = pb->blocks.begin(); itchild != pb->blocks.end(); ++itchild) { + VuInstruction& front = (*itchild)->insts.front(); + livevars[0] |= front.livevars[0]; + livevars[1] |= front.livevars[1]; + } + + newlive = COMPUTE_LIVE(itinst->addvars[0], itinst->keepvars[0], livevars[0]); + + // should propagate status flags whose parent insts are not in this block +// if( itinst->nParentPc >= 0 && (itinst->type & (INST_STATUS_WRITE|INST_MAC_WRITE)) ) +// newlive |= livevars[0]&((1<livevars[0] != newlive ) { + changed = TRUE; + itinst->livevars[0] = newlive; + } + + newlive = COMPUTE_LIVE(itinst->addvars[1], itinst->keepvars[1], livevars[1]); + if( itinst->livevars[1] != newlive ) { + changed = TRUE; + itinst->livevars[1] = newlive; + } + } + + while( itinst != pb->insts.begin() ) { + + itnext = itinst; --itnext; + + newlive = COMPUTE_LIVE(itnext->addvars[0], itnext->keepvars[0], itinst->livevars[0]); + + // should propagate status flags whose parent insts are not in this block +// if( itnext->nParentPc >= 0 && (itnext->type & (INST_STATUS_WRITE|INST_MAC_WRITE)) && !(itinst->type & (INST_STATUS_WRITE|INST_MAC_WRITE)) ) +// newlive |= itinst->livevars[0]&((1<livevars[0] != newlive ) { + changed = TRUE; + itnext->livevars[0] = newlive; + itnext->livevars[1] = COMPUTE_LIVE(itnext->addvars[1], itnext->keepvars[1], itinst->livevars[1]); + } + else { + newlive = COMPUTE_LIVE(itnext->addvars[1], itnext->keepvars[1], itinst->livevars[1]); + if( itnext->livevars[1] != newlive ) { + changed = TRUE; + itnext->livevars[1] = newlive; + } + } + + itinst = itnext; + } + +// if( (livevars[0] | itinst->livevars[0]) != itinst->livevars[0] ) { +// changed = TRUE; +// itinst->livevars[0] |= livevars[0]; +// } +// if( (livevars[1] | itinst->livevars[1]) != itinst->livevars[1] ) { +// changed = TRUE; +// itinst->livevars[1] |= livevars[1]; +// } +// +// while( itinst != pb->insts.begin() ) { +// +// itnext = itinst; --itnext; +// if( (itnext->livevars[0] | (itinst->livevars[0] & itnext->keepvars[0])) != itnext->livevars[0] ) { +// changed = TRUE; +// itnext->livevars[0] |= itinst->livevars[0] & itnext->keepvars[0]; +// itnext->livevars[1] |= itinst->livevars[1] & itnext->keepvars[1]; +// } +// else if( (itnext->livevars[1] | (itinst->livevars[1] & itnext->keepvars[1])) != itnext->livevars[1] ) { +// changed = TRUE; +// itnext->livevars[1] |= itinst->livevars[1] & itnext->keepvars[1]; +// } +// +// itinst = itnext; +// } + } + + } while(changed); +} + +static void SuperVUEliminateDeadCode() +{ + list::iterator itblock; + VuBaseBlock::LISTBLOCKS::iterator itchild; + list::iterator itinst, itnext; + list listParents; + list::iterator itparent; + + FORIT(itblock, s_listBlocks) { + +#ifdef _DEBUG + u32 startpc = (*itblock)->startpc; + u32 curpc = startpc; +#endif + + itnext = (*itblock)->insts.begin(); + itinst = itnext++; + while(itnext != (*itblock)->insts.end() ) { + if( itinst->type & (INST_CLIP_WRITE|INST_MAC_WRITE|INST_STATUS_WRITE) ) { + u32 live0 = itnext->livevars[0]; + if( itinst->nParentPc >= 0 && itnext->nParentPc >= 0 && itinst->nParentPc != itnext->nParentPc ) { // superman returns + // take the live vars from the next next inst + list::iterator itnextnext = itnext; ++itnextnext; + if( itnextnext != (*itblock)->insts.end() ) { + live0 = itnextnext->livevars[0]; + } + } + + itinst->regs[0].VIwrite &= live0; + itinst->regs[1].VIwrite &= live0; + + u32 viwrite = itinst->regs[0].VIwrite|itinst->regs[1].VIwrite; + + (*itblock)->GetInstsAtPc(itinst->nParentPc, listParents); + int removetype = 0; + + FORIT(itparent, listParents) { + VuInstruction* parent = *itparent; + + if( viwrite & (1<regs[0].VIwrite |= (itinst->regs[0].VIwrite&(1<regs[1].VIwrite |= (itinst->regs[1].VIwrite&(1<info.macflag && (itinst->type & INST_MAC_WRITE) ) { + if( !(viwrite&(1<info.macflag = 0; + // parent->regs[0].VIwrite &= ~(1<regs[1].VIwrite &= ~(1<regs[0].VIwrite & (1<regs[1].VIwrite & (1<regs[1].pipe == VUPIPE_FMAC && (parent->regs[1].VFwrite == 0&&!(parent->regs[1].VIwrite&(1<regs[0].VIwrite |= ((1<regs[1].VIwrite |= ((1<regs[0].VIwrite |= (itinst->regs[0].VIwrite&(1<regs[1].VIwrite |= (itinst->regs[1].VIwrite&(1<info.statusflag && (itinst->type & INST_STATUS_WRITE)) { + if( !(viwrite&(1<info.statusflag = 0; + // parent->regs[0].VIwrite &= ~(1<regs[1].VIwrite &= ~(1<regs[0].VIwrite & (1<regs[1].VIwrite & (1<regs[1].pipe == VUPIPE_FMAC && (parent->regs[1].VFwrite == 0&&!(parent->regs[1].VIwrite&(1<regs[0].VIwrite |= ((1<regs[1].VIwrite |= ((1<regs[0].VIwrite |= (itinst->regs[0].VIwrite&(1<regs[1].VIwrite |= (itinst->regs[1].VIwrite&(1<type &= ~removetype; + if( itinst->type == 0 ) { + itnext = (*itblock)->insts.erase(itinst); + itinst = itnext++; + continue; + } + } +#ifdef _DEBUG + else curpc += 8; +#endif + itinst = itnext; + ++itnext; + } + + if( itinst->type & INST_DUMMY ) { + // last inst with the children + u32 mask = 0; + for(itchild = (*itblock)->blocks.begin(); itchild != (*itblock)->blocks.end(); ++itchild) { + mask |= (*itchild)->insts.front().livevars[0]; + } + itinst->regs[0].VIwrite &= mask; + itinst->regs[1].VIwrite &= mask; + u32 viwrite = itinst->regs[0].VIwrite|itinst->regs[1].VIwrite; + + if( itinst->nParentPc >= 0 ) { + + (*itblock)->GetInstsAtPc(itinst->nParentPc, listParents); + int removetype = 0; + + FORIT(itparent, listParents) { + VuInstruction* parent = *itparent; + + if( viwrite & (1<regs[0].VIwrite |= (itinst->regs[0].VIwrite&(1<regs[1].VIwrite |= (itinst->regs[1].VIwrite&(1<info.macflag && (itinst->type & INST_MAC_WRITE) ) { + if( !(viwrite&(1<info.macflag = 0; +#ifndef SUPERVU_WRITEBACKS + assert( !(parent->regs[0].VIwrite & (1<regs[1].VIwrite & (1<regs[0].VIwrite |= (itinst->regs[0].VIwrite&(1<regs[1].VIwrite |= (itinst->regs[1].VIwrite&(1<info.statusflag && (itinst->type & INST_STATUS_WRITE)) { + if( !(viwrite&(1<info.statusflag = 0; +#ifndef SUPERVU_WRITEBACKS + assert( !(parent->regs[0].VIwrite & (1<regs[1].VIwrite & (1<regs[0].VIwrite |= (itinst->regs[0].VIwrite&(1<regs[1].VIwrite |= (itinst->regs[1].VIwrite&(1<type &= ~removetype; + if( itinst->type == 0 ) { + (*itblock)->insts.erase(itinst); + } + } + } + } +} + +void VuBaseBlock::AssignVFRegs() +{ + int i; + VuBaseBlock::LISTBLOCKS::iterator itchild; + list::iterator itblock; + list::iterator itinst, itnext, itinst2; + + // init the start regs + if( type & BLOCKTYPE_ANALYZED ) return; // nothing changed + memcpy(xmmregs, startregs, sizeof(xmmregs)); + + if( type & BLOCKTYPE_ANALYZED ) { + // check if changed + for(i = 0; i < XMMREGS; ++i) { + if( xmmregs[i].inuse != startregs[i].inuse ) + break; + if( xmmregs[i].inuse && (xmmregs[i].reg != startregs[i].reg || xmmregs[i].type != startregs[i].type) ) + break; + } + + if( i == XMMREGS ) return; // nothing changed + } + + u8* oldX86 = x86Ptr; + + FORIT(itinst, insts) { + + if( itinst->type & INST_DUMMY ) + continue; + + // reserve, go from upper to lower + int lastwrite = -1; + + for(i = 1; i >= 0; --i) { + _VURegsNum* regs = itinst->regs+i; + + // redo the counters so that the proper regs are released + for(int j = 0; j < XMMREGS; ++j) { + if( xmmregs[j].inuse ) { + if( xmmregs[j].type == XMMTYPE_VFREG ) { + int count = 0; + itinst2 = itinst; + + if( i ) { + if( itinst2->regs[0].VFread0 == xmmregs[j].reg || itinst2->regs[0].VFread1 == xmmregs[j].reg || itinst2->regs[0].VFwrite == xmmregs[j].reg ) { + itinst2 = insts.end(); + break; + } + else { + ++count; + ++itinst2; + } + } + + while(itinst2 != insts.end() ) { + if( itinst2->regs[0].VFread0 == xmmregs[j].reg || itinst2->regs[0].VFread1 == xmmregs[j].reg || itinst2->regs[0].VFwrite == xmmregs[j].reg || + itinst2->regs[1].VFread0 == xmmregs[j].reg || itinst2->regs[1].VFread1 == xmmregs[j].reg || itinst2->regs[1].VFwrite == xmmregs[j].reg) + break; + + ++count; + ++itinst2; + } + xmmregs[j].counter = 1000-count; + } + else { + assert( xmmregs[j].type == XMMTYPE_ACC ); + + int count = 0; + itinst2 = itinst; + + if( i ) ++itinst2; // acc isn't used in lower insts + + while(itinst2 != insts.end() ) { + assert( !((itinst2->regs[0].VIread|itinst2->regs[0].VIwrite) & (1<regs[1].VIread|itinst2->regs[1].VIwrite) & (1<VFread0 ) _addNeededVFtoXMMreg(regs->VFread0); + if( regs->VFread1 ) _addNeededVFtoXMMreg(regs->VFread1); + if( regs->VFwrite ) _addNeededVFtoXMMreg(regs->VFwrite); + if( regs->VIread & (1<VIread & (1<vfread0[i] = itinst->vfread1[i] = itinst->vfwrite[i] = itinst->vfacc[i] = -1; + itinst->vfflush[i] = -1; + + if( regs->VFread0 ) itinst->vfread0[i] = _allocVFtoXMMreg(VU, -1, regs->VFread0, 0); + else if( regs->VIread & (1<vfread0[i] = _allocVFtoXMMreg(VU, -1, 0, 0); + if( regs->VFread1 ) itinst->vfread1[i] = _allocVFtoXMMreg(VU, -1, regs->VFread1, 0); + else if( (regs->VIread & (1<VFr1xyzw != 0xff ) itinst->vfread1[i] = _allocVFtoXMMreg(VU, -1, 0, 0); + if( regs->VIread & (1<vfacc[i] = _allocACCtoXMMreg(VU, -1, 0); + + int reusereg = -1; // 0 - VFwrite, 1 - VFAcc + + if( regs->VFwrite ) { + assert( !(regs->VIwrite&(1<VFwxyzw == 0xf ) { + itinst->vfwrite[i] = _checkXMMreg(XMMTYPE_VFREG, regs->VFwrite, 0); + if( itinst->vfwrite[i] < 0 ) reusereg = 0; + } + else { + itinst->vfwrite[i] = _allocVFtoXMMreg(VU, -1, regs->VFwrite, 0); + } + } + else if( regs->VIwrite & (1<VFwxyzw == 0xf ) { + itinst->vfacc[i] = _checkXMMreg(XMMTYPE_ACC, 0, 0); + if( itinst->vfacc[i] < 0 ) reusereg = 1; + } + else { + itinst->vfacc[i] = _allocACCtoXMMreg(VU, -1, 0); + } + } + + if( reusereg >= 0 ) { + // reuse + itnext = itinst; itnext++; + + u8 type = reusereg ? XMMTYPE_ACC : XMMTYPE_VFREG; + u8 reg = reusereg ? 0 : regs->VFwrite; + + if( itinst->vfacc[i] >= 0 && lastwrite != itinst->vfacc[i] && + (itnext == insts.end() || ((regs->VIread&(1<usedvars[0]&(1<livevars[0]&(1<livevars[0]&(1<vfacc[i]); + xmmregs[itinst->vfacc[i]].inuse = 1; + xmmregs[itinst->vfacc[i]].reg = reg; + xmmregs[itinst->vfacc[i]].type = type; + xmmregs[itinst->vfacc[i]].mode = 0; + itinst->vfwrite[i] = itinst->vfacc[i]; + } + else if( itinst->vfread0[i] >= 0 && lastwrite != itinst->vfread0[i] && + (itnext == insts.end() || (regs->VFread0 > 0 && (!(itnext->usedvars[1]&(1<VFread0)) || !(itnext->livevars[1]&(1<VFread0))))) ) { + + if(itnext == insts.end() || (itnext->livevars[1]®s->VFread0)) _freeXMMreg(itinst->vfread0[i]); + xmmregs[itinst->vfread0[i]].inuse = 1; + xmmregs[itinst->vfread0[i]].reg = reg; + xmmregs[itinst->vfread0[i]].type = type; + xmmregs[itinst->vfread0[i]].mode = 0; + if( reusereg ) itinst->vfacc[i] = itinst->vfread0[i]; + else itinst->vfwrite[i] = itinst->vfread0[i]; + } + else if( itinst->vfread1[i] >= 0 && lastwrite != itinst->vfread1[i] && + (itnext == insts.end() || (regs->VFread1 > 0 && (!(itnext->usedvars[1]&(1<VFread1)) || !(itnext->livevars[1]&(1<VFread1))))) ) { + + if(itnext == insts.end() || (itnext->livevars[1]®s->VFread1)) _freeXMMreg(itinst->vfread1[i]); + xmmregs[itinst->vfread1[i]].inuse = 1; + xmmregs[itinst->vfread1[i]].reg = reg; + xmmregs[itinst->vfread1[i]].type = type; + xmmregs[itinst->vfread1[i]].mode = 0; + if( reusereg ) itinst->vfacc[i] = itinst->vfread1[i]; + else itinst->vfwrite[i] = itinst->vfread1[i]; + } + else { + if( reusereg ) itinst->vfacc[i] = _allocACCtoXMMreg(VU, -1, 0); + else itinst->vfwrite[i] = _allocVFtoXMMreg(VU, -1, regs->VFwrite, 0); + } + } + + if( itinst->vfwrite[i] >= 0 ) lastwrite = itinst->vfwrite[i]; + else if( itinst->vfacc[i] >= 0 ) lastwrite = itinst->vfacc[i]; + + // always alloc at least 1 temp reg + int free0 = (i||regs->VFwrite||regs->VFread0||regs->VFread1||(regs->VIwrite&(1<vfwrite[1] >= 0 && (itinst->vfread0[0]==itinst->vfwrite[1]||itinst->vfread1[0]==itinst->vfwrite[1]) ) { + itinst->vfflush[i] = _allocTempXMMreg(XMMT_FPS, -1); + } + + if( i == 1 && (regs->VIwrite & (1<VIwrite & (1<vfflush[i] >= 0 ) _freeXMMreg(itinst->vfflush[i]); + if( free0 >= 0 ) _freeXMMreg(free0); + + itinst->vffree[i] = (free0&0xf)|(free1<<8)|(free2<<16); + if( free0 == -1 ) itinst->vffree[i] |= VFFREE_INVALID0; + + _clearNeededXMMregs(); + } + } + + assert( x86Ptr == oldX86 ); + u32 analyzechildren = !(type&BLOCKTYPE_ANALYZED); + type |= BLOCKTYPE_ANALYZED; + + //memset(endregs, 0, sizeof(endregs)); + + if( analyzechildren ) { + FORIT(itchild, blocks) (*itchild)->AssignVFRegs(); + } +} + +struct MARKOVBLANKET +{ + list parents; + list children; +}; + +static MARKOVBLANKET s_markov; + +void VuBaseBlock::AssignVIRegs(int parent) +{ + const int maxregs = 6; + + if( parent ) { + if( (type&BLOCKTYPE_ANALYZEDPARENT) ) + return; + + type |= BLOCKTYPE_ANALYZEDPARENT; + s_markov.parents.push_back(this); + for(LISTBLOCKS::iterator it = blocks.begin(); it != blocks.end(); ++it) { + (*it)->AssignVIRegs(0); + } + return; + } + + if( (type&BLOCKTYPE_ANALYZED) ) + return; + + // child + assert( allocX86Regs == -1 ); + allocX86Regs = s_vecRegArray.size(); + s_vecRegArray.resize(allocX86Regs+X86REGS); + + _x86regs* pregs = &s_vecRegArray[allocX86Regs]; + memset(pregs, 0, sizeof(_x86regs)*X86REGS); + + assert( parents.size() > 0 ); + + list::iterator itparent; + u32 usedvars = insts.front().usedvars[0]; + u32 livevars = insts.front().livevars[0]; + + if( parents.size() > 0 ) { + u32 usedvars2 = 0xffffffff; + FORIT(itparent, parents) usedvars2 &= (*itparent)->insts.front().usedvars[0]; + usedvars |= usedvars2; + } + + usedvars &= livevars; + + // currently order doesn't matter + int num = 0; + + if( usedvars ) { + for(int i = 1; i < 16; ++i) { + if( usedvars & (1<= maxregs ) break; + } + } + } + + if( num < maxregs) { + livevars &= ~usedvars; + livevars &= insts.back().usedvars[0]; + + if( livevars ) { + for(int i = 1; i < 16; ++i) { + if( livevars & (1<= maxregs) break; + } + } + } + } + + s_markov.children.push_back(this); + type |= BLOCKTYPE_ANALYZED; + FORIT(itparent, parents) { + (*itparent)->AssignVIRegs(1); + } +} + +static void SuperVUAssignRegs() +{ + list::iterator itblock, itblock2; + + FORIT(itblock, s_listBlocks) (*itblock)->type &= ~BLOCKTYPE_ANALYZED; + s_listBlocks.front()->AssignVFRegs(); + + // VI assignments, find markov blanket for each node in the graph + // then allocate regs based on the commonly used ones +#ifdef SUPERVU_X86CACHING + FORIT(itblock, s_listBlocks) (*itblock)->type &= ~(BLOCKTYPE_ANALYZED|BLOCKTYPE_ANALYZEDPARENT); + s_vecRegArray.resize(0); + u8 usedregs[16]; + + // note: first block always has to start with no alloc regs + bool bfirst = true; + + FORIT(itblock, s_listBlocks) { + + if( !((*itblock)->type & BLOCKTYPE_ANALYZED) ) { + + if( (*itblock)->parents.size() == 0 ) { + (*itblock)->type |= BLOCKTYPE_ANALYZED; + bfirst = false; + continue; + } + + s_markov.children.clear(); + s_markov.parents.clear(); + (*itblock)->AssignVIRegs(0); + + // assign the regs + int regid = s_vecRegArray.size(); + s_vecRegArray.resize(regid+X86REGS); + + _x86regs* mergedx86 = &s_vecRegArray[regid]; + memset(mergedx86, 0, sizeof(_x86regs)*X86REGS); + + if( !bfirst ) { + *(u32*)usedregs = *((u32*)usedregs+1) = *((u32*)usedregs+2) = *((u32*)usedregs+3) = 0; + + FORIT(itblock2, s_markov.children) { + assert( (*itblock2)->allocX86Regs >= 0 ); + _x86regs* pregs = &s_vecRegArray[(*itblock2)->allocX86Regs]; + for(int i = 0; i < X86REGS; ++i) { + if( pregs[i].inuse && pregs[i].reg < 16) { + //assert( pregs[i].reg < 16); + usedregs[pregs[i].reg]++; + } + } + } + + int num = 1; + for(int i = 0; i < 16; ++i) { + if( usedregs[i] == s_markov.children.size() ) { + // use + mergedx86[num].inuse = 1; + mergedx86[num].reg = i; + mergedx86[num].type = (s_vu?X86TYPE_VU1:0)|X86TYPE_VI; + mergedx86[num].mode = MODE_READ; + if( ++num >= X86REGS ) + break; + if( num == ESP ) + ++num; + } + } + + FORIT(itblock2, s_markov.children) { + assert( (*itblock2)->nStartx86 == -1 ); + (*itblock2)->nStartx86 = regid; + } + + FORIT(itblock2, s_markov.parents) { + assert( (*itblock2)->nEndx86 == -1 ); + (*itblock2)->nEndx86 = regid; + } + } + + bfirst = false; + } + } +#endif +} + +////////////////// +// Recompilation +////////////////// + +// cycles in which the last Q,P regs were finished (written to VU->VI[]) +// the write occurs before the instruction is executed at that cycle +// compare with s_TotalVUCycles +// if less than 0, already flushed +int s_writeQ, s_writeP; + +// declare the saved registers +uptr s_vu1esp, s_callstack;//, s_vu1esp +uptr s_vu1ebp, s_vuebx, s_vuedi, s_vu1esi; + +static int s_recWriteQ, s_recWriteP; // wait times during recompilation +static int s_needFlush; // first bit - Q, second bit - P, third bit - Q has been written, fourth bit - P has been written + +static int s_JumpX86; +static int s_ScheduleXGKICK = 0, s_XGKICKReg = -1; + +void recVUMI_XGKICK_( VURegs *VU ); + +void SuperVUCleanupProgram(u32 startpc, int vuindex) +{ +#ifdef SUPERVU_COUNT + QueryPerformanceCounter(&svufinal); + svutime += (u32)(svufinal.QuadPart-svubase.QuadPart); +#endif + + assert( s_vu1esp == 0 ); + + VU = vuindex ? &VU1 : &VU0; + VU->cycle += s_TotalVUCycles; + if( (int)s_writeQ > 0 ) VU->VI[REG_Q] = VU->q; + if( (int)s_writeP > 0 ) { + assert(VU == &VU1); + VU1.VI[REG_P] = VU1.p; // only VU1 + } + + //memset(recVUStack, 0, SUPERVU_STACKSIZE * 4); + + // Clear allocation info to prevent bad data being used in other parts of pcsx2; doing this just incase (cottonvibes) + _initXMMregs(); + _initMMXregs(); + _initX86regs(); +} + +#if defined(_MSC_VER) + +// entry point of all vu programs from emulator calls +__declspec(naked) void SuperVUExecuteProgram(u32 startpc, int vuindex) +{ +#ifdef SUPERVU_COUNT + QueryPerformanceCounter(&svubase); +#endif + __asm { + mov eax, dword ptr [esp] + mov s_TotalVUCycles, 0 // necessary to be here! + add esp, 4 + mov s_callstack, eax + call SuperVUGetProgram + + // save cpu state + mov s_vu1ebp, ebp + mov s_vu1esi, esi // have to save even in Release + mov s_vuedi, edi // have to save even in Release + mov s_vuebx, ebx + } +#ifdef _DEBUG + __asm { + mov s_vu1esp, esp + } +#endif + + __asm { + //stmxcsr s_ssecsr + ldmxcsr g_sseVUMXCSR + + // init vars + mov s_writeQ, 0xffffffff + mov s_writeP, 0xffffffff + + jmp eax + } +} + +// exit point of all vu programs +__declspec(naked) static void SuperVUEndProgram() +{ + __asm { + // restore cpu state + ldmxcsr g_sseMXCSR + + mov ebp, s_vu1ebp + mov esi, s_vu1esi + mov edi, s_vuedi + mov ebx, s_vuebx + } + +#ifdef _DEBUG + __asm { + sub s_vu1esp, esp + } +#endif + + __asm { + call SuperVUCleanupProgram + jmp s_callstack // so returns correctly + } +} + +#endif + +// Flushes P/Q regs +void SuperVUFlush(int p, int wait) +{ + u8* pjmp[3]; + if( !(s_needFlush&(1<info.cycle < recwait ) return; + + if( recwait == 0 ) { + // write didn't happen this block + MOV32MtoR(EAX, p ? (uptr)&s_writeP : (uptr)&s_writeQ); + OR32RtoR(EAX, EAX); + pjmp[0] = JS8(0); + + if( s_pCurInst->info.cycle ) SUB32ItoR(EAX, s_pCurInst->info.cycle); + + // if writeQ <= total+offset + if( !wait ) { // only write back if time is up + CMP32MtoR(EAX, (uptr)&s_TotalVUCycles); + pjmp[1] = JG8(0); + } + else { + // add (writeQ-total-offset) to s_TotalVUCycles + // necessary? + CMP32MtoR(EAX, (uptr)&s_TotalVUCycles); + pjmp[2] = JLE8(0); + MOV32RtoM((uptr)&s_TotalVUCycles, EAX); + x86SetJ8(pjmp[2]); + } + } + else if( wait && s_pCurInst->info.cycle < recwait ) { + ADD32ItoM((uptr)&s_TotalVUCycles, recwait); + } + + MOV32MtoR(EAX, SuperVUGetVIAddr(p?REG_P:REG_Q, 0)); + MOV32ItoM(p ? (uptr)&s_writeP : (uptr)&s_writeQ, 0x80000000); + MOV32RtoM(SuperVUGetVIAddr(p?REG_P:REG_Q, 1), EAX); + + if( recwait == 0 ) { + if( !wait ) x86SetJ8(pjmp[1]); + x86SetJ8(pjmp[0]); + } + + if( wait || (!p && recwait == 0 && s_pCurInst->info.cycle >= 12) || (!p && recwait > 0 && s_pCurInst->info.cycle >= recwait ) ) + s_needFlush &= ~(1<::iterator itblock; + + FORIT(itblock, s_listBlocks) (*itblock)->type &= ~BLOCKTYPE_ANALYZED; + s_listBlocks.front()->Recompile(); + // make sure everything compiled + FORIT(itblock, s_listBlocks) assert( ((*itblock)->type & BLOCKTYPE_ANALYZED) && (*itblock)->pcode != NULL ); + + // link all blocks + FORIT(itblock, s_listBlocks) { + VuBaseBlock::LISTBLOCKS::iterator itchild; + + assert( (*itblock)->blocks.size() <= ARRAYSIZE((*itblock)->pChildJumps) ); + + int i = 0; + FORIT(itchild, (*itblock)->blocks) { + + if( (u32)(uptr)(*itblock)->pChildJumps[i] == 0xffffffff ) + continue; + + if( (*itblock)->pChildJumps[i] == NULL ) { + VuBaseBlock* pchild = *itchild; + + if( pchild->type & BLOCKTYPE_HASEOP) { + assert( pchild->blocks.size() == 0); + + AND32ItoM( (uptr)&VU0.VI[ REG_VPU_STAT ].UL, s_vu?~0x100:~0x001 ); // E flag + AND32ItoM( (uptr)&VU->vifRegs->stat, ~0x4 ); + + MOV32ItoM((uptr)&VU->VI[REG_TPC], pchild->endpc); + JMP32( (uptr)SuperVUEndProgram - ( (uptr)x86Ptr + 5 )); + } + // only other case is when there are two branches + else assert( (*itblock)->insts.back().regs[0].pipe == VUPIPE_BRANCH ); + + continue; + } + + if( (u32)(uptr)(*itblock)->pChildJumps[i] & 0x80000000 ) { + // relative + assert( (uptr)(*itblock)->pChildJumps[i] <= 0xffffffff); + (*itblock)->pChildJumps[i] = (u32*)((uptr)(*itblock)->pChildJumps[i] & 0x7fffffff); + *(*itblock)->pChildJumps[i] = (uptr)(*itchild)->pcode - ((uptr)(*itblock)->pChildJumps[i] + 4); + } + else *(*itblock)->pChildJumps[i] = (uptr)(*itchild)->pcode; + + ++i; + } + } + + s_pFnHeader->pprogfunc = s_listBlocks.front()->pcode; +} + +// debug + + +u32 s_saveecx, s_saveedx, s_saveebx, s_saveesi, s_saveedi, s_saveebp; +u32 g_curdebugvu; + +//float vuDouble(u32 f); + +#if defined(_MSC_VER) +__declspec(naked) static void svudispfn() +{ + __asm { + mov g_curdebugvu, eax + mov s_saveecx, ecx + mov s_saveedx, edx + mov s_saveebx, ebx + mov s_saveesi, esi + mov s_saveedi, edi + mov s_saveebp, ebp + } +#else +#ifdef __LINUX__ +extern "C" { +#endif +void svudispfn(); +#ifdef __LINUX__ +} +#endif + +void svudispfntemp() +{ +#endif + +#ifdef _DEBUG + static u32 i; + + if( ((vudump&8) && g_curdebugvu) || ((vudump&0x80) && !g_curdebugvu) ) { //&& g_vu1lastrec != g_vu1last ) { + + if( skipparent != g_vu1lastrec ) { + for(i = 0; i < ARRAYSIZE(badaddrs); ++i) { + if( s_svulast == badaddrs[i][1] && g_vu1lastrec == badaddrs[i][0] ) + break; + } + + if( i == ARRAYSIZE(badaddrs) ) + { + //static int curesp; + //__asm mov curesp, esp + //Console::WriteLn("tVU: %x %x %x", s_svulast, s_vucount, s_vufnheader); + if( g_curdebugvu ) iDumpVU1Registers(); + else iDumpVU0Registers(); + s_vucount++; + } + } + + g_vu1lastrec = s_svulast; + } +#endif + +#if defined(_MSC_VER) + __asm { + mov ecx, s_saveecx + mov edx, s_saveedx + mov ebx, s_saveebx + mov esi, s_saveesi + mov edi, s_saveedi + mov ebp, s_saveebp + ret + } +#endif +} + +// frees all regs taking into account the livevars +void SuperVUFreeXMMregs(u32* livevars) +{ + for(int i = 0; i < XMMREGS; ++i) { + if( xmmregs[i].inuse ) { + // same reg + if( (xmmregs[i].mode & MODE_WRITE) ) { + +#ifdef SUPERVU_INTERCACHING + if( xmmregs[i].type == XMMTYPE_VFREG ) { + if( !(livevars[1] & (1<VF[xmmregs[i].reg] : (uptr)&VU->ACC; + + if( xmmregs[i].mode & MODE_VUZ ) { + SSE_MOVHPS_XMM_to_M64(addr, (x86SSERegType)i); + SSE_SHUFPS_M128_to_XMM((x86SSERegType)i, addr, 0xc4); + } + else SSE_MOVHPS_M64_to_XMM((x86SSERegType)i, addr+8); + + xmmregs[i].mode &= ~MODE_VUXYZ; + } + + _freeXMMreg(i); + } + } + } + + //_freeXMMregs(); +} + +void SuperVUTestVU0Condition(u32 incstack) +{ + if( s_vu && !SUPERVU_CHECKCONDITION ) return; // vu0 only + + CMP32ItoM((uptr)&s_TotalVUCycles, 512); // sometimes games spin on vu0, so be careful with this value + // woody hangs if too high + + if( incstack ) { + u8* ptr = JB8(0); + + ADD32ItoR(ESP, incstack); + //CALLFunc((u32)timeout); + JMP32( (uptr)SuperVUEndProgram - ( (uptr)x86Ptr + 5 )); + + x86SetJ8(ptr); + } + else JAE32( (uptr)SuperVUEndProgram - ( (uptr)x86Ptr + 6 ) ); +} + +void VuBaseBlock::Recompile() +{ + if( type & BLOCKTYPE_ANALYZED ) return; + + x86Align(16); + pcode = x86Ptr; + +#ifdef _DEBUG + MOV32ItoM((uptr)&s_vufnheader, s_pFnHeader->startpc); + MOV32ItoM((uptr)&VU->VI[REG_TPC], startpc); + MOV32ItoM((uptr)&s_svulast, startpc); + list::iterator itparent; + for(itparent = parents.begin(); itparent != parents.end(); ++itparent) { + if( (*itparent)->blocks.size()==1 && (*itparent)->blocks.front()->startpc == startpc && + ((*itparent)->insts.size() < 2 || (----(*itparent)->insts.end())->regs[0].pipe != VUPIPE_BRANCH) ) { + MOV32ItoM((uptr)&skipparent, (*itparent)->startpc); + break; + } + } + + if( itparent == parents.end() ) MOV32ItoM((uptr)&skipparent, -1); + + MOV32ItoR(EAX, s_vu); + CALLFunc((uptr)svudispfn); +#endif + + s_pCurBlock = this; + s_needFlush = 3; + pc = startpc; + branch = 0; + s_recWriteQ = s_recWriteP = 0; + s_XGKICKReg = -1; + s_ScheduleXGKICK = 0; + + s_ClipRead = s_PrevClipWrite = (uptr)&VU->VI[REG_CLIP_FLAG]; + s_StatusRead = s_PrevStatusWrite = (uptr)&VU->VI[REG_STATUS_FLAG]; + s_MACRead = s_PrevMACWrite = (uptr)&VU->VI[REG_MAC_FLAG]; + s_PrevIWrite = (uptr)&VU->VI[REG_I]; + s_JumpX86 = 0; + s_UnconditionalDelay = 0; + + memcpy(xmmregs, startregs, sizeof(xmmregs)); +#ifdef SUPERVU_X86CACHING + if( nStartx86 >= 0 ) + memcpy(x86regs, &s_vecRegArray[nStartx86], sizeof(x86regs)); + else _initX86regs(); +#else + _initX86regs(); +#endif + + list::iterator itinst; + FORIT(itinst, insts) { + s_pCurInst = &(*itinst); + if( s_JumpX86 > 0 ) { + if( !x86regs[s_JumpX86].inuse ) { + // load + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_READ); + } + x86regs[s_JumpX86].needed = 1; + } + + if( s_ScheduleXGKICK && s_XGKICKReg > 0 ) { + assert( x86regs[s_XGKICKReg].inuse ); + x86regs[s_XGKICKReg].needed = 1; + } + itinst->Recompile(itinst, vuxyz); + + if( s_ScheduleXGKICK > 0 ) { + if( s_ScheduleXGKICK-- == 1 ) { + recVUMI_XGKICK_(VU); + } + } + } + assert( pc == endpc ); + assert( s_ScheduleXGKICK == 0 ); + + // flush flags + if( s_PrevClipWrite != (uptr)&VU->VI[REG_CLIP_FLAG] ) { + MOV32MtoR(EAX, s_PrevClipWrite); + MOV32RtoM((uptr)&VU->VI[REG_CLIP_FLAG], EAX); + } + if( s_PrevStatusWrite != (uptr)&VU->VI[REG_STATUS_FLAG] ) { + MOV32MtoR(EAX, s_PrevStatusWrite); + MOV32RtoM((uptr)&VU->VI[REG_STATUS_FLAG], EAX); + } + if( s_PrevMACWrite != (uptr)&VU->VI[REG_MAC_FLAG] ) { + MOV32MtoR(EAX, s_PrevMACWrite); + MOV32RtoM((uptr)&VU->VI[REG_MAC_FLAG], EAX); + } +// if( s_StatusRead != (uptr)&VU->VI[REG_STATUS_FLAG] ) { +// // only lower 8 bits valid! +// MOVZX32M8toR(EAX, s_StatusRead); +// MOV32RtoM((uptr)&VU->VI[REG_STATUS_FLAG], EAX); +// } +// if( s_MACRead != (uptr)&VU->VI[REG_MAC_FLAG] ) { +// // only lower 8 bits valid! +// MOVZX32M8toR(EAX, s_MACRead); +// MOV32RtoM((uptr)&VU->VI[REG_MAC_FLAG], EAX); +// } + if( s_PrevIWrite != (uptr)&VU->VI[REG_I] ) { + MOV32ItoM((uptr)&VU->VI[REG_I], *(u32*)s_PrevIWrite); // never changes + } + + ADD32ItoM((uptr)&s_TotalVUCycles, cycles); + + // compute branches, jumps, eop + if( type & BLOCKTYPE_HASEOP ) { + // end + _freeXMMregs(); + _freeX86regs(); + AND32ItoM( (uptr)&VU0.VI[ REG_VPU_STAT ].UL, s_vu?~0x100:~0x001 ); // E flag + AND32ItoM( (uptr)&VU->vifRegs->stat, ~0x4 ); + if( !branch ) MOV32ItoM((uptr)&VU->VI[REG_TPC], endpc); + JMP32( (uptr)SuperVUEndProgram - ( (uptr)x86Ptr + 5 )); + } + else { + + u32 livevars[2] = {0}; + + list::iterator lastinst = GetInstIterAtPc(endpc-8); + lastinst++; + + if( lastinst != insts.end() ) { + livevars[0] = lastinst->livevars[0]; + livevars[1] = lastinst->livevars[1]; + } + else { + // take from children + if( blocks.size() > 0 ) { + LISTBLOCKS::iterator itchild; + FORIT(itchild, blocks) { + livevars[0] |= (*itchild)->insts.front().livevars[0]; + livevars[1] |= (*itchild)->insts.front().livevars[1]; + } + } + else { + livevars[0] = ~0; + livevars[1] = ~0; + } + } + + SuperVUFreeXMMregs(livevars); + + // get rid of any writes, otherwise _freeX86regs will write + x86regs[s_JumpX86].mode &= ~MODE_WRITE; + + if( branch == 1 ) { + if( !x86regs[s_JumpX86].inuse ) { + assert( x86regs[s_JumpX86].type == X86TYPE_VUJUMP ); + s_JumpX86 = 0xffffffff; // notify to jump from g_recWriteback + } + } + + // align VI regs +#ifdef SUPERVU_X86CACHING + if( nEndx86 >= 0 ) { + _x86regs* endx86 = &s_vecRegArray[nEndx86]; + for(int i = 0; i < X86REGS; ++i) { + if( endx86[i].inuse ) { + + if( s_JumpX86 == i && x86regs[s_JumpX86].inuse ) { + x86regs[s_JumpX86].inuse = 0; + x86regs[EAX].inuse = 1; + MOV32RtoR(EAX, s_JumpX86); + s_JumpX86 = EAX; + } + + if( x86regs[i].inuse ) { + if( x86regs[i].type == endx86[i].type && x86regs[i].reg == endx86[i].reg ) { + _freeX86reg(i); + // will continue to use it + continue; + } + + if( x86regs[i].type == (X86TYPE_VI|(s_vu?X86TYPE_VU1:0)) ) { +#ifdef SUPERVU_INTERCACHING + if( livevars[0] & (1<startpc); + + switch(branch) { + case 1: // branch, esi has new prog + + SuperVUTestVU0Condition(0); + + if( s_JumpX86 == 0xffffffff ) + JMP32M((uptr)&g_recWriteback); + else + JMPR(s_JumpX86); + + break; + case 4: // jalr + pChildJumps[0] = (u32*)0xffffffff; + // fall through + + case 0x10: // jump, esi has new vupc + { + _freeXMMregs(); + _freeX86regs(); + + SuperVUTestVU0Condition(8); + + // already onto stack + CALLFunc((uptr)SuperVUGetProgram); + ADD32ItoR(ESP, 8); + JMPR(EAX); + break; + } + + case 0x13: // jr with uncon branch, uncond branch takes precendence (dropship) + { +// s32 delta = (s32)(VU->code & 0x400 ? 0xfffffc00 | (VU->code & 0x3ff) : VU->code & 0x3ff) << 3; +// ADD32ItoRmOffset(ESP, delta, 0); + + ADD32ItoR(ESP, 8); // restore + pChildJumps[0] = (u32*)((uptr)JMP32(0)|0x80000000); + break; + } + case 0: + case 3: // unconditional branch + pChildJumps[s_UnconditionalDelay] = (u32*)((uptr)JMP32(0)|0x80000000); + break; + + default: + DevCon::Error("Bad branch %x\n", params branch); + assert(0); + break; + } + } + + pendcode = x86Ptr; + type |= BLOCKTYPE_ANALYZED; + + LISTBLOCKS::iterator itchild; + FORIT(itchild, blocks) { + (*itchild)->Recompile(); + } +} + +#define GET_VUXYZMODE(reg) 0//((vuxyz&(1<<(reg)))?MODE_VUXYZ:0) + +int VuInstruction::SetCachedRegs(int upper, u32 vuxyz) +{ + if( vfread0[upper] >= 0 ) { + SuperVUFreeXMMreg(vfread0[upper], XMMTYPE_VFREG, regs[upper].VFread0); + _allocVFtoXMMreg(VU, vfread0[upper], regs[upper].VFread0, MODE_READ|GET_VUXYZMODE(regs[upper].VFread0)); + } + if( vfread1[upper] >= 0 ) { + SuperVUFreeXMMreg(vfread1[upper], XMMTYPE_VFREG, regs[upper].VFread1); + _allocVFtoXMMreg(VU, vfread1[upper], regs[upper].VFread1, MODE_READ|GET_VUXYZMODE(regs[upper].VFread1)); + } + if( vfacc[upper] >= 0 && (regs[upper].VIread&(1<= 0 ) { + assert( regs[upper].VFwrite > 0); + SuperVUFreeXMMreg(vfwrite[upper], XMMTYPE_VFREG, regs[upper].VFwrite); + _allocVFtoXMMreg(VU, vfwrite[upper], regs[upper].VFwrite, + MODE_WRITE|(regs[upper].VFwxyzw != 0xf?MODE_READ:0)|GET_VUXYZMODE(regs[upper].VFwrite)); + } + if( vfacc[upper] >= 0 && (regs[upper].VIwrite&(1<= 0 ) info |= PROCESS_EE_SET_S(vfread0[upper]); + if( vfread1[upper] >= 0 ) info |= PROCESS_EE_SET_T(vfread1[upper]); + if( vfacc[upper] >= 0 ) info |= PROCESS_VU_SET_ACC(vfacc[upper]); + if( vfwrite[upper] >= 0 ) { + if( regs[upper].VFwrite == _Ft_ && vfread1[upper] < 0 ) { + info |= PROCESS_EE_SET_T(vfwrite[upper]); + } + else { + assert( regs[upper].VFwrite == _Fd_ ); + info |= PROCESS_EE_SET_D(vfwrite[upper]); + } + } + + if( !(vffree[upper]&VFFREE_INVALID0) ) { + SuperVUFreeXMMreg(vffree[upper]&0xf, XMMTYPE_TEMP, 0); + _allocTempXMMreg(XMMT_FPS, vffree[upper]&0xf); + } + info |= PROCESS_VU_SET_TEMP(vffree[upper]&0xf); + + if( vfflush[upper] >= 0 ) { + SuperVUFreeXMMreg(vfflush[upper], XMMTYPE_TEMP, 0); + _allocTempXMMreg(XMMT_FPS, vfflush[upper]); + } + + if( upper && (regs[upper].VIwrite & (1 << REG_CLIP_FLAG)) ) { + // CLIP inst, need two extra temp registers, put it EEREC_D and EEREC_ACC + assert( vfwrite[upper] == -1 ); + SuperVUFreeXMMreg((vffree[upper]>>8)&0xf, XMMTYPE_TEMP, 0); + _allocTempXMMreg(XMMT_FPS, (vffree[upper]>>8)&0xf); + info |= PROCESS_EE_SET_D((vffree[upper]>>8)&0xf); + + SuperVUFreeXMMreg((vffree[upper]>>16)&0xf, XMMTYPE_TEMP, 0); + _allocTempXMMreg(XMMT_FPS, (vffree[upper]>>16)&0xf); + info |= PROCESS_EE_SET_ACC((vffree[upper]>>16)&0xf); + + _freeXMMreg((vffree[upper]>>8)&0xf); // don't need anymore + _freeXMMreg((vffree[upper]>>16)&0xf); // don't need anymore + } + else if( regs[upper].VIwrite & (1<>8)&0xf, XMMTYPE_TEMP, 0); + _allocTempXMMreg(XMMT_FPS, (vffree[upper]>>8)&0xf); + info |= PROCESS_EE_SET_D((vffree[upper]>>8)&0xf); + _freeXMMreg((vffree[upper]>>8)&0xf); // don't need anymore + } + + if( vfflush[upper] >= 0 ) _freeXMMreg(vfflush[upper]); + if( !(vffree[upper]&VFFREE_INVALID0) ) + _freeXMMreg(vffree[upper]&0xf); // don't need anymore + + if( (regs[0].VIwrite|regs[1].VIwrite) & ((1<::iterator& itinst, u32 vuxyz) +{ + static PCSX2_ALIGNED16(VECTOR _VF); + static PCSX2_ALIGNED16(VECTOR _VFc); + u32 *ptr; + u8* pjmp; + int vfregstore=0; + + assert( s_pCurInst == this); + s_WriteToReadQ = 0; + + ptr = (u32*)&VU->Micro[ pc ]; + + if( type & INST_Q_READ ) + SuperVUFlush(0, (ptr[0] == 0x800003bf)||!!(regs[0].VIwrite & (1<startpc || nParentPc >= (int)pc) ) { + +// if( !s_vu ) { +// for(int j = 0; j < ARRAYSIZE(badaddrs); ++j) { +// if( badaddrs[j] == nParentPc ) +// goto NoParent; +// } +// } + + list::iterator itblock; + FORIT(itblock, s_listBlocks) { + if( nParentPc >= (*itblock)->startpc && nParentPc < (*itblock)->endpc ) { + pparentinst = &(*(*itblock)->GetInstIterAtPc(nParentPc)); + //if( !s_vu ) SysPrintf("%x ", nParentPc); + if( find(s_pCurBlock->parents.begin(), s_pCurBlock->parents.end(), *itblock) != s_pCurBlock->parents.end() ) + nParentCheckForExecution = (*itblock)->startpc; + break; + } + } + + assert( pparentinst != NULL ); + } +#endif + + if( type & INST_CLIP_WRITE ) { + if( nParentPc < s_pCurBlock->startpc || nParentPc >= (int)pc ) + // reading from out of this block, so already flushed to mem + s_ClipRead = (uptr)&VU->VI[REG_CLIP_FLAG]; + else { + s_ClipRead = s_pCurBlock->GetInstIterAtPc(nParentPc)->pClipWrite; + if (s_ClipRead == 0) SysPrintf("super ClipRead allocation error! \n"); + } + } + + // before modifying, check if they will ever be read + if( s_pCurBlock->type & BLOCKTYPE_MACFLAGS ) { + + u8 outofblock=0; + if( type & INST_STATUS_WRITE ) { + + if( nParentPc < s_pCurBlock->startpc || nParentPc >= (int)pc ) { + + // reading from out of this block, so already flushed to mem + if( pparentinst != NULL ) { //&& pparentinst->pStatusWrite != NULL ) { + + // might not have processed it yet, so reserve a mem loc + if( pparentinst->pStatusWrite == 0 ) { + pparentinst->pStatusWrite = (uptr)SuperVUStaticAlloc(4); + //MOV32ItoM(pparentinst->pStatusWrite, 0); + } + +// if( s_pCurBlock->prevFlagsOutOfBlock && s_StatusRead != NULL ) { +// // or instead since don't now which parent we came from +// MOV32MtoR(EAX, pparentinst->pStatusWrite); +// OR32RtoM(s_StatusRead, EAX); +// MOV32ItoM(pparentinst->pStatusWrite, 0); +// } + + if( nParentCheckForExecution >= 0 ) { + + // don't now which parent we came from, so have to check +// uptr tempstatus = (uptr)SuperVUStaticAlloc(4); +// if( s_StatusRead != NULL ) +// MOV32MtoR(EAX, s_StatusRead); +// else +// MOV32MtoR(EAX, (uptr)&VU->VI[REG_STATUS_FLAG]); +// s_StatusRead = tempstatus; + if( s_StatusRead == 0 ) + s_StatusRead = (uptr)&VU->VI[REG_STATUS_FLAG]; + + CMP32ItoM((uptr)&g_nLastBlockExecuted, nParentCheckForExecution); + u8* jptr = JNE8(0); + MOV32MtoR(EAX, pparentinst->pStatusWrite); + MOV32ItoM(pparentinst->pStatusWrite, 0); + MOV32RtoM(s_StatusRead, EAX); + x86SetJ8(jptr); + } + else { + uptr tempstatus = (uptr)SuperVUStaticAlloc(4); + MOV32MtoR(EAX, pparentinst->pStatusWrite); + MOV32RtoM(tempstatus, EAX); + MOV32ItoM(pparentinst->pStatusWrite, 0); + s_StatusRead = tempstatus; + } + + outofblock = 2; + } + else + s_StatusRead = (uptr)&VU->VI[REG_STATUS_FLAG]; + } + else { + s_StatusRead = s_pCurBlock->GetInstIterAtPc(nParentPc)->pStatusWrite; + if (s_StatusRead == 0) SysPrintf("super StatusRead allocation error! \n"); +// if( pc >= (u32)s_pCurBlock->endpc-8 ) { +// // towards the end, so variable might be leaded to another block (silent hill 4) +// uptr tempstatus = (uptr)SuperVUStaticAlloc(4); +// MOV32MtoR(EAX, s_StatusRead); +// MOV32RtoM(tempstatus, EAX); +// MOV32ItoM(s_StatusRead, 0); +// s_StatusRead = tempstatus; +// } + } + } + if( type & INST_MAC_WRITE ) { + + if( nParentPc < s_pCurBlock->startpc || nParentPc >= (int)pc ) { + // reading from out of this block, so already flushed to mem + + if( pparentinst != NULL ) {//&& pparentinst->pMACWrite != NULL ) { + // necessary for (katamari) + // towards the end, so variable might be leaked to another block (silent hill 4) + + // might not have processed it yet, so reserve a mem loc + if( pparentinst->pMACWrite == 0 ) { + pparentinst->pMACWrite = (uptr)SuperVUStaticAlloc(4); + //MOV32ItoM(pparentinst->pMACWrite, 0); + } + +// if( s_pCurBlock->prevFlagsOutOfBlock && s_MACRead != NULL ) { +// // or instead since don't now which parent we came from +// MOV32MtoR(EAX, pparentinst->pMACWrite); +// OR32RtoM(s_MACRead, EAX); +// MOV32ItoM(pparentinst->pMACWrite, 0); +// } + if( nParentCheckForExecution >= 0 ) { + + // don't now which parent we came from, so have to check +// uptr tempmac = (uptr)SuperVUStaticAlloc(4); +// if( s_MACRead != NULL ) +// MOV32MtoR(EAX, s_MACRead); +// else +// MOV32MtoR(EAX, (uptr)&VU->VI[REG_MAC_FLAG]); +// s_MACRead = tempmac; + + if( s_MACRead == 0 ) + s_MACRead = (uptr)&VU->VI[REG_MAC_FLAG]; + + CMP32ItoM((uptr)&g_nLastBlockExecuted, nParentCheckForExecution); + u8* jptr = JNE8(0); + MOV32MtoR(EAX, pparentinst->pMACWrite); + MOV32ItoM(pparentinst->pMACWrite, 0); + MOV32RtoM(s_MACRead, EAX); + x86SetJ8(jptr); + } + else { + uptr tempMAC = (uptr)SuperVUStaticAlloc(4); + MOV32MtoR(EAX, pparentinst->pMACWrite); + MOV32RtoM(tempMAC, EAX); + MOV32ItoM(pparentinst->pMACWrite, 0); + s_MACRead = tempMAC; + } + + outofblock = 2; + } + else + s_MACRead = (uptr)&VU->VI[REG_MAC_FLAG]; + +// if( pc >= (u32)s_pCurBlock->endpc-8 ) { +// // towards the end, so variable might be leaked to another block (silent hill 4) +// uptr tempMAC = (uptr)SuperVUStaticAlloc(4); +// MOV32MtoR(EAX, s_MACRead); +// MOV32RtoM(tempMAC, EAX); +// MOV32ItoM(s_MACRead, 0); +// s_MACRead = tempMAC; +// } + } + else { + s_MACRead = s_pCurBlock->GetInstIterAtPc(nParentPc)->pMACWrite; + } + } + + s_pCurBlock->prevFlagsOutOfBlock = outofblock; + } + else if( pparentinst != NULL) { + // make sure to reset the mac and status flags! (katamari) + if( pparentinst->pStatusWrite) + MOV32ItoM(pparentinst->pStatusWrite, 0); + if( pparentinst->pMACWrite) + MOV32ItoM(pparentinst->pMACWrite, 0); + } + + assert( s_ClipRead != 0 ); + assert( s_MACRead != 0 ); + assert( s_StatusRead != 0 ); + + return; + } + + s_pCurBlock->prevFlagsOutOfBlock = 0; + +#ifdef _DEBUG + MOV32ItoR(EAX, pc); +#endif + + assert( !(type & (INST_CLIP_WRITE|INST_STATUS_WRITE|INST_MAC_WRITE)) ); + pc += 8; + + list::const_iterator itinst2; + + if( (regs[0].VIwrite|regs[1].VIwrite) & ((1<type & BLOCKTYPE_MACFLAGS ) { + if( pMACWrite == 0 ) { + pMACWrite = (uptr)SuperVUStaticAlloc(4); + //MOV32ItoM(pMACWrite, 0); + } + if( pStatusWrite == 0 ) { + pStatusWrite = (uptr)SuperVUStaticAlloc(4); + //MOV32ItoM(pStatusWrite, 0); + } + } + else { + assert( s_StatusRead == (uptr)&VU->VI[REG_STATUS_FLAG] ); + assert( s_MACRead == (uptr)&VU->VI[REG_MAC_FLAG] ); + pMACWrite = s_MACRead; + pStatusWrite = s_StatusRead; + } + } + + if( (pClipWrite == 0) && ((regs[0].VIwrite|regs[1].VIwrite) & (1<insts.end() ) { + if( (itinst2->regs[0].VIread|itinst2->regs[0].VIwrite|itinst2->regs[1].VIread|itinst2->regs[1].VIwrite) && (1<flags, VUFLAG_MFLAGSET); + } + if (ptr[1] & 0x10000000) { // D flag + TEST32ItoM((uptr)&VU0.VI[REG_FBRST].UL, s_vu?0x400:0x004); + u8* ptr = JZ8(0); + OR32ItoM((uptr)&VU0.VI[REG_VPU_STAT].UL, s_vu?0x200:0x002); + _callFunctionArg1((uptr)hwIntcIrq, MEM_CONSTTAG, s_vu?INTC_VU1:INTC_VU0); + x86SetJ8(ptr); + } + if (ptr[1] & 0x08000000) { // T flag + TEST32ItoM((uptr)&VU0.VI[REG_FBRST].UL, s_vu?0x800:0x008); + u8* ptr = JZ8(0); + OR32ItoM((uptr)&VU0.VI[REG_VPU_STAT].UL, s_vu?0x400:0x004); + _callFunctionArg1((uptr)hwIntcIrq, MEM_CONSTTAG, s_vu?INTC_VU1:INTC_VU0); + x86SetJ8(ptr); + } + + // check upper flags + if (ptr[1] & 0x80000000) { // I flag + + assert( !(regs[0].VIwrite & ((1<code = ptr[1]; + s_vuInfo = SetCachedRegs(1, vuxyz); + if( s_JumpX86 > 0 ) x86regs[s_JumpX86].needed = 1; + if( s_ScheduleXGKICK && s_XGKICKReg > 0 ) x86regs[s_XGKICKReg].needed = 1; + + recVU_UPPER_OPCODE[ VU->code & 0x3f ]( VU, s_vuInfo ); + + s_PrevIWrite = (uptr)ptr; + _clearNeededXMMregs(); + _clearNeededX86regs(); + } + else { + if( regs[0].VIwrite & (1<insts.end()); + u32* codeptr2 = ptr+2; + + while(itinst2 != s_pCurBlock->insts.end() ) { + if( !(itinst2->type & INST_DUMMY) && ((itinst2->regs[0].VIwrite&(1<type & INST_Q_WRITE) && itinst2->nParentPc == pc-8 ) { + break; + } + if( itinst2->type & INST_Q_READ ) { + cacheq = 1; + break; + } + if( itinst2->type & INST_DUMMY ) { + ++itinst2; + continue; + } + codeptr2 += 2; + ++itinst2; + } + + if( itinst2 == s_pCurBlock->insts.end() ) + cacheq = 1; + + int x86temp = -1; + if( cacheq ) + x86temp = _allocX86reg(-1, X86TYPE_TEMP, 0, 0); + + // new is written so flush old + // if type & INST_Q_READ, already flushed + if( !(type & INST_Q_READ) && s_recWriteQ == 0 ) MOV32MtoR(EAX, (uptr)&s_writeQ); + + if( cacheq ) + MOV32MtoR(x86temp, (uptr)&s_TotalVUCycles); + + if( !(type & INST_Q_READ) ) { + if( s_recWriteQ == 0 ) { + OR32RtoR(EAX, EAX); + pjmp = JS8(0); + MOV32MtoR(EAX, SuperVUGetVIAddr(REG_Q, 0)); + MOV32RtoM(SuperVUGetVIAddr(REG_Q, 1), EAX); + x86SetJ8(pjmp); + } + else if( s_needFlush & 1 ) { + MOV32MtoR(EAX, SuperVUGetVIAddr(REG_Q, 0)); + MOV32RtoM(SuperVUGetVIAddr(REG_Q, 1), EAX); + s_needFlush &= ~1; + } + } + + // write new Q + if( cacheq ) { + assert(s_pCurInst->pqcycles>1); + ADD32ItoR(x86temp, s_pCurInst->info.cycle+s_pCurInst->pqcycles); + MOV32RtoM((uptr)&s_writeQ, x86temp); + s_needFlush |= 1; + } + else { + // won't be writing back + s_WriteToReadQ = 1; + s_needFlush &= ~1; + MOV32ItoM((uptr)&s_writeQ, 0x80000001); + } + + s_recWriteQ = s_pCurInst->info.cycle+s_pCurInst->pqcycles; + + if( x86temp >= 0 ) + _freeX86reg(x86temp); + } + + if( regs[0].VIwrite & (1<pqcycles>1); + ADD32ItoR(x86temp, s_pCurInst->info.cycle+s_pCurInst->pqcycles); + MOV32RtoM((uptr)&s_writeP, x86temp); + s_needFlush |= 2; + + s_recWriteP = s_pCurInst->info.cycle+s_pCurInst->pqcycles; + + _freeX86reg(x86temp); + } + + if( ptr[0] == 0x800003bf ) // waitq + SuperVUFlush(0, 1); + + if( ptr[0] == 0x800007bf ) // waitp + SuperVUFlush(1, 1); + +#ifdef PCSX2_DEVBUILD + if ( regs[1].VIread & regs[0].VIwrite & ~((1<startpc); + } +#endif + + u32 modewrite = 0; + if( vfwrite[1] >= 0 && xmmregs[vfwrite[1]].inuse && xmmregs[vfwrite[1]].type == XMMTYPE_VFREG && xmmregs[vfwrite[1]].reg == regs[1].VFwrite ) + modewrite = xmmregs[vfwrite[1]].mode & MODE_WRITE; + + VU->code = ptr[1]; + s_vuInfo = SetCachedRegs(1, vuxyz); + + if (vfwrite[1] >= 0) { + assert( regs[1].VFwrite > 0 ); + + if (vfwrite[0] == vfwrite[1]) { + //SysPrintf("*PCSX2*: Warning, VF write to the same reg in both lower/upper cycle %x\n", s_pCurBlock->startpc); + } + + if (vfread0[0] == vfwrite[1] || vfread1[0] == vfwrite[1] ) { + assert( regs[0].VFread0 == regs[1].VFwrite || regs[0].VFread1 == regs[1].VFwrite ); + assert( vfflush[0] >= 0 ); + if( modewrite ) { + SSE_MOVAPS_XMM_to_M128((uptr)&VU->VF[regs[1].VFwrite], (x86SSERegType)vfwrite[1]); + } + vfregstore = 1; + } + } + + if( s_JumpX86 > 0 ) x86regs[s_JumpX86].needed = 1; + if( s_ScheduleXGKICK && s_XGKICKReg > 0 ) x86regs[s_XGKICKReg].needed = 1; + + recVU_UPPER_OPCODE[ VU->code & 0x3f ]( VU, s_vuInfo ); + _clearNeededXMMregs(); + _clearNeededX86regs(); + + // necessary because status can be set by both upper and lower + if( regs[1].VIwrite & (1<code = ptr[0]; + s_vuInfo = SetCachedRegs(0, vuxyz); + + if( vfregstore ) { + // load + SSE_MOVAPS_M128_to_XMM(vfflush[0], (uptr)&VU->VF[regs[1].VFwrite]); + + assert( xmmregs[vfwrite[1]].mode & MODE_WRITE ); + + // replace with vfflush + if( _Fs_ == regs[1].VFwrite ) { + s_vuInfo &= ~PROCESS_EE_SET_S(0xf); + s_vuInfo |= PROCESS_EE_SET_S(vfflush[0]); + } + if( _Ft_ == regs[1].VFwrite ) { + s_vuInfo &= ~PROCESS_EE_SET_T(0xf); + s_vuInfo |= PROCESS_EE_SET_T(vfflush[0]); + } + + xmmregs[vfflush[0]].mode |= MODE_NOFLUSH|MODE_WRITE; // so that lower inst doesn't flush + } + + // notify vuinsts that upper inst is a fmac + if( regs[1].pipe == VUPIPE_FMAC ) + s_vuInfo |= PROCESS_VU_SET_FMAC(); + + if( s_JumpX86 > 0 ) x86regs[s_JumpX86].needed = 1; + if( s_ScheduleXGKICK && s_XGKICKReg > 0 ) x86regs[s_XGKICKReg].needed = 1; + +#ifdef SUPERVU_VIBRANCHDELAY + if ( type & INST_CACHE_VI ) { + assert( vicached >= 0 ); + int cachedreg = _allocX86reg(-1, X86TYPE_VI|(s_vu?X86TYPE_VU1:0), vicached, MODE_READ); + MOV32RtoM((uptr)&s_VIBranchDelay, cachedreg); + } +#endif + + // check if inst before branch and the write is the same as the read in the branch (wipeout) +// int oldreg=0; +// if( pc == s_pCurBlock->endpc-16 ) { +// itinst2 = itinst; ++itinst2; +// if( itinst2->regs[0].pipe == VUPIPE_BRANCH && (itinst->regs[0].VIwrite&itinst2->regs[0].VIread) ) { +// +// CALLFunc((u32)branchfn); +// assert( itinst->regs[0].VIwrite & 0xffff ); +// SysPrintf("vi write before branch\n"); +// for(s_CacheVIReg = 0; s_CacheVIReg < 16; ++s_CacheVIReg) { +// if( itinst->regs[0].VIwrite & (1<endpc-8 && s_CacheVIReg >= 0 ) { +// assert( s_CacheVIX86 > 0 && x86regs[s_CacheVIX86].inuse && x86regs[s_CacheVIX86].reg == s_CacheVIReg && x86regs[s_CacheVIX86].type == X86TYPE_VITEMP ); +// +// oldreg = _allocX86reg(-1, X86TYPE_VI|(s_vu?X86TYPE_VU1:0), s_CacheVIReg, MODE_READ); +// x86regs[s_CacheVIX86].needed = 1; +// assert( x86regs[oldreg].mode & MODE_WRITE ); +// +// x86regs[s_CacheVIX86].type = X86TYPE_VI|(s_vu?X86TYPE_VU1:0); +// x86regs[oldreg].type = X86TYPE_VITEMP; +// } + + recVU_LOWER_OPCODE[ VU->code >> 25 ]( VU, s_vuInfo ); + +// if( pc == s_pCurBlock->endpc-8 && s_CacheVIReg >= 0 ) { +// // revert +// x86regs[s_CacheVIX86].inuse = 0; +// x86regs[oldreg].type = X86TYPE_VI|(s_vu?X86TYPE_VU1:0); +// } + + _clearNeededXMMregs(); + _clearNeededX86regs(); + } + + // clip is always written so ok + if( (regs[0].VIwrite|regs[1].VIwrite) & (1<code); + int curjump = 0; + + if( s_pCurInst->type & INST_BRANCH_DELAY ) { + assert( (branch&0x17)!=0x10 && (branch&0x17)!=4 ); // no jump handlig for now + + if( (branch & 0x7) == 3 ) { + // previous was a direct jump + curjump = 1; + } + else if( branch & 1 ) curjump = 2; + } + + assert( s_JumpX86 > 0 ); + + if( (s_pCurBlock->type & BLOCKTYPE_HASEOP) || s_vu == 0 || SUPERVU_CHECKCONDITION) + MOV32ItoM(SuperVUGetVIAddr(REG_TPC, 0), bpc); + MOV32ItoR(s_JumpX86, 0); + s_pCurBlock->pChildJumps[curjump] = (u32*)x86Ptr-1; + + if( !(s_pCurInst->type & INST_BRANCH_DELAY) ) { + j8Ptr[1] = JMP8(0); + x86SetJ8( j8Ptr[ 0 ] ); + + if( (s_pCurBlock->type & BLOCKTYPE_HASEOP) || s_vu == 0 || SUPERVU_CHECKCONDITION ) + MOV32ItoM(SuperVUGetVIAddr(REG_TPC, 0), pc+8); + MOV32ItoR(s_JumpX86, 0); + s_pCurBlock->pChildJumps[curjump+1] = (u32*)x86Ptr-1; + + x86SetJ8( j8Ptr[ 1 ] ); + } + else + x86SetJ8( j8Ptr[ 0 ] ); + + branch |= 1; +} + +// supervu specific insts +void recVUMI_IBQ_prep() +{ + int fsreg, ftreg; + + if( _Fs_ == 0 ) { +#ifdef SUPERVU_VIBRANCHDELAY + if( s_pCurInst->vicached >= 0 && s_pCurInst->vicached == _Ft_ ) { + ftreg = -1; + } + else +#endif + { + ftreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Ft_, MODE_READ); + } + + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); + + if( ftreg >= 0 ) { + CMP16ItoR( ftreg, 0 ); + } + else CMP16ItoM(SuperVUGetVIAddr(_Ft_, 1), 0); + } + else if( _Ft_ == 0 ) { +#ifdef SUPERVU_VIBRANCHDELAY + if( s_pCurInst->vicached >= 0 && s_pCurInst->vicached == _Fs_ ) { + fsreg = -1; + } + else +#endif + { + fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + } + + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); + + if( fsreg >= 0 ) { + CMP16ItoR( fsreg, 0 ); + } + else CMP16ItoM(SuperVUGetVIAddr(_Fs_, 1), 0); + + } + else { + _addNeededX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Ft_); + +#ifdef SUPERVU_VIBRANCHDELAY + if( s_pCurInst->vicached >= 0 && s_pCurInst->vicached == _Fs_ ) { + fsreg = -1; + } + else +#endif + { + fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + } + +#ifdef SUPERVU_VIBRANCHDELAY + if( s_pCurInst->vicached >= 0 && s_pCurInst->vicached == _Ft_ ) { + ftreg = -1; + + if( fsreg <= 0 ) { + // allocate fsreg + if( s_pCurInst->vicached >= 0 && s_pCurInst->vicached == _Fs_ ) { + fsreg = _allocX86reg(-1, X86TYPE_TEMP, 0, MODE_READ|MODE_WRITE); + MOV32MtoR(fsreg, SuperVUGetVIAddr(_Fs_, 1)); + } + else + fsreg = _allocX86reg(-1, X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + } + } + else +#endif + { + ftreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Ft_, MODE_READ); + } + + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); + + if( fsreg >= 0 ) { + if( ftreg >= 0 ) { + CMP16RtoR( fsreg, ftreg ); + } + else CMP16MtoR(fsreg, SuperVUGetVIAddr(_Ft_, 1)); + } + else if( ftreg >= 0 ) { + CMP16MtoR(ftreg, SuperVUGetVIAddr(_Fs_, 1)); + } + else { + fsreg = _allocX86reg(-1, X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + CMP16MtoR(fsreg, SuperVUGetVIAddr(_Ft_, 1)); + } + } +} + +void recVUMI_IBEQ( VURegs* vuu, s32 info ) +{ + recVUMI_IBQ_prep(); + j8Ptr[ 0 ] = JNE8( 0 ); + recVUMI_BranchHandle(); +} + +void recVUMI_IBGEZ( VURegs* vuu, s32 info ) +{ + int fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); + + if( fsreg >= 0 ) { + OR16RtoR(fsreg, fsreg); + j8Ptr[ 0 ] = JS8( 0 ); + } + else { + CMP16ItoM( SuperVUGetVIAddr(_Fs_, 1), 0x0 ); + j8Ptr[ 0 ] = JL8( 0 ); + } + + recVUMI_BranchHandle(); +} + +void recVUMI_IBGTZ( VURegs* vuu, s32 info ) +{ + int fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); + + if( fsreg >= 0 ) { + CMP16ItoR(fsreg, 0); + j8Ptr[ 0 ] = JLE8( 0 ); + } + else { + CMP16ItoM( SuperVUGetVIAddr(_Fs_, 1), 0x0 ); + j8Ptr[ 0 ] = JLE8( 0 ); + } + recVUMI_BranchHandle(); +} + +void recVUMI_IBLEZ( VURegs* vuu, s32 info ) +{ + int fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); + + if( fsreg >= 0 ) { + CMP16ItoR(fsreg, 0); + j8Ptr[ 0 ] = JG8( 0 ); + } + else { + CMP16ItoM( SuperVUGetVIAddr(_Fs_, 1), 0x0 ); + j8Ptr[ 0 ] = JG8( 0 ); + } + recVUMI_BranchHandle(); +} + +void recVUMI_IBLTZ( VURegs* vuu, s32 info ) +{ + int fsreg = _checkX86reg(X86TYPE_VI|(VU==&VU1?X86TYPE_VU1:0), _Fs_, MODE_READ); + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); + + if( fsreg >= 0 ) { + OR16RtoR(fsreg, fsreg); + j8Ptr[ 0 ] = JNS8( 0 ); + } + else { + CMP16ItoM( SuperVUGetVIAddr(_Fs_, 1), 0x0 ); + j8Ptr[ 0 ] = JGE8( 0 ); + } + recVUMI_BranchHandle(); +} + +void recVUMI_IBNE( VURegs* vuu, s32 info ) +{ + recVUMI_IBQ_prep(); + j8Ptr[ 0 ] = JE8( 0 ); + recVUMI_BranchHandle(); +} + +void recVUMI_B( VURegs* vuu, s32 info ) +{ + // supervu will take care of the rest + int bpc = _recbranchAddr(VU->code); + if( (s_pCurBlock->type & BLOCKTYPE_HASEOP) || s_vu == 0 || SUPERVU_CHECKCONDITION) + MOV32ItoM(SuperVUGetVIAddr(REG_TPC, 0), bpc); + + // loops to self, so check condition + if( bpc == s_pCurBlock->startpc && (s_vu == 0 || SUPERVU_CHECKCONDITION) ) { + SuperVUTestVU0Condition(0); + } + + if( s_pCurBlock->blocks.size() > 1 ) { + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); + MOV32ItoR(s_JumpX86, 0); + s_pCurBlock->pChildJumps[(s_pCurInst->type & INST_BRANCH_DELAY)?1:0] = (u32*)x86Ptr-1; + s_UnconditionalDelay = 1; + } + + branch |= 3; +} + +void recVUMI_BAL( VURegs* vuu, s32 info ) +{ + int bpc = _recbranchAddr(VU->code); + if( (s_pCurBlock->type & BLOCKTYPE_HASEOP) || s_vu == 0 || SUPERVU_CHECKCONDITION ) + MOV32ItoM(SuperVUGetVIAddr(REG_TPC, 0), bpc); + + // loops to self, so check condition + if( bpc == s_pCurBlock->startpc && (s_vu == 0 || SUPERVU_CHECKCONDITION) ) { + SuperVUTestVU0Condition(0); + } + + if ( _Ft_ ) { + _deleteX86reg(X86TYPE_VI|(s_vu?X86TYPE_VU1:0), _Ft_, 2); + MOV16ItoM( SuperVUGetVIAddr(_Ft_, 0), (pc+8)>>3 ); + } + + if( s_pCurBlock->blocks.size() > 1 ) { + s_JumpX86 = _allocX86reg(-1, X86TYPE_VUJUMP, 0, MODE_WRITE); + MOV32ItoR(s_JumpX86, 0); + s_pCurBlock->pChildJumps[(s_pCurInst->type & INST_BRANCH_DELAY)?1:0] = (u32*)x86Ptr-1; + s_UnconditionalDelay = 1; + } + + branch |= 3; +} + +void recVUMI_JR( VURegs* vuu, s32 info ) +{ + int fsreg = _allocX86reg(-1, X86TYPE_VI|(s_vu?X86TYPE_VU1:0), _Fs_, MODE_READ); + LEA32RStoR(EAX, fsreg, 3); + CWDE(); + + if( (s_pCurBlock->type & BLOCKTYPE_HASEOP) || s_vu == 0 ) MOV32RtoM(SuperVUGetVIAddr(REG_TPC, 0), EAX); + + if( !(s_pCurBlock->type & BLOCKTYPE_HASEOP) ) { + PUSH32I(s_vu); + PUSH32R(EAX); + } + branch |= 0x10; // 0x08 is reserved +} + +void recVUMI_JALR( VURegs* vuu, s32 info ) +{ + _addNeededX86reg(X86TYPE_VI|(s_vu?X86TYPE_VU1:0), _Ft_); + + int fsreg = _allocX86reg(-1, X86TYPE_VI|(s_vu?X86TYPE_VU1:0), _Fs_, MODE_READ); + LEA32RStoR(EAX, fsreg, 3); + CWDE(); // necessary, charlie and chocolate factory gives bad addrs, but graphics are ok + + if ( _Ft_ ) { + _deleteX86reg(X86TYPE_VI|(s_vu?X86TYPE_VU1:0), _Ft_, 2); + MOV16ItoM( SuperVUGetVIAddr(_Ft_, 0), (pc+8)>>3 ); + } + + if( (s_pCurBlock->type & BLOCKTYPE_HASEOP) || s_vu == 0 ) MOV32RtoM(SuperVUGetVIAddr(REG_TPC, 0), EAX); + + if( !(s_pCurBlock->type & BLOCKTYPE_HASEOP) ) { + PUSH32I(s_vu); + PUSH32R(EAX); + } + + branch |= 4; +} + +#ifdef SUPERVU_COUNT +void StopSVUCounter() +{ + QueryPerformanceCounter(&svufinal); + svutime += (u32)(svufinal.QuadPart-svubase.QuadPart); +} + +void StartSVUCounter() +{ + QueryPerformanceCounter(&svubase); +} +#endif + +#ifdef PCSX2_DEVBUILD +void vu1xgkick(u32* pMem, u32 addr) +{ + assert( addr < 0x4000 ); +#ifdef SUPERVU_COUNT + StopSVUCounter(); +#endif + + GSGIFTRANSFER1(pMem, addr); + +#ifdef SUPERVU_COUNT + StartSVUCounter(); +#endif +} +#endif + +void recVUMI_XGKICK_( VURegs *VU ) +{ + assert( s_XGKICKReg > 0 && x86regs[s_XGKICKReg].inuse && x86regs[s_XGKICKReg].type == X86TYPE_VITEMP); + + x86regs[s_XGKICKReg].inuse = 0; // so free doesn't flush + _freeX86regs(); + _freeXMMregs(); + + PUSH32R(s_XGKICKReg); + PUSH32I((uptr)VU->Mem); + + //CALLFunc((u32)countfn); + + if( mtgsThread != NULL ) { + CALLFunc((uptr)VU1XGKICK_MTGSTransfer); + ADD32ItoR(ESP, 8); + } + else { +#ifdef PCSX2_DEVBUILD + CALLFunc((uptr)vu1xgkick); + ADD32ItoR(ESP, 8); +#else + CALLFunc((uptr)GSgifTransfer1); +#endif + } + + s_ScheduleXGKICK = 0; +} + +void recVUMI_XGKICK( VURegs *VU, int info ) +{ + if( s_ScheduleXGKICK ) { + // second xgkick, so launch the first + recVUMI_XGKICK_(VU); + } + + int fsreg = _allocX86reg(X86ARG2, X86TYPE_VI|(s_vu?X86TYPE_VU1:0), _Fs_, MODE_READ); + _freeX86reg(fsreg); // flush + x86regs[fsreg].inuse = 1; + x86regs[fsreg].type = X86TYPE_VITEMP; + x86regs[fsreg].needed = 1; + x86regs[fsreg].mode = MODE_WRITE|MODE_READ; + SHL32ItoR(fsreg, 4); + AND32ItoR(fsreg, 0x3fff); + s_XGKICKReg = fsreg; + + if( !SUPERVU_XGKICKDELAY || pc == s_pCurBlock->endpc ) { + recVUMI_XGKICK_(VU); + } + else { + if( g_VUGameFixes & VUFIX_XGKICKDELAY2 ) + s_ScheduleXGKICK = min((u32)4, (s_pCurBlock->endpc-pc)/8); + else + s_ScheduleXGKICK = 2; + } +} + +void recVU_UPPER_FD_00( VURegs* VU, s32 info ); +void recVU_UPPER_FD_01( VURegs* VU, s32 info ); +void recVU_UPPER_FD_10( VURegs* VU, s32 info ); +void recVU_UPPER_FD_11( VURegs* VU, s32 info ); +void recVULowerOP( VURegs* VU, s32 info ); +void recVULowerOP_T3_00( VURegs* VU, s32 info ); +void recVULowerOP_T3_01( VURegs* VU, s32 info ); +void recVULowerOP_T3_10( VURegs* VU, s32 info ); +void recVULowerOP_T3_11( VURegs* VU, s32 info ); +void recVUunknown( VURegs* VU, s32 info ); + +void (*recVU_LOWER_OPCODE[128])( VURegs* VU, s32 info ) = { + recVUMI_LQ , recVUMI_SQ , recVUunknown , recVUunknown, + recVUMI_ILW , recVUMI_ISW , recVUunknown , recVUunknown, + recVUMI_IADDIU, recVUMI_ISUBIU, recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUMI_FCEQ , recVUMI_FCSET , recVUMI_FCAND, recVUMI_FCOR, /* 0x10 */ + recVUMI_FSEQ , recVUMI_FSSET , recVUMI_FSAND, recVUMI_FSOR, + recVUMI_FMEQ , recVUunknown , recVUMI_FMAND, recVUMI_FMOR, + recVUMI_FCGET , recVUunknown , recVUunknown , recVUunknown, + recVUMI_B , recVUMI_BAL , recVUunknown , recVUunknown, /* 0x20 */ + recVUMI_JR , recVUMI_JALR , recVUunknown , recVUunknown, + recVUMI_IBEQ , recVUMI_IBNE , recVUunknown , recVUunknown, + recVUMI_IBLTZ , recVUMI_IBGTZ , recVUMI_IBLEZ, recVUMI_IBGEZ, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, /* 0x30 */ + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVULowerOP , recVUunknown , recVUunknown , recVUunknown, /* 0x40*/ + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, /* 0x50 */ + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, /* 0x60 */ + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, /* 0x70 */ + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, +}; + +void (*recVULowerOP_T3_00_OPCODE[32])(VURegs* VU, s32 info) = { + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUMI_MOVE , recVUMI_LQI , recVUMI_DIV , recVUMI_MTIR, + recVUMI_RNEXT , recVUunknown , recVUunknown , recVUunknown, /* 0x10 */ + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUMI_MFP , recVUMI_XTOP , recVUMI_XGKICK, + recVUMI_ESADD , recVUMI_EATANxy, recVUMI_ESQRT, recVUMI_ESIN, +}; + +void (*recVULowerOP_T3_01_OPCODE[32])(VURegs* VU, s32 info) = { + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUMI_MR32 , recVUMI_SQI , recVUMI_SQRT , recVUMI_MFIR, + recVUMI_RGET , recVUunknown , recVUunknown , recVUunknown, /* 0x10 */ + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUMI_XITOP, recVUunknown, + recVUMI_ERSADD, recVUMI_EATANxz, recVUMI_ERSQRT, recVUMI_EATAN, +}; + +void (*recVULowerOP_T3_10_OPCODE[32])(VURegs* VU, s32 info) = { + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUMI_LQD , recVUMI_RSQRT, recVUMI_ILWR, + recVUMI_RINIT , recVUunknown , recVUunknown , recVUunknown, /* 0x10 */ + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUMI_ELENG , recVUMI_ESUM , recVUMI_ERCPR, recVUMI_EEXP, +}; + +void (*recVULowerOP_T3_11_OPCODE[32])(VURegs* VU, s32 info) = { + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUMI_SQD , recVUMI_WAITQ, recVUMI_ISWR, + recVUMI_RXOR , recVUunknown , recVUunknown , recVUunknown, /* 0x10 */ + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUMI_ERLENG, recVUunknown , recVUMI_WAITP, recVUunknown, +}; + +void (*recVULowerOP_OPCODE[64])(VURegs* VU, s32 info) = { + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, /* 0x10 */ + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, /* 0x20 */ + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUMI_IADD , recVUMI_ISUB , recVUMI_IADDI, recVUunknown, /* 0x30 */ + recVUMI_IAND , recVUMI_IOR , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVULowerOP_T3_00, recVULowerOP_T3_01, recVULowerOP_T3_10, recVULowerOP_T3_11, +}; + +void (*recVU_UPPER_OPCODE[64])(VURegs* VU, s32 info) = { + recVUMI_ADDx , recVUMI_ADDy , recVUMI_ADDz , recVUMI_ADDw, + recVUMI_SUBx , recVUMI_SUBy , recVUMI_SUBz , recVUMI_SUBw, + recVUMI_MADDx , recVUMI_MADDy , recVUMI_MADDz , recVUMI_MADDw, + recVUMI_MSUBx , recVUMI_MSUBy , recVUMI_MSUBz , recVUMI_MSUBw, + recVUMI_MAXx , recVUMI_MAXy , recVUMI_MAXz , recVUMI_MAXw, /* 0x10 */ + recVUMI_MINIx , recVUMI_MINIy , recVUMI_MINIz , recVUMI_MINIw, + recVUMI_MULx , recVUMI_MULy , recVUMI_MULz , recVUMI_MULw, + recVUMI_MULq , recVUMI_MAXi , recVUMI_MULi , recVUMI_MINIi, + recVUMI_ADDq , recVUMI_MADDq , recVUMI_ADDi , recVUMI_MADDi, /* 0x20 */ + recVUMI_SUBq , recVUMI_MSUBq , recVUMI_SUBi , recVUMI_MSUBi, + recVUMI_ADD , recVUMI_MADD , recVUMI_MUL , recVUMI_MAX, + recVUMI_SUB , recVUMI_MSUB , recVUMI_OPMSUB, recVUMI_MINI, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, /* 0x30 */ + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVUunknown , recVUunknown , recVUunknown , recVUunknown, + recVU_UPPER_FD_00, recVU_UPPER_FD_01, recVU_UPPER_FD_10, recVU_UPPER_FD_11, +}; + +void (*recVU_UPPER_FD_00_TABLE[32])(VURegs* VU, s32 info) = { + recVUMI_ADDAx, recVUMI_SUBAx , recVUMI_MADDAx, recVUMI_MSUBAx, + recVUMI_ITOF0, recVUMI_FTOI0, recVUMI_MULAx , recVUMI_MULAq , + recVUMI_ADDAq, recVUMI_SUBAq, recVUMI_ADDA , recVUMI_SUBA , + recVUunknown , recVUunknown , recVUunknown , recVUunknown , + recVUunknown , recVUunknown , recVUunknown , recVUunknown , + recVUunknown , recVUunknown , recVUunknown , recVUunknown , + recVUunknown , recVUunknown , recVUunknown , recVUunknown , + recVUunknown , recVUunknown , recVUunknown , recVUunknown , +}; + +void (*recVU_UPPER_FD_01_TABLE[32])(VURegs* VU, s32 info) = { + recVUMI_ADDAy , recVUMI_SUBAy , recVUMI_MADDAy, recVUMI_MSUBAy, + recVUMI_ITOF4 , recVUMI_FTOI4 , recVUMI_MULAy , recVUMI_ABS , + recVUMI_MADDAq, recVUMI_MSUBAq, recVUMI_MADDA , recVUMI_MSUBA , + recVUunknown , recVUunknown , recVUunknown , recVUunknown , + recVUunknown , recVUunknown , recVUunknown , recVUunknown , + recVUunknown , recVUunknown , recVUunknown , recVUunknown , + recVUunknown , recVUunknown , recVUunknown , recVUunknown , + recVUunknown , recVUunknown , recVUunknown , recVUunknown , +}; + +void (*recVU_UPPER_FD_10_TABLE[32])(VURegs* VU, s32 info) = { + recVUMI_ADDAz , recVUMI_SUBAz , recVUMI_MADDAz, recVUMI_MSUBAz, + recVUMI_ITOF12, recVUMI_FTOI12, recVUMI_MULAz , recVUMI_MULAi , + recVUMI_ADDAi, recVUMI_SUBAi , recVUMI_MULA , recVUMI_OPMULA, + recVUunknown , recVUunknown , recVUunknown , recVUunknown , + recVUunknown , recVUunknown , recVUunknown , recVUunknown , + recVUunknown , recVUunknown , recVUunknown , recVUunknown , + recVUunknown , recVUunknown , recVUunknown , recVUunknown , + recVUunknown , recVUunknown , recVUunknown , recVUunknown , +}; + +void (*recVU_UPPER_FD_11_TABLE[32])(VURegs* VU, s32 info) = { + recVUMI_ADDAw , recVUMI_SUBAw , recVUMI_MADDAw, recVUMI_MSUBAw, + recVUMI_ITOF15, recVUMI_FTOI15, recVUMI_MULAw , recVUMI_CLIP , + recVUMI_MADDAi, recVUMI_MSUBAi, recVUunknown , recVUMI_NOP , + recVUunknown , recVUunknown , recVUunknown , recVUunknown , + recVUunknown , recVUunknown , recVUunknown , recVUunknown , + recVUunknown , recVUunknown , recVUunknown , recVUunknown , + recVUunknown , recVUunknown , recVUunknown , recVUunknown , + recVUunknown , recVUunknown , recVUunknown , recVUunknown , +}; + +void recVU_UPPER_FD_00( VURegs* VU, s32 info ) +{ + recVU_UPPER_FD_00_TABLE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); +} + +void recVU_UPPER_FD_01( VURegs* VU, s32 info ) +{ + recVU_UPPER_FD_01_TABLE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); +} + +void recVU_UPPER_FD_10( VURegs* VU, s32 info ) +{ + recVU_UPPER_FD_10_TABLE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); +} + +void recVU_UPPER_FD_11( VURegs* VU, s32 info ) +{ + recVU_UPPER_FD_11_TABLE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); +} + +void recVULowerOP( VURegs* VU, s32 info ) +{ + recVULowerOP_OPCODE[ VU->code & 0x3f ]( VU, info ); +} + +void recVULowerOP_T3_00( VURegs* VU, s32 info ) +{ + recVULowerOP_T3_00_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); +} + +void recVULowerOP_T3_01( VURegs* VU, s32 info ) +{ + recVULowerOP_T3_01_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); +} + +void recVULowerOP_T3_10( VURegs* VU, s32 info ) +{ + recVULowerOP_T3_10_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); +} + +void recVULowerOP_T3_11( VURegs* VU, s32 info ) +{ + recVULowerOP_T3_11_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); +} + +void recVUunknown( VURegs* VU, s32 info ) +{ + SysPrintf("Unknown SVU micromode opcode called\n"); +} diff --git a/pcsx2/x86/iVUzerorec.h b/pcsx2/x86/iVUzerorec.h index c62a166d9f..1f451fd58f 100644 --- a/pcsx2/x86/iVUzerorec.h +++ b/pcsx2/x86/iVUzerorec.h @@ -1,50 +1,50 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -// Super VU recompiler - author: zerofrog(@gmail.com) - -#ifndef VU1_SUPER_RECOMPILER -#define VU1_SUPER_RECOMPILER - -#include "iVUmicro.h" - -extern void SuperVUAlloc(int vuindex); // global VU resources are automatically allocated if necessary. -extern void SuperVUDestroy(int vuindex); // if vuindex is -1, destroys everything -extern void SuperVUReset(int vuindex); // if vuindex is -1, resets everything - -//Using assembly code from an external file. -#ifdef __LINUX__ -extern "C" { -#endif -extern void SuperVUExecuteProgram(u32 startpc, int vuindex); -extern void SuperVUEndProgram(); -extern void svudispfntemp(); -#ifdef __LINUX__ -} -#endif -extern void __fastcall SuperVUClear(u32 startpc, u32 size, int vuindex); - -// read = 0, will write to reg -// read = 1, will read from reg -// read = 2, addr of previously written reg (used for status and clip flags) -extern u32 SuperVUGetVIAddr(int reg, int read); - -// if p == 0, flush q else flush p; if wait is != 0, waits for p/q -extern void SuperVUFlush(int p, int wait); - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +// Super VU recompiler - author: zerofrog(@gmail.com) + +#ifndef VU1_SUPER_RECOMPILER +#define VU1_SUPER_RECOMPILER + +#include "iVUmicro.h" + +extern void SuperVUAlloc(int vuindex); // global VU resources are automatically allocated if necessary. +extern void SuperVUDestroy(int vuindex); // if vuindex is -1, destroys everything +extern void SuperVUReset(int vuindex); // if vuindex is -1, resets everything + +//Using assembly code from an external file. +#ifdef __LINUX__ +extern "C" { +#endif +extern void SuperVUExecuteProgram(u32 startpc, int vuindex); +extern void SuperVUEndProgram(); +extern void svudispfntemp(); +#ifdef __LINUX__ +} +#endif +extern void __fastcall SuperVUClear(u32 startpc, u32 size, int vuindex); + +// read = 0, will write to reg +// read = 1, will read from reg +// read = 2, addr of previously written reg (used for status and clip flags) +extern u32 SuperVUGetVIAddr(int reg, int read); + +// if p == 0, flush q else flush p; if wait is != 0, waits for p/q +extern void SuperVUFlush(int p, int wait); + +#endif diff --git a/pcsx2/x86/iVif.cpp b/pcsx2/x86/iVif.cpp index 3eeba0b22b..93fed101c4 100644 --- a/pcsx2/x86/iVif.cpp +++ b/pcsx2/x86/iVif.cpp @@ -1,139 +1,139 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "ix86/ix86.h" -#include "Vif.h" -#include "VUmicro.h" - -// sse2 highly optimized vif (~200 separate functions are built) zerofrog(@gmail.com) -extern u32 g_vif1Masks[48], g_vif0Masks[48]; -extern u32 g_vif1HasMask3[4], g_vif0HasMask3[4]; - -//static const u32 writearr[4] = { 0xffffffff, 0, 0, 0 }; -//static const u32 rowarr[4] = { 0, 0xffffffff, 0, 0 }; -//static const u32 colarr[4] = { 0, 0, 0xffffffff, 0 }; -//static const u32 updatearr[4] = {0xffffffff, 0xffffffff, 0xffffffff, 0 }; - -// arranged in writearr, rowarr, colarr, updatearr -static PCSX2_ALIGNED16(u32 s_maskarr[16][4]) = { - 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, - 0xffff0000, 0x0000ffff, 0x00000000, 0xffffffff, - 0xffff0000, 0x00000000, 0x0000ffff, 0xffffffff, - 0xffff0000, 0x00000000, 0x00000000, 0xffff0000, - 0x0000ffff, 0xffff0000, 0x00000000, 0xffffffff, - 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, - 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff, - 0x00000000, 0xffff0000, 0x00000000, 0xffff0000, - 0x0000ffff, 0x00000000, 0xffff0000, 0xffffffff, - 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff, - 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, - 0x00000000, 0x00000000, 0xffff0000, 0xffff0000, - 0x0000ffff, 0x00000000, 0x00000000, 0x0000ffff, - 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, - 0x00000000, 0x00000000, 0x0000ffff, 0x0000ffff, - 0x00000000, 0x00000000, 0x00000000, 0x00000000 -}; - -extern u8 s_maskwrite[256]; - -extern "C" PCSX2_ALIGNED16(u32 s_TempDecompress[4]) = {0}; - -#if defined(_MSC_VER) - -#include -#include - -void SetNewMask(u32* vif1masks, u32* hasmask, u32 mask, u32 oldmask) -{ - u32 i; - u32 prev = 0; - FreezeXMMRegs(1); - for(i = 0; i < 4; ++i, mask >>= 8, oldmask >>= 8, vif1masks += 16) { - - prev |= s_maskwrite[mask&0xff];//((mask&3)==3)||((mask&0xc)==0xc)||((mask&0x30)==0x30)||((mask&0xc0)==0xc0); - hasmask[i] = prev; - - if( (mask&0xff) != (oldmask&0xff) ) { - __m128i r0, r1, r2, r3; - r0 = _mm_load_si128((__m128i*)&s_maskarr[mask&15][0]); - r2 = _mm_unpackhi_epi16(r0, r0); - r0 = _mm_unpacklo_epi16(r0, r0); - - r1 = _mm_load_si128((__m128i*)&s_maskarr[(mask>>4)&15][0]); - r3 = _mm_unpackhi_epi16(r1, r1); - r1 = _mm_unpacklo_epi16(r1, r1); - - _mm_storel_pi((__m64*)&vif1masks[0], *(__m128*)&r0); - _mm_storel_pi((__m64*)&vif1masks[2], *(__m128*)&r1); - _mm_storeh_pi((__m64*)&vif1masks[4], *(__m128*)&r0); - _mm_storeh_pi((__m64*)&vif1masks[6], *(__m128*)&r1); - - _mm_storel_pi((__m64*)&vif1masks[8], *(__m128*)&r2); - _mm_storel_pi((__m64*)&vif1masks[10], *(__m128*)&r3); - _mm_storeh_pi((__m64*)&vif1masks[12], *(__m128*)&r2); - _mm_storeh_pi((__m64*)&vif1masks[14], *(__m128*)&r3); - } - } - FreezeXMMRegs(0); -} - - -#else // gcc - -void SetNewMask(u32* vif1masks, u32* hasmask, u32 mask, u32 oldmask) -{ - u32 i; - u32 prev = 0; - FreezeXMMRegs(1); - - for(i = 0; i < 4; ++i, mask >>= 8, oldmask >>= 8, vif1masks += 16) { - - prev |= s_maskwrite[mask&0xff];//((mask&3)==3)||((mask&0xc)==0xc)||((mask&0x30)==0x30)||((mask&0xc0)==0xc0); - hasmask[i] = prev; - - if( (mask&0xff) != (oldmask&0xff) ) { - u8* p0 = (u8*)&s_maskarr[mask&15][0]; - u8* p1 = (u8*)&s_maskarr[(mask>>4)&15][0]; - - __asm__(".intel_syntax\n" - "movaps %%xmm0, [%0]\n" - "movaps %%xmm1, [%1]\n" - "movaps %%xmm2, %%xmm0\n" - "punpcklwd %%xmm0, %%xmm0\n" - "punpckhwd %%xmm2, %%xmm2\n" - "movaps %%xmm3, %%xmm1\n" - "punpcklwd %%xmm1, %%xmm1\n" - "punpckhwd %%xmm3, %%xmm3\n" - "movq [%2], %%xmm0\n" - "movq [%2+8], %%xmm1\n" - "movhps [%2+16], %%xmm0\n" - "movhps [%2+24], %%xmm1\n" - "movq [%2+32], %%xmm2\n" - "movq [%2+40], %%xmm3\n" - "movhps [%2+48], %%xmm2\n" - "movhps [%2+56], %%xmm3\n" - ".att_syntax\n" : : "r"(p0), "r"(p1), "r"(vif1masks) ); - } - } - FreezeXMMRegs(0); -} - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "ix86/ix86.h" +#include "Vif.h" +#include "VUmicro.h" + +// sse2 highly optimized vif (~200 separate functions are built) zerofrog(@gmail.com) +extern u32 g_vif1Masks[48], g_vif0Masks[48]; +extern u32 g_vif1HasMask3[4], g_vif0HasMask3[4]; + +//static const u32 writearr[4] = { 0xffffffff, 0, 0, 0 }; +//static const u32 rowarr[4] = { 0, 0xffffffff, 0, 0 }; +//static const u32 colarr[4] = { 0, 0, 0xffffffff, 0 }; +//static const u32 updatearr[4] = {0xffffffff, 0xffffffff, 0xffffffff, 0 }; + +// arranged in writearr, rowarr, colarr, updatearr +static PCSX2_ALIGNED16(u32 s_maskarr[16][4]) = { + 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, + 0xffff0000, 0x0000ffff, 0x00000000, 0xffffffff, + 0xffff0000, 0x00000000, 0x0000ffff, 0xffffffff, + 0xffff0000, 0x00000000, 0x00000000, 0xffff0000, + 0x0000ffff, 0xffff0000, 0x00000000, 0xffffffff, + 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, + 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff, + 0x00000000, 0xffff0000, 0x00000000, 0xffff0000, + 0x0000ffff, 0x00000000, 0xffff0000, 0xffffffff, + 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff, + 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, + 0x00000000, 0x00000000, 0xffff0000, 0xffff0000, + 0x0000ffff, 0x00000000, 0x00000000, 0x0000ffff, + 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, + 0x00000000, 0x00000000, 0x0000ffff, 0x0000ffff, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +extern u8 s_maskwrite[256]; + +extern "C" PCSX2_ALIGNED16(u32 s_TempDecompress[4]) = {0}; + +#if defined(_MSC_VER) + +#include +#include + +void SetNewMask(u32* vif1masks, u32* hasmask, u32 mask, u32 oldmask) +{ + u32 i; + u32 prev = 0; + FreezeXMMRegs(1); + for(i = 0; i < 4; ++i, mask >>= 8, oldmask >>= 8, vif1masks += 16) { + + prev |= s_maskwrite[mask&0xff];//((mask&3)==3)||((mask&0xc)==0xc)||((mask&0x30)==0x30)||((mask&0xc0)==0xc0); + hasmask[i] = prev; + + if( (mask&0xff) != (oldmask&0xff) ) { + __m128i r0, r1, r2, r3; + r0 = _mm_load_si128((__m128i*)&s_maskarr[mask&15][0]); + r2 = _mm_unpackhi_epi16(r0, r0); + r0 = _mm_unpacklo_epi16(r0, r0); + + r1 = _mm_load_si128((__m128i*)&s_maskarr[(mask>>4)&15][0]); + r3 = _mm_unpackhi_epi16(r1, r1); + r1 = _mm_unpacklo_epi16(r1, r1); + + _mm_storel_pi((__m64*)&vif1masks[0], *(__m128*)&r0); + _mm_storel_pi((__m64*)&vif1masks[2], *(__m128*)&r1); + _mm_storeh_pi((__m64*)&vif1masks[4], *(__m128*)&r0); + _mm_storeh_pi((__m64*)&vif1masks[6], *(__m128*)&r1); + + _mm_storel_pi((__m64*)&vif1masks[8], *(__m128*)&r2); + _mm_storel_pi((__m64*)&vif1masks[10], *(__m128*)&r3); + _mm_storeh_pi((__m64*)&vif1masks[12], *(__m128*)&r2); + _mm_storeh_pi((__m64*)&vif1masks[14], *(__m128*)&r3); + } + } + FreezeXMMRegs(0); +} + + +#else // gcc + +void SetNewMask(u32* vif1masks, u32* hasmask, u32 mask, u32 oldmask) +{ + u32 i; + u32 prev = 0; + FreezeXMMRegs(1); + + for(i = 0; i < 4; ++i, mask >>= 8, oldmask >>= 8, vif1masks += 16) { + + prev |= s_maskwrite[mask&0xff];//((mask&3)==3)||((mask&0xc)==0xc)||((mask&0x30)==0x30)||((mask&0xc0)==0xc0); + hasmask[i] = prev; + + if( (mask&0xff) != (oldmask&0xff) ) { + u8* p0 = (u8*)&s_maskarr[mask&15][0]; + u8* p1 = (u8*)&s_maskarr[(mask>>4)&15][0]; + + __asm__(".intel_syntax\n" + "movaps %%xmm0, [%0]\n" + "movaps %%xmm1, [%1]\n" + "movaps %%xmm2, %%xmm0\n" + "punpcklwd %%xmm0, %%xmm0\n" + "punpckhwd %%xmm2, %%xmm2\n" + "movaps %%xmm3, %%xmm1\n" + "punpcklwd %%xmm1, %%xmm1\n" + "punpckhwd %%xmm3, %%xmm3\n" + "movq [%2], %%xmm0\n" + "movq [%2+8], %%xmm1\n" + "movhps [%2+16], %%xmm0\n" + "movhps [%2+24], %%xmm1\n" + "movq [%2+32], %%xmm2\n" + "movq [%2+40], %%xmm3\n" + "movhps [%2+48], %%xmm2\n" + "movhps [%2+56], %%xmm3\n" + ".att_syntax\n" : : "r"(p0), "r"(p1), "r"(vif1masks) ); + } + } + FreezeXMMRegs(0); +} + +#endif diff --git a/pcsx2/x86/ir5900tables.cpp b/pcsx2/x86/ir5900tables.cpp index f9ee0a3fac..17c17cd621 100644 --- a/pcsx2/x86/ir5900tables.cpp +++ b/pcsx2/x86/ir5900tables.cpp @@ -1,1049 +1,1049 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -// Holds instruction tables for the r5900 recompiler - -#include "PrecompiledHeader.h" - -#include "Common.h" -#include "Memory.h" -#include "R5900OpcodeTables.h" -#include "ix86/ix86.h" -#include "iR5900.h" -#include "iR5900AritImm.h" -#include "iR5900Arit.h" -#include "iR5900MultDiv.h" -#include "iR5900Shift.h" -#include "iR5900Branch.h" -#include "iR5900Jump.h" -#include "iR5900LoadStore.h" -#include "iR5900Move.h" -#include "iMMI.h" -#include "iFPU.h" -#include "iCOP0.h" - -// Use this to call into interpreter functions that require an immediate branchtest -// to be done afterward (anything that throws an exception or enables interrupts, etc). -void recBranchCall( void (*func)() ) -{ - // In order to make sure a branch test is performed, the nextBranchCycle is set - // to the current cpu cycle. - - MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); - MOV32MtoR( EAX, (uptr)&cpuRegs.cycle ); - MOV32ItoM( (uptr)&cpuRegs.pc, pc ); - MOV32RtoM( (uptr)&g_nextBranchCycle, EAX ); - - // Might as well flush everything -- it'll all get flushed when the - // recompiler inserts the branchtest anyway. - iFlushCall(FLUSH_EVERYTHING); - CALLFunc( (uptr)func ); - branch = 2; -} - -void recCall( void (*func)(), int delreg ) -{ - MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (uptr)&cpuRegs.pc, pc ); - - iFlushCall(FLUSH_EVERYTHING); - if( delreg > 0 ) _deleteEEreg(delreg, 0); - CALLFunc( (uptr)func ); -} - -using namespace R5900::Dynarec::OpcodeImpl; - -#ifdef PCSX2_VM_COISSUE -// coissued insts -void (*recBSC_co[64] )() = { - recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, - recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, - recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, - recNULL, recNULL, recLDL_co, recLDR_co, recNULL, recNULL, recLQ_co, recSQ_co, - recLB_co, recLH_co, recLWL_co, recLW_co, recLBU_co, recLHU_co, recLWR_co, recLWU_co, - recSB_co, recSH_co, recSWL_co, recSW_co, recSDL_co, recSDR_co, recSWR_co, recNULL, - recNULL, recLWC1_co, recNULL, recNULL, recNULL, recNULL, recLQC2_co, recLD_co, - recNULL, recSWC1_co, recNULL, recNULL, recNULL, recNULL, recSQC2_co, recSD_co -}; -#endif - - -//////////////////////////////////////////////// -// Back-Prob Function Tables - Gathering Info // -//////////////////////////////////////////////// -BSCPropagate::BSCPropagate( EEINST& previous, EEINST& pinstance ) : - prev( previous ) -, pinst( pinstance ) -{ -} - -void BSCPropagate::rpropSetRead( int reg, int mask ) -{ - if( !(pinst.regs[reg] & EEINST_USED) ) - pinst.regs[reg] |= EEINST_LASTUSE; - prev.regs[reg] |= EEINST_LIVE0|(mask)|EEINST_USED; - pinst.regs[reg] |= EEINST_USED; - if( reg ) pinst.info = ((mask)&(EEINST_MMX|EEINST_XMM)); - _recFillRegister(pinst, XMMTYPE_GPRREG, reg, 0); -} - -template< int live > -void BSCPropagate::rpropSetWrite0( int reg, int mask ) -{ - prev.regs[reg] &= ~((mask)|live|EEINST_XMM|EEINST_MMX); - if( !(pinst.regs[reg] & EEINST_USED) ) - pinst.regs[reg] |= EEINST_LASTUSE; - pinst.regs[reg] |= EEINST_USED; - prev.regs[reg] |= EEINST_USED; - _recFillRegister(pinst, XMMTYPE_GPRREG, reg, 1); -} - -__forceinline void BSCPropagate::rpropSetWrite( int reg, int mask ) -{ - rpropSetWrite0( reg, mask ); -} - -__forceinline void BSCPropagate::rpropSetFast( int write1, int read1, int read2, int mask ) -{ - if( write1 ) { rpropSetWrite(write1,mask); } - if( read1 ) { rpropSetRead(read1,mask); } - if( read2 ) { rpropSetRead(read2,mask); } -} - -template< int lo, int hi > -void BSCPropagate::rpropSetLOHI( int write1, int read1, int read2, int mask ) -{ - if( write1 ) { rpropSetWrite(write1,mask); } - if( lo & MODE_WRITE ) { rpropSetWrite(XMMGPR_LO,mask); } - if( hi & MODE_WRITE ) { rpropSetWrite(XMMGPR_HI,mask); } - if( read1 ) { rpropSetRead(read1,mask); } - if( read2 ) { rpropSetRead(read2,mask); } - if( lo & MODE_READ ) { rpropSetRead(XMMGPR_LO,mask); } - if( hi & MODE_READ ) { rpropSetRead(XMMGPR_HI,mask); } -} - -// FPU regs -void BSCPropagate::rpropSetFPURead( int reg, int mask ) -{ - if( !(pinst.fpuregs[reg] & EEINST_USED) ) - pinst.fpuregs[reg] |= EEINST_LASTUSE; - prev.fpuregs[reg] |= EEINST_LIVE0|(mask)|EEINST_USED; - pinst.fpuregs[reg] |= EEINST_USED; - if( reg ) pinst.info = ((mask)&(EEINST_MMX|EEINST_XMM)); - if( reg == XMMFPU_ACC ) _recFillRegister(pinst, XMMTYPE_FPACC, 0, 0); - else _recFillRegister(pinst, XMMTYPE_FPREG, reg, 0); -} - -template< int live > -void BSCPropagate::rpropSetFPUWrite0( int reg, int mask ) -{ - prev.fpuregs[reg] &= ~((mask)|live|EEINST_XMM|EEINST_MMX); - if( !(pinst.fpuregs[reg] & EEINST_USED) ) - pinst.fpuregs[reg] |= EEINST_LASTUSE; - pinst.fpuregs[reg] |= EEINST_USED; - prev.fpuregs[reg] |= EEINST_USED; - if( reg == XMMFPU_ACC ) _recFillRegister(pinst, XMMTYPE_FPACC, 0, 1); - else _recFillRegister(pinst, XMMTYPE_FPREG, reg, 1); -} - -__forceinline void BSCPropagate::rpropSetFPUWrite( int reg, int mask ) -{ - rpropSetFPUWrite0( reg, mask ); -} - - -#define EEINST_REALXMM EEINST_XMM - -//SLL, NULL, SRL, SRA, SLLV, NULL, SRLV, SRAV, -//JR, JALR, MOVZ, MOVN, SYSCALL, BREAK, NULL, SYNC, -//MFHI, MTHI, MFLO, MTLO, DSLLV, NULL, DSRLV, DSRAV, -//MULT, MULTU, DIV, DIVU, NULL, NULL, NULL, NULL, -//ADD, ADDU, SUB, SUBU, AND, OR, XOR, NOR, -//MFSA, MTSA, SLT, SLTU, DADD, DADDU, DSUB, DSUBU, -//TGE, TGEU, TLT, TLTU, TEQ, NULL, TNE, NULL, -//DSLL, NULL, DSRL, DSRA, DSLL32, NULL, DSRL32, DSRA32 - -__forceinline void BSCPropagate::rpropSPECIAL() -{ - switch(_Funct_) { - case 0: // SLL - case 2: // SRL - case 3: // SRA - rpropSetWrite(_Rd_, EEINST_LIVE1); - rpropSetRead(_Rt_, EEINST_MMX); - break; - - case 4: // sllv - case 6: // srlv - case 7: // srav - rpropSetWrite(_Rd_, EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_MMX); - rpropSetRead(_Rt_, EEINST_MMX); - break; - - case 8: // JR - rpropSetRead(_Rs_, 0); - break; - case 9: // JALR - rpropSetWrite(_Rd_, EEINST_LIVE1); - rpropSetRead(_Rs_, 0); - break; - - case 10: // movz - case 11: // movn - // do not write _Rd_! - rpropSetRead(_Rs_, EEINST_LIVE1); - rpropSetRead(_Rt_, EEINST_LIVE1); - rpropSetRead(_Rd_, EEINST_LIVE1); - pinst.info |= EEINST_MMX; - _recFillRegister(pinst, XMMTYPE_GPRREG, _Rd_, 1); - break; - - case 12: // syscall - case 13: // break - _recClearInst(&prev); - prev.info = 0; - break; - case 15: // sync - break; - - case 16: // mfhi - rpropSetWrite(_Rd_, EEINST_LIVE1); - rpropSetRead(XMMGPR_HI, (pinst.regs[_Rd_]&(EEINST_MMX|EEINST_REALXMM))|EEINST_LIVE1); - break; - case 17: // mthi - rpropSetWrite(XMMGPR_HI, EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_LIVE1); - break; - case 18: // mflo - rpropSetWrite(_Rd_, EEINST_LIVE1); - rpropSetRead(XMMGPR_LO, (pinst.regs[_Rd_]&(EEINST_MMX|EEINST_REALXMM))|EEINST_LIVE1); - break; - case 19: // mtlo - rpropSetWrite(XMMGPR_LO, EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_LIVE1); - break; - - case 20: // dsllv - case 22: // dsrlv - case 23: // dsrav - rpropSetWrite(_Rd_, EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_MMX); - rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_MMX); - break; - - //case 24: // mult - // // can do unsigned mult only if HI isn't used - - // //using this allocation for temp causes the emu to crash - // //temp = (pinst.regs[XMMGPR_HI]&(EEINST_LIVE0|EEINST_LIVE1))?0:EEINST_MMX; - // temp = 0; - // rpropSetWrite(XMMGPR_LO, EEINST_LIVE1); - // rpropSetWrite(XMMGPR_HI, EEINST_LIVE1); - // rpropSetWrite(_Rd_, EEINST_LIVE1); - // - // // fixme - temp is always 0, so I doubt the next three lines are right. (arcum42) - - // // Yep, its wrong. Using always 0 causes the wrong damage calculations in Soul Nomad. - // rpropSetRead(_Rs_, temp); - // rpropSetRead(_Rt_, temp); - // pinst.info |= temp; - // break; - - //case 25: // multu - // rpropSetWrite(XMMGPR_LO, EEINST_LIVE1); - // rpropSetWrite(XMMGPR_HI, EEINST_LIVE1); - // rpropSetWrite(_Rd_, EEINST_LIVE1); - // rpropSetRead(_Rs_, EEINST_MMX); - // rpropSetRead(_Rt_, EEINST_MMX); - // pinst.info |= EEINST_MMX; - // break; - - - case 24: // mult - case 25: // multu - rpropSetWrite(XMMGPR_LO, EEINST_LIVE1); - rpropSetWrite(XMMGPR_HI, EEINST_LIVE1); - rpropSetWrite(_Rd_, EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_USED); //EEINST_MMX crashes on init, EEINST_XMM fails on Tales of Abyss, so EEINST_USED (rama) - rpropSetRead(_Rt_, EEINST_USED); - // did we ever try EEINST_LIVE1 or 0 in the place of EEINST_USED? I think of those might be more correct here (Air) - - pinst.info |= EEINST_USED; - break; - - case 26: // div - case 27: // divu - rpropSetWrite(XMMGPR_LO, EEINST_LIVE1); - rpropSetWrite(XMMGPR_HI, EEINST_LIVE1); - rpropSetRead(_Rs_, 0); - rpropSetRead(_Rt_, 0); - //pinst.info |= EEINST_REALXMM|EEINST_MMX; - break; - - case 32: // add - case 33: // addu - case 34: // sub - case 35: // subu - rpropSetWrite(_Rd_, EEINST_LIVE1); - if( _Rs_ ) rpropSetRead(_Rs_, 0); - if( _Rt_ ) rpropSetRead(_Rt_, 0); - pinst.info |= EEINST_MMX; - break; - - case 36: // and - case 37: // or - case 38: // xor - case 39: // nor - // if rd == rs or rt, keep live1 - rpropSetWrite(_Rd_, EEINST_LIVE1); - rpropSetRead(_Rs_, (pinst.regs[_Rd_]&EEINST_LIVE1)|EEINST_MMX); - rpropSetRead(_Rt_, (pinst.regs[_Rd_]&EEINST_LIVE1)|EEINST_MMX); - break; - - case 40: // mfsa - rpropSetWrite(_Rd_, EEINST_LIVE1); - break; - case 41: // mtsa - rpropSetRead(_Rs_, EEINST_LIVE1|EEINST_MMX); - break; - - case 42: // slt - rpropSetWrite(_Rd_, EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_LIVE1); - rpropSetRead(_Rt_, EEINST_LIVE1); - pinst.info |= EEINST_MMX; - break; - - case 43: // sltu - rpropSetWrite(_Rd_, EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_LIVE1); - rpropSetRead(_Rt_, EEINST_LIVE1); - pinst.info |= EEINST_MMX; - break; - - case 44: // dadd - case 45: // daddu - case 46: // dsub - case 47: // dsubu - rpropSetWrite(_Rd_, EEINST_LIVE1); - if( _Rs_ == 0 || _Rt_ == 0 ) { - // just a copy, so don't force mmx - rpropSetRead(_Rs_, (pinst.regs[_Rd_]&EEINST_LIVE1)); - rpropSetRead(_Rt_, (pinst.regs[_Rd_]&EEINST_LIVE1)); - } - else { - rpropSetRead(_Rs_, (pinst.regs[_Rd_]&EEINST_LIVE1)|EEINST_MMX); - rpropSetRead(_Rt_, (pinst.regs[_Rd_]&EEINST_LIVE1)|EEINST_MMX); - } - pinst.info |= EEINST_MMX; - break; - - // traps - case 48: case 49: case 50: case 51: case 52: case 54: - rpropSetRead(_Rs_, EEINST_LIVE1); - rpropSetRead(_Rt_, EEINST_LIVE1); - break; - - case 56: // dsll - case 58: // dsrl - case 59: // dsra - case 62: // dsrl32 - case 63: // dsra32 - rpropSetWrite(_Rd_, EEINST_LIVE1); - rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_MMX); - pinst.info |= EEINST_MMX; - break; - - case 60: // dsll32 - rpropSetWrite(_Rd_, EEINST_LIVE1); - rpropSetRead(_Rt_, EEINST_MMX); - pinst.info |= EEINST_MMX; - break; - - default: - rpropSetWrite(_Rd_, EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_LIVE1|EEINST_MMX); - rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_MMX); - break; - } -} - -//BLTZ, BGEZ, BLTZL, BGEZL, NULL, NULL, NULL, NULL, -//TGEI, TGEIU, TLTI, TLTIU, TEQI, NULL, TNEI, NULL, -//BLTZAL, BGEZAL, BLTZALL, BGEZALL, NULL, NULL, NULL, NULL, -//MTSAB, MTSAH, NULL, NULL, NULL, NULL, NULL, NULL, -__forceinline void BSCPropagate::rpropREGIMM() -{ - switch(_Rt_) { - case 0: // bltz - case 1: // bgez - rpropSetRead(_Rs_, EEINST_LIVE1); - pinst.info |= EEINST_MMX; - pinst.info |= EEINST_REALXMM; - break; - - case 2: // bltzl - case 3: // bgezl - // reset since don't know which path to go - _recClearInst(&prev); - prev.info = 0; - rpropSetRead(_Rs_, EEINST_LIVE1); - pinst.info |= EEINST_MMX; - pinst.info |= EEINST_REALXMM; - break; - - // traps - case 8: - case 9: - case 10: - case 11: - case 12: - case 14: - rpropSetRead(_Rs_, EEINST_LIVE1); - break; - - case 16: // bltzal - case 17: // bgezal - // do not write 31 - rpropSetRead(_Rs_, EEINST_LIVE1); - break; - - case 18: // bltzall - case 19: // bgezall - // reset since don't know which path to go - _recClearInst(&prev); - prev.info = 0; - // do not write 31 - rpropSetRead(_Rs_, EEINST_LIVE1); - break; - - case 24: // mtsab - case 25: // mtsah - rpropSetRead(_Rs_, 0); - break; - default: - assert(0); - break; - } -} - -//MFC0, NULL, NULL, NULL, MTC0, NULL, NULL, NULL, -//COP0BC0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -//COP0C0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -//NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -__forceinline void BSCPropagate::rpropCP0() -{ - switch(_Rs_) { - case 0: // mfc0 - rpropSetWrite(_Rt_, EEINST_LIVE1|EEINST_REALXMM); - break; - case 4: - rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_REALXMM); - break; - case 8: // cop0bc0 - _recClearInst(&prev); - prev.info = 0; - break; - case 16: // cop0c0 - _recClearInst(&prev); - prev.info = 0; - break; - } -} - -#define _Ft_ _Rt_ -#define _Fs_ _Rd_ -#define _Fd_ _Sa_ - -//ADD_S, SUB_S, MUL_S, DIV_S, SQRT_S, ABS_S, MOV_S, NEG_S, -//NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -//NULL, NULL, NULL, NULL, NULL, NULL, RSQRT_S, NULL, -//ADDA_S, SUBA_S, MULA_S, NULL, MADD_S, MSUB_S, MADDA_S, MSUBA_S, -//NULL, NULL, NULL, NULL, CVT_W, NULL, NULL, NULL, -//MAX_S, MIN_S, NULL, NULL, NULL, NULL, NULL, NULL, -//C_F, NULL, C_EQ, NULL, C_LT, NULL, C_LE, NULL, -//NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -__forceinline void BSCPropagate::rpropCP1() -{ - switch(_Rs_) { - case 0: // mfc1 - rpropSetWrite(_Rt_, EEINST_LIVE1|EEINST_REALXMM); - rpropSetFPURead(_Fs_, EEINST_REALXMM); - break; - case 2: // cfc1 - rpropSetWrite(_Rt_, EEINST_LIVE1|EEINST_REALXMM|EEINST_MMX); - break; - case 4: // mtc1 - rpropSetFPUWrite(_Fs_, EEINST_REALXMM); - rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_REALXMM); - break; - case 6: // ctc1 - rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_REALXMM|EEINST_MMX); - break; - case 8: // bc1 - // reset since don't know which path to go - _recClearInst(&prev); - prev.info = 0; - break; - case 16: - // floating point ops - pinst.info |= EEINST_REALXMM; - switch( _Funct_ ) { - case 0: // add.s - case 1: // sub.s - case 2: // mul.s - case 3: // div.s - case 22: // rsqrt.s - case 40: // max.s - case 41: // min.s - rpropSetFPUWrite(_Fd_, EEINST_REALXMM); - rpropSetFPURead(_Fs_, EEINST_REALXMM); - rpropSetFPURead(_Ft_, EEINST_REALXMM); - break; - case 4: // sqrt.s - rpropSetFPUWrite(_Fd_, EEINST_REALXMM); - rpropSetFPURead(_Ft_, EEINST_REALXMM); - break; - case 5: // abs.s - case 6: // mov.s - case 7: // neg.s - case 36: // cvt.w - rpropSetFPUWrite(_Fd_, EEINST_REALXMM); - rpropSetFPURead(_Fs_, EEINST_REALXMM); - break; - case 24: // adda.s - case 25: // suba.s - case 26: // mula.s - rpropSetFPUWrite(XMMFPU_ACC, EEINST_REALXMM); - rpropSetFPURead(_Fs_, EEINST_REALXMM); - rpropSetFPURead(_Ft_, EEINST_REALXMM); - break; - case 28: // madd.s - case 29: // msub.s - rpropSetFPUWrite(_Fd_, EEINST_REALXMM); - rpropSetFPURead(XMMFPU_ACC, EEINST_REALXMM); - rpropSetFPURead(_Fs_, EEINST_REALXMM); - rpropSetFPURead(_Ft_, EEINST_REALXMM); - break; - - case 30: // madda.s - case 31: // msuba.s - rpropSetFPUWrite(XMMFPU_ACC, EEINST_REALXMM); - rpropSetFPURead(XMMFPU_ACC, EEINST_REALXMM); - rpropSetFPURead(_Fs_, EEINST_REALXMM); - rpropSetFPURead(_Ft_, EEINST_REALXMM); - break; - - case 48: // c.f - case 50: // c.eq - case 52: // c.lt - case 54: // c.le - rpropSetFPURead(_Fs_, EEINST_REALXMM); - rpropSetFPURead(_Ft_, EEINST_REALXMM); - break; - default: assert(0); - } - break; - case 20: - assert( _Funct_ == 32 ); // CVT.S.W - rpropSetFPUWrite(_Fd_, EEINST_REALXMM); - rpropSetFPURead(_Fs_, EEINST_REALXMM); - break; - default: - assert(0); - } -} - -#undef _Ft_ -#undef _Fs_ -#undef _Fd_ - -__forceinline void BSCPropagate::rpropCP2() -{ - switch(_Rs_) { - case 1: // qmfc2 - rpropSetWrite(_Rt_, EEINST_LIVE2|EEINST_LIVE1); - break; - - case 2: // cfc2 - rpropSetWrite(_Rt_, EEINST_LIVE1); - break; - - case 5: // qmtc2 - rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_LIVE2); - break; - - case 6: // ctc2 - rpropSetRead(_Rt_, 0); - break; - - case 8: // bc2 - break; - - default: - // vu macro mode insts - pinst.info |= EEINSTINFO_COP2; - break; - } -} - -//MADD, MADDU, NULL, NULL, PLZCW, NULL, NULL, NULL, -//MMI0, MMI2, NULL, NULL, NULL, NULL, NULL, NULL, -//MFHI1, MTHI1, MFLO1, MTLO1, NULL, NULL, NULL, NULL, -//MULT1, MULTU1, DIV1, DIVU1, NULL, NULL, NULL, NULL, -//MADD1, MADDU1, NULL, NULL, NULL, NULL, NULL, NULL, -//MMI1 , MMI3, NULL, NULL, NULL, NULL, NULL, NULL, -//PMFHL, PMTHL, NULL, NULL, PSLLH, NULL, PSRLH, PSRAH, -//NULL, NULL, NULL, NULL, PSLLW, NULL, PSRLW, PSRAW, -__forceinline void BSCPropagate::rpropMMI() -{ - switch(cpuRegs.code&0x3f) { - case 0: // madd - case 1: // maddu - rpropSetLOHI(_Rd_, _Rs_, _Rt_, EEINST_LIVE1); - break; - case 4: // plzcw - rpropSetFast(_Rd_, _Rs_, 0, EEINST_LIVE1); - break; - case 8: rpropMMI0(); break; - case 9: rpropMMI2(); break; - - case 16: // mfhi1 - { - rpropSetWrite(_Rd_, EEINST_LIVE1); - int temp = ((pinst.regs[_Rd_]&(EEINST_MMX|EEINST_REALXMM))?EEINST_MMX:EEINST_REALXMM); - rpropSetRead(XMMGPR_HI, temp|EEINST_LIVE2); - break; - } - case 17: // mthi1 - rpropSetWrite0<0>(XMMGPR_HI, EEINST_LIVE2); - rpropSetRead(_Rs_, EEINST_LIVE1); - break; - case 18: // mflo1 - { - rpropSetWrite(_Rd_, EEINST_LIVE1); - int temp = ((pinst.regs[_Rd_]&(EEINST_MMX|EEINST_REALXMM))?EEINST_MMX:EEINST_REALXMM); - rpropSetRead(XMMGPR_LO, temp|EEINST_LIVE2); - break; - } - case 19: // mtlo1 - rpropSetWrite0<0>(XMMGPR_LO, EEINST_LIVE2); - rpropSetRead(_Rs_, EEINST_LIVE1); - break; - - case 24: // mult1 - { - int temp = (pinst.regs[XMMGPR_HI]&(EEINST_LIVE2))?0:EEINST_MMX; - rpropSetWrite0<0>(XMMGPR_LO, EEINST_LIVE2); - rpropSetWrite0<0>(XMMGPR_HI, EEINST_LIVE2); - rpropSetWrite(_Rd_, EEINST_LIVE1); - rpropSetRead(_Rs_, temp); - rpropSetRead(_Rt_, temp); - pinst.info |= temp; - break; - } - case 25: // multu1 - rpropSetWrite0<0>(XMMGPR_LO, EEINST_LIVE2); - rpropSetWrite0<0>(XMMGPR_HI, EEINST_LIVE2); - rpropSetWrite(_Rd_, EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_MMX); - rpropSetRead(_Rt_, EEINST_MMX); - pinst.info |= EEINST_MMX; - break; - - case 26: // div1 - case 27: // divu1 - rpropSetWrite0<0>(XMMGPR_LO, EEINST_LIVE2); - rpropSetWrite0<0>(XMMGPR_HI, EEINST_LIVE2); - rpropSetRead(_Rs_, 0); - rpropSetRead(_Rt_, 0); - //pinst.info |= EEINST_REALXMM|EEINST_MMX; - break; - - case 32: // madd1 - case 33: // maddu1 - rpropSetWrite0<0>(XMMGPR_LO, EEINST_LIVE2); - rpropSetWrite0<0>(XMMGPR_HI, EEINST_LIVE2); - rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1); - rpropSetRead(XMMGPR_LO, EEINST_LIVE2); - rpropSetRead(XMMGPR_HI, EEINST_LIVE2); - break; - - case 40: rpropMMI1(); break; - case 41: rpropMMI3(); break; - - case 48: // pmfhl - rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); - rpropSetRead(XMMGPR_LO, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); - rpropSetRead(XMMGPR_HI, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); - break; - - case 49: // pmthl - rpropSetWrite(XMMGPR_LO, EEINST_LIVE2|EEINST_LIVE1); - rpropSetWrite(XMMGPR_HI, EEINST_LIVE2|EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); - break; - - default: - rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2|EEINST_REALXMM); - break; - } -} - -//recPADDW, PSUBW, PCGTW, PMAXW, -//PADDH, PSUBH, PCGTH, PMAXH, -//PADDB, PSUBB, PCGTB, NULL, -//NULL, NULL, NULL, NULL, -//PADDSW, PSUBSW, PEXTLW, PPACW, -//PADDSH, PSUBSH, PEXTLH, PPACH, -//PADDSB, PSUBSB, PEXTLB, PPACB, -//NULL, NULL, PEXT5, PPAC5, -__forceinline void BSCPropagate::rpropMMI0() -{ - switch((cpuRegs.code>>6)&0x1f) { - case 16: // paddsw - case 17: // psubsw - rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2); - break; - - case 18: // pextlw - case 22: // pextlh - case 26: // pextlb - rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_LIVE1|EEINST_REALXMM); - rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_REALXMM); - break; - - case 30: // pext5 - case 31: // ppac5 - rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2); - break; - - default: - rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2|EEINST_REALXMM); - break; - } -} - -__forceinline void BSCPropagate::rpropMMI1() -{ - switch((cpuRegs.code>>6)&0x1f) { - case 1: // pabsw - case 5: // pabsh - rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); - rpropSetRead(_Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); - break; - - case 17: // psubuw - rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2); - break; - - case 18: // pextuw - case 22: // pextuh - case 26: // pextub - rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_LIVE2|EEINST_REALXMM); - rpropSetRead(_Rt_, EEINST_LIVE2|EEINST_REALXMM); - break; - - default: - rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2|EEINST_REALXMM); - break; - } -} - -__forceinline void BSCPropagate::rpropMMI2() -{ - switch((cpuRegs.code>>6)&0x1f) { - case 0: // pmaddw - case 4: // pmsubw - rpropSetLOHI - (_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1); - break; - case 2: // psllvw - case 3: // psllvw - rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE2); - break; - case 8: // pmfhi - rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); - rpropSetRead(XMMGPR_HI, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); - break; - case 9: // pmflo - rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); - rpropSetRead(XMMGPR_HI, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); - break; - case 10: // pinth - rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_LIVE2|EEINST_REALXMM); - rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_REALXMM); - break; - case 12: // pmultw, - rpropSetLOHI - (_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1); - break; - case 13: // pdivw - rpropSetLOHI - (0, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1); - break; - case 14: // pcpyld - rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_LIVE1|EEINST_REALXMM); - rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_REALXMM); - break; - case 16: // pmaddh - case 17: // phmadh - case 20: // pmsubh - case 21: // phmsbh - rpropSetLOHI - (_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); - break; - - case 26: // pexeh - case 27: // prevh - case 30: // pexew - case 31: // prot3w - rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); - rpropSetRead(_Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); - break; - - case 28: // pmulth - rpropSetLOHI - (_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); - break; - case 29: // pdivbw - rpropSetLOHI - (_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); - break; - - default: - rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2|EEINST_REALXMM); - break; - } -} - -__forceinline void BSCPropagate::rpropMMI3() -{ - switch((cpuRegs.code>>6)&0x1f) { - case 0: // pmadduw - rpropSetLOHI - (_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM ); - break; - case 3: // psravw - rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE2); - break; - - case 8: // pmthi - rpropSetWrite(XMMGPR_HI, EEINST_LIVE2|EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); - break; - case 9: // pmtlo - rpropSetWrite(XMMGPR_LO, EEINST_LIVE2|EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); - break; - case 12: // pmultuw, - rpropSetLOHI - (_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); - break; - case 13: // pdivuw - rpropSetLOHI - (0, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1); - break; - case 14: // pcpyud - rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_LIVE2|EEINST_REALXMM); - rpropSetRead(_Rt_, EEINST_LIVE2|EEINST_REALXMM); - break; - - case 26: // pexch - case 27: // pcpyh - case 30: // pexcw - rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); - rpropSetRead(_Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); - break; - - default: - rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2|EEINST_REALXMM); - break; - } -} - -//SPECIAL, REGIMM, J, JAL, BEQ, BNE, BLEZ, BGTZ, -//ADDI, ADDIU, SLTI, SLTIU, ANDI, ORI, XORI, LUI, -//COP0, COP1, COP2, NULL, BEQL, BNEL, BLEZL, BGTZL, -//DADDI, DADDIU, LDL, LDR, MMI, NULL, LQ, SQ, -//LB, LH, LWL, LW, LBU, LHU, LWR, LWU, -//SB, SH, SWL, SW, SDL, SDR, SWR, CACHE, -//NULL, LWC1, NULL, PREF, NULL, NULL, LQC2, LD, -//NULL, SWC1, NULL, NULL, NULL, NULL, SQC2, SD -void BSCPropagate::rprop() -{ - switch(cpuRegs.code >> 26) { - case 0: rpropSPECIAL(); break; - case 1: rpropREGIMM(); break; - case 2: // j - break; - case 3: // jal - rpropSetWrite(31, EEINST_LIVE1); - break; - case 4: // beq - case 5: // bne - rpropSetRead(_Rs_, EEINST_LIVE1); - rpropSetRead(_Rt_, EEINST_LIVE1); - pinst.info |= EEINST_REALXMM|EEINST_MMX; - break; - - case 20: // beql - case 21: // bnel - // reset since don't know which path to go - _recClearInst(&prev); - prev.info = 0; - rpropSetRead(_Rs_, EEINST_LIVE1); - rpropSetRead(_Rt_, EEINST_LIVE1); - pinst.info |= EEINST_REALXMM|EEINST_MMX; - break; - - case 6: // blez - case 7: // bgtz - rpropSetRead(_Rs_, EEINST_LIVE1); - break; - - case 22: // blezl - case 23: // bgtzl - // reset since don't know which path to go - _recClearInst(&prev); - prev.info = 0; - rpropSetRead(_Rs_, EEINST_LIVE1); - break; - - case 24: // daddi - case 25: // daddiu - rpropSetWrite(_Rt_, EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_LIVE1 | (_Rs_!=0?EEINST_MMX:0)); // This looks like what ZeroFrog wanted; ToDo: Needs checking! (cottonvibes) - break; - - case 8: // addi - case 9: // addiu - rpropSetWrite(_Rt_, EEINST_LIVE1); - rpropSetRead(_Rs_, 0); - pinst.info |= EEINST_MMX; - break; - - case 10: // slti - rpropSetWrite(_Rt_, EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_LIVE1); - pinst.info |= EEINST_MMX; - break; - case 11: // sltiu - rpropSetWrite(_Rt_, EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_LIVE1); - pinst.info |= EEINST_MMX; - break; - - case 12: // andi - rpropSetWrite(_Rt_, EEINST_LIVE1); - rpropSetRead(_Rs_, (_Rs_!=_Rt_?EEINST_MMX:0)); - pinst.info |= EEINST_MMX; - break; - case 13: // ori - rpropSetWrite(_Rt_, EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_LIVE1|(_Rs_!=_Rt_?EEINST_MMX:0)); - pinst.info |= EEINST_MMX; - break; - case 14: // xori - rpropSetWrite(_Rt_, EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_LIVE1|(_Rs_!=_Rt_?EEINST_MMX:0)); - pinst.info |= EEINST_MMX; - break; - - case 15: // lui - rpropSetWrite(_Rt_, EEINST_LIVE1); - break; - - case 16: rpropCP0(); break; - case 17: rpropCP1(); break; - case 18: rpropCP2(); break; - - // loads - case 34: // lwl - case 38: // lwr - case 26: // ldl - case 27: // ldr - rpropSetWrite(_Rt_, EEINST_LIVE1); - rpropSetRead(_Rt_, EEINST_LIVE1); - rpropSetRead(_Rs_, 0); - break; - - case 32: case 33: case 35: case 36: case 37: case 39: - case 55: // LD - rpropSetWrite(_Rt_, EEINST_LIVE1); - rpropSetRead(_Rs_, 0); - break; - - case 28: rpropMMI(); break; - - case 30: // lq - rpropSetWrite(_Rt_, EEINST_LIVE1|EEINST_LIVE2); - rpropSetRead(_Rs_, 0); - pinst.info |= EEINST_MMX; - pinst.info |= EEINST_REALXMM; - break; - - case 31: // sq - rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_LIVE2|EEINST_REALXMM); - rpropSetRead(_Rs_, 0); - pinst.info |= EEINST_MMX; - pinst.info |= EEINST_REALXMM; - break; - - // 4 byte stores - case 40: case 41: case 42: case 43: case 46: - rpropSetRead(_Rt_, 0); - rpropSetRead(_Rs_, 0); - pinst.info |= EEINST_MMX; - pinst.info |= EEINST_REALXMM; - break; - - case 44: // sdl - case 45: // sdr - case 63: // sd - rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_MMX|EEINST_REALXMM); - rpropSetRead(_Rs_, 0); - break; - - case 49: // lwc1 - rpropSetFPUWrite(_Rt_, EEINST_REALXMM); - rpropSetRead(_Rs_, 0); - break; - - case 57: // swc1 - rpropSetFPURead(_Rt_, EEINST_REALXMM); - rpropSetRead(_Rs_, 0); - break; - - case 54: // lqc2 - case 62: // sqc2 - rpropSetRead(_Rs_, 0); - break; - - default: - rpropSetWrite(_Rt_, EEINST_LIVE1); - rpropSetRead(_Rs_, EEINST_LIVE1|(_Rs_!=0?EEINST_MMX:0)); - break; - } -} // End namespace OpcodeImpl +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +// Holds instruction tables for the r5900 recompiler + +#include "PrecompiledHeader.h" + +#include "Common.h" +#include "Memory.h" +#include "R5900OpcodeTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "iR5900AritImm.h" +#include "iR5900Arit.h" +#include "iR5900MultDiv.h" +#include "iR5900Shift.h" +#include "iR5900Branch.h" +#include "iR5900Jump.h" +#include "iR5900LoadStore.h" +#include "iR5900Move.h" +#include "iMMI.h" +#include "iFPU.h" +#include "iCOP0.h" + +// Use this to call into interpreter functions that require an immediate branchtest +// to be done afterward (anything that throws an exception or enables interrupts, etc). +void recBranchCall( void (*func)() ) +{ + // In order to make sure a branch test is performed, the nextBranchCycle is set + // to the current cpu cycle. + + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32MtoR( EAX, (uptr)&cpuRegs.cycle ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + MOV32RtoM( (uptr)&g_nextBranchCycle, EAX ); + + // Might as well flush everything -- it'll all get flushed when the + // recompiler inserts the branchtest anyway. + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (uptr)func ); + branch = 2; +} + +void recCall( void (*func)(), int delreg ) +{ + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + + iFlushCall(FLUSH_EVERYTHING); + if( delreg > 0 ) _deleteEEreg(delreg, 0); + CALLFunc( (uptr)func ); +} + +using namespace R5900::Dynarec::OpcodeImpl; + +#ifdef PCSX2_VM_COISSUE +// coissued insts +void (*recBSC_co[64] )() = { + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recLDL_co, recLDR_co, recNULL, recNULL, recLQ_co, recSQ_co, + recLB_co, recLH_co, recLWL_co, recLW_co, recLBU_co, recLHU_co, recLWR_co, recLWU_co, + recSB_co, recSH_co, recSWL_co, recSW_co, recSDL_co, recSDR_co, recSWR_co, recNULL, + recNULL, recLWC1_co, recNULL, recNULL, recNULL, recNULL, recLQC2_co, recLD_co, + recNULL, recSWC1_co, recNULL, recNULL, recNULL, recNULL, recSQC2_co, recSD_co +}; +#endif + + +//////////////////////////////////////////////// +// Back-Prob Function Tables - Gathering Info // +//////////////////////////////////////////////// +BSCPropagate::BSCPropagate( EEINST& previous, EEINST& pinstance ) : + prev( previous ) +, pinst( pinstance ) +{ +} + +void BSCPropagate::rpropSetRead( int reg, int mask ) +{ + if( !(pinst.regs[reg] & EEINST_USED) ) + pinst.regs[reg] |= EEINST_LASTUSE; + prev.regs[reg] |= EEINST_LIVE0|(mask)|EEINST_USED; + pinst.regs[reg] |= EEINST_USED; + if( reg ) pinst.info = ((mask)&(EEINST_MMX|EEINST_XMM)); + _recFillRegister(pinst, XMMTYPE_GPRREG, reg, 0); +} + +template< int live > +void BSCPropagate::rpropSetWrite0( int reg, int mask ) +{ + prev.regs[reg] &= ~((mask)|live|EEINST_XMM|EEINST_MMX); + if( !(pinst.regs[reg] & EEINST_USED) ) + pinst.regs[reg] |= EEINST_LASTUSE; + pinst.regs[reg] |= EEINST_USED; + prev.regs[reg] |= EEINST_USED; + _recFillRegister(pinst, XMMTYPE_GPRREG, reg, 1); +} + +__forceinline void BSCPropagate::rpropSetWrite( int reg, int mask ) +{ + rpropSetWrite0( reg, mask ); +} + +__forceinline void BSCPropagate::rpropSetFast( int write1, int read1, int read2, int mask ) +{ + if( write1 ) { rpropSetWrite(write1,mask); } + if( read1 ) { rpropSetRead(read1,mask); } + if( read2 ) { rpropSetRead(read2,mask); } +} + +template< int lo, int hi > +void BSCPropagate::rpropSetLOHI( int write1, int read1, int read2, int mask ) +{ + if( write1 ) { rpropSetWrite(write1,mask); } + if( lo & MODE_WRITE ) { rpropSetWrite(XMMGPR_LO,mask); } + if( hi & MODE_WRITE ) { rpropSetWrite(XMMGPR_HI,mask); } + if( read1 ) { rpropSetRead(read1,mask); } + if( read2 ) { rpropSetRead(read2,mask); } + if( lo & MODE_READ ) { rpropSetRead(XMMGPR_LO,mask); } + if( hi & MODE_READ ) { rpropSetRead(XMMGPR_HI,mask); } +} + +// FPU regs +void BSCPropagate::rpropSetFPURead( int reg, int mask ) +{ + if( !(pinst.fpuregs[reg] & EEINST_USED) ) + pinst.fpuregs[reg] |= EEINST_LASTUSE; + prev.fpuregs[reg] |= EEINST_LIVE0|(mask)|EEINST_USED; + pinst.fpuregs[reg] |= EEINST_USED; + if( reg ) pinst.info = ((mask)&(EEINST_MMX|EEINST_XMM)); + if( reg == XMMFPU_ACC ) _recFillRegister(pinst, XMMTYPE_FPACC, 0, 0); + else _recFillRegister(pinst, XMMTYPE_FPREG, reg, 0); +} + +template< int live > +void BSCPropagate::rpropSetFPUWrite0( int reg, int mask ) +{ + prev.fpuregs[reg] &= ~((mask)|live|EEINST_XMM|EEINST_MMX); + if( !(pinst.fpuregs[reg] & EEINST_USED) ) + pinst.fpuregs[reg] |= EEINST_LASTUSE; + pinst.fpuregs[reg] |= EEINST_USED; + prev.fpuregs[reg] |= EEINST_USED; + if( reg == XMMFPU_ACC ) _recFillRegister(pinst, XMMTYPE_FPACC, 0, 1); + else _recFillRegister(pinst, XMMTYPE_FPREG, reg, 1); +} + +__forceinline void BSCPropagate::rpropSetFPUWrite( int reg, int mask ) +{ + rpropSetFPUWrite0( reg, mask ); +} + + +#define EEINST_REALXMM EEINST_XMM + +//SLL, NULL, SRL, SRA, SLLV, NULL, SRLV, SRAV, +//JR, JALR, MOVZ, MOVN, SYSCALL, BREAK, NULL, SYNC, +//MFHI, MTHI, MFLO, MTLO, DSLLV, NULL, DSRLV, DSRAV, +//MULT, MULTU, DIV, DIVU, NULL, NULL, NULL, NULL, +//ADD, ADDU, SUB, SUBU, AND, OR, XOR, NOR, +//MFSA, MTSA, SLT, SLTU, DADD, DADDU, DSUB, DSUBU, +//TGE, TGEU, TLT, TLTU, TEQ, NULL, TNE, NULL, +//DSLL, NULL, DSRL, DSRA, DSLL32, NULL, DSRL32, DSRA32 + +__forceinline void BSCPropagate::rpropSPECIAL() +{ + switch(_Funct_) { + case 0: // SLL + case 2: // SRL + case 3: // SRA + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_MMX); + break; + + case 4: // sllv + case 6: // srlv + case 7: // srav + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_MMX); + rpropSetRead(_Rt_, EEINST_MMX); + break; + + case 8: // JR + rpropSetRead(_Rs_, 0); + break; + case 9: // JALR + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, 0); + break; + + case 10: // movz + case 11: // movn + // do not write _Rd_! + rpropSetRead(_Rs_, EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rd_, EEINST_LIVE1); + pinst.info |= EEINST_MMX; + _recFillRegister(pinst, XMMTYPE_GPRREG, _Rd_, 1); + break; + + case 12: // syscall + case 13: // break + _recClearInst(&prev); + prev.info = 0; + break; + case 15: // sync + break; + + case 16: // mfhi + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(XMMGPR_HI, (pinst.regs[_Rd_]&(EEINST_MMX|EEINST_REALXMM))|EEINST_LIVE1); + break; + case 17: // mthi + rpropSetWrite(XMMGPR_HI, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1); + break; + case 18: // mflo + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(XMMGPR_LO, (pinst.regs[_Rd_]&(EEINST_MMX|EEINST_REALXMM))|EEINST_LIVE1); + break; + case 19: // mtlo + rpropSetWrite(XMMGPR_LO, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1); + break; + + case 20: // dsllv + case 22: // dsrlv + case 23: // dsrav + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_MMX); + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_MMX); + break; + + //case 24: // mult + // // can do unsigned mult only if HI isn't used + + // //using this allocation for temp causes the emu to crash + // //temp = (pinst.regs[XMMGPR_HI]&(EEINST_LIVE0|EEINST_LIVE1))?0:EEINST_MMX; + // temp = 0; + // rpropSetWrite(XMMGPR_LO, EEINST_LIVE1); + // rpropSetWrite(XMMGPR_HI, EEINST_LIVE1); + // rpropSetWrite(_Rd_, EEINST_LIVE1); + // + // // fixme - temp is always 0, so I doubt the next three lines are right. (arcum42) + + // // Yep, its wrong. Using always 0 causes the wrong damage calculations in Soul Nomad. + // rpropSetRead(_Rs_, temp); + // rpropSetRead(_Rt_, temp); + // pinst.info |= temp; + // break; + + //case 25: // multu + // rpropSetWrite(XMMGPR_LO, EEINST_LIVE1); + // rpropSetWrite(XMMGPR_HI, EEINST_LIVE1); + // rpropSetWrite(_Rd_, EEINST_LIVE1); + // rpropSetRead(_Rs_, EEINST_MMX); + // rpropSetRead(_Rt_, EEINST_MMX); + // pinst.info |= EEINST_MMX; + // break; + + + case 24: // mult + case 25: // multu + rpropSetWrite(XMMGPR_LO, EEINST_LIVE1); + rpropSetWrite(XMMGPR_HI, EEINST_LIVE1); + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_USED); //EEINST_MMX crashes on init, EEINST_XMM fails on Tales of Abyss, so EEINST_USED (rama) + rpropSetRead(_Rt_, EEINST_USED); + // did we ever try EEINST_LIVE1 or 0 in the place of EEINST_USED? I think of those might be more correct here (Air) + + pinst.info |= EEINST_USED; + break; + + case 26: // div + case 27: // divu + rpropSetWrite(XMMGPR_LO, EEINST_LIVE1); + rpropSetWrite(XMMGPR_HI, EEINST_LIVE1); + rpropSetRead(_Rs_, 0); + rpropSetRead(_Rt_, 0); + //pinst.info |= EEINST_REALXMM|EEINST_MMX; + break; + + case 32: // add + case 33: // addu + case 34: // sub + case 35: // subu + rpropSetWrite(_Rd_, EEINST_LIVE1); + if( _Rs_ ) rpropSetRead(_Rs_, 0); + if( _Rt_ ) rpropSetRead(_Rt_, 0); + pinst.info |= EEINST_MMX; + break; + + case 36: // and + case 37: // or + case 38: // xor + case 39: // nor + // if rd == rs or rt, keep live1 + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, (pinst.regs[_Rd_]&EEINST_LIVE1)|EEINST_MMX); + rpropSetRead(_Rt_, (pinst.regs[_Rd_]&EEINST_LIVE1)|EEINST_MMX); + break; + + case 40: // mfsa + rpropSetWrite(_Rd_, EEINST_LIVE1); + break; + case 41: // mtsa + rpropSetRead(_Rs_, EEINST_LIVE1|EEINST_MMX); + break; + + case 42: // slt + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE1); + pinst.info |= EEINST_MMX; + break; + + case 43: // sltu + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE1); + pinst.info |= EEINST_MMX; + break; + + case 44: // dadd + case 45: // daddu + case 46: // dsub + case 47: // dsubu + rpropSetWrite(_Rd_, EEINST_LIVE1); + if( _Rs_ == 0 || _Rt_ == 0 ) { + // just a copy, so don't force mmx + rpropSetRead(_Rs_, (pinst.regs[_Rd_]&EEINST_LIVE1)); + rpropSetRead(_Rt_, (pinst.regs[_Rd_]&EEINST_LIVE1)); + } + else { + rpropSetRead(_Rs_, (pinst.regs[_Rd_]&EEINST_LIVE1)|EEINST_MMX); + rpropSetRead(_Rt_, (pinst.regs[_Rd_]&EEINST_LIVE1)|EEINST_MMX); + } + pinst.info |= EEINST_MMX; + break; + + // traps + case 48: case 49: case 50: case 51: case 52: case 54: + rpropSetRead(_Rs_, EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE1); + break; + + case 56: // dsll + case 58: // dsrl + case 59: // dsra + case 62: // dsrl32 + case 63: // dsra32 + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_MMX); + pinst.info |= EEINST_MMX; + break; + + case 60: // dsll32 + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_MMX); + pinst.info |= EEINST_MMX; + break; + + default: + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1|EEINST_MMX); + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_MMX); + break; + } +} + +//BLTZ, BGEZ, BLTZL, BGEZL, NULL, NULL, NULL, NULL, +//TGEI, TGEIU, TLTI, TLTIU, TEQI, NULL, TNEI, NULL, +//BLTZAL, BGEZAL, BLTZALL, BGEZALL, NULL, NULL, NULL, NULL, +//MTSAB, MTSAH, NULL, NULL, NULL, NULL, NULL, NULL, +__forceinline void BSCPropagate::rpropREGIMM() +{ + switch(_Rt_) { + case 0: // bltz + case 1: // bgez + rpropSetRead(_Rs_, EEINST_LIVE1); + pinst.info |= EEINST_MMX; + pinst.info |= EEINST_REALXMM; + break; + + case 2: // bltzl + case 3: // bgezl + // reset since don't know which path to go + _recClearInst(&prev); + prev.info = 0; + rpropSetRead(_Rs_, EEINST_LIVE1); + pinst.info |= EEINST_MMX; + pinst.info |= EEINST_REALXMM; + break; + + // traps + case 8: + case 9: + case 10: + case 11: + case 12: + case 14: + rpropSetRead(_Rs_, EEINST_LIVE1); + break; + + case 16: // bltzal + case 17: // bgezal + // do not write 31 + rpropSetRead(_Rs_, EEINST_LIVE1); + break; + + case 18: // bltzall + case 19: // bgezall + // reset since don't know which path to go + _recClearInst(&prev); + prev.info = 0; + // do not write 31 + rpropSetRead(_Rs_, EEINST_LIVE1); + break; + + case 24: // mtsab + case 25: // mtsah + rpropSetRead(_Rs_, 0); + break; + default: + assert(0); + break; + } +} + +//MFC0, NULL, NULL, NULL, MTC0, NULL, NULL, NULL, +//COP0BC0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +//COP0C0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +//NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +__forceinline void BSCPropagate::rpropCP0() +{ + switch(_Rs_) { + case 0: // mfc0 + rpropSetWrite(_Rt_, EEINST_LIVE1|EEINST_REALXMM); + break; + case 4: + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_REALXMM); + break; + case 8: // cop0bc0 + _recClearInst(&prev); + prev.info = 0; + break; + case 16: // cop0c0 + _recClearInst(&prev); + prev.info = 0; + break; + } +} + +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +//ADD_S, SUB_S, MUL_S, DIV_S, SQRT_S, ABS_S, MOV_S, NEG_S, +//NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +//NULL, NULL, NULL, NULL, NULL, NULL, RSQRT_S, NULL, +//ADDA_S, SUBA_S, MULA_S, NULL, MADD_S, MSUB_S, MADDA_S, MSUBA_S, +//NULL, NULL, NULL, NULL, CVT_W, NULL, NULL, NULL, +//MAX_S, MIN_S, NULL, NULL, NULL, NULL, NULL, NULL, +//C_F, NULL, C_EQ, NULL, C_LT, NULL, C_LE, NULL, +//NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +__forceinline void BSCPropagate::rpropCP1() +{ + switch(_Rs_) { + case 0: // mfc1 + rpropSetWrite(_Rt_, EEINST_LIVE1|EEINST_REALXMM); + rpropSetFPURead(_Fs_, EEINST_REALXMM); + break; + case 2: // cfc1 + rpropSetWrite(_Rt_, EEINST_LIVE1|EEINST_REALXMM|EEINST_MMX); + break; + case 4: // mtc1 + rpropSetFPUWrite(_Fs_, EEINST_REALXMM); + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_REALXMM); + break; + case 6: // ctc1 + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_REALXMM|EEINST_MMX); + break; + case 8: // bc1 + // reset since don't know which path to go + _recClearInst(&prev); + prev.info = 0; + break; + case 16: + // floating point ops + pinst.info |= EEINST_REALXMM; + switch( _Funct_ ) { + case 0: // add.s + case 1: // sub.s + case 2: // mul.s + case 3: // div.s + case 22: // rsqrt.s + case 40: // max.s + case 41: // min.s + rpropSetFPUWrite(_Fd_, EEINST_REALXMM); + rpropSetFPURead(_Fs_, EEINST_REALXMM); + rpropSetFPURead(_Ft_, EEINST_REALXMM); + break; + case 4: // sqrt.s + rpropSetFPUWrite(_Fd_, EEINST_REALXMM); + rpropSetFPURead(_Ft_, EEINST_REALXMM); + break; + case 5: // abs.s + case 6: // mov.s + case 7: // neg.s + case 36: // cvt.w + rpropSetFPUWrite(_Fd_, EEINST_REALXMM); + rpropSetFPURead(_Fs_, EEINST_REALXMM); + break; + case 24: // adda.s + case 25: // suba.s + case 26: // mula.s + rpropSetFPUWrite(XMMFPU_ACC, EEINST_REALXMM); + rpropSetFPURead(_Fs_, EEINST_REALXMM); + rpropSetFPURead(_Ft_, EEINST_REALXMM); + break; + case 28: // madd.s + case 29: // msub.s + rpropSetFPUWrite(_Fd_, EEINST_REALXMM); + rpropSetFPURead(XMMFPU_ACC, EEINST_REALXMM); + rpropSetFPURead(_Fs_, EEINST_REALXMM); + rpropSetFPURead(_Ft_, EEINST_REALXMM); + break; + + case 30: // madda.s + case 31: // msuba.s + rpropSetFPUWrite(XMMFPU_ACC, EEINST_REALXMM); + rpropSetFPURead(XMMFPU_ACC, EEINST_REALXMM); + rpropSetFPURead(_Fs_, EEINST_REALXMM); + rpropSetFPURead(_Ft_, EEINST_REALXMM); + break; + + case 48: // c.f + case 50: // c.eq + case 52: // c.lt + case 54: // c.le + rpropSetFPURead(_Fs_, EEINST_REALXMM); + rpropSetFPURead(_Ft_, EEINST_REALXMM); + break; + default: assert(0); + } + break; + case 20: + assert( _Funct_ == 32 ); // CVT.S.W + rpropSetFPUWrite(_Fd_, EEINST_REALXMM); + rpropSetFPURead(_Fs_, EEINST_REALXMM); + break; + default: + assert(0); + } +} + +#undef _Ft_ +#undef _Fs_ +#undef _Fd_ + +__forceinline void BSCPropagate::rpropCP2() +{ + switch(_Rs_) { + case 1: // qmfc2 + rpropSetWrite(_Rt_, EEINST_LIVE2|EEINST_LIVE1); + break; + + case 2: // cfc2 + rpropSetWrite(_Rt_, EEINST_LIVE1); + break; + + case 5: // qmtc2 + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_LIVE2); + break; + + case 6: // ctc2 + rpropSetRead(_Rt_, 0); + break; + + case 8: // bc2 + break; + + default: + // vu macro mode insts + pinst.info |= EEINSTINFO_COP2; + break; + } +} + +//MADD, MADDU, NULL, NULL, PLZCW, NULL, NULL, NULL, +//MMI0, MMI2, NULL, NULL, NULL, NULL, NULL, NULL, +//MFHI1, MTHI1, MFLO1, MTLO1, NULL, NULL, NULL, NULL, +//MULT1, MULTU1, DIV1, DIVU1, NULL, NULL, NULL, NULL, +//MADD1, MADDU1, NULL, NULL, NULL, NULL, NULL, NULL, +//MMI1 , MMI3, NULL, NULL, NULL, NULL, NULL, NULL, +//PMFHL, PMTHL, NULL, NULL, PSLLH, NULL, PSRLH, PSRAH, +//NULL, NULL, NULL, NULL, PSLLW, NULL, PSRLW, PSRAW, +__forceinline void BSCPropagate::rpropMMI() +{ + switch(cpuRegs.code&0x3f) { + case 0: // madd + case 1: // maddu + rpropSetLOHI(_Rd_, _Rs_, _Rt_, EEINST_LIVE1); + break; + case 4: // plzcw + rpropSetFast(_Rd_, _Rs_, 0, EEINST_LIVE1); + break; + case 8: rpropMMI0(); break; + case 9: rpropMMI2(); break; + + case 16: // mfhi1 + { + rpropSetWrite(_Rd_, EEINST_LIVE1); + int temp = ((pinst.regs[_Rd_]&(EEINST_MMX|EEINST_REALXMM))?EEINST_MMX:EEINST_REALXMM); + rpropSetRead(XMMGPR_HI, temp|EEINST_LIVE2); + break; + } + case 17: // mthi1 + rpropSetWrite0<0>(XMMGPR_HI, EEINST_LIVE2); + rpropSetRead(_Rs_, EEINST_LIVE1); + break; + case 18: // mflo1 + { + rpropSetWrite(_Rd_, EEINST_LIVE1); + int temp = ((pinst.regs[_Rd_]&(EEINST_MMX|EEINST_REALXMM))?EEINST_MMX:EEINST_REALXMM); + rpropSetRead(XMMGPR_LO, temp|EEINST_LIVE2); + break; + } + case 19: // mtlo1 + rpropSetWrite0<0>(XMMGPR_LO, EEINST_LIVE2); + rpropSetRead(_Rs_, EEINST_LIVE1); + break; + + case 24: // mult1 + { + int temp = (pinst.regs[XMMGPR_HI]&(EEINST_LIVE2))?0:EEINST_MMX; + rpropSetWrite0<0>(XMMGPR_LO, EEINST_LIVE2); + rpropSetWrite0<0>(XMMGPR_HI, EEINST_LIVE2); + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, temp); + rpropSetRead(_Rt_, temp); + pinst.info |= temp; + break; + } + case 25: // multu1 + rpropSetWrite0<0>(XMMGPR_LO, EEINST_LIVE2); + rpropSetWrite0<0>(XMMGPR_HI, EEINST_LIVE2); + rpropSetWrite(_Rd_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_MMX); + rpropSetRead(_Rt_, EEINST_MMX); + pinst.info |= EEINST_MMX; + break; + + case 26: // div1 + case 27: // divu1 + rpropSetWrite0<0>(XMMGPR_LO, EEINST_LIVE2); + rpropSetWrite0<0>(XMMGPR_HI, EEINST_LIVE2); + rpropSetRead(_Rs_, 0); + rpropSetRead(_Rt_, 0); + //pinst.info |= EEINST_REALXMM|EEINST_MMX; + break; + + case 32: // madd1 + case 33: // maddu1 + rpropSetWrite0<0>(XMMGPR_LO, EEINST_LIVE2); + rpropSetWrite0<0>(XMMGPR_HI, EEINST_LIVE2); + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1); + rpropSetRead(XMMGPR_LO, EEINST_LIVE2); + rpropSetRead(XMMGPR_HI, EEINST_LIVE2); + break; + + case 40: rpropMMI1(); break; + case 41: rpropMMI3(); break; + + case 48: // pmfhl + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(XMMGPR_LO, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + rpropSetRead(XMMGPR_HI, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + + case 49: // pmthl + rpropSetWrite(XMMGPR_LO, EEINST_LIVE2|EEINST_LIVE1); + rpropSetWrite(XMMGPR_HI, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + + default: + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2|EEINST_REALXMM); + break; + } +} + +//recPADDW, PSUBW, PCGTW, PMAXW, +//PADDH, PSUBH, PCGTH, PMAXH, +//PADDB, PSUBB, PCGTB, NULL, +//NULL, NULL, NULL, NULL, +//PADDSW, PSUBSW, PEXTLW, PPACW, +//PADDSH, PSUBSH, PEXTLH, PPACH, +//PADDSB, PSUBSB, PEXTLB, PPACB, +//NULL, NULL, PEXT5, PPAC5, +__forceinline void BSCPropagate::rpropMMI0() +{ + switch((cpuRegs.code>>6)&0x1f) { + case 16: // paddsw + case 17: // psubsw + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2); + break; + + case 18: // pextlw + case 22: // pextlh + case 26: // pextlb + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1|EEINST_REALXMM); + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_REALXMM); + break; + + case 30: // pext5 + case 31: // ppac5 + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2); + break; + + default: + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2|EEINST_REALXMM); + break; + } +} + +__forceinline void BSCPropagate::rpropMMI1() +{ + switch((cpuRegs.code>>6)&0x1f) { + case 1: // pabsw + case 5: // pabsh + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + + case 17: // psubuw + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2); + break; + + case 18: // pextuw + case 22: // pextuh + case 26: // pextub + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE2|EEINST_REALXMM); + rpropSetRead(_Rt_, EEINST_LIVE2|EEINST_REALXMM); + break; + + default: + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2|EEINST_REALXMM); + break; + } +} + +__forceinline void BSCPropagate::rpropMMI2() +{ + switch((cpuRegs.code>>6)&0x1f) { + case 0: // pmaddw + case 4: // pmsubw + rpropSetLOHI + (_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1); + break; + case 2: // psllvw + case 3: // psllvw + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE2); + break; + case 8: // pmfhi + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(XMMGPR_HI, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + case 9: // pmflo + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(XMMGPR_HI, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + case 10: // pinth + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE2|EEINST_REALXMM); + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_REALXMM); + break; + case 12: // pmultw, + rpropSetLOHI + (_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1); + break; + case 13: // pdivw + rpropSetLOHI + (0, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1); + break; + case 14: // pcpyld + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1|EEINST_REALXMM); + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_REALXMM); + break; + case 16: // pmaddh + case 17: // phmadh + case 20: // pmsubh + case 21: // phmsbh + rpropSetLOHI + (_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + + case 26: // pexeh + case 27: // prevh + case 30: // pexew + case 31: // prot3w + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + + case 28: // pmulth + rpropSetLOHI + (_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + case 29: // pdivbw + rpropSetLOHI + (_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + + default: + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2|EEINST_REALXMM); + break; + } +} + +__forceinline void BSCPropagate::rpropMMI3() +{ + switch((cpuRegs.code>>6)&0x1f) { + case 0: // pmadduw + rpropSetLOHI + (_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM ); + break; + case 3: // psravw + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE2); + break; + + case 8: // pmthi + rpropSetWrite(XMMGPR_HI, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + case 9: // pmtlo + rpropSetWrite(XMMGPR_LO, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + case 12: // pmultuw, + rpropSetLOHI + (_Rd_, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + case 13: // pdivuw + rpropSetLOHI + (0, _Rs_, _Rt_, EEINST_LIVE2|EEINST_LIVE1); + break; + case 14: // pcpyud + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE2|EEINST_REALXMM); + rpropSetRead(_Rt_, EEINST_LIVE2|EEINST_REALXMM); + break; + + case 26: // pexch + case 27: // pcpyh + case 30: // pexcw + rpropSetWrite(_Rd_, EEINST_LIVE2|EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE2|EEINST_LIVE1|EEINST_REALXMM); + break; + + default: + rpropSetFast(_Rd_, _Rs_, _Rt_, EEINST_LIVE1|EEINST_LIVE2|EEINST_REALXMM); + break; + } +} + +//SPECIAL, REGIMM, J, JAL, BEQ, BNE, BLEZ, BGTZ, +//ADDI, ADDIU, SLTI, SLTIU, ANDI, ORI, XORI, LUI, +//COP0, COP1, COP2, NULL, BEQL, BNEL, BLEZL, BGTZL, +//DADDI, DADDIU, LDL, LDR, MMI, NULL, LQ, SQ, +//LB, LH, LWL, LW, LBU, LHU, LWR, LWU, +//SB, SH, SWL, SW, SDL, SDR, SWR, CACHE, +//NULL, LWC1, NULL, PREF, NULL, NULL, LQC2, LD, +//NULL, SWC1, NULL, NULL, NULL, NULL, SQC2, SD +void BSCPropagate::rprop() +{ + switch(cpuRegs.code >> 26) { + case 0: rpropSPECIAL(); break; + case 1: rpropREGIMM(); break; + case 2: // j + break; + case 3: // jal + rpropSetWrite(31, EEINST_LIVE1); + break; + case 4: // beq + case 5: // bne + rpropSetRead(_Rs_, EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE1); + pinst.info |= EEINST_REALXMM|EEINST_MMX; + break; + + case 20: // beql + case 21: // bnel + // reset since don't know which path to go + _recClearInst(&prev); + prev.info = 0; + rpropSetRead(_Rs_, EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE1); + pinst.info |= EEINST_REALXMM|EEINST_MMX; + break; + + case 6: // blez + case 7: // bgtz + rpropSetRead(_Rs_, EEINST_LIVE1); + break; + + case 22: // blezl + case 23: // bgtzl + // reset since don't know which path to go + _recClearInst(&prev); + prev.info = 0; + rpropSetRead(_Rs_, EEINST_LIVE1); + break; + + case 24: // daddi + case 25: // daddiu + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1 | (_Rs_!=0?EEINST_MMX:0)); // This looks like what ZeroFrog wanted; ToDo: Needs checking! (cottonvibes) + break; + + case 8: // addi + case 9: // addiu + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, 0); + pinst.info |= EEINST_MMX; + break; + + case 10: // slti + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1); + pinst.info |= EEINST_MMX; + break; + case 11: // sltiu + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1); + pinst.info |= EEINST_MMX; + break; + + case 12: // andi + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, (_Rs_!=_Rt_?EEINST_MMX:0)); + pinst.info |= EEINST_MMX; + break; + case 13: // ori + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1|(_Rs_!=_Rt_?EEINST_MMX:0)); + pinst.info |= EEINST_MMX; + break; + case 14: // xori + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1|(_Rs_!=_Rt_?EEINST_MMX:0)); + pinst.info |= EEINST_MMX; + break; + + case 15: // lui + rpropSetWrite(_Rt_, EEINST_LIVE1); + break; + + case 16: rpropCP0(); break; + case 17: rpropCP1(); break; + case 18: rpropCP2(); break; + + // loads + case 34: // lwl + case 38: // lwr + case 26: // ldl + case 27: // ldr + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, 0); + break; + + case 32: case 33: case 35: case 36: case 37: case 39: + case 55: // LD + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, 0); + break; + + case 28: rpropMMI(); break; + + case 30: // lq + rpropSetWrite(_Rt_, EEINST_LIVE1|EEINST_LIVE2); + rpropSetRead(_Rs_, 0); + pinst.info |= EEINST_MMX; + pinst.info |= EEINST_REALXMM; + break; + + case 31: // sq + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_LIVE2|EEINST_REALXMM); + rpropSetRead(_Rs_, 0); + pinst.info |= EEINST_MMX; + pinst.info |= EEINST_REALXMM; + break; + + // 4 byte stores + case 40: case 41: case 42: case 43: case 46: + rpropSetRead(_Rt_, 0); + rpropSetRead(_Rs_, 0); + pinst.info |= EEINST_MMX; + pinst.info |= EEINST_REALXMM; + break; + + case 44: // sdl + case 45: // sdr + case 63: // sd + rpropSetRead(_Rt_, EEINST_LIVE1|EEINST_MMX|EEINST_REALXMM); + rpropSetRead(_Rs_, 0); + break; + + case 49: // lwc1 + rpropSetFPUWrite(_Rt_, EEINST_REALXMM); + rpropSetRead(_Rs_, 0); + break; + + case 57: // swc1 + rpropSetFPURead(_Rt_, EEINST_REALXMM); + rpropSetRead(_Rs_, 0); + break; + + case 54: // lqc2 + case 62: // sqc2 + rpropSetRead(_Rs_, 0); + break; + + default: + rpropSetWrite(_Rt_, EEINST_LIVE1); + rpropSetRead(_Rs_, EEINST_LIVE1|(_Rs_!=0?EEINST_MMX:0)); + break; + } +} // End namespace OpcodeImpl diff --git a/pcsx2/x86/ix86-32/iCore-32.cpp b/pcsx2/x86/ix86-32/iCore-32.cpp index 3b23bdf060..9f36663ed7 100644 --- a/pcsx2/x86/ix86-32/iCore-32.cpp +++ b/pcsx2/x86/ix86-32/iCore-32.cpp @@ -1,1112 +1,1112 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Misc.h" -#include "iR5900.h" -#include "Vif.h" -#include "VU.h" -#include "ix86/ix86.h" -#include "iR3000A.h" - -#include - -using namespace std; - -u16 x86FpuState, iCWstate; -u16 g_mmxAllocCounter = 0; - -// X86 caching -int g_x86checknext; - -// use special x86 register allocation for ia32 - -void _initX86regs() { - memzero_obj(x86regs); - g_x86AllocCounter = 0; - g_x86checknext = 0; -} - -u32 _x86GetAddr(int type, int reg) -{ - switch(type&~X86TYPE_VU1) { - case X86TYPE_GPR: return (u32)&cpuRegs.GPR.r[reg]; - case X86TYPE_VI: { - //assert( reg < 16 || reg == REG_R ); - return (type&X86TYPE_VU1)?(u32)&VU1.VI[reg]:(u32)&VU0.VI[reg]; - } - case X86TYPE_MEMOFFSET: return 0; - case X86TYPE_VIMEMOFFSET: return 0; - case X86TYPE_VUQREAD: return (type&X86TYPE_VU1)?(u32)&VU1.VI[REG_Q]:(u32)&VU0.VI[REG_Q]; - case X86TYPE_VUPREAD: return (type&X86TYPE_VU1)?(u32)&VU1.VI[REG_P]:(u32)&VU0.VI[REG_P]; - case X86TYPE_VUQWRITE: return (type&X86TYPE_VU1)?(u32)&VU1.q:(u32)&VU0.q; - case X86TYPE_VUPWRITE: return (type&X86TYPE_VU1)?(u32)&VU1.p:(u32)&VU0.p; - case X86TYPE_PSX: return (u32)&psxRegs.GPR.r[reg]; - case X86TYPE_PCWRITEBACK: - return (u32)&g_recWriteback; - case X86TYPE_VUJUMP: - return (u32)&g_recWriteback; - - jNO_DEFAULT; - } - - return 0; -} - -int _getFreeX86reg(int mode) -{ - int i, tempi; - u32 bestcount = 0x10000; - - int maxreg = (mode&MODE_8BITREG)?4:X86REGS; - - for (i=0; i= maxreg ) continue; - if( (mode&MODE_NOFRAME) && reg==EBP ) continue; - - if (x86regs[reg].inuse == 0) { - g_x86checknext = (reg+1)%X86REGS; - return reg; - } - } - - tempi = -1; - for (i=1; i= 0 && reg < 32 ); - -// if( X86_ISVI(type) ) -// assert( reg < 16 || reg == REG_R ); - - // don't alloc EAX and ESP,EBP if MODE_NOFRAME - int oldmode = mode; - int noframe = mode&MODE_NOFRAME; - int maxreg = (mode&MODE_8BITREG)?4:X86REGS; - mode &= ~(MODE_NOFRAME|MODE_8BITREG); - int readfromreg = -1; - - if( type != X86TYPE_TEMP ) { - - if( maxreg < X86REGS ) { - // make sure reg isn't in the higher regs - - for(i = maxreg; i < X86REGS; ++i) { - if (!x86regs[i].inuse || x86regs[i].type != type || x86regs[i].reg != reg) continue; - - if( mode & MODE_READ ) { - readfromreg = i; - x86regs[i].inuse = 0; - break; - } - else if( mode & MODE_WRITE ) { - x86regs[i].inuse = 0; - break; - } - } - } - - for (i=1; i= maxreg) ) { - if( x86regs[i].mode & MODE_READ ) - readfromreg = i; - //if( xmmregs[i].mode & MODE_WRITE ) mode |= MODE_WRITE; - mode |= x86regs[i].mode&MODE_WRITE; - x86regs[i].inuse = 0; - break; - } - - if( x86reg >= 0 ) { - // requested specific reg, so return that instead - if( i != x86reg ) { - if( x86regs[i].mode & MODE_READ ) readfromreg = i; - //if( x86regs[i].mode & MODE_WRITE ) mode |= MODE_WRITE; - mode |= x86regs[i].mode&MODE_WRITE; - x86regs[i].inuse = 0; - break; - } - } - - if( type != X86TYPE_TEMP && !(x86regs[i].mode & MODE_READ) && (mode&MODE_READ)) { - - if( type == X86TYPE_GPR ) _flushConstReg(reg); - - if( X86_ISVI(type) && reg < 16 ) MOVZX32M16toR(i, _x86GetAddr(type, reg)); - else MOV32MtoR(i, _x86GetAddr(type, reg)); - - x86regs[i].mode |= MODE_READ; - } - - x86regs[i].needed = 1; - x86regs[i].mode|= mode; - return i; - } - } - - if (x86reg == -1) { - x86reg = _getFreeX86reg(oldmode); - } - else { - _freeX86reg(x86reg); - } - - x86regs[x86reg].type = type; - x86regs[x86reg].reg = reg; - x86regs[x86reg].mode = mode; - x86regs[x86reg].needed = 1; - x86regs[x86reg].inuse = 1; - - if( mode & MODE_READ ) { - if( readfromreg >= 0 ) MOV32RtoR(x86reg, readfromreg); - else { - if( type == X86TYPE_GPR ) { - - if( reg == 0 ) { - XOR32RtoR(x86reg, x86reg); - } - else { - _flushConstReg(reg); - _deleteMMXreg(MMX_GPR+reg, 1); - _deleteGPRtoXMMreg(reg, 1); - - _eeMoveGPRtoR(x86reg, reg); - - _deleteMMXreg(MMX_GPR+reg, 0); - _deleteGPRtoXMMreg(reg, 0); - } - } - else { - if( X86_ISVI(type) && reg < 16 ) { - if( reg == 0 ) XOR32RtoR(x86reg, x86reg); - else MOVZX32M16toR(x86reg, _x86GetAddr(type, reg)); - } - else MOV32MtoR(x86reg, _x86GetAddr(type, reg)); - } - } - } - - return x86reg; -} - -int _checkX86reg(int type, int reg, int mode) -{ - int i; - - for (i=0; i= 0 && x86reg < X86REGS ); - - if( x86regs[x86reg].inuse && (x86regs[x86reg].mode&MODE_WRITE) ) { - x86regs[x86reg].mode &= ~MODE_WRITE; - - if( X86_ISVI(x86regs[x86reg].type) && x86regs[x86reg].reg < 16 ) { - MOV16RtoM(_x86GetAddr(x86regs[x86reg].type, x86regs[x86reg].reg), x86reg); - } - else - MOV32RtoM(_x86GetAddr(x86regs[x86reg].type, x86regs[x86reg].reg), x86reg); - } - - x86regs[x86reg].inuse = 0; -} - -void _freeX86regs() { - int i; - - for (i=0; i= MMX_GPR && reg < MMX_GPR+32 ) return &cpuRegs.GPR.r[reg&31]; - if( reg >= MMX_FPU && reg < MMX_FPU+32 ) return &fpuRegs.fpr[reg&31]; - if( reg >= MMX_COP0 && reg < MMX_COP0+32 ) return &cpuRegs.CP0.r[reg&31]; - - assert( 0 ); - return NULL; -} - -int _getFreeMMXreg() -{ - int i, tempi; - u32 bestcount = 0x10000; - - for (i=0; i= MMX_GPR && mmxregs[i].reg < MMX_GPR+34 ) { - if( !(g_pCurInstInfo->regs[mmxregs[i].reg-MMX_GPR] & (EEINST_LIVE0|EEINST_LIVE1)) ) { - _freeMMXreg(i); - return i; - } - if( !(g_pCurInstInfo->regs[mmxregs[i].reg-MMX_GPR]&EEINST_USED) ) { - _freeMMXreg(i); - return i; - } - } - } - - // check for future xmm usage - for (i=0; i= MMX_GPR && mmxregs[i].reg < MMX_GPR+34 ) { - if( !(g_pCurInstInfo->regs[mmxregs[i].reg] & EEINST_MMX) ) { - _freeMMXreg(i); - return i; - } - } - } - - tempi = -1; - for (i=0; i= 0 ) { - SSE_MOVHPS_XMM_to_M64((u32)_MMXGetAddr(reg)+8, xmmreg); - if( mode & MODE_READ ) - SSE2_MOVDQ2Q_XMM_to_MM(mmxreg, xmmreg); - - if( xmmregs[xmmreg].mode & MODE_WRITE ) - mmxregs[mmxreg].mode |= MODE_WRITE; - - // don't flush - xmmregs[xmmreg].inuse = 0; - } - else { - if( MMX_ISGPR(reg) ) { - if(mode&(MODE_READHALF|MODE_READ)) _flushConstReg(reg-MMX_GPR); - } - - if( (mode & MODE_READHALF) || (MMX_IS32BITS(reg)&&(mode&MODE_READ)) ) { - MOVDMtoMMX(mmxreg, (u32)_MMXGetAddr(reg)); - } - else if( mode & MODE_READ ) { - MOVQMtoR(mmxreg, (u32)_MMXGetAddr(reg)); - } - } - } - - return mmxreg; -} - -int _checkMMXreg(int reg, int mode) -{ - int i; - for (i=0; i= MMX_GPR && mmxregs[i].reg < MMX_GPR+34 ) { - if( !EEINST_ISLIVE64(mmxregs[i].reg-MMX_GPR) ) { - return 1; - } - } - } - - // check for dead regs - for (i=0; i= MMX_GPR && mmxregs[i].reg < MMX_GPR+34 ) { - if( !(g_pCurInstInfo->regs[mmxregs[i].reg-MMX_GPR]&EEINST_USED) ) { - return 1; - } - } - } - - return 0; -} - -void _freeMMXreg(int mmxreg) -{ - assert( mmxreg < MMXREGS ); - if (!mmxregs[mmxreg].inuse) return; - - if (mmxregs[mmxreg].mode & MODE_WRITE ) { - - if( mmxregs[mmxreg].reg >= MMX_GPR && mmxregs[mmxreg].reg < MMX_GPR+32 ) - assert( !(g_cpuHasConstReg & (1<<(mmxregs[mmxreg].reg-MMX_GPR))) ); - - assert( mmxregs[mmxreg].reg != MMX_GPR ); - - if( MMX_IS32BITS(mmxregs[mmxreg].reg) ) - MOVDMMXtoM((u32)_MMXGetAddr(mmxregs[mmxreg].reg), mmxreg); - else - MOVQRtoM((u32)_MMXGetAddr(mmxregs[mmxreg].reg), mmxreg); - - SetMMXstate(); - } - - mmxregs[mmxreg].mode &= ~MODE_WRITE; - mmxregs[mmxreg].inuse = 0; -} - -void _moveMMXreg(int mmxreg) -{ - int i; - if( !mmxregs[mmxreg].inuse ) return; - - for (i=0; i>16)&0x1f].UL[0]); - } - else if( IS_PSXCONSTREG(arg) ) { - PUSH32I(g_psxConstRegs[(arg>>16)&0x1f]); - } - else if( IS_MEMORYREG(arg) ) PUSH32M(argmem); - else { - assert( (arg&0xfff0) == 0 ); - // assume it is a GPR reg - PUSH32R(arg&0xf); - } -} - -__forceinline void _callFunctionArg1(uptr fn, u32 arg1, uptr arg1mem) -{ - _callPushArg(arg1, arg1mem); - CALLFunc((uptr)fn); - ADD32ItoR(ESP, 4); -} - -__forceinline void _callFunctionArg2(uptr fn, u32 arg1, u32 arg2, uptr arg1mem, uptr arg2mem) -{ - _callPushArg(arg2, arg2mem); - _callPushArg(arg1, arg1mem); - CALLFunc((uptr)fn); - ADD32ItoR(ESP, 8); -} - -__forceinline void _callFunctionArg3(uptr fn, u32 arg1, u32 arg2, u32 arg3, uptr arg1mem, uptr arg2mem, uptr arg3mem) -{ - _callPushArg(arg3, arg3mem); - _callPushArg(arg2, arg2mem); - _callPushArg(arg1, arg1mem); - CALLFunc((uptr)fn); - ADD32ItoR(ESP, 12); -} - -void _recPushReg(int mmreg) -{ - if( IS_XMMREG(mmreg) ) { - SUB32ItoR(ESP, 4); - SSEX_MOVD_XMM_to_Rm(ESP, mmreg&0xf); - } - else if( IS_MMXREG(mmreg) ) { - SUB32ItoR(ESP, 4); - MOVD32MMXtoRm(ESP, mmreg&0xf); - } - else if( IS_EECONSTREG(mmreg) ) { - PUSH32I(g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]); - } - else if( IS_PSXCONSTREG(mmreg) ) { - PUSH32I(g_psxConstRegs[(mmreg>>16)&0x1f]); - } - else { - assert( (mmreg&0xfff0) == 0 ); - PUSH32R(mmreg); - } -} - -void _signExtendSFtoM(u32 mem) -{ - LAHF(); - SAR16ItoR(EAX, 15); - CWDE(); - MOV32RtoM(mem, EAX ); -} - -int _signExtendMtoMMX(x86MMXRegType to, u32 mem) -{ - int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVDMtoMMX(t0reg, mem); - MOVQRtoR(to, t0reg); - PSRADItoR(t0reg, 31); - PUNPCKLDQRtoR(to, t0reg); - _freeMMXreg(t0reg); - return to; -} - -int _signExtendGPRMMXtoMMX(x86MMXRegType to, u32 gprreg, x86MMXRegType from, u32 gprfromreg) -{ - assert( to >= 0 && from >= 0 ); - if( !EEINST_ISLIVE1(gprreg) ) { - EEINST_RESETHASLIVE1(gprreg); - if( to != from ) MOVQRtoR(to, from); - return to; - } - - if( to == from ) return _signExtendGPRtoMMX(to, gprreg, 0); - if( !(g_pCurInstInfo->regs[gprfromreg]&EEINST_LASTUSE) ) { - if( EEINST_ISLIVE64(gprfromreg) ) { - MOVQRtoR(to, from); - return _signExtendGPRtoMMX(to, gprreg, 0); - } - } - - // from is free for use - SetMMXstate(); - - if( g_pCurInstInfo->regs[gprreg] & EEINST_MMX ) { - - if( EEINST_ISLIVE64(gprfromreg) ) { - _freeMMXreg(from); - } - - MOVQRtoR(to, from); - PSRADItoR(from, 31); - PUNPCKLDQRtoR(to, from); - return to; - } - else { - MOVQRtoR(to, from); - MOVDMMXtoM((u32)&cpuRegs.GPR.r[gprreg].UL[0], from); - PSRADItoR(from, 31); - MOVDMMXtoM((u32)&cpuRegs.GPR.r[gprreg].UL[1], from); - mmxregs[to].inuse = 0; - return -1; - } - - assert(0); -} - -int _signExtendGPRtoMMX(x86MMXRegType to, u32 gprreg, int shift) -{ - assert( to >= 0 && shift >= 0 ); - if( !EEINST_ISLIVE1(gprreg) ) { - if( shift > 0 ) PSRADItoR(to, shift); - EEINST_RESETHASLIVE1(gprreg); - return to; - } - - SetMMXstate(); - - if( g_pCurInstInfo->regs[gprreg] & EEINST_MMX ) { - if( _hasFreeMMXreg() ) { - int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQRtoR(t0reg, to); - PSRADItoR(to, 31); - if( shift > 0 ) PSRADItoR(t0reg, shift); - PUNPCKLDQRtoR(t0reg, to); - - // swap mmx regs.. don't ask - mmxregs[t0reg] = mmxregs[to]; - mmxregs[to].inuse = 0; - return t0reg; - } - else { - // will be used in the future as mmx - if( shift > 0 ) PSRADItoR(to, shift); - MOVDMMXtoM((u32)&cpuRegs.GPR.r[gprreg].UL[0], to); - PSRADItoR(to, 31); - MOVDMMXtoM((u32)&cpuRegs.GPR.r[gprreg].UL[1], to); - - // read again - MOVQMtoR(to, (u32)&cpuRegs.GPR.r[gprreg].UL[0]); - mmxregs[to].mode &= ~MODE_WRITE; - return to; - } - } - else { - if( shift > 0 ) PSRADItoR(to, shift); - MOVDMMXtoM((u32)&cpuRegs.GPR.r[gprreg].UL[0], to); - PSRADItoR(to, 31); - MOVDMMXtoM((u32)&cpuRegs.GPR.r[gprreg].UL[1], to); - mmxregs[to].inuse = 0; - return -1; - } - - assert(0); -} - -int _allocCheckGPRtoMMX(EEINST* pinst, int reg, int mode) -{ - if( pinst->regs[reg] & EEINST_MMX ) return _allocMMXreg(-1, MMX_GPR+reg, mode); - - return _checkMMXreg(MMX_GPR+reg, mode); -} - -// fixme - yay stupid? This sucks, and is used form iCOp2.cpp only. -// Surely there is a better way! -void _recMove128MtoM(u32 to, u32 from) -{ - MOV32MtoR(EAX, from); - MOV32MtoR(EDX, from+4); - MOV32RtoM(to, EAX); - MOV32RtoM(to+4, EDX); - MOV32MtoR(EAX, from+8); - MOV32MtoR(EDX, from+12); - MOV32RtoM(to+8, EAX); - MOV32RtoM(to+12, EDX); -} - -// fixme - see above function! -void _recMove128RmOffsettoM(u32 to, u32 offset) -{ - MOV32RmtoROffset(EAX, ECX, offset); - MOV32RmtoROffset(EDX, ECX, offset+4); - MOV32RtoM(to, EAX); - MOV32RtoM(to+4, EDX); - MOV32RmtoROffset(EAX, ECX, offset+8); - MOV32RmtoROffset(EDX, ECX, offset+12); - MOV32RtoM(to+8, EAX); - MOV32RtoM(to+12, EDX); -} - -// fixme - see above function again! -void _recMove128MtoRmOffset(u32 offset, u32 from) -{ - MOV32MtoR(EAX, from); - MOV32MtoR(EDX, from+4); - MOV32RtoRmOffset(ECX, EAX, offset); - MOV32RtoRmOffset(ECX, EDX, offset+4); - MOV32MtoR(EAX, from+8); - MOV32MtoR(EDX, from+12); - MOV32RtoRmOffset(ECX, EAX, offset+8); - MOV32RtoRmOffset(ECX, EDX, offset+12); -} - -static PCSX2_ALIGNED16(u32 s_ones[2]) = {0xffffffff, 0xffffffff}; - -void LogicalOpRtoR(x86MMXRegType to, x86MMXRegType from, int op) -{ - switch(op) { - case 0: PANDRtoR(to, from); break; - case 1: PORRtoR(to, from); break; - case 2: PXORRtoR(to, from); break; - case 3: - PORRtoR(to, from); - PXORMtoR(to, (u32)&s_ones[0]); - break; - } -} - -void LogicalOpMtoR(x86MMXRegType to, u32 from, int op) -{ - switch(op) { - case 0: PANDMtoR(to, from); break; - case 1: PORMtoR(to, from); break; - case 2: PXORMtoR(to, from); break; - case 3: - PORRtoR(to, from); - PXORMtoR(to, (u32)&s_ones[0]); - break; - } -} - -void LogicalOp32RtoM(u32 to, x86IntRegType from, int op) -{ - switch(op) { - case 0: AND32RtoM(to, from); break; - case 1: OR32RtoM(to, from); break; - case 2: XOR32RtoM(to, from); break; - case 3: OR32RtoM(to, from); break; - } -} - -void LogicalOp32MtoR(x86IntRegType to, u32 from, int op) -{ - switch(op) { - case 0: AND32MtoR(to, from); break; - case 1: OR32MtoR(to, from); break; - case 2: XOR32MtoR(to, from); break; - case 3: OR32MtoR(to, from); break; - } -} - -void LogicalOp32ItoR(x86IntRegType to, u32 from, int op) -{ - switch(op) { - case 0: AND32ItoR(to, from); break; - case 1: OR32ItoR(to, from); break; - case 2: XOR32ItoR(to, from); break; - case 3: OR32ItoR(to, from); break; - } -} - -void LogicalOp32ItoM(u32 to, u32 from, int op) -{ - switch(op) { - case 0: AND32ItoM(to, from); break; - case 1: OR32ItoM(to, from); break; - case 2: XOR32ItoM(to, from); break; - case 3: OR32ItoM(to, from); break; - } -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Misc.h" +#include "iR5900.h" +#include "Vif.h" +#include "VU.h" +#include "ix86/ix86.h" +#include "iR3000A.h" + +#include + +using namespace std; + +u16 x86FpuState, iCWstate; +u16 g_mmxAllocCounter = 0; + +// X86 caching +int g_x86checknext; + +// use special x86 register allocation for ia32 + +void _initX86regs() { + memzero_obj(x86regs); + g_x86AllocCounter = 0; + g_x86checknext = 0; +} + +u32 _x86GetAddr(int type, int reg) +{ + switch(type&~X86TYPE_VU1) { + case X86TYPE_GPR: return (u32)&cpuRegs.GPR.r[reg]; + case X86TYPE_VI: { + //assert( reg < 16 || reg == REG_R ); + return (type&X86TYPE_VU1)?(u32)&VU1.VI[reg]:(u32)&VU0.VI[reg]; + } + case X86TYPE_MEMOFFSET: return 0; + case X86TYPE_VIMEMOFFSET: return 0; + case X86TYPE_VUQREAD: return (type&X86TYPE_VU1)?(u32)&VU1.VI[REG_Q]:(u32)&VU0.VI[REG_Q]; + case X86TYPE_VUPREAD: return (type&X86TYPE_VU1)?(u32)&VU1.VI[REG_P]:(u32)&VU0.VI[REG_P]; + case X86TYPE_VUQWRITE: return (type&X86TYPE_VU1)?(u32)&VU1.q:(u32)&VU0.q; + case X86TYPE_VUPWRITE: return (type&X86TYPE_VU1)?(u32)&VU1.p:(u32)&VU0.p; + case X86TYPE_PSX: return (u32)&psxRegs.GPR.r[reg]; + case X86TYPE_PCWRITEBACK: + return (u32)&g_recWriteback; + case X86TYPE_VUJUMP: + return (u32)&g_recWriteback; + + jNO_DEFAULT; + } + + return 0; +} + +int _getFreeX86reg(int mode) +{ + int i, tempi; + u32 bestcount = 0x10000; + + int maxreg = (mode&MODE_8BITREG)?4:X86REGS; + + for (i=0; i= maxreg ) continue; + if( (mode&MODE_NOFRAME) && reg==EBP ) continue; + + if (x86regs[reg].inuse == 0) { + g_x86checknext = (reg+1)%X86REGS; + return reg; + } + } + + tempi = -1; + for (i=1; i= 0 && reg < 32 ); + +// if( X86_ISVI(type) ) +// assert( reg < 16 || reg == REG_R ); + + // don't alloc EAX and ESP,EBP if MODE_NOFRAME + int oldmode = mode; + int noframe = mode&MODE_NOFRAME; + int maxreg = (mode&MODE_8BITREG)?4:X86REGS; + mode &= ~(MODE_NOFRAME|MODE_8BITREG); + int readfromreg = -1; + + if( type != X86TYPE_TEMP ) { + + if( maxreg < X86REGS ) { + // make sure reg isn't in the higher regs + + for(i = maxreg; i < X86REGS; ++i) { + if (!x86regs[i].inuse || x86regs[i].type != type || x86regs[i].reg != reg) continue; + + if( mode & MODE_READ ) { + readfromreg = i; + x86regs[i].inuse = 0; + break; + } + else if( mode & MODE_WRITE ) { + x86regs[i].inuse = 0; + break; + } + } + } + + for (i=1; i= maxreg) ) { + if( x86regs[i].mode & MODE_READ ) + readfromreg = i; + //if( xmmregs[i].mode & MODE_WRITE ) mode |= MODE_WRITE; + mode |= x86regs[i].mode&MODE_WRITE; + x86regs[i].inuse = 0; + break; + } + + if( x86reg >= 0 ) { + // requested specific reg, so return that instead + if( i != x86reg ) { + if( x86regs[i].mode & MODE_READ ) readfromreg = i; + //if( x86regs[i].mode & MODE_WRITE ) mode |= MODE_WRITE; + mode |= x86regs[i].mode&MODE_WRITE; + x86regs[i].inuse = 0; + break; + } + } + + if( type != X86TYPE_TEMP && !(x86regs[i].mode & MODE_READ) && (mode&MODE_READ)) { + + if( type == X86TYPE_GPR ) _flushConstReg(reg); + + if( X86_ISVI(type) && reg < 16 ) MOVZX32M16toR(i, _x86GetAddr(type, reg)); + else MOV32MtoR(i, _x86GetAddr(type, reg)); + + x86regs[i].mode |= MODE_READ; + } + + x86regs[i].needed = 1; + x86regs[i].mode|= mode; + return i; + } + } + + if (x86reg == -1) { + x86reg = _getFreeX86reg(oldmode); + } + else { + _freeX86reg(x86reg); + } + + x86regs[x86reg].type = type; + x86regs[x86reg].reg = reg; + x86regs[x86reg].mode = mode; + x86regs[x86reg].needed = 1; + x86regs[x86reg].inuse = 1; + + if( mode & MODE_READ ) { + if( readfromreg >= 0 ) MOV32RtoR(x86reg, readfromreg); + else { + if( type == X86TYPE_GPR ) { + + if( reg == 0 ) { + XOR32RtoR(x86reg, x86reg); + } + else { + _flushConstReg(reg); + _deleteMMXreg(MMX_GPR+reg, 1); + _deleteGPRtoXMMreg(reg, 1); + + _eeMoveGPRtoR(x86reg, reg); + + _deleteMMXreg(MMX_GPR+reg, 0); + _deleteGPRtoXMMreg(reg, 0); + } + } + else { + if( X86_ISVI(type) && reg < 16 ) { + if( reg == 0 ) XOR32RtoR(x86reg, x86reg); + else MOVZX32M16toR(x86reg, _x86GetAddr(type, reg)); + } + else MOV32MtoR(x86reg, _x86GetAddr(type, reg)); + } + } + } + + return x86reg; +} + +int _checkX86reg(int type, int reg, int mode) +{ + int i; + + for (i=0; i= 0 && x86reg < X86REGS ); + + if( x86regs[x86reg].inuse && (x86regs[x86reg].mode&MODE_WRITE) ) { + x86regs[x86reg].mode &= ~MODE_WRITE; + + if( X86_ISVI(x86regs[x86reg].type) && x86regs[x86reg].reg < 16 ) { + MOV16RtoM(_x86GetAddr(x86regs[x86reg].type, x86regs[x86reg].reg), x86reg); + } + else + MOV32RtoM(_x86GetAddr(x86regs[x86reg].type, x86regs[x86reg].reg), x86reg); + } + + x86regs[x86reg].inuse = 0; +} + +void _freeX86regs() { + int i; + + for (i=0; i= MMX_GPR && reg < MMX_GPR+32 ) return &cpuRegs.GPR.r[reg&31]; + if( reg >= MMX_FPU && reg < MMX_FPU+32 ) return &fpuRegs.fpr[reg&31]; + if( reg >= MMX_COP0 && reg < MMX_COP0+32 ) return &cpuRegs.CP0.r[reg&31]; + + assert( 0 ); + return NULL; +} + +int _getFreeMMXreg() +{ + int i, tempi; + u32 bestcount = 0x10000; + + for (i=0; i= MMX_GPR && mmxregs[i].reg < MMX_GPR+34 ) { + if( !(g_pCurInstInfo->regs[mmxregs[i].reg-MMX_GPR] & (EEINST_LIVE0|EEINST_LIVE1)) ) { + _freeMMXreg(i); + return i; + } + if( !(g_pCurInstInfo->regs[mmxregs[i].reg-MMX_GPR]&EEINST_USED) ) { + _freeMMXreg(i); + return i; + } + } + } + + // check for future xmm usage + for (i=0; i= MMX_GPR && mmxregs[i].reg < MMX_GPR+34 ) { + if( !(g_pCurInstInfo->regs[mmxregs[i].reg] & EEINST_MMX) ) { + _freeMMXreg(i); + return i; + } + } + } + + tempi = -1; + for (i=0; i= 0 ) { + SSE_MOVHPS_XMM_to_M64((u32)_MMXGetAddr(reg)+8, xmmreg); + if( mode & MODE_READ ) + SSE2_MOVDQ2Q_XMM_to_MM(mmxreg, xmmreg); + + if( xmmregs[xmmreg].mode & MODE_WRITE ) + mmxregs[mmxreg].mode |= MODE_WRITE; + + // don't flush + xmmregs[xmmreg].inuse = 0; + } + else { + if( MMX_ISGPR(reg) ) { + if(mode&(MODE_READHALF|MODE_READ)) _flushConstReg(reg-MMX_GPR); + } + + if( (mode & MODE_READHALF) || (MMX_IS32BITS(reg)&&(mode&MODE_READ)) ) { + MOVDMtoMMX(mmxreg, (u32)_MMXGetAddr(reg)); + } + else if( mode & MODE_READ ) { + MOVQMtoR(mmxreg, (u32)_MMXGetAddr(reg)); + } + } + } + + return mmxreg; +} + +int _checkMMXreg(int reg, int mode) +{ + int i; + for (i=0; i= MMX_GPR && mmxregs[i].reg < MMX_GPR+34 ) { + if( !EEINST_ISLIVE64(mmxregs[i].reg-MMX_GPR) ) { + return 1; + } + } + } + + // check for dead regs + for (i=0; i= MMX_GPR && mmxregs[i].reg < MMX_GPR+34 ) { + if( !(g_pCurInstInfo->regs[mmxregs[i].reg-MMX_GPR]&EEINST_USED) ) { + return 1; + } + } + } + + return 0; +} + +void _freeMMXreg(int mmxreg) +{ + assert( mmxreg < MMXREGS ); + if (!mmxregs[mmxreg].inuse) return; + + if (mmxregs[mmxreg].mode & MODE_WRITE ) { + + if( mmxregs[mmxreg].reg >= MMX_GPR && mmxregs[mmxreg].reg < MMX_GPR+32 ) + assert( !(g_cpuHasConstReg & (1<<(mmxregs[mmxreg].reg-MMX_GPR))) ); + + assert( mmxregs[mmxreg].reg != MMX_GPR ); + + if( MMX_IS32BITS(mmxregs[mmxreg].reg) ) + MOVDMMXtoM((u32)_MMXGetAddr(mmxregs[mmxreg].reg), mmxreg); + else + MOVQRtoM((u32)_MMXGetAddr(mmxregs[mmxreg].reg), mmxreg); + + SetMMXstate(); + } + + mmxregs[mmxreg].mode &= ~MODE_WRITE; + mmxregs[mmxreg].inuse = 0; +} + +void _moveMMXreg(int mmxreg) +{ + int i; + if( !mmxregs[mmxreg].inuse ) return; + + for (i=0; i>16)&0x1f].UL[0]); + } + else if( IS_PSXCONSTREG(arg) ) { + PUSH32I(g_psxConstRegs[(arg>>16)&0x1f]); + } + else if( IS_MEMORYREG(arg) ) PUSH32M(argmem); + else { + assert( (arg&0xfff0) == 0 ); + // assume it is a GPR reg + PUSH32R(arg&0xf); + } +} + +__forceinline void _callFunctionArg1(uptr fn, u32 arg1, uptr arg1mem) +{ + _callPushArg(arg1, arg1mem); + CALLFunc((uptr)fn); + ADD32ItoR(ESP, 4); +} + +__forceinline void _callFunctionArg2(uptr fn, u32 arg1, u32 arg2, uptr arg1mem, uptr arg2mem) +{ + _callPushArg(arg2, arg2mem); + _callPushArg(arg1, arg1mem); + CALLFunc((uptr)fn); + ADD32ItoR(ESP, 8); +} + +__forceinline void _callFunctionArg3(uptr fn, u32 arg1, u32 arg2, u32 arg3, uptr arg1mem, uptr arg2mem, uptr arg3mem) +{ + _callPushArg(arg3, arg3mem); + _callPushArg(arg2, arg2mem); + _callPushArg(arg1, arg1mem); + CALLFunc((uptr)fn); + ADD32ItoR(ESP, 12); +} + +void _recPushReg(int mmreg) +{ + if( IS_XMMREG(mmreg) ) { + SUB32ItoR(ESP, 4); + SSEX_MOVD_XMM_to_Rm(ESP, mmreg&0xf); + } + else if( IS_MMXREG(mmreg) ) { + SUB32ItoR(ESP, 4); + MOVD32MMXtoRm(ESP, mmreg&0xf); + } + else if( IS_EECONSTREG(mmreg) ) { + PUSH32I(g_cpuConstRegs[(mmreg>>16)&0x1f].UL[0]); + } + else if( IS_PSXCONSTREG(mmreg) ) { + PUSH32I(g_psxConstRegs[(mmreg>>16)&0x1f]); + } + else { + assert( (mmreg&0xfff0) == 0 ); + PUSH32R(mmreg); + } +} + +void _signExtendSFtoM(u32 mem) +{ + LAHF(); + SAR16ItoR(EAX, 15); + CWDE(); + MOV32RtoM(mem, EAX ); +} + +int _signExtendMtoMMX(x86MMXRegType to, u32 mem) +{ + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVDMtoMMX(t0reg, mem); + MOVQRtoR(to, t0reg); + PSRADItoR(t0reg, 31); + PUNPCKLDQRtoR(to, t0reg); + _freeMMXreg(t0reg); + return to; +} + +int _signExtendGPRMMXtoMMX(x86MMXRegType to, u32 gprreg, x86MMXRegType from, u32 gprfromreg) +{ + assert( to >= 0 && from >= 0 ); + if( !EEINST_ISLIVE1(gprreg) ) { + EEINST_RESETHASLIVE1(gprreg); + if( to != from ) MOVQRtoR(to, from); + return to; + } + + if( to == from ) return _signExtendGPRtoMMX(to, gprreg, 0); + if( !(g_pCurInstInfo->regs[gprfromreg]&EEINST_LASTUSE) ) { + if( EEINST_ISLIVE64(gprfromreg) ) { + MOVQRtoR(to, from); + return _signExtendGPRtoMMX(to, gprreg, 0); + } + } + + // from is free for use + SetMMXstate(); + + if( g_pCurInstInfo->regs[gprreg] & EEINST_MMX ) { + + if( EEINST_ISLIVE64(gprfromreg) ) { + _freeMMXreg(from); + } + + MOVQRtoR(to, from); + PSRADItoR(from, 31); + PUNPCKLDQRtoR(to, from); + return to; + } + else { + MOVQRtoR(to, from); + MOVDMMXtoM((u32)&cpuRegs.GPR.r[gprreg].UL[0], from); + PSRADItoR(from, 31); + MOVDMMXtoM((u32)&cpuRegs.GPR.r[gprreg].UL[1], from); + mmxregs[to].inuse = 0; + return -1; + } + + assert(0); +} + +int _signExtendGPRtoMMX(x86MMXRegType to, u32 gprreg, int shift) +{ + assert( to >= 0 && shift >= 0 ); + if( !EEINST_ISLIVE1(gprreg) ) { + if( shift > 0 ) PSRADItoR(to, shift); + EEINST_RESETHASLIVE1(gprreg); + return to; + } + + SetMMXstate(); + + if( g_pCurInstInfo->regs[gprreg] & EEINST_MMX ) { + if( _hasFreeMMXreg() ) { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, to); + PSRADItoR(to, 31); + if( shift > 0 ) PSRADItoR(t0reg, shift); + PUNPCKLDQRtoR(t0reg, to); + + // swap mmx regs.. don't ask + mmxregs[t0reg] = mmxregs[to]; + mmxregs[to].inuse = 0; + return t0reg; + } + else { + // will be used in the future as mmx + if( shift > 0 ) PSRADItoR(to, shift); + MOVDMMXtoM((u32)&cpuRegs.GPR.r[gprreg].UL[0], to); + PSRADItoR(to, 31); + MOVDMMXtoM((u32)&cpuRegs.GPR.r[gprreg].UL[1], to); + + // read again + MOVQMtoR(to, (u32)&cpuRegs.GPR.r[gprreg].UL[0]); + mmxregs[to].mode &= ~MODE_WRITE; + return to; + } + } + else { + if( shift > 0 ) PSRADItoR(to, shift); + MOVDMMXtoM((u32)&cpuRegs.GPR.r[gprreg].UL[0], to); + PSRADItoR(to, 31); + MOVDMMXtoM((u32)&cpuRegs.GPR.r[gprreg].UL[1], to); + mmxregs[to].inuse = 0; + return -1; + } + + assert(0); +} + +int _allocCheckGPRtoMMX(EEINST* pinst, int reg, int mode) +{ + if( pinst->regs[reg] & EEINST_MMX ) return _allocMMXreg(-1, MMX_GPR+reg, mode); + + return _checkMMXreg(MMX_GPR+reg, mode); +} + +// fixme - yay stupid? This sucks, and is used form iCOp2.cpp only. +// Surely there is a better way! +void _recMove128MtoM(u32 to, u32 from) +{ + MOV32MtoR(EAX, from); + MOV32MtoR(EDX, from+4); + MOV32RtoM(to, EAX); + MOV32RtoM(to+4, EDX); + MOV32MtoR(EAX, from+8); + MOV32MtoR(EDX, from+12); + MOV32RtoM(to+8, EAX); + MOV32RtoM(to+12, EDX); +} + +// fixme - see above function! +void _recMove128RmOffsettoM(u32 to, u32 offset) +{ + MOV32RmtoROffset(EAX, ECX, offset); + MOV32RmtoROffset(EDX, ECX, offset+4); + MOV32RtoM(to, EAX); + MOV32RtoM(to+4, EDX); + MOV32RmtoROffset(EAX, ECX, offset+8); + MOV32RmtoROffset(EDX, ECX, offset+12); + MOV32RtoM(to+8, EAX); + MOV32RtoM(to+12, EDX); +} + +// fixme - see above function again! +void _recMove128MtoRmOffset(u32 offset, u32 from) +{ + MOV32MtoR(EAX, from); + MOV32MtoR(EDX, from+4); + MOV32RtoRmOffset(ECX, EAX, offset); + MOV32RtoRmOffset(ECX, EDX, offset+4); + MOV32MtoR(EAX, from+8); + MOV32MtoR(EDX, from+12); + MOV32RtoRmOffset(ECX, EAX, offset+8); + MOV32RtoRmOffset(ECX, EDX, offset+12); +} + +static PCSX2_ALIGNED16(u32 s_ones[2]) = {0xffffffff, 0xffffffff}; + +void LogicalOpRtoR(x86MMXRegType to, x86MMXRegType from, int op) +{ + switch(op) { + case 0: PANDRtoR(to, from); break; + case 1: PORRtoR(to, from); break; + case 2: PXORRtoR(to, from); break; + case 3: + PORRtoR(to, from); + PXORMtoR(to, (u32)&s_ones[0]); + break; + } +} + +void LogicalOpMtoR(x86MMXRegType to, u32 from, int op) +{ + switch(op) { + case 0: PANDMtoR(to, from); break; + case 1: PORMtoR(to, from); break; + case 2: PXORMtoR(to, from); break; + case 3: + PORRtoR(to, from); + PXORMtoR(to, (u32)&s_ones[0]); + break; + } +} + +void LogicalOp32RtoM(u32 to, x86IntRegType from, int op) +{ + switch(op) { + case 0: AND32RtoM(to, from); break; + case 1: OR32RtoM(to, from); break; + case 2: XOR32RtoM(to, from); break; + case 3: OR32RtoM(to, from); break; + } +} + +void LogicalOp32MtoR(x86IntRegType to, u32 from, int op) +{ + switch(op) { + case 0: AND32MtoR(to, from); break; + case 1: OR32MtoR(to, from); break; + case 2: XOR32MtoR(to, from); break; + case 3: OR32MtoR(to, from); break; + } +} + +void LogicalOp32ItoR(x86IntRegType to, u32 from, int op) +{ + switch(op) { + case 0: AND32ItoR(to, from); break; + case 1: OR32ItoR(to, from); break; + case 2: XOR32ItoR(to, from); break; + case 3: OR32ItoR(to, from); break; + } +} + +void LogicalOp32ItoM(u32 to, u32 from, int op) +{ + switch(op) { + case 0: AND32ItoM(to, from); break; + case 1: OR32ItoM(to, from); break; + case 2: XOR32ItoM(to, from); break; + case 3: OR32ItoM(to, from); break; + } +} diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index 0a688a1730..e3e442e35a 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -1,2062 +1,2062 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "Memory.h" -#include "R5900OpcodeTables.h" -#include "ix86/ix86.h" -#include "iR5900.h" -#include "iR5900AritImm.h" -#include "iR5900Arit.h" -#include "iR5900MultDiv.h" -#include "iR5900Shift.h" -#include "iR5900Branch.h" -#include "iR5900Jump.h" -#include "iR5900LoadStore.h" -#include "iR5900Move.h" -#include "iMMI.h" -#include "iFPU.h" -#include "iCOP0.h" -#include "iVUmicro.h" -#include "VU.h" -#include "VUmicro.h" - -#include "iVUzerorec.h" -#include "vtlb.h" - -#include "SamplProf.h" - -using namespace R5900; - -// used to disable register freezing during cpuBranchTests (registers -// are safe then since they've been completely flushed) -bool g_EEFreezeRegs = false; - -// I can't find where the Linux recRecompile is defined. Is it used anymore? -// If so, namespacing might break it. :/ (air) -#ifdef __LINUX__ -extern "C" { -#endif -void recRecompile( u32 startpc ); -#ifdef __LINUX__ -} -#endif - -u32 maxrecmem = 0; -uptr *recLUT = NULL; - -u32 s_nBlockCycles = 0; // cycles of current block recompiling -//u8* dyna_block_discard_recmem=0; - -u32 pc; // recompiler pc -int branch; // set for branch - -PCSX2_ALIGNED16(GPR_reg64 g_cpuConstRegs[32]) = {0}; -u32 g_cpuHasConstReg = 0, g_cpuFlushedConstReg = 0; -u32 s_saveConstGPRreg = 0; -GPR_reg64 s_ConstGPRreg; - -//////////////////////////////////////////////////////////////// -// Static Private Variables - R5900 Dynarec - -#define X86 -static const int RECSTACK_SIZE = 0x00010000; -static const int EE_NUMBLOCKS = (1<<15); - -static u8 *recMem = NULL; // the recompiled blocks will be here -static u8* recStack = NULL; // stack mem -static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here -static BASEBLOCK *recROM = NULL; // and here -static BASEBLOCK *recROM1 = NULL; // also here -static BASEBLOCKEX *recBlocks = NULL; -static u8* recPtr = NULL, *recStackPtr = NULL; -static EEINST* s_pInstCache = NULL; -static u32 s_nInstCacheSize = 0; - -static BASEBLOCK* s_pCurBlock = NULL; -static BASEBLOCKEX* s_pCurBlockEx = NULL; -const BASEBLOCK* s_pDispatchBlock = NULL; -static u32 s_nEndBlock = 0; // what pc the current block ends -static u32 s_nHasDelay = 0; - -static u32 s_nNextBlock = 0; // next free block in recBlocks - -// save states for branches -static u16 s_savex86FpuState, s_saveiCWstate; -static u32 s_saveHasConstReg = 0, s_saveFlushedConstReg = 0, s_saveRegHasLive1 = 0, s_saveRegHasSignExt = 0; -static EEINST* s_psaveInstInfo = NULL; - -static u32 s_savenBlockCycles = 0; - -#ifdef _DEBUG -static u32 dumplog = 0; -#else -#define dumplog 0 -#endif - -#ifdef PCSX2_DEVBUILD -// and not sure what these might have once been used for... (air) -//static const char *txt0 = "EAX = %x : ECX = %x : EDX = %x\n"; -//static const char *txt0RC = "EAX = %x : EBX = %x : ECX = %x : EDX = %x : ESI = %x : EDI = %x\n"; -//static const char *txt1 = "REG[%d] = %x_%x\n"; -//static const char *txt2 = "M32 = %x\n"; -#endif - -static void iBranchTest(u32 newpc, bool noDispatch=false); - -BASEBLOCKEX* PC_GETBLOCKEX(BASEBLOCK* p) -{ -// BASEBLOCKEX* pex = *(BASEBLOCKEX**)(p+1); -// if( pex >= recBlocks && pex < recBlocks+EE_NUMBLOCKS ) -// return pex; - - // otherwise, use the sorted list - return GetBaseBlockEx(p->startpc, 0); -} - -//////////////////////////////////////////////////// -static void iDumpBlock( int startpc, u8 * ptr ) -{ - FILE *f; - char filename[ g_MaxPath ]; - u32 i, j; - EEINST* pcur; - u8 used[34]; - u8 fpuused[33]; - int numused, count, fpunumused; - - Console::Status( "dump1 %x:%x, %x", params startpc, pc, cpuRegs.cycle ); -#ifdef _WIN32 - CreateDirectory("dumps", NULL); - sprintf_s( filename, g_MaxPath, "dumps\\dump%.8X.txt", startpc); -#else - mkdir("dumps", 0755); - sprintf( filename, "dumps/dump%.8X.txt", startpc); -#endif - - fflush( stdout ); -// f = fopen( "dump1", "wb" ); -// fwrite( ptr, 1, (u32)x86Ptr - (u32)ptr, f ); -// fclose( f ); -// -// sprintf( command, "objdump -D --target=binary --architecture=i386 dump1 > %s", filename ); -// system( command ); - - f = fopen( filename, "w" ); - - std::string output; - - if( disR5900GetSym(startpc) != NULL ) - fprintf(f, "%s\n", disR5900GetSym(startpc)); - for ( i = startpc; i < s_nEndBlock; i += 4 ) { - disR5900Fasm( output, PSMu32( i ), i ); - fprintf( f, output.c_str() ); - } - - // write the instruction info - - fprintf(f, "\n\nlive0 - %x, live1 - %x, live2 - %x, lastuse - %x\nmmx - %x, xmm - %x, used - %x\n", - EEINST_LIVE0, EEINST_LIVE1, EEINST_LIVE2, EEINST_LASTUSE, EEINST_MMX, EEINST_XMM, EEINST_USED); - - memzero_obj(used); - numused = 0; - for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { - if( s_pInstCache->regs[i] & EEINST_USED ) { - used[i] = 1; - numused++; - } - } - - memzero_obj(fpuused); - fpunumused = 0; - for(i = 0; i < ARRAYSIZE(s_pInstCache->fpuregs); ++i) { - if( s_pInstCache->fpuregs[i] & EEINST_USED ) { - fpuused[i] = 1; - fpunumused++; - } - } - - fprintf(f, " "); - for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { - if( used[i] ) fprintf(f, "%2d ", i); - } - for(i = 0; i < ARRAYSIZE(s_pInstCache->fpuregs); ++i) { - if( fpuused[i] ) fprintf(f, "%2d ", i); - } - fprintf(f, "\n"); - - fprintf(f, " "); - for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { - if( used[i] ) fprintf(f, "%s ", disRNameGPR[i]); - } - for(i = 0; i < ARRAYSIZE(s_pInstCache->fpuregs); ++i) { - if( fpuused[i] ) fprintf(f, "%s ", i<32?"FR":"FA"); - } - fprintf(f, "\n"); - - pcur = s_pInstCache+1; - for( i = 0; i < (s_nEndBlock-startpc)/4; ++i, ++pcur) { - fprintf(f, "%2d: %2.2x ", i+1, pcur->info); - - count = 1; - for(j = 0; j < ARRAYSIZE(s_pInstCache->regs); j++) { - if( used[j] ) { - fprintf(f, "%2.2x%s", pcur->regs[j], ((count%8)&&countfpuregs); j++) { - if( fpuused[j] ) { - fprintf(f, "%2.2x%s", pcur->fpuregs[j], ((count%8)&&count>26) { - case 26: // ldl - case 27: // ldr - case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: - case 55: // LD - case 30: // lq - return ((tempcode>>21)&0x1f)==((tempcode>>16)&0x1f); // rs==rt - } - return 0; -} - -static u8 _eeIsLoadStoreCoIssue(u32 firstcode, u32 secondcode) -{ - switch(firstcode>>26) { - case 34: // lwl - return (secondcode>>26)==38; - case 38: // lwr - return (secondcode>>26)==34; - case 42: // swl - return (secondcode>>26)==46; - case 46: // swr - return (secondcode>>26)==42; - case 26: // ldl - return (secondcode>>26)==27; - case 27: // ldr - return (secondcode>>26)==26; - case 44: // sdl - return (secondcode>>26)==45; - case 45: // sdr - return (secondcode>>26)==44; - - case 32: case 33: case 35: case 36: case 37: case 39: - case 55: // LD - - // stores - case 40: case 41: case 43: - case 63: // sd - return (secondcode>>26)==(firstcode>>26); - - case 30: // lq - case 31: // sq - case 49: // lwc1 - case 57: // swc1 - case 54: // lqc2 - case 62: // sqc2 - return (secondcode>>26)==(firstcode>>26); - } - return 0; -} - -static u8 _eeIsLoadStoreCoX(u32 tempcode) -{ - switch( tempcode>>26 ) { - case 30: case 31: case 49: case 57: case 55: case 63: - return 1; - } - return 0; -} - -void _eeFlushAllUnused() -{ - int i; - for(i = 0; i < 34; ++i) { - if( pc < s_nEndBlock ) { - if( (g_pCurInstInfo[1].regs[i]&EEINST_USED) ) - continue; - } - else if( (g_pCurInstInfo[0].regs[i]&EEINST_USED) ) - continue; - - if( i < 32 && GPR_IS_CONST1(i) ) _flushConstReg(i); - else { - _deleteMMXreg(MMX_GPR+i, 1); - _deleteGPRtoXMMreg(i, 1); - } - } - - //TODO when used info is done for FPU and VU0 - for(i = 0; i < XMMREGS; ++i) { - if( xmmregs[i].inuse && xmmregs[i].type != XMMTYPE_GPRREG ) - _freeXMMreg(i); - } -} - -u32* _eeGetConstReg(int reg) -{ - assert( GPR_IS_CONST1( reg ) ); - - if( g_cpuFlushedConstReg & (1<= 0 && (xmmregs[mmreg].mode&MODE_WRITE)) { - SSE2_MOVD_XMM_to_R(to, mmreg); - } - else if( (mmreg = _checkMMXreg(MMX_GPR+fromgpr, MODE_READ)) >= 0 && (mmxregs[mmreg].mode&MODE_WRITE) ) { - MOVD32MMXtoR(to, mmreg); - SetMMXstate(); - } - else { - MOV32MtoR(to, (int)&cpuRegs.GPR.r[ fromgpr ].UL[ 0 ] ); - } - } -} - -void _eeMoveGPRtoM(u32 to, int fromgpr) -{ - if( GPR_IS_CONST1(fromgpr) ) - MOV32ItoM( to, g_cpuConstRegs[fromgpr].UL[0] ); - else { - int mmreg; - - if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, fromgpr, MODE_READ)) >= 0 ) { - SSEX_MOVD_XMM_to_M32(to, mmreg); - } - else if( (mmreg = _checkMMXreg(MMX_GPR+fromgpr, MODE_READ)) >= 0 ) { - MOVDMMXtoM(to, mmreg); - SetMMXstate(); - } - else { - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ fromgpr ].UL[ 0 ] ); - MOV32RtoM(to, EAX ); - } - } -} - -void _eeMoveGPRtoRm(x86IntRegType to, int fromgpr) -{ - if( GPR_IS_CONST1(fromgpr) ) - MOV32ItoRmOffset( to, g_cpuConstRegs[fromgpr].UL[0], 0 ); - else { - int mmreg; - - if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, fromgpr, MODE_READ)) >= 0 ) { - SSEX_MOVD_XMM_to_Rm(to, mmreg); - } - else if( (mmreg = _checkMMXreg(MMX_GPR+fromgpr, MODE_READ)) >= 0 ) { - MOVD32MMXtoRm(to, mmreg); - SetMMXstate(); - } - else { - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ fromgpr ].UL[ 0 ] ); - MOV32RtoRm(to, EAX ); - } - } -} - -int _flushXMMunused() -{ - int i; - for (i=0; iregs[xmmregs[i].reg]&EEINST_USED) ) { - if( !_recIsRegWritten(g_pCurInstInfo+1, (s_nEndBlock-pc)/4, XMMTYPE_GPRREG, xmmregs[i].reg) ) { - _freeXMMreg(i); - xmmregs[i].inuse = 1; - return 1; - } - } - } - - return 0; -} - -int _flushMMXunused() -{ - int i; - for (i=0; iregs[mmxregs[i].reg-MMX_GPR]&EEINST_USED) ) { - if( !_recIsRegWritten(g_pCurInstInfo+1, (s_nEndBlock-pc)/4, XMMTYPE_GPRREG, mmxregs[i].reg-MMX_GPR) ) { - _freeMMXreg(i); - mmxregs[i].inuse = 1; - return 1; - } - } - } - - return 0; -} - -int _flushUnusedConstReg() -{ - int i; - for(i = 1; i < 32; ++i) { - if( (g_cpuHasConstReg & (1< failed to allocate recompiler memory." ); - - // Goal: Allocate BASEBLOCKs for every possible branch target in PS2 memory. - // Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are - // always 4 bytes long). - - if( m_recBlockAlloc == NULL ) - m_recBlockAlloc = (u8*) _aligned_malloc( m_recBlockAllocSize, 4096 ); - - if( m_recBlockAlloc == NULL ) - throw Exception::OutOfMemory( "R5900-32 Init > Failed to allocate memory for BASEBLOCK tables." ); - - u8* curpos = m_recBlockAlloc; - recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Base / 4) * sizeof(BASEBLOCK); - recROM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom / 4) * sizeof(BASEBLOCK); - recROM1 = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom1 / 4) * sizeof(BASEBLOCK); - recBlocks = (BASEBLOCKEX*)curpos; curpos += sizeof(BASEBLOCKEX)*EE_NUMBLOCKS; - recStack = (u8*)curpos; - - if( s_pInstCache == NULL ) - { - s_nInstCacheSize = 128; - s_pInstCache = (EEINST*)malloc( sizeof(EEINST) * s_nInstCacheSize ); - } - - if( s_pInstCache == NULL ) - throw Exception::OutOfMemory( "R5900-32 Init > failed to allocate memory for pInstCache." ); - - // No errors.. Proceed with initialization: - - ProfilerRegisterSource( "EERec", recMem, REC_CACHEMEM+0x1000 ); - - x86FpuState = FPU_STATE; -} - -//////////////////////////////////////////////////// -void recResetEE( void ) -{ - DbgCon::Status( "iR5900-32 > Resetting recompiler memory and structures." ); - - s_nNextBlock = 0; - maxrecmem = 0; - - memset_8<0xcd, REC_CACHEMEM>(recMem); - memzero_ptr( m_recBlockAlloc ); - - if( s_pInstCache ) - memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize ); - - ResetBaseBlockEx(0); - mmap_ResetBlockTracking(); - -#ifdef _MSC_VER - __asm emms; -#else - __asm__("emms"); -#endif - - memzero_ptr<0x010000 * sizeof(uptr)>( recLUT ); - - for ( int i = 0x0000; i < 0x0200; i++ ) - { - recLUT[ i + 0x0000 ] = (uptr)&recRAM[ i << 14 ]; - recLUT[ i + 0x2000 ] = (uptr)&recRAM[ i << 14 ]; - recLUT[ i + 0x3000 ] = (uptr)&recRAM[ i << 14 ]; - } - - for ( int i = 0x0000; i < 0x0040; i++ ) - { - recLUT[ i + 0x1fc0 ] = (uptr)&recROM[ i << 14 ]; - recLUT[ i + 0x9fc0 ] = (uptr)&recROM[ i << 14 ]; - recLUT[ i + 0xbfc0 ] = (uptr)&recROM[ i << 14 ]; - } - - for ( int i = 0x0000; i < 0x0004; i++ ) - { - recLUT[ i + 0x1e00 ] = (uptr)&recROM1[ i << 14 ]; - recLUT[ i + 0x9e00 ] = (uptr)&recROM1[ i << 14 ]; - recLUT[ i + 0xbe00 ] = (uptr)&recROM1[ i << 14 ]; - } - - memcpy_fast( recLUT + 0x8000, recLUT, 0x2000 * sizeof(uptr) ); - memcpy_fast( recLUT + 0xa000, recLUT, 0x2000 * sizeof(uptr) ); - - // drk||Raziel says this is useful but I'm not sure why. Something to do with forward jumps. - // Anyways, it causes random crashing for some reasom, possibly because of memory - // corrupition elsewhere in the recs. I can't reproduce the problem here though, - // so a fix will have to wait until later. -_- (air) - - //x86SetPtr(recMem+REC_CACHEMEM); - //dyna_block_discard_recmem=(u8*)x86Ptr; - //JMP32( (uptr)&dyna_block_discard - ( (u32)x86Ptr + 5 )); - - x86SetPtr(recMem); - - recPtr = recMem; - recStackPtr = recStack; - x86FpuState = FPU_STATE; - iCWstate = 0; - - branch = 0; - SetCPUState(Config.sseMXCSR, Config.sseVUMXCSR); -} - -static void recShutdown( void ) -{ - ProfilerTerminateSource( "EERec" ); - ResetBaseBlockEx(0); - - SafeSysMunmap( recMem, REC_CACHEMEM ); - safe_aligned_free( recLUT ); - safe_aligned_free( m_recBlockAlloc ); - recRAM = recROM = recROM1 = NULL; - recBlocks = NULL; - recStack = NULL; - - safe_free( s_pInstCache ); - s_nInstCacheSize = 0; - - x86Shutdown(); -} - -#pragma warning(disable:4731) // frame pointer register 'ebp' modified by inline assembly code - -void recStep( void ) { -} - -static __forceinline bool recEventTest() -{ -#ifdef PCSX2_DEVBUILD - // dont' remove this check unless doing an official release - if( g_globalXMMSaved || g_globalMMXSaved) - DevCon::Error("Pcsx2 Foopah! Frozen regs have not been restored!!!"); - assert( !g_globalXMMSaved && !g_globalMMXSaved); -#endif - - // Perform counters, ints, and IOP updates: - bool retval = _cpuBranchTest_Shared(); - -#ifdef PCSX2_DEVBUILD - assert( !g_globalXMMSaved && !g_globalMMXSaved); -#endif - return retval; -} - -//////////////////////////////////////////////////// - -static u32 g_lastpc = 0; -u32 g_EEDispatchTemp; - -#ifdef _MSC_VER - -// jumped to when invalid pc address -// EDX contains the jump addr to modify -static __naked void Dispatcher() -{ - // EDX contains the jump addr to modify - __asm push edx - - // calc PC_GETBLOCK - s_pDispatchBlock = PC_GETBLOCK(cpuRegs.pc); - - if( s_pDispatchBlock->startpc != cpuRegs.pc ) - recRecompile(cpuRegs.pc); - - __asm - { - mov eax, s_pDispatchBlock - mov eax, dword ptr [eax] - } - -#ifdef _DEBUG - __asm mov g_EEDispatchTemp, eax - assert( g_EEDispatchTemp ); -#endif - - __asm { - //and eax, 0x0fffffff - shl eax, 4 - pop ecx // x86Ptr to mod - mov edx, eax - sub edx, ecx - sub edx, 4 - mov dword ptr [ecx], edx - - jmp eax - } -} - -// edx - baseblock->startpc -// stack - x86Ptr -static __naked void DispatcherClear() -{ - // EDX contains the current pc - __asm mov cpuRegs.pc, edx - __asm push edx - - // calc PC_GETBLOCK - s_pDispatchBlock = PC_GETBLOCK(cpuRegs.pc); - - if( s_pDispatchBlock != NULL && s_pDispatchBlock->startpc == cpuRegs.pc ) - { - assert( s_pDispatchBlock->GetFnptr() != 0 ); - - // already modded the code, jump to the new place - __asm { - pop edx - mov eax, s_pDispatchBlock - add esp, 4 // ignore stack - mov eax, dword ptr [eax] - //and eax, 0x0fffffff - shl eax, 4 - jmp eax - } - } - - __asm { - call recRecompile - add esp, 4 // pop old param - mov eax, s_pDispatchBlock - mov eax, dword ptr [eax] - - pop ecx // old fnptr - - //and eax, 0x0fffffff - shl eax, 4 - mov byte ptr [ecx], 0xe9 // jmp32 - mov edx, eax - sub edx, ecx - sub edx, 5 - mov dword ptr [ecx+1], edx - - jmp eax - } -} - -// called when jumping to variable pc address -static __naked void DispatcherReg() -{ - s_pDispatchBlock = PC_GETBLOCK(cpuRegs.pc); - - if( s_pDispatchBlock->startpc != cpuRegs.pc ) - recRecompile(cpuRegs.pc); - - __asm - { - mov eax, s_pDispatchBlock - mov eax, dword ptr [eax] - } - -#ifdef _DEBUG - __asm mov g_EEDispatchTemp, eax - assert( g_EEDispatchTemp ); -#endif - - __asm { - //and eax, 0x0fffffff - shl eax, 4 - jmp eax - } -} - -__forceinline void recExecute() -{ - // Optimization note : Compared pushad against manually pushing the regs one-by-one. - // Manually pushing is faster, especially on Core2's and such. :) - do { - g_EEFreezeRegs = true; - __asm - { - push ebx - push esi - push edi - push ebp - - call DispatcherReg - - pop ebp - pop edi - pop esi - pop ebx - } - g_EEFreezeRegs = false; - } - while( !recEventTest() ); -} - -static void recExecuteBlock() -{ - g_EEFreezeRegs = true; - __asm - { - push ebx - push esi - push edi - push ebp - - call DispatcherReg - - pop ebp - pop edi - pop esi - pop ebx - } - g_EEFreezeRegs = false; - recEventTest(); -} - -#else // _MSC_VER -// Linux uses an assembly version of these routines. -extern "C" { -extern void Dispatcher(); -extern void DispatcherClear(); -extern void DispatcherReg(); -} -__forceinline void recExecute() -{ - // Optimization note : Compared pushad against manually pushing the regs one-by-one. - // Manually pushing is faster, especially on Core2's and such. :) - do { - g_EEFreezeRegs = true; - __asm__ - ( - ".intel_syntax\n" - "push %ebx\n" - "push %esi\n" - "push %edi\n" - "push %ebp\n" - - "call DispatcherReg\n" - - "pop %ebp\n" - "pop %edi\n" - "pop %esi\n" - "pop %ebx\n" - ".att_syntax\n" - ); - g_EEFreezeRegs = false; - } - while( !recEventTest() ); -} - -static void recExecuteBlock() -{ - g_EEFreezeRegs = true; - __asm__ - ( - ".intel_syntax\n" - "push %ebx\n" - "push %esi\n" - "push %edi\n" - "push %ebp\n" - - "call DispatcherReg\n" - - "pop %ebp\n" - "pop %edi\n" - "pop %esi\n" - "pop %ebx\n" - ".att_syntax\n" - ); - g_EEFreezeRegs = false; - recEventTest(); -} -#endif - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl { - -//////////////////////////////////////////////////// -void recSYSCALL( void ) { - MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (uptr)&cpuRegs.pc, pc ); - iFlushCall(FLUSH_NODESTROY); - CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::SYSCALL ); - - CMP32ItoM((uptr)&cpuRegs.pc, pc); - j8Ptr[0] = JE8(0); - ADD32ItoM((uptr)&cpuRegs.cycle, eeScaleBlockCycles()); - JMP32((uptr)DispatcherReg - ( (uptr)x86Ptr + 5 )); - x86SetJ8(j8Ptr[0]); - //branch = 2; -} - -//////////////////////////////////////////////////// -void recBREAK( void ) { - MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (uptr)&cpuRegs.pc, pc ); - iFlushCall(FLUSH_EVERYTHING); - CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::BREAK ); - - CMP32ItoM((uptr)&cpuRegs.pc, pc); - j8Ptr[0] = JE8(0); - ADD32ItoM((uptr)&cpuRegs.cycle, eeScaleBlockCycles()); - RET(); - x86SetJ8(j8Ptr[0]); - //branch = 2; -} - -} } } // end namespace R5900::Dynarec::OpcodeImpl - -//////////////////////////////////////////////////// -void recClear( u32 Addr, u32 Size ) -{ - u32 i; - for(i = 0; i < Size; ++i, Addr+=4) { - REC_CLEARM(Addr); - } -} - -static const int EE_MIN_BLOCK_BYTES = 15; - -void recClearMem(BASEBLOCK* p) -{ - BASEBLOCKEX* pexblock; - BASEBLOCK* pstart; - int lastdelay; - - // necessary since recompiler doesn't call femms/emms -#ifdef _MSC_VER - if (cpucaps.has3DNOWInstructionExtensions) __asm femms; - else __asm emms; -#else - if( cpucaps.has3DNOWInstructionExtensions )__asm__("femms"); - else __asm__("emms"); -#endif - - assert( p != NULL ); - - if( p->uType & BLOCKTYPE_DELAYSLOT ) { - recClearMem(p-1); - if( p->GetFnptr() == 0 ) - return; - } - - assert( p->GetFnptr() != 0 ); - assert( p->startpc ); - - x86Ptr = (u8*)p->GetFnptr(); - - // there is a small problem: mem can be ored with 0xa<<28 or 0x8<<28, and don't know which - MOV32ItoR(EDX, p->startpc); - PUSH32I((u32)x86Ptr); // will be replaced by JMP32 - JMP32((u32)DispatcherClear - ( (u32)x86Ptr + 5 )); - assert( x86Ptr == (u8*)p->GetFnptr() + EE_MIN_BLOCK_BYTES ); - - pstart = PC_GETBLOCK(p->startpc); - pexblock = PC_GETBLOCKEX(pstart); - assert( pexblock->startpc == pstart->startpc ); - - if( pexblock->startpc != pstart->startpc ) { - // some bug with ffx after beating a big snake in sewers - RemoveBaseBlockEx(pexblock, 0); - pexblock->size = 0; - pexblock->startpc = 0; - return; - } - - // don't delete if last is delay - lastdelay = pexblock->size; - if( pstart[pexblock->size-1].uType & BLOCKTYPE_DELAYSLOT ) { - assert( pstart[pexblock->size-1].GetFnptr() != pstart->GetFnptr() ); - if( pstart[pexblock->size-1].GetFnptr() != 0 ) { - pstart[pexblock->size-1].uType = 0; - --lastdelay; - } - } - - memset(pstart, 0, lastdelay*sizeof(BASEBLOCK)); - - RemoveBaseBlockEx(pexblock, 0); - pexblock->size = 0; - pexblock->startpc = 0; -} - -void REC_CLEARM( u32 mem ) -{ - if ((mem) < maxrecmem && recLUT[(mem) >> 16]) { - BASEBLOCK* p = PC_GETBLOCK(mem); - if( *(u32*)p ) recClearMem(p); - } -} - -// check for end of bios -void CheckForBIOSEnd() -{ - MOV32MtoR(EAX, (int)&cpuRegs.pc); - - CMP32ItoR(EAX, 0x00200008); - j8Ptr[0] = JE8(0); - - CMP32ItoR(EAX, 0x00100008); - j8Ptr[1] = JE8(0); - - // return - j8Ptr[2] = JMP8(0); - - x86SetJ8( j8Ptr[0] ); - x86SetJ8( j8Ptr[1] ); - - // bios end - RET2(); - - x86SetJ8( j8Ptr[2] ); -} - -static int *s_pCode; - -void SetBranchReg( u32 reg ) -{ - branch = 1; - - if( reg != 0xffffffff ) { -// if( GPR_IS_CONST1(reg) ) -// MOV32ItoM( (uptr)&cpuRegs.pc, g_cpuConstRegs[reg].UL[0] ); -// else { -// int mmreg; -// -// if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, reg, MODE_READ)) >= 0 ) { -// SSE_MOVSS_XMM_to_M32((u32)&cpuRegs.pc, mmreg); -// } -// else if( (mmreg = _checkMMXreg(MMX_GPR+reg, MODE_READ)) >= 0 ) { -// MOVDMMXtoM((u32)&cpuRegs.pc, mmreg); -// SetMMXstate(); -// } -// else { -// MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ reg ].UL[ 0 ] ); -// MOV32RtoM((u32)&cpuRegs.pc, EAX); -// } -// } - _allocX86reg(ESI, X86TYPE_PCWRITEBACK, 0, MODE_WRITE); - _eeMoveGPRtoR(ESI, reg); - - recompileNextInstruction(1); - - if( x86regs[ESI].inuse ) { - assert( x86regs[ESI].type == X86TYPE_PCWRITEBACK ); - MOV32RtoM((int)&cpuRegs.pc, ESI); - x86regs[ESI].inuse = 0; - } - else { - MOV32MtoR(EAX, (u32)&g_recWriteback); - MOV32RtoM((int)&cpuRegs.pc, EAX); - } - } - -// CMP32ItoM((u32)&cpuRegs.pc, 0); -// j8Ptr[5] = JNE8(0); -// CALLFunc((uptr)tempfn); -// x86SetJ8( j8Ptr[5] ); - - iFlushCall(FLUSH_EVERYTHING); - - iBranchTest(0xffffffff); -} - -void SetBranchImm( u32 imm ) -{ - branch = 1; - - assert( imm ); - - // end the current block - MOV32ItoM( (uptr)&cpuRegs.pc, imm ); - iFlushCall(FLUSH_EVERYTHING); - - iBranchTest(imm); -} - -void SaveBranchState() -{ - s_savex86FpuState = x86FpuState; - s_saveiCWstate = iCWstate; - s_savenBlockCycles = s_nBlockCycles; - s_saveConstGPRreg = 0xffffffff; // indicate searching - s_saveHasConstReg = g_cpuHasConstReg; - s_saveFlushedConstReg = g_cpuFlushedConstReg; - s_psaveInstInfo = g_pCurInstInfo; - s_saveRegHasLive1 = g_cpuRegHasLive1; - s_saveRegHasSignExt = g_cpuRegHasSignExt; - - // save all mmx regs - memcpy_fast(s_saveMMXregs, mmxregs, sizeof(mmxregs)); - memcpy_fast(s_saveXMMregs, xmmregs, sizeof(xmmregs)); -} - -void LoadBranchState() -{ - x86FpuState = s_savex86FpuState; - iCWstate = s_saveiCWstate; - s_nBlockCycles = s_savenBlockCycles; - - if( s_saveConstGPRreg != 0xffffffff ) { - assert( s_saveConstGPRreg > 0 ); - - // make sure right GPR was saved - assert( g_cpuHasConstReg == s_saveHasConstReg || (g_cpuHasConstReg ^ s_saveHasConstReg) == (1<> 3; - - uint scalarLow, scalarMid, scalarHigh; - - // Note: larger blocks get a smaller scalar, to help keep - // them from becoming "too fat" and delaying branch tests. - - switch( CHECK_EE_CYCLERATE ) - { - case 0: return s_nBlockCycles >> 3; - - case 1: // Sync hack x1.5! - scalarLow = 5; - scalarMid = 7; - scalarHigh = 5; - break; - - case 2: // Sync hack x2 - scalarLow = 7; - scalarMid = 9; - scalarHigh = 7; - break; - - case 3: // Sync hack x3 - scalarLow = 10; - scalarMid = 19; - scalarHigh = 10; - break; - - jNO_DEFAULT - } - - s_nBlockCycles *= - (s_nBlockCycles <= (10<<3)) ? scalarLow : - ((s_nBlockCycles > (21<<3)) ? scalarHigh : scalarMid ); - - return s_nBlockCycles >> (3+2); -} - -// Generates dynarec code for Event tests followed by a block dispatch (branch). -// Parameters: -// newpc - address to jump to at the end of the block. If newpc == 0xffffffff then -// the jump is assumed to be to a register (dynamic). For any other value the -// jump is assumed to be static, in which case the block will be "hardlinked" after -// the first time it's dispatched. -// -// noDispatch - When set true, the jump to Dispatcher. Used by the recs -// for blocks which perform exception checks without branching (it's enabled by -// setting "branch = 2"; -static void iBranchTest(u32 newpc, bool noDispatch) -{ -#ifdef _DEBUG - //CALLFunc((uptr)testfpu); -#endif - u32* ptr; - - if( bExecBIOS ) CheckForBIOSEnd(); - - MOV32MtoR(EAX, (uptr)&cpuRegs.cycle); - if( !noDispatch && newpc != 0xffffffff ) - { - // Optimization note: Instructions order to pair EDX with EAX's load above. - - // Load EDX with the address of the JS32 jump below. - // We do this because the the Dispatcher will use this info to modify - // the JS instruction later on with the address of the block it's jumping - // to; creating a static link of blocks that doesn't require the overhead - // of a dispatcher. - MOV32ItoR(EDX, 0); - ptr = (u32*)(x86Ptr-4); - } - - // Check the Event scheduler if our "cycle target" has been reached. - // Equiv code to: - // cpuRegs.cycle += blockcycles; - // if( cpuRegs.cycle > g_nextBranchCycle ) { DoEvents(); } - ADD32ItoR(EAX, eeScaleBlockCycles()); - MOV32RtoM((uptr)&cpuRegs.cycle, EAX); // update cycles - SUB32MtoR(EAX, (uptr)&g_nextBranchCycle); - - if( newpc != 0xffffffff ) - { - // This is the jump instruction which gets modified by Dispatcher. - *ptr = (u32)JS32((u32)Dispatcher - ( (u32)x86Ptr + 6 )); - } - else if( !noDispatch ) - { - // This instruction is a dynamic link, so it's never modified. - JS32((uptr)DispatcherReg - ( (uptr)x86Ptr + 6 )); - } - - RET2(); -} - -static void checkcodefn() -{ - int pctemp; - -#ifdef _MSC_VER - __asm mov pctemp, eax; -#else - __asm__("movl %%eax, %0" : "=m"(pctemp) ); -#endif - - Console::Error("code changed! %x", params pctemp); - assert(0); -} - -//#ifdef _DEBUG -//#define CHECK_XMMCHANGED() CALLFunc((uptr)checkxmmchanged); -//#else -//#define CHECK_XMMCHANGED() -//#endif -// -//static void checkxmmchanged() -//{ -// assert( !g_globalMMXSaved ); -// assert( !g_globalXMMSaved ); -//} - -u32 recompileCodeSafe(u32 temppc) -{ - BASEBLOCK* pblock = PC_GETBLOCK(temppc); - - if( pblock->GetFnptr() != 0 && pblock->startpc != s_pCurBlock->startpc ) { - if( pc == pblock->startpc ) - return 0; - } - - return 1; -} - -void recompileNextInstruction(int delayslot) -{ - static u8 s_bFlushReg = 1; - int i, count; - - BASEBLOCK* pblock = PC_GETBLOCK(pc); - - // need *ppblock != s_pCurBlock because of branches - if( pblock->GetFnptr() != 0 && pblock->startpc != s_pCurBlock->startpc ) { - - if( !delayslot && pc == pblock->startpc ) { - // code already in place, so jump to it and exit recomp - assert( PC_GETBLOCKEX(pblock)->startpc == pblock->startpc ); - - iFlushCall(FLUSH_EVERYTHING); - MOV32ItoM((uptr)&cpuRegs.pc, pc); - -// if( pexblock->pOldFnptr ) { -// // code already in place, so jump to it and exit recomp -// JMP32((u32)pexblock->pOldFnptr - ((u32)x86Ptr + 5)); -// branch = 3; -// return; -// } - - JMP32((uptr)pblock->GetFnptr() - ((uptr)x86Ptr + 5)); - branch = 3; - return; - } - else { - - if( !(delayslot && pblock->startpc == pc) ) { - u8* oldX86 = x86Ptr; - //__Log("clear block %x\n", pblock->startpc); - recClearMem(pblock); - x86Ptr = oldX86; - if( delayslot ) - Console::Notice("delay slot %x", params pc); - } - } - } - - if( delayslot ) - pblock->uType = BLOCKTYPE_DELAYSLOT; - - s_pCode = (int *)PSM( pc ); - assert(s_pCode); - -#ifdef _DEBUG - MOV32ItoR(EAX, pc); -#endif - - cpuRegs.code = *(int *)s_pCode; - pc += 4; - -//#ifdef _DEBUG -// CMP32ItoM((u32)s_pCode, cpuRegs.code); -// j8Ptr[0] = JE8(0); -// MOV32ItoR(EAX, pc); -// CALLFunc((uptr)checkcodefn); -// x86SetJ8( j8Ptr[ 0 ] ); -// -// if( !delayslot ) { -// CMP32ItoM((u32)&cpuRegs.pc, s_pCurBlockEx->startpc); -// j8Ptr[0] = JB8(0); -// CMP32ItoM((u32)&cpuRegs.pc, pc); -// j8Ptr[1] = JA8(0); -// j8Ptr[2] = JMP8(0); -// x86SetJ8( j8Ptr[ 0 ] ); -// x86SetJ8( j8Ptr[ 1 ] ); -// PUSH32I(s_pCurBlockEx->startpc); -// ADD32ItoR(ESP, 4); -// x86SetJ8( j8Ptr[ 2 ] ); -// } -//#endif - - g_pCurInstInfo++; - - // reorder register priorities -// for(i = 0; i < X86REGS; ++i) { -// if( x86regs[i].inuse ) { -// if( count > 0 ) mmxregs[i].counter = 1000-count; -// else mmxregs[i].counter = 0; -// } -// } - - for(i = 0; i < MMXREGS; ++i) { - if( mmxregs[i].inuse ) { - assert( MMX_ISGPR(mmxregs[i].reg) ); - count = _recIsRegWritten(g_pCurInstInfo, (s_nEndBlock-pc)/4 + 1, XMMTYPE_GPRREG, mmxregs[i].reg-MMX_GPR); - if( count > 0 ) mmxregs[i].counter = 1000-count; - else mmxregs[i].counter = 0; - } - } - - for(i = 0; i < XMMREGS; ++i) { - if( xmmregs[i].inuse ) { - count = _recIsRegWritten(g_pCurInstInfo, (s_nEndBlock-pc)/4 + 1, xmmregs[i].type, xmmregs[i].reg); - if( count > 0 ) xmmregs[i].counter = 1000-count; - else xmmregs[i].counter = 0; - } - } - - const OPCODE& opcode = GetCurrentInstruction(); - - // peephole optimizations -#ifdef PCSX2_VM_COISSUE - if( g_pCurInstInfo->info & EEINSTINFO_COREC ) { - - if( g_pCurInstInfo->numpeeps > 1 ) { - switch(_Opcode_) { - case 30: recLQ_coX(g_pCurInstInfo->numpeeps); break; - case 31: recSQ_coX(g_pCurInstInfo->numpeeps); break; - case 49: recLWC1_coX(g_pCurInstInfo->numpeeps); break; - case 57: recSWC1_coX(g_pCurInstInfo->numpeeps); break; - case 55: recLD_coX(g_pCurInstInfo->numpeeps); break; - case 63: recSD_coX(g_pCurInstInfo->numpeeps, 1); break; //not sure if should be set to 1 or 0; looks like "1" handles alignment, so i'm going with that for now - - jNO_DEFAULT - } - pc += g_pCurInstInfo->numpeeps*4; - s_nBlockCycles += (g_pCurInstInfo->numpeeps+1) * opcode.cycles; - g_pCurInstInfo += g_pCurInstInfo->numpeeps; - } - else { - recBSC_co[_Opcode_](); - pc += 4; - g_pCurInstInfo++; - s_nBlockCycles += opcode.cycles*2; - } - } - else -#endif - { - //assert( !(g_pCurInstInfo->info & EEINSTINFO_NOREC) ); - - // if this instruction is a jump or a branch, exit right away - if( delayslot ) { - switch(_Opcode_) { - case 1: - switch(_Rt_) { - case 0: case 1: case 2: case 3: case 0x10: case 0x11: case 0x12: case 0x13: - Console::Notice("branch %x in delay slot!", params cpuRegs.code); - _clearNeededX86regs(); - _clearNeededMMXregs(); - _clearNeededXMMregs(); - return; - } - break; - - case 2: case 3: case 4: case 5: case 6: case 7: case 0x14: case 0x15: case 0x16: case 0x17: - Console::Notice("branch %x in delay slot!", params cpuRegs.code); - _clearNeededX86regs(); - _clearNeededMMXregs(); - _clearNeededXMMregs(); - return; - } - } - opcode.recompile(); - s_nBlockCycles += opcode.cycles; - } - - if( !delayslot ) { - if( s_bFlushReg ) { - //if( !_flushUnusedConstReg() ) { - int flushed = 0; - if( _getNumMMXwrite() > 3 ) flushed = _flushMMXunused(); - if( !flushed && _getNumXMMwrite() > 2 ) _flushXMMunused(); - s_bFlushReg = !flushed; -// } -// else s_bFlushReg = 0; - } - else s_bFlushReg = 1; - } - else s_bFlushReg = 1; - - //CHECK_XMMCHANGED(); - _clearNeededX86regs(); - _clearNeededMMXregs(); - _clearNeededXMMregs(); - -// _freeXMMregs(); -// _freeMMXregs(); -// _flushCachedRegs(); -// g_cpuHasConstReg = 1; -} - -extern u32 psxdump; - -static void printfn() -{ - static int lastrec = 0; - static int curcount = 0; - const int skip = 0; - - assert( !g_globalMMXSaved ); - assert( !g_globalXMMSaved ); - - if( (dumplog&2) && g_lastpc != 0x81fc0 ) {//&& lastrec != g_lastpc ) { - curcount++; - - if( curcount > skip ) { - iDumpRegisters(g_lastpc, 1); - curcount = 0; - } - - lastrec = g_lastpc; - } -} - -u32 s_recblocks[] = {0}; - -void badespfn() { - Console::Error("Bad esp!"); - assert(0); -} - -void __fastcall dyna_block_discard(u32 start,u32 sz) -{ - Console::WriteLn("dyna_block_discard %08X , count %d", params start,sz); - Cpu->Clear(start,sz); -} - -void recRecompile( const u32 startpc ) -{ - u32 i = 0; - u32 branchTo; - u32 willbranch3 = 0; - u32* ptr; - u32 usecop2; - -#ifdef _DEBUG - //dumplog |= 4; - if( dumplog & 4 ) - iDumpRegisters(startpc, 0); -#endif - - assert( startpc ); - - // if recPtr reached the mem limit reset whole mem - if ( ( (uptr)recPtr - (uptr)recMem ) >= REC_CACHEMEM-0x40000 || dumplog == 0xffffffff) { - DevCon::WriteLn( "EE Recompiler data reset" ); - recResetEE(); - } - if ( ( (uptr)recStackPtr - (uptr)recStack ) >= RECSTACK_SIZE-0x100 ) { - DevCon::WriteLn("EE recompiler stack reset"); - recResetEE(); - } - - s_pCurBlock = PC_GETBLOCK(startpc); - - if( s_pCurBlock->GetFnptr() ) { - // clear if already taken - assert( s_pCurBlock->startpc < startpc ); - recClearMem(s_pCurBlock); - } - - if( s_pCurBlock->startpc == startpc ) { - s_pCurBlockEx = PC_GETBLOCKEX(s_pCurBlock); - assert( s_pCurBlockEx->startpc == startpc ); - } - else { - s_pCurBlockEx = NULL; - for(i = 0; i < EE_NUMBLOCKS; ++i) { - if( recBlocks[(i+s_nNextBlock)%EE_NUMBLOCKS].size == 0 ) { - s_pCurBlockEx = recBlocks+(i+s_nNextBlock)%EE_NUMBLOCKS; - s_nNextBlock = (i+s_nNextBlock+1)%EE_NUMBLOCKS; - break; - } - } - - if( s_pCurBlockEx == NULL ) { - //SysPrintf("ee reset (blocks)\n"); - recResetEE(); - s_nNextBlock = 0; - s_pCurBlockEx = recBlocks; - } - - s_pCurBlockEx->startpc = startpc; - } - - x86SetPtr( recPtr ); - x86Align(16); - recPtr = x86Ptr; - s_pCurBlock->SetFnptr( (uptr)x86Ptr ); - s_pCurBlock->startpc = startpc; - - branch = 0; - - // reset recomp state variables - s_nBlockCycles = 0; - pc = startpc; - x86FpuState = FPU_STATE; - iCWstate = 0; - s_saveConstGPRreg = 0; - g_cpuHasConstReg = g_cpuFlushedConstReg = 1; - g_cpuPrevRegHasLive1 = g_cpuRegHasLive1 = 0xffffffff; - g_cpuPrevRegHasSignExt = g_cpuRegHasSignExt = 0; - assert( g_cpuConstRegs[0].UD[0] == 0 ); - - _initX86regs(); - _initXMMregs(); - _initMMXregs(); - -#ifdef _DEBUG - // for debugging purposes - MOV32ItoM((uptr)&g_lastpc, pc); - CALLFunc((uptr)printfn); - -// CMP32MtoR(EBP, (uptr)&s_uSaveEBP); -// j8Ptr[0] = JE8(0); -// CALLFunc((uptr)badespfn); -// x86SetJ8(j8Ptr[0]); -#endif - - // go until the next branch - i = startpc; - s_nEndBlock = 0xffffffff; - s_nHasDelay = 0; - - while(1) { - BASEBLOCK* pblock = PC_GETBLOCK(i); - if( pblock->GetFnptr() != 0 && pblock->startpc != s_pCurBlock->startpc ) { - - if( i == pblock->startpc ) { - // branch = 3 - willbranch3 = 1; - s_nEndBlock = i; - break; - } - } - //HUH ? PSM ? whut ? THIS IS VIRTUAL ACCESS GOD DAMMIT - cpuRegs.code = *(int *)PSM(i); - - switch(cpuRegs.code >> 26) { - case 0: // special - - if( _Funct_ == 8 || _Funct_ == 9 ) { // JR, JALR - s_nEndBlock = i + 8; - s_nHasDelay = 1; - goto StartRecomp; - } - - break; - case 1: // regimm - - if( _Rt_ < 4 || (_Rt_ >= 16 && _Rt_ < 20) ) { - // branches - if( _Rt_ == 2 || _Rt_ == 3 || _Rt_ == 18 || _Rt_ == 19 ) s_nHasDelay = 1; - else s_nHasDelay = 2; - - branchTo = _Imm_ * 4 + i + 4; - if( branchTo > startpc && branchTo < i ) s_nEndBlock = branchTo; - else s_nEndBlock = i+8; - - goto StartRecomp; - } - - break; - - case 2: // J - case 3: // JAL - s_nHasDelay = 1; - s_nEndBlock = i + 8; - goto StartRecomp; - - // branches - case 4: case 5: case 6: case 7: - case 20: case 21: case 22: case 23: - - if( (cpuRegs.code >> 26) >= 20 ) s_nHasDelay = 1; - else s_nHasDelay = 2; - - branchTo = _Imm_ * 4 + i + 4; - if( branchTo > startpc && branchTo < i ) s_nEndBlock = branchTo; - else s_nEndBlock = i+8; - - goto StartRecomp; - - case 16: // cp0 - if( _Rs_ == 16 ) { - if( _Funct_ == 24 ) { // eret - s_nEndBlock = i+4; - goto StartRecomp; - } - } - // Fall through! - // COP0's branch opcodes line up with COP1 and COP2's - - case 17: // cp1 - case 18: // cp2 - if( _Rs_ == 8 ) { - // BC1F, BC1T, BC1FL, BC1TL - // BC2F, BC2T, BC2FL, BC2TL - if( _Rt_ >= 2 ) s_nHasDelay = 1; - else s_nHasDelay = 2; - - branchTo = _Imm_ * 4 + i + 4; - if( branchTo > startpc && branchTo < i ) s_nEndBlock = branchTo; - else s_nEndBlock = i+8; - - goto StartRecomp; - } - break; - } - - i += 4; - } - -StartRecomp: - - // rec info // - { - EEINST* pcur; - - if( s_nInstCacheSize < (s_nEndBlock-startpc)/4+1 ) { - free(s_pInstCache); - s_nInstCacheSize = (s_nEndBlock-startpc)/4+10; - s_pInstCache = (EEINST*)malloc(sizeof(EEINST)*s_nInstCacheSize); - assert( s_pInstCache != NULL ); - } - - pcur = s_pInstCache + (s_nEndBlock-startpc)/4; - _recClearInst(pcur); - pcur->info = 0; - - for(i = s_nEndBlock; i > startpc; i -= 4 ) { - cpuRegs.code = *(int *)PSM(i-4); - pcur[-1] = pcur[0]; - - BSCPropagate bsc( pcur[-1], pcur[0] ); - bsc.rprop(); - pcur--; - } - } - - // analyze instructions // - { - usecop2 = 0; - g_pCurInstInfo = s_pInstCache; - - for(i = startpc; i < s_nEndBlock; i += 4) { - g_pCurInstInfo++; - cpuRegs.code = *(u32*)PSM(i); - - // cop2 // - if( g_pCurInstInfo->info & EEINSTINFO_COP2 ) { - - if( !usecop2 ) { - // init - vucycle = 0; - usecop2 = 1; - } - - VU0.code = cpuRegs.code; - _vuRegsCOP22( &VU0, &g_pCurInstInfo->vuregs ); - continue; - } - - // fixme - This should be based on the cycle count of the current EE - // instruction being analyzed. - if( usecop2 ) vucycle++; - - // peephole optimizations // -#ifdef PCSX2_VM_COISSUE - if( i < s_nEndBlock-4 && recompileCodeSafe(i) ) { - u32 curcode = cpuRegs.code; - u32 nextcode = *(u32*)PSM(i+4); - if( _eeIsLoadStoreCoIssue(curcode, nextcode) && recBSC_co[curcode>>26] != NULL ) { - - // rs has to be the same, and cannot be just written - if( ((curcode >> 21) & 0x1F) == ((nextcode >> 21) & 0x1F) && !_eeLoadWritesRs(curcode) ) { - - if( _eeIsLoadStoreCoX(curcode) && ((nextcode>>16)&0x1f) != ((curcode>>21)&0x1f) ) { - // see how many stores there are - u32 j; - // use xmmregs since only supporting lwc1,lq,swc1,sq - for(j = i+8; j < s_nEndBlock && j < i+4*XMMREGS; j += 4 ) { - u32 nncode = *(u32*)PSM(j); - if( (nncode>>26) != (curcode>>26) || ((curcode>>21)&0x1f) != ((nncode>>21)&0x1f) || - _eeLoadWritesRs(nncode)) - break; - } - - if( j > i+8 ) { - u32 num = (j-i)>>2; // number of stores that can coissue - assert( num <= XMMREGS ); - - g_pCurInstInfo[0].numpeeps = num-1; - g_pCurInstInfo[0].info |= EEINSTINFO_COREC; - - while(i < j-4) { - g_pCurInstInfo++; - g_pCurInstInfo[0].info |= EEINSTINFO_NOREC; - i += 4; - } - - continue; - } - - // fall through - } - - // unaligned loadstores - - // if LWL, check if LWR and that offsets are +3 away - switch(curcode >> 26) { - case 0x22: // LWL - if( (nextcode>>26) != 0x26 || ((s16)nextcode)+3 != (s16)curcode ) - continue; - break; - case 0x26: // LWR - if( (nextcode>>26) != 0x22 || ((s16)nextcode) != (s16)curcode+3 ) - continue; - break; - - case 0x2a: // SWL - if( (nextcode>>26) != 0x2e || ((s16)nextcode)+3 != (s16)curcode ) - continue; - break; - case 0x2e: // SWR - if( (nextcode>>26) != 0x2a || ((s16)nextcode) != (s16)curcode+3 ) - continue; - break; - - case 0x1a: // LDL - if( (nextcode>>26) != 0x1b || ((s16)nextcode)+7 != (s16)curcode ) - continue; - break; - case 0x1b: // LWR - if( (nextcode>>26) != 0x1aa || ((s16)nextcode) != (s16)curcode+7 ) - continue; - break; - - case 0x2c: // SWL - if( (nextcode>>26) != 0x2d || ((s16)nextcode)+7 != (s16)curcode ) - continue; - break; - case 0x2d: // SWR - if( (nextcode>>26) != 0x2c || ((s16)nextcode) != (s16)curcode+7 ) - continue; - break; - } - - // good enough - g_pCurInstInfo[0].info |= EEINSTINFO_COREC; - g_pCurInstInfo[0].numpeeps = 1; - g_pCurInstInfo[1].info |= EEINSTINFO_NOREC; - g_pCurInstInfo++; - i += 4; - continue; - } - } - } -#endif // end peephole - } - // This *is* important because g_pCurInstInfo is checked a bit later on and - // if it's not equal to s_pInstCache it handles recompilation differently. - // ... but the empty if() conditional inside the for loop is still amusing. >_< - if( usecop2 ) { - // add necessary mac writebacks - g_pCurInstInfo = s_pInstCache; - - for(i = startpc; i < s_nEndBlock-4; i += 4) { - g_pCurInstInfo++; - - if( g_pCurInstInfo->info & EEINSTINFO_COP2 ) { - } - } - } - } - -#ifdef _DEBUG - // dump code - for(i = 0; i < ARRAYSIZE(s_recblocks); ++i) { - if( startpc == s_recblocks[i] ) { - iDumpBlock(startpc, recPtr); - } - } - - if( (dumplog & 1) ) //|| usecop2 ) - iDumpBlock(startpc, recPtr); -#endif - - u32 sz=(s_nEndBlock-startpc)>>2; -#ifdef lulz - /* - Block checking (ADDED BY RAZ-TEMP) - */ - - MOV32ItoR(ECX,startpc); - MOV32ItoR(EDX,sz); - -#endif - - u32 inpage_offs=startpc&0xFFF; - u32 inpage_ptr=startpc; - u32 inpage_sz=sz*4; - - MOV32ItoR(ECX,startpc); - MOV32ItoR(EDX,sz); - - while(inpage_sz) - { - int PageType=mmap_GetRamPageInfo((u32*)PSM(inpage_ptr)); - u32 pgsz=std::min(0x1000-inpage_offs,inpage_sz); - - if(PageType!=-1) - { - if (PageType==0) - { - //MOV32ItoR(EAX,*pageVer); - //CMP32MtoR(EAX,(uptr)pageVer); - //JNE32(((u32)dyna_block_discard_recmem)- ( (u32)x86Ptr + 6 )); - - mmap_MarkCountedRamPage(PSM(inpage_ptr),inpage_ptr&~0xFFF); - } - else - { - u32 lpc=inpage_ptr; - u32 stg=pgsz; - while(stg>0) - { - // was dyna_block_discard_recmem. See note in recResetEE for details. - CMP32ItoM((uptr)PSM(lpc),*(u32*)PSM(lpc)); - JNE32(((u32)&dyna_block_discard)- ( (u32)x86Ptr + 6 )); - - stg-=4; - lpc+=4; - } - DbgCon::WriteLn("Manual block @ %08X : %08X %d %d %d %d", params - startpc,inpage_ptr,pgsz,0x1000-inpage_offs,inpage_sz,sz*4); - } - } - inpage_ptr+=pgsz; - inpage_sz-=pgsz; - inpage_offs=inpage_ptr&0xFFF; - } - - // finally recompile // - g_pCurInstInfo = s_pInstCache; - while (!branch && pc < s_nEndBlock) { - recompileNextInstruction(0); - } - -#ifdef _DEBUG - if( (dumplog & 1) ) - iDumpBlock(startpc, recPtr); -#endif - - assert( (pc-startpc)>>2 <= 0xffff ); - s_pCurBlockEx->size = (pc-startpc)>>2; - - for(i = 1; i < (u32)s_pCurBlockEx->size-1; ++i) { - s_pCurBlock[i].SetFnptr( s_pCurBlock->GetFnptr() ); - s_pCurBlock[i].startpc = s_pCurBlock->startpc; - } - - // don't overwrite if delay slot - if( i < (u32)s_pCurBlockEx->size && !(s_pCurBlock[i].uType & BLOCKTYPE_DELAYSLOT) ) { - s_pCurBlock[i].SetFnptr( s_pCurBlock->GetFnptr() ); - s_pCurBlock[i].startpc = s_pCurBlock->startpc; - } - - // set the block ptr - AddBaseBlockEx(s_pCurBlockEx, 0); -// if( p[1].startpc == p[0].startpc + 4 ) { -// assert( p[1].GetFnptr() != 0 ); -// // already fn in place, so add to list -// AddBaseBlockEx(s_pCurBlockEx, 0); -// } -// else -// *(BASEBLOCKEX**)(p+1) = pex; -// } - - //PC_SETBLOCKEX(s_pCurBlock, s_pCurBlockEx); - - if( !(pc&0x10000000) ) - maxrecmem = std::max( (pc&~0xa0000000), maxrecmem ); - - if( branch == 2 ) - { - // Branch type 2 - This is how I "think" this works (air): - // Performs a branch/event test but does not actually "break" the block. - // This allows exceptions to be raised, and is thus sufficient for - // certain types of things like SYSCALL, EI, etc. but it is not sufficient - // for actual branching instructions. - - iFlushCall(FLUSH_EVERYTHING); - iBranchTest(0xffffffff, true); - } - else - { - assert( branch != 3 ); - if( branch ) - assert( !willbranch3 ); - else - ADD32ItoM((int)&cpuRegs.cycle, eeScaleBlockCycles() ); - - if( willbranch3 ) { - BASEBLOCK* pblock = PC_GETBLOCK(s_nEndBlock); - assert( pc == s_nEndBlock ); - iFlushCall(FLUSH_EVERYTHING); - MOV32ItoM((uptr)&cpuRegs.pc, pc); - JMP32((uptr)pblock->GetFnptr() - ((uptr)x86Ptr + 5)); - branch = 3; - } - else if( !branch ) { - // didn't branch, but had to stop - MOV32ItoM( (uptr)&cpuRegs.pc, pc ); - - iFlushCall(FLUSH_EVERYTHING); - - ptr = JMP32(0); - } - } - - assert( x86Ptr >= (u8*)s_pCurBlock->GetFnptr() + EE_MIN_BLOCK_BYTES ); - assert( x86Ptr < recMem+REC_CACHEMEM ); - assert( recStackPtr < recStack+RECSTACK_SIZE ); - assert( x86FpuState == 0 ); - - recPtr = x86Ptr; - - assert( (g_cpuHasConstReg&g_cpuFlushedConstReg) == g_cpuHasConstReg ); - - if( !branch ) { - BASEBLOCK* pcurblock = s_pCurBlock; - u32 nEndBlock = s_nEndBlock; - s_pCurBlock = PC_GETBLOCK(pc); - assert( ptr != NULL ); - - if( s_pCurBlock->startpc != pc ) - recRecompile(pc); - - if( pcurblock->startpc == startpc ) { - assert( pcurblock->GetFnptr() ); - assert( s_pCurBlock->startpc == nEndBlock ); - *ptr = s_pCurBlock->GetFnptr() - ( (u32)ptr + 4 ); - } - else { - recRecompile(startpc); - assert( pcurblock->GetFnptr() != 0 ); - } - } -} - -R5900cpu recCpu = { - recAlloc, - recResetEE, - recStep, - recExecute, - recExecuteBlock, - recClear, - recShutdown -}; +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "Memory.h" +#include "R5900OpcodeTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "iR5900AritImm.h" +#include "iR5900Arit.h" +#include "iR5900MultDiv.h" +#include "iR5900Shift.h" +#include "iR5900Branch.h" +#include "iR5900Jump.h" +#include "iR5900LoadStore.h" +#include "iR5900Move.h" +#include "iMMI.h" +#include "iFPU.h" +#include "iCOP0.h" +#include "iVUmicro.h" +#include "VU.h" +#include "VUmicro.h" + +#include "iVUzerorec.h" +#include "vtlb.h" + +#include "SamplProf.h" + +using namespace R5900; + +// used to disable register freezing during cpuBranchTests (registers +// are safe then since they've been completely flushed) +bool g_EEFreezeRegs = false; + +// I can't find where the Linux recRecompile is defined. Is it used anymore? +// If so, namespacing might break it. :/ (air) +#ifdef __LINUX__ +extern "C" { +#endif +void recRecompile( u32 startpc ); +#ifdef __LINUX__ +} +#endif + +u32 maxrecmem = 0; +uptr *recLUT = NULL; + +u32 s_nBlockCycles = 0; // cycles of current block recompiling +//u8* dyna_block_discard_recmem=0; + +u32 pc; // recompiler pc +int branch; // set for branch + +PCSX2_ALIGNED16(GPR_reg64 g_cpuConstRegs[32]) = {0}; +u32 g_cpuHasConstReg = 0, g_cpuFlushedConstReg = 0; +u32 s_saveConstGPRreg = 0; +GPR_reg64 s_ConstGPRreg; + +//////////////////////////////////////////////////////////////// +// Static Private Variables - R5900 Dynarec + +#define X86 +static const int RECSTACK_SIZE = 0x00010000; +static const int EE_NUMBLOCKS = (1<<15); + +static u8 *recMem = NULL; // the recompiled blocks will be here +static u8* recStack = NULL; // stack mem +static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here +static BASEBLOCK *recROM = NULL; // and here +static BASEBLOCK *recROM1 = NULL; // also here +static BASEBLOCKEX *recBlocks = NULL; +static u8* recPtr = NULL, *recStackPtr = NULL; +static EEINST* s_pInstCache = NULL; +static u32 s_nInstCacheSize = 0; + +static BASEBLOCK* s_pCurBlock = NULL; +static BASEBLOCKEX* s_pCurBlockEx = NULL; +const BASEBLOCK* s_pDispatchBlock = NULL; +static u32 s_nEndBlock = 0; // what pc the current block ends +static u32 s_nHasDelay = 0; + +static u32 s_nNextBlock = 0; // next free block in recBlocks + +// save states for branches +static u16 s_savex86FpuState, s_saveiCWstate; +static u32 s_saveHasConstReg = 0, s_saveFlushedConstReg = 0, s_saveRegHasLive1 = 0, s_saveRegHasSignExt = 0; +static EEINST* s_psaveInstInfo = NULL; + +static u32 s_savenBlockCycles = 0; + +#ifdef _DEBUG +static u32 dumplog = 0; +#else +#define dumplog 0 +#endif + +#ifdef PCSX2_DEVBUILD +// and not sure what these might have once been used for... (air) +//static const char *txt0 = "EAX = %x : ECX = %x : EDX = %x\n"; +//static const char *txt0RC = "EAX = %x : EBX = %x : ECX = %x : EDX = %x : ESI = %x : EDI = %x\n"; +//static const char *txt1 = "REG[%d] = %x_%x\n"; +//static const char *txt2 = "M32 = %x\n"; +#endif + +static void iBranchTest(u32 newpc, bool noDispatch=false); + +BASEBLOCKEX* PC_GETBLOCKEX(BASEBLOCK* p) +{ +// BASEBLOCKEX* pex = *(BASEBLOCKEX**)(p+1); +// if( pex >= recBlocks && pex < recBlocks+EE_NUMBLOCKS ) +// return pex; + + // otherwise, use the sorted list + return GetBaseBlockEx(p->startpc, 0); +} + +//////////////////////////////////////////////////// +static void iDumpBlock( int startpc, u8 * ptr ) +{ + FILE *f; + char filename[ g_MaxPath ]; + u32 i, j; + EEINST* pcur; + u8 used[34]; + u8 fpuused[33]; + int numused, count, fpunumused; + + Console::Status( "dump1 %x:%x, %x", params startpc, pc, cpuRegs.cycle ); +#ifdef _WIN32 + CreateDirectory("dumps", NULL); + sprintf_s( filename, g_MaxPath, "dumps\\dump%.8X.txt", startpc); +#else + mkdir("dumps", 0755); + sprintf( filename, "dumps/dump%.8X.txt", startpc); +#endif + + fflush( stdout ); +// f = fopen( "dump1", "wb" ); +// fwrite( ptr, 1, (u32)x86Ptr - (u32)ptr, f ); +// fclose( f ); +// +// sprintf( command, "objdump -D --target=binary --architecture=i386 dump1 > %s", filename ); +// system( command ); + + f = fopen( filename, "w" ); + + std::string output; + + if( disR5900GetSym(startpc) != NULL ) + fprintf(f, "%s\n", disR5900GetSym(startpc)); + for ( i = startpc; i < s_nEndBlock; i += 4 ) { + disR5900Fasm( output, PSMu32( i ), i ); + fprintf( f, output.c_str() ); + } + + // write the instruction info + + fprintf(f, "\n\nlive0 - %x, live1 - %x, live2 - %x, lastuse - %x\nmmx - %x, xmm - %x, used - %x\n", + EEINST_LIVE0, EEINST_LIVE1, EEINST_LIVE2, EEINST_LASTUSE, EEINST_MMX, EEINST_XMM, EEINST_USED); + + memzero_obj(used); + numused = 0; + for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { + if( s_pInstCache->regs[i] & EEINST_USED ) { + used[i] = 1; + numused++; + } + } + + memzero_obj(fpuused); + fpunumused = 0; + for(i = 0; i < ARRAYSIZE(s_pInstCache->fpuregs); ++i) { + if( s_pInstCache->fpuregs[i] & EEINST_USED ) { + fpuused[i] = 1; + fpunumused++; + } + } + + fprintf(f, " "); + for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { + if( used[i] ) fprintf(f, "%2d ", i); + } + for(i = 0; i < ARRAYSIZE(s_pInstCache->fpuregs); ++i) { + if( fpuused[i] ) fprintf(f, "%2d ", i); + } + fprintf(f, "\n"); + + fprintf(f, " "); + for(i = 0; i < ARRAYSIZE(s_pInstCache->regs); ++i) { + if( used[i] ) fprintf(f, "%s ", disRNameGPR[i]); + } + for(i = 0; i < ARRAYSIZE(s_pInstCache->fpuregs); ++i) { + if( fpuused[i] ) fprintf(f, "%s ", i<32?"FR":"FA"); + } + fprintf(f, "\n"); + + pcur = s_pInstCache+1; + for( i = 0; i < (s_nEndBlock-startpc)/4; ++i, ++pcur) { + fprintf(f, "%2d: %2.2x ", i+1, pcur->info); + + count = 1; + for(j = 0; j < ARRAYSIZE(s_pInstCache->regs); j++) { + if( used[j] ) { + fprintf(f, "%2.2x%s", pcur->regs[j], ((count%8)&&countfpuregs); j++) { + if( fpuused[j] ) { + fprintf(f, "%2.2x%s", pcur->fpuregs[j], ((count%8)&&count>26) { + case 26: // ldl + case 27: // ldr + case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: + case 55: // LD + case 30: // lq + return ((tempcode>>21)&0x1f)==((tempcode>>16)&0x1f); // rs==rt + } + return 0; +} + +static u8 _eeIsLoadStoreCoIssue(u32 firstcode, u32 secondcode) +{ + switch(firstcode>>26) { + case 34: // lwl + return (secondcode>>26)==38; + case 38: // lwr + return (secondcode>>26)==34; + case 42: // swl + return (secondcode>>26)==46; + case 46: // swr + return (secondcode>>26)==42; + case 26: // ldl + return (secondcode>>26)==27; + case 27: // ldr + return (secondcode>>26)==26; + case 44: // sdl + return (secondcode>>26)==45; + case 45: // sdr + return (secondcode>>26)==44; + + case 32: case 33: case 35: case 36: case 37: case 39: + case 55: // LD + + // stores + case 40: case 41: case 43: + case 63: // sd + return (secondcode>>26)==(firstcode>>26); + + case 30: // lq + case 31: // sq + case 49: // lwc1 + case 57: // swc1 + case 54: // lqc2 + case 62: // sqc2 + return (secondcode>>26)==(firstcode>>26); + } + return 0; +} + +static u8 _eeIsLoadStoreCoX(u32 tempcode) +{ + switch( tempcode>>26 ) { + case 30: case 31: case 49: case 57: case 55: case 63: + return 1; + } + return 0; +} + +void _eeFlushAllUnused() +{ + int i; + for(i = 0; i < 34; ++i) { + if( pc < s_nEndBlock ) { + if( (g_pCurInstInfo[1].regs[i]&EEINST_USED) ) + continue; + } + else if( (g_pCurInstInfo[0].regs[i]&EEINST_USED) ) + continue; + + if( i < 32 && GPR_IS_CONST1(i) ) _flushConstReg(i); + else { + _deleteMMXreg(MMX_GPR+i, 1); + _deleteGPRtoXMMreg(i, 1); + } + } + + //TODO when used info is done for FPU and VU0 + for(i = 0; i < XMMREGS; ++i) { + if( xmmregs[i].inuse && xmmregs[i].type != XMMTYPE_GPRREG ) + _freeXMMreg(i); + } +} + +u32* _eeGetConstReg(int reg) +{ + assert( GPR_IS_CONST1( reg ) ); + + if( g_cpuFlushedConstReg & (1<= 0 && (xmmregs[mmreg].mode&MODE_WRITE)) { + SSE2_MOVD_XMM_to_R(to, mmreg); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+fromgpr, MODE_READ)) >= 0 && (mmxregs[mmreg].mode&MODE_WRITE) ) { + MOVD32MMXtoR(to, mmreg); + SetMMXstate(); + } + else { + MOV32MtoR(to, (int)&cpuRegs.GPR.r[ fromgpr ].UL[ 0 ] ); + } + } +} + +void _eeMoveGPRtoM(u32 to, int fromgpr) +{ + if( GPR_IS_CONST1(fromgpr) ) + MOV32ItoM( to, g_cpuConstRegs[fromgpr].UL[0] ); + else { + int mmreg; + + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, fromgpr, MODE_READ)) >= 0 ) { + SSEX_MOVD_XMM_to_M32(to, mmreg); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+fromgpr, MODE_READ)) >= 0 ) { + MOVDMMXtoM(to, mmreg); + SetMMXstate(); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ fromgpr ].UL[ 0 ] ); + MOV32RtoM(to, EAX ); + } + } +} + +void _eeMoveGPRtoRm(x86IntRegType to, int fromgpr) +{ + if( GPR_IS_CONST1(fromgpr) ) + MOV32ItoRmOffset( to, g_cpuConstRegs[fromgpr].UL[0], 0 ); + else { + int mmreg; + + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, fromgpr, MODE_READ)) >= 0 ) { + SSEX_MOVD_XMM_to_Rm(to, mmreg); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+fromgpr, MODE_READ)) >= 0 ) { + MOVD32MMXtoRm(to, mmreg); + SetMMXstate(); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ fromgpr ].UL[ 0 ] ); + MOV32RtoRm(to, EAX ); + } + } +} + +int _flushXMMunused() +{ + int i; + for (i=0; iregs[xmmregs[i].reg]&EEINST_USED) ) { + if( !_recIsRegWritten(g_pCurInstInfo+1, (s_nEndBlock-pc)/4, XMMTYPE_GPRREG, xmmregs[i].reg) ) { + _freeXMMreg(i); + xmmregs[i].inuse = 1; + return 1; + } + } + } + + return 0; +} + +int _flushMMXunused() +{ + int i; + for (i=0; iregs[mmxregs[i].reg-MMX_GPR]&EEINST_USED) ) { + if( !_recIsRegWritten(g_pCurInstInfo+1, (s_nEndBlock-pc)/4, XMMTYPE_GPRREG, mmxregs[i].reg-MMX_GPR) ) { + _freeMMXreg(i); + mmxregs[i].inuse = 1; + return 1; + } + } + } + + return 0; +} + +int _flushUnusedConstReg() +{ + int i; + for(i = 1; i < 32; ++i) { + if( (g_cpuHasConstReg & (1< failed to allocate recompiler memory." ); + + // Goal: Allocate BASEBLOCKs for every possible branch target in PS2 memory. + // Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are + // always 4 bytes long). + + if( m_recBlockAlloc == NULL ) + m_recBlockAlloc = (u8*) _aligned_malloc( m_recBlockAllocSize, 4096 ); + + if( m_recBlockAlloc == NULL ) + throw Exception::OutOfMemory( "R5900-32 Init > Failed to allocate memory for BASEBLOCK tables." ); + + u8* curpos = m_recBlockAlloc; + recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Base / 4) * sizeof(BASEBLOCK); + recROM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom / 4) * sizeof(BASEBLOCK); + recROM1 = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom1 / 4) * sizeof(BASEBLOCK); + recBlocks = (BASEBLOCKEX*)curpos; curpos += sizeof(BASEBLOCKEX)*EE_NUMBLOCKS; + recStack = (u8*)curpos; + + if( s_pInstCache == NULL ) + { + s_nInstCacheSize = 128; + s_pInstCache = (EEINST*)malloc( sizeof(EEINST) * s_nInstCacheSize ); + } + + if( s_pInstCache == NULL ) + throw Exception::OutOfMemory( "R5900-32 Init > failed to allocate memory for pInstCache." ); + + // No errors.. Proceed with initialization: + + ProfilerRegisterSource( "EERec", recMem, REC_CACHEMEM+0x1000 ); + + x86FpuState = FPU_STATE; +} + +//////////////////////////////////////////////////// +void recResetEE( void ) +{ + DbgCon::Status( "iR5900-32 > Resetting recompiler memory and structures." ); + + s_nNextBlock = 0; + maxrecmem = 0; + + memset_8<0xcd, REC_CACHEMEM>(recMem); + memzero_ptr( m_recBlockAlloc ); + + if( s_pInstCache ) + memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize ); + + ResetBaseBlockEx(0); + mmap_ResetBlockTracking(); + +#ifdef _MSC_VER + __asm emms; +#else + __asm__("emms"); +#endif + + memzero_ptr<0x010000 * sizeof(uptr)>( recLUT ); + + for ( int i = 0x0000; i < 0x0200; i++ ) + { + recLUT[ i + 0x0000 ] = (uptr)&recRAM[ i << 14 ]; + recLUT[ i + 0x2000 ] = (uptr)&recRAM[ i << 14 ]; + recLUT[ i + 0x3000 ] = (uptr)&recRAM[ i << 14 ]; + } + + for ( int i = 0x0000; i < 0x0040; i++ ) + { + recLUT[ i + 0x1fc0 ] = (uptr)&recROM[ i << 14 ]; + recLUT[ i + 0x9fc0 ] = (uptr)&recROM[ i << 14 ]; + recLUT[ i + 0xbfc0 ] = (uptr)&recROM[ i << 14 ]; + } + + for ( int i = 0x0000; i < 0x0004; i++ ) + { + recLUT[ i + 0x1e00 ] = (uptr)&recROM1[ i << 14 ]; + recLUT[ i + 0x9e00 ] = (uptr)&recROM1[ i << 14 ]; + recLUT[ i + 0xbe00 ] = (uptr)&recROM1[ i << 14 ]; + } + + memcpy_fast( recLUT + 0x8000, recLUT, 0x2000 * sizeof(uptr) ); + memcpy_fast( recLUT + 0xa000, recLUT, 0x2000 * sizeof(uptr) ); + + // drk||Raziel says this is useful but I'm not sure why. Something to do with forward jumps. + // Anyways, it causes random crashing for some reasom, possibly because of memory + // corrupition elsewhere in the recs. I can't reproduce the problem here though, + // so a fix will have to wait until later. -_- (air) + + //x86SetPtr(recMem+REC_CACHEMEM); + //dyna_block_discard_recmem=(u8*)x86Ptr; + //JMP32( (uptr)&dyna_block_discard - ( (u32)x86Ptr + 5 )); + + x86SetPtr(recMem); + + recPtr = recMem; + recStackPtr = recStack; + x86FpuState = FPU_STATE; + iCWstate = 0; + + branch = 0; + SetCPUState(Config.sseMXCSR, Config.sseVUMXCSR); +} + +static void recShutdown( void ) +{ + ProfilerTerminateSource( "EERec" ); + ResetBaseBlockEx(0); + + SafeSysMunmap( recMem, REC_CACHEMEM ); + safe_aligned_free( recLUT ); + safe_aligned_free( m_recBlockAlloc ); + recRAM = recROM = recROM1 = NULL; + recBlocks = NULL; + recStack = NULL; + + safe_free( s_pInstCache ); + s_nInstCacheSize = 0; + + x86Shutdown(); +} + +#pragma warning(disable:4731) // frame pointer register 'ebp' modified by inline assembly code + +void recStep( void ) { +} + +static __forceinline bool recEventTest() +{ +#ifdef PCSX2_DEVBUILD + // dont' remove this check unless doing an official release + if( g_globalXMMSaved || g_globalMMXSaved) + DevCon::Error("Pcsx2 Foopah! Frozen regs have not been restored!!!"); + assert( !g_globalXMMSaved && !g_globalMMXSaved); +#endif + + // Perform counters, ints, and IOP updates: + bool retval = _cpuBranchTest_Shared(); + +#ifdef PCSX2_DEVBUILD + assert( !g_globalXMMSaved && !g_globalMMXSaved); +#endif + return retval; +} + +//////////////////////////////////////////////////// + +static u32 g_lastpc = 0; +u32 g_EEDispatchTemp; + +#ifdef _MSC_VER + +// jumped to when invalid pc address +// EDX contains the jump addr to modify +static __naked void Dispatcher() +{ + // EDX contains the jump addr to modify + __asm push edx + + // calc PC_GETBLOCK + s_pDispatchBlock = PC_GETBLOCK(cpuRegs.pc); + + if( s_pDispatchBlock->startpc != cpuRegs.pc ) + recRecompile(cpuRegs.pc); + + __asm + { + mov eax, s_pDispatchBlock + mov eax, dword ptr [eax] + } + +#ifdef _DEBUG + __asm mov g_EEDispatchTemp, eax + assert( g_EEDispatchTemp ); +#endif + + __asm { + //and eax, 0x0fffffff + shl eax, 4 + pop ecx // x86Ptr to mod + mov edx, eax + sub edx, ecx + sub edx, 4 + mov dword ptr [ecx], edx + + jmp eax + } +} + +// edx - baseblock->startpc +// stack - x86Ptr +static __naked void DispatcherClear() +{ + // EDX contains the current pc + __asm mov cpuRegs.pc, edx + __asm push edx + + // calc PC_GETBLOCK + s_pDispatchBlock = PC_GETBLOCK(cpuRegs.pc); + + if( s_pDispatchBlock != NULL && s_pDispatchBlock->startpc == cpuRegs.pc ) + { + assert( s_pDispatchBlock->GetFnptr() != 0 ); + + // already modded the code, jump to the new place + __asm { + pop edx + mov eax, s_pDispatchBlock + add esp, 4 // ignore stack + mov eax, dword ptr [eax] + //and eax, 0x0fffffff + shl eax, 4 + jmp eax + } + } + + __asm { + call recRecompile + add esp, 4 // pop old param + mov eax, s_pDispatchBlock + mov eax, dword ptr [eax] + + pop ecx // old fnptr + + //and eax, 0x0fffffff + shl eax, 4 + mov byte ptr [ecx], 0xe9 // jmp32 + mov edx, eax + sub edx, ecx + sub edx, 5 + mov dword ptr [ecx+1], edx + + jmp eax + } +} + +// called when jumping to variable pc address +static __naked void DispatcherReg() +{ + s_pDispatchBlock = PC_GETBLOCK(cpuRegs.pc); + + if( s_pDispatchBlock->startpc != cpuRegs.pc ) + recRecompile(cpuRegs.pc); + + __asm + { + mov eax, s_pDispatchBlock + mov eax, dword ptr [eax] + } + +#ifdef _DEBUG + __asm mov g_EEDispatchTemp, eax + assert( g_EEDispatchTemp ); +#endif + + __asm { + //and eax, 0x0fffffff + shl eax, 4 + jmp eax + } +} + +__forceinline void recExecute() +{ + // Optimization note : Compared pushad against manually pushing the regs one-by-one. + // Manually pushing is faster, especially on Core2's and such. :) + do { + g_EEFreezeRegs = true; + __asm + { + push ebx + push esi + push edi + push ebp + + call DispatcherReg + + pop ebp + pop edi + pop esi + pop ebx + } + g_EEFreezeRegs = false; + } + while( !recEventTest() ); +} + +static void recExecuteBlock() +{ + g_EEFreezeRegs = true; + __asm + { + push ebx + push esi + push edi + push ebp + + call DispatcherReg + + pop ebp + pop edi + pop esi + pop ebx + } + g_EEFreezeRegs = false; + recEventTest(); +} + +#else // _MSC_VER +// Linux uses an assembly version of these routines. +extern "C" { +extern void Dispatcher(); +extern void DispatcherClear(); +extern void DispatcherReg(); +} +__forceinline void recExecute() +{ + // Optimization note : Compared pushad against manually pushing the regs one-by-one. + // Manually pushing is faster, especially on Core2's and such. :) + do { + g_EEFreezeRegs = true; + __asm__ + ( + ".intel_syntax\n" + "push %ebx\n" + "push %esi\n" + "push %edi\n" + "push %ebp\n" + + "call DispatcherReg\n" + + "pop %ebp\n" + "pop %edi\n" + "pop %esi\n" + "pop %ebx\n" + ".att_syntax\n" + ); + g_EEFreezeRegs = false; + } + while( !recEventTest() ); +} + +static void recExecuteBlock() +{ + g_EEFreezeRegs = true; + __asm__ + ( + ".intel_syntax\n" + "push %ebx\n" + "push %esi\n" + "push %edi\n" + "push %ebp\n" + + "call DispatcherReg\n" + + "pop %ebp\n" + "pop %edi\n" + "pop %esi\n" + "pop %ebx\n" + ".att_syntax\n" + ); + g_EEFreezeRegs = false; + recEventTest(); +} +#endif + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl { + +//////////////////////////////////////////////////// +void recSYSCALL( void ) { + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_NODESTROY); + CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::SYSCALL ); + + CMP32ItoM((uptr)&cpuRegs.pc, pc); + j8Ptr[0] = JE8(0); + ADD32ItoM((uptr)&cpuRegs.cycle, eeScaleBlockCycles()); + JMP32((uptr)DispatcherReg - ( (uptr)x86Ptr + 5 )); + x86SetJ8(j8Ptr[0]); + //branch = 2; +} + +//////////////////////////////////////////////////// +void recBREAK( void ) { + MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::BREAK ); + + CMP32ItoM((uptr)&cpuRegs.pc, pc); + j8Ptr[0] = JE8(0); + ADD32ItoM((uptr)&cpuRegs.cycle, eeScaleBlockCycles()); + RET(); + x86SetJ8(j8Ptr[0]); + //branch = 2; +} + +} } } // end namespace R5900::Dynarec::OpcodeImpl + +//////////////////////////////////////////////////// +void recClear( u32 Addr, u32 Size ) +{ + u32 i; + for(i = 0; i < Size; ++i, Addr+=4) { + REC_CLEARM(Addr); + } +} + +static const int EE_MIN_BLOCK_BYTES = 15; + +void recClearMem(BASEBLOCK* p) +{ + BASEBLOCKEX* pexblock; + BASEBLOCK* pstart; + int lastdelay; + + // necessary since recompiler doesn't call femms/emms +#ifdef _MSC_VER + if (cpucaps.has3DNOWInstructionExtensions) __asm femms; + else __asm emms; +#else + if( cpucaps.has3DNOWInstructionExtensions )__asm__("femms"); + else __asm__("emms"); +#endif + + assert( p != NULL ); + + if( p->uType & BLOCKTYPE_DELAYSLOT ) { + recClearMem(p-1); + if( p->GetFnptr() == 0 ) + return; + } + + assert( p->GetFnptr() != 0 ); + assert( p->startpc ); + + x86Ptr = (u8*)p->GetFnptr(); + + // there is a small problem: mem can be ored with 0xa<<28 or 0x8<<28, and don't know which + MOV32ItoR(EDX, p->startpc); + PUSH32I((u32)x86Ptr); // will be replaced by JMP32 + JMP32((u32)DispatcherClear - ( (u32)x86Ptr + 5 )); + assert( x86Ptr == (u8*)p->GetFnptr() + EE_MIN_BLOCK_BYTES ); + + pstart = PC_GETBLOCK(p->startpc); + pexblock = PC_GETBLOCKEX(pstart); + assert( pexblock->startpc == pstart->startpc ); + + if( pexblock->startpc != pstart->startpc ) { + // some bug with ffx after beating a big snake in sewers + RemoveBaseBlockEx(pexblock, 0); + pexblock->size = 0; + pexblock->startpc = 0; + return; + } + + // don't delete if last is delay + lastdelay = pexblock->size; + if( pstart[pexblock->size-1].uType & BLOCKTYPE_DELAYSLOT ) { + assert( pstart[pexblock->size-1].GetFnptr() != pstart->GetFnptr() ); + if( pstart[pexblock->size-1].GetFnptr() != 0 ) { + pstart[pexblock->size-1].uType = 0; + --lastdelay; + } + } + + memset(pstart, 0, lastdelay*sizeof(BASEBLOCK)); + + RemoveBaseBlockEx(pexblock, 0); + pexblock->size = 0; + pexblock->startpc = 0; +} + +void REC_CLEARM( u32 mem ) +{ + if ((mem) < maxrecmem && recLUT[(mem) >> 16]) { + BASEBLOCK* p = PC_GETBLOCK(mem); + if( *(u32*)p ) recClearMem(p); + } +} + +// check for end of bios +void CheckForBIOSEnd() +{ + MOV32MtoR(EAX, (int)&cpuRegs.pc); + + CMP32ItoR(EAX, 0x00200008); + j8Ptr[0] = JE8(0); + + CMP32ItoR(EAX, 0x00100008); + j8Ptr[1] = JE8(0); + + // return + j8Ptr[2] = JMP8(0); + + x86SetJ8( j8Ptr[0] ); + x86SetJ8( j8Ptr[1] ); + + // bios end + RET2(); + + x86SetJ8( j8Ptr[2] ); +} + +static int *s_pCode; + +void SetBranchReg( u32 reg ) +{ + branch = 1; + + if( reg != 0xffffffff ) { +// if( GPR_IS_CONST1(reg) ) +// MOV32ItoM( (uptr)&cpuRegs.pc, g_cpuConstRegs[reg].UL[0] ); +// else { +// int mmreg; +// +// if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, reg, MODE_READ)) >= 0 ) { +// SSE_MOVSS_XMM_to_M32((u32)&cpuRegs.pc, mmreg); +// } +// else if( (mmreg = _checkMMXreg(MMX_GPR+reg, MODE_READ)) >= 0 ) { +// MOVDMMXtoM((u32)&cpuRegs.pc, mmreg); +// SetMMXstate(); +// } +// else { +// MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ reg ].UL[ 0 ] ); +// MOV32RtoM((u32)&cpuRegs.pc, EAX); +// } +// } + _allocX86reg(ESI, X86TYPE_PCWRITEBACK, 0, MODE_WRITE); + _eeMoveGPRtoR(ESI, reg); + + recompileNextInstruction(1); + + if( x86regs[ESI].inuse ) { + assert( x86regs[ESI].type == X86TYPE_PCWRITEBACK ); + MOV32RtoM((int)&cpuRegs.pc, ESI); + x86regs[ESI].inuse = 0; + } + else { + MOV32MtoR(EAX, (u32)&g_recWriteback); + MOV32RtoM((int)&cpuRegs.pc, EAX); + } + } + +// CMP32ItoM((u32)&cpuRegs.pc, 0); +// j8Ptr[5] = JNE8(0); +// CALLFunc((uptr)tempfn); +// x86SetJ8( j8Ptr[5] ); + + iFlushCall(FLUSH_EVERYTHING); + + iBranchTest(0xffffffff); +} + +void SetBranchImm( u32 imm ) +{ + branch = 1; + + assert( imm ); + + // end the current block + MOV32ItoM( (uptr)&cpuRegs.pc, imm ); + iFlushCall(FLUSH_EVERYTHING); + + iBranchTest(imm); +} + +void SaveBranchState() +{ + s_savex86FpuState = x86FpuState; + s_saveiCWstate = iCWstate; + s_savenBlockCycles = s_nBlockCycles; + s_saveConstGPRreg = 0xffffffff; // indicate searching + s_saveHasConstReg = g_cpuHasConstReg; + s_saveFlushedConstReg = g_cpuFlushedConstReg; + s_psaveInstInfo = g_pCurInstInfo; + s_saveRegHasLive1 = g_cpuRegHasLive1; + s_saveRegHasSignExt = g_cpuRegHasSignExt; + + // save all mmx regs + memcpy_fast(s_saveMMXregs, mmxregs, sizeof(mmxregs)); + memcpy_fast(s_saveXMMregs, xmmregs, sizeof(xmmregs)); +} + +void LoadBranchState() +{ + x86FpuState = s_savex86FpuState; + iCWstate = s_saveiCWstate; + s_nBlockCycles = s_savenBlockCycles; + + if( s_saveConstGPRreg != 0xffffffff ) { + assert( s_saveConstGPRreg > 0 ); + + // make sure right GPR was saved + assert( g_cpuHasConstReg == s_saveHasConstReg || (g_cpuHasConstReg ^ s_saveHasConstReg) == (1<> 3; + + uint scalarLow, scalarMid, scalarHigh; + + // Note: larger blocks get a smaller scalar, to help keep + // them from becoming "too fat" and delaying branch tests. + + switch( CHECK_EE_CYCLERATE ) + { + case 0: return s_nBlockCycles >> 3; + + case 1: // Sync hack x1.5! + scalarLow = 5; + scalarMid = 7; + scalarHigh = 5; + break; + + case 2: // Sync hack x2 + scalarLow = 7; + scalarMid = 9; + scalarHigh = 7; + break; + + case 3: // Sync hack x3 + scalarLow = 10; + scalarMid = 19; + scalarHigh = 10; + break; + + jNO_DEFAULT + } + + s_nBlockCycles *= + (s_nBlockCycles <= (10<<3)) ? scalarLow : + ((s_nBlockCycles > (21<<3)) ? scalarHigh : scalarMid ); + + return s_nBlockCycles >> (3+2); +} + +// Generates dynarec code for Event tests followed by a block dispatch (branch). +// Parameters: +// newpc - address to jump to at the end of the block. If newpc == 0xffffffff then +// the jump is assumed to be to a register (dynamic). For any other value the +// jump is assumed to be static, in which case the block will be "hardlinked" after +// the first time it's dispatched. +// +// noDispatch - When set true, the jump to Dispatcher. Used by the recs +// for blocks which perform exception checks without branching (it's enabled by +// setting "branch = 2"; +static void iBranchTest(u32 newpc, bool noDispatch) +{ +#ifdef _DEBUG + //CALLFunc((uptr)testfpu); +#endif + u32* ptr; + + if( bExecBIOS ) CheckForBIOSEnd(); + + MOV32MtoR(EAX, (uptr)&cpuRegs.cycle); + if( !noDispatch && newpc != 0xffffffff ) + { + // Optimization note: Instructions order to pair EDX with EAX's load above. + + // Load EDX with the address of the JS32 jump below. + // We do this because the the Dispatcher will use this info to modify + // the JS instruction later on with the address of the block it's jumping + // to; creating a static link of blocks that doesn't require the overhead + // of a dispatcher. + MOV32ItoR(EDX, 0); + ptr = (u32*)(x86Ptr-4); + } + + // Check the Event scheduler if our "cycle target" has been reached. + // Equiv code to: + // cpuRegs.cycle += blockcycles; + // if( cpuRegs.cycle > g_nextBranchCycle ) { DoEvents(); } + ADD32ItoR(EAX, eeScaleBlockCycles()); + MOV32RtoM((uptr)&cpuRegs.cycle, EAX); // update cycles + SUB32MtoR(EAX, (uptr)&g_nextBranchCycle); + + if( newpc != 0xffffffff ) + { + // This is the jump instruction which gets modified by Dispatcher. + *ptr = (u32)JS32((u32)Dispatcher - ( (u32)x86Ptr + 6 )); + } + else if( !noDispatch ) + { + // This instruction is a dynamic link, so it's never modified. + JS32((uptr)DispatcherReg - ( (uptr)x86Ptr + 6 )); + } + + RET2(); +} + +static void checkcodefn() +{ + int pctemp; + +#ifdef _MSC_VER + __asm mov pctemp, eax; +#else + __asm__("movl %%eax, %0" : "=m"(pctemp) ); +#endif + + Console::Error("code changed! %x", params pctemp); + assert(0); +} + +//#ifdef _DEBUG +//#define CHECK_XMMCHANGED() CALLFunc((uptr)checkxmmchanged); +//#else +//#define CHECK_XMMCHANGED() +//#endif +// +//static void checkxmmchanged() +//{ +// assert( !g_globalMMXSaved ); +// assert( !g_globalXMMSaved ); +//} + +u32 recompileCodeSafe(u32 temppc) +{ + BASEBLOCK* pblock = PC_GETBLOCK(temppc); + + if( pblock->GetFnptr() != 0 && pblock->startpc != s_pCurBlock->startpc ) { + if( pc == pblock->startpc ) + return 0; + } + + return 1; +} + +void recompileNextInstruction(int delayslot) +{ + static u8 s_bFlushReg = 1; + int i, count; + + BASEBLOCK* pblock = PC_GETBLOCK(pc); + + // need *ppblock != s_pCurBlock because of branches + if( pblock->GetFnptr() != 0 && pblock->startpc != s_pCurBlock->startpc ) { + + if( !delayslot && pc == pblock->startpc ) { + // code already in place, so jump to it and exit recomp + assert( PC_GETBLOCKEX(pblock)->startpc == pblock->startpc ); + + iFlushCall(FLUSH_EVERYTHING); + MOV32ItoM((uptr)&cpuRegs.pc, pc); + +// if( pexblock->pOldFnptr ) { +// // code already in place, so jump to it and exit recomp +// JMP32((u32)pexblock->pOldFnptr - ((u32)x86Ptr + 5)); +// branch = 3; +// return; +// } + + JMP32((uptr)pblock->GetFnptr() - ((uptr)x86Ptr + 5)); + branch = 3; + return; + } + else { + + if( !(delayslot && pblock->startpc == pc) ) { + u8* oldX86 = x86Ptr; + //__Log("clear block %x\n", pblock->startpc); + recClearMem(pblock); + x86Ptr = oldX86; + if( delayslot ) + Console::Notice("delay slot %x", params pc); + } + } + } + + if( delayslot ) + pblock->uType = BLOCKTYPE_DELAYSLOT; + + s_pCode = (int *)PSM( pc ); + assert(s_pCode); + +#ifdef _DEBUG + MOV32ItoR(EAX, pc); +#endif + + cpuRegs.code = *(int *)s_pCode; + pc += 4; + +//#ifdef _DEBUG +// CMP32ItoM((u32)s_pCode, cpuRegs.code); +// j8Ptr[0] = JE8(0); +// MOV32ItoR(EAX, pc); +// CALLFunc((uptr)checkcodefn); +// x86SetJ8( j8Ptr[ 0 ] ); +// +// if( !delayslot ) { +// CMP32ItoM((u32)&cpuRegs.pc, s_pCurBlockEx->startpc); +// j8Ptr[0] = JB8(0); +// CMP32ItoM((u32)&cpuRegs.pc, pc); +// j8Ptr[1] = JA8(0); +// j8Ptr[2] = JMP8(0); +// x86SetJ8( j8Ptr[ 0 ] ); +// x86SetJ8( j8Ptr[ 1 ] ); +// PUSH32I(s_pCurBlockEx->startpc); +// ADD32ItoR(ESP, 4); +// x86SetJ8( j8Ptr[ 2 ] ); +// } +//#endif + + g_pCurInstInfo++; + + // reorder register priorities +// for(i = 0; i < X86REGS; ++i) { +// if( x86regs[i].inuse ) { +// if( count > 0 ) mmxregs[i].counter = 1000-count; +// else mmxregs[i].counter = 0; +// } +// } + + for(i = 0; i < MMXREGS; ++i) { + if( mmxregs[i].inuse ) { + assert( MMX_ISGPR(mmxregs[i].reg) ); + count = _recIsRegWritten(g_pCurInstInfo, (s_nEndBlock-pc)/4 + 1, XMMTYPE_GPRREG, mmxregs[i].reg-MMX_GPR); + if( count > 0 ) mmxregs[i].counter = 1000-count; + else mmxregs[i].counter = 0; + } + } + + for(i = 0; i < XMMREGS; ++i) { + if( xmmregs[i].inuse ) { + count = _recIsRegWritten(g_pCurInstInfo, (s_nEndBlock-pc)/4 + 1, xmmregs[i].type, xmmregs[i].reg); + if( count > 0 ) xmmregs[i].counter = 1000-count; + else xmmregs[i].counter = 0; + } + } + + const OPCODE& opcode = GetCurrentInstruction(); + + // peephole optimizations +#ifdef PCSX2_VM_COISSUE + if( g_pCurInstInfo->info & EEINSTINFO_COREC ) { + + if( g_pCurInstInfo->numpeeps > 1 ) { + switch(_Opcode_) { + case 30: recLQ_coX(g_pCurInstInfo->numpeeps); break; + case 31: recSQ_coX(g_pCurInstInfo->numpeeps); break; + case 49: recLWC1_coX(g_pCurInstInfo->numpeeps); break; + case 57: recSWC1_coX(g_pCurInstInfo->numpeeps); break; + case 55: recLD_coX(g_pCurInstInfo->numpeeps); break; + case 63: recSD_coX(g_pCurInstInfo->numpeeps, 1); break; //not sure if should be set to 1 or 0; looks like "1" handles alignment, so i'm going with that for now + + jNO_DEFAULT + } + pc += g_pCurInstInfo->numpeeps*4; + s_nBlockCycles += (g_pCurInstInfo->numpeeps+1) * opcode.cycles; + g_pCurInstInfo += g_pCurInstInfo->numpeeps; + } + else { + recBSC_co[_Opcode_](); + pc += 4; + g_pCurInstInfo++; + s_nBlockCycles += opcode.cycles*2; + } + } + else +#endif + { + //assert( !(g_pCurInstInfo->info & EEINSTINFO_NOREC) ); + + // if this instruction is a jump or a branch, exit right away + if( delayslot ) { + switch(_Opcode_) { + case 1: + switch(_Rt_) { + case 0: case 1: case 2: case 3: case 0x10: case 0x11: case 0x12: case 0x13: + Console::Notice("branch %x in delay slot!", params cpuRegs.code); + _clearNeededX86regs(); + _clearNeededMMXregs(); + _clearNeededXMMregs(); + return; + } + break; + + case 2: case 3: case 4: case 5: case 6: case 7: case 0x14: case 0x15: case 0x16: case 0x17: + Console::Notice("branch %x in delay slot!", params cpuRegs.code); + _clearNeededX86regs(); + _clearNeededMMXregs(); + _clearNeededXMMregs(); + return; + } + } + opcode.recompile(); + s_nBlockCycles += opcode.cycles; + } + + if( !delayslot ) { + if( s_bFlushReg ) { + //if( !_flushUnusedConstReg() ) { + int flushed = 0; + if( _getNumMMXwrite() > 3 ) flushed = _flushMMXunused(); + if( !flushed && _getNumXMMwrite() > 2 ) _flushXMMunused(); + s_bFlushReg = !flushed; +// } +// else s_bFlushReg = 0; + } + else s_bFlushReg = 1; + } + else s_bFlushReg = 1; + + //CHECK_XMMCHANGED(); + _clearNeededX86regs(); + _clearNeededMMXregs(); + _clearNeededXMMregs(); + +// _freeXMMregs(); +// _freeMMXregs(); +// _flushCachedRegs(); +// g_cpuHasConstReg = 1; +} + +extern u32 psxdump; + +static void printfn() +{ + static int lastrec = 0; + static int curcount = 0; + const int skip = 0; + + assert( !g_globalMMXSaved ); + assert( !g_globalXMMSaved ); + + if( (dumplog&2) && g_lastpc != 0x81fc0 ) {//&& lastrec != g_lastpc ) { + curcount++; + + if( curcount > skip ) { + iDumpRegisters(g_lastpc, 1); + curcount = 0; + } + + lastrec = g_lastpc; + } +} + +u32 s_recblocks[] = {0}; + +void badespfn() { + Console::Error("Bad esp!"); + assert(0); +} + +void __fastcall dyna_block_discard(u32 start,u32 sz) +{ + Console::WriteLn("dyna_block_discard %08X , count %d", params start,sz); + Cpu->Clear(start,sz); +} + +void recRecompile( const u32 startpc ) +{ + u32 i = 0; + u32 branchTo; + u32 willbranch3 = 0; + u32* ptr; + u32 usecop2; + +#ifdef _DEBUG + //dumplog |= 4; + if( dumplog & 4 ) + iDumpRegisters(startpc, 0); +#endif + + assert( startpc ); + + // if recPtr reached the mem limit reset whole mem + if ( ( (uptr)recPtr - (uptr)recMem ) >= REC_CACHEMEM-0x40000 || dumplog == 0xffffffff) { + DevCon::WriteLn( "EE Recompiler data reset" ); + recResetEE(); + } + if ( ( (uptr)recStackPtr - (uptr)recStack ) >= RECSTACK_SIZE-0x100 ) { + DevCon::WriteLn("EE recompiler stack reset"); + recResetEE(); + } + + s_pCurBlock = PC_GETBLOCK(startpc); + + if( s_pCurBlock->GetFnptr() ) { + // clear if already taken + assert( s_pCurBlock->startpc < startpc ); + recClearMem(s_pCurBlock); + } + + if( s_pCurBlock->startpc == startpc ) { + s_pCurBlockEx = PC_GETBLOCKEX(s_pCurBlock); + assert( s_pCurBlockEx->startpc == startpc ); + } + else { + s_pCurBlockEx = NULL; + for(i = 0; i < EE_NUMBLOCKS; ++i) { + if( recBlocks[(i+s_nNextBlock)%EE_NUMBLOCKS].size == 0 ) { + s_pCurBlockEx = recBlocks+(i+s_nNextBlock)%EE_NUMBLOCKS; + s_nNextBlock = (i+s_nNextBlock+1)%EE_NUMBLOCKS; + break; + } + } + + if( s_pCurBlockEx == NULL ) { + //SysPrintf("ee reset (blocks)\n"); + recResetEE(); + s_nNextBlock = 0; + s_pCurBlockEx = recBlocks; + } + + s_pCurBlockEx->startpc = startpc; + } + + x86SetPtr( recPtr ); + x86Align(16); + recPtr = x86Ptr; + s_pCurBlock->SetFnptr( (uptr)x86Ptr ); + s_pCurBlock->startpc = startpc; + + branch = 0; + + // reset recomp state variables + s_nBlockCycles = 0; + pc = startpc; + x86FpuState = FPU_STATE; + iCWstate = 0; + s_saveConstGPRreg = 0; + g_cpuHasConstReg = g_cpuFlushedConstReg = 1; + g_cpuPrevRegHasLive1 = g_cpuRegHasLive1 = 0xffffffff; + g_cpuPrevRegHasSignExt = g_cpuRegHasSignExt = 0; + assert( g_cpuConstRegs[0].UD[0] == 0 ); + + _initX86regs(); + _initXMMregs(); + _initMMXregs(); + +#ifdef _DEBUG + // for debugging purposes + MOV32ItoM((uptr)&g_lastpc, pc); + CALLFunc((uptr)printfn); + +// CMP32MtoR(EBP, (uptr)&s_uSaveEBP); +// j8Ptr[0] = JE8(0); +// CALLFunc((uptr)badespfn); +// x86SetJ8(j8Ptr[0]); +#endif + + // go until the next branch + i = startpc; + s_nEndBlock = 0xffffffff; + s_nHasDelay = 0; + + while(1) { + BASEBLOCK* pblock = PC_GETBLOCK(i); + if( pblock->GetFnptr() != 0 && pblock->startpc != s_pCurBlock->startpc ) { + + if( i == pblock->startpc ) { + // branch = 3 + willbranch3 = 1; + s_nEndBlock = i; + break; + } + } + //HUH ? PSM ? whut ? THIS IS VIRTUAL ACCESS GOD DAMMIT + cpuRegs.code = *(int *)PSM(i); + + switch(cpuRegs.code >> 26) { + case 0: // special + + if( _Funct_ == 8 || _Funct_ == 9 ) { // JR, JALR + s_nEndBlock = i + 8; + s_nHasDelay = 1; + goto StartRecomp; + } + + break; + case 1: // regimm + + if( _Rt_ < 4 || (_Rt_ >= 16 && _Rt_ < 20) ) { + // branches + if( _Rt_ == 2 || _Rt_ == 3 || _Rt_ == 18 || _Rt_ == 19 ) s_nHasDelay = 1; + else s_nHasDelay = 2; + + branchTo = _Imm_ * 4 + i + 4; + if( branchTo > startpc && branchTo < i ) s_nEndBlock = branchTo; + else s_nEndBlock = i+8; + + goto StartRecomp; + } + + break; + + case 2: // J + case 3: // JAL + s_nHasDelay = 1; + s_nEndBlock = i + 8; + goto StartRecomp; + + // branches + case 4: case 5: case 6: case 7: + case 20: case 21: case 22: case 23: + + if( (cpuRegs.code >> 26) >= 20 ) s_nHasDelay = 1; + else s_nHasDelay = 2; + + branchTo = _Imm_ * 4 + i + 4; + if( branchTo > startpc && branchTo < i ) s_nEndBlock = branchTo; + else s_nEndBlock = i+8; + + goto StartRecomp; + + case 16: // cp0 + if( _Rs_ == 16 ) { + if( _Funct_ == 24 ) { // eret + s_nEndBlock = i+4; + goto StartRecomp; + } + } + // Fall through! + // COP0's branch opcodes line up with COP1 and COP2's + + case 17: // cp1 + case 18: // cp2 + if( _Rs_ == 8 ) { + // BC1F, BC1T, BC1FL, BC1TL + // BC2F, BC2T, BC2FL, BC2TL + if( _Rt_ >= 2 ) s_nHasDelay = 1; + else s_nHasDelay = 2; + + branchTo = _Imm_ * 4 + i + 4; + if( branchTo > startpc && branchTo < i ) s_nEndBlock = branchTo; + else s_nEndBlock = i+8; + + goto StartRecomp; + } + break; + } + + i += 4; + } + +StartRecomp: + + // rec info // + { + EEINST* pcur; + + if( s_nInstCacheSize < (s_nEndBlock-startpc)/4+1 ) { + free(s_pInstCache); + s_nInstCacheSize = (s_nEndBlock-startpc)/4+10; + s_pInstCache = (EEINST*)malloc(sizeof(EEINST)*s_nInstCacheSize); + assert( s_pInstCache != NULL ); + } + + pcur = s_pInstCache + (s_nEndBlock-startpc)/4; + _recClearInst(pcur); + pcur->info = 0; + + for(i = s_nEndBlock; i > startpc; i -= 4 ) { + cpuRegs.code = *(int *)PSM(i-4); + pcur[-1] = pcur[0]; + + BSCPropagate bsc( pcur[-1], pcur[0] ); + bsc.rprop(); + pcur--; + } + } + + // analyze instructions // + { + usecop2 = 0; + g_pCurInstInfo = s_pInstCache; + + for(i = startpc; i < s_nEndBlock; i += 4) { + g_pCurInstInfo++; + cpuRegs.code = *(u32*)PSM(i); + + // cop2 // + if( g_pCurInstInfo->info & EEINSTINFO_COP2 ) { + + if( !usecop2 ) { + // init + vucycle = 0; + usecop2 = 1; + } + + VU0.code = cpuRegs.code; + _vuRegsCOP22( &VU0, &g_pCurInstInfo->vuregs ); + continue; + } + + // fixme - This should be based on the cycle count of the current EE + // instruction being analyzed. + if( usecop2 ) vucycle++; + + // peephole optimizations // +#ifdef PCSX2_VM_COISSUE + if( i < s_nEndBlock-4 && recompileCodeSafe(i) ) { + u32 curcode = cpuRegs.code; + u32 nextcode = *(u32*)PSM(i+4); + if( _eeIsLoadStoreCoIssue(curcode, nextcode) && recBSC_co[curcode>>26] != NULL ) { + + // rs has to be the same, and cannot be just written + if( ((curcode >> 21) & 0x1F) == ((nextcode >> 21) & 0x1F) && !_eeLoadWritesRs(curcode) ) { + + if( _eeIsLoadStoreCoX(curcode) && ((nextcode>>16)&0x1f) != ((curcode>>21)&0x1f) ) { + // see how many stores there are + u32 j; + // use xmmregs since only supporting lwc1,lq,swc1,sq + for(j = i+8; j < s_nEndBlock && j < i+4*XMMREGS; j += 4 ) { + u32 nncode = *(u32*)PSM(j); + if( (nncode>>26) != (curcode>>26) || ((curcode>>21)&0x1f) != ((nncode>>21)&0x1f) || + _eeLoadWritesRs(nncode)) + break; + } + + if( j > i+8 ) { + u32 num = (j-i)>>2; // number of stores that can coissue + assert( num <= XMMREGS ); + + g_pCurInstInfo[0].numpeeps = num-1; + g_pCurInstInfo[0].info |= EEINSTINFO_COREC; + + while(i < j-4) { + g_pCurInstInfo++; + g_pCurInstInfo[0].info |= EEINSTINFO_NOREC; + i += 4; + } + + continue; + } + + // fall through + } + + // unaligned loadstores + + // if LWL, check if LWR and that offsets are +3 away + switch(curcode >> 26) { + case 0x22: // LWL + if( (nextcode>>26) != 0x26 || ((s16)nextcode)+3 != (s16)curcode ) + continue; + break; + case 0x26: // LWR + if( (nextcode>>26) != 0x22 || ((s16)nextcode) != (s16)curcode+3 ) + continue; + break; + + case 0x2a: // SWL + if( (nextcode>>26) != 0x2e || ((s16)nextcode)+3 != (s16)curcode ) + continue; + break; + case 0x2e: // SWR + if( (nextcode>>26) != 0x2a || ((s16)nextcode) != (s16)curcode+3 ) + continue; + break; + + case 0x1a: // LDL + if( (nextcode>>26) != 0x1b || ((s16)nextcode)+7 != (s16)curcode ) + continue; + break; + case 0x1b: // LWR + if( (nextcode>>26) != 0x1aa || ((s16)nextcode) != (s16)curcode+7 ) + continue; + break; + + case 0x2c: // SWL + if( (nextcode>>26) != 0x2d || ((s16)nextcode)+7 != (s16)curcode ) + continue; + break; + case 0x2d: // SWR + if( (nextcode>>26) != 0x2c || ((s16)nextcode) != (s16)curcode+7 ) + continue; + break; + } + + // good enough + g_pCurInstInfo[0].info |= EEINSTINFO_COREC; + g_pCurInstInfo[0].numpeeps = 1; + g_pCurInstInfo[1].info |= EEINSTINFO_NOREC; + g_pCurInstInfo++; + i += 4; + continue; + } + } + } +#endif // end peephole + } + // This *is* important because g_pCurInstInfo is checked a bit later on and + // if it's not equal to s_pInstCache it handles recompilation differently. + // ... but the empty if() conditional inside the for loop is still amusing. >_< + if( usecop2 ) { + // add necessary mac writebacks + g_pCurInstInfo = s_pInstCache; + + for(i = startpc; i < s_nEndBlock-4; i += 4) { + g_pCurInstInfo++; + + if( g_pCurInstInfo->info & EEINSTINFO_COP2 ) { + } + } + } + } + +#ifdef _DEBUG + // dump code + for(i = 0; i < ARRAYSIZE(s_recblocks); ++i) { + if( startpc == s_recblocks[i] ) { + iDumpBlock(startpc, recPtr); + } + } + + if( (dumplog & 1) ) //|| usecop2 ) + iDumpBlock(startpc, recPtr); +#endif + + u32 sz=(s_nEndBlock-startpc)>>2; +#ifdef lulz + /* + Block checking (ADDED BY RAZ-TEMP) + */ + + MOV32ItoR(ECX,startpc); + MOV32ItoR(EDX,sz); + +#endif + + u32 inpage_offs=startpc&0xFFF; + u32 inpage_ptr=startpc; + u32 inpage_sz=sz*4; + + MOV32ItoR(ECX,startpc); + MOV32ItoR(EDX,sz); + + while(inpage_sz) + { + int PageType=mmap_GetRamPageInfo((u32*)PSM(inpage_ptr)); + u32 pgsz=std::min(0x1000-inpage_offs,inpage_sz); + + if(PageType!=-1) + { + if (PageType==0) + { + //MOV32ItoR(EAX,*pageVer); + //CMP32MtoR(EAX,(uptr)pageVer); + //JNE32(((u32)dyna_block_discard_recmem)- ( (u32)x86Ptr + 6 )); + + mmap_MarkCountedRamPage(PSM(inpage_ptr),inpage_ptr&~0xFFF); + } + else + { + u32 lpc=inpage_ptr; + u32 stg=pgsz; + while(stg>0) + { + // was dyna_block_discard_recmem. See note in recResetEE for details. + CMP32ItoM((uptr)PSM(lpc),*(u32*)PSM(lpc)); + JNE32(((u32)&dyna_block_discard)- ( (u32)x86Ptr + 6 )); + + stg-=4; + lpc+=4; + } + DbgCon::WriteLn("Manual block @ %08X : %08X %d %d %d %d", params + startpc,inpage_ptr,pgsz,0x1000-inpage_offs,inpage_sz,sz*4); + } + } + inpage_ptr+=pgsz; + inpage_sz-=pgsz; + inpage_offs=inpage_ptr&0xFFF; + } + + // finally recompile // + g_pCurInstInfo = s_pInstCache; + while (!branch && pc < s_nEndBlock) { + recompileNextInstruction(0); + } + +#ifdef _DEBUG + if( (dumplog & 1) ) + iDumpBlock(startpc, recPtr); +#endif + + assert( (pc-startpc)>>2 <= 0xffff ); + s_pCurBlockEx->size = (pc-startpc)>>2; + + for(i = 1; i < (u32)s_pCurBlockEx->size-1; ++i) { + s_pCurBlock[i].SetFnptr( s_pCurBlock->GetFnptr() ); + s_pCurBlock[i].startpc = s_pCurBlock->startpc; + } + + // don't overwrite if delay slot + if( i < (u32)s_pCurBlockEx->size && !(s_pCurBlock[i].uType & BLOCKTYPE_DELAYSLOT) ) { + s_pCurBlock[i].SetFnptr( s_pCurBlock->GetFnptr() ); + s_pCurBlock[i].startpc = s_pCurBlock->startpc; + } + + // set the block ptr + AddBaseBlockEx(s_pCurBlockEx, 0); +// if( p[1].startpc == p[0].startpc + 4 ) { +// assert( p[1].GetFnptr() != 0 ); +// // already fn in place, so add to list +// AddBaseBlockEx(s_pCurBlockEx, 0); +// } +// else +// *(BASEBLOCKEX**)(p+1) = pex; +// } + + //PC_SETBLOCKEX(s_pCurBlock, s_pCurBlockEx); + + if( !(pc&0x10000000) ) + maxrecmem = std::max( (pc&~0xa0000000), maxrecmem ); + + if( branch == 2 ) + { + // Branch type 2 - This is how I "think" this works (air): + // Performs a branch/event test but does not actually "break" the block. + // This allows exceptions to be raised, and is thus sufficient for + // certain types of things like SYSCALL, EI, etc. but it is not sufficient + // for actual branching instructions. + + iFlushCall(FLUSH_EVERYTHING); + iBranchTest(0xffffffff, true); + } + else + { + assert( branch != 3 ); + if( branch ) + assert( !willbranch3 ); + else + ADD32ItoM((int)&cpuRegs.cycle, eeScaleBlockCycles() ); + + if( willbranch3 ) { + BASEBLOCK* pblock = PC_GETBLOCK(s_nEndBlock); + assert( pc == s_nEndBlock ); + iFlushCall(FLUSH_EVERYTHING); + MOV32ItoM((uptr)&cpuRegs.pc, pc); + JMP32((uptr)pblock->GetFnptr() - ((uptr)x86Ptr + 5)); + branch = 3; + } + else if( !branch ) { + // didn't branch, but had to stop + MOV32ItoM( (uptr)&cpuRegs.pc, pc ); + + iFlushCall(FLUSH_EVERYTHING); + + ptr = JMP32(0); + } + } + + assert( x86Ptr >= (u8*)s_pCurBlock->GetFnptr() + EE_MIN_BLOCK_BYTES ); + assert( x86Ptr < recMem+REC_CACHEMEM ); + assert( recStackPtr < recStack+RECSTACK_SIZE ); + assert( x86FpuState == 0 ); + + recPtr = x86Ptr; + + assert( (g_cpuHasConstReg&g_cpuFlushedConstReg) == g_cpuHasConstReg ); + + if( !branch ) { + BASEBLOCK* pcurblock = s_pCurBlock; + u32 nEndBlock = s_nEndBlock; + s_pCurBlock = PC_GETBLOCK(pc); + assert( ptr != NULL ); + + if( s_pCurBlock->startpc != pc ) + recRecompile(pc); + + if( pcurblock->startpc == startpc ) { + assert( pcurblock->GetFnptr() ); + assert( s_pCurBlock->startpc == nEndBlock ); + *ptr = s_pCurBlock->GetFnptr() - ( (u32)ptr + 4 ); + } + else { + recRecompile(startpc); + assert( pcurblock->GetFnptr() != 0 ); + } + } +} + +R5900cpu recCpu = { + recAlloc, + recResetEE, + recStep, + recExecute, + recExecuteBlock, + recClear, + recShutdown +}; diff --git a/pcsx2/x86/ix86-32/iR5900Arit.cpp b/pcsx2/x86/ix86-32/iR5900Arit.cpp index d0f6dd4396..0debf6f069 100644 --- a/pcsx2/x86/ix86-32/iR5900Arit.cpp +++ b/pcsx2/x86/ix86-32/iR5900Arit.cpp @@ -1,1993 +1,1993 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "R5900OpcodeTables.h" -#include "ix86/ix86.h" -#include "iR5900.h" - - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl -{ - -/********************************************************* -* Register arithmetic * -* Format: OP rd, rs, rt * -*********************************************************/ - -// NOTE: The reason ADD/SUB/etc are so large is because they are very commonly -// used and recompiler needs to cover ALL possible usages to minimize code size (zerofrog) - -#ifndef ARITHMETIC_RECOMPILE - -namespace Interp = R5900::Interpreter::OpcodeImpl; - -REC_FUNC(ADD); -REC_FUNC(ADDU); -REC_FUNC(DADD); -REC_FUNC(DADDU); -REC_FUNC(SUB); -REC_FUNC(SUBU); -REC_FUNC(DSUB); -REC_FUNC(DSUBU); -REC_FUNC(AND); -REC_FUNC(OR); -REC_FUNC(XOR); -REC_FUNC(NOR); -REC_FUNC(SLT); -REC_FUNC(SLTU); - -#elif defined(EE_CONST_PROP) - -//// ADD -void recADD_const() -{ - g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SL[0] + g_cpuConstRegs[_Rt_].SL[0]; -} - -void recADD_constv(int info, int creg, int vreg) -{ - assert( !(info&PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; - - if( g_cpuConstRegs[ creg ].UL[0] ) { - u32* ptempmem; - - ptempmem = _eeGetConstReg(creg); - if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); - PADDDMtoR(EEREC_D, (u32)ptempmem); - - _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); - } - else { - // just move and sign extend - if( EEINST_HASLIVE1(vreg) ) { - if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); - } - else { - _signExtendGPRMMXtoMMX(EEREC_D, _Rd_, mmreg, vreg); - } - } - } - else { - - if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && (!EEINST_ISLIVE1(_Rd_) || !g_cpuConstRegs[ creg ].UL[0]) ) { - int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - - if( EEINST_HASLIVE1(vreg) && EEINST_ISLIVE1(_Rd_) ) { - MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); - } - else { - if( g_cpuConstRegs[creg].UL[0] ) { - MOVDMtoMMX(mmreg, (u32)_eeGetConstReg(creg)); - PADDDMtoR(mmreg, (u32)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); - } - else { - if( EEINST_ISLIVE1(_Rd_) ) { - _signExtendMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); - } - else { - MOVDMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); - EEINST_RESETHASLIVE1(_Rd_); - } - } - } - } - else { - if( _Rd_ == vreg ) { - ADD32ItoM((int)&cpuRegs.GPR.r[_Rd_].UL[ 0 ], g_cpuConstRegs[creg].UL[0]); - if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); - else EEINST_RESETHASLIVE1(_Rd_); - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ] ); - if( g_cpuConstRegs[ creg ].UL[0] ) - ADD32ItoR( EAX, g_cpuConstRegs[ creg ].UL[0] ); - - if( EEINST_ISLIVE1(_Rd_) ) { - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - } - else { - EEINST_RESETHASLIVE1(_Rd_); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - } - } - } - } -} - -// s is constant -void recADD_consts(int info) -{ - recADD_constv(info, _Rs_, _Rt_); - EEINST_SETSIGNEXT(_Rd_); - EEINST_SETSIGNEXT(_Rt_); -} - -// t is constant -void recADD_constt(int info) -{ - recADD_constv(info, _Rt_, _Rs_); - EEINST_SETSIGNEXT(_Rd_); - EEINST_SETSIGNEXT(_Rs_); -} - -// nothing is constant -void recADD_(int info) -{ - assert( !(info&PROCESS_EE_XMM) ); - EEINST_SETSIGNEXT(_Rd_); - EEINST_SETSIGNEXT(_Rs_); - EEINST_SETSIGNEXT(_Rt_); - - if( info & PROCESS_EE_MMX ) { - - if( EEREC_D == EEREC_S ) PADDDRtoR(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) PADDDRtoR(EEREC_D, EEREC_S); - else { - MOVQRtoR(EEREC_D, EEREC_T); - PADDDRtoR(EEREC_D, EEREC_S); - } - - if( EEINST_ISLIVE1(_Rd_) ) { - // sign extend - _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); - } - else { - EEINST_RESETHASLIVE1(_Rd_); - } - } - else { - - if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && !EEINST_ISLIVE1(_Rd_) ) { - int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - - EEINST_RESETHASLIVE1(_Rd_); - MOVDMtoMMX(mmreg, (int)&cpuRegs.GPR.r[_Rs_].UL[0] ); - PADDDMtoR(mmreg, (int)&cpuRegs.GPR.r[_Rt_].UL[0] ); - } - else { - if( _Rd_ == _Rs_ ) { - if( _Rd_ == _Rt_ ) SHL32ItoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], 1); // mult by 2 - else { - MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); - ADD32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], ECX); - } - - if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); - else EEINST_RESETHASLIVE1(_Rd_); - - return; - } - else if( _Rd_ == _Rt_ ) { - EEINST_RESETHASLIVE1(_Rd_); - MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - ADD32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], ECX); - - if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); - else EEINST_RESETHASLIVE1(_Rd_); - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if( _Rs_ != _Rt_ ) ADD32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - else SHL32ItoR(EAX, 1); // mult by 2 - - if( EEINST_ISLIVE1(_Rd_) ) { - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - } - else { - EEINST_RESETHASLIVE1(_Rd_); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - } - } - } - } -} - -EERECOMPILE_CODE0(ADD, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); - -//// ADDU -void recADDU( void ) -{ - recADD( ); -} - -//// DADD -void recDADD_const( void ) -{ - g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SD[0] + g_cpuConstRegs[_Rt_].SD[0]; -} - -void recDADD_constv(int info, int creg, int vreg) -{ - assert( !(info&PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; - - if( g_cpuConstRegs[ creg ].UD[0] ) { - - if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); - PADDQMtoR(EEREC_D, (u32)_eeGetConstReg(creg)); - } - else { - if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); - } - } - else { - - if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { - int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - - MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); - if( g_cpuConstRegs[ creg ].UD[0] ) PADDQMtoR(mmreg, (u32)_eeGetConstReg(creg)); - } - else { - - if( g_cpuConstRegs[ creg ].UL[0] == 0 && g_cpuConstRegs[ creg ].UL[1] == 0 && _hasFreeMMXreg() ) { - // copy - int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - if( EEINST_ISLIVE1(_Rd_) ) MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); - else { - MOVDMtoMMX(mmreg, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); - EEINST_RESETHASLIVE1(_Rd_); - } - } - else { - if( _Rd_ == vreg ) { - - if( EEINST_ISLIVE1(_Rd_) && (g_cpuConstRegs[ creg ].UL[ 0 ] || g_cpuConstRegs[ creg ].UL[ 1 ]) ) { - ADD32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[ creg ].UL[ 0 ] ); - ADC32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[ creg ].UL[ 1 ] ); - } - else if( g_cpuConstRegs[ creg ].UL[ 0 ] ) { - EEINST_RESETHASLIVE1(_Rd_); - ADD32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[ creg ].UL[ 0 ] ); - } - - return; - } - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ] ); - - if( EEINST_ISLIVE1(_Rd_) ) - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 1 ] ); - - if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { - ADD32ItoR( EAX, g_cpuConstRegs[ creg ].UL[ 0 ] ); - if( EEINST_ISLIVE1(_Rd_) ) - ADC32ItoR( EDX, g_cpuConstRegs[ creg ].UL[ 1 ] ); - } - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - - if( EEINST_ISLIVE1(_Rd_) ) - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - - if( !EEINST_ISLIVE1(_Rd_) ) - EEINST_RESETHASLIVE1(_Rd_); - } - } - } -} - -void recDADD_consts(int info) -{ - recDADD_constv(info, _Rs_, _Rt_); -} - -void recDADD_constt(int info) -{ - recDADD_constv(info, _Rt_, _Rs_); -} - -void recDADD_(int info) -{ - assert( !(info&PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - - if( EEREC_D == EEREC_S ) PADDQRtoR(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) PADDQRtoR(EEREC_D, EEREC_S); - else { - MOVQRtoR(EEREC_D, EEREC_T); - PADDQRtoR(EEREC_D, EEREC_S); - } - } - else { - if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { - int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - - MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - if( _Rs_ != _Rt_ ) PADDQMtoR(mmreg, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); - else PSLLQItoR(mmreg, 1); // mult by 2 - } - else { - if( _Rd_ == _Rs_ || _Rd_ == _Rt_ ) { - int vreg = _Rd_ == _Rs_ ? _Rt_ : _Rs_; - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ] ); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 1 ] ); - ADD32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX); - if( EEINST_ISLIVE1(_Rd_) ) - ADC32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX); - else - EEINST_RESETHASLIVE1(_Rd_); - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); - ADD32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - if( EEINST_ISLIVE1(_Rd_) ) - ADC32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - - if( !EEINST_ISLIVE1(_Rd_) ) - EEINST_RESETHASLIVE1(_Rd_); - } - } - } -} - -EERECOMPILE_CODE0(DADD, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); - -//// DADDU -void recDADDU( void ) -{ - recDADD( ); -} - -//// SUB - -void recSUB_const() -{ - g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SL[0] - g_cpuConstRegs[_Rt_].SL[0]; -} - -void recSUB_consts(int info) -{ - assert( !(info&PROCESS_EE_XMM) ); - EEINST_SETSIGNEXT(_Rt_); - EEINST_SETSIGNEXT(_Rd_); - - if( info & PROCESS_EE_MMX ) { - if( g_cpuConstRegs[ _Rs_ ].UL[0] ) { - - if( EEREC_D != EEREC_T ) { - MOVQMtoR(EEREC_D, (u32)_eeGetConstReg(_Rs_)); - PSUBDRtoR(EEREC_D, EEREC_T); - - if( EEINST_ISLIVE1(_Rd_) ) _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); - else EEINST_RESETHASLIVE1(_Rd_); - } - else { - int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVDMtoMMX(t0reg, (u32)_eeGetConstReg(_Rs_)); - PSUBDRtoR(t0reg, EEREC_T); - - // swap mmx regs - mmxregs[t0reg] = mmxregs[EEREC_D]; - mmxregs[EEREC_D].inuse = 0; - - if( EEINST_ISLIVE1(_Rd_) ) _signExtendGPRtoMMX(t0reg, _Rd_, 0); - else EEINST_RESETHASLIVE1(_Rd_); - } - } - else { - // just move and sign extend - if( EEREC_D != EEREC_T ) { - PXORRtoR(EEREC_D, EEREC_D); - PSUBDRtoR(EEREC_D, EEREC_T); - - if( EEINST_ISLIVE1(_Rd_) ) _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); - else EEINST_RESETHASLIVE1(_Rd_); - } - else { - int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - PXORRtoR(t0reg, t0reg); - PSUBDRtoR(t0reg, EEREC_T); - - // swap mmx regs.. don't ask - mmxregs[t0reg] = mmxregs[EEREC_D]; - mmxregs[EEREC_D].inuse = 0; - - if( EEINST_ISLIVE1(_Rd_) ) _signExtendGPRtoMMX(t0reg, _Rd_, 0); - else EEINST_RESETHASLIVE1(_Rd_); - } - } - } - else { - if( _Rd_ == _Rt_ ) { - if( g_cpuConstRegs[ _Rs_ ].UL[ 0 ] ) SUB32ItoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], g_cpuConstRegs[ _Rs_ ].UL[ 0 ]); - NEG32M((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ]); - - if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); - else EEINST_RESETHASLIVE1(_Rd_); - } - else { - if( g_cpuConstRegs[ _Rs_ ].UL[ 0 ] ) { - MOV32ItoR( EAX, g_cpuConstRegs[ _Rs_ ].UL[ 0 ] ); - SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - NEG32R(EAX); - } - - if( EEINST_ISLIVE1(_Rd_) ) { - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - } - else { - EEINST_RESETHASLIVE1(_Rd_); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - } - } - } -} - -void recSUB_constt(int info) -{ - assert( !(info&PROCESS_EE_XMM) ); - EEINST_SETSIGNEXT(_Rs_); - EEINST_SETSIGNEXT(_Rd_); - - if( info & PROCESS_EE_MMX ) { - if( g_cpuConstRegs[ _Rt_ ].UL[0] ) { - - u32* ptempmem = _eeGetConstReg(_Rt_); - if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); - PSUBDMtoR(EEREC_D, (u32)ptempmem); - - _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); - } - else { - // just move and sign extend - if( EEINST_HASLIVE1(_Rs_) ) { - if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); - } - else { - _signExtendGPRMMXtoMMX(EEREC_D, _Rd_, EEREC_S, _Rs_); - } - } - } - else { - - if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && (!EEINST_ISLIVE1(_Rd_) || !g_cpuConstRegs[_Rt_].UL[0]) ) { - int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - - if( EEINST_HASLIVE1(_Rs_) && EEINST_ISLIVE1(_Rd_) ) { - MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - } - else { - if( g_cpuConstRegs[_Rt_].UL[0] ) { - MOVDMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - PSUBDMtoR(mmreg, (u32)_eeGetConstReg(_Rt_)); - } - else { - if( EEINST_ISLIVE1(_Rd_) ) { - _signExtendMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - } - else { - MOVDMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - EEINST_RESETHASLIVE1(_Rd_); - } - } - } - } - else { - if( _Rd_ == _Rs_ ) { - if( g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ) { - SUB32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], g_cpuConstRegs[ _Rt_ ].UL[ 0 ]); - - if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); - else EEINST_RESETHASLIVE1(_Rd_); - } - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if( g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ) - SUB32ItoR( EAX, g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ); - - if( EEINST_ISLIVE1(_Rd_) ) { - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - } - else { - EEINST_RESETHASLIVE1(_Rd_); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - } - } - } - } -} - -void recSUB_(int info) -{ - assert( !(info&PROCESS_EE_XMM) ); - EEINST_SETSIGNEXT(_Rs_); - EEINST_SETSIGNEXT(_Rt_); - EEINST_SETSIGNEXT(_Rd_); - - if( info & PROCESS_EE_MMX ) { - - if( EEREC_D == EEREC_S ) PSUBDRtoR(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) { - int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQRtoR(t0reg, EEREC_S); - PSUBDRtoR(t0reg, EEREC_T); - - // swap mmx regs.. don't ask - mmxregs[t0reg] = mmxregs[EEREC_D]; - mmxregs[EEREC_D].inuse = 0; - info = (info&~PROCESS_EE_SET_D(0xf))|PROCESS_EE_SET_D(t0reg); - } - else { - MOVQRtoR(EEREC_D, EEREC_S); - PSUBDRtoR(EEREC_D, EEREC_T); - } - - if( EEINST_ISLIVE1(_Rd_) ) { - // sign extend - _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); - } - else { - EEINST_RESETHASLIVE1(_Rd_); - } - } - else { - - if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && !EEINST_ISLIVE1(_Rd_)) { - int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - - EEINST_RESETHASLIVE1(_Rd_); - MOVDMtoMMX(mmreg, (int)&cpuRegs.GPR.r[_Rs_].UL[0] ); - PSUBDMtoR(mmreg, (int)&cpuRegs.GPR.r[_Rt_].UL[0] ); - } - else { - if( !EEINST_ISLIVE1(_Rd_) ) { - if( _Rd_ == _Rs_) { - EEINST_RESETHASLIVE1(_Rd_); - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - SUB32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - return; - } - } - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - - if( EEINST_ISLIVE1(_Rd_) ) { - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - } - else { - EEINST_RESETHASLIVE1(_Rd_); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - } - } - } -} - -EERECOMPILE_CODE0(SUB, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); - -//// SUBU -void recSUBU( void ) -{ - recSUB( ); -} - -//// DSUB -void recDSUB_const() -{ - g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SD[0] - g_cpuConstRegs[_Rt_].SD[0]; -} - -void recDSUB_consts(int info) -{ - assert( !(info&PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - - if( g_cpuConstRegs[ _Rs_ ].UD[0] ) { - - // flush - if( EEREC_D != EEREC_T ) { - MOVQMtoR(EEREC_D, (u32)_eeGetConstReg(_Rs_)); - PSUBQRtoR(EEREC_D, EEREC_T); - } - else { - int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQMtoR(t0reg, (u32)_eeGetConstReg(_Rs_)); - PSUBQRtoR(t0reg, EEREC_T); - - // swap mmx regs.. don't ask - mmxregs[t0reg] = mmxregs[EEREC_D]; - mmxregs[EEREC_D].inuse = 0; - } - } - else { - // just move and sign extend - if( EEREC_D != EEREC_T ) { - PXORRtoR(EEREC_D, EEREC_D); - PSUBQRtoR(EEREC_D, EEREC_T); - } - else { - int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - PXORRtoR(t0reg, t0reg); - PSUBQRtoR(t0reg, EEREC_T); - - // swap mmx regs.. don't ask - mmxregs[t0reg] = mmxregs[EEREC_D]; - mmxregs[EEREC_D].inuse = 0; - } - } - } - else { - if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { - int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - MOVQMtoR(mmreg, (u32)_eeGetConstReg(_Rs_)); - PSUBQMtoR(mmreg, (u32)&cpuRegs.GPR.r[_Rt_].UL[ 0 ]); - } - else { - if( g_cpuConstRegs[ _Rs_ ].UL[ 0 ] || g_cpuConstRegs[ _Rs_ ].UL[ 1 ] ) { - MOV32ItoR( EAX, g_cpuConstRegs[ _Rs_ ].UL[ 0 ] ); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32ItoR( EDX, g_cpuConstRegs[ _Rs_ ].UL[ 1 ] ); - SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - if( EEINST_ISLIVE1(_Rd_) ) - SBB32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - - if( !EEINST_ISLIVE1(_Rd_) ) - EEINST_RESETHASLIVE1(_Rd_); - } - else { - - if( _Rd_ == _Rt_ ) { - // negate _Rt_ all in memory - if( EEINST_ISLIVE1(_Rd_) ) { - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - NEG32M((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); - ADC32ItoR(EDX, 0); - NEG32R(EDX); - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX); - } - else { - EEINST_RESETHASLIVE1(_Rd_); - NEG32M((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ]); - } - return; - } - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - // take negative of 64bit number - NEG32R(EAX); - - if( EEINST_ISLIVE1(_Rd_) ) { - ADC32ItoR(EDX, 0); - NEG32R(EDX); - } - else { - EEINST_RESETHASLIVE1(_Rd_); - } - } - - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - else { - EEINST_RESETHASLIVE1(_Rd_); - } - } - } -} - -void recDSUB_constt(int info) -{ - assert( !(info&PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - - if( g_cpuConstRegs[ _Rt_ ].UD[0] ) { - - if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); - PSUBQMtoR(EEREC_D, (u32)_eeGetConstReg(_Rt_)); - } - else { - if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); - } - } - else { - if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { - int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - if( g_cpuConstRegs[_Rt_].UD[0] ) PSUBQMtoR(mmreg, (u32)_eeGetConstReg(_Rt_)); - } - else { - - if( _Rd_ == _Rs_ ) { - if( EEINST_ISLIVE1(_Rd_) && (g_cpuConstRegs[ _Rt_ ].UL[ 0 ] || g_cpuConstRegs[ _Rt_ ].UL[ 1 ]) ) { - SUB32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ); - SBB32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[ _Rt_ ].UL[ 1 ] ); - } - else if( g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ) { - EEINST_RESETHASLIVE1(_Rd_); - SUB32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ); - } - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); - - if( g_cpuConstRegs[ _Rt_ ].UL[ 0 ] || g_cpuConstRegs[ _Rt_ ].UL[ 1 ] ) { - SUB32ItoR( EAX, g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ); - if( EEINST_ISLIVE1(_Rd_) ) - SBB32ItoR( EDX, g_cpuConstRegs[ _Rt_ ].UL[ 1 ] ); - } - - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - else - EEINST_RESETHASLIVE1(_Rd_); - } - } - } -} - -void recDSUB_(int info) -{ - assert( !(info&PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - - if( EEREC_D == EEREC_S ) PSUBQRtoR(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) { - int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQRtoR(t0reg, EEREC_S); - PSUBQRtoR(t0reg, EEREC_T); - - // swap mmx regs.. don't ask - mmxregs[t0reg] = mmxregs[EEREC_D]; - mmxregs[EEREC_D].inuse = 0; - } - else { - MOVQRtoR(EEREC_D, EEREC_S); - PSUBQRtoR(EEREC_D, EEREC_T); - } - } - else { - if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { - int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[_Rs_].UL[ 0 ]); - PSUBQMtoR(mmreg, (int)&cpuRegs.GPR.r[_Rt_].UL[ 0 ]); - } - else { - if( _Rd_ == _Rs_ ) { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - SUB32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - if( EEINST_ISLIVE1(_Rd_) ) - SBB32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - else - EEINST_RESETHASLIVE1(_Rd_); - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); - SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - if( EEINST_ISLIVE1(_Rd_) ) - SBB32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - else - EEINST_RESETHASLIVE1(_Rd_); - } - } - } -} - -EERECOMPILE_CODE0(DSUB, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); - -//// DSUBU -void recDSUBU( void ) -{ - recDSUB( ); -} - -//// AND -void recAND_const() -{ - g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] & g_cpuConstRegs[_Rt_].UD[0]; -} - -void recAND_constv(int info, int creg, int vreg) -{ - assert( !(info & PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; - - if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { - _flushConstReg(creg); - if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); - PANDMtoR(EEREC_D, (u32)&cpuRegs.GPR.r[creg].UL[0] ); - } - else { - PXORRtoR(EEREC_D, EEREC_D); - } - } - else { - - if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) || (_Rd_ != vreg && _hasFreeMMXreg()) ) { - int rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - - MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[vreg].UL[0] ); - PANDMtoR(rdreg, (u32)_eeGetConstReg(creg) ); - } - else { - if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { - - if( _Rd_ == vreg ) { - AND32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[0], g_cpuConstRegs[creg].UL[0]); - if( EEINST_ISLIVE1(_Rd_) ) { - if( g_cpuConstRegs[creg].UL[1] != 0xffffffff ) AND32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[1], g_cpuConstRegs[creg].UL[1]); - } - else - EEINST_RESETHASLIVE1(_Rd_); - } - else { - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); - AND32ItoR(EAX, g_cpuConstRegs[ creg ].UL[0]); - if( EEINST_ISLIVE1(_Rd_) ) - AND32ItoR(ECX, g_cpuConstRegs[ creg ].UL[1]); - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); - else - EEINST_RESETHASLIVE1(_Rd_); - } - } - else { - MOV32ItoM((int)&cpuRegs.GPR.r[ _Rd_ ], 0); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32ItoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, 0); - else - EEINST_RESETHASLIVE1(_Rd_); - } - } - } -} - -void recAND_consts(int info) -{ - recAND_constv(info, _Rs_, _Rt_); -} - -void recAND_constt(int info) -{ - recAND_constv(info, _Rt_, _Rs_); -} - -void recLogicalOp(int info, int op) -{ - assert( !(info & PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - if( EEREC_D == EEREC_S ) LogicalOpRtoR(EEREC_D, EEREC_T, op); - else if( EEREC_D == EEREC_T ) LogicalOpRtoR(EEREC_D, EEREC_S, op); - else { - MOVQRtoR(EEREC_D, EEREC_S); - LogicalOpRtoR(EEREC_D, EEREC_T, op); - } - } - else if( (g_pCurInstInfo->regs[_Rs_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { - int rsreg, rtreg, rdreg; - _addNeededMMXreg(MMX_GPR+_Rs_); - _addNeededMMXreg(MMX_GPR+_Rt_); - _addNeededMMXreg(MMX_GPR+_Rd_); - - rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - rsreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rs_, MODE_READ); - rtreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_READ); - SetMMXstate(); - - if( rdreg == rsreg ) { - if( rtreg >= 0 ) LogicalOpRtoR(rdreg, rtreg, op); - else LogicalOpMtoR(rdreg, (int)&cpuRegs.GPR.r[ _Rt_ ], op); - } - else { - if( rdreg != rtreg ) { - if( rtreg >= 0 ) MOVQRtoR(rdreg, rtreg); - else MOVQMtoR(rdreg, (int)&cpuRegs.GPR.r[ _Rt_ ]); - } - - if( rsreg >= 0 ) LogicalOpRtoR(rdreg, rsreg, op); - else LogicalOpMtoR(rdreg, (int)&cpuRegs.GPR.r[ _Rs_ ], op); - } - } - else { - if( _Rd_ == _Rs_ || _Rd_ == _Rt_ ) { - int vreg = _Rd_ == _Rs_ ? _Rt_ : _Rs_; - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); - LogicalOp32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX, op ); - if( EEINST_ISLIVE1(_Rd_) ) - LogicalOp32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ] + 4, EDX, op ); - if( op == 3 ) { - NOT32M((int)&cpuRegs.GPR.r[ _Rd_ ]); - if( EEINST_ISLIVE1(_Rd_) ) - NOT32M((int)&cpuRegs.GPR.r[ _Rd_ ]+4); - } - - if( !EEINST_ISLIVE1(_Rd_) ) EEINST_RESETHASLIVE1(_Rd_); - } - else { - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ]); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ] + 4 ); - LogicalOp32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rt_ ], op ); - if( EEINST_ISLIVE1(_Rd_) ) - LogicalOp32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rt_ ] + 4, op ); - - if( op == 3 ) { - NOT32R(EAX); - if( EEINST_ISLIVE1(_Rd_) ) - NOT32R(ECX); - } - - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); - else - EEINST_RESETHASLIVE1(_Rd_); - } - } -} - -void recAND_(int info) -{ - recLogicalOp(info, 0); -} - -EERECOMPILE_CODE0(AND, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); - -//// OR -void recOR_const() -{ - g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] | g_cpuConstRegs[_Rt_].UD[0]; -} - -void recOR_constv(int info, int creg, int vreg) -{ - assert( !(info & PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; - - if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { - _flushConstReg(creg); - if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); - PORMtoR(EEREC_D, (u32)&cpuRegs.GPR.r[creg].UL[0] ); - } - else { - if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); - } - } - else { - - if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) || (_Rd_ != vreg && _hasFreeMMXreg()) ) { - int rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - - MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[vreg].UL[0] ); - - if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { - PORMtoR(rdreg, (u32)_eeGetConstReg(creg) ); - } - } - else { - if( _Rd_ == vreg ) { - OR32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[0], g_cpuConstRegs[creg].UL[0]); - if( EEINST_ISLIVE1(_Rd_) ) { - if( g_cpuConstRegs[creg].UL[1] ) OR32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[1], g_cpuConstRegs[creg].UL[1]); - } - else - EEINST_RESETHASLIVE1(_Rd_); - } - else { - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); - - if( g_cpuConstRegs[ creg ].UL[0] ) OR32ItoR(EAX, g_cpuConstRegs[ creg ].UL[0]); - if( g_cpuConstRegs[ creg ].UL[1] && EEINST_ISLIVE1(_Rd_) ) OR32ItoR(ECX, g_cpuConstRegs[ creg ].UL[1]); - - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); - else - EEINST_RESETHASLIVE1(_Rd_); - } - } - } -} - -void recOR_consts(int info) -{ - recOR_constv(info, _Rs_, _Rt_); -} - -void recOR_constt(int info) -{ - recOR_constv(info, _Rt_, _Rs_); -} - -void recOR_(int info) -{ - recLogicalOp(info, 1); -} - -EERECOMPILE_CODE0(OR, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); - -//// XOR -void recXOR_const() -{ - g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] ^ g_cpuConstRegs[_Rt_].UD[0]; -} - -void recXOR_constv(int info, int creg, int vreg) -{ - assert( !(info & PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; - - if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { - _flushConstReg(creg); - if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); - PXORMtoR(EEREC_D, (u32)&cpuRegs.GPR.r[creg].UL[0] ); - } - else { - if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); - } - } - else { - - if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) || (_Rd_ != vreg && _hasFreeMMXreg()) ) { - int rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[vreg].UL[0] ); - - if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { - PXORMtoR(rdreg, (u32)_eeGetConstReg(creg) ); - } - } - else { - if( _Rd_ == vreg ) { - XOR32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[0], g_cpuConstRegs[creg].UL[0]); - if( EEINST_ISLIVE1(_Rd_) ) { - if( g_cpuConstRegs[creg].UL[1] ) XOR32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[1], g_cpuConstRegs[creg].UL[1]); - } - else - EEINST_RESETHASLIVE1(_Rd_); - } - else { - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); - - if( g_cpuConstRegs[ creg ].UL[0] ) XOR32ItoR(EAX, g_cpuConstRegs[ creg ].UL[0]); - if( g_cpuConstRegs[ creg ].UL[1] && EEINST_ISLIVE1(_Rd_) ) XOR32ItoR(ECX, g_cpuConstRegs[ creg ].UL[1]); - - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); - else - EEINST_RESETHASLIVE1(_Rd_); - } - } - } -} - -void recXOR_consts(int info) -{ - recXOR_constv(info, _Rs_, _Rt_); -} - -void recXOR_constt(int info) -{ - recXOR_constv(info, _Rt_, _Rs_); -} - -void recXOR_(int info) -{ - recLogicalOp(info, 2); -} - -EERECOMPILE_CODE0(XOR, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); - -//// NOR -void recNOR_const() -{ - g_cpuConstRegs[_Rd_].UD[0] =~(g_cpuConstRegs[_Rs_].UD[0] | g_cpuConstRegs[_Rt_].UD[0]); -} - -void recNOR_constv(int info, int creg, int vreg) -{ - assert( !(info & PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; - int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - - if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { - if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); - PORMtoR(EEREC_D, (u32)_eeGetConstReg(creg)); - } - else { - if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); - } - - // take the NOT - PCMPEQDRtoR( t0reg,t0reg); - PXORRtoR( EEREC_D,t0reg); - _freeMMXreg(t0reg); - } - else { - - if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) || (_Rd_ != vreg && _hasFreeMMXreg()) ) { - int rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - - SetMMXstate(); - - MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[vreg].UL[0] ); - PCMPEQDRtoR( t0reg,t0reg); - if( g_cpuConstRegs[ creg ].UD[0] ) PORMtoR(rdreg, (u32)_eeGetConstReg(creg) ); - - // take the NOT - PXORRtoR( rdreg,t0reg); - - _freeMMXreg(t0reg); - } - else { - if( _Rd_ == vreg ) { - NOT32M((int)&cpuRegs.GPR.r[ vreg ].UL[0]); - if( EEINST_ISLIVE1(_Rd_) ) NOT32M((int)&cpuRegs.GPR.r[ vreg ].UL[1]); - - if( g_cpuConstRegs[creg].UL[0] ) AND32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[0], ~g_cpuConstRegs[creg].UL[0]); - if( EEINST_ISLIVE1(_Rd_) ) { - if( g_cpuConstRegs[creg].UL[1] ) AND32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[1], ~g_cpuConstRegs[creg].UL[1]); - } - else - EEINST_RESETHASLIVE1(_Rd_); - } - else { - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); - if( g_cpuConstRegs[ creg ].UL[0] ) OR32ItoR(EAX, g_cpuConstRegs[ creg ].UL[0]); - if( g_cpuConstRegs[ creg ].UL[1] && EEINST_ISLIVE1(_Rd_) ) OR32ItoR(ECX, g_cpuConstRegs[ creg ].UL[1]); - NOT32R(EAX); - if( EEINST_ISLIVE1(_Rd_) ) - NOT32R(ECX); - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); - else - EEINST_RESETHASLIVE1(_Rd_); - } - } - } -} - -void recNOR_consts(int info) -{ - recNOR_constv(info, _Rs_, _Rt_); -} - -void recNOR_constt(int info) -{ - recNOR_constv(info, _Rt_, _Rs_); -} - -void recNOR_(int info) -{ - recLogicalOp(info, 3); -} - -EERECOMPILE_CODE0(NOR, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); - -//// SLT - test with silent hill, lemans -void recSLT_const() -{ - g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SD[0] < g_cpuConstRegs[_Rt_].SD[0]; -} - -static u32 s_sltconst = 0x80000000; -static u32 s_sltconst64[2] = {0, 0x80000000}; -u32 s_sltone = 1; - -void recSLTs_consts(int info, int sign) -{ - assert( !(info & PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - - if( _Rs_ == _Rt_ ) { - PXORRtoR(EEREC_D, EEREC_D); - return; - } - - if( g_cpuConstRegs[_Rs_].UL[1] == (g_cpuConstRegs[_Rs_].SL[0]<0?0xffffffff:0) && EEINST_ISSIGNEXT(_Rt_) ) { - // just compare the lower values - if( sign ) { - if( EEREC_D != EEREC_T ) MOVQRtoR(EEREC_D, EEREC_T); - PCMPGTDMtoR(EEREC_D, (u32)_eeGetConstReg(_Rs_)); - - PUNPCKLDQRtoR(EEREC_D, EEREC_D); - PSRLQItoR(EEREC_D, 63); - } - else { - u32* ptempmem = recAllocStackMem(8,4); - ptempmem[0] = g_cpuConstRegs[_Rs_].UL[0]^0x80000000; - ptempmem[1] = 0; - - if( EEREC_D != EEREC_T ) { - MOVDMtoMMX(EEREC_D, (u32)&s_sltconst); - PXORRtoR(EEREC_D, EEREC_T); - } - else { - PXORMtoR(EEREC_D, (u32)&s_sltconst); - } - - PCMPGTDMtoR(EEREC_D, (u32)ptempmem); - - PUNPCKLDQRtoR(EEREC_D, EEREC_D); - PSRLQItoR(EEREC_D, 63); - } - - return; - } - else { - // need to compare total 64 bit value - if( info & PROCESS_EE_MODEWRITET ) { - MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_], EEREC_T); - if( mmxregs[EEREC_T].reg == MMX_GPR+_Rt_ ) mmxregs[EEREC_T].mode &= ~MODE_WRITE; - } - - // fall through - mmxregs[EEREC_D].mode |= MODE_WRITE; // in case EEREC_D was just flushed - } - } - - if( info & PROCESS_EE_MMX ) PXORRtoR(EEREC_D, EEREC_D); - else XOR32RtoR(EAX, EAX); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); - if( sign ) { - j8Ptr[0] = JL8( 0 ); - j8Ptr[2] = JG8( 0 ); - } - else { - j8Ptr[0] = JB8( 0 ); - j8Ptr[2] = JA8( 0 ); - } - - CMP32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); - j8Ptr[1] = JBE8(0); - - x86SetJ8(j8Ptr[2]); - if( info & PROCESS_EE_MMX ) MOVDMtoMMX(EEREC_D, (u32)&s_sltone); - else MOV32ItoR(EAX, 1); - - x86SetJ8(j8Ptr[0]); - x86SetJ8(j8Ptr[1]); - - if( !(info & PROCESS_EE_MMX) ) { - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - if( EEINST_ISLIVE1(_Rd_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); - else EEINST_RESETHASLIVE1(_Rd_); - } -} - -// SLT with one operand coming from mem (compares only low 32 bits) -void recSLTmemconstt(int regd, int regs, u32 mem, int sign) -{ - // just compare the lower values - int t0reg; - - if( sign ) { - if( regd == regs ) { - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQMtoR(t0reg, mem); - PCMPGTDRtoR(t0reg, regs); - - PUNPCKLDQRtoR(t0reg, t0reg); - PSRLQItoR(t0reg, 63); - - // swap regs - mmxregs[t0reg] = mmxregs[regd]; - mmxregs[regd].inuse = 0; - } - else { - MOVQMtoR(regd, mem); - PCMPGTDRtoR(regd, regs); - - PUNPCKLDQRtoR(regd, regd); - PSRLQItoR(regd, 63); - } - } - else { - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - - if( regd == regs ) { - MOVQMtoR(t0reg, mem); - PXORMtoR(regs, (u32)&s_sltconst); - PCMPGTDRtoR(t0reg, regs); - - PUNPCKLDQRtoR(t0reg, t0reg); - PSRLQItoR(t0reg, 63); - - // swap regs - mmxregs[t0reg] = mmxregs[regd]; - mmxregs[regd].inuse = 0; - } - else { - MOVQRtoR(t0reg, regs); - MOVQMtoR(regd, mem); - PXORMtoR(t0reg, (u32)&s_sltconst); - PCMPGTDRtoR(regd, t0reg); - - PUNPCKLDQRtoR(regd, regd); - PSRLQItoR(regd, 63); - _freeMMXreg(t0reg); - } - } -} - -void recSLTs_constt(int info, int sign) -{ - assert( !(info & PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - if( _Rs_ == _Rt_ ) { - PXORRtoR(EEREC_D, EEREC_D); - return; - } - - if( EEINST_ISSIGNEXT(_Rs_) && g_cpuConstRegs[_Rt_].UL[1] == (g_cpuConstRegs[_Rt_].SL[0]<0?0xffffffff:0) ) { - // just compare the lower values - if( sign ) { - recSLTmemconstt(EEREC_D, EEREC_S, (u32)_eeGetConstReg(_Rt_), 1); - } - else { - u32* ptempmem = recAllocStackMem(8,4); - ptempmem[0] = g_cpuConstRegs[_Rt_].UL[0]^0x80000000; - ptempmem[1] = 0; - - recSLTmemconstt(EEREC_D, EEREC_S, (u32)ptempmem, 0); - } - - return; - } - else { - // need to compare total 64 bit value - if( info & PROCESS_EE_MODEWRITES ) { - MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_], EEREC_S); - if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; - } - mmxregs[EEREC_D].mode |= MODE_WRITE; // in case EEREC_D was just flushed - - // fall through - } - } - - if( info & PROCESS_EE_MMX ) MOVDMtoMMX(EEREC_D, (u32)&s_sltone); - else MOV32ItoR(EAX, 1); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1]); - if( sign ) { - j8Ptr[0] = JL8( 0 ); - j8Ptr[2] = JG8( 0 ); - } - else { - j8Ptr[0] = JB8( 0 ); - j8Ptr[2] = JA8( 0 ); - } - - CMP32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0]); - j8Ptr[1] = JB8(0); - - x86SetJ8(j8Ptr[2]); - if( info & PROCESS_EE_MMX ) PXORRtoR(EEREC_D, EEREC_D); - else XOR32RtoR(EAX, EAX); - - x86SetJ8(j8Ptr[0]); - x86SetJ8(j8Ptr[1]); - - if( !(info & PROCESS_EE_MMX) ) { - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - if( EEINST_ISLIVE1(_Rd_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); - else EEINST_RESETHASLIVE1(_Rd_); - } -} - -void recSLTs_(int info, int sign) -{ - if( info & PROCESS_EE_MMX ) MOVDMtoMMX(EEREC_D, (u32)&s_sltone); - else MOV32ItoR(EAX, 1); - - MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); - CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ]); - - if( sign ) { - j8Ptr[0] = JL8( 0 ); - j8Ptr[2] = JG8( 0 ); - } - else { - j8Ptr[0] = JB8( 0 ); - j8Ptr[2] = JA8( 0 ); - } - - MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); - j8Ptr[1] = JB8(0); - - x86SetJ8(j8Ptr[2]); - if( info & PROCESS_EE_MMX ) PXORRtoR(EEREC_D, EEREC_D); - else XOR32RtoR(EAX, EAX); - - x86SetJ8(j8Ptr[0]); - x86SetJ8(j8Ptr[1]); - - if( !(info & PROCESS_EE_MMX) ) { - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - if( EEINST_ISLIVE1(_Rd_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); - else EEINST_RESETHASLIVE1(_Rd_); - } -} - -void recSLT_consts(int info) -{ - recSLTs_consts(info, 1); -} - -void recSLT_constt(int info) -{ - recSLTs_constt(info, 1); -} - -void recSLT_(int info) -{ - int t0reg; - assert( !(info & PROCESS_EE_XMM) ); - - if( !(info & PROCESS_EE_MMX) ) { - recSLTs_(info, 1); - return; - } - - if( !EEINST_ISSIGNEXT(_Rs_) || !EEINST_ISSIGNEXT(_Rt_) ) { - // need to compare total 64 bit value - if( info & PROCESS_EE_MODEWRITES ) { - MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_], EEREC_S); - if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; - } - if( info & PROCESS_EE_MODEWRITET ) { - MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_], EEREC_T); - if( mmxregs[EEREC_T].reg == MMX_GPR+_Rt_ ) mmxregs[EEREC_T].mode &= ~MODE_WRITE; - } - mmxregs[EEREC_D].mode |= MODE_WRITE; // in case EEREC_D was just flushed - recSLTs_(info, 1); - return; - } - - if( EEREC_S == EEREC_T ) { - PXORRtoR(EEREC_D, EEREC_D); - return; - } - - // just compare the lower values - if( EEREC_D == EEREC_S ) { - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQRtoR(t0reg, EEREC_T); - PCMPGTDRtoR(t0reg, EEREC_S); - - PUNPCKLDQRtoR(t0reg, t0reg); - PSRLQItoR(t0reg, 63); - - // swap regs - mmxregs[t0reg] = mmxregs[EEREC_D]; - mmxregs[EEREC_D].inuse = 0; - } - else { - if( EEREC_D != EEREC_T ) MOVQRtoR(EEREC_D, EEREC_T); - PCMPGTDRtoR(EEREC_D, EEREC_S); - - PUNPCKLDQRtoR(EEREC_D, EEREC_D); - PSRLQItoR(EEREC_D, 63); - } -} - -EERECOMPILE_CODE0(SLT, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); - -// SLTU - test with silent hill, lemans -void recSLTU_const() -{ - g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] < g_cpuConstRegs[_Rt_].UD[0]; -} - -void recSLTU_consts(int info) -{ - recSLTs_consts(info, 0); - EEINST_SETSIGNEXT(_Rd_); -} - -void recSLTU_constt(int info) -{ - recSLTs_constt(info, 0); - EEINST_SETSIGNEXT(_Rd_); -} - -void recSLTU_(int info) -{ - int t1reg; - - assert( !(info & PROCESS_EE_XMM) ); - EEINST_SETSIGNEXT(_Rd_); - - if( !(info & PROCESS_EE_MMX) ) { - recSLTs_(info, 0); - return; - } - - if( EEREC_S == EEREC_T ) { - PXORRtoR(EEREC_D, EEREC_D); - return; - } - - if( !EEINST_ISSIGNEXT(_Rs_) || !EEINST_ISSIGNEXT(_Rt_) ) { - // need to compare total 64 bit value - if( info & PROCESS_EE_MODEWRITES ) { - MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_], EEREC_S); - if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; - } - if( info & PROCESS_EE_MODEWRITET ) { - MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_], EEREC_T); - if( mmxregs[EEREC_T].reg == MMX_GPR+_Rt_ ) mmxregs[EEREC_T].mode &= ~MODE_WRITE; - } - mmxregs[EEREC_D].mode |= MODE_WRITE; // in case EEREC_D was just flushed - recSLTs_(info, 0); - return; - } - - t1reg = _allocMMXreg(-1, MMX_TEMP, 0); - - MOVDMtoMMX(t1reg, (u32)&s_sltconst); - - if( EEREC_D == EEREC_S ) { - PXORRtoR(EEREC_S, t1reg); - PXORRtoR(t1reg, EEREC_T); - PCMPGTDRtoR(t1reg, EEREC_S); - - PUNPCKLDQRtoR(t1reg, t1reg); - PSRLQItoR(t1reg, 63); - - // swap regs - mmxregs[t1reg] = mmxregs[EEREC_D]; - mmxregs[EEREC_D].inuse = 0; - } - else { - if( EEREC_D != EEREC_T ) { - MOVDMtoMMX(EEREC_D, (u32)&s_sltconst); - PXORRtoR(t1reg, EEREC_S); - PXORRtoR(EEREC_D, EEREC_T); - } - else { - PXORRtoR(EEREC_D, t1reg); - PXORRtoR(t1reg, EEREC_S); - } - - PCMPGTDRtoR(EEREC_D, t1reg); - - PUNPCKLDQRtoR(EEREC_D, EEREC_D); - PSRLQItoR(EEREC_D, 63); - - _freeMMXreg(t1reg); - } -} - -EERECOMPILE_CODE0(SLTU, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); - -#else - -//////////////////////////////////////////////////// -void recADD( void ) -{ - if ( ! _Rd_ ) - { - return; - } - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - ADD32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); -} - -//////////////////////////////////////////////////// -void recADDU( void ) -{ - recADD( ); -} - -//////////////////////////////////////////////////// -void recDADD( void ) -{ - if ( ! _Rd_ ) - { - return; - } - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); - ADD32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - ADC32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); -} - -//////////////////////////////////////////////////// -void recDADDU( void ) -{ - recDADD( ); -} - -//////////////////////////////////////////////////// -void recSUB( void ) -{ - if ( ! _Rd_ ) return; - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - -} - -//////////////////////////////////////////////////// -void recSUBU( void ) -{ - recSUB( ); -} - -//////////////////////////////////////////////////// -void recDSUB( void ) -{ - if ( ! _Rd_ ) return; - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); - SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - SBB32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - -} - -//////////////////////////////////////////////////// -void recDSUBU( void ) -{ - recDSUB( ); -} - -//////////////////////////////////////////////////// -void recAND( void ) -{ - if ( ! _Rd_ ) - { - return; - } - if ( ( _Rt_ == 0 ) || ( _Rs_ == 0 ) ) - { - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], 0 ); - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); - } - else - { - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); - MOVQMtoR( MM1, (int)&cpuRegs.GPR.r[ _Rt_ ] ); - PANDRtoR( MM0, MM1); - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); - SetMMXstate(); - } - -} - -//////////////////////////////////////////////////// -void recOR( void ) -{ - if ( ! _Rd_ ) - { - return; - } - - if ( ( _Rs_ == 0 ) && ( _Rt_ == 0 ) ) - { - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], 0x0 ); - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0x0 ); - } - else if ( _Rs_ == 0 ) - { - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); - SetMMXstate(); - } - else if ( _Rt_ == 0 ) - { - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); - SetMMXstate(); - } - else - { - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); - MOVQMtoR( MM1, (int)&cpuRegs.GPR.r[ _Rt_ ] ); - PORRtoR( MM0, MM1 ); - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); - SetMMXstate(); - } -} - -//////////////////////////////////////////////////// -void recXOR( void ) -{ - if ( ! _Rd_ ) - { - return; - } - - if ( ( _Rs_ == 0 ) && ( _Rt_ == 0 ) ) - { - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ],0x0); - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ],0x0); - return; - } - - if ( _Rs_ == 0 ) - { - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); - SetMMXstate(); - return; - } - - if ( _Rt_ == 0 ) - { - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); - SetMMXstate(); - return; - } - - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); - MOVQMtoR( MM1, (int)&cpuRegs.GPR.r[ _Rt_ ] ); - PXORRtoR( MM0, MM1); - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); - SetMMXstate(); -} - -//////////////////////////////////////////////////// -void recNOR( void ) -{ - if ( ! _Rd_ ) - { - return; - } - - if ( ( _Rs_ == 0 ) && ( _Rt_ == 0 ) ) - { - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ],0xffffffff); - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ],0xffffffff); - return; - } - - if ( _Rs_ == 0 ) - { - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); - PCMPEQDRtoR( MM1,MM1); - PXORRtoR( MM0,MM1); - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ],MM0); - SetMMXstate(); - return; - } - - if ( _Rt_ == 0 ) - { - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); - PCMPEQDRtoR( MM1,MM1); - PXORRtoR( MM0,MM1); - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ],MM0); - SetMMXstate(); - return; - } - - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); - PCMPEQDRtoR( MM1,MM1); - PORMtoR( MM0,(int)&cpuRegs.GPR.r[ _Rt_ ] ); - PXORRtoR( MM0,MM1); - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ],MM0); - SetMMXstate(); -} - -//////////////////////////////////////////////////// -// test with silent hill, lemans -void recSLT( void ) -{ - if ( ! _Rd_ ) - return; - - MOV32ItoR(EAX, 1); - - if( _Rs_ == 0 ) { - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0); - j8Ptr[0] = JG8( 0 ); - j8Ptr[2] = JL8( 0 ); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], 0 ); - j8Ptr[1] = JA8(0); - - x86SetJ8(j8Ptr[2]); - XOR32RtoR(EAX, EAX); - } - else if( _Rt_ == 0 ) { - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0); - j8Ptr[0] = JL8( 0 ); - j8Ptr[2] = JG8( 0 ); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0); - j8Ptr[1] = JB8(0); - - x86SetJ8(j8Ptr[2]); - XOR32RtoR(EAX, EAX); - } - else { - MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); - CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ]); - j8Ptr[0] = JL8( 0 ); - j8Ptr[2] = JG8( 0 ); - - MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); - j8Ptr[1] = JB8(0); - - x86SetJ8(j8Ptr[2]); - XOR32RtoR(EAX, EAX); - } - - x86SetJ8(j8Ptr[0]); - x86SetJ8(j8Ptr[1]); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); -} - -//////////////////////////////////////////////////// -void recSLTU( void ) -{ - MOV32ItoR(EAX, 1); - - if( _Rs_ == 0 ) { - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0); - j8Ptr[0] = JA8( 0 ); - j8Ptr[2] = JB8( 0 ); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], 0 ); - j8Ptr[1] = JA8(0); - - x86SetJ8(j8Ptr[2]); - XOR32RtoR(EAX, EAX); - } - else if( _Rt_ == 0 ) { - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0); - j8Ptr[0] = JB8( 0 ); - j8Ptr[2] = JA8( 0 ); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0); - j8Ptr[1] = JB8(0); - - x86SetJ8(j8Ptr[2]); - XOR32RtoR(EAX, EAX); - } - else { - MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); - CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ]); - j8Ptr[0] = JB8( 0 ); - j8Ptr[2] = JA8( 0 ); - - MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); - j8Ptr[1] = JB8(0); - - x86SetJ8(j8Ptr[2]); - XOR32RtoR(EAX, EAX); - } - - x86SetJ8(j8Ptr[0]); - x86SetJ8(j8Ptr[1]); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); -} - -#endif - -} } } +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "R5900OpcodeTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl +{ + +/********************************************************* +* Register arithmetic * +* Format: OP rd, rs, rt * +*********************************************************/ + +// NOTE: The reason ADD/SUB/etc are so large is because they are very commonly +// used and recompiler needs to cover ALL possible usages to minimize code size (zerofrog) + +#ifndef ARITHMETIC_RECOMPILE + +namespace Interp = R5900::Interpreter::OpcodeImpl; + +REC_FUNC(ADD); +REC_FUNC(ADDU); +REC_FUNC(DADD); +REC_FUNC(DADDU); +REC_FUNC(SUB); +REC_FUNC(SUBU); +REC_FUNC(DSUB); +REC_FUNC(DSUBU); +REC_FUNC(AND); +REC_FUNC(OR); +REC_FUNC(XOR); +REC_FUNC(NOR); +REC_FUNC(SLT); +REC_FUNC(SLTU); + +#elif defined(EE_CONST_PROP) + +//// ADD +void recADD_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SL[0] + g_cpuConstRegs[_Rt_].SL[0]; +} + +void recADD_constv(int info, int creg, int vreg) +{ + assert( !(info&PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; + + if( g_cpuConstRegs[ creg ].UL[0] ) { + u32* ptempmem; + + ptempmem = _eeGetConstReg(creg); + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + PADDDMtoR(EEREC_D, (u32)ptempmem); + + _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); + } + else { + // just move and sign extend + if( EEINST_HASLIVE1(vreg) ) { + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + } + else { + _signExtendGPRMMXtoMMX(EEREC_D, _Rd_, mmreg, vreg); + } + } + } + else { + + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && (!EEINST_ISLIVE1(_Rd_) || !g_cpuConstRegs[ creg ].UL[0]) ) { + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + + if( EEINST_HASLIVE1(vreg) && EEINST_ISLIVE1(_Rd_) ) { + MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); + } + else { + if( g_cpuConstRegs[creg].UL[0] ) { + MOVDMtoMMX(mmreg, (u32)_eeGetConstReg(creg)); + PADDDMtoR(mmreg, (u32)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); + } + else { + if( EEINST_ISLIVE1(_Rd_) ) { + _signExtendMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); + } + else { + MOVDMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); + EEINST_RESETHASLIVE1(_Rd_); + } + } + } + } + else { + if( _Rd_ == vreg ) { + ADD32ItoM((int)&cpuRegs.GPR.r[_Rd_].UL[ 0 ], g_cpuConstRegs[creg].UL[0]); + if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); + else EEINST_RESETHASLIVE1(_Rd_); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ] ); + if( g_cpuConstRegs[ creg ].UL[0] ) + ADD32ItoR( EAX, g_cpuConstRegs[ creg ].UL[0] ); + + if( EEINST_ISLIVE1(_Rd_) ) { + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + } + } + } + } +} + +// s is constant +void recADD_consts(int info) +{ + recADD_constv(info, _Rs_, _Rt_); + EEINST_SETSIGNEXT(_Rd_); + EEINST_SETSIGNEXT(_Rt_); +} + +// t is constant +void recADD_constt(int info) +{ + recADD_constv(info, _Rt_, _Rs_); + EEINST_SETSIGNEXT(_Rd_); + EEINST_SETSIGNEXT(_Rs_); +} + +// nothing is constant +void recADD_(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + EEINST_SETSIGNEXT(_Rd_); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + + if( info & PROCESS_EE_MMX ) { + + if( EEREC_D == EEREC_S ) PADDDRtoR(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) PADDDRtoR(EEREC_D, EEREC_S); + else { + MOVQRtoR(EEREC_D, EEREC_T); + PADDDRtoR(EEREC_D, EEREC_S); + } + + if( EEINST_ISLIVE1(_Rd_) ) { + // sign extend + _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + } + } + else { + + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && !EEINST_ISLIVE1(_Rd_) ) { + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + + EEINST_RESETHASLIVE1(_Rd_); + MOVDMtoMMX(mmreg, (int)&cpuRegs.GPR.r[_Rs_].UL[0] ); + PADDDMtoR(mmreg, (int)&cpuRegs.GPR.r[_Rt_].UL[0] ); + } + else { + if( _Rd_ == _Rs_ ) { + if( _Rd_ == _Rt_ ) SHL32ItoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], 1); // mult by 2 + else { + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + ADD32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], ECX); + } + + if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); + else EEINST_RESETHASLIVE1(_Rd_); + + return; + } + else if( _Rd_ == _Rt_ ) { + EEINST_RESETHASLIVE1(_Rd_); + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + ADD32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], ECX); + + if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); + else EEINST_RESETHASLIVE1(_Rd_); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if( _Rs_ != _Rt_ ) ADD32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + else SHL32ItoR(EAX, 1); // mult by 2 + + if( EEINST_ISLIVE1(_Rd_) ) { + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + } + } + } + } +} + +EERECOMPILE_CODE0(ADD, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); + +//// ADDU +void recADDU( void ) +{ + recADD( ); +} + +//// DADD +void recDADD_const( void ) +{ + g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SD[0] + g_cpuConstRegs[_Rt_].SD[0]; +} + +void recDADD_constv(int info, int creg, int vreg) +{ + assert( !(info&PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; + + if( g_cpuConstRegs[ creg ].UD[0] ) { + + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + PADDQMtoR(EEREC_D, (u32)_eeGetConstReg(creg)); + } + else { + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + } + } + else { + + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + + MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); + if( g_cpuConstRegs[ creg ].UD[0] ) PADDQMtoR(mmreg, (u32)_eeGetConstReg(creg)); + } + else { + + if( g_cpuConstRegs[ creg ].UL[0] == 0 && g_cpuConstRegs[ creg ].UL[1] == 0 && _hasFreeMMXreg() ) { + // copy + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + if( EEINST_ISLIVE1(_Rd_) ) MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); + else { + MOVDMtoMMX(mmreg, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); + EEINST_RESETHASLIVE1(_Rd_); + } + } + else { + if( _Rd_ == vreg ) { + + if( EEINST_ISLIVE1(_Rd_) && (g_cpuConstRegs[ creg ].UL[ 0 ] || g_cpuConstRegs[ creg ].UL[ 1 ]) ) { + ADD32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[ creg ].UL[ 0 ] ); + ADC32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[ creg ].UL[ 1 ] ); + } + else if( g_cpuConstRegs[ creg ].UL[ 0 ] ) { + EEINST_RESETHASLIVE1(_Rd_); + ADD32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[ creg ].UL[ 0 ] ); + } + + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ] ); + + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 1 ] ); + + if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { + ADD32ItoR( EAX, g_cpuConstRegs[ creg ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + ADC32ItoR( EDX, g_cpuConstRegs[ creg ].UL[ 1 ] ); + } + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + + if( !EEINST_ISLIVE1(_Rd_) ) + EEINST_RESETHASLIVE1(_Rd_); + } + } + } +} + +void recDADD_consts(int info) +{ + recDADD_constv(info, _Rs_, _Rt_); +} + +void recDADD_constt(int info) +{ + recDADD_constv(info, _Rt_, _Rs_); +} + +void recDADD_(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + + if( EEREC_D == EEREC_S ) PADDQRtoR(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) PADDQRtoR(EEREC_D, EEREC_S); + else { + MOVQRtoR(EEREC_D, EEREC_T); + PADDQRtoR(EEREC_D, EEREC_S); + } + } + else { + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + + MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + if( _Rs_ != _Rt_ ) PADDQMtoR(mmreg, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + else PSLLQItoR(mmreg, 1); // mult by 2 + } + else { + if( _Rd_ == _Rs_ || _Rd_ == _Rt_ ) { + int vreg = _Rd_ == _Rs_ ? _Rt_ : _Rs_; + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 1 ] ); + ADD32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX); + if( EEINST_ISLIVE1(_Rd_) ) + ADC32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX); + else + EEINST_RESETHASLIVE1(_Rd_); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + ADD32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + ADC32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + + if( !EEINST_ISLIVE1(_Rd_) ) + EEINST_RESETHASLIVE1(_Rd_); + } + } + } +} + +EERECOMPILE_CODE0(DADD, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); + +//// DADDU +void recDADDU( void ) +{ + recDADD( ); +} + +//// SUB + +void recSUB_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SL[0] - g_cpuConstRegs[_Rt_].SL[0]; +} + +void recSUB_consts(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + EEINST_SETSIGNEXT(_Rt_); + EEINST_SETSIGNEXT(_Rd_); + + if( info & PROCESS_EE_MMX ) { + if( g_cpuConstRegs[ _Rs_ ].UL[0] ) { + + if( EEREC_D != EEREC_T ) { + MOVQMtoR(EEREC_D, (u32)_eeGetConstReg(_Rs_)); + PSUBDRtoR(EEREC_D, EEREC_T); + + if( EEINST_ISLIVE1(_Rd_) ) _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); + else EEINST_RESETHASLIVE1(_Rd_); + } + else { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVDMtoMMX(t0reg, (u32)_eeGetConstReg(_Rs_)); + PSUBDRtoR(t0reg, EEREC_T); + + // swap mmx regs + mmxregs[t0reg] = mmxregs[EEREC_D]; + mmxregs[EEREC_D].inuse = 0; + + if( EEINST_ISLIVE1(_Rd_) ) _signExtendGPRtoMMX(t0reg, _Rd_, 0); + else EEINST_RESETHASLIVE1(_Rd_); + } + } + else { + // just move and sign extend + if( EEREC_D != EEREC_T ) { + PXORRtoR(EEREC_D, EEREC_D); + PSUBDRtoR(EEREC_D, EEREC_T); + + if( EEINST_ISLIVE1(_Rd_) ) _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); + else EEINST_RESETHASLIVE1(_Rd_); + } + else { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + PXORRtoR(t0reg, t0reg); + PSUBDRtoR(t0reg, EEREC_T); + + // swap mmx regs.. don't ask + mmxregs[t0reg] = mmxregs[EEREC_D]; + mmxregs[EEREC_D].inuse = 0; + + if( EEINST_ISLIVE1(_Rd_) ) _signExtendGPRtoMMX(t0reg, _Rd_, 0); + else EEINST_RESETHASLIVE1(_Rd_); + } + } + } + else { + if( _Rd_ == _Rt_ ) { + if( g_cpuConstRegs[ _Rs_ ].UL[ 0 ] ) SUB32ItoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], g_cpuConstRegs[ _Rs_ ].UL[ 0 ]); + NEG32M((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ]); + + if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); + else EEINST_RESETHASLIVE1(_Rd_); + } + else { + if( g_cpuConstRegs[ _Rs_ ].UL[ 0 ] ) { + MOV32ItoR( EAX, g_cpuConstRegs[ _Rs_ ].UL[ 0 ] ); + SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + NEG32R(EAX); + } + + if( EEINST_ISLIVE1(_Rd_) ) { + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + } + } + } +} + +void recSUB_constt(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rd_); + + if( info & PROCESS_EE_MMX ) { + if( g_cpuConstRegs[ _Rt_ ].UL[0] ) { + + u32* ptempmem = _eeGetConstReg(_Rt_); + if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); + PSUBDMtoR(EEREC_D, (u32)ptempmem); + + _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); + } + else { + // just move and sign extend + if( EEINST_HASLIVE1(_Rs_) ) { + if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); + } + else { + _signExtendGPRMMXtoMMX(EEREC_D, _Rd_, EEREC_S, _Rs_); + } + } + } + else { + + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && (!EEINST_ISLIVE1(_Rd_) || !g_cpuConstRegs[_Rt_].UL[0]) ) { + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + + if( EEINST_HASLIVE1(_Rs_) && EEINST_ISLIVE1(_Rd_) ) { + MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + } + else { + if( g_cpuConstRegs[_Rt_].UL[0] ) { + MOVDMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + PSUBDMtoR(mmreg, (u32)_eeGetConstReg(_Rt_)); + } + else { + if( EEINST_ISLIVE1(_Rd_) ) { + _signExtendMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + } + else { + MOVDMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + EEINST_RESETHASLIVE1(_Rd_); + } + } + } + } + else { + if( _Rd_ == _Rs_ ) { + if( g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ) { + SUB32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], g_cpuConstRegs[ _Rt_ ].UL[ 0 ]); + + if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); + else EEINST_RESETHASLIVE1(_Rd_); + } + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if( g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ) + SUB32ItoR( EAX, g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ); + + if( EEINST_ISLIVE1(_Rd_) ) { + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + } + } + } + } +} + +void recSUB_(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + EEINST_SETSIGNEXT(_Rd_); + + if( info & PROCESS_EE_MMX ) { + + if( EEREC_D == EEREC_S ) PSUBDRtoR(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, EEREC_S); + PSUBDRtoR(t0reg, EEREC_T); + + // swap mmx regs.. don't ask + mmxregs[t0reg] = mmxregs[EEREC_D]; + mmxregs[EEREC_D].inuse = 0; + info = (info&~PROCESS_EE_SET_D(0xf))|PROCESS_EE_SET_D(t0reg); + } + else { + MOVQRtoR(EEREC_D, EEREC_S); + PSUBDRtoR(EEREC_D, EEREC_T); + } + + if( EEINST_ISLIVE1(_Rd_) ) { + // sign extend + _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + } + } + else { + + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && !EEINST_ISLIVE1(_Rd_)) { + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + + EEINST_RESETHASLIVE1(_Rd_); + MOVDMtoMMX(mmreg, (int)&cpuRegs.GPR.r[_Rs_].UL[0] ); + PSUBDMtoR(mmreg, (int)&cpuRegs.GPR.r[_Rt_].UL[0] ); + } + else { + if( !EEINST_ISLIVE1(_Rd_) ) { + if( _Rd_ == _Rs_) { + EEINST_RESETHASLIVE1(_Rd_); + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + SUB32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + return; + } + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + + if( EEINST_ISLIVE1(_Rd_) ) { + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + } + } + } +} + +EERECOMPILE_CODE0(SUB, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// SUBU +void recSUBU( void ) +{ + recSUB( ); +} + +//// DSUB +void recDSUB_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SD[0] - g_cpuConstRegs[_Rt_].SD[0]; +} + +void recDSUB_consts(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + + if( g_cpuConstRegs[ _Rs_ ].UD[0] ) { + + // flush + if( EEREC_D != EEREC_T ) { + MOVQMtoR(EEREC_D, (u32)_eeGetConstReg(_Rs_)); + PSUBQRtoR(EEREC_D, EEREC_T); + } + else { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(t0reg, (u32)_eeGetConstReg(_Rs_)); + PSUBQRtoR(t0reg, EEREC_T); + + // swap mmx regs.. don't ask + mmxregs[t0reg] = mmxregs[EEREC_D]; + mmxregs[EEREC_D].inuse = 0; + } + } + else { + // just move and sign extend + if( EEREC_D != EEREC_T ) { + PXORRtoR(EEREC_D, EEREC_D); + PSUBQRtoR(EEREC_D, EEREC_T); + } + else { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + PXORRtoR(t0reg, t0reg); + PSUBQRtoR(t0reg, EEREC_T); + + // swap mmx regs.. don't ask + mmxregs[t0reg] = mmxregs[EEREC_D]; + mmxregs[EEREC_D].inuse = 0; + } + } + } + else { + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + MOVQMtoR(mmreg, (u32)_eeGetConstReg(_Rs_)); + PSUBQMtoR(mmreg, (u32)&cpuRegs.GPR.r[_Rt_].UL[ 0 ]); + } + else { + if( g_cpuConstRegs[ _Rs_ ].UL[ 0 ] || g_cpuConstRegs[ _Rs_ ].UL[ 1 ] ) { + MOV32ItoR( EAX, g_cpuConstRegs[ _Rs_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32ItoR( EDX, g_cpuConstRegs[ _Rs_ ].UL[ 1 ] ); + SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + SBB32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + + if( !EEINST_ISLIVE1(_Rd_) ) + EEINST_RESETHASLIVE1(_Rd_); + } + else { + + if( _Rd_ == _Rt_ ) { + // negate _Rt_ all in memory + if( EEINST_ISLIVE1(_Rd_) ) { + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + NEG32M((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + ADC32ItoR(EDX, 0); + NEG32R(EDX); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + NEG32M((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ]); + } + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + // take negative of 64bit number + NEG32R(EAX); + + if( EEINST_ISLIVE1(_Rd_) ) { + ADC32ItoR(EDX, 0); + NEG32R(EDX); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + } + } + + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + else { + EEINST_RESETHASLIVE1(_Rd_); + } + } + } +} + +void recDSUB_constt(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + + if( g_cpuConstRegs[ _Rt_ ].UD[0] ) { + + if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); + PSUBQMtoR(EEREC_D, (u32)_eeGetConstReg(_Rt_)); + } + else { + if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); + } + } + else { + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + if( g_cpuConstRegs[_Rt_].UD[0] ) PSUBQMtoR(mmreg, (u32)_eeGetConstReg(_Rt_)); + } + else { + + if( _Rd_ == _Rs_ ) { + if( EEINST_ISLIVE1(_Rd_) && (g_cpuConstRegs[ _Rt_ ].UL[ 0 ] || g_cpuConstRegs[ _Rt_ ].UL[ 1 ]) ) { + SUB32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ); + SBB32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[ _Rt_ ].UL[ 1 ] ); + } + else if( g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ) { + EEINST_RESETHASLIVE1(_Rd_); + SUB32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ); + } + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + + if( g_cpuConstRegs[ _Rt_ ].UL[ 0 ] || g_cpuConstRegs[ _Rt_ ].UL[ 1 ] ) { + SUB32ItoR( EAX, g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + SBB32ItoR( EDX, g_cpuConstRegs[ _Rt_ ].UL[ 1 ] ); + } + + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + else + EEINST_RESETHASLIVE1(_Rd_); + } + } + } +} + +void recDSUB_(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + + if( EEREC_D == EEREC_S ) PSUBQRtoR(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, EEREC_S); + PSUBQRtoR(t0reg, EEREC_T); + + // swap mmx regs.. don't ask + mmxregs[t0reg] = mmxregs[EEREC_D]; + mmxregs[EEREC_D].inuse = 0; + } + else { + MOVQRtoR(EEREC_D, EEREC_S); + PSUBQRtoR(EEREC_D, EEREC_T); + } + } + else { + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { + int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[_Rs_].UL[ 0 ]); + PSUBQMtoR(mmreg, (int)&cpuRegs.GPR.r[_Rt_].UL[ 0 ]); + } + else { + if( _Rd_ == _Rs_ ) { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + SUB32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) + SBB32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + else + EEINST_RESETHASLIVE1(_Rd_); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rd_) ) + SBB32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + else + EEINST_RESETHASLIVE1(_Rd_); + } + } + } +} + +EERECOMPILE_CODE0(DSUB, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// DSUBU +void recDSUBU( void ) +{ + recDSUB( ); +} + +//// AND +void recAND_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] & g_cpuConstRegs[_Rt_].UD[0]; +} + +void recAND_constv(int info, int creg, int vreg) +{ + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; + + if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { + _flushConstReg(creg); + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + PANDMtoR(EEREC_D, (u32)&cpuRegs.GPR.r[creg].UL[0] ); + } + else { + PXORRtoR(EEREC_D, EEREC_D); + } + } + else { + + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) || (_Rd_ != vreg && _hasFreeMMXreg()) ) { + int rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + + MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[vreg].UL[0] ); + PANDMtoR(rdreg, (u32)_eeGetConstReg(creg) ); + } + else { + if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { + + if( _Rd_ == vreg ) { + AND32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[0], g_cpuConstRegs[creg].UL[0]); + if( EEINST_ISLIVE1(_Rd_) ) { + if( g_cpuConstRegs[creg].UL[1] != 0xffffffff ) AND32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[1], g_cpuConstRegs[creg].UL[1]); + } + else + EEINST_RESETHASLIVE1(_Rd_); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); + AND32ItoR(EAX, g_cpuConstRegs[ creg ].UL[0]); + if( EEINST_ISLIVE1(_Rd_) ) + AND32ItoR(ECX, g_cpuConstRegs[ creg ].UL[1]); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); + else + EEINST_RESETHASLIVE1(_Rd_); + } + } + else { + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rd_ ], 0); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, 0); + else + EEINST_RESETHASLIVE1(_Rd_); + } + } + } +} + +void recAND_consts(int info) +{ + recAND_constv(info, _Rs_, _Rt_); +} + +void recAND_constt(int info) +{ + recAND_constv(info, _Rt_, _Rs_); +} + +void recLogicalOp(int info, int op) +{ + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + if( EEREC_D == EEREC_S ) LogicalOpRtoR(EEREC_D, EEREC_T, op); + else if( EEREC_D == EEREC_T ) LogicalOpRtoR(EEREC_D, EEREC_S, op); + else { + MOVQRtoR(EEREC_D, EEREC_S); + LogicalOpRtoR(EEREC_D, EEREC_T, op); + } + } + else if( (g_pCurInstInfo->regs[_Rs_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { + int rsreg, rtreg, rdreg; + _addNeededMMXreg(MMX_GPR+_Rs_); + _addNeededMMXreg(MMX_GPR+_Rt_); + _addNeededMMXreg(MMX_GPR+_Rd_); + + rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + rsreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rs_, MODE_READ); + rtreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_READ); + SetMMXstate(); + + if( rdreg == rsreg ) { + if( rtreg >= 0 ) LogicalOpRtoR(rdreg, rtreg, op); + else LogicalOpMtoR(rdreg, (int)&cpuRegs.GPR.r[ _Rt_ ], op); + } + else { + if( rdreg != rtreg ) { + if( rtreg >= 0 ) MOVQRtoR(rdreg, rtreg); + else MOVQMtoR(rdreg, (int)&cpuRegs.GPR.r[ _Rt_ ]); + } + + if( rsreg >= 0 ) LogicalOpRtoR(rdreg, rsreg, op); + else LogicalOpMtoR(rdreg, (int)&cpuRegs.GPR.r[ _Rs_ ], op); + } + } + else { + if( _Rd_ == _Rs_ || _Rd_ == _Rt_ ) { + int vreg = _Rd_ == _Rs_ ? _Rt_ : _Rs_; + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); + LogicalOp32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX, op ); + if( EEINST_ISLIVE1(_Rd_) ) + LogicalOp32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ] + 4, EDX, op ); + if( op == 3 ) { + NOT32M((int)&cpuRegs.GPR.r[ _Rd_ ]); + if( EEINST_ISLIVE1(_Rd_) ) + NOT32M((int)&cpuRegs.GPR.r[ _Rd_ ]+4); + } + + if( !EEINST_ISLIVE1(_Rd_) ) EEINST_RESETHASLIVE1(_Rd_); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ]); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ] + 4 ); + LogicalOp32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rt_ ], op ); + if( EEINST_ISLIVE1(_Rd_) ) + LogicalOp32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rt_ ] + 4, op ); + + if( op == 3 ) { + NOT32R(EAX); + if( EEINST_ISLIVE1(_Rd_) ) + NOT32R(ECX); + } + + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); + else + EEINST_RESETHASLIVE1(_Rd_); + } + } +} + +void recAND_(int info) +{ + recLogicalOp(info, 0); +} + +EERECOMPILE_CODE0(AND, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// OR +void recOR_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] | g_cpuConstRegs[_Rt_].UD[0]; +} + +void recOR_constv(int info, int creg, int vreg) +{ + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; + + if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { + _flushConstReg(creg); + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + PORMtoR(EEREC_D, (u32)&cpuRegs.GPR.r[creg].UL[0] ); + } + else { + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + } + } + else { + + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) || (_Rd_ != vreg && _hasFreeMMXreg()) ) { + int rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + + MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[vreg].UL[0] ); + + if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { + PORMtoR(rdreg, (u32)_eeGetConstReg(creg) ); + } + } + else { + if( _Rd_ == vreg ) { + OR32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[0], g_cpuConstRegs[creg].UL[0]); + if( EEINST_ISLIVE1(_Rd_) ) { + if( g_cpuConstRegs[creg].UL[1] ) OR32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[1], g_cpuConstRegs[creg].UL[1]); + } + else + EEINST_RESETHASLIVE1(_Rd_); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); + + if( g_cpuConstRegs[ creg ].UL[0] ) OR32ItoR(EAX, g_cpuConstRegs[ creg ].UL[0]); + if( g_cpuConstRegs[ creg ].UL[1] && EEINST_ISLIVE1(_Rd_) ) OR32ItoR(ECX, g_cpuConstRegs[ creg ].UL[1]); + + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); + else + EEINST_RESETHASLIVE1(_Rd_); + } + } + } +} + +void recOR_consts(int info) +{ + recOR_constv(info, _Rs_, _Rt_); +} + +void recOR_constt(int info) +{ + recOR_constv(info, _Rt_, _Rs_); +} + +void recOR_(int info) +{ + recLogicalOp(info, 1); +} + +EERECOMPILE_CODE0(OR, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// XOR +void recXOR_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] ^ g_cpuConstRegs[_Rt_].UD[0]; +} + +void recXOR_constv(int info, int creg, int vreg) +{ + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; + + if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { + _flushConstReg(creg); + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + PXORMtoR(EEREC_D, (u32)&cpuRegs.GPR.r[creg].UL[0] ); + } + else { + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + } + } + else { + + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) || (_Rd_ != vreg && _hasFreeMMXreg()) ) { + int rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[vreg].UL[0] ); + + if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { + PXORMtoR(rdreg, (u32)_eeGetConstReg(creg) ); + } + } + else { + if( _Rd_ == vreg ) { + XOR32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[0], g_cpuConstRegs[creg].UL[0]); + if( EEINST_ISLIVE1(_Rd_) ) { + if( g_cpuConstRegs[creg].UL[1] ) XOR32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[1], g_cpuConstRegs[creg].UL[1]); + } + else + EEINST_RESETHASLIVE1(_Rd_); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); + + if( g_cpuConstRegs[ creg ].UL[0] ) XOR32ItoR(EAX, g_cpuConstRegs[ creg ].UL[0]); + if( g_cpuConstRegs[ creg ].UL[1] && EEINST_ISLIVE1(_Rd_) ) XOR32ItoR(ECX, g_cpuConstRegs[ creg ].UL[1]); + + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); + else + EEINST_RESETHASLIVE1(_Rd_); + } + } + } +} + +void recXOR_consts(int info) +{ + recXOR_constv(info, _Rs_, _Rt_); +} + +void recXOR_constt(int info) +{ + recXOR_constv(info, _Rt_, _Rs_); +} + +void recXOR_(int info) +{ + recLogicalOp(info, 2); +} + +EERECOMPILE_CODE0(XOR, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// NOR +void recNOR_const() +{ + g_cpuConstRegs[_Rd_].UD[0] =~(g_cpuConstRegs[_Rs_].UD[0] | g_cpuConstRegs[_Rt_].UD[0]); +} + +void recNOR_constv(int info, int creg, int vreg) +{ + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + PORMtoR(EEREC_D, (u32)_eeGetConstReg(creg)); + } + else { + if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); + } + + // take the NOT + PCMPEQDRtoR( t0reg,t0reg); + PXORRtoR( EEREC_D,t0reg); + _freeMMXreg(t0reg); + } + else { + + if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) || (_Rd_ != vreg && _hasFreeMMXreg()) ) { + int rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + SetMMXstate(); + + MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[vreg].UL[0] ); + PCMPEQDRtoR( t0reg,t0reg); + if( g_cpuConstRegs[ creg ].UD[0] ) PORMtoR(rdreg, (u32)_eeGetConstReg(creg) ); + + // take the NOT + PXORRtoR( rdreg,t0reg); + + _freeMMXreg(t0reg); + } + else { + if( _Rd_ == vreg ) { + NOT32M((int)&cpuRegs.GPR.r[ vreg ].UL[0]); + if( EEINST_ISLIVE1(_Rd_) ) NOT32M((int)&cpuRegs.GPR.r[ vreg ].UL[1]); + + if( g_cpuConstRegs[creg].UL[0] ) AND32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[0], ~g_cpuConstRegs[creg].UL[0]); + if( EEINST_ISLIVE1(_Rd_) ) { + if( g_cpuConstRegs[creg].UL[1] ) AND32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[1], ~g_cpuConstRegs[creg].UL[1]); + } + else + EEINST_RESETHASLIVE1(_Rd_); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); + if( g_cpuConstRegs[ creg ].UL[0] ) OR32ItoR(EAX, g_cpuConstRegs[ creg ].UL[0]); + if( g_cpuConstRegs[ creg ].UL[1] && EEINST_ISLIVE1(_Rd_) ) OR32ItoR(ECX, g_cpuConstRegs[ creg ].UL[1]); + NOT32R(EAX); + if( EEINST_ISLIVE1(_Rd_) ) + NOT32R(ECX); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); + else + EEINST_RESETHASLIVE1(_Rd_); + } + } + } +} + +void recNOR_consts(int info) +{ + recNOR_constv(info, _Rs_, _Rt_); +} + +void recNOR_constt(int info) +{ + recNOR_constv(info, _Rt_, _Rs_); +} + +void recNOR_(int info) +{ + recLogicalOp(info, 3); +} + +EERECOMPILE_CODE0(NOR, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// SLT - test with silent hill, lemans +void recSLT_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SD[0] < g_cpuConstRegs[_Rt_].SD[0]; +} + +static u32 s_sltconst = 0x80000000; +static u32 s_sltconst64[2] = {0, 0x80000000}; +u32 s_sltone = 1; + +void recSLTs_consts(int info, int sign) +{ + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + + if( _Rs_ == _Rt_ ) { + PXORRtoR(EEREC_D, EEREC_D); + return; + } + + if( g_cpuConstRegs[_Rs_].UL[1] == (g_cpuConstRegs[_Rs_].SL[0]<0?0xffffffff:0) && EEINST_ISSIGNEXT(_Rt_) ) { + // just compare the lower values + if( sign ) { + if( EEREC_D != EEREC_T ) MOVQRtoR(EEREC_D, EEREC_T); + PCMPGTDMtoR(EEREC_D, (u32)_eeGetConstReg(_Rs_)); + + PUNPCKLDQRtoR(EEREC_D, EEREC_D); + PSRLQItoR(EEREC_D, 63); + } + else { + u32* ptempmem = recAllocStackMem(8,4); + ptempmem[0] = g_cpuConstRegs[_Rs_].UL[0]^0x80000000; + ptempmem[1] = 0; + + if( EEREC_D != EEREC_T ) { + MOVDMtoMMX(EEREC_D, (u32)&s_sltconst); + PXORRtoR(EEREC_D, EEREC_T); + } + else { + PXORMtoR(EEREC_D, (u32)&s_sltconst); + } + + PCMPGTDMtoR(EEREC_D, (u32)ptempmem); + + PUNPCKLDQRtoR(EEREC_D, EEREC_D); + PSRLQItoR(EEREC_D, 63); + } + + return; + } + else { + // need to compare total 64 bit value + if( info & PROCESS_EE_MODEWRITET ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_], EEREC_T); + if( mmxregs[EEREC_T].reg == MMX_GPR+_Rt_ ) mmxregs[EEREC_T].mode &= ~MODE_WRITE; + } + + // fall through + mmxregs[EEREC_D].mode |= MODE_WRITE; // in case EEREC_D was just flushed + } + } + + if( info & PROCESS_EE_MMX ) PXORRtoR(EEREC_D, EEREC_D); + else XOR32RtoR(EAX, EAX); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); + if( sign ) { + j8Ptr[0] = JL8( 0 ); + j8Ptr[2] = JG8( 0 ); + } + else { + j8Ptr[0] = JB8( 0 ); + j8Ptr[2] = JA8( 0 ); + } + + CMP32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); + j8Ptr[1] = JBE8(0); + + x86SetJ8(j8Ptr[2]); + if( info & PROCESS_EE_MMX ) MOVDMtoMMX(EEREC_D, (u32)&s_sltone); + else MOV32ItoR(EAX, 1); + + x86SetJ8(j8Ptr[0]); + x86SetJ8(j8Ptr[1]); + + if( !(info & PROCESS_EE_MMX) ) { + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); + else EEINST_RESETHASLIVE1(_Rd_); + } +} + +// SLT with one operand coming from mem (compares only low 32 bits) +void recSLTmemconstt(int regd, int regs, u32 mem, int sign) +{ + // just compare the lower values + int t0reg; + + if( sign ) { + if( regd == regs ) { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(t0reg, mem); + PCMPGTDRtoR(t0reg, regs); + + PUNPCKLDQRtoR(t0reg, t0reg); + PSRLQItoR(t0reg, 63); + + // swap regs + mmxregs[t0reg] = mmxregs[regd]; + mmxregs[regd].inuse = 0; + } + else { + MOVQMtoR(regd, mem); + PCMPGTDRtoR(regd, regs); + + PUNPCKLDQRtoR(regd, regd); + PSRLQItoR(regd, 63); + } + } + else { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + if( regd == regs ) { + MOVQMtoR(t0reg, mem); + PXORMtoR(regs, (u32)&s_sltconst); + PCMPGTDRtoR(t0reg, regs); + + PUNPCKLDQRtoR(t0reg, t0reg); + PSRLQItoR(t0reg, 63); + + // swap regs + mmxregs[t0reg] = mmxregs[regd]; + mmxregs[regd].inuse = 0; + } + else { + MOVQRtoR(t0reg, regs); + MOVQMtoR(regd, mem); + PXORMtoR(t0reg, (u32)&s_sltconst); + PCMPGTDRtoR(regd, t0reg); + + PUNPCKLDQRtoR(regd, regd); + PSRLQItoR(regd, 63); + _freeMMXreg(t0reg); + } + } +} + +void recSLTs_constt(int info, int sign) +{ + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + if( _Rs_ == _Rt_ ) { + PXORRtoR(EEREC_D, EEREC_D); + return; + } + + if( EEINST_ISSIGNEXT(_Rs_) && g_cpuConstRegs[_Rt_].UL[1] == (g_cpuConstRegs[_Rt_].SL[0]<0?0xffffffff:0) ) { + // just compare the lower values + if( sign ) { + recSLTmemconstt(EEREC_D, EEREC_S, (u32)_eeGetConstReg(_Rt_), 1); + } + else { + u32* ptempmem = recAllocStackMem(8,4); + ptempmem[0] = g_cpuConstRegs[_Rt_].UL[0]^0x80000000; + ptempmem[1] = 0; + + recSLTmemconstt(EEREC_D, EEREC_S, (u32)ptempmem, 0); + } + + return; + } + else { + // need to compare total 64 bit value + if( info & PROCESS_EE_MODEWRITES ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_], EEREC_S); + if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; + } + mmxregs[EEREC_D].mode |= MODE_WRITE; // in case EEREC_D was just flushed + + // fall through + } + } + + if( info & PROCESS_EE_MMX ) MOVDMtoMMX(EEREC_D, (u32)&s_sltone); + else MOV32ItoR(EAX, 1); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1]); + if( sign ) { + j8Ptr[0] = JL8( 0 ); + j8Ptr[2] = JG8( 0 ); + } + else { + j8Ptr[0] = JB8( 0 ); + j8Ptr[2] = JA8( 0 ); + } + + CMP32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0]); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + if( info & PROCESS_EE_MMX ) PXORRtoR(EEREC_D, EEREC_D); + else XOR32RtoR(EAX, EAX); + + x86SetJ8(j8Ptr[0]); + x86SetJ8(j8Ptr[1]); + + if( !(info & PROCESS_EE_MMX) ) { + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); + else EEINST_RESETHASLIVE1(_Rd_); + } +} + +void recSLTs_(int info, int sign) +{ + if( info & PROCESS_EE_MMX ) MOVDMtoMMX(EEREC_D, (u32)&s_sltone); + else MOV32ItoR(EAX, 1); + + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ]); + + if( sign ) { + j8Ptr[0] = JL8( 0 ); + j8Ptr[2] = JG8( 0 ); + } + else { + j8Ptr[0] = JB8( 0 ); + j8Ptr[2] = JA8( 0 ); + } + + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + if( info & PROCESS_EE_MMX ) PXORRtoR(EEREC_D, EEREC_D); + else XOR32RtoR(EAX, EAX); + + x86SetJ8(j8Ptr[0]); + x86SetJ8(j8Ptr[1]); + + if( !(info & PROCESS_EE_MMX) ) { + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); + else EEINST_RESETHASLIVE1(_Rd_); + } +} + +void recSLT_consts(int info) +{ + recSLTs_consts(info, 1); +} + +void recSLT_constt(int info) +{ + recSLTs_constt(info, 1); +} + +void recSLT_(int info) +{ + int t0reg; + assert( !(info & PROCESS_EE_XMM) ); + + if( !(info & PROCESS_EE_MMX) ) { + recSLTs_(info, 1); + return; + } + + if( !EEINST_ISSIGNEXT(_Rs_) || !EEINST_ISSIGNEXT(_Rt_) ) { + // need to compare total 64 bit value + if( info & PROCESS_EE_MODEWRITES ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_], EEREC_S); + if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; + } + if( info & PROCESS_EE_MODEWRITET ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_], EEREC_T); + if( mmxregs[EEREC_T].reg == MMX_GPR+_Rt_ ) mmxregs[EEREC_T].mode &= ~MODE_WRITE; + } + mmxregs[EEREC_D].mode |= MODE_WRITE; // in case EEREC_D was just flushed + recSLTs_(info, 1); + return; + } + + if( EEREC_S == EEREC_T ) { + PXORRtoR(EEREC_D, EEREC_D); + return; + } + + // just compare the lower values + if( EEREC_D == EEREC_S ) { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, EEREC_T); + PCMPGTDRtoR(t0reg, EEREC_S); + + PUNPCKLDQRtoR(t0reg, t0reg); + PSRLQItoR(t0reg, 63); + + // swap regs + mmxregs[t0reg] = mmxregs[EEREC_D]; + mmxregs[EEREC_D].inuse = 0; + } + else { + if( EEREC_D != EEREC_T ) MOVQRtoR(EEREC_D, EEREC_T); + PCMPGTDRtoR(EEREC_D, EEREC_S); + + PUNPCKLDQRtoR(EEREC_D, EEREC_D); + PSRLQItoR(EEREC_D, 63); + } +} + +EERECOMPILE_CODE0(SLT, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +// SLTU - test with silent hill, lemans +void recSLTU_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] < g_cpuConstRegs[_Rt_].UD[0]; +} + +void recSLTU_consts(int info) +{ + recSLTs_consts(info, 0); + EEINST_SETSIGNEXT(_Rd_); +} + +void recSLTU_constt(int info) +{ + recSLTs_constt(info, 0); + EEINST_SETSIGNEXT(_Rd_); +} + +void recSLTU_(int info) +{ + int t1reg; + + assert( !(info & PROCESS_EE_XMM) ); + EEINST_SETSIGNEXT(_Rd_); + + if( !(info & PROCESS_EE_MMX) ) { + recSLTs_(info, 0); + return; + } + + if( EEREC_S == EEREC_T ) { + PXORRtoR(EEREC_D, EEREC_D); + return; + } + + if( !EEINST_ISSIGNEXT(_Rs_) || !EEINST_ISSIGNEXT(_Rt_) ) { + // need to compare total 64 bit value + if( info & PROCESS_EE_MODEWRITES ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_], EEREC_S); + if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; + } + if( info & PROCESS_EE_MODEWRITET ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_], EEREC_T); + if( mmxregs[EEREC_T].reg == MMX_GPR+_Rt_ ) mmxregs[EEREC_T].mode &= ~MODE_WRITE; + } + mmxregs[EEREC_D].mode |= MODE_WRITE; // in case EEREC_D was just flushed + recSLTs_(info, 0); + return; + } + + t1reg = _allocMMXreg(-1, MMX_TEMP, 0); + + MOVDMtoMMX(t1reg, (u32)&s_sltconst); + + if( EEREC_D == EEREC_S ) { + PXORRtoR(EEREC_S, t1reg); + PXORRtoR(t1reg, EEREC_T); + PCMPGTDRtoR(t1reg, EEREC_S); + + PUNPCKLDQRtoR(t1reg, t1reg); + PSRLQItoR(t1reg, 63); + + // swap regs + mmxregs[t1reg] = mmxregs[EEREC_D]; + mmxregs[EEREC_D].inuse = 0; + } + else { + if( EEREC_D != EEREC_T ) { + MOVDMtoMMX(EEREC_D, (u32)&s_sltconst); + PXORRtoR(t1reg, EEREC_S); + PXORRtoR(EEREC_D, EEREC_T); + } + else { + PXORRtoR(EEREC_D, t1reg); + PXORRtoR(t1reg, EEREC_S); + } + + PCMPGTDRtoR(EEREC_D, t1reg); + + PUNPCKLDQRtoR(EEREC_D, EEREC_D); + PSRLQItoR(EEREC_D, 63); + + _freeMMXreg(t1reg); + } +} + +EERECOMPILE_CODE0(SLTU, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +#else + +//////////////////////////////////////////////////// +void recADD( void ) +{ + if ( ! _Rd_ ) + { + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + ADD32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); +} + +//////////////////////////////////////////////////// +void recADDU( void ) +{ + recADD( ); +} + +//////////////////////////////////////////////////// +void recDADD( void ) +{ + if ( ! _Rd_ ) + { + return; + } + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + ADD32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + ADC32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); +} + +//////////////////////////////////////////////////// +void recDADDU( void ) +{ + recDADD( ); +} + +//////////////////////////////////////////////////// +void recSUB( void ) +{ + if ( ! _Rd_ ) return; + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +void recSUBU( void ) +{ + recSUB( ); +} + +//////////////////////////////////////////////////// +void recDSUB( void ) +{ + if ( ! _Rd_ ) return; + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + SBB32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +void recDSUBU( void ) +{ + recDSUB( ); +} + +//////////////////////////////////////////////////// +void recAND( void ) +{ + if ( ! _Rd_ ) + { + return; + } + if ( ( _Rt_ == 0 ) || ( _Rs_ == 0 ) ) + { + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], 0 ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); + } + else + { + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + MOVQMtoR( MM1, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + PANDRtoR( MM0, MM1); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + } + +} + +//////////////////////////////////////////////////// +void recOR( void ) +{ + if ( ! _Rd_ ) + { + return; + } + + if ( ( _Rs_ == 0 ) && ( _Rt_ == 0 ) ) + { + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], 0x0 ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0x0 ); + } + else if ( _Rs_ == 0 ) + { + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + } + else if ( _Rt_ == 0 ) + { + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + } + else + { + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + MOVQMtoR( MM1, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + PORRtoR( MM0, MM1 ); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + } +} + +//////////////////////////////////////////////////// +void recXOR( void ) +{ + if ( ! _Rd_ ) + { + return; + } + + if ( ( _Rs_ == 0 ) && ( _Rt_ == 0 ) ) + { + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ],0x0); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ],0x0); + return; + } + + if ( _Rs_ == 0 ) + { + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + return; + } + + if ( _Rt_ == 0 ) + { + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + return; + } + + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + MOVQMtoR( MM1, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + PXORRtoR( MM0, MM1); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); +} + +//////////////////////////////////////////////////// +void recNOR( void ) +{ + if ( ! _Rd_ ) + { + return; + } + + if ( ( _Rs_ == 0 ) && ( _Rt_ == 0 ) ) + { + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ],0xffffffff); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ],0xffffffff); + return; + } + + if ( _Rs_ == 0 ) + { + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + PCMPEQDRtoR( MM1,MM1); + PXORRtoR( MM0,MM1); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ],MM0); + SetMMXstate(); + return; + } + + if ( _Rt_ == 0 ) + { + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + PCMPEQDRtoR( MM1,MM1); + PXORRtoR( MM0,MM1); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ],MM0); + SetMMXstate(); + return; + } + + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + PCMPEQDRtoR( MM1,MM1); + PORMtoR( MM0,(int)&cpuRegs.GPR.r[ _Rt_ ] ); + PXORRtoR( MM0,MM1); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ],MM0); + SetMMXstate(); +} + +//////////////////////////////////////////////////// +// test with silent hill, lemans +void recSLT( void ) +{ + if ( ! _Rd_ ) + return; + + MOV32ItoR(EAX, 1); + + if( _Rs_ == 0 ) { + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0); + j8Ptr[0] = JG8( 0 ); + j8Ptr[2] = JL8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], 0 ); + j8Ptr[1] = JA8(0); + + x86SetJ8(j8Ptr[2]); + XOR32RtoR(EAX, EAX); + } + else if( _Rt_ == 0 ) { + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0); + j8Ptr[0] = JL8( 0 ); + j8Ptr[2] = JG8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + XOR32RtoR(EAX, EAX); + } + else { + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ]); + j8Ptr[0] = JL8( 0 ); + j8Ptr[2] = JG8( 0 ); + + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + XOR32RtoR(EAX, EAX); + } + + x86SetJ8(j8Ptr[0]); + x86SetJ8(j8Ptr[1]); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); +} + +//////////////////////////////////////////////////// +void recSLTU( void ) +{ + MOV32ItoR(EAX, 1); + + if( _Rs_ == 0 ) { + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0); + j8Ptr[0] = JA8( 0 ); + j8Ptr[2] = JB8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], 0 ); + j8Ptr[1] = JA8(0); + + x86SetJ8(j8Ptr[2]); + XOR32RtoR(EAX, EAX); + } + else if( _Rt_ == 0 ) { + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0); + j8Ptr[0] = JB8( 0 ); + j8Ptr[2] = JA8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + XOR32RtoR(EAX, EAX); + } + else { + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ]); + j8Ptr[0] = JB8( 0 ); + j8Ptr[2] = JA8( 0 ); + + MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + XOR32RtoR(EAX, EAX); + } + + x86SetJ8(j8Ptr[0]); + x86SetJ8(j8Ptr[1]); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); +} + +#endif + +} } } diff --git a/pcsx2/x86/ix86-32/iR5900AritImm.cpp b/pcsx2/x86/ix86-32/iR5900AritImm.cpp index ce9bbd98dd..d9bdba665e 100644 --- a/pcsx2/x86/ix86-32/iR5900AritImm.cpp +++ b/pcsx2/x86/ix86-32/iR5900AritImm.cpp @@ -1,640 +1,640 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "R5900OpcodeTables.h" -#include "ix86/ix86.h" -#include "iR5900.h" - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl -{ - -/********************************************************* -* Arithmetic with immediate operand * -* Format: OP rt, rs, immediate * -*********************************************************/ - -#ifndef ARITHMETICIMM_RECOMPILE - -namespace Interp = R5900::Interpreter::OpcodeImpl; - -REC_FUNC_DEL(ADDI, _Rt_); -REC_FUNC_DEL(ADDIU, _Rt_); -REC_FUNC_DEL(DADDI, _Rt_); -REC_FUNC_DEL(DADDIU, _Rt_); -REC_FUNC_DEL(ANDI, _Rt_); -REC_FUNC_DEL(ORI, _Rt_); -REC_FUNC_DEL(XORI, _Rt_); - -REC_FUNC_DEL(SLTI, _Rt_); -REC_FUNC_DEL(SLTIU, _Rt_); - -#elif defined(EE_CONST_PROP) - -//// ADDI -void recADDI_const( void ) -{ - g_cpuConstRegs[_Rt_].SD[0] = (s64)(g_cpuConstRegs[_Rs_].SL[0] + (s32)_Imm_); -} - -void recADDI_(int info) -{ - assert( !(info&PROCESS_EE_XMM) ); - EEINST_SETSIGNEXT(_Rt_); - EEINST_SETSIGNEXT(_Rs_); - - if ( info & PROCESS_EE_MMX ) { - if ( _Imm_ != 0 ) { - - u32* ptempmem = recAllocStackMem(8, 8); - ptempmem[0] = (s32)_Imm_; - ptempmem[1] = 0; - - if ( EEREC_T != EEREC_S ) MOVQRtoR(EEREC_T, EEREC_S); - PADDDMtoR(EEREC_T, (u32)ptempmem); - if ( EEINST_ISLIVE1(_Rt_) ) _signExtendGPRtoMMX(EEREC_T, _Rt_, 0); - else EEINST_RESETHASLIVE1(_Rt_); - } - else { - // just move and sign extend - if ( !EEINST_HASLIVE1(_Rs_) ) { - if ( EEINST_ISLIVE1(_Rt_) ) _signExtendGPRMMXtoMMX(EEREC_T, _Rt_, EEREC_S, _Rs_); - else EEINST_RESETHASLIVE1(_Rt_); - } - else if ( EEREC_T != EEREC_S ) MOVQRtoR(EEREC_T, EEREC_S); - } - return; - } - - if ( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) && (_Rt_ != _Rs_) ) { - int rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE); - SetMMXstate(); - - if ( _Imm_ != 0 ) { - u32* ptempmem = recAllocStackMem(8, 8); - ptempmem[0] = (s32)_Imm_; - ptempmem[1] = 0; - - MOVDMtoMMX(rtreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - PADDDMtoR(rtreg, (u32)ptempmem); - - if ( EEINST_ISLIVE1(_Rt_) ) _signExtendGPRtoMMX(rtreg, _Rt_, 0); - else EEINST_RESETHASLIVE1(_Rt_); - } - else { - // just move and sign extend - if ( !EEINST_HASLIVE1(_Rs_) ) { - MOVDMtoMMX(rtreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - if ( EEINST_ISLIVE1(_Rt_) ) _signExtendGPRtoMMX(rtreg, _Rt_, 0); - else EEINST_RESETHASLIVE1(_Rt_); - } - else MOVQMtoR(rtreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - } - } - else { - if ( _Rt_ == _Rs_ ) { - ADD32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], _Imm_); - if ( EEINST_ISLIVE1(_Rt_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ]); - else EEINST_RESETHASLIVE1(_Rt_); - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - - if ( _Imm_ != 0 ) ADD32ItoR( EAX, _Imm_ ); - - if ( EEINST_ISLIVE1(_Rt_) ) { - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); - } - else { - EEINST_RESETHASLIVE1(_Rt_); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - } - } - } -} - -EERECOMPILE_CODEX(eeRecompileCode1, ADDI); - -//////////////////////////////////////////////////// -void recADDIU( void ) -{ - recADDI( ); -} - -//////////////////////////////////////////////////// -void recDADDI_const( void ) -{ - g_cpuConstRegs[_Rt_].SD[0] = g_cpuConstRegs[_Rs_].SD[0] + (s64)_Imm_; -} - -void recDADDI_(int info) -{ - assert( !(info&PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - - if( _Imm_ != 0 ) { - - // flush - u32* ptempmem = recAllocStackMem(8, 8); - ptempmem[0] = _Imm_; - ptempmem[1] = _Imm_ >= 0 ? 0 : 0xffffffff; - if( EEREC_T != EEREC_S ) MOVQRtoR(EEREC_T, EEREC_S); - PADDQMtoR(EEREC_T, (u32)ptempmem); - } - else { - if( EEREC_T != EEREC_S ) MOVQRtoR(EEREC_T, EEREC_S); - } - return; - } - - if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) ) { - int rtreg; - u32* ptempmem = recAllocStackMem(8, 8); - ptempmem[0] = _Imm_; - ptempmem[1] = _Imm_ >= 0 ? 0 : 0xffffffff; - - rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE); - SetMMXstate(); - - MOVQMtoR(rtreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - PADDQMtoR(rtreg, (u32)ptempmem); - } - else { - if( _Rt_ == _Rs_ ) { - ADD32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], _Imm_); - ADC32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], _Imm_<0?0xffffffff:0); - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - - if( EEINST_ISLIVE1(_Rt_) ) - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); - - if ( _Imm_ != 0 ) - { - ADD32ItoR( EAX, _Imm_ ); - - if( EEINST_ISLIVE1(_Rt_) ) { - ADC32ItoR( EDX, _Imm_ < 0?0xffffffff:0); - } - } - - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - - if( EEINST_ISLIVE1(_Rt_) ) - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); - else - EEINST_RESETHASLIVE1(_Rt_); - } - } -} - -EERECOMPILE_CODEX(eeRecompileCode1, DADDI); - -//// DADDIU -void recDADDIU( void ) -{ - recDADDI( ); -} - -//// SLTIU -void recSLTIU_const() -{ - g_cpuConstRegs[_Rt_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] < (u64)(_Imm_); -} - -extern void recSLTmemconstt(int regd, int regs, u32 mem, int sign); -extern u32 s_sltone; - -void recSLTIU_(int info) -{ - if( info & PROCESS_EE_MMX ) { - if( EEINST_ISSIGNEXT(_Rs_) ) { - u32* ptempmem = recAllocStackMem(8,4); - ptempmem[0] = ((s32)(_Imm_))^0x80000000; - ptempmem[1] = 0; - recSLTmemconstt(EEREC_T, EEREC_S, (u32)ptempmem, 0); - EEINST_SETSIGNEXT(_Rt_); - return; - } - - if( info & PROCESS_EE_MODEWRITES ) { - MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_], EEREC_S); - if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; - } - mmxregs[EEREC_T].mode |= MODE_WRITE; // in case EEREC_T==EEREC_S - } - - if( info & PROCESS_EE_MMX ) MOVDMtoMMX(EEREC_T, (u32)&s_sltone); - else MOV32ItoR(EAX, 1); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], _Imm_ >= 0 ? 0 : 0xffffffff); - j8Ptr[0] = JB8( 0 ); - j8Ptr[2] = JA8( 0 ); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], (s32)_Imm_ ); - j8Ptr[1] = JB8(0); - - x86SetJ8(j8Ptr[2]); - if( info & PROCESS_EE_MMX ) PXORRtoR(EEREC_T, EEREC_T); - else XOR32RtoR(EAX, EAX); - - x86SetJ8(j8Ptr[0]); - x86SetJ8(j8Ptr[1]); - - if( !(info & PROCESS_EE_MMX) ) { - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - if( EEINST_ISLIVE1(_Rt_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); - else EEINST_RESETHASLIVE1(_Rt_); - } - EEINST_SETSIGNEXT(_Rt_); -} - -EERECOMPILE_CODEX(eeRecompileCode1, SLTIU); - -//// SLTI -void recSLTI_const() -{ - g_cpuConstRegs[_Rt_].UD[0] = g_cpuConstRegs[_Rs_].SD[0] < (s64)(_Imm_); -} - -void recSLTI_(int info) -{ - if( info & PROCESS_EE_MMX) { - - if( EEINST_ISSIGNEXT(_Rs_) ) { - u32* ptempmem = recAllocStackMem(8,4); - ptempmem[0] = _Imm_; - ptempmem[1] = 0; - recSLTmemconstt(EEREC_T, EEREC_S, (u32)ptempmem, 1); - EEINST_SETSIGNEXT(_Rt_); - return; - } - - if( info & PROCESS_EE_MODEWRITES ) { - MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_], EEREC_S); - if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; - } - mmxregs[EEREC_T].mode |= MODE_WRITE; // in case EEREC_T==EEREC_S - } - - // test silent hill if modding - if( info & PROCESS_EE_MMX ) MOVDMtoMMX(EEREC_T, (u32)&s_sltone); - else MOV32ItoR(EAX, 1); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], _Imm_ >= 0 ? 0 : 0xffffffff); - j8Ptr[0] = JL8( 0 ); - j8Ptr[2] = JG8( 0 ); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], (s32)_Imm_ ); - j8Ptr[1] = JB8(0); - - x86SetJ8(j8Ptr[2]); - if( info & PROCESS_EE_MMX ) PXORRtoR(EEREC_T, EEREC_T); - else XOR32RtoR(EAX, EAX); - - x86SetJ8(j8Ptr[0]); - x86SetJ8(j8Ptr[1]); - - if( !(info & PROCESS_EE_MMX) ) { - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - if( EEINST_ISLIVE1(_Rt_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); - else EEINST_RESETHASLIVE1(_Rt_); - } - EEINST_SETSIGNEXT(_Rt_); -} - -EERECOMPILE_CODEX(eeRecompileCode1, SLTI); - -//// ANDI -void recANDI_const() -{ - g_cpuConstRegs[_Rt_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] & (u64)_ImmU_; // Zero-extended Immediate -} - -void recLogicalOpI(int info, int op) -{ - if( info & PROCESS_EE_MMX ) { - SetMMXstate(); - - if( _ImmU_ != 0 ) { - u32* ptempmem = recAllocStackMem(8, 8); - ptempmem[0] = _ImmU_; - ptempmem[1] = 0; - - if( EEREC_T != EEREC_S ) MOVQRtoR(EEREC_T, EEREC_S); - LogicalOpMtoR(EEREC_T, (u32)ptempmem, op); - } - else { - if( op == 0 ) PXORRtoR(EEREC_T, EEREC_T); - else if( EEREC_T != EEREC_S ) MOVQRtoR(EEREC_T, EEREC_S); - } - return; - } - - if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) && ((_Rt_ != _Rs_) || (_ImmU_==0)) ) { - int rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE); - SetMMXstate(); - - if( op == 0 ) { - if ( _ImmU_ != 0 ) { - u32* ptempmem = recAllocStackMem(8, 8); - ptempmem[0] = _ImmU_; - ptempmem[1] = 0; - MOVDMtoMMX(rtreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - PANDMtoR(rtreg, (u32)ptempmem); - } - else PXORRtoR(rtreg, rtreg); - } - else { - MOVQMtoR(rtreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - if ( _ImmU_ != 0 ) { - u32* ptempmem = recAllocStackMem(8, 8); - ptempmem[0] = _ImmU_; - ptempmem[1] = 0; - LogicalOpMtoR(rtreg, (u32)ptempmem, op); - } - } - } - else { - if ( _ImmU_ != 0 ) - { - if( _Rt_ == _Rs_ ) { - LogicalOp32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], _ImmU_, op); - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if( op != 0 && EEINST_ISLIVE1(_Rt_) ) - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); - LogicalOp32ItoR( EAX, _ImmU_, op); - if( op != 0 && EEINST_ISLIVE1(_Rt_) ) - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - } - - if( op == 0 ) { - if( EEINST_ISLIVE1(_Rt_ ) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); - else EEINST_RESETHASLIVE1(_Rt_); - } - } - else - { - if( op == 0 ) { - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], 0 ); - if( EEINST_ISLIVE1(_Rt_ ) ) - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); - } - else { - if( _Rt_ != _Rs_ ) { - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if( EEINST_ISLIVE1(_Rt_ ) ) - MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - if( EEINST_ISLIVE1(_Rt_ ) ) - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); - } - } - - if( !EEINST_ISLIVE1(_Rt_) ) EEINST_RESETHASLIVE1(_Rt_); - } - } -} - -void recANDI_(int info) -{ - recLogicalOpI(info, 0); -} - -EERECOMPILE_CODEX(eeRecompileCode1, ANDI); - -//////////////////////////////////////////////////// -void recORI_const() -{ - g_cpuConstRegs[_Rt_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] | (u64)_ImmU_; // Zero-extended Immediate -} - -void recORI_(int info) -{ - recLogicalOpI(info, 1); -} - -EERECOMPILE_CODEX(eeRecompileCode1, ORI); - -//////////////////////////////////////////////////// -void recXORI_const() -{ - g_cpuConstRegs[_Rt_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] ^ (u64)_ImmU_; // Zero-extended Immediate -} - -void recXORI_(int info) -{ - recLogicalOpI(info, 2); -} - -EERECOMPILE_CODEX(eeRecompileCode1, XORI); - -#else - -//////////////////////////////////////////////////// -void recADDI( void ) -{ - if ( ! _Rt_ ) - { - return; - } - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - - if ( _Imm_ != 0 ) - { - ADD32ItoR( EAX, _Imm_ ); - } - - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); - -} - -//////////////////////////////////////////////////// -void recADDIU( void ) -{ - recADDI( ); -} - -//////////////////////////////////////////////////// -void recDADDI( void ) -{ -#ifdef __x86_64_ - if ( ! _Rt_ ) - { - return; - } - - MOV64MtoR( RAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - { - ADD64ItoR( EAX, _Imm_ ); - } - MOV64RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], RAX ); -#else - if ( ! _Rt_ ) - { - return; - } - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); - if ( _Imm_ != 0 ) - { - ADD32ItoR( EAX, _Imm_ ); - if ( _Imm_ < 0 ) - { - ADC32ItoR( EDX, 0xffffffff ); - } - else - { - ADC32ItoR( EDX, 0 ); - } - } - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); -#endif -} - -//////////////////////////////////////////////////// -void recDADDIU( void ) -{ - recDADDI( ); -} - -//////////////////////////////////////////////////// -void recSLTIU( void ) -{ - if ( ! _Rt_ ) - return; - - MOV32ItoR(EAX, 1); - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], _Imm_ >= 0 ? 0 : 0xffffffff); - j8Ptr[0] = JB8( 0 ); - j8Ptr[2] = JA8( 0 ); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], (s32)_Imm_ ); - j8Ptr[1] = JB8(0); - - x86SetJ8(j8Ptr[2]); - XOR32RtoR(EAX, EAX); - - x86SetJ8(j8Ptr[0]); - x86SetJ8(j8Ptr[1]); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); -} - -//////////////////////////////////////////////////// -void recSLTI( void ) -{ - if ( ! _Rt_ ) - return; - - // test silent hill if modding - MOV32ItoR(EAX, 1); - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], _Imm_ >= 0 ? 0 : 0xffffffff); - j8Ptr[0] = JL8( 0 ); - j8Ptr[2] = JG8( 0 ); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], (s32)_Imm_ ); - j8Ptr[1] = JB8(0); - - x86SetJ8(j8Ptr[2]); - XOR32RtoR(EAX, EAX); - - x86SetJ8(j8Ptr[0]); - x86SetJ8(j8Ptr[1]); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); -} - -//////////////////////////////////////////////////// -void recANDI( void ) -{ - if ( ! _Rt_ ) - { - return; - } - if ( _ImmU_ != 0 ) - { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - AND32ItoR( EAX, _ImmU_ ); - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - } - else - { - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], 0 ); - } - -} - -//////////////////////////////////////////////////// -static u64 _imm = 0; // temp immediate - -void recORI( void ) -{ - if ( ! _Rt_ ) - return; - - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - if ( _ImmU_ != 0 ) - { - MOV32ItoM( (int)&_imm, _ImmU_ ); - MOVQMtoR( MM1, (int)&_imm ); - PORRtoR( MM0, MM1 ); - } - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ], MM0 ); - SetMMXstate(); -} - -//////////////////////////////////////////////////// -void recXORI( void ) -{ - if ( ! _Rt_ ) - return; - - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); - if ( _ImmU_ != 0 ) - { - MOV32ItoM( (int)&_imm, _ImmU_ ); - MOVQMtoR( MM1, (int)&_imm ); - PXORRtoR( MM0, MM1 ); - } - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rt_ ], MM0 ); - SetMMXstate(); -} - -#endif - -} } } +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "R5900OpcodeTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl +{ + +/********************************************************* +* Arithmetic with immediate operand * +* Format: OP rt, rs, immediate * +*********************************************************/ + +#ifndef ARITHMETICIMM_RECOMPILE + +namespace Interp = R5900::Interpreter::OpcodeImpl; + +REC_FUNC_DEL(ADDI, _Rt_); +REC_FUNC_DEL(ADDIU, _Rt_); +REC_FUNC_DEL(DADDI, _Rt_); +REC_FUNC_DEL(DADDIU, _Rt_); +REC_FUNC_DEL(ANDI, _Rt_); +REC_FUNC_DEL(ORI, _Rt_); +REC_FUNC_DEL(XORI, _Rt_); + +REC_FUNC_DEL(SLTI, _Rt_); +REC_FUNC_DEL(SLTIU, _Rt_); + +#elif defined(EE_CONST_PROP) + +//// ADDI +void recADDI_const( void ) +{ + g_cpuConstRegs[_Rt_].SD[0] = (s64)(g_cpuConstRegs[_Rs_].SL[0] + (s32)_Imm_); +} + +void recADDI_(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + EEINST_SETSIGNEXT(_Rt_); + EEINST_SETSIGNEXT(_Rs_); + + if ( info & PROCESS_EE_MMX ) { + if ( _Imm_ != 0 ) { + + u32* ptempmem = recAllocStackMem(8, 8); + ptempmem[0] = (s32)_Imm_; + ptempmem[1] = 0; + + if ( EEREC_T != EEREC_S ) MOVQRtoR(EEREC_T, EEREC_S); + PADDDMtoR(EEREC_T, (u32)ptempmem); + if ( EEINST_ISLIVE1(_Rt_) ) _signExtendGPRtoMMX(EEREC_T, _Rt_, 0); + else EEINST_RESETHASLIVE1(_Rt_); + } + else { + // just move and sign extend + if ( !EEINST_HASLIVE1(_Rs_) ) { + if ( EEINST_ISLIVE1(_Rt_) ) _signExtendGPRMMXtoMMX(EEREC_T, _Rt_, EEREC_S, _Rs_); + else EEINST_RESETHASLIVE1(_Rt_); + } + else if ( EEREC_T != EEREC_S ) MOVQRtoR(EEREC_T, EEREC_S); + } + return; + } + + if ( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) && (_Rt_ != _Rs_) ) { + int rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE); + SetMMXstate(); + + if ( _Imm_ != 0 ) { + u32* ptempmem = recAllocStackMem(8, 8); + ptempmem[0] = (s32)_Imm_; + ptempmem[1] = 0; + + MOVDMtoMMX(rtreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + PADDDMtoR(rtreg, (u32)ptempmem); + + if ( EEINST_ISLIVE1(_Rt_) ) _signExtendGPRtoMMX(rtreg, _Rt_, 0); + else EEINST_RESETHASLIVE1(_Rt_); + } + else { + // just move and sign extend + if ( !EEINST_HASLIVE1(_Rs_) ) { + MOVDMtoMMX(rtreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + if ( EEINST_ISLIVE1(_Rt_) ) _signExtendGPRtoMMX(rtreg, _Rt_, 0); + else EEINST_RESETHASLIVE1(_Rt_); + } + else MOVQMtoR(rtreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + } + } + else { + if ( _Rt_ == _Rs_ ) { + ADD32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], _Imm_); + if ( EEINST_ISLIVE1(_Rt_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ]); + else EEINST_RESETHASLIVE1(_Rt_); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + + if ( _Imm_ != 0 ) ADD32ItoR( EAX, _Imm_ ); + + if ( EEINST_ISLIVE1(_Rt_) ) { + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rt_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + } + } + } +} + +EERECOMPILE_CODEX(eeRecompileCode1, ADDI); + +//////////////////////////////////////////////////// +void recADDIU( void ) +{ + recADDI( ); +} + +//////////////////////////////////////////////////// +void recDADDI_const( void ) +{ + g_cpuConstRegs[_Rt_].SD[0] = g_cpuConstRegs[_Rs_].SD[0] + (s64)_Imm_; +} + +void recDADDI_(int info) +{ + assert( !(info&PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + + if( _Imm_ != 0 ) { + + // flush + u32* ptempmem = recAllocStackMem(8, 8); + ptempmem[0] = _Imm_; + ptempmem[1] = _Imm_ >= 0 ? 0 : 0xffffffff; + if( EEREC_T != EEREC_S ) MOVQRtoR(EEREC_T, EEREC_S); + PADDQMtoR(EEREC_T, (u32)ptempmem); + } + else { + if( EEREC_T != EEREC_S ) MOVQRtoR(EEREC_T, EEREC_S); + } + return; + } + + if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) ) { + int rtreg; + u32* ptempmem = recAllocStackMem(8, 8); + ptempmem[0] = _Imm_; + ptempmem[1] = _Imm_ >= 0 ? 0 : 0xffffffff; + + rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE); + SetMMXstate(); + + MOVQMtoR(rtreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + PADDQMtoR(rtreg, (u32)ptempmem); + } + else { + if( _Rt_ == _Rs_ ) { + ADD32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], _Imm_); + ADC32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], _Imm_<0?0xffffffff:0); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + + if( EEINST_ISLIVE1(_Rt_) ) + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + + if( EEINST_ISLIVE1(_Rt_) ) { + ADC32ItoR( EDX, _Imm_ < 0?0xffffffff:0); + } + } + + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + + if( EEINST_ISLIVE1(_Rt_) ) + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); + else + EEINST_RESETHASLIVE1(_Rt_); + } + } +} + +EERECOMPILE_CODEX(eeRecompileCode1, DADDI); + +//// DADDIU +void recDADDIU( void ) +{ + recDADDI( ); +} + +//// SLTIU +void recSLTIU_const() +{ + g_cpuConstRegs[_Rt_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] < (u64)(_Imm_); +} + +extern void recSLTmemconstt(int regd, int regs, u32 mem, int sign); +extern u32 s_sltone; + +void recSLTIU_(int info) +{ + if( info & PROCESS_EE_MMX ) { + if( EEINST_ISSIGNEXT(_Rs_) ) { + u32* ptempmem = recAllocStackMem(8,4); + ptempmem[0] = ((s32)(_Imm_))^0x80000000; + ptempmem[1] = 0; + recSLTmemconstt(EEREC_T, EEREC_S, (u32)ptempmem, 0); + EEINST_SETSIGNEXT(_Rt_); + return; + } + + if( info & PROCESS_EE_MODEWRITES ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_], EEREC_S); + if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; + } + mmxregs[EEREC_T].mode |= MODE_WRITE; // in case EEREC_T==EEREC_S + } + + if( info & PROCESS_EE_MMX ) MOVDMtoMMX(EEREC_T, (u32)&s_sltone); + else MOV32ItoR(EAX, 1); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], _Imm_ >= 0 ? 0 : 0xffffffff); + j8Ptr[0] = JB8( 0 ); + j8Ptr[2] = JA8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], (s32)_Imm_ ); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + if( info & PROCESS_EE_MMX ) PXORRtoR(EEREC_T, EEREC_T); + else XOR32RtoR(EAX, EAX); + + x86SetJ8(j8Ptr[0]); + x86SetJ8(j8Ptr[1]); + + if( !(info & PROCESS_EE_MMX) ) { + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rt_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + else EEINST_RESETHASLIVE1(_Rt_); + } + EEINST_SETSIGNEXT(_Rt_); +} + +EERECOMPILE_CODEX(eeRecompileCode1, SLTIU); + +//// SLTI +void recSLTI_const() +{ + g_cpuConstRegs[_Rt_].UD[0] = g_cpuConstRegs[_Rs_].SD[0] < (s64)(_Imm_); +} + +void recSLTI_(int info) +{ + if( info & PROCESS_EE_MMX) { + + if( EEINST_ISSIGNEXT(_Rs_) ) { + u32* ptempmem = recAllocStackMem(8,4); + ptempmem[0] = _Imm_; + ptempmem[1] = 0; + recSLTmemconstt(EEREC_T, EEREC_S, (u32)ptempmem, 1); + EEINST_SETSIGNEXT(_Rt_); + return; + } + + if( info & PROCESS_EE_MODEWRITES ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_], EEREC_S); + if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; + } + mmxregs[EEREC_T].mode |= MODE_WRITE; // in case EEREC_T==EEREC_S + } + + // test silent hill if modding + if( info & PROCESS_EE_MMX ) MOVDMtoMMX(EEREC_T, (u32)&s_sltone); + else MOV32ItoR(EAX, 1); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], _Imm_ >= 0 ? 0 : 0xffffffff); + j8Ptr[0] = JL8( 0 ); + j8Ptr[2] = JG8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], (s32)_Imm_ ); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + if( info & PROCESS_EE_MMX ) PXORRtoR(EEREC_T, EEREC_T); + else XOR32RtoR(EAX, EAX); + + x86SetJ8(j8Ptr[0]); + x86SetJ8(j8Ptr[1]); + + if( !(info & PROCESS_EE_MMX) ) { + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rt_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + else EEINST_RESETHASLIVE1(_Rt_); + } + EEINST_SETSIGNEXT(_Rt_); +} + +EERECOMPILE_CODEX(eeRecompileCode1, SLTI); + +//// ANDI +void recANDI_const() +{ + g_cpuConstRegs[_Rt_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] & (u64)_ImmU_; // Zero-extended Immediate +} + +void recLogicalOpI(int info, int op) +{ + if( info & PROCESS_EE_MMX ) { + SetMMXstate(); + + if( _ImmU_ != 0 ) { + u32* ptempmem = recAllocStackMem(8, 8); + ptempmem[0] = _ImmU_; + ptempmem[1] = 0; + + if( EEREC_T != EEREC_S ) MOVQRtoR(EEREC_T, EEREC_S); + LogicalOpMtoR(EEREC_T, (u32)ptempmem, op); + } + else { + if( op == 0 ) PXORRtoR(EEREC_T, EEREC_T); + else if( EEREC_T != EEREC_S ) MOVQRtoR(EEREC_T, EEREC_S); + } + return; + } + + if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) && ((_Rt_ != _Rs_) || (_ImmU_==0)) ) { + int rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE); + SetMMXstate(); + + if( op == 0 ) { + if ( _ImmU_ != 0 ) { + u32* ptempmem = recAllocStackMem(8, 8); + ptempmem[0] = _ImmU_; + ptempmem[1] = 0; + MOVDMtoMMX(rtreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + PANDMtoR(rtreg, (u32)ptempmem); + } + else PXORRtoR(rtreg, rtreg); + } + else { + MOVQMtoR(rtreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + if ( _ImmU_ != 0 ) { + u32* ptempmem = recAllocStackMem(8, 8); + ptempmem[0] = _ImmU_; + ptempmem[1] = 0; + LogicalOpMtoR(rtreg, (u32)ptempmem, op); + } + } + } + else { + if ( _ImmU_ != 0 ) + { + if( _Rt_ == _Rs_ ) { + LogicalOp32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], _ImmU_, op); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if( op != 0 && EEINST_ISLIVE1(_Rt_) ) + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + LogicalOp32ItoR( EAX, _ImmU_, op); + if( op != 0 && EEINST_ISLIVE1(_Rt_) ) + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + } + + if( op == 0 ) { + if( EEINST_ISLIVE1(_Rt_ ) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + else EEINST_RESETHASLIVE1(_Rt_); + } + } + else + { + if( op == 0 ) { + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], 0 ); + if( EEINST_ISLIVE1(_Rt_ ) ) + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + } + else { + if( _Rt_ != _Rs_ ) { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if( EEINST_ISLIVE1(_Rt_ ) ) + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rt_ ) ) + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); + } + } + + if( !EEINST_ISLIVE1(_Rt_) ) EEINST_RESETHASLIVE1(_Rt_); + } + } +} + +void recANDI_(int info) +{ + recLogicalOpI(info, 0); +} + +EERECOMPILE_CODEX(eeRecompileCode1, ANDI); + +//////////////////////////////////////////////////// +void recORI_const() +{ + g_cpuConstRegs[_Rt_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] | (u64)_ImmU_; // Zero-extended Immediate +} + +void recORI_(int info) +{ + recLogicalOpI(info, 1); +} + +EERECOMPILE_CODEX(eeRecompileCode1, ORI); + +//////////////////////////////////////////////////// +void recXORI_const() +{ + g_cpuConstRegs[_Rt_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] ^ (u64)_ImmU_; // Zero-extended Immediate +} + +void recXORI_(int info) +{ + recLogicalOpI(info, 2); +} + +EERECOMPILE_CODEX(eeRecompileCode1, XORI); + +#else + +//////////////////////////////////////////////////// +void recADDI( void ) +{ + if ( ! _Rt_ ) + { + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +void recADDIU( void ) +{ + recADDI( ); +} + +//////////////////////////////////////////////////// +void recDADDI( void ) +{ +#ifdef __x86_64_ + if ( ! _Rt_ ) + { + return; + } + + MOV64MtoR( RAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD64ItoR( EAX, _Imm_ ); + } + MOV64RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], RAX ); +#else + if ( ! _Rt_ ) + { + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + if ( _Imm_ < 0 ) + { + ADC32ItoR( EDX, 0xffffffff ); + } + else + { + ADC32ItoR( EDX, 0 ); + } + } + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); +#endif +} + +//////////////////////////////////////////////////// +void recDADDIU( void ) +{ + recDADDI( ); +} + +//////////////////////////////////////////////////// +void recSLTIU( void ) +{ + if ( ! _Rt_ ) + return; + + MOV32ItoR(EAX, 1); + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], _Imm_ >= 0 ? 0 : 0xffffffff); + j8Ptr[0] = JB8( 0 ); + j8Ptr[2] = JA8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], (s32)_Imm_ ); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + XOR32RtoR(EAX, EAX); + + x86SetJ8(j8Ptr[0]); + x86SetJ8(j8Ptr[1]); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); +} + +//////////////////////////////////////////////////// +void recSLTI( void ) +{ + if ( ! _Rt_ ) + return; + + // test silent hill if modding + MOV32ItoR(EAX, 1); + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], _Imm_ >= 0 ? 0 : 0xffffffff); + j8Ptr[0] = JL8( 0 ); + j8Ptr[2] = JG8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], (s32)_Imm_ ); + j8Ptr[1] = JB8(0); + + x86SetJ8(j8Ptr[2]); + XOR32RtoR(EAX, EAX); + + x86SetJ8(j8Ptr[0]); + x86SetJ8(j8Ptr[1]); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); +} + +//////////////////////////////////////////////////// +void recANDI( void ) +{ + if ( ! _Rt_ ) + { + return; + } + if ( _ImmU_ != 0 ) + { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( EAX, _ImmU_ ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + } + else + { + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], 0 ); + } + +} + +//////////////////////////////////////////////////// +static u64 _imm = 0; // temp immediate + +void recORI( void ) +{ + if ( ! _Rt_ ) + return; + + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + if ( _ImmU_ != 0 ) + { + MOV32ItoM( (int)&_imm, _ImmU_ ); + MOVQMtoR( MM1, (int)&_imm ); + PORRtoR( MM0, MM1 ); + } + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ], MM0 ); + SetMMXstate(); +} + +//////////////////////////////////////////////////// +void recXORI( void ) +{ + if ( ! _Rt_ ) + return; + + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + if ( _ImmU_ != 0 ) + { + MOV32ItoM( (int)&_imm, _ImmU_ ); + MOVQMtoR( MM1, (int)&_imm ); + PXORRtoR( MM0, MM1 ); + } + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rt_ ], MM0 ); + SetMMXstate(); +} + +#endif + +} } } diff --git a/pcsx2/x86/ix86-32/iR5900Branch.cpp b/pcsx2/x86/ix86-32/iR5900Branch.cpp index 7137531684..e1397d139f 100644 --- a/pcsx2/x86/ix86-32/iR5900Branch.cpp +++ b/pcsx2/x86/ix86-32/iR5900Branch.cpp @@ -1,1198 +1,1198 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -// recompiler reworked to add dynamic linking zerofrog(@gmail.com) Jan06 - -#include "PrecompiledHeader.h" - -#include "Common.h" -#include "R5900OpcodeTables.h" -#include "ix86/ix86.h" -#include "iR5900.h" - -namespace Interp = R5900::Interpreter::OpcodeImpl; - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl -{ - -/********************************************************* -* Register branch logic * -* Format: OP rs, rt, offset * -*********************************************************/ -#ifndef BRANCH_RECOMPILE - -REC_SYS(BEQ); -REC_SYS(BEQL); -REC_SYS(BNE); -REC_SYS(BNEL); -REC_SYS(BLTZ); -REC_SYS(BGTZ); -REC_SYS(BLEZ); -REC_SYS(BGEZ); -REC_SYS(BGTZL); -REC_SYS(BLTZL); -REC_SYS(BLTZAL); -REC_SYS(BLTZALL); -REC_SYS(BLEZL); -REC_SYS(BGEZL); -REC_SYS(BGEZAL); -REC_SYS(BGEZALL); - -#else - -#if defined(EE_CONST_PROP) - -void recSetBranchEQ(int info, int bne, int process) -{ - if( info & PROCESS_EE_MMX ) { - int t0reg; - - SetMMXstate(); - - if( process & PROCESS_CONSTS ) { - if( (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rt_) ) { - _deleteMMXreg(_Rt_, 1); - mmxregs[EEREC_T].inuse = 0; - t0reg = EEREC_T; - } - else { - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQRtoR(t0reg, EEREC_T); - } - - _flushConstReg(_Rs_); - PCMPEQDMtoR(t0reg, (u32)&cpuRegs.GPR.r[_Rs_].UL[0]); - - if( t0reg != EEREC_T ) _freeMMXreg(t0reg); - } - else if( process & PROCESS_CONSTT ) { - if( (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rs_) ) { - _deleteMMXreg(_Rs_, 1); - mmxregs[EEREC_S].inuse = 0; - t0reg = EEREC_S; - } - else { - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQRtoR(t0reg, EEREC_S); - } - - _flushConstReg(_Rt_); - PCMPEQDMtoR(t0reg, (u32)&cpuRegs.GPR.r[_Rt_].UL[0]); - - if( t0reg != EEREC_S ) _freeMMXreg(t0reg); - } - else { - - if( (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rs_) ) { - _deleteMMXreg(_Rs_, 1); - mmxregs[EEREC_S].inuse = 0; - t0reg = EEREC_S; - PCMPEQDRtoR(t0reg, EEREC_T); - } - else if( (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rt_) ) { - _deleteMMXreg(_Rt_, 1); - mmxregs[EEREC_T].inuse = 0; - t0reg = EEREC_T; - PCMPEQDRtoR(t0reg, EEREC_S); - } - else { - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQRtoR(t0reg, EEREC_S); - PCMPEQDRtoR(t0reg, EEREC_T); - } - - if( t0reg != EEREC_S && t0reg != EEREC_T ) _freeMMXreg(t0reg); - } - - PMOVMSKBMMXtoR(EAX, t0reg); - - _eeFlushAllUnused(); - - CMP8ItoR( EAX, 0xff ); - - if( bne ) j32Ptr[ 1 ] = JE32( 0 ); - else j32Ptr[ 0 ] = j32Ptr[ 1 ] = JNE32( 0 ); - } - else if( info & PROCESS_EE_XMM ) { - int t0reg; - - if( process & PROCESS_CONSTS ) { - if( (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rt_) ) { - _deleteGPRtoXMMreg(_Rt_, 1); - xmmregs[EEREC_T].inuse = 0; - t0reg = EEREC_T; - } - else { - t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSE2_MOVQ_XMM_to_XMM(t0reg, EEREC_T); - } - - _flushConstReg(_Rs_); - SSE2_PCMPEQD_M128_to_XMM(t0reg, (u32)&cpuRegs.GPR.r[_Rs_].UL[0]); - - - if( t0reg != EEREC_T ) _freeXMMreg(t0reg); - } - else if( process & PROCESS_CONSTT ) { - if( (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rs_) ) { - _deleteGPRtoXMMreg(_Rs_, 1); - xmmregs[EEREC_S].inuse = 0; - t0reg = EEREC_S; - } - else { - t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSE2_MOVQ_XMM_to_XMM(t0reg, EEREC_S); - } - - _flushConstReg(_Rt_); - SSE2_PCMPEQD_M128_to_XMM(t0reg, (u32)&cpuRegs.GPR.r[_Rt_].UL[0]); - - if( t0reg != EEREC_S ) _freeXMMreg(t0reg); - } - else { - - if( (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rs_) ) { - _deleteGPRtoXMMreg(_Rs_, 1); - xmmregs[EEREC_S].inuse = 0; - t0reg = EEREC_S; - SSE2_PCMPEQD_XMM_to_XMM(t0reg, EEREC_T); - } - else if( (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rt_) ) { - _deleteGPRtoXMMreg(_Rt_, 1); - xmmregs[EEREC_T].inuse = 0; - t0reg = EEREC_T; - SSE2_PCMPEQD_XMM_to_XMM(t0reg, EEREC_S); - } - else { - t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSE2_MOVQ_XMM_to_XMM(t0reg, EEREC_S); - SSE2_PCMPEQD_XMM_to_XMM(t0reg, EEREC_T); - } - - if( t0reg != EEREC_S && t0reg != EEREC_T ) _freeXMMreg(t0reg); - } - - SSE_MOVMSKPS_XMM_to_R32(EAX, t0reg); - - _eeFlushAllUnused(); - - AND8ItoR(EAX, 3); - CMP8ItoR( EAX, 0x3 ); - - if( bne ) j32Ptr[ 1 ] = JE32( 0 ); - else j32Ptr[ 0 ] = j32Ptr[ 1 ] = JNE32( 0 ); - } - else { - - _eeFlushAllUnused(); - - if( bne ) { - if( process & PROCESS_CONSTS ) { - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0] ); - j8Ptr[ 0 ] = JNE8( 0 ); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1] ); - j32Ptr[ 1 ] = JE32( 0 ); - } - else if( process & PROCESS_CONSTT ) { - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0] ); - j8Ptr[ 0 ] = JNE8( 0 ); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1] ); - j32Ptr[ 1 ] = JE32( 0 ); - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - CMP32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - j8Ptr[ 0 ] = JNE8( 0 ); - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); - CMP32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - j32Ptr[ 1 ] = JE32( 0 ); - } - - x86SetJ8( j8Ptr[0] ); - } - else { - // beq - if( process & PROCESS_CONSTS ) { - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0] ); - j32Ptr[ 0 ] = JNE32( 0 ); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1] ); - j32Ptr[ 1 ] = JNE32( 0 ); - } - else if( process & PROCESS_CONSTT ) { - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0] ); - j32Ptr[ 0 ] = JNE32( 0 ); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1] ); - j32Ptr[ 1 ] = JNE32( 0 ); - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - CMP32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - j32Ptr[ 0 ] = JNE32( 0 ); - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); - CMP32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - j32Ptr[ 1 ] = JNE32( 0 ); - } - } - } - - _clearNeededMMXregs(); - _clearNeededXMMregs(); -} - -void recSetBranchL(int ltz) -{ - int regs = _checkMMXreg(MMX_GPR+_Rs_, MODE_READ); - - if( regs >= 0 ) { - - int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - - SetMMXstate(); - - PXORRtoR(t0reg, t0reg); - PCMPGTDRtoR(t0reg, regs); - PMOVMSKBMMXtoR(EAX, t0reg); - - _freeMMXreg(t0reg); - _eeFlushAllUnused(); - - TEST8ItoR( EAX, 0x80 ); - - if( ltz ) j32Ptr[ 0 ] = JZ32( 0 ); - else j32Ptr[ 0 ] = JNZ32( 0 ); - - return; - } - - regs = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ); - - if( regs >= 0 ) { - - int t0reg = _allocTempXMMreg(XMMT_INT, -1); - SSE_XORPS_XMM_to_XMM(t0reg, t0reg); - SSE2_PCMPGTD_XMM_to_XMM(t0reg, regs); - SSE_MOVMSKPS_XMM_to_R32(EAX, t0reg); - - _freeXMMreg(t0reg); - _eeFlushAllUnused(); - - TEST8ItoR( EAX, 2 ); - - if( ltz ) j32Ptr[ 0 ] = JZ32( 0 ); - else j32Ptr[ 0 ] = JNZ32( 0 ); - - return; - } - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0 ); - if( ltz ) j32Ptr[ 0 ] = JGE32( 0 ); - else j32Ptr[ 0 ] = JL32( 0 ); - - _clearNeededMMXregs(); - _clearNeededXMMregs(); -} - -//// BEQ -void recBEQ_const() -{ - u32 branchTo; - - if( g_cpuConstRegs[_Rs_].SD[0] == g_cpuConstRegs[_Rt_].SD[0] ) - branchTo = ((s32)_Imm_ * 4) + pc; - else - branchTo = pc+4; - - recompileNextInstruction(1); - SetBranchImm( branchTo ); -} - -void recBEQ_process(int info, int process) -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - - if ( _Rs_ == _Rt_ ) - { - recompileNextInstruction(1); - SetBranchImm( branchTo ); - } - else - { - recSetBranchEQ(info, 0, process); - - SaveBranchState(); - recompileNextInstruction(1); - - SetBranchImm(branchTo); - - x86SetJ32( j32Ptr[ 0 ] ); - x86SetJ32( j32Ptr[ 1 ] ); - - // recopy the next inst - pc -= 4; - LoadBranchState(); - recompileNextInstruction(1); - - SetBranchImm(pc); - } -} - -void recBEQ_(int info) { recBEQ_process(info, 0); } -void recBEQ_consts(int info) { recBEQ_process(info, PROCESS_CONSTS); } -void recBEQ_constt(int info) { recBEQ_process(info, PROCESS_CONSTT); } - -EERECOMPILE_CODE0(BEQ, XMMINFO_READS|XMMINFO_READT); - -//// BNE -void recBNE_const() -{ - u32 branchTo; - - if( g_cpuConstRegs[_Rs_].SD[0] != g_cpuConstRegs[_Rt_].SD[0] ) - branchTo = ((s32)_Imm_ * 4) + pc; - else - branchTo = pc+4; - - recompileNextInstruction(1); - SetBranchImm( branchTo ); -} - -void recBNE_process(int info, int process) -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - - if ( _Rs_ == _Rt_ ) - { - recompileNextInstruction(1); - SetBranchImm(pc); - return; - } - - recSetBranchEQ(info, 1, process); - - SaveBranchState(); - recompileNextInstruction(1); - - SetBranchImm(branchTo); - - x86SetJ32( j32Ptr[ 1 ] ); - - // recopy the next inst - pc -= 4; - LoadBranchState(); - recompileNextInstruction(1); - - SetBranchImm(pc); -} - -void recBNE_(int info) { recBNE_process(info, 0); } -void recBNE_consts(int info) { recBNE_process(info, PROCESS_CONSTS); } -void recBNE_constt(int info) { recBNE_process(info, PROCESS_CONSTT); } - -EERECOMPILE_CODE0(BNE, XMMINFO_READS|XMMINFO_READT); - -//// BEQL -void recBEQL_const() -{ - if( g_cpuConstRegs[_Rs_].SD[0] == g_cpuConstRegs[_Rt_].SD[0] ) { - u32 branchTo = ((s32)_Imm_ * 4) + pc; - recompileNextInstruction(1); - SetBranchImm( branchTo ); - } - else { - SetBranchImm( pc+4 ); - } -} - -void recBEQL_process(int info, int process) -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - recSetBranchEQ(info, 0, process); - - SaveBranchState(); - recompileNextInstruction(1); - SetBranchImm(branchTo); - - x86SetJ32( j32Ptr[ 0 ] ); - x86SetJ32( j32Ptr[ 1 ] ); - - LoadBranchState(); - SetBranchImm(pc); -} - -void recBEQL_(int info) { recBEQL_process(info, 0); } -void recBEQL_consts(int info) { recBEQL_process(info, PROCESS_CONSTS); } -void recBEQL_constt(int info) { recBEQL_process(info, PROCESS_CONSTT); } - -EERECOMPILE_CODE0(BEQL, XMMINFO_READS|XMMINFO_READT); - -//// BNEL -void recBNEL_const() -{ - if( g_cpuConstRegs[_Rs_].SD[0] != g_cpuConstRegs[_Rt_].SD[0] ) { - u32 branchTo = ((s32)_Imm_ * 4) + pc; - recompileNextInstruction(1); - SetBranchImm(branchTo); - } - else { - SetBranchImm( pc+4 ); - } -} - -void recBNEL_process(int info, int process) -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - - recSetBranchEQ(info, 0, process); - - SaveBranchState(); - SetBranchImm(pc+4); - - x86SetJ32( j32Ptr[ 0 ] ); - x86SetJ32( j32Ptr[ 1 ] ); - - // recopy the next inst - LoadBranchState(); - recompileNextInstruction(1); - SetBranchImm(branchTo); -} - -void recBNEL_(int info) { recBNEL_process(info, 0); } -void recBNEL_consts(int info) { recBNEL_process(info, PROCESS_CONSTS); } -void recBNEL_constt(int info) { recBNEL_process(info, PROCESS_CONSTT); } - -EERECOMPILE_CODE0(BNEL, XMMINFO_READS|XMMINFO_READT); - -/********************************************************* -* Register branch logic * -* Format: OP rs, offset * -*********************************************************/ - -//////////////////////////////////////////////////// -//void recBLTZAL( void ) -//{ -// SysPrintf("BLTZAL\n"); -// _eeFlushAllUnused(); -// MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); -// MOV32ItoM( (int)&cpuRegs.pc, pc ); -// iFlushCall(FLUSH_EVERYTHING); -// CALLFunc( (int)BLTZAL ); -// branch = 2; -//} - -//////////////////////////////////////////////////// -void recBLTZAL() -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - - _eeOnWriteReg(31, 0); - _eeFlushAllUnused(); - - _deleteEEreg(31, 0); - MOV32ItoM((uptr)&cpuRegs.GPR.r[31].UL[0], pc+4); - MOV32ItoM((uptr)&cpuRegs.GPR.r[31].UL[1], 0); - - if( GPR_IS_CONST1(_Rs_) ) { - if( !(g_cpuConstRegs[_Rs_].SD[0] < 0) ) - branchTo = pc+4; - - recompileNextInstruction(1); - SetBranchImm( branchTo ); - return; - } - - recSetBranchL(1); - - SaveBranchState(); - - recompileNextInstruction(1); - - SetBranchImm(branchTo); - - x86SetJ32( j32Ptr[ 0 ] ); - - // recopy the next inst - pc -= 4; - LoadBranchState(); - recompileNextInstruction(1); - - SetBranchImm(pc); -} - -//////////////////////////////////////////////////// -void recBGEZAL( void ) -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - - _eeOnWriteReg(31, 0); - _eeFlushAllUnused(); - - _deleteEEreg(31, 0); - MOV32ItoM((uptr)&cpuRegs.GPR.r[31].UL[0], pc+4); - MOV32ItoM((uptr)&cpuRegs.GPR.r[31].UL[1], 0); - - if( GPR_IS_CONST1(_Rs_) ) { - if( !(g_cpuConstRegs[_Rs_].SD[0] >= 0) ) - branchTo = pc+4; - - recompileNextInstruction(1); - SetBranchImm( branchTo ); - return; - } - - recSetBranchL(0); - - SaveBranchState(); - - recompileNextInstruction(1); - - SetBranchImm(branchTo); - - x86SetJ32( j32Ptr[ 0 ] ); - - // recopy the next inst - pc -= 4; - LoadBranchState(); - recompileNextInstruction(1); - - SetBranchImm(pc); -} - -//////////////////////////////////////////////////// -void recBLTZALL( void ) -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - - _eeOnWriteReg(31, 0); - _eeFlushAllUnused(); - - _deleteEEreg(31, 0); - MOV32ItoM((uptr)&cpuRegs.GPR.r[31].UL[0], pc+4); - MOV32ItoM((uptr)&cpuRegs.GPR.r[31].UL[1], 0); - - if( GPR_IS_CONST1(_Rs_) ) { - if( !(g_cpuConstRegs[_Rs_].SD[0] < 0) ) - SetBranchImm( pc + 4); - else { - recompileNextInstruction(1); - SetBranchImm( branchTo ); - } - return; - } - - recSetBranchL(1); - - SaveBranchState(); - recompileNextInstruction(1); - SetBranchImm(branchTo); - - x86SetJ32( j32Ptr[ 0 ] ); - - LoadBranchState(); - SetBranchImm(pc); -} - -//////////////////////////////////////////////////// -void recBGEZALL( void ) -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - - _eeOnWriteReg(31, 0); - _eeFlushAllUnused(); - - _deleteEEreg(31, 0); - MOV32ItoM((uptr)&cpuRegs.GPR.r[31].UL[0], pc+4); - MOV32ItoM((uptr)&cpuRegs.GPR.r[31].UL[1], 0); - - if( GPR_IS_CONST1(_Rs_) ) { - if( !(g_cpuConstRegs[_Rs_].SD[0] >= 0) ) - SetBranchImm( pc + 4); - else { - recompileNextInstruction(1); - SetBranchImm( branchTo ); - } - return; - } - - recSetBranchL(0); - - SaveBranchState(); - recompileNextInstruction(1); - SetBranchImm(branchTo); - - x86SetJ32( j32Ptr[ 0 ] ); - - LoadBranchState(); - SetBranchImm(pc); -} - -#else - - -//////////////////////////////////////////////////// -void recBEQ( void ) -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - - if ( _Rs_ == _Rt_ ) - { - _clearNeededMMXregs(); - _clearNeededXMMregs(); - recompileNextInstruction(1); - SetBranchImm( branchTo ); - } - else - { - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - j32Ptr[ 0 ] = JNE32( 0 ); - - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); - CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - j32Ptr[ 1 ] = JNE32( 0 ); - - _clearNeededMMXregs(); - _clearNeededXMMregs(); - - SaveBranchState(); - recompileNextInstruction(1); - - SetBranchImm(branchTo); - - x86SetJ32( j32Ptr[ 0 ] ); - x86SetJ32( j32Ptr[ 1 ] ); - - // recopy the next inst - pc -= 4; - LoadBranchState(); - recompileNextInstruction(1); - - SetBranchImm(pc); - } -} - -//////////////////////////////////////////////////// -void recBNE( void ) -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - - if ( _Rs_ == _Rt_ ) - { - _clearNeededMMXregs(); - _clearNeededXMMregs(); - recompileNextInstruction(1); - SetBranchImm(pc); - return; - } - - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - j32Ptr[ 0 ] = JNE32( 0 ); - - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); - CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - j32Ptr[ 1 ] = JE32( 0 ); - - x86SetJ32( j32Ptr[ 0 ] ); - - _clearNeededMMXregs(); - _clearNeededXMMregs(); - - SaveBranchState(); - recompileNextInstruction(1); - - SetBranchImm(branchTo); - - x86SetJ32( j32Ptr[ 1 ] ); - - // recopy the next inst - pc -= 4; - LoadBranchState(); - recompileNextInstruction(1); - - SetBranchImm(pc); -} - -//////////////////////////////////////////////////// -void recBEQL( void ) -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - CMP32RtoR( ECX, EDX ); - j32Ptr[ 0 ] = JNE32( 0 ); - - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - CMP32RtoR( ECX, EDX ); - j32Ptr[ 1 ] = JNE32( 0 ); - - _clearNeededMMXregs(); - _clearNeededXMMregs(); - - SaveBranchState(); - recompileNextInstruction(1); - SetBranchImm(branchTo); - - x86SetJ32( j32Ptr[ 0 ] ); - x86SetJ32( j32Ptr[ 1 ] ); - - LoadBranchState(); - SetBranchImm(pc); -} - -//////////////////////////////////////////////////// -void recBNEL( void ) -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - CMP32RtoR( ECX, EDX ); - j32Ptr[ 0 ] = JNE32( 0 ); - - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - CMP32RtoR( ECX, EDX ); - j32Ptr[ 1 ] = JNE32( 0 ); - - _clearNeededMMXregs(); - _clearNeededXMMregs(); - - SaveBranchState(); - SetBranchImm(pc+4); - - x86SetJ32( j32Ptr[ 0 ] ); - x86SetJ32( j32Ptr[ 1 ] ); - - // recopy the next inst - LoadBranchState(); - recompileNextInstruction(1); - SetBranchImm(branchTo); -} - -/********************************************************* -* Register branch logic * -* Format: OP rs, offset * -*********************************************************/ - -//////////////////////////////////////////////////// -void recBLTZAL( void ) -{ - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - iFlushCall(FLUSH_EVERYTHING); - CALLFunc( (int)BLTZAL ); - branch = 2; -} - -//////////////////////////////////////////////////// -void recBGEZAL( void ) -{ - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - iFlushCall(FLUSH_EVERYTHING); - CALLFunc( (int)BGEZAL ); - branch = 2; -} - -//////////////////////////////////////////////////// -void recBLTZALL( void ) -{ - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - iFlushCall(FLUSH_EVERYTHING); - CALLFunc( (int)BLTZALL ); - branch = 2; -} - -//////////////////////////////////////////////////// -void recBGEZALL( void ) -{ - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - iFlushCall(FLUSH_EVERYTHING); - CALLFunc( (int)BGEZALL ); - branch = 2; -} - -#endif - -//// BLEZ -void recBLEZ( void ) -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - - _eeFlushAllUnused(); - - if( GPR_IS_CONST1(_Rs_) ) { - if( !(g_cpuConstRegs[_Rs_].SD[0] <= 0) ) - branchTo = pc+4; - - recompileNextInstruction(1); - SetBranchImm( branchTo ); - return; - } - - _deleteEEreg(_Rs_, 1); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0 ); - j8Ptr[ 0 ] = JL8( 0 ); - j32Ptr[ 1 ] = JG32( 0 ); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0 ); - j32Ptr[ 2 ] = JNZ32( 0 ); - - x86SetJ8( j8Ptr[ 0 ] ); - - _clearNeededMMXregs(); - _clearNeededXMMregs(); - - SaveBranchState(); - recompileNextInstruction(1); - - SetBranchImm(branchTo); - - x86SetJ32( j32Ptr[ 1 ] ); - x86SetJ32( j32Ptr[ 2 ] ); - - // recopy the next inst - pc -= 4; - LoadBranchState(); - recompileNextInstruction(1); - - SetBranchImm(pc); -} - -//// BGTZ -void recBGTZ( void ) -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - - _eeFlushAllUnused(); - - if( GPR_IS_CONST1(_Rs_) ) { - if( !(g_cpuConstRegs[_Rs_].SD[0] > 0) ) - branchTo = pc+4; - - recompileNextInstruction(1); - SetBranchImm( branchTo ); - return; - } - - _deleteEEreg(_Rs_, 1); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0 ); - j8Ptr[ 0 ] = JG8( 0 ); - j32Ptr[ 1 ] = JL32( 0 ); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0 ); - j32Ptr[ 2 ] = JZ32( 0 ); - - x86SetJ8( j8Ptr[ 0 ] ); - - _clearNeededMMXregs(); - _clearNeededXMMregs(); - - SaveBranchState(); - recompileNextInstruction(1); - - SetBranchImm(branchTo); - - x86SetJ32( j32Ptr[ 1 ] ); - x86SetJ32( j32Ptr[ 2 ] ); - - // recopy the next inst - pc -= 4; - LoadBranchState(); - recompileNextInstruction(1); - - SetBranchImm(pc); -} - -//////////////////////////////////////////////////// -#ifdef EE_CONST_PROP -void recBLTZ() -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - - _eeFlushAllUnused(); - - if( GPR_IS_CONST1(_Rs_) ) { - if( !(g_cpuConstRegs[_Rs_].SD[0] < 0) ) - branchTo = pc+4; - - recompileNextInstruction(1); - SetBranchImm( branchTo ); - return; - } - - recSetBranchL(1); - - SaveBranchState(); - recompileNextInstruction(1); - - SetBranchImm(branchTo); - - x86SetJ32( j32Ptr[ 0 ] ); - - // recopy the next inst - pc -= 4; - LoadBranchState(); - recompileNextInstruction(1); - - SetBranchImm(pc); -} - -//////////////////////////////////////////////////// -void recBGEZ( void ) -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - - _eeFlushAllUnused(); - - if( GPR_IS_CONST1(_Rs_) ) { - if( !(g_cpuConstRegs[_Rs_].SD[0] >= 0) ) - branchTo = pc+4; - - recompileNextInstruction(1); - SetBranchImm( branchTo ); - return; - } - - recSetBranchL(0); - - SaveBranchState(); - recompileNextInstruction(1); - - SetBranchImm(branchTo); - - x86SetJ32( j32Ptr[ 0 ] ); - - // recopy the next inst - pc -= 4; - LoadBranchState(); - recompileNextInstruction(1); - - SetBranchImm(pc); -} - -//////////////////////////////////////////////////// -void recBLTZL( void ) -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - - _eeFlushAllUnused(); - - if( GPR_IS_CONST1(_Rs_) ) { - if( !(g_cpuConstRegs[_Rs_].SD[0] < 0) ) - SetBranchImm( pc + 4); - else { - recompileNextInstruction(1); - SetBranchImm( branchTo ); - } - return; - } - - recSetBranchL(1); - - SaveBranchState(); - recompileNextInstruction(1); - SetBranchImm(branchTo); - - x86SetJ32( j32Ptr[ 0 ] ); - - LoadBranchState(); - SetBranchImm(pc); -} - - -//////////////////////////////////////////////////// -void recBGEZL( void ) -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - - _eeFlushAllUnused(); - - if( GPR_IS_CONST1(_Rs_) ) { - if( !(g_cpuConstRegs[_Rs_].SD[0] >= 0) ) - SetBranchImm( pc + 4); - else { - recompileNextInstruction(1); - SetBranchImm( branchTo ); - } - return; - } - - recSetBranchL(0); - - SaveBranchState(); - recompileNextInstruction(1); - SetBranchImm(branchTo); - - x86SetJ32( j32Ptr[ 0 ] ); - - LoadBranchState(); - SetBranchImm(pc); -} - -#else -void recBLTZ( void ) -{ - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - iFlushCall(FLUSH_EVERYTHING); - CALLFunc( (int)BLTZ ); - branch = 2; -} - -void recBGEZ( void ) -{ - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - iFlushCall(FLUSH_EVERYTHING); - CALLFunc( (int)BGEZ ); - branch = 2; -} - -void recBLTZL( void ) -{ - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - iFlushCall(FLUSH_EVERYTHING); - CALLFunc( (int)BLTZL ); - branch = 2; -} - -void recBGEZL( void ) -{ - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - iFlushCall(FLUSH_EVERYTHING); - CALLFunc( (int)BGEZL ); - branch = 2; -} - -#endif - - - -/********************************************************* -* Register branch logic Likely * -* Format: OP rs, offset * -*********************************************************/ - -//////////////////////////////////////////////////// -void recBLEZL( void ) -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - - _eeFlushAllUnused(); - - if( GPR_IS_CONST1(_Rs_) ) { - if( !(g_cpuConstRegs[_Rs_].SD[0] <= 0) ) - SetBranchImm( pc + 4); - else { - _clearNeededMMXregs(); - _clearNeededXMMregs(); - recompileNextInstruction(1); - SetBranchImm( branchTo ); - } - return; - } - - _deleteEEreg(_Rs_, 1); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0 ); - j32Ptr[ 0 ] = JL32( 0 ); - j32Ptr[ 1 ] = JG32( 0 ); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0 ); - j32Ptr[ 2 ] = JNZ32( 0 ); - - x86SetJ32( j32Ptr[ 0 ] ); - - _clearNeededMMXregs(); - _clearNeededXMMregs(); - - SaveBranchState(); - recompileNextInstruction(1); - SetBranchImm(branchTo); - - x86SetJ32( j32Ptr[ 1 ] ); - x86SetJ32( j32Ptr[ 2 ] ); - - LoadBranchState(); - SetBranchImm(pc); -} - -//////////////////////////////////////////////////// -void recBGTZL( void ) -{ - u32 branchTo = ((s32)_Imm_ * 4) + pc; - - _eeFlushAllUnused(); - - if( GPR_IS_CONST1(_Rs_) ) { - if( !(g_cpuConstRegs[_Rs_].SD[0] > 0) ) - SetBranchImm( pc + 4); - else { - _clearNeededMMXregs(); - _clearNeededXMMregs(); - recompileNextInstruction(1); - SetBranchImm( branchTo ); - } - return; - } - - _deleteEEreg(_Rs_, 1); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0 ); - j32Ptr[ 0 ] = JG32( 0 ); - j32Ptr[ 1 ] = JL32( 0 ); - - CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0 ); - j32Ptr[ 2 ] = JZ32( 0 ); - - x86SetJ32( j32Ptr[ 0 ] ); - - _clearNeededMMXregs(); - _clearNeededXMMregs(); - - SaveBranchState(); - recompileNextInstruction(1); - SetBranchImm(branchTo); - - x86SetJ32( j32Ptr[ 1 ] ); - x86SetJ32( j32Ptr[ 2 ] ); - - LoadBranchState(); - SetBranchImm(pc); -} - -#endif - -} } } +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +// recompiler reworked to add dynamic linking zerofrog(@gmail.com) Jan06 + +#include "PrecompiledHeader.h" + +#include "Common.h" +#include "R5900OpcodeTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + +namespace Interp = R5900::Interpreter::OpcodeImpl; + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl +{ + +/********************************************************* +* Register branch logic * +* Format: OP rs, rt, offset * +*********************************************************/ +#ifndef BRANCH_RECOMPILE + +REC_SYS(BEQ); +REC_SYS(BEQL); +REC_SYS(BNE); +REC_SYS(BNEL); +REC_SYS(BLTZ); +REC_SYS(BGTZ); +REC_SYS(BLEZ); +REC_SYS(BGEZ); +REC_SYS(BGTZL); +REC_SYS(BLTZL); +REC_SYS(BLTZAL); +REC_SYS(BLTZALL); +REC_SYS(BLEZL); +REC_SYS(BGEZL); +REC_SYS(BGEZAL); +REC_SYS(BGEZALL); + +#else + +#if defined(EE_CONST_PROP) + +void recSetBranchEQ(int info, int bne, int process) +{ + if( info & PROCESS_EE_MMX ) { + int t0reg; + + SetMMXstate(); + + if( process & PROCESS_CONSTS ) { + if( (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rt_) ) { + _deleteMMXreg(_Rt_, 1); + mmxregs[EEREC_T].inuse = 0; + t0reg = EEREC_T; + } + else { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, EEREC_T); + } + + _flushConstReg(_Rs_); + PCMPEQDMtoR(t0reg, (u32)&cpuRegs.GPR.r[_Rs_].UL[0]); + + if( t0reg != EEREC_T ) _freeMMXreg(t0reg); + } + else if( process & PROCESS_CONSTT ) { + if( (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rs_) ) { + _deleteMMXreg(_Rs_, 1); + mmxregs[EEREC_S].inuse = 0; + t0reg = EEREC_S; + } + else { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, EEREC_S); + } + + _flushConstReg(_Rt_); + PCMPEQDMtoR(t0reg, (u32)&cpuRegs.GPR.r[_Rt_].UL[0]); + + if( t0reg != EEREC_S ) _freeMMXreg(t0reg); + } + else { + + if( (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rs_) ) { + _deleteMMXreg(_Rs_, 1); + mmxregs[EEREC_S].inuse = 0; + t0reg = EEREC_S; + PCMPEQDRtoR(t0reg, EEREC_T); + } + else if( (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rt_) ) { + _deleteMMXreg(_Rt_, 1); + mmxregs[EEREC_T].inuse = 0; + t0reg = EEREC_T; + PCMPEQDRtoR(t0reg, EEREC_S); + } + else { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, EEREC_S); + PCMPEQDRtoR(t0reg, EEREC_T); + } + + if( t0reg != EEREC_S && t0reg != EEREC_T ) _freeMMXreg(t0reg); + } + + PMOVMSKBMMXtoR(EAX, t0reg); + + _eeFlushAllUnused(); + + CMP8ItoR( EAX, 0xff ); + + if( bne ) j32Ptr[ 1 ] = JE32( 0 ); + else j32Ptr[ 0 ] = j32Ptr[ 1 ] = JNE32( 0 ); + } + else if( info & PROCESS_EE_XMM ) { + int t0reg; + + if( process & PROCESS_CONSTS ) { + if( (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rt_) ) { + _deleteGPRtoXMMreg(_Rt_, 1); + xmmregs[EEREC_T].inuse = 0; + t0reg = EEREC_T; + } + else { + t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_MOVQ_XMM_to_XMM(t0reg, EEREC_T); + } + + _flushConstReg(_Rs_); + SSE2_PCMPEQD_M128_to_XMM(t0reg, (u32)&cpuRegs.GPR.r[_Rs_].UL[0]); + + + if( t0reg != EEREC_T ) _freeXMMreg(t0reg); + } + else if( process & PROCESS_CONSTT ) { + if( (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rs_) ) { + _deleteGPRtoXMMreg(_Rs_, 1); + xmmregs[EEREC_S].inuse = 0; + t0reg = EEREC_S; + } + else { + t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_MOVQ_XMM_to_XMM(t0reg, EEREC_S); + } + + _flushConstReg(_Rt_); + SSE2_PCMPEQD_M128_to_XMM(t0reg, (u32)&cpuRegs.GPR.r[_Rt_].UL[0]); + + if( t0reg != EEREC_S ) _freeXMMreg(t0reg); + } + else { + + if( (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rs_) ) { + _deleteGPRtoXMMreg(_Rs_, 1); + xmmregs[EEREC_S].inuse = 0; + t0reg = EEREC_S; + SSE2_PCMPEQD_XMM_to_XMM(t0reg, EEREC_T); + } + else if( (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rt_) ) { + _deleteGPRtoXMMreg(_Rt_, 1); + xmmregs[EEREC_T].inuse = 0; + t0reg = EEREC_T; + SSE2_PCMPEQD_XMM_to_XMM(t0reg, EEREC_S); + } + else { + t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE2_MOVQ_XMM_to_XMM(t0reg, EEREC_S); + SSE2_PCMPEQD_XMM_to_XMM(t0reg, EEREC_T); + } + + if( t0reg != EEREC_S && t0reg != EEREC_T ) _freeXMMreg(t0reg); + } + + SSE_MOVMSKPS_XMM_to_R32(EAX, t0reg); + + _eeFlushAllUnused(); + + AND8ItoR(EAX, 3); + CMP8ItoR( EAX, 0x3 ); + + if( bne ) j32Ptr[ 1 ] = JE32( 0 ); + else j32Ptr[ 0 ] = j32Ptr[ 1 ] = JNE32( 0 ); + } + else { + + _eeFlushAllUnused(); + + if( bne ) { + if( process & PROCESS_CONSTS ) { + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0] ); + j8Ptr[ 0 ] = JNE8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1] ); + j32Ptr[ 1 ] = JE32( 0 ); + } + else if( process & PROCESS_CONSTT ) { + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0] ); + j8Ptr[ 0 ] = JNE8( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1] ); + j32Ptr[ 1 ] = JE32( 0 ); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + CMP32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + j8Ptr[ 0 ] = JNE8( 0 ); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + CMP32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j32Ptr[ 1 ] = JE32( 0 ); + } + + x86SetJ8( j8Ptr[0] ); + } + else { + // beq + if( process & PROCESS_CONSTS ) { + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0] ); + j32Ptr[ 0 ] = JNE32( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1] ); + j32Ptr[ 1 ] = JNE32( 0 ); + } + else if( process & PROCESS_CONSTT ) { + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0] ); + j32Ptr[ 0 ] = JNE32( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1] ); + j32Ptr[ 1 ] = JNE32( 0 ); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + CMP32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + j32Ptr[ 0 ] = JNE32( 0 ); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + CMP32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j32Ptr[ 1 ] = JNE32( 0 ); + } + } + } + + _clearNeededMMXregs(); + _clearNeededXMMregs(); +} + +void recSetBranchL(int ltz) +{ + int regs = _checkMMXreg(MMX_GPR+_Rs_, MODE_READ); + + if( regs >= 0 ) { + + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + SetMMXstate(); + + PXORRtoR(t0reg, t0reg); + PCMPGTDRtoR(t0reg, regs); + PMOVMSKBMMXtoR(EAX, t0reg); + + _freeMMXreg(t0reg); + _eeFlushAllUnused(); + + TEST8ItoR( EAX, 0x80 ); + + if( ltz ) j32Ptr[ 0 ] = JZ32( 0 ); + else j32Ptr[ 0 ] = JNZ32( 0 ); + + return; + } + + regs = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ); + + if( regs >= 0 ) { + + int t0reg = _allocTempXMMreg(XMMT_INT, -1); + SSE_XORPS_XMM_to_XMM(t0reg, t0reg); + SSE2_PCMPGTD_XMM_to_XMM(t0reg, regs); + SSE_MOVMSKPS_XMM_to_R32(EAX, t0reg); + + _freeXMMreg(t0reg); + _eeFlushAllUnused(); + + TEST8ItoR( EAX, 2 ); + + if( ltz ) j32Ptr[ 0 ] = JZ32( 0 ); + else j32Ptr[ 0 ] = JNZ32( 0 ); + + return; + } + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0 ); + if( ltz ) j32Ptr[ 0 ] = JGE32( 0 ); + else j32Ptr[ 0 ] = JL32( 0 ); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); +} + +//// BEQ +void recBEQ_const() +{ + u32 branchTo; + + if( g_cpuConstRegs[_Rs_].SD[0] == g_cpuConstRegs[_Rt_].SD[0] ) + branchTo = ((s32)_Imm_ * 4) + pc; + else + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); +} + +void recBEQ_process(int info, int process) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + if ( _Rs_ == _Rt_ ) + { + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + else + { + recSetBranchEQ(info, 0, process); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + x86SetJ32( j32Ptr[ 1 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); + } +} + +void recBEQ_(int info) { recBEQ_process(info, 0); } +void recBEQ_consts(int info) { recBEQ_process(info, PROCESS_CONSTS); } +void recBEQ_constt(int info) { recBEQ_process(info, PROCESS_CONSTT); } + +EERECOMPILE_CODE0(BEQ, XMMINFO_READS|XMMINFO_READT); + +//// BNE +void recBNE_const() +{ + u32 branchTo; + + if( g_cpuConstRegs[_Rs_].SD[0] != g_cpuConstRegs[_Rt_].SD[0] ) + branchTo = ((s32)_Imm_ * 4) + pc; + else + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); +} + +void recBNE_process(int info, int process) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + if ( _Rs_ == _Rt_ ) + { + recompileNextInstruction(1); + SetBranchImm(pc); + return; + } + + recSetBranchEQ(info, 1, process); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 1 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +void recBNE_(int info) { recBNE_process(info, 0); } +void recBNE_consts(int info) { recBNE_process(info, PROCESS_CONSTS); } +void recBNE_constt(int info) { recBNE_process(info, PROCESS_CONSTT); } + +EERECOMPILE_CODE0(BNE, XMMINFO_READS|XMMINFO_READT); + +//// BEQL +void recBEQL_const() +{ + if( g_cpuConstRegs[_Rs_].SD[0] == g_cpuConstRegs[_Rt_].SD[0] ) { + u32 branchTo = ((s32)_Imm_ * 4) + pc; + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + else { + SetBranchImm( pc+4 ); + } +} + +void recBEQL_process(int info, int process) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + recSetBranchEQ(info, 0, process); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + x86SetJ32( j32Ptr[ 1 ] ); + + LoadBranchState(); + SetBranchImm(pc); +} + +void recBEQL_(int info) { recBEQL_process(info, 0); } +void recBEQL_consts(int info) { recBEQL_process(info, PROCESS_CONSTS); } +void recBEQL_constt(int info) { recBEQL_process(info, PROCESS_CONSTT); } + +EERECOMPILE_CODE0(BEQL, XMMINFO_READS|XMMINFO_READT); + +//// BNEL +void recBNEL_const() +{ + if( g_cpuConstRegs[_Rs_].SD[0] != g_cpuConstRegs[_Rt_].SD[0] ) { + u32 branchTo = ((s32)_Imm_ * 4) + pc; + recompileNextInstruction(1); + SetBranchImm(branchTo); + } + else { + SetBranchImm( pc+4 ); + } +} + +void recBNEL_process(int info, int process) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + recSetBranchEQ(info, 0, process); + + SaveBranchState(); + SetBranchImm(pc+4); + + x86SetJ32( j32Ptr[ 0 ] ); + x86SetJ32( j32Ptr[ 1 ] ); + + // recopy the next inst + LoadBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); +} + +void recBNEL_(int info) { recBNEL_process(info, 0); } +void recBNEL_consts(int info) { recBNEL_process(info, PROCESS_CONSTS); } +void recBNEL_constt(int info) { recBNEL_process(info, PROCESS_CONSTT); } + +EERECOMPILE_CODE0(BNEL, XMMINFO_READS|XMMINFO_READT); + +/********************************************************* +* Register branch logic * +* Format: OP rs, offset * +*********************************************************/ + +//////////////////////////////////////////////////// +//void recBLTZAL( void ) +//{ +// SysPrintf("BLTZAL\n"); +// _eeFlushAllUnused(); +// MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); +// MOV32ItoM( (int)&cpuRegs.pc, pc ); +// iFlushCall(FLUSH_EVERYTHING); +// CALLFunc( (int)BLTZAL ); +// branch = 2; +//} + +//////////////////////////////////////////////////// +void recBLTZAL() +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeOnWriteReg(31, 0); + _eeFlushAllUnused(); + + _deleteEEreg(31, 0); + MOV32ItoM((uptr)&cpuRegs.GPR.r[31].UL[0], pc+4); + MOV32ItoM((uptr)&cpuRegs.GPR.r[31].UL[1], 0); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] < 0) ) + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); + return; + } + + recSetBranchL(1); + + SaveBranchState(); + + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBGEZAL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeOnWriteReg(31, 0); + _eeFlushAllUnused(); + + _deleteEEreg(31, 0); + MOV32ItoM((uptr)&cpuRegs.GPR.r[31].UL[0], pc+4); + MOV32ItoM((uptr)&cpuRegs.GPR.r[31].UL[1], 0); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] >= 0) ) + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); + return; + } + + recSetBranchL(0); + + SaveBranchState(); + + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBLTZALL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeOnWriteReg(31, 0); + _eeFlushAllUnused(); + + _deleteEEreg(31, 0); + MOV32ItoM((uptr)&cpuRegs.GPR.r[31].UL[0], pc+4); + MOV32ItoM((uptr)&cpuRegs.GPR.r[31].UL[1], 0); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] < 0) ) + SetBranchImm( pc + 4); + else { + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + return; + } + + recSetBranchL(1); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + LoadBranchState(); + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBGEZALL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeOnWriteReg(31, 0); + _eeFlushAllUnused(); + + _deleteEEreg(31, 0); + MOV32ItoM((uptr)&cpuRegs.GPR.r[31].UL[0], pc+4); + MOV32ItoM((uptr)&cpuRegs.GPR.r[31].UL[1], 0); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] >= 0) ) + SetBranchImm( pc + 4); + else { + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + return; + } + + recSetBranchL(0); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + LoadBranchState(); + SetBranchImm(pc); +} + +#else + + +//////////////////////////////////////////////////// +void recBEQ( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + if ( _Rs_ == _Rt_ ) + { + _clearNeededMMXregs(); + _clearNeededXMMregs(); + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + else + { + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + j32Ptr[ 0 ] = JNE32( 0 ); + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j32Ptr[ 1 ] = JNE32( 0 ); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + x86SetJ32( j32Ptr[ 1 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); + } +} + +//////////////////////////////////////////////////// +void recBNE( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + if ( _Rs_ == _Rt_ ) + { + _clearNeededMMXregs(); + _clearNeededXMMregs(); + recompileNextInstruction(1); + SetBranchImm(pc); + return; + } + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + j32Ptr[ 0 ] = JNE32( 0 ); + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j32Ptr[ 1 ] = JE32( 0 ); + + x86SetJ32( j32Ptr[ 0 ] ); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 1 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBEQL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + CMP32RtoR( ECX, EDX ); + j32Ptr[ 0 ] = JNE32( 0 ); + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + CMP32RtoR( ECX, EDX ); + j32Ptr[ 1 ] = JNE32( 0 ); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + x86SetJ32( j32Ptr[ 1 ] ); + + LoadBranchState(); + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBNEL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + CMP32RtoR( ECX, EDX ); + j32Ptr[ 0 ] = JNE32( 0 ); + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + CMP32RtoR( ECX, EDX ); + j32Ptr[ 1 ] = JNE32( 0 ); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + + SaveBranchState(); + SetBranchImm(pc+4); + + x86SetJ32( j32Ptr[ 0 ] ); + x86SetJ32( j32Ptr[ 1 ] ); + + // recopy the next inst + LoadBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); +} + +/********************************************************* +* Register branch logic * +* Format: OP rs, offset * +*********************************************************/ + +//////////////////////////////////////////////////// +void recBLTZAL( void ) +{ + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (int)BLTZAL ); + branch = 2; +} + +//////////////////////////////////////////////////// +void recBGEZAL( void ) +{ + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (int)BGEZAL ); + branch = 2; +} + +//////////////////////////////////////////////////// +void recBLTZALL( void ) +{ + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (int)BLTZALL ); + branch = 2; +} + +//////////////////////////////////////////////////// +void recBGEZALL( void ) +{ + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (int)BGEZALL ); + branch = 2; +} + +#endif + +//// BLEZ +void recBLEZ( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] <= 0) ) + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); + return; + } + + _deleteEEreg(_Rs_, 1); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0 ); + j8Ptr[ 0 ] = JL8( 0 ); + j32Ptr[ 1 ] = JG32( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0 ); + j32Ptr[ 2 ] = JNZ32( 0 ); + + x86SetJ8( j8Ptr[ 0 ] ); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 1 ] ); + x86SetJ32( j32Ptr[ 2 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +//// BGTZ +void recBGTZ( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] > 0) ) + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); + return; + } + + _deleteEEreg(_Rs_, 1); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0 ); + j8Ptr[ 0 ] = JG8( 0 ); + j32Ptr[ 1 ] = JL32( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0 ); + j32Ptr[ 2 ] = JZ32( 0 ); + + x86SetJ8( j8Ptr[ 0 ] ); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 1 ] ); + x86SetJ32( j32Ptr[ 2 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +#ifdef EE_CONST_PROP +void recBLTZ() +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] < 0) ) + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); + return; + } + + recSetBranchL(1); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBGEZ( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] >= 0) ) + branchTo = pc+4; + + recompileNextInstruction(1); + SetBranchImm( branchTo ); + return; + } + + recSetBranchL(0); + + SaveBranchState(); + recompileNextInstruction(1); + + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + // recopy the next inst + pc -= 4; + LoadBranchState(); + recompileNextInstruction(1); + + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBLTZL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] < 0) ) + SetBranchImm( pc + 4); + else { + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + return; + } + + recSetBranchL(1); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + LoadBranchState(); + SetBranchImm(pc); +} + + +//////////////////////////////////////////////////// +void recBGEZL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] >= 0) ) + SetBranchImm( pc + 4); + else { + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + return; + } + + recSetBranchL(0); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 0 ] ); + + LoadBranchState(); + SetBranchImm(pc); +} + +#else +void recBLTZ( void ) +{ + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (int)BLTZ ); + branch = 2; +} + +void recBGEZ( void ) +{ + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (int)BGEZ ); + branch = 2; +} + +void recBLTZL( void ) +{ + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (int)BLTZL ); + branch = 2; +} + +void recBGEZL( void ) +{ + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + iFlushCall(FLUSH_EVERYTHING); + CALLFunc( (int)BGEZL ); + branch = 2; +} + +#endif + + + +/********************************************************* +* Register branch logic Likely * +* Format: OP rs, offset * +*********************************************************/ + +//////////////////////////////////////////////////// +void recBLEZL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] <= 0) ) + SetBranchImm( pc + 4); + else { + _clearNeededMMXregs(); + _clearNeededXMMregs(); + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + return; + } + + _deleteEEreg(_Rs_, 1); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0 ); + j32Ptr[ 0 ] = JL32( 0 ); + j32Ptr[ 1 ] = JG32( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0 ); + j32Ptr[ 2 ] = JNZ32( 0 ); + + x86SetJ32( j32Ptr[ 0 ] ); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 1 ] ); + x86SetJ32( j32Ptr[ 2 ] ); + + LoadBranchState(); + SetBranchImm(pc); +} + +//////////////////////////////////////////////////// +void recBGTZL( void ) +{ + u32 branchTo = ((s32)_Imm_ * 4) + pc; + + _eeFlushAllUnused(); + + if( GPR_IS_CONST1(_Rs_) ) { + if( !(g_cpuConstRegs[_Rs_].SD[0] > 0) ) + SetBranchImm( pc + 4); + else { + _clearNeededMMXregs(); + _clearNeededXMMregs(); + recompileNextInstruction(1); + SetBranchImm( branchTo ); + } + return; + } + + _deleteEEreg(_Rs_, 1); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0 ); + j32Ptr[ 0 ] = JG32( 0 ); + j32Ptr[ 1 ] = JL32( 0 ); + + CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0 ); + j32Ptr[ 2 ] = JZ32( 0 ); + + x86SetJ32( j32Ptr[ 0 ] ); + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + + SaveBranchState(); + recompileNextInstruction(1); + SetBranchImm(branchTo); + + x86SetJ32( j32Ptr[ 1 ] ); + x86SetJ32( j32Ptr[ 2 ] ); + + LoadBranchState(); + SetBranchImm(pc); +} + +#endif + +} } } diff --git a/pcsx2/x86/ix86-32/iR5900Jump.cpp b/pcsx2/x86/ix86-32/iR5900Jump.cpp index b38211cef5..5e871c33c8 100644 --- a/pcsx2/x86/ix86-32/iR5900Jump.cpp +++ b/pcsx2/x86/ix86-32/iR5900Jump.cpp @@ -1,133 +1,133 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ - -// recompiler reworked to add dynamic linking zerofrog(@gmail.com) Jan06 - -#include "PrecompiledHeader.h" - -#include "Common.h" -#include "R5900OpcodeTables.h" -#include "ix86/ix86.h" -#include "iR5900.h" - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl -{ - -/********************************************************* -* Jump to target * -* Format: OP target * -*********************************************************/ -#ifndef JUMP_RECOMPILE - -namespace Interp = R5900::Interpreter::OpcodeImpl; - -REC_SYS(J); -REC_SYS(JAL); -REC_SYS(JR); -REC_SYS(JALR); - -#else - -//////////////////////////////////////////////////// -void recJ( void ) -{ - // SET_FPUSTATE; - u32 newpc = (_Target_ << 2) + ( pc & 0xf0000000 ); - recompileNextInstruction(1); - SetBranchImm(newpc); -} - -//////////////////////////////////////////////////// -void recJAL( void ) -{ - u32 newpc = (_Target_ << 2) + ( pc & 0xf0000000 ); - _deleteEEreg(31, 0); - GPR_SET_CONST(31); - g_cpuConstRegs[31].UL[0] = pc + 4; - g_cpuConstRegs[31].UL[1] = 0; - - recompileNextInstruction(1); - SetBranchImm(newpc); -} - -/********************************************************* -* Register jump * -* Format: OP rs, rd * -*********************************************************/ - -//////////////////////////////////////////////////// -void recJR( void ) -{ - SetBranchReg( _Rs_); -} - -//////////////////////////////////////////////////// -void recJALR( void ) -{ - _allocX86reg(ESI, X86TYPE_PCWRITEBACK, 0, MODE_WRITE); - _eeMoveGPRtoR(ESI, _Rs_); - // uncomment when there are NO instructions that need to call interpreter -// int mmreg; -// if( GPR_IS_CONST1(_Rs_) ) -// MOV32ItoM( (u32)&cpuRegs.pc, g_cpuConstRegs[_Rs_].UL[0] ); -// else { -// int mmreg; -// -// if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ)) >= 0 ) { -// SSE_MOVSS_XMM_to_M32((u32)&cpuRegs.pc, mmreg); -// } -// else if( (mmreg = _checkMMXreg(MMX_GPR+_Rs_, MODE_READ)) >= 0 ) { -// MOVDMMXtoM((u32)&cpuRegs.pc, mmreg); -// SetMMXstate(); -// } -// else { -// MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); -// MOV32RtoM((u32)&cpuRegs.pc, EAX); -// } -// } - - if ( _Rd_ ) - { - _deleteEEreg(_Rd_, 0); - GPR_SET_CONST(_Rd_); - g_cpuConstRegs[_Rd_].UL[0] = pc + 4; - g_cpuConstRegs[_Rd_].UL[1] = 0; - } - - _clearNeededMMXregs(); - _clearNeededXMMregs(); - recompileNextInstruction(1); - - if( x86regs[ESI].inuse ) { - assert( x86regs[ESI].type == X86TYPE_PCWRITEBACK ); - MOV32RtoM((int)&cpuRegs.pc, ESI); - x86regs[ESI].inuse = 0; - } - else { - MOV32MtoR(EAX, (u32)&g_recWriteback); - MOV32RtoM((int)&cpuRegs.pc, EAX); - } - - SetBranchReg(0xffffffff); -} - -#endif - -} } } +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ + +// recompiler reworked to add dynamic linking zerofrog(@gmail.com) Jan06 + +#include "PrecompiledHeader.h" + +#include "Common.h" +#include "R5900OpcodeTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl +{ + +/********************************************************* +* Jump to target * +* Format: OP target * +*********************************************************/ +#ifndef JUMP_RECOMPILE + +namespace Interp = R5900::Interpreter::OpcodeImpl; + +REC_SYS(J); +REC_SYS(JAL); +REC_SYS(JR); +REC_SYS(JALR); + +#else + +//////////////////////////////////////////////////// +void recJ( void ) +{ + // SET_FPUSTATE; + u32 newpc = (_Target_ << 2) + ( pc & 0xf0000000 ); + recompileNextInstruction(1); + SetBranchImm(newpc); +} + +//////////////////////////////////////////////////// +void recJAL( void ) +{ + u32 newpc = (_Target_ << 2) + ( pc & 0xf0000000 ); + _deleteEEreg(31, 0); + GPR_SET_CONST(31); + g_cpuConstRegs[31].UL[0] = pc + 4; + g_cpuConstRegs[31].UL[1] = 0; + + recompileNextInstruction(1); + SetBranchImm(newpc); +} + +/********************************************************* +* Register jump * +* Format: OP rs, rd * +*********************************************************/ + +//////////////////////////////////////////////////// +void recJR( void ) +{ + SetBranchReg( _Rs_); +} + +//////////////////////////////////////////////////// +void recJALR( void ) +{ + _allocX86reg(ESI, X86TYPE_PCWRITEBACK, 0, MODE_WRITE); + _eeMoveGPRtoR(ESI, _Rs_); + // uncomment when there are NO instructions that need to call interpreter +// int mmreg; +// if( GPR_IS_CONST1(_Rs_) ) +// MOV32ItoM( (u32)&cpuRegs.pc, g_cpuConstRegs[_Rs_].UL[0] ); +// else { +// int mmreg; +// +// if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ)) >= 0 ) { +// SSE_MOVSS_XMM_to_M32((u32)&cpuRegs.pc, mmreg); +// } +// else if( (mmreg = _checkMMXreg(MMX_GPR+_Rs_, MODE_READ)) >= 0 ) { +// MOVDMMXtoM((u32)&cpuRegs.pc, mmreg); +// SetMMXstate(); +// } +// else { +// MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); +// MOV32RtoM((u32)&cpuRegs.pc, EAX); +// } +// } + + if ( _Rd_ ) + { + _deleteEEreg(_Rd_, 0); + GPR_SET_CONST(_Rd_); + g_cpuConstRegs[_Rd_].UL[0] = pc + 4; + g_cpuConstRegs[_Rd_].UL[1] = 0; + } + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + recompileNextInstruction(1); + + if( x86regs[ESI].inuse ) { + assert( x86regs[ESI].type == X86TYPE_PCWRITEBACK ); + MOV32RtoM((int)&cpuRegs.pc, ESI); + x86regs[ESI].inuse = 0; + } + else { + MOV32MtoR(EAX, (u32)&g_recWriteback); + MOV32RtoM((int)&cpuRegs.pc, EAX); + } + + SetBranchReg(0xffffffff); +} + +#endif + +} } } diff --git a/pcsx2/x86/ix86-32/iR5900LoadStore.cpp b/pcsx2/x86/ix86-32/iR5900LoadStore.cpp index 562947c5a4..ffb5cc92fe 100644 --- a/pcsx2/x86/ix86-32/iR5900LoadStore.cpp +++ b/pcsx2/x86/ix86-32/iR5900LoadStore.cpp @@ -1,2765 +1,2765 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "R5900OpcodeTables.h" -#include "iR5900LoadStore.h" -#include "ix86/ix86.h" -#include "iR5900.h" - -// Implemented at the bottom of the module: -void SetFastMemory(int bSetFast); - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl { - -/********************************************************* -* Load and store for GPR * -* Format: OP rt, offset(base) * -*********************************************************/ -#ifndef LOADSTORE_RECOMPILE - -namespace Interp = R5900::Interpreter::OpcodeImpl; - -REC_FUNC(LB); -REC_FUNC(LBU); -REC_FUNC(LH); -REC_FUNC(LHU); -REC_FUNC(LW); -REC_FUNC(LWU); -REC_FUNC(LWL); -REC_FUNC(LWR); -REC_FUNC(LD); -REC_FUNC(LDR); -REC_FUNC(LDL); -REC_FUNC(LQ); -REC_FUNC(SB); -REC_FUNC(SH); -REC_FUNC(SW); -REC_FUNC(SWL); -REC_FUNC(SWR); -REC_FUNC(SD); -REC_FUNC(SDL); -REC_FUNC(SDR); -REC_FUNC(SQ); -REC_FUNC(LWC1); -REC_FUNC(SWC1); -REC_FUNC(LQC2); -REC_FUNC(SQC2); - -#else - -PCSX2_ALIGNED16(u64 retValues[2]); -static u32 s_bCachingMem = 0; -static u32 s_nAddMemOffset = 0; -static u32 s_tempaddr = 0; - -void _eeOnLoadWrite(int reg) -{ - int regt; - - if( !reg ) return; - - _eeOnWriteReg(reg, 1); - regt = _checkXMMreg(XMMTYPE_GPRREG, reg, MODE_READ); - - if( regt >= 0 ) { - if( xmmregs[regt].mode & MODE_WRITE ) { - if( reg != _Rs_ ) { - SSE2_PUNPCKHQDQ_XMM_to_XMM(regt, regt); - SSE2_MOVQ_XMM_to_M64((u32)&cpuRegs.GPR.r[reg].UL[2], regt); - } - else SSE_MOVHPS_XMM_to_M64((u32)&cpuRegs.GPR.r[reg].UL[2], regt); - } - xmmregs[regt].inuse = 0; - } -} - -#ifdef PCSX2_VIRTUAL_MEM - -//////////////////////////////////////////////////// -//#define REC_SLOWREAD -//#define REC_SLOWWRITE -#define REC_FORCEMMX 0 - -// if sp, always mem write -int _eeIsMemWrite() { return _Rs_==29||_Rs_== 31||_Rs_==26||_Rs_==27; } // sp, ra, k0, k1 -// gp can be 1000a020 (jak1) - -void recTransferX86ToReg(int x86reg, int gprreg, int sign) -{ - //if( !REC_FORCEMMX ) assert( _checkMMXreg(MMX_GPR+gprreg, MODE_WRITE) == -1 ); - if( sign ) { - if( x86reg == EAX && EEINST_ISLIVE1(gprreg) ) CDQ(); - - MOV32RtoM( (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], x86reg ); - - if(EEINST_ISLIVE1(gprreg)) { - if( x86reg == EAX ) MOV32RtoM( (int)&cpuRegs.GPR.r[ gprreg ].UL[ 1 ], EDX ); - else { - SAR32ItoR(x86reg, 31); - MOV32RtoM( (int)&cpuRegs.GPR.r[ gprreg ].UL[ 1 ], x86reg ); - } - } - else { - EEINST_RESETHASLIVE1(gprreg); - } - } - else { - MOV32RtoM( (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], x86reg ); - if(EEINST_ISLIVE1(gprreg)) MOV32ItoM( (int)&cpuRegs.GPR.r[ gprreg ].UL[ 1 ], 0 ); - else EEINST_RESETHASLIVE1(gprreg); - } -} - -#ifdef _DEBUG -void testaddrs() -{ - register int tempaddr; - - __asm mov tempaddr, ecx - //__asm mov incaddr, edx - - assert( (tempaddr < 0x40000000) || (tempaddr&0xd0000000)==0x50000000 || (tempaddr >= 0x80000000 && tempaddr < 0xc0000000) ); - //assert( (tempaddr>>28) == ((tempaddr+incaddr)>>28) ); - - __asm mov ecx, tempaddr -} -#endif - -static __forceinline void SET_HWLOC_R5900() { - if ( s_bCachingMem & 2 ) - { - x86SetJ32(j32Ptr[2]); - x86SetJ32(j32Ptr[3]); - } - else - { - x86SetJ8(j8Ptr[0]); - x86SetJ8(j8Ptr[3]); - } - - if (x86FpuState==MMX_STATE) { - if (cpucaps.has3DNOWInstructionExtensions) - FEMMS(); - else - EMMS(); - } - if( s_nAddMemOffset ) - ADD32ItoR(ECX, s_nAddMemOffset); - if( s_bCachingMem & 4 ) - AND32ItoR(ECX, 0x5fffffff); -} - -static u16 g_MemMasks0[16] = {0x00f0, 0x80f1, 0x00f2, 0x00f3, - 0x00f1, 0x00f5, 0x00f1, 0x00f5, - 0x00f5, 0x80f5, 0x00f5, 0x80f5, - 0x00f1, 0x00f1, 0x00f1, 0x00f5 }; -static u16 g_MemMasks8[16] = {0x0080, 0x8081, 0x0082, 0x0083, - 0x0081, 0x0085, 0x0081, 0x0085, - 0x0085, 0x8085, 0x0085, 0x8085, - 0x0081, 0x0081, 0x0081, 0x0085 }; -static u16 g_MemMasks16[16] ={0x0000, 0x8001, 0x0002, 0x0003, - 0x0001, 0x0005, 0x0001, 0x0005, - 0x0005, 0x8005, 0x0005, 0x8005, - 0x0001, 0x0001, 0x0001, 0x0005 }; - -void assertmem() -{ - __asm mov s_tempaddr, ecx - __asm mov s_bCachingMem, edx - Console::Error("%x(%x) not mem write!", params s_tempaddr, s_bCachingMem); - assert(0); -} - -int _eePrepareReg(int gprreg) -{ - int mmreg = _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ); - - if( mmreg >= 0 && (xmmregs[mmreg].mode&MODE_WRITE) ) { - mmreg |= MEM_XMMTAG; - } - else if( (mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ)) >= 0 ) { - if( mmxregs[mmreg].mode&MODE_WRITE ) mmreg |= MEM_MMXTAG; - else { - mmxregs[mmreg].needed = 0; // coX can possibly use all regs - mmreg = 0; - } - } - else { - mmreg = 0; - } - - return mmreg; -} - -// returns true if should also include hardware writes -int recSetMemLocation(int regs, int imm, int mmreg, int msize, int j32) -{ - s_bCachingMem = j32 ? 2 : 0; - s_nAddMemOffset = 0; - - //int num; - if( mmreg >= 0 && (mmreg & MEM_XMMTAG) ) { - SSE2_MOVD_XMM_to_R(ECX, mmreg&0xf); - } - else if( mmreg >= 0 && (mmreg & MEM_MMXTAG) ) { - MOVD32MMXtoR(ECX, mmreg&0xf); - SetMMXstate(); - } - else { - MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ regs ].UL[ 0 ] ); - } - - if ( imm != 0 ) ADD32ItoR( ECX, imm ); - - LoadCW(); - -#ifdef _DEBUG - //CALLFunc((uptr)testaddrs); -#endif - - - // 32bit version (faster?) -// MOV32RtoR(EAX, ECX); -// ROR32ItoR(ECX, 28); -// SHR32ItoR(EAX, 28); -// MOV32RmSOffsettoR(EAX, EAX, msize == 2 ? (u32)&g_MemMasks16[0] : (msize == 1 ? (u32)&g_MemMasks8[0] : (u32)&g_MemMasks0[0]), 2); -// AND8RtoR(ECX, EAX); -// ROR32ItoR(ECX, 4); -// // do extra alignment masks here -// OR32RtoR(EAX, EAX); - - if( _eeIsMemWrite() ) { - u8* ptr; - CMP32ItoR(ECX, 0x40000000); - ptr = JB8(0); - if( msize == 1 ) AND32ItoR(ECX, 0x5ffffff8); - else if( msize == 2 ) AND32ItoR(ECX, 0x5ffffff0); - else AND32ItoR(ECX, 0x5fffffff); - x86SetJ8(ptr); - if( msize == 1 ) AND8ItoR(ECX, 0xf8); - else if( msize == 2 ) AND8ItoR(ECX, 0xf0); -#ifdef _DEBUG - MOV32RtoR(EAX, ECX); - SHR32ItoR(EAX, 28); - CMP32ItoR(EAX, 1); - ptr = JNE8(0); - MOV32ItoR(EDX, _Rs_); - CALLFunc((uptr)assertmem); - x86SetJ8(ptr); -#endif - return 0; - } - else { - // 16 bit version - MOV32RtoR(EAX, ECX); - ROR32ItoR(ECX, 28); - SHR32ItoR(EAX, 28); - MOV16RmSOffsettoR(EAX, EAX, msize == 2 ? (u32)&g_MemMasks16[0] : (msize == 1 ? (u32)&g_MemMasks8[0] : (u32)&g_MemMasks0[0]), 1); - AND8RtoR(ECX, EAX); - ROR32ItoR(ECX, 4); - - TEST16RtoR(EAX, EAX); // this is faster, because sets no dependend reg. - - if( s_bCachingMem & 2 ) j32Ptr[2] = j32Ptr[3] = JS32(0); - else j8Ptr[0] = j8Ptr[3] = JS8(0); - } - - return 1; -} - - -void recLoad32(u32 bit, u32 imm, u32 sign) -{ - int mmreg = -1; - -#ifdef REC_SLOWREAD - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - // do const processing - int ineax = 0; - - _eeOnLoadWrite(_Rt_); - if( bit == 32 ) { - mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); - if( mmreg >= 0 ) mmreg |= MEM_MMXTAG; - else mmreg = EAX; - } - else { - _deleteEEreg(_Rt_, 0); - mmreg = EAX; - } - - switch(bit) { - case 8: ineax = recMemConstRead8(mmreg, g_cpuConstRegs[_Rs_].UL[0]+imm, sign); break; - case 16: - assert( (g_cpuConstRegs[_Rs_].UL[0]+imm) % 2 == 0 ); - ineax = recMemConstRead16(mmreg, g_cpuConstRegs[_Rs_].UL[0]+imm, sign); - break; - case 32: - // used by LWL/LWR - //assert( (g_cpuConstRegs[_Rs_].UL[0]+imm) % 4 == 0 ); - ineax = recMemConstRead32(mmreg, g_cpuConstRegs[_Rs_].UL[0]+imm); - break; - } - - if( ineax || !(mmreg&MEM_MMXTAG) ) { - if( mmreg&MEM_MMXTAG ) mmxregs[mmreg&0xf].inuse = 0; - recTransferX86ToReg(EAX, _Rt_, sign); - } - else { - assert( mmxregs[mmreg&0xf].mode & MODE_WRITE ); - if( sign ) _signExtendGPRtoMMX(mmreg&0xf, _Rt_, 32-bit); - else if( bit < 32 ) PSRLDItoR(mmreg&0xf, 32-bit); - } - } - else -#endif - { - int dohw; - int mmregs = _eePrepareReg(_Rs_); - - _eeOnLoadWrite(_Rt_); - - if( REC_FORCEMMX ) mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); - else _deleteEEreg(_Rt_, 0); - - dohw = recSetMemLocation(_Rs_, imm, mmregs, 0, 0); - - if( mmreg >= 0 ) { - MOVD32RmOffsettoMMX(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset-(32-bit)/8); - if( sign ) _signExtendGPRtoMMX(mmreg&0xf, _Rt_, 32-bit); - else if( bit < 32 ) PSRLDItoR(mmreg&0xf, 32-bit); - } - else { - switch(bit) { - case 8: - if( sign ) MOVSX32Rm8toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); - else MOVZX32Rm8toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); - break; - case 16: - if( sign ) MOVSX32Rm16toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); - else MOVZX32Rm16toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); - break; - case 32: - MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); - break; - } - - if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); - } - - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - switch(bit) { - case 8: - CALLFunc( (int)recMemRead8 ); - if( sign ) MOVSX32R8toR(EAX, EAX); - else MOVZX32R8toR(EAX, EAX); - break; - case 16: - CALLFunc( (int)recMemRead16 ); - if( sign ) MOVSX32R16toR(EAX, EAX); - else MOVZX32R16toR(EAX, EAX); - break; - case 32: - iMemRead32Check(); - CALLFunc( (int)recMemRead32 ); - break; - } - - if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); - - if( mmreg >= 0 ) { - if( EEINST_ISLIVE1(_Rt_) ) MOVQMtoR(mmreg, (u32)&cpuRegs.GPR.r[_Rt_]); - else MOVD32RtoMMX(mmreg, EAX); - } - - if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); - else x86SetJ8(j8Ptr[2]); - } - } -} - -void recLB( void ) { recLoad32(8, _Imm_, 1); } -void recLBU( void ) { recLoad32(8, _Imm_, 0); } -void recLH( void ) { recLoad32(16, _Imm_, 1); } -void recLHU( void ) { recLoad32(16, _Imm_, 0); } -void recLW( void ) { recLoad32(32, _Imm_, 1); } -void recLWU( void ) { recLoad32(32, _Imm_, 0); } - -//////////////////////////////////////////////////// - -void recLWL( void ) -{ -#ifdef REC_SLOWREAD - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - _eeOnLoadWrite(_Rt_); - _deleteEEreg(_Rt_, 0); - - recMemConstRead32(EAX, (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3); - - if( _Rt_ ) { - u32 shift = (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&3; - - _eeMoveGPRtoR(ECX, _Rt_); - SHL32ItoR(EAX, 24-shift*8); - AND32ItoR(ECX, (0xffffff>>(shift*8))); - OR32RtoR(EAX, ECX); - - if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, 1); - } - } - else -#endif - { - int dohw; - int mmregs = _eePrepareReg(_Rs_); - - _eeOnLoadWrite(_Rt_); - _deleteEEreg(_Rt_, 0); - - dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); - - MOV32ItoR(EDX, 0x3); - AND32RtoR(EDX, ECX); - AND32ItoR(ECX, ~3); - SHL32ItoR(EDX, 3); // *8 - MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); - - if( dohw ) { - j8Ptr[1] = JMP8(0); - SET_HWLOC_R5900(); - - iMemRead32Check(); - - // repeat - MOV32ItoR(EDX, 0x3); - AND32RtoR(EDX, ECX); - AND32ItoR(ECX, ~3); - SHL32ItoR(EDX, 3); // *8 - - PUSH32R(EDX); - CALLFunc( (int)recMemRead32 ); - POP32R(EDX); - - x86SetJ8(j8Ptr[1]); - } - - if ( _Rt_ ) { - // mem << LWL_SHIFT[shift] - MOV32ItoR(ECX, 24); - SUB32RtoR(ECX, EDX); - SHL32CLtoR(EAX); - - // mov temp and compute _rt_ & LWL_MASK[shift] - MOV32RtoR(ECX, EDX); - MOV32ItoR(EDX, 0xffffff); - SAR32CLtoR(EDX); - - _eeMoveGPRtoR(ECX, _Rt_); - AND32RtoR(EDX, ECX); - - // combine - OR32RtoR(EAX, EDX); - recTransferX86ToReg(EAX, _Rt_, 1); - } - } -} - -//////////////////////////////////////////////////// - -void recLWR( void ) -{ -#ifdef REC_SLOWREAD - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - _eeOnLoadWrite(_Rt_); - _deleteEEreg(_Rt_, 0); - - recMemConstRead32(EAX, (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3); - - if( _Rt_ ) { - u32 shift = (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&3; - - _eeMoveGPRtoR(ECX, _Rt_); - SHL32ItoR(EAX, shift*8); - AND32ItoR(ECX, (0xffffff00<<(24-shift*8))); - OR32RtoR(EAX, ECX); - - recTransferX86ToReg(EAX, _Rt_, 1); - } - } - else -#endif - { - int dohw; - int mmregs = _eePrepareReg(_Rs_); - - _eeOnLoadWrite(_Rt_); - _deleteEEreg(_Rt_, 0); - - dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); - - MOV32RtoR(EDX, ECX); - AND32ItoR(ECX, ~3); - MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); - - if( dohw ) { - j8Ptr[1] = JMP8(0); - SET_HWLOC_R5900(); - - iMemRead32Check(); - - PUSH32R(ECX); - AND32ItoR(ECX, ~3); - CALLFunc( (int)recMemRead32 ); - POP32R(EDX); - - x86SetJ8(j8Ptr[1]); - } - - if ( _Rt_ ) - { - // mem << LWL_SHIFT[shift] - MOV32RtoR(ECX, EDX); - AND32ItoR(ECX, 3); - SHL32ItoR(ECX, 3); // *8 - SHR32CLtoR(EAX); - - // mov temp and compute _rt_ & LWL_MASK[shift] - MOV32RtoR(EDX, ECX); - MOV32ItoR(ECX, 24); - SUB32RtoR(ECX, EDX); - MOV32ItoR(EDX, 0xffffff00); - SHL32CLtoR(EDX); - _eeMoveGPRtoR(ECX, _Rt_); - AND32RtoR(ECX, EDX); - - // combine - OR32RtoR(EAX, ECX); - - recTransferX86ToReg(EAX, _Rt_, 1); - } - } -} - -//////////////////////////////////////////////////// -void recLoad64(u32 imm, int align) -{ - int mmreg; - int mask = align ? ~7 : ~0; - -#ifdef REC_SLOWREAD - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - // also used by LDL/LDR - //assert( (g_cpuConstRegs[_Rs_].UL[0]+imm) % 8 == 0 ); - - mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); - if( _Rt_ && mmreg >= 0 ) { - recMemConstRead64((g_cpuConstRegs[_Rs_].UL[0]+imm)&mask, mmreg); - assert( mmxregs[mmreg&0xf].mode & MODE_WRITE ); - } - else if( _Rt_ && (mmreg = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE|MODE_READ)) >= 0 ) { - recMemConstRead64((g_cpuConstRegs[_Rs_].UL[0]+imm)&mask, mmreg|0x8000); - assert( xmmregs[mmreg&0xf].mode & MODE_WRITE ); - } - else { - if( !_hasFreeMMXreg() && _hasFreeXMMreg() ) { - mmreg = _allocGPRtoXMMreg(-1, _Rt_, MODE_READ|MODE_WRITE); - recMemConstRead64((g_cpuConstRegs[_Rs_].UL[0]+imm)&mask, mmreg|0x8000); - assert( xmmregs[mmreg&0xf].mode & MODE_WRITE ); - } - else { - int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - recMemConstRead64((g_cpuConstRegs[_Rs_].UL[0]+imm)&mask, t0reg); - - if( _Rt_ ) { - SetMMXstate(); - MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_].UD[0], t0reg); - } - - _freeMMXreg(t0reg); - } - } - } - else -#endif - { - int dohw; - int mmregs = _eePrepareReg(_Rs_); - - if( _Rt_ && (mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE)) >= 0 ) { - dohw = recSetMemLocation(_Rs_, imm, mmregs, align, 0); - - MOVQRmtoROffset(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset); - - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - CALLFunc( (int)recMemRead64 ); - MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); - ADD32ItoR(ESP, 4); - } - - SetMMXstate(); - } - else if( _Rt_ && (mmreg = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE|MODE_READ)) >= 0 ) { - dohw = recSetMemLocation(_Rs_, imm, mmregs, align, 0); - - SSE_MOVLPSRmtoROffset(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset); - - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - CALLFunc( (int)recMemRead64 ); - SSE_MOVLPS_M64_to_XMM(mmreg, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); - ADD32ItoR(ESP, 4); - } - } - else { - int t0reg = _Rt_ ? _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE) : -1; - - dohw = recSetMemLocation(_Rs_, imm, mmregs, align, 0); - - if( t0reg >= 0 ) { - MOVQRmtoROffset(t0reg, ECX, PS2MEM_BASE_+s_nAddMemOffset); - SetMMXstate(); - } - - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - if( _Rt_ ) { - //_deleteEEreg(_Rt_, 0); - PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - } - else PUSH32I( (int)&retValues[0] ); - - CALLFunc( (int)recMemRead64 ); - ADD32ItoR(ESP, 4); - - if( t0reg >= 0 ) MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); - } - } - - if( dohw ) { - if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); - else x86SetJ8(j8Ptr[2]); - } - } - - _clearNeededMMXregs(); - _clearNeededXMMregs(); - if( _Rt_ ) _eeOnWriteReg(_Rt_, 0); -} - -void recLD(void) { recLoad64(_Imm_, 1); } - -//////////////////////////////////////////////////// -void recLDL( void ) -{ - iFlushCall(FLUSH_NOCONST); - - if( GPR_IS_CONST1( _Rs_ ) ) { - // flush temporarily - MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); - //MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); - } - else { - _deleteGPRtoXMMreg(_Rs_, 1); - _deleteMMXreg(MMX_GPR+_Rs_, 1); - } - - if( _Rt_ ) - _deleteEEreg(_Rt_, _Rt_==_Rs_); - - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - CALLFunc( (int)R5900::Interpreter::OpcodeImpl::LDL ); -} - -//////////////////////////////////////////////////// -void recLDR( void ) -{ - iFlushCall(FLUSH_NOCONST); - - if( GPR_IS_CONST1( _Rs_ ) ) { - // flush temporarily - MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); - //MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); - } - else { - _deleteGPRtoXMMreg(_Rs_, 1); - _deleteMMXreg(MMX_GPR+_Rs_, 1); - } - - if( _Rt_ ) - _deleteEEreg(_Rt_, _Rt_==_Rs_); - - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - CALLFunc( (int)R5900::Interpreter::OpcodeImpl::LDR ); -} - -//////////////////////////////////////////////////// -void recLQ( void ) -{ - int mmreg = -1; -#ifdef REC_SLOWREAD - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - // malice hits this - assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 16 == 0 ); - - if( _Rt_ ) { - if( (g_pCurInstInfo->regs[_Rt_]&EEINST_XMM) || !(g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) ) { - _deleteMMXreg(MMX_GPR+_Rt_, 2); - _eeOnWriteReg(_Rt_, 0); - mmreg = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); - } - else { - int t0reg; - _deleteGPRtoXMMreg(_Rt_, 2); - _eeOnWriteReg(_Rt_, 0); - mmreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE)|MEM_MMXTAG; - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - mmreg |= t0reg<<4; - } - } - else { - mmreg = _allocTempXMMreg(XMMT_INT, -1); - } - - recMemConstRead128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg); - - if( !_Rt_ ) _freeXMMreg(mmreg); - if( IS_MMXREG(mmreg) ) { - // flush temp - assert( mmxregs[mmreg&0xf].mode & MODE_WRITE ); - MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_].UL[2], (mmreg>>4)&0xf); - _freeMMXreg((mmreg>>4)&0xf); - } - else assert( xmmregs[mmreg&0xf].mode & MODE_WRITE ); - } - else -#endif - { - int dohw; - int mmregs; - int t0reg = -1; - - if( GPR_IS_CONST1( _Rs_ ) ) - _flushConstReg(_Rs_); - - mmregs = _eePrepareReg(_Rs_); - - if( _Rt_ ) { - _eeOnWriteReg(_Rt_, 0); - - // check if can process mmx - if( _hasFreeMMXreg() ) { - mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); - if( mmreg >= 0 ) { - mmreg |= MEM_MMXTAG; - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - } - } - else _deleteMMXreg(MMX_GPR+_Rt_, 2); - - if( mmreg < 0 ) { - mmreg = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); - if( mmreg >= 0 ) mmreg |= MEM_XMMTAG; - } - } - - if( mmreg < 0 ) { - _deleteEEreg(_Rt_, 1); - } - - dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0); - - if( _Rt_ ) { - if( mmreg >= 0 && (mmreg & MEM_MMXTAG) ) { - MOVQRmtoROffset(t0reg, ECX, PS2MEM_BASE_+s_nAddMemOffset+8); - MOVQRmtoROffset(mmreg&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); - MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_].UL[2], t0reg); - } - else if( mmreg >= 0 && (mmreg & MEM_XMMTAG) ) { - SSEX_MOVDQARmtoROffset(mmreg&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); - } - else { - _recMove128RmOffsettoM((u32)&cpuRegs.GPR.r[_Rt_].UL[0], PS2MEM_BASE_+s_nAddMemOffset); - } - - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - PUSH32I( (u32)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - CALLFunc( (uptr)recMemRead128 ); - - if( mmreg >= 0 && (mmreg & MEM_MMXTAG) ) MOVQMtoR(mmreg&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); - else if( mmreg >= 0 && (mmreg & MEM_XMMTAG) ) SSEX_MOVDQA_M128_to_XMM(mmreg&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - - ADD32ItoR(ESP, 4); - } - } - else { - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - PUSH32I( (u32)&retValues[0] ); - CALLFunc( (uptr)recMemRead128 ); - ADD32ItoR(ESP, 4); - } - } - - if( dohw ) { - if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); - else x86SetJ8(j8Ptr[2]); - } - - if( t0reg >= 0 ) _freeMMXreg(t0reg); - } - - _clearNeededXMMregs(); // needed since allocing -} - -//////////////////////////////////////////////////// -static void recClear64(BASEBLOCK* p) -{ - int left = 4 - ((u32)p % 16)/sizeof(BASEBLOCK); - recClearMem(p); - - if( left > 1 && *(u32*)(p+1) ) recClearMem(p+1); -} - -static void recClear128(BASEBLOCK* p) -{ - int left = 4 - ((u32)p % 32)/sizeof(BASEBLOCK); - recClearMem(p); - - if( left > 1 && *(u32*)(p+1) ) recClearMem(p+1); - if( left > 2 && *(u32*)(p+2) ) recClearMem(p+2); - if( left > 3 && *(u32*)(p+3) ) recClearMem(p+3); -} - -// check if clearing executable code, size is in dwords -void recMemConstClear(u32 mem, u32 size) -{ - // NOTE! This assumes recLUT never changes its mapping - if( !recLUT[mem>>16] ) - return; - - //iFlushCall(0); // just in case - - // check if mem is executable, and clear it - //CMP32ItoM((u32)&maxrecmem, mem); - //j8Ptr[5] = JBE8(0); - - // can clear now - if( size == 1 ) { - CMP32ItoM((u32)PC_GETBLOCK(mem), 0); - j8Ptr[6] = JE8(0); - - PUSH32I((u32)PC_GETBLOCK(mem)); - CALLFunc((uptr)recClearMem); - ADD32ItoR(ESP, 4); - x86SetJ8(j8Ptr[6]); - } - else if( size == 2 ) { - // need to clear 8 bytes - - CMP32I8toM((u32)PC_GETBLOCK(mem), 0); - j8Ptr[6] = JNE8(0); - - CMP32I8toM((u32)PC_GETBLOCK(mem)+8, 0); - j8Ptr[7] = JNE8(0); - - j8Ptr[8] = JMP8(0); - - // call clear - x86SetJ8( j8Ptr[7] ); - x86SetJ8( j8Ptr[6] ); - - PUSH32I((u32)PC_GETBLOCK(mem)); - CALLFunc((uptr)recClear64); - ADD32ItoR(ESP, 4); - - x86SetJ8( j8Ptr[8] ); - } - else { - assert( size == 4 ); - // need to clear 16 bytes - - CMP32I8toM((u32)PC_GETBLOCK(mem), 0); - j8Ptr[6] = JNE8(0); - - CMP32I8toM((u32)PC_GETBLOCK(mem)+sizeof(BASEBLOCK), 0); - j8Ptr[7] = JNE8(0); - - CMP32I8toM((u32)PC_GETBLOCK(mem)+sizeof(BASEBLOCK)*2, 0); - j8Ptr[8] = JNE8(0); - - CMP32I8toM((u32)PC_GETBLOCK(mem)+sizeof(BASEBLOCK)*3, 0); - j8Ptr[9] = JNE8(0); - - j8Ptr[10] = JMP8(0); - - // call clear - x86SetJ8( j8Ptr[6] ); - x86SetJ8( j8Ptr[7] ); - x86SetJ8( j8Ptr[8] ); - x86SetJ8( j8Ptr[9] ); - - PUSH32I((u32)PC_GETBLOCK(mem)); - CALLFunc((uptr)recClear128); - ADD32ItoR(ESP, 4); - - x86SetJ8( j8Ptr[10] ); - } - - //x86SetJ8(j8Ptr[5]); -} - -// check if mem is executable, and clear it -__declspec(naked) void recWriteMemClear32() -{ - _asm { - mov edx, ecx - shr edx, 14 - and dl, 0xfc - add edx, recLUT - test dword ptr [edx], 0xffffffff - jnz Clear32 - ret -Clear32: - // recLUT[mem>>16] + (mem&0xfffc) - mov edx, dword ptr [edx] - mov eax, ecx - and eax, 0xfffc - // edx += 2*eax - shl eax, 1 - add edx, eax - cmp dword ptr [edx], 0 - je ClearRet - sub esp, 4 - mov dword ptr [esp], edx - call recClearMem - add esp, 4 -ClearRet: - ret - } -} - -// check if mem is executable, and clear it -__declspec(naked) void recWriteMemClear64() -{ - __asm { - // check if mem is executable, and clear it - mov edx, ecx - shr edx, 14 - and edx, 0xfffffffc - add edx, recLUT - cmp dword ptr [edx], 0 - jne Clear64 - ret -Clear64: - // recLUT[mem>>16] + (mem&0xffff) - mov edx, dword ptr [edx] - mov eax, ecx - and eax, 0xfffc - // edx += 2*eax - shl eax, 1 - add edx, eax - - // note: have to check both blocks - cmp dword ptr [edx], 0 - jne DoClear0 - cmp dword ptr [edx+8], 0 - jne DoClear1 - ret - -DoClear1: - add edx, 8 -DoClear0: - sub esp, 4 - mov dword ptr [esp], edx - call recClear64 - add esp, 4 - ret - } -} - -// check if mem is executable, and clear it -__declspec(naked) void recWriteMemClear128() -{ - __asm { - // check if mem is executable, and clear it - mov edx, ecx - shr edx, 14 - and edx, 0xfffffffc - add edx, recLUT - cmp dword ptr [edx], 0 - jne Clear128 - ret -Clear128: - // recLUT[mem>>16] + (mem&0xffff) - mov edx, dword ptr [edx] - mov eax, ecx - and eax, 0xfffc - // edx += 2*eax - shl eax, 1 - add edx, eax - - // note: have to check all 4 blocks - cmp dword ptr [edx], 0 - jne DoClear - add edx, 8 - cmp dword ptr [edx], 0 - jne DoClear - add edx, 8 - cmp dword ptr [edx], 0 - jne DoClear - add edx, 8 - cmp dword ptr [edx], 0 - jne DoClear - ret - -DoClear: - sub esp, 4 - mov dword ptr [esp], edx - call recClear128 - add esp, 4 - ret - } -} - -void recStore_raw(EEINST* pinst, int bit, int x86reg, int gprreg, u32 offset) -{ - if( bit == 128 ) { - int mmreg; - if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ)) >= 0) { - SSEX_MOVDQARtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); - } - else if( (mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ)) >= 0) { - - if( _hasFreeMMXreg() ) { - int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); - MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); - MOVQRtoRmOffset(ECX, t0reg, PS2MEM_BASE_+offset+8); - _freeMMXreg(t0reg); - } - else { - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); - MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 3 ]); - MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+offset+8); - MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+offset+12); - } - - SetMMXstate(); - } - else { - - if( GPR_IS_CONST1( gprreg ) ) { - assert( _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ) == -1 ); - - if( _hasFreeMMXreg() ) { - int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - SetMMXstate(); - MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); - MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[0], PS2MEM_BASE_+offset); - MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[1], PS2MEM_BASE_+offset+4); - MOVQRtoRmOffset(ECX, t0reg, PS2MEM_BASE_+offset+8); - _freeMMXreg(t0reg); - } - else { - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); - MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 3 ]); - MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[0], PS2MEM_BASE_+offset); - MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[1], PS2MEM_BASE_+offset+4); - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+offset+8); - MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+offset+12); - } - } - else { - if( _hasFreeXMMreg() ) { - mmreg = _allocGPRtoXMMreg(-1, gprreg, MODE_READ); - SSEX_MOVDQARtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); - _freeXMMreg(mmreg); - } - else if( _hasFreeMMXreg() ) { - mmreg = _allocMMXreg(-1, MMX_TEMP, 0); - - if( _hasFreeMMXreg() ) { - int t0reg; - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); - MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); - MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); - MOVQRtoRmOffset(ECX, t0reg, PS2MEM_BASE_+offset+8); - _freeMMXreg(t0reg); - } - else { - MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); - MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 3 ]); - MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+offset+8); - MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+offset+12); -// MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); -// MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset+8); - } - SetMMXstate(); - _freeMMXreg(mmreg); - } - else { - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); - MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 1 ]); - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+offset); - MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+offset+4); - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); - MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 3 ]); - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+offset+8); - MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+offset+12); - } - } - } - return; - } - - if( GPR_IS_CONST1( gprreg ) ) { - switch(bit) { - case 8: MOV8ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[0], PS2MEM_BASE_+offset); break; - case 16: MOV16ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[0], PS2MEM_BASE_+offset); break; - case 32: MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[0], PS2MEM_BASE_+offset); break; - case 64: - MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[0], PS2MEM_BASE_+offset); - MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[1], PS2MEM_BASE_+offset+4); - break; - } - } - else { - int mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ); - if( mmreg < 0 ) { - mmreg = _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ); - if( mmreg >= 0 ) mmreg |= 0x8000; - } - - if( bit == 64 ) { - //sd - if( mmreg >= 0 ) { - if( mmreg & 0x8000 ) { - SSE_MOVLPSRtoRmOffset(ECX, mmreg&0xf, PS2MEM_BASE_+offset); - } - else { - MOVQRtoRmOffset(ECX, mmreg&0xf, PS2MEM_BASE_+offset); - SetMMXstate(); - } - } - else { - if( (mmreg = _allocCheckGPRtoMMX(pinst, gprreg, MODE_READ)) >= 0 ) { - MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); - SetMMXstate(); - _freeMMXreg(mmreg); - } - else if( _hasFreeMMXreg() ) { - mmreg = _allocMMXreg(-1, MMX_GPR+gprreg, MODE_READ); - MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); - SetMMXstate(); - _freeMMXreg(mmreg); - } - else { - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); - MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 1 ]); - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+offset); - MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+offset+4); - } - } - } - else if( bit == 32 ) { - // sw - if( mmreg >= 0 ) { - if( mmreg & 0x8000) { - SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg&0xf, PS2MEM_BASE_+offset); - } - else { - MOVD32MMXtoRmOffset(ECX, mmreg&0xf, PS2MEM_BASE_+offset); - SetMMXstate(); - } - } - else { - MOV32MtoR(x86reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); - MOV32RtoRmOffset(ECX, x86reg, PS2MEM_BASE_+offset); - } - } - else { - // sb, sh - if( mmreg >= 0) { - if( mmreg & 0x8000) { - if( !(xmmregs[mmreg&0xf].mode&MODE_WRITE) ) mmreg = -1; - } - else { - if( !(mmxregs[mmreg&0xf].mode&MODE_WRITE) ) mmreg = -1; - } - } - - if( mmreg >= 0) { - if( mmreg & 0x8000 ) SSE2_MOVD_XMM_to_R(x86reg, mmreg&0xf); - else { - MOVD32MMXtoR(x86reg, mmreg&0xf); - SetMMXstate(); - } - } - else { - switch(bit) { - case 8: MOV8MtoR(x86reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); break; - case 16: MOV16MtoR(x86reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); break; - case 32: MOV32MtoR(x86reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); break; - } - } - - switch(bit) { - case 8: MOV8RtoRmOffset(ECX, x86reg, PS2MEM_BASE_+offset); break; - case 16: MOV16RtoRmOffset(ECX, x86reg, PS2MEM_BASE_+offset); break; - case 32: MOV32RtoRmOffset(ECX, x86reg, PS2MEM_BASE_+offset); break; - } - } - } -} - -void recStore_call(int bit, int gprreg, u32 offset) -{ - // some type of hardware write - if( GPR_IS_CONST1( gprreg ) ) { - if( bit == 128 ) { - if( gprreg > 0 ) { - assert( _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ) == -1 ); - MOV32ItoM((int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], g_cpuConstRegs[gprreg].UL[0]); - MOV32ItoM((int)&cpuRegs.GPR.r[ gprreg ].UL[ 1 ], g_cpuConstRegs[gprreg].UL[1]); - } - - MOV32ItoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); - } - else if( bit == 64 ) { - if( !(g_cpuFlushedConstReg&(1<= 0) { - - if( xmmregs[mmreg].mode & MODE_WRITE ) { - SSEX_MOVDQA_XMM_to_M128((int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], mmreg); - } - } - else if( (mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ)) >= 0) { - if( mmxregs[mmreg].mode & MODE_WRITE ) { - MOVQRtoM((int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], mmreg); - } - } - - MOV32ItoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); - } - else if( bit == 64 ) { - // sd - if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ)) >= 0) { - - if( xmmregs[mmreg].mode & MODE_WRITE ) { - SSE_MOVLPS_XMM_to_M64((int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], mmreg); - } - } - else if( (mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ)) >= 0) { - if( mmxregs[mmreg].mode & MODE_WRITE ) { - MOVQRtoM((int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], mmreg); - SetMMXstate(); - } - } - - MOV32ItoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); - } - else { - // sb, sh, sw - if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ)) >= 0 && (xmmregs[mmreg].mode&MODE_WRITE) ) { - SSE2_MOVD_XMM_to_R(EAX, mmreg); - } - else if( (mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ)) >= 0 && (mmxregs[mmreg].mode&MODE_WRITE)) { - MOVD32MMXtoR(EAX, mmreg); - SetMMXstate(); - } - else { - switch(bit) { - case 8: MOV8MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); break; - case 16: MOV16MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); break; - case 32: MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); break; - } - } - } - } - - if( offset != 0 ) ADD32ItoR(ECX, offset); - - // some type of hardware write - switch(bit) { - case 8: CALLFunc( (int)recMemWrite8 ); break; - case 16: CALLFunc( (int)recMemWrite16 ); break; - case 32: CALLFunc( (int)recMemWrite32 ); break; - case 64: CALLFunc( (int)recMemWrite64 ); break; - case 128: CALLFunc( (int)recMemWrite128 ); break; - } -} - -int _eePrepConstWrite128(int gprreg) -{ - int mmreg = 0; - - if( GPR_IS_CONST1(gprreg) ) { - if( gprreg ) { - mmreg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQMtoR(mmreg, (u32)&cpuRegs.GPR.r[gprreg].UL[2]); - _freeMMXreg(mmreg); - mmreg |= (gprreg<<16)|MEM_EECONSTTAG; - } - else { - mmreg = _allocTempXMMreg(XMMT_INT, -1); - SSEX_PXOR_XMM_to_XMM(mmreg, mmreg); - _freeXMMreg(mmreg); - mmreg |= MEM_XMMTAG; - } - } - else { - if( (mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ)) >= 0 ) { - int mmregtemp = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQMtoR(mmregtemp, (u32)&cpuRegs.GPR.r[gprreg].UL[2]); - mmreg |= (mmregtemp<<4)|MEM_MMXTAG; - _freeMMXreg(mmregtemp); - } - else mmreg = _allocGPRtoXMMreg(-1, gprreg, MODE_READ)|MEM_XMMTAG; - } - - return mmreg; -} - -void recStore(int bit, u32 imm, int align) -{ - int mmreg; - -#ifdef REC_SLOWWRITE - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - u32 addr = g_cpuConstRegs[_Rs_].UL[0]+imm; - int doclear = 0; - switch(bit) { - case 8: - if( GPR_IS_CONST1(_Rt_) ) doclear = recMemConstWrite8(addr, MEM_EECONSTTAG|(_Rt_<<16)); - else { - _eeMoveGPRtoR(EAX, _Rt_); - doclear = recMemConstWrite8(addr, EAX); - } - - if( doclear ) { - recMemConstClear((addr)&~3, 1); - } - - break; - case 16: - assert( (addr)%2 == 0 ); - if( GPR_IS_CONST1(_Rt_) ) doclear = recMemConstWrite16(addr, MEM_EECONSTTAG|(_Rt_<<16)); - else { - _eeMoveGPRtoR(EAX, _Rt_); - doclear = recMemConstWrite16(addr, EAX); - } - - if( doclear ) { - recMemConstClear((addr)&~3, 1); - } - - break; - case 32: - // used by SWL/SWR - //assert( (addr)%4 == 0 ); - if( GPR_IS_CONST1(_Rt_) ) doclear = recMemConstWrite32(addr, MEM_EECONSTTAG|(_Rt_<<16)); - else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ)) >= 0 ) { - doclear = recMemConstWrite32(addr, mmreg|MEM_XMMTAG|(_Rt_<<16)); - } - else if( (mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_READ)) >= 0 ) { - doclear = recMemConstWrite32(addr, mmreg|MEM_MMXTAG|(_Rt_<<16)); - } - else { - _eeMoveGPRtoR(EAX, _Rt_); - doclear = recMemConstWrite32(addr, EAX); - } - - if( doclear ) { - recMemConstClear((addr)&~3, 1); - } - break; - case 64: - { - //assert( (addr)%8 == 0 ); - int mask = align ? ~7 : ~0; - - if( GPR_IS_CONST1(_Rt_) ) doclear = recMemConstWrite64(addr, MEM_EECONSTTAG|(_Rt_<<16)); - else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ)) >= 0 ) { - doclear = recMemConstWrite64(addr&mask, mmreg|MEM_XMMTAG|(_Rt_<<16)); - } - else { - mmreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); - doclear = recMemConstWrite64(addr&mask, mmreg|MEM_MMXTAG|(_Rt_<<16)); - } - - if( doclear ) { - recMemConstClear((addr)&~7, 2); - } - - break; - } - case 128: - //assert( (addr)%16 == 0 ); - - if( recMemConstWrite128((addr)&~15, _eePrepConstWrite128(_Rt_)) ) { - CMP32ItoM((u32)&maxrecmem, addr); - j8Ptr[0] = JB8(0); - recMemConstClear((addr)&~15, 4); - x86SetJ8(j8Ptr[0]); - } - - break; - } - } - else -#endif - { - int dohw; - int mmregs; - - if( GPR_IS_CONST1( _Rs_ ) ) { - _flushConstReg(_Rs_); - } - - mmregs = _eePrepareReg(_Rs_); - dohw = recSetMemLocation(_Rs_, imm, mmregs, align ? bit/64 : 0, 0); - - recStore_raw(g_pCurInstInfo, bit, EAX, _Rt_, s_nAddMemOffset); - - if( s_nAddMemOffset ) ADD32ItoR(ECX, s_nAddMemOffset); - CMP32MtoR(ECX, (u32)&maxrecmem); - - if( s_bCachingMem & 2 ) j32Ptr[4] = JAE32(0); - else j8Ptr[1] = JAE8(0); - - if( bit < 32 || !align ) AND8ItoR(ECX, 0xfc); - if( bit <= 32 ) CALLFunc((uptr)recWriteMemClear32); - else if( bit == 64 ) CALLFunc((uptr)recWriteMemClear64); - else CALLFunc((uptr)recWriteMemClear128); - - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[5] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - recStore_call(bit, _Rt_, s_nAddMemOffset); - - if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[5]); - else x86SetJ8(j8Ptr[2]); - } - - if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); - else x86SetJ8(j8Ptr[1]); - } - - _clearNeededMMXregs(); // needed since allocing - _clearNeededXMMregs(); // needed since allocing -} - - -void recSB( void ) { recStore(8, _Imm_, 1); } -void recSH( void ) { recStore(16, _Imm_, 1); } -void recSW( void ) { recStore(32, _Imm_, 1); } - -//////////////////////////////////////////////////// -void recSWL( void ) -{ -#ifdef REC_SLOWWRITE - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - int shift = (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&3; - - recMemConstRead32(EAX, (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3); - - _eeMoveGPRtoR(ECX, _Rt_); - AND32ItoR(EAX, 0xffffff00<<(shift*8)); - SHR32ItoR(ECX, 24-shift*8); - OR32RtoR(EAX, ECX); - - if( recMemConstWrite32((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3, EAX) ) - recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3, 1); - } - else -#endif - { - int dohw; - int mmregs = _eePrepareReg(_Rs_); - dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); - - MOV32ItoR(EDX, 0x3); - AND32RtoR(EDX, ECX); - AND32ItoR(ECX, ~3); - SHL32ItoR(EDX, 3); // *8 - PUSH32R(ECX); - XOR32RtoR(EDI, EDI); - - MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); - - if( dohw ) { - j8Ptr[1] = JMP8(0); - SET_HWLOC_R5900(); - - // repeat - MOV32ItoR(EDX, 0x3); - AND32RtoR(EDX, ECX); - AND32ItoR(ECX, ~3); - SHL32ItoR(EDX, 3); // *8 - - PUSH32R(ECX); - PUSH32R(EDX); - CALLFunc( (int)recMemRead32 ); - POP32R(EDX); - MOV8ItoR(EDI, 0xff); - - x86SetJ8(j8Ptr[1]); - } - - _eeMoveGPRtoR(EBX, _Rt_); - - // oldmem is in EAX - // mem >> SWL_SHIFT[shift] - MOV32ItoR(ECX, 24); - SUB32RtoR(ECX, EDX); - SHR32CLtoR(EBX); - - // mov temp and compute _rt_ & SWL_MASK[shift] - MOV32RtoR(ECX, EDX); - MOV32ItoR(EDX, 0xffffff00); - SHL32CLtoR(EDX); - AND32RtoR(EAX, EDX); - - // combine - OR32RtoR(EAX, EBX); - - POP32R(ECX); - - // read the old mem again - TEST32RtoR(EDI, EDI); - j8Ptr[0] = JNZ8(0); - - // manual write - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); - - j8Ptr[1] = JMP8(0); - x86SetJ8(j8Ptr[0]); - - CALLFunc( (int)recMemWrite32 ); - - x86SetJ8(j8Ptr[1]); - } -} - -//////////////////////////////////////////////////// -void recSWR( void ) -{ -#ifdef REC_SLOWWRITE - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - int shift = (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&3; - - recMemConstRead32(EAX, (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3); - - _eeMoveGPRtoR(ECX, _Rt_); - AND32ItoR(EAX, 0x00ffffff>>(24-shift*8)); - SHL32ItoR(ECX, shift*8); - OR32RtoR(EAX, ECX); - - if( recMemConstWrite32((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3, EAX) ) - recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3, 1); - } - else -#endif - { - int dohw; - int mmregs = _eePrepareReg(_Rs_); - dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); - - MOV32ItoR(EDX, 0x3); - AND32RtoR(EDX, ECX); - AND32ItoR(ECX, ~3); - SHL32ItoR(EDX, 3); // *8 - - PUSH32R(ECX); - XOR32RtoR(EDI, EDI); - - MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); - - if( dohw ) { - j8Ptr[1] = JMP8(0); - SET_HWLOC_R5900(); - - // repeat - MOV32ItoR(EDX, 0x3); - AND32RtoR(EDX, ECX); - AND32ItoR(ECX, ~3); - SHL32ItoR(EDX, 3); // *8 - - PUSH32R(ECX); - PUSH32R(EDX); - CALLFunc( (int)recMemRead32 ); - POP32R(EDX); - MOV8ItoR(EDI, 0xff); - - x86SetJ8(j8Ptr[1]); - } - - _eeMoveGPRtoR(EBX, _Rt_); - - // oldmem is in EAX - // mem << SWR_SHIFT[shift] - MOV32RtoR(ECX, EDX); - SHL32CLtoR(EBX); - - // mov temp and compute _rt_ & SWR_MASK[shift] - MOV32ItoR(ECX, 24); - SUB32RtoR(ECX, EDX); - MOV32ItoR(EDX, 0x00ffffff); - SHR32CLtoR(EDX); - AND32RtoR(EAX, EDX); - - // combine - OR32RtoR(EAX, EBX); - - POP32R(ECX); - - // read the old mem again - TEST32RtoR(EDI, EDI); - j8Ptr[0] = JNZ8(0); - - // manual write - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); - - j8Ptr[1] = JMP8(0); - x86SetJ8(j8Ptr[0]); - - CALLFunc( (int)recMemWrite32 ); - - x86SetJ8(j8Ptr[1]); - } -} - -void recSD( void ) { recStore(64, _Imm_, 1); } - -//////////////////////////////////////////////////// -void recSDR( void ) -{ - iFlushCall(FLUSH_NOCONST); - - if( GPR_IS_CONST1( _Rs_ ) ) { - // flush temporarily - MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); - //MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); - } - - if( GPR_IS_CONST1( _Rt_ ) && !(g_cpuFlushedConstReg&(1<<_Rt_)) ) { - MOV32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0]); - MOV32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1]); - g_cpuFlushedConstReg |= (1<<_Rt_); - } - - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - CALLFunc( (int)R5900::Interpreter::OpcodeImpl::SDR ); -} - -//////////////////////////////////////////////////// -void recSDL( void ) -{ - iFlushCall(FLUSH_NOCONST); - - if( GPR_IS_CONST1( _Rs_ ) ) { - // flush temporarily - MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); - //MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); - } - - if( GPR_IS_CONST1( _Rt_ ) && !(g_cpuFlushedConstReg&(1<<_Rt_)) ) { - MOV32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0]); - MOV32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1]); - g_cpuFlushedConstReg |= (1<<_Rt_); - } - - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - CALLFunc( (int)R5900::Interpreter::OpcodeImpl::SDL ); -} - -//////////////////////////////////////////////////// -void recSQ( void ) { recStore(128, _Imm_, 1); } - -/********************************************************* -* Load and store for COP1 * -* Format: OP rt, offset(base) * -*********************************************************/ - -//////////////////////////////////////////////////// -void recLWC1( void ) -{ -#ifdef REC_SLOWREAD - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - int mmreg; - assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 ); - - mmreg = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE); - if( mmreg >= 0 ) mmreg |= MEM_XMMTAG; - else mmreg = EAX; - - if( recMemConstRead32(mmreg, g_cpuConstRegs[_Rs_].UL[0]+_Imm_) ) { - if( mmreg&MEM_XMMTAG ) xmmregs[mmreg&0xf].inuse = 0; - mmreg = EAX; - } - - if( !(mmreg&MEM_XMMTAG) ) - MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); - } - else -#endif - { - int dohw; - int regt = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE); - int mmregs = _eePrepareReg(_Rs_); - - _deleteMMXreg(MMX_FPU+_Rt_, 2); - dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); - - if( regt >= 0 ) { - SSEX_MOVD_RmOffset_to_XMM(regt, ECX, PS2MEM_BASE_+s_nAddMemOffset); - } - else { - MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); - MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); - } - - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - iMemRead32Check(); - CALLFunc( (int)recMemRead32 ); - - if( regt >= 0 ) SSE2_MOVD_R_to_XMM(regt, EAX); - else MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); - - if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); - else x86SetJ8(j8Ptr[2]); - } - } -} - -//////////////////////////////////////////////////// -void recSWC1( void ) -{ - int mmreg; - -#ifdef REC_SLOWWRITE - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)%4 == 0 ); - - mmreg = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ); - - if( mmreg >= 0 ) mmreg |= MEM_XMMTAG|(_Rt_<<16); - else { - MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); - mmreg = EAX; - } - - recMemConstWrite32(g_cpuConstRegs[_Rs_].UL[0]+_Imm_, mmreg); - } - else -#endif - { - int dohw; - int mmregs = _eePrepareReg(_Rs_); - - assert( _checkMMXreg(MMX_FPU+_Rt_, MODE_READ) == -1 ); - - mmreg = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ); - dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); - - if( mmreg >= 0) { - SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg, PS2MEM_BASE_+s_nAddMemOffset); - } - else { - MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); - } - - if( dohw ) { - if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); - else j8Ptr[2] = JMP8(0); - - SET_HWLOC_R5900(); - - // some type of hardware write - if( mmreg >= 0) SSE2_MOVD_XMM_to_R(EAX, mmreg); - else MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); - - CALLFunc( (int)recMemWrite32 ); - - if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); - else x86SetJ8(j8Ptr[2]); - } - } -} - -//////////////////////////////////////////////////// - -#define _Ft_ _Rt_ -#define _Fs_ _Rd_ -#define _Fd_ _Sa_ - -void recLQC2( void ) -{ - int mmreg; - -#ifdef REC_SLOWREAD - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 16 == 0 ); - - if( _Ft_ ) mmreg = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_WRITE); - else mmreg = _allocTempXMMreg(XMMT_FPS, -1); - recMemConstRead128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg); - - if( !_Ft_ ) _freeXMMreg(mmreg); - } - else -#endif - { - int dohw, mmregs; - - if( GPR_IS_CONST1( _Rs_ ) ) { - _flushConstReg(_Rs_); - } - - mmregs = _eePrepareReg(_Rs_); - - if( _Ft_ ) mmreg = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_WRITE); - - dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0); - - if( _Ft_ ) { - u8* rawreadptr = x86Ptr; - - if( mmreg >= 0 ) { - SSEX_MOVDQARmtoROffset(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset); - } - else { - _recMove128RmOffsettoM((u32)&VU0.VF[_Ft_].UL[0], PS2MEM_BASE_+s_nAddMemOffset); - } - - if( dohw ) { - j8Ptr[1] = JMP8(0); - SET_HWLOC_R5900(); - - // check if writing to VUs - CMP32ItoR(ECX, 0x11000000); - JAE8(rawreadptr - (x86Ptr+2)); - - PUSH32I( (int)&VU0.VF[_Ft_].UD[0] ); - CALLFunc( (int)recMemRead128 ); - if( mmreg >= 0 ) SSEX_MOVDQA_M128_to_XMM(mmreg, (int)&VU0.VF[_Ft_].UD[0] ); - ADD32ItoR(ESP, 4); - - x86SetJ8(j8Ptr[1]); - } - } - else { - if( dohw ) { - j8Ptr[1] = JMP8(0); - SET_HWLOC_R5900(); - - PUSH32I( (int)&retValues[0] ); - CALLFunc( (int)recMemRead128 ); - ADD32ItoR(ESP, 4); - - x86SetJ8(j8Ptr[1]); - } - } - } - - _clearNeededXMMregs(); // needed since allocing -} - -//////////////////////////////////////////////////// -void recSQC2( void ) -{ - int mmreg; - -#ifdef REC_SLOWWRITE - _flushConstReg(_Rs_); -#else - if( GPR_IS_CONST1( _Rs_ ) ) { - assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)%16 == 0 ); - - mmreg = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_READ)|MEM_XMMTAG; - recMemConstWrite128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg); - } - else -#endif - { - u8* rawreadptr; - int dohw, mmregs; - - if( GPR_IS_CONST1( _Rs_ ) ) { - _flushConstReg(_Rs_); - } - - mmregs = _eePrepareReg(_Rs_); - dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0); - - rawreadptr = x86Ptr; - - if( (mmreg = _checkXMMreg(XMMTYPE_VFREG, _Ft_, MODE_READ)) >= 0) { - SSEX_MOVDQARtoRmOffset(ECX, mmreg, PS2MEM_BASE_+s_nAddMemOffset); - } - else { - if( _hasFreeXMMreg() ) { - mmreg = _allocTempXMMreg(XMMT_FPS, -1); - SSEX_MOVDQA_M128_to_XMM(mmreg, (int)&VU0.VF[_Ft_].UD[0]); - SSEX_MOVDQARtoRmOffset(ECX, mmreg, PS2MEM_BASE_+s_nAddMemOffset); - _freeXMMreg(mmreg); - } - else if( _hasFreeMMXreg() ) { - mmreg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQMtoR(mmreg, (int)&VU0.VF[_Ft_].UD[0]); - MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+s_nAddMemOffset); - MOVQMtoR(mmreg, (int)&VU0.VF[_Ft_].UL[2]); - MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+s_nAddMemOffset+8); - SetMMXstate(); - _freeMMXreg(mmreg); - } - else { - MOV32MtoR(EAX, (int)&VU0.VF[_Ft_].UL[0]); - MOV32MtoR(EDX, (int)&VU0.VF[_Ft_].UL[1]); - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); - MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+4); - MOV32MtoR(EAX, (int)&VU0.VF[_Ft_].UL[2]); - MOV32MtoR(EDX, (int)&VU0.VF[_Ft_].UL[3]); - MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+8); - MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+12); - } - } - - if( dohw ) { - j8Ptr[1] = JMP8(0); - - SET_HWLOC_R5900(); - - // check if writing to VUs - CMP32ItoR(ECX, 0x11000000); - JAE8(rawreadptr - (x86Ptr+2)); - - // some type of hardware write - if( (mmreg = _checkXMMreg(XMMTYPE_VFREG, _Ft_, MODE_READ)) >= 0) { - - if( xmmregs[mmreg].mode & MODE_WRITE ) { - SSEX_MOVDQA_XMM_to_M128((int)&VU0.VF[_Ft_].UD[0], mmreg); - } - } - - MOV32ItoR(EAX, (int)&VU0.VF[_Ft_].UD[0]); - CALLFunc( (int)recMemWrite128 ); - - x86SetJ8A(j8Ptr[1]); - } - } -} - -#else - -using namespace Interpreter::OpcodeImpl; - -PCSX2_ALIGNED16(u32 dummyValue[4]); - -void SetFastMemory(int bSetFast) -{ - // nothing -} - -void recLoad64( u32 bits, bool sign ) -{ - jASSUME( bits == 64 || bits == 128 ); - - //no int 3? i love to get my hands dirty ;p - Raz - //write8(0xCC); - - _deleteEEreg(_Rs_, 1); - _eeOnLoadWrite(_Rt_); - - EEINST_RESETSIGNEXT(_Rt_); // remove the sign extension -> what does this really do ? - - _deleteEEreg(_Rt_, 0); - - // Load ECX with the source memory address that we're reading from. - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - ADD32ItoR( ECX, _Imm_ ); - - if( bits == 128 ) // force 16 byte alignment on 128 bit reads - AND32I8toR(ECX,0xF0); - - // Load EDX with the destination. 64/128 bit modes load the result directly into - // the cpuRegs.GPR struct. - - if ( _Rt_ ) - MOV32ItoR(EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - else - MOV32ItoR(EDX, (int)&dummyValue[0] ); - - vtlb_DynGenRead64(bits); -} - -void recLoad32(u32 bits,bool sign) -{ - jASSUME( bits <= 32 ); - - //no int 3? i love to get my hands dirty ;p - Raz - //write8(0xCC); - - _deleteEEreg(_Rs_, 1); - _eeOnLoadWrite(_Rt_); - _deleteEEreg(_Rt_, 0); - - // Load ECX with the source memory address that we're reading from. - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - ADD32ItoR( ECX, _Imm_ ); - - // 8/16/32 bit modes return the loaded value in EAX. - //MOV32ItoR(EDX, (int)&dummyValue[0] ); - - vtlb_DynGenRead32(bits, sign); - - if ( _Rt_ ) - { - // Perform sign extension if needed - - //MOV32MtoR( EAX, (int)&dummyValue[0] ); //ewww, lame ! movsx /zx has r/m forms too ... - /*if (bits==8) - { - if (sign) - //MOVSX32M8toR( EAX, (int)&dummyValue[0] ); - MOVSX32R8toR( EAX, EAX ); - //else - //MOVZX32M8toR( EAX, (int)&dummyValue[0] ); - //MOVZX32R8toR( EAX, EAX ); - } - else if (bits==16) - { - if (sign) - //MOVSX32M16toR( EAX, (int)&dummyValue[0] ); - MOVSX32R16toR( EAX, EAX ); - //else - //MOVZX32M16toR( EAX, (int)&dummyValue[0] ); - //MOVZX32R16toR( EAX, EAX ); - }*/ - - if (sign) - CDQ(); - else - XOR32RtoR(EDX,EDX); - - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); - } -} - -//////////////////////////////////////////////////// -void recLB( void ) -{ - recLoad32(8,true); - /* - _deleteEEreg(_Rs_, 1); - _eeOnLoadWrite(_Rt_); - _deleteEEreg(_Rt_, 0); - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - { - ADD32ItoR( EAX, _Imm_ ); - } - PUSH32I( (int)&dummyValue[0] ); - PUSH32R( EAX ); - - CALLFunc( (int)memRead8 ); - ADD32ItoR( ESP, 8 ); - if ( _Rt_ ) - { - u8* linkEnd; - TEST32RtoR( EAX, EAX ); - linkEnd = JNZ8( 0 ); - MOV32MtoR( EAX, (int)&dummyValue[0] ); - MOVSX32R8toR( EAX, EAX ); - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); - x86SetJ8( linkEnd ); - } - */ -} - -//////////////////////////////////////////////////// -void recLBU( void ) -{ - recLoad32(8,false); - /* - _deleteEEreg(_Rs_, 1); - _eeOnLoadWrite(_Rt_); - _deleteEEreg(_Rt_, 0); - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - { - ADD32ItoR( EAX, _Imm_ ); - } - PUSH32I( (int)&dummyValue[0] ); - PUSH32R( EAX ); - - CALLFunc( (int)memRead8 ); - ADD32ItoR( ESP, 8 ); - if ( _Rt_ ) - { - u8* linkEnd; - TEST32RtoR( EAX, EAX ); - linkEnd = JNZ8( 0 ); - MOV32MtoR( EAX, (int)&dummyValue[0] ); - MOVZX32R8toR( EAX, EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); - x86SetJ8( linkEnd ); - } - */ -} - -//////////////////////////////////////////////////// -void recLH( void ) -{ - recLoad32(16,true); - /* - _deleteEEreg(_Rs_, 1); - _eeOnLoadWrite(_Rt_); - _deleteEEreg(_Rt_, 0); - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - { - ADD32ItoR( EAX, _Imm_ ); - } - PUSH32I( (int)&dummyValue[0] ); - PUSH32R( EAX ); - - CALLFunc( (int)memRead16 ); - ADD32ItoR( ESP, 8 ); - if ( _Rt_ ) - { - u8* linkEnd; - TEST32RtoR( EAX, EAX ); - linkEnd = JNZ8( 0 ); - MOV32MtoR( EAX, (int)&dummyValue[0]); - MOVSX32R16toR( EAX, EAX ); - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); - x86SetJ8( linkEnd ); - } - */ -} - -//////////////////////////////////////////////////// -void recLHU( void ) -{ - recLoad32(16,false); - /* - _deleteEEreg(_Rs_, 1); - _eeOnLoadWrite(_Rt_); - _deleteEEreg(_Rt_, 0); - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - { - ADD32ItoR( EAX, _Imm_ ); - } - PUSH32I( (int)&dummyValue[0] ); - PUSH32R( EAX ); - CALLFunc( (int)memRead16 ); - ADD32ItoR( ESP, 8 ); - if ( _Rt_ ) - { - u8* linkEnd; - TEST32RtoR( EAX, EAX ); - linkEnd = JNZ8( 0 ); - MOV32MtoR( EAX, (int)&dummyValue[0] ); - MOVZX32R16toR( EAX, EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); - x86SetJ8( linkEnd ); - }*/ -} - -//////////////////////////////////////////////////// -void recLW( void ) -{ - recLoad32(32,true); - /* - _deleteEEreg(_Rs_, 1); - _eeOnLoadWrite(_Rt_); - _deleteEEreg(_Rt_, 0); - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - { - ADD32ItoR( EAX, _Imm_ ); - } - - PUSH32I( (int)&dummyValue[0]); - PUSH32R( EAX ); - - CALLFunc( (int)memRead32 ); - ADD32ItoR( ESP, 8 ); - - if ( _Rt_ ) - { - u8* linkEnd; - TEST32RtoR( EAX, EAX ); - linkEnd = JNZ8( 0 ); - MOV32MtoR( EAX, (int)&dummyValue[0]); - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); - x86SetJ8( linkEnd ); - }*/ -} - -//////////////////////////////////////////////////// -void recLWU( void ) -{ - recLoad32(32,false); - /* - _deleteEEreg(_Rs_, 1); - _eeOnLoadWrite(_Rt_); - _deleteEEreg(_Rt_, 0); - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - { - ADD32ItoR( EAX, _Imm_ ); - } - - PUSH32I( (int)&dummyValue[0]); - PUSH32R( EAX ); - CALLFunc( (int)memRead32 ); - ADD32ItoR( ESP, 8 ); - if ( _Rt_ ) - { - u8* linkEnd; - TEST32RtoR( EAX, EAX ); - linkEnd = JNZ8( 0 ); - MOV32MtoR( EAX, (int)&dummyValue[0]); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); - x86SetJ8( linkEnd ); - } - */ -} - -//////////////////////////////////////////////////// -void recLWL( void ) -{ - _deleteEEreg(_Rs_, 1); - _eeOnLoadWrite(_Rt_); - _deleteEEreg(_Rt_, 0); - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - CALLFunc( (int)LWL ); -} - -//////////////////////////////////////////////////// -void recLWR( void ) -{ - iFlushCall(FLUSH_EVERYTHING); - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - CALLFunc( (int)LWR ); -} - -//////////////////////////////////////////////////// -extern void MOV64RmtoR( x86IntRegType to, x86IntRegType from ); - -void recLD( void ) -{ - recLoad64(64,false); - /* - _deleteEEreg(_Rs_, 1); - _eeOnLoadWrite(_Rt_); - EEINST_RESETSIGNEXT(_Rt_); // remove the sign extension - _deleteEEreg(_Rt_, 0); - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - { - ADD32ItoR( EAX, _Imm_ ); - } - - if ( _Rt_ ) - { - PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - } - else - { - PUSH32I( (int)&dummyValue[0] ); - } - PUSH32R( EAX ); - CALLFunc( (int)memRead64 ); - ADD32ItoR( ESP, 8 ); - */ -} - -//////////////////////////////////////////////////// -void recLDL( void ) -{ - _deleteEEreg(_Rs_, 1); - _eeOnLoadWrite(_Rt_); - EEINST_RESETSIGNEXT(_Rt_); // remove the sign extension - _deleteEEreg(_Rt_, 0); - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - CALLFunc( (int)LDL ); -} - -//////////////////////////////////////////////////// -void recLDR( void ) -{ - _deleteEEreg(_Rs_, 1); - _eeOnLoadWrite(_Rt_); - EEINST_RESETSIGNEXT(_Rt_); // remove the sign extension - _deleteEEreg(_Rt_, 0); - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - CALLFunc( (int)LDR ); -} - -//////////////////////////////////////////////////// -void recLQ( void ) -{ - recLoad64(128,false); -/* - _deleteEEreg(_Rs_, 1); - _eeOnLoadWrite(_Rt_); - EEINST_RESETSIGNEXT(_Rt_); // remove the sign extension - _deleteEEreg(_Rt_, 0); - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - { - ADD32ItoR( EAX, _Imm_); - } - AND32ItoR( EAX, ~0xf ); - - if ( _Rt_ ) - { - PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - } - else - { - PUSH32I( (int)&dummyValue[0] ); - } - PUSH32R( EAX ); - CALLFunc( (int)memRead128 ); - ADD32ItoR( ESP, 8 ); - */ -} -void recStore(u32 sz) -{ - //no int 3? i love to get my hands dirty ;p - Raz - //write8(0xCC); - - _deleteEEreg(_Rs_, 1); - _deleteEEreg(_Rt_, 1); - - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - { - ADD32ItoR( ECX, _Imm_); - } - if (sz==128) - { - AND32I8toR(ECX,0xF0); - } - - if (sz<64) - { - if (_Rt_) - MOV32MtoR(EDX,(int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); - else - XOR32RtoR(EDX,EDX); - } - else if (sz==128 || sz==64) - { - MOV32ItoR(EDX,(int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); - } - - - vtlb_DynGenWrite(sz); - - /* - if (sz==8) - CALLFunc( (int)memWrite8 ); - else if (sz==16) - CALLFunc( (int)memWrite16 ); - else if (sz==32) - CALLFunc( (int)memWrite32 ); - else if (sz==64) - CALLFunc( (int)memWrite64 ); - else if (sz==128) - CALLFunc( (int)memWrite128 ); - */ -} -//////////////////////////////////////////////////// -void recSB( void ) -{ - recStore(8); - /* - _deleteEEreg(_Rs_, 1); - _deleteEEreg(_Rt_, 1); - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - { - ADD32ItoR( EAX, _Imm_); - } - PUSH32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - PUSH32R( EAX ); - CALLFunc( (int)memWrite8 ); - ADD32ItoR( ESP, 8 ); - */ -} - -//////////////////////////////////////////////////// -void recSH( void ) -{ - recStore(16); - /* - _deleteEEreg(_Rs_, 1); - _deleteEEreg(_Rt_, 1); - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - { - ADD32ItoR( EAX, _Imm_ ); - } - PUSH32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - PUSH32R( EAX ); - CALLFunc( (int)memWrite16 ); - ADD32ItoR( ESP, 8 ); - */ -} - -//////////////////////////////////////////////////// -void recSW( void ) -{ - recStore(32); - /* - _deleteEEreg(_Rs_, 1); - _deleteEEreg(_Rt_, 1); - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - { - ADD32ItoR( EAX, _Imm_ ); - } - - PUSH32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - PUSH32R( EAX ); - CALLFunc( (int)memWrite32 ); - ADD32ItoR( ESP, 8 ); - */ -} - -//////////////////////////////////////////////////// -void recSWL( void ) -{ - _deleteEEreg(_Rs_, 1); - _deleteEEreg(_Rt_, 1); - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - CALLFunc( (int)SWL ); -} - -//////////////////////////////////////////////////// -void recSWR( void ) -{ - _deleteEEreg(_Rs_, 1); - _deleteEEreg(_Rt_, 1); - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - CALLFunc( (int)SWR ); -} - -//////////////////////////////////////////////////// -void recSD( void ) -{ - recStore(64); - /* - _deleteEEreg(_Rs_, 1); - _deleteEEreg(_Rt_, 1); - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - { - ADD32ItoR( EAX, _Imm_ ); - } - - PUSH32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - PUSH32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - PUSH32R( EAX ); - CALLFunc( (int)memWrite64 ); - ADD32ItoR( ESP, 12 ); - */ -} - -//////////////////////////////////////////////////// -void recSDL( void ) -{ - _deleteEEreg(_Rs_, 1); - _deleteEEreg(_Rt_, 1); - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - CALLFunc( (int)SDL ); -} - -//////////////////////////////////////////////////// -void recSDR( void ) -{ - _deleteEEreg(_Rs_, 1); - _deleteEEreg(_Rt_, 1); - MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); - MOV32ItoM( (int)&cpuRegs.pc, pc ); - CALLFunc( (int)SDR ); -} - -//////////////////////////////////////////////////// -void recSQ( void ) -{ - recStore(128); - /* - _deleteEEreg(_Rs_, 1); - _deleteEEreg(_Rt_, 1); - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - { - ADD32ItoR( EAX, _Imm_ ); - } - AND32ItoR( EAX, ~0xf ); - - PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); - PUSH32R( EAX ); - CALLFunc( (int)memWrite128 ); - ADD32ItoR( ESP, 8 );*/ -} - -/********************************************************* -* Load and store for COP1 * -* Format: OP rt, offset(base) * -*********************************************************/ - -//////////////////////////////////////////////////// -void recLWC1( void ) -{ - _deleteEEreg(_Rs_, 1); - _deleteFPtoXMMreg(_Rt_, 2); - - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - ADD32ItoR( ECX, _Imm_ ); - - //MOV32ItoR(EDX, (int)&fpuRegs.fpr[ _Rt_ ].UL ); //no 0 for fpu ? - //CALLFunc( (int)memRead32 ); - vtlb_DynGenRead32(32, false); - MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); -} - -//////////////////////////////////////////////////// -void recSWC1( void ) -{ - _deleteEEreg(_Rs_, 1); - _deleteFPtoXMMreg(_Rt_, 0); - - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - ADD32ItoR( ECX, _Imm_ ); - - MOV32MtoR(EDX, (int)&fpuRegs.fpr[ _Rt_ ].UL ); - vtlb_DynGenWrite(32); -} - -//////////////////////////////////////////////////// - -/********************************************************* -* Load and store for COP2 (VU0 unit) * -* Format: OP rt, offset(base) * -*********************************************************/ - -#define _Ft_ _Rt_ -#define _Fs_ _Rd_ -#define _Fd_ _Sa_ - -void recLQC2( void ) -{ - _deleteEEreg(_Rs_, 1); - _deleteVFtoXMMreg(_Ft_, 0, 2); - - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - ADD32ItoR( ECX, _Imm_); - - if ( _Rt_ ) - MOV32ItoR(EDX, (int)&VU0.VF[_Ft_].UD[0] ); - else - MOV32ItoR(EDX, (int)&dummyValue[0] ); - - vtlb_DynGenRead64(128); -} - -//////////////////////////////////////////////////// -void recSQC2( void ) -{ - _deleteEEreg(_Rs_, 1); - _deleteVFtoXMMreg(_Ft_, 0, 0); - - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - if ( _Imm_ != 0 ) - ADD32ItoR( ECX, _Imm_ ); - - MOV32ItoR(EDX, (int)&VU0.VF[_Ft_].UD[0] ); - vtlb_DynGenWrite(128); -} - -#endif - -#endif - -} } } // end namespace R5900::Dynarec::OpcodeImpl - -using namespace R5900::Dynarec; -using namespace R5900::Dynarec::OpcodeImpl; - -#ifdef PCSX2_VIRTUAL_MEM - -#ifndef LOADSTORE_RECOMPILE - void SetFastMemory(int bSetFast) {} -#else - static int s_bFastMemory = 0; - void SetFastMemory(int bSetFast) - { - s_bFastMemory = bSetFast; - if( bSetFast ) { - g_MemMasks0[0] = 0x00f0; g_MemMasks0[1] = 0x80f1; g_MemMasks0[2] = 0x00f0; g_MemMasks0[3] = 0x00f1; - g_MemMasks8[0] = 0x0080; g_MemMasks8[1] = 0x8081; g_MemMasks8[2] = 0x0080; g_MemMasks8[3] = 0x0081; - g_MemMasks16[0] = 0x0000; g_MemMasks16[1] = 0x8001; g_MemMasks16[2] = 0x0000; g_MemMasks16[3] = 0x0001; - } - else { - g_MemMasks0[0] = 0x00f0; g_MemMasks0[1] = 0x80f1; g_MemMasks0[2] = 0x00f2; g_MemMasks0[3] = 0x00f3; - g_MemMasks8[0] = 0x0080; g_MemMasks8[1] = 0x8081; g_MemMasks8[2] = 0x0082; g_MemMasks8[3] = 0x0083; - g_MemMasks16[0] = 0x0000; g_MemMasks16[1] = 0x8001; g_MemMasks16[2] = 0x0002; g_MemMasks16[3] = 0x0003; - } - } -#endif - -#else // VTLB version - - void SetFastMemory(int bSetFast) {} - -#endif +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "R5900OpcodeTables.h" +#include "iR5900LoadStore.h" +#include "ix86/ix86.h" +#include "iR5900.h" + +// Implemented at the bottom of the module: +void SetFastMemory(int bSetFast); + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl { + +/********************************************************* +* Load and store for GPR * +* Format: OP rt, offset(base) * +*********************************************************/ +#ifndef LOADSTORE_RECOMPILE + +namespace Interp = R5900::Interpreter::OpcodeImpl; + +REC_FUNC(LB); +REC_FUNC(LBU); +REC_FUNC(LH); +REC_FUNC(LHU); +REC_FUNC(LW); +REC_FUNC(LWU); +REC_FUNC(LWL); +REC_FUNC(LWR); +REC_FUNC(LD); +REC_FUNC(LDR); +REC_FUNC(LDL); +REC_FUNC(LQ); +REC_FUNC(SB); +REC_FUNC(SH); +REC_FUNC(SW); +REC_FUNC(SWL); +REC_FUNC(SWR); +REC_FUNC(SD); +REC_FUNC(SDL); +REC_FUNC(SDR); +REC_FUNC(SQ); +REC_FUNC(LWC1); +REC_FUNC(SWC1); +REC_FUNC(LQC2); +REC_FUNC(SQC2); + +#else + +PCSX2_ALIGNED16(u64 retValues[2]); +static u32 s_bCachingMem = 0; +static u32 s_nAddMemOffset = 0; +static u32 s_tempaddr = 0; + +void _eeOnLoadWrite(int reg) +{ + int regt; + + if( !reg ) return; + + _eeOnWriteReg(reg, 1); + regt = _checkXMMreg(XMMTYPE_GPRREG, reg, MODE_READ); + + if( regt >= 0 ) { + if( xmmregs[regt].mode & MODE_WRITE ) { + if( reg != _Rs_ ) { + SSE2_PUNPCKHQDQ_XMM_to_XMM(regt, regt); + SSE2_MOVQ_XMM_to_M64((u32)&cpuRegs.GPR.r[reg].UL[2], regt); + } + else SSE_MOVHPS_XMM_to_M64((u32)&cpuRegs.GPR.r[reg].UL[2], regt); + } + xmmregs[regt].inuse = 0; + } +} + +#ifdef PCSX2_VIRTUAL_MEM + +//////////////////////////////////////////////////// +//#define REC_SLOWREAD +//#define REC_SLOWWRITE +#define REC_FORCEMMX 0 + +// if sp, always mem write +int _eeIsMemWrite() { return _Rs_==29||_Rs_== 31||_Rs_==26||_Rs_==27; } // sp, ra, k0, k1 +// gp can be 1000a020 (jak1) + +void recTransferX86ToReg(int x86reg, int gprreg, int sign) +{ + //if( !REC_FORCEMMX ) assert( _checkMMXreg(MMX_GPR+gprreg, MODE_WRITE) == -1 ); + if( sign ) { + if( x86reg == EAX && EEINST_ISLIVE1(gprreg) ) CDQ(); + + MOV32RtoM( (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], x86reg ); + + if(EEINST_ISLIVE1(gprreg)) { + if( x86reg == EAX ) MOV32RtoM( (int)&cpuRegs.GPR.r[ gprreg ].UL[ 1 ], EDX ); + else { + SAR32ItoR(x86reg, 31); + MOV32RtoM( (int)&cpuRegs.GPR.r[ gprreg ].UL[ 1 ], x86reg ); + } + } + else { + EEINST_RESETHASLIVE1(gprreg); + } + } + else { + MOV32RtoM( (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], x86reg ); + if(EEINST_ISLIVE1(gprreg)) MOV32ItoM( (int)&cpuRegs.GPR.r[ gprreg ].UL[ 1 ], 0 ); + else EEINST_RESETHASLIVE1(gprreg); + } +} + +#ifdef _DEBUG +void testaddrs() +{ + register int tempaddr; + + __asm mov tempaddr, ecx + //__asm mov incaddr, edx + + assert( (tempaddr < 0x40000000) || (tempaddr&0xd0000000)==0x50000000 || (tempaddr >= 0x80000000 && tempaddr < 0xc0000000) ); + //assert( (tempaddr>>28) == ((tempaddr+incaddr)>>28) ); + + __asm mov ecx, tempaddr +} +#endif + +static __forceinline void SET_HWLOC_R5900() { + if ( s_bCachingMem & 2 ) + { + x86SetJ32(j32Ptr[2]); + x86SetJ32(j32Ptr[3]); + } + else + { + x86SetJ8(j8Ptr[0]); + x86SetJ8(j8Ptr[3]); + } + + if (x86FpuState==MMX_STATE) { + if (cpucaps.has3DNOWInstructionExtensions) + FEMMS(); + else + EMMS(); + } + if( s_nAddMemOffset ) + ADD32ItoR(ECX, s_nAddMemOffset); + if( s_bCachingMem & 4 ) + AND32ItoR(ECX, 0x5fffffff); +} + +static u16 g_MemMasks0[16] = {0x00f0, 0x80f1, 0x00f2, 0x00f3, + 0x00f1, 0x00f5, 0x00f1, 0x00f5, + 0x00f5, 0x80f5, 0x00f5, 0x80f5, + 0x00f1, 0x00f1, 0x00f1, 0x00f5 }; +static u16 g_MemMasks8[16] = {0x0080, 0x8081, 0x0082, 0x0083, + 0x0081, 0x0085, 0x0081, 0x0085, + 0x0085, 0x8085, 0x0085, 0x8085, + 0x0081, 0x0081, 0x0081, 0x0085 }; +static u16 g_MemMasks16[16] ={0x0000, 0x8001, 0x0002, 0x0003, + 0x0001, 0x0005, 0x0001, 0x0005, + 0x0005, 0x8005, 0x0005, 0x8005, + 0x0001, 0x0001, 0x0001, 0x0005 }; + +void assertmem() +{ + __asm mov s_tempaddr, ecx + __asm mov s_bCachingMem, edx + Console::Error("%x(%x) not mem write!", params s_tempaddr, s_bCachingMem); + assert(0); +} + +int _eePrepareReg(int gprreg) +{ + int mmreg = _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ); + + if( mmreg >= 0 && (xmmregs[mmreg].mode&MODE_WRITE) ) { + mmreg |= MEM_XMMTAG; + } + else if( (mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ)) >= 0 ) { + if( mmxregs[mmreg].mode&MODE_WRITE ) mmreg |= MEM_MMXTAG; + else { + mmxregs[mmreg].needed = 0; // coX can possibly use all regs + mmreg = 0; + } + } + else { + mmreg = 0; + } + + return mmreg; +} + +// returns true if should also include hardware writes +int recSetMemLocation(int regs, int imm, int mmreg, int msize, int j32) +{ + s_bCachingMem = j32 ? 2 : 0; + s_nAddMemOffset = 0; + + //int num; + if( mmreg >= 0 && (mmreg & MEM_XMMTAG) ) { + SSE2_MOVD_XMM_to_R(ECX, mmreg&0xf); + } + else if( mmreg >= 0 && (mmreg & MEM_MMXTAG) ) { + MOVD32MMXtoR(ECX, mmreg&0xf); + SetMMXstate(); + } + else { + MOV32MtoR( ECX, (uptr)&cpuRegs.GPR.r[ regs ].UL[ 0 ] ); + } + + if ( imm != 0 ) ADD32ItoR( ECX, imm ); + + LoadCW(); + +#ifdef _DEBUG + //CALLFunc((uptr)testaddrs); +#endif + + + // 32bit version (faster?) +// MOV32RtoR(EAX, ECX); +// ROR32ItoR(ECX, 28); +// SHR32ItoR(EAX, 28); +// MOV32RmSOffsettoR(EAX, EAX, msize == 2 ? (u32)&g_MemMasks16[0] : (msize == 1 ? (u32)&g_MemMasks8[0] : (u32)&g_MemMasks0[0]), 2); +// AND8RtoR(ECX, EAX); +// ROR32ItoR(ECX, 4); +// // do extra alignment masks here +// OR32RtoR(EAX, EAX); + + if( _eeIsMemWrite() ) { + u8* ptr; + CMP32ItoR(ECX, 0x40000000); + ptr = JB8(0); + if( msize == 1 ) AND32ItoR(ECX, 0x5ffffff8); + else if( msize == 2 ) AND32ItoR(ECX, 0x5ffffff0); + else AND32ItoR(ECX, 0x5fffffff); + x86SetJ8(ptr); + if( msize == 1 ) AND8ItoR(ECX, 0xf8); + else if( msize == 2 ) AND8ItoR(ECX, 0xf0); +#ifdef _DEBUG + MOV32RtoR(EAX, ECX); + SHR32ItoR(EAX, 28); + CMP32ItoR(EAX, 1); + ptr = JNE8(0); + MOV32ItoR(EDX, _Rs_); + CALLFunc((uptr)assertmem); + x86SetJ8(ptr); +#endif + return 0; + } + else { + // 16 bit version + MOV32RtoR(EAX, ECX); + ROR32ItoR(ECX, 28); + SHR32ItoR(EAX, 28); + MOV16RmSOffsettoR(EAX, EAX, msize == 2 ? (u32)&g_MemMasks16[0] : (msize == 1 ? (u32)&g_MemMasks8[0] : (u32)&g_MemMasks0[0]), 1); + AND8RtoR(ECX, EAX); + ROR32ItoR(ECX, 4); + + TEST16RtoR(EAX, EAX); // this is faster, because sets no dependend reg. + + if( s_bCachingMem & 2 ) j32Ptr[2] = j32Ptr[3] = JS32(0); + else j8Ptr[0] = j8Ptr[3] = JS8(0); + } + + return 1; +} + + +void recLoad32(u32 bit, u32 imm, u32 sign) +{ + int mmreg = -1; + +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + // do const processing + int ineax = 0; + + _eeOnLoadWrite(_Rt_); + if( bit == 32 ) { + mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( mmreg >= 0 ) mmreg |= MEM_MMXTAG; + else mmreg = EAX; + } + else { + _deleteEEreg(_Rt_, 0); + mmreg = EAX; + } + + switch(bit) { + case 8: ineax = recMemConstRead8(mmreg, g_cpuConstRegs[_Rs_].UL[0]+imm, sign); break; + case 16: + assert( (g_cpuConstRegs[_Rs_].UL[0]+imm) % 2 == 0 ); + ineax = recMemConstRead16(mmreg, g_cpuConstRegs[_Rs_].UL[0]+imm, sign); + break; + case 32: + // used by LWL/LWR + //assert( (g_cpuConstRegs[_Rs_].UL[0]+imm) % 4 == 0 ); + ineax = recMemConstRead32(mmreg, g_cpuConstRegs[_Rs_].UL[0]+imm); + break; + } + + if( ineax || !(mmreg&MEM_MMXTAG) ) { + if( mmreg&MEM_MMXTAG ) mmxregs[mmreg&0xf].inuse = 0; + recTransferX86ToReg(EAX, _Rt_, sign); + } + else { + assert( mmxregs[mmreg&0xf].mode & MODE_WRITE ); + if( sign ) _signExtendGPRtoMMX(mmreg&0xf, _Rt_, 32-bit); + else if( bit < 32 ) PSRLDItoR(mmreg&0xf, 32-bit); + } + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + + _eeOnLoadWrite(_Rt_); + + if( REC_FORCEMMX ) mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); + else _deleteEEreg(_Rt_, 0); + + dohw = recSetMemLocation(_Rs_, imm, mmregs, 0, 0); + + if( mmreg >= 0 ) { + MOVD32RmOffsettoMMX(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset-(32-bit)/8); + if( sign ) _signExtendGPRtoMMX(mmreg&0xf, _Rt_, 32-bit); + else if( bit < 32 ) PSRLDItoR(mmreg&0xf, 32-bit); + } + else { + switch(bit) { + case 8: + if( sign ) MOVSX32Rm8toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + else MOVZX32Rm8toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + break; + case 16: + if( sign ) MOVSX32Rm16toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + else MOVZX32Rm16toROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + break; + case 32: + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + break; + } + + if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + switch(bit) { + case 8: + CALLFunc( (int)recMemRead8 ); + if( sign ) MOVSX32R8toR(EAX, EAX); + else MOVZX32R8toR(EAX, EAX); + break; + case 16: + CALLFunc( (int)recMemRead16 ); + if( sign ) MOVSX32R16toR(EAX, EAX); + else MOVZX32R16toR(EAX, EAX); + break; + case 32: + iMemRead32Check(); + CALLFunc( (int)recMemRead32 ); + break; + } + + if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, sign); + + if( mmreg >= 0 ) { + if( EEINST_ISLIVE1(_Rt_) ) MOVQMtoR(mmreg, (u32)&cpuRegs.GPR.r[_Rt_]); + else MOVD32RtoMMX(mmreg, EAX); + } + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + } +} + +void recLB( void ) { recLoad32(8, _Imm_, 1); } +void recLBU( void ) { recLoad32(8, _Imm_, 0); } +void recLH( void ) { recLoad32(16, _Imm_, 1); } +void recLHU( void ) { recLoad32(16, _Imm_, 0); } +void recLW( void ) { recLoad32(32, _Imm_, 1); } +void recLWU( void ) { recLoad32(32, _Imm_, 0); } + +//////////////////////////////////////////////////// + +void recLWL( void ) +{ +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + recMemConstRead32(EAX, (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3); + + if( _Rt_ ) { + u32 shift = (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&3; + + _eeMoveGPRtoR(ECX, _Rt_); + SHL32ItoR(EAX, 24-shift*8); + AND32ItoR(ECX, (0xffffff>>(shift*8))); + OR32RtoR(EAX, ECX); + + if ( _Rt_ ) recTransferX86ToReg(EAX, _Rt_, 1); + } + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); + + MOV32ItoR(EDX, 0x3); + AND32RtoR(EDX, ECX); + AND32ItoR(ECX, ~3); + SHL32ItoR(EDX, 3); // *8 + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + + if( dohw ) { + j8Ptr[1] = JMP8(0); + SET_HWLOC_R5900(); + + iMemRead32Check(); + + // repeat + MOV32ItoR(EDX, 0x3); + AND32RtoR(EDX, ECX); + AND32ItoR(ECX, ~3); + SHL32ItoR(EDX, 3); // *8 + + PUSH32R(EDX); + CALLFunc( (int)recMemRead32 ); + POP32R(EDX); + + x86SetJ8(j8Ptr[1]); + } + + if ( _Rt_ ) { + // mem << LWL_SHIFT[shift] + MOV32ItoR(ECX, 24); + SUB32RtoR(ECX, EDX); + SHL32CLtoR(EAX); + + // mov temp and compute _rt_ & LWL_MASK[shift] + MOV32RtoR(ECX, EDX); + MOV32ItoR(EDX, 0xffffff); + SAR32CLtoR(EDX); + + _eeMoveGPRtoR(ECX, _Rt_); + AND32RtoR(EDX, ECX); + + // combine + OR32RtoR(EAX, EDX); + recTransferX86ToReg(EAX, _Rt_, 1); + } + } +} + +//////////////////////////////////////////////////// + +void recLWR( void ) +{ +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + recMemConstRead32(EAX, (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3); + + if( _Rt_ ) { + u32 shift = (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&3; + + _eeMoveGPRtoR(ECX, _Rt_); + SHL32ItoR(EAX, shift*8); + AND32ItoR(ECX, (0xffffff00<<(24-shift*8))); + OR32RtoR(EAX, ECX); + + recTransferX86ToReg(EAX, _Rt_, 1); + } + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); + + MOV32RtoR(EDX, ECX); + AND32ItoR(ECX, ~3); + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + + if( dohw ) { + j8Ptr[1] = JMP8(0); + SET_HWLOC_R5900(); + + iMemRead32Check(); + + PUSH32R(ECX); + AND32ItoR(ECX, ~3); + CALLFunc( (int)recMemRead32 ); + POP32R(EDX); + + x86SetJ8(j8Ptr[1]); + } + + if ( _Rt_ ) + { + // mem << LWL_SHIFT[shift] + MOV32RtoR(ECX, EDX); + AND32ItoR(ECX, 3); + SHL32ItoR(ECX, 3); // *8 + SHR32CLtoR(EAX); + + // mov temp and compute _rt_ & LWL_MASK[shift] + MOV32RtoR(EDX, ECX); + MOV32ItoR(ECX, 24); + SUB32RtoR(ECX, EDX); + MOV32ItoR(EDX, 0xffffff00); + SHL32CLtoR(EDX); + _eeMoveGPRtoR(ECX, _Rt_); + AND32RtoR(ECX, EDX); + + // combine + OR32RtoR(EAX, ECX); + + recTransferX86ToReg(EAX, _Rt_, 1); + } + } +} + +//////////////////////////////////////////////////// +void recLoad64(u32 imm, int align) +{ + int mmreg; + int mask = align ? ~7 : ~0; + +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + // also used by LDL/LDR + //assert( (g_cpuConstRegs[_Rs_].UL[0]+imm) % 8 == 0 ); + + mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( _Rt_ && mmreg >= 0 ) { + recMemConstRead64((g_cpuConstRegs[_Rs_].UL[0]+imm)&mask, mmreg); + assert( mmxregs[mmreg&0xf].mode & MODE_WRITE ); + } + else if( _Rt_ && (mmreg = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE|MODE_READ)) >= 0 ) { + recMemConstRead64((g_cpuConstRegs[_Rs_].UL[0]+imm)&mask, mmreg|0x8000); + assert( xmmregs[mmreg&0xf].mode & MODE_WRITE ); + } + else { + if( !_hasFreeMMXreg() && _hasFreeXMMreg() ) { + mmreg = _allocGPRtoXMMreg(-1, _Rt_, MODE_READ|MODE_WRITE); + recMemConstRead64((g_cpuConstRegs[_Rs_].UL[0]+imm)&mask, mmreg|0x8000); + assert( xmmregs[mmreg&0xf].mode & MODE_WRITE ); + } + else { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + recMemConstRead64((g_cpuConstRegs[_Rs_].UL[0]+imm)&mask, t0reg); + + if( _Rt_ ) { + SetMMXstate(); + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_].UD[0], t0reg); + } + + _freeMMXreg(t0reg); + } + } + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + + if( _Rt_ && (mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE)) >= 0 ) { + dohw = recSetMemLocation(_Rs_, imm, mmregs, align, 0); + + MOVQRmtoROffset(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset); + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + CALLFunc( (int)recMemRead64 ); + MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); + ADD32ItoR(ESP, 4); + } + + SetMMXstate(); + } + else if( _Rt_ && (mmreg = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE|MODE_READ)) >= 0 ) { + dohw = recSetMemLocation(_Rs_, imm, mmregs, align, 0); + + SSE_MOVLPSRmtoROffset(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset); + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + CALLFunc( (int)recMemRead64 ); + SSE_MOVLPS_M64_to_XMM(mmreg, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); + ADD32ItoR(ESP, 4); + } + } + else { + int t0reg = _Rt_ ? _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE) : -1; + + dohw = recSetMemLocation(_Rs_, imm, mmregs, align, 0); + + if( t0reg >= 0 ) { + MOVQRmtoROffset(t0reg, ECX, PS2MEM_BASE_+s_nAddMemOffset); + SetMMXstate(); + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + if( _Rt_ ) { + //_deleteEEreg(_Rt_, 0); + PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + } + else PUSH32I( (int)&retValues[0] ); + + CALLFunc( (int)recMemRead64 ); + ADD32ItoR(ESP, 4); + + if( t0reg >= 0 ) MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ]); + } + } + + if( dohw ) { + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + } + + _clearNeededMMXregs(); + _clearNeededXMMregs(); + if( _Rt_ ) _eeOnWriteReg(_Rt_, 0); +} + +void recLD(void) { recLoad64(_Imm_, 1); } + +//////////////////////////////////////////////////// +void recLDL( void ) +{ + iFlushCall(FLUSH_NOCONST); + + if( GPR_IS_CONST1( _Rs_ ) ) { + // flush temporarily + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); + //MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); + } + else { + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteMMXreg(MMX_GPR+_Rs_, 1); + } + + if( _Rt_ ) + _deleteEEreg(_Rt_, _Rt_==_Rs_); + + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)R5900::Interpreter::OpcodeImpl::LDL ); +} + +//////////////////////////////////////////////////// +void recLDR( void ) +{ + iFlushCall(FLUSH_NOCONST); + + if( GPR_IS_CONST1( _Rs_ ) ) { + // flush temporarily + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); + //MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); + } + else { + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteMMXreg(MMX_GPR+_Rs_, 1); + } + + if( _Rt_ ) + _deleteEEreg(_Rt_, _Rt_==_Rs_); + + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)R5900::Interpreter::OpcodeImpl::LDR ); +} + +//////////////////////////////////////////////////// +void recLQ( void ) +{ + int mmreg = -1; +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + // malice hits this + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 16 == 0 ); + + if( _Rt_ ) { + if( (g_pCurInstInfo->regs[_Rt_]&EEINST_XMM) || !(g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) ) { + _deleteMMXreg(MMX_GPR+_Rt_, 2); + _eeOnWriteReg(_Rt_, 0); + mmreg = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); + } + else { + int t0reg; + _deleteGPRtoXMMreg(_Rt_, 2); + _eeOnWriteReg(_Rt_, 0); + mmreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE)|MEM_MMXTAG; + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + mmreg |= t0reg<<4; + } + } + else { + mmreg = _allocTempXMMreg(XMMT_INT, -1); + } + + recMemConstRead128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg); + + if( !_Rt_ ) _freeXMMreg(mmreg); + if( IS_MMXREG(mmreg) ) { + // flush temp + assert( mmxregs[mmreg&0xf].mode & MODE_WRITE ); + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_].UL[2], (mmreg>>4)&0xf); + _freeMMXreg((mmreg>>4)&0xf); + } + else assert( xmmregs[mmreg&0xf].mode & MODE_WRITE ); + } + else +#endif + { + int dohw; + int mmregs; + int t0reg = -1; + + if( GPR_IS_CONST1( _Rs_ ) ) + _flushConstReg(_Rs_); + + mmregs = _eePrepareReg(_Rs_); + + if( _Rt_ ) { + _eeOnWriteReg(_Rt_, 0); + + // check if can process mmx + if( _hasFreeMMXreg() ) { + mmreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( mmreg >= 0 ) { + mmreg |= MEM_MMXTAG; + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + } + } + else _deleteMMXreg(MMX_GPR+_Rt_, 2); + + if( mmreg < 0 ) { + mmreg = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG; + } + } + + if( mmreg < 0 ) { + _deleteEEreg(_Rt_, 1); + } + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0); + + if( _Rt_ ) { + if( mmreg >= 0 && (mmreg & MEM_MMXTAG) ) { + MOVQRmtoROffset(t0reg, ECX, PS2MEM_BASE_+s_nAddMemOffset+8); + MOVQRmtoROffset(mmreg&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_].UL[2], t0reg); + } + else if( mmreg >= 0 && (mmreg & MEM_XMMTAG) ) { + SSEX_MOVDQARmtoROffset(mmreg&0xf, ECX, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + _recMove128RmOffsettoM((u32)&cpuRegs.GPR.r[_Rt_].UL[0], PS2MEM_BASE_+s_nAddMemOffset); + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + PUSH32I( (u32)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + CALLFunc( (uptr)recMemRead128 ); + + if( mmreg >= 0 && (mmreg & MEM_MMXTAG) ) MOVQMtoR(mmreg&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + else if( mmreg >= 0 && (mmreg & MEM_XMMTAG) ) SSEX_MOVDQA_M128_to_XMM(mmreg&0xf, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + + ADD32ItoR(ESP, 4); + } + } + else { + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + PUSH32I( (u32)&retValues[0] ); + CALLFunc( (uptr)recMemRead128 ); + ADD32ItoR(ESP, 4); + } + } + + if( dohw ) { + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + + if( t0reg >= 0 ) _freeMMXreg(t0reg); + } + + _clearNeededXMMregs(); // needed since allocing +} + +//////////////////////////////////////////////////// +static void recClear64(BASEBLOCK* p) +{ + int left = 4 - ((u32)p % 16)/sizeof(BASEBLOCK); + recClearMem(p); + + if( left > 1 && *(u32*)(p+1) ) recClearMem(p+1); +} + +static void recClear128(BASEBLOCK* p) +{ + int left = 4 - ((u32)p % 32)/sizeof(BASEBLOCK); + recClearMem(p); + + if( left > 1 && *(u32*)(p+1) ) recClearMem(p+1); + if( left > 2 && *(u32*)(p+2) ) recClearMem(p+2); + if( left > 3 && *(u32*)(p+3) ) recClearMem(p+3); +} + +// check if clearing executable code, size is in dwords +void recMemConstClear(u32 mem, u32 size) +{ + // NOTE! This assumes recLUT never changes its mapping + if( !recLUT[mem>>16] ) + return; + + //iFlushCall(0); // just in case + + // check if mem is executable, and clear it + //CMP32ItoM((u32)&maxrecmem, mem); + //j8Ptr[5] = JBE8(0); + + // can clear now + if( size == 1 ) { + CMP32ItoM((u32)PC_GETBLOCK(mem), 0); + j8Ptr[6] = JE8(0); + + PUSH32I((u32)PC_GETBLOCK(mem)); + CALLFunc((uptr)recClearMem); + ADD32ItoR(ESP, 4); + x86SetJ8(j8Ptr[6]); + } + else if( size == 2 ) { + // need to clear 8 bytes + + CMP32I8toM((u32)PC_GETBLOCK(mem), 0); + j8Ptr[6] = JNE8(0); + + CMP32I8toM((u32)PC_GETBLOCK(mem)+8, 0); + j8Ptr[7] = JNE8(0); + + j8Ptr[8] = JMP8(0); + + // call clear + x86SetJ8( j8Ptr[7] ); + x86SetJ8( j8Ptr[6] ); + + PUSH32I((u32)PC_GETBLOCK(mem)); + CALLFunc((uptr)recClear64); + ADD32ItoR(ESP, 4); + + x86SetJ8( j8Ptr[8] ); + } + else { + assert( size == 4 ); + // need to clear 16 bytes + + CMP32I8toM((u32)PC_GETBLOCK(mem), 0); + j8Ptr[6] = JNE8(0); + + CMP32I8toM((u32)PC_GETBLOCK(mem)+sizeof(BASEBLOCK), 0); + j8Ptr[7] = JNE8(0); + + CMP32I8toM((u32)PC_GETBLOCK(mem)+sizeof(BASEBLOCK)*2, 0); + j8Ptr[8] = JNE8(0); + + CMP32I8toM((u32)PC_GETBLOCK(mem)+sizeof(BASEBLOCK)*3, 0); + j8Ptr[9] = JNE8(0); + + j8Ptr[10] = JMP8(0); + + // call clear + x86SetJ8( j8Ptr[6] ); + x86SetJ8( j8Ptr[7] ); + x86SetJ8( j8Ptr[8] ); + x86SetJ8( j8Ptr[9] ); + + PUSH32I((u32)PC_GETBLOCK(mem)); + CALLFunc((uptr)recClear128); + ADD32ItoR(ESP, 4); + + x86SetJ8( j8Ptr[10] ); + } + + //x86SetJ8(j8Ptr[5]); +} + +// check if mem is executable, and clear it +__declspec(naked) void recWriteMemClear32() +{ + _asm { + mov edx, ecx + shr edx, 14 + and dl, 0xfc + add edx, recLUT + test dword ptr [edx], 0xffffffff + jnz Clear32 + ret +Clear32: + // recLUT[mem>>16] + (mem&0xfffc) + mov edx, dword ptr [edx] + mov eax, ecx + and eax, 0xfffc + // edx += 2*eax + shl eax, 1 + add edx, eax + cmp dword ptr [edx], 0 + je ClearRet + sub esp, 4 + mov dword ptr [esp], edx + call recClearMem + add esp, 4 +ClearRet: + ret + } +} + +// check if mem is executable, and clear it +__declspec(naked) void recWriteMemClear64() +{ + __asm { + // check if mem is executable, and clear it + mov edx, ecx + shr edx, 14 + and edx, 0xfffffffc + add edx, recLUT + cmp dword ptr [edx], 0 + jne Clear64 + ret +Clear64: + // recLUT[mem>>16] + (mem&0xffff) + mov edx, dword ptr [edx] + mov eax, ecx + and eax, 0xfffc + // edx += 2*eax + shl eax, 1 + add edx, eax + + // note: have to check both blocks + cmp dword ptr [edx], 0 + jne DoClear0 + cmp dword ptr [edx+8], 0 + jne DoClear1 + ret + +DoClear1: + add edx, 8 +DoClear0: + sub esp, 4 + mov dword ptr [esp], edx + call recClear64 + add esp, 4 + ret + } +} + +// check if mem is executable, and clear it +__declspec(naked) void recWriteMemClear128() +{ + __asm { + // check if mem is executable, and clear it + mov edx, ecx + shr edx, 14 + and edx, 0xfffffffc + add edx, recLUT + cmp dword ptr [edx], 0 + jne Clear128 + ret +Clear128: + // recLUT[mem>>16] + (mem&0xffff) + mov edx, dword ptr [edx] + mov eax, ecx + and eax, 0xfffc + // edx += 2*eax + shl eax, 1 + add edx, eax + + // note: have to check all 4 blocks + cmp dword ptr [edx], 0 + jne DoClear + add edx, 8 + cmp dword ptr [edx], 0 + jne DoClear + add edx, 8 + cmp dword ptr [edx], 0 + jne DoClear + add edx, 8 + cmp dword ptr [edx], 0 + jne DoClear + ret + +DoClear: + sub esp, 4 + mov dword ptr [esp], edx + call recClear128 + add esp, 4 + ret + } +} + +void recStore_raw(EEINST* pinst, int bit, int x86reg, int gprreg, u32 offset) +{ + if( bit == 128 ) { + int mmreg; + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ)) >= 0) { + SSEX_MOVDQARtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ)) >= 0) { + + if( _hasFreeMMXreg() ) { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); + MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); + MOVQRtoRmOffset(ECX, t0reg, PS2MEM_BASE_+offset+8); + _freeMMXreg(t0reg); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 3 ]); + MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+offset+8); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+offset+12); + } + + SetMMXstate(); + } + else { + + if( GPR_IS_CONST1( gprreg ) ) { + assert( _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ) == -1 ); + + if( _hasFreeMMXreg() ) { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + SetMMXstate(); + MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); + MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[0], PS2MEM_BASE_+offset); + MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[1], PS2MEM_BASE_+offset+4); + MOVQRtoRmOffset(ECX, t0reg, PS2MEM_BASE_+offset+8); + _freeMMXreg(t0reg); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 3 ]); + MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[0], PS2MEM_BASE_+offset); + MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[1], PS2MEM_BASE_+offset+4); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+offset+8); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+offset+12); + } + } + else { + if( _hasFreeXMMreg() ) { + mmreg = _allocGPRtoXMMreg(-1, gprreg, MODE_READ); + SSEX_MOVDQARtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); + _freeXMMreg(mmreg); + } + else if( _hasFreeMMXreg() ) { + mmreg = _allocMMXreg(-1, MMX_TEMP, 0); + + if( _hasFreeMMXreg() ) { + int t0reg; + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); + MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); + MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); + MOVQRtoRmOffset(ECX, t0reg, PS2MEM_BASE_+offset+8); + _freeMMXreg(t0reg); + } + else { + MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 3 ]); + MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+offset+8); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+offset+12); +// MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); +// MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset+8); + } + SetMMXstate(); + _freeMMXreg(mmreg); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 1 ]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+offset); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+offset+4); + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 2 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 3 ]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+offset+8); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+offset+12); + } + } + } + return; + } + + if( GPR_IS_CONST1( gprreg ) ) { + switch(bit) { + case 8: MOV8ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[0], PS2MEM_BASE_+offset); break; + case 16: MOV16ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[0], PS2MEM_BASE_+offset); break; + case 32: MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[0], PS2MEM_BASE_+offset); break; + case 64: + MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[0], PS2MEM_BASE_+offset); + MOV32ItoRmOffset(ECX, g_cpuConstRegs[gprreg].UL[1], PS2MEM_BASE_+offset+4); + break; + } + } + else { + int mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ); + if( mmreg < 0 ) { + mmreg = _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ); + if( mmreg >= 0 ) mmreg |= 0x8000; + } + + if( bit == 64 ) { + //sd + if( mmreg >= 0 ) { + if( mmreg & 0x8000 ) { + SSE_MOVLPSRtoRmOffset(ECX, mmreg&0xf, PS2MEM_BASE_+offset); + } + else { + MOVQRtoRmOffset(ECX, mmreg&0xf, PS2MEM_BASE_+offset); + SetMMXstate(); + } + } + else { + if( (mmreg = _allocCheckGPRtoMMX(pinst, gprreg, MODE_READ)) >= 0 ) { + MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); + SetMMXstate(); + _freeMMXreg(mmreg); + } + else if( _hasFreeMMXreg() ) { + mmreg = _allocMMXreg(-1, MMX_GPR+gprreg, MODE_READ); + MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+offset); + SetMMXstate(); + _freeMMXreg(mmreg); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 1 ]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+offset); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+offset+4); + } + } + } + else if( bit == 32 ) { + // sw + if( mmreg >= 0 ) { + if( mmreg & 0x8000) { + SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg&0xf, PS2MEM_BASE_+offset); + } + else { + MOVD32MMXtoRmOffset(ECX, mmreg&0xf, PS2MEM_BASE_+offset); + SetMMXstate(); + } + } + else { + MOV32MtoR(x86reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); + MOV32RtoRmOffset(ECX, x86reg, PS2MEM_BASE_+offset); + } + } + else { + // sb, sh + if( mmreg >= 0) { + if( mmreg & 0x8000) { + if( !(xmmregs[mmreg&0xf].mode&MODE_WRITE) ) mmreg = -1; + } + else { + if( !(mmxregs[mmreg&0xf].mode&MODE_WRITE) ) mmreg = -1; + } + } + + if( mmreg >= 0) { + if( mmreg & 0x8000 ) SSE2_MOVD_XMM_to_R(x86reg, mmreg&0xf); + else { + MOVD32MMXtoR(x86reg, mmreg&0xf); + SetMMXstate(); + } + } + else { + switch(bit) { + case 8: MOV8MtoR(x86reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); break; + case 16: MOV16MtoR(x86reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); break; + case 32: MOV32MtoR(x86reg, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); break; + } + } + + switch(bit) { + case 8: MOV8RtoRmOffset(ECX, x86reg, PS2MEM_BASE_+offset); break; + case 16: MOV16RtoRmOffset(ECX, x86reg, PS2MEM_BASE_+offset); break; + case 32: MOV32RtoRmOffset(ECX, x86reg, PS2MEM_BASE_+offset); break; + } + } + } +} + +void recStore_call(int bit, int gprreg, u32 offset) +{ + // some type of hardware write + if( GPR_IS_CONST1( gprreg ) ) { + if( bit == 128 ) { + if( gprreg > 0 ) { + assert( _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ) == -1 ); + MOV32ItoM((int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], g_cpuConstRegs[gprreg].UL[0]); + MOV32ItoM((int)&cpuRegs.GPR.r[ gprreg ].UL[ 1 ], g_cpuConstRegs[gprreg].UL[1]); + } + + MOV32ItoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); + } + else if( bit == 64 ) { + if( !(g_cpuFlushedConstReg&(1<= 0) { + + if( xmmregs[mmreg].mode & MODE_WRITE ) { + SSEX_MOVDQA_XMM_to_M128((int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], mmreg); + } + } + else if( (mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ)) >= 0) { + if( mmxregs[mmreg].mode & MODE_WRITE ) { + MOVQRtoM((int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], mmreg); + } + } + + MOV32ItoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); + } + else if( bit == 64 ) { + // sd + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ)) >= 0) { + + if( xmmregs[mmreg].mode & MODE_WRITE ) { + SSE_MOVLPS_XMM_to_M64((int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], mmreg); + } + } + else if( (mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ)) >= 0) { + if( mmxregs[mmreg].mode & MODE_WRITE ) { + MOVQRtoM((int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ], mmreg); + SetMMXstate(); + } + } + + MOV32ItoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); + } + else { + // sb, sh, sw + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, gprreg, MODE_READ)) >= 0 && (xmmregs[mmreg].mode&MODE_WRITE) ) { + SSE2_MOVD_XMM_to_R(EAX, mmreg); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ)) >= 0 && (mmxregs[mmreg].mode&MODE_WRITE)) { + MOVD32MMXtoR(EAX, mmreg); + SetMMXstate(); + } + else { + switch(bit) { + case 8: MOV8MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); break; + case 16: MOV16MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); break; + case 32: MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ gprreg ].UL[ 0 ]); break; + } + } + } + } + + if( offset != 0 ) ADD32ItoR(ECX, offset); + + // some type of hardware write + switch(bit) { + case 8: CALLFunc( (int)recMemWrite8 ); break; + case 16: CALLFunc( (int)recMemWrite16 ); break; + case 32: CALLFunc( (int)recMemWrite32 ); break; + case 64: CALLFunc( (int)recMemWrite64 ); break; + case 128: CALLFunc( (int)recMemWrite128 ); break; + } +} + +int _eePrepConstWrite128(int gprreg) +{ + int mmreg = 0; + + if( GPR_IS_CONST1(gprreg) ) { + if( gprreg ) { + mmreg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(mmreg, (u32)&cpuRegs.GPR.r[gprreg].UL[2]); + _freeMMXreg(mmreg); + mmreg |= (gprreg<<16)|MEM_EECONSTTAG; + } + else { + mmreg = _allocTempXMMreg(XMMT_INT, -1); + SSEX_PXOR_XMM_to_XMM(mmreg, mmreg); + _freeXMMreg(mmreg); + mmreg |= MEM_XMMTAG; + } + } + else { + if( (mmreg = _checkMMXreg(MMX_GPR+gprreg, MODE_READ)) >= 0 ) { + int mmregtemp = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(mmregtemp, (u32)&cpuRegs.GPR.r[gprreg].UL[2]); + mmreg |= (mmregtemp<<4)|MEM_MMXTAG; + _freeMMXreg(mmregtemp); + } + else mmreg = _allocGPRtoXMMreg(-1, gprreg, MODE_READ)|MEM_XMMTAG; + } + + return mmreg; +} + +void recStore(int bit, u32 imm, int align) +{ + int mmreg; + +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + u32 addr = g_cpuConstRegs[_Rs_].UL[0]+imm; + int doclear = 0; + switch(bit) { + case 8: + if( GPR_IS_CONST1(_Rt_) ) doclear = recMemConstWrite8(addr, MEM_EECONSTTAG|(_Rt_<<16)); + else { + _eeMoveGPRtoR(EAX, _Rt_); + doclear = recMemConstWrite8(addr, EAX); + } + + if( doclear ) { + recMemConstClear((addr)&~3, 1); + } + + break; + case 16: + assert( (addr)%2 == 0 ); + if( GPR_IS_CONST1(_Rt_) ) doclear = recMemConstWrite16(addr, MEM_EECONSTTAG|(_Rt_<<16)); + else { + _eeMoveGPRtoR(EAX, _Rt_); + doclear = recMemConstWrite16(addr, EAX); + } + + if( doclear ) { + recMemConstClear((addr)&~3, 1); + } + + break; + case 32: + // used by SWL/SWR + //assert( (addr)%4 == 0 ); + if( GPR_IS_CONST1(_Rt_) ) doclear = recMemConstWrite32(addr, MEM_EECONSTTAG|(_Rt_<<16)); + else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ)) >= 0 ) { + doclear = recMemConstWrite32(addr, mmreg|MEM_XMMTAG|(_Rt_<<16)); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_READ)) >= 0 ) { + doclear = recMemConstWrite32(addr, mmreg|MEM_MMXTAG|(_Rt_<<16)); + } + else { + _eeMoveGPRtoR(EAX, _Rt_); + doclear = recMemConstWrite32(addr, EAX); + } + + if( doclear ) { + recMemConstClear((addr)&~3, 1); + } + break; + case 64: + { + //assert( (addr)%8 == 0 ); + int mask = align ? ~7 : ~0; + + if( GPR_IS_CONST1(_Rt_) ) doclear = recMemConstWrite64(addr, MEM_EECONSTTAG|(_Rt_<<16)); + else if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ)) >= 0 ) { + doclear = recMemConstWrite64(addr&mask, mmreg|MEM_XMMTAG|(_Rt_<<16)); + } + else { + mmreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); + doclear = recMemConstWrite64(addr&mask, mmreg|MEM_MMXTAG|(_Rt_<<16)); + } + + if( doclear ) { + recMemConstClear((addr)&~7, 2); + } + + break; + } + case 128: + //assert( (addr)%16 == 0 ); + + if( recMemConstWrite128((addr)&~15, _eePrepConstWrite128(_Rt_)) ) { + CMP32ItoM((u32)&maxrecmem, addr); + j8Ptr[0] = JB8(0); + recMemConstClear((addr)&~15, 4); + x86SetJ8(j8Ptr[0]); + } + + break; + } + } + else +#endif + { + int dohw; + int mmregs; + + if( GPR_IS_CONST1( _Rs_ ) ) { + _flushConstReg(_Rs_); + } + + mmregs = _eePrepareReg(_Rs_); + dohw = recSetMemLocation(_Rs_, imm, mmregs, align ? bit/64 : 0, 0); + + recStore_raw(g_pCurInstInfo, bit, EAX, _Rt_, s_nAddMemOffset); + + if( s_nAddMemOffset ) ADD32ItoR(ECX, s_nAddMemOffset); + CMP32MtoR(ECX, (u32)&maxrecmem); + + if( s_bCachingMem & 2 ) j32Ptr[4] = JAE32(0); + else j8Ptr[1] = JAE8(0); + + if( bit < 32 || !align ) AND8ItoR(ECX, 0xfc); + if( bit <= 32 ) CALLFunc((uptr)recWriteMemClear32); + else if( bit == 64 ) CALLFunc((uptr)recWriteMemClear64); + else CALLFunc((uptr)recWriteMemClear128); + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[5] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + recStore_call(bit, _Rt_, s_nAddMemOffset); + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[5]); + else x86SetJ8(j8Ptr[2]); + } + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[1]); + } + + _clearNeededMMXregs(); // needed since allocing + _clearNeededXMMregs(); // needed since allocing +} + + +void recSB( void ) { recStore(8, _Imm_, 1); } +void recSH( void ) { recStore(16, _Imm_, 1); } +void recSW( void ) { recStore(32, _Imm_, 1); } + +//////////////////////////////////////////////////// +void recSWL( void ) +{ +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + int shift = (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&3; + + recMemConstRead32(EAX, (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3); + + _eeMoveGPRtoR(ECX, _Rt_); + AND32ItoR(EAX, 0xffffff00<<(shift*8)); + SHR32ItoR(ECX, 24-shift*8); + OR32RtoR(EAX, ECX); + + if( recMemConstWrite32((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3, EAX) ) + recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3, 1); + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); + + MOV32ItoR(EDX, 0x3); + AND32RtoR(EDX, ECX); + AND32ItoR(ECX, ~3); + SHL32ItoR(EDX, 3); // *8 + PUSH32R(ECX); + XOR32RtoR(EDI, EDI); + + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + + if( dohw ) { + j8Ptr[1] = JMP8(0); + SET_HWLOC_R5900(); + + // repeat + MOV32ItoR(EDX, 0x3); + AND32RtoR(EDX, ECX); + AND32ItoR(ECX, ~3); + SHL32ItoR(EDX, 3); // *8 + + PUSH32R(ECX); + PUSH32R(EDX); + CALLFunc( (int)recMemRead32 ); + POP32R(EDX); + MOV8ItoR(EDI, 0xff); + + x86SetJ8(j8Ptr[1]); + } + + _eeMoveGPRtoR(EBX, _Rt_); + + // oldmem is in EAX + // mem >> SWL_SHIFT[shift] + MOV32ItoR(ECX, 24); + SUB32RtoR(ECX, EDX); + SHR32CLtoR(EBX); + + // mov temp and compute _rt_ & SWL_MASK[shift] + MOV32RtoR(ECX, EDX); + MOV32ItoR(EDX, 0xffffff00); + SHL32CLtoR(EDX); + AND32RtoR(EAX, EDX); + + // combine + OR32RtoR(EAX, EBX); + + POP32R(ECX); + + // read the old mem again + TEST32RtoR(EDI, EDI); + j8Ptr[0] = JNZ8(0); + + // manual write + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); + + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + + CALLFunc( (int)recMemWrite32 ); + + x86SetJ8(j8Ptr[1]); + } +} + +//////////////////////////////////////////////////// +void recSWR( void ) +{ +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + int shift = (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&3; + + recMemConstRead32(EAX, (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3); + + _eeMoveGPRtoR(ECX, _Rt_); + AND32ItoR(EAX, 0x00ffffff>>(24-shift*8)); + SHL32ItoR(ECX, shift*8); + OR32RtoR(EAX, ECX); + + if( recMemConstWrite32((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3, EAX) ) + recMemConstClear((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~3, 1); + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); + + MOV32ItoR(EDX, 0x3); + AND32RtoR(EDX, ECX); + AND32ItoR(ECX, ~3); + SHL32ItoR(EDX, 3); // *8 + + PUSH32R(ECX); + XOR32RtoR(EDI, EDI); + + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + + if( dohw ) { + j8Ptr[1] = JMP8(0); + SET_HWLOC_R5900(); + + // repeat + MOV32ItoR(EDX, 0x3); + AND32RtoR(EDX, ECX); + AND32ItoR(ECX, ~3); + SHL32ItoR(EDX, 3); // *8 + + PUSH32R(ECX); + PUSH32R(EDX); + CALLFunc( (int)recMemRead32 ); + POP32R(EDX); + MOV8ItoR(EDI, 0xff); + + x86SetJ8(j8Ptr[1]); + } + + _eeMoveGPRtoR(EBX, _Rt_); + + // oldmem is in EAX + // mem << SWR_SHIFT[shift] + MOV32RtoR(ECX, EDX); + SHL32CLtoR(EBX); + + // mov temp and compute _rt_ & SWR_MASK[shift] + MOV32ItoR(ECX, 24); + SUB32RtoR(ECX, EDX); + MOV32ItoR(EDX, 0x00ffffff); + SHR32CLtoR(EDX); + AND32RtoR(EAX, EDX); + + // combine + OR32RtoR(EAX, EBX); + + POP32R(ECX); + + // read the old mem again + TEST32RtoR(EDI, EDI); + j8Ptr[0] = JNZ8(0); + + // manual write + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); + + j8Ptr[1] = JMP8(0); + x86SetJ8(j8Ptr[0]); + + CALLFunc( (int)recMemWrite32 ); + + x86SetJ8(j8Ptr[1]); + } +} + +void recSD( void ) { recStore(64, _Imm_, 1); } + +//////////////////////////////////////////////////// +void recSDR( void ) +{ + iFlushCall(FLUSH_NOCONST); + + if( GPR_IS_CONST1( _Rs_ ) ) { + // flush temporarily + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); + //MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); + } + + if( GPR_IS_CONST1( _Rt_ ) && !(g_cpuFlushedConstReg&(1<<_Rt_)) ) { + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0]); + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1]); + g_cpuFlushedConstReg |= (1<<_Rt_); + } + + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)R5900::Interpreter::OpcodeImpl::SDR ); +} + +//////////////////////////////////////////////////// +void recSDL( void ) +{ + iFlushCall(FLUSH_NOCONST); + + if( GPR_IS_CONST1( _Rs_ ) ) { + // flush temporarily + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); + //MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); + } + + if( GPR_IS_CONST1( _Rt_ ) && !(g_cpuFlushedConstReg&(1<<_Rt_)) ) { + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0]); + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1]); + g_cpuFlushedConstReg |= (1<<_Rt_); + } + + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)R5900::Interpreter::OpcodeImpl::SDL ); +} + +//////////////////////////////////////////////////// +void recSQ( void ) { recStore(128, _Imm_, 1); } + +/********************************************************* +* Load and store for COP1 * +* Format: OP rt, offset(base) * +*********************************************************/ + +//////////////////////////////////////////////////// +void recLWC1( void ) +{ +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + int mmreg; + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 4 == 0 ); + + mmreg = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE); + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG; + else mmreg = EAX; + + if( recMemConstRead32(mmreg, g_cpuConstRegs[_Rs_].UL[0]+_Imm_) ) { + if( mmreg&MEM_XMMTAG ) xmmregs[mmreg&0xf].inuse = 0; + mmreg = EAX; + } + + if( !(mmreg&MEM_XMMTAG) ) + MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); + } + else +#endif + { + int dohw; + int regt = _allocCheckFPUtoXMM(g_pCurInstInfo, _Rt_, MODE_WRITE); + int mmregs = _eePrepareReg(_Rs_); + + _deleteMMXreg(MMX_FPU+_Rt_, 2); + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); + + if( regt >= 0 ) { + SSEX_MOVD_RmOffset_to_XMM(regt, ECX, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + MOV32RmtoROffset(EAX, ECX, PS2MEM_BASE_+s_nAddMemOffset); + MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + iMemRead32Check(); + CALLFunc( (int)recMemRead32 ); + + if( regt >= 0 ) SSE2_MOVD_R_to_XMM(regt, EAX); + else MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + } +} + +//////////////////////////////////////////////////// +void recSWC1( void ) +{ + int mmreg; + +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)%4 == 0 ); + + mmreg = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ); + + if( mmreg >= 0 ) mmreg |= MEM_XMMTAG|(_Rt_<<16); + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + mmreg = EAX; + } + + recMemConstWrite32(g_cpuConstRegs[_Rs_].UL[0]+_Imm_, mmreg); + } + else +#endif + { + int dohw; + int mmregs = _eePrepareReg(_Rs_); + + assert( _checkMMXreg(MMX_FPU+_Rt_, MODE_READ) == -1 ); + + mmreg = _checkXMMreg(XMMTYPE_FPREG, _Rt_, MODE_READ); + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 0, 0); + + if( mmreg >= 0) { + SSEX_MOVD_XMM_to_RmOffset(ECX, mmreg, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); + } + + if( dohw ) { + if( s_bCachingMem & 2 ) j32Ptr[4] = JMP32(0); + else j8Ptr[2] = JMP8(0); + + SET_HWLOC_R5900(); + + // some type of hardware write + if( mmreg >= 0) SSE2_MOVD_XMM_to_R(EAX, mmreg); + else MOV32MtoR(EAX, (int)&fpuRegs.fpr[ _Rt_ ].UL); + + CALLFunc( (int)recMemWrite32 ); + + if( s_bCachingMem & 2 ) x86SetJ32(j32Ptr[4]); + else x86SetJ8(j8Ptr[2]); + } + } +} + +//////////////////////////////////////////////////// + +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +void recLQC2( void ) +{ + int mmreg; + +#ifdef REC_SLOWREAD + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_) % 16 == 0 ); + + if( _Ft_ ) mmreg = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_WRITE); + else mmreg = _allocTempXMMreg(XMMT_FPS, -1); + recMemConstRead128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg); + + if( !_Ft_ ) _freeXMMreg(mmreg); + } + else +#endif + { + int dohw, mmregs; + + if( GPR_IS_CONST1( _Rs_ ) ) { + _flushConstReg(_Rs_); + } + + mmregs = _eePrepareReg(_Rs_); + + if( _Ft_ ) mmreg = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_WRITE); + + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0); + + if( _Ft_ ) { + u8* rawreadptr = x86Ptr; + + if( mmreg >= 0 ) { + SSEX_MOVDQARmtoROffset(mmreg, ECX, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + _recMove128RmOffsettoM((u32)&VU0.VF[_Ft_].UL[0], PS2MEM_BASE_+s_nAddMemOffset); + } + + if( dohw ) { + j8Ptr[1] = JMP8(0); + SET_HWLOC_R5900(); + + // check if writing to VUs + CMP32ItoR(ECX, 0x11000000); + JAE8(rawreadptr - (x86Ptr+2)); + + PUSH32I( (int)&VU0.VF[_Ft_].UD[0] ); + CALLFunc( (int)recMemRead128 ); + if( mmreg >= 0 ) SSEX_MOVDQA_M128_to_XMM(mmreg, (int)&VU0.VF[_Ft_].UD[0] ); + ADD32ItoR(ESP, 4); + + x86SetJ8(j8Ptr[1]); + } + } + else { + if( dohw ) { + j8Ptr[1] = JMP8(0); + SET_HWLOC_R5900(); + + PUSH32I( (int)&retValues[0] ); + CALLFunc( (int)recMemRead128 ); + ADD32ItoR(ESP, 4); + + x86SetJ8(j8Ptr[1]); + } + } + } + + _clearNeededXMMregs(); // needed since allocing +} + +//////////////////////////////////////////////////// +void recSQC2( void ) +{ + int mmreg; + +#ifdef REC_SLOWWRITE + _flushConstReg(_Rs_); +#else + if( GPR_IS_CONST1( _Rs_ ) ) { + assert( (g_cpuConstRegs[_Rs_].UL[0]+_Imm_)%16 == 0 ); + + mmreg = _allocVFtoXMMreg(&VU0, -1, _Ft_, MODE_READ)|MEM_XMMTAG; + recMemConstWrite128((g_cpuConstRegs[_Rs_].UL[0]+_Imm_)&~15, mmreg); + } + else +#endif + { + u8* rawreadptr; + int dohw, mmregs; + + if( GPR_IS_CONST1( _Rs_ ) ) { + _flushConstReg(_Rs_); + } + + mmregs = _eePrepareReg(_Rs_); + dohw = recSetMemLocation(_Rs_, _Imm_, mmregs, 2, 0); + + rawreadptr = x86Ptr; + + if( (mmreg = _checkXMMreg(XMMTYPE_VFREG, _Ft_, MODE_READ)) >= 0) { + SSEX_MOVDQARtoRmOffset(ECX, mmreg, PS2MEM_BASE_+s_nAddMemOffset); + } + else { + if( _hasFreeXMMreg() ) { + mmreg = _allocTempXMMreg(XMMT_FPS, -1); + SSEX_MOVDQA_M128_to_XMM(mmreg, (int)&VU0.VF[_Ft_].UD[0]); + SSEX_MOVDQARtoRmOffset(ECX, mmreg, PS2MEM_BASE_+s_nAddMemOffset); + _freeXMMreg(mmreg); + } + else if( _hasFreeMMXreg() ) { + mmreg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(mmreg, (int)&VU0.VF[_Ft_].UD[0]); + MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+s_nAddMemOffset); + MOVQMtoR(mmreg, (int)&VU0.VF[_Ft_].UL[2]); + MOVQRtoRmOffset(ECX, mmreg, PS2MEM_BASE_+s_nAddMemOffset+8); + SetMMXstate(); + _freeMMXreg(mmreg); + } + else { + MOV32MtoR(EAX, (int)&VU0.VF[_Ft_].UL[0]); + MOV32MtoR(EDX, (int)&VU0.VF[_Ft_].UL[1]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+4); + MOV32MtoR(EAX, (int)&VU0.VF[_Ft_].UL[2]); + MOV32MtoR(EDX, (int)&VU0.VF[_Ft_].UL[3]); + MOV32RtoRmOffset(ECX, EAX, PS2MEM_BASE_+s_nAddMemOffset+8); + MOV32RtoRmOffset(ECX, EDX, PS2MEM_BASE_+s_nAddMemOffset+12); + } + } + + if( dohw ) { + j8Ptr[1] = JMP8(0); + + SET_HWLOC_R5900(); + + // check if writing to VUs + CMP32ItoR(ECX, 0x11000000); + JAE8(rawreadptr - (x86Ptr+2)); + + // some type of hardware write + if( (mmreg = _checkXMMreg(XMMTYPE_VFREG, _Ft_, MODE_READ)) >= 0) { + + if( xmmregs[mmreg].mode & MODE_WRITE ) { + SSEX_MOVDQA_XMM_to_M128((int)&VU0.VF[_Ft_].UD[0], mmreg); + } + } + + MOV32ItoR(EAX, (int)&VU0.VF[_Ft_].UD[0]); + CALLFunc( (int)recMemWrite128 ); + + x86SetJ8A(j8Ptr[1]); + } + } +} + +#else + +using namespace Interpreter::OpcodeImpl; + +PCSX2_ALIGNED16(u32 dummyValue[4]); + +void SetFastMemory(int bSetFast) +{ + // nothing +} + +void recLoad64( u32 bits, bool sign ) +{ + jASSUME( bits == 64 || bits == 128 ); + + //no int 3? i love to get my hands dirty ;p - Raz + //write8(0xCC); + + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + + EEINST_RESETSIGNEXT(_Rt_); // remove the sign extension -> what does this really do ? + + _deleteEEreg(_Rt_, 0); + + // Load ECX with the source memory address that we're reading from. + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + ADD32ItoR( ECX, _Imm_ ); + + if( bits == 128 ) // force 16 byte alignment on 128 bit reads + AND32I8toR(ECX,0xF0); + + // Load EDX with the destination. 64/128 bit modes load the result directly into + // the cpuRegs.GPR struct. + + if ( _Rt_ ) + MOV32ItoR(EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + else + MOV32ItoR(EDX, (int)&dummyValue[0] ); + + vtlb_DynGenRead64(bits); +} + +void recLoad32(u32 bits,bool sign) +{ + jASSUME( bits <= 32 ); + + //no int 3? i love to get my hands dirty ;p - Raz + //write8(0xCC); + + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + // Load ECX with the source memory address that we're reading from. + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + ADD32ItoR( ECX, _Imm_ ); + + // 8/16/32 bit modes return the loaded value in EAX. + //MOV32ItoR(EDX, (int)&dummyValue[0] ); + + vtlb_DynGenRead32(bits, sign); + + if ( _Rt_ ) + { + // Perform sign extension if needed + + //MOV32MtoR( EAX, (int)&dummyValue[0] ); //ewww, lame ! movsx /zx has r/m forms too ... + /*if (bits==8) + { + if (sign) + //MOVSX32M8toR( EAX, (int)&dummyValue[0] ); + MOVSX32R8toR( EAX, EAX ); + //else + //MOVZX32M8toR( EAX, (int)&dummyValue[0] ); + //MOVZX32R8toR( EAX, EAX ); + } + else if (bits==16) + { + if (sign) + //MOVSX32M16toR( EAX, (int)&dummyValue[0] ); + MOVSX32R16toR( EAX, EAX ); + //else + //MOVZX32M16toR( EAX, (int)&dummyValue[0] ); + //MOVZX32R16toR( EAX, EAX ); + }*/ + + if (sign) + CDQ(); + else + XOR32RtoR(EDX,EDX); + + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); + } +} + +//////////////////////////////////////////////////// +void recLB( void ) +{ + recLoad32(8,true); + /* + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + PUSH32I( (int)&dummyValue[0] ); + PUSH32R( EAX ); + + CALLFunc( (int)memRead8 ); + ADD32ItoR( ESP, 8 ); + if ( _Rt_ ) + { + u8* linkEnd; + TEST32RtoR( EAX, EAX ); + linkEnd = JNZ8( 0 ); + MOV32MtoR( EAX, (int)&dummyValue[0] ); + MOVSX32R8toR( EAX, EAX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); + x86SetJ8( linkEnd ); + } + */ +} + +//////////////////////////////////////////////////// +void recLBU( void ) +{ + recLoad32(8,false); + /* + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + PUSH32I( (int)&dummyValue[0] ); + PUSH32R( EAX ); + + CALLFunc( (int)memRead8 ); + ADD32ItoR( ESP, 8 ); + if ( _Rt_ ) + { + u8* linkEnd; + TEST32RtoR( EAX, EAX ); + linkEnd = JNZ8( 0 ); + MOV32MtoR( EAX, (int)&dummyValue[0] ); + MOVZX32R8toR( EAX, EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + x86SetJ8( linkEnd ); + } + */ +} + +//////////////////////////////////////////////////// +void recLH( void ) +{ + recLoad32(16,true); + /* + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + PUSH32I( (int)&dummyValue[0] ); + PUSH32R( EAX ); + + CALLFunc( (int)memRead16 ); + ADD32ItoR( ESP, 8 ); + if ( _Rt_ ) + { + u8* linkEnd; + TEST32RtoR( EAX, EAX ); + linkEnd = JNZ8( 0 ); + MOV32MtoR( EAX, (int)&dummyValue[0]); + MOVSX32R16toR( EAX, EAX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); + x86SetJ8( linkEnd ); + } + */ +} + +//////////////////////////////////////////////////// +void recLHU( void ) +{ + recLoad32(16,false); + /* + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + PUSH32I( (int)&dummyValue[0] ); + PUSH32R( EAX ); + CALLFunc( (int)memRead16 ); + ADD32ItoR( ESP, 8 ); + if ( _Rt_ ) + { + u8* linkEnd; + TEST32RtoR( EAX, EAX ); + linkEnd = JNZ8( 0 ); + MOV32MtoR( EAX, (int)&dummyValue[0] ); + MOVZX32R16toR( EAX, EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + x86SetJ8( linkEnd ); + }*/ +} + +//////////////////////////////////////////////////// +void recLW( void ) +{ + recLoad32(32,true); + /* + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + + PUSH32I( (int)&dummyValue[0]); + PUSH32R( EAX ); + + CALLFunc( (int)memRead32 ); + ADD32ItoR( ESP, 8 ); + + if ( _Rt_ ) + { + u8* linkEnd; + TEST32RtoR( EAX, EAX ); + linkEnd = JNZ8( 0 ); + MOV32MtoR( EAX, (int)&dummyValue[0]); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX ); + x86SetJ8( linkEnd ); + }*/ +} + +//////////////////////////////////////////////////// +void recLWU( void ) +{ + recLoad32(32,false); + /* + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + + PUSH32I( (int)&dummyValue[0]); + PUSH32R( EAX ); + CALLFunc( (int)memRead32 ); + ADD32ItoR( ESP, 8 ); + if ( _Rt_ ) + { + u8* linkEnd; + TEST32RtoR( EAX, EAX ); + linkEnd = JNZ8( 0 ); + MOV32MtoR( EAX, (int)&dummyValue[0]); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); + x86SetJ8( linkEnd ); + } + */ +} + +//////////////////////////////////////////////////// +void recLWL( void ) +{ + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + _deleteEEreg(_Rt_, 0); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)LWL ); +} + +//////////////////////////////////////////////////// +void recLWR( void ) +{ + iFlushCall(FLUSH_EVERYTHING); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)LWR ); +} + +//////////////////////////////////////////////////// +extern void MOV64RmtoR( x86IntRegType to, x86IntRegType from ); + +void recLD( void ) +{ + recLoad64(64,false); + /* + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + EEINST_RESETSIGNEXT(_Rt_); // remove the sign extension + _deleteEEreg(_Rt_, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + + if ( _Rt_ ) + { + PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + } + else + { + PUSH32I( (int)&dummyValue[0] ); + } + PUSH32R( EAX ); + CALLFunc( (int)memRead64 ); + ADD32ItoR( ESP, 8 ); + */ +} + +//////////////////////////////////////////////////// +void recLDL( void ) +{ + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + EEINST_RESETSIGNEXT(_Rt_); // remove the sign extension + _deleteEEreg(_Rt_, 0); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)LDL ); +} + +//////////////////////////////////////////////////// +void recLDR( void ) +{ + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + EEINST_RESETSIGNEXT(_Rt_); // remove the sign extension + _deleteEEreg(_Rt_, 0); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)LDR ); +} + +//////////////////////////////////////////////////// +void recLQ( void ) +{ + recLoad64(128,false); +/* + _deleteEEreg(_Rs_, 1); + _eeOnLoadWrite(_Rt_); + EEINST_RESETSIGNEXT(_Rt_); // remove the sign extension + _deleteEEreg(_Rt_, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_); + } + AND32ItoR( EAX, ~0xf ); + + if ( _Rt_ ) + { + PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + } + else + { + PUSH32I( (int)&dummyValue[0] ); + } + PUSH32R( EAX ); + CALLFunc( (int)memRead128 ); + ADD32ItoR( ESP, 8 ); + */ +} +void recStore(u32 sz) +{ + //no int 3? i love to get my hands dirty ;p - Raz + //write8(0xCC); + + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( ECX, _Imm_); + } + if (sz==128) + { + AND32I8toR(ECX,0xF0); + } + + if (sz<64) + { + if (_Rt_) + MOV32MtoR(EDX,(int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + else + XOR32RtoR(EDX,EDX); + } + else if (sz==128 || sz==64) + { + MOV32ItoR(EDX,(int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); + } + + + vtlb_DynGenWrite(sz); + + /* + if (sz==8) + CALLFunc( (int)memWrite8 ); + else if (sz==16) + CALLFunc( (int)memWrite16 ); + else if (sz==32) + CALLFunc( (int)memWrite32 ); + else if (sz==64) + CALLFunc( (int)memWrite64 ); + else if (sz==128) + CALLFunc( (int)memWrite128 ); + */ +} +//////////////////////////////////////////////////// +void recSB( void ) +{ + recStore(8); + /* + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_); + } + PUSH32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + PUSH32R( EAX ); + CALLFunc( (int)memWrite8 ); + ADD32ItoR( ESP, 8 ); + */ +} + +//////////////////////////////////////////////////// +void recSH( void ) +{ + recStore(16); + /* + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + PUSH32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + PUSH32R( EAX ); + CALLFunc( (int)memWrite16 ); + ADD32ItoR( ESP, 8 ); + */ +} + +//////////////////////////////////////////////////// +void recSW( void ) +{ + recStore(32); + /* + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + + PUSH32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + PUSH32R( EAX ); + CALLFunc( (int)memWrite32 ); + ADD32ItoR( ESP, 8 ); + */ +} + +//////////////////////////////////////////////////// +void recSWL( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)SWL ); +} + +//////////////////////////////////////////////////// +void recSWR( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)SWR ); +} + +//////////////////////////////////////////////////// +void recSD( void ) +{ + recStore(64); + /* + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + + PUSH32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + PUSH32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + PUSH32R( EAX ); + CALLFunc( (int)memWrite64 ); + ADD32ItoR( ESP, 12 ); + */ +} + +//////////////////////////////////////////////////// +void recSDL( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)SDL ); +} + +//////////////////////////////////////////////////// +void recSDR( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + MOV32ItoM( (int)&cpuRegs.code, cpuRegs.code ); + MOV32ItoM( (int)&cpuRegs.pc, pc ); + CALLFunc( (int)SDR ); +} + +//////////////////////////////////////////////////// +void recSQ( void ) +{ + recStore(128); + /* + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + { + ADD32ItoR( EAX, _Imm_ ); + } + AND32ItoR( EAX, ~0xf ); + + PUSH32I( (int)&cpuRegs.GPR.r[ _Rt_ ].UD[ 0 ] ); + PUSH32R( EAX ); + CALLFunc( (int)memWrite128 ); + ADD32ItoR( ESP, 8 );*/ +} + +/********************************************************* +* Load and store for COP1 * +* Format: OP rt, offset(base) * +*********************************************************/ + +//////////////////////////////////////////////////// +void recLWC1( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteFPtoXMMreg(_Rt_, 2); + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + ADD32ItoR( ECX, _Imm_ ); + + //MOV32ItoR(EDX, (int)&fpuRegs.fpr[ _Rt_ ].UL ); //no 0 for fpu ? + //CALLFunc( (int)memRead32 ); + vtlb_DynGenRead32(32, false); + MOV32RtoM( (int)&fpuRegs.fpr[ _Rt_ ].UL, EAX ); +} + +//////////////////////////////////////////////////// +void recSWC1( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteFPtoXMMreg(_Rt_, 0); + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + ADD32ItoR( ECX, _Imm_ ); + + MOV32MtoR(EDX, (int)&fpuRegs.fpr[ _Rt_ ].UL ); + vtlb_DynGenWrite(32); +} + +//////////////////////////////////////////////////// + +/********************************************************* +* Load and store for COP2 (VU0 unit) * +* Format: OP rt, offset(base) * +*********************************************************/ + +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +void recLQC2( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteVFtoXMMreg(_Ft_, 0, 2); + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + ADD32ItoR( ECX, _Imm_); + + if ( _Rt_ ) + MOV32ItoR(EDX, (int)&VU0.VF[_Ft_].UD[0] ); + else + MOV32ItoR(EDX, (int)&dummyValue[0] ); + + vtlb_DynGenRead64(128); +} + +//////////////////////////////////////////////////// +void recSQC2( void ) +{ + _deleteEEreg(_Rs_, 1); + _deleteVFtoXMMreg(_Ft_, 0, 0); + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + if ( _Imm_ != 0 ) + ADD32ItoR( ECX, _Imm_ ); + + MOV32ItoR(EDX, (int)&VU0.VF[_Ft_].UD[0] ); + vtlb_DynGenWrite(128); +} + +#endif + +#endif + +} } } // end namespace R5900::Dynarec::OpcodeImpl + +using namespace R5900::Dynarec; +using namespace R5900::Dynarec::OpcodeImpl; + +#ifdef PCSX2_VIRTUAL_MEM + +#ifndef LOADSTORE_RECOMPILE + void SetFastMemory(int bSetFast) {} +#else + static int s_bFastMemory = 0; + void SetFastMemory(int bSetFast) + { + s_bFastMemory = bSetFast; + if( bSetFast ) { + g_MemMasks0[0] = 0x00f0; g_MemMasks0[1] = 0x80f1; g_MemMasks0[2] = 0x00f0; g_MemMasks0[3] = 0x00f1; + g_MemMasks8[0] = 0x0080; g_MemMasks8[1] = 0x8081; g_MemMasks8[2] = 0x0080; g_MemMasks8[3] = 0x0081; + g_MemMasks16[0] = 0x0000; g_MemMasks16[1] = 0x8001; g_MemMasks16[2] = 0x0000; g_MemMasks16[3] = 0x0001; + } + else { + g_MemMasks0[0] = 0x00f0; g_MemMasks0[1] = 0x80f1; g_MemMasks0[2] = 0x00f2; g_MemMasks0[3] = 0x00f3; + g_MemMasks8[0] = 0x0080; g_MemMasks8[1] = 0x8081; g_MemMasks8[2] = 0x0082; g_MemMasks8[3] = 0x0083; + g_MemMasks16[0] = 0x0000; g_MemMasks16[1] = 0x8001; g_MemMasks16[2] = 0x0002; g_MemMasks16[3] = 0x0003; + } + } +#endif + +#else // VTLB version + + void SetFastMemory(int bSetFast) {} + +#endif diff --git a/pcsx2/x86/ix86-32/iR5900Move.cpp b/pcsx2/x86/ix86-32/iR5900Move.cpp index e2a82d71d3..ce80ea252c 100644 --- a/pcsx2/x86/ix86-32/iR5900Move.cpp +++ b/pcsx2/x86/ix86-32/iR5900Move.cpp @@ -1,825 +1,825 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "R5900OpcodeTables.h" -#include "ix86/ix86.h" -#include "iR5900.h" - - -#ifdef _WIN32 -#pragma warning(disable:4244) -#pragma warning(disable:4761) -#endif - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl -{ - -/********************************************************* -* Shift arithmetic with constant shift * -* Format: OP rd, rt, sa * -*********************************************************/ -#ifndef MOVE_RECOMPILE - -namespace Interp = R5900::Interpreter::OpcodeImpl; - -REC_FUNC_DEL(LUI,_Rt_); -REC_FUNC(MFLO); -REC_FUNC(MFHI); -REC_FUNC(MTLO); -REC_FUNC(MTHI); - -REC_FUNC( MFHI1 ); -REC_FUNC( MFLO1 ); -REC_FUNC( MTHI1 ); -REC_FUNC( MTLO1 ); - -REC_FUNC(MOVZ); -REC_FUNC(MOVN); - -#elif defined(EE_CONST_PROP) - -/********************************************************* -* Load higher 16 bits of the first word in GPR with imm * -* Format: OP rt, immediate * -*********************************************************/ - -//// LUI -void recLUI() -{ - int mmreg; - if(!_Rt_) return; - - _eeOnWriteReg(_Rt_, 1); - - if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_WRITE)) >= 0 ) { - if( xmmregs[mmreg].mode & MODE_WRITE ) { - SSE_MOVHPS_XMM_to_M64((u32)&cpuRegs.GPR.r[_Rt_].UL[2], mmreg); - } - xmmregs[mmreg].inuse = 0; - } - - _deleteEEreg(_Rt_, 0); - GPR_SET_CONST(_Rt_); - g_cpuConstRegs[_Rt_].UD[0] = (s32)(cpuRegs.code << 16); -} - -//////////////////////////////////////////////////// -void recMFHILO(int hi) -{ - int reghi, regd, xmmhilo; - if ( ! _Rd_ ) - return; - - xmmhilo = hi ? XMMGPR_HI : XMMGPR_LO; - reghi = _checkXMMreg(XMMTYPE_GPRREG, xmmhilo, MODE_READ); - - _eeOnWriteReg(_Rd_, 0); - - regd = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_READ|MODE_WRITE); - - if( reghi >= 0 ) { - if( regd >= 0 ) { - assert( regd != reghi ); - - xmmregs[regd].inuse = 0; - - SSE2_MOVQ_XMM_to_M64((u32)&cpuRegs.GPR.r[_Rd_].UL[0], reghi); - - if( xmmregs[regd].mode & MODE_WRITE ) { - SSE_MOVHPS_XMM_to_M64((u32)&cpuRegs.GPR.r[_Rd_].UL[2], regd); - } - } - else { - regd = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rd_, MODE_WRITE); - - if( regd >= 0 ) { - SSE2_MOVDQ2Q_XMM_to_MM(regd, reghi); - } - else { - _deleteEEreg(_Rd_, 0); - SSE2_MOVQ_XMM_to_M64((int)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], reghi); - } - } - } - else { - reghi = _checkMMXreg(MMX_GPR+xmmhilo, MODE_READ); - - if( reghi >= 0 ) { - - if( regd >= 0 ) { - if( EEINST_ISLIVE2(_Rd_) ) { - if( xmmregs[regd].mode & MODE_WRITE ) { - SSE_MOVHPS_XMM_to_M64((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 2 ], regd); - } - xmmregs[regd].inuse = 0; - MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], reghi); - } - else { - SetMMXstate(); - SSE2_MOVQ2DQ_MM_to_XMM(regd, reghi); - xmmregs[regd].mode |= MODE_WRITE; - } - } - else { - regd = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rd_, MODE_WRITE); - SetMMXstate(); - - if( regd >= 0 ) { - MOVQRtoR(regd, reghi); - } - else { - _deleteEEreg(_Rd_, 0); - MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], reghi); - } - } - } - else { - if( regd >= 0 ) { - if( EEINST_ISLIVE2(_Rd_) ) SSE_MOVLPS_M64_to_XMM(regd, hi ? (int)&cpuRegs.HI.UD[ 0 ] : (int)&cpuRegs.LO.UD[ 0 ]); - else SSE2_MOVQ_M64_to_XMM(regd, hi ? (int)&cpuRegs.HI.UD[ 0 ] : (int)&cpuRegs.LO.UD[ 0 ]); - } - else { - regd = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rd_, MODE_WRITE); - - if( regd >= 0 ) { - SetMMXstate(); - MOVQMtoR(regd, hi ? (int)&cpuRegs.HI.UD[ 0 ] : (int)&cpuRegs.LO.UD[ 0 ]); - } - else { - _deleteEEreg(_Rd_, 0); - MOV32MtoR( EAX, hi ? (int)&cpuRegs.HI.UL[ 0 ] : (int)&cpuRegs.LO.UL[ 0 ]); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32MtoR( EDX, hi ? (int)&cpuRegs.HI.UL[ 1 ] : (int)&cpuRegs.LO.UL[ 1 ]); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - if( EEINST_ISLIVE1(_Rd_) ) - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - else - EEINST_RESETHASLIVE1(_Rd_); - } - } - } - } -} - -void recMTHILO(int hi) -{ - int reghi, regs, xmmhilo; - u32 addrhilo; - - xmmhilo = hi ? XMMGPR_HI : XMMGPR_LO; - addrhilo = hi ? (int)&cpuRegs.HI.UD[0] : (int)&cpuRegs.LO.UD[0]; - - regs = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ); - reghi = _checkXMMreg(XMMTYPE_GPRREG, xmmhilo, MODE_READ|MODE_WRITE); - - if( reghi >= 0 ) { - if( regs >= 0 ) { - assert( reghi != regs ); - - _deleteGPRtoXMMreg(_Rs_, 0); - SSE2_PUNPCKHQDQ_XMM_to_XMM(reghi, reghi); - SSE2_PUNPCKLQDQ_XMM_to_XMM(regs, reghi); - - // swap regs - xmmregs[regs] = xmmregs[reghi]; - xmmregs[reghi].inuse = 0; - xmmregs[regs].mode |= MODE_WRITE; - - } - else { - regs = _checkMMXreg(MMX_GPR+_Rs_, MODE_READ); - - if( regs >= 0 ) { - - if( EEINST_ISLIVE2(xmmhilo) ) { - if( xmmregs[reghi].mode & MODE_WRITE ) { - SSE_MOVHPS_XMM_to_M64(addrhilo+8, reghi); - } - xmmregs[reghi].inuse = 0; - MOVQRtoM(addrhilo, regs); - } - else { - SetMMXstate(); - SSE2_MOVQ2DQ_MM_to_XMM(reghi, regs); - xmmregs[reghi].mode |= MODE_WRITE; - } - } - else { - _flushConstReg(_Rs_); - SSE_MOVLPS_M64_to_XMM(reghi, (int)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ]); - xmmregs[reghi].mode |= MODE_WRITE; - } - } - } - else { - reghi = _allocCheckGPRtoMMX(g_pCurInstInfo, xmmhilo, MODE_WRITE); - - if( reghi >= 0 ) { - if( regs >= 0 ) { - //SetMMXstate(); - SSE2_MOVDQ2Q_XMM_to_MM(reghi, regs); - } - else { - regs = _checkMMXreg(MMX_GPR+_Rs_, MODE_WRITE); - - if( regs >= 0 ) { - SetMMXstate(); - MOVQRtoR(reghi, regs); - } - else { - _flushConstReg(_Rs_); - MOVQMtoR(reghi, (int)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ]); - } - } - } - else { - if( regs >= 0 ) { - SSE2_MOVQ_XMM_to_M64(addrhilo, regs); - } - else { - regs = _checkMMXreg(MMX_GPR+_Rs_, MODE_WRITE); - - if( regs >= 0 ) { - SetMMXstate(); - MOVQRtoM(addrhilo, regs); - } - else { - if( GPR_IS_CONST1(_Rs_) ) { - MOV32ItoM(addrhilo, g_cpuConstRegs[_Rs_].UL[0] ); - MOV32ItoM(addrhilo+4, g_cpuConstRegs[_Rs_].UL[1] ); - } - else { - _deleteEEreg(_Rs_, 1); - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); - MOV32RtoM( addrhilo, EAX ); - MOV32RtoM( addrhilo+4, EDX ); - } - } - } - } - } -} - -void recMFHI( void ) -{ - recMFHILO(1); -} - -void recMFLO( void ) -{ - recMFHILO(0); -} - -void recMTHI( void ) -{ - recMTHILO(1); -} - -void recMTLO( void ) -{ - recMTHILO(0); -} - -//////////////////////////////////////////////////// -void recMFHILO1(int hi) -{ - int reghi, regd, xmmhilo; - if ( ! _Rd_ ) - return; - - xmmhilo = hi ? XMMGPR_HI : XMMGPR_LO; - reghi = _checkXMMreg(XMMTYPE_GPRREG, xmmhilo, MODE_READ); - - _eeOnWriteReg(_Rd_, 0); - - regd = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_READ|MODE_WRITE); - - if( reghi >= 0 ) { - if( regd >= 0 ) { - SSEX_MOVHLPS_XMM_to_XMM(regd, reghi); - xmmregs[regd].mode |= MODE_WRITE; - } - else { - _deleteEEreg(_Rd_, 0); - SSE_MOVHPS_XMM_to_M64((int)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], reghi); - } - } - else { - if( regd >= 0 ) { - if( EEINST_ISLIVE2(_Rd_) ) { - SSE2_PUNPCKHQDQ_M128_to_XMM(regd, hi ? (int)&cpuRegs.HI.UD[ 0 ] : (int)&cpuRegs.LO.UD[ 0 ]); - SSE2_PSHUFD_XMM_to_XMM(regd, regd, 0x4e); - } - else { - SSE2_MOVQ_M64_to_XMM(regd, hi ? (int)&cpuRegs.HI.UD[ 1 ] : (int)&cpuRegs.LO.UD[ 1 ]); - } - - xmmregs[regd].mode |= MODE_WRITE; - } - else { - regd = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rd_, MODE_WRITE); - - if( regd >= 0 ) { - SetMMXstate(); - MOVQMtoR(regd, hi ? (int)&cpuRegs.HI.UD[ 1 ] : (int)&cpuRegs.LO.UD[ 1 ]); - } - else { - _deleteEEreg(_Rd_, 0); - MOV32MtoR( EAX, hi ? (int)&cpuRegs.HI.UL[ 2 ] : (int)&cpuRegs.LO.UL[ 2 ]); - MOV32MtoR( EDX, hi ? (int)&cpuRegs.HI.UL[ 3 ] : (int)&cpuRegs.LO.UL[ 3 ]); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - } - } - } -} - -void recMTHILO1(int hi) -{ - int reghi, regs, xmmhilo; - u32 addrhilo; - - xmmhilo = hi ? XMMGPR_HI : XMMGPR_LO; - addrhilo = hi ? (int)&cpuRegs.HI.UD[0] : (int)&cpuRegs.LO.UD[0]; - - regs = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ); - reghi = _allocCheckGPRtoXMM(g_pCurInstInfo, xmmhilo, MODE_WRITE|MODE_READ); - - if( reghi >= 0 ) { - if( regs >= 0 ) { - SSE2_PUNPCKLQDQ_XMM_to_XMM(reghi, regs); - } - else { - _deleteEEreg(_Rs_, 1); - SSE2_PUNPCKLQDQ_M128_to_XMM(reghi, (int)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ]); - } - } - else { - if( regs >= 0 ) { - SSE2_MOVQ_XMM_to_M64(addrhilo+8, regs); - } - else { - regs = _checkMMXreg(MMX_GPR+_Rs_, MODE_WRITE); - - if( regs >= 0 ) { - SetMMXstate(); - MOVQRtoM(addrhilo+8, regs); - } - else { - if( GPR_IS_CONST1(_Rs_) ) { - MOV32ItoM(addrhilo+8, g_cpuConstRegs[_Rs_].UL[0] ); - MOV32ItoM(addrhilo+12, g_cpuConstRegs[_Rs_].UL[1] ); - } - else { - _deleteEEreg(_Rs_, 1); - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); - MOV32RtoM( addrhilo+8, EAX ); - MOV32RtoM( addrhilo+12, EDX ); - } - } - } - } -} - -void recMFHI1( void ) -{ - recMFHILO1(1); -} - -void recMFLO1( void ) -{ - recMFHILO1(0); -} - -void recMTHI1( void ) -{ - recMTHILO1(1); -} - -void recMTLO1( void ) -{ - recMTHILO1(0); -} - -//// MOVZ -void recMOVZtemp_const() -{ - GPR_DEL_CONST(_Rd_); - _deleteEEreg(_Rd_, 1); - _eeOnWriteReg(_Rd_, 0); - if (g_cpuConstRegs[_Rt_].UD[0] == 0) { - MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[_Rs_].UL[0]); - MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[_Rs_].UL[1]); - } -} - -//static PCSX2_ALIGNED16(u32 s_zero[4]) = {0,0,0xffffffff, 0xffffffff}; - -void recMOVZtemp_consts(int info) -{ - if( info & PROCESS_EE_MMX ) { - - u32* mem; - int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - PXORRtoR(t0reg, t0reg); - PCMPEQDRtoR(t0reg, EEREC_T); - PMOVMSKBMMXtoR(EAX, t0reg); - CMP8ItoR(EAX, 0xff); - j8Ptr[ 0 ] = JNE8( 0 ); - - if( g_cpuFlushedConstReg & (1<<_Rs_) ) mem = &cpuRegs.GPR.r[_Rs_].UL[0]; - else { - mem = recAllocStackMem(8,8); - - mem[0] = g_cpuConstRegs[_Rs_].UL[0]; - mem[1] = g_cpuConstRegs[_Rs_].UL[1]; - } - - MOVQMtoR(EEREC_D, (u32)mem); - x86SetJ8( j8Ptr[ 0 ] ); - - _freeMMXreg(t0reg); - return; - } - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - OR32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - j8Ptr[ 0 ] = JNZ8( 0 ); - - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0] ); - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1] ); - - x86SetJ8( j8Ptr[ 0 ] ); -} - -void recMOVZtemp_constt(int info) -{ - if (g_cpuConstRegs[_Rt_].UD[0] == 0) { - if( info & PROCESS_EE_MMX ) { - if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); - return; - } - - if( _hasFreeXMMreg() ) { - int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], t0reg); - _freeMMXreg(t0reg); - } - else { - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX); - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX); - } - } -} - -void recMOVZtemp_(int info) -{ - int t0reg = -1; - - if( info & PROCESS_EE_MMX ) { - - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - PXORRtoR(t0reg, t0reg); - PCMPEQDRtoR(t0reg, EEREC_T); - PMOVMSKBMMXtoR(EAX, t0reg); - CMP8ItoR(EAX, 0xff); - j8Ptr[ 0 ] = JNE8( 0 ); - - MOVQRtoR(EEREC_D, EEREC_S); - x86SetJ8( j8Ptr[ 0 ] ); - - _freeMMXreg(t0reg); - return; - } - - if( _hasFreeXMMreg() ) - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - OR32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - j8Ptr[ 0 ] = JNZ8( 0 ); - - if( t0reg >= 0 ) { - MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], t0reg); - _freeMMXreg(t0reg); - } - else { - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX); - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX); - } - - x86SetJ8( j8Ptr[ 0 ] ); - SetMMXstate(); -} - -EERECOMPILE_CODE0(MOVZtemp, XMMINFO_READS|XMMINFO_READD|XMMINFO_READD|XMMINFO_WRITED); - -void recMOVZ() -{ - if( _Rs_ == _Rd_ ) - return; - - if( GPR_IS_CONST1(_Rd_) ) { - - if( !GPR_IS_CONST2(_Rs_, _Rt_) ) { - // remove the const, since move is conditional - _deleteEEreg(_Rd_, 0); - MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[_Rd_].UL[0]); - MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[_Rd_].UL[1]); - } - else { - if (g_cpuConstRegs[_Rt_].UD[0] == 0) { - g_cpuConstRegs[_Rd_].UL[0] = g_cpuConstRegs[_Rs_].UL[0]; - g_cpuConstRegs[_Rd_].UL[1] = g_cpuConstRegs[_Rs_].UL[1]; - } - return; - } - } - - recMOVZtemp(); -} - -//// MOVN -void recMOVNtemp_const() -{ - GPR_DEL_CONST(_Rd_); - _deleteEEreg(_Rd_, 1); - _eeOnWriteReg(_Rd_, 0); - if (g_cpuConstRegs[_Rt_].UD[0] != 0) { - MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[_Rs_].UL[0]); - MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[_Rs_].UL[1]); - } -} - -void recMOVNtemp_consts(int info) -{ - if( info & PROCESS_EE_MMX ) { - - u32* mem; - int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - PXORRtoR(t0reg, t0reg); - PCMPEQDRtoR(t0reg, EEREC_T); - - PMOVMSKBMMXtoR(EAX, t0reg); - CMP8ItoR(EAX, 0xff); - j8Ptr[ 0 ] = JE8( 0 ); - - if( g_cpuFlushedConstReg & (1<<_Rs_) ) mem = &cpuRegs.GPR.r[_Rs_].UL[0]; - else { - mem = recAllocStackMem(8,8); - - mem[0] = g_cpuConstRegs[_Rs_].UL[0]; - mem[1] = g_cpuConstRegs[_Rs_].UL[1]; - } - - MOVQMtoR(EEREC_D, (u32)mem); - x86SetJ8( j8Ptr[ 0 ] ); - - _freeMMXreg(t0reg); - return; - } - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - OR32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - j8Ptr[ 0 ] = JZ8( 0 ); - - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0] ); - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1] ); - - x86SetJ8( j8Ptr[ 0 ] ); -} - -void recMOVNtemp_constt(int info) -{ - if (g_cpuConstRegs[_Rt_].UD[0] != 0) { - if( _hasFreeXMMreg() ) { - int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], t0reg); - _freeMMXreg(t0reg); - } - else { - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX); - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX); - } - } -} - -void recMOVNtemp_(int info) -{ - int t0reg=-1; - - if( info & PROCESS_EE_MMX ) { - - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - PXORRtoR(t0reg, t0reg); - PCMPEQDRtoR(t0reg, EEREC_T); - PMOVMSKBMMXtoR(EAX, t0reg); - CMP8ItoR(EAX, 0xff); - j8Ptr[ 0 ] = JE8( 0 ); - - MOVQRtoR(EEREC_D, EEREC_S); - x86SetJ8( j8Ptr[ 0 ] ); - - _freeMMXreg(t0reg); - return; - } - - if( _hasFreeXMMreg() ) - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - OR32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - j8Ptr[ 0 ] = JZ8( 0 ); - - if( t0reg >= 0 ) { - MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], t0reg); - _freeMMXreg(t0reg); - } - else { - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); - MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX); - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX); - } - - x86SetJ8( j8Ptr[ 0 ] ); - - SetMMXstate(); -} - -EERECOMPILE_CODE0(MOVNtemp, XMMINFO_READS|XMMINFO_READD|XMMINFO_READD|XMMINFO_WRITED); - -void recMOVN() -{ - if( _Rs_ == _Rd_ ) - return; - - if( GPR_IS_CONST1(_Rd_) ) { - - if( !GPR_IS_CONST2(_Rs_, _Rt_) ) { - // remove the const, since move is conditional - _deleteEEreg(_Rd_, 0); - MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[_Rd_].UL[0]); - MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[_Rd_].UL[1]); - } - else { - if (g_cpuConstRegs[_Rt_].UD[0] != 0) { - g_cpuConstRegs[_Rd_].UL[0] = g_cpuConstRegs[_Rs_].UL[0]; - g_cpuConstRegs[_Rd_].UL[1] = g_cpuConstRegs[_Rs_].UL[1]; - } - return; - } - } - - recMOVNtemp(); -} - -#else - -//////////////////////////////////////////////////// -void recLUI( void ) -{ - if(!_Rt_) return; - if ( _Imm_ < 0 ) - { - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], (u32)_Imm_ << 16 ); //U - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0xffffffff ); //V - } - else - { - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], (u32)_Imm_ << 16 ); //U - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); //V - } -} - -//////////////////////////////////////////////////// -void recMFHI( void ) -{ - - if ( ! _Rd_ ) - { - return; - } - - MOVQMtoR( MM0, (int)&cpuRegs.HI.UD[ 0 ] ); - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], MM0 ); - SetMMXstate(); - -} - -//////////////////////////////////////////////////// -void recMFLO( void ) -{ - - if ( ! _Rd_ ) - { - return; - } - - MOVQMtoR( MM0, (int)&cpuRegs.LO.UD[ 0 ] ); - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], MM0 ); - SetMMXstate(); - -} - -//////////////////////////////////////////////////// -void recMTHI( void ) -{ - - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQRtoM( (int)&cpuRegs.HI.UD[ 0 ], MM0 ); - SetMMXstate(); - -} - -//////////////////////////////////////////////////// -void recMTLO( void ) -{ - - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); - MOVQRtoM( (int)&cpuRegs.LO.UD[ 0 ], MM0 ); - SetMMXstate(); - -} - -//////////////////////////////////////////////////// -void recMOVZ( void ) -{ - if ( ! _Rd_ ) - { - return; - } - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - OR32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - j8Ptr[ 0 ] = JNZ8( 0 ); - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - - x86SetJ8( j8Ptr[ 0 ] ); - -} - -//////////////////////////////////////////////////// -void recMOVN( void ) -{ - if ( ! _Rd_ ) - { - return; - } - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - OR32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - j8Ptr[ 0 ] = JZ8( 0 ); - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], ECX ); - - x86SetJ8( j8Ptr[ 0 ] ); - -} - -REC_FUNC( MFHI1 ); -REC_FUNC( MFLO1 ); -REC_FUNC( MTHI1 ); -REC_FUNC( MTLO1 ); - -#endif - -} } } +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "R5900OpcodeTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + + +#ifdef _WIN32 +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl +{ + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ +#ifndef MOVE_RECOMPILE + +namespace Interp = R5900::Interpreter::OpcodeImpl; + +REC_FUNC_DEL(LUI,_Rt_); +REC_FUNC(MFLO); +REC_FUNC(MFHI); +REC_FUNC(MTLO); +REC_FUNC(MTHI); + +REC_FUNC( MFHI1 ); +REC_FUNC( MFLO1 ); +REC_FUNC( MTHI1 ); +REC_FUNC( MTLO1 ); + +REC_FUNC(MOVZ); +REC_FUNC(MOVN); + +#elif defined(EE_CONST_PROP) + +/********************************************************* +* Load higher 16 bits of the first word in GPR with imm * +* Format: OP rt, immediate * +*********************************************************/ + +//// LUI +void recLUI() +{ + int mmreg; + if(!_Rt_) return; + + _eeOnWriteReg(_Rt_, 1); + + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_WRITE)) >= 0 ) { + if( xmmregs[mmreg].mode & MODE_WRITE ) { + SSE_MOVHPS_XMM_to_M64((u32)&cpuRegs.GPR.r[_Rt_].UL[2], mmreg); + } + xmmregs[mmreg].inuse = 0; + } + + _deleteEEreg(_Rt_, 0); + GPR_SET_CONST(_Rt_); + g_cpuConstRegs[_Rt_].UD[0] = (s32)(cpuRegs.code << 16); +} + +//////////////////////////////////////////////////// +void recMFHILO(int hi) +{ + int reghi, regd, xmmhilo; + if ( ! _Rd_ ) + return; + + xmmhilo = hi ? XMMGPR_HI : XMMGPR_LO; + reghi = _checkXMMreg(XMMTYPE_GPRREG, xmmhilo, MODE_READ); + + _eeOnWriteReg(_Rd_, 0); + + regd = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_READ|MODE_WRITE); + + if( reghi >= 0 ) { + if( regd >= 0 ) { + assert( regd != reghi ); + + xmmregs[regd].inuse = 0; + + SSE2_MOVQ_XMM_to_M64((u32)&cpuRegs.GPR.r[_Rd_].UL[0], reghi); + + if( xmmregs[regd].mode & MODE_WRITE ) { + SSE_MOVHPS_XMM_to_M64((u32)&cpuRegs.GPR.r[_Rd_].UL[2], regd); + } + } + else { + regd = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rd_, MODE_WRITE); + + if( regd >= 0 ) { + SSE2_MOVDQ2Q_XMM_to_MM(regd, reghi); + } + else { + _deleteEEreg(_Rd_, 0); + SSE2_MOVQ_XMM_to_M64((int)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], reghi); + } + } + } + else { + reghi = _checkMMXreg(MMX_GPR+xmmhilo, MODE_READ); + + if( reghi >= 0 ) { + + if( regd >= 0 ) { + if( EEINST_ISLIVE2(_Rd_) ) { + if( xmmregs[regd].mode & MODE_WRITE ) { + SSE_MOVHPS_XMM_to_M64((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 2 ], regd); + } + xmmregs[regd].inuse = 0; + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], reghi); + } + else { + SetMMXstate(); + SSE2_MOVQ2DQ_MM_to_XMM(regd, reghi); + xmmregs[regd].mode |= MODE_WRITE; + } + } + else { + regd = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rd_, MODE_WRITE); + SetMMXstate(); + + if( regd >= 0 ) { + MOVQRtoR(regd, reghi); + } + else { + _deleteEEreg(_Rd_, 0); + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], reghi); + } + } + } + else { + if( regd >= 0 ) { + if( EEINST_ISLIVE2(_Rd_) ) SSE_MOVLPS_M64_to_XMM(regd, hi ? (int)&cpuRegs.HI.UD[ 0 ] : (int)&cpuRegs.LO.UD[ 0 ]); + else SSE2_MOVQ_M64_to_XMM(regd, hi ? (int)&cpuRegs.HI.UD[ 0 ] : (int)&cpuRegs.LO.UD[ 0 ]); + } + else { + regd = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rd_, MODE_WRITE); + + if( regd >= 0 ) { + SetMMXstate(); + MOVQMtoR(regd, hi ? (int)&cpuRegs.HI.UD[ 0 ] : (int)&cpuRegs.LO.UD[ 0 ]); + } + else { + _deleteEEreg(_Rd_, 0); + MOV32MtoR( EAX, hi ? (int)&cpuRegs.HI.UL[ 0 ] : (int)&cpuRegs.LO.UL[ 0 ]); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32MtoR( EDX, hi ? (int)&cpuRegs.HI.UL[ 1 ] : (int)&cpuRegs.LO.UL[ 1 ]); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + else + EEINST_RESETHASLIVE1(_Rd_); + } + } + } + } +} + +void recMTHILO(int hi) +{ + int reghi, regs, xmmhilo; + u32 addrhilo; + + xmmhilo = hi ? XMMGPR_HI : XMMGPR_LO; + addrhilo = hi ? (int)&cpuRegs.HI.UD[0] : (int)&cpuRegs.LO.UD[0]; + + regs = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ); + reghi = _checkXMMreg(XMMTYPE_GPRREG, xmmhilo, MODE_READ|MODE_WRITE); + + if( reghi >= 0 ) { + if( regs >= 0 ) { + assert( reghi != regs ); + + _deleteGPRtoXMMreg(_Rs_, 0); + SSE2_PUNPCKHQDQ_XMM_to_XMM(reghi, reghi); + SSE2_PUNPCKLQDQ_XMM_to_XMM(regs, reghi); + + // swap regs + xmmregs[regs] = xmmregs[reghi]; + xmmregs[reghi].inuse = 0; + xmmregs[regs].mode |= MODE_WRITE; + + } + else { + regs = _checkMMXreg(MMX_GPR+_Rs_, MODE_READ); + + if( regs >= 0 ) { + + if( EEINST_ISLIVE2(xmmhilo) ) { + if( xmmregs[reghi].mode & MODE_WRITE ) { + SSE_MOVHPS_XMM_to_M64(addrhilo+8, reghi); + } + xmmregs[reghi].inuse = 0; + MOVQRtoM(addrhilo, regs); + } + else { + SetMMXstate(); + SSE2_MOVQ2DQ_MM_to_XMM(reghi, regs); + xmmregs[reghi].mode |= MODE_WRITE; + } + } + else { + _flushConstReg(_Rs_); + SSE_MOVLPS_M64_to_XMM(reghi, (int)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ]); + xmmregs[reghi].mode |= MODE_WRITE; + } + } + } + else { + reghi = _allocCheckGPRtoMMX(g_pCurInstInfo, xmmhilo, MODE_WRITE); + + if( reghi >= 0 ) { + if( regs >= 0 ) { + //SetMMXstate(); + SSE2_MOVDQ2Q_XMM_to_MM(reghi, regs); + } + else { + regs = _checkMMXreg(MMX_GPR+_Rs_, MODE_WRITE); + + if( regs >= 0 ) { + SetMMXstate(); + MOVQRtoR(reghi, regs); + } + else { + _flushConstReg(_Rs_); + MOVQMtoR(reghi, (int)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ]); + } + } + } + else { + if( regs >= 0 ) { + SSE2_MOVQ_XMM_to_M64(addrhilo, regs); + } + else { + regs = _checkMMXreg(MMX_GPR+_Rs_, MODE_WRITE); + + if( regs >= 0 ) { + SetMMXstate(); + MOVQRtoM(addrhilo, regs); + } + else { + if( GPR_IS_CONST1(_Rs_) ) { + MOV32ItoM(addrhilo, g_cpuConstRegs[_Rs_].UL[0] ); + MOV32ItoM(addrhilo+4, g_cpuConstRegs[_Rs_].UL[1] ); + } + else { + _deleteEEreg(_Rs_, 1); + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + MOV32RtoM( addrhilo, EAX ); + MOV32RtoM( addrhilo+4, EDX ); + } + } + } + } + } +} + +void recMFHI( void ) +{ + recMFHILO(1); +} + +void recMFLO( void ) +{ + recMFHILO(0); +} + +void recMTHI( void ) +{ + recMTHILO(1); +} + +void recMTLO( void ) +{ + recMTHILO(0); +} + +//////////////////////////////////////////////////// +void recMFHILO1(int hi) +{ + int reghi, regd, xmmhilo; + if ( ! _Rd_ ) + return; + + xmmhilo = hi ? XMMGPR_HI : XMMGPR_LO; + reghi = _checkXMMreg(XMMTYPE_GPRREG, xmmhilo, MODE_READ); + + _eeOnWriteReg(_Rd_, 0); + + regd = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_READ|MODE_WRITE); + + if( reghi >= 0 ) { + if( regd >= 0 ) { + SSEX_MOVHLPS_XMM_to_XMM(regd, reghi); + xmmregs[regd].mode |= MODE_WRITE; + } + else { + _deleteEEreg(_Rd_, 0); + SSE_MOVHPS_XMM_to_M64((int)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], reghi); + } + } + else { + if( regd >= 0 ) { + if( EEINST_ISLIVE2(_Rd_) ) { + SSE2_PUNPCKHQDQ_M128_to_XMM(regd, hi ? (int)&cpuRegs.HI.UD[ 0 ] : (int)&cpuRegs.LO.UD[ 0 ]); + SSE2_PSHUFD_XMM_to_XMM(regd, regd, 0x4e); + } + else { + SSE2_MOVQ_M64_to_XMM(regd, hi ? (int)&cpuRegs.HI.UD[ 1 ] : (int)&cpuRegs.LO.UD[ 1 ]); + } + + xmmregs[regd].mode |= MODE_WRITE; + } + else { + regd = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rd_, MODE_WRITE); + + if( regd >= 0 ) { + SetMMXstate(); + MOVQMtoR(regd, hi ? (int)&cpuRegs.HI.UD[ 1 ] : (int)&cpuRegs.LO.UD[ 1 ]); + } + else { + _deleteEEreg(_Rd_, 0); + MOV32MtoR( EAX, hi ? (int)&cpuRegs.HI.UL[ 2 ] : (int)&cpuRegs.LO.UL[ 2 ]); + MOV32MtoR( EDX, hi ? (int)&cpuRegs.HI.UL[ 3 ] : (int)&cpuRegs.LO.UL[ 3 ]); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + } + } +} + +void recMTHILO1(int hi) +{ + int reghi, regs, xmmhilo; + u32 addrhilo; + + xmmhilo = hi ? XMMGPR_HI : XMMGPR_LO; + addrhilo = hi ? (int)&cpuRegs.HI.UD[0] : (int)&cpuRegs.LO.UD[0]; + + regs = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ); + reghi = _allocCheckGPRtoXMM(g_pCurInstInfo, xmmhilo, MODE_WRITE|MODE_READ); + + if( reghi >= 0 ) { + if( regs >= 0 ) { + SSE2_PUNPCKLQDQ_XMM_to_XMM(reghi, regs); + } + else { + _deleteEEreg(_Rs_, 1); + SSE2_PUNPCKLQDQ_M128_to_XMM(reghi, (int)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ]); + } + } + else { + if( regs >= 0 ) { + SSE2_MOVQ_XMM_to_M64(addrhilo+8, regs); + } + else { + regs = _checkMMXreg(MMX_GPR+_Rs_, MODE_WRITE); + + if( regs >= 0 ) { + SetMMXstate(); + MOVQRtoM(addrhilo+8, regs); + } + else { + if( GPR_IS_CONST1(_Rs_) ) { + MOV32ItoM(addrhilo+8, g_cpuConstRegs[_Rs_].UL[0] ); + MOV32ItoM(addrhilo+12, g_cpuConstRegs[_Rs_].UL[1] ); + } + else { + _deleteEEreg(_Rs_, 1); + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + MOV32RtoM( addrhilo+8, EAX ); + MOV32RtoM( addrhilo+12, EDX ); + } + } + } + } +} + +void recMFHI1( void ) +{ + recMFHILO1(1); +} + +void recMFLO1( void ) +{ + recMFHILO1(0); +} + +void recMTHI1( void ) +{ + recMTHILO1(1); +} + +void recMTLO1( void ) +{ + recMTHILO1(0); +} + +//// MOVZ +void recMOVZtemp_const() +{ + GPR_DEL_CONST(_Rd_); + _deleteEEreg(_Rd_, 1); + _eeOnWriteReg(_Rd_, 0); + if (g_cpuConstRegs[_Rt_].UD[0] == 0) { + MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[_Rs_].UL[0]); + MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[_Rs_].UL[1]); + } +} + +//static PCSX2_ALIGNED16(u32 s_zero[4]) = {0,0,0xffffffff, 0xffffffff}; + +void recMOVZtemp_consts(int info) +{ + if( info & PROCESS_EE_MMX ) { + + u32* mem; + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + PXORRtoR(t0reg, t0reg); + PCMPEQDRtoR(t0reg, EEREC_T); + PMOVMSKBMMXtoR(EAX, t0reg); + CMP8ItoR(EAX, 0xff); + j8Ptr[ 0 ] = JNE8( 0 ); + + if( g_cpuFlushedConstReg & (1<<_Rs_) ) mem = &cpuRegs.GPR.r[_Rs_].UL[0]; + else { + mem = recAllocStackMem(8,8); + + mem[0] = g_cpuConstRegs[_Rs_].UL[0]; + mem[1] = g_cpuConstRegs[_Rs_].UL[1]; + } + + MOVQMtoR(EEREC_D, (u32)mem); + x86SetJ8( j8Ptr[ 0 ] ); + + _freeMMXreg(t0reg); + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + OR32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j8Ptr[ 0 ] = JNZ8( 0 ); + + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0] ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1] ); + + x86SetJ8( j8Ptr[ 0 ] ); +} + +void recMOVZtemp_constt(int info) +{ + if (g_cpuConstRegs[_Rt_].UD[0] == 0) { + if( info & PROCESS_EE_MMX ) { + if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); + return; + } + + if( _hasFreeXMMreg() ) { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], t0reg); + _freeMMXreg(t0reg); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX); + } + } +} + +void recMOVZtemp_(int info) +{ + int t0reg = -1; + + if( info & PROCESS_EE_MMX ) { + + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + PXORRtoR(t0reg, t0reg); + PCMPEQDRtoR(t0reg, EEREC_T); + PMOVMSKBMMXtoR(EAX, t0reg); + CMP8ItoR(EAX, 0xff); + j8Ptr[ 0 ] = JNE8( 0 ); + + MOVQRtoR(EEREC_D, EEREC_S); + x86SetJ8( j8Ptr[ 0 ] ); + + _freeMMXreg(t0reg); + return; + } + + if( _hasFreeXMMreg() ) + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + OR32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j8Ptr[ 0 ] = JNZ8( 0 ); + + if( t0reg >= 0 ) { + MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], t0reg); + _freeMMXreg(t0reg); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX); + } + + x86SetJ8( j8Ptr[ 0 ] ); + SetMMXstate(); +} + +EERECOMPILE_CODE0(MOVZtemp, XMMINFO_READS|XMMINFO_READD|XMMINFO_READD|XMMINFO_WRITED); + +void recMOVZ() +{ + if( _Rs_ == _Rd_ ) + return; + + if( GPR_IS_CONST1(_Rd_) ) { + + if( !GPR_IS_CONST2(_Rs_, _Rt_) ) { + // remove the const, since move is conditional + _deleteEEreg(_Rd_, 0); + MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[_Rd_].UL[0]); + MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[_Rd_].UL[1]); + } + else { + if (g_cpuConstRegs[_Rt_].UD[0] == 0) { + g_cpuConstRegs[_Rd_].UL[0] = g_cpuConstRegs[_Rs_].UL[0]; + g_cpuConstRegs[_Rd_].UL[1] = g_cpuConstRegs[_Rs_].UL[1]; + } + return; + } + } + + recMOVZtemp(); +} + +//// MOVN +void recMOVNtemp_const() +{ + GPR_DEL_CONST(_Rd_); + _deleteEEreg(_Rd_, 1); + _eeOnWriteReg(_Rd_, 0); + if (g_cpuConstRegs[_Rt_].UD[0] != 0) { + MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[_Rs_].UL[0]); + MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[_Rs_].UL[1]); + } +} + +void recMOVNtemp_consts(int info) +{ + if( info & PROCESS_EE_MMX ) { + + u32* mem; + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + PXORRtoR(t0reg, t0reg); + PCMPEQDRtoR(t0reg, EEREC_T); + + PMOVMSKBMMXtoR(EAX, t0reg); + CMP8ItoR(EAX, 0xff); + j8Ptr[ 0 ] = JE8( 0 ); + + if( g_cpuFlushedConstReg & (1<<_Rs_) ) mem = &cpuRegs.GPR.r[_Rs_].UL[0]; + else { + mem = recAllocStackMem(8,8); + + mem[0] = g_cpuConstRegs[_Rs_].UL[0]; + mem[1] = g_cpuConstRegs[_Rs_].UL[1]; + } + + MOVQMtoR(EEREC_D, (u32)mem); + x86SetJ8( j8Ptr[ 0 ] ); + + _freeMMXreg(t0reg); + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + OR32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j8Ptr[ 0 ] = JZ8( 0 ); + + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0] ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1] ); + + x86SetJ8( j8Ptr[ 0 ] ); +} + +void recMOVNtemp_constt(int info) +{ + if (g_cpuConstRegs[_Rt_].UD[0] != 0) { + if( _hasFreeXMMreg() ) { + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], t0reg); + _freeMMXreg(t0reg); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX); + } + } +} + +void recMOVNtemp_(int info) +{ + int t0reg=-1; + + if( info & PROCESS_EE_MMX ) { + + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + PXORRtoR(t0reg, t0reg); + PCMPEQDRtoR(t0reg, EEREC_T); + PMOVMSKBMMXtoR(EAX, t0reg); + CMP8ItoR(EAX, 0xff); + j8Ptr[ 0 ] = JE8( 0 ); + + MOVQRtoR(EEREC_D, EEREC_S); + x86SetJ8( j8Ptr[ 0 ] ); + + _freeMMXreg(t0reg); + return; + } + + if( _hasFreeXMMreg() ) + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + OR32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j8Ptr[ 0 ] = JZ8( 0 ); + + if( t0reg >= 0 ) { + MOVQMtoR(t0reg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], t0reg); + _freeMMXreg(t0reg); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); + MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX); + } + + x86SetJ8( j8Ptr[ 0 ] ); + + SetMMXstate(); +} + +EERECOMPILE_CODE0(MOVNtemp, XMMINFO_READS|XMMINFO_READD|XMMINFO_READD|XMMINFO_WRITED); + +void recMOVN() +{ + if( _Rs_ == _Rd_ ) + return; + + if( GPR_IS_CONST1(_Rd_) ) { + + if( !GPR_IS_CONST2(_Rs_, _Rt_) ) { + // remove the const, since move is conditional + _deleteEEreg(_Rd_, 0); + MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[_Rd_].UL[0]); + MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[_Rd_].UL[1]); + } + else { + if (g_cpuConstRegs[_Rt_].UD[0] != 0) { + g_cpuConstRegs[_Rd_].UL[0] = g_cpuConstRegs[_Rs_].UL[0]; + g_cpuConstRegs[_Rd_].UL[1] = g_cpuConstRegs[_Rs_].UL[1]; + } + return; + } + } + + recMOVNtemp(); +} + +#else + +//////////////////////////////////////////////////// +void recLUI( void ) +{ + if(!_Rt_) return; + if ( _Imm_ < 0 ) + { + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], (u32)_Imm_ << 16 ); //U + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0xffffffff ); //V + } + else + { + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], (u32)_Imm_ << 16 ); //U + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0 ); //V + } +} + +//////////////////////////////////////////////////// +void recMFHI( void ) +{ + + if ( ! _Rd_ ) + { + return; + } + + MOVQMtoR( MM0, (int)&cpuRegs.HI.UD[ 0 ] ); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], MM0 ); + SetMMXstate(); + +} + +//////////////////////////////////////////////////// +void recMFLO( void ) +{ + + if ( ! _Rd_ ) + { + return; + } + + MOVQMtoR( MM0, (int)&cpuRegs.LO.UD[ 0 ] ); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UD[ 0 ], MM0 ); + SetMMXstate(); + +} + +//////////////////////////////////////////////////// +void recMTHI( void ) +{ + + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQRtoM( (int)&cpuRegs.HI.UD[ 0 ], MM0 ); + SetMMXstate(); + +} + +//////////////////////////////////////////////////// +void recMTLO( void ) +{ + + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ].UD[ 0 ] ); + MOVQRtoM( (int)&cpuRegs.LO.UD[ 0 ], MM0 ); + SetMMXstate(); + +} + +//////////////////////////////////////////////////// +void recMOVZ( void ) +{ + if ( ! _Rd_ ) + { + return; + } + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + OR32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j8Ptr[ 0 ] = JNZ8( 0 ); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + + x86SetJ8( j8Ptr[ 0 ] ); + +} + +//////////////////////////////////////////////////// +void recMOVN( void ) +{ + if ( ! _Rd_ ) + { + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + OR32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + j8Ptr[ 0 ] = JZ8( 0 ); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], ECX ); + + x86SetJ8( j8Ptr[ 0 ] ); + +} + +REC_FUNC( MFHI1 ); +REC_FUNC( MFLO1 ); +REC_FUNC( MTHI1 ); +REC_FUNC( MTLO1 ); + +#endif + +} } } diff --git a/pcsx2/x86/ix86-32/iR5900MultDiv.cpp b/pcsx2/x86/ix86-32/iR5900MultDiv.cpp index 99857d6f0d..5623f2482f 100644 --- a/pcsx2/x86/ix86-32/iR5900MultDiv.cpp +++ b/pcsx2/x86/ix86-32/iR5900MultDiv.cpp @@ -1,955 +1,955 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "R5900OpcodeTables.h" -#include "ix86/ix86.h" -#include "iR5900.h" - -namespace Interp = R5900::Interpreter::OpcodeImpl; - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl -{ - -/********************************************************* -* Register mult/div & Register trap logic * -* Format: OP rs, rt * -*********************************************************/ -#ifndef MULTDIV_RECOMPILE - -REC_FUNC(MULT); -REC_FUNC(MULTU); -REC_FUNC( MULT1 ); -REC_FUNC( MULTU1 ); - -REC_FUNC(DIV); -REC_FUNC(DIVU); -REC_FUNC( DIV1 ); -REC_FUNC( DIVU1 ); - -REC_FUNC( MADD ); -REC_FUNC( MADDU ); -REC_FUNC( MADD1 ); -REC_FUNC( MADDU1 ); - -#elif defined(EE_CONST_PROP) - -// if upper is 1, write in upper 64 bits of LO/HI -void recWritebackHILO(int info, int writed, int upper) -{ - int regd, reglo = -1, reghi, savedlo = 0; - u32 loaddr = (int)&cpuRegs.LO.UL[ upper ? 2 : 0 ]; - u32 hiaddr = (int)&cpuRegs.HI.UL[ upper ? 2 : 0 ]; - u8 testlive = upper?EEINST_LIVE2:EEINST_LIVE0; - - if( g_pCurInstInfo->regs[XMMGPR_HI] & testlive ) - MOV32RtoR( ECX, EDX ); - - if( g_pCurInstInfo->regs[XMMGPR_LO] & testlive ) { - - _deleteMMXreg(XMMGPR_LO, 2); - - if( (reglo = _checkXMMreg(XMMTYPE_GPRREG, XMMGPR_LO, MODE_READ)) >= 0 ) { - if( xmmregs[reglo].mode & MODE_WRITE ) { - if( upper ) SSE2_MOVQ_XMM_to_M64(loaddr-8, reglo); - else SSE_MOVHPS_XMM_to_M64(loaddr+8, reglo); - } - - xmmregs[reglo].inuse = 0; - reglo = -1; - } - - CDQ(); - MOV32RtoM( loaddr, EAX ); - MOV32RtoM( loaddr+4, EDX ); - savedlo = 1; - } - - if ( writed && _Rd_ ) - { - _eeOnWriteReg(_Rd_, 1); - - regd = -1; - if( g_pCurInstInfo->regs[_Rd_] & EEINST_MMX ) { - - if( savedlo ) { - regd = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - MOVQMtoR(regd, loaddr); - } - } - else if( g_pCurInstInfo->regs[_Rd_] & EEINST_XMM ) { - if( savedlo ) { - regd = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_WRITE|MODE_READ); - if( regd >= 0 ) { - SSE_MOVLPS_M64_to_XMM(regd, loaddr); - regd |= 0x8000; - } - } - } - - if( regd < 0 ) { - _deleteEEreg(_Rd_, 0); - - if( EEINST_ISLIVE1(_Rd_) && !savedlo ) CDQ(); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - - if( EEINST_ISLIVE1(_Rd_) ) { - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - } - else EEINST_RESETHASLIVE1(_Rd_); - } - } - - if( g_pCurInstInfo->regs[XMMGPR_HI] & testlive ) { - _deleteMMXreg(XMMGPR_HI, 2); - - if( (reghi = _checkXMMreg(XMMTYPE_GPRREG, XMMGPR_HI, MODE_READ)) >= 0 ) { - if( xmmregs[reghi].mode & MODE_WRITE ) { - if( upper ) SSE2_MOVQ_XMM_to_M64(hiaddr-8, reghi); - else SSE_MOVHPS_XMM_to_M64(hiaddr+8, reghi); - } - - xmmregs[reghi].inuse = 0; - reghi = -1; - } - - MOV32RtoM(hiaddr, ECX ); - SAR32ItoR(ECX, 31); - MOV32RtoM(hiaddr+4, ECX ); - } -} - -void recWritebackHILOMMX(int info, int regsource, int writed, int upper) -{ - int regd, t0reg, t1reg = -1; - u32 loaddr = (int)&cpuRegs.LO.UL[ upper ? 2 : 0 ]; - u32 hiaddr = (int)&cpuRegs.HI.UL[ upper ? 2 : 0 ]; - u8 testlive = upper?EEINST_LIVE2:EEINST_LIVE0; - - SetMMXstate(); - - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQRtoR(t0reg, regsource); - PSRADItoR(t0reg, 31); // shift in 0s - - if( (g_pCurInstInfo->regs[XMMGPR_LO] & testlive) || (writed && _Rd_) ) { - if( (g_pCurInstInfo->regs[XMMGPR_HI] & testlive) ) - { - if( !_hasFreeMMXreg() ) { - if( g_pCurInstInfo->regs[XMMGPR_HI] & testlive ) - _deleteMMXreg(MMX_GPR+MMX_HI, 2); - } - - t1reg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQRtoR(t1reg, regsource); - } - - PUNPCKLDQRtoR(regsource, t0reg); - } - - if( g_pCurInstInfo->regs[XMMGPR_LO] & testlive ) { - int reglo; - if( !upper && (reglo = _allocCheckGPRtoMMX(g_pCurInstInfo, XMMGPR_LO, MODE_WRITE)) >= 0 ) { - MOVQRtoR(reglo, regsource); - } - else { - reglo = _checkXMMreg(XMMTYPE_GPRREG, XMMGPR_LO, MODE_READ); - - MOVQRtoM(loaddr, regsource); - - if( reglo >= 0 ) { - if( xmmregs[reglo].mode & MODE_WRITE ) { - if( upper ) SSE2_MOVQ_XMM_to_M64(loaddr-8, reglo); - else SSE_MOVHPS_XMM_to_M64(loaddr+8, reglo); - } - xmmregs[reglo].inuse = 0; - reglo = -1; - } - } - } - - if ( writed && _Rd_ ) - { - regd = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rd_, MODE_WRITE); - - if( regd >= 0 ) { - if( regd != regsource ) MOVQRtoR(regd, regsource); - } - else { - regd = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_READ); - - if( regd >= 0 ) { - if( g_pCurInstInfo->regs[XMMGPR_LO] & testlive ) { - // lo written - SSE_MOVLPS_M64_to_XMM(regd, loaddr); - xmmregs[regd].mode |= MODE_WRITE; - } - else { - MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], regsource); - - if( xmmregs[regd].mode & MODE_WRITE ) { - SSE_MOVHPS_XMM_to_M64((int)&cpuRegs.GPR.r[_Rd_].UL[2], regd); - } - - xmmregs[regd].inuse = 0; - } - } - else { - MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], regsource); - } - } - } - - if( g_pCurInstInfo->regs[XMMGPR_HI] & testlive ) { - - int mmreg = -1, reghi; - - if( t1reg >= 0 ) { - PUNPCKHDQRtoR(t1reg, t0reg); - mmreg = t1reg; - } - else { - // can't modify regsource - PUNPCKHDQRtoR(t0reg, regsource); - mmreg = t0reg; - PSHUFWRtoR(t0reg, t0reg, 0x4e); - } - - if( upper ) { - reghi = _checkXMMreg(XMMTYPE_GPRREG, XMMGPR_HI, MODE_READ); - if( reghi >= 0 ) { - if( xmmregs[reghi].mode & MODE_WRITE ) SSE2_MOVQ_XMM_to_M64(hiaddr-8, reghi); - } - - xmmregs[reghi].inuse = 0; - MOVQRtoM(hiaddr, mmreg); - } - else { - _deleteGPRtoXMMreg(XMMGPR_HI, 2); - _deleteMMXreg(MMX_GPR+MMX_HI, 2); - mmxregs[mmreg].mode = MODE_WRITE; - mmxregs[mmreg].reg = MMX_GPR+MMX_HI; - - if( t1reg >= 0 ) t1reg = -1; - else t0reg = -1; - } - } - - if( t0reg >= 0 ) _freeMMXreg(t0reg&0xf); - if( t1reg >= 0 ) _freeMMXreg(t1reg&0xf); -} - -void recWritebackConstHILO(u64 res, int writed, int upper) -{ - int reglo, reghi; - u32 loaddr = (int)&cpuRegs.LO.UL[ upper ? 2 : 0 ]; - u32 hiaddr = (int)&cpuRegs.HI.UL[ upper ? 2 : 0 ]; - u8 testlive = upper?EEINST_LIVE2:EEINST_LIVE0; - - if( g_pCurInstInfo->regs[XMMGPR_LO] & testlive ) { - if( !upper && (reglo = _allocCheckGPRtoMMX(g_pCurInstInfo, XMMGPR_LO, MODE_WRITE)) >= 0 ) { - u32* ptr = recAllocStackMem(8, 8); - ptr[0] = res & 0xffffffff; - ptr[1] = (res&0x80000000)?0xffffffff:0; - MOVQMtoR(reglo, (u32)ptr); - } - else { - reglo = _allocCheckGPRtoXMM(g_pCurInstInfo, XMMGPR_LO, MODE_WRITE|MODE_READ); - - if( reglo >= 0 ) { - u32* ptr = recAllocStackMem(8, 8); - ptr[0] = res & 0xffffffff; - ptr[1] = (res&0x80000000)?0xffffffff:0; - if( upper ) SSE_MOVHPS_M64_to_XMM(reglo, (u32)ptr); - else SSE_MOVLPS_M64_to_XMM(reglo, (u32)ptr); - } - else { - MOV32ItoM(loaddr, res & 0xffffffff); - MOV32ItoM(loaddr+4, (res&0x80000000)?0xffffffff:0); - } - } - } - - if( g_pCurInstInfo->regs[XMMGPR_HI] & testlive ) { - - if( !upper && (reghi = _allocCheckGPRtoMMX(g_pCurInstInfo, XMMGPR_HI, MODE_WRITE)) >= 0 ) { - u32* ptr = recAllocStackMem(8, 8); - ptr[0] = res >> 32; - ptr[1] = (res>>63)?0xffffffff:0; - MOVQMtoR(reghi, (u32)ptr); - } - else { - reghi = _allocCheckGPRtoXMM(g_pCurInstInfo, XMMGPR_HI, MODE_WRITE|MODE_READ); - - if( reghi >= 0 ) { - u32* ptr = recAllocStackMem(8, 8); - ptr[0] = res >> 32; - ptr[1] = (res>>63)?0xffffffff:0; - if( upper ) SSE_MOVHPS_M64_to_XMM(reghi, (u32)ptr); - else SSE_MOVLPS_M64_to_XMM(reghi, (u32)ptr); - } - else { - _deleteEEreg(XMMGPR_HI, 0); - MOV32ItoM(hiaddr, res >> 32); - MOV32ItoM(hiaddr+4, (res>>63)?0xffffffff:0); - } - } - } - - if (!writed || !_Rd_) return; - g_cpuConstRegs[_Rd_].UD[0] = (s32)(res & 0xffffffff); //that is the difference -} - -//// MULT -void recMULT_const() -{ - s64 res = (s64)g_cpuConstRegs[_Rs_].SL[0] * (s64)g_cpuConstRegs[_Rt_].SL[0]; - - recWritebackConstHILO(res, 1, 0); -} - -void recMULTUsuper(int info, int upper, int process); -void recMULTsuper(int info, int upper, int process) -{ - assert( !(info&PROCESS_EE_MMX) ); - if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); - EEINST_SETSIGNEXT(_Rs_); - EEINST_SETSIGNEXT(_Rt_); - - if( process & PROCESS_CONSTS ) { - MOV32ItoR( EAX, g_cpuConstRegs[_Rs_].UL[0] ); - IMUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - } - else if( process & PROCESS_CONSTT) { - MOV32ItoR( EAX, g_cpuConstRegs[_Rt_].UL[0] ); - IMUL32M( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - IMUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - } - - recWritebackHILO(info, 1, upper); -} - -//void recMULT_process(int info, int process) -//{ -// if( EEINST_ISLIVE64(XMMGPR_HI) || !(info&PROCESS_EE_MMX) ) { -// recMULTsuper(info, 0, process); -// } -// else { -// // EEREC_D isn't set -// int mmregd; -// -// if( _Rd_ ) { -// assert(EEREC_D == 0); -// mmregd = _checkMMXreg(MMX_GPR+_Rd_, MODE_WRITE); -// -// if( mmregd < 0 ) { -// if( !(process&PROCESS_CONSTS) && ((g_pCurInstInfo->regs[_Rs_]&EEINST_LASTUSE)||!EEINST_ISLIVE64(_Rs_)) ) { -// _freeMMXreg(EEREC_S); -// _deleteGPRtoXMMreg(_Rd_, 2); -// mmxregs[EEREC_S].inuse = 1; -// mmxregs[EEREC_S].reg = _Rd_; -// mmxregs[EEREC_S].mode = MODE_WRITE; -// mmregd = EEREC_S; -// } -// else if( !(process&PROCESS_CONSTT) && ((g_pCurInstInfo->regs[_Rt_]&EEINST_LASTUSE)||!EEINST_ISLIVE64(_Rt_)) ) { -// _freeMMXreg(EEREC_T); -// _deleteGPRtoXMMreg(_Rd_, 2); -// mmxregs[EEREC_T].inuse = 1; -// mmxregs[EEREC_T].reg = _Rd_; -// mmxregs[EEREC_T].mode = MODE_WRITE; -// mmregd = EEREC_T; -// } -// else mmregd = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); -// } -// -// info |= PROCESS_EE_SET_D(mmregd); -// } -// recMULTUsuper(info, 0, process); -// } -// -// // sometimes _Rd_ can be const -// if( _Rd_ ) _eeOnWriteReg(_Rd_, 1); -//} - -void recMULT_(int info) -{ - //recMULT_process(info, 0); - if( (g_pCurInstInfo->regs[XMMGPR_HI]&EEINST_LIVE2) || !(info&PROCESS_EE_MMX) ) { - recMULTsuper(info, 0, 0); - } - else recMULTUsuper(info, 0, 0); -} - -void recMULT_consts(int info) -{ - //recMULT_process(info, PROCESS_CONSTS); - if( (g_pCurInstInfo->regs[XMMGPR_HI]&EEINST_LIVE2) || !(info&PROCESS_EE_MMX) ) { - recMULTsuper(info, 0, PROCESS_CONSTS); - } - else recMULTUsuper(info, 0, PROCESS_CONSTS); -} - -void recMULT_constt(int info) -{ - //recMULT_process(info, PROCESS_CONSTT); - if( (g_pCurInstInfo->regs[XMMGPR_HI]&EEINST_LIVE2) || !(info&PROCESS_EE_MMX) ) { - recMULTsuper(info, 0, PROCESS_CONSTT); - } - else recMULTUsuper(info, 0, PROCESS_CONSTT); -} - -// don't set XMMINFO_WRITED|XMMINFO_WRITELO|XMMINFO_WRITEHI -EERECOMPILE_CODE0(MULT, XMMINFO_READS|XMMINFO_READT|(_Rd_?XMMINFO_WRITED:0) ); - -//// MULTU -void recMULTU_const() -{ - u64 res = (u64)g_cpuConstRegs[_Rs_].UL[0] * (u64)g_cpuConstRegs[_Rt_].UL[0]; - - recWritebackConstHILO(res, 1, 0); -} - -void recMULTUsuper(int info, int upper, int process) -{ - if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); - EEINST_SETSIGNEXT(_Rs_); - EEINST_SETSIGNEXT(_Rt_); - - if( (info & PROCESS_EE_MMX) ) { - - if( !_Rd_ ) { - // need some temp reg - int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - assert( EEREC_D == 0 ); - info |= PROCESS_EE_SET_D(t0reg); - } - - if( process & PROCESS_CONSTS ) { - u32* ptempmem = _eeGetConstReg(_Rs_); - if( EEREC_D != EEREC_T ) MOVQRtoR(EEREC_D, EEREC_T); - PMULUDQMtoR(EEREC_D, (u32)ptempmem); - } - else if( process & PROCESS_CONSTT ) { - u32* ptempmem = _eeGetConstReg(_Rt_); - if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); - PMULUDQMtoR(EEREC_D, (u32)ptempmem); - } - else { - if( EEREC_D == EEREC_S ) PMULUDQRtoR(EEREC_D, EEREC_T); - else if( EEREC_D == EEREC_T ) PMULUDQRtoR(EEREC_D, EEREC_S); - else { - MOVQRtoR(EEREC_D, EEREC_S); - PMULUDQRtoR(EEREC_D, EEREC_T); - } - } - - recWritebackHILOMMX(info, EEREC_D, 1, upper); - - if( !_Rd_ ) _freeMMXreg(EEREC_D); - return; - } - - if( info & PROCESS_EE_MMX ) { - if( info & PROCESS_EE_MODEWRITES ) { - MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_].UL[0], EEREC_S); - if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; - } - if( info & PROCESS_EE_MODEWRITET ) { - MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_].UL[0], EEREC_T); - if( mmxregs[EEREC_T].reg == MMX_GPR+_Rt_ ) mmxregs[EEREC_T].mode &= ~MODE_WRITE; - } - _deleteMMXreg(MMX_GPR+_Rd_, 0); - } - - if( process & PROCESS_CONSTS ) { - MOV32ItoR( EAX, g_cpuConstRegs[_Rs_].UL[0] ); - - if( info & PROCESS_EE_MMX ) { - MOVD32MMXtoR(EDX, EEREC_T); - MUL32R(EDX); - } - else - MUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - } - else if( process & PROCESS_CONSTT) { - MOV32ItoR( EAX, g_cpuConstRegs[_Rt_].UL[0] ); - - if( info & PROCESS_EE_MMX ) { - MOVD32MMXtoR(EDX, EEREC_S); - MUL32R(EDX); - } - else - MUL32M( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - } - else { - if( info & PROCESS_EE_MMX ) { - MOVD32MMXtoR(EAX, EEREC_S); - MOVD32MMXtoR(EDX, EEREC_T); - MUL32R(EDX); - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - MUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - } - } - - recWritebackHILO(info, 1, upper); -} - -void recMULTU_(int info) -{ - recMULTUsuper(info, 0, 0); -} - -void recMULTU_consts(int info) -{ - recMULTUsuper(info, 0, PROCESS_CONSTS); -} - -void recMULTU_constt(int info) -{ - recMULTUsuper(info, 0, PROCESS_CONSTT); -} - -// don't specify XMMINFO_WRITELO or XMMINFO_WRITEHI, that is taken care of -EERECOMPILE_CODE0(MULTU, XMMINFO_READS|XMMINFO_READT|(_Rd_?XMMINFO_WRITED:0)); - -//////////////////////////////////////////////////// -void recMULT1_const() -{ - u64 res = (u64)g_cpuConstRegs[_Rs_].UL[0] * (u64)g_cpuConstRegs[_Rt_].UL[0]; - - recWritebackConstHILO(res, 1, 1); -} - -void recMULT1_(int info) -{ - if( (g_pCurInstInfo->regs[XMMGPR_HI]&EEINST_LIVE2) || !(info&PROCESS_EE_MMX) ) { - recMULTsuper(info, 1, 0); - } - else recMULTUsuper(info, 1, 0); -} - -void recMULT1_consts(int info) -{ - if( (g_pCurInstInfo->regs[XMMGPR_HI]&EEINST_LIVE2) || !(info&PROCESS_EE_MMX) ) { - recMULTsuper(info, 1, PROCESS_CONSTS); - } - else recMULTUsuper(info, 1, PROCESS_CONSTS); -} - -void recMULT1_constt(int info) -{ - if( (g_pCurInstInfo->regs[XMMGPR_HI]&EEINST_LIVE2) || !(info&PROCESS_EE_MMX) ) { - recMULTsuper(info, 1, PROCESS_CONSTT); - } - else recMULTUsuper(info, 1, PROCESS_CONSTT); -} - -EERECOMPILE_CODE0(MULT1, XMMINFO_READS|XMMINFO_READT|(_Rd_?XMMINFO_WRITED:0) ); - -//////////////////////////////////////////////////// -void recMULTU1_const() -{ - u64 res = (u64)g_cpuConstRegs[_Rs_].UL[0] * (u64)g_cpuConstRegs[_Rt_].UL[0]; - - recWritebackConstHILO(res, 1, 1); -} - -void recMULTU1_(int info) -{ - recMULTUsuper(info, 1, 0); -} - -void recMULTU1_consts(int info) -{ - recMULTUsuper(info, 1, PROCESS_CONSTS); -} - -void recMULTU1_constt(int info) -{ - recMULTUsuper(info, 1, PROCESS_CONSTT); -} - -EERECOMPILE_CODE0(MULTU1, XMMINFO_READS|XMMINFO_READT|(_Rd_?XMMINFO_WRITED:0)); - -//// DIV -void recDIV_const() -{ - if (g_cpuConstRegs[_Rt_].SL[0] != 0) { - s32 quot = g_cpuConstRegs[_Rs_].SL[0] / g_cpuConstRegs[_Rt_].SL[0]; - s32 rem = g_cpuConstRegs[_Rs_].SL[0] % g_cpuConstRegs[_Rt_].SL[0]; - - recWritebackConstHILO((u64)quot|((u64)rem<<32), 0, 0); - } -} - -void recDIVsuper(int info, int sign, int upper, int process) -{ - EEINST_SETSIGNEXT(_Rs_); - EEINST_SETSIGNEXT(_Rt_); - - if( process & PROCESS_CONSTT ) { - if( !g_cpuConstRegs[_Rt_].UL[0] ) - return; - MOV32ItoR( ECX, g_cpuConstRegs[_Rt_].UL[0] ); - } - else { - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - - OR32RtoR( ECX, ECX ); - j8Ptr[ 0 ] = JE8( 0 ); - } - - if( process & PROCESS_CONSTS ) - MOV32ItoR( EAX, g_cpuConstRegs[_Rs_].UL[0] ); - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - } - - if( sign ) { - CDQ(); - IDIV32R( ECX ); - } - else { - XOR32RtoR( EDX, EDX ); - DIV32R( ECX ); - } - if( !(process & PROCESS_CONSTT) ) x86SetJ8( j8Ptr[ 0 ] ); - - // need to execute regardless of bad divide - recWritebackHILO(info, 0, upper); -} - -void recDIV_(int info) -{ - recDIVsuper(info, 1, 0, 0); -} - -void recDIV_consts(int info) -{ - recDIVsuper(info, 1, 0, PROCESS_CONSTS); -} - -void recDIV_constt(int info) -{ - recDIVsuper(info, 1, 0, PROCESS_CONSTT); -} - -EERECOMPILE_CODE0(DIV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITELO|XMMINFO_WRITEHI); - -//// DIVU -void recDIVU_const() -{ - if (g_cpuConstRegs[_Rt_].UL[0] != 0) { - u32 quot = g_cpuConstRegs[_Rs_].UL[0] / g_cpuConstRegs[_Rt_].UL[0]; - u32 rem = g_cpuConstRegs[_Rs_].UL[0] % g_cpuConstRegs[_Rt_].UL[0]; - - recWritebackConstHILO((u64)quot|((u64)rem<<32), 0, 0); - } -} - -void recDIVU_(int info) -{ - recDIVsuper(info, 0, 0, 0); -} - -void recDIVU_consts(int info) -{ - recDIVsuper(info, 0, 0, PROCESS_CONSTS); -} - -void recDIVU_constt(int info) -{ - recDIVsuper(info, 0, 0, PROCESS_CONSTT); -} - -EERECOMPILE_CODE0(DIVU, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITELO|XMMINFO_WRITEHI); - -void recDIV1_const() -{ - if (g_cpuConstRegs[_Rt_].SL[0] != 0) { - s32 quot = g_cpuConstRegs[_Rs_].SL[0] / g_cpuConstRegs[_Rt_].SL[0]; - s32 rem = g_cpuConstRegs[_Rs_].SL[0] % g_cpuConstRegs[_Rt_].SL[0]; - - recWritebackConstHILO((u64)quot|((u64)rem<<32), 0, 1); - } -} - -void recDIV1_(int info) -{ - recDIVsuper(info, 1, 1, 0); -} - -void recDIV1_consts(int info) -{ - recDIVsuper(info, 1, 1, PROCESS_CONSTS); -} - -void recDIV1_constt(int info) -{ - recDIVsuper(info, 1, 1, PROCESS_CONSTT); -} - -EERECOMPILE_CODE0(DIV1, XMMINFO_READS|XMMINFO_READT); - -void recDIVU1_const() -{ - if (g_cpuConstRegs[_Rt_].UL[0] != 0) { - u32 quot = g_cpuConstRegs[_Rs_].UL[0] / g_cpuConstRegs[_Rt_].UL[0]; - u32 rem = g_cpuConstRegs[_Rs_].UL[0] % g_cpuConstRegs[_Rt_].UL[0]; - - recWritebackConstHILO((u64)quot|((u64)rem<<32), 0, 1); - } -} - -void recDIVU1_(int info) -{ - recDIVsuper(info, 0, 1, 0); -} - -void recDIVU1_consts(int info) -{ - recDIVsuper(info, 0, 1, PROCESS_CONSTS); -} - -void recDIVU1_constt(int info) -{ - recDIVsuper(info, 0, 1, PROCESS_CONSTT); -} - -EERECOMPILE_CODE0(DIVU1, XMMINFO_READS|XMMINFO_READT); - -//do EEINST_SETSIGNEXT -REC_FUNC_DEL( MADD, _Rd_ ); - -static PCSX2_ALIGNED16(u32 s_MaddMask[]) = { 0x80000000, 0, 0x80000000, 0 }; - -void recMADDU() -{ - _eeOnWriteReg(_Rd_, 1); - EEINST_SETSIGNEXT(_Rs_); - EEINST_SETSIGNEXT(_Rt_); - - if( GPR_IS_CONST2(_Rs_, _Rt_) ) { - u64 result = ((u64)g_cpuConstRegs[_Rs_].UL[0] * (u64)g_cpuConstRegs[_Rt_].UL[0]); - _deleteEEreg(XMMGPR_LO, 1); - _deleteEEreg(XMMGPR_HI, 1); - - // dadd - MOV32MtoR( EAX, (int)&cpuRegs.LO.UL[ 0 ] ); - MOV32MtoR( ECX, (int)&cpuRegs.HI.UL[ 0 ] ); - ADD32ItoR( EAX, (u32)result&0xffffffff ); - ADC32ItoR( ECX, (u32)(result>>32) ); - CDQ(); - if( _Rd_) { - _deleteEEreg(_Rd_, 0); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - } - - MOV32RtoM( (int)&cpuRegs.LO.UL[0], EAX ); - MOV32RtoM( (int)&cpuRegs.LO.UL[1], EDX ); - - MOV32RtoM( (int)&cpuRegs.HI.UL[0], ECX ); - MOV32RtoR(EAX, ECX); - CDQ(); - MOV32RtoM( (int)&cpuRegs.HI.UL[1], EDX ); - return; - } - - _deleteEEreg(XMMGPR_LO, 1); - _deleteEEreg(XMMGPR_HI, 1); - _deleteGPRtoXMMreg(_Rs_, 1); - _deleteGPRtoXMMreg(_Rt_, 1); - _deleteMMXreg(MMX_GPR+_Rs_, 1); - _deleteMMXreg(MMX_GPR+_Rt_, 1); - - if( GPR_IS_CONST1(_Rs_) ) { - MOV32ItoR( EAX, g_cpuConstRegs[_Rs_].UL[0] ); - IMUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - } - else if ( GPR_IS_CONST1(_Rt_) ) { - MOV32ItoR( EAX, g_cpuConstRegs[_Rt_].UL[0] ); - IMUL32M( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - IMUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - } - - MOV32RtoR( ECX, EDX ); - ADD32MtoR( EAX, (u32)&cpuRegs.LO.UL[0] ); - ADC32MtoR( ECX, (u32)&cpuRegs.HI.UL[0] ); - CDQ(); - if( _Rd_ ) { - _deleteEEreg(_Rd_, 0); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - } - - MOV32RtoM( (int)&cpuRegs.LO.UL[0], EAX ); - MOV32RtoM( (int)&cpuRegs.LO.UL[1], EDX ); - - MOV32RtoM( (int)&cpuRegs.HI.UL[0], ECX ); - MOV32RtoR(EAX, ECX); - CDQ(); - MOV32RtoM( (int)&cpuRegs.HI.UL[1], EDX ); -} - -void recMADD1() -{ - //SysPrintf("MADD1 email zero if abnormal behavior\n"); - EEINST_SETSIGNEXT(_Rs_); - EEINST_SETSIGNEXT(_Rt_); - if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); - _deleteEEreg(XMMGPR_LO, 0); - _deleteEEreg(XMMGPR_HI, 0); - recCall( Interp::MADD1, _Rd_ ); -} - -void recMADDU1() -{ - //SysPrintf("MADDU1 email zero if abnormal behavior\n"); - EEINST_SETSIGNEXT(_Rs_); - EEINST_SETSIGNEXT(_Rt_); - if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); - _deleteEEreg(XMMGPR_LO, 0); - _deleteEEreg(XMMGPR_HI, 0); - recCall( Interp::MADDU1, _Rd_ ); -} - -#else - -//////////////////////////////////////////////////// -void recMULT( void ) -{ - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - IMUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - - MOV32RtoR( ECX, EDX ); - CDQ( ); - MOV32RtoM( (int)&cpuRegs.LO.UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.LO.UL[ 1 ], EDX ); - if ( _Rd_ ) - { - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - } - MOV32RtoR( EAX, ECX ); - CDQ( ); - MOV32RtoM( (int)&cpuRegs.HI.UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.HI.UL[ 1 ], EDX ); - -} - -//////////////////////////////////////////////////// -void recMULTU( void ) -{ - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - MUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - - MOV32RtoR( ECX, EDX ); - CDQ( ); - MOV32RtoM( (int)&cpuRegs.LO.UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.LO.UL[ 1 ], EDX ); - if ( _Rd_ != 0 ) - { - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - } - MOV32RtoR( EAX, ECX ); - CDQ( ); - MOV32RtoM( (int)&cpuRegs.HI.UL[ 0 ], ECX ); - MOV32RtoM( (int)&cpuRegs.HI.UL[ 1 ], EDX ); - -} - -//////////////////////////////////////////////////// -void recDIV( void ) -{ - - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - OR32RtoR( ECX, ECX ); - j8Ptr[ 0 ] = JE8( 0 ); - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); -// XOR32RtoR( EDX,EDX ); - CDQ(); - IDIV32R( ECX ); - - MOV32RtoR( ECX, EDX ); - CDQ( ); - MOV32RtoM( (int)&cpuRegs.LO.UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.LO.UL[ 1 ], EDX ); - - MOV32RtoR( EAX, ECX ); - CDQ( ); - MOV32RtoM( (int)&cpuRegs.HI.UL[ 0 ], ECX ); - MOV32RtoM( (int)&cpuRegs.HI.UL[ 1 ], EDX ); - - x86SetJ8( j8Ptr[ 0 ] ); - -} - -//////////////////////////////////////////////////// -void recDIVU( void ) -{ - - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - OR32RtoR( ECX, ECX ); - j8Ptr[ 0 ] = JE8( 0 ); - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - XOR32RtoR( EDX, EDX ); - // CDQ(); - DIV32R( ECX ); - - MOV32RtoR( ECX, EDX ); - CDQ( ); - MOV32RtoM( (int)&cpuRegs.LO.UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.LO.UL[ 1 ], EDX ); - - MOV32RtoR( EAX,ECX ); - CDQ( ); - MOV32RtoM( (int)&cpuRegs.HI.UL[ 0 ], ECX ); - MOV32RtoM( (int)&cpuRegs.HI.UL[ 1 ], EDX ); - x86SetJ8( j8Ptr[ 0 ] ); - -} - -REC_FUNC_DEL( MULT1, _Rd_ ); -REC_FUNC_DEL( MULTU1, _Rd_ ); -REC_FUNC_DEL( DIV1, _Rd_ ); -REC_FUNC_DEL( DIVU1, _Rd_ ); - -REC_FUNC_DEL( MADD, _Rd_ ); -REC_FUNC_DEL( MADDU, _Rd_ ); -REC_FUNC_DEL( MADD1, _Rd_ ); -REC_FUNC_DEL( MADDU1, _Rd_ ); - -#endif - -} } } +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "R5900OpcodeTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + +namespace Interp = R5900::Interpreter::OpcodeImpl; + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl +{ + +/********************************************************* +* Register mult/div & Register trap logic * +* Format: OP rs, rt * +*********************************************************/ +#ifndef MULTDIV_RECOMPILE + +REC_FUNC(MULT); +REC_FUNC(MULTU); +REC_FUNC( MULT1 ); +REC_FUNC( MULTU1 ); + +REC_FUNC(DIV); +REC_FUNC(DIVU); +REC_FUNC( DIV1 ); +REC_FUNC( DIVU1 ); + +REC_FUNC( MADD ); +REC_FUNC( MADDU ); +REC_FUNC( MADD1 ); +REC_FUNC( MADDU1 ); + +#elif defined(EE_CONST_PROP) + +// if upper is 1, write in upper 64 bits of LO/HI +void recWritebackHILO(int info, int writed, int upper) +{ + int regd, reglo = -1, reghi, savedlo = 0; + u32 loaddr = (int)&cpuRegs.LO.UL[ upper ? 2 : 0 ]; + u32 hiaddr = (int)&cpuRegs.HI.UL[ upper ? 2 : 0 ]; + u8 testlive = upper?EEINST_LIVE2:EEINST_LIVE0; + + if( g_pCurInstInfo->regs[XMMGPR_HI] & testlive ) + MOV32RtoR( ECX, EDX ); + + if( g_pCurInstInfo->regs[XMMGPR_LO] & testlive ) { + + _deleteMMXreg(XMMGPR_LO, 2); + + if( (reglo = _checkXMMreg(XMMTYPE_GPRREG, XMMGPR_LO, MODE_READ)) >= 0 ) { + if( xmmregs[reglo].mode & MODE_WRITE ) { + if( upper ) SSE2_MOVQ_XMM_to_M64(loaddr-8, reglo); + else SSE_MOVHPS_XMM_to_M64(loaddr+8, reglo); + } + + xmmregs[reglo].inuse = 0; + reglo = -1; + } + + CDQ(); + MOV32RtoM( loaddr, EAX ); + MOV32RtoM( loaddr+4, EDX ); + savedlo = 1; + } + + if ( writed && _Rd_ ) + { + _eeOnWriteReg(_Rd_, 1); + + regd = -1; + if( g_pCurInstInfo->regs[_Rd_] & EEINST_MMX ) { + + if( savedlo ) { + regd = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + MOVQMtoR(regd, loaddr); + } + } + else if( g_pCurInstInfo->regs[_Rd_] & EEINST_XMM ) { + if( savedlo ) { + regd = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_WRITE|MODE_READ); + if( regd >= 0 ) { + SSE_MOVLPS_M64_to_XMM(regd, loaddr); + regd |= 0x8000; + } + } + } + + if( regd < 0 ) { + _deleteEEreg(_Rd_, 0); + + if( EEINST_ISLIVE1(_Rd_) && !savedlo ) CDQ(); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + + if( EEINST_ISLIVE1(_Rd_) ) { + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else EEINST_RESETHASLIVE1(_Rd_); + } + } + + if( g_pCurInstInfo->regs[XMMGPR_HI] & testlive ) { + _deleteMMXreg(XMMGPR_HI, 2); + + if( (reghi = _checkXMMreg(XMMTYPE_GPRREG, XMMGPR_HI, MODE_READ)) >= 0 ) { + if( xmmregs[reghi].mode & MODE_WRITE ) { + if( upper ) SSE2_MOVQ_XMM_to_M64(hiaddr-8, reghi); + else SSE_MOVHPS_XMM_to_M64(hiaddr+8, reghi); + } + + xmmregs[reghi].inuse = 0; + reghi = -1; + } + + MOV32RtoM(hiaddr, ECX ); + SAR32ItoR(ECX, 31); + MOV32RtoM(hiaddr+4, ECX ); + } +} + +void recWritebackHILOMMX(int info, int regsource, int writed, int upper) +{ + int regd, t0reg, t1reg = -1; + u32 loaddr = (int)&cpuRegs.LO.UL[ upper ? 2 : 0 ]; + u32 hiaddr = (int)&cpuRegs.HI.UL[ upper ? 2 : 0 ]; + u8 testlive = upper?EEINST_LIVE2:EEINST_LIVE0; + + SetMMXstate(); + + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, regsource); + PSRADItoR(t0reg, 31); // shift in 0s + + if( (g_pCurInstInfo->regs[XMMGPR_LO] & testlive) || (writed && _Rd_) ) { + if( (g_pCurInstInfo->regs[XMMGPR_HI] & testlive) ) + { + if( !_hasFreeMMXreg() ) { + if( g_pCurInstInfo->regs[XMMGPR_HI] & testlive ) + _deleteMMXreg(MMX_GPR+MMX_HI, 2); + } + + t1reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t1reg, regsource); + } + + PUNPCKLDQRtoR(regsource, t0reg); + } + + if( g_pCurInstInfo->regs[XMMGPR_LO] & testlive ) { + int reglo; + if( !upper && (reglo = _allocCheckGPRtoMMX(g_pCurInstInfo, XMMGPR_LO, MODE_WRITE)) >= 0 ) { + MOVQRtoR(reglo, regsource); + } + else { + reglo = _checkXMMreg(XMMTYPE_GPRREG, XMMGPR_LO, MODE_READ); + + MOVQRtoM(loaddr, regsource); + + if( reglo >= 0 ) { + if( xmmregs[reglo].mode & MODE_WRITE ) { + if( upper ) SSE2_MOVQ_XMM_to_M64(loaddr-8, reglo); + else SSE_MOVHPS_XMM_to_M64(loaddr+8, reglo); + } + xmmregs[reglo].inuse = 0; + reglo = -1; + } + } + } + + if ( writed && _Rd_ ) + { + regd = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rd_, MODE_WRITE); + + if( regd >= 0 ) { + if( regd != regsource ) MOVQRtoR(regd, regsource); + } + else { + regd = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_READ); + + if( regd >= 0 ) { + if( g_pCurInstInfo->regs[XMMGPR_LO] & testlive ) { + // lo written + SSE_MOVLPS_M64_to_XMM(regd, loaddr); + xmmregs[regd].mode |= MODE_WRITE; + } + else { + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], regsource); + + if( xmmregs[regd].mode & MODE_WRITE ) { + SSE_MOVHPS_XMM_to_M64((int)&cpuRegs.GPR.r[_Rd_].UL[2], regd); + } + + xmmregs[regd].inuse = 0; + } + } + else { + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], regsource); + } + } + } + + if( g_pCurInstInfo->regs[XMMGPR_HI] & testlive ) { + + int mmreg = -1, reghi; + + if( t1reg >= 0 ) { + PUNPCKHDQRtoR(t1reg, t0reg); + mmreg = t1reg; + } + else { + // can't modify regsource + PUNPCKHDQRtoR(t0reg, regsource); + mmreg = t0reg; + PSHUFWRtoR(t0reg, t0reg, 0x4e); + } + + if( upper ) { + reghi = _checkXMMreg(XMMTYPE_GPRREG, XMMGPR_HI, MODE_READ); + if( reghi >= 0 ) { + if( xmmregs[reghi].mode & MODE_WRITE ) SSE2_MOVQ_XMM_to_M64(hiaddr-8, reghi); + } + + xmmregs[reghi].inuse = 0; + MOVQRtoM(hiaddr, mmreg); + } + else { + _deleteGPRtoXMMreg(XMMGPR_HI, 2); + _deleteMMXreg(MMX_GPR+MMX_HI, 2); + mmxregs[mmreg].mode = MODE_WRITE; + mmxregs[mmreg].reg = MMX_GPR+MMX_HI; + + if( t1reg >= 0 ) t1reg = -1; + else t0reg = -1; + } + } + + if( t0reg >= 0 ) _freeMMXreg(t0reg&0xf); + if( t1reg >= 0 ) _freeMMXreg(t1reg&0xf); +} + +void recWritebackConstHILO(u64 res, int writed, int upper) +{ + int reglo, reghi; + u32 loaddr = (int)&cpuRegs.LO.UL[ upper ? 2 : 0 ]; + u32 hiaddr = (int)&cpuRegs.HI.UL[ upper ? 2 : 0 ]; + u8 testlive = upper?EEINST_LIVE2:EEINST_LIVE0; + + if( g_pCurInstInfo->regs[XMMGPR_LO] & testlive ) { + if( !upper && (reglo = _allocCheckGPRtoMMX(g_pCurInstInfo, XMMGPR_LO, MODE_WRITE)) >= 0 ) { + u32* ptr = recAllocStackMem(8, 8); + ptr[0] = res & 0xffffffff; + ptr[1] = (res&0x80000000)?0xffffffff:0; + MOVQMtoR(reglo, (u32)ptr); + } + else { + reglo = _allocCheckGPRtoXMM(g_pCurInstInfo, XMMGPR_LO, MODE_WRITE|MODE_READ); + + if( reglo >= 0 ) { + u32* ptr = recAllocStackMem(8, 8); + ptr[0] = res & 0xffffffff; + ptr[1] = (res&0x80000000)?0xffffffff:0; + if( upper ) SSE_MOVHPS_M64_to_XMM(reglo, (u32)ptr); + else SSE_MOVLPS_M64_to_XMM(reglo, (u32)ptr); + } + else { + MOV32ItoM(loaddr, res & 0xffffffff); + MOV32ItoM(loaddr+4, (res&0x80000000)?0xffffffff:0); + } + } + } + + if( g_pCurInstInfo->regs[XMMGPR_HI] & testlive ) { + + if( !upper && (reghi = _allocCheckGPRtoMMX(g_pCurInstInfo, XMMGPR_HI, MODE_WRITE)) >= 0 ) { + u32* ptr = recAllocStackMem(8, 8); + ptr[0] = res >> 32; + ptr[1] = (res>>63)?0xffffffff:0; + MOVQMtoR(reghi, (u32)ptr); + } + else { + reghi = _allocCheckGPRtoXMM(g_pCurInstInfo, XMMGPR_HI, MODE_WRITE|MODE_READ); + + if( reghi >= 0 ) { + u32* ptr = recAllocStackMem(8, 8); + ptr[0] = res >> 32; + ptr[1] = (res>>63)?0xffffffff:0; + if( upper ) SSE_MOVHPS_M64_to_XMM(reghi, (u32)ptr); + else SSE_MOVLPS_M64_to_XMM(reghi, (u32)ptr); + } + else { + _deleteEEreg(XMMGPR_HI, 0); + MOV32ItoM(hiaddr, res >> 32); + MOV32ItoM(hiaddr+4, (res>>63)?0xffffffff:0); + } + } + } + + if (!writed || !_Rd_) return; + g_cpuConstRegs[_Rd_].UD[0] = (s32)(res & 0xffffffff); //that is the difference +} + +//// MULT +void recMULT_const() +{ + s64 res = (s64)g_cpuConstRegs[_Rs_].SL[0] * (s64)g_cpuConstRegs[_Rt_].SL[0]; + + recWritebackConstHILO(res, 1, 0); +} + +void recMULTUsuper(int info, int upper, int process); +void recMULTsuper(int info, int upper, int process) +{ + assert( !(info&PROCESS_EE_MMX) ); + if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + + if( process & PROCESS_CONSTS ) { + MOV32ItoR( EAX, g_cpuConstRegs[_Rs_].UL[0] ); + IMUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + else if( process & PROCESS_CONSTT) { + MOV32ItoR( EAX, g_cpuConstRegs[_Rt_].UL[0] ); + IMUL32M( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + IMUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + + recWritebackHILO(info, 1, upper); +} + +//void recMULT_process(int info, int process) +//{ +// if( EEINST_ISLIVE64(XMMGPR_HI) || !(info&PROCESS_EE_MMX) ) { +// recMULTsuper(info, 0, process); +// } +// else { +// // EEREC_D isn't set +// int mmregd; +// +// if( _Rd_ ) { +// assert(EEREC_D == 0); +// mmregd = _checkMMXreg(MMX_GPR+_Rd_, MODE_WRITE); +// +// if( mmregd < 0 ) { +// if( !(process&PROCESS_CONSTS) && ((g_pCurInstInfo->regs[_Rs_]&EEINST_LASTUSE)||!EEINST_ISLIVE64(_Rs_)) ) { +// _freeMMXreg(EEREC_S); +// _deleteGPRtoXMMreg(_Rd_, 2); +// mmxregs[EEREC_S].inuse = 1; +// mmxregs[EEREC_S].reg = _Rd_; +// mmxregs[EEREC_S].mode = MODE_WRITE; +// mmregd = EEREC_S; +// } +// else if( !(process&PROCESS_CONSTT) && ((g_pCurInstInfo->regs[_Rt_]&EEINST_LASTUSE)||!EEINST_ISLIVE64(_Rt_)) ) { +// _freeMMXreg(EEREC_T); +// _deleteGPRtoXMMreg(_Rd_, 2); +// mmxregs[EEREC_T].inuse = 1; +// mmxregs[EEREC_T].reg = _Rd_; +// mmxregs[EEREC_T].mode = MODE_WRITE; +// mmregd = EEREC_T; +// } +// else mmregd = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); +// } +// +// info |= PROCESS_EE_SET_D(mmregd); +// } +// recMULTUsuper(info, 0, process); +// } +// +// // sometimes _Rd_ can be const +// if( _Rd_ ) _eeOnWriteReg(_Rd_, 1); +//} + +void recMULT_(int info) +{ + //recMULT_process(info, 0); + if( (g_pCurInstInfo->regs[XMMGPR_HI]&EEINST_LIVE2) || !(info&PROCESS_EE_MMX) ) { + recMULTsuper(info, 0, 0); + } + else recMULTUsuper(info, 0, 0); +} + +void recMULT_consts(int info) +{ + //recMULT_process(info, PROCESS_CONSTS); + if( (g_pCurInstInfo->regs[XMMGPR_HI]&EEINST_LIVE2) || !(info&PROCESS_EE_MMX) ) { + recMULTsuper(info, 0, PROCESS_CONSTS); + } + else recMULTUsuper(info, 0, PROCESS_CONSTS); +} + +void recMULT_constt(int info) +{ + //recMULT_process(info, PROCESS_CONSTT); + if( (g_pCurInstInfo->regs[XMMGPR_HI]&EEINST_LIVE2) || !(info&PROCESS_EE_MMX) ) { + recMULTsuper(info, 0, PROCESS_CONSTT); + } + else recMULTUsuper(info, 0, PROCESS_CONSTT); +} + +// don't set XMMINFO_WRITED|XMMINFO_WRITELO|XMMINFO_WRITEHI +EERECOMPILE_CODE0(MULT, XMMINFO_READS|XMMINFO_READT|(_Rd_?XMMINFO_WRITED:0) ); + +//// MULTU +void recMULTU_const() +{ + u64 res = (u64)g_cpuConstRegs[_Rs_].UL[0] * (u64)g_cpuConstRegs[_Rt_].UL[0]; + + recWritebackConstHILO(res, 1, 0); +} + +void recMULTUsuper(int info, int upper, int process) +{ + if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + + if( (info & PROCESS_EE_MMX) ) { + + if( !_Rd_ ) { + // need some temp reg + int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + assert( EEREC_D == 0 ); + info |= PROCESS_EE_SET_D(t0reg); + } + + if( process & PROCESS_CONSTS ) { + u32* ptempmem = _eeGetConstReg(_Rs_); + if( EEREC_D != EEREC_T ) MOVQRtoR(EEREC_D, EEREC_T); + PMULUDQMtoR(EEREC_D, (u32)ptempmem); + } + else if( process & PROCESS_CONSTT ) { + u32* ptempmem = _eeGetConstReg(_Rt_); + if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); + PMULUDQMtoR(EEREC_D, (u32)ptempmem); + } + else { + if( EEREC_D == EEREC_S ) PMULUDQRtoR(EEREC_D, EEREC_T); + else if( EEREC_D == EEREC_T ) PMULUDQRtoR(EEREC_D, EEREC_S); + else { + MOVQRtoR(EEREC_D, EEREC_S); + PMULUDQRtoR(EEREC_D, EEREC_T); + } + } + + recWritebackHILOMMX(info, EEREC_D, 1, upper); + + if( !_Rd_ ) _freeMMXreg(EEREC_D); + return; + } + + if( info & PROCESS_EE_MMX ) { + if( info & PROCESS_EE_MODEWRITES ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_].UL[0], EEREC_S); + if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; + } + if( info & PROCESS_EE_MODEWRITET ) { + MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_].UL[0], EEREC_T); + if( mmxregs[EEREC_T].reg == MMX_GPR+_Rt_ ) mmxregs[EEREC_T].mode &= ~MODE_WRITE; + } + _deleteMMXreg(MMX_GPR+_Rd_, 0); + } + + if( process & PROCESS_CONSTS ) { + MOV32ItoR( EAX, g_cpuConstRegs[_Rs_].UL[0] ); + + if( info & PROCESS_EE_MMX ) { + MOVD32MMXtoR(EDX, EEREC_T); + MUL32R(EDX); + } + else + MUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + else if( process & PROCESS_CONSTT) { + MOV32ItoR( EAX, g_cpuConstRegs[_Rt_].UL[0] ); + + if( info & PROCESS_EE_MMX ) { + MOVD32MMXtoR(EDX, EEREC_S); + MUL32R(EDX); + } + else + MUL32M( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + } + else { + if( info & PROCESS_EE_MMX ) { + MOVD32MMXtoR(EAX, EEREC_S); + MOVD32MMXtoR(EDX, EEREC_T); + MUL32R(EDX); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + } + + recWritebackHILO(info, 1, upper); +} + +void recMULTU_(int info) +{ + recMULTUsuper(info, 0, 0); +} + +void recMULTU_consts(int info) +{ + recMULTUsuper(info, 0, PROCESS_CONSTS); +} + +void recMULTU_constt(int info) +{ + recMULTUsuper(info, 0, PROCESS_CONSTT); +} + +// don't specify XMMINFO_WRITELO or XMMINFO_WRITEHI, that is taken care of +EERECOMPILE_CODE0(MULTU, XMMINFO_READS|XMMINFO_READT|(_Rd_?XMMINFO_WRITED:0)); + +//////////////////////////////////////////////////// +void recMULT1_const() +{ + u64 res = (u64)g_cpuConstRegs[_Rs_].UL[0] * (u64)g_cpuConstRegs[_Rt_].UL[0]; + + recWritebackConstHILO(res, 1, 1); +} + +void recMULT1_(int info) +{ + if( (g_pCurInstInfo->regs[XMMGPR_HI]&EEINST_LIVE2) || !(info&PROCESS_EE_MMX) ) { + recMULTsuper(info, 1, 0); + } + else recMULTUsuper(info, 1, 0); +} + +void recMULT1_consts(int info) +{ + if( (g_pCurInstInfo->regs[XMMGPR_HI]&EEINST_LIVE2) || !(info&PROCESS_EE_MMX) ) { + recMULTsuper(info, 1, PROCESS_CONSTS); + } + else recMULTUsuper(info, 1, PROCESS_CONSTS); +} + +void recMULT1_constt(int info) +{ + if( (g_pCurInstInfo->regs[XMMGPR_HI]&EEINST_LIVE2) || !(info&PROCESS_EE_MMX) ) { + recMULTsuper(info, 1, PROCESS_CONSTT); + } + else recMULTUsuper(info, 1, PROCESS_CONSTT); +} + +EERECOMPILE_CODE0(MULT1, XMMINFO_READS|XMMINFO_READT|(_Rd_?XMMINFO_WRITED:0) ); + +//////////////////////////////////////////////////// +void recMULTU1_const() +{ + u64 res = (u64)g_cpuConstRegs[_Rs_].UL[0] * (u64)g_cpuConstRegs[_Rt_].UL[0]; + + recWritebackConstHILO(res, 1, 1); +} + +void recMULTU1_(int info) +{ + recMULTUsuper(info, 1, 0); +} + +void recMULTU1_consts(int info) +{ + recMULTUsuper(info, 1, PROCESS_CONSTS); +} + +void recMULTU1_constt(int info) +{ + recMULTUsuper(info, 1, PROCESS_CONSTT); +} + +EERECOMPILE_CODE0(MULTU1, XMMINFO_READS|XMMINFO_READT|(_Rd_?XMMINFO_WRITED:0)); + +//// DIV +void recDIV_const() +{ + if (g_cpuConstRegs[_Rt_].SL[0] != 0) { + s32 quot = g_cpuConstRegs[_Rs_].SL[0] / g_cpuConstRegs[_Rt_].SL[0]; + s32 rem = g_cpuConstRegs[_Rs_].SL[0] % g_cpuConstRegs[_Rt_].SL[0]; + + recWritebackConstHILO((u64)quot|((u64)rem<<32), 0, 0); + } +} + +void recDIVsuper(int info, int sign, int upper, int process) +{ + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + + if( process & PROCESS_CONSTT ) { + if( !g_cpuConstRegs[_Rt_].UL[0] ) + return; + MOV32ItoR( ECX, g_cpuConstRegs[_Rt_].UL[0] ); + } + else { + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + + OR32RtoR( ECX, ECX ); + j8Ptr[ 0 ] = JE8( 0 ); + } + + if( process & PROCESS_CONSTS ) + MOV32ItoR( EAX, g_cpuConstRegs[_Rs_].UL[0] ); + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + } + + if( sign ) { + CDQ(); + IDIV32R( ECX ); + } + else { + XOR32RtoR( EDX, EDX ); + DIV32R( ECX ); + } + if( !(process & PROCESS_CONSTT) ) x86SetJ8( j8Ptr[ 0 ] ); + + // need to execute regardless of bad divide + recWritebackHILO(info, 0, upper); +} + +void recDIV_(int info) +{ + recDIVsuper(info, 1, 0, 0); +} + +void recDIV_consts(int info) +{ + recDIVsuper(info, 1, 0, PROCESS_CONSTS); +} + +void recDIV_constt(int info) +{ + recDIVsuper(info, 1, 0, PROCESS_CONSTT); +} + +EERECOMPILE_CODE0(DIV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITELO|XMMINFO_WRITEHI); + +//// DIVU +void recDIVU_const() +{ + if (g_cpuConstRegs[_Rt_].UL[0] != 0) { + u32 quot = g_cpuConstRegs[_Rs_].UL[0] / g_cpuConstRegs[_Rt_].UL[0]; + u32 rem = g_cpuConstRegs[_Rs_].UL[0] % g_cpuConstRegs[_Rt_].UL[0]; + + recWritebackConstHILO((u64)quot|((u64)rem<<32), 0, 0); + } +} + +void recDIVU_(int info) +{ + recDIVsuper(info, 0, 0, 0); +} + +void recDIVU_consts(int info) +{ + recDIVsuper(info, 0, 0, PROCESS_CONSTS); +} + +void recDIVU_constt(int info) +{ + recDIVsuper(info, 0, 0, PROCESS_CONSTT); +} + +EERECOMPILE_CODE0(DIVU, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITELO|XMMINFO_WRITEHI); + +void recDIV1_const() +{ + if (g_cpuConstRegs[_Rt_].SL[0] != 0) { + s32 quot = g_cpuConstRegs[_Rs_].SL[0] / g_cpuConstRegs[_Rt_].SL[0]; + s32 rem = g_cpuConstRegs[_Rs_].SL[0] % g_cpuConstRegs[_Rt_].SL[0]; + + recWritebackConstHILO((u64)quot|((u64)rem<<32), 0, 1); + } +} + +void recDIV1_(int info) +{ + recDIVsuper(info, 1, 1, 0); +} + +void recDIV1_consts(int info) +{ + recDIVsuper(info, 1, 1, PROCESS_CONSTS); +} + +void recDIV1_constt(int info) +{ + recDIVsuper(info, 1, 1, PROCESS_CONSTT); +} + +EERECOMPILE_CODE0(DIV1, XMMINFO_READS|XMMINFO_READT); + +void recDIVU1_const() +{ + if (g_cpuConstRegs[_Rt_].UL[0] != 0) { + u32 quot = g_cpuConstRegs[_Rs_].UL[0] / g_cpuConstRegs[_Rt_].UL[0]; + u32 rem = g_cpuConstRegs[_Rs_].UL[0] % g_cpuConstRegs[_Rt_].UL[0]; + + recWritebackConstHILO((u64)quot|((u64)rem<<32), 0, 1); + } +} + +void recDIVU1_(int info) +{ + recDIVsuper(info, 0, 1, 0); +} + +void recDIVU1_consts(int info) +{ + recDIVsuper(info, 0, 1, PROCESS_CONSTS); +} + +void recDIVU1_constt(int info) +{ + recDIVsuper(info, 0, 1, PROCESS_CONSTT); +} + +EERECOMPILE_CODE0(DIVU1, XMMINFO_READS|XMMINFO_READT); + +//do EEINST_SETSIGNEXT +REC_FUNC_DEL( MADD, _Rd_ ); + +static PCSX2_ALIGNED16(u32 s_MaddMask[]) = { 0x80000000, 0, 0x80000000, 0 }; + +void recMADDU() +{ + _eeOnWriteReg(_Rd_, 1); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + + if( GPR_IS_CONST2(_Rs_, _Rt_) ) { + u64 result = ((u64)g_cpuConstRegs[_Rs_].UL[0] * (u64)g_cpuConstRegs[_Rt_].UL[0]); + _deleteEEreg(XMMGPR_LO, 1); + _deleteEEreg(XMMGPR_HI, 1); + + // dadd + MOV32MtoR( EAX, (int)&cpuRegs.LO.UL[ 0 ] ); + MOV32MtoR( ECX, (int)&cpuRegs.HI.UL[ 0 ] ); + ADD32ItoR( EAX, (u32)result&0xffffffff ); + ADC32ItoR( ECX, (u32)(result>>32) ); + CDQ(); + if( _Rd_) { + _deleteEEreg(_Rd_, 0); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + + MOV32RtoM( (int)&cpuRegs.LO.UL[0], EAX ); + MOV32RtoM( (int)&cpuRegs.LO.UL[1], EDX ); + + MOV32RtoM( (int)&cpuRegs.HI.UL[0], ECX ); + MOV32RtoR(EAX, ECX); + CDQ(); + MOV32RtoM( (int)&cpuRegs.HI.UL[1], EDX ); + return; + } + + _deleteEEreg(XMMGPR_LO, 1); + _deleteEEreg(XMMGPR_HI, 1); + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 1); + _deleteMMXreg(MMX_GPR+_Rs_, 1); + _deleteMMXreg(MMX_GPR+_Rt_, 1); + + if( GPR_IS_CONST1(_Rs_) ) { + MOV32ItoR( EAX, g_cpuConstRegs[_Rs_].UL[0] ); + IMUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + else if ( GPR_IS_CONST1(_Rt_) ) { + MOV32ItoR( EAX, g_cpuConstRegs[_Rt_].UL[0] ); + IMUL32M( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + IMUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + } + + MOV32RtoR( ECX, EDX ); + ADD32MtoR( EAX, (u32)&cpuRegs.LO.UL[0] ); + ADC32MtoR( ECX, (u32)&cpuRegs.HI.UL[0] ); + CDQ(); + if( _Rd_ ) { + _deleteEEreg(_Rd_, 0); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + + MOV32RtoM( (int)&cpuRegs.LO.UL[0], EAX ); + MOV32RtoM( (int)&cpuRegs.LO.UL[1], EDX ); + + MOV32RtoM( (int)&cpuRegs.HI.UL[0], ECX ); + MOV32RtoR(EAX, ECX); + CDQ(); + MOV32RtoM( (int)&cpuRegs.HI.UL[1], EDX ); +} + +void recMADD1() +{ + //SysPrintf("MADD1 email zero if abnormal behavior\n"); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); + _deleteEEreg(XMMGPR_LO, 0); + _deleteEEreg(XMMGPR_HI, 0); + recCall( Interp::MADD1, _Rd_ ); +} + +void recMADDU1() +{ + //SysPrintf("MADDU1 email zero if abnormal behavior\n"); + EEINST_SETSIGNEXT(_Rs_); + EEINST_SETSIGNEXT(_Rt_); + if( _Rd_ ) EEINST_SETSIGNEXT(_Rd_); + _deleteEEreg(XMMGPR_LO, 0); + _deleteEEreg(XMMGPR_HI, 0); + recCall( Interp::MADDU1, _Rd_ ); +} + +#else + +//////////////////////////////////////////////////// +void recMULT( void ) +{ + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + IMUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + + MOV32RtoR( ECX, EDX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.LO.UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.LO.UL[ 1 ], EDX ); + if ( _Rd_ ) + { + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + MOV32RtoR( EAX, ECX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.HI.UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.HI.UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +void recMULTU( void ) +{ + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + MUL32M( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + + MOV32RtoR( ECX, EDX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.LO.UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.LO.UL[ 1 ], EDX ); + if ( _Rd_ != 0 ) + { + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + MOV32RtoR( EAX, ECX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.HI.UL[ 0 ], ECX ); + MOV32RtoM( (int)&cpuRegs.HI.UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +void recDIV( void ) +{ + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + OR32RtoR( ECX, ECX ); + j8Ptr[ 0 ] = JE8( 0 ); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); +// XOR32RtoR( EDX,EDX ); + CDQ(); + IDIV32R( ECX ); + + MOV32RtoR( ECX, EDX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.LO.UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.LO.UL[ 1 ], EDX ); + + MOV32RtoR( EAX, ECX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.HI.UL[ 0 ], ECX ); + MOV32RtoM( (int)&cpuRegs.HI.UL[ 1 ], EDX ); + + x86SetJ8( j8Ptr[ 0 ] ); + +} + +//////////////////////////////////////////////////// +void recDIVU( void ) +{ + + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + OR32RtoR( ECX, ECX ); + j8Ptr[ 0 ] = JE8( 0 ); + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + XOR32RtoR( EDX, EDX ); + // CDQ(); + DIV32R( ECX ); + + MOV32RtoR( ECX, EDX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.LO.UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.LO.UL[ 1 ], EDX ); + + MOV32RtoR( EAX,ECX ); + CDQ( ); + MOV32RtoM( (int)&cpuRegs.HI.UL[ 0 ], ECX ); + MOV32RtoM( (int)&cpuRegs.HI.UL[ 1 ], EDX ); + x86SetJ8( j8Ptr[ 0 ] ); + +} + +REC_FUNC_DEL( MULT1, _Rd_ ); +REC_FUNC_DEL( MULTU1, _Rd_ ); +REC_FUNC_DEL( DIV1, _Rd_ ); +REC_FUNC_DEL( DIVU1, _Rd_ ); + +REC_FUNC_DEL( MADD, _Rd_ ); +REC_FUNC_DEL( MADDU, _Rd_ ); +REC_FUNC_DEL( MADD1, _Rd_ ); +REC_FUNC_DEL( MADDU1, _Rd_ ); + +#endif + +} } } diff --git a/pcsx2/x86/ix86-32/iR5900Shift.cpp b/pcsx2/x86/ix86-32/iR5900Shift.cpp index 780bc0314c..3957f5ef8c 100644 --- a/pcsx2/x86/ix86-32/iR5900Shift.cpp +++ b/pcsx2/x86/ix86-32/iR5900Shift.cpp @@ -1,1351 +1,1351 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "R5900OpcodeTables.h" -#include "ix86/ix86.h" -#include "iR5900.h" - - -namespace R5900 { -namespace Dynarec { -namespace OpcodeImpl -{ - -/********************************************************* -* Shift arithmetic with constant shift * -* Format: OP rd, rt, sa * -*********************************************************/ -#ifndef SHIFT_RECOMPILE - -namespace Interp = R5900::Interpreter::OpcodeImpl; - -REC_FUNC(SLL); -REC_FUNC(SRL); -REC_FUNC(SRA); -REC_FUNC(DSLL); -REC_FUNC(DSRL); -REC_FUNC(DSRA); -REC_FUNC(DSLL32); -REC_FUNC(DSRL32); -REC_FUNC(DSRA32); - -REC_FUNC(SLLV); -REC_FUNC(SRLV); -REC_FUNC(SRAV); -REC_FUNC(DSLLV); -REC_FUNC(DSRLV); -REC_FUNC(DSRAV); - -#elif defined(EE_CONST_PROP) - -//// SLL -void recSLL_const() -{ - g_cpuConstRegs[_Rd_].SD[0] = (s32)(g_cpuConstRegs[_Rt_].UL[0] << _Sa_); -} - -void recSLLs_(int info, int sa) -{ - int rtreg, rdreg, t0reg; - assert( !(info & PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - rtreg = EEREC_T; - rdreg = EEREC_D; - } - else if( g_pCurInstInfo->regs[_Rd_]&EEINST_MMX ) { - _addNeededMMXreg(MMX_GPR+_Rd_); - rtreg = rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - MOVDMtoMMX(rtreg, (u32)&cpuRegs.GPR.r[_Rt_].UL[0]); - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - if ( sa != 0 ) - { - SHL32ItoR( EAX, sa ); - } - - if( EEINST_ISLIVE1(_Rd_) ) { - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - } - else { - EEINST_RESETHASLIVE1(_Rd_); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - } - return; - } - - if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); - - if( !EEINST_ISLIVE1(_Rd_) ) { - EEINST_RESETHASLIVE1(_Rd_); - PSLLDItoR(rdreg, sa); - return; - } - - if ( sa != 0 ) { - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - - // it is a signed shift - PSLLDItoR(rdreg, sa); - MOVQRtoR(t0reg, rdreg); - PSRADItoR(t0reg, 31); - - // take lower dword of rdreg and lower dword of t0reg - PUNPCKLDQRtoR(rdreg, t0reg); - _freeMMXreg(t0reg); - } - else { - if( EEINST_ISLIVE1(_Rd_) ) _signExtendGPRtoMMX(rdreg, _Rd_, 0); - else EEINST_RESETHASLIVE1(_Rd_); - } -} - -void recSLL_(int info) -{ - recSLLs_(info, _Sa_); - EEINST_SETSIGNEXT(_Rd_); -} - -EERECOMPILE_CODEX(eeRecompileCode2, SLL); - -//// SRL -void recSRL_const() -{ - g_cpuConstRegs[_Rd_].SD[0] = (s32)(g_cpuConstRegs[_Rt_].UL[0] >> _Sa_); -} - -void recSRLs_(int info, int sa) -{ - int rtreg, rdreg; - assert( !(info & PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - rtreg = EEREC_T; - rdreg = EEREC_D; - } - else if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { - _addNeededMMXreg(MMX_GPR+_Rd_); - rtreg = rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - MOVDMtoMMX(rtreg, (u32)&cpuRegs.GPR.r[_Rt_].UL[0]); - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - if ( sa != 0 ) SHR32ItoR( EAX, sa); - - if( EEINST_ISLIVE1(_Rd_) ) { - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - } - else { - EEINST_RESETHASLIVE1(_Rd_); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - } - return; - } - - if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); - - if( !EEINST_ISLIVE1(_Rd_) ) { - EEINST_RESETHASLIVE1(_Rd_); - PSRLDItoR(rdreg, sa); - return; - } - - if ( sa != 0 ) { - // rdreg already sign extended - PSLLQItoR(rdreg, 32); - PSRLQItoR(rdreg, 32+sa); -// t0reg = _allocMMXreg(-1, MMX_TEMP, 0); -// -// // it is a signed shift -// PSRLDItoR(rdreg, sa); -// MOVQRtoR(t0reg, rdreg); -// PSRADItoR(t0reg, 31); -// -// take lower dword of rdreg and lower dword of t0reg -// PUNPCKLDQRtoR(rdreg, t0reg); -// _freeMMXreg(t0reg); - } -} - -void recSRL_(int info) -{ - recSRLs_(info, _Sa_); - EEINST_SETSIGNEXT(_Rd_); -} - -EERECOMPILE_CODEX(eeRecompileCode2, SRL); - -//// SRA -void recSRA_const() -{ - g_cpuConstRegs[_Rd_].SD[0] = (s32)(g_cpuConstRegs[_Rt_].SL[0] >> _Sa_); -} - -void recSRAs_(int info, int sa) -{ - int rtreg, rdreg, t0reg; - assert( !(info & PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - rtreg = EEREC_T; - rdreg = EEREC_D; - } - else if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { - _addNeededMMXreg(MMX_GPR+_Rd_); - rtreg = rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - MOVDMtoMMX(rtreg, (u32)&cpuRegs.GPR.r[_Rt_].UL[0]); - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - if ( sa != 0 ) SAR32ItoR( EAX, sa); - - if( EEINST_ISLIVE1(_Rd_) ) { - CDQ(); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - } - else { - EEINST_RESETHASLIVE1(_Rd_); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - } - return; - } - - if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); - - if( EEINST_ISSIGNEXT(_Rt_) && EEINST_HASLIVE1(_Rt_) ) { - PSRADItoR(rdreg, sa); - return; - } - - if( !EEINST_ISLIVE1(_Rd_) ) { - EEINST_RESETHASLIVE1(_Rd_); - PSRADItoR(rdreg, sa); - return; - } - - if ( sa != 0 ) { - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - - // it is a signed shift - PSRADItoR(rdreg, sa); - MOVQRtoR(t0reg, rdreg); - PSRADItoR(rdreg, 31); - - // take lower dword of rdreg and lower dword of t0reg - PUNPCKLDQRtoR(t0reg, rdreg); - - // swap regs - mmxregs[t0reg] = mmxregs[rdreg]; - mmxregs[rdreg].inuse = 0; - } -} - -void recSRA_(int info) -{ - recSRAs_(info, _Sa_); - EEINST_SETSIGNEXT(_Rd_); -} - -EERECOMPILE_CODEX(eeRecompileCode2, SRA); - -//////////////////////////////////////////////////// -void recDSLL_const() -{ - g_cpuConstRegs[_Rd_].UD[0] = (u64)(g_cpuConstRegs[_Rt_].UD[0] << _Sa_); -} - -void recDSLLs_(int info, int sa) -{ - int rtreg, rdreg; - assert( !(info & PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - rtreg = EEREC_T; - rdreg = EEREC_D; - } - else { - _addNeededMMXreg(MMX_GPR+_Rt_); - _addNeededMMXreg(MMX_GPR+_Rd_); - rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); - rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - } - - if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); - PSLLQItoR(rdreg, sa); -} - -void recDSLL_(int info) -{ - recDSLLs_(info, _Sa_); -} - -EERECOMPILE_CODEX(eeRecompileCode2, DSLL); - -//////////////////////////////////////////////////// -void recDSRL_const() -{ - g_cpuConstRegs[_Rd_].UD[0] = (u64)(g_cpuConstRegs[_Rt_].UD[0] >> _Sa_); -} - -void recDSRLs_(int info, int sa) -{ - int rtreg, rdreg; - assert( !(info & PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - rtreg = EEREC_T; - rdreg = EEREC_D; - } - else { - _addNeededMMXreg(MMX_GPR+_Rt_); - _addNeededMMXreg(MMX_GPR+_Rd_); - rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); - rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - } - - if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); - PSRLQItoR(rdreg, sa); -} - -void recDSRL_(int info) -{ - recDSRLs_(info, _Sa_); -} - -EERECOMPILE_CODEX(eeRecompileCode2, DSRL); - -//// DSRA -void recDSRA_const() -{ - g_cpuConstRegs[_Rd_].SD[0] = (u64)(g_cpuConstRegs[_Rt_].SD[0] >> _Sa_); -} - -void recDSRAs_(int info, int sa) -{ - int rtreg, rdreg, t0reg; - assert( !(info & PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - rtreg = EEREC_T; - rdreg = EEREC_D; - } - else { - _addNeededMMXreg(MMX_GPR+_Rt_); - _addNeededMMXreg(MMX_GPR+_Rd_); - rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); - rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - } - - if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); - - if( EEINST_ISSIGNEXT(_Rt_) && EEINST_HASLIVE1(_Rt_) ) { - PSRADItoR(rdreg, sa); - return; - } - - if( !EEINST_ISLIVE1(_Rd_) ) { - EEINST_RESETHASLIVE1(_Rd_); - PSRLQItoR(rdreg, sa); - return; - } - - if ( sa != 0 ) { - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQRtoR(t0reg, rtreg); - - // it is a signed shift - PSRADItoR(t0reg, sa); - PSRLQItoR(rdreg, sa); - - PUNPCKHDQRtoR(t0reg, t0reg); // shift to lower - // take lower dword of rdreg and lower dword of t0reg - PUNPCKLDQRtoR(rdreg, t0reg); - - _freeMMXreg(t0reg); - } -} - -void recDSRA_(int info) -{ - recDSRAs_(info, _Sa_); -} - -EERECOMPILE_CODEX(eeRecompileCode2, DSRA); - -///// DSLL32 -void recDSLL32_const() -{ - g_cpuConstRegs[_Rd_].UD[0] = (u64)(g_cpuConstRegs[_Rt_].UD[0] << (_Sa_+32)); -} - -void recDSLL32s_(int info, int sa) -{ - int rtreg, rdreg; - assert( !(info & PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - rtreg = EEREC_T; - rdreg = EEREC_D; - } - else if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { - _addNeededMMXreg(MMX_GPR+_Rt_); - _addNeededMMXreg(MMX_GPR+_Rd_); - rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); - rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - if ( sa != 0 ) - { - SHL32ItoR( EAX, sa ); - } - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], 0 ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EAX ); - return; - } - - if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); - PSLLQItoR(rdreg, sa+32); -} - -void recDSLL32_(int info) -{ - recDSLL32s_(info, _Sa_); -} - -EERECOMPILE_CODEX(eeRecompileCode2, DSLL32); - -//// DSRL32 -void recDSRL32_const() -{ - g_cpuConstRegs[_Rd_].UD[0] = (u64)(g_cpuConstRegs[_Rt_].UD[0] >> (_Sa_+32)); -} - -void recDSRL32s_(int info, int sa) -{ - int rtreg, rdreg; - assert( !(info & PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - rtreg = EEREC_T; - rdreg = EEREC_D; - } - else if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { - _addNeededMMXreg(MMX_GPR+_Rt_); - _addNeededMMXreg(MMX_GPR+_Rd_); - rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); - rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - if ( sa != 0 ) SHR32ItoR( EAX, sa ); - - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - if( EEINST_ISLIVE1(_Rd_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); - else EEINST_RESETHASLIVE1(_Rd_); - return; - } - - if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); - PSRLQItoR(rdreg, sa+32); -} - -void recDSRL32_(int info) -{ - recDSRL32s_(info, _Sa_); -} - -EERECOMPILE_CODEX(eeRecompileCode2, DSRL32); - -//// DSRA32 -void recDSRA32_const() -{ - g_cpuConstRegs[_Rd_].SD[0] = (u64)(g_cpuConstRegs[_Rt_].SD[0] >> (_Sa_+32)); -} - -void recDSRA32s_(int info, int sa) -{ - int rtreg, rdreg, t0reg; - assert( !(info & PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - rtreg = EEREC_T; - rdreg = EEREC_D; - } - else if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { - _addNeededMMXreg(MMX_GPR+_Rt_); - _addNeededMMXreg(MMX_GPR+_Rd_); - rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); - rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - } - else { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - CDQ( ); - if ( sa != 0 ) SAR32ItoR( EAX, sa ); - - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - if( EEINST_ISLIVE1(_Rd_) ) MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - else EEINST_RESETHASLIVE1(_Rd_); - return; - } - - if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); - - if( EEINST_ISSIGNEXT(_Rt_) && EEINST_HASLIVE1(_Rt_) ) { - PSRADItoR(rdreg, 31); - return; - } - - if( !EEINST_ISLIVE1(_Rd_) ) { - EEINST_RESETHASLIVE1(_Rd_); - if( sa ) PSRADItoR(rdreg, sa); - PUNPCKHDQRtoR(rdreg, rdreg); - return; - } - - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQRtoR(t0reg, rtreg); - - // it is a signed shift - if( sa ) { - PSRADItoR(rdreg, sa); - PSRADItoR(t0reg, 31); - - // take higher dword of rdreg and lower dword of t0reg - PUNPCKHDQRtoR(rdreg, t0reg); - _freeMMXreg(t0reg); - } - else { - // better timing - PSRADItoR(rdreg, 31); - - // take higher dword of rdreg and lower dword of t0reg - PUNPCKHDQRtoR(t0reg, rdreg); - - // swap - mmxregs[t0reg] = mmxregs[rdreg]; - mmxregs[rdreg].inuse = 0; - } -} - -void recDSRA32_(int info) -{ - recDSRA32s_(info, _Sa_); -} - -EERECOMPILE_CODEX(eeRecompileCode2, DSRA32); - -/********************************************************* -* Shift arithmetic with variant register shift * -* Format: OP rd, rt, rs * -*********************************************************/ - -PCSX2_ALIGNED16(u32 s_sa[4]) = {0x1f, 0, 0x3f, 0}; - -int recSetShiftV(int info, int* rsreg, int* rtreg, int* rdreg, int* rstemp, int forcemmx, int shift64) -{ - assert( !(info & PROCESS_EE_XMM) ); - - if( info & PROCESS_EE_MMX ) { - *rtreg = EEREC_T; - *rdreg = EEREC_D; - *rsreg = EEREC_S; - - // make sure to take only low 5 bits of *rsreg - if( !(g_pCurInstInfo->regs[_Rs_]&EEINST_LASTUSE) && EEINST_ISLIVE64(_Rs_)) { - *rstemp = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQRtoR(*rstemp, *rsreg); - *rsreg = *rstemp; - } - else { - if( *rsreg != *rdreg ) { - _freeMMXreg(*rsreg); - mmxregs[*rsreg].inuse = 0; - } - } - - PANDMtoR(*rsreg, (u32)&s_sa[shift64?2:0]); - - if( EEREC_D == EEREC_S ) { - // need to be separate - int mmreg = _allocMMXreg(-1, MMX_TEMP, 0); - *rdreg = mmreg; - mmxregs[mmreg] = mmxregs[EEREC_S]; - mmxregs[EEREC_S].inuse = 0; - } - } - else if( forcemmx || (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { - _addNeededMMXreg(MMX_GPR+_Rt_); - _addNeededMMXreg(MMX_GPR+_Rd_); - *rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); - *rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - - *rstemp = _allocMMXreg(-1, MMX_TEMP, 0); - MOV32MtoR(EAX, (u32)&cpuRegs.GPR.r[_Rs_].UL[0]); - AND32ItoR(EAX, shift64?0x3f:0x1f); - MOVD32RtoMMX(*rstemp, EAX); - *rsreg = *rstemp; - } - else { - return 0; - } - - if( *rtreg != *rdreg ) MOVQRtoR(*rdreg, *rtreg); - return 1; -} - -void recSetConstShiftV(int info, int* rsreg, int* rdreg, int* rstemp, int shift64) -{ - if( info & PROCESS_EE_MMX ) { - *rdreg = EEREC_D; - *rsreg = EEREC_S; - - // make sure to take only low 5 bits of *rsreg - if( !(g_pCurInstInfo->regs[_Rs_]&EEINST_LASTUSE) && EEINST_ISLIVE64(_Rs_) ) { - *rstemp = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQRtoR(*rstemp, *rsreg); - *rsreg = *rstemp; - } - else { - if( *rsreg != *rdreg ) { - _freeMMXreg(*rsreg); - mmxregs[*rsreg].inuse = 0; - } - } - - PANDMtoR(*rsreg, (u32)&s_sa[shift64?2:0]); - - - if( EEREC_D == EEREC_S ) { - // need to be separate - int mmreg = _allocMMXreg(-1, MMX_TEMP, 0); - *rdreg = mmreg; - mmxregs[mmreg] = mmxregs[EEREC_S]; - mmxregs[EEREC_S].inuse = 0; - } - } - else { - _addNeededMMXreg(MMX_GPR+_Rd_); - *rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - SetMMXstate(); - - *rstemp = _allocMMXreg(-1, MMX_TEMP, 0); - MOV32MtoR(EAX, (u32)&cpuRegs.GPR.r[_Rs_].UL[0]); - AND32ItoR(EAX, shift64?0x3f:0x1f); - MOVD32RtoMMX(*rstemp, EAX); - *rsreg = *rstemp; - } - - _flushConstReg(_Rt_); -} - -void recMoveSignToRd(int info) -{ - if( EEINST_ISLIVE1(_Rd_) ) { - CDQ(); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - } - else { - EEINST_RESETHASLIVE1(_Rd_); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - } - - if( info & PROCESS_EE_MMX ) { - mmxregs[EEREC_D].inuse = 0; - } -} - -//// SLLV -void recSLLV_const() -{ - g_cpuConstRegs[_Rd_].SD[0] = (s32)(g_cpuConstRegs[_Rt_].UL[0] << (g_cpuConstRegs[_Rs_].UL[0] &0x1f)); -} - -void recSLLV_consts(int info) -{ - recSLLs_(info, g_cpuConstRegs[_Rs_].UL[0]&0x1f); - EEINST_SETSIGNEXT(_Rd_); -} - -void recSLLV_constt(int info) -{ - if( (info & PROCESS_EE_MMX) && (info & PROCESS_EE_MODEWRITES) ) MOVD32MMXtoR(ECX, EEREC_S); - else MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - - MOV32ItoR( EAX, g_cpuConstRegs[_Rt_].UL[0] ); - AND32ItoR( ECX, 0x1f ); - SHL32CLtoR( EAX ); - - recMoveSignToRd(info); - EEINST_SETSIGNEXT(_Rd_); -} - -void recSLLV_(int info) -{ - int rsreg, rtreg, rdreg, rstemp = -1, t0reg; - EEINST_SETSIGNEXT(_Rd_); - - if( recSetShiftV(info, &rsreg, &rtreg, &rdreg, &rstemp, 0, 0) == 0 ) { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - if ( _Rs_ != 0 ) - { - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - AND32ItoR( ECX, 0x1f ); - SHL32CLtoR( EAX ); - } - CDQ(); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - return; - } - - if( !EEINST_ISLIVE1(_Rd_) ) { - EEINST_RESETHASLIVE1(_Rd_); - PSLLDRtoR(rdreg, rsreg); - if( rstemp != -1 ) _freeMMXreg(rstemp); - return; - } - - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - - // it is a signed shift - PSLLDRtoR(rdreg, rsreg); - MOVQRtoR(t0reg, rdreg); - PSRADItoR(t0reg, 31); - - // take lower dword of rdreg and lower dword of t0reg - PUNPCKLDQRtoR(rdreg, t0reg); - _freeMMXreg(t0reg); - if( rstemp != -1 ) _freeMMXreg(rstemp); -} - -EERECOMPILE_CODE0(SLLV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); - -//// SRLV -void recSRLV_const() -{ - g_cpuConstRegs[_Rd_].SD[0] = (s32)(g_cpuConstRegs[_Rt_].UL[0] >> (g_cpuConstRegs[_Rs_].UL[0] &0x1f)); -} - -void recSRLV_consts(int info) -{ - recSRLs_(info, g_cpuConstRegs[_Rs_].UL[0]&0x1f); - EEINST_SETSIGNEXT(_Rd_); -} - -void recSRLV_constt(int info) -{ - if( (info & PROCESS_EE_MMX) && (info&PROCESS_EE_MODEWRITES) ) MOVD32MMXtoR(ECX, EEREC_S); - else MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - - MOV32ItoR( EAX, g_cpuConstRegs[_Rt_].UL[0] ); - AND32ItoR( ECX, 0x1f ); - SHR32CLtoR( EAX ); - - recMoveSignToRd(info); - EEINST_SETSIGNEXT(_Rd_); -} - -void recSRLV_(int info) -{ - int rsreg, rtreg, rdreg, rstemp = -1, t0reg; - EEINST_SETSIGNEXT(_Rd_); - - if( recSetShiftV(info, &rsreg, &rtreg, &rdreg, &rstemp, 0, 0) == 0 ) { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - if ( _Rs_ != 0 ) - { - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - AND32ItoR( ECX, 0x1f ); - SHR32CLtoR( EAX ); - } - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - return; - } - - if( !EEINST_ISLIVE1(_Rd_) ) { - EEINST_RESETHASLIVE1(_Rd_); - PSRLDRtoR(rdreg, rsreg); - if( rstemp != -1 ) _freeMMXreg(rstemp); - return; - } - - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - - // it is a signed shift - PSRLDRtoR(rdreg, rsreg); - MOVQRtoR(t0reg, rdreg); - PSRADItoR(t0reg, 31); - - // take lower dword of rdreg and lower dword of t0reg - PUNPCKLDQRtoR(rdreg, t0reg); - _freeMMXreg(t0reg); - if( rstemp != -1 ) _freeMMXreg(rstemp); -} - -EERECOMPILE_CODE0(SRLV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); - -//// SRAV -void recSRAV_const() -{ - g_cpuConstRegs[_Rd_].SD[0] = (s32)(g_cpuConstRegs[_Rt_].SL[0] >> (g_cpuConstRegs[_Rs_].UL[0] &0x1f)); -} - -void recSRAV_consts(int info) -{ - recSRAs_(info, g_cpuConstRegs[_Rs_].UL[0]&0x1f); - EEINST_SETSIGNEXT(_Rd_); -} - -void recSRAV_constt(int info) -{ - if( (info & PROCESS_EE_MMX) && (info&PROCESS_EE_MODEWRITES) ) MOVD32MMXtoR(ECX, EEREC_S); - else MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - - MOV32ItoR( EAX, g_cpuConstRegs[_Rt_].UL[0] ); - AND32ItoR( ECX, 0x1f ); - SAR32CLtoR( EAX ); - - recMoveSignToRd(info); - EEINST_SETSIGNEXT(_Rd_); -} - -void recSRAV_(int info) -{ - int rsreg, rtreg, rdreg, rstemp = -1, t0reg; - EEINST_SETSIGNEXT(_Rd_); - - if( recSetShiftV(info, &rsreg, &rtreg, &rdreg, &rstemp, 0, 0) == 0 ) { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - if ( _Rs_ != 0 ) - { - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - AND32ItoR( ECX, 0x1f ); - SAR32CLtoR( EAX ); - } - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - return; - } - - if( !EEINST_ISLIVE1(_Rd_) ) { - EEINST_RESETHASLIVE1(_Rd_); - PSRADRtoR(rdreg, rsreg); - if( rstemp != -1 ) _freeMMXreg(rstemp); - return; - } - - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - - // it is a signed shift - PSRADRtoR(rdreg, rsreg); - MOVQRtoR(t0reg, rdreg); - PSRADItoR(t0reg, 31); - - // take lower dword of rdreg and lower dword of t0reg - PUNPCKLDQRtoR(rdreg, t0reg); - _freeMMXreg(t0reg); - if( rstemp != -1 ) _freeMMXreg(rstemp); -} - -EERECOMPILE_CODE0(SRAV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); - -//// DSLLV -void recDSLLV_const() -{ - g_cpuConstRegs[_Rd_].UD[0] = (u64)(g_cpuConstRegs[_Rt_].UD[0] << (g_cpuConstRegs[_Rs_].UL[0] &0x3f)); -} - -void recDSLLV_consts(int info) -{ - int sa = g_cpuConstRegs[_Rs_].UL[0]&0x3f; - if( sa < 32 ) recDSLLs_(info, sa); - else recDSLL32s_(info, sa-32); -} - -void recDSLLV_constt(int info) -{ - int rsreg, rdreg, rstemp = -1; - recSetConstShiftV(info, &rsreg, &rdreg, &rstemp, 1); - - MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[_Rt_]); - PSLLQRtoR(rdreg, rsreg); - if( rstemp != -1 ) _freeMMXreg(rstemp); -} - -void recDSLLV_(int info) -{ - int rsreg, rtreg, rdreg, rstemp = -1; - recSetShiftV(info, &rsreg, &rtreg, &rdreg, &rstemp, 1, 1); - - PSLLQRtoR(rdreg, rsreg); - if( rstemp != -1 ) _freeMMXreg(rstemp); -} - -EERECOMPILE_CODE0(DSLLV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); - -//// DSRLV -void recDSRLV_const() -{ - g_cpuConstRegs[_Rd_].UD[0] = (u64)(g_cpuConstRegs[_Rt_].UD[0] >> (g_cpuConstRegs[_Rs_].UL[0] &0x3f)); -} - -void recDSRLV_consts(int info) -{ - int sa = g_cpuConstRegs[_Rs_].UL[0]&0x3f; - if( sa < 32 ) recDSRLs_(info, sa); - else recDSRL32s_(info, sa-32); -} - -void recDSRLV_constt(int info) -{ - int rsreg, rdreg, rstemp = -1; - recSetConstShiftV(info, &rsreg, &rdreg, &rstemp, 1); - - MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[_Rt_]); - PSRLQRtoR(rdreg, rsreg); - if( rstemp != -1 ) _freeMMXreg(rstemp); -} - -void recDSRLV_(int info) -{ - int rsreg, rtreg, rdreg, rstemp = -1; - recSetShiftV(info, &rsreg, &rtreg, &rdreg, &rstemp, 1, 1); - - PSRLQRtoR(rdreg, rsreg); - if( rstemp != -1 ) _freeMMXreg(rstemp); -} - -EERECOMPILE_CODE0(DSRLV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); - -//// DSRAV -void recDSRAV_const() -{ - g_cpuConstRegs[_Rd_].SD[0] = (s64)(g_cpuConstRegs[_Rt_].SD[0] >> (g_cpuConstRegs[_Rs_].UL[0] &0x3f)); -} - -void recDSRAV_consts(int info) -{ - int sa = g_cpuConstRegs[_Rs_].UL[0]&0x3f; - if( sa < 32 ) recDSRAs_(info, sa); - else recDSRA32s_(info, sa-32); -} - -void recDSRAV_constt(int info) -{ - int rsreg, rdreg, rstemp = -1, t0reg, t1reg; - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - t1reg = _allocMMXreg(-1, MMX_TEMP, 0); - - recSetConstShiftV(info, &rsreg, &rdreg, &rstemp, 1); - - MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[_Rt_]); - PXORRtoR(t0reg, t0reg); - - // calc high bit - MOVQRtoR(t1reg, rdreg); - PCMPGTDRtoR(t0reg, rdreg); - PUNPCKHDQRtoR(t0reg, t0reg); // shift to lower - - // shift highest bit, 64 - eax - MOV32ItoR(EAX, 64); - MOVD32RtoMMX(t1reg, EAX); - PSUBDRtoR(t1reg, rsreg); - - // right logical shift - PSRLQRtoR(rdreg, rsreg); - PSLLQRtoR(t0reg, t1reg); // highest bits - - PORRtoR(rdreg, t0reg); - - _freeMMXreg(t0reg); - _freeMMXreg(t1reg); - if( rstemp != -1 ) _freeMMXreg(rstemp); -} - -void recDSRAV_(int info) -{ - int rsreg, rtreg, rdreg, rstemp = -1, t0reg, t1reg; - t0reg = _allocMMXreg(-1, MMX_TEMP, 0); - t1reg = _allocMMXreg(-1, MMX_TEMP, 0); - recSetShiftV(info, &rsreg, &rtreg, &rdreg, &rstemp, 1, 1); - - PXORRtoR(t0reg, t0reg); - - // calc high bit - MOVQRtoR(t1reg, rdreg); - PCMPGTDRtoR(t0reg, rdreg); - PUNPCKHDQRtoR(t0reg, t0reg); // shift to lower - - // shift highest bit, 64 - eax - MOV32ItoR(EAX, 64); - MOVD32RtoMMX(t1reg, EAX); - PSUBDRtoR(t1reg, rsreg); - - // right logical shift - PSRLQRtoR(rdreg, rsreg); - PSLLQRtoR(t0reg, t1reg); // highest bits - - PORRtoR(rdreg, t0reg); - - _freeMMXreg(t0reg); - _freeMMXreg(t1reg); - if( rstemp != -1 ) _freeMMXreg(rstemp); -} - -EERECOMPILE_CODE0(DSRAV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); - -#else - -//////////////////////////////////////////////////// -void recDSRA( void ) -{ - if( !_Rd_ ) return; //? - - if ( _Sa_ != 0 ) { - // it is a signed shift - MOVQMtoR(MM0, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - MOVQRtoR(MM1, MM0); - PSRADItoR(MM0, _Sa_); - PSRLQItoR(MM1, _Sa_); - - PUNPCKHDQRtoR(MM0, MM0); // shift to lower - // take lower dword of MM1 and lower dword of MM0 - - PUNPCKLDQRtoR(MM1, MM0); - - MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], MM1); - } - else { - MOVQMtoR(MM0, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], MM0); - } - - SetMMXstate(); -} - -//////////////////////////////////////////////////// -void recDSRA32(void) -{ - if( !_Rd_ ) return; //? - - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - CDQ(); - - if ( _Sa_ != 0 ) - { - SAR32ItoR( EAX, _Sa_ ); - } - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX); - MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX); -} - -//////////////////////////////////////////////////// -void recSLL( void ) -{ - if ( ! _Rd_ ) - return; - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - if ( _Sa_ != 0 ) - { - SHL32ItoR( EAX, _Sa_ ); - } - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); -} - -//////////////////////////////////////////////////// -void recSRL( void ) -{ - if ( ! _Rd_ ) - { - return; - } - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - if ( _Sa_ != 0 ) - { - SHR32ItoR( EAX, _Sa_); - } - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - -} - -//////////////////////////////////////////////////// -void recSRA( void ) -{ - if ( ! _Rd_ ) - { - return; - } - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - if ( _Sa_ != 0 ) - { - SAR32ItoR( EAX, _Sa_); - } - CDQ(); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - -} - -//////////////////////////////////////////////////// -void recDSLL( void ) -{ - if ( ! _Rd_ ) - { - return; - } - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); - if ( _Sa_ != 0 ) - { - PSLLQItoR( MM0, _Sa_ ); - } - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); - SetMMXstate(); - -} - -//////////////////////////////////////////////////// -void recDSRL( void ) -{ - if ( ! _Rd_ ) - { - return; - } - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); - if ( _Sa_ != 0 ) - { - PSRLQItoR( MM0, _Sa_ ); - } - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); - SetMMXstate(); -} - -//////////////////////////////////////////////////// -void recDSLL32( void ) -{ - if ( ! _Rd_ ) - { - return; - } - - if ( _Sa_ == 0 ) - { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], 0 ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EAX ); - return; - } - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); - PSLLQItoR( MM0, _Sa_ + 32 ); - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); - SetMMXstate(); - -} - -//////////////////////////////////////////////////// -void recDSRL32( void ) -{ - if ( ! _Rd_ ) - { - return; - } - - - if ( _Sa_ == 0 ) - { - MOV32MtoR( EAX,(int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); - MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - return; - } - - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); - PSRLQItoR( MM0, _Sa_ + 32 ); - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); - SetMMXstate(); - -} - - -/********************************************************* -* Shift arithmetic with variant register shift * -* Format: OP rd, rt, rs * -*********************************************************/ - -//////////////////////////////////////////////////// - - -//////////////////////////////////////////////////// -void recSLLV( void ) -{ - - if ( ! _Rd_ ) return; - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - if ( _Rs_ != 0 ) - { - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - AND32ItoR( ECX, 0x1f ); - SHL32CLtoR( EAX ); - } - CDQ(); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - -} - -//////////////////////////////////////////////////// -void recSRLV( void ) -{ - - if ( ! _Rd_ ) return; - - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - if ( _Rs_ != 0 ) - { - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - AND32ItoR( ECX, 0x1f ); - SHR32CLtoR( EAX ); - } - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - -} - -//////////////////////////////////////////////////// -void recSRAV( void ) -{ - if ( ! _Rd_ ) return; - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - if ( _Rs_ != 0 ) - { - MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); - AND32ItoR( ECX, 0x1f ); - SAR32CLtoR( EAX ); - } - CDQ( ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); - MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); - -} - -//////////////////////////////////////////////////// -static u64 _sa = 0; -void recDSLLV( void ) -{ - if ( ! _Rd_ ) return; - - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); - if ( _Rs_ != 0 ) - { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ] ); - AND32ItoR( EAX, 0x3f); - MOV32RtoM( (int)&_sa, EAX ); - PSLLQMtoR( MM0, (int)&_sa ); - } - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); - SetMMXstate(); - -} - -//////////////////////////////////////////////////// -void recDSRLV( void ) -{ - if ( ! _Rd_ ) return; - MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); - if ( _Rs_ != 0 ) - { - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ] ); - AND32ItoR( EAX, 0x3f); - MOV32RtoM( (int)&_sa, EAX ); - PSRLQMtoR( MM0, (int)&_sa ); - } - MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); - SetMMXstate(); - -} -//////////////////////////////////////////////////////////////// -void recDSRAV( void ) -{ - MOVQMtoR(MM0, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); - - if ( _Rs_ != 0 ) { - PXORRtoR(MM1, MM1); - - // calc high bit - MOVQRtoR(MM2, MM0); - PUNPCKHDQRtoR(MM2, MM2); // shift to lower - PCMPGTDRtoR(MM1, MM2); - - // it is a signed shift - MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ] ); - AND32ItoR( EAX, 0x3f); - MOVD32RtoMMX(MM2, EAX); // amount to shift - NOT32R(EAX); - ADD32ItoR(EAX, 65); - - // right logical shift - PSRLQRtoR(MM0, MM2); - - // shift highest bit, 64 - eax - MOVD32RtoMMX(MM2, EAX); - PSLLQRtoR(MM1, MM2); // highest bits - - PORRtoR(MM0, MM1); - MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], MM0); - } - else { - MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], MM0); - } - - SetMMXstate(); -} -#endif - -} } } +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "R5900OpcodeTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" + + +namespace R5900 { +namespace Dynarec { +namespace OpcodeImpl +{ + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ +#ifndef SHIFT_RECOMPILE + +namespace Interp = R5900::Interpreter::OpcodeImpl; + +REC_FUNC(SLL); +REC_FUNC(SRL); +REC_FUNC(SRA); +REC_FUNC(DSLL); +REC_FUNC(DSRL); +REC_FUNC(DSRA); +REC_FUNC(DSLL32); +REC_FUNC(DSRL32); +REC_FUNC(DSRA32); + +REC_FUNC(SLLV); +REC_FUNC(SRLV); +REC_FUNC(SRAV); +REC_FUNC(DSLLV); +REC_FUNC(DSRLV); +REC_FUNC(DSRAV); + +#elif defined(EE_CONST_PROP) + +//// SLL +void recSLL_const() +{ + g_cpuConstRegs[_Rd_].SD[0] = (s32)(g_cpuConstRegs[_Rt_].UL[0] << _Sa_); +} + +void recSLLs_(int info, int sa) +{ + int rtreg, rdreg, t0reg; + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + rtreg = EEREC_T; + rdreg = EEREC_D; + } + else if( g_pCurInstInfo->regs[_Rd_]&EEINST_MMX ) { + _addNeededMMXreg(MMX_GPR+_Rd_); + rtreg = rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + MOVDMtoMMX(rtreg, (u32)&cpuRegs.GPR.r[_Rt_].UL[0]); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( sa != 0 ) + { + SHL32ItoR( EAX, sa ); + } + + if( EEINST_ISLIVE1(_Rd_) ) { + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + } + return; + } + + if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); + + if( !EEINST_ISLIVE1(_Rd_) ) { + EEINST_RESETHASLIVE1(_Rd_); + PSLLDItoR(rdreg, sa); + return; + } + + if ( sa != 0 ) { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + // it is a signed shift + PSLLDItoR(rdreg, sa); + MOVQRtoR(t0reg, rdreg); + PSRADItoR(t0reg, 31); + + // take lower dword of rdreg and lower dword of t0reg + PUNPCKLDQRtoR(rdreg, t0reg); + _freeMMXreg(t0reg); + } + else { + if( EEINST_ISLIVE1(_Rd_) ) _signExtendGPRtoMMX(rdreg, _Rd_, 0); + else EEINST_RESETHASLIVE1(_Rd_); + } +} + +void recSLL_(int info) +{ + recSLLs_(info, _Sa_); + EEINST_SETSIGNEXT(_Rd_); +} + +EERECOMPILE_CODEX(eeRecompileCode2, SLL); + +//// SRL +void recSRL_const() +{ + g_cpuConstRegs[_Rd_].SD[0] = (s32)(g_cpuConstRegs[_Rt_].UL[0] >> _Sa_); +} + +void recSRLs_(int info, int sa) +{ + int rtreg, rdreg; + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + rtreg = EEREC_T; + rdreg = EEREC_D; + } + else if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { + _addNeededMMXreg(MMX_GPR+_Rd_); + rtreg = rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + MOVDMtoMMX(rtreg, (u32)&cpuRegs.GPR.r[_Rt_].UL[0]); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( sa != 0 ) SHR32ItoR( EAX, sa); + + if( EEINST_ISLIVE1(_Rd_) ) { + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + } + return; + } + + if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); + + if( !EEINST_ISLIVE1(_Rd_) ) { + EEINST_RESETHASLIVE1(_Rd_); + PSRLDItoR(rdreg, sa); + return; + } + + if ( sa != 0 ) { + // rdreg already sign extended + PSLLQItoR(rdreg, 32); + PSRLQItoR(rdreg, 32+sa); +// t0reg = _allocMMXreg(-1, MMX_TEMP, 0); +// +// // it is a signed shift +// PSRLDItoR(rdreg, sa); +// MOVQRtoR(t0reg, rdreg); +// PSRADItoR(t0reg, 31); +// +// take lower dword of rdreg and lower dword of t0reg +// PUNPCKLDQRtoR(rdreg, t0reg); +// _freeMMXreg(t0reg); + } +} + +void recSRL_(int info) +{ + recSRLs_(info, _Sa_); + EEINST_SETSIGNEXT(_Rd_); +} + +EERECOMPILE_CODEX(eeRecompileCode2, SRL); + +//// SRA +void recSRA_const() +{ + g_cpuConstRegs[_Rd_].SD[0] = (s32)(g_cpuConstRegs[_Rt_].SL[0] >> _Sa_); +} + +void recSRAs_(int info, int sa) +{ + int rtreg, rdreg, t0reg; + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + rtreg = EEREC_T; + rdreg = EEREC_D; + } + else if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { + _addNeededMMXreg(MMX_GPR+_Rd_); + rtreg = rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + MOVDMtoMMX(rtreg, (u32)&cpuRegs.GPR.r[_Rt_].UL[0]); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( sa != 0 ) SAR32ItoR( EAX, sa); + + if( EEINST_ISLIVE1(_Rd_) ) { + CDQ(); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + } + return; + } + + if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); + + if( EEINST_ISSIGNEXT(_Rt_) && EEINST_HASLIVE1(_Rt_) ) { + PSRADItoR(rdreg, sa); + return; + } + + if( !EEINST_ISLIVE1(_Rd_) ) { + EEINST_RESETHASLIVE1(_Rd_); + PSRADItoR(rdreg, sa); + return; + } + + if ( sa != 0 ) { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + // it is a signed shift + PSRADItoR(rdreg, sa); + MOVQRtoR(t0reg, rdreg); + PSRADItoR(rdreg, 31); + + // take lower dword of rdreg and lower dword of t0reg + PUNPCKLDQRtoR(t0reg, rdreg); + + // swap regs + mmxregs[t0reg] = mmxregs[rdreg]; + mmxregs[rdreg].inuse = 0; + } +} + +void recSRA_(int info) +{ + recSRAs_(info, _Sa_); + EEINST_SETSIGNEXT(_Rd_); +} + +EERECOMPILE_CODEX(eeRecompileCode2, SRA); + +//////////////////////////////////////////////////// +void recDSLL_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = (u64)(g_cpuConstRegs[_Rt_].UD[0] << _Sa_); +} + +void recDSLLs_(int info, int sa) +{ + int rtreg, rdreg; + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + rtreg = EEREC_T; + rdreg = EEREC_D; + } + else { + _addNeededMMXreg(MMX_GPR+_Rt_); + _addNeededMMXreg(MMX_GPR+_Rd_); + rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); + rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + } + + if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); + PSLLQItoR(rdreg, sa); +} + +void recDSLL_(int info) +{ + recDSLLs_(info, _Sa_); +} + +EERECOMPILE_CODEX(eeRecompileCode2, DSLL); + +//////////////////////////////////////////////////// +void recDSRL_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = (u64)(g_cpuConstRegs[_Rt_].UD[0] >> _Sa_); +} + +void recDSRLs_(int info, int sa) +{ + int rtreg, rdreg; + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + rtreg = EEREC_T; + rdreg = EEREC_D; + } + else { + _addNeededMMXreg(MMX_GPR+_Rt_); + _addNeededMMXreg(MMX_GPR+_Rd_); + rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); + rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + } + + if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); + PSRLQItoR(rdreg, sa); +} + +void recDSRL_(int info) +{ + recDSRLs_(info, _Sa_); +} + +EERECOMPILE_CODEX(eeRecompileCode2, DSRL); + +//// DSRA +void recDSRA_const() +{ + g_cpuConstRegs[_Rd_].SD[0] = (u64)(g_cpuConstRegs[_Rt_].SD[0] >> _Sa_); +} + +void recDSRAs_(int info, int sa) +{ + int rtreg, rdreg, t0reg; + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + rtreg = EEREC_T; + rdreg = EEREC_D; + } + else { + _addNeededMMXreg(MMX_GPR+_Rt_); + _addNeededMMXreg(MMX_GPR+_Rd_); + rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); + rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + } + + if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); + + if( EEINST_ISSIGNEXT(_Rt_) && EEINST_HASLIVE1(_Rt_) ) { + PSRADItoR(rdreg, sa); + return; + } + + if( !EEINST_ISLIVE1(_Rd_) ) { + EEINST_RESETHASLIVE1(_Rd_); + PSRLQItoR(rdreg, sa); + return; + } + + if ( sa != 0 ) { + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, rtreg); + + // it is a signed shift + PSRADItoR(t0reg, sa); + PSRLQItoR(rdreg, sa); + + PUNPCKHDQRtoR(t0reg, t0reg); // shift to lower + // take lower dword of rdreg and lower dword of t0reg + PUNPCKLDQRtoR(rdreg, t0reg); + + _freeMMXreg(t0reg); + } +} + +void recDSRA_(int info) +{ + recDSRAs_(info, _Sa_); +} + +EERECOMPILE_CODEX(eeRecompileCode2, DSRA); + +///// DSLL32 +void recDSLL32_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = (u64)(g_cpuConstRegs[_Rt_].UD[0] << (_Sa_+32)); +} + +void recDSLL32s_(int info, int sa) +{ + int rtreg, rdreg; + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + rtreg = EEREC_T; + rdreg = EEREC_D; + } + else if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { + _addNeededMMXreg(MMX_GPR+_Rt_); + _addNeededMMXreg(MMX_GPR+_Rd_); + rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); + rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( sa != 0 ) + { + SHL32ItoR( EAX, sa ); + } + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], 0 ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EAX ); + return; + } + + if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); + PSLLQItoR(rdreg, sa+32); +} + +void recDSLL32_(int info) +{ + recDSLL32s_(info, _Sa_); +} + +EERECOMPILE_CODEX(eeRecompileCode2, DSLL32); + +//// DSRL32 +void recDSRL32_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = (u64)(g_cpuConstRegs[_Rt_].UD[0] >> (_Sa_+32)); +} + +void recDSRL32s_(int info, int sa) +{ + int rtreg, rdreg; + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + rtreg = EEREC_T; + rdreg = EEREC_D; + } + else if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { + _addNeededMMXreg(MMX_GPR+_Rt_); + _addNeededMMXreg(MMX_GPR+_Rd_); + rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); + rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + if ( sa != 0 ) SHR32ItoR( EAX, sa ); + + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); + else EEINST_RESETHASLIVE1(_Rd_); + return; + } + + if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); + PSRLQItoR(rdreg, sa+32); +} + +void recDSRL32_(int info) +{ + recDSRL32s_(info, _Sa_); +} + +EERECOMPILE_CODEX(eeRecompileCode2, DSRL32); + +//// DSRA32 +void recDSRA32_const() +{ + g_cpuConstRegs[_Rd_].SD[0] = (u64)(g_cpuConstRegs[_Rt_].SD[0] >> (_Sa_+32)); +} + +void recDSRA32s_(int info, int sa) +{ + int rtreg, rdreg, t0reg; + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + rtreg = EEREC_T; + rdreg = EEREC_D; + } + else if( (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { + _addNeededMMXreg(MMX_GPR+_Rt_); + _addNeededMMXreg(MMX_GPR+_Rd_); + rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); + rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + } + else { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + CDQ( ); + if ( sa != 0 ) SAR32ItoR( EAX, sa ); + + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + if( EEINST_ISLIVE1(_Rd_) ) MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + else EEINST_RESETHASLIVE1(_Rd_); + return; + } + + if( rtreg != rdreg ) MOVQRtoR(rdreg, rtreg); + + if( EEINST_ISSIGNEXT(_Rt_) && EEINST_HASLIVE1(_Rt_) ) { + PSRADItoR(rdreg, 31); + return; + } + + if( !EEINST_ISLIVE1(_Rd_) ) { + EEINST_RESETHASLIVE1(_Rd_); + if( sa ) PSRADItoR(rdreg, sa); + PUNPCKHDQRtoR(rdreg, rdreg); + return; + } + + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(t0reg, rtreg); + + // it is a signed shift + if( sa ) { + PSRADItoR(rdreg, sa); + PSRADItoR(t0reg, 31); + + // take higher dword of rdreg and lower dword of t0reg + PUNPCKHDQRtoR(rdreg, t0reg); + _freeMMXreg(t0reg); + } + else { + // better timing + PSRADItoR(rdreg, 31); + + // take higher dword of rdreg and lower dword of t0reg + PUNPCKHDQRtoR(t0reg, rdreg); + + // swap + mmxregs[t0reg] = mmxregs[rdreg]; + mmxregs[rdreg].inuse = 0; + } +} + +void recDSRA32_(int info) +{ + recDSRA32s_(info, _Sa_); +} + +EERECOMPILE_CODEX(eeRecompileCode2, DSRA32); + +/********************************************************* +* Shift arithmetic with variant register shift * +* Format: OP rd, rt, rs * +*********************************************************/ + +PCSX2_ALIGNED16(u32 s_sa[4]) = {0x1f, 0, 0x3f, 0}; + +int recSetShiftV(int info, int* rsreg, int* rtreg, int* rdreg, int* rstemp, int forcemmx, int shift64) +{ + assert( !(info & PROCESS_EE_XMM) ); + + if( info & PROCESS_EE_MMX ) { + *rtreg = EEREC_T; + *rdreg = EEREC_D; + *rsreg = EEREC_S; + + // make sure to take only low 5 bits of *rsreg + if( !(g_pCurInstInfo->regs[_Rs_]&EEINST_LASTUSE) && EEINST_ISLIVE64(_Rs_)) { + *rstemp = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(*rstemp, *rsreg); + *rsreg = *rstemp; + } + else { + if( *rsreg != *rdreg ) { + _freeMMXreg(*rsreg); + mmxregs[*rsreg].inuse = 0; + } + } + + PANDMtoR(*rsreg, (u32)&s_sa[shift64?2:0]); + + if( EEREC_D == EEREC_S ) { + // need to be separate + int mmreg = _allocMMXreg(-1, MMX_TEMP, 0); + *rdreg = mmreg; + mmxregs[mmreg] = mmxregs[EEREC_S]; + mmxregs[EEREC_S].inuse = 0; + } + } + else if( forcemmx || (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { + _addNeededMMXreg(MMX_GPR+_Rt_); + _addNeededMMXreg(MMX_GPR+_Rd_); + *rtreg = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); + *rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + + *rstemp = _allocMMXreg(-1, MMX_TEMP, 0); + MOV32MtoR(EAX, (u32)&cpuRegs.GPR.r[_Rs_].UL[0]); + AND32ItoR(EAX, shift64?0x3f:0x1f); + MOVD32RtoMMX(*rstemp, EAX); + *rsreg = *rstemp; + } + else { + return 0; + } + + if( *rtreg != *rdreg ) MOVQRtoR(*rdreg, *rtreg); + return 1; +} + +void recSetConstShiftV(int info, int* rsreg, int* rdreg, int* rstemp, int shift64) +{ + if( info & PROCESS_EE_MMX ) { + *rdreg = EEREC_D; + *rsreg = EEREC_S; + + // make sure to take only low 5 bits of *rsreg + if( !(g_pCurInstInfo->regs[_Rs_]&EEINST_LASTUSE) && EEINST_ISLIVE64(_Rs_) ) { + *rstemp = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRtoR(*rstemp, *rsreg); + *rsreg = *rstemp; + } + else { + if( *rsreg != *rdreg ) { + _freeMMXreg(*rsreg); + mmxregs[*rsreg].inuse = 0; + } + } + + PANDMtoR(*rsreg, (u32)&s_sa[shift64?2:0]); + + + if( EEREC_D == EEREC_S ) { + // need to be separate + int mmreg = _allocMMXreg(-1, MMX_TEMP, 0); + *rdreg = mmreg; + mmxregs[mmreg] = mmxregs[EEREC_S]; + mmxregs[EEREC_S].inuse = 0; + } + } + else { + _addNeededMMXreg(MMX_GPR+_Rd_); + *rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + SetMMXstate(); + + *rstemp = _allocMMXreg(-1, MMX_TEMP, 0); + MOV32MtoR(EAX, (u32)&cpuRegs.GPR.r[_Rs_].UL[0]); + AND32ItoR(EAX, shift64?0x3f:0x1f); + MOVD32RtoMMX(*rstemp, EAX); + *rsreg = *rstemp; + } + + _flushConstReg(_Rt_); +} + +void recMoveSignToRd(int info) +{ + if( EEINST_ISLIVE1(_Rd_) ) { + CDQ(); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + } + else { + EEINST_RESETHASLIVE1(_Rd_); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + } + + if( info & PROCESS_EE_MMX ) { + mmxregs[EEREC_D].inuse = 0; + } +} + +//// SLLV +void recSLLV_const() +{ + g_cpuConstRegs[_Rd_].SD[0] = (s32)(g_cpuConstRegs[_Rt_].UL[0] << (g_cpuConstRegs[_Rs_].UL[0] &0x1f)); +} + +void recSLLV_consts(int info) +{ + recSLLs_(info, g_cpuConstRegs[_Rs_].UL[0]&0x1f); + EEINST_SETSIGNEXT(_Rd_); +} + +void recSLLV_constt(int info) +{ + if( (info & PROCESS_EE_MMX) && (info & PROCESS_EE_MODEWRITES) ) MOVD32MMXtoR(ECX, EEREC_S); + else MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + + MOV32ItoR( EAX, g_cpuConstRegs[_Rt_].UL[0] ); + AND32ItoR( ECX, 0x1f ); + SHL32CLtoR( EAX ); + + recMoveSignToRd(info); + EEINST_SETSIGNEXT(_Rd_); +} + +void recSLLV_(int info) +{ + int rsreg, rtreg, rdreg, rstemp = -1, t0reg; + EEINST_SETSIGNEXT(_Rd_); + + if( recSetShiftV(info, &rsreg, &rtreg, &rdreg, &rstemp, 0, 0) == 0 ) { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( ECX, 0x1f ); + SHL32CLtoR( EAX ); + } + CDQ(); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + return; + } + + if( !EEINST_ISLIVE1(_Rd_) ) { + EEINST_RESETHASLIVE1(_Rd_); + PSLLDRtoR(rdreg, rsreg); + if( rstemp != -1 ) _freeMMXreg(rstemp); + return; + } + + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + // it is a signed shift + PSLLDRtoR(rdreg, rsreg); + MOVQRtoR(t0reg, rdreg); + PSRADItoR(t0reg, 31); + + // take lower dword of rdreg and lower dword of t0reg + PUNPCKLDQRtoR(rdreg, t0reg); + _freeMMXreg(t0reg); + if( rstemp != -1 ) _freeMMXreg(rstemp); +} + +EERECOMPILE_CODE0(SLLV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// SRLV +void recSRLV_const() +{ + g_cpuConstRegs[_Rd_].SD[0] = (s32)(g_cpuConstRegs[_Rt_].UL[0] >> (g_cpuConstRegs[_Rs_].UL[0] &0x1f)); +} + +void recSRLV_consts(int info) +{ + recSRLs_(info, g_cpuConstRegs[_Rs_].UL[0]&0x1f); + EEINST_SETSIGNEXT(_Rd_); +} + +void recSRLV_constt(int info) +{ + if( (info & PROCESS_EE_MMX) && (info&PROCESS_EE_MODEWRITES) ) MOVD32MMXtoR(ECX, EEREC_S); + else MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + + MOV32ItoR( EAX, g_cpuConstRegs[_Rt_].UL[0] ); + AND32ItoR( ECX, 0x1f ); + SHR32CLtoR( EAX ); + + recMoveSignToRd(info); + EEINST_SETSIGNEXT(_Rd_); +} + +void recSRLV_(int info) +{ + int rsreg, rtreg, rdreg, rstemp = -1, t0reg; + EEINST_SETSIGNEXT(_Rd_); + + if( recSetShiftV(info, &rsreg, &rtreg, &rdreg, &rstemp, 0, 0) == 0 ) { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( ECX, 0x1f ); + SHR32CLtoR( EAX ); + } + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + return; + } + + if( !EEINST_ISLIVE1(_Rd_) ) { + EEINST_RESETHASLIVE1(_Rd_); + PSRLDRtoR(rdreg, rsreg); + if( rstemp != -1 ) _freeMMXreg(rstemp); + return; + } + + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + // it is a signed shift + PSRLDRtoR(rdreg, rsreg); + MOVQRtoR(t0reg, rdreg); + PSRADItoR(t0reg, 31); + + // take lower dword of rdreg and lower dword of t0reg + PUNPCKLDQRtoR(rdreg, t0reg); + _freeMMXreg(t0reg); + if( rstemp != -1 ) _freeMMXreg(rstemp); +} + +EERECOMPILE_CODE0(SRLV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// SRAV +void recSRAV_const() +{ + g_cpuConstRegs[_Rd_].SD[0] = (s32)(g_cpuConstRegs[_Rt_].SL[0] >> (g_cpuConstRegs[_Rs_].UL[0] &0x1f)); +} + +void recSRAV_consts(int info) +{ + recSRAs_(info, g_cpuConstRegs[_Rs_].UL[0]&0x1f); + EEINST_SETSIGNEXT(_Rd_); +} + +void recSRAV_constt(int info) +{ + if( (info & PROCESS_EE_MMX) && (info&PROCESS_EE_MODEWRITES) ) MOVD32MMXtoR(ECX, EEREC_S); + else MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + + MOV32ItoR( EAX, g_cpuConstRegs[_Rt_].UL[0] ); + AND32ItoR( ECX, 0x1f ); + SAR32CLtoR( EAX ); + + recMoveSignToRd(info); + EEINST_SETSIGNEXT(_Rd_); +} + +void recSRAV_(int info) +{ + int rsreg, rtreg, rdreg, rstemp = -1, t0reg; + EEINST_SETSIGNEXT(_Rd_); + + if( recSetShiftV(info, &rsreg, &rtreg, &rdreg, &rstemp, 0, 0) == 0 ) { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( ECX, 0x1f ); + SAR32CLtoR( EAX ); + } + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + return; + } + + if( !EEINST_ISLIVE1(_Rd_) ) { + EEINST_RESETHASLIVE1(_Rd_); + PSRADRtoR(rdreg, rsreg); + if( rstemp != -1 ) _freeMMXreg(rstemp); + return; + } + + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + + // it is a signed shift + PSRADRtoR(rdreg, rsreg); + MOVQRtoR(t0reg, rdreg); + PSRADItoR(t0reg, 31); + + // take lower dword of rdreg and lower dword of t0reg + PUNPCKLDQRtoR(rdreg, t0reg); + _freeMMXreg(t0reg); + if( rstemp != -1 ) _freeMMXreg(rstemp); +} + +EERECOMPILE_CODE0(SRAV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// DSLLV +void recDSLLV_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = (u64)(g_cpuConstRegs[_Rt_].UD[0] << (g_cpuConstRegs[_Rs_].UL[0] &0x3f)); +} + +void recDSLLV_consts(int info) +{ + int sa = g_cpuConstRegs[_Rs_].UL[0]&0x3f; + if( sa < 32 ) recDSLLs_(info, sa); + else recDSLL32s_(info, sa-32); +} + +void recDSLLV_constt(int info) +{ + int rsreg, rdreg, rstemp = -1; + recSetConstShiftV(info, &rsreg, &rdreg, &rstemp, 1); + + MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[_Rt_]); + PSLLQRtoR(rdreg, rsreg); + if( rstemp != -1 ) _freeMMXreg(rstemp); +} + +void recDSLLV_(int info) +{ + int rsreg, rtreg, rdreg, rstemp = -1; + recSetShiftV(info, &rsreg, &rtreg, &rdreg, &rstemp, 1, 1); + + PSLLQRtoR(rdreg, rsreg); + if( rstemp != -1 ) _freeMMXreg(rstemp); +} + +EERECOMPILE_CODE0(DSLLV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// DSRLV +void recDSRLV_const() +{ + g_cpuConstRegs[_Rd_].UD[0] = (u64)(g_cpuConstRegs[_Rt_].UD[0] >> (g_cpuConstRegs[_Rs_].UL[0] &0x3f)); +} + +void recDSRLV_consts(int info) +{ + int sa = g_cpuConstRegs[_Rs_].UL[0]&0x3f; + if( sa < 32 ) recDSRLs_(info, sa); + else recDSRL32s_(info, sa-32); +} + +void recDSRLV_constt(int info) +{ + int rsreg, rdreg, rstemp = -1; + recSetConstShiftV(info, &rsreg, &rdreg, &rstemp, 1); + + MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[_Rt_]); + PSRLQRtoR(rdreg, rsreg); + if( rstemp != -1 ) _freeMMXreg(rstemp); +} + +void recDSRLV_(int info) +{ + int rsreg, rtreg, rdreg, rstemp = -1; + recSetShiftV(info, &rsreg, &rtreg, &rdreg, &rstemp, 1, 1); + + PSRLQRtoR(rdreg, rsreg); + if( rstemp != -1 ) _freeMMXreg(rstemp); +} + +EERECOMPILE_CODE0(DSRLV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +//// DSRAV +void recDSRAV_const() +{ + g_cpuConstRegs[_Rd_].SD[0] = (s64)(g_cpuConstRegs[_Rt_].SD[0] >> (g_cpuConstRegs[_Rs_].UL[0] &0x3f)); +} + +void recDSRAV_consts(int info) +{ + int sa = g_cpuConstRegs[_Rs_].UL[0]&0x3f; + if( sa < 32 ) recDSRAs_(info, sa); + else recDSRA32s_(info, sa-32); +} + +void recDSRAV_constt(int info) +{ + int rsreg, rdreg, rstemp = -1, t0reg, t1reg; + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + t1reg = _allocMMXreg(-1, MMX_TEMP, 0); + + recSetConstShiftV(info, &rsreg, &rdreg, &rstemp, 1); + + MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[_Rt_]); + PXORRtoR(t0reg, t0reg); + + // calc high bit + MOVQRtoR(t1reg, rdreg); + PCMPGTDRtoR(t0reg, rdreg); + PUNPCKHDQRtoR(t0reg, t0reg); // shift to lower + + // shift highest bit, 64 - eax + MOV32ItoR(EAX, 64); + MOVD32RtoMMX(t1reg, EAX); + PSUBDRtoR(t1reg, rsreg); + + // right logical shift + PSRLQRtoR(rdreg, rsreg); + PSLLQRtoR(t0reg, t1reg); // highest bits + + PORRtoR(rdreg, t0reg); + + _freeMMXreg(t0reg); + _freeMMXreg(t1reg); + if( rstemp != -1 ) _freeMMXreg(rstemp); +} + +void recDSRAV_(int info) +{ + int rsreg, rtreg, rdreg, rstemp = -1, t0reg, t1reg; + t0reg = _allocMMXreg(-1, MMX_TEMP, 0); + t1reg = _allocMMXreg(-1, MMX_TEMP, 0); + recSetShiftV(info, &rsreg, &rtreg, &rdreg, &rstemp, 1, 1); + + PXORRtoR(t0reg, t0reg); + + // calc high bit + MOVQRtoR(t1reg, rdreg); + PCMPGTDRtoR(t0reg, rdreg); + PUNPCKHDQRtoR(t0reg, t0reg); // shift to lower + + // shift highest bit, 64 - eax + MOV32ItoR(EAX, 64); + MOVD32RtoMMX(t1reg, EAX); + PSUBDRtoR(t1reg, rsreg); + + // right logical shift + PSRLQRtoR(rdreg, rsreg); + PSLLQRtoR(t0reg, t1reg); // highest bits + + PORRtoR(rdreg, t0reg); + + _freeMMXreg(t0reg); + _freeMMXreg(t1reg); + if( rstemp != -1 ) _freeMMXreg(rstemp); +} + +EERECOMPILE_CODE0(DSRAV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); + +#else + +//////////////////////////////////////////////////// +void recDSRA( void ) +{ + if( !_Rd_ ) return; //? + + if ( _Sa_ != 0 ) { + // it is a signed shift + MOVQMtoR(MM0, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + MOVQRtoR(MM1, MM0); + PSRADItoR(MM0, _Sa_); + PSRLQItoR(MM1, _Sa_); + + PUNPCKHDQRtoR(MM0, MM0); // shift to lower + // take lower dword of MM1 and lower dword of MM0 + + PUNPCKLDQRtoR(MM1, MM0); + + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], MM1); + } + else { + MOVQMtoR(MM0, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], MM0); + } + + SetMMXstate(); +} + +//////////////////////////////////////////////////// +void recDSRA32(void) +{ + if( !_Rd_ ) return; //? + + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + CDQ(); + + if ( _Sa_ != 0 ) + { + SAR32ItoR( EAX, _Sa_ ); + } + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX); + MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX); +} + +//////////////////////////////////////////////////// +void recSLL( void ) +{ + if ( ! _Rd_ ) + return; + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Sa_ != 0 ) + { + SHL32ItoR( EAX, _Sa_ ); + } + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); +} + +//////////////////////////////////////////////////// +void recSRL( void ) +{ + if ( ! _Rd_ ) + { + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Sa_ != 0 ) + { + SHR32ItoR( EAX, _Sa_); + } + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +void recSRA( void ) +{ + if ( ! _Rd_ ) + { + return; + } + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Sa_ != 0 ) + { + SAR32ItoR( EAX, _Sa_); + } + CDQ(); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +void recDSLL( void ) +{ + if ( ! _Rd_ ) + { + return; + } + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + if ( _Sa_ != 0 ) + { + PSLLQItoR( MM0, _Sa_ ); + } + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + +} + +//////////////////////////////////////////////////// +void recDSRL( void ) +{ + if ( ! _Rd_ ) + { + return; + } + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + if ( _Sa_ != 0 ) + { + PSRLQItoR( MM0, _Sa_ ); + } + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); +} + +//////////////////////////////////////////////////// +void recDSLL32( void ) +{ + if ( ! _Rd_ ) + { + return; + } + + if ( _Sa_ == 0 ) + { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], 0 ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EAX ); + return; + } + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + PSLLQItoR( MM0, _Sa_ + 32 ); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + +} + +//////////////////////////////////////////////////// +void recDSRL32( void ) +{ + if ( ! _Rd_ ) + { + return; + } + + + if ( _Sa_ == 0 ) + { + MOV32MtoR( EAX,(int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); + MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + return; + } + + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + PSRLQItoR( MM0, _Sa_ + 32 ); + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + +} + + +/********************************************************* +* Shift arithmetic with variant register shift * +* Format: OP rd, rt, rs * +*********************************************************/ + +//////////////////////////////////////////////////// + + +//////////////////////////////////////////////////// +void recSLLV( void ) +{ + + if ( ! _Rd_ ) return; + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( ECX, 0x1f ); + SHL32CLtoR( EAX ); + } + CDQ(); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +void recSRLV( void ) +{ + + if ( ! _Rd_ ) return; + + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( ECX, 0x1f ); + SHR32CLtoR( EAX ); + } + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +void recSRAV( void ) +{ + if ( ! _Rd_ ) return; + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); + AND32ItoR( ECX, 0x1f ); + SAR32CLtoR( EAX ); + } + CDQ( ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); + MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); + +} + +//////////////////////////////////////////////////// +static u64 _sa = 0; +void recDSLLV( void ) +{ + if ( ! _Rd_ ) return; + + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + AND32ItoR( EAX, 0x3f); + MOV32RtoM( (int)&_sa, EAX ); + PSLLQMtoR( MM0, (int)&_sa ); + } + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + +} + +//////////////////////////////////////////////////// +void recDSRLV( void ) +{ + if ( ! _Rd_ ) return; + MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); + if ( _Rs_ != 0 ) + { + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + AND32ItoR( EAX, 0x3f); + MOV32RtoM( (int)&_sa, EAX ); + PSRLQMtoR( MM0, (int)&_sa ); + } + MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); + SetMMXstate(); + +} +//////////////////////////////////////////////////////////////// +void recDSRAV( void ) +{ + MOVQMtoR(MM0, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); + + if ( _Rs_ != 0 ) { + PXORRtoR(MM1, MM1); + + // calc high bit + MOVQRtoR(MM2, MM0); + PUNPCKHDQRtoR(MM2, MM2); // shift to lower + PCMPGTDRtoR(MM1, MM2); + + // it is a signed shift + MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ] ); + AND32ItoR( EAX, 0x3f); + MOVD32RtoMMX(MM2, EAX); // amount to shift + NOT32R(EAX); + ADD32ItoR(EAX, 65); + + // right logical shift + PSRLQRtoR(MM0, MM2); + + // shift highest bit, 64 - eax + MOVD32RtoMMX(MM2, EAX); + PSLLQRtoR(MM1, MM2); // highest bits + + PORRtoR(MM0, MM1); + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], MM0); + } + else { + MOVQRtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], MM0); + } + + SetMMXstate(); +} +#endif + +} } } diff --git a/pcsx2/x86/ix86-32/iR5900Templates.cpp b/pcsx2/x86/ix86-32/iR5900Templates.cpp index 09eb8291fc..038ca99410 100644 --- a/pcsx2/x86/ix86-32/iR5900Templates.cpp +++ b/pcsx2/x86/ix86-32/iR5900Templates.cpp @@ -1,1005 +1,1005 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "Memory.h" -#include "R5900OpcodeTables.h" -#include "ix86/ix86.h" -#include "iR5900.h" -#include "iMMI.h" -#include "iFPU.h" -#include "iCOP0.h" -#include "iVUmicro.h" -#include "VU.h" -#include "VUmicro.h" - -#include "iVUzerorec.h" - -#include "vtlb.h" - -//////////////////// -// Code Templates // -//////////////////// - -void CHECK_SAVE_REG(int reg) -{ - if( s_saveConstGPRreg == 0xffffffff ) { - if( GPR_IS_CONST1(reg) ) { - s_saveConstGPRreg = reg; - s_ConstGPRreg = g_cpuConstRegs[reg]; - } - } - else { - assert( s_saveConstGPRreg == 0 || s_saveConstGPRreg == reg ); - } -} - -void _eeProcessHasLive(int reg, int signext) -{ - g_cpuPrevRegHasLive1 = g_cpuRegHasLive1; - g_cpuRegHasLive1 |= 1<regs[reg]&EEINST_LASTUSE) ) { - if( usemmx ) return _allocMMXreg(-1, MMX_GPR+reg, mode); - return _allocGPRtoXMMreg(-1, reg, mode); - } - - return -1; -} - -#define PROCESS_EE_SETMODES(mmreg) ((mmxregs[mmreg].mode&MODE_WRITE)?PROCESS_EE_MODEWRITES:0) -#define PROCESS_EE_SETMODET(mmreg) ((mmxregs[mmreg].mode&MODE_WRITE)?PROCESS_EE_MODEWRITET:0) - -// ignores XMMINFO_READS, XMMINFO_READT, and XMMINFO_READD_LO from xmminfo -// core of reg caching -void eeRecompileCode0(R5900FNPTR constcode, R5900FNPTR_INFO constscode, R5900FNPTR_INFO consttcode, R5900FNPTR_INFO noconstcode, int xmminfo) -{ - int mmreg1, mmreg2, mmreg3, mmtemp, moded; - - if ( ! _Rd_ && (xmminfo&XMMINFO_WRITED) ) return; - - if( xmminfo&XMMINFO_WRITED) { - CHECK_SAVE_REG(_Rd_); - _eeProcessHasLive(_Rd_, 0); - EEINST_RESETSIGNEXT(_Rd_); - } - - if( GPR_IS_CONST2(_Rs_, _Rt_) ) { - if( xmminfo & XMMINFO_WRITED ) { - _deleteMMXreg(MMX_GPR+_Rd_, 2); - _deleteGPRtoXMMreg(_Rd_, 2); - } - if( xmminfo&XMMINFO_WRITED ) GPR_SET_CONST(_Rd_); - constcode(); - return; - } - - moded = MODE_WRITE|((xmminfo&XMMINFO_READD)?MODE_READ:0); - - // test if should write mmx - if( g_pCurInstInfo->info & EEINST_MMX ) { - - if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) _addNeededMMXreg(MMX_GPR+MMX_LO); - if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) _addNeededMMXreg(MMX_GPR+MMX_HI); - _addNeededMMXreg(MMX_GPR+_Rs_); - _addNeededMMXreg(MMX_GPR+_Rt_); - - if( GPR_IS_CONST1(_Rs_) || GPR_IS_CONST1(_Rt_) ) { - int creg = GPR_IS_CONST1(_Rs_) ? _Rs_ : _Rt_; - int vreg = creg == _Rs_ ? _Rt_ : _Rs_; - -// if(g_pCurInstInfo->regs[vreg]&EEINST_MMX) { -// mmreg1 = _allocMMXreg(-1, MMX_GPR+vreg, MODE_READ); -// _addNeededMMXreg(MMX_GPR+vreg); -// } - mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, vreg, MODE_READ); - - if( mmreg1 >= 0 ) { - int info = PROCESS_EE_MMX; - - if( GPR_IS_CONST1(_Rs_) ) info |= PROCESS_EE_SETMODET(mmreg1); - else info |= PROCESS_EE_SETMODES(mmreg1); - - if( xmminfo & XMMINFO_WRITED ) { - _addNeededMMXreg(MMX_GPR+_Rd_); - mmreg3 = _checkMMXreg(MMX_GPR+_Rd_, moded); - - if( !(xmminfo&XMMINFO_READD) && mmreg3 < 0 && ((g_pCurInstInfo->regs[vreg] & EEINST_LASTUSE) || !EEINST_ISLIVE64(vreg)) ) { - if( EEINST_ISLIVE64(vreg) ) { - _freeMMXreg(mmreg1); - if( GPR_IS_CONST1(_Rs_) ) info &= ~PROCESS_EE_MODEWRITET; - else info &= ~PROCESS_EE_MODEWRITES; - } - _deleteGPRtoXMMreg(_Rd_, 2); - mmxregs[mmreg1].inuse = 1; - mmxregs[mmreg1].reg = _Rd_; - mmxregs[mmreg1].mode = moded; - mmreg3 = mmreg1; - } - else if( mmreg3 < 0 ) mmreg3 = _allocMMXreg(-1, MMX_GPR+_Rd_, moded); - - info |= PROCESS_EE_SET_D(mmreg3); - } - - if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { - mmtemp = eeProcessHILO(MMX_LO, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 1); - if( mmtemp >= 0 ) info |= PROCESS_EE_SET_LO(mmtemp); - } - if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { - mmtemp = eeProcessHILO(MMX_HI, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 1); - if( mmtemp >= 0 ) info |= PROCESS_EE_SET_HI(mmtemp); - } - - SetMMXstate(); - if( creg == _Rs_ ) constscode(info|PROCESS_EE_SET_T(mmreg1)); - else consttcode(info|PROCESS_EE_SET_S(mmreg1)); - _clearNeededMMXregs(); - if( xmminfo & XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); - return; - } - } - else { - // no const regs - mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rs_, MODE_READ); - mmreg2 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_READ); - - if( mmreg1 >= 0 || mmreg2 >= 0 ) { - int info = PROCESS_EE_MMX; - - // do it all in mmx - if( mmreg1 < 0 ) mmreg1 = _allocMMXreg(-1, MMX_GPR+_Rs_, MODE_READ); - if( mmreg2 < 0 ) mmreg2 = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); - - info |= PROCESS_EE_SETMODES(mmreg1)|PROCESS_EE_SETMODET(mmreg2); - - // check for last used, if so don't alloc a new MMX reg - if( xmminfo & XMMINFO_WRITED ) { - _addNeededMMXreg(MMX_GPR+_Rd_); - mmreg3 = _checkMMXreg(MMX_GPR+_Rd_, moded); - - if( mmreg3 < 0 ) { - if( !(xmminfo&XMMINFO_READD) && ((g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rt_)) ) { - if( EEINST_ISLIVE64(_Rt_) ) { - _freeMMXreg(mmreg2); - info &= ~PROCESS_EE_MODEWRITET; - } - _deleteGPRtoXMMreg(_Rd_, 2); - mmxregs[mmreg2].inuse = 1; - mmxregs[mmreg2].reg = _Rd_; - mmxregs[mmreg2].mode = moded; - mmreg3 = mmreg2; - } - else if( !(xmminfo&XMMINFO_READD) && ((g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rs_)) ) { - if( EEINST_ISLIVE64(_Rs_) ) { - _freeMMXreg(mmreg1); - info &= ~PROCESS_EE_MODEWRITES; - } - _deleteGPRtoXMMreg(_Rd_, 2); - mmxregs[mmreg1].inuse = 1; - mmxregs[mmreg1].reg = _Rd_; - mmxregs[mmreg1].mode = moded; - mmreg3 = mmreg1; - } - else mmreg3 = _allocMMXreg(-1, MMX_GPR+_Rd_, moded); - } - - info |= PROCESS_EE_SET_D(mmreg3); - } - - if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { - mmtemp = eeProcessHILO(MMX_LO, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 1); - if( mmtemp >= 0 ) info |= PROCESS_EE_SET_LO(mmtemp); - } - if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { - mmtemp = eeProcessHILO(MMX_HI, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 1); - if( mmtemp >= 0 ) info |= PROCESS_EE_SET_HI(mmtemp); - } - - SetMMXstate(); - noconstcode(info|PROCESS_EE_SET_S(mmreg1)|PROCESS_EE_SET_T(mmreg2)); - _clearNeededMMXregs(); - if( xmminfo & XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); - return; - } - } - - _clearNeededMMXregs(); - } - - // test if should write xmm, mirror to mmx code - if( g_pCurInstInfo->info & EEINST_XMM ) { - - if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) _addNeededGPRtoXMMreg(XMMGPR_LO); - if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) _addNeededGPRtoXMMreg(XMMGPR_HI); - _addNeededGPRtoXMMreg(_Rs_); - _addNeededGPRtoXMMreg(_Rt_); - - if( GPR_IS_CONST1(_Rs_) || GPR_IS_CONST1(_Rt_) ) { - int creg = GPR_IS_CONST1(_Rs_) ? _Rs_ : _Rt_; - int vreg = creg == _Rs_ ? _Rt_ : _Rs_; - -// if(g_pCurInstInfo->regs[vreg]&EEINST_XMM) { -// mmreg1 = _allocGPRtoXMMreg(-1, vreg, MODE_READ); -// _addNeededGPRtoXMMreg(vreg); -// } - mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, vreg, MODE_READ); - - if( mmreg1 >= 0 ) { - int info = PROCESS_EE_XMM; - - if( GPR_IS_CONST1(_Rs_) ) info |= PROCESS_EE_SETMODET(mmreg1); - else info |= PROCESS_EE_SETMODES(mmreg1); - - if( xmminfo & XMMINFO_WRITED ) { - - _addNeededGPRtoXMMreg(_Rd_); - mmreg3 = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_WRITE); - - if( !(xmminfo&XMMINFO_READD) && mmreg3 < 0 && ((g_pCurInstInfo->regs[vreg] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(vreg)) ) { - _freeXMMreg(mmreg1); - if( GPR_IS_CONST1(_Rs_) ) info &= ~PROCESS_EE_MODEWRITET; - else info &= ~PROCESS_EE_MODEWRITES; - _deleteMMXreg(MMX_GPR+_Rd_, 2); - xmmregs[mmreg1].inuse = 1; - xmmregs[mmreg1].reg = _Rd_; - xmmregs[mmreg1].mode = moded; - mmreg3 = mmreg1; - } - else if( mmreg3 < 0 ) mmreg3 = _allocGPRtoXMMreg(-1, _Rd_, moded); - - info |= PROCESS_EE_SET_D(mmreg3); - } - - if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { - mmtemp = eeProcessHILO(XMMGPR_LO, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 0); - if( mmtemp >= 0 ) info |= PROCESS_EE_SET_LO(mmtemp); - } - if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { - mmtemp = eeProcessHILO(XMMGPR_HI, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 0); - if( mmtemp >= 0 ) info |= PROCESS_EE_SET_HI(mmtemp); - } - - if( creg == _Rs_ ) constscode(info|PROCESS_EE_SET_T(mmreg1)); - else consttcode(info|PROCESS_EE_SET_S(mmreg1)); - _clearNeededXMMregs(); - if( xmminfo & XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); - return; - } - } - else { - // no const regs - mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rs_, MODE_READ); - mmreg2 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_READ); - - if( mmreg1 >= 0 || mmreg2 >= 0 ) { - int info = PROCESS_EE_XMM; - - // do it all in xmm - if( mmreg1 < 0 ) mmreg1 = _allocGPRtoXMMreg(-1, _Rs_, MODE_READ); - if( mmreg2 < 0 ) mmreg2 = _allocGPRtoXMMreg(-1, _Rt_, MODE_READ); - - info |= PROCESS_EE_SETMODES(mmreg1)|PROCESS_EE_SETMODET(mmreg2); - - if( xmminfo & XMMINFO_WRITED ) { - // check for last used, if so don't alloc a new XMM reg - _addNeededGPRtoXMMreg(_Rd_); - mmreg3 = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, moded); - - if( mmreg3 < 0 ) { - if( !(xmminfo&XMMINFO_READD) && ((g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rt_)) ) { - _freeXMMreg(mmreg2); - info &= ~PROCESS_EE_MODEWRITET; - _deleteMMXreg(MMX_GPR+_Rd_, 2); - xmmregs[mmreg2].inuse = 1; - xmmregs[mmreg2].reg = _Rd_; - xmmregs[mmreg2].mode = moded; - mmreg3 = mmreg2; - } - else if( !(xmminfo&XMMINFO_READD) && ((g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rs_)) ) { - _freeXMMreg(mmreg1); - info &= ~PROCESS_EE_MODEWRITES; - _deleteMMXreg(MMX_GPR+_Rd_, 2); - xmmregs[mmreg1].inuse = 1; - xmmregs[mmreg1].reg = _Rd_; - xmmregs[mmreg1].mode = moded; - mmreg3 = mmreg1; - } - else mmreg3 = _allocGPRtoXMMreg(-1, _Rd_, moded); - } - - info |= PROCESS_EE_SET_D(mmreg3); - } - - if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { - mmtemp = eeProcessHILO(XMMGPR_LO, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 0); - if( mmtemp >= 0 ) info |= PROCESS_EE_SET_LO(mmtemp); - } - if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { - mmtemp = eeProcessHILO(XMMGPR_HI, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 0); - if( mmtemp >= 0 ) info |= PROCESS_EE_SET_HI(mmtemp); - } - - noconstcode(info|PROCESS_EE_SET_S(mmreg1)|PROCESS_EE_SET_T(mmreg2)); - _clearNeededXMMregs(); - if( xmminfo & XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); - return; - } - } - - _clearNeededXMMregs(); - } - - // regular x86 - _deleteGPRtoXMMreg(_Rs_, 1); - _deleteGPRtoXMMreg(_Rt_, 1); - if( xmminfo&XMMINFO_WRITED ) - _deleteGPRtoXMMreg(_Rd_, (xmminfo&XMMINFO_READD)?0:2); - _deleteMMXreg(MMX_GPR+_Rs_, 1); - _deleteMMXreg(MMX_GPR+_Rt_, 1); - if( xmminfo&XMMINFO_WRITED ) - _deleteMMXreg(MMX_GPR+_Rd_, (xmminfo&XMMINFO_READD)?0:2); - - // don't delete, fn will take care of them -// if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { -// _deleteGPRtoXMMreg(XMMGPR_LO, (xmminfo&XMMINFO_READLO)?1:0); -// _deleteMMXreg(MMX_GPR+MMX_LO, (xmminfo&XMMINFO_READLO)?1:0); -// } -// if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { -// _deleteGPRtoXMMreg(XMMGPR_HI, (xmminfo&XMMINFO_READHI)?1:0); -// _deleteMMXreg(MMX_GPR+MMX_HI, (xmminfo&XMMINFO_READHI)?1:0); -// } - - if( GPR_IS_CONST1(_Rs_) ) { - constscode(0); - if( xmminfo&XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); - return; - } - - if( GPR_IS_CONST1(_Rt_) ) { - consttcode(0); - if( xmminfo&XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); - return; - } - - noconstcode(0); - if( xmminfo&XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); -} - -// rt = rs op imm16 -void eeRecompileCode1(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode) -{ - int mmreg1, mmreg2; - if ( ! _Rt_ ) return; - - CHECK_SAVE_REG(_Rt_); - _eeProcessHasLive(_Rt_, 0); - EEINST_RESETSIGNEXT(_Rt_); - - if( GPR_IS_CONST1(_Rs_) ) { - _deleteMMXreg(MMX_GPR+_Rt_, 2); - _deleteGPRtoXMMreg(_Rt_, 2); - GPR_SET_CONST(_Rt_); - constcode(); - return; - } - - // test if should write mmx - if( g_pCurInstInfo->info & EEINST_MMX ) { - - // no const regs - mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rs_, MODE_READ); - - if( mmreg1 >= 0 ) { - int info = PROCESS_EE_MMX|PROCESS_EE_SETMODES(mmreg1); - - // check for last used, if so don't alloc a new MMX reg - _addNeededMMXreg(MMX_GPR+_Rt_); - mmreg2 = _checkMMXreg(MMX_GPR+_Rt_, MODE_WRITE); - - if( mmreg2 < 0 ) { - if( (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rs_) ) { - if( EEINST_ISLIVE64(_Rs_) ) { - _freeMMXreg(mmreg1); - info &= ~PROCESS_EE_MODEWRITES; - } - _deleteGPRtoXMMreg(_Rt_, 2); - mmxregs[mmreg1].inuse = 1; - mmxregs[mmreg1].reg = _Rt_; - mmxregs[mmreg1].mode = MODE_WRITE|MODE_READ; - mmreg2 = mmreg1; - } - else mmreg2 = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE); - } - - SetMMXstate(); - noconstcode(info|PROCESS_EE_SET_S(mmreg1)|PROCESS_EE_SET_T(mmreg2)); - _clearNeededMMXregs(); - GPR_DEL_CONST(_Rt_); - return; - } - - _clearNeededMMXregs(); - } - - // test if should write xmm, mirror to mmx code - if( g_pCurInstInfo->info & EEINST_XMM ) { - - // no const regs - mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rs_, MODE_READ); - - if( mmreg1 >= 0 ) { - int info = PROCESS_EE_XMM|PROCESS_EE_SETMODES(mmreg1); - - // check for last used, if so don't alloc a new XMM reg - _addNeededGPRtoXMMreg(_Rt_); - mmreg2 = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_WRITE); - - if( mmreg2 < 0 ) { - if( (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rs_) ) { - _freeXMMreg(mmreg1); - info &= ~PROCESS_EE_MODEWRITES; - _deleteMMXreg(MMX_GPR+_Rt_, 2); - xmmregs[mmreg1].inuse = 1; - xmmregs[mmreg1].reg = _Rt_; - xmmregs[mmreg1].mode = MODE_WRITE|MODE_READ; - mmreg2 = mmreg1; - } - else mmreg2 = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); - } - - noconstcode(info|PROCESS_EE_SET_S(mmreg1)|PROCESS_EE_SET_T(mmreg2)); - _clearNeededXMMregs(); - GPR_DEL_CONST(_Rt_); - return; - } - - _clearNeededXMMregs(); - } - - // regular x86 - _deleteGPRtoXMMreg(_Rs_, 1); - _deleteGPRtoXMMreg(_Rt_, 2); - _deleteMMXreg(MMX_GPR+_Rs_, 1); - _deleteMMXreg(MMX_GPR+_Rt_, 2); - - noconstcode(0); - GPR_DEL_CONST(_Rt_); -} - -// rd = rt op sa -void eeRecompileCode2(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode) -{ - int mmreg1, mmreg2; - if ( ! _Rd_ ) return; - - CHECK_SAVE_REG(_Rd_); - _eeProcessHasLive(_Rd_, 0); - EEINST_RESETSIGNEXT(_Rd_); - - if( GPR_IS_CONST1(_Rt_) ) { - _deleteMMXreg(MMX_GPR+_Rd_, 2); - _deleteGPRtoXMMreg(_Rd_, 2); - GPR_SET_CONST(_Rd_); - constcode(); - return; - } - - // test if should write mmx - if( g_pCurInstInfo->info & EEINST_MMX ) { - - // no const regs - mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_READ); - - if( mmreg1 >= 0 ) { - int info = PROCESS_EE_MMX|PROCESS_EE_SETMODET(mmreg1); - - // check for last used, if so don't alloc a new MMX reg - _addNeededMMXreg(MMX_GPR+_Rd_); - mmreg2 = _checkMMXreg(MMX_GPR+_Rd_, MODE_WRITE); - - if( mmreg2 < 0 ) { - if( (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rt_) ) { - if( EEINST_ISLIVE64(_Rt_) ) { - _freeMMXreg(mmreg1); - info &= ~PROCESS_EE_MODEWRITET; - } - _deleteGPRtoXMMreg(_Rd_, 2); - mmxregs[mmreg1].inuse = 1; - mmxregs[mmreg1].reg = _Rd_; - mmxregs[mmreg1].mode = MODE_WRITE|MODE_READ; - mmreg2 = mmreg1; - } - else mmreg2 = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); - } - - SetMMXstate(); - noconstcode(info|PROCESS_EE_SET_T(mmreg1)|PROCESS_EE_SET_D(mmreg2)); - _clearNeededMMXregs(); - GPR_DEL_CONST(_Rd_); - return; - } - - _clearNeededMMXregs(); - } - - // test if should write xmm, mirror to mmx code - if( g_pCurInstInfo->info & EEINST_XMM ) { - - // no const regs - mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_READ); - - if( mmreg1 >= 0 ) { - int info = PROCESS_EE_XMM|PROCESS_EE_SETMODET(mmreg1); - - // check for last used, if so don't alloc a new XMM reg - _addNeededGPRtoXMMreg(_Rd_); - mmreg2 = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_WRITE); - - if( mmreg2 < 0 ) { - if( (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rt_) ) { - _freeXMMreg(mmreg1); - info &= ~PROCESS_EE_MODEWRITET; - _deleteMMXreg(MMX_GPR+_Rd_, 2); - xmmregs[mmreg1].inuse = 1; - xmmregs[mmreg1].reg = _Rd_; - xmmregs[mmreg1].mode = MODE_WRITE|MODE_READ; - mmreg2 = mmreg1; - } - else mmreg2 = _allocGPRtoXMMreg(-1, _Rd_, MODE_WRITE); - } - - noconstcode(info|PROCESS_EE_SET_T(mmreg1)|PROCESS_EE_SET_D(mmreg2)); - _clearNeededXMMregs(); - GPR_DEL_CONST(_Rd_); - return; - } - - _clearNeededXMMregs(); - } - - // regular x86 - _deleteGPRtoXMMreg(_Rt_, 1); - _deleteGPRtoXMMreg(_Rd_, 2); - _deleteMMXreg(MMX_GPR+_Rt_, 1); - _deleteMMXreg(MMX_GPR+_Rd_, 2); - - noconstcode(0); - GPR_DEL_CONST(_Rd_); -} - -// rt op rs -void eeRecompileCode3(R5900FNPTR constcode, R5900FNPTR_INFO multicode) -{ - assert(0); - // for now, don't support xmm - _deleteEEreg(_Rs_, 1); - _deleteEEreg(_Rt_, 1); - - if( GPR_IS_CONST2(_Rs_, _Rt_) ) { - constcode(); - return; - } - - if( GPR_IS_CONST1(_Rs_) ) { - //multicode(PROCESS_EE_CONSTT); - return; - } - - if( GPR_IS_CONST1(_Rt_) ) { - //multicode(PROCESS_EE_CONSTT); - return; - } - - multicode(0); -} - -// Simple Code Templates // - -// rd = rs op rt -void eeRecompileCodeConst0(R5900FNPTR constcode, R5900FNPTR_INFO constscode, R5900FNPTR_INFO consttcode, R5900FNPTR_INFO noconstcode) -{ - if ( ! _Rd_ ) return; - - // for now, don't support xmm - CHECK_SAVE_REG(_Rd_); - - _deleteGPRtoXMMreg(_Rs_, 1); - _deleteGPRtoXMMreg(_Rt_, 1); - _deleteGPRtoXMMreg(_Rd_, 0); - _deleteMMXreg(MMX_GPR+_Rs_, 1); - _deleteMMXreg(MMX_GPR+_Rt_, 1); - _deleteMMXreg(MMX_GPR+_Rd_, 0); - - if( GPR_IS_CONST2(_Rs_, _Rt_) ) { - GPR_SET_CONST(_Rd_); - constcode(); - return; - } - - if( GPR_IS_CONST1(_Rs_) ) { - constscode(0); - GPR_DEL_CONST(_Rd_); - return; - } - - if( GPR_IS_CONST1(_Rt_) ) { - consttcode(0); - GPR_DEL_CONST(_Rd_); - return; - } - - noconstcode(0); - GPR_DEL_CONST(_Rd_); -} - -// rt = rs op imm16 -void eeRecompileCodeConst1(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode) -{ - if ( ! _Rt_ ) - return; - - // for now, don't support xmm - CHECK_SAVE_REG(_Rt_); - - _deleteGPRtoXMMreg(_Rs_, 1); - _deleteGPRtoXMMreg(_Rt_, 0); - - if( GPR_IS_CONST1(_Rs_) ) { - GPR_SET_CONST(_Rt_); - constcode(); - return; - } - - noconstcode(0); - GPR_DEL_CONST(_Rt_); -} - -// rd = rt op sa -void eeRecompileCodeConst2(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode) -{ - if ( ! _Rd_ ) return; - - // for now, don't support xmm - CHECK_SAVE_REG(_Rd_); - - _deleteGPRtoXMMreg(_Rt_, 1); - _deleteGPRtoXMMreg(_Rd_, 0); - - if( GPR_IS_CONST1(_Rt_) ) { - GPR_SET_CONST(_Rd_); - constcode(); - return; - } - - noconstcode(0); - GPR_DEL_CONST(_Rd_); -} - -// rd = rt MULT rs (SPECIAL) -void eeRecompileCodeConstSPECIAL(R5900FNPTR constcode, R5900FNPTR_INFO multicode, int MULT) -{ - assert(0); - // for now, don't support xmm - if( MULT ) { - CHECK_SAVE_REG(_Rd_); - _deleteGPRtoXMMreg(_Rd_, 0); - } - - _deleteGPRtoXMMreg(_Rs_, 1); - _deleteGPRtoXMMreg(_Rt_, 1); - - if( GPR_IS_CONST2(_Rs_, _Rt_) ) { - if( MULT && _Rd_ ) GPR_SET_CONST(_Rd_); - constcode(); - return; - } - - if( GPR_IS_CONST1(_Rs_) ) { - //multicode(PROCESS_EE_CONSTS); - if( MULT && _Rd_ ) GPR_DEL_CONST(_Rd_); - return; - } - - if( GPR_IS_CONST1(_Rt_) ) { - //multicode(PROCESS_EE_CONSTT); - if( MULT && _Rd_ ) GPR_DEL_CONST(_Rd_); - return; - } - - multicode(0); - if( MULT && _Rd_ ) GPR_DEL_CONST(_Rd_); -} - -// EE XMM allocation code -int eeRecompileCodeXMM(int xmminfo) -{ - int info = PROCESS_EE_XMM; - - // save state - if( xmminfo & XMMINFO_WRITED ) { - CHECK_SAVE_REG(_Rd_); - _eeProcessHasLive(_Rd_, 0); - EEINST_RESETSIGNEXT(_Rd_); - } - - // flush consts - if( xmminfo & XMMINFO_READT ) { - if( GPR_IS_CONST1( _Rt_ ) && !(g_cpuFlushedConstReg&(1<<_Rt_)) ) { - MOV32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0]); - MOV32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1]); - g_cpuFlushedConstReg |= (1<<_Rt_); - } - } - if( xmminfo & XMMINFO_READS) { - if( GPR_IS_CONST1( _Rs_ ) && !(g_cpuFlushedConstReg&(1<<_Rs_)) ) { - MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); - MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); - g_cpuFlushedConstReg |= (1<<_Rs_); - } - } - - if( xmminfo & XMMINFO_WRITED ) { - GPR_DEL_CONST(_Rd_); - } - - // add needed - if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { - _addNeededGPRtoXMMreg(XMMGPR_LO); - } - if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { - _addNeededGPRtoXMMreg(XMMGPR_HI); - } - if( xmminfo & XMMINFO_READS) _addNeededGPRtoXMMreg(_Rs_); - if( xmminfo & XMMINFO_READT) _addNeededGPRtoXMMreg(_Rt_); - if( xmminfo & XMMINFO_WRITED ) _addNeededGPRtoXMMreg(_Rd_); - - // allocate - if( xmminfo & XMMINFO_READS) { - int reg = _allocGPRtoXMMreg(-1, _Rs_, MODE_READ); - info |= PROCESS_EE_SET_S(reg)|PROCESS_EE_SETMODES(reg); - } - if( xmminfo & XMMINFO_READT) { - int reg = _allocGPRtoXMMreg(-1, _Rt_, MODE_READ); - info |= PROCESS_EE_SET_T(reg)|PROCESS_EE_SETMODET(reg); - } - - if( xmminfo & XMMINFO_WRITED ) { - int readd = MODE_WRITE|((xmminfo&XMMINFO_READD)?((xmminfo&XMMINFO_READD_LO)?(MODE_READ|MODE_READHALF):MODE_READ):0); - - int regd = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, readd); - - if( regd < 0 ) { - if( !(xmminfo&XMMINFO_READD) && (xmminfo & XMMINFO_READT) && (_Rt_ == 0 || (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rt_)) ) { - _freeXMMreg(EEREC_T); - _deleteMMXreg(MMX_GPR+_Rd_, 2); - xmmregs[EEREC_T].inuse = 1; - xmmregs[EEREC_T].reg = _Rd_; - xmmregs[EEREC_T].mode = readd; - regd = EEREC_T; - } - else if( !(xmminfo&XMMINFO_READD) && (xmminfo & XMMINFO_READS) && (_Rs_ == 0 || (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rs_)) ) { - _freeXMMreg(EEREC_S); - _deleteMMXreg(MMX_GPR+_Rd_, 2); - xmmregs[EEREC_S].inuse = 1; - xmmregs[EEREC_S].reg = _Rd_; - xmmregs[EEREC_S].mode = readd; - regd = EEREC_S; - } - else regd = _allocGPRtoXMMreg(-1, _Rd_, readd); - } - - info |= PROCESS_EE_SET_D(regd); - } - if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { - info |= PROCESS_EE_SET_LO(_allocGPRtoXMMreg(-1, XMMGPR_LO, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0))); - info |= PROCESS_EE_LO; - } - if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { - info |= PROCESS_EE_SET_HI(_allocGPRtoXMMreg(-1, XMMGPR_HI, ((xmminfo&XMMINFO_READHI)?MODE_READ:0)|((xmminfo&XMMINFO_WRITEHI)?MODE_WRITE:0))); - info |= PROCESS_EE_HI; - } - return info; -} - -// EE COP1(FPU) XMM allocation code -#define _Ft_ _Rt_ -#define _Fs_ _Rd_ -#define _Fd_ _Sa_ - -#define PROCESS_EE_SETMODES_XMM(mmreg) ((xmmregs[mmreg].mode&MODE_WRITE)?PROCESS_EE_MODEWRITES:0) -#define PROCESS_EE_SETMODET_XMM(mmreg) ((xmmregs[mmreg].mode&MODE_WRITE)?PROCESS_EE_MODEWRITET:0) - -// rd = rs op rt -void eeFPURecompileCode(R5900FNPTR_INFO xmmcode, R5900FNPTR fpucode, int xmminfo) -{ - int mmregs=-1, mmregt=-1, mmregd=-1, mmregacc=-1; - int info = PROCESS_EE_XMM; - - if( xmminfo & XMMINFO_READS ) _addNeededFPtoXMMreg(_Fs_); - if( xmminfo & XMMINFO_READT ) _addNeededFPtoXMMreg(_Ft_); - if( xmminfo & (XMMINFO_WRITED|XMMINFO_READD) ) _addNeededFPtoXMMreg(_Fd_); - if( xmminfo & (XMMINFO_WRITEACC|XMMINFO_READACC) ) _addNeededFPACCtoXMMreg(); - - if( xmminfo & XMMINFO_READT ) { - if( g_pCurInstInfo->fpuregs[_Ft_] & EEINST_LASTUSE ) mmregt = _checkXMMreg(XMMTYPE_FPREG, _Ft_, MODE_READ); - else mmregt = _allocFPtoXMMreg(-1, _Ft_, MODE_READ); - } - - if( xmminfo & XMMINFO_READS ) { - if( ( !(xmminfo & XMMINFO_READT) || (mmregt >= 0) ) && (g_pCurInstInfo->fpuregs[_Fs_] & EEINST_LASTUSE) ) { - mmregs = _checkXMMreg(XMMTYPE_FPREG, _Fs_, MODE_READ); - } - else mmregs = _allocFPtoXMMreg(-1, _Fs_, MODE_READ); - } - - if( mmregs >= 0 ) info |= PROCESS_EE_SETMODES_XMM(mmregs); - if( mmregt >= 0 ) info |= PROCESS_EE_SETMODET_XMM(mmregt); - - if( xmminfo & XMMINFO_READD ) { - assert( xmminfo & XMMINFO_WRITED ); - mmregd = _allocFPtoXMMreg(-1, _Fd_, MODE_READ); - } - - if( xmminfo & XMMINFO_READACC ) { - if( !(xmminfo&XMMINFO_WRITEACC) && (g_pCurInstInfo->fpuregs[_Ft_] & EEINST_LASTUSE) ) - mmregacc = _checkXMMreg(XMMTYPE_FPACC, 0, MODE_READ); - else mmregacc = _allocFPACCtoXMMreg(-1, MODE_READ); - } - - if( xmminfo & XMMINFO_WRITEACC ) { - - // check for last used, if so don't alloc a new XMM reg - int readacc = MODE_WRITE|((xmminfo&XMMINFO_READACC)?MODE_READ:0); - - mmregacc = _checkXMMreg(XMMTYPE_FPACC, 0, readacc); - - if( mmregacc < 0 ) { - if( (xmminfo&XMMINFO_READT) && mmregt >= 0 && (FPUINST_LASTUSE(_Ft_) || !FPUINST_ISLIVE(_Ft_)) ) { - if( FPUINST_ISLIVE(_Ft_) ) { - _freeXMMreg(mmregt); - info &= ~PROCESS_EE_MODEWRITET; - } - _deleteMMXreg(MMX_FPU+XMMFPU_ACC, 2); - xmmregs[mmregt].inuse = 1; - xmmregs[mmregt].reg = 0; - xmmregs[mmregt].mode = readacc; - xmmregs[mmregt].type = XMMTYPE_FPACC; - mmregacc = mmregt; - } - else if( (xmminfo&XMMINFO_READS) && mmregs >= 0 && (FPUINST_LASTUSE(_Fs_) || !FPUINST_ISLIVE(_Fs_)) ) { - if( FPUINST_ISLIVE(_Fs_) ) { - _freeXMMreg(mmregs); - info &= ~PROCESS_EE_MODEWRITES; - } - _deleteMMXreg(MMX_FPU+XMMFPU_ACC, 2); - xmmregs[mmregs].inuse = 1; - xmmregs[mmregs].reg = 0; - xmmregs[mmregs].mode = readacc; - xmmregs[mmregs].type = XMMTYPE_FPACC; - mmregacc = mmregs; - } - else mmregacc = _allocFPACCtoXMMreg(-1, readacc); - } - - xmmregs[mmregacc].mode |= MODE_WRITE; - } - else if( xmminfo & XMMINFO_WRITED ) { - // check for last used, if so don't alloc a new XMM reg - int readd = MODE_WRITE|((xmminfo&XMMINFO_READD)?MODE_READ:0); - if( xmminfo&XMMINFO_READD ) mmregd = _allocFPtoXMMreg(-1, _Fd_, readd); - else mmregd = _checkXMMreg(XMMTYPE_FPREG, _Fd_, readd); - - if( mmregd < 0 ) { - if( (xmminfo&XMMINFO_READT) && mmregt >= 0 && (FPUINST_LASTUSE(_Ft_) || !FPUINST_ISLIVE(_Ft_)) ) { - if( FPUINST_ISLIVE(_Ft_) ) { - _freeXMMreg(mmregt); - info &= ~PROCESS_EE_MODEWRITET; - } - _deleteMMXreg(MMX_FPU+_Fd_, 2); - xmmregs[mmregt].inuse = 1; - xmmregs[mmregt].reg = _Fd_; - xmmregs[mmregt].mode = readd; - mmregd = mmregt; - } - else if( (xmminfo&XMMINFO_READS) && mmregs >= 0 && (FPUINST_LASTUSE(_Fs_) || !FPUINST_ISLIVE(_Fs_)) ) { - if( FPUINST_ISLIVE(_Fs_) ) { - _freeXMMreg(mmregs); - info &= ~PROCESS_EE_MODEWRITES; - } - _deleteMMXreg(MMX_FPU+_Fd_, 2); - xmmregs[mmregs].inuse = 1; - xmmregs[mmregs].reg = _Fd_; - xmmregs[mmregs].mode = readd; - mmregd = mmregs; - } - else if( (xmminfo&XMMINFO_READACC) && mmregacc >= 0 && (FPUINST_LASTUSE(XMMFPU_ACC) || !FPUINST_ISLIVE(XMMFPU_ACC)) ) { - if( FPUINST_ISLIVE(XMMFPU_ACC) ) - _freeXMMreg(mmregacc); - _deleteMMXreg(MMX_FPU+_Fd_, 2); - xmmregs[mmregacc].inuse = 1; - xmmregs[mmregacc].reg = _Fd_; - xmmregs[mmregacc].mode = readd; - xmmregs[mmregacc].type = XMMTYPE_FPREG; - mmregd = mmregacc; - } - else mmregd = _allocFPtoXMMreg(-1, _Fd_, readd); - } - } - - assert( mmregs >= 0 || mmregt >= 0 || mmregd >= 0 || mmregacc >= 0 ); - - if( xmminfo & XMMINFO_WRITED ) { - assert( mmregd >= 0 ); - info |= PROCESS_EE_SET_D(mmregd); - } - if( xmminfo & (XMMINFO_WRITEACC|XMMINFO_READACC) ) { - if( mmregacc >= 0 ) info |= PROCESS_EE_SET_ACC(mmregacc)|PROCESS_EE_ACC; - else assert( !(xmminfo&XMMINFO_WRITEACC)); - } - - if( xmminfo & XMMINFO_READS ) { - if( mmregs >= 0 ) info |= PROCESS_EE_SET_S(mmregs)|PROCESS_EE_S; - } - if( xmminfo & XMMINFO_READT ) { - if( mmregt >= 0 ) info |= PROCESS_EE_SET_T(mmregt)|PROCESS_EE_T; - } - - // at least one must be in xmm - if( (xmminfo & (XMMINFO_READS|XMMINFO_READT)) == (XMMINFO_READS|XMMINFO_READT) ) { - assert( mmregs >= 0 || mmregt >= 0 ); - } - - xmmcode(info); - _clearNeededXMMregs(); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "Memory.h" +#include "R5900OpcodeTables.h" +#include "ix86/ix86.h" +#include "iR5900.h" +#include "iMMI.h" +#include "iFPU.h" +#include "iCOP0.h" +#include "iVUmicro.h" +#include "VU.h" +#include "VUmicro.h" + +#include "iVUzerorec.h" + +#include "vtlb.h" + +//////////////////// +// Code Templates // +//////////////////// + +void CHECK_SAVE_REG(int reg) +{ + if( s_saveConstGPRreg == 0xffffffff ) { + if( GPR_IS_CONST1(reg) ) { + s_saveConstGPRreg = reg; + s_ConstGPRreg = g_cpuConstRegs[reg]; + } + } + else { + assert( s_saveConstGPRreg == 0 || s_saveConstGPRreg == reg ); + } +} + +void _eeProcessHasLive(int reg, int signext) +{ + g_cpuPrevRegHasLive1 = g_cpuRegHasLive1; + g_cpuRegHasLive1 |= 1<regs[reg]&EEINST_LASTUSE) ) { + if( usemmx ) return _allocMMXreg(-1, MMX_GPR+reg, mode); + return _allocGPRtoXMMreg(-1, reg, mode); + } + + return -1; +} + +#define PROCESS_EE_SETMODES(mmreg) ((mmxregs[mmreg].mode&MODE_WRITE)?PROCESS_EE_MODEWRITES:0) +#define PROCESS_EE_SETMODET(mmreg) ((mmxregs[mmreg].mode&MODE_WRITE)?PROCESS_EE_MODEWRITET:0) + +// ignores XMMINFO_READS, XMMINFO_READT, and XMMINFO_READD_LO from xmminfo +// core of reg caching +void eeRecompileCode0(R5900FNPTR constcode, R5900FNPTR_INFO constscode, R5900FNPTR_INFO consttcode, R5900FNPTR_INFO noconstcode, int xmminfo) +{ + int mmreg1, mmreg2, mmreg3, mmtemp, moded; + + if ( ! _Rd_ && (xmminfo&XMMINFO_WRITED) ) return; + + if( xmminfo&XMMINFO_WRITED) { + CHECK_SAVE_REG(_Rd_); + _eeProcessHasLive(_Rd_, 0); + EEINST_RESETSIGNEXT(_Rd_); + } + + if( GPR_IS_CONST2(_Rs_, _Rt_) ) { + if( xmminfo & XMMINFO_WRITED ) { + _deleteMMXreg(MMX_GPR+_Rd_, 2); + _deleteGPRtoXMMreg(_Rd_, 2); + } + if( xmminfo&XMMINFO_WRITED ) GPR_SET_CONST(_Rd_); + constcode(); + return; + } + + moded = MODE_WRITE|((xmminfo&XMMINFO_READD)?MODE_READ:0); + + // test if should write mmx + if( g_pCurInstInfo->info & EEINST_MMX ) { + + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) _addNeededMMXreg(MMX_GPR+MMX_LO); + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) _addNeededMMXreg(MMX_GPR+MMX_HI); + _addNeededMMXreg(MMX_GPR+_Rs_); + _addNeededMMXreg(MMX_GPR+_Rt_); + + if( GPR_IS_CONST1(_Rs_) || GPR_IS_CONST1(_Rt_) ) { + int creg = GPR_IS_CONST1(_Rs_) ? _Rs_ : _Rt_; + int vreg = creg == _Rs_ ? _Rt_ : _Rs_; + +// if(g_pCurInstInfo->regs[vreg]&EEINST_MMX) { +// mmreg1 = _allocMMXreg(-1, MMX_GPR+vreg, MODE_READ); +// _addNeededMMXreg(MMX_GPR+vreg); +// } + mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, vreg, MODE_READ); + + if( mmreg1 >= 0 ) { + int info = PROCESS_EE_MMX; + + if( GPR_IS_CONST1(_Rs_) ) info |= PROCESS_EE_SETMODET(mmreg1); + else info |= PROCESS_EE_SETMODES(mmreg1); + + if( xmminfo & XMMINFO_WRITED ) { + _addNeededMMXreg(MMX_GPR+_Rd_); + mmreg3 = _checkMMXreg(MMX_GPR+_Rd_, moded); + + if( !(xmminfo&XMMINFO_READD) && mmreg3 < 0 && ((g_pCurInstInfo->regs[vreg] & EEINST_LASTUSE) || !EEINST_ISLIVE64(vreg)) ) { + if( EEINST_ISLIVE64(vreg) ) { + _freeMMXreg(mmreg1); + if( GPR_IS_CONST1(_Rs_) ) info &= ~PROCESS_EE_MODEWRITET; + else info &= ~PROCESS_EE_MODEWRITES; + } + _deleteGPRtoXMMreg(_Rd_, 2); + mmxregs[mmreg1].inuse = 1; + mmxregs[mmreg1].reg = _Rd_; + mmxregs[mmreg1].mode = moded; + mmreg3 = mmreg1; + } + else if( mmreg3 < 0 ) mmreg3 = _allocMMXreg(-1, MMX_GPR+_Rd_, moded); + + info |= PROCESS_EE_SET_D(mmreg3); + } + + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { + mmtemp = eeProcessHILO(MMX_LO, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 1); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_LO(mmtemp); + } + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { + mmtemp = eeProcessHILO(MMX_HI, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 1); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_HI(mmtemp); + } + + SetMMXstate(); + if( creg == _Rs_ ) constscode(info|PROCESS_EE_SET_T(mmreg1)); + else consttcode(info|PROCESS_EE_SET_S(mmreg1)); + _clearNeededMMXregs(); + if( xmminfo & XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); + return; + } + } + else { + // no const regs + mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rs_, MODE_READ); + mmreg2 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_READ); + + if( mmreg1 >= 0 || mmreg2 >= 0 ) { + int info = PROCESS_EE_MMX; + + // do it all in mmx + if( mmreg1 < 0 ) mmreg1 = _allocMMXreg(-1, MMX_GPR+_Rs_, MODE_READ); + if( mmreg2 < 0 ) mmreg2 = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_READ); + + info |= PROCESS_EE_SETMODES(mmreg1)|PROCESS_EE_SETMODET(mmreg2); + + // check for last used, if so don't alloc a new MMX reg + if( xmminfo & XMMINFO_WRITED ) { + _addNeededMMXreg(MMX_GPR+_Rd_); + mmreg3 = _checkMMXreg(MMX_GPR+_Rd_, moded); + + if( mmreg3 < 0 ) { + if( !(xmminfo&XMMINFO_READD) && ((g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rt_)) ) { + if( EEINST_ISLIVE64(_Rt_) ) { + _freeMMXreg(mmreg2); + info &= ~PROCESS_EE_MODEWRITET; + } + _deleteGPRtoXMMreg(_Rd_, 2); + mmxregs[mmreg2].inuse = 1; + mmxregs[mmreg2].reg = _Rd_; + mmxregs[mmreg2].mode = moded; + mmreg3 = mmreg2; + } + else if( !(xmminfo&XMMINFO_READD) && ((g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rs_)) ) { + if( EEINST_ISLIVE64(_Rs_) ) { + _freeMMXreg(mmreg1); + info &= ~PROCESS_EE_MODEWRITES; + } + _deleteGPRtoXMMreg(_Rd_, 2); + mmxregs[mmreg1].inuse = 1; + mmxregs[mmreg1].reg = _Rd_; + mmxregs[mmreg1].mode = moded; + mmreg3 = mmreg1; + } + else mmreg3 = _allocMMXreg(-1, MMX_GPR+_Rd_, moded); + } + + info |= PROCESS_EE_SET_D(mmreg3); + } + + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { + mmtemp = eeProcessHILO(MMX_LO, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 1); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_LO(mmtemp); + } + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { + mmtemp = eeProcessHILO(MMX_HI, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 1); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_HI(mmtemp); + } + + SetMMXstate(); + noconstcode(info|PROCESS_EE_SET_S(mmreg1)|PROCESS_EE_SET_T(mmreg2)); + _clearNeededMMXregs(); + if( xmminfo & XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); + return; + } + } + + _clearNeededMMXregs(); + } + + // test if should write xmm, mirror to mmx code + if( g_pCurInstInfo->info & EEINST_XMM ) { + + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) _addNeededGPRtoXMMreg(XMMGPR_LO); + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) _addNeededGPRtoXMMreg(XMMGPR_HI); + _addNeededGPRtoXMMreg(_Rs_); + _addNeededGPRtoXMMreg(_Rt_); + + if( GPR_IS_CONST1(_Rs_) || GPR_IS_CONST1(_Rt_) ) { + int creg = GPR_IS_CONST1(_Rs_) ? _Rs_ : _Rt_; + int vreg = creg == _Rs_ ? _Rt_ : _Rs_; + +// if(g_pCurInstInfo->regs[vreg]&EEINST_XMM) { +// mmreg1 = _allocGPRtoXMMreg(-1, vreg, MODE_READ); +// _addNeededGPRtoXMMreg(vreg); +// } + mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, vreg, MODE_READ); + + if( mmreg1 >= 0 ) { + int info = PROCESS_EE_XMM; + + if( GPR_IS_CONST1(_Rs_) ) info |= PROCESS_EE_SETMODET(mmreg1); + else info |= PROCESS_EE_SETMODES(mmreg1); + + if( xmminfo & XMMINFO_WRITED ) { + + _addNeededGPRtoXMMreg(_Rd_); + mmreg3 = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_WRITE); + + if( !(xmminfo&XMMINFO_READD) && mmreg3 < 0 && ((g_pCurInstInfo->regs[vreg] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(vreg)) ) { + _freeXMMreg(mmreg1); + if( GPR_IS_CONST1(_Rs_) ) info &= ~PROCESS_EE_MODEWRITET; + else info &= ~PROCESS_EE_MODEWRITES; + _deleteMMXreg(MMX_GPR+_Rd_, 2); + xmmregs[mmreg1].inuse = 1; + xmmregs[mmreg1].reg = _Rd_; + xmmregs[mmreg1].mode = moded; + mmreg3 = mmreg1; + } + else if( mmreg3 < 0 ) mmreg3 = _allocGPRtoXMMreg(-1, _Rd_, moded); + + info |= PROCESS_EE_SET_D(mmreg3); + } + + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { + mmtemp = eeProcessHILO(XMMGPR_LO, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 0); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_LO(mmtemp); + } + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { + mmtemp = eeProcessHILO(XMMGPR_HI, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 0); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_HI(mmtemp); + } + + if( creg == _Rs_ ) constscode(info|PROCESS_EE_SET_T(mmreg1)); + else consttcode(info|PROCESS_EE_SET_S(mmreg1)); + _clearNeededXMMregs(); + if( xmminfo & XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); + return; + } + } + else { + // no const regs + mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rs_, MODE_READ); + mmreg2 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_READ); + + if( mmreg1 >= 0 || mmreg2 >= 0 ) { + int info = PROCESS_EE_XMM; + + // do it all in xmm + if( mmreg1 < 0 ) mmreg1 = _allocGPRtoXMMreg(-1, _Rs_, MODE_READ); + if( mmreg2 < 0 ) mmreg2 = _allocGPRtoXMMreg(-1, _Rt_, MODE_READ); + + info |= PROCESS_EE_SETMODES(mmreg1)|PROCESS_EE_SETMODET(mmreg2); + + if( xmminfo & XMMINFO_WRITED ) { + // check for last used, if so don't alloc a new XMM reg + _addNeededGPRtoXMMreg(_Rd_); + mmreg3 = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, moded); + + if( mmreg3 < 0 ) { + if( !(xmminfo&XMMINFO_READD) && ((g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rt_)) ) { + _freeXMMreg(mmreg2); + info &= ~PROCESS_EE_MODEWRITET; + _deleteMMXreg(MMX_GPR+_Rd_, 2); + xmmregs[mmreg2].inuse = 1; + xmmregs[mmreg2].reg = _Rd_; + xmmregs[mmreg2].mode = moded; + mmreg3 = mmreg2; + } + else if( !(xmminfo&XMMINFO_READD) && ((g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rs_)) ) { + _freeXMMreg(mmreg1); + info &= ~PROCESS_EE_MODEWRITES; + _deleteMMXreg(MMX_GPR+_Rd_, 2); + xmmregs[mmreg1].inuse = 1; + xmmregs[mmreg1].reg = _Rd_; + xmmregs[mmreg1].mode = moded; + mmreg3 = mmreg1; + } + else mmreg3 = _allocGPRtoXMMreg(-1, _Rd_, moded); + } + + info |= PROCESS_EE_SET_D(mmreg3); + } + + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { + mmtemp = eeProcessHILO(XMMGPR_LO, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 0); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_LO(mmtemp); + } + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { + mmtemp = eeProcessHILO(XMMGPR_HI, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0), 0); + if( mmtemp >= 0 ) info |= PROCESS_EE_SET_HI(mmtemp); + } + + noconstcode(info|PROCESS_EE_SET_S(mmreg1)|PROCESS_EE_SET_T(mmreg2)); + _clearNeededXMMregs(); + if( xmminfo & XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); + return; + } + } + + _clearNeededXMMregs(); + } + + // regular x86 + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 1); + if( xmminfo&XMMINFO_WRITED ) + _deleteGPRtoXMMreg(_Rd_, (xmminfo&XMMINFO_READD)?0:2); + _deleteMMXreg(MMX_GPR+_Rs_, 1); + _deleteMMXreg(MMX_GPR+_Rt_, 1); + if( xmminfo&XMMINFO_WRITED ) + _deleteMMXreg(MMX_GPR+_Rd_, (xmminfo&XMMINFO_READD)?0:2); + + // don't delete, fn will take care of them +// if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { +// _deleteGPRtoXMMreg(XMMGPR_LO, (xmminfo&XMMINFO_READLO)?1:0); +// _deleteMMXreg(MMX_GPR+MMX_LO, (xmminfo&XMMINFO_READLO)?1:0); +// } +// if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { +// _deleteGPRtoXMMreg(XMMGPR_HI, (xmminfo&XMMINFO_READHI)?1:0); +// _deleteMMXreg(MMX_GPR+MMX_HI, (xmminfo&XMMINFO_READHI)?1:0); +// } + + if( GPR_IS_CONST1(_Rs_) ) { + constscode(0); + if( xmminfo&XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); + return; + } + + if( GPR_IS_CONST1(_Rt_) ) { + consttcode(0); + if( xmminfo&XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); + return; + } + + noconstcode(0); + if( xmminfo&XMMINFO_WRITED ) GPR_DEL_CONST(_Rd_); +} + +// rt = rs op imm16 +void eeRecompileCode1(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode) +{ + int mmreg1, mmreg2; + if ( ! _Rt_ ) return; + + CHECK_SAVE_REG(_Rt_); + _eeProcessHasLive(_Rt_, 0); + EEINST_RESETSIGNEXT(_Rt_); + + if( GPR_IS_CONST1(_Rs_) ) { + _deleteMMXreg(MMX_GPR+_Rt_, 2); + _deleteGPRtoXMMreg(_Rt_, 2); + GPR_SET_CONST(_Rt_); + constcode(); + return; + } + + // test if should write mmx + if( g_pCurInstInfo->info & EEINST_MMX ) { + + // no const regs + mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rs_, MODE_READ); + + if( mmreg1 >= 0 ) { + int info = PROCESS_EE_MMX|PROCESS_EE_SETMODES(mmreg1); + + // check for last used, if so don't alloc a new MMX reg + _addNeededMMXreg(MMX_GPR+_Rt_); + mmreg2 = _checkMMXreg(MMX_GPR+_Rt_, MODE_WRITE); + + if( mmreg2 < 0 ) { + if( (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rs_) ) { + if( EEINST_ISLIVE64(_Rs_) ) { + _freeMMXreg(mmreg1); + info &= ~PROCESS_EE_MODEWRITES; + } + _deleteGPRtoXMMreg(_Rt_, 2); + mmxregs[mmreg1].inuse = 1; + mmxregs[mmreg1].reg = _Rt_; + mmxregs[mmreg1].mode = MODE_WRITE|MODE_READ; + mmreg2 = mmreg1; + } + else mmreg2 = _allocMMXreg(-1, MMX_GPR+_Rt_, MODE_WRITE); + } + + SetMMXstate(); + noconstcode(info|PROCESS_EE_SET_S(mmreg1)|PROCESS_EE_SET_T(mmreg2)); + _clearNeededMMXregs(); + GPR_DEL_CONST(_Rt_); + return; + } + + _clearNeededMMXregs(); + } + + // test if should write xmm, mirror to mmx code + if( g_pCurInstInfo->info & EEINST_XMM ) { + + // no const regs + mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rs_, MODE_READ); + + if( mmreg1 >= 0 ) { + int info = PROCESS_EE_XMM|PROCESS_EE_SETMODES(mmreg1); + + // check for last used, if so don't alloc a new XMM reg + _addNeededGPRtoXMMreg(_Rt_); + mmreg2 = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_WRITE); + + if( mmreg2 < 0 ) { + if( (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rs_) ) { + _freeXMMreg(mmreg1); + info &= ~PROCESS_EE_MODEWRITES; + _deleteMMXreg(MMX_GPR+_Rt_, 2); + xmmregs[mmreg1].inuse = 1; + xmmregs[mmreg1].reg = _Rt_; + xmmregs[mmreg1].mode = MODE_WRITE|MODE_READ; + mmreg2 = mmreg1; + } + else mmreg2 = _allocGPRtoXMMreg(-1, _Rt_, MODE_WRITE); + } + + noconstcode(info|PROCESS_EE_SET_S(mmreg1)|PROCESS_EE_SET_T(mmreg2)); + _clearNeededXMMregs(); + GPR_DEL_CONST(_Rt_); + return; + } + + _clearNeededXMMregs(); + } + + // regular x86 + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 2); + _deleteMMXreg(MMX_GPR+_Rs_, 1); + _deleteMMXreg(MMX_GPR+_Rt_, 2); + + noconstcode(0); + GPR_DEL_CONST(_Rt_); +} + +// rd = rt op sa +void eeRecompileCode2(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode) +{ + int mmreg1, mmreg2; + if ( ! _Rd_ ) return; + + CHECK_SAVE_REG(_Rd_); + _eeProcessHasLive(_Rd_, 0); + EEINST_RESETSIGNEXT(_Rd_); + + if( GPR_IS_CONST1(_Rt_) ) { + _deleteMMXreg(MMX_GPR+_Rd_, 2); + _deleteGPRtoXMMreg(_Rd_, 2); + GPR_SET_CONST(_Rd_); + constcode(); + return; + } + + // test if should write mmx + if( g_pCurInstInfo->info & EEINST_MMX ) { + + // no const regs + mmreg1 = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_READ); + + if( mmreg1 >= 0 ) { + int info = PROCESS_EE_MMX|PROCESS_EE_SETMODET(mmreg1); + + // check for last used, if so don't alloc a new MMX reg + _addNeededMMXreg(MMX_GPR+_Rd_); + mmreg2 = _checkMMXreg(MMX_GPR+_Rd_, MODE_WRITE); + + if( mmreg2 < 0 ) { + if( (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rt_) ) { + if( EEINST_ISLIVE64(_Rt_) ) { + _freeMMXreg(mmreg1); + info &= ~PROCESS_EE_MODEWRITET; + } + _deleteGPRtoXMMreg(_Rd_, 2); + mmxregs[mmreg1].inuse = 1; + mmxregs[mmreg1].reg = _Rd_; + mmxregs[mmreg1].mode = MODE_WRITE|MODE_READ; + mmreg2 = mmreg1; + } + else mmreg2 = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); + } + + SetMMXstate(); + noconstcode(info|PROCESS_EE_SET_T(mmreg1)|PROCESS_EE_SET_D(mmreg2)); + _clearNeededMMXregs(); + GPR_DEL_CONST(_Rd_); + return; + } + + _clearNeededMMXregs(); + } + + // test if should write xmm, mirror to mmx code + if( g_pCurInstInfo->info & EEINST_XMM ) { + + // no const regs + mmreg1 = _allocCheckGPRtoXMM(g_pCurInstInfo, _Rt_, MODE_READ); + + if( mmreg1 >= 0 ) { + int info = PROCESS_EE_XMM|PROCESS_EE_SETMODET(mmreg1); + + // check for last used, if so don't alloc a new XMM reg + _addNeededGPRtoXMMreg(_Rd_); + mmreg2 = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_WRITE); + + if( mmreg2 < 0 ) { + if( (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVE64(_Rt_) ) { + _freeXMMreg(mmreg1); + info &= ~PROCESS_EE_MODEWRITET; + _deleteMMXreg(MMX_GPR+_Rd_, 2); + xmmregs[mmreg1].inuse = 1; + xmmregs[mmreg1].reg = _Rd_; + xmmregs[mmreg1].mode = MODE_WRITE|MODE_READ; + mmreg2 = mmreg1; + } + else mmreg2 = _allocGPRtoXMMreg(-1, _Rd_, MODE_WRITE); + } + + noconstcode(info|PROCESS_EE_SET_T(mmreg1)|PROCESS_EE_SET_D(mmreg2)); + _clearNeededXMMregs(); + GPR_DEL_CONST(_Rd_); + return; + } + + _clearNeededXMMregs(); + } + + // regular x86 + _deleteGPRtoXMMreg(_Rt_, 1); + _deleteGPRtoXMMreg(_Rd_, 2); + _deleteMMXreg(MMX_GPR+_Rt_, 1); + _deleteMMXreg(MMX_GPR+_Rd_, 2); + + noconstcode(0); + GPR_DEL_CONST(_Rd_); +} + +// rt op rs +void eeRecompileCode3(R5900FNPTR constcode, R5900FNPTR_INFO multicode) +{ + assert(0); + // for now, don't support xmm + _deleteEEreg(_Rs_, 1); + _deleteEEreg(_Rt_, 1); + + if( GPR_IS_CONST2(_Rs_, _Rt_) ) { + constcode(); + return; + } + + if( GPR_IS_CONST1(_Rs_) ) { + //multicode(PROCESS_EE_CONSTT); + return; + } + + if( GPR_IS_CONST1(_Rt_) ) { + //multicode(PROCESS_EE_CONSTT); + return; + } + + multicode(0); +} + +// Simple Code Templates // + +// rd = rs op rt +void eeRecompileCodeConst0(R5900FNPTR constcode, R5900FNPTR_INFO constscode, R5900FNPTR_INFO consttcode, R5900FNPTR_INFO noconstcode) +{ + if ( ! _Rd_ ) return; + + // for now, don't support xmm + CHECK_SAVE_REG(_Rd_); + + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 1); + _deleteGPRtoXMMreg(_Rd_, 0); + _deleteMMXreg(MMX_GPR+_Rs_, 1); + _deleteMMXreg(MMX_GPR+_Rt_, 1); + _deleteMMXreg(MMX_GPR+_Rd_, 0); + + if( GPR_IS_CONST2(_Rs_, _Rt_) ) { + GPR_SET_CONST(_Rd_); + constcode(); + return; + } + + if( GPR_IS_CONST1(_Rs_) ) { + constscode(0); + GPR_DEL_CONST(_Rd_); + return; + } + + if( GPR_IS_CONST1(_Rt_) ) { + consttcode(0); + GPR_DEL_CONST(_Rd_); + return; + } + + noconstcode(0); + GPR_DEL_CONST(_Rd_); +} + +// rt = rs op imm16 +void eeRecompileCodeConst1(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode) +{ + if ( ! _Rt_ ) + return; + + // for now, don't support xmm + CHECK_SAVE_REG(_Rt_); + + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 0); + + if( GPR_IS_CONST1(_Rs_) ) { + GPR_SET_CONST(_Rt_); + constcode(); + return; + } + + noconstcode(0); + GPR_DEL_CONST(_Rt_); +} + +// rd = rt op sa +void eeRecompileCodeConst2(R5900FNPTR constcode, R5900FNPTR_INFO noconstcode) +{ + if ( ! _Rd_ ) return; + + // for now, don't support xmm + CHECK_SAVE_REG(_Rd_); + + _deleteGPRtoXMMreg(_Rt_, 1); + _deleteGPRtoXMMreg(_Rd_, 0); + + if( GPR_IS_CONST1(_Rt_) ) { + GPR_SET_CONST(_Rd_); + constcode(); + return; + } + + noconstcode(0); + GPR_DEL_CONST(_Rd_); +} + +// rd = rt MULT rs (SPECIAL) +void eeRecompileCodeConstSPECIAL(R5900FNPTR constcode, R5900FNPTR_INFO multicode, int MULT) +{ + assert(0); + // for now, don't support xmm + if( MULT ) { + CHECK_SAVE_REG(_Rd_); + _deleteGPRtoXMMreg(_Rd_, 0); + } + + _deleteGPRtoXMMreg(_Rs_, 1); + _deleteGPRtoXMMreg(_Rt_, 1); + + if( GPR_IS_CONST2(_Rs_, _Rt_) ) { + if( MULT && _Rd_ ) GPR_SET_CONST(_Rd_); + constcode(); + return; + } + + if( GPR_IS_CONST1(_Rs_) ) { + //multicode(PROCESS_EE_CONSTS); + if( MULT && _Rd_ ) GPR_DEL_CONST(_Rd_); + return; + } + + if( GPR_IS_CONST1(_Rt_) ) { + //multicode(PROCESS_EE_CONSTT); + if( MULT && _Rd_ ) GPR_DEL_CONST(_Rd_); + return; + } + + multicode(0); + if( MULT && _Rd_ ) GPR_DEL_CONST(_Rd_); +} + +// EE XMM allocation code +int eeRecompileCodeXMM(int xmminfo) +{ + int info = PROCESS_EE_XMM; + + // save state + if( xmminfo & XMMINFO_WRITED ) { + CHECK_SAVE_REG(_Rd_); + _eeProcessHasLive(_Rd_, 0); + EEINST_RESETSIGNEXT(_Rd_); + } + + // flush consts + if( xmminfo & XMMINFO_READT ) { + if( GPR_IS_CONST1( _Rt_ ) && !(g_cpuFlushedConstReg&(1<<_Rt_)) ) { + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0]); + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1]); + g_cpuFlushedConstReg |= (1<<_Rt_); + } + } + if( xmminfo & XMMINFO_READS) { + if( GPR_IS_CONST1( _Rs_ ) && !(g_cpuFlushedConstReg&(1<<_Rs_)) ) { + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); + MOV32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); + g_cpuFlushedConstReg |= (1<<_Rs_); + } + } + + if( xmminfo & XMMINFO_WRITED ) { + GPR_DEL_CONST(_Rd_); + } + + // add needed + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { + _addNeededGPRtoXMMreg(XMMGPR_LO); + } + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { + _addNeededGPRtoXMMreg(XMMGPR_HI); + } + if( xmminfo & XMMINFO_READS) _addNeededGPRtoXMMreg(_Rs_); + if( xmminfo & XMMINFO_READT) _addNeededGPRtoXMMreg(_Rt_); + if( xmminfo & XMMINFO_WRITED ) _addNeededGPRtoXMMreg(_Rd_); + + // allocate + if( xmminfo & XMMINFO_READS) { + int reg = _allocGPRtoXMMreg(-1, _Rs_, MODE_READ); + info |= PROCESS_EE_SET_S(reg)|PROCESS_EE_SETMODES(reg); + } + if( xmminfo & XMMINFO_READT) { + int reg = _allocGPRtoXMMreg(-1, _Rt_, MODE_READ); + info |= PROCESS_EE_SET_T(reg)|PROCESS_EE_SETMODET(reg); + } + + if( xmminfo & XMMINFO_WRITED ) { + int readd = MODE_WRITE|((xmminfo&XMMINFO_READD)?((xmminfo&XMMINFO_READD_LO)?(MODE_READ|MODE_READHALF):MODE_READ):0); + + int regd = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, readd); + + if( regd < 0 ) { + if( !(xmminfo&XMMINFO_READD) && (xmminfo & XMMINFO_READT) && (_Rt_ == 0 || (g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rt_)) ) { + _freeXMMreg(EEREC_T); + _deleteMMXreg(MMX_GPR+_Rd_, 2); + xmmregs[EEREC_T].inuse = 1; + xmmregs[EEREC_T].reg = _Rd_; + xmmregs[EEREC_T].mode = readd; + regd = EEREC_T; + } + else if( !(xmminfo&XMMINFO_READD) && (xmminfo & XMMINFO_READS) && (_Rs_ == 0 || (g_pCurInstInfo->regs[_Rs_] & EEINST_LASTUSE) || !EEINST_ISLIVEXMM(_Rs_)) ) { + _freeXMMreg(EEREC_S); + _deleteMMXreg(MMX_GPR+_Rd_, 2); + xmmregs[EEREC_S].inuse = 1; + xmmregs[EEREC_S].reg = _Rd_; + xmmregs[EEREC_S].mode = readd; + regd = EEREC_S; + } + else regd = _allocGPRtoXMMreg(-1, _Rd_, readd); + } + + info |= PROCESS_EE_SET_D(regd); + } + if( xmminfo & (XMMINFO_READLO|XMMINFO_WRITELO) ) { + info |= PROCESS_EE_SET_LO(_allocGPRtoXMMreg(-1, XMMGPR_LO, ((xmminfo&XMMINFO_READLO)?MODE_READ:0)|((xmminfo&XMMINFO_WRITELO)?MODE_WRITE:0))); + info |= PROCESS_EE_LO; + } + if( xmminfo & (XMMINFO_READHI|XMMINFO_WRITEHI) ) { + info |= PROCESS_EE_SET_HI(_allocGPRtoXMMreg(-1, XMMGPR_HI, ((xmminfo&XMMINFO_READHI)?MODE_READ:0)|((xmminfo&XMMINFO_WRITEHI)?MODE_WRITE:0))); + info |= PROCESS_EE_HI; + } + return info; +} + +// EE COP1(FPU) XMM allocation code +#define _Ft_ _Rt_ +#define _Fs_ _Rd_ +#define _Fd_ _Sa_ + +#define PROCESS_EE_SETMODES_XMM(mmreg) ((xmmregs[mmreg].mode&MODE_WRITE)?PROCESS_EE_MODEWRITES:0) +#define PROCESS_EE_SETMODET_XMM(mmreg) ((xmmregs[mmreg].mode&MODE_WRITE)?PROCESS_EE_MODEWRITET:0) + +// rd = rs op rt +void eeFPURecompileCode(R5900FNPTR_INFO xmmcode, R5900FNPTR fpucode, int xmminfo) +{ + int mmregs=-1, mmregt=-1, mmregd=-1, mmregacc=-1; + int info = PROCESS_EE_XMM; + + if( xmminfo & XMMINFO_READS ) _addNeededFPtoXMMreg(_Fs_); + if( xmminfo & XMMINFO_READT ) _addNeededFPtoXMMreg(_Ft_); + if( xmminfo & (XMMINFO_WRITED|XMMINFO_READD) ) _addNeededFPtoXMMreg(_Fd_); + if( xmminfo & (XMMINFO_WRITEACC|XMMINFO_READACC) ) _addNeededFPACCtoXMMreg(); + + if( xmminfo & XMMINFO_READT ) { + if( g_pCurInstInfo->fpuregs[_Ft_] & EEINST_LASTUSE ) mmregt = _checkXMMreg(XMMTYPE_FPREG, _Ft_, MODE_READ); + else mmregt = _allocFPtoXMMreg(-1, _Ft_, MODE_READ); + } + + if( xmminfo & XMMINFO_READS ) { + if( ( !(xmminfo & XMMINFO_READT) || (mmregt >= 0) ) && (g_pCurInstInfo->fpuregs[_Fs_] & EEINST_LASTUSE) ) { + mmregs = _checkXMMreg(XMMTYPE_FPREG, _Fs_, MODE_READ); + } + else mmregs = _allocFPtoXMMreg(-1, _Fs_, MODE_READ); + } + + if( mmregs >= 0 ) info |= PROCESS_EE_SETMODES_XMM(mmregs); + if( mmregt >= 0 ) info |= PROCESS_EE_SETMODET_XMM(mmregt); + + if( xmminfo & XMMINFO_READD ) { + assert( xmminfo & XMMINFO_WRITED ); + mmregd = _allocFPtoXMMreg(-1, _Fd_, MODE_READ); + } + + if( xmminfo & XMMINFO_READACC ) { + if( !(xmminfo&XMMINFO_WRITEACC) && (g_pCurInstInfo->fpuregs[_Ft_] & EEINST_LASTUSE) ) + mmregacc = _checkXMMreg(XMMTYPE_FPACC, 0, MODE_READ); + else mmregacc = _allocFPACCtoXMMreg(-1, MODE_READ); + } + + if( xmminfo & XMMINFO_WRITEACC ) { + + // check for last used, if so don't alloc a new XMM reg + int readacc = MODE_WRITE|((xmminfo&XMMINFO_READACC)?MODE_READ:0); + + mmregacc = _checkXMMreg(XMMTYPE_FPACC, 0, readacc); + + if( mmregacc < 0 ) { + if( (xmminfo&XMMINFO_READT) && mmregt >= 0 && (FPUINST_LASTUSE(_Ft_) || !FPUINST_ISLIVE(_Ft_)) ) { + if( FPUINST_ISLIVE(_Ft_) ) { + _freeXMMreg(mmregt); + info &= ~PROCESS_EE_MODEWRITET; + } + _deleteMMXreg(MMX_FPU+XMMFPU_ACC, 2); + xmmregs[mmregt].inuse = 1; + xmmregs[mmregt].reg = 0; + xmmregs[mmregt].mode = readacc; + xmmregs[mmregt].type = XMMTYPE_FPACC; + mmregacc = mmregt; + } + else if( (xmminfo&XMMINFO_READS) && mmregs >= 0 && (FPUINST_LASTUSE(_Fs_) || !FPUINST_ISLIVE(_Fs_)) ) { + if( FPUINST_ISLIVE(_Fs_) ) { + _freeXMMreg(mmregs); + info &= ~PROCESS_EE_MODEWRITES; + } + _deleteMMXreg(MMX_FPU+XMMFPU_ACC, 2); + xmmregs[mmregs].inuse = 1; + xmmregs[mmregs].reg = 0; + xmmregs[mmregs].mode = readacc; + xmmregs[mmregs].type = XMMTYPE_FPACC; + mmregacc = mmregs; + } + else mmregacc = _allocFPACCtoXMMreg(-1, readacc); + } + + xmmregs[mmregacc].mode |= MODE_WRITE; + } + else if( xmminfo & XMMINFO_WRITED ) { + // check for last used, if so don't alloc a new XMM reg + int readd = MODE_WRITE|((xmminfo&XMMINFO_READD)?MODE_READ:0); + if( xmminfo&XMMINFO_READD ) mmregd = _allocFPtoXMMreg(-1, _Fd_, readd); + else mmregd = _checkXMMreg(XMMTYPE_FPREG, _Fd_, readd); + + if( mmregd < 0 ) { + if( (xmminfo&XMMINFO_READT) && mmregt >= 0 && (FPUINST_LASTUSE(_Ft_) || !FPUINST_ISLIVE(_Ft_)) ) { + if( FPUINST_ISLIVE(_Ft_) ) { + _freeXMMreg(mmregt); + info &= ~PROCESS_EE_MODEWRITET; + } + _deleteMMXreg(MMX_FPU+_Fd_, 2); + xmmregs[mmregt].inuse = 1; + xmmregs[mmregt].reg = _Fd_; + xmmregs[mmregt].mode = readd; + mmregd = mmregt; + } + else if( (xmminfo&XMMINFO_READS) && mmregs >= 0 && (FPUINST_LASTUSE(_Fs_) || !FPUINST_ISLIVE(_Fs_)) ) { + if( FPUINST_ISLIVE(_Fs_) ) { + _freeXMMreg(mmregs); + info &= ~PROCESS_EE_MODEWRITES; + } + _deleteMMXreg(MMX_FPU+_Fd_, 2); + xmmregs[mmregs].inuse = 1; + xmmregs[mmregs].reg = _Fd_; + xmmregs[mmregs].mode = readd; + mmregd = mmregs; + } + else if( (xmminfo&XMMINFO_READACC) && mmregacc >= 0 && (FPUINST_LASTUSE(XMMFPU_ACC) || !FPUINST_ISLIVE(XMMFPU_ACC)) ) { + if( FPUINST_ISLIVE(XMMFPU_ACC) ) + _freeXMMreg(mmregacc); + _deleteMMXreg(MMX_FPU+_Fd_, 2); + xmmregs[mmregacc].inuse = 1; + xmmregs[mmregacc].reg = _Fd_; + xmmregs[mmregacc].mode = readd; + xmmregs[mmregacc].type = XMMTYPE_FPREG; + mmregd = mmregacc; + } + else mmregd = _allocFPtoXMMreg(-1, _Fd_, readd); + } + } + + assert( mmregs >= 0 || mmregt >= 0 || mmregd >= 0 || mmregacc >= 0 ); + + if( xmminfo & XMMINFO_WRITED ) { + assert( mmregd >= 0 ); + info |= PROCESS_EE_SET_D(mmregd); + } + if( xmminfo & (XMMINFO_WRITEACC|XMMINFO_READACC) ) { + if( mmregacc >= 0 ) info |= PROCESS_EE_SET_ACC(mmregacc)|PROCESS_EE_ACC; + else assert( !(xmminfo&XMMINFO_WRITEACC)); + } + + if( xmminfo & XMMINFO_READS ) { + if( mmregs >= 0 ) info |= PROCESS_EE_SET_S(mmregs)|PROCESS_EE_S; + } + if( xmminfo & XMMINFO_READT ) { + if( mmregt >= 0 ) info |= PROCESS_EE_SET_T(mmregt)|PROCESS_EE_T; + } + + // at least one must be in xmm + if( (xmminfo & (XMMINFO_READS|XMMINFO_READT)) == (XMMINFO_READS|XMMINFO_READT) ) { + assert( mmregs >= 0 || mmregt >= 0 ); + } + + xmmcode(info); + _clearNeededXMMregs(); +} diff --git a/pcsx2/x86/ix86-32/recVTLB.cpp b/pcsx2/x86/ix86-32/recVTLB.cpp index 80a05fb78c..68f102c792 100644 --- a/pcsx2/x86/ix86-32/recVTLB.cpp +++ b/pcsx2/x86/ix86-32/recVTLB.cpp @@ -1,319 +1,319 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Common.h" -#include "vtlb.h" - -#include "x86/ix86/ix86.h" -#include "iCore.h" -#include "iR5900.h" - -using namespace vtlb_private; - -/* - // Pseudo-Code For the following Dynarec Implementations --> - - u32 vmv=vmap[addr>>VTLB_PAGE_BITS]; - s32 ppf=addr+vmv; - if (!(ppf<0)) - { - data[0]=*reinterpret_cast(ppf); - if (DataSize==128) - data[1]=*reinterpret_cast(ppf+8); - return 0; - } - else - { - //has to: translate, find function, call function - u32 hand=(u8)vmv; - u32 paddr=ppf-hand+0x80000000; - //SysPrintf("Translted 0x%08X to 0x%08X\n",addr,paddr); - return reinterpret_cast::HandlerType*>(RWFT[TemplateHelper::sidx][0][hand])(paddr,data); - } - - // And in ASM it looks something like this --> - - mov eax,ecx; - shr eax,VTLB_PAGE_BITS; - mov eax,[eax*4+vmap]; - add ecx,eax; - js _fullread; - - //these are wrong order, just an example ... - mov [eax],ecx; - mov ecx,[edx]; - mov [eax+4],ecx; - mov ecx,[edx+4]; - mov [eax+4+4],ecx; - mov ecx,[edx+4+4]; - mov [eax+4+4+4+4],ecx; - mov ecx,[edx+4+4+4+4]; - ///.... - - jmp cont; - _fullread: - movzx eax,al; - sub ecx,eax; - sub ecx,0x80000000; - call [eax+stuff]; - cont: - ........ - - */ - - -//ecx = addr -//edx = ptr -void vtlb_DynGenRead64(u32 bits) -{ - MOV32RtoR(EAX,ECX); - SHR32ItoR(EAX,VTLB_PAGE_BITS); - MOV32RmSOffsettoR(EAX,EAX,(int)vmap,2); - ADD32RtoR(ECX,EAX); - u8* _fullread=JS8(0); - switch(bits) - { - case 64: - if( _hasFreeMMXreg() ) - { - const int freereg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQRmtoROffset(freereg,ECX,0); - MOVQRtoRmOffset(EDX,freereg,0); - _freeMMXreg(freereg); - } - else - { - MOV32RmtoR(EAX,ECX); - MOV32RtoRm(EDX,EAX); - - MOV32RmtoROffset(EAX,ECX,4); - MOV32RtoRmOffset(EDX,EAX,4); - } - break; - - case 128: - if( _hasFreeXMMreg() ) - { - const int freereg = _allocTempXMMreg( XMMT_INT, -1 ); - SSE2_MOVDQARmtoROffset(freereg,ECX,0); - SSE2_MOVDQARtoRmOffset(EDX,freereg,0); - _freeXMMreg(freereg); - } - else - { - // Could put in an MMX optimization here as well, but no point really. - // It's almost never used since there's almost always a free XMM reg. - - MOV32RmtoR(EAX,ECX); - MOV32RtoRm(EDX,EAX); - - MOV32RmtoROffset(EAX,ECX,4); - MOV32RtoRmOffset(EDX,EAX,4); - - MOV32RmtoROffset(EAX,ECX,8); - MOV32RtoRmOffset(EDX,EAX,8); - - MOV32RmtoROffset(EAX,ECX,12); - MOV32RtoRmOffset(EDX,EAX,12); - } - break; - - jNO_DEFAULT - } - - u8* cont=JMP8(0); - x86SetJ8(_fullread); - int szidx; - - switch(bits) - { - case 64: szidx=3; break; - case 128: szidx=4; break; - jNO_DEFAULT - } - - MOVZX32R8toR(EAX,EAX); - SUB32RtoR(ECX,EAX); - //eax=[funct+eax] - MOV32RmSOffsettoR(EAX,EAX,(int)RWFT[szidx][0],2); - SUB32ItoR(ECX,0x80000000); - CALL32R(EAX); - - x86SetJ8(cont); -} - -// ecx - source address to read from -// Returns read value in eax. -void vtlb_DynGenRead32(u32 bits, bool sign) -{ - jASSUME( bits <= 32 ); - - MOV32RtoR(EAX,ECX); - SHR32ItoR(EAX,VTLB_PAGE_BITS); - MOV32RmSOffsettoR(EAX,EAX,(int)vmap,2); - ADD32RtoR(ECX,EAX); - u8* _fullread=JS8(0); - - switch(bits) - { - case 8: - if( sign ) - MOVSX32Rm8toR(EAX,ECX); - else - MOVZX32Rm8toR(EAX,ECX); - break; - - case 16: - if( sign ) - MOVSX32Rm16toR(EAX,ECX); - else - MOVZX32Rm16toR(EAX,ECX); - break; - - case 32: - MOV32RmtoR(EAX,ECX); - break; - - jNO_DEFAULT - } - - u8* cont=JMP8(0); - x86SetJ8(_fullread); - int szidx; - - switch(bits) - { - case 8: szidx=0; break; - case 16: szidx=1; break; - case 32: szidx=2; break; - jNO_DEFAULT - } - - MOVZX32R8toR(EAX,EAX); - SUB32RtoR(ECX,EAX); - //eax=[funct+eax] - MOV32RmSOffsettoR(EAX,EAX,(int)RWFT[szidx][0],2); - SUB32ItoR(ECX,0x80000000); - CALL32R(EAX); - - // perform sign extension on the result: - - if( bits==8 ) - { - if( sign ) - MOVSX32R8toR(EAX,EAX); - else - MOVZX32R8toR(EAX,EAX); - } - else if( bits==16 ) - { - if( sign ) - MOVSX32R16toR(EAX,EAX); - else - MOVZX32R16toR(EAX,EAX); - } - - x86SetJ8(cont); -} - -void vtlb_DynGenWrite(u32 sz) -{ - MOV32RtoR(EAX,ECX); - SHR32ItoR(EAX,VTLB_PAGE_BITS); - MOV32RmSOffsettoR(EAX,EAX,(int)vmap,2); - ADD32RtoR(ECX,EAX); - u8* _full=JS8(0); - switch(sz) - { - //8 , 16, 32 : data on EDX - case 8: - MOV8RtoRm(ECX,EDX); - break; - case 16: - MOV16RtoRm(ECX,EDX); - break; - case 32: - MOV32RtoRm(ECX,EDX); - break; - - case 64: - if( _hasFreeMMXreg() ) - { - const int freereg = _allocMMXreg(-1, MMX_TEMP, 0); - MOVQRmtoROffset(freereg,EDX,0); - MOVQRtoRmOffset(ECX,freereg,0); - _freeMMXreg( freereg ); - } - else - { - MOV32RmtoR(EAX,EDX); - MOV32RtoRm(ECX,EAX); - - MOV32RmtoROffset(EAX,EDX,4); - MOV32RtoRmOffset(ECX,EAX,4); - } - break; - - case 128: - if( _hasFreeXMMreg() ) - { - const int freereg = _allocTempXMMreg( XMMT_INT, -1 ); - SSE2_MOVDQARmtoROffset(freereg,EDX,0); - SSE2_MOVDQARtoRmOffset(ECX,freereg,0); - _freeXMMreg( freereg ); - } - else - { - // Could put in an MMX optimization here as well, but no point really. - // It's almost never used since there's almost always a free XMM reg. - - MOV32RmtoR(EAX,EDX); - MOV32RtoRm(ECX,EAX); - MOV32RmtoROffset(EAX,EDX,4); - MOV32RtoRmOffset(ECX,EAX,4); - MOV32RmtoROffset(EAX,EDX,8); - MOV32RtoRmOffset(ECX,EAX,8); - MOV32RmtoROffset(EAX,EDX,12); - MOV32RtoRmOffset(ECX,EAX,12); - } - break; - } - u8* cont=JMP8(0); - - x86SetJ8(_full); - - int szidx=0; - switch(sz) - { - case 8: szidx=0; break; - case 16: szidx=1; break; - case 32: szidx=2; break; - case 64: szidx=3; break; - case 128: szidx=4; break; - } - MOVZX32R8toR(EAX,EAX); - SUB32RtoR(ECX,EAX); - //eax=[funct+eax] - MOV32RmSOffsettoR(EAX,EAX,(int)RWFT[szidx][1],2); - SUB32ItoR(ECX,0x80000000); - CALL32R(EAX); - - x86SetJ8(cont); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Common.h" +#include "vtlb.h" + +#include "x86/ix86/ix86.h" +#include "iCore.h" +#include "iR5900.h" + +using namespace vtlb_private; + +/* + // Pseudo-Code For the following Dynarec Implementations --> + + u32 vmv=vmap[addr>>VTLB_PAGE_BITS]; + s32 ppf=addr+vmv; + if (!(ppf<0)) + { + data[0]=*reinterpret_cast(ppf); + if (DataSize==128) + data[1]=*reinterpret_cast(ppf+8); + return 0; + } + else + { + //has to: translate, find function, call function + u32 hand=(u8)vmv; + u32 paddr=ppf-hand+0x80000000; + //SysPrintf("Translted 0x%08X to 0x%08X\n",addr,paddr); + return reinterpret_cast::HandlerType*>(RWFT[TemplateHelper::sidx][0][hand])(paddr,data); + } + + // And in ASM it looks something like this --> + + mov eax,ecx; + shr eax,VTLB_PAGE_BITS; + mov eax,[eax*4+vmap]; + add ecx,eax; + js _fullread; + + //these are wrong order, just an example ... + mov [eax],ecx; + mov ecx,[edx]; + mov [eax+4],ecx; + mov ecx,[edx+4]; + mov [eax+4+4],ecx; + mov ecx,[edx+4+4]; + mov [eax+4+4+4+4],ecx; + mov ecx,[edx+4+4+4+4]; + ///.... + + jmp cont; + _fullread: + movzx eax,al; + sub ecx,eax; + sub ecx,0x80000000; + call [eax+stuff]; + cont: + ........ + + */ + + +//ecx = addr +//edx = ptr +void vtlb_DynGenRead64(u32 bits) +{ + MOV32RtoR(EAX,ECX); + SHR32ItoR(EAX,VTLB_PAGE_BITS); + MOV32RmSOffsettoR(EAX,EAX,(int)vmap,2); + ADD32RtoR(ECX,EAX); + u8* _fullread=JS8(0); + switch(bits) + { + case 64: + if( _hasFreeMMXreg() ) + { + const int freereg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRmtoROffset(freereg,ECX,0); + MOVQRtoRmOffset(EDX,freereg,0); + _freeMMXreg(freereg); + } + else + { + MOV32RmtoR(EAX,ECX); + MOV32RtoRm(EDX,EAX); + + MOV32RmtoROffset(EAX,ECX,4); + MOV32RtoRmOffset(EDX,EAX,4); + } + break; + + case 128: + if( _hasFreeXMMreg() ) + { + const int freereg = _allocTempXMMreg( XMMT_INT, -1 ); + SSE2_MOVDQARmtoROffset(freereg,ECX,0); + SSE2_MOVDQARtoRmOffset(EDX,freereg,0); + _freeXMMreg(freereg); + } + else + { + // Could put in an MMX optimization here as well, but no point really. + // It's almost never used since there's almost always a free XMM reg. + + MOV32RmtoR(EAX,ECX); + MOV32RtoRm(EDX,EAX); + + MOV32RmtoROffset(EAX,ECX,4); + MOV32RtoRmOffset(EDX,EAX,4); + + MOV32RmtoROffset(EAX,ECX,8); + MOV32RtoRmOffset(EDX,EAX,8); + + MOV32RmtoROffset(EAX,ECX,12); + MOV32RtoRmOffset(EDX,EAX,12); + } + break; + + jNO_DEFAULT + } + + u8* cont=JMP8(0); + x86SetJ8(_fullread); + int szidx; + + switch(bits) + { + case 64: szidx=3; break; + case 128: szidx=4; break; + jNO_DEFAULT + } + + MOVZX32R8toR(EAX,EAX); + SUB32RtoR(ECX,EAX); + //eax=[funct+eax] + MOV32RmSOffsettoR(EAX,EAX,(int)RWFT[szidx][0],2); + SUB32ItoR(ECX,0x80000000); + CALL32R(EAX); + + x86SetJ8(cont); +} + +// ecx - source address to read from +// Returns read value in eax. +void vtlb_DynGenRead32(u32 bits, bool sign) +{ + jASSUME( bits <= 32 ); + + MOV32RtoR(EAX,ECX); + SHR32ItoR(EAX,VTLB_PAGE_BITS); + MOV32RmSOffsettoR(EAX,EAX,(int)vmap,2); + ADD32RtoR(ECX,EAX); + u8* _fullread=JS8(0); + + switch(bits) + { + case 8: + if( sign ) + MOVSX32Rm8toR(EAX,ECX); + else + MOVZX32Rm8toR(EAX,ECX); + break; + + case 16: + if( sign ) + MOVSX32Rm16toR(EAX,ECX); + else + MOVZX32Rm16toR(EAX,ECX); + break; + + case 32: + MOV32RmtoR(EAX,ECX); + break; + + jNO_DEFAULT + } + + u8* cont=JMP8(0); + x86SetJ8(_fullread); + int szidx; + + switch(bits) + { + case 8: szidx=0; break; + case 16: szidx=1; break; + case 32: szidx=2; break; + jNO_DEFAULT + } + + MOVZX32R8toR(EAX,EAX); + SUB32RtoR(ECX,EAX); + //eax=[funct+eax] + MOV32RmSOffsettoR(EAX,EAX,(int)RWFT[szidx][0],2); + SUB32ItoR(ECX,0x80000000); + CALL32R(EAX); + + // perform sign extension on the result: + + if( bits==8 ) + { + if( sign ) + MOVSX32R8toR(EAX,EAX); + else + MOVZX32R8toR(EAX,EAX); + } + else if( bits==16 ) + { + if( sign ) + MOVSX32R16toR(EAX,EAX); + else + MOVZX32R16toR(EAX,EAX); + } + + x86SetJ8(cont); +} + +void vtlb_DynGenWrite(u32 sz) +{ + MOV32RtoR(EAX,ECX); + SHR32ItoR(EAX,VTLB_PAGE_BITS); + MOV32RmSOffsettoR(EAX,EAX,(int)vmap,2); + ADD32RtoR(ECX,EAX); + u8* _full=JS8(0); + switch(sz) + { + //8 , 16, 32 : data on EDX + case 8: + MOV8RtoRm(ECX,EDX); + break; + case 16: + MOV16RtoRm(ECX,EDX); + break; + case 32: + MOV32RtoRm(ECX,EDX); + break; + + case 64: + if( _hasFreeMMXreg() ) + { + const int freereg = _allocMMXreg(-1, MMX_TEMP, 0); + MOVQRmtoROffset(freereg,EDX,0); + MOVQRtoRmOffset(ECX,freereg,0); + _freeMMXreg( freereg ); + } + else + { + MOV32RmtoR(EAX,EDX); + MOV32RtoRm(ECX,EAX); + + MOV32RmtoROffset(EAX,EDX,4); + MOV32RtoRmOffset(ECX,EAX,4); + } + break; + + case 128: + if( _hasFreeXMMreg() ) + { + const int freereg = _allocTempXMMreg( XMMT_INT, -1 ); + SSE2_MOVDQARmtoROffset(freereg,EDX,0); + SSE2_MOVDQARtoRmOffset(ECX,freereg,0); + _freeXMMreg( freereg ); + } + else + { + // Could put in an MMX optimization here as well, but no point really. + // It's almost never used since there's almost always a free XMM reg. + + MOV32RmtoR(EAX,EDX); + MOV32RtoRm(ECX,EAX); + MOV32RmtoROffset(EAX,EDX,4); + MOV32RtoRmOffset(ECX,EAX,4); + MOV32RmtoROffset(EAX,EDX,8); + MOV32RtoRmOffset(ECX,EAX,8); + MOV32RmtoROffset(EAX,EDX,12); + MOV32RtoRmOffset(ECX,EAX,12); + } + break; + } + u8* cont=JMP8(0); + + x86SetJ8(_full); + + int szidx=0; + switch(sz) + { + case 8: szidx=0; break; + case 16: szidx=1; break; + case 32: szidx=2; break; + case 64: szidx=3; break; + case 128: szidx=4; break; + } + MOVZX32R8toR(EAX,EAX); + SUB32RtoR(ECX,EAX); + //eax=[funct+eax] + MOV32RmSOffsettoR(EAX,EAX,(int)RWFT[szidx][1],2); + SUB32ItoR(ECX,0x80000000); + CALL32R(EAX); + + x86SetJ8(cont); +} diff --git a/pcsx2/x86/ix86/ix86.cpp b/pcsx2/x86/ix86/ix86.cpp index 5ed9b637cd..c020ee837e 100644 --- a/pcsx2/x86/ix86/ix86.cpp +++ b/pcsx2/x86/ix86/ix86.cpp @@ -1,3360 +1,3360 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -/* - * ix86 core v0.6.2 - * Authors: linuzappz - * alexey silinov - * goldfinger - * zerofrog(@gmail.com) - */ - -#include "PrecompiledHeader.h" -#include "System.h" - -#include "ix86.h" - -#define SWAP(x, y) { *(u32*)&y ^= *(u32*)&x; *(u32*)&x ^= *(u32*)&y; *(u32*)&y ^= *(u32*)&x; } - -u8 *x86Ptr; -u8 *j8Ptr[32]; -u32 *j32Ptr[32]; - -extern void SysPrintf(const char *fmt, ...); - -__forceinline void WriteRmOffset(x86IntRegType to, s32 offset) -{ - if( (to&7) == ESP ) { - if( offset == 0 ) { - ModRM( 0, 0, 4 ); - SibSB( 0, ESP, 4 ); - } - else if( offset < 128 && offset >= -128 ) { - ModRM( 1, 0, 4 ); - SibSB( 0, ESP, 4 ); - write8(offset); - } - else { - ModRM( 2, 0, 4 ); - SibSB( 0, ESP, 4 ); - write32(offset); - } - } - else { - if( offset == 0 ) { - ModRM( 0, 0, to ); - } - else if( offset < 128 && offset >= -128 ) { - ModRM( 1, 0, to ); - write8(offset); - } - else { - ModRM( 2, 0, to ); - write32(offset); - } - } -} - -__forceinline void WriteRmOffsetFrom(x86IntRegType to, x86IntRegType from, int offset) -{ - if ((from&7) == ESP) { - if( offset == 0 ) { - ModRM( 0, to, 0x4 ); - SibSB( 0, 0x4, 0x4 ); - } - else if( offset < 128 && offset >= -128 ) { - ModRM( 1, to, 0x4 ); - SibSB( 0, 0x4, 0x4 ); - write8(offset); - } - else { - ModRM( 2, to, 0x4 ); - SibSB( 0, 0x4, 0x4 ); - write32(offset); - } - } - else { - if( offset == 0 ) { - ModRM( 0, to, from ); - } - else if( offset < 128 && offset >= -128 ) { - ModRM( 1, to, from ); - write8(offset); - } - else { - ModRM( 2, to, from ); - write32(offset); - } - } -} - -// This function is just for rec debugging purposes -__forceinline void CheckX86Ptr( void ) -{ -} - -__forceinline void write64( u64 val ) -{ -#ifdef _DEBUG - CheckX86Ptr( ); -#endif - - *(u64*)x86Ptr = val; - x86Ptr += 8; -} - -__forceinline void ModRM( s32 mod, s32 reg, s32 rm ) -{ - write8( ( mod << 6 ) | ( (reg & 7) << 3 ) | ( rm & 7 ) ); -} - -__forceinline void SibSB( s32 ss, s32 index, s32 base ) -{ - write8( ( ss << 6 ) | ( (index & 7) << 3 ) | ( base & 7 ) ); -} - -__forceinline void SET8R( int cc, int to ) -{ - RexB(0, to); - write8( 0x0F ); - write8( cc ); - write8( 0xC0 | ( to ) ); -} - -__forceinline u8* J8Rel( int cc, int to ) -{ - write8( cc ); - write8( to ); - return (u8*)(x86Ptr - 1); -} - -__forceinline u16* J16Rel( int cc, u32 to ) -{ - write16( 0x0F66 ); - write8( cc ); - write16( to ); - return (u16*)( x86Ptr - 2 ); -} - -__forceinline u32* J32Rel( int cc, u32 to ) -{ - write8( 0x0F ); - write8( cc ); - write32( to ); - return (u32*)( x86Ptr - 4 ); -} - -__forceinline void CMOV32RtoR( int cc, int to, int from ) -{ - RexRB(0,to, from); - write8( 0x0F ); - write8( cc ); - ModRM( 3, to, from ); -} - -__forceinline void CMOV32MtoR( int cc, int to, uptr from ) -{ - RexR(0, to); - write8( 0x0F ); - write8( cc ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -//////////////////////////////////////////////////// -__forceinline void x86SetPtr( u8* ptr ) -{ - x86Ptr = ptr; -} - -//////////////////////////////////////////////////// -__forceinline void x86Shutdown( void ) -{ -} - -//////////////////////////////////////////////////// -__forceinline void x86SetJ8( u8* j8 ) -{ - u32 jump = ( x86Ptr - j8 ) - 1; - - if ( jump > 0x7f ) { - Console::Error( "j8 greater than 0x7f!!" ); - assert(0); - } - *j8 = (u8)jump; -} - -__forceinline void x86SetJ8A( u8* j8 ) -{ - u32 jump = ( x86Ptr - j8 ) - 1; - - if ( jump > 0x7f ) { - Console::Error( "j8 greater than 0x7f!!" ); - assert(0); - } - - if( ((uptr)x86Ptr&0xf) > 4 ) { - - uptr newjump = jump + 16-((uptr)x86Ptr&0xf); - - if( newjump <= 0x7f ) { - jump = newjump; - while((uptr)x86Ptr&0xf) *x86Ptr++ = 0x90; - } - } - *j8 = (u8)jump; -} - -__forceinline void x86SetJ16( u16 *j16 ) -{ - // doesn't work - u32 jump = ( x86Ptr - (u8*)j16 ) - 2; - - if ( jump > 0x7fff ) { - Console::Error( "j16 greater than 0x7fff!!" ); - assert(0); - } - *j16 = (u16)jump; -} - -__forceinline void x86SetJ16A( u16 *j16 ) -{ - if( ((uptr)x86Ptr&0xf) > 4 ) { - while((uptr)x86Ptr&0xf) *x86Ptr++ = 0x90; - } - x86SetJ16(j16); -} - -//////////////////////////////////////////////////// -__forceinline void x86SetJ32( u32* j32 ) -{ - *j32 = ( x86Ptr - (u8*)j32 ) - 4; -} - -__forceinline void x86SetJ32A( u32* j32 ) -{ - while((uptr)x86Ptr&0xf) *x86Ptr++ = 0x90; - x86SetJ32(j32); -} - -//////////////////////////////////////////////////// -__forceinline void x86Align( int bytes ) -{ - // fordward align - x86Ptr = (u8*)( ( (uptr)x86Ptr + bytes - 1) & ~( bytes - 1 ) ); -} - -//////////////////////////////////////////////////// -// Generates executable code to align to the given alignment (could be useful for the second leg -// of if/else conditionals, which usually fall through a jump target label). -void x86AlignExecutable( int align ) -{ - uptr newx86 = ( (uptr)x86Ptr + align - 1) & ~( align - 1 ); - uptr bytes = ( newx86 - (uptr)x86Ptr ); - - switch( bytes ) - { - case 0: break; - - case 1: NOP(); break; - case 2: MOV32RtoR( ESI, ESI ); break; - case 3: write8(0x08D); write8(0x024); write8(0x024); break; - case 5: NOP(); // falls through to 4... - case 4: write8(0x08D); write8(0x064); write8(0x024); write8(0); break; - case 6: write8(0x08D); write8(0x0B6); write32(0); break; - case 8: NOP(); // falls through to 7... - case 7: write8(0x08D); write8(0x034); write8(0x035); write32(0); break; - - default: - { - // for larger alignments, just use a JMP... - u8* aligned_target = JMP8(0); - x86Ptr = (u8*)newx86; - x86SetJ8( aligned_target ); - } - } - - jASSUME( x86Ptr == (u8*)newx86 ); -} - -/********************/ -/* IX86 intructions */ -/********************/ - -__forceinline void STC( void ) -{ - write8( 0xF9 ); -} - -__forceinline void CLC( void ) -{ - write8( 0xF8 ); -} - -// NOP 1-byte -__forceinline void NOP( void ) -{ - write8(0x90); -} - - -//////////////////////////////////// -// mov instructions / -//////////////////////////////////// - -/* mov r64 to r64 */ -__forceinline void MOV64RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(1, from, to); - write8( 0x89 ); - ModRM( 3, from, to ); -} - -/* mov r64 to m64 */ -__forceinline void MOV64RtoM( uptr to, x86IntRegType from ) -{ - RexR(1, from); - write8( 0x89 ); - ModRM( 0, from, DISP32 ); - write32( (u32)MEMADDR(to, 4) ); -} - -/* mov m64 to r64 */ -__forceinline void MOV64MtoR( x86IntRegType to, uptr from ) -{ - RexR(1, to); - write8( 0x8B ); - ModRM( 0, to, DISP32 ); - write32( (u32)MEMADDR(from, 4) ); -} - -/* mov imm32 to m64 */ -__forceinline void MOV64I32toM(uptr to, u32 from ) -{ - Rex(1, 0, 0, 0); - write8( 0xC7 ); - ModRM( 0, 0, DISP32 ); - write32( MEMADDR(to, 8) ); - write32( from ); -} - -// mov imm64 to r64 -__forceinline void MOV64ItoR( x86IntRegType to, u64 from) -{ - RexB(1, to); - write8( 0xB8 | (to & 0x7) ); - write64( from ); -} - -/* mov imm32 to r64 */ -__forceinline void MOV64I32toR( x86IntRegType to, s32 from ) -{ - RexB(1, to); - write8( 0xC7 ); - ModRM( 0, 0, to ); - write32( from ); -} - -// mov imm64 to [r64+off] -__forceinline void MOV64ItoRmOffset( x86IntRegType to, u32 from, int offset) -{ - RexB(1,to); - write8( 0xC7 ); - WriteRmOffset(to, offset); - write32(from); -} - -// mov [r64+offset] to r64 -__forceinline void MOV64RmOffsettoR( x86IntRegType to, x86IntRegType from, int offset ) -{ - RexRB(1, to, from); - write8( 0x8B ); - WriteRmOffsetFrom(to, from, offset); -} - -/* mov [r64][r64*scale] to r64 */ -__forceinline void MOV64RmStoR( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale) { - RexRXB(1, to, from2, from); - write8( 0x8B ); - ModRM( 0, to, 0x4 ); - SibSB(scale, from2, from ); -} - -/* mov r64 to [r64+offset] */ -__forceinline void MOV64RtoRmOffset( x86IntRegType to, x86IntRegType from, int offset ) -{ - RexRB(1,from,to); - write8( 0x89 ); - WriteRmOffsetFrom(from, to, offset); -} - -/* mov r64 to [r64][r64*scale] */ -__forceinline void MOV64RtoRmS( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale) { - RexRXB(1, to, from2, from); - write8( 0x89 ); - ModRM( 0, to, 0x4 ); - SibSB(scale, from2, from ); -} - - -/* mov r32 to r32 */ -__forceinline void MOV32RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(0, from, to); - write8( 0x89 ); - ModRM( 3, from, to ); -} - -/* mov r32 to m32 */ -void MOV32RtoM( uptr to, x86IntRegType from ) -{ - RexR(0, from); - write8( 0x89 ); - ModRM( 0, from, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -/* mov m32 to r32 */ -__forceinline void MOV32MtoR( x86IntRegType to, uptr from ) -{ - RexR(0, to); - write8( 0x8B ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* mov [r32] to r32 */ -__forceinline void MOV32RmtoR( x86IntRegType to, x86IntRegType from ) { - RexRB(0, to, from); - write8(0x8B); - WriteRmOffsetFrom(to, from, 0); -} - -__forceinline void MOV32RmtoROffset( x86IntRegType to, x86IntRegType from, int offset ) { - RexRB(0, to, from); - write8( 0x8B ); - WriteRmOffsetFrom(to, from, offset); -} - -/* mov [r32+r32*scale] to r32 */ -__forceinline void MOV32RmStoR( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale) { - RexRXB(0,to,from2,from); - write8( 0x8B ); - ModRM( 0, to, 0x4 ); - SibSB(scale, from2, from ); -} - -// mov r32 to [r32<> 3); - if ( to == EAX) { - write8( 0x05 ); - } else { - write8( 0x81 ); - ModRM( 3, 0, to ); - } - write32( from ); -} - -/* add m64 to r64 */ -__forceinline void ADD64MtoR( x86IntRegType to, uptr from ) -{ - Rex(1, to >> 3, 0, 0); - write8( 0x03 ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* add r64 to r64 */ -__forceinline void ADD64RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(1, from, to); - write8( 0x01 ); - ModRM( 3, from, to ); -} - -/* add imm32 to EAX */ -void ADD32ItoEAX( u32 from ) -{ - write8( 0x05 ); - write32( from ); -} - -/* add imm32 to r32 */ -__forceinline void ADD32ItoR( x86IntRegType to, u32 from ) -{ - RexB(0, to); - if(from < 0x80) - { - write8( 0x83 ); - ModRM( 3, 0, to ); - write8( from ); - } - else - { - if ( to == EAX ) { - ADD32ItoEAX(from); - } - else { - write8( 0x81 ); - ModRM( 3, 0, to ); - write32( from ); - } - } -} - -/* add imm32 to m32 */ -__forceinline void ADD32ItoM( uptr to, u32 from ) -{ - /*if(from < 0x80) // crashes games in 64bit build; TODO: figure out why. - { - write8( 0x83 ); - ModRM( 0, 0, DISP32 ); - write32( MEMADDR(to, 8) ); - write8( from ); - } - else*/ - { - write8( 0x81 ); - ModRM( 0, 0, DISP32 ); - write32( MEMADDR(to, 8) ); - write32( from ); - } -} - -// add imm32 to [r32+off] -__forceinline void ADD32ItoRmOffset( x86IntRegType to, u32 from, s32 offset) -{ - RexB(0,to); - if(from < 0x80) - { - write8( 0x83 ); - WriteRmOffset(to,offset); - write8(from); - } - else - { - write8( 0x81 ); - WriteRmOffset(to,offset); - write32(from); - } -} - -/* add r32 to r32 */ -__forceinline void ADD32RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(0, from, to); - write8( 0x01 ); - ModRM( 3, from, to ); -} - -/* add r32 to m32 */ -__forceinline void ADD32RtoM(uptr to, x86IntRegType from ) -{ - RexR(0,from); - write8( 0x01 ); - ModRM( 0, from, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -/* add m32 to r32 */ -__forceinline void ADD32MtoR( x86IntRegType to, uptr from ) -{ - RexR(0,to); - write8( 0x03 ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -// add r16 to r16 -__forceinline void ADD16RtoR( x86IntRegType to , x86IntRegType from ) -{ - write8(0x66); - RexRB(0,to,from); - write8( 0x03 ); - ModRM( 3, to, from ); -} - -/* add imm16 to r16 */ -__forceinline void ADD16ItoR( x86IntRegType to, u16 from ) -{ - write8( 0x66 ); - RexB(0,to); - - if ( to == EAX) - { - write8( 0x05 ); - write16( from ); - } - else if(from < 0x80) - { - write8( 0x83 ); - ModRM( 3, 0, to ); - write8((u8)from ); - } - else - { - write8( 0x81 ); - ModRM( 3, 0, to ); - write16( from ); - } -} - -/* add imm16 to m16 */ -__forceinline void ADD16ItoM( uptr to, u16 from ) -{ - write8( 0x66 ); - if(from < 0x80) - { - write8( 0x83 ); - ModRM( 0, 0, DISP32 ); - write32( MEMADDR(to, 6) ); - write8((u8)from ); - } - else - { - write8( 0x81 ); - ModRM( 0, 0, DISP32 ); - write32( MEMADDR(to, 6) ); - write16( from ); - } -} - -/* add r16 to m16 */ -__forceinline void ADD16RtoM(uptr to, x86IntRegType from ) -{ - write8( 0x66 ); - RexR(0,from); - write8( 0x01 ); - ModRM( 0, from, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -/* add m16 to r16 */ -__forceinline void ADD16MtoR( x86IntRegType to, uptr from ) -{ - write8( 0x66 ); - RexR(0,to); - write8( 0x03 ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -// add m8 to r8 -__forceinline void ADD8MtoR( x86IntRegType to, uptr from ) -{ - RexR(0,to); - write8( 0x02 ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* adc imm32 to r32 */ -__forceinline void ADC32ItoR( x86IntRegType to, u32 from ) -{ - RexB(0,to); - if ( to == EAX ) { - write8( 0x15 ); - } - else { - write8( 0x81 ); - ModRM( 3, 2, to ); - } - write32( from ); -} - -/* adc imm32 to m32 */ -__forceinline void ADC32ItoM( uptr to, u32 from ) -{ - write8( 0x81 ); - ModRM( 0, 2, DISP32 ); - write32( MEMADDR(to, 8) ); - write32( from ); -} - -/* adc r32 to r32 */ -__forceinline void ADC32RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(0,from,to); - write8( 0x11 ); - ModRM( 3, from, to ); -} - -/* adc m32 to r32 */ -__forceinline void ADC32MtoR( x86IntRegType to, uptr from ) -{ - RexR(0,to); - write8( 0x13 ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -// adc r32 to m32 -__forceinline void ADC32RtoM( uptr to, x86IntRegType from ) -{ - RexR(0,from); - write8( 0x11 ); - ModRM( 0, from, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -/* inc r32 */ -__forceinline void INC32R( x86IntRegType to ) -{ - write8( 0x40 + to ); -} - -/* inc m32 */ -__forceinline void INC32M( u32 to ) -{ - write8( 0xFF ); - ModRM( 0, 0, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -/* inc r16 */ -__forceinline void INC16R( x86IntRegType to ) -{ - write8( 0x66 ); - write8( 0x40 + to ); -} - -/* inc m16 */ -__forceinline void INC16M( u32 to ) -{ - write8( 0x66 ); - write8( 0xFF ); - ModRM( 0, 0, DISP32 ); - write32( MEMADDR(to, 4) ); -} - - -/* sub imm32 to r64 */ -__forceinline void SUB64ItoR( x86IntRegType to, u32 from ) -{ - RexB(1, to); - if ( to == EAX ) { - write8( 0x2D ); - } - else { - write8( 0x81 ); - ModRM( 3, 5, to ); - } - write32( from ); -} - -/* sub r64 to r64 */ -__forceinline void SUB64RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(1, from, to); - write8( 0x29 ); - ModRM( 3, from, to ); -} - -/* sub m64 to r64 */ -__forceinline void SUB64MtoR( x86IntRegType to, uptr from ) -{ - RexR(1, to); - write8( 0x2B ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* sub imm32 to r32 */ -__forceinline void SUB32ItoR( x86IntRegType to, u32 from ) -{ - RexB(0,to); - if ( to == EAX ) { - write8( 0x2D ); - } - else { - write8( 0x81 ); - ModRM( 3, 5, to ); - } - write32( from ); -} - -/* sub imm32 to m32 */ -__forceinline void SUB32ItoM( uptr to, u32 from ) -{ - write8( 0x81 ); - ModRM( 0, 5, DISP32 ); - write32( MEMADDR(to, 8) ); - write32( from ); -} - -/* sub r32 to r32 */ -__forceinline void SUB32RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(0, from, to); - write8( 0x29 ); - ModRM( 3, from, to ); -} - -/* sub m32 to r32 */ -__forceinline void SUB32MtoR( x86IntRegType to, uptr from ) -{ - RexR(0,to); - write8( 0x2B ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -// sub r32 to m32 -__forceinline void SUB32RtoM( uptr to, x86IntRegType from ) -{ - RexR(0,from); - write8( 0x29 ); - ModRM( 0, from, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -// sub r16 to r16 -__forceinline void SUB16RtoR( x86IntRegType to, u16 from ) -{ - write8(0x66); - RexRB(0,to,from); - write8( 0x2b ); - ModRM( 3, to, from ); -} - -/* sub imm16 to r16 */ -__forceinline void SUB16ItoR( x86IntRegType to, u16 from ) { - write8( 0x66 ); - RexB(0,to); - if ( to == EAX ) { - write8( 0x2D ); - } else { - write8( 0x81 ); - ModRM( 3, 5, to ); - } - write16( from ); -} - -/* sub imm16 to m16 */ -__forceinline void SUB16ItoM( uptr to, u16 from ) { - write8( 0x66 ); - write8( 0x81 ); - ModRM( 0, 5, DISP32 ); - write32( MEMADDR(to, 6) ); - write16( from ); -} - -/* sub m16 to r16 */ -__forceinline void SUB16MtoR( x86IntRegType to, uptr from ) { - write8( 0x66 ); - RexR(0,to); - write8( 0x2B ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* sbb r64 to r64 */ -__forceinline void SBB64RtoR( x86IntRegType to, x86IntRegType from ) { - RexRB(1, from,to); - write8( 0x19 ); - ModRM( 3, from, to ); -} - -/* sbb imm32 to r32 */ -__forceinline void SBB32ItoR( x86IntRegType to, u32 from ) { - RexB(0,to); - if ( to == EAX ) { - write8( 0x1D ); - } - else { - write8( 0x81 ); - ModRM( 3, 3, to ); - } - write32( from ); -} - -/* sbb imm32 to m32 */ -__forceinline void SBB32ItoM( uptr to, u32 from ) { - write8( 0x81 ); - ModRM( 0, 3, DISP32 ); - write32( MEMADDR(to, 8) ); - write32( from ); -} - -/* sbb r32 to r32 */ -__forceinline void SBB32RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(0,from,to); - write8( 0x19 ); - ModRM( 3, from, to ); -} - -/* sbb m32 to r32 */ -__forceinline void SBB32MtoR( x86IntRegType to, uptr from ) -{ - RexR(0,to); - write8( 0x1B ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* sbb r32 to m32 */ -__forceinline void SBB32RtoM( uptr to, x86IntRegType from ) -{ - RexR(0,from); - write8( 0x19 ); - ModRM( 0, from, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -/* dec r32 */ -__forceinline void DEC32R( x86IntRegType to ) -{ - write8( 0x48 + to ); -} - -/* dec m32 */ -__forceinline void DEC32M( u32 to ) -{ - write8( 0xFF ); - ModRM( 0, 1, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -/* dec r16 */ -__forceinline void DEC16R( x86IntRegType to ) -{ - write8( 0x66 ); - write8( 0x48 + to ); -} - -/* dec m16 */ -__forceinline void DEC16M( u32 to ) -{ - write8( 0x66 ); - write8( 0xFF ); - ModRM( 0, 1, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -/* mul eax by r32 to edx:eax */ -__forceinline void MUL32R( x86IntRegType from ) -{ - RexB(0,from); - write8( 0xF7 ); - ModRM( 3, 4, from ); -} - -/* imul eax by r32 to edx:eax */ -__forceinline void IMUL32R( x86IntRegType from ) -{ - RexB(0,from); - write8( 0xF7 ); - ModRM( 3, 5, from ); -} - -/* mul eax by m32 to edx:eax */ -__forceinline void MUL32M( u32 from ) -{ - write8( 0xF7 ); - ModRM( 0, 4, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* imul eax by m32 to edx:eax */ -__forceinline void IMUL32M( u32 from ) -{ - write8( 0xF7 ); - ModRM( 0, 5, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* imul r32 by r32 to r32 */ -__forceinline void IMUL32RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(0,to,from); - write16( 0xAF0F ); - ModRM( 3, to, from ); -} - -/* div eax by r32 to edx:eax */ -__forceinline void DIV32R( x86IntRegType from ) -{ - RexB(0,from); - write8( 0xF7 ); - ModRM( 3, 6, from ); -} - -/* idiv eax by r32 to edx:eax */ -__forceinline void IDIV32R( x86IntRegType from ) -{ - RexB(0,from); - write8( 0xF7 ); - ModRM( 3, 7, from ); -} - -/* div eax by m32 to edx:eax */ -__forceinline void DIV32M( u32 from ) -{ - write8( 0xF7 ); - ModRM( 0, 6, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* idiv eax by m32 to edx:eax */ -__forceinline void IDIV32M( u32 from ) -{ - write8( 0xF7 ); - ModRM( 0, 7, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -//////////////////////////////////// -// shifting instructions / -//////////////////////////////////// - -/* shl imm8 to r64 */ -__forceinline void SHL64ItoR( x86IntRegType to, u8 from ) -{ - RexB(1, to); - if ( from == 1 ) - { - write8( 0xD1 ); - ModRM( 3, 4, to ); - return; - } - write8( 0xC1 ); - ModRM( 3, 4, to ); - write8( from ); -} - -/* shl cl to r64 */ -__forceinline void SHL64CLtoR( x86IntRegType to ) -{ - RexB(1, to); - write8( 0xD3 ); - ModRM( 3, 4, to ); -} - -/* shr imm8 to r64 */ -__forceinline void SHR64ItoR( x86IntRegType to, u8 from ) -{ - RexB(1,to); - if ( from == 1 ) { - write8( 0xD1 ); - ModRM( 3, 5, to ); - return; - } - write8( 0xC1 ); - ModRM( 3, 5, to ); - write8( from ); -} - -/* shr cl to r64 */ -__forceinline void SHR64CLtoR( x86IntRegType to ) -{ - RexB(1, to); - write8( 0xD3 ); - ModRM( 3, 5, to ); -} - -/* shl imm8 to r32 */ -__forceinline void SHL32ItoR( x86IntRegType to, u8 from ) -{ - RexB(0, to); - if ( from == 1 ) - { - write8( 0xD1 ); - write8( 0xE0 | (to & 0x7) ); - return; - } - write8( 0xC1 ); - ModRM( 3, 4, to ); - write8( from ); -} - -/* shl imm8 to m32 */ -__forceinline void SHL32ItoM( uptr to, u8 from ) -{ - if ( from == 1 ) - { - write8( 0xD1 ); - ModRM( 0, 4, DISP32 ); - write32( MEMADDR(to, 4) ); - } - else - { - write8( 0xC1 ); - ModRM( 0, 4, DISP32 ); - write32( MEMADDR(to, 5) ); - write8( from ); - } -} - -/* shl cl to r32 */ -__forceinline void SHL32CLtoR( x86IntRegType to ) -{ - RexB(0,to); - write8( 0xD3 ); - ModRM( 3, 4, to ); -} - -// shl imm8 to r16 -__forceinline void SHL16ItoR( x86IntRegType to, u8 from ) -{ - write8(0x66); - RexB(0,to); - if ( from == 1 ) - { - write8( 0xD1 ); - write8( 0xE0 | (to & 0x7) ); - return; - } - write8( 0xC1 ); - ModRM( 3, 4, to ); - write8( from ); -} - -// shl imm8 to r8 -__forceinline void SHL8ItoR( x86IntRegType to, u8 from ) -{ - RexB(0,to); - if ( from == 1 ) - { - write8( 0xD0 ); - write8( 0xE0 | (to & 0x7) ); - return; - } - write8( 0xC0 ); - ModRM( 3, 4, to ); - write8( from ); -} - -/* shr imm8 to r32 */ -__forceinline void SHR32ItoR( x86IntRegType to, u8 from ) { - RexB(0,to); - if ( from == 1 ) - { - write8( 0xD1 ); - write8( 0xE8 | (to & 0x7) ); - } - else - { - write8( 0xC1 ); - ModRM( 3, 5, to ); - write8( from ); - } -} - -/* shr imm8 to m32 */ -__forceinline void SHR32ItoM( uptr to, u8 from ) -{ - if ( from == 1 ) - { - write8( 0xD1 ); - ModRM( 0, 5, DISP32 ); - write32( MEMADDR(to, 4) ); - } - else - { - write8( 0xC1 ); - ModRM( 0, 5, DISP32 ); - write32( MEMADDR(to, 5) ); - write8( from ); - } -} - -/* shr cl to r32 */ -__forceinline void SHR32CLtoR( x86IntRegType to ) -{ - RexB(0,to); - write8( 0xD3 ); - ModRM( 3, 5, to ); -} - -// shr imm8 to r16 -__forceinline void SHR16ItoR( x86IntRegType to, u8 from ) -{ - RexB(0,to); - if ( from == 1 ) - { - write8( 0xD1 ); - ModRM( 3, 5, to ); - } - else - { - write8( 0xC1 ); - ModRM( 3, 5, to ); - write8( from ); - } -} - -// shr imm8 to r8 -__forceinline void SHR8ItoR( x86IntRegType to, u8 from ) -{ - RexB(0,to); - if ( from == 1 ) - { - write8( 0xD0 ); - write8( 0xE8 | (to & 0x7) ); - } - else - { - write8( 0xC0 ); - ModRM( 3, 5, to ); - write8( from ); - } -} - -/* sar imm8 to r64 */ -__forceinline void SAR64ItoR( x86IntRegType to, u8 from ) -{ - RexB(1,to); - if ( from == 1 ) - { - write8( 0xD1 ); - ModRM( 3, 7, to ); - return; - } - write8( 0xC1 ); - ModRM( 3, 7, to ); - write8( from ); -} - -/* sar cl to r64 */ -__forceinline void SAR64CLtoR( x86IntRegType to ) -{ - RexB(1, to); - write8( 0xD3 ); - ModRM( 3, 7, to ); -} - -/* sar imm8 to r32 */ -__forceinline void SAR32ItoR( x86IntRegType to, u8 from ) -{ - RexB(0,to); - if ( from == 1 ) - { - write8( 0xD1 ); - ModRM( 3, 7, to ); - return; - } - write8( 0xC1 ); - ModRM( 3, 7, to ); - write8( from ); -} - -/* sar imm8 to m32 */ -__forceinline void SAR32ItoM( uptr to, u8 from ) -{ - write8( 0xC1 ); - ModRM( 0, 7, DISP32 ); - write32( MEMADDR(to, 5) ); - write8( from ); -} - -/* sar cl to r32 */ -__forceinline void SAR32CLtoR( x86IntRegType to ) -{ - RexB(0,to); - write8( 0xD3 ); - ModRM( 3, 7, to ); -} - -// sar imm8 to r16 -__forceinline void SAR16ItoR( x86IntRegType to, u8 from ) -{ - write8(0x66); - RexB(0,to); - if ( from == 1 ) - { - write8( 0xD1 ); - ModRM( 3, 7, to ); - return; - } - write8( 0xC1 ); - ModRM( 3, 7, to ); - write8( from ); -} - -__forceinline void ROR32ItoR( x86IntRegType to,u8 from ) -{ - RexB(0,to); - if ( from == 1 ) { - write8( 0xd1 ); - write8( 0xc8 | to ); - } - else - { - write8( 0xc1 ); - write8( 0xc8 | to ); - write8( from ); - } -} - -__forceinline void RCR32ItoR( x86IntRegType to, u8 from ) -{ - RexB(0,to); - if ( from == 1 ) { - write8( 0xd1 ); - ModRM(3, 3, to); - } - else - { - write8( 0xc1 ); - ModRM(3, 3, to); - write8( from ); - } -} - -__forceinline void RCR32ItoM( uptr to, u8 from ) -{ - RexB(0,to); - if ( from == 1 ) { - write8( 0xd1 ); - ModRM( 0, 3, DISP32 ); - write32( MEMADDR(to, 8) ); - } - else - { - write8( 0xc1 ); - ModRM( 0, 3, DISP32 ); - write32( MEMADDR(to, 8) ); - write8( from ); - } -} - -// shld imm8 to r32 -__forceinline void SHLD32ItoR( x86IntRegType to, x86IntRegType from, u8 shift ) -{ - RexRB(0,from,to); - write8( 0x0F ); - write8( 0xA4 ); - ModRM( 3, from, to ); - write8( shift ); -} - -// shrd imm8 to r32 -__forceinline void SHRD32ItoR( x86IntRegType to, x86IntRegType from, u8 shift ) -{ - RexRB(0,from,to); - write8( 0x0F ); - write8( 0xAC ); - ModRM( 3, from, to ); - write8( shift ); -} - -//////////////////////////////////// -// logical instructions / -//////////////////////////////////// - -/* or imm32 to r32 */ -__forceinline void OR64ItoR( x86IntRegType to, u32 from ) -{ - RexB(1, to); - if ( to == EAX ) { - write8( 0x0D ); - } else { - write8( 0x81 ); - ModRM( 3, 1, to ); - } - write32( from ); -} - -/* or m64 to r64 */ -__forceinline void OR64MtoR( x86IntRegType to, uptr from ) -{ - RexR(1, to); - write8( 0x0B ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* or r64 to r64 */ -__forceinline void OR64RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(1, from, to); - write8( 0x09 ); - ModRM( 3, from, to ); -} - -// or r32 to m64 -__forceinline void OR64RtoM(uptr to, x86IntRegType from ) -{ - RexR(1,from); - write8( 0x09 ); - ModRM( 0, from, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -/* or imm32 to r32 */ -__forceinline void OR32ItoR( x86IntRegType to, u32 from ) -{ - RexB(0,to); - if ( to == EAX ) { - write8( 0x0D ); - } - else { - write8( 0x81 ); - ModRM( 3, 1, to ); - } - write32( from ); -} - -/* or imm32 to m32 */ -__forceinline void OR32ItoM(uptr to, u32 from ) -{ - write8( 0x81 ); - ModRM( 0, 1, DISP32 ); - write32( MEMADDR(to, 8) ); - write32( from ); -} - -/* or r32 to r32 */ -__forceinline void OR32RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(0,from,to); - write8( 0x09 ); - ModRM( 3, from, to ); -} - -/* or r32 to m32 */ -__forceinline void OR32RtoM(uptr to, x86IntRegType from ) -{ - RexR(0,from); - write8( 0x09 ); - ModRM( 0, from, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -/* or m32 to r32 */ -__forceinline void OR32MtoR( x86IntRegType to, uptr from ) -{ - RexR(0,to); - write8( 0x0B ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -// or r16 to r16 -__forceinline void OR16RtoR( x86IntRegType to, x86IntRegType from ) -{ - write8(0x66); - RexRB(0,from,to); - write8( 0x09 ); - ModRM( 3, from, to ); -} - -// or imm16 to r16 -__forceinline void OR16ItoR( x86IntRegType to, u16 from ) -{ - write8(0x66); - RexB(0,to); - if ( to == EAX ) { - write8( 0x0D ); - } - else { - write8( 0x81 ); - ModRM( 3, 1, to ); - } - write16( from ); -} - -// or imm16 to m316 -__forceinline void OR16ItoM( uptr to, u16 from ) -{ - write8(0x66); - write8( 0x81 ); - ModRM( 0, 1, DISP32 ); - write32( MEMADDR(to, 6) ); - write16( from ); -} - -/* or m16 to r16 */ -__forceinline void OR16MtoR( x86IntRegType to, uptr from ) -{ - write8(0x66); - RexR(0,to); - write8( 0x0B ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -// or r16 to m16 -__forceinline void OR16RtoM( uptr to, x86IntRegType from ) -{ - write8(0x66); - RexR(0,from); - write8( 0x09 ); - ModRM( 0, from, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -// or r8 to r8 -__forceinline void OR8RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(0,from,to); - write8( 0x08 ); - ModRM( 3, from, to ); -} - -// or r8 to m8 -__forceinline void OR8RtoM( uptr to, x86IntRegType from ) -{ - RexR(0,from); - write8( 0x08 ); - ModRM( 0, from, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -// or imm8 to m8 -__forceinline void OR8ItoM( uptr to, u8 from ) -{ - write8( 0x80 ); - ModRM( 0, 1, DISP32 ); - write32( MEMADDR(to, 5) ); - write8( from ); -} - -// or m8 to r8 -__forceinline void OR8MtoR( x86IntRegType to, uptr from ) -{ - RexR(0,to); - write8( 0x0A ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* xor imm32 to r64 */ -__forceinline void XOR64ItoR( x86IntRegType to, u32 from ) -{ - RexB(1,to); - if ( to == EAX ) { - write8( 0x35 ); - } else { - write8( 0x81 ); - ModRM( 3, 6, to ); - } - write32( from ); -} - -/* xor r64 to r64 */ -__forceinline void XOR64RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(1, from, to); - write8( 0x31 ); - ModRM( 3, from, to ); -} - -/* xor m64 to r64 */ -__forceinline void XOR64MtoR( x86IntRegType to, uptr from ) -{ - RexR(1, to); - write8( 0x33 ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* xor r64 to m64 */ -__forceinline void XOR64RtoM( uptr to, x86IntRegType from ) -{ - RexR(1,from); - write8( 0x31 ); - ModRM( 0, from, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -/* xor imm32 to r32 */ -__forceinline void XOR32ItoR( x86IntRegType to, u32 from ) -{ - RexB(0,to); - if ( to == EAX ) { - write8( 0x35 ); - } - else { - write8( 0x81 ); - ModRM( 3, 6, to ); - } - write32( from ); -} - -/* xor imm32 to m32 */ -__forceinline void XOR32ItoM( uptr to, u32 from ) -{ - write8( 0x81 ); - ModRM( 0, 6, DISP32 ); - write32( MEMADDR(to, 8) ); - write32( from ); -} - -/* xor r32 to r32 */ -__forceinline void XOR32RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(0,from,to); - write8( 0x31 ); - ModRM( 3, from, to ); -} - -/* xor r16 to r16 */ -__forceinline void XOR16RtoR( x86IntRegType to, x86IntRegType from ) -{ - write8( 0x66 ); - RexRB(0,from,to); - write8( 0x31 ); - ModRM( 3, from, to ); -} - -/* xor r32 to m32 */ -__forceinline void XOR32RtoM( uptr to, x86IntRegType from ) -{ - RexR(0,from); - write8( 0x31 ); - ModRM( 0, from, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -/* xor m32 to r32 */ -__forceinline void XOR32MtoR( x86IntRegType to, uptr from ) -{ - RexR(0,to); - write8( 0x33 ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -// xor imm16 to r16 -__forceinline void XOR16ItoR( x86IntRegType to, u16 from ) -{ - write8(0x66); - RexB(0,to); - if ( to == EAX ) { - write8( 0x35 ); - } - else { - write8( 0x81 ); - ModRM( 3, 6, to ); - } - write16( from ); -} - -// xor r16 to m16 -__forceinline void XOR16RtoM( uptr to, x86IntRegType from ) -{ - write8(0x66); - RexR(0,from); - write8( 0x31 ); - ModRM( 0, from, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -/* and imm32 to r64 */ -__forceinline void AND64I32toR( x86IntRegType to, u32 from ) -{ - RexB(1, to); - if ( to == EAX ) { - write8( 0x25 ); - } else { - write8( 0x81 ); - ModRM( 3, 0x4, to ); - } - write32( from ); -} - -/* and m64 to r64 */ -__forceinline void AND64MtoR( x86IntRegType to, uptr from ) -{ - RexR(1, to); - write8( 0x23 ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* and r64 to m64 */ -__forceinline void AND64RtoM( uptr to, x86IntRegType from ) -{ - RexR(1, from); - write8( 0x21 ); - ModRM( 0, from, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -/* and r64 to r64 */ -__forceinline void AND64RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(1, from, to); - write8( 0x21 ); - ModRM( 3, from, to ); -} - -/* and imm32 to m64 */ -__forceinline void AND64I32toM( uptr to, u32 from ) -{ - Rex(1,0,0,0); - write8( 0x81 ); - ModRM( 0, 0x4, DISP32 ); - write32( MEMADDR(to, 8) ); - write32( from ); -} - -/* and imm32 to r32 */ -__forceinline void AND32ItoR( x86IntRegType to, u32 from ) -{ - RexB(0,to); - if(from < 0x80) - { - AND32I8toR(to, (u8)from); - } - else - { - if ( to == EAX ) { - write8( 0x25 ); - } else { - write8( 0x81 ); - ModRM( 3, 0x4, to ); - } - write32( from ); - } -} - -/* and sign ext imm8 to r32 */ -__forceinline void AND32I8toR( x86IntRegType to, u8 from ) -{ - RexB(0,to); - write8( 0x83 ); - ModRM( 3, 0x4, to ); - write8( from ); -} - -/* and imm32 to m32 */ -__forceinline void AND32ItoM( uptr to, u32 from ) -{ - if(from < 0x80) - { - AND32I8toM(to, (u8)from); - } - else - { - write8( 0x81 ); - ModRM( 0, 0x4, DISP32 ); - write32( MEMADDR(to, 8) ); - write32( from ); - } -} - - -/* and sign ext imm8 to m32 */ -__forceinline void AND32I8toM( uptr to, u8 from ) -{ - write8( 0x83 ); - ModRM( 0, 0x4, DISP32 ); - write32( MEMADDR(to, 5) ); - write8( from ); -} - -/* and r32 to r32 */ -__forceinline void AND32RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(0,from,to); - write8( 0x21 ); - ModRM( 3, from, to ); -} - -/* and r32 to m32 */ -__forceinline void AND32RtoM( uptr to, x86IntRegType from ) -{ - RexR(0,from); - write8( 0x21 ); - ModRM( 0, from, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -/* and m32 to r32 */ -__forceinline void AND32MtoR( x86IntRegType to, uptr from ) -{ - RexR(0,to); - write8( 0x23 ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -// and r16 to r16 -__forceinline void AND16RtoR( x86IntRegType to, x86IntRegType from ) -{ - write8(0x66); - RexRB(0,to,from); - write8( 0x23 ); - ModRM( 3, to, from ); -} - -/* and imm16 to r16 */ -__forceinline void AND16ItoR( x86IntRegType to, u16 from ) -{ - write8(0x66); - RexB(0,to); - - if ( to == EAX ) { - write8( 0x25 ); - write16( from ); - } - else if ( from < 0x80 ) { - write8( 0x83 ); - ModRM( 3, 0x4, to ); - write8((u8)from ); - } - else { - write8( 0x81 ); - ModRM( 3, 0x4, to ); - write16( from ); - } -} - -/* and imm16 to m16 */ -__forceinline void AND16ItoM( uptr to, u16 from ) -{ - write8(0x66); - if ( from < 0x80 ) { - write8( 0x83 ); - ModRM( 0, 0x4, DISP32 ); - write32( MEMADDR(to, 6) ); - write8((u8)from ); - } - else - { - write8( 0x81 ); - ModRM( 0, 0x4, DISP32 ); - write32( MEMADDR(to, 6) ); - write16( from ); - - } -} - -/* and r16 to m16 */ -__forceinline void AND16RtoM( uptr to, x86IntRegType from ) -{ - write8( 0x66 ); - RexR(0,from); - write8( 0x21 ); - ModRM( 0, from, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -/* and m16 to r16 */ -__forceinline void AND16MtoR( x86IntRegType to, uptr from ) -{ - write8( 0x66 ); - RexR(0,to); - write8( 0x23 ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4)); -} - -/* and imm8 to r8 */ -__forceinline void AND8ItoR( x86IntRegType to, u8 from ) -{ - RexB(0,to); - if ( to == EAX ) { - write8( 0x24 ); - } else { - write8( 0x80 ); - ModRM( 3, 0x4, to ); - } - write8( from ); -} - -/* and imm8 to m8 */ -__forceinline void AND8ItoM( uptr to, u8 from ) -{ - write8( 0x80 ); - ModRM( 0, 0x4, DISP32 ); - write32( MEMADDR(to, 5) ); - write8( from ); -} - -// and r8 to r8 -__forceinline void AND8RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(0,to,from); - write8( 0x22 ); - ModRM( 3, to, from ); -} - -/* and r8 to m8 */ -__forceinline void AND8RtoM( uptr to, x86IntRegType from ) -{ - RexR(0,from); - write8( 0x20 ); - ModRM( 0, from, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -/* and m8 to r8 */ -__forceinline void AND8MtoR( x86IntRegType to, uptr from ) -{ - RexR(0,to); - write8( 0x22 ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4)); -} - -/* not r64 */ -__forceinline void NOT64R( x86IntRegType from ) -{ - RexB(1, from); - write8( 0xF7 ); - ModRM( 3, 2, from ); -} - -/* not r32 */ -__forceinline void NOT32R( x86IntRegType from ) -{ - RexB(0,from); - write8( 0xF7 ); - ModRM( 3, 2, from ); -} - -// not m32 -__forceinline void NOT32M( u32 from ) -{ - write8( 0xF7 ); - ModRM( 0, 2, DISP32 ); - write32( MEMADDR(from, 4)); -} - -/* neg r64 */ -__forceinline void NEG64R( x86IntRegType from ) -{ - RexB(1, from); - write8( 0xF7 ); - ModRM( 3, 3, from ); -} - -/* neg r32 */ -__forceinline void NEG32R( x86IntRegType from ) -{ - RexB(0,from); - write8( 0xF7 ); - ModRM( 3, 3, from ); -} - -__forceinline void NEG32M( u32 from ) -{ - write8( 0xF7 ); - ModRM( 0, 3, DISP32 ); - write32( MEMADDR(from, 4)); -} - -/* neg r16 */ -__forceinline void NEG16R( x86IntRegType from ) -{ - write8( 0x66 ); - RexB(0,from); - write8( 0xF7 ); - ModRM( 3, 3, from ); -} - -//////////////////////////////////// -// jump instructions / -//////////////////////////////////// - -__forceinline u8* JMP( uptr to ) { - uptr jump = ( x86Ptr - (u8*)to ) - 1; - - if ( jump > 0x7f ) { - assert( to <= 0xffffffff ); - return (u8*)JMP32( to ); - } - else { - return (u8*)JMP8( to ); - } -} - -/* jmp rel8 */ -__forceinline u8* JMP8( u8 to ) -{ - write8( 0xEB ); - write8( to ); - return x86Ptr - 1; -} - -/* jmp rel32 */ -__forceinline u32* JMP32( uptr to ) -{ - assert( (sptr)to <= 0x7fffffff && (sptr)to >= -0x7fffffff ); - write8( 0xE9 ); - write32( to ); - return (u32*)(x86Ptr - 4 ); -} - -/* jmp r32/r64 */ -__forceinline void JMPR( x86IntRegType to ) -{ - RexB(0, to); - write8( 0xFF ); - ModRM( 3, 4, to ); -} - -// jmp m32 -__forceinline void JMP32M( uptr to ) -{ - write8( 0xFF ); - ModRM( 0, 4, DISP32 ); - write32( MEMADDR(to, 4)); -} - -/* jp rel8 */ -__forceinline u8* JP8( u8 to ) { - return J8Rel( 0x7A, to ); -} - -/* jnp rel8 */ -__forceinline u8* JNP8( u8 to ) { - return J8Rel( 0x7B, to ); -} - -/* je rel8 */ -__forceinline u8* JE8( u8 to ) { - return J8Rel( 0x74, to ); -} - -/* jz rel8 */ -__forceinline u8* JZ8( u8 to ) -{ - return J8Rel( 0x74, to ); -} - -/* js rel8 */ -__forceinline u8* JS8( u8 to ) -{ - return J8Rel( 0x78, to ); -} - -/* jns rel8 */ -__forceinline u8* JNS8( u8 to ) -{ - return J8Rel( 0x79, to ); -} - -/* jg rel8 */ -__forceinline u8* JG8( u8 to ) -{ - return J8Rel( 0x7F, to ); -} - -/* jge rel8 */ -__forceinline u8* JGE8( u8 to ) -{ - return J8Rel( 0x7D, to ); -} - -/* jl rel8 */ -__forceinline u8* JL8( u8 to ) -{ - return J8Rel( 0x7C, to ); -} - -/* ja rel8 */ -__forceinline u8* JA8( u8 to ) -{ - return J8Rel( 0x77, to ); -} - -__forceinline u8* JAE8( u8 to ) -{ - return J8Rel( 0x73, to ); -} - -/* jb rel8 */ -__forceinline u8* JB8( u8 to ) -{ - return J8Rel( 0x72, to ); -} - -/* jbe rel8 */ -__forceinline u8* JBE8( u8 to ) -{ - return J8Rel( 0x76, to ); -} - -/* jle rel8 */ -__forceinline u8* JLE8( u8 to ) -{ - return J8Rel( 0x7E, to ); -} - -/* jne rel8 */ -__forceinline u8* JNE8( u8 to ) -{ - return J8Rel( 0x75, to ); -} - -/* jnz rel8 */ -__forceinline u8* JNZ8( u8 to ) -{ - return J8Rel( 0x75, to ); -} - -/* jng rel8 */ -__forceinline u8* JNG8( u8 to ) -{ - return J8Rel( 0x7E, to ); -} - -/* jnge rel8 */ -__forceinline u8* JNGE8( u8 to ) -{ - return J8Rel( 0x7C, to ); -} - -/* jnl rel8 */ -__forceinline u8* JNL8( u8 to ) -{ - return J8Rel( 0x7D, to ); -} - -/* jnle rel8 */ -__forceinline u8* JNLE8( u8 to ) -{ - return J8Rel( 0x7F, to ); -} - -/* jo rel8 */ -__forceinline u8* JO8( u8 to ) -{ - return J8Rel( 0x70, to ); -} - -/* jno rel8 */ -__forceinline u8* JNO8( u8 to ) -{ - return J8Rel( 0x71, to ); -} -/* Untested and slower, use 32bit versions instead -// ja rel16 -__forceinline u16* JA16( u16 to ) -{ - return J16Rel( 0x87, to ); -} - -// jb rel16 -__forceinline u16* JB16( u16 to ) -{ - return J16Rel( 0x82, to ); -} - -// je rel16 -__forceinline u16* JE16( u16 to ) -{ - return J16Rel( 0x84, to ); -} - -// jz rel16 -__forceinline u16* JZ16( u16 to ) -{ - return J16Rel( 0x84, to ); -} -*/ -// jb rel32 -__forceinline u32* JB32( u32 to ) -{ - return J32Rel( 0x82, to ); -} - -/* je rel32 */ -__forceinline u32* JE32( u32 to ) -{ - return J32Rel( 0x84, to ); -} - -/* jz rel32 */ -__forceinline u32* JZ32( u32 to ) -{ - return J32Rel( 0x84, to ); -} - -/* js rel32 */ -__forceinline u32* JS32( u32 to ) -{ - return J32Rel( 0x88, to ); -} - -/* jns rel32 */ -__forceinline u32* JNS32( u32 to ) -{ - return J32Rel( 0x89, to ); -} - -/* jg rel32 */ -__forceinline u32* JG32( u32 to ) -{ - return J32Rel( 0x8F, to ); -} - -/* jge rel32 */ -__forceinline u32* JGE32( u32 to ) -{ - return J32Rel( 0x8D, to ); -} - -/* jl rel32 */ -__forceinline u32* JL32( u32 to ) -{ - return J32Rel( 0x8C, to ); -} - -/* jle rel32 */ -__forceinline u32* JLE32( u32 to ) -{ - return J32Rel( 0x8E, to ); -} - -/* ja rel32 */ -__forceinline u32* JA32( u32 to ) -{ - return J32Rel( 0x87, to ); -} - -/* jae rel32 */ -__forceinline u32* JAE32( u32 to ) -{ - return J32Rel( 0x83, to ); -} - -/* jne rel32 */ -__forceinline u32* JNE32( u32 to ) -{ - return J32Rel( 0x85, to ); -} - -/* jnz rel32 */ -__forceinline u32* JNZ32( u32 to ) -{ - return J32Rel( 0x85, to ); -} - -/* jng rel32 */ -__forceinline u32* JNG32( u32 to ) -{ - return J32Rel( 0x8E, to ); -} - -/* jnge rel32 */ -__forceinline u32* JNGE32( u32 to ) -{ - return J32Rel( 0x8C, to ); -} - -/* jnl rel32 */ -__forceinline u32* JNL32( u32 to ) -{ - return J32Rel( 0x8D, to ); -} - -/* jnle rel32 */ -__forceinline u32* JNLE32( u32 to ) -{ - return J32Rel( 0x8F, to ); -} - -/* jo rel32 */ -__forceinline u32* JO32( u32 to ) -{ - return J32Rel( 0x80, to ); -} - -/* jno rel32 */ -__forceinline u32* JNO32( u32 to ) -{ - return J32Rel( 0x81, to ); -} - - - -/* call func */ -__forceinline void CALLFunc( uptr func ) -{ - func -= ( (uptr)x86Ptr + 5 ); - assert( (sptr)func <= 0x7fffffff && (sptr)func >= -0x7fffffff ); - CALL32(func); -} - -/* call rel32 */ -__forceinline void CALL32( u32 to ) -{ - write8( 0xE8 ); - write32( to ); -} - -/* call r32 */ -__forceinline void CALL32R( x86IntRegType to ) -{ - write8( 0xFF ); - ModRM( 3, 2, to ); -} - -/* call r64 */ -__forceinline void CALL64R( x86IntRegType to ) -{ - RexB(0, to); - write8( 0xFF ); - ModRM( 3, 2, to ); -} - -/* call m32 */ -__forceinline void CALL32M( u32 to ) -{ - write8( 0xFF ); - ModRM( 0, 2, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -//////////////////////////////////// -// misc instructions / -//////////////////////////////////// - -/* cmp imm32 to r64 */ -__forceinline void CMP64I32toR( x86IntRegType to, u32 from ) -{ - RexB(1, to); - if ( to == EAX ) { - write8( 0x3D ); - } - else { - write8( 0x81 ); - ModRM( 3, 7, to ); - } - write32( from ); -} - -/* cmp m64 to r64 */ -__forceinline void CMP64MtoR( x86IntRegType to, uptr from ) -{ - RexR(1, to); - write8( 0x3B ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -// cmp r64 to r64 -__forceinline void CMP64RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(1,from,to); - write8( 0x39 ); - ModRM( 3, from, to ); -} - -/* cmp imm32 to r32 */ -__forceinline void CMP32ItoR( x86IntRegType to, u32 from ) -{ - RexB(0,to); - if ( to == EAX ) { - write8( 0x3D ); - } - else { - write8( 0x81 ); - ModRM( 3, 7, to ); - } - write32( from ); -} - -/* cmp imm32 to m32 */ -__forceinline void CMP32ItoM( uptr to, u32 from ) -{ - write8( 0x81 ); - ModRM( 0, 7, DISP32 ); - write32( MEMADDR(to, 8) ); - write32( from ); -} - -/* cmp r32 to r32 */ -__forceinline void CMP32RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(0,from,to); - write8( 0x39 ); - ModRM( 3, from, to ); -} - -/* cmp m32 to r32 */ -__forceinline void CMP32MtoR( x86IntRegType to, uptr from ) -{ - RexR(0,to); - write8( 0x3B ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -// cmp imm8 to [r32] -__forceinline void CMP32I8toRm( x86IntRegType to, u8 from) -{ - RexB(0,to); - write8( 0x83 ); - ModRM( 0, 7, to ); - write8(from); -} - -// cmp imm32 to [r32+off] -__forceinline void CMP32I8toRmOffset8( x86IntRegType to, u8 from, u8 off) -{ - RexB(0,to); - write8( 0x83 ); - ModRM( 1, 7, to ); - write8(off); - write8(from); -} - -// cmp imm8 to [r32] -__forceinline void CMP32I8toM( uptr to, u8 from) -{ - write8( 0x83 ); - ModRM( 0, 7, DISP32 ); - write32( MEMADDR(to, 5) ); - write8( from ); -} - -/* cmp imm16 to r16 */ -__forceinline void CMP16ItoR( x86IntRegType to, u16 from ) -{ - write8( 0x66 ); - RexB(0,to); - if ( to == EAX ) - { - write8( 0x3D ); - } - else - { - write8( 0x81 ); - ModRM( 3, 7, to ); - } - write16( from ); -} - -/* cmp imm16 to m16 */ -__forceinline void CMP16ItoM( uptr to, u16 from ) -{ - write8( 0x66 ); - write8( 0x81 ); - ModRM( 0, 7, DISP32 ); - write32( MEMADDR(to, 6) ); - write16( from ); -} - -/* cmp r16 to r16 */ -__forceinline void CMP16RtoR( x86IntRegType to, x86IntRegType from ) -{ - write8( 0x66 ); - RexRB(0,from,to); - write8( 0x39 ); - ModRM( 3, from, to ); -} - -/* cmp m16 to r16 */ -__forceinline void CMP16MtoR( x86IntRegType to, uptr from ) -{ - write8( 0x66 ); - RexR(0,to); - write8( 0x3B ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -// cmp imm8 to r8 -__forceinline void CMP8ItoR( x86IntRegType to, u8 from ) -{ - RexB(0,to); - if ( to == EAX ) - { - write8( 0x3C ); - } - else - { - write8( 0x80 ); - ModRM( 3, 7, to ); - } - write8( from ); -} - -// cmp m8 to r8 -__forceinline void CMP8MtoR( x86IntRegType to, uptr from ) -{ - RexR(0,to); - write8( 0x3A ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* test imm32 to r32 */ -__forceinline void TEST32ItoR( x86IntRegType to, u32 from ) -{ - RexB(0,to); - if ( to == EAX ) - { - write8( 0xA9 ); - } - else - { - write8( 0xF7 ); - ModRM( 3, 0, to ); - } - write32( from ); -} - -__forceinline void TEST32ItoM( uptr to, u32 from ) -{ - write8( 0xF7 ); - ModRM( 0, 0, DISP32 ); - write32( MEMADDR(to, 8) ); - write32( from ); -} - -/* test r32 to r32 */ -__forceinline void TEST32RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(0,from,to); - write8( 0x85 ); - ModRM( 3, from, to ); -} - -// test imm32 to [r32] -__forceinline void TEST32ItoRm( x86IntRegType to, u32 from ) -{ - RexB(0,to); - write8( 0xF7 ); - ModRM( 0, 0, to ); - write32(from); -} - -// test imm16 to r16 -__forceinline void TEST16ItoR( x86IntRegType to, u16 from ) -{ - write8(0x66); - RexB(0,to); - if ( to == EAX ) - { - write8( 0xA9 ); - } - else - { - write8( 0xF7 ); - ModRM( 3, 0, to ); - } - write16( from ); -} - -// test r16 to r16 -__forceinline void TEST16RtoR( x86IntRegType to, x86IntRegType from ) -{ - write8(0x66); - RexRB(0,from,to); - write8( 0x85 ); - ModRM( 3, from, to ); -} - -// test r8 to r8 -__forceinline void TEST8RtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(0, from, to); - write8( 0x84 ); - ModRM( 3, from, to ); -} - - -// test imm8 to r8 -__forceinline void TEST8ItoR( x86IntRegType to, u8 from ) -{ - RexB(0,to); - if ( to == EAX ) - { - write8( 0xA8 ); - } - else - { - write8( 0xF6 ); - ModRM( 3, 0, to ); - } - write8( from ); -} - -// test imm8 to r8 -__forceinline void TEST8ItoM( uptr to, u8 from ) -{ - write8( 0xF6 ); - ModRM( 0, 0, DISP32 ); - write32( MEMADDR(to, 5) ); - write8( from ); -} - -/* sets r8 */ -__forceinline void SETS8R( x86IntRegType to ) -{ - SET8R( 0x98, to ); -} - -/* setl r8 */ -__forceinline void SETL8R( x86IntRegType to ) -{ - SET8R( 0x9C, to ); -} - -// setge r8 -__forceinline void SETGE8R( x86IntRegType to ) { SET8R(0x9d, to); } -// setg r8 -__forceinline void SETG8R( x86IntRegType to ) { SET8R(0x9f, to); } -// seta r8 -__forceinline void SETA8R( x86IntRegType to ) { SET8R(0x97, to); } -// setae r8 -__forceinline void SETAE8R( x86IntRegType to ) { SET8R(0x99, to); } -/* setb r8 */ -__forceinline void SETB8R( x86IntRegType to ) { SET8R( 0x92, to ); } -/* setb r8 */ -__forceinline void SETNZ8R( x86IntRegType to ) { SET8R( 0x95, to ); } -// setz r8 -__forceinline void SETZ8R( x86IntRegType to ) { SET8R(0x94, to); } -// sete r8 -__forceinline void SETE8R( x86IntRegType to ) { SET8R(0x94, to); } - -/* push imm32 */ -__forceinline void PUSH32I( u32 from ) -{; - write8( 0x68 ); - write32( from ); -} - -/* push r32 */ -__forceinline void PUSH32R( x86IntRegType from ) { write8( 0x50 | from ); } - -/* push m32 */ -__forceinline void PUSH32M( u32 from ) -{ - write8( 0xFF ); - ModRM( 0, 6, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* pop r32 */ -__forceinline void POP32R( x86IntRegType from ) { write8( 0x58 | from ); } - -/* pushad */ -__forceinline void PUSHA32( void ) { write8( 0x60 ); } - -/* popad */ -__forceinline void POPA32( void ) { write8( 0x61 ); } - -__forceinline void PUSHR(x86IntRegType from) { PUSH32R(from); } -__forceinline void POPR(x86IntRegType from) { POP32R(from); } - - -/* pushfd */ -__forceinline void PUSHFD( void ) { write8( 0x9C ); } -/* popfd */ -__forceinline void POPFD( void ) { write8( 0x9D ); } - -__forceinline void RET( void ) { write8( 0xC3 ); } -__forceinline void RET2( void ) { write16( 0xc3f3 ); } - -__forceinline void CBW( void ) { write16( 0x9866 ); } -__forceinline void CWD( void ) { write8( 0x98 ); } -__forceinline void CDQ( void ) { write8( 0x99 ); } -__forceinline void CWDE() { write8(0x98); } - -__forceinline void LAHF() { write8(0x9f); } -__forceinline void SAHF() { write8(0x9e); } - -__forceinline void BT32ItoR( x86IntRegType to, u8 from ) -{ - write16( 0xBA0F ); - ModRM(3, 4, to); - write8( from ); -} - -__forceinline void BTR32ItoR( x86IntRegType to, u8 from ) -{ - write16( 0xBA0F ); - ModRM(3, 6, to); - write8( from ); -} - -__forceinline void BSRRtoR(x86IntRegType to, x86IntRegType from) -{ - write16( 0xBD0F ); - ModRM( 3, from, to ); -} - -__forceinline void BSWAP32R( x86IntRegType to ) -{ - write8( 0x0F ); - write8( 0xC8 + to ); -} - -// to = from + offset -__forceinline void LEA16RtoR(x86IntRegType to, x86IntRegType from, u16 offset) -{ - write8(0x66); - LEA32RtoR(to, from, offset); -} - -__forceinline void LEA32RtoR(x86IntRegType to, x86IntRegType from, u32 offset) -{ - RexRB(0,to,from); - write8(0x8d); - - if( (from&7) == ESP ) { - if( offset == 0 ) { - ModRM(1, to, from); - write8(0x24); - } - else if( offset < 128 ) { - ModRM(1, to, from); - write8(0x24); - write8(offset); - } - else { - ModRM(2, to, from); - write8(0x24); - write32(offset); - } - } - else { - if( offset == 0 && from != EBP && from!=ESP ) { - ModRM(0, to, from); - } - else if( offset < 128 ) { - ModRM(1, to, from); - write8(offset); - } - else { - ModRM(2, to, from); - write32(offset); - } - } -} - -// to = from0 + from1 -__forceinline void LEA16RRtoR(x86IntRegType to, x86IntRegType from0, x86IntRegType from1) -{ - write8(0x66); - LEA32RRtoR(to, from0, from1); -} - -__forceinline void LEA32RRtoR(x86IntRegType to, x86IntRegType from0, x86IntRegType from1) -{ - RexRXB(0, to, from0, from1); - write8(0x8d); - - if( (from1&7) == EBP ) { - ModRM(1, to, 4); - ModRM(0, from0, from1); - write8(0); - } - else { - ModRM(0, to, 4); - ModRM(0, from0, from1); - } -} - -// to = from << scale (max is 3) -__forceinline void LEA16RStoR(x86IntRegType to, x86IntRegType from, u32 scale) -{ - write8(0x66); - LEA32RStoR(to, from, scale); -} - -// Don't inline recursive functions -void LEA32RStoR(x86IntRegType to, x86IntRegType from, u32 scale) -{ - if( to == from ) { - SHL32ItoR(to, scale); - return; - } - - if( from != ESP ) { - RexRXB(0,to,from,0); - write8(0x8d); - ModRM(0, to, 4); - ModRM(scale, from, 5); - write32(0); - } - else { - assert( to != ESP ); - MOV32RtoR(to, from); - LEA32RStoR(to, to, scale); - } +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +/* + * ix86 core v0.6.2 + * Authors: linuzappz + * alexey silinov + * goldfinger + * zerofrog(@gmail.com) + */ + +#include "PrecompiledHeader.h" +#include "System.h" + +#include "ix86.h" + +#define SWAP(x, y) { *(u32*)&y ^= *(u32*)&x; *(u32*)&x ^= *(u32*)&y; *(u32*)&y ^= *(u32*)&x; } + +u8 *x86Ptr; +u8 *j8Ptr[32]; +u32 *j32Ptr[32]; + +extern void SysPrintf(const char *fmt, ...); + +__forceinline void WriteRmOffset(x86IntRegType to, s32 offset) +{ + if( (to&7) == ESP ) { + if( offset == 0 ) { + ModRM( 0, 0, 4 ); + SibSB( 0, ESP, 4 ); + } + else if( offset < 128 && offset >= -128 ) { + ModRM( 1, 0, 4 ); + SibSB( 0, ESP, 4 ); + write8(offset); + } + else { + ModRM( 2, 0, 4 ); + SibSB( 0, ESP, 4 ); + write32(offset); + } + } + else { + if( offset == 0 ) { + ModRM( 0, 0, to ); + } + else if( offset < 128 && offset >= -128 ) { + ModRM( 1, 0, to ); + write8(offset); + } + else { + ModRM( 2, 0, to ); + write32(offset); + } + } +} + +__forceinline void WriteRmOffsetFrom(x86IntRegType to, x86IntRegType from, int offset) +{ + if ((from&7) == ESP) { + if( offset == 0 ) { + ModRM( 0, to, 0x4 ); + SibSB( 0, 0x4, 0x4 ); + } + else if( offset < 128 && offset >= -128 ) { + ModRM( 1, to, 0x4 ); + SibSB( 0, 0x4, 0x4 ); + write8(offset); + } + else { + ModRM( 2, to, 0x4 ); + SibSB( 0, 0x4, 0x4 ); + write32(offset); + } + } + else { + if( offset == 0 ) { + ModRM( 0, to, from ); + } + else if( offset < 128 && offset >= -128 ) { + ModRM( 1, to, from ); + write8(offset); + } + else { + ModRM( 2, to, from ); + write32(offset); + } + } +} + +// This function is just for rec debugging purposes +__forceinline void CheckX86Ptr( void ) +{ +} + +__forceinline void write64( u64 val ) +{ +#ifdef _DEBUG + CheckX86Ptr( ); +#endif + + *(u64*)x86Ptr = val; + x86Ptr += 8; +} + +__forceinline void ModRM( s32 mod, s32 reg, s32 rm ) +{ + write8( ( mod << 6 ) | ( (reg & 7) << 3 ) | ( rm & 7 ) ); +} + +__forceinline void SibSB( s32 ss, s32 index, s32 base ) +{ + write8( ( ss << 6 ) | ( (index & 7) << 3 ) | ( base & 7 ) ); +} + +__forceinline void SET8R( int cc, int to ) +{ + RexB(0, to); + write8( 0x0F ); + write8( cc ); + write8( 0xC0 | ( to ) ); +} + +__forceinline u8* J8Rel( int cc, int to ) +{ + write8( cc ); + write8( to ); + return (u8*)(x86Ptr - 1); +} + +__forceinline u16* J16Rel( int cc, u32 to ) +{ + write16( 0x0F66 ); + write8( cc ); + write16( to ); + return (u16*)( x86Ptr - 2 ); +} + +__forceinline u32* J32Rel( int cc, u32 to ) +{ + write8( 0x0F ); + write8( cc ); + write32( to ); + return (u32*)( x86Ptr - 4 ); +} + +__forceinline void CMOV32RtoR( int cc, int to, int from ) +{ + RexRB(0,to, from); + write8( 0x0F ); + write8( cc ); + ModRM( 3, to, from ); +} + +__forceinline void CMOV32MtoR( int cc, int to, uptr from ) +{ + RexR(0, to); + write8( 0x0F ); + write8( cc ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +//////////////////////////////////////////////////// +__forceinline void x86SetPtr( u8* ptr ) +{ + x86Ptr = ptr; +} + +//////////////////////////////////////////////////// +__forceinline void x86Shutdown( void ) +{ +} + +//////////////////////////////////////////////////// +__forceinline void x86SetJ8( u8* j8 ) +{ + u32 jump = ( x86Ptr - j8 ) - 1; + + if ( jump > 0x7f ) { + Console::Error( "j8 greater than 0x7f!!" ); + assert(0); + } + *j8 = (u8)jump; +} + +__forceinline void x86SetJ8A( u8* j8 ) +{ + u32 jump = ( x86Ptr - j8 ) - 1; + + if ( jump > 0x7f ) { + Console::Error( "j8 greater than 0x7f!!" ); + assert(0); + } + + if( ((uptr)x86Ptr&0xf) > 4 ) { + + uptr newjump = jump + 16-((uptr)x86Ptr&0xf); + + if( newjump <= 0x7f ) { + jump = newjump; + while((uptr)x86Ptr&0xf) *x86Ptr++ = 0x90; + } + } + *j8 = (u8)jump; +} + +__forceinline void x86SetJ16( u16 *j16 ) +{ + // doesn't work + u32 jump = ( x86Ptr - (u8*)j16 ) - 2; + + if ( jump > 0x7fff ) { + Console::Error( "j16 greater than 0x7fff!!" ); + assert(0); + } + *j16 = (u16)jump; +} + +__forceinline void x86SetJ16A( u16 *j16 ) +{ + if( ((uptr)x86Ptr&0xf) > 4 ) { + while((uptr)x86Ptr&0xf) *x86Ptr++ = 0x90; + } + x86SetJ16(j16); +} + +//////////////////////////////////////////////////// +__forceinline void x86SetJ32( u32* j32 ) +{ + *j32 = ( x86Ptr - (u8*)j32 ) - 4; +} + +__forceinline void x86SetJ32A( u32* j32 ) +{ + while((uptr)x86Ptr&0xf) *x86Ptr++ = 0x90; + x86SetJ32(j32); +} + +//////////////////////////////////////////////////// +__forceinline void x86Align( int bytes ) +{ + // fordward align + x86Ptr = (u8*)( ( (uptr)x86Ptr + bytes - 1) & ~( bytes - 1 ) ); +} + +//////////////////////////////////////////////////// +// Generates executable code to align to the given alignment (could be useful for the second leg +// of if/else conditionals, which usually fall through a jump target label). +void x86AlignExecutable( int align ) +{ + uptr newx86 = ( (uptr)x86Ptr + align - 1) & ~( align - 1 ); + uptr bytes = ( newx86 - (uptr)x86Ptr ); + + switch( bytes ) + { + case 0: break; + + case 1: NOP(); break; + case 2: MOV32RtoR( ESI, ESI ); break; + case 3: write8(0x08D); write8(0x024); write8(0x024); break; + case 5: NOP(); // falls through to 4... + case 4: write8(0x08D); write8(0x064); write8(0x024); write8(0); break; + case 6: write8(0x08D); write8(0x0B6); write32(0); break; + case 8: NOP(); // falls through to 7... + case 7: write8(0x08D); write8(0x034); write8(0x035); write32(0); break; + + default: + { + // for larger alignments, just use a JMP... + u8* aligned_target = JMP8(0); + x86Ptr = (u8*)newx86; + x86SetJ8( aligned_target ); + } + } + + jASSUME( x86Ptr == (u8*)newx86 ); +} + +/********************/ +/* IX86 intructions */ +/********************/ + +__forceinline void STC( void ) +{ + write8( 0xF9 ); +} + +__forceinline void CLC( void ) +{ + write8( 0xF8 ); +} + +// NOP 1-byte +__forceinline void NOP( void ) +{ + write8(0x90); +} + + +//////////////////////////////////// +// mov instructions / +//////////////////////////////////// + +/* mov r64 to r64 */ +__forceinline void MOV64RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(1, from, to); + write8( 0x89 ); + ModRM( 3, from, to ); +} + +/* mov r64 to m64 */ +__forceinline void MOV64RtoM( uptr to, x86IntRegType from ) +{ + RexR(1, from); + write8( 0x89 ); + ModRM( 0, from, DISP32 ); + write32( (u32)MEMADDR(to, 4) ); +} + +/* mov m64 to r64 */ +__forceinline void MOV64MtoR( x86IntRegType to, uptr from ) +{ + RexR(1, to); + write8( 0x8B ); + ModRM( 0, to, DISP32 ); + write32( (u32)MEMADDR(from, 4) ); +} + +/* mov imm32 to m64 */ +__forceinline void MOV64I32toM(uptr to, u32 from ) +{ + Rex(1, 0, 0, 0); + write8( 0xC7 ); + ModRM( 0, 0, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +// mov imm64 to r64 +__forceinline void MOV64ItoR( x86IntRegType to, u64 from) +{ + RexB(1, to); + write8( 0xB8 | (to & 0x7) ); + write64( from ); +} + +/* mov imm32 to r64 */ +__forceinline void MOV64I32toR( x86IntRegType to, s32 from ) +{ + RexB(1, to); + write8( 0xC7 ); + ModRM( 0, 0, to ); + write32( from ); +} + +// mov imm64 to [r64+off] +__forceinline void MOV64ItoRmOffset( x86IntRegType to, u32 from, int offset) +{ + RexB(1,to); + write8( 0xC7 ); + WriteRmOffset(to, offset); + write32(from); +} + +// mov [r64+offset] to r64 +__forceinline void MOV64RmOffsettoR( x86IntRegType to, x86IntRegType from, int offset ) +{ + RexRB(1, to, from); + write8( 0x8B ); + WriteRmOffsetFrom(to, from, offset); +} + +/* mov [r64][r64*scale] to r64 */ +__forceinline void MOV64RmStoR( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale) { + RexRXB(1, to, from2, from); + write8( 0x8B ); + ModRM( 0, to, 0x4 ); + SibSB(scale, from2, from ); +} + +/* mov r64 to [r64+offset] */ +__forceinline void MOV64RtoRmOffset( x86IntRegType to, x86IntRegType from, int offset ) +{ + RexRB(1,from,to); + write8( 0x89 ); + WriteRmOffsetFrom(from, to, offset); +} + +/* mov r64 to [r64][r64*scale] */ +__forceinline void MOV64RtoRmS( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale) { + RexRXB(1, to, from2, from); + write8( 0x89 ); + ModRM( 0, to, 0x4 ); + SibSB(scale, from2, from ); +} + + +/* mov r32 to r32 */ +__forceinline void MOV32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0, from, to); + write8( 0x89 ); + ModRM( 3, from, to ); +} + +/* mov r32 to m32 */ +void MOV32RtoM( uptr to, x86IntRegType from ) +{ + RexR(0, from); + write8( 0x89 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* mov m32 to r32 */ +__forceinline void MOV32MtoR( x86IntRegType to, uptr from ) +{ + RexR(0, to); + write8( 0x8B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* mov [r32] to r32 */ +__forceinline void MOV32RmtoR( x86IntRegType to, x86IntRegType from ) { + RexRB(0, to, from); + write8(0x8B); + WriteRmOffsetFrom(to, from, 0); +} + +__forceinline void MOV32RmtoROffset( x86IntRegType to, x86IntRegType from, int offset ) { + RexRB(0, to, from); + write8( 0x8B ); + WriteRmOffsetFrom(to, from, offset); +} + +/* mov [r32+r32*scale] to r32 */ +__forceinline void MOV32RmStoR( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale) { + RexRXB(0,to,from2,from); + write8( 0x8B ); + ModRM( 0, to, 0x4 ); + SibSB(scale, from2, from ); +} + +// mov r32 to [r32<> 3); + if ( to == EAX) { + write8( 0x05 ); + } else { + write8( 0x81 ); + ModRM( 3, 0, to ); + } + write32( from ); +} + +/* add m64 to r64 */ +__forceinline void ADD64MtoR( x86IntRegType to, uptr from ) +{ + Rex(1, to >> 3, 0, 0); + write8( 0x03 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* add r64 to r64 */ +__forceinline void ADD64RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(1, from, to); + write8( 0x01 ); + ModRM( 3, from, to ); +} + +/* add imm32 to EAX */ +void ADD32ItoEAX( u32 from ) +{ + write8( 0x05 ); + write32( from ); +} + +/* add imm32 to r32 */ +__forceinline void ADD32ItoR( x86IntRegType to, u32 from ) +{ + RexB(0, to); + if(from < 0x80) + { + write8( 0x83 ); + ModRM( 3, 0, to ); + write8( from ); + } + else + { + if ( to == EAX ) { + ADD32ItoEAX(from); + } + else { + write8( 0x81 ); + ModRM( 3, 0, to ); + write32( from ); + } + } +} + +/* add imm32 to m32 */ +__forceinline void ADD32ItoM( uptr to, u32 from ) +{ + /*if(from < 0x80) // crashes games in 64bit build; TODO: figure out why. + { + write8( 0x83 ); + ModRM( 0, 0, DISP32 ); + write32( MEMADDR(to, 8) ); + write8( from ); + } + else*/ + { + write8( 0x81 ); + ModRM( 0, 0, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); + } +} + +// add imm32 to [r32+off] +__forceinline void ADD32ItoRmOffset( x86IntRegType to, u32 from, s32 offset) +{ + RexB(0,to); + if(from < 0x80) + { + write8( 0x83 ); + WriteRmOffset(to,offset); + write8(from); + } + else + { + write8( 0x81 ); + WriteRmOffset(to,offset); + write32(from); + } +} + +/* add r32 to r32 */ +__forceinline void ADD32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0, from, to); + write8( 0x01 ); + ModRM( 3, from, to ); +} + +/* add r32 to m32 */ +__forceinline void ADD32RtoM(uptr to, x86IntRegType from ) +{ + RexR(0,from); + write8( 0x01 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* add m32 to r32 */ +__forceinline void ADD32MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x03 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// add r16 to r16 +__forceinline void ADD16RtoR( x86IntRegType to , x86IntRegType from ) +{ + write8(0x66); + RexRB(0,to,from); + write8( 0x03 ); + ModRM( 3, to, from ); +} + +/* add imm16 to r16 */ +__forceinline void ADD16ItoR( x86IntRegType to, u16 from ) +{ + write8( 0x66 ); + RexB(0,to); + + if ( to == EAX) + { + write8( 0x05 ); + write16( from ); + } + else if(from < 0x80) + { + write8( 0x83 ); + ModRM( 3, 0, to ); + write8((u8)from ); + } + else + { + write8( 0x81 ); + ModRM( 3, 0, to ); + write16( from ); + } +} + +/* add imm16 to m16 */ +__forceinline void ADD16ItoM( uptr to, u16 from ) +{ + write8( 0x66 ); + if(from < 0x80) + { + write8( 0x83 ); + ModRM( 0, 0, DISP32 ); + write32( MEMADDR(to, 6) ); + write8((u8)from ); + } + else + { + write8( 0x81 ); + ModRM( 0, 0, DISP32 ); + write32( MEMADDR(to, 6) ); + write16( from ); + } +} + +/* add r16 to m16 */ +__forceinline void ADD16RtoM(uptr to, x86IntRegType from ) +{ + write8( 0x66 ); + RexR(0,from); + write8( 0x01 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* add m16 to r16 */ +__forceinline void ADD16MtoR( x86IntRegType to, uptr from ) +{ + write8( 0x66 ); + RexR(0,to); + write8( 0x03 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// add m8 to r8 +__forceinline void ADD8MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x02 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* adc imm32 to r32 */ +__forceinline void ADC32ItoR( x86IntRegType to, u32 from ) +{ + RexB(0,to); + if ( to == EAX ) { + write8( 0x15 ); + } + else { + write8( 0x81 ); + ModRM( 3, 2, to ); + } + write32( from ); +} + +/* adc imm32 to m32 */ +__forceinline void ADC32ItoM( uptr to, u32 from ) +{ + write8( 0x81 ); + ModRM( 0, 2, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +/* adc r32 to r32 */ +__forceinline void ADC32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,from,to); + write8( 0x11 ); + ModRM( 3, from, to ); +} + +/* adc m32 to r32 */ +__forceinline void ADC32MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x13 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// adc r32 to m32 +__forceinline void ADC32RtoM( uptr to, x86IntRegType from ) +{ + RexR(0,from); + write8( 0x11 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* inc r32 */ +__forceinline void INC32R( x86IntRegType to ) +{ + write8( 0x40 + to ); +} + +/* inc m32 */ +__forceinline void INC32M( u32 to ) +{ + write8( 0xFF ); + ModRM( 0, 0, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* inc r16 */ +__forceinline void INC16R( x86IntRegType to ) +{ + write8( 0x66 ); + write8( 0x40 + to ); +} + +/* inc m16 */ +__forceinline void INC16M( u32 to ) +{ + write8( 0x66 ); + write8( 0xFF ); + ModRM( 0, 0, DISP32 ); + write32( MEMADDR(to, 4) ); +} + + +/* sub imm32 to r64 */ +__forceinline void SUB64ItoR( x86IntRegType to, u32 from ) +{ + RexB(1, to); + if ( to == EAX ) { + write8( 0x2D ); + } + else { + write8( 0x81 ); + ModRM( 3, 5, to ); + } + write32( from ); +} + +/* sub r64 to r64 */ +__forceinline void SUB64RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(1, from, to); + write8( 0x29 ); + ModRM( 3, from, to ); +} + +/* sub m64 to r64 */ +__forceinline void SUB64MtoR( x86IntRegType to, uptr from ) +{ + RexR(1, to); + write8( 0x2B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* sub imm32 to r32 */ +__forceinline void SUB32ItoR( x86IntRegType to, u32 from ) +{ + RexB(0,to); + if ( to == EAX ) { + write8( 0x2D ); + } + else { + write8( 0x81 ); + ModRM( 3, 5, to ); + } + write32( from ); +} + +/* sub imm32 to m32 */ +__forceinline void SUB32ItoM( uptr to, u32 from ) +{ + write8( 0x81 ); + ModRM( 0, 5, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +/* sub r32 to r32 */ +__forceinline void SUB32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0, from, to); + write8( 0x29 ); + ModRM( 3, from, to ); +} + +/* sub m32 to r32 */ +__forceinline void SUB32MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x2B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// sub r32 to m32 +__forceinline void SUB32RtoM( uptr to, x86IntRegType from ) +{ + RexR(0,from); + write8( 0x29 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +// sub r16 to r16 +__forceinline void SUB16RtoR( x86IntRegType to, u16 from ) +{ + write8(0x66); + RexRB(0,to,from); + write8( 0x2b ); + ModRM( 3, to, from ); +} + +/* sub imm16 to r16 */ +__forceinline void SUB16ItoR( x86IntRegType to, u16 from ) { + write8( 0x66 ); + RexB(0,to); + if ( to == EAX ) { + write8( 0x2D ); + } else { + write8( 0x81 ); + ModRM( 3, 5, to ); + } + write16( from ); +} + +/* sub imm16 to m16 */ +__forceinline void SUB16ItoM( uptr to, u16 from ) { + write8( 0x66 ); + write8( 0x81 ); + ModRM( 0, 5, DISP32 ); + write32( MEMADDR(to, 6) ); + write16( from ); +} + +/* sub m16 to r16 */ +__forceinline void SUB16MtoR( x86IntRegType to, uptr from ) { + write8( 0x66 ); + RexR(0,to); + write8( 0x2B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* sbb r64 to r64 */ +__forceinline void SBB64RtoR( x86IntRegType to, x86IntRegType from ) { + RexRB(1, from,to); + write8( 0x19 ); + ModRM( 3, from, to ); +} + +/* sbb imm32 to r32 */ +__forceinline void SBB32ItoR( x86IntRegType to, u32 from ) { + RexB(0,to); + if ( to == EAX ) { + write8( 0x1D ); + } + else { + write8( 0x81 ); + ModRM( 3, 3, to ); + } + write32( from ); +} + +/* sbb imm32 to m32 */ +__forceinline void SBB32ItoM( uptr to, u32 from ) { + write8( 0x81 ); + ModRM( 0, 3, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +/* sbb r32 to r32 */ +__forceinline void SBB32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,from,to); + write8( 0x19 ); + ModRM( 3, from, to ); +} + +/* sbb m32 to r32 */ +__forceinline void SBB32MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x1B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* sbb r32 to m32 */ +__forceinline void SBB32RtoM( uptr to, x86IntRegType from ) +{ + RexR(0,from); + write8( 0x19 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* dec r32 */ +__forceinline void DEC32R( x86IntRegType to ) +{ + write8( 0x48 + to ); +} + +/* dec m32 */ +__forceinline void DEC32M( u32 to ) +{ + write8( 0xFF ); + ModRM( 0, 1, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* dec r16 */ +__forceinline void DEC16R( x86IntRegType to ) +{ + write8( 0x66 ); + write8( 0x48 + to ); +} + +/* dec m16 */ +__forceinline void DEC16M( u32 to ) +{ + write8( 0x66 ); + write8( 0xFF ); + ModRM( 0, 1, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* mul eax by r32 to edx:eax */ +__forceinline void MUL32R( x86IntRegType from ) +{ + RexB(0,from); + write8( 0xF7 ); + ModRM( 3, 4, from ); +} + +/* imul eax by r32 to edx:eax */ +__forceinline void IMUL32R( x86IntRegType from ) +{ + RexB(0,from); + write8( 0xF7 ); + ModRM( 3, 5, from ); +} + +/* mul eax by m32 to edx:eax */ +__forceinline void MUL32M( u32 from ) +{ + write8( 0xF7 ); + ModRM( 0, 4, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* imul eax by m32 to edx:eax */ +__forceinline void IMUL32M( u32 from ) +{ + write8( 0xF7 ); + ModRM( 0, 5, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* imul r32 by r32 to r32 */ +__forceinline void IMUL32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,to,from); + write16( 0xAF0F ); + ModRM( 3, to, from ); +} + +/* div eax by r32 to edx:eax */ +__forceinline void DIV32R( x86IntRegType from ) +{ + RexB(0,from); + write8( 0xF7 ); + ModRM( 3, 6, from ); +} + +/* idiv eax by r32 to edx:eax */ +__forceinline void IDIV32R( x86IntRegType from ) +{ + RexB(0,from); + write8( 0xF7 ); + ModRM( 3, 7, from ); +} + +/* div eax by m32 to edx:eax */ +__forceinline void DIV32M( u32 from ) +{ + write8( 0xF7 ); + ModRM( 0, 6, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* idiv eax by m32 to edx:eax */ +__forceinline void IDIV32M( u32 from ) +{ + write8( 0xF7 ); + ModRM( 0, 7, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +//////////////////////////////////// +// shifting instructions / +//////////////////////////////////// + +/* shl imm8 to r64 */ +__forceinline void SHL64ItoR( x86IntRegType to, u8 from ) +{ + RexB(1, to); + if ( from == 1 ) + { + write8( 0xD1 ); + ModRM( 3, 4, to ); + return; + } + write8( 0xC1 ); + ModRM( 3, 4, to ); + write8( from ); +} + +/* shl cl to r64 */ +__forceinline void SHL64CLtoR( x86IntRegType to ) +{ + RexB(1, to); + write8( 0xD3 ); + ModRM( 3, 4, to ); +} + +/* shr imm8 to r64 */ +__forceinline void SHR64ItoR( x86IntRegType to, u8 from ) +{ + RexB(1,to); + if ( from == 1 ) { + write8( 0xD1 ); + ModRM( 3, 5, to ); + return; + } + write8( 0xC1 ); + ModRM( 3, 5, to ); + write8( from ); +} + +/* shr cl to r64 */ +__forceinline void SHR64CLtoR( x86IntRegType to ) +{ + RexB(1, to); + write8( 0xD3 ); + ModRM( 3, 5, to ); +} + +/* shl imm8 to r32 */ +__forceinline void SHL32ItoR( x86IntRegType to, u8 from ) +{ + RexB(0, to); + if ( from == 1 ) + { + write8( 0xD1 ); + write8( 0xE0 | (to & 0x7) ); + return; + } + write8( 0xC1 ); + ModRM( 3, 4, to ); + write8( from ); +} + +/* shl imm8 to m32 */ +__forceinline void SHL32ItoM( uptr to, u8 from ) +{ + if ( from == 1 ) + { + write8( 0xD1 ); + ModRM( 0, 4, DISP32 ); + write32( MEMADDR(to, 4) ); + } + else + { + write8( 0xC1 ); + ModRM( 0, 4, DISP32 ); + write32( MEMADDR(to, 5) ); + write8( from ); + } +} + +/* shl cl to r32 */ +__forceinline void SHL32CLtoR( x86IntRegType to ) +{ + RexB(0,to); + write8( 0xD3 ); + ModRM( 3, 4, to ); +} + +// shl imm8 to r16 +__forceinline void SHL16ItoR( x86IntRegType to, u8 from ) +{ + write8(0x66); + RexB(0,to); + if ( from == 1 ) + { + write8( 0xD1 ); + write8( 0xE0 | (to & 0x7) ); + return; + } + write8( 0xC1 ); + ModRM( 3, 4, to ); + write8( from ); +} + +// shl imm8 to r8 +__forceinline void SHL8ItoR( x86IntRegType to, u8 from ) +{ + RexB(0,to); + if ( from == 1 ) + { + write8( 0xD0 ); + write8( 0xE0 | (to & 0x7) ); + return; + } + write8( 0xC0 ); + ModRM( 3, 4, to ); + write8( from ); +} + +/* shr imm8 to r32 */ +__forceinline void SHR32ItoR( x86IntRegType to, u8 from ) { + RexB(0,to); + if ( from == 1 ) + { + write8( 0xD1 ); + write8( 0xE8 | (to & 0x7) ); + } + else + { + write8( 0xC1 ); + ModRM( 3, 5, to ); + write8( from ); + } +} + +/* shr imm8 to m32 */ +__forceinline void SHR32ItoM( uptr to, u8 from ) +{ + if ( from == 1 ) + { + write8( 0xD1 ); + ModRM( 0, 5, DISP32 ); + write32( MEMADDR(to, 4) ); + } + else + { + write8( 0xC1 ); + ModRM( 0, 5, DISP32 ); + write32( MEMADDR(to, 5) ); + write8( from ); + } +} + +/* shr cl to r32 */ +__forceinline void SHR32CLtoR( x86IntRegType to ) +{ + RexB(0,to); + write8( 0xD3 ); + ModRM( 3, 5, to ); +} + +// shr imm8 to r16 +__forceinline void SHR16ItoR( x86IntRegType to, u8 from ) +{ + RexB(0,to); + if ( from == 1 ) + { + write8( 0xD1 ); + ModRM( 3, 5, to ); + } + else + { + write8( 0xC1 ); + ModRM( 3, 5, to ); + write8( from ); + } +} + +// shr imm8 to r8 +__forceinline void SHR8ItoR( x86IntRegType to, u8 from ) +{ + RexB(0,to); + if ( from == 1 ) + { + write8( 0xD0 ); + write8( 0xE8 | (to & 0x7) ); + } + else + { + write8( 0xC0 ); + ModRM( 3, 5, to ); + write8( from ); + } +} + +/* sar imm8 to r64 */ +__forceinline void SAR64ItoR( x86IntRegType to, u8 from ) +{ + RexB(1,to); + if ( from == 1 ) + { + write8( 0xD1 ); + ModRM( 3, 7, to ); + return; + } + write8( 0xC1 ); + ModRM( 3, 7, to ); + write8( from ); +} + +/* sar cl to r64 */ +__forceinline void SAR64CLtoR( x86IntRegType to ) +{ + RexB(1, to); + write8( 0xD3 ); + ModRM( 3, 7, to ); +} + +/* sar imm8 to r32 */ +__forceinline void SAR32ItoR( x86IntRegType to, u8 from ) +{ + RexB(0,to); + if ( from == 1 ) + { + write8( 0xD1 ); + ModRM( 3, 7, to ); + return; + } + write8( 0xC1 ); + ModRM( 3, 7, to ); + write8( from ); +} + +/* sar imm8 to m32 */ +__forceinline void SAR32ItoM( uptr to, u8 from ) +{ + write8( 0xC1 ); + ModRM( 0, 7, DISP32 ); + write32( MEMADDR(to, 5) ); + write8( from ); +} + +/* sar cl to r32 */ +__forceinline void SAR32CLtoR( x86IntRegType to ) +{ + RexB(0,to); + write8( 0xD3 ); + ModRM( 3, 7, to ); +} + +// sar imm8 to r16 +__forceinline void SAR16ItoR( x86IntRegType to, u8 from ) +{ + write8(0x66); + RexB(0,to); + if ( from == 1 ) + { + write8( 0xD1 ); + ModRM( 3, 7, to ); + return; + } + write8( 0xC1 ); + ModRM( 3, 7, to ); + write8( from ); +} + +__forceinline void ROR32ItoR( x86IntRegType to,u8 from ) +{ + RexB(0,to); + if ( from == 1 ) { + write8( 0xd1 ); + write8( 0xc8 | to ); + } + else + { + write8( 0xc1 ); + write8( 0xc8 | to ); + write8( from ); + } +} + +__forceinline void RCR32ItoR( x86IntRegType to, u8 from ) +{ + RexB(0,to); + if ( from == 1 ) { + write8( 0xd1 ); + ModRM(3, 3, to); + } + else + { + write8( 0xc1 ); + ModRM(3, 3, to); + write8( from ); + } +} + +__forceinline void RCR32ItoM( uptr to, u8 from ) +{ + RexB(0,to); + if ( from == 1 ) { + write8( 0xd1 ); + ModRM( 0, 3, DISP32 ); + write32( MEMADDR(to, 8) ); + } + else + { + write8( 0xc1 ); + ModRM( 0, 3, DISP32 ); + write32( MEMADDR(to, 8) ); + write8( from ); + } +} + +// shld imm8 to r32 +__forceinline void SHLD32ItoR( x86IntRegType to, x86IntRegType from, u8 shift ) +{ + RexRB(0,from,to); + write8( 0x0F ); + write8( 0xA4 ); + ModRM( 3, from, to ); + write8( shift ); +} + +// shrd imm8 to r32 +__forceinline void SHRD32ItoR( x86IntRegType to, x86IntRegType from, u8 shift ) +{ + RexRB(0,from,to); + write8( 0x0F ); + write8( 0xAC ); + ModRM( 3, from, to ); + write8( shift ); +} + +//////////////////////////////////// +// logical instructions / +//////////////////////////////////// + +/* or imm32 to r32 */ +__forceinline void OR64ItoR( x86IntRegType to, u32 from ) +{ + RexB(1, to); + if ( to == EAX ) { + write8( 0x0D ); + } else { + write8( 0x81 ); + ModRM( 3, 1, to ); + } + write32( from ); +} + +/* or m64 to r64 */ +__forceinline void OR64MtoR( x86IntRegType to, uptr from ) +{ + RexR(1, to); + write8( 0x0B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* or r64 to r64 */ +__forceinline void OR64RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(1, from, to); + write8( 0x09 ); + ModRM( 3, from, to ); +} + +// or r32 to m64 +__forceinline void OR64RtoM(uptr to, x86IntRegType from ) +{ + RexR(1,from); + write8( 0x09 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* or imm32 to r32 */ +__forceinline void OR32ItoR( x86IntRegType to, u32 from ) +{ + RexB(0,to); + if ( to == EAX ) { + write8( 0x0D ); + } + else { + write8( 0x81 ); + ModRM( 3, 1, to ); + } + write32( from ); +} + +/* or imm32 to m32 */ +__forceinline void OR32ItoM(uptr to, u32 from ) +{ + write8( 0x81 ); + ModRM( 0, 1, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +/* or r32 to r32 */ +__forceinline void OR32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,from,to); + write8( 0x09 ); + ModRM( 3, from, to ); +} + +/* or r32 to m32 */ +__forceinline void OR32RtoM(uptr to, x86IntRegType from ) +{ + RexR(0,from); + write8( 0x09 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* or m32 to r32 */ +__forceinline void OR32MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x0B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// or r16 to r16 +__forceinline void OR16RtoR( x86IntRegType to, x86IntRegType from ) +{ + write8(0x66); + RexRB(0,from,to); + write8( 0x09 ); + ModRM( 3, from, to ); +} + +// or imm16 to r16 +__forceinline void OR16ItoR( x86IntRegType to, u16 from ) +{ + write8(0x66); + RexB(0,to); + if ( to == EAX ) { + write8( 0x0D ); + } + else { + write8( 0x81 ); + ModRM( 3, 1, to ); + } + write16( from ); +} + +// or imm16 to m316 +__forceinline void OR16ItoM( uptr to, u16 from ) +{ + write8(0x66); + write8( 0x81 ); + ModRM( 0, 1, DISP32 ); + write32( MEMADDR(to, 6) ); + write16( from ); +} + +/* or m16 to r16 */ +__forceinline void OR16MtoR( x86IntRegType to, uptr from ) +{ + write8(0x66); + RexR(0,to); + write8( 0x0B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// or r16 to m16 +__forceinline void OR16RtoM( uptr to, x86IntRegType from ) +{ + write8(0x66); + RexR(0,from); + write8( 0x09 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +// or r8 to r8 +__forceinline void OR8RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,from,to); + write8( 0x08 ); + ModRM( 3, from, to ); +} + +// or r8 to m8 +__forceinline void OR8RtoM( uptr to, x86IntRegType from ) +{ + RexR(0,from); + write8( 0x08 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +// or imm8 to m8 +__forceinline void OR8ItoM( uptr to, u8 from ) +{ + write8( 0x80 ); + ModRM( 0, 1, DISP32 ); + write32( MEMADDR(to, 5) ); + write8( from ); +} + +// or m8 to r8 +__forceinline void OR8MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x0A ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* xor imm32 to r64 */ +__forceinline void XOR64ItoR( x86IntRegType to, u32 from ) +{ + RexB(1,to); + if ( to == EAX ) { + write8( 0x35 ); + } else { + write8( 0x81 ); + ModRM( 3, 6, to ); + } + write32( from ); +} + +/* xor r64 to r64 */ +__forceinline void XOR64RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(1, from, to); + write8( 0x31 ); + ModRM( 3, from, to ); +} + +/* xor m64 to r64 */ +__forceinline void XOR64MtoR( x86IntRegType to, uptr from ) +{ + RexR(1, to); + write8( 0x33 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* xor r64 to m64 */ +__forceinline void XOR64RtoM( uptr to, x86IntRegType from ) +{ + RexR(1,from); + write8( 0x31 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* xor imm32 to r32 */ +__forceinline void XOR32ItoR( x86IntRegType to, u32 from ) +{ + RexB(0,to); + if ( to == EAX ) { + write8( 0x35 ); + } + else { + write8( 0x81 ); + ModRM( 3, 6, to ); + } + write32( from ); +} + +/* xor imm32 to m32 */ +__forceinline void XOR32ItoM( uptr to, u32 from ) +{ + write8( 0x81 ); + ModRM( 0, 6, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +/* xor r32 to r32 */ +__forceinline void XOR32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,from,to); + write8( 0x31 ); + ModRM( 3, from, to ); +} + +/* xor r16 to r16 */ +__forceinline void XOR16RtoR( x86IntRegType to, x86IntRegType from ) +{ + write8( 0x66 ); + RexRB(0,from,to); + write8( 0x31 ); + ModRM( 3, from, to ); +} + +/* xor r32 to m32 */ +__forceinline void XOR32RtoM( uptr to, x86IntRegType from ) +{ + RexR(0,from); + write8( 0x31 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* xor m32 to r32 */ +__forceinline void XOR32MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x33 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// xor imm16 to r16 +__forceinline void XOR16ItoR( x86IntRegType to, u16 from ) +{ + write8(0x66); + RexB(0,to); + if ( to == EAX ) { + write8( 0x35 ); + } + else { + write8( 0x81 ); + ModRM( 3, 6, to ); + } + write16( from ); +} + +// xor r16 to m16 +__forceinline void XOR16RtoM( uptr to, x86IntRegType from ) +{ + write8(0x66); + RexR(0,from); + write8( 0x31 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* and imm32 to r64 */ +__forceinline void AND64I32toR( x86IntRegType to, u32 from ) +{ + RexB(1, to); + if ( to == EAX ) { + write8( 0x25 ); + } else { + write8( 0x81 ); + ModRM( 3, 0x4, to ); + } + write32( from ); +} + +/* and m64 to r64 */ +__forceinline void AND64MtoR( x86IntRegType to, uptr from ) +{ + RexR(1, to); + write8( 0x23 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* and r64 to m64 */ +__forceinline void AND64RtoM( uptr to, x86IntRegType from ) +{ + RexR(1, from); + write8( 0x21 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* and r64 to r64 */ +__forceinline void AND64RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(1, from, to); + write8( 0x21 ); + ModRM( 3, from, to ); +} + +/* and imm32 to m64 */ +__forceinline void AND64I32toM( uptr to, u32 from ) +{ + Rex(1,0,0,0); + write8( 0x81 ); + ModRM( 0, 0x4, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +/* and imm32 to r32 */ +__forceinline void AND32ItoR( x86IntRegType to, u32 from ) +{ + RexB(0,to); + if(from < 0x80) + { + AND32I8toR(to, (u8)from); + } + else + { + if ( to == EAX ) { + write8( 0x25 ); + } else { + write8( 0x81 ); + ModRM( 3, 0x4, to ); + } + write32( from ); + } +} + +/* and sign ext imm8 to r32 */ +__forceinline void AND32I8toR( x86IntRegType to, u8 from ) +{ + RexB(0,to); + write8( 0x83 ); + ModRM( 3, 0x4, to ); + write8( from ); +} + +/* and imm32 to m32 */ +__forceinline void AND32ItoM( uptr to, u32 from ) +{ + if(from < 0x80) + { + AND32I8toM(to, (u8)from); + } + else + { + write8( 0x81 ); + ModRM( 0, 0x4, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); + } +} + + +/* and sign ext imm8 to m32 */ +__forceinline void AND32I8toM( uptr to, u8 from ) +{ + write8( 0x83 ); + ModRM( 0, 0x4, DISP32 ); + write32( MEMADDR(to, 5) ); + write8( from ); +} + +/* and r32 to r32 */ +__forceinline void AND32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,from,to); + write8( 0x21 ); + ModRM( 3, from, to ); +} + +/* and r32 to m32 */ +__forceinline void AND32RtoM( uptr to, x86IntRegType from ) +{ + RexR(0,from); + write8( 0x21 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* and m32 to r32 */ +__forceinline void AND32MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x23 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// and r16 to r16 +__forceinline void AND16RtoR( x86IntRegType to, x86IntRegType from ) +{ + write8(0x66); + RexRB(0,to,from); + write8( 0x23 ); + ModRM( 3, to, from ); +} + +/* and imm16 to r16 */ +__forceinline void AND16ItoR( x86IntRegType to, u16 from ) +{ + write8(0x66); + RexB(0,to); + + if ( to == EAX ) { + write8( 0x25 ); + write16( from ); + } + else if ( from < 0x80 ) { + write8( 0x83 ); + ModRM( 3, 0x4, to ); + write8((u8)from ); + } + else { + write8( 0x81 ); + ModRM( 3, 0x4, to ); + write16( from ); + } +} + +/* and imm16 to m16 */ +__forceinline void AND16ItoM( uptr to, u16 from ) +{ + write8(0x66); + if ( from < 0x80 ) { + write8( 0x83 ); + ModRM( 0, 0x4, DISP32 ); + write32( MEMADDR(to, 6) ); + write8((u8)from ); + } + else + { + write8( 0x81 ); + ModRM( 0, 0x4, DISP32 ); + write32( MEMADDR(to, 6) ); + write16( from ); + + } +} + +/* and r16 to m16 */ +__forceinline void AND16RtoM( uptr to, x86IntRegType from ) +{ + write8( 0x66 ); + RexR(0,from); + write8( 0x21 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* and m16 to r16 */ +__forceinline void AND16MtoR( x86IntRegType to, uptr from ) +{ + write8( 0x66 ); + RexR(0,to); + write8( 0x23 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4)); +} + +/* and imm8 to r8 */ +__forceinline void AND8ItoR( x86IntRegType to, u8 from ) +{ + RexB(0,to); + if ( to == EAX ) { + write8( 0x24 ); + } else { + write8( 0x80 ); + ModRM( 3, 0x4, to ); + } + write8( from ); +} + +/* and imm8 to m8 */ +__forceinline void AND8ItoM( uptr to, u8 from ) +{ + write8( 0x80 ); + ModRM( 0, 0x4, DISP32 ); + write32( MEMADDR(to, 5) ); + write8( from ); +} + +// and r8 to r8 +__forceinline void AND8RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,to,from); + write8( 0x22 ); + ModRM( 3, to, from ); +} + +/* and r8 to m8 */ +__forceinline void AND8RtoM( uptr to, x86IntRegType from ) +{ + RexR(0,from); + write8( 0x20 ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* and m8 to r8 */ +__forceinline void AND8MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x22 ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4)); +} + +/* not r64 */ +__forceinline void NOT64R( x86IntRegType from ) +{ + RexB(1, from); + write8( 0xF7 ); + ModRM( 3, 2, from ); +} + +/* not r32 */ +__forceinline void NOT32R( x86IntRegType from ) +{ + RexB(0,from); + write8( 0xF7 ); + ModRM( 3, 2, from ); +} + +// not m32 +__forceinline void NOT32M( u32 from ) +{ + write8( 0xF7 ); + ModRM( 0, 2, DISP32 ); + write32( MEMADDR(from, 4)); +} + +/* neg r64 */ +__forceinline void NEG64R( x86IntRegType from ) +{ + RexB(1, from); + write8( 0xF7 ); + ModRM( 3, 3, from ); +} + +/* neg r32 */ +__forceinline void NEG32R( x86IntRegType from ) +{ + RexB(0,from); + write8( 0xF7 ); + ModRM( 3, 3, from ); +} + +__forceinline void NEG32M( u32 from ) +{ + write8( 0xF7 ); + ModRM( 0, 3, DISP32 ); + write32( MEMADDR(from, 4)); +} + +/* neg r16 */ +__forceinline void NEG16R( x86IntRegType from ) +{ + write8( 0x66 ); + RexB(0,from); + write8( 0xF7 ); + ModRM( 3, 3, from ); +} + +//////////////////////////////////// +// jump instructions / +//////////////////////////////////// + +__forceinline u8* JMP( uptr to ) { + uptr jump = ( x86Ptr - (u8*)to ) - 1; + + if ( jump > 0x7f ) { + assert( to <= 0xffffffff ); + return (u8*)JMP32( to ); + } + else { + return (u8*)JMP8( to ); + } +} + +/* jmp rel8 */ +__forceinline u8* JMP8( u8 to ) +{ + write8( 0xEB ); + write8( to ); + return x86Ptr - 1; +} + +/* jmp rel32 */ +__forceinline u32* JMP32( uptr to ) +{ + assert( (sptr)to <= 0x7fffffff && (sptr)to >= -0x7fffffff ); + write8( 0xE9 ); + write32( to ); + return (u32*)(x86Ptr - 4 ); +} + +/* jmp r32/r64 */ +__forceinline void JMPR( x86IntRegType to ) +{ + RexB(0, to); + write8( 0xFF ); + ModRM( 3, 4, to ); +} + +// jmp m32 +__forceinline void JMP32M( uptr to ) +{ + write8( 0xFF ); + ModRM( 0, 4, DISP32 ); + write32( MEMADDR(to, 4)); +} + +/* jp rel8 */ +__forceinline u8* JP8( u8 to ) { + return J8Rel( 0x7A, to ); +} + +/* jnp rel8 */ +__forceinline u8* JNP8( u8 to ) { + return J8Rel( 0x7B, to ); +} + +/* je rel8 */ +__forceinline u8* JE8( u8 to ) { + return J8Rel( 0x74, to ); +} + +/* jz rel8 */ +__forceinline u8* JZ8( u8 to ) +{ + return J8Rel( 0x74, to ); +} + +/* js rel8 */ +__forceinline u8* JS8( u8 to ) +{ + return J8Rel( 0x78, to ); +} + +/* jns rel8 */ +__forceinline u8* JNS8( u8 to ) +{ + return J8Rel( 0x79, to ); +} + +/* jg rel8 */ +__forceinline u8* JG8( u8 to ) +{ + return J8Rel( 0x7F, to ); +} + +/* jge rel8 */ +__forceinline u8* JGE8( u8 to ) +{ + return J8Rel( 0x7D, to ); +} + +/* jl rel8 */ +__forceinline u8* JL8( u8 to ) +{ + return J8Rel( 0x7C, to ); +} + +/* ja rel8 */ +__forceinline u8* JA8( u8 to ) +{ + return J8Rel( 0x77, to ); +} + +__forceinline u8* JAE8( u8 to ) +{ + return J8Rel( 0x73, to ); +} + +/* jb rel8 */ +__forceinline u8* JB8( u8 to ) +{ + return J8Rel( 0x72, to ); +} + +/* jbe rel8 */ +__forceinline u8* JBE8( u8 to ) +{ + return J8Rel( 0x76, to ); +} + +/* jle rel8 */ +__forceinline u8* JLE8( u8 to ) +{ + return J8Rel( 0x7E, to ); +} + +/* jne rel8 */ +__forceinline u8* JNE8( u8 to ) +{ + return J8Rel( 0x75, to ); +} + +/* jnz rel8 */ +__forceinline u8* JNZ8( u8 to ) +{ + return J8Rel( 0x75, to ); +} + +/* jng rel8 */ +__forceinline u8* JNG8( u8 to ) +{ + return J8Rel( 0x7E, to ); +} + +/* jnge rel8 */ +__forceinline u8* JNGE8( u8 to ) +{ + return J8Rel( 0x7C, to ); +} + +/* jnl rel8 */ +__forceinline u8* JNL8( u8 to ) +{ + return J8Rel( 0x7D, to ); +} + +/* jnle rel8 */ +__forceinline u8* JNLE8( u8 to ) +{ + return J8Rel( 0x7F, to ); +} + +/* jo rel8 */ +__forceinline u8* JO8( u8 to ) +{ + return J8Rel( 0x70, to ); +} + +/* jno rel8 */ +__forceinline u8* JNO8( u8 to ) +{ + return J8Rel( 0x71, to ); +} +/* Untested and slower, use 32bit versions instead +// ja rel16 +__forceinline u16* JA16( u16 to ) +{ + return J16Rel( 0x87, to ); +} + +// jb rel16 +__forceinline u16* JB16( u16 to ) +{ + return J16Rel( 0x82, to ); +} + +// je rel16 +__forceinline u16* JE16( u16 to ) +{ + return J16Rel( 0x84, to ); +} + +// jz rel16 +__forceinline u16* JZ16( u16 to ) +{ + return J16Rel( 0x84, to ); +} +*/ +// jb rel32 +__forceinline u32* JB32( u32 to ) +{ + return J32Rel( 0x82, to ); +} + +/* je rel32 */ +__forceinline u32* JE32( u32 to ) +{ + return J32Rel( 0x84, to ); +} + +/* jz rel32 */ +__forceinline u32* JZ32( u32 to ) +{ + return J32Rel( 0x84, to ); +} + +/* js rel32 */ +__forceinline u32* JS32( u32 to ) +{ + return J32Rel( 0x88, to ); +} + +/* jns rel32 */ +__forceinline u32* JNS32( u32 to ) +{ + return J32Rel( 0x89, to ); +} + +/* jg rel32 */ +__forceinline u32* JG32( u32 to ) +{ + return J32Rel( 0x8F, to ); +} + +/* jge rel32 */ +__forceinline u32* JGE32( u32 to ) +{ + return J32Rel( 0x8D, to ); +} + +/* jl rel32 */ +__forceinline u32* JL32( u32 to ) +{ + return J32Rel( 0x8C, to ); +} + +/* jle rel32 */ +__forceinline u32* JLE32( u32 to ) +{ + return J32Rel( 0x8E, to ); +} + +/* ja rel32 */ +__forceinline u32* JA32( u32 to ) +{ + return J32Rel( 0x87, to ); +} + +/* jae rel32 */ +__forceinline u32* JAE32( u32 to ) +{ + return J32Rel( 0x83, to ); +} + +/* jne rel32 */ +__forceinline u32* JNE32( u32 to ) +{ + return J32Rel( 0x85, to ); +} + +/* jnz rel32 */ +__forceinline u32* JNZ32( u32 to ) +{ + return J32Rel( 0x85, to ); +} + +/* jng rel32 */ +__forceinline u32* JNG32( u32 to ) +{ + return J32Rel( 0x8E, to ); +} + +/* jnge rel32 */ +__forceinline u32* JNGE32( u32 to ) +{ + return J32Rel( 0x8C, to ); +} + +/* jnl rel32 */ +__forceinline u32* JNL32( u32 to ) +{ + return J32Rel( 0x8D, to ); +} + +/* jnle rel32 */ +__forceinline u32* JNLE32( u32 to ) +{ + return J32Rel( 0x8F, to ); +} + +/* jo rel32 */ +__forceinline u32* JO32( u32 to ) +{ + return J32Rel( 0x80, to ); +} + +/* jno rel32 */ +__forceinline u32* JNO32( u32 to ) +{ + return J32Rel( 0x81, to ); +} + + + +/* call func */ +__forceinline void CALLFunc( uptr func ) +{ + func -= ( (uptr)x86Ptr + 5 ); + assert( (sptr)func <= 0x7fffffff && (sptr)func >= -0x7fffffff ); + CALL32(func); +} + +/* call rel32 */ +__forceinline void CALL32( u32 to ) +{ + write8( 0xE8 ); + write32( to ); +} + +/* call r32 */ +__forceinline void CALL32R( x86IntRegType to ) +{ + write8( 0xFF ); + ModRM( 3, 2, to ); +} + +/* call r64 */ +__forceinline void CALL64R( x86IntRegType to ) +{ + RexB(0, to); + write8( 0xFF ); + ModRM( 3, 2, to ); +} + +/* call m32 */ +__forceinline void CALL32M( u32 to ) +{ + write8( 0xFF ); + ModRM( 0, 2, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +//////////////////////////////////// +// misc instructions / +//////////////////////////////////// + +/* cmp imm32 to r64 */ +__forceinline void CMP64I32toR( x86IntRegType to, u32 from ) +{ + RexB(1, to); + if ( to == EAX ) { + write8( 0x3D ); + } + else { + write8( 0x81 ); + ModRM( 3, 7, to ); + } + write32( from ); +} + +/* cmp m64 to r64 */ +__forceinline void CMP64MtoR( x86IntRegType to, uptr from ) +{ + RexR(1, to); + write8( 0x3B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// cmp r64 to r64 +__forceinline void CMP64RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(1,from,to); + write8( 0x39 ); + ModRM( 3, from, to ); +} + +/* cmp imm32 to r32 */ +__forceinline void CMP32ItoR( x86IntRegType to, u32 from ) +{ + RexB(0,to); + if ( to == EAX ) { + write8( 0x3D ); + } + else { + write8( 0x81 ); + ModRM( 3, 7, to ); + } + write32( from ); +} + +/* cmp imm32 to m32 */ +__forceinline void CMP32ItoM( uptr to, u32 from ) +{ + write8( 0x81 ); + ModRM( 0, 7, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +/* cmp r32 to r32 */ +__forceinline void CMP32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,from,to); + write8( 0x39 ); + ModRM( 3, from, to ); +} + +/* cmp m32 to r32 */ +__forceinline void CMP32MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x3B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// cmp imm8 to [r32] +__forceinline void CMP32I8toRm( x86IntRegType to, u8 from) +{ + RexB(0,to); + write8( 0x83 ); + ModRM( 0, 7, to ); + write8(from); +} + +// cmp imm32 to [r32+off] +__forceinline void CMP32I8toRmOffset8( x86IntRegType to, u8 from, u8 off) +{ + RexB(0,to); + write8( 0x83 ); + ModRM( 1, 7, to ); + write8(off); + write8(from); +} + +// cmp imm8 to [r32] +__forceinline void CMP32I8toM( uptr to, u8 from) +{ + write8( 0x83 ); + ModRM( 0, 7, DISP32 ); + write32( MEMADDR(to, 5) ); + write8( from ); +} + +/* cmp imm16 to r16 */ +__forceinline void CMP16ItoR( x86IntRegType to, u16 from ) +{ + write8( 0x66 ); + RexB(0,to); + if ( to == EAX ) + { + write8( 0x3D ); + } + else + { + write8( 0x81 ); + ModRM( 3, 7, to ); + } + write16( from ); +} + +/* cmp imm16 to m16 */ +__forceinline void CMP16ItoM( uptr to, u16 from ) +{ + write8( 0x66 ); + write8( 0x81 ); + ModRM( 0, 7, DISP32 ); + write32( MEMADDR(to, 6) ); + write16( from ); +} + +/* cmp r16 to r16 */ +__forceinline void CMP16RtoR( x86IntRegType to, x86IntRegType from ) +{ + write8( 0x66 ); + RexRB(0,from,to); + write8( 0x39 ); + ModRM( 3, from, to ); +} + +/* cmp m16 to r16 */ +__forceinline void CMP16MtoR( x86IntRegType to, uptr from ) +{ + write8( 0x66 ); + RexR(0,to); + write8( 0x3B ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// cmp imm8 to r8 +__forceinline void CMP8ItoR( x86IntRegType to, u8 from ) +{ + RexB(0,to); + if ( to == EAX ) + { + write8( 0x3C ); + } + else + { + write8( 0x80 ); + ModRM( 3, 7, to ); + } + write8( from ); +} + +// cmp m8 to r8 +__forceinline void CMP8MtoR( x86IntRegType to, uptr from ) +{ + RexR(0,to); + write8( 0x3A ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* test imm32 to r32 */ +__forceinline void TEST32ItoR( x86IntRegType to, u32 from ) +{ + RexB(0,to); + if ( to == EAX ) + { + write8( 0xA9 ); + } + else + { + write8( 0xF7 ); + ModRM( 3, 0, to ); + } + write32( from ); +} + +__forceinline void TEST32ItoM( uptr to, u32 from ) +{ + write8( 0xF7 ); + ModRM( 0, 0, DISP32 ); + write32( MEMADDR(to, 8) ); + write32( from ); +} + +/* test r32 to r32 */ +__forceinline void TEST32RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0,from,to); + write8( 0x85 ); + ModRM( 3, from, to ); +} + +// test imm32 to [r32] +__forceinline void TEST32ItoRm( x86IntRegType to, u32 from ) +{ + RexB(0,to); + write8( 0xF7 ); + ModRM( 0, 0, to ); + write32(from); +} + +// test imm16 to r16 +__forceinline void TEST16ItoR( x86IntRegType to, u16 from ) +{ + write8(0x66); + RexB(0,to); + if ( to == EAX ) + { + write8( 0xA9 ); + } + else + { + write8( 0xF7 ); + ModRM( 3, 0, to ); + } + write16( from ); +} + +// test r16 to r16 +__forceinline void TEST16RtoR( x86IntRegType to, x86IntRegType from ) +{ + write8(0x66); + RexRB(0,from,to); + write8( 0x85 ); + ModRM( 3, from, to ); +} + +// test r8 to r8 +__forceinline void TEST8RtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0, from, to); + write8( 0x84 ); + ModRM( 3, from, to ); +} + + +// test imm8 to r8 +__forceinline void TEST8ItoR( x86IntRegType to, u8 from ) +{ + RexB(0,to); + if ( to == EAX ) + { + write8( 0xA8 ); + } + else + { + write8( 0xF6 ); + ModRM( 3, 0, to ); + } + write8( from ); +} + +// test imm8 to r8 +__forceinline void TEST8ItoM( uptr to, u8 from ) +{ + write8( 0xF6 ); + ModRM( 0, 0, DISP32 ); + write32( MEMADDR(to, 5) ); + write8( from ); +} + +/* sets r8 */ +__forceinline void SETS8R( x86IntRegType to ) +{ + SET8R( 0x98, to ); +} + +/* setl r8 */ +__forceinline void SETL8R( x86IntRegType to ) +{ + SET8R( 0x9C, to ); +} + +// setge r8 +__forceinline void SETGE8R( x86IntRegType to ) { SET8R(0x9d, to); } +// setg r8 +__forceinline void SETG8R( x86IntRegType to ) { SET8R(0x9f, to); } +// seta r8 +__forceinline void SETA8R( x86IntRegType to ) { SET8R(0x97, to); } +// setae r8 +__forceinline void SETAE8R( x86IntRegType to ) { SET8R(0x99, to); } +/* setb r8 */ +__forceinline void SETB8R( x86IntRegType to ) { SET8R( 0x92, to ); } +/* setb r8 */ +__forceinline void SETNZ8R( x86IntRegType to ) { SET8R( 0x95, to ); } +// setz r8 +__forceinline void SETZ8R( x86IntRegType to ) { SET8R(0x94, to); } +// sete r8 +__forceinline void SETE8R( x86IntRegType to ) { SET8R(0x94, to); } + +/* push imm32 */ +__forceinline void PUSH32I( u32 from ) +{; + write8( 0x68 ); + write32( from ); +} + +/* push r32 */ +__forceinline void PUSH32R( x86IntRegType from ) { write8( 0x50 | from ); } + +/* push m32 */ +__forceinline void PUSH32M( u32 from ) +{ + write8( 0xFF ); + ModRM( 0, 6, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* pop r32 */ +__forceinline void POP32R( x86IntRegType from ) { write8( 0x58 | from ); } + +/* pushad */ +__forceinline void PUSHA32( void ) { write8( 0x60 ); } + +/* popad */ +__forceinline void POPA32( void ) { write8( 0x61 ); } + +__forceinline void PUSHR(x86IntRegType from) { PUSH32R(from); } +__forceinline void POPR(x86IntRegType from) { POP32R(from); } + + +/* pushfd */ +__forceinline void PUSHFD( void ) { write8( 0x9C ); } +/* popfd */ +__forceinline void POPFD( void ) { write8( 0x9D ); } + +__forceinline void RET( void ) { write8( 0xC3 ); } +__forceinline void RET2( void ) { write16( 0xc3f3 ); } + +__forceinline void CBW( void ) { write16( 0x9866 ); } +__forceinline void CWD( void ) { write8( 0x98 ); } +__forceinline void CDQ( void ) { write8( 0x99 ); } +__forceinline void CWDE() { write8(0x98); } + +__forceinline void LAHF() { write8(0x9f); } +__forceinline void SAHF() { write8(0x9e); } + +__forceinline void BT32ItoR( x86IntRegType to, u8 from ) +{ + write16( 0xBA0F ); + ModRM(3, 4, to); + write8( from ); +} + +__forceinline void BTR32ItoR( x86IntRegType to, u8 from ) +{ + write16( 0xBA0F ); + ModRM(3, 6, to); + write8( from ); +} + +__forceinline void BSRRtoR(x86IntRegType to, x86IntRegType from) +{ + write16( 0xBD0F ); + ModRM( 3, from, to ); +} + +__forceinline void BSWAP32R( x86IntRegType to ) +{ + write8( 0x0F ); + write8( 0xC8 + to ); +} + +// to = from + offset +__forceinline void LEA16RtoR(x86IntRegType to, x86IntRegType from, u16 offset) +{ + write8(0x66); + LEA32RtoR(to, from, offset); +} + +__forceinline void LEA32RtoR(x86IntRegType to, x86IntRegType from, u32 offset) +{ + RexRB(0,to,from); + write8(0x8d); + + if( (from&7) == ESP ) { + if( offset == 0 ) { + ModRM(1, to, from); + write8(0x24); + } + else if( offset < 128 ) { + ModRM(1, to, from); + write8(0x24); + write8(offset); + } + else { + ModRM(2, to, from); + write8(0x24); + write32(offset); + } + } + else { + if( offset == 0 && from != EBP && from!=ESP ) { + ModRM(0, to, from); + } + else if( offset < 128 ) { + ModRM(1, to, from); + write8(offset); + } + else { + ModRM(2, to, from); + write32(offset); + } + } +} + +// to = from0 + from1 +__forceinline void LEA16RRtoR(x86IntRegType to, x86IntRegType from0, x86IntRegType from1) +{ + write8(0x66); + LEA32RRtoR(to, from0, from1); +} + +__forceinline void LEA32RRtoR(x86IntRegType to, x86IntRegType from0, x86IntRegType from1) +{ + RexRXB(0, to, from0, from1); + write8(0x8d); + + if( (from1&7) == EBP ) { + ModRM(1, to, 4); + ModRM(0, from0, from1); + write8(0); + } + else { + ModRM(0, to, 4); + ModRM(0, from0, from1); + } +} + +// to = from << scale (max is 3) +__forceinline void LEA16RStoR(x86IntRegType to, x86IntRegType from, u32 scale) +{ + write8(0x66); + LEA32RStoR(to, from, scale); +} + +// Don't inline recursive functions +void LEA32RStoR(x86IntRegType to, x86IntRegType from, u32 scale) +{ + if( to == from ) { + SHL32ItoR(to, scale); + return; + } + + if( from != ESP ) { + RexRXB(0,to,from,0); + write8(0x8d); + ModRM(0, to, 4); + ModRM(scale, from, 5); + write32(0); + } + else { + assert( to != ESP ); + MOV32RtoR(to, from); + LEA32RStoR(to, to, scale); + } } \ No newline at end of file diff --git a/pcsx2/x86/ix86/ix86.h b/pcsx2/x86/ix86/ix86.h index cf7c4d09b7..80a7f78623 100644 --- a/pcsx2/x86/ix86/ix86.h +++ b/pcsx2/x86/ix86/ix86.h @@ -1,1753 +1,1753 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -/* - * ix86 definitions v0.6.2 - * Authors: linuzappz - * alexey silinov - * goldfinger - * shadow < shadow@pcsx2.net > - */ - -#ifndef __IX86_H__ -#define __IX86_H__ - -#include "PS2Etypes.h" // Basic types header - -#define XMMREGS 8 -#define X86REGS 8 - -#define MMXREGS 8 - -#define SIB 4 -#define SIBDISP 5 -#define DISP32 5 - -// general types -typedef int x86IntRegType; -#define EAX 0 -#define EBX 3 -#define ECX 1 -#define EDX 2 -#define ESI 6 -#define EDI 7 -#define EBP 5 -#define ESP 4 - -#define X86ARG1 EAX -#define X86ARG2 ECX -#define X86ARG3 EDX -#define X86ARG4 EBX - -#define MM0 0 -#define MM1 1 -#define MM2 2 -#define MM3 3 -#define MM4 4 -#define MM5 5 -#define MM6 6 -#define MM7 7 - -typedef int x86MMXRegType; - -#define XMM0 0 -#define XMM1 1 -#define XMM2 2 -#define XMM3 3 -#define XMM4 4 -#define XMM5 5 -#define XMM6 6 -#define XMM7 7 -#define XMM8 8 -#define XMM9 9 -#define XMM10 10 -#define XMM11 11 -#define XMM12 12 -#define XMM13 13 -#define XMM14 14 -#define XMM15 15 - -typedef int x86SSERegType; - -enum XMMSSEType -{ - XMMT_INT = 0, // integer (sse2 only) - XMMT_FPS = 1, // floating point - //XMMT_FPD = 3, // double -}; - -extern XMMSSEType g_xmmtypes[XMMREGS]; - -extern void cpudetectInit( void );//this is all that needs to be called and will fill up the below structs - -typedef struct CAPABILITIES CAPABILITIES; -//cpu capabilities structure -struct CAPABILITIES { - u32 hasFloatingPointUnit; - u32 hasVirtual8086ModeEnhancements; - u32 hasDebuggingExtensions; - u32 hasPageSizeExtensions; - u32 hasTimeStampCounter; - u32 hasModelSpecificRegisters; - u32 hasPhysicalAddressExtension; - u32 hasCOMPXCHG8BInstruction; - u32 hasAdvancedProgrammableInterruptController; - u32 hasSEPFastSystemCall; - u32 hasMemoryTypeRangeRegisters; - u32 hasPTEGlobalFlag; - u32 hasMachineCheckArchitecture; - u32 hasConditionalMoveAndCompareInstructions; - u32 hasFGPageAttributeTable; - u32 has36bitPageSizeExtension; - u32 hasProcessorSerialNumber; - u32 hasCFLUSHInstruction; - u32 hasDebugStore; - u32 hasACPIThermalMonitorAndClockControl; - u32 hasMultimediaExtensions; - u32 hasFastStreamingSIMDExtensionsSaveRestore; - u32 hasStreamingSIMDExtensions; - u32 hasStreamingSIMD2Extensions; - u32 hasSelfSnoop; - u32 hasMultiThreading; // is TRUE for both mutli-core and Hyperthreaded CPUs. - u32 hasThermalMonitor; - u32 hasIntel64BitArchitecture; - u32 hasStreamingSIMD3Extensions; - u32 hasStreamingSIMD4Extensions; - - // AMD-specific CPU Features - u32 hasMultimediaExtensionsExt; - u32 hasAMD64BitArchitecture; - u32 has3DNOWInstructionExtensionsExt; - u32 has3DNOWInstructionExtensions; -}; - -extern CAPABILITIES cpucaps; - -struct CPUINFO{ - - u32 x86Family; // Processor Family - u32 x86Model; // Processor Model - u32 x86PType; // Processor Type - u32 x86StepID; // Stepping ID - u32 x86Flags; // Feature Flags - u32 x86Flags2; // More Feature Flags - u32 x86EFlags; // Extended Feature Flags - - u32 PhysicalCores; - u32 LogicalCores; - - char x86ID[16]; // Vendor ID //the vendor creator (in %s) - char x86Type[20]; //cpu type in char format //the cpu type (in %s) - char x86Fam[50]; // family in char format //the original cpu name string (in %s) - u32 cpuspeed; // speed of cpu //this will give cpu speed (in %d) -}; - -extern CPUINFO cpuinfo; - -extern u8 *x86Ptr; -extern u8 *j8Ptr[32]; -extern u32 *j32Ptr[32]; - -#define MEMADDR(addr, oplen) (addr) - -#define Rex(w,r,x,b) assert(0); -#define RexR(w, reg) if( w||(reg)>=8 ) assert(0); -#define RexB(w, base) if( w||(base)>=8 ) assert(0); -#define RexRB(w, reg, base) if( w||(reg) >= 8 || (base)>=8 ) assert(0); -#define RexRXB(w, reg, index, base) if( w||(reg) >= 8 || (index) >= 8 || (base) >= 8 ) assert(0); - -// perf counters -#ifdef PCSX2_DEVBUILD -extern void StartPerfCounter(); -extern void StopPerfCounter(); -#else -#define StartPerfCounter() -#define StopPerfCounter() -#endif - - -extern __forceinline void write8( u8 val ); -extern __forceinline void write16( u16 val ); -extern __forceinline void write32( u32 val ); -extern void write64( u64 val ); - - -extern void x86SetPtr( u8 *ptr ); -extern void x86Shutdown( void ); - -extern void x86SetJ8( u8 *j8 ); -extern void x86SetJ8A( u8 *j8 ); -extern void x86SetJ16( u16 *j16 ); -extern void x86SetJ16A( u16 *j16 ); -extern void x86SetJ32( u32 *j32 ); -extern void x86SetJ32A( u32 *j32 ); - -extern void x86Align( int bytes ); -extern void x86AlignExecutable( int align ); - -u64 GetCPUTick( void ); - -// General Helper functions -extern void ModRM( int mod, int reg, int rm ); -extern void SibSB( int ss, int index, int base ); -extern void SET8R( int cc, int to ); -extern u8* J8Rel( int cc, int to ); -extern u32* J32Rel( int cc, u32 to ); -extern void CMOV32RtoR( int cc, int to, int from ); -extern void CMOV32MtoR( int cc, int to, uptr from ); - -//****************** -// IX86 intructions -//****************** - -// -// * scale values: -// * 0 - *1 -// * 1 - *2 -// * 2 - *4 -// * 3 - *8 -// - -extern void STC( void ); -extern void CLC( void ); -extern void NOP( void ); - -//////////////////////////////////// -// mov instructions // -//////////////////////////////////// - -// mov r64 to r64 -extern void MOV64RtoR( x86IntRegType to, x86IntRegType from ); -// mov r64 to m64 -extern void MOV64RtoM( uptr to, x86IntRegType from ); -// mov m64 to r64 -extern void MOV64MtoR( x86IntRegType to, uptr from ); -// mov sign ext imm32 to m64 -extern void MOV64I32toM( uptr to, u32 from ); -// mov sign ext imm32 to r64 -extern void MOV64I32toR( x86IntRegType to, s32 from); -// mov imm64 to r64 -extern void MOV64ItoR( x86IntRegType to, u64 from); -// mov imm64 to [r64+off] -extern void MOV64ItoRmOffset( x86IntRegType to, u32 from, int offset); -// mov [r64+offset] to r64 -extern void MOV64RmOffsettoR( x86IntRegType to, x86IntRegType from, int offset ); -// mov [r64][r64*scale] to r64 -extern void MOV64RmStoR( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale); -// mov r64 to [r64+offset] -extern void MOV64RtoRmOffset( x86IntRegType to, x86IntRegType from, int offset ); -// mov r64 to [r64][r64*scale] -extern void MOV64RtoRmS( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale); - -// mov r32 to r32 -extern void MOV32RtoR( x86IntRegType to, x86IntRegType from ); -// mov r32 to m32 -extern void MOV32RtoM( uptr to, x86IntRegType from ); -// mov m32 to r32 -extern void MOV32MtoR( x86IntRegType to, uptr from ); -// mov [r32] to r32 -extern void MOV32RmtoR( x86IntRegType to, x86IntRegType from ); -extern void MOV32RmtoROffset( x86IntRegType to, x86IntRegType from, int offset ); -// mov [r32][r32< subtract ST(0) from ST(1), store in ST(1) and POP stack -extern void FSUBP( void ); -// fmul ST(src) to fpu reg stack ST(0) -extern void FMUL32Rto0( x86IntRegType src ); -// fmul ST(0) to fpu reg stack ST(src) -extern void FMUL320toR( x86IntRegType src ); -// fdiv ST(src) to fpu reg stack ST(0) -extern void FDIV32Rto0( x86IntRegType src ); -// fdiv ST(0) to fpu reg stack ST(src) -extern void FDIV320toR( x86IntRegType src ); -// fdiv ST(0) to fpu reg stack ST(src), pop stack, store in ST(src) -extern void FDIV320toRP( x86IntRegType src ); - -// fadd m32 to fpu reg stack -extern void FADD32( u32 from ); -// fsub m32 to fpu reg stack -extern void FSUB32( u32 from ); -// fmul m32 to fpu reg stack -extern void FMUL32( u32 from ); -// fdiv m32 to fpu reg stack -extern void FDIV32( u32 from ); -// fcomi st, st( i) -extern void FCOMI( x86IntRegType src ); -// fcomip st, st( i) -extern void FCOMIP( x86IntRegType src ); -// fucomi st, st( i) -extern void FUCOMI( x86IntRegType src ); -// fucomip st, st( i) -extern void FUCOMIP( x86IntRegType src ); -// fcom m32 to fpu reg stack -extern void FCOM32( u32 from ); -// fabs fpu reg stack -extern void FABS( void ); -// fsqrt fpu reg stack -extern void FSQRT( void ); -// ftan fpu reg stack -extern void FPATAN( void ); -// fsin fpu reg stack -extern void FSIN( void ); -// fchs fpu reg stack -extern void FCHS( void ); - -// fcmovb fpu reg to fpu reg stack -extern void FCMOVB32( x86IntRegType from ); -// fcmove fpu reg to fpu reg stack -extern void FCMOVE32( x86IntRegType from ); -// fcmovbe fpu reg to fpu reg stack -extern void FCMOVBE32( x86IntRegType from ); -// fcmovu fpu reg to fpu reg stack -extern void FCMOVU32( x86IntRegType from ); -// fcmovnb fpu reg to fpu reg stack -extern void FCMOVNB32( x86IntRegType from ); -// fcmovne fpu reg to fpu reg stack -extern void FCMOVNE32( x86IntRegType from ); -// fcmovnbe fpu reg to fpu reg stack -extern void FCMOVNBE32( x86IntRegType from ); -// fcmovnu fpu reg to fpu reg stack -extern void FCMOVNU32( x86IntRegType from ); -extern void FCOMP32( u32 from ); -extern void FNSTSWtoAX( void ); - -#define MMXONLY(code) code - -//****************** -// MMX instructions -//****************** - -// r64 = mm - -// movq m64 to r64 -extern void MOVQMtoR( x86MMXRegType to, uptr from ); -// movq r64 to m64 -extern void MOVQRtoM( uptr to, x86MMXRegType from ); - -// pand r64 to r64 -extern void PANDRtoR( x86MMXRegType to, x86MMXRegType from ); -extern void PANDNRtoR( x86MMXRegType to, x86MMXRegType from ); -// pand m64 to r64 ; -extern void PANDMtoR( x86MMXRegType to, uptr from ); -// pandn r64 to r64 -extern void PANDNRtoR( x86MMXRegType to, x86MMXRegType from ); -// pandn r64 to r64 -extern void PANDNMtoR( x86MMXRegType to, uptr from ); -// por r64 to r64 -extern void PORRtoR( x86MMXRegType to, x86MMXRegType from ); -// por m64 to r64 -extern void PORMtoR( x86MMXRegType to, uptr from ); -// pxor r64 to r64 -extern void PXORRtoR( x86MMXRegType to, x86MMXRegType from ); -// pxor m64 to r64 -extern void PXORMtoR( x86MMXRegType to, uptr from ); - -// psllq r64 to r64 -extern void PSLLQRtoR( x86MMXRegType to, x86MMXRegType from ); -// psllq m64 to r64 -extern void PSLLQMtoR( x86MMXRegType to, uptr from ); -// psllq imm8 to r64 -extern void PSLLQItoR( x86MMXRegType to, u8 from ); -// psrlq r64 to r64 -extern void PSRLQRtoR( x86MMXRegType to, x86MMXRegType from ); -// psrlq m64 to r64 -extern void PSRLQMtoR( x86MMXRegType to, uptr from ); -// psrlq imm8 to r64 -extern void PSRLQItoR( x86MMXRegType to, u8 from ); - -// paddusb r64 to r64 -extern void PADDUSBRtoR( x86MMXRegType to, x86MMXRegType from ); -// paddusb m64 to r64 -extern void PADDUSBMtoR( x86MMXRegType to, uptr from ); -// paddusw r64 to r64 -extern void PADDUSWRtoR( x86MMXRegType to, x86MMXRegType from ); -// paddusw m64 to r64 -extern void PADDUSWMtoR( x86MMXRegType to, uptr from ); - -// paddb r64 to r64 -extern void PADDBRtoR( x86MMXRegType to, x86MMXRegType from ); -// paddb m64 to r64 -extern void PADDBMtoR( x86MMXRegType to, uptr from ); -// paddw r64 to r64 -extern void PADDWRtoR( x86MMXRegType to, x86MMXRegType from ); -// paddw m64 to r64 -extern void PADDWMtoR( x86MMXRegType to, uptr from ); -// paddd r64 to r64 -extern void PADDDRtoR( x86MMXRegType to, x86MMXRegType from ); -// paddd m64 to r64 -extern void PADDDMtoR( x86MMXRegType to, uptr from ); -extern void PADDSBRtoR( x86MMXRegType to, x86MMXRegType from ); -extern void PADDSWRtoR( x86MMXRegType to, x86MMXRegType from ); - -// paddq m64 to r64 (sse2 only?) -extern void PADDQMtoR( x86MMXRegType to, uptr from ); -// paddq r64 to r64 (sse2 only?) -extern void PADDQRtoR( x86MMXRegType to, x86MMXRegType from ); - -extern void PSUBSBRtoR( x86MMXRegType to, x86MMXRegType from ); -extern void PSUBSWRtoR( x86MMXRegType to, x86MMXRegType from ); - -extern void PSUBBRtoR( x86MMXRegType to, x86MMXRegType from ); -extern void PSUBWRtoR( x86MMXRegType to, x86MMXRegType from ); -extern void PSUBDRtoR( x86MMXRegType to, x86MMXRegType from ); -extern void PSUBDMtoR( x86MMXRegType to, uptr from ); - -// psubq m64 to r64 (sse2 only?) -extern void PSUBQMtoR( x86MMXRegType to, uptr from ); -// psubq r64 to r64 (sse2 only?) -extern void PSUBQRtoR( x86MMXRegType to, x86MMXRegType from ); - -// pmuludq m64 to r64 (sse2 only?) -extern void PMULUDQMtoR( x86MMXRegType to, uptr from ); -// pmuludq r64 to r64 (sse2 only?) -extern void PMULUDQRtoR( x86MMXRegType to, x86MMXRegType from ); - -extern void PCMPEQBRtoR( x86MMXRegType to, x86MMXRegType from ); -extern void PCMPEQWRtoR( x86MMXRegType to, x86MMXRegType from ); -extern void PCMPEQDRtoR( x86MMXRegType to, x86MMXRegType from ); -extern void PCMPEQDMtoR( x86MMXRegType to, uptr from ); -extern void PCMPGTBRtoR( x86MMXRegType to, x86MMXRegType from ); -extern void PCMPGTWRtoR( x86MMXRegType to, x86MMXRegType from ); -extern void PCMPGTDRtoR( x86MMXRegType to, x86MMXRegType from ); -extern void PCMPGTDMtoR( x86MMXRegType to, uptr from ); -extern void PSRLWItoR( x86MMXRegType to, u8 from ); -extern void PSRLDItoR( x86MMXRegType to, u8 from ); -extern void PSRLDRtoR( x86MMXRegType to, x86MMXRegType from ); -extern void PSLLWItoR( x86MMXRegType to, u8 from ); -extern void PSLLDItoR( x86MMXRegType to, u8 from ); -extern void PSLLDRtoR( x86MMXRegType to, x86MMXRegType from ); -extern void PSRAWItoR( x86MMXRegType to, u8 from ); -extern void PSRADItoR( x86MMXRegType to, u8 from ); -extern void PSRADRtoR( x86MMXRegType to, x86MMXRegType from ); -extern void PUNPCKLDQRtoR( x86MMXRegType to, x86MMXRegType from ); -extern void PUNPCKLDQMtoR( x86MMXRegType to, uptr from ); -extern void PUNPCKHDQRtoR( x86MMXRegType to, x86MMXRegType from ); -extern void PUNPCKHDQMtoR( x86MMXRegType to, uptr from ); -extern void MOVQ64ItoR( x86MMXRegType reg, u64 i ); //Prototype.Todo add all consts to end of block.not after jr $+8 -extern void MOVQRtoR( x86MMXRegType to, x86MMXRegType from ); -extern void MOVQRmtoROffset( x86MMXRegType to, x86IntRegType from, u32 offset ); -extern void MOVQRtoRmOffset( x86IntRegType to, x86MMXRegType from, u32 offset ); -extern void MOVDMtoMMX( x86MMXRegType to, uptr from ); -extern void MOVDMMXtoM( uptr to, x86MMXRegType from ); -extern void MOVD32RtoMMX( x86MMXRegType to, x86IntRegType from ); -extern void MOVD32RmtoMMX( x86MMXRegType to, x86IntRegType from ); -extern void MOVD32RmOffsettoMMX( x86MMXRegType to, x86IntRegType from, u32 offset ); -extern void MOVD32MMXtoR( x86IntRegType to, x86MMXRegType from ); -extern void MOVD32MMXtoRm( x86IntRegType to, x86MMXRegType from ); -extern void MOVD32MMXtoRmOffset( x86IntRegType to, x86MMXRegType from, u32 offset ); -extern void PINSRWRtoMMX( x86MMXRegType to, x86SSERegType from, u8 imm8 ); -extern void PSHUFWRtoR(x86MMXRegType to, x86MMXRegType from, u8 imm8); -extern void PSHUFWMtoR(x86MMXRegType to, uptr from, u8 imm8); -extern void MASKMOVQRtoR(x86MMXRegType to, x86MMXRegType from); - -// emms -extern void EMMS( void ); - -//**********************************************************************************/ -//PACKSSWB,PACKSSDW: Pack Saturate Signed Word 64bits -//********************************************************************************** -extern void PACKSSWBMMXtoMMX(x86MMXRegType to, x86MMXRegType from); -extern void PACKSSDWMMXtoMMX(x86MMXRegType to, x86MMXRegType from); - -extern void PMOVMSKBMMXtoR(x86IntRegType to, x86MMXRegType from); - -extern void SSE2_MOVDQ2Q_XMM_to_MM( x86MMXRegType to, x86SSERegType from); -extern void SSE2_MOVQ2DQ_MM_to_XMM( x86SSERegType to, x86MMXRegType from); - -//********************* -// SSE instructions * -//********************* -extern void SSE_MOVAPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_MOVAPS_XMM_to_M128( uptr to, x86SSERegType from ); -extern void SSE_MOVAPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); - -extern void SSE_MOVUPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_MOVUPS_XMM_to_M128( uptr to, x86SSERegType from ); - -extern void SSE_MOVSS_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_MOVSS_XMM_to_M32( u32 to, x86SSERegType from ); -extern void SSE_MOVSS_XMM_to_Rm( x86IntRegType to, x86SSERegType from ); -extern void SSE_MOVSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_MOVSS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ); -extern void SSE_MOVSS_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ); - -extern void SSE2_MOVSD_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); - -extern void SSE2_MOVQ_M64_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_MOVQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_MOVQ_XMM_to_M64( u32 to, x86SSERegType from ); - -extern void SSE_MASKMOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); - -extern void SSE_MOVLPS_M64_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_MOVLPS_XMM_to_M64( u32 to, x86SSERegType from ); -extern void SSE_MOVLPS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ); -extern void SSE_MOVLPS_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ); - -extern void SSE_MOVHPS_M64_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_MOVHPS_XMM_to_M64( u32 to, x86SSERegType from ); -extern void SSE_MOVHPS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ); -extern void SSE_MOVHPS_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ); - -extern void SSE_MOVLHPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_MOVHLPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_MOVLPSRmtoR( x86SSERegType to, x86IntRegType from ); -extern void SSE_MOVLPSRmtoROffset( x86SSERegType to, x86IntRegType from, int offset ); -extern void SSE_MOVLPSRtoRm( x86SSERegType to, x86IntRegType from ); -extern void SSE_MOVLPSRtoRmOffset( x86SSERegType to, x86IntRegType from, int offset ); - -extern void SSE_MOVAPSRmStoR( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ); -extern void SSE_MOVAPSRtoRmS( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ); -extern void SSE_MOVAPSRtoRmOffset( x86IntRegType to, x86SSERegType from, int offset ); -extern void SSE_MOVAPSRmtoROffset( x86SSERegType to, x86IntRegType from, int offset ); -extern void SSE_MOVUPSRmStoR( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ); -extern void SSE_MOVUPSRtoRmS( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ); -extern void SSE_MOVUPSRtoRm( x86IntRegType to, x86IntRegType from ); -extern void SSE_MOVUPSRmtoR( x86IntRegType to, x86IntRegType from ); - -extern void SSE_MOVUPSRmtoROffset( x86SSERegType to, x86IntRegType from, int offset ); -extern void SSE_MOVUPSRtoRmOffset( x86SSERegType to, x86IntRegType from, int offset ); - -extern void SSE2_MOVDQARtoRmOffset( x86IntRegType to, x86SSERegType from, int offset ); -extern void SSE2_MOVDQARmtoROffset( x86SSERegType to, x86IntRegType from, int offset ); - -extern void SSE_RCPPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_RCPPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_RCPSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_RCPSS_M32_to_XMM( x86SSERegType to, uptr from ); - -extern void SSE_ORPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_ORPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_XORPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_XORPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_ANDPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_ANDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_ANDNPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_ANDNPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_ADDPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_ADDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_ADDSS_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_ADDSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_SUBPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_SUBPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_SUBSS_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_SUBSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_MULPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_MULPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_MULSS_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_MULSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_CMPEQSS_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_CMPEQSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_CMPLTSS_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_CMPLTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_CMPLESS_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_CMPLESS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_CMPUNORDSS_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_CMPUNORDSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_CMPNESS_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_CMPNESS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_CMPNLTSS_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_CMPNLTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_CMPNLESS_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_CMPNLESS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_CMPORDSS_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_CMPORDSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); - -extern void SSE_UCOMISS_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_UCOMISS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); - -extern void SSE_PMAXSW_MM_to_MM( x86MMXRegType to, x86MMXRegType from ); -extern void SSE_PMINSW_MM_to_MM( x86MMXRegType to, x86MMXRegType from ); -extern void SSE_CVTPI2PS_MM_to_XMM( x86SSERegType to, x86MMXRegType from ); -extern void SSE_CVTPS2PI_M64_to_MM( x86MMXRegType to, uptr from ); -extern void SSE_CVTPS2PI_XMM_to_MM( x86MMXRegType to, x86SSERegType from ); - -extern void SSE_CVTPI2PS_M64_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_CVTTSS2SI_M32_to_R32(x86IntRegType to, uptr from); -extern void SSE_CVTTSS2SI_XMM_to_R32(x86IntRegType to, x86SSERegType from); -extern void SSE_CVTSI2SS_M32_to_XMM(x86SSERegType to, uptr from); -extern void SSE_CVTSI2SS_R_to_XMM(x86SSERegType to, x86IntRegType from); - -extern void SSE2_CVTDQ2PS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_CVTDQ2PS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_CVTPS2DQ_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_CVTPS2DQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_CVTTPS2DQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); - -extern void SSE2_MAXPD_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_MAXPD_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_MAXPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_MAXPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_MAXSS_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_MAXSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_MINPD_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_MINPD_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_MINPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_MINPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_MINSS_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_MINSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_RSQRTPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_RSQRTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_RSQRTSS_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_RSQRTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_SQRTPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_SQRTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_SQRTSS_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_SQRTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_UNPCKLPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_UNPCKLPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_UNPCKHPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_UNPCKHPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_SHUFPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ); -extern void SSE_SHUFPS_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ); -extern void SSE_SHUFPS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset, u8 imm8 ); -extern void SSE_CMPEQPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_CMPEQPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_CMPLTPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_CMPLTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_CMPLEPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_CMPLEPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_CMPUNORDPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_CMPUNORDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_CMPNEPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_CMPNEPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_CMPNLTPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_CMPNLTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_CMPNLEPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_CMPNLEPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_CMPORDPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_CMPORDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_DIVPS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_DIVPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE_DIVSS_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSE_DIVSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -// VectorPath -extern void SSE2_PSHUFD_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ); -extern void SSE2_PSHUFD_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ); - -extern void SSE2_PSHUFLW_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ); -extern void SSE2_PSHUFLW_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ); -extern void SSE2_PSHUFHW_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ); -extern void SSE2_PSHUFHW_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ); - -extern void SSE_STMXCSR( uptr from ); -extern void SSE_LDMXCSR( uptr from ); - - -//********************* -// SSE 2 Instructions* -//********************* -extern void SSE2_MOVDQA_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE2_MOVDQA_XMM_to_M128( uptr to, x86SSERegType from); -extern void SSE2_MOVDQA_XMM_to_XMM( x86SSERegType to, x86SSERegType from); - -extern void SSE2_MOVDQU_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE2_MOVDQU_XMM_to_M128( uptr to, x86SSERegType from); -extern void SSE2_MOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from); - -extern void SSE2_PSRLW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PSRLW_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE2_PSRLW_I8_to_XMM(x86SSERegType to, u8 imm8); -extern void SSE2_PSRLD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PSRLD_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE2_PSRLD_I8_to_XMM(x86SSERegType to, u8 imm8); -extern void SSE2_PSRLQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PSRLQ_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE2_PSRLQ_I8_to_XMM(x86SSERegType to, u8 imm8); -extern void SSE2_PSRLDQ_I8_to_XMM(x86SSERegType to, u8 imm8); -extern void SSE2_PSRAW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PSRAW_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE2_PSRAW_I8_to_XMM(x86SSERegType to, u8 imm8); -extern void SSE2_PSRAD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PSRAD_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE2_PSRAD_I8_to_XMM(x86SSERegType to, u8 imm8); -extern void SSE2_PSLLW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PSLLW_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE2_PSLLW_I8_to_XMM(x86SSERegType to, u8 imm8); -extern void SSE2_PSLLD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PSLLD_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE2_PSLLD_I8_to_XMM(x86SSERegType to, u8 imm8); -extern void SSE2_PSLLQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PSLLQ_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE2_PSLLQ_I8_to_XMM(x86SSERegType to, u8 imm8); -extern void SSE2_PSLLDQ_I8_to_XMM(x86SSERegType to, u8 imm8); -extern void SSE2_PMAXSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_PMAXSW_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_PMAXUB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_PMAXUB_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_PMINSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_PMINSW_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_PMINUB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_PMINUB_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_PADDSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_PADDSB_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_PADDSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_PADDSW_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_PSUBSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_PSUBSB_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_PSUBSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_PSUBSW_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_PSUBUSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_PSUBUSB_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_PSUBUSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_PSUBUSW_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_PAND_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_PAND_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_PANDN_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_PANDN_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_PXOR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_PXOR_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_PADDW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); -extern void SSE2_PADDW_M128_to_XMM(x86SSERegType to, uptr from ); -extern void SSE2_PADDUSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_PADDUSB_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_PADDUSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_PADDUSW_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_PADDB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); -extern void SSE2_PADDB_M128_to_XMM(x86SSERegType to, uptr from ); -extern void SSE2_PADDD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); -extern void SSE2_PADDD_M128_to_XMM(x86SSERegType to, uptr from ); -extern void SSE2_PADDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); -extern void SSE2_PADDQ_M128_to_XMM(x86SSERegType to, uptr from ); -extern void SSE2_PMADDWD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); - -//**********************************************************************************/ -//PACKSSWB,PACKSSDW: Pack Saturate Signed Word -//********************************************************************************** -extern void SSE2_PACKSSWB_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PACKSSWB_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE2_PACKSSDW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PACKSSDW_M128_to_XMM(x86SSERegType to, uptr from); - -extern void SSE2_PACKUSWB_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PACKUSWB_M128_to_XMM(x86SSERegType to, uptr from); - -//**********************************************************************************/ -//PUNPCKHWD: Unpack 16bit high -//********************************************************************************** -extern void SSE2_PUNPCKLBW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PUNPCKLBW_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE2_PUNPCKHBW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PUNPCKHBW_M128_to_XMM(x86SSERegType to, uptr from); - -extern void SSE2_PUNPCKLWD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PUNPCKLWD_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE2_PUNPCKHWD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PUNPCKHWD_M128_to_XMM(x86SSERegType to, uptr from); - -extern void SSE2_PUNPCKLDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PUNPCKLDQ_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE2_PUNPCKHDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PUNPCKHDQ_M128_to_XMM(x86SSERegType to, uptr from); - -extern void SSE2_PUNPCKLQDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PUNPCKLQDQ_M128_to_XMM(x86SSERegType to, uptr from); - -extern void SSE2_PUNPCKHQDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PUNPCKHQDQ_M128_to_XMM(x86SSERegType to, uptr from); - -// mult by half words -extern void SSE2_PMULLW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PMULLW_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE2_PMULHW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PMULHW_M128_to_XMM(x86SSERegType to, uptr from); - -extern void SSE2_PMULUDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE2_PMULUDQ_M128_to_XMM(x86SSERegType to, uptr from); - - -//**********************************************************************************/ -//PMOVMSKB: Create 16bit mask from signs of 8bit integers -//********************************************************************************** -extern void SSE2_PMOVMSKB_XMM_to_R32(x86IntRegType to, x86SSERegType from); - -extern void SSE_MOVMSKPS_XMM_to_R32(x86IntRegType to, x86SSERegType from); -extern void SSE2_MOVMSKPD_XMM_to_R32(x86IntRegType to, x86SSERegType from); - -//**********************************************************************************/ -//PEXTRW,PINSRW: Packed Extract/Insert Word * -//********************************************************************************** -extern void SSE_PEXTRW_XMM_to_R32(x86IntRegType to, x86SSERegType from, u8 imm8 ); -extern void SSE_PINSRW_R32_to_XMM(x86SSERegType from, x86IntRegType to, u8 imm8 ); - - -//**********************************************************************************/ -//PSUBx: Subtract Packed Integers * -//********************************************************************************** -extern void SSE2_PSUBB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); -extern void SSE2_PSUBB_M128_to_XMM(x86SSERegType to, uptr from ); -extern void SSE2_PSUBW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); -extern void SSE2_PSUBW_M128_to_XMM(x86SSERegType to, uptr from ); -extern void SSE2_PSUBD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); -extern void SSE2_PSUBD_M128_to_XMM(x86SSERegType to, uptr from ); -extern void SSE2_PSUBQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); -extern void SSE2_PSUBQ_M128_to_XMM(x86SSERegType to, uptr from ); -/////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//PCMPxx: Compare Packed Integers * -//********************************************************************************** -extern void SSE2_PCMPGTB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); -extern void SSE2_PCMPGTB_M128_to_XMM(x86SSERegType to, uptr from ); -extern void SSE2_PCMPGTW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); -extern void SSE2_PCMPGTW_M128_to_XMM(x86SSERegType to, uptr from ); -extern void SSE2_PCMPGTD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); -extern void SSE2_PCMPGTD_M128_to_XMM(x86SSERegType to, uptr from ); -extern void SSE2_PCMPEQB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); -extern void SSE2_PCMPEQB_M128_to_XMM(x86SSERegType to, uptr from ); -extern void SSE2_PCMPEQW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); -extern void SSE2_PCMPEQW_M128_to_XMM(x86SSERegType to, uptr from ); -extern void SSE2_PCMPEQD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); -extern void SSE2_PCMPEQD_M128_to_XMM(x86SSERegType to, uptr from ); -//**********************************************************************************/ -//MOVD: Move Dword(32bit) to /from XMM reg * -//********************************************************************************** -extern void SSE2_MOVD_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2_MOVD_R_to_XMM( x86SSERegType to, x86IntRegType from ); -extern void SSE2_MOVD_Rm_to_XMM( x86SSERegType to, x86IntRegType from ); -extern void SSE2_MOVD_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ); -extern void SSE2_MOVD_XMM_to_M32( u32 to, x86SSERegType from ); -extern void SSE2_MOVD_XMM_to_R( x86IntRegType to, x86SSERegType from ); -extern void SSE2_MOVD_XMM_to_Rm( x86IntRegType to, x86SSERegType from ); -extern void SSE2_MOVD_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ); - -extern void SSE2_MOVQ_XMM_to_R( x86IntRegType to, x86SSERegType from ); -extern void SSE2_MOVQ_R_to_XMM( x86SSERegType to, x86IntRegType from ); - -//**********************************************************************************/ -//POR : SSE Bitwise OR * -//********************************************************************************** -extern void SSE2_POR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2_POR_M128_to_XMM( x86SSERegType to, uptr from ); - -extern void SSE3_HADDPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE3_HADDPS_M128_to_XMM(x86SSERegType to, uptr from); - -extern void SSE3_MOVSLDUP_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE3_MOVSLDUP_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE3_MOVSHDUP_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE3_MOVSHDUP_M128_to_XMM(x86SSERegType to, uptr from); - -// SSE4.1 - -#ifndef _MM_MK_INSERTPS_NDX -#define _MM_MK_INSERTPS_NDX(srcField, dstField, zeroMask) (((srcField)<<6) | ((dstField)<<4) | (zeroMask)) -#endif - -extern void SSE4_DPPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from, u8 imm8); -extern void SSE4_DPPS_M128_to_XMM(x86SSERegType to, uptr from, u8 imm8); -extern void SSE4_INSERTPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from, u8 imm8); -extern void SSE4_EXTRACTPS_XMM_to_R32(x86IntRegType to, x86SSERegType from, u8 imm8); -extern void SSE4_BLENDPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from, u8 imm8); -extern void SSE4_BLENDVPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE4_BLENDVPS_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE4_PMOVSXDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE4_PINSRD_R32_to_XMM(x86SSERegType to, x86IntRegType from, u8 imm8); -extern void SSE4_PMAXSD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE4_PMINSD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE4_PMAXUD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE4_PMINUD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSE4_PMAXSD_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE4_PMINSD_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE4_PMAXUD_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSE4_PMINUD_M128_to_XMM(x86SSERegType to, uptr from); - -//********************* -// SSE-X - uses both SSE,SSE2 code and tries to keep consistensies between the data -// Uses g_xmmtypes to infer the correct type. -//********************* -extern void SSEX_MOVDQA_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSEX_MOVDQA_XMM_to_M128( uptr to, x86SSERegType from ); -extern void SSEX_MOVDQA_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); - -extern void SSEX_MOVDQARmtoROffset( x86SSERegType to, x86IntRegType from, int offset ); -extern void SSEX_MOVDQARtoRmOffset( x86IntRegType to, x86SSERegType from, int offset ); - -extern void SSEX_MOVDQU_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSEX_MOVDQU_XMM_to_M128( uptr to, x86SSERegType from ); -extern void SSEX_MOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); - -extern void SSEX_MOVD_M32_to_XMM( x86SSERegType to, uptr from ); -extern void SSEX_MOVD_XMM_to_M32( u32 to, x86SSERegType from ); -extern void SSEX_MOVD_XMM_to_Rm( x86IntRegType to, x86SSERegType from ); -extern void SSEX_MOVD_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ); -extern void SSEX_MOVD_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ); - -extern void SSEX_POR_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSEX_POR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSEX_PXOR_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSEX_PXOR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSEX_PAND_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSEX_PAND_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSEX_PANDN_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSEX_PANDN_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); - -extern void SSEX_PUNPCKLDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSEX_PUNPCKLDQ_M128_to_XMM(x86SSERegType to, uptr from); -extern void SSEX_PUNPCKHDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); -extern void SSEX_PUNPCKHDQ_M128_to_XMM(x86SSERegType to, uptr from); - -extern void SSEX_MOVHLPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); - -//********************* -// 3DNOW instructions * -//********************* -extern void FEMMS( void ); -extern void PFCMPEQMtoR( x86IntRegType to, uptr from ); -extern void PFCMPGTMtoR( x86IntRegType to, uptr from ); -extern void PFCMPGEMtoR( x86IntRegType to, uptr from ); -extern void PFADDMtoR( x86IntRegType to, uptr from ); -extern void PFADDRtoR( x86IntRegType to, x86IntRegType from ); -extern void PFSUBMtoR( x86IntRegType to, uptr from ); -extern void PFSUBRtoR( x86IntRegType to, x86IntRegType from ); -extern void PFMULMtoR( x86IntRegType to, uptr from ); -extern void PFMULRtoR( x86IntRegType to, x86IntRegType from ); -extern void PFRCPMtoR( x86IntRegType to, uptr from ); -extern void PFRCPRtoR( x86IntRegType to, x86IntRegType from ); -extern void PFRCPIT1RtoR( x86IntRegType to, x86IntRegType from ); -extern void PFRCPIT2RtoR( x86IntRegType to, x86IntRegType from ); -extern void PFRSQRTRtoR( x86IntRegType to, x86IntRegType from ); -extern void PFRSQIT1RtoR( x86IntRegType to, x86IntRegType from ); -extern void PF2IDMtoR( x86IntRegType to, uptr from ); -extern void PI2FDMtoR( x86IntRegType to, uptr from ); -extern void PI2FDRtoR( x86IntRegType to, x86IntRegType from ); -extern void PFMAXMtoR( x86IntRegType to, uptr from ); -extern void PFMAXRtoR( x86IntRegType to, x86IntRegType from ); -extern void PFMINMtoR( x86IntRegType to, uptr from ); -extern void PFMINRtoR( x86IntRegType to, x86IntRegType from ); - -extern void SSE2EMU_MOVSD_XMM_to_XMM( x86SSERegType to, x86SSERegType from); -extern void SSE2EMU_MOVQ_M64_to_XMM( x86SSERegType to, uptr from); -extern void SSE2EMU_MOVQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from); -extern void SSE2EMU_MOVD_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ); -extern void SSE2EMU_MOVD_XMM_to_RmOffset(x86IntRegType to, x86SSERegType from, int offset ); - -extern void SSE2EMU_MOVDQ2Q_XMM_to_MM( x86MMXRegType to, x86SSERegType from); -extern void SSE2EMU_MOVQ2DQ_MM_to_XMM( x86SSERegType to, x86MMXRegType from); - -/* SSE2 emulated functions for SSE CPU's by kekko*/ - -extern void SSE2EMU_PSHUFD_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ); -extern void SSE2EMU_MOVD_XMM_to_R( x86IntRegType to, x86SSERegType from ); -extern void SSE2EMU_CVTPS2DQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); -extern void SSE2EMU_CVTDQ2PS_M128_to_XMM( x86SSERegType to, uptr from ); -extern void SSE2EMU_MOVD_XMM_to_M32( u32 to, x86SSERegType from ); -extern void SSE2EMU_MOVD_R_to_XMM( x86SSERegType to, x86IntRegType from ); - -//////////////////////////////////////////////////// -#ifdef _DEBUG -#define WRITECHECK() CheckX86Ptr() -#else -#define WRITECHECK() -#endif - -__forceinline void write8(u8 val ) { - *x86Ptr = (u8)val; - x86Ptr++; -} - -__forceinline void write16(u16 val ) -{ - *(u16*)x86Ptr = (u16)val; - x86Ptr += 2; -} - -__forceinline void write24(u32 val ) -{ - *(u8*)x86Ptr = (u8)(val & 0xff); - x86Ptr++; - *(u8*)x86Ptr = (u8)((val >> 8) & 0xff); - x86Ptr++; - *(u8*)x86Ptr = (u8)((val >> 16) & 0xff); - x86Ptr++; -} - -__forceinline void write32(u32 val ) -{ - *(u32*)x86Ptr = val; - x86Ptr += 4; -} - +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +/* + * ix86 definitions v0.6.2 + * Authors: linuzappz + * alexey silinov + * goldfinger + * shadow < shadow@pcsx2.net > + */ + +#ifndef __IX86_H__ +#define __IX86_H__ + +#include "PS2Etypes.h" // Basic types header + +#define XMMREGS 8 +#define X86REGS 8 + +#define MMXREGS 8 + +#define SIB 4 +#define SIBDISP 5 +#define DISP32 5 + +// general types +typedef int x86IntRegType; +#define EAX 0 +#define EBX 3 +#define ECX 1 +#define EDX 2 +#define ESI 6 +#define EDI 7 +#define EBP 5 +#define ESP 4 + +#define X86ARG1 EAX +#define X86ARG2 ECX +#define X86ARG3 EDX +#define X86ARG4 EBX + +#define MM0 0 +#define MM1 1 +#define MM2 2 +#define MM3 3 +#define MM4 4 +#define MM5 5 +#define MM6 6 +#define MM7 7 + +typedef int x86MMXRegType; + +#define XMM0 0 +#define XMM1 1 +#define XMM2 2 +#define XMM3 3 +#define XMM4 4 +#define XMM5 5 +#define XMM6 6 +#define XMM7 7 +#define XMM8 8 +#define XMM9 9 +#define XMM10 10 +#define XMM11 11 +#define XMM12 12 +#define XMM13 13 +#define XMM14 14 +#define XMM15 15 + +typedef int x86SSERegType; + +enum XMMSSEType +{ + XMMT_INT = 0, // integer (sse2 only) + XMMT_FPS = 1, // floating point + //XMMT_FPD = 3, // double +}; + +extern XMMSSEType g_xmmtypes[XMMREGS]; + +extern void cpudetectInit( void );//this is all that needs to be called and will fill up the below structs + +typedef struct CAPABILITIES CAPABILITIES; +//cpu capabilities structure +struct CAPABILITIES { + u32 hasFloatingPointUnit; + u32 hasVirtual8086ModeEnhancements; + u32 hasDebuggingExtensions; + u32 hasPageSizeExtensions; + u32 hasTimeStampCounter; + u32 hasModelSpecificRegisters; + u32 hasPhysicalAddressExtension; + u32 hasCOMPXCHG8BInstruction; + u32 hasAdvancedProgrammableInterruptController; + u32 hasSEPFastSystemCall; + u32 hasMemoryTypeRangeRegisters; + u32 hasPTEGlobalFlag; + u32 hasMachineCheckArchitecture; + u32 hasConditionalMoveAndCompareInstructions; + u32 hasFGPageAttributeTable; + u32 has36bitPageSizeExtension; + u32 hasProcessorSerialNumber; + u32 hasCFLUSHInstruction; + u32 hasDebugStore; + u32 hasACPIThermalMonitorAndClockControl; + u32 hasMultimediaExtensions; + u32 hasFastStreamingSIMDExtensionsSaveRestore; + u32 hasStreamingSIMDExtensions; + u32 hasStreamingSIMD2Extensions; + u32 hasSelfSnoop; + u32 hasMultiThreading; // is TRUE for both mutli-core and Hyperthreaded CPUs. + u32 hasThermalMonitor; + u32 hasIntel64BitArchitecture; + u32 hasStreamingSIMD3Extensions; + u32 hasStreamingSIMD4Extensions; + + // AMD-specific CPU Features + u32 hasMultimediaExtensionsExt; + u32 hasAMD64BitArchitecture; + u32 has3DNOWInstructionExtensionsExt; + u32 has3DNOWInstructionExtensions; +}; + +extern CAPABILITIES cpucaps; + +struct CPUINFO{ + + u32 x86Family; // Processor Family + u32 x86Model; // Processor Model + u32 x86PType; // Processor Type + u32 x86StepID; // Stepping ID + u32 x86Flags; // Feature Flags + u32 x86Flags2; // More Feature Flags + u32 x86EFlags; // Extended Feature Flags + + u32 PhysicalCores; + u32 LogicalCores; + + char x86ID[16]; // Vendor ID //the vendor creator (in %s) + char x86Type[20]; //cpu type in char format //the cpu type (in %s) + char x86Fam[50]; // family in char format //the original cpu name string (in %s) + u32 cpuspeed; // speed of cpu //this will give cpu speed (in %d) +}; + +extern CPUINFO cpuinfo; + +extern u8 *x86Ptr; +extern u8 *j8Ptr[32]; +extern u32 *j32Ptr[32]; + +#define MEMADDR(addr, oplen) (addr) + +#define Rex(w,r,x,b) assert(0); +#define RexR(w, reg) if( w||(reg)>=8 ) assert(0); +#define RexB(w, base) if( w||(base)>=8 ) assert(0); +#define RexRB(w, reg, base) if( w||(reg) >= 8 || (base)>=8 ) assert(0); +#define RexRXB(w, reg, index, base) if( w||(reg) >= 8 || (index) >= 8 || (base) >= 8 ) assert(0); + +// perf counters +#ifdef PCSX2_DEVBUILD +extern void StartPerfCounter(); +extern void StopPerfCounter(); +#else +#define StartPerfCounter() +#define StopPerfCounter() +#endif + + +extern __forceinline void write8( u8 val ); +extern __forceinline void write16( u16 val ); +extern __forceinline void write32( u32 val ); +extern void write64( u64 val ); + + +extern void x86SetPtr( u8 *ptr ); +extern void x86Shutdown( void ); + +extern void x86SetJ8( u8 *j8 ); +extern void x86SetJ8A( u8 *j8 ); +extern void x86SetJ16( u16 *j16 ); +extern void x86SetJ16A( u16 *j16 ); +extern void x86SetJ32( u32 *j32 ); +extern void x86SetJ32A( u32 *j32 ); + +extern void x86Align( int bytes ); +extern void x86AlignExecutable( int align ); + +u64 GetCPUTick( void ); + +// General Helper functions +extern void ModRM( int mod, int reg, int rm ); +extern void SibSB( int ss, int index, int base ); +extern void SET8R( int cc, int to ); +extern u8* J8Rel( int cc, int to ); +extern u32* J32Rel( int cc, u32 to ); +extern void CMOV32RtoR( int cc, int to, int from ); +extern void CMOV32MtoR( int cc, int to, uptr from ); + +//****************** +// IX86 intructions +//****************** + +// +// * scale values: +// * 0 - *1 +// * 1 - *2 +// * 2 - *4 +// * 3 - *8 +// + +extern void STC( void ); +extern void CLC( void ); +extern void NOP( void ); + +//////////////////////////////////// +// mov instructions // +//////////////////////////////////// + +// mov r64 to r64 +extern void MOV64RtoR( x86IntRegType to, x86IntRegType from ); +// mov r64 to m64 +extern void MOV64RtoM( uptr to, x86IntRegType from ); +// mov m64 to r64 +extern void MOV64MtoR( x86IntRegType to, uptr from ); +// mov sign ext imm32 to m64 +extern void MOV64I32toM( uptr to, u32 from ); +// mov sign ext imm32 to r64 +extern void MOV64I32toR( x86IntRegType to, s32 from); +// mov imm64 to r64 +extern void MOV64ItoR( x86IntRegType to, u64 from); +// mov imm64 to [r64+off] +extern void MOV64ItoRmOffset( x86IntRegType to, u32 from, int offset); +// mov [r64+offset] to r64 +extern void MOV64RmOffsettoR( x86IntRegType to, x86IntRegType from, int offset ); +// mov [r64][r64*scale] to r64 +extern void MOV64RmStoR( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale); +// mov r64 to [r64+offset] +extern void MOV64RtoRmOffset( x86IntRegType to, x86IntRegType from, int offset ); +// mov r64 to [r64][r64*scale] +extern void MOV64RtoRmS( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale); + +// mov r32 to r32 +extern void MOV32RtoR( x86IntRegType to, x86IntRegType from ); +// mov r32 to m32 +extern void MOV32RtoM( uptr to, x86IntRegType from ); +// mov m32 to r32 +extern void MOV32MtoR( x86IntRegType to, uptr from ); +// mov [r32] to r32 +extern void MOV32RmtoR( x86IntRegType to, x86IntRegType from ); +extern void MOV32RmtoROffset( x86IntRegType to, x86IntRegType from, int offset ); +// mov [r32][r32< subtract ST(0) from ST(1), store in ST(1) and POP stack +extern void FSUBP( void ); +// fmul ST(src) to fpu reg stack ST(0) +extern void FMUL32Rto0( x86IntRegType src ); +// fmul ST(0) to fpu reg stack ST(src) +extern void FMUL320toR( x86IntRegType src ); +// fdiv ST(src) to fpu reg stack ST(0) +extern void FDIV32Rto0( x86IntRegType src ); +// fdiv ST(0) to fpu reg stack ST(src) +extern void FDIV320toR( x86IntRegType src ); +// fdiv ST(0) to fpu reg stack ST(src), pop stack, store in ST(src) +extern void FDIV320toRP( x86IntRegType src ); + +// fadd m32 to fpu reg stack +extern void FADD32( u32 from ); +// fsub m32 to fpu reg stack +extern void FSUB32( u32 from ); +// fmul m32 to fpu reg stack +extern void FMUL32( u32 from ); +// fdiv m32 to fpu reg stack +extern void FDIV32( u32 from ); +// fcomi st, st( i) +extern void FCOMI( x86IntRegType src ); +// fcomip st, st( i) +extern void FCOMIP( x86IntRegType src ); +// fucomi st, st( i) +extern void FUCOMI( x86IntRegType src ); +// fucomip st, st( i) +extern void FUCOMIP( x86IntRegType src ); +// fcom m32 to fpu reg stack +extern void FCOM32( u32 from ); +// fabs fpu reg stack +extern void FABS( void ); +// fsqrt fpu reg stack +extern void FSQRT( void ); +// ftan fpu reg stack +extern void FPATAN( void ); +// fsin fpu reg stack +extern void FSIN( void ); +// fchs fpu reg stack +extern void FCHS( void ); + +// fcmovb fpu reg to fpu reg stack +extern void FCMOVB32( x86IntRegType from ); +// fcmove fpu reg to fpu reg stack +extern void FCMOVE32( x86IntRegType from ); +// fcmovbe fpu reg to fpu reg stack +extern void FCMOVBE32( x86IntRegType from ); +// fcmovu fpu reg to fpu reg stack +extern void FCMOVU32( x86IntRegType from ); +// fcmovnb fpu reg to fpu reg stack +extern void FCMOVNB32( x86IntRegType from ); +// fcmovne fpu reg to fpu reg stack +extern void FCMOVNE32( x86IntRegType from ); +// fcmovnbe fpu reg to fpu reg stack +extern void FCMOVNBE32( x86IntRegType from ); +// fcmovnu fpu reg to fpu reg stack +extern void FCMOVNU32( x86IntRegType from ); +extern void FCOMP32( u32 from ); +extern void FNSTSWtoAX( void ); + +#define MMXONLY(code) code + +//****************** +// MMX instructions +//****************** + +// r64 = mm + +// movq m64 to r64 +extern void MOVQMtoR( x86MMXRegType to, uptr from ); +// movq r64 to m64 +extern void MOVQRtoM( uptr to, x86MMXRegType from ); + +// pand r64 to r64 +extern void PANDRtoR( x86MMXRegType to, x86MMXRegType from ); +extern void PANDNRtoR( x86MMXRegType to, x86MMXRegType from ); +// pand m64 to r64 ; +extern void PANDMtoR( x86MMXRegType to, uptr from ); +// pandn r64 to r64 +extern void PANDNRtoR( x86MMXRegType to, x86MMXRegType from ); +// pandn r64 to r64 +extern void PANDNMtoR( x86MMXRegType to, uptr from ); +// por r64 to r64 +extern void PORRtoR( x86MMXRegType to, x86MMXRegType from ); +// por m64 to r64 +extern void PORMtoR( x86MMXRegType to, uptr from ); +// pxor r64 to r64 +extern void PXORRtoR( x86MMXRegType to, x86MMXRegType from ); +// pxor m64 to r64 +extern void PXORMtoR( x86MMXRegType to, uptr from ); + +// psllq r64 to r64 +extern void PSLLQRtoR( x86MMXRegType to, x86MMXRegType from ); +// psllq m64 to r64 +extern void PSLLQMtoR( x86MMXRegType to, uptr from ); +// psllq imm8 to r64 +extern void PSLLQItoR( x86MMXRegType to, u8 from ); +// psrlq r64 to r64 +extern void PSRLQRtoR( x86MMXRegType to, x86MMXRegType from ); +// psrlq m64 to r64 +extern void PSRLQMtoR( x86MMXRegType to, uptr from ); +// psrlq imm8 to r64 +extern void PSRLQItoR( x86MMXRegType to, u8 from ); + +// paddusb r64 to r64 +extern void PADDUSBRtoR( x86MMXRegType to, x86MMXRegType from ); +// paddusb m64 to r64 +extern void PADDUSBMtoR( x86MMXRegType to, uptr from ); +// paddusw r64 to r64 +extern void PADDUSWRtoR( x86MMXRegType to, x86MMXRegType from ); +// paddusw m64 to r64 +extern void PADDUSWMtoR( x86MMXRegType to, uptr from ); + +// paddb r64 to r64 +extern void PADDBRtoR( x86MMXRegType to, x86MMXRegType from ); +// paddb m64 to r64 +extern void PADDBMtoR( x86MMXRegType to, uptr from ); +// paddw r64 to r64 +extern void PADDWRtoR( x86MMXRegType to, x86MMXRegType from ); +// paddw m64 to r64 +extern void PADDWMtoR( x86MMXRegType to, uptr from ); +// paddd r64 to r64 +extern void PADDDRtoR( x86MMXRegType to, x86MMXRegType from ); +// paddd m64 to r64 +extern void PADDDMtoR( x86MMXRegType to, uptr from ); +extern void PADDSBRtoR( x86MMXRegType to, x86MMXRegType from ); +extern void PADDSWRtoR( x86MMXRegType to, x86MMXRegType from ); + +// paddq m64 to r64 (sse2 only?) +extern void PADDQMtoR( x86MMXRegType to, uptr from ); +// paddq r64 to r64 (sse2 only?) +extern void PADDQRtoR( x86MMXRegType to, x86MMXRegType from ); + +extern void PSUBSBRtoR( x86MMXRegType to, x86MMXRegType from ); +extern void PSUBSWRtoR( x86MMXRegType to, x86MMXRegType from ); + +extern void PSUBBRtoR( x86MMXRegType to, x86MMXRegType from ); +extern void PSUBWRtoR( x86MMXRegType to, x86MMXRegType from ); +extern void PSUBDRtoR( x86MMXRegType to, x86MMXRegType from ); +extern void PSUBDMtoR( x86MMXRegType to, uptr from ); + +// psubq m64 to r64 (sse2 only?) +extern void PSUBQMtoR( x86MMXRegType to, uptr from ); +// psubq r64 to r64 (sse2 only?) +extern void PSUBQRtoR( x86MMXRegType to, x86MMXRegType from ); + +// pmuludq m64 to r64 (sse2 only?) +extern void PMULUDQMtoR( x86MMXRegType to, uptr from ); +// pmuludq r64 to r64 (sse2 only?) +extern void PMULUDQRtoR( x86MMXRegType to, x86MMXRegType from ); + +extern void PCMPEQBRtoR( x86MMXRegType to, x86MMXRegType from ); +extern void PCMPEQWRtoR( x86MMXRegType to, x86MMXRegType from ); +extern void PCMPEQDRtoR( x86MMXRegType to, x86MMXRegType from ); +extern void PCMPEQDMtoR( x86MMXRegType to, uptr from ); +extern void PCMPGTBRtoR( x86MMXRegType to, x86MMXRegType from ); +extern void PCMPGTWRtoR( x86MMXRegType to, x86MMXRegType from ); +extern void PCMPGTDRtoR( x86MMXRegType to, x86MMXRegType from ); +extern void PCMPGTDMtoR( x86MMXRegType to, uptr from ); +extern void PSRLWItoR( x86MMXRegType to, u8 from ); +extern void PSRLDItoR( x86MMXRegType to, u8 from ); +extern void PSRLDRtoR( x86MMXRegType to, x86MMXRegType from ); +extern void PSLLWItoR( x86MMXRegType to, u8 from ); +extern void PSLLDItoR( x86MMXRegType to, u8 from ); +extern void PSLLDRtoR( x86MMXRegType to, x86MMXRegType from ); +extern void PSRAWItoR( x86MMXRegType to, u8 from ); +extern void PSRADItoR( x86MMXRegType to, u8 from ); +extern void PSRADRtoR( x86MMXRegType to, x86MMXRegType from ); +extern void PUNPCKLDQRtoR( x86MMXRegType to, x86MMXRegType from ); +extern void PUNPCKLDQMtoR( x86MMXRegType to, uptr from ); +extern void PUNPCKHDQRtoR( x86MMXRegType to, x86MMXRegType from ); +extern void PUNPCKHDQMtoR( x86MMXRegType to, uptr from ); +extern void MOVQ64ItoR( x86MMXRegType reg, u64 i ); //Prototype.Todo add all consts to end of block.not after jr $+8 +extern void MOVQRtoR( x86MMXRegType to, x86MMXRegType from ); +extern void MOVQRmtoROffset( x86MMXRegType to, x86IntRegType from, u32 offset ); +extern void MOVQRtoRmOffset( x86IntRegType to, x86MMXRegType from, u32 offset ); +extern void MOVDMtoMMX( x86MMXRegType to, uptr from ); +extern void MOVDMMXtoM( uptr to, x86MMXRegType from ); +extern void MOVD32RtoMMX( x86MMXRegType to, x86IntRegType from ); +extern void MOVD32RmtoMMX( x86MMXRegType to, x86IntRegType from ); +extern void MOVD32RmOffsettoMMX( x86MMXRegType to, x86IntRegType from, u32 offset ); +extern void MOVD32MMXtoR( x86IntRegType to, x86MMXRegType from ); +extern void MOVD32MMXtoRm( x86IntRegType to, x86MMXRegType from ); +extern void MOVD32MMXtoRmOffset( x86IntRegType to, x86MMXRegType from, u32 offset ); +extern void PINSRWRtoMMX( x86MMXRegType to, x86SSERegType from, u8 imm8 ); +extern void PSHUFWRtoR(x86MMXRegType to, x86MMXRegType from, u8 imm8); +extern void PSHUFWMtoR(x86MMXRegType to, uptr from, u8 imm8); +extern void MASKMOVQRtoR(x86MMXRegType to, x86MMXRegType from); + +// emms +extern void EMMS( void ); + +//**********************************************************************************/ +//PACKSSWB,PACKSSDW: Pack Saturate Signed Word 64bits +//********************************************************************************** +extern void PACKSSWBMMXtoMMX(x86MMXRegType to, x86MMXRegType from); +extern void PACKSSDWMMXtoMMX(x86MMXRegType to, x86MMXRegType from); + +extern void PMOVMSKBMMXtoR(x86IntRegType to, x86MMXRegType from); + +extern void SSE2_MOVDQ2Q_XMM_to_MM( x86MMXRegType to, x86SSERegType from); +extern void SSE2_MOVQ2DQ_MM_to_XMM( x86SSERegType to, x86MMXRegType from); + +//********************* +// SSE instructions * +//********************* +extern void SSE_MOVAPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_MOVAPS_XMM_to_M128( uptr to, x86SSERegType from ); +extern void SSE_MOVAPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +extern void SSE_MOVUPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_MOVUPS_XMM_to_M128( uptr to, x86SSERegType from ); + +extern void SSE_MOVSS_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_MOVSS_XMM_to_M32( u32 to, x86SSERegType from ); +extern void SSE_MOVSS_XMM_to_Rm( x86IntRegType to, x86SSERegType from ); +extern void SSE_MOVSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_MOVSS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ); +extern void SSE_MOVSS_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ); + +extern void SSE2_MOVSD_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +extern void SSE2_MOVQ_M64_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_MOVQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_MOVQ_XMM_to_M64( u32 to, x86SSERegType from ); + +extern void SSE_MASKMOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +extern void SSE_MOVLPS_M64_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_MOVLPS_XMM_to_M64( u32 to, x86SSERegType from ); +extern void SSE_MOVLPS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ); +extern void SSE_MOVLPS_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ); + +extern void SSE_MOVHPS_M64_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_MOVHPS_XMM_to_M64( u32 to, x86SSERegType from ); +extern void SSE_MOVHPS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ); +extern void SSE_MOVHPS_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ); + +extern void SSE_MOVLHPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_MOVHLPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_MOVLPSRmtoR( x86SSERegType to, x86IntRegType from ); +extern void SSE_MOVLPSRmtoROffset( x86SSERegType to, x86IntRegType from, int offset ); +extern void SSE_MOVLPSRtoRm( x86SSERegType to, x86IntRegType from ); +extern void SSE_MOVLPSRtoRmOffset( x86SSERegType to, x86IntRegType from, int offset ); + +extern void SSE_MOVAPSRmStoR( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ); +extern void SSE_MOVAPSRtoRmS( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ); +extern void SSE_MOVAPSRtoRmOffset( x86IntRegType to, x86SSERegType from, int offset ); +extern void SSE_MOVAPSRmtoROffset( x86SSERegType to, x86IntRegType from, int offset ); +extern void SSE_MOVUPSRmStoR( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ); +extern void SSE_MOVUPSRtoRmS( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ); +extern void SSE_MOVUPSRtoRm( x86IntRegType to, x86IntRegType from ); +extern void SSE_MOVUPSRmtoR( x86IntRegType to, x86IntRegType from ); + +extern void SSE_MOVUPSRmtoROffset( x86SSERegType to, x86IntRegType from, int offset ); +extern void SSE_MOVUPSRtoRmOffset( x86SSERegType to, x86IntRegType from, int offset ); + +extern void SSE2_MOVDQARtoRmOffset( x86IntRegType to, x86SSERegType from, int offset ); +extern void SSE2_MOVDQARmtoROffset( x86SSERegType to, x86IntRegType from, int offset ); + +extern void SSE_RCPPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_RCPPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_RCPSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_RCPSS_M32_to_XMM( x86SSERegType to, uptr from ); + +extern void SSE_ORPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_ORPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_XORPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_XORPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_ANDPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_ANDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_ANDNPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_ANDNPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_ADDPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_ADDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_ADDSS_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_ADDSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_SUBPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_SUBPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_SUBSS_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_SUBSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_MULPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_MULPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_MULSS_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_MULSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_CMPEQSS_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_CMPEQSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_CMPLTSS_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_CMPLTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_CMPLESS_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_CMPLESS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_CMPUNORDSS_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_CMPUNORDSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_CMPNESS_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_CMPNESS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_CMPNLTSS_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_CMPNLTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_CMPNLESS_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_CMPNLESS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_CMPORDSS_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_CMPORDSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +extern void SSE_UCOMISS_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_UCOMISS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +extern void SSE_PMAXSW_MM_to_MM( x86MMXRegType to, x86MMXRegType from ); +extern void SSE_PMINSW_MM_to_MM( x86MMXRegType to, x86MMXRegType from ); +extern void SSE_CVTPI2PS_MM_to_XMM( x86SSERegType to, x86MMXRegType from ); +extern void SSE_CVTPS2PI_M64_to_MM( x86MMXRegType to, uptr from ); +extern void SSE_CVTPS2PI_XMM_to_MM( x86MMXRegType to, x86SSERegType from ); + +extern void SSE_CVTPI2PS_M64_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_CVTTSS2SI_M32_to_R32(x86IntRegType to, uptr from); +extern void SSE_CVTTSS2SI_XMM_to_R32(x86IntRegType to, x86SSERegType from); +extern void SSE_CVTSI2SS_M32_to_XMM(x86SSERegType to, uptr from); +extern void SSE_CVTSI2SS_R_to_XMM(x86SSERegType to, x86IntRegType from); + +extern void SSE2_CVTDQ2PS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_CVTDQ2PS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_CVTPS2DQ_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_CVTPS2DQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_CVTTPS2DQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +extern void SSE2_MAXPD_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_MAXPD_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_MAXPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_MAXPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_MAXSS_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_MAXSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_MINPD_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_MINPD_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_MINPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_MINPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_MINSS_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_MINSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_RSQRTPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_RSQRTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_RSQRTSS_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_RSQRTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_SQRTPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_SQRTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_SQRTSS_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_SQRTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_UNPCKLPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_UNPCKLPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_UNPCKHPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_UNPCKHPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_SHUFPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ); +extern void SSE_SHUFPS_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ); +extern void SSE_SHUFPS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset, u8 imm8 ); +extern void SSE_CMPEQPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_CMPEQPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_CMPLTPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_CMPLTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_CMPLEPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_CMPLEPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_CMPUNORDPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_CMPUNORDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_CMPNEPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_CMPNEPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_CMPNLTPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_CMPNLTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_CMPNLEPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_CMPNLEPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_CMPORDPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_CMPORDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_DIVPS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_DIVPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE_DIVSS_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSE_DIVSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +// VectorPath +extern void SSE2_PSHUFD_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ); +extern void SSE2_PSHUFD_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ); + +extern void SSE2_PSHUFLW_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ); +extern void SSE2_PSHUFLW_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ); +extern void SSE2_PSHUFHW_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ); +extern void SSE2_PSHUFHW_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ); + +extern void SSE_STMXCSR( uptr from ); +extern void SSE_LDMXCSR( uptr from ); + + +//********************* +// SSE 2 Instructions* +//********************* +extern void SSE2_MOVDQA_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE2_MOVDQA_XMM_to_M128( uptr to, x86SSERegType from); +extern void SSE2_MOVDQA_XMM_to_XMM( x86SSERegType to, x86SSERegType from); + +extern void SSE2_MOVDQU_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE2_MOVDQU_XMM_to_M128( uptr to, x86SSERegType from); +extern void SSE2_MOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from); + +extern void SSE2_PSRLW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PSRLW_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE2_PSRLW_I8_to_XMM(x86SSERegType to, u8 imm8); +extern void SSE2_PSRLD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PSRLD_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE2_PSRLD_I8_to_XMM(x86SSERegType to, u8 imm8); +extern void SSE2_PSRLQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PSRLQ_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE2_PSRLQ_I8_to_XMM(x86SSERegType to, u8 imm8); +extern void SSE2_PSRLDQ_I8_to_XMM(x86SSERegType to, u8 imm8); +extern void SSE2_PSRAW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PSRAW_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE2_PSRAW_I8_to_XMM(x86SSERegType to, u8 imm8); +extern void SSE2_PSRAD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PSRAD_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE2_PSRAD_I8_to_XMM(x86SSERegType to, u8 imm8); +extern void SSE2_PSLLW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PSLLW_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE2_PSLLW_I8_to_XMM(x86SSERegType to, u8 imm8); +extern void SSE2_PSLLD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PSLLD_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE2_PSLLD_I8_to_XMM(x86SSERegType to, u8 imm8); +extern void SSE2_PSLLQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PSLLQ_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE2_PSLLQ_I8_to_XMM(x86SSERegType to, u8 imm8); +extern void SSE2_PSLLDQ_I8_to_XMM(x86SSERegType to, u8 imm8); +extern void SSE2_PMAXSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_PMAXSW_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_PMAXUB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_PMAXUB_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_PMINSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_PMINSW_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_PMINUB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_PMINUB_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_PADDSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_PADDSB_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_PADDSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_PADDSW_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_PSUBSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_PSUBSB_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_PSUBSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_PSUBSW_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_PSUBUSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_PSUBUSB_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_PSUBUSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_PSUBUSW_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_PAND_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_PAND_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_PANDN_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_PANDN_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_PXOR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_PXOR_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_PADDW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +extern void SSE2_PADDW_M128_to_XMM(x86SSERegType to, uptr from ); +extern void SSE2_PADDUSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_PADDUSB_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_PADDUSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_PADDUSW_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_PADDB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +extern void SSE2_PADDB_M128_to_XMM(x86SSERegType to, uptr from ); +extern void SSE2_PADDD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +extern void SSE2_PADDD_M128_to_XMM(x86SSERegType to, uptr from ); +extern void SSE2_PADDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +extern void SSE2_PADDQ_M128_to_XMM(x86SSERegType to, uptr from ); +extern void SSE2_PMADDWD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); + +//**********************************************************************************/ +//PACKSSWB,PACKSSDW: Pack Saturate Signed Word +//********************************************************************************** +extern void SSE2_PACKSSWB_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PACKSSWB_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE2_PACKSSDW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PACKSSDW_M128_to_XMM(x86SSERegType to, uptr from); + +extern void SSE2_PACKUSWB_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PACKUSWB_M128_to_XMM(x86SSERegType to, uptr from); + +//**********************************************************************************/ +//PUNPCKHWD: Unpack 16bit high +//********************************************************************************** +extern void SSE2_PUNPCKLBW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PUNPCKLBW_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE2_PUNPCKHBW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PUNPCKHBW_M128_to_XMM(x86SSERegType to, uptr from); + +extern void SSE2_PUNPCKLWD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PUNPCKLWD_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE2_PUNPCKHWD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PUNPCKHWD_M128_to_XMM(x86SSERegType to, uptr from); + +extern void SSE2_PUNPCKLDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PUNPCKLDQ_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE2_PUNPCKHDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PUNPCKHDQ_M128_to_XMM(x86SSERegType to, uptr from); + +extern void SSE2_PUNPCKLQDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PUNPCKLQDQ_M128_to_XMM(x86SSERegType to, uptr from); + +extern void SSE2_PUNPCKHQDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PUNPCKHQDQ_M128_to_XMM(x86SSERegType to, uptr from); + +// mult by half words +extern void SSE2_PMULLW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PMULLW_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE2_PMULHW_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PMULHW_M128_to_XMM(x86SSERegType to, uptr from); + +extern void SSE2_PMULUDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE2_PMULUDQ_M128_to_XMM(x86SSERegType to, uptr from); + + +//**********************************************************************************/ +//PMOVMSKB: Create 16bit mask from signs of 8bit integers +//********************************************************************************** +extern void SSE2_PMOVMSKB_XMM_to_R32(x86IntRegType to, x86SSERegType from); + +extern void SSE_MOVMSKPS_XMM_to_R32(x86IntRegType to, x86SSERegType from); +extern void SSE2_MOVMSKPD_XMM_to_R32(x86IntRegType to, x86SSERegType from); + +//**********************************************************************************/ +//PEXTRW,PINSRW: Packed Extract/Insert Word * +//********************************************************************************** +extern void SSE_PEXTRW_XMM_to_R32(x86IntRegType to, x86SSERegType from, u8 imm8 ); +extern void SSE_PINSRW_R32_to_XMM(x86SSERegType from, x86IntRegType to, u8 imm8 ); + + +//**********************************************************************************/ +//PSUBx: Subtract Packed Integers * +//********************************************************************************** +extern void SSE2_PSUBB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +extern void SSE2_PSUBB_M128_to_XMM(x86SSERegType to, uptr from ); +extern void SSE2_PSUBW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +extern void SSE2_PSUBW_M128_to_XMM(x86SSERegType to, uptr from ); +extern void SSE2_PSUBD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +extern void SSE2_PSUBD_M128_to_XMM(x86SSERegType to, uptr from ); +extern void SSE2_PSUBQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +extern void SSE2_PSUBQ_M128_to_XMM(x86SSERegType to, uptr from ); +/////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//PCMPxx: Compare Packed Integers * +//********************************************************************************** +extern void SSE2_PCMPGTB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +extern void SSE2_PCMPGTB_M128_to_XMM(x86SSERegType to, uptr from ); +extern void SSE2_PCMPGTW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +extern void SSE2_PCMPGTW_M128_to_XMM(x86SSERegType to, uptr from ); +extern void SSE2_PCMPGTD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +extern void SSE2_PCMPGTD_M128_to_XMM(x86SSERegType to, uptr from ); +extern void SSE2_PCMPEQB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +extern void SSE2_PCMPEQB_M128_to_XMM(x86SSERegType to, uptr from ); +extern void SSE2_PCMPEQW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +extern void SSE2_PCMPEQW_M128_to_XMM(x86SSERegType to, uptr from ); +extern void SSE2_PCMPEQD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ); +extern void SSE2_PCMPEQD_M128_to_XMM(x86SSERegType to, uptr from ); +//**********************************************************************************/ +//MOVD: Move Dword(32bit) to /from XMM reg * +//********************************************************************************** +extern void SSE2_MOVD_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2_MOVD_R_to_XMM( x86SSERegType to, x86IntRegType from ); +extern void SSE2_MOVD_Rm_to_XMM( x86SSERegType to, x86IntRegType from ); +extern void SSE2_MOVD_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ); +extern void SSE2_MOVD_XMM_to_M32( u32 to, x86SSERegType from ); +extern void SSE2_MOVD_XMM_to_R( x86IntRegType to, x86SSERegType from ); +extern void SSE2_MOVD_XMM_to_Rm( x86IntRegType to, x86SSERegType from ); +extern void SSE2_MOVD_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ); + +extern void SSE2_MOVQ_XMM_to_R( x86IntRegType to, x86SSERegType from ); +extern void SSE2_MOVQ_R_to_XMM( x86SSERegType to, x86IntRegType from ); + +//**********************************************************************************/ +//POR : SSE Bitwise OR * +//********************************************************************************** +extern void SSE2_POR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2_POR_M128_to_XMM( x86SSERegType to, uptr from ); + +extern void SSE3_HADDPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE3_HADDPS_M128_to_XMM(x86SSERegType to, uptr from); + +extern void SSE3_MOVSLDUP_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE3_MOVSLDUP_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE3_MOVSHDUP_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE3_MOVSHDUP_M128_to_XMM(x86SSERegType to, uptr from); + +// SSE4.1 + +#ifndef _MM_MK_INSERTPS_NDX +#define _MM_MK_INSERTPS_NDX(srcField, dstField, zeroMask) (((srcField)<<6) | ((dstField)<<4) | (zeroMask)) +#endif + +extern void SSE4_DPPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from, u8 imm8); +extern void SSE4_DPPS_M128_to_XMM(x86SSERegType to, uptr from, u8 imm8); +extern void SSE4_INSERTPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from, u8 imm8); +extern void SSE4_EXTRACTPS_XMM_to_R32(x86IntRegType to, x86SSERegType from, u8 imm8); +extern void SSE4_BLENDPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from, u8 imm8); +extern void SSE4_BLENDVPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE4_BLENDVPS_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE4_PMOVSXDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE4_PINSRD_R32_to_XMM(x86SSERegType to, x86IntRegType from, u8 imm8); +extern void SSE4_PMAXSD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE4_PMINSD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE4_PMAXUD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE4_PMINUD_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSE4_PMAXSD_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE4_PMINSD_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE4_PMAXUD_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSE4_PMINUD_M128_to_XMM(x86SSERegType to, uptr from); + +//********************* +// SSE-X - uses both SSE,SSE2 code and tries to keep consistensies between the data +// Uses g_xmmtypes to infer the correct type. +//********************* +extern void SSEX_MOVDQA_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSEX_MOVDQA_XMM_to_M128( uptr to, x86SSERegType from ); +extern void SSEX_MOVDQA_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +extern void SSEX_MOVDQARmtoROffset( x86SSERegType to, x86IntRegType from, int offset ); +extern void SSEX_MOVDQARtoRmOffset( x86IntRegType to, x86SSERegType from, int offset ); + +extern void SSEX_MOVDQU_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSEX_MOVDQU_XMM_to_M128( uptr to, x86SSERegType from ); +extern void SSEX_MOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +extern void SSEX_MOVD_M32_to_XMM( x86SSERegType to, uptr from ); +extern void SSEX_MOVD_XMM_to_M32( u32 to, x86SSERegType from ); +extern void SSEX_MOVD_XMM_to_Rm( x86IntRegType to, x86SSERegType from ); +extern void SSEX_MOVD_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ); +extern void SSEX_MOVD_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ); + +extern void SSEX_POR_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSEX_POR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSEX_PXOR_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSEX_PXOR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSEX_PAND_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSEX_PAND_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSEX_PANDN_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSEX_PANDN_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +extern void SSEX_PUNPCKLDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSEX_PUNPCKLDQ_M128_to_XMM(x86SSERegType to, uptr from); +extern void SSEX_PUNPCKHDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from); +extern void SSEX_PUNPCKHDQ_M128_to_XMM(x86SSERegType to, uptr from); + +extern void SSEX_MOVHLPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); + +//********************* +// 3DNOW instructions * +//********************* +extern void FEMMS( void ); +extern void PFCMPEQMtoR( x86IntRegType to, uptr from ); +extern void PFCMPGTMtoR( x86IntRegType to, uptr from ); +extern void PFCMPGEMtoR( x86IntRegType to, uptr from ); +extern void PFADDMtoR( x86IntRegType to, uptr from ); +extern void PFADDRtoR( x86IntRegType to, x86IntRegType from ); +extern void PFSUBMtoR( x86IntRegType to, uptr from ); +extern void PFSUBRtoR( x86IntRegType to, x86IntRegType from ); +extern void PFMULMtoR( x86IntRegType to, uptr from ); +extern void PFMULRtoR( x86IntRegType to, x86IntRegType from ); +extern void PFRCPMtoR( x86IntRegType to, uptr from ); +extern void PFRCPRtoR( x86IntRegType to, x86IntRegType from ); +extern void PFRCPIT1RtoR( x86IntRegType to, x86IntRegType from ); +extern void PFRCPIT2RtoR( x86IntRegType to, x86IntRegType from ); +extern void PFRSQRTRtoR( x86IntRegType to, x86IntRegType from ); +extern void PFRSQIT1RtoR( x86IntRegType to, x86IntRegType from ); +extern void PF2IDMtoR( x86IntRegType to, uptr from ); +extern void PI2FDMtoR( x86IntRegType to, uptr from ); +extern void PI2FDRtoR( x86IntRegType to, x86IntRegType from ); +extern void PFMAXMtoR( x86IntRegType to, uptr from ); +extern void PFMAXRtoR( x86IntRegType to, x86IntRegType from ); +extern void PFMINMtoR( x86IntRegType to, uptr from ); +extern void PFMINRtoR( x86IntRegType to, x86IntRegType from ); + +extern void SSE2EMU_MOVSD_XMM_to_XMM( x86SSERegType to, x86SSERegType from); +extern void SSE2EMU_MOVQ_M64_to_XMM( x86SSERegType to, uptr from); +extern void SSE2EMU_MOVQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from); +extern void SSE2EMU_MOVD_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ); +extern void SSE2EMU_MOVD_XMM_to_RmOffset(x86IntRegType to, x86SSERegType from, int offset ); + +extern void SSE2EMU_MOVDQ2Q_XMM_to_MM( x86MMXRegType to, x86SSERegType from); +extern void SSE2EMU_MOVQ2DQ_MM_to_XMM( x86SSERegType to, x86MMXRegType from); + +/* SSE2 emulated functions for SSE CPU's by kekko*/ + +extern void SSE2EMU_PSHUFD_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ); +extern void SSE2EMU_MOVD_XMM_to_R( x86IntRegType to, x86SSERegType from ); +extern void SSE2EMU_CVTPS2DQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ); +extern void SSE2EMU_CVTDQ2PS_M128_to_XMM( x86SSERegType to, uptr from ); +extern void SSE2EMU_MOVD_XMM_to_M32( u32 to, x86SSERegType from ); +extern void SSE2EMU_MOVD_R_to_XMM( x86SSERegType to, x86IntRegType from ); + +//////////////////////////////////////////////////// +#ifdef _DEBUG +#define WRITECHECK() CheckX86Ptr() +#else +#define WRITECHECK() +#endif + +__forceinline void write8(u8 val ) { + *x86Ptr = (u8)val; + x86Ptr++; +} + +__forceinline void write16(u16 val ) +{ + *(u16*)x86Ptr = (u16)val; + x86Ptr += 2; +} + +__forceinline void write24(u32 val ) +{ + *(u8*)x86Ptr = (u8)(val & 0xff); + x86Ptr++; + *(u8*)x86Ptr = (u8)((val >> 8) & 0xff); + x86Ptr++; + *(u8*)x86Ptr = (u8)((val >> 16) & 0xff); + x86Ptr++; +} + +__forceinline void write32(u32 val ) +{ + *(u32*)x86Ptr = val; + x86Ptr += 4; +} + #endif // __IX86_H__ \ No newline at end of file diff --git a/pcsx2/x86/ix86/ix86_3dnow.cpp b/pcsx2/x86/ix86/ix86_3dnow.cpp index acc9b96f45..b96d350bc9 100644 --- a/pcsx2/x86/ix86/ix86_3dnow.cpp +++ b/pcsx2/x86/ix86/ix86_3dnow.cpp @@ -1,202 +1,202 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" -#include "ix86.h" - -/**********************/ -/* 3DNOW instructions */ -/**********************/ - -/* femms */ -void FEMMS( void ) -{ - write16( 0x0E0F ); -} - -void PFCMPEQMtoR( x86IntRegType to, uptr from ) -{ - write16( 0x0F0F ); - ModRM( 0, to, DISP32 ); - write32( from ); - write8( 0xB0 ); -} - -void PFCMPGTMtoR( x86IntRegType to, uptr from ) -{ - write16( 0x0F0F ); - ModRM( 0, to, DISP32 ); - write32( from ); - write8( 0xA0 ); -} - -void PFCMPGEMtoR( x86IntRegType to, uptr from ) -{ - write16( 0x0F0F ); - ModRM( 0, to, DISP32 ); - write32( from ); - write8( 0x90 ); -} - -void PFADDMtoR( x86IntRegType to, uptr from ) -{ - write16( 0x0F0F ); - ModRM( 0, to, DISP32 ); - write32( from ); - write8( 0x9E ); -} - -void PFADDRtoR( x86IntRegType to, x86IntRegType from ) -{ - write16( 0x0F0F ); - ModRM( 3, to, from ); - write8( 0x9E ); -} - -void PFSUBMtoR( x86IntRegType to, uptr from ) -{ - write16( 0x0F0F ); - ModRM( 0, to, DISP32 ); - write32( from ); - write8( 0x9A ); -} - -void PFSUBRtoR( x86IntRegType to, x86IntRegType from ) -{ - write16( 0x0F0F ); - ModRM( 3, to, from ); - write8( 0x9A ); -} - -void PFMULMtoR( x86IntRegType to, uptr from ) -{ - write16( 0x0F0F ); - ModRM( 0, to, DISP32 ); - write32( from ); - write8( 0xB4 ); -} - -void PFMULRtoR( x86IntRegType to, x86IntRegType from ) -{ - write16( 0x0F0F ); - ModRM( 3, to, from ); - write8( 0xB4 ); -} - -void PFRCPMtoR( x86IntRegType to, uptr from ) -{ - write16( 0x0F0F ); - ModRM( 0, to, DISP32 ); - write32( from ); - write8( 0x96 ); -} - -void PFRCPRtoR( x86IntRegType to, x86IntRegType from ) -{ - write16( 0x0F0F ); - ModRM( 3, to, from ); - write8( 0x96 ); -} - -void PFRCPIT1RtoR( x86IntRegType to, x86IntRegType from ) -{ - write16( 0x0F0F ); - ModRM( 3, to, from ); - write8( 0xA6 ); -} - -void PFRCPIT2RtoR( x86IntRegType to, x86IntRegType from ) -{ - write16( 0x0F0F ); - ModRM( 3, to, from ); - write8( 0xB6 ); -} - -void PFRSQRTRtoR( x86IntRegType to, x86IntRegType from ) -{ - write16( 0x0F0F ); - ModRM( 3, to, from ); - write8( 0x97 ); -} - -void PFRSQIT1RtoR( x86IntRegType to, x86IntRegType from ) -{ - write16( 0x0F0F ); - ModRM( 3, to, from ); - write8( 0xA7 ); -} - -void PF2IDMtoR( x86IntRegType to, uptr from ) -{ - write16( 0x0F0F ); - ModRM( 0, to, DISP32 ); - write32( from ); - write8( 0x1D ); -} - -void PF2IDRtoR( x86IntRegType to, x86IntRegType from ) -{ - write16( 0x0F0F ); - ModRM( 3, to, from ); - write8( 0x1D ); -} - -void PI2FDMtoR( x86IntRegType to, uptr from ) -{ - write16( 0x0F0F ); - ModRM( 0, to, DISP32 ); - write32( from ); - write8( 0x0D ); -} - -void PI2FDRtoR( x86IntRegType to, x86IntRegType from ) -{ - write16( 0x0F0F ); - ModRM( 3, to, from ); - write8( 0x0D ); -} - -void PFMAXMtoR( x86IntRegType to, uptr from ) -{ - write16( 0x0F0F ); - ModRM( 0, to, DISP32 ); - write32( from ); - write8( 0xA4 ); -} - -void PFMAXRtoR( x86IntRegType to, x86IntRegType from ) -{ - write16( 0x0F0F ); - ModRM( 3, to, from ); - write8( 0xA4 ); -} - -void PFMINMtoR( x86IntRegType to, uptr from ) -{ - write16( 0x0F0F ); - ModRM( 0, to, DISP32 ); - write32( from ); - write8( 0x94 ); -} - -void PFMINRtoR( x86IntRegType to, x86IntRegType from ) -{ - write16( 0x0F0F ); - ModRM( 3, to, from ); - write8( 0x94 ); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" +#include "ix86.h" + +/**********************/ +/* 3DNOW instructions */ +/**********************/ + +/* femms */ +void FEMMS( void ) +{ + write16( 0x0E0F ); +} + +void PFCMPEQMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0xB0 ); +} + +void PFCMPGTMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0xA0 ); +} + +void PFCMPGEMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0x90 ); +} + +void PFADDMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0x9E ); +} + +void PFADDRtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0x9E ); +} + +void PFSUBMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0x9A ); +} + +void PFSUBRtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0x9A ); +} + +void PFMULMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0xB4 ); +} + +void PFMULRtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0xB4 ); +} + +void PFRCPMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0x96 ); +} + +void PFRCPRtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0x96 ); +} + +void PFRCPIT1RtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0xA6 ); +} + +void PFRCPIT2RtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0xB6 ); +} + +void PFRSQRTRtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0x97 ); +} + +void PFRSQIT1RtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0xA7 ); +} + +void PF2IDMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0x1D ); +} + +void PF2IDRtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0x1D ); +} + +void PI2FDMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0x0D ); +} + +void PI2FDRtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0x0D ); +} + +void PFMAXMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0xA4 ); +} + +void PFMAXRtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0xA4 ); +} + +void PFMINMtoR( x86IntRegType to, uptr from ) +{ + write16( 0x0F0F ); + ModRM( 0, to, DISP32 ); + write32( from ); + write8( 0x94 ); +} + +void PFMINRtoR( x86IntRegType to, x86IntRegType from ) +{ + write16( 0x0F0F ); + ModRM( 3, to, from ); + write8( 0x94 ); +} diff --git a/pcsx2/x86/ix86/ix86_cpudetect.cpp b/pcsx2/x86/ix86/ix86_cpudetect.cpp index d0da987e99..d3a31d6984 100644 --- a/pcsx2/x86/ix86/ix86_cpudetect.cpp +++ b/pcsx2/x86/ix86/ix86_cpudetect.cpp @@ -1,403 +1,403 @@ -/* Cpudetection lib - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "ix86.h" -#include "Misc.h" -#include "Threading.h" - -#if defined (_MSC_VER) && _MSC_VER >= 1400 - - extern "C" - { - void __cpuid(int* CPUInfo, int InfoType); - unsigned __int64 __rdtsc(); -# pragma intrinsic(__cpuid) -# pragma intrinsic(__rdtsc) - } - -#endif - -CAPABILITIES cpucaps; -CPUINFO cpuinfo; - -#define cpuid(cmd,a,b,c,d) \ - __asm__ __volatile__("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1" \ - : "=a" (a), "=r" (b), "=c" (c), "=d" (d) : "0" (cmd), "c" (0)) - -extern s32 iCpuId( u32 cmd, u32 *regs ) -{ - int flag=1; - -#if defined (_MSC_VER) && _MSC_VER >= 1400 - - __asm - { - xor ecx, ecx; /* ecx should be zero for CPUID(4) */ - } - __cpuid( (int*)regs, cmd ); - - return 0; - -#elif defined (_MSC_VER) - __asm - { - push ebx; - push edi; - - pushfd; - pop eax; - mov edx, eax; - xor eax, 1 << 21; - push eax; - popfd; - pushfd; - pop eax; - xor eax, edx; - mov flag, eax; - } - if ( ! flag ) - { - return -1; - } - - __asm - { - mov eax, cmd; - xor ecx, ecx; /* ecx should be zero for CPUID(4) */ - cpuid; - mov edi, [regs] - mov [edi], eax; - mov [edi+4], ebx; - mov [edi+8], ecx; - mov [edi+12], edx; - - pop edi; - pop ebx; - } - return 0; - -#else - - // GCC Assembly Code --> - - // see if we can use cpuid - __asm__ __volatile__ ( - "sub $0x18, %%esp\n" - "pushf\n" - "pop %%eax\n" - "mov %%eax, %%edx\n" - "xor $0x200000, %%eax\n" - "push %%eax\n" - "popf\n" - "pushf\n" - "pop %%eax\n" - "xor %%edx, %%eax\n" - "mov %%eax, %0\n" - "add $0x18, %%esp\n" - "cmpl $0x0,%%eax\n" - "jne 1f\n" - "mov $0xffffffff, %%eax\n" - "leave\n" - "ret\n" - "1:\n" - : "=r"(flag) : - ); - - cpuid(cmd, regs[0], regs[1], regs[2], regs[3]); - return 0; - -#endif // _MSC_VER -} - -u64 GetCPUTick( void ) -{ -#if defined (_MSC_VER) && _MSC_VER >= 1400 - - return __rdtsc(); - -#elif defined(_WIN32) - - __asm rdtsc; - -#else - - u32 _a, _d; - __asm__ __volatile__ ("rdtsc" : "=a"(_a), "=d"(_d)); - return (u64)_a | ((u64)_d << 32); - -#endif -} - -// Note: This function doesn't support GCC/Linux. Looking online it seems the only -// way to simulate the Micrsoft SEH model is to use unix signals, and the 'sigaction' -// function specifically. Maybe a project for a linux developer at a later date. :) -void cpudetectSSE3(void* pfnCallSSE3) -{ - cpucaps.hasStreamingSIMD3Extensions = 1; - -#ifdef _MSC_VER - __try { - ((void (*)())pfnCallSSE3)(); - } - __except(EXCEPTION_EXECUTE_HANDLER) { - cpucaps.hasStreamingSIMD3Extensions = 0; - } -#else // linux - -#ifdef PCSX2_FORCESSE3 - cpucaps.hasStreamingSIMD3Extensions = 1; -#else - // exception handling doesn't work, so disable for x86 builds of linux - cpucaps.hasStreamingSIMD3Extensions = 0; -#endif -#endif -} - -#if defined __LINUX__ - -#include -#include - -#endif - -s64 CPUSpeedHz( unsigned int time ) -{ - s64 timeStart, - timeStop; - s64 startTick, - endTick; - s64 overhead; - - if( ! cpucaps.hasTimeStampCounter ) - { - return 0; //check if function is supported - } - - overhead = GetCPUTick() - GetCPUTick(); - - timeStart = timeGetTime( ); - while( timeGetTime( ) == timeStart ) - { - timeStart = timeGetTime( ); - } - for(;;) - { - timeStop = timeGetTime( ); - if ( ( timeStop - timeStart ) > 1 ) - { - startTick = GetCPUTick( ); - break; - } - } - - timeStart = timeStop; - for(;;) - { - timeStop = timeGetTime( ); - if ( ( timeStop - timeStart ) > time ) - { - endTick = GetCPUTick( ); - break; - } - } - - return (s64)( ( endTick - startTick ) + ( overhead ) ); -} - -//////////////////////////////////////////////////// -int arr[] = { - 0x65746e49, 0x2952286c, 0x726f4320, 0x4d542865, - 0x51203229,0x20646175,0x20555043,0x20202020 , - 0x20202020,0x20402020,0x36362e32,0x7a4847 -}; - -void cpudetectInit() -{ - u32 regs[ 4 ]; - u32 cmds; - int cputype=0; // Cpu type - //AMD 64 STUFF - u32 x86_64_8BITBRANDID; - u32 x86_64_12BITBRANDID; - int num; - char str[50]; - - memzero_obj( cpuinfo.x86ID ); - cpuinfo.x86Family = 0; - cpuinfo.x86Model = 0; - cpuinfo.x86PType = 0; - cpuinfo.x86StepID = 0; - cpuinfo.x86Flags = 0; - cpuinfo.x86EFlags = 0; - - if ( iCpuId( 0, regs ) == -1 ) return; - - cmds = regs[ 0 ]; - ((u32*)cpuinfo.x86ID)[ 0 ] = regs[ 1 ]; - ((u32*)cpuinfo.x86ID)[ 1 ] = regs[ 3 ]; - ((u32*)cpuinfo.x86ID)[ 2 ] = regs[ 2 ]; - - // Hack - prevents reg[2] & reg[3] from being optimized out of existance! - num = sprintf(str, "\tx86Flags = %8.8x %8.8x\n", regs[3], regs[2]); - - u32 LogicalCoresPerPhysicalCPU = 0; - u32 PhysicalCoresPerPhysicalCPU = 1; - - if ( cmds >= 0x00000001 ) - { - if ( iCpuId( 0x00000001, regs ) != -1 ) - { - cpuinfo.x86StepID = regs[ 0 ] & 0xf; - cpuinfo.x86Model = (regs[ 0 ] >> 4) & 0xf; - cpuinfo.x86Family = (regs[ 0 ] >> 8) & 0xf; - cpuinfo.x86PType = (regs[ 0 ] >> 12) & 0x3; - LogicalCoresPerPhysicalCPU = ( regs[1] >> 16 ) & 0xff; - x86_64_8BITBRANDID = regs[1] & 0xff; - cpuinfo.x86Flags = regs[ 3 ]; - cpuinfo.x86Flags2 = regs[ 2 ]; - } - } - /* detect multicore for intel cpu */ - if ((cmds >= 0x00000004) && !strcmp("GenuineIntel",cpuinfo.x86ID)) - { - if ( iCpuId( 0x00000004, regs ) != -1 ) - { - PhysicalCoresPerPhysicalCPU += ( regs[0] >> 26) & 0x3f; - } - } - - if ( iCpuId( 0x80000000, regs ) != -1 ) - { - cmds = regs[ 0 ]; - if ( cmds >= 0x80000001 ) - { - if ( iCpuId( 0x80000001, regs ) != -1 ) - { - x86_64_12BITBRANDID = regs[1] & 0xfff; - cpuinfo.x86EFlags = regs[ 3 ]; - - } - } - /* detect multicore for amd cpu */ - if ((cmds >= 0x80000008) && !strcmp("AuthenticAMD",cpuinfo.x86ID)) - { - if ( iCpuId( 0x80000008, regs ) != -1 ) - { - PhysicalCoresPerPhysicalCPU += ( regs[2] ) & 0xff; - } - } - } - - switch(cpuinfo.x86PType) - { - case 0: - strcpy( cpuinfo.x86Type, "Standard OEM"); - break; - case 1: - strcpy( cpuinfo.x86Type, "Overdrive"); - break; - case 2: - strcpy( cpuinfo.x86Type, "Dual"); - break; - case 3: - strcpy( cpuinfo.x86Type, "Reserved"); - break; - default: - strcpy( cpuinfo.x86Type, "Unknown"); - break; - } - if ( cpuinfo.x86ID[ 0 ] == 'G' ){ cputype=0;}//trick lines but if you know a way better ;p - if ( cpuinfo.x86ID[ 0 ] == 'A' ){ cputype=1;} - - memzero_obj( cpuinfo.x86Fam ); - iCpuId( 0x80000002, (u32*)cpuinfo.x86Fam); - iCpuId( 0x80000003, (u32*)(cpuinfo.x86Fam+16)); - iCpuId( 0x80000004, (u32*)(cpuinfo.x86Fam+32)); - - //capabilities - cpucaps.hasFloatingPointUnit = ( cpuinfo.x86Flags >> 0 ) & 1; - cpucaps.hasVirtual8086ModeEnhancements = ( cpuinfo.x86Flags >> 1 ) & 1; - cpucaps.hasDebuggingExtensions = ( cpuinfo.x86Flags >> 2 ) & 1; - cpucaps.hasPageSizeExtensions = ( cpuinfo.x86Flags >> 3 ) & 1; - cpucaps.hasTimeStampCounter = ( cpuinfo.x86Flags >> 4 ) & 1; - cpucaps.hasModelSpecificRegisters = ( cpuinfo.x86Flags >> 5 ) & 1; - cpucaps.hasPhysicalAddressExtension = ( cpuinfo.x86Flags >> 6 ) & 1; - cpucaps.hasMachineCheckArchitecture = ( cpuinfo.x86Flags >> 7 ) & 1; - cpucaps.hasCOMPXCHG8BInstruction = ( cpuinfo.x86Flags >> 8 ) & 1; - cpucaps.hasAdvancedProgrammableInterruptController = ( cpuinfo.x86Flags >> 9 ) & 1; - cpucaps.hasSEPFastSystemCall = ( cpuinfo.x86Flags >> 11 ) & 1; - cpucaps.hasMemoryTypeRangeRegisters = ( cpuinfo.x86Flags >> 12 ) & 1; - cpucaps.hasPTEGlobalFlag = ( cpuinfo.x86Flags >> 13 ) & 1; - cpucaps.hasMachineCheckArchitecture = ( cpuinfo.x86Flags >> 14 ) & 1; - cpucaps.hasConditionalMoveAndCompareInstructions = ( cpuinfo.x86Flags >> 15 ) & 1; - cpucaps.hasFGPageAttributeTable = ( cpuinfo.x86Flags >> 16 ) & 1; - cpucaps.has36bitPageSizeExtension = ( cpuinfo.x86Flags >> 17 ) & 1; - cpucaps.hasProcessorSerialNumber = ( cpuinfo.x86Flags >> 18 ) & 1; - cpucaps.hasCFLUSHInstruction = ( cpuinfo.x86Flags >> 19 ) & 1; - cpucaps.hasDebugStore = ( cpuinfo.x86Flags >> 21 ) & 1; - cpucaps.hasACPIThermalMonitorAndClockControl = ( cpuinfo.x86Flags >> 22 ) & 1; - cpucaps.hasMultimediaExtensions = ( cpuinfo.x86Flags >> 23 ) & 1; //mmx - cpucaps.hasFastStreamingSIMDExtensionsSaveRestore = ( cpuinfo.x86Flags >> 24 ) & 1; - cpucaps.hasStreamingSIMDExtensions = ( cpuinfo.x86Flags >> 25 ) & 1; //sse - cpucaps.hasStreamingSIMD2Extensions = ( cpuinfo.x86Flags >> 26 ) & 1; //sse2 - cpucaps.hasSelfSnoop = ( cpuinfo.x86Flags >> 27 ) & 1; - cpucaps.hasMultiThreading = ( cpuinfo.x86Flags >> 28 ) & 1; - cpucaps.hasThermalMonitor = ( cpuinfo.x86Flags >> 29 ) & 1; - cpucaps.hasIntel64BitArchitecture = ( cpuinfo.x86Flags >> 30 ) & 1; - //that is only for AMDs - cpucaps.hasMultimediaExtensionsExt = ( cpuinfo.x86EFlags >> 22 ) & 1; //mmx2 - cpucaps.hasAMD64BitArchitecture = ( cpuinfo.x86EFlags >> 29 ) & 1; //64bit cpu - cpucaps.has3DNOWInstructionExtensionsExt = ( cpuinfo.x86EFlags >> 30 ) & 1; //3dnow+ - cpucaps.has3DNOWInstructionExtensions = ( cpuinfo.x86EFlags >> 31 ) & 1; //3dnow - - cpuinfo.cpuspeed = (u32)(CPUSpeedHz( 1000 ) / 1000000); - - // --> SSE 4.1 detection <-- - // We don't care about the small subset of CPUs using SSE4 (which is also hard to - // detect, in addition to being of limited use due to the abbreviated instruction set). - // So we'll just leave it at SSE 4.1. SSE4 cpu detection is ignored. - - cpucaps.hasStreamingSIMD4Extensions = ( cpuinfo.x86Flags2 >> 19 ) & 1; //sse4.1 - - // --> SSE3 detection <-- - // These instructions may not be recognized by some compilers, or may not have - // intrinsic equivalents available. So we use our own ix86 emitter to generate - // some code and run it that way. :) - - u8* recSSE = (u8*)SysMmap( NULL, 0x1000 ); - if( recSSE != NULL ) - { - x86SetPtr(recSSE); - SSE3_MOVSLDUP_XMM_to_XMM(XMM0, XMM0); - RET(); - cpudetectSSE3(recSSE); - SysMunmap( recSSE, 0x1000 ); - } - - ////////////////////////////////////// - // Core Counting! - - if( !cpucaps.hasMultiThreading || LogicalCoresPerPhysicalCPU == 0 ) - LogicalCoresPerPhysicalCPU = 1; - - // This will assign values into cpuinfo.LogicalCores and PhysicalCores - Threading::CountLogicalCores( LogicalCoresPerPhysicalCPU, PhysicalCoresPerPhysicalCPU ); -} - +/* Cpudetection lib + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "ix86.h" +#include "Misc.h" +#include "Threading.h" + +#if defined (_MSC_VER) && _MSC_VER >= 1400 + + extern "C" + { + void __cpuid(int* CPUInfo, int InfoType); + unsigned __int64 __rdtsc(); +# pragma intrinsic(__cpuid) +# pragma intrinsic(__rdtsc) + } + +#endif + +CAPABILITIES cpucaps; +CPUINFO cpuinfo; + +#define cpuid(cmd,a,b,c,d) \ + __asm__ __volatile__("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1" \ + : "=a" (a), "=r" (b), "=c" (c), "=d" (d) : "0" (cmd), "c" (0)) + +extern s32 iCpuId( u32 cmd, u32 *regs ) +{ + int flag=1; + +#if defined (_MSC_VER) && _MSC_VER >= 1400 + + __asm + { + xor ecx, ecx; /* ecx should be zero for CPUID(4) */ + } + __cpuid( (int*)regs, cmd ); + + return 0; + +#elif defined (_MSC_VER) + __asm + { + push ebx; + push edi; + + pushfd; + pop eax; + mov edx, eax; + xor eax, 1 << 21; + push eax; + popfd; + pushfd; + pop eax; + xor eax, edx; + mov flag, eax; + } + if ( ! flag ) + { + return -1; + } + + __asm + { + mov eax, cmd; + xor ecx, ecx; /* ecx should be zero for CPUID(4) */ + cpuid; + mov edi, [regs] + mov [edi], eax; + mov [edi+4], ebx; + mov [edi+8], ecx; + mov [edi+12], edx; + + pop edi; + pop ebx; + } + return 0; + +#else + + // GCC Assembly Code --> + + // see if we can use cpuid + __asm__ __volatile__ ( + "sub $0x18, %%esp\n" + "pushf\n" + "pop %%eax\n" + "mov %%eax, %%edx\n" + "xor $0x200000, %%eax\n" + "push %%eax\n" + "popf\n" + "pushf\n" + "pop %%eax\n" + "xor %%edx, %%eax\n" + "mov %%eax, %0\n" + "add $0x18, %%esp\n" + "cmpl $0x0,%%eax\n" + "jne 1f\n" + "mov $0xffffffff, %%eax\n" + "leave\n" + "ret\n" + "1:\n" + : "=r"(flag) : + ); + + cpuid(cmd, regs[0], regs[1], regs[2], regs[3]); + return 0; + +#endif // _MSC_VER +} + +u64 GetCPUTick( void ) +{ +#if defined (_MSC_VER) && _MSC_VER >= 1400 + + return __rdtsc(); + +#elif defined(_WIN32) + + __asm rdtsc; + +#else + + u32 _a, _d; + __asm__ __volatile__ ("rdtsc" : "=a"(_a), "=d"(_d)); + return (u64)_a | ((u64)_d << 32); + +#endif +} + +// Note: This function doesn't support GCC/Linux. Looking online it seems the only +// way to simulate the Micrsoft SEH model is to use unix signals, and the 'sigaction' +// function specifically. Maybe a project for a linux developer at a later date. :) +void cpudetectSSE3(void* pfnCallSSE3) +{ + cpucaps.hasStreamingSIMD3Extensions = 1; + +#ifdef _MSC_VER + __try { + ((void (*)())pfnCallSSE3)(); + } + __except(EXCEPTION_EXECUTE_HANDLER) { + cpucaps.hasStreamingSIMD3Extensions = 0; + } +#else // linux + +#ifdef PCSX2_FORCESSE3 + cpucaps.hasStreamingSIMD3Extensions = 1; +#else + // exception handling doesn't work, so disable for x86 builds of linux + cpucaps.hasStreamingSIMD3Extensions = 0; +#endif +#endif +} + +#if defined __LINUX__ + +#include +#include + +#endif + +s64 CPUSpeedHz( unsigned int time ) +{ + s64 timeStart, + timeStop; + s64 startTick, + endTick; + s64 overhead; + + if( ! cpucaps.hasTimeStampCounter ) + { + return 0; //check if function is supported + } + + overhead = GetCPUTick() - GetCPUTick(); + + timeStart = timeGetTime( ); + while( timeGetTime( ) == timeStart ) + { + timeStart = timeGetTime( ); + } + for(;;) + { + timeStop = timeGetTime( ); + if ( ( timeStop - timeStart ) > 1 ) + { + startTick = GetCPUTick( ); + break; + } + } + + timeStart = timeStop; + for(;;) + { + timeStop = timeGetTime( ); + if ( ( timeStop - timeStart ) > time ) + { + endTick = GetCPUTick( ); + break; + } + } + + return (s64)( ( endTick - startTick ) + ( overhead ) ); +} + +//////////////////////////////////////////////////// +int arr[] = { + 0x65746e49, 0x2952286c, 0x726f4320, 0x4d542865, + 0x51203229,0x20646175,0x20555043,0x20202020 , + 0x20202020,0x20402020,0x36362e32,0x7a4847 +}; + +void cpudetectInit() +{ + u32 regs[ 4 ]; + u32 cmds; + int cputype=0; // Cpu type + //AMD 64 STUFF + u32 x86_64_8BITBRANDID; + u32 x86_64_12BITBRANDID; + int num; + char str[50]; + + memzero_obj( cpuinfo.x86ID ); + cpuinfo.x86Family = 0; + cpuinfo.x86Model = 0; + cpuinfo.x86PType = 0; + cpuinfo.x86StepID = 0; + cpuinfo.x86Flags = 0; + cpuinfo.x86EFlags = 0; + + if ( iCpuId( 0, regs ) == -1 ) return; + + cmds = regs[ 0 ]; + ((u32*)cpuinfo.x86ID)[ 0 ] = regs[ 1 ]; + ((u32*)cpuinfo.x86ID)[ 1 ] = regs[ 3 ]; + ((u32*)cpuinfo.x86ID)[ 2 ] = regs[ 2 ]; + + // Hack - prevents reg[2] & reg[3] from being optimized out of existance! + num = sprintf(str, "\tx86Flags = %8.8x %8.8x\n", regs[3], regs[2]); + + u32 LogicalCoresPerPhysicalCPU = 0; + u32 PhysicalCoresPerPhysicalCPU = 1; + + if ( cmds >= 0x00000001 ) + { + if ( iCpuId( 0x00000001, regs ) != -1 ) + { + cpuinfo.x86StepID = regs[ 0 ] & 0xf; + cpuinfo.x86Model = (regs[ 0 ] >> 4) & 0xf; + cpuinfo.x86Family = (regs[ 0 ] >> 8) & 0xf; + cpuinfo.x86PType = (regs[ 0 ] >> 12) & 0x3; + LogicalCoresPerPhysicalCPU = ( regs[1] >> 16 ) & 0xff; + x86_64_8BITBRANDID = regs[1] & 0xff; + cpuinfo.x86Flags = regs[ 3 ]; + cpuinfo.x86Flags2 = regs[ 2 ]; + } + } + /* detect multicore for intel cpu */ + if ((cmds >= 0x00000004) && !strcmp("GenuineIntel",cpuinfo.x86ID)) + { + if ( iCpuId( 0x00000004, regs ) != -1 ) + { + PhysicalCoresPerPhysicalCPU += ( regs[0] >> 26) & 0x3f; + } + } + + if ( iCpuId( 0x80000000, regs ) != -1 ) + { + cmds = regs[ 0 ]; + if ( cmds >= 0x80000001 ) + { + if ( iCpuId( 0x80000001, regs ) != -1 ) + { + x86_64_12BITBRANDID = regs[1] & 0xfff; + cpuinfo.x86EFlags = regs[ 3 ]; + + } + } + /* detect multicore for amd cpu */ + if ((cmds >= 0x80000008) && !strcmp("AuthenticAMD",cpuinfo.x86ID)) + { + if ( iCpuId( 0x80000008, regs ) != -1 ) + { + PhysicalCoresPerPhysicalCPU += ( regs[2] ) & 0xff; + } + } + } + + switch(cpuinfo.x86PType) + { + case 0: + strcpy( cpuinfo.x86Type, "Standard OEM"); + break; + case 1: + strcpy( cpuinfo.x86Type, "Overdrive"); + break; + case 2: + strcpy( cpuinfo.x86Type, "Dual"); + break; + case 3: + strcpy( cpuinfo.x86Type, "Reserved"); + break; + default: + strcpy( cpuinfo.x86Type, "Unknown"); + break; + } + if ( cpuinfo.x86ID[ 0 ] == 'G' ){ cputype=0;}//trick lines but if you know a way better ;p + if ( cpuinfo.x86ID[ 0 ] == 'A' ){ cputype=1;} + + memzero_obj( cpuinfo.x86Fam ); + iCpuId( 0x80000002, (u32*)cpuinfo.x86Fam); + iCpuId( 0x80000003, (u32*)(cpuinfo.x86Fam+16)); + iCpuId( 0x80000004, (u32*)(cpuinfo.x86Fam+32)); + + //capabilities + cpucaps.hasFloatingPointUnit = ( cpuinfo.x86Flags >> 0 ) & 1; + cpucaps.hasVirtual8086ModeEnhancements = ( cpuinfo.x86Flags >> 1 ) & 1; + cpucaps.hasDebuggingExtensions = ( cpuinfo.x86Flags >> 2 ) & 1; + cpucaps.hasPageSizeExtensions = ( cpuinfo.x86Flags >> 3 ) & 1; + cpucaps.hasTimeStampCounter = ( cpuinfo.x86Flags >> 4 ) & 1; + cpucaps.hasModelSpecificRegisters = ( cpuinfo.x86Flags >> 5 ) & 1; + cpucaps.hasPhysicalAddressExtension = ( cpuinfo.x86Flags >> 6 ) & 1; + cpucaps.hasMachineCheckArchitecture = ( cpuinfo.x86Flags >> 7 ) & 1; + cpucaps.hasCOMPXCHG8BInstruction = ( cpuinfo.x86Flags >> 8 ) & 1; + cpucaps.hasAdvancedProgrammableInterruptController = ( cpuinfo.x86Flags >> 9 ) & 1; + cpucaps.hasSEPFastSystemCall = ( cpuinfo.x86Flags >> 11 ) & 1; + cpucaps.hasMemoryTypeRangeRegisters = ( cpuinfo.x86Flags >> 12 ) & 1; + cpucaps.hasPTEGlobalFlag = ( cpuinfo.x86Flags >> 13 ) & 1; + cpucaps.hasMachineCheckArchitecture = ( cpuinfo.x86Flags >> 14 ) & 1; + cpucaps.hasConditionalMoveAndCompareInstructions = ( cpuinfo.x86Flags >> 15 ) & 1; + cpucaps.hasFGPageAttributeTable = ( cpuinfo.x86Flags >> 16 ) & 1; + cpucaps.has36bitPageSizeExtension = ( cpuinfo.x86Flags >> 17 ) & 1; + cpucaps.hasProcessorSerialNumber = ( cpuinfo.x86Flags >> 18 ) & 1; + cpucaps.hasCFLUSHInstruction = ( cpuinfo.x86Flags >> 19 ) & 1; + cpucaps.hasDebugStore = ( cpuinfo.x86Flags >> 21 ) & 1; + cpucaps.hasACPIThermalMonitorAndClockControl = ( cpuinfo.x86Flags >> 22 ) & 1; + cpucaps.hasMultimediaExtensions = ( cpuinfo.x86Flags >> 23 ) & 1; //mmx + cpucaps.hasFastStreamingSIMDExtensionsSaveRestore = ( cpuinfo.x86Flags >> 24 ) & 1; + cpucaps.hasStreamingSIMDExtensions = ( cpuinfo.x86Flags >> 25 ) & 1; //sse + cpucaps.hasStreamingSIMD2Extensions = ( cpuinfo.x86Flags >> 26 ) & 1; //sse2 + cpucaps.hasSelfSnoop = ( cpuinfo.x86Flags >> 27 ) & 1; + cpucaps.hasMultiThreading = ( cpuinfo.x86Flags >> 28 ) & 1; + cpucaps.hasThermalMonitor = ( cpuinfo.x86Flags >> 29 ) & 1; + cpucaps.hasIntel64BitArchitecture = ( cpuinfo.x86Flags >> 30 ) & 1; + //that is only for AMDs + cpucaps.hasMultimediaExtensionsExt = ( cpuinfo.x86EFlags >> 22 ) & 1; //mmx2 + cpucaps.hasAMD64BitArchitecture = ( cpuinfo.x86EFlags >> 29 ) & 1; //64bit cpu + cpucaps.has3DNOWInstructionExtensionsExt = ( cpuinfo.x86EFlags >> 30 ) & 1; //3dnow+ + cpucaps.has3DNOWInstructionExtensions = ( cpuinfo.x86EFlags >> 31 ) & 1; //3dnow + + cpuinfo.cpuspeed = (u32)(CPUSpeedHz( 1000 ) / 1000000); + + // --> SSE 4.1 detection <-- + // We don't care about the small subset of CPUs using SSE4 (which is also hard to + // detect, in addition to being of limited use due to the abbreviated instruction set). + // So we'll just leave it at SSE 4.1. SSE4 cpu detection is ignored. + + cpucaps.hasStreamingSIMD4Extensions = ( cpuinfo.x86Flags2 >> 19 ) & 1; //sse4.1 + + // --> SSE3 detection <-- + // These instructions may not be recognized by some compilers, or may not have + // intrinsic equivalents available. So we use our own ix86 emitter to generate + // some code and run it that way. :) + + u8* recSSE = (u8*)SysMmap( NULL, 0x1000 ); + if( recSSE != NULL ) + { + x86SetPtr(recSSE); + SSE3_MOVSLDUP_XMM_to_XMM(XMM0, XMM0); + RET(); + cpudetectSSE3(recSSE); + SysMunmap( recSSE, 0x1000 ); + } + + ////////////////////////////////////// + // Core Counting! + + if( !cpucaps.hasMultiThreading || LogicalCoresPerPhysicalCPU == 0 ) + LogicalCoresPerPhysicalCPU = 1; + + // This will assign values into cpuinfo.LogicalCores and PhysicalCores + Threading::CountLogicalCores( LogicalCoresPerPhysicalCPU, PhysicalCoresPerPhysicalCPU ); +} + diff --git a/pcsx2/x86/ix86/ix86_fpu.cpp b/pcsx2/x86/ix86/ix86_fpu.cpp index 41e40380ca..c1711505df 100644 --- a/pcsx2/x86/ix86/ix86_fpu.cpp +++ b/pcsx2/x86/ix86/ix86_fpu.cpp @@ -1,286 +1,286 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" -#include "ix86.h" - -/********************/ -/* FPU instructions */ -/********************/ - -/* fild m32 to fpu reg stack */ -void FILD32( u32 from ) -{ - write8( 0xDB ); - ModRM( 0, 0x0, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* fistp m32 from fpu reg stack */ -void FISTP32( u32 from ) -{ - write8( 0xDB ); - ModRM( 0, 0x3, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* fld m32 to fpu reg stack */ -void FLD32( u32 from ) -{ - write8( 0xD9 ); - ModRM( 0, 0x0, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -// fld st(i) -void FLD(int st) { write16(0xc0d9+(st<<8)); } - -void FLD1() { write16(0xe8d9); } -void FLDL2E() { write16(0xead9); } - -/* fst m32 from fpu reg stack */ -void FST32( u32 to ) -{ - write8( 0xD9 ); - ModRM( 0, 0x2, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -/* fstp m32 from fpu reg stack */ -void FSTP32( u32 to ) -{ - write8( 0xD9 ); - ModRM( 0, 0x3, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -// fstp st(i) -void FSTP(int st) { write16(0xd8dd+(st<<8)); } - -/* fldcw fpu control word from m16 */ -void FLDCW( u32 from ) -{ - write8( 0xD9 ); - ModRM( 0, 0x5, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* fnstcw fpu control word to m16 */ -void FNSTCW( u32 to ) -{ - write8( 0xD9 ); - ModRM( 0, 0x7, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -void FNSTSWtoAX( void ) -{ - write16( 0xE0DF ); -} - -void FXAM() -{ - write16(0xe5d9); -} - -void FDECSTP() { write16(0xf6d9); } -void FRNDINT() { write16(0xfcd9); } -void FXCH(int st) { write16(0xc8d9+(st<<8)); } -void F2XM1() { write16(0xf0d9); } -void FSCALE() { write16(0xfdd9); } - -/* fadd ST(src) to fpu reg stack ST(0) */ -void FADD32Rto0( x86IntRegType src ) -{ - write8( 0xD8 ); - write8( 0xC0 + src ); -} - -/* fadd ST(0) to fpu reg stack ST(src) */ -void FADD320toR( x86IntRegType src ) -{ - write8( 0xDC ); - write8( 0xC0 + src ); -} - -/* fsub ST(src) to fpu reg stack ST(0) */ -void FSUB32Rto0( x86IntRegType src ) -{ - write8( 0xD8 ); - write8( 0xE0 + src ); -} - -/* fsub ST(0) to fpu reg stack ST(src) */ -void FSUB320toR( x86IntRegType src ) -{ - write8( 0xDC ); - write8( 0xE8 + src ); -} - -/* fsubp -> substract ST(0) from ST(1), store in ST(1) and POP stack */ -void FSUBP( void ) -{ - write8( 0xDE ); - write8( 0xE9 ); -} - -/* fmul ST(src) to fpu reg stack ST(0) */ -void FMUL32Rto0( x86IntRegType src ) -{ - write8( 0xD8 ); - write8( 0xC8 + src ); -} - -/* fmul ST(0) to fpu reg stack ST(src) */ -void FMUL320toR( x86IntRegType src ) -{ - write8( 0xDC ); - write8( 0xC8 + src ); -} - -/* fdiv ST(src) to fpu reg stack ST(0) */ -void FDIV32Rto0( x86IntRegType src ) -{ - write8( 0xD8 ); - write8( 0xF0 + src ); -} - -/* fdiv ST(0) to fpu reg stack ST(src) */ -void FDIV320toR( x86IntRegType src ) -{ - write8( 0xDC ); - write8( 0xF8 + src ); -} - -void FDIV320toRP( x86IntRegType src ) -{ - write8( 0xDE ); - write8( 0xF8 + src ); -} - -/* fadd m32 to fpu reg stack */ -void FADD32( u32 from ) -{ - write8( 0xD8 ); - ModRM( 0, 0x0, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* fsub m32 to fpu reg stack */ -void FSUB32( u32 from ) -{ - write8( 0xD8 ); - ModRM( 0, 0x4, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* fmul m32 to fpu reg stack */ -void FMUL32( u32 from ) -{ - write8( 0xD8 ); - ModRM( 0, 0x1, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* fdiv m32 to fpu reg stack */ -void FDIV32( u32 from ) -{ - write8( 0xD8 ); - ModRM( 0, 0x6, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* fabs fpu reg stack */ -void FABS( void ) -{ - write16( 0xE1D9 ); -} - -/* fsqrt fpu reg stack */ -void FSQRT( void ) -{ - write16( 0xFAD9 ); -} - -void FPATAN(void) { write16(0xf3d9); } -void FSIN(void) { write16(0xfed9); } - -/* fchs fpu reg stack */ -void FCHS( void ) -{ - write16( 0xE0D9 ); -} - -/* fcomi st, st(i) */ -void FCOMI( x86IntRegType src ) -{ - write8( 0xDB ); - write8( 0xF0 + src ); -} - -/* fcomip st, st(i) */ -void FCOMIP( x86IntRegType src ) -{ - write8( 0xDF ); - write8( 0xF0 + src ); -} - -/* fucomi st, st(i) */ -void FUCOMI( x86IntRegType src ) -{ - write8( 0xDB ); - write8( 0xE8 + src ); -} - -/* fucomip st, st(i) */ -void FUCOMIP( x86IntRegType src ) -{ - write8( 0xDF ); - write8( 0xE8 + src ); -} - -/* fcom m32 to fpu reg stack */ -void FCOM32( u32 from ) -{ - write8( 0xD8 ); - ModRM( 0, 0x2, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* fcomp m32 to fpu reg stack */ -void FCOMP32( u32 from ) -{ - write8( 0xD8 ); - ModRM( 0, 0x3, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -#define FCMOV32( low, high ) \ - { \ - write8( low ); \ - write8( high + from ); \ - } - -void FCMOVB32( x86IntRegType from ) { FCMOV32( 0xDA, 0xC0 ); } -void FCMOVE32( x86IntRegType from ) { FCMOV32( 0xDA, 0xC8 ); } -void FCMOVBE32( x86IntRegType from ) { FCMOV32( 0xDA, 0xD0 ); } -void FCMOVU32( x86IntRegType from ) { FCMOV32( 0xDA, 0xD8 ); } -void FCMOVNB32( x86IntRegType from ) { FCMOV32( 0xDB, 0xC0 ); } -void FCMOVNE32( x86IntRegType from ) { FCMOV32( 0xDB, 0xC8 ); } -void FCMOVNBE32( x86IntRegType from ) { FCMOV32( 0xDB, 0xD0 ); } -void FCMOVNU32( x86IntRegType from ) { FCMOV32( 0xDB, 0xD8 ); } +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" +#include "ix86.h" + +/********************/ +/* FPU instructions */ +/********************/ + +/* fild m32 to fpu reg stack */ +void FILD32( u32 from ) +{ + write8( 0xDB ); + ModRM( 0, 0x0, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* fistp m32 from fpu reg stack */ +void FISTP32( u32 from ) +{ + write8( 0xDB ); + ModRM( 0, 0x3, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* fld m32 to fpu reg stack */ +void FLD32( u32 from ) +{ + write8( 0xD9 ); + ModRM( 0, 0x0, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// fld st(i) +void FLD(int st) { write16(0xc0d9+(st<<8)); } + +void FLD1() { write16(0xe8d9); } +void FLDL2E() { write16(0xead9); } + +/* fst m32 from fpu reg stack */ +void FST32( u32 to ) +{ + write8( 0xD9 ); + ModRM( 0, 0x2, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +/* fstp m32 from fpu reg stack */ +void FSTP32( u32 to ) +{ + write8( 0xD9 ); + ModRM( 0, 0x3, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +// fstp st(i) +void FSTP(int st) { write16(0xd8dd+(st<<8)); } + +/* fldcw fpu control word from m16 */ +void FLDCW( u32 from ) +{ + write8( 0xD9 ); + ModRM( 0, 0x5, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* fnstcw fpu control word to m16 */ +void FNSTCW( u32 to ) +{ + write8( 0xD9 ); + ModRM( 0, 0x7, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +void FNSTSWtoAX( void ) +{ + write16( 0xE0DF ); +} + +void FXAM() +{ + write16(0xe5d9); +} + +void FDECSTP() { write16(0xf6d9); } +void FRNDINT() { write16(0xfcd9); } +void FXCH(int st) { write16(0xc8d9+(st<<8)); } +void F2XM1() { write16(0xf0d9); } +void FSCALE() { write16(0xfdd9); } + +/* fadd ST(src) to fpu reg stack ST(0) */ +void FADD32Rto0( x86IntRegType src ) +{ + write8( 0xD8 ); + write8( 0xC0 + src ); +} + +/* fadd ST(0) to fpu reg stack ST(src) */ +void FADD320toR( x86IntRegType src ) +{ + write8( 0xDC ); + write8( 0xC0 + src ); +} + +/* fsub ST(src) to fpu reg stack ST(0) */ +void FSUB32Rto0( x86IntRegType src ) +{ + write8( 0xD8 ); + write8( 0xE0 + src ); +} + +/* fsub ST(0) to fpu reg stack ST(src) */ +void FSUB320toR( x86IntRegType src ) +{ + write8( 0xDC ); + write8( 0xE8 + src ); +} + +/* fsubp -> substract ST(0) from ST(1), store in ST(1) and POP stack */ +void FSUBP( void ) +{ + write8( 0xDE ); + write8( 0xE9 ); +} + +/* fmul ST(src) to fpu reg stack ST(0) */ +void FMUL32Rto0( x86IntRegType src ) +{ + write8( 0xD8 ); + write8( 0xC8 + src ); +} + +/* fmul ST(0) to fpu reg stack ST(src) */ +void FMUL320toR( x86IntRegType src ) +{ + write8( 0xDC ); + write8( 0xC8 + src ); +} + +/* fdiv ST(src) to fpu reg stack ST(0) */ +void FDIV32Rto0( x86IntRegType src ) +{ + write8( 0xD8 ); + write8( 0xF0 + src ); +} + +/* fdiv ST(0) to fpu reg stack ST(src) */ +void FDIV320toR( x86IntRegType src ) +{ + write8( 0xDC ); + write8( 0xF8 + src ); +} + +void FDIV320toRP( x86IntRegType src ) +{ + write8( 0xDE ); + write8( 0xF8 + src ); +} + +/* fadd m32 to fpu reg stack */ +void FADD32( u32 from ) +{ + write8( 0xD8 ); + ModRM( 0, 0x0, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* fsub m32 to fpu reg stack */ +void FSUB32( u32 from ) +{ + write8( 0xD8 ); + ModRM( 0, 0x4, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* fmul m32 to fpu reg stack */ +void FMUL32( u32 from ) +{ + write8( 0xD8 ); + ModRM( 0, 0x1, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* fdiv m32 to fpu reg stack */ +void FDIV32( u32 from ) +{ + write8( 0xD8 ); + ModRM( 0, 0x6, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* fabs fpu reg stack */ +void FABS( void ) +{ + write16( 0xE1D9 ); +} + +/* fsqrt fpu reg stack */ +void FSQRT( void ) +{ + write16( 0xFAD9 ); +} + +void FPATAN(void) { write16(0xf3d9); } +void FSIN(void) { write16(0xfed9); } + +/* fchs fpu reg stack */ +void FCHS( void ) +{ + write16( 0xE0D9 ); +} + +/* fcomi st, st(i) */ +void FCOMI( x86IntRegType src ) +{ + write8( 0xDB ); + write8( 0xF0 + src ); +} + +/* fcomip st, st(i) */ +void FCOMIP( x86IntRegType src ) +{ + write8( 0xDF ); + write8( 0xF0 + src ); +} + +/* fucomi st, st(i) */ +void FUCOMI( x86IntRegType src ) +{ + write8( 0xDB ); + write8( 0xE8 + src ); +} + +/* fucomip st, st(i) */ +void FUCOMIP( x86IntRegType src ) +{ + write8( 0xDF ); + write8( 0xE8 + src ); +} + +/* fcom m32 to fpu reg stack */ +void FCOM32( u32 from ) +{ + write8( 0xD8 ); + ModRM( 0, 0x2, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* fcomp m32 to fpu reg stack */ +void FCOMP32( u32 from ) +{ + write8( 0xD8 ); + ModRM( 0, 0x3, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +#define FCMOV32( low, high ) \ + { \ + write8( low ); \ + write8( high + from ); \ + } + +void FCMOVB32( x86IntRegType from ) { FCMOV32( 0xDA, 0xC0 ); } +void FCMOVE32( x86IntRegType from ) { FCMOV32( 0xDA, 0xC8 ); } +void FCMOVBE32( x86IntRegType from ) { FCMOV32( 0xDA, 0xD0 ); } +void FCMOVU32( x86IntRegType from ) { FCMOV32( 0xDA, 0xD8 ); } +void FCMOVNB32( x86IntRegType from ) { FCMOV32( 0xDB, 0xC0 ); } +void FCMOVNE32( x86IntRegType from ) { FCMOV32( 0xDB, 0xC8 ); } +void FCMOVNBE32( x86IntRegType from ) { FCMOV32( 0xDB, 0xD0 ); } +void FCMOVNU32( x86IntRegType from ) { FCMOV32( 0xDB, 0xD8 ); } diff --git a/pcsx2/x86/ix86/ix86_mmx.cpp b/pcsx2/x86/ix86/ix86_mmx.cpp index 82701894cf..9ddd9aaada 100644 --- a/pcsx2/x86/ix86/ix86_mmx.cpp +++ b/pcsx2/x86/ix86/ix86_mmx.cpp @@ -1,648 +1,648 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" -#include "ix86.h" - -/********************/ -/* MMX instructions */ -/********************/ - -// r64 = mm - -/* movq m64 to r64 */ -void MOVQMtoR( x86MMXRegType to, uptr from ) -{ - write16( 0x6F0F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* movq r64 to m64 */ -void MOVQRtoM( uptr to, x86MMXRegType from ) -{ - write16( 0x7F0F ); - ModRM( 0, from, DISP32 ); - write32(MEMADDR(to, 4)); -} - -/* pand r64 to r64 */ -void PANDRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xDB0F ); - ModRM( 3, to, from ); -} - -void PANDNRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xDF0F ); - ModRM( 3, to, from ); -} - -/* por r64 to r64 */ -void PORRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xEB0F ); - ModRM( 3, to, from ); -} - -/* pxor r64 to r64 */ -void PXORRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xEF0F ); - ModRM( 3, to, from ); -} - -/* psllq r64 to r64 */ -void PSLLQRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xF30F ); - ModRM( 3, to, from ); -} - -/* psllq m64 to r64 */ -void PSLLQMtoR( x86MMXRegType to, uptr from ) -{ - write16( 0xF30F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* psllq imm8 to r64 */ -void PSLLQItoR( x86MMXRegType to, u8 from ) -{ - write16( 0x730F ); - ModRM( 3, 6, to); - write8( from ); -} - -/* psrlq r64 to r64 */ -void PSRLQRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xD30F ); - ModRM( 3, to, from ); -} - -/* psrlq m64 to r64 */ -void PSRLQMtoR( x86MMXRegType to, uptr from ) -{ - write16( 0xD30F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* psrlq imm8 to r64 */ -void PSRLQItoR( x86MMXRegType to, u8 from ) -{ - write16( 0x730F ); - ModRM( 3, 2, to); - write8( from ); -} - -/* paddusb r64 to r64 */ -void PADDUSBRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xDC0F ); - ModRM( 3, to, from ); -} - -/* paddusb m64 to r64 */ -void PADDUSBMtoR( x86MMXRegType to, uptr from ) -{ - write16( 0xDC0F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* paddusw r64 to r64 */ -void PADDUSWRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xDD0F ); - ModRM( 3, to, from ); -} - -/* paddusw m64 to r64 */ -void PADDUSWMtoR( x86MMXRegType to, uptr from ) -{ - write16( 0xDD0F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* paddb r64 to r64 */ -void PADDBRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xFC0F ); - ModRM( 3, to, from ); -} - -/* paddb m64 to r64 */ -void PADDBMtoR( x86MMXRegType to, uptr from ) -{ - write16( 0xFC0F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* paddw r64 to r64 */ -void PADDWRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xFD0F ); - ModRM( 3, to, from ); -} - -/* paddw m64 to r64 */ -void PADDWMtoR( x86MMXRegType to, uptr from ) -{ - write16( 0xFD0F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* paddd r64 to r64 */ -void PADDDRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xFE0F ); - ModRM( 3, to, from ); -} - -/* paddd m64 to r64 */ -void PADDDMtoR( x86MMXRegType to, uptr from ) -{ - write16( 0xFE0F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* emms */ -void EMMS( void ) -{ - write16( 0x770F ); -} - -void PADDSBRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xEC0F ); - ModRM( 3, to, from ); -} - -void PADDSWRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xED0F ); - ModRM( 3, to, from ); -} - -// paddq m64 to r64 (sse2 only?) -void PADDQMtoR( x86MMXRegType to, uptr from ) -{ - write16( 0xD40F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -// paddq r64 to r64 (sse2 only?) -void PADDQRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xD40F ); - ModRM( 3, to, from ); -} - -void PSUBSBRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xE80F ); - ModRM( 3, to, from ); -} - -void PSUBSWRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xE90F ); - ModRM( 3, to, from ); -} - - -void PSUBBRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xF80F ); - ModRM( 3, to, from ); -} - -void PSUBWRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xF90F ); - ModRM( 3, to, from ); -} - -void PSUBDRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xFA0F ); - ModRM( 3, to, from ); -} - -void PSUBDMtoR( x86MMXRegType to, uptr from ) -{ - write16( 0xFA0F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -void PSUBUSBRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xD80F ); - ModRM( 3, to, from ); -} - -void PSUBUSWRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xD90F ); - ModRM( 3, to, from ); -} - -// psubq m64 to r64 (sse2 only?) -void PSUBQMtoR( x86MMXRegType to, uptr from ) -{ - write16( 0xFB0F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -// psubq r64 to r64 (sse2 only?) -void PSUBQRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xFB0F ); - ModRM( 3, to, from ); -} - -// pmuludq m64 to r64 (sse2 only?) -void PMULUDQMtoR( x86MMXRegType to, uptr from ) -{ - write16( 0xF40F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -// pmuludq r64 to r64 (sse2 only?) -void PMULUDQRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xF40F ); - ModRM( 3, to, from ); -} - -void PCMPEQBRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0x740F ); - ModRM( 3, to, from ); -} - -void PCMPEQWRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0x750F ); - ModRM( 3, to, from ); -} - -void PCMPEQDRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0x760F ); - ModRM( 3, to, from ); -} - -void PCMPEQDMtoR( x86MMXRegType to, uptr from ) -{ - write16( 0x760F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -void PCMPGTBRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0x640F ); - ModRM( 3, to, from ); -} - -void PCMPGTWRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0x650F ); - ModRM( 3, to, from ); -} - -void PCMPGTDRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0x660F ); - ModRM( 3, to, from ); -} - -void PCMPGTDMtoR( x86MMXRegType to, uptr from ) -{ - write16( 0x660F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -void PSRLWItoR( x86MMXRegType to, u8 from ) -{ - write16( 0x710F ); - ModRM( 3, 2 , to ); - write8( from ); -} - -void PSRLDItoR( x86MMXRegType to, u8 from ) -{ - write16( 0x720F ); - ModRM( 3, 2 , to ); - write8( from ); -} - -void PSRLDRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xD20F ); - ModRM( 3, to, from ); -} - -void PSLLWItoR( x86MMXRegType to, u8 from ) -{ - write16( 0x710F ); - ModRM( 3, 6 , to ); - write8( from ); -} - -void PSLLDItoR( x86MMXRegType to, u8 from ) -{ - write16( 0x720F ); - ModRM( 3, 6 , to ); - write8( from ); -} - -void PSLLDRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xF20F ); - ModRM( 3, to, from ); -} - -void PSRAWItoR( x86MMXRegType to, u8 from ) -{ - write16( 0x710F ); - ModRM( 3, 4 , to ); - write8( from ); -} - -void PSRADItoR( x86MMXRegType to, u8 from ) -{ - write16( 0x720F ); - ModRM( 3, 4 , to ); - write8( from ); -} - -void PSRADRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0xE20F ); - ModRM( 3, to, from ); -} - -/* por m64 to r64 */ -void PORMtoR( x86MMXRegType to, uptr from ) -{ - write16( 0xEB0F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* pxor m64 to r64 */ -void PXORMtoR( x86MMXRegType to, uptr from ) -{ - write16( 0xEF0F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* pand m64 to r64 */ -void PANDMtoR( x86MMXRegType to, uptr from ) -{ - //u64 rip = (u64)x86Ptr + 7; - write16( 0xDB0F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -void PANDNMtoR( x86MMXRegType to, uptr from ) -{ - write16( 0xDF0F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -void PUNPCKHDQRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0x6A0F ); - ModRM( 3, to, from ); -} - -void PUNPCKHDQMtoR( x86MMXRegType to, uptr from ) -{ - write16( 0x6A0F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -void PUNPCKLDQRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0x620F ); - ModRM( 3, to, from ); -} - -void PUNPCKLDQMtoR( x86MMXRegType to, uptr from ) -{ - write16( 0x620F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -void MOVQ64ItoR( x86MMXRegType reg, u64 i ) -{ - MOVQMtoR( reg, ( uptr )(x86Ptr) + 2 + 7 ); - JMP8( 8 ); - write64( i ); -} - -void MOVQRtoR( x86MMXRegType to, x86MMXRegType from ) -{ - write16( 0x6F0F ); - ModRM( 3, to, from ); -} - -void MOVQRmtoROffset( x86MMXRegType to, x86IntRegType from, u32 offset ) -{ - write16( 0x6F0F ); - - if( offset < 128 ) { - ModRM( 1, to, from ); - write8(offset); - } - else { - ModRM( 2, to, from ); - write32(offset); - } -} - -void MOVQRtoRmOffset( x86IntRegType to, x86MMXRegType from, u32 offset ) -{ - write16( 0x7F0F ); - - if( offset < 128 ) { - ModRM( 1, from , to ); - write8(offset); - } - else { - ModRM( 2, from, to ); - write32(offset); - } -} - -/* movd m32 to r64 */ -void MOVDMtoMMX( x86MMXRegType to, uptr from ) -{ - write16( 0x6E0F ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -/* movd r64 to m32 */ -void MOVDMMXtoM( uptr to, x86MMXRegType from ) -{ - write16( 0x7E0F ); - ModRM( 0, from, DISP32 ); - write32( MEMADDR(to, 4) ); -} - -void MOVD32RtoMMX( x86MMXRegType to, x86IntRegType from ) -{ - write16( 0x6E0F ); - ModRM( 3, to, from ); -} - -void MOVD32RmtoMMX( x86MMXRegType to, x86IntRegType from ) -{ - write16( 0x6E0F ); - ModRM( 0, to, from ); -} - -void MOVD32RmOffsettoMMX( x86MMXRegType to, x86IntRegType from, u32 offset ) -{ - write16( 0x6E0F ); - - if( offset < 128 ) { - ModRM( 1, to, from ); - write8(offset); - } - else { - ModRM( 2, to, from ); - write32(offset); - } -} - -void MOVD32MMXtoR( x86IntRegType to, x86MMXRegType from ) -{ - write16( 0x7E0F ); - ModRM( 3, from, to ); -} - -void MOVD32MMXtoRm( x86IntRegType to, x86MMXRegType from ) -{ - write16( 0x7E0F ); - ModRM( 0, from, to ); - if( to >= 4 ) { - // no idea why - assert( to == ESP ); - write8(0x24); - } - -} - -void MOVD32MMXtoRmOffset( x86IntRegType to, x86MMXRegType from, u32 offset ) -{ - write16( 0x7E0F ); - - if( offset < 128 ) { - ModRM( 1, from, to ); - write8(offset); - } - else { - ModRM( 2, from, to ); - write32(offset); - } -} - -///* movd r32 to r64 */ -//void MOVD32MMXtoMMX( x86MMXRegType to, x86MMXRegType from ) -//{ -// write16( 0x6E0F ); -// ModRM( 3, to, from ); -//} -// -///* movq r64 to r32 */ -//void MOVD64MMXtoMMX( x86MMXRegType to, x86MMXRegType from ) -//{ -// write16( 0x7E0F ); -// ModRM( 3, from, to ); -//} - -// untested -void PACKSSWBMMXtoMMX(x86MMXRegType to, x86MMXRegType from) -{ - write16( 0x630F ); - ModRM( 3, to, from ); -} - -void PACKSSDWMMXtoMMX(x86MMXRegType to, x86MMXRegType from) -{ - write16( 0x6B0F ); - ModRM( 3, to, from ); -} - -void PMOVMSKBMMXtoR(x86IntRegType to, x86MMXRegType from) -{ - write16( 0xD70F ); - ModRM( 3, to, from ); -} - -void PINSRWRtoMMX( x86MMXRegType to, x86SSERegType from, u8 imm8 ) -{ - if (to > 7 || from > 7) Rex(1, to >> 3, 0, from >> 3); - write16( 0xc40f ); - ModRM( 3, to, from ); - write8( imm8 ); -} - -void PSHUFWRtoR(x86MMXRegType to, x86MMXRegType from, u8 imm8) -{ - write16(0x700f); - ModRM( 3, to, from ); - write8(imm8); -} - -void PSHUFWMtoR(x86MMXRegType to, uptr from, u8 imm8) -{ - write16( 0x700f ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); - write8(imm8); -} - -void MASKMOVQRtoR(x86MMXRegType to, x86MMXRegType from) -{ - write16(0xf70f); - ModRM( 3, to, from ); -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" +#include "ix86.h" + +/********************/ +/* MMX instructions */ +/********************/ + +// r64 = mm + +/* movq m64 to r64 */ +void MOVQMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0x6F0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* movq r64 to m64 */ +void MOVQRtoM( uptr to, x86MMXRegType from ) +{ + write16( 0x7F0F ); + ModRM( 0, from, DISP32 ); + write32(MEMADDR(to, 4)); +} + +/* pand r64 to r64 */ +void PANDRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xDB0F ); + ModRM( 3, to, from ); +} + +void PANDNRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xDF0F ); + ModRM( 3, to, from ); +} + +/* por r64 to r64 */ +void PORRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xEB0F ); + ModRM( 3, to, from ); +} + +/* pxor r64 to r64 */ +void PXORRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xEF0F ); + ModRM( 3, to, from ); +} + +/* psllq r64 to r64 */ +void PSLLQRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xF30F ); + ModRM( 3, to, from ); +} + +/* psllq m64 to r64 */ +void PSLLQMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xF30F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* psllq imm8 to r64 */ +void PSLLQItoR( x86MMXRegType to, u8 from ) +{ + write16( 0x730F ); + ModRM( 3, 6, to); + write8( from ); +} + +/* psrlq r64 to r64 */ +void PSRLQRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xD30F ); + ModRM( 3, to, from ); +} + +/* psrlq m64 to r64 */ +void PSRLQMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xD30F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* psrlq imm8 to r64 */ +void PSRLQItoR( x86MMXRegType to, u8 from ) +{ + write16( 0x730F ); + ModRM( 3, 2, to); + write8( from ); +} + +/* paddusb r64 to r64 */ +void PADDUSBRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xDC0F ); + ModRM( 3, to, from ); +} + +/* paddusb m64 to r64 */ +void PADDUSBMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xDC0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* paddusw r64 to r64 */ +void PADDUSWRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xDD0F ); + ModRM( 3, to, from ); +} + +/* paddusw m64 to r64 */ +void PADDUSWMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xDD0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* paddb r64 to r64 */ +void PADDBRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xFC0F ); + ModRM( 3, to, from ); +} + +/* paddb m64 to r64 */ +void PADDBMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xFC0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* paddw r64 to r64 */ +void PADDWRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xFD0F ); + ModRM( 3, to, from ); +} + +/* paddw m64 to r64 */ +void PADDWMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xFD0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* paddd r64 to r64 */ +void PADDDRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xFE0F ); + ModRM( 3, to, from ); +} + +/* paddd m64 to r64 */ +void PADDDMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xFE0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* emms */ +void EMMS( void ) +{ + write16( 0x770F ); +} + +void PADDSBRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xEC0F ); + ModRM( 3, to, from ); +} + +void PADDSWRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xED0F ); + ModRM( 3, to, from ); +} + +// paddq m64 to r64 (sse2 only?) +void PADDQMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xD40F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// paddq r64 to r64 (sse2 only?) +void PADDQRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xD40F ); + ModRM( 3, to, from ); +} + +void PSUBSBRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xE80F ); + ModRM( 3, to, from ); +} + +void PSUBSWRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xE90F ); + ModRM( 3, to, from ); +} + + +void PSUBBRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xF80F ); + ModRM( 3, to, from ); +} + +void PSUBWRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xF90F ); + ModRM( 3, to, from ); +} + +void PSUBDRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xFA0F ); + ModRM( 3, to, from ); +} + +void PSUBDMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xFA0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +void PSUBUSBRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xD80F ); + ModRM( 3, to, from ); +} + +void PSUBUSWRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xD90F ); + ModRM( 3, to, from ); +} + +// psubq m64 to r64 (sse2 only?) +void PSUBQMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xFB0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// psubq r64 to r64 (sse2 only?) +void PSUBQRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xFB0F ); + ModRM( 3, to, from ); +} + +// pmuludq m64 to r64 (sse2 only?) +void PMULUDQMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xF40F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +// pmuludq r64 to r64 (sse2 only?) +void PMULUDQRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xF40F ); + ModRM( 3, to, from ); +} + +void PCMPEQBRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0x740F ); + ModRM( 3, to, from ); +} + +void PCMPEQWRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0x750F ); + ModRM( 3, to, from ); +} + +void PCMPEQDRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0x760F ); + ModRM( 3, to, from ); +} + +void PCMPEQDMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0x760F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +void PCMPGTBRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0x640F ); + ModRM( 3, to, from ); +} + +void PCMPGTWRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0x650F ); + ModRM( 3, to, from ); +} + +void PCMPGTDRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0x660F ); + ModRM( 3, to, from ); +} + +void PCMPGTDMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0x660F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +void PSRLWItoR( x86MMXRegType to, u8 from ) +{ + write16( 0x710F ); + ModRM( 3, 2 , to ); + write8( from ); +} + +void PSRLDItoR( x86MMXRegType to, u8 from ) +{ + write16( 0x720F ); + ModRM( 3, 2 , to ); + write8( from ); +} + +void PSRLDRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xD20F ); + ModRM( 3, to, from ); +} + +void PSLLWItoR( x86MMXRegType to, u8 from ) +{ + write16( 0x710F ); + ModRM( 3, 6 , to ); + write8( from ); +} + +void PSLLDItoR( x86MMXRegType to, u8 from ) +{ + write16( 0x720F ); + ModRM( 3, 6 , to ); + write8( from ); +} + +void PSLLDRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xF20F ); + ModRM( 3, to, from ); +} + +void PSRAWItoR( x86MMXRegType to, u8 from ) +{ + write16( 0x710F ); + ModRM( 3, 4 , to ); + write8( from ); +} + +void PSRADItoR( x86MMXRegType to, u8 from ) +{ + write16( 0x720F ); + ModRM( 3, 4 , to ); + write8( from ); +} + +void PSRADRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0xE20F ); + ModRM( 3, to, from ); +} + +/* por m64 to r64 */ +void PORMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xEB0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* pxor m64 to r64 */ +void PXORMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xEF0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* pand m64 to r64 */ +void PANDMtoR( x86MMXRegType to, uptr from ) +{ + //u64 rip = (u64)x86Ptr + 7; + write16( 0xDB0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +void PANDNMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0xDF0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +void PUNPCKHDQRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0x6A0F ); + ModRM( 3, to, from ); +} + +void PUNPCKHDQMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0x6A0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +void PUNPCKLDQRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0x620F ); + ModRM( 3, to, from ); +} + +void PUNPCKLDQMtoR( x86MMXRegType to, uptr from ) +{ + write16( 0x620F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +void MOVQ64ItoR( x86MMXRegType reg, u64 i ) +{ + MOVQMtoR( reg, ( uptr )(x86Ptr) + 2 + 7 ); + JMP8( 8 ); + write64( i ); +} + +void MOVQRtoR( x86MMXRegType to, x86MMXRegType from ) +{ + write16( 0x6F0F ); + ModRM( 3, to, from ); +} + +void MOVQRmtoROffset( x86MMXRegType to, x86IntRegType from, u32 offset ) +{ + write16( 0x6F0F ); + + if( offset < 128 ) { + ModRM( 1, to, from ); + write8(offset); + } + else { + ModRM( 2, to, from ); + write32(offset); + } +} + +void MOVQRtoRmOffset( x86IntRegType to, x86MMXRegType from, u32 offset ) +{ + write16( 0x7F0F ); + + if( offset < 128 ) { + ModRM( 1, from , to ); + write8(offset); + } + else { + ModRM( 2, from, to ); + write32(offset); + } +} + +/* movd m32 to r64 */ +void MOVDMtoMMX( x86MMXRegType to, uptr from ) +{ + write16( 0x6E0F ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +/* movd r64 to m32 */ +void MOVDMMXtoM( uptr to, x86MMXRegType from ) +{ + write16( 0x7E0F ); + ModRM( 0, from, DISP32 ); + write32( MEMADDR(to, 4) ); +} + +void MOVD32RtoMMX( x86MMXRegType to, x86IntRegType from ) +{ + write16( 0x6E0F ); + ModRM( 3, to, from ); +} + +void MOVD32RmtoMMX( x86MMXRegType to, x86IntRegType from ) +{ + write16( 0x6E0F ); + ModRM( 0, to, from ); +} + +void MOVD32RmOffsettoMMX( x86MMXRegType to, x86IntRegType from, u32 offset ) +{ + write16( 0x6E0F ); + + if( offset < 128 ) { + ModRM( 1, to, from ); + write8(offset); + } + else { + ModRM( 2, to, from ); + write32(offset); + } +} + +void MOVD32MMXtoR( x86IntRegType to, x86MMXRegType from ) +{ + write16( 0x7E0F ); + ModRM( 3, from, to ); +} + +void MOVD32MMXtoRm( x86IntRegType to, x86MMXRegType from ) +{ + write16( 0x7E0F ); + ModRM( 0, from, to ); + if( to >= 4 ) { + // no idea why + assert( to == ESP ); + write8(0x24); + } + +} + +void MOVD32MMXtoRmOffset( x86IntRegType to, x86MMXRegType from, u32 offset ) +{ + write16( 0x7E0F ); + + if( offset < 128 ) { + ModRM( 1, from, to ); + write8(offset); + } + else { + ModRM( 2, from, to ); + write32(offset); + } +} + +///* movd r32 to r64 */ +//void MOVD32MMXtoMMX( x86MMXRegType to, x86MMXRegType from ) +//{ +// write16( 0x6E0F ); +// ModRM( 3, to, from ); +//} +// +///* movq r64 to r32 */ +//void MOVD64MMXtoMMX( x86MMXRegType to, x86MMXRegType from ) +//{ +// write16( 0x7E0F ); +// ModRM( 3, from, to ); +//} + +// untested +void PACKSSWBMMXtoMMX(x86MMXRegType to, x86MMXRegType from) +{ + write16( 0x630F ); + ModRM( 3, to, from ); +} + +void PACKSSDWMMXtoMMX(x86MMXRegType to, x86MMXRegType from) +{ + write16( 0x6B0F ); + ModRM( 3, to, from ); +} + +void PMOVMSKBMMXtoR(x86IntRegType to, x86MMXRegType from) +{ + write16( 0xD70F ); + ModRM( 3, to, from ); +} + +void PINSRWRtoMMX( x86MMXRegType to, x86SSERegType from, u8 imm8 ) +{ + if (to > 7 || from > 7) Rex(1, to >> 3, 0, from >> 3); + write16( 0xc40f ); + ModRM( 3, to, from ); + write8( imm8 ); +} + +void PSHUFWRtoR(x86MMXRegType to, x86MMXRegType from, u8 imm8) +{ + write16(0x700f); + ModRM( 3, to, from ); + write8(imm8); +} + +void PSHUFWMtoR(x86MMXRegType to, uptr from, u8 imm8) +{ + write16( 0x700f ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); + write8(imm8); +} + +void MASKMOVQRtoR(x86MMXRegType to, x86MMXRegType from) +{ + write16(0xf70f); + ModRM( 3, to, from ); +} diff --git a/pcsx2/x86/ix86/ix86_sse.cpp b/pcsx2/x86/ix86/ix86_sse.cpp index 2d81d5a27e..b76a24c0ff 100644 --- a/pcsx2/x86/ix86/ix86_sse.cpp +++ b/pcsx2/x86/ix86/ix86_sse.cpp @@ -1,1387 +1,1387 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" -#include "ix86.h" - -PCSX2_ALIGNED16(unsigned int p[4]); -PCSX2_ALIGNED16(unsigned int p2[4]); -PCSX2_ALIGNED16(float f[4]); - - -XMMSSEType g_xmmtypes[XMMREGS] = { XMMT_INT }; - -/********************/ -/* SSE instructions */ -/********************/ - -#define SSEMtoR( code, overb ) \ - assert( to < XMMREGS ) ; \ - RexR(0, to); \ - write16( code ); \ - ModRM( 0, to, DISP32 ); \ - write32( MEMADDR(from, 4 + overb) ); \ - -#define SSERtoM( code, overb ) \ - assert( from < XMMREGS) ; \ - RexR(0, from); \ - write16( code ); \ - ModRM( 0, from, DISP32 ); \ - write32( MEMADDR(to, 4 + overb) ); \ - -#define SSE_SS_MtoR( code, overb ) \ - assert( to < XMMREGS ) ; \ - write8( 0xf3 ); \ - RexR(0, to); \ - write16( code ); \ - ModRM( 0, to, DISP32 ); \ - write32( MEMADDR(from, 4 + overb) ); \ - -#define SSE_SS_RtoM( code, overb ) \ - assert( from < XMMREGS) ; \ - write8( 0xf3 ); \ - RexR(0, from); \ - write16( code ); \ - ModRM( 0, from, DISP32 ); \ - write32( MEMADDR(to, 4 + overb) ); \ - -#define SSERtoR( code ) \ - assert( to < XMMREGS && from < XMMREGS) ; \ - RexRB(0, to, from); \ - write16( code ); \ - ModRM( 3, to, from ); - -#define SSEMtoR66( code ) \ - write8( 0x66 ); \ - SSEMtoR( code, 0 ); - -#define SSERtoM66( code ) \ - write8( 0x66 ); \ - SSERtoM( code, 0 ); - -#define SSERtoR66( code ) \ - write8( 0x66 ); \ - SSERtoR( code ); - -#define _SSERtoR66( code ) \ - assert( to < XMMREGS && from < XMMREGS) ; \ - write8( 0x66 ); \ - RexRB(0, from, to); \ - write16( code ); \ - ModRM( 3, from, to ); - -#define SSE_SS_RtoR( code ) \ - assert( to < XMMREGS && from < XMMREGS) ; \ - write8( 0xf3 ); \ - RexRB(0, to, from); \ - write16( code ); \ - ModRM( 3, to, from ); - -#define CMPPSMtoR( op ) \ - SSEMtoR( 0xc20f, 1 ); \ - write8( op ); - -#define CMPPSRtoR( op ) \ - SSERtoR( 0xc20f ); \ - write8( op ); - -#define CMPSSMtoR( op ) \ - SSE_SS_MtoR( 0xc20f, 1 ); \ - write8( op ); - -#define CMPSSRtoR( op ) \ - SSE_SS_RtoR( 0xc20f ); \ - write8( op ); - - - -void WriteRmOffset(x86IntRegType to, int offset); -void WriteRmOffsetFrom(x86IntRegType to, x86IntRegType from, int offset); - -/* movups [r32][r32*scale] to xmm1 */ -__forceinline void SSE_MOVUPSRmStoR( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ) -{ - RexRXB(0, to, from2, from); - write16( 0x100f ); - ModRM( 0, to, 0x4 ); - SibSB( scale, from2, from ); -} - -/* movups xmm1 to [r32][r32*scale] */ -__forceinline void SSE_MOVUPSRtoRmS( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ) -{ - RexRXB(1, to, from2, from); - write16( 0x110f ); - ModRM( 0, to, 0x4 ); - SibSB( scale, from2, from ); -} - -/* movups [r32] to r32 */ -__forceinline void SSE_MOVUPSRmtoR( x86IntRegType to, x86IntRegType from ) -{ - RexRB(0, to, from); - write16( 0x100f ); - ModRM( 0, to, from ); -} - -/* movups r32 to [r32] */ -__forceinline void SSE_MOVUPSRtoRm( x86IntRegType to, x86IntRegType from ) -{ - RexRB(0, from, to); - write16( 0x110f ); - ModRM( 0, from, to ); -} - -/* movlps [r32] to r32 */ -__forceinline void SSE_MOVLPSRmtoR( x86SSERegType to, x86IntRegType from ) -{ - RexRB(1, to, from); - write16( 0x120f ); - ModRM( 0, to, from ); -} - -__forceinline void SSE_MOVLPSRmtoROffset( x86SSERegType to, x86IntRegType from, int offset ) -{ - RexRB(0, to, from); - write16( 0x120f ); - WriteRmOffsetFrom(to, from, offset); -} - -/* movaps r32 to [r32] */ -__forceinline void SSE_MOVLPSRtoRm( x86IntRegType to, x86IntRegType from ) -{ - RexRB(0, from, to); - write16( 0x130f ); - ModRM( 0, from, to ); -} - -__forceinline void SSE_MOVLPSRtoRmOffset( x86SSERegType to, x86IntRegType from, int offset ) -{ - RexRB(0, from, to); - write16( 0x130f ); - WriteRmOffsetFrom(from, to, offset); -} - -/* movaps [r32][r32*scale] to xmm1 */ -__forceinline void SSE_MOVAPSRmStoR( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ) -{ - assert( from != EBP ); - RexRXB(0, to, from2, from); - write16( 0x280f ); - ModRM( 0, to, 0x4 ); - SibSB( scale, from2, from ); -} - -/* movaps xmm1 to [r32][r32*scale] */ -__forceinline void SSE_MOVAPSRtoRmS( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ) -{ - assert( from != EBP ); - RexRXB(0, to, from2, from); - write16( 0x290f ); - ModRM( 0, to, 0x4 ); - SibSB( scale, from2, from ); -} - -// movaps [r32+offset] to r32 -__forceinline void SSE_MOVAPSRmtoROffset( x86SSERegType to, x86IntRegType from, int offset ) -{ - RexRB(0, to, from); - write16( 0x280f ); - WriteRmOffsetFrom(to, from, offset); -} - -// movaps r32 to [r32+offset] -__forceinline void SSE_MOVAPSRtoRmOffset( x86IntRegType to, x86SSERegType from, int offset ) -{ - RexRB(0, from, to); - write16( 0x290f ); - WriteRmOffsetFrom(from, to, offset); -} - -// movdqa [r32+offset] to r32 -__forceinline void SSE2_MOVDQARmtoROffset( x86SSERegType to, x86IntRegType from, int offset ) -{ - write8(0x66); - RexRB(0, to, from); - write16( 0x6f0f ); - WriteRmOffsetFrom(to, from, offset); -} - -// movdqa r32 to [r32+offset] -__forceinline void SSE2_MOVDQARtoRmOffset( x86IntRegType to, x86SSERegType from, int offset ) -{ - write8(0x66); - RexRB(0, from, to); - write16( 0x7f0f ); - WriteRmOffsetFrom(from, to, offset); -} - -// movups [r32+offset] to r32 -__forceinline void SSE_MOVUPSRmtoROffset( x86SSERegType to, x86IntRegType from, int offset ) -{ - RexRB(0, to, from); - write16( 0x100f ); - WriteRmOffsetFrom(to, from, offset); -} - -// movups r32 to [r32+offset] -__forceinline void SSE_MOVUPSRtoRmOffset( x86SSERegType to, x86IntRegType from, int offset ) -{ - RexRB(0, from, to); - write16( 0x110f ); - WriteRmOffsetFrom(from, to, offset); -} - -//**********************************************************************************/ -//MOVAPS: Move aligned Packed Single Precision FP values * -//********************************************************************************** -__forceinline void SSE_MOVAPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x280f, 0 ); } -__forceinline void SSE_MOVAPS_XMM_to_M128( uptr to, x86SSERegType from ) { SSERtoM( 0x290f, 0 ); } -__forceinline void SSE_MOVAPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { if (to != from) { SSERtoR( 0x280f ); } } - -__forceinline void SSE_MOVUPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x100f, 0 ); } -__forceinline void SSE_MOVUPS_XMM_to_M128( uptr to, x86SSERegType from ) { SSERtoM( 0x110f, 0 ); } - -__forceinline void SSE2_MOVSD_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) -{ - write8(0xf2); - SSERtoR( 0x100f); -} - -__forceinline void SSE2_MOVQ_M64_to_XMM( x86SSERegType to, uptr from ) -{ - write8(0xf3); SSEMtoR( 0x7e0f, 0); -} - -__forceinline void SSE2_MOVQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) -{ - write8(0xf3); SSERtoR( 0x7e0f); -} - -__forceinline void SSE2_MOVQ_XMM_to_M64( u32 to, x86SSERegType from ) -{ - SSERtoM66(0xd60f); -} - -__forceinline void SSE2_MOVDQ2Q_XMM_to_MM( x86MMXRegType to, x86SSERegType from) -{ - write8(0xf2); - SSERtoR( 0xd60f); -} -__forceinline void SSE2_MOVQ2DQ_MM_to_XMM( x86SSERegType to, x86MMXRegType from) -{ - write8(0xf3); - SSERtoR( 0xd60f); -} - -//**********************************************************************************/ -//MOVSS: Move Scalar Single-Precision FP value * -//********************************************************************************** -__forceinline void SSE_MOVSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x100f, 0 ); } -__forceinline void SSE_MOVSS_XMM_to_M32( u32 to, x86SSERegType from ) { SSE_SS_RtoM( 0x110f, 0 ); } -__forceinline void SSE_MOVSS_XMM_to_Rm( x86IntRegType to, x86SSERegType from ) -{ - write8(0xf3); - RexRB(0, from, to); - write16(0x110f); - ModRM(0, from, to); -} - -__forceinline void SSE_MOVSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { if (to != from) { SSE_SS_RtoR( 0x100f ); } } - -__forceinline void SSE_MOVSS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ) -{ - write8(0xf3); - RexRB(0, to, from); - write16( 0x100f ); - WriteRmOffsetFrom(to, from, offset); -} - -__forceinline void SSE_MOVSS_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ) -{ - write8(0xf3); - RexRB(0, from, to); - write16(0x110f); - WriteRmOffsetFrom(from, to, offset); -} - -__forceinline void SSE_MASKMOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xf70f ); } -//**********************************************************************************/ -//MOVLPS: Move low Packed Single-Precision FP * -//********************************************************************************** -__forceinline void SSE_MOVLPS_M64_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x120f, 0 ); } -__forceinline void SSE_MOVLPS_XMM_to_M64( u32 to, x86SSERegType from ) { SSERtoM( 0x130f, 0 ); } - -__forceinline void SSE_MOVLPS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ) -{ - RexRB(0, to, from); - write16( 0x120f ); - WriteRmOffsetFrom(to, from, offset); -} - -__forceinline void SSE_MOVLPS_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ) -{ - RexRB(0, from, to); - write16(0x130f); - WriteRmOffsetFrom(from, to, offset); -} - -///////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//MOVHPS: Move High Packed Single-Precision FP * -//********************************************************************************** -__forceinline void SSE_MOVHPS_M64_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x160f, 0 ); } -__forceinline void SSE_MOVHPS_XMM_to_M64( u32 to, x86SSERegType from ) { SSERtoM( 0x170f, 0 ); } - -__forceinline void SSE_MOVHPS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ) -{ - RexRB(0, to, from); - write16( 0x160f ); - WriteRmOffsetFrom(to, from, offset); -} - -__forceinline void SSE_MOVHPS_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ) -{ - RexRB(0, from, to); - write16(0x170f); - WriteRmOffsetFrom(from, to, offset); -} - -///////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//MOVLHPS: Moved packed Single-Precision FP low to high * -//********************************************************************************** -__forceinline void SSE_MOVLHPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x160f ); } - -////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//MOVHLPS: Moved packed Single-Precision FP High to Low * -//********************************************************************************** -__forceinline void SSE_MOVHLPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x120f ); } - -/////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//ANDPS: Logical Bit-wise AND for Single FP * -//********************************************************************************** -__forceinline void SSE_ANDPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x540f, 0 ); } -__forceinline void SSE_ANDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x540f ); } - -/////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//ANDNPS : Logical Bit-wise AND NOT of Single-precision FP values * -//********************************************************************************** -__forceinline void SSE_ANDNPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x550f, 0 ); } -__forceinline void SSE_ANDNPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR( 0x550f ); } - -///////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//RCPPS : Packed Single-Precision FP Reciprocal * -//********************************************************************************** -__forceinline void SSE_RCPPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x530f ); } -__forceinline void SSE_RCPPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x530f, 0 ); } - -__forceinline void SSE_RCPSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR(0x530f); } -__forceinline void SSE_RCPSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR(0x530f, 0); } - -////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//ORPS : Bit-wise Logical OR of Single-Precision FP Data * -//********************************************************************************** -__forceinline void SSE_ORPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x560f, 0 ); } -__forceinline void SSE_ORPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x560f ); } - -///////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//XORPS : Bitwise Logical XOR of Single-Precision FP Values * -//********************************************************************************** - -__forceinline void SSE_XORPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x570f, 0 ); } -__forceinline void SSE_XORPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x570f ); } - -/////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//ADDPS : ADD Packed Single-Precision FP Values * -//********************************************************************************** -__forceinline void SSE_ADDPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x580f, 0 ); } -__forceinline void SSE_ADDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x580f ); } - -//////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//ADDSS : ADD Scalar Single-Precision FP Values * -//********************************************************************************** -__forceinline void SSE_ADDSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x580f, 0 ); } -__forceinline void SSE_ADDSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR( 0x580f ); } - -///////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//SUBPS: Packed Single-Precision FP Subtract * -//********************************************************************************** -__forceinline void SSE_SUBPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x5c0f, 0 ); } -__forceinline void SSE_SUBPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x5c0f ); } - -/////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//SUBSS : Scalar Single-Precision FP Subtract * -//********************************************************************************** -__forceinline void SSE_SUBSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x5c0f, 0 ); } -__forceinline void SSE_SUBSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR( 0x5c0f ); } - -///////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//MULPS : Packed Single-Precision FP Multiply * -//********************************************************************************** -__forceinline void SSE_MULPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x590f, 0 ); } -__forceinline void SSE_MULPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x590f ); } - -//////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//MULSS : Scalar Single-Precision FP Multiply * -//********************************************************************************** -__forceinline void SSE_MULSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x590f, 0 ); } -__forceinline void SSE_MULSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR( 0x590f ); } - -//////////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//Packed Single-Precission FP compare (CMPccPS) * -//********************************************************************************** -//missing SSE_CMPPS_I8_to_XMM -// SSE_CMPPS_M32_to_XMM -// SSE_CMPPS_XMM_to_XMM -__forceinline void SSE_CMPEQPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 0 ); } -__forceinline void SSE_CMPEQPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 0 ); } -__forceinline void SSE_CMPLTPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 1 ); } -__forceinline void SSE_CMPLTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 1 ); } -__forceinline void SSE_CMPLEPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 2 ); } -__forceinline void SSE_CMPLEPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 2 ); } -__forceinline void SSE_CMPUNORDPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 3 ); } -__forceinline void SSE_CMPUNORDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 3 ); } -__forceinline void SSE_CMPNEPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 4 ); } -__forceinline void SSE_CMPNEPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 4 ); } -__forceinline void SSE_CMPNLTPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 5 ); } -__forceinline void SSE_CMPNLTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 5 ); } -__forceinline void SSE_CMPNLEPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 6 ); } -__forceinline void SSE_CMPNLEPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 6 ); } -__forceinline void SSE_CMPORDPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 7 ); } -__forceinline void SSE_CMPORDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 7 ); } - -/////////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//Scalar Single-Precission FP compare (CMPccSS) * -//********************************************************************************** -//missing SSE_CMPSS_I8_to_XMM -// SSE_CMPSS_M32_to_XMM -// SSE_CMPSS_XMM_to_XMM -__forceinline void SSE_CMPEQSS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 0 ); } -__forceinline void SSE_CMPEQSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 0 ); } -__forceinline void SSE_CMPLTSS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 1 ); } -__forceinline void SSE_CMPLTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 1 ); } -__forceinline void SSE_CMPLESS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 2 ); } -__forceinline void SSE_CMPLESS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 2 ); } -__forceinline void SSE_CMPUNORDSS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 3 ); } -__forceinline void SSE_CMPUNORDSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 3 ); } -__forceinline void SSE_CMPNESS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 4 ); } -__forceinline void SSE_CMPNESS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 4 ); } -__forceinline void SSE_CMPNLTSS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 5 ); } -__forceinline void SSE_CMPNLTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 5 ); } -__forceinline void SSE_CMPNLESS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 6 ); } -__forceinline void SSE_CMPNLESS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 6 ); } -__forceinline void SSE_CMPORDSS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 7 ); } -__forceinline void SSE_CMPORDSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 7 ); } - -__forceinline void SSE_UCOMISS_M32_to_XMM( x86SSERegType to, uptr from ) -{ - RexR(0, to); - write16( 0x2e0f ); - ModRM( 0, to, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -__forceinline void SSE_UCOMISS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) -{ - RexRB(0, to, from); - write16( 0x2e0f ); - ModRM( 3, to, from ); -} - -////////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//RSQRTPS : Packed Single-Precision FP Square Root Reciprocal * -//********************************************************************************** -__forceinline void SSE_RSQRTPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x520f, 0 ); } -__forceinline void SSE_RSQRTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR( 0x520f ); } - -///////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//RSQRTSS : Scalar Single-Precision FP Square Root Reciprocal * -//********************************************************************************** -__forceinline void SSE_RSQRTSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x520f, 0 ); } -__forceinline void SSE_RSQRTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSE_SS_RtoR( 0x520f ); } - -//////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//SQRTPS : Packed Single-Precision FP Square Root * -//********************************************************************************** -__forceinline void SSE_SQRTPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x510f, 0 ); } -__forceinline void SSE_SQRTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR( 0x510f ); } - -////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//SQRTSS : Scalar Single-Precision FP Square Root * -//********************************************************************************** -__forceinline void SSE_SQRTSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x510f, 0 ); } -__forceinline void SSE_SQRTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSE_SS_RtoR( 0x510f ); } - -//////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//MAXPS: Return Packed Single-Precision FP Maximum * -//********************************************************************************** -__forceinline void SSE_MAXPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x5f0f, 0 ); } -__forceinline void SSE_MAXPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x5f0f ); } - -__forceinline void SSE2_MAXPD_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0x5f0f ); } -__forceinline void SSE2_MAXPD_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0x5f0f ); } - -///////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//MAXSS: Return Scalar Single-Precision FP Maximum * -//********************************************************************************** -__forceinline void SSE_MAXSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x5f0f, 0 ); } -__forceinline void SSE_MAXSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR( 0x5f0f ); } - -///////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//CVTPI2PS: Packed Signed INT32 to Packed Single FP Conversion * -//********************************************************************************** -__forceinline void SSE_CVTPI2PS_M64_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x2a0f, 0 ); } -__forceinline void SSE_CVTPI2PS_MM_to_XMM( x86SSERegType to, x86MMXRegType from ) { SSERtoR( 0x2a0f ); } - -/////////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//CVTPS2PI: Packed Single FP to Packed Signed INT32 Conversion * -//********************************************************************************** -__forceinline void SSE_CVTPS2PI_M64_to_MM( x86MMXRegType to, uptr from ) { SSEMtoR( 0x2d0f, 0 ); } -__forceinline void SSE_CVTPS2PI_XMM_to_MM( x86MMXRegType to, x86SSERegType from ) { SSERtoR( 0x2d0f ); } - -__forceinline void SSE_CVTTSS2SI_M32_to_R32(x86IntRegType to, uptr from) { write8(0xf3); SSEMtoR(0x2c0f, 0); } -__forceinline void SSE_CVTTSS2SI_XMM_to_R32(x86IntRegType to, x86SSERegType from) -{ - write8(0xf3); - RexRB(0, to, from); - write16(0x2c0f); - ModRM(3, to, from); -} - -__forceinline void SSE_CVTSI2SS_M32_to_XMM(x86SSERegType to, uptr from) { write8(0xf3); SSEMtoR(0x2a0f, 0); } -__forceinline void SSE_CVTSI2SS_R_to_XMM(x86SSERegType to, x86IntRegType from) -{ - write8(0xf3); - RexRB(0, to, from); - write16(0x2a0f); - ModRM(3, to, from); -} - -/////////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//CVTDQ2PS: Packed Signed INT32 to Packed Single Precision FP Conversion * -//********************************************************************************** -__forceinline void SSE2_CVTDQ2PS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x5b0f, 0 ); } -__forceinline void SSE2_CVTDQ2PS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x5b0f ); } - -//**********************************************************************************/ -//CVTPS2DQ: Packed Single Precision FP to Packed Signed INT32 Conversion * -//********************************************************************************** -__forceinline void SSE2_CVTPS2DQ_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0x5b0f ); } -__forceinline void SSE2_CVTPS2DQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0x5b0f ); } - -__forceinline void SSE2_CVTTPS2DQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { write8(0xf3); SSERtoR(0x5b0f); } -///////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//MINPS: Return Packed Single-Precision FP Minimum * -//********************************************************************************** -__forceinline void SSE_MINPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x5d0f, 0 ); } -__forceinline void SSE_MINPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x5d0f ); } - -__forceinline void SSE2_MINPD_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0x5d0f ); } -__forceinline void SSE2_MINPD_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0x5d0f ); } - -////////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//MINSS: Return Scalar Single-Precision FP Minimum * -//********************************************************************************** -__forceinline void SSE_MINSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x5d0f, 0 ); } -__forceinline void SSE_MINSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR( 0x5d0f ); } - -/////////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//PMAXSW: Packed Signed Integer Word Maximum * -//********************************************************************************** -//missing - // SSE_PMAXSW_M64_to_MM -// SSE2_PMAXSW_M128_to_XMM -// SSE2_PMAXSW_XMM_to_XMM -__forceinline void SSE_PMAXSW_MM_to_MM( x86MMXRegType to, x86MMXRegType from ){ SSERtoR( 0xEE0F ); } - -/////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//PMINSW: Packed Signed Integer Word Minimum * -//********************************************************************************** -//missing - // SSE_PMINSW_M64_to_MM -// SSE2_PMINSW_M128_to_XMM -// SSE2_PMINSW_XMM_to_XMM -__forceinline void SSE_PMINSW_MM_to_MM( x86MMXRegType to, x86MMXRegType from ){ SSERtoR( 0xEA0F ); } - -////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//SHUFPS: Shuffle Packed Single-Precision FP Values * -//********************************************************************************** -__forceinline void SSE_SHUFPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ) { SSERtoR( 0xC60F ); write8( imm8 ); } -__forceinline void SSE_SHUFPS_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ) { SSEMtoR( 0xC60F, 1 ); write8( imm8 ); } - -__forceinline void SSE_SHUFPS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset, u8 imm8 ) -{ - RexRB(0, to, from); - write16(0xc60f); - WriteRmOffsetFrom(to, from, offset); - write8(imm8); -} - -//////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//PSHUFD: Shuffle Packed DoubleWords * -//********************************************************************************** -__forceinline void SSE2_PSHUFD_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ) -{ - SSERtoR66( 0x700F ); - write8( imm8 ); -} -__forceinline void SSE2_PSHUFD_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ) { SSEMtoR66( 0x700F ); write8( imm8 ); } - -__forceinline void SSE2_PSHUFLW_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ) { write8(0xF2); SSERtoR(0x700F); write8(imm8); } -__forceinline void SSE2_PSHUFLW_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ) { write8(0xF2); SSEMtoR(0x700F, 1); write8(imm8); } -__forceinline void SSE2_PSHUFHW_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ) { write8(0xF3); SSERtoR(0x700F); write8(imm8); } -__forceinline void SSE2_PSHUFHW_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ) { write8(0xF3); SSEMtoR(0x700F, 1); write8(imm8); } - -/////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//UNPCKLPS: Unpack and Interleave low Packed Single-Precision FP Data * -//********************************************************************************** -__forceinline void SSE_UNPCKLPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR(0x140f, 0); } -__forceinline void SSE_UNPCKLPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x140F ); } - -//////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//UNPCKHPS: Unpack and Interleave High Packed Single-Precision FP Data * -//********************************************************************************** -__forceinline void SSE_UNPCKHPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR(0x150f, 0); } -__forceinline void SSE_UNPCKHPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x150F ); } - -//////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//DIVPS : Packed Single-Precision FP Divide * -//********************************************************************************** -__forceinline void SSE_DIVPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x5e0F, 0 ); } -__forceinline void SSE_DIVPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x5e0F ); } - -////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//DIVSS : Scalar Single-Precision FP Divide * -//********************************************************************************** -__forceinline void SSE_DIVSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x5e0F, 0 ); } -__forceinline void SSE_DIVSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR( 0x5e0F ); } - -///////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//STMXCSR : Store Streaming SIMD Extension Control/Status * -//********************************************************************************** -__forceinline void SSE_STMXCSR( uptr from ) { - write16( 0xAE0F ); - ModRM( 0, 0x3, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -///////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//LDMXCSR : Load Streaming SIMD Extension Control/Status * -//********************************************************************************** -__forceinline void SSE_LDMXCSR( uptr from ) { - write16( 0xAE0F ); - ModRM( 0, 0x2, DISP32 ); - write32( MEMADDR(from, 4) ); -} - -///////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//PADDB,PADDW,PADDD : Add Packed Integers * -//********************************************************************************** -__forceinline void SSE2_PADDB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xFC0F ); } -__forceinline void SSE2_PADDB_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xFC0F ); } -__forceinline void SSE2_PADDW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xFD0F ); } -__forceinline void SSE2_PADDW_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xFD0F ); } -__forceinline void SSE2_PADDD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xFE0F ); } -__forceinline void SSE2_PADDD_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xFE0F ); } - -__forceinline void SSE2_PADDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xD40F ); } -__forceinline void SSE2_PADDQ_M128_to_XMM(x86SSERegType to, uptr from ) { SSEMtoR66( 0xD40F ); } - -/////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//PCMPxx: Compare Packed Integers * -//********************************************************************************** -__forceinline void SSE2_PCMPGTB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0x640F ); } -__forceinline void SSE2_PCMPGTB_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0x640F ); } -__forceinline void SSE2_PCMPGTW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0x650F ); } -__forceinline void SSE2_PCMPGTW_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0x650F ); } -__forceinline void SSE2_PCMPGTD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0x660F ); } -__forceinline void SSE2_PCMPGTD_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0x660F ); } -__forceinline void SSE2_PCMPEQB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0x740F ); } -__forceinline void SSE2_PCMPEQB_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0x740F ); } -__forceinline void SSE2_PCMPEQW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0x750F ); } -__forceinline void SSE2_PCMPEQW_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0x750F ); } -__forceinline void SSE2_PCMPEQD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ) -{ - SSERtoR66( 0x760F ); -} - -__forceinline void SSE2_PCMPEQD_M128_to_XMM(x86SSERegType to, uptr from ) -{ - SSEMtoR66( 0x760F ); -} - -//////////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//PEXTRW,PINSRW: Packed Extract/Insert Word * -//********************************************************************************** -__forceinline void SSE_PEXTRW_XMM_to_R32(x86IntRegType to, x86SSERegType from, u8 imm8 ){ SSERtoR66(0xC50F); write8( imm8 ); } -__forceinline void SSE_PINSRW_R32_to_XMM(x86SSERegType to, x86IntRegType from, u8 imm8 ){ SSERtoR66(0xC40F); write8( imm8 ); } - -//////////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//PSUBx: Subtract Packed Integers * -//********************************************************************************** -__forceinline void SSE2_PSUBB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xF80F ); } -__forceinline void SSE2_PSUBB_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xF80F ); } -__forceinline void SSE2_PSUBW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xF90F ); } -__forceinline void SSE2_PSUBW_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xF90F ); } -__forceinline void SSE2_PSUBD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xFA0F ); } -__forceinline void SSE2_PSUBD_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xFA0F ); } -__forceinline void SSE2_PSUBQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xFB0F ); } -__forceinline void SSE2_PSUBQ_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xFB0F ); } - -/////////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//MOVD: Move Dword(32bit) to /from XMM reg * -//********************************************************************************** -__forceinline void SSE2_MOVD_M32_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66(0x6E0F); } -__forceinline void SSE2_MOVD_R_to_XMM( x86SSERegType to, x86IntRegType from ) -{ - SSERtoR66(0x6E0F); -} - -__forceinline void SSE2_MOVD_Rm_to_XMM( x86SSERegType to, x86IntRegType from ) -{ - write8(0x66); - RexRB(0, to, from); - write16( 0x6e0f ); - ModRM( 0, to, from); -} - -__forceinline void SSE2_MOVD_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ) -{ - write8(0x66); - RexRB(0, to, from); - write16( 0x6e0f ); - WriteRmOffsetFrom(to, from, offset); -} - -__forceinline void SSE2_MOVD_XMM_to_M32( u32 to, x86SSERegType from ) { SSERtoM66(0x7E0F); } -__forceinline void SSE2_MOVD_XMM_to_R( x86IntRegType to, x86SSERegType from ) -{ - _SSERtoR66(0x7E0F); -} - -__forceinline void SSE2_MOVD_XMM_to_Rm( x86IntRegType to, x86SSERegType from ) -{ - write8(0x66); - RexRB(0, from, to); - write16( 0x7e0f ); - ModRM( 0, from, to ); -} - -__forceinline void SSE2_MOVD_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ) -{ - write8(0x66); - RexRB(0, from, to); - write16( 0x7e0f ); - WriteRmOffsetFrom(from, to, offset); -} - -//////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//POR : SSE Bitwise OR * -//********************************************************************************** -__forceinline void SSE2_POR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xEB0F ); } -__forceinline void SSE2_POR_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xEB0F ); } - -// logical and to &= from -__forceinline void SSE2_PAND_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xDB0F ); } -__forceinline void SSE2_PAND_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xDB0F ); } - -// to = (~to) & from -__forceinline void SSE2_PANDN_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xDF0F ); } -__forceinline void SSE2_PANDN_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xDF0F ); } - -///////////////////////////////////////////////////////////////////////////////////// -//**********************************************************************************/ -//PXOR : SSE Bitwise XOR * -//********************************************************************************** -__forceinline void SSE2_PXOR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xEF0F ); } -__forceinline void SSE2_PXOR_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xEF0F ) }; -/////////////////////////////////////////////////////////////////////////////////////// - -__forceinline void SSE2_MOVDQA_M128_to_XMM(x86SSERegType to, uptr from) {SSEMtoR66(0x6F0F); } -__forceinline void SSE2_MOVDQA_XMM_to_M128( uptr to, x86SSERegType from ){SSERtoM66(0x7F0F);} -__forceinline void SSE2_MOVDQA_XMM_to_XMM( x86SSERegType to, x86SSERegType from) { if (to != from) { SSERtoR66(0x6F0F); } } - -__forceinline void SSE2_MOVDQU_M128_to_XMM(x86SSERegType to, uptr from) { write8(0xF3); SSEMtoR(0x6F0F, 0); } -__forceinline void SSE2_MOVDQU_XMM_to_M128( uptr to, x86SSERegType from) { write8(0xF3); SSERtoM(0x7F0F, 0); } -__forceinline void SSE2_MOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from) { write8(0xF3); SSERtoR(0x6F0F); } - -// shift right logical - -__forceinline void SSE2_PSRLW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xD10F); } -__forceinline void SSE2_PSRLW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xD10F); } -__forceinline void SSE2_PSRLW_I8_to_XMM(x86SSERegType to, u8 imm8) -{ - write8( 0x66 ); - RexB(0, to); - write16( 0x710F ); - ModRM( 3, 2 , to ); - write8( imm8 ); -} - -__forceinline void SSE2_PSRLD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xD20F); } -__forceinline void SSE2_PSRLD_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xD20F); } -__forceinline void SSE2_PSRLD_I8_to_XMM(x86SSERegType to, u8 imm8) -{ - write8( 0x66 ); - RexB(0, to); - write16( 0x720F ); - ModRM( 3, 2 , to ); - write8( imm8 ); -} - -__forceinline void SSE2_PSRLQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xD30F); } -__forceinline void SSE2_PSRLQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xD30F); } -__forceinline void SSE2_PSRLQ_I8_to_XMM(x86SSERegType to, u8 imm8) -{ - write8( 0x66 ); - RexB(0, to); - write16( 0x730F ); - ModRM( 3, 2 , to ); - write8( imm8 ); -} - -__forceinline void SSE2_PSRLDQ_I8_to_XMM(x86SSERegType to, u8 imm8) -{ - write8( 0x66 ); - RexB(0, to); - write16( 0x730F ); - ModRM( 3, 3 , to ); - write8( imm8 ); -} - -// shift right arithmetic - -__forceinline void SSE2_PSRAW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xE10F); } -__forceinline void SSE2_PSRAW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xE10F); } -__forceinline void SSE2_PSRAW_I8_to_XMM(x86SSERegType to, u8 imm8) -{ - write8( 0x66 ); - RexB(0, to); - write16( 0x710F ); - ModRM( 3, 4 , to ); - write8( imm8 ); -} - -__forceinline void SSE2_PSRAD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xE20F); } -__forceinline void SSE2_PSRAD_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xE20F); } -__forceinline void SSE2_PSRAD_I8_to_XMM(x86SSERegType to, u8 imm8) -{ - write8( 0x66 ); - RexB(0, to); - write16( 0x720F ); - ModRM( 3, 4 , to ); - write8( imm8 ); -} - -// shift left logical - -__forceinline void SSE2_PSLLW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xF10F); } -__forceinline void SSE2_PSLLW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xF10F); } -__forceinline void SSE2_PSLLW_I8_to_XMM(x86SSERegType to, u8 imm8) -{ - write8( 0x66 ); - RexB(0, to); - write16( 0x710F ); - ModRM( 3, 6 , to ); - write8( imm8 ); -} - -__forceinline void SSE2_PSLLD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xF20F); } -__forceinline void SSE2_PSLLD_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xF20F); } -__forceinline void SSE2_PSLLD_I8_to_XMM(x86SSERegType to, u8 imm8) -{ - write8( 0x66 ); - RexB(0, to); - write16( 0x720F ); - ModRM( 3, 6 , to ); - write8( imm8 ); -} - -__forceinline void SSE2_PSLLQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xF30F); } -__forceinline void SSE2_PSLLQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xF30F); } -__forceinline void SSE2_PSLLQ_I8_to_XMM(x86SSERegType to, u8 imm8) -{ - write8( 0x66 ); - RexB(0, to); - write16( 0x730F ); - ModRM( 3, 6 , to ); - write8( imm8 ); -} - -__forceinline void SSE2_PSLLDQ_I8_to_XMM(x86SSERegType to, u8 imm8) -{ - write8( 0x66 ); - RexB(0, to); - write16( 0x730F ); - ModRM( 3, 7 , to ); - write8( imm8 ); -} - - -__forceinline void SSE2_PMAXSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xEE0F ); } -__forceinline void SSE2_PMAXSW_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xEE0F ); } - -__forceinline void SSE2_PMAXUB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xDE0F ); } -__forceinline void SSE2_PMAXUB_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xDE0F ); } - -__forceinline void SSE2_PMINSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xEA0F ); } -__forceinline void SSE2_PMINSW_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xEA0F ); } - -__forceinline void SSE2_PMINUB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xDA0F ); } -__forceinline void SSE2_PMINUB_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xDA0F ); } - -// - -__forceinline void SSE2_PADDSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xEC0F ); } -__forceinline void SSE2_PADDSB_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xEC0F ); } - -__forceinline void SSE2_PADDSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xED0F ); } -__forceinline void SSE2_PADDSW_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xED0F ); } - -__forceinline void SSE2_PSUBSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xE80F ); } -__forceinline void SSE2_PSUBSB_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xE80F ); } - -__forceinline void SSE2_PSUBSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xE90F ); } -__forceinline void SSE2_PSUBSW_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xE90F ); } - -__forceinline void SSE2_PSUBUSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xD80F ); } -__forceinline void SSE2_PSUBUSB_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xD80F ); } -__forceinline void SSE2_PSUBUSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xD90F ); } -__forceinline void SSE2_PSUBUSW_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xD90F ); } - -__forceinline void SSE2_PADDUSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xDC0F ); } -__forceinline void SSE2_PADDUSB_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xDC0F ); } -__forceinline void SSE2_PADDUSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xDD0F ); } -__forceinline void SSE2_PADDUSW_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xDD0F ); } - -//**********************************************************************************/ -//PACKSSWB,PACKSSDW: Pack Saturate Signed Word -//********************************************************************************** -__forceinline void SSE2_PACKSSWB_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x630F ); } -__forceinline void SSE2_PACKSSWB_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x630F ); } -__forceinline void SSE2_PACKSSDW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x6B0F ); } -__forceinline void SSE2_PACKSSDW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x6B0F ); } - -__forceinline void SSE2_PACKUSWB_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x670F ); } -__forceinline void SSE2_PACKUSWB_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x670F ); } - -//**********************************************************************************/ -//PUNPCKHWD: Unpack 16bit high -//********************************************************************************** -__forceinline void SSE2_PUNPCKLBW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x600F ); } -__forceinline void SSE2_PUNPCKLBW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x600F ); } - -__forceinline void SSE2_PUNPCKHBW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x680F ); } -__forceinline void SSE2_PUNPCKHBW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x680F ); } - -__forceinline void SSE2_PUNPCKLWD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x610F ); } -__forceinline void SSE2_PUNPCKLWD_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x610F ); } -__forceinline void SSE2_PUNPCKHWD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x690F ); } -__forceinline void SSE2_PUNPCKHWD_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x690F ); } - -__forceinline void SSE2_PUNPCKLDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x620F ); } -__forceinline void SSE2_PUNPCKLDQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x620F ); } -__forceinline void SSE2_PUNPCKHDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x6A0F ); } -__forceinline void SSE2_PUNPCKHDQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x6A0F ); } - -__forceinline void SSE2_PUNPCKLQDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x6C0F ); } -__forceinline void SSE2_PUNPCKLQDQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x6C0F ); } - -__forceinline void SSE2_PUNPCKHQDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x6D0F ); } -__forceinline void SSE2_PUNPCKHQDQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x6D0F ); } - -__forceinline void SSE2_PMULLW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0xD50F ); } -__forceinline void SSE2_PMULLW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0xD50F ); } -__forceinline void SSE2_PMULHW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0xE50F ); } -__forceinline void SSE2_PMULHW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0xE50F ); } - -__forceinline void SSE2_PMULUDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0xF40F ); } -__forceinline void SSE2_PMULUDQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0xF40F ); } - -__forceinline void SSE2_PMOVMSKB_XMM_to_R32(x86IntRegType to, x86SSERegType from) { SSERtoR66(0xD70F); } - -__forceinline void SSE_MOVMSKPS_XMM_to_R32(x86IntRegType to, x86SSERegType from) { SSERtoR(0x500F); } -__forceinline void SSE2_MOVMSKPD_XMM_to_R32(x86IntRegType to, x86SSERegType from) { SSERtoR66(0x500F); } - -__forceinline void SSE2_PMADDWD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xF50F); } - -__forceinline void SSE3_HADDPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { write8(0xf2); SSERtoR( 0x7c0f ); } -__forceinline void SSE3_HADDPS_M128_to_XMM(x86SSERegType to, uptr from){ write8(0xf2); SSEMtoR( 0x7c0f, 0 ); } - -__forceinline void SSE3_MOVSLDUP_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { - write8(0xf3); - RexRB(0, to, from); - write16( 0x120f); - ModRM( 3, to, from ); -} - -__forceinline void SSE3_MOVSLDUP_M128_to_XMM(x86SSERegType to, uptr from) { write8(0xf3); SSEMtoR(0x120f, 0); } -__forceinline void SSE3_MOVSHDUP_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { write8(0xf3); SSERtoR(0x160f); } -__forceinline void SSE3_MOVSHDUP_M128_to_XMM(x86SSERegType to, uptr from) { write8(0xf3); SSEMtoR(0x160f, 0); } - -// SSE4.1 - -__forceinline void SSE4_DPPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from, u8 imm8) -{ - write8(0x66); - write24(0x403A0F); - ModRM(3, to, from); - write8(imm8); -} - -__forceinline void SSE4_DPPS_M128_to_XMM(x86SSERegType to, uptr from, u8 imm8) -{ - write8(0x66); - write24(0x403A0F); - ModRM(0, to, DISP32); - write32(MEMADDR(from, 4)); - write8(imm8); -} - -__forceinline void SSE4_INSERTPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from, u8 imm8) -{ - write8(0x66); - RexRB(0, to, from); - write24(0x213A0F); - ModRM(3, to, from); - write8(imm8); -} - -__forceinline void SSE4_EXTRACTPS_XMM_to_R32(x86IntRegType to, x86SSERegType from, u8 imm8) -{ - write8(0x66); - RexRB(0, to, from); - write24(0x173A0F); - ModRM(3, to, from); - write8(imm8); -} - -__forceinline void SSE4_BLENDPS_XMM_to_XMM(x86IntRegType to, x86SSERegType from, u8 imm8) -{ - write8(0x66); - RexRB(0, to, from); - write24(0x0C3A0F); - ModRM(3, to, from); - write8(imm8); -} - -__forceinline void SSE4_BLENDVPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from) -{ - write8(0x66); - RexRB(0, to, from); - write24(0x14380F); - ModRM(3, to, from); -} - -__forceinline void SSE4_BLENDVPS_M128_to_XMM(x86SSERegType to, uptr from) -{ - write8(0x66); - RexR(0, to); - write24(0x14380F); - ModRM(0, to, DISP32); - write32(MEMADDR(from, 4)); -} - -__forceinline void SSE4_PMOVSXDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) -{ - write8(0x66); - RexRB(0, to, from); - write24(0x25380F); - ModRM(3, to, from); -} - -__forceinline void SSE4_PINSRD_R32_to_XMM(x86SSERegType to, x86IntRegType from, u8 imm8) -{ - write8(0x66); - RexRB(0, to, from); - write24(0x223A0F); - ModRM(3, to, from); - write8(imm8); -} - -__forceinline void SSE4_PMAXSD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) -{ - write8(0x66); - RexRB(0, to, from); - write24(0x3D380F); - ModRM(3, to, from); -} - -__forceinline void SSE4_PMINSD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) -{ - write8(0x66); - RexRB(0, to, from); - write24(0x39380F); - ModRM(3, to, from); -} - -__forceinline void SSE4_PMAXUD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) -{ - write8(0x66); - RexRB(0, to, from); - write24(0x3F380F); - ModRM(3, to, from); -} - -__forceinline void SSE4_PMINUD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) -{ - write8(0x66); - RexRB(0, to, from); - write24(0x3B380F); - ModRM(3, to, from); -} - -__forceinline void SSE4_PMAXSD_M128_to_XMM(x86SSERegType to, uptr from) -{ - write8(0x66); - RexR(0, to); - write24(0x3D380F); - ModRM( 0, to, DISP32 ); - write32(MEMADDR(from, 4)); -} - -__forceinline void SSE4_PMINSD_M128_to_XMM(x86SSERegType to, uptr from) -{ - write8(0x66); - RexR(0, to); - write24(0x39380F); - ModRM( 0, to, DISP32 ); - write32(MEMADDR(from, 4)); -} - -__forceinline void SSE4_PMAXUD_M128_to_XMM(x86SSERegType to, uptr from) -{ - write8(0x66); - RexR(0, to); - write24(0x3F380F); - ModRM( 0, to, DISP32 ); - write32(MEMADDR(from, 4)); -} - -__forceinline void SSE4_PMINUD_M128_to_XMM(x86SSERegType to, uptr from) -{ - write8(0x66); - RexR(0, to); - write24(0x3B380F); - ModRM( 0, to, DISP32 ); - write32(MEMADDR(from, 4)); -} - -// SSE-X -__forceinline void SSEX_MOVDQA_M128_to_XMM( x86SSERegType to, uptr from ) -{ - if( g_xmmtypes[to] == XMMT_INT ) SSE2_MOVDQA_M128_to_XMM(to, from); - else SSE_MOVAPS_M128_to_XMM(to, from); -} - -__forceinline void SSEX_MOVDQA_XMM_to_M128( uptr to, x86SSERegType from ) -{ - if( g_xmmtypes[from] == XMMT_INT ) SSE2_MOVDQA_XMM_to_M128(to, from); - else SSE_MOVAPS_XMM_to_M128(to, from); -} - -__forceinline void SSEX_MOVDQA_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) -{ - if( g_xmmtypes[from] == XMMT_INT ) SSE2_MOVDQA_XMM_to_XMM(to, from); - else SSE_MOVAPS_XMM_to_XMM(to, from); -} - -__forceinline void SSEX_MOVDQARmtoROffset( x86SSERegType to, x86IntRegType from, int offset ) -{ - if( g_xmmtypes[to] == XMMT_INT ) SSE2_MOVDQARmtoROffset(to, from, offset); - else SSE_MOVAPSRmtoROffset(to, from, offset); -} - -__forceinline void SSEX_MOVDQARtoRmOffset( x86IntRegType to, x86SSERegType from, int offset ) -{ - if( g_xmmtypes[from] == XMMT_INT ) SSE2_MOVDQARtoRmOffset(to, from, offset); - else SSE_MOVAPSRtoRmOffset(to, from, offset); -} - -__forceinline void SSEX_MOVDQU_M128_to_XMM( x86SSERegType to, uptr from ) -{ - if( g_xmmtypes[to] == XMMT_INT ) SSE2_MOVDQU_M128_to_XMM(to, from); - else SSE_MOVAPS_M128_to_XMM(to, from); -} - -__forceinline void SSEX_MOVDQU_XMM_to_M128( uptr to, x86SSERegType from ) -{ - if( g_xmmtypes[from] == XMMT_INT ) SSE2_MOVDQU_XMM_to_M128(to, from); - else SSE_MOVAPS_XMM_to_M128(to, from); -} - -__forceinline void SSEX_MOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) -{ - if( g_xmmtypes[from] == XMMT_INT ) SSE2_MOVDQU_XMM_to_XMM(to, from); - else SSE_MOVAPS_XMM_to_XMM(to, from); -} - -__forceinline void SSEX_MOVD_M32_to_XMM( x86SSERegType to, uptr from ) -{ - if( g_xmmtypes[to] == XMMT_INT ) SSE2_MOVD_M32_to_XMM(to, from); - else SSE_MOVSS_M32_to_XMM(to, from); -} - -__forceinline void SSEX_MOVD_XMM_to_M32( u32 to, x86SSERegType from ) -{ - if( g_xmmtypes[from] == XMMT_INT ) SSE2_MOVD_XMM_to_M32(to, from); - else SSE_MOVSS_XMM_to_M32(to, from); -} - -__forceinline void SSEX_MOVD_XMM_to_Rm( x86IntRegType to, x86SSERegType from ) -{ - if( g_xmmtypes[from] == XMMT_INT ) SSE2_MOVD_XMM_to_Rm(to, from); - else SSE_MOVSS_XMM_to_Rm(to, from); -} - -__forceinline void SSEX_MOVD_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ) -{ - if( g_xmmtypes[to] == XMMT_INT ) SSE2_MOVD_RmOffset_to_XMM(to, from, offset); - else SSE_MOVSS_RmOffset_to_XMM(to, from, offset); -} - -__forceinline void SSEX_MOVD_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ) -{ - if( g_xmmtypes[from] == XMMT_INT ) SSE2_MOVD_XMM_to_RmOffset(to, from, offset); - else SSE_MOVSS_XMM_to_RmOffset(to, from, offset); -} - -__forceinline void SSEX_POR_M128_to_XMM( x86SSERegType to, uptr from ) -{ - if( g_xmmtypes[to] == XMMT_INT ) SSE2_POR_M128_to_XMM(to, from); - else SSE_ORPS_M128_to_XMM(to, from); -} - -__forceinline void SSEX_POR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) -{ - if( g_xmmtypes[from] == XMMT_INT ) SSE2_POR_XMM_to_XMM(to, from); - else SSE_ORPS_XMM_to_XMM(to, from); -} - -__forceinline void SSEX_PXOR_M128_to_XMM( x86SSERegType to, uptr from ) -{ - if( g_xmmtypes[to] == XMMT_INT ) SSE2_PXOR_M128_to_XMM(to, from); - else SSE_XORPS_M128_to_XMM(to, from); -} - -__forceinline void SSEX_PXOR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) -{ - if( g_xmmtypes[from] == XMMT_INT ) SSE2_PXOR_XMM_to_XMM(to, from); - else SSE_XORPS_XMM_to_XMM(to, from); -} - -__forceinline void SSEX_PAND_M128_to_XMM( x86SSERegType to, uptr from ) -{ - if( g_xmmtypes[to] == XMMT_INT ) SSE2_PAND_M128_to_XMM(to, from); - else SSE_ANDPS_M128_to_XMM(to, from); -} - -__forceinline void SSEX_PAND_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) -{ - if( g_xmmtypes[from] == XMMT_INT ) SSE2_PAND_XMM_to_XMM(to, from); - else SSE_ANDPS_XMM_to_XMM(to, from); -} - -__forceinline void SSEX_PANDN_M128_to_XMM( x86SSERegType to, uptr from ) -{ - if( g_xmmtypes[to] == XMMT_INT ) SSE2_PANDN_M128_to_XMM(to, from); - else SSE_ANDNPS_M128_to_XMM(to, from); -} - -__forceinline void SSEX_PANDN_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) -{ - if( g_xmmtypes[from] == XMMT_INT ) SSE2_PANDN_XMM_to_XMM(to, from); - else SSE_ANDNPS_XMM_to_XMM(to, from); -} - -__forceinline void SSEX_PUNPCKLDQ_M128_to_XMM(x86SSERegType to, uptr from) -{ - if( g_xmmtypes[to] == XMMT_INT ) SSE2_PUNPCKLDQ_M128_to_XMM(to, from); - else SSE_UNPCKLPS_M128_to_XMM(to, from); -} - -__forceinline void SSEX_PUNPCKLDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) -{ - if( g_xmmtypes[from] == XMMT_INT ) SSE2_PUNPCKLDQ_XMM_to_XMM(to, from); - else SSE_UNPCKLPS_XMM_to_XMM(to, from); -} - -__forceinline void SSEX_PUNPCKHDQ_M128_to_XMM(x86SSERegType to, uptr from) -{ - if( g_xmmtypes[to] == XMMT_INT ) SSE2_PUNPCKHDQ_M128_to_XMM(to, from); - else SSE_UNPCKHPS_M128_to_XMM(to, from); -} - -__forceinline void SSEX_PUNPCKHDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) -{ - if( g_xmmtypes[from] == XMMT_INT ) SSE2_PUNPCKHDQ_XMM_to_XMM(to, from); - else SSE_UNPCKHPS_XMM_to_XMM(to, from); -} - -__forceinline void SSEX_MOVHLPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) -{ - if( g_xmmtypes[from] == XMMT_INT ) { - SSE2_PUNPCKHQDQ_XMM_to_XMM(to, from); - if( to != from ) SSE2_PSHUFD_XMM_to_XMM(to, to, 0x4e); - } - else { - SSE_MOVHLPS_XMM_to_XMM(to, from); - } +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" +#include "ix86.h" + +PCSX2_ALIGNED16(unsigned int p[4]); +PCSX2_ALIGNED16(unsigned int p2[4]); +PCSX2_ALIGNED16(float f[4]); + + +XMMSSEType g_xmmtypes[XMMREGS] = { XMMT_INT }; + +/********************/ +/* SSE instructions */ +/********************/ + +#define SSEMtoR( code, overb ) \ + assert( to < XMMREGS ) ; \ + RexR(0, to); \ + write16( code ); \ + ModRM( 0, to, DISP32 ); \ + write32( MEMADDR(from, 4 + overb) ); \ + +#define SSERtoM( code, overb ) \ + assert( from < XMMREGS) ; \ + RexR(0, from); \ + write16( code ); \ + ModRM( 0, from, DISP32 ); \ + write32( MEMADDR(to, 4 + overb) ); \ + +#define SSE_SS_MtoR( code, overb ) \ + assert( to < XMMREGS ) ; \ + write8( 0xf3 ); \ + RexR(0, to); \ + write16( code ); \ + ModRM( 0, to, DISP32 ); \ + write32( MEMADDR(from, 4 + overb) ); \ + +#define SSE_SS_RtoM( code, overb ) \ + assert( from < XMMREGS) ; \ + write8( 0xf3 ); \ + RexR(0, from); \ + write16( code ); \ + ModRM( 0, from, DISP32 ); \ + write32( MEMADDR(to, 4 + overb) ); \ + +#define SSERtoR( code ) \ + assert( to < XMMREGS && from < XMMREGS) ; \ + RexRB(0, to, from); \ + write16( code ); \ + ModRM( 3, to, from ); + +#define SSEMtoR66( code ) \ + write8( 0x66 ); \ + SSEMtoR( code, 0 ); + +#define SSERtoM66( code ) \ + write8( 0x66 ); \ + SSERtoM( code, 0 ); + +#define SSERtoR66( code ) \ + write8( 0x66 ); \ + SSERtoR( code ); + +#define _SSERtoR66( code ) \ + assert( to < XMMREGS && from < XMMREGS) ; \ + write8( 0x66 ); \ + RexRB(0, from, to); \ + write16( code ); \ + ModRM( 3, from, to ); + +#define SSE_SS_RtoR( code ) \ + assert( to < XMMREGS && from < XMMREGS) ; \ + write8( 0xf3 ); \ + RexRB(0, to, from); \ + write16( code ); \ + ModRM( 3, to, from ); + +#define CMPPSMtoR( op ) \ + SSEMtoR( 0xc20f, 1 ); \ + write8( op ); + +#define CMPPSRtoR( op ) \ + SSERtoR( 0xc20f ); \ + write8( op ); + +#define CMPSSMtoR( op ) \ + SSE_SS_MtoR( 0xc20f, 1 ); \ + write8( op ); + +#define CMPSSRtoR( op ) \ + SSE_SS_RtoR( 0xc20f ); \ + write8( op ); + + + +void WriteRmOffset(x86IntRegType to, int offset); +void WriteRmOffsetFrom(x86IntRegType to, x86IntRegType from, int offset); + +/* movups [r32][r32*scale] to xmm1 */ +__forceinline void SSE_MOVUPSRmStoR( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ) +{ + RexRXB(0, to, from2, from); + write16( 0x100f ); + ModRM( 0, to, 0x4 ); + SibSB( scale, from2, from ); +} + +/* movups xmm1 to [r32][r32*scale] */ +__forceinline void SSE_MOVUPSRtoRmS( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ) +{ + RexRXB(1, to, from2, from); + write16( 0x110f ); + ModRM( 0, to, 0x4 ); + SibSB( scale, from2, from ); +} + +/* movups [r32] to r32 */ +__forceinline void SSE_MOVUPSRmtoR( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0, to, from); + write16( 0x100f ); + ModRM( 0, to, from ); +} + +/* movups r32 to [r32] */ +__forceinline void SSE_MOVUPSRtoRm( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0, from, to); + write16( 0x110f ); + ModRM( 0, from, to ); +} + +/* movlps [r32] to r32 */ +__forceinline void SSE_MOVLPSRmtoR( x86SSERegType to, x86IntRegType from ) +{ + RexRB(1, to, from); + write16( 0x120f ); + ModRM( 0, to, from ); +} + +__forceinline void SSE_MOVLPSRmtoROffset( x86SSERegType to, x86IntRegType from, int offset ) +{ + RexRB(0, to, from); + write16( 0x120f ); + WriteRmOffsetFrom(to, from, offset); +} + +/* movaps r32 to [r32] */ +__forceinline void SSE_MOVLPSRtoRm( x86IntRegType to, x86IntRegType from ) +{ + RexRB(0, from, to); + write16( 0x130f ); + ModRM( 0, from, to ); +} + +__forceinline void SSE_MOVLPSRtoRmOffset( x86SSERegType to, x86IntRegType from, int offset ) +{ + RexRB(0, from, to); + write16( 0x130f ); + WriteRmOffsetFrom(from, to, offset); +} + +/* movaps [r32][r32*scale] to xmm1 */ +__forceinline void SSE_MOVAPSRmStoR( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ) +{ + assert( from != EBP ); + RexRXB(0, to, from2, from); + write16( 0x280f ); + ModRM( 0, to, 0x4 ); + SibSB( scale, from2, from ); +} + +/* movaps xmm1 to [r32][r32*scale] */ +__forceinline void SSE_MOVAPSRtoRmS( x86SSERegType to, x86IntRegType from, x86IntRegType from2, int scale ) +{ + assert( from != EBP ); + RexRXB(0, to, from2, from); + write16( 0x290f ); + ModRM( 0, to, 0x4 ); + SibSB( scale, from2, from ); +} + +// movaps [r32+offset] to r32 +__forceinline void SSE_MOVAPSRmtoROffset( x86SSERegType to, x86IntRegType from, int offset ) +{ + RexRB(0, to, from); + write16( 0x280f ); + WriteRmOffsetFrom(to, from, offset); +} + +// movaps r32 to [r32+offset] +__forceinline void SSE_MOVAPSRtoRmOffset( x86IntRegType to, x86SSERegType from, int offset ) +{ + RexRB(0, from, to); + write16( 0x290f ); + WriteRmOffsetFrom(from, to, offset); +} + +// movdqa [r32+offset] to r32 +__forceinline void SSE2_MOVDQARmtoROffset( x86SSERegType to, x86IntRegType from, int offset ) +{ + write8(0x66); + RexRB(0, to, from); + write16( 0x6f0f ); + WriteRmOffsetFrom(to, from, offset); +} + +// movdqa r32 to [r32+offset] +__forceinline void SSE2_MOVDQARtoRmOffset( x86IntRegType to, x86SSERegType from, int offset ) +{ + write8(0x66); + RexRB(0, from, to); + write16( 0x7f0f ); + WriteRmOffsetFrom(from, to, offset); +} + +// movups [r32+offset] to r32 +__forceinline void SSE_MOVUPSRmtoROffset( x86SSERegType to, x86IntRegType from, int offset ) +{ + RexRB(0, to, from); + write16( 0x100f ); + WriteRmOffsetFrom(to, from, offset); +} + +// movups r32 to [r32+offset] +__forceinline void SSE_MOVUPSRtoRmOffset( x86SSERegType to, x86IntRegType from, int offset ) +{ + RexRB(0, from, to); + write16( 0x110f ); + WriteRmOffsetFrom(from, to, offset); +} + +//**********************************************************************************/ +//MOVAPS: Move aligned Packed Single Precision FP values * +//********************************************************************************** +__forceinline void SSE_MOVAPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x280f, 0 ); } +__forceinline void SSE_MOVAPS_XMM_to_M128( uptr to, x86SSERegType from ) { SSERtoM( 0x290f, 0 ); } +__forceinline void SSE_MOVAPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { if (to != from) { SSERtoR( 0x280f ); } } + +__forceinline void SSE_MOVUPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x100f, 0 ); } +__forceinline void SSE_MOVUPS_XMM_to_M128( uptr to, x86SSERegType from ) { SSERtoM( 0x110f, 0 ); } + +__forceinline void SSE2_MOVSD_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + write8(0xf2); + SSERtoR( 0x100f); +} + +__forceinline void SSE2_MOVQ_M64_to_XMM( x86SSERegType to, uptr from ) +{ + write8(0xf3); SSEMtoR( 0x7e0f, 0); +} + +__forceinline void SSE2_MOVQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + write8(0xf3); SSERtoR( 0x7e0f); +} + +__forceinline void SSE2_MOVQ_XMM_to_M64( u32 to, x86SSERegType from ) +{ + SSERtoM66(0xd60f); +} + +__forceinline void SSE2_MOVDQ2Q_XMM_to_MM( x86MMXRegType to, x86SSERegType from) +{ + write8(0xf2); + SSERtoR( 0xd60f); +} +__forceinline void SSE2_MOVQ2DQ_MM_to_XMM( x86SSERegType to, x86MMXRegType from) +{ + write8(0xf3); + SSERtoR( 0xd60f); +} + +//**********************************************************************************/ +//MOVSS: Move Scalar Single-Precision FP value * +//********************************************************************************** +__forceinline void SSE_MOVSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x100f, 0 ); } +__forceinline void SSE_MOVSS_XMM_to_M32( u32 to, x86SSERegType from ) { SSE_SS_RtoM( 0x110f, 0 ); } +__forceinline void SSE_MOVSS_XMM_to_Rm( x86IntRegType to, x86SSERegType from ) +{ + write8(0xf3); + RexRB(0, from, to); + write16(0x110f); + ModRM(0, from, to); +} + +__forceinline void SSE_MOVSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { if (to != from) { SSE_SS_RtoR( 0x100f ); } } + +__forceinline void SSE_MOVSS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ) +{ + write8(0xf3); + RexRB(0, to, from); + write16( 0x100f ); + WriteRmOffsetFrom(to, from, offset); +} + +__forceinline void SSE_MOVSS_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ) +{ + write8(0xf3); + RexRB(0, from, to); + write16(0x110f); + WriteRmOffsetFrom(from, to, offset); +} + +__forceinline void SSE_MASKMOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xf70f ); } +//**********************************************************************************/ +//MOVLPS: Move low Packed Single-Precision FP * +//********************************************************************************** +__forceinline void SSE_MOVLPS_M64_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x120f, 0 ); } +__forceinline void SSE_MOVLPS_XMM_to_M64( u32 to, x86SSERegType from ) { SSERtoM( 0x130f, 0 ); } + +__forceinline void SSE_MOVLPS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ) +{ + RexRB(0, to, from); + write16( 0x120f ); + WriteRmOffsetFrom(to, from, offset); +} + +__forceinline void SSE_MOVLPS_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ) +{ + RexRB(0, from, to); + write16(0x130f); + WriteRmOffsetFrom(from, to, offset); +} + +///////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MOVHPS: Move High Packed Single-Precision FP * +//********************************************************************************** +__forceinline void SSE_MOVHPS_M64_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x160f, 0 ); } +__forceinline void SSE_MOVHPS_XMM_to_M64( u32 to, x86SSERegType from ) { SSERtoM( 0x170f, 0 ); } + +__forceinline void SSE_MOVHPS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ) +{ + RexRB(0, to, from); + write16( 0x160f ); + WriteRmOffsetFrom(to, from, offset); +} + +__forceinline void SSE_MOVHPS_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ) +{ + RexRB(0, from, to); + write16(0x170f); + WriteRmOffsetFrom(from, to, offset); +} + +///////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MOVLHPS: Moved packed Single-Precision FP low to high * +//********************************************************************************** +__forceinline void SSE_MOVLHPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x160f ); } + +////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MOVHLPS: Moved packed Single-Precision FP High to Low * +//********************************************************************************** +__forceinline void SSE_MOVHLPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x120f ); } + +/////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//ANDPS: Logical Bit-wise AND for Single FP * +//********************************************************************************** +__forceinline void SSE_ANDPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x540f, 0 ); } +__forceinline void SSE_ANDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x540f ); } + +/////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//ANDNPS : Logical Bit-wise AND NOT of Single-precision FP values * +//********************************************************************************** +__forceinline void SSE_ANDNPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x550f, 0 ); } +__forceinline void SSE_ANDNPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR( 0x550f ); } + +///////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//RCPPS : Packed Single-Precision FP Reciprocal * +//********************************************************************************** +__forceinline void SSE_RCPPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x530f ); } +__forceinline void SSE_RCPPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x530f, 0 ); } + +__forceinline void SSE_RCPSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR(0x530f); } +__forceinline void SSE_RCPSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR(0x530f, 0); } + +////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//ORPS : Bit-wise Logical OR of Single-Precision FP Data * +//********************************************************************************** +__forceinline void SSE_ORPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x560f, 0 ); } +__forceinline void SSE_ORPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x560f ); } + +///////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//XORPS : Bitwise Logical XOR of Single-Precision FP Values * +//********************************************************************************** + +__forceinline void SSE_XORPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x570f, 0 ); } +__forceinline void SSE_XORPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x570f ); } + +/////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//ADDPS : ADD Packed Single-Precision FP Values * +//********************************************************************************** +__forceinline void SSE_ADDPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x580f, 0 ); } +__forceinline void SSE_ADDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x580f ); } + +//////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//ADDSS : ADD Scalar Single-Precision FP Values * +//********************************************************************************** +__forceinline void SSE_ADDSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x580f, 0 ); } +__forceinline void SSE_ADDSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR( 0x580f ); } + +///////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//SUBPS: Packed Single-Precision FP Subtract * +//********************************************************************************** +__forceinline void SSE_SUBPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x5c0f, 0 ); } +__forceinline void SSE_SUBPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x5c0f ); } + +/////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//SUBSS : Scalar Single-Precision FP Subtract * +//********************************************************************************** +__forceinline void SSE_SUBSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x5c0f, 0 ); } +__forceinline void SSE_SUBSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR( 0x5c0f ); } + +///////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MULPS : Packed Single-Precision FP Multiply * +//********************************************************************************** +__forceinline void SSE_MULPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x590f, 0 ); } +__forceinline void SSE_MULPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x590f ); } + +//////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MULSS : Scalar Single-Precision FP Multiply * +//********************************************************************************** +__forceinline void SSE_MULSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x590f, 0 ); } +__forceinline void SSE_MULSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR( 0x590f ); } + +//////////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//Packed Single-Precission FP compare (CMPccPS) * +//********************************************************************************** +//missing SSE_CMPPS_I8_to_XMM +// SSE_CMPPS_M32_to_XMM +// SSE_CMPPS_XMM_to_XMM +__forceinline void SSE_CMPEQPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 0 ); } +__forceinline void SSE_CMPEQPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 0 ); } +__forceinline void SSE_CMPLTPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 1 ); } +__forceinline void SSE_CMPLTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 1 ); } +__forceinline void SSE_CMPLEPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 2 ); } +__forceinline void SSE_CMPLEPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 2 ); } +__forceinline void SSE_CMPUNORDPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 3 ); } +__forceinline void SSE_CMPUNORDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 3 ); } +__forceinline void SSE_CMPNEPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 4 ); } +__forceinline void SSE_CMPNEPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 4 ); } +__forceinline void SSE_CMPNLTPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 5 ); } +__forceinline void SSE_CMPNLTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 5 ); } +__forceinline void SSE_CMPNLEPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 6 ); } +__forceinline void SSE_CMPNLEPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 6 ); } +__forceinline void SSE_CMPORDPS_M128_to_XMM( x86SSERegType to, uptr from ) { CMPPSMtoR( 7 ); } +__forceinline void SSE_CMPORDPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPPSRtoR( 7 ); } + +/////////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//Scalar Single-Precission FP compare (CMPccSS) * +//********************************************************************************** +//missing SSE_CMPSS_I8_to_XMM +// SSE_CMPSS_M32_to_XMM +// SSE_CMPSS_XMM_to_XMM +__forceinline void SSE_CMPEQSS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 0 ); } +__forceinline void SSE_CMPEQSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 0 ); } +__forceinline void SSE_CMPLTSS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 1 ); } +__forceinline void SSE_CMPLTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 1 ); } +__forceinline void SSE_CMPLESS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 2 ); } +__forceinline void SSE_CMPLESS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 2 ); } +__forceinline void SSE_CMPUNORDSS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 3 ); } +__forceinline void SSE_CMPUNORDSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 3 ); } +__forceinline void SSE_CMPNESS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 4 ); } +__forceinline void SSE_CMPNESS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 4 ); } +__forceinline void SSE_CMPNLTSS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 5 ); } +__forceinline void SSE_CMPNLTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 5 ); } +__forceinline void SSE_CMPNLESS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 6 ); } +__forceinline void SSE_CMPNLESS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 6 ); } +__forceinline void SSE_CMPORDSS_M32_to_XMM( x86SSERegType to, uptr from ) { CMPSSMtoR( 7 ); } +__forceinline void SSE_CMPORDSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { CMPSSRtoR( 7 ); } + +__forceinline void SSE_UCOMISS_M32_to_XMM( x86SSERegType to, uptr from ) +{ + RexR(0, to); + write16( 0x2e0f ); + ModRM( 0, to, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +__forceinline void SSE_UCOMISS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + RexRB(0, to, from); + write16( 0x2e0f ); + ModRM( 3, to, from ); +} + +////////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//RSQRTPS : Packed Single-Precision FP Square Root Reciprocal * +//********************************************************************************** +__forceinline void SSE_RSQRTPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x520f, 0 ); } +__forceinline void SSE_RSQRTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR( 0x520f ); } + +///////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//RSQRTSS : Scalar Single-Precision FP Square Root Reciprocal * +//********************************************************************************** +__forceinline void SSE_RSQRTSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x520f, 0 ); } +__forceinline void SSE_RSQRTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSE_SS_RtoR( 0x520f ); } + +//////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//SQRTPS : Packed Single-Precision FP Square Root * +//********************************************************************************** +__forceinline void SSE_SQRTPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x510f, 0 ); } +__forceinline void SSE_SQRTPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR( 0x510f ); } + +////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//SQRTSS : Scalar Single-Precision FP Square Root * +//********************************************************************************** +__forceinline void SSE_SQRTSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x510f, 0 ); } +__forceinline void SSE_SQRTSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSE_SS_RtoR( 0x510f ); } + +//////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MAXPS: Return Packed Single-Precision FP Maximum * +//********************************************************************************** +__forceinline void SSE_MAXPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x5f0f, 0 ); } +__forceinline void SSE_MAXPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x5f0f ); } + +__forceinline void SSE2_MAXPD_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0x5f0f ); } +__forceinline void SSE2_MAXPD_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0x5f0f ); } + +///////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MAXSS: Return Scalar Single-Precision FP Maximum * +//********************************************************************************** +__forceinline void SSE_MAXSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x5f0f, 0 ); } +__forceinline void SSE_MAXSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR( 0x5f0f ); } + +///////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//CVTPI2PS: Packed Signed INT32 to Packed Single FP Conversion * +//********************************************************************************** +__forceinline void SSE_CVTPI2PS_M64_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x2a0f, 0 ); } +__forceinline void SSE_CVTPI2PS_MM_to_XMM( x86SSERegType to, x86MMXRegType from ) { SSERtoR( 0x2a0f ); } + +/////////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//CVTPS2PI: Packed Single FP to Packed Signed INT32 Conversion * +//********************************************************************************** +__forceinline void SSE_CVTPS2PI_M64_to_MM( x86MMXRegType to, uptr from ) { SSEMtoR( 0x2d0f, 0 ); } +__forceinline void SSE_CVTPS2PI_XMM_to_MM( x86MMXRegType to, x86SSERegType from ) { SSERtoR( 0x2d0f ); } + +__forceinline void SSE_CVTTSS2SI_M32_to_R32(x86IntRegType to, uptr from) { write8(0xf3); SSEMtoR(0x2c0f, 0); } +__forceinline void SSE_CVTTSS2SI_XMM_to_R32(x86IntRegType to, x86SSERegType from) +{ + write8(0xf3); + RexRB(0, to, from); + write16(0x2c0f); + ModRM(3, to, from); +} + +__forceinline void SSE_CVTSI2SS_M32_to_XMM(x86SSERegType to, uptr from) { write8(0xf3); SSEMtoR(0x2a0f, 0); } +__forceinline void SSE_CVTSI2SS_R_to_XMM(x86SSERegType to, x86IntRegType from) +{ + write8(0xf3); + RexRB(0, to, from); + write16(0x2a0f); + ModRM(3, to, from); +} + +/////////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//CVTDQ2PS: Packed Signed INT32 to Packed Single Precision FP Conversion * +//********************************************************************************** +__forceinline void SSE2_CVTDQ2PS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x5b0f, 0 ); } +__forceinline void SSE2_CVTDQ2PS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x5b0f ); } + +//**********************************************************************************/ +//CVTPS2DQ: Packed Single Precision FP to Packed Signed INT32 Conversion * +//********************************************************************************** +__forceinline void SSE2_CVTPS2DQ_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0x5b0f ); } +__forceinline void SSE2_CVTPS2DQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0x5b0f ); } + +__forceinline void SSE2_CVTTPS2DQ_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { write8(0xf3); SSERtoR(0x5b0f); } +///////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MINPS: Return Packed Single-Precision FP Minimum * +//********************************************************************************** +__forceinline void SSE_MINPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x5d0f, 0 ); } +__forceinline void SSE_MINPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x5d0f ); } + +__forceinline void SSE2_MINPD_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0x5d0f ); } +__forceinline void SSE2_MINPD_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0x5d0f ); } + +////////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MINSS: Return Scalar Single-Precision FP Minimum * +//********************************************************************************** +__forceinline void SSE_MINSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x5d0f, 0 ); } +__forceinline void SSE_MINSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR( 0x5d0f ); } + +/////////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//PMAXSW: Packed Signed Integer Word Maximum * +//********************************************************************************** +//missing + // SSE_PMAXSW_M64_to_MM +// SSE2_PMAXSW_M128_to_XMM +// SSE2_PMAXSW_XMM_to_XMM +__forceinline void SSE_PMAXSW_MM_to_MM( x86MMXRegType to, x86MMXRegType from ){ SSERtoR( 0xEE0F ); } + +/////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//PMINSW: Packed Signed Integer Word Minimum * +//********************************************************************************** +//missing + // SSE_PMINSW_M64_to_MM +// SSE2_PMINSW_M128_to_XMM +// SSE2_PMINSW_XMM_to_XMM +__forceinline void SSE_PMINSW_MM_to_MM( x86MMXRegType to, x86MMXRegType from ){ SSERtoR( 0xEA0F ); } + +////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//SHUFPS: Shuffle Packed Single-Precision FP Values * +//********************************************************************************** +__forceinline void SSE_SHUFPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ) { SSERtoR( 0xC60F ); write8( imm8 ); } +__forceinline void SSE_SHUFPS_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ) { SSEMtoR( 0xC60F, 1 ); write8( imm8 ); } + +__forceinline void SSE_SHUFPS_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset, u8 imm8 ) +{ + RexRB(0, to, from); + write16(0xc60f); + WriteRmOffsetFrom(to, from, offset); + write8(imm8); +} + +//////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//PSHUFD: Shuffle Packed DoubleWords * +//********************************************************************************** +__forceinline void SSE2_PSHUFD_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ) +{ + SSERtoR66( 0x700F ); + write8( imm8 ); +} +__forceinline void SSE2_PSHUFD_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ) { SSEMtoR66( 0x700F ); write8( imm8 ); } + +__forceinline void SSE2_PSHUFLW_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ) { write8(0xF2); SSERtoR(0x700F); write8(imm8); } +__forceinline void SSE2_PSHUFLW_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ) { write8(0xF2); SSEMtoR(0x700F, 1); write8(imm8); } +__forceinline void SSE2_PSHUFHW_XMM_to_XMM( x86SSERegType to, x86SSERegType from, u8 imm8 ) { write8(0xF3); SSERtoR(0x700F); write8(imm8); } +__forceinline void SSE2_PSHUFHW_M128_to_XMM( x86SSERegType to, uptr from, u8 imm8 ) { write8(0xF3); SSEMtoR(0x700F, 1); write8(imm8); } + +/////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//UNPCKLPS: Unpack and Interleave low Packed Single-Precision FP Data * +//********************************************************************************** +__forceinline void SSE_UNPCKLPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR(0x140f, 0); } +__forceinline void SSE_UNPCKLPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x140F ); } + +//////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//UNPCKHPS: Unpack and Interleave High Packed Single-Precision FP Data * +//********************************************************************************** +__forceinline void SSE_UNPCKHPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR(0x150f, 0); } +__forceinline void SSE_UNPCKHPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x150F ); } + +//////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//DIVPS : Packed Single-Precision FP Divide * +//********************************************************************************** +__forceinline void SSE_DIVPS_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR( 0x5e0F, 0 ); } +__forceinline void SSE_DIVPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR( 0x5e0F ); } + +////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//DIVSS : Scalar Single-Precision FP Divide * +//********************************************************************************** +__forceinline void SSE_DIVSS_M32_to_XMM( x86SSERegType to, uptr from ) { SSE_SS_MtoR( 0x5e0F, 0 ); } +__forceinline void SSE_DIVSS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSE_SS_RtoR( 0x5e0F ); } + +///////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//STMXCSR : Store Streaming SIMD Extension Control/Status * +//********************************************************************************** +__forceinline void SSE_STMXCSR( uptr from ) { + write16( 0xAE0F ); + ModRM( 0, 0x3, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +///////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//LDMXCSR : Load Streaming SIMD Extension Control/Status * +//********************************************************************************** +__forceinline void SSE_LDMXCSR( uptr from ) { + write16( 0xAE0F ); + ModRM( 0, 0x2, DISP32 ); + write32( MEMADDR(from, 4) ); +} + +///////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//PADDB,PADDW,PADDD : Add Packed Integers * +//********************************************************************************** +__forceinline void SSE2_PADDB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xFC0F ); } +__forceinline void SSE2_PADDB_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xFC0F ); } +__forceinline void SSE2_PADDW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xFD0F ); } +__forceinline void SSE2_PADDW_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xFD0F ); } +__forceinline void SSE2_PADDD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xFE0F ); } +__forceinline void SSE2_PADDD_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xFE0F ); } + +__forceinline void SSE2_PADDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xD40F ); } +__forceinline void SSE2_PADDQ_M128_to_XMM(x86SSERegType to, uptr from ) { SSEMtoR66( 0xD40F ); } + +/////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//PCMPxx: Compare Packed Integers * +//********************************************************************************** +__forceinline void SSE2_PCMPGTB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0x640F ); } +__forceinline void SSE2_PCMPGTB_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0x640F ); } +__forceinline void SSE2_PCMPGTW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0x650F ); } +__forceinline void SSE2_PCMPGTW_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0x650F ); } +__forceinline void SSE2_PCMPGTD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0x660F ); } +__forceinline void SSE2_PCMPGTD_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0x660F ); } +__forceinline void SSE2_PCMPEQB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0x740F ); } +__forceinline void SSE2_PCMPEQB_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0x740F ); } +__forceinline void SSE2_PCMPEQW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0x750F ); } +__forceinline void SSE2_PCMPEQW_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0x750F ); } +__forceinline void SSE2_PCMPEQD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ) +{ + SSERtoR66( 0x760F ); +} + +__forceinline void SSE2_PCMPEQD_M128_to_XMM(x86SSERegType to, uptr from ) +{ + SSEMtoR66( 0x760F ); +} + +//////////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//PEXTRW,PINSRW: Packed Extract/Insert Word * +//********************************************************************************** +__forceinline void SSE_PEXTRW_XMM_to_R32(x86IntRegType to, x86SSERegType from, u8 imm8 ){ SSERtoR66(0xC50F); write8( imm8 ); } +__forceinline void SSE_PINSRW_R32_to_XMM(x86SSERegType to, x86IntRegType from, u8 imm8 ){ SSERtoR66(0xC40F); write8( imm8 ); } + +//////////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//PSUBx: Subtract Packed Integers * +//********************************************************************************** +__forceinline void SSE2_PSUBB_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xF80F ); } +__forceinline void SSE2_PSUBB_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xF80F ); } +__forceinline void SSE2_PSUBW_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xF90F ); } +__forceinline void SSE2_PSUBW_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xF90F ); } +__forceinline void SSE2_PSUBD_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xFA0F ); } +__forceinline void SSE2_PSUBD_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xFA0F ); } +__forceinline void SSE2_PSUBQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xFB0F ); } +__forceinline void SSE2_PSUBQ_M128_to_XMM(x86SSERegType to, uptr from ){ SSEMtoR66( 0xFB0F ); } + +/////////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//MOVD: Move Dword(32bit) to /from XMM reg * +//********************************************************************************** +__forceinline void SSE2_MOVD_M32_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66(0x6E0F); } +__forceinline void SSE2_MOVD_R_to_XMM( x86SSERegType to, x86IntRegType from ) +{ + SSERtoR66(0x6E0F); +} + +__forceinline void SSE2_MOVD_Rm_to_XMM( x86SSERegType to, x86IntRegType from ) +{ + write8(0x66); + RexRB(0, to, from); + write16( 0x6e0f ); + ModRM( 0, to, from); +} + +__forceinline void SSE2_MOVD_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ) +{ + write8(0x66); + RexRB(0, to, from); + write16( 0x6e0f ); + WriteRmOffsetFrom(to, from, offset); +} + +__forceinline void SSE2_MOVD_XMM_to_M32( u32 to, x86SSERegType from ) { SSERtoM66(0x7E0F); } +__forceinline void SSE2_MOVD_XMM_to_R( x86IntRegType to, x86SSERegType from ) +{ + _SSERtoR66(0x7E0F); +} + +__forceinline void SSE2_MOVD_XMM_to_Rm( x86IntRegType to, x86SSERegType from ) +{ + write8(0x66); + RexRB(0, from, to); + write16( 0x7e0f ); + ModRM( 0, from, to ); +} + +__forceinline void SSE2_MOVD_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ) +{ + write8(0x66); + RexRB(0, from, to); + write16( 0x7e0f ); + WriteRmOffsetFrom(from, to, offset); +} + +//////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//POR : SSE Bitwise OR * +//********************************************************************************** +__forceinline void SSE2_POR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xEB0F ); } +__forceinline void SSE2_POR_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xEB0F ); } + +// logical and to &= from +__forceinline void SSE2_PAND_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xDB0F ); } +__forceinline void SSE2_PAND_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xDB0F ); } + +// to = (~to) & from +__forceinline void SSE2_PANDN_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xDF0F ); } +__forceinline void SSE2_PANDN_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xDF0F ); } + +///////////////////////////////////////////////////////////////////////////////////// +//**********************************************************************************/ +//PXOR : SSE Bitwise XOR * +//********************************************************************************** +__forceinline void SSE2_PXOR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xEF0F ); } +__forceinline void SSE2_PXOR_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xEF0F ) }; +/////////////////////////////////////////////////////////////////////////////////////// + +__forceinline void SSE2_MOVDQA_M128_to_XMM(x86SSERegType to, uptr from) {SSEMtoR66(0x6F0F); } +__forceinline void SSE2_MOVDQA_XMM_to_M128( uptr to, x86SSERegType from ){SSERtoM66(0x7F0F);} +__forceinline void SSE2_MOVDQA_XMM_to_XMM( x86SSERegType to, x86SSERegType from) { if (to != from) { SSERtoR66(0x6F0F); } } + +__forceinline void SSE2_MOVDQU_M128_to_XMM(x86SSERegType to, uptr from) { write8(0xF3); SSEMtoR(0x6F0F, 0); } +__forceinline void SSE2_MOVDQU_XMM_to_M128( uptr to, x86SSERegType from) { write8(0xF3); SSERtoM(0x7F0F, 0); } +__forceinline void SSE2_MOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from) { write8(0xF3); SSERtoR(0x6F0F); } + +// shift right logical + +__forceinline void SSE2_PSRLW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xD10F); } +__forceinline void SSE2_PSRLW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xD10F); } +__forceinline void SSE2_PSRLW_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x710F ); + ModRM( 3, 2 , to ); + write8( imm8 ); +} + +__forceinline void SSE2_PSRLD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xD20F); } +__forceinline void SSE2_PSRLD_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xD20F); } +__forceinline void SSE2_PSRLD_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x720F ); + ModRM( 3, 2 , to ); + write8( imm8 ); +} + +__forceinline void SSE2_PSRLQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xD30F); } +__forceinline void SSE2_PSRLQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xD30F); } +__forceinline void SSE2_PSRLQ_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x730F ); + ModRM( 3, 2 , to ); + write8( imm8 ); +} + +__forceinline void SSE2_PSRLDQ_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x730F ); + ModRM( 3, 3 , to ); + write8( imm8 ); +} + +// shift right arithmetic + +__forceinline void SSE2_PSRAW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xE10F); } +__forceinline void SSE2_PSRAW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xE10F); } +__forceinline void SSE2_PSRAW_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x710F ); + ModRM( 3, 4 , to ); + write8( imm8 ); +} + +__forceinline void SSE2_PSRAD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xE20F); } +__forceinline void SSE2_PSRAD_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xE20F); } +__forceinline void SSE2_PSRAD_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x720F ); + ModRM( 3, 4 , to ); + write8( imm8 ); +} + +// shift left logical + +__forceinline void SSE2_PSLLW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xF10F); } +__forceinline void SSE2_PSLLW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xF10F); } +__forceinline void SSE2_PSLLW_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x710F ); + ModRM( 3, 6 , to ); + write8( imm8 ); +} + +__forceinline void SSE2_PSLLD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xF20F); } +__forceinline void SSE2_PSLLD_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xF20F); } +__forceinline void SSE2_PSLLD_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x720F ); + ModRM( 3, 6 , to ); + write8( imm8 ); +} + +__forceinline void SSE2_PSLLQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xF30F); } +__forceinline void SSE2_PSLLQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66(0xF30F); } +__forceinline void SSE2_PSLLQ_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x730F ); + ModRM( 3, 6 , to ); + write8( imm8 ); +} + +__forceinline void SSE2_PSLLDQ_I8_to_XMM(x86SSERegType to, u8 imm8) +{ + write8( 0x66 ); + RexB(0, to); + write16( 0x730F ); + ModRM( 3, 7 , to ); + write8( imm8 ); +} + + +__forceinline void SSE2_PMAXSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xEE0F ); } +__forceinline void SSE2_PMAXSW_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xEE0F ); } + +__forceinline void SSE2_PMAXUB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xDE0F ); } +__forceinline void SSE2_PMAXUB_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xDE0F ); } + +__forceinline void SSE2_PMINSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xEA0F ); } +__forceinline void SSE2_PMINSW_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xEA0F ); } + +__forceinline void SSE2_PMINUB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xDA0F ); } +__forceinline void SSE2_PMINUB_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xDA0F ); } + +// + +__forceinline void SSE2_PADDSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xEC0F ); } +__forceinline void SSE2_PADDSB_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xEC0F ); } + +__forceinline void SSE2_PADDSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xED0F ); } +__forceinline void SSE2_PADDSW_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xED0F ); } + +__forceinline void SSE2_PSUBSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xE80F ); } +__forceinline void SSE2_PSUBSB_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xE80F ); } + +__forceinline void SSE2_PSUBSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ){ SSERtoR66( 0xE90F ); } +__forceinline void SSE2_PSUBSW_M128_to_XMM( x86SSERegType to, uptr from ){ SSEMtoR66( 0xE90F ); } + +__forceinline void SSE2_PSUBUSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xD80F ); } +__forceinline void SSE2_PSUBUSB_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xD80F ); } +__forceinline void SSE2_PSUBUSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xD90F ); } +__forceinline void SSE2_PSUBUSW_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xD90F ); } + +__forceinline void SSE2_PADDUSB_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xDC0F ); } +__forceinline void SSE2_PADDUSB_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xDC0F ); } +__forceinline void SSE2_PADDUSW_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) { SSERtoR66( 0xDD0F ); } +__forceinline void SSE2_PADDUSW_M128_to_XMM( x86SSERegType to, uptr from ) { SSEMtoR66( 0xDD0F ); } + +//**********************************************************************************/ +//PACKSSWB,PACKSSDW: Pack Saturate Signed Word +//********************************************************************************** +__forceinline void SSE2_PACKSSWB_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x630F ); } +__forceinline void SSE2_PACKSSWB_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x630F ); } +__forceinline void SSE2_PACKSSDW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x6B0F ); } +__forceinline void SSE2_PACKSSDW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x6B0F ); } + +__forceinline void SSE2_PACKUSWB_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x670F ); } +__forceinline void SSE2_PACKUSWB_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x670F ); } + +//**********************************************************************************/ +//PUNPCKHWD: Unpack 16bit high +//********************************************************************************** +__forceinline void SSE2_PUNPCKLBW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x600F ); } +__forceinline void SSE2_PUNPCKLBW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x600F ); } + +__forceinline void SSE2_PUNPCKHBW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x680F ); } +__forceinline void SSE2_PUNPCKHBW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x680F ); } + +__forceinline void SSE2_PUNPCKLWD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x610F ); } +__forceinline void SSE2_PUNPCKLWD_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x610F ); } +__forceinline void SSE2_PUNPCKHWD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x690F ); } +__forceinline void SSE2_PUNPCKHWD_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x690F ); } + +__forceinline void SSE2_PUNPCKLDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x620F ); } +__forceinline void SSE2_PUNPCKLDQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x620F ); } +__forceinline void SSE2_PUNPCKHDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x6A0F ); } +__forceinline void SSE2_PUNPCKHDQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x6A0F ); } + +__forceinline void SSE2_PUNPCKLQDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x6C0F ); } +__forceinline void SSE2_PUNPCKLQDQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x6C0F ); } + +__forceinline void SSE2_PUNPCKHQDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0x6D0F ); } +__forceinline void SSE2_PUNPCKHQDQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0x6D0F ); } + +__forceinline void SSE2_PMULLW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0xD50F ); } +__forceinline void SSE2_PMULLW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0xD50F ); } +__forceinline void SSE2_PMULHW_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0xE50F ); } +__forceinline void SSE2_PMULHW_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0xE50F ); } + +__forceinline void SSE2_PMULUDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66( 0xF40F ); } +__forceinline void SSE2_PMULUDQ_M128_to_XMM(x86SSERegType to, uptr from) { SSEMtoR66( 0xF40F ); } + +__forceinline void SSE2_PMOVMSKB_XMM_to_R32(x86IntRegType to, x86SSERegType from) { SSERtoR66(0xD70F); } + +__forceinline void SSE_MOVMSKPS_XMM_to_R32(x86IntRegType to, x86SSERegType from) { SSERtoR(0x500F); } +__forceinline void SSE2_MOVMSKPD_XMM_to_R32(x86IntRegType to, x86SSERegType from) { SSERtoR66(0x500F); } + +__forceinline void SSE2_PMADDWD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { SSERtoR66(0xF50F); } + +__forceinline void SSE3_HADDPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { write8(0xf2); SSERtoR( 0x7c0f ); } +__forceinline void SSE3_HADDPS_M128_to_XMM(x86SSERegType to, uptr from){ write8(0xf2); SSEMtoR( 0x7c0f, 0 ); } + +__forceinline void SSE3_MOVSLDUP_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { + write8(0xf3); + RexRB(0, to, from); + write16( 0x120f); + ModRM( 3, to, from ); +} + +__forceinline void SSE3_MOVSLDUP_M128_to_XMM(x86SSERegType to, uptr from) { write8(0xf3); SSEMtoR(0x120f, 0); } +__forceinline void SSE3_MOVSHDUP_XMM_to_XMM(x86SSERegType to, x86SSERegType from) { write8(0xf3); SSERtoR(0x160f); } +__forceinline void SSE3_MOVSHDUP_M128_to_XMM(x86SSERegType to, uptr from) { write8(0xf3); SSEMtoR(0x160f, 0); } + +// SSE4.1 + +__forceinline void SSE4_DPPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from, u8 imm8) +{ + write8(0x66); + write24(0x403A0F); + ModRM(3, to, from); + write8(imm8); +} + +__forceinline void SSE4_DPPS_M128_to_XMM(x86SSERegType to, uptr from, u8 imm8) +{ + write8(0x66); + write24(0x403A0F); + ModRM(0, to, DISP32); + write32(MEMADDR(from, 4)); + write8(imm8); +} + +__forceinline void SSE4_INSERTPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from, u8 imm8) +{ + write8(0x66); + RexRB(0, to, from); + write24(0x213A0F); + ModRM(3, to, from); + write8(imm8); +} + +__forceinline void SSE4_EXTRACTPS_XMM_to_R32(x86IntRegType to, x86SSERegType from, u8 imm8) +{ + write8(0x66); + RexRB(0, to, from); + write24(0x173A0F); + ModRM(3, to, from); + write8(imm8); +} + +__forceinline void SSE4_BLENDPS_XMM_to_XMM(x86IntRegType to, x86SSERegType from, u8 imm8) +{ + write8(0x66); + RexRB(0, to, from); + write24(0x0C3A0F); + ModRM(3, to, from); + write8(imm8); +} + +__forceinline void SSE4_BLENDVPS_XMM_to_XMM(x86SSERegType to, x86SSERegType from) +{ + write8(0x66); + RexRB(0, to, from); + write24(0x14380F); + ModRM(3, to, from); +} + +__forceinline void SSE4_BLENDVPS_M128_to_XMM(x86SSERegType to, uptr from) +{ + write8(0x66); + RexR(0, to); + write24(0x14380F); + ModRM(0, to, DISP32); + write32(MEMADDR(from, 4)); +} + +__forceinline void SSE4_PMOVSXDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) +{ + write8(0x66); + RexRB(0, to, from); + write24(0x25380F); + ModRM(3, to, from); +} + +__forceinline void SSE4_PINSRD_R32_to_XMM(x86SSERegType to, x86IntRegType from, u8 imm8) +{ + write8(0x66); + RexRB(0, to, from); + write24(0x223A0F); + ModRM(3, to, from); + write8(imm8); +} + +__forceinline void SSE4_PMAXSD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) +{ + write8(0x66); + RexRB(0, to, from); + write24(0x3D380F); + ModRM(3, to, from); +} + +__forceinline void SSE4_PMINSD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) +{ + write8(0x66); + RexRB(0, to, from); + write24(0x39380F); + ModRM(3, to, from); +} + +__forceinline void SSE4_PMAXUD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) +{ + write8(0x66); + RexRB(0, to, from); + write24(0x3F380F); + ModRM(3, to, from); +} + +__forceinline void SSE4_PMINUD_XMM_to_XMM(x86SSERegType to, x86SSERegType from) +{ + write8(0x66); + RexRB(0, to, from); + write24(0x3B380F); + ModRM(3, to, from); +} + +__forceinline void SSE4_PMAXSD_M128_to_XMM(x86SSERegType to, uptr from) +{ + write8(0x66); + RexR(0, to); + write24(0x3D380F); + ModRM( 0, to, DISP32 ); + write32(MEMADDR(from, 4)); +} + +__forceinline void SSE4_PMINSD_M128_to_XMM(x86SSERegType to, uptr from) +{ + write8(0x66); + RexR(0, to); + write24(0x39380F); + ModRM( 0, to, DISP32 ); + write32(MEMADDR(from, 4)); +} + +__forceinline void SSE4_PMAXUD_M128_to_XMM(x86SSERegType to, uptr from) +{ + write8(0x66); + RexR(0, to); + write24(0x3F380F); + ModRM( 0, to, DISP32 ); + write32(MEMADDR(from, 4)); +} + +__forceinline void SSE4_PMINUD_M128_to_XMM(x86SSERegType to, uptr from) +{ + write8(0x66); + RexR(0, to); + write24(0x3B380F); + ModRM( 0, to, DISP32 ); + write32(MEMADDR(from, 4)); +} + +// SSE-X +__forceinline void SSEX_MOVDQA_M128_to_XMM( x86SSERegType to, uptr from ) +{ + if( g_xmmtypes[to] == XMMT_INT ) SSE2_MOVDQA_M128_to_XMM(to, from); + else SSE_MOVAPS_M128_to_XMM(to, from); +} + +__forceinline void SSEX_MOVDQA_XMM_to_M128( uptr to, x86SSERegType from ) +{ + if( g_xmmtypes[from] == XMMT_INT ) SSE2_MOVDQA_XMM_to_M128(to, from); + else SSE_MOVAPS_XMM_to_M128(to, from); +} + +__forceinline void SSEX_MOVDQA_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + if( g_xmmtypes[from] == XMMT_INT ) SSE2_MOVDQA_XMM_to_XMM(to, from); + else SSE_MOVAPS_XMM_to_XMM(to, from); +} + +__forceinline void SSEX_MOVDQARmtoROffset( x86SSERegType to, x86IntRegType from, int offset ) +{ + if( g_xmmtypes[to] == XMMT_INT ) SSE2_MOVDQARmtoROffset(to, from, offset); + else SSE_MOVAPSRmtoROffset(to, from, offset); +} + +__forceinline void SSEX_MOVDQARtoRmOffset( x86IntRegType to, x86SSERegType from, int offset ) +{ + if( g_xmmtypes[from] == XMMT_INT ) SSE2_MOVDQARtoRmOffset(to, from, offset); + else SSE_MOVAPSRtoRmOffset(to, from, offset); +} + +__forceinline void SSEX_MOVDQU_M128_to_XMM( x86SSERegType to, uptr from ) +{ + if( g_xmmtypes[to] == XMMT_INT ) SSE2_MOVDQU_M128_to_XMM(to, from); + else SSE_MOVAPS_M128_to_XMM(to, from); +} + +__forceinline void SSEX_MOVDQU_XMM_to_M128( uptr to, x86SSERegType from ) +{ + if( g_xmmtypes[from] == XMMT_INT ) SSE2_MOVDQU_XMM_to_M128(to, from); + else SSE_MOVAPS_XMM_to_M128(to, from); +} + +__forceinline void SSEX_MOVDQU_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + if( g_xmmtypes[from] == XMMT_INT ) SSE2_MOVDQU_XMM_to_XMM(to, from); + else SSE_MOVAPS_XMM_to_XMM(to, from); +} + +__forceinline void SSEX_MOVD_M32_to_XMM( x86SSERegType to, uptr from ) +{ + if( g_xmmtypes[to] == XMMT_INT ) SSE2_MOVD_M32_to_XMM(to, from); + else SSE_MOVSS_M32_to_XMM(to, from); +} + +__forceinline void SSEX_MOVD_XMM_to_M32( u32 to, x86SSERegType from ) +{ + if( g_xmmtypes[from] == XMMT_INT ) SSE2_MOVD_XMM_to_M32(to, from); + else SSE_MOVSS_XMM_to_M32(to, from); +} + +__forceinline void SSEX_MOVD_XMM_to_Rm( x86IntRegType to, x86SSERegType from ) +{ + if( g_xmmtypes[from] == XMMT_INT ) SSE2_MOVD_XMM_to_Rm(to, from); + else SSE_MOVSS_XMM_to_Rm(to, from); +} + +__forceinline void SSEX_MOVD_RmOffset_to_XMM( x86SSERegType to, x86IntRegType from, int offset ) +{ + if( g_xmmtypes[to] == XMMT_INT ) SSE2_MOVD_RmOffset_to_XMM(to, from, offset); + else SSE_MOVSS_RmOffset_to_XMM(to, from, offset); +} + +__forceinline void SSEX_MOVD_XMM_to_RmOffset( x86IntRegType to, x86SSERegType from, int offset ) +{ + if( g_xmmtypes[from] == XMMT_INT ) SSE2_MOVD_XMM_to_RmOffset(to, from, offset); + else SSE_MOVSS_XMM_to_RmOffset(to, from, offset); +} + +__forceinline void SSEX_POR_M128_to_XMM( x86SSERegType to, uptr from ) +{ + if( g_xmmtypes[to] == XMMT_INT ) SSE2_POR_M128_to_XMM(to, from); + else SSE_ORPS_M128_to_XMM(to, from); +} + +__forceinline void SSEX_POR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + if( g_xmmtypes[from] == XMMT_INT ) SSE2_POR_XMM_to_XMM(to, from); + else SSE_ORPS_XMM_to_XMM(to, from); +} + +__forceinline void SSEX_PXOR_M128_to_XMM( x86SSERegType to, uptr from ) +{ + if( g_xmmtypes[to] == XMMT_INT ) SSE2_PXOR_M128_to_XMM(to, from); + else SSE_XORPS_M128_to_XMM(to, from); +} + +__forceinline void SSEX_PXOR_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + if( g_xmmtypes[from] == XMMT_INT ) SSE2_PXOR_XMM_to_XMM(to, from); + else SSE_XORPS_XMM_to_XMM(to, from); +} + +__forceinline void SSEX_PAND_M128_to_XMM( x86SSERegType to, uptr from ) +{ + if( g_xmmtypes[to] == XMMT_INT ) SSE2_PAND_M128_to_XMM(to, from); + else SSE_ANDPS_M128_to_XMM(to, from); +} + +__forceinline void SSEX_PAND_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + if( g_xmmtypes[from] == XMMT_INT ) SSE2_PAND_XMM_to_XMM(to, from); + else SSE_ANDPS_XMM_to_XMM(to, from); +} + +__forceinline void SSEX_PANDN_M128_to_XMM( x86SSERegType to, uptr from ) +{ + if( g_xmmtypes[to] == XMMT_INT ) SSE2_PANDN_M128_to_XMM(to, from); + else SSE_ANDNPS_M128_to_XMM(to, from); +} + +__forceinline void SSEX_PANDN_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + if( g_xmmtypes[from] == XMMT_INT ) SSE2_PANDN_XMM_to_XMM(to, from); + else SSE_ANDNPS_XMM_to_XMM(to, from); +} + +__forceinline void SSEX_PUNPCKLDQ_M128_to_XMM(x86SSERegType to, uptr from) +{ + if( g_xmmtypes[to] == XMMT_INT ) SSE2_PUNPCKLDQ_M128_to_XMM(to, from); + else SSE_UNPCKLPS_M128_to_XMM(to, from); +} + +__forceinline void SSEX_PUNPCKLDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) +{ + if( g_xmmtypes[from] == XMMT_INT ) SSE2_PUNPCKLDQ_XMM_to_XMM(to, from); + else SSE_UNPCKLPS_XMM_to_XMM(to, from); +} + +__forceinline void SSEX_PUNPCKHDQ_M128_to_XMM(x86SSERegType to, uptr from) +{ + if( g_xmmtypes[to] == XMMT_INT ) SSE2_PUNPCKHDQ_M128_to_XMM(to, from); + else SSE_UNPCKHPS_M128_to_XMM(to, from); +} + +__forceinline void SSEX_PUNPCKHDQ_XMM_to_XMM(x86SSERegType to, x86SSERegType from) +{ + if( g_xmmtypes[from] == XMMT_INT ) SSE2_PUNPCKHDQ_XMM_to_XMM(to, from); + else SSE_UNPCKHPS_XMM_to_XMM(to, from); +} + +__forceinline void SSEX_MOVHLPS_XMM_to_XMM( x86SSERegType to, x86SSERegType from ) +{ + if( g_xmmtypes[from] == XMMT_INT ) { + SSE2_PUNPCKHQDQ_XMM_to_XMM(to, from); + if( to != from ) SSE2_PSHUFD_XMM_to_XMM(to, to, 0x4e); + } + else { + SSE_MOVHLPS_XMM_to_XMM(to, from); + } } \ No newline at end of file diff --git a/pcsx2/x86/ix86/ix86_tools.cpp b/pcsx2/x86/ix86/ix86_tools.cpp index 3c67a62797..20824d52da 100644 --- a/pcsx2/x86/ix86/ix86_tools.cpp +++ b/pcsx2/x86/ix86/ix86_tools.cpp @@ -1,275 +1,275 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -#include "Misc.h" -#include "ix86/ix86.h" - -// used to make sure regs don't get changed while in recompiler -// use FreezeMMXRegs, FreezeXMMRegs - -u8 g_globalMMXSaved = 0; -u8 g_globalXMMSaved = 0; - -PCSX2_ALIGNED16( static u64 g_globalMMXData[8] ); -PCSX2_ALIGNED16( static u64 g_globalXMMData[2*XMMREGS] ); - -// performance counter vars. -LARGE_INTEGER lbase = {0}, lfinal = {0}; -u32 s_pCurBlock_ltime; - - -///////////////////////////////////////////////////////////////////// -// SetCPUState -- for assugnment of SSE roundmodes and clampmodes. - -u32 g_sseMXCSR = DEFAULT_sseMXCSR; -u32 g_sseVUMXCSR = DEFAULT_sseVUMXCSR; - -void SetCPUState(u32 sseMXCSR, u32 sseVUMXCSR) -{ - //Msgbox::Alert("SetCPUState: Config.sseMXCSR = %x; Config.sseVUMXCSR = %x \n", Config.sseMXCSR, Config.sseVUMXCSR); - // SSE STATE // - // WARNING: do not touch unless you know what you are doing - - sseMXCSR &= 0xffff; // clear the upper 16 bits since they shouldn't be set - sseVUMXCSR &= 0xffff; - - if( !cpucaps.hasStreamingSIMD2Extensions ) - { - // SSE1 cpus do not support Denormals Are Zero flag (throws an exception - // if we don't mask them off) - - sseMXCSR &= ~0x0040; - sseVUMXCSR &= ~0x0040; - } - - g_sseMXCSR = sseMXCSR; - g_sseVUMXCSR = sseVUMXCSR; - -#ifdef _MSC_VER - __asm ldmxcsr g_sseMXCSR; // set the new sse control -#else - __asm__("ldmxcsr %0" : : "m"(g_sseMXCSR) ); -#endif - //g_sseVUMXCSR = g_sseMXCSR|0x6000; -} - -///////////////////////////////////////////////////////////////////// -// -__forceinline void FreezeMMXRegs_(int save) -{ - assert( g_EEFreezeRegs ); - - if( save ) { - g_globalMMXSaved++; - if( g_globalMMXSaved>1 ) - { - //SysPrintf("MMX Already Saved!\n"); - return; - } - -#ifdef _MSC_VER - __asm { - movntq mmword ptr [g_globalMMXData + 0], mm0 - movntq mmword ptr [g_globalMMXData + 8], mm1 - movntq mmword ptr [g_globalMMXData + 16], mm2 - movntq mmword ptr [g_globalMMXData + 24], mm3 - movntq mmword ptr [g_globalMMXData + 32], mm4 - movntq mmword ptr [g_globalMMXData + 40], mm5 - movntq mmword ptr [g_globalMMXData + 48], mm6 - movntq mmword ptr [g_globalMMXData + 56], mm7 - emms - } -#else - __asm__(".intel_syntax\n" - "movq [%0+0x00], %%mm0\n" - "movq [%0+0x08], %%mm1\n" - "movq [%0+0x10], %%mm2\n" - "movq [%0+0x18], %%mm3\n" - "movq [%0+0x20], %%mm4\n" - "movq [%0+0x28], %%mm5\n" - "movq [%0+0x30], %%mm6\n" - "movq [%0+0x38], %%mm7\n" - "emms\n" - ".att_syntax\n" : : "r"(g_globalMMXData) ); -#endif - - } - else { - if( g_globalMMXSaved==0 ) - { - //SysPrintf("MMX Not Saved!\n"); - return; - } - g_globalMMXSaved--; - - if( g_globalMMXSaved > 0 ) return; - -#ifdef _MSC_VER - __asm { - movq mm0, mmword ptr [g_globalMMXData + 0] - movq mm1, mmword ptr [g_globalMMXData + 8] - movq mm2, mmword ptr [g_globalMMXData + 16] - movq mm3, mmword ptr [g_globalMMXData + 24] - movq mm4, mmword ptr [g_globalMMXData + 32] - movq mm5, mmword ptr [g_globalMMXData + 40] - movq mm6, mmword ptr [g_globalMMXData + 48] - movq mm7, mmword ptr [g_globalMMXData + 56] - emms - } -#else - __asm__(".intel_syntax\n" - "movq %%mm0, [%0+0x00]\n" - "movq %%mm1, [%0+0x08]\n" - "movq %%mm2, [%0+0x10]\n" - "movq %%mm3, [%0+0x18]\n" - "movq %%mm4, [%0+0x20]\n" - "movq %%mm5, [%0+0x28]\n" - "movq %%mm6, [%0+0x30]\n" - "movq %%mm7, [%0+0x38]\n" - "emms\n" - ".att_syntax\n" : : "r"(g_globalMMXData) ); -#endif - } -} - -////////////////////////////////////////////////////////////////////// - -__forceinline void FreezeXMMRegs_(int save) -{ - //SysPrintf("FreezeXMMRegs_(%d); [%d]\n", save, g_globalXMMSaved); - assert( g_EEFreezeRegs ); - - if( save ) { - g_globalXMMSaved++; - if( g_globalXMMSaved > 1 ){ - //SysPrintf("XMM Already saved\n"); - return; - } - - -#ifdef _MSC_VER - __asm { - movaps xmmword ptr [g_globalXMMData + 0x00], xmm0 - movaps xmmword ptr [g_globalXMMData + 0x10], xmm1 - movaps xmmword ptr [g_globalXMMData + 0x20], xmm2 - movaps xmmword ptr [g_globalXMMData + 0x30], xmm3 - movaps xmmword ptr [g_globalXMMData + 0x40], xmm4 - movaps xmmword ptr [g_globalXMMData + 0x50], xmm5 - movaps xmmword ptr [g_globalXMMData + 0x60], xmm6 - movaps xmmword ptr [g_globalXMMData + 0x70], xmm7 - } - -#else - __asm__(".intel_syntax\n" - "movaps [%0+0x00], %%xmm0\n" - "movaps [%0+0x10], %%xmm1\n" - "movaps [%0+0x20], %%xmm2\n" - "movaps [%0+0x30], %%xmm3\n" - "movaps [%0+0x40], %%xmm4\n" - "movaps [%0+0x50], %%xmm5\n" - "movaps [%0+0x60], %%xmm6\n" - "movaps [%0+0x70], %%xmm7\n" - ".att_syntax\n" : : "r"(g_globalXMMData) ); - -#endif // _MSC_VER - } - else { - if( g_globalXMMSaved==0 ) - { - //SysPrintf("XMM Regs not saved!\n"); - return; - } - - // TODO: really need to backup all regs? - g_globalXMMSaved--; - if( g_globalXMMSaved > 0 ) return; - -#ifdef _MSC_VER - __asm { - movaps xmm0, xmmword ptr [g_globalXMMData + 0x00] - movaps xmm1, xmmword ptr [g_globalXMMData + 0x10] - movaps xmm2, xmmword ptr [g_globalXMMData + 0x20] - movaps xmm3, xmmword ptr [g_globalXMMData + 0x30] - movaps xmm4, xmmword ptr [g_globalXMMData + 0x40] - movaps xmm5, xmmword ptr [g_globalXMMData + 0x50] - movaps xmm6, xmmword ptr [g_globalXMMData + 0x60] - movaps xmm7, xmmword ptr [g_globalXMMData + 0x70] - } - -#else - __asm__(".intel_syntax\n" - "movaps %%xmm0, [%0+0x00]\n" - "movaps %%xmm1, [%0+0x10]\n" - "movaps %%xmm2, [%0+0x20]\n" - "movaps %%xmm3, [%0+0x30]\n" - "movaps %%xmm4, [%0+0x40]\n" - "movaps %%xmm5, [%0+0x50]\n" - "movaps %%xmm6, [%0+0x60]\n" - "movaps %%xmm7, [%0+0x70]\n" - ".att_syntax\n" : : "r"(g_globalXMMData) ); - -#endif // _MSC_VER - } -} - -#ifdef PCSX2_DEVBUILD -#ifdef _WIN32 -__declspec(naked) void _StartPerfCounter() -{ - __asm { - push eax - push ebx - push ecx - - rdtsc - mov dword ptr [offset lbase], eax - mov dword ptr [offset lbase + 4], edx - - pop ecx - pop ebx - pop eax - ret - } -} - -__declspec(naked) void _StopPerfCounter() -{ - __asm { - push eax - push ebx - push ecx - - rdtsc - - sub eax, dword ptr [offset lbase] - sbb edx, dword ptr [offset lbase + 4] - mov ecx, s_pCurBlock_ltime - add eax, dword ptr [ecx] - adc edx, dword ptr [ecx + 4] - mov dword ptr [ecx], eax - mov dword ptr [ecx + 4], edx - pop ecx - pop ebx - pop eax - ret - } -} -#endif // WIN32 +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +#include "Misc.h" +#include "ix86/ix86.h" + +// used to make sure regs don't get changed while in recompiler +// use FreezeMMXRegs, FreezeXMMRegs + +u8 g_globalMMXSaved = 0; +u8 g_globalXMMSaved = 0; + +PCSX2_ALIGNED16( static u64 g_globalMMXData[8] ); +PCSX2_ALIGNED16( static u64 g_globalXMMData[2*XMMREGS] ); + +// performance counter vars. +LARGE_INTEGER lbase = {0}, lfinal = {0}; +u32 s_pCurBlock_ltime; + + +///////////////////////////////////////////////////////////////////// +// SetCPUState -- for assugnment of SSE roundmodes and clampmodes. + +u32 g_sseMXCSR = DEFAULT_sseMXCSR; +u32 g_sseVUMXCSR = DEFAULT_sseVUMXCSR; + +void SetCPUState(u32 sseMXCSR, u32 sseVUMXCSR) +{ + //Msgbox::Alert("SetCPUState: Config.sseMXCSR = %x; Config.sseVUMXCSR = %x \n", Config.sseMXCSR, Config.sseVUMXCSR); + // SSE STATE // + // WARNING: do not touch unless you know what you are doing + + sseMXCSR &= 0xffff; // clear the upper 16 bits since they shouldn't be set + sseVUMXCSR &= 0xffff; + + if( !cpucaps.hasStreamingSIMD2Extensions ) + { + // SSE1 cpus do not support Denormals Are Zero flag (throws an exception + // if we don't mask them off) + + sseMXCSR &= ~0x0040; + sseVUMXCSR &= ~0x0040; + } + + g_sseMXCSR = sseMXCSR; + g_sseVUMXCSR = sseVUMXCSR; + +#ifdef _MSC_VER + __asm ldmxcsr g_sseMXCSR; // set the new sse control +#else + __asm__("ldmxcsr %0" : : "m"(g_sseMXCSR) ); +#endif + //g_sseVUMXCSR = g_sseMXCSR|0x6000; +} + +///////////////////////////////////////////////////////////////////// +// +__forceinline void FreezeMMXRegs_(int save) +{ + assert( g_EEFreezeRegs ); + + if( save ) { + g_globalMMXSaved++; + if( g_globalMMXSaved>1 ) + { + //SysPrintf("MMX Already Saved!\n"); + return; + } + +#ifdef _MSC_VER + __asm { + movntq mmword ptr [g_globalMMXData + 0], mm0 + movntq mmword ptr [g_globalMMXData + 8], mm1 + movntq mmword ptr [g_globalMMXData + 16], mm2 + movntq mmword ptr [g_globalMMXData + 24], mm3 + movntq mmword ptr [g_globalMMXData + 32], mm4 + movntq mmword ptr [g_globalMMXData + 40], mm5 + movntq mmword ptr [g_globalMMXData + 48], mm6 + movntq mmword ptr [g_globalMMXData + 56], mm7 + emms + } +#else + __asm__(".intel_syntax\n" + "movq [%0+0x00], %%mm0\n" + "movq [%0+0x08], %%mm1\n" + "movq [%0+0x10], %%mm2\n" + "movq [%0+0x18], %%mm3\n" + "movq [%0+0x20], %%mm4\n" + "movq [%0+0x28], %%mm5\n" + "movq [%0+0x30], %%mm6\n" + "movq [%0+0x38], %%mm7\n" + "emms\n" + ".att_syntax\n" : : "r"(g_globalMMXData) ); +#endif + + } + else { + if( g_globalMMXSaved==0 ) + { + //SysPrintf("MMX Not Saved!\n"); + return; + } + g_globalMMXSaved--; + + if( g_globalMMXSaved > 0 ) return; + +#ifdef _MSC_VER + __asm { + movq mm0, mmword ptr [g_globalMMXData + 0] + movq mm1, mmword ptr [g_globalMMXData + 8] + movq mm2, mmword ptr [g_globalMMXData + 16] + movq mm3, mmword ptr [g_globalMMXData + 24] + movq mm4, mmword ptr [g_globalMMXData + 32] + movq mm5, mmword ptr [g_globalMMXData + 40] + movq mm6, mmword ptr [g_globalMMXData + 48] + movq mm7, mmword ptr [g_globalMMXData + 56] + emms + } +#else + __asm__(".intel_syntax\n" + "movq %%mm0, [%0+0x00]\n" + "movq %%mm1, [%0+0x08]\n" + "movq %%mm2, [%0+0x10]\n" + "movq %%mm3, [%0+0x18]\n" + "movq %%mm4, [%0+0x20]\n" + "movq %%mm5, [%0+0x28]\n" + "movq %%mm6, [%0+0x30]\n" + "movq %%mm7, [%0+0x38]\n" + "emms\n" + ".att_syntax\n" : : "r"(g_globalMMXData) ); +#endif + } +} + +////////////////////////////////////////////////////////////////////// + +__forceinline void FreezeXMMRegs_(int save) +{ + //SysPrintf("FreezeXMMRegs_(%d); [%d]\n", save, g_globalXMMSaved); + assert( g_EEFreezeRegs ); + + if( save ) { + g_globalXMMSaved++; + if( g_globalXMMSaved > 1 ){ + //SysPrintf("XMM Already saved\n"); + return; + } + + +#ifdef _MSC_VER + __asm { + movaps xmmword ptr [g_globalXMMData + 0x00], xmm0 + movaps xmmword ptr [g_globalXMMData + 0x10], xmm1 + movaps xmmword ptr [g_globalXMMData + 0x20], xmm2 + movaps xmmword ptr [g_globalXMMData + 0x30], xmm3 + movaps xmmword ptr [g_globalXMMData + 0x40], xmm4 + movaps xmmword ptr [g_globalXMMData + 0x50], xmm5 + movaps xmmword ptr [g_globalXMMData + 0x60], xmm6 + movaps xmmword ptr [g_globalXMMData + 0x70], xmm7 + } + +#else + __asm__(".intel_syntax\n" + "movaps [%0+0x00], %%xmm0\n" + "movaps [%0+0x10], %%xmm1\n" + "movaps [%0+0x20], %%xmm2\n" + "movaps [%0+0x30], %%xmm3\n" + "movaps [%0+0x40], %%xmm4\n" + "movaps [%0+0x50], %%xmm5\n" + "movaps [%0+0x60], %%xmm6\n" + "movaps [%0+0x70], %%xmm7\n" + ".att_syntax\n" : : "r"(g_globalXMMData) ); + +#endif // _MSC_VER + } + else { + if( g_globalXMMSaved==0 ) + { + //SysPrintf("XMM Regs not saved!\n"); + return; + } + + // TODO: really need to backup all regs? + g_globalXMMSaved--; + if( g_globalXMMSaved > 0 ) return; + +#ifdef _MSC_VER + __asm { + movaps xmm0, xmmword ptr [g_globalXMMData + 0x00] + movaps xmm1, xmmword ptr [g_globalXMMData + 0x10] + movaps xmm2, xmmword ptr [g_globalXMMData + 0x20] + movaps xmm3, xmmword ptr [g_globalXMMData + 0x30] + movaps xmm4, xmmword ptr [g_globalXMMData + 0x40] + movaps xmm5, xmmword ptr [g_globalXMMData + 0x50] + movaps xmm6, xmmword ptr [g_globalXMMData + 0x60] + movaps xmm7, xmmword ptr [g_globalXMMData + 0x70] + } + +#else + __asm__(".intel_syntax\n" + "movaps %%xmm0, [%0+0x00]\n" + "movaps %%xmm1, [%0+0x10]\n" + "movaps %%xmm2, [%0+0x20]\n" + "movaps %%xmm3, [%0+0x30]\n" + "movaps %%xmm4, [%0+0x40]\n" + "movaps %%xmm5, [%0+0x50]\n" + "movaps %%xmm6, [%0+0x60]\n" + "movaps %%xmm7, [%0+0x70]\n" + ".att_syntax\n" : : "r"(g_globalXMMData) ); + +#endif // _MSC_VER + } +} + +#ifdef PCSX2_DEVBUILD +#ifdef _WIN32 +__declspec(naked) void _StartPerfCounter() +{ + __asm { + push eax + push ebx + push ecx + + rdtsc + mov dword ptr [offset lbase], eax + mov dword ptr [offset lbase + 4], edx + + pop ecx + pop ebx + pop eax + ret + } +} + +__declspec(naked) void _StopPerfCounter() +{ + __asm { + push eax + push ebx + push ecx + + rdtsc + + sub eax, dword ptr [offset lbase] + sbb edx, dword ptr [offset lbase + 4] + mov ecx, s_pCurBlock_ltime + add eax, dword ptr [ecx] + adc edx, dword ptr [ecx + 4] + mov dword ptr [ecx], eax + mov dword ptr [ecx + 4], edx + pop ecx + pop ebx + pop eax + ret + } +} +#endif // WIN32 #endif // PCSX2_DEVBUILD \ No newline at end of file diff --git a/pcsx2/x86/microVU.cpp b/pcsx2/x86/microVU.cpp index c203b154df..9af86584df 100644 --- a/pcsx2/x86/microVU.cpp +++ b/pcsx2/x86/microVU.cpp @@ -1,277 +1,277 @@ -/* Pcsx2 - Pc Ps2 Emulator -* Copyright (C) 2009 Pcsx2-Playground 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 -*/ - -// Micro VU recompiler! - author: cottonvibes(@gmail.com) - -#include "PrecompiledHeader.h" -#include "microVU.h" -#ifdef PCSX2_MICROVU - -//------------------------------------------------------------------ -// VU Micro - Global Variables -//------------------------------------------------------------------ - -microVU microVU0; -microVU microVU1; - -//------------------------------------------------------------------ -// Micro VU - Main Functions -//------------------------------------------------------------------ - -// Only run this once! ;) -__forceinline void mVUinit(microVU* mVU, VURegs* vuRegsPtr, const int vuIndex) { - - mVU->regs = vuRegsPtr; - mVU->index = vuIndex; - mVU->microSize = (vuIndex ? 0x4000 : 0x1000); - mVU->progSize = (vuIndex ? 0x4000 : 0x1000) / 8; - mVU->cacheAddr = 0xC0000000 + (vuIndex ? mVU->cacheSize : 0); - mVU->cache = NULL; - - mVUreset(mVU); -} - -// Will Optimize later -__forceinline void mVUreset(microVU* mVU) { - - mVUclose(mVU); // Close - - // Create Block Managers - for (int i; i <= mVU->prog.max; i++) { - for (u32 j; j < mVU->progSize; j++) { - mVU->prog.prog[i].block[j] = new microBlockManager(); - } - } - - // Dynarec Cache - mVU->cache = SysMmapEx(mVU->cacheAddr, mVU->cacheSize, 0x10000000, "Micro VU"); - if ( mVU->cache == NULL ) throw Exception::OutOfMemory(fmt_string( "microVU Error: failed to allocate recompiler memory! (addr: 0x%x)", params (u32)mVU->cache)); - - // Other Variables - ZeroMemory(&mVU->prog, sizeof(mVU->prog)); - mVU->prog.finished = 1; - mVU->prog.cleared = 1; - mVU->prog.cur = -1; - mVU->prog.total = -1; -} - -// Free Allocated Resources -__forceinline void mVUclose(microVU* mVU) { - - if ( mVU->cache ) { SysMunmap( mVU->cache, mVU->cacheSize ); mVU->cache = NULL; } - - // Delete Block Managers - for (int i; i <= mVU->prog.max; i++) { - for (u32 j; j < mVU->progSize; j++) { - if (mVU->prog.prog[i].block[j]) delete mVU->prog.prog[i].block[j]; - } - } -} - -// Clears Block Data in specified range (Caches current microProgram if a difference has been found) -__forceinline void mVUclear(microVU* mVU, u32 addr, u32 size) { - - int i = addr/8; - int end = i+((size+(8-(size&7)))/8); // ToDo: Can be simplified to addr+size if Size is always a multiple of 8 - - if (!mVU->prog.cleared) { - for ( ; i < end; i++) { - if ( mVU->prog.prog[mVU->prog.cur].block[i]->clear() ) { - mVUcacheProg(mVU); - mVU->prog.cleared = 1; - i++; - break; - } - } - } - for ( ; i < end; i++) { - mVU->prog.prog[mVU->prog.cur].block[i]->clearFast(); - } -} - -// Executes for number of cycles -void* __fastcall mVUexecuteVU0(u32 startPC, u32 cycles) { -/* Pseudocode: (ToDo: implement # of cycles) - 1) Search for existing program - 2) If program not found, goto 5 - 3) Search for recompiled block - 4) If recompiled block found, goto 6 - 5) Recompile as much blocks as possible - 6) Return start execution address of block -*/ - if ( mVUsearchProg(µVU0) ) { // Found Program - microBlock* block = microVU0.prog.prog[microVU0.prog.cur].block[startPC]->search(microVU0.prog.lastPipelineState); - if (block) return block->x86ptrStart; - } - // Recompile code - return NULL; -} -void* __fastcall mVUexecuteVU1(u32 startPC, u32 cycles) { - return NULL; -} - -/* -// Executes till finished -void* mVUexecuteF(microVU* mVU, u32 startPC) { - //if (!mProg.finished) { - // runMicroProgram(startPC); - //} - //if (mProg.cleared && !mProg.finished) { - - //} - return NULL; -} -*/ - -//------------------------------------------------------------------ -// Micro VU - Private Functions -//------------------------------------------------------------------ - -// Finds the least used program -__forceinline int mVUfindLeastUsedProg(microVU* mVU) { - if (mVU->prog.total < mVU->prog.max) { - mVU->prog.total++; - return mVU->prog.total; - } - else { - int j = 0; - u32 smallest = mVU->prog.prog[0].used; - for (int i = 1; i <= mVU->prog.total; i++) { - if (smallest > mVU->prog.prog[i].used) { - smallest = mVU->prog.prog[i].used; - j = i; - } - } - return j; - } -} - -// Caches Micro Program if appropriate -__forceinline void mVUcacheProg(microVU* mVU) { - if (!mVU->prog.prog[mVU->prog.cur].cached) { // If uncached, then cache - memcpy_fast(mVU->prog.prog[mVU->prog.cur].data, mVU->regs->Micro, mVU->microSize); - mVU->prog.prog[mVU->prog.cur].cached = 1; - } -} - -// Searches for Cached Micro Program and sets prog.cur to it (returns 1 if program found, else returns 0) -__forceinline int mVUsearchProg(microVU* mVU) { - if (mVU->prog.cleared) { // If cleared, we need to search for new program - for (int i = 0; i <= mVU->prog.total; i++) { - if (i == mVU->prog.cur) continue; // We can skip the current program. - if (mVU->prog.prog[i].cached) { - if (!memcmp_mmx(mVU->prog.prog[i].data, mVU->regs->Micro, mVU->microSize)) { - mVU->prog.cur = i; - return 1; - } - } - } - mVU->prog.cur = mVUfindLeastUsedProg(mVU); // If cleared and program not cached, make a new program instance - // ToDo: Clear old data if overwriting old program - return 0; - } - else return 1; // If !cleared, then we're still on the same program as last-time ;) -} - -//------------------------------------------------------------------ -// Dispatcher Functions -//------------------------------------------------------------------ - -// Runs VU0 for number of cycles -__declspec(naked) void __fastcall startVU0(u32 startPC, u32 cycles) { - __asm { - // __fastcall = The first two DWORD or smaller arguments are passed in ECX and EDX registers; all other arguments are passed right to left. - call mVUexecuteVU0 - - /*backup cpu state*/ - push ebx; - push ebp; - push esi; - push edi; - - ldmxcsr g_sseVUMXCSR - - jmp eax - } -} - -// Runs VU1 for number of cycles -__declspec(naked) void __fastcall startVU1(u32 startPC, u32 cycles) { - __asm { - - call mVUexecuteVU1 - - /*backup cpu state*/ - push ebx; - push ebp; - push esi; - push edi; - - ldmxcsr g_sseVUMXCSR - - jmp eax - } -} - -// Exit point -__declspec(naked) void __fastcall endVU0(u32 startPC, u32 cycles) { - __asm { - - //call mVUcleanUpVU0 - - /*restore cpu state*/ - pop edi; - pop esi; - pop ebp; - pop ebx; - - ldmxcsr g_sseMXCSR - - ret - } -} -//------------------------------------------------------------------ -// Wrapper Functions - Called by other parts of the Emu -//------------------------------------------------------------------ - -__forceinline void initVUrec(VURegs* vuRegs, int vuIndex) { - if (!vuIndex) mVUinit(µVU0, vuRegs, 0); - else mVUinit(µVU1, vuRegs, 1); -} - -__forceinline void closeVUrec(int vuIndex) { - if (!vuIndex) mVUclose(µVU0); - else mVUclose(µVU1); -} - -__forceinline void resetVUrec(int vuIndex) { - if (!vuIndex) mVUreset(µVU0); - else mVUreset(µVU1); -} - -__forceinline void clearVUrec(u32 addr, u32 size, int vuIndex) { - if (!vuIndex) mVUclear(µVU0, addr, size); - else mVUclear(µVU1, addr, size); -} - -__forceinline void runVUrec(u32 startPC, u32 cycles, int vuIndex) { - if (!vuIndex) startVU0(startPC, cycles); - else startVU1(startPC, cycles); -} - -#endif // PCSX2_MICROVU +/* Pcsx2 - Pc Ps2 Emulator +* Copyright (C) 2009 Pcsx2-Playground 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 +*/ + +// Micro VU recompiler! - author: cottonvibes(@gmail.com) + +#include "PrecompiledHeader.h" +#include "microVU.h" +#ifdef PCSX2_MICROVU + +//------------------------------------------------------------------ +// VU Micro - Global Variables +//------------------------------------------------------------------ + +microVU microVU0; +microVU microVU1; + +//------------------------------------------------------------------ +// Micro VU - Main Functions +//------------------------------------------------------------------ + +// Only run this once! ;) +__forceinline void mVUinit(microVU* mVU, VURegs* vuRegsPtr, const int vuIndex) { + + mVU->regs = vuRegsPtr; + mVU->index = vuIndex; + mVU->microSize = (vuIndex ? 0x4000 : 0x1000); + mVU->progSize = (vuIndex ? 0x4000 : 0x1000) / 8; + mVU->cacheAddr = 0xC0000000 + (vuIndex ? mVU->cacheSize : 0); + mVU->cache = NULL; + + mVUreset(mVU); +} + +// Will Optimize later +__forceinline void mVUreset(microVU* mVU) { + + mVUclose(mVU); // Close + + // Create Block Managers + for (int i; i <= mVU->prog.max; i++) { + for (u32 j; j < mVU->progSize; j++) { + mVU->prog.prog[i].block[j] = new microBlockManager(); + } + } + + // Dynarec Cache + mVU->cache = SysMmapEx(mVU->cacheAddr, mVU->cacheSize, 0x10000000, "Micro VU"); + if ( mVU->cache == NULL ) throw Exception::OutOfMemory(fmt_string( "microVU Error: failed to allocate recompiler memory! (addr: 0x%x)", params (u32)mVU->cache)); + + // Other Variables + ZeroMemory(&mVU->prog, sizeof(mVU->prog)); + mVU->prog.finished = 1; + mVU->prog.cleared = 1; + mVU->prog.cur = -1; + mVU->prog.total = -1; +} + +// Free Allocated Resources +__forceinline void mVUclose(microVU* mVU) { + + if ( mVU->cache ) { SysMunmap( mVU->cache, mVU->cacheSize ); mVU->cache = NULL; } + + // Delete Block Managers + for (int i; i <= mVU->prog.max; i++) { + for (u32 j; j < mVU->progSize; j++) { + if (mVU->prog.prog[i].block[j]) delete mVU->prog.prog[i].block[j]; + } + } +} + +// Clears Block Data in specified range (Caches current microProgram if a difference has been found) +__forceinline void mVUclear(microVU* mVU, u32 addr, u32 size) { + + int i = addr/8; + int end = i+((size+(8-(size&7)))/8); // ToDo: Can be simplified to addr+size if Size is always a multiple of 8 + + if (!mVU->prog.cleared) { + for ( ; i < end; i++) { + if ( mVU->prog.prog[mVU->prog.cur].block[i]->clear() ) { + mVUcacheProg(mVU); + mVU->prog.cleared = 1; + i++; + break; + } + } + } + for ( ; i < end; i++) { + mVU->prog.prog[mVU->prog.cur].block[i]->clearFast(); + } +} + +// Executes for number of cycles +void* __fastcall mVUexecuteVU0(u32 startPC, u32 cycles) { +/* Pseudocode: (ToDo: implement # of cycles) + 1) Search for existing program + 2) If program not found, goto 5 + 3) Search for recompiled block + 4) If recompiled block found, goto 6 + 5) Recompile as much blocks as possible + 6) Return start execution address of block +*/ + if ( mVUsearchProg(µVU0) ) { // Found Program + microBlock* block = microVU0.prog.prog[microVU0.prog.cur].block[startPC]->search(microVU0.prog.lastPipelineState); + if (block) return block->x86ptrStart; + } + // Recompile code + return NULL; +} +void* __fastcall mVUexecuteVU1(u32 startPC, u32 cycles) { + return NULL; +} + +/* +// Executes till finished +void* mVUexecuteF(microVU* mVU, u32 startPC) { + //if (!mProg.finished) { + // runMicroProgram(startPC); + //} + //if (mProg.cleared && !mProg.finished) { + + //} + return NULL; +} +*/ + +//------------------------------------------------------------------ +// Micro VU - Private Functions +//------------------------------------------------------------------ + +// Finds the least used program +__forceinline int mVUfindLeastUsedProg(microVU* mVU) { + if (mVU->prog.total < mVU->prog.max) { + mVU->prog.total++; + return mVU->prog.total; + } + else { + int j = 0; + u32 smallest = mVU->prog.prog[0].used; + for (int i = 1; i <= mVU->prog.total; i++) { + if (smallest > mVU->prog.prog[i].used) { + smallest = mVU->prog.prog[i].used; + j = i; + } + } + return j; + } +} + +// Caches Micro Program if appropriate +__forceinline void mVUcacheProg(microVU* mVU) { + if (!mVU->prog.prog[mVU->prog.cur].cached) { // If uncached, then cache + memcpy_fast(mVU->prog.prog[mVU->prog.cur].data, mVU->regs->Micro, mVU->microSize); + mVU->prog.prog[mVU->prog.cur].cached = 1; + } +} + +// Searches for Cached Micro Program and sets prog.cur to it (returns 1 if program found, else returns 0) +__forceinline int mVUsearchProg(microVU* mVU) { + if (mVU->prog.cleared) { // If cleared, we need to search for new program + for (int i = 0; i <= mVU->prog.total; i++) { + if (i == mVU->prog.cur) continue; // We can skip the current program. + if (mVU->prog.prog[i].cached) { + if (!memcmp_mmx(mVU->prog.prog[i].data, mVU->regs->Micro, mVU->microSize)) { + mVU->prog.cur = i; + return 1; + } + } + } + mVU->prog.cur = mVUfindLeastUsedProg(mVU); // If cleared and program not cached, make a new program instance + // ToDo: Clear old data if overwriting old program + return 0; + } + else return 1; // If !cleared, then we're still on the same program as last-time ;) +} + +//------------------------------------------------------------------ +// Dispatcher Functions +//------------------------------------------------------------------ + +// Runs VU0 for number of cycles +__declspec(naked) void __fastcall startVU0(u32 startPC, u32 cycles) { + __asm { + // __fastcall = The first two DWORD or smaller arguments are passed in ECX and EDX registers; all other arguments are passed right to left. + call mVUexecuteVU0 + + /*backup cpu state*/ + push ebx; + push ebp; + push esi; + push edi; + + ldmxcsr g_sseVUMXCSR + + jmp eax + } +} + +// Runs VU1 for number of cycles +__declspec(naked) void __fastcall startVU1(u32 startPC, u32 cycles) { + __asm { + + call mVUexecuteVU1 + + /*backup cpu state*/ + push ebx; + push ebp; + push esi; + push edi; + + ldmxcsr g_sseVUMXCSR + + jmp eax + } +} + +// Exit point +__declspec(naked) void __fastcall endVU0(u32 startPC, u32 cycles) { + __asm { + + //call mVUcleanUpVU0 + + /*restore cpu state*/ + pop edi; + pop esi; + pop ebp; + pop ebx; + + ldmxcsr g_sseMXCSR + + ret + } +} +//------------------------------------------------------------------ +// Wrapper Functions - Called by other parts of the Emu +//------------------------------------------------------------------ + +__forceinline void initVUrec(VURegs* vuRegs, int vuIndex) { + if (!vuIndex) mVUinit(µVU0, vuRegs, 0); + else mVUinit(µVU1, vuRegs, 1); +} + +__forceinline void closeVUrec(int vuIndex) { + if (!vuIndex) mVUclose(µVU0); + else mVUclose(µVU1); +} + +__forceinline void resetVUrec(int vuIndex) { + if (!vuIndex) mVUreset(µVU0); + else mVUreset(µVU1); +} + +__forceinline void clearVUrec(u32 addr, u32 size, int vuIndex) { + if (!vuIndex) mVUclear(µVU0, addr, size); + else mVUclear(µVU1, addr, size); +} + +__forceinline void runVUrec(u32 startPC, u32 cycles, int vuIndex) { + if (!vuIndex) startVU0(startPC, cycles); + else startVU1(startPC, cycles); +} + +#endif // PCSX2_MICROVU diff --git a/pcsx2/x86/microVU.h b/pcsx2/x86/microVU.h index 653759a028..5244c8000b 100644 --- a/pcsx2/x86/microVU.h +++ b/pcsx2/x86/microVU.h @@ -1,136 +1,136 @@ -/* Pcsx2 - Pc Ps2 Emulator -* Copyright (C) 2009 Pcsx2-Playground 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 -#include "Common.h" -#include "VU.h" -#include "microVU_Tables.h" -//#include - -struct microBlock { - u32 pipelineState; // FMACx|y|z|w | FDiv | EFU | IALU | BRANCH // Still thinking of how I'm going to do this - u8* x86ptrStart; - u8* x86ptrEnd; - u8* x86ptrBranch; - //u32 size; -}; - -#define mMaxBlocks 32 // Max Blocks With Different Pipeline States (For n = 1, 2, 4, 8, 16, etc...) -class microBlockManager { -private: - static const int MaxBlocks = mMaxBlocks - 1; - u32 startPC; - u32 endPC; - int listSize; // Total Items - 1 - int callerSize; // Total Callers - 1 - microBlock blockList[mMaxBlocks]; - microBlock callersList[mMaxBlocks]; // Foreign Blocks that call Local Blocks - -public: - microBlockManager() { init(); } - ~microBlockManager() { close(); } - void init() { - listSize = -1; - callerSize = -1; - ZeroMemory(&blockList, sizeof(blockList)); // Can be Omitted? - } - void close() {}; // Can be Omitted? - void add(u32 pipelineState, u8* x86ptrStart) { - if (!search(pipelineState)) { - listSize++; - listSize &= MaxBlocks; - blockList[listSize].pipelineState = pipelineState; - blockList[listSize].x86ptrStart = x86ptrStart; - } - } - microBlock* search(u32 pipelineState) { - for (int i = 0; i < listSize; i++) { - if (blockList[i].pipelineState == pipelineState) return &blockList[i]; - } - return NULL; - } - void clearFast() { - listSize = -1; - for ( ; callerSize >= 0; callerSize--) { - //callerList[callerSize]. // Implement Branch Link Removal Code - } - } - int clear() { - if (listSize >= 0) { clearFast(); return 1; } - else return 0; - } -}; - -template -struct microProgram { - u8 data[progSize]; - u32 used; // Number of times its been used - int cached; // Has been Cached? - microBlockManager* block[progSize]; -}; - -#define mMaxProg 16 // The amount of Micro Programs Recs will 'remember' (For n = 1, 2, 4, 8, 16, etc...) -template -struct microProgManager { - microProgram prog[mMaxProg]; // Store MicroPrograms in memory - static const int max = mMaxProg - 1; - int cur; // Index to Current MicroProgram thats running (-1 = uncached) - int total; // Total Number of valid MicroPrograms minus 1 - int cleared; // Micro Program is Indeterminate so must be searched for (and if no matches are found then recompile a new one) - int finished; // Completed MicroProgram to E-bit Termination - u32 lastPipelineState; // Pipeline state from where it left off (useful for continuing execution) -}; - -struct microVU { - int index; // VU Index (VU0 or VU1) - u32 microSize; // VU Micro Memory Size - u32 progSize; // VU Micro Program Size (microSize/8) - u32 cacheAddr; // VU Cache Start Address - static const u32 cacheSize = 0x400000; // VU Cache Size - - VURegs* regs; // VU Regs Struct - u8* cache; // Dynarec Cache Start (where we will start writing the recompiled code to) - u8* ptr; // Pointer to next place to write recompiled code to -/* - uptr x86eax; // Accumulator register. Used in arithmetic operations. - uptr x86ecx; // Counter register. Used in shift/rotate instructions. - uptr x86edx; // Data register. Used in arithmetic operations and I/O operations. - uptr x86ebx; // Base register. Used as a pointer to data (located in DS in segmented mode). - uptr x86esp; // Stack Pointer register. Pointer to the top of the stack. - uptr x86ebp; // Stack Base Pointer register. Used to point to the base of the stack. - uptr x86esi; // Source register. Used as a pointer to a source in stream operations. - uptr x86edi; // Destination register. Used as a pointer to a destination in stream operations. -*/ - microProgManager<0x800> prog; // Micro Program Data -}; - -// Opcode Tables -extern void (*mVU_UPPER_OPCODE[64])( VURegs* VU, s32 info ); -extern void (*mVU_LOWER_OPCODE[128])( VURegs* VU, s32 info ); - -//void invalidateBlocks(u32 addr, u32 size); // Invalidates Blocks in the range [addr, addr+size) -__forceinline void mVUinit(microVU* mVU, VURegs* vuRegsPtr, const int vuIndex); -__forceinline void mVUreset(microVU* mVU); -__forceinline void mVUclose(microVU* mVU); -__forceinline void mVUclear(microVU* mVU, u32 addr, u32 size); // Clears part of a Micro Program (must use before modifying micro program!) -//void* mVUexecute(microVU* mVU, u32 startPC, u32 cycles); // Recompiles/Executes code for the number of cycles indicated (will always run for >= 'cycles' amount unless 'finished') -//void* mVUexecuteF(microVU* mVU, u32 startPC); // Recompiles/Executes code till finished - -__forceinline int mVUfindLeastUsedProg(microVU* mVU); -__forceinline int mVUsearchProg(microVU* mVU); -__forceinline void mVUcacheProg(microVU* mVU); +/* Pcsx2 - Pc Ps2 Emulator +* Copyright (C) 2009 Pcsx2-Playground 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 +#include "Common.h" +#include "VU.h" +#include "microVU_Tables.h" +//#include + +struct microBlock { + u32 pipelineState; // FMACx|y|z|w | FDiv | EFU | IALU | BRANCH // Still thinking of how I'm going to do this + u8* x86ptrStart; + u8* x86ptrEnd; + u8* x86ptrBranch; + //u32 size; +}; + +#define mMaxBlocks 32 // Max Blocks With Different Pipeline States (For n = 1, 2, 4, 8, 16, etc...) +class microBlockManager { +private: + static const int MaxBlocks = mMaxBlocks - 1; + u32 startPC; + u32 endPC; + int listSize; // Total Items - 1 + int callerSize; // Total Callers - 1 + microBlock blockList[mMaxBlocks]; + microBlock callersList[mMaxBlocks]; // Foreign Blocks that call Local Blocks + +public: + microBlockManager() { init(); } + ~microBlockManager() { close(); } + void init() { + listSize = -1; + callerSize = -1; + ZeroMemory(&blockList, sizeof(blockList)); // Can be Omitted? + } + void close() {}; // Can be Omitted? + void add(u32 pipelineState, u8* x86ptrStart) { + if (!search(pipelineState)) { + listSize++; + listSize &= MaxBlocks; + blockList[listSize].pipelineState = pipelineState; + blockList[listSize].x86ptrStart = x86ptrStart; + } + } + microBlock* search(u32 pipelineState) { + for (int i = 0; i < listSize; i++) { + if (blockList[i].pipelineState == pipelineState) return &blockList[i]; + } + return NULL; + } + void clearFast() { + listSize = -1; + for ( ; callerSize >= 0; callerSize--) { + //callerList[callerSize]. // Implement Branch Link Removal Code + } + } + int clear() { + if (listSize >= 0) { clearFast(); return 1; } + else return 0; + } +}; + +template +struct microProgram { + u8 data[progSize]; + u32 used; // Number of times its been used + int cached; // Has been Cached? + microBlockManager* block[progSize]; +}; + +#define mMaxProg 16 // The amount of Micro Programs Recs will 'remember' (For n = 1, 2, 4, 8, 16, etc...) +template +struct microProgManager { + microProgram prog[mMaxProg]; // Store MicroPrograms in memory + static const int max = mMaxProg - 1; + int cur; // Index to Current MicroProgram thats running (-1 = uncached) + int total; // Total Number of valid MicroPrograms minus 1 + int cleared; // Micro Program is Indeterminate so must be searched for (and if no matches are found then recompile a new one) + int finished; // Completed MicroProgram to E-bit Termination + u32 lastPipelineState; // Pipeline state from where it left off (useful for continuing execution) +}; + +struct microVU { + int index; // VU Index (VU0 or VU1) + u32 microSize; // VU Micro Memory Size + u32 progSize; // VU Micro Program Size (microSize/8) + u32 cacheAddr; // VU Cache Start Address + static const u32 cacheSize = 0x400000; // VU Cache Size + + VURegs* regs; // VU Regs Struct + u8* cache; // Dynarec Cache Start (where we will start writing the recompiled code to) + u8* ptr; // Pointer to next place to write recompiled code to +/* + uptr x86eax; // Accumulator register. Used in arithmetic operations. + uptr x86ecx; // Counter register. Used in shift/rotate instructions. + uptr x86edx; // Data register. Used in arithmetic operations and I/O operations. + uptr x86ebx; // Base register. Used as a pointer to data (located in DS in segmented mode). + uptr x86esp; // Stack Pointer register. Pointer to the top of the stack. + uptr x86ebp; // Stack Base Pointer register. Used to point to the base of the stack. + uptr x86esi; // Source register. Used as a pointer to a source in stream operations. + uptr x86edi; // Destination register. Used as a pointer to a destination in stream operations. +*/ + microProgManager<0x800> prog; // Micro Program Data +}; + +// Opcode Tables +extern void (*mVU_UPPER_OPCODE[64])( VURegs* VU, s32 info ); +extern void (*mVU_LOWER_OPCODE[128])( VURegs* VU, s32 info ); + +//void invalidateBlocks(u32 addr, u32 size); // Invalidates Blocks in the range [addr, addr+size) +__forceinline void mVUinit(microVU* mVU, VURegs* vuRegsPtr, const int vuIndex); +__forceinline void mVUreset(microVU* mVU); +__forceinline void mVUclose(microVU* mVU); +__forceinline void mVUclear(microVU* mVU, u32 addr, u32 size); // Clears part of a Micro Program (must use before modifying micro program!) +//void* mVUexecute(microVU* mVU, u32 startPC, u32 cycles); // Recompiles/Executes code for the number of cycles indicated (will always run for >= 'cycles' amount unless 'finished') +//void* mVUexecuteF(microVU* mVU, u32 startPC); // Recompiles/Executes code till finished + +__forceinline int mVUfindLeastUsedProg(microVU* mVU); +__forceinline int mVUsearchProg(microVU* mVU); +__forceinline void mVUcacheProg(microVU* mVU); diff --git a/pcsx2/x86/microVU_Lower.cpp b/pcsx2/x86/microVU_Lower.cpp index 74cd64b17c..2f2804bdb3 100644 --- a/pcsx2/x86/microVU_Lower.cpp +++ b/pcsx2/x86/microVU_Lower.cpp @@ -1,19 +1,19 @@ -/* Pcsx2 - Pc Ps2 Emulator -* Copyright (C) 2009 Pcsx2-Playground 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 "PrecompiledHeader.h" +/* Pcsx2 - Pc Ps2 Emulator +* Copyright (C) 2009 Pcsx2-Playground 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 "PrecompiledHeader.h" diff --git a/pcsx2/x86/microVU_Tables.cpp b/pcsx2/x86/microVU_Tables.cpp index 0f7bc9e260..9377463346 100644 --- a/pcsx2/x86/microVU_Tables.cpp +++ b/pcsx2/x86/microVU_Tables.cpp @@ -1,227 +1,227 @@ -/* Pcsx2 - Pc Ps2 Emulator -* Copyright (C) 2009 Pcsx2-Playground 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 meived 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 "PrecompiledHeader.h" -#include "microVU.h" - -#ifdef PCSX2_MICROVU_lulz - -void mVU_UPPER_FD_00(VURegs* VU, s32 info); -void mVU_UPPER_FD_01(VURegs* VU, s32 info); -void mVU_UPPER_FD_10(VURegs* VU, s32 info); -void mVU_UPPER_FD_11(VURegs* VU, s32 info); -void mVULowerOP(VURegs* VU, s32 info); -void mVULowerOP_T3_00(VURegs* VU, s32 info); -void mVULowerOP_T3_01(VURegs* VU, s32 info); -void mVULowerOP_T3_10(VURegs* VU, s32 info); -void mVULowerOP_T3_11(VURegs* VU, s32 info); -void mVUunknown(VURegs* VU, s32 info); - -void (*mVU_LOWER_OPCODE[128])(VURegs* VU, s32 info) = { - mVU_LQ , mVU_SQ , mVUunknown , mVUunknown, - mVU_ILW , mVU_ISW , mVUunknown , mVUunknown, - mVU_IADDIU , mVU_ISUBIU , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVU_FCEQ , mVU_FCSET , mVU_FCAND , mVU_FCOR, /* 0x10 */ - mVU_FSEQ , mVU_FSSET , mVU_FSAND , mVU_FSOR, - mVU_FMEQ , mVUunknown , mVU_FMAND , mVU_FMOR, - mVU_FCGET , mVUunknown , mVUunknown , mVUunknown, - mVU_B , mVU_BAL , mVUunknown , mVUunknown, /* 0x20 */ - mVU_JR , mVU_JALR , mVUunknown , mVUunknown, - mVU_IBEQ , mVU_IBNE , mVUunknown , mVUunknown, - mVU_IBLTZ , mVU_IBGTZ , mVU_IBLEZ , mVU_IBGEZ, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, /* 0x30 */ - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVULowerOP , mVUunknown , mVUunknown , mVUunknown, /* 0x40*/ - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, /* 0x50 */ - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, /* 0x60 */ - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, /* 0x70 */ - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, -}; - -void (*mVULowerOP_T3_00_OPCODE[32])(VURegs* VU, s32 info) = { - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVU_MOVE , mVU_LQI , mVU_DIV , mVU_MTIR, - mVU_RNEXT , mVUunknown , mVUunknown , mVUunknown, /* 0x10 */ - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVU_MFP , mVU_XTOP , mVU_XGKICK, - mVU_ESADD , mVU_EATANxy , mVU_ESQRT , mVU_ESIN, -}; - -void (*mVULowerOP_T3_01_OPCODE[32])(VURegs* VU, s32 info) = { - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVU_MR32 , mVU_SQI , mVU_SQRT , mVU_MFIR, - mVU_RGET , mVUunknown , mVUunknown , mVUunknown, /* 0x10 */ - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVU_XITOP , mVUunknown, - mVU_ERSADD , mVU_EATANxz , mVU_ERSQRT , mVU_EATAN, -}; - -void (*mVULowerOP_T3_10_OPCODE[32])(VURegs* VU, s32 info) = { - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVU_LQD , mVU_RSQRT , mVU_ILWR, - mVU_RINIT , mVUunknown , mVUunknown , mVUunknown, /* 0x10 */ - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVU_ELENG , mVU_ESUM , mVU_ERCPR , mVU_EEXP, -}; - -void (*mVULowerOP_T3_11_OPCODE[32])(VURegs* VU, s32 info) = { - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVU_SQD , mVU_WAITQ , mVU_ISWR, - mVU_RXOR , mVUunknown , mVUunknown , mVUunknown, /* 0x10 */ - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVU_ERLENG , mVUunknown , mVU_WAITP , mVUunknown, -}; - -void (*mVULowerOP_OPCODE[64])(VURegs* VU, s32 info) = { - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, /* 0x10 */ - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, /* 0x20 */ - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVU_IADD , mVU_ISUB , mVU_IADDI , mVUunknown, /* 0x30 */ - mVU_IAND , mVU_IOR , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVULowerOP_T3_00, mVULowerOP_T3_01, mVULowerOP_T3_10, mVULowerOP_T3_11, -}; - -void (*mVU_UPPER_OPCODE[64])(VURegs* VU, s32 info) = { - mVU_ADDx , mVU_ADDy , mVU_ADDz , mVU_ADDw, - mVU_SUBx , mVU_SUBy , mVU_SUBz , mVU_SUBw, - mVU_MADDx , mVU_MADDy , mVU_MADDz , mVU_MADDw, - mVU_MSUBx , mVU_MSUBy , mVU_MSUBz , mVU_MSUBw, - mVU_MAXx , mVU_MAXy , mVU_MAXz , mVU_MAXw, /* 0x10 */ - mVU_MINIx , mVU_MINIy , mVU_MINIz , mVU_MINIw, - mVU_MULx , mVU_MULy , mVU_MULz , mVU_MULw, - mVU_MULq , mVU_MAXi , mVU_MULi , mVU_MINIi, - mVU_ADDq , mVU_MADDq , mVU_ADDi , mVU_MADDi, /* 0x20 */ - mVU_SUBq , mVU_MSUBq , mVU_SUBi , mVU_MSUBi, - mVU_ADD , mVU_MADD , mVU_MUL , mVU_MAX, - mVU_SUB , mVU_MSUB , mVU_OPMSUB , mVU_MINI, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, /* 0x30 */ - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVU_UPPER_FD_00, mVU_UPPER_FD_01, mVU_UPPER_FD_10, mVU_UPPER_FD_11, -}; - -void (*mVU_UPPER_FD_00_TABLE[32])(VURegs* VU, s32 info) = { - mVU_ADDAx , mVU_SUBAx , mVU_MADDAx , mVU_MSUBAx, - mVU_ITOF0 , mVU_FTOI0 , mVU_MULAx , mVU_MULAq, - mVU_ADDAq , mVU_SUBAq , mVU_ADDA , mVU_SUBA, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, -}; - -void (*mVU_UPPER_FD_01_TABLE[32])(VURegs* VU, s32 info) = { - mVU_ADDAy , mVU_SUBAy , mVU_MADDAy , mVU_MSUBAy, - mVU_ITOF4 , mVU_FTOI4 , mVU_MULAy , mVU_ABS, - mVU_MADDAq , mVU_MSUBAq , mVU_MADDA , mVU_MSUBA, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, -}; - -void (*mVU_UPPER_FD_10_TABLE[32])(VURegs* VU, s32 info) = { - mVU_ADDAz , mVU_SUBAz , mVU_MADDAz , mVU_MSUBAz, - mVU_ITOF12 , mVU_FTOI12 , mVU_MULAz , mVU_MULAi, - mVU_ADDAi , mVU_SUBAi , mVU_MULA , mVU_OPMULA, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, -}; - -void (*mVU_UPPER_FD_11_TABLE[32])(VURegs* VU, s32 info) = { - mVU_ADDAw , mVU_SUBAw , mVU_MADDAw , mVU_MSUBAw, - mVU_ITOF15 , mVU_FTOI15 , mVU_MULAw , mVU_CLIP, - mVU_MADDAi , mVU_MSUBAi , mVUunknown , mVU_NOP, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, - mVUunknown , mVUunknown , mVUunknown , mVUunknown, -}; - -void mVU_UPPER_FD_00(VURegs* VU, s32 info) { - mVU_UPPER_FD_00_TABLE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); -} -void mVU_UPPER_FD_01(VURegs* VU, s32 info) { - mVU_UPPER_FD_01_TABLE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); -} -void mVU_UPPER_FD_10(VURegs* VU, s32 info) { - mVU_UPPER_FD_10_TABLE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); -} -void mVU_UPPER_FD_11(VURegs* VU, s32 info) { - mVU_UPPER_FD_11_TABLE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); -} -void mVULowerOP(VURegs* VU, s32 info) { - mVULowerOP_OPCODE[ VU->code & 0x3f ]( VU, info ); -} -void mVULowerOP_T3_00(VURegs* VU, s32 info) { - mVULowerOP_T3_00_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); -} -void mVULowerOP_T3_01(VURegs* VU, s32 info) { - mVULowerOP_T3_01_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); -} -void mVULowerOP_T3_10(VURegs* VU, s32 info) { - mVULowerOP_T3_10_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); -} -void mVULowerOP_T3_11(VURegs* VU, s32 info) { - mVULowerOP_T3_11_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); -} -void mVUunknown(VURegs* VU, s32 info) { - SysPrintf("Unknown Micro VU opcode called\n"); -} - -#endif +/* Pcsx2 - Pc Ps2 Emulator +* Copyright (C) 2009 Pcsx2-Playground 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 meived 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 "PrecompiledHeader.h" +#include "microVU.h" + +#ifdef PCSX2_MICROVU_lulz + +void mVU_UPPER_FD_00(VURegs* VU, s32 info); +void mVU_UPPER_FD_01(VURegs* VU, s32 info); +void mVU_UPPER_FD_10(VURegs* VU, s32 info); +void mVU_UPPER_FD_11(VURegs* VU, s32 info); +void mVULowerOP(VURegs* VU, s32 info); +void mVULowerOP_T3_00(VURegs* VU, s32 info); +void mVULowerOP_T3_01(VURegs* VU, s32 info); +void mVULowerOP_T3_10(VURegs* VU, s32 info); +void mVULowerOP_T3_11(VURegs* VU, s32 info); +void mVUunknown(VURegs* VU, s32 info); + +void (*mVU_LOWER_OPCODE[128])(VURegs* VU, s32 info) = { + mVU_LQ , mVU_SQ , mVUunknown , mVUunknown, + mVU_ILW , mVU_ISW , mVUunknown , mVUunknown, + mVU_IADDIU , mVU_ISUBIU , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVU_FCEQ , mVU_FCSET , mVU_FCAND , mVU_FCOR, /* 0x10 */ + mVU_FSEQ , mVU_FSSET , mVU_FSAND , mVU_FSOR, + mVU_FMEQ , mVUunknown , mVU_FMAND , mVU_FMOR, + mVU_FCGET , mVUunknown , mVUunknown , mVUunknown, + mVU_B , mVU_BAL , mVUunknown , mVUunknown, /* 0x20 */ + mVU_JR , mVU_JALR , mVUunknown , mVUunknown, + mVU_IBEQ , mVU_IBNE , mVUunknown , mVUunknown, + mVU_IBLTZ , mVU_IBGTZ , mVU_IBLEZ , mVU_IBGEZ, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, /* 0x30 */ + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVULowerOP , mVUunknown , mVUunknown , mVUunknown, /* 0x40*/ + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, /* 0x50 */ + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, /* 0x60 */ + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, /* 0x70 */ + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, +}; + +void (*mVULowerOP_T3_00_OPCODE[32])(VURegs* VU, s32 info) = { + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVU_MOVE , mVU_LQI , mVU_DIV , mVU_MTIR, + mVU_RNEXT , mVUunknown , mVUunknown , mVUunknown, /* 0x10 */ + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVU_MFP , mVU_XTOP , mVU_XGKICK, + mVU_ESADD , mVU_EATANxy , mVU_ESQRT , mVU_ESIN, +}; + +void (*mVULowerOP_T3_01_OPCODE[32])(VURegs* VU, s32 info) = { + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVU_MR32 , mVU_SQI , mVU_SQRT , mVU_MFIR, + mVU_RGET , mVUunknown , mVUunknown , mVUunknown, /* 0x10 */ + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVU_XITOP , mVUunknown, + mVU_ERSADD , mVU_EATANxz , mVU_ERSQRT , mVU_EATAN, +}; + +void (*mVULowerOP_T3_10_OPCODE[32])(VURegs* VU, s32 info) = { + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVU_LQD , mVU_RSQRT , mVU_ILWR, + mVU_RINIT , mVUunknown , mVUunknown , mVUunknown, /* 0x10 */ + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVU_ELENG , mVU_ESUM , mVU_ERCPR , mVU_EEXP, +}; + +void (*mVULowerOP_T3_11_OPCODE[32])(VURegs* VU, s32 info) = { + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVU_SQD , mVU_WAITQ , mVU_ISWR, + mVU_RXOR , mVUunknown , mVUunknown , mVUunknown, /* 0x10 */ + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVU_ERLENG , mVUunknown , mVU_WAITP , mVUunknown, +}; + +void (*mVULowerOP_OPCODE[64])(VURegs* VU, s32 info) = { + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, /* 0x10 */ + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, /* 0x20 */ + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVU_IADD , mVU_ISUB , mVU_IADDI , mVUunknown, /* 0x30 */ + mVU_IAND , mVU_IOR , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVULowerOP_T3_00, mVULowerOP_T3_01, mVULowerOP_T3_10, mVULowerOP_T3_11, +}; + +void (*mVU_UPPER_OPCODE[64])(VURegs* VU, s32 info) = { + mVU_ADDx , mVU_ADDy , mVU_ADDz , mVU_ADDw, + mVU_SUBx , mVU_SUBy , mVU_SUBz , mVU_SUBw, + mVU_MADDx , mVU_MADDy , mVU_MADDz , mVU_MADDw, + mVU_MSUBx , mVU_MSUBy , mVU_MSUBz , mVU_MSUBw, + mVU_MAXx , mVU_MAXy , mVU_MAXz , mVU_MAXw, /* 0x10 */ + mVU_MINIx , mVU_MINIy , mVU_MINIz , mVU_MINIw, + mVU_MULx , mVU_MULy , mVU_MULz , mVU_MULw, + mVU_MULq , mVU_MAXi , mVU_MULi , mVU_MINIi, + mVU_ADDq , mVU_MADDq , mVU_ADDi , mVU_MADDi, /* 0x20 */ + mVU_SUBq , mVU_MSUBq , mVU_SUBi , mVU_MSUBi, + mVU_ADD , mVU_MADD , mVU_MUL , mVU_MAX, + mVU_SUB , mVU_MSUB , mVU_OPMSUB , mVU_MINI, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, /* 0x30 */ + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVU_UPPER_FD_00, mVU_UPPER_FD_01, mVU_UPPER_FD_10, mVU_UPPER_FD_11, +}; + +void (*mVU_UPPER_FD_00_TABLE[32])(VURegs* VU, s32 info) = { + mVU_ADDAx , mVU_SUBAx , mVU_MADDAx , mVU_MSUBAx, + mVU_ITOF0 , mVU_FTOI0 , mVU_MULAx , mVU_MULAq, + mVU_ADDAq , mVU_SUBAq , mVU_ADDA , mVU_SUBA, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, +}; + +void (*mVU_UPPER_FD_01_TABLE[32])(VURegs* VU, s32 info) = { + mVU_ADDAy , mVU_SUBAy , mVU_MADDAy , mVU_MSUBAy, + mVU_ITOF4 , mVU_FTOI4 , mVU_MULAy , mVU_ABS, + mVU_MADDAq , mVU_MSUBAq , mVU_MADDA , mVU_MSUBA, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, +}; + +void (*mVU_UPPER_FD_10_TABLE[32])(VURegs* VU, s32 info) = { + mVU_ADDAz , mVU_SUBAz , mVU_MADDAz , mVU_MSUBAz, + mVU_ITOF12 , mVU_FTOI12 , mVU_MULAz , mVU_MULAi, + mVU_ADDAi , mVU_SUBAi , mVU_MULA , mVU_OPMULA, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, +}; + +void (*mVU_UPPER_FD_11_TABLE[32])(VURegs* VU, s32 info) = { + mVU_ADDAw , mVU_SUBAw , mVU_MADDAw , mVU_MSUBAw, + mVU_ITOF15 , mVU_FTOI15 , mVU_MULAw , mVU_CLIP, + mVU_MADDAi , mVU_MSUBAi , mVUunknown , mVU_NOP, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, + mVUunknown , mVUunknown , mVUunknown , mVUunknown, +}; + +void mVU_UPPER_FD_00(VURegs* VU, s32 info) { + mVU_UPPER_FD_00_TABLE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); +} +void mVU_UPPER_FD_01(VURegs* VU, s32 info) { + mVU_UPPER_FD_01_TABLE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); +} +void mVU_UPPER_FD_10(VURegs* VU, s32 info) { + mVU_UPPER_FD_10_TABLE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); +} +void mVU_UPPER_FD_11(VURegs* VU, s32 info) { + mVU_UPPER_FD_11_TABLE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); +} +void mVULowerOP(VURegs* VU, s32 info) { + mVULowerOP_OPCODE[ VU->code & 0x3f ]( VU, info ); +} +void mVULowerOP_T3_00(VURegs* VU, s32 info) { + mVULowerOP_T3_00_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); +} +void mVULowerOP_T3_01(VURegs* VU, s32 info) { + mVULowerOP_T3_01_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); +} +void mVULowerOP_T3_10(VURegs* VU, s32 info) { + mVULowerOP_T3_10_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); +} +void mVULowerOP_T3_11(VURegs* VU, s32 info) { + mVULowerOP_T3_11_OPCODE[ ( VU->code >> 6 ) & 0x1f ]( VU, info ); +} +void mVUunknown(VURegs* VU, s32 info) { + SysPrintf("Unknown Micro VU opcode called\n"); +} + +#endif diff --git a/pcsx2/x86/microVU_Tables.h b/pcsx2/x86/microVU_Tables.h index e9b8f26500..1b36bab504 100644 --- a/pcsx2/x86/microVU_Tables.h +++ b/pcsx2/x86/microVU_Tables.h @@ -1,195 +1,195 @@ -/* Pcsx2 - Pc Ps2 Emulator -* Copyright (C) 2009 Pcsx2-Playground 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 meived 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 - -//------------------------------------------------------------------ -// Micro VU Micromode Upper instructions -//------------------------------------------------------------------ - -void mVU_ABS(VURegs *vuRegs, int info); -void mVU_ADD(VURegs *vuRegs, int info); -void mVU_ADDi(VURegs *vuRegs, int info); -void mVU_ADDq(VURegs *vuRegs, int info); -void mVU_ADDx(VURegs *vuRegs, int info); -void mVU_ADDy(VURegs *vuRegs, int info); -void mVU_ADDz(VURegs *vuRegs, int info); -void mVU_ADDw(VURegs *vuRegs, int info); -void mVU_ADDA(VURegs *vuRegs, int info); -void mVU_ADDAi(VURegs *vuRegs, int info); -void mVU_ADDAq(VURegs *vuRegs, int info); -void mVU_ADDAx(VURegs *vuRegs, int info); -void mVU_ADDAy(VURegs *vuRegs, int info); -void mVU_ADDAz(VURegs *vuRegs, int info); -void mVU_ADDAw(VURegs *vuRegs, int info); -void mVU_SUB(VURegs *vuRegs, int info); -void mVU_SUBi(VURegs *vuRegs, int info); -void mVU_SUBq(VURegs *vuRegs, int info); -void mVU_SUBx(VURegs *vuRegs, int info); -void mVU_SUBy(VURegs *vuRegs, int info); -void mVU_SUBz(VURegs *vuRegs, int info); -void mVU_SUBw(VURegs *vuRegs, int info); -void mVU_SUBA(VURegs *vuRegs, int info); -void mVU_SUBAi(VURegs *vuRegs, int info); -void mVU_SUBAq(VURegs *vuRegs, int info); -void mVU_SUBAx(VURegs *vuRegs, int info); -void mVU_SUBAy(VURegs *vuRegs, int info); -void mVU_SUBAz(VURegs *vuRegs, int info); -void mVU_SUBAw(VURegs *vuRegs, int info); -void mVU_MUL(VURegs *vuRegs, int info); -void mVU_MULi(VURegs *vuRegs, int info); -void mVU_MULq(VURegs *vuRegs, int info); -void mVU_MULx(VURegs *vuRegs, int info); -void mVU_MULy(VURegs *vuRegs, int info); -void mVU_MULz(VURegs *vuRegs, int info); -void mVU_MULw(VURegs *vuRegs, int info); -void mVU_MULA(VURegs *vuRegs, int info); -void mVU_MULAi(VURegs *vuRegs, int info); -void mVU_MULAq(VURegs *vuRegs, int info); -void mVU_MULAx(VURegs *vuRegs, int info); -void mVU_MULAy(VURegs *vuRegs, int info); -void mVU_MULAz(VURegs *vuRegs, int info); -void mVU_MULAw(VURegs *vuRegs, int info); -void mVU_MADD(VURegs *vuRegs, int info); -void mVU_MADDi(VURegs *vuRegs, int info); -void mVU_MADDq(VURegs *vuRegs, int info); -void mVU_MADDx(VURegs *vuRegs, int info); -void mVU_MADDy(VURegs *vuRegs, int info); -void mVU_MADDz(VURegs *vuRegs, int info); -void mVU_MADDw(VURegs *vuRegs, int info); -void mVU_MADDA(VURegs *vuRegs, int info); -void mVU_MADDAi(VURegs *vuRegs, int info); -void mVU_MADDAq(VURegs *vuRegs, int info); -void mVU_MADDAx(VURegs *vuRegs, int info); -void mVU_MADDAy(VURegs *vuRegs, int info); -void mVU_MADDAz(VURegs *vuRegs, int info); -void mVU_MADDAw(VURegs *vuRegs, int info); -void mVU_MSUB(VURegs *vuRegs, int info); -void mVU_MSUBi(VURegs *vuRegs, int info); -void mVU_MSUBq(VURegs *vuRegs, int info); -void mVU_MSUBx(VURegs *vuRegs, int info); -void mVU_MSUBy(VURegs *vuRegs, int info); -void mVU_MSUBz(VURegs *vuRegs, int info); -void mVU_MSUBw(VURegs *vuRegs, int info); -void mVU_MSUBA(VURegs *vuRegs, int info); -void mVU_MSUBAi(VURegs *vuRegs, int info); -void mVU_MSUBAq(VURegs *vuRegs, int info); -void mVU_MSUBAx(VURegs *vuRegs, int info); -void mVU_MSUBAy(VURegs *vuRegs, int info); -void mVU_MSUBAz(VURegs *vuRegs, int info); -void mVU_MSUBAw(VURegs *vuRegs, int info); -void mVU_MAX(VURegs *vuRegs, int info); -void mVU_MAXi(VURegs *vuRegs, int info); -void mVU_MAXx(VURegs *vuRegs, int info); -void mVU_MAXy(VURegs *vuRegs, int info); -void mVU_MAXz(VURegs *vuRegs, int info); -void mVU_MAXw(VURegs *vuRegs, int info); -void mVU_MINI(VURegs *vuRegs, int info); -void mVU_MINIi(VURegs *vuRegs, int info); -void mVU_MINIx(VURegs *vuRegs, int info); -void mVU_MINIy(VURegs *vuRegs, int info); -void mVU_MINIz(VURegs *vuRegs, int info); -void mVU_MINIw(VURegs *vuRegs, int info); -void mVU_OPMULA(VURegs *vuRegs, int info); -void mVU_OPMSUB(VURegs *vuRegs, int info); -void mVU_NOP(VURegs *vuRegs, int info); -void mVU_FTOI0(VURegs *vuRegs, int info); -void mVU_FTOI4(VURegs *vuRegs, int info); -void mVU_FTOI12(VURegs *vuRegs, int info); -void mVU_FTOI15(VURegs *vuRegs, int info); -void mVU_ITOF0(VURegs *vuRegs, int info); -void mVU_ITOF4(VURegs *vuRegs, int info); -void mVU_ITOF12(VURegs *vuRegs, int info); -void mVU_ITOF15(VURegs *vuRegs, int info); -void mVU_CLIP(VURegs *vuRegs, int info); - -//------------------------------------------------------------------ -// Micro VU Micromode Lower instructions -//------------------------------------------------------------------ - -void mVU_DIV(VURegs *vuRegs, int info); -void mVU_SQRT(VURegs *vuRegs, int info); -void mVU_RSQRT(VURegs *vuRegs, int info); -void mVU_IADD(VURegs *vuRegs, int info); -void mVU_IADDI(VURegs *vuRegs, int info); -void mVU_IADDIU(VURegs *vuRegs, int info); -void mVU_IAND(VURegs *vuRegs, int info); -void mVU_IOR(VURegs *vuRegs, int info); -void mVU_ISUB(VURegs *vuRegs, int info); -void mVU_ISUBIU(VURegs *vuRegs, int info); -void mVU_MOVE(VURegs *vuRegs, int info); -void mVU_MFIR(VURegs *vuRegs, int info); -void mVU_MTIR(VURegs *vuRegs, int info); -void mVU_MR32(VURegs *vuRegs, int info); -void mVU_LQ(VURegs *vuRegs, int info); -void mVU_LQD(VURegs *vuRegs, int info); -void mVU_LQI(VURegs *vuRegs, int info); -void mVU_SQ(VURegs *vuRegs, int info); -void mVU_SQD(VURegs *vuRegs, int info); -void mVU_SQI(VURegs *vuRegs, int info); -void mVU_ILW(VURegs *vuRegs, int info); -void mVU_ISW(VURegs *vuRegs, int info); -void mVU_ILWR(VURegs *vuRegs, int info); -void mVU_ISWR(VURegs *vuRegs, int info); -void mVU_LOI(VURegs *vuRegs, int info); -void mVU_RINIT(VURegs *vuRegs, int info); -void mVU_RGET(VURegs *vuRegs, int info); -void mVU_RNEXT(VURegs *vuRegs, int info); -void mVU_RXOR(VURegs *vuRegs, int info); -void mVU_WAITQ(VURegs *vuRegs, int info); -void mVU_FSAND(VURegs *vuRegs, int info); -void mVU_FSEQ(VURegs *vuRegs, int info); -void mVU_FSOR(VURegs *vuRegs, int info); -void mVU_FSSET(VURegs *vuRegs, int info); -void mVU_FMAND(VURegs *vuRegs, int info); -void mVU_FMEQ(VURegs *vuRegs, int info); -void mVU_FMOR(VURegs *vuRegs, int info); -void mVU_FCAND(VURegs *vuRegs, int info); -void mVU_FCEQ(VURegs *vuRegs, int info); -void mVU_FCOR(VURegs *vuRegs, int info); -void mVU_FCSET(VURegs *vuRegs, int info); -void mVU_FCGET(VURegs *vuRegs, int info); -void mVU_IBEQ(VURegs *vuRegs, int info); -void mVU_IBGEZ(VURegs *vuRegs, int info); -void mVU_IBGTZ(VURegs *vuRegs, int info); -void mVU_IBLTZ(VURegs *vuRegs, int info); -void mVU_IBLEZ(VURegs *vuRegs, int info); -void mVU_IBNE(VURegs *vuRegs, int info); -void mVU_B(VURegs *vuRegs, int info); -void mVU_BAL(VURegs *vuRegs, int info); -void mVU_JR(VURegs *vuRegs, int info); -void mVU_JALR(VURegs *vuRegs, int info); -void mVU_MFP(VURegs *vuRegs, int info); -void mVU_WAITP(VURegs *vuRegs, int info); -void mVU_ESADD(VURegs *vuRegs, int info); -void mVU_ERSADD(VURegs *vuRegs, int info); -void mVU_ELENG(VURegs *vuRegs, int info); -void mVU_ERLENG(VURegs *vuRegs, int info); -void mVU_EATANxy(VURegs *vuRegs, int info); -void mVU_EATANxz(VURegs *vuRegs, int info); -void mVU_ESUM(VURegs *vuRegs, int info); -void mVU_ERCPR(VURegs *vuRegs, int info); -void mVU_ESQRT(VURegs *vuRegs, int info); -void mVU_ERSQRT(VURegs *vuRegs, int info); -void mVU_ESIN(VURegs *vuRegs, int info); -void mVU_EATAN(VURegs *vuRegs, int info); -void mVU_EEXP(VURegs *vuRegs, int info); -void mVU_XGKICK(VURegs *vuRegs, int info); -void mVU_XTOP(VURegs *vuRegs, int info); -void mVU_XITOP(VURegs *vuRegs, int info); -void mVU_XTOP( VURegs *VU , int info); +/* Pcsx2 - Pc Ps2 Emulator +* Copyright (C) 2009 Pcsx2-Playground 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 meived 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 + +//------------------------------------------------------------------ +// Micro VU Micromode Upper instructions +//------------------------------------------------------------------ + +void mVU_ABS(VURegs *vuRegs, int info); +void mVU_ADD(VURegs *vuRegs, int info); +void mVU_ADDi(VURegs *vuRegs, int info); +void mVU_ADDq(VURegs *vuRegs, int info); +void mVU_ADDx(VURegs *vuRegs, int info); +void mVU_ADDy(VURegs *vuRegs, int info); +void mVU_ADDz(VURegs *vuRegs, int info); +void mVU_ADDw(VURegs *vuRegs, int info); +void mVU_ADDA(VURegs *vuRegs, int info); +void mVU_ADDAi(VURegs *vuRegs, int info); +void mVU_ADDAq(VURegs *vuRegs, int info); +void mVU_ADDAx(VURegs *vuRegs, int info); +void mVU_ADDAy(VURegs *vuRegs, int info); +void mVU_ADDAz(VURegs *vuRegs, int info); +void mVU_ADDAw(VURegs *vuRegs, int info); +void mVU_SUB(VURegs *vuRegs, int info); +void mVU_SUBi(VURegs *vuRegs, int info); +void mVU_SUBq(VURegs *vuRegs, int info); +void mVU_SUBx(VURegs *vuRegs, int info); +void mVU_SUBy(VURegs *vuRegs, int info); +void mVU_SUBz(VURegs *vuRegs, int info); +void mVU_SUBw(VURegs *vuRegs, int info); +void mVU_SUBA(VURegs *vuRegs, int info); +void mVU_SUBAi(VURegs *vuRegs, int info); +void mVU_SUBAq(VURegs *vuRegs, int info); +void mVU_SUBAx(VURegs *vuRegs, int info); +void mVU_SUBAy(VURegs *vuRegs, int info); +void mVU_SUBAz(VURegs *vuRegs, int info); +void mVU_SUBAw(VURegs *vuRegs, int info); +void mVU_MUL(VURegs *vuRegs, int info); +void mVU_MULi(VURegs *vuRegs, int info); +void mVU_MULq(VURegs *vuRegs, int info); +void mVU_MULx(VURegs *vuRegs, int info); +void mVU_MULy(VURegs *vuRegs, int info); +void mVU_MULz(VURegs *vuRegs, int info); +void mVU_MULw(VURegs *vuRegs, int info); +void mVU_MULA(VURegs *vuRegs, int info); +void mVU_MULAi(VURegs *vuRegs, int info); +void mVU_MULAq(VURegs *vuRegs, int info); +void mVU_MULAx(VURegs *vuRegs, int info); +void mVU_MULAy(VURegs *vuRegs, int info); +void mVU_MULAz(VURegs *vuRegs, int info); +void mVU_MULAw(VURegs *vuRegs, int info); +void mVU_MADD(VURegs *vuRegs, int info); +void mVU_MADDi(VURegs *vuRegs, int info); +void mVU_MADDq(VURegs *vuRegs, int info); +void mVU_MADDx(VURegs *vuRegs, int info); +void mVU_MADDy(VURegs *vuRegs, int info); +void mVU_MADDz(VURegs *vuRegs, int info); +void mVU_MADDw(VURegs *vuRegs, int info); +void mVU_MADDA(VURegs *vuRegs, int info); +void mVU_MADDAi(VURegs *vuRegs, int info); +void mVU_MADDAq(VURegs *vuRegs, int info); +void mVU_MADDAx(VURegs *vuRegs, int info); +void mVU_MADDAy(VURegs *vuRegs, int info); +void mVU_MADDAz(VURegs *vuRegs, int info); +void mVU_MADDAw(VURegs *vuRegs, int info); +void mVU_MSUB(VURegs *vuRegs, int info); +void mVU_MSUBi(VURegs *vuRegs, int info); +void mVU_MSUBq(VURegs *vuRegs, int info); +void mVU_MSUBx(VURegs *vuRegs, int info); +void mVU_MSUBy(VURegs *vuRegs, int info); +void mVU_MSUBz(VURegs *vuRegs, int info); +void mVU_MSUBw(VURegs *vuRegs, int info); +void mVU_MSUBA(VURegs *vuRegs, int info); +void mVU_MSUBAi(VURegs *vuRegs, int info); +void mVU_MSUBAq(VURegs *vuRegs, int info); +void mVU_MSUBAx(VURegs *vuRegs, int info); +void mVU_MSUBAy(VURegs *vuRegs, int info); +void mVU_MSUBAz(VURegs *vuRegs, int info); +void mVU_MSUBAw(VURegs *vuRegs, int info); +void mVU_MAX(VURegs *vuRegs, int info); +void mVU_MAXi(VURegs *vuRegs, int info); +void mVU_MAXx(VURegs *vuRegs, int info); +void mVU_MAXy(VURegs *vuRegs, int info); +void mVU_MAXz(VURegs *vuRegs, int info); +void mVU_MAXw(VURegs *vuRegs, int info); +void mVU_MINI(VURegs *vuRegs, int info); +void mVU_MINIi(VURegs *vuRegs, int info); +void mVU_MINIx(VURegs *vuRegs, int info); +void mVU_MINIy(VURegs *vuRegs, int info); +void mVU_MINIz(VURegs *vuRegs, int info); +void mVU_MINIw(VURegs *vuRegs, int info); +void mVU_OPMULA(VURegs *vuRegs, int info); +void mVU_OPMSUB(VURegs *vuRegs, int info); +void mVU_NOP(VURegs *vuRegs, int info); +void mVU_FTOI0(VURegs *vuRegs, int info); +void mVU_FTOI4(VURegs *vuRegs, int info); +void mVU_FTOI12(VURegs *vuRegs, int info); +void mVU_FTOI15(VURegs *vuRegs, int info); +void mVU_ITOF0(VURegs *vuRegs, int info); +void mVU_ITOF4(VURegs *vuRegs, int info); +void mVU_ITOF12(VURegs *vuRegs, int info); +void mVU_ITOF15(VURegs *vuRegs, int info); +void mVU_CLIP(VURegs *vuRegs, int info); + +//------------------------------------------------------------------ +// Micro VU Micromode Lower instructions +//------------------------------------------------------------------ + +void mVU_DIV(VURegs *vuRegs, int info); +void mVU_SQRT(VURegs *vuRegs, int info); +void mVU_RSQRT(VURegs *vuRegs, int info); +void mVU_IADD(VURegs *vuRegs, int info); +void mVU_IADDI(VURegs *vuRegs, int info); +void mVU_IADDIU(VURegs *vuRegs, int info); +void mVU_IAND(VURegs *vuRegs, int info); +void mVU_IOR(VURegs *vuRegs, int info); +void mVU_ISUB(VURegs *vuRegs, int info); +void mVU_ISUBIU(VURegs *vuRegs, int info); +void mVU_MOVE(VURegs *vuRegs, int info); +void mVU_MFIR(VURegs *vuRegs, int info); +void mVU_MTIR(VURegs *vuRegs, int info); +void mVU_MR32(VURegs *vuRegs, int info); +void mVU_LQ(VURegs *vuRegs, int info); +void mVU_LQD(VURegs *vuRegs, int info); +void mVU_LQI(VURegs *vuRegs, int info); +void mVU_SQ(VURegs *vuRegs, int info); +void mVU_SQD(VURegs *vuRegs, int info); +void mVU_SQI(VURegs *vuRegs, int info); +void mVU_ILW(VURegs *vuRegs, int info); +void mVU_ISW(VURegs *vuRegs, int info); +void mVU_ILWR(VURegs *vuRegs, int info); +void mVU_ISWR(VURegs *vuRegs, int info); +void mVU_LOI(VURegs *vuRegs, int info); +void mVU_RINIT(VURegs *vuRegs, int info); +void mVU_RGET(VURegs *vuRegs, int info); +void mVU_RNEXT(VURegs *vuRegs, int info); +void mVU_RXOR(VURegs *vuRegs, int info); +void mVU_WAITQ(VURegs *vuRegs, int info); +void mVU_FSAND(VURegs *vuRegs, int info); +void mVU_FSEQ(VURegs *vuRegs, int info); +void mVU_FSOR(VURegs *vuRegs, int info); +void mVU_FSSET(VURegs *vuRegs, int info); +void mVU_FMAND(VURegs *vuRegs, int info); +void mVU_FMEQ(VURegs *vuRegs, int info); +void mVU_FMOR(VURegs *vuRegs, int info); +void mVU_FCAND(VURegs *vuRegs, int info); +void mVU_FCEQ(VURegs *vuRegs, int info); +void mVU_FCOR(VURegs *vuRegs, int info); +void mVU_FCSET(VURegs *vuRegs, int info); +void mVU_FCGET(VURegs *vuRegs, int info); +void mVU_IBEQ(VURegs *vuRegs, int info); +void mVU_IBGEZ(VURegs *vuRegs, int info); +void mVU_IBGTZ(VURegs *vuRegs, int info); +void mVU_IBLTZ(VURegs *vuRegs, int info); +void mVU_IBLEZ(VURegs *vuRegs, int info); +void mVU_IBNE(VURegs *vuRegs, int info); +void mVU_B(VURegs *vuRegs, int info); +void mVU_BAL(VURegs *vuRegs, int info); +void mVU_JR(VURegs *vuRegs, int info); +void mVU_JALR(VURegs *vuRegs, int info); +void mVU_MFP(VURegs *vuRegs, int info); +void mVU_WAITP(VURegs *vuRegs, int info); +void mVU_ESADD(VURegs *vuRegs, int info); +void mVU_ERSADD(VURegs *vuRegs, int info); +void mVU_ELENG(VURegs *vuRegs, int info); +void mVU_ERLENG(VURegs *vuRegs, int info); +void mVU_EATANxy(VURegs *vuRegs, int info); +void mVU_EATANxz(VURegs *vuRegs, int info); +void mVU_ESUM(VURegs *vuRegs, int info); +void mVU_ERCPR(VURegs *vuRegs, int info); +void mVU_ESQRT(VURegs *vuRegs, int info); +void mVU_ERSQRT(VURegs *vuRegs, int info); +void mVU_ESIN(VURegs *vuRegs, int info); +void mVU_EATAN(VURegs *vuRegs, int info); +void mVU_EEXP(VURegs *vuRegs, int info); +void mVU_XGKICK(VURegs *vuRegs, int info); +void mVU_XTOP(VURegs *vuRegs, int info); +void mVU_XITOP(VURegs *vuRegs, int info); +void mVU_XTOP( VURegs *VU , int info); diff --git a/pcsx2/x86/microVU_Upper.cpp b/pcsx2/x86/microVU_Upper.cpp index 95bfc6502c..addd54b008 100644 --- a/pcsx2/x86/microVU_Upper.cpp +++ b/pcsx2/x86/microVU_Upper.cpp @@ -1,71 +1,71 @@ -/* Pcsx2 - Pc Ps2 Emulator -* Copyright (C) 2009 Pcsx2-Playground 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 "PrecompiledHeader.h" - -/* -Cotton's Notes on how things will work (*experimental*, subject to change if I get different ideas): - -Guide: -Fd, Fs, Ft = operands in the Micro Instructions -Acc = VU's Accumulator register -Fs/t = shorthand notation I made-up for "Fs or Ft" -xmmFd, xmmFs, xmmFt, xmmAcc = XMM regs that hold Fd, Fs, Ft, and Acc values respectively. -xmmZ = XMM reg that holds the zero Register; always {0, 0, 0, 1.0} -xmmT1, xmmT2, xmmT3 = temp regs. - -General: -XMM0 is a volatile temp reg throughout the recs. You can always freely use it. -EAX is a volatile temp reg. You can always freely use it. - -Mapping: -xmmT1 = xmm0 -xmmFd = xmm1 -xmmFs = xmm2 -xmmFt = xmm3 -xmmAcc = xmm4 -xmmT2 = xmm5 -xmmT3 = xmm6 -xmmZ = xmm7 - -Most of the time the above mapping will be true, unless I find a reason not to do it this way :) - -Opcodes: -Fd's 4-vectors must be preserved (kept valid); Unless operation is single-scalar, then only 'x' XMM vector -will contain valid data for X, Y, Z, or W, and the other XMM vectors will be garbage and freely modifiable. - -Fs and Ft are temp regs that won't be used after the opcode, so their values can be freely modified. - -If (Fd == 0), Then you don't need to explicitly handle this case in the opcode implementation, - since its dealt-with in the analyzing microVU pipeline functions. - (So just do the normal operation and don't worry about it.) - -If (_X_Y_Z_W == 0) Then same as above. (btw, I'm'm not sure if this case ever happens...) - -If (Fd == Fs/t), Then xmmFd != xmmFs/t (unless its more optimized this way! it'll be commented on the opcode) - -Clamping: -Fs/t can always be clamped by case 15 (all vectors modified) since they won't be written back. - -Problems: -The biggest problem I think I'll have is xgkick opcode having variable timing/stalling. - -Other Notes: -These notes are mostly to help me (cottonvibes) remember good ideas and to help confused devs to -have an idea of how things work. Right now its all theoretical and I'll change things once implemented ;p +/* Pcsx2 - Pc Ps2 Emulator +* Copyright (C) 2009 Pcsx2-Playground 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 "PrecompiledHeader.h" + +/* +Cotton's Notes on how things will work (*experimental*, subject to change if I get different ideas): + +Guide: +Fd, Fs, Ft = operands in the Micro Instructions +Acc = VU's Accumulator register +Fs/t = shorthand notation I made-up for "Fs or Ft" +xmmFd, xmmFs, xmmFt, xmmAcc = XMM regs that hold Fd, Fs, Ft, and Acc values respectively. +xmmZ = XMM reg that holds the zero Register; always {0, 0, 0, 1.0} +xmmT1, xmmT2, xmmT3 = temp regs. + +General: +XMM0 is a volatile temp reg throughout the recs. You can always freely use it. +EAX is a volatile temp reg. You can always freely use it. + +Mapping: +xmmT1 = xmm0 +xmmFd = xmm1 +xmmFs = xmm2 +xmmFt = xmm3 +xmmAcc = xmm4 +xmmT2 = xmm5 +xmmT3 = xmm6 +xmmZ = xmm7 + +Most of the time the above mapping will be true, unless I find a reason not to do it this way :) + +Opcodes: +Fd's 4-vectors must be preserved (kept valid); Unless operation is single-scalar, then only 'x' XMM vector +will contain valid data for X, Y, Z, or W, and the other XMM vectors will be garbage and freely modifiable. + +Fs and Ft are temp regs that won't be used after the opcode, so their values can be freely modified. + +If (Fd == 0), Then you don't need to explicitly handle this case in the opcode implementation, + since its dealt-with in the analyzing microVU pipeline functions. + (So just do the normal operation and don't worry about it.) + +If (_X_Y_Z_W == 0) Then same as above. (btw, I'm'm not sure if this case ever happens...) + +If (Fd == Fs/t), Then xmmFd != xmmFs/t (unless its more optimized this way! it'll be commented on the opcode) + +Clamping: +Fs/t can always be clamped by case 15 (all vectors modified) since they won't be written back. + +Problems: +The biggest problem I think I'll have is xgkick opcode having variable timing/stalling. + +Other Notes: +These notes are mostly to help me (cottonvibes) remember good ideas and to help confused devs to +have an idea of how things work. Right now its all theoretical and I'll change things once implemented ;p */ \ No newline at end of file diff --git a/pcsx2/xmlpatchloader.cpp b/pcsx2/xmlpatchloader.cpp index 5fd232f4cb..8646afce2f 100644 --- a/pcsx2/xmlpatchloader.cpp +++ b/pcsx2/xmlpatchloader.cpp @@ -1,373 +1,373 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" - -using namespace std; - -#include "tinyxml/tinyxml.h" - -#include "Patch.h" -#include "System.h" - -#ifdef _MSC_VER -#pragma warning(disable:4996) //ignore the stricmp deprecated warning -#endif - -#ifdef _WIN32 -#include -#endif - -#if !defined(_WIN32) -#ifndef strnicmp -#define strnicmp strncasecmp -#endif - -#ifndef stricmp -#define stricmp strcasecmp -#endif -#else -#define strnicmp _strnicmp -#define stricmp _stricmp -#endif - -#include "../cheatscpp.h" - -int LoadGroup(TiXmlNode *group, int parent); - -Group::Group(int nParent,bool nEnabled, string &nTitle): - parentIndex(nParent),enabled(nEnabled),title(nTitle) -{ -} - -Patch::Patch(int patch, int grp, bool en, string &ttl): - title(ttl), - group(grp), - enabled(en), - patchIndex(patch) -{ -} - -Patch Patch::operator =(const Patch&p) -{ - title.assign(p.title); - group=p.group; - enabled=p.enabled; - patchIndex=p.patchIndex; - return *this; -} - - -vector groups; -vector patches; - -int LoadPatch( const string& crc) -{ - char pfile[256]; - sprintf(pfile,"patches\\%hs.xml",&crc); - - patchnumber=0; - - TiXmlDocument doc( pfile ); - bool loadOkay = doc.LoadFile(); - if ( !loadOkay ) - { - //SysPrintf("XML Patch Loader: Could not load file '%s'. Error='%s'.\n", pfile, doc.ErrorDesc() ); - return -1; - } else SysPrintf("XML Patch Loader: '%s' Found\n", pfile); - - TiXmlNode *root = doc.FirstChild("GAME"); - if(!root) - { - SysPrintf("XML Patch Loader: Root node is not GAME, invalid patch file.\n"); - return -1; - } - - TiXmlElement *rootelement = root->ToElement(); - - const char *title=rootelement->Attribute("title"); - if(title) - SysPrintf("XML Patch Loader: Game Title: %s\n",title); - - int result=LoadGroup(root,-1); - if(result) { - patchnumber=0; - return result; - } - - Console::SetTitle( - ((title==NULL) || (strlen(title)==0)) ? "" : title ); - - return 0; -} - - -int LoadGroup(TiXmlNode *group,int gParent) -{ - TiXmlElement *groupelement = group->ToElement(); - - const char *gtitle=groupelement->Attribute("title"); - if(gtitle) - SysPrintf("XML Patch Loader: Group Title: %s\n",gtitle); - - const char *enable=groupelement->Attribute("enabled"); - bool gEnabled=true; - if(enable) - { - if(strcmp(enable,"false")==0) - { - SysPrintf("XML Patch Loader: Group is disabled.\n"); - gEnabled=false; - } - } - - TiXmlNode *comment = group->FirstChild("COMMENT"); - if(comment) - { - TiXmlElement *cmelement = comment->ToElement(); - const char *comment = cmelement->GetText(); - if(comment) - SysPrintf("XML Patch Loader: Group Comment:\n%s\n---\n",comment); - } - - string t; - - if(gtitle) - t.assign(gtitle); - else - t.clear(); - - Group gp=Group(gParent,gEnabled,t); - groups.push_back(gp); - - int gIndex=groups.size()-1; - - // only valid for recompilers - TiXmlNode *fastmemory=group->FirstChild("FASTMEMORY"); - if(fastmemory!=NULL) - SetFastMemory(1); - - TiXmlNode *zerogs=group->FirstChild("ZEROGS"); - if(zerogs!=NULL) - { - TiXmlElement *rm=zerogs->ToElement(); - const char* pid = rm->FirstAttribute()->Value(); - if( pid != NULL ) sscanf(pid, "%x", &g_ZeroGSOptions); - else SysPrintf("zerogs attribute wrong"); - } - - TiXmlNode *roundmode=group->FirstChild("ROUNDMODE"); - if(roundmode!=NULL) - { - int eetype=0x0000; - int vutype=0x6000; - - TiXmlElement *rm=roundmode->ToElement(); - if(rm!=NULL) - { - const char *eetext=rm->Attribute("ee"); - const char *vutext=rm->Attribute("vu"); - - if(eetext != NULL) { - eetype = 0xffff; - if( stricmp(eetext, "near") == 0 ) { - eetype = 0x0000; - } - else if( stricmp(eetext, "down") == 0 ) { - eetype = 0x2000; - } - else if( stricmp(eetext, "up") == 0 ) { - eetype = 0x4000; - } - else if( stricmp(eetext, "chop") == 0 ) { - eetype = 0x6000; - } - } - - if(vutext != NULL) { - vutype = 0xffff; - if( stricmp(vutext, "near") == 0 ) { - vutype = 0x0000; - } - else if( stricmp(vutext, "down") == 0 ) { - vutype = 0x2000; - } - else if( stricmp(vutext, "up") == 0 ) { - vutype = 0x4000; - } - else if( stricmp(vutext, "chop") == 0 ) { - vutype = 0x6000; - } - } - } - if(( eetype == 0xffff )||( vutype == 0xffff )) { - printf("XML Patch Loader: WARNING: Invalid value in ROUNDMODE.\n"); - } - else { - SetRoundMode(eetype,vutype); - } - } - - TiXmlNode *cpatch = group->FirstChild("PATCH"); - while(cpatch) - { - TiXmlElement *celement = cpatch->ToElement(); - if(!celement) - { - SysPrintf("XML Patch Loader: ERROR: Couldn't convert node to element.\n" ); - return -1; - } - - - const char *ptitle=celement->Attribute("title"); - const char *penable=celement->Attribute("enabled"); - const char *applymode=celement->Attribute("applymode"); - const char *place=celement->Attribute("place"); - const char *address=celement->Attribute("address"); - const char *size=celement->Attribute("size"); - const char *value=celement->Attribute("value"); - - if(ptitle) { - SysPrintf("XML Patch Loader: Patch title: %s\n", ptitle); - } - - bool penabled=gEnabled; - if(penable) - { - if(strcmp(penable,"false")==0) - { - SysPrintf("XML Patch Loader: Patch is disabled.\n"); - penabled=false; - } - } - - if(!applymode) applymode="frame"; - if(!place) place="EE"; - if(!address) { - SysPrintf("XML Patch Loader: ERROR: Patch doesn't contain an address.\n"); - return -1; - } - if(!value) { - SysPrintf("XML Patch Loader: ERROR: Patch doesn't contain a value.\n"); - return -1; - } - if(!size) { - SysPrintf("XML Patch Loader: WARNING: Patch doesn't contain the size. Trying to deduce from the value size.\n"); - switch(strlen(value)) - { - case 8: - case 7: - case 6: - case 5: - size="32"; - break; - case 4: - case 3: - size="16"; - break; - case 2: - case 1: - size="8"; - break; - case 0: - size="0"; - break; - default: - size="64"; - break; - } - } - - if(strcmp(applymode,"startup")==0) - { - patch[patchnumber].placetopatch=0; - } else - if(strcmp(applymode,"vsync")==0) - { - patch[patchnumber].placetopatch=1; - } else - { - SysPrintf("XML Patch Loader: ERROR: Invalid applymode attribute.\n"); - patchnumber=0; - return -1; - } - - if(strcmp(place,"EE")==0) - { - patch[patchnumber].cpu= CPU_EE; - } else - if(strcmp(place,"IOP")==0) - { - patch[patchnumber].cpu= CPU_IOP; - } else - { - SysPrintf("XML Patch Loader: ERROR: Invalid place attribute.\n"); - patchnumber=0; - return -1; - } - - if(strcmp(size,"64")==0) - { - patch[patchnumber].type = DOUBLE_T; - } else - if(strcmp(size,"32")==0) - { - patch[patchnumber].type = WORD_T; - } else - if(strcmp(size,"16")==0) - { - patch[patchnumber].type = SHORT_T; - } else - if(strcmp(size,"8")==0) - { - patch[patchnumber].type = BYTE_T; - } else - { - SysPrintf("XML Patch Loader: ERROR: Invalid size attribute.\n"); - patchnumber=0; - return -1; - } - - sscanf( address, "%X", &patch[ patchnumber ].addr ); - sscanf( value, "%I64X", &patch[ patchnumber ].data ); - - patch[patchnumber].enabled=penabled?1:0; - - string pt; - - if(ptitle) - pt.assign(ptitle); - else - pt.clear(); - - Patch p=Patch(patchnumber,gIndex,penabled,pt); - patches.push_back(p); - - patchnumber++; - - cpatch = cpatch->NextSibling("PATCH"); - } - - cpatch = group->FirstChild("GROUP"); - while(cpatch) { - int result=LoadGroup(cpatch,gIndex); - if(result) return result; - cpatch = cpatch->NextSibling("GROUP"); - } - - return 0; -} +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 "PrecompiledHeader.h" + +using namespace std; + +#include "tinyxml/tinyxml.h" + +#include "Patch.h" +#include "System.h" + +#ifdef _MSC_VER +#pragma warning(disable:4996) //ignore the stricmp deprecated warning +#endif + +#ifdef _WIN32 +#include +#endif + +#if !defined(_WIN32) +#ifndef strnicmp +#define strnicmp strncasecmp +#endif + +#ifndef stricmp +#define stricmp strcasecmp +#endif +#else +#define strnicmp _strnicmp +#define stricmp _stricmp +#endif + +#include "../cheatscpp.h" + +int LoadGroup(TiXmlNode *group, int parent); + +Group::Group(int nParent,bool nEnabled, string &nTitle): + parentIndex(nParent),enabled(nEnabled),title(nTitle) +{ +} + +Patch::Patch(int patch, int grp, bool en, string &ttl): + title(ttl), + group(grp), + enabled(en), + patchIndex(patch) +{ +} + +Patch Patch::operator =(const Patch&p) +{ + title.assign(p.title); + group=p.group; + enabled=p.enabled; + patchIndex=p.patchIndex; + return *this; +} + + +vector groups; +vector patches; + +int LoadPatch( const string& crc) +{ + char pfile[256]; + sprintf(pfile,"patches\\%hs.xml",&crc); + + patchnumber=0; + + TiXmlDocument doc( pfile ); + bool loadOkay = doc.LoadFile(); + if ( !loadOkay ) + { + //SysPrintf("XML Patch Loader: Could not load file '%s'. Error='%s'.\n", pfile, doc.ErrorDesc() ); + return -1; + } else SysPrintf("XML Patch Loader: '%s' Found\n", pfile); + + TiXmlNode *root = doc.FirstChild("GAME"); + if(!root) + { + SysPrintf("XML Patch Loader: Root node is not GAME, invalid patch file.\n"); + return -1; + } + + TiXmlElement *rootelement = root->ToElement(); + + const char *title=rootelement->Attribute("title"); + if(title) + SysPrintf("XML Patch Loader: Game Title: %s\n",title); + + int result=LoadGroup(root,-1); + if(result) { + patchnumber=0; + return result; + } + + Console::SetTitle( + ((title==NULL) || (strlen(title)==0)) ? "" : title ); + + return 0; +} + + +int LoadGroup(TiXmlNode *group,int gParent) +{ + TiXmlElement *groupelement = group->ToElement(); + + const char *gtitle=groupelement->Attribute("title"); + if(gtitle) + SysPrintf("XML Patch Loader: Group Title: %s\n",gtitle); + + const char *enable=groupelement->Attribute("enabled"); + bool gEnabled=true; + if(enable) + { + if(strcmp(enable,"false")==0) + { + SysPrintf("XML Patch Loader: Group is disabled.\n"); + gEnabled=false; + } + } + + TiXmlNode *comment = group->FirstChild("COMMENT"); + if(comment) + { + TiXmlElement *cmelement = comment->ToElement(); + const char *comment = cmelement->GetText(); + if(comment) + SysPrintf("XML Patch Loader: Group Comment:\n%s\n---\n",comment); + } + + string t; + + if(gtitle) + t.assign(gtitle); + else + t.clear(); + + Group gp=Group(gParent,gEnabled,t); + groups.push_back(gp); + + int gIndex=groups.size()-1; + + // only valid for recompilers + TiXmlNode *fastmemory=group->FirstChild("FASTMEMORY"); + if(fastmemory!=NULL) + SetFastMemory(1); + + TiXmlNode *zerogs=group->FirstChild("ZEROGS"); + if(zerogs!=NULL) + { + TiXmlElement *rm=zerogs->ToElement(); + const char* pid = rm->FirstAttribute()->Value(); + if( pid != NULL ) sscanf(pid, "%x", &g_ZeroGSOptions); + else SysPrintf("zerogs attribute wrong"); + } + + TiXmlNode *roundmode=group->FirstChild("ROUNDMODE"); + if(roundmode!=NULL) + { + int eetype=0x0000; + int vutype=0x6000; + + TiXmlElement *rm=roundmode->ToElement(); + if(rm!=NULL) + { + const char *eetext=rm->Attribute("ee"); + const char *vutext=rm->Attribute("vu"); + + if(eetext != NULL) { + eetype = 0xffff; + if( stricmp(eetext, "near") == 0 ) { + eetype = 0x0000; + } + else if( stricmp(eetext, "down") == 0 ) { + eetype = 0x2000; + } + else if( stricmp(eetext, "up") == 0 ) { + eetype = 0x4000; + } + else if( stricmp(eetext, "chop") == 0 ) { + eetype = 0x6000; + } + } + + if(vutext != NULL) { + vutype = 0xffff; + if( stricmp(vutext, "near") == 0 ) { + vutype = 0x0000; + } + else if( stricmp(vutext, "down") == 0 ) { + vutype = 0x2000; + } + else if( stricmp(vutext, "up") == 0 ) { + vutype = 0x4000; + } + else if( stricmp(vutext, "chop") == 0 ) { + vutype = 0x6000; + } + } + } + if(( eetype == 0xffff )||( vutype == 0xffff )) { + printf("XML Patch Loader: WARNING: Invalid value in ROUNDMODE.\n"); + } + else { + SetRoundMode(eetype,vutype); + } + } + + TiXmlNode *cpatch = group->FirstChild("PATCH"); + while(cpatch) + { + TiXmlElement *celement = cpatch->ToElement(); + if(!celement) + { + SysPrintf("XML Patch Loader: ERROR: Couldn't convert node to element.\n" ); + return -1; + } + + + const char *ptitle=celement->Attribute("title"); + const char *penable=celement->Attribute("enabled"); + const char *applymode=celement->Attribute("applymode"); + const char *place=celement->Attribute("place"); + const char *address=celement->Attribute("address"); + const char *size=celement->Attribute("size"); + const char *value=celement->Attribute("value"); + + if(ptitle) { + SysPrintf("XML Patch Loader: Patch title: %s\n", ptitle); + } + + bool penabled=gEnabled; + if(penable) + { + if(strcmp(penable,"false")==0) + { + SysPrintf("XML Patch Loader: Patch is disabled.\n"); + penabled=false; + } + } + + if(!applymode) applymode="frame"; + if(!place) place="EE"; + if(!address) { + SysPrintf("XML Patch Loader: ERROR: Patch doesn't contain an address.\n"); + return -1; + } + if(!value) { + SysPrintf("XML Patch Loader: ERROR: Patch doesn't contain a value.\n"); + return -1; + } + if(!size) { + SysPrintf("XML Patch Loader: WARNING: Patch doesn't contain the size. Trying to deduce from the value size.\n"); + switch(strlen(value)) + { + case 8: + case 7: + case 6: + case 5: + size="32"; + break; + case 4: + case 3: + size="16"; + break; + case 2: + case 1: + size="8"; + break; + case 0: + size="0"; + break; + default: + size="64"; + break; + } + } + + if(strcmp(applymode,"startup")==0) + { + patch[patchnumber].placetopatch=0; + } else + if(strcmp(applymode,"vsync")==0) + { + patch[patchnumber].placetopatch=1; + } else + { + SysPrintf("XML Patch Loader: ERROR: Invalid applymode attribute.\n"); + patchnumber=0; + return -1; + } + + if(strcmp(place,"EE")==0) + { + patch[patchnumber].cpu= CPU_EE; + } else + if(strcmp(place,"IOP")==0) + { + patch[patchnumber].cpu= CPU_IOP; + } else + { + SysPrintf("XML Patch Loader: ERROR: Invalid place attribute.\n"); + patchnumber=0; + return -1; + } + + if(strcmp(size,"64")==0) + { + patch[patchnumber].type = DOUBLE_T; + } else + if(strcmp(size,"32")==0) + { + patch[patchnumber].type = WORD_T; + } else + if(strcmp(size,"16")==0) + { + patch[patchnumber].type = SHORT_T; + } else + if(strcmp(size,"8")==0) + { + patch[patchnumber].type = BYTE_T; + } else + { + SysPrintf("XML Patch Loader: ERROR: Invalid size attribute.\n"); + patchnumber=0; + return -1; + } + + sscanf( address, "%X", &patch[ patchnumber ].addr ); + sscanf( value, "%I64X", &patch[ patchnumber ].data ); + + patch[patchnumber].enabled=penabled?1:0; + + string pt; + + if(ptitle) + pt.assign(ptitle); + else + pt.clear(); + + Patch p=Patch(patchnumber,gIndex,penabled,pt); + patches.push_back(p); + + patchnumber++; + + cpatch = cpatch->NextSibling("PATCH"); + } + + cpatch = group->FirstChild("GROUP"); + while(cpatch) { + int result=LoadGroup(cpatch,gIndex); + if(result) return result; + cpatch = cpatch->NextSibling("GROUP"); + } + + return 0; +} diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/blocksort.c b/plugins/CDVDiso/src/3rdparty/bzip2/blocksort.c index aceb5e9508..8535c93c8d 100644 --- a/plugins/CDVDiso/src/3rdparty/bzip2/blocksort.c +++ b/plugins/CDVDiso/src/3rdparty/bzip2/blocksort.c @@ -1,1094 +1,1094 @@ - -/*-------------------------------------------------------------*/ -/*--- Block sorting machinery ---*/ -/*--- blocksort.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.4 of 20 December 2006 - Copyright (C) 1996-2006 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - -/*---------------------------------------------*/ -/*--- Fallback O(N log(N)^2) sorting ---*/ -/*--- algorithm, for repetitive blocks ---*/ -/*---------------------------------------------*/ - -/*---------------------------------------------*/ -static -__inline__ -void fallbackSimpleSort ( UInt32* fmap, - UInt32* eclass, - Int32 lo, - Int32 hi ) -{ - Int32 i, j, tmp; - UInt32 ec_tmp; - - if (lo == hi) return; - - if (hi - lo > 3) { - for ( i = hi-4; i >= lo; i-- ) { - tmp = fmap[i]; - ec_tmp = eclass[tmp]; - for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 ) - fmap[j-4] = fmap[j]; - fmap[j-4] = tmp; - } - } - - for ( i = hi-1; i >= lo; i-- ) { - tmp = fmap[i]; - ec_tmp = eclass[tmp]; - for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ ) - fmap[j-1] = fmap[j]; - fmap[j-1] = tmp; - } -} - - -/*---------------------------------------------*/ -#define fswap(zz1, zz2) \ - { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } - -#define fvswap(zzp1, zzp2, zzn) \ -{ \ - Int32 yyp1 = (zzp1); \ - Int32 yyp2 = (zzp2); \ - Int32 yyn = (zzn); \ - while (yyn > 0) { \ - fswap(fmap[yyp1], fmap[yyp2]); \ - yyp1++; yyp2++; yyn--; \ - } \ -} - - -#define fmin(a,b) ((a) < (b)) ? (a) : (b) - -#define fpush(lz,hz) { stackLo[sp] = lz; \ - stackHi[sp] = hz; \ - sp++; } - -#define fpop(lz,hz) { sp--; \ - lz = stackLo[sp]; \ - hz = stackHi[sp]; } - -#define FALLBACK_QSORT_SMALL_THRESH 10 -#define FALLBACK_QSORT_STACK_SIZE 100 - - -static -void fallbackQSort3 ( UInt32* fmap, - UInt32* eclass, - Int32 loSt, - Int32 hiSt ) -{ - Int32 unLo, unHi, ltLo, gtHi, n, m; - Int32 sp, lo, hi; - UInt32 med, r, r3; - Int32 stackLo[FALLBACK_QSORT_STACK_SIZE]; - Int32 stackHi[FALLBACK_QSORT_STACK_SIZE]; - - r = 0; - - sp = 0; - fpush ( loSt, hiSt ); - - while (sp > 0) { - - AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 ); - - fpop ( lo, hi ); - if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { - fallbackSimpleSort ( fmap, eclass, lo, hi ); - continue; - } - - /* Random partitioning. Median of 3 sometimes fails to - avoid bad cases. Median of 9 seems to help but - looks rather expensive. This too seems to work but - is cheaper. Guidance for the magic constants - 7621 and 32768 is taken from Sedgewick's algorithms - book, chapter 35. - */ - r = ((r * 7621) + 1) % 32768; - r3 = r % 3; - if (r3 == 0) med = eclass[fmap[lo]]; else - if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else - med = eclass[fmap[hi]]; - - unLo = ltLo = lo; - unHi = gtHi = hi; - - while (1) { - while (1) { - if (unLo > unHi) break; - n = (Int32)eclass[fmap[unLo]] - (Int32)med; - if (n == 0) { - fswap(fmap[unLo], fmap[ltLo]); - ltLo++; unLo++; - continue; - }; - if (n > 0) break; - unLo++; - } - while (1) { - if (unLo > unHi) break; - n = (Int32)eclass[fmap[unHi]] - (Int32)med; - if (n == 0) { - fswap(fmap[unHi], fmap[gtHi]); - gtHi--; unHi--; - continue; - }; - if (n < 0) break; - unHi--; - } - if (unLo > unHi) break; - fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; - } - - AssertD ( unHi == unLo-1, "fallbackQSort3(2)" ); - - if (gtHi < ltLo) continue; - - n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n); - m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m); - - n = lo + unLo - ltLo - 1; - m = hi - (gtHi - unHi) + 1; - - if (n - lo > hi - m) { - fpush ( lo, n ); - fpush ( m, hi ); - } else { - fpush ( m, hi ); - fpush ( lo, n ); - } - } -} - -#undef fmin -#undef fpush -#undef fpop -#undef fswap -#undef fvswap -#undef FALLBACK_QSORT_SMALL_THRESH -#undef FALLBACK_QSORT_STACK_SIZE - - -/*---------------------------------------------*/ -/* Pre: - nblock > 0 - eclass exists for [0 .. nblock-1] - ((UChar*)eclass) [0 .. nblock-1] holds block - ptr exists for [0 .. nblock-1] - - Post: - ((UChar*)eclass) [0 .. nblock-1] holds block - All other areas of eclass destroyed - fmap [0 .. nblock-1] holds sorted order - bhtab [ 0 .. 2+(nblock/32) ] destroyed -*/ - -#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) -#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) -#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) -#define WORD_BH(zz) bhtab[(zz) >> 5] -#define UNALIGNED_BH(zz) ((zz) & 0x01f) - -static -void fallbackSort ( UInt32* fmap, - UInt32* eclass, - UInt32* bhtab, - Int32 nblock, - Int32 verb ) -{ - Int32 ftab[257]; - Int32 ftabCopy[256]; - Int32 H, i, j, k, l, r, cc, cc1; - Int32 nNotDone; - Int32 nBhtab; - UChar* eclass8 = (UChar*)eclass; - - /*-- - Initial 1-char radix sort to generate - initial fmap and initial BH bits. - --*/ - if (verb >= 4) - VPrintf0 ( " bucket sorting ...\n" ); - for (i = 0; i < 257; i++) ftab[i] = 0; - for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; - for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; - for (i = 1; i < 257; i++) ftab[i] += ftab[i-1]; - - for (i = 0; i < nblock; i++) { - j = eclass8[i]; - k = ftab[j] - 1; - ftab[j] = k; - fmap[k] = i; - } - - nBhtab = 2 + (nblock / 32); - for (i = 0; i < nBhtab; i++) bhtab[i] = 0; - for (i = 0; i < 256; i++) SET_BH(ftab[i]); - - /*-- - Inductively refine the buckets. Kind-of an - "exponential radix sort" (!), inspired by the - Manber-Myers suffix array construction algorithm. - --*/ - - /*-- set sentinel bits for block-end detection --*/ - for (i = 0; i < 32; i++) { - SET_BH(nblock + 2*i); - CLEAR_BH(nblock + 2*i + 1); - } - - /*-- the log(N) loop --*/ - H = 1; - while (1) { - - if (verb >= 4) - VPrintf1 ( " depth %6d has ", H ); - - j = 0; - for (i = 0; i < nblock; i++) { - if (ISSET_BH(i)) j = i; - k = fmap[i] - H; if (k < 0) k += nblock; - eclass[k] = j; - } - - nNotDone = 0; - r = -1; - while (1) { - - /*-- find the next non-singleton bucket --*/ - k = r + 1; - while (ISSET_BH(k) && UNALIGNED_BH(k)) k++; - if (ISSET_BH(k)) { - while (WORD_BH(k) == 0xffffffff) k += 32; - while (ISSET_BH(k)) k++; - } - l = k - 1; - if (l >= nblock) break; - while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++; - if (!ISSET_BH(k)) { - while (WORD_BH(k) == 0x00000000) k += 32; - while (!ISSET_BH(k)) k++; - } - r = k - 1; - if (r >= nblock) break; - - /*-- now [l, r] bracket current bucket --*/ - if (r > l) { - nNotDone += (r - l + 1); - fallbackQSort3 ( fmap, eclass, l, r ); - - /*-- scan bucket and generate header bits-- */ - cc = -1; - for (i = l; i <= r; i++) { - cc1 = eclass[fmap[i]]; - if (cc != cc1) { SET_BH(i); cc = cc1; }; - } - } - } - - if (verb >= 4) - VPrintf1 ( "%6d unresolved strings\n", nNotDone ); - - H *= 2; - if (H > nblock || nNotDone == 0) break; - } - - /*-- - Reconstruct the original block in - eclass8 [0 .. nblock-1], since the - previous phase destroyed it. - --*/ - if (verb >= 4) - VPrintf0 ( " reconstructing block ...\n" ); - j = 0; - for (i = 0; i < nblock; i++) { - while (ftabCopy[j] == 0) j++; - ftabCopy[j]--; - eclass8[fmap[i]] = (UChar)j; - } - AssertH ( j < 256, 1005 ); -} - -#undef SET_BH -#undef CLEAR_BH -#undef ISSET_BH -#undef WORD_BH -#undef UNALIGNED_BH - - -/*---------------------------------------------*/ -/*--- The main, O(N^2 log(N)) sorting ---*/ -/*--- algorithm. Faster for "normal" ---*/ -/*--- non-repetitive blocks. ---*/ -/*---------------------------------------------*/ - -/*---------------------------------------------*/ -static -__inline__ -Bool mainGtU ( UInt32 i1, - UInt32 i2, - UChar* block, - UInt16* quadrant, - UInt32 nblock, - Int32* budget ) -{ - Int32 k; - UChar c1, c2; - UInt16 s1, s2; - - AssertD ( i1 != i2, "mainGtU" ); - /* 1 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 2 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 3 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 4 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 5 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 6 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 7 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 8 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 9 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 10 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 11 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 12 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - - k = nblock + 8; - - do { - /* 1 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 2 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 3 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 4 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 5 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 6 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 7 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 8 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - - if (i1 >= nblock) i1 -= nblock; - if (i2 >= nblock) i2 -= nblock; - - k -= 8; - (*budget)--; - } - while (k >= 0); - - return False; -} - - -/*---------------------------------------------*/ -/*-- - Knuth's increments seem to work better - than Incerpi-Sedgewick here. Possibly - because the number of elems to sort is - usually small, typically <= 20. ---*/ -static -Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, - 9841, 29524, 88573, 265720, - 797161, 2391484 }; - -static -void mainSimpleSort ( UInt32* ptr, - UChar* block, - UInt16* quadrant, - Int32 nblock, - Int32 lo, - Int32 hi, - Int32 d, - Int32* budget ) -{ - Int32 i, j, h, bigN, hp; - UInt32 v; - - bigN = hi - lo + 1; - if (bigN < 2) return; - - hp = 0; - while (incs[hp] < bigN) hp++; - hp--; - - for (; hp >= 0; hp--) { - h = incs[hp]; - - i = lo + h; - while (True) { - - /*-- copy 1 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while ( mainGtU ( - ptr[j-h]+d, v+d, block, quadrant, nblock, budget - ) ) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - - /*-- copy 2 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while ( mainGtU ( - ptr[j-h]+d, v+d, block, quadrant, nblock, budget - ) ) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - - /*-- copy 3 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while ( mainGtU ( - ptr[j-h]+d, v+d, block, quadrant, nblock, budget - ) ) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - - if (*budget < 0) return; - } - } -} - - -/*---------------------------------------------*/ -/*-- - The following is an implementation of - an elegant 3-way quicksort for strings, - described in a paper "Fast Algorithms for - Sorting and Searching Strings", by Robert - Sedgewick and Jon L. Bentley. ---*/ - -#define mswap(zz1, zz2) \ - { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } - -#define mvswap(zzp1, zzp2, zzn) \ -{ \ - Int32 yyp1 = (zzp1); \ - Int32 yyp2 = (zzp2); \ - Int32 yyn = (zzn); \ - while (yyn > 0) { \ - mswap(ptr[yyp1], ptr[yyp2]); \ - yyp1++; yyp2++; yyn--; \ - } \ -} - -static -__inline__ -UChar mmed3 ( UChar a, UChar b, UChar c ) -{ - UChar t; - if (a > b) { t = a; a = b; b = t; }; - if (b > c) { - b = c; - if (a > b) b = a; - } - return b; -} - -#define mmin(a,b) ((a) < (b)) ? (a) : (b) - -#define mpush(lz,hz,dz) { stackLo[sp] = lz; \ - stackHi[sp] = hz; \ - stackD [sp] = dz; \ - sp++; } - -#define mpop(lz,hz,dz) { sp--; \ - lz = stackLo[sp]; \ - hz = stackHi[sp]; \ - dz = stackD [sp]; } - - -#define mnextsize(az) (nextHi[az]-nextLo[az]) - -#define mnextswap(az,bz) \ - { Int32 tz; \ - tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ - tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ - tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; } - - -#define MAIN_QSORT_SMALL_THRESH 20 -#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) -#define MAIN_QSORT_STACK_SIZE 100 - -static -void mainQSort3 ( UInt32* ptr, - UChar* block, - UInt16* quadrant, - Int32 nblock, - Int32 loSt, - Int32 hiSt, - Int32 dSt, - Int32* budget ) -{ - Int32 unLo, unHi, ltLo, gtHi, n, m, med; - Int32 sp, lo, hi, d; - - Int32 stackLo[MAIN_QSORT_STACK_SIZE]; - Int32 stackHi[MAIN_QSORT_STACK_SIZE]; - Int32 stackD [MAIN_QSORT_STACK_SIZE]; - - Int32 nextLo[3]; - Int32 nextHi[3]; - Int32 nextD [3]; - - sp = 0; - mpush ( loSt, hiSt, dSt ); - - while (sp > 0) { - - AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 ); - - mpop ( lo, hi, d ); - if (hi - lo < MAIN_QSORT_SMALL_THRESH || - d > MAIN_QSORT_DEPTH_THRESH) { - mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget ); - if (*budget < 0) return; - continue; - } - - med = (Int32) - mmed3 ( block[ptr[ lo ]+d], - block[ptr[ hi ]+d], - block[ptr[ (lo+hi)>>1 ]+d] ); - - unLo = ltLo = lo; - unHi = gtHi = hi; - - while (True) { - while (True) { - if (unLo > unHi) break; - n = ((Int32)block[ptr[unLo]+d]) - med; - if (n == 0) { - mswap(ptr[unLo], ptr[ltLo]); - ltLo++; unLo++; continue; - }; - if (n > 0) break; - unLo++; - } - while (True) { - if (unLo > unHi) break; - n = ((Int32)block[ptr[unHi]+d]) - med; - if (n == 0) { - mswap(ptr[unHi], ptr[gtHi]); - gtHi--; unHi--; continue; - }; - if (n < 0) break; - unHi--; - } - if (unLo > unHi) break; - mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--; - } - - AssertD ( unHi == unLo-1, "mainQSort3(2)" ); - - if (gtHi < ltLo) { - mpush(lo, hi, d+1 ); - continue; - } - - n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n); - m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m); - - n = lo + unLo - ltLo - 1; - m = hi - (gtHi - unHi) + 1; - - nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; - nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; - nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; - - if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); - if (mnextsize(1) < mnextsize(2)) mnextswap(1,2); - if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); - - AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" ); - AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" ); - - mpush (nextLo[0], nextHi[0], nextD[0]); - mpush (nextLo[1], nextHi[1], nextD[1]); - mpush (nextLo[2], nextHi[2], nextD[2]); - } -} - -#undef mswap -#undef mvswap -#undef mpush -#undef mpop -#undef mmin -#undef mnextsize -#undef mnextswap -#undef MAIN_QSORT_SMALL_THRESH -#undef MAIN_QSORT_DEPTH_THRESH -#undef MAIN_QSORT_STACK_SIZE - - -/*---------------------------------------------*/ -/* Pre: - nblock > N_OVERSHOOT - block32 exists for [0 .. nblock-1 +N_OVERSHOOT] - ((UChar*)block32) [0 .. nblock-1] holds block - ptr exists for [0 .. nblock-1] - - Post: - ((UChar*)block32) [0 .. nblock-1] holds block - All other areas of block32 destroyed - ftab [0 .. 65536 ] destroyed - ptr [0 .. nblock-1] holds sorted order - if (*budget < 0), sorting was abandoned -*/ - -#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) -#define SETMASK (1 << 21) -#define CLEARMASK (~(SETMASK)) - -static -void mainSort ( UInt32* ptr, - UChar* block, - UInt16* quadrant, - UInt32* ftab, - Int32 nblock, - Int32 verb, - Int32* budget ) -{ - Int32 i, j, k, ss, sb; - Int32 runningOrder[256]; - Bool bigDone[256]; - Int32 copyStart[256]; - Int32 copyEnd [256]; - UChar c1; - Int32 numQSorted; - UInt16 s; - if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" ); - - /*-- set up the 2-byte frequency table --*/ - for (i = 65536; i >= 0; i--) ftab[i] = 0; - - j = block[0] << 8; - i = nblock-1; - for (; i >= 3; i -= 4) { - quadrant[i] = 0; - j = (j >> 8) | ( ((UInt16)block[i]) << 8); - ftab[j]++; - quadrant[i-1] = 0; - j = (j >> 8) | ( ((UInt16)block[i-1]) << 8); - ftab[j]++; - quadrant[i-2] = 0; - j = (j >> 8) | ( ((UInt16)block[i-2]) << 8); - ftab[j]++; - quadrant[i-3] = 0; - j = (j >> 8) | ( ((UInt16)block[i-3]) << 8); - ftab[j]++; - } - for (; i >= 0; i--) { - quadrant[i] = 0; - j = (j >> 8) | ( ((UInt16)block[i]) << 8); - ftab[j]++; - } - - /*-- (emphasises close relationship of block & quadrant) --*/ - for (i = 0; i < BZ_N_OVERSHOOT; i++) { - block [nblock+i] = block[i]; - quadrant[nblock+i] = 0; - } - - if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" ); - - /*-- Complete the initial radix sort --*/ - for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1]; - - s = block[0] << 8; - i = nblock-1; - for (; i >= 3; i -= 4) { - s = (s >> 8) | (block[i] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i; - s = (s >> 8) | (block[i-1] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i-1; - s = (s >> 8) | (block[i-2] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i-2; - s = (s >> 8) | (block[i-3] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i-3; - } - for (; i >= 0; i--) { - s = (s >> 8) | (block[i] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i; - } - - /*-- - Now ftab contains the first loc of every small bucket. - Calculate the running order, from smallest to largest - big bucket. - --*/ - for (i = 0; i <= 255; i++) { - bigDone [i] = False; - runningOrder[i] = i; - } - - { - Int32 vv; - Int32 h = 1; - do h = 3 * h + 1; while (h <= 256); - do { - h = h / 3; - for (i = h; i <= 255; i++) { - vv = runningOrder[i]; - j = i; - while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) { - runningOrder[j] = runningOrder[j-h]; - j = j - h; - if (j <= (h - 1)) goto zero; - } - zero: - runningOrder[j] = vv; - } - } while (h != 1); - } - - /*-- - The main sorting loop. - --*/ - - numQSorted = 0; - - for (i = 0; i <= 255; i++) { - - /*-- - Process big buckets, starting with the least full. - Basically this is a 3-step process in which we call - mainQSort3 to sort the small buckets [ss, j], but - also make a big effort to avoid the calls if we can. - --*/ - ss = runningOrder[i]; - - /*-- - Step 1: - Complete the big bucket [ss] by quicksorting - any unsorted small buckets [ss, j], for j != ss. - Hopefully previous pointer-scanning phases have already - completed many of the small buckets [ss, j], so - we don't have to sort them at all. - --*/ - for (j = 0; j <= 255; j++) { - if (j != ss) { - sb = (ss << 8) + j; - if ( ! (ftab[sb] & SETMASK) ) { - Int32 lo = ftab[sb] & CLEARMASK; - Int32 hi = (ftab[sb+1] & CLEARMASK) - 1; - if (hi > lo) { - if (verb >= 4) - VPrintf4 ( " qsort [0x%x, 0x%x] " - "done %d this %d\n", - ss, j, numQSorted, hi - lo + 1 ); - mainQSort3 ( - ptr, block, quadrant, nblock, - lo, hi, BZ_N_RADIX, budget - ); - numQSorted += (hi - lo + 1); - if (*budget < 0) return; - } - } - ftab[sb] |= SETMASK; - } - } - - AssertH ( !bigDone[ss], 1006 ); - - /*-- - Step 2: - Now scan this big bucket [ss] so as to synthesise the - sorted order for small buckets [t, ss] for all t, - including, magically, the bucket [ss,ss] too. - This will avoid doing Real Work in subsequent Step 1's. - --*/ - { - for (j = 0; j <= 255; j++) { - copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; - copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; - } - for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { - k = ptr[j]-1; if (k < 0) k += nblock; - c1 = block[k]; - if (!bigDone[c1]) - ptr[ copyStart[c1]++ ] = k; - } - for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { - k = ptr[j]-1; if (k < 0) k += nblock; - c1 = block[k]; - if (!bigDone[c1]) - ptr[ copyEnd[c1]-- ] = k; - } - } - - AssertH ( (copyStart[ss]-1 == copyEnd[ss]) - || - /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. - Necessity for this case is demonstrated by compressing - a sequence of approximately 48.5 million of character - 251; 1.0.0/1.0.1 will then die here. */ - (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), - 1007 ) - - for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK; - - /*-- - Step 3: - The [ss] big bucket is now done. Record this fact, - and update the quadrant descriptors. Remember to - update quadrants in the overshoot area too, if - necessary. The "if (i < 255)" test merely skips - this updating for the last bucket processed, since - updating for the last bucket is pointless. - - The quadrant array provides a way to incrementally - cache sort orderings, as they appear, so as to - make subsequent comparisons in fullGtU() complete - faster. For repetitive blocks this makes a big - difference (but not big enough to be able to avoid - the fallback sorting mechanism, exponential radix sort). - - The precise meaning is: at all times: - - for 0 <= i < nblock and 0 <= j <= nblock - - if block[i] != block[j], - - then the relative values of quadrant[i] and - quadrant[j] are meaningless. - - else { - if quadrant[i] < quadrant[j] - then the string starting at i lexicographically - precedes the string starting at j - - else if quadrant[i] > quadrant[j] - then the string starting at j lexicographically - precedes the string starting at i - - else - the relative ordering of the strings starting - at i and j has not yet been determined. - } - --*/ - bigDone[ss] = True; - - if (i < 255) { - Int32 bbStart = ftab[ss << 8] & CLEARMASK; - Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; - Int32 shifts = 0; - - while ((bbSize >> shifts) > 65534) shifts++; - - for (j = bbSize-1; j >= 0; j--) { - Int32 a2update = ptr[bbStart + j]; - UInt16 qVal = (UInt16)(j >> shifts); - quadrant[a2update] = qVal; - if (a2update < BZ_N_OVERSHOOT) - quadrant[a2update + nblock] = qVal; - } - AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 ); - } - - } - - if (verb >= 4) - VPrintf3 ( " %d pointers, %d sorted, %d scanned\n", - nblock, numQSorted, nblock - numQSorted ); -} - -#undef BIGFREQ -#undef SETMASK -#undef CLEARMASK - - -/*---------------------------------------------*/ -/* Pre: - nblock > 0 - arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] - ((UChar*)arr2) [0 .. nblock-1] holds block - arr1 exists for [0 .. nblock-1] - - Post: - ((UChar*)arr2) [0 .. nblock-1] holds block - All other areas of block destroyed - ftab [ 0 .. 65536 ] destroyed - arr1 [0 .. nblock-1] holds sorted order -*/ -void BZ2_blockSort ( EState* s ) -{ - UInt32* ptr = s->ptr; - UChar* block = s->block; - UInt32* ftab = s->ftab; - Int32 nblock = s->nblock; - Int32 verb = s->verbosity; - Int32 wfact = s->workFactor; - UInt16* quadrant; - Int32 budget; - Int32 budgetInit; - Int32 i; - - if (nblock < 10000) { - fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); - } else { - /* Calculate the location for quadrant, remembering to get - the alignment right. Assumes that &(block[0]) is at least - 2-byte aligned -- this should be ok since block is really - the first section of arr2. - */ - i = nblock+BZ_N_OVERSHOOT; - if (i & 1) i++; - quadrant = (UInt16*)(&(block[i])); - - /* (wfact-1) / 3 puts the default-factor-30 - transition point at very roughly the same place as - with v0.1 and v0.9.0. - Not that it particularly matters any more, since the - resulting compressed stream is now the same regardless - of whether or not we use the main sort or fallback sort. - */ - if (wfact < 1 ) wfact = 1; - if (wfact > 100) wfact = 100; - budgetInit = nblock * ((wfact-1) / 3); - budget = budgetInit; - - mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget ); - if (verb >= 3) - VPrintf3 ( " %d work, %d block, ratio %5.2f\n", - budgetInit - budget, - nblock, - (float)(budgetInit - budget) / - (float)(nblock==0 ? 1 : nblock) ); - if (budget < 0) { - if (verb >= 2) - VPrintf0 ( " too repetitive; using fallback" - " sorting algorithm\n" ); - fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); - } - } - - s->origPtr = -1; - for (i = 0; i < s->nblock; i++) - if (ptr[i] == 0) - { s->origPtr = i; break; }; - - AssertH( s->origPtr != -1, 1003 ); -} - - -/*-------------------------------------------------------------*/ -/*--- end blocksort.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Block sorting machinery ---*/ +/*--- blocksort.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*---------------------------------------------*/ +/*--- Fallback O(N log(N)^2) sorting ---*/ +/*--- algorithm, for repetitive blocks ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +void fallbackSimpleSort ( UInt32* fmap, + UInt32* eclass, + Int32 lo, + Int32 hi ) +{ + Int32 i, j, tmp; + UInt32 ec_tmp; + + if (lo == hi) return; + + if (hi - lo > 3) { + for ( i = hi-4; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 ) + fmap[j-4] = fmap[j]; + fmap[j-4] = tmp; + } + } + + for ( i = hi-1; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ ) + fmap[j-1] = fmap[j]; + fmap[j-1] = tmp; + } +} + + +/*---------------------------------------------*/ +#define fswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define fvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + fswap(fmap[yyp1], fmap[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + + +#define fmin(a,b) ((a) < (b)) ? (a) : (b) + +#define fpush(lz,hz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + sp++; } + +#define fpop(lz,hz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; } + +#define FALLBACK_QSORT_SMALL_THRESH 10 +#define FALLBACK_QSORT_STACK_SIZE 100 + + +static +void fallbackQSort3 ( UInt32* fmap, + UInt32* eclass, + Int32 loSt, + Int32 hiSt ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m; + Int32 sp, lo, hi; + UInt32 med, r, r3; + Int32 stackLo[FALLBACK_QSORT_STACK_SIZE]; + Int32 stackHi[FALLBACK_QSORT_STACK_SIZE]; + + r = 0; + + sp = 0; + fpush ( loSt, hiSt ); + + while (sp > 0) { + + AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 ); + + fpop ( lo, hi ); + if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { + fallbackSimpleSort ( fmap, eclass, lo, hi ); + continue; + } + + /* Random partitioning. Median of 3 sometimes fails to + avoid bad cases. Median of 9 seems to help but + looks rather expensive. This too seems to work but + is cheaper. Guidance for the magic constants + 7621 and 32768 is taken from Sedgewick's algorithms + book, chapter 35. + */ + r = ((r * 7621) + 1) % 32768; + r3 = r % 3; + if (r3 == 0) med = eclass[fmap[lo]]; else + if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else + med = eclass[fmap[hi]]; + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (1) { + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unLo]] - (Int32)med; + if (n == 0) { + fswap(fmap[unLo], fmap[ltLo]); + ltLo++; unLo++; + continue; + }; + if (n > 0) break; + unLo++; + } + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unHi]] - (Int32)med; + if (n == 0) { + fswap(fmap[unHi], fmap[gtHi]); + gtHi--; unHi--; + continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "fallbackQSort3(2)" ); + + if (gtHi < ltLo) continue; + + n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n); + m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + if (n - lo > hi - m) { + fpush ( lo, n ); + fpush ( m, hi ); + } else { + fpush ( m, hi ); + fpush ( lo, n ); + } + } +} + +#undef fmin +#undef fpush +#undef fpop +#undef fswap +#undef fvswap +#undef FALLBACK_QSORT_SMALL_THRESH +#undef FALLBACK_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + eclass exists for [0 .. nblock-1] + ((UChar*)eclass) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)eclass) [0 .. nblock-1] holds block + All other areas of eclass destroyed + fmap [0 .. nblock-1] holds sorted order + bhtab [ 0 .. 2+(nblock/32) ] destroyed +*/ + +#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) +#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) +#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) +#define WORD_BH(zz) bhtab[(zz) >> 5] +#define UNALIGNED_BH(zz) ((zz) & 0x01f) + +static +void fallbackSort ( UInt32* fmap, + UInt32* eclass, + UInt32* bhtab, + Int32 nblock, + Int32 verb ) +{ + Int32 ftab[257]; + Int32 ftabCopy[256]; + Int32 H, i, j, k, l, r, cc, cc1; + Int32 nNotDone; + Int32 nBhtab; + UChar* eclass8 = (UChar*)eclass; + + /*-- + Initial 1-char radix sort to generate + initial fmap and initial BH bits. + --*/ + if (verb >= 4) + VPrintf0 ( " bucket sorting ...\n" ); + for (i = 0; i < 257; i++) ftab[i] = 0; + for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; + for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; + for (i = 1; i < 257; i++) ftab[i] += ftab[i-1]; + + for (i = 0; i < nblock; i++) { + j = eclass8[i]; + k = ftab[j] - 1; + ftab[j] = k; + fmap[k] = i; + } + + nBhtab = 2 + (nblock / 32); + for (i = 0; i < nBhtab; i++) bhtab[i] = 0; + for (i = 0; i < 256; i++) SET_BH(ftab[i]); + + /*-- + Inductively refine the buckets. Kind-of an + "exponential radix sort" (!), inspired by the + Manber-Myers suffix array construction algorithm. + --*/ + + /*-- set sentinel bits for block-end detection --*/ + for (i = 0; i < 32; i++) { + SET_BH(nblock + 2*i); + CLEAR_BH(nblock + 2*i + 1); + } + + /*-- the log(N) loop --*/ + H = 1; + while (1) { + + if (verb >= 4) + VPrintf1 ( " depth %6d has ", H ); + + j = 0; + for (i = 0; i < nblock; i++) { + if (ISSET_BH(i)) j = i; + k = fmap[i] - H; if (k < 0) k += nblock; + eclass[k] = j; + } + + nNotDone = 0; + r = -1; + while (1) { + + /*-- find the next non-singleton bucket --*/ + k = r + 1; + while (ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (ISSET_BH(k)) { + while (WORD_BH(k) == 0xffffffff) k += 32; + while (ISSET_BH(k)) k++; + } + l = k - 1; + if (l >= nblock) break; + while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (!ISSET_BH(k)) { + while (WORD_BH(k) == 0x00000000) k += 32; + while (!ISSET_BH(k)) k++; + } + r = k - 1; + if (r >= nblock) break; + + /*-- now [l, r] bracket current bucket --*/ + if (r > l) { + nNotDone += (r - l + 1); + fallbackQSort3 ( fmap, eclass, l, r ); + + /*-- scan bucket and generate header bits-- */ + cc = -1; + for (i = l; i <= r; i++) { + cc1 = eclass[fmap[i]]; + if (cc != cc1) { SET_BH(i); cc = cc1; }; + } + } + } + + if (verb >= 4) + VPrintf1 ( "%6d unresolved strings\n", nNotDone ); + + H *= 2; + if (H > nblock || nNotDone == 0) break; + } + + /*-- + Reconstruct the original block in + eclass8 [0 .. nblock-1], since the + previous phase destroyed it. + --*/ + if (verb >= 4) + VPrintf0 ( " reconstructing block ...\n" ); + j = 0; + for (i = 0; i < nblock; i++) { + while (ftabCopy[j] == 0) j++; + ftabCopy[j]--; + eclass8[fmap[i]] = (UChar)j; + } + AssertH ( j < 256, 1005 ); +} + +#undef SET_BH +#undef CLEAR_BH +#undef ISSET_BH +#undef WORD_BH +#undef UNALIGNED_BH + + +/*---------------------------------------------*/ +/*--- The main, O(N^2 log(N)) sorting ---*/ +/*--- algorithm. Faster for "normal" ---*/ +/*--- non-repetitive blocks. ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +Bool mainGtU ( UInt32 i1, + UInt32 i2, + UChar* block, + UInt16* quadrant, + UInt32 nblock, + Int32* budget ) +{ + Int32 k; + UChar c1, c2; + UInt16 s1, s2; + + AssertD ( i1 != i2, "mainGtU" ); + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 9 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 10 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 11 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 12 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + + k = nblock + 8; + + do { + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + + if (i1 >= nblock) i1 -= nblock; + if (i2 >= nblock) i2 -= nblock; + + k -= 8; + (*budget)--; + } + while (k >= 0); + + return False; +} + + +/*---------------------------------------------*/ +/*-- + Knuth's increments seem to work better + than Incerpi-Sedgewick here. Possibly + because the number of elems to sort is + usually small, typically <= 20. +--*/ +static +Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, + 9841, 29524, 88573, 265720, + 797161, 2391484 }; + +static +void mainSimpleSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 lo, + Int32 hi, + Int32 d, + Int32* budget ) +{ + Int32 i, j, h, bigN, hp; + UInt32 v; + + bigN = hi - lo + 1; + if (bigN < 2) return; + + hp = 0; + while (incs[hp] < bigN) hp++; + hp--; + + for (; hp >= 0; hp--) { + h = incs[hp]; + + i = lo + h; + while (True) { + + /*-- copy 1 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 2 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 3 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + if (*budget < 0) return; + } + } +} + + +/*---------------------------------------------*/ +/*-- + The following is an implementation of + an elegant 3-way quicksort for strings, + described in a paper "Fast Algorithms for + Sorting and Searching Strings", by Robert + Sedgewick and Jon L. Bentley. +--*/ + +#define mswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define mvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + mswap(ptr[yyp1], ptr[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + +static +__inline__ +UChar mmed3 ( UChar a, UChar b, UChar c ) +{ + UChar t; + if (a > b) { t = a; a = b; b = t; }; + if (b > c) { + b = c; + if (a > b) b = a; + } + return b; +} + +#define mmin(a,b) ((a) < (b)) ? (a) : (b) + +#define mpush(lz,hz,dz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + stackD [sp] = dz; \ + sp++; } + +#define mpop(lz,hz,dz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; \ + dz = stackD [sp]; } + + +#define mnextsize(az) (nextHi[az]-nextLo[az]) + +#define mnextswap(az,bz) \ + { Int32 tz; \ + tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ + tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ + tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; } + + +#define MAIN_QSORT_SMALL_THRESH 20 +#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) +#define MAIN_QSORT_STACK_SIZE 100 + +static +void mainQSort3 ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 loSt, + Int32 hiSt, + Int32 dSt, + Int32* budget ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m, med; + Int32 sp, lo, hi, d; + + Int32 stackLo[MAIN_QSORT_STACK_SIZE]; + Int32 stackHi[MAIN_QSORT_STACK_SIZE]; + Int32 stackD [MAIN_QSORT_STACK_SIZE]; + + Int32 nextLo[3]; + Int32 nextHi[3]; + Int32 nextD [3]; + + sp = 0; + mpush ( loSt, hiSt, dSt ); + + while (sp > 0) { + + AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 ); + + mpop ( lo, hi, d ); + if (hi - lo < MAIN_QSORT_SMALL_THRESH || + d > MAIN_QSORT_DEPTH_THRESH) { + mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget ); + if (*budget < 0) return; + continue; + } + + med = (Int32) + mmed3 ( block[ptr[ lo ]+d], + block[ptr[ hi ]+d], + block[ptr[ (lo+hi)>>1 ]+d] ); + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (True) { + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unLo]+d]) - med; + if (n == 0) { + mswap(ptr[unLo], ptr[ltLo]); + ltLo++; unLo++; continue; + }; + if (n > 0) break; + unLo++; + } + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unHi]+d]) - med; + if (n == 0) { + mswap(ptr[unHi], ptr[gtHi]); + gtHi--; unHi--; continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "mainQSort3(2)" ); + + if (gtHi < ltLo) { + mpush(lo, hi, d+1 ); + continue; + } + + n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n); + m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; + nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; + nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; + + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + if (mnextsize(1) < mnextsize(2)) mnextswap(1,2); + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + + AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" ); + AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" ); + + mpush (nextLo[0], nextHi[0], nextD[0]); + mpush (nextLo[1], nextHi[1], nextD[1]); + mpush (nextLo[2], nextHi[2], nextD[2]); + } +} + +#undef mswap +#undef mvswap +#undef mpush +#undef mpop +#undef mmin +#undef mnextsize +#undef mnextswap +#undef MAIN_QSORT_SMALL_THRESH +#undef MAIN_QSORT_DEPTH_THRESH +#undef MAIN_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > N_OVERSHOOT + block32 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)block32) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)block32) [0 .. nblock-1] holds block + All other areas of block32 destroyed + ftab [0 .. 65536 ] destroyed + ptr [0 .. nblock-1] holds sorted order + if (*budget < 0), sorting was abandoned +*/ + +#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) +#define SETMASK (1 << 21) +#define CLEARMASK (~(SETMASK)) + +static +void mainSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + UInt32* ftab, + Int32 nblock, + Int32 verb, + Int32* budget ) +{ + Int32 i, j, k, ss, sb; + Int32 runningOrder[256]; + Bool bigDone[256]; + Int32 copyStart[256]; + Int32 copyEnd [256]; + UChar c1; + Int32 numQSorted; + UInt16 s; + if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" ); + + /*-- set up the 2-byte frequency table --*/ + for (i = 65536; i >= 0; i--) ftab[i] = 0; + + j = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + quadrant[i-1] = 0; + j = (j >> 8) | ( ((UInt16)block[i-1]) << 8); + ftab[j]++; + quadrant[i-2] = 0; + j = (j >> 8) | ( ((UInt16)block[i-2]) << 8); + ftab[j]++; + quadrant[i-3] = 0; + j = (j >> 8) | ( ((UInt16)block[i-3]) << 8); + ftab[j]++; + } + for (; i >= 0; i--) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + } + + /*-- (emphasises close relationship of block & quadrant) --*/ + for (i = 0; i < BZ_N_OVERSHOOT; i++) { + block [nblock+i] = block[i]; + quadrant[nblock+i] = 0; + } + + if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" ); + + /*-- Complete the initial radix sort --*/ + for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1]; + + s = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + s = (s >> 8) | (block[i-1] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-1; + s = (s >> 8) | (block[i-2] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-2; + s = (s >> 8) | (block[i-3] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-3; + } + for (; i >= 0; i--) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + } + + /*-- + Now ftab contains the first loc of every small bucket. + Calculate the running order, from smallest to largest + big bucket. + --*/ + for (i = 0; i <= 255; i++) { + bigDone [i] = False; + runningOrder[i] = i; + } + + { + Int32 vv; + Int32 h = 1; + do h = 3 * h + 1; while (h <= 256); + do { + h = h / 3; + for (i = h; i <= 255; i++) { + vv = runningOrder[i]; + j = i; + while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) { + runningOrder[j] = runningOrder[j-h]; + j = j - h; + if (j <= (h - 1)) goto zero; + } + zero: + runningOrder[j] = vv; + } + } while (h != 1); + } + + /*-- + The main sorting loop. + --*/ + + numQSorted = 0; + + for (i = 0; i <= 255; i++) { + + /*-- + Process big buckets, starting with the least full. + Basically this is a 3-step process in which we call + mainQSort3 to sort the small buckets [ss, j], but + also make a big effort to avoid the calls if we can. + --*/ + ss = runningOrder[i]; + + /*-- + Step 1: + Complete the big bucket [ss] by quicksorting + any unsorted small buckets [ss, j], for j != ss. + Hopefully previous pointer-scanning phases have already + completed many of the small buckets [ss, j], so + we don't have to sort them at all. + --*/ + for (j = 0; j <= 255; j++) { + if (j != ss) { + sb = (ss << 8) + j; + if ( ! (ftab[sb] & SETMASK) ) { + Int32 lo = ftab[sb] & CLEARMASK; + Int32 hi = (ftab[sb+1] & CLEARMASK) - 1; + if (hi > lo) { + if (verb >= 4) + VPrintf4 ( " qsort [0x%x, 0x%x] " + "done %d this %d\n", + ss, j, numQSorted, hi - lo + 1 ); + mainQSort3 ( + ptr, block, quadrant, nblock, + lo, hi, BZ_N_RADIX, budget + ); + numQSorted += (hi - lo + 1); + if (*budget < 0) return; + } + } + ftab[sb] |= SETMASK; + } + } + + AssertH ( !bigDone[ss], 1006 ); + + /*-- + Step 2: + Now scan this big bucket [ss] so as to synthesise the + sorted order for small buckets [t, ss] for all t, + including, magically, the bucket [ss,ss] too. + This will avoid doing Real Work in subsequent Step 1's. + --*/ + { + for (j = 0; j <= 255; j++) { + copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; + copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; + } + for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyStart[c1]++ ] = k; + } + for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyEnd[c1]-- ] = k; + } + } + + AssertH ( (copyStart[ss]-1 == copyEnd[ss]) + || + /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. + Necessity for this case is demonstrated by compressing + a sequence of approximately 48.5 million of character + 251; 1.0.0/1.0.1 will then die here. */ + (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), + 1007 ) + + for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK; + + /*-- + Step 3: + The [ss] big bucket is now done. Record this fact, + and update the quadrant descriptors. Remember to + update quadrants in the overshoot area too, if + necessary. The "if (i < 255)" test merely skips + this updating for the last bucket processed, since + updating for the last bucket is pointless. + + The quadrant array provides a way to incrementally + cache sort orderings, as they appear, so as to + make subsequent comparisons in fullGtU() complete + faster. For repetitive blocks this makes a big + difference (but not big enough to be able to avoid + the fallback sorting mechanism, exponential radix sort). + + The precise meaning is: at all times: + + for 0 <= i < nblock and 0 <= j <= nblock + + if block[i] != block[j], + + then the relative values of quadrant[i] and + quadrant[j] are meaningless. + + else { + if quadrant[i] < quadrant[j] + then the string starting at i lexicographically + precedes the string starting at j + + else if quadrant[i] > quadrant[j] + then the string starting at j lexicographically + precedes the string starting at i + + else + the relative ordering of the strings starting + at i and j has not yet been determined. + } + --*/ + bigDone[ss] = True; + + if (i < 255) { + Int32 bbStart = ftab[ss << 8] & CLEARMASK; + Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; + Int32 shifts = 0; + + while ((bbSize >> shifts) > 65534) shifts++; + + for (j = bbSize-1; j >= 0; j--) { + Int32 a2update = ptr[bbStart + j]; + UInt16 qVal = (UInt16)(j >> shifts); + quadrant[a2update] = qVal; + if (a2update < BZ_N_OVERSHOOT) + quadrant[a2update + nblock] = qVal; + } + AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 ); + } + + } + + if (verb >= 4) + VPrintf3 ( " %d pointers, %d sorted, %d scanned\n", + nblock, numQSorted, nblock - numQSorted ); +} + +#undef BIGFREQ +#undef SETMASK +#undef CLEARMASK + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)arr2) [0 .. nblock-1] holds block + arr1 exists for [0 .. nblock-1] + + Post: + ((UChar*)arr2) [0 .. nblock-1] holds block + All other areas of block destroyed + ftab [ 0 .. 65536 ] destroyed + arr1 [0 .. nblock-1] holds sorted order +*/ +void BZ2_blockSort ( EState* s ) +{ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt32* ftab = s->ftab; + Int32 nblock = s->nblock; + Int32 verb = s->verbosity; + Int32 wfact = s->workFactor; + UInt16* quadrant; + Int32 budget; + Int32 budgetInit; + Int32 i; + + if (nblock < 10000) { + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } else { + /* Calculate the location for quadrant, remembering to get + the alignment right. Assumes that &(block[0]) is at least + 2-byte aligned -- this should be ok since block is really + the first section of arr2. + */ + i = nblock+BZ_N_OVERSHOOT; + if (i & 1) i++; + quadrant = (UInt16*)(&(block[i])); + + /* (wfact-1) / 3 puts the default-factor-30 + transition point at very roughly the same place as + with v0.1 and v0.9.0. + Not that it particularly matters any more, since the + resulting compressed stream is now the same regardless + of whether or not we use the main sort or fallback sort. + */ + if (wfact < 1 ) wfact = 1; + if (wfact > 100) wfact = 100; + budgetInit = nblock * ((wfact-1) / 3); + budget = budgetInit; + + mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget ); + if (verb >= 3) + VPrintf3 ( " %d work, %d block, ratio %5.2f\n", + budgetInit - budget, + nblock, + (float)(budgetInit - budget) / + (float)(nblock==0 ? 1 : nblock) ); + if (budget < 0) { + if (verb >= 2) + VPrintf0 ( " too repetitive; using fallback" + " sorting algorithm\n" ); + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } + } + + s->origPtr = -1; + for (i = 0; i < s->nblock; i++) + if (ptr[i] == 0) + { s->origPtr = i; break; }; + + AssertH( s->origPtr != -1, 1003 ); +} + + +/*-------------------------------------------------------------*/ +/*--- end blocksort.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/bzlib.c b/plugins/CDVDiso/src/3rdparty/bzip2/bzlib.c index 5b70a84bbc..3afc812f75 100644 --- a/plugins/CDVDiso/src/3rdparty/bzip2/bzlib.c +++ b/plugins/CDVDiso/src/3rdparty/bzip2/bzlib.c @@ -1,1571 +1,1571 @@ - -/*-------------------------------------------------------------*/ -/*--- Library top-level functions. ---*/ -/*--- bzlib.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.4 of 20 December 2006 - Copyright (C) 1996-2006 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - -/* CHANGES - 0.9.0 -- original version. - 0.9.0a/b -- no changes in this file. - 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). - fixed bzWrite/bzRead to ignore zero-length requests. - fixed bzread to correctly handle read requests after EOF. - wrong parameter order in call to bzDecompressInit in - bzBuffToBuffDecompress. Fixed. -*/ - -#include "bzlib_private.h" - - -/*---------------------------------------------------*/ -/*--- Compression stuff ---*/ -/*---------------------------------------------------*/ - - -/*---------------------------------------------------*/ -#ifndef BZ_NO_STDIO -void BZ2_bz__AssertH__fail ( int errcode ) -{ - fprintf(stderr, - "\n\nbzip2/libbzip2: internal error number %d.\n" - "This is a bug in bzip2/libbzip2, %s.\n" - "Please report it to me at: jseward@bzip.org. If this happened\n" - "when you were using some program which uses libbzip2 as a\n" - "component, you should also report this bug to the author(s)\n" - "of that program. Please make an effort to report this bug;\n" - "timely and accurate bug reports eventually lead to higher\n" - "quality software. Thanks. Julian Seward, 15 February 2005.\n\n", - errcode, - BZ2_bzlibVersion() - ); - - if (errcode == 1007) { - fprintf(stderr, - "\n*** A special note about internal error number 1007 ***\n" - "\n" - "Experience suggests that a common cause of i.e. 1007\n" - "is unreliable memory or other hardware. The 1007 assertion\n" - "just happens to cross-check the results of huge numbers of\n" - "memory reads/writes, and so acts (unintendedly) as a stress\n" - "test of your memory system.\n" - "\n" - "I suggest the following: try compressing the file again,\n" - "possibly monitoring progress in detail with the -vv flag.\n" - "\n" - "* If the error cannot be reproduced, and/or happens at different\n" - " points in compression, you may have a flaky memory system.\n" - " Try a memory-test program. I have used Memtest86\n" - " (www.memtest86.com). At the time of writing it is free (GPLd).\n" - " Memtest86 tests memory much more thorougly than your BIOSs\n" - " power-on test, and may find failures that the BIOS doesn't.\n" - "\n" - "* If the error can be repeatably reproduced, this is a bug in\n" - " bzip2, and I would very much like to hear about it. Please\n" - " let me know, and, ideally, save a copy of the file causing the\n" - " problem -- without which I will be unable to investigate it.\n" - "\n" - ); - } - - exit(3); -} -#endif - - -/*---------------------------------------------------*/ -static -int bz_config_ok ( void ) -{ - if (sizeof(int) != 4) return 0; - if (sizeof(short) != 2) return 0; - if (sizeof(char) != 1) return 0; - return 1; -} - - -/*---------------------------------------------------*/ -static -void* default_bzalloc ( void* opaque, Int32 items, Int32 size ) -{ - void* v = malloc ( items * size ); - return v; -} - -static -void default_bzfree ( void* opaque, void* addr ) -{ - if (addr != NULL) free ( addr ); -} - - -/*---------------------------------------------------*/ -static -void prepare_new_block ( EState* s ) -{ - Int32 i; - s->nblock = 0; - s->numZ = 0; - s->state_out_pos = 0; - BZ_INITIALISE_CRC ( s->blockCRC ); - for (i = 0; i < 256; i++) s->inUse[i] = False; - s->blockNo++; -} - - -/*---------------------------------------------------*/ -static -void init_RL ( EState* s ) -{ - s->state_in_ch = 256; - s->state_in_len = 0; -} - - -static -Bool isempty_RL ( EState* s ) -{ - if (s->state_in_ch < 256 && s->state_in_len > 0) - return False; else - return True; -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzCompressInit) - ( bz_stream* strm, - int blockSize100k, - int verbosity, - int workFactor ) -{ - Int32 n; - EState* s; - - if (!bz_config_ok()) return BZ_CONFIG_ERROR; - - if (strm == NULL || - blockSize100k < 1 || blockSize100k > 9 || - workFactor < 0 || workFactor > 250) - return BZ_PARAM_ERROR; - - if (workFactor == 0) workFactor = 30; - if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; - if (strm->bzfree == NULL) strm->bzfree = default_bzfree; - - s = BZALLOC( sizeof(EState) ); - if (s == NULL) return BZ_MEM_ERROR; - s->strm = strm; - - s->arr1 = NULL; - s->arr2 = NULL; - s->ftab = NULL; - - n = 100000 * blockSize100k; - s->arr1 = BZALLOC( n * sizeof(UInt32) ); - s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) ); - s->ftab = BZALLOC( 65537 * sizeof(UInt32) ); - - if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) { - if (s->arr1 != NULL) BZFREE(s->arr1); - if (s->arr2 != NULL) BZFREE(s->arr2); - if (s->ftab != NULL) BZFREE(s->ftab); - if (s != NULL) BZFREE(s); - return BZ_MEM_ERROR; - } - - s->blockNo = 0; - s->state = BZ_S_INPUT; - s->mode = BZ_M_RUNNING; - s->combinedCRC = 0; - s->blockSize100k = blockSize100k; - s->nblockMAX = 100000 * blockSize100k - 19; - s->verbosity = verbosity; - s->workFactor = workFactor; - - s->block = (UChar*)s->arr2; - s->mtfv = (UInt16*)s->arr1; - s->zbits = NULL; - s->ptr = (UInt32*)s->arr1; - - strm->state = s; - strm->total_in_lo32 = 0; - strm->total_in_hi32 = 0; - strm->total_out_lo32 = 0; - strm->total_out_hi32 = 0; - init_RL ( s ); - prepare_new_block ( s ); - return BZ_OK; -} - - -/*---------------------------------------------------*/ -static -void add_pair_to_block ( EState* s ) -{ - Int32 i; - UChar ch = (UChar)(s->state_in_ch); - for (i = 0; i < s->state_in_len; i++) { - BZ_UPDATE_CRC( s->blockCRC, ch ); - } - s->inUse[s->state_in_ch] = True; - switch (s->state_in_len) { - case 1: - s->block[s->nblock] = (UChar)ch; s->nblock++; - break; - case 2: - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - break; - case 3: - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - break; - default: - s->inUse[s->state_in_len-4] = True; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = ((UChar)(s->state_in_len-4)); - s->nblock++; - break; - } -} - - -/*---------------------------------------------------*/ -static -void flush_RL ( EState* s ) -{ - if (s->state_in_ch < 256) add_pair_to_block ( s ); - init_RL ( s ); -} - - -/*---------------------------------------------------*/ -#define ADD_CHAR_TO_BLOCK(zs,zchh0) \ -{ \ - UInt32 zchh = (UInt32)(zchh0); \ - /*-- fast track the common case --*/ \ - if (zchh != zs->state_in_ch && \ - zs->state_in_len == 1) { \ - UChar ch = (UChar)(zs->state_in_ch); \ - BZ_UPDATE_CRC( zs->blockCRC, ch ); \ - zs->inUse[zs->state_in_ch] = True; \ - zs->block[zs->nblock] = (UChar)ch; \ - zs->nblock++; \ - zs->state_in_ch = zchh; \ - } \ - else \ - /*-- general, uncommon cases --*/ \ - if (zchh != zs->state_in_ch || \ - zs->state_in_len == 255) { \ - if (zs->state_in_ch < 256) \ - add_pair_to_block ( zs ); \ - zs->state_in_ch = zchh; \ - zs->state_in_len = 1; \ - } else { \ - zs->state_in_len++; \ - } \ -} - - -/*---------------------------------------------------*/ -static -Bool copy_input_until_stop ( EState* s ) -{ - Bool progress_in = False; - - if (s->mode == BZ_M_RUNNING) { - - /*-- fast track the common case --*/ - while (True) { - /*-- block full? --*/ - if (s->nblock >= s->nblockMAX) break; - /*-- no input? --*/ - if (s->strm->avail_in == 0) break; - progress_in = True; - ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); - s->strm->next_in++; - s->strm->avail_in--; - s->strm->total_in_lo32++; - if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; - } - - } else { - - /*-- general, uncommon case --*/ - while (True) { - /*-- block full? --*/ - if (s->nblock >= s->nblockMAX) break; - /*-- no input? --*/ - if (s->strm->avail_in == 0) break; - /*-- flush/finish end? --*/ - if (s->avail_in_expect == 0) break; - progress_in = True; - ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); - s->strm->next_in++; - s->strm->avail_in--; - s->strm->total_in_lo32++; - if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; - s->avail_in_expect--; - } - } - return progress_in; -} - - -/*---------------------------------------------------*/ -static -Bool copy_output_until_stop ( EState* s ) -{ - Bool progress_out = False; - - while (True) { - - /*-- no output space? --*/ - if (s->strm->avail_out == 0) break; - - /*-- block done? --*/ - if (s->state_out_pos >= s->numZ) break; - - progress_out = True; - *(s->strm->next_out) = s->zbits[s->state_out_pos]; - s->state_out_pos++; - s->strm->avail_out--; - s->strm->next_out++; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - return progress_out; -} - - -/*---------------------------------------------------*/ -static -Bool handle_compress ( bz_stream* strm ) -{ - Bool progress_in = False; - Bool progress_out = False; - EState* s = strm->state; - - while (True) { - - if (s->state == BZ_S_OUTPUT) { - progress_out |= copy_output_until_stop ( s ); - if (s->state_out_pos < s->numZ) break; - if (s->mode == BZ_M_FINISHING && - s->avail_in_expect == 0 && - isempty_RL(s)) break; - prepare_new_block ( s ); - s->state = BZ_S_INPUT; - if (s->mode == BZ_M_FLUSHING && - s->avail_in_expect == 0 && - isempty_RL(s)) break; - } - - if (s->state == BZ_S_INPUT) { - progress_in |= copy_input_until_stop ( s ); - if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { - flush_RL ( s ); - BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) ); - s->state = BZ_S_OUTPUT; - } - else - if (s->nblock >= s->nblockMAX) { - BZ2_compressBlock ( s, False ); - s->state = BZ_S_OUTPUT; - } - else - if (s->strm->avail_in == 0) { - break; - } - } - - } - - return progress_in || progress_out; -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action ) -{ - Bool progress; - EState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - preswitch: - switch (s->mode) { - - case BZ_M_IDLE: - return BZ_SEQUENCE_ERROR; - - case BZ_M_RUNNING: - if (action == BZ_RUN) { - progress = handle_compress ( strm ); - return progress ? BZ_RUN_OK : BZ_PARAM_ERROR; - } - else - if (action == BZ_FLUSH) { - s->avail_in_expect = strm->avail_in; - s->mode = BZ_M_FLUSHING; - goto preswitch; - } - else - if (action == BZ_FINISH) { - s->avail_in_expect = strm->avail_in; - s->mode = BZ_M_FINISHING; - goto preswitch; - } - else - return BZ_PARAM_ERROR; - - case BZ_M_FLUSHING: - if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR; - if (s->avail_in_expect != s->strm->avail_in) - return BZ_SEQUENCE_ERROR; - progress = handle_compress ( strm ); - if (s->avail_in_expect > 0 || !isempty_RL(s) || - s->state_out_pos < s->numZ) return BZ_FLUSH_OK; - s->mode = BZ_M_RUNNING; - return BZ_RUN_OK; - - case BZ_M_FINISHING: - if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR; - if (s->avail_in_expect != s->strm->avail_in) - return BZ_SEQUENCE_ERROR; - progress = handle_compress ( strm ); - if (!progress) return BZ_SEQUENCE_ERROR; - if (s->avail_in_expect > 0 || !isempty_RL(s) || - s->state_out_pos < s->numZ) return BZ_FINISH_OK; - s->mode = BZ_M_IDLE; - return BZ_STREAM_END; - } - return BZ_OK; /*--not reached--*/ -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm ) -{ - EState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - if (s->arr1 != NULL) BZFREE(s->arr1); - if (s->arr2 != NULL) BZFREE(s->arr2); - if (s->ftab != NULL) BZFREE(s->ftab); - BZFREE(strm->state); - - strm->state = NULL; - - return BZ_OK; -} - - -/*---------------------------------------------------*/ -/*--- Decompression stuff ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzDecompressInit) - ( bz_stream* strm, - int verbosity, - int small ) -{ - DState* s; - - if (!bz_config_ok()) return BZ_CONFIG_ERROR; - - if (strm == NULL) return BZ_PARAM_ERROR; - if (small != 0 && small != 1) return BZ_PARAM_ERROR; - if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; - - if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; - if (strm->bzfree == NULL) strm->bzfree = default_bzfree; - - s = BZALLOC( sizeof(DState) ); - if (s == NULL) return BZ_MEM_ERROR; - s->strm = strm; - strm->state = s; - s->state = BZ_X_MAGIC_1; - s->bsLive = 0; - s->bsBuff = 0; - s->calculatedCombinedCRC = 0; - strm->total_in_lo32 = 0; - strm->total_in_hi32 = 0; - strm->total_out_lo32 = 0; - strm->total_out_hi32 = 0; - s->smallDecompress = (Bool)small; - s->ll4 = NULL; - s->ll16 = NULL; - s->tt = NULL; - s->currBlockNo = 0; - s->verbosity = verbosity; - - return BZ_OK; -} - - -/*---------------------------------------------------*/ -/* Return True iff data corruption is discovered. - Returns False if there is no problem. -*/ -static -Bool unRLE_obuf_to_output_FAST ( DState* s ) -{ - UChar k1; - - if (s->blockRandomised) { - - while (True) { - /* try to finish existing run */ - while (True) { - if (s->strm->avail_out == 0) return False; - if (s->state_out_len == 0) break; - *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; - BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); - s->state_out_len--; - s->strm->next_out++; - s->strm->avail_out--; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - /* can a new run be started? */ - if (s->nblock_used == s->save_nblock+1) return False; - - /* Only caused by corrupt data stream? */ - if (s->nblock_used > s->save_nblock+1) - return True; - - s->state_out_len = 1; - s->state_out_ch = s->k0; - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 2; - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 3; - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - s->state_out_len = ((Int32)k1) + 4; - BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; - s->k0 ^= BZ_RAND_MASK; s->nblock_used++; - } - - } else { - - /* restore */ - UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; - UChar c_state_out_ch = s->state_out_ch; - Int32 c_state_out_len = s->state_out_len; - Int32 c_nblock_used = s->nblock_used; - Int32 c_k0 = s->k0; - UInt32* c_tt = s->tt; - UInt32 c_tPos = s->tPos; - char* cs_next_out = s->strm->next_out; - unsigned int cs_avail_out = s->strm->avail_out; - /* end restore */ - - UInt32 avail_out_INIT = cs_avail_out; - Int32 s_save_nblockPP = s->save_nblock+1; - unsigned int total_out_lo32_old; - - while (True) { - - /* try to finish existing run */ - if (c_state_out_len > 0) { - while (True) { - if (cs_avail_out == 0) goto return_notr; - if (c_state_out_len == 1) break; - *( (UChar*)(cs_next_out) ) = c_state_out_ch; - BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); - c_state_out_len--; - cs_next_out++; - cs_avail_out--; - } - s_state_out_len_eq_one: - { - if (cs_avail_out == 0) { - c_state_out_len = 1; goto return_notr; - }; - *( (UChar*)(cs_next_out) ) = c_state_out_ch; - BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); - cs_next_out++; - cs_avail_out--; - } - } - /* Only caused by corrupt data stream? */ - if (c_nblock_used > s_save_nblockPP) - return True; - - /* can a new run be started? */ - if (c_nblock_used == s_save_nblockPP) { - c_state_out_len = 0; goto return_notr; - }; - c_state_out_ch = c_k0; - BZ_GET_FAST_C(k1); c_nblock_used++; - if (k1 != c_k0) { - c_k0 = k1; goto s_state_out_len_eq_one; - }; - if (c_nblock_used == s_save_nblockPP) - goto s_state_out_len_eq_one; - - c_state_out_len = 2; - BZ_GET_FAST_C(k1); c_nblock_used++; - if (c_nblock_used == s_save_nblockPP) continue; - if (k1 != c_k0) { c_k0 = k1; continue; }; - - c_state_out_len = 3; - BZ_GET_FAST_C(k1); c_nblock_used++; - if (c_nblock_used == s_save_nblockPP) continue; - if (k1 != c_k0) { c_k0 = k1; continue; }; - - BZ_GET_FAST_C(k1); c_nblock_used++; - c_state_out_len = ((Int32)k1) + 4; - BZ_GET_FAST_C(c_k0); c_nblock_used++; - } - - return_notr: - total_out_lo32_old = s->strm->total_out_lo32; - s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); - if (s->strm->total_out_lo32 < total_out_lo32_old) - s->strm->total_out_hi32++; - - /* save */ - s->calculatedBlockCRC = c_calculatedBlockCRC; - s->state_out_ch = c_state_out_ch; - s->state_out_len = c_state_out_len; - s->nblock_used = c_nblock_used; - s->k0 = c_k0; - s->tt = c_tt; - s->tPos = c_tPos; - s->strm->next_out = cs_next_out; - s->strm->avail_out = cs_avail_out; - /* end save */ - } - return False; -} - - - -/*---------------------------------------------------*/ -__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) -{ - Int32 nb, na, mid; - nb = 0; - na = 256; - do { - mid = (nb + na) >> 1; - if (indx >= cftab[mid]) nb = mid; else na = mid; - } - while (na - nb != 1); - return nb; -} - - -/*---------------------------------------------------*/ -/* Return True iff data corruption is discovered. - Returns False if there is no problem. -*/ -static -Bool unRLE_obuf_to_output_SMALL ( DState* s ) -{ - UChar k1; - - if (s->blockRandomised) { - - while (True) { - /* try to finish existing run */ - while (True) { - if (s->strm->avail_out == 0) return False; - if (s->state_out_len == 0) break; - *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; - BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); - s->state_out_len--; - s->strm->next_out++; - s->strm->avail_out--; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - /* can a new run be started? */ - if (s->nblock_used == s->save_nblock+1) return False; - - /* Only caused by corrupt data stream? */ - if (s->nblock_used > s->save_nblock+1) - return True; - - s->state_out_len = 1; - s->state_out_ch = s->k0; - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 2; - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 3; - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - s->state_out_len = ((Int32)k1) + 4; - BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; - s->k0 ^= BZ_RAND_MASK; s->nblock_used++; - } - - } else { - - while (True) { - /* try to finish existing run */ - while (True) { - if (s->strm->avail_out == 0) return False; - if (s->state_out_len == 0) break; - *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; - BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); - s->state_out_len--; - s->strm->next_out++; - s->strm->avail_out--; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - /* can a new run be started? */ - if (s->nblock_used == s->save_nblock+1) return False; - - /* Only caused by corrupt data stream? */ - if (s->nblock_used > s->save_nblock+1) - return True; - - s->state_out_len = 1; - s->state_out_ch = s->k0; - BZ_GET_SMALL(k1); s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 2; - BZ_GET_SMALL(k1); s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 3; - BZ_GET_SMALL(k1); s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - BZ_GET_SMALL(k1); s->nblock_used++; - s->state_out_len = ((Int32)k1) + 4; - BZ_GET_SMALL(s->k0); s->nblock_used++; - } - - } -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) -{ - Bool corrupt; - DState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - while (True) { - if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; - if (s->state == BZ_X_OUTPUT) { - if (s->smallDecompress) - corrupt = unRLE_obuf_to_output_SMALL ( s ); else - corrupt = unRLE_obuf_to_output_FAST ( s ); - if (corrupt) return BZ_DATA_ERROR; - if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { - BZ_FINALISE_CRC ( s->calculatedBlockCRC ); - if (s->verbosity >= 3) - VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, - s->calculatedBlockCRC ); - if (s->verbosity >= 2) VPrintf0 ( "]" ); - if (s->calculatedBlockCRC != s->storedBlockCRC) - return BZ_DATA_ERROR; - s->calculatedCombinedCRC - = (s->calculatedCombinedCRC << 1) | - (s->calculatedCombinedCRC >> 31); - s->calculatedCombinedCRC ^= s->calculatedBlockCRC; - s->state = BZ_X_BLKHDR_1; - } else { - return BZ_OK; - } - } - if (s->state >= BZ_X_MAGIC_1) { - Int32 r = BZ2_decompress ( s ); - if (r == BZ_STREAM_END) { - if (s->verbosity >= 3) - VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x", - s->storedCombinedCRC, s->calculatedCombinedCRC ); - if (s->calculatedCombinedCRC != s->storedCombinedCRC) - return BZ_DATA_ERROR; - return r; - } - if (s->state != BZ_X_OUTPUT) return r; - } - } - - AssertH ( 0, 6001 ); - - return 0; /*NOTREACHED*/ -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) -{ - DState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - if (s->tt != NULL) BZFREE(s->tt); - if (s->ll16 != NULL) BZFREE(s->ll16); - if (s->ll4 != NULL) BZFREE(s->ll4); - - BZFREE(strm->state); - strm->state = NULL; - - return BZ_OK; -} - - -#ifndef BZ_NO_STDIO -/*---------------------------------------------------*/ -/*--- File I/O stuff ---*/ -/*---------------------------------------------------*/ - -#define BZ_SETERR(eee) \ -{ \ - if (bzerror != NULL) *bzerror = eee; \ - if (bzf != NULL) bzf->lastErr = eee; \ -} - -typedef - struct { - FILE* handle; - Char buf[BZ_MAX_UNUSED]; - Int32 bufN; - Bool writing; - bz_stream strm; - Int32 lastErr; - Bool initialisedOk; - } - bzFile; - - -/*---------------------------------------------*/ -static Bool myfeof ( FILE* f ) -{ - Int32 c = fgetc ( f ); - if (c == EOF) return True; - ungetc ( c, f ); - return False; -} - - -/*---------------------------------------------------*/ -BZFILE* BZ_API(BZ2_bzWriteOpen) - ( int* bzerror, - FILE* f, - int blockSize100k, - int verbosity, - int workFactor ) -{ - Int32 ret; - bzFile* bzf = NULL; - - BZ_SETERR(BZ_OK); - - if (f == NULL || - (blockSize100k < 1 || blockSize100k > 9) || - (workFactor < 0 || workFactor > 250) || - (verbosity < 0 || verbosity > 4)) - { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; - - if (ferror(f)) - { BZ_SETERR(BZ_IO_ERROR); return NULL; }; - - bzf = malloc ( sizeof(bzFile) ); - if (bzf == NULL) - { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; - - BZ_SETERR(BZ_OK); - bzf->initialisedOk = False; - bzf->bufN = 0; - bzf->handle = f; - bzf->writing = True; - bzf->strm.bzalloc = NULL; - bzf->strm.bzfree = NULL; - bzf->strm.opaque = NULL; - - if (workFactor == 0) workFactor = 30; - ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, - verbosity, workFactor ); - if (ret != BZ_OK) - { BZ_SETERR(ret); free(bzf); return NULL; }; - - bzf->strm.avail_in = 0; - bzf->initialisedOk = True; - return bzf; -} - - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzWrite) - ( int* bzerror, - BZFILE* b, - void* buf, - int len ) -{ - Int32 n, n2, ret; - bzFile* bzf = (bzFile*)b; - - BZ_SETERR(BZ_OK); - if (bzf == NULL || buf == NULL || len < 0) - { BZ_SETERR(BZ_PARAM_ERROR); return; }; - if (!(bzf->writing)) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - - if (len == 0) - { BZ_SETERR(BZ_OK); return; }; - - bzf->strm.avail_in = len; - bzf->strm.next_in = buf; - - while (True) { - bzf->strm.avail_out = BZ_MAX_UNUSED; - bzf->strm.next_out = bzf->buf; - ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN ); - if (ret != BZ_RUN_OK) - { BZ_SETERR(ret); return; }; - - if (bzf->strm.avail_out < BZ_MAX_UNUSED) { - n = BZ_MAX_UNUSED - bzf->strm.avail_out; - n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), - n, bzf->handle ); - if (n != n2 || ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - } - - if (bzf->strm.avail_in == 0) - { BZ_SETERR(BZ_OK); return; }; - } -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzWriteClose) - ( int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in, - unsigned int* nbytes_out ) -{ - BZ2_bzWriteClose64 ( bzerror, b, abandon, - nbytes_in, NULL, nbytes_out, NULL ); -} - - -void BZ_API(BZ2_bzWriteClose64) - ( int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in_lo32, - unsigned int* nbytes_in_hi32, - unsigned int* nbytes_out_lo32, - unsigned int* nbytes_out_hi32 ) -{ - Int32 n, n2, ret; - bzFile* bzf = (bzFile*)b; - - if (bzf == NULL) - { BZ_SETERR(BZ_OK); return; }; - if (!(bzf->writing)) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - - if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0; - if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0; - if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0; - if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0; - - if ((!abandon) && bzf->lastErr == BZ_OK) { - while (True) { - bzf->strm.avail_out = BZ_MAX_UNUSED; - bzf->strm.next_out = bzf->buf; - ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH ); - if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) - { BZ_SETERR(ret); return; }; - - if (bzf->strm.avail_out < BZ_MAX_UNUSED) { - n = BZ_MAX_UNUSED - bzf->strm.avail_out; - n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), - n, bzf->handle ); - if (n != n2 || ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - } - - if (ret == BZ_STREAM_END) break; - } - } - - if ( !abandon && !ferror ( bzf->handle ) ) { - fflush ( bzf->handle ); - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - } - - if (nbytes_in_lo32 != NULL) - *nbytes_in_lo32 = bzf->strm.total_in_lo32; - if (nbytes_in_hi32 != NULL) - *nbytes_in_hi32 = bzf->strm.total_in_hi32; - if (nbytes_out_lo32 != NULL) - *nbytes_out_lo32 = bzf->strm.total_out_lo32; - if (nbytes_out_hi32 != NULL) - *nbytes_out_hi32 = bzf->strm.total_out_hi32; - - BZ_SETERR(BZ_OK); - BZ2_bzCompressEnd ( &(bzf->strm) ); - free ( bzf ); -} - - -/*---------------------------------------------------*/ -BZFILE* BZ_API(BZ2_bzReadOpen) - ( int* bzerror, - FILE* f, - int verbosity, - int small, - void* unused, - int nUnused ) -{ - bzFile* bzf = NULL; - int ret; - - BZ_SETERR(BZ_OK); - - if (f == NULL || - (small != 0 && small != 1) || - (verbosity < 0 || verbosity > 4) || - (unused == NULL && nUnused != 0) || - (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) - { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; - - if (ferror(f)) - { BZ_SETERR(BZ_IO_ERROR); return NULL; }; - - bzf = malloc ( sizeof(bzFile) ); - if (bzf == NULL) - { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; - - BZ_SETERR(BZ_OK); - - bzf->initialisedOk = False; - bzf->handle = f; - bzf->bufN = 0; - bzf->writing = False; - bzf->strm.bzalloc = NULL; - bzf->strm.bzfree = NULL; - bzf->strm.opaque = NULL; - - while (nUnused > 0) { - bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; - unused = ((void*)( 1 + ((UChar*)(unused)) )); - nUnused--; - } - - ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); - if (ret != BZ_OK) - { BZ_SETERR(ret); free(bzf); return NULL; }; - - bzf->strm.avail_in = bzf->bufN; - bzf->strm.next_in = bzf->buf; - - bzf->initialisedOk = True; - return bzf; -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) -{ - bzFile* bzf = (bzFile*)b; - - BZ_SETERR(BZ_OK); - if (bzf == NULL) - { BZ_SETERR(BZ_OK); return; }; - - if (bzf->writing) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - - if (bzf->initialisedOk) - (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); - free ( bzf ); -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzRead) - ( int* bzerror, - BZFILE* b, - void* buf, - int len ) -{ - Int32 n, ret; - bzFile* bzf = (bzFile*)b; - - BZ_SETERR(BZ_OK); - - if (bzf == NULL || buf == NULL || len < 0) - { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; - - if (bzf->writing) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; - - if (len == 0) - { BZ_SETERR(BZ_OK); return 0; }; - - bzf->strm.avail_out = len; - bzf->strm.next_out = buf; - - while (True) { - - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return 0; }; - - if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { - n = fread ( bzf->buf, sizeof(UChar), - BZ_MAX_UNUSED, bzf->handle ); - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return 0; }; - bzf->bufN = n; - bzf->strm.avail_in = bzf->bufN; - bzf->strm.next_in = bzf->buf; - } - - ret = BZ2_bzDecompress ( &(bzf->strm) ); - - if (ret != BZ_OK && ret != BZ_STREAM_END) - { BZ_SETERR(ret); return 0; }; - - if (ret == BZ_OK && myfeof(bzf->handle) && - bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) - { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; - - if (ret == BZ_STREAM_END) - { BZ_SETERR(BZ_STREAM_END); - return len - bzf->strm.avail_out; }; - if (bzf->strm.avail_out == 0) - { BZ_SETERR(BZ_OK); return len; }; - - } - - return 0; /*not reached*/ -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzReadGetUnused) - ( int* bzerror, - BZFILE* b, - void** unused, - int* nUnused ) -{ - bzFile* bzf = (bzFile*)b; - if (bzf == NULL) - { BZ_SETERR(BZ_PARAM_ERROR); return; }; - if (bzf->lastErr != BZ_STREAM_END) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - if (unused == NULL || nUnused == NULL) - { BZ_SETERR(BZ_PARAM_ERROR); return; }; - - BZ_SETERR(BZ_OK); - *nUnused = bzf->strm.avail_in; - *unused = bzf->strm.next_in; -} -#endif - - -/*---------------------------------------------------*/ -/*--- Misc convenience stuff ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzBuffToBuffCompress) - ( char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int blockSize100k, - int verbosity, - int workFactor ) -{ - bz_stream strm; - int ret; - - if (dest == NULL || destLen == NULL || - source == NULL || - blockSize100k < 1 || blockSize100k > 9 || - verbosity < 0 || verbosity > 4 || - workFactor < 0 || workFactor > 250) - return BZ_PARAM_ERROR; - - if (workFactor == 0) workFactor = 30; - strm.bzalloc = NULL; - strm.bzfree = NULL; - strm.opaque = NULL; - ret = BZ2_bzCompressInit ( &strm, blockSize100k, - verbosity, workFactor ); - if (ret != BZ_OK) return ret; - - strm.next_in = source; - strm.next_out = dest; - strm.avail_in = sourceLen; - strm.avail_out = *destLen; - - ret = BZ2_bzCompress ( &strm, BZ_FINISH ); - if (ret == BZ_FINISH_OK) goto output_overflow; - if (ret != BZ_STREAM_END) goto errhandler; - - /* normal termination */ - *destLen -= strm.avail_out; - BZ2_bzCompressEnd ( &strm ); - return BZ_OK; - - output_overflow: - BZ2_bzCompressEnd ( &strm ); - return BZ_OUTBUFF_FULL; - - errhandler: - BZ2_bzCompressEnd ( &strm ); - return ret; -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzBuffToBuffDecompress) - ( char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int small, - int verbosity ) -{ - bz_stream strm; - int ret; - - if (dest == NULL || destLen == NULL || - source == NULL || - (small != 0 && small != 1) || - verbosity < 0 || verbosity > 4) - return BZ_PARAM_ERROR; - - strm.bzalloc = NULL; - strm.bzfree = NULL; - strm.opaque = NULL; - ret = BZ2_bzDecompressInit ( &strm, verbosity, small ); - if (ret != BZ_OK) return ret; - - strm.next_in = source; - strm.next_out = dest; - strm.avail_in = sourceLen; - strm.avail_out = *destLen; - - ret = BZ2_bzDecompress ( &strm ); - if (ret == BZ_OK) goto output_overflow_or_eof; - if (ret != BZ_STREAM_END) goto errhandler; - - /* normal termination */ - *destLen -= strm.avail_out; - BZ2_bzDecompressEnd ( &strm ); - return BZ_OK; - - output_overflow_or_eof: - if (strm.avail_out > 0) { - BZ2_bzDecompressEnd ( &strm ); - return BZ_UNEXPECTED_EOF; - } else { - BZ2_bzDecompressEnd ( &strm ); - return BZ_OUTBUFF_FULL; - }; - - errhandler: - BZ2_bzDecompressEnd ( &strm ); - return ret; -} - - -/*---------------------------------------------------*/ -/*-- - Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) - to support better zlib compatibility. - This code is not _officially_ part of libbzip2 (yet); - I haven't tested it, documented it, or considered the - threading-safeness of it. - If this code breaks, please contact both Yoshioka and me. ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -/*-- - return version like "0.9.5d, 4-Sept-1999". ---*/ -const char * BZ_API(BZ2_bzlibVersion)(void) -{ - return BZ_VERSION; -} - - -#ifndef BZ_NO_STDIO -/*---------------------------------------------------*/ - -#if defined(_WIN32) || defined(OS2) || defined(MSDOS) -# include -# include -# define SET_BINARY_MODE(file) _setmode(_fileno(file),O_BINARY) -#else -# define SET_BINARY_MODE(file) -#endif -static -BZFILE * bzopen_or_bzdopen - ( const char *path, /* no use when bzdopen */ - int fd, /* no use when bzdopen */ - const char *mode, - int open_mode) /* bzopen: 0, bzdopen:1 */ -{ - int bzerr; - char unused[BZ_MAX_UNUSED]; - int blockSize100k = 9; - int writing = 0; - char mode2[10] = ""; - FILE *fp = NULL; - BZFILE *bzfp = NULL; - int verbosity = 0; - int workFactor = 30; - int smallMode = 0; - int nUnused = 0; - - if (mode == NULL) return NULL; - while (*mode) { - switch (*mode) { - case 'r': - writing = 0; break; - case 'w': - writing = 1; break; - case 's': - smallMode = 1; break; - default: - if (isdigit((int)(*mode))) { - blockSize100k = *mode-BZ_HDR_0; - } - } - mode++; - } - strcat(mode2, writing ? "w" : "r" ); - strcat(mode2,"b"); /* binary mode */ - - if (open_mode==0) { - if (path==NULL || strcmp(path,"")==0) { - fp = (writing ? stdout : stdin); - SET_BINARY_MODE(fp); - } else { - fp = fopen(path,mode2); - } - } else { -#ifdef BZ_STRICT_ANSI - fp = NULL; -#else - fp = _fdopen(fd,mode2); -#endif - } - if (fp == NULL) return NULL; - - if (writing) { - /* Guard against total chaos and anarchy -- JRS */ - if (blockSize100k < 1) blockSize100k = 1; - if (blockSize100k > 9) blockSize100k = 9; - bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k, - verbosity,workFactor); - } else { - bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode, - unused,nUnused); - } - if (bzfp == NULL) { - if (fp != stdin && fp != stdout) fclose(fp); - return NULL; - } - return bzfp; -} - - -/*---------------------------------------------------*/ -/*-- - open file for read or write. - ex) bzopen("file","w9") - case path="" or NULL => use stdin or stdout. ---*/ -BZFILE * BZ_API(BZ2_bzopen) - ( const char *path, - const char *mode ) -{ - return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0); -} - - -/*---------------------------------------------------*/ -BZFILE * BZ_API(BZ2_bzdopen) - ( int fd, - const char *mode ) -{ - return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1); -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len ) -{ - int bzerr, nread; - if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0; - nread = BZ2_bzRead(&bzerr,b,buf,len); - if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) { - return nread; - } else { - return -1; - } -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len ) -{ - int bzerr; - - BZ2_bzWrite(&bzerr,b,buf,len); - if(bzerr == BZ_OK){ - return len; - }else{ - return -1; - } -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzflush) (BZFILE *b) -{ - /* do nothing now... */ - return 0; -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzclose) (BZFILE* b) -{ - int bzerr; - FILE *fp; - - if (b==NULL) {return;} - fp = ((bzFile *)b)->handle; - if(((bzFile*)b)->writing){ - BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); - if(bzerr != BZ_OK){ - BZ2_bzWriteClose(NULL,b,1,NULL,NULL); - } - }else{ - BZ2_bzReadClose(&bzerr,b); - } - if(fp!=stdin && fp!=stdout){ - fclose(fp); - } -} - - -/*---------------------------------------------------*/ -/*-- - return last error code ---*/ -static const char *bzerrorstrings[] = { - "OK" - ,"SEQUENCE_ERROR" - ,"PARAM_ERROR" - ,"MEM_ERROR" - ,"DATA_ERROR" - ,"DATA_ERROR_MAGIC" - ,"IO_ERROR" - ,"UNEXPECTED_EOF" - ,"OUTBUFF_FULL" - ,"CONFIG_ERROR" - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ -}; - - -const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum) -{ - int err = ((bzFile *)b)->lastErr; - - if(err>0) err = 0; - *errnum = err; - return bzerrorstrings[err*-1]; -} -#endif - - -/*-------------------------------------------------------------*/ -/*--- end bzlib.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Library top-level functions. ---*/ +/*--- bzlib.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + +/* CHANGES + 0.9.0 -- original version. + 0.9.0a/b -- no changes in this file. + 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). + fixed bzWrite/bzRead to ignore zero-length requests. + fixed bzread to correctly handle read requests after EOF. + wrong parameter order in call to bzDecompressInit in + bzBuffToBuffDecompress. Fixed. +*/ + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Compression stuff ---*/ +/*---------------------------------------------------*/ + + +/*---------------------------------------------------*/ +#ifndef BZ_NO_STDIO +void BZ2_bz__AssertH__fail ( int errcode ) +{ + fprintf(stderr, + "\n\nbzip2/libbzip2: internal error number %d.\n" + "This is a bug in bzip2/libbzip2, %s.\n" + "Please report it to me at: jseward@bzip.org. If this happened\n" + "when you were using some program which uses libbzip2 as a\n" + "component, you should also report this bug to the author(s)\n" + "of that program. Please make an effort to report this bug;\n" + "timely and accurate bug reports eventually lead to higher\n" + "quality software. Thanks. Julian Seward, 15 February 2005.\n\n", + errcode, + BZ2_bzlibVersion() + ); + + if (errcode == 1007) { + fprintf(stderr, + "\n*** A special note about internal error number 1007 ***\n" + "\n" + "Experience suggests that a common cause of i.e. 1007\n" + "is unreliable memory or other hardware. The 1007 assertion\n" + "just happens to cross-check the results of huge numbers of\n" + "memory reads/writes, and so acts (unintendedly) as a stress\n" + "test of your memory system.\n" + "\n" + "I suggest the following: try compressing the file again,\n" + "possibly monitoring progress in detail with the -vv flag.\n" + "\n" + "* If the error cannot be reproduced, and/or happens at different\n" + " points in compression, you may have a flaky memory system.\n" + " Try a memory-test program. I have used Memtest86\n" + " (www.memtest86.com). At the time of writing it is free (GPLd).\n" + " Memtest86 tests memory much more thorougly than your BIOSs\n" + " power-on test, and may find failures that the BIOS doesn't.\n" + "\n" + "* If the error can be repeatably reproduced, this is a bug in\n" + " bzip2, and I would very much like to hear about it. Please\n" + " let me know, and, ideally, save a copy of the file causing the\n" + " problem -- without which I will be unable to investigate it.\n" + "\n" + ); + } + + exit(3); +} +#endif + + +/*---------------------------------------------------*/ +static +int bz_config_ok ( void ) +{ + if (sizeof(int) != 4) return 0; + if (sizeof(short) != 2) return 0; + if (sizeof(char) != 1) return 0; + return 1; +} + + +/*---------------------------------------------------*/ +static +void* default_bzalloc ( void* opaque, Int32 items, Int32 size ) +{ + void* v = malloc ( items * size ); + return v; +} + +static +void default_bzfree ( void* opaque, void* addr ) +{ + if (addr != NULL) free ( addr ); +} + + +/*---------------------------------------------------*/ +static +void prepare_new_block ( EState* s ) +{ + Int32 i; + s->nblock = 0; + s->numZ = 0; + s->state_out_pos = 0; + BZ_INITIALISE_CRC ( s->blockCRC ); + for (i = 0; i < 256; i++) s->inUse[i] = False; + s->blockNo++; +} + + +/*---------------------------------------------------*/ +static +void init_RL ( EState* s ) +{ + s->state_in_ch = 256; + s->state_in_len = 0; +} + + +static +Bool isempty_RL ( EState* s ) +{ + if (s->state_in_ch < 256 && s->state_in_len > 0) + return False; else + return True; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressInit) + ( bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 n; + EState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL || + blockSize100k < 1 || blockSize100k > 9 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(EState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + + s->arr1 = NULL; + s->arr2 = NULL; + s->ftab = NULL; + + n = 100000 * blockSize100k; + s->arr1 = BZALLOC( n * sizeof(UInt32) ); + s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) ); + s->ftab = BZALLOC( 65537 * sizeof(UInt32) ); + + if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) { + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + if (s != NULL) BZFREE(s); + return BZ_MEM_ERROR; + } + + s->blockNo = 0; + s->state = BZ_S_INPUT; + s->mode = BZ_M_RUNNING; + s->combinedCRC = 0; + s->blockSize100k = blockSize100k; + s->nblockMAX = 100000 * blockSize100k - 19; + s->verbosity = verbosity; + s->workFactor = workFactor; + + s->block = (UChar*)s->arr2; + s->mtfv = (UInt16*)s->arr1; + s->zbits = NULL; + s->ptr = (UInt32*)s->arr1; + + strm->state = s; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + init_RL ( s ); + prepare_new_block ( s ); + return BZ_OK; +} + + +/*---------------------------------------------------*/ +static +void add_pair_to_block ( EState* s ) +{ + Int32 i; + UChar ch = (UChar)(s->state_in_ch); + for (i = 0; i < s->state_in_len; i++) { + BZ_UPDATE_CRC( s->blockCRC, ch ); + } + s->inUse[s->state_in_ch] = True; + switch (s->state_in_len) { + case 1: + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 2: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 3: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + default: + s->inUse[s->state_in_len-4] = True; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = ((UChar)(s->state_in_len-4)); + s->nblock++; + break; + } +} + + +/*---------------------------------------------------*/ +static +void flush_RL ( EState* s ) +{ + if (s->state_in_ch < 256) add_pair_to_block ( s ); + init_RL ( s ); +} + + +/*---------------------------------------------------*/ +#define ADD_CHAR_TO_BLOCK(zs,zchh0) \ +{ \ + UInt32 zchh = (UInt32)(zchh0); \ + /*-- fast track the common case --*/ \ + if (zchh != zs->state_in_ch && \ + zs->state_in_len == 1) { \ + UChar ch = (UChar)(zs->state_in_ch); \ + BZ_UPDATE_CRC( zs->blockCRC, ch ); \ + zs->inUse[zs->state_in_ch] = True; \ + zs->block[zs->nblock] = (UChar)ch; \ + zs->nblock++; \ + zs->state_in_ch = zchh; \ + } \ + else \ + /*-- general, uncommon cases --*/ \ + if (zchh != zs->state_in_ch || \ + zs->state_in_len == 255) { \ + if (zs->state_in_ch < 256) \ + add_pair_to_block ( zs ); \ + zs->state_in_ch = zchh; \ + zs->state_in_len = 1; \ + } else { \ + zs->state_in_len++; \ + } \ +} + + +/*---------------------------------------------------*/ +static +Bool copy_input_until_stop ( EState* s ) +{ + Bool progress_in = False; + + if (s->mode == BZ_M_RUNNING) { + + /*-- fast track the common case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + } + + } else { + + /*-- general, uncommon case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + /*-- flush/finish end? --*/ + if (s->avail_in_expect == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + s->avail_in_expect--; + } + } + return progress_in; +} + + +/*---------------------------------------------------*/ +static +Bool copy_output_until_stop ( EState* s ) +{ + Bool progress_out = False; + + while (True) { + + /*-- no output space? --*/ + if (s->strm->avail_out == 0) break; + + /*-- block done? --*/ + if (s->state_out_pos >= s->numZ) break; + + progress_out = True; + *(s->strm->next_out) = s->zbits[s->state_out_pos]; + s->state_out_pos++; + s->strm->avail_out--; + s->strm->next_out++; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + return progress_out; +} + + +/*---------------------------------------------------*/ +static +Bool handle_compress ( bz_stream* strm ) +{ + Bool progress_in = False; + Bool progress_out = False; + EState* s = strm->state; + + while (True) { + + if (s->state == BZ_S_OUTPUT) { + progress_out |= copy_output_until_stop ( s ); + if (s->state_out_pos < s->numZ) break; + if (s->mode == BZ_M_FINISHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + prepare_new_block ( s ); + s->state = BZ_S_INPUT; + if (s->mode == BZ_M_FLUSHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + } + + if (s->state == BZ_S_INPUT) { + progress_in |= copy_input_until_stop ( s ); + if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { + flush_RL ( s ); + BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) ); + s->state = BZ_S_OUTPUT; + } + else + if (s->nblock >= s->nblockMAX) { + BZ2_compressBlock ( s, False ); + s->state = BZ_S_OUTPUT; + } + else + if (s->strm->avail_in == 0) { + break; + } + } + + } + + return progress_in || progress_out; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action ) +{ + Bool progress; + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + preswitch: + switch (s->mode) { + + case BZ_M_IDLE: + return BZ_SEQUENCE_ERROR; + + case BZ_M_RUNNING: + if (action == BZ_RUN) { + progress = handle_compress ( strm ); + return progress ? BZ_RUN_OK : BZ_PARAM_ERROR; + } + else + if (action == BZ_FLUSH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FLUSHING; + goto preswitch; + } + else + if (action == BZ_FINISH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FINISHING; + goto preswitch; + } + else + return BZ_PARAM_ERROR; + + case BZ_M_FLUSHING: + if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FLUSH_OK; + s->mode = BZ_M_RUNNING; + return BZ_RUN_OK; + + case BZ_M_FINISHING: + if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (!progress) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FINISH_OK; + s->mode = BZ_M_IDLE; + return BZ_STREAM_END; + } + return BZ_OK; /*--not reached--*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm ) +{ + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + BZFREE(strm->state); + + strm->state = NULL; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/*--- Decompression stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressInit) + ( bz_stream* strm, + int verbosity, + int small ) +{ + DState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL) return BZ_PARAM_ERROR; + if (small != 0 && small != 1) return BZ_PARAM_ERROR; + if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; + + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(DState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + strm->state = s; + s->state = BZ_X_MAGIC_1; + s->bsLive = 0; + s->bsBuff = 0; + s->calculatedCombinedCRC = 0; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + s->smallDecompress = (Bool)small; + s->ll4 = NULL; + s->ll16 = NULL; + s->tt = NULL; + s->currBlockNo = 0; + s->verbosity = verbosity; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_FAST ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + /* restore */ + UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; + UChar c_state_out_ch = s->state_out_ch; + Int32 c_state_out_len = s->state_out_len; + Int32 c_nblock_used = s->nblock_used; + Int32 c_k0 = s->k0; + UInt32* c_tt = s->tt; + UInt32 c_tPos = s->tPos; + char* cs_next_out = s->strm->next_out; + unsigned int cs_avail_out = s->strm->avail_out; + /* end restore */ + + UInt32 avail_out_INIT = cs_avail_out; + Int32 s_save_nblockPP = s->save_nblock+1; + unsigned int total_out_lo32_old; + + while (True) { + + /* try to finish existing run */ + if (c_state_out_len > 0) { + while (True) { + if (cs_avail_out == 0) goto return_notr; + if (c_state_out_len == 1) break; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + c_state_out_len--; + cs_next_out++; + cs_avail_out--; + } + s_state_out_len_eq_one: + { + if (cs_avail_out == 0) { + c_state_out_len = 1; goto return_notr; + }; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + cs_next_out++; + cs_avail_out--; + } + } + /* Only caused by corrupt data stream? */ + if (c_nblock_used > s_save_nblockPP) + return True; + + /* can a new run be started? */ + if (c_nblock_used == s_save_nblockPP) { + c_state_out_len = 0; goto return_notr; + }; + c_state_out_ch = c_k0; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (k1 != c_k0) { + c_k0 = k1; goto s_state_out_len_eq_one; + }; + if (c_nblock_used == s_save_nblockPP) + goto s_state_out_len_eq_one; + + c_state_out_len = 2; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + c_state_out_len = 3; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + BZ_GET_FAST_C(k1); c_nblock_used++; + c_state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST_C(c_k0); c_nblock_used++; + } + + return_notr: + total_out_lo32_old = s->strm->total_out_lo32; + s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); + if (s->strm->total_out_lo32 < total_out_lo32_old) + s->strm->total_out_hi32++; + + /* save */ + s->calculatedBlockCRC = c_calculatedBlockCRC; + s->state_out_ch = c_state_out_ch; + s->state_out_len = c_state_out_len; + s->nblock_used = c_nblock_used; + s->k0 = c_k0; + s->tt = c_tt; + s->tPos = c_tPos; + s->strm->next_out = cs_next_out; + s->strm->avail_out = cs_avail_out; + /* end save */ + } + return False; +} + + + +/*---------------------------------------------------*/ +__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) +{ + Int32 nb, na, mid; + nb = 0; + na = 256; + do { + mid = (nb + na) >> 1; + if (indx >= cftab[mid]) nb = mid; else na = mid; + } + while (na - nb != 1); + return nb; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_SMALL ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) +{ + Bool corrupt; + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + while (True) { + if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; + if (s->state == BZ_X_OUTPUT) { + if (s->smallDecompress) + corrupt = unRLE_obuf_to_output_SMALL ( s ); else + corrupt = unRLE_obuf_to_output_FAST ( s ); + if (corrupt) return BZ_DATA_ERROR; + if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { + BZ_FINALISE_CRC ( s->calculatedBlockCRC ); + if (s->verbosity >= 3) + VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, + s->calculatedBlockCRC ); + if (s->verbosity >= 2) VPrintf0 ( "]" ); + if (s->calculatedBlockCRC != s->storedBlockCRC) + return BZ_DATA_ERROR; + s->calculatedCombinedCRC + = (s->calculatedCombinedCRC << 1) | + (s->calculatedCombinedCRC >> 31); + s->calculatedCombinedCRC ^= s->calculatedBlockCRC; + s->state = BZ_X_BLKHDR_1; + } else { + return BZ_OK; + } + } + if (s->state >= BZ_X_MAGIC_1) { + Int32 r = BZ2_decompress ( s ); + if (r == BZ_STREAM_END) { + if (s->verbosity >= 3) + VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x", + s->storedCombinedCRC, s->calculatedCombinedCRC ); + if (s->calculatedCombinedCRC != s->storedCombinedCRC) + return BZ_DATA_ERROR; + return r; + } + if (s->state != BZ_X_OUTPUT) return r; + } + } + + AssertH ( 0, 6001 ); + + return 0; /*NOTREACHED*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) +{ + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->tt != NULL) BZFREE(s->tt); + if (s->ll16 != NULL) BZFREE(s->ll16); + if (s->ll4 != NULL) BZFREE(s->ll4); + + BZFREE(strm->state); + strm->state = NULL; + + return BZ_OK; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ +/*--- File I/O stuff ---*/ +/*---------------------------------------------------*/ + +#define BZ_SETERR(eee) \ +{ \ + if (bzerror != NULL) *bzerror = eee; \ + if (bzf != NULL) bzf->lastErr = eee; \ +} + +typedef + struct { + FILE* handle; + Char buf[BZ_MAX_UNUSED]; + Int32 bufN; + Bool writing; + bz_stream strm; + Int32 lastErr; + Bool initialisedOk; + } + bzFile; + + +/*---------------------------------------------*/ +static Bool myfeof ( FILE* f ) +{ + Int32 c = fgetc ( f ); + if (c == EOF) return True; + ungetc ( c, f ); + return False; +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzWriteOpen) + ( int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 ret; + bzFile* bzf = NULL; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (blockSize100k < 1 || blockSize100k > 9) || + (workFactor < 0 || workFactor > 250) || + (verbosity < 0 || verbosity > 4)) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + bzf->initialisedOk = False; + bzf->bufN = 0; + bzf->handle = f; + bzf->writing = True; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + if (workFactor == 0) workFactor = 30; + ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = 0; + bzf->initialisedOk = True; + return bzf; +} + + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWrite) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return; }; + + bzf->strm.avail_in = len; + bzf->strm.next_in = buf; + + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN ); + if (ret != BZ_RUN_OK) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (bzf->strm.avail_in == 0) + { BZ_SETERR(BZ_OK); return; }; + } +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWriteClose) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out ) +{ + BZ2_bzWriteClose64 ( bzerror, b, abandon, + nbytes_in, NULL, nbytes_out, NULL ); +} + + +void BZ_API(BZ2_bzWriteClose64) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0; + if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0; + if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0; + if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0; + + if ((!abandon) && bzf->lastErr == BZ_OK) { + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH ); + if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (ret == BZ_STREAM_END) break; + } + } + + if ( !abandon && !ferror ( bzf->handle ) ) { + fflush ( bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (nbytes_in_lo32 != NULL) + *nbytes_in_lo32 = bzf->strm.total_in_lo32; + if (nbytes_in_hi32 != NULL) + *nbytes_in_hi32 = bzf->strm.total_in_hi32; + if (nbytes_out_lo32 != NULL) + *nbytes_out_lo32 = bzf->strm.total_out_lo32; + if (nbytes_out_hi32 != NULL) + *nbytes_out_hi32 = bzf->strm.total_out_hi32; + + BZ_SETERR(BZ_OK); + BZ2_bzCompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzReadOpen) + ( int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused ) +{ + bzFile* bzf = NULL; + int ret; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (small != 0 && small != 1) || + (verbosity < 0 || verbosity > 4) || + (unused == NULL && nUnused != 0) || + (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + + bzf->initialisedOk = False; + bzf->handle = f; + bzf->bufN = 0; + bzf->writing = False; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + while (nUnused > 0) { + bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; + unused = ((void*)( 1 + ((UChar*)(unused)) )); + nUnused--; + } + + ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + + bzf->initialisedOk = True; + return bzf; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) +{ + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + + if (bzf->initialisedOk) + (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzRead) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return 0; }; + + bzf->strm.avail_out = len; + bzf->strm.next_out = buf; + + while (True) { + + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + + if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { + n = fread ( bzf->buf, sizeof(UChar), + BZ_MAX_UNUSED, bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + bzf->bufN = n; + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + } + + ret = BZ2_bzDecompress ( &(bzf->strm) ); + + if (ret != BZ_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return 0; }; + + if (ret == BZ_OK && myfeof(bzf->handle) && + bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) + { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; + + if (ret == BZ_STREAM_END) + { BZ_SETERR(BZ_STREAM_END); + return len - bzf->strm.avail_out; }; + if (bzf->strm.avail_out == 0) + { BZ_SETERR(BZ_OK); return len; }; + + } + + return 0; /*not reached*/ +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadGetUnused) + ( int* bzerror, + BZFILE* b, + void** unused, + int* nUnused ) +{ + bzFile* bzf = (bzFile*)b; + if (bzf == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (bzf->lastErr != BZ_STREAM_END) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (unused == NULL || nUnused == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + + BZ_SETERR(BZ_OK); + *nUnused = bzf->strm.avail_in; + *unused = bzf->strm.next_in; +} +#endif + + +/*---------------------------------------------------*/ +/*--- Misc convenience stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffCompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + blockSize100k < 1 || blockSize100k > 9 || + verbosity < 0 || verbosity > 4 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzCompressInit ( &strm, blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzCompress ( &strm, BZ_FINISH ); + if (ret == BZ_FINISH_OK) goto output_overflow; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzCompressEnd ( &strm ); + return BZ_OK; + + output_overflow: + BZ2_bzCompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + + errhandler: + BZ2_bzCompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffDecompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + (small != 0 && small != 1) || + verbosity < 0 || verbosity > 4) + return BZ_PARAM_ERROR; + + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzDecompressInit ( &strm, verbosity, small ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzDecompress ( &strm ); + if (ret == BZ_OK) goto output_overflow_or_eof; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzDecompressEnd ( &strm ); + return BZ_OK; + + output_overflow_or_eof: + if (strm.avail_out > 0) { + BZ2_bzDecompressEnd ( &strm ); + return BZ_UNEXPECTED_EOF; + } else { + BZ2_bzDecompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + }; + + errhandler: + BZ2_bzDecompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +/*-- + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +/*-- + return version like "0.9.5d, 4-Sept-1999". +--*/ +const char * BZ_API(BZ2_bzlibVersion)(void) +{ + return BZ_VERSION; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ + +#if defined(_WIN32) || defined(OS2) || defined(MSDOS) +# include +# include +# define SET_BINARY_MODE(file) _setmode(_fileno(file),O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif +static +BZFILE * bzopen_or_bzdopen + ( const char *path, /* no use when bzdopen */ + int fd, /* no use when bzdopen */ + const char *mode, + int open_mode) /* bzopen: 0, bzdopen:1 */ +{ + int bzerr; + char unused[BZ_MAX_UNUSED]; + int blockSize100k = 9; + int writing = 0; + char mode2[10] = ""; + FILE *fp = NULL; + BZFILE *bzfp = NULL; + int verbosity = 0; + int workFactor = 30; + int smallMode = 0; + int nUnused = 0; + + if (mode == NULL) return NULL; + while (*mode) { + switch (*mode) { + case 'r': + writing = 0; break; + case 'w': + writing = 1; break; + case 's': + smallMode = 1; break; + default: + if (isdigit((int)(*mode))) { + blockSize100k = *mode-BZ_HDR_0; + } + } + mode++; + } + strcat(mode2, writing ? "w" : "r" ); + strcat(mode2,"b"); /* binary mode */ + + if (open_mode==0) { + if (path==NULL || strcmp(path,"")==0) { + fp = (writing ? stdout : stdin); + SET_BINARY_MODE(fp); + } else { + fp = fopen(path,mode2); + } + } else { +#ifdef BZ_STRICT_ANSI + fp = NULL; +#else + fp = _fdopen(fd,mode2); +#endif + } + if (fp == NULL) return NULL; + + if (writing) { + /* Guard against total chaos and anarchy -- JRS */ + if (blockSize100k < 1) blockSize100k = 1; + if (blockSize100k > 9) blockSize100k = 9; + bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k, + verbosity,workFactor); + } else { + bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode, + unused,nUnused); + } + if (bzfp == NULL) { + if (fp != stdin && fp != stdout) fclose(fp); + return NULL; + } + return bzfp; +} + + +/*---------------------------------------------------*/ +/*-- + open file for read or write. + ex) bzopen("file","w9") + case path="" or NULL => use stdin or stdout. +--*/ +BZFILE * BZ_API(BZ2_bzopen) + ( const char *path, + const char *mode ) +{ + return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0); +} + + +/*---------------------------------------------------*/ +BZFILE * BZ_API(BZ2_bzdopen) + ( int fd, + const char *mode ) +{ + return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len ) +{ + int bzerr, nread; + if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0; + nread = BZ2_bzRead(&bzerr,b,buf,len); + if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) { + return nread; + } else { + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len ) +{ + int bzerr; + + BZ2_bzWrite(&bzerr,b,buf,len); + if(bzerr == BZ_OK){ + return len; + }else{ + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzflush) (BZFILE *b) +{ + /* do nothing now... */ + return 0; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzclose) (BZFILE* b) +{ + int bzerr; + FILE *fp; + + if (b==NULL) {return;} + fp = ((bzFile *)b)->handle; + if(((bzFile*)b)->writing){ + BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); + if(bzerr != BZ_OK){ + BZ2_bzWriteClose(NULL,b,1,NULL,NULL); + } + }else{ + BZ2_bzReadClose(&bzerr,b); + } + if(fp!=stdin && fp!=stdout){ + fclose(fp); + } +} + + +/*---------------------------------------------------*/ +/*-- + return last error code +--*/ +static const char *bzerrorstrings[] = { + "OK" + ,"SEQUENCE_ERROR" + ,"PARAM_ERROR" + ,"MEM_ERROR" + ,"DATA_ERROR" + ,"DATA_ERROR_MAGIC" + ,"IO_ERROR" + ,"UNEXPECTED_EOF" + ,"OUTBUFF_FULL" + ,"CONFIG_ERROR" + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ +}; + + +const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum) +{ + int err = ((bzFile *)b)->lastErr; + + if(err>0) err = 0; + *errnum = err; + return bzerrorstrings[err*-1]; +} +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/bzlib.h b/plugins/CDVDiso/src/3rdparty/bzip2/bzlib.h index 941c9c5908..fdb0dbe7b0 100644 --- a/plugins/CDVDiso/src/3rdparty/bzip2/bzlib.h +++ b/plugins/CDVDiso/src/3rdparty/bzip2/bzlib.h @@ -1,282 +1,282 @@ - -/*-------------------------------------------------------------*/ -/*--- Public header file for the library. ---*/ -/*--- bzlib.h ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.4 of 20 December 2006 - Copyright (C) 1996-2006 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#ifndef _BZLIB_H -#define _BZLIB_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define BZ_RUN 0 -#define BZ_FLUSH 1 -#define BZ_FINISH 2 - -#define BZ_OK 0 -#define BZ_RUN_OK 1 -#define BZ_FLUSH_OK 2 -#define BZ_FINISH_OK 3 -#define BZ_STREAM_END 4 -#define BZ_SEQUENCE_ERROR (-1) -#define BZ_PARAM_ERROR (-2) -#define BZ_MEM_ERROR (-3) -#define BZ_DATA_ERROR (-4) -#define BZ_DATA_ERROR_MAGIC (-5) -#define BZ_IO_ERROR (-6) -#define BZ_UNEXPECTED_EOF (-7) -#define BZ_OUTBUFF_FULL (-8) -#define BZ_CONFIG_ERROR (-9) - -typedef - struct { - char *next_in; - unsigned int avail_in; - unsigned int total_in_lo32; - unsigned int total_in_hi32; - - char *next_out; - unsigned int avail_out; - unsigned int total_out_lo32; - unsigned int total_out_hi32; - - void *state; - - void *(*bzalloc)(void *,int,int); - void (*bzfree)(void *,void *); - void *opaque; - } - bz_stream; - - -#ifndef BZ_IMPORT -#define BZ_EXPORT -#endif - -#ifndef BZ_NO_STDIO -/* Need a definitition for FILE */ -#include -#endif - -#ifdef _WIN32 -# include -# ifdef small - /* windows.h define small to char */ -# undef small -# endif -# ifdef BZ_EXPORT -# define BZ_API(func) WINAPI func -# define BZ_EXTERN extern -# else - /* import windows dll dynamically */ -# define BZ_API(func) (WINAPI * func) -# define BZ_EXTERN -# endif -#else -# define BZ_API(func) func -# define BZ_EXTERN extern -#endif - - -/*-- Core (low-level) library functions --*/ - -BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( - bz_stream* strm, - int blockSize100k, - int verbosity, - int workFactor - ); - -BZ_EXTERN int BZ_API(BZ2_bzCompress) ( - bz_stream* strm, - int action - ); - -BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( - bz_stream* strm - ); - -BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( - bz_stream *strm, - int verbosity, - int small - ); - -BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( - bz_stream* strm - ); - -BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( - bz_stream *strm - ); - - - -/*-- High(er) level library functions --*/ - -#ifndef BZ_NO_STDIO -#define BZ_MAX_UNUSED 5000 - -typedef void BZFILE; - -BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( - int* bzerror, - FILE* f, - int verbosity, - int small, - void* unused, - int nUnused - ); - -BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( - int* bzerror, - BZFILE* b - ); - -BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( - int* bzerror, - BZFILE* b, - void** unused, - int* nUnused - ); - -BZ_EXTERN int BZ_API(BZ2_bzRead) ( - int* bzerror, - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( - int* bzerror, - FILE* f, - int blockSize100k, - int verbosity, - int workFactor - ); - -BZ_EXTERN void BZ_API(BZ2_bzWrite) ( - int* bzerror, - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( - int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in, - unsigned int* nbytes_out - ); - -BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( - int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in_lo32, - unsigned int* nbytes_in_hi32, - unsigned int* nbytes_out_lo32, - unsigned int* nbytes_out_hi32 - ); -#endif - - -/*-- Utility functions --*/ - -BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( - char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int blockSize100k, - int verbosity, - int workFactor - ); - -BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( - char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int small, - int verbosity - ); - - -/*-- - Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) - to support better zlib compatibility. - This code is not _officially_ part of libbzip2 (yet); - I haven't tested it, documented it, or considered the - threading-safeness of it. - If this code breaks, please contact both Yoshioka and me. ---*/ - -BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) ( - void - ); - -#ifndef BZ_NO_STDIO -BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) ( - const char *path, - const char *mode - ); - -BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) ( - int fd, - const char *mode - ); - -BZ_EXTERN int BZ_API(BZ2_bzread) ( - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN int BZ_API(BZ2_bzwrite) ( - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN int BZ_API(BZ2_bzflush) ( - BZFILE* b - ); - -BZ_EXTERN void BZ_API(BZ2_bzclose) ( - BZFILE* b - ); - -BZ_EXTERN const char * BZ_API(BZ2_bzerror) ( - BZFILE *b, - int *errnum - ); -#endif - -#ifdef __cplusplus -} -#endif - -#endif - -/*-------------------------------------------------------------*/ -/*--- end bzlib.h ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Public header file for the library. ---*/ +/*--- bzlib.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#ifndef _BZLIB_H +#define _BZLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define BZ_RUN 0 +#define BZ_FLUSH 1 +#define BZ_FINISH 2 + +#define BZ_OK 0 +#define BZ_RUN_OK 1 +#define BZ_FLUSH_OK 2 +#define BZ_FINISH_OK 3 +#define BZ_STREAM_END 4 +#define BZ_SEQUENCE_ERROR (-1) +#define BZ_PARAM_ERROR (-2) +#define BZ_MEM_ERROR (-3) +#define BZ_DATA_ERROR (-4) +#define BZ_DATA_ERROR_MAGIC (-5) +#define BZ_IO_ERROR (-6) +#define BZ_UNEXPECTED_EOF (-7) +#define BZ_OUTBUFF_FULL (-8) +#define BZ_CONFIG_ERROR (-9) + +typedef + struct { + char *next_in; + unsigned int avail_in; + unsigned int total_in_lo32; + unsigned int total_in_hi32; + + char *next_out; + unsigned int avail_out; + unsigned int total_out_lo32; + unsigned int total_out_hi32; + + void *state; + + void *(*bzalloc)(void *,int,int); + void (*bzfree)(void *,void *); + void *opaque; + } + bz_stream; + + +#ifndef BZ_IMPORT +#define BZ_EXPORT +#endif + +#ifndef BZ_NO_STDIO +/* Need a definitition for FILE */ +#include +#endif + +#ifdef _WIN32 +# include +# ifdef small + /* windows.h define small to char */ +# undef small +# endif +# ifdef BZ_EXPORT +# define BZ_API(func) WINAPI func +# define BZ_EXTERN extern +# else + /* import windows dll dynamically */ +# define BZ_API(func) (WINAPI * func) +# define BZ_EXTERN +# endif +#else +# define BZ_API(func) func +# define BZ_EXTERN extern +#endif + + +/*-- Core (low-level) library functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( + bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompress) ( + bz_stream* strm, + int action + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( + bz_stream *strm, + int verbosity, + int small + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( + bz_stream *strm + ); + + + +/*-- High(er) level library functions --*/ + +#ifndef BZ_NO_STDIO +#define BZ_MAX_UNUSED 5000 + +typedef void BZFILE; + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( + int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( + int* bzerror, + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( + int* bzerror, + BZFILE* b, + void** unused, + int* nUnused + ); + +BZ_EXTERN int BZ_API(BZ2_bzRead) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( + int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN void BZ_API(BZ2_bzWrite) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 + ); +#endif + + +/*-- Utility functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity + ); + + +/*-- + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ + +BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) ( + void + ); + +#ifndef BZ_NO_STDIO +BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) ( + const char *path, + const char *mode + ); + +BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) ( + int fd, + const char *mode + ); + +BZ_EXTERN int BZ_API(BZ2_bzread) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzwrite) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzflush) ( + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzclose) ( + BZFILE* b + ); + +BZ_EXTERN const char * BZ_API(BZ2_bzerror) ( + BZFILE *b, + int *errnum + ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +/*-------------------------------------------------------------*/ +/*--- end bzlib.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/bzlib_private.h b/plugins/CDVDiso/src/3rdparty/bzip2/bzlib_private.h index df7a22dd31..d0a05546ef 100644 --- a/plugins/CDVDiso/src/3rdparty/bzip2/bzlib_private.h +++ b/plugins/CDVDiso/src/3rdparty/bzip2/bzlib_private.h @@ -1,503 +1,503 @@ - -/*-------------------------------------------------------------*/ -/*--- Private header file for the library. ---*/ -/*--- bzlib_private.h ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.4 of 20 December 2006 - Copyright (C) 1996-2006 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#ifndef _BZLIB_PRIVATE_H -#define _BZLIB_PRIVATE_H - -#include - -#ifndef BZ_NO_STDIO -#include -#include -#include -#endif - -#include "bzlib.h" - - - -/*-- General stuff. --*/ - -#define BZ_VERSION "1.0.4, 20-Dec-2006" - -typedef char Char; -typedef unsigned char Bool; -typedef unsigned char UChar; -typedef int Int32; -typedef unsigned int UInt32; -typedef short Int16; -typedef unsigned short UInt16; - -#define True ((Bool)1) -#define False ((Bool)0) - -#ifndef __GNUC__ -#define __inline__ /* */ -#endif - -#ifndef BZ_NO_STDIO - -extern void BZ2_bz__AssertH__fail ( int errcode ); -#define AssertH(cond,errcode) \ - { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); } - -#if BZ_DEBUG -#define AssertD(cond,msg) \ - { if (!(cond)) { \ - fprintf ( stderr, \ - "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\ - exit(1); \ - }} -#else -#define AssertD(cond,msg) /* */ -#endif - -#define VPrintf0(zf) \ - fprintf(stderr,zf) -#define VPrintf1(zf,za1) \ - fprintf(stderr,zf,za1) -#define VPrintf2(zf,za1,za2) \ - fprintf(stderr,zf,za1,za2) -#define VPrintf3(zf,za1,za2,za3) \ - fprintf(stderr,zf,za1,za2,za3) -#define VPrintf4(zf,za1,za2,za3,za4) \ - fprintf(stderr,zf,za1,za2,za3,za4) -#define VPrintf5(zf,za1,za2,za3,za4,za5) \ - fprintf(stderr,zf,za1,za2,za3,za4,za5) - -#else - -extern void bz_internal_error ( int errcode ); -#define AssertH(cond,errcode) \ - { if (!(cond)) bz_internal_error ( errcode ); } -#define AssertD(cond,msg) do { } while (0) -#define VPrintf0(zf) do { } while (0) -#define VPrintf1(zf,za1) do { } while (0) -#define VPrintf2(zf,za1,za2) do { } while (0) -#define VPrintf3(zf,za1,za2,za3) do { } while (0) -#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0) -#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0) - -#endif - - -#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1) -#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp)) - - -/*-- Header bytes. --*/ - -#define BZ_HDR_B 0x42 /* 'B' */ -#define BZ_HDR_Z 0x5a /* 'Z' */ -#define BZ_HDR_h 0x68 /* 'h' */ -#define BZ_HDR_0 0x30 /* '0' */ - -/*-- Constants for the back end. --*/ - -#define BZ_MAX_ALPHA_SIZE 258 -#define BZ_MAX_CODE_LEN 23 - -#define BZ_RUNA 0 -#define BZ_RUNB 1 - -#define BZ_N_GROUPS 6 -#define BZ_G_SIZE 50 -#define BZ_N_ITERS 4 - -#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) - - - -/*-- Stuff for randomising repetitive blocks. --*/ - -extern Int32 BZ2_rNums[512]; - -#define BZ_RAND_DECLS \ - Int32 rNToGo; \ - Int32 rTPos \ - -#define BZ_RAND_INIT_MASK \ - s->rNToGo = 0; \ - s->rTPos = 0 \ - -#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0) - -#define BZ_RAND_UPD_MASK \ - if (s->rNToGo == 0) { \ - s->rNToGo = BZ2_rNums[s->rTPos]; \ - s->rTPos++; \ - if (s->rTPos == 512) s->rTPos = 0; \ - } \ - s->rNToGo--; - - - -/*-- Stuff for doing CRCs. --*/ - -extern UInt32 BZ2_crc32Table[256]; - -#define BZ_INITIALISE_CRC(crcVar) \ -{ \ - crcVar = 0xffffffffL; \ -} - -#define BZ_FINALISE_CRC(crcVar) \ -{ \ - crcVar = ~(crcVar); \ -} - -#define BZ_UPDATE_CRC(crcVar,cha) \ -{ \ - crcVar = (crcVar << 8) ^ \ - BZ2_crc32Table[(crcVar >> 24) ^ \ - ((UChar)cha)]; \ -} - - - -/*-- States and modes for compression. --*/ - -#define BZ_M_IDLE 1 -#define BZ_M_RUNNING 2 -#define BZ_M_FLUSHING 3 -#define BZ_M_FINISHING 4 - -#define BZ_S_OUTPUT 1 -#define BZ_S_INPUT 2 - -#define BZ_N_RADIX 2 -#define BZ_N_QSORT 12 -#define BZ_N_SHELL 18 -#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) - - - - -/*-- Structure holding all the compression-side stuff. --*/ - -typedef - struct { - /* pointer back to the struct bz_stream */ - bz_stream* strm; - - /* mode this stream is in, and whether inputting */ - /* or outputting data */ - Int32 mode; - Int32 state; - - /* remembers avail_in when flush/finish requested */ - UInt32 avail_in_expect; - - /* for doing the block sorting */ - UInt32* arr1; - UInt32* arr2; - UInt32* ftab; - Int32 origPtr; - - /* aliases for arr1 and arr2 */ - UInt32* ptr; - UChar* block; - UInt16* mtfv; - UChar* zbits; - - /* for deciding when to use the fallback sorting algorithm */ - Int32 workFactor; - - /* run-length-encoding of the input */ - UInt32 state_in_ch; - Int32 state_in_len; - BZ_RAND_DECLS; - - /* input and output limits and current posns */ - Int32 nblock; - Int32 nblockMAX; - Int32 numZ; - Int32 state_out_pos; - - /* map of bytes used in block */ - Int32 nInUse; - Bool inUse[256]; - UChar unseqToSeq[256]; - - /* the buffer for bit stream creation */ - UInt32 bsBuff; - Int32 bsLive; - - /* block and combined CRCs */ - UInt32 blockCRC; - UInt32 combinedCRC; - - /* misc administratium */ - Int32 verbosity; - Int32 blockNo; - Int32 blockSize100k; - - /* stuff for coding the MTF values */ - Int32 nMTF; - Int32 mtfFreq [BZ_MAX_ALPHA_SIZE]; - UChar selector [BZ_MAX_SELECTORS]; - UChar selectorMtf[BZ_MAX_SELECTORS]; - - UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - /* second dimension: only 3 needed; 4 makes index calculations faster */ - UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4]; - - } - EState; - - - -/*-- externs for compression. --*/ - -extern void -BZ2_blockSort ( EState* ); - -extern void -BZ2_compressBlock ( EState*, Bool ); - -extern void -BZ2_bsInitWrite ( EState* ); - -extern void -BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 ); - -extern void -BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 ); - - - -/*-- states for decompression. --*/ - -#define BZ_X_IDLE 1 -#define BZ_X_OUTPUT 2 - -#define BZ_X_MAGIC_1 10 -#define BZ_X_MAGIC_2 11 -#define BZ_X_MAGIC_3 12 -#define BZ_X_MAGIC_4 13 -#define BZ_X_BLKHDR_1 14 -#define BZ_X_BLKHDR_2 15 -#define BZ_X_BLKHDR_3 16 -#define BZ_X_BLKHDR_4 17 -#define BZ_X_BLKHDR_5 18 -#define BZ_X_BLKHDR_6 19 -#define BZ_X_BCRC_1 20 -#define BZ_X_BCRC_2 21 -#define BZ_X_BCRC_3 22 -#define BZ_X_BCRC_4 23 -#define BZ_X_RANDBIT 24 -#define BZ_X_ORIGPTR_1 25 -#define BZ_X_ORIGPTR_2 26 -#define BZ_X_ORIGPTR_3 27 -#define BZ_X_MAPPING_1 28 -#define BZ_X_MAPPING_2 29 -#define BZ_X_SELECTOR_1 30 -#define BZ_X_SELECTOR_2 31 -#define BZ_X_SELECTOR_3 32 -#define BZ_X_CODING_1 33 -#define BZ_X_CODING_2 34 -#define BZ_X_CODING_3 35 -#define BZ_X_MTF_1 36 -#define BZ_X_MTF_2 37 -#define BZ_X_MTF_3 38 -#define BZ_X_MTF_4 39 -#define BZ_X_MTF_5 40 -#define BZ_X_MTF_6 41 -#define BZ_X_ENDHDR_2 42 -#define BZ_X_ENDHDR_3 43 -#define BZ_X_ENDHDR_4 44 -#define BZ_X_ENDHDR_5 45 -#define BZ_X_ENDHDR_6 46 -#define BZ_X_CCRC_1 47 -#define BZ_X_CCRC_2 48 -#define BZ_X_CCRC_3 49 -#define BZ_X_CCRC_4 50 - - - -/*-- Constants for the fast MTF decoder. --*/ - -#define MTFA_SIZE 4096 -#define MTFL_SIZE 16 - - - -/*-- Structure holding all the decompression-side stuff. --*/ - -typedef - struct { - /* pointer back to the struct bz_stream */ - bz_stream* strm; - - /* state indicator for this stream */ - Int32 state; - - /* for doing the final run-length decoding */ - UChar state_out_ch; - Int32 state_out_len; - Bool blockRandomised; - BZ_RAND_DECLS; - - /* the buffer for bit stream reading */ - UInt32 bsBuff; - Int32 bsLive; - - /* misc administratium */ - Int32 blockSize100k; - Bool smallDecompress; - Int32 currBlockNo; - Int32 verbosity; - - /* for undoing the Burrows-Wheeler transform */ - Int32 origPtr; - UInt32 tPos; - Int32 k0; - Int32 unzftab[256]; - Int32 nblock_used; - Int32 cftab[257]; - Int32 cftabCopy[257]; - - /* for undoing the Burrows-Wheeler transform (FAST) */ - UInt32 *tt; - - /* for undoing the Burrows-Wheeler transform (SMALL) */ - UInt16 *ll16; - UChar *ll4; - - /* stored and calculated CRCs */ - UInt32 storedBlockCRC; - UInt32 storedCombinedCRC; - UInt32 calculatedBlockCRC; - UInt32 calculatedCombinedCRC; - - /* map of bytes used in block */ - Int32 nInUse; - Bool inUse[256]; - Bool inUse16[16]; - UChar seqToUnseq[256]; - - /* for decoding the MTF values */ - UChar mtfa [MTFA_SIZE]; - Int32 mtfbase[256 / MTFL_SIZE]; - UChar selector [BZ_MAX_SELECTORS]; - UChar selectorMtf[BZ_MAX_SELECTORS]; - UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - - Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 minLens[BZ_N_GROUPS]; - - /* save area for scalars in the main decompress code */ - Int32 save_i; - Int32 save_j; - Int32 save_t; - Int32 save_alphaSize; - Int32 save_nGroups; - Int32 save_nSelectors; - Int32 save_EOB; - Int32 save_groupNo; - Int32 save_groupPos; - Int32 save_nextSym; - Int32 save_nblockMAX; - Int32 save_nblock; - Int32 save_es; - Int32 save_N; - Int32 save_curr; - Int32 save_zt; - Int32 save_zn; - Int32 save_zvec; - Int32 save_zj; - Int32 save_gSel; - Int32 save_gMinlen; - Int32* save_gLimit; - Int32* save_gBase; - Int32* save_gPerm; - - } - DState; - - - -/*-- Macros for decompression. --*/ - -#define BZ_GET_FAST(cccc) \ - s->tPos = s->tt[s->tPos]; \ - cccc = (UChar)(s->tPos & 0xff); \ - s->tPos >>= 8; - -#define BZ_GET_FAST_C(cccc) \ - c_tPos = c_tt[c_tPos]; \ - cccc = (UChar)(c_tPos & 0xff); \ - c_tPos >>= 8; - -#define SET_LL4(i,n) \ - { if (((i) & 0x1) == 0) \ - s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \ - s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ - } - -#define GET_LL4(i) \ - ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF) - -#define SET_LL(i,n) \ - { s->ll16[i] = (UInt16)(n & 0x0000ffff); \ - SET_LL4(i, n >> 16); \ - } - -#define GET_LL(i) \ - (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16)) - -#define BZ_GET_SMALL(cccc) \ - cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ - s->tPos = GET_LL(s->tPos); - - -/*-- externs for decompression. --*/ - -extern Int32 -BZ2_indexIntoF ( Int32, Int32* ); - -extern Int32 -BZ2_decompress ( DState* ); - -extern void -BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*, - Int32, Int32, Int32 ); - - -#endif - - -/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/ - -#ifdef BZ_NO_STDIO -#ifndef NULL -#define NULL 0 -#endif -#endif - - -/*-------------------------------------------------------------*/ -/*--- end bzlib_private.h ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Private header file for the library. ---*/ +/*--- bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#ifndef _BZLIB_PRIVATE_H +#define _BZLIB_PRIVATE_H + +#include + +#ifndef BZ_NO_STDIO +#include +#include +#include +#endif + +#include "bzlib.h" + + + +/*-- General stuff. --*/ + +#define BZ_VERSION "1.0.4, 20-Dec-2006" + +typedef char Char; +typedef unsigned char Bool; +typedef unsigned char UChar; +typedef int Int32; +typedef unsigned int UInt32; +typedef short Int16; +typedef unsigned short UInt16; + +#define True ((Bool)1) +#define False ((Bool)0) + +#ifndef __GNUC__ +#define __inline__ /* */ +#endif + +#ifndef BZ_NO_STDIO + +extern void BZ2_bz__AssertH__fail ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); } + +#if BZ_DEBUG +#define AssertD(cond,msg) \ + { if (!(cond)) { \ + fprintf ( stderr, \ + "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\ + exit(1); \ + }} +#else +#define AssertD(cond,msg) /* */ +#endif + +#define VPrintf0(zf) \ + fprintf(stderr,zf) +#define VPrintf1(zf,za1) \ + fprintf(stderr,zf,za1) +#define VPrintf2(zf,za1,za2) \ + fprintf(stderr,zf,za1,za2) +#define VPrintf3(zf,za1,za2,za3) \ + fprintf(stderr,zf,za1,za2,za3) +#define VPrintf4(zf,za1,za2,za3,za4) \ + fprintf(stderr,zf,za1,za2,za3,za4) +#define VPrintf5(zf,za1,za2,za3,za4,za5) \ + fprintf(stderr,zf,za1,za2,za3,za4,za5) + +#else + +extern void bz_internal_error ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) bz_internal_error ( errcode ); } +#define AssertD(cond,msg) do { } while (0) +#define VPrintf0(zf) do { } while (0) +#define VPrintf1(zf,za1) do { } while (0) +#define VPrintf2(zf,za1,za2) do { } while (0) +#define VPrintf3(zf,za1,za2,za3) do { } while (0) +#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0) +#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0) + +#endif + + +#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1) +#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp)) + + +/*-- Header bytes. --*/ + +#define BZ_HDR_B 0x42 /* 'B' */ +#define BZ_HDR_Z 0x5a /* 'Z' */ +#define BZ_HDR_h 0x68 /* 'h' */ +#define BZ_HDR_0 0x30 /* '0' */ + +/*-- Constants for the back end. --*/ + +#define BZ_MAX_ALPHA_SIZE 258 +#define BZ_MAX_CODE_LEN 23 + +#define BZ_RUNA 0 +#define BZ_RUNB 1 + +#define BZ_N_GROUPS 6 +#define BZ_G_SIZE 50 +#define BZ_N_ITERS 4 + +#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) + + + +/*-- Stuff for randomising repetitive blocks. --*/ + +extern Int32 BZ2_rNums[512]; + +#define BZ_RAND_DECLS \ + Int32 rNToGo; \ + Int32 rTPos \ + +#define BZ_RAND_INIT_MASK \ + s->rNToGo = 0; \ + s->rTPos = 0 \ + +#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0) + +#define BZ_RAND_UPD_MASK \ + if (s->rNToGo == 0) { \ + s->rNToGo = BZ2_rNums[s->rTPos]; \ + s->rTPos++; \ + if (s->rTPos == 512) s->rTPos = 0; \ + } \ + s->rNToGo--; + + + +/*-- Stuff for doing CRCs. --*/ + +extern UInt32 BZ2_crc32Table[256]; + +#define BZ_INITIALISE_CRC(crcVar) \ +{ \ + crcVar = 0xffffffffL; \ +} + +#define BZ_FINALISE_CRC(crcVar) \ +{ \ + crcVar = ~(crcVar); \ +} + +#define BZ_UPDATE_CRC(crcVar,cha) \ +{ \ + crcVar = (crcVar << 8) ^ \ + BZ2_crc32Table[(crcVar >> 24) ^ \ + ((UChar)cha)]; \ +} + + + +/*-- States and modes for compression. --*/ + +#define BZ_M_IDLE 1 +#define BZ_M_RUNNING 2 +#define BZ_M_FLUSHING 3 +#define BZ_M_FINISHING 4 + +#define BZ_S_OUTPUT 1 +#define BZ_S_INPUT 2 + +#define BZ_N_RADIX 2 +#define BZ_N_QSORT 12 +#define BZ_N_SHELL 18 +#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) + + + + +/*-- Structure holding all the compression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* mode this stream is in, and whether inputting */ + /* or outputting data */ + Int32 mode; + Int32 state; + + /* remembers avail_in when flush/finish requested */ + UInt32 avail_in_expect; + + /* for doing the block sorting */ + UInt32* arr1; + UInt32* arr2; + UInt32* ftab; + Int32 origPtr; + + /* aliases for arr1 and arr2 */ + UInt32* ptr; + UChar* block; + UInt16* mtfv; + UChar* zbits; + + /* for deciding when to use the fallback sorting algorithm */ + Int32 workFactor; + + /* run-length-encoding of the input */ + UInt32 state_in_ch; + Int32 state_in_len; + BZ_RAND_DECLS; + + /* input and output limits and current posns */ + Int32 nblock; + Int32 nblockMAX; + Int32 numZ; + Int32 state_out_pos; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + UChar unseqToSeq[256]; + + /* the buffer for bit stream creation */ + UInt32 bsBuff; + Int32 bsLive; + + /* block and combined CRCs */ + UInt32 blockCRC; + UInt32 combinedCRC; + + /* misc administratium */ + Int32 verbosity; + Int32 blockNo; + Int32 blockSize100k; + + /* stuff for coding the MTF values */ + Int32 nMTF; + Int32 mtfFreq [BZ_MAX_ALPHA_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + /* second dimension: only 3 needed; 4 makes index calculations faster */ + UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4]; + + } + EState; + + + +/*-- externs for compression. --*/ + +extern void +BZ2_blockSort ( EState* ); + +extern void +BZ2_compressBlock ( EState*, Bool ); + +extern void +BZ2_bsInitWrite ( EState* ); + +extern void +BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 ); + +extern void +BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 ); + + + +/*-- states for decompression. --*/ + +#define BZ_X_IDLE 1 +#define BZ_X_OUTPUT 2 + +#define BZ_X_MAGIC_1 10 +#define BZ_X_MAGIC_2 11 +#define BZ_X_MAGIC_3 12 +#define BZ_X_MAGIC_4 13 +#define BZ_X_BLKHDR_1 14 +#define BZ_X_BLKHDR_2 15 +#define BZ_X_BLKHDR_3 16 +#define BZ_X_BLKHDR_4 17 +#define BZ_X_BLKHDR_5 18 +#define BZ_X_BLKHDR_6 19 +#define BZ_X_BCRC_1 20 +#define BZ_X_BCRC_2 21 +#define BZ_X_BCRC_3 22 +#define BZ_X_BCRC_4 23 +#define BZ_X_RANDBIT 24 +#define BZ_X_ORIGPTR_1 25 +#define BZ_X_ORIGPTR_2 26 +#define BZ_X_ORIGPTR_3 27 +#define BZ_X_MAPPING_1 28 +#define BZ_X_MAPPING_2 29 +#define BZ_X_SELECTOR_1 30 +#define BZ_X_SELECTOR_2 31 +#define BZ_X_SELECTOR_3 32 +#define BZ_X_CODING_1 33 +#define BZ_X_CODING_2 34 +#define BZ_X_CODING_3 35 +#define BZ_X_MTF_1 36 +#define BZ_X_MTF_2 37 +#define BZ_X_MTF_3 38 +#define BZ_X_MTF_4 39 +#define BZ_X_MTF_5 40 +#define BZ_X_MTF_6 41 +#define BZ_X_ENDHDR_2 42 +#define BZ_X_ENDHDR_3 43 +#define BZ_X_ENDHDR_4 44 +#define BZ_X_ENDHDR_5 45 +#define BZ_X_ENDHDR_6 46 +#define BZ_X_CCRC_1 47 +#define BZ_X_CCRC_2 48 +#define BZ_X_CCRC_3 49 +#define BZ_X_CCRC_4 50 + + + +/*-- Constants for the fast MTF decoder. --*/ + +#define MTFA_SIZE 4096 +#define MTFL_SIZE 16 + + + +/*-- Structure holding all the decompression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* state indicator for this stream */ + Int32 state; + + /* for doing the final run-length decoding */ + UChar state_out_ch; + Int32 state_out_len; + Bool blockRandomised; + BZ_RAND_DECLS; + + /* the buffer for bit stream reading */ + UInt32 bsBuff; + Int32 bsLive; + + /* misc administratium */ + Int32 blockSize100k; + Bool smallDecompress; + Int32 currBlockNo; + Int32 verbosity; + + /* for undoing the Burrows-Wheeler transform */ + Int32 origPtr; + UInt32 tPos; + Int32 k0; + Int32 unzftab[256]; + Int32 nblock_used; + Int32 cftab[257]; + Int32 cftabCopy[257]; + + /* for undoing the Burrows-Wheeler transform (FAST) */ + UInt32 *tt; + + /* for undoing the Burrows-Wheeler transform (SMALL) */ + UInt16 *ll16; + UChar *ll4; + + /* stored and calculated CRCs */ + UInt32 storedBlockCRC; + UInt32 storedCombinedCRC; + UInt32 calculatedBlockCRC; + UInt32 calculatedCombinedCRC; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + Bool inUse16[16]; + UChar seqToUnseq[256]; + + /* for decoding the MTF values */ + UChar mtfa [MTFA_SIZE]; + Int32 mtfbase[256 / MTFL_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + + Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 minLens[BZ_N_GROUPS]; + + /* save area for scalars in the main decompress code */ + Int32 save_i; + Int32 save_j; + Int32 save_t; + Int32 save_alphaSize; + Int32 save_nGroups; + Int32 save_nSelectors; + Int32 save_EOB; + Int32 save_groupNo; + Int32 save_groupPos; + Int32 save_nextSym; + Int32 save_nblockMAX; + Int32 save_nblock; + Int32 save_es; + Int32 save_N; + Int32 save_curr; + Int32 save_zt; + Int32 save_zn; + Int32 save_zvec; + Int32 save_zj; + Int32 save_gSel; + Int32 save_gMinlen; + Int32* save_gLimit; + Int32* save_gBase; + Int32* save_gPerm; + + } + DState; + + + +/*-- Macros for decompression. --*/ + +#define BZ_GET_FAST(cccc) \ + s->tPos = s->tt[s->tPos]; \ + cccc = (UChar)(s->tPos & 0xff); \ + s->tPos >>= 8; + +#define BZ_GET_FAST_C(cccc) \ + c_tPos = c_tt[c_tPos]; \ + cccc = (UChar)(c_tPos & 0xff); \ + c_tPos >>= 8; + +#define SET_LL4(i,n) \ + { if (((i) & 0x1) == 0) \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ + } + +#define GET_LL4(i) \ + ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF) + +#define SET_LL(i,n) \ + { s->ll16[i] = (UInt16)(n & 0x0000ffff); \ + SET_LL4(i, n >> 16); \ + } + +#define GET_LL(i) \ + (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16)) + +#define BZ_GET_SMALL(cccc) \ + cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ + s->tPos = GET_LL(s->tPos); + + +/*-- externs for decompression. --*/ + +extern Int32 +BZ2_indexIntoF ( Int32, Int32* ); + +extern Int32 +BZ2_decompress ( DState* ); + +extern void +BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*, + Int32, Int32, Int32 ); + + +#endif + + +/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/ + +#ifdef BZ_NO_STDIO +#ifndef NULL +#define NULL 0 +#endif +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/compress.c b/plugins/CDVDiso/src/3rdparty/bzip2/compress.c index 7be1976f69..d98d5c0bd8 100644 --- a/plugins/CDVDiso/src/3rdparty/bzip2/compress.c +++ b/plugins/CDVDiso/src/3rdparty/bzip2/compress.c @@ -1,672 +1,672 @@ - -/*-------------------------------------------------------------*/ -/*--- Compression machinery (not incl block sorting) ---*/ -/*--- compress.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.4 of 20 December 2006 - Copyright (C) 1996-2006 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -/* CHANGES - 0.9.0 -- original version. - 0.9.0a/b -- no changes in this file. - 0.9.0c -- changed setting of nGroups in sendMTFValues() - so as to do a bit better on small files -*/ - -#include "bzlib_private.h" - - -/*---------------------------------------------------*/ -/*--- Bit stream I/O ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -void BZ2_bsInitWrite ( EState* s ) -{ - s->bsLive = 0; - s->bsBuff = 0; -} - - -/*---------------------------------------------------*/ -static -void bsFinishWrite ( EState* s ) -{ - while (s->bsLive > 0) { - s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24); - s->numZ++; - s->bsBuff <<= 8; - s->bsLive -= 8; - } -} - - -/*---------------------------------------------------*/ -#define bsNEEDW(nz) \ -{ \ - while (s->bsLive >= 8) { \ - s->zbits[s->numZ] \ - = (UChar)(s->bsBuff >> 24); \ - s->numZ++; \ - s->bsBuff <<= 8; \ - s->bsLive -= 8; \ - } \ -} - - -/*---------------------------------------------------*/ -static -__inline__ -void bsW ( EState* s, Int32 n, UInt32 v ) -{ - bsNEEDW ( n ); - s->bsBuff |= (v << (32 - s->bsLive - n)); - s->bsLive += n; -} - - -/*---------------------------------------------------*/ -static -void bsPutUInt32 ( EState* s, UInt32 u ) -{ - bsW ( s, 8, (u >> 24) & 0xffL ); - bsW ( s, 8, (u >> 16) & 0xffL ); - bsW ( s, 8, (u >> 8) & 0xffL ); - bsW ( s, 8, u & 0xffL ); -} - - -/*---------------------------------------------------*/ -static -void bsPutUChar ( EState* s, UChar c ) -{ - bsW( s, 8, (UInt32)c ); -} - - -/*---------------------------------------------------*/ -/*--- The back end proper ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -static -void makeMaps_e ( EState* s ) -{ - Int32 i; - s->nInUse = 0; - for (i = 0; i < 256; i++) - if (s->inUse[i]) { - s->unseqToSeq[i] = s->nInUse; - s->nInUse++; - } -} - - -/*---------------------------------------------------*/ -static -void generateMTFValues ( EState* s ) -{ - UChar yy[256]; - Int32 i, j; - Int32 zPend; - Int32 wr; - Int32 EOB; - - /* - After sorting (eg, here), - s->arr1 [ 0 .. s->nblock-1 ] holds sorted order, - and - ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] - holds the original block data. - - The first thing to do is generate the MTF values, - and put them in - ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ]. - Because there are strictly fewer or equal MTF values - than block values, ptr values in this area are overwritten - with MTF values only when they are no longer needed. - - The final compressed bitstream is generated into the - area starting at - (UChar*) (&((UChar*)s->arr2)[s->nblock]) - - These storage aliases are set up in bzCompressInit(), - except for the last one, which is arranged in - compressBlock(). - */ - UInt32* ptr = s->ptr; - UChar* block = s->block; - UInt16* mtfv = s->mtfv; - - makeMaps_e ( s ); - EOB = s->nInUse+1; - - for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0; - - wr = 0; - zPend = 0; - for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i; - - for (i = 0; i < s->nblock; i++) { - UChar ll_i; - AssertD ( wr <= i, "generateMTFValues(1)" ); - j = ptr[i]-1; if (j < 0) j += s->nblock; - ll_i = s->unseqToSeq[block[j]]; - AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" ); - - if (yy[0] == ll_i) { - zPend++; - } else { - - if (zPend > 0) { - zPend--; - while (True) { - if (zPend & 1) { - mtfv[wr] = BZ_RUNB; wr++; - s->mtfFreq[BZ_RUNB]++; - } else { - mtfv[wr] = BZ_RUNA; wr++; - s->mtfFreq[BZ_RUNA]++; - } - if (zPend < 2) break; - zPend = (zPend - 2) / 2; - }; - zPend = 0; - } - { - register UChar rtmp; - register UChar* ryy_j; - register UChar rll_i; - rtmp = yy[1]; - yy[1] = yy[0]; - ryy_j = &(yy[1]); - rll_i = ll_i; - while ( rll_i != rtmp ) { - register UChar rtmp2; - ryy_j++; - rtmp2 = rtmp; - rtmp = *ryy_j; - *ryy_j = rtmp2; - }; - yy[0] = rtmp; - j = ryy_j - &(yy[0]); - mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++; - } - - } - } - - if (zPend > 0) { - zPend--; - while (True) { - if (zPend & 1) { - mtfv[wr] = BZ_RUNB; wr++; - s->mtfFreq[BZ_RUNB]++; - } else { - mtfv[wr] = BZ_RUNA; wr++; - s->mtfFreq[BZ_RUNA]++; - } - if (zPend < 2) break; - zPend = (zPend - 2) / 2; - }; - zPend = 0; - } - - mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++; - - s->nMTF = wr; -} - - -/*---------------------------------------------------*/ -#define BZ_LESSER_ICOST 0 -#define BZ_GREATER_ICOST 15 - -static -void sendMTFValues ( EState* s ) -{ - Int32 v, t, i, j, gs, ge, totc, bt, bc, iter; - Int32 nSelectors, alphaSize, minLen, maxLen, selCtr; - Int32 nGroups, nBytes; - - /*-- - UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - is a global since the decoder also needs it. - - Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - are also globals only used in this proc. - Made global to keep stack frame size small. - --*/ - - - UInt16 cost[BZ_N_GROUPS]; - Int32 fave[BZ_N_GROUPS]; - - UInt16* mtfv = s->mtfv; - - if (s->verbosity >= 3) - VPrintf3( " %d in block, %d after MTF & 1-2 coding, " - "%d+2 syms in use\n", - s->nblock, s->nMTF, s->nInUse ); - - alphaSize = s->nInUse+2; - for (t = 0; t < BZ_N_GROUPS; t++) - for (v = 0; v < alphaSize; v++) - s->len[t][v] = BZ_GREATER_ICOST; - - /*--- Decide how many coding tables to use ---*/ - AssertH ( s->nMTF > 0, 3001 ); - if (s->nMTF < 200) nGroups = 2; else - if (s->nMTF < 600) nGroups = 3; else - if (s->nMTF < 1200) nGroups = 4; else - if (s->nMTF < 2400) nGroups = 5; else - nGroups = 6; - - /*--- Generate an initial set of coding tables ---*/ - { - Int32 nPart, remF, tFreq, aFreq; - - nPart = nGroups; - remF = s->nMTF; - gs = 0; - while (nPart > 0) { - tFreq = remF / nPart; - ge = gs-1; - aFreq = 0; - while (aFreq < tFreq && ge < alphaSize-1) { - ge++; - aFreq += s->mtfFreq[ge]; - } - - if (ge > gs - && nPart != nGroups && nPart != 1 - && ((nGroups-nPart) % 2 == 1)) { - aFreq -= s->mtfFreq[ge]; - ge--; - } - - if (s->verbosity >= 3) - VPrintf5( " initial group %d, [%d .. %d], " - "has %d syms (%4.1f%%)\n", - nPart, gs, ge, aFreq, - (100.0 * (float)aFreq) / (float)(s->nMTF) ); - - for (v = 0; v < alphaSize; v++) - if (v >= gs && v <= ge) - s->len[nPart-1][v] = BZ_LESSER_ICOST; else - s->len[nPart-1][v] = BZ_GREATER_ICOST; - - nPart--; - gs = ge+1; - remF -= aFreq; - } - } - - /*--- - Iterate up to BZ_N_ITERS times to improve the tables. - ---*/ - for (iter = 0; iter < BZ_N_ITERS; iter++) { - - for (t = 0; t < nGroups; t++) fave[t] = 0; - - for (t = 0; t < nGroups; t++) - for (v = 0; v < alphaSize; v++) - s->rfreq[t][v] = 0; - - /*--- - Set up an auxiliary length table which is used to fast-track - the common case (nGroups == 6). - ---*/ - if (nGroups == 6) { - for (v = 0; v < alphaSize; v++) { - s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; - s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; - s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; - } - } - - nSelectors = 0; - totc = 0; - gs = 0; - while (True) { - - /*--- Set group start & end marks. --*/ - if (gs >= s->nMTF) break; - ge = gs + BZ_G_SIZE - 1; - if (ge >= s->nMTF) ge = s->nMTF-1; - - /*-- - Calculate the cost of this group as coded - by each of the coding tables. - --*/ - for (t = 0; t < nGroups; t++) cost[t] = 0; - - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - register UInt32 cost01, cost23, cost45; - register UInt16 icv; - cost01 = cost23 = cost45 = 0; - -# define BZ_ITER(nn) \ - icv = mtfv[gs+(nn)]; \ - cost01 += s->len_pack[icv][0]; \ - cost23 += s->len_pack[icv][1]; \ - cost45 += s->len_pack[icv][2]; \ - - BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); - BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); - BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); - BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); - BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); - BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); - BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); - BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); - BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); - BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); - -# undef BZ_ITER - - cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; - cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; - cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; - - } else { - /*--- slow version which correctly handles all situations ---*/ - for (i = gs; i <= ge; i++) { - UInt16 icv = mtfv[i]; - for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv]; - } - } - - /*-- - Find the coding table which is best for this group, - and record its identity in the selector table. - --*/ - bc = 999999999; bt = -1; - for (t = 0; t < nGroups; t++) - if (cost[t] < bc) { bc = cost[t]; bt = t; }; - totc += bc; - fave[bt]++; - s->selector[nSelectors] = bt; - nSelectors++; - - /*-- - Increment the symbol frequencies for the selected table. - --*/ - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - -# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++ - - BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); - BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); - BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); - BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); - BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); - BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); - BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); - BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); - BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); - BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); - -# undef BZ_ITUR - - } else { - /*--- slow version which correctly handles all situations ---*/ - for (i = gs; i <= ge; i++) - s->rfreq[bt][ mtfv[i] ]++; - } - - gs = ge+1; - } - if (s->verbosity >= 3) { - VPrintf2 ( " pass %d: size is %d, grp uses are ", - iter+1, totc/8 ); - for (t = 0; t < nGroups; t++) - VPrintf1 ( "%d ", fave[t] ); - VPrintf0 ( "\n" ); - } - - /*-- - Recompute the tables based on the accumulated frequencies. - --*/ - /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See - comment in huffman.c for details. */ - for (t = 0; t < nGroups; t++) - BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), - alphaSize, 17 /*20*/ ); - } - - - AssertH( nGroups < 8, 3002 ); - AssertH( nSelectors < 32768 && - nSelectors <= (2 + (900000 / BZ_G_SIZE)), - 3003 ); - - - /*--- Compute MTF values for the selectors. ---*/ - { - UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp; - for (i = 0; i < nGroups; i++) pos[i] = i; - for (i = 0; i < nSelectors; i++) { - ll_i = s->selector[i]; - j = 0; - tmp = pos[j]; - while ( ll_i != tmp ) { - j++; - tmp2 = tmp; - tmp = pos[j]; - pos[j] = tmp2; - }; - pos[0] = tmp; - s->selectorMtf[i] = j; - } - }; - - /*--- Assign actual codes for the tables. --*/ - for (t = 0; t < nGroups; t++) { - minLen = 32; - maxLen = 0; - for (i = 0; i < alphaSize; i++) { - if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; - if (s->len[t][i] < minLen) minLen = s->len[t][i]; - } - AssertH ( !(maxLen > 17 /*20*/ ), 3004 ); - AssertH ( !(minLen < 1), 3005 ); - BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), - minLen, maxLen, alphaSize ); - } - - /*--- Transmit the mapping table. ---*/ - { - Bool inUse16[16]; - for (i = 0; i < 16; i++) { - inUse16[i] = False; - for (j = 0; j < 16; j++) - if (s->inUse[i * 16 + j]) inUse16[i] = True; - } - - nBytes = s->numZ; - for (i = 0; i < 16; i++) - if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0); - - for (i = 0; i < 16; i++) - if (inUse16[i]) - for (j = 0; j < 16; j++) { - if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0); - } - - if (s->verbosity >= 3) - VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes ); - } - - /*--- Now the selectors. ---*/ - nBytes = s->numZ; - bsW ( s, 3, nGroups ); - bsW ( s, 15, nSelectors ); - for (i = 0; i < nSelectors; i++) { - for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1); - bsW(s,1,0); - } - if (s->verbosity >= 3) - VPrintf1( "selectors %d, ", s->numZ-nBytes ); - - /*--- Now the coding tables. ---*/ - nBytes = s->numZ; - - for (t = 0; t < nGroups; t++) { - Int32 curr = s->len[t][0]; - bsW ( s, 5, curr ); - for (i = 0; i < alphaSize; i++) { - while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ }; - while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ }; - bsW ( s, 1, 0 ); - } - } - - if (s->verbosity >= 3) - VPrintf1 ( "code lengths %d, ", s->numZ-nBytes ); - - /*--- And finally, the block data proper ---*/ - nBytes = s->numZ; - selCtr = 0; - gs = 0; - while (True) { - if (gs >= s->nMTF) break; - ge = gs + BZ_G_SIZE - 1; - if (ge >= s->nMTF) ge = s->nMTF-1; - AssertH ( s->selector[selCtr] < nGroups, 3006 ); - - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - UInt16 mtfv_i; - UChar* s_len_sel_selCtr - = &(s->len[s->selector[selCtr]][0]); - Int32* s_code_sel_selCtr - = &(s->code[s->selector[selCtr]][0]); - -# define BZ_ITAH(nn) \ - mtfv_i = mtfv[gs+(nn)]; \ - bsW ( s, \ - s_len_sel_selCtr[mtfv_i], \ - s_code_sel_selCtr[mtfv_i] ) - - BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); - BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); - BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); - BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); - BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); - BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); - BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); - BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); - BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); - BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); - -# undef BZ_ITAH - - } else { - /*--- slow version which correctly handles all situations ---*/ - for (i = gs; i <= ge; i++) { - bsW ( s, - s->len [s->selector[selCtr]] [mtfv[i]], - s->code [s->selector[selCtr]] [mtfv[i]] ); - } - } - - - gs = ge+1; - selCtr++; - } - AssertH( selCtr == nSelectors, 3007 ); - - if (s->verbosity >= 3) - VPrintf1( "codes %d\n", s->numZ-nBytes ); -} - - -/*---------------------------------------------------*/ -void BZ2_compressBlock ( EState* s, Bool is_last_block ) -{ - if (s->nblock > 0) { - - BZ_FINALISE_CRC ( s->blockCRC ); - s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); - s->combinedCRC ^= s->blockCRC; - if (s->blockNo > 1) s->numZ = 0; - - if (s->verbosity >= 2) - VPrintf4( " block %d: crc = 0x%08x, " - "combined CRC = 0x%08x, size = %d\n", - s->blockNo, s->blockCRC, s->combinedCRC, s->nblock ); - - BZ2_blockSort ( s ); - } - - s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]); - - /*-- If this is the first block, create the stream header. --*/ - if (s->blockNo == 1) { - BZ2_bsInitWrite ( s ); - bsPutUChar ( s, BZ_HDR_B ); - bsPutUChar ( s, BZ_HDR_Z ); - bsPutUChar ( s, BZ_HDR_h ); - bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) ); - } - - if (s->nblock > 0) { - - bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 ); - bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 ); - bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 ); - - /*-- Now the block's CRC, so it is in a known place. --*/ - bsPutUInt32 ( s, s->blockCRC ); - - /*-- - Now a single bit indicating (non-)randomisation. - As of version 0.9.5, we use a better sorting algorithm - which makes randomisation unnecessary. So always set - the randomised bit to 'no'. Of course, the decoder - still needs to be able to handle randomised blocks - so as to maintain backwards compatibility with - older versions of bzip2. - --*/ - bsW(s,1,0); - - bsW ( s, 24, s->origPtr ); - generateMTFValues ( s ); - sendMTFValues ( s ); - } - - - /*-- If this is the last block, add the stream trailer. --*/ - if (is_last_block) { - - bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 ); - bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 ); - bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 ); - bsPutUInt32 ( s, s->combinedCRC ); - if (s->verbosity >= 2) - VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC ); - bsFinishWrite ( s ); - } -} - - -/*-------------------------------------------------------------*/ -/*--- end compress.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Compression machinery (not incl block sorting) ---*/ +/*--- compress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +/* CHANGES + 0.9.0 -- original version. + 0.9.0a/b -- no changes in this file. + 0.9.0c -- changed setting of nGroups in sendMTFValues() + so as to do a bit better on small files +*/ + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Bit stream I/O ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +void BZ2_bsInitWrite ( EState* s ) +{ + s->bsLive = 0; + s->bsBuff = 0; +} + + +/*---------------------------------------------------*/ +static +void bsFinishWrite ( EState* s ) +{ + while (s->bsLive > 0) { + s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24); + s->numZ++; + s->bsBuff <<= 8; + s->bsLive -= 8; + } +} + + +/*---------------------------------------------------*/ +#define bsNEEDW(nz) \ +{ \ + while (s->bsLive >= 8) { \ + s->zbits[s->numZ] \ + = (UChar)(s->bsBuff >> 24); \ + s->numZ++; \ + s->bsBuff <<= 8; \ + s->bsLive -= 8; \ + } \ +} + + +/*---------------------------------------------------*/ +static +__inline__ +void bsW ( EState* s, Int32 n, UInt32 v ) +{ + bsNEEDW ( n ); + s->bsBuff |= (v << (32 - s->bsLive - n)); + s->bsLive += n; +} + + +/*---------------------------------------------------*/ +static +void bsPutUInt32 ( EState* s, UInt32 u ) +{ + bsW ( s, 8, (u >> 24) & 0xffL ); + bsW ( s, 8, (u >> 16) & 0xffL ); + bsW ( s, 8, (u >> 8) & 0xffL ); + bsW ( s, 8, u & 0xffL ); +} + + +/*---------------------------------------------------*/ +static +void bsPutUChar ( EState* s, UChar c ) +{ + bsW( s, 8, (UInt32)c ); +} + + +/*---------------------------------------------------*/ +/*--- The back end proper ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +static +void makeMaps_e ( EState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->unseqToSeq[i] = s->nInUse; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +static +void generateMTFValues ( EState* s ) +{ + UChar yy[256]; + Int32 i, j; + Int32 zPend; + Int32 wr; + Int32 EOB; + + /* + After sorting (eg, here), + s->arr1 [ 0 .. s->nblock-1 ] holds sorted order, + and + ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] + holds the original block data. + + The first thing to do is generate the MTF values, + and put them in + ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ]. + Because there are strictly fewer or equal MTF values + than block values, ptr values in this area are overwritten + with MTF values only when they are no longer needed. + + The final compressed bitstream is generated into the + area starting at + (UChar*) (&((UChar*)s->arr2)[s->nblock]) + + These storage aliases are set up in bzCompressInit(), + except for the last one, which is arranged in + compressBlock(). + */ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt16* mtfv = s->mtfv; + + makeMaps_e ( s ); + EOB = s->nInUse+1; + + for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0; + + wr = 0; + zPend = 0; + for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i; + + for (i = 0; i < s->nblock; i++) { + UChar ll_i; + AssertD ( wr <= i, "generateMTFValues(1)" ); + j = ptr[i]-1; if (j < 0) j += s->nblock; + ll_i = s->unseqToSeq[block[j]]; + AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" ); + + if (yy[0] == ll_i) { + zPend++; + } else { + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + { + register UChar rtmp; + register UChar* ryy_j; + register UChar rll_i; + rtmp = yy[1]; + yy[1] = yy[0]; + ryy_j = &(yy[1]); + rll_i = ll_i; + while ( rll_i != rtmp ) { + register UChar rtmp2; + ryy_j++; + rtmp2 = rtmp; + rtmp = *ryy_j; + *ryy_j = rtmp2; + }; + yy[0] = rtmp; + j = ryy_j - &(yy[0]); + mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++; + } + + } + } + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + + mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++; + + s->nMTF = wr; +} + + +/*---------------------------------------------------*/ +#define BZ_LESSER_ICOST 0 +#define BZ_GREATER_ICOST 15 + +static +void sendMTFValues ( EState* s ) +{ + Int32 v, t, i, j, gs, ge, totc, bt, bc, iter; + Int32 nSelectors, alphaSize, minLen, maxLen, selCtr; + Int32 nGroups, nBytes; + + /*-- + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + is a global since the decoder also needs it. + + Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + are also globals only used in this proc. + Made global to keep stack frame size small. + --*/ + + + UInt16 cost[BZ_N_GROUPS]; + Int32 fave[BZ_N_GROUPS]; + + UInt16* mtfv = s->mtfv; + + if (s->verbosity >= 3) + VPrintf3( " %d in block, %d after MTF & 1-2 coding, " + "%d+2 syms in use\n", + s->nblock, s->nMTF, s->nInUse ); + + alphaSize = s->nInUse+2; + for (t = 0; t < BZ_N_GROUPS; t++) + for (v = 0; v < alphaSize; v++) + s->len[t][v] = BZ_GREATER_ICOST; + + /*--- Decide how many coding tables to use ---*/ + AssertH ( s->nMTF > 0, 3001 ); + if (s->nMTF < 200) nGroups = 2; else + if (s->nMTF < 600) nGroups = 3; else + if (s->nMTF < 1200) nGroups = 4; else + if (s->nMTF < 2400) nGroups = 5; else + nGroups = 6; + + /*--- Generate an initial set of coding tables ---*/ + { + Int32 nPart, remF, tFreq, aFreq; + + nPart = nGroups; + remF = s->nMTF; + gs = 0; + while (nPart > 0) { + tFreq = remF / nPart; + ge = gs-1; + aFreq = 0; + while (aFreq < tFreq && ge < alphaSize-1) { + ge++; + aFreq += s->mtfFreq[ge]; + } + + if (ge > gs + && nPart != nGroups && nPart != 1 + && ((nGroups-nPart) % 2 == 1)) { + aFreq -= s->mtfFreq[ge]; + ge--; + } + + if (s->verbosity >= 3) + VPrintf5( " initial group %d, [%d .. %d], " + "has %d syms (%4.1f%%)\n", + nPart, gs, ge, aFreq, + (100.0 * (float)aFreq) / (float)(s->nMTF) ); + + for (v = 0; v < alphaSize; v++) + if (v >= gs && v <= ge) + s->len[nPart-1][v] = BZ_LESSER_ICOST; else + s->len[nPart-1][v] = BZ_GREATER_ICOST; + + nPart--; + gs = ge+1; + remF -= aFreq; + } + } + + /*--- + Iterate up to BZ_N_ITERS times to improve the tables. + ---*/ + for (iter = 0; iter < BZ_N_ITERS; iter++) { + + for (t = 0; t < nGroups; t++) fave[t] = 0; + + for (t = 0; t < nGroups; t++) + for (v = 0; v < alphaSize; v++) + s->rfreq[t][v] = 0; + + /*--- + Set up an auxiliary length table which is used to fast-track + the common case (nGroups == 6). + ---*/ + if (nGroups == 6) { + for (v = 0; v < alphaSize; v++) { + s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; + s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; + s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; + } + } + + nSelectors = 0; + totc = 0; + gs = 0; + while (True) { + + /*--- Set group start & end marks. --*/ + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + + /*-- + Calculate the cost of this group as coded + by each of the coding tables. + --*/ + for (t = 0; t < nGroups; t++) cost[t] = 0; + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + register UInt32 cost01, cost23, cost45; + register UInt16 icv; + cost01 = cost23 = cost45 = 0; + +# define BZ_ITER(nn) \ + icv = mtfv[gs+(nn)]; \ + cost01 += s->len_pack[icv][0]; \ + cost23 += s->len_pack[icv][1]; \ + cost45 += s->len_pack[icv][2]; \ + + BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); + BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); + BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); + BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); + BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); + BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); + BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); + BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); + BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); + BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); + +# undef BZ_ITER + + cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; + cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; + cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + UInt16 icv = mtfv[i]; + for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv]; + } + } + + /*-- + Find the coding table which is best for this group, + and record its identity in the selector table. + --*/ + bc = 999999999; bt = -1; + for (t = 0; t < nGroups; t++) + if (cost[t] < bc) { bc = cost[t]; bt = t; }; + totc += bc; + fave[bt]++; + s->selector[nSelectors] = bt; + nSelectors++; + + /*-- + Increment the symbol frequencies for the selected table. + --*/ + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + +# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++ + + BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); + BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); + BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); + BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); + BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); + BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); + BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); + BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); + BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); + BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); + +# undef BZ_ITUR + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) + s->rfreq[bt][ mtfv[i] ]++; + } + + gs = ge+1; + } + if (s->verbosity >= 3) { + VPrintf2 ( " pass %d: size is %d, grp uses are ", + iter+1, totc/8 ); + for (t = 0; t < nGroups; t++) + VPrintf1 ( "%d ", fave[t] ); + VPrintf0 ( "\n" ); + } + + /*-- + Recompute the tables based on the accumulated frequencies. + --*/ + /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See + comment in huffman.c for details. */ + for (t = 0; t < nGroups; t++) + BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), + alphaSize, 17 /*20*/ ); + } + + + AssertH( nGroups < 8, 3002 ); + AssertH( nSelectors < 32768 && + nSelectors <= (2 + (900000 / BZ_G_SIZE)), + 3003 ); + + + /*--- Compute MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp; + for (i = 0; i < nGroups; i++) pos[i] = i; + for (i = 0; i < nSelectors; i++) { + ll_i = s->selector[i]; + j = 0; + tmp = pos[j]; + while ( ll_i != tmp ) { + j++; + tmp2 = tmp; + tmp = pos[j]; + pos[j] = tmp2; + }; + pos[0] = tmp; + s->selectorMtf[i] = j; + } + }; + + /*--- Assign actual codes for the tables. --*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + AssertH ( !(maxLen > 17 /*20*/ ), 3004 ); + AssertH ( !(minLen < 1), 3005 ); + BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), + minLen, maxLen, alphaSize ); + } + + /*--- Transmit the mapping table. ---*/ + { + Bool inUse16[16]; + for (i = 0; i < 16; i++) { + inUse16[i] = False; + for (j = 0; j < 16; j++) + if (s->inUse[i * 16 + j]) inUse16[i] = True; + } + + nBytes = s->numZ; + for (i = 0; i < 16; i++) + if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0); + + for (i = 0; i < 16; i++) + if (inUse16[i]) + for (j = 0; j < 16; j++) { + if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0); + } + + if (s->verbosity >= 3) + VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes ); + } + + /*--- Now the selectors. ---*/ + nBytes = s->numZ; + bsW ( s, 3, nGroups ); + bsW ( s, 15, nSelectors ); + for (i = 0; i < nSelectors; i++) { + for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1); + bsW(s,1,0); + } + if (s->verbosity >= 3) + VPrintf1( "selectors %d, ", s->numZ-nBytes ); + + /*--- Now the coding tables. ---*/ + nBytes = s->numZ; + + for (t = 0; t < nGroups; t++) { + Int32 curr = s->len[t][0]; + bsW ( s, 5, curr ); + for (i = 0; i < alphaSize; i++) { + while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ }; + while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ }; + bsW ( s, 1, 0 ); + } + } + + if (s->verbosity >= 3) + VPrintf1 ( "code lengths %d, ", s->numZ-nBytes ); + + /*--- And finally, the block data proper ---*/ + nBytes = s->numZ; + selCtr = 0; + gs = 0; + while (True) { + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + AssertH ( s->selector[selCtr] < nGroups, 3006 ); + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + UInt16 mtfv_i; + UChar* s_len_sel_selCtr + = &(s->len[s->selector[selCtr]][0]); + Int32* s_code_sel_selCtr + = &(s->code[s->selector[selCtr]][0]); + +# define BZ_ITAH(nn) \ + mtfv_i = mtfv[gs+(nn)]; \ + bsW ( s, \ + s_len_sel_selCtr[mtfv_i], \ + s_code_sel_selCtr[mtfv_i] ) + + BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); + BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); + BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); + BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); + BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); + BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); + BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); + BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); + BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); + BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); + +# undef BZ_ITAH + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + bsW ( s, + s->len [s->selector[selCtr]] [mtfv[i]], + s->code [s->selector[selCtr]] [mtfv[i]] ); + } + } + + + gs = ge+1; + selCtr++; + } + AssertH( selCtr == nSelectors, 3007 ); + + if (s->verbosity >= 3) + VPrintf1( "codes %d\n", s->numZ-nBytes ); +} + + +/*---------------------------------------------------*/ +void BZ2_compressBlock ( EState* s, Bool is_last_block ) +{ + if (s->nblock > 0) { + + BZ_FINALISE_CRC ( s->blockCRC ); + s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); + s->combinedCRC ^= s->blockCRC; + if (s->blockNo > 1) s->numZ = 0; + + if (s->verbosity >= 2) + VPrintf4( " block %d: crc = 0x%08x, " + "combined CRC = 0x%08x, size = %d\n", + s->blockNo, s->blockCRC, s->combinedCRC, s->nblock ); + + BZ2_blockSort ( s ); + } + + s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]); + + /*-- If this is the first block, create the stream header. --*/ + if (s->blockNo == 1) { + BZ2_bsInitWrite ( s ); + bsPutUChar ( s, BZ_HDR_B ); + bsPutUChar ( s, BZ_HDR_Z ); + bsPutUChar ( s, BZ_HDR_h ); + bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) ); + } + + if (s->nblock > 0) { + + bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 ); + bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 ); + bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 ); + + /*-- Now the block's CRC, so it is in a known place. --*/ + bsPutUInt32 ( s, s->blockCRC ); + + /*-- + Now a single bit indicating (non-)randomisation. + As of version 0.9.5, we use a better sorting algorithm + which makes randomisation unnecessary. So always set + the randomised bit to 'no'. Of course, the decoder + still needs to be able to handle randomised blocks + so as to maintain backwards compatibility with + older versions of bzip2. + --*/ + bsW(s,1,0); + + bsW ( s, 24, s->origPtr ); + generateMTFValues ( s ); + sendMTFValues ( s ); + } + + + /*-- If this is the last block, add the stream trailer. --*/ + if (is_last_block) { + + bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 ); + bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 ); + bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 ); + bsPutUInt32 ( s, s->combinedCRC ); + if (s->verbosity >= 2) + VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC ); + bsFinishWrite ( s ); + } +} + + +/*-------------------------------------------------------------*/ +/*--- end compress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/crctable.c b/plugins/CDVDiso/src/3rdparty/bzip2/crctable.c index 5fd7cf6506..bc7e2ae39d 100644 --- a/plugins/CDVDiso/src/3rdparty/bzip2/crctable.c +++ b/plugins/CDVDiso/src/3rdparty/bzip2/crctable.c @@ -1,104 +1,104 @@ - -/*-------------------------------------------------------------*/ -/*--- Table for doing CRCs ---*/ -/*--- crctable.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.4 of 20 December 2006 - Copyright (C) 1996-2006 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - -/*-- - I think this is an implementation of the AUTODIN-II, - Ethernet & FDDI 32-bit CRC standard. Vaguely derived - from code by Rob Warnock, in Section 51 of the - comp.compression FAQ. ---*/ - -UInt32 BZ2_crc32Table[256] = { - - /*-- Ugly, innit? --*/ - - 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, - 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, - 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, - 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, - 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, - 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, - 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, - 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, - 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, - 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, - 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, - 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, - 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, - 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, - 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, - 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, - 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, - 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, - 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, - 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, - 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, - 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, - 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, - 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, - 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, - 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, - 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, - 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, - 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, - 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, - 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, - 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, - 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, - 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, - 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, - 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, - 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, - 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, - 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, - 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, - 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, - 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, - 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, - 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, - 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, - 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, - 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, - 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, - 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, - 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, - 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, - 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, - 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, - 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, - 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, - 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, - 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, - 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, - 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, - 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, - 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, - 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, - 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, - 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L -}; - - -/*-------------------------------------------------------------*/ -/*--- end crctable.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Table for doing CRCs ---*/ +/*--- crctable.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*-- + I think this is an implementation of the AUTODIN-II, + Ethernet & FDDI 32-bit CRC standard. Vaguely derived + from code by Rob Warnock, in Section 51 of the + comp.compression FAQ. +--*/ + +UInt32 BZ2_crc32Table[256] = { + + /*-- Ugly, innit? --*/ + + 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, + 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, + 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, + 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, + 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, + 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, + 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, + 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, + 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, + 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, + 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, + 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, + 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, + 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, + 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, + 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, + 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, + 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, + 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, + 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, + 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, + 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, + 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, + 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, + 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, + 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, + 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, + 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, + 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, + 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, + 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, + 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, + 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, + 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, + 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, + 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, + 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, + 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, + 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, + 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, + 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, + 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, + 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, + 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, + 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, + 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, + 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, + 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, + 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, + 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, + 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, + 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, + 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, + 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, + 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, + 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, + 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, + 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, + 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, + 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, + 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, + 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, + 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, + 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L +}; + + +/*-------------------------------------------------------------*/ +/*--- end crctable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/decompress.c b/plugins/CDVDiso/src/3rdparty/bzip2/decompress.c index 4aa7f53c0c..124cc8ddc7 100644 --- a/plugins/CDVDiso/src/3rdparty/bzip2/decompress.c +++ b/plugins/CDVDiso/src/3rdparty/bzip2/decompress.c @@ -1,626 +1,626 @@ - -/*-------------------------------------------------------------*/ -/*--- Decompression machinery ---*/ -/*--- decompress.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.4 of 20 December 2006 - Copyright (C) 1996-2006 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - - -/*---------------------------------------------------*/ -static -void makeMaps_d ( DState* s ) -{ - Int32 i; - s->nInUse = 0; - for (i = 0; i < 256; i++) - if (s->inUse[i]) { - s->seqToUnseq[s->nInUse] = i; - s->nInUse++; - } -} - - -/*---------------------------------------------------*/ -#define RETURN(rrr) \ - { retVal = rrr; goto save_state_and_return; }; - -#define GET_BITS(lll,vvv,nnn) \ - case lll: s->state = lll; \ - while (True) { \ - if (s->bsLive >= nnn) { \ - UInt32 v; \ - v = (s->bsBuff >> \ - (s->bsLive-nnn)) & ((1 << nnn)-1); \ - s->bsLive -= nnn; \ - vvv = v; \ - break; \ - } \ - if (s->strm->avail_in == 0) RETURN(BZ_OK); \ - s->bsBuff \ - = (s->bsBuff << 8) | \ - ((UInt32) \ - (*((UChar*)(s->strm->next_in)))); \ - s->bsLive += 8; \ - s->strm->next_in++; \ - s->strm->avail_in--; \ - s->strm->total_in_lo32++; \ - if (s->strm->total_in_lo32 == 0) \ - s->strm->total_in_hi32++; \ - } - -#define GET_UCHAR(lll,uuu) \ - GET_BITS(lll,uuu,8) - -#define GET_BIT(lll,uuu) \ - GET_BITS(lll,uuu,1) - -/*---------------------------------------------------*/ -#define GET_MTF_VAL(label1,label2,lval) \ -{ \ - if (groupPos == 0) { \ - groupNo++; \ - if (groupNo >= nSelectors) \ - RETURN(BZ_DATA_ERROR); \ - groupPos = BZ_G_SIZE; \ - gSel = s->selector[groupNo]; \ - gMinlen = s->minLens[gSel]; \ - gLimit = &(s->limit[gSel][0]); \ - gPerm = &(s->perm[gSel][0]); \ - gBase = &(s->base[gSel][0]); \ - } \ - groupPos--; \ - zn = gMinlen; \ - GET_BITS(label1, zvec, zn); \ - while (1) { \ - if (zn > 20 /* the longest code */) \ - RETURN(BZ_DATA_ERROR); \ - if (zvec <= gLimit[zn]) break; \ - zn++; \ - GET_BIT(label2, zj); \ - zvec = (zvec << 1) | zj; \ - }; \ - if (zvec - gBase[zn] < 0 \ - || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \ - RETURN(BZ_DATA_ERROR); \ - lval = gPerm[zvec - gBase[zn]]; \ -} - - -/*---------------------------------------------------*/ -Int32 BZ2_decompress ( DState* s ) -{ - UChar uc; - Int32 retVal; - Int32 minLen, maxLen; - bz_stream* strm = s->strm; - - /* stuff that needs to be saved/restored */ - Int32 i; - Int32 j; - Int32 t; - Int32 alphaSize; - Int32 nGroups; - Int32 nSelectors; - Int32 EOB; - Int32 groupNo; - Int32 groupPos; - Int32 nextSym; - Int32 nblockMAX; - Int32 nblock; - Int32 es; - Int32 N; - Int32 curr; - Int32 zt; - Int32 zn; - Int32 zvec; - Int32 zj; - Int32 gSel; - Int32 gMinlen; - Int32* gLimit; - Int32* gBase; - Int32* gPerm; - - if (s->state == BZ_X_MAGIC_1) { - /*initialise the save area*/ - s->save_i = 0; - s->save_j = 0; - s->save_t = 0; - s->save_alphaSize = 0; - s->save_nGroups = 0; - s->save_nSelectors = 0; - s->save_EOB = 0; - s->save_groupNo = 0; - s->save_groupPos = 0; - s->save_nextSym = 0; - s->save_nblockMAX = 0; - s->save_nblock = 0; - s->save_es = 0; - s->save_N = 0; - s->save_curr = 0; - s->save_zt = 0; - s->save_zn = 0; - s->save_zvec = 0; - s->save_zj = 0; - s->save_gSel = 0; - s->save_gMinlen = 0; - s->save_gLimit = NULL; - s->save_gBase = NULL; - s->save_gPerm = NULL; - } - - /*restore from the save area*/ - i = s->save_i; - j = s->save_j; - t = s->save_t; - alphaSize = s->save_alphaSize; - nGroups = s->save_nGroups; - nSelectors = s->save_nSelectors; - EOB = s->save_EOB; - groupNo = s->save_groupNo; - groupPos = s->save_groupPos; - nextSym = s->save_nextSym; - nblockMAX = s->save_nblockMAX; - nblock = s->save_nblock; - es = s->save_es; - N = s->save_N; - curr = s->save_curr; - zt = s->save_zt; - zn = s->save_zn; - zvec = s->save_zvec; - zj = s->save_zj; - gSel = s->save_gSel; - gMinlen = s->save_gMinlen; - gLimit = s->save_gLimit; - gBase = s->save_gBase; - gPerm = s->save_gPerm; - - retVal = BZ_OK; - - switch (s->state) { - - GET_UCHAR(BZ_X_MAGIC_1, uc); - if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC); - - GET_UCHAR(BZ_X_MAGIC_2, uc); - if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC); - - GET_UCHAR(BZ_X_MAGIC_3, uc) - if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC); - - GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8) - if (s->blockSize100k < (BZ_HDR_0 + 1) || - s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC); - s->blockSize100k -= BZ_HDR_0; - - if (s->smallDecompress) { - s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) ); - s->ll4 = BZALLOC( - ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) - ); - if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR); - } else { - s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) ); - if (s->tt == NULL) RETURN(BZ_MEM_ERROR); - } - - GET_UCHAR(BZ_X_BLKHDR_1, uc); - - if (uc == 0x17) goto endhdr_2; - if (uc != 0x31) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_2, uc); - if (uc != 0x41) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_3, uc); - if (uc != 0x59) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_4, uc); - if (uc != 0x26) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_5, uc); - if (uc != 0x53) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_6, uc); - if (uc != 0x59) RETURN(BZ_DATA_ERROR); - - s->currBlockNo++; - if (s->verbosity >= 2) - VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo ); - - s->storedBlockCRC = 0; - GET_UCHAR(BZ_X_BCRC_1, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_BCRC_2, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_BCRC_3, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_BCRC_4, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - - GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1); - - s->origPtr = 0; - GET_UCHAR(BZ_X_ORIGPTR_1, uc); - s->origPtr = (s->origPtr << 8) | ((Int32)uc); - GET_UCHAR(BZ_X_ORIGPTR_2, uc); - s->origPtr = (s->origPtr << 8) | ((Int32)uc); - GET_UCHAR(BZ_X_ORIGPTR_3, uc); - s->origPtr = (s->origPtr << 8) | ((Int32)uc); - - if (s->origPtr < 0) - RETURN(BZ_DATA_ERROR); - if (s->origPtr > 10 + 100000*s->blockSize100k) - RETURN(BZ_DATA_ERROR); - - /*--- Receive the mapping table ---*/ - for (i = 0; i < 16; i++) { - GET_BIT(BZ_X_MAPPING_1, uc); - if (uc == 1) - s->inUse16[i] = True; else - s->inUse16[i] = False; - } - - for (i = 0; i < 256; i++) s->inUse[i] = False; - - for (i = 0; i < 16; i++) - if (s->inUse16[i]) - for (j = 0; j < 16; j++) { - GET_BIT(BZ_X_MAPPING_2, uc); - if (uc == 1) s->inUse[i * 16 + j] = True; - } - makeMaps_d ( s ); - if (s->nInUse == 0) RETURN(BZ_DATA_ERROR); - alphaSize = s->nInUse+2; - - /*--- Now the selectors ---*/ - GET_BITS(BZ_X_SELECTOR_1, nGroups, 3); - if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR); - GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15); - if (nSelectors < 1) RETURN(BZ_DATA_ERROR); - for (i = 0; i < nSelectors; i++) { - j = 0; - while (True) { - GET_BIT(BZ_X_SELECTOR_3, uc); - if (uc == 0) break; - j++; - if (j >= nGroups) RETURN(BZ_DATA_ERROR); - } - s->selectorMtf[i] = j; - } - - /*--- Undo the MTF values for the selectors. ---*/ - { - UChar pos[BZ_N_GROUPS], tmp, v; - for (v = 0; v < nGroups; v++) pos[v] = v; - - for (i = 0; i < nSelectors; i++) { - v = s->selectorMtf[i]; - tmp = pos[v]; - while (v > 0) { pos[v] = pos[v-1]; v--; } - pos[0] = tmp; - s->selector[i] = tmp; - } - } - - /*--- Now the coding tables ---*/ - for (t = 0; t < nGroups; t++) { - GET_BITS(BZ_X_CODING_1, curr, 5); - for (i = 0; i < alphaSize; i++) { - while (True) { - if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR); - GET_BIT(BZ_X_CODING_2, uc); - if (uc == 0) break; - GET_BIT(BZ_X_CODING_3, uc); - if (uc == 0) curr++; else curr--; - } - s->len[t][i] = curr; - } - } - - /*--- Create the Huffman decoding tables ---*/ - for (t = 0; t < nGroups; t++) { - minLen = 32; - maxLen = 0; - for (i = 0; i < alphaSize; i++) { - if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; - if (s->len[t][i] < minLen) minLen = s->len[t][i]; - } - BZ2_hbCreateDecodeTables ( - &(s->limit[t][0]), - &(s->base[t][0]), - &(s->perm[t][0]), - &(s->len[t][0]), - minLen, maxLen, alphaSize - ); - s->minLens[t] = minLen; - } - - /*--- Now the MTF values ---*/ - - EOB = s->nInUse+1; - nblockMAX = 100000 * s->blockSize100k; - groupNo = -1; - groupPos = 0; - - for (i = 0; i <= 255; i++) s->unzftab[i] = 0; - - /*-- MTF init --*/ - { - Int32 ii, jj, kk; - kk = MTFA_SIZE-1; - for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) { - for (jj = MTFL_SIZE-1; jj >= 0; jj--) { - s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj); - kk--; - } - s->mtfbase[ii] = kk + 1; - } - } - /*-- end MTF init --*/ - - nblock = 0; - GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym); - - while (True) { - - if (nextSym == EOB) break; - - if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) { - - es = -1; - N = 1; - do { - if (nextSym == BZ_RUNA) es = es + (0+1) * N; else - if (nextSym == BZ_RUNB) es = es + (1+1) * N; - N = N * 2; - GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym); - } - while (nextSym == BZ_RUNA || nextSym == BZ_RUNB); - - es++; - uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ]; - s->unzftab[uc] += es; - - if (s->smallDecompress) - while (es > 0) { - if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); - s->ll16[nblock] = (UInt16)uc; - nblock++; - es--; - } - else - while (es > 0) { - if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); - s->tt[nblock] = (UInt32)uc; - nblock++; - es--; - }; - - continue; - - } else { - - if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); - - /*-- uc = MTF ( nextSym-1 ) --*/ - { - Int32 ii, jj, kk, pp, lno, off; - UInt32 nn; - nn = (UInt32)(nextSym - 1); - - if (nn < MTFL_SIZE) { - /* avoid general-case expense */ - pp = s->mtfbase[0]; - uc = s->mtfa[pp+nn]; - while (nn > 3) { - Int32 z = pp+nn; - s->mtfa[(z) ] = s->mtfa[(z)-1]; - s->mtfa[(z)-1] = s->mtfa[(z)-2]; - s->mtfa[(z)-2] = s->mtfa[(z)-3]; - s->mtfa[(z)-3] = s->mtfa[(z)-4]; - nn -= 4; - } - while (nn > 0) { - s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; - }; - s->mtfa[pp] = uc; - } else { - /* general case */ - lno = nn / MTFL_SIZE; - off = nn % MTFL_SIZE; - pp = s->mtfbase[lno] + off; - uc = s->mtfa[pp]; - while (pp > s->mtfbase[lno]) { - s->mtfa[pp] = s->mtfa[pp-1]; pp--; - }; - s->mtfbase[lno]++; - while (lno > 0) { - s->mtfbase[lno]--; - s->mtfa[s->mtfbase[lno]] - = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1]; - lno--; - } - s->mtfbase[0]--; - s->mtfa[s->mtfbase[0]] = uc; - if (s->mtfbase[0] == 0) { - kk = MTFA_SIZE-1; - for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) { - for (jj = MTFL_SIZE-1; jj >= 0; jj--) { - s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj]; - kk--; - } - s->mtfbase[ii] = kk + 1; - } - } - } - } - /*-- end uc = MTF ( nextSym-1 ) --*/ - - s->unzftab[s->seqToUnseq[uc]]++; - if (s->smallDecompress) - s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else - s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]); - nblock++; - - GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym); - continue; - } - } - - /* Now we know what nblock is, we can do a better sanity - check on s->origPtr. - */ - if (s->origPtr < 0 || s->origPtr >= nblock) - RETURN(BZ_DATA_ERROR); - - /*-- Set up cftab to facilitate generation of T^(-1) --*/ - s->cftab[0] = 0; - for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1]; - for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1]; - for (i = 0; i <= 256; i++) { - if (s->cftab[i] < 0 || s->cftab[i] > nblock) { - /* s->cftab[i] can legitimately be == nblock */ - RETURN(BZ_DATA_ERROR); - } - } - - s->state_out_len = 0; - s->state_out_ch = 0; - BZ_INITIALISE_CRC ( s->calculatedBlockCRC ); - s->state = BZ_X_OUTPUT; - if (s->verbosity >= 2) VPrintf0 ( "rt+rld" ); - - if (s->smallDecompress) { - - /*-- Make a copy of cftab, used in generation of T --*/ - for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i]; - - /*-- compute the T vector --*/ - for (i = 0; i < nblock; i++) { - uc = (UChar)(s->ll16[i]); - SET_LL(i, s->cftabCopy[uc]); - s->cftabCopy[uc]++; - } - - /*-- Compute T^(-1) by pointer reversal on T --*/ - i = s->origPtr; - j = GET_LL(i); - do { - Int32 tmp = GET_LL(j); - SET_LL(j, i); - i = j; - j = tmp; - } - while (i != s->origPtr); - - s->tPos = s->origPtr; - s->nblock_used = 0; - if (s->blockRandomised) { - BZ_RAND_INIT_MASK; - BZ_GET_SMALL(s->k0); s->nblock_used++; - BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; - } else { - BZ_GET_SMALL(s->k0); s->nblock_used++; - } - - } else { - - /*-- compute the T^(-1) vector --*/ - for (i = 0; i < nblock; i++) { - uc = (UChar)(s->tt[i] & 0xff); - s->tt[s->cftab[uc]] |= (i << 8); - s->cftab[uc]++; - } - - s->tPos = s->tt[s->origPtr] >> 8; - s->nblock_used = 0; - if (s->blockRandomised) { - BZ_RAND_INIT_MASK; - BZ_GET_FAST(s->k0); s->nblock_used++; - BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; - } else { - BZ_GET_FAST(s->k0); s->nblock_used++; - } - - } - - RETURN(BZ_OK); - - - - endhdr_2: - - GET_UCHAR(BZ_X_ENDHDR_2, uc); - if (uc != 0x72) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_3, uc); - if (uc != 0x45) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_4, uc); - if (uc != 0x38) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_5, uc); - if (uc != 0x50) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_6, uc); - if (uc != 0x90) RETURN(BZ_DATA_ERROR); - - s->storedCombinedCRC = 0; - GET_UCHAR(BZ_X_CCRC_1, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_CCRC_2, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_CCRC_3, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_CCRC_4, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - - s->state = BZ_X_IDLE; - RETURN(BZ_STREAM_END); - - default: AssertH ( False, 4001 ); - } - - AssertH ( False, 4002 ); - - save_state_and_return: - - s->save_i = i; - s->save_j = j; - s->save_t = t; - s->save_alphaSize = alphaSize; - s->save_nGroups = nGroups; - s->save_nSelectors = nSelectors; - s->save_EOB = EOB; - s->save_groupNo = groupNo; - s->save_groupPos = groupPos; - s->save_nextSym = nextSym; - s->save_nblockMAX = nblockMAX; - s->save_nblock = nblock; - s->save_es = es; - s->save_N = N; - s->save_curr = curr; - s->save_zt = zt; - s->save_zn = zn; - s->save_zvec = zvec; - s->save_zj = zj; - s->save_gSel = gSel; - s->save_gMinlen = gMinlen; - s->save_gLimit = gLimit; - s->save_gBase = gBase; - s->save_gPerm = gPerm; - - return retVal; -} - - -/*-------------------------------------------------------------*/ -/*--- end decompress.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Decompression machinery ---*/ +/*--- decompress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +static +void makeMaps_d ( DState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->seqToUnseq[s->nInUse] = i; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +#define RETURN(rrr) \ + { retVal = rrr; goto save_state_and_return; }; + +#define GET_BITS(lll,vvv,nnn) \ + case lll: s->state = lll; \ + while (True) { \ + if (s->bsLive >= nnn) { \ + UInt32 v; \ + v = (s->bsBuff >> \ + (s->bsLive-nnn)) & ((1 << nnn)-1); \ + s->bsLive -= nnn; \ + vvv = v; \ + break; \ + } \ + if (s->strm->avail_in == 0) RETURN(BZ_OK); \ + s->bsBuff \ + = (s->bsBuff << 8) | \ + ((UInt32) \ + (*((UChar*)(s->strm->next_in)))); \ + s->bsLive += 8; \ + s->strm->next_in++; \ + s->strm->avail_in--; \ + s->strm->total_in_lo32++; \ + if (s->strm->total_in_lo32 == 0) \ + s->strm->total_in_hi32++; \ + } + +#define GET_UCHAR(lll,uuu) \ + GET_BITS(lll,uuu,8) + +#define GET_BIT(lll,uuu) \ + GET_BITS(lll,uuu,1) + +/*---------------------------------------------------*/ +#define GET_MTF_VAL(label1,label2,lval) \ +{ \ + if (groupPos == 0) { \ + groupNo++; \ + if (groupNo >= nSelectors) \ + RETURN(BZ_DATA_ERROR); \ + groupPos = BZ_G_SIZE; \ + gSel = s->selector[groupNo]; \ + gMinlen = s->minLens[gSel]; \ + gLimit = &(s->limit[gSel][0]); \ + gPerm = &(s->perm[gSel][0]); \ + gBase = &(s->base[gSel][0]); \ + } \ + groupPos--; \ + zn = gMinlen; \ + GET_BITS(label1, zvec, zn); \ + while (1) { \ + if (zn > 20 /* the longest code */) \ + RETURN(BZ_DATA_ERROR); \ + if (zvec <= gLimit[zn]) break; \ + zn++; \ + GET_BIT(label2, zj); \ + zvec = (zvec << 1) | zj; \ + }; \ + if (zvec - gBase[zn] < 0 \ + || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \ + RETURN(BZ_DATA_ERROR); \ + lval = gPerm[zvec - gBase[zn]]; \ +} + + +/*---------------------------------------------------*/ +Int32 BZ2_decompress ( DState* s ) +{ + UChar uc; + Int32 retVal; + Int32 minLen, maxLen; + bz_stream* strm = s->strm; + + /* stuff that needs to be saved/restored */ + Int32 i; + Int32 j; + Int32 t; + Int32 alphaSize; + Int32 nGroups; + Int32 nSelectors; + Int32 EOB; + Int32 groupNo; + Int32 groupPos; + Int32 nextSym; + Int32 nblockMAX; + Int32 nblock; + Int32 es; + Int32 N; + Int32 curr; + Int32 zt; + Int32 zn; + Int32 zvec; + Int32 zj; + Int32 gSel; + Int32 gMinlen; + Int32* gLimit; + Int32* gBase; + Int32* gPerm; + + if (s->state == BZ_X_MAGIC_1) { + /*initialise the save area*/ + s->save_i = 0; + s->save_j = 0; + s->save_t = 0; + s->save_alphaSize = 0; + s->save_nGroups = 0; + s->save_nSelectors = 0; + s->save_EOB = 0; + s->save_groupNo = 0; + s->save_groupPos = 0; + s->save_nextSym = 0; + s->save_nblockMAX = 0; + s->save_nblock = 0; + s->save_es = 0; + s->save_N = 0; + s->save_curr = 0; + s->save_zt = 0; + s->save_zn = 0; + s->save_zvec = 0; + s->save_zj = 0; + s->save_gSel = 0; + s->save_gMinlen = 0; + s->save_gLimit = NULL; + s->save_gBase = NULL; + s->save_gPerm = NULL; + } + + /*restore from the save area*/ + i = s->save_i; + j = s->save_j; + t = s->save_t; + alphaSize = s->save_alphaSize; + nGroups = s->save_nGroups; + nSelectors = s->save_nSelectors; + EOB = s->save_EOB; + groupNo = s->save_groupNo; + groupPos = s->save_groupPos; + nextSym = s->save_nextSym; + nblockMAX = s->save_nblockMAX; + nblock = s->save_nblock; + es = s->save_es; + N = s->save_N; + curr = s->save_curr; + zt = s->save_zt; + zn = s->save_zn; + zvec = s->save_zvec; + zj = s->save_zj; + gSel = s->save_gSel; + gMinlen = s->save_gMinlen; + gLimit = s->save_gLimit; + gBase = s->save_gBase; + gPerm = s->save_gPerm; + + retVal = BZ_OK; + + switch (s->state) { + + GET_UCHAR(BZ_X_MAGIC_1, uc); + if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_2, uc); + if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_3, uc) + if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8) + if (s->blockSize100k < (BZ_HDR_0 + 1) || + s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC); + s->blockSize100k -= BZ_HDR_0; + + if (s->smallDecompress) { + s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) ); + s->ll4 = BZALLOC( + ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) + ); + if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR); + } else { + s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) ); + if (s->tt == NULL) RETURN(BZ_MEM_ERROR); + } + + GET_UCHAR(BZ_X_BLKHDR_1, uc); + + if (uc == 0x17) goto endhdr_2; + if (uc != 0x31) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_2, uc); + if (uc != 0x41) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_3, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_4, uc); + if (uc != 0x26) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_5, uc); + if (uc != 0x53) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_6, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + + s->currBlockNo++; + if (s->verbosity >= 2) + VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo ); + + s->storedBlockCRC = 0; + GET_UCHAR(BZ_X_BCRC_1, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_2, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_3, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_4, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + + GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1); + + s->origPtr = 0; + GET_UCHAR(BZ_X_ORIGPTR_1, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_2, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_3, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + + if (s->origPtr < 0) + RETURN(BZ_DATA_ERROR); + if (s->origPtr > 10 + 100000*s->blockSize100k) + RETURN(BZ_DATA_ERROR); + + /*--- Receive the mapping table ---*/ + for (i = 0; i < 16; i++) { + GET_BIT(BZ_X_MAPPING_1, uc); + if (uc == 1) + s->inUse16[i] = True; else + s->inUse16[i] = False; + } + + for (i = 0; i < 256; i++) s->inUse[i] = False; + + for (i = 0; i < 16; i++) + if (s->inUse16[i]) + for (j = 0; j < 16; j++) { + GET_BIT(BZ_X_MAPPING_2, uc); + if (uc == 1) s->inUse[i * 16 + j] = True; + } + makeMaps_d ( s ); + if (s->nInUse == 0) RETURN(BZ_DATA_ERROR); + alphaSize = s->nInUse+2; + + /*--- Now the selectors ---*/ + GET_BITS(BZ_X_SELECTOR_1, nGroups, 3); + if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR); + GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15); + if (nSelectors < 1) RETURN(BZ_DATA_ERROR); + for (i = 0; i < nSelectors; i++) { + j = 0; + while (True) { + GET_BIT(BZ_X_SELECTOR_3, uc); + if (uc == 0) break; + j++; + if (j >= nGroups) RETURN(BZ_DATA_ERROR); + } + s->selectorMtf[i] = j; + } + + /*--- Undo the MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], tmp, v; + for (v = 0; v < nGroups; v++) pos[v] = v; + + for (i = 0; i < nSelectors; i++) { + v = s->selectorMtf[i]; + tmp = pos[v]; + while (v > 0) { pos[v] = pos[v-1]; v--; } + pos[0] = tmp; + s->selector[i] = tmp; + } + } + + /*--- Now the coding tables ---*/ + for (t = 0; t < nGroups; t++) { + GET_BITS(BZ_X_CODING_1, curr, 5); + for (i = 0; i < alphaSize; i++) { + while (True) { + if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR); + GET_BIT(BZ_X_CODING_2, uc); + if (uc == 0) break; + GET_BIT(BZ_X_CODING_3, uc); + if (uc == 0) curr++; else curr--; + } + s->len[t][i] = curr; + } + } + + /*--- Create the Huffman decoding tables ---*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + BZ2_hbCreateDecodeTables ( + &(s->limit[t][0]), + &(s->base[t][0]), + &(s->perm[t][0]), + &(s->len[t][0]), + minLen, maxLen, alphaSize + ); + s->minLens[t] = minLen; + } + + /*--- Now the MTF values ---*/ + + EOB = s->nInUse+1; + nblockMAX = 100000 * s->blockSize100k; + groupNo = -1; + groupPos = 0; + + for (i = 0; i <= 255; i++) s->unzftab[i] = 0; + + /*-- MTF init --*/ + { + Int32 ii, jj, kk; + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj); + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + /*-- end MTF init --*/ + + nblock = 0; + GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym); + + while (True) { + + if (nextSym == EOB) break; + + if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) { + + es = -1; + N = 1; + do { + if (nextSym == BZ_RUNA) es = es + (0+1) * N; else + if (nextSym == BZ_RUNB) es = es + (1+1) * N; + N = N * 2; + GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym); + } + while (nextSym == BZ_RUNA || nextSym == BZ_RUNB); + + es++; + uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ]; + s->unzftab[uc] += es; + + if (s->smallDecompress) + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->ll16[nblock] = (UInt16)uc; + nblock++; + es--; + } + else + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->tt[nblock] = (UInt32)uc; + nblock++; + es--; + }; + + continue; + + } else { + + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + + /*-- uc = MTF ( nextSym-1 ) --*/ + { + Int32 ii, jj, kk, pp, lno, off; + UInt32 nn; + nn = (UInt32)(nextSym - 1); + + if (nn < MTFL_SIZE) { + /* avoid general-case expense */ + pp = s->mtfbase[0]; + uc = s->mtfa[pp+nn]; + while (nn > 3) { + Int32 z = pp+nn; + s->mtfa[(z) ] = s->mtfa[(z)-1]; + s->mtfa[(z)-1] = s->mtfa[(z)-2]; + s->mtfa[(z)-2] = s->mtfa[(z)-3]; + s->mtfa[(z)-3] = s->mtfa[(z)-4]; + nn -= 4; + } + while (nn > 0) { + s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; + }; + s->mtfa[pp] = uc; + } else { + /* general case */ + lno = nn / MTFL_SIZE; + off = nn % MTFL_SIZE; + pp = s->mtfbase[lno] + off; + uc = s->mtfa[pp]; + while (pp > s->mtfbase[lno]) { + s->mtfa[pp] = s->mtfa[pp-1]; pp--; + }; + s->mtfbase[lno]++; + while (lno > 0) { + s->mtfbase[lno]--; + s->mtfa[s->mtfbase[lno]] + = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1]; + lno--; + } + s->mtfbase[0]--; + s->mtfa[s->mtfbase[0]] = uc; + if (s->mtfbase[0] == 0) { + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj]; + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + } + } + /*-- end uc = MTF ( nextSym-1 ) --*/ + + s->unzftab[s->seqToUnseq[uc]]++; + if (s->smallDecompress) + s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else + s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]); + nblock++; + + GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym); + continue; + } + } + + /* Now we know what nblock is, we can do a better sanity + check on s->origPtr. + */ + if (s->origPtr < 0 || s->origPtr >= nblock) + RETURN(BZ_DATA_ERROR); + + /*-- Set up cftab to facilitate generation of T^(-1) --*/ + s->cftab[0] = 0; + for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1]; + for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1]; + for (i = 0; i <= 256; i++) { + if (s->cftab[i] < 0 || s->cftab[i] > nblock) { + /* s->cftab[i] can legitimately be == nblock */ + RETURN(BZ_DATA_ERROR); + } + } + + s->state_out_len = 0; + s->state_out_ch = 0; + BZ_INITIALISE_CRC ( s->calculatedBlockCRC ); + s->state = BZ_X_OUTPUT; + if (s->verbosity >= 2) VPrintf0 ( "rt+rld" ); + + if (s->smallDecompress) { + + /*-- Make a copy of cftab, used in generation of T --*/ + for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i]; + + /*-- compute the T vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->ll16[i]); + SET_LL(i, s->cftabCopy[uc]); + s->cftabCopy[uc]++; + } + + /*-- Compute T^(-1) by pointer reversal on T --*/ + i = s->origPtr; + j = GET_LL(i); + do { + Int32 tmp = GET_LL(j); + SET_LL(j, i); + i = j; + j = tmp; + } + while (i != s->origPtr); + + s->tPos = s->origPtr; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_SMALL(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } else { + + /*-- compute the T^(-1) vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->tt[i] & 0xff); + s->tt[s->cftab[uc]] |= (i << 8); + s->cftab[uc]++; + } + + s->tPos = s->tt[s->origPtr] >> 8; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_FAST(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_FAST(s->k0); s->nblock_used++; + } + + } + + RETURN(BZ_OK); + + + + endhdr_2: + + GET_UCHAR(BZ_X_ENDHDR_2, uc); + if (uc != 0x72) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_3, uc); + if (uc != 0x45) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_4, uc); + if (uc != 0x38) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_5, uc); + if (uc != 0x50) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_6, uc); + if (uc != 0x90) RETURN(BZ_DATA_ERROR); + + s->storedCombinedCRC = 0; + GET_UCHAR(BZ_X_CCRC_1, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_2, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_3, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_4, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + + s->state = BZ_X_IDLE; + RETURN(BZ_STREAM_END); + + default: AssertH ( False, 4001 ); + } + + AssertH ( False, 4002 ); + + save_state_and_return: + + s->save_i = i; + s->save_j = j; + s->save_t = t; + s->save_alphaSize = alphaSize; + s->save_nGroups = nGroups; + s->save_nSelectors = nSelectors; + s->save_EOB = EOB; + s->save_groupNo = groupNo; + s->save_groupPos = groupPos; + s->save_nextSym = nextSym; + s->save_nblockMAX = nblockMAX; + s->save_nblock = nblock; + s->save_es = es; + s->save_N = N; + s->save_curr = curr; + s->save_zt = zt; + s->save_zn = zn; + s->save_zvec = zvec; + s->save_zj = zj; + s->save_gSel = gSel; + s->save_gMinlen = gMinlen; + s->save_gLimit = gLimit; + s->save_gBase = gBase; + s->save_gPerm = gPerm; + + return retVal; +} + + +/*-------------------------------------------------------------*/ +/*--- end decompress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/huffman.c b/plugins/CDVDiso/src/3rdparty/bzip2/huffman.c index 00066bd0ab..be4dc024dc 100644 --- a/plugins/CDVDiso/src/3rdparty/bzip2/huffman.c +++ b/plugins/CDVDiso/src/3rdparty/bzip2/huffman.c @@ -1,205 +1,205 @@ - -/*-------------------------------------------------------------*/ -/*--- Huffman coding low-level stuff ---*/ -/*--- huffman.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.4 of 20 December 2006 - Copyright (C) 1996-2006 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - -/*---------------------------------------------------*/ -#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) -#define DEPTHOF(zz1) ((zz1) & 0x000000ff) -#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) - -#define ADDWEIGHTS(zw1,zw2) \ - (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ - (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) - -#define UPHEAP(z) \ -{ \ - Int32 zz, tmp; \ - zz = z; tmp = heap[zz]; \ - while (weight[tmp] < weight[heap[zz >> 1]]) { \ - heap[zz] = heap[zz >> 1]; \ - zz >>= 1; \ - } \ - heap[zz] = tmp; \ -} - -#define DOWNHEAP(z) \ -{ \ - Int32 zz, yy, tmp; \ - zz = z; tmp = heap[zz]; \ - while (True) { \ - yy = zz << 1; \ - if (yy > nHeap) break; \ - if (yy < nHeap && \ - weight[heap[yy+1]] < weight[heap[yy]]) \ - yy++; \ - if (weight[tmp] < weight[heap[yy]]) break; \ - heap[zz] = heap[yy]; \ - zz = yy; \ - } \ - heap[zz] = tmp; \ -} - - -/*---------------------------------------------------*/ -void BZ2_hbMakeCodeLengths ( UChar *len, - Int32 *freq, - Int32 alphaSize, - Int32 maxLen ) -{ - /*-- - Nodes and heap entries run from 1. Entry 0 - for both the heap and nodes is a sentinel. - --*/ - Int32 nNodes, nHeap, n1, n2, i, j, k; - Bool tooLong; - - Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ]; - Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ]; - Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; - - for (i = 0; i < alphaSize; i++) - weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; - - while (True) { - - nNodes = alphaSize; - nHeap = 0; - - heap[0] = 0; - weight[0] = 0; - parent[0] = -2; - - for (i = 1; i <= alphaSize; i++) { - parent[i] = -1; - nHeap++; - heap[nHeap] = i; - UPHEAP(nHeap); - } - - AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 ); - - while (nHeap > 1) { - n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); - n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); - nNodes++; - parent[n1] = parent[n2] = nNodes; - weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); - parent[nNodes] = -1; - nHeap++; - heap[nHeap] = nNodes; - UPHEAP(nHeap); - } - - AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 ); - - tooLong = False; - for (i = 1; i <= alphaSize; i++) { - j = 0; - k = i; - while (parent[k] >= 0) { k = parent[k]; j++; } - len[i-1] = j; - if (j > maxLen) tooLong = True; - } - - if (! tooLong) break; - - /* 17 Oct 04: keep-going condition for the following loop used - to be 'i < alphaSize', which missed the last element, - theoretically leading to the possibility of the compressor - looping. However, this count-scaling step is only needed if - one of the generated Huffman code words is longer than - maxLen, which up to and including version 1.0.2 was 20 bits, - which is extremely unlikely. In version 1.0.3 maxLen was - changed to 17 bits, which has minimal effect on compression - ratio, but does mean this scaling step is used from time to - time, enough to verify that it works. - - This means that bzip2-1.0.3 and later will only produce - Huffman codes with a maximum length of 17 bits. However, in - order to preserve backwards compatibility with bitstreams - produced by versions pre-1.0.3, the decompressor must still - handle lengths of up to 20. */ - - for (i = 1; i <= alphaSize; i++) { - j = weight[i] >> 8; - j = 1 + (j / 2); - weight[i] = j << 8; - } - } -} - - -/*---------------------------------------------------*/ -void BZ2_hbAssignCodes ( Int32 *code, - UChar *length, - Int32 minLen, - Int32 maxLen, - Int32 alphaSize ) -{ - Int32 n, vec, i; - - vec = 0; - for (n = minLen; n <= maxLen; n++) { - for (i = 0; i < alphaSize; i++) - if (length[i] == n) { code[i] = vec; vec++; }; - vec <<= 1; - } -} - - -/*---------------------------------------------------*/ -void BZ2_hbCreateDecodeTables ( Int32 *limit, - Int32 *base, - Int32 *perm, - UChar *length, - Int32 minLen, - Int32 maxLen, - Int32 alphaSize ) -{ - Int32 pp, i, j, vec; - - pp = 0; - for (i = minLen; i <= maxLen; i++) - for (j = 0; j < alphaSize; j++) - if (length[j] == i) { perm[pp] = j; pp++; }; - - for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0; - for (i = 0; i < alphaSize; i++) base[length[i]+1]++; - - for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1]; - - for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0; - vec = 0; - - for (i = minLen; i <= maxLen; i++) { - vec += (base[i+1] - base[i]); - limit[i] = vec-1; - vec <<= 1; - } - for (i = minLen + 1; i <= maxLen; i++) - base[i] = ((limit[i-1] + 1) << 1) - base[i]; -} - - -/*-------------------------------------------------------------*/ -/*--- end huffman.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Huffman coding low-level stuff ---*/ +/*--- huffman.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*---------------------------------------------------*/ +#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) +#define DEPTHOF(zz1) ((zz1) & 0x000000ff) +#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) + +#define ADDWEIGHTS(zw1,zw2) \ + (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ + (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) + +#define UPHEAP(z) \ +{ \ + Int32 zz, tmp; \ + zz = z; tmp = heap[zz]; \ + while (weight[tmp] < weight[heap[zz >> 1]]) { \ + heap[zz] = heap[zz >> 1]; \ + zz >>= 1; \ + } \ + heap[zz] = tmp; \ +} + +#define DOWNHEAP(z) \ +{ \ + Int32 zz, yy, tmp; \ + zz = z; tmp = heap[zz]; \ + while (True) { \ + yy = zz << 1; \ + if (yy > nHeap) break; \ + if (yy < nHeap && \ + weight[heap[yy+1]] < weight[heap[yy]]) \ + yy++; \ + if (weight[tmp] < weight[heap[yy]]) break; \ + heap[zz] = heap[yy]; \ + zz = yy; \ + } \ + heap[zz] = tmp; \ +} + + +/*---------------------------------------------------*/ +void BZ2_hbMakeCodeLengths ( UChar *len, + Int32 *freq, + Int32 alphaSize, + Int32 maxLen ) +{ + /*-- + Nodes and heap entries run from 1. Entry 0 + for both the heap and nodes is a sentinel. + --*/ + Int32 nNodes, nHeap, n1, n2, i, j, k; + Bool tooLong; + + Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ]; + Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ]; + Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; + + for (i = 0; i < alphaSize; i++) + weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; + + while (True) { + + nNodes = alphaSize; + nHeap = 0; + + heap[0] = 0; + weight[0] = 0; + parent[0] = -2; + + for (i = 1; i <= alphaSize; i++) { + parent[i] = -1; + nHeap++; + heap[nHeap] = i; + UPHEAP(nHeap); + } + + AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 ); + + while (nHeap > 1) { + n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + nNodes++; + parent[n1] = parent[n2] = nNodes; + weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); + parent[nNodes] = -1; + nHeap++; + heap[nHeap] = nNodes; + UPHEAP(nHeap); + } + + AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 ); + + tooLong = False; + for (i = 1; i <= alphaSize; i++) { + j = 0; + k = i; + while (parent[k] >= 0) { k = parent[k]; j++; } + len[i-1] = j; + if (j > maxLen) tooLong = True; + } + + if (! tooLong) break; + + /* 17 Oct 04: keep-going condition for the following loop used + to be 'i < alphaSize', which missed the last element, + theoretically leading to the possibility of the compressor + looping. However, this count-scaling step is only needed if + one of the generated Huffman code words is longer than + maxLen, which up to and including version 1.0.2 was 20 bits, + which is extremely unlikely. In version 1.0.3 maxLen was + changed to 17 bits, which has minimal effect on compression + ratio, but does mean this scaling step is used from time to + time, enough to verify that it works. + + This means that bzip2-1.0.3 and later will only produce + Huffman codes with a maximum length of 17 bits. However, in + order to preserve backwards compatibility with bitstreams + produced by versions pre-1.0.3, the decompressor must still + handle lengths of up to 20. */ + + for (i = 1; i <= alphaSize; i++) { + j = weight[i] >> 8; + j = 1 + (j / 2); + weight[i] = j << 8; + } + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbAssignCodes ( Int32 *code, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 n, vec, i; + + vec = 0; + for (n = minLen; n <= maxLen; n++) { + for (i = 0; i < alphaSize; i++) + if (length[i] == n) { code[i] = vec; vec++; }; + vec <<= 1; + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbCreateDecodeTables ( Int32 *limit, + Int32 *base, + Int32 *perm, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 pp, i, j, vec; + + pp = 0; + for (i = minLen; i <= maxLen; i++) + for (j = 0; j < alphaSize; j++) + if (length[j] == i) { perm[pp] = j; pp++; }; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0; + for (i = 0; i < alphaSize; i++) base[length[i]+1]++; + + for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1]; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0; + vec = 0; + + for (i = minLen; i <= maxLen; i++) { + vec += (base[i+1] - base[i]); + limit[i] = vec-1; + vec <<= 1; + } + for (i = minLen + 1; i <= maxLen; i++) + base[i] = ((limit[i-1] + 1) << 1) - base[i]; +} + + +/*-------------------------------------------------------------*/ +/*--- end huffman.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/randtable.c b/plugins/CDVDiso/src/3rdparty/bzip2/randtable.c index 87a2f05012..d186335e0e 100644 --- a/plugins/CDVDiso/src/3rdparty/bzip2/randtable.c +++ b/plugins/CDVDiso/src/3rdparty/bzip2/randtable.c @@ -1,84 +1,84 @@ - -/*-------------------------------------------------------------*/ -/*--- Table for randomising repetitive blocks ---*/ -/*--- randtable.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.4 of 20 December 2006 - Copyright (C) 1996-2006 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - - -/*---------------------------------------------*/ -Int32 BZ2_rNums[512] = { - 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, - 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, - 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, - 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, - 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, - 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, - 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, - 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, - 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, - 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, - 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, - 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, - 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, - 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, - 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, - 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, - 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, - 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, - 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, - 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, - 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, - 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, - 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, - 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, - 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, - 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, - 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, - 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, - 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, - 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, - 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, - 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, - 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, - 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, - 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, - 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, - 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, - 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, - 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, - 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, - 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, - 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, - 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, - 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, - 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, - 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, - 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, - 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, - 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, - 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, - 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, - 936, 638 -}; - - -/*-------------------------------------------------------------*/ -/*--- end randtable.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Table for randomising repetitive blocks ---*/ +/*--- randtable.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + + +/*---------------------------------------------*/ +Int32 BZ2_rNums[512] = { + 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, + 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, + 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, + 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, + 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, + 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, + 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, + 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, + 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, + 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, + 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, + 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, + 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, + 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, + 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, + 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, + 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, + 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, + 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, + 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, + 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, + 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, + 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, + 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, + 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, + 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, + 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, + 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, + 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, + 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, + 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, + 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, + 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, + 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, + 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, + 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, + 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, + 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, + 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, + 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, + 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, + 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, + 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, + 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, + 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, + 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, + 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, + 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, + 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, + 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, + 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, + 936, 638 +}; + + +/*-------------------------------------------------------------*/ +/*--- end randtable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDiso/src/3rdparty/zlib/adler32.c b/plugins/CDVDiso/src/3rdparty/zlib/adler32.c index f201d6701e..007ba26277 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/adler32.c +++ b/plugins/CDVDiso/src/3rdparty/zlib/adler32.c @@ -1,149 +1,149 @@ -/* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2004 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -#define BASE 65521UL /* largest prime smaller than 65536 */ -#define NMAX 5552 -/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ - -#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} -#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); -#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); -#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); -#define DO16(buf) DO8(buf,0); DO8(buf,8); - -/* use NO_DIVIDE if your processor does not do division in hardware */ -#ifdef NO_DIVIDE -# define MOD(a) \ - do { \ - if (a >= (BASE << 16)) a -= (BASE << 16); \ - if (a >= (BASE << 15)) a -= (BASE << 15); \ - if (a >= (BASE << 14)) a -= (BASE << 14); \ - if (a >= (BASE << 13)) a -= (BASE << 13); \ - if (a >= (BASE << 12)) a -= (BASE << 12); \ - if (a >= (BASE << 11)) a -= (BASE << 11); \ - if (a >= (BASE << 10)) a -= (BASE << 10); \ - if (a >= (BASE << 9)) a -= (BASE << 9); \ - if (a >= (BASE << 8)) a -= (BASE << 8); \ - if (a >= (BASE << 7)) a -= (BASE << 7); \ - if (a >= (BASE << 6)) a -= (BASE << 6); \ - if (a >= (BASE << 5)) a -= (BASE << 5); \ - if (a >= (BASE << 4)) a -= (BASE << 4); \ - if (a >= (BASE << 3)) a -= (BASE << 3); \ - if (a >= (BASE << 2)) a -= (BASE << 2); \ - if (a >= (BASE << 1)) a -= (BASE << 1); \ - if (a >= BASE) a -= BASE; \ - } while (0) -# define MOD4(a) \ - do { \ - if (a >= (BASE << 4)) a -= (BASE << 4); \ - if (a >= (BASE << 3)) a -= (BASE << 3); \ - if (a >= (BASE << 2)) a -= (BASE << 2); \ - if (a >= (BASE << 1)) a -= (BASE << 1); \ - if (a >= BASE) a -= BASE; \ - } while (0) -#else -# define MOD(a) a %= BASE -# define MOD4(a) a %= BASE -#endif - -/* ========================================================================= */ -uLong ZEXPORT adler32(adler, buf, len) - uLong adler; - const Bytef *buf; - uInt len; -{ - unsigned long sum2; - unsigned n; - - /* split Adler-32 into component sums */ - sum2 = (adler >> 16) & 0xffff; - adler &= 0xffff; - - /* in case user likes doing a byte at a time, keep it fast */ - if (len == 1) { - adler += buf[0]; - if (adler >= BASE) - adler -= BASE; - sum2 += adler; - if (sum2 >= BASE) - sum2 -= BASE; - return adler | (sum2 << 16); - } - - /* initial Adler-32 value (deferred check for len == 1 speed) */ - if (buf == Z_NULL) - return 1L; - - /* in case short lengths are provided, keep it somewhat fast */ - if (len < 16) { - while (len--) { - adler += *buf++; - sum2 += adler; - } - if (adler >= BASE) - adler -= BASE; - MOD4(sum2); /* only added so many BASE's */ - return adler | (sum2 << 16); - } - - /* do length NMAX blocks -- requires just one modulo operation */ - while (len >= NMAX) { - len -= NMAX; - n = NMAX / 16; /* NMAX is divisible by 16 */ - do { - DO16(buf); /* 16 sums unrolled */ - buf += 16; - } while (--n); - MOD(adler); - MOD(sum2); - } - - /* do remaining bytes (less than NMAX, still just one modulo) */ - if (len) { /* avoid modulos if none remaining */ - while (len >= 16) { - len -= 16; - DO16(buf); - buf += 16; - } - while (len--) { - adler += *buf++; - sum2 += adler; - } - MOD(adler); - MOD(sum2); - } - - /* return recombined sums */ - return adler | (sum2 << 16); -} - -/* ========================================================================= */ -uLong ZEXPORT adler32_combine(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off_t len2; -{ - unsigned long sum1; - unsigned long sum2; - unsigned rem; - - /* the derivation of this formula is left as an exercise for the reader */ - rem = (unsigned)(len2 % BASE); - sum1 = adler1 & 0xffff; - sum2 = rem * sum1; - MOD(sum2); - sum1 += (adler2 & 0xffff) + BASE - 1; - sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; - if (sum1 > BASE) sum1 -= BASE; - if (sum1 > BASE) sum1 -= BASE; - if (sum2 > (BASE << 1)) sum2 -= (BASE << 1); - if (sum2 > BASE) sum2 -= BASE; - return sum1 | (sum2 << 16); -} +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware */ +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD4(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD4(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* the derivation of this formula is left as an exercise for the reader */ + rem = (unsigned)(len2 % BASE); + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 > BASE) sum1 -= BASE; + if (sum1 > BASE) sum1 -= BASE; + if (sum2 > (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 > BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} diff --git a/plugins/CDVDiso/src/3rdparty/zlib/compress.c b/plugins/CDVDiso/src/3rdparty/zlib/compress.c index d37e84f5e3..df04f0148e 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/compress.c +++ b/plugins/CDVDiso/src/3rdparty/zlib/compress.c @@ -1,79 +1,79 @@ -/* compress.c -- compress a memory buffer - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -/* =========================================================================== - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least 0.1% larger than sourceLen plus - 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ -int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; - int level; -{ - z_stream stream; - int err; - - stream.next_in = (Bytef*)source; - stream.avail_in = (uInt)sourceLen; -#ifdef MAXSEG_64K - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; -#endif - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; - - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - stream.opaque = (voidpf)0; - - err = deflateInit(&stream, level); - if (err != Z_OK) return err; - - err = deflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - deflateEnd(&stream); - return err == Z_OK ? Z_BUF_ERROR : err; - } - *destLen = stream.total_out; - - err = deflateEnd(&stream); - return err; -} - -/* =========================================================================== - */ -int ZEXPORT compress (dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ - return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); -} - -/* =========================================================================== - If the default memLevel or windowBits for deflateInit() is changed, then - this function needs to be updated. - */ -uLong ZEXPORT compressBound (sourceLen) - uLong sourceLen; -{ - return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; -} +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/plugins/CDVDiso/src/3rdparty/zlib/crc32.c b/plugins/CDVDiso/src/3rdparty/zlib/crc32.c index 32814c20c8..f658a9ef55 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/crc32.c +++ b/plugins/CDVDiso/src/3rdparty/zlib/crc32.c @@ -1,423 +1,423 @@ -/* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Thanks to Rodney Brown for his contribution of faster - * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing - * tables for updating the shift register in one step with three exclusive-ors - * instead of four steps with four exclusive-ors. This results in about a - * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. - */ - -/* @(#) $Id$ */ - -/* - Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore - protection on the static variables used to control the first-use generation - of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should - first call get_crc_table() to initialize the tables before allowing more than - one thread to use crc32(). - */ - -#ifdef MAKECRCH -# include -# ifndef DYNAMIC_CRC_TABLE -# define DYNAMIC_CRC_TABLE -# endif /* !DYNAMIC_CRC_TABLE */ -#endif /* MAKECRCH */ - -#include "zutil.h" /* for STDC and FAR definitions */ - -#define local static - -/* Find a four-byte integer type for crc32_little() and crc32_big(). */ -#ifndef NOBYFOUR -# ifdef STDC /* need ANSI C limits.h to determine sizes */ -# include -# define BYFOUR -# if (UINT_MAX == 0xffffffffUL) - typedef unsigned int u4; -# else -# if (ULONG_MAX == 0xffffffffUL) - typedef unsigned long u4; -# else -# if (USHRT_MAX == 0xffffffffUL) - typedef unsigned short u4; -# else -# undef BYFOUR /* can't find a four-byte integer type! */ -# endif -# endif -# endif -# endif /* STDC */ -#endif /* !NOBYFOUR */ - -/* Definitions for doing the crc four data bytes at a time. */ -#ifdef BYFOUR -# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ - (((w)&0xff00)<<8)+(((w)&0xff)<<24)) - local unsigned long crc32_little OF((unsigned long, - const unsigned char FAR *, unsigned)); - local unsigned long crc32_big OF((unsigned long, - const unsigned char FAR *, unsigned)); -# define TBLS 8 -#else -# define TBLS 1 -#endif /* BYFOUR */ - -/* Local functions for crc concatenation */ -local unsigned long gf2_matrix_times OF((unsigned long *mat, - unsigned long vec)); -local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); - -#ifdef DYNAMIC_CRC_TABLE - -local volatile int crc_table_empty = 1; -local unsigned long FAR crc_table[TBLS][256]; -local void make_crc_table OF((void)); -#ifdef MAKECRCH - local void write_table OF((FILE *, const unsigned long FAR *)); -#endif /* MAKECRCH */ -/* - Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: - x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. - - Polynomials over GF(2) are represented in binary, one bit per coefficient, - with the lowest powers in the most significant bit. Then adding polynomials - is just exclusive-or, and multiplying a polynomial by x is a right shift by - one. If we call the above polynomial p, and represent a byte as the - polynomial q, also with the lowest power in the most significant bit (so the - byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, - where a mod b means the remainder after dividing a by b. - - This calculation is done using the shift-register method of multiplying and - taking the remainder. The register is initialized to zero, and for each - incoming bit, x^32 is added mod p to the register if the bit is a one (where - x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by - x (which is shifting right by one and adding x^32 mod p if the bit shifted - out is a one). We start with the highest power (least significant bit) of - q and repeat for all eight bits of q. - - The first table is simply the CRC of all possible eight bit values. This is - all the information needed to generate CRCs on data a byte at a time for all - combinations of CRC register values and incoming bytes. The remaining tables - allow for word-at-a-time CRC calculation for both big-endian and little- - endian machines, where a word is four bytes. -*/ -local void make_crc_table() -{ - unsigned long c; - int n, k; - unsigned long poly; /* polynomial exclusive-or pattern */ - /* terms of polynomial defining this crc (except x^32): */ - static volatile int first = 1; /* flag to limit concurrent making */ - static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - /* See if another task is already doing this (not thread-safe, but better - than nothing -- significantly reduces duration of vulnerability in - case the advice about DYNAMIC_CRC_TABLE is ignored) */ - if (first) { - first = 0; - - /* make exclusive-or pattern from polynomial (0xedb88320UL) */ - poly = 0UL; - for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) - poly |= 1UL << (31 - p[n]); - - /* generate a crc for every 8-bit value */ - for (n = 0; n < 256; n++) { - c = (unsigned long)n; - for (k = 0; k < 8; k++) - c = c & 1 ? poly ^ (c >> 1) : c >> 1; - crc_table[0][n] = c; - } - -#ifdef BYFOUR - /* generate crc for each value followed by one, two, and three zeros, - and then the byte reversal of those as well as the first table */ - for (n = 0; n < 256; n++) { - c = crc_table[0][n]; - crc_table[4][n] = REV(c); - for (k = 1; k < 4; k++) { - c = crc_table[0][c & 0xff] ^ (c >> 8); - crc_table[k][n] = c; - crc_table[k + 4][n] = REV(c); - } - } -#endif /* BYFOUR */ - - crc_table_empty = 0; - } - else { /* not first */ - /* wait for the other guy to finish (not efficient, but rare) */ - while (crc_table_empty) - ; - } - -#ifdef MAKECRCH - /* write out CRC tables to crc32.h */ - { - FILE *out; - - out = fopen("crc32.h", "w"); - if (out == NULL) return; - fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); - fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); - fprintf(out, "local const unsigned long FAR "); - fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); - write_table(out, crc_table[0]); -# ifdef BYFOUR - fprintf(out, "#ifdef BYFOUR\n"); - for (k = 1; k < 8; k++) { - fprintf(out, " },\n {\n"); - write_table(out, crc_table[k]); - } - fprintf(out, "#endif\n"); -# endif /* BYFOUR */ - fprintf(out, " }\n};\n"); - fclose(out); - } -#endif /* MAKECRCH */ -} - -#ifdef MAKECRCH -local void write_table(out, table) - FILE *out; - const unsigned long FAR *table; -{ - int n; - - for (n = 0; n < 256; n++) - fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], - n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); -} -#endif /* MAKECRCH */ - -#else /* !DYNAMIC_CRC_TABLE */ -/* ======================================================================== - * Tables of CRC-32s of all single-byte values, made by make_crc_table(). - */ -#include "crc32.h" -#endif /* DYNAMIC_CRC_TABLE */ - -/* ========================================================================= - * This function can be used by asm versions of crc32() - */ -const unsigned long FAR * ZEXPORT get_crc_table() -{ -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); -#endif /* DYNAMIC_CRC_TABLE */ - return (const unsigned long FAR *)crc_table; -} - -/* ========================================================================= */ -#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) -#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 - -/* ========================================================================= */ -unsigned long ZEXPORT crc32(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - if (buf == Z_NULL) return 0UL; - -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); -#endif /* DYNAMIC_CRC_TABLE */ - -#ifdef BYFOUR - if (sizeof(void *) == sizeof(ptrdiff_t)) { - u4 endian; - - endian = 1; - if (*((unsigned char *)(&endian))) - return crc32_little(crc, buf, len); - else - return crc32_big(crc, buf, len); - } -#endif /* BYFOUR */ - crc = crc ^ 0xffffffffUL; - while (len >= 8) { - DO8; - len -= 8; - } - if (len) do { - DO1; - } while (--len); - return crc ^ 0xffffffffUL; -} - -#ifdef BYFOUR - -/* ========================================================================= */ -#define DOLIT4 c ^= *buf4++; \ - c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ - crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] -#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 - -/* ========================================================================= */ -local unsigned long crc32_little(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - register u4 c; - register const u4 FAR *buf4; - - c = (u4)crc; - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - len--; - } - - buf4 = (const u4 FAR *)(const void FAR *)buf; - while (len >= 32) { - DOLIT32; - len -= 32; - } - while (len >= 4) { - DOLIT4; - len -= 4; - } - buf = (const unsigned char FAR *)buf4; - - if (len) do { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - } while (--len); - c = ~c; - return (unsigned long)c; -} - -/* ========================================================================= */ -#define DOBIG4 c ^= *++buf4; \ - c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ - crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] -#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 - -/* ========================================================================= */ -local unsigned long crc32_big(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - register u4 c; - register const u4 FAR *buf4; - - c = REV((u4)crc); - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - len--; - } - - buf4 = (const u4 FAR *)(const void FAR *)buf; - buf4--; - while (len >= 32) { - DOBIG32; - len -= 32; - } - while (len >= 4) { - DOBIG4; - len -= 4; - } - buf4++; - buf = (const unsigned char FAR *)buf4; - - if (len) do { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - } while (--len); - c = ~c; - return (unsigned long)(REV(c)); -} - -#endif /* BYFOUR */ - -#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ - -/* ========================================================================= */ -local unsigned long gf2_matrix_times(mat, vec) - unsigned long *mat; - unsigned long vec; -{ - unsigned long sum; - - sum = 0; - while (vec) { - if (vec & 1) - sum ^= *mat; - vec >>= 1; - mat++; - } - return sum; -} - -/* ========================================================================= */ -local void gf2_matrix_square(square, mat) - unsigned long *square; - unsigned long *mat; -{ - int n; - - for (n = 0; n < GF2_DIM; n++) - square[n] = gf2_matrix_times(mat, mat[n]); -} - -/* ========================================================================= */ -uLong ZEXPORT crc32_combine(crc1, crc2, len2) - uLong crc1; - uLong crc2; - z_off_t len2; -{ - int n; - unsigned long row; - unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ - unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ - - /* degenerate case */ - if (len2 == 0) - return crc1; - - /* put operator for one zero bit in odd */ - odd[0] = 0xedb88320L; /* CRC-32 polynomial */ - row = 1; - for (n = 1; n < GF2_DIM; n++) { - odd[n] = row; - row <<= 1; - } - - /* put operator for two zero bits in even */ - gf2_matrix_square(even, odd); - - /* put operator for four zero bits in odd */ - gf2_matrix_square(odd, even); - - /* apply len2 zeros to crc1 (first square will put the operator for one - zero byte, eight zero bits, in even) */ - do { - /* apply zeros operator for this bit of len2 */ - gf2_matrix_square(even, odd); - if (len2 & 1) - crc1 = gf2_matrix_times(even, crc1); - len2 >>= 1; - - /* if no more bits set, then done */ - if (len2 == 0) - break; - - /* another iteration of the loop with odd and even swapped */ - gf2_matrix_square(odd, even); - if (len2 & 1) - crc1 = gf2_matrix_times(odd, crc1); - len2 >>= 1; - - /* if no more bits set, then done */ - } while (len2 != 0); - - /* return combined crc */ - crc1 ^= crc2; - return crc1; -} +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case */ + if (len2 == 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320L; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} diff --git a/plugins/CDVDiso/src/3rdparty/zlib/crc32.h b/plugins/CDVDiso/src/3rdparty/zlib/crc32.h index 5de49bc978..8053b6117c 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/crc32.h +++ b/plugins/CDVDiso/src/3rdparty/zlib/crc32.h @@ -1,441 +1,441 @@ -/* crc32.h -- tables for rapid CRC calculation - * Generated automatically by crc32.c - */ - -local const unsigned long FAR crc_table[TBLS][256] = -{ - { - 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, - 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, - 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, - 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, - 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, - 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, - 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, - 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, - 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, - 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, - 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, - 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, - 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, - 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, - 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, - 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, - 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, - 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, - 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, - 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, - 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, - 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, - 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, - 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, - 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, - 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, - 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, - 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, - 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, - 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, - 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, - 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, - 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, - 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, - 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, - 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, - 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, - 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, - 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, - 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, - 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, - 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, - 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, - 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, - 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, - 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, - 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, - 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, - 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, - 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, - 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, - 0x2d02ef8dUL -#ifdef BYFOUR - }, - { - 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, - 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, - 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, - 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, - 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, - 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, - 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, - 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, - 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, - 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, - 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, - 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, - 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, - 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, - 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, - 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, - 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, - 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, - 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, - 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, - 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, - 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, - 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, - 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, - 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, - 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, - 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, - 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, - 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, - 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, - 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, - 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, - 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, - 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, - 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, - 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, - 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, - 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, - 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, - 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, - 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, - 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, - 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, - 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, - 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, - 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, - 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, - 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, - 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, - 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, - 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, - 0x9324fd72UL - }, - { - 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, - 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, - 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, - 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, - 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, - 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, - 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, - 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, - 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, - 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, - 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, - 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, - 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, - 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, - 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, - 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, - 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, - 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, - 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, - 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, - 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, - 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, - 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, - 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, - 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, - 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, - 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, - 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, - 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, - 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, - 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, - 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, - 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, - 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, - 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, - 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, - 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, - 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, - 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, - 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, - 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, - 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, - 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, - 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, - 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, - 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, - 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, - 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, - 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, - 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, - 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, - 0xbe9834edUL - }, - { - 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, - 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, - 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, - 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, - 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, - 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, - 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, - 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, - 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, - 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, - 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, - 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, - 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, - 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, - 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, - 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, - 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, - 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, - 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, - 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, - 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, - 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, - 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, - 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, - 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, - 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, - 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, - 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, - 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, - 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, - 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, - 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, - 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, - 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, - 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, - 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, - 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, - 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, - 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, - 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, - 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, - 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, - 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, - 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, - 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, - 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, - 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, - 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, - 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, - 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, - 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, - 0xde0506f1UL - }, - { - 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, - 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, - 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, - 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, - 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, - 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, - 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, - 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, - 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, - 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, - 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, - 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, - 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, - 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, - 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, - 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, - 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, - 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, - 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, - 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, - 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, - 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, - 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, - 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, - 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, - 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, - 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, - 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, - 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, - 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, - 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, - 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, - 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, - 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, - 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, - 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, - 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, - 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, - 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, - 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, - 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, - 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, - 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, - 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, - 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, - 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, - 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, - 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, - 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, - 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, - 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, - 0x8def022dUL - }, - { - 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, - 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, - 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, - 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, - 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, - 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, - 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, - 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, - 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, - 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, - 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, - 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, - 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, - 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, - 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, - 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, - 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, - 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, - 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, - 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, - 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, - 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, - 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, - 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, - 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, - 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, - 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, - 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, - 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, - 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, - 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, - 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, - 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, - 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, - 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, - 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, - 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, - 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, - 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, - 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, - 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, - 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, - 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, - 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, - 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, - 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, - 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, - 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, - 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, - 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, - 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, - 0x72fd2493UL - }, - { - 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, - 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, - 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, - 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, - 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, - 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, - 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, - 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, - 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, - 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, - 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, - 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, - 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, - 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, - 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, - 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, - 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, - 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, - 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, - 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, - 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, - 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, - 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, - 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, - 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, - 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, - 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, - 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, - 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, - 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, - 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, - 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, - 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, - 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, - 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, - 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, - 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, - 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, - 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, - 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, - 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, - 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, - 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, - 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, - 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, - 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, - 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, - 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, - 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, - 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, - 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, - 0xed3498beUL - }, - { - 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, - 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, - 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, - 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, - 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, - 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, - 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, - 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, - 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, - 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, - 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, - 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, - 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, - 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, - 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, - 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, - 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, - 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, - 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, - 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, - 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, - 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, - 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, - 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, - 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, - 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, - 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, - 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, - 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, - 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, - 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, - 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, - 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, - 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, - 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, - 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, - 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, - 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, - 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, - 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, - 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, - 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, - 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, - 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, - 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, - 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, - 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, - 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, - 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, - 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, - 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, - 0xf10605deUL -#endif - } -}; +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/plugins/CDVDiso/src/3rdparty/zlib/deflate.c b/plugins/CDVDiso/src/3rdparty/zlib/deflate.c index 529f716b7a..29ce1f64a5 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/deflate.c +++ b/plugins/CDVDiso/src/3rdparty/zlib/deflate.c @@ -1,1736 +1,1736 @@ -/* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process depends on being able to identify portions - * of the input text which are identical to earlier input (within a - * sliding window trailing behind the input currently being processed). - * - * The most straightforward technique turns out to be the fastest for - * most input files: try all possible matches and select the longest. - * The key feature of this algorithm is that insertions into the string - * dictionary are very simple and thus fast, and deletions are avoided - * completely. Insertions are performed at each input character, whereas - * string matches are performed only when the previous match ends. So it - * is preferable to spend more time in matches to allow very fast string - * insertions and avoid deletions. The matching algorithm for small - * strings is inspired from that of Rabin & Karp. A brute force approach - * is used to find longer strings when a small match has been found. - * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze - * (by Leonid Broukhis). - * A previous version of this file used a more sophisticated algorithm - * (by Fiala and Greene) which is guaranteed to run in linear amortized - * time, but has a larger average cost, uses more memory and is patented. - * However the F&G algorithm may be faster for some highly redundant - * files if the parameter max_chain_length (described below) is too large. - * - * ACKNOWLEDGEMENTS - * - * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and - * I found it in 'freeze' written by Leonid Broukhis. - * Thanks to many people for bug reports and testing. - * - * REFERENCES - * - * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". - * Available in http://www.ietf.org/rfc/rfc1951.txt - * - * A description of the Rabin and Karp algorithm is given in the book - * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. - * - * Fiala,E.R., and Greene,D.H. - * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 - * - */ - -/* @(#) $Id$ */ - -#include "deflate.h" - -const char deflate_copyright[] = - " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* =========================================================================== - * Function prototypes. - */ -typedef enum { - need_more, /* block not completed, need more input or more output */ - block_done, /* block flush performed */ - finish_started, /* finish started, need only more output at next deflate */ - finish_done /* finish done, accept no more input or output */ -} block_state; - -typedef block_state (*compress_func) OF((deflate_state *s, int flush)); -/* Compression function. Returns the block state after the call. */ - -local void fill_window OF((deflate_state *s)); -local block_state deflate_stored OF((deflate_state *s, int flush)); -local block_state deflate_fast OF((deflate_state *s, int flush)); -#ifndef FASTEST -local block_state deflate_slow OF((deflate_state *s, int flush)); -#endif -local void lm_init OF((deflate_state *s)); -local void putShortMSB OF((deflate_state *s, uInt b)); -local void flush_pending OF((z_streamp strm)); -local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); -#ifndef FASTEST -#ifdef ASMV - void match_init OF((void)); /* asm code initialization */ - uInt longest_match OF((deflate_state *s, IPos cur_match)); -#else -local uInt longest_match OF((deflate_state *s, IPos cur_match)); -#endif -#endif -local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); - -#ifdef DEBUG -local void check_match OF((deflate_state *s, IPos start, IPos match, - int length)); -#endif - -/* =========================================================================== - * Local data - */ - -#define NIL 0 -/* Tail of hash chains */ - -#ifndef TOO_FAR -# define TOO_FAR 4096 -#endif -/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -/* Values for max_lazy_match, good_match and max_chain_length, depending on - * the desired pack level (0..9). The values given below have been tuned to - * exclude worst case performance for pathological files. Better values may be - * found for specific files. - */ -typedef struct config_s { - ush good_length; /* reduce lazy search above this match length */ - ush max_lazy; /* do not perform lazy search above this match length */ - ush nice_length; /* quit search above this match length */ - ush max_chain; - compress_func func; -} config; - -#ifdef FASTEST -local const config configuration_table[2] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ -#else -local const config configuration_table[10] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ -/* 2 */ {4, 5, 16, 8, deflate_fast}, -/* 3 */ {4, 6, 32, 32, deflate_fast}, - -/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ -/* 5 */ {8, 16, 32, 32, deflate_slow}, -/* 6 */ {8, 16, 128, 128, deflate_slow}, -/* 7 */ {8, 32, 128, 256, deflate_slow}, -/* 8 */ {32, 128, 258, 1024, deflate_slow}, -/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ -#endif - -/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 - * For deflate_fast() (levels <= 3) good is ignored and lazy has a different - * meaning. - */ - -#define EQUAL 0 -/* result of memcmp for equal strings */ - -#ifndef NO_DUMMY_DECL -struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ -#endif - -/* =========================================================================== - * Update a hash value with the given input byte - * IN assertion: all calls to to UPDATE_HASH are made with consecutive - * input characters, so that a running hash key can be computed from the - * previous key instead of complete recalculation each time. - */ -#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) - - -/* =========================================================================== - * Insert string str in the dictionary and set match_head to the previous head - * of the hash chain (the most recent string with same hash key). Return - * the previous length of the hash chain. - * If this file is compiled with -DFASTEST, the compression level is forced - * to 1, and no hash chains are maintained. - * IN assertion: all calls to to INSERT_STRING are made with consecutive - * input characters and the first MIN_MATCH bytes of str are valid - * (except for the last MIN_MATCH-1 bytes of the input file). - */ -#ifdef FASTEST -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - match_head = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) -#else -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) -#endif - -/* =========================================================================== - * Initialize the hash table (avoiding 64K overflow for 16 bit systems). - * prev[] will be initialized on the fly. - */ -#define CLEAR_HASH(s) \ - s->head[s->hash_size-1] = NIL; \ - zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); - -/* ========================================================================= */ -int ZEXPORT deflateInit_(strm, level, version, stream_size) - z_streamp strm; - int level; - const char *version; - int stream_size; -{ - return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, version, stream_size); - /* To do: ignore strm->next_in if we use it as window */ -} - -/* ========================================================================= */ -int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, - version, stream_size) - z_streamp strm; - int level; - int method; - int windowBits; - int memLevel; - int strategy; - const char *version; - int stream_size; -{ - deflate_state *s; - int wrap = 1; - static const char my_version[] = ZLIB_VERSION; - - ushf *overlay; - /* We overlay pending_buf and d_buf+l_buf. This works since the average - * output size for (length,distance) codes is <= 24 bits. - */ - - if (version == Z_NULL || version[0] != my_version[0] || - stream_size != sizeof(z_stream)) { - return Z_VERSION_ERROR; - } - if (strm == Z_NULL) return Z_STREAM_ERROR; - - strm->msg = Z_NULL; - if (strm->zalloc == (alloc_func)0) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; - -#ifdef FASTEST - if (level != 0) level = 1; -#else - if (level == Z_DEFAULT_COMPRESSION) level = 6; -#endif - - if (windowBits < 0) { /* suppress zlib wrapper */ - wrap = 0; - windowBits = -windowBits; - } -#ifdef GZIP - else if (windowBits > 15) { - wrap = 2; /* write gzip wrapper instead */ - windowBits -= 16; - } -#endif - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || - windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_FIXED) { - return Z_STREAM_ERROR; - } - if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ - s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); - if (s == Z_NULL) return Z_MEM_ERROR; - strm->state = (struct internal_state FAR *)s; - s->strm = strm; - - s->wrap = wrap; - s->gzhead = Z_NULL; - s->w_bits = windowBits; - s->w_size = 1 << s->w_bits; - s->w_mask = s->w_size - 1; - - s->hash_bits = memLevel + 7; - s->hash_size = 1 << s->hash_bits; - s->hash_mask = s->hash_size - 1; - s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); - - s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); - s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); - s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); - - s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ - - overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); - s->pending_buf = (uchf *) overlay; - s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); - - if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || - s->pending_buf == Z_NULL) { - s->status = FINISH_STATE; - strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); - deflateEnd (strm); - return Z_MEM_ERROR; - } - s->d_buf = overlay + s->lit_bufsize/sizeof(ush); - s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; - - s->level = level; - s->strategy = strategy; - s->method = (Byte)method; - - return deflateReset(strm); -} - -/* ========================================================================= */ -int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) - z_streamp strm; - const Bytef *dictionary; - uInt dictLength; -{ - deflate_state *s; - uInt length = dictLength; - uInt n; - IPos hash_head = 0; - - if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || - strm->state->wrap == 2 || - (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) - return Z_STREAM_ERROR; - - s = strm->state; - if (s->wrap) - strm->adler = adler32(strm->adler, dictionary, dictLength); - - if (length < MIN_MATCH) return Z_OK; - if (length > MAX_DIST(s)) { - length = MAX_DIST(s); - dictionary += dictLength - length; /* use the tail of the dictionary */ - } - zmemcpy(s->window, dictionary, length); - s->strstart = length; - s->block_start = (long)length; - - /* Insert all strings in the hash table (except for the last two bytes). - * s->lookahead stays null, so s->ins_h will be recomputed at the next - * call of fill_window. - */ - s->ins_h = s->window[0]; - UPDATE_HASH(s, s->ins_h, s->window[1]); - for (n = 0; n <= length - MIN_MATCH; n++) { - INSERT_STRING(s, n, hash_head); - } - if (hash_head) hash_head = 0; /* to make compiler happy */ - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateReset (strm) - z_streamp strm; -{ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL || - strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { - return Z_STREAM_ERROR; - } - - strm->total_in = strm->total_out = 0; - strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ - strm->data_type = Z_UNKNOWN; - - s = (deflate_state *)strm->state; - s->pending = 0; - s->pending_out = s->pending_buf; - - if (s->wrap < 0) { - s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ - } - s->status = s->wrap ? INIT_STATE : BUSY_STATE; - strm->adler = -#ifdef GZIP - s->wrap == 2 ? crc32(0L, Z_NULL, 0) : -#endif - adler32(0L, Z_NULL, 0); - s->last_flush = Z_NO_FLUSH; - - _tr_init(s); - lm_init(s); - - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateSetHeader (strm, head) - z_streamp strm; - gz_headerp head; -{ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - if (strm->state->wrap != 2) return Z_STREAM_ERROR; - strm->state->gzhead = head; - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflatePrime (strm, bits, value) - z_streamp strm; - int bits; - int value; -{ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - strm->state->bi_valid = bits; - strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateParams(strm, level, strategy) - z_streamp strm; - int level; - int strategy; -{ - deflate_state *s; - compress_func func; - int err = Z_OK; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - s = strm->state; - -#ifdef FASTEST - if (level != 0) level = 1; -#else - if (level == Z_DEFAULT_COMPRESSION) level = 6; -#endif - if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { - return Z_STREAM_ERROR; - } - func = configuration_table[s->level].func; - - if (func != configuration_table[level].func && strm->total_in != 0) { - /* Flush the last buffer: */ - err = deflate(strm, Z_PARTIAL_FLUSH); - } - if (s->level != level) { - s->level = level; - s->max_lazy_match = configuration_table[level].max_lazy; - s->good_match = configuration_table[level].good_length; - s->nice_match = configuration_table[level].nice_length; - s->max_chain_length = configuration_table[level].max_chain; - } - s->strategy = strategy; - return err; -} - -/* ========================================================================= */ -int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) - z_streamp strm; - int good_length; - int max_lazy; - int nice_length; - int max_chain; -{ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - s = strm->state; - s->good_match = good_length; - s->max_lazy_match = max_lazy; - s->nice_match = nice_length; - s->max_chain_length = max_chain; - return Z_OK; -} - -/* ========================================================================= - * For the default windowBits of 15 and memLevel of 8, this function returns - * a close to exact, as well as small, upper bound on the compressed size. - * They are coded as constants here for a reason--if the #define's are - * changed, then this function needs to be changed as well. The return - * value for 15 and 8 only works for those exact settings. - * - * For any setting other than those defaults for windowBits and memLevel, - * the value returned is a conservative worst case for the maximum expansion - * resulting from using fixed blocks instead of stored blocks, which deflate - * can emit on compressed data for some combinations of the parameters. - * - * This function could be more sophisticated to provide closer upper bounds - * for every combination of windowBits and memLevel, as well as wrap. - * But even the conservative upper bound of about 14% expansion does not - * seem onerous for output buffer allocation. - */ -uLong ZEXPORT deflateBound(strm, sourceLen) - z_streamp strm; - uLong sourceLen; -{ - deflate_state *s; - uLong destLen; - - /* conservative upper bound */ - destLen = sourceLen + - ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; - - /* if can't get parameters, return conservative bound */ - if (strm == Z_NULL || strm->state == Z_NULL) - return destLen; - - /* if not default parameters, return conservative bound */ - s = strm->state; - if (s->w_bits != 15 || s->hash_bits != 8 + 7) - return destLen; - - /* default settings: return tight bound for that case */ - return compressBound(sourceLen); -} - -/* ========================================================================= - * Put a short in the pending buffer. The 16-bit value is put in MSB order. - * IN assertion: the stream state is correct and there is enough room in - * pending_buf. - */ -local void putShortMSB (s, b) - deflate_state *s; - uInt b; -{ - put_byte(s, (Byte)(b >> 8)); - put_byte(s, (Byte)(b & 0xff)); -} - -/* ========================================================================= - * Flush as much pending output as possible. All deflate() output goes - * through this function so some applications may wish to modify it - * to avoid allocating a large strm->next_out buffer and copying into it. - * (See also read_buf()). - */ -local void flush_pending(strm) - z_streamp strm; -{ - unsigned len = strm->state->pending; - - if (len > strm->avail_out) len = strm->avail_out; - if (len == 0) return; - - zmemcpy(strm->next_out, strm->state->pending_out, len); - strm->next_out += len; - strm->state->pending_out += len; - strm->total_out += len; - strm->avail_out -= len; - strm->state->pending -= len; - if (strm->state->pending == 0) { - strm->state->pending_out = strm->state->pending_buf; - } -} - -/* ========================================================================= */ -int ZEXPORT deflate (strm, flush) - z_streamp strm; - int flush; -{ - int old_flush; /* value of flush param for previous deflate call */ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL || - flush > Z_FINISH || flush < 0) { - return Z_STREAM_ERROR; - } - s = strm->state; - - if (strm->next_out == Z_NULL || - (strm->next_in == Z_NULL && strm->avail_in != 0) || - (s->status == FINISH_STATE && flush != Z_FINISH)) { - ERR_RETURN(strm, Z_STREAM_ERROR); - } - if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); - - s->strm = strm; /* just in case */ - old_flush = s->last_flush; - s->last_flush = flush; - - /* Write the header */ - if (s->status == INIT_STATE) { -#ifdef GZIP - if (s->wrap == 2) { - strm->adler = crc32(0L, Z_NULL, 0); - put_byte(s, 31); - put_byte(s, 139); - put_byte(s, 8); - if (s->gzhead == NULL) { - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, OS_CODE); - s->status = BUSY_STATE; - } - else { - put_byte(s, (s->gzhead->text ? 1 : 0) + - (s->gzhead->hcrc ? 2 : 0) + - (s->gzhead->extra == Z_NULL ? 0 : 4) + - (s->gzhead->name == Z_NULL ? 0 : 8) + - (s->gzhead->comment == Z_NULL ? 0 : 16) - ); - put_byte(s, (Byte)(s->gzhead->time & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, s->gzhead->os & 0xff); - if (s->gzhead->extra != NULL) { - put_byte(s, s->gzhead->extra_len & 0xff); - put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); - } - if (s->gzhead->hcrc) - strm->adler = crc32(strm->adler, s->pending_buf, - s->pending); - s->gzindex = 0; - s->status = EXTRA_STATE; - } - } - else -#endif - { - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; - uInt level_flags; - - if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) - level_flags = 0; - else if (s->level < 6) - level_flags = 1; - else if (s->level == 6) - level_flags = 2; - else - level_flags = 3; - header |= (level_flags << 6); - if (s->strstart != 0) header |= PRESET_DICT; - header += 31 - (header % 31); - - s->status = BUSY_STATE; - putShortMSB(s, header); - - /* Save the adler32 of the preset dictionary: */ - if (s->strstart != 0) { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - strm->adler = adler32(0L, Z_NULL, 0); - } - } -#ifdef GZIP - if (s->status == EXTRA_STATE) { - if (s->gzhead->extra != NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - - while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) - break; - } - put_byte(s, s->gzhead->extra[s->gzindex]); - s->gzindex++; - } - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (s->gzindex == s->gzhead->extra_len) { - s->gzindex = 0; - s->status = NAME_STATE; - } - } - else - s->status = NAME_STATE; - } - if (s->status == NAME_STATE) { - if (s->gzhead->name != NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - int val; - - do { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) { - val = 1; - break; - } - } - val = s->gzhead->name[s->gzindex++]; - put_byte(s, val); - } while (val != 0); - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (val == 0) { - s->gzindex = 0; - s->status = COMMENT_STATE; - } - } - else - s->status = COMMENT_STATE; - } - if (s->status == COMMENT_STATE) { - if (s->gzhead->comment != NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - int val; - - do { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) { - val = 1; - break; - } - } - val = s->gzhead->comment[s->gzindex++]; - put_byte(s, val); - } while (val != 0); - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (val == 0) - s->status = HCRC_STATE; - } - else - s->status = HCRC_STATE; - } - if (s->status == HCRC_STATE) { - if (s->gzhead->hcrc) { - if (s->pending + 2 > s->pending_buf_size) - flush_pending(strm); - if (s->pending + 2 <= s->pending_buf_size) { - put_byte(s, (Byte)(strm->adler & 0xff)); - put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); - strm->adler = crc32(0L, Z_NULL, 0); - s->status = BUSY_STATE; - } - } - else - s->status = BUSY_STATE; - } -#endif - - /* Flush as much pending output as possible */ - if (s->pending != 0) { - flush_pending(strm); - if (strm->avail_out == 0) { - /* Since avail_out is 0, deflate will be called again with - * more output space, but possibly with both pending and - * avail_in equal to zero. There won't be anything to do, - * but this is not an error situation so make sure we - * return OK instead of BUF_ERROR at next call of deflate: - */ - s->last_flush = -1; - return Z_OK; - } - - /* Make sure there is something to do and avoid duplicate consecutive - * flushes. For repeated and useless calls with Z_FINISH, we keep - * returning Z_STREAM_END instead of Z_BUF_ERROR. - */ - } else if (strm->avail_in == 0 && flush <= old_flush && - flush != Z_FINISH) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* User must not provide more input after the first FINISH: */ - if (s->status == FINISH_STATE && strm->avail_in != 0) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* Start a new block or continue the current one. - */ - if (strm->avail_in != 0 || s->lookahead != 0 || - (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { - block_state bstate; - - bstate = (*(configuration_table[s->level].func))(s, flush); - - if (bstate == finish_started || bstate == finish_done) { - s->status = FINISH_STATE; - } - if (bstate == need_more || bstate == finish_started) { - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ - } - return Z_OK; - /* If flush != Z_NO_FLUSH && avail_out == 0, the next call - * of deflate should use the same flush parameter to make sure - * that the flush is complete. So we don't have to output an - * empty block here, this will be done at next call. This also - * ensures that for a very small output buffer, we emit at most - * one empty block. - */ - } - if (bstate == block_done) { - if (flush == Z_PARTIAL_FLUSH) { - _tr_align(s); - } else { /* FULL_FLUSH or SYNC_FLUSH */ - _tr_stored_block(s, (char*)0, 0L, 0); - /* For a full flush, this empty block will be recognized - * as a special marker by inflate_sync(). - */ - if (flush == Z_FULL_FLUSH) { - CLEAR_HASH(s); /* forget history */ - } - } - flush_pending(strm); - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ - return Z_OK; - } - } - } - Assert(strm->avail_out > 0, "bug2"); - - if (flush != Z_FINISH) return Z_OK; - if (s->wrap <= 0) return Z_STREAM_END; - - /* Write the trailer */ -#ifdef GZIP - if (s->wrap == 2) { - put_byte(s, (Byte)(strm->adler & 0xff)); - put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); - put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); - put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); - put_byte(s, (Byte)(strm->total_in & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); - } - else -#endif - { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - flush_pending(strm); - /* If avail_out is zero, the application will call deflate again - * to flush the rest. - */ - if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ - return s->pending != 0 ? Z_OK : Z_STREAM_END; -} - -/* ========================================================================= */ -int ZEXPORT deflateEnd (strm) - z_streamp strm; -{ - int status; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - - status = strm->state->status; - if (status != INIT_STATE && - status != EXTRA_STATE && - status != NAME_STATE && - status != COMMENT_STATE && - status != HCRC_STATE && - status != BUSY_STATE && - status != FINISH_STATE) { - return Z_STREAM_ERROR; - } - - /* Deallocate in reverse order of allocations: */ - TRY_FREE(strm, strm->state->pending_buf); - TRY_FREE(strm, strm->state->head); - TRY_FREE(strm, strm->state->prev); - TRY_FREE(strm, strm->state->window); - - ZFREE(strm, strm->state); - strm->state = Z_NULL; - - return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; -} - -/* ========================================================================= - * Copy the source state to the destination state. - * To simplify the source, this is not supported for 16-bit MSDOS (which - * doesn't have enough memory anyway to duplicate compression states). - */ -int ZEXPORT deflateCopy (dest, source) - z_streamp dest; - z_streamp source; -{ -#ifdef MAXSEG_64K - return Z_STREAM_ERROR; -#else - deflate_state *ds; - deflate_state *ss; - ushf *overlay; - - - if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { - return Z_STREAM_ERROR; - } - - ss = source->state; - - zmemcpy(dest, source, sizeof(z_stream)); - - ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); - if (ds == Z_NULL) return Z_MEM_ERROR; - dest->state = (struct internal_state FAR *) ds; - zmemcpy(ds, ss, sizeof(deflate_state)); - ds->strm = dest; - - ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); - ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); - ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); - overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); - ds->pending_buf = (uchf *) overlay; - - if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || - ds->pending_buf == Z_NULL) { - deflateEnd (dest); - return Z_MEM_ERROR; - } - /* following zmemcpy do not work for 16-bit MSDOS */ - zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); - zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); - zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); - zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); - - ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); - ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); - ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; - - ds->l_desc.dyn_tree = ds->dyn_ltree; - ds->d_desc.dyn_tree = ds->dyn_dtree; - ds->bl_desc.dyn_tree = ds->bl_tree; - - return Z_OK; -#endif /* MAXSEG_64K */ -} - -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->next_in buffer and copying from it. - * (See also flush_pending()). - */ -local int read_buf(strm, buf, size) - z_streamp strm; - Bytef *buf; - unsigned size; -{ - unsigned len = strm->avail_in; - - if (len > size) len = size; - if (len == 0) return 0; - - strm->avail_in -= len; - - if (strm->state->wrap == 1) { - strm->adler = adler32(strm->adler, strm->next_in, len); - } -#ifdef GZIP - else if (strm->state->wrap == 2) { - strm->adler = crc32(strm->adler, strm->next_in, len); - } -#endif - zmemcpy(buf, strm->next_in, len); - strm->next_in += len; - strm->total_in += len; - - return (int)len; -} - -/* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ -local void lm_init (s) - deflate_state *s; -{ - s->window_size = (ulg)2L*s->w_size; - - CLEAR_HASH(s); - - /* Set the default configuration parameters: - */ - s->max_lazy_match = configuration_table[s->level].max_lazy; - s->good_match = configuration_table[s->level].good_length; - s->nice_match = configuration_table[s->level].nice_length; - s->max_chain_length = configuration_table[s->level].max_chain; - - s->strstart = 0; - s->block_start = 0L; - s->lookahead = 0; - s->match_length = s->prev_length = MIN_MATCH-1; - s->match_available = 0; - s->ins_h = 0; -#ifndef FASTEST -#ifdef ASMV - match_init(); /* initialize the asm code */ -#endif -#endif -} - -#ifndef FASTEST -/* =========================================================================== - * Set match_start to the longest match starting at the given string and - * return its length. Matches shorter or equal to prev_length are discarded, - * in which case the result is equal to prev_length and match_start is - * garbage. - * IN assertions: cur_match is the head of the hash chain for the current - * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 - * OUT assertion: the match length is not greater than s->lookahead. - */ -#ifndef ASMV -/* For 80x86 and 680x0, an optimized version will be provided in match.asm or - * match.S. The code will be functionally equivalent. - */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - unsigned chain_length = s->max_chain_length;/* max hash chain length */ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - int best_len = s->prev_length; /* best match length so far */ - int nice_match = s->nice_match; /* stop if match long enough */ - IPos limit = s->strstart > (IPos)MAX_DIST(s) ? - s->strstart - (IPos)MAX_DIST(s) : NIL; - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0. - */ - Posf *prev = s->prev; - uInt wmask = s->w_mask; - -#ifdef UNALIGNED_OK - /* Compare two bytes at a time. Note: this is not always beneficial. - * Try with and without -DUNALIGNED_OK to check. - */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; - register ush scan_start = *(ushf*)scan; - register ush scan_end = *(ushf*)(scan+best_len-1); -#else - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - register Byte scan_end1 = scan[best_len-1]; - register Byte scan_end = scan[best_len]; -#endif - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - /* Do not waste too much time if we already have a good match: */ - if (s->prev_length >= s->good_match) { - chain_length >>= 2; - } - /* Do not look for matches beyond the end of the input. This is necessary - * to make deflate deterministic. - */ - if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - do { - Assert(cur_match < s->strstart, "no future"); - match = s->window + cur_match; - - /* Skip to next match if the match length cannot increase - * or if the match length is less than 2. Note that the checks below - * for insufficient lookahead only occur occasionally for performance - * reasons. Therefore uninitialized memory will be accessed, and - * conditional jumps will be made that depend on those values. - * However the length of the match is limited to the lookahead, so - * the output of deflate is not affected by the uninitialized values. - */ -#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) - /* This code assumes sizeof(unsigned short) == 2. Do not use - * UNALIGNED_OK if your compiler uses a different size. - */ - if (*(ushf*)(match+best_len-1) != scan_end || - *(ushf*)match != scan_start) continue; - - /* It is not necessary to compare scan[2] and match[2] since they are - * always equal when the other bytes match, given that the hash keys - * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at - * strstart+3, +5, ... up to strstart+257. We check for insufficient - * lookahead only every 4th comparison; the 128th check will be made - * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is - * necessary to put more guard bytes at the end of the window, or - * to check more often for insufficient lookahead. - */ - Assert(scan[2] == match[2], "scan[2]?"); - scan++, match++; - do { - } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - scan < strend); - /* The funny "do {}" generates better code on most compilers */ - - /* Here, scan <= window+strstart+257 */ - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - if (*scan == *match) scan++; - - len = (MAX_MATCH - 1) - (int)(strend-scan); - scan = strend - (MAX_MATCH-1); - -#else /* UNALIGNED_OK */ - - if (match[best_len] != scan_end || - match[best_len-1] != scan_end1 || - *match != *scan || - *++match != scan[1]) continue; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match++; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - scan = strend - MAX_MATCH; - -#endif /* UNALIGNED_OK */ - - if (len > best_len) { - s->match_start = cur_match; - best_len = len; - if (len >= nice_match) break; -#ifdef UNALIGNED_OK - scan_end = *(ushf*)(scan+best_len-1); -#else - scan_end1 = scan[best_len-1]; - scan_end = scan[best_len]; -#endif - } - } while ((cur_match = prev[cur_match & wmask]) > limit - && --chain_length != 0); - - if ((uInt)best_len <= s->lookahead) return (uInt)best_len; - return s->lookahead; -} -#endif /* ASMV */ -#endif /* FASTEST */ - -/* --------------------------------------------------------------------------- - * Optimized version for level == 1 or strategy == Z_RLE only - */ -local uInt longest_match_fast(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - Assert(cur_match < s->strstart, "no future"); - - match = s->window + cur_match; - - /* Return failure if the match length is less than 2: - */ - if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match += 2; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - - if (len < MIN_MATCH) return MIN_MATCH - 1; - - s->match_start = cur_match; - return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; -} - -#ifdef DEBUG -/* =========================================================================== - * Check that the match at match_start is indeed a match. - */ -local void check_match(s, start, match, length) - deflate_state *s; - IPos start, match; - int length; -{ - /* check that the match is indeed a match */ - if (zmemcmp(s->window + match, - s->window + start, length) != EQUAL) { - fprintf(stderr, " start %u, match %u, length %d\n", - start, match, length); - do { - fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); - } while (--length != 0); - z_error("invalid match"); - } - if (z_verbose > 1) { - fprintf(stderr,"\\[%d,%d]", start-match, length); - do { putc(s->window[start++], stderr); } while (--length != 0); - } -} -#else -# define check_match(s, start, match, length) -#endif /* DEBUG */ - -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ -local void fill_window(s) - deflate_state *s; -{ - register unsigned n, m; - register Posf *p; - unsigned more; /* Amount of free space at the end of the window. */ - uInt wsize = s->w_size; - - do { - more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); - - /* Deal with !@#$% 64K limit: */ - if (sizeof(int) <= 2) { - if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - more = wsize; - - } else if (more == (unsigned)(-1)) { - /* Very unlikely, but possible on 16 bit machine if - * strstart == 0 && lookahead == 1 (input done a byte at time) - */ - more--; - } - } - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (s->strstart >= wsize+MAX_DIST(s)) { - - zmemcpy(s->window, s->window+wsize, (unsigned)wsize); - s->match_start -= wsize; - s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ - s->block_start -= (long) wsize; - - /* Slide the hash table (could be avoided with 32 bit values - at the expense of memory usage). We slide even when level == 0 - to keep the hash table consistent if we switch back to level > 0 - later. (Using level 0 permanently is not an optimal usage of - zlib, so we don't care about this pathological case.) - */ - /* %%% avoid this when Z_RLE */ - n = s->hash_size; - p = &s->head[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - } while (--n); - - n = wsize; -#ifndef FASTEST - p = &s->prev[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); -#endif - more += wsize; - } - if (s->strm->avail_in == 0) return; - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - Assert(more >= 2, "more < 2"); - - n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); - s->lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s->lookahead >= MIN_MATCH) { - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ - - } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); -} - -/* =========================================================================== - * Flush the current block, with given end-of-file flag. - * IN assertion: strstart is set to the end of the current match. - */ -#define FLUSH_BLOCK_ONLY(s, eof) { \ - _tr_flush_block(s, (s->block_start >= 0L ? \ - (charf *)&s->window[(unsigned)s->block_start] : \ - (charf *)Z_NULL), \ - (ulg)((long)s->strstart - s->block_start), \ - (eof)); \ - s->block_start = s->strstart; \ - flush_pending(s->strm); \ - Tracev((stderr,"[FLUSH]")); \ -} - -/* Same but force premature exit if necessary. */ -#define FLUSH_BLOCK(s, eof) { \ - FLUSH_BLOCK_ONLY(s, eof); \ - if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ -} - -/* =========================================================================== - * Copy without compression as much as possible from the input stream, return - * the current block state. - * This function does not insert new strings in the dictionary since - * uncompressible data is probably not useful. This function is used - * only for the level=0 compression option. - * NOTE: this function should be optimized to avoid extra copying from - * window to pending_buf. - */ -local block_state deflate_stored(s, flush) - deflate_state *s; - int flush; -{ - /* Stored blocks are limited to 0xffff bytes, pending_buf is limited - * to pending_buf_size, and each stored block has a 5 byte header: - */ - ulg max_block_size = 0xffff; - ulg max_start; - - if (max_block_size > s->pending_buf_size - 5) { - max_block_size = s->pending_buf_size - 5; - } - - /* Copy as much as possible from input to output: */ - for (;;) { - /* Fill the window as much as possible: */ - if (s->lookahead <= 1) { - - Assert(s->strstart < s->w_size+MAX_DIST(s) || - s->block_start >= (long)s->w_size, "slide too late"); - - fill_window(s); - if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; - - if (s->lookahead == 0) break; /* flush the current block */ - } - Assert(s->block_start >= 0L, "block gone"); - - s->strstart += s->lookahead; - s->lookahead = 0; - - /* Emit a stored block if pending_buf will be full: */ - max_start = s->block_start + max_block_size; - if (s->strstart == 0 || (ulg)s->strstart >= max_start) { - /* strstart == 0 is possible when wraparound on 16-bit machine */ - s->lookahead = (uInt)(s->strstart - max_start); - s->strstart = (uInt)max_start; - FLUSH_BLOCK(s, 0); - } - /* Flush if we may have to slide, otherwise block_start may become - * negative and the data will be gone: - */ - if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { - FLUSH_BLOCK(s, 0); - } - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} - -/* =========================================================================== - * Compress as much as possible from the input stream, return the current - * block state. - * This function does not perform lazy evaluation of matches and inserts - * new strings in the dictionary only for unmatched strings or for short - * matches. It is used only for the fast compression options. - */ -local block_state deflate_fast(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head = NIL; /* head of the hash chain */ - int bflush; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - * At this point we have always match_length < MIN_MATCH - */ - if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ -#ifdef FASTEST - if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || - (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { - s->match_length = longest_match_fast (s, hash_head); - } -#else - if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { - s->match_length = longest_match (s, hash_head); - } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { - s->match_length = longest_match_fast (s, hash_head); - } -#endif - /* longest_match() or longest_match_fast() sets match_start */ - } - if (s->match_length >= MIN_MATCH) { - check_match(s, s->strstart, s->match_start, s->match_length); - - _tr_tally_dist(s, s->strstart - s->match_start, - s->match_length - MIN_MATCH, bflush); - - s->lookahead -= s->match_length; - - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ -#ifndef FASTEST - if (s->match_length <= s->max_insert_length && - s->lookahead >= MIN_MATCH) { - s->match_length--; /* string at strstart already in table */ - do { - s->strstart++; - INSERT_STRING(s, s->strstart, hash_head); - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. - */ - } while (--s->match_length != 0); - s->strstart++; - } else -#endif - { - s->strstart += s->match_length; - s->match_length = 0; - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not - * matter since it will be recomputed at next deflate call. - */ - } - } else { - /* No match, output a literal byte */ - Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - } - if (bflush) FLUSH_BLOCK(s, 0); - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} - -#ifndef FASTEST -/* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ -local block_state deflate_slow(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head = NIL; /* head of hash chain */ - int bflush; /* set if current block must be flushed */ - - /* Process the input block. */ - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - */ - s->prev_length = s->match_length, s->prev_match = s->match_start; - s->match_length = MIN_MATCH-1; - - if (hash_head != NIL && s->prev_length < s->max_lazy_match && - s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { - s->match_length = longest_match (s, hash_head); - } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { - s->match_length = longest_match_fast (s, hash_head); - } - /* longest_match() or longest_match_fast() sets match_start */ - - if (s->match_length <= 5 && (s->strategy == Z_FILTERED -#if TOO_FAR <= 32767 - || (s->match_length == MIN_MATCH && - s->strstart - s->match_start > TOO_FAR) -#endif - )) { - - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - s->match_length = MIN_MATCH-1; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { - uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; - /* Do not insert strings in hash table beyond this. */ - - check_match(s, s->strstart-1, s->prev_match, s->prev_length); - - _tr_tally_dist(s, s->strstart -1 - s->prev_match, - s->prev_length - MIN_MATCH, bflush); - - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not - * enough lookahead, the last two strings are not inserted in - * the hash table. - */ - s->lookahead -= s->prev_length-1; - s->prev_length -= 2; - do { - if (++s->strstart <= max_insert) { - INSERT_STRING(s, s->strstart, hash_head); - } - } while (--s->prev_length != 0); - s->match_available = 0; - s->match_length = MIN_MATCH-1; - s->strstart++; - - if (bflush) FLUSH_BLOCK(s, 0); - - } else if (s->match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - if (bflush) { - FLUSH_BLOCK_ONLY(s, 0); - } - s->strstart++; - s->lookahead--; - if (s->strm->avail_out == 0) return need_more; - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - s->match_available = 1; - s->strstart++; - s->lookahead--; - } - } - Assert (flush != Z_NO_FLUSH, "no flush?"); - if (s->match_available) { - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - s->match_available = 0; - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} -#endif /* FASTEST */ - -#if 0 -/* =========================================================================== - * For Z_RLE, simply look for runs of bytes, generate matches only of distance - * one. Do not maintain a hash table. (It will be regenerated if this run of - * deflate switches away from Z_RLE.) - */ -local block_state deflate_rle(s, flush) - deflate_state *s; - int flush; -{ - int bflush; /* set if current block must be flushed */ - uInt run; /* length of run */ - uInt max; /* maximum length of run */ - uInt prev; /* byte at distance one to match */ - Bytef *scan; /* scan for end of run */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the longest encodable run. - */ - if (s->lookahead < MAX_MATCH) { - fill_window(s); - if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* See how many times the previous byte repeats */ - run = 0; - if (s->strstart > 0) { /* if there is a previous byte, that is */ - max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; - scan = s->window + s->strstart - 1; - prev = *scan++; - do { - if (*scan++ != prev) - break; - } while (++run < max); - } - - /* Emit match if have run of MIN_MATCH or longer, else emit literal */ - if (run >= MIN_MATCH) { - check_match(s, s->strstart, s->strstart - 1, run); - _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); - s->lookahead -= run; - s->strstart += run; - } else { - /* No match, output a literal byte */ - Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - } - if (bflush) FLUSH_BLOCK(s, 0); - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} -#endif +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); + dictionary += dictLength - length; /* use the tail of the dictionary */ + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy(dest, source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy(ds, ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + /* %%% avoid this when Z_RLE */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ + +#if 0 +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt run; /* length of run */ + uInt max; /* maximum length of run */ + uInt prev; /* byte at distance one to match */ + Bytef *scan; /* scan for end of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest encodable run. + */ + if (s->lookahead < MAX_MATCH) { + fill_window(s); + if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + run = 0; + if (s->strstart > 0) { /* if there is a previous byte, that is */ + max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; + scan = s->window + s->strstart - 1; + prev = *scan++; + do { + if (*scan++ != prev) + break; + } while (++run < max); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (run >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, run); + _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); + s->lookahead -= run; + s->strstart += run; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif diff --git a/plugins/CDVDiso/src/3rdparty/zlib/deflate.h b/plugins/CDVDiso/src/3rdparty/zlib/deflate.h index 222c53e043..05a5ab3a2c 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/deflate.h +++ b/plugins/CDVDiso/src/3rdparty/zlib/deflate.h @@ -1,331 +1,331 @@ -/* deflate.h -- internal compression state - * Copyright (C) 1995-2004 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id$ */ - -#ifndef DEFLATE_H -#define DEFLATE_H - -#include "zutil.h" - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer creation by deflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip encoding - should be left enabled. */ -#ifndef NO_GZIP -# define GZIP -#endif - -/* =========================================================================== - * Internal compression state. - */ - -#define LENGTH_CODES 29 -/* number of length codes, not counting the special END_BLOCK code */ - -#define LITERALS 256 -/* number of literal bytes 0..255 */ - -#define L_CODES (LITERALS+1+LENGTH_CODES) -/* number of Literal or Length codes, including the END_BLOCK code */ - -#define D_CODES 30 -/* number of distance codes */ - -#define BL_CODES 19 -/* number of codes used to transfer the bit lengths */ - -#define HEAP_SIZE (2*L_CODES+1) -/* maximum heap size */ - -#define MAX_BITS 15 -/* All codes must not exceed MAX_BITS bits */ - -#define INIT_STATE 42 -#define EXTRA_STATE 69 -#define NAME_STATE 73 -#define COMMENT_STATE 91 -#define HCRC_STATE 103 -#define BUSY_STATE 113 -#define FINISH_STATE 666 -/* Stream status */ - - -/* Data structure describing a single value and its code string. */ -typedef struct ct_data_s { - union { - ush freq; /* frequency count */ - ush code; /* bit string */ - } fc; - union { - ush dad; /* father node in Huffman tree */ - ush len; /* length of bit string */ - } dl; -} FAR ct_data; - -#define Freq fc.freq -#define Code fc.code -#define Dad dl.dad -#define Len dl.len - -typedef struct static_tree_desc_s static_tree_desc; - -typedef struct tree_desc_s { - ct_data *dyn_tree; /* the dynamic tree */ - int max_code; /* largest code with non zero frequency */ - static_tree_desc *stat_desc; /* the corresponding static tree */ -} FAR tree_desc; - -typedef ush Pos; -typedef Pos FAR Posf; -typedef unsigned IPos; - -/* A Pos is an index in the character window. We use short instead of int to - * save space in the various tables. IPos is used only for parameter passing. - */ - -typedef struct internal_state { - z_streamp strm; /* pointer back to this zlib stream */ - int status; /* as the name implies */ - Bytef *pending_buf; /* output still pending */ - ulg pending_buf_size; /* size of pending_buf */ - Bytef *pending_out; /* next pending byte to output to the stream */ - uInt pending; /* nb of bytes in the pending buffer */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - gz_headerp gzhead; /* gzip header information to write */ - uInt gzindex; /* where in extra, name, or comment */ - Byte method; /* STORED (for zip only) or DEFLATED */ - int last_flush; /* value of flush param for previous deflate call */ - - /* used by deflate.c: */ - - uInt w_size; /* LZ77 window size (32K by default) */ - uInt w_bits; /* log2(w_size) (8..16) */ - uInt w_mask; /* w_size - 1 */ - - Bytef *window; - /* Sliding window. Input bytes are read into the second half of the window, - * and move to the first half later to keep a dictionary of at least wSize - * bytes. With this organization, matches are limited to a distance of - * wSize-MAX_MATCH bytes, but this ensures that IO is always - * performed with a length multiple of the block size. Also, it limits - * the window size to 64K, which is quite useful on MSDOS. - * To do: use the user input buffer as sliding window. - */ - - ulg window_size; - /* Actual size of window: 2*wSize, except when the user input buffer - * is directly used as sliding window. - */ - - Posf *prev; - /* Link to older string with same hash index. To limit the size of this - * array to 64K, this link is maintained only for the last 32K strings. - * An index in this array is thus a window index modulo 32K. - */ - - Posf *head; /* Heads of the hash chains or NIL. */ - - uInt ins_h; /* hash index of string to be inserted */ - uInt hash_size; /* number of elements in hash table */ - uInt hash_bits; /* log2(hash_size) */ - uInt hash_mask; /* hash_size-1 */ - - uInt hash_shift; - /* Number of bits by which ins_h must be shifted at each input - * step. It must be such that after MIN_MATCH steps, the oldest - * byte no longer takes part in the hash key, that is: - * hash_shift * MIN_MATCH >= hash_bits - */ - - long block_start; - /* Window position at the beginning of the current output block. Gets - * negative when the window is moved backwards. - */ - - uInt match_length; /* length of best match */ - IPos prev_match; /* previous match */ - int match_available; /* set if previous match exists */ - uInt strstart; /* start of string to insert */ - uInt match_start; /* start of matching string */ - uInt lookahead; /* number of valid bytes ahead in window */ - - uInt prev_length; - /* Length of the best match at previous step. Matches not greater than this - * are discarded. This is used in the lazy match evaluation. - */ - - uInt max_chain_length; - /* To speed up deflation, hash chains are never searched beyond this - * length. A higher limit improves compression ratio but degrades the - * speed. - */ - - uInt max_lazy_match; - /* Attempt to find a better match only when the current match is strictly - * smaller than this value. This mechanism is used only for compression - * levels >= 4. - */ -# define max_insert_length max_lazy_match - /* Insert new strings in the hash table only if the match length is not - * greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 3. - */ - - int level; /* compression level (1..9) */ - int strategy; /* favor or force Huffman coding*/ - - uInt good_match; - /* Use a faster search when the previous match is longer than this */ - - int nice_match; /* Stop searching when current match exceeds this */ - - /* used by trees.c: */ - /* Didn't use ct_data typedef below to supress compiler warning */ - struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ - struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ - struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ - - struct tree_desc_s l_desc; /* desc. for literal tree */ - struct tree_desc_s d_desc; /* desc. for distance tree */ - struct tree_desc_s bl_desc; /* desc. for bit length tree */ - - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ - int heap_len; /* number of elements in the heap */ - int heap_max; /* element of largest frequency */ - /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - * The same heap array is used to build all trees. - */ - - uch depth[2*L_CODES+1]; - /* Depth of each subtree used as tie breaker for trees of equal frequency - */ - - uchf *l_buf; /* buffer for literals or lengths */ - - uInt lit_bufsize; - /* Size of match buffer for literals/lengths. There are 4 reasons for - * limiting lit_bufsize to 64K: - * - frequencies can be kept in 16 bit counters - * - if compression is not successful for the first block, all input - * data is still in the window so we can still emit a stored block even - * when input comes from standard input. (This can also be done for - * all blocks if lit_bufsize is not greater than 32K.) - * - if compression is not successful for a file smaller than 64K, we can - * even emit a stored file instead of a stored block (saving 5 bytes). - * This is applicable only for zip (not gzip or zlib). - * - creating new Huffman trees less frequently may not provide fast - * adaptation to changes in the input data statistics. (Take for - * example a binary file with poorly compressible code followed by - * a highly compressible string table.) Smaller buffer sizes give - * fast adaptation but have of course the overhead of transmitting - * trees more frequently. - * - I can't count above 4 - */ - - uInt last_lit; /* running index in l_buf */ - - ushf *d_buf; - /* Buffer for distances. To simplify the code, d_buf and l_buf have - * the same number of elements. To use different lengths, an extra flag - * array would be necessary. - */ - - ulg opt_len; /* bit length of current block with optimal trees */ - ulg static_len; /* bit length of current block with static trees */ - uInt matches; /* number of string matches in current block */ - int last_eob_len; /* bit length of EOB code for last block */ - -#ifdef DEBUG - ulg compressed_len; /* total bit length of compressed file mod 2^32 */ - ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ -#endif - - ush bi_buf; - /* Output buffer. bits are inserted starting at the bottom (least - * significant bits). - */ - int bi_valid; - /* Number of valid bits in bi_buf. All bits above the last valid bit - * are always zero. - */ - -} FAR deflate_state; - -/* Output a byte on the stream. - * IN assertion: there is enough room in pending_buf. - */ -#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} - - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) -/* In order to simplify the code, particularly on 16 bit machines, match - * distances are limited to MAX_DIST instead of WSIZE. - */ - - /* in trees.c */ -void _tr_init OF((deflate_state *s)); -int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); -void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); -void _tr_align OF((deflate_state *s)); -void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); - -#define d_code(dist) \ - ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) -/* Mapping from a distance to a distance code. dist is the distance - 1 and - * must not have side effects. _dist_code[256] and _dist_code[257] are never - * used. - */ - -#ifndef DEBUG -/* Inline versions of _tr_tally for speed: */ - -#if defined(GEN_TREES_H) || !defined(STDC) - extern uch _length_code[]; - extern uch _dist_code[]; -#else - extern const uch _length_code[]; - extern const uch _dist_code[]; -#endif - -# define _tr_tally_lit(s, c, flush) \ - { uch cc = (c); \ - s->d_buf[s->last_lit] = 0; \ - s->l_buf[s->last_lit++] = cc; \ - s->dyn_ltree[cc].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -# define _tr_tally_dist(s, distance, length, flush) \ - { uch len = (length); \ - ush dist = (distance); \ - s->d_buf[s->last_lit] = dist; \ - s->l_buf[s->last_lit++] = len; \ - dist--; \ - s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ - s->dyn_dtree[d_code(dist)].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -#else -# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) -# define _tr_tally_dist(s, distance, length, flush) \ - flush = _tr_tally(s, distance, length) -#endif - -#endif /* DEFLATE_H */ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2004 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/plugins/CDVDiso/src/3rdparty/zlib/gzio.c b/plugins/CDVDiso/src/3rdparty/zlib/gzio.c index 2de9a36441..b3c59ecd4c 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/gzio.c +++ b/plugins/CDVDiso/src/3rdparty/zlib/gzio.c @@ -1,1026 +1,1026 @@ -/* gzio.c -- IO on .gz files - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. - */ - -/* @(#) $Id$ */ - -#include - -#include "zutil.h" - -#ifdef NO_DEFLATE /* for compatibility with old definition */ -# define NO_GZCOMPRESS -#endif - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -#ifndef Z_BUFSIZE -# ifdef MAXSEG_64K -# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ -# else -# define Z_BUFSIZE 16384 -# endif -#endif -#ifndef Z_PRINTF_BUFSIZE -# define Z_PRINTF_BUFSIZE 4096 -#endif - -#ifdef __MVS__ -# pragma map (fdopen , "\174\174FDOPEN") - FILE *fdopen(int, const char *); -#endif - -#ifndef STDC -extern voidp malloc OF((uInt size)); -extern void free OF((voidpf ptr)); -#endif - -#define ALLOC(size) malloc(size) -#define TRYFREE(p) {if (p) free(p);} - -static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ - -/* gzip flag byte */ -#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ -#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ -#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ -#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ -#define COMMENT 0x10 /* bit 4 set: file comment present */ -#define RESERVED 0xE0 /* bits 5..7: reserved */ - -typedef struct gz_stream { - z_stream stream; - int z_err; /* error code for last stream operation */ - int z_eof; /* set if end of input file */ - FILE *file; /* .gz file */ - Byte *inbuf; /* input buffer */ - Byte *outbuf; /* output buffer */ - uLong crc; /* crc32 of uncompressed data */ - char *msg; /* error message */ - char *path; /* path name for debugging only */ - int transparent; /* 1 if input file is not a .gz file */ - char mode; /* 'w' or 'r' */ - z_off_t start; /* start of compressed data in file (header skipped) */ - z_off_t in; /* bytes into deflate or inflate */ - z_off_t out; /* bytes out of deflate or inflate */ - int back; /* one character push-back */ - int last; /* true if push-back is last character */ -} gz_stream; - - -local gzFile gz_open OF((const char *path, const char *mode, int fd)); -local int do_flush OF((gzFile file, int flush)); -local int get_byte OF((gz_stream *s)); -local void check_header OF((gz_stream *s)); -local int destroy OF((gz_stream *s)); -local void putLong OF((FILE *file, uLong x)); -local uLong getLong OF((gz_stream *s)); - -/* =========================================================================== - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb"). The file is given either by file descriptor - or path name (if fd == -1). - gz_open returns NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). -*/ -local gzFile gz_open (path, mode, fd) - const char *path; - const char *mode; - int fd; -{ - int err; - int level = Z_BEST_SPEED; /* compression level */ - int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ - char *p = (char*)mode; - gz_stream *s; - char fmode[80]; /* copy of mode, without the compression level */ - char *m = fmode; - - if (!path || !mode) return Z_NULL; - - s = (gz_stream *)ALLOC(sizeof(gz_stream)); - if (!s) return Z_NULL; - - s->stream.zalloc = (alloc_func)0; - s->stream.zfree = (free_func)0; - s->stream.opaque = (voidpf)0; - s->stream.next_in = s->inbuf = Z_NULL; - s->stream.next_out = s->outbuf = Z_NULL; - s->stream.avail_in = s->stream.avail_out = 0; - s->file = NULL; - s->z_err = Z_OK; - s->z_eof = 0; - s->in = 0; - s->out = 0; - s->back = EOF; - s->crc = crc32(0L, Z_NULL, 0); - s->msg = NULL; - s->transparent = 0; - - s->path = (char*)ALLOC(strlen(path)+1); - if (s->path == NULL) { - return destroy(s), (gzFile)Z_NULL; - } - strcpy(s->path, path); /* do this early for debugging */ - - s->mode = '\0'; - do { - if (*p == 'r') s->mode = 'r'; - if (*p == 'w' || *p == 'a') s->mode = 'w'; - if (*p >= '0' && *p <= '9') { - level = *p - '0'; - } else if (*p == 'f') { - strategy = Z_FILTERED; - } else if (*p == 'h') { - strategy = Z_HUFFMAN_ONLY; - } else if (*p == 'R') { - strategy = Z_RLE; - } else { - *m++ = *p; /* copy the mode */ - } - } while (*p++ && m != fmode + sizeof(fmode)); - if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - err = Z_STREAM_ERROR; -#else - err = deflateInit2(&(s->stream), level, - Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); - /* windowBits is passed < 0 to suppress zlib header */ - - s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); -#endif - if (err != Z_OK || s->outbuf == Z_NULL) { - return destroy(s), (gzFile)Z_NULL; - } - } else { - s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); - - err = inflateInit2(&(s->stream), -MAX_WBITS); - /* windowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are - * present after the compressed stream. - */ - if (err != Z_OK || s->inbuf == Z_NULL) { - return destroy(s), (gzFile)Z_NULL; - } - } - s->stream.avail_out = Z_BUFSIZE; - - errno = 0; - s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); - - if (s->file == NULL) { - return destroy(s), (gzFile)Z_NULL; - } - if (s->mode == 'w') { - /* Write a very simple .gz header: - */ - fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], - Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); - s->start = 10L; - /* We use 10L instead of ftell(s->file) to because ftell causes an - * fflush on some systems. This version of the library doesn't use - * start anyway in write mode, so this initialization is not - * necessary. - */ - } else { - check_header(s); /* skip the .gz header */ - s->start = ftell(s->file) - s->stream.avail_in; - } - - return (gzFile)s; -} - -/* =========================================================================== - Opens a gzip (.gz) file for reading or writing. -*/ -gzFile ZEXPORT gzopen (path, mode) - const char *path; - const char *mode; -{ - return gz_open (path, mode, -1); -} - -/* =========================================================================== - Associate a gzFile with the file descriptor fd. fd is not dup'ed here - to mimic the behavio(u)r of fdopen. -*/ -gzFile ZEXPORT gzdopen (fd, mode) - int fd; - const char *mode; -{ - char name[46]; /* allow for up to 128-bit integers */ - - if (fd < 0) return (gzFile)Z_NULL; - sprintf(name, "", fd); /* for debugging */ - - return gz_open (name, mode, fd); -} - -/* =========================================================================== - * Update the compression level and strategy - */ -int ZEXPORT gzsetparams (file, level, strategy) - gzFile file; - int level; - int strategy; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - /* Make room to allow flushing */ - if (s->stream.avail_out == 0) { - - s->stream.next_out = s->outbuf; - if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { - s->z_err = Z_ERRNO; - } - s->stream.avail_out = Z_BUFSIZE; - } - - return deflateParams (&(s->stream), level, strategy); -} - -/* =========================================================================== - Read a byte from a gz_stream; update next_in and avail_in. Return EOF - for end of file. - IN assertion: the stream s has been sucessfully opened for reading. -*/ -local int get_byte(s) - gz_stream *s; -{ - if (s->z_eof) return EOF; - if (s->stream.avail_in == 0) { - errno = 0; - s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); - if (s->stream.avail_in == 0) { - s->z_eof = 1; - if (ferror(s->file)) s->z_err = Z_ERRNO; - return EOF; - } - s->stream.next_in = s->inbuf; - } - s->stream.avail_in--; - return *(s->stream.next_in)++; -} - -/* =========================================================================== - Check the gzip header of a gz_stream opened for reading. Set the stream - mode to transparent if the gzip magic header is not present; set s->err - to Z_DATA_ERROR if the magic header is present but the rest of the header - is incorrect. - IN assertion: the stream s has already been created sucessfully; - s->stream.avail_in is zero for the first time, but may be non-zero - for concatenated .gz files. -*/ -local void check_header(s) - gz_stream *s; -{ - int method; /* method byte */ - int flags; /* flags byte */ - uInt len; - int c; - - /* Assure two bytes in the buffer so we can peek ahead -- handle case - where first byte of header is at the end of the buffer after the last - gzip segment */ - len = s->stream.avail_in; - if (len < 2) { - if (len) s->inbuf[0] = s->stream.next_in[0]; - errno = 0; - len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); - if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; - s->stream.avail_in += len; - s->stream.next_in = s->inbuf; - if (s->stream.avail_in < 2) { - s->transparent = s->stream.avail_in; - return; - } - } - - /* Peek ahead to check the gzip magic header */ - if (s->stream.next_in[0] != gz_magic[0] || - s->stream.next_in[1] != gz_magic[1]) { - s->transparent = 1; - return; - } - s->stream.avail_in -= 2; - s->stream.next_in += 2; - - /* Check the rest of the gzip header */ - method = get_byte(s); - flags = get_byte(s); - if (method != Z_DEFLATED || (flags & RESERVED) != 0) { - s->z_err = Z_DATA_ERROR; - return; - } - - /* Discard time, xflags and OS code: */ - for (len = 0; len < 6; len++) (void)get_byte(s); - - if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ - len = (uInt)get_byte(s); - len += ((uInt)get_byte(s))<<8; - /* len is garbage if EOF but the loop below will quit anyway */ - while (len-- != 0 && get_byte(s) != EOF) ; - } - if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ - while ((c = get_byte(s)) != 0 && c != EOF) ; - } - if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ - while ((c = get_byte(s)) != 0 && c != EOF) ; - } - if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ - for (len = 0; len < 2; len++) (void)get_byte(s); - } - s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; -} - - /* =========================================================================== - * Cleanup then free the given gz_stream. Return a zlib error code. - Try freeing in the reverse order of allocations. - */ -local int destroy (s) - gz_stream *s; -{ - int err = Z_OK; - - if (!s) return Z_STREAM_ERROR; - - TRYFREE(s->msg); - - if (s->stream.state != NULL) { - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - err = Z_STREAM_ERROR; -#else - err = deflateEnd(&(s->stream)); -#endif - } else if (s->mode == 'r') { - err = inflateEnd(&(s->stream)); - } - } - if (s->file != NULL && fclose(s->file)) { -#ifdef ESPIPE - if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ -#endif - err = Z_ERRNO; - } - if (s->z_err < 0) err = s->z_err; - - TRYFREE(s->inbuf); - TRYFREE(s->outbuf); - TRYFREE(s->path); - TRYFREE(s); - return err; -} - -/* =========================================================================== - Reads the given number of uncompressed bytes from the compressed file. - gzread returns the number of bytes actually read (0 for end of file). -*/ -int ZEXPORT gzread (file, buf, len) - gzFile file; - voidp buf; - unsigned len; -{ - gz_stream *s = (gz_stream*)file; - Bytef *start = (Bytef*)buf; /* starting point for crc computation */ - Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ - - if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; - - if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; - if (s->z_err == Z_STREAM_END) return 0; /* EOF */ - - next_out = (Byte*)buf; - s->stream.next_out = (Bytef*)buf; - s->stream.avail_out = len; - - if (s->stream.avail_out && s->back != EOF) { - *next_out++ = s->back; - s->stream.next_out++; - s->stream.avail_out--; - s->back = EOF; - s->out++; - start++; - if (s->last) { - s->z_err = Z_STREAM_END; - return 1; - } - } - - while (s->stream.avail_out != 0) { - - if (s->transparent) { - /* Copy first the lookahead bytes: */ - uInt n = s->stream.avail_in; - if (n > s->stream.avail_out) n = s->stream.avail_out; - if (n > 0) { - zmemcpy(s->stream.next_out, s->stream.next_in, n); - next_out += n; - s->stream.next_out = next_out; - s->stream.next_in += n; - s->stream.avail_out -= n; - s->stream.avail_in -= n; - } - if (s->stream.avail_out > 0) { - s->stream.avail_out -= - (uInt)fread(next_out, 1, s->stream.avail_out, s->file); - } - len -= s->stream.avail_out; - s->in += len; - s->out += len; - if (len == 0) s->z_eof = 1; - return (int)len; - } - if (s->stream.avail_in == 0 && !s->z_eof) { - - errno = 0; - s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); - if (s->stream.avail_in == 0) { - s->z_eof = 1; - if (ferror(s->file)) { - s->z_err = Z_ERRNO; - break; - } - } - s->stream.next_in = s->inbuf; - } - s->in += s->stream.avail_in; - s->out += s->stream.avail_out; - s->z_err = inflate(&(s->stream), Z_NO_FLUSH); - s->in -= s->stream.avail_in; - s->out -= s->stream.avail_out; - - if (s->z_err == Z_STREAM_END) { - /* Check CRC and original size */ - s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); - start = s->stream.next_out; - - if (getLong(s) != s->crc) { - s->z_err = Z_DATA_ERROR; - } else { - (void)getLong(s); - /* The uncompressed length returned by above getlong() may be - * different from s->out in case of concatenated .gz files. - * Check for such files: - */ - check_header(s); - if (s->z_err == Z_OK) { - inflateReset(&(s->stream)); - s->crc = crc32(0L, Z_NULL, 0); - } - } - } - if (s->z_err != Z_OK || s->z_eof) break; - } - s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); - - if (len == s->stream.avail_out && - (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) - return -1; - return (int)(len - s->stream.avail_out); -} - - -/* =========================================================================== - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. -*/ -int ZEXPORT gzgetc(file) - gzFile file; -{ - unsigned char c; - - return gzread(file, &c, 1) == 1 ? c : -1; -} - - -/* =========================================================================== - Push one byte back onto the stream. -*/ -int ZEXPORT gzungetc(c, file) - int c; - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; - s->back = c; - s->out--; - s->last = (s->z_err == Z_STREAM_END); - if (s->last) s->z_err = Z_OK; - s->z_eof = 0; - return c; -} - - -/* =========================================================================== - Reads bytes from the compressed file until len-1 characters are - read, or a newline character is read and transferred to buf, or an - end-of-file condition is encountered. The string is then terminated - with a null character. - gzgets returns buf, or Z_NULL in case of error. - - The current implementation is not optimized at all. -*/ -char * ZEXPORT gzgets(file, buf, len) - gzFile file; - char *buf; - int len; -{ - char *b = buf; - if (buf == Z_NULL || len <= 0) return Z_NULL; - - while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; - *buf = '\0'; - return b == buf && len > 0 ? Z_NULL : b; -} - - -#ifndef NO_GZCOMPRESS -/* =========================================================================== - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of bytes actually written (0 in case of error). -*/ -int ZEXPORT gzwrite (file, buf, len) - gzFile file; - voidpc buf; - unsigned len; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - s->stream.next_in = (Bytef*)buf; - s->stream.avail_in = len; - - while (s->stream.avail_in != 0) { - - if (s->stream.avail_out == 0) { - - s->stream.next_out = s->outbuf; - if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { - s->z_err = Z_ERRNO; - break; - } - s->stream.avail_out = Z_BUFSIZE; - } - s->in += s->stream.avail_in; - s->out += s->stream.avail_out; - s->z_err = deflate(&(s->stream), Z_NO_FLUSH); - s->in -= s->stream.avail_in; - s->out -= s->stream.avail_out; - if (s->z_err != Z_OK) break; - } - s->crc = crc32(s->crc, (const Bytef *)buf, len); - - return (int)(len - s->stream.avail_in); -} - - -/* =========================================================================== - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). -*/ -#ifdef STDC -#include - -int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) -{ - char buf[Z_PRINTF_BUFSIZE]; - va_list va; - int len; - - buf[sizeof(buf) - 1] = 0; - va_start(va, format); -#ifdef NO_vsnprintf -# ifdef HAS_vsprintf_void - (void)vsprintf(buf, format, va); - va_end(va); - for (len = 0; len < sizeof(buf); len++) - if (buf[len] == 0) break; -# else - len = vsprintf(buf, format, va); - va_end(va); -# endif -#else -# ifdef HAS_vsnprintf_void - (void)vsnprintf(buf, sizeof(buf), format, va); - va_end(va); - len = strlen(buf); -# else - len = vsnprintf(buf, sizeof(buf), format, va); - va_end(va); -# endif -#endif - if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) - return 0; - return gzwrite(file, buf, (unsigned)len); -} -#else /* not ANSI C */ - -int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) - gzFile file; - const char *format; - int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; -{ - char buf[Z_PRINTF_BUFSIZE]; - int len; - - buf[sizeof(buf) - 1] = 0; -#ifdef NO_snprintf -# ifdef HAS_sprintf_void - sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); - for (len = 0; len < sizeof(buf); len++) - if (buf[len] == 0) break; -# else - len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); -# endif -#else -# ifdef HAS_snprintf_void - snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); - len = strlen(buf); -# else - len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); -# endif -#endif - if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) - return 0; - return gzwrite(file, buf, len); -} -#endif - -/* =========================================================================== - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. -*/ -int ZEXPORT gzputc(file, c) - gzFile file; - int c; -{ - unsigned char cc = (unsigned char) c; /* required for big endian systems */ - - return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; -} - - -/* =========================================================================== - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. -*/ -int ZEXPORT gzputs(file, s) - gzFile file; - const char *s; -{ - return gzwrite(file, (char*)s, (unsigned)strlen(s)); -} - - -/* =========================================================================== - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. -*/ -local int do_flush (file, flush) - gzFile file; - int flush; -{ - uInt len; - int done = 0; - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - s->stream.avail_in = 0; /* should be zero already anyway */ - - for (;;) { - len = Z_BUFSIZE - s->stream.avail_out; - - if (len != 0) { - if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { - s->z_err = Z_ERRNO; - return Z_ERRNO; - } - s->stream.next_out = s->outbuf; - s->stream.avail_out = Z_BUFSIZE; - } - if (done) break; - s->out += s->stream.avail_out; - s->z_err = deflate(&(s->stream), flush); - s->out -= s->stream.avail_out; - - /* Ignore the second of two consecutive flushes: */ - if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; - - /* deflate has finished flushing only when it hasn't used up - * all the available space in the output buffer: - */ - done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); - - if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; - } - return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; -} - -int ZEXPORT gzflush (file, flush) - gzFile file; - int flush; -{ - gz_stream *s = (gz_stream*)file; - int err = do_flush (file, flush); - - if (err) return err; - fflush(s->file); - return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; -} -#endif /* NO_GZCOMPRESS */ - -/* =========================================================================== - Sets the starting position for the next gzread or gzwrite on the given - compressed file. The offset represents a number of bytes in the - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error. - SEEK_END is not implemented, returns error. - In this version of the library, gzseek can be extremely slow. -*/ -z_off_t ZEXPORT gzseek (file, offset, whence) - gzFile file; - z_off_t offset; - int whence; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || whence == SEEK_END || - s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { - return -1L; - } - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - return -1L; -#else - if (whence == SEEK_SET) { - offset -= s->in; - } - if (offset < 0) return -1L; - - /* At this point, offset is the number of zero bytes to write. */ - if (s->inbuf == Z_NULL) { - s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ - if (s->inbuf == Z_NULL) return -1L; - zmemzero(s->inbuf, Z_BUFSIZE); - } - while (offset > 0) { - uInt size = Z_BUFSIZE; - if (offset < Z_BUFSIZE) size = (uInt)offset; - - size = gzwrite(file, s->inbuf, size); - if (size == 0) return -1L; - - offset -= size; - } - return s->in; -#endif - } - /* Rest of function is for reading only */ - - /* compute absolute position */ - if (whence == SEEK_CUR) { - offset += s->out; - } - if (offset < 0) return -1L; - - if (s->transparent) { - /* map to fseek */ - s->back = EOF; - s->stream.avail_in = 0; - s->stream.next_in = s->inbuf; - if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; - - s->in = s->out = offset; - return offset; - } - - /* For a negative seek, rewind and use positive seek */ - if (offset >= s->out) { - offset -= s->out; - } else if (gzrewind(file) < 0) { - return -1L; - } - /* offset is now the number of bytes to skip. */ - - if (offset != 0 && s->outbuf == Z_NULL) { - s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); - if (s->outbuf == Z_NULL) return -1L; - } - if (offset && s->back != EOF) { - s->back = EOF; - s->out++; - offset--; - if (s->last) s->z_err = Z_STREAM_END; - } - while (offset > 0) { - int size = Z_BUFSIZE; - if (offset < Z_BUFSIZE) size = (int)offset; - - size = gzread(file, s->outbuf, (uInt)size); - if (size <= 0) return -1L; - offset -= size; - } - return s->out; -} - -/* =========================================================================== - Rewinds input file. -*/ -int ZEXPORT gzrewind (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'r') return -1; - - s->z_err = Z_OK; - s->z_eof = 0; - s->back = EOF; - s->stream.avail_in = 0; - s->stream.next_in = s->inbuf; - s->crc = crc32(0L, Z_NULL, 0); - if (!s->transparent) (void)inflateReset(&s->stream); - s->in = 0; - s->out = 0; - return fseek(s->file, s->start, SEEK_SET); -} - -/* =========================================================================== - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. -*/ -z_off_t ZEXPORT gztell (file) - gzFile file; -{ - return gzseek(file, 0L, SEEK_CUR); -} - -/* =========================================================================== - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. -*/ -int ZEXPORT gzeof (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - /* With concatenated compressed files that can have embedded - * crc trailers, z_eof is no longer the only/best indicator of EOF - * on a gz_stream. Handle end-of-stream error explicitly here. - */ - if (s == NULL || s->mode != 'r') return 0; - if (s->z_eof) return 1; - return s->z_err == Z_STREAM_END; -} - -/* =========================================================================== - Returns 1 if reading and doing so transparently, otherwise zero. -*/ -int ZEXPORT gzdirect (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'r') return 0; - return s->transparent; -} - -/* =========================================================================== - Outputs a long in LSB order to the given file -*/ -local void putLong (file, x) - FILE *file; - uLong x; -{ - int n; - for (n = 0; n < 4; n++) { - fputc((int)(x & 0xff), file); - x >>= 8; - } -} - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets z_err in case - of error. -*/ -local uLong getLong (s) - gz_stream *s; -{ - uLong x = (uLong)get_byte(s); - int c; - - x += ((uLong)get_byte(s))<<8; - x += ((uLong)get_byte(s))<<16; - c = get_byte(s); - if (c == EOF) s->z_err = Z_DATA_ERROR; - x += ((uLong)c)<<24; - return x; -} - -/* =========================================================================== - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. -*/ -int ZEXPORT gzclose (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL) return Z_STREAM_ERROR; - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - return Z_STREAM_ERROR; -#else - if (do_flush (file, Z_FINISH) != Z_OK) - return destroy((gz_stream*)file); - - putLong (s->file, s->crc); - putLong (s->file, (uLong)(s->in & 0xffffffff)); -#endif - } - return destroy((gz_stream*)file); -} - -#ifdef STDC -# define zstrerror(errnum) strerror(errnum) -#else -# define zstrerror(errnum) "" -#endif - -/* =========================================================================== - Returns the error message for the last error which occurred on the - given compressed file. errnum is set to zlib error number. If an - error occurred in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. -*/ -const char * ZEXPORT gzerror (file, errnum) - gzFile file; - int *errnum; -{ - char *m; - gz_stream *s = (gz_stream*)file; - - if (s == NULL) { - *errnum = Z_STREAM_ERROR; - return (const char*)ERR_MSG(Z_STREAM_ERROR); - } - *errnum = s->z_err; - if (*errnum == Z_OK) return (const char*)""; - - m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); - - if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); - - TRYFREE(s->msg); - s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); - if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); - strcpy(s->msg, s->path); - strcat(s->msg, ": "); - strcat(s->msg, m); - return (const char*)s->msg; -} - -/* =========================================================================== - Clear the error and end-of-file flags, and do the same for the real file. -*/ -void ZEXPORT gzclearerr (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL) return; - if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; - s->z_eof = 0; - clearerr(s->file); -} +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id$ */ + +#include + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_BEST_SPEED; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[46]; /* allow for up to 128-bit integers */ + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + start++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= + (uInt)fread(next_out, 1, s->stream.avail_out, s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + if (len == s->stream.avail_out && + (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) + return -1; + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Returns 1 if reading and doing so transparently, otherwise zero. +*/ +int ZEXPORT gzdirect (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return 0; + return s->transparent; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + if (do_flush (file, Z_FINISH) != Z_OK) + return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +#ifdef STDC +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +/* =========================================================================== + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/plugins/CDVDiso/src/3rdparty/zlib/infback.c b/plugins/CDVDiso/src/3rdparty/zlib/infback.c index 1e03e1bab0..455dbc9ee8 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/infback.c +++ b/plugins/CDVDiso/src/3rdparty/zlib/infback.c @@ -1,623 +1,623 @@ -/* infback.c -- inflate using a call-back interface - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - This code is largely copied from inflate.c. Normally either infback.o or - inflate.o would be linked into an application--not both. The interface - with inffast.c is retained so that optimized assembler-coded versions of - inflate_fast() can be used with either inflate.c or infback.c. - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -/* function prototypes */ -local void fixedtables OF((struct inflate_state FAR *state)); - -/* - strm provides memory allocation functions in zalloc and zfree, or - Z_NULL to use the library memory allocation functions. - - windowBits is in the range 8..15, and window is a user-supplied - window and output buffer that is 2**windowBits bytes. - */ -int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) -z_streamp strm; -int windowBits; -unsigned char FAR *window; -const char *version; -int stream_size; -{ - struct inflate_state FAR *state; - - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != (int)(sizeof(z_stream))) - return Z_VERSION_ERROR; - if (strm == Z_NULL || window == Z_NULL || - windowBits < 8 || windowBits > 15) - return Z_STREAM_ERROR; - strm->msg = Z_NULL; /* in case we return an error */ - if (strm->zalloc == (alloc_func)0) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; - state = (struct inflate_state FAR *)ZALLOC(strm, 1, - sizeof(struct inflate_state)); - if (state == Z_NULL) return Z_MEM_ERROR; - Tracev((stderr, "inflate: allocated\n")); - strm->state = (struct internal_state FAR *)state; - state->dmax = 32768U; - state->wbits = windowBits; - state->wsize = 1U << windowBits; - state->window = window; - state->write = 0; - state->whave = 0; - return Z_OK; -} - -/* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ -#ifdef BUILDFIXED - static int virgin = 1; - static code *lenfix, *distfix; - static code fixed[544]; - - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - unsigned sym, bits; - static code *next; - - /* literal/length table */ - sym = 0; - while (sym < 144) state->lens[sym++] = 8; - while (sym < 256) state->lens[sym++] = 9; - while (sym < 280) state->lens[sym++] = 7; - while (sym < 288) state->lens[sym++] = 8; - next = fixed; - lenfix = next; - bits = 9; - inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); - - /* distance table */ - sym = 0; - while (sym < 32) state->lens[sym++] = 5; - distfix = next; - bits = 5; - inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); - - /* do this just once */ - virgin = 0; - } -#else /* !BUILDFIXED */ -# include "inffixed.h" -#endif /* BUILDFIXED */ - state->lencode = lenfix; - state->lenbits = 9; - state->distcode = distfix; - state->distbits = 5; -} - -/* Macros for inflateBack(): */ - -/* Load returned state from inflate_fast() */ -#define LOAD() \ - do { \ - put = strm->next_out; \ - left = strm->avail_out; \ - next = strm->next_in; \ - have = strm->avail_in; \ - hold = state->hold; \ - bits = state->bits; \ - } while (0) - -/* Set state from registers for inflate_fast() */ -#define RESTORE() \ - do { \ - strm->next_out = put; \ - strm->avail_out = left; \ - strm->next_in = next; \ - strm->avail_in = have; \ - state->hold = hold; \ - state->bits = bits; \ - } while (0) - -/* Clear the input bit accumulator */ -#define INITBITS() \ - do { \ - hold = 0; \ - bits = 0; \ - } while (0) - -/* Assure that some input is available. If input is requested, but denied, - then return a Z_BUF_ERROR from inflateBack(). */ -#define PULL() \ - do { \ - if (have == 0) { \ - have = in(in_desc, &next); \ - if (have == 0) { \ - next = Z_NULL; \ - ret = Z_BUF_ERROR; \ - goto inf_leave; \ - } \ - } \ - } while (0) - -/* Get a byte of input into the bit accumulator, or return from inflateBack() - with an error if there is no input available. */ -#define PULLBYTE() \ - do { \ - PULL(); \ - have--; \ - hold += (unsigned long)(*next++) << bits; \ - bits += 8; \ - } while (0) - -/* Assure that there are at least n bits in the bit accumulator. If there is - not enough available input to do that, then return from inflateBack() with - an error. */ -#define NEEDBITS(n) \ - do { \ - while (bits < (unsigned)(n)) \ - PULLBYTE(); \ - } while (0) - -/* Return the low n bits of the bit accumulator (n < 16) */ -#define BITS(n) \ - ((unsigned)hold & ((1U << (n)) - 1)) - -/* Remove n bits from the bit accumulator */ -#define DROPBITS(n) \ - do { \ - hold >>= (n); \ - bits -= (unsigned)(n); \ - } while (0) - -/* Remove zero to seven bits as needed to go to a byte boundary */ -#define BYTEBITS() \ - do { \ - hold >>= bits & 7; \ - bits -= bits & 7; \ - } while (0) - -/* Assure that some output space is available, by writing out the window - if it's full. If the write fails, return from inflateBack() with a - Z_BUF_ERROR. */ -#define ROOM() \ - do { \ - if (left == 0) { \ - put = state->window; \ - left = state->wsize; \ - state->whave = left; \ - if (out(out_desc, put, left)) { \ - ret = Z_BUF_ERROR; \ - goto inf_leave; \ - } \ - } \ - } while (0) - -/* - strm provides the memory allocation functions and window buffer on input, - and provides information on the unused input on return. For Z_DATA_ERROR - returns, strm will also provide an error message. - - in() and out() are the call-back input and output functions. When - inflateBack() needs more input, it calls in(). When inflateBack() has - filled the window with output, or when it completes with data in the - window, it calls out() to write out the data. The application must not - change the provided input until in() is called again or inflateBack() - returns. The application must not change the window/output buffer until - inflateBack() returns. - - in() and out() are called with a descriptor parameter provided in the - inflateBack() call. This parameter can be a structure that provides the - information required to do the read or write, as well as accumulated - information on the input and output such as totals and check values. - - in() should return zero on failure. out() should return non-zero on - failure. If either in() or out() fails, than inflateBack() returns a - Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it - was in() or out() that caused in the error. Otherwise, inflateBack() - returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format - error, or Z_MEM_ERROR if it could not allocate memory for the state. - inflateBack() can also return Z_STREAM_ERROR if the input parameters - are not correct, i.e. strm is Z_NULL or the state was not initialized. - */ -int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) -z_streamp strm; -in_func in; -void FAR *in_desc; -out_func out; -void FAR *out_desc; -{ - struct inflate_state FAR *state; - unsigned char FAR *next; /* next input */ - unsigned char FAR *put; /* next output */ - unsigned have, left; /* available input and output */ - unsigned long hold; /* bit buffer */ - unsigned bits; /* bits in bit buffer */ - unsigned copy; /* number of stored or match bytes to copy */ - unsigned char FAR *from; /* where to copy match bytes from */ - code this; /* current decoding table entry */ - code last; /* parent table entry */ - unsigned len; /* length to copy for repeats, bits to drop */ - int ret; /* return code */ - static const unsigned short order[19] = /* permutation of code lengths */ - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - /* Check that the strm exists and that the state was initialized */ - if (strm == Z_NULL || strm->state == Z_NULL) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - - /* Reset the state */ - strm->msg = Z_NULL; - state->mode = TYPE; - state->last = 0; - state->whave = 0; - next = strm->next_in; - have = next != Z_NULL ? strm->avail_in : 0; - hold = 0; - bits = 0; - put = state->window; - left = state->wsize; - - /* Inflate until end of block marked as last */ - for (;;) - switch (state->mode) { - case TYPE: - /* determine and dispatch block type */ - if (state->last) { - BYTEBITS(); - state->mode = DONE; - break; - } - NEEDBITS(3); - state->last = BITS(1); - DROPBITS(1); - switch (BITS(2)) { - case 0: /* stored block */ - Tracev((stderr, "inflate: stored block%s\n", - state->last ? " (last)" : "")); - state->mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - Tracev((stderr, "inflate: fixed codes block%s\n", - state->last ? " (last)" : "")); - state->mode = LEN; /* decode codes */ - break; - case 2: /* dynamic block */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - state->last ? " (last)" : "")); - state->mode = TABLE; - break; - case 3: - strm->msg = (char *)"invalid block type"; - state->mode = BAD; - } - DROPBITS(2); - break; - - case STORED: - /* get and verify stored block length */ - BYTEBITS(); /* go to byte boundary */ - NEEDBITS(32); - if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - strm->msg = (char *)"invalid stored block lengths"; - state->mode = BAD; - break; - } - state->length = (unsigned)hold & 0xffff; - Tracev((stderr, "inflate: stored length %u\n", - state->length)); - INITBITS(); - - /* copy stored block from input to output */ - while (state->length != 0) { - copy = state->length; - PULL(); - ROOM(); - if (copy > have) copy = have; - if (copy > left) copy = left; - zmemcpy(put, next, copy); - have -= copy; - next += copy; - left -= copy; - put += copy; - state->length -= copy; - } - Tracev((stderr, "inflate: stored end\n")); - state->mode = TYPE; - break; - - case TABLE: - /* get dynamic table entries descriptor */ - NEEDBITS(14); - state->nlen = BITS(5) + 257; - DROPBITS(5); - state->ndist = BITS(5) + 1; - DROPBITS(5); - state->ncode = BITS(4) + 4; - DROPBITS(4); -#ifndef PKZIP_BUG_WORKAROUND - if (state->nlen > 286 || state->ndist > 30) { - strm->msg = (char *)"too many length or distance symbols"; - state->mode = BAD; - break; - } -#endif - Tracev((stderr, "inflate: table sizes ok\n")); - - /* get code length code lengths (not a typo) */ - state->have = 0; - while (state->have < state->ncode) { - NEEDBITS(3); - state->lens[order[state->have++]] = (unsigned short)BITS(3); - DROPBITS(3); - } - while (state->have < 19) - state->lens[order[state->have++]] = 0; - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 7; - ret = inflate_table(CODES, state->lens, 19, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid code lengths set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: code lengths ok\n")); - - /* get length and distance code code lengths */ - state->have = 0; - while (state->have < state->nlen + state->ndist) { - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.val < 16) { - NEEDBITS(this.bits); - DROPBITS(this.bits); - state->lens[state->have++] = this.val; - } - else { - if (this.val == 16) { - NEEDBITS(this.bits + 2); - DROPBITS(this.bits); - if (state->have == 0) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - len = (unsigned)(state->lens[state->have - 1]); - copy = 3 + BITS(2); - DROPBITS(2); - } - else if (this.val == 17) { - NEEDBITS(this.bits + 3); - DROPBITS(this.bits); - len = 0; - copy = 3 + BITS(3); - DROPBITS(3); - } - else { - NEEDBITS(this.bits + 7); - DROPBITS(this.bits); - len = 0; - copy = 11 + BITS(7); - DROPBITS(7); - } - if (state->have + copy > state->nlen + state->ndist) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - while (copy--) - state->lens[state->have++] = (unsigned short)len; - } - } - - /* handle error breaks in while */ - if (state->mode == BAD) break; - - /* build code tables */ - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 9; - ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid literal/lengths set"; - state->mode = BAD; - break; - } - state->distcode = (code const FAR *)(state->next); - state->distbits = 6; - ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, - &(state->next), &(state->distbits), state->work); - if (ret) { - strm->msg = (char *)"invalid distances set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: codes ok\n")); - state->mode = LEN; - - case LEN: - /* use inflate_fast() if we have enough input and output */ - if (have >= 6 && left >= 258) { - RESTORE(); - if (state->whave < state->wsize) - state->whave = state->wsize - left; - inflate_fast(strm, state->wsize); - LOAD(); - break; - } - - /* get a literal, length, or end-of-block code */ - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.op && (this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->lencode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - state->length = (unsigned)this.val; - - /* process literal */ - if (this.op == 0) { - Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", this.val)); - ROOM(); - *put++ = (unsigned char)(state->length); - left--; - state->mode = LEN; - break; - } - - /* process end of block */ - if (this.op & 32) { - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - - /* invalid code */ - if (this.op & 64) { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - - /* length code -- get extra bits, if any */ - state->extra = (unsigned)(this.op) & 15; - if (state->extra != 0) { - NEEDBITS(state->extra); - state->length += BITS(state->extra); - DROPBITS(state->extra); - } - Tracevv((stderr, "inflate: length %u\n", state->length)); - - /* get distance code */ - for (;;) { - this = state->distcode[BITS(state->distbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if ((this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->distcode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - if (this.op & 64) { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - state->offset = (unsigned)this.val; - - /* get distance extra bits, if any */ - state->extra = (unsigned)(this.op) & 15; - if (state->extra != 0) { - NEEDBITS(state->extra); - state->offset += BITS(state->extra); - DROPBITS(state->extra); - } - if (state->offset > state->wsize - (state->whave < state->wsize ? - left : 0)) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - Tracevv((stderr, "inflate: distance %u\n", state->offset)); - - /* copy match from window to output */ - do { - ROOM(); - copy = state->wsize - state->offset; - if (copy < left) { - from = put + copy; - copy = left - copy; - } - else { - from = put - state->offset; - copy = left; - } - if (copy > state->length) copy = state->length; - state->length -= copy; - left -= copy; - do { - *put++ = *from++; - } while (--copy); - } while (state->length != 0); - break; - - case DONE: - /* inflate stream terminated properly -- write leftover output */ - ret = Z_STREAM_END; - if (left < state->wsize) { - if (out(out_desc, state->window, state->wsize - left)) - ret = Z_BUF_ERROR; - } - goto inf_leave; - - case BAD: - ret = Z_DATA_ERROR; - goto inf_leave; - - default: /* can't happen, but makes compilers happy */ - ret = Z_STREAM_ERROR; - goto inf_leave; - } - - /* Return unused input */ - inf_leave: - strm->next_in = next; - strm->avail_in = have; - return ret; -} - -int ZEXPORT inflateBackEnd(strm) -z_streamp strm; -{ - if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) - return Z_STREAM_ERROR; - ZFREE(strm, strm->state); - strm->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; -} +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/plugins/CDVDiso/src/3rdparty/zlib/inffast.c b/plugins/CDVDiso/src/3rdparty/zlib/inffast.c index fa31cad905..bbee92ed1e 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/inffast.c +++ b/plugins/CDVDiso/src/3rdparty/zlib/inffast.c @@ -1,318 +1,318 @@ -/* inffast.c -- fast decoding - * Copyright (C) 1995-2004 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -#ifndef ASMINF - -/* Allow machine dependent optimization for post-increment or pre-increment. - Based on testing to date, - Pre-increment preferred for: - - PowerPC G3 (Adler) - - MIPS R5000 (Randers-Pehrson) - Post-increment preferred for: - - none - No measurable difference: - - Pentium III (Anderson) - - M68060 (Nikl) - */ -#ifdef POSTINC -# define OFF 0 -# define PUP(a) *(a)++ -#else -# define OFF 1 -# define PUP(a) *++(a) -#endif - -/* - Decode literal, length, and distance codes and write out the resulting - literal and match bytes until either not enough input or output is - available, an end-of-block is encountered, or a data error is encountered. - When large enough input and output buffers are supplied to inflate(), for - example, a 16K input buffer and a 64K output buffer, more than 95% of the - inflate execution time is spent in this routine. - - Entry assumptions: - - state->mode == LEN - strm->avail_in >= 6 - strm->avail_out >= 258 - start >= strm->avail_out - state->bits < 8 - - On return, state->mode is one of: - - LEN -- ran out of enough output space or enough available input - TYPE -- reached end of block code, inflate() to interpret next block - BAD -- error in block data - - Notes: - - - The maximum input bits used by a length/distance pair is 15 bits for the - length code, 5 bits for the length extra, 15 bits for the distance code, - and 13 bits for the distance extra. This totals 48 bits, or six bytes. - Therefore if strm->avail_in >= 6, then there is enough input to avoid - checking for available input while decoding. - - - The maximum bytes that a single length/distance pair can output is 258 - bytes, which is the maximum length that can be coded. inflate_fast() - requires strm->avail_out >= 258 for each loop to avoid checking for - output space. - */ -void inflate_fast(strm, start) -z_streamp strm; -unsigned start; /* inflate()'s starting value for strm->avail_out */ -{ - struct inflate_state FAR *state; - unsigned char FAR *in; /* local strm->next_in */ - unsigned char FAR *last; /* while in < last, enough input available */ - unsigned char FAR *out; /* local strm->next_out */ - unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ - unsigned char FAR *end; /* while out < end, enough space available */ -#ifdef INFLATE_STRICT - unsigned dmax; /* maximum distance from zlib header */ -#endif - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned write; /* window write index */ - unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ - unsigned long hold; /* local strm->hold */ - unsigned bits; /* local strm->bits */ - code const FAR *lcode; /* local strm->lencode */ - code const FAR *dcode; /* local strm->distcode */ - unsigned lmask; /* mask for first level of length codes */ - unsigned dmask; /* mask for first level of distance codes */ - code this; /* retrieved table entry */ - unsigned op; /* code bits, operation, extra bits, or */ - /* window position, window bytes to copy */ - unsigned len; /* match length, unused bytes */ - unsigned dist; /* match distance */ - unsigned char FAR *from; /* where to copy match from */ - - /* copy state to local variables */ - state = (struct inflate_state FAR *)strm->state; - in = strm->next_in - OFF; - last = in + (strm->avail_in - 5); - out = strm->next_out - OFF; - beg = out - (start - strm->avail_out); - end = out + (strm->avail_out - 257); -#ifdef INFLATE_STRICT - dmax = state->dmax; -#endif - wsize = state->wsize; - whave = state->whave; - write = state->write; - window = state->window; - hold = state->hold; - bits = state->bits; - lcode = state->lencode; - dcode = state->distcode; - lmask = (1U << state->lenbits) - 1; - dmask = (1U << state->distbits) - 1; - - /* decode literals and length/distances until end-of-block or not enough - input data or output space */ - do { - if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - this = lcode[hold & lmask]; - dolen: - op = (unsigned)(this.bits); - hold >>= op; - bits -= op; - op = (unsigned)(this.op); - if (op == 0) { /* literal */ - Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", this.val)); - PUP(out) = (unsigned char)(this.val); - } - else if (op & 16) { /* length base */ - len = (unsigned)(this.val); - op &= 15; /* number of extra bits */ - if (op) { - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - len += (unsigned)hold & ((1U << op) - 1); - hold >>= op; - bits -= op; - } - Tracevv((stderr, "inflate: length %u\n", len)); - if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - this = dcode[hold & dmask]; - dodist: - op = (unsigned)(this.bits); - hold >>= op; - bits -= op; - op = (unsigned)(this.op); - if (op & 16) { /* distance base */ - dist = (unsigned)(this.val); - op &= 15; /* number of extra bits */ - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - } - dist += (unsigned)hold & ((1U << op) - 1); -#ifdef INFLATE_STRICT - if (dist > dmax) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#endif - hold >>= op; - bits -= op; - Tracevv((stderr, "inflate: distance %u\n", dist)); - op = (unsigned)(out - beg); /* max distance in output */ - if (dist > op) { /* see if copy from window */ - op = dist - op; /* distance back in window */ - if (op > whave) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - from = window - OFF; - if (write == 0) { /* very common case */ - from += wsize - op; - if (op < len) { /* some from window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - else if (write < op) { /* wrap around window */ - from += wsize + write - op; - op -= write; - if (op < len) { /* some from end of window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = window - OFF; - if (write < len) { /* some from start of window */ - op = write; - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - } - else { /* contiguous in window */ - from += write - op; - if (op < len) { /* some from window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - while (len > 2) { - PUP(out) = PUP(from); - PUP(out) = PUP(from); - PUP(out) = PUP(from); - len -= 3; - } - if (len) { - PUP(out) = PUP(from); - if (len > 1) - PUP(out) = PUP(from); - } - } - else { - from = out - dist; /* copy direct from output */ - do { /* minimum length is three */ - PUP(out) = PUP(from); - PUP(out) = PUP(from); - PUP(out) = PUP(from); - len -= 3; - } while (len > 2); - if (len) { - PUP(out) = PUP(from); - if (len > 1) - PUP(out) = PUP(from); - } - } - } - else if ((op & 64) == 0) { /* 2nd level distance code */ - this = dcode[this.val + (hold & ((1U << op) - 1))]; - goto dodist; - } - else { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - } - else if ((op & 64) == 0) { /* 2nd level length code */ - this = lcode[this.val + (hold & ((1U << op) - 1))]; - goto dolen; - } - else if (op & 32) { /* end-of-block */ - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - else { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - } while (in < last && out < end); - - /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ - len = bits >> 3; - in -= len; - bits -= len << 3; - hold &= (1U << bits) - 1; - - /* update state and return */ - strm->next_in = in + OFF; - strm->next_out = out + OFF; - strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); - strm->avail_out = (unsigned)(out < end ? - 257 + (end - out) : 257 - (out - end)); - state->hold = hold; - state->bits = bits; - return; -} - -/* - inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - - Using bit fields for code structure - - Different op definition to avoid & for extra bits (do & for table bits) - - Three separate decoding do-loops for direct, window, and write == 0 - - Special case for distance > 1 copies to do overlapped load and store copy - - Explicit branch predictions (based on measured branch probabilities) - - Deferring match copy and interspersed it with decoding subsequent codes - - Swapping literal/length else - - Swapping window/direct else - - Larger unrolled copy loops (three is about right) - - Moving len -= 3 statement into middle of loop - */ - -#endif /* !ASMINF */ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - M68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/plugins/CDVDiso/src/3rdparty/zlib/inffast.h b/plugins/CDVDiso/src/3rdparty/zlib/inffast.h index 614fa7877d..1e88d2d97b 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/inffast.h +++ b/plugins/CDVDiso/src/3rdparty/zlib/inffast.h @@ -1,11 +1,11 @@ -/* inffast.h -- header to use inffast.c - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -void inflate_fast OF((z_streamp strm, unsigned start)); +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/plugins/CDVDiso/src/3rdparty/zlib/inffixed.h b/plugins/CDVDiso/src/3rdparty/zlib/inffixed.h index 423d5c5b50..75ed4b5978 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/inffixed.h +++ b/plugins/CDVDiso/src/3rdparty/zlib/inffixed.h @@ -1,94 +1,94 @@ - /* inffixed.h -- table for decoding fixed codes - * Generated automatically by makefixed(). - */ - - /* WARNING: this file should *not* be used by applications. It - is part of the implementation of the compression library and - is subject to change. Applications should only use zlib.h. - */ - - static const code lenfix[512] = { - {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, - {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, - {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, - {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, - {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, - {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, - {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, - {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, - {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, - {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, - {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, - {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, - {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, - {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, - {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, - {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, - {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, - {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, - {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, - {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, - {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, - {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, - {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, - {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, - {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, - {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, - {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, - {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, - {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, - {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, - {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, - {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, - {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, - {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, - {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, - {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, - {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, - {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, - {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, - {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, - {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, - {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, - {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, - {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, - {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, - {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, - {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, - {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, - {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, - {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, - {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, - {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, - {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, - {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, - {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, - {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, - {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, - {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, - {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, - {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, - {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, - {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, - {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, - {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, - {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, - {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, - {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, - {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, - {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, - {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, - {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, - {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, - {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, - {0,9,255} - }; - - static const code distfix[32] = { - {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, - {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, - {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, - {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, - {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, - {22,5,193},{64,5,0} - }; + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/plugins/CDVDiso/src/3rdparty/zlib/inflate.c b/plugins/CDVDiso/src/3rdparty/zlib/inflate.c index 33ea902928..792fdee8e9 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/inflate.c +++ b/plugins/CDVDiso/src/3rdparty/zlib/inflate.c @@ -1,1368 +1,1368 @@ -/* inflate.c -- zlib decompression - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * Change history: - * - * 1.2.beta0 24 Nov 2002 - * - First version -- complete rewrite of inflate to simplify code, avoid - * creation of window when not needed, minimize use of window when it is - * needed, make inffast.c even faster, implement gzip decoding, and to - * improve code readability and style over the previous zlib inflate code - * - * 1.2.beta1 25 Nov 2002 - * - Use pointers for available input and output checking in inffast.c - * - Remove input and output counters in inffast.c - * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 - * - Remove unnecessary second byte pull from length extra in inffast.c - * - Unroll direct copy to three copies per loop in inffast.c - * - * 1.2.beta2 4 Dec 2002 - * - Change external routine names to reduce potential conflicts - * - Correct filename to inffixed.h for fixed tables in inflate.c - * - Make hbuf[] unsigned char to match parameter type in inflate.c - * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) - * to avoid negation problem on Alphas (64 bit) in inflate.c - * - * 1.2.beta3 22 Dec 2002 - * - Add comments on state->bits assertion in inffast.c - * - Add comments on op field in inftrees.h - * - Fix bug in reuse of allocated window after inflateReset() - * - Remove bit fields--back to byte structure for speed - * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths - * - Change post-increments to pre-increments in inflate_fast(), PPC biased? - * - Add compile time option, POSTINC, to use post-increments instead (Intel?) - * - Make MATCH copy in inflate() much faster for when inflate_fast() not used - * - Use local copies of stream next and avail values, as well as local bit - * buffer and bit count in inflate()--for speed when inflate_fast() not used - * - * 1.2.beta4 1 Jan 2003 - * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings - * - Move a comment on output buffer sizes from inffast.c to inflate.c - * - Add comments in inffast.c to introduce the inflate_fast() routine - * - Rearrange window copies in inflate_fast() for speed and simplification - * - Unroll last copy for window match in inflate_fast() - * - Use local copies of window variables in inflate_fast() for speed - * - Pull out common write == 0 case for speed in inflate_fast() - * - Make op and len in inflate_fast() unsigned for consistency - * - Add FAR to lcode and dcode declarations in inflate_fast() - * - Simplified bad distance check in inflate_fast() - * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new - * source file infback.c to provide a call-back interface to inflate for - * programs like gzip and unzip -- uses window as output buffer to avoid - * window copying - * - * 1.2.beta5 1 Jan 2003 - * - Improved inflateBack() interface to allow the caller to provide initial - * input in strm. - * - Fixed stored blocks bug in inflateBack() - * - * 1.2.beta6 4 Jan 2003 - * - Added comments in inffast.c on effectiveness of POSTINC - * - Typecasting all around to reduce compiler warnings - * - Changed loops from while (1) or do {} while (1) to for (;;), again to - * make compilers happy - * - Changed type of window in inflateBackInit() to unsigned char * - * - * 1.2.beta7 27 Jan 2003 - * - Changed many types to unsigned or unsigned short to avoid warnings - * - Added inflateCopy() function - * - * 1.2.0 9 Mar 2003 - * - Changed inflateBack() interface to provide separate opaque descriptors - * for the in() and out() functions - * - Changed inflateBack() argument and in_func typedef to swap the length - * and buffer address return values for the input function - * - Check next_in and next_out for Z_NULL on entry to inflate() - * - * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -#ifdef MAKEFIXED -# ifndef BUILDFIXED -# define BUILDFIXED -# endif -#endif - -/* function prototypes */ -local void fixedtables OF((struct inflate_state FAR *state)); -local int updatewindow OF((z_streamp strm, unsigned out)); -#ifdef BUILDFIXED - void makefixed OF((void)); -#endif -local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, - unsigned len)); - -int ZEXPORT inflateReset(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - strm->total_in = strm->total_out = state->total = 0; - strm->msg = Z_NULL; - strm->adler = 1; /* to support ill-conceived Java test suite */ - state->mode = HEAD; - state->last = 0; - state->havedict = 0; - state->dmax = 32768U; - state->head = Z_NULL; - state->wsize = 0; - state->whave = 0; - state->write = 0; - state->hold = 0; - state->bits = 0; - state->lencode = state->distcode = state->next = state->codes; - Tracev((stderr, "inflate: reset\n")); - return Z_OK; -} - -int ZEXPORT inflatePrime(strm, bits, value) -z_streamp strm; -int bits; -int value; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; - value &= (1L << bits) - 1; - state->hold += value << state->bits; - state->bits += bits; - return Z_OK; -} - -int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) -z_streamp strm; -int windowBits; -const char *version; -int stream_size; -{ - struct inflate_state FAR *state; - - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != (int)(sizeof(z_stream))) - return Z_VERSION_ERROR; - if (strm == Z_NULL) return Z_STREAM_ERROR; - strm->msg = Z_NULL; /* in case we return an error */ - if (strm->zalloc == (alloc_func)0) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; - state = (struct inflate_state FAR *) - ZALLOC(strm, 1, sizeof(struct inflate_state)); - if (state == Z_NULL) return Z_MEM_ERROR; - Tracev((stderr, "inflate: allocated\n")); - strm->state = (struct internal_state FAR *)state; - if (windowBits < 0) { - state->wrap = 0; - windowBits = -windowBits; - } - else { - state->wrap = (windowBits >> 4) + 1; -#ifdef GUNZIP - if (windowBits < 48) windowBits &= 15; -#endif - } - if (windowBits < 8 || windowBits > 15) { - ZFREE(strm, state); - strm->state = Z_NULL; - return Z_STREAM_ERROR; - } - state->wbits = (unsigned)windowBits; - state->window = Z_NULL; - return inflateReset(strm); -} - -int ZEXPORT inflateInit_(strm, version, stream_size) -z_streamp strm; -const char *version; -int stream_size; -{ - return inflateInit2_(strm, DEF_WBITS, version, stream_size); -} - -/* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ -#ifdef BUILDFIXED - static int virgin = 1; - static code *lenfix, *distfix; - static code fixed[544]; - - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - unsigned sym, bits; - static code *next; - - /* literal/length table */ - sym = 0; - while (sym < 144) state->lens[sym++] = 8; - while (sym < 256) state->lens[sym++] = 9; - while (sym < 280) state->lens[sym++] = 7; - while (sym < 288) state->lens[sym++] = 8; - next = fixed; - lenfix = next; - bits = 9; - inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); - - /* distance table */ - sym = 0; - while (sym < 32) state->lens[sym++] = 5; - distfix = next; - bits = 5; - inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); - - /* do this just once */ - virgin = 0; - } -#else /* !BUILDFIXED */ -# include "inffixed.h" -#endif /* BUILDFIXED */ - state->lencode = lenfix; - state->lenbits = 9; - state->distcode = distfix; - state->distbits = 5; -} - -#ifdef MAKEFIXED -#include - -/* - Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also - defines BUILDFIXED, so the tables are built on the fly. makefixed() writes - those tables to stdout, which would be piped to inffixed.h. A small program - can simply call makefixed to do this: - - void makefixed(void); - - int main(void) - { - makefixed(); - return 0; - } - - Then that can be linked with zlib built with MAKEFIXED defined and run: - - a.out > inffixed.h - */ -void makefixed() -{ - unsigned low, size; - struct inflate_state state; - - fixedtables(&state); - puts(" /* inffixed.h -- table for decoding fixed codes"); - puts(" * Generated automatically by makefixed()."); - puts(" */"); - puts(""); - puts(" /* WARNING: this file should *not* be used by applications."); - puts(" It is part of the implementation of this library and is"); - puts(" subject to change. Applications should only use zlib.h."); - puts(" */"); - puts(""); - size = 1U << 9; - printf(" static const code lenfix[%u] = {", size); - low = 0; - for (;;) { - if ((low % 7) == 0) printf("\n "); - printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, - state.lencode[low].val); - if (++low == size) break; - putchar(','); - } - puts("\n };"); - size = 1U << 5; - printf("\n static const code distfix[%u] = {", size); - low = 0; - for (;;) { - if ((low % 6) == 0) printf("\n "); - printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, - state.distcode[low].val); - if (++low == size) break; - putchar(','); - } - puts("\n };"); -} -#endif /* MAKEFIXED */ - -/* - Update the window with the last wsize (normally 32K) bytes written before - returning. If window does not exist yet, create it. This is only called - when a window is already in use, or when output has been written during this - inflate call, but the end of the deflate stream has not been reached yet. - It is also called to create a window for dictionary data when a dictionary - is loaded. - - Providing output buffers larger than 32K to inflate() should provide a speed - advantage, since only the last 32K of output is copied to the sliding window - upon return from inflate(), and since all distances after the first 32K of - output will fall in the output data, making match copies simpler and faster. - The advantage may be dependent on the size of the processor's data caches. - */ -local int updatewindow(strm, out) -z_streamp strm; -unsigned out; -{ - struct inflate_state FAR *state; - unsigned copy, dist; - - state = (struct inflate_state FAR *)strm->state; - - /* if it hasn't been done already, allocate space for the window */ - if (state->window == Z_NULL) { - state->window = (unsigned char FAR *) - ZALLOC(strm, 1U << state->wbits, - sizeof(unsigned char)); - if (state->window == Z_NULL) return 1; - } - - /* if window not in use yet, initialize */ - if (state->wsize == 0) { - state->wsize = 1U << state->wbits; - state->write = 0; - state->whave = 0; - } - - /* copy state->wsize or less output bytes into the circular window */ - copy = out - strm->avail_out; - if (copy >= state->wsize) { - zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); - state->write = 0; - state->whave = state->wsize; - } - else { - dist = state->wsize - state->write; - if (dist > copy) dist = copy; - zmemcpy(state->window + state->write, strm->next_out - copy, dist); - copy -= dist; - if (copy) { - zmemcpy(state->window, strm->next_out - copy, copy); - state->write = copy; - state->whave = state->wsize; - } - else { - state->write += dist; - if (state->write == state->wsize) state->write = 0; - if (state->whave < state->wsize) state->whave += dist; - } - } - return 0; -} - -/* Macros for inflate(): */ - -/* check function to use adler32() for zlib or crc32() for gzip */ -#ifdef GUNZIP -# define UPDATE(check, buf, len) \ - (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) -#else -# define UPDATE(check, buf, len) adler32(check, buf, len) -#endif - -/* check macros for header crc */ -#ifdef GUNZIP -# define CRC2(check, word) \ - do { \ - hbuf[0] = (unsigned char)(word); \ - hbuf[1] = (unsigned char)((word) >> 8); \ - check = crc32(check, hbuf, 2); \ - } while (0) - -# define CRC4(check, word) \ - do { \ - hbuf[0] = (unsigned char)(word); \ - hbuf[1] = (unsigned char)((word) >> 8); \ - hbuf[2] = (unsigned char)((word) >> 16); \ - hbuf[3] = (unsigned char)((word) >> 24); \ - check = crc32(check, hbuf, 4); \ - } while (0) -#endif - -/* Load registers with state in inflate() for speed */ -#define LOAD() \ - do { \ - put = strm->next_out; \ - left = strm->avail_out; \ - next = strm->next_in; \ - have = strm->avail_in; \ - hold = state->hold; \ - bits = state->bits; \ - } while (0) - -/* Restore state from registers in inflate() */ -#define RESTORE() \ - do { \ - strm->next_out = put; \ - strm->avail_out = left; \ - strm->next_in = next; \ - strm->avail_in = have; \ - state->hold = hold; \ - state->bits = bits; \ - } while (0) - -/* Clear the input bit accumulator */ -#define INITBITS() \ - do { \ - hold = 0; \ - bits = 0; \ - } while (0) - -/* Get a byte of input into the bit accumulator, or return from inflate() - if there is no input available. */ -#define PULLBYTE() \ - do { \ - if (have == 0) goto inf_leave; \ - have--; \ - hold += (unsigned long)(*next++) << bits; \ - bits += 8; \ - } while (0) - -/* Assure that there are at least n bits in the bit accumulator. If there is - not enough available input to do that, then return from inflate(). */ -#define NEEDBITS(n) \ - do { \ - while (bits < (unsigned)(n)) \ - PULLBYTE(); \ - } while (0) - -/* Return the low n bits of the bit accumulator (n < 16) */ -#define BITS(n) \ - ((unsigned)hold & ((1U << (n)) - 1)) - -/* Remove n bits from the bit accumulator */ -#define DROPBITS(n) \ - do { \ - hold >>= (n); \ - bits -= (unsigned)(n); \ - } while (0) - -/* Remove zero to seven bits as needed to go to a byte boundary */ -#define BYTEBITS() \ - do { \ - hold >>= bits & 7; \ - bits -= bits & 7; \ - } while (0) - -/* Reverse the bytes in a 32-bit value */ -#define REVERSE(q) \ - ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ - (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) - -/* - inflate() uses a state machine to process as much input data and generate as - much output data as possible before returning. The state machine is - structured roughly as follows: - - for (;;) switch (state) { - ... - case STATEn: - if (not enough input data or output space to make progress) - return; - ... make progress ... - state = STATEm; - break; - ... - } - - so when inflate() is called again, the same case is attempted again, and - if the appropriate resources are provided, the machine proceeds to the - next state. The NEEDBITS() macro is usually the way the state evaluates - whether it can proceed or should return. NEEDBITS() does the return if - the requested bits are not available. The typical use of the BITS macros - is: - - NEEDBITS(n); - ... do something with BITS(n) ... - DROPBITS(n); - - where NEEDBITS(n) either returns from inflate() if there isn't enough - input left to load n bits into the accumulator, or it continues. BITS(n) - gives the low n bits in the accumulator. When done, DROPBITS(n) drops - the low n bits off the accumulator. INITBITS() clears the accumulator - and sets the number of available bits to zero. BYTEBITS() discards just - enough bits to put the accumulator on a byte boundary. After BYTEBITS() - and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. - - NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return - if there is no input available. The decoding of variable length codes uses - PULLBYTE() directly in order to pull just enough bytes to decode the next - code, and no more. - - Some states loop until they get enough input, making sure that enough - state information is maintained to continue the loop where it left off - if NEEDBITS() returns in the loop. For example, want, need, and keep - would all have to actually be part of the saved state in case NEEDBITS() - returns: - - case STATEw: - while (want < need) { - NEEDBITS(n); - keep[want++] = BITS(n); - DROPBITS(n); - } - state = STATEx; - case STATEx: - - As shown above, if the next state is also the next case, then the break - is omitted. - - A state may also return if there is not enough output space available to - complete that state. Those states are copying stored data, writing a - literal byte, and copying a matching string. - - When returning, a "goto inf_leave" is used to update the total counters, - update the check value, and determine whether any progress has been made - during that inflate() call in order to return the proper return code. - Progress is defined as a change in either strm->avail_in or strm->avail_out. - When there is a window, goto inf_leave will update the window with the last - output written. If a goto inf_leave occurs in the middle of decompression - and there is no window currently, goto inf_leave will create one and copy - output to the window for the next call of inflate(). - - In this implementation, the flush parameter of inflate() only affects the - return code (per zlib.h). inflate() always writes as much as possible to - strm->next_out, given the space available and the provided input--the effect - documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers - the allocation of and copying into a sliding window until necessary, which - provides the effect documented in zlib.h for Z_FINISH when the entire input - stream available. So the only thing the flush parameter actually does is: - when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it - will return Z_BUF_ERROR if it has not reached the end of the stream. - */ - -int ZEXPORT inflate(strm, flush) -z_streamp strm; -int flush; -{ - struct inflate_state FAR *state; - unsigned char FAR *next; /* next input */ - unsigned char FAR *put; /* next output */ - unsigned have, left; /* available input and output */ - unsigned long hold; /* bit buffer */ - unsigned bits; /* bits in bit buffer */ - unsigned in, out; /* save starting available input and output */ - unsigned copy; /* number of stored or match bytes to copy */ - unsigned char FAR *from; /* where to copy match bytes from */ - code this; /* current decoding table entry */ - code last; /* parent table entry */ - unsigned len; /* length to copy for repeats, bits to drop */ - int ret; /* return code */ -#ifdef GUNZIP - unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ -#endif - static const unsigned short order[19] = /* permutation of code lengths */ - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || - (strm->next_in == Z_NULL && strm->avail_in != 0)) - return Z_STREAM_ERROR; - - state = (struct inflate_state FAR *)strm->state; - if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ - LOAD(); - in = have; - out = left; - ret = Z_OK; - for (;;) - switch (state->mode) { - case HEAD: - if (state->wrap == 0) { - state->mode = TYPEDO; - break; - } - NEEDBITS(16); -#ifdef GUNZIP - if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ - state->check = crc32(0L, Z_NULL, 0); - CRC2(state->check, hold); - INITBITS(); - state->mode = FLAGS; - break; - } - state->flags = 0; /* expect zlib header */ - if (state->head != Z_NULL) - state->head->done = -1; - if (!(state->wrap & 1) || /* check if zlib header allowed */ -#else - if ( -#endif - ((BITS(8) << 8) + (hold >> 8)) % 31) { - strm->msg = (char *)"incorrect header check"; - state->mode = BAD; - break; - } - if (BITS(4) != Z_DEFLATED) { - strm->msg = (char *)"unknown compression method"; - state->mode = BAD; - break; - } - DROPBITS(4); - len = BITS(4) + 8; - if (len > state->wbits) { - strm->msg = (char *)"invalid window size"; - state->mode = BAD; - break; - } - state->dmax = 1U << len; - Tracev((stderr, "inflate: zlib header ok\n")); - strm->adler = state->check = adler32(0L, Z_NULL, 0); - state->mode = hold & 0x200 ? DICTID : TYPE; - INITBITS(); - break; -#ifdef GUNZIP - case FLAGS: - NEEDBITS(16); - state->flags = (int)(hold); - if ((state->flags & 0xff) != Z_DEFLATED) { - strm->msg = (char *)"unknown compression method"; - state->mode = BAD; - break; - } - if (state->flags & 0xe000) { - strm->msg = (char *)"unknown header flags set"; - state->mode = BAD; - break; - } - if (state->head != Z_NULL) - state->head->text = (int)((hold >> 8) & 1); - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - state->mode = TIME; - case TIME: - NEEDBITS(32); - if (state->head != Z_NULL) - state->head->time = hold; - if (state->flags & 0x0200) CRC4(state->check, hold); - INITBITS(); - state->mode = OS; - case OS: - NEEDBITS(16); - if (state->head != Z_NULL) { - state->head->xflags = (int)(hold & 0xff); - state->head->os = (int)(hold >> 8); - } - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - state->mode = EXLEN; - case EXLEN: - if (state->flags & 0x0400) { - NEEDBITS(16); - state->length = (unsigned)(hold); - if (state->head != Z_NULL) - state->head->extra_len = (unsigned)hold; - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - } - else if (state->head != Z_NULL) - state->head->extra = Z_NULL; - state->mode = EXTRA; - case EXTRA: - if (state->flags & 0x0400) { - copy = state->length; - if (copy > have) copy = have; - if (copy) { - if (state->head != Z_NULL && - state->head->extra != Z_NULL) { - len = state->head->extra_len - state->length; - zmemcpy(state->head->extra + len, next, - len + copy > state->head->extra_max ? - state->head->extra_max - len : copy); - } - if (state->flags & 0x0200) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - state->length -= copy; - } - if (state->length) goto inf_leave; - } - state->length = 0; - state->mode = NAME; - case NAME: - if (state->flags & 0x0800) { - if (have == 0) goto inf_leave; - copy = 0; - do { - len = (unsigned)(next[copy++]); - if (state->head != Z_NULL && - state->head->name != Z_NULL && - state->length < state->head->name_max) - state->head->name[state->length++] = len; - } while (len && copy < have); - if (state->flags & 0x0200) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - if (len) goto inf_leave; - } - else if (state->head != Z_NULL) - state->head->name = Z_NULL; - state->length = 0; - state->mode = COMMENT; - case COMMENT: - if (state->flags & 0x1000) { - if (have == 0) goto inf_leave; - copy = 0; - do { - len = (unsigned)(next[copy++]); - if (state->head != Z_NULL && - state->head->comment != Z_NULL && - state->length < state->head->comm_max) - state->head->comment[state->length++] = len; - } while (len && copy < have); - if (state->flags & 0x0200) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - if (len) goto inf_leave; - } - else if (state->head != Z_NULL) - state->head->comment = Z_NULL; - state->mode = HCRC; - case HCRC: - if (state->flags & 0x0200) { - NEEDBITS(16); - if (hold != (state->check & 0xffff)) { - strm->msg = (char *)"header crc mismatch"; - state->mode = BAD; - break; - } - INITBITS(); - } - if (state->head != Z_NULL) { - state->head->hcrc = (int)((state->flags >> 9) & 1); - state->head->done = 1; - } - strm->adler = state->check = crc32(0L, Z_NULL, 0); - state->mode = TYPE; - break; -#endif - case DICTID: - NEEDBITS(32); - strm->adler = state->check = REVERSE(hold); - INITBITS(); - state->mode = DICT; - case DICT: - if (state->havedict == 0) { - RESTORE(); - return Z_NEED_DICT; - } - strm->adler = state->check = adler32(0L, Z_NULL, 0); - state->mode = TYPE; - case TYPE: - if (flush == Z_BLOCK) goto inf_leave; - case TYPEDO: - if (state->last) { - BYTEBITS(); - state->mode = CHECK; - break; - } - NEEDBITS(3); - state->last = BITS(1); - DROPBITS(1); - switch (BITS(2)) { - case 0: /* stored block */ - Tracev((stderr, "inflate: stored block%s\n", - state->last ? " (last)" : "")); - state->mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - Tracev((stderr, "inflate: fixed codes block%s\n", - state->last ? " (last)" : "")); - state->mode = LEN; /* decode codes */ - break; - case 2: /* dynamic block */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - state->last ? " (last)" : "")); - state->mode = TABLE; - break; - case 3: - strm->msg = (char *)"invalid block type"; - state->mode = BAD; - } - DROPBITS(2); - break; - case STORED: - BYTEBITS(); /* go to byte boundary */ - NEEDBITS(32); - if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - strm->msg = (char *)"invalid stored block lengths"; - state->mode = BAD; - break; - } - state->length = (unsigned)hold & 0xffff; - Tracev((stderr, "inflate: stored length %u\n", - state->length)); - INITBITS(); - state->mode = COPY; - case COPY: - copy = state->length; - if (copy) { - if (copy > have) copy = have; - if (copy > left) copy = left; - if (copy == 0) goto inf_leave; - zmemcpy(put, next, copy); - have -= copy; - next += copy; - left -= copy; - put += copy; - state->length -= copy; - break; - } - Tracev((stderr, "inflate: stored end\n")); - state->mode = TYPE; - break; - case TABLE: - NEEDBITS(14); - state->nlen = BITS(5) + 257; - DROPBITS(5); - state->ndist = BITS(5) + 1; - DROPBITS(5); - state->ncode = BITS(4) + 4; - DROPBITS(4); -#ifndef PKZIP_BUG_WORKAROUND - if (state->nlen > 286 || state->ndist > 30) { - strm->msg = (char *)"too many length or distance symbols"; - state->mode = BAD; - break; - } -#endif - Tracev((stderr, "inflate: table sizes ok\n")); - state->have = 0; - state->mode = LENLENS; - case LENLENS: - while (state->have < state->ncode) { - NEEDBITS(3); - state->lens[order[state->have++]] = (unsigned short)BITS(3); - DROPBITS(3); - } - while (state->have < 19) - state->lens[order[state->have++]] = 0; - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 7; - ret = inflate_table(CODES, state->lens, 19, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid code lengths set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: code lengths ok\n")); - state->have = 0; - state->mode = CODELENS; - case CODELENS: - while (state->have < state->nlen + state->ndist) { - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.val < 16) { - NEEDBITS(this.bits); - DROPBITS(this.bits); - state->lens[state->have++] = this.val; - } - else { - if (this.val == 16) { - NEEDBITS(this.bits + 2); - DROPBITS(this.bits); - if (state->have == 0) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - len = state->lens[state->have - 1]; - copy = 3 + BITS(2); - DROPBITS(2); - } - else if (this.val == 17) { - NEEDBITS(this.bits + 3); - DROPBITS(this.bits); - len = 0; - copy = 3 + BITS(3); - DROPBITS(3); - } - else { - NEEDBITS(this.bits + 7); - DROPBITS(this.bits); - len = 0; - copy = 11 + BITS(7); - DROPBITS(7); - } - if (state->have + copy > state->nlen + state->ndist) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - while (copy--) - state->lens[state->have++] = (unsigned short)len; - } - } - - /* handle error breaks in while */ - if (state->mode == BAD) break; - - /* build code tables */ - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 9; - ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid literal/lengths set"; - state->mode = BAD; - break; - } - state->distcode = (code const FAR *)(state->next); - state->distbits = 6; - ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, - &(state->next), &(state->distbits), state->work); - if (ret) { - strm->msg = (char *)"invalid distances set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: codes ok\n")); - state->mode = LEN; - case LEN: - if (have >= 6 && left >= 258) { - RESTORE(); - inflate_fast(strm, out); - LOAD(); - break; - } - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.op && (this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->lencode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - state->length = (unsigned)this.val; - if ((int)(this.op) == 0) { - Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", this.val)); - state->mode = LIT; - break; - } - if (this.op & 32) { - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - if (this.op & 64) { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - state->extra = (unsigned)(this.op) & 15; - state->mode = LENEXT; - case LENEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->length += BITS(state->extra); - DROPBITS(state->extra); - } - Tracevv((stderr, "inflate: length %u\n", state->length)); - state->mode = DIST; - case DIST: - for (;;) { - this = state->distcode[BITS(state->distbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if ((this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->distcode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - if (this.op & 64) { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - state->offset = (unsigned)this.val; - state->extra = (unsigned)(this.op) & 15; - state->mode = DISTEXT; - case DISTEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->offset += BITS(state->extra); - DROPBITS(state->extra); - } -#ifdef INFLATE_STRICT - if (state->offset > state->dmax) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#endif - if (state->offset > state->whave + out - left) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - Tracevv((stderr, "inflate: distance %u\n", state->offset)); - state->mode = MATCH; - case MATCH: - if (left == 0) goto inf_leave; - copy = out - left; - if (state->offset > copy) { /* copy from window */ - copy = state->offset - copy; - if (copy > state->write) { - copy -= state->write; - from = state->window + (state->wsize - copy); - } - else - from = state->window + (state->write - copy); - if (copy > state->length) copy = state->length; - } - else { /* copy from output */ - from = put - state->offset; - copy = state->length; - } - if (copy > left) copy = left; - left -= copy; - state->length -= copy; - do { - *put++ = *from++; - } while (--copy); - if (state->length == 0) state->mode = LEN; - break; - case LIT: - if (left == 0) goto inf_leave; - *put++ = (unsigned char)(state->length); - left--; - state->mode = LEN; - break; - case CHECK: - if (state->wrap) { - NEEDBITS(32); - out -= left; - strm->total_out += out; - state->total += out; - if (out) - strm->adler = state->check = - UPDATE(state->check, put - out, out); - out = left; - if (( -#ifdef GUNZIP - state->flags ? hold : -#endif - REVERSE(hold)) != state->check) { - strm->msg = (char *)"incorrect data check"; - state->mode = BAD; - break; - } - INITBITS(); - Tracev((stderr, "inflate: check matches trailer\n")); - } -#ifdef GUNZIP - state->mode = LENGTH; - case LENGTH: - if (state->wrap && state->flags) { - NEEDBITS(32); - if (hold != (state->total & 0xffffffffUL)) { - strm->msg = (char *)"incorrect length check"; - state->mode = BAD; - break; - } - INITBITS(); - Tracev((stderr, "inflate: length matches trailer\n")); - } -#endif - state->mode = DONE; - case DONE: - ret = Z_STREAM_END; - goto inf_leave; - case BAD: - ret = Z_DATA_ERROR; - goto inf_leave; - case MEM: - return Z_MEM_ERROR; - case SYNC: - default: - return Z_STREAM_ERROR; - } - - /* - Return from inflate(), updating the total counts and the check value. - If there was no progress during the inflate() call, return a buffer - error. Call updatewindow() to create and/or update the window state. - Note: a memory error from inflate() is non-recoverable. - */ - inf_leave: - RESTORE(); - if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) - if (updatewindow(strm, out)) { - state->mode = MEM; - return Z_MEM_ERROR; - } - in -= strm->avail_in; - out -= strm->avail_out; - strm->total_in += in; - strm->total_out += out; - state->total += out; - if (state->wrap && out) - strm->adler = state->check = - UPDATE(state->check, strm->next_out - out, out); - strm->data_type = state->bits + (state->last ? 64 : 0) + - (state->mode == TYPE ? 128 : 0); - if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) - ret = Z_BUF_ERROR; - return ret; -} - -int ZEXPORT inflateEnd(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (state->window != Z_NULL) ZFREE(strm, state->window); - ZFREE(strm, strm->state); - strm->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; -} - -int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) -z_streamp strm; -const Bytef *dictionary; -uInt dictLength; -{ - struct inflate_state FAR *state; - unsigned long id; - - /* check state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (state->wrap != 0 && state->mode != DICT) - return Z_STREAM_ERROR; - - /* check for correct dictionary id */ - if (state->mode == DICT) { - id = adler32(0L, Z_NULL, 0); - id = adler32(id, dictionary, dictLength); - if (id != state->check) - return Z_DATA_ERROR; - } - - /* copy dictionary to window */ - if (updatewindow(strm, strm->avail_out)) { - state->mode = MEM; - return Z_MEM_ERROR; - } - if (dictLength > state->wsize) { - zmemcpy(state->window, dictionary + dictLength - state->wsize, - state->wsize); - state->whave = state->wsize; - } - else { - zmemcpy(state->window + state->wsize - dictLength, dictionary, - dictLength); - state->whave = dictLength; - } - state->havedict = 1; - Tracev((stderr, "inflate: dictionary set\n")); - return Z_OK; -} - -int ZEXPORT inflateGetHeader(strm, head) -z_streamp strm; -gz_headerp head; -{ - struct inflate_state FAR *state; - - /* check state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; - - /* save header structure */ - state->head = head; - head->done = 0; - return Z_OK; -} - -/* - Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found - or when out of input. When called, *have is the number of pattern bytes - found in order so far, in 0..3. On return *have is updated to the new - state. If on return *have equals four, then the pattern was found and the - return value is how many bytes were read including the last byte of the - pattern. If *have is less than four, then the pattern has not been found - yet and the return value is len. In the latter case, syncsearch() can be - called again with more data and the *have state. *have is initialized to - zero for the first call. - */ -local unsigned syncsearch(have, buf, len) -unsigned FAR *have; -unsigned char FAR *buf; -unsigned len; -{ - unsigned got; - unsigned next; - - got = *have; - next = 0; - while (next < len && got < 4) { - if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) - got++; - else if (buf[next]) - got = 0; - else - got = 4 - got; - next++; - } - *have = got; - return next; -} - -int ZEXPORT inflateSync(strm) -z_streamp strm; -{ - unsigned len; /* number of bytes to look at or looked at */ - unsigned long in, out; /* temporary to save total_in and total_out */ - unsigned char buf[4]; /* to restore bit buffer to byte string */ - struct inflate_state FAR *state; - - /* check parameters */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; - - /* if first time, start search in bit buffer */ - if (state->mode != SYNC) { - state->mode = SYNC; - state->hold <<= state->bits & 7; - state->bits -= state->bits & 7; - len = 0; - while (state->bits >= 8) { - buf[len++] = (unsigned char)(state->hold); - state->hold >>= 8; - state->bits -= 8; - } - state->have = 0; - syncsearch(&(state->have), buf, len); - } - - /* search available input */ - len = syncsearch(&(state->have), strm->next_in, strm->avail_in); - strm->avail_in -= len; - strm->next_in += len; - strm->total_in += len; - - /* return no joy or set up to restart inflate() on a new block */ - if (state->have != 4) return Z_DATA_ERROR; - in = strm->total_in; out = strm->total_out; - inflateReset(strm); - strm->total_in = in; strm->total_out = out; - state->mode = TYPE; - return Z_OK; -} - -/* - Returns true if inflate is currently at the end of a block generated by - Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP - implementation to provide an additional safety check. PPP uses - Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored - block. When decompressing, PPP checks that at the end of input packet, - inflate is waiting for these length bytes. - */ -int ZEXPORT inflateSyncPoint(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - return state->mode == STORED && state->bits == 0; -} - -int ZEXPORT inflateCopy(dest, source) -z_streamp dest; -z_streamp source; -{ - struct inflate_state FAR *state; - struct inflate_state FAR *copy; - unsigned char FAR *window; - unsigned wsize; - - /* check input */ - if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || - source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)source->state; - - /* allocate space */ - copy = (struct inflate_state FAR *) - ZALLOC(source, 1, sizeof(struct inflate_state)); - if (copy == Z_NULL) return Z_MEM_ERROR; - window = Z_NULL; - if (state->window != Z_NULL) { - window = (unsigned char FAR *) - ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); - if (window == Z_NULL) { - ZFREE(source, copy); - return Z_MEM_ERROR; - } - } - - /* copy state */ - zmemcpy(dest, source, sizeof(z_stream)); - zmemcpy(copy, state, sizeof(struct inflate_state)); - if (state->lencode >= state->codes && - state->lencode <= state->codes + ENOUGH - 1) { - copy->lencode = copy->codes + (state->lencode - state->codes); - copy->distcode = copy->codes + (state->distcode - state->codes); - } - copy->next = copy->codes + (state->next - state->codes); - if (window != Z_NULL) { - wsize = 1U << state->wbits; - zmemcpy(window, state->window, wsize); - } - copy->window = window; - dest->state = (struct internal_state FAR *)copy; - return Z_OK; -} +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + strm->adler = 1; /* to support ill-conceived Java test suite */ + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->wsize = 0; + state->whave = 0; + state->write = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + if (state->mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy(dest, source, sizeof(z_stream)); + zmemcpy(copy, state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} diff --git a/plugins/CDVDiso/src/3rdparty/zlib/inflate.h b/plugins/CDVDiso/src/3rdparty/zlib/inflate.h index fbbc871432..07bd3e78a7 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/inflate.h +++ b/plugins/CDVDiso/src/3rdparty/zlib/inflate.h @@ -1,115 +1,115 @@ -/* inflate.h -- internal inflate state definition - * Copyright (C) 1995-2004 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer decoding by inflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip decoding - should be left enabled. */ -#ifndef NO_GZIP -# define GUNZIP -#endif - -/* Possible inflate modes between inflate() calls */ -typedef enum { - HEAD, /* i: waiting for magic header */ - FLAGS, /* i: waiting for method and flags (gzip) */ - TIME, /* i: waiting for modification time (gzip) */ - OS, /* i: waiting for extra flags and operating system (gzip) */ - EXLEN, /* i: waiting for extra length (gzip) */ - EXTRA, /* i: waiting for extra bytes (gzip) */ - NAME, /* i: waiting for end of file name (gzip) */ - COMMENT, /* i: waiting for end of comment (gzip) */ - HCRC, /* i: waiting for header crc (gzip) */ - DICTID, /* i: waiting for dictionary check value */ - DICT, /* waiting for inflateSetDictionary() call */ - TYPE, /* i: waiting for type bits, including last-flag bit */ - TYPEDO, /* i: same, but skip check to exit inflate on new block */ - STORED, /* i: waiting for stored size (length and complement) */ - COPY, /* i/o: waiting for input or output to copy stored block */ - TABLE, /* i: waiting for dynamic block table lengths */ - LENLENS, /* i: waiting for code length code lengths */ - CODELENS, /* i: waiting for length/lit and distance code lengths */ - LEN, /* i: waiting for length/lit code */ - LENEXT, /* i: waiting for length extra bits */ - DIST, /* i: waiting for distance code */ - DISTEXT, /* i: waiting for distance extra bits */ - MATCH, /* o: waiting for output space to copy string */ - LIT, /* o: waiting for output space to write literal */ - CHECK, /* i: waiting for 32-bit check value */ - LENGTH, /* i: waiting for 32-bit length (gzip) */ - DONE, /* finished check, done -- remain here until reset */ - BAD, /* got a data error -- remain here until reset */ - MEM, /* got an inflate() memory error -- remain here until reset */ - SYNC /* looking for synchronization bytes to restart inflate() */ -} inflate_mode; - -/* - State transitions between above modes - - - (most modes can go to the BAD or MEM mode -- not shown for clarity) - - Process header: - HEAD -> (gzip) or (zlib) - (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME - NAME -> COMMENT -> HCRC -> TYPE - (zlib) -> DICTID or TYPE - DICTID -> DICT -> TYPE - Read deflate blocks: - TYPE -> STORED or TABLE or LEN or CHECK - STORED -> COPY -> TYPE - TABLE -> LENLENS -> CODELENS -> LEN - Read deflate codes: - LEN -> LENEXT or LIT or TYPE - LENEXT -> DIST -> DISTEXT -> MATCH -> LEN - LIT -> LEN - Process trailer: - CHECK -> LENGTH -> DONE - */ - -/* state maintained between inflate() calls. Approximately 7K bytes. */ -struct inflate_state { - inflate_mode mode; /* current inflate mode */ - int last; /* true if processing last block */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - int havedict; /* true if dictionary provided */ - int flags; /* gzip header method and flags (0 if zlib) */ - unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ - unsigned long check; /* protected copy of check value */ - unsigned long total; /* protected copy of output count */ - gz_headerp head; /* where to save gzip header information */ - /* sliding window */ - unsigned wbits; /* log base 2 of requested window size */ - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned write; /* window write index */ - unsigned char FAR *window; /* allocated sliding window, if needed */ - /* bit accumulator */ - unsigned long hold; /* input bit accumulator */ - unsigned bits; /* number of bits in "in" */ - /* for string and stored block copying */ - unsigned length; /* literal or length of data to copy */ - unsigned offset; /* distance back to copy string from */ - /* for table and code decoding */ - unsigned extra; /* extra bits needed */ - /* fixed and dynamic code tables */ - code const FAR *lencode; /* starting table for length/literal codes */ - code const FAR *distcode; /* starting table for distance codes */ - unsigned lenbits; /* index bits for lencode */ - unsigned distbits; /* index bits for distcode */ - /* dynamic table building */ - unsigned ncode; /* number of code length code lengths */ - unsigned nlen; /* number of length code lengths */ - unsigned ndist; /* number of distance code lengths */ - unsigned have; /* number of code lengths in lens[] */ - code FAR *next; /* next available space in codes[] */ - unsigned short lens[320]; /* temporary storage for code lengths */ - unsigned short work[288]; /* work area for code table building */ - code codes[ENOUGH]; /* space for code tables */ -}; +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/plugins/CDVDiso/src/3rdparty/zlib/inftrees.c b/plugins/CDVDiso/src/3rdparty/zlib/inftrees.c index 38ded81c36..8a9c13ff03 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/inftrees.c +++ b/plugins/CDVDiso/src/3rdparty/zlib/inftrees.c @@ -1,329 +1,329 @@ -/* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" - -#define MAXBITS 15 - -const char inflate_copyright[] = - " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* - Build a set of tables to decode the provided canonical Huffman code. - The code lengths are lens[0..codes-1]. The result starts at *table, - whose indices are 0..2^bits-1. work is a writable array of at least - lens shorts, which is used as a work area. type is the type of code - to be generated, CODES, LENS, or DISTS. On return, zero is success, - -1 is an invalid code, and +1 means that ENOUGH isn't enough. table - on return points to the next available entry's address. bits is the - requested root table index bits, and on return it is the actual root - table index bits. It will differ if the request is greater than the - longest code or if it is less than the shortest code. - */ -int inflate_table(type, lens, codes, table, bits, work) -codetype type; -unsigned short FAR *lens; -unsigned codes; -code FAR * FAR *table; -unsigned FAR *bits; -unsigned short FAR *work; -{ - unsigned len; /* a code's length in bits */ - unsigned sym; /* index of code symbols */ - unsigned min, max; /* minimum and maximum code lengths */ - unsigned root; /* number of index bits for root table */ - unsigned curr; /* number of index bits for current table */ - unsigned drop; /* code bits to drop for sub-table */ - int left; /* number of prefix codes available */ - unsigned used; /* code entries in table used */ - unsigned huff; /* Huffman code */ - unsigned incr; /* for incrementing code, index */ - unsigned fill; /* index for replicating entries */ - unsigned low; /* low bits for current root entry */ - unsigned mask; /* mask for low root bits */ - code this; /* table entry for duplication */ - code FAR *next; /* next available space in table */ - const unsigned short FAR *base; /* base value table to use */ - const unsigned short FAR *extra; /* extra bits table to use */ - int end; /* use base and extra for symbol > end */ - unsigned short count[MAXBITS+1]; /* number of codes of each length */ - unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ - static const unsigned short lbase[31] = { /* Length codes 257..285 base */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - static const unsigned short lext[31] = { /* Length codes 257..285 extra */ - 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; - static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577, 0, 0}; - static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ - 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, - 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, - 28, 28, 29, 29, 64, 64}; - - /* - Process a set of code lengths to create a canonical Huffman code. The - code lengths are lens[0..codes-1]. Each length corresponds to the - symbols 0..codes-1. The Huffman code is generated by first sorting the - symbols by length from short to long, and retaining the symbol order - for codes with equal lengths. Then the code starts with all zero bits - for the first code of the shortest length, and the codes are integer - increments for the same length, and zeros are appended as the length - increases. For the deflate format, these bits are stored backwards - from their more natural integer increment ordering, and so when the - decoding tables are built in the large loop below, the integer codes - are incremented backwards. - - This routine assumes, but does not check, that all of the entries in - lens[] are in the range 0..MAXBITS. The caller must assure this. - 1..MAXBITS is interpreted as that code length. zero means that that - symbol does not occur in this code. - - The codes are sorted by computing a count of codes for each length, - creating from that a table of starting indices for each length in the - sorted table, and then entering the symbols in order in the sorted - table. The sorted table is work[], with that space being provided by - the caller. - - The length counts are used for other purposes as well, i.e. finding - the minimum and maximum length codes, determining if there are any - codes at all, checking for a valid set of lengths, and looking ahead - at length counts to determine sub-table sizes when building the - decoding tables. - */ - - /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ - for (len = 0; len <= MAXBITS; len++) - count[len] = 0; - for (sym = 0; sym < codes; sym++) - count[lens[sym]]++; - - /* bound code lengths, force root to be within code lengths */ - root = *bits; - for (max = MAXBITS; max >= 1; max--) - if (count[max] != 0) break; - if (root > max) root = max; - if (max == 0) { /* no symbols to code at all */ - this.op = (unsigned char)64; /* invalid code marker */ - this.bits = (unsigned char)1; - this.val = (unsigned short)0; - *(*table)++ = this; /* make a table to force an error */ - *(*table)++ = this; - *bits = 1; - return 0; /* no symbols, but wait for decoding to report error */ - } - for (min = 1; min <= MAXBITS; min++) - if (count[min] != 0) break; - if (root < min) root = min; - - /* check for an over-subscribed or incomplete set of lengths */ - left = 1; - for (len = 1; len <= MAXBITS; len++) { - left <<= 1; - left -= count[len]; - if (left < 0) return -1; /* over-subscribed */ - } - if (left > 0 && (type == CODES || max != 1)) - return -1; /* incomplete set */ - - /* generate offsets into symbol table for each length for sorting */ - offs[1] = 0; - for (len = 1; len < MAXBITS; len++) - offs[len + 1] = offs[len] + count[len]; - - /* sort symbols by length, by symbol order within each length */ - for (sym = 0; sym < codes; sym++) - if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; - - /* - Create and fill in decoding tables. In this loop, the table being - filled is at next and has curr index bits. The code being used is huff - with length len. That code is converted to an index by dropping drop - bits off of the bottom. For codes where len is less than drop + curr, - those top drop + curr - len bits are incremented through all values to - fill the table with replicated entries. - - root is the number of index bits for the root table. When len exceeds - root, sub-tables are created pointed to by the root entry with an index - of the low root bits of huff. This is saved in low to check for when a - new sub-table should be started. drop is zero when the root table is - being filled, and drop is root when sub-tables are being filled. - - When a new sub-table is needed, it is necessary to look ahead in the - code lengths to determine what size sub-table is needed. The length - counts are used for this, and so count[] is decremented as codes are - entered in the tables. - - used keeps track of how many table entries have been allocated from the - provided *table space. It is checked when a LENS table is being made - against the space in *table, ENOUGH, minus the maximum space needed by - the worst case distance code, MAXD. This should never happen, but the - sufficiency of ENOUGH has not been proven exhaustively, hence the check. - This assumes that when type == LENS, bits == 9. - - sym increments through all symbols, and the loop terminates when - all codes of length max, i.e. all codes, have been processed. This - routine permits incomplete codes, so another loop after this one fills - in the rest of the decoding tables with invalid code markers. - */ - - /* set up for code type */ - switch (type) { - case CODES: - base = extra = work; /* dummy value--not used */ - end = 19; - break; - case LENS: - base = lbase; - base -= 257; - extra = lext; - extra -= 257; - end = 256; - break; - default: /* DISTS */ - base = dbase; - extra = dext; - end = -1; - } - - /* initialize state for loop */ - huff = 0; /* starting code */ - sym = 0; /* starting code symbol */ - len = min; /* starting code length */ - next = *table; /* current table to fill in */ - curr = root; /* current table index bits */ - drop = 0; /* current bits to drop from code for index */ - low = (unsigned)(-1); /* trigger new sub-table when len > root */ - used = 1U << root; /* use root table entries */ - mask = used - 1; /* mask for comparing low */ - - /* check available table space */ - if (type == LENS && used >= ENOUGH - MAXD) - return 1; - - /* process all codes and make table entries */ - for (;;) { - /* create table entry */ - this.bits = (unsigned char)(len - drop); - if ((int)(work[sym]) < end) { - this.op = (unsigned char)0; - this.val = work[sym]; - } - else if ((int)(work[sym]) > end) { - this.op = (unsigned char)(extra[work[sym]]); - this.val = base[work[sym]]; - } - else { - this.op = (unsigned char)(32 + 64); /* end of block */ - this.val = 0; - } - - /* replicate for those indices with low len bits equal to huff */ - incr = 1U << (len - drop); - fill = 1U << curr; - min = fill; /* save offset to next table */ - do { - fill -= incr; - next[(huff >> drop) + fill] = this; - } while (fill != 0); - - /* backwards increment the len-bit code huff */ - incr = 1U << (len - 1); - while (huff & incr) - incr >>= 1; - if (incr != 0) { - huff &= incr - 1; - huff += incr; - } - else - huff = 0; - - /* go to next symbol, update count, len */ - sym++; - if (--(count[len]) == 0) { - if (len == max) break; - len = lens[work[sym]]; - } - - /* create new sub-table if needed */ - if (len > root && (huff & mask) != low) { - /* if first time, transition to sub-tables */ - if (drop == 0) - drop = root; - - /* increment past last table */ - next += min; /* here min is 1 << curr */ - - /* determine length of next table */ - curr = len - drop; - left = (int)(1 << curr); - while (curr + drop < max) { - left -= count[curr + drop]; - if (left <= 0) break; - curr++; - left <<= 1; - } - - /* check for enough space */ - used += 1U << curr; - if (type == LENS && used >= ENOUGH - MAXD) - return 1; - - /* point entry in root table to sub-table */ - low = huff & mask; - (*table)[low].op = (unsigned char)curr; - (*table)[low].bits = (unsigned char)root; - (*table)[low].val = (unsigned short)(next - *table); - } - } - - /* - Fill in rest of table for incomplete codes. This loop is similar to the - loop above in incrementing huff for table indices. It is assumed that - len is equal to curr + drop, so there is no loop needed to increment - through high index bits. When the current sub-table is filled, the loop - drops back to the root table to fill in any remaining entries there. - */ - this.op = (unsigned char)64; /* invalid code marker */ - this.bits = (unsigned char)(len - drop); - this.val = (unsigned short)0; - while (huff != 0) { - /* when done with sub-table, drop back to root table */ - if (drop != 0 && (huff & mask) != low) { - drop = 0; - len = root; - next = *table; - this.bits = (unsigned char)len; - } - - /* put invalid code marker in table */ - next[huff >> drop] = this; - - /* backwards increment the len-bit code huff */ - incr = 1U << (len - 1); - while (huff & incr) - incr >>= 1; - if (incr != 0) { - huff &= incr - 1; - huff += incr; - } - else - huff = 0; - } - - /* set return parameters */ - *table += used; - *bits = root; - return 0; -} +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)1; + this.val = (unsigned short)0; + *(*table)++ = this; /* make a table to force an error */ + *(*table)++ = this; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/plugins/CDVDiso/src/3rdparty/zlib/inftrees.h b/plugins/CDVDiso/src/3rdparty/zlib/inftrees.h index dc0fd567ea..b1104c87e7 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/inftrees.h +++ b/plugins/CDVDiso/src/3rdparty/zlib/inftrees.h @@ -1,55 +1,55 @@ -/* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* Structure for decoding tables. Each entry provides either the - information needed to do the operation requested by the code that - indexed that table entry, or it provides a pointer to another - table that indexes more bits of the code. op indicates whether - the entry is a pointer to another table, a literal, a length or - distance, an end-of-block, or an invalid code. For a table - pointer, the low four bits of op is the number of index bits of - that table. For a length or distance, the low four bits of op - is the number of extra bits to get after the code. bits is - the number of bits in this code or part of the code to drop off - of the bit buffer. val is the actual byte to output in the case - of a literal, the base length or distance, or the offset from - the current table to the next table. Each entry is four bytes. */ -typedef struct { - unsigned char op; /* operation, extra bits, table bits */ - unsigned char bits; /* bits in this part of the code */ - unsigned short val; /* offset in table or code value */ -} code; - -/* op values as set by inflate_table(): - 00000000 - literal - 0000tttt - table link, tttt != 0 is the number of table index bits - 0001eeee - length or distance, eeee is the number of extra bits - 01100000 - end of block - 01000000 - invalid code - */ - -/* Maximum size of dynamic tree. The maximum found in a long but non- - exhaustive search was 1444 code structures (852 for length/literals - and 592 for distances, the latter actually the result of an - exhaustive search). The true maximum is not known, but the value - below is more than safe. */ -#define ENOUGH 2048 -#define MAXD 592 - -/* Type of code to build for inftable() */ -typedef enum { - CODES, - LENS, - DISTS -} codetype; - -extern int inflate_table OF((codetype type, unsigned short FAR *lens, - unsigned codes, code FAR * FAR *table, - unsigned FAR *bits, unsigned short FAR *work)); +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1444 code structures (852 for length/literals + and 592 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 2048 +#define MAXD 592 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/plugins/CDVDiso/src/3rdparty/zlib/trees.c b/plugins/CDVDiso/src/3rdparty/zlib/trees.c index 7a04802862..395e4e1681 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/trees.c +++ b/plugins/CDVDiso/src/3rdparty/zlib/trees.c @@ -1,1219 +1,1219 @@ -/* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2005 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process uses several Huffman trees. The more - * common source values are represented by shorter bit sequences. - * - * Each code tree is stored in a compressed form which is itself - * a Huffman encoding of the lengths of all the code strings (in - * ascending order by source values). The actual code strings are - * reconstructed from the lengths in the inflate process, as described - * in the deflate specification. - * - * REFERENCES - * - * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". - * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc - * - * Storer, James A. - * Data Compression: Methods and Theory, pp. 49-50. - * Computer Science Press, 1988. ISBN 0-7167-8156-5. - * - * Sedgewick, R. - * Algorithms, p290. - * Addison-Wesley, 1983. ISBN 0-201-06672-6. - */ - -/* @(#) $Id$ */ - -/* #define GEN_TREES_H */ - -#include "deflate.h" - -#ifdef DEBUG -# include -#endif - -/* =========================================================================== - * Constants - */ - -#define MAX_BL_BITS 7 -/* Bit length codes must not exceed MAX_BL_BITS bits */ - -#define END_BLOCK 256 -/* end of block literal code */ - -#define REP_3_6 16 -/* repeat previous bit length 3-6 times (2 bits of repeat count) */ - -#define REPZ_3_10 17 -/* repeat a zero length 3-10 times (3 bits of repeat count) */ - -#define REPZ_11_138 18 -/* repeat a zero length 11-138 times (7 bits of repeat count) */ - -local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ - = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; - -local const int extra_dbits[D_CODES] /* extra bits for each distance code */ - = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ - = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; - -local const uch bl_order[BL_CODES] - = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; -/* The lengths of the bit length codes are sent in order of decreasing - * probability, to avoid transmitting the lengths for unused bit length codes. - */ - -#define Buf_size (8 * 2*sizeof(char)) -/* Number of bits used within bi_buf. (bi_buf might be implemented on - * more than 16 bits on some systems.) - */ - -/* =========================================================================== - * Local data. These are initialized only once. - */ - -#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ - -#if defined(GEN_TREES_H) || !defined(STDC) -/* non ANSI compilers may not accept trees.h */ - -local ct_data static_ltree[L_CODES+2]; -/* The static literal tree. Since the bit lengths are imposed, there is no - * need for the L_CODES extra codes used during heap construction. However - * The codes 286 and 287 are needed to build a canonical tree (see _tr_init - * below). - */ - -local ct_data static_dtree[D_CODES]; -/* The static distance tree. (Actually a trivial tree since all codes use - * 5 bits.) - */ - -uch _dist_code[DIST_CODE_LEN]; -/* Distance codes. The first 256 values correspond to the distances - * 3 .. 258, the last 256 values correspond to the top 8 bits of - * the 15 bit distances. - */ - -uch _length_code[MAX_MATCH-MIN_MATCH+1]; -/* length code for each normalized match length (0 == MIN_MATCH) */ - -local int base_length[LENGTH_CODES]; -/* First normalized length for each code (0 = MIN_MATCH) */ - -local int base_dist[D_CODES]; -/* First normalized distance for each code (0 = distance of 1) */ - -#else -# include "trees.h" -#endif /* GEN_TREES_H */ - -struct static_tree_desc_s { - const ct_data *static_tree; /* static tree or NULL */ - const intf *extra_bits; /* extra bits for each code or NULL */ - int extra_base; /* base index for extra_bits */ - int elems; /* max number of elements in the tree */ - int max_length; /* max bit length for the codes */ -}; - -local static_tree_desc static_l_desc = -{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; - -local static_tree_desc static_d_desc = -{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; - -local static_tree_desc static_bl_desc = -{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; - -/* =========================================================================== - * Local (static) routines in this file. - */ - -local void tr_static_init OF((void)); -local void init_block OF((deflate_state *s)); -local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); -local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); -local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); -local void build_tree OF((deflate_state *s, tree_desc *desc)); -local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local int build_bl_tree OF((deflate_state *s)); -local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, - int blcodes)); -local void compress_block OF((deflate_state *s, ct_data *ltree, - ct_data *dtree)); -local void set_data_type OF((deflate_state *s)); -local unsigned bi_reverse OF((unsigned value, int length)); -local void bi_windup OF((deflate_state *s)); -local void bi_flush OF((deflate_state *s)); -local void copy_block OF((deflate_state *s, charf *buf, unsigned len, - int header)); - -#ifdef GEN_TREES_H -local void gen_trees_header OF((void)); -#endif - -#ifndef DEBUG -# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) - /* Send a code of the given tree. c and tree must not have side effects */ - -#else /* DEBUG */ -# define send_code(s, c, tree) \ - { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ - send_bits(s, tree[c].Code, tree[c].Len); } -#endif - -/* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ -#define put_short(s, w) { \ - put_byte(s, (uch)((w) & 0xff)); \ - put_byte(s, (uch)((ush)(w) >> 8)); \ -} - -/* =========================================================================== - * Send a value on a given number of bits. - * IN assertion: length <= 16 and value fits in length bits. - */ -#ifdef DEBUG -local void send_bits OF((deflate_state *s, int value, int length)); - -local void send_bits(s, value, length) - deflate_state *s; - int value; /* value to send */ - int length; /* number of bits */ -{ - Tracevv((stderr," l %2d v %4x ", length, value)); - Assert(length > 0 && length <= 15, "invalid length"); - s->bits_sent += (ulg)length; - - /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) - * unused bits in value. - */ - if (s->bi_valid > (int)Buf_size - length) { - s->bi_buf |= (value << s->bi_valid); - put_short(s, s->bi_buf); - s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); - s->bi_valid += length - Buf_size; - } else { - s->bi_buf |= value << s->bi_valid; - s->bi_valid += length; - } -} -#else /* !DEBUG */ - -#define send_bits(s, value, length) \ -{ int len = length;\ - if (s->bi_valid > (int)Buf_size - len) {\ - int val = value;\ - s->bi_buf |= (val << s->bi_valid);\ - put_short(s, s->bi_buf);\ - s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ - s->bi_valid += len - Buf_size;\ - } else {\ - s->bi_buf |= (value) << s->bi_valid;\ - s->bi_valid += len;\ - }\ -} -#endif /* DEBUG */ - - -/* the arguments must not have side effects */ - -/* =========================================================================== - * Initialize the various 'constant' tables. - */ -local void tr_static_init() -{ -#if defined(GEN_TREES_H) || !defined(STDC) - static int static_init_done = 0; - int n; /* iterates over tree elements */ - int bits; /* bit counter */ - int length; /* length value */ - int code; /* code value */ - int dist; /* distance index */ - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - if (static_init_done) return; - - /* For some embedded targets, global variables are not initialized: */ - static_l_desc.static_tree = static_ltree; - static_l_desc.extra_bits = extra_lbits; - static_d_desc.static_tree = static_dtree; - static_d_desc.extra_bits = extra_dbits; - static_bl_desc.extra_bits = extra_blbits; - - /* Initialize the mapping length (0..255) -> length code (0..28) */ - length = 0; - for (code = 0; code < LENGTH_CODES-1; code++) { - base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ - dist = 0; - for (code = 0 ; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ - for ( ; code < D_CODES; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { - _dist_code[256 + dist++] = (uch)code; - } - } - Assert (dist == 256, "tr_static_init: 256+dist != 512"); - - /* Construct the codes of the static literal tree */ - for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; - n = 0; - while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; - while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; - while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; - while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; - /* Codes 286 and 287 do not exist, but we must include them in the - * tree construction to get a canonical Huffman tree (longest code - * all ones) - */ - gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); - - /* The static distance tree is trivial: */ - for (n = 0; n < D_CODES; n++) { - static_dtree[n].Len = 5; - static_dtree[n].Code = bi_reverse((unsigned)n, 5); - } - static_init_done = 1; - -# ifdef GEN_TREES_H - gen_trees_header(); -# endif -#endif /* defined(GEN_TREES_H) || !defined(STDC) */ -} - -/* =========================================================================== - * Genererate the file trees.h describing the static trees. - */ -#ifdef GEN_TREES_H -# ifndef DEBUG -# include -# endif - -# define SEPARATOR(i, last, width) \ - ((i) == (last)? "\n};\n\n" : \ - ((i) % (width) == (width)-1 ? ",\n" : ", ")) - -void gen_trees_header() -{ - FILE *header = fopen("trees.h", "w"); - int i; - - Assert (header != NULL, "Can't open trees.h"); - fprintf(header, - "/* header created automatically with -DGEN_TREES_H */\n\n"); - - fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); - for (i = 0; i < L_CODES+2; i++) { - fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, - static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); - } - - fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); - for (i = 0; i < D_CODES; i++) { - fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, - static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); - } - - fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); - for (i = 0; i < DIST_CODE_LEN; i++) { - fprintf(header, "%2u%s", _dist_code[i], - SEPARATOR(i, DIST_CODE_LEN-1, 20)); - } - - fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); - for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { - fprintf(header, "%2u%s", _length_code[i], - SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); - } - - fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); - for (i = 0; i < LENGTH_CODES; i++) { - fprintf(header, "%1u%s", base_length[i], - SEPARATOR(i, LENGTH_CODES-1, 20)); - } - - fprintf(header, "local const int base_dist[D_CODES] = {\n"); - for (i = 0; i < D_CODES; i++) { - fprintf(header, "%5u%s", base_dist[i], - SEPARATOR(i, D_CODES-1, 10)); - } - - fclose(header); -} -#endif /* GEN_TREES_H */ - -/* =========================================================================== - * Initialize the tree data structures for a new zlib stream. - */ -void _tr_init(s) - deflate_state *s; -{ - tr_static_init(); - - s->l_desc.dyn_tree = s->dyn_ltree; - s->l_desc.stat_desc = &static_l_desc; - - s->d_desc.dyn_tree = s->dyn_dtree; - s->d_desc.stat_desc = &static_d_desc; - - s->bl_desc.dyn_tree = s->bl_tree; - s->bl_desc.stat_desc = &static_bl_desc; - - s->bi_buf = 0; - s->bi_valid = 0; - s->last_eob_len = 8; /* enough lookahead for inflate */ -#ifdef DEBUG - s->compressed_len = 0L; - s->bits_sent = 0L; -#endif - - /* Initialize the first block of the first file: */ - init_block(s); -} - -/* =========================================================================== - * Initialize a new block. - */ -local void init_block(s) - deflate_state *s; -{ - int n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; - for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; - for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; - - s->dyn_ltree[END_BLOCK].Freq = 1; - s->opt_len = s->static_len = 0L; - s->last_lit = s->matches = 0; -} - -#define SMALLEST 1 -/* Index within the heap array of least frequent node in the Huffman tree */ - - -/* =========================================================================== - * Remove the smallest element from the heap and recreate the heap with - * one less element. Updates heap and heap_len. - */ -#define pqremove(s, tree, top) \ -{\ - top = s->heap[SMALLEST]; \ - s->heap[SMALLEST] = s->heap[s->heap_len--]; \ - pqdownheap(s, tree, SMALLEST); \ -} - -/* =========================================================================== - * Compares to subtrees, using the tree depth as tie breaker when - * the subtrees have equal frequency. This minimizes the worst case length. - */ -#define smaller(tree, n, m, depth) \ - (tree[n].Freq < tree[m].Freq || \ - (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) - -/* =========================================================================== - * Restore the heap property by moving down the tree starting at node k, - * exchanging a node with the smallest of its two sons if necessary, stopping - * when the heap property is re-established (each father smaller than its - * two sons). - */ -local void pqdownheap(s, tree, k) - deflate_state *s; - ct_data *tree; /* the tree to restore */ - int k; /* node to move down */ -{ - int v = s->heap[k]; - int j = k << 1; /* left son of k */ - while (j <= s->heap_len) { - /* Set j to the smallest of the two sons: */ - if (j < s->heap_len && - smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { - j++; - } - /* Exit if v is smaller than both sons */ - if (smaller(tree, v, s->heap[j], s->depth)) break; - - /* Exchange v with the smallest son */ - s->heap[k] = s->heap[j]; k = j; - - /* And continue down the tree, setting j to the left son of k */ - j <<= 1; - } - s->heap[k] = v; -} - -/* =========================================================================== - * Compute the optimal bit lengths for a tree and update the total bit length - * for the current block. - * IN assertion: the fields freq and dad are set, heap[heap_max] and - * above are the tree nodes sorted by increasing frequency. - * OUT assertions: the field len is set to the optimal bit length, the - * array bl_count contains the frequencies for each bit length. - * The length opt_len is updated; static_len is also updated if stree is - * not null. - */ -local void gen_bitlen(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ -{ - ct_data *tree = desc->dyn_tree; - int max_code = desc->max_code; - const ct_data *stree = desc->stat_desc->static_tree; - const intf *extra = desc->stat_desc->extra_bits; - int base = desc->stat_desc->extra_base; - int max_length = desc->stat_desc->max_length; - int h; /* heap index */ - int n, m; /* iterate over the tree elements */ - int bits; /* bit length */ - int xbits; /* extra bits */ - ush f; /* frequency */ - int overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; - - /* In a first pass, compute the optimal bit lengths (which may - * overflow in the case of the bit length tree). - */ - tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - - for (h = s->heap_max+1; h < HEAP_SIZE; h++) { - n = s->heap[h]; - bits = tree[tree[n].Dad].Len + 1; - if (bits > max_length) bits = max_length, overflow++; - tree[n].Len = (ush)bits; - /* We overwrite tree[n].Dad which is no longer needed */ - - if (n > max_code) continue; /* not a leaf node */ - - s->bl_count[bits]++; - xbits = 0; - if (n >= base) xbits = extra[n-base]; - f = tree[n].Freq; - s->opt_len += (ulg)f * (bits + xbits); - if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); - } - if (overflow == 0) return; - - Trace((stderr,"\nbit length overflow\n")); - /* This happens for example on obj2 and pic of the Calgary corpus */ - - /* Find the first bit length which could increase: */ - do { - bits = max_length-1; - while (s->bl_count[bits] == 0) bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ - s->bl_count[max_length]--; - /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] - */ - overflow -= 2; - } while (overflow > 0); - - /* Now recompute all bit lengths, scanning in increasing frequency. - * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - * lengths instead of fixing only the wrong ones. This idea is taken - * from 'ar' written by Haruhiko Okumura.) - */ - for (bits = max_length; bits != 0; bits--) { - n = s->bl_count[bits]; - while (n != 0) { - m = s->heap[--h]; - if (m > max_code) continue; - if ((unsigned) tree[m].Len != (unsigned) bits) { - Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); - s->opt_len += ((long)bits - (long)tree[m].Len) - *(long)tree[m].Freq; - tree[m].Len = (ush)bits; - } - n--; - } - } -} - -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -local void gen_codes (tree, max_code, bl_count) - ct_data *tree; /* the tree to decorate */ - int max_code; /* largest code with non zero frequency */ - ushf *bl_count; /* number of codes at each bit length */ -{ - ush next_code[MAX_BITS+1]; /* next code value for each bit length */ - ush code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (code + bl_count[bits-1]) << 1; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; - const ct_data *stree = desc->stat_desc->static_tree; - int elems = desc->stat_desc->elems; - int n, m; /* iterate over heap elements */ - int max_code = -1; /* largest code with non zero frequency */ - int node; /* new node being created */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - s->heap_len = 0, s->heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) { - if (tree[n].Freq != 0) { - s->heap[++(s->heap_len)] = max_code = n; - s->depth[n] = 0; - } else { - tree[n].Len = 0; - } - } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (s->heap_len < 2) { - node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); - tree[node].Freq = 1; - s->depth[node] = 0; - s->opt_len--; if (stree) s->static_len -= stree[node].Len; - /* node is 0 or 1 so it does not have extra bits */ - } - desc->max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - node = elems; /* next internal node of the tree */ - do { - pqremove(s, tree, n); /* n = node of least frequency */ - m = s->heap[SMALLEST]; /* m = node of next least frequency */ - - s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ - s->heap[--(s->heap_max)] = m; - - /* Create a new node father of n and m */ - tree[node].Freq = tree[n].Freq + tree[m].Freq; - s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? - s->depth[n] : s->depth[m]) + 1); - tree[n].Dad = tree[m].Dad = (ush)node; -#ifdef DUMP_BL_TREE - if (tree == s->bl_tree) { - fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", - node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); - } -#endif - /* and insert the new node in the heap */ - s->heap[SMALLEST] = node++; - pqdownheap(s, tree, SMALLEST); - - } while (s->heap_len >= 2); - - s->heap[--(s->heap_max)] = s->heap[SMALLEST]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen(s, (tree_desc *)desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes ((ct_data *)tree, max_code, s->bl_count); -} - -/* =========================================================================== - * Scan a literal or distance tree to determine the frequencies of the codes - * in the bit length tree. - */ -local void scan_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].Len = (ush)0xffff; /* guard */ - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - s->bl_tree[curlen].Freq += count; - } else if (curlen != 0) { - if (curlen != prevlen) s->bl_tree[curlen].Freq++; - s->bl_tree[REP_3_6].Freq++; - } else if (count <= 10) { - s->bl_tree[REPZ_3_10].Freq++; - } else { - s->bl_tree[REPZ_11_138].Freq++; - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Send a literal or distance tree in compressed form, using the codes in - * bl_tree. - */ -local void send_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - /* tree[max_code+1].Len = -1; */ /* guard already set */ - if (nextlen == 0) max_count = 138, min_count = 3; - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - do { send_code(s, curlen, s->bl_tree); } while (--count != 0); - - } else if (curlen != 0) { - if (curlen != prevlen) { - send_code(s, curlen, s->bl_tree); count--; - } - Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); - - } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); - - } else { - send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Construct the Huffman tree for the bit lengths and return the index in - * bl_order of the last bit length code to send. - */ -local int build_bl_tree(s) - deflate_state *s; -{ - int max_blindex; /* index of last bit length code of non zero freq */ - - /* Determine the bit length frequencies for literal and distance trees */ - scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); - scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); - - /* Build the bit length tree: */ - build_tree(s, (tree_desc *)(&(s->bl_desc))); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - */ - - /* Determine the number of bit length codes to send. The pkzip format - * requires that at least 4 bit length codes be sent. (appnote.txt says - * 3 but the actual value used is 4.) - */ - for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { - if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; - } - /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*(max_blindex+1) + 5+5+4; - Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", - s->opt_len, s->static_len)); - - return max_blindex; -} - -/* =========================================================================== - * Send the header for a block using dynamic Huffman trees: the counts, the - * lengths of the bit length codes, the literal tree and the distance tree. - * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - */ -local void send_all_trees(s, lcodes, dcodes, blcodes) - deflate_state *s; - int lcodes, dcodes, blcodes; /* number of codes for each tree */ -{ - int rank; /* index in bl_order */ - - Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); - Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, - "too many codes"); - Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ - for (rank = 0; rank < blcodes; rank++) { - Tracev((stderr, "\nbl code %2d ", bl_order[rank])); - send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); - } - Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ - Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ - Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); -} - -/* =========================================================================== - * Send a stored block - */ -void _tr_stored_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ -{ - send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ -#ifdef DEBUG - s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; - s->compressed_len += (stored_len + 4) << 3; -#endif - copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ -} - -/* =========================================================================== - * Send one empty static block to give enough lookahead for inflate. - * This takes 10 bits, of which 7 may remain in the bit buffer. - * The current inflate code requires 9 bits of lookahead. If the - * last two codes for the previous block (real code plus EOB) were coded - * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode - * the last real code. In this case we send two empty static blocks instead - * of one. (There are no problems if the previous block is stored or fixed.) - * To simplify the code, we assume the worst case of last real code encoded - * on one bit only. - */ -void _tr_align(s) - deflate_state *s; -{ - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); -#ifdef DEBUG - s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ -#endif - bi_flush(s); - /* Of the 10 bits for the empty block, we have already sent - * (10 - bi_valid) bits. The lookahead for the last real code (before - * the EOB of the previous block) was thus at least one plus the length - * of the EOB plus what we have just sent of the empty static block. - */ - if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); -#ifdef DEBUG - s->compressed_len += 10L; -#endif - bi_flush(s); - } - s->last_eob_len = 7; -} - -/* =========================================================================== - * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. - */ -void _tr_flush_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block, or NULL if too old */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ -{ - ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ - int max_blindex = 0; /* index of last bit length code of non zero freq */ - - /* Build the Huffman trees unless a stored block is forced */ - if (s->level > 0) { - - /* Check if the file is binary or text */ - if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) - set_data_type(s); - - /* Construct the literal and distance trees */ - build_tree(s, (tree_desc *)(&(s->l_desc))); - Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - - build_tree(s, (tree_desc *)(&(s->d_desc))); - Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ - - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(s); - - /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; - - Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", - opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - s->last_lit)); - - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; - - } else { - Assert(buf != (char*)0, "lost buf"); - opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ - } - -#ifdef FORCE_STORED - if (buf != (char*)0) { /* force stored block */ -#else - if (stored_len+4 <= opt_lenb && buf != (char*)0) { - /* 4: two words for the lengths */ -#endif - /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - * Otherwise we can't have processed more than WSIZE input bytes since - * the last block flush, because compression would have been - * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - * transform a block into a stored block. - */ - _tr_stored_block(s, buf, stored_len, eof); - -#ifdef FORCE_STATIC - } else if (static_lenb >= 0) { /* force static trees */ -#else - } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { -#endif - send_bits(s, (STATIC_TREES<<1)+eof, 3); - compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); -#ifdef DEBUG - s->compressed_len += 3 + s->static_len; -#endif - } else { - send_bits(s, (DYN_TREES<<1)+eof, 3); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, - max_blindex+1); - compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); -#ifdef DEBUG - s->compressed_len += 3 + s->opt_len; -#endif - } - Assert (s->compressed_len == s->bits_sent, "bad compressed size"); - /* The above check is made mod 2^32, for files larger than 512 MB - * and uLong implemented on 32 bits. - */ - init_block(s); - - if (eof) { - bi_windup(s); -#ifdef DEBUG - s->compressed_len += 7; /* align on byte boundary */ -#endif - } - Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - s->compressed_len-7*eof)); -} - -/* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ -int _tr_tally (s, dist, lc) - deflate_state *s; - unsigned dist; /* distance of matched string */ - unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ -{ - s->d_buf[s->last_lit] = (ush)dist; - s->l_buf[s->last_lit++] = (uch)lc; - if (dist == 0) { - /* lc is the unmatched char */ - s->dyn_ltree[lc].Freq++; - } else { - s->matches++; - /* Here, lc is the match length - MIN_MATCH */ - dist--; /* dist = match distance - 1 */ - Assert((ush)dist < (ush)MAX_DIST(s) && - (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && - (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - - s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; - s->dyn_dtree[d_code(dist)].Freq++; - } - -#ifdef TRUNCATE_BLOCK - /* Try to guess if it is profitable to stop the current block here */ - if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { - /* Compute an upper bound for the compressed length */ - ulg out_length = (ulg)s->last_lit*8L; - ulg in_length = (ulg)((long)s->strstart - s->block_start); - int dcode; - for (dcode = 0; dcode < D_CODES; dcode++) { - out_length += (ulg)s->dyn_dtree[dcode].Freq * - (5L+extra_dbits[dcode]); - } - out_length >>= 3; - Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", - s->last_lit, in_length, out_length, - 100L - out_length*100L/in_length)); - if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; - } -#endif - return (s->last_lit == s->lit_bufsize-1); - /* We avoid equality with lit_bufsize because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ -} - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -local void compress_block(s, ltree, dtree) - deflate_state *s; - ct_data *ltree; /* literal tree */ - ct_data *dtree; /* distance tree */ -{ - unsigned dist; /* distance of matched string */ - int lc; /* match length or unmatched char (if dist == 0) */ - unsigned lx = 0; /* running index in l_buf */ - unsigned code; /* the code to send */ - int extra; /* number of extra bits to send */ - - if (s->last_lit != 0) do { - dist = s->d_buf[lx]; - lc = s->l_buf[lx++]; - if (dist == 0) { - send_code(s, lc, ltree); /* send a literal byte */ - Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = _length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra != 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra != 0) { - dist -= base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ - Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, - "pendingBuf overflow"); - - } while (lx < s->last_lit); - - send_code(s, END_BLOCK, ltree); - s->last_eob_len = ltree[END_BLOCK].Len; -} - -/* =========================================================================== - * Set the data type to BINARY or TEXT, using a crude approximation: - * set it to Z_TEXT if all symbols are either printable characters (33 to 255) - * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. - * IN assertion: the fields Freq of dyn_ltree are set. - */ -local void set_data_type(s) - deflate_state *s; -{ - int n; - - for (n = 0; n < 9; n++) - if (s->dyn_ltree[n].Freq != 0) - break; - if (n == 9) - for (n = 14; n < 32; n++) - if (s->dyn_ltree[n].Freq != 0) - break; - s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; -} - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -local unsigned bi_reverse(code, len) - unsigned code; /* the value to invert */ - int len; /* its bit length */ -{ - register unsigned res = 0; - do { - res |= code & 1; - code >>= 1, res <<= 1; - } while (--len > 0); - return res >> 1; -} - -/* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ -local void bi_flush(s) - deflate_state *s; -{ - if (s->bi_valid == 16) { - put_short(s, s->bi_buf); - s->bi_buf = 0; - s->bi_valid = 0; - } else if (s->bi_valid >= 8) { - put_byte(s, (Byte)s->bi_buf); - s->bi_buf >>= 8; - s->bi_valid -= 8; - } -} - -/* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ -local void bi_windup(s) - deflate_state *s; -{ - if (s->bi_valid > 8) { - put_short(s, s->bi_buf); - } else if (s->bi_valid > 0) { - put_byte(s, (Byte)s->bi_buf); - } - s->bi_buf = 0; - s->bi_valid = 0; -#ifdef DEBUG - s->bits_sent = (s->bits_sent+7) & ~7; -#endif -} - -/* =========================================================================== - * Copy a stored block, storing first the length and its - * one's complement if requested. - */ -local void copy_block(s, buf, len, header) - deflate_state *s; - charf *buf; /* the input data */ - unsigned len; /* its length */ - int header; /* true if block header must be written */ -{ - bi_windup(s); /* align on byte boundary */ - s->last_eob_len = 8; /* enough lookahead for inflate */ - - if (header) { - put_short(s, (ush)len); - put_short(s, (ush)~len); -#ifdef DEBUG - s->bits_sent += 2*16; -#endif - } -#ifdef DEBUG - s->bits_sent += (ulg)len<<3; -#endif - while (len--) { - put_byte(s, *buf++); - } -} +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2005 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) + set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to BINARY or TEXT, using a crude approximation: + * set it to Z_TEXT if all symbols are either printable characters (33 to 255) + * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local void set_data_type(s) + deflate_state *s; +{ + int n; + + for (n = 0; n < 9; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + if (n == 9) + for (n = 14; n < 32; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/plugins/CDVDiso/src/3rdparty/zlib/trees.h b/plugins/CDVDiso/src/3rdparty/zlib/trees.h index 1ca868b848..72facf900f 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/trees.h +++ b/plugins/CDVDiso/src/3rdparty/zlib/trees.h @@ -1,128 +1,128 @@ -/* header created automatically with -DGEN_TREES_H */ - -local const ct_data static_ltree[L_CODES+2] = { -{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, -{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, -{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, -{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, -{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, -{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, -{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, -{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, -{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, -{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, -{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, -{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, -{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, -{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, -{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, -{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, -{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, -{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, -{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, -{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, -{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, -{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, -{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, -{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, -{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, -{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, -{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, -{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, -{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, -{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, -{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, -{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, -{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, -{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, -{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, -{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, -{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, -{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, -{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, -{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, -{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, -{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, -{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, -{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, -{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, -{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, -{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, -{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, -{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, -{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, -{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, -{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, -{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, -{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, -{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, -{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, -{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, -{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} -}; - -local const ct_data static_dtree[D_CODES] = { -{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, -{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, -{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, -{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, -{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, -{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} -}; - -const uch _dist_code[DIST_CODE_LEN] = { - 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, - 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, -10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, -11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, -12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, -18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 -}; - -const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, -13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, -17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, -19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, -21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, -22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 -}; - -local const int base_length[LENGTH_CODES] = { -0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, -64, 80, 96, 112, 128, 160, 192, 224, 0 -}; - -local const int base_dist[D_CODES] = { - 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, - 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, - 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 -}; - +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/plugins/CDVDiso/src/3rdparty/zlib/uncompr.c b/plugins/CDVDiso/src/3rdparty/zlib/uncompr.c index ad6db0a67c..b59e3d0def 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/uncompr.c +++ b/plugins/CDVDiso/src/3rdparty/zlib/uncompr.c @@ -1,61 +1,61 @@ -/* uncompr.c -- decompress a memory buffer - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -/* =========================================================================== - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted. -*/ -int ZEXPORT uncompress (dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ - z_stream stream; - int err; - - stream.next_in = (Bytef*)source; - stream.avail_in = (uInt)sourceLen; - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; - - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; - - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - - err = inflateInit(&stream); - if (err != Z_OK) return err; - - err = inflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - inflateEnd(&stream); - if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) - return Z_DATA_ERROR; - return err; - } - *destLen = stream.total_out; - - err = inflateEnd(&stream); - return err; -} +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/plugins/CDVDiso/src/3rdparty/zlib/zconf.h b/plugins/CDVDiso/src/3rdparty/zlib/zconf.h index e3b0c962e3..03a9431c8b 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/zconf.h +++ b/plugins/CDVDiso/src/3rdparty/zlib/zconf.h @@ -1,332 +1,332 @@ -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#ifndef ZCONF_H -#define ZCONF_H - -/* - * If you *really* need a unique prefix for all types and library functions, - * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. - */ -#ifdef Z_PREFIX -# define deflateInit_ z_deflateInit_ -# define deflate z_deflate -# define deflateEnd z_deflateEnd -# define inflateInit_ z_inflateInit_ -# define inflate z_inflate -# define inflateEnd z_inflateEnd -# define deflateInit2_ z_deflateInit2_ -# define deflateSetDictionary z_deflateSetDictionary -# define deflateCopy z_deflateCopy -# define deflateReset z_deflateReset -# define deflateParams z_deflateParams -# define deflateBound z_deflateBound -# define deflatePrime z_deflatePrime -# define inflateInit2_ z_inflateInit2_ -# define inflateSetDictionary z_inflateSetDictionary -# define inflateSync z_inflateSync -# define inflateSyncPoint z_inflateSyncPoint -# define inflateCopy z_inflateCopy -# define inflateReset z_inflateReset -# define inflateBack z_inflateBack -# define inflateBackEnd z_inflateBackEnd -# define compress z_compress -# define compress2 z_compress2 -# define compressBound z_compressBound -# define uncompress z_uncompress -# define adler32 z_adler32 -# define crc32 z_crc32 -# define get_crc_table z_get_crc_table -# define zError z_zError - -# define alloc_func z_alloc_func -# define free_func z_free_func -# define in_func z_in_func -# define out_func z_out_func -# define Byte z_Byte -# define uInt z_uInt -# define uLong z_uLong -# define Bytef z_Bytef -# define charf z_charf -# define intf z_intf -# define uIntf z_uIntf -# define uLongf z_uLongf -# define voidpf z_voidpf -# define voidp z_voidp -#endif - -#if defined(__MSDOS__) && !defined(MSDOS) -# define MSDOS -#endif -#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) -# define OS2 -#endif -#if defined(_WINDOWS) && !defined(WINDOWS) -# define WINDOWS -#endif -#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) -# ifndef WIN32 -# define WIN32 -# endif -#endif -#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) -# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) -# ifndef SYS16BIT -# define SYS16BIT -# endif -# endif -#endif - -/* - * Compile with -DMAXSEG_64K if the alloc function cannot allocate more - * than 64k bytes at a time (needed on systems with 16-bit int). - */ -#ifdef SYS16BIT -# define MAXSEG_64K -#endif -#ifdef MSDOS -# define UNALIGNED_OK -#endif - -#ifdef __STDC_VERSION__ -# ifndef STDC -# define STDC -# endif -# if __STDC_VERSION__ >= 199901L -# ifndef STDC99 -# define STDC99 -# endif -# endif -#endif -#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) -# define STDC -#endif -#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) -# define STDC -#endif -#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) -# define STDC -#endif -#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) -# define STDC -#endif - -#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ -# define STDC -#endif - -#ifndef STDC -# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ -# define const /* note: need a more gentle solution here */ -# endif -#endif - -/* Some Mac compilers merge all .h files incorrectly: */ -#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) -# define NO_DUMMY_DECL -#endif - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# ifdef MAXSEG_64K -# define MAX_MEM_LEVEL 8 -# else -# define MAX_MEM_LEVEL 9 -# endif -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2. - * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files - * created by gzip. (Files created by minigzip can still be extracted by - * gzip.) - */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - (1 << (windowBits+2)) + (1 << (memLevel+9)) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects. -*/ - - /* Type declarations */ - -#ifndef OF /* function prototypes */ -# ifdef STDC -# define OF(args) args -# else -# define OF(args) () -# endif -#endif - -/* The following definitions for FAR are needed only for MSDOS mixed - * model programming (small or medium model with some far allocations). - * This was tested only with MSC; for other MSDOS compilers you may have - * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, - * just define FAR to be empty. - */ -#ifdef SYS16BIT -# if defined(M_I86SM) || defined(M_I86MM) - /* MSC small or medium model */ -# define SMALL_MEDIUM -# ifdef _MSC_VER -# define FAR _far -# else -# define FAR far -# endif -# endif -# if (defined(__SMALL__) || defined(__MEDIUM__)) - /* Turbo C small or medium model */ -# define SMALL_MEDIUM -# ifdef __BORLANDC__ -# define FAR _far -# else -# define FAR far -# endif -# endif -#endif - -#if defined(WINDOWS) || defined(WIN32) - /* If building or using zlib as a DLL, define ZLIB_DLL. - * This is not mandatory, but it offers a little performance increase. - */ -# ifdef ZLIB_DLL -# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) -# ifdef ZLIB_INTERNAL -# define ZEXTERN extern __declspec(dllexport) -# else -# define ZEXTERN extern __declspec(dllimport) -# endif -# endif -# endif /* ZLIB_DLL */ - /* If building or using zlib with the WINAPI/WINAPIV calling convention, - * define ZLIB_WINAPI. - * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. - */ -# ifdef ZLIB_WINAPI -# ifdef FAR -# undef FAR -# endif -# include - /* No need for _export, use ZLIB.DEF instead. */ - /* For complete Windows compatibility, use WINAPI, not __stdcall. */ -# define ZEXPORT WINAPI -# ifdef WIN32 -# define ZEXPORTVA WINAPIV -# else -# define ZEXPORTVA FAR CDECL -# endif -# endif -#endif - -#if defined (__BEOS__) -# ifdef ZLIB_DLL -# ifdef ZLIB_INTERNAL -# define ZEXPORT __declspec(dllexport) -# define ZEXPORTVA __declspec(dllexport) -# else -# define ZEXPORT __declspec(dllimport) -# define ZEXPORTVA __declspec(dllimport) -# endif -# endif -#endif - -#ifndef ZEXTERN -# define ZEXTERN extern -#endif -#ifndef ZEXPORT -# define ZEXPORT -#endif -#ifndef ZEXPORTVA -# define ZEXPORTVA -#endif - -#ifndef FAR -# define FAR -#endif - -#if !defined(__MACTYPES__) -typedef unsigned char Byte; /* 8 bits */ -#endif -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ - -#ifdef SMALL_MEDIUM - /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ -# define Bytef Byte FAR -#else - typedef Byte FAR Bytef; -#endif -typedef char FAR charf; -typedef int FAR intf; -typedef uInt FAR uIntf; -typedef uLong FAR uLongf; - -#ifdef STDC - typedef void const *voidpc; - typedef void FAR *voidpf; - typedef void *voidp; -#else - typedef Byte const *voidpc; - typedef Byte FAR *voidpf; - typedef Byte *voidp; -#endif - -#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ -# include /* for off_t */ -# include /* for SEEK_* and off_t */ -# ifdef VMS -# include /* for off_t */ -# endif -# define z_off_t off_t -#endif -#ifndef SEEK_SET -# define SEEK_SET 0 /* Seek from beginning of file. */ -# define SEEK_CUR 1 /* Seek from current position. */ -# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ -#endif -#ifndef z_off_t -# define z_off_t long -#endif - -#if defined(__OS400__) -# define NO_vsnprintf -#endif - -#if defined(__MVS__) -# define NO_vsnprintf -# ifdef FAR -# undef FAR -# endif -#endif - -/* MVS linker does not support external names larger than 8 bytes */ -#if defined(__MVS__) -# pragma map(deflateInit_,"DEIN") -# pragma map(deflateInit2_,"DEIN2") -# pragma map(deflateEnd,"DEEND") -# pragma map(deflateBound,"DEBND") -# pragma map(inflateInit_,"ININ") -# pragma map(inflateInit2_,"ININ2") -# pragma map(inflateEnd,"INEND") -# pragma map(inflateSync,"INSY") -# pragma map(inflateSetDictionary,"INSEDI") -# pragma map(compressBound,"CMBND") -# pragma map(inflate_table,"INTABL") -# pragma map(inflate_fast,"INFA") -# pragma map(inflate_copyright,"INCOPY") -#endif - -#endif /* ZCONF_H */ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/plugins/CDVDiso/src/3rdparty/zlib/zlib.h b/plugins/CDVDiso/src/3rdparty/zlib/zlib.h index 62d0e4675b..022817927c 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/zlib.h +++ b/plugins/CDVDiso/src/3rdparty/zlib/zlib.h @@ -1,1357 +1,1357 @@ -/* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.3, July 18th, 2005 - - Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - - - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). -*/ - -#ifndef ZLIB_H -#define ZLIB_H - -#include "zconf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define ZLIB_VERSION "1.2.3" -#define ZLIB_VERNUM 0x1230 - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed - data. This version of the library supports only one compression method - (deflation) but other algorithms will be added later and will have the same - stream interface. - - Compression can be done in a single step if the buffers are large - enough (for example if an input file is mmap'ed), or can be done by - repeated calls of the compression function. In the latter case, the - application must provide more input and/or consume the output - (providing more output space) before each call. - - The compressed data format used by default by the in-memory functions is - the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped - around a deflate stream, which is itself documented in RFC 1951. - - The library also supports reading and writing files in gzip (.gz) format - with an interface similar to that of stdio using the functions that start - with "gz". The gzip format is different from the zlib format. gzip is a - gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. - - This library can optionally read and write gzip streams in memory as well. - - The zlib format was designed to be compact and fast for use in memory - and on communications channels. The gzip format was designed for single- - file compression on file systems, has a larger header than zlib to maintain - directory information, and uses a different, slower check method than zlib. - - The library does not install any signal handler. The decoder checks - the consistency of the compressed data, so the library should never - crash even in case of corrupted input. -*/ - -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address)); - -struct internal_state; - -typedef struct z_stream_s { - Bytef *next_in; /* next input byte */ - uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total nb of input bytes read so far */ - - Bytef *next_out; /* next output byte should be put there */ - uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total nb of bytes output so far */ - - char *msg; /* last error message, NULL if no error */ - struct internal_state FAR *state; /* not visible by applications */ - - alloc_func zalloc; /* used to allocate the internal state */ - free_func zfree; /* used to free the internal state */ - voidpf opaque; /* private data object passed to zalloc and zfree */ - - int data_type; /* best guess about the data type: binary or text */ - uLong adler; /* adler32 value of the uncompressed data */ - uLong reserved; /* reserved for future use */ -} z_stream; - -typedef z_stream FAR *z_streamp; - -/* - gzip header information passed to and from zlib routines. See RFC 1952 - for more details on the meanings of these fields. -*/ -typedef struct gz_header_s { - int text; /* true if compressed data believed to be text */ - uLong time; /* modification time */ - int xflags; /* extra flags (not used when writing a gzip file) */ - int os; /* operating system */ - Bytef *extra; /* pointer to extra field or Z_NULL if none */ - uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ - uInt extra_max; /* space at extra (only when reading header) */ - Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ - uInt name_max; /* space at name (only when reading header) */ - Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ - uInt comm_max; /* space at comment (only when reading header) */ - int hcrc; /* true if there was or will be a header crc */ - int done; /* true when done reading gzip header (not used - when writing a gzip file) */ -} gz_header; - -typedef gz_header FAR *gz_headerp; - -/* - The application must update next_in and avail_in when avail_in has - dropped to zero. It must update next_out and avail_out when avail_out - has dropped to zero. The application must initialize zalloc, zfree and - opaque before calling the init function. All other fields are set by the - compression library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - If zlib is used in a multi-threaded application, zalloc and zfree must be - thread safe. - - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this - if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, - pointers returned by zalloc for objects of exactly 65536 bytes *must* - have their offset normalized to zero. The default allocation function - provided by this library ensures this (see zutil.c). To reduce memory - requirements and avoid any allocation of 64K objects, at the expense of - compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or - progress reports. After compression, total_in holds the total size of - the uncompressed data and may be saved for use in the decompressor - (particularly if the decompressor wants to decompress everything in - a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ -#define Z_SYNC_FLUSH 2 -#define Z_FULL_FLUSH 3 -#define Z_FINISH 4 -#define Z_BLOCK 5 -/* Allowed flush values; see deflate() and inflate() below for details */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_NEED_DICT 2 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -#define Z_VERSION_ERROR (-6) -/* Return codes for the compression/decompression functions. Negative - * values are errors, positive values are used for special but normal events. - */ - -#define Z_NO_COMPRESSION 0 -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_RLE 3 -#define Z_FIXED 4 -#define Z_DEFAULT_STRATEGY 0 -/* compression strategy; see deflateInit2() below for details */ - -#define Z_BINARY 0 -#define Z_TEXT 1 -#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ -#define Z_UNKNOWN 2 -/* Possible values of the data_type field (though see inflate()) */ - -#define Z_DEFLATED 8 -/* The deflate compression method (the only one supported in this version) */ - -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - -#define zlib_version zlibVersion() -/* for compatibility with versions < 1.0.2 */ - - /* basic functions */ - -ZEXTERN const char * ZEXPORT zlibVersion OF((void)); -/* The application can compare zlibVersion and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is - not compatible with the zlib.h header file used by the application. - This check is automatically made by deflateInit and inflateInit. - */ - -/* -ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); - - Initializes the internal stream state for compression. The fields - zalloc, zfree and opaque must be initialized before by the caller. - If zalloc and zfree are set to Z_NULL, deflateInit updates them to - use default allocation functions. - - The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: - 1 gives best speed, 9 gives best compression, 0 gives no compression at - all (the input data is simply copied a block at a time). - Z_DEFAULT_COMPRESSION requests a default compromise between speed and - compression (currently equivalent to level 6). - - deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if level is not a valid compression level, - Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible - with the version assumed by the caller (ZLIB_VERSION). - msg is set to null if there is no error message. deflateInit does not - perform any compression: this will be done by deflate(). -*/ - - -ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); -/* - deflate compresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce some - output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. deflate performs one or both of the - following actions: - - - Compress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in and avail_in are updated and - processing will resume at this point for the next call of deflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. This action is forced if the parameter flush is non zero. - Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary (in interactive applications). - Some output may be provided even if flush is not set. - - Before the call of deflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating avail_in or avail_out accordingly; avail_out - should never be zero before the call. The application can consume the - compressed output when it wants, for example when the output buffer is full - (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK - and with zero avail_out, it must be called again after making room in the - output buffer because there might be more output pending. - - Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to - decide how much data to accumualte before producing output, in order to - maximize compression. - - If the parameter flush is set to Z_SYNC_FLUSH, all pending output is - flushed to the output buffer and the output is aligned on a byte boundary, so - that the decompressor can get all input data available so far. (In particular - avail_in is zero after the call if enough output space has been provided - before the call.) Flushing may degrade compression for some compression - algorithms and so it should be used only when necessary. - - If flush is set to Z_FULL_FLUSH, all output is flushed as with - Z_SYNC_FLUSH, and the compression state is reset so that decompression can - restart from this point if previous compressed data has been damaged or if - random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - compression. - - If deflate returns with avail_out == 0, this function must be called again - with the same value of the flush parameter and more output space (updated - avail_out), until the flush is complete (deflate returns with non-zero - avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that - avail_out is greater than six to avoid repeated flush markers due to - avail_out == 0 on return. - - If the parameter flush is set to Z_FINISH, pending input is processed, - pending output is flushed and deflate returns with Z_STREAM_END if there - was enough output space; if deflate returns with Z_OK, this function must be - called again with Z_FINISH and more output space (updated avail_out) but no - more input data, until it returns with Z_STREAM_END or an error. After - deflate has returned Z_STREAM_END, the only possible operations on the - stream are deflateReset or deflateEnd. - - Z_FINISH can be used immediately after deflateInit if all the compression - is to be done in a single step. In this case, avail_out must be at least - the value returned by deflateBound (see below). If deflate does not return - Z_STREAM_END, then it must be called again as described above. - - deflate() sets strm->adler to the adler32 checksum of all input read - so far (that is, total_in bytes). - - deflate() may update strm->data_type if it can make a good guess about - the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered - binary. This field is only for information purposes and does not affect - the compression algorithm in any manner. - - deflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if all input has been - consumed and all output has been produced (only when flush is set to - Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible - (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not - fatal, and deflate() can be called again with more input and more output - space to continue compressing. -*/ - - -ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the - stream state was inconsistent, Z_DATA_ERROR if the stream was freed - prematurely (some input or output was discarded). In the error case, - msg may be set but then points to a static string (which must not be - deallocated). -*/ - - -/* -ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); - - Initializes the internal stream state for decompression. The fields - next_in, avail_in, zalloc, zfree and opaque must be initialized before by - the caller. If next_in is not Z_NULL and avail_in is large enough (the exact - value depends on the compression method), inflateInit determines the - compression method from the zlib header and allocates all data structures - accordingly; otherwise the allocation will be deferred to the first call of - inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to - use default allocation functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller. msg is set to null if there is no error - message. inflateInit does not perform any decompression apart from reading - the zlib header if present: this will be done by inflate(). (So next_in and - avail_in may be modified, but next_out and avail_out are unchanged.) -*/ - - -ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); -/* - inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce - some output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. inflate performs one or both of the - following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing - will resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() provides as much output as possible, until there - is no more input data or no more space in the output buffer (see below - about the flush parameter). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating the next_* and avail_* values accordingly. - The application can consume the uncompressed output when it wants, for - example when the output buffer is full (avail_out == 0), or after each - call of inflate(). If inflate returns Z_OK and with zero avail_out, it - must be called again after making room in the output buffer because there - might be more output pending. - - The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, - Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much - output as possible to the output buffer. Z_BLOCK requests that inflate() stop - if and when it gets to the next deflate block boundary. When decoding the - zlib or gzip format, this will cause inflate() to return immediately after - the header and before the first block. When doing a raw inflate, inflate() - will go ahead and process the first block, and will return when it gets to - the end of that block, or when it runs out of data. - - The Z_BLOCK option assists in appending to or combining deflate streams. - Also to assist in this, on return inflate() will set strm->data_type to the - number of unused bits in the last byte taken from strm->next_in, plus 64 - if inflate() is currently decoding the last block in the deflate stream, - plus 128 if inflate() returned immediately after decoding an end-of-block - code or decoding the complete header up to just before the first byte of the - deflate stream. The end-of-block will not be indicated until all of the - uncompressed data from that block has been written to strm->next_out. The - number of unused bits may in general be greater than seven, except when - bit 7 of data_type is set, in which case the number of unused bits will be - less than eight. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step - (a single call of inflate), the parameter flush should be set to - Z_FINISH. In this case all pending input is processed and all pending - output is flushed; avail_out must be large enough to hold all the - uncompressed data. (The size of the uncompressed data may have been saved - by the compressor for this purpose.) The next operation on this stream must - be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster approach - may be used for the single inflate() call. - - In this implementation, inflate() always flushes as much output as - possible to the output buffer, and always uses the faster approach on the - first call. So the only effect of the flush parameter in this implementation - is on the return value of inflate(), as noted below, or when it returns early - because Z_BLOCK is used. - - If a preset dictionary is needed after this call (see inflateSetDictionary - below), inflate sets strm->adler to the adler32 checksum of the dictionary - chosen by the compressor and returns Z_NEED_DICT; otherwise it sets - strm->adler to the adler32 checksum of all output produced so far (that is, - total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described - below. At the end of the stream, inflate() checks that its computed adler32 - checksum is equal to that saved by the compressor and returns Z_STREAM_END - only if the checksum is correct. - - inflate() will decompress and check either zlib-wrapped or gzip-wrapped - deflate data. The header type is detected automatically. Any information - contained in the gzip header is not retained, so applications that need that - information should instead use raw inflate, see inflateInit2() below, or - inflateBack() and perform their own processing of the gzip header and - trailer. - - inflate() returns Z_OK if some progress has been made (more input processed - or more output produced), Z_STREAM_END if the end of the compressed data has - been reached and all uncompressed output has been produced, Z_NEED_DICT if a - preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect check - value), Z_STREAM_ERROR if the stream structure was inconsistent (for example - if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, - Z_BUF_ERROR if no progress is possible or if there was not enough room in the - output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and - inflate() can be called again with more input and more output space to - continue decompressing. If Z_DATA_ERROR is returned, the application may then - call inflateSync() to look for a good compression block if a partial recovery - of the data is desired. -*/ - - -ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). -*/ - - /* Advanced functions */ - -/* - The following functions are needed only in some special applications. -*/ - -/* -ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); - - This is another version of deflateInit with more compression options. The - fields next_in, zalloc, zfree and opaque must be initialized before by - the caller. - - The method parameter is the compression method. It must be Z_DEFLATED in - this version of the library. - - The windowBits parameter is the base two logarithm of the window size - (the size of the history buffer). It should be in the range 8..15 for this - version of the library. Larger values of this parameter result in better - compression at the expense of memory usage. The default value is 15 if - deflateInit is used instead. - - windowBits can also be -8..-15 for raw deflate. In this case, -windowBits - determines the window size. deflate() will then generate raw deflate data - with no zlib header or trailer, and will not compute an adler32 check value. - - windowBits can also be greater than 15 for optional gzip encoding. Add - 16 to windowBits to write a simple gzip header and trailer around the - compressed data instead of a zlib wrapper. The gzip header will have no - file name, no extra data, no comment, no modification time (set to zero), - no header crc, and the operating system will be set to 255 (unknown). If a - gzip stream is being written, strm->adler is a crc32 instead of an adler32. - - The memLevel parameter specifies how much memory should be allocated - for the internal compression state. memLevel=1 uses minimum memory but - is slow and reduces compression ratio; memLevel=9 uses maximum memory - for optimal speed. The default value is 8. See zconf.h for total memory - usage as a function of windowBits and memLevel. - - The strategy parameter is used to tune the compression algorithm. Use the - value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match), or Z_RLE to limit match distances to one (run-length - encoding). Filtered data consists mostly of small values with a somewhat - random distribution. In this case, the compression algorithm is tuned to - compress them better. The effect of Z_FILTERED is to force more Huffman - coding and less string matching; it is somewhat intermediate between - Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as - Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy - parameter only affects the compression ratio but not the correctness of the - compressed output even if it is not set appropriately. Z_FIXED prevents the - use of dynamic Huffman codes, allowing for a simpler decoder for special - applications. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid - method). msg is set to null if there is no error message. deflateInit2 does - not perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the compression dictionary from the given byte sequence - without producing any compressed output. This function must be called - immediately after deflateInit, deflateInit2 or deflateReset, before any - call of deflate. The compressor and decompressor must use exactly the same - dictionary (see inflateSetDictionary). - - The dictionary should consist of strings (byte sequences) that are likely - to be encountered later in the data to be compressed, with the most commonly - used strings preferably put towards the end of the dictionary. Using a - dictionary is most useful when the data to be compressed is short and can be - predicted with good accuracy; the data can then be compressed better than - with the default empty dictionary. - - Depending on the size of the compression data structures selected by - deflateInit or deflateInit2, a part of the dictionary may in effect be - discarded, for example if the dictionary is larger than the window size in - deflate or deflate2. Thus the strings most likely to be useful should be - put at the end of the dictionary, not at the front. In addition, the - current implementation of deflate will use at most the window size minus - 262 bytes of the provided dictionary. - - Upon return of this function, strm->adler is set to the adler32 value - of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The adler32 value - applies to the whole dictionary even if only a subset of the dictionary is - actually used by the compressor.) If a raw deflate was requested, then the - adler32 value is not computed and strm->adler is not set. - - deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent (for example if deflate has already been called for this stream - or if the compression method is bsort). deflateSetDictionary does not - perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when several compression strategies will be - tried, for example when there are several ways of pre-processing the input - data with a filter. The streams that will be discarded should then be freed - by calling deflateEnd. Note that deflateCopy duplicates the internal - compression state which can be quite large, so this strategy is slow and - can consume lots of memory. - - deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); -/* - This function is equivalent to deflateEnd followed by deflateInit, - but does not free and reallocate all the internal compression state. - The stream will keep the same compression level and any other attributes - that may have been set by deflateInit2. - - deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, - int level, - int strategy)); -/* - Dynamically update the compression level and compression strategy. The - interpretation of level and strategy is as in deflateInit2. This can be - used to switch between compression and straight copy of the input data, or - to switch to a different kind of input data requiring a different - strategy. If the compression level is changed, the input available so far - is compressed with the old level (and may be flushed); the new level will - take effect only at the next call of deflate(). - - Before the call of deflateParams, the stream state must be set as for - a call of deflate(), since the currently available input may have to - be compressed and flushed. In particular, strm->avail_out must be non-zero. - - deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source - stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR - if strm->avail_out was zero. -*/ - -ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, - int good_length, - int max_lazy, - int nice_length, - int max_chain)); -/* - Fine tune deflate's internal compression parameters. This should only be - used by someone who understands the algorithm used by zlib's deflate for - searching for the best matching string, and even then only by the most - fanatic optimizer trying to squeeze out the last compressed bit for their - specific input data. Read the deflate.c source code for the meaning of the - max_lazy, good_length, nice_length, and max_chain parameters. - - deflateTune() can be called after deflateInit() or deflateInit2(), and - returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. - */ - -ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, - uLong sourceLen)); -/* - deflateBound() returns an upper bound on the compressed size after - deflation of sourceLen bytes. It must be called after deflateInit() - or deflateInit2(). This would be used to allocate an output buffer - for deflation in a single pass, and so would be called before deflate(). -*/ - -ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - deflatePrime() inserts bits in the deflate output stream. The intent - is that this function is used to start off the deflate output with the - bits leftover from a previous deflate stream when appending to it. As such, - this function can only be used for raw deflate, and must be used before the - first deflate() call after a deflateInit2() or deflateReset(). bits must be - less than or equal to 16, and that many of the least significant bits of - value will be inserted in the output. - - deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, - gz_headerp head)); -/* - deflateSetHeader() provides gzip header information for when a gzip - stream is requested by deflateInit2(). deflateSetHeader() may be called - after deflateInit2() or deflateReset() and before the first call of - deflate(). The text, time, os, extra field, name, and comment information - in the provided gz_header structure are written to the gzip header (xflag is - ignored -- the extra flags are set according to the compression level). The - caller must assure that, if not Z_NULL, name and comment are terminated with - a zero byte, and that if extra is not Z_NULL, that extra_len bytes are - available there. If hcrc is true, a gzip header crc is included. Note that - the current versions of the command-line version of gzip (up through version - 1.3.x) do not support header crc's, and will report that it is a "multi-part - gzip file" and give up. - - If deflateSetHeader is not used, the default gzip header has text false, - the time set to zero, and os set to 255, with no extra, name, or comment - fields. The gzip header is returned to the default state by deflateReset(). - - deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, - int windowBits)); - - This is another version of inflateInit with an extra parameter. The - fields next_in, avail_in, zalloc, zfree and opaque must be initialized - before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library. The default value is 15 if inflateInit is used - instead. windowBits must be greater than or equal to the windowBits value - provided to deflateInit2() while compressing, or it must be equal to 15 if - deflateInit2() was not used. If a compressed stream with a larger window - size is given as input, inflate() will return with the error code - Z_DATA_ERROR instead of trying to allocate a larger window. - - windowBits can also be -8..-15 for raw inflate. In this case, -windowBits - determines the window size. inflate() will then process raw deflate data, - not looking for a zlib or gzip header, not generating a check value, and not - looking for any check values for comparison at the end of the stream. This - is for use with other formats that use the deflate compressed data format - such as zip. Those formats provide their own check values. If a custom - format is developed using the raw deflate format for compressed data, it is - recommended that a check value such as an adler32 or a crc32 be applied to - the uncompressed data as is done in the zlib, gzip, and zip formats. For - most applications, the zlib format should be used as is. Note that comments - above on the use in deflateInit2() applies to the magnitude of windowBits. - - windowBits can also be greater than 15 for optional gzip decoding. Add - 32 to windowBits to enable zlib and gzip decoding with automatic header - detection, or add 16 to decode only the gzip format (the zlib format will - return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is - a crc32 instead of an adler32. - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg - is set to null if there is no error message. inflateInit2 does not perform - any decompression apart from reading the zlib header if present: this will - be done by inflate(). (So next_in and avail_in may be modified, but next_out - and avail_out are unchanged.) -*/ - -ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate, - if that call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the adler32 value returned by that call of inflate. - The compressor and decompressor must use exactly the same dictionary (see - deflateSetDictionary). For raw inflate, this function can be called - immediately after inflateInit2() or inflateReset() and before any call of - inflate() to set the dictionary. The application must insure that the - dictionary that was used for compression is provided. - - inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect adler32 value). inflateSetDictionary does not - perform any decompression: this will be done by subsequent calls of - inflate(). -*/ - -ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); -/* - Skips invalid compressed data until a full flush point (see above the - description of deflate with Z_FULL_FLUSH) can be found, or until all - available input is skipped. No output is provided. - - inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR - if no more input was provided, Z_DATA_ERROR if no flush point has been found, - or Z_STREAM_ERROR if the stream structure was inconsistent. In the success - case, the application may save the current current value of total_in which - indicates where valid compressed data was found. In the error case, the - application may repeatedly call inflateSync, providing more input each time, - until success or end of the input data. -*/ - -ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when randomly accessing a large stream. The - first pass through the stream can periodically record the inflate state, - allowing restarting inflate at those points when randomly accessing the - stream. - - inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); -/* - This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate all the internal decompression state. - The stream will keep attributes that may have been set by inflateInit2. - - inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - This function inserts bits in the inflate input stream. The intent is - that this function is used to start inflating at a bit position in the - middle of a byte. The provided bits will be used before any bytes are used - from next_in. This function should only be used with raw inflate, and - should be used before the first inflate() call after inflateInit2() or - inflateReset(). bits must be less than or equal to 16, and that many of the - least significant bits of value will be inserted in the input. - - inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, - gz_headerp head)); -/* - inflateGetHeader() requests that gzip header information be stored in the - provided gz_header structure. inflateGetHeader() may be called after - inflateInit2() or inflateReset(), and before the first call of inflate(). - As inflate() processes the gzip stream, head->done is zero until the header - is completed, at which time head->done is set to one. If a zlib stream is - being decoded, then head->done is set to -1 to indicate that there will be - no gzip header information forthcoming. Note that Z_BLOCK can be used to - force inflate() to return immediately after header processing is complete - and before any actual data is decompressed. - - The text, time, xflags, and os fields are filled in with the gzip header - contents. hcrc is set to true if there is a header CRC. (The header CRC - was valid if done is set to one.) If extra is not Z_NULL, then extra_max - contains the maximum number of bytes to write to extra. Once done is true, - extra_len contains the actual extra field length, and extra contains the - extra field, or that field truncated if extra_max is less than extra_len. - If name is not Z_NULL, then up to name_max characters are written there, - terminated with a zero unless the length is greater than name_max. If - comment is not Z_NULL, then up to comm_max characters are written there, - terminated with a zero unless the length is greater than comm_max. When - any of extra, name, or comment are not Z_NULL and the respective field is - not present in the header, then that field is set to Z_NULL to signal its - absence. This allows the use of deflateSetHeader() with the returned - structure to duplicate the header. However if those fields are set to - allocated memory, then the application will need to save those pointers - elsewhere so that they can be eventually freed. - - If inflateGetHeader is not used, then the header information is simply - discarded. The header is always checked for validity, including the header - CRC if present. inflateReset() will reset the process to discard the header - information. The application would need to call inflateGetHeader() again to - retrieve the header from the next gzip stream. - - inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, - unsigned char FAR *window)); - - Initialize the internal stream state for decompression using inflateBack() - calls. The fields zalloc, zfree and opaque in strm must be initialized - before the call. If zalloc and zfree are Z_NULL, then the default library- - derived memory allocation routines are used. windowBits is the base two - logarithm of the window size, in the range 8..15. window is a caller - supplied buffer of that size. Except for special applications where it is - assured that deflate was used with small window sizes, windowBits must be 15 - and a 32K byte window must be supplied to be able to decompress general - deflate streams. - - See inflateBack() for the usage of these routines. - - inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of - the paramaters are invalid, Z_MEM_ERROR if the internal state could not - be allocated, or Z_VERSION_ERROR if the version of the library does not - match the version of the header file. -*/ - -typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); -typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); - -ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, - in_func in, void FAR *in_desc, - out_func out, void FAR *out_desc)); -/* - inflateBack() does a raw inflate with a single call using a call-back - interface for input and output. This is more efficient than inflate() for - file i/o applications in that it avoids copying between the output and the - sliding window by simply making the window itself the output buffer. This - function trusts the application to not change the output buffer passed by - the output function, at least until inflateBack() returns. - - inflateBackInit() must be called first to allocate the internal state - and to initialize the state with the user-provided window buffer. - inflateBack() may then be used multiple times to inflate a complete, raw - deflate stream with each call. inflateBackEnd() is then called to free - the allocated state. - - A raw deflate stream is one with no zlib or gzip header or trailer. - This routine would normally be used in a utility that reads zip or gzip - files and writes out uncompressed files. The utility would decode the - header and process the trailer on its own, hence this routine expects - only the raw deflate stream to decompress. This is different from the - normal behavior of inflate(), which expects either a zlib or gzip header and - trailer around the deflate stream. - - inflateBack() uses two subroutines supplied by the caller that are then - called by inflateBack() for input and output. inflateBack() calls those - routines until it reads a complete deflate stream and writes out all of the - uncompressed data, or until it encounters an error. The function's - parameters and return types are defined above in the in_func and out_func - typedefs. inflateBack() will call in(in_desc, &buf) which should return the - number of bytes of provided input, and a pointer to that input in buf. If - there is no input available, in() must return zero--buf is ignored in that - case--and inflateBack() will return a buffer error. inflateBack() will call - out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() - should return zero on success, or non-zero on failure. If out() returns - non-zero, inflateBack() will return with an error. Neither in() nor out() - are permitted to change the contents of the window provided to - inflateBackInit(), which is also the buffer that out() uses to write from. - The length written by out() will be at most the window size. Any non-zero - amount of input may be provided by in(). - - For convenience, inflateBack() can be provided input on the first call by - setting strm->next_in and strm->avail_in. If that input is exhausted, then - in() will be called. Therefore strm->next_in must be initialized before - calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called - immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in - must also be initialized, and then if strm->avail_in is not zero, input will - initially be taken from strm->next_in[0 .. strm->avail_in - 1]. - - The in_desc and out_desc parameters of inflateBack() is passed as the - first parameter of in() and out() respectively when they are called. These - descriptors can be optionally used to pass any information that the caller- - supplied in() and out() functions need to do their job. - - On return, inflateBack() will set strm->next_in and strm->avail_in to - pass back any unused input that was provided by the last in() call. The - return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR - if in() or out() returned an error, Z_DATA_ERROR if there was a format - error in the deflate stream (in which case strm->msg is set to indicate the - nature of the error), or Z_STREAM_ERROR if the stream was not properly - initialized. In the case of Z_BUF_ERROR, an input or output error can be - distinguished using strm->next_in which will be Z_NULL only if in() returned - an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to - out() returning non-zero. (in() will always be called before out(), so - strm->next_in is assured to be defined if out() returns non-zero.) Note - that inflateBack() cannot return Z_OK. -*/ - -ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); -/* - All memory allocated by inflateBackInit() is freed. - - inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream - state was inconsistent. -*/ - -ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); -/* Return flags indicating compile-time options. - - Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: - 1.0: size of uInt - 3.2: size of uLong - 5.4: size of voidpf (pointer) - 7.6: size of z_off_t - - Compiler, assembler, and debug options: - 8: DEBUG - 9: ASMV or ASMINF -- use ASM code - 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention - 11: 0 (reserved) - - One-time table building (smaller code, but not thread-safe if true): - 12: BUILDFIXED -- build static block decoding tables when needed - 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed - 14,15: 0 (reserved) - - Library content (indicates missing functionality): - 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking - deflate code when not needed) - 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect - and decode gzip streams (to avoid linking crc code) - 18-19: 0 (reserved) - - Operation variations (changes in library functionality): - 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate - 21: FASTEST -- deflate algorithm with only one, lowest compression level - 22,23: 0 (reserved) - - The sprintf variant used by gzprintf (zero is best): - 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format - 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! - 26: 0 = returns value, 1 = void -- 1 means inferred string length returned - - Remainder: - 27-31: 0 (reserved) - */ - - - /* utility functions */ - -/* - The following utility functions are implemented on top of the - basic stream-oriented functions. To simplify the interface, some - default options are assumed (compression level and memory usage, - standard memory allocation functions). The source code of these - utility functions can easily be modified if you need special options. -*/ - -ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Compresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be at least the value returned - by compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - This function can be used to compress a whole file at once if the - input file is mmap'ed. - compress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer. -*/ - -ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen, - int level)); -/* - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least the value returned by - compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ - -ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); -/* - compressBound() returns an upper bound on the compressed size after - compress() or compress2() on sourceLen bytes. It would be used before - a compress() or compress2() call to allocate the destination buffer. -*/ - -ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. -*/ - - -typedef voidp gzFile; - -ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); -/* - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb") but can also include a compression level - ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for - Huffman only compression as in "wb1h", or 'R' for run-length encoding - as in "wb1R". (See the description of deflateInit2 for more information - about the strategy parameter.) - - gzopen can be used to read a file which is not in gzip format; in this - case gzread will directly read from the file without decompression. - - gzopen returns NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). */ - -ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); -/* - gzdopen() associates a gzFile with the file descriptor fd. File - descriptors are obtained from calls like open, dup, creat, pipe or - fileno (in the file has been previously opened with fopen). - The mode parameter is as in gzopen. - The next call of gzclose on the returned gzFile will also close the - file descriptor fd, just like fclose(fdopen(fd), mode) closes the file - descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). - gzdopen returns NULL if there was insufficient memory to allocate - the (de)compression state. -*/ - -ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); -/* - Dynamically update the compression level or strategy. See the description - of deflateInit2 for the meaning of these parameters. - gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not - opened for writing. -*/ - -ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); -/* - Reads the given number of uncompressed bytes from the compressed file. - If the input file was not in gzip format, gzread copies the given number - of bytes into the buffer. - gzread returns the number of uncompressed bytes actually read (0 for - end of file, -1 for error). */ - -ZEXTERN int ZEXPORT gzwrite OF((gzFile file, - voidpc buf, unsigned len)); -/* - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of uncompressed bytes actually written - (0 in case of error). -*/ - -ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); -/* - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). The number of - uncompressed bytes written is limited to 4095. The caller should assure that - this limit is not exceeded. If it is exceeded, then gzprintf() will return - return an error (0) with nothing written. In this case, there may also be a - buffer overflow with unpredictable consequences, which is possible only if - zlib was compiled with the insecure functions sprintf() or vsprintf() - because the secure snprintf() or vsnprintf() functions were not available. -*/ - -ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); -/* - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. -*/ - -ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); -/* - Reads bytes from the compressed file until len-1 characters are read, or - a newline character is read and transferred to buf, or an end-of-file - condition is encountered. The string is then terminated with a null - character. - gzgets returns buf, or Z_NULL in case of error. -*/ - -ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); -/* - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. -*/ - -ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); -/* - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. -*/ - -ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); -/* - Push one character back onto the stream to be read again later. - Only one character of push-back is allowed. gzungetc() returns the - character pushed, or -1 on failure. gzungetc() will fail if a - character has been pushed but not read yet, or if c is -1. The pushed - character will be discarded if the stream is repositioned with gzseek() - or gzrewind(). -*/ - -ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); -/* - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. The return value is the zlib - error number (see function gzerror below). gzflush returns Z_OK if - the flush parameter is Z_FINISH and all output could be flushed. - gzflush should be called only when strictly necessary because it can - degrade compression. -*/ - -ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, - z_off_t offset, int whence)); -/* - Sets the starting position for the next gzread or gzwrite on the - given compressed file. The offset represents a number of bytes in the - uncompressed data stream. The whence parameter is defined as in lseek(2); - the value SEEK_END is not supported. - If the file is opened for reading, this function is emulated but can be - extremely slow. If the file is opened for writing, only forward seeks are - supported; gzseek then compresses a sequence of zeroes up to the new - starting position. - - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error, in - particular if the file is opened for writing and the new starting position - would be before the current position. -*/ - -ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); -/* - Rewinds the given file. This function is supported only for reading. - - gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) -*/ - -ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); -/* - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. - - gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) -*/ - -ZEXTERN int ZEXPORT gzeof OF((gzFile file)); -/* - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. -*/ - -ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); -/* - Returns 1 if file is being read directly without decompression, otherwise - zero. -*/ - -ZEXTERN int ZEXPORT gzclose OF((gzFile file)); -/* - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. The return value is the zlib - error number (see function gzerror below). -*/ - -ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); -/* - Returns the error message for the last error which occurred on the - given compressed file. errnum is set to zlib error number. If an - error occurred in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. -*/ - -ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); -/* - Clears the error and end-of-file flags for file. This is analogous to the - clearerr() function in stdio. This is useful for continuing to read a gzip - file that is being written concurrently. -*/ - - /* checksum functions */ - -/* - These functions are not related to compression but are exported - anyway because they might be useful in applications using the - compression library. -*/ - -ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); -/* - Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. If buf is NULL, this function returns - the required initial value for the checksum. - An Adler-32 checksum is almost as reliable as a CRC32 but can be computed - much faster. Usage example: - - uLong adler = adler32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - adler = adler32(adler, buffer, length); - } - if (adler != original_adler) error(); -*/ - -ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, - z_off_t len2)); -/* - Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 - and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for - each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of - seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. -*/ - -ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); -/* - Update a running CRC-32 with the bytes buf[0..len-1] and return the - updated CRC-32. If buf is NULL, this function returns the required initial - value for the for the crc. Pre- and post-conditioning (one's complement) is - performed within this function so it shouldn't be done by the application. - Usage example: - - uLong crc = crc32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - crc = crc32(crc, buffer, length); - } - if (crc != original_crc) error(); -*/ - -ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); - -/* - Combine two CRC-32 check values into one. For two sequences of bytes, - seq1 and seq2 with lengths len1 and len2, CRC-32 check values were - calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 - check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and - len2. -*/ - - - /* various hacks, don't look :) */ - -/* deflateInit and inflateInit are macros to allow checking the zlib version - * and the compiler's view of z_stream: - */ -ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy, const char *version, - int stream_size)); -ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, - unsigned char FAR *window, - const char *version, - int stream_size)); -#define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) -#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) -#define inflateBackInit(strm, windowBits, window) \ - inflateBackInit_((strm), (windowBits), (window), \ - ZLIB_VERSION, sizeof(z_stream)) - - -#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) - struct internal_state {int dummy;}; /* hack for buggy compilers */ -#endif - -ZEXTERN const char * ZEXPORT zError OF((int)); -ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); -ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); - -#ifdef __cplusplus -} -#endif - -#endif /* ZLIB_H */ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/plugins/CDVDiso/src/3rdparty/zlib/zutil.c b/plugins/CDVDiso/src/3rdparty/zlib/zutil.c index 0f4bd7871d..d55f5948a3 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/zutil.c +++ b/plugins/CDVDiso/src/3rdparty/zlib/zutil.c @@ -1,318 +1,318 @@ -/* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#include "zutil.h" - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -const char * const z_errmsg[10] = { -"need dictionary", /* Z_NEED_DICT 2 */ -"stream end", /* Z_STREAM_END 1 */ -"", /* Z_OK 0 */ -"file error", /* Z_ERRNO (-1) */ -"stream error", /* Z_STREAM_ERROR (-2) */ -"data error", /* Z_DATA_ERROR (-3) */ -"insufficient memory", /* Z_MEM_ERROR (-4) */ -"buffer error", /* Z_BUF_ERROR (-5) */ -"incompatible version",/* Z_VERSION_ERROR (-6) */ -""}; - - -const char * ZEXPORT zlibVersion() -{ - return ZLIB_VERSION; -} - -uLong ZEXPORT zlibCompileFlags() -{ - uLong flags; - - flags = 0; - switch (sizeof(uInt)) { - case 2: break; - case 4: flags += 1; break; - case 8: flags += 2; break; - default: flags += 3; - } - switch (sizeof(uLong)) { - case 2: break; - case 4: flags += 1 << 2; break; - case 8: flags += 2 << 2; break; - default: flags += 3 << 2; - } - switch (sizeof(voidpf)) { - case 2: break; - case 4: flags += 1 << 4; break; - case 8: flags += 2 << 4; break; - default: flags += 3 << 4; - } - switch (sizeof(z_off_t)) { - case 2: break; - case 4: flags += 1 << 6; break; - case 8: flags += 2 << 6; break; - default: flags += 3 << 6; - } -#ifdef DEBUG - flags += 1 << 8; -#endif -#if defined(ASMV) || defined(ASMINF) - flags += 1 << 9; -#endif -#ifdef ZLIB_WINAPI - flags += 1 << 10; -#endif -#ifdef BUILDFIXED - flags += 1 << 12; -#endif -#ifdef DYNAMIC_CRC_TABLE - flags += 1 << 13; -#endif -#ifdef NO_GZCOMPRESS - flags += 1L << 16; -#endif -#ifdef NO_GZIP - flags += 1L << 17; -#endif -#ifdef PKZIP_BUG_WORKAROUND - flags += 1L << 20; -#endif -#ifdef FASTEST - flags += 1L << 21; -#endif -#ifdef STDC -# ifdef NO_vsnprintf - flags += 1L << 25; -# ifdef HAS_vsprintf_void - flags += 1L << 26; -# endif -# else -# ifdef HAS_vsnprintf_void - flags += 1L << 26; -# endif -# endif -#else - flags += 1L << 24; -# ifdef NO_snprintf - flags += 1L << 25; -# ifdef HAS_sprintf_void - flags += 1L << 26; -# endif -# else -# ifdef HAS_snprintf_void - flags += 1L << 26; -# endif -# endif -#endif - return flags; -} - -#ifdef DEBUG - -# ifndef verbose -# define verbose 0 -# endif -int z_verbose = verbose; - -void z_error (m) - char *m; -{ - fprintf(stderr, "%s\n", m); - exit(1); -} -#endif - -/* exported to allow conversion of error code to string for compress() and - * uncompress() - */ -const char * ZEXPORT zError(err) - int err; -{ - return ERR_MSG(err); -} - -#if defined(_WIN32_WCE) - /* The Microsoft C Run-Time Library for Windows CE doesn't have - * errno. We define it as a global variable to simplify porting. - * Its value is always 0 and should not be used. - */ - int errno = 0; -#endif - -#ifndef HAVE_MEMCPY - -void zmemcpy(dest, source, len) - Bytef* dest; - const Bytef* source; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = *source++; /* ??? to be unrolled */ - } while (--len != 0); -} - -int zmemcmp(s1, s2, len) - const Bytef* s1; - const Bytef* s2; - uInt len; -{ - uInt j; - - for (j = 0; j < len; j++) { - if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; - } - return 0; -} - -void zmemzero(dest, len) - Bytef* dest; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = 0; /* ??? to be unrolled */ - } while (--len != 0); -} -#endif - - -#ifdef SYS16BIT - -#ifdef __TURBOC__ -/* Turbo C in 16-bit mode */ - -# define MY_ZCALLOC - -/* Turbo C malloc() does not allow dynamic allocation of 64K bytes - * and farmalloc(64K) returns a pointer with an offset of 8, so we - * must fix the pointer. Warning: the pointer must be put back to its - * original form in order to free it, use zcfree(). - */ - -#define MAX_PTR 10 -/* 10*64K = 640K */ - -local int next_ptr = 0; - -typedef struct ptr_table_s { - voidpf org_ptr; - voidpf new_ptr; -} ptr_table; - -local ptr_table table[MAX_PTR]; -/* This table is used to remember the original form of pointers - * to large buffers (64K). Such pointers are normalized with a zero offset. - * Since MSDOS is not a preemptive multitasking OS, this table is not - * protected from concurrent access. This hack doesn't work anyway on - * a protected system like OS/2. Use Microsoft C instead. - */ - -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - voidpf buf = opaque; /* just to make some compilers happy */ - ulg bsize = (ulg)items*size; - - /* If we allocate less than 65520 bytes, we assume that farmalloc - * will return a usable pointer which doesn't have to be normalized. - */ - if (bsize < 65520L) { - buf = farmalloc(bsize); - if (*(ush*)&buf != 0) return buf; - } else { - buf = farmalloc(bsize + 16L); - } - if (buf == NULL || next_ptr >= MAX_PTR) return NULL; - table[next_ptr].org_ptr = buf; - - /* Normalize the pointer to seg:0 */ - *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; - *(ush*)&buf = 0; - table[next_ptr++].new_ptr = buf; - return buf; -} - -void zcfree (voidpf opaque, voidpf ptr) -{ - int n; - if (*(ush*)&ptr != 0) { /* object < 64K */ - farfree(ptr); - return; - } - /* Find the original pointer */ - for (n = 0; n < next_ptr; n++) { - if (ptr != table[n].new_ptr) continue; - - farfree(table[n].org_ptr); - while (++n < next_ptr) { - table[n-1] = table[n]; - } - next_ptr--; - return; - } - ptr = opaque; /* just to make some compilers happy */ - Assert(0, "zcfree: ptr not found"); -} - -#endif /* __TURBOC__ */ - - -#ifdef M_I86 -/* Microsoft C in 16-bit mode */ - -# define MY_ZCALLOC - -#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) -# define _halloc halloc -# define _hfree hfree -#endif - -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - if (opaque) opaque = 0; /* to make compiler happy */ - return _halloc((long)items, size); -} - -void zcfree (voidpf opaque, voidpf ptr) -{ - if (opaque) opaque = 0; /* to make compiler happy */ - _hfree(ptr); -} - -#endif /* M_I86 */ - -#endif /* SYS16BIT */ - - -#ifndef MY_ZCALLOC /* Any system without a special alloc function */ - -#ifndef STDC -extern voidp malloc OF((uInt size)); -extern voidp calloc OF((uInt items, uInt size)); -extern void free OF((voidpf ptr)); -#endif - -voidpf zcalloc (opaque, items, size) - voidpf opaque; - unsigned items; - unsigned size; -{ - if (opaque) items += size - size; /* make compiler happy */ - return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : - (voidpf)calloc(items, size); -} - -void zcfree (opaque, ptr) - voidpf opaque; - voidpf ptr; -{ - free(ptr); - if (opaque) return; /* make compiler happy */ -} - -#endif /* MY_ZCALLOC */ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/plugins/CDVDiso/src/3rdparty/zlib/zutil.h b/plugins/CDVDiso/src/3rdparty/zlib/zutil.h index 0e3a9a0638..532fc7084a 100644 --- a/plugins/CDVDiso/src/3rdparty/zlib/zutil.h +++ b/plugins/CDVDiso/src/3rdparty/zlib/zutil.h @@ -1,269 +1,269 @@ -/* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id$ */ - -#ifndef ZUTIL_H -#define ZUTIL_H - -#define ZLIB_INTERNAL -#include "zlib.h" - -#ifdef STDC -# ifndef _WIN32_WCE -# include -# endif -# include -# include -#endif -#ifdef NO_ERRNO_H -# ifdef _WIN32_WCE - /* The Microsoft C Run-Time Library for Windows CE doesn't have - * errno. We define it as a global variable to simplify porting. - * Its value is always 0 and should not be used. We rename it to - * avoid conflict with other libraries that use the same workaround. - */ -# define errno z_errno -# endif - extern int errno; -#else -# ifndef _WIN32_WCE -# include -# endif -#endif - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -typedef unsigned char uch; -typedef uch FAR uchf; -typedef unsigned short ush; -typedef ush FAR ushf; -typedef unsigned long ulg; - -extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ -/* (size given to avoid silly warnings with Visual C++) */ - -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] - -#define ERR_RETURN(strm,err) \ - return (strm->msg = (char*)ERR_MSG(err), (err)) -/* To be used only when the state is known to be valid */ - - /* common constants */ - -#ifndef DEF_WBITS -# define DEF_WBITS MAX_WBITS -#endif -/* default windowBits for decompression. MAX_WBITS is for compression only */ - -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 9 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -/* default memLevel */ - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - -#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ - - /* target dependencies */ - -#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) -# define OS_CODE 0x00 -# if defined(__TURBOC__) || defined(__BORLANDC__) -# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) - /* Allow compilation with ANSI keywords only enabled */ - void _Cdecl farfree( void *block ); - void *_Cdecl farmalloc( unsigned long nbytes ); -# else -# include -# endif -# else /* MSC or DJGPP */ -# include -# endif -#endif - -#ifdef AMIGA -# define OS_CODE 0x01 -#endif - -#if defined(VAXC) || defined(VMS) -# define OS_CODE 0x02 -# define F_OPEN(name, mode) \ - fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") -#endif - -#if defined(ATARI) || defined(atarist) -# define OS_CODE 0x05 -#endif - -#ifdef OS2 -# define OS_CODE 0x06 -# ifdef M_I86 - #include -# endif -#endif - -#if defined(MACOS) || defined(TARGET_OS_MAC) -# define OS_CODE 0x07 -# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os -# include /* for fdopen */ -# else -# ifndef fdopen -# define fdopen(fd,mode) NULL /* No fdopen() */ -# endif -# endif -#endif - -#ifdef TOPS20 -# define OS_CODE 0x0a -#endif - -#ifdef WIN32 -# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ -# define OS_CODE 0x0b -# endif -#endif - -#ifdef __50SERIES /* Prime/PRIMOS */ -# define OS_CODE 0x0f -#endif - -#if defined(_BEOS_) || defined(RISCOS) -# define fdopen(fd,mode) NULL /* No fdopen() */ -#endif - -#if (defined(_MSC_VER) && (_MSC_VER > 600)) -# if defined(_WIN32_WCE) -# define fdopen(fd,mode) NULL /* No fdopen() */ -# ifndef _PTRDIFF_T_DEFINED - typedef int ptrdiff_t; -# define _PTRDIFF_T_DEFINED -# endif -# else -# define fdopen(fd,type) _fdopen(fd,type) -# endif -#endif - - /* common defaults */ - -#ifndef OS_CODE -# define OS_CODE 0x03 /* assume Unix */ -#endif - -#ifndef F_OPEN -# define F_OPEN(name, mode) fopen((name), (mode)) -#endif - - /* functions */ - -#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif -#if defined(__CYGWIN__) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif -#ifndef HAVE_VSNPRINTF -# ifdef MSDOS - /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), - but for now we just assume it doesn't. */ -# define NO_vsnprintf -# endif -# ifdef __TURBOC__ -# define NO_vsnprintf -# endif -# ifdef WIN32 - /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ -# if !defined(vsnprintf) && !defined(NO_vsnprintf) -# define vsnprintf _vsnprintf -# endif -# endif -# ifdef __SASC -# define NO_vsnprintf -# endif -#endif -#ifdef VMS -# define NO_vsnprintf -#endif - -#if defined(pyr) -# define NO_MEMCPY -#endif -#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) - /* Use our own functions for small and medium model with MSC <= 5.0. - * You may have to use the same strategy for Borland C (untested). - * The __SC__ check is for Symantec. - */ -# define NO_MEMCPY -#endif -#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) -# define HAVE_MEMCPY -#endif -#ifdef HAVE_MEMCPY -# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ -# define zmemcpy _fmemcpy -# define zmemcmp _fmemcmp -# define zmemzero(dest, len) _fmemset(dest, 0, len) -# else -# define zmemcpy memcpy -# define zmemcmp memcmp -# define zmemzero(dest, len) memset(dest, 0, len) -# endif -#else - extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); - extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); - extern void zmemzero OF((Bytef* dest, uInt len)); -#endif - -/* Diagnostic functions */ -#ifdef DEBUG -# include - extern int z_verbose; - extern void z_error OF((char *m)); -# define Assert(cond,msg) {if(!(cond)) z_error(msg);} -# define Trace(x) {if (z_verbose>=0) fprintf x ;} -# define Tracev(x) {if (z_verbose>0) fprintf x ;} -# define Tracevv(x) {if (z_verbose>1) fprintf x ;} -# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} -# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - - -voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); -void zcfree OF((voidpf opaque, voidpf ptr)); - -#define ZALLOC(strm, items, size) \ - (*((strm)->zalloc))((strm)->opaque, (items), (size)) -#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) -#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} - -#endif /* ZUTIL_H */ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# ifndef _WIN32_WCE +# include +# endif +# include +# include +#endif +#ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif + extern int errno; +#else +# ifndef _WIN32_WCE +# include +# endif +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 9 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 + #include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/plugins/CDVDiso/src/CDVDiso.h b/plugins/CDVDiso/src/CDVDiso.h index ba3813eb80..bcb891856d 100644 --- a/plugins/CDVDiso/src/CDVDiso.h +++ b/plugins/CDVDiso/src/CDVDiso.h @@ -1,132 +1,132 @@ -/* CDVDiso - * Copyright (C) 2002-2004 CDVDiso 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifdef _MSC_VER -#pragma warning(disable:4018) -#endif - -#include "common/PS2Etypes.h" -#include "common/PS2Edefs.h" -#include "libiso.h" - -#ifdef __cplusplus - -#ifdef _MSC_VER -#define EXPORT_C(type) extern "C" __declspec(dllexport) type CALLBACK -#else -#define EXPORT_C(type) extern "C" type -#endif - -#else - -#ifdef _MSC_VER -#define EXPORT_C(type) __declspec(dllexport) type __stdcall -#else -#define EXPORT_C(type) type -#endif - -#endif - -EXPORT_C(u32) PS2EgetLibType(); -EXPORT_C(u32) PS2EgetLibVersion2(u32 type); -EXPORT_C(char*) PS2EgetLibName(); - - -EXPORT_C(s32) CDVDinit(); -EXPORT_C(s32) CDVDopen(const char* pTitleFilename); -EXPORT_C(void) CDVDclose(); -EXPORT_C(void) CDVDshutdown(); -EXPORT_C(s32) CDVDreadTrack(u32 lsn, int mode); - -// return can be NULL (for async modes) -EXPORT_C(u8*) CDVDgetBuffer(); - -EXPORT_C(s32) CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) -EXPORT_C(s32) CDVDgetTN(cdvdTN *Buffer); //disk information -EXPORT_C(s32) CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type -EXPORT_C(s32) CDVDgetTOC(void* toc); //gets ps2 style toc from disc -EXPORT_C(s32) CDVDgetDiskType(); //CDVD_TYPE_xxxx -EXPORT_C(s32) CDVDgetTrayStatus(); //CDVD_TRAY_xxxx -EXPORT_C(s32) CDVDctrlTrayOpen(); //open disc tray -EXPORT_C(s32) CDVDctrlTrayClose(); //close disc tray - -// extended funcs - -EXPORT_C(void) CDVDconfigure(); -EXPORT_C(void) CDVDabout(); -EXPORT_C(s32) CDVDtest(); -EXPORT_C(void) CDVDnewDiskCB(void (*callback)()); - -#define CDVD_LOG __Log -extern FILE *cdvdLog; - -void __Log(char *fmt, ...); - -#define VERBOSE 1 - -#define DEV_DEF "" -#define CDDEV_DEF "/dev/cdrom" - -typedef struct -{ - int slsn; - int elsn; -#ifdef _WINDOWS_ - HANDLE handle; -#else - FILE *handle; -#endif -} _cdIso; - -extern _cdIso cdIso[8]; - -#define CD_FRAMESIZE_RAW 2352 -#define DATA_SIZE (CD_FRAMESIZE_RAW-12) - -#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ -#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ - -#define MSF2SECT(m,s,f) (((m)*60+(s)-2)*75+(f)) - -extern char IsoFile[256]; -extern char IsoCWD[256]; -extern char CdDev[256]; - -extern int BlockDump; -extern isoFile *fdump; -extern isoFile *iso; - -extern u8 cdbuffer[]; -extern u8 *pbuffer; -extern int cdblocksize; -extern int cdblockofs; -extern int cdoffset; -extern int cdtype; -extern int cdblocks; - -extern int Zmode; // 1 Z - 2 bz2 -extern int fmode; // 0 - file / 1 - Zfile -extern char *Ztable; - -extern char *methods[]; - -void UpdateZmode(); -void CfgOpenFile(); -void SysMessage(char *fmt, ...); - +/* CDVDiso + * Copyright (C) 2002-2004 CDVDiso 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifdef _MSC_VER +#pragma warning(disable:4018) +#endif + +#include "common/PS2Etypes.h" +#include "common/PS2Edefs.h" +#include "libiso.h" + +#ifdef __cplusplus + +#ifdef _MSC_VER +#define EXPORT_C(type) extern "C" __declspec(dllexport) type CALLBACK +#else +#define EXPORT_C(type) extern "C" type +#endif + +#else + +#ifdef _MSC_VER +#define EXPORT_C(type) __declspec(dllexport) type __stdcall +#else +#define EXPORT_C(type) type +#endif + +#endif + +EXPORT_C(u32) PS2EgetLibType(); +EXPORT_C(u32) PS2EgetLibVersion2(u32 type); +EXPORT_C(char*) PS2EgetLibName(); + + +EXPORT_C(s32) CDVDinit(); +EXPORT_C(s32) CDVDopen(const char* pTitleFilename); +EXPORT_C(void) CDVDclose(); +EXPORT_C(void) CDVDshutdown(); +EXPORT_C(s32) CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +EXPORT_C(u8*) CDVDgetBuffer(); + +EXPORT_C(s32) CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +EXPORT_C(s32) CDVDgetTN(cdvdTN *Buffer); //disk information +EXPORT_C(s32) CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +EXPORT_C(s32) CDVDgetTOC(void* toc); //gets ps2 style toc from disc +EXPORT_C(s32) CDVDgetDiskType(); //CDVD_TYPE_xxxx +EXPORT_C(s32) CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +EXPORT_C(s32) CDVDctrlTrayOpen(); //open disc tray +EXPORT_C(s32) CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +EXPORT_C(void) CDVDconfigure(); +EXPORT_C(void) CDVDabout(); +EXPORT_C(s32) CDVDtest(); +EXPORT_C(void) CDVDnewDiskCB(void (*callback)()); + +#define CDVD_LOG __Log +extern FILE *cdvdLog; + +void __Log(char *fmt, ...); + +#define VERBOSE 1 + +#define DEV_DEF "" +#define CDDEV_DEF "/dev/cdrom" + +typedef struct +{ + int slsn; + int elsn; +#ifdef _WINDOWS_ + HANDLE handle; +#else + FILE *handle; +#endif +} _cdIso; + +extern _cdIso cdIso[8]; + +#define CD_FRAMESIZE_RAW 2352 +#define DATA_SIZE (CD_FRAMESIZE_RAW-12) + +#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ +#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ + +#define MSF2SECT(m,s,f) (((m)*60+(s)-2)*75+(f)) + +extern char IsoFile[256]; +extern char IsoCWD[256]; +extern char CdDev[256]; + +extern int BlockDump; +extern isoFile *fdump; +extern isoFile *iso; + +extern u8 cdbuffer[]; +extern u8 *pbuffer; +extern int cdblocksize; +extern int cdblockofs; +extern int cdoffset; +extern int cdtype; +extern int cdblocks; + +extern int Zmode; // 1 Z - 2 bz2 +extern int fmode; // 0 - file / 1 - Zfile +extern char *Ztable; + +extern char *methods[]; + +void UpdateZmode(); +void CfgOpenFile(); +void SysMessage(char *fmt, ...); + diff --git a/plugins/CDVDiso/src/CDVDisop.c b/plugins/CDVDiso/src/CDVDisop.c index e4b7ac989f..240b6a9edb 100644 --- a/plugins/CDVDiso/src/CDVDisop.c +++ b/plugins/CDVDiso/src/CDVDisop.c @@ -1,499 +1,499 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "CDVDiso.h" -#include "Config.h" - -#ifndef MAX_PATH -#define MAX_PATH 255 -#endif - -char IsoFile[256]; -char IsoCWD[256]; -char CdDev[256]; - -_cdIso cdIso[8]; -u8 *pbuffer; -int cdblocksize; -int cdblockofs; -int cdoffset; -int cdtype; -int cdblocks; - -int Zmode; // 1 Z - 2 bz2 -int fmode; // 0 - file / 1 - Zfile -char *Ztable; - -int BlockDump; -isoFile *fdump; -isoFile *iso; - -FILE *cdvdLog = NULL; - -// This var is used to detect resume-style behavior of the Pcsx2 emulator, -// and skip prompting the user for a new CD when it's likely they want to run the existing one. -static char cdvdCurrentIso[MAX_PATH]; - -char *methods[] = -{ - ".Z - compress faster", - ".BZ - compress better", - NULL -}; - -#ifdef _DEBUG -char *LibName = "Linuz Iso CDVD (Debug) "; -#else -char *LibName = "Linuz Iso CDVD "; -#endif - -const unsigned char version = PS2E_CDVD_VERSION; -const unsigned char revision = 0; -const unsigned char build = 8; - -unsigned char cdbuffer[CD_FRAMESIZE_RAW * 10] = {0}; - -s32 msf_to_lba(u8 m, u8 s, u8 f) -{ - u32 lsn; - lsn = f; - lsn += (s - 2) * 75; - lsn += m * 75 * 60; - return lsn; -} - -void lba_to_msf(s32 lba, u8* m, u8* s, u8* f) -{ - lba += 150; - *m = lba / (60 * 75); - *s = (lba / 75) % 60; - *f = lba % 75; -} - -#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ -#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ - - -EXPORT_C(char*) PS2EgetLibName() -{ - return LibName; -} - -EXPORT_C(u32) PS2EgetLibType() -{ - return PS2E_LT_CDVD; -} - -EXPORT_C(u32) PS2EgetLibVersion2(u32 type) -{ - return (version << 16) | (revision << 8) | build; -} - -#ifdef _DEBUG -void __Log(char *fmt, ...) -{ - va_list list; - - if (cdvdLog == NULL) return; - - va_start(list, fmt); - vfprintf(cdvdLog, fmt, list); - va_end(list); -} -#else -#define __Log 0&& -#endif - - -EXPORT_C(s32) CDVDinit() -{ -#ifdef _DEBUG - cdvdLog = fopen("logs/cdvdLog.txt", "w"); - if (cdvdLog == NULL) - { - cdvdLog = fopen("cdvdLog.txt", "w"); - if (cdvdLog == NULL) - { - SysMessage("Can't create cdvdLog.txt"); - return -1; - } - } - setvbuf(cdvdLog, NULL, _IONBF, 0); - CDVD_LOG("CDVDinit\n"); -#endif - - cdvdCurrentIso[0] = 0; - memset(cdIso, 0, sizeof(cdIso)); - return 0; -} - -EXPORT_C(void) CDVDshutdown() -{ - cdvdCurrentIso[0] = 0; -#ifdef CDVD_LOG - if (cdvdLog != NULL) fclose(cdvdLog); -#endif -} - -EXPORT_C(s32) CDVDopen(const char* pTitle) -{ - LoadConf(); - - if (pTitle != NULL) strcpy(IsoFile, pTitle); - - if (*IsoFile == 0) strcpy(IsoFile, cdvdCurrentIso); - - if (*IsoFile == 0) - { - char temp[256]; - - CfgOpenFile(); - - LoadConf(); - strcpy(temp, IsoFile); - *IsoFile = 0; - SaveConf(); - strcpy(IsoFile, temp); - } - - iso = isoOpen(IsoFile); - if (iso == NULL) - { - SysMessage("Error loading %s\n", IsoFile); - return -1; - } - - if (iso->type == ISOTYPE_DVD) - cdtype = CDVD_TYPE_PS2DVD; - else if (iso->type == ISOTYPE_AUDIO) - cdtype = CDVD_TYPE_CDDA; - else - cdtype = CDVD_TYPE_PS2CD; - - if (BlockDump) - { - char fname_only[MAX_PATH]; - -#ifdef _WIN32 - char fname[MAX_PATH], ext[MAX_PATH]; - _splitpath(IsoFile, NULL, NULL, fname, ext); - _makepath(fname_only, NULL, NULL, fname, NULL); -#else - char* p, *plast; - - plast = p = strchr(IsoFile, '/'); - while (p != NULL) - { - plast = p; - p = strchr(p + 1, '/'); - } - - // Lets not create dumps in the plugin directory. - strcpy(fname_only, "../"); - if (plast != NULL) - strcat(fname_only, plast + 1); - else - strcat(fname_only, IsoFile); - - plast = p = strchr(fname_only, '.'); - - while (p != NULL) - { - plast = p; - p = strchr(p + 1, '.'); - } - - if (plast != NULL) *plast = 0; - -#endif - strcat(fname_only, ".dump"); - fdump = isoCreate(fname_only, ISOFLAGS_BLOCKDUMP); - if (fdump) isoSetFormat(fdump, iso->blockofs, iso->blocksize, iso->blocks); - } - else - { - fdump = NULL; - } - - return 0; -} - -EXPORT_C(void) CDVDclose() -{ - - strcpy(cdvdCurrentIso, IsoFile); - - isoClose(iso); - if (fdump != NULL) isoClose(fdump); -} - -EXPORT_C(s32) CDVDreadSubQ(u32 lsn, cdvdSubQ* subq) -{ - // fake it - u8 min, sec, frm; - subq->ctrl = 4; - subq->mode = 1; - subq->trackNum = itob(1); - subq->trackIndex = itob(1); - - lba_to_msf(lsn, &min, &sec, &frm); - subq->trackM = itob(min); - subq->trackS = itob(sec); - subq->trackF = itob(frm); - - subq->pad = 0; - - lba_to_msf(lsn + (2*75), &min, &sec, &frm); - subq->discM = itob(min); - subq->discS = itob(sec); - subq->discF = itob(frm); - return 0; -} - -EXPORT_C(s32) CDVDgetTN(cdvdTN *Buffer) -{ - Buffer->strack = 1; - Buffer->etrack = 1; - - return 0; -} - -EXPORT_C(s32) CDVDgetTD(u8 Track, cdvdTD *Buffer) -{ - if (Track == 0) - { - Buffer->lsn = iso->blocks; - } - else - { - Buffer->type = CDVD_MODE1_TRACK; - Buffer->lsn = 0; - } - - return 0; -} - -static int layer1start = -1; -EXPORT_C(s32) CDVDgetTOC(void* toc) -{ - u8 type = CDVDgetDiskType(); - u8* tocBuff = (u8*)toc; - - //__Log("CDVDgetTOC\n"); - - if (type == CDVD_TYPE_DVDV || type == CDVD_TYPE_PS2DVD) - { - int i; - - // get dvd structure format - // scsi command 0x43 - memset(tocBuff, 0, 2048); - - if (layer1start != -2 && iso->blocks >= 0x300000) - { - int off = iso->blockofs; - u8* tempbuffer; - - // dual sided - tocBuff[ 0] = 0x24; - tocBuff[ 1] = 0x02; - tocBuff[ 2] = 0xF2; - tocBuff[ 3] = 0x00; - tocBuff[ 4] = 0x41; - tocBuff[ 5] = 0x95; - - tocBuff[14] = 0x60; // dual sided, ptp - - tocBuff[16] = 0x00; - tocBuff[17] = 0x03; - tocBuff[18] = 0x00; - tocBuff[19] = 0x00; - - // search for it - if (layer1start == -1) - { - printf("CDVD: searching for layer1..."); - tempbuffer = (u8*)malloc(CD_FRAMESIZE_RAW * 10); - for (layer1start = (iso->blocks / 2 - 0x10) & ~0xf; layer1start < 0x200010; layer1start += 16) - { - isoReadBlock(iso, tempbuffer, layer1start); - // CD001 - if (tempbuffer[off+1] == 0x43 && tempbuffer[off+2] == 0x44 && tempbuffer[off+3] == 0x30 && tempbuffer[off+4] == 0x30 && tempbuffer[off+5] == 0x31) - break; - } - free(tempbuffer); - - if (layer1start == 0x200010) - { - printf("Couldn't find second layer on dual layer... ignoring\n"); - // fake it - tocBuff[ 0] = 0x04; - tocBuff[ 1] = 0x02; - tocBuff[ 2] = 0xF2; - tocBuff[ 3] = 0x00; - tocBuff[ 4] = 0x86; - tocBuff[ 5] = 0x72; - - tocBuff[16] = 0x00; - tocBuff[17] = 0x03; - tocBuff[18] = 0x00; - tocBuff[19] = 0x00; - layer1start = -2; - return 0; - } - - printf("found at 0x%8.8x\n", layer1start); - layer1start = layer1start + 0x30000 - 1; - } - - tocBuff[20] = layer1start >> 24; - tocBuff[21] = (layer1start >> 16) & 0xff; - tocBuff[22] = (layer1start >> 8) & 0xff; - tocBuff[23] = (layer1start >> 0) & 0xff; - } - else - { - // fake it - tocBuff[ 0] = 0x04; - tocBuff[ 1] = 0x02; - tocBuff[ 2] = 0xF2; - tocBuff[ 3] = 0x00; - tocBuff[ 4] = 0x86; - tocBuff[ 5] = 0x72; - - tocBuff[16] = 0x00; - tocBuff[17] = 0x03; - tocBuff[18] = 0x00; - tocBuff[19] = 0x00; - } - } - else if ((type == CDVD_TYPE_CDDA) || (type == CDVD_TYPE_PS2CDDA) || - (type == CDVD_TYPE_PS2CD) || (type == CDVD_TYPE_PSCDDA) || (type == CDVD_TYPE_PSCD)) - { - // cd toc - // (could be replaced by 1 command that reads the full toc) - u8 min, sec, frm; - s32 i, err; - cdvdTN diskInfo; - cdvdTD trackInfo; - memset(tocBuff, 0, 1024); - if (CDVDgetTN(&diskInfo) == -1) - { - diskInfo.etrack = 0; - diskInfo.strack = 1; - } - if (CDVDgetTD(0, &trackInfo) == -1) trackInfo.lsn = 0; - - tocBuff[0] = 0x41; - tocBuff[1] = 0x00; - - //Number of FirstTrack - tocBuff[2] = 0xA0; - tocBuff[7] = itob(diskInfo.strack); - - //Number of LastTrack - tocBuff[12] = 0xA1; - tocBuff[17] = itob(diskInfo.etrack); - - //DiskLength - lba_to_msf(trackInfo.lsn, &min, &sec, &frm); - tocBuff[22] = 0xA2; - tocBuff[27] = itob(min); - tocBuff[28] = itob(sec); - - for (i = diskInfo.strack; i <= diskInfo.etrack; i++) - { - err = CDVDgetTD(i, &trackInfo); - lba_to_msf(trackInfo.lsn, &min, &sec, &frm); - tocBuff[i*10+30] = trackInfo.type; - tocBuff[i*10+32] = err == -1 ? 0 : itob(i); //number - tocBuff[i*10+37] = itob(min); - tocBuff[i*10+38] = itob(sec); - tocBuff[i*10+39] = itob(frm); - } - } - else - return -1; - - return 0; -} - -EXPORT_C(s32) CDVDreadTrack(u32 lsn, int mode) -{ - int _lsn = lsn; - - //__Log("CDVDreadTrack: %x %x\n", lsn, mode); - if (_lsn < 0) - { -// lsn = 2097152 + (-_lsn); - lsn = iso->blocks - (-_lsn); - } -// printf ("CDRreadTrack %d\n", lsn); - - isoReadBlock(iso, cdbuffer, lsn); - if (fdump != NULL) - { - isoWriteBlock(fdump, cdbuffer, lsn); - } - - pbuffer = cdbuffer; - switch (mode) - { - case CDVD_MODE_2352: - break; - case CDVD_MODE_2340: - pbuffer += 12; - break; - case CDVD_MODE_2328: - pbuffer += 24; - break; - case CDVD_MODE_2048: - pbuffer += 24; - break; - } - - return 0; -} - -EXPORT_C(u8*) CDVDgetBuffer() -{ - return pbuffer; -} - -EXPORT_C(s32) CDVDgetDiskType() -{ - return cdtype; -} - -EXPORT_C(s32) CDVDgetTrayStatus() -{ - return CDVD_TRAY_CLOSE; -} - -EXPORT_C(s32) CDVDctrlTrayOpen() -{ - return 0; -} -EXPORT_C(s32) CDVDctrlTrayClose() -{ - return 0; -} - - -EXPORT_C(s32) CDVDtest() -{ - if (*IsoFile == 0) return 0; - - iso = isoOpen(IsoFile); - if (iso == NULL) return -1; - isoClose(iso); - - return 0; -} - +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CDVDiso.h" +#include "Config.h" + +#ifndef MAX_PATH +#define MAX_PATH 255 +#endif + +char IsoFile[256]; +char IsoCWD[256]; +char CdDev[256]; + +_cdIso cdIso[8]; +u8 *pbuffer; +int cdblocksize; +int cdblockofs; +int cdoffset; +int cdtype; +int cdblocks; + +int Zmode; // 1 Z - 2 bz2 +int fmode; // 0 - file / 1 - Zfile +char *Ztable; + +int BlockDump; +isoFile *fdump; +isoFile *iso; + +FILE *cdvdLog = NULL; + +// This var is used to detect resume-style behavior of the Pcsx2 emulator, +// and skip prompting the user for a new CD when it's likely they want to run the existing one. +static char cdvdCurrentIso[MAX_PATH]; + +char *methods[] = +{ + ".Z - compress faster", + ".BZ - compress better", + NULL +}; + +#ifdef _DEBUG +char *LibName = "Linuz Iso CDVD (Debug) "; +#else +char *LibName = "Linuz Iso CDVD "; +#endif + +const unsigned char version = PS2E_CDVD_VERSION; +const unsigned char revision = 0; +const unsigned char build = 8; + +unsigned char cdbuffer[CD_FRAMESIZE_RAW * 10] = {0}; + +s32 msf_to_lba(u8 m, u8 s, u8 f) +{ + u32 lsn; + lsn = f; + lsn += (s - 2) * 75; + lsn += m * 75 * 60; + return lsn; +} + +void lba_to_msf(s32 lba, u8* m, u8* s, u8* f) +{ + lba += 150; + *m = lba / (60 * 75); + *s = (lba / 75) % 60; + *f = lba % 75; +} + +#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ +#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ + + +EXPORT_C(char*) PS2EgetLibName() +{ + return LibName; +} + +EXPORT_C(u32) PS2EgetLibType() +{ + return PS2E_LT_CDVD; +} + +EXPORT_C(u32) PS2EgetLibVersion2(u32 type) +{ + return (version << 16) | (revision << 8) | build; +} + +#ifdef _DEBUG +void __Log(char *fmt, ...) +{ + va_list list; + + if (cdvdLog == NULL) return; + + va_start(list, fmt); + vfprintf(cdvdLog, fmt, list); + va_end(list); +} +#else +#define __Log 0&& +#endif + + +EXPORT_C(s32) CDVDinit() +{ +#ifdef _DEBUG + cdvdLog = fopen("logs/cdvdLog.txt", "w"); + if (cdvdLog == NULL) + { + cdvdLog = fopen("cdvdLog.txt", "w"); + if (cdvdLog == NULL) + { + SysMessage("Can't create cdvdLog.txt"); + return -1; + } + } + setvbuf(cdvdLog, NULL, _IONBF, 0); + CDVD_LOG("CDVDinit\n"); +#endif + + cdvdCurrentIso[0] = 0; + memset(cdIso, 0, sizeof(cdIso)); + return 0; +} + +EXPORT_C(void) CDVDshutdown() +{ + cdvdCurrentIso[0] = 0; +#ifdef CDVD_LOG + if (cdvdLog != NULL) fclose(cdvdLog); +#endif +} + +EXPORT_C(s32) CDVDopen(const char* pTitle) +{ + LoadConf(); + + if (pTitle != NULL) strcpy(IsoFile, pTitle); + + if (*IsoFile == 0) strcpy(IsoFile, cdvdCurrentIso); + + if (*IsoFile == 0) + { + char temp[256]; + + CfgOpenFile(); + + LoadConf(); + strcpy(temp, IsoFile); + *IsoFile = 0; + SaveConf(); + strcpy(IsoFile, temp); + } + + iso = isoOpen(IsoFile); + if (iso == NULL) + { + SysMessage("Error loading %s\n", IsoFile); + return -1; + } + + if (iso->type == ISOTYPE_DVD) + cdtype = CDVD_TYPE_PS2DVD; + else if (iso->type == ISOTYPE_AUDIO) + cdtype = CDVD_TYPE_CDDA; + else + cdtype = CDVD_TYPE_PS2CD; + + if (BlockDump) + { + char fname_only[MAX_PATH]; + +#ifdef _WIN32 + char fname[MAX_PATH], ext[MAX_PATH]; + _splitpath(IsoFile, NULL, NULL, fname, ext); + _makepath(fname_only, NULL, NULL, fname, NULL); +#else + char* p, *plast; + + plast = p = strchr(IsoFile, '/'); + while (p != NULL) + { + plast = p; + p = strchr(p + 1, '/'); + } + + // Lets not create dumps in the plugin directory. + strcpy(fname_only, "../"); + if (plast != NULL) + strcat(fname_only, plast + 1); + else + strcat(fname_only, IsoFile); + + plast = p = strchr(fname_only, '.'); + + while (p != NULL) + { + plast = p; + p = strchr(p + 1, '.'); + } + + if (plast != NULL) *plast = 0; + +#endif + strcat(fname_only, ".dump"); + fdump = isoCreate(fname_only, ISOFLAGS_BLOCKDUMP); + if (fdump) isoSetFormat(fdump, iso->blockofs, iso->blocksize, iso->blocks); + } + else + { + fdump = NULL; + } + + return 0; +} + +EXPORT_C(void) CDVDclose() +{ + + strcpy(cdvdCurrentIso, IsoFile); + + isoClose(iso); + if (fdump != NULL) isoClose(fdump); +} + +EXPORT_C(s32) CDVDreadSubQ(u32 lsn, cdvdSubQ* subq) +{ + // fake it + u8 min, sec, frm; + subq->ctrl = 4; + subq->mode = 1; + subq->trackNum = itob(1); + subq->trackIndex = itob(1); + + lba_to_msf(lsn, &min, &sec, &frm); + subq->trackM = itob(min); + subq->trackS = itob(sec); + subq->trackF = itob(frm); + + subq->pad = 0; + + lba_to_msf(lsn + (2*75), &min, &sec, &frm); + subq->discM = itob(min); + subq->discS = itob(sec); + subq->discF = itob(frm); + return 0; +} + +EXPORT_C(s32) CDVDgetTN(cdvdTN *Buffer) +{ + Buffer->strack = 1; + Buffer->etrack = 1; + + return 0; +} + +EXPORT_C(s32) CDVDgetTD(u8 Track, cdvdTD *Buffer) +{ + if (Track == 0) + { + Buffer->lsn = iso->blocks; + } + else + { + Buffer->type = CDVD_MODE1_TRACK; + Buffer->lsn = 0; + } + + return 0; +} + +static int layer1start = -1; +EXPORT_C(s32) CDVDgetTOC(void* toc) +{ + u8 type = CDVDgetDiskType(); + u8* tocBuff = (u8*)toc; + + //__Log("CDVDgetTOC\n"); + + if (type == CDVD_TYPE_DVDV || type == CDVD_TYPE_PS2DVD) + { + int i; + + // get dvd structure format + // scsi command 0x43 + memset(tocBuff, 0, 2048); + + if (layer1start != -2 && iso->blocks >= 0x300000) + { + int off = iso->blockofs; + u8* tempbuffer; + + // dual sided + tocBuff[ 0] = 0x24; + tocBuff[ 1] = 0x02; + tocBuff[ 2] = 0xF2; + tocBuff[ 3] = 0x00; + tocBuff[ 4] = 0x41; + tocBuff[ 5] = 0x95; + + tocBuff[14] = 0x60; // dual sided, ptp + + tocBuff[16] = 0x00; + tocBuff[17] = 0x03; + tocBuff[18] = 0x00; + tocBuff[19] = 0x00; + + // search for it + if (layer1start == -1) + { + printf("CDVD: searching for layer1..."); + tempbuffer = (u8*)malloc(CD_FRAMESIZE_RAW * 10); + for (layer1start = (iso->blocks / 2 - 0x10) & ~0xf; layer1start < 0x200010; layer1start += 16) + { + isoReadBlock(iso, tempbuffer, layer1start); + // CD001 + if (tempbuffer[off+1] == 0x43 && tempbuffer[off+2] == 0x44 && tempbuffer[off+3] == 0x30 && tempbuffer[off+4] == 0x30 && tempbuffer[off+5] == 0x31) + break; + } + free(tempbuffer); + + if (layer1start == 0x200010) + { + printf("Couldn't find second layer on dual layer... ignoring\n"); + // fake it + tocBuff[ 0] = 0x04; + tocBuff[ 1] = 0x02; + tocBuff[ 2] = 0xF2; + tocBuff[ 3] = 0x00; + tocBuff[ 4] = 0x86; + tocBuff[ 5] = 0x72; + + tocBuff[16] = 0x00; + tocBuff[17] = 0x03; + tocBuff[18] = 0x00; + tocBuff[19] = 0x00; + layer1start = -2; + return 0; + } + + printf("found at 0x%8.8x\n", layer1start); + layer1start = layer1start + 0x30000 - 1; + } + + tocBuff[20] = layer1start >> 24; + tocBuff[21] = (layer1start >> 16) & 0xff; + tocBuff[22] = (layer1start >> 8) & 0xff; + tocBuff[23] = (layer1start >> 0) & 0xff; + } + else + { + // fake it + tocBuff[ 0] = 0x04; + tocBuff[ 1] = 0x02; + tocBuff[ 2] = 0xF2; + tocBuff[ 3] = 0x00; + tocBuff[ 4] = 0x86; + tocBuff[ 5] = 0x72; + + tocBuff[16] = 0x00; + tocBuff[17] = 0x03; + tocBuff[18] = 0x00; + tocBuff[19] = 0x00; + } + } + else if ((type == CDVD_TYPE_CDDA) || (type == CDVD_TYPE_PS2CDDA) || + (type == CDVD_TYPE_PS2CD) || (type == CDVD_TYPE_PSCDDA) || (type == CDVD_TYPE_PSCD)) + { + // cd toc + // (could be replaced by 1 command that reads the full toc) + u8 min, sec, frm; + s32 i, err; + cdvdTN diskInfo; + cdvdTD trackInfo; + memset(tocBuff, 0, 1024); + if (CDVDgetTN(&diskInfo) == -1) + { + diskInfo.etrack = 0; + diskInfo.strack = 1; + } + if (CDVDgetTD(0, &trackInfo) == -1) trackInfo.lsn = 0; + + tocBuff[0] = 0x41; + tocBuff[1] = 0x00; + + //Number of FirstTrack + tocBuff[2] = 0xA0; + tocBuff[7] = itob(diskInfo.strack); + + //Number of LastTrack + tocBuff[12] = 0xA1; + tocBuff[17] = itob(diskInfo.etrack); + + //DiskLength + lba_to_msf(trackInfo.lsn, &min, &sec, &frm); + tocBuff[22] = 0xA2; + tocBuff[27] = itob(min); + tocBuff[28] = itob(sec); + + for (i = diskInfo.strack; i <= diskInfo.etrack; i++) + { + err = CDVDgetTD(i, &trackInfo); + lba_to_msf(trackInfo.lsn, &min, &sec, &frm); + tocBuff[i*10+30] = trackInfo.type; + tocBuff[i*10+32] = err == -1 ? 0 : itob(i); //number + tocBuff[i*10+37] = itob(min); + tocBuff[i*10+38] = itob(sec); + tocBuff[i*10+39] = itob(frm); + } + } + else + return -1; + + return 0; +} + +EXPORT_C(s32) CDVDreadTrack(u32 lsn, int mode) +{ + int _lsn = lsn; + + //__Log("CDVDreadTrack: %x %x\n", lsn, mode); + if (_lsn < 0) + { +// lsn = 2097152 + (-_lsn); + lsn = iso->blocks - (-_lsn); + } +// printf ("CDRreadTrack %d\n", lsn); + + isoReadBlock(iso, cdbuffer, lsn); + if (fdump != NULL) + { + isoWriteBlock(fdump, cdbuffer, lsn); + } + + pbuffer = cdbuffer; + switch (mode) + { + case CDVD_MODE_2352: + break; + case CDVD_MODE_2340: + pbuffer += 12; + break; + case CDVD_MODE_2328: + pbuffer += 24; + break; + case CDVD_MODE_2048: + pbuffer += 24; + break; + } + + return 0; +} + +EXPORT_C(u8*) CDVDgetBuffer() +{ + return pbuffer; +} + +EXPORT_C(s32) CDVDgetDiskType() +{ + return cdtype; +} + +EXPORT_C(s32) CDVDgetTrayStatus() +{ + return CDVD_TRAY_CLOSE; +} + +EXPORT_C(s32) CDVDctrlTrayOpen() +{ + return 0; +} +EXPORT_C(s32) CDVDctrlTrayClose() +{ + return 0; +} + + +EXPORT_C(s32) CDVDtest() +{ + if (*IsoFile == 0) return 0; + + iso = isoOpen(IsoFile); + if (iso == NULL) return -1; + isoClose(iso); + + return 0; +} + diff --git a/plugins/CDVDiso/src/Linux/Config.c b/plugins/CDVDiso/src/Linux/Config.c index 4ee44063c5..ae1aa1a4af 100644 --- a/plugins/CDVDiso/src/Linux/Config.c +++ b/plugins/CDVDiso/src/Linux/Config.c @@ -1,82 +1,82 @@ -/* CDVDiso - * Copyright (C) 2002-2004 CDVDiso 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include - -#include "CDVDiso.h" - - -const char *s_strIniPath="../inis/CDVDiso.ini"; - -void LoadConf() -{ - FILE *f; - char cfg[256]; - - //sprintf(cfg, "%s/.PS2E/CDVDiso.cfg", getenv("HOME")); - strcpy(cfg, s_strIniPath); - f = fopen(cfg, "r"); - - if (f == NULL) - { - printf("Unable to load %s\n", cfg); - strcpy(IsoFile, DEV_DEF); - strcpy(CdDev, CDDEV_DEF); - BlockDump = 0; - SaveConf(); - return; - } - - fscanf(f, "IsoFile = %[^\n]\n", IsoFile); - fscanf(f, "CdDev = %[^\n]\n", CdDev); - fscanf(f, "BlockDump = %d\n", &BlockDump); - - if (!strncmp(IsoFile, "CdDev =", 9)) *IsoFile = 0; // quick fix - if (*CdDev == 0) strcpy(CdDev, CDDEV_DEF); - - fclose(f); -} - -void SaveConf() -{ - FILE *f; - char cfg[256]; - - //sprintf(cfg, "%s/.PS2E", getenv("HOME")); - - //mkdir(cfg, 0755); - //sprintf(cfg, "%s/.PS2E/CDVDiso.cfg", getenv("HOME")); - strcpy(cfg, s_strIniPath); - - f = fopen(cfg, "w"); - if (f == NULL) - { - printf("Unable to save %s\n", cfg); - return; - } - - fprintf(f, "IsoFile = %s\n", IsoFile); - fprintf(f, "CdDev = %s\n", CdDev); - fprintf(f, "BlockDump = %d\n", BlockDump); - fclose(f); -} - +/* CDVDiso + * Copyright (C) 2002-2004 CDVDiso 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include "CDVDiso.h" + + +const char *s_strIniPath="../inis/CDVDiso.ini"; + +void LoadConf() +{ + FILE *f; + char cfg[256]; + + //sprintf(cfg, "%s/.PS2E/CDVDiso.cfg", getenv("HOME")); + strcpy(cfg, s_strIniPath); + f = fopen(cfg, "r"); + + if (f == NULL) + { + printf("Unable to load %s\n", cfg); + strcpy(IsoFile, DEV_DEF); + strcpy(CdDev, CDDEV_DEF); + BlockDump = 0; + SaveConf(); + return; + } + + fscanf(f, "IsoFile = %[^\n]\n", IsoFile); + fscanf(f, "CdDev = %[^\n]\n", CdDev); + fscanf(f, "BlockDump = %d\n", &BlockDump); + + if (!strncmp(IsoFile, "CdDev =", 9)) *IsoFile = 0; // quick fix + if (*CdDev == 0) strcpy(CdDev, CDDEV_DEF); + + fclose(f); +} + +void SaveConf() +{ + FILE *f; + char cfg[256]; + + //sprintf(cfg, "%s/.PS2E", getenv("HOME")); + + //mkdir(cfg, 0755); + //sprintf(cfg, "%s/.PS2E/CDVDiso.cfg", getenv("HOME")); + strcpy(cfg, s_strIniPath); + + f = fopen(cfg, "w"); + if (f == NULL) + { + printf("Unable to save %s\n", cfg); + return; + } + + fprintf(f, "IsoFile = %s\n", IsoFile); + fprintf(f, "CdDev = %s\n", CdDev); + fprintf(f, "BlockDump = %d\n", BlockDump); + fclose(f); +} + diff --git a/plugins/CDVDiso/src/Linux/Config.h b/plugins/CDVDiso/src/Linux/Config.h index d1df0d3e72..ee6fad76c7 100644 --- a/plugins/CDVDiso/src/Linux/Config.h +++ b/plugins/CDVDiso/src/Linux/Config.h @@ -1,20 +1,20 @@ -/* CDVDiso - * Copyright (C) 2002-2004 CDVDiso 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -void SaveConf(); -void LoadConf(); +/* CDVDiso + * Copyright (C) 2002-2004 CDVDiso 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +void SaveConf(); +void LoadConf(); diff --git a/plugins/CDVDiso/src/Linux/Linux.c b/plugins/CDVDiso/src/Linux/Linux.c index 28c6251365..69e1e73fc1 100644 --- a/plugins/CDVDiso/src/Linux/Linux.c +++ b/plugins/CDVDiso/src/Linux/Linux.c @@ -1,87 +1,87 @@ -/* CDVDiso - * Copyright (C) 2002-2004 CDVDiso 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include - -#include "Config.h" -#include "CDVDiso.h" - -void ExecCfg(char *arg) -{ - char cfg[256]; - struct stat buf; - - strcpy(cfg, "./cfgCDVDiso"); - if (stat(cfg, &buf) != -1) - { - sprintf(cfg, "%s %s", cfg, arg); - system(cfg); - return; - } - - strcpy(cfg, "./cfg/cfgCDVDiso"); - if (stat(cfg, &buf) != -1) - { - sprintf(cfg, "%s %s", cfg, arg); - system(cfg); - return; - } - - sprintf(cfg, "%s/cfgCDVDiso", getenv("HOME")); - if (stat(cfg, &buf) != -1) - { - sprintf(cfg, "%s %s", cfg, arg); - system(cfg); - return; - } - - printf("cfgCDVDiso file not found!\n"); -} - -void CDVDconfigure() -{ - ExecCfg("configure"); -} - -void CDVDabout() -{ - ExecCfg("about"); -} - -void CfgOpenFile() -{ - ExecCfg("open"); -} - -void SysMessage(char *fmt, ...) -{ - va_list list; - char tmp[256]; - char cmd[256]; - - va_start(list, fmt); - vsprintf(tmp, fmt, list); - va_end(list); - - sprintf(cmd, "message \"%s\"", tmp); - ExecCfg(cmd); -} +/* CDVDiso + * Copyright (C) 2002-2004 CDVDiso 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include "Config.h" +#include "CDVDiso.h" + +void ExecCfg(char *arg) +{ + char cfg[256]; + struct stat buf; + + strcpy(cfg, "./cfgCDVDiso"); + if (stat(cfg, &buf) != -1) + { + sprintf(cfg, "%s %s", cfg, arg); + system(cfg); + return; + } + + strcpy(cfg, "./cfg/cfgCDVDiso"); + if (stat(cfg, &buf) != -1) + { + sprintf(cfg, "%s %s", cfg, arg); + system(cfg); + return; + } + + sprintf(cfg, "%s/cfgCDVDiso", getenv("HOME")); + if (stat(cfg, &buf) != -1) + { + sprintf(cfg, "%s %s", cfg, arg); + system(cfg); + return; + } + + printf("cfgCDVDiso file not found!\n"); +} + +void CDVDconfigure() +{ + ExecCfg("configure"); +} + +void CDVDabout() +{ + ExecCfg("about"); +} + +void CfgOpenFile() +{ + ExecCfg("open"); +} + +void SysMessage(char *fmt, ...) +{ + va_list list; + char tmp[256]; + char cmd[256]; + + va_start(list, fmt); + vsprintf(tmp, fmt, list); + va_end(list); + + sprintf(cmd, "message \"%s\"", tmp); + ExecCfg(cmd); +} diff --git a/plugins/CDVDiso/src/Linux/Makefile b/plugins/CDVDiso/src/Linux/Makefile index 921f6190c9..7893a6548d 100644 --- a/plugins/CDVDiso/src/Linux/Makefile +++ b/plugins/CDVDiso/src/Linux/Makefile @@ -1,33 +1,33 @@ - -CC = gcc - -PLUGIN = libCDVDiso.so -CFG = cfgCDVDiso -MKISO = mkiso -CFLAGS = -fPIC -Wall -g -I.. -I. -D__LINUX__ -OBJS = ../CDVDisop.o Config.o Linux.o ../libiso.o -CFGOBJS = conf.o interface.o support.o ${OBJS} -LIBS = -lz -lbz2 -lstdc++ -CFGLIBS = $(shell pkg-config --libs gtk+-2.0) ${LIBS} -CFLAGS += $(shell pkg-config --cflags gtk+-2.0) -I../common -DEPS:= $(OBJS:.o=.d) $(CFGOBJS:.o=.d) - -all: plugin cfg -install: all - -plugin: ${OBJS} - rm -f ${PLUGIN} - ${CC} -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} - -cfg: ${CFGOBJS} - rm -f ${CFG} - ${CC} ${CFLAGS} ${CFGOBJS} -o ${CFG} ${CFGLIBS} - strip ${CFG} - -clean: - rm -f ${OBJS} ${DEPS} ${PLUGIN} ${CFGOBJS} ${CFG} - -%.o: %.c - ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) - --include ${DEPS} + +CC = gcc + +PLUGIN = libCDVDiso.so +CFG = cfgCDVDiso +MKISO = mkiso +CFLAGS = -fPIC -Wall -g -I.. -I. -D__LINUX__ +OBJS = ../CDVDisop.o Config.o Linux.o ../libiso.o +CFGOBJS = conf.o interface.o support.o ${OBJS} +LIBS = -lz -lbz2 -lstdc++ +CFGLIBS = $(shell pkg-config --libs gtk+-2.0) ${LIBS} +CFLAGS += $(shell pkg-config --cflags gtk+-2.0) -I../common +DEPS:= $(OBJS:.o=.d) $(CFGOBJS:.o=.d) + +all: plugin cfg +install: all + +plugin: ${OBJS} + rm -f ${PLUGIN} + ${CC} -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + +cfg: ${CFGOBJS} + rm -f ${CFG} + ${CC} ${CFLAGS} ${CFGOBJS} -o ${CFG} ${CFGLIBS} + strip ${CFG} + +clean: + rm -f ${OBJS} ${DEPS} ${PLUGIN} ${CFGOBJS} ${CFG} + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +-include ${DEPS} diff --git a/plugins/CDVDiso/src/Linux/conf.c b/plugins/CDVDiso/src/Linux/conf.c index a016d3396b..298c99962b 100644 --- a/plugins/CDVDiso/src/Linux/conf.c +++ b/plugins/CDVDiso/src/Linux/conf.c @@ -1,966 +1,966 @@ -/* CDVDiso - * Copyright (C) 2002-2004 CDVDiso 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "interface.h" -#include "support.h" -#include "CDVDiso.h" -#include "Config.h" - - -// Make it easier to check and set checkmarks in the gui -#define is_checked(main_widget, widget_name) (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(main_widget, widget_name)))) -#define set_checked(main_widget,widget_name, state) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(main_widget, widget_name)), state) - -unsigned char Zbuf[CD_FRAMESIZE_RAW * 10 * 2]; - -extern char *LibName; - -extern const unsigned char revision; -extern const unsigned char build; - -GtkWidget *FileSel; - -void OnFile_Ok() -{ - gchar *File; - - gtk_widget_hide(FileSel); - File = gtk_file_selection_get_filename(GTK_FILE_SELECTION(FileSel)); - strcpy(IsoFile, File); - gtk_main_quit(); -} - -void OnFile_Cancel() -{ - gtk_widget_hide(FileSel); - gtk_main_quit(); -} - -void _CDRopen() -{ - GtkWidget *Ok, *Cancel; - - FileSel = gtk_file_selection_new("Select Iso File"); - - Ok = GTK_FILE_SELECTION(FileSel)->ok_button; - gtk_signal_connect(GTK_OBJECT(Ok), "clicked", - GTK_SIGNAL_FUNC(OnFile_Ok), NULL); - gtk_widget_show(Ok); - - Cancel = GTK_FILE_SELECTION(FileSel)->cancel_button; - gtk_signal_connect(GTK_OBJECT(Cancel), "clicked", - GTK_SIGNAL_FUNC(OnFile_Cancel), NULL); - gtk_widget_show(Cancel); - - gtk_widget_show(FileSel); - gdk_window_raise(FileSel->window); - - gtk_main(); - - SaveConf(); -} - -GtkWidget *MsgDlg; - -void OnMsg_Ok() -{ - gtk_widget_destroy(MsgDlg); - gtk_main_quit(); -} - -static void SysMessageLoc(char *fmt, ...) -{ - GtkWidget *Ok, *Txt; - GtkWidget *Box, *Box1; - va_list list; - int w; - char msg[512]; - - va_start(list, fmt); - vsprintf(msg, fmt, list); - va_end(list); - - if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; - - w = strlen(msg) * 6 + 20; - - MsgDlg = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_widget_set_usize(MsgDlg, w, 70); - gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); - gtk_window_set_title(GTK_WINDOW(MsgDlg), "cdriso Msg"); - gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 0); - - Box = gtk_vbox_new(0, 0); - gtk_container_add(GTK_CONTAINER(MsgDlg), Box); - gtk_widget_show(Box); - - Txt = gtk_label_new(msg); - - gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); - gtk_widget_show(Txt); - - Box1 = gtk_hbutton_box_new(); - gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); - gtk_widget_show(Box1); - - Ok = gtk_button_new_with_label("Ok"); - gtk_signal_connect(GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); - gtk_container_add(GTK_CONTAINER(Box1), Ok); - GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); - gtk_widget_show(Ok); - - gtk_widget_show(MsgDlg); - - gtk_main(); -} - -GtkWidget *ConfDlg; -GtkWidget *Edit, *CdEdit; -GtkWidget *FileSel; -GtkWidget *Progress; -GtkWidget *BtnCompress; -GtkWidget *BtnDecompress; -GtkWidget *BtnCreate; -GtkWidget *BtnCreateZ; -GtkWidget *Method; - -GList *methodlist; -extern char *methods[]; - -int stop; - -void OnOk(GtkMenuItem * menuitem, gpointer userdata) -{ - char *tmp; - - stop = 1; - tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); - strcpy(IsoFile, tmp); - tmp = gtk_entry_get_text(GTK_ENTRY(CdEdit)); - strcpy(CdDev, tmp); - - if is_checked(ConfDlg, "checkBlockDump") - BlockDump = 1; - else - BlockDump = 0; - - SaveConf(); - gtk_widget_destroy(ConfDlg); - gtk_main_quit(); -} - -void OnCancel(GtkMenuItem * menuitem, gpointer userdata) -{ - stop = 1; - gtk_widget_destroy(ConfDlg); - gtk_main_quit(); -} - -void OnFileSel_Ok() -{ - gchar *File; - - File = gtk_file_selection_get_filename(GTK_FILE_SELECTION(FileSel)); - gtk_entry_set_text(GTK_ENTRY(Edit), File); - gtk_widget_destroy(FileSel); -} - -void OnFileSel_Cancel() -{ - gtk_widget_destroy(FileSel); -} - -void OnFileSel() -{ - GtkWidget *Ok, *Cancel; - - FileSel = gtk_file_selection_new("Select Psx Iso File"); - gtk_file_selection_set_filename(GTK_FILE_SELECTION(FileSel), IsoFile); - - Ok = GTK_FILE_SELECTION(FileSel)->ok_button; - gtk_signal_connect(GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnFileSel_Ok), NULL); - gtk_widget_show(Ok); - - Cancel = GTK_FILE_SELECTION(FileSel)->cancel_button; - gtk_signal_connect(GTK_OBJECT(Cancel), "clicked", GTK_SIGNAL_FUNC(OnFileSel_Cancel), NULL); - gtk_widget_show(Cancel); - - gtk_widget_show(FileSel); - gdk_window_raise(FileSel->window); -} - -void OnStop() -{ - stop = 1; -} - -void UpdZmode() -{ - char *tmp; - - tmp = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(Method)->entry)); - if (!strcmp(tmp, methods[0])) Zmode = 1; - else Zmode = 2; -} - -char buffer[2352 * 10]; - -void OnCompress() -{ - struct stat buf; - u32 lsn; - u8 cdbuff[10*2352]; - char Zfile[256]; - char *tmp; - int ret; - isoFile *src; - isoFile *dst; - - tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); - strcpy(IsoFile, tmp); - UpdZmode(); - - if (Zmode == 1) sprintf(Zfile, "%s.Z2", IsoFile); - if (Zmode == 2) sprintf(Zfile, "%s.BZ2", IsoFile); - - if (stat(Zfile, &buf) != -1) - { - /*char str[256];*/ - return; - /* sprintf(str, "'%s' already exists, overwrite?", Zfile); - if (MessageBox(hDlg, str, "Question", MB_YESNO) != IDYES) { - return; - }*/ - } - - src = isoOpen(IsoFile); - if (src == NULL) return; - dst = isoCreate(Zfile, Zmode == 1 ? ISOFLAGS_Z2 : ISOFLAGS_BZ2); - if (dst == NULL) return; - - gtk_widget_set_sensitive(BtnCompress, FALSE); - gtk_widget_set_sensitive(BtnDecompress, FALSE); - gtk_widget_set_sensitive(BtnCreate, FALSE); - gtk_widget_set_sensitive(BtnCreateZ, FALSE); - stop = 0; - - for (lsn = 0; lsn < src->blocks; lsn++) - { - printf("block %d ", lsn); - putchar(13); - fflush(stdout); - ret = isoReadBlock(src, cdbuff, lsn); - if (ret == -1) break; - ret = isoWriteBlock(dst, cdbuff, lsn); - if (ret == -1) break; - - gtk_progress_bar_update(GTK_PROGRESS_BAR(Progress), (lsn * 100) / src->blocks); - while (gtk_events_pending()) gtk_main_iteration(); - if (stop) break; - } - isoClose(src); - isoClose(dst); - - if (!stop) gtk_entry_set_text(GTK_ENTRY(Edit), IsoFile); - - gtk_widget_set_sensitive(BtnCompress, TRUE); - gtk_widget_set_sensitive(BtnDecompress, TRUE); - gtk_widget_set_sensitive(BtnCreate, TRUE); - gtk_widget_set_sensitive(BtnCreateZ, TRUE); - - if (!stop) - { - if (ret == -1) - { - SysMessageLoc("Error compressing iso image"); - } - else - { - SysMessageLoc("Iso image compressed OK"); - } - } -} - -void OnDecompress() -{ -#if 0 - struct stat buf; - FILE *f; - unsigned long c = 0, p = 0, s; - char table[256]; - char *tmp; - int blocks; - - tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); - strcpy(IsoFile, tmp); - - if (strstr(IsoFile, ".Z") != NULL) Zmode = 1; - else Zmode = 2; - - strcpy(table, IsoFile); - if (Zmode == 1) strcat(table, ".table"); - else strcat(table, ".index"); - - if (stat(table, &buf) == -1) - { - return; - } - - if (Zmode == 1) - c = s = buf.st_size / 6; - else - c = s = (buf.st_size / 4) - 1; - - f = fopen(table, "rb"); - Ztable = (char*)malloc(buf.st_size); - fread(Ztable, 1, buf.st_size, f); - fclose(f); - - cdHandle[0] = fopen(IsoFile, "rb"); - if (cdHandle[0] == NULL) - { - return; - } - - if (Zmode == 1) - IsoFile[strlen(IsoFile) - 2] = 0; - else - IsoFile[strlen(IsoFile) - 3] = 0; - - f = fopen(IsoFile, "wb"); - if (f == NULL) - { - return; - } - - gtk_widget_set_sensitive(BtnCompress, FALSE); - gtk_widget_set_sensitive(BtnDecompress, FALSE); - gtk_widget_set_sensitive(BtnCreate, FALSE); - gtk_widget_set_sensitive(BtnCreateZ, FALSE); - stop = 0; - - if (Zmode == 1) - { - blocks = 1; - } - else - { - blocks = 10; - } - - while (c--) - { - unsigned long size, pos, ssize; - float per; - - if (Zmode == 1) - { - pos = *(unsigned long*) & Ztable[p * 6]; - fseek(cdHandle[0], pos, SEEK_SET); - - ssize = *(unsigned short*) & Ztable[p * 6 + 4]; - fread(Zbuf, 1, ssize, cdHandle[0]); - } - else - { - pos = *(unsigned long*) & Ztable[p * 4]; - fseek(cdHandle[0], pos, SEEK_SET); - - ssize = *(unsigned long*) & Ztable[p * 4 + 4] - pos; - fread(Zbuf, 1, ssize, cdHandle[0]); - } - - size = CD_FRAMESIZE_RAW * blocks; - if (Zmode == 1) - uncompress(cdbuffer, &size, Zbuf, ssize); - else - BZ2_bzBuffToBuffDecompress(cdbuffer, (unsigned int*)&size, Zbuf, ssize, 0, 0); - - fwrite(cdbuffer, 1, size, f); - - p++; - - per = ((float)p / s); - - gtk_progress_bar_update(GTK_PROGRESS_BAR(Progress), per); - while (gtk_events_pending()) gtk_main_iteration(); - - if (stop) break; - } - if (!stop) gtk_entry_set_text(GTK_ENTRY(Edit), IsoFile); - - fclose(f); - fclose(cdHandle[0]); - cdHandle[0] = NULL; - free(Ztable); - Ztable = NULL; - - gtk_widget_set_sensitive(BtnCompress, TRUE); - gtk_widget_set_sensitive(BtnDecompress, TRUE); - gtk_widget_set_sensitive(BtnCreate, TRUE); - gtk_widget_set_sensitive(BtnCreateZ, TRUE); - - if (!stop) SysMessageLoc("Iso Image Decompressed OK"); -#endif -} - -#define CD_LEADOUT (0xaa) -unsigned char param[4]; -int cddev = -1; - -union -{ - struct cdrom_msf msf; - unsigned char buf[CD_FRAMESIZE_RAW]; -} cr; - -void incSector() -{ - param[2]++; - if (param[2] == 75) - { - param[2] = 0; - param[1]++; - } - if (param[1] == 60) - { - param[1] = 0; - param[0]++; - } -} - -long CDR_open(void) -{ - if (cddev != -1) - return 0; - cddev = open(CdDev, O_RDONLY); - if (cddev == -1) - { - printf("CDR: Could not open %s\n", CdDev); - return -1; - } - - return 0; -} - -long CDR_close(void) -{ - if (cddev == -1) return 0; - close(cddev); - cddev = -1; - - return 0; -} - -// return Starting and Ending Track -// buffer: -// byte 0 - start track -// byte 1 - end track -long CDR_getTN(unsigned char *buffer) -{ - struct cdrom_tochdr toc; - - if (ioctl(cddev, CDROMREADTOCHDR, &toc) == -1) return -1; - - buffer[0] = toc.cdth_trk0; // start track - buffer[1] = toc.cdth_trk1; // end track - - return 0; -} - -// return Track Time -// buffer: -// byte 0 - frame -// byte 1 - second -// byte 2 - minute -long CDR_getTD(unsigned char track, unsigned char *buffer) -{ - struct cdrom_tocentry entry; - - if (track == 0) track = 0xaa; // total time - entry.cdte_track = track; - entry.cdte_format = CDROM_MSF; - - if (ioctl(cddev, CDROMREADTOCENTRY, &entry) == -1) return -1; - - buffer[0] = entry.cdte_addr.msf.minute; /* minute */ - buffer[1] = entry.cdte_addr.msf.second; /* second */ - buffer[2] = entry.cdte_addr.msf.frame; /* frame */ - - return 0; -} - -// read track -// time: -// byte 0 - minute -// byte 1 - second -// byte 2 - frame -char *CDR_readTrack(unsigned char *time) -{ - cr.msf.cdmsf_min0 = time[0]; - cr.msf.cdmsf_sec0 = time[1]; - cr.msf.cdmsf_frame0 = time[2]; - - if (ioctl(cddev, CDROMREADRAW, &cr) == -1) return NULL; - return cr.buf; -} - - -void OnCreate() -{ - FILE *f; - struct stat buf; - struct tm *Tm; - time_t Ttime; - unsigned long ftrack, ltrack; - unsigned long p = 0, s; - unsigned char *buffer; - unsigned char bufferz[2352]; - unsigned char start[4], end[4]; - char *tmp; -#ifdef VERBOSE - unsigned long count = 0; - int i = 0; -#endif - - memset(bufferz, 0, sizeof(bufferz)); - ftrack = 1; - ltrack = CD_LEADOUT; - - tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); - strcpy(IsoFile, tmp); - - if (stat(IsoFile, &buf) == 0) - { - printf("File %s Already exists\n", IsoFile); - return; - } - - if (CDR_open() == -1) - { - return; - } - - if (CDR_getTD(ftrack, start) == -1) - { - printf("Error getting TD\n"); - - CDR_close(); - return; - } - if (CDR_getTD(ltrack, end) == -1) - { - printf("Error getting TD\n"); - - CDR_close(); - return; - } - - f = fopen(IsoFile, "wb"); - if (f == NULL) - { - CDR_close(); - printf("Error opening %s", IsoFile); - return; - } - - printf("Making Iso: from %2.2d:%2.2d:%2.2d to %2.2d:%2.2d:%2.2d\n", - start[0], start[1], start[2], end[0], end[1], end[2]); - - memcpy(param, start, 3); - - time(&Ttime); - - stop = 0; - s = MSF2SECT(end[0], end[1], end[2]); - gtk_widget_set_sensitive(BtnCompress, FALSE); - gtk_widget_set_sensitive(BtnDecompress, FALSE); - gtk_widget_set_sensitive(BtnCreate, FALSE); - gtk_widget_set_sensitive(BtnCreateZ, FALSE); - - for (;;) /* loop until end */ - { - float per; - - if ((param[0] == end[0]) & (param[1] == end[1]) & (param[2] == end[2])) - break; - buffer = CDR_readTrack(param); - if (buffer == NULL) - { - int i; - - for (i = 0; i < 10; i++) - { - buffer = CDR_readTrack(param); - if (buffer != NULL) break; - } - if (buffer == NULL) - { - printf("Error Reading %2d:%2d:%2d\n", param[0], param[1], param[2]); - buffer = bufferz; - buffer[12] = param[0]; - buffer[13] = param[1]; - buffer[14] = param[2]; - buffer[15] = 0x2; - } - } - fwrite(buffer, 1, 2352, f); -#ifdef VERBOSE - count += CD_FRAMESIZE_RAW; - - printf("reading %2d:%2d:%2d ", param[0], param[1], param[2]); - if ((time(NULL) - Ttime) != 0) - { - i = (count / 1024) / (time(NULL) - Ttime); - printf("( %5dKbytes/s, %dX)", i, i / 150); - } - putchar(13); - fflush(stdout); -#endif - - incSector(); - - p++; - per = ((float)p / s); - gtk_progress_bar_update(GTK_PROGRESS_BAR(Progress), per); - while (gtk_events_pending()) gtk_main_iteration(); - if (stop) break; - } - - Ttime = time(NULL) - Ttime; - Tm = gmtime(&Ttime); - printf("\nTotal Time used: %d:%d:%d\n", Tm->tm_hour, Tm->tm_min, - Tm->tm_sec); - - CDR_close(); - fclose(f); - - gtk_widget_set_sensitive(BtnCompress, TRUE); - gtk_widget_set_sensitive(BtnDecompress, TRUE); - gtk_widget_set_sensitive(BtnCreate, TRUE); - gtk_widget_set_sensitive(BtnCreateZ, TRUE); - - if (!stop) SysMessageLoc("Iso Image Created OK"); -} - -void OnCreateZ() -{ - FILE *f; - FILE *t; - struct stat buf; - struct tm *Tm; - time_t Ttime; - unsigned long ftrack, ltrack; - unsigned long p = 0, s, c = 0; - unsigned char *buffer; - unsigned char bufferz[2352]; - unsigned char start[4], end[4]; - char table[256]; - char *tmp; - int b, blocks; -#ifdef VERBOSE - unsigned long count = 0; - int i = 0; -#endif - - memset(bufferz, 0, sizeof(bufferz)); - ftrack = 1; - ltrack = CD_LEADOUT; - - tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); - strcpy(IsoFile, tmp); - - UpdZmode(); - - if (Zmode == 1) - { - blocks = 1; - if (strstr(IsoFile, ".Z") == NULL) strcat(IsoFile, ".Z"); - } - else - { - blocks = 10; - if (strstr(IsoFile, ".bz") == NULL) strcat(IsoFile, ".bz"); - } - - if (stat(IsoFile, &buf) == 0) - { - printf("File %s Already exists\n", IsoFile); - return; - } - - strcpy(table, IsoFile); - if (Zmode == 1) - strcat(table, ".table"); - else - strcat(table, ".index"); - - t = fopen(table, "wb"); - - if (t == NULL) return; - if (CDR_open() == -1) return; - - if (CDR_getTD(ftrack, start) == -1) - { - printf("Error getting TD\n"); - CDR_close(); - return; - } - - if (CDR_getTD(ltrack, end) == -1) - { - printf("Error getting TD\n"); - CDR_close(); - return; - } - - f = fopen(IsoFile, "wb"); - if (f == NULL) - { - CDR_close(); - printf("Error opening %s", IsoFile); - return; - } - - printf("Making Iso: from %2.2d:%2.2d:%2.2d to %2.2d:%2.2d:%2.2d\n", - start[0], start[1], start[2], end[0], end[1], end[2]); - - memcpy(param, start, 3); - - time(&Ttime); - - stop = 0; - s = MSF2SECT(end[0], end[1], end[2]) / blocks; - gtk_widget_set_sensitive(BtnCompress, FALSE); - gtk_widget_set_sensitive(BtnDecompress, FALSE); - gtk_widget_set_sensitive(BtnCreate, FALSE); - gtk_widget_set_sensitive(BtnCreateZ, FALSE); - - for (;;) /* loop until end */ - { - unsigned long size; - unsigned char Zbuf[CD_FRAMESIZE_RAW * 10 * 2]; - float per; - - for (b = 0; b < blocks; b++) - { - if ((param[0] == end[0]) & (param[1] == end[1]) & (param[2] == end[2])) - break; - - buffer = CDR_readTrack(param); - if (buffer == NULL) - { - int i; - - for (i = 0; i < 10; i++) - { - buffer = CDR_readTrack(param); - if (buffer != NULL) break; - } - - if (buffer == NULL) - { - printf("Error Reading %2d:%2d:%2d\n", param[0], param[1], param[2]); - buffer = bufferz; - buffer[12] = param[0]; - buffer[13] = param[1]; - buffer[14] = param[2]; - buffer[15] = 0x2; - } - } - memcpy(cdbuffer + b * CD_FRAMESIZE_RAW, buffer, CD_FRAMESIZE_RAW); - - incSector(); - } - if ((param[0] == end[0]) & (param[1] == end[1]) & (param[2] == end[2])) - break; - - size = CD_FRAMESIZE_RAW * blocks * 2; - if (Zmode == 1) - compress(Zbuf, &size, cdbuffer, CD_FRAMESIZE_RAW); - else - BZ2_bzBuffToBuffCompress(Zbuf, (unsigned int*)&size, cdbuffer, CD_FRAMESIZE_RAW * 10, 1, 0, 30); - - fwrite(&c, 1, 4, t); - if (Zmode == 1) fwrite(&size, 1, 2, t); - - fwrite(Zbuf, 1, size, f); - - c += size; -#ifdef VERBOSE - count += CD_FRAMESIZE_RAW * blocks; - - printf("reading %2d:%2d:%2d ", param[0], param[1], param[2]); - if ((time(NULL) - Ttime) != 0) - { - i = (count / 1024) / (time(NULL) - Ttime); - printf("( %5dKbytes/s, %dX)", i, i / 150); - } - putchar(13); - fflush(stdout); -#endif - - p++; - per = ((float)p / s); - - gtk_progress_bar_update(GTK_PROGRESS_BAR(Progress), per); - while (gtk_events_pending()) gtk_main_iteration(); - - if (stop) break; - } - if (Zmode == 2) fwrite(&c, 1, 4, f); - - if (!stop) gtk_entry_set_text(GTK_ENTRY(Edit), IsoFile); - - Ttime = time(NULL) - Ttime; - Tm = gmtime(&Ttime); - printf("\nTotal Time used: %d:%d:%d\n", Tm->tm_hour, Tm->tm_min, - Tm->tm_sec); - - CDR_close(); - fclose(f); - fclose(t); - - gtk_widget_set_sensitive(BtnCompress, TRUE); - gtk_widget_set_sensitive(BtnDecompress, TRUE); - gtk_widget_set_sensitive(BtnCreate, TRUE); - gtk_widget_set_sensitive(BtnCreateZ, TRUE); - - if (!stop) SysMessageLoc("Compressed Iso Image Created OK"); -} - -long CDRconfigure(void) -{ - int i; - - LoadConf(); - - ConfDlg = create_Config(); - - Edit = lookup_widget(ConfDlg, "GtkEntry_Iso"); - gtk_entry_set_text(GTK_ENTRY(Edit), IsoFile); - CdEdit = lookup_widget(ConfDlg, "GtkEntry_CdDev"); - gtk_entry_set_text(GTK_ENTRY(CdEdit), CdDev); - - Progress = lookup_widget(ConfDlg, "GtkProgressBar_Progress"); - - BtnCompress = lookup_widget(ConfDlg, "GtkButton_Compress"); - BtnDecompress = lookup_widget(ConfDlg, "GtkButton_Decompress"); - BtnCreate = lookup_widget(ConfDlg, "GtkButton_Create"); - BtnCreateZ = lookup_widget(ConfDlg, "GtkButton_CreateZ"); - - methodlist = NULL; - for (i = 0; i < 2; i++) - methodlist = g_list_append(methodlist, methods[i]); - - Method = lookup_widget(ConfDlg, "GtkCombo_Method"); - gtk_combo_set_popdown_strings(GTK_COMBO(Method), methodlist); - if (strstr(IsoFile, ".Z") != NULL) - gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(Method)->entry), methods[0]); - else - gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(Method)->entry), methods[1]); - - set_checked(ConfDlg, "checkBlockDump", (BlockDump == 1)); - - gtk_widget_show_all(ConfDlg); - gtk_main(); - - return 0; -} - -GtkWidget *AboutDlg; - -void OnAboutOk(GtkMenuItem * menuitem, gpointer userdata) -{ - gtk_widget_hide(AboutDlg); - gtk_main_quit(); -} - -void CDRabout(void) -{ - GtkWidget *Label; - GtkWidget *Ok; - GtkWidget *Box, *BBox; - char AboutText[255]; - - sprintf(AboutText, "%s %d.%d\n", LibName, revision, build); - - AboutDlg = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_widget_set_usize(AboutDlg, 260, 80); - gtk_window_set_title(GTK_WINDOW(AboutDlg), "CDVD About Dialog"); - gtk_window_set_position(GTK_WINDOW(AboutDlg), GTK_WIN_POS_CENTER); - gtk_container_set_border_width(GTK_CONTAINER(AboutDlg), 10); - - Box = gtk_vbox_new(0, 0); - gtk_container_add(GTK_CONTAINER(AboutDlg), Box); - gtk_widget_show(Box); - - Label = gtk_label_new(AboutText); - gtk_box_pack_start(GTK_BOX(Box), Label, FALSE, FALSE, 0); - gtk_widget_show(Label); - - BBox = gtk_hbutton_box_new(); - gtk_box_pack_start(GTK_BOX(Box), BBox, FALSE, FALSE, 0); - gtk_widget_show(BBox); - - Ok = gtk_button_new_with_label("Ok"); - gtk_signal_connect(GTK_OBJECT(Ok), "clicked", - GTK_SIGNAL_FUNC(OnAboutOk), NULL); - gtk_container_add(GTK_CONTAINER(BBox), Ok); - GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); - gtk_widget_show(Ok); - - gtk_widget_show(AboutDlg); - gtk_main(); -} - -int main(int argc, char *argv[]) -{ - if (argc < 2) return 0; - - gtk_init(NULL, NULL); - - if (!strcmp(argv[1], "open")) - _CDRopen(); - else if (!strcmp(argv[1], "configure")) - CDRconfigure(); - else if (!strcmp(argv[1], "message")) - { - if (argc > 2) SysMessageLoc(argv[2]); - } - else - CDRabout(); - - return 0; -} - - +/* CDVDiso + * Copyright (C) 2002-2004 CDVDiso 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "interface.h" +#include "support.h" +#include "CDVDiso.h" +#include "Config.h" + + +// Make it easier to check and set checkmarks in the gui +#define is_checked(main_widget, widget_name) (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(main_widget, widget_name)))) +#define set_checked(main_widget,widget_name, state) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(main_widget, widget_name)), state) + +unsigned char Zbuf[CD_FRAMESIZE_RAW * 10 * 2]; + +extern char *LibName; + +extern const unsigned char revision; +extern const unsigned char build; + +GtkWidget *FileSel; + +void OnFile_Ok() +{ + gchar *File; + + gtk_widget_hide(FileSel); + File = gtk_file_selection_get_filename(GTK_FILE_SELECTION(FileSel)); + strcpy(IsoFile, File); + gtk_main_quit(); +} + +void OnFile_Cancel() +{ + gtk_widget_hide(FileSel); + gtk_main_quit(); +} + +void _CDRopen() +{ + GtkWidget *Ok, *Cancel; + + FileSel = gtk_file_selection_new("Select Iso File"); + + Ok = GTK_FILE_SELECTION(FileSel)->ok_button; + gtk_signal_connect(GTK_OBJECT(Ok), "clicked", + GTK_SIGNAL_FUNC(OnFile_Ok), NULL); + gtk_widget_show(Ok); + + Cancel = GTK_FILE_SELECTION(FileSel)->cancel_button; + gtk_signal_connect(GTK_OBJECT(Cancel), "clicked", + GTK_SIGNAL_FUNC(OnFile_Cancel), NULL); + gtk_widget_show(Cancel); + + gtk_widget_show(FileSel); + gdk_window_raise(FileSel->window); + + gtk_main(); + + SaveConf(); +} + +GtkWidget *MsgDlg; + +void OnMsg_Ok() +{ + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + +static void SysMessageLoc(char *fmt, ...) +{ + GtkWidget *Ok, *Txt; + GtkWidget *Box, *Box1; + va_list list; + int w; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + w = strlen(msg) * 6 + 20; + + MsgDlg = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_set_usize(MsgDlg, w, 70); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "cdriso Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 0); + + Box = gtk_vbox_new(0, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect(GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main(); +} + +GtkWidget *ConfDlg; +GtkWidget *Edit, *CdEdit; +GtkWidget *FileSel; +GtkWidget *Progress; +GtkWidget *BtnCompress; +GtkWidget *BtnDecompress; +GtkWidget *BtnCreate; +GtkWidget *BtnCreateZ; +GtkWidget *Method; + +GList *methodlist; +extern char *methods[]; + +int stop; + +void OnOk(GtkMenuItem * menuitem, gpointer userdata) +{ + char *tmp; + + stop = 1; + tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); + strcpy(IsoFile, tmp); + tmp = gtk_entry_get_text(GTK_ENTRY(CdEdit)); + strcpy(CdDev, tmp); + + if is_checked(ConfDlg, "checkBlockDump") + BlockDump = 1; + else + BlockDump = 0; + + SaveConf(); + gtk_widget_destroy(ConfDlg); + gtk_main_quit(); +} + +void OnCancel(GtkMenuItem * menuitem, gpointer userdata) +{ + stop = 1; + gtk_widget_destroy(ConfDlg); + gtk_main_quit(); +} + +void OnFileSel_Ok() +{ + gchar *File; + + File = gtk_file_selection_get_filename(GTK_FILE_SELECTION(FileSel)); + gtk_entry_set_text(GTK_ENTRY(Edit), File); + gtk_widget_destroy(FileSel); +} + +void OnFileSel_Cancel() +{ + gtk_widget_destroy(FileSel); +} + +void OnFileSel() +{ + GtkWidget *Ok, *Cancel; + + FileSel = gtk_file_selection_new("Select Psx Iso File"); + gtk_file_selection_set_filename(GTK_FILE_SELECTION(FileSel), IsoFile); + + Ok = GTK_FILE_SELECTION(FileSel)->ok_button; + gtk_signal_connect(GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnFileSel_Ok), NULL); + gtk_widget_show(Ok); + + Cancel = GTK_FILE_SELECTION(FileSel)->cancel_button; + gtk_signal_connect(GTK_OBJECT(Cancel), "clicked", GTK_SIGNAL_FUNC(OnFileSel_Cancel), NULL); + gtk_widget_show(Cancel); + + gtk_widget_show(FileSel); + gdk_window_raise(FileSel->window); +} + +void OnStop() +{ + stop = 1; +} + +void UpdZmode() +{ + char *tmp; + + tmp = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(Method)->entry)); + if (!strcmp(tmp, methods[0])) Zmode = 1; + else Zmode = 2; +} + +char buffer[2352 * 10]; + +void OnCompress() +{ + struct stat buf; + u32 lsn; + u8 cdbuff[10*2352]; + char Zfile[256]; + char *tmp; + int ret; + isoFile *src; + isoFile *dst; + + tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); + strcpy(IsoFile, tmp); + UpdZmode(); + + if (Zmode == 1) sprintf(Zfile, "%s.Z2", IsoFile); + if (Zmode == 2) sprintf(Zfile, "%s.BZ2", IsoFile); + + if (stat(Zfile, &buf) != -1) + { + /*char str[256];*/ + return; + /* sprintf(str, "'%s' already exists, overwrite?", Zfile); + if (MessageBox(hDlg, str, "Question", MB_YESNO) != IDYES) { + return; + }*/ + } + + src = isoOpen(IsoFile); + if (src == NULL) return; + dst = isoCreate(Zfile, Zmode == 1 ? ISOFLAGS_Z2 : ISOFLAGS_BZ2); + if (dst == NULL) return; + + gtk_widget_set_sensitive(BtnCompress, FALSE); + gtk_widget_set_sensitive(BtnDecompress, FALSE); + gtk_widget_set_sensitive(BtnCreate, FALSE); + gtk_widget_set_sensitive(BtnCreateZ, FALSE); + stop = 0; + + for (lsn = 0; lsn < src->blocks; lsn++) + { + printf("block %d ", lsn); + putchar(13); + fflush(stdout); + ret = isoReadBlock(src, cdbuff, lsn); + if (ret == -1) break; + ret = isoWriteBlock(dst, cdbuff, lsn); + if (ret == -1) break; + + gtk_progress_bar_update(GTK_PROGRESS_BAR(Progress), (lsn * 100) / src->blocks); + while (gtk_events_pending()) gtk_main_iteration(); + if (stop) break; + } + isoClose(src); + isoClose(dst); + + if (!stop) gtk_entry_set_text(GTK_ENTRY(Edit), IsoFile); + + gtk_widget_set_sensitive(BtnCompress, TRUE); + gtk_widget_set_sensitive(BtnDecompress, TRUE); + gtk_widget_set_sensitive(BtnCreate, TRUE); + gtk_widget_set_sensitive(BtnCreateZ, TRUE); + + if (!stop) + { + if (ret == -1) + { + SysMessageLoc("Error compressing iso image"); + } + else + { + SysMessageLoc("Iso image compressed OK"); + } + } +} + +void OnDecompress() +{ +#if 0 + struct stat buf; + FILE *f; + unsigned long c = 0, p = 0, s; + char table[256]; + char *tmp; + int blocks; + + tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); + strcpy(IsoFile, tmp); + + if (strstr(IsoFile, ".Z") != NULL) Zmode = 1; + else Zmode = 2; + + strcpy(table, IsoFile); + if (Zmode == 1) strcat(table, ".table"); + else strcat(table, ".index"); + + if (stat(table, &buf) == -1) + { + return; + } + + if (Zmode == 1) + c = s = buf.st_size / 6; + else + c = s = (buf.st_size / 4) - 1; + + f = fopen(table, "rb"); + Ztable = (char*)malloc(buf.st_size); + fread(Ztable, 1, buf.st_size, f); + fclose(f); + + cdHandle[0] = fopen(IsoFile, "rb"); + if (cdHandle[0] == NULL) + { + return; + } + + if (Zmode == 1) + IsoFile[strlen(IsoFile) - 2] = 0; + else + IsoFile[strlen(IsoFile) - 3] = 0; + + f = fopen(IsoFile, "wb"); + if (f == NULL) + { + return; + } + + gtk_widget_set_sensitive(BtnCompress, FALSE); + gtk_widget_set_sensitive(BtnDecompress, FALSE); + gtk_widget_set_sensitive(BtnCreate, FALSE); + gtk_widget_set_sensitive(BtnCreateZ, FALSE); + stop = 0; + + if (Zmode == 1) + { + blocks = 1; + } + else + { + blocks = 10; + } + + while (c--) + { + unsigned long size, pos, ssize; + float per; + + if (Zmode == 1) + { + pos = *(unsigned long*) & Ztable[p * 6]; + fseek(cdHandle[0], pos, SEEK_SET); + + ssize = *(unsigned short*) & Ztable[p * 6 + 4]; + fread(Zbuf, 1, ssize, cdHandle[0]); + } + else + { + pos = *(unsigned long*) & Ztable[p * 4]; + fseek(cdHandle[0], pos, SEEK_SET); + + ssize = *(unsigned long*) & Ztable[p * 4 + 4] - pos; + fread(Zbuf, 1, ssize, cdHandle[0]); + } + + size = CD_FRAMESIZE_RAW * blocks; + if (Zmode == 1) + uncompress(cdbuffer, &size, Zbuf, ssize); + else + BZ2_bzBuffToBuffDecompress(cdbuffer, (unsigned int*)&size, Zbuf, ssize, 0, 0); + + fwrite(cdbuffer, 1, size, f); + + p++; + + per = ((float)p / s); + + gtk_progress_bar_update(GTK_PROGRESS_BAR(Progress), per); + while (gtk_events_pending()) gtk_main_iteration(); + + if (stop) break; + } + if (!stop) gtk_entry_set_text(GTK_ENTRY(Edit), IsoFile); + + fclose(f); + fclose(cdHandle[0]); + cdHandle[0] = NULL; + free(Ztable); + Ztable = NULL; + + gtk_widget_set_sensitive(BtnCompress, TRUE); + gtk_widget_set_sensitive(BtnDecompress, TRUE); + gtk_widget_set_sensitive(BtnCreate, TRUE); + gtk_widget_set_sensitive(BtnCreateZ, TRUE); + + if (!stop) SysMessageLoc("Iso Image Decompressed OK"); +#endif +} + +#define CD_LEADOUT (0xaa) +unsigned char param[4]; +int cddev = -1; + +union +{ + struct cdrom_msf msf; + unsigned char buf[CD_FRAMESIZE_RAW]; +} cr; + +void incSector() +{ + param[2]++; + if (param[2] == 75) + { + param[2] = 0; + param[1]++; + } + if (param[1] == 60) + { + param[1] = 0; + param[0]++; + } +} + +long CDR_open(void) +{ + if (cddev != -1) + return 0; + cddev = open(CdDev, O_RDONLY); + if (cddev == -1) + { + printf("CDR: Could not open %s\n", CdDev); + return -1; + } + + return 0; +} + +long CDR_close(void) +{ + if (cddev == -1) return 0; + close(cddev); + cddev = -1; + + return 0; +} + +// return Starting and Ending Track +// buffer: +// byte 0 - start track +// byte 1 - end track +long CDR_getTN(unsigned char *buffer) +{ + struct cdrom_tochdr toc; + + if (ioctl(cddev, CDROMREADTOCHDR, &toc) == -1) return -1; + + buffer[0] = toc.cdth_trk0; // start track + buffer[1] = toc.cdth_trk1; // end track + + return 0; +} + +// return Track Time +// buffer: +// byte 0 - frame +// byte 1 - second +// byte 2 - minute +long CDR_getTD(unsigned char track, unsigned char *buffer) +{ + struct cdrom_tocentry entry; + + if (track == 0) track = 0xaa; // total time + entry.cdte_track = track; + entry.cdte_format = CDROM_MSF; + + if (ioctl(cddev, CDROMREADTOCENTRY, &entry) == -1) return -1; + + buffer[0] = entry.cdte_addr.msf.minute; /* minute */ + buffer[1] = entry.cdte_addr.msf.second; /* second */ + buffer[2] = entry.cdte_addr.msf.frame; /* frame */ + + return 0; +} + +// read track +// time: +// byte 0 - minute +// byte 1 - second +// byte 2 - frame +char *CDR_readTrack(unsigned char *time) +{ + cr.msf.cdmsf_min0 = time[0]; + cr.msf.cdmsf_sec0 = time[1]; + cr.msf.cdmsf_frame0 = time[2]; + + if (ioctl(cddev, CDROMREADRAW, &cr) == -1) return NULL; + return cr.buf; +} + + +void OnCreate() +{ + FILE *f; + struct stat buf; + struct tm *Tm; + time_t Ttime; + unsigned long ftrack, ltrack; + unsigned long p = 0, s; + unsigned char *buffer; + unsigned char bufferz[2352]; + unsigned char start[4], end[4]; + char *tmp; +#ifdef VERBOSE + unsigned long count = 0; + int i = 0; +#endif + + memset(bufferz, 0, sizeof(bufferz)); + ftrack = 1; + ltrack = CD_LEADOUT; + + tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); + strcpy(IsoFile, tmp); + + if (stat(IsoFile, &buf) == 0) + { + printf("File %s Already exists\n", IsoFile); + return; + } + + if (CDR_open() == -1) + { + return; + } + + if (CDR_getTD(ftrack, start) == -1) + { + printf("Error getting TD\n"); + + CDR_close(); + return; + } + if (CDR_getTD(ltrack, end) == -1) + { + printf("Error getting TD\n"); + + CDR_close(); + return; + } + + f = fopen(IsoFile, "wb"); + if (f == NULL) + { + CDR_close(); + printf("Error opening %s", IsoFile); + return; + } + + printf("Making Iso: from %2.2d:%2.2d:%2.2d to %2.2d:%2.2d:%2.2d\n", + start[0], start[1], start[2], end[0], end[1], end[2]); + + memcpy(param, start, 3); + + time(&Ttime); + + stop = 0; + s = MSF2SECT(end[0], end[1], end[2]); + gtk_widget_set_sensitive(BtnCompress, FALSE); + gtk_widget_set_sensitive(BtnDecompress, FALSE); + gtk_widget_set_sensitive(BtnCreate, FALSE); + gtk_widget_set_sensitive(BtnCreateZ, FALSE); + + for (;;) /* loop until end */ + { + float per; + + if ((param[0] == end[0]) & (param[1] == end[1]) & (param[2] == end[2])) + break; + buffer = CDR_readTrack(param); + if (buffer == NULL) + { + int i; + + for (i = 0; i < 10; i++) + { + buffer = CDR_readTrack(param); + if (buffer != NULL) break; + } + if (buffer == NULL) + { + printf("Error Reading %2d:%2d:%2d\n", param[0], param[1], param[2]); + buffer = bufferz; + buffer[12] = param[0]; + buffer[13] = param[1]; + buffer[14] = param[2]; + buffer[15] = 0x2; + } + } + fwrite(buffer, 1, 2352, f); +#ifdef VERBOSE + count += CD_FRAMESIZE_RAW; + + printf("reading %2d:%2d:%2d ", param[0], param[1], param[2]); + if ((time(NULL) - Ttime) != 0) + { + i = (count / 1024) / (time(NULL) - Ttime); + printf("( %5dKbytes/s, %dX)", i, i / 150); + } + putchar(13); + fflush(stdout); +#endif + + incSector(); + + p++; + per = ((float)p / s); + gtk_progress_bar_update(GTK_PROGRESS_BAR(Progress), per); + while (gtk_events_pending()) gtk_main_iteration(); + if (stop) break; + } + + Ttime = time(NULL) - Ttime; + Tm = gmtime(&Ttime); + printf("\nTotal Time used: %d:%d:%d\n", Tm->tm_hour, Tm->tm_min, + Tm->tm_sec); + + CDR_close(); + fclose(f); + + gtk_widget_set_sensitive(BtnCompress, TRUE); + gtk_widget_set_sensitive(BtnDecompress, TRUE); + gtk_widget_set_sensitive(BtnCreate, TRUE); + gtk_widget_set_sensitive(BtnCreateZ, TRUE); + + if (!stop) SysMessageLoc("Iso Image Created OK"); +} + +void OnCreateZ() +{ + FILE *f; + FILE *t; + struct stat buf; + struct tm *Tm; + time_t Ttime; + unsigned long ftrack, ltrack; + unsigned long p = 0, s, c = 0; + unsigned char *buffer; + unsigned char bufferz[2352]; + unsigned char start[4], end[4]; + char table[256]; + char *tmp; + int b, blocks; +#ifdef VERBOSE + unsigned long count = 0; + int i = 0; +#endif + + memset(bufferz, 0, sizeof(bufferz)); + ftrack = 1; + ltrack = CD_LEADOUT; + + tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); + strcpy(IsoFile, tmp); + + UpdZmode(); + + if (Zmode == 1) + { + blocks = 1; + if (strstr(IsoFile, ".Z") == NULL) strcat(IsoFile, ".Z"); + } + else + { + blocks = 10; + if (strstr(IsoFile, ".bz") == NULL) strcat(IsoFile, ".bz"); + } + + if (stat(IsoFile, &buf) == 0) + { + printf("File %s Already exists\n", IsoFile); + return; + } + + strcpy(table, IsoFile); + if (Zmode == 1) + strcat(table, ".table"); + else + strcat(table, ".index"); + + t = fopen(table, "wb"); + + if (t == NULL) return; + if (CDR_open() == -1) return; + + if (CDR_getTD(ftrack, start) == -1) + { + printf("Error getting TD\n"); + CDR_close(); + return; + } + + if (CDR_getTD(ltrack, end) == -1) + { + printf("Error getting TD\n"); + CDR_close(); + return; + } + + f = fopen(IsoFile, "wb"); + if (f == NULL) + { + CDR_close(); + printf("Error opening %s", IsoFile); + return; + } + + printf("Making Iso: from %2.2d:%2.2d:%2.2d to %2.2d:%2.2d:%2.2d\n", + start[0], start[1], start[2], end[0], end[1], end[2]); + + memcpy(param, start, 3); + + time(&Ttime); + + stop = 0; + s = MSF2SECT(end[0], end[1], end[2]) / blocks; + gtk_widget_set_sensitive(BtnCompress, FALSE); + gtk_widget_set_sensitive(BtnDecompress, FALSE); + gtk_widget_set_sensitive(BtnCreate, FALSE); + gtk_widget_set_sensitive(BtnCreateZ, FALSE); + + for (;;) /* loop until end */ + { + unsigned long size; + unsigned char Zbuf[CD_FRAMESIZE_RAW * 10 * 2]; + float per; + + for (b = 0; b < blocks; b++) + { + if ((param[0] == end[0]) & (param[1] == end[1]) & (param[2] == end[2])) + break; + + buffer = CDR_readTrack(param); + if (buffer == NULL) + { + int i; + + for (i = 0; i < 10; i++) + { + buffer = CDR_readTrack(param); + if (buffer != NULL) break; + } + + if (buffer == NULL) + { + printf("Error Reading %2d:%2d:%2d\n", param[0], param[1], param[2]); + buffer = bufferz; + buffer[12] = param[0]; + buffer[13] = param[1]; + buffer[14] = param[2]; + buffer[15] = 0x2; + } + } + memcpy(cdbuffer + b * CD_FRAMESIZE_RAW, buffer, CD_FRAMESIZE_RAW); + + incSector(); + } + if ((param[0] == end[0]) & (param[1] == end[1]) & (param[2] == end[2])) + break; + + size = CD_FRAMESIZE_RAW * blocks * 2; + if (Zmode == 1) + compress(Zbuf, &size, cdbuffer, CD_FRAMESIZE_RAW); + else + BZ2_bzBuffToBuffCompress(Zbuf, (unsigned int*)&size, cdbuffer, CD_FRAMESIZE_RAW * 10, 1, 0, 30); + + fwrite(&c, 1, 4, t); + if (Zmode == 1) fwrite(&size, 1, 2, t); + + fwrite(Zbuf, 1, size, f); + + c += size; +#ifdef VERBOSE + count += CD_FRAMESIZE_RAW * blocks; + + printf("reading %2d:%2d:%2d ", param[0], param[1], param[2]); + if ((time(NULL) - Ttime) != 0) + { + i = (count / 1024) / (time(NULL) - Ttime); + printf("( %5dKbytes/s, %dX)", i, i / 150); + } + putchar(13); + fflush(stdout); +#endif + + p++; + per = ((float)p / s); + + gtk_progress_bar_update(GTK_PROGRESS_BAR(Progress), per); + while (gtk_events_pending()) gtk_main_iteration(); + + if (stop) break; + } + if (Zmode == 2) fwrite(&c, 1, 4, f); + + if (!stop) gtk_entry_set_text(GTK_ENTRY(Edit), IsoFile); + + Ttime = time(NULL) - Ttime; + Tm = gmtime(&Ttime); + printf("\nTotal Time used: %d:%d:%d\n", Tm->tm_hour, Tm->tm_min, + Tm->tm_sec); + + CDR_close(); + fclose(f); + fclose(t); + + gtk_widget_set_sensitive(BtnCompress, TRUE); + gtk_widget_set_sensitive(BtnDecompress, TRUE); + gtk_widget_set_sensitive(BtnCreate, TRUE); + gtk_widget_set_sensitive(BtnCreateZ, TRUE); + + if (!stop) SysMessageLoc("Compressed Iso Image Created OK"); +} + +long CDRconfigure(void) +{ + int i; + + LoadConf(); + + ConfDlg = create_Config(); + + Edit = lookup_widget(ConfDlg, "GtkEntry_Iso"); + gtk_entry_set_text(GTK_ENTRY(Edit), IsoFile); + CdEdit = lookup_widget(ConfDlg, "GtkEntry_CdDev"); + gtk_entry_set_text(GTK_ENTRY(CdEdit), CdDev); + + Progress = lookup_widget(ConfDlg, "GtkProgressBar_Progress"); + + BtnCompress = lookup_widget(ConfDlg, "GtkButton_Compress"); + BtnDecompress = lookup_widget(ConfDlg, "GtkButton_Decompress"); + BtnCreate = lookup_widget(ConfDlg, "GtkButton_Create"); + BtnCreateZ = lookup_widget(ConfDlg, "GtkButton_CreateZ"); + + methodlist = NULL; + for (i = 0; i < 2; i++) + methodlist = g_list_append(methodlist, methods[i]); + + Method = lookup_widget(ConfDlg, "GtkCombo_Method"); + gtk_combo_set_popdown_strings(GTK_COMBO(Method), methodlist); + if (strstr(IsoFile, ".Z") != NULL) + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(Method)->entry), methods[0]); + else + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(Method)->entry), methods[1]); + + set_checked(ConfDlg, "checkBlockDump", (BlockDump == 1)); + + gtk_widget_show_all(ConfDlg); + gtk_main(); + + return 0; +} + +GtkWidget *AboutDlg; + +void OnAboutOk(GtkMenuItem * menuitem, gpointer userdata) +{ + gtk_widget_hide(AboutDlg); + gtk_main_quit(); +} + +void CDRabout(void) +{ + GtkWidget *Label; + GtkWidget *Ok; + GtkWidget *Box, *BBox; + char AboutText[255]; + + sprintf(AboutText, "%s %d.%d\n", LibName, revision, build); + + AboutDlg = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_set_usize(AboutDlg, 260, 80); + gtk_window_set_title(GTK_WINDOW(AboutDlg), "CDVD About Dialog"); + gtk_window_set_position(GTK_WINDOW(AboutDlg), GTK_WIN_POS_CENTER); + gtk_container_set_border_width(GTK_CONTAINER(AboutDlg), 10); + + Box = gtk_vbox_new(0, 0); + gtk_container_add(GTK_CONTAINER(AboutDlg), Box); + gtk_widget_show(Box); + + Label = gtk_label_new(AboutText); + gtk_box_pack_start(GTK_BOX(Box), Label, FALSE, FALSE, 0); + gtk_widget_show(Label); + + BBox = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), BBox, FALSE, FALSE, 0); + gtk_widget_show(BBox); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect(GTK_OBJECT(Ok), "clicked", + GTK_SIGNAL_FUNC(OnAboutOk), NULL); + gtk_container_add(GTK_CONTAINER(BBox), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(AboutDlg); + gtk_main(); +} + +int main(int argc, char *argv[]) +{ + if (argc < 2) return 0; + + gtk_init(NULL, NULL); + + if (!strcmp(argv[1], "open")) + _CDRopen(); + else if (!strcmp(argv[1], "configure")) + CDRconfigure(); + else if (!strcmp(argv[1], "message")) + { + if (argc > 2) SysMessageLoc(argv[2]); + } + else + CDRabout(); + + return 0; +} + + diff --git a/plugins/CDVDiso/src/Win32/Config.c b/plugins/CDVDiso/src/Win32/Config.c index 83976b0980..1799df5cf4 100644 --- a/plugins/CDVDiso/src/Win32/Config.c +++ b/plugins/CDVDiso/src/Win32/Config.c @@ -1,51 +1,51 @@ -#include -#include - -#include "../CDVDiso.h" - -#define GetKeyV(name, var, s, t) \ - size = s; type = t; \ - RegQueryValueEx(myKey, name, 0, &type, (LPBYTE) var, &size); - -#define GetKeyVdw(name, var) \ - GetKeyV(name, var, 4, REG_DWORD); - -#define SetKeyV(name, var, s, t) \ - RegSetValueEx(myKey, name, 0, t, (LPBYTE) var, s); - -#define SetKeyVdw(name, var) \ - SetKeyV(name, var, 4, REG_DWORD); - -void SaveConf() -{ - HKEY myKey; - DWORD myDisp; - - RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\PS2Eplugin\\CDVD\\CDVDiso", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &myKey, &myDisp); - - SetKeyV("IsoFile", IsoFile, sizeof(IsoFile), REG_BINARY); - SetKeyV("CurrentWorkingFolder", IsoCWD, sizeof(IsoCWD), REG_BINARY); - SetKeyVdw("BlockDump", &BlockDump); - - RegCloseKey(myKey); -} - -void LoadConf() -{ - HKEY myKey; - DWORD type, size; - - memset(IsoFile, 0, sizeof(IsoFile)); - - if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\PS2Eplugin\\CDVD\\CDVDiso", 0, KEY_ALL_ACCESS, &myKey) != ERROR_SUCCESS) - { - SaveConf(); - return; - } - - GetKeyV("IsoFile", IsoFile, sizeof(IsoFile), REG_BINARY); - GetKeyV("CurrentWorkingFolder", IsoCWD, sizeof(IsoCWD), REG_BINARY); - GetKeyVdw("BlockDump", &BlockDump); - - RegCloseKey(myKey); -} +#include +#include + +#include "../CDVDiso.h" + +#define GetKeyV(name, var, s, t) \ + size = s; type = t; \ + RegQueryValueEx(myKey, name, 0, &type, (LPBYTE) var, &size); + +#define GetKeyVdw(name, var) \ + GetKeyV(name, var, 4, REG_DWORD); + +#define SetKeyV(name, var, s, t) \ + RegSetValueEx(myKey, name, 0, t, (LPBYTE) var, s); + +#define SetKeyVdw(name, var) \ + SetKeyV(name, var, 4, REG_DWORD); + +void SaveConf() +{ + HKEY myKey; + DWORD myDisp; + + RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\PS2Eplugin\\CDVD\\CDVDiso", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &myKey, &myDisp); + + SetKeyV("IsoFile", IsoFile, sizeof(IsoFile), REG_BINARY); + SetKeyV("CurrentWorkingFolder", IsoCWD, sizeof(IsoCWD), REG_BINARY); + SetKeyVdw("BlockDump", &BlockDump); + + RegCloseKey(myKey); +} + +void LoadConf() +{ + HKEY myKey; + DWORD type, size; + + memset(IsoFile, 0, sizeof(IsoFile)); + + if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\PS2Eplugin\\CDVD\\CDVDiso", 0, KEY_ALL_ACCESS, &myKey) != ERROR_SUCCESS) + { + SaveConf(); + return; + } + + GetKeyV("IsoFile", IsoFile, sizeof(IsoFile), REG_BINARY); + GetKeyV("CurrentWorkingFolder", IsoCWD, sizeof(IsoCWD), REG_BINARY); + GetKeyVdw("BlockDump", &BlockDump); + + RegCloseKey(myKey); +} diff --git a/plugins/CDVDiso/src/Win32/Config.h b/plugins/CDVDiso/src/Win32/Config.h index 0ce9be191d..9039132ce7 100644 --- a/plugins/CDVDiso/src/Win32/Config.h +++ b/plugins/CDVDiso/src/Win32/Config.h @@ -1,3 +1,3 @@ -void SaveConf(); -void LoadConf(); - +void SaveConf(); +void LoadConf(); + diff --git a/plugins/CDVDiso/src/Win32/Makefile b/plugins/CDVDiso/src/Win32/Makefile index 483698ad3a..a8282185af 100644 --- a/plugins/CDVDiso/src/Win32/Makefile +++ b/plugins/CDVDiso/src/Win32/Makefile @@ -1,57 +1,57 @@ -# -# Makefile for MINGW32 -# - - -all: cdvdiso - -PLUGIN = CDVDiso.dll - -CC = gcc -NASM = nasmw -RM = rm -f -AR = ar -STRIP = strip -RC = windres - -OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing -FLAGS = -D__WIN32__ -D__MINGW32__ # -DENABLE_NLS -DPACKAGE=\"pcsx2\" -RC1FLAGS = -d__MINGW32__ -LIBS = -L./ -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 #-lintl -RESOBJ = cdvdiso.o - -OBJS = ../CDVDiso.o ../libiso.o -OBJS+= Config.o Win32.o ${RESOBJ} -OBJS+= ../zlib/adler32.o ../zlib/compress.o ../zlib/crc32.o ../zlib/gzio.o ../zlib/uncompr.o ../zlib/deflate.o ../zlib/trees.o \ - ../zlib/zutil.o ../zlib/inflate.o ../zlib/infback.o ../zlib/inftrees.o ../zlib/inffast.o -OBJS+= ../bzip2/blocksort.o ../bzip2/bzlib.o \ - ../bzip2/compress.o ../bzip2/crctable.o \ - ../bzip2/decompress.o ../bzip2/huffman.o \ - ../bzip2/randtable.o - -DEPS:= $(OBJS:.o=.d) - -CFLAGS = -Wall ${OPTIMIZE} -I. -I.. -I/usr/local/include -I../zlib -I../bzip2 ${FLAGS} - -cdvdiso: ${OBJS} - dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} ${LIBS} -# ${CC} -shared -Wl,--kill-at,--output-def,plugin.def ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} - ${STRIP} ${PLUGIN} - -.PHONY: clean cdvdiso - -clean: - ${RM} ${OBJS} ${DEPS} ${PCSX2} - -%.o: %.asm - ${NASM} ${ASMFLAGS} -o $@ $< - -%.o: %.c - ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) - -${RESOBJ}: CDVDiso.rc - ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< - --include ${DEPS} - +# +# Makefile for MINGW32 +# + + +all: cdvdiso + +PLUGIN = CDVDiso.dll + +CC = gcc +NASM = nasmw +RM = rm -f +AR = ar +STRIP = strip +RC = windres + +OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing +FLAGS = -D__WIN32__ -D__MINGW32__ # -DENABLE_NLS -DPACKAGE=\"pcsx2\" +RC1FLAGS = -d__MINGW32__ +LIBS = -L./ -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 #-lintl +RESOBJ = cdvdiso.o + +OBJS = ../CDVDiso.o ../libiso.o +OBJS+= Config.o Win32.o ${RESOBJ} +OBJS+= ../zlib/adler32.o ../zlib/compress.o ../zlib/crc32.o ../zlib/gzio.o ../zlib/uncompr.o ../zlib/deflate.o ../zlib/trees.o \ + ../zlib/zutil.o ../zlib/inflate.o ../zlib/infback.o ../zlib/inftrees.o ../zlib/inffast.o +OBJS+= ../bzip2/blocksort.o ../bzip2/bzlib.o \ + ../bzip2/compress.o ../bzip2/crctable.o \ + ../bzip2/decompress.o ../bzip2/huffman.o \ + ../bzip2/randtable.o + +DEPS:= $(OBJS:.o=.d) + +CFLAGS = -Wall ${OPTIMIZE} -I. -I.. -I/usr/local/include -I../zlib -I../bzip2 ${FLAGS} + +cdvdiso: ${OBJS} + dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} ${LIBS} +# ${CC} -shared -Wl,--kill-at,--output-def,plugin.def ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + ${STRIP} ${PLUGIN} + +.PHONY: clean cdvdiso + +clean: + ${RM} ${OBJS} ${DEPS} ${PCSX2} + +%.o: %.asm + ${NASM} ${ASMFLAGS} -o $@ $< + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +${RESOBJ}: CDVDiso.rc + ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< + +-include ${DEPS} + \ No newline at end of file diff --git a/plugins/CDVDiso/src/Win32/Win32.c b/plugins/CDVDiso/src/Win32/Win32.c index b443e9be81..35e3f5b88f 100644 --- a/plugins/CDVDiso/src/Win32/Win32.c +++ b/plugins/CDVDiso/src/Win32/Win32.c @@ -1,398 +1,398 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "zlib/zlib.h" - - -#include "Config.h" -#include "CDVDiso.h" -#include "resource.h" - -HINSTANCE hInst; -#define MAXFILENAME 256 - -u8 Zbuf[2352 * 10 * 2]; -HWND hDlg; -HWND hProgress; -HWND hIsoFile; -HWND hMethod; -HWND hBlockDump; -int stop; - -void SysMessage(char *fmt, ...) -{ - va_list list; - char tmp[512]; - - va_start(list, fmt); - vsprintf(tmp, fmt, list); - va_end(list); - MessageBox(0, tmp, "CDVDiso Msg", 0); -} - -int _GetFile(char *out) -{ - OPENFILENAME ofn; - char szFileName[MAXFILENAME]; - char szFileTitle[MAXFILENAME]; - - memset(&szFileName, 0, sizeof(szFileName)); - memset(&szFileTitle, 0, sizeof(szFileTitle)); - - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = GetActiveWindow(); - ofn.lpstrFilter = - "Supported Formats\0*.bin;*.iso;*.img;*.nrg;*.mdf;*.Z;*.Z2;*.BZ2;*.dump\0" - "Cd Iso Format (*.bin;*.iso;*.img;*.nrg;*.mdf)\0" - "*.bin;*.iso;*.img;*.nrg;*.mdf\0" - "Compressed Z Iso Format (*.Z;*.Z2)\0" - "*.Z;*.Z2\0Compressed BZ Iso Format (*.BZ2)\0" - "*.BZ2\0Block Dumps (*.dump)\0*.dump\0All Files\0*.*\0"; - - ofn.lpstrCustomFilter = NULL; - ofn.nMaxCustFilter = 0; - ofn.nFilterIndex = 1; - ofn.lpstrFile = szFileName; - ofn.nMaxFile = MAXFILENAME; - ofn.lpstrInitialDir = (IsoCWD[0] == 0) ? NULL : IsoCWD; - ofn.lpstrFileTitle = szFileTitle; - ofn.nMaxFileTitle = MAXFILENAME; - ofn.lpstrTitle = NULL; - ofn.lpstrDefExt = NULL; - ofn.Flags = OFN_HIDEREADONLY; - - if (GetOpenFileName((LPOPENFILENAME)&ofn)) - { - strcpy(out, szFileName); - return 1; - } - - return 0; -} - -int _OpenFile(int saveConf) -{ - - int retval = 0; - - // for saving the pcsx2 current working directory; - char* cwd_pcsx2 = _getcwd(NULL, MAXFILENAME); - - if (IsoCWD[0] != 0) - _chdir(IsoCWD); - - if (_GetFile(IsoFile) == 1) - { - // Save the user's new cwd: - if (_getcwd(IsoCWD, MAXFILENAME) == NULL) - IsoCWD[0] = 0; - - if (saveConf) - SaveConf(); - - retval = 1; - } - - // Restore Pcsx2's path. - if (cwd_pcsx2 != NULL) - { - _chdir(cwd_pcsx2); - free(cwd_pcsx2); - cwd_pcsx2 = NULL; - } - return retval; -} - -void CfgOpenFile() -{ - _OpenFile(TRUE); -} - -void UpdZmode() -{ - if (ComboBox_GetCurSel(hMethod) == 0) - { - Zmode = 1; - } - else - { - Zmode = 2; - } -} - - -void SysUpdate() -{ - MSG msg; - - while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } -} - -void OnCompress() -{ - u32 lsn; - u8 cdbuff[10*2352]; - char Zfile[256]; - int ret; - isoFile *src; - isoFile *dst; - - Edit_GetText(hIsoFile, IsoFile, 256); - UpdZmode(); - - if (Zmode == 1) - { - sprintf(Zfile, "%s.Z2", IsoFile); - } - else - { - sprintf(Zfile, "%s.BZ2", IsoFile); - } - - src = isoOpen(IsoFile); - if (src == NULL) return; - if (Zmode == 1) - { - dst = isoCreate(Zfile, ISOFLAGS_Z2); - } - else - { - dst = isoCreate(Zfile, ISOFLAGS_BZ2); - } - if (dst == NULL) return; - - isoSetFormat(dst, src->blockofs, src->blocksize, src->blocks); - Button_Enable(GetDlgItem(hDlg, IDC_COMPRESSISO), FALSE); - Button_Enable(GetDlgItem(hDlg, IDC_DECOMPRESSISO), FALSE); - stop = 0; - - for (lsn = 0; lsn < src->blocks; lsn++) - { - printf("block %d ", lsn); - putchar(13); - fflush(stdout); - ret = isoReadBlock(src, cdbuff, lsn); - if (ret == -1) break; - ret = isoWriteBlock(dst, cdbuff, lsn); - if (ret == -1) break; - - SendMessage(hProgress, PBM_SETPOS, (lsn * 100) / src->blocks, 0); - SysUpdate(); - if (stop) break; - } - isoClose(src); - isoClose(dst); - - if (!stop) Edit_SetText(hIsoFile, Zfile); - - Button_Enable(GetDlgItem(hDlg, IDC_COMPRESSISO), TRUE); - Button_Enable(GetDlgItem(hDlg, IDC_DECOMPRESSISO), TRUE); - - if (!stop) - { - if (ret == -1) - { - SysMessage("Error compressing iso image"); - } - else - { - SysMessage("Iso image compressed OK"); - } - } -} - -void OnDecompress() -{ - char file[256]; - u8 cdbuff[10*2352]; - u32 lsn; - isoFile *src; - isoFile *dst; - int ret; - - Edit_GetText(hIsoFile, IsoFile, 256); - - src = isoOpen(IsoFile); - if (src == NULL) return; - - strcpy(file, IsoFile); - if (src->flags & ISOFLAGS_Z) - { - file[strlen(file) - 2] = 0; - } - else - if (src->flags & ISOFLAGS_Z2) - { - file[strlen(file) - 3] = 0; - } - else - if (src->flags & ISOFLAGS_BZ2) - { - file[strlen(file) - 3] = 0; - } - else - { - SysMessage("%s is not a compressed image", IsoFile); - return; - } - - dst = isoCreate(file, 0); - if (dst == NULL) return; - - isoSetFormat(dst, src->blockofs, src->blocksize, src->blocks); - Button_Enable(GetDlgItem(hDlg, IDC_COMPRESSISO), FALSE); - Button_Enable(GetDlgItem(hDlg, IDC_DECOMPRESSISO), FALSE); - stop = 0; - - for (lsn = 0; lsn < src->blocks; lsn++) - { - printf("block %d ", lsn); - putchar(13); - fflush(stdout); - ret = isoReadBlock(src, cdbuff, lsn); - if (ret == -1) break; - ret = isoWriteBlock(dst, cdbuff, lsn); - if (ret == -1) break; - - SendMessage(hProgress, PBM_SETPOS, (lsn * 100) / src->blocks, 0); - SysUpdate(); - if (stop) break; - } - if (!stop) Edit_SetText(hIsoFile, file); - - isoClose(src); - isoClose(dst); - - Button_Enable(GetDlgItem(hDlg, IDC_COMPRESSISO), TRUE); - Button_Enable(GetDlgItem(hDlg, IDC_DECOMPRESSISO), TRUE); - - if (!stop) - { - if (ret == -1) - { - SysMessage("Error decompressing iso image"); - } - else - { - SysMessage("Iso image decompressed OK"); - } - } -} - -BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - int i; - - switch (uMsg) - { - case WM_INITDIALOG: - hDlg = hW; - LoadConf(); - - hProgress = GetDlgItem(hW, IDC_PROGRESS); - hIsoFile = GetDlgItem(hW, IDC_ISOFILE); - hMethod = GetDlgItem(hW, IDC_METHOD); - hBlockDump = GetDlgItem(hW, IDC_BLOCKDUMP); - - for (i = 0; methods[i] != NULL; i++) - { - ComboBox_AddString(hMethod, methods[i]); - } - - Edit_SetText(hIsoFile, IsoFile); - ComboBox_SetCurSel(hMethod, 0); - /* if (strstr(IsoFile, ".Z") != NULL) - ComboBox_SetCurSel(hMethod, 1); - else ComboBox_SetCurSel(hMethod, 0);*/ - Button_SetCheck(hBlockDump, BlockDump); - - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDC_SELECTISO: - if (_OpenFile(FALSE) == 1) - Edit_SetText(hIsoFile, IsoFile); - return TRUE; - - case IDC_COMPRESSISO: - OnCompress(); - return TRUE; - - case IDC_DECOMPRESSISO: - OnDecompress(); - return TRUE; - - case IDC_STOP: - stop = 1; - return TRUE; - - case IDCANCEL: - EndDialog(hW, TRUE); - return TRUE; - - case IDOK: - Edit_GetText(hIsoFile, IsoFile, 256); - BlockDump = Button_GetCheck(hBlockDump); - - SaveConf(); - EndDialog(hW, FALSE); - return TRUE; - } - } - return FALSE; -} - -EXPORT_C(void) CDVDconfigure() -{ - DialogBox(hInst, - MAKEINTRESOURCE(IDD_CONFIG), - GetActiveWindow(), - (DLGPROC)ConfigureDlgProc); -} - -BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_INITDIALOG: - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDOK: - EndDialog(hW, TRUE); - return FALSE; - } - } - return FALSE; -} - -EXPORT_C(void) CDVDabout() -{ - DialogBox(hInst, - MAKEINTRESOURCE(IDD_ABOUT), - GetActiveWindow(), - (DLGPROC)AboutDlgProc); -} - -BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT - DWORD dwReason, - LPVOID lpReserved) -{ - hInst = (HINSTANCE)hModule; - return TRUE; // very quick :) -} - +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zlib/zlib.h" + + +#include "Config.h" +#include "CDVDiso.h" +#include "resource.h" + +HINSTANCE hInst; +#define MAXFILENAME 256 + +u8 Zbuf[2352 * 10 * 2]; +HWND hDlg; +HWND hProgress; +HWND hIsoFile; +HWND hMethod; +HWND hBlockDump; +int stop; + +void SysMessage(char *fmt, ...) +{ + va_list list; + char tmp[512]; + + va_start(list, fmt); + vsprintf(tmp, fmt, list); + va_end(list); + MessageBox(0, tmp, "CDVDiso Msg", 0); +} + +int _GetFile(char *out) +{ + OPENFILENAME ofn; + char szFileName[MAXFILENAME]; + char szFileTitle[MAXFILENAME]; + + memset(&szFileName, 0, sizeof(szFileName)); + memset(&szFileTitle, 0, sizeof(szFileTitle)); + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = GetActiveWindow(); + ofn.lpstrFilter = + "Supported Formats\0*.bin;*.iso;*.img;*.nrg;*.mdf;*.Z;*.Z2;*.BZ2;*.dump\0" + "Cd Iso Format (*.bin;*.iso;*.img;*.nrg;*.mdf)\0" + "*.bin;*.iso;*.img;*.nrg;*.mdf\0" + "Compressed Z Iso Format (*.Z;*.Z2)\0" + "*.Z;*.Z2\0Compressed BZ Iso Format (*.BZ2)\0" + "*.BZ2\0Block Dumps (*.dump)\0*.dump\0All Files\0*.*\0"; + + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 1; + ofn.lpstrFile = szFileName; + ofn.nMaxFile = MAXFILENAME; + ofn.lpstrInitialDir = (IsoCWD[0] == 0) ? NULL : IsoCWD; + ofn.lpstrFileTitle = szFileTitle; + ofn.nMaxFileTitle = MAXFILENAME; + ofn.lpstrTitle = NULL; + ofn.lpstrDefExt = NULL; + ofn.Flags = OFN_HIDEREADONLY; + + if (GetOpenFileName((LPOPENFILENAME)&ofn)) + { + strcpy(out, szFileName); + return 1; + } + + return 0; +} + +int _OpenFile(int saveConf) +{ + + int retval = 0; + + // for saving the pcsx2 current working directory; + char* cwd_pcsx2 = _getcwd(NULL, MAXFILENAME); + + if (IsoCWD[0] != 0) + _chdir(IsoCWD); + + if (_GetFile(IsoFile) == 1) + { + // Save the user's new cwd: + if (_getcwd(IsoCWD, MAXFILENAME) == NULL) + IsoCWD[0] = 0; + + if (saveConf) + SaveConf(); + + retval = 1; + } + + // Restore Pcsx2's path. + if (cwd_pcsx2 != NULL) + { + _chdir(cwd_pcsx2); + free(cwd_pcsx2); + cwd_pcsx2 = NULL; + } + return retval; +} + +void CfgOpenFile() +{ + _OpenFile(TRUE); +} + +void UpdZmode() +{ + if (ComboBox_GetCurSel(hMethod) == 0) + { + Zmode = 1; + } + else + { + Zmode = 2; + } +} + + +void SysUpdate() +{ + MSG msg; + + while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +void OnCompress() +{ + u32 lsn; + u8 cdbuff[10*2352]; + char Zfile[256]; + int ret; + isoFile *src; + isoFile *dst; + + Edit_GetText(hIsoFile, IsoFile, 256); + UpdZmode(); + + if (Zmode == 1) + { + sprintf(Zfile, "%s.Z2", IsoFile); + } + else + { + sprintf(Zfile, "%s.BZ2", IsoFile); + } + + src = isoOpen(IsoFile); + if (src == NULL) return; + if (Zmode == 1) + { + dst = isoCreate(Zfile, ISOFLAGS_Z2); + } + else + { + dst = isoCreate(Zfile, ISOFLAGS_BZ2); + } + if (dst == NULL) return; + + isoSetFormat(dst, src->blockofs, src->blocksize, src->blocks); + Button_Enable(GetDlgItem(hDlg, IDC_COMPRESSISO), FALSE); + Button_Enable(GetDlgItem(hDlg, IDC_DECOMPRESSISO), FALSE); + stop = 0; + + for (lsn = 0; lsn < src->blocks; lsn++) + { + printf("block %d ", lsn); + putchar(13); + fflush(stdout); + ret = isoReadBlock(src, cdbuff, lsn); + if (ret == -1) break; + ret = isoWriteBlock(dst, cdbuff, lsn); + if (ret == -1) break; + + SendMessage(hProgress, PBM_SETPOS, (lsn * 100) / src->blocks, 0); + SysUpdate(); + if (stop) break; + } + isoClose(src); + isoClose(dst); + + if (!stop) Edit_SetText(hIsoFile, Zfile); + + Button_Enable(GetDlgItem(hDlg, IDC_COMPRESSISO), TRUE); + Button_Enable(GetDlgItem(hDlg, IDC_DECOMPRESSISO), TRUE); + + if (!stop) + { + if (ret == -1) + { + SysMessage("Error compressing iso image"); + } + else + { + SysMessage("Iso image compressed OK"); + } + } +} + +void OnDecompress() +{ + char file[256]; + u8 cdbuff[10*2352]; + u32 lsn; + isoFile *src; + isoFile *dst; + int ret; + + Edit_GetText(hIsoFile, IsoFile, 256); + + src = isoOpen(IsoFile); + if (src == NULL) return; + + strcpy(file, IsoFile); + if (src->flags & ISOFLAGS_Z) + { + file[strlen(file) - 2] = 0; + } + else + if (src->flags & ISOFLAGS_Z2) + { + file[strlen(file) - 3] = 0; + } + else + if (src->flags & ISOFLAGS_BZ2) + { + file[strlen(file) - 3] = 0; + } + else + { + SysMessage("%s is not a compressed image", IsoFile); + return; + } + + dst = isoCreate(file, 0); + if (dst == NULL) return; + + isoSetFormat(dst, src->blockofs, src->blocksize, src->blocks); + Button_Enable(GetDlgItem(hDlg, IDC_COMPRESSISO), FALSE); + Button_Enable(GetDlgItem(hDlg, IDC_DECOMPRESSISO), FALSE); + stop = 0; + + for (lsn = 0; lsn < src->blocks; lsn++) + { + printf("block %d ", lsn); + putchar(13); + fflush(stdout); + ret = isoReadBlock(src, cdbuff, lsn); + if (ret == -1) break; + ret = isoWriteBlock(dst, cdbuff, lsn); + if (ret == -1) break; + + SendMessage(hProgress, PBM_SETPOS, (lsn * 100) / src->blocks, 0); + SysUpdate(); + if (stop) break; + } + if (!stop) Edit_SetText(hIsoFile, file); + + isoClose(src); + isoClose(dst); + + Button_Enable(GetDlgItem(hDlg, IDC_COMPRESSISO), TRUE); + Button_Enable(GetDlgItem(hDlg, IDC_DECOMPRESSISO), TRUE); + + if (!stop) + { + if (ret == -1) + { + SysMessage("Error decompressing iso image"); + } + else + { + SysMessage("Iso image decompressed OK"); + } + } +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + int i; + + switch (uMsg) + { + case WM_INITDIALOG: + hDlg = hW; + LoadConf(); + + hProgress = GetDlgItem(hW, IDC_PROGRESS); + hIsoFile = GetDlgItem(hW, IDC_ISOFILE); + hMethod = GetDlgItem(hW, IDC_METHOD); + hBlockDump = GetDlgItem(hW, IDC_BLOCKDUMP); + + for (i = 0; methods[i] != NULL; i++) + { + ComboBox_AddString(hMethod, methods[i]); + } + + Edit_SetText(hIsoFile, IsoFile); + ComboBox_SetCurSel(hMethod, 0); + /* if (strstr(IsoFile, ".Z") != NULL) + ComboBox_SetCurSel(hMethod, 1); + else ComboBox_SetCurSel(hMethod, 0);*/ + Button_SetCheck(hBlockDump, BlockDump); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_SELECTISO: + if (_OpenFile(FALSE) == 1) + Edit_SetText(hIsoFile, IsoFile); + return TRUE; + + case IDC_COMPRESSISO: + OnCompress(); + return TRUE; + + case IDC_DECOMPRESSISO: + OnDecompress(); + return TRUE; + + case IDC_STOP: + stop = 1; + return TRUE; + + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + + case IDOK: + Edit_GetText(hIsoFile, IsoFile, 256); + BlockDump = Button_GetCheck(hBlockDump); + + SaveConf(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +EXPORT_C(void) CDVDconfigure() +{ + DialogBox(hInst, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + EndDialog(hW, TRUE); + return FALSE; + } + } + return FALSE; +} + +EXPORT_C(void) CDVDabout() +{ + DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc); +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) +{ + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + diff --git a/plugins/CDVDiso/src/Win32/afxresmw.h b/plugins/CDVDiso/src/Win32/afxresmw.h index 8a4b9df35b..99eace37c4 100644 --- a/plugins/CDVDiso/src/Win32/afxresmw.h +++ b/plugins/CDVDiso/src/Win32/afxresmw.h @@ -1,5 +1,5 @@ - -#include -#include - -#define IDC_STATIC (-1) + +#include +#include + +#define IDC_STATIC (-1) diff --git a/plugins/CDVDiso/src/Win32/resource.h b/plugins/CDVDiso/src/Win32/resource.h index 98a1f53a0b..0aebd9c9e8 100644 --- a/plugins/CDVDiso/src/Win32/resource.h +++ b/plugins/CDVDiso/src/Win32/resource.h @@ -1,28 +1,28 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by CDVDiso.rc -// -#define IDD_CONFDLG 101 -#define IDD_CONFIG 101 -#define IDD_ABOUT 103 -#define IDC_NAME 1000 -#define IDC_ISOFILE 1000 -#define IDC_SELECTISO 1001 -#define IDC_COMPRESSISO 1002 -#define IDC_DECOMPRESSISO 1003 -#define IDC_METHOD 1004 -#define IDC_PROGRESS 1005 -#define IDC_STOP 1006 -#define IDC_BLOCKDUMP 1007 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 105 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1008 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif - +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by CDVDiso.rc +// +#define IDD_CONFDLG 101 +#define IDD_CONFIG 101 +#define IDD_ABOUT 103 +#define IDC_NAME 1000 +#define IDC_ISOFILE 1000 +#define IDC_SELECTISO 1001 +#define IDC_COMPRESSISO 1002 +#define IDC_DECOMPRESSISO 1003 +#define IDC_METHOD 1004 +#define IDC_PROGRESS 1005 +#define IDC_STOP 1006 +#define IDC_BLOCKDUMP 1007 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1008 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif + diff --git a/plugins/CDVDiso/src/Win32/vsprops/svnrev_template.h b/plugins/CDVDiso/src/Win32/vsprops/svnrev_template.h index afab6c4fd1..f2656ef1e8 100644 --- a/plugins/CDVDiso/src/Win32/vsprops/svnrev_template.h +++ b/plugins/CDVDiso/src/Win32/vsprops/svnrev_template.h @@ -1,18 +1,18 @@ -// svnrev_template.h --> svnrev.h -// -// This file acts as a template for the automatic SVN revision/version tag. -// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for -// whichever project is being compiled (as indicated by command line options -// passed to SubWCRev.exe during the project's pre-build step). -// -// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs -// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN -// installed on your system. If you do not have it installed, a generic template -// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not -// necessary. If you do not have it installed, everything will still compile -// fine except without the SVN revision tagged to the application/dll version. -// -// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org - -#define SVN_REV $WCREV$ +// svnrev_template.h --> svnrev.h +// +// This file acts as a template for the automatic SVN revision/version tag. +// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for +// whichever project is being compiled (as indicated by command line options +// passed to SubWCRev.exe during the project's pre-build step). +// +// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs +// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN +// installed on your system. If you do not have it installed, a generic template +// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not +// necessary. If you do not have it installed, everything will still compile +// fine except without the SVN revision tagged to the application/dll version. +// +// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV $WCREV$ #define SVN_MODS $WCMODS?1:0$ \ No newline at end of file diff --git a/plugins/CDVDiso/src/Win32/vsprops/svnrev_unknown.h b/plugins/CDVDiso/src/Win32/vsprops/svnrev_unknown.h index a2a3703186..4872e23b20 100644 --- a/plugins/CDVDiso/src/Win32/vsprops/svnrev_unknown.h +++ b/plugins/CDVDiso/src/Win32/vsprops/svnrev_unknown.h @@ -1,23 +1,23 @@ -// svnrev_genric.h --> svnrev.h -// -// This file acts as a placebo for people who do not have TortoiseSVN installed. -// It provides "empty" revision information to the Pcsx2 Playground projects in -// the absence of real revisions derived from the repository being built. -// -// This file does not affect application/dll builds in any significant manner, -// other than the lack of automatic revision tags inserted into the app (which -// is very convenient but hardly necessary). -// -// See svn_template.h for more information on how the process of revision -// templating works. -// -// If you would like to enable automatic revisin tagging, TortoiseSVN can be -// downloaded from http://tortoisesvn.tigris.org - -#define SVN_REV_UNKNOWN - -// The following defines are included so that code will still compile even if it -// doesn't check for the SVN_REV_UNKNOWN define. - -#define SVN_REV 0 +// svnrev_genric.h --> svnrev.h +// +// This file acts as a placebo for people who do not have TortoiseSVN installed. +// It provides "empty" revision information to the Pcsx2 Playground projects in +// the absence of real revisions derived from the repository being built. +// +// This file does not affect application/dll builds in any significant manner, +// other than the lack of automatic revision tags inserted into the app (which +// is very convenient but hardly necessary). +// +// See svn_template.h for more information on how the process of revision +// templating works. +// +// If you would like to enable automatic revisin tagging, TortoiseSVN can be +// downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV_UNKNOWN + +// The following defines are included so that code will still compile even if it +// doesn't check for the SVN_REV_UNKNOWN define. + +#define SVN_REV 0 #define SVN_MODS "" \ No newline at end of file diff --git a/plugins/CDVDiso/src/common/PS2Edefs.h b/plugins/CDVDiso/src/common/PS2Edefs.h index 1f65fc02b9..49b16e16d5 100644 --- a/plugins/CDVDiso/src/common/PS2Edefs.h +++ b/plugins/CDVDiso/src/common/PS2Edefs.h @@ -1,885 +1,885 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef __PS2EDEFS_H__ -#define __PS2EDEFS_H__ - -/* - * PS2E Definitions v0.6.2 (beta) - * - * Author: linuzappz@hotmail.com - * shadowpcsx2@yahoo.gr - * florinsasu@hotmail.com - */ - -/* - Notes: - * Since this is still beta things may change. - - * OSflags: - __LINUX__ (linux OS) - _WIN32 (win32 OS) - - * common return values (for ie. GSinit): - 0 - success - -1 - error - - * reserved keys: - F1 to F10 are reserved for the emulator - - * plugins should NOT change the current - working directory. - (on win32, add flag OFN_NOCHANGEDIR for - GetOpenFileName) - -*/ - -#include "PS2Etypes.h" - - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ - defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ - defined(USBdefs) || defined(FWdefs) -#define COMMONdefs -#endif - -// PS2EgetLibType returns (may be OR'd) -#define PS2E_LT_GS 0x01 -#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- -#define PS2E_LT_SPU2 0x04 -#define PS2E_LT_CDVD 0x08 -#define PS2E_LT_DEV9 0x10 -#define PS2E_LT_USB 0x20 -#define PS2E_LT_FW 0x40 -#define PS2E_LT_SIO 0x80 - -// PS2EgetLibVersion2 (high 16 bits) -#define PS2E_GS_VERSION 0x0006 -#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- -#define PS2E_SPU2_VERSION 0x0005 -#define PS2E_CDVD_VERSION 0x0005 -#define PS2E_DEV9_VERSION 0x0003 -#define PS2E_USB_VERSION 0x0003 -#define PS2E_FW_VERSION 0x0002 -#define PS2E_SIO_VERSION 0x0001 -#ifdef COMMONdefs - -u32 CALLBACK PS2EgetLibType(void); -u32 CALLBACK PS2EgetLibVersion2(u32 type); -char* CALLBACK PS2EgetLibName(void); - -#endif - -// key values: -/* key values must be OS dependant: - win32: the VK_XXX will be used (WinUser) - linux: the XK_XXX will be used (XFree86) -*/ - -// event values: -#define KEYPRESS 1 -#define KEYRELEASE 2 - -typedef struct _keyEvent { - u32 key; - u32 evt; -} keyEvent; - -// for 64bit compilers -typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; - -// plugin types -#define SIO_TYPE_PAD 0x00000001 -#define SIO_TYPE_MTAP 0x00000004 -#define SIO_TYPE_RM 0x00000040 -#define SIO_TYPE_MC 0x00000100 - -typedef int (CALLBACK * SIOchangeSlotCB)(int slot); - -typedef struct _cdvdSubQ { - u8 ctrl:4; // control and mode bits - u8 mode:4; // control and mode bits - u8 trackNum; // current track number (1 to 99) - u8 trackIndex; // current index within track (0 to 99) - u8 trackM; // current minute location on the disc (BCD encoded) - u8 trackS; // current sector location on the disc (BCD encoded) - u8 trackF; // current frame location on the disc (BCD encoded) - u8 pad; // unused - u8 discM; // current minute offset from first track (BCD encoded) - u8 discS; // current sector offset from first track (BCD encoded) - u8 discF; // current frame offset from first track (BCD encoded) -} cdvdSubQ; - -typedef struct _cdvdTD { // NOT bcd coded - u32 lsn; - u8 type; -} cdvdTD; - -typedef struct _cdvdTN { - u8 strack; //number of the first track (usually 1) - u8 etrack; //number of the last track -} cdvdTN; - -// CDVDreadTrack mode values: -#define CDVD_MODE_2352 0 // full 2352 bytes -#define CDVD_MODE_2340 1 // skip sync (12) bytes -#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq - -// CDVDgetDiskType returns: -#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc -#define CDVD_TYPE_DVDV 0xfe // DVD Video -#define CDVD_TYPE_CDDA 0xfd // Audio CD -#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD -#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) -#define CDVD_TYPE_PS2CD 0x12 // PS2 CD -#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) -#define CDVD_TYPE_PSCD 0x10 // PS CD -#define CDVD_TYPE_UNKNOWN 0x05 // Unknown -#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided -#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided -#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd -#define CDVD_TYPE_DETCT 0x01 // Detecting -#define CDVD_TYPE_NODISC 0x00 // No Disc - -// CDVDgetTrayStatus returns: -#define CDVD_TRAY_CLOSE 0x00 -#define CDVD_TRAY_OPEN 0x01 - -// cdvdTD.type (track types for cds) -#define CDVD_AUDIO_TRACK 0x01 -#define CDVD_MODE1_TRACK 0x41 -#define CDVD_MODE2_TRACK 0x61 - -#define CDVD_AUDIO_MASK 0x00 -#define CDVD_DATA_MASK 0x40 -// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) - -typedef void (*DEV9callback)(int cycles); -typedef int (*DEV9handler)(void); - -typedef void (*USBcallback)(int cycles); -typedef int (*USBhandler)(void); - -// freeze modes: -#define FREEZE_LOAD 0 -#define FREEZE_SAVE 1 -#define FREEZE_SIZE 2 - -typedef struct _GSdriverInfo { - char name[8]; - void *common; -} GSdriverInfo; - -#ifdef _WINDOWS_ -typedef struct _winInfo { // unsupported values must be set to zero - HWND hWnd; - HMENU hMenu; - HWND hStatusWnd; -} winInfo; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* GS plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef GSdefs - -// basic funcs - -s32 CALLBACK GSinit(); -s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); -void CALLBACK GSclose(); -void CALLBACK GSshutdown(); -void CALLBACK GSvsync(int field); -void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); -void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); -void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); -void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) -void CALLBACK GSgifSoftReset(u32 mask); -void CALLBACK GSreadFIFO(u64 *mem); -void CALLBACK GSreadFIFO2(u64 *mem, int qwc); - -// extended funcs - -// GSkeyEvent gets called when there is a keyEvent from the PAD plugin -void CALLBACK GSkeyEvent(keyEvent *ev); -void CALLBACK GSchangeSaveState(int, const char* filename); -void CALLBACK GSmakeSnapshot(char *path); -void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); -void CALLBACK GSirqCallback(void (*callback)()); -void CALLBACK GSprintf(int timeout, char *fmt, ...); -void CALLBACK GSsetBaseMem(void*); -void CALLBACK GSsetGameCRC(int crc, int gameoptions); - -// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done -void CALLBACK GSsetFrameSkip(int frameskip); - -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK GSsetupRecording(int start, void* pData); - -void CALLBACK GSreset(); -void CALLBACK GSwriteCSR(u32 value); -void CALLBACK GSgetDriverInfo(GSdriverInfo *info); -#ifdef _WIN32 -s32 CALLBACK GSsetWindowInfo(winInfo *info); -#endif -s32 CALLBACK GSfreeze(int mode, freezeData *data); -void CALLBACK GSconfigure(); -void CALLBACK GSabout(); -s32 CALLBACK GStest(); - -#endif - -/* PAD plugin API -=[ OBSOLETE ]=- */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef PADdefs - -// basic funcs - -s32 CALLBACK PADinit(u32 flags); -s32 CALLBACK PADopen(void *pDsp); -void CALLBACK PADclose(); -void CALLBACK PADshutdown(); -// PADkeyEvent is called every vsync (return NULL if no event) -keyEvent* CALLBACK PADkeyEvent(); -u8 CALLBACK PADstartPoll(int pad); -u8 CALLBACK PADpoll(u8 value); -// returns: 1 if supported pad1 -// 2 if supported pad2 -// 3 if both are supported -u32 CALLBACK PADquery(); - -// call to give a hint to the PAD plugin to query for the keyboard state. A -// good plugin will query the OS for keyboard state ONLY in this function. -// This function is necessary when multithreading because otherwise -// the PAD plugin can get into deadlocks with the thread that really owns -// the window (and input). Note that PADupdate can be called from a different -// thread than the other functions, so mutex or other multithreading primitives -// have to be added to maintain data integrity. -void CALLBACK PADupdate(int pad); - -// extended funcs - -void CALLBACK PADgsDriverInfo(GSdriverInfo *info); -void CALLBACK PADconfigure(); -void CALLBACK PADabout(); -s32 CALLBACK PADtest(); - -#endif - -/* SIO plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SIOdefs - -// basic funcs - -s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); -s32 CALLBACK SIOopen(void *pDsp); -void CALLBACK SIOclose(); -void CALLBACK SIOshutdown(); -u8 CALLBACK SIOstartPoll(u8 value); -u8 CALLBACK SIOpoll(u8 value); -// returns: SIO_TYPE_{PAD,MTAP,RM,MC} -u32 CALLBACK SIOquery(); - -// extended funcs - -void CALLBACK SIOconfigure(); -void CALLBACK SIOabout(); -s32 CALLBACK SIOtest(); - -#endif - -/* SPU2 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SPU2defs - -// basic funcs - -s32 CALLBACK SPU2init(); -s32 CALLBACK SPU2open(void *pDsp); -void CALLBACK SPU2close(); -void CALLBACK SPU2shutdown(); -void CALLBACK SPU2write(u32 mem, u16 value); -u16 CALLBACK SPU2read(u32 mem); -void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA4(); -void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); -void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); - -// all addresses passed by dma will be pointers to the array starting at baseaddr -// This function is necessary to successfully save and reload the spu2 state -void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); - -void CALLBACK SPU2interruptDMA7(); -u32 CALLBACK SPU2ReadMemAddr(int core); -void CALLBACK SPU2WriteMemAddr(int core,u32 value); -void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); - -// extended funcs -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK SPU2setupRecording(int start, void* pData); - -void CALLBACK SPU2setClockPtr(u32* ptr); -void CALLBACK SPU2setTimeStretcher(short int enable); - -void CALLBACK SPU2async(u32 cycles); -s32 CALLBACK SPU2freeze(int mode, freezeData *data); -void CALLBACK SPU2configure(); -void CALLBACK SPU2about(); -s32 CALLBACK SPU2test(); - -#endif - -/* CDVD plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef CDVDdefs - -// basic funcs - -s32 CALLBACK CDVDinit(); -s32 CALLBACK CDVDopen(const char* pTitleFilename); -void CALLBACK CDVDclose(); -void CALLBACK CDVDshutdown(); -s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); - -// return can be NULL (for async modes) -u8* CALLBACK CDVDgetBuffer(); - -s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) -s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information -s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type -s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc -s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx -s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx -s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray -s32 CALLBACK CDVDctrlTrayClose(); //close disc tray - -// extended funcs - -void CALLBACK CDVDconfigure(); -void CALLBACK CDVDabout(); -s32 CALLBACK CDVDtest(); -void CALLBACK CDVDnewDiskCB(void (*callback)()); - -#endif - -/* DEV9 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef DEV9defs - -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK DEV9init(); -s32 CALLBACK DEV9open(void *pDsp); -void CALLBACK DEV9close(); -void CALLBACK DEV9shutdown(); -u8 CALLBACK DEV9read8(u32 addr); -u16 CALLBACK DEV9read16(u32 addr); -u32 CALLBACK DEV9read32(u32 addr); -void CALLBACK DEV9write8(u32 addr, u8 value); -void CALLBACK DEV9write16(u32 addr, u16 value); -void CALLBACK DEV9write32(u32 addr, u32 value); -void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); -void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK DEV9irqCallback(DEV9callback callback); -DEV9handler CALLBACK DEV9irqHandler(void); - -// extended funcs - -s32 CALLBACK DEV9freeze(int mode, freezeData *data); -void CALLBACK DEV9configure(); -void CALLBACK DEV9about(); -s32 CALLBACK DEV9test(); - -#endif - -/* USB plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef USBdefs - -// basic funcs - -s32 CALLBACK USBinit(); -s32 CALLBACK USBopen(void *pDsp); -void CALLBACK USBclose(); -void CALLBACK USBshutdown(); -u8 CALLBACK USBread8(u32 addr); -u16 CALLBACK USBread16(u32 addr); -u32 CALLBACK USBread32(u32 addr); -void CALLBACK USBwrite8(u32 addr, u8 value); -void CALLBACK USBwrite16(u32 addr, u16 value); -void CALLBACK USBwrite32(u32 addr, u32 value); -void CALLBACK USBasync(u32 cycles); - -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK USBirqCallback(USBcallback callback); -USBhandler CALLBACK USBirqHandler(void); -void CALLBACK USBsetRAM(void *mem); - -// extended funcs - -s32 CALLBACK USBfreeze(int mode, freezeData *data); -void CALLBACK USBconfigure(); -void CALLBACK USBabout(); -s32 CALLBACK USBtest(); - -#endif - -/* FW plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef FWdefs -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK FWinit(); -s32 CALLBACK FWopen(void *pDsp); -void CALLBACK FWclose(); -void CALLBACK FWshutdown(); -u32 CALLBACK FWread32(u32 addr); -void CALLBACK FWwrite32(u32 addr, u32 value); -void CALLBACK FWirqCallback(void (*callback)()); - -// extended funcs - -s32 CALLBACK FWfreeze(int mode, freezeData *data); -void CALLBACK FWconfigure(); -void CALLBACK FWabout(); -s32 CALLBACK FWtest(); -#endif - -// might be useful for emulators -#ifdef PLUGINtypedefs - -typedef u32 (CALLBACK* _PS2EgetLibType)(void); -typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); -typedef char*(CALLBACK* _PS2EgetLibName)(void); - -// GS -// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _GSinit)(); -typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); -typedef void (CALLBACK* _GSclose)(); -typedef void (CALLBACK* _GSshutdown)(); -typedef void (CALLBACK* _GSvsync)(int field); -typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); -typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) -typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); -typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); -typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); - -typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); -typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); -typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); -typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); -typedef void (CALLBACK* _GSsetBaseMem)(void*); -typedef void (CALLBACK* _GSsetGameCRC)(int, int); -typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); -typedef int (CALLBACK* _GSsetupRecording)(int, void*); -typedef void (CALLBACK* _GSreset)(); -typedef void (CALLBACK* _GSwriteCSR)(u32 value); -typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); -#ifdef _WINDOWS_ -typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); -#endif -typedef void (CALLBACK* _GSmakeSnapshot)(const char *path); -typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); -typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _GSconfigure)(); -typedef s32 (CALLBACK* _GStest)(); -typedef void (CALLBACK* _GSabout)(); - -// PAD -typedef s32 (CALLBACK* _PADinit)(u32 flags); -typedef s32 (CALLBACK* _PADopen)(void *pDsp); -typedef void (CALLBACK* _PADclose)(); -typedef void (CALLBACK* _PADshutdown)(); -typedef keyEvent* (CALLBACK* _PADkeyEvent)(); -typedef u8 (CALLBACK* _PADstartPoll)(int pad); -typedef u8 (CALLBACK* _PADpoll)(u8 value); -typedef u32 (CALLBACK* _PADquery)(); -typedef void (CALLBACK* _PADupdate)(int pad); - -typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); -typedef void (CALLBACK* _PADconfigure)(); -typedef s32 (CALLBACK* _PADtest)(); -typedef void (CALLBACK* _PADabout)(); - -// SIO -typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); -typedef s32 (CALLBACK* _SIOopen)(void *pDsp); -typedef void (CALLBACK* _SIOclose)(); -typedef void (CALLBACK* _SIOshutdown)(); -typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); -typedef u8 (CALLBACK* _SIOpoll)(u8 value); -typedef u32 (CALLBACK* _SIOquery)(); - -typedef void (CALLBACK* _SIOconfigure)(); -typedef s32 (CALLBACK* _SIOtest)(); -typedef void (CALLBACK* _SIOabout)(); - -// SPU2 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _SPU2init)(); -typedef s32 (CALLBACK* _SPU2open)(void *pDsp); -typedef void (CALLBACK* _SPU2close)(); -typedef void (CALLBACK* _SPU2shutdown)(); -typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); -typedef u16 (CALLBACK* _SPU2read)(u32 mem); -typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA4)(); -typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); -typedef void (CALLBACK* _SPU2interruptDMA7)(); -typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); -typedef int (CALLBACK* _SPU2setupRecording)(int, void*); - -typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); -typedef void (CALLBACK* _SPU2setTimeStretcher)(short int enable); - -typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); -typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); -typedef void (CALLBACK* _SPU2async)(u32 cycles); -typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _SPU2configure)(); -typedef s32 (CALLBACK* _SPU2test)(); -typedef void (CALLBACK* _SPU2about)(); - - -// CDVD -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _CDVDinit)(); -typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); -typedef void (CALLBACK* _CDVDclose)(); -typedef void (CALLBACK* _CDVDshutdown)(); -typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); -typedef u8* (CALLBACK* _CDVDgetBuffer)(); -typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); -typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); -typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); -typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); -typedef s32 (CALLBACK* _CDVDgetDiskType)(); -typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); -typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); -typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); - -typedef void (CALLBACK* _CDVDconfigure)(); -typedef s32 (CALLBACK* _CDVDtest)(); -typedef void (CALLBACK* _CDVDabout)(); -typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); - -// DEV9 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _DEV9init)(); -typedef s32 (CALLBACK* _DEV9open)(void *pDsp); -typedef void (CALLBACK* _DEV9close)(); -typedef void (CALLBACK* _DEV9shutdown)(); -typedef u8 (CALLBACK* _DEV9read8)(u32 mem); -typedef u16 (CALLBACK* _DEV9read16)(u32 mem); -typedef u32 (CALLBACK* _DEV9read32)(u32 mem); -typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); -typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); -typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); -typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); -typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); - -typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _DEV9configure)(); -typedef s32 (CALLBACK* _DEV9test)(); -typedef void (CALLBACK* _DEV9about)(); - -// USB -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _USBinit)(); -typedef s32 (CALLBACK* _USBopen)(void *pDsp); -typedef void (CALLBACK* _USBclose)(); -typedef void (CALLBACK* _USBshutdown)(); -typedef u8 (CALLBACK* _USBread8)(u32 mem); -typedef u16 (CALLBACK* _USBread16)(u32 mem); -typedef u32 (CALLBACK* _USBread32)(u32 mem); -typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); -typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); -typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _USBasync)(u32 cycles); - - -typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); -typedef USBhandler (CALLBACK* _USBirqHandler)(void); -typedef void (CALLBACK* _USBsetRAM)(void *mem); - -typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _USBconfigure)(); -typedef s32 (CALLBACK* _USBtest)(); -typedef void (CALLBACK* _USBabout)(); - -//FW -typedef s32 (CALLBACK* _FWinit)(); -typedef s32 (CALLBACK* _FWopen)(void *pDsp); -typedef void (CALLBACK* _FWclose)(); -typedef void (CALLBACK* _FWshutdown)(); -typedef u32 (CALLBACK* _FWread32)(u32 mem); -typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); - -typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _FWconfigure)(); -typedef s32 (CALLBACK* _FWtest)(); -typedef void (CALLBACK* _FWabout)(); - -#endif - -#ifdef PLUGINfuncs - -// GS -extern _GSinit GSinit; -extern _GSopen GSopen; -extern _GSclose GSclose; -extern _GSshutdown GSshutdown; -extern _GSvsync GSvsync; -extern _GSgifTransfer1 GSgifTransfer1; -extern _GSgifTransfer2 GSgifTransfer2; -extern _GSgifTransfer3 GSgifTransfer3; -extern _GSgetLastTag GSgetLastTag; -extern _GSgifSoftReset GSgifSoftReset; -extern _GSreadFIFO GSreadFIFO; -extern _GSreadFIFO2 GSreadFIFO2; - -extern _GSkeyEvent GSkeyEvent; -extern _GSchangeSaveState GSchangeSaveState; -extern _GSmakeSnapshot GSmakeSnapshot; -extern _GSmakeSnapshot2 GSmakeSnapshot2; -extern _GSirqCallback GSirqCallback; -extern _GSprintf GSprintf; -extern _GSsetBaseMem GSsetBaseMem; -extern _GSsetGameCRC GSsetGameCRC; -extern _GSsetFrameSkip GSsetFrameSkip; -extern _GSsetupRecording GSsetupRecording; -extern _GSreset GSreset; -extern _GSwriteCSR GSwriteCSR; -extern _GSgetDriverInfo GSgetDriverInfo; -#ifdef _WINDOWS_ -extern _GSsetWindowInfo GSsetWindowInfo; -#endif -extern _GSfreeze GSfreeze; -extern _GSconfigure GSconfigure; -extern _GStest GStest; -extern _GSabout GSabout; - -// PAD1 -extern _PADinit PAD1init; -extern _PADopen PAD1open; -extern _PADclose PAD1close; -extern _PADshutdown PAD1shutdown; -extern _PADkeyEvent PAD1keyEvent; -extern _PADstartPoll PAD1startPoll; -extern _PADpoll PAD1poll; -extern _PADquery PAD1query; -extern _PADupdate PAD1update; - -extern _PADgsDriverInfo PAD1gsDriverInfo; -extern _PADconfigure PAD1configure; -extern _PADtest PAD1test; -extern _PADabout PAD1about; - -// PAD2 -extern _PADinit PAD2init; -extern _PADopen PAD2open; -extern _PADclose PAD2close; -extern _PADshutdown PAD2shutdown; -extern _PADkeyEvent PAD2keyEvent; -extern _PADstartPoll PAD2startPoll; -extern _PADpoll PAD2poll; -extern _PADquery PAD2query; -extern _PADupdate PAD2update; - -extern _PADgsDriverInfo PAD2gsDriverInfo; -extern _PADconfigure PAD2configure; -extern _PADtest PAD2test; -extern _PADabout PAD2about; - -// SIO[2] -extern _SIOinit SIOinit[2][9]; -extern _SIOopen SIOopen[2][9]; -extern _SIOclose SIOclose[2][9]; -extern _SIOshutdown SIOshutdown[2][9]; -extern _SIOstartPoll SIOstartPoll[2][9]; -extern _SIOpoll SIOpoll[2][9]; -extern _SIOquery SIOquery[2][9]; - -extern _SIOconfigure SIOconfigure[2][9]; -extern _SIOtest SIOtest[2][9]; -extern _SIOabout SIOabout[2][9]; - -// SPU2 -extern _SPU2init SPU2init; -extern _SPU2open SPU2open; -extern _SPU2close SPU2close; -extern _SPU2shutdown SPU2shutdown; -extern _SPU2write SPU2write; -extern _SPU2read SPU2read; -extern _SPU2readDMA4Mem SPU2readDMA4Mem; -extern _SPU2writeDMA4Mem SPU2writeDMA4Mem; -extern _SPU2interruptDMA4 SPU2interruptDMA4; -extern _SPU2readDMA7Mem SPU2readDMA7Mem; -extern _SPU2writeDMA7Mem SPU2writeDMA7Mem; -extern _SPU2setDMABaseAddr SPU2setDMABaseAddr; -extern _SPU2interruptDMA7 SPU2interruptDMA7; -extern _SPU2ReadMemAddr SPU2ReadMemAddr; -extern _SPU2setupRecording SPU2setupRecording; -extern _SPU2WriteMemAddr SPU2WriteMemAddr; -extern _SPU2irqCallback SPU2irqCallback; - -extern _SPU2setClockPtr SPU2setClockPtr; -extern _SPU2setTimeStretcher SPU2setTimeStretcher; - -extern _SPU2async SPU2async; -extern _SPU2freeze SPU2freeze; -extern _SPU2configure SPU2configure; -extern _SPU2test SPU2test; -extern _SPU2about SPU2about; - -// CDVD -extern _CDVDinit CDVDinit; -extern _CDVDopen CDVDopen; -extern _CDVDclose CDVDclose; -extern _CDVDshutdown CDVDshutdown; -extern _CDVDreadTrack CDVDreadTrack; -extern _CDVDgetBuffer CDVDgetBuffer; -extern _CDVDreadSubQ CDVDreadSubQ; -extern _CDVDgetTN CDVDgetTN; -extern _CDVDgetTD CDVDgetTD; -extern _CDVDgetTOC CDVDgetTOC; -extern _CDVDgetDiskType CDVDgetDiskType; -extern _CDVDgetTrayStatus CDVDgetTrayStatus; -extern _CDVDctrlTrayOpen CDVDctrlTrayOpen; -extern _CDVDctrlTrayClose CDVDctrlTrayClose; - -extern _CDVDconfigure CDVDconfigure; -extern _CDVDtest CDVDtest; -extern _CDVDabout CDVDabout; -extern _CDVDnewDiskCB CDVDnewDiskCB; - -// DEV9 -extern _DEV9init DEV9init; -extern _DEV9open DEV9open; -extern _DEV9close DEV9close; -extern _DEV9shutdown DEV9shutdown; -extern _DEV9read8 DEV9read8; -extern _DEV9read16 DEV9read16; -extern _DEV9read32 DEV9read32; -extern _DEV9write8 DEV9write8; -extern _DEV9write16 DEV9write16; -extern _DEV9write32 DEV9write32; -extern _DEV9readDMA8Mem DEV9readDMA8Mem; -extern _DEV9writeDMA8Mem DEV9writeDMA8Mem; -extern _DEV9irqCallback DEV9irqCallback; -extern _DEV9irqHandler DEV9irqHandler; - -extern _DEV9configure DEV9configure; -extern _DEV9freeze DEV9freeze; -extern _DEV9test DEV9test; -extern _DEV9about DEV9about; - -// USB -extern _USBinit USBinit; -extern _USBopen USBopen; -extern _USBclose USBclose; -extern _USBshutdown USBshutdown; -extern _USBread8 USBread8; -extern _USBread16 USBread16; -extern _USBread32 USBread32; -extern _USBwrite8 USBwrite8; -extern _USBwrite16 USBwrite16; -extern _USBwrite32 USBwrite32; -extern _USBasync USBasync; - -extern _USBirqCallback USBirqCallback; -extern _USBirqHandler USBirqHandler; -extern _USBsetRAM USBsetRAM; - -extern _USBconfigure USBconfigure; -extern _USBfreeze USBfreeze; -extern _USBtest USBtest; -extern _USBabout USBabout; - -// FW -extern _FWinit FWinit; -extern _FWopen FWopen; -extern _FWclose FWclose; -extern _FWshutdown FWshutdown; -extern _FWread32 FWread32; -extern _FWwrite32 FWwrite32; -extern _FWirqCallback FWirqCallback; - -extern _FWconfigure FWconfigure; -extern _FWfreeze FWfreeze; -extern _FWtest FWtest; -extern _FWabout FWabout; -#endif - -#ifdef __cplusplus -} // End extern "C" -#endif - -#endif /* __PS2EDEFS_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct _keyEvent { + u32 key; + u32 evt; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct _cdvdSubQ { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct _cdvdTD { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct _cdvdTN { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct _GSdriverInfo { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WINDOWS_ +typedef struct _winInfo { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2setClockPtr(u32* ptr); +void CALLBACK SPU2setTimeStretcher(short int enable); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +void CALLBACK USBasync(u32 cycles); + +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WINDOWS_ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(const char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); + +typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); +typedef void (CALLBACK* _SPU2setTimeStretcher)(short int enable); + +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBasync)(u32 cycles); + + +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +extern _GSinit GSinit; +extern _GSopen GSopen; +extern _GSclose GSclose; +extern _GSshutdown GSshutdown; +extern _GSvsync GSvsync; +extern _GSgifTransfer1 GSgifTransfer1; +extern _GSgifTransfer2 GSgifTransfer2; +extern _GSgifTransfer3 GSgifTransfer3; +extern _GSgetLastTag GSgetLastTag; +extern _GSgifSoftReset GSgifSoftReset; +extern _GSreadFIFO GSreadFIFO; +extern _GSreadFIFO2 GSreadFIFO2; + +extern _GSkeyEvent GSkeyEvent; +extern _GSchangeSaveState GSchangeSaveState; +extern _GSmakeSnapshot GSmakeSnapshot; +extern _GSmakeSnapshot2 GSmakeSnapshot2; +extern _GSirqCallback GSirqCallback; +extern _GSprintf GSprintf; +extern _GSsetBaseMem GSsetBaseMem; +extern _GSsetGameCRC GSsetGameCRC; +extern _GSsetFrameSkip GSsetFrameSkip; +extern _GSsetupRecording GSsetupRecording; +extern _GSreset GSreset; +extern _GSwriteCSR GSwriteCSR; +extern _GSgetDriverInfo GSgetDriverInfo; +#ifdef _WINDOWS_ +extern _GSsetWindowInfo GSsetWindowInfo; +#endif +extern _GSfreeze GSfreeze; +extern _GSconfigure GSconfigure; +extern _GStest GStest; +extern _GSabout GSabout; + +// PAD1 +extern _PADinit PAD1init; +extern _PADopen PAD1open; +extern _PADclose PAD1close; +extern _PADshutdown PAD1shutdown; +extern _PADkeyEvent PAD1keyEvent; +extern _PADstartPoll PAD1startPoll; +extern _PADpoll PAD1poll; +extern _PADquery PAD1query; +extern _PADupdate PAD1update; + +extern _PADgsDriverInfo PAD1gsDriverInfo; +extern _PADconfigure PAD1configure; +extern _PADtest PAD1test; +extern _PADabout PAD1about; + +// PAD2 +extern _PADinit PAD2init; +extern _PADopen PAD2open; +extern _PADclose PAD2close; +extern _PADshutdown PAD2shutdown; +extern _PADkeyEvent PAD2keyEvent; +extern _PADstartPoll PAD2startPoll; +extern _PADpoll PAD2poll; +extern _PADquery PAD2query; +extern _PADupdate PAD2update; + +extern _PADgsDriverInfo PAD2gsDriverInfo; +extern _PADconfigure PAD2configure; +extern _PADtest PAD2test; +extern _PADabout PAD2about; + +// SIO[2] +extern _SIOinit SIOinit[2][9]; +extern _SIOopen SIOopen[2][9]; +extern _SIOclose SIOclose[2][9]; +extern _SIOshutdown SIOshutdown[2][9]; +extern _SIOstartPoll SIOstartPoll[2][9]; +extern _SIOpoll SIOpoll[2][9]; +extern _SIOquery SIOquery[2][9]; + +extern _SIOconfigure SIOconfigure[2][9]; +extern _SIOtest SIOtest[2][9]; +extern _SIOabout SIOabout[2][9]; + +// SPU2 +extern _SPU2init SPU2init; +extern _SPU2open SPU2open; +extern _SPU2close SPU2close; +extern _SPU2shutdown SPU2shutdown; +extern _SPU2write SPU2write; +extern _SPU2read SPU2read; +extern _SPU2readDMA4Mem SPU2readDMA4Mem; +extern _SPU2writeDMA4Mem SPU2writeDMA4Mem; +extern _SPU2interruptDMA4 SPU2interruptDMA4; +extern _SPU2readDMA7Mem SPU2readDMA7Mem; +extern _SPU2writeDMA7Mem SPU2writeDMA7Mem; +extern _SPU2setDMABaseAddr SPU2setDMABaseAddr; +extern _SPU2interruptDMA7 SPU2interruptDMA7; +extern _SPU2ReadMemAddr SPU2ReadMemAddr; +extern _SPU2setupRecording SPU2setupRecording; +extern _SPU2WriteMemAddr SPU2WriteMemAddr; +extern _SPU2irqCallback SPU2irqCallback; + +extern _SPU2setClockPtr SPU2setClockPtr; +extern _SPU2setTimeStretcher SPU2setTimeStretcher; + +extern _SPU2async SPU2async; +extern _SPU2freeze SPU2freeze; +extern _SPU2configure SPU2configure; +extern _SPU2test SPU2test; +extern _SPU2about SPU2about; + +// CDVD +extern _CDVDinit CDVDinit; +extern _CDVDopen CDVDopen; +extern _CDVDclose CDVDclose; +extern _CDVDshutdown CDVDshutdown; +extern _CDVDreadTrack CDVDreadTrack; +extern _CDVDgetBuffer CDVDgetBuffer; +extern _CDVDreadSubQ CDVDreadSubQ; +extern _CDVDgetTN CDVDgetTN; +extern _CDVDgetTD CDVDgetTD; +extern _CDVDgetTOC CDVDgetTOC; +extern _CDVDgetDiskType CDVDgetDiskType; +extern _CDVDgetTrayStatus CDVDgetTrayStatus; +extern _CDVDctrlTrayOpen CDVDctrlTrayOpen; +extern _CDVDctrlTrayClose CDVDctrlTrayClose; + +extern _CDVDconfigure CDVDconfigure; +extern _CDVDtest CDVDtest; +extern _CDVDabout CDVDabout; +extern _CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +extern _DEV9init DEV9init; +extern _DEV9open DEV9open; +extern _DEV9close DEV9close; +extern _DEV9shutdown DEV9shutdown; +extern _DEV9read8 DEV9read8; +extern _DEV9read16 DEV9read16; +extern _DEV9read32 DEV9read32; +extern _DEV9write8 DEV9write8; +extern _DEV9write16 DEV9write16; +extern _DEV9write32 DEV9write32; +extern _DEV9readDMA8Mem DEV9readDMA8Mem; +extern _DEV9writeDMA8Mem DEV9writeDMA8Mem; +extern _DEV9irqCallback DEV9irqCallback; +extern _DEV9irqHandler DEV9irqHandler; + +extern _DEV9configure DEV9configure; +extern _DEV9freeze DEV9freeze; +extern _DEV9test DEV9test; +extern _DEV9about DEV9about; + +// USB +extern _USBinit USBinit; +extern _USBopen USBopen; +extern _USBclose USBclose; +extern _USBshutdown USBshutdown; +extern _USBread8 USBread8; +extern _USBread16 USBread16; +extern _USBread32 USBread32; +extern _USBwrite8 USBwrite8; +extern _USBwrite16 USBwrite16; +extern _USBwrite32 USBwrite32; +extern _USBasync USBasync; + +extern _USBirqCallback USBirqCallback; +extern _USBirqHandler USBirqHandler; +extern _USBsetRAM USBsetRAM; + +extern _USBconfigure USBconfigure; +extern _USBfreeze USBfreeze; +extern _USBtest USBtest; +extern _USBabout USBabout; + +// FW +extern _FWinit FWinit; +extern _FWopen FWopen; +extern _FWclose FWclose; +extern _FWshutdown FWshutdown; +extern _FWread32 FWread32; +extern _FWwrite32 FWwrite32; +extern _FWirqCallback FWirqCallback; + +extern _FWconfigure FWconfigure; +extern _FWfreeze FWfreeze; +extern _FWtest FWtest; +extern _FWabout FWabout; +#endif + +#ifdef __cplusplus +} // End extern "C" +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/CDVDiso/src/common/PS2Etypes.h b/plugins/CDVDiso/src/common/PS2Etypes.h index 59be1c3de4..4c62b47f0f 100644 --- a/plugins/CDVDiso/src/common/PS2Etypes.h +++ b/plugins/CDVDiso/src/common/PS2Etypes.h @@ -1,219 +1,219 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef __PS2ETYPES_H__ -#define __PS2ETYPES_H__ - -#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case -#define __LINUX__ -#endif - -#ifdef __CYGWIN__ -#define __LINUX__ -#endif - -#ifndef ARRAYSIZE -#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) -#endif - -#ifdef __LINUX__ -#define CALLBACK -#else -#define CALLBACK __stdcall -#endif - - -// jASSUME - give hints to the optimizer -// This is primarily useful for the default case switch optimizer, which enables VC to -// generate more compact switches. - -#ifdef NDEBUG -# define jBREAKPOINT() ((void) 0) -# ifdef _MSC_VER -# define jASSUME(exp) (__assume(exp)) -# else -# define jASSUME(exp) ((void) sizeof(exp)) -# endif -#else -# if defined(_MSC_VER) -# define jBREAKPOINT() do { __asm int 3 } while(0) -# else -# define jBREAKPOINT() ((void) *(volatile char *) 0) -# endif -# define jASSUME(exp) if(exp) ; else jBREAKPOINT() -#endif - -// disable the default case in a switch -#define jNO_DEFAULT \ -{ \ - break; \ - \ -default: \ - jASSUME(0); \ - break; \ -} - - -// Basic types -#if defined(_MSC_VER) - -typedef __int8 s8; -typedef __int16 s16; -typedef __int32 s32; -typedef __int64 s64; - -typedef unsigned __int8 u8; -typedef unsigned __int16 u16; -typedef unsigned __int32 u32; -typedef unsigned __int64 u64; - -typedef unsigned int uint; - -#define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x -#define PCSX2_ALIGNED16(x) __declspec(align(16)) x -#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x - -#define __naked __declspec(naked) - -#else // _MSC_VER - -#ifdef __LINUX__ - -#ifdef HAVE_STDINT_H -#include "stdint.h" - -typedef int8_t s8; -typedef int16_t s16; -typedef int32_t s32; -typedef int64_t s64; - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -typedef uintptr_t uptr; -typedef intptr_t sptr; - -#else // HAVE_STDINT_H - -typedef char s8; -typedef short s16; -typedef int s32; -typedef long long s64; - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long long u64; - -#endif // HAVE_STDINT_H - -typedef unsigned int uint; - -#define LONG long -typedef union _LARGE_INTEGER -{ - long long QuadPart; -} LARGE_INTEGER; - -#define __fastcall __attribute__((fastcall)) -#define __unused __attribute__((unused)) -#define _inline __inline__ __attribute__((unused)) -#define __forceinline __attribute__((always_inline,unused)) -#define __naked // GCC lacks the naked specifier - -#endif // __LINUX__ - -#define PCSX2_ALIGNED(alig,x) x __attribute((aligned(alig))) -#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) - -#define PCSX2_ALIGNED16_DECL(x) x - -#endif // _MSC_VER - -#if !defined(__LINUX__) || !defined(HAVE_STDINT_H) -#if defined(__x86_64__) -typedef u64 uptr; -typedef s64 sptr; -#else -typedef u32 uptr; -typedef s32 sptr; -#endif -#endif - -// A rough-and-ready cross platform 128-bit datatype, Non-SSE style. -#ifdef __cplusplus -struct u128 -{ - u64 lo; - u64 hi; - - // Implicit conversion from u64 - u128( u64 src ) : - lo( src ) - , hi( 0 ) {} - - // Implicit conversion from u32 - u128( u32 src ) : - lo( src ) - , hi( 0 ) {} -}; - -struct s128 -{ - s64 lo; - s64 hi; - - // Implicit conversion from u64 - s128( s64 src ) : - lo( src ) - , hi( 0 ) {} - - // Implicit conversion from u32 - s128( s32 src ) : - lo( src ) - , hi( 0 ) {} -}; - -#else - -typedef union _u128_t -{ - u64 lo; - u64 hi; -} u128; - -typedef union _s128_t -{ - s64 lo; - s64 hi; -} s128; - -#endif - -typedef struct { - int size; - s8 *data; -} freezeData; - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#endif /* __PS2ETYPES_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +#ifdef __CYGWIN__ +#define __LINUX__ +#endif + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#ifdef __LINUX__ +#define CALLBACK +#else +#define CALLBACK __stdcall +#endif + + +// jASSUME - give hints to the optimizer +// This is primarily useful for the default case switch optimizer, which enables VC to +// generate more compact switches. + +#ifdef NDEBUG +# define jBREAKPOINT() ((void) 0) +# ifdef _MSC_VER +# define jASSUME(exp) (__assume(exp)) +# else +# define jASSUME(exp) ((void) sizeof(exp)) +# endif +#else +# if defined(_MSC_VER) +# define jBREAKPOINT() do { __asm int 3 } while(0) +# else +# define jBREAKPOINT() ((void) *(volatile char *) 0) +# endif +# define jASSUME(exp) if(exp) ; else jBREAKPOINT() +#endif + +// disable the default case in a switch +#define jNO_DEFAULT \ +{ \ + break; \ + \ +default: \ + jASSUME(0); \ + break; \ +} + + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +typedef unsigned int uint; + +#define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x + +#define __naked __declspec(naked) + +#else // _MSC_VER + +#ifdef __LINUX__ + +#ifdef HAVE_STDINT_H +#include "stdint.h" + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef uintptr_t uptr; +typedef intptr_t sptr; + +#else // HAVE_STDINT_H + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#endif // HAVE_STDINT_H + +typedef unsigned int uint; + +#define LONG long +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; + +#define __fastcall __attribute__((fastcall)) +#define __unused __attribute__((unused)) +#define _inline __inline__ __attribute__((unused)) +#define __forceinline __attribute__((always_inline,unused)) +#define __naked // GCC lacks the naked specifier + +#endif // __LINUX__ + +#define PCSX2_ALIGNED(alig,x) x __attribute((aligned(alig))) +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) + +#define PCSX2_ALIGNED16_DECL(x) x + +#endif // _MSC_VER + +#if !defined(__LINUX__) || !defined(HAVE_STDINT_H) +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif +#endif + +// A rough-and-ready cross platform 128-bit datatype, Non-SSE style. +#ifdef __cplusplus +struct u128 +{ + u64 lo; + u64 hi; + + // Implicit conversion from u64 + u128( u64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + u128( u32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +struct s128 +{ + s64 lo; + s64 hi; + + // Implicit conversion from u64 + s128( s64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + s128( s32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +#else + +typedef union _u128_t +{ + u64 lo; + u64 hi; +} u128; + +typedef union _s128_t +{ + s64 lo; + s64 hi; +} s128; + +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/CDVDiso/src/libiso.c b/plugins/CDVDiso/src/libiso.c index 75566d91fb..d6c8168e9c 100644 --- a/plugins/CDVDiso/src/libiso.c +++ b/plugins/CDVDiso/src/libiso.c @@ -1,1043 +1,1043 @@ -#define __USE_LARGEFILE64 -#define __USE_FILE_OFFSET64 -#define _FILE_OFFSET_BITS 64 - -#ifdef _WIN32 -#include -#endif - -#include -#include -#include -#include -#include -#include -#include "3rdparty/zlib/zlib.h" -#include "3rdparty/bzip2/bzlib.h" - -#include "CDVDiso.h" -#include "libiso.h" - -/* some structs from libcdvd by Hiryu & Sjeep (C) 2002 */ - -#if defined(_WIN32) -#pragma pack(1) -#endif - -struct rootDirTocHeader -{ - u16 length; //+00 - u32 tocLBA; //+02 - u32 tocLBA_bigend; //+06 - u32 tocSize; //+0A - u32 tocSize_bigend; //+0E - u8 dateStamp[8]; //+12 - u8 reserved[6]; //+1A - u8 reserved2; //+20 - u8 reserved3; //+21 -#if defined(_WIN32) -}; //+22 -#else -} __attribute__((packed)); -#endif - -struct asciiDate -{ - char year[4]; - char month[2]; - char day[2]; - char hours[2]; - char minutes[2]; - char seconds[2]; - char hundreths[2]; - char terminator[1]; -#if defined(_WIN32) -}; -#else -} __attribute__((packed)); -#endif - -struct cdVolDesc -{ - u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL - u8 volID[5]; // "CD001" - u8 reserved2; - u8 reserved3; - u8 sysIdName[32]; - u8 volName[32]; // The ISO9660 Volume Name - u8 reserved5[8]; - u32 volSize; // Volume Size - u32 volSizeBig; // Volume Size Big-Endian - u8 reserved6[32]; - u32 unknown1; - u32 unknown1_bigend; - u16 volDescSize; //+80 - u16 volDescSize_bigend; //+82 - u32 unknown3; //+84 - u32 unknown3_bigend; //+88 - u32 priDirTableLBA; // LBA of Primary Dir Table //+8C - u32 reserved7; //+90 - u32 secDirTableLBA; // LBA of Secondary Dir Table //+94 - u32 reserved8; //+98 - struct rootDirTocHeader rootToc; - u8 volSetName[128]; - u8 publisherName[128]; - u8 preparerName[128]; - u8 applicationName[128]; - u8 copyrightFileName[37]; - u8 abstractFileName[37]; - u8 bibliographyFileName[37]; - struct asciiDate creationDate; - struct asciiDate modificationDate; - struct asciiDate effectiveDate; - struct asciiDate expirationDate; - u8 reserved10; - u8 reserved11[1166]; -#if defined(_WIN32) -}; -#else -} __attribute__((packed)); -#endif - - -#ifdef _WIN32 -void *_openfile(const char *filename, int flags) -{ - HANDLE handle; - -// printf("_openfile %s, %d\n", filename, flags & O_RDONLY); - if (flags & O_WRONLY) - { - int _flags = CREATE_NEW; - if (flags & O_CREAT) _flags = CREATE_ALWAYS; - handle = CreateFile(filename, GENERIC_WRITE, 0, NULL, _flags, 0, NULL); - } - else - { - handle = CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); - } - - return handle == INVALID_HANDLE_VALUE ? NULL : handle; -} - -u64 _tellfile(void *handle) -{ - u64 ofs; - PLONG _ofs = (LONG*) & ofs; - _ofs[1] = 0; - _ofs[0] = SetFilePointer(handle, 0, &_ofs[1], FILE_CURRENT); - return ofs; -} - -int _seekfile(void *handle, u64 offset, int whence) -{ - u64 ofs = (u64)offset; - PLONG _ofs = (LONG*) & ofs; -// printf("_seekfile %p, %d_%d\n", handle, _ofs[1], _ofs[0]); - if (whence == SEEK_SET) - { - SetFilePointer(handle, _ofs[0], &_ofs[1], FILE_BEGIN); - } - else - { - SetFilePointer(handle, _ofs[0], &_ofs[1], FILE_END); - } - return 0; -} - -int _readfile(void *handle, void *dst, int size) -{ - DWORD ret; - -// printf("_readfile %p %d\n", handle, size); - ReadFile(handle, dst, size, &ret, NULL); -// printf("_readfile ret %d; %d\n", ret, GetLastError()); - return ret; -} - -int _writefile(void *handle, void *src, int size) -{ - DWORD ret; - -// printf("_writefile %p, %d\n", handle, size); -// _seekfile(handle, _tellfile(handle)); - WriteFile(handle, src, size, &ret, NULL); -// printf("_writefile ret %d\n", ret); - return ret; -} - -void _closefile(void *handle) -{ - CloseHandle(handle); -} - -#else - -void *_openfile(const char *filename, int flags) -{ - printf("_openfile %s %x\n", filename, flags); - - if (flags & O_WRONLY) - return fopen64(filename, "wb"); - else - return fopen64(filename, "rb"); -} - -#include - -u64 _tellfile(void *handle) -{ - u64 cursize = ftell(handle); - if (cursize == -1) - { - // try 64bit - cursize = ftello64(handle); - if (cursize < -1) - { - // zero top 32 bits - cursize &= 0xffffffff; - } - } - return cursize; -} - -int _seekfile(void *handle, u64 offset, int whence) -{ - int seekerr = fseeko64(handle, offset, whence); - - if (seekerr == -1) printf("failed to seek\n"); - - return seekerr; -} - -int _readfile(void *handle, void *dst, int size) -{ - return fread(dst, 1, size, handle); -} - -int _writefile(void *handle, void *src, int size) -{ - return fwrite(src, 1, size, handle); -} - -void _closefile(void *handle) -{ - fclose(handle); -} - -#endif - -int detect(isoFile *iso) -{ - u8 buf[2448]; - struct cdVolDesc *volDesc; - - if (isoReadBlock(iso, buf, 16) == -1) return -1; - - volDesc = (struct cdVolDesc *)(buf + 24); - - if (strncmp((char*)volDesc->volID, "CD001", 5)) return 0; - - if (volDesc->rootToc.tocSize == 2048) - iso->type = ISOTYPE_CD; - else - iso->type = ISOTYPE_DVD; - - return 1; -} - -int _isoReadZtable(isoFile *iso) -{ - void *handle; - char table[256]; - int size; - - sprintf(table, "%s.table", iso->filename); - handle = _openfile(table, O_RDONLY); - if (handle == NULL) - { - printf("Error loading %s\n", table); - return -1; - } - - _seekfile(handle, 0, SEEK_END); - size = _tellfile(handle); - iso->Ztable = (char*)malloc(size); - - if (iso->Ztable == NULL) - { - return -1; - } - - _seekfile(handle, 0, SEEK_SET); - _readfile(handle, iso->Ztable, size); - _closefile(handle); - - iso->blocks = size / 6; - - return 0; -} - -int _isoReadZ2table(isoFile *iso) -{ - void *handle; - char table[256]; - u32 *Ztable; - int ofs; - int size; - int i; - - sprintf(table, "%s.table", iso->filename); - handle = _openfile(table, O_RDONLY); - - if (handle == NULL) - { - printf("Error loading %s\n", table); - return -1; - } - - _seekfile(handle, 0, SEEK_END); - size = _tellfile(handle); - Ztable = (u32*)malloc(size); - - if (Ztable == NULL) - { - return -1; - } - - _seekfile(handle, 0, SEEK_SET); - _readfile(handle, Ztable, size); - _closefile(handle); - - iso->Ztable = (char*)malloc(iso->blocks * 8); - - if (iso->Ztable == NULL) - { - return -1; - } - - ofs = 16; - - for (i = 0; i < iso->blocks; i++) - { - *(u32*)&iso->Ztable[i*8+0] = ofs; - *(u32*)&iso->Ztable[i*8+4] = Ztable[i]; - ofs += Ztable[i]; - } - - free(Ztable); - - return 0; -} - -int _isoReadBZ2table(isoFile *iso) -{ - void *handle; - char table[256]; - u32 *Ztable; - int ofs; - int size; - int i; - - sprintf(table, "%s.table", iso->filename); - handle = _openfile(table, O_RDONLY); - if (handle == NULL) - { - printf("Error loading %s\n", table); - return -1; - } - - _seekfile(handle, 0, SEEK_END); - size = _tellfile(handle); - Ztable = (u32*)malloc(size); - if (Ztable == NULL) return -1; - - _seekfile(handle, 0, SEEK_SET); - _readfile(handle, Ztable, size); - _closefile(handle); - - iso->Ztable = (char*)malloc(iso->blocks * 8); - if (iso->Ztable == NULL) return -1; - - ofs = 16; - - for (i = 0; i < iso->blocks / 16; i++) - { - *(u32*)&iso->Ztable[i*8+0] = ofs; - *(u32*)&iso->Ztable[i*8+4] = Ztable[i]; - ofs += Ztable[i]; - } - - if (iso->blocks & 0xf) - { - *(u32*)&iso->Ztable[i*8+0] = ofs; - *(u32*)&iso->Ztable[i*8+4] = Ztable[i]; - ofs += Ztable[i]; - } - - free(Ztable); - - return 0; -} - -int _isoReadDtable(isoFile *iso) -{ - int ret; - int i; - - _seekfile(iso->handle, 0, SEEK_END); - iso->dtablesize = (_tellfile(iso->handle) - 16) / (iso->blocksize + 4); - iso->dtable = (u32*)malloc(iso->dtablesize * 4); - - for (i = 0; i < iso->dtablesize; i++) - { - _seekfile(iso->handle, 16 + (iso->blocksize + 4)*i, SEEK_SET); - ret = _readfile(iso->handle, &iso->dtable[i], 4); - if (ret < 4) return -1; - } - - return 0; -} - -int isoDetect(isoFile *iso) // based on florin's CDVDbin detection code :) -{ - char buf[32]; - int len; - - iso->type = ISOTYPE_ILLEGAL; - - len = strlen(iso->filename); - if (len >= 2) - { - if (!strncmp(iso->filename + (len - 2), ".Z", 2)) - { - iso->flags = ISOFLAGS_Z; - iso->blocksize = 2352; - _isoReadZtable(iso); - return detect(iso) == 1 ? 0 : -1; - } - } - - _seekfile(iso->handle, 0, SEEK_SET); - _readfile(iso->handle, buf, 4); - - if (strncmp(buf, "BDV2", 4) == 0) - { - iso->flags = ISOFLAGS_BLOCKDUMP; - _readfile(iso->handle, &iso->blocksize, 4); - _readfile(iso->handle, &iso->blocks, 4); - _readfile(iso->handle, &iso->blockofs, 4); - _isoReadDtable(iso); - return detect(iso) == 1 ? 0 : -1; - } - else if (strncmp(buf, "Z V2", 4) == 0) - { - iso->flags = ISOFLAGS_Z2; - _readfile(iso->handle, &iso->blocksize, 4); - _readfile(iso->handle, &iso->blocks, 4); - _readfile(iso->handle, &iso->blockofs, 4); - _isoReadZ2table(iso); - return detect(iso) == 1 ? 0 : -1; - } - else if (strncmp(buf, "BZV2", 4) == 0) - { - iso->flags = ISOFLAGS_BZ2; - _readfile(iso->handle, &iso->blocksize, 4); - _readfile(iso->handle, &iso->blocks, 4); - _readfile(iso->handle, &iso->blockofs, 4); - iso->buflsn = -1; - iso->buffer = (u8*)malloc(iso->blocksize * 16); - if (iso->buffer == NULL) return -1; - _isoReadBZ2table(iso); - return detect(iso) == 1 ? 0 : -1; - } - else - { - iso->blocks = 16; - } - - // ISO 2048 - iso->blocksize = 2048; - iso->offset = 0; - iso->blockofs = 24; - if (detect(iso) == 1) return 0; - - // RAW 2336 - iso->blocksize = 2336; - iso->offset = 0; - iso->blockofs = 16; - if (detect(iso) == 1) return 0; - - // RAW 2352 - iso->blocksize = 2352; - iso->offset = 0; - iso->blockofs = 0; - if (detect(iso) == 1) return 0; - - // RAWQ 2448 - iso->blocksize = 2448; - iso->offset = 0; - iso->blockofs = 0; - if (detect(iso) == 1) return 0; - - // NERO ISO 2048 - iso->blocksize = 2048; - iso->offset = 150 * 2048; - iso->blockofs = 24; - if (detect(iso) == 1) return 0; - - // NERO RAW 2352 - iso->blocksize = 2352; - iso->offset = 150 * 2048; - iso->blockofs = 0; - if (detect(iso) == 1) return 0; - - // NERO RAWQ 2448 - iso->blocksize = 2448; - iso->offset = 150 * 2048; - iso->blockofs = 0; - if (detect(iso) == 1) return 0; - - // ISO 2048 - iso->blocksize = 2048; - iso->offset = -8; - iso->blockofs = 24; - if (detect(iso) == 1) return 0; - - // RAW 2352 - iso->blocksize = 2352; - iso->offset = -8; - iso->blockofs = 0; - if (detect(iso) == 1) return 0; - - // RAWQ 2448 - iso->blocksize = 2448; - iso->offset = -8; - iso->blockofs = 0; - if (detect(iso) == 1) return 0; - - iso->offset = 0; - iso->blocksize = 2352; - iso->type = ISOTYPE_AUDIO; - return 0; - - return -1; -} - -isoFile *isoOpen(const char *filename) -{ - isoFile *iso; - int i; - - iso = (isoFile*)malloc(sizeof(isoFile)); - if (iso == NULL) return NULL; - - memset(iso, 0, sizeof(isoFile)); - strcpy(iso->filename, filename); - - iso->handle = _openfile(iso->filename, O_RDONLY); - if (iso->handle == NULL) - { - printf("Error loading %s\n", iso->filename); - return NULL; - } - - if (isoDetect(iso) == -1) return NULL; - - printf("detected blocksize = %d\n", iso->blocksize); - - if (strlen(iso->filename) > 3 && strncmp(iso->filename + (strlen(iso->filename) - 3), "I00", 3) == 0) - { - _closefile(iso->handle); - iso->flags |= ISOFLAGS_MULTI; - iso->blocks = 0; - for (i = 0; i < 8; i++) - { - iso->filename[strlen(iso->filename) - 1] = '0' + i; - iso->multih[i].handle = _openfile(iso->filename, O_RDONLY); - if (iso->multih[i].handle == NULL) - { - break; - } - iso->multih[i].slsn = iso->blocks; - _seekfile(iso->multih[i].handle, 0, SEEK_END); - iso->blocks += (u32)((_tellfile(iso->multih[i].handle) - iso->offset) / - (iso->blocksize)); - iso->multih[i].elsn = iso->blocks - 1; - } - - if (i == 0) - { - return NULL; - } - } - - if (iso->flags == 0) - { - _seekfile(iso->handle, 0, SEEK_END); - iso->blocks = (u32)((_tellfile(iso->handle) - iso->offset) / - (iso->blocksize)); - } - - - printf("isoOpen: %s ok\n", iso->filename); - printf("offset = %d\n", iso->offset); - printf("blockofs = %d\n", iso->blockofs); - printf("blocksize = %d\n", iso->blocksize); - printf("blocks = %d\n", iso->blocks); - printf("type = %d\n", iso->type); - - return iso; -} - -isoFile *isoCreate(const char *filename, int flags) -{ - isoFile *iso; - char Zfile[256]; - - iso = (isoFile*)malloc(sizeof(isoFile)); - if (iso == NULL) return NULL; - - memset(iso, 0, sizeof(isoFile)); - strcpy(iso->filename, filename); - iso->flags = flags; - iso->offset = 0; - iso->blockofs = 24; - iso->blocksize = CD_FRAMESIZE_RAW; - iso->blocksize = 2048; - - if (iso->flags & (ISOFLAGS_Z | ISOFLAGS_Z2 | ISOFLAGS_BZ2)) - { - sprintf(Zfile, "%s.table", iso->filename); - iso->htable = _openfile(Zfile, O_WRONLY); - if (iso->htable == NULL) - { - return NULL; - } - } - - iso->handle = _openfile(iso->filename, O_WRONLY | O_CREAT); - if (iso->handle == NULL) - { - printf("Error loading %s\n", iso->filename); - return NULL; - } - printf("isoCreate: %s ok\n", iso->filename); - printf("offset = %d\n", iso->offset); - - return iso; -} - -int isoSetFormat(isoFile *iso, int blockofs, int blocksize, int blocks) -{ - iso->blocksize = blocksize; - iso->blocks = blocks; - iso->blockofs = blockofs; - printf("blockofs = %d\n", iso->blockofs); - printf("blocksize = %d\n", iso->blocksize); - printf("blocks = %d\n", iso->blocks); - if (iso->flags & ISOFLAGS_Z2) - { - if (_writefile(iso->handle, "Z V2", 4) < 4) return -1; - if (_writefile(iso->handle, &blocksize, 4) < 4) return -1; - if (_writefile(iso->handle, &blocks, 4) < 4) return -1; - if (_writefile(iso->handle, &blockofs, 4) < 4) return -1; - } - if (iso->flags & ISOFLAGS_BZ2) - { - if (_writefile(iso->handle, "BZV2", 4) < 4) return -1; - if (_writefile(iso->handle, &blocksize, 4) < 4) return -1; - if (_writefile(iso->handle, &blocks, 4) < 4) return -1; - if (_writefile(iso->handle, &blockofs, 4) < 4) return -1; - iso->buflsn = -1; - iso->buffer = (u8*)malloc(iso->blocksize * 16); - if (iso->buffer == NULL) return -1; - } - if (iso->flags & ISOFLAGS_BLOCKDUMP) - { - if (_writefile(iso->handle, "BDV2", 4) < 4) return -1; - if (_writefile(iso->handle, &blocksize, 4) < 4) return -1; - if (_writefile(iso->handle, &blocks, 4) < 4) return -1; - if (_writefile(iso->handle, &blockofs, 4) < 4) return -1; - } - - return 0; -} - -s32 MSFtoLSN(u8 *Time) -{ - u32 lsn; - - lsn = Time[2]; - lsn += (Time[1] - 2) * 75; - lsn += Time[0] * 75 * 60; - return lsn; -} - -void LSNtoMSF(u8 *Time, s32 lsn) -{ - u8 m, s, f; - - lsn += 150; - m = lsn / 4500; // minuten - lsn = lsn - m * 4500; // minuten rest - s = lsn / 75; // sekunden - f = lsn - (s * 75); // sekunden rest - Time[0] = itob(m); - Time[1] = itob(s); - Time[2] = itob(f); -} - -int _isoReadBlock(isoFile *iso, u8 *dst, int lsn) -{ - u64 ofs = (u64)lsn * iso->blocksize + iso->offset; - int ret; - -// printf("_isoReadBlock %d, blocksize=%d, blockofs=%d\n", lsn, iso->blocksize, iso->blockofs); - memset(dst, 0, iso->blockofs); - _seekfile(iso->handle, ofs, SEEK_SET); - ret = _readfile(iso->handle, dst + iso->blockofs, iso->blocksize); - if (ret < iso->blocksize) - { - printf("read error %d\n", ret); - return -1; - } - - return 0; -} - -int _isoReadBlockZ(isoFile *iso, u8 *dst, int lsn) -{ - u32 pos, p; - uLongf size; - u8 Zbuf[CD_FRAMESIZE_RAW*2]; - int ret; - -// printf("_isoReadBlockZ %d, %d\n", lsn, iso->blocksize); - pos = *(unsigned long*) & iso->Ztable[lsn * 6]; - p = *(unsigned short*) & iso->Ztable[lsn * 6 + 4]; -// printf("%d, %d\n", pos, p); - _seekfile(iso->handle, pos, SEEK_SET); - ret = _readfile(iso->handle, Zbuf, p); - if (ret < p) - { - printf("error reading block!!\n"); - return -1; - } - - size = CD_FRAMESIZE_RAW; - uncompress(dst, &size, Zbuf, p); - - return 0; -} - -int _isoReadBlockZ2(isoFile *iso, u8 *dst, int lsn) -{ - u32 pos, p; - uLongf size; - u8 Zbuf[16*1024]; - int ret; - -// printf("_isoReadBlockZ2 %d, %d\n", lsn, iso->blocksize); - pos = *(u32*) & iso->Ztable[lsn*8]; - p = *(u32*) & iso->Ztable[lsn*8+4]; -// printf("%d, %d\n", pos, p); - _seekfile(iso->handle, pos, SEEK_SET); - ret = _readfile(iso->handle, Zbuf, p); - if (ret < p) - { - printf("error reading block!!\n"); - return -1; - } - - size = iso->blocksize; - uncompress(dst + iso->blockofs, &size, Zbuf, p); - - return 0; -} - -int _isoReadBlockBZ2(isoFile *iso, u8 *dst, int lsn) -{ - u32 pos, p; - u32 size; - u8 Zbuf[64*1024]; - int ret; - - if ((lsn / 16) == iso->buflsn) - { - memset(dst, 0, iso->blockofs); - memcpy(dst + iso->blockofs, iso->buffer + (iso->blocksize*(lsn&0xf)), iso->blocksize); - return 0; - } - - iso->buflsn = lsn / 16; -// printf("_isoReadBlockBZ2 %d, %d\n", lsn, iso->blocksize); - pos = *(u32*) & iso->Ztable[(lsn/16)*8]; - p = *(u32*) & iso->Ztable[(lsn/16)*8+4]; -// printf("%d, %d\n", pos, p); - _seekfile(iso->handle, pos, SEEK_SET); - ret = _readfile(iso->handle, Zbuf, p); - - if (ret < p) - { - printf("error reading block!!\n"); - return -1; - } - - size = iso->blocksize * 64; - ret = BZ2_bzBuffToBuffDecompress((s8*)iso->buffer, &size, (s8*)Zbuf, p, 0, 0); - - if (ret != BZ_OK) - { - printf("_isoReadBlockBZ2 %d, %d\n", lsn, iso->blocksize); - printf("%d, %d\n", pos, p); - printf("error on BZ2: %d\n", ret); - } - - memset(dst, 0, iso->blockofs); - memcpy(dst + iso->blockofs, iso->buffer + (iso->blocksize*(lsn&0xf)), iso->blocksize); - - return 0; -} - -int _isoReadBlockD(isoFile *iso, u8 *dst, int lsn) -{ - int ret; - int i; - -// printf("_isoReadBlockD %d, blocksize=%d, blockofs=%d\n", lsn, iso->blocksize, iso->blockofs); - memset(dst, 0, iso->blockofs); - for (i = 0; i < iso->dtablesize;i++) - { - if (iso->dtable[i] != lsn) continue; - - _seekfile(iso->handle, 16 + i*(iso->blocksize + 4) + 4, SEEK_SET); - ret = _readfile(iso->handle, dst + iso->blockofs, iso->blocksize); - if (ret < iso->blocksize) return -1; - - return 0; - } - printf("block %d not found in dump\n", lsn); - - return -1; -} - -int _isoReadBlockM(isoFile *iso, u8 *dst, int lsn) -{ - u64 ofs; - int ret; - int i; - - for (i = 0; i < 8; i++) - { - if (lsn >= iso->multih[i].slsn && - lsn <= iso->multih[i].elsn) - { - break; - } - } - if (i == 8) return -1; - - ofs = (u64)(lsn - iso->multih[i].slsn) * iso->blocksize + iso->offset; -// printf("_isoReadBlock %d, blocksize=%d, blockofs=%d\n", lsn, iso->blocksize, iso->blockofs); - memset(dst, 0, iso->blockofs); - _seekfile(iso->multih[i].handle, ofs, SEEK_SET); - ret = _readfile(iso->multih[i].handle, dst + iso->blockofs, iso->blocksize); - - if (ret < iso->blocksize) - { - printf("read error %d\n", ret); - return -1; - } - - return 0; -} - -int isoReadBlock(isoFile *iso, u8 *dst, int lsn) -{ - int ret; - - if (lsn > iso->blocks) - { - printf("isoReadBlock: %d > %d\n", lsn, iso->blocks); - return -1; - } - - if (iso->flags & ISOFLAGS_Z) - ret = _isoReadBlockZ(iso, dst, lsn); - else if (iso->flags & ISOFLAGS_Z2) - ret = _isoReadBlockZ2(iso, dst, lsn); - else if (iso->flags & ISOFLAGS_BLOCKDUMP) - ret = _isoReadBlockD(iso, dst, lsn); - else if (iso->flags & ISOFLAGS_MULTI) - ret = _isoReadBlockM(iso, dst, lsn); - else if (iso->flags & ISOFLAGS_BZ2) - ret = _isoReadBlockBZ2(iso, dst, lsn); - else - ret = _isoReadBlock(iso, dst, lsn); - - if (ret == -1) return ret; - - if (iso->type == ISOTYPE_CD) - { - LSNtoMSF(dst + 12, lsn); - dst[15] = 2; - } - - return 0; -} - - -int _isoWriteBlock(isoFile *iso, u8 *src, int lsn) -{ - u64 ofs = (u64)lsn * iso->blocksize + iso->offset; - int ret; - -// printf("_isoWriteBlock %d (ofs=%d)\n", iso->blocksize, ofs); - _seekfile(iso->handle, ofs, SEEK_SET); - ret = _writefile(iso->handle, src + iso->blockofs, iso->blocksize); -// printf("_isoWriteBlock %d\n", ret); - if (ret < iso->blocksize) return -1; - - return 0; -} - -int _isoWriteBlockZ(isoFile *iso, u8 *src, int lsn) -{ - u32 pos; - uLongf size; - u8 Zbuf[CD_FRAMESIZE_RAW]; - int ret; - -// printf("_isoWriteBlockZ %d\n", iso->blocksize); - size = 2352; - compress(Zbuf, &size, src, 2352); -// printf("_isoWriteBlockZ %d\n", size); - - pos = (u32)_tellfile(iso->handle); - ret = _writefile(iso->htable, &pos, 4); - if (ret < 4) return -1; - ret = _writefile(iso->htable, &size, 2); - if (ret < 2) return -1; - - ret = _writefile(iso->handle, Zbuf, size); -// printf("_isoWriteBlockZ %d\n", ret); - if (ret < size) - { - printf("error writing block!!\n"); - return -1; - } - - return 0; -} - -int _isoWriteBlockZ2(isoFile *iso, u8 *src, int lsn) -{ - uLongf size; - u8 Zbuf[1024*16]; - int ret; - -// printf("_isoWriteBlockZ %d\n", iso->blocksize); - size = 1024 * 16; - compress(Zbuf, &size, src + iso->blockofs, iso->blocksize); -// printf("_isoWriteBlockZ %d\n", size); - - ret = _writefile(iso->htable, (u8*) & size, 4); - if (ret < 4) return -1; - ret = _writefile(iso->handle, Zbuf, size); -// printf("_isoWriteBlockZ %d\n", ret); - if (ret < size) - { - printf("error writing block!!\n"); - return -1; - } - - return 0; -} - -int _isoWriteBlockD(isoFile *iso, u8 *src, int lsn) -{ - int ret; - -// printf("_isoWriteBlock %d (ofs=%d)\n", iso->blocksize, ofs); - ret = _writefile(iso->handle, &lsn, 4); - if (ret < 4) return -1; - ret = _writefile(iso->handle, src + iso->blockofs, iso->blocksize); -// printf("_isoWriteBlock %d\n", ret); - if (ret < iso->blocksize) return -1; - - return 0; -} - -int _isoWriteBlockBZ2(isoFile *iso, u8 *src, int lsn) -{ - u32 size; - u8 Zbuf[64*1024]; - int blocks; - int ret; - - memcpy(iso->buffer + (iso->blocksize*(lsn&0xf)), src + iso->blockofs, iso->blocksize); - - if (lsn == (iso->blocks - 1)) - { - blocks = (lsn & 0xf) + 1; - } - else - { - blocks = 16; - if ((lsn & 0xf) != 0xf) return 0; - } - -// printf("_isoWriteBlockBZ2 %d\n", iso->blocksize); - size = 64 * 1024; - ret = BZ2_bzBuffToBuffCompress((s8*)Zbuf, (u32*) & size, (s8*)iso->buffer, iso->blocksize * blocks, 9, 0, 30); - - if (ret != BZ_OK) - { - printf("error on BZ2: %d\n", ret); - } - -// printf("_isoWriteBlockBZ2 %d\n", size); - - ret = _writefile(iso->htable, (u8*) & size, 4); - if (ret < 4) return -1; - ret = _writefile(iso->handle, Zbuf, size); -// printf("_isoWriteBlockZ %d\n", ret); - - if (ret < size) - { - printf("error writing block!!\n"); - return -1; - } - - return 0; -} - -int isoWriteBlock(isoFile *iso, u8 *src, int lsn) -{ - int ret; - - if (iso->flags & ISOFLAGS_Z) - ret = _isoWriteBlockZ(iso, src, lsn); - else if (iso->flags & ISOFLAGS_Z2) - ret = _isoWriteBlockZ2(iso, src, lsn); - else if (iso->flags & ISOFLAGS_BLOCKDUMP) - ret = _isoWriteBlockD(iso, src, lsn); - else if (iso->flags & ISOFLAGS_BZ2) - ret = _isoWriteBlockBZ2(iso, src, lsn); - else - ret = _isoWriteBlock(iso, src, lsn); - - if (ret == -1) return ret; - return 0; -} - -void isoClose(isoFile *iso) -{ - if (iso->handle) _closefile(iso->handle); - if (iso->htable) _closefile(iso->htable); - if (iso->buffer) free(iso->buffer); - - free(iso); -} - +#define __USE_LARGEFILE64 +#define __USE_FILE_OFFSET64 +#define _FILE_OFFSET_BITS 64 + +#ifdef _WIN32 +#include +#endif + +#include +#include +#include +#include +#include +#include +#include "3rdparty/zlib/zlib.h" +#include "3rdparty/bzip2/bzlib.h" + +#include "CDVDiso.h" +#include "libiso.h" + +/* some structs from libcdvd by Hiryu & Sjeep (C) 2002 */ + +#if defined(_WIN32) +#pragma pack(1) +#endif + +struct rootDirTocHeader +{ + u16 length; //+00 + u32 tocLBA; //+02 + u32 tocLBA_bigend; //+06 + u32 tocSize; //+0A + u32 tocSize_bigend; //+0E + u8 dateStamp[8]; //+12 + u8 reserved[6]; //+1A + u8 reserved2; //+20 + u8 reserved3; //+21 +#if defined(_WIN32) +}; //+22 +#else +} __attribute__((packed)); +#endif + +struct asciiDate +{ + char year[4]; + char month[2]; + char day[2]; + char hours[2]; + char minutes[2]; + char seconds[2]; + char hundreths[2]; + char terminator[1]; +#if defined(_WIN32) +}; +#else +} __attribute__((packed)); +#endif + +struct cdVolDesc +{ + u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL + u8 volID[5]; // "CD001" + u8 reserved2; + u8 reserved3; + u8 sysIdName[32]; + u8 volName[32]; // The ISO9660 Volume Name + u8 reserved5[8]; + u32 volSize; // Volume Size + u32 volSizeBig; // Volume Size Big-Endian + u8 reserved6[32]; + u32 unknown1; + u32 unknown1_bigend; + u16 volDescSize; //+80 + u16 volDescSize_bigend; //+82 + u32 unknown3; //+84 + u32 unknown3_bigend; //+88 + u32 priDirTableLBA; // LBA of Primary Dir Table //+8C + u32 reserved7; //+90 + u32 secDirTableLBA; // LBA of Secondary Dir Table //+94 + u32 reserved8; //+98 + struct rootDirTocHeader rootToc; + u8 volSetName[128]; + u8 publisherName[128]; + u8 preparerName[128]; + u8 applicationName[128]; + u8 copyrightFileName[37]; + u8 abstractFileName[37]; + u8 bibliographyFileName[37]; + struct asciiDate creationDate; + struct asciiDate modificationDate; + struct asciiDate effectiveDate; + struct asciiDate expirationDate; + u8 reserved10; + u8 reserved11[1166]; +#if defined(_WIN32) +}; +#else +} __attribute__((packed)); +#endif + + +#ifdef _WIN32 +void *_openfile(const char *filename, int flags) +{ + HANDLE handle; + +// printf("_openfile %s, %d\n", filename, flags & O_RDONLY); + if (flags & O_WRONLY) + { + int _flags = CREATE_NEW; + if (flags & O_CREAT) _flags = CREATE_ALWAYS; + handle = CreateFile(filename, GENERIC_WRITE, 0, NULL, _flags, 0, NULL); + } + else + { + handle = CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + } + + return handle == INVALID_HANDLE_VALUE ? NULL : handle; +} + +u64 _tellfile(void *handle) +{ + u64 ofs; + PLONG _ofs = (LONG*) & ofs; + _ofs[1] = 0; + _ofs[0] = SetFilePointer(handle, 0, &_ofs[1], FILE_CURRENT); + return ofs; +} + +int _seekfile(void *handle, u64 offset, int whence) +{ + u64 ofs = (u64)offset; + PLONG _ofs = (LONG*) & ofs; +// printf("_seekfile %p, %d_%d\n", handle, _ofs[1], _ofs[0]); + if (whence == SEEK_SET) + { + SetFilePointer(handle, _ofs[0], &_ofs[1], FILE_BEGIN); + } + else + { + SetFilePointer(handle, _ofs[0], &_ofs[1], FILE_END); + } + return 0; +} + +int _readfile(void *handle, void *dst, int size) +{ + DWORD ret; + +// printf("_readfile %p %d\n", handle, size); + ReadFile(handle, dst, size, &ret, NULL); +// printf("_readfile ret %d; %d\n", ret, GetLastError()); + return ret; +} + +int _writefile(void *handle, void *src, int size) +{ + DWORD ret; + +// printf("_writefile %p, %d\n", handle, size); +// _seekfile(handle, _tellfile(handle)); + WriteFile(handle, src, size, &ret, NULL); +// printf("_writefile ret %d\n", ret); + return ret; +} + +void _closefile(void *handle) +{ + CloseHandle(handle); +} + +#else + +void *_openfile(const char *filename, int flags) +{ + printf("_openfile %s %x\n", filename, flags); + + if (flags & O_WRONLY) + return fopen64(filename, "wb"); + else + return fopen64(filename, "rb"); +} + +#include + +u64 _tellfile(void *handle) +{ + u64 cursize = ftell(handle); + if (cursize == -1) + { + // try 64bit + cursize = ftello64(handle); + if (cursize < -1) + { + // zero top 32 bits + cursize &= 0xffffffff; + } + } + return cursize; +} + +int _seekfile(void *handle, u64 offset, int whence) +{ + int seekerr = fseeko64(handle, offset, whence); + + if (seekerr == -1) printf("failed to seek\n"); + + return seekerr; +} + +int _readfile(void *handle, void *dst, int size) +{ + return fread(dst, 1, size, handle); +} + +int _writefile(void *handle, void *src, int size) +{ + return fwrite(src, 1, size, handle); +} + +void _closefile(void *handle) +{ + fclose(handle); +} + +#endif + +int detect(isoFile *iso) +{ + u8 buf[2448]; + struct cdVolDesc *volDesc; + + if (isoReadBlock(iso, buf, 16) == -1) return -1; + + volDesc = (struct cdVolDesc *)(buf + 24); + + if (strncmp((char*)volDesc->volID, "CD001", 5)) return 0; + + if (volDesc->rootToc.tocSize == 2048) + iso->type = ISOTYPE_CD; + else + iso->type = ISOTYPE_DVD; + + return 1; +} + +int _isoReadZtable(isoFile *iso) +{ + void *handle; + char table[256]; + int size; + + sprintf(table, "%s.table", iso->filename); + handle = _openfile(table, O_RDONLY); + if (handle == NULL) + { + printf("Error loading %s\n", table); + return -1; + } + + _seekfile(handle, 0, SEEK_END); + size = _tellfile(handle); + iso->Ztable = (char*)malloc(size); + + if (iso->Ztable == NULL) + { + return -1; + } + + _seekfile(handle, 0, SEEK_SET); + _readfile(handle, iso->Ztable, size); + _closefile(handle); + + iso->blocks = size / 6; + + return 0; +} + +int _isoReadZ2table(isoFile *iso) +{ + void *handle; + char table[256]; + u32 *Ztable; + int ofs; + int size; + int i; + + sprintf(table, "%s.table", iso->filename); + handle = _openfile(table, O_RDONLY); + + if (handle == NULL) + { + printf("Error loading %s\n", table); + return -1; + } + + _seekfile(handle, 0, SEEK_END); + size = _tellfile(handle); + Ztable = (u32*)malloc(size); + + if (Ztable == NULL) + { + return -1; + } + + _seekfile(handle, 0, SEEK_SET); + _readfile(handle, Ztable, size); + _closefile(handle); + + iso->Ztable = (char*)malloc(iso->blocks * 8); + + if (iso->Ztable == NULL) + { + return -1; + } + + ofs = 16; + + for (i = 0; i < iso->blocks; i++) + { + *(u32*)&iso->Ztable[i*8+0] = ofs; + *(u32*)&iso->Ztable[i*8+4] = Ztable[i]; + ofs += Ztable[i]; + } + + free(Ztable); + + return 0; +} + +int _isoReadBZ2table(isoFile *iso) +{ + void *handle; + char table[256]; + u32 *Ztable; + int ofs; + int size; + int i; + + sprintf(table, "%s.table", iso->filename); + handle = _openfile(table, O_RDONLY); + if (handle == NULL) + { + printf("Error loading %s\n", table); + return -1; + } + + _seekfile(handle, 0, SEEK_END); + size = _tellfile(handle); + Ztable = (u32*)malloc(size); + if (Ztable == NULL) return -1; + + _seekfile(handle, 0, SEEK_SET); + _readfile(handle, Ztable, size); + _closefile(handle); + + iso->Ztable = (char*)malloc(iso->blocks * 8); + if (iso->Ztable == NULL) return -1; + + ofs = 16; + + for (i = 0; i < iso->blocks / 16; i++) + { + *(u32*)&iso->Ztable[i*8+0] = ofs; + *(u32*)&iso->Ztable[i*8+4] = Ztable[i]; + ofs += Ztable[i]; + } + + if (iso->blocks & 0xf) + { + *(u32*)&iso->Ztable[i*8+0] = ofs; + *(u32*)&iso->Ztable[i*8+4] = Ztable[i]; + ofs += Ztable[i]; + } + + free(Ztable); + + return 0; +} + +int _isoReadDtable(isoFile *iso) +{ + int ret; + int i; + + _seekfile(iso->handle, 0, SEEK_END); + iso->dtablesize = (_tellfile(iso->handle) - 16) / (iso->blocksize + 4); + iso->dtable = (u32*)malloc(iso->dtablesize * 4); + + for (i = 0; i < iso->dtablesize; i++) + { + _seekfile(iso->handle, 16 + (iso->blocksize + 4)*i, SEEK_SET); + ret = _readfile(iso->handle, &iso->dtable[i], 4); + if (ret < 4) return -1; + } + + return 0; +} + +int isoDetect(isoFile *iso) // based on florin's CDVDbin detection code :) +{ + char buf[32]; + int len; + + iso->type = ISOTYPE_ILLEGAL; + + len = strlen(iso->filename); + if (len >= 2) + { + if (!strncmp(iso->filename + (len - 2), ".Z", 2)) + { + iso->flags = ISOFLAGS_Z; + iso->blocksize = 2352; + _isoReadZtable(iso); + return detect(iso) == 1 ? 0 : -1; + } + } + + _seekfile(iso->handle, 0, SEEK_SET); + _readfile(iso->handle, buf, 4); + + if (strncmp(buf, "BDV2", 4) == 0) + { + iso->flags = ISOFLAGS_BLOCKDUMP; + _readfile(iso->handle, &iso->blocksize, 4); + _readfile(iso->handle, &iso->blocks, 4); + _readfile(iso->handle, &iso->blockofs, 4); + _isoReadDtable(iso); + return detect(iso) == 1 ? 0 : -1; + } + else if (strncmp(buf, "Z V2", 4) == 0) + { + iso->flags = ISOFLAGS_Z2; + _readfile(iso->handle, &iso->blocksize, 4); + _readfile(iso->handle, &iso->blocks, 4); + _readfile(iso->handle, &iso->blockofs, 4); + _isoReadZ2table(iso); + return detect(iso) == 1 ? 0 : -1; + } + else if (strncmp(buf, "BZV2", 4) == 0) + { + iso->flags = ISOFLAGS_BZ2; + _readfile(iso->handle, &iso->blocksize, 4); + _readfile(iso->handle, &iso->blocks, 4); + _readfile(iso->handle, &iso->blockofs, 4); + iso->buflsn = -1; + iso->buffer = (u8*)malloc(iso->blocksize * 16); + if (iso->buffer == NULL) return -1; + _isoReadBZ2table(iso); + return detect(iso) == 1 ? 0 : -1; + } + else + { + iso->blocks = 16; + } + + // ISO 2048 + iso->blocksize = 2048; + iso->offset = 0; + iso->blockofs = 24; + if (detect(iso) == 1) return 0; + + // RAW 2336 + iso->blocksize = 2336; + iso->offset = 0; + iso->blockofs = 16; + if (detect(iso) == 1) return 0; + + // RAW 2352 + iso->blocksize = 2352; + iso->offset = 0; + iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // RAWQ 2448 + iso->blocksize = 2448; + iso->offset = 0; + iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // NERO ISO 2048 + iso->blocksize = 2048; + iso->offset = 150 * 2048; + iso->blockofs = 24; + if (detect(iso) == 1) return 0; + + // NERO RAW 2352 + iso->blocksize = 2352; + iso->offset = 150 * 2048; + iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // NERO RAWQ 2448 + iso->blocksize = 2448; + iso->offset = 150 * 2048; + iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // ISO 2048 + iso->blocksize = 2048; + iso->offset = -8; + iso->blockofs = 24; + if (detect(iso) == 1) return 0; + + // RAW 2352 + iso->blocksize = 2352; + iso->offset = -8; + iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // RAWQ 2448 + iso->blocksize = 2448; + iso->offset = -8; + iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + iso->offset = 0; + iso->blocksize = 2352; + iso->type = ISOTYPE_AUDIO; + return 0; + + return -1; +} + +isoFile *isoOpen(const char *filename) +{ + isoFile *iso; + int i; + + iso = (isoFile*)malloc(sizeof(isoFile)); + if (iso == NULL) return NULL; + + memset(iso, 0, sizeof(isoFile)); + strcpy(iso->filename, filename); + + iso->handle = _openfile(iso->filename, O_RDONLY); + if (iso->handle == NULL) + { + printf("Error loading %s\n", iso->filename); + return NULL; + } + + if (isoDetect(iso) == -1) return NULL; + + printf("detected blocksize = %d\n", iso->blocksize); + + if (strlen(iso->filename) > 3 && strncmp(iso->filename + (strlen(iso->filename) - 3), "I00", 3) == 0) + { + _closefile(iso->handle); + iso->flags |= ISOFLAGS_MULTI; + iso->blocks = 0; + for (i = 0; i < 8; i++) + { + iso->filename[strlen(iso->filename) - 1] = '0' + i; + iso->multih[i].handle = _openfile(iso->filename, O_RDONLY); + if (iso->multih[i].handle == NULL) + { + break; + } + iso->multih[i].slsn = iso->blocks; + _seekfile(iso->multih[i].handle, 0, SEEK_END); + iso->blocks += (u32)((_tellfile(iso->multih[i].handle) - iso->offset) / + (iso->blocksize)); + iso->multih[i].elsn = iso->blocks - 1; + } + + if (i == 0) + { + return NULL; + } + } + + if (iso->flags == 0) + { + _seekfile(iso->handle, 0, SEEK_END); + iso->blocks = (u32)((_tellfile(iso->handle) - iso->offset) / + (iso->blocksize)); + } + + + printf("isoOpen: %s ok\n", iso->filename); + printf("offset = %d\n", iso->offset); + printf("blockofs = %d\n", iso->blockofs); + printf("blocksize = %d\n", iso->blocksize); + printf("blocks = %d\n", iso->blocks); + printf("type = %d\n", iso->type); + + return iso; +} + +isoFile *isoCreate(const char *filename, int flags) +{ + isoFile *iso; + char Zfile[256]; + + iso = (isoFile*)malloc(sizeof(isoFile)); + if (iso == NULL) return NULL; + + memset(iso, 0, sizeof(isoFile)); + strcpy(iso->filename, filename); + iso->flags = flags; + iso->offset = 0; + iso->blockofs = 24; + iso->blocksize = CD_FRAMESIZE_RAW; + iso->blocksize = 2048; + + if (iso->flags & (ISOFLAGS_Z | ISOFLAGS_Z2 | ISOFLAGS_BZ2)) + { + sprintf(Zfile, "%s.table", iso->filename); + iso->htable = _openfile(Zfile, O_WRONLY); + if (iso->htable == NULL) + { + return NULL; + } + } + + iso->handle = _openfile(iso->filename, O_WRONLY | O_CREAT); + if (iso->handle == NULL) + { + printf("Error loading %s\n", iso->filename); + return NULL; + } + printf("isoCreate: %s ok\n", iso->filename); + printf("offset = %d\n", iso->offset); + + return iso; +} + +int isoSetFormat(isoFile *iso, int blockofs, int blocksize, int blocks) +{ + iso->blocksize = blocksize; + iso->blocks = blocks; + iso->blockofs = blockofs; + printf("blockofs = %d\n", iso->blockofs); + printf("blocksize = %d\n", iso->blocksize); + printf("blocks = %d\n", iso->blocks); + if (iso->flags & ISOFLAGS_Z2) + { + if (_writefile(iso->handle, "Z V2", 4) < 4) return -1; + if (_writefile(iso->handle, &blocksize, 4) < 4) return -1; + if (_writefile(iso->handle, &blocks, 4) < 4) return -1; + if (_writefile(iso->handle, &blockofs, 4) < 4) return -1; + } + if (iso->flags & ISOFLAGS_BZ2) + { + if (_writefile(iso->handle, "BZV2", 4) < 4) return -1; + if (_writefile(iso->handle, &blocksize, 4) < 4) return -1; + if (_writefile(iso->handle, &blocks, 4) < 4) return -1; + if (_writefile(iso->handle, &blockofs, 4) < 4) return -1; + iso->buflsn = -1; + iso->buffer = (u8*)malloc(iso->blocksize * 16); + if (iso->buffer == NULL) return -1; + } + if (iso->flags & ISOFLAGS_BLOCKDUMP) + { + if (_writefile(iso->handle, "BDV2", 4) < 4) return -1; + if (_writefile(iso->handle, &blocksize, 4) < 4) return -1; + if (_writefile(iso->handle, &blocks, 4) < 4) return -1; + if (_writefile(iso->handle, &blockofs, 4) < 4) return -1; + } + + return 0; +} + +s32 MSFtoLSN(u8 *Time) +{ + u32 lsn; + + lsn = Time[2]; + lsn += (Time[1] - 2) * 75; + lsn += Time[0] * 75 * 60; + return lsn; +} + +void LSNtoMSF(u8 *Time, s32 lsn) +{ + u8 m, s, f; + + lsn += 150; + m = lsn / 4500; // minuten + lsn = lsn - m * 4500; // minuten rest + s = lsn / 75; // sekunden + f = lsn - (s * 75); // sekunden rest + Time[0] = itob(m); + Time[1] = itob(s); + Time[2] = itob(f); +} + +int _isoReadBlock(isoFile *iso, u8 *dst, int lsn) +{ + u64 ofs = (u64)lsn * iso->blocksize + iso->offset; + int ret; + +// printf("_isoReadBlock %d, blocksize=%d, blockofs=%d\n", lsn, iso->blocksize, iso->blockofs); + memset(dst, 0, iso->blockofs); + _seekfile(iso->handle, ofs, SEEK_SET); + ret = _readfile(iso->handle, dst + iso->blockofs, iso->blocksize); + if (ret < iso->blocksize) + { + printf("read error %d\n", ret); + return -1; + } + + return 0; +} + +int _isoReadBlockZ(isoFile *iso, u8 *dst, int lsn) +{ + u32 pos, p; + uLongf size; + u8 Zbuf[CD_FRAMESIZE_RAW*2]; + int ret; + +// printf("_isoReadBlockZ %d, %d\n", lsn, iso->blocksize); + pos = *(unsigned long*) & iso->Ztable[lsn * 6]; + p = *(unsigned short*) & iso->Ztable[lsn * 6 + 4]; +// printf("%d, %d\n", pos, p); + _seekfile(iso->handle, pos, SEEK_SET); + ret = _readfile(iso->handle, Zbuf, p); + if (ret < p) + { + printf("error reading block!!\n"); + return -1; + } + + size = CD_FRAMESIZE_RAW; + uncompress(dst, &size, Zbuf, p); + + return 0; +} + +int _isoReadBlockZ2(isoFile *iso, u8 *dst, int lsn) +{ + u32 pos, p; + uLongf size; + u8 Zbuf[16*1024]; + int ret; + +// printf("_isoReadBlockZ2 %d, %d\n", lsn, iso->blocksize); + pos = *(u32*) & iso->Ztable[lsn*8]; + p = *(u32*) & iso->Ztable[lsn*8+4]; +// printf("%d, %d\n", pos, p); + _seekfile(iso->handle, pos, SEEK_SET); + ret = _readfile(iso->handle, Zbuf, p); + if (ret < p) + { + printf("error reading block!!\n"); + return -1; + } + + size = iso->blocksize; + uncompress(dst + iso->blockofs, &size, Zbuf, p); + + return 0; +} + +int _isoReadBlockBZ2(isoFile *iso, u8 *dst, int lsn) +{ + u32 pos, p; + u32 size; + u8 Zbuf[64*1024]; + int ret; + + if ((lsn / 16) == iso->buflsn) + { + memset(dst, 0, iso->blockofs); + memcpy(dst + iso->blockofs, iso->buffer + (iso->blocksize*(lsn&0xf)), iso->blocksize); + return 0; + } + + iso->buflsn = lsn / 16; +// printf("_isoReadBlockBZ2 %d, %d\n", lsn, iso->blocksize); + pos = *(u32*) & iso->Ztable[(lsn/16)*8]; + p = *(u32*) & iso->Ztable[(lsn/16)*8+4]; +// printf("%d, %d\n", pos, p); + _seekfile(iso->handle, pos, SEEK_SET); + ret = _readfile(iso->handle, Zbuf, p); + + if (ret < p) + { + printf("error reading block!!\n"); + return -1; + } + + size = iso->blocksize * 64; + ret = BZ2_bzBuffToBuffDecompress((s8*)iso->buffer, &size, (s8*)Zbuf, p, 0, 0); + + if (ret != BZ_OK) + { + printf("_isoReadBlockBZ2 %d, %d\n", lsn, iso->blocksize); + printf("%d, %d\n", pos, p); + printf("error on BZ2: %d\n", ret); + } + + memset(dst, 0, iso->blockofs); + memcpy(dst + iso->blockofs, iso->buffer + (iso->blocksize*(lsn&0xf)), iso->blocksize); + + return 0; +} + +int _isoReadBlockD(isoFile *iso, u8 *dst, int lsn) +{ + int ret; + int i; + +// printf("_isoReadBlockD %d, blocksize=%d, blockofs=%d\n", lsn, iso->blocksize, iso->blockofs); + memset(dst, 0, iso->blockofs); + for (i = 0; i < iso->dtablesize;i++) + { + if (iso->dtable[i] != lsn) continue; + + _seekfile(iso->handle, 16 + i*(iso->blocksize + 4) + 4, SEEK_SET); + ret = _readfile(iso->handle, dst + iso->blockofs, iso->blocksize); + if (ret < iso->blocksize) return -1; + + return 0; + } + printf("block %d not found in dump\n", lsn); + + return -1; +} + +int _isoReadBlockM(isoFile *iso, u8 *dst, int lsn) +{ + u64 ofs; + int ret; + int i; + + for (i = 0; i < 8; i++) + { + if (lsn >= iso->multih[i].slsn && + lsn <= iso->multih[i].elsn) + { + break; + } + } + if (i == 8) return -1; + + ofs = (u64)(lsn - iso->multih[i].slsn) * iso->blocksize + iso->offset; +// printf("_isoReadBlock %d, blocksize=%d, blockofs=%d\n", lsn, iso->blocksize, iso->blockofs); + memset(dst, 0, iso->blockofs); + _seekfile(iso->multih[i].handle, ofs, SEEK_SET); + ret = _readfile(iso->multih[i].handle, dst + iso->blockofs, iso->blocksize); + + if (ret < iso->blocksize) + { + printf("read error %d\n", ret); + return -1; + } + + return 0; +} + +int isoReadBlock(isoFile *iso, u8 *dst, int lsn) +{ + int ret; + + if (lsn > iso->blocks) + { + printf("isoReadBlock: %d > %d\n", lsn, iso->blocks); + return -1; + } + + if (iso->flags & ISOFLAGS_Z) + ret = _isoReadBlockZ(iso, dst, lsn); + else if (iso->flags & ISOFLAGS_Z2) + ret = _isoReadBlockZ2(iso, dst, lsn); + else if (iso->flags & ISOFLAGS_BLOCKDUMP) + ret = _isoReadBlockD(iso, dst, lsn); + else if (iso->flags & ISOFLAGS_MULTI) + ret = _isoReadBlockM(iso, dst, lsn); + else if (iso->flags & ISOFLAGS_BZ2) + ret = _isoReadBlockBZ2(iso, dst, lsn); + else + ret = _isoReadBlock(iso, dst, lsn); + + if (ret == -1) return ret; + + if (iso->type == ISOTYPE_CD) + { + LSNtoMSF(dst + 12, lsn); + dst[15] = 2; + } + + return 0; +} + + +int _isoWriteBlock(isoFile *iso, u8 *src, int lsn) +{ + u64 ofs = (u64)lsn * iso->blocksize + iso->offset; + int ret; + +// printf("_isoWriteBlock %d (ofs=%d)\n", iso->blocksize, ofs); + _seekfile(iso->handle, ofs, SEEK_SET); + ret = _writefile(iso->handle, src + iso->blockofs, iso->blocksize); +// printf("_isoWriteBlock %d\n", ret); + if (ret < iso->blocksize) return -1; + + return 0; +} + +int _isoWriteBlockZ(isoFile *iso, u8 *src, int lsn) +{ + u32 pos; + uLongf size; + u8 Zbuf[CD_FRAMESIZE_RAW]; + int ret; + +// printf("_isoWriteBlockZ %d\n", iso->blocksize); + size = 2352; + compress(Zbuf, &size, src, 2352); +// printf("_isoWriteBlockZ %d\n", size); + + pos = (u32)_tellfile(iso->handle); + ret = _writefile(iso->htable, &pos, 4); + if (ret < 4) return -1; + ret = _writefile(iso->htable, &size, 2); + if (ret < 2) return -1; + + ret = _writefile(iso->handle, Zbuf, size); +// printf("_isoWriteBlockZ %d\n", ret); + if (ret < size) + { + printf("error writing block!!\n"); + return -1; + } + + return 0; +} + +int _isoWriteBlockZ2(isoFile *iso, u8 *src, int lsn) +{ + uLongf size; + u8 Zbuf[1024*16]; + int ret; + +// printf("_isoWriteBlockZ %d\n", iso->blocksize); + size = 1024 * 16; + compress(Zbuf, &size, src + iso->blockofs, iso->blocksize); +// printf("_isoWriteBlockZ %d\n", size); + + ret = _writefile(iso->htable, (u8*) & size, 4); + if (ret < 4) return -1; + ret = _writefile(iso->handle, Zbuf, size); +// printf("_isoWriteBlockZ %d\n", ret); + if (ret < size) + { + printf("error writing block!!\n"); + return -1; + } + + return 0; +} + +int _isoWriteBlockD(isoFile *iso, u8 *src, int lsn) +{ + int ret; + +// printf("_isoWriteBlock %d (ofs=%d)\n", iso->blocksize, ofs); + ret = _writefile(iso->handle, &lsn, 4); + if (ret < 4) return -1; + ret = _writefile(iso->handle, src + iso->blockofs, iso->blocksize); +// printf("_isoWriteBlock %d\n", ret); + if (ret < iso->blocksize) return -1; + + return 0; +} + +int _isoWriteBlockBZ2(isoFile *iso, u8 *src, int lsn) +{ + u32 size; + u8 Zbuf[64*1024]; + int blocks; + int ret; + + memcpy(iso->buffer + (iso->blocksize*(lsn&0xf)), src + iso->blockofs, iso->blocksize); + + if (lsn == (iso->blocks - 1)) + { + blocks = (lsn & 0xf) + 1; + } + else + { + blocks = 16; + if ((lsn & 0xf) != 0xf) return 0; + } + +// printf("_isoWriteBlockBZ2 %d\n", iso->blocksize); + size = 64 * 1024; + ret = BZ2_bzBuffToBuffCompress((s8*)Zbuf, (u32*) & size, (s8*)iso->buffer, iso->blocksize * blocks, 9, 0, 30); + + if (ret != BZ_OK) + { + printf("error on BZ2: %d\n", ret); + } + +// printf("_isoWriteBlockBZ2 %d\n", size); + + ret = _writefile(iso->htable, (u8*) & size, 4); + if (ret < 4) return -1; + ret = _writefile(iso->handle, Zbuf, size); +// printf("_isoWriteBlockZ %d\n", ret); + + if (ret < size) + { + printf("error writing block!!\n"); + return -1; + } + + return 0; +} + +int isoWriteBlock(isoFile *iso, u8 *src, int lsn) +{ + int ret; + + if (iso->flags & ISOFLAGS_Z) + ret = _isoWriteBlockZ(iso, src, lsn); + else if (iso->flags & ISOFLAGS_Z2) + ret = _isoWriteBlockZ2(iso, src, lsn); + else if (iso->flags & ISOFLAGS_BLOCKDUMP) + ret = _isoWriteBlockD(iso, src, lsn); + else if (iso->flags & ISOFLAGS_BZ2) + ret = _isoWriteBlockBZ2(iso, src, lsn); + else + ret = _isoWriteBlock(iso, src, lsn); + + if (ret == -1) return ret; + return 0; +} + +void isoClose(isoFile *iso) +{ + if (iso->handle) _closefile(iso->handle); + if (iso->htable) _closefile(iso->htable); + if (iso->buffer) free(iso->buffer); + + free(iso); +} + diff --git a/plugins/CDVDiso/src/libiso.h b/plugins/CDVDiso/src/libiso.h index 2d3057815b..48249837ba 100644 --- a/plugins/CDVDiso/src/libiso.h +++ b/plugins/CDVDiso/src/libiso.h @@ -1,67 +1,67 @@ -#ifndef __LIBISO_H__ -#define __LIBISO_H__ - -#ifdef _MSC_VER -#pragma warning(disable:4018) -#endif - -#define ISOTYPE_ILLEGAL 0 -#define ISOTYPE_CD 1 -#define ISOTYPE_DVD 2 -#define ISOTYPE_AUDIO 3 - -#define ISOFLAGS_Z 0x0001 -#define ISOFLAGS_Z2 0x0002 -#define ISOFLAGS_BLOCKDUMP 0x0004 -#define ISOFLAGS_MULTI 0x0008 -#define ISOFLAGS_BZ2 0x0010 - -#define CD_FRAMESIZE_RAW 2352 -#define DATA_SIZE (CD_FRAMESIZE_RAW-12) - -#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ -#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ - -typedef struct -{ - u32 slsn; - u32 elsn; - void *handle; -} _multih; - -typedef struct -{ - char filename[256]; - u32 type; - u32 flags; - u32 offset; - u32 blockofs; - u32 blocksize; - u32 blocks; - void *handle; - void *htable; - char *Ztable; - u32 *dtable; - int dtablesize; - _multih multih[8]; - int buflsn; - u8 *buffer; -} isoFile; - - -isoFile *isoOpen(const char *filename); -isoFile *isoCreate(const char *filename, int mode); -int isoSetFormat(isoFile *iso, int blockofs, int blocksize, int blocks); -int isoDetect(isoFile *iso); -int isoReadBlock(isoFile *iso, u8 *dst, int lsn); -int isoWriteBlock(isoFile *iso, u8 *src, int lsn); -void isoClose(isoFile *iso); - -void *_openfile(const char *filename, int flags); -u64 _tellfile(void *handle); -int _seekfile(void *handle, u64 offset, int whence); -int _readfile(void *handle, void *dst, int size); -int _writefile(void *handle, void *src, int size); -void _closefile(void *handle); - -#endif /* __LIBISO_H__ */ +#ifndef __LIBISO_H__ +#define __LIBISO_H__ + +#ifdef _MSC_VER +#pragma warning(disable:4018) +#endif + +#define ISOTYPE_ILLEGAL 0 +#define ISOTYPE_CD 1 +#define ISOTYPE_DVD 2 +#define ISOTYPE_AUDIO 3 + +#define ISOFLAGS_Z 0x0001 +#define ISOFLAGS_Z2 0x0002 +#define ISOFLAGS_BLOCKDUMP 0x0004 +#define ISOFLAGS_MULTI 0x0008 +#define ISOFLAGS_BZ2 0x0010 + +#define CD_FRAMESIZE_RAW 2352 +#define DATA_SIZE (CD_FRAMESIZE_RAW-12) + +#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ +#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ + +typedef struct +{ + u32 slsn; + u32 elsn; + void *handle; +} _multih; + +typedef struct +{ + char filename[256]; + u32 type; + u32 flags; + u32 offset; + u32 blockofs; + u32 blocksize; + u32 blocks; + void *handle; + void *htable; + char *Ztable; + u32 *dtable; + int dtablesize; + _multih multih[8]; + int buflsn; + u8 *buffer; +} isoFile; + + +isoFile *isoOpen(const char *filename); +isoFile *isoCreate(const char *filename, int mode); +int isoSetFormat(isoFile *iso, int blockofs, int blocksize, int blocks); +int isoDetect(isoFile *iso); +int isoReadBlock(isoFile *iso, u8 *dst, int lsn); +int isoWriteBlock(isoFile *iso, u8 *src, int lsn); +void isoClose(isoFile *iso); + +void *_openfile(const char *filename, int flags); +u64 _tellfile(void *handle); +int _seekfile(void *handle, u64 offset, int whence); +int _readfile(void *handle, void *dst, int size); +int _writefile(void *handle, void *src, int size); +void _closefile(void *handle); + +#endif /* __LIBISO_H__ */ diff --git a/plugins/CDVDiso/src/mkiso/Makefile b/plugins/CDVDiso/src/mkiso/Makefile index 0954b9e918..317097597a 100644 --- a/plugins/CDVDiso/src/mkiso/Makefile +++ b/plugins/CDVDiso/src/mkiso/Makefile @@ -1,27 +1,27 @@ - -CC = gcc - -MKISO = mkiso -CFLAGS = -fPIC -Wall -O2 -fomit-frame-pointer -I.. -I. -D__LINUX__ -I../3rdparty/zlib -OBJS = mkiso.o ../libiso.o -LIBS = -OBJS+= ../3rdparty/zlib/adler32.o ../3rdparty/zlib/compress.o ../3rdparty/zlib/crc32.o ../3rdparty/zlib/gzio.o ../3rdparty/zlib/uncompr.o \ -../3rdparty/zlib/deflate.o ../3rdparty/zlib/trees.o ../3rdparty/zlib/zutil.o ../3rdparty/zlib/inflate.o ../3rdparty/zlib/infback.o ../3rdparty/zlib/inftrees.o \ -../3rdparty/zlib/inffast.o - -DEPS:= $(OBJS:.o=.d) - -all: mkiso - -mkiso: ${OBJS} - rm -f ${MKISO} - ${CC} ${CFLAGS} ${OBJS} -o ${MKISO} ${LIBS} - strip ${MKISO} - -clean: - rm -f ${OBJS} ${DEPS} ${MKISO} - -%.o: %.c - ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) - --include ${DEPS} + +CC = gcc + +MKISO = mkiso +CFLAGS = -fPIC -Wall -O2 -fomit-frame-pointer -I.. -I. -D__LINUX__ -I../3rdparty/zlib +OBJS = mkiso.o ../libiso.o +LIBS = +OBJS+= ../3rdparty/zlib/adler32.o ../3rdparty/zlib/compress.o ../3rdparty/zlib/crc32.o ../3rdparty/zlib/gzio.o ../3rdparty/zlib/uncompr.o \ +../3rdparty/zlib/deflate.o ../3rdparty/zlib/trees.o ../3rdparty/zlib/zutil.o ../3rdparty/zlib/inflate.o ../3rdparty/zlib/infback.o ../3rdparty/zlib/inftrees.o \ +../3rdparty/zlib/inffast.o + +DEPS:= $(OBJS:.o=.d) + +all: mkiso + +mkiso: ${OBJS} + rm -f ${MKISO} + ${CC} ${CFLAGS} ${OBJS} -o ${MKISO} ${LIBS} + strip ${MKISO} + +clean: + rm -f ${OBJS} ${DEPS} ${MKISO} + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +-include ${DEPS} diff --git a/plugins/CDVDiso/src/mkiso/Makefile.mingw b/plugins/CDVDiso/src/mkiso/Makefile.mingw deleted file mode 100644 index c85439923e..0000000000 --- a/plugins/CDVDiso/src/mkiso/Makefile.mingw +++ /dev/null @@ -1,31 +0,0 @@ - -CC = gcc - -MKISO = mkiso.exe -OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing -CFLAGS = -Wall ${OPTIMIZE} -I.. -I. -D__WIN32__ -I../zlib -I../bzip2 -OBJS = mkiso.o ../libiso.o -LIBS = -OBJS+= ../zlib/adler32.o ../zlib/compress.o ../zlib/crc32.o ../zlib/gzio.o ../zlib/uncompr.o ../zlib/deflate.o ../zlib/trees.o \ - ../zlib/zutil.o ../zlib/inflate.o ../zlib/infback.o ../zlib/inftrees.o ../zlib/inffast.o -OBJS+= ../bzip2/blocksort.o ../bzip2/huffman.o \ - ../bzip2/crctable.o ../bzip2/randtable.o \ - ../bzip2/compress.o ../bzip2/decompress.o \ - ../bzip2/bzlib.o - -DEPS:= $(OBJS:.o=.d) - -all: mkiso - -mkiso: ${OBJS} - rm -f ${MKISO} - ${CC} ${CFLAGS} ${OBJS} -o ${MKISO} ${LIBS} - strip ${MKISO} - -clean: - rm -f ${OBJS} ${DEPS} ${MKISO} - -%.o: %.c - ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) - --include ${DEPS} diff --git a/plugins/CDVDiso/src/mkiso/mkiso.c b/plugins/CDVDiso/src/mkiso/mkiso.c index 2a2ad5e1e9..df31a048a3 100644 --- a/plugins/CDVDiso/src/mkiso/mkiso.c +++ b/plugins/CDVDiso/src/mkiso/mkiso.c @@ -1,172 +1,172 @@ -/* CDVDiso - * Copyright (C) 2002-2004 CDVDiso 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include - -#include "CDVDiso.h" - - -void Compress(char *filename, int mode) -{ - struct stat buf; - u32 lsn; - u8 cdbuff[1024*16]; - char Zfile[256]; - int ret = 0; - isoFile *src; - isoFile *dst; - - if (mode == 1) - { - sprintf(Zfile, "%s.Z2", filename); - } - else - { - sprintf(Zfile, "%s.BZ2", filename); - } - - if (stat(Zfile, &buf) != -1) - { - printf("'%s' already exists\n", Zfile); - return; - /* sprintf(str, "'%s' already exists, overwrite?", Zfile); - if (MessageBox(hDlg, str, "Question", MB_YESNO) != IDYES) { - return; - }*/ - } - - printf("src %s; dst %s\n", filename, Zfile); - src = isoOpen(filename); - if (src == NULL) return; - - if (mode == 1) - { - dst = isoCreate(Zfile, ISOFLAGS_Z2); - } - else - { - dst = isoCreate(Zfile, ISOFLAGS_BZ2); - } - isoSetFormat(dst, src->blockofs, src->blocksize, src->blocks); - if (dst == NULL) return; - - for (lsn = 0; lsn < src->blocks; lsn++) - { - printf("block %d ", lsn); - putchar(13); - fflush(stdout); - ret = isoReadBlock(src, cdbuff, lsn); - if (ret == -1) break; - ret = isoWriteBlock(dst, cdbuff, lsn); - if (ret == -1) break; - } - isoClose(src); - isoClose(dst); - - if (ret == -1) - { - printf("Error compressing iso image\n"); - } - else - { - printf("Iso image compressed OK\n"); - } -} - -void Decompress(char *filename) -{ - struct stat buf; - char file[256]; - u8 cdbuff[10*2352]; - u32 lsn; - isoFile *src; - isoFile *dst; - int ret = 0; - - src = isoOpen(filename); - if (src == NULL) return; - - strcpy(file, filename); - if (src->flags & ISOFLAGS_Z) - file[strlen(file) - 2] = 0; - else if (src->flags & ISOFLAGS_Z2) - file[strlen(file) - 3] = 0; - else if (src->flags & ISOFLAGS_BZ2) - file[strlen(file) - 3] = 0; - else - { - printf("%s is not a compressed image\n", filename); - return; - } - - if (stat(file, &buf) != -1) - { - char str[256]; - sprintf(str, "'%s' already exists", file); - isoClose(src); - return; - } - - dst = isoCreate(file, 0); - if (dst == NULL) return; - isoSetFormat(dst, src->blockofs, src->blocksize, src->blocks); - - for (lsn = 0; lsn < src->blocks; lsn++) - { - printf("block %d ", lsn); - putchar(13); - fflush(stdout); - ret = isoReadBlock(src, cdbuff, lsn); - if (ret == -1) break; - ret = isoWriteBlock(dst, cdbuff, lsn); - if (ret == -1) break; - } - - isoClose(src); - isoClose(dst); - - if (ret == -1) - printf("Error decompressing iso image\n"); - else - printf("Iso image decompressed OK\n"); -} - - -int main(int argc, char *argv[]) -{ - if (argc < 3) return 0; - - switch (argv[1][0]) - { - case 'c': - Compress(argv[2], 1); - break; - case 'C': - Compress(argv[2], 2); - break; - case 'd': - Decompress(argv[2]); - break; - default: break; - } - - return 0; -} +/* CDVDiso + * Copyright (C) 2002-2004 CDVDiso 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include "CDVDiso.h" + + +void Compress(char *filename, int mode) +{ + struct stat buf; + u32 lsn; + u8 cdbuff[1024*16]; + char Zfile[256]; + int ret = 0; + isoFile *src; + isoFile *dst; + + if (mode == 1) + { + sprintf(Zfile, "%s.Z2", filename); + } + else + { + sprintf(Zfile, "%s.BZ2", filename); + } + + if (stat(Zfile, &buf) != -1) + { + printf("'%s' already exists\n", Zfile); + return; + /* sprintf(str, "'%s' already exists, overwrite?", Zfile); + if (MessageBox(hDlg, str, "Question", MB_YESNO) != IDYES) { + return; + }*/ + } + + printf("src %s; dst %s\n", filename, Zfile); + src = isoOpen(filename); + if (src == NULL) return; + + if (mode == 1) + { + dst = isoCreate(Zfile, ISOFLAGS_Z2); + } + else + { + dst = isoCreate(Zfile, ISOFLAGS_BZ2); + } + isoSetFormat(dst, src->blockofs, src->blocksize, src->blocks); + if (dst == NULL) return; + + for (lsn = 0; lsn < src->blocks; lsn++) + { + printf("block %d ", lsn); + putchar(13); + fflush(stdout); + ret = isoReadBlock(src, cdbuff, lsn); + if (ret == -1) break; + ret = isoWriteBlock(dst, cdbuff, lsn); + if (ret == -1) break; + } + isoClose(src); + isoClose(dst); + + if (ret == -1) + { + printf("Error compressing iso image\n"); + } + else + { + printf("Iso image compressed OK\n"); + } +} + +void Decompress(char *filename) +{ + struct stat buf; + char file[256]; + u8 cdbuff[10*2352]; + u32 lsn; + isoFile *src; + isoFile *dst; + int ret = 0; + + src = isoOpen(filename); + if (src == NULL) return; + + strcpy(file, filename); + if (src->flags & ISOFLAGS_Z) + file[strlen(file) - 2] = 0; + else if (src->flags & ISOFLAGS_Z2) + file[strlen(file) - 3] = 0; + else if (src->flags & ISOFLAGS_BZ2) + file[strlen(file) - 3] = 0; + else + { + printf("%s is not a compressed image\n", filename); + return; + } + + if (stat(file, &buf) != -1) + { + char str[256]; + sprintf(str, "'%s' already exists", file); + isoClose(src); + return; + } + + dst = isoCreate(file, 0); + if (dst == NULL) return; + isoSetFormat(dst, src->blockofs, src->blocksize, src->blocks); + + for (lsn = 0; lsn < src->blocks; lsn++) + { + printf("block %d ", lsn); + putchar(13); + fflush(stdout); + ret = isoReadBlock(src, cdbuff, lsn); + if (ret == -1) break; + ret = isoWriteBlock(dst, cdbuff, lsn); + if (ret == -1) break; + } + + isoClose(src); + isoClose(dst); + + if (ret == -1) + printf("Error decompressing iso image\n"); + else + printf("Iso image decompressed OK\n"); +} + + +int main(int argc, char *argv[]) +{ + if (argc < 3) return 0; + + switch (argv[1][0]) + { + case 'c': + Compress(argv[2], 1); + break; + case 'C': + Compress(argv[2], 2); + break; + case 'd': + Decompress(argv[2]); + break; + default: break; + } + + return 0; +} diff --git a/plugins/CDVDisoEFP/src/Linux/CD.c b/plugins/CDVDisoEFP/src/Linux/CD.c index ab5796c8c3..c9918f29af 100644 --- a/plugins/CDVDisoEFP/src/Linux/CD.c +++ b/plugins/CDVDisoEFP/src/Linux/CD.c @@ -1,367 +1,734 @@ -/* CD.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - -#include // errno -#include // NULL -#include // strerror() -#include // open() -#include // ioctl() -#include // open() -#include // lseek(), open() -#include // close(), lseek(), (sleep()) - -#include // CD/DVD based ioctl() and defines. - -#include "../convert.h" -#include "logfile.h" -#include "device.h" -#include "CD.h" - - -// Constants -u8 *playstationcdname = "PLAYSTATION\0"; -u8 *ps1name = "CD-XA001\0"; - -// CD-ROM temp storage structures (see linux/cdrom.h for details) -struct cdrom_tochdr cdheader; -struct cdrom_tocentry cdtrack; -struct cdrom_subchnl subchannel; -u8 cdtempbuffer[2352]; - -int cdmode; // mode of last CDVDreadTrack call (important for CDs) - - -// Internal Functions - -void InitCDSectorInfo() { - cdmode = -1; -} // END InitSectorInfo(); - - -// Function Calls from CDVD.c - -void InitCDInfo() { - InitCDSectorInfo(); -} // END InitDiscType() - -s32 CDreadTrack(u32 lsn, int mode, u8 *buffer) { - s32 s32result; - -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: CDreadTrack(%i)", lsn); -#endif /* VERBOSE_FUNCTION */ - - s32result = 0; - - if(buffer == NULL) return(-1); - - // The CD way of figuring out where to read. - LBAtoMSF(lsn, buffer); - - switch(mode) { - case CDVD_MODE_2048: - case CDVD_MODE_2328: - case CDVD_MODE_2340: - case CDVD_MODE_2352: - errno = 4; // Interrupted system call... (simulated the first time) - while(errno == 4) { - errno = 0; - s32result = ioctl(devicehandle, CDROMREADRAW, buffer); - } // ENDWHILE- Continually being interrupted by the system... - break; - case CDVD_MODE_2368: // Unimplemented... as yet. - default: -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Unknown Mode %i", mode); -#endif /* VERBOSE_WARNINGS */ - return(-1); // Illegal Read Mode? Abort - break; - } // ENDSWITCH- Which read mode should we choose? - if((s32result == -1) || (errno != 0)) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Error reading CD: %i:%s", errno, strerror(errno)); -#endif /* VERBOSE_WARNINGS */ - InitCDSectorInfo(); - return(-1); - } // ENDIF- Trouble getting a track count? - - cdmode = mode; // Save mode for buffer positioning later. - return(0); // Call accomplished -} // END CDreadTrack() - -s32 CDgetBufferOffset() { -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: CDgetBufferOffset()"); -#endif /* VERBOSE_FUNCTION */ - - switch(cdmode) { - case CDVD_MODE_2048: - return(0+24); - case CDVD_MODE_2328: - return(0+24); - case CDVD_MODE_2340: - return(0+12); - case CDVD_MODE_2352: - return(0+0); - case CDVD_MODE_2368: // Unimplemented... as yet. - default: -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Unknown Mode %i", cdmode); -#endif /* VERBOSE_WARNINGS */ - return(0); // Not to worry. for now. - } // ENDSWITCH- where should we put the buffer pointer? -} // END CDgetBuffer() - -// I, personally, don't see the big deal with SubQ -// However, sooner or later I'll incorporate it into the Cache Buffer system -// (backward compatibility, and all that) -s32 CDreadSubQ(u32 lsn, cdvdSubQ *subq) { - int tempmode; - s32 s32result; - - s32result = 0; - -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: CDreadSubQ()"); -#endif /* VERBOSE_FUNCTION */ - - tempmode = cdmode; - if(tempmode == -1) tempmode = CDVD_MODE_2352; - CDreadTrack(lsn, tempmode, cdtempbuffer); - if((s32result == -1) || (errno != 0)) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Error prepping CD SubQ: %i:%s", errno, strerror(errno)); -#endif /* VERBOSE_WARNINGS */ - return(s32result); - } // ENDIF- Trouble? - - subchannel.cdsc_format = CDROM_MSF; - s32result = ioctl(devicehandle, CDROMSUBCHNL, &subchannel); - if((s32result == -1) || (errno != 0)) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Error reading CD SubQ: %i:%s", errno, strerror(errno)); -#endif /* VERBOSE_WARNINGS */ - return(s32result); - } // ENDIF- Trouble? - - if(subq != NULL) { - subq->mode = subchannel.cdsc_adr; - subq->ctrl = subchannel.cdsc_ctrl; - subq->trackNum = subchannel.cdsc_trk; - subq->trackIndex = subchannel.cdsc_ind; - subq->trackM = subchannel.cdsc_reladdr.msf.minute; - subq->trackS = subchannel.cdsc_reladdr.msf.second; - subq->trackF = subchannel.cdsc_reladdr.msf.frame; - subq->discM = subchannel.cdsc_absaddr.msf.minute; - subq->discS = subchannel.cdsc_absaddr.msf.second; - subq->discF = subchannel.cdsc_absaddr.msf.frame; - } // ENDIF- Did the caller want all this data? - - return(0); -} // END CDVDreadSubQ() - -s32 CDgetTN(cdvdTN *cdvdtn) { -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: CDgetTN()"); -#endif /* VERBOSE_FUNCTION */ - - if(cdvdtn != NULL) { - cdvdtn->strack = cdheader.cdth_trk0; - cdvdtn->etrack = cdheader.cdth_trk1; - } // ENDIF- programmer actually WANTS this info? - - return(0); // Call accomplished -} // END CDVDgetTN() - -s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd) { - u8 j; - u16 k; - char temptime[3]; - -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: CDgetTD()"); -#endif /* VERBOSE_FUNCTION */ - - j = newtrack; - if(j == CDROM_LEADOUT) j = 0; - - if(j == 0) { - k = 27; - } else { - k = j * 10 + 37; - } // ENDIF- Where to start hunting for this number? - - if(cdvdtd != NULL) { - cdvdtd->type = tocbuffer[j*10 + 30]; - - temptime[0] = BCDTOHEX(tocbuffer[k]); - temptime[1] = BCDTOHEX(tocbuffer[k + 1]); - temptime[2] = BCDTOHEX(tocbuffer[k + 2]); - cdvdtd->lsn = MSFtoLBA(temptime); - } // ENDIF- Does the caller REALLY want this data? - - return(0); // Call accomplished -} // END CDVDgetTD() - -s32 CALLBACK CDgetDiskType(s32 ioctldisktype) { - s32 offset; - s32 s32result; - int i; - u8 j; - int tempdisctype; - - offset = 0; - errno = 0; - i = 0; - j = 0; - tempdisctype = CDVD_TYPE_UNKNOWN; - -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: CDgetDiskType()"); -#endif /* VERBOSE_FUNCTION */ - - s32result = CDreadTrack(16, CDVD_MODE_2352, cdtempbuffer); - if((s32result != 0) || (errno != 0)) { - return(-1); - } // ENDIF- Cannot read the CD's ISO9660 volume sector? Abort - disctype = CDVD_TYPE_DETCTCD; - - switch(ioctldisktype) { - case CDS_AUDIO: -#ifdef VERBOSE_DISC_TYPE - PrintLog("CDVD driver: Detected CDDA Audio disc."); -#endif /* VERBOSE_DISC_TYPE */ - tempdisctype = CDVD_TYPE_CDDA; - tocbuffer[0] = 0x01; - break; - - case CDS_DATA_1: - case CDS_MIXED: -#ifdef VERBOSE_DISC_TYPE - PrintLog("CDVD driver: Detected CD disc."); -#endif /* VERBOSE_DISC_TYPE */ - tocbuffer[0] = 0x41; - - CDreadTrack(16, CDVD_MODE_2048, cdtempbuffer); - offset = CDgetBufferOffset(); - i = 0; - while((*(playstationcdname + i) != 0) && - (*(playstationcdname + i) == cdtempbuffer[offset + 8 + i])) i++; - if(*(playstationcdname + i) == 0) { - i = 0; - while((*(ps1name + i) != 0) && - (*(ps1name + i) == cdtempbuffer[offset + 1024 + i])) i++; - if(*(ps1name + i) == 0) { -#ifdef VERBOSE_DISC_TYPE - PrintLog("CDVD driver: Detected Playstation CD disc."); -#endif /* VERBOSE_DISC_TYPE */ - tempdisctype = CDVD_TYPE_PSCD; - } else { -#ifdef VERBOSE_DISC_TYPE - PrintLog("CDVD driver: Detected Playstation 2 CD disc."); -#endif /* VERBOSE_DISC_TYPE */ - tempdisctype = CDVD_TYPE_PS2CD; - } // ENDIF- Did we find the CD ident? (For Playstation 1 CDs) - } else { - tempdisctype = CDVD_TYPE_UNKNOWN; - } // ENDIF- Did we find the Playstation name? - break; - - default: - return(-1); - } // ENDSWITCH- What has ioctl disc type come up with? - - // Collect TN data - cdheader.cdth_trk0 = 0; - cdheader.cdth_trk1 = 0; - - s32result = ioctl(devicehandle, CDROMREADTOCHDR, &cdheader); - if((s32result == -1) || (errno != 0)) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Error reading TN: (%i) %i:%s", - s32result, errno, strerror(errno)); -#endif /* VERBOSE_WARNINGS */ - cdheader.cdth_trk0 = 1; - cdheader.cdth_trk1 = 1; - } // ENDIF- Failed to read in track count? Assume 1 track. -#ifdef VERBOSE_DISC_INFO - PrintLog("CDVD driver: Track Number Range: %i-%i", - cdheader.cdth_trk0, cdheader.cdth_trk1); -#endif /* VERBOSE_DISC_INFO */ - tocbuffer[2] = 0xA0; - tocbuffer[7] = HEXTOBCD(cdheader.cdth_trk0); - tocbuffer[12] = 0xA1; - tocbuffer[17] = HEXTOBCD(cdheader.cdth_trk1); - - // Collect disc TD data - cdtrack.cdte_track = CDROM_LEADOUT; - cdtrack.cdte_format = CDROM_LBA; - s32result = ioctl(devicehandle, CDROMREADTOCENTRY, &cdtrack); - if((s32result == -1) || (errno != 0)) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Error reading TD for disc: (%i) %i:%s", - s32result, errno, strerror(errno)); -#endif /* VERBOSE_WARNINGS */ - return(-1); - } // ENDIF- Trouble getting a track count? - - LBAtoMSF(cdtrack.cdte_addr.lba, &tocbuffer[27]); -#ifdef VERBOSE_DISC_INFO - PrintLog("CDVD driver: Total Time: %i:%i", - tocbuffer[27], tocbuffer[28]); -#endif /* VERBOSE_DISC_INFO */ - tocbuffer[27] = HEXTOBCD(tocbuffer[27]); - tocbuffer[28] = HEXTOBCD(tocbuffer[28]); - tocbuffer[29] = HEXTOBCD(tocbuffer[29]); - - // Collect track TD data - for(j = cdheader.cdth_trk0; j <= cdheader.cdth_trk1; j++) { - cdtrack.cdte_track = j; // j-1? - cdtrack.cdte_format = CDROM_LBA; - s32result = ioctl(devicehandle, CDROMREADTOCENTRY, &cdtrack); - if((s32result == -1) || (errno != 0)) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Error reading TD for track %i: (%i) %i:%s", - j, s32result, errno, strerror(errno)); -#endif /* VERBOSE_WARNINGS */ - // No more here... - - } else { - LBAtoMSF(cdtrack.cdte_addr.lba, &tocbuffer[j*10 + 37]); -#ifdef VERBOSE_DISC_INFO - PrintLog("CDVD driver: Track %i: Data Mode %i Disc Start Time:%i:%i.%i\n", - j, - cdtrack.cdte_datamode, - tocbuffer[j*10+37], - tocbuffer[j*10+38], - tocbuffer[j*10+39]); -#endif /* VERBOSE_DISC_INFO */ - tocbuffer[j*10 + 30] = cdtrack.cdte_datamode; - tocbuffer[j*10 + 32] = HEXTOBCD(j); - tocbuffer[j*10 + 37] = HEXTOBCD(tocbuffer[j*10 + 37]); - tocbuffer[j*10 + 38] = HEXTOBCD(tocbuffer[j*10 + 38]); - tocbuffer[j*10 + 39] = HEXTOBCD(tocbuffer[j*10 + 39]); - } // ENDIF- Trouble getting a track count? - } // NEXT j- Reading each track's info in turn - - errno = 0; - disctype = tempdisctype; // Trigger the fact we have the info (finally) - return(disctype); -} // END CDVDgetDiskType() +/* CD.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + +#include // errno + +#include // NULL + +#include // strerror() + +#include // open() + +#include // ioctl() + +#include // open() + +#include // lseek(), open() + +#include // close(), lseek(), (sleep()) + + + +#include // CD/DVD based ioctl() and defines. + + + +#include "../convert.h" + +#include "logfile.h" + +#include "device.h" + +#include "CD.h" + + + + + +// Constants + +u8 *playstationcdname = "PLAYSTATION\0"; + +u8 *ps1name = "CD-XA001\0"; + + + +// CD-ROM temp storage structures (see linux/cdrom.h for details) + +struct cdrom_tochdr cdheader; + +struct cdrom_tocentry cdtrack; + +struct cdrom_subchnl subchannel; + +u8 cdtempbuffer[2352]; + + + +int cdmode; // mode of last CDVDreadTrack call (important for CDs) + + + + + +// Internal Functions + + + +void InitCDSectorInfo() { + + cdmode = -1; + +} // END InitSectorInfo(); + + + + + +// Function Calls from CDVD.c + + + +void InitCDInfo() { + + InitCDSectorInfo(); + +} // END InitDiscType() + + + +s32 CDreadTrack(u32 lsn, int mode, u8 *buffer) { + + s32 s32result; + + + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: CDreadTrack(%i)", lsn); + +#endif /* VERBOSE_FUNCTION */ + + + + s32result = 0; + + + + if(buffer == NULL) return(-1); + + + + // The CD way of figuring out where to read. + + LBAtoMSF(lsn, buffer); + + + + switch(mode) { + + case CDVD_MODE_2048: + + case CDVD_MODE_2328: + + case CDVD_MODE_2340: + + case CDVD_MODE_2352: + + errno = 4; // Interrupted system call... (simulated the first time) + + while(errno == 4) { + + errno = 0; + + s32result = ioctl(devicehandle, CDROMREADRAW, buffer); + + } // ENDWHILE- Continually being interrupted by the system... + + break; + + case CDVD_MODE_2368: // Unimplemented... as yet. + + default: + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Unknown Mode %i", mode); + +#endif /* VERBOSE_WARNINGS */ + + return(-1); // Illegal Read Mode? Abort + + break; + + } // ENDSWITCH- Which read mode should we choose? + + if((s32result == -1) || (errno != 0)) { + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Error reading CD: %i:%s", errno, strerror(errno)); + +#endif /* VERBOSE_WARNINGS */ + + InitCDSectorInfo(); + + return(-1); + + } // ENDIF- Trouble getting a track count? + + + + cdmode = mode; // Save mode for buffer positioning later. + + return(0); // Call accomplished + +} // END CDreadTrack() + + + +s32 CDgetBufferOffset() { + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: CDgetBufferOffset()"); + +#endif /* VERBOSE_FUNCTION */ + + + + switch(cdmode) { + + case CDVD_MODE_2048: + + return(0+24); + + case CDVD_MODE_2328: + + return(0+24); + + case CDVD_MODE_2340: + + return(0+12); + + case CDVD_MODE_2352: + + return(0+0); + + case CDVD_MODE_2368: // Unimplemented... as yet. + + default: + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Unknown Mode %i", cdmode); + +#endif /* VERBOSE_WARNINGS */ + + return(0); // Not to worry. for now. + + } // ENDSWITCH- where should we put the buffer pointer? + +} // END CDgetBuffer() + + + +// I, personally, don't see the big deal with SubQ + +// However, sooner or later I'll incorporate it into the Cache Buffer system + +// (backward compatibility, and all that) + +s32 CDreadSubQ(u32 lsn, cdvdSubQ *subq) { + + int tempmode; + + s32 s32result; + + + + s32result = 0; + + + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: CDreadSubQ()"); + +#endif /* VERBOSE_FUNCTION */ + + + + tempmode = cdmode; + + if(tempmode == -1) tempmode = CDVD_MODE_2352; + + CDreadTrack(lsn, tempmode, cdtempbuffer); + + if((s32result == -1) || (errno != 0)) { + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Error prepping CD SubQ: %i:%s", errno, strerror(errno)); + +#endif /* VERBOSE_WARNINGS */ + + return(s32result); + + } // ENDIF- Trouble? + + + + subchannel.cdsc_format = CDROM_MSF; + + s32result = ioctl(devicehandle, CDROMSUBCHNL, &subchannel); + + if((s32result == -1) || (errno != 0)) { + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Error reading CD SubQ: %i:%s", errno, strerror(errno)); + +#endif /* VERBOSE_WARNINGS */ + + return(s32result); + + } // ENDIF- Trouble? + + + + if(subq != NULL) { + + subq->mode = subchannel.cdsc_adr; + + subq->ctrl = subchannel.cdsc_ctrl; + + subq->trackNum = subchannel.cdsc_trk; + + subq->trackIndex = subchannel.cdsc_ind; + + subq->trackM = subchannel.cdsc_reladdr.msf.minute; + + subq->trackS = subchannel.cdsc_reladdr.msf.second; + + subq->trackF = subchannel.cdsc_reladdr.msf.frame; + + subq->discM = subchannel.cdsc_absaddr.msf.minute; + + subq->discS = subchannel.cdsc_absaddr.msf.second; + + subq->discF = subchannel.cdsc_absaddr.msf.frame; + + } // ENDIF- Did the caller want all this data? + + + + return(0); + +} // END CDVDreadSubQ() + + + +s32 CDgetTN(cdvdTN *cdvdtn) { + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: CDgetTN()"); + +#endif /* VERBOSE_FUNCTION */ + + + + if(cdvdtn != NULL) { + + cdvdtn->strack = cdheader.cdth_trk0; + + cdvdtn->etrack = cdheader.cdth_trk1; + + } // ENDIF- programmer actually WANTS this info? + + + + return(0); // Call accomplished + +} // END CDVDgetTN() + + + +s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd) { + + u8 j; + + u16 k; + + char temptime[3]; + + + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: CDgetTD()"); + +#endif /* VERBOSE_FUNCTION */ + + + + j = newtrack; + + if(j == CDROM_LEADOUT) j = 0; + + + + if(j == 0) { + + k = 27; + + } else { + + k = j * 10 + 37; + + } // ENDIF- Where to start hunting for this number? + + + + if(cdvdtd != NULL) { + + cdvdtd->type = tocbuffer[j*10 + 30]; + + + + temptime[0] = BCDTOHEX(tocbuffer[k]); + + temptime[1] = BCDTOHEX(tocbuffer[k + 1]); + + temptime[2] = BCDTOHEX(tocbuffer[k + 2]); + + cdvdtd->lsn = MSFtoLBA(temptime); + + } // ENDIF- Does the caller REALLY want this data? + + + + return(0); // Call accomplished + +} // END CDVDgetTD() + + + +s32 CALLBACK CDgetDiskType(s32 ioctldisktype) { + + s32 offset; + + s32 s32result; + + int i; + + u8 j; + + int tempdisctype; + + + + offset = 0; + + errno = 0; + + i = 0; + + j = 0; + + tempdisctype = CDVD_TYPE_UNKNOWN; + + + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: CDgetDiskType()"); + +#endif /* VERBOSE_FUNCTION */ + + + + s32result = CDreadTrack(16, CDVD_MODE_2352, cdtempbuffer); + + if((s32result != 0) || (errno != 0)) { + + return(-1); + + } // ENDIF- Cannot read the CD's ISO9660 volume sector? Abort + + disctype = CDVD_TYPE_DETCTCD; + + + + switch(ioctldisktype) { + + case CDS_AUDIO: + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("CDVD driver: Detected CDDA Audio disc."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_CDDA; + + tocbuffer[0] = 0x01; + + break; + + + + case CDS_DATA_1: + + case CDS_MIXED: + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("CDVD driver: Detected CD disc."); + +#endif /* VERBOSE_DISC_TYPE */ + + tocbuffer[0] = 0x41; + + + + CDreadTrack(16, CDVD_MODE_2048, cdtempbuffer); + + offset = CDgetBufferOffset(); + + i = 0; + + while((*(playstationcdname + i) != 0) && + + (*(playstationcdname + i) == cdtempbuffer[offset + 8 + i])) i++; + + if(*(playstationcdname + i) == 0) { + + i = 0; + + while((*(ps1name + i) != 0) && + + (*(ps1name + i) == cdtempbuffer[offset + 1024 + i])) i++; + + if(*(ps1name + i) == 0) { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("CDVD driver: Detected Playstation CD disc."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_PSCD; + + } else { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("CDVD driver: Detected Playstation 2 CD disc."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_PS2CD; + + } // ENDIF- Did we find the CD ident? (For Playstation 1 CDs) + + } else { + + tempdisctype = CDVD_TYPE_UNKNOWN; + + } // ENDIF- Did we find the Playstation name? + + break; + + + + default: + + return(-1); + + } // ENDSWITCH- What has ioctl disc type come up with? + + + + // Collect TN data + + cdheader.cdth_trk0 = 0; + + cdheader.cdth_trk1 = 0; + + + + s32result = ioctl(devicehandle, CDROMREADTOCHDR, &cdheader); + + if((s32result == -1) || (errno != 0)) { + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Error reading TN: (%i) %i:%s", + + s32result, errno, strerror(errno)); + +#endif /* VERBOSE_WARNINGS */ + + cdheader.cdth_trk0 = 1; + + cdheader.cdth_trk1 = 1; + + } // ENDIF- Failed to read in track count? Assume 1 track. + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD driver: Track Number Range: %i-%i", + + cdheader.cdth_trk0, cdheader.cdth_trk1); + +#endif /* VERBOSE_DISC_INFO */ + + tocbuffer[2] = 0xA0; + + tocbuffer[7] = HEXTOBCD(cdheader.cdth_trk0); + + tocbuffer[12] = 0xA1; + + tocbuffer[17] = HEXTOBCD(cdheader.cdth_trk1); + + + + // Collect disc TD data + + cdtrack.cdte_track = CDROM_LEADOUT; + + cdtrack.cdte_format = CDROM_LBA; + + s32result = ioctl(devicehandle, CDROMREADTOCENTRY, &cdtrack); + + if((s32result == -1) || (errno != 0)) { + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Error reading TD for disc: (%i) %i:%s", + + s32result, errno, strerror(errno)); + +#endif /* VERBOSE_WARNINGS */ + + return(-1); + + } // ENDIF- Trouble getting a track count? + + + + LBAtoMSF(cdtrack.cdte_addr.lba, &tocbuffer[27]); + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD driver: Total Time: %i:%i", + + tocbuffer[27], tocbuffer[28]); + +#endif /* VERBOSE_DISC_INFO */ + + tocbuffer[27] = HEXTOBCD(tocbuffer[27]); + + tocbuffer[28] = HEXTOBCD(tocbuffer[28]); + + tocbuffer[29] = HEXTOBCD(tocbuffer[29]); + + + + // Collect track TD data + + for(j = cdheader.cdth_trk0; j <= cdheader.cdth_trk1; j++) { + + cdtrack.cdte_track = j; // j-1? + + cdtrack.cdte_format = CDROM_LBA; + + s32result = ioctl(devicehandle, CDROMREADTOCENTRY, &cdtrack); + + if((s32result == -1) || (errno != 0)) { + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Error reading TD for track %i: (%i) %i:%s", + + j, s32result, errno, strerror(errno)); + +#endif /* VERBOSE_WARNINGS */ + + // No more here... + + + + } else { + + LBAtoMSF(cdtrack.cdte_addr.lba, &tocbuffer[j*10 + 37]); + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD driver: Track %i: Data Mode %i Disc Start Time:%i:%i.%i\n", + + j, + + cdtrack.cdte_datamode, + + tocbuffer[j*10+37], + + tocbuffer[j*10+38], + + tocbuffer[j*10+39]); + +#endif /* VERBOSE_DISC_INFO */ + + tocbuffer[j*10 + 30] = cdtrack.cdte_datamode; + + tocbuffer[j*10 + 32] = HEXTOBCD(j); + + tocbuffer[j*10 + 37] = HEXTOBCD(tocbuffer[j*10 + 37]); + + tocbuffer[j*10 + 38] = HEXTOBCD(tocbuffer[j*10 + 38]); + + tocbuffer[j*10 + 39] = HEXTOBCD(tocbuffer[j*10 + 39]); + + } // ENDIF- Trouble getting a track count? + + } // NEXT j- Reading each track's info in turn + + + + errno = 0; + + disctype = tempdisctype; // Trigger the fact we have the info (finally) + + return(disctype); + +} // END CDVDgetDiskType() + diff --git a/plugins/CDVDisoEFP/src/Linux/CD.h b/plugins/CDVDisoEFP/src/Linux/CD.h index 2546cbaabd..0f8f6f485e 100644 --- a/plugins/CDVDisoEFP/src/Linux/CD.h +++ b/plugins/CDVDisoEFP/src/Linux/CD.h @@ -1,46 +1,92 @@ -/* CD.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - -#ifndef __CD_H__ -#define __CD_H__ - - -#ifndef __LINUX__ -#ifdef __linux__ -#define __LINUX__ -#endif /* __linux__ */ -#endif /* No __LINUX__ */ - -#define CDVDdefs -#include "../PS2Edefs.h" - - -// Exported Functions - -extern void InitCDInfo(); -extern s32 CDreadTrack(u32 lsn, int mode, u8 *buffer); -extern s32 CDgetBufferOffset(); -extern s32 CDreadSubQ(u32 lsn, cdvdSubQ *subq); -extern s32 CDgetTN(cdvdTN *cdvdtn); -extern s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd); -extern s32 CDgetDiskType(s32 ioctldisktype); - - -#endif /* __CD_H__ */ +/* CD.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + +#ifndef __CD_H__ + +#define __CD_H__ + + + + + +#ifndef __LINUX__ + +#ifdef __linux__ + +#define __LINUX__ + +#endif /* __linux__ */ + +#endif /* No __LINUX__ */ + + + +#define CDVDdefs + +#include "../PS2Edefs.h" + + + + + +// Exported Functions + + + +extern void InitCDInfo(); + +extern s32 CDreadTrack(u32 lsn, int mode, u8 *buffer); + +extern s32 CDgetBufferOffset(); + +extern s32 CDreadSubQ(u32 lsn, cdvdSubQ *subq); + +extern s32 CDgetTN(cdvdTN *cdvdtn); + +extern s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd); + +extern s32 CDgetDiskType(s32 ioctldisktype); + + + + + +#endif /* __CD_H__ */ + diff --git a/plugins/CDVDisoEFP/src/Linux/CDVDiso.h b/plugins/CDVDisoEFP/src/Linux/CDVDiso.h index 8cd9301e5b..268bbb2e0d 100644 --- a/plugins/CDVDisoEFP/src/Linux/CDVDiso.h +++ b/plugins/CDVDisoEFP/src/Linux/CDVDiso.h @@ -1,29 +1,58 @@ -/* CDVDiso.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef CDVDISO_H -#define CDVDISO_H - - -// #define VERBOSE_FUNCTION_INTERFACE - - -#endif /* CDVDISO_H */ +/* CDVDiso.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef CDVDISO_H + +#define CDVDISO_H + + + + + +// #define VERBOSE_FUNCTION_INTERFACE + + + + + +#endif /* CDVDISO_H */ + diff --git a/plugins/CDVDisoEFP/src/Linux/DVD.c b/plugins/CDVDisoEFP/src/Linux/DVD.c index 8bf18ae205..46bfeb678b 100644 --- a/plugins/CDVDisoEFP/src/Linux/DVD.c +++ b/plugins/CDVDisoEFP/src/Linux/DVD.c @@ -1,582 +1,1164 @@ -/* DVD.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - -#include // errno -#include // NULL -#include // sprintf() -#include // strerror(), memset(), memcpy() -#include // open() -#include // ioctl() -#include // open() -#include // lseek(), open() -#include // close(), lseek(), (sleep()) - -#include // CD/DVD based ioctl() and defines. - -#include "logfile.h" -#include "device.h" -#include "DVD.h" - - -// Constants -u8 *playstationname = "PLAYSTATION\0"; - -// DVD storage structures (see linux/cdrom.h for details) -dvd_struct dvdphysical; -dvd_struct dvdcopyright[DVD_LAYERS]; -dvd_struct dvdbca; -dvd_struct dvdmanufact[DVD_LAYERS]; - -u32 dvdlastlsn; -u8 dvdtempbuffer[2064]; - - -// Internal Functions - -void InitDVDSectorInfo() { - dvdlastlsn = 0xffffffff; -} // END InitSectorInfo(); - -void HexDump(u8 *strptr, u8 count) { - int i; - u8 ch[2]; - char hexline[81]; - int hexlinepos; - - ch[1] = 0; - - if(count == 0) count = 16; - if((count < 1) || (count > 16)) return; - - hexlinepos = 0; - hexlinepos += sprintf(&hexline[hexlinepos], "CDVD driver: "); - - for(i = 0; i < count; i++) { - hexlinepos += sprintf(&hexline[hexlinepos], "%.2x ", (*(strptr + i)) * 1); - } // NEXT i- printing each new Hex number - - for(i = 0; i < count; i++) { - if((*(strptr + i) < 32) || (*(strptr + i) > 127)) { - hexlinepos += sprintf(&hexline[hexlinepos], "."); - } else { - ch[0] = *(strptr + i); - hexlinepos += sprintf(&hexline[hexlinepos], "%s", ch); - } // ENDIF- Is this an unprintable character? - } // NEXT i- printing each new character - PrintLog(hexline); -} // ENDIF HexDump() - - -//// DVD Structure Functions - -s32 DVDreadPhysical() { - s32 s32result; - u8 i; - - errno = 0; - -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: DVDreadPhysical()\n"); -#endif /* VERBOSE_FUNCTION */ - - memset(&dvdphysical, 0, sizeof(dvd_struct)); - dvdphysical.type = DVD_STRUCT_PHYSICAL; - - i = DVD_LAYERS; - while(i > 0) { - i--; - dvdphysical.physical.layer_num = i; - errno = 0; - s32result = ioctl(devicehandle, DVD_READ_STRUCT, &dvdphysical); - } // ENDWHILE- reading in all physical layers... - - if((s32result == -1) || (errno != 0)) { - dvdphysical.type = 0xFF; -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Error getting Physical structure: (%i) %i:%s", s32result, errno, strerror(errno)); -#endif /* VERBOSE_WARNINGS */ - return(-1); - } // ENDIF- Problem with reading Layer 0 of the physical data? Abort - - i = 3; - while((i > 0) && (dvdphysical.physical.layer[i].end_sector == 0)) i--; - dvdphysical.physical.layer_num = i; - -#ifdef VERBOSE_DISC_INFO - PrintLog("CDVD driver: Physical Characteristics"); - PrintLog("CDVD driver: Number of Layers: %i", - (s32) dvdphysical.physical.layer_num + 1); - for(i = 0; i <= dvdphysical.physical.layer_num; i++) { - PrintLog("CDVD driver: Layer Number %i", i); - switch(dvdphysical.physical.layer[i].book_type) { - case 0: - PrintLog("CDVD driver: Book Type: DVD-ROM"); - break; - case 1: - PrintLog("CDVD driver: Book Type: DVD-RAM"); - break; - case 2: - PrintLog("CDVD driver: Book Type: DVD-R"); - break; - case 3: - PrintLog("CDVD driver: Book Type: DVD-RW"); - break; - case 9: - PrintLog("CDVD driver: Book Type: DVD+RW"); - break; - default: - PrintLog("CDVD driver: Book Type: Unknown (%i)", - dvdphysical.physical.layer[i].book_type); - break; - } // ENDSWITCH- Displaying the Book Type - PrintLog("CDVD driver: Book Version %i", - dvdphysical.physical.layer[i].book_version); - switch(dvdphysical.physical.layer[i].min_rate) { - case 0: - PrintLog("CDVD driver: Use Minimum Rate for: DVD-ROM"); - break; - case 1: - PrintLog("CDVD driver: Use Minimum Rate for: DVD-RAM"); - break; - case 2: - PrintLog("CDVD driver: Use Minimum Rate for: DVD-R"); - break; - case 3: - PrintLog("CDVD driver: Use Minimum Rate for: DVD-RW"); - break; - case 9: - PrintLog("CDVD driver: Use Minimum Rate for: DVD+RW"); - break; - default: - PrintLog("CDVD driver: Use Minimum Rate for: Unknown (%i)", - dvdphysical.physical.layer[i].min_rate); - break; - } // ENDSWITCH- Displaying the Minimum (Spin?) Rate - switch(dvdphysical.physical.layer[i].disc_size) { - case 0: - PrintLog("CDVD driver: Physical Disk Size: 120mm"); - break; - case 1: - PrintLog("CDVD driver: Physical Disk Size: 80mm"); - break; - default: - PrintLog("CDVD driver: Physical Disk Size: Unknown (%i)", - dvdphysical.physical.layer[i].disc_size); - break; - } // ENDSWITCH- What's the Disk Size? - switch(dvdphysical.physical.layer[i].layer_type) { - case 1: - PrintLog("CDVD driver: Layer Type: Read-Only"); - break; - case 2: - PrintLog("CDVD driver: Layer Type: Recordable"); - break; - case 4: - PrintLog("CDVD driver: Layer Type: Rewritable"); - break; - default: - PrintLog("CDVD driver: Layer Type: Unknown (%i)", - dvdphysical.physical.layer[i].layer_type); - break; - } // ENDSWITCH- Displaying the Layer Type - switch(dvdphysical.physical.layer[i].track_path) { - case 0: - PrintLog("CDVD driver: Track Path: PTP"); - break; - case 1: - PrintLog("CDVD driver: Track Path: OTP"); - break; - default: - PrintLog("CDVD driver: Track Path: Unknown (%i)", - dvdphysical.physical.layer[i].track_path); - break; - } // ENDSWITCH- What's Track Path Layout? - // PrintLog("CDVD driver: Disc Size %i Layer Type %i Track Path %i Nlayers %i", - // dvdphysical.physical.layer[i].nlayers); - switch(dvdphysical.physical.layer[i].track_density) { - case 0: - PrintLog("CDVD driver: Track Density: .74 m/track"); - break; - case 1: - PrintLog("CDVD driver: Track Density: .8 m/track"); - break; - case 2: - PrintLog("CDVD driver: Track Density: .615 m/track"); - break; - default: - PrintLog("CDVD driver: Track Density: Unknown (%i)", - dvdphysical.physical.layer[i].track_density); - break; - } // ENDSWITCH- Displaying the Track Density - switch(dvdphysical.physical.layer[i].linear_density) { - case 0: - PrintLog("CDVD driver: Linear Density: .267 m/bit"); - break; - case 1: - PrintLog("CDVD driver: Linear Density: .293 m/bit"); - break; - case 2: - PrintLog("CDVD driver: Linear Density: .409 to .435 m/bit"); - break; - case 4: - PrintLog("CDVD driver: Linear Density: .280 to .291 m/bit"); - break; - case 8: - PrintLog("CDVD driver: Linear Density: .353 m/bit"); - break; - default: - PrintLog("CDVD driver: Linear Density: Unknown (%i)", - dvdphysical.physical.layer[i].linear_density); - break; - } // ENDSWITCH- Displaying the Linear Density - if(dvdphysical.physical.layer[i].start_sector == 0x30000) { - PrintLog("CDVD driver: Starting Sector: %lu (DVD-ROM, DVD-R, DVD-RW)", - dvdphysical.physical.layer[i].start_sector); - } else if(dvdphysical.physical.layer[i].start_sector == 0x31000) { - PrintLog("CDVD driver: Starting Sector: %lu (DVD-RAM, DVD+RW)", - dvdphysical.physical.layer[i].start_sector); - } else { - PrintLog("CDVD driver: Starting Sector: %lu", - dvdphysical.physical.layer[i].start_sector); - } // ENDLONGIF- What does the starting sector tell us? - PrintLog("CDVD driver: End of Layer 0: %lu", - dvdphysical.physical.layer[i].end_sector_l0); - PrintLog("CDVD driver: Ending Sector: %lu", - dvdphysical.physical.layer[i].end_sector); - if(dvdphysical.physical.layer[i].bca != 0) - PrintLog("CDVD driver: BCA data present"); - } // NEXT i- Work our way through each layer... -#endif /* VERBOSE_DISC_INFO */ - - return(0); // Success. Physical data stored for perusal. -} // END DVDreadPhysical() - -s32 DVDreadCopyright() { - s32 s32result; - u8 i; - int successflag; - -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: DVDreadCopyright()"); -#endif /* VERBOSE_FUNCTION */ - - successflag = 0; - - for(i = 0; i <= dvdphysical.physical.layer_num; i++) { - memset(&dvdcopyright[i], 0, sizeof(dvd_struct)); - dvdcopyright[i].type = DVD_STRUCT_COPYRIGHT; - dvdcopyright[i].copyright.layer_num = i; - errno = 0; - s32result = ioctl(devicehandle, DVD_READ_STRUCT, &dvdcopyright[i]); - if(s32result == 0) { - successflag = 1; - } else { - dvdcopyright[i].type = 0xFF; - } // ENDIF- - } // NEXT i- Getting copyright data for every known layer - - if(successflag == 0) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Error getting Copyright info: (%i) %i:%s", s32result, errno, strerror(errno)); -#endif /* VERBOSE_WARNINGS */ - return(-1); - } // ENDIF- Problem with read of physical data? - -#ifdef VERBOSE_DISC_INFO - PrintLog("CDVD driver: Copyright Information\n"); - for(i = 0; i <= dvdphysical.physical.layer_num; i++) { - if(dvdcopyright[i].type != 0xFF) { - PrintLog("CDVD driver: Layer Number %i CPST %i RMI %i", - dvdcopyright[i].copyright.layer_num, - dvdcopyright[i].copyright.cpst, - dvdcopyright[i].copyright.rmi); - } // ENDIF- Were we successful reading this one? - } // NEXT i- Printing out all copyright info found... -#endif /* VERBOSE_DISC_INFO */ - - errno = 0; - return(0); // Success. Copyright data stored for perusal. -} // END DVDreadCopyright() - -s32 DVDreadBCA() { - s32 s32result; - int i; - - i = 0; - errno = 0; - -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: DVDreadBCA()"); -#endif /* VERBOSE_FUNCTION */ - - memset(&dvdbca, 0, sizeof(dvd_struct)); - dvdbca.type = DVD_STRUCT_BCA; - s32result = ioctl(devicehandle, DVD_READ_STRUCT, &dvdbca); - if((s32result == -1) || (errno != 0)) { - dvdbca.type = 0xFF; -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Error getting BCA: (%i) %i:%s", s32result, errno, strerror(errno)); -#endif /* VERBOSE_WARNINGS */ - return(-1); - } // ENDIF- Problem with read of physical data? - -#ifdef VERBOSE_DISC_INFO - PrintLog("CDVD driver: BCA Length %i Value:", - dvdbca.bca.len); - for(i = 0; i < 188-15; i += 16) { - HexDump(dvdbca.bca.value+i, 16); - } // NEXT i- dumping whole key data -#endif /* VERBOSE_DISC_INFO */ - - return(0); // Success. BCA data stored for perusal. -} // END DVDreadBCA() - -s32 DVDreadManufact() { - s32 s32result; - u8 i; - int successflag; - int j; - -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: DVDreadManufact()"); -#endif /* VERBOSE_FUNCTION */ - - j = 0; - successflag = 0; - - for(i = 0; i <= dvdphysical.physical.layer_num; i++) { - memset(&dvdmanufact[i], 0, sizeof(dvd_struct)); - dvdmanufact[i].type = DVD_STRUCT_MANUFACT; - dvdmanufact[i].manufact.layer_num = i; - errno = 0; - s32result = ioctl(devicehandle, DVD_READ_STRUCT, &dvdmanufact[i]); - if((s32result != 0) || (errno != 0)) { - dvdmanufact[i].type = 0xFF; - } else { - successflag = 1; - } // ENDIF- Did we fail to read in some manufacturer data? - } // NEXT i- Collecting manufacturer data from all layers - - if(successflag == 0) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Error getting Manufact: (%i) %i:%s", s32result, errno, strerror(errno)); -#endif /* VERBOSE_WARNINGS */ - return(-1); - } // ENDIF- Problem with read of physical data? - -#ifdef VERBOSE_DISC_INFO - PrintLog("CDVD driver: Manufact Data"); - for(i = 0; i <= dvdphysical.physical.layer_num; i++) { - if(dvdmanufact[i].type != 0xFF) { - PrintLog("CDVD driver: Layer %i Length %i Value:", - dvdmanufact[i].manufact.layer_num, - dvdmanufact[i].manufact.len); - for(j = 0; j < 128-15; j += 16) { - HexDump(dvdmanufact[i].manufact.value+j, 16); - } // NEXT j- dumping whole key data - } // ENDIF- Do we have data at this layer? - } // NEXT i- Running through all the layers -#endif /* VERBOSE_DISC_INFO */ - - errno = 0; - return(0); // Success. Manufacturer's data stored for perusal. -} // END DVDreadManufact() - - -// External Functions - -// Function Calls from CDVD.c - -void InitDVDInfo() { - int j; - - dvdphysical.type = 0xFF; // Using for empty=0xff, full!=0xff test - dvdbca.type = 0xFF; - for(j = 0; j < DVD_LAYERS; j++) { - dvdcopyright[j].type = 0xFF; - dvdmanufact[j].type = 0xFF; - } // NEXT j- Zeroing each layer of data - InitDVDSectorInfo(); -} // END InitDiscType() - -s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer) { - s32 s32result; - off64_t offsettarget; - off64_t offsetresult; - - errno = 0; - s32result = 0; - offsetresult = 0; - -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: DVDreadTrack(%i)", lsn); -#endif /* VERBOSE_FUNCTION */ - - if(lsn != dvdlastlsn + 1) { - offsettarget = lsn; - offsettarget *= 2048; - errno = 4; - while(errno == 4) { - errno = 0; - offsetresult = lseek64(devicehandle, offsettarget, SEEK_SET); - } // ENDWHILE- waiting for the system interruptions to cease. - if((offsetresult < 0) || (errno != 0)) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Error on seek: %i:%s", errno, strerror(errno)); -#endif /* VERBOSE_WARNINGS */ - InitDVDSectorInfo(); - return(-1); - } // ENDIF- trouble with seek? Reset pointer and abort - } // ENDIF- Do we have to seek a new position to read? - - errno = 4; - while(errno == 4) { - errno = 0; - s32result = read(devicehandle, buffer, 2048); - } // ENDWHILE- waiting for the system interruptions to cease. - if((s32result != 2048) || (errno != 0)) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: DVD Short Block, Size: %i", s32result); - PrintLog("CDVD driver: Error: %i:%s", errno, strerror(errno)); -#endif /* VERBOSE_WARNINGS */ - InitDVDSectorInfo(); - return(-1); - } // ENDIF- Trouble reading the data? Reset pointer and abort - - dvdlastlsn = lsn; - return(0); // Call accomplished -} // END DVDreadTrack() - -s32 DVDgetTN(cdvdTN *cdvdtn) { -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: CDVDgetTN()"); -#endif /* VERBOSE_FUNCTION */ - - // Going to treat this as one large track for now. - if(cdvdtn != NULL) { - cdvdtn->strack = 1; - cdvdtn->etrack = 1; - } // ENDIF- programmer actually WANTS this info? - - return(0); // Call accomplished -} // END DVDgetTN() - -s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd) { -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: CDVDgetTD()"); -#endif /* VERBOSE_FUNCTION */ - - if((newtrack >= 2) && (newtrack != CDROM_LEADOUT)) return(-1); - - if(cdvdtd != NULL) { - cdvdtd->lsn = dvdphysical.physical.layer[0].end_sector - - dvdphysical.physical.layer[0].start_sector - + 1; - cdvdtd->type = CDVD_MODE_2048; - } // ENDIF- Does the caller REALLY want this data? - - return(0); // Call accomplished -} // END DVDgetTD() - -s32 DVDgetDiskType(s32 ioctldisktype) { - s32 s32result; - int i; - s32 tempdisctype; - - errno = 0; - s32result = 0; - i = 0; - tempdisctype = CDVD_TYPE_UNKNOWN; - -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: DVDgetDiskType()"); -#endif /* VERBOSE_FUNCTION */ - - if((ioctldisktype != CDS_DATA_1) && (ioctldisktype != CDS_MIXED)) { - return(-1); - } // ENDIF- Not a data disc we know of? Abort then - - s32result = DVDreadPhysical(); - if((s32result != 0) || (errno != 0)) { - return(-1); - } // ENDIF- Error reading the DVD physical structure? Not a DVD after all. - - if(dvdphysical.physical.layer[0].end_sector >= (2048*1024)) { -#ifdef VERBOSE_DISC_TYPE - PrintLog("CDVD driver: DVD Found (Dual-Sided)"); -#endif /* VERBOSE_DISC_TYPE */ - disctype = CDVD_TYPE_DETCTDVDD; - } else { -#ifdef VERBOSE_DISC_TYPE - PrintLog("CDVD driver: DVD Found (Single-Sided)"); -#endif /* VERBOSE_DISC_TYPE */ - disctype = CDVD_TYPE_DETCTDVDS; - } // ENDIF- Definitely a DVD. Size Test? - - // Read in the rest of the structures... - DVDreadCopyright(); - DVDreadBCA(); - DVDreadManufact(); - - // Test for "Playstation" header - s32result = DVDreadTrack(16, CDVD_MODE_2048, dvdtempbuffer); - if(s32result != 0) { - return(-1); - } else { - i = 0; - while((*(playstationname + i) != 0) && - (*(playstationname + i) == dvdtempbuffer[8 + i])) { - i++; - } // ENDWHILE- Checking each letter of PLAYSTATION name for a match - if(*(playstationname + i) == 0) { -#ifdef VERBOSE_DISC_TYPE - PrintLog("CDVD driver: Detected Playstation 2 DVD"); -#endif /* VERBOSE_DISC_TYPE */ - tempdisctype = CDVD_TYPE_PS2DVD; - } else { -#ifdef VERBOSE_DISC_TYPE - PrintLog("CDVD driver: Guessing it's a Video DVD"); -#endif /* VERBOSE_DISC_TYPE */ - tempdisctype = CDVD_TYPE_DVDV; - } // ENDIF- Did we find the Playstation name? - } // ENDIF- Error reading disc volume information? Invalidate Disc - - if(dvdphysical.physical.layer[0].end_sector >= (2048*1024)) { - tocbuffer[0] = 0x24; // Dual-Sided DVD - tocbuffer[4] = 0x41; - tocbuffer[5] = 0x95; - } else { - tocbuffer[0] = 0x04; // Single-Sided DVD - tocbuffer[4] = 0x86; - tocbuffer[5] = 0x72; - } // ENDIF- Are there too many sectors for a single-sided disc? - - tocbuffer[1] = 0x02; - tocbuffer[2] = 0xF2; - tocbuffer[3] = 0x00; - - tocbuffer[16] = 0x00; - tocbuffer[17] = 0x03; - tocbuffer[18] = 0x00; - tocbuffer[19] = 0x00; - - disctype = tempdisctype; // Triggers the fact the other info is available - return(disctype); -} // END DVDgetDiskType() +/* DVD.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + +#include // errno + +#include // NULL + +#include // sprintf() + +#include // strerror(), memset(), memcpy() + +#include // open() + +#include // ioctl() + +#include // open() + +#include // lseek(), open() + +#include // close(), lseek(), (sleep()) + + + +#include // CD/DVD based ioctl() and defines. + + + +#include "logfile.h" + +#include "device.h" + +#include "DVD.h" + + + + + +// Constants + +u8 *playstationname = "PLAYSTATION\0"; + + + +// DVD storage structures (see linux/cdrom.h for details) + +dvd_struct dvdphysical; + +dvd_struct dvdcopyright[DVD_LAYERS]; + +dvd_struct dvdbca; + +dvd_struct dvdmanufact[DVD_LAYERS]; + + + +u32 dvdlastlsn; + +u8 dvdtempbuffer[2064]; + + + + + +// Internal Functions + + + +void InitDVDSectorInfo() { + + dvdlastlsn = 0xffffffff; + +} // END InitSectorInfo(); + + + +void HexDump(u8 *strptr, u8 count) { + + int i; + + u8 ch[2]; + + char hexline[81]; + + int hexlinepos; + + + + ch[1] = 0; + + + + if(count == 0) count = 16; + + if((count < 1) || (count > 16)) return; + + + + hexlinepos = 0; + + hexlinepos += sprintf(&hexline[hexlinepos], "CDVD driver: "); + + + + for(i = 0; i < count; i++) { + + hexlinepos += sprintf(&hexline[hexlinepos], "%.2x ", (*(strptr + i)) * 1); + + } // NEXT i- printing each new Hex number + + + + for(i = 0; i < count; i++) { + + if((*(strptr + i) < 32) || (*(strptr + i) > 127)) { + + hexlinepos += sprintf(&hexline[hexlinepos], "."); + + } else { + + ch[0] = *(strptr + i); + + hexlinepos += sprintf(&hexline[hexlinepos], "%s", ch); + + } // ENDIF- Is this an unprintable character? + + } // NEXT i- printing each new character + + PrintLog(hexline); + +} // ENDIF HexDump() + + + + + +//// DVD Structure Functions + + + +s32 DVDreadPhysical() { + + s32 s32result; + + u8 i; + + + + errno = 0; + + + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: DVDreadPhysical()\n"); + +#endif /* VERBOSE_FUNCTION */ + + + + memset(&dvdphysical, 0, sizeof(dvd_struct)); + + dvdphysical.type = DVD_STRUCT_PHYSICAL; + + + + i = DVD_LAYERS; + + while(i > 0) { + + i--; + + dvdphysical.physical.layer_num = i; + + errno = 0; + + s32result = ioctl(devicehandle, DVD_READ_STRUCT, &dvdphysical); + + } // ENDWHILE- reading in all physical layers... + + + + if((s32result == -1) || (errno != 0)) { + + dvdphysical.type = 0xFF; + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Error getting Physical structure: (%i) %i:%s", s32result, errno, strerror(errno)); + +#endif /* VERBOSE_WARNINGS */ + + return(-1); + + } // ENDIF- Problem with reading Layer 0 of the physical data? Abort + + + + i = 3; + + while((i > 0) && (dvdphysical.physical.layer[i].end_sector == 0)) i--; + + dvdphysical.physical.layer_num = i; + + + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD driver: Physical Characteristics"); + + PrintLog("CDVD driver: Number of Layers: %i", + + (s32) dvdphysical.physical.layer_num + 1); + + for(i = 0; i <= dvdphysical.physical.layer_num; i++) { + + PrintLog("CDVD driver: Layer Number %i", i); + + switch(dvdphysical.physical.layer[i].book_type) { + + case 0: + + PrintLog("CDVD driver: Book Type: DVD-ROM"); + + break; + + case 1: + + PrintLog("CDVD driver: Book Type: DVD-RAM"); + + break; + + case 2: + + PrintLog("CDVD driver: Book Type: DVD-R"); + + break; + + case 3: + + PrintLog("CDVD driver: Book Type: DVD-RW"); + + break; + + case 9: + + PrintLog("CDVD driver: Book Type: DVD+RW"); + + break; + + default: + + PrintLog("CDVD driver: Book Type: Unknown (%i)", + + dvdphysical.physical.layer[i].book_type); + + break; + + } // ENDSWITCH- Displaying the Book Type + + PrintLog("CDVD driver: Book Version %i", + + dvdphysical.physical.layer[i].book_version); + + switch(dvdphysical.physical.layer[i].min_rate) { + + case 0: + + PrintLog("CDVD driver: Use Minimum Rate for: DVD-ROM"); + + break; + + case 1: + + PrintLog("CDVD driver: Use Minimum Rate for: DVD-RAM"); + + break; + + case 2: + + PrintLog("CDVD driver: Use Minimum Rate for: DVD-R"); + + break; + + case 3: + + PrintLog("CDVD driver: Use Minimum Rate for: DVD-RW"); + + break; + + case 9: + + PrintLog("CDVD driver: Use Minimum Rate for: DVD+RW"); + + break; + + default: + + PrintLog("CDVD driver: Use Minimum Rate for: Unknown (%i)", + + dvdphysical.physical.layer[i].min_rate); + + break; + + } // ENDSWITCH- Displaying the Minimum (Spin?) Rate + + switch(dvdphysical.physical.layer[i].disc_size) { + + case 0: + + PrintLog("CDVD driver: Physical Disk Size: 120mm"); + + break; + + case 1: + + PrintLog("CDVD driver: Physical Disk Size: 80mm"); + + break; + + default: + + PrintLog("CDVD driver: Physical Disk Size: Unknown (%i)", + + dvdphysical.physical.layer[i].disc_size); + + break; + + } // ENDSWITCH- What's the Disk Size? + + switch(dvdphysical.physical.layer[i].layer_type) { + + case 1: + + PrintLog("CDVD driver: Layer Type: Read-Only"); + + break; + + case 2: + + PrintLog("CDVD driver: Layer Type: Recordable"); + + break; + + case 4: + + PrintLog("CDVD driver: Layer Type: Rewritable"); + + break; + + default: + + PrintLog("CDVD driver: Layer Type: Unknown (%i)", + + dvdphysical.physical.layer[i].layer_type); + + break; + + } // ENDSWITCH- Displaying the Layer Type + + switch(dvdphysical.physical.layer[i].track_path) { + + case 0: + + PrintLog("CDVD driver: Track Path: PTP"); + + break; + + case 1: + + PrintLog("CDVD driver: Track Path: OTP"); + + break; + + default: + + PrintLog("CDVD driver: Track Path: Unknown (%i)", + + dvdphysical.physical.layer[i].track_path); + + break; + + } // ENDSWITCH- What's Track Path Layout? + + // PrintLog("CDVD driver: Disc Size %i Layer Type %i Track Path %i Nlayers %i", + + // dvdphysical.physical.layer[i].nlayers); + + switch(dvdphysical.physical.layer[i].track_density) { + + case 0: + + PrintLog("CDVD driver: Track Density: .74 m/track"); + + break; + + case 1: + + PrintLog("CDVD driver: Track Density: .8 m/track"); + + break; + + case 2: + + PrintLog("CDVD driver: Track Density: .615 m/track"); + + break; + + default: + + PrintLog("CDVD driver: Track Density: Unknown (%i)", + + dvdphysical.physical.layer[i].track_density); + + break; + + } // ENDSWITCH- Displaying the Track Density + + switch(dvdphysical.physical.layer[i].linear_density) { + + case 0: + + PrintLog("CDVD driver: Linear Density: .267 m/bit"); + + break; + + case 1: + + PrintLog("CDVD driver: Linear Density: .293 m/bit"); + + break; + + case 2: + + PrintLog("CDVD driver: Linear Density: .409 to .435 m/bit"); + + break; + + case 4: + + PrintLog("CDVD driver: Linear Density: .280 to .291 m/bit"); + + break; + + case 8: + + PrintLog("CDVD driver: Linear Density: .353 m/bit"); + + break; + + default: + + PrintLog("CDVD driver: Linear Density: Unknown (%i)", + + dvdphysical.physical.layer[i].linear_density); + + break; + + } // ENDSWITCH- Displaying the Linear Density + + if(dvdphysical.physical.layer[i].start_sector == 0x30000) { + + PrintLog("CDVD driver: Starting Sector: %lu (DVD-ROM, DVD-R, DVD-RW)", + + dvdphysical.physical.layer[i].start_sector); + + } else if(dvdphysical.physical.layer[i].start_sector == 0x31000) { + + PrintLog("CDVD driver: Starting Sector: %lu (DVD-RAM, DVD+RW)", + + dvdphysical.physical.layer[i].start_sector); + + } else { + + PrintLog("CDVD driver: Starting Sector: %lu", + + dvdphysical.physical.layer[i].start_sector); + + } // ENDLONGIF- What does the starting sector tell us? + + PrintLog("CDVD driver: End of Layer 0: %lu", + + dvdphysical.physical.layer[i].end_sector_l0); + + PrintLog("CDVD driver: Ending Sector: %lu", + + dvdphysical.physical.layer[i].end_sector); + + if(dvdphysical.physical.layer[i].bca != 0) + + PrintLog("CDVD driver: BCA data present"); + + } // NEXT i- Work our way through each layer... + +#endif /* VERBOSE_DISC_INFO */ + + + + return(0); // Success. Physical data stored for perusal. + +} // END DVDreadPhysical() + + + +s32 DVDreadCopyright() { + + s32 s32result; + + u8 i; + + int successflag; + + + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: DVDreadCopyright()"); + +#endif /* VERBOSE_FUNCTION */ + + + + successflag = 0; + + + + for(i = 0; i <= dvdphysical.physical.layer_num; i++) { + + memset(&dvdcopyright[i], 0, sizeof(dvd_struct)); + + dvdcopyright[i].type = DVD_STRUCT_COPYRIGHT; + + dvdcopyright[i].copyright.layer_num = i; + + errno = 0; + + s32result = ioctl(devicehandle, DVD_READ_STRUCT, &dvdcopyright[i]); + + if(s32result == 0) { + + successflag = 1; + + } else { + + dvdcopyright[i].type = 0xFF; + + } // ENDIF- + + } // NEXT i- Getting copyright data for every known layer + + + + if(successflag == 0) { + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Error getting Copyright info: (%i) %i:%s", s32result, errno, strerror(errno)); + +#endif /* VERBOSE_WARNINGS */ + + return(-1); + + } // ENDIF- Problem with read of physical data? + + + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD driver: Copyright Information\n"); + + for(i = 0; i <= dvdphysical.physical.layer_num; i++) { + + if(dvdcopyright[i].type != 0xFF) { + + PrintLog("CDVD driver: Layer Number %i CPST %i RMI %i", + + dvdcopyright[i].copyright.layer_num, + + dvdcopyright[i].copyright.cpst, + + dvdcopyright[i].copyright.rmi); + + } // ENDIF- Were we successful reading this one? + + } // NEXT i- Printing out all copyright info found... + +#endif /* VERBOSE_DISC_INFO */ + + + + errno = 0; + + return(0); // Success. Copyright data stored for perusal. + +} // END DVDreadCopyright() + + + +s32 DVDreadBCA() { + + s32 s32result; + + int i; + + + + i = 0; + + errno = 0; + + + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: DVDreadBCA()"); + +#endif /* VERBOSE_FUNCTION */ + + + + memset(&dvdbca, 0, sizeof(dvd_struct)); + + dvdbca.type = DVD_STRUCT_BCA; + + s32result = ioctl(devicehandle, DVD_READ_STRUCT, &dvdbca); + + if((s32result == -1) || (errno != 0)) { + + dvdbca.type = 0xFF; + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Error getting BCA: (%i) %i:%s", s32result, errno, strerror(errno)); + +#endif /* VERBOSE_WARNINGS */ + + return(-1); + + } // ENDIF- Problem with read of physical data? + + + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD driver: BCA Length %i Value:", + + dvdbca.bca.len); + + for(i = 0; i < 188-15; i += 16) { + + HexDump(dvdbca.bca.value+i, 16); + + } // NEXT i- dumping whole key data + +#endif /* VERBOSE_DISC_INFO */ + + + + return(0); // Success. BCA data stored for perusal. + +} // END DVDreadBCA() + + + +s32 DVDreadManufact() { + + s32 s32result; + + u8 i; + + int successflag; + + int j; + + + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: DVDreadManufact()"); + +#endif /* VERBOSE_FUNCTION */ + + + + j = 0; + + successflag = 0; + + + + for(i = 0; i <= dvdphysical.physical.layer_num; i++) { + + memset(&dvdmanufact[i], 0, sizeof(dvd_struct)); + + dvdmanufact[i].type = DVD_STRUCT_MANUFACT; + + dvdmanufact[i].manufact.layer_num = i; + + errno = 0; + + s32result = ioctl(devicehandle, DVD_READ_STRUCT, &dvdmanufact[i]); + + if((s32result != 0) || (errno != 0)) { + + dvdmanufact[i].type = 0xFF; + + } else { + + successflag = 1; + + } // ENDIF- Did we fail to read in some manufacturer data? + + } // NEXT i- Collecting manufacturer data from all layers + + + + if(successflag == 0) { + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Error getting Manufact: (%i) %i:%s", s32result, errno, strerror(errno)); + +#endif /* VERBOSE_WARNINGS */ + + return(-1); + + } // ENDIF- Problem with read of physical data? + + + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD driver: Manufact Data"); + + for(i = 0; i <= dvdphysical.physical.layer_num; i++) { + + if(dvdmanufact[i].type != 0xFF) { + + PrintLog("CDVD driver: Layer %i Length %i Value:", + + dvdmanufact[i].manufact.layer_num, + + dvdmanufact[i].manufact.len); + + for(j = 0; j < 128-15; j += 16) { + + HexDump(dvdmanufact[i].manufact.value+j, 16); + + } // NEXT j- dumping whole key data + + } // ENDIF- Do we have data at this layer? + + } // NEXT i- Running through all the layers + +#endif /* VERBOSE_DISC_INFO */ + + + + errno = 0; + + return(0); // Success. Manufacturer's data stored for perusal. + +} // END DVDreadManufact() + + + + + +// External Functions + + + +// Function Calls from CDVD.c + + + +void InitDVDInfo() { + + int j; + + + + dvdphysical.type = 0xFF; // Using for empty=0xff, full!=0xff test + + dvdbca.type = 0xFF; + + for(j = 0; j < DVD_LAYERS; j++) { + + dvdcopyright[j].type = 0xFF; + + dvdmanufact[j].type = 0xFF; + + } // NEXT j- Zeroing each layer of data + + InitDVDSectorInfo(); + +} // END InitDiscType() + + + +s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer) { + + s32 s32result; + + off64_t offsettarget; + + off64_t offsetresult; + + + + errno = 0; + + s32result = 0; + + offsetresult = 0; + + + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: DVDreadTrack(%i)", lsn); + +#endif /* VERBOSE_FUNCTION */ + + + + if(lsn != dvdlastlsn + 1) { + + offsettarget = lsn; + + offsettarget *= 2048; + + errno = 4; + + while(errno == 4) { + + errno = 0; + + offsetresult = lseek64(devicehandle, offsettarget, SEEK_SET); + + } // ENDWHILE- waiting for the system interruptions to cease. + + if((offsetresult < 0) || (errno != 0)) { + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Error on seek: %i:%s", errno, strerror(errno)); + +#endif /* VERBOSE_WARNINGS */ + + InitDVDSectorInfo(); + + return(-1); + + } // ENDIF- trouble with seek? Reset pointer and abort + + } // ENDIF- Do we have to seek a new position to read? + + + + errno = 4; + + while(errno == 4) { + + errno = 0; + + s32result = read(devicehandle, buffer, 2048); + + } // ENDWHILE- waiting for the system interruptions to cease. + + if((s32result != 2048) || (errno != 0)) { + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: DVD Short Block, Size: %i", s32result); + + PrintLog("CDVD driver: Error: %i:%s", errno, strerror(errno)); + +#endif /* VERBOSE_WARNINGS */ + + InitDVDSectorInfo(); + + return(-1); + + } // ENDIF- Trouble reading the data? Reset pointer and abort + + + + dvdlastlsn = lsn; + + return(0); // Call accomplished + +} // END DVDreadTrack() + + + +s32 DVDgetTN(cdvdTN *cdvdtn) { + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: CDVDgetTN()"); + +#endif /* VERBOSE_FUNCTION */ + + + + // Going to treat this as one large track for now. + + if(cdvdtn != NULL) { + + cdvdtn->strack = 1; + + cdvdtn->etrack = 1; + + } // ENDIF- programmer actually WANTS this info? + + + + return(0); // Call accomplished + +} // END DVDgetTN() + + + +s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd) { + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: CDVDgetTD()"); + +#endif /* VERBOSE_FUNCTION */ + + + + if((newtrack >= 2) && (newtrack != CDROM_LEADOUT)) return(-1); + + + + if(cdvdtd != NULL) { + + cdvdtd->lsn = dvdphysical.physical.layer[0].end_sector + + - dvdphysical.physical.layer[0].start_sector + + + 1; + + cdvdtd->type = CDVD_MODE_2048; + + } // ENDIF- Does the caller REALLY want this data? + + + + return(0); // Call accomplished + +} // END DVDgetTD() + + + +s32 DVDgetDiskType(s32 ioctldisktype) { + + s32 s32result; + + int i; + + s32 tempdisctype; + + + + errno = 0; + + s32result = 0; + + i = 0; + + tempdisctype = CDVD_TYPE_UNKNOWN; + + + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: DVDgetDiskType()"); + +#endif /* VERBOSE_FUNCTION */ + + + + if((ioctldisktype != CDS_DATA_1) && (ioctldisktype != CDS_MIXED)) { + + return(-1); + + } // ENDIF- Not a data disc we know of? Abort then + + + + s32result = DVDreadPhysical(); + + if((s32result != 0) || (errno != 0)) { + + return(-1); + + } // ENDIF- Error reading the DVD physical structure? Not a DVD after all. + + + + if(dvdphysical.physical.layer[0].end_sector >= (2048*1024)) { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("CDVD driver: DVD Found (Dual-Sided)"); + +#endif /* VERBOSE_DISC_TYPE */ + + disctype = CDVD_TYPE_DETCTDVDD; + + } else { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("CDVD driver: DVD Found (Single-Sided)"); + +#endif /* VERBOSE_DISC_TYPE */ + + disctype = CDVD_TYPE_DETCTDVDS; + + } // ENDIF- Definitely a DVD. Size Test? + + + + // Read in the rest of the structures... + + DVDreadCopyright(); + + DVDreadBCA(); + + DVDreadManufact(); + + + + // Test for "Playstation" header + + s32result = DVDreadTrack(16, CDVD_MODE_2048, dvdtempbuffer); + + if(s32result != 0) { + + return(-1); + + } else { + + i = 0; + + while((*(playstationname + i) != 0) && + + (*(playstationname + i) == dvdtempbuffer[8 + i])) { + + i++; + + } // ENDWHILE- Checking each letter of PLAYSTATION name for a match + + if(*(playstationname + i) == 0) { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("CDVD driver: Detected Playstation 2 DVD"); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_PS2DVD; + + } else { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("CDVD driver: Guessing it's a Video DVD"); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_DVDV; + + } // ENDIF- Did we find the Playstation name? + + } // ENDIF- Error reading disc volume information? Invalidate Disc + + + + if(dvdphysical.physical.layer[0].end_sector >= (2048*1024)) { + + tocbuffer[0] = 0x24; // Dual-Sided DVD + + tocbuffer[4] = 0x41; + + tocbuffer[5] = 0x95; + + } else { + + tocbuffer[0] = 0x04; // Single-Sided DVD + + tocbuffer[4] = 0x86; + + tocbuffer[5] = 0x72; + + } // ENDIF- Are there too many sectors for a single-sided disc? + + + + tocbuffer[1] = 0x02; + + tocbuffer[2] = 0xF2; + + tocbuffer[3] = 0x00; + + + + tocbuffer[16] = 0x00; + + tocbuffer[17] = 0x03; + + tocbuffer[18] = 0x00; + + tocbuffer[19] = 0x00; + + + + disctype = tempdisctype; // Triggers the fact the other info is available + + return(disctype); + +} // END DVDgetDiskType() + diff --git a/plugins/CDVDisoEFP/src/Linux/DVD.h b/plugins/CDVDisoEFP/src/Linux/DVD.h index 7dbc1c7c0d..d3837b8520 100644 --- a/plugins/CDVDisoEFP/src/Linux/DVD.h +++ b/plugins/CDVDisoEFP/src/Linux/DVD.h @@ -1,45 +1,90 @@ -/* DVD.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - -#ifndef __DVD_H__ -#define __DVD_H__ - - -#ifndef __LINUX__ -#ifdef __linux__ -#define __LINUX__ -#endif /* __linux__ */ -#endif /* No __LINUX__ */ - -#define CDVDdefs -#include "PS2Edefs.h" - - -// Exported Functions - -extern void HexDump(u8 *strptr, u8 count); -extern void InitDVDInfo(); -extern s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer); -extern s32 DVDgetTN(cdvdTN *cdvdtn); -extern s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd); -extern s32 DVDgetDiskType(s32 ioctldisktype); - - -#endif /* __DVD_H__ */ +/* DVD.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + +#ifndef __DVD_H__ + +#define __DVD_H__ + + + + + +#ifndef __LINUX__ + +#ifdef __linux__ + +#define __LINUX__ + +#endif /* __linux__ */ + +#endif /* No __LINUX__ */ + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + + + +// Exported Functions + + + +extern void HexDump(u8 *strptr, u8 count); + +extern void InitDVDInfo(); + +extern s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer); + +extern s32 DVDgetTN(cdvdTN *cdvdtn); + +extern s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd); + +extern s32 DVDgetDiskType(s32 ioctldisktype); + + + + + +#endif /* __DVD_H__ */ + diff --git a/plugins/CDVDisoEFP/src/Linux/aboutbox.c b/plugins/CDVDisoEFP/src/Linux/aboutbox.c index 80b73f5e53..b722ae5367 100644 --- a/plugins/CDVDisoEFP/src/Linux/aboutbox.c +++ b/plugins/CDVDisoEFP/src/Linux/aboutbox.c @@ -1,106 +1,212 @@ -/* aboutbox.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // NULL -#include // sprintf() - -#include // gtk_button_new_with_label() -#include // gtk_container_add() -#include // gtk_hbutton_box_new() -#include // gtk_label_new() -#include // gtk_init(), gtk_main(), gtk_main_quit() -#include // gtk_vbox_new() -#include // gtk_window_new() - -#include "version.h" -#include "aboutbox.h" - - -struct AboutBoxData aboutbox; - - -gint AboutBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - if(aboutbox.window != NULL) { - gtk_widget_destroy(aboutbox.window); - aboutbox.window = NULL; - } // ENDIF- Do we have an About Box still? - - gtk_main_quit(); - return(TRUE); -} // END AboutBoxCancelEvent() - - -void AboutBoxDisplay() { - GtkWidget *item; - GtkWidget *container; - GtkWidget *vbox1; - char templine[256]; - - aboutbox.window = NULL; - aboutbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_container_set_border_width(GTK_CONTAINER(aboutbox.window), 5); - gtk_window_set_title(GTK_WINDOW(aboutbox.window), "About CDVDisoEFP"); - gtk_window_set_position(GTK_WINDOW(aboutbox.window), GTK_WIN_POS_CENTER); - gtk_window_set_modal(GTK_WINDOW(aboutbox.window), TRUE); - gtk_window_set_resizable(GTK_WINDOW(aboutbox.window), FALSE); - - g_signal_connect(G_OBJECT(aboutbox.window), "delete_event", - G_CALLBACK(AboutBoxCancelEvent), NULL); - - vbox1 = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(aboutbox.window), vbox1); - gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); - gtk_widget_show(vbox1); - - sprintf(templine, "%s v%i.%i", libname, revision, build); - item = gtk_label_new(templine); - gtk_box_pack_start(GTK_BOX(vbox1), item, FALSE, FALSE, 0); - gtk_widget_show(item); - item = NULL; - - item = gtk_label_new("Current Author: efp"); - gtk_box_pack_start(GTK_BOX(vbox1), item, FALSE, FALSE, 0); - gtk_widget_show(item); - item = NULL; - - item = gtk_label_new("Original code by: linuzappz & shadow"); - gtk_box_pack_start(GTK_BOX(vbox1), item, FALSE, FALSE, 0); - gtk_widget_show(item); - item = NULL; - - container = gtk_hbutton_box_new(); - gtk_box_pack_start(GTK_BOX(vbox1), container, TRUE, TRUE, 0); - gtk_widget_show(container); - - item = gtk_button_new_with_label("Ok"); - gtk_container_add(GTK_CONTAINER(container), item); - GTK_WIDGET_SET_FLAGS(item, GTK_CAN_DEFAULT); - gtk_widget_show(item); - - g_signal_connect(G_OBJECT(item), "clicked", - G_CALLBACK(AboutBoxCancelEvent), NULL); - item = NULL; - container = NULL; - vbox1 = NULL; - - gtk_widget_show(aboutbox.window); - gtk_main(); -} // END AboutDisplay() +/* aboutbox.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // sprintf() + + + +#include // gtk_button_new_with_label() + +#include // gtk_container_add() + +#include // gtk_hbutton_box_new() + +#include // gtk_label_new() + +#include // gtk_init(), gtk_main(), gtk_main_quit() + +#include // gtk_vbox_new() + +#include // gtk_window_new() + + + +#include "version.h" + +#include "aboutbox.h" + + + + + +struct AboutBoxData aboutbox; + + + + + +gint AboutBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + if(aboutbox.window != NULL) { + + gtk_widget_destroy(aboutbox.window); + + aboutbox.window = NULL; + + } // ENDIF- Do we have an About Box still? + + + + gtk_main_quit(); + + return(TRUE); + +} // END AboutBoxCancelEvent() + + + + + +void AboutBoxDisplay() { + + GtkWidget *item; + + GtkWidget *container; + + GtkWidget *vbox1; + + char templine[256]; + + + + aboutbox.window = NULL; + + aboutbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + gtk_container_set_border_width(GTK_CONTAINER(aboutbox.window), 5); + + gtk_window_set_title(GTK_WINDOW(aboutbox.window), "About CDVDisoEFP"); + + gtk_window_set_position(GTK_WINDOW(aboutbox.window), GTK_WIN_POS_CENTER); + + gtk_window_set_modal(GTK_WINDOW(aboutbox.window), TRUE); + + gtk_window_set_resizable(GTK_WINDOW(aboutbox.window), FALSE); + + + + g_signal_connect(G_OBJECT(aboutbox.window), "delete_event", + + G_CALLBACK(AboutBoxCancelEvent), NULL); + + + + vbox1 = gtk_vbox_new(FALSE, 5); + + gtk_container_add(GTK_CONTAINER(aboutbox.window), vbox1); + + gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); + + gtk_widget_show(vbox1); + + + + sprintf(templine, "%s v%i.%i", libname, revision, build); + + item = gtk_label_new(templine); + + gtk_box_pack_start(GTK_BOX(vbox1), item, FALSE, FALSE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + item = gtk_label_new("Current Author: efp"); + + gtk_box_pack_start(GTK_BOX(vbox1), item, FALSE, FALSE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + item = gtk_label_new("Original code by: linuzappz & shadow"); + + gtk_box_pack_start(GTK_BOX(vbox1), item, FALSE, FALSE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + container = gtk_hbutton_box_new(); + + gtk_box_pack_start(GTK_BOX(vbox1), container, TRUE, TRUE, 0); + + gtk_widget_show(container); + + + + item = gtk_button_new_with_label("Ok"); + + gtk_container_add(GTK_CONTAINER(container), item); + + GTK_WIDGET_SET_FLAGS(item, GTK_CAN_DEFAULT); + + gtk_widget_show(item); + + + + g_signal_connect(G_OBJECT(item), "clicked", + + G_CALLBACK(AboutBoxCancelEvent), NULL); + + item = NULL; + + container = NULL; + + vbox1 = NULL; + + + + gtk_widget_show(aboutbox.window); + + gtk_main(); + +} // END AboutDisplay() + diff --git a/plugins/CDVDisoEFP/src/Linux/aboutbox.h b/plugins/CDVDisoEFP/src/Linux/aboutbox.h index bf1df52ca0..875772f0c6 100644 --- a/plugins/CDVDisoEFP/src/Linux/aboutbox.h +++ b/plugins/CDVDisoEFP/src/Linux/aboutbox.h @@ -1,39 +1,78 @@ -/* aboutbox.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef ABOUTBOX_H -#define ABOUTBOX_H - - -#include - - -struct AboutBoxData { - GtkWidget *window; // GtkWindow - About Box -}; - -extern struct AboutBoxData aboutbox; - - -extern void AboutBoxDisplay(); - - -#endif /* ABOUTBOX_H */ +/* aboutbox.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef ABOUTBOX_H + +#define ABOUTBOX_H + + + + + +#include + + + + + +struct AboutBoxData { + + GtkWidget *window; // GtkWindow - About Box + +}; + + + +extern struct AboutBoxData aboutbox; + + + + + +extern void AboutBoxDisplay(); + + + + + +#endif /* ABOUTBOX_H */ + diff --git a/plugins/CDVDisoEFP/src/Linux/actualfile.c b/plugins/CDVDisoEFP/src/Linux/actualfile.c index 64eaa69a7b..947cbe3a6c 100644 --- a/plugins/CDVDisoEFP/src/Linux/actualfile.c +++ b/plugins/CDVDisoEFP/src/Linux/actualfile.c @@ -1,222 +1,444 @@ -/* actualfile.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // errno -#include // open() -#include // rename() -#include // strerror() -#include // stat64(), open(), fstat() -#include // stat64(), open(), fstat(), lseek64() -#include // stat64(), fstat(), lseek64(), read(), close(), write() -// unlink() - -#include "logfile.h" -#include "actualfile.h" - - -int IsActualFile(const char *filename) { - int retval; - struct stat64 filestat; - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: IsActualFile(%s)", filename); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - errno = 0; - retval = stat64(filename, &filestat); - if((retval < 0) || (errno != 0)) { -#ifdef VERBOSE_WARNING_ACTUALFILE - PrintLog("CDVDiso file: Error retrieving stats on %s", filename); - PrintLog("CDVDiso file: %i:%s\n", errno, strerror(errno)); -#endif /* VERBOSE_WARNING_ACTUALFILE */ - return(-1); // Name doesn't exist. - } // ENDIF- Trouble getting stat on a file? - - if(S_ISREG(filestat.st_mode) == 0) return(-2); // Not a regular file. - return(0); // Yep, that's a file. -} // END IsActualFile() - - -void ActualFileDelete(const char *filename) { -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileDelete(%s)", filename); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - unlink(filename); -} // END ActualFileDelete() - - -void ActualFileRename(const char *origname, const char *newname) { -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileRename(%s->%s)", origname, newname); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - rename(origname, newname); - return; -} // END ActualFileRename() - - -ACTUALHANDLE ActualFileOpenForRead(const char *filename) { - int newhandle; - - if(filename == NULL) return(-1); - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileOpenForRead(%s)", filename); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - errno = 0; - newhandle = open(filename, O_RDONLY | O_LARGEFILE); - if((newhandle < 0) || (errno != 0)) { -#ifdef VERBOSE_WARNING_ACTUALFILE - PrintLog("CDVDiso file: Error opening file %s\n", filename); - PrintLog("CDVDiso file: (%i) %i:%s\n", newhandle, errno, strerror(errno)); -#endif /* VERBOSE_WARNING_ACTUALFILE */ - return(-1); - } // ENDIF- Error? Abort - - return(newhandle); -} // END ActualFileOpenForRead() - - -off64_t ActualFileSize(ACTUALHANDLE handle) { - int retval; - struct stat64 filestat; - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileSize()\n"); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - errno = 0; - retval = fstat64(handle, &filestat); - if((retval < 0) || (errno != 0)) return(-1); // Name doesn't exist. - return(filestat.st_size); -} // END ActualFileSize() - - -int ActualFileSeek(ACTUALHANDLE handle, off64_t position) { - off64_t moved; - - if(handle < 0) return(-1); - if(position < 0) return(-1); // Maybe... position = 0? - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileSeek(%lli)", position); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - errno = 0; - moved = lseek64(handle, position, SEEK_SET); - if(errno != 0) { -#ifdef VERBOSE_WARNING_ACTUALFILE - PrintLog("CDVDiso file: Error on seek (%lli)", position); - PrintLog("CDVDiso file: %i:%s\n", errno, strerror(errno)); -#endif /* VERBOSE_WARNING_ACTUALFILE */ - return(-1); - } // ENDIF- Error? Abort - - return(0); -} // END ActualFileSeek() - - -int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer) { - int retval; - - if(handle == ACTUALHANDLENULL) return(-1); - if(bytes < 1) return(-1); - if(buffer == NULL) return(-1); - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileRead(%i)", bytes); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - errno = 0; - retval = read(handle, buffer, bytes); - if((retval < 0) || (errno != 0)) { -#ifdef VERBOSE_WARNING_ACTUALFILE - PrintLog("CDVDiso file: Error reading from file!"); - PrintLog("CDVDiso file: %i:%s", errno, strerror(errno)); -#endif /* VERBOSE_WARNING_ACTUALFILE */ - // return(-1); - } // ENDIF- Error? Abort - - return(retval); // Send back how many bytes read -} // END ActualFileRead() - - -void ActualFileClose(ACTUALHANDLE handle) { - if(handle < 0) return; - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileClose()"); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - errno = 0; - close(handle); - return; -} // END ActualFileClose() - - -ACTUALHANDLE ActualFileOpenForWrite(const char *filename) { - int newhandle; - - if(filename == NULL) return(-1); - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileOpenForWrite(%s)", filename); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - errno = 0; - newhandle = open(filename, O_WRONLY | O_CREAT | O_LARGEFILE, 0644); - if((newhandle < 0) || (errno != 0)) { -#ifdef VERBOSE_WARNING_ACTUALFILE - PrintLog("CDVDiso file: Error opening file %s", filename); - PrintLog("CDVDiso file: (%i) %i:%s", newhandle, errno, strerror(errno)); -#endif /* VERBOSE_WARNING_ACTUALFILE */ - return(-1); - } // ENDIF- Error? Abort - - return(newhandle); -} // END ActualFileOpenForWrite() - - -int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer) { - int retval; - - if(handle < 0) return(-1); - if(bytes < 1) return(-1); - if(buffer == NULL) return(-1); - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileWrite(%i)", bytes); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - errno = 0; - retval = write(handle, buffer, bytes); - if((retval < 0) || (errno != 0)) { -#ifdef VERBOSE_WARNING_ACTUALFILE - PrintLog("CDVDiso file: Error writing to file!"); - PrintLog("CDVDiso file: %i:%s", errno, strerror(errno)); -#endif /* VERBOSE_WARNING_ACTUALFILE */ - // return(-1); - } // ENDIF- Error? Abort - - return(retval); // Send back how many bytes written -} // END ActualFileWrite() +/* actualfile.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // errno + +#include // open() + +#include // rename() + +#include // strerror() + +#include // stat64(), open(), fstat() + +#include // stat64(), open(), fstat(), lseek64() + +#include // stat64(), fstat(), lseek64(), read(), close(), write() + +// unlink() + + + +#include "logfile.h" + +#include "actualfile.h" + + + + + +int IsActualFile(const char *filename) { + + int retval; + + struct stat64 filestat; + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: IsActualFile(%s)", filename); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + errno = 0; + + retval = stat64(filename, &filestat); + + if((retval < 0) || (errno != 0)) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error retrieving stats on %s", filename); + + PrintLog("CDVDiso file: %i:%s\n", errno, strerror(errno)); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + return(-1); // Name doesn't exist. + + } // ENDIF- Trouble getting stat on a file? + + + + if(S_ISREG(filestat.st_mode) == 0) return(-2); // Not a regular file. + + return(0); // Yep, that's a file. + +} // END IsActualFile() + + + + + +void ActualFileDelete(const char *filename) { + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileDelete(%s)", filename); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + unlink(filename); + +} // END ActualFileDelete() + + + + + +void ActualFileRename(const char *origname, const char *newname) { + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileRename(%s->%s)", origname, newname); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + rename(origname, newname); + + return; + +} // END ActualFileRename() + + + + + +ACTUALHANDLE ActualFileOpenForRead(const char *filename) { + + int newhandle; + + + + if(filename == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileOpenForRead(%s)", filename); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + errno = 0; + + newhandle = open(filename, O_RDONLY | O_LARGEFILE); + + if((newhandle < 0) || (errno != 0)) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error opening file %s\n", filename); + + PrintLog("CDVDiso file: (%i) %i:%s\n", newhandle, errno, strerror(errno)); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + return(-1); + + } // ENDIF- Error? Abort + + + + return(newhandle); + +} // END ActualFileOpenForRead() + + + + + +off64_t ActualFileSize(ACTUALHANDLE handle) { + + int retval; + + struct stat64 filestat; + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileSize()\n"); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + errno = 0; + + retval = fstat64(handle, &filestat); + + if((retval < 0) || (errno != 0)) return(-1); // Name doesn't exist. + + return(filestat.st_size); + +} // END ActualFileSize() + + + + + +int ActualFileSeek(ACTUALHANDLE handle, off64_t position) { + + off64_t moved; + + + + if(handle < 0) return(-1); + + if(position < 0) return(-1); // Maybe... position = 0? + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileSeek(%lli)", position); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + errno = 0; + + moved = lseek64(handle, position, SEEK_SET); + + if(errno != 0) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error on seek (%lli)", position); + + PrintLog("CDVDiso file: %i:%s\n", errno, strerror(errno)); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + return(-1); + + } // ENDIF- Error? Abort + + + + return(0); + +} // END ActualFileSeek() + + + + + +int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer) { + + int retval; + + + + if(handle == ACTUALHANDLENULL) return(-1); + + if(bytes < 1) return(-1); + + if(buffer == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileRead(%i)", bytes); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + errno = 0; + + retval = read(handle, buffer, bytes); + + if((retval < 0) || (errno != 0)) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error reading from file!"); + + PrintLog("CDVDiso file: %i:%s", errno, strerror(errno)); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + // return(-1); + + } // ENDIF- Error? Abort + + + + return(retval); // Send back how many bytes read + +} // END ActualFileRead() + + + + + +void ActualFileClose(ACTUALHANDLE handle) { + + if(handle < 0) return; + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileClose()"); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + errno = 0; + + close(handle); + + return; + +} // END ActualFileClose() + + + + + +ACTUALHANDLE ActualFileOpenForWrite(const char *filename) { + + int newhandle; + + + + if(filename == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileOpenForWrite(%s)", filename); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + errno = 0; + + newhandle = open(filename, O_WRONLY | O_CREAT | O_LARGEFILE, 0644); + + if((newhandle < 0) || (errno != 0)) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error opening file %s", filename); + + PrintLog("CDVDiso file: (%i) %i:%s", newhandle, errno, strerror(errno)); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + return(-1); + + } // ENDIF- Error? Abort + + + + return(newhandle); + +} // END ActualFileOpenForWrite() + + + + + +int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer) { + + int retval; + + + + if(handle < 0) return(-1); + + if(bytes < 1) return(-1); + + if(buffer == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileWrite(%i)", bytes); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + errno = 0; + + retval = write(handle, buffer, bytes); + + if((retval < 0) || (errno != 0)) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error writing to file!"); + + PrintLog("CDVDiso file: %i:%s", errno, strerror(errno)); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + // return(-1); + + } // ENDIF- Error? Abort + + + + return(retval); // Send back how many bytes written + +} // END ActualFileWrite() + diff --git a/plugins/CDVDisoEFP/src/Linux/actualfile.h b/plugins/CDVDisoEFP/src/Linux/actualfile.h index a678b634d6..b7a72df55f 100644 --- a/plugins/CDVDisoEFP/src/Linux/actualfile.h +++ b/plugins/CDVDisoEFP/src/Linux/actualfile.h @@ -1,50 +1,100 @@ -/* actualfile.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef ACTUALFILE_H -#define ACTUALFILE_H - - -#include // off64_t - - -#define ACTUALHANDLE int -#define ACTUALHANDLENULL -1 - -// #define VERBOSE_FUNCTION_ACTUALFILE -// #define VERBOSE_WARNING_ACTUALFILE - - -extern int IsActualFile(const char *filename); -extern void ActualFileDelete(const char *filename); -extern void ActualFileRename(const char *origname, const char *newname); - -extern ACTUALHANDLE ActualFileOpenForRead(const char *filename); -extern off64_t ActualFileSize(ACTUALHANDLE handle); -extern int ActualFileSeek(ACTUALHANDLE handle, off64_t position); -extern int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer); -extern void ActualFileClose(ACTUALHANDLE handle); - -extern ACTUALHANDLE ActualFileOpenForWrite(const char *filename); -extern int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer); - - -#endif /* ACTUALFILE_H */ +/* actualfile.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef ACTUALFILE_H + +#define ACTUALFILE_H + + + + + +#include // off64_t + + + + + +#define ACTUALHANDLE int + +#define ACTUALHANDLENULL -1 + + + +// #define VERBOSE_FUNCTION_ACTUALFILE + +// #define VERBOSE_WARNING_ACTUALFILE + + + + + +extern int IsActualFile(const char *filename); + +extern void ActualFileDelete(const char *filename); + +extern void ActualFileRename(const char *origname, const char *newname); + + + +extern ACTUALHANDLE ActualFileOpenForRead(const char *filename); + +extern off64_t ActualFileSize(ACTUALHANDLE handle); + +extern int ActualFileSeek(ACTUALHANDLE handle, off64_t position); + +extern int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer); + +extern void ActualFileClose(ACTUALHANDLE handle); + + + +extern ACTUALHANDLE ActualFileOpenForWrite(const char *filename); + +extern int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer); + + + + + +#endif /* ACTUALFILE_H */ + diff --git a/plugins/CDVDisoEFP/src/Linux/comparisonbox.c b/plugins/CDVDisoEFP/src/Linux/comparisonbox.c index 3eb216bef1..4b18abd64b 100644 --- a/plugins/CDVDisoEFP/src/Linux/comparisonbox.c +++ b/plugins/CDVDisoEFP/src/Linux/comparisonbox.c @@ -1,415 +1,830 @@ -/* comparisonbox.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // NULL -#include // sprintf() -#include // strcpy() - -#include // gtk_button_new_with_label() -#include // gtk_container_add() -#include // gtk_entry_new() -#include // gtk_file_selection_set_filename() -#include // gtk_hbutton_box_new() -#include // gtk_hbox_new() -#include // gtk_hseparator_new() -#include // gtk_label_new() -#include // gtk_init(), gtk_main(), gtk_main_quit() -#include // gtk_vbox_new() -#include -#include // gtk_window_new() - -#include "logfile.h" -#include "conf.h" -#include "isofile.h" -#include "isocompress.h" // compressdesc[] -#include "multifile.h" // multinames[] -#include "tablerebuild.h" // IsoTableRebuild() -#include "progressbox.h" -#include "messagebox.h" - - -struct MainBoxData { - GtkWidget *window; // GtkWindow - GtkWidget *file1; // GtkEntry - GtkWidget *desc1; // GtkLabel - GtkWidget *file2; // GtkEntry - GtkWidget *desc2; // GtkLabel - GtkWidget *okbutton; // GtkButton - // Leaving the Cancel button unblocked... for emergency shutdown - - int stop; // Variable signal to stop long processes -}; - - -struct MainBoxData mainbox; - - -void MainBoxDestroy() { - if(mainbox.window != NULL) { - gtk_widget_destroy(mainbox.window); - mainbox.window = NULL; - mainbox.file1 = NULL; - mainbox.desc1 = NULL; - mainbox.file2 = NULL; - mainbox.desc2 = NULL; - mainbox.okbutton = NULL; - } // ENDIF- Do we have a Main Window still? -} // END MainBoxDestroy() - - -void MainBoxUnfocus() { - gtk_widget_set_sensitive(mainbox.file1, FALSE); - gtk_widget_set_sensitive(mainbox.file2, FALSE); - gtk_widget_set_sensitive(mainbox.okbutton, FALSE); - gtk_window_iconify(GTK_WINDOW(mainbox.window)); -} // END MainBoxUnfocus() - - -gint MainBoxFile1Event(GtkWidget *widget, GdkEvent event, gpointer data) { - int returnval; - char templine[256]; - struct IsoFile *tempfile; - - returnval = IsIsoFile(gtk_entry_get_text(GTK_ENTRY(mainbox.file1))); - if(returnval == -1) { - gtk_label_set_text(GTK_LABEL(mainbox.desc1), "File Type: ---"); - return(TRUE); - } // ENDIF- Not a name of any sort? - - if(returnval == -2) { - gtk_label_set_text(GTK_LABEL(mainbox.desc1), "File Type: Not a file"); - return(TRUE); - } // ENDIF- Not a regular file? - - if(returnval == -3) { - gtk_label_set_text(GTK_LABEL(mainbox.desc1), "File Type: Not a valid image file"); - return(TRUE); - } // ENDIF- Not an Image file? - - if(returnval == -4) { - gtk_label_set_text(GTK_LABEL(mainbox.desc1), "File Type: Missing Table File (will rebuild)"); - return(TRUE); - } // ENDIF- Missing Compression seek table? - - tempfile = IsoFileOpenForRead(gtk_entry_get_text(GTK_ENTRY(mainbox.file1))); - sprintf(templine, "File Type: %s%s%s", - multinames[tempfile->multi], - tempfile->imagename, - compressdesc[tempfile->compress]); - gtk_label_set_text(GTK_LABEL(mainbox.desc1), templine); - tempfile = IsoFileClose(tempfile); - return(TRUE); -} // END MainBoxFileEvent() - - -gint MainBoxFile2Event(GtkWidget *widget, GdkEvent event, gpointer data) { - int returnval; - char templine[256]; - struct IsoFile *tempfile; - - returnval = IsIsoFile(gtk_entry_get_text(GTK_ENTRY(mainbox.file2))); - if(returnval == -1) { - gtk_label_set_text(GTK_LABEL(mainbox.desc2), "File Type: ---"); - return(TRUE); - } // ENDIF- Not a name of any sort? - - if(returnval == -2) { - gtk_label_set_text(GTK_LABEL(mainbox.desc2), "File Type: Not a file"); - return(TRUE); - } // ENDIF- Not a regular file? - - if(returnval == -3) { - gtk_label_set_text(GTK_LABEL(mainbox.desc2), "File Type: Not a valid image file"); - return(TRUE); - } // ENDIF- Not an Image file? - - if(returnval == -4) { - gtk_label_set_text(GTK_LABEL(mainbox.desc2), "File Type: Missing Table File (will rebuild)"); - return(TRUE); - } // ENDIF- Missing Compression seek table? - - tempfile = IsoFileOpenForRead(gtk_entry_get_text(GTK_ENTRY(mainbox.file2))); - sprintf(templine, "File Type: %s%s%s", - multinames[tempfile->multi], - tempfile->imagename, - compressdesc[tempfile->compress]); - gtk_label_set_text(GTK_LABEL(mainbox.desc2), templine); - tempfile = IsoFileClose(tempfile); - return(TRUE); -} // END MainBoxFileEvent() - - -void MainBoxRefocus() { - GdkEvent event; - - MainBoxFile1Event(NULL, event, NULL); - MainBoxFile2Event(NULL, event, NULL); - - gtk_widget_set_sensitive(mainbox.file1, TRUE); - gtk_widget_set_sensitive(mainbox.file2, TRUE); - gtk_widget_set_sensitive(mainbox.okbutton, TRUE); - gtk_window_set_focus(GTK_WINDOW(mainbox.window), mainbox.file1); - gtk_window_deiconify(GTK_WINDOW(mainbox.window)); -} // END MainBoxRefocus() - - -gint MainBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - mainbox.stop = 1; // Halt all long processess... - - MessageBoxDestroy(); - ProgressBoxDestroy(); - MainBoxDestroy(); - - gtk_main_quit(); - return(TRUE); -} // END MainBoxCancelEvent() - - -gint MainBoxOKEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - const char *tempisoname1; - const char *tempisoname2; - struct IsoFile *tempiso1; - struct IsoFile *tempiso2; - int stop; - off64_t endsector; - off64_t sector; - int retval; - char tempblock1[2448]; - char tempblock2[2448]; - int i; - - MainBoxUnfocus(); - - tempisoname1 = gtk_entry_get_text(GTK_ENTRY(mainbox.file1)); - tempisoname2 = gtk_entry_get_text(GTK_ENTRY(mainbox.file2)); - tempiso1 = NULL; - tempiso2 = NULL; - - tempiso1 = IsoFileOpenForRead(tempisoname1); - if(tempiso1 == NULL) { - MainBoxRefocus(); - MessageBoxShow("First file is not a Valid Image File.", 0); - tempisoname1 = NULL; - tempisoname2 = NULL; - return(TRUE); - } // ENDIF- Not an ISO file? Message and Stop here. - - tempiso2 = IsoFileOpenForRead(tempisoname2); - if(tempiso2 == NULL) { - MainBoxRefocus(); - MessageBoxShow("Second file is not a Valid Image File.", 0); - tempiso1 = IsoFileClose(tempiso1); - tempisoname1 = NULL; - tempisoname2 = NULL; - return(TRUE); - } // ENDIF- Not an ISO file? Message and Stop here. - - if(tempiso1->blocksize != tempiso2->blocksize) { - MainBoxRefocus(); - MessageBoxShow("Block sizes in Image files do not match.", 0); - tempiso1 = IsoFileClose(tempiso1); - tempiso2 = IsoFileClose(tempiso2); - tempisoname1 = NULL; - tempisoname2 = NULL; - return(TRUE); - } // ENDIF- Not an ISO file? Message and Stop here. - - if(tempiso1->multi == 1) { - i = 0; - while((i < 10) && - (IsoFileSeek(tempiso1, tempiso1->multisectorend[i] + 1) == 0)) i++; - endsector = tempiso1->multisectorend[tempiso1->multiend]; - } else { - endsector = tempiso1->filesectorsize; - } // ENDIF- Get ending sector from multifile? (Or single file?) - IsoFileSeek(tempiso1, 0); - - if(tempiso2->multi == 1) { - i = 0; - while((i < 10) && - (IsoFileSeek(tempiso2, tempiso2->multisectorend[i] + 1) == 0)) i++; - sector = tempiso2->multisectorend[tempiso2->multiend]; - } else { - sector = tempiso2->filesectorsize; - } // ENDIF- Get ending sector from multifile? (Or single file?) - IsoFileSeek(tempiso2, 0); - if(sector != endsector) { - MainBoxRefocus(); - MessageBoxShow("Number of blocks in Image files do not match.", 0); - tempiso1 = IsoFileClose(tempiso1); - tempiso2 = IsoFileClose(tempiso2); - tempisoname1 = NULL; - tempisoname2 = NULL; - return(TRUE); - } // ENDIF- Number of blocks don't match? Say so. - - sprintf(tempblock1, "%s == %s ?", tempisoname1, tempisoname2); - ProgressBoxStart(tempblock1, endsector); - - stop = 0; - mainbox.stop = 0; - progressbox.stop = 0; - while((stop == 0) && (tempiso1->sectorpos < endsector)) { - retval = IsoFileRead(tempiso1, tempblock1); - if(retval < 0) { - MainBoxRefocus(); - MessageBoxShow("Trouble reading first file.", 0); - stop = 1; - } else { - retval = IsoFileRead(tempiso2, tempblock2); - if(retval < 0) { - MainBoxRefocus(); - MessageBoxShow("Trouble reading second file.", 0); - stop = 1; - } else { - i = 0; - while((i < tempiso1->blocksize) && (tempblock1[i] == tempblock2[i])) i++; - if(i < tempiso1->blocksize) { - MainBoxRefocus(); - MessageBoxShow("Trouble reading second file.", 0); - stop = 1; - } // ENDIF- Sectors don't match? Say so. - } // ENDIF- Trouble reading second file? - } // ENDIF- Trouble reading first file? - - ProgressBoxTick(tempiso1->sectorpos); - while(gtk_events_pending()) gtk_main_iteration(); - - if(mainbox.stop != 0) stop = 2; - if(progressbox.stop != 0) stop = 2; - } // ENDWHILE- Comparing two files... sector by sector - - if(stop == 0) { - MainBoxRefocus(); - MessageBoxShow("Images Match.", 0); - } // ENDIF- Everything checked out? Say so. - tempiso1 = IsoFileClose(tempiso1); - tempiso2 = IsoFileClose(tempiso2); - tempisoname1 = NULL; - tempisoname2 = NULL; - return(TRUE); -} // END MainBoxOKEvent() - - -void MainBoxDisplay() { - GtkWidget *item; - GtkWidget *hbox1; - GtkWidget *vbox1; - - mainbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_container_set_border_width(GTK_CONTAINER(mainbox.window), 5); - gtk_window_set_title(GTK_WINDOW(mainbox.window), "CDVDisoEFP Comparsion"); - gtk_window_set_position(GTK_WINDOW(mainbox.window), GTK_WIN_POS_CENTER); - // gtk_window_set_resizable(GTK_WINDOW(mainbox.window), FALSE); - - g_signal_connect(G_OBJECT(mainbox.window), "delete_event", - G_CALLBACK(MainBoxCancelEvent), NULL); - - vbox1 = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(mainbox.window), vbox1); - gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); - gtk_widget_show(vbox1); - - hbox1 = gtk_hbox_new(FALSE, 10); - gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); - gtk_widget_show(hbox1); - - item = gtk_label_new("First Iso File:"); - gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); - gtk_widget_show(item); - item = NULL; - - mainbox.file1 = gtk_entry_new(); - gtk_box_pack_start(GTK_BOX(hbox1), mainbox.file1, TRUE, TRUE, 0); - gtk_widget_show(mainbox.file1); - g_signal_connect(G_OBJECT(mainbox.file1), "changed", - G_CALLBACK(MainBoxFile1Event), NULL); - hbox1 = NULL; - - mainbox.desc1 = gtk_label_new("File Type: ---"); - gtk_box_pack_start(GTK_BOX(vbox1), mainbox.desc1, FALSE, FALSE, 0); - gtk_widget_show(mainbox.desc1); - - item = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(vbox1), item, TRUE, TRUE, 0); - gtk_widget_show(item); - item = NULL; - - hbox1 = gtk_hbox_new(FALSE, 10); - gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); - gtk_widget_show(hbox1); - - item = gtk_label_new("Second Iso File:"); - gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); - gtk_widget_show(item); - item = NULL; - - mainbox.file2 = gtk_entry_new(); - gtk_box_pack_start(GTK_BOX(hbox1), mainbox.file2, TRUE, TRUE, 0); - gtk_widget_show(mainbox.file2); - g_signal_connect(G_OBJECT(mainbox.file2), "changed", - G_CALLBACK(MainBoxFile2Event), NULL); - hbox1 = NULL; - - mainbox.desc2 = gtk_label_new("File Type: ---"); - gtk_box_pack_start(GTK_BOX(vbox1), mainbox.desc2, FALSE, FALSE, 0); - gtk_widget_show(mainbox.desc2); - - hbox1 = gtk_hbutton_box_new(); - gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); - gtk_widget_show(hbox1); - - mainbox.okbutton = gtk_button_new_with_label("Compare"); - gtk_box_pack_start(GTK_BOX(hbox1), mainbox.okbutton, TRUE, TRUE, 0); - gtk_widget_show(mainbox.okbutton); - g_signal_connect(G_OBJECT(mainbox.okbutton), "clicked", - G_CALLBACK(MainBoxOKEvent), NULL); - - item = gtk_button_new_with_label("Exit"); - gtk_box_pack_start(GTK_BOX(hbox1), item, TRUE, TRUE, 0); - gtk_widget_show(item); - g_signal_connect(G_OBJECT(item), "clicked", - G_CALLBACK(MainBoxCancelEvent), NULL); - item = NULL; - hbox1 = NULL; - vbox1 = NULL; - - // We held off setting the name until now... so description would show. - gtk_entry_set_text(GTK_ENTRY(mainbox.file1), conf.isoname); - gtk_entry_set_text(GTK_ENTRY(mainbox.file2), conf.isoname); -} // END MainBoxDisplay() - - -int main(int argc, char *argv[]) { - gtk_init(NULL, NULL); - - OpenLog(); - InitConf(); - LoadConf(); - MainBoxDisplay(); - ProgressBoxDisplay(); - MessageBoxDisplay(); - - gtk_widget_show_all(mainbox.window); - gtk_main(); - CloseLog(); - return(0); -} // END main() +/* comparisonbox.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // sprintf() + +#include // strcpy() + + + +#include // gtk_button_new_with_label() + +#include // gtk_container_add() + +#include // gtk_entry_new() + +#include // gtk_file_selection_set_filename() + +#include // gtk_hbutton_box_new() + +#include // gtk_hbox_new() + +#include // gtk_hseparator_new() + +#include // gtk_label_new() + +#include // gtk_init(), gtk_main(), gtk_main_quit() + +#include // gtk_vbox_new() + +#include + +#include // gtk_window_new() + + + +#include "logfile.h" + +#include "conf.h" + +#include "isofile.h" + +#include "isocompress.h" // compressdesc[] + +#include "multifile.h" // multinames[] + +#include "tablerebuild.h" // IsoTableRebuild() + +#include "progressbox.h" + +#include "messagebox.h" + + + + + +struct MainBoxData { + + GtkWidget *window; // GtkWindow + + GtkWidget *file1; // GtkEntry + + GtkWidget *desc1; // GtkLabel + + GtkWidget *file2; // GtkEntry + + GtkWidget *desc2; // GtkLabel + + GtkWidget *okbutton; // GtkButton + + // Leaving the Cancel button unblocked... for emergency shutdown + + + + int stop; // Variable signal to stop long processes + +}; + + + + + +struct MainBoxData mainbox; + + + + + +void MainBoxDestroy() { + + if(mainbox.window != NULL) { + + gtk_widget_destroy(mainbox.window); + + mainbox.window = NULL; + + mainbox.file1 = NULL; + + mainbox.desc1 = NULL; + + mainbox.file2 = NULL; + + mainbox.desc2 = NULL; + + mainbox.okbutton = NULL; + + } // ENDIF- Do we have a Main Window still? + +} // END MainBoxDestroy() + + + + + +void MainBoxUnfocus() { + + gtk_widget_set_sensitive(mainbox.file1, FALSE); + + gtk_widget_set_sensitive(mainbox.file2, FALSE); + + gtk_widget_set_sensitive(mainbox.okbutton, FALSE); + + gtk_window_iconify(GTK_WINDOW(mainbox.window)); + +} // END MainBoxUnfocus() + + + + + +gint MainBoxFile1Event(GtkWidget *widget, GdkEvent event, gpointer data) { + + int returnval; + + char templine[256]; + + struct IsoFile *tempfile; + + + + returnval = IsIsoFile(gtk_entry_get_text(GTK_ENTRY(mainbox.file1))); + + if(returnval == -1) { + + gtk_label_set_text(GTK_LABEL(mainbox.desc1), "File Type: ---"); + + return(TRUE); + + } // ENDIF- Not a name of any sort? + + + + if(returnval == -2) { + + gtk_label_set_text(GTK_LABEL(mainbox.desc1), "File Type: Not a file"); + + return(TRUE); + + } // ENDIF- Not a regular file? + + + + if(returnval == -3) { + + gtk_label_set_text(GTK_LABEL(mainbox.desc1), "File Type: Not a valid image file"); + + return(TRUE); + + } // ENDIF- Not an Image file? + + + + if(returnval == -4) { + + gtk_label_set_text(GTK_LABEL(mainbox.desc1), "File Type: Missing Table File (will rebuild)"); + + return(TRUE); + + } // ENDIF- Missing Compression seek table? + + + + tempfile = IsoFileOpenForRead(gtk_entry_get_text(GTK_ENTRY(mainbox.file1))); + + sprintf(templine, "File Type: %s%s%s", + + multinames[tempfile->multi], + + tempfile->imagename, + + compressdesc[tempfile->compress]); + + gtk_label_set_text(GTK_LABEL(mainbox.desc1), templine); + + tempfile = IsoFileClose(tempfile); + + return(TRUE); + +} // END MainBoxFileEvent() + + + + + +gint MainBoxFile2Event(GtkWidget *widget, GdkEvent event, gpointer data) { + + int returnval; + + char templine[256]; + + struct IsoFile *tempfile; + + + + returnval = IsIsoFile(gtk_entry_get_text(GTK_ENTRY(mainbox.file2))); + + if(returnval == -1) { + + gtk_label_set_text(GTK_LABEL(mainbox.desc2), "File Type: ---"); + + return(TRUE); + + } // ENDIF- Not a name of any sort? + + + + if(returnval == -2) { + + gtk_label_set_text(GTK_LABEL(mainbox.desc2), "File Type: Not a file"); + + return(TRUE); + + } // ENDIF- Not a regular file? + + + + if(returnval == -3) { + + gtk_label_set_text(GTK_LABEL(mainbox.desc2), "File Type: Not a valid image file"); + + return(TRUE); + + } // ENDIF- Not an Image file? + + + + if(returnval == -4) { + + gtk_label_set_text(GTK_LABEL(mainbox.desc2), "File Type: Missing Table File (will rebuild)"); + + return(TRUE); + + } // ENDIF- Missing Compression seek table? + + + + tempfile = IsoFileOpenForRead(gtk_entry_get_text(GTK_ENTRY(mainbox.file2))); + + sprintf(templine, "File Type: %s%s%s", + + multinames[tempfile->multi], + + tempfile->imagename, + + compressdesc[tempfile->compress]); + + gtk_label_set_text(GTK_LABEL(mainbox.desc2), templine); + + tempfile = IsoFileClose(tempfile); + + return(TRUE); + +} // END MainBoxFileEvent() + + + + + +void MainBoxRefocus() { + + GdkEvent event; + + + + MainBoxFile1Event(NULL, event, NULL); + + MainBoxFile2Event(NULL, event, NULL); + + + + gtk_widget_set_sensitive(mainbox.file1, TRUE); + + gtk_widget_set_sensitive(mainbox.file2, TRUE); + + gtk_widget_set_sensitive(mainbox.okbutton, TRUE); + + gtk_window_set_focus(GTK_WINDOW(mainbox.window), mainbox.file1); + + gtk_window_deiconify(GTK_WINDOW(mainbox.window)); + +} // END MainBoxRefocus() + + + + + +gint MainBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + mainbox.stop = 1; // Halt all long processess... + + + + MessageBoxDestroy(); + + ProgressBoxDestroy(); + + MainBoxDestroy(); + + + + gtk_main_quit(); + + return(TRUE); + +} // END MainBoxCancelEvent() + + + + + +gint MainBoxOKEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + const char *tempisoname1; + + const char *tempisoname2; + + struct IsoFile *tempiso1; + + struct IsoFile *tempiso2; + + int stop; + + off64_t endsector; + + off64_t sector; + + int retval; + + char tempblock1[2448]; + + char tempblock2[2448]; + + int i; + + + + MainBoxUnfocus(); + + + + tempisoname1 = gtk_entry_get_text(GTK_ENTRY(mainbox.file1)); + + tempisoname2 = gtk_entry_get_text(GTK_ENTRY(mainbox.file2)); + + tempiso1 = NULL; + + tempiso2 = NULL; + + + + tempiso1 = IsoFileOpenForRead(tempisoname1); + + if(tempiso1 == NULL) { + + MainBoxRefocus(); + + MessageBoxShow("First file is not a Valid Image File.", 0); + + tempisoname1 = NULL; + + tempisoname2 = NULL; + + return(TRUE); + + } // ENDIF- Not an ISO file? Message and Stop here. + + + + tempiso2 = IsoFileOpenForRead(tempisoname2); + + if(tempiso2 == NULL) { + + MainBoxRefocus(); + + MessageBoxShow("Second file is not a Valid Image File.", 0); + + tempiso1 = IsoFileClose(tempiso1); + + tempisoname1 = NULL; + + tempisoname2 = NULL; + + return(TRUE); + + } // ENDIF- Not an ISO file? Message and Stop here. + + + + if(tempiso1->blocksize != tempiso2->blocksize) { + + MainBoxRefocus(); + + MessageBoxShow("Block sizes in Image files do not match.", 0); + + tempiso1 = IsoFileClose(tempiso1); + + tempiso2 = IsoFileClose(tempiso2); + + tempisoname1 = NULL; + + tempisoname2 = NULL; + + return(TRUE); + + } // ENDIF- Not an ISO file? Message and Stop here. + + + + if(tempiso1->multi == 1) { + + i = 0; + + while((i < 10) && + + (IsoFileSeek(tempiso1, tempiso1->multisectorend[i] + 1) == 0)) i++; + + endsector = tempiso1->multisectorend[tempiso1->multiend]; + + } else { + + endsector = tempiso1->filesectorsize; + + } // ENDIF- Get ending sector from multifile? (Or single file?) + + IsoFileSeek(tempiso1, 0); + + + + if(tempiso2->multi == 1) { + + i = 0; + + while((i < 10) && + + (IsoFileSeek(tempiso2, tempiso2->multisectorend[i] + 1) == 0)) i++; + + sector = tempiso2->multisectorend[tempiso2->multiend]; + + } else { + + sector = tempiso2->filesectorsize; + + } // ENDIF- Get ending sector from multifile? (Or single file?) + + IsoFileSeek(tempiso2, 0); + + if(sector != endsector) { + + MainBoxRefocus(); + + MessageBoxShow("Number of blocks in Image files do not match.", 0); + + tempiso1 = IsoFileClose(tempiso1); + + tempiso2 = IsoFileClose(tempiso2); + + tempisoname1 = NULL; + + tempisoname2 = NULL; + + return(TRUE); + + } // ENDIF- Number of blocks don't match? Say so. + + + + sprintf(tempblock1, "%s == %s ?", tempisoname1, tempisoname2); + + ProgressBoxStart(tempblock1, endsector); + + + + stop = 0; + + mainbox.stop = 0; + + progressbox.stop = 0; + + while((stop == 0) && (tempiso1->sectorpos < endsector)) { + + retval = IsoFileRead(tempiso1, tempblock1); + + if(retval < 0) { + + MainBoxRefocus(); + + MessageBoxShow("Trouble reading first file.", 0); + + stop = 1; + + } else { + + retval = IsoFileRead(tempiso2, tempblock2); + + if(retval < 0) { + + MainBoxRefocus(); + + MessageBoxShow("Trouble reading second file.", 0); + + stop = 1; + + } else { + + i = 0; + + while((i < tempiso1->blocksize) && (tempblock1[i] == tempblock2[i])) i++; + + if(i < tempiso1->blocksize) { + + MainBoxRefocus(); + + MessageBoxShow("Trouble reading second file.", 0); + + stop = 1; + + } // ENDIF- Sectors don't match? Say so. + + } // ENDIF- Trouble reading second file? + + } // ENDIF- Trouble reading first file? + + + + ProgressBoxTick(tempiso1->sectorpos); + + while(gtk_events_pending()) gtk_main_iteration(); + + + + if(mainbox.stop != 0) stop = 2; + + if(progressbox.stop != 0) stop = 2; + + } // ENDWHILE- Comparing two files... sector by sector + + + + if(stop == 0) { + + MainBoxRefocus(); + + MessageBoxShow("Images Match.", 0); + + } // ENDIF- Everything checked out? Say so. + + tempiso1 = IsoFileClose(tempiso1); + + tempiso2 = IsoFileClose(tempiso2); + + tempisoname1 = NULL; + + tempisoname2 = NULL; + + return(TRUE); + +} // END MainBoxOKEvent() + + + + + +void MainBoxDisplay() { + + GtkWidget *item; + + GtkWidget *hbox1; + + GtkWidget *vbox1; + + + + mainbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + gtk_container_set_border_width(GTK_CONTAINER(mainbox.window), 5); + + gtk_window_set_title(GTK_WINDOW(mainbox.window), "CDVDisoEFP Comparsion"); + + gtk_window_set_position(GTK_WINDOW(mainbox.window), GTK_WIN_POS_CENTER); + + // gtk_window_set_resizable(GTK_WINDOW(mainbox.window), FALSE); + + + + g_signal_connect(G_OBJECT(mainbox.window), "delete_event", + + G_CALLBACK(MainBoxCancelEvent), NULL); + + + + vbox1 = gtk_vbox_new(FALSE, 5); + + gtk_container_add(GTK_CONTAINER(mainbox.window), vbox1); + + gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); + + gtk_widget_show(vbox1); + + + + hbox1 = gtk_hbox_new(FALSE, 10); + + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + + gtk_widget_show(hbox1); + + + + item = gtk_label_new("First Iso File:"); + + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + mainbox.file1 = gtk_entry_new(); + + gtk_box_pack_start(GTK_BOX(hbox1), mainbox.file1, TRUE, TRUE, 0); + + gtk_widget_show(mainbox.file1); + + g_signal_connect(G_OBJECT(mainbox.file1), "changed", + + G_CALLBACK(MainBoxFile1Event), NULL); + + hbox1 = NULL; + + + + mainbox.desc1 = gtk_label_new("File Type: ---"); + + gtk_box_pack_start(GTK_BOX(vbox1), mainbox.desc1, FALSE, FALSE, 0); + + gtk_widget_show(mainbox.desc1); + + + + item = gtk_hseparator_new(); + + gtk_box_pack_start(GTK_BOX(vbox1), item, TRUE, TRUE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + hbox1 = gtk_hbox_new(FALSE, 10); + + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + + gtk_widget_show(hbox1); + + + + item = gtk_label_new("Second Iso File:"); + + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + mainbox.file2 = gtk_entry_new(); + + gtk_box_pack_start(GTK_BOX(hbox1), mainbox.file2, TRUE, TRUE, 0); + + gtk_widget_show(mainbox.file2); + + g_signal_connect(G_OBJECT(mainbox.file2), "changed", + + G_CALLBACK(MainBoxFile2Event), NULL); + + hbox1 = NULL; + + + + mainbox.desc2 = gtk_label_new("File Type: ---"); + + gtk_box_pack_start(GTK_BOX(vbox1), mainbox.desc2, FALSE, FALSE, 0); + + gtk_widget_show(mainbox.desc2); + + + + hbox1 = gtk_hbutton_box_new(); + + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + + gtk_widget_show(hbox1); + + + + mainbox.okbutton = gtk_button_new_with_label("Compare"); + + gtk_box_pack_start(GTK_BOX(hbox1), mainbox.okbutton, TRUE, TRUE, 0); + + gtk_widget_show(mainbox.okbutton); + + g_signal_connect(G_OBJECT(mainbox.okbutton), "clicked", + + G_CALLBACK(MainBoxOKEvent), NULL); + + + + item = gtk_button_new_with_label("Exit"); + + gtk_box_pack_start(GTK_BOX(hbox1), item, TRUE, TRUE, 0); + + gtk_widget_show(item); + + g_signal_connect(G_OBJECT(item), "clicked", + + G_CALLBACK(MainBoxCancelEvent), NULL); + + item = NULL; + + hbox1 = NULL; + + vbox1 = NULL; + + + + // We held off setting the name until now... so description would show. + + gtk_entry_set_text(GTK_ENTRY(mainbox.file1), conf.isoname); + + gtk_entry_set_text(GTK_ENTRY(mainbox.file2), conf.isoname); + +} // END MainBoxDisplay() + + + + + +int main(int argc, char *argv[]) { + + gtk_init(NULL, NULL); + + + + OpenLog(); + + InitConf(); + + LoadConf(); + + MainBoxDisplay(); + + ProgressBoxDisplay(); + + MessageBoxDisplay(); + + + + gtk_widget_show_all(mainbox.window); + + gtk_main(); + + CloseLog(); + + return(0); + +} // END main() + diff --git a/plugins/CDVDisoEFP/src/Linux/comparisondummy.c b/plugins/CDVDisoEFP/src/Linux/comparisondummy.c index ebedf17b26..43dd5519a0 100644 --- a/plugins/CDVDisoEFP/src/Linux/comparisondummy.c +++ b/plugins/CDVDisoEFP/src/Linux/comparisondummy.c @@ -1,24 +1,48 @@ -/* comparisondummy.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -void ConversionBoxRefocus() { return; } - -void DeviceBoxRefocus() { return; } +/* comparisondummy.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +void ConversionBoxRefocus() { return; } + + + +void DeviceBoxRefocus() { return; } + diff --git a/plugins/CDVDisoEFP/src/Linux/conf.c b/plugins/CDVDisoEFP/src/Linux/conf.c index cd75fe4812..70d6853727 100644 --- a/plugins/CDVDisoEFP/src/Linux/conf.c +++ b/plugins/CDVDisoEFP/src/Linux/conf.c @@ -1,204 +1,408 @@ -/* conf.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - -#include // errno -#include // NULL -#include // sprintf() -#include // getenv() -#include // strerror() -#include // mkdir(), stat() -#include // mkdir(), stat() -#include // stat() - -// #define CDVDdefs -// #include "../PS2Edefs.h" -#include "logfile.h" -#include "../ini.h" -#include "conf.h" - - -const char *cfgname[] = { \ - "./cfg/cfgCDVDisoEFP", \ - "../cfg/cfgCDVDisoEFP", \ - "./cfgCDVDisoEFP", \ - "../cfgCDVDisoEFP", \ - "./plugins/cfgCDVDisoEFP", \ - "../plugins/cfgCDVDisoEFP", \ - NULL }; - -const char *confnames[] = { "IsoFile", "CdDev", NULL }; -const u8 defaultdevice[] = DEFAULT_DEVICE; -const char defaulthome[] = "../inis"; -const char defaultdirectory[] = ".PS2E"; -const char defaultfile[] = "CDVDisoEFP.ini"; - -char confdirname[256]; -char conffilename[256]; - -CDVDconf conf; - - -void ExecCfg(char *arg) { - int nameptr; - struct stat filestat; - char templine[256]; - -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVDiso interface: ExecCfg(%s)", arg); -#endif /* VERBOSE FUNCTION_CONF */ - errno = 0; - nameptr = 0; - while((cfgname[nameptr] != NULL) && - (stat(cfgname[nameptr], &filestat) == -1)) nameptr++; - errno = 0; - - if(cfgname[nameptr] == NULL) { -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVDiso interface: Couldn't find configuration program!"); -#endif /* VERBOSE_FUNCTION_CONF */ - return; - } // ENDIF- Did not find the executable? - - sprintf(templine, "%s %s", cfgname[nameptr], arg); - system(templine); -} // END ExecCfg() - - -void InitConf() { - int i; - int pos; - char *envptr; - -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVD config: InitConf()"); -#endif /* VERBOSE_FUNCTION_CONF */ - - conf.isoname[0] = 0; // Empty the iso name - - i = 0; - while((i < 255) && defaultdevice[i] != 0) { - conf.devicename[i] = defaultdevice[i]; - i++; - } // ENDWHILE- copying the default CD/DVD name in - conf.devicename[i] = 0; // 0-terminate the device name - - // Locating directory and file positions - pos = 0; - envptr = getenv("HOME"); - if(envptr == NULL) { - // = - i = 0; - while((pos < 253) && (defaulthome[i] != 0)) { - confdirname[pos] = defaulthome[i]; - conffilename[pos] = defaulthome[i]; - pos++; - i++; - } // NEXT- putting a default place to store configuration data - - } else { - // = / - i = 0; - while((pos < 253) && (*(envptr + i) != 0)) { - confdirname[pos] = *(envptr + i); - conffilename[pos] = *(envptr + i); - pos++; - i++; - } // ENDWHILE- copying home directory info in - - if(confdirname[pos-1] != '/') { - confdirname[pos] = '/'; - conffilename[pos] = '/'; - pos++; - } // ENDIF- No directory separator here? Add one. - - i = 0; - while((pos < 253) && (defaultdirectory[i] != 0)) { - confdirname[pos] = defaultdirectory[i]; - conffilename[pos] = defaultdirectory[i]; - pos++; - i++; - } // NEXT- putting a default place to store configuration data - } // ENDIF- No Home directory? - - confdirname[pos] = 0; // Directory reference finished - - // += / - if(conffilename[pos-1] != '/') { - conffilename[pos] = '/'; - pos++; - } // ENDIF- No directory separator here? Add one. - - i = 0; - while((pos < 253) && (defaultfile[i] != 0)) { - conffilename[pos] = defaultfile[i]; - pos++; - i++; - } // NEXT- putting a default place to store configuration data - - conffilename[pos] = 0; // File reference finished - -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVD config: Directory: %s\n", confdirname); - PrintLog("CDVD config: File: %s\n", conffilename); -#endif /* VERBOSE_FUNCTION_CONF */ -} // END InitConf() - - -void LoadConf() { - int retval; - -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVD config: LoadConf()\n"); -#endif /* VERBOSE_FUNCTION_CONF */ - - retval = INILoadString(conffilename, "Settings", "IsoFile", conf.isoname); - if(retval < 0) { - sprintf(conf.isoname, "[Put an Image Name here]"); - } // ENDIF- Couldn't find keyword? Fill in a default - - retval = INILoadString(conffilename, "Settings", "Device", conf.devicename); - if(retval < 0) { - sprintf(conf.devicename, "/dev/dvd"); - } // ENDIF- Couldn't find keyword? Fill in a default - - retval = INILoadUInt(conffilename, "Settings", "OpenOnStart", &conf.startconfigure); - if(retval < 0) { - conf.startconfigure = 0; // False - } // ENDIF- Couldn't find keyword? Fill in a default - - retval = INILoadUInt(conffilename, "Settings", "OpenOnRestart", &conf.restartconfigure); - if(retval < 0) { - conf.restartconfigure = 1; // True - } // ENDIF- Couldn't find keyword? Fill in a default -} // END LoadConf() - - -void SaveConf() { -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVD config: SaveConf()\n"); -#endif /* VERBOSE_FUNCTION_CONF */ - - mkdir(confdirname, 0755); - - INISaveString(conffilename, "Settings", "IsoFile", conf.isoname); - INISaveString(conffilename, "Settings", "Device", conf.devicename); - INISaveUInt(conffilename, "Settings", "OpenOnStart", conf.startconfigure); - INISaveUInt(conffilename, "Settings", "OpenOnRestart", conf.restartconfigure); -} // END SaveConf() +/* conf.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + +#include // errno + +#include // NULL + +#include // sprintf() + +#include // getenv() + +#include // strerror() + +#include // mkdir(), stat() + +#include // mkdir(), stat() + +#include // stat() + + + +// #define CDVDdefs + +// #include "../PS2Edefs.h" + +#include "logfile.h" + +#include "../ini.h" + +#include "conf.h" + + + + + +const char *cfgname[] = { \ + + "./cfg/cfgCDVDisoEFP", \ + + "../cfg/cfgCDVDisoEFP", \ + + "./cfgCDVDisoEFP", \ + + "../cfgCDVDisoEFP", \ + + "./plugins/cfgCDVDisoEFP", \ + + "../plugins/cfgCDVDisoEFP", \ + + NULL }; + + + +const char *confnames[] = { "IsoFile", "CdDev", NULL }; + +const u8 defaultdevice[] = DEFAULT_DEVICE; + +const char defaulthome[] = "../inis"; + +const char defaultdirectory[] = ".PS2E"; + +const char defaultfile[] = "CDVDisoEFP.ini"; + + + +char confdirname[256]; + +char conffilename[256]; + + + +CDVDconf conf; + + + + + +void ExecCfg(char *arg) { + + int nameptr; + + struct stat filestat; + + char templine[256]; + + + +#ifdef VERBOSE_FUNCTION_CONF + + PrintLog("CDVDiso interface: ExecCfg(%s)", arg); + +#endif /* VERBOSE FUNCTION_CONF */ + + errno = 0; + + nameptr = 0; + + while((cfgname[nameptr] != NULL) && + + (stat(cfgname[nameptr], &filestat) == -1)) nameptr++; + + errno = 0; + + + + if(cfgname[nameptr] == NULL) { + +#ifdef VERBOSE_FUNCTION_CONF + + PrintLog("CDVDiso interface: Couldn't find configuration program!"); + +#endif /* VERBOSE_FUNCTION_CONF */ + + return; + + } // ENDIF- Did not find the executable? + + + + sprintf(templine, "%s %s", cfgname[nameptr], arg); + + system(templine); + +} // END ExecCfg() + + + + + +void InitConf() { + + int i; + + int pos; + + char *envptr; + + + +#ifdef VERBOSE_FUNCTION_CONF + + PrintLog("CDVD config: InitConf()"); + +#endif /* VERBOSE_FUNCTION_CONF */ + + + + conf.isoname[0] = 0; // Empty the iso name + + + + i = 0; + + while((i < 255) && defaultdevice[i] != 0) { + + conf.devicename[i] = defaultdevice[i]; + + i++; + + } // ENDWHILE- copying the default CD/DVD name in + + conf.devicename[i] = 0; // 0-terminate the device name + + + + // Locating directory and file positions + + pos = 0; + + envptr = getenv("HOME"); + + if(envptr == NULL) { + + // = + + i = 0; + + while((pos < 253) && (defaulthome[i] != 0)) { + + confdirname[pos] = defaulthome[i]; + + conffilename[pos] = defaulthome[i]; + + pos++; + + i++; + + } // NEXT- putting a default place to store configuration data + + + + } else { + + // = / + + i = 0; + + while((pos < 253) && (*(envptr + i) != 0)) { + + confdirname[pos] = *(envptr + i); + + conffilename[pos] = *(envptr + i); + + pos++; + + i++; + + } // ENDWHILE- copying home directory info in + + + + if(confdirname[pos-1] != '/') { + + confdirname[pos] = '/'; + + conffilename[pos] = '/'; + + pos++; + + } // ENDIF- No directory separator here? Add one. + + + + i = 0; + + while((pos < 253) && (defaultdirectory[i] != 0)) { + + confdirname[pos] = defaultdirectory[i]; + + conffilename[pos] = defaultdirectory[i]; + + pos++; + + i++; + + } // NEXT- putting a default place to store configuration data + + } // ENDIF- No Home directory? + + + + confdirname[pos] = 0; // Directory reference finished + + + + // += / + + if(conffilename[pos-1] != '/') { + + conffilename[pos] = '/'; + + pos++; + + } // ENDIF- No directory separator here? Add one. + + + + i = 0; + + while((pos < 253) && (defaultfile[i] != 0)) { + + conffilename[pos] = defaultfile[i]; + + pos++; + + i++; + + } // NEXT- putting a default place to store configuration data + + + + conffilename[pos] = 0; // File reference finished + + + +#ifdef VERBOSE_FUNCTION_CONF + + PrintLog("CDVD config: Directory: %s\n", confdirname); + + PrintLog("CDVD config: File: %s\n", conffilename); + +#endif /* VERBOSE_FUNCTION_CONF */ + +} // END InitConf() + + + + + +void LoadConf() { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_CONF + + PrintLog("CDVD config: LoadConf()\n"); + +#endif /* VERBOSE_FUNCTION_CONF */ + + + + retval = INILoadString(conffilename, "Settings", "IsoFile", conf.isoname); + + if(retval < 0) { + + sprintf(conf.isoname, "[Put an Image Name here]"); + + } // ENDIF- Couldn't find keyword? Fill in a default + + + + retval = INILoadString(conffilename, "Settings", "Device", conf.devicename); + + if(retval < 0) { + + sprintf(conf.devicename, "/dev/dvd"); + + } // ENDIF- Couldn't find keyword? Fill in a default + + + + retval = INILoadUInt(conffilename, "Settings", "OpenOnStart", &conf.startconfigure); + + if(retval < 0) { + + conf.startconfigure = 0; // False + + } // ENDIF- Couldn't find keyword? Fill in a default + + + + retval = INILoadUInt(conffilename, "Settings", "OpenOnRestart", &conf.restartconfigure); + + if(retval < 0) { + + conf.restartconfigure = 1; // True + + } // ENDIF- Couldn't find keyword? Fill in a default + +} // END LoadConf() + + + + + +void SaveConf() { + +#ifdef VERBOSE_FUNCTION_CONF + + PrintLog("CDVD config: SaveConf()\n"); + +#endif /* VERBOSE_FUNCTION_CONF */ + + + + mkdir(confdirname, 0755); + + + + INISaveString(conffilename, "Settings", "IsoFile", conf.isoname); + + INISaveString(conffilename, "Settings", "Device", conf.devicename); + + INISaveUInt(conffilename, "Settings", "OpenOnStart", conf.startconfigure); + + INISaveUInt(conffilename, "Settings", "OpenOnRestart", conf.restartconfigure); + +} // END SaveConf() + diff --git a/plugins/CDVDisoEFP/src/Linux/conversionbox.c b/plugins/CDVDisoEFP/src/Linux/conversionbox.c index 7bd5501c64..f54ae8084c 100644 --- a/plugins/CDVDisoEFP/src/Linux/conversionbox.c +++ b/plugins/CDVDisoEFP/src/Linux/conversionbox.c @@ -1,388 +1,776 @@ -/* conversionbox.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // NULL -#include // sprintf() -#include // strcpy() -#include // off64_t - -#include // gtk_button_new_with_label() -#include // gtk_combo_box_new() -#include // gtk_check_button_new() -#include // gtk_container_add() -#include // gtk_entry_new() -#include // gtk_file_selection_set_filename() -#include // gtk_hbutton_box_new() -#include // gtk_hbox_new() -#include // gtk_hseparator_new() -#include // gtk_label_new() -#include // gtk_main_iteration() -#include // gtk_toggle_button_get_active() -#include // gtk_vbox_new() -#include // gtk_window_new() - -#include "isofile.h" -#include "isocompress.h" // compressdesc[] -#include "imagetype.h" // imagedata[] -#include "multifile.h" // multinames[] -#include "toc.h" -#include "progressbox.h" -#include "messagebox.h" -#include "selectionbox.h" -#include "mainbox.h" -#include "conversionbox.h" - - -struct ConversionBoxData conversionbox; - - -void ConversionBoxDestroy() { - if(conversionbox.window != NULL) { - gtk_widget_destroy(conversionbox.window); - conversionbox.window = NULL; - conversionbox.file = NULL; - conversionbox.selectbutton = NULL; - conversionbox.filedesc = NULL; - conversionbox.compress = NULL; - conversionbox.multi = NULL; - conversionbox.okbutton = NULL; - conversionbox.cancelbutton = NULL; - } // ENDIF- Do we have a Main Window still? -} // END ConversionBoxDestroy() - - -void ConversionBoxUnfocus() { - gtk_widget_set_sensitive(conversionbox.file, FALSE); - gtk_widget_set_sensitive(conversionbox.selectbutton, FALSE); - gtk_widget_set_sensitive(conversionbox.compress, FALSE); - gtk_widget_set_sensitive(conversionbox.multi, FALSE); - gtk_widget_set_sensitive(conversionbox.okbutton, FALSE); - gtk_widget_set_sensitive(conversionbox.cancelbutton, FALSE); - // gtk_window_iconify(GTK_WINDOW(conversionbox.window)); - gtk_widget_hide(conversionbox.window); -} // END ConversionBoxUnfocus() - - -gint ConversionBoxFileEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - int returnval; - char templine[256]; - struct IsoFile *tempfile; - - returnval = IsIsoFile(gtk_entry_get_text(GTK_ENTRY(conversionbox.file))); - if(returnval == -1) { - gtk_label_set_text(GTK_LABEL(conversionbox.filedesc), "File Type: ---"); - return(TRUE); - } // ENDIF- Not a name of any sort? - - if(returnval == -2) { - gtk_label_set_text(GTK_LABEL(conversionbox.filedesc), - "File Type: Not a file"); - return(TRUE); - } // ENDIF- Not a regular file? - - if(returnval == -3) { - gtk_label_set_text(GTK_LABEL(conversionbox.filedesc), - "File Type: Not a valid image file"); - return(TRUE); - } // ENDIF- Not a regular file? - - if(returnval == -4) { - gtk_label_set_text(GTK_LABEL(conversionbox.filedesc), - "File Type: Missing Table File (will rebuild)"); - return(TRUE); - } // ENDIF- Not a regular file? - - tempfile = IsoFileOpenForRead(gtk_entry_get_text(GTK_ENTRY(conversionbox.file))); - sprintf(templine, "File Type: %s%s%s", - multinames[tempfile->multi], - tempfile->imagename, - compressdesc[tempfile->compress]); - gtk_label_set_text(GTK_LABEL(conversionbox.filedesc), templine); - tempfile = IsoFileClose(tempfile); - return(TRUE); -} // END ConversionBoxFileEvent() - - -void ConversionBoxRefocus() { - GdkEvent event; - - ConversionBoxFileEvent(NULL, event, NULL); - - gtk_widget_set_sensitive(conversionbox.file, TRUE); - gtk_widget_set_sensitive(conversionbox.selectbutton, TRUE); - gtk_widget_set_sensitive(conversionbox.compress, TRUE); - gtk_widget_set_sensitive(conversionbox.multi, TRUE); - gtk_widget_set_sensitive(conversionbox.okbutton, TRUE); - gtk_widget_set_sensitive(conversionbox.cancelbutton, TRUE); - gtk_window_set_focus(GTK_WINDOW(conversionbox.window), conversionbox.file); - gtk_widget_show_all(conversionbox.window); - gtk_window_deiconify(GTK_WINDOW(conversionbox.window)); -} // END ConversionBoxRefocus() - - -gint ConversionBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - gtk_widget_hide(conversionbox.window); - MainBoxRefocus(); - return(TRUE); -} // END ConversionBoxCancelEvent() - - -gint ConversionBoxOKEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - char templine[256]; - char tempblock[2352]; - const char *filename; - int compressmethod; - int multi; - struct IsoFile *fromfile; - struct IsoFile *tofile; - int i; - off64_t endsector; - int stop; - int retval; - - ConversionBoxUnfocus(); - - filename = gtk_entry_get_text(GTK_ENTRY(conversionbox.file)); - if(IsIsoFile(filename) < 0) { - filename = NULL; - MessageBoxShow("Not a valid file", 3); - return(TRUE); - } // ENDIF- Not an Iso File? Stop early. - - compressmethod = gtk_combo_box_get_active(GTK_COMBO_BOX(conversionbox.compress)); - if(compressmethod > 0) compressmethod += 2; - multi = 0; - if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(conversionbox.multi)) == TRUE) - multi = 1; - - fromfile = NULL; - fromfile = IsoFileOpenForRead(filename); - if(fromfile == NULL) { - filename = NULL; - MessageBoxShow("Cannot opening the source file", 3); - return(TRUE); - } // ENDIF- Not an Iso File? Stop early. - - if((compressmethod == fromfile->compress) && - (multi == fromfile->multi)) { - fromfile = IsoFileClose(fromfile); - filename = NULL; - MessageBoxShow("Compress/Multifile methods match - no need to convert", 3); - return(TRUE); - } // ENDIF- Not an Iso File? Stop early. - - tofile = IsoFileOpenForWrite(filename, - GetImageTypeConvertTo(fromfile->imagetype), - multi, - compressmethod); - if(tofile == NULL) { - fromfile = IsoFileClose(fromfile); - filename = NULL; - MessageBoxShow("Cannot create the new file", 3); - return(TRUE); - } // ENDIF- Not an Iso File? Stop early. - - if(fromfile->multi == 1) { - i = 0; - while((i < 10) && - (IsoFileSeek(fromfile, fromfile->multisectorend[i] + 1) == 0)) i++; - endsector = fromfile->multisectorend[fromfile->multiend]; - } else { - endsector = fromfile->filesectorsize; - } // ENDIF- Get ending sector from multifile? (Or single file?) - IsoFileSeek(fromfile, 0); - - // Open Progress Bar - sprintf(templine, "%s: %s%s -> %s%s", - filename, - multinames[fromfile->multi], - compressdesc[fromfile->compress], - multinames[tofile->multi], - compressdesc[tofile->compress]); - ProgressBoxStart(templine, endsector); - - tofile->cdvdtype = fromfile->cdvdtype; - for(i = 0; i < 2048; i++) tofile->toc[i] = fromfile->toc[i]; - - stop = 0; - mainbox.stop = 0; - progressbox.stop = 0; - while((stop == 0) && (tofile->sectorpos < endsector)) { - retval = IsoFileRead(fromfile, tempblock); - if(retval < 0) { - MessageBoxShow("Trouble reading source file", 3); - stop = 1; - } else { - retval = IsoFileWrite(tofile, tempblock); - if(retval < 0) { - MessageBoxShow("Trouble writing new file", 3); - stop = 1; - } // ENDIF- Trouble writing out the next block? - } // ENDIF- Trouble reading in the next block? - - ProgressBoxTick(tofile->sectorpos); - while(gtk_events_pending()) gtk_main_iteration(); - - if(mainbox.stop != 0) stop = 2; - if(progressbox.stop != 0) stop = 2; - } // ENDWHILE- Not stopped for some reason... - - ProgressBoxStop(); - - if(stop == 0) { - if(tofile->multi == 1) tofile->name[tofile->multipos] = '0'; // First file - strcpy(templine, tofile->name); - - // fromfile = IsoFileCloseAndDelete(fromfile); - fromfile = IsoFileClose(fromfile); - - IsoSaveTOC(tofile); - tofile = IsoFileClose(tofile); - gtk_entry_set_text(GTK_ENTRY(mainbox.file), templine); - - } else { - fromfile = IsoFileClose(fromfile); - tofile = IsoFileCloseAndDelete(tofile); - } // ENDIF- Did we succeed in the transfer? - - if(stop != 1) ConversionBoxRefocus(); - if(stop == 0) ConversionBoxCancelEvent(widget, event, data); - return(TRUE); -} // END ConversionBoxOKEvent() - - -gint ConversionBoxBrowseEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - ConversionBoxUnfocus(); - - // Transfer file name to file selection - gtk_file_selection_set_filename(GTK_FILE_SELECTION(selectionbox.window), - gtk_entry_get_text(GTK_ENTRY(conversionbox.file))); - selectionbox.wherefrom = 3; // From the Conversion Window - SelectionBoxRefocus(); - return(TRUE); -} // END ConversionBoxBrowseEvent() - - -void ConversionBoxDisplay() { - GtkWidget *item; - GtkWidget *hbox1; - GtkWidget *vbox1; - int nameptr; - - conversionbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_container_set_border_width(GTK_CONTAINER(conversionbox.window), 5); - gtk_window_set_title(GTK_WINDOW(conversionbox.window), "CDVDisoEFP File Conversion"); - gtk_window_set_position(GTK_WINDOW(conversionbox.window), GTK_WIN_POS_CENTER); - - g_signal_connect(G_OBJECT(conversionbox.window), "delete_event", - G_CALLBACK(ConversionBoxCancelEvent), NULL); - - vbox1 = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(conversionbox.window), vbox1); - gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); - gtk_widget_show(vbox1); - - hbox1 = gtk_hbox_new(FALSE, 10); - gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); - gtk_widget_show(hbox1); - - item = gtk_label_new("Iso File:"); - gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); - gtk_widget_show(item); - item = NULL; - - conversionbox.file = gtk_entry_new(); - gtk_box_pack_start(GTK_BOX(hbox1), conversionbox.file, TRUE, TRUE, 0); - gtk_widget_show(conversionbox.file); - g_signal_connect(G_OBJECT(conversionbox.file), "changed", - G_CALLBACK(ConversionBoxFileEvent), NULL); - - conversionbox.selectbutton = gtk_button_new_with_label("Browse"); - gtk_box_pack_start(GTK_BOX(hbox1), conversionbox.selectbutton, FALSE, FALSE, 0); - gtk_widget_show(conversionbox.selectbutton); - g_signal_connect(G_OBJECT(conversionbox.selectbutton), "clicked", - G_CALLBACK(ConversionBoxBrowseEvent), NULL); - hbox1 = NULL; - - conversionbox.filedesc = gtk_label_new("File Type: ---"); - gtk_box_pack_start(GTK_BOX(vbox1), conversionbox.filedesc, FALSE, FALSE, 0); - gtk_widget_show(conversionbox.filedesc); - // ConversionBoxFileEvent(NULL, 0, NULL); // Work out compromise later... - - item = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(vbox1), item, TRUE, TRUE, 0); - gtk_widget_show(item); - item = NULL; - - hbox1 = gtk_hbox_new(FALSE, 10); - gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); - gtk_widget_show(hbox1); - - item = gtk_label_new("Change Compression To:"); - gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); - gtk_widget_show(item); - item = NULL; - - conversionbox.compress = gtk_combo_box_new_text(); - gtk_box_pack_start(GTK_BOX(hbox1), conversionbox.compress, FALSE, FALSE, 0); - nameptr = 0; - while(compressnames[nameptr] != NULL) { - gtk_combo_box_append_text(GTK_COMBO_BOX(conversionbox.compress), - compressnames[nameptr]); - nameptr++; - } // ENDWHILE- loading compression types into combo box - gtk_combo_box_set_active(GTK_COMBO_BOX(conversionbox.compress), 0); // Temp Line - gtk_widget_show(conversionbox.compress); - hbox1 = NULL; - - hbox1 = gtk_hbox_new(FALSE, 10); - gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); - gtk_widget_show(hbox1); - - item = gtk_label_new("Multiple Files (all under 2 GB):"); - gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); - gtk_widget_show(item); - item = NULL; - - conversionbox.multi = gtk_check_button_new(); - gtk_box_pack_start(GTK_BOX(hbox1), conversionbox.multi, FALSE, FALSE, 0); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(conversionbox.multi), FALSE); - gtk_widget_show(conversionbox.multi); - hbox1 = NULL; - - hbox1 = gtk_hbutton_box_new(); - gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); - gtk_widget_show(hbox1); - - conversionbox.okbutton = gtk_button_new_with_label("Change File"); - gtk_box_pack_start(GTK_BOX(hbox1), conversionbox.okbutton, TRUE, TRUE, 0); - gtk_widget_show(conversionbox.okbutton); - g_signal_connect(G_OBJECT(conversionbox.okbutton), "clicked", - G_CALLBACK(ConversionBoxOKEvent), NULL); - - conversionbox.cancelbutton = gtk_button_new_with_label("Cancel"); - gtk_box_pack_start(GTK_BOX(hbox1), conversionbox.cancelbutton, TRUE, TRUE, 0); - gtk_widget_show(conversionbox.cancelbutton); - g_signal_connect(G_OBJECT(conversionbox.cancelbutton), "clicked", - G_CALLBACK(ConversionBoxCancelEvent), NULL); - hbox1 = NULL; - vbox1 = NULL; -} // END ConversionBoxDisplay() +/* conversionbox.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // sprintf() + +#include // strcpy() + +#include // off64_t + + + +#include // gtk_button_new_with_label() + +#include // gtk_combo_box_new() + +#include // gtk_check_button_new() + +#include // gtk_container_add() + +#include // gtk_entry_new() + +#include // gtk_file_selection_set_filename() + +#include // gtk_hbutton_box_new() + +#include // gtk_hbox_new() + +#include // gtk_hseparator_new() + +#include // gtk_label_new() + +#include // gtk_main_iteration() + +#include // gtk_toggle_button_get_active() + +#include // gtk_vbox_new() + +#include // gtk_window_new() + + + +#include "isofile.h" + +#include "isocompress.h" // compressdesc[] + +#include "imagetype.h" // imagedata[] + +#include "multifile.h" // multinames[] + +#include "toc.h" + +#include "progressbox.h" + +#include "messagebox.h" + +#include "selectionbox.h" + +#include "mainbox.h" + +#include "conversionbox.h" + + + + + +struct ConversionBoxData conversionbox; + + + + + +void ConversionBoxDestroy() { + + if(conversionbox.window != NULL) { + + gtk_widget_destroy(conversionbox.window); + + conversionbox.window = NULL; + + conversionbox.file = NULL; + + conversionbox.selectbutton = NULL; + + conversionbox.filedesc = NULL; + + conversionbox.compress = NULL; + + conversionbox.multi = NULL; + + conversionbox.okbutton = NULL; + + conversionbox.cancelbutton = NULL; + + } // ENDIF- Do we have a Main Window still? + +} // END ConversionBoxDestroy() + + + + + +void ConversionBoxUnfocus() { + + gtk_widget_set_sensitive(conversionbox.file, FALSE); + + gtk_widget_set_sensitive(conversionbox.selectbutton, FALSE); + + gtk_widget_set_sensitive(conversionbox.compress, FALSE); + + gtk_widget_set_sensitive(conversionbox.multi, FALSE); + + gtk_widget_set_sensitive(conversionbox.okbutton, FALSE); + + gtk_widget_set_sensitive(conversionbox.cancelbutton, FALSE); + + // gtk_window_iconify(GTK_WINDOW(conversionbox.window)); + + gtk_widget_hide(conversionbox.window); + +} // END ConversionBoxUnfocus() + + + + + +gint ConversionBoxFileEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + int returnval; + + char templine[256]; + + struct IsoFile *tempfile; + + + + returnval = IsIsoFile(gtk_entry_get_text(GTK_ENTRY(conversionbox.file))); + + if(returnval == -1) { + + gtk_label_set_text(GTK_LABEL(conversionbox.filedesc), "File Type: ---"); + + return(TRUE); + + } // ENDIF- Not a name of any sort? + + + + if(returnval == -2) { + + gtk_label_set_text(GTK_LABEL(conversionbox.filedesc), + + "File Type: Not a file"); + + return(TRUE); + + } // ENDIF- Not a regular file? + + + + if(returnval == -3) { + + gtk_label_set_text(GTK_LABEL(conversionbox.filedesc), + + "File Type: Not a valid image file"); + + return(TRUE); + + } // ENDIF- Not a regular file? + + + + if(returnval == -4) { + + gtk_label_set_text(GTK_LABEL(conversionbox.filedesc), + + "File Type: Missing Table File (will rebuild)"); + + return(TRUE); + + } // ENDIF- Not a regular file? + + + + tempfile = IsoFileOpenForRead(gtk_entry_get_text(GTK_ENTRY(conversionbox.file))); + + sprintf(templine, "File Type: %s%s%s", + + multinames[tempfile->multi], + + tempfile->imagename, + + compressdesc[tempfile->compress]); + + gtk_label_set_text(GTK_LABEL(conversionbox.filedesc), templine); + + tempfile = IsoFileClose(tempfile); + + return(TRUE); + +} // END ConversionBoxFileEvent() + + + + + +void ConversionBoxRefocus() { + + GdkEvent event; + + + + ConversionBoxFileEvent(NULL, event, NULL); + + + + gtk_widget_set_sensitive(conversionbox.file, TRUE); + + gtk_widget_set_sensitive(conversionbox.selectbutton, TRUE); + + gtk_widget_set_sensitive(conversionbox.compress, TRUE); + + gtk_widget_set_sensitive(conversionbox.multi, TRUE); + + gtk_widget_set_sensitive(conversionbox.okbutton, TRUE); + + gtk_widget_set_sensitive(conversionbox.cancelbutton, TRUE); + + gtk_window_set_focus(GTK_WINDOW(conversionbox.window), conversionbox.file); + + gtk_widget_show_all(conversionbox.window); + + gtk_window_deiconify(GTK_WINDOW(conversionbox.window)); + +} // END ConversionBoxRefocus() + + + + + +gint ConversionBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + gtk_widget_hide(conversionbox.window); + + MainBoxRefocus(); + + return(TRUE); + +} // END ConversionBoxCancelEvent() + + + + + +gint ConversionBoxOKEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + char templine[256]; + + char tempblock[2352]; + + const char *filename; + + int compressmethod; + + int multi; + + struct IsoFile *fromfile; + + struct IsoFile *tofile; + + int i; + + off64_t endsector; + + int stop; + + int retval; + + + + ConversionBoxUnfocus(); + + + + filename = gtk_entry_get_text(GTK_ENTRY(conversionbox.file)); + + if(IsIsoFile(filename) < 0) { + + filename = NULL; + + MessageBoxShow("Not a valid file", 3); + + return(TRUE); + + } // ENDIF- Not an Iso File? Stop early. + + + + compressmethod = gtk_combo_box_get_active(GTK_COMBO_BOX(conversionbox.compress)); + + if(compressmethod > 0) compressmethod += 2; + + multi = 0; + + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(conversionbox.multi)) == TRUE) + + multi = 1; + + + + fromfile = NULL; + + fromfile = IsoFileOpenForRead(filename); + + if(fromfile == NULL) { + + filename = NULL; + + MessageBoxShow("Cannot opening the source file", 3); + + return(TRUE); + + } // ENDIF- Not an Iso File? Stop early. + + + + if((compressmethod == fromfile->compress) && + + (multi == fromfile->multi)) { + + fromfile = IsoFileClose(fromfile); + + filename = NULL; + + MessageBoxShow("Compress/Multifile methods match - no need to convert", 3); + + return(TRUE); + + } // ENDIF- Not an Iso File? Stop early. + + + + tofile = IsoFileOpenForWrite(filename, + + GetImageTypeConvertTo(fromfile->imagetype), + + multi, + + compressmethod); + + if(tofile == NULL) { + + fromfile = IsoFileClose(fromfile); + + filename = NULL; + + MessageBoxShow("Cannot create the new file", 3); + + return(TRUE); + + } // ENDIF- Not an Iso File? Stop early. + + + + if(fromfile->multi == 1) { + + i = 0; + + while((i < 10) && + + (IsoFileSeek(fromfile, fromfile->multisectorend[i] + 1) == 0)) i++; + + endsector = fromfile->multisectorend[fromfile->multiend]; + + } else { + + endsector = fromfile->filesectorsize; + + } // ENDIF- Get ending sector from multifile? (Or single file?) + + IsoFileSeek(fromfile, 0); + + + + // Open Progress Bar + + sprintf(templine, "%s: %s%s -> %s%s", + + filename, + + multinames[fromfile->multi], + + compressdesc[fromfile->compress], + + multinames[tofile->multi], + + compressdesc[tofile->compress]); + + ProgressBoxStart(templine, endsector); + + + + tofile->cdvdtype = fromfile->cdvdtype; + + for(i = 0; i < 2048; i++) tofile->toc[i] = fromfile->toc[i]; + + + + stop = 0; + + mainbox.stop = 0; + + progressbox.stop = 0; + + while((stop == 0) && (tofile->sectorpos < endsector)) { + + retval = IsoFileRead(fromfile, tempblock); + + if(retval < 0) { + + MessageBoxShow("Trouble reading source file", 3); + + stop = 1; + + } else { + + retval = IsoFileWrite(tofile, tempblock); + + if(retval < 0) { + + MessageBoxShow("Trouble writing new file", 3); + + stop = 1; + + } // ENDIF- Trouble writing out the next block? + + } // ENDIF- Trouble reading in the next block? + + + + ProgressBoxTick(tofile->sectorpos); + + while(gtk_events_pending()) gtk_main_iteration(); + + + + if(mainbox.stop != 0) stop = 2; + + if(progressbox.stop != 0) stop = 2; + + } // ENDWHILE- Not stopped for some reason... + + + + ProgressBoxStop(); + + + + if(stop == 0) { + + if(tofile->multi == 1) tofile->name[tofile->multipos] = '0'; // First file + + strcpy(templine, tofile->name); + + + + // fromfile = IsoFileCloseAndDelete(fromfile); + + fromfile = IsoFileClose(fromfile); + + + + IsoSaveTOC(tofile); + + tofile = IsoFileClose(tofile); + + gtk_entry_set_text(GTK_ENTRY(mainbox.file), templine); + + + + } else { + + fromfile = IsoFileClose(fromfile); + + tofile = IsoFileCloseAndDelete(tofile); + + } // ENDIF- Did we succeed in the transfer? + + + + if(stop != 1) ConversionBoxRefocus(); + + if(stop == 0) ConversionBoxCancelEvent(widget, event, data); + + return(TRUE); + +} // END ConversionBoxOKEvent() + + + + + +gint ConversionBoxBrowseEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + ConversionBoxUnfocus(); + + + + // Transfer file name to file selection + + gtk_file_selection_set_filename(GTK_FILE_SELECTION(selectionbox.window), + + gtk_entry_get_text(GTK_ENTRY(conversionbox.file))); + + selectionbox.wherefrom = 3; // From the Conversion Window + + SelectionBoxRefocus(); + + return(TRUE); + +} // END ConversionBoxBrowseEvent() + + + + + +void ConversionBoxDisplay() { + + GtkWidget *item; + + GtkWidget *hbox1; + + GtkWidget *vbox1; + + int nameptr; + + + + conversionbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + gtk_container_set_border_width(GTK_CONTAINER(conversionbox.window), 5); + + gtk_window_set_title(GTK_WINDOW(conversionbox.window), "CDVDisoEFP File Conversion"); + + gtk_window_set_position(GTK_WINDOW(conversionbox.window), GTK_WIN_POS_CENTER); + + + + g_signal_connect(G_OBJECT(conversionbox.window), "delete_event", + + G_CALLBACK(ConversionBoxCancelEvent), NULL); + + + + vbox1 = gtk_vbox_new(FALSE, 5); + + gtk_container_add(GTK_CONTAINER(conversionbox.window), vbox1); + + gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); + + gtk_widget_show(vbox1); + + + + hbox1 = gtk_hbox_new(FALSE, 10); + + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + + gtk_widget_show(hbox1); + + + + item = gtk_label_new("Iso File:"); + + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + conversionbox.file = gtk_entry_new(); + + gtk_box_pack_start(GTK_BOX(hbox1), conversionbox.file, TRUE, TRUE, 0); + + gtk_widget_show(conversionbox.file); + + g_signal_connect(G_OBJECT(conversionbox.file), "changed", + + G_CALLBACK(ConversionBoxFileEvent), NULL); + + + + conversionbox.selectbutton = gtk_button_new_with_label("Browse"); + + gtk_box_pack_start(GTK_BOX(hbox1), conversionbox.selectbutton, FALSE, FALSE, 0); + + gtk_widget_show(conversionbox.selectbutton); + + g_signal_connect(G_OBJECT(conversionbox.selectbutton), "clicked", + + G_CALLBACK(ConversionBoxBrowseEvent), NULL); + + hbox1 = NULL; + + + + conversionbox.filedesc = gtk_label_new("File Type: ---"); + + gtk_box_pack_start(GTK_BOX(vbox1), conversionbox.filedesc, FALSE, FALSE, 0); + + gtk_widget_show(conversionbox.filedesc); + + // ConversionBoxFileEvent(NULL, 0, NULL); // Work out compromise later... + + + + item = gtk_hseparator_new(); + + gtk_box_pack_start(GTK_BOX(vbox1), item, TRUE, TRUE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + hbox1 = gtk_hbox_new(FALSE, 10); + + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + + gtk_widget_show(hbox1); + + + + item = gtk_label_new("Change Compression To:"); + + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + conversionbox.compress = gtk_combo_box_new_text(); + + gtk_box_pack_start(GTK_BOX(hbox1), conversionbox.compress, FALSE, FALSE, 0); + + nameptr = 0; + + while(compressnames[nameptr] != NULL) { + + gtk_combo_box_append_text(GTK_COMBO_BOX(conversionbox.compress), + + compressnames[nameptr]); + + nameptr++; + + } // ENDWHILE- loading compression types into combo box + + gtk_combo_box_set_active(GTK_COMBO_BOX(conversionbox.compress), 0); // Temp Line + + gtk_widget_show(conversionbox.compress); + + hbox1 = NULL; + + + + hbox1 = gtk_hbox_new(FALSE, 10); + + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + + gtk_widget_show(hbox1); + + + + item = gtk_label_new("Multiple Files (all under 2 GB):"); + + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + conversionbox.multi = gtk_check_button_new(); + + gtk_box_pack_start(GTK_BOX(hbox1), conversionbox.multi, FALSE, FALSE, 0); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(conversionbox.multi), FALSE); + + gtk_widget_show(conversionbox.multi); + + hbox1 = NULL; + + + + hbox1 = gtk_hbutton_box_new(); + + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + + gtk_widget_show(hbox1); + + + + conversionbox.okbutton = gtk_button_new_with_label("Change File"); + + gtk_box_pack_start(GTK_BOX(hbox1), conversionbox.okbutton, TRUE, TRUE, 0); + + gtk_widget_show(conversionbox.okbutton); + + g_signal_connect(G_OBJECT(conversionbox.okbutton), "clicked", + + G_CALLBACK(ConversionBoxOKEvent), NULL); + + + + conversionbox.cancelbutton = gtk_button_new_with_label("Cancel"); + + gtk_box_pack_start(GTK_BOX(hbox1), conversionbox.cancelbutton, TRUE, TRUE, 0); + + gtk_widget_show(conversionbox.cancelbutton); + + g_signal_connect(G_OBJECT(conversionbox.cancelbutton), "clicked", + + G_CALLBACK(ConversionBoxCancelEvent), NULL); + + hbox1 = NULL; + + vbox1 = NULL; + +} // END ConversionBoxDisplay() + diff --git a/plugins/CDVDisoEFP/src/Linux/conversionbox.h b/plugins/CDVDisoEFP/src/Linux/conversionbox.h index d583837943..f0ff425924 100644 --- a/plugins/CDVDisoEFP/src/Linux/conversionbox.h +++ b/plugins/CDVDisoEFP/src/Linux/conversionbox.h @@ -1,47 +1,94 @@ -/* conversionbox.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef CONVERSIONBOX_H -#define CONVERSIONBOX_H - - -#include - - -struct ConversionBoxData { - GtkWidget *window; // GtkWindow - GtkWidget *file; // GtkEntry - GtkWidget *selectbutton; // GtkButton - GtkWidget *filedesc; // GtkLabel - GtkWidget *compress; // GtkComboBox - GtkWidget *multi; // GtkCheckButton - GtkWidget *okbutton; // GtkButton - GtkWidget *cancelbutton; // GtkButton -}; - -extern struct ConversionBoxData conversionbox; - -extern void ConversionBoxDestroy(); -extern void ConversionBoxRefocus(); -extern void ConversionBoxDisplay(); - - -#endif /* CONVERSIONBOX_H */ +/* conversionbox.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef CONVERSIONBOX_H + +#define CONVERSIONBOX_H + + + + + +#include + + + + + +struct ConversionBoxData { + + GtkWidget *window; // GtkWindow + + GtkWidget *file; // GtkEntry + + GtkWidget *selectbutton; // GtkButton + + GtkWidget *filedesc; // GtkLabel + + GtkWidget *compress; // GtkComboBox + + GtkWidget *multi; // GtkCheckButton + + GtkWidget *okbutton; // GtkButton + + GtkWidget *cancelbutton; // GtkButton + +}; + + + +extern struct ConversionBoxData conversionbox; + + + +extern void ConversionBoxDestroy(); + +extern void ConversionBoxRefocus(); + +extern void ConversionBoxDisplay(); + + + + + +#endif /* CONVERSIONBOX_H */ + diff --git a/plugins/CDVDisoEFP/src/Linux/device.h b/plugins/CDVDisoEFP/src/Linux/device.h index 0d0d8ffe49..ec38e857a5 100644 --- a/plugins/CDVDisoEFP/src/Linux/device.h +++ b/plugins/CDVDisoEFP/src/Linux/device.h @@ -1,69 +1,138 @@ -/* device.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - -#ifndef __DEVICE_H__ -#define __DEVICE_H__ - - -#include // time_t - -#ifndef __LINUX__ -#ifdef __linux__ -#define __LINUX__ -#endif /* __linux__ */ -#endif /* No __LINUX__ */ -#define CDVDdefs -#include "../PS2Edefs.h" - - -// #define VERBOSE_FUNCTION_DEVICE -// #define VERBOSE_WARNINGS -#define VERBOSE_DISC_TYPE -#define VERBOSE_DISC_INFO - - -// Device Data - -extern int devicehandle; -extern s32 devicecapability; // Need to export? - -extern time_t lasttime; -extern s32 traystatus; -extern s32 disctype; -extern u8 tocbuffer[]; - - -// Device Functions - -extern void DeviceInit(); -extern void InitDisc(); -extern s32 DiscInserted(); -extern s32 DeviceOpen(); -extern void DeviceClose(); -extern s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer); -extern s32 DeviceBufferOffset(); -extern s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd); -extern s32 DeviceGetDiskType(); -extern s32 DeviceTrayStatus(); -extern s32 DeviceTrayOpen(); -extern s32 DeviceTrayClose(); - - -#endif /* __DEVICE_H__ */ +/* device.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + +#ifndef __DEVICE_H__ + +#define __DEVICE_H__ + + + + + +#include // time_t + + + +#ifndef __LINUX__ + +#ifdef __linux__ + +#define __LINUX__ + +#endif /* __linux__ */ + +#endif /* No __LINUX__ */ + +#define CDVDdefs + +#include "../PS2Edefs.h" + + + + + +// #define VERBOSE_FUNCTION_DEVICE + +// #define VERBOSE_WARNINGS + +#define VERBOSE_DISC_TYPE + +#define VERBOSE_DISC_INFO + + + + + +// Device Data + + + +extern int devicehandle; + +extern s32 devicecapability; // Need to export? + + + +extern time_t lasttime; + +extern s32 traystatus; + +extern s32 disctype; + +extern u8 tocbuffer[]; + + + + + +// Device Functions + + + +extern void DeviceInit(); + +extern void InitDisc(); + +extern s32 DiscInserted(); + +extern s32 DeviceOpen(); + +extern void DeviceClose(); + +extern s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer); + +extern s32 DeviceBufferOffset(); + +extern s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd); + +extern s32 DeviceGetDiskType(); + +extern s32 DeviceTrayStatus(); + +extern s32 DeviceTrayOpen(); + +extern s32 DeviceTrayClose(); + + + + + +#endif /* __DEVICE_H__ */ + diff --git a/plugins/CDVDisoEFP/src/Linux/devicebox.c b/plugins/CDVDisoEFP/src/Linux/devicebox.c index ff0f56679e..128d7ed0e7 100644 --- a/plugins/CDVDisoEFP/src/Linux/devicebox.c +++ b/plugins/CDVDisoEFP/src/Linux/devicebox.c @@ -1,443 +1,886 @@ -/* devicebox.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // NULL -#include // sprintf() -#include // strcpy() -#include // stat() -#include // stat() -#include // stat() - -#include // gtk_button_new_with_label() -#include // gtk_combo_box_new() -#include // gtk_check_button_new() -#include // gtk_container_add() -#include // gtk_entry_new() -#include // gtk_file_selection_set_filename() -#include // gtk_hbutton_box_new() -#include // gtk_hbox_new() -#include // gtk_hseparator_new() -#include // gtk_label_new() -#include // gtk_main_iteration() -#include // gtk_toggle_button_get_active() -#include // gtk_vbox_new() -#include // gtk_window_new() - -#ifndef __LINUX__ -#ifdef __linux__ -#define __LINUX__ -#endif /* __linux__ */ -#endif /* No __LINUX__ */ -#define CDVDdefs -#include "PS2Edefs.h" - -#include "conf.h" -#include "device.h" -#include "isofile.h" -#include "isocompress.h" // compressdesc[] -// #include "imagetype.h" // imagedata[].name -#include "multifile.h" // multinames[] -#include "toc.h" -#include "progressbox.h" -#include "messagebox.h" -#include "selectionbox.h" -#include "mainbox.h" -#include "devicebox.h" - - -struct DeviceBoxData devicebox; - - -void DeviceBoxDestroy() { - if(devicebox.window != NULL) { - gtk_widget_destroy(devicebox.window); - devicebox.window = NULL; - devicebox.device = NULL; - devicebox.devicedesc = NULL; - devicebox.file = NULL; - devicebox.selectbutton = NULL; - devicebox.filedesc = NULL; - devicebox.compress = NULL; - devicebox.multi = NULL; - devicebox.okbutton = NULL; - devicebox.cancelbutton = NULL; - } // ENDIF- Do we have a Main Window still? -} // END DeviceBoxDestroy() - - -void DeviceBoxUnfocus() { - gtk_widget_set_sensitive(devicebox.device, FALSE); - gtk_widget_set_sensitive(devicebox.file, FALSE); - gtk_widget_set_sensitive(devicebox.selectbutton, FALSE); - gtk_widget_set_sensitive(devicebox.compress, FALSE); - gtk_widget_set_sensitive(devicebox.multi, FALSE); - gtk_widget_set_sensitive(devicebox.okbutton, FALSE); - gtk_widget_set_sensitive(devicebox.cancelbutton, FALSE); - gtk_widget_hide(devicebox.window); - // gtk_window_iconify(GTK_WINDOW(devicebox.window)); -} // END DeviceBoxUnfocus() - - -gint DeviceBoxDeviceEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - struct stat filestat; - int returnval; - - returnval = stat(gtk_entry_get_text(GTK_ENTRY(devicebox.device)), &filestat); - if(returnval == -1) { - gtk_label_set_text(GTK_LABEL(devicebox.devicedesc), "Device Type: ---"); - return(TRUE); - } // ENDIF- Not a name of any sort? - - if(S_ISDIR(filestat.st_mode) != 0) { - gtk_label_set_text(GTK_LABEL(devicebox.devicedesc), "Device Type: Not a device"); - return(TRUE); - } // ENDIF- Not a regular file? - - gtk_label_set_text(GTK_LABEL(devicebox.devicedesc), "Device Type: Device Likely"); - return(TRUE); -} // END DeviceBoxDeviceEvent() - - -gint DeviceBoxFileEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - int returnval; - char templine[256]; - struct IsoFile *tempfile; - - returnval = IsIsoFile(gtk_entry_get_text(GTK_ENTRY(devicebox.file))); - if(returnval == -1) { - gtk_label_set_text(GTK_LABEL(devicebox.filedesc), "File Type: ---"); - return(TRUE); - } // ENDIF- Not a name of any sort? - - if(returnval == -2) { - gtk_label_set_text(GTK_LABEL(devicebox.filedesc), "File Type: Not a file"); - return(TRUE); - } // ENDIF- Not a regular file? - - if(returnval == -3) { - gtk_label_set_text(GTK_LABEL(devicebox.filedesc), "File Type: Not a valid image file"); - return(TRUE); - } // ENDIF- Not an image file? - - if(returnval == -4) { - gtk_label_set_text(GTK_LABEL(devicebox.filedesc), "File Type: Missing Table File (will rebuild)"); - return(TRUE); - } // ENDIF- Not a regular file? - - tempfile = IsoFileOpenForRead(gtk_entry_get_text(GTK_ENTRY(devicebox.file))); - sprintf(templine, "File Type: %s%s%s", - multinames[tempfile->multi], - tempfile->imagename, - compressdesc[tempfile->compress]); - gtk_label_set_text(GTK_LABEL(devicebox.filedesc), templine); - tempfile = IsoFileClose(tempfile); - return(TRUE); -} // END DeviceBoxFileEvent() - - -void DeviceBoxRefocus() { - GdkEvent event; - - DeviceBoxDeviceEvent(NULL, event, NULL); - DeviceBoxFileEvent(NULL, event, NULL); - - gtk_widget_set_sensitive(devicebox.device, TRUE); - gtk_widget_set_sensitive(devicebox.file, TRUE); - gtk_widget_set_sensitive(devicebox.selectbutton, TRUE); - gtk_widget_set_sensitive(devicebox.compress, TRUE); - gtk_widget_set_sensitive(devicebox.multi, TRUE); - gtk_widget_set_sensitive(devicebox.okbutton, TRUE); - gtk_widget_set_sensitive(devicebox.cancelbutton, TRUE); - gtk_window_set_focus(GTK_WINDOW(devicebox.window), devicebox.file); - gtk_widget_show_all(devicebox.window); - gtk_window_deiconify(GTK_WINDOW(devicebox.window)); -} // END DeviceBoxRefocus() - - -gint DeviceBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - gtk_widget_hide(devicebox.window); - MainBoxRefocus(); - return(TRUE); -} // END DeviceBoxCancelEvent() - - -gint DeviceBoxOKEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - char templine[256]; - u8 tempbuffer[2352]; - struct IsoFile *tofile; - const char *tempdevice; - s32 retval; - cdvdTD cdvdtd; - int stop; - int compressmethod; - int multi; - int imagetype; - int i; - - DeviceBoxUnfocus(); - - tempdevice = gtk_entry_get_text(GTK_ENTRY(devicebox.device)); - strcpy(conf.devicename, tempdevice); // Temporarily put in new device name - tempdevice = NULL; - retval = DeviceOpen(); - if(retval != 0) { - DeviceClose(); - MessageBoxShow("Could not open the device", 2); - return(TRUE); - } // ENDIF- Trouble opening device? Abort here. - - DeviceTrayStatus(); - retval = DiscInserted(); - if(retval != 0) { - DeviceClose(); - MessageBoxShow("No disc in the device\r\nPlease put a disc in and try again.", 2); - return(TRUE); - } // ENDIF- Trouble opening device? Abort here. - - retval = DeviceGetTD(0, &cdvdtd); // Fish for Ending Sector - if(retval < 0) { - DeviceClose(); - MessageBoxShow("Could not retrieve disc sector size", 2); - return(TRUE); - } // ENDIF- Trouble getting disc sector count? - - compressmethod = gtk_combo_box_get_active(GTK_COMBO_BOX(devicebox.compress)); - if(compressmethod > 0) compressmethod += 2; - multi = 0; - if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(devicebox.multi)) == TRUE) - multi = 1; - - imagetype = 0; - if((disctype != CDVD_TYPE_PS2DVD) && - (disctype != CDVD_TYPE_DVDV)) imagetype = 8; - - tofile = IsoFileOpenForWrite(gtk_entry_get_text(GTK_ENTRY(devicebox.file)), - imagetype, - multi, - compressmethod); - if(tofile == NULL) { - DeviceClose(); - MessageBoxShow("Could not create the new ISO file", 2); - return(TRUE); - } // ENDIF- Trouble opening the ISO file? - - // Open Progress Bar - sprintf(templine, "%s -> %s", - gtk_entry_get_text(GTK_ENTRY(devicebox.device)), tofile->name); - ProgressBoxStart(templine, (off64_t) cdvdtd.lsn); - - tofile->cdvdtype = disctype; - for(i = 0; i < 2048; i++) tofile->toc[i] = tocbuffer[i]; - - stop = 0; - mainbox.stop = 0; - progressbox.stop = 0; - while((stop == 0) && (tofile->sectorpos < cdvdtd.lsn)) { - if(imagetype == 0) { - retval = DeviceReadTrack((u32) tofile->sectorpos, - CDVD_MODE_2048, - tempbuffer); - } else { - retval = DeviceReadTrack((u32) tofile->sectorpos, - CDVD_MODE_2352, - tempbuffer); - } // ENDIF- Are we reading a DVD sector? (Or a CD sector?) - if(retval < 0) { - for(i = 0; i < 2352; i++) { - tempbuffer[i] = 0; - } // NEXT i- Zeroing the buffer - } // ENDIF- Trouble reading next block? - retval = IsoFileWrite(tofile, tempbuffer); - if(retval < 0) { - MessageBoxShow("Trouble writing new file", 3); - stop = 1; - } // ENDIF- Trouble writing out the next block? - - ProgressBoxTick(tofile->sectorpos); - while(gtk_events_pending()) gtk_main_iteration(); - - if(mainbox.stop != 0) stop = 2; - if(progressbox.stop != 0) stop = 2; - } // ENDWHILE- No reason found to stop... - - ProgressBoxStop(); - - if(stop == 0) { - if(tofile->multi == 1) tofile->name[tofile->multipos] = '0'; // First file - strcpy(templine, tofile->name); - } // ENDIF- Did we succeed with the transfer? - - DeviceClose(); - if(stop == 0) { - IsoSaveTOC(tofile); - tofile = IsoFileClose(tofile); - gtk_entry_set_text(GTK_ENTRY(mainbox.file), templine); - } else { - tofile = IsoFileCloseAndDelete(tofile); - } // ENDIF- (Failed to complete writing file? Get rid of the garbage files.) - - if(stop != 1) DeviceBoxRefocus(); - if(stop == 0) DeviceBoxCancelEvent(widget, event, data); - return(TRUE); -} // END DeviceBoxOKEvent() - - -gint DeviceBoxBrowseEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - DeviceBoxUnfocus(); - - // Transfer file name to file selection - gtk_file_selection_set_filename(GTK_FILE_SELECTION(selectionbox.window), - gtk_entry_get_text(GTK_ENTRY(devicebox.file))); - selectionbox.wherefrom = 2; // From the Device Window - SelectionBoxRefocus(); - return(TRUE); -} // END DeviceBoxBrowseEvent() - - -void DeviceBoxDisplay() { - GtkWidget *item; - GtkWidget *hbox1; - GtkWidget *vbox1; - int nameptr; - - devicebox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_container_set_border_width(GTK_CONTAINER(devicebox.window), 5); - gtk_window_set_title(GTK_WINDOW(devicebox.window), "CDVDisoEFP ISO Creation"); - gtk_window_set_position(GTK_WINDOW(devicebox.window), GTK_WIN_POS_CENTER); - - g_signal_connect(G_OBJECT(devicebox.window), "delete_event", - G_CALLBACK(DeviceBoxCancelEvent), NULL); - - vbox1 = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(devicebox.window), vbox1); - gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); - gtk_widget_show(vbox1); - - hbox1 = gtk_hbox_new(FALSE, 10); - gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); - gtk_widget_show(hbox1); - - item = gtk_label_new("Source CD/DVD Device:"); - gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); - gtk_widget_show(item); - item = NULL; - - devicebox.device = gtk_entry_new(); - gtk_box_pack_start(GTK_BOX(hbox1), devicebox.device, TRUE, TRUE, 0); - gtk_widget_show(devicebox.device); - g_signal_connect(G_OBJECT(devicebox.device), "changed", - G_CALLBACK(DeviceBoxDeviceEvent), NULL); - hbox1 = NULL; - - devicebox.devicedesc = gtk_label_new("Device Type: ---"); - gtk_box_pack_start(GTK_BOX(vbox1), devicebox.devicedesc, FALSE, FALSE, 0); - gtk_widget_show(devicebox.devicedesc); - - item = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(vbox1), item, TRUE, TRUE, 0); - gtk_widget_show(item); - item = NULL; - - hbox1 = gtk_hbox_new(FALSE, 10); - gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); - gtk_widget_show(hbox1); - - item = gtk_label_new("Iso File:"); - gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); - gtk_widget_show(item); - item = NULL; - - devicebox.file = gtk_entry_new(); - gtk_box_pack_start(GTK_BOX(hbox1), devicebox.file, TRUE, TRUE, 0); - gtk_widget_show(devicebox.file); - g_signal_connect(G_OBJECT(devicebox.file), "changed", - G_CALLBACK(DeviceBoxFileEvent), NULL); - - devicebox.selectbutton = gtk_button_new_with_label("Browse"); - gtk_box_pack_start(GTK_BOX(hbox1), devicebox.selectbutton, FALSE, FALSE, 0); - gtk_widget_show(devicebox.selectbutton); - g_signal_connect(G_OBJECT(devicebox.selectbutton), "clicked", - G_CALLBACK(DeviceBoxBrowseEvent), NULL); - hbox1 = NULL; - - devicebox.filedesc = gtk_label_new("File Type: ---"); - gtk_box_pack_start(GTK_BOX(vbox1), devicebox.filedesc, FALSE, FALSE, 0); - gtk_widget_show(devicebox.filedesc); - - hbox1 = gtk_hbox_new(FALSE, 10); - gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); - gtk_widget_show(hbox1); - - item = gtk_label_new("New File Compression:"); - gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); - gtk_widget_show(item); - item = NULL; - - devicebox.compress = gtk_combo_box_new_text(); - gtk_box_pack_start(GTK_BOX(hbox1), devicebox.compress, FALSE, FALSE, 0); - nameptr = 0; - while(compressnames[nameptr] != NULL) { - gtk_combo_box_append_text(GTK_COMBO_BOX(devicebox.compress), - compressnames[nameptr]); - nameptr++; - } // ENDWHILE- loading compression types into combo box - gtk_combo_box_set_active(GTK_COMBO_BOX(devicebox.compress), 0); // Temp Line - gtk_widget_show(devicebox.compress); - hbox1 = NULL; - - hbox1 = gtk_hbox_new(FALSE, 10); - gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); - gtk_widget_show(hbox1); - - item = gtk_label_new("Multiple Files (all under 2 GB):"); - gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); - gtk_widget_show(item); - item = NULL; - - devicebox.multi = gtk_check_button_new(); - gtk_box_pack_start(GTK_BOX(hbox1), devicebox.multi, FALSE, FALSE, 0); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(devicebox.multi), FALSE); - gtk_widget_show(devicebox.multi); - hbox1 = NULL; - - hbox1 = gtk_hbutton_box_new(); - gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); - gtk_widget_show(hbox1); - - devicebox.okbutton = gtk_button_new_with_label("Make File"); - gtk_box_pack_start(GTK_BOX(hbox1), devicebox.okbutton, TRUE, TRUE, 0); - gtk_widget_show(devicebox.okbutton); - g_signal_connect(G_OBJECT(devicebox.okbutton), "clicked", - G_CALLBACK(DeviceBoxOKEvent), NULL); - - devicebox.cancelbutton = gtk_button_new_with_label("Cancel"); - gtk_box_pack_start(GTK_BOX(hbox1), devicebox.cancelbutton, TRUE, TRUE, 0); - gtk_widget_show(devicebox.cancelbutton); - g_signal_connect(G_OBJECT(devicebox.cancelbutton), "clicked", - G_CALLBACK(DeviceBoxCancelEvent), NULL); - hbox1 = NULL; - vbox1 = NULL; - - // Device text not set until now to get the correct description. - gtk_entry_set_text(GTK_ENTRY(devicebox.device), conf.devicename); - - DeviceInit(); // Initialize device access -} // END DeviceBoxDisplay() +/* devicebox.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // sprintf() + +#include // strcpy() + +#include // stat() + +#include // stat() + +#include // stat() + + + +#include // gtk_button_new_with_label() + +#include // gtk_combo_box_new() + +#include // gtk_check_button_new() + +#include // gtk_container_add() + +#include // gtk_entry_new() + +#include // gtk_file_selection_set_filename() + +#include // gtk_hbutton_box_new() + +#include // gtk_hbox_new() + +#include // gtk_hseparator_new() + +#include // gtk_label_new() + +#include // gtk_main_iteration() + +#include // gtk_toggle_button_get_active() + +#include // gtk_vbox_new() + +#include // gtk_window_new() + + + +#ifndef __LINUX__ + +#ifdef __linux__ + +#define __LINUX__ + +#endif /* __linux__ */ + +#endif /* No __LINUX__ */ + +#define CDVDdefs + +#include "PS2Edefs.h" + + + +#include "conf.h" + +#include "device.h" + +#include "isofile.h" + +#include "isocompress.h" // compressdesc[] + +// #include "imagetype.h" // imagedata[].name + +#include "multifile.h" // multinames[] + +#include "toc.h" + +#include "progressbox.h" + +#include "messagebox.h" + +#include "selectionbox.h" + +#include "mainbox.h" + +#include "devicebox.h" + + + + + +struct DeviceBoxData devicebox; + + + + + +void DeviceBoxDestroy() { + + if(devicebox.window != NULL) { + + gtk_widget_destroy(devicebox.window); + + devicebox.window = NULL; + + devicebox.device = NULL; + + devicebox.devicedesc = NULL; + + devicebox.file = NULL; + + devicebox.selectbutton = NULL; + + devicebox.filedesc = NULL; + + devicebox.compress = NULL; + + devicebox.multi = NULL; + + devicebox.okbutton = NULL; + + devicebox.cancelbutton = NULL; + + } // ENDIF- Do we have a Main Window still? + +} // END DeviceBoxDestroy() + + + + + +void DeviceBoxUnfocus() { + + gtk_widget_set_sensitive(devicebox.device, FALSE); + + gtk_widget_set_sensitive(devicebox.file, FALSE); + + gtk_widget_set_sensitive(devicebox.selectbutton, FALSE); + + gtk_widget_set_sensitive(devicebox.compress, FALSE); + + gtk_widget_set_sensitive(devicebox.multi, FALSE); + + gtk_widget_set_sensitive(devicebox.okbutton, FALSE); + + gtk_widget_set_sensitive(devicebox.cancelbutton, FALSE); + + gtk_widget_hide(devicebox.window); + + // gtk_window_iconify(GTK_WINDOW(devicebox.window)); + +} // END DeviceBoxUnfocus() + + + + + +gint DeviceBoxDeviceEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + struct stat filestat; + + int returnval; + + + + returnval = stat(gtk_entry_get_text(GTK_ENTRY(devicebox.device)), &filestat); + + if(returnval == -1) { + + gtk_label_set_text(GTK_LABEL(devicebox.devicedesc), "Device Type: ---"); + + return(TRUE); + + } // ENDIF- Not a name of any sort? + + + + if(S_ISDIR(filestat.st_mode) != 0) { + + gtk_label_set_text(GTK_LABEL(devicebox.devicedesc), "Device Type: Not a device"); + + return(TRUE); + + } // ENDIF- Not a regular file? + + + + gtk_label_set_text(GTK_LABEL(devicebox.devicedesc), "Device Type: Device Likely"); + + return(TRUE); + +} // END DeviceBoxDeviceEvent() + + + + + +gint DeviceBoxFileEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + int returnval; + + char templine[256]; + + struct IsoFile *tempfile; + + + + returnval = IsIsoFile(gtk_entry_get_text(GTK_ENTRY(devicebox.file))); + + if(returnval == -1) { + + gtk_label_set_text(GTK_LABEL(devicebox.filedesc), "File Type: ---"); + + return(TRUE); + + } // ENDIF- Not a name of any sort? + + + + if(returnval == -2) { + + gtk_label_set_text(GTK_LABEL(devicebox.filedesc), "File Type: Not a file"); + + return(TRUE); + + } // ENDIF- Not a regular file? + + + + if(returnval == -3) { + + gtk_label_set_text(GTK_LABEL(devicebox.filedesc), "File Type: Not a valid image file"); + + return(TRUE); + + } // ENDIF- Not an image file? + + + + if(returnval == -4) { + + gtk_label_set_text(GTK_LABEL(devicebox.filedesc), "File Type: Missing Table File (will rebuild)"); + + return(TRUE); + + } // ENDIF- Not a regular file? + + + + tempfile = IsoFileOpenForRead(gtk_entry_get_text(GTK_ENTRY(devicebox.file))); + + sprintf(templine, "File Type: %s%s%s", + + multinames[tempfile->multi], + + tempfile->imagename, + + compressdesc[tempfile->compress]); + + gtk_label_set_text(GTK_LABEL(devicebox.filedesc), templine); + + tempfile = IsoFileClose(tempfile); + + return(TRUE); + +} // END DeviceBoxFileEvent() + + + + + +void DeviceBoxRefocus() { + + GdkEvent event; + + + + DeviceBoxDeviceEvent(NULL, event, NULL); + + DeviceBoxFileEvent(NULL, event, NULL); + + + + gtk_widget_set_sensitive(devicebox.device, TRUE); + + gtk_widget_set_sensitive(devicebox.file, TRUE); + + gtk_widget_set_sensitive(devicebox.selectbutton, TRUE); + + gtk_widget_set_sensitive(devicebox.compress, TRUE); + + gtk_widget_set_sensitive(devicebox.multi, TRUE); + + gtk_widget_set_sensitive(devicebox.okbutton, TRUE); + + gtk_widget_set_sensitive(devicebox.cancelbutton, TRUE); + + gtk_window_set_focus(GTK_WINDOW(devicebox.window), devicebox.file); + + gtk_widget_show_all(devicebox.window); + + gtk_window_deiconify(GTK_WINDOW(devicebox.window)); + +} // END DeviceBoxRefocus() + + + + + +gint DeviceBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + gtk_widget_hide(devicebox.window); + + MainBoxRefocus(); + + return(TRUE); + +} // END DeviceBoxCancelEvent() + + + + + +gint DeviceBoxOKEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + char templine[256]; + + u8 tempbuffer[2352]; + + struct IsoFile *tofile; + + const char *tempdevice; + + s32 retval; + + cdvdTD cdvdtd; + + int stop; + + int compressmethod; + + int multi; + + int imagetype; + + int i; + + + + DeviceBoxUnfocus(); + + + + tempdevice = gtk_entry_get_text(GTK_ENTRY(devicebox.device)); + + strcpy(conf.devicename, tempdevice); // Temporarily put in new device name + + tempdevice = NULL; + + retval = DeviceOpen(); + + if(retval != 0) { + + DeviceClose(); + + MessageBoxShow("Could not open the device", 2); + + return(TRUE); + + } // ENDIF- Trouble opening device? Abort here. + + + + DeviceTrayStatus(); + + retval = DiscInserted(); + + if(retval != 0) { + + DeviceClose(); + + MessageBoxShow("No disc in the device\r\nPlease put a disc in and try again.", 2); + + return(TRUE); + + } // ENDIF- Trouble opening device? Abort here. + + + + retval = DeviceGetTD(0, &cdvdtd); // Fish for Ending Sector + + if(retval < 0) { + + DeviceClose(); + + MessageBoxShow("Could not retrieve disc sector size", 2); + + return(TRUE); + + } // ENDIF- Trouble getting disc sector count? + + + + compressmethod = gtk_combo_box_get_active(GTK_COMBO_BOX(devicebox.compress)); + + if(compressmethod > 0) compressmethod += 2; + + multi = 0; + + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(devicebox.multi)) == TRUE) + + multi = 1; + + + + imagetype = 0; + + if((disctype != CDVD_TYPE_PS2DVD) && + + (disctype != CDVD_TYPE_DVDV)) imagetype = 8; + + + + tofile = IsoFileOpenForWrite(gtk_entry_get_text(GTK_ENTRY(devicebox.file)), + + imagetype, + + multi, + + compressmethod); + + if(tofile == NULL) { + + DeviceClose(); + + MessageBoxShow("Could not create the new ISO file", 2); + + return(TRUE); + + } // ENDIF- Trouble opening the ISO file? + + + + // Open Progress Bar + + sprintf(templine, "%s -> %s", + + gtk_entry_get_text(GTK_ENTRY(devicebox.device)), tofile->name); + + ProgressBoxStart(templine, (off64_t) cdvdtd.lsn); + + + + tofile->cdvdtype = disctype; + + for(i = 0; i < 2048; i++) tofile->toc[i] = tocbuffer[i]; + + + + stop = 0; + + mainbox.stop = 0; + + progressbox.stop = 0; + + while((stop == 0) && (tofile->sectorpos < cdvdtd.lsn)) { + + if(imagetype == 0) { + + retval = DeviceReadTrack((u32) tofile->sectorpos, + + CDVD_MODE_2048, + + tempbuffer); + + } else { + + retval = DeviceReadTrack((u32) tofile->sectorpos, + + CDVD_MODE_2352, + + tempbuffer); + + } // ENDIF- Are we reading a DVD sector? (Or a CD sector?) + + if(retval < 0) { + + for(i = 0; i < 2352; i++) { + + tempbuffer[i] = 0; + + } // NEXT i- Zeroing the buffer + + } // ENDIF- Trouble reading next block? + + retval = IsoFileWrite(tofile, tempbuffer); + + if(retval < 0) { + + MessageBoxShow("Trouble writing new file", 3); + + stop = 1; + + } // ENDIF- Trouble writing out the next block? + + + + ProgressBoxTick(tofile->sectorpos); + + while(gtk_events_pending()) gtk_main_iteration(); + + + + if(mainbox.stop != 0) stop = 2; + + if(progressbox.stop != 0) stop = 2; + + } // ENDWHILE- No reason found to stop... + + + + ProgressBoxStop(); + + + + if(stop == 0) { + + if(tofile->multi == 1) tofile->name[tofile->multipos] = '0'; // First file + + strcpy(templine, tofile->name); + + } // ENDIF- Did we succeed with the transfer? + + + + DeviceClose(); + + if(stop == 0) { + + IsoSaveTOC(tofile); + + tofile = IsoFileClose(tofile); + + gtk_entry_set_text(GTK_ENTRY(mainbox.file), templine); + + } else { + + tofile = IsoFileCloseAndDelete(tofile); + + } // ENDIF- (Failed to complete writing file? Get rid of the garbage files.) + + + + if(stop != 1) DeviceBoxRefocus(); + + if(stop == 0) DeviceBoxCancelEvent(widget, event, data); + + return(TRUE); + +} // END DeviceBoxOKEvent() + + + + + +gint DeviceBoxBrowseEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + DeviceBoxUnfocus(); + + + + // Transfer file name to file selection + + gtk_file_selection_set_filename(GTK_FILE_SELECTION(selectionbox.window), + + gtk_entry_get_text(GTK_ENTRY(devicebox.file))); + + selectionbox.wherefrom = 2; // From the Device Window + + SelectionBoxRefocus(); + + return(TRUE); + +} // END DeviceBoxBrowseEvent() + + + + + +void DeviceBoxDisplay() { + + GtkWidget *item; + + GtkWidget *hbox1; + + GtkWidget *vbox1; + + int nameptr; + + + + devicebox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + gtk_container_set_border_width(GTK_CONTAINER(devicebox.window), 5); + + gtk_window_set_title(GTK_WINDOW(devicebox.window), "CDVDisoEFP ISO Creation"); + + gtk_window_set_position(GTK_WINDOW(devicebox.window), GTK_WIN_POS_CENTER); + + + + g_signal_connect(G_OBJECT(devicebox.window), "delete_event", + + G_CALLBACK(DeviceBoxCancelEvent), NULL); + + + + vbox1 = gtk_vbox_new(FALSE, 5); + + gtk_container_add(GTK_CONTAINER(devicebox.window), vbox1); + + gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); + + gtk_widget_show(vbox1); + + + + hbox1 = gtk_hbox_new(FALSE, 10); + + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + + gtk_widget_show(hbox1); + + + + item = gtk_label_new("Source CD/DVD Device:"); + + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + devicebox.device = gtk_entry_new(); + + gtk_box_pack_start(GTK_BOX(hbox1), devicebox.device, TRUE, TRUE, 0); + + gtk_widget_show(devicebox.device); + + g_signal_connect(G_OBJECT(devicebox.device), "changed", + + G_CALLBACK(DeviceBoxDeviceEvent), NULL); + + hbox1 = NULL; + + + + devicebox.devicedesc = gtk_label_new("Device Type: ---"); + + gtk_box_pack_start(GTK_BOX(vbox1), devicebox.devicedesc, FALSE, FALSE, 0); + + gtk_widget_show(devicebox.devicedesc); + + + + item = gtk_hseparator_new(); + + gtk_box_pack_start(GTK_BOX(vbox1), item, TRUE, TRUE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + hbox1 = gtk_hbox_new(FALSE, 10); + + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + + gtk_widget_show(hbox1); + + + + item = gtk_label_new("Iso File:"); + + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + devicebox.file = gtk_entry_new(); + + gtk_box_pack_start(GTK_BOX(hbox1), devicebox.file, TRUE, TRUE, 0); + + gtk_widget_show(devicebox.file); + + g_signal_connect(G_OBJECT(devicebox.file), "changed", + + G_CALLBACK(DeviceBoxFileEvent), NULL); + + + + devicebox.selectbutton = gtk_button_new_with_label("Browse"); + + gtk_box_pack_start(GTK_BOX(hbox1), devicebox.selectbutton, FALSE, FALSE, 0); + + gtk_widget_show(devicebox.selectbutton); + + g_signal_connect(G_OBJECT(devicebox.selectbutton), "clicked", + + G_CALLBACK(DeviceBoxBrowseEvent), NULL); + + hbox1 = NULL; + + + + devicebox.filedesc = gtk_label_new("File Type: ---"); + + gtk_box_pack_start(GTK_BOX(vbox1), devicebox.filedesc, FALSE, FALSE, 0); + + gtk_widget_show(devicebox.filedesc); + + + + hbox1 = gtk_hbox_new(FALSE, 10); + + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + + gtk_widget_show(hbox1); + + + + item = gtk_label_new("New File Compression:"); + + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + devicebox.compress = gtk_combo_box_new_text(); + + gtk_box_pack_start(GTK_BOX(hbox1), devicebox.compress, FALSE, FALSE, 0); + + nameptr = 0; + + while(compressnames[nameptr] != NULL) { + + gtk_combo_box_append_text(GTK_COMBO_BOX(devicebox.compress), + + compressnames[nameptr]); + + nameptr++; + + } // ENDWHILE- loading compression types into combo box + + gtk_combo_box_set_active(GTK_COMBO_BOX(devicebox.compress), 0); // Temp Line + + gtk_widget_show(devicebox.compress); + + hbox1 = NULL; + + + + hbox1 = gtk_hbox_new(FALSE, 10); + + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + + gtk_widget_show(hbox1); + + + + item = gtk_label_new("Multiple Files (all under 2 GB):"); + + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + devicebox.multi = gtk_check_button_new(); + + gtk_box_pack_start(GTK_BOX(hbox1), devicebox.multi, FALSE, FALSE, 0); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(devicebox.multi), FALSE); + + gtk_widget_show(devicebox.multi); + + hbox1 = NULL; + + + + hbox1 = gtk_hbutton_box_new(); + + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + + gtk_widget_show(hbox1); + + + + devicebox.okbutton = gtk_button_new_with_label("Make File"); + + gtk_box_pack_start(GTK_BOX(hbox1), devicebox.okbutton, TRUE, TRUE, 0); + + gtk_widget_show(devicebox.okbutton); + + g_signal_connect(G_OBJECT(devicebox.okbutton), "clicked", + + G_CALLBACK(DeviceBoxOKEvent), NULL); + + + + devicebox.cancelbutton = gtk_button_new_with_label("Cancel"); + + gtk_box_pack_start(GTK_BOX(hbox1), devicebox.cancelbutton, TRUE, TRUE, 0); + + gtk_widget_show(devicebox.cancelbutton); + + g_signal_connect(G_OBJECT(devicebox.cancelbutton), "clicked", + + G_CALLBACK(DeviceBoxCancelEvent), NULL); + + hbox1 = NULL; + + vbox1 = NULL; + + + + // Device text not set until now to get the correct description. + + gtk_entry_set_text(GTK_ENTRY(devicebox.device), conf.devicename); + + + + DeviceInit(); // Initialize device access + +} // END DeviceBoxDisplay() + diff --git a/plugins/CDVDisoEFP/src/Linux/devicebox.h b/plugins/CDVDisoEFP/src/Linux/devicebox.h index ecf748ad92..05d662e73f 100644 --- a/plugins/CDVDisoEFP/src/Linux/devicebox.h +++ b/plugins/CDVDisoEFP/src/Linux/devicebox.h @@ -1,50 +1,100 @@ -/* devicebox.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef DEVICEBOX_H -#define DEVICEBOX_H - - -#include - - -struct DeviceBoxData { - GtkWidget *window; // GtkWindow - GtkWidget *device; // GtkEntry - GtkWidget *devicedesc; // GtkLabel - GtkWidget *file; // GtkEntry - GtkWidget *selectbutton; // GtkButton - GtkWidget *filedesc; // GtkLabel - GtkWidget *compress; // GtkComboBox - GtkWidget *multi; // GtkCheckButton - GtkWidget *okbutton; // GtkButton - GtkWidget *cancelbutton; // GtkButton -}; - -extern struct DeviceBoxData devicebox; - -extern void DeviceBoxDestroy(); -// extern void DeviceBoxUnfocus(); -extern void DeviceBoxRefocus(); -extern void DeviceBoxDisplay(); - - -#endif /* DEVICEBOX_H */ +/* devicebox.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef DEVICEBOX_H + +#define DEVICEBOX_H + + + + + +#include + + + + + +struct DeviceBoxData { + + GtkWidget *window; // GtkWindow + + GtkWidget *device; // GtkEntry + + GtkWidget *devicedesc; // GtkLabel + + GtkWidget *file; // GtkEntry + + GtkWidget *selectbutton; // GtkButton + + GtkWidget *filedesc; // GtkLabel + + GtkWidget *compress; // GtkComboBox + + GtkWidget *multi; // GtkCheckButton + + GtkWidget *okbutton; // GtkButton + + GtkWidget *cancelbutton; // GtkButton + +}; + + + +extern struct DeviceBoxData devicebox; + + + +extern void DeviceBoxDestroy(); + +// extern void DeviceBoxUnfocus(); + +extern void DeviceBoxRefocus(); + +extern void DeviceBoxDisplay(); + + + + + +#endif /* DEVICEBOX_H */ + diff --git a/plugins/CDVDisoEFP/src/Linux/interface.c b/plugins/CDVDisoEFP/src/Linux/interface.c index af63d8f450..7243c15b6f 100644 --- a/plugins/CDVDisoEFP/src/Linux/interface.c +++ b/plugins/CDVDisoEFP/src/Linux/interface.c @@ -1,67 +1,134 @@ -/* interface.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // NULL -#include // sprintf() -#include // strcmp() - -#include // gtk_init(), gtk_main(), gtk_main_quit() -#include // gtk_widget_show_all() - -#include "logfile.h" -#include "conf.h" -#include "aboutbox.h" -#include "mainbox.h" -#include "devicebox.h" -#include "selectionbox.h" -#include "progressbox.h" -#include "messagebox.h" -#include "conversionbox.h" -#include "interface.h" - - -int main(int argc, char *argv[]) { - if(argc != 2) return(1); - - gtk_init(NULL, NULL); - - if(!strcmp(argv[1], "about")) { - AboutBoxDisplay(); - return(0); - } else if (!strcmp(argv[1], "configure")) { - OpenLog(); - InitConf(); - LoadConf(); - MainBoxDisplay(); - DeviceBoxDisplay(); - ConversionBoxDisplay(); - ProgressBoxDisplay(); - MessageBoxDisplay(); - SelectionBoxDisplay(); - - gtk_widget_show_all(mainbox.window); - gtk_main(); - CloseLog(); - return(0); - } // ENDLONGIF- Which display would you like to see? - - return(1); // No Displays chosen? Abort! -} // END main() +/* interface.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // sprintf() + +#include // strcmp() + + + +#include // gtk_init(), gtk_main(), gtk_main_quit() + +#include // gtk_widget_show_all() + + + +#include "logfile.h" + +#include "conf.h" + +#include "aboutbox.h" + +#include "mainbox.h" + +#include "devicebox.h" + +#include "selectionbox.h" + +#include "progressbox.h" + +#include "messagebox.h" + +#include "conversionbox.h" + +#include "interface.h" + + + + + +int main(int argc, char *argv[]) { + + if(argc != 2) return(1); + + + + gtk_init(NULL, NULL); + + + + if(!strcmp(argv[1], "about")) { + + AboutBoxDisplay(); + + return(0); + + } else if (!strcmp(argv[1], "configure")) { + + OpenLog(); + + InitConf(); + + LoadConf(); + + MainBoxDisplay(); + + DeviceBoxDisplay(); + + ConversionBoxDisplay(); + + ProgressBoxDisplay(); + + MessageBoxDisplay(); + + SelectionBoxDisplay(); + + + + gtk_widget_show_all(mainbox.window); + + gtk_main(); + + CloseLog(); + + return(0); + + } // ENDLONGIF- Which display would you like to see? + + + + return(1); // No Displays chosen? Abort! + +} // END main() + diff --git a/plugins/CDVDisoEFP/src/Linux/interface.h b/plugins/CDVDisoEFP/src/Linux/interface.h index a23946f677..badfac8930 100644 --- a/plugins/CDVDisoEFP/src/Linux/interface.h +++ b/plugins/CDVDisoEFP/src/Linux/interface.h @@ -1,29 +1,58 @@ -/* interface.h - * Copyright (C) 2002-2004 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef INTERFACE_H -#define INTERFACE_H - - -// Place holder... for now - - -#endif /* INTERFACE_H */ +/* interface.h + + * Copyright (C) 2002-2004 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef INTERFACE_H + +#define INTERFACE_H + + + + + +// Place holder... for now + + + + + +#endif /* INTERFACE_H */ + diff --git a/plugins/CDVDisoEFP/src/Linux/logfile.c b/plugins/CDVDisoEFP/src/Linux/logfile.c index 27c6fe879b..9c1a2348f5 100644 --- a/plugins/CDVDisoEFP/src/Linux/logfile.c +++ b/plugins/CDVDisoEFP/src/Linux/logfile.c @@ -1,90 +1,180 @@ -/* logfile.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // open -#include // vsprintf() -#include // va_start(), va_end(), vsprintf() -#include // mkdir(), open() -#include // mkdir(), open() -#include // close(), write(), unlink() - -#include "logfile.h" - - -int logfile; -char logfiletemp[2048]; - - -void InitLog() { - // Token comment line -#ifdef VERBOSE_LOGFILE - mkdir("./logs", 0755); - - unlink("./logs/CDVDlog.txt"); -#endif /* VERBOSE LOGFILE */ -} // END InitLog(); - - -int OpenLog() { - // Token comment line -#ifdef VERBOSE_LOGFILE - logfile = -1; - logfile = open("./logs/CDVDlog.txt", O_WRONLY | O_CREAT | O_APPEND, 0755); - if(logfile == -1) return(-1); -#endif /* VERBOSE LOGFILE */ - - return(0); -} // END OpenLog(); - - -void CloseLog() { - // Token comment line -#ifdef VERBOSE_LOGFILE - if(logfile != -1) { - close(logfile); - logfile = -1; - } // ENDIF- Is the log file actually open? Close it. -#endif /* VERBOSE LOGFILE */ -} // END CloseLog() - - -void PrintLog(const char *fmt, ...) { - // Token comment line -#ifdef VERBOSE_LOGFILE - va_list list; - int len; - - if(logfile == -1) return; // Log file not open. - - va_start(list, fmt); - vsprintf(logfiletemp, fmt, list); - va_end(list); - - len = 0; - while((len < 2048) && (logfiletemp[len] != 0)) len++; - if((len > 0) && (logfiletemp[len-1] == '\n')) len--; - if((len > 0) && (logfiletemp[len-1] == '\r')) len--; - logfiletemp[len] = 0; // Slice off the last "\r\n"... - - write(logfile, logfiletemp, len); - write(logfile, "\r\n", 2); // ... and write out your own. -#endif /* VERBOSE LOGFILE */ -} // END PrintLog() +/* logfile.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // open + +#include // vsprintf() + +#include // va_start(), va_end(), vsprintf() + +#include // mkdir(), open() + +#include // mkdir(), open() + +#include // close(), write(), unlink() + + + +#include "logfile.h" + + + + + +int logfile; + +char logfiletemp[2048]; + + + + + +void InitLog() { + + // Token comment line + +#ifdef VERBOSE_LOGFILE + + mkdir("./logs", 0755); + + + + unlink("./logs/CDVDlog.txt"); + +#endif /* VERBOSE LOGFILE */ + +} // END InitLog(); + + + + + +int OpenLog() { + + // Token comment line + +#ifdef VERBOSE_LOGFILE + + logfile = -1; + + logfile = open("./logs/CDVDlog.txt", O_WRONLY | O_CREAT | O_APPEND, 0755); + + if(logfile == -1) return(-1); + +#endif /* VERBOSE LOGFILE */ + + + + return(0); + +} // END OpenLog(); + + + + + +void CloseLog() { + + // Token comment line + +#ifdef VERBOSE_LOGFILE + + if(logfile != -1) { + + close(logfile); + + logfile = -1; + + } // ENDIF- Is the log file actually open? Close it. + +#endif /* VERBOSE LOGFILE */ + +} // END CloseLog() + + + + + +void PrintLog(const char *fmt, ...) { + + // Token comment line + +#ifdef VERBOSE_LOGFILE + + va_list list; + + int len; + + + + if(logfile == -1) return; // Log file not open. + + + + va_start(list, fmt); + + vsprintf(logfiletemp, fmt, list); + + va_end(list); + + + + len = 0; + + while((len < 2048) && (logfiletemp[len] != 0)) len++; + + if((len > 0) && (logfiletemp[len-1] == '\n')) len--; + + if((len > 0) && (logfiletemp[len-1] == '\r')) len--; + + logfiletemp[len] = 0; // Slice off the last "\r\n"... + + + + write(logfile, logfiletemp, len); + + write(logfile, "\r\n", 2); // ... and write out your own. + +#endif /* VERBOSE LOGFILE */ + +} // END PrintLog() + diff --git a/plugins/CDVDisoEFP/src/Linux/mainbox.c b/plugins/CDVDisoEFP/src/Linux/mainbox.c index d9989d5b1a..9e8fc1c980 100644 --- a/plugins/CDVDisoEFP/src/Linux/mainbox.c +++ b/plugins/CDVDisoEFP/src/Linux/mainbox.c @@ -1,324 +1,648 @@ -/* mainbox.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // NULL -#include // sprintf() -#include // strcpy() - -#include // gtk_button_new_with_label() -#include // gtk_check_button_new_with_label() -#include // gtk_container_add() -#include // gtk_entry_new() -#include // gtk_file_selection_set_filename() -#include // gtk_hbutton_box_new() -#include // gtk_hbox_new() -#include // gtk_label_new() -#include // gtk_init(), gtk_main(), gtk_main_quit() -#include // gtk_toggle_button_set_active(), (_get_) -#include // gtk_vbox_new() -#include // gtk_window_new() - -#include "conf.h" -#include "isofile.h" -#include "isocompress.h" // compressdesc[] -// #include "imagetype.h" // imagedata[].name -#include "multifile.h" // multinames[] -#include "tablerebuild.h" // IsoTableRebuild() -#include "devicebox.h" -#include "conversionbox.h" -#include "progressbox.h" -#include "messagebox.h" -#include "selectionbox.h" -#include "mainbox.h" - - -struct MainBoxData mainbox; - - -void MainBoxDestroy() { - if(mainbox.window != NULL) { - gtk_widget_destroy(mainbox.window); - mainbox.window = NULL; - mainbox.file = NULL; - mainbox.selectbutton = NULL; - mainbox.desc = NULL; - mainbox.startcheck = NULL; - mainbox.restartcheck = NULL; - mainbox.okbutton = NULL; - mainbox.devbutton = NULL; - mainbox.convbutton = NULL; - } // ENDIF- Do we have a Main Window still? -} // END MainBoxDestroy() - - -void MainBoxUnfocus() { - gtk_widget_set_sensitive(mainbox.file, FALSE); - gtk_widget_set_sensitive(mainbox.selectbutton, FALSE); - gtk_widget_set_sensitive(mainbox.startcheck, FALSE); - gtk_widget_set_sensitive(mainbox.restartcheck, FALSE); - gtk_widget_set_sensitive(mainbox.okbutton, FALSE); - gtk_widget_set_sensitive(mainbox.devbutton, FALSE); - gtk_widget_set_sensitive(mainbox.convbutton, FALSE); - gtk_window_iconify(GTK_WINDOW(mainbox.window)); -} // END MainBoxUnfocus() - - -gint MainBoxFileEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - int returnval; - char templine[256]; - struct IsoFile *tempfile; - - returnval = IsIsoFile(gtk_entry_get_text(GTK_ENTRY(mainbox.file))); - if(returnval == -1) { - gtk_label_set_text(GTK_LABEL(mainbox.desc), "File Type: ---"); - return(TRUE); - } // ENDIF- Not a name of any sort? - - if(returnval == -2) { - gtk_label_set_text(GTK_LABEL(mainbox.desc), "File Type: Not a file"); - return(TRUE); - } // ENDIF- Not a regular file? - - if(returnval == -3) { - gtk_label_set_text(GTK_LABEL(mainbox.desc), "File Type: Not a valid image file"); - return(TRUE); - } // ENDIF- Not an Image file? - - if(returnval == -4) { - gtk_label_set_text(GTK_LABEL(mainbox.desc), "File Type: Missing Table File (will rebuild)"); - return(TRUE); - } // ENDIF- Missing Compression seek table? - - tempfile = IsoFileOpenForRead(gtk_entry_get_text(GTK_ENTRY(mainbox.file))); - sprintf(templine, "File Type: %s%s%s", - multinames[tempfile->multi], - tempfile->imagename, - compressdesc[tempfile->compress]); - gtk_label_set_text(GTK_LABEL(mainbox.desc), templine); - tempfile = IsoFileClose(tempfile); - return(TRUE); -} // END MainBoxFileEvent() - - -void MainBoxRefocus() { - GdkEvent event; - - MainBoxFileEvent(NULL, event, NULL); - - gtk_widget_set_sensitive(mainbox.file, TRUE); - gtk_widget_set_sensitive(mainbox.selectbutton, TRUE); - gtk_widget_set_sensitive(mainbox.startcheck, TRUE); - gtk_widget_set_sensitive(mainbox.restartcheck, TRUE); - gtk_widget_set_sensitive(mainbox.okbutton, TRUE); - gtk_widget_set_sensitive(mainbox.devbutton, TRUE); - gtk_widget_set_sensitive(mainbox.convbutton, TRUE); - gtk_window_set_focus(GTK_WINDOW(mainbox.window), mainbox.file); - gtk_window_deiconify(GTK_WINDOW(mainbox.window)); -} // END MainBoxRefocus() - - -gint MainBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - mainbox.stop = 1; // Halt all long processess... - - MessageBoxDestroy(); - SelectionBoxDestroy(); - ProgressBoxDestroy(); - ConversionBoxDestroy(); - DeviceBoxDestroy(); - MainBoxDestroy(); - - gtk_main_quit(); - return(TRUE); -} // END MainBoxCancelEvent() - - -gint MainBoxOKEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - const char *tempisoname; - - MainBoxUnfocus(); - - tempisoname = gtk_entry_get_text(GTK_ENTRY(mainbox.file)); - if(*(tempisoname) != 0) { - if(IsIsoFile(tempisoname) == -4) { - IsoTableRebuild(tempisoname); - MainBoxRefocus(); - return(TRUE); - } // ENDIF- Do we need to rebuild an image file's index before using it? - - if(IsIsoFile(tempisoname) < 0) { - tempisoname = NULL; - MainBoxRefocus(); - MessageBoxShow("Not a Valid Image File.", 1); - return(TRUE); - } // ENDIF- Not an ISO file? Message and Stop here. - } // ENDIF- Is there an ISO file to check out? - - strcpy(conf.isoname, tempisoname); - tempisoname = NULL; - if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mainbox.startcheck)) == FALSE) { - conf.startconfigure = 0; // FALSE - } else { - conf.startconfigure = 1; // TRUE - } // ENDIF- Was this check button turned off? - if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mainbox.restartcheck)) == FALSE) { - conf.restartconfigure = 0; // FALSE - } else { - conf.restartconfigure = 1; // TRUE - } // ENDIF- Was this check button turned off? - - SaveConf(); - - MainBoxCancelEvent(widget, event, data); - return(TRUE); -} // END MainBoxOKEvent() - - -gint MainBoxBrowseEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - MainBoxUnfocus(); - - gtk_file_selection_set_filename(GTK_FILE_SELECTION(selectionbox.window), - gtk_entry_get_text(GTK_ENTRY(mainbox.file))); - selectionbox.wherefrom = 1; // From the Main Window - SelectionBoxRefocus(); - return(TRUE); -} // END MainBoxBrowseEvent() - - -gint MainBoxDeviceEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - MainBoxUnfocus(); - - gtk_entry_set_text(GTK_ENTRY(devicebox.file), - gtk_entry_get_text(GTK_ENTRY(mainbox.file))); - gtk_window_set_focus(GTK_WINDOW(devicebox.window), devicebox.file); - gtk_widget_show_all(devicebox.window); - return(TRUE); -} // END MainBoxBrowseEvent() - - -gint MainBoxConversionEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - MainBoxUnfocus(); - - gtk_entry_set_text(GTK_ENTRY(conversionbox.file), - gtk_entry_get_text(GTK_ENTRY(mainbox.file))); - gtk_window_set_focus(GTK_WINDOW(conversionbox.window), conversionbox.file); - gtk_widget_show_all(conversionbox.window); - return(TRUE); -} // END MainBoxBrowseEvent() - - -void MainBoxDisplay() { - GtkWidget *item; - GtkWidget *hbox1; - GtkWidget *vbox1; - - mainbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_container_set_border_width(GTK_CONTAINER(mainbox.window), 5); - gtk_window_set_title(GTK_WINDOW(mainbox.window), "CDVDisoEFP Configuration"); - gtk_window_set_position(GTK_WINDOW(mainbox.window), GTK_WIN_POS_CENTER); - - g_signal_connect(G_OBJECT(mainbox.window), "delete_event", - G_CALLBACK(MainBoxCancelEvent), NULL); - - vbox1 = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(mainbox.window), vbox1); - gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); - gtk_widget_show(vbox1); - - hbox1 = gtk_hbox_new(FALSE, 10); - gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); - gtk_widget_show(hbox1); - - item = gtk_label_new("Iso File:"); - gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); - gtk_widget_show(item); - item = NULL; - - mainbox.file = gtk_entry_new(); - gtk_box_pack_start(GTK_BOX(hbox1), mainbox.file, TRUE, TRUE, 0); - gtk_widget_show(mainbox.file); - g_signal_connect(G_OBJECT(mainbox.file), "changed", - G_CALLBACK(MainBoxFileEvent), NULL); - - mainbox.selectbutton = gtk_button_new_with_label("Browse"); - gtk_box_pack_start(GTK_BOX(hbox1), mainbox.selectbutton, FALSE, FALSE, 0); - gtk_widget_show(mainbox.selectbutton); - g_signal_connect(G_OBJECT(mainbox.selectbutton), "clicked", - G_CALLBACK(MainBoxBrowseEvent), NULL); - hbox1 = NULL; - - mainbox.desc = gtk_label_new("File Type: ---"); - gtk_box_pack_start(GTK_BOX(vbox1), mainbox.desc, FALSE, FALSE, 0); - gtk_widget_show(mainbox.desc); - - // hbox1 = gtk_hbox_new(FALSE, 10); - // gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); - // gtk_widget_show(hbox1); - - mainbox.startcheck = gtk_check_button_new_with_label("Show Configure screen when starting emulation"); - gtk_box_pack_start(GTK_BOX(vbox1), mainbox.startcheck, FALSE, FALSE, 0); - gtk_widget_show(mainbox.startcheck); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mainbox.startcheck), FALSE); - if(conf.startconfigure != 0) { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mainbox.startcheck), TRUE); - } // ENDIF- Is this box supposed to be checked? - - mainbox.restartcheck = gtk_check_button_new_with_label("Show Configure screen when restarting emulation"); - gtk_box_pack_start(GTK_BOX(vbox1), mainbox.restartcheck, FALSE, FALSE, 0); - gtk_widget_show(mainbox.restartcheck); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mainbox.restartcheck), FALSE); - if(conf.restartconfigure != 0) { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mainbox.restartcheck), TRUE); - } // ENDIF- Is this box supposed to be checked? - - hbox1 = gtk_hbutton_box_new(); - gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); - gtk_widget_show(hbox1); - - mainbox.okbutton = gtk_button_new_with_label("Ok"); - gtk_box_pack_start(GTK_BOX(hbox1), mainbox.okbutton, TRUE, TRUE, 0); - gtk_widget_show(mainbox.okbutton); - g_signal_connect(G_OBJECT(mainbox.okbutton), "clicked", - G_CALLBACK(MainBoxOKEvent), NULL); - - mainbox.devbutton = gtk_button_new_with_label("Get from Disc"); - gtk_box_pack_start(GTK_BOX(hbox1), mainbox.devbutton, TRUE, TRUE, 0); - gtk_widget_show(mainbox.devbutton); - g_signal_connect(G_OBJECT(mainbox.devbutton), "clicked", - G_CALLBACK(MainBoxDeviceEvent), NULL); - - mainbox.convbutton = gtk_button_new_with_label("Convert"); - gtk_box_pack_start(GTK_BOX(hbox1), mainbox.convbutton, TRUE, TRUE, 0); - gtk_widget_show(mainbox.convbutton); - g_signal_connect(G_OBJECT(mainbox.convbutton), "clicked", - G_CALLBACK(MainBoxConversionEvent), NULL); - - item = gtk_button_new_with_label("Cancel"); - gtk_box_pack_start(GTK_BOX(hbox1), item, TRUE, TRUE, 0); - gtk_widget_show(item); - g_signal_connect(G_OBJECT(item), "clicked", - G_CALLBACK(MainBoxCancelEvent), NULL); - item = NULL; - hbox1 = NULL; - vbox1 = NULL; - - // We held off setting the name until now... so description would show. - gtk_entry_set_text(GTK_ENTRY(mainbox.file), conf.isoname); -} // END MainBoxDisplay() +/* mainbox.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // sprintf() + +#include // strcpy() + + + +#include // gtk_button_new_with_label() + +#include // gtk_check_button_new_with_label() + +#include // gtk_container_add() + +#include // gtk_entry_new() + +#include // gtk_file_selection_set_filename() + +#include // gtk_hbutton_box_new() + +#include // gtk_hbox_new() + +#include // gtk_label_new() + +#include // gtk_init(), gtk_main(), gtk_main_quit() + +#include // gtk_toggle_button_set_active(), (_get_) + +#include // gtk_vbox_new() + +#include // gtk_window_new() + + + +#include "conf.h" + +#include "isofile.h" + +#include "isocompress.h" // compressdesc[] + +// #include "imagetype.h" // imagedata[].name + +#include "multifile.h" // multinames[] + +#include "tablerebuild.h" // IsoTableRebuild() + +#include "devicebox.h" + +#include "conversionbox.h" + +#include "progressbox.h" + +#include "messagebox.h" + +#include "selectionbox.h" + +#include "mainbox.h" + + + + + +struct MainBoxData mainbox; + + + + + +void MainBoxDestroy() { + + if(mainbox.window != NULL) { + + gtk_widget_destroy(mainbox.window); + + mainbox.window = NULL; + + mainbox.file = NULL; + + mainbox.selectbutton = NULL; + + mainbox.desc = NULL; + + mainbox.startcheck = NULL; + + mainbox.restartcheck = NULL; + + mainbox.okbutton = NULL; + + mainbox.devbutton = NULL; + + mainbox.convbutton = NULL; + + } // ENDIF- Do we have a Main Window still? + +} // END MainBoxDestroy() + + + + + +void MainBoxUnfocus() { + + gtk_widget_set_sensitive(mainbox.file, FALSE); + + gtk_widget_set_sensitive(mainbox.selectbutton, FALSE); + + gtk_widget_set_sensitive(mainbox.startcheck, FALSE); + + gtk_widget_set_sensitive(mainbox.restartcheck, FALSE); + + gtk_widget_set_sensitive(mainbox.okbutton, FALSE); + + gtk_widget_set_sensitive(mainbox.devbutton, FALSE); + + gtk_widget_set_sensitive(mainbox.convbutton, FALSE); + + gtk_window_iconify(GTK_WINDOW(mainbox.window)); + +} // END MainBoxUnfocus() + + + + + +gint MainBoxFileEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + int returnval; + + char templine[256]; + + struct IsoFile *tempfile; + + + + returnval = IsIsoFile(gtk_entry_get_text(GTK_ENTRY(mainbox.file))); + + if(returnval == -1) { + + gtk_label_set_text(GTK_LABEL(mainbox.desc), "File Type: ---"); + + return(TRUE); + + } // ENDIF- Not a name of any sort? + + + + if(returnval == -2) { + + gtk_label_set_text(GTK_LABEL(mainbox.desc), "File Type: Not a file"); + + return(TRUE); + + } // ENDIF- Not a regular file? + + + + if(returnval == -3) { + + gtk_label_set_text(GTK_LABEL(mainbox.desc), "File Type: Not a valid image file"); + + return(TRUE); + + } // ENDIF- Not an Image file? + + + + if(returnval == -4) { + + gtk_label_set_text(GTK_LABEL(mainbox.desc), "File Type: Missing Table File (will rebuild)"); + + return(TRUE); + + } // ENDIF- Missing Compression seek table? + + + + tempfile = IsoFileOpenForRead(gtk_entry_get_text(GTK_ENTRY(mainbox.file))); + + sprintf(templine, "File Type: %s%s%s", + + multinames[tempfile->multi], + + tempfile->imagename, + + compressdesc[tempfile->compress]); + + gtk_label_set_text(GTK_LABEL(mainbox.desc), templine); + + tempfile = IsoFileClose(tempfile); + + return(TRUE); + +} // END MainBoxFileEvent() + + + + + +void MainBoxRefocus() { + + GdkEvent event; + + + + MainBoxFileEvent(NULL, event, NULL); + + + + gtk_widget_set_sensitive(mainbox.file, TRUE); + + gtk_widget_set_sensitive(mainbox.selectbutton, TRUE); + + gtk_widget_set_sensitive(mainbox.startcheck, TRUE); + + gtk_widget_set_sensitive(mainbox.restartcheck, TRUE); + + gtk_widget_set_sensitive(mainbox.okbutton, TRUE); + + gtk_widget_set_sensitive(mainbox.devbutton, TRUE); + + gtk_widget_set_sensitive(mainbox.convbutton, TRUE); + + gtk_window_set_focus(GTK_WINDOW(mainbox.window), mainbox.file); + + gtk_window_deiconify(GTK_WINDOW(mainbox.window)); + +} // END MainBoxRefocus() + + + + + +gint MainBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + mainbox.stop = 1; // Halt all long processess... + + + + MessageBoxDestroy(); + + SelectionBoxDestroy(); + + ProgressBoxDestroy(); + + ConversionBoxDestroy(); + + DeviceBoxDestroy(); + + MainBoxDestroy(); + + + + gtk_main_quit(); + + return(TRUE); + +} // END MainBoxCancelEvent() + + + + + +gint MainBoxOKEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + const char *tempisoname; + + + + MainBoxUnfocus(); + + + + tempisoname = gtk_entry_get_text(GTK_ENTRY(mainbox.file)); + + if(*(tempisoname) != 0) { + + if(IsIsoFile(tempisoname) == -4) { + + IsoTableRebuild(tempisoname); + + MainBoxRefocus(); + + return(TRUE); + + } // ENDIF- Do we need to rebuild an image file's index before using it? + + + + if(IsIsoFile(tempisoname) < 0) { + + tempisoname = NULL; + + MainBoxRefocus(); + + MessageBoxShow("Not a Valid Image File.", 1); + + return(TRUE); + + } // ENDIF- Not an ISO file? Message and Stop here. + + } // ENDIF- Is there an ISO file to check out? + + + + strcpy(conf.isoname, tempisoname); + + tempisoname = NULL; + + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mainbox.startcheck)) == FALSE) { + + conf.startconfigure = 0; // FALSE + + } else { + + conf.startconfigure = 1; // TRUE + + } // ENDIF- Was this check button turned off? + + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mainbox.restartcheck)) == FALSE) { + + conf.restartconfigure = 0; // FALSE + + } else { + + conf.restartconfigure = 1; // TRUE + + } // ENDIF- Was this check button turned off? + + + + SaveConf(); + + + + MainBoxCancelEvent(widget, event, data); + + return(TRUE); + +} // END MainBoxOKEvent() + + + + + +gint MainBoxBrowseEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + MainBoxUnfocus(); + + + + gtk_file_selection_set_filename(GTK_FILE_SELECTION(selectionbox.window), + + gtk_entry_get_text(GTK_ENTRY(mainbox.file))); + + selectionbox.wherefrom = 1; // From the Main Window + + SelectionBoxRefocus(); + + return(TRUE); + +} // END MainBoxBrowseEvent() + + + + + +gint MainBoxDeviceEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + MainBoxUnfocus(); + + + + gtk_entry_set_text(GTK_ENTRY(devicebox.file), + + gtk_entry_get_text(GTK_ENTRY(mainbox.file))); + + gtk_window_set_focus(GTK_WINDOW(devicebox.window), devicebox.file); + + gtk_widget_show_all(devicebox.window); + + return(TRUE); + +} // END MainBoxBrowseEvent() + + + + + +gint MainBoxConversionEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + MainBoxUnfocus(); + + + + gtk_entry_set_text(GTK_ENTRY(conversionbox.file), + + gtk_entry_get_text(GTK_ENTRY(mainbox.file))); + + gtk_window_set_focus(GTK_WINDOW(conversionbox.window), conversionbox.file); + + gtk_widget_show_all(conversionbox.window); + + return(TRUE); + +} // END MainBoxBrowseEvent() + + + + + +void MainBoxDisplay() { + + GtkWidget *item; + + GtkWidget *hbox1; + + GtkWidget *vbox1; + + + + mainbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + gtk_container_set_border_width(GTK_CONTAINER(mainbox.window), 5); + + gtk_window_set_title(GTK_WINDOW(mainbox.window), "CDVDisoEFP Configuration"); + + gtk_window_set_position(GTK_WINDOW(mainbox.window), GTK_WIN_POS_CENTER); + + + + g_signal_connect(G_OBJECT(mainbox.window), "delete_event", + + G_CALLBACK(MainBoxCancelEvent), NULL); + + + + vbox1 = gtk_vbox_new(FALSE, 5); + + gtk_container_add(GTK_CONTAINER(mainbox.window), vbox1); + + gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); + + gtk_widget_show(vbox1); + + + + hbox1 = gtk_hbox_new(FALSE, 10); + + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + + gtk_widget_show(hbox1); + + + + item = gtk_label_new("Iso File:"); + + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + mainbox.file = gtk_entry_new(); + + gtk_box_pack_start(GTK_BOX(hbox1), mainbox.file, TRUE, TRUE, 0); + + gtk_widget_show(mainbox.file); + + g_signal_connect(G_OBJECT(mainbox.file), "changed", + + G_CALLBACK(MainBoxFileEvent), NULL); + + + + mainbox.selectbutton = gtk_button_new_with_label("Browse"); + + gtk_box_pack_start(GTK_BOX(hbox1), mainbox.selectbutton, FALSE, FALSE, 0); + + gtk_widget_show(mainbox.selectbutton); + + g_signal_connect(G_OBJECT(mainbox.selectbutton), "clicked", + + G_CALLBACK(MainBoxBrowseEvent), NULL); + + hbox1 = NULL; + + + + mainbox.desc = gtk_label_new("File Type: ---"); + + gtk_box_pack_start(GTK_BOX(vbox1), mainbox.desc, FALSE, FALSE, 0); + + gtk_widget_show(mainbox.desc); + + + + // hbox1 = gtk_hbox_new(FALSE, 10); + + // gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + + // gtk_widget_show(hbox1); + + + + mainbox.startcheck = gtk_check_button_new_with_label("Show Configure screen when starting emulation"); + + gtk_box_pack_start(GTK_BOX(vbox1), mainbox.startcheck, FALSE, FALSE, 0); + + gtk_widget_show(mainbox.startcheck); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mainbox.startcheck), FALSE); + + if(conf.startconfigure != 0) { + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mainbox.startcheck), TRUE); + + } // ENDIF- Is this box supposed to be checked? + + + + mainbox.restartcheck = gtk_check_button_new_with_label("Show Configure screen when restarting emulation"); + + gtk_box_pack_start(GTK_BOX(vbox1), mainbox.restartcheck, FALSE, FALSE, 0); + + gtk_widget_show(mainbox.restartcheck); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mainbox.restartcheck), FALSE); + + if(conf.restartconfigure != 0) { + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mainbox.restartcheck), TRUE); + + } // ENDIF- Is this box supposed to be checked? + + + + hbox1 = gtk_hbutton_box_new(); + + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + + gtk_widget_show(hbox1); + + + + mainbox.okbutton = gtk_button_new_with_label("Ok"); + + gtk_box_pack_start(GTK_BOX(hbox1), mainbox.okbutton, TRUE, TRUE, 0); + + gtk_widget_show(mainbox.okbutton); + + g_signal_connect(G_OBJECT(mainbox.okbutton), "clicked", + + G_CALLBACK(MainBoxOKEvent), NULL); + + + + mainbox.devbutton = gtk_button_new_with_label("Get from Disc"); + + gtk_box_pack_start(GTK_BOX(hbox1), mainbox.devbutton, TRUE, TRUE, 0); + + gtk_widget_show(mainbox.devbutton); + + g_signal_connect(G_OBJECT(mainbox.devbutton), "clicked", + + G_CALLBACK(MainBoxDeviceEvent), NULL); + + + + mainbox.convbutton = gtk_button_new_with_label("Convert"); + + gtk_box_pack_start(GTK_BOX(hbox1), mainbox.convbutton, TRUE, TRUE, 0); + + gtk_widget_show(mainbox.convbutton); + + g_signal_connect(G_OBJECT(mainbox.convbutton), "clicked", + + G_CALLBACK(MainBoxConversionEvent), NULL); + + + + item = gtk_button_new_with_label("Cancel"); + + gtk_box_pack_start(GTK_BOX(hbox1), item, TRUE, TRUE, 0); + + gtk_widget_show(item); + + g_signal_connect(G_OBJECT(item), "clicked", + + G_CALLBACK(MainBoxCancelEvent), NULL); + + item = NULL; + + hbox1 = NULL; + + vbox1 = NULL; + + + + // We held off setting the name until now... so description would show. + + gtk_entry_set_text(GTK_ENTRY(mainbox.file), conf.isoname); + +} // END MainBoxDisplay() + diff --git a/plugins/CDVDisoEFP/src/Linux/messagebox.c b/plugins/CDVDisoEFP/src/Linux/messagebox.c index 845aba31e8..a8145ecb25 100644 --- a/plugins/CDVDisoEFP/src/Linux/messagebox.c +++ b/plugins/CDVDisoEFP/src/Linux/messagebox.c @@ -1,113 +1,226 @@ -/* messagebox.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // NULL - -#include // gtk_button_new_with_label() -#include // gtk_hbutton_box_new() -#include // gtk_label_new() -#include // gtk_init(), gtk_main(), gtk_main_quit() -#include // gtk_vbox_new() -#include // gtk_window_new() - -#include "mainbox.h" -#include "devicebox.h" -#include "conversionbox.h" -#include "messagebox.h" - - -struct MessageBoxData messagebox; - - -void MessageBoxDestroy() { - if(messagebox.window != NULL) { - gtk_widget_destroy(messagebox.window); - messagebox.window = NULL; - messagebox.desc = NULL; - } // ENDIF- Do we have a Main Window still? -} // END MessageBoxDestroy() - - -void MessageBoxShow(char *message, int wherefrom) { - gtk_label_set_text(GTK_LABEL(messagebox.desc), message); - messagebox.wherefrom = wherefrom; - - gtk_widget_show_all(messagebox.window); - gtk_window_deiconify(GTK_WINDOW(messagebox.window)); -} // END MessageBox() - - -gint MessageBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - gtk_widget_hide(messagebox.window); - - switch(messagebox.wherefrom) { - case 1: - MainBoxRefocus(); - break; - case 2: - DeviceBoxRefocus(); - break; - case 3: - ConversionBoxRefocus(); - break; - } // ENDSWITCH- Whose window do I get to re-focus when this is done? - - return(TRUE); -} // END MessageBoxCancelEvent() - - -void MessageBoxDisplay() { - GtkWidget *item; - GtkWidget *hbox1; - GtkWidget *vbox1; - - messagebox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_container_set_border_width(GTK_CONTAINER(messagebox.window), 5); - gtk_window_set_title(GTK_WINDOW(messagebox.window), "CDVDisoEFP"); - gtk_window_set_position(GTK_WINDOW(messagebox.window), GTK_WIN_POS_CENTER); - gtk_window_set_resizable(GTK_WINDOW(messagebox.window), FALSE); - - g_signal_connect(G_OBJECT(messagebox.window), "delete_event", - G_CALLBACK(MessageBoxCancelEvent), NULL); - - vbox1 = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(messagebox.window), vbox1); - gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); - gtk_widget_show(vbox1); - - messagebox.desc = gtk_label_new("Hi There!\r\nHow are you doing?"); - gtk_box_pack_start(GTK_BOX(vbox1), messagebox.desc, FALSE, FALSE, 0); - gtk_widget_show(messagebox.desc); - - hbox1 = gtk_hbutton_box_new(); - gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); - gtk_widget_show(hbox1); - - item = gtk_button_new_with_label("Cancel"); - gtk_box_pack_start(GTK_BOX(hbox1), item, TRUE, TRUE, 0); - GTK_WIDGET_SET_FLAGS(item, GTK_CAN_DEFAULT); - gtk_widget_show(item); - g_signal_connect(G_OBJECT(item), "clicked", - G_CALLBACK(MessageBoxCancelEvent), NULL); - item = NULL; - hbox1 = NULL; - vbox1 = NULL; -} // END MessageBoxDisplay() +/* messagebox.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + + + +#include // gtk_button_new_with_label() + +#include // gtk_hbutton_box_new() + +#include // gtk_label_new() + +#include // gtk_init(), gtk_main(), gtk_main_quit() + +#include // gtk_vbox_new() + +#include // gtk_window_new() + + + +#include "mainbox.h" + +#include "devicebox.h" + +#include "conversionbox.h" + +#include "messagebox.h" + + + + + +struct MessageBoxData messagebox; + + + + + +void MessageBoxDestroy() { + + if(messagebox.window != NULL) { + + gtk_widget_destroy(messagebox.window); + + messagebox.window = NULL; + + messagebox.desc = NULL; + + } // ENDIF- Do we have a Main Window still? + +} // END MessageBoxDestroy() + + + + + +void MessageBoxShow(char *message, int wherefrom) { + + gtk_label_set_text(GTK_LABEL(messagebox.desc), message); + + messagebox.wherefrom = wherefrom; + + + + gtk_widget_show_all(messagebox.window); + + gtk_window_deiconify(GTK_WINDOW(messagebox.window)); + +} // END MessageBox() + + + + + +gint MessageBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + gtk_widget_hide(messagebox.window); + + + + switch(messagebox.wherefrom) { + + case 1: + + MainBoxRefocus(); + + break; + + case 2: + + DeviceBoxRefocus(); + + break; + + case 3: + + ConversionBoxRefocus(); + + break; + + } // ENDSWITCH- Whose window do I get to re-focus when this is done? + + + + return(TRUE); + +} // END MessageBoxCancelEvent() + + + + + +void MessageBoxDisplay() { + + GtkWidget *item; + + GtkWidget *hbox1; + + GtkWidget *vbox1; + + + + messagebox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + gtk_container_set_border_width(GTK_CONTAINER(messagebox.window), 5); + + gtk_window_set_title(GTK_WINDOW(messagebox.window), "CDVDisoEFP"); + + gtk_window_set_position(GTK_WINDOW(messagebox.window), GTK_WIN_POS_CENTER); + + gtk_window_set_resizable(GTK_WINDOW(messagebox.window), FALSE); + + + + g_signal_connect(G_OBJECT(messagebox.window), "delete_event", + + G_CALLBACK(MessageBoxCancelEvent), NULL); + + + + vbox1 = gtk_vbox_new(FALSE, 5); + + gtk_container_add(GTK_CONTAINER(messagebox.window), vbox1); + + gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); + + gtk_widget_show(vbox1); + + + + messagebox.desc = gtk_label_new("Hi There!\r\nHow are you doing?"); + + gtk_box_pack_start(GTK_BOX(vbox1), messagebox.desc, FALSE, FALSE, 0); + + gtk_widget_show(messagebox.desc); + + + + hbox1 = gtk_hbutton_box_new(); + + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + + gtk_widget_show(hbox1); + + + + item = gtk_button_new_with_label("Cancel"); + + gtk_box_pack_start(GTK_BOX(hbox1), item, TRUE, TRUE, 0); + + GTK_WIDGET_SET_FLAGS(item, GTK_CAN_DEFAULT); + + gtk_widget_show(item); + + g_signal_connect(G_OBJECT(item), "clicked", + + G_CALLBACK(MessageBoxCancelEvent), NULL); + + item = NULL; + + hbox1 = NULL; + + vbox1 = NULL; + +} // END MessageBoxDisplay() + diff --git a/plugins/CDVDisoEFP/src/Linux/progressbox.c b/plugins/CDVDisoEFP/src/Linux/progressbox.c index 10fd1733b8..2c497053c1 100644 --- a/plugins/CDVDisoEFP/src/Linux/progressbox.c +++ b/plugins/CDVDisoEFP/src/Linux/progressbox.c @@ -1,144 +1,288 @@ -/* progressbox.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // NULL -#include // sprintf() -#include // off64_t - -#include // gtk_button_new_with_label() -#include // gtk_container_add() -#include // gtk_file_selection_set_filename() -#include // gtk_hbutton_box_new() -#include // gtk_hbox_new() -#include // gtk_label_new() -#include // gtk_main_iteration(), gtk_events_pending() -#include // gtk_progress_bar_new() -#include // gtk_vbox_new() -#include // gtk_window_new() - -#include "progressbox.h" - - -struct ProgressBoxData progressbox; -char progressboxline[256]; - - -void ProgressBoxDestroy() { - if(progressbox.window != NULL) { - gtk_widget_destroy(progressbox.window); - progressbox.window = NULL; - progressbox.desc = NULL; - } // ENDIF- Do we have a Main Window still? -} // END ProgressBoxDestroy() - - -void ProgressBoxStart(char *description, off64_t maximum) { - gtk_label_set_text(GTK_LABEL(progressbox.desc), description); - - progressbox.max = maximum; - progressbox.gmax = maximum; - progressbox.lastpct = 100; - progressbox.stop = 0; - - ProgressBoxTick(0); - gtk_widget_show_all(progressbox.window); - gtk_window_deiconify(GTK_WINDOW(progressbox.window)); -} // END ProgressBoxStart() - - -void ProgressBoxTick(off64_t current) { - gdouble gcur; - off64_t thispct; - - gcur = current; - gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressbox.bar), - gcur / progressbox.gmax); - - sprintf(progressboxline, "%llu of %llu", current, progressbox.max); - gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progressbox.bar), progressboxline); - - if(progressbox.max >= 100) { - thispct = current / ( progressbox.max / 100 ); - if(thispct != progressbox.lastpct) { - sprintf(progressboxline, "%llu%% CDVDisoEFP Progress", thispct); - gtk_window_set_title(GTK_WINDOW(progressbox.window), progressboxline); - progressbox.lastpct = thispct; - } // ENDIF- Change in percentage? (Avoiding title flicker) - } // ENDIF- Our maximum # over 100? (Avoiding divide-by-zero error) - - while(gtk_events_pending()) gtk_main_iteration(); // Give time for window to redraw. -} // END ProgressBoxTick() - - -void ProgressBoxStop() { - gtk_widget_hide(progressbox.window); - gtk_window_set_title(GTK_WINDOW(progressbox.window), "CDVDisoEFP Progress"); -} // END ProgressBoxStop() - - -gint ProgressBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - progressbox.stop = 1; - - return(TRUE); -} // END ProgressBoxCancelEvent() - - -void ProgressBoxDisplay() { - GtkWidget *item; - GtkWidget *hbox1; - GtkWidget *vbox1; - - progressbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_container_set_border_width(GTK_CONTAINER(progressbox.window), 5); - gtk_window_set_title(GTK_WINDOW(progressbox.window), "CDVDisoEFP Progress"); - gtk_window_set_position(GTK_WINDOW(progressbox.window), GTK_WIN_POS_CENTER); - gtk_window_set_resizable(GTK_WINDOW(progressbox.window), FALSE); - - g_signal_connect(G_OBJECT(progressbox.window), "delete_event", - G_CALLBACK(ProgressBoxCancelEvent), NULL); - - vbox1 = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(progressbox.window), vbox1); - gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); - gtk_widget_show(vbox1); - - progressbox.desc = gtk_label_new("Twiddling Thumbs"); - gtk_box_pack_start(GTK_BOX(vbox1), progressbox.desc, FALSE, FALSE, 0); - gtk_widget_show(progressbox.desc); - - progressbox.bar = gtk_progress_bar_new(); - gtk_box_pack_start(GTK_BOX(vbox1), progressbox.bar, FALSE, FALSE, 0); - gtk_widget_show(progressbox.bar); - - hbox1 = gtk_hbutton_box_new(); - gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); - gtk_widget_show(hbox1); - - item = gtk_button_new_with_label("Cancel"); - gtk_box_pack_start(GTK_BOX(hbox1), item, TRUE, TRUE, 0); - GTK_WIDGET_SET_FLAGS(item, GTK_CAN_DEFAULT); - gtk_widget_show(item); - g_signal_connect(G_OBJECT(item), "clicked", - G_CALLBACK(ProgressBoxCancelEvent), NULL); - item = NULL; - hbox1 = NULL; - vbox1 = NULL; -} // END ProgressBoxDisplay() +/* progressbox.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // sprintf() + +#include // off64_t + + + +#include // gtk_button_new_with_label() + +#include // gtk_container_add() + +#include // gtk_file_selection_set_filename() + +#include // gtk_hbutton_box_new() + +#include // gtk_hbox_new() + +#include // gtk_label_new() + +#include // gtk_main_iteration(), gtk_events_pending() + +#include // gtk_progress_bar_new() + +#include // gtk_vbox_new() + +#include // gtk_window_new() + + + +#include "progressbox.h" + + + + + +struct ProgressBoxData progressbox; + +char progressboxline[256]; + + + + + +void ProgressBoxDestroy() { + + if(progressbox.window != NULL) { + + gtk_widget_destroy(progressbox.window); + + progressbox.window = NULL; + + progressbox.desc = NULL; + + } // ENDIF- Do we have a Main Window still? + +} // END ProgressBoxDestroy() + + + + + +void ProgressBoxStart(char *description, off64_t maximum) { + + gtk_label_set_text(GTK_LABEL(progressbox.desc), description); + + + + progressbox.max = maximum; + + progressbox.gmax = maximum; + + progressbox.lastpct = 100; + + progressbox.stop = 0; + + + + ProgressBoxTick(0); + + gtk_widget_show_all(progressbox.window); + + gtk_window_deiconify(GTK_WINDOW(progressbox.window)); + +} // END ProgressBoxStart() + + + + + +void ProgressBoxTick(off64_t current) { + + gdouble gcur; + + off64_t thispct; + + + + gcur = current; + + gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressbox.bar), + + gcur / progressbox.gmax); + + + + sprintf(progressboxline, "%llu of %llu", current, progressbox.max); + + gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progressbox.bar), progressboxline); + + + + if(progressbox.max >= 100) { + + thispct = current / ( progressbox.max / 100 ); + + if(thispct != progressbox.lastpct) { + + sprintf(progressboxline, "%llu%% CDVDisoEFP Progress", thispct); + + gtk_window_set_title(GTK_WINDOW(progressbox.window), progressboxline); + + progressbox.lastpct = thispct; + + } // ENDIF- Change in percentage? (Avoiding title flicker) + + } // ENDIF- Our maximum # over 100? (Avoiding divide-by-zero error) + + + + while(gtk_events_pending()) gtk_main_iteration(); // Give time for window to redraw. + +} // END ProgressBoxTick() + + + + + +void ProgressBoxStop() { + + gtk_widget_hide(progressbox.window); + + gtk_window_set_title(GTK_WINDOW(progressbox.window), "CDVDisoEFP Progress"); + +} // END ProgressBoxStop() + + + + + +gint ProgressBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + progressbox.stop = 1; + + + + return(TRUE); + +} // END ProgressBoxCancelEvent() + + + + + +void ProgressBoxDisplay() { + + GtkWidget *item; + + GtkWidget *hbox1; + + GtkWidget *vbox1; + + + + progressbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + gtk_container_set_border_width(GTK_CONTAINER(progressbox.window), 5); + + gtk_window_set_title(GTK_WINDOW(progressbox.window), "CDVDisoEFP Progress"); + + gtk_window_set_position(GTK_WINDOW(progressbox.window), GTK_WIN_POS_CENTER); + + gtk_window_set_resizable(GTK_WINDOW(progressbox.window), FALSE); + + + + g_signal_connect(G_OBJECT(progressbox.window), "delete_event", + + G_CALLBACK(ProgressBoxCancelEvent), NULL); + + + + vbox1 = gtk_vbox_new(FALSE, 5); + + gtk_container_add(GTK_CONTAINER(progressbox.window), vbox1); + + gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); + + gtk_widget_show(vbox1); + + + + progressbox.desc = gtk_label_new("Twiddling Thumbs"); + + gtk_box_pack_start(GTK_BOX(vbox1), progressbox.desc, FALSE, FALSE, 0); + + gtk_widget_show(progressbox.desc); + + + + progressbox.bar = gtk_progress_bar_new(); + + gtk_box_pack_start(GTK_BOX(vbox1), progressbox.bar, FALSE, FALSE, 0); + + gtk_widget_show(progressbox.bar); + + + + hbox1 = gtk_hbutton_box_new(); + + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + + gtk_widget_show(hbox1); + + + + item = gtk_button_new_with_label("Cancel"); + + gtk_box_pack_start(GTK_BOX(hbox1), item, TRUE, TRUE, 0); + + GTK_WIDGET_SET_FLAGS(item, GTK_CAN_DEFAULT); + + gtk_widget_show(item); + + g_signal_connect(G_OBJECT(item), "clicked", + + G_CALLBACK(ProgressBoxCancelEvent), NULL); + + item = NULL; + + hbox1 = NULL; + + vbox1 = NULL; + +} // END ProgressBoxDisplay() + diff --git a/plugins/CDVDisoEFP/src/Linux/selectionbox.c b/plugins/CDVDisoEFP/src/Linux/selectionbox.c index a33a55944f..01a04f48e0 100644 --- a/plugins/CDVDisoEFP/src/Linux/selectionbox.c +++ b/plugins/CDVDisoEFP/src/Linux/selectionbox.c @@ -1,102 +1,204 @@ -/* selectionbox.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // NULL - -#include // g_signal_connect() -#include // gtk_entry_set_text() -#include // gtk_file_selection_new() - -#include "devicebox.h" -#include "conversionbox.h" -#include "selectionbox.h" -#include "mainbox.h" - - -struct SelectionBoxData selectionbox; - - -void SelectionBoxDestroy() { - if(selectionbox.window != NULL) { - gtk_widget_destroy(selectionbox.window); - selectionbox.window = NULL; - } // ENDIF- Do we have a Main Window still? -} // END SelectionBoxDestroy() - - -void SelectionBoxRefresh() { -} // END SelectionBoxRefresh() - - -void SelectionBoxUnfocus() { - gtk_widget_hide(selectionbox.window); -} // END SelectionBoxUnfocus() - - -void SelectionBoxRefocus() { - gtk_widget_show(selectionbox.window); -} // END SelectionBoxRefocus() - - -gint SelectionBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - SelectionBoxUnfocus(); - switch(selectionbox.wherefrom) { - case 1: - gtk_entry_set_text(GTK_ENTRY(mainbox.file), - gtk_file_selection_get_filename(GTK_FILE_SELECTION(selectionbox.window))); - MainBoxRefocus(); - break; - case 2: - gtk_entry_set_text(GTK_ENTRY(devicebox.file), - gtk_file_selection_get_filename(GTK_FILE_SELECTION(selectionbox.window))); - DeviceBoxRefocus(); - break; - case 3: - gtk_entry_set_text(GTK_ENTRY(conversionbox.file), - gtk_file_selection_get_filename(GTK_FILE_SELECTION(selectionbox.window))); - ConversionBoxRefocus(); - break; - } // ENDSWITCH wherefrom- What Box called us? - return(TRUE); -} // END SelectionBoxCancelEvent() - - -gint SelectionBoxOKEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - // Validate listed file(?) - - // Transfer file name to calling window? - - SelectionBoxCancelEvent(widget, event, data); - return(TRUE); -} // END SelectionBoxOKEvent() - - -void SelectionBoxDisplay() { - selectionbox.window = gtk_file_selection_new("Select an ISO file"); - g_signal_connect(G_OBJECT(selectionbox.window), "delete_event", - G_CALLBACK(SelectionBoxCancelEvent), NULL); - g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(selectionbox.window)->ok_button), - "clicked", G_CALLBACK(SelectionBoxOKEvent), NULL); - g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(selectionbox.window)->cancel_button), - "clicked", G_CALLBACK(SelectionBoxCancelEvent), NULL); - - selectionbox.wherefrom = 0; // Called by no one... yet. -} // END SelectionBoxDisplay() +/* selectionbox.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + + + +#include // g_signal_connect() + +#include // gtk_entry_set_text() + +#include // gtk_file_selection_new() + + + +#include "devicebox.h" + +#include "conversionbox.h" + +#include "selectionbox.h" + +#include "mainbox.h" + + + + + +struct SelectionBoxData selectionbox; + + + + + +void SelectionBoxDestroy() { + + if(selectionbox.window != NULL) { + + gtk_widget_destroy(selectionbox.window); + + selectionbox.window = NULL; + + } // ENDIF- Do we have a Main Window still? + +} // END SelectionBoxDestroy() + + + + + +void SelectionBoxRefresh() { + +} // END SelectionBoxRefresh() + + + + + +void SelectionBoxUnfocus() { + + gtk_widget_hide(selectionbox.window); + +} // END SelectionBoxUnfocus() + + + + + +void SelectionBoxRefocus() { + + gtk_widget_show(selectionbox.window); + +} // END SelectionBoxRefocus() + + + + + +gint SelectionBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + SelectionBoxUnfocus(); + + switch(selectionbox.wherefrom) { + + case 1: + + gtk_entry_set_text(GTK_ENTRY(mainbox.file), + + gtk_file_selection_get_filename(GTK_FILE_SELECTION(selectionbox.window))); + + MainBoxRefocus(); + + break; + + case 2: + + gtk_entry_set_text(GTK_ENTRY(devicebox.file), + + gtk_file_selection_get_filename(GTK_FILE_SELECTION(selectionbox.window))); + + DeviceBoxRefocus(); + + break; + + case 3: + + gtk_entry_set_text(GTK_ENTRY(conversionbox.file), + + gtk_file_selection_get_filename(GTK_FILE_SELECTION(selectionbox.window))); + + ConversionBoxRefocus(); + + break; + + } // ENDSWITCH wherefrom- What Box called us? + + return(TRUE); + +} // END SelectionBoxCancelEvent() + + + + + +gint SelectionBoxOKEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + // Validate listed file(?) + + + + // Transfer file name to calling window? + + + + SelectionBoxCancelEvent(widget, event, data); + + return(TRUE); + +} // END SelectionBoxOKEvent() + + + + + +void SelectionBoxDisplay() { + + selectionbox.window = gtk_file_selection_new("Select an ISO file"); + + g_signal_connect(G_OBJECT(selectionbox.window), "delete_event", + + G_CALLBACK(SelectionBoxCancelEvent), NULL); + + g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(selectionbox.window)->ok_button), + + "clicked", G_CALLBACK(SelectionBoxOKEvent), NULL); + + g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(selectionbox.window)->cancel_button), + + "clicked", G_CALLBACK(SelectionBoxCancelEvent), NULL); + + + + selectionbox.wherefrom = 0; // Called by no one... yet. + +} // END SelectionBoxDisplay() + diff --git a/plugins/CDVDisoEFP/src/Linux/tablerebuild.c b/plugins/CDVDisoEFP/src/Linux/tablerebuild.c index 3d913ecee2..99a67aa148 100644 --- a/plugins/CDVDisoEFP/src/Linux/tablerebuild.c +++ b/plugins/CDVDisoEFP/src/Linux/tablerebuild.c @@ -1,190 +1,380 @@ -/* tablerebuild.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // NULL -#include // sprintf() -#include // malloc() - -// #include // gtk_main_iteration() - -#include "mainbox.h" -#include "progressbox.h" -#include "isofile.h" -#include "multifile.h" -#include "isocompress.h" // CompressClose() -#include "gzipv1.h" -#include "gzipv2.h" -#include "bzip2v2.h" -#include "bzip2v3.h" -#include "actualfile.h" // ACTUALHANDLENULL - - -void IsoTableRebuild(const char *filename) { - struct IsoFile *datafile; - struct IsoFile *tablefile; - int retval; - char tempblock[65536]; - int stop; - - struct TableData table; - - datafile = IsoFileOpenForRead(filename); - - // Note: This is the start of the "Multifile" process. It's commented - // out so at least we can rebuild 1 part of a multifile at a time. - // IsoNameStripExt(datafile); - // IsoNameStripMulti(datafile); - - // Prep tablefile to hold ONLY a table (no data) - tablefile = (struct IsoFile *) malloc(sizeof(struct IsoFile)); - if(tablefile == NULL) { - datafile = IsoFileClose(datafile); - return; - } // ENDIF- Failed to allocate? Abort. - - tablefile->sectorpos = 0; - tablefile->openforread = 0; - tablefile->filebytepos = 0; - tablefile->filebytesize = 0; - tablefile->filesectorpos = 0; - tablefile->filesectorsize = 0; - tablefile->handle = ACTUALHANDLENULL; - - tablefile->namepos = 0; - while((tablefile->namepos < 255) && - (*(filename + tablefile->namepos) != 0)) { - tablefile->name[tablefile->namepos] = *(filename + tablefile->namepos); - tablefile->namepos++; - } // ENDWHILE- Copying file name into tablefile - tablefile->name[tablefile->namepos] = 0; // And 0-terminate. - - tablefile->imageheader = datafile->imageheader; - tablefile->blocksize = datafile->blocksize; - tablefile->blockoffset = datafile->blockoffset; - tablefile->cdvdtype = 0; // Not important right now. - - tablefile->compress = datafile->compress; - tablefile->compresspos = datafile->compresspos; - tablefile->numsectors = datafile->numsectors; - tablefile->tabledata = NULL; - - switch(tablefile->compress) { - case 1: - retval = GZipV1OpenTableForWrite(tablefile); - break; - case 2: - retval = -1; - break; - case 3: - retval = GZipV2OpenTableForWrite(tablefile); - break; - case 4: - retval = BZip2V2OpenTableForWrite(tablefile); - break; - case 5: - retval = BZip2V3OpenTableForWrite(tablefile); - break; - default: - retval = -1; - break; - } // ENDSWITCH compress- Which table are we writing out? - if(retval < 0) { - datafile = IsoFileClose(datafile); - return; - } // ENDIF- Failed to open table file? Abort - - sprintf(tempblock, "Rebuilding table for %s", datafile->name); - ProgressBoxStart(tempblock, datafile->filebytesize); - - stop = 0; - mainbox.stop = 0; - progressbox.stop = 0; - while((stop == 0) && (datafile->filebytepos < datafile->filebytesize)) { - switch(datafile->compress) { - case 1: - retval = GZipV1Read(datafile, 0, tempblock); - break; - case 2: - retval = -1; - break; - case 3: - retval = GZipV2Read(datafile, 0, tempblock); - break; - case 4: - retval = BZip2V2Read(datafile, 0, tempblock); - break; - case 5: - retval = BZip2V3Read(datafile, 0, tempblock); - break; - default: - retval = -1; - break; - } // ENDSWITCH compress- Scanning for the next complete compressed block - - if(retval <= 0) { -#ifdef FUNCTION_WARNING_TABLEREBUILD - PrintLog("CDVDiso rebuild: failed to decompress - data corrupt"); -#endif /* FUNCTION_WARNING_TABLEREBUILD */ - stop = 1; - } else { - table.offset = datafile->filebytepos - retval; - table.size = retval; - switch(tablefile->compress) { - case 1: - retval = GZipV1WriteTable(tablefile, table); - break; - case 2: - retval = -1; - break; - case 3: - retval = GZipV2WriteTable(tablefile, table); - break; - case 4: - retval = BZip2V2WriteTable(tablefile, table); - break; - case 5: - retval = BZip2V3WriteTable(tablefile, table); - break; - default: - retval = -1; - break; - } // ENDSWITCH compress- Writing out the relavent table facts - if(retval < 0) stop = 1; - } // ENDIF- Do we have a valid record to write an entry for? - - ProgressBoxTick(datafile->filebytepos); - // while(gtk_events_pending()) gtk_main_iteration(); - - if(mainbox.stop != 0) stop = 2; - if(progressbox.stop != 0) stop = 2; - } // ENDWHILE- Read in the data file and writing a table, 1 block at a time - - ProgressBoxStop(); - - CompressClose(tablefile); // Guarentee the table is flushed and closed. - if(stop != 0) { - ActualFileDelete(tablefile->tablename); - } // ENDIF- Aborted or trouble? Delete the table file - tablefile = IsoFileClose(tablefile); - datafile = IsoFileClose(datafile); - - return; -} // END IsoTableRebuild() +/* tablerebuild.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // sprintf() + +#include // malloc() + + + +// #include // gtk_main_iteration() + + + +#include "mainbox.h" + +#include "progressbox.h" + +#include "isofile.h" + +#include "multifile.h" + +#include "isocompress.h" // CompressClose() + +#include "gzipv1.h" + +#include "gzipv2.h" + +#include "bzip2v2.h" + +#include "bzip2v3.h" + +#include "actualfile.h" // ACTUALHANDLENULL + + + + + +void IsoTableRebuild(const char *filename) { + + struct IsoFile *datafile; + + struct IsoFile *tablefile; + + int retval; + + char tempblock[65536]; + + int stop; + + + + struct TableData table; + + + + datafile = IsoFileOpenForRead(filename); + + + + // Note: This is the start of the "Multifile" process. It's commented + + // out so at least we can rebuild 1 part of a multifile at a time. + + // IsoNameStripExt(datafile); + + // IsoNameStripMulti(datafile); + + + + // Prep tablefile to hold ONLY a table (no data) + + tablefile = (struct IsoFile *) malloc(sizeof(struct IsoFile)); + + if(tablefile == NULL) { + + datafile = IsoFileClose(datafile); + + return; + + } // ENDIF- Failed to allocate? Abort. + + + + tablefile->sectorpos = 0; + + tablefile->openforread = 0; + + tablefile->filebytepos = 0; + + tablefile->filebytesize = 0; + + tablefile->filesectorpos = 0; + + tablefile->filesectorsize = 0; + + tablefile->handle = ACTUALHANDLENULL; + + + + tablefile->namepos = 0; + + while((tablefile->namepos < 255) && + + (*(filename + tablefile->namepos) != 0)) { + + tablefile->name[tablefile->namepos] = *(filename + tablefile->namepos); + + tablefile->namepos++; + + } // ENDWHILE- Copying file name into tablefile + + tablefile->name[tablefile->namepos] = 0; // And 0-terminate. + + + + tablefile->imageheader = datafile->imageheader; + + tablefile->blocksize = datafile->blocksize; + + tablefile->blockoffset = datafile->blockoffset; + + tablefile->cdvdtype = 0; // Not important right now. + + + + tablefile->compress = datafile->compress; + + tablefile->compresspos = datafile->compresspos; + + tablefile->numsectors = datafile->numsectors; + + tablefile->tabledata = NULL; + + + + switch(tablefile->compress) { + + case 1: + + retval = GZipV1OpenTableForWrite(tablefile); + + break; + + case 2: + + retval = -1; + + break; + + case 3: + + retval = GZipV2OpenTableForWrite(tablefile); + + break; + + case 4: + + retval = BZip2V2OpenTableForWrite(tablefile); + + break; + + case 5: + + retval = BZip2V3OpenTableForWrite(tablefile); + + break; + + default: + + retval = -1; + + break; + + } // ENDSWITCH compress- Which table are we writing out? + + if(retval < 0) { + + datafile = IsoFileClose(datafile); + + return; + + } // ENDIF- Failed to open table file? Abort + + + + sprintf(tempblock, "Rebuilding table for %s", datafile->name); + + ProgressBoxStart(tempblock, datafile->filebytesize); + + + + stop = 0; + + mainbox.stop = 0; + + progressbox.stop = 0; + + while((stop == 0) && (datafile->filebytepos < datafile->filebytesize)) { + + switch(datafile->compress) { + + case 1: + + retval = GZipV1Read(datafile, 0, tempblock); + + break; + + case 2: + + retval = -1; + + break; + + case 3: + + retval = GZipV2Read(datafile, 0, tempblock); + + break; + + case 4: + + retval = BZip2V2Read(datafile, 0, tempblock); + + break; + + case 5: + + retval = BZip2V3Read(datafile, 0, tempblock); + + break; + + default: + + retval = -1; + + break; + + } // ENDSWITCH compress- Scanning for the next complete compressed block + + + + if(retval <= 0) { + +#ifdef FUNCTION_WARNING_TABLEREBUILD + + PrintLog("CDVDiso rebuild: failed to decompress - data corrupt"); + +#endif /* FUNCTION_WARNING_TABLEREBUILD */ + + stop = 1; + + } else { + + table.offset = datafile->filebytepos - retval; + + table.size = retval; + + switch(tablefile->compress) { + + case 1: + + retval = GZipV1WriteTable(tablefile, table); + + break; + + case 2: + + retval = -1; + + break; + + case 3: + + retval = GZipV2WriteTable(tablefile, table); + + break; + + case 4: + + retval = BZip2V2WriteTable(tablefile, table); + + break; + + case 5: + + retval = BZip2V3WriteTable(tablefile, table); + + break; + + default: + + retval = -1; + + break; + + } // ENDSWITCH compress- Writing out the relavent table facts + + if(retval < 0) stop = 1; + + } // ENDIF- Do we have a valid record to write an entry for? + + + + ProgressBoxTick(datafile->filebytepos); + + // while(gtk_events_pending()) gtk_main_iteration(); + + + + if(mainbox.stop != 0) stop = 2; + + if(progressbox.stop != 0) stop = 2; + + } // ENDWHILE- Read in the data file and writing a table, 1 block at a time + + + + ProgressBoxStop(); + + + + CompressClose(tablefile); // Guarentee the table is flushed and closed. + + if(stop != 0) { + + ActualFileDelete(tablefile->tablename); + + } // ENDIF- Aborted or trouble? Delete the table file + + tablefile = IsoFileClose(tablefile); + + datafile = IsoFileClose(datafile); + + + + return; + +} // END IsoTableRebuild() + diff --git a/plugins/CDVDisoEFP/src/PS2Edefs.h b/plugins/CDVDisoEFP/src/PS2Edefs.h index 620a7c87fc..8bf1cc0c93 100644 --- a/plugins/CDVDisoEFP/src/PS2Edefs.h +++ b/plugins/CDVDisoEFP/src/PS2Edefs.h @@ -1,812 +1,812 @@ -#ifndef __PS2EDEFS_H__ -#define __PS2EDEFS_H__ - -/* - * PS2E Definitions v0.6.2 (beta) - * - * Author: linuzappz@hotmail.com - * shadowpcsx2@yahoo.gr - * florinsasu@hotmail.com - */ - -/* - Notes: - * Since this is still beta things may change. - - * OSflags: - __LINUX__ (linux OS) - _WIN32 (win32 OS) - - * common return values (for ie. GSinit): - 0 - success - -1 - error - - * reserved keys: - F1 to F10 are reserved for the emulator - - * plugins should NOT change the current - working directory. - (on win32, add flag OFN_NOCHANGEDIR for - GetOpenFileName) - -*/ - -#include "PS2Etypes.h" - -#ifdef __LINUX__ -#define CALLBACK -#else -#include -#endif - - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ - defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ - defined(USBdefs) || defined(FWdefs) -#define COMMONdefs -#endif - -// PS2EgetLibType returns (may be OR'd) -#define PS2E_LT_GS 0x01 -#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- -#define PS2E_LT_SPU2 0x04 -#define PS2E_LT_CDVD 0x08 -#define PS2E_LT_DEV9 0x10 -#define PS2E_LT_USB 0x20 -#define PS2E_LT_FW 0x40 -#define PS2E_LT_SIO 0x80 - -// PS2EgetLibVersion2 (high 16 bits) -#define PS2E_GS_VERSION 0x0006 -#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- -#define PS2E_SPU2_VERSION 0x0005 -#define PS2E_CDVD_VERSION 0x0005 -#define PS2E_DEV9_VERSION 0x0003 -#define PS2E_USB_VERSION 0x0003 -#define PS2E_FW_VERSION 0x0002 -#define PS2E_SIO_VERSION 0x0001 -#ifdef COMMONdefs - -u32 CALLBACK PS2EgetLibType(void); -u32 CALLBACK PS2EgetLibVersion2(u32 type); -char* CALLBACK PS2EgetLibName(void); - -#endif - -// key values: -/* key values must be OS dependant: - win32: the VK_XXX will be used (WinUser) - linux: the XK_XXX will be used (XFree86) -*/ - -// event values: -#define KEYPRESS 1 -#define KEYRELEASE 2 - -typedef struct { - u32 key; - u32 event; -} keyEvent; - -// for 64bit compilers -typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; - -// plugin types -#define SIO_TYPE_PAD 0x00000001 -#define SIO_TYPE_MTAP 0x00000004 -#define SIO_TYPE_RM 0x00000040 -#define SIO_TYPE_MC 0x00000100 - -typedef int (CALLBACK * SIOchangeSlotCB)(int slot); - -typedef struct { - u8 ctrl:4; // control and mode bits - u8 mode:4; // control and mode bits - u8 trackNum; // current track number (1 to 99) - u8 trackIndex; // current index within track (0 to 99) - u8 trackM; // current minute location on the disc (BCD encoded) - u8 trackS; // current sector location on the disc (BCD encoded) - u8 trackF; // current frame location on the disc (BCD encoded) - u8 pad; // unused - u8 discM; // current minute offset from first track (BCD encoded) - u8 discS; // current sector offset from first track (BCD encoded) - u8 discF; // current frame offset from first track (BCD encoded) -} cdvdSubQ; - -typedef struct { // NOT bcd coded - u32 lsn; - u8 type; -} cdvdTD; - -typedef struct { - u8 strack; //number of the first track (usually 1) - u8 etrack; //number of the last track -} cdvdTN; - -// CDVDreadTrack mode values: -#define CDVD_MODE_2352 0 // full 2352 bytes -#define CDVD_MODE_2340 1 // skip sync (12) bytes -#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq - -// CDVDgetDiskType returns: -#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc -#define CDVD_TYPE_DVDV 0xfe // DVD Video -#define CDVD_TYPE_CDDA 0xfd // Audio CD -#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD -#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) -#define CDVD_TYPE_PS2CD 0x12 // PS2 CD -#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) -#define CDVD_TYPE_PSCD 0x10 // PS CD -#define CDVD_TYPE_UNKNOWN 0x05 // Unknown -#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided -#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided -#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd -#define CDVD_TYPE_DETCT 0x01 // Detecting -#define CDVD_TYPE_NODISC 0x00 // No Disc - -// CDVDgetTrayStatus returns: -#define CDVD_TRAY_CLOSE 0x00 -#define CDVD_TRAY_OPEN 0x01 - -// cdvdTD.type (track types for cds) -#define CDVD_AUDIO_TRACK 0x01 -#define CDVD_MODE1_TRACK 0x41 -#define CDVD_MODE2_TRACK 0x61 - -#define CDVD_AUDIO_MASK 0x00 -#define CDVD_DATA_MASK 0x40 -// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) - -typedef void (*DEV9callback)(int cycles); -typedef int (*DEV9handler)(void); - -typedef void (*USBcallback)(int cycles); -typedef int (*USBhandler)(void); - -// freeze modes: -#define FREEZE_LOAD 0 -#define FREEZE_SAVE 1 -#define FREEZE_SIZE 2 - -typedef struct { - char name[8]; - void *common; -} GSdriverInfo; - -#ifdef _WIN32 -typedef struct { // unsupported values must be set to zero - HWND hWnd; - HMENU hMenu; - HWND hStatusWnd; -} winInfo; -#endif - -/* GS plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef GSdefs - -// basic funcs - -s32 CALLBACK GSinit(); -s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); -void CALLBACK GSclose(); -void CALLBACK GSshutdown(); -void CALLBACK GSvsync(int field); -void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); -void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); -void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); -void CALLBACK GSgifSoftReset(u32 mask); -void CALLBACK GSreadFIFO(off64_t *mem); -void CALLBACK GSreadFIFO2(off64_t *mem, int qwc); - -// extended funcs - -// GSkeyEvent gets called when there is a keyEvent from the PAD plugin -void CALLBACK GSkeyEvent(keyEvent *ev); -void CALLBACK GSchangeSaveState(int, const char* filename); -void CALLBACK GSmakeSnapshot(char *path); -void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); -void CALLBACK GSirqCallback(void (*callback)()); -void CALLBACK GSprintf(int timeout, char *fmt, ...); -void CALLBACK GSsetBaseMem(void*); -void CALLBACK GSsetGameCRC(int); - -// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done -void CALLBACK GSsetFrameSkip(int frameskip); - -void CALLBACK GSreset(); -void CALLBACK GSwriteCSR(u32 value); -void CALLBACK GSgetDriverInfo(GSdriverInfo *info); -#ifdef _WIN32 -s32 CALLBACK GSsetWindowInfo(winInfo *info); -#endif -s32 CALLBACK GSfreeze(int mode, freezeData *data); -void CALLBACK GSconfigure(); -void CALLBACK GSabout(); -s32 CALLBACK GStest(); - -#endif - -/* PAD plugin API -=[ OBSOLETE ]=- */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef PADdefs - -// basic funcs - -s32 CALLBACK PADinit(u32 flags); -s32 CALLBACK PADopen(void *pDsp); -void CALLBACK PADclose(); -void CALLBACK PADshutdown(); -// PADkeyEvent is called every vsync (return NULL if no event) -keyEvent* CALLBACK PADkeyEvent(); -u8 CALLBACK PADstartPoll(int pad); -u8 CALLBACK PADpoll(u8 value); -// returns: 1 if supported pad1 -// 2 if supported pad2 -// 3 if both are supported -u32 CALLBACK PADquery(); - -// extended funcs - -void CALLBACK PADgsDriverInfo(GSdriverInfo *info); -void CALLBACK PADconfigure(); -void CALLBACK PADabout(); -s32 CALLBACK PADtest(); - -#endif - -/* SIO plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SIOdefs - -// basic funcs - -s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); -s32 CALLBACK SIOopen(void *pDsp); -void CALLBACK SIOclose(); -void CALLBACK SIOshutdown(); -u8 CALLBACK SIOstartPoll(u8 value); -u8 CALLBACK SIOpoll(u8 value); -// returns: SIO_TYPE_{PAD,MTAP,RM,MC} -u32 CALLBACK SIOquery(); - -// extended funcs - -void CALLBACK SIOconfigure(); -void CALLBACK SIOabout(); -s32 CALLBACK SIOtest(); - -#endif - -/* SPU2 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SPU2defs - -// basic funcs - -s32 CALLBACK SPU2init(); -s32 CALLBACK SPU2open(void *pDsp); -void CALLBACK SPU2close(); -void CALLBACK SPU2shutdown(); -void CALLBACK SPU2write(u32 mem, u16 value); -u16 CALLBACK SPU2read(u32 mem); -void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA4(); -void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); -void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA7(); -u32 CALLBACK SPU2ReadMemAddr(int core); -void CALLBACK SPU2WriteMemAddr(int core,u32 value); -void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); -// extended funcs - -void CALLBACK SPU2async(u32 cycles); -s32 CALLBACK SPU2freeze(int mode, freezeData *data); -void CALLBACK SPU2configure(); -void CALLBACK SPU2about(); -s32 CALLBACK SPU2test(); - -#endif - -/* CDVD plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef CDVDdefs - -// basic funcs - -s32 CALLBACK CDVDinit(); -s32 CALLBACK CDVDopen(const char* pTitleFilename); -void CALLBACK CDVDclose(); -void CALLBACK CDVDshutdown(); -s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); - -// return can be NULL (for async modes) -u8* CALLBACK CDVDgetBuffer(); - -s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) -s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information -s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type -s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc -s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx -s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx -s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray -s32 CALLBACK CDVDctrlTrayClose(); //close disc tray - -// extended funcs - -void CALLBACK CDVDconfigure(); -void CALLBACK CDVDabout(); -s32 CALLBACK CDVDtest(); -void CALLBACK CDVDnewDiskCB(void (*callback)()); - -#endif - -/* DEV9 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef DEV9defs - -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK DEV9init(); -s32 CALLBACK DEV9open(void *pDsp); -void CALLBACK DEV9close(); -void CALLBACK DEV9shutdown(); -u8 CALLBACK DEV9read8(u32 addr); -u16 CALLBACK DEV9read16(u32 addr); -u32 CALLBACK DEV9read32(u32 addr); -void CALLBACK DEV9write8(u32 addr, u8 value); -void CALLBACK DEV9write16(u32 addr, u16 value); -void CALLBACK DEV9write32(u32 addr, u32 value); -void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); -void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK DEV9irqCallback(DEV9callback callback); -DEV9handler CALLBACK DEV9irqHandler(void); - -// extended funcs - -s32 CALLBACK DEV9freeze(int mode, freezeData *data); -void CALLBACK DEV9configure(); -void CALLBACK DEV9about(); -s32 CALLBACK DEV9test(); - -#endif - -/* USB plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef USBdefs - -// basic funcs - -s32 CALLBACK USBinit(); -s32 CALLBACK USBopen(void *pDsp); -void CALLBACK USBclose(); -void CALLBACK USBshutdown(); -u8 CALLBACK USBread8(u32 addr); -u16 CALLBACK USBread16(u32 addr); -u32 CALLBACK USBread32(u32 addr); -void CALLBACK USBwrite8(u32 addr, u8 value); -void CALLBACK USBwrite16(u32 addr, u16 value); -void CALLBACK USBwrite32(u32 addr, u32 value); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK USBirqCallback(USBcallback callback); -USBhandler CALLBACK USBirqHandler(void); -void CALLBACK USBsetRAM(void *mem); - -// extended funcs - -s32 CALLBACK USBfreeze(int mode, freezeData *data); -void CALLBACK USBconfigure(); -void CALLBACK USBabout(); -s32 CALLBACK USBtest(); - -#endif - -/* FW plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef FWdefs -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK FWinit(); -s32 CALLBACK FWopen(void *pDsp); -void CALLBACK FWclose(); -void CALLBACK FWshutdown(); -u32 CALLBACK FWread32(u32 addr); -void CALLBACK FWwrite32(u32 addr, u32 value); -void CALLBACK FWirqCallback(void (*callback)()); - -// extended funcs - -s32 CALLBACK FWfreeze(int mode, freezeData *data); -void CALLBACK FWconfigure(); -void CALLBACK FWabout(); -s32 CALLBACK FWtest(); -#endif - -// might be useful for emulators -#ifdef PLUGINtypedefs - -typedef u32 (CALLBACK* _PS2EgetLibType)(void); -typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); -typedef char*(CALLBACK* _PS2EgetLibName)(void); - -// GS -// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _GSinit)(); -typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); -typedef void (CALLBACK* _GSclose)(); -typedef void (CALLBACK* _GSshutdown)(); -typedef void (CALLBACK* _GSvsync)(int field); -typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); -typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); -typedef void (CALLBACK* _GSreadFIFO)(off64_t *pMem); -typedef void (CALLBACK* _GSreadFIFO2)(off64_t *pMem, int qwc); - -typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); -typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); -typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); -typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); -typedef void (CALLBACK* _GSsetBaseMem)(void*); -typedef void (CALLBACK* _GSsetGameCRC)(int); -typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); -typedef void (CALLBACK* _GSreset)(); -typedef void (CALLBACK* _GSwriteCSR)(u32 value); -typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); -#ifdef _WIN32 -typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); -#endif -typedef void (CALLBACK* _GSmakeSnapshot)(char *path); -typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); -typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _GSconfigure)(); -typedef s32 (CALLBACK* _GStest)(); -typedef void (CALLBACK* _GSabout)(); - -// PAD -typedef s32 (CALLBACK* _PADinit)(u32 flags); -typedef s32 (CALLBACK* _PADopen)(void *pDsp); -typedef void (CALLBACK* _PADclose)(); -typedef void (CALLBACK* _PADshutdown)(); -typedef keyEvent* (CALLBACK* _PADkeyEvent)(); -typedef u8 (CALLBACK* _PADstartPoll)(int pad); -typedef u8 (CALLBACK* _PADpoll)(u8 value); -typedef u32 (CALLBACK* _PADquery)(); - -typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); -typedef void (CALLBACK* _PADconfigure)(); -typedef s32 (CALLBACK* _PADtest)(); -typedef void (CALLBACK* _PADabout)(); - -// SIO -typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); -typedef s32 (CALLBACK* _SIOopen)(void *pDsp); -typedef void (CALLBACK* _SIOclose)(); -typedef void (CALLBACK* _SIOshutdown)(); -typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); -typedef u8 (CALLBACK* _SIOpoll)(u8 value); -typedef u32 (CALLBACK* _SIOquery)(); - -typedef void (CALLBACK* _SIOconfigure)(); -typedef s32 (CALLBACK* _SIOtest)(); -typedef void (CALLBACK* _SIOabout)(); - -// SPU2 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _SPU2init)(); -typedef s32 (CALLBACK* _SPU2open)(void *pDsp); -typedef void (CALLBACK* _SPU2close)(); -typedef void (CALLBACK* _SPU2shutdown)(); -typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); -typedef u16 (CALLBACK* _SPU2read)(u32 mem); -typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA4)(); -typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA7)(); -typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); -typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); -typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); -typedef void (CALLBACK* _SPU2async)(u32 cycles); -typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _SPU2configure)(); -typedef s32 (CALLBACK* _SPU2test)(); -typedef void (CALLBACK* _SPU2about)(); - -// CDVD -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _CDVDinit)(); -typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); -typedef void (CALLBACK* _CDVDclose)(); -typedef void (CALLBACK* _CDVDshutdown)(); -typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); -typedef u8* (CALLBACK* _CDVDgetBuffer)(); -typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); -typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); -typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); -typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); -typedef s32 (CALLBACK* _CDVDgetDiskType)(); -typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); -typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); -typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); - -typedef void (CALLBACK* _CDVDconfigure)(); -typedef s32 (CALLBACK* _CDVDtest)(); -typedef void (CALLBACK* _CDVDabout)(); -typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); - -// DEV9 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _DEV9init)(); -typedef s32 (CALLBACK* _DEV9open)(void *pDsp); -typedef void (CALLBACK* _DEV9close)(); -typedef void (CALLBACK* _DEV9shutdown)(); -typedef u8 (CALLBACK* _DEV9read8)(u32 mem); -typedef u16 (CALLBACK* _DEV9read16)(u32 mem); -typedef u32 (CALLBACK* _DEV9read32)(u32 mem); -typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); -typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); -typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); -typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); -typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); - -typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _DEV9configure)(); -typedef s32 (CALLBACK* _DEV9test)(); -typedef void (CALLBACK* _DEV9about)(); - -// USB -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _USBinit)(); -typedef s32 (CALLBACK* _USBopen)(void *pDsp); -typedef void (CALLBACK* _USBclose)(); -typedef void (CALLBACK* _USBshutdown)(); -typedef u8 (CALLBACK* _USBread8)(u32 mem); -typedef u16 (CALLBACK* _USBread16)(u32 mem); -typedef u32 (CALLBACK* _USBread32)(u32 mem); -typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); -typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); -typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); -typedef USBhandler (CALLBACK* _USBirqHandler)(void); -typedef void (CALLBACK* _USBsetRAM)(void *mem); - -typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _USBconfigure)(); -typedef s32 (CALLBACK* _USBtest)(); -typedef void (CALLBACK* _USBabout)(); - -//FW -typedef s32 (CALLBACK* _FWinit)(); -typedef s32 (CALLBACK* _FWopen)(void *pDsp); -typedef void (CALLBACK* _FWclose)(); -typedef void (CALLBACK* _FWshutdown)(); -typedef u32 (CALLBACK* _FWread32)(u32 mem); -typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); - -typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _FWconfigure)(); -typedef s32 (CALLBACK* _FWtest)(); -typedef void (CALLBACK* _FWabout)(); - -#endif - -#ifdef PLUGINfuncs - -// GS -_GSinit GSinit; -_GSopen GSopen; -_GSclose GSclose; -_GSshutdown GSshutdown; -_GSvsync GSvsync; -_GSgifTransfer1 GSgifTransfer1; -_GSgifTransfer2 GSgifTransfer2; -_GSgifTransfer3 GSgifTransfer3; -_GSgifSoftReset GSgifSoftReset; -_GSreadFIFO GSreadFIFO; -_GSreadFIFO2 GSreadFIFO2; - -_GSkeyEvent GSkeyEvent; -_GSchangeSaveState GSchangeSaveState; -_GSmakeSnapshot GSmakeSnapshot; -_GSmakeSnapshot2 GSmakeSnapshot2; -_GSirqCallback GSirqCallback; -_GSprintf GSprintf; -_GSsetBaseMem GSsetBaseMem; -_GSsetGameCRC GSsetGameCRC; -_GSsetFrameSkip GSsetFrameSkip; -_GSreset GSreset; -_GSwriteCSR GSwriteCSR; -_GSgetDriverInfo GSgetDriverInfo; -#ifdef _WIN32 -_GSsetWindowInfo GSsetWindowInfo; -#endif -_GSfreeze GSfreeze; -_GSconfigure GSconfigure; -_GStest GStest; -_GSabout GSabout; - -// PAD1 -_PADinit PAD1init; -_PADopen PAD1open; -_PADclose PAD1close; -_PADshutdown PAD1shutdown; -_PADkeyEvent PAD1keyEvent; -_PADstartPoll PAD1startPoll; -_PADpoll PAD1poll; -_PADquery PAD1query; - -_PADgsDriverInfo PAD1gsDriverInfo; -_PADconfigure PAD1configure; -_PADtest PAD1test; -_PADabout PAD1about; - -// PAD2 -_PADinit PAD2init; -_PADopen PAD2open; -_PADclose PAD2close; -_PADshutdown PAD2shutdown; -_PADkeyEvent PAD2keyEvent; -_PADstartPoll PAD2startPoll; -_PADpoll PAD2poll; -_PADquery PAD2query; - -_PADgsDriverInfo PAD2gsDriverInfo; -_PADconfigure PAD2configure; -_PADtest PAD2test; -_PADabout PAD2about; - -// SIO[2] -_SIOinit SIOinit[2][9]; -_SIOopen SIOopen[2][9]; -_SIOclose SIOclose[2][9]; -_SIOshutdown SIOshutdown[2][9]; -_SIOstartPoll SIOstartPoll[2][9]; -_SIOpoll SIOpoll[2][9]; -_SIOquery SIOquery[2][9]; - -_SIOconfigure SIOconfigure[2][9]; -_SIOtest SIOtest[2][9]; -_SIOabout SIOabout[2][9]; - -// SPU2 -_SPU2init SPU2init; -_SPU2open SPU2open; -_SPU2close SPU2close; -_SPU2shutdown SPU2shutdown; -_SPU2write SPU2write; -_SPU2read SPU2read; -_SPU2readDMA4Mem SPU2readDMA4Mem; -_SPU2writeDMA4Mem SPU2writeDMA4Mem; -_SPU2interruptDMA4 SPU2interruptDMA4; -_SPU2readDMA7Mem SPU2readDMA7Mem; -_SPU2writeDMA7Mem SPU2writeDMA7Mem; -_SPU2interruptDMA7 SPU2interruptDMA7; -_SPU2ReadMemAddr SPU2ReadMemAddr; -_SPU2WriteMemAddr SPU2WriteMemAddr; -_SPU2irqCallback SPU2irqCallback; - -_SPU2async SPU2async; -_SPU2freeze SPU2freeze; -_SPU2configure SPU2configure; -_SPU2test SPU2test; -_SPU2about SPU2about; - -// CDVD -_CDVDinit CDVDinit; -_CDVDopen CDVDopen; -_CDVDclose CDVDclose; -_CDVDshutdown CDVDshutdown; -_CDVDreadTrack CDVDreadTrack; -_CDVDgetBuffer CDVDgetBuffer; -_CDVDreadSubQ CDVDreadSubQ; -_CDVDgetTN CDVDgetTN; -_CDVDgetTD CDVDgetTD; -_CDVDgetTOC CDVDgetTOC; -_CDVDgetDiskType CDVDgetDiskType; -_CDVDgetTrayStatus CDVDgetTrayStatus; -_CDVDctrlTrayOpen CDVDctrlTrayOpen; -_CDVDctrlTrayClose CDVDctrlTrayClose; - -_CDVDconfigure CDVDconfigure; -_CDVDtest CDVDtest; -_CDVDabout CDVDabout; -_CDVDnewDiskCB CDVDnewDiskCB; - -// DEV9 -_DEV9init DEV9init; -_DEV9open DEV9open; -_DEV9close DEV9close; -_DEV9shutdown DEV9shutdown; -_DEV9read8 DEV9read8; -_DEV9read16 DEV9read16; -_DEV9read32 DEV9read32; -_DEV9write8 DEV9write8; -_DEV9write16 DEV9write16; -_DEV9write32 DEV9write32; -_DEV9readDMA8Mem DEV9readDMA8Mem; -_DEV9writeDMA8Mem DEV9writeDMA8Mem; -_DEV9irqCallback DEV9irqCallback; -_DEV9irqHandler DEV9irqHandler; - -_DEV9configure DEV9configure; -_DEV9freeze DEV9freeze; -_DEV9test DEV9test; -_DEV9about DEV9about; - -// USB -_USBinit USBinit; -_USBopen USBopen; -_USBclose USBclose; -_USBshutdown USBshutdown; -_USBread8 USBread8; -_USBread16 USBread16; -_USBread32 USBread32; -_USBwrite8 USBwrite8; -_USBwrite16 USBwrite16; -_USBwrite32 USBwrite32; -_USBirqCallback USBirqCallback; -_USBirqHandler USBirqHandler; -_USBsetRAM USBsetRAM; - -_USBconfigure USBconfigure; -_USBfreeze USBfreeze; -_USBtest USBtest; -_USBabout USBabout; - -// FW -_FWinit FWinit; -_FWopen FWopen; -_FWclose FWclose; -_FWshutdown FWshutdown; -_FWread32 FWread32; -_FWwrite32 FWwrite32; -_FWirqCallback FWirqCallback; - -_FWconfigure FWconfigure; -_FWfreeze FWfreeze; -_FWtest FWtest; -_FWabout FWabout; -#endif - -#endif /* __PS2EDEFS_H__ */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(off64_t *mem); +void CALLBACK GSreadFIFO2(off64_t *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(off64_t *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(off64_t *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/CDVDisoEFP/src/Win32/CD.c b/plugins/CDVDisoEFP/src/Win32/CD.c index 469a2dcb71..593e348468 100644 --- a/plugins/CDVDisoEFP/src/Win32/CD.c +++ b/plugins/CDVDisoEFP/src/Win32/CD.c @@ -1,774 +1,774 @@ -/* CD.c - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#include - -#include // IOCTL_CDROM... - - - -#include // off64_t - - - -#define CDVDdefs - -#include "PS2Edefs.h" - - - -#include "logfile.h" - -#include "../convert.h" // MSFtoLBA(), HEXTOBCD() - -#include "actualfile.h" - -#include "device.h" // tocbuffer[], FinishCommand() - -#include "CD.h" - - - - - -int actualcdmode; // -1=ReadFile, 0=YellowMode2, 1=XAForm2, 2=CDDA - -DWORD cdblocksize; // 2048 to 2352 - -int cdoffset; // 0, 8, 16, or 24 - -int cdmode; - - - - - -void InitCDInfo() { - - actualcdmode = -1; - - cdblocksize = 2048; - - cdmode = -1; - -} // END InitCDInfo() - - - - - -s32 CDreadTrackPass(u32 lsn, int mode, u8 *buffer) { - - RAW_READ_INFO rawinfo; - - BOOL boolresult; - - DWORD byteswritten; - - DWORD errcode; - - LARGE_INTEGER targetpos; - - int i; - - - - if((actualcdmode < -1) || (actualcdmode > 2)) return(-1); - - - -#ifdef VERBOSE_FUNCTION_DEVICE - - PrintLog("CDVD CD: CDreadTrack(%llu, %i)", lsn, actualcdmode); - -#endif /* VERBOSE_FUNCTION_DEVICE */ - - - - if(actualcdmode >= 0) { - - rawinfo.DiskOffset.QuadPart = lsn * 2048; // Yes, 2048. - - rawinfo.SectorCount = 1; - - rawinfo.TrackMode = actualcdmode; - - boolresult = DeviceIoControl(devicehandle, - - IOCTL_CDROM_RAW_READ, - - &rawinfo, - - sizeof(RAW_READ_INFO), - - buffer, - - 2352, - - &byteswritten, - - &waitevent); - - errcode = FinishCommand(boolresult); - - - - if(errcode != 0) { - -#ifdef VERBOSE_WARNING_DEVICE - - PrintLog("CDVDiso CD: Couldn't read a sector raw!"); - - PrintError("CDVDiso CD", errcode); - -#endif /* VERBOSE_WARNING_DEVICE */ - - return(-1); - - } // ENDIF- Couldn't read a raw sector? Maybe not a CD. - - - - } else { - - targetpos.QuadPart = lsn * 2048; - - waitevent.Offset = targetpos.LowPart; - - waitevent.OffsetHigh = targetpos.HighPart; - - - - boolresult = ReadFile(devicehandle, - - buffer + 24, - - 2048, - - &byteswritten, - - &waitevent); - - errcode = FinishCommand(boolresult); - - - - if(errcode != 0) { - -#ifdef VERBOSE_WARNING_DEVICE - - PrintLog("CDVDiso CD: Couldn't read a cooked sector!"); - - PrintError("CDVDiso CD", errcode); - -#endif /* VERBOSE_WARNING_DEVICE */ - - return(-1); - - } // ENDIF- Trouble with seek? Report it. - - - - for(i = 0; i < 24; i++) *(buffer + i) = 0; - - for(i = 24 + 2048; i < 2352; i++) *(buffer + i) = 0; - - } // ENDIF- Could we read a raw sector? Read another one! - - - - if(boolresult == FALSE) { - - boolresult = GetOverlappedResult(devicehandle, - - &waitevent, - - &byteswritten, - - FALSE); - - } // ENDIF- Did the initial call not complete? Get byteswritten for - - // the completed call. - - - - if(byteswritten < 2048) { - -#ifdef VERBOSE_WARNING_DEVICE - - errcode = GetLastError(); - - PrintLog("CDVDiso CD: Short block! only got %u out of %u bytes", - - byteswritten, cdblocksize); - - PrintError("CDVDiso CD", errcode); - -#endif /* VERBOSE_WARNING_DEVICE */ - - return(-1); - - } // ENDIF- Couldn't read a raw sector? Maybe not a CD. - - - - cdmode = mode; - - cdblocksize = byteswritten; - - return(0); - -} // END CDreadTrackPass() - - - - - -s32 CDreadTrack(u32 lsn, int mode, u8 *buffer) { - - int retval; - - int lastmode; - - int i; - - - - retval = CDreadTrackPass(lsn, mode, buffer); - - if(retval >= 0) return(retval); - - - -#ifdef VERBOSE_WARNING_DEVICE - - PrintLog("CDVDiso CD: Same mode doesn't work. Scanning..."); - -#endif /* VERBOSE_WARNING_DEVICE */ - - - - lastmode = actualcdmode; - - actualcdmode = 2; - - while(actualcdmode >= -1) { - - retval = CDreadTrackPass(lsn, mode, buffer); - - if(retval >= 0) return(retval); - - actualcdmode--; - - } // ENDWHILE- Searching each mode for a way to read the sector - - actualcdmode = lastmode; // None worked? Go back to first mode. - - - -#ifdef VERBOSE_WARNING_DEVICE - - PrintLog("CDVDiso CD: No modes work. Failing sector!"); - -#endif /* VERBOSE_WARNING_DEVICE */ - - - - for(i = 0; i < 2352; i++) *(buffer + i) = 0; - - return(-1); - -} // END CDreadTrack() - - - - - -s32 CDgetBufferOffset() { - -#ifdef VERBOSE_FUNCTION_DEVICE - - PrintLog("CDVD CD: CDgetBufferOffset()"); - -#endif /* VERBOSE_FUNCTION_DEVICE */ - - - - // Send a whole CDDA record in? - - if((actualcdmode == CDDA) && (cdmode == CDVD_MODE_2352)) return(0); - - - - // Otherwise, send the start of the data block in... - - return(cdoffset); - -} // END CDgetBufferOffset() - - - - - -s32 CDreadSubQ() { - - return(-1); - -} // END CDreadSubQ() - - - - - -s32 CDgetTN(cdvdTN *cdvdtn) { - - cdvdtn->strack = BCDTOHEX(tocbuffer[7]); - - cdvdtn->etrack = BCDTOHEX(tocbuffer[17]); - - return(0); - -} // END CDgetTN() - - - - - -s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd) { - - u8 actualtrack; - - int pos; - - char temptime[3]; - - - -#ifdef VERBOSE_FUNCTION_DEVICE - - PrintLog("CDVDiso CD: CDgetTD()"); - -#endif /* VERBOSE_FUNCTION_DEVICE */ - - - - actualtrack = newtrack; - - if(actualtrack == 0xaa) actualtrack = 0; - - - - if(actualtrack == 0) { - - cdvdtd->type = 0; - - temptime[0] = BCDTOHEX(tocbuffer[27]); - - temptime[1] = BCDTOHEX(tocbuffer[28]); - - temptime[2] = BCDTOHEX(tocbuffer[29]); - - cdvdtd->lsn = MSFtoLBA(temptime); - - } else { - - pos = actualtrack * 10; - - pos += 30; - - cdvdtd->type = tocbuffer[pos]; - - temptime[0] = BCDTOHEX(tocbuffer[pos + 7]); - - temptime[1] = BCDTOHEX(tocbuffer[pos + 8]); - - temptime[2] = BCDTOHEX(tocbuffer[pos + 9]); - - cdvdtd->lsn = MSFtoLBA(temptime); - - } // ENDIF- Whole disc? (or single track?) - - - - return(0); - -} // END CDgetTD() - - - - - -s32 CDgetDiskType() { - - CDROM_TOC cdinfo; - - BOOL boolresult; - - int retval; - - DWORD byteswritten; - - DWORD errcode; - - u8 iso9660name[] = "CD001\0"; - - u8 playstationname[] = "PLAYSTATION\0"; - - u8 ps1name[] = "CD-XA001\0"; - - u8 tempbuffer[2448]; - - int tempdisctype; - - int i; - - int pos; - - unsigned long volumesize; - - - -#ifdef VERBOSE_FUNCTION_DEVICE - - PrintLog("CDVDiso CD: CDgetDiskType()"); - -#endif /* VERBOSE_FUNCTION_DEVICE */ - - - - tempdisctype = CDVD_TYPE_UNKNOWN; - - - - actualcdmode = 2; - - retval = CDreadTrack(16, CDVD_MODE_2048, tempbuffer); - - if(retval < 0) { - - disctype = tempdisctype; - - return(-1); - - } // ENDIF- Couldn't read the directory sector? Abort. - - - - disctype = CDVD_TYPE_DETCTCD; - - tempdisctype = CDVD_TYPE_CDDA; - - - - cdoffset = 0; - - i = 0; - - while((cdoffset <= 24) && (iso9660name[i] != 0)) { - - i = 0; - - while((iso9660name[i] != 0) && - - (iso9660name[i] == tempbuffer[cdoffset + 1 + i])) i++; - - if(iso9660name[i] != 0) cdoffset += 8; - - } // ENDWHILE- Trying to find a working offset for a ISO9660 record. - - - - if(iso9660name[i] != 0) { - -#ifdef VERBOSE_DISC_TYPE - - PrintLog("Detected a CDDA (Music CD)."); - -#endif /* VERBOSE_DISC_TYPE */ - - tempdisctype = CDVD_TYPE_CDDA; - - tocbuffer[0] = 0x01; - - - - } else { - - tocbuffer[0] = 0x41; - - i = 0; - - while((playstationname[i] != 0) && - - (playstationname[i] == tempbuffer[cdoffset + 8 + i])) i++; - - if(playstationname[i] != 0) { - -#ifdef VERBOSE_DISC_TYPE - - PrintLog("Detected a non-Playstation CD."); - -#endif /* VERBOSE_DISC_TYPE */ - - tempdisctype = CDVD_TYPE_UNKNOWN; - - - - } else { - - i = 0; - - while((ps1name[i] != 0) && - - (ps1name[i] == tempbuffer[cdoffset + 1024 + i])) i++; - - if(ps1name[i] != 0) { - -#ifdef VERBOSE_DISC_TYPE - - PrintLog("Detected a Playstation 2 CD."); - -#endif /* VERBOSE_DISC_TYPE */ - - tempdisctype = CDVD_TYPE_PS2CD; - - } else { - -#ifdef VERBOSE_DISC_TYPE - - PrintLog("Detected a Playstation CD."); - -#endif /* VERBOSE_DISC_TYPE */ - - tempdisctype = CDVD_TYPE_PSCD; - - } // ENDIF- Is this not a PlayStation Disc? - - } // ENDIF- Is this not a PlayStation Disc? - - } // ENDIF- Is this not an ISO9660 CD? (a CDDA, in other words?) - - - - // Build the Fake TOC - - tocbuffer[2] = 0xA0; - - tocbuffer[7] = HEXTOBCD(1); // Starting Track - - tocbuffer[12] = 0xA1; - - tocbuffer[17] = HEXTOBCD(1); // Ending Track - - - - volumesize = tempbuffer[84]; // Volume size (big endian) - - volumesize *= 256; - - volumesize += tempbuffer[85]; - - volumesize *= 256; - - volumesize += tempbuffer[86]; - - volumesize *= 256; - - volumesize += tempbuffer[87]; - -#ifdef VERBOSE_DISC_INFO - - if(tempdisctype != CDVD_TYPE_CDDA) { - - PrintLog("CDVDiso CD: ISO9660 size %llu", volumesize); - - } // ENDIF- Data CD? Print size in blocks. - -#endif /* VERBOSE_DISC_INFO */ - - - - LBAtoMSF(volumesize, &tocbuffer[27]); - - tocbuffer[27] = HEXTOBCD(tocbuffer[27]); - - tocbuffer[28] = HEXTOBCD(tocbuffer[28]); - - tocbuffer[29] = HEXTOBCD(tocbuffer[29]); - - - - tocbuffer[40] = 0x02; // Data Mode - - tocbuffer[42] = 0x01; // Track # - - LBAtoMSF(0, &tocbuffer[47]); - - tocbuffer[47] = HEXTOBCD(tocbuffer[47]); - - tocbuffer[48] = HEXTOBCD(tocbuffer[48]); - - tocbuffer[49] = HEXTOBCD(tocbuffer[49]); - - - - // Can we get the REAL TOC? - - boolresult = DeviceIoControl(devicehandle, - - IOCTL_CDROM_READ_TOC, - - NULL, - - 0, - - &cdinfo, - - sizeof(CDROM_TOC), - - &byteswritten, - - NULL); - - - - if(boolresult == FALSE) { - -#ifdef VERBOSE_WARNING_DEVICE - - errcode = GetLastError(); - - PrintLog("CDVDiso CD: Can't get TOC!"); - - PrintError("CDVDiso CD", errcode); - -#endif /* VERBOSE_WARNING_DEVICE */ - - disctype = tempdisctype; - - return(disctype); - - } // ENDIF- Can't read the TOC? Accept the fake TOC then. - - - - // Fill in the pieces of the REAL TOC. - -#ifdef VERBOSE_DISC_INFO - - PrintLog("CDVDiso CD: TOC First Track: %u Last Track: %u", - - cdinfo.FirstTrack, cdinfo.LastTrack); - -#endif /* VERBOSE_DISC_INFO */ - - tocbuffer[7] = HEXTOBCD(cdinfo.FirstTrack); - - tocbuffer[17] = HEXTOBCD(cdinfo.LastTrack); - - - - // for(i = cdinfo.FirstTrack; i <= cdinfo.LastTrack; i++) { - - for(i = 0; i <= cdinfo.LastTrack - cdinfo.FirstTrack; i++) { - -#ifdef VERBOSE_DISC_INFO - - PrintLog("CDVDiso CD: TOC Track %u Disc Size: %u:%u.%u Data Mode %u", - - cdinfo.TrackData[i].TrackNumber, - - cdinfo.TrackData[i].Address[1] * 1, - - cdinfo.TrackData[i].Address[2] * 1, - - cdinfo.TrackData[i].Address[3] * 1, - - cdinfo.TrackData[i].Control * 1); - -#endif /* VERBOSE_DISC_INFO */ - - pos = i * 10 + 40; - - tocbuffer[pos] = cdinfo.TrackData[i].Control; - - tocbuffer[pos + 2] = HEXTOBCD(i + 1); - - tocbuffer[pos + 7] = HEXTOBCD(cdinfo.TrackData[i].Address[1]); - - tocbuffer[pos + 8] = HEXTOBCD(cdinfo.TrackData[i].Address[2]); - - tocbuffer[pos + 9] = HEXTOBCD(cdinfo.TrackData[i].Address[3]); - - } // NEXT i- Transferring Track data to the PS2 TOC - - - - - -#ifdef VERBOSE_DISC_INFO - - PrintLog("CDVDiso CD: TOC Disc Size: %u:%u.%u", - - cdinfo.TrackData[i].Address[1] * 1, - - cdinfo.TrackData[i].Address[2] * 1, - - cdinfo.TrackData[i].Address[3] * 1); - -#endif /* VERBOSE_DISC_INFO */ - - tocbuffer[27] = HEXTOBCD(cdinfo.TrackData[i].Address[1]); - - tocbuffer[28] = HEXTOBCD(cdinfo.TrackData[i].Address[2]); - - tocbuffer[29] = HEXTOBCD(cdinfo.TrackData[i].Address[3]); - - - - disctype = tempdisctype; - - return(disctype); - -} // END CDgetDiskType() - +/* CD.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + +#include // IOCTL_CDROM... + + + +#include // off64_t + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + +#include "logfile.h" + +#include "../convert.h" // MSFtoLBA(), HEXTOBCD() + +#include "actualfile.h" + +#include "device.h" // tocbuffer[], FinishCommand() + +#include "CD.h" + + + + + +int actualcdmode; // -1=ReadFile, 0=YellowMode2, 1=XAForm2, 2=CDDA + +DWORD cdblocksize; // 2048 to 2352 + +int cdoffset; // 0, 8, 16, or 24 + +int cdmode; + + + + + +void InitCDInfo() { + + actualcdmode = -1; + + cdblocksize = 2048; + + cdmode = -1; + +} // END InitCDInfo() + + + + + +s32 CDreadTrackPass(u32 lsn, int mode, u8 *buffer) { + + RAW_READ_INFO rawinfo; + + BOOL boolresult; + + DWORD byteswritten; + + DWORD errcode; + + LARGE_INTEGER targetpos; + + int i; + + + + if((actualcdmode < -1) || (actualcdmode > 2)) return(-1); + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVD CD: CDreadTrack(%llu, %i)", lsn, actualcdmode); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + if(actualcdmode >= 0) { + + rawinfo.DiskOffset.QuadPart = lsn * 2048; // Yes, 2048. + + rawinfo.SectorCount = 1; + + rawinfo.TrackMode = actualcdmode; + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_CDROM_RAW_READ, + + &rawinfo, + + sizeof(RAW_READ_INFO), + + buffer, + + 2352, + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso CD: Couldn't read a sector raw!"); + + PrintError("CDVDiso CD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Couldn't read a raw sector? Maybe not a CD. + + + + } else { + + targetpos.QuadPart = lsn * 2048; + + waitevent.Offset = targetpos.LowPart; + + waitevent.OffsetHigh = targetpos.HighPart; + + + + boolresult = ReadFile(devicehandle, + + buffer + 24, + + 2048, + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso CD: Couldn't read a cooked sector!"); + + PrintError("CDVDiso CD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Trouble with seek? Report it. + + + + for(i = 0; i < 24; i++) *(buffer + i) = 0; + + for(i = 24 + 2048; i < 2352; i++) *(buffer + i) = 0; + + } // ENDIF- Could we read a raw sector? Read another one! + + + + if(boolresult == FALSE) { + + boolresult = GetOverlappedResult(devicehandle, + + &waitevent, + + &byteswritten, + + FALSE); + + } // ENDIF- Did the initial call not complete? Get byteswritten for + + // the completed call. + + + + if(byteswritten < 2048) { + +#ifdef VERBOSE_WARNING_DEVICE + + errcode = GetLastError(); + + PrintLog("CDVDiso CD: Short block! only got %u out of %u bytes", + + byteswritten, cdblocksize); + + PrintError("CDVDiso CD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Couldn't read a raw sector? Maybe not a CD. + + + + cdmode = mode; + + cdblocksize = byteswritten; + + return(0); + +} // END CDreadTrackPass() + + + + + +s32 CDreadTrack(u32 lsn, int mode, u8 *buffer) { + + int retval; + + int lastmode; + + int i; + + + + retval = CDreadTrackPass(lsn, mode, buffer); + + if(retval >= 0) return(retval); + + + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso CD: Same mode doesn't work. Scanning..."); + +#endif /* VERBOSE_WARNING_DEVICE */ + + + + lastmode = actualcdmode; + + actualcdmode = 2; + + while(actualcdmode >= -1) { + + retval = CDreadTrackPass(lsn, mode, buffer); + + if(retval >= 0) return(retval); + + actualcdmode--; + + } // ENDWHILE- Searching each mode for a way to read the sector + + actualcdmode = lastmode; // None worked? Go back to first mode. + + + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso CD: No modes work. Failing sector!"); + +#endif /* VERBOSE_WARNING_DEVICE */ + + + + for(i = 0; i < 2352; i++) *(buffer + i) = 0; + + return(-1); + +} // END CDreadTrack() + + + + + +s32 CDgetBufferOffset() { + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVD CD: CDgetBufferOffset()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + // Send a whole CDDA record in? + + if((actualcdmode == CDDA) && (cdmode == CDVD_MODE_2352)) return(0); + + + + // Otherwise, send the start of the data block in... + + return(cdoffset); + +} // END CDgetBufferOffset() + + + + + +s32 CDreadSubQ() { + + return(-1); + +} // END CDreadSubQ() + + + + + +s32 CDgetTN(cdvdTN *cdvdtn) { + + cdvdtn->strack = BCDTOHEX(tocbuffer[7]); + + cdvdtn->etrack = BCDTOHEX(tocbuffer[17]); + + return(0); + +} // END CDgetTN() + + + + + +s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd) { + + u8 actualtrack; + + int pos; + + char temptime[3]; + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso CD: CDgetTD()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + actualtrack = newtrack; + + if(actualtrack == 0xaa) actualtrack = 0; + + + + if(actualtrack == 0) { + + cdvdtd->type = 0; + + temptime[0] = BCDTOHEX(tocbuffer[27]); + + temptime[1] = BCDTOHEX(tocbuffer[28]); + + temptime[2] = BCDTOHEX(tocbuffer[29]); + + cdvdtd->lsn = MSFtoLBA(temptime); + + } else { + + pos = actualtrack * 10; + + pos += 30; + + cdvdtd->type = tocbuffer[pos]; + + temptime[0] = BCDTOHEX(tocbuffer[pos + 7]); + + temptime[1] = BCDTOHEX(tocbuffer[pos + 8]); + + temptime[2] = BCDTOHEX(tocbuffer[pos + 9]); + + cdvdtd->lsn = MSFtoLBA(temptime); + + } // ENDIF- Whole disc? (or single track?) + + + + return(0); + +} // END CDgetTD() + + + + + +s32 CDgetDiskType() { + + CDROM_TOC cdinfo; + + BOOL boolresult; + + int retval; + + DWORD byteswritten; + + DWORD errcode; + + u8 iso9660name[] = "CD001\0"; + + u8 playstationname[] = "PLAYSTATION\0"; + + u8 ps1name[] = "CD-XA001\0"; + + u8 tempbuffer[2448]; + + int tempdisctype; + + int i; + + int pos; + + unsigned long volumesize; + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso CD: CDgetDiskType()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + tempdisctype = CDVD_TYPE_UNKNOWN; + + + + actualcdmode = 2; + + retval = CDreadTrack(16, CDVD_MODE_2048, tempbuffer); + + if(retval < 0) { + + disctype = tempdisctype; + + return(-1); + + } // ENDIF- Couldn't read the directory sector? Abort. + + + + disctype = CDVD_TYPE_DETCTCD; + + tempdisctype = CDVD_TYPE_CDDA; + + + + cdoffset = 0; + + i = 0; + + while((cdoffset <= 24) && (iso9660name[i] != 0)) { + + i = 0; + + while((iso9660name[i] != 0) && + + (iso9660name[i] == tempbuffer[cdoffset + 1 + i])) i++; + + if(iso9660name[i] != 0) cdoffset += 8; + + } // ENDWHILE- Trying to find a working offset for a ISO9660 record. + + + + if(iso9660name[i] != 0) { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("Detected a CDDA (Music CD)."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_CDDA; + + tocbuffer[0] = 0x01; + + + + } else { + + tocbuffer[0] = 0x41; + + i = 0; + + while((playstationname[i] != 0) && + + (playstationname[i] == tempbuffer[cdoffset + 8 + i])) i++; + + if(playstationname[i] != 0) { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("Detected a non-Playstation CD."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_UNKNOWN; + + + + } else { + + i = 0; + + while((ps1name[i] != 0) && + + (ps1name[i] == tempbuffer[cdoffset + 1024 + i])) i++; + + if(ps1name[i] != 0) { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("Detected a Playstation 2 CD."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_PS2CD; + + } else { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("Detected a Playstation CD."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_PSCD; + + } // ENDIF- Is this not a PlayStation Disc? + + } // ENDIF- Is this not a PlayStation Disc? + + } // ENDIF- Is this not an ISO9660 CD? (a CDDA, in other words?) + + + + // Build the Fake TOC + + tocbuffer[2] = 0xA0; + + tocbuffer[7] = HEXTOBCD(1); // Starting Track + + tocbuffer[12] = 0xA1; + + tocbuffer[17] = HEXTOBCD(1); // Ending Track + + + + volumesize = tempbuffer[84]; // Volume size (big endian) + + volumesize *= 256; + + volumesize += tempbuffer[85]; + + volumesize *= 256; + + volumesize += tempbuffer[86]; + + volumesize *= 256; + + volumesize += tempbuffer[87]; + +#ifdef VERBOSE_DISC_INFO + + if(tempdisctype != CDVD_TYPE_CDDA) { + + PrintLog("CDVDiso CD: ISO9660 size %llu", volumesize); + + } // ENDIF- Data CD? Print size in blocks. + +#endif /* VERBOSE_DISC_INFO */ + + + + LBAtoMSF(volumesize, &tocbuffer[27]); + + tocbuffer[27] = HEXTOBCD(tocbuffer[27]); + + tocbuffer[28] = HEXTOBCD(tocbuffer[28]); + + tocbuffer[29] = HEXTOBCD(tocbuffer[29]); + + + + tocbuffer[40] = 0x02; // Data Mode + + tocbuffer[42] = 0x01; // Track # + + LBAtoMSF(0, &tocbuffer[47]); + + tocbuffer[47] = HEXTOBCD(tocbuffer[47]); + + tocbuffer[48] = HEXTOBCD(tocbuffer[48]); + + tocbuffer[49] = HEXTOBCD(tocbuffer[49]); + + + + // Can we get the REAL TOC? + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_CDROM_READ_TOC, + + NULL, + + 0, + + &cdinfo, + + sizeof(CDROM_TOC), + + &byteswritten, + + NULL); + + + + if(boolresult == FALSE) { + +#ifdef VERBOSE_WARNING_DEVICE + + errcode = GetLastError(); + + PrintLog("CDVDiso CD: Can't get TOC!"); + + PrintError("CDVDiso CD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + disctype = tempdisctype; + + return(disctype); + + } // ENDIF- Can't read the TOC? Accept the fake TOC then. + + + + // Fill in the pieces of the REAL TOC. + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVDiso CD: TOC First Track: %u Last Track: %u", + + cdinfo.FirstTrack, cdinfo.LastTrack); + +#endif /* VERBOSE_DISC_INFO */ + + tocbuffer[7] = HEXTOBCD(cdinfo.FirstTrack); + + tocbuffer[17] = HEXTOBCD(cdinfo.LastTrack); + + + + // for(i = cdinfo.FirstTrack; i <= cdinfo.LastTrack; i++) { + + for(i = 0; i <= cdinfo.LastTrack - cdinfo.FirstTrack; i++) { + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVDiso CD: TOC Track %u Disc Size: %u:%u.%u Data Mode %u", + + cdinfo.TrackData[i].TrackNumber, + + cdinfo.TrackData[i].Address[1] * 1, + + cdinfo.TrackData[i].Address[2] * 1, + + cdinfo.TrackData[i].Address[3] * 1, + + cdinfo.TrackData[i].Control * 1); + +#endif /* VERBOSE_DISC_INFO */ + + pos = i * 10 + 40; + + tocbuffer[pos] = cdinfo.TrackData[i].Control; + + tocbuffer[pos + 2] = HEXTOBCD(i + 1); + + tocbuffer[pos + 7] = HEXTOBCD(cdinfo.TrackData[i].Address[1]); + + tocbuffer[pos + 8] = HEXTOBCD(cdinfo.TrackData[i].Address[2]); + + tocbuffer[pos + 9] = HEXTOBCD(cdinfo.TrackData[i].Address[3]); + + } // NEXT i- Transferring Track data to the PS2 TOC + + + + + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVDiso CD: TOC Disc Size: %u:%u.%u", + + cdinfo.TrackData[i].Address[1] * 1, + + cdinfo.TrackData[i].Address[2] * 1, + + cdinfo.TrackData[i].Address[3] * 1); + +#endif /* VERBOSE_DISC_INFO */ + + tocbuffer[27] = HEXTOBCD(cdinfo.TrackData[i].Address[1]); + + tocbuffer[28] = HEXTOBCD(cdinfo.TrackData[i].Address[2]); + + tocbuffer[29] = HEXTOBCD(cdinfo.TrackData[i].Address[3]); + + + + disctype = tempdisctype; + + return(disctype); + +} // END CDgetDiskType() + diff --git a/plugins/CDVDisoEFP/src/Win32/CD.h b/plugins/CDVDisoEFP/src/Win32/CD.h index 6bff6d8e82..2049fe764d 100644 --- a/plugins/CDVDisoEFP/src/Win32/CD.h +++ b/plugins/CDVDisoEFP/src/Win32/CD.h @@ -1,44 +1,88 @@ -/* CD.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef CD_H -#define CD_H - - -#include // DWORD - -#define CDVDdefs -#include "PS2Edefs.h" - - -extern DWORD cdblocksize; - - -extern void InitCDInfo(); -extern s32 CDreadTrack(u32 lsn, int mode, u8 *buffer); -extern s32 CDgetBufferOffset(); -extern s32 CDreadSubQ(); -extern s32 CDgetTN(cdvdTN *cdvdtn); -extern s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd); -extern s32 CDgetDiskType(); - - -#endif /* CD_H */ +/* CD.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef CD_H + +#define CD_H + + + + + +#include // DWORD + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + + + +extern DWORD cdblocksize; + + + + + +extern void InitCDInfo(); + +extern s32 CDreadTrack(u32 lsn, int mode, u8 *buffer); + +extern s32 CDgetBufferOffset(); + +extern s32 CDreadSubQ(); + +extern s32 CDgetTN(cdvdTN *cdvdtn); + +extern s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd); + +extern s32 CDgetDiskType(); + + + + + +#endif /* CD_H */ + diff --git a/plugins/CDVDisoEFP/src/Win32/CDVDiso.h b/plugins/CDVDisoEFP/src/Win32/CDVDiso.h index 61aab42bc4..f502d4150e 100644 --- a/plugins/CDVDisoEFP/src/Win32/CDVDiso.h +++ b/plugins/CDVDisoEFP/src/Win32/CDVDiso.h @@ -1,36 +1,72 @@ -/* CDVDiso.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef CDVDISO_H -#define CDVDISO_H - - -#include // HINSTANCE - - -// #define VERBOSE_FUNCTION_INTERFACE - - -extern HINSTANCE progmodule; -extern char isobuffer[]; - - -#endif /* CDVDISO_H */ +/* CDVDiso.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef CDVDISO_H + +#define CDVDISO_H + + + + + +#include // HINSTANCE + + + + + +// #define VERBOSE_FUNCTION_INTERFACE + + + + + +extern HINSTANCE progmodule; + +extern char isobuffer[]; + + + + + +#endif /* CDVDISO_H */ + diff --git a/plugins/CDVDisoEFP/src/Win32/DVD.c b/plugins/CDVDisoEFP/src/Win32/DVD.c index 18f5c6563f..077c50f6a0 100644 --- a/plugins/CDVDisoEFP/src/Win32/DVD.c +++ b/plugins/CDVDisoEFP/src/Win32/DVD.c @@ -1,796 +1,796 @@ -/* DVD.c - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#include - -#include // IOCTL_DVD... - - - -#include // off64_t - - - -#define CDVDdefs - -#include "PS2Edefs.h" - - - -#include "logfile.h" - -#include "device.h" // FinishCommand() - - - - - -struct { - - DVD_DESCRIPTOR_HEADER h; - - DVD_LAYER_DESCRIPTOR d; - -} layer; - -// DVD_LAYER_DESCRIPTOR layer; - -// DVD_COPYRIGHT_DESCRIPTOR copyright; - -// DVD_DISK_KEY_DESCRIPTOR disckey; - -// DVD_BCA_DESCRIPTOR bca; - -// DVD_MANUFACTURER_DESCRIPTOR manufact; - - - - - -void InitDVDInfo() { - - layer.d.EndDataSector = 0; - -} // END InitDVDInfo() - - - - - -s32 DVDGetStructures() { - - DVD_SESSION_ID sessionid; - - DVD_READ_STRUCTURE request; - - DWORD byteswritten; - - BOOL boolresult; - - DWORD errcode; - - s32 retval; - - - -#ifdef VERBOSE_FUNCTION_DEVICE - - PrintLog("CDVDiso DVD: DVDgetStructures()"); - -#endif /* VERBOSE_FUNCTION_DEVICE */ - - - - boolresult = DeviceIoControl(devicehandle, - - IOCTL_DVD_START_SESSION, - - NULL, - - 0, - - &sessionid, - - sizeof(DVD_SESSION_ID), - - &byteswritten, - - &waitevent); - - errcode = FinishCommand(boolresult); - - if(errcode != 0) { - -#ifdef VERBOSE_WARNING_DEVICE - - PrintLog("CDVDiso DVD: Couldn't start session!"); - - PrintError("CDVDiso DVD", errcode); - -#endif /* VERBOSE_WARNING_DEVICE */ - - return(-1); - - } // ENDIF- Couldn't start a user session on the DVD drive? Fail. - - - - request.BlockByteOffset.QuadPart = 0; - - request.Format = DvdPhysicalDescriptor; - - request.SessionId = sessionid; - - request.LayerNumber = 0; - - retval = 0; - - boolresult = DeviceIoControl(devicehandle, - - IOCTL_DVD_READ_STRUCTURE, - - &request, - - sizeof(DVD_READ_STRUCTURE), - - &layer, - - sizeof(layer), - - &byteswritten, - - &waitevent); - - errcode = FinishCommand(boolresult); - - if(errcode != 0) { - -#ifdef VERBOSE_WARNING_DEVICE - - PrintLog("CDVDiso DVD: Couldn't get layer data!"); - - PrintError("CDVDiso DVD", errcode); - -#endif /* VERBOSE_WARNING_DEVICE */ - - retval = -1; - - } // ENDIF- Couldn't get layer data? (Including DVD size) Abort. - - - -#ifdef VERBOSE_DISC_INFO - - switch(layer.d.BookType) { - - case 0: - - PrintLog("CDVDiso DVD: Book Type: DVD-ROM"); - - break; - - case 1: - - PrintLog("CDVDiso DVD: Book Type: DVD-RAM"); - - break; - - case 2: - - PrintLog("CDVDiso DVD: Book Type: DVD-R"); - - break; - - case 3: - - PrintLog("CDVDiso DVD: Book Type: DVD-RW"); - - break; - - case 9: - - PrintLog("CDVDiso DVD: Book Type: DVD+RW"); - - break; - - default: - - PrintLog("CDVDiso DVD: Book Type: Unknown (%i)", layer.d.BookType); - - break; - - } // ENDSWITCH- Displaying the Book Type - - PrintLog("CDVDiso DVD: Book Version %i", layer.d.BookVersion); - - switch(layer.d.MinimumRate) { - - case 0: - - PrintLog("CDVDiso DVD: Use Minimum Rate for: DVD-ROM"); - - break; - - case 1: - - PrintLog("CDVDiso DVD: Use Minimum Rate for: DVD-RAM"); - - break; - - case 2: - - PrintLog("CDVDiso DVD: Use Minimum Rate for: DVD-R"); - - break; - - case 3: - - PrintLog("CDVDiso DVD: Use Minimum Rate for: DVD-RW"); - - break; - - case 9: - - PrintLog("CDVDiso DVD: Use Minimum Rate for: DVD+RW"); - - break; - - default: - - PrintLog("CDVDiso DVD: Use Minimum Rate for: Unknown (%i)", layer.d.MinimumRate); - - break; - - } // ENDSWITCH- Displaying the Minimum (Spin?) Rate - - switch(layer.d.DiskSize) { - - case 0: - - PrintLog("CDVDiso DVD: Physical Disk Size: 120mm"); - - break; - - case 1: - - PrintLog("CDVDiso DVD: Physical Disk Size: 80mm"); - - break; - - default: - - PrintLog("CDVDiso DVD: Physical Disk Size: Unknown (%i)", layer.d.DiskSize); - - break; - - } // ENDSWITCH- What's the Disk Size? - - switch(layer.d.LayerType) { - - case 1: - - PrintLog("CDVDiso DVD: Layer Type: Read-Only"); - - break; - - case 2: - - PrintLog("CDVDiso DVD: Layer Type: Recordable"); - - break; - - case 4: - - PrintLog("CDVDiso DVD: Layer Type: Rewritable"); - - break; - - default: - - PrintLog("CDVDiso DVD: Layer Type: Unknown (%i)", layer.d.LayerType); - - break; - - } // ENDSWITCH- Displaying the Layer Type - - switch(layer.d.TrackPath) { - - case 0: - - PrintLog("CDVDiso DVD: Track Path: PTP"); - - break; - - case 1: - - PrintLog("CDVDiso DVD: Track Path: OTP"); - - break; - - default: - - PrintLog("CDVDiso DVD: Track Path: Unknown (%i)", layer.d.TrackPath); - - break; - - } // ENDSWITCH- What's Track Path Layout? - - PrintLog("CDVDiso DVD: Number of Layers: %i", layer.d.NumberOfLayers + 1); - - switch(layer.d.TrackDensity) { - - case 0: - - PrintLog("CDVDiso DVD: Track Density: .74 m/track"); - - break; - - case 1: - - PrintLog("CDVDiso DVD: Track Density: .8 m/track"); - - break; - - case 2: - - PrintLog("CDVDiso DVD: Track Density: .615 m/track"); - - break; - - default: - - PrintLog("CDVDiso DVD: Track Density: Unknown (%i)", layer.d.TrackDensity); - - break; - - } // ENDSWITCH- Displaying the Layer Type - - switch(layer.d.LinearDensity) { - - case 0: - - PrintLog("CDVDiso DVD: Linear Density: .267 m/bit"); - - break; - - case 1: - - PrintLog("CDVDiso DVD: Linear Density: .293 m/bit"); - - break; - - case 2: - - PrintLog("CDVDiso DVD: Linear Density: .409 to .435 m/bit"); - - break; - - case 4: - - PrintLog("CDVDiso DVD: Linear Density: .280 to .291 m/bit"); - - break; - - case 8: - - PrintLog("CDVDiso DVD: Linear Density: .353 m/bit"); - - break; - - default: - - PrintLog("CDVDiso DVD: Linear Density: Unknown (%i)", layer.d.LinearDensity); - - break; - - } // ENDSWITCH- Displaying the Book Type - - if(layer.d.StartingDataSector == 0x30000) { - - PrintLog("CDVDiso DVD: Starting Sector: %lu (DVD-ROM, DVD-R, DVD-RW)", - - layer.d.StartingDataSector); - - } else if(layer.d.StartingDataSector == 0x31000) { - - PrintLog("CDVDiso DVD: Starting Sector: %lu (DVD-RAM, DVD+RW)", - - layer.d.StartingDataSector); - - } else { - - PrintLog("CDVDiso DVD: Starting Sector: %lu", layer.d.StartingDataSector); - - } // ENDLONGIF- What does the starting sector tell us? - - PrintLog("CDVDiso DVD: End of Layer 0: %lu", layer.d.EndLayerZeroSector); - - PrintLog("CDVDiso DVD: Ending Sector: %lu", layer.d.EndDataSector); - - if(layer.d.BCAFlag != 0) PrintLog("CDVDiso DVD: BCA data present"); - -#endif /* VERBOSE_DISC_INFO */ - - - - boolresult = DeviceIoControl(devicehandle, - - IOCTL_DVD_END_SESSION, - - &sessionid, - - sizeof(DVD_SESSION_ID), - - NULL, - - 0, - - &byteswritten, - - &waitevent); - - errcode = FinishCommand(boolresult); - - if(errcode != 0) { - -#ifdef VERBOSE_WARNING_DEVICE - - PrintLog("CDVDiso DVD: Couldn't end the session!"); - - PrintError("CDVDiso DVD", errcode); - -#endif /* VERBOSE_WARNING_DEVICE */ - - } // ENDIF- Couldn't end the user session? Report it. - - - - return(retval); - -} // END DVDGetStructures() - - - - - -s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer) { - - LARGE_INTEGER targetpos; - - DWORD byteswritten; - - BOOL boolresult; - - DWORD errcode; - - - -#ifdef VERBOSE_FUNCTION_DEVICE - - PrintLog("CDVDiso DVD: DVDreadTrack(%lu)", lsn); - -#endif /* VERBOSE_FUNCTION_DEVICE */ - - - - targetpos.QuadPart = lsn * 2048; - - waitevent.Offset = targetpos.LowPart; - - waitevent.OffsetHigh = targetpos.HighPart; - - - - boolresult = ReadFile(devicehandle, - - buffer, - - 2048, - - &byteswritten, - - &waitevent); - - errcode = FinishCommand(boolresult); - - - - if(errcode != 0) { - -#ifdef VERBOSE_WARNING_DEVICE - - PrintLog("CDVDiso DVD: Couldn't read sector!"); - - PrintError("CDVDiso DVD", errcode); - -#endif /* VERBOSE_WARNING_DEVICE */ - - return(-1); - - } // ENDIF- Trouble with the command? Report it. - - - - if(boolresult == FALSE) { - - boolresult = GetOverlappedResult(devicehandle, - - &waitevent, - - &byteswritten, - - FALSE); - - } // ENDIF- Did the initial call not complete? Get byteswritten for - - // the completed call. - - - - if(byteswritten < 2048) { - -#ifdef VERBOSE_WARNING_DEVICE - - errcode = GetLastError(); - - PrintLog("CDVDiso CD: Short block! only got %u out of %u bytes", - - byteswritten, 2048); - - PrintError("CDVDiso CD", errcode); - -#endif /* VERBOSE_WARNING_DEVICE */ - - return(-1); - - } // ENDIF- Didn't get enough bytes? Report and Abort! - - - - return(0); - -} // END DVDreadTrack() - - - - - -s32 DVDgetTN(cdvdTN *cdvdtn) { - -#ifdef VERBOSE_FUNCTION_DEVICE - - PrintLog("CDVDiso DVD: DVDgetTN()"); - -#endif /* VERBOSE_FUNCTION_DEVICE */ - - - - if(cdvdtn != NULL) { - - cdvdtn->strack = 1; - - cdvdtn->etrack = 1; - - } // ENDIF- Does the user really want this data? - - return(0); - -} // END DVDgetTN() - - - - - -s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd) { - -#ifdef VERBOSE_FUNCTION_DEVICE - - PrintLog("CDVDiso DVD: DVDgetTD()"); - -#endif /* VERBOSE_FUNCTION_DEVICE */ - - - - if((newtrack >= 2) && (newtrack != 0xAA)) return(-1); // Wrong track - - - - if(cdvdtd != NULL) { - - cdvdtd->type = 0; - - cdvdtd->lsn = layer.d.EndDataSector - layer.d.StartingDataSector + 1; - - } // ENDIF- Does the user really want this data? - - return(0); - -} // END DVDgetTD() - - - - - -s32 DVDgetDiskType() { - - char playstationname[] = "PLAYSTATION\0"; - - int retval; - - s32 tempdisctype; - - char tempbuffer[2048]; - - int i; - - - -#ifdef VERBOSE_FUNCTION_DEVICE - - PrintLog("CDVDiso DVD: DVDgetDiskType()"); - -#endif /* VERBOSE_FUNCTION_DEVICE */ - - - - retval = DVDGetStructures(); - - if(retval < 0) return(-1); // Can't get DVD structures? Not a DVD then. - - if(layer.d.EndDataSector == 0) return(-1); // Missing info? Abort. - - - - retval = DVDreadTrack(16, CDVD_MODE_2048, tempbuffer); - - if(retval < 0) { - - return(-1); - - } // ENDIF- Couldn't read the ISO9660 volume track? Fail. - - - - tempdisctype = CDVD_TYPE_UNKNOWN; - - if(layer.d.NumberOfLayers == 0) { - -#ifdef VERBOSE_DISC_INFO - - PrintLog("CDVDiso DVD: Found Single-Sided DVD."); - -#endif /* VERBOSE_DISC_INFO */ - - disctype = CDVD_TYPE_DETCTDVDS; - - } else { - -#ifdef VERBOSE_DISC_INFO - - PrintLog("CDVDiso DVD: Found Dual-Sided DVD."); - -#endif /* VERBOSE_DISC_INFO */ - - disctype = CDVD_TYPE_DETCTDVDD; - - } // ENDIF- Are we looking at a single layer DVD? (NumberOfLayers + 1) - - - - i = 0; - - while((playstationname[i] != 0) && - - (playstationname[i] == tempbuffer[8 + i])) i++; - - if(playstationname[i] == 0) { - -#ifdef VERBOSE_DISC_TYPE - - PrintLog("CDVDiso DVD: Found Playstation 2 DVD."); - -#endif /* VERBOSE_DISC_TYPE */ - - tempdisctype = CDVD_TYPE_PS2DVD; - - } else { - -#ifdef VERBOSE_DISC_TYPE - - PrintLog("CDVDiso DVD: Guessing it's a Video DVD."); - -#endif /* VERBOSE_DISC_TYPE */ - - tempdisctype = CDVD_TYPE_DVDV; - - } // ENDIF- Is this a playstation disc? - - - - for(i = 0; i < 2048; i++) tocbuffer[i] = 0; - - - - if(layer.d.NumberOfLayers == 0) { - - tocbuffer[0] = 0x04; - - tocbuffer[4] = 0x86; - - tocbuffer[5] = 0x72; - - } else { - - tocbuffer[0] = 0x24; - - tocbuffer[4] = 0x41; - - tocbuffer[5] = 0x95; - - } // ENDIF- Are we looking at a single layer DVD? (NumberOfLayers + 1) - - - - tocbuffer[1] = 0x02; - - tocbuffer[2] = 0xF2; - - tocbuffer[3] = 0x00; - - - - tocbuffer[16] = 0x00; - - tocbuffer[17] = 0x03; - - tocbuffer[18] = 0x00; - - tocbuffer[19] = 0x00; - - - - disctype = tempdisctype; - - return(disctype); - -} // END DVDgetDiskType() - +/* DVD.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + +#include // IOCTL_DVD... + + + +#include // off64_t + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + +#include "logfile.h" + +#include "device.h" // FinishCommand() + + + + + +struct { + + DVD_DESCRIPTOR_HEADER h; + + DVD_LAYER_DESCRIPTOR d; + +} layer; + +// DVD_LAYER_DESCRIPTOR layer; + +// DVD_COPYRIGHT_DESCRIPTOR copyright; + +// DVD_DISK_KEY_DESCRIPTOR disckey; + +// DVD_BCA_DESCRIPTOR bca; + +// DVD_MANUFACTURER_DESCRIPTOR manufact; + + + + + +void InitDVDInfo() { + + layer.d.EndDataSector = 0; + +} // END InitDVDInfo() + + + + + +s32 DVDGetStructures() { + + DVD_SESSION_ID sessionid; + + DVD_READ_STRUCTURE request; + + DWORD byteswritten; + + BOOL boolresult; + + DWORD errcode; + + s32 retval; + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso DVD: DVDgetStructures()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_DVD_START_SESSION, + + NULL, + + 0, + + &sessionid, + + sizeof(DVD_SESSION_ID), + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso DVD: Couldn't start session!"); + + PrintError("CDVDiso DVD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Couldn't start a user session on the DVD drive? Fail. + + + + request.BlockByteOffset.QuadPart = 0; + + request.Format = DvdPhysicalDescriptor; + + request.SessionId = sessionid; + + request.LayerNumber = 0; + + retval = 0; + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_DVD_READ_STRUCTURE, + + &request, + + sizeof(DVD_READ_STRUCTURE), + + &layer, + + sizeof(layer), + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso DVD: Couldn't get layer data!"); + + PrintError("CDVDiso DVD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + retval = -1; + + } // ENDIF- Couldn't get layer data? (Including DVD size) Abort. + + + +#ifdef VERBOSE_DISC_INFO + + switch(layer.d.BookType) { + + case 0: + + PrintLog("CDVDiso DVD: Book Type: DVD-ROM"); + + break; + + case 1: + + PrintLog("CDVDiso DVD: Book Type: DVD-RAM"); + + break; + + case 2: + + PrintLog("CDVDiso DVD: Book Type: DVD-R"); + + break; + + case 3: + + PrintLog("CDVDiso DVD: Book Type: DVD-RW"); + + break; + + case 9: + + PrintLog("CDVDiso DVD: Book Type: DVD+RW"); + + break; + + default: + + PrintLog("CDVDiso DVD: Book Type: Unknown (%i)", layer.d.BookType); + + break; + + } // ENDSWITCH- Displaying the Book Type + + PrintLog("CDVDiso DVD: Book Version %i", layer.d.BookVersion); + + switch(layer.d.MinimumRate) { + + case 0: + + PrintLog("CDVDiso DVD: Use Minimum Rate for: DVD-ROM"); + + break; + + case 1: + + PrintLog("CDVDiso DVD: Use Minimum Rate for: DVD-RAM"); + + break; + + case 2: + + PrintLog("CDVDiso DVD: Use Minimum Rate for: DVD-R"); + + break; + + case 3: + + PrintLog("CDVDiso DVD: Use Minimum Rate for: DVD-RW"); + + break; + + case 9: + + PrintLog("CDVDiso DVD: Use Minimum Rate for: DVD+RW"); + + break; + + default: + + PrintLog("CDVDiso DVD: Use Minimum Rate for: Unknown (%i)", layer.d.MinimumRate); + + break; + + } // ENDSWITCH- Displaying the Minimum (Spin?) Rate + + switch(layer.d.DiskSize) { + + case 0: + + PrintLog("CDVDiso DVD: Physical Disk Size: 120mm"); + + break; + + case 1: + + PrintLog("CDVDiso DVD: Physical Disk Size: 80mm"); + + break; + + default: + + PrintLog("CDVDiso DVD: Physical Disk Size: Unknown (%i)", layer.d.DiskSize); + + break; + + } // ENDSWITCH- What's the Disk Size? + + switch(layer.d.LayerType) { + + case 1: + + PrintLog("CDVDiso DVD: Layer Type: Read-Only"); + + break; + + case 2: + + PrintLog("CDVDiso DVD: Layer Type: Recordable"); + + break; + + case 4: + + PrintLog("CDVDiso DVD: Layer Type: Rewritable"); + + break; + + default: + + PrintLog("CDVDiso DVD: Layer Type: Unknown (%i)", layer.d.LayerType); + + break; + + } // ENDSWITCH- Displaying the Layer Type + + switch(layer.d.TrackPath) { + + case 0: + + PrintLog("CDVDiso DVD: Track Path: PTP"); + + break; + + case 1: + + PrintLog("CDVDiso DVD: Track Path: OTP"); + + break; + + default: + + PrintLog("CDVDiso DVD: Track Path: Unknown (%i)", layer.d.TrackPath); + + break; + + } // ENDSWITCH- What's Track Path Layout? + + PrintLog("CDVDiso DVD: Number of Layers: %i", layer.d.NumberOfLayers + 1); + + switch(layer.d.TrackDensity) { + + case 0: + + PrintLog("CDVDiso DVD: Track Density: .74 m/track"); + + break; + + case 1: + + PrintLog("CDVDiso DVD: Track Density: .8 m/track"); + + break; + + case 2: + + PrintLog("CDVDiso DVD: Track Density: .615 m/track"); + + break; + + default: + + PrintLog("CDVDiso DVD: Track Density: Unknown (%i)", layer.d.TrackDensity); + + break; + + } // ENDSWITCH- Displaying the Layer Type + + switch(layer.d.LinearDensity) { + + case 0: + + PrintLog("CDVDiso DVD: Linear Density: .267 m/bit"); + + break; + + case 1: + + PrintLog("CDVDiso DVD: Linear Density: .293 m/bit"); + + break; + + case 2: + + PrintLog("CDVDiso DVD: Linear Density: .409 to .435 m/bit"); + + break; + + case 4: + + PrintLog("CDVDiso DVD: Linear Density: .280 to .291 m/bit"); + + break; + + case 8: + + PrintLog("CDVDiso DVD: Linear Density: .353 m/bit"); + + break; + + default: + + PrintLog("CDVDiso DVD: Linear Density: Unknown (%i)", layer.d.LinearDensity); + + break; + + } // ENDSWITCH- Displaying the Book Type + + if(layer.d.StartingDataSector == 0x30000) { + + PrintLog("CDVDiso DVD: Starting Sector: %lu (DVD-ROM, DVD-R, DVD-RW)", + + layer.d.StartingDataSector); + + } else if(layer.d.StartingDataSector == 0x31000) { + + PrintLog("CDVDiso DVD: Starting Sector: %lu (DVD-RAM, DVD+RW)", + + layer.d.StartingDataSector); + + } else { + + PrintLog("CDVDiso DVD: Starting Sector: %lu", layer.d.StartingDataSector); + + } // ENDLONGIF- What does the starting sector tell us? + + PrintLog("CDVDiso DVD: End of Layer 0: %lu", layer.d.EndLayerZeroSector); + + PrintLog("CDVDiso DVD: Ending Sector: %lu", layer.d.EndDataSector); + + if(layer.d.BCAFlag != 0) PrintLog("CDVDiso DVD: BCA data present"); + +#endif /* VERBOSE_DISC_INFO */ + + + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_DVD_END_SESSION, + + &sessionid, + + sizeof(DVD_SESSION_ID), + + NULL, + + 0, + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso DVD: Couldn't end the session!"); + + PrintError("CDVDiso DVD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + } // ENDIF- Couldn't end the user session? Report it. + + + + return(retval); + +} // END DVDGetStructures() + + + + + +s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer) { + + LARGE_INTEGER targetpos; + + DWORD byteswritten; + + BOOL boolresult; + + DWORD errcode; + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso DVD: DVDreadTrack(%lu)", lsn); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + targetpos.QuadPart = lsn * 2048; + + waitevent.Offset = targetpos.LowPart; + + waitevent.OffsetHigh = targetpos.HighPart; + + + + boolresult = ReadFile(devicehandle, + + buffer, + + 2048, + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso DVD: Couldn't read sector!"); + + PrintError("CDVDiso DVD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Trouble with the command? Report it. + + + + if(boolresult == FALSE) { + + boolresult = GetOverlappedResult(devicehandle, + + &waitevent, + + &byteswritten, + + FALSE); + + } // ENDIF- Did the initial call not complete? Get byteswritten for + + // the completed call. + + + + if(byteswritten < 2048) { + +#ifdef VERBOSE_WARNING_DEVICE + + errcode = GetLastError(); + + PrintLog("CDVDiso CD: Short block! only got %u out of %u bytes", + + byteswritten, 2048); + + PrintError("CDVDiso CD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Didn't get enough bytes? Report and Abort! + + + + return(0); + +} // END DVDreadTrack() + + + + + +s32 DVDgetTN(cdvdTN *cdvdtn) { + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso DVD: DVDgetTN()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + if(cdvdtn != NULL) { + + cdvdtn->strack = 1; + + cdvdtn->etrack = 1; + + } // ENDIF- Does the user really want this data? + + return(0); + +} // END DVDgetTN() + + + + + +s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd) { + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso DVD: DVDgetTD()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + if((newtrack >= 2) && (newtrack != 0xAA)) return(-1); // Wrong track + + + + if(cdvdtd != NULL) { + + cdvdtd->type = 0; + + cdvdtd->lsn = layer.d.EndDataSector - layer.d.StartingDataSector + 1; + + } // ENDIF- Does the user really want this data? + + return(0); + +} // END DVDgetTD() + + + + + +s32 DVDgetDiskType() { + + char playstationname[] = "PLAYSTATION\0"; + + int retval; + + s32 tempdisctype; + + char tempbuffer[2048]; + + int i; + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso DVD: DVDgetDiskType()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + retval = DVDGetStructures(); + + if(retval < 0) return(-1); // Can't get DVD structures? Not a DVD then. + + if(layer.d.EndDataSector == 0) return(-1); // Missing info? Abort. + + + + retval = DVDreadTrack(16, CDVD_MODE_2048, tempbuffer); + + if(retval < 0) { + + return(-1); + + } // ENDIF- Couldn't read the ISO9660 volume track? Fail. + + + + tempdisctype = CDVD_TYPE_UNKNOWN; + + if(layer.d.NumberOfLayers == 0) { + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVDiso DVD: Found Single-Sided DVD."); + +#endif /* VERBOSE_DISC_INFO */ + + disctype = CDVD_TYPE_DETCTDVDS; + + } else { + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVDiso DVD: Found Dual-Sided DVD."); + +#endif /* VERBOSE_DISC_INFO */ + + disctype = CDVD_TYPE_DETCTDVDD; + + } // ENDIF- Are we looking at a single layer DVD? (NumberOfLayers + 1) + + + + i = 0; + + while((playstationname[i] != 0) && + + (playstationname[i] == tempbuffer[8 + i])) i++; + + if(playstationname[i] == 0) { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("CDVDiso DVD: Found Playstation 2 DVD."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_PS2DVD; + + } else { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("CDVDiso DVD: Guessing it's a Video DVD."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_DVDV; + + } // ENDIF- Is this a playstation disc? + + + + for(i = 0; i < 2048; i++) tocbuffer[i] = 0; + + + + if(layer.d.NumberOfLayers == 0) { + + tocbuffer[0] = 0x04; + + tocbuffer[4] = 0x86; + + tocbuffer[5] = 0x72; + + } else { + + tocbuffer[0] = 0x24; + + tocbuffer[4] = 0x41; + + tocbuffer[5] = 0x95; + + } // ENDIF- Are we looking at a single layer DVD? (NumberOfLayers + 1) + + + + tocbuffer[1] = 0x02; + + tocbuffer[2] = 0xF2; + + tocbuffer[3] = 0x00; + + + + tocbuffer[16] = 0x00; + + tocbuffer[17] = 0x03; + + tocbuffer[18] = 0x00; + + tocbuffer[19] = 0x00; + + + + disctype = tempdisctype; + + return(disctype); + +} // END DVDgetDiskType() + diff --git a/plugins/CDVDisoEFP/src/Win32/DVD.h b/plugins/CDVDisoEFP/src/Win32/DVD.h index 3876101750..b6d05d0e29 100644 --- a/plugins/CDVDisoEFP/src/Win32/DVD.h +++ b/plugins/CDVDisoEFP/src/Win32/DVD.h @@ -1,37 +1,74 @@ -/* DVD.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef DVD_H -#define DVD_H - - -#define CDVDdefs -#include "PS2Edefs.h" - - -extern void InitDVDInfo(); -extern s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer); -extern s32 DVDgetTN(cdvdTN *cdvdtn); -extern s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd); -extern s32 DVDgetDiskType(); - - -#endif /* DVD_H */ +/* DVD.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef DVD_H + +#define DVD_H + + + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + + + +extern void InitDVDInfo(); + +extern s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer); + +extern s32 DVDgetTN(cdvdTN *cdvdtn); + +extern s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd); + +extern s32 DVDgetDiskType(); + + + + + +#endif /* DVD_H */ + diff --git a/plugins/CDVDisoEFP/src/Win32/Makefile.MinGW32 b/plugins/CDVDisoEFP/src/Win32/Makefile.MinGW32 deleted file mode 100644 index d499a79abd..0000000000 --- a/plugins/CDVDisoEFP/src/Win32/Makefile.MinGW32 +++ /dev/null @@ -1,59 +0,0 @@ -all: plugin - -PLUGIN = CDVDisoEFP.dll -CC = mingw32-gcc.exe - -PLUGINOBJS = CDVDiso.o mainbox.o tablerebuild.o progressbox.o conversionbox.o \ - devicebox.o device.o DVD.o CD.o -PLUGINHEADERS = CDVDiso.h mainbox.h tablerebuild.h progressbox.h conversionbox.h \ - devicebox.h device.h DVD.h CD.h -PLUGINFLAGS = -Wall -O2 -D_WIN32 -D_LARGEFILE64_SOURCE -I.. -I. -I./Win32 -mwindows -PLUGINLIBS = -L./ -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 -lkernel32 \ - -luser32 --subsystem,windows -# Note: Don't think we need all the above libs... will pare down later. - -SHAREDOBJS = ..\\version.o conf.o ..\\isofile.o actualfile.o logfile.o \ - ..\\imagetype.o ..\\multifile.o ..\\isocompress.o ..\\convert.o \ - ..\\gzipv1.o ..\\blockv2.o ..\\gzipv2.o ..\\bzip2v2.o ..\\ecma119.o \ - ..\\toc.o ..\\ini.o ..\\bzip2v3.o \ - ..\\zlib\\adler32.o ..\\zlib\\compress.o ..\\zlib\\crc32.o \ - ..\\zlib\\gzio.o ..\\zlib\\uncompr.o ..\\zlib\\deflate.o \ - ..\\zlib\\trees.o ..\\zlib\\zutil.o ..\\zlib\\inflate.o \ - ..\\zlib\\infback.o ..\\zlib\\inftrees.o ..\\zlib\\inffast.o \ - ..\\bzip2\\blocksort.o ..\\bzip2\\bzlib.o ..\\bzip2\\compress.o \ - ..\\bzip2\\crctable.o ..\\bzip2\\decompress.o ..\\bzip2\\huffman.o \ - ..\\bzip2\\randtable.o -SHAREDHEADERS = ..\\version.h conf.h ..\\isofile.h actualfile.h logfile.h \ - ..\\imagetype.h ..\\multifile.h ..\\isocompress.h ..\\convert.h \ - ..\\gzipv1.h ..\\blockv2.o ..\\gzipv2.h ..\\bzip2v2.h ..\\ecma119.h \ - ..\\toc.h ..\\ini.h ..\\bzip2v3.o - - - -WINDRES = windres.exe - - - -release: plugin - copy $(PLUGIN) ..\\.. - -plugin: $(PLUGINOBJS) $(SHAREDOBJS) screens.res - -del $(PLUGIN) - dllwrap --def plugin.def -o $(PLUGIN) $(PLUGINOBJS) screens.res $(SHAREDOBJS) $(PLUGINLIBS) - strip --strip-unneeded --strip-debug $(PLUGIN) - -$(PLUGINOBJS) $(SHAREDOBJS): %.o: %.c - $(CC) $(PLUGINFLAGS) -c $< -o $@ - -screens.res: screens.rc - $(WINDRES) -i screens.rc -J rc -o screens.res -O coff - -.PHONY : clean allclean -clean: - -del $(PLUGINOBJS) $(PLUGIN) $(SHAREDOBJS) screens.res - -allclean: - -del $(PLUGINOBJS) $(PLUGIN) $(SHAREDOBJS) screens.res - -del temp.txt err.txt ..\\temp.txt ..\\err.txt - -del ..\\..\\$(PLUGIN) - diff --git a/plugins/CDVDisoEFP/src/Win32/Makefile.MinGW32.bak b/plugins/CDVDisoEFP/src/Win32/Makefile.MinGW32.bak deleted file mode 100644 index 6e9077ff01..0000000000 --- a/plugins/CDVDisoEFP/src/Win32/Makefile.MinGW32.bak +++ /dev/null @@ -1,57 +0,0 @@ - -PLUGIN = CDVDisoEFP.dll -PLUGINOBJS = CDVDiso.o mainbox.o tablerebuild.o progressbox.o conversionbox.o \ - devicebox.o device.o DVD.o CD.o -PLUGINHEADERS = CDVDiso.h mainbox.h tablerebuild.h progressbox.h conversionbox.h \ - devicebox.h device.h DVD.h CD.h -PLUGINFLAGS = -Wall -O2 -D_LARGEFILE64_SOURCE -I.. -I. -I./Win32 -mwindows -PLUGINLIBS = -L./ -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 -lkernel32 \ - -luser32 --subsystem,windows -# Note: Don't think we need all the above libs... will pare down later. - -SHAREDOBJS = ..\\version.o conf.o ..\\isofile.o actualfile.o logfile.o \ - ..\\imagetype.o ..\\multifile.o ..\\isocompress.o ..\\convert.o \ - ..\\gzipv1.o ..\\blockv2.o ..\\gzipv2.o ..\\bzip2v2.o ..\\ecma119.o \ - ..\\toc.o ..\\ini.o ..\\bzip2v3.o \ - ..\\zlib\\adler32.o ..\\zlib\\compress.o ..\\zlib\\crc32.o \ - ..\\zlib\\gzio.o ..\\zlib\\uncompr.o ..\\zlib\\deflate.o \ - ..\\zlib\\trees.o ..\\zlib\\zutil.o ..\\zlib\\inflate.o \ - ..\\zlib\\infback.o ..\\zlib\\inftrees.o ..\\zlib\\inffast.o \ - ..\\bzip2\\blocksort.o ..\\bzip2\\bzlib.o ..\\bzip2\\compress.o \ - ..\\bzip2\\crctable.o ..\\bzip2\\decompress.o ..\\bzip2\\huffman.o \ - ..\\bzip2\\randtable.o -SHAREDHEADERS = ..\\version.h conf.h ..\\isofile.h actualfile.h logfile.h \ - ..\\imagetype.h ..\\multifile.h ..\\isocompress.h ..\\convert.h \ - ..\\gzipv1.h ..\\blockv2.o ..\\gzipv2.h ..\\bzip2v2.h ..\\ecma119.h \ - ..\\toc.h ..\\ini.h ..\\bzip2v3.o - - -CC = mingw32-gcc.exe -WINDRES = windres.exe - - -all: plugin - -release: plugin - copy $(PLUGIN) ..\\.. - -plugin: $(PLUGINOBJS) $(SHAREDOBJS) screens.res - -del $(PLUGIN) - dllwrap --def plugin.def -o $(PLUGIN) $(PLUGINOBJS) screens.res $(SHAREDOBJS) $(PLUGINLIBS) - strip --strip-unneeded --strip-debug $(PLUGIN) - -$(PLUGINOBJS) $(SHAREDOBJS): %.o: %.c - $(CC) $(PLUGINFLAGS) -c $< -o $@ - -screens.res: screens.rc - $(WINDRES) -i screens.rc -J rc -o screens.res -O coff - -.PHONY : clean allclean -clean: - -del $(PLUGINOBJS) $(PLUGIN) $(SHAREDOBJS) screens.res - -allclean: - -del $(PLUGINOBJS) $(PLUGIN) $(SHAREDOBJS) screens.res - -del temp.txt err.txt ..\\temp.txt ..\\err.txt - -del ..\\..\\$(PLUGIN) - diff --git a/plugins/CDVDisoEFP/src/Win32/conf.c b/plugins/CDVDisoEFP/src/Win32/conf.c index 467a317b1a..abc603e9cd 100644 --- a/plugins/CDVDisoEFP/src/Win32/conf.c +++ b/plugins/CDVDisoEFP/src/Win32/conf.c @@ -1,195 +1,390 @@ -/* conf.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - -#include // errno -#include // NULL -#include // sprintf() -#include // getenv() -#include // strerror() -#include // mkdir(), stat() -#include // mkdir(), stat(), fork() -#include // stat(), fork(), execlp() - -#include // CreateProcess() - -// #define CDVDdefs -// #include "../PS2Edefs.h" -#include "../PS2Etypes.h" // u8 -#include "logfile.h" -#include "../ini.h" -#include "conf.h" - - -const char *confnames[] = { "IsoFile", "Device", "OpenOnStart", "OpenOnRestart", NULL }; -const u8 defaultdevice[] = DEFAULT_DEVICE; -const char defaulthome[] = "inis"; -const char defaultdirectory[] = "HideMe.PS2E"; -const char defaultfile[] = "CDVDisoEFP.ini"; - -char confdirname[256]; -char conffilename[256]; - -CDVDconf conf; - - -void InitConf() { - DWORD retval; - int i; - int pos; - char *envptr; - -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVD config: InitConf()"); -#endif /* VERBOSE_FUNCTION_CONF */ - - conf.isoname[0] = 0; // Empty the iso name - - i = 0; - while((i < 255) && defaultdevice[i] != 0) { - conf.devicename[i] = defaultdevice[i]; - i++; - } // ENDWHILE- copying the default CD/DVD name in - conf.devicename[i] = 0; // 0-terminate the device name - - // Locating directory and file positions - pos = 0; - envptr = NULL; - // envptr = getenv("HOME"); - if(envptr == NULL) { - // = - retval = GetCurrentDirectory(253, confdirname); - if(retval > 0) { - pos = retval; - } else { - pos = 2; - confdirname[0] = '.'; - confdirname[1] = '\\'; - } // ENDIF- Did we retrieve a directory reference? - - i = 0; - while(i < pos) { - conffilename[i] = confdirname[i]; - i++; - } // ENDWHILE- Copying dir info (so far) into file info - - if(confdirname[pos-1] != '\\') { - confdirname[pos] = '\\'; - conffilename[pos] = '\\'; - pos++; - } // ENDIF- No directory separator here? Add one. - - i = 0; - while((pos < 253) && (defaulthome[i] != 0)) { - confdirname[pos] = defaulthome[i]; - conffilename[pos] = defaulthome[i]; - pos++; - i++; - } // ENDWHILE- putting an offset where to store ini data - - } else { - // = / - i = 0; - while((pos < 253) && (*(envptr + i) != 0)) { - confdirname[pos] = *(envptr + i); - conffilename[pos] = *(envptr + i); - pos++; - i++; - } // ENDWHILE- copying home directory info in - - if(confdirname[pos-1] != '\\') { - confdirname[pos] = '\\'; - conffilename[pos] = '\\'; - pos++; - } // ENDIF- No directory separator here? Add one. - - i = 0; - while((pos < 253) && (defaultdirectory[i] != 0)) { - confdirname[pos] = defaultdirectory[i]; - conffilename[pos] = defaultdirectory[i]; - pos++; - i++; - } // NEXT- putting a default place to store configuration data - } // ENDIF- No Home directory? - - confdirname[pos] = 0; // Directory reference finished - - // += / - if(conffilename[pos-1] != '\\') { - conffilename[pos] = '\\'; - pos++; - } // ENDIF- No directory separator here? Add one. - - i = 0; - while((pos < 253) && (defaultfile[i] != 0)) { - conffilename[pos] = defaultfile[i]; - pos++; - i++; - } // NEXT- putting a default place to store configuration data - - conffilename[pos] = 0; // File reference finished - -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVD config: Directory: %s", confdirname); - PrintLog("CDVD config: File: %s", conffilename); -#endif /* VERBOSE_FUNCTION_CONF */ -} // END InitConf() - - -void LoadConf() { - int retval; - -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVD config: LoadConf()"); -#endif /* VERBOSE_FUNCTION_CONF */ - - retval = INILoadString(conffilename, "Settings", "IsoFile", conf.isoname); - if(retval < 0) { - sprintf(conf.isoname, "[Put an Image File here]"); - } // ENDIF- Couldn't find keyword? Fill in a default - - retval = INILoadString(conffilename, "Settings", "Device", conf.devicename); - if(retval < 0) { - sprintf(conf.devicename, "D:"); - } // ENDIF- Couldn't find keyword? Fill in a default - - retval = INILoadUInt(conffilename, "Settings", "OpenOnStart", &conf.startconfigure); - if(retval < 0) { - conf.startconfigure = 0; // FALSE - } // ENDIF- Couldn't find keyword? Fill in a default - - retval = INILoadUInt(conffilename, "Settings", "OpenOnRestart", &conf.restartconfigure); - if(retval < 0) { - conf.restartconfigure = 1; // TRUE - } // ENDIF- Couldn't find keyword? Fill in a default -} // END LoadConf() - - -void SaveConf() { -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVD config: SaveConf()"); -#endif /* VERBOSE_FUNCTION_CONF */ - - mkdir(confdirname); - - INISaveString(conffilename, "Settings", "IsoFile", conf.isoname); - INISaveString(conffilename, "Settings", "Device", conf.devicename); - INISaveUInt(conffilename, "Settings", "OpenOnStart", conf.startconfigure); - INISaveUInt(conffilename, "Settings", "OpenOnRestart", conf.restartconfigure); -} // END SaveConf() +/* conf.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + +#include // errno + +#include // NULL + +#include // sprintf() + +#include // getenv() + +#include // strerror() + +#include // mkdir(), stat() + +#include // mkdir(), stat(), fork() + +#include // stat(), fork(), execlp() + + + +#include // CreateProcess() + + + +// #define CDVDdefs + +// #include "../PS2Edefs.h" + +#include "../PS2Etypes.h" // u8 + +#include "logfile.h" + +#include "../ini.h" + +#include "conf.h" + + + + + +const char *confnames[] = { "IsoFile", "Device", "OpenOnStart", "OpenOnRestart", NULL }; + +const u8 defaultdevice[] = DEFAULT_DEVICE; + +const char defaulthome[] = "inis"; + +const char defaultdirectory[] = "HideMe.PS2E"; + +const char defaultfile[] = "CDVDisoEFP.ini"; + + + +char confdirname[256]; + +char conffilename[256]; + + + +CDVDconf conf; + + + + + +void InitConf() { + + DWORD retval; + + int i; + + int pos; + + char *envptr; + + + +#ifdef VERBOSE_FUNCTION_CONF + + PrintLog("CDVD config: InitConf()"); + +#endif /* VERBOSE_FUNCTION_CONF */ + + + + conf.isoname[0] = 0; // Empty the iso name + + + + i = 0; + + while((i < 255) && defaultdevice[i] != 0) { + + conf.devicename[i] = defaultdevice[i]; + + i++; + + } // ENDWHILE- copying the default CD/DVD name in + + conf.devicename[i] = 0; // 0-terminate the device name + + + + // Locating directory and file positions + + pos = 0; + + envptr = NULL; + + // envptr = getenv("HOME"); + + if(envptr == NULL) { + + // = + + retval = GetCurrentDirectory(253, confdirname); + + if(retval > 0) { + + pos = retval; + + } else { + + pos = 2; + + confdirname[0] = '.'; + + confdirname[1] = '\\'; + + } // ENDIF- Did we retrieve a directory reference? + + + + i = 0; + + while(i < pos) { + + conffilename[i] = confdirname[i]; + + i++; + + } // ENDWHILE- Copying dir info (so far) into file info + + + + if(confdirname[pos-1] != '\\') { + + confdirname[pos] = '\\'; + + conffilename[pos] = '\\'; + + pos++; + + } // ENDIF- No directory separator here? Add one. + + + + i = 0; + + while((pos < 253) && (defaulthome[i] != 0)) { + + confdirname[pos] = defaulthome[i]; + + conffilename[pos] = defaulthome[i]; + + pos++; + + i++; + + } // ENDWHILE- putting an offset where to store ini data + + + + } else { + + // = / + + i = 0; + + while((pos < 253) && (*(envptr + i) != 0)) { + + confdirname[pos] = *(envptr + i); + + conffilename[pos] = *(envptr + i); + + pos++; + + i++; + + } // ENDWHILE- copying home directory info in + + + + if(confdirname[pos-1] != '\\') { + + confdirname[pos] = '\\'; + + conffilename[pos] = '\\'; + + pos++; + + } // ENDIF- No directory separator here? Add one. + + + + i = 0; + + while((pos < 253) && (defaultdirectory[i] != 0)) { + + confdirname[pos] = defaultdirectory[i]; + + conffilename[pos] = defaultdirectory[i]; + + pos++; + + i++; + + } // NEXT- putting a default place to store configuration data + + } // ENDIF- No Home directory? + + + + confdirname[pos] = 0; // Directory reference finished + + + + // += / + + if(conffilename[pos-1] != '\\') { + + conffilename[pos] = '\\'; + + pos++; + + } // ENDIF- No directory separator here? Add one. + + + + i = 0; + + while((pos < 253) && (defaultfile[i] != 0)) { + + conffilename[pos] = defaultfile[i]; + + pos++; + + i++; + + } // NEXT- putting a default place to store configuration data + + + + conffilename[pos] = 0; // File reference finished + + + +#ifdef VERBOSE_FUNCTION_CONF + + PrintLog("CDVD config: Directory: %s", confdirname); + + PrintLog("CDVD config: File: %s", conffilename); + +#endif /* VERBOSE_FUNCTION_CONF */ + +} // END InitConf() + + + + + +void LoadConf() { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_CONF + + PrintLog("CDVD config: LoadConf()"); + +#endif /* VERBOSE_FUNCTION_CONF */ + + + + retval = INILoadString(conffilename, "Settings", "IsoFile", conf.isoname); + + if(retval < 0) { + + sprintf(conf.isoname, "[Put an Image File here]"); + + } // ENDIF- Couldn't find keyword? Fill in a default + + + + retval = INILoadString(conffilename, "Settings", "Device", conf.devicename); + + if(retval < 0) { + + sprintf(conf.devicename, "D:"); + + } // ENDIF- Couldn't find keyword? Fill in a default + + + + retval = INILoadUInt(conffilename, "Settings", "OpenOnStart", &conf.startconfigure); + + if(retval < 0) { + + conf.startconfigure = 0; // FALSE + + } // ENDIF- Couldn't find keyword? Fill in a default + + + + retval = INILoadUInt(conffilename, "Settings", "OpenOnRestart", &conf.restartconfigure); + + if(retval < 0) { + + conf.restartconfigure = 1; // TRUE + + } // ENDIF- Couldn't find keyword? Fill in a default + +} // END LoadConf() + + + + + +void SaveConf() { + +#ifdef VERBOSE_FUNCTION_CONF + + PrintLog("CDVD config: SaveConf()"); + +#endif /* VERBOSE_FUNCTION_CONF */ + + + + mkdir(confdirname); + + + + INISaveString(conffilename, "Settings", "IsoFile", conf.isoname); + + INISaveString(conffilename, "Settings", "Device", conf.devicename); + + INISaveUInt(conffilename, "Settings", "OpenOnStart", conf.startconfigure); + + INISaveUInt(conffilename, "Settings", "OpenOnRestart", conf.restartconfigure); + +} // END SaveConf() + diff --git a/plugins/CDVDisoEFP/src/Win32/conf.h b/plugins/CDVDisoEFP/src/Win32/conf.h index 42bb401da6..e490985a89 100644 --- a/plugins/CDVDisoEFP/src/Win32/conf.h +++ b/plugins/CDVDisoEFP/src/Win32/conf.h @@ -1,54 +1,108 @@ -/* conf.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - -#ifndef CONF_H -#define CONF_H - - -#define CDVDdefs -#include "../PS2Edefs.h" - - -#define VERBOSE_FUNCTION_CONF - - -// Configuration Data - -typedef struct { - u8 isoname[256]; - u8 devicename[256]; - unsigned int startconfigure; - unsigned int restartconfigure; -} CDVDconf; -extern CDVDconf conf; - -#define DEFAULT_DEVICE "K:\\" - - -// Configuration Functions - -extern void InitConf(); -extern void LoadConf(); -extern void SaveConf(); - -extern void ExecCfg(char *arg); - - -#endif /* CONF_H */ +/* conf.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + +#ifndef CONF_H + +#define CONF_H + + + + + +#define CDVDdefs + +#include "../PS2Edefs.h" + + + + + +#define VERBOSE_FUNCTION_CONF + + + + + +// Configuration Data + + + +typedef struct { + + u8 isoname[256]; + + u8 devicename[256]; + + unsigned int startconfigure; + + unsigned int restartconfigure; + +} CDVDconf; + +extern CDVDconf conf; + + + +#define DEFAULT_DEVICE "K:\\" + + + + + +// Configuration Functions + + + +extern void InitConf(); + +extern void LoadConf(); + +extern void SaveConf(); + + + +extern void ExecCfg(char *arg); + + + + + +#endif /* CONF_H */ + diff --git a/plugins/CDVDisoEFP/src/Win32/conversionbox.c b/plugins/CDVDisoEFP/src/Win32/conversionbox.c index 03ee140015..ea78fc622a 100644 --- a/plugins/CDVDisoEFP/src/Win32/conversionbox.c +++ b/plugins/CDVDisoEFP/src/Win32/conversionbox.c @@ -1,750 +1,750 @@ -/* conversionbox.c - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#include - -#include // ComboBox_AddString(), CheckDlgButton() - -#include // NULL - -// #include - - - -#include // sprintf() - -#include // strcpy() - -#include // off64_t - - - -#include "isofile.h" - -#include "isocompress.h" // compressdesc[] - -#include "imagetype.h" // imagedata[] - -#include "multifile.h" // multinames[] - -#include "toc.h" - -#include "progressbox.h" - -#include "mainbox.h" - -#include "screens.h" // DLG_..., IDC_... - -#include "conversionbox.h" - - - - - -HWND conversionboxwindow; - - - - - -void ConversionBoxDestroy() { - - if(conversionboxwindow != NULL) { - - EndDialog(conversionboxwindow, FALSE); - - conversionboxwindow = NULL; - - } // ENDIF- Do we have a Main Window still? - -} // END ConversionBoxDestroy() - - - - - -void ConversionBoxUnfocus() { - - // gtk_widget_set_sensitive(conversionbox.file, FALSE); - - // gtk_widget_set_sensitive(conversionbox.selectbutton, FALSE); - - // gtk_widget_set_sensitive(conversionbox.compress, FALSE); - - // gtk_widget_set_sensitive(conversionbox.multi, FALSE); - - // gtk_widget_set_sensitive(conversionbox.okbutton, FALSE); - - // gtk_widget_set_sensitive(conversionbox.cancelbutton, FALSE); - - ShowWindow(conversionboxwindow, SW_HIDE); - -} // END ConversionBoxUnfocus() - - - - - -void ConversionBoxFileEvent() { - - int returnval; - - char templine[256]; - - struct IsoFile *tempfile; - - - - GetDlgItemText(conversionboxwindow, IDC_0402, templine, 256); - - returnval = IsIsoFile(templine); - - if(returnval == -1) { - - SetDlgItemText(conversionboxwindow, IDC_0404, "File Type: ---"); - - return; - - } // ENDIF- Not a name of any sort? - - - - if(returnval == -2) { - - SetDlgItemText(conversionboxwindow, IDC_0404, "File Type: Not a file"); - - return; - - } // ENDIF- Not a regular file? - - - - if(returnval == -3) { - - SetDlgItemText(conversionboxwindow, IDC_0404, "File Type: Not a valid image file"); - - return; - - } // ENDIF- Not a regular file? - - - - if(returnval == -4) { - - SetDlgItemText(conversionboxwindow, IDC_0404, "File Type: Missing Table File (will rebuild)"); - - return; - - } // ENDIF- Not a regular file? - - - - tempfile = IsoFileOpenForRead(templine); - - sprintf(templine, "File Type: %s%s%s", - - multinames[tempfile->multi], - - tempfile->imagename, - - compressdesc[tempfile->compress]); - - SetDlgItemText(conversionboxwindow, IDC_0404, templine); - - tempfile = IsoFileClose(tempfile); - - return; - -} // END ConversionBoxFileEvent() - - - - - -void ConversionBoxRefocus() { - - ConversionBoxFileEvent(); - - - - // gtk_widget_set_sensitive(conversionbox.file, TRUE); - - // gtk_widget_set_sensitive(conversionbox.selectbutton, TRUE); - - // gtk_widget_set_sensitive(conversionbox.compress, TRUE); - - // gtk_widget_set_sensitive(conversionbox.multi, TRUE); - - // gtk_widget_set_sensitive(conversionbox.okbutton, TRUE); - - // gtk_widget_set_sensitive(conversionbox.cancelbutton, TRUE); - - // gtk_window_set_focus(GTK_WINDOW(conversionbox.window), conversionbox.file); - - ShowWindow(conversionboxwindow, SW_SHOW); - - SetActiveWindow(conversionboxwindow); - -} // END ConversionBoxRefocus() - - - - - -void ConversionBoxCancelEvent() { - - // ShowWindow(conversionboxwindow, SW_HIDE); - - ConversionBoxDestroy(); - - MainBoxRefocus(); - - return; - -} // END ConversionBoxCancelEvent() - - - - - -void ConversionBoxOKEvent() { - - char templine[256]; - - char tempblock[2352]; - - char filename[256]; - - HWND tempitem; - - int compressmethod; - - int multi; - - struct IsoFile *fromfile; - - struct IsoFile *tofile; - - int i; - - off64_t endsector; - - int stop; - - int retval; - - - - ConversionBoxUnfocus(); - - - - GetDlgItemText(conversionboxwindow, IDC_0402, filename, 256); - - if(IsIsoFile(filename) < 0) { - - ConversionBoxRefocus(); - - MessageBox(conversionboxwindow, - - "Not a Valid Image File.", - - "CDVDisoEFP Message", - - MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); - - return; - - } // ENDIF- Not an Iso File? Stop early. - - - - tempitem = GetDlgItem(conversionboxwindow, IDC_0406); - - compressmethod = ComboBox_GetCurSel(tempitem); - - tempitem = NULL; - - if(compressmethod > 0) compressmethod += 2; - - - - multi = 0; - - if(IsDlgButtonChecked(conversionboxwindow, IDC_0408)) multi = 1; - - - - fromfile = NULL; - - fromfile = IsoFileOpenForRead(filename); - - if(fromfile == NULL) { - - ConversionBoxRefocus(); - - MessageBox(conversionboxwindow, - - "Cannot opening the source file", - - "CDVDisoEFP Message", - - MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); - - return; - - } // ENDIF- Not an Iso File? Stop early. - - - - if((compressmethod == fromfile->compress) && - - (multi == fromfile->multi)) { - - fromfile = IsoFileClose(fromfile); - - ConversionBoxRefocus(); - - MessageBox(conversionboxwindow, - - "Compress/Multifile methods match - no need to convert", - - "CDVDisoEFP Message", - - MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); - - return; - - } // ENDIF- Not an Iso File? Stop early. - - - - tofile = IsoFileOpenForWrite(filename, - - GetImageTypeConvertTo(fromfile->imagetype), - - multi, - - compressmethod); - - if(tofile == NULL) { - - fromfile = IsoFileClose(fromfile); - - ConversionBoxRefocus(); - - MessageBox(conversionboxwindow, - - "Cannot create the new file", - - "CDVDisoEFP Message", - - MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); - - return; - - } // ENDIF- Not an Iso File? Stop early. - - - - if(fromfile->multi == 1) { - - i = 0; - - while((i < 10) && - - (IsoFileSeek(fromfile, fromfile->multisectorend[i] + 1) == 0)) i++; - - endsector = fromfile->multisectorend[fromfile->multiend]; - - } else { - - endsector = fromfile->filesectorsize; - - } // ENDIF- Get ending sector from multifile? (Or single file?) - - IsoFileSeek(fromfile, 0); - - - - // Open Progress Bar - - sprintf(templine, "%s: %s%s -> %s%s", - - filename, - - multinames[fromfile->multi], - - compressdesc[fromfile->compress], - - multinames[tofile->multi], - - compressdesc[tofile->compress]); - - ProgressBoxStart(templine, endsector); - - - - tofile->cdvdtype = fromfile->cdvdtype; - - for(i = 0; i < 2048; i++) tofile->toc[i] = fromfile->toc[i]; - - - - stop = 0; - - mainboxstop = 0; - - progressboxstop = 0; - - while((stop == 0) && (tofile->sectorpos < endsector)) { - - retval = IsoFileRead(fromfile, tempblock); - - if(retval < 0) { - - MessageBox(conversionboxwindow, - - "Trouble reading source file", - - "CDVDisoEFP Message", - - MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); - - stop = 1; - - } else { - - retval = IsoFileWrite(tofile, tempblock); - - if(retval < 0) { - - MessageBox(conversionboxwindow, - - "Trouble writing new file", - - "CDVDisoEFP Message", - - MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); - - stop = 1; - - } // ENDIF- Trouble writing out the next block? - - } // ENDIF- Trouble reading in the next block? - - - - ProgressBoxTick(tofile->sectorpos); - - - - if(mainboxstop != 0) stop = 2; - - if(progressboxstop != 0) stop = 2; - - } // ENDWHILE- Not stopped for some reason... - - - - ProgressBoxStop(); - - - - if(stop == 0) { - - if(tofile->multi == 1) tofile->name[tofile->multipos] = '0'; // First file - - strcpy(templine, tofile->name); - - - - // fromfile = IsoFileCloseAndDelete(fromfile); - - fromfile = IsoFileClose(fromfile); - - - - IsoSaveTOC(tofile); - - tofile = IsoFileClose(tofile); - - SetDlgItemText(mainboxwindow, IDC_0202, templine); - - - - } else { - - fromfile = IsoFileClose(fromfile); - - tofile = IsoFileCloseAndDelete(tofile); - - } // ENDIF- Did we succeed in the transfer? - - - - ConversionBoxRefocus(); - - if(stop == 0) ConversionBoxCancelEvent(); - - return; - -} // END ConversionBoxOKEvent() - - - - - -void ConversionBoxBrowseEvent() { - - OPENFILENAME filebox; - - char newfilename[256]; - - BOOL returnbool; - - - - filebox.lStructSize = sizeof(filebox); - - filebox.hwndOwner = conversionboxwindow; - - filebox.hInstance = NULL; - - filebox.lpstrFilter = fileselection; - - filebox.lpstrCustomFilter = NULL; - - filebox.nFilterIndex = 0; - - filebox.lpstrFile = newfilename; - - filebox.nMaxFile = 256; - - filebox.lpstrFileTitle = NULL; - - filebox.nMaxFileTitle = 0; - - filebox.lpstrInitialDir = NULL; - - filebox.lpstrTitle = NULL; - - filebox.Flags = OFN_FILEMUSTEXIST - - | OFN_NOCHANGEDIR - - | OFN_HIDEREADONLY; - - filebox.nFileOffset = 0; - - filebox.nFileExtension = 0; - - filebox.lpstrDefExt = NULL; - - filebox.lCustData = 0; - - filebox.lpfnHook = NULL; - - filebox.lpTemplateName = NULL; - - - - GetDlgItemText(conversionboxwindow, IDC_0402, newfilename, 256); - - returnbool = GetOpenFileName(&filebox); - - if(returnbool != FALSE) { - - SetDlgItemText(conversionboxwindow, IDC_0402, newfilename); - - } // ENDIF- User actually selected a name? Save it. - - - - return; - -} // END ConversionBoxBrowseEvent() - - - - - -void ConversionBoxDisplay() { - - char templine[256]; - - HWND itemptr; - - int itemcount; - - - - // Adjust window position? - - - - // Pull the name from the Main Window... for a starting place. - - GetDlgItemText(mainboxwindow, IDC_0202, templine, 256); - - SetDlgItemText(conversionboxwindow, IDC_0402, templine); - - - - // ConversionBoxFileEvent(); // Needed? - - - - itemptr = GetDlgItem(conversionboxwindow, IDC_0406); // Compression Combo - - itemcount = 0; - - while(compressnames[itemcount] != NULL) { - - ComboBox_AddString(itemptr, compressnames[itemcount]); - - itemcount++; - - } // ENDWHILE- loading compression types into combo box - - ComboBox_SetCurSel(itemptr, 0); // First Selection? - - itemptr = NULL; - - - - CheckDlgButton(conversionboxwindow, IDC_0408, FALSE); // Start unchecked - - - - return; - -} // END ConversionBoxDisplay() - - - - - -BOOL CALLBACK ConversionBoxCallback(HWND window, - - UINT msg, - - WPARAM param, - - LPARAM param2) { - - switch(msg) { - - case WM_INITDIALOG: - - conversionboxwindow = window; - - ConversionBoxDisplay(); // Final touches to this window - - return(FALSE); // Let Windows display this window - - break; - - - - case WM_CLOSE: // The "X" in the upper right corner was hit. - - ConversionBoxCancelEvent(); - - return(TRUE); - - break; - - - - case WM_COMMAND: - - switch(LOWORD(param)) { - - case IDC_0402: // Filename Edit Box - - ConversionBoxFileEvent(); // Describe the File's current type... - - return(FALSE); // Let Windows edit the text. - - break; - - - - case IDC_0403: // "Browse" Button - - ConversionBoxBrowseEvent(); - - return(TRUE); - - break; - - - - case IDC_0409: // "Change File" Button - - ConversionBoxOKEvent(); - - return(TRUE); - - break; - - - - case IDC_0410: // "Cancel" Button - - ConversionBoxCancelEvent(); - - return(TRUE); - - break; - - } // ENDSWITCH param- Which object got the message? - - } // ENDSWITCH msg- what message has been sent to this window? - - - - return(FALSE); - -} // END ConversionBoxEventLoop() - +/* conversionbox.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + +#include // ComboBox_AddString(), CheckDlgButton() + +#include // NULL + +// #include + + + +#include // sprintf() + +#include // strcpy() + +#include // off64_t + + + +#include "isofile.h" + +#include "isocompress.h" // compressdesc[] + +#include "imagetype.h" // imagedata[] + +#include "multifile.h" // multinames[] + +#include "toc.h" + +#include "progressbox.h" + +#include "mainbox.h" + +#include "screens.h" // DLG_..., IDC_... + +#include "conversionbox.h" + + + + + +HWND conversionboxwindow; + + + + + +void ConversionBoxDestroy() { + + if(conversionboxwindow != NULL) { + + EndDialog(conversionboxwindow, FALSE); + + conversionboxwindow = NULL; + + } // ENDIF- Do we have a Main Window still? + +} // END ConversionBoxDestroy() + + + + + +void ConversionBoxUnfocus() { + + // gtk_widget_set_sensitive(conversionbox.file, FALSE); + + // gtk_widget_set_sensitive(conversionbox.selectbutton, FALSE); + + // gtk_widget_set_sensitive(conversionbox.compress, FALSE); + + // gtk_widget_set_sensitive(conversionbox.multi, FALSE); + + // gtk_widget_set_sensitive(conversionbox.okbutton, FALSE); + + // gtk_widget_set_sensitive(conversionbox.cancelbutton, FALSE); + + ShowWindow(conversionboxwindow, SW_HIDE); + +} // END ConversionBoxUnfocus() + + + + + +void ConversionBoxFileEvent() { + + int returnval; + + char templine[256]; + + struct IsoFile *tempfile; + + + + GetDlgItemText(conversionboxwindow, IDC_0402, templine, 256); + + returnval = IsIsoFile(templine); + + if(returnval == -1) { + + SetDlgItemText(conversionboxwindow, IDC_0404, "File Type: ---"); + + return; + + } // ENDIF- Not a name of any sort? + + + + if(returnval == -2) { + + SetDlgItemText(conversionboxwindow, IDC_0404, "File Type: Not a file"); + + return; + + } // ENDIF- Not a regular file? + + + + if(returnval == -3) { + + SetDlgItemText(conversionboxwindow, IDC_0404, "File Type: Not a valid image file"); + + return; + + } // ENDIF- Not a regular file? + + + + if(returnval == -4) { + + SetDlgItemText(conversionboxwindow, IDC_0404, "File Type: Missing Table File (will rebuild)"); + + return; + + } // ENDIF- Not a regular file? + + + + tempfile = IsoFileOpenForRead(templine); + + sprintf(templine, "File Type: %s%s%s", + + multinames[tempfile->multi], + + tempfile->imagename, + + compressdesc[tempfile->compress]); + + SetDlgItemText(conversionboxwindow, IDC_0404, templine); + + tempfile = IsoFileClose(tempfile); + + return; + +} // END ConversionBoxFileEvent() + + + + + +void ConversionBoxRefocus() { + + ConversionBoxFileEvent(); + + + + // gtk_widget_set_sensitive(conversionbox.file, TRUE); + + // gtk_widget_set_sensitive(conversionbox.selectbutton, TRUE); + + // gtk_widget_set_sensitive(conversionbox.compress, TRUE); + + // gtk_widget_set_sensitive(conversionbox.multi, TRUE); + + // gtk_widget_set_sensitive(conversionbox.okbutton, TRUE); + + // gtk_widget_set_sensitive(conversionbox.cancelbutton, TRUE); + + // gtk_window_set_focus(GTK_WINDOW(conversionbox.window), conversionbox.file); + + ShowWindow(conversionboxwindow, SW_SHOW); + + SetActiveWindow(conversionboxwindow); + +} // END ConversionBoxRefocus() + + + + + +void ConversionBoxCancelEvent() { + + // ShowWindow(conversionboxwindow, SW_HIDE); + + ConversionBoxDestroy(); + + MainBoxRefocus(); + + return; + +} // END ConversionBoxCancelEvent() + + + + + +void ConversionBoxOKEvent() { + + char templine[256]; + + char tempblock[2352]; + + char filename[256]; + + HWND tempitem; + + int compressmethod; + + int multi; + + struct IsoFile *fromfile; + + struct IsoFile *tofile; + + int i; + + off64_t endsector; + + int stop; + + int retval; + + + + ConversionBoxUnfocus(); + + + + GetDlgItemText(conversionboxwindow, IDC_0402, filename, 256); + + if(IsIsoFile(filename) < 0) { + + ConversionBoxRefocus(); + + MessageBox(conversionboxwindow, + + "Not a Valid Image File.", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + return; + + } // ENDIF- Not an Iso File? Stop early. + + + + tempitem = GetDlgItem(conversionboxwindow, IDC_0406); + + compressmethod = ComboBox_GetCurSel(tempitem); + + tempitem = NULL; + + if(compressmethod > 0) compressmethod += 2; + + + + multi = 0; + + if(IsDlgButtonChecked(conversionboxwindow, IDC_0408)) multi = 1; + + + + fromfile = NULL; + + fromfile = IsoFileOpenForRead(filename); + + if(fromfile == NULL) { + + ConversionBoxRefocus(); + + MessageBox(conversionboxwindow, + + "Cannot opening the source file", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + return; + + } // ENDIF- Not an Iso File? Stop early. + + + + if((compressmethod == fromfile->compress) && + + (multi == fromfile->multi)) { + + fromfile = IsoFileClose(fromfile); + + ConversionBoxRefocus(); + + MessageBox(conversionboxwindow, + + "Compress/Multifile methods match - no need to convert", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + return; + + } // ENDIF- Not an Iso File? Stop early. + + + + tofile = IsoFileOpenForWrite(filename, + + GetImageTypeConvertTo(fromfile->imagetype), + + multi, + + compressmethod); + + if(tofile == NULL) { + + fromfile = IsoFileClose(fromfile); + + ConversionBoxRefocus(); + + MessageBox(conversionboxwindow, + + "Cannot create the new file", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + return; + + } // ENDIF- Not an Iso File? Stop early. + + + + if(fromfile->multi == 1) { + + i = 0; + + while((i < 10) && + + (IsoFileSeek(fromfile, fromfile->multisectorend[i] + 1) == 0)) i++; + + endsector = fromfile->multisectorend[fromfile->multiend]; + + } else { + + endsector = fromfile->filesectorsize; + + } // ENDIF- Get ending sector from multifile? (Or single file?) + + IsoFileSeek(fromfile, 0); + + + + // Open Progress Bar + + sprintf(templine, "%s: %s%s -> %s%s", + + filename, + + multinames[fromfile->multi], + + compressdesc[fromfile->compress], + + multinames[tofile->multi], + + compressdesc[tofile->compress]); + + ProgressBoxStart(templine, endsector); + + + + tofile->cdvdtype = fromfile->cdvdtype; + + for(i = 0; i < 2048; i++) tofile->toc[i] = fromfile->toc[i]; + + + + stop = 0; + + mainboxstop = 0; + + progressboxstop = 0; + + while((stop == 0) && (tofile->sectorpos < endsector)) { + + retval = IsoFileRead(fromfile, tempblock); + + if(retval < 0) { + + MessageBox(conversionboxwindow, + + "Trouble reading source file", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + stop = 1; + + } else { + + retval = IsoFileWrite(tofile, tempblock); + + if(retval < 0) { + + MessageBox(conversionboxwindow, + + "Trouble writing new file", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + stop = 1; + + } // ENDIF- Trouble writing out the next block? + + } // ENDIF- Trouble reading in the next block? + + + + ProgressBoxTick(tofile->sectorpos); + + + + if(mainboxstop != 0) stop = 2; + + if(progressboxstop != 0) stop = 2; + + } // ENDWHILE- Not stopped for some reason... + + + + ProgressBoxStop(); + + + + if(stop == 0) { + + if(tofile->multi == 1) tofile->name[tofile->multipos] = '0'; // First file + + strcpy(templine, tofile->name); + + + + // fromfile = IsoFileCloseAndDelete(fromfile); + + fromfile = IsoFileClose(fromfile); + + + + IsoSaveTOC(tofile); + + tofile = IsoFileClose(tofile); + + SetDlgItemText(mainboxwindow, IDC_0202, templine); + + + + } else { + + fromfile = IsoFileClose(fromfile); + + tofile = IsoFileCloseAndDelete(tofile); + + } // ENDIF- Did we succeed in the transfer? + + + + ConversionBoxRefocus(); + + if(stop == 0) ConversionBoxCancelEvent(); + + return; + +} // END ConversionBoxOKEvent() + + + + + +void ConversionBoxBrowseEvent() { + + OPENFILENAME filebox; + + char newfilename[256]; + + BOOL returnbool; + + + + filebox.lStructSize = sizeof(filebox); + + filebox.hwndOwner = conversionboxwindow; + + filebox.hInstance = NULL; + + filebox.lpstrFilter = fileselection; + + filebox.lpstrCustomFilter = NULL; + + filebox.nFilterIndex = 0; + + filebox.lpstrFile = newfilename; + + filebox.nMaxFile = 256; + + filebox.lpstrFileTitle = NULL; + + filebox.nMaxFileTitle = 0; + + filebox.lpstrInitialDir = NULL; + + filebox.lpstrTitle = NULL; + + filebox.Flags = OFN_FILEMUSTEXIST + + | OFN_NOCHANGEDIR + + | OFN_HIDEREADONLY; + + filebox.nFileOffset = 0; + + filebox.nFileExtension = 0; + + filebox.lpstrDefExt = NULL; + + filebox.lCustData = 0; + + filebox.lpfnHook = NULL; + + filebox.lpTemplateName = NULL; + + + + GetDlgItemText(conversionboxwindow, IDC_0402, newfilename, 256); + + returnbool = GetOpenFileName(&filebox); + + if(returnbool != FALSE) { + + SetDlgItemText(conversionboxwindow, IDC_0402, newfilename); + + } // ENDIF- User actually selected a name? Save it. + + + + return; + +} // END ConversionBoxBrowseEvent() + + + + + +void ConversionBoxDisplay() { + + char templine[256]; + + HWND itemptr; + + int itemcount; + + + + // Adjust window position? + + + + // Pull the name from the Main Window... for a starting place. + + GetDlgItemText(mainboxwindow, IDC_0202, templine, 256); + + SetDlgItemText(conversionboxwindow, IDC_0402, templine); + + + + // ConversionBoxFileEvent(); // Needed? + + + + itemptr = GetDlgItem(conversionboxwindow, IDC_0406); // Compression Combo + + itemcount = 0; + + while(compressnames[itemcount] != NULL) { + + ComboBox_AddString(itemptr, compressnames[itemcount]); + + itemcount++; + + } // ENDWHILE- loading compression types into combo box + + ComboBox_SetCurSel(itemptr, 0); // First Selection? + + itemptr = NULL; + + + + CheckDlgButton(conversionboxwindow, IDC_0408, FALSE); // Start unchecked + + + + return; + +} // END ConversionBoxDisplay() + + + + + +BOOL CALLBACK ConversionBoxCallback(HWND window, + + UINT msg, + + WPARAM param, + + LPARAM param2) { + + switch(msg) { + + case WM_INITDIALOG: + + conversionboxwindow = window; + + ConversionBoxDisplay(); // Final touches to this window + + return(FALSE); // Let Windows display this window + + break; + + + + case WM_CLOSE: // The "X" in the upper right corner was hit. + + ConversionBoxCancelEvent(); + + return(TRUE); + + break; + + + + case WM_COMMAND: + + switch(LOWORD(param)) { + + case IDC_0402: // Filename Edit Box + + ConversionBoxFileEvent(); // Describe the File's current type... + + return(FALSE); // Let Windows edit the text. + + break; + + + + case IDC_0403: // "Browse" Button + + ConversionBoxBrowseEvent(); + + return(TRUE); + + break; + + + + case IDC_0409: // "Change File" Button + + ConversionBoxOKEvent(); + + return(TRUE); + + break; + + + + case IDC_0410: // "Cancel" Button + + ConversionBoxCancelEvent(); + + return(TRUE); + + break; + + } // ENDSWITCH param- Which object got the message? + + } // ENDSWITCH msg- what message has been sent to this window? + + + + return(FALSE); + +} // END ConversionBoxEventLoop() + diff --git a/plugins/CDVDisoEFP/src/Win32/conversionbox.h b/plugins/CDVDisoEFP/src/Win32/conversionbox.h index 91a7ffe7a1..7bf8c0dfdb 100644 --- a/plugins/CDVDisoEFP/src/Win32/conversionbox.h +++ b/plugins/CDVDisoEFP/src/Win32/conversionbox.h @@ -1,40 +1,80 @@ -/* conversionbox.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef CONVERSIONBOX_H -#define CONVERSIONBOX_H - - -#include // HWND - - -extern HWND conversionboxwindow; - -extern void ConversionBoxDestroy(); -extern void ConversionBoxRefocus(); -extern void ConversionBoxDisplay(); -extern BOOL CALLBACK ConversionBoxCallback(HWND window, - UINT msg, - WPARAM param, - LPARAM param2); - - -#endif /* CONVERSIONBOX_H */ +/* conversionbox.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef CONVERSIONBOX_H + +#define CONVERSIONBOX_H + + + + + +#include // HWND + + + + + +extern HWND conversionboxwindow; + + + +extern void ConversionBoxDestroy(); + +extern void ConversionBoxRefocus(); + +extern void ConversionBoxDisplay(); + +extern BOOL CALLBACK ConversionBoxCallback(HWND window, + + UINT msg, + + WPARAM param, + + LPARAM param2); + + + + + +#endif /* CONVERSIONBOX_H */ + diff --git a/plugins/CDVDisoEFP/src/Win32/device.c b/plugins/CDVDisoEFP/src/Win32/device.c index 2b45636503..f46ad13cd9 100644 --- a/plugins/CDVDisoEFP/src/Win32/device.c +++ b/plugins/CDVDisoEFP/src/Win32/device.c @@ -1,586 +1,1172 @@ -/* device.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include -#include // IOCTL_CDROM..., IOCTL_STORAGE... -#include // IOCTL_DISK... -#include // sprintf() -#include // time_t - -#define CDVDdefs -#include "PS2Edefs.h" - -#include "logfile.h" -#include "conf.h" -#include "CD.h" -#include "DVD.h" -#include "device.h" - - -HANDLE devicehandle; -OVERLAPPED waitevent; - -time_t lasttime; -s32 traystatus; -int traystatusmethod; -s32 disctype; -char tocbuffer[2048]; - - -void DeviceInit() { - devicehandle = NULL; - waitevent.hEvent = NULL; - waitevent.Internal = 0; - waitevent.InternalHigh = 0; - waitevent.Offset = 0; - waitevent.OffsetHigh = 0; - lasttime = 0; - - InitDisc(); -} // END DeviceInit() - - -void InitDisc() { - int i; - - InitCDInfo(); - InitDVDInfo(); - traystatus = CDVD_TRAY_OPEN; - traystatusmethod = 0; // Poll all until one works - disctype = CDVD_TYPE_NODISC; - for(i = 0; i < 2048; i++) tocbuffer[i] = 0; -} // END InitDisc() - - -s32 DiscInserted() { - if(traystatus != CDVD_TRAY_CLOSE) return(-1); - - if(disctype == CDVD_TYPE_ILLEGAL) return(-1); - // if(disctype == CDVD_TYPE_UNKNOWN) return(-1); // Hmm. Let this one through? - if(disctype == CDVD_TYPE_DETCTDVDD) return(-1); - if(disctype == CDVD_TYPE_DETCTDVDS) return(-1); - if(disctype == CDVD_TYPE_DETCTCD) return(-1); - if(disctype == CDVD_TYPE_DETCT) return(-1); - if(disctype == CDVD_TYPE_NODISC) return(-1); - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDiso device: DiscInserted()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - return(0); -} // END DiscInserted() - - -// Returns errcode (or 0 if successful) -DWORD FinishCommand(BOOL boolresult) { - DWORD errcode; - DWORD waitcode; - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDiso device: FinishCommand()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - if(boolresult == TRUE) { - ResetEvent(waitevent.hEvent); - return(0); - } // ENDIF- Device is ready? Say so. - - errcode = GetLastError(); - if(errcode == ERROR_IO_PENDING) { -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDiso device: Waiting for completion."); -#endif /* VERBOSE_FUNCTION_DEVICE */ - waitcode = WaitForSingleObject(waitevent.hEvent, 10 * 1000); // 10 sec wait - if((waitcode == WAIT_FAILED) || (waitcode == WAIT_ABANDONED)) { - errcode = GetLastError(); - } else if(waitcode == WAIT_TIMEOUT) { - errcode = 21; - CancelIo(devicehandle); // Speculative Line - } else { - ResetEvent(waitevent.hEvent); - return(0); // Success! - } // ENDIF- Trouble waiting? (Or doesn't finish in 5 seconds?) - } // ENDIF- Should we wait for the call to finish? - - ResetEvent(waitevent.hEvent); - return(errcode); -} // END DeviceCommand() - - -s32 DeviceOpen() { - char tempname[256]; - UINT drivetype; - DWORD errcode; - - if(conf.devicename[0] == 0) return(-1); - - if(devicehandle != NULL) return(0); - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDiso device: DeviceOpen()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - // InitConf(); - // LoadConf(); // Should be done at least once before this call - - // Root Directory reference - if(conf.devicename[1] == 0) { - sprintf(tempname, "%s:\\", conf.devicename); - } else if((conf.devicename[1] == ':') && (conf.devicename[2] == 0)) { - sprintf(tempname, "%s\\", conf.devicename); - } else { - sprintf(tempname, "%s", conf.devicename); - } // ENDIF- Not a single drive letter? (or a letter/colon?) Copy the name in. - - drivetype = GetDriveType(tempname); - if(drivetype != DRIVE_CDROM) { -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDiso device: Not a CD-ROM!"); - PrintLog("CDVDiso device: (Came back: %u)", drivetype); - errcode = GetLastError(); - if(errcode > 0) PrintError("CDVDiso device", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - return(-1); - } // ENDIF- Not a CD-ROM? Say so! - // Hmm. Do we want to include DRIVE_REMOVABLE... just in case? - - // Device Reference - if(conf.devicename[1] == 0) { - sprintf(tempname, "\\\\.\\%s:", conf.devicename); - } else if((conf.devicename[1] == ':') && (conf.devicename[2] == 0)) { - sprintf(tempname, "\\\\.\\%s", conf.devicename); - } else { - sprintf(tempname, "%s", conf.devicename); - } // ENDIF- Not a single drive letter? (or a letter/colon?) Copy the name in. - - devicehandle = CreateFile(tempname, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN, - NULL); - - if(devicehandle == INVALID_HANDLE_VALUE) { -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDiso device: Couldn't open device read-only! Read-Write perhaps?"); - errcode = GetLastError(); - PrintError("CDVDiso device", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - devicehandle = CreateFile(tempname, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN, - NULL); - } // ENDIF- Couldn't open for read? Try read/write (for those drives that insist) - - if(devicehandle == INVALID_HANDLE_VALUE) { -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDiso device: Couldn't open device!"); - errcode = GetLastError(); - PrintError("CDVDiso device", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - devicehandle = NULL; - return(-1); - } // ENDIF- Couldn't open that way either? Abort. - - waitevent.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if(waitevent.hEvent == INVALID_HANDLE_VALUE) { -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDiso device: Couldn't open event handler!"); - errcode = GetLastError(); - PrintError("CDVDiso device", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - waitevent.hEvent = NULL; - CloseHandle(devicehandle); - devicehandle = NULL; - } // ENDIF- Couldn't create an "Wait for I/O" handle? Abort. - - // More here... DeviceIoControl? for Drive Capabilities - // DEVICE_CAPABILITIES? - - ////// Should be done just after the first DeviceOpen(); - // InitDisc(); // ? - // DeviceTrayStatus(); - - return(0); -} // END DeviceOpen() - - -void DeviceClose() { - if(devicehandle == NULL) return; - - if(devicehandle == INVALID_HANDLE_VALUE) { - devicehandle = NULL; - return; - } // ENDIF- Bad value? Just clear the value. - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDiso device: DeviceClose()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - if(waitevent.hEvent != NULL) { - if(waitevent.hEvent != INVALID_HANDLE_VALUE) { - CancelIo(devicehandle); - CloseHandle(waitevent.hEvent); - } // ENDIF- Is this handle actually open? - waitevent.hEvent = NULL; - waitevent.Offset = 0; - waitevent.OffsetHigh = 0; - } // ENDIF- Reset the event handle? - - CloseHandle(devicehandle); - devicehandle = NULL; - return; -} // END DeviceClose() - - -s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer) { - if(DiscInserted() == -1) return(-1); - - if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { - return(DVDreadTrack(lsn, mode, buffer)); - } else { - return(CDreadTrack(lsn, mode, buffer)); - } // ENDIF- Is this a DVD? -} // END DeviceReadTrack() - - -s32 DeviceBufferOffset() { - if(DiscInserted() == -1) return(-1); - - if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { - return(0); - } else { - return(CDgetBufferOffset()); - } // ENDIF- Is this a DVD? - - return(-1); -} // END DeviceBufferOffset() - - -s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd) { - if(DiscInserted() == -1) return(-1); - - if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { - return(DVDgetTD(track, cdvdtd)); - } else { - return(CDgetTD(track, cdvdtd)); - } // ENDIF- Is this a DVD? - - return(-1); -} // END DeviceGetTD() - - -s32 DeviceGetDiskType() { - s32 s32result; - - if(devicehandle == NULL) return(-1); - if(devicehandle == INVALID_HANDLE_VALUE) return(-1); - - if(traystatus == CDVD_TRAY_OPEN) return(disctype); - - if(disctype != CDVD_TYPE_NODISC) return(disctype); - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDiso device: DeviceGetDiskType()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - disctype = CDVD_TYPE_DETCT; - - s32result = DVDgetDiskType(); - if(s32result != -1) return(disctype); - - s32result = CDgetDiskType(); - if(s32result != -1) return(disctype); - - disctype = CDVD_TYPE_UNKNOWN; - return(disctype); -} // END DeviceGetDiskType() - - -BOOL DeviceTrayStatusStorage() { - BOOL boolresult; - DWORD byteswritten; - DWORD errcode; - - // Note: Unlike other calls, CHECK_VERIFY is not waited on. At this point, - // this is the only way to detect if a disc is ready for action. - - boolresult = DeviceIoControl(devicehandle, - IOCTL_STORAGE_CHECK_VERIFY, - NULL, - 0, - NULL, - 0, - &byteswritten, - NULL); - errcode = GetLastError(); - - if(errcode == 0) return(TRUE); - if(errcode == 21) return(FALSE); // Device not ready? (Valid error) - -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDiso device: Trouble detecting drive status (STORAGE)!"); - PrintError("CDVDiso device", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - return(FALSE); -} // END DeviceTrayStatusStorage() - - -BOOL DeviceTrayStatusCDRom() { - BOOL boolresult; - DWORD byteswritten; - DWORD errcode; - - // Note: Unlike other calls, CHECK_VERIFY is not waited on. At this point, - // this is the only way to detect if a disc is ready for action. - - boolresult = DeviceIoControl(devicehandle, - IOCTL_CDROM_CHECK_VERIFY, - NULL, - 0, - NULL, - 0, - &byteswritten, - NULL); - errcode = GetLastError(); - - if(errcode == 0) return(TRUE); - if(errcode == 21) return(FALSE); // Device not ready? (Valid error) - -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDiso device: Trouble detecting drive status (CDROM)!"); - PrintError("CDVDiso device", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - return(FALSE); -} // END DeviceTrayStatusCDRom() - - -BOOL DeviceTrayStatusDisk() { - BOOL boolresult; - DWORD byteswritten; - DWORD errcode; - - // Note: Unlike other calls, CHECK_VERIFY is not waited on. At this point, - // this is the only way to detect if a disc is ready for action. - - boolresult = DeviceIoControl(devicehandle, - IOCTL_DISK_CHECK_VERIFY, - NULL, - 0, - NULL, - 0, - &byteswritten, - NULL); - errcode = GetLastError(); - - if(errcode == 0) return(TRUE); - if(errcode == 21) return(FALSE); // Device not ready? (Valid error) - -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDiso device: Trouble detecting drive status (DISK)!"); - PrintError("CDVDiso device", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - return(FALSE); -} // END DeviceTrayStatusDisk() - - -s32 DeviceTrayStatus() { - BOOL boolresult; - - if(devicehandle == NULL) return(-1); - if(devicehandle == INVALID_HANDLE_VALUE) return(-1); - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDiso device: DeviceTrayStatus()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - switch(traystatusmethod) { - case 1: - boolresult = DeviceTrayStatusStorage(); - break; - case 2: - boolresult = DeviceTrayStatusCDRom(); - break; - case 3: - boolresult = DeviceTrayStatusDisk(); - break; - default: - boolresult = FALSE; - break; - } // ENDSWITCH traystatusmethod- One method already working? Try it again. - - if(boolresult == FALSE) { - traystatusmethod = 0; - boolresult = DeviceTrayStatusStorage(); - if(boolresult == TRUE) { - traystatusmethod = 1; - } else { - boolresult = DeviceTrayStatusCDRom(); - if(boolresult == TRUE) { - traystatusmethod = 2; - } else { - boolresult = DeviceTrayStatusDisk(); - if(boolresult == TRUE) traystatusmethod = 3; - } // ENDIF- Did we succeed with CDRom? - } // ENDIF- Did we succeed with Storage? - } // Single call to already working test just failed? Test them all. - - if(boolresult == FALSE) { - if(traystatus == CDVD_TRAY_CLOSE) { - traystatus = CDVD_TRAY_OPEN; - DeviceClose(); - DeviceOpen(); - InitDisc(); - } // ENDIF- Just opened? clear disc info - return(traystatus); - } // ENDIF- Still failed? Assume no disc in drive then. - - if(traystatus == CDVD_TRAY_OPEN) { - traystatus = CDVD_TRAY_CLOSE; - DeviceGetDiskType(); - return(traystatus); - } // ENDIF- Just closed? Get disc information - - return(traystatus); -} // END DeviceTrayStatus() - - -s32 DeviceTrayOpen() { - BOOL boolresult; - DWORD byteswritten; - DWORD errcode; - - if(devicehandle == NULL) return(-1); - if(devicehandle == INVALID_HANDLE_VALUE) return(-1); - - if(traystatus == CDVD_TRAY_OPEN) return(0); - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDiso device: DeviceOpenTray()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - boolresult = DeviceIoControl(devicehandle, - IOCTL_STORAGE_EJECT_MEDIA, - NULL, - 0, - NULL, - 0, - &byteswritten, - &waitevent); - errcode = FinishCommand(boolresult); - - if(errcode != 0) { -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDiso device: Couldn't signal media to eject! (STORAGE)"); - PrintError("CDVDiso device", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - -// boolresult = DeviceIoControl(devicehandle, -// IOCTL_DISK_EJECT_MEDIA, -// NULL, -// 0, -// NULL, -// 0, -// &byteswritten, -// NULL); -// } // ENDIF- Storage Call failed? Try Disk call. - -// if(boolresult == FALSE) { -// #ifdef VERBOSE_WARNING_DEVICE -// PrintLog("CDVDiso device: Couldn't signal media to eject! (DISK)"); -// PrintError("CDVDiso device", errcode); -// #endif /* VERBOSE_WARNING_DEVICE */ - return(-1); - } // ENDIF- Disk Call failed as well? Give it up. - - return(0); -} // END DeviceTrayOpen() - - -s32 DeviceTrayClose() { - BOOL boolresult; - DWORD byteswritten; - DWORD errcode; - - if(devicehandle == NULL) return(-1); - if(devicehandle == INVALID_HANDLE_VALUE) return(-1); - - if(traystatus == CDVD_TRAY_CLOSE) return(0); - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDiso device: DeviceCloseTray()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - boolresult = DeviceIoControl(devicehandle, - IOCTL_STORAGE_LOAD_MEDIA, - NULL, - 0, - NULL, - 0, - &byteswritten, - NULL); - errcode = FinishCommand(boolresult); - - if(errcode != 0) { -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDiso device: Couldn't signal media to load! (STORAGE)"); - PrintError("CDVDiso device", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ -// boolresult = DeviceIoControl(devicehandle, -// IOCTL_CDROM_LOAD_MEDIA, -// NULL, -// 0, -// NULL, -// 0, -// &byteswritten, -// NULL); -// } // ENDIF- Storage call failed. CDRom call? - -// if(boolresult == FALSE) { -// errcode = GetLastError(); -// #ifdef VERBOSE_WARNING_DEVICE -// PrintLog("CDVDiso device: Couldn't signal media to load! (CDROM)"); -// PrintError("CDVDiso device", errcode); -// #endif /* VERBOSE_WARNING_DEVICE */ -// boolresult = DeviceIoControl(devicehandle, -// IOCTL_DISK_LOAD_MEDIA, -// NULL, -// 0, -// NULL, -// 0, -// &byteswritten, -// NULL); -// } // ENDIF- CDRom call failed. Disk call? - -// if(boolresult == FALSE) { -// #ifdef VERBOSE_WARNING_DEVICE -// PrintLog("CDVDiso device: Couldn't signal media to load! (DISK)"); -// PrintError("CDVDiso device", errcode); -// #endif /* VERBOSE_WARNING_DEVICE */ - return(-1); - } // ENDIF- Media not available? - - return(0); -} // END DeviceTrayClose() +/* device.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + +#include // IOCTL_CDROM..., IOCTL_STORAGE... + +#include // IOCTL_DISK... + +#include // sprintf() + +#include // time_t + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + +#include "logfile.h" + +#include "conf.h" + +#include "CD.h" + +#include "DVD.h" + +#include "device.h" + + + + + +HANDLE devicehandle; + +OVERLAPPED waitevent; + + + +time_t lasttime; + +s32 traystatus; + +int traystatusmethod; + +s32 disctype; + +char tocbuffer[2048]; + + + + + +void DeviceInit() { + + devicehandle = NULL; + + waitevent.hEvent = NULL; + + waitevent.Internal = 0; + + waitevent.InternalHigh = 0; + + waitevent.Offset = 0; + + waitevent.OffsetHigh = 0; + + lasttime = 0; + + + + InitDisc(); + +} // END DeviceInit() + + + + + +void InitDisc() { + + int i; + + + + InitCDInfo(); + + InitDVDInfo(); + + traystatus = CDVD_TRAY_OPEN; + + traystatusmethod = 0; // Poll all until one works + + disctype = CDVD_TYPE_NODISC; + + for(i = 0; i < 2048; i++) tocbuffer[i] = 0; + +} // END InitDisc() + + + + + +s32 DiscInserted() { + + if(traystatus != CDVD_TRAY_CLOSE) return(-1); + + + + if(disctype == CDVD_TYPE_ILLEGAL) return(-1); + + // if(disctype == CDVD_TYPE_UNKNOWN) return(-1); // Hmm. Let this one through? + + if(disctype == CDVD_TYPE_DETCTDVDD) return(-1); + + if(disctype == CDVD_TYPE_DETCTDVDS) return(-1); + + if(disctype == CDVD_TYPE_DETCTCD) return(-1); + + if(disctype == CDVD_TYPE_DETCT) return(-1); + + if(disctype == CDVD_TYPE_NODISC) return(-1); + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso device: DiscInserted()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + return(0); + +} // END DiscInserted() + + + + + +// Returns errcode (or 0 if successful) + +DWORD FinishCommand(BOOL boolresult) { + + DWORD errcode; + + DWORD waitcode; + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso device: FinishCommand()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + if(boolresult == TRUE) { + + ResetEvent(waitevent.hEvent); + + return(0); + + } // ENDIF- Device is ready? Say so. + + + + errcode = GetLastError(); + + if(errcode == ERROR_IO_PENDING) { + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso device: Waiting for completion."); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + waitcode = WaitForSingleObject(waitevent.hEvent, 10 * 1000); // 10 sec wait + + if((waitcode == WAIT_FAILED) || (waitcode == WAIT_ABANDONED)) { + + errcode = GetLastError(); + + } else if(waitcode == WAIT_TIMEOUT) { + + errcode = 21; + + CancelIo(devicehandle); // Speculative Line + + } else { + + ResetEvent(waitevent.hEvent); + + return(0); // Success! + + } // ENDIF- Trouble waiting? (Or doesn't finish in 5 seconds?) + + } // ENDIF- Should we wait for the call to finish? + + + + ResetEvent(waitevent.hEvent); + + return(errcode); + +} // END DeviceCommand() + + + + + +s32 DeviceOpen() { + + char tempname[256]; + + UINT drivetype; + + DWORD errcode; + + + + if(conf.devicename[0] == 0) return(-1); + + + + if(devicehandle != NULL) return(0); + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso device: DeviceOpen()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + // InitConf(); + + // LoadConf(); // Should be done at least once before this call + + + + // Root Directory reference + + if(conf.devicename[1] == 0) { + + sprintf(tempname, "%s:\\", conf.devicename); + + } else if((conf.devicename[1] == ':') && (conf.devicename[2] == 0)) { + + sprintf(tempname, "%s\\", conf.devicename); + + } else { + + sprintf(tempname, "%s", conf.devicename); + + } // ENDIF- Not a single drive letter? (or a letter/colon?) Copy the name in. + + + + drivetype = GetDriveType(tempname); + + if(drivetype != DRIVE_CDROM) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso device: Not a CD-ROM!"); + + PrintLog("CDVDiso device: (Came back: %u)", drivetype); + + errcode = GetLastError(); + + if(errcode > 0) PrintError("CDVDiso device", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Not a CD-ROM? Say so! + + // Hmm. Do we want to include DRIVE_REMOVABLE... just in case? + + + + // Device Reference + + if(conf.devicename[1] == 0) { + + sprintf(tempname, "\\\\.\\%s:", conf.devicename); + + } else if((conf.devicename[1] == ':') && (conf.devicename[2] == 0)) { + + sprintf(tempname, "\\\\.\\%s", conf.devicename); + + } else { + + sprintf(tempname, "%s", conf.devicename); + + } // ENDIF- Not a single drive letter? (or a letter/colon?) Copy the name in. + + + + devicehandle = CreateFile(tempname, + + GENERIC_READ, + + FILE_SHARE_READ, + + NULL, + + OPEN_EXISTING, + + FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN, + + NULL); + + + + if(devicehandle == INVALID_HANDLE_VALUE) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso device: Couldn't open device read-only! Read-Write perhaps?"); + + errcode = GetLastError(); + + PrintError("CDVDiso device", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + devicehandle = CreateFile(tempname, + + GENERIC_READ | GENERIC_WRITE, + + FILE_SHARE_READ | FILE_SHARE_WRITE, + + NULL, + + OPEN_EXISTING, + + FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN, + + NULL); + + } // ENDIF- Couldn't open for read? Try read/write (for those drives that insist) + + + + if(devicehandle == INVALID_HANDLE_VALUE) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso device: Couldn't open device!"); + + errcode = GetLastError(); + + PrintError("CDVDiso device", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + devicehandle = NULL; + + return(-1); + + } // ENDIF- Couldn't open that way either? Abort. + + + + waitevent.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + if(waitevent.hEvent == INVALID_HANDLE_VALUE) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso device: Couldn't open event handler!"); + + errcode = GetLastError(); + + PrintError("CDVDiso device", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + waitevent.hEvent = NULL; + + CloseHandle(devicehandle); + + devicehandle = NULL; + + } // ENDIF- Couldn't create an "Wait for I/O" handle? Abort. + + + + // More here... DeviceIoControl? for Drive Capabilities + + // DEVICE_CAPABILITIES? + + + + ////// Should be done just after the first DeviceOpen(); + + // InitDisc(); // ? + + // DeviceTrayStatus(); + + + + return(0); + +} // END DeviceOpen() + + + + + +void DeviceClose() { + + if(devicehandle == NULL) return; + + + + if(devicehandle == INVALID_HANDLE_VALUE) { + + devicehandle = NULL; + + return; + + } // ENDIF- Bad value? Just clear the value. + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso device: DeviceClose()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + if(waitevent.hEvent != NULL) { + + if(waitevent.hEvent != INVALID_HANDLE_VALUE) { + + CancelIo(devicehandle); + + CloseHandle(waitevent.hEvent); + + } // ENDIF- Is this handle actually open? + + waitevent.hEvent = NULL; + + waitevent.Offset = 0; + + waitevent.OffsetHigh = 0; + + } // ENDIF- Reset the event handle? + + + + CloseHandle(devicehandle); + + devicehandle = NULL; + + return; + +} // END DeviceClose() + + + + + +s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer) { + + if(DiscInserted() == -1) return(-1); + + + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + + return(DVDreadTrack(lsn, mode, buffer)); + + } else { + + return(CDreadTrack(lsn, mode, buffer)); + + } // ENDIF- Is this a DVD? + +} // END DeviceReadTrack() + + + + + +s32 DeviceBufferOffset() { + + if(DiscInserted() == -1) return(-1); + + + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + + return(0); + + } else { + + return(CDgetBufferOffset()); + + } // ENDIF- Is this a DVD? + + + + return(-1); + +} // END DeviceBufferOffset() + + + + + +s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd) { + + if(DiscInserted() == -1) return(-1); + + + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + + return(DVDgetTD(track, cdvdtd)); + + } else { + + return(CDgetTD(track, cdvdtd)); + + } // ENDIF- Is this a DVD? + + + + return(-1); + +} // END DeviceGetTD() + + + + + +s32 DeviceGetDiskType() { + + s32 s32result; + + + + if(devicehandle == NULL) return(-1); + + if(devicehandle == INVALID_HANDLE_VALUE) return(-1); + + + + if(traystatus == CDVD_TRAY_OPEN) return(disctype); + + + + if(disctype != CDVD_TYPE_NODISC) return(disctype); + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso device: DeviceGetDiskType()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + disctype = CDVD_TYPE_DETCT; + + + + s32result = DVDgetDiskType(); + + if(s32result != -1) return(disctype); + + + + s32result = CDgetDiskType(); + + if(s32result != -1) return(disctype); + + + + disctype = CDVD_TYPE_UNKNOWN; + + return(disctype); + +} // END DeviceGetDiskType() + + + + + +BOOL DeviceTrayStatusStorage() { + + BOOL boolresult; + + DWORD byteswritten; + + DWORD errcode; + + + + // Note: Unlike other calls, CHECK_VERIFY is not waited on. At this point, + + // this is the only way to detect if a disc is ready for action. + + + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_STORAGE_CHECK_VERIFY, + + NULL, + + 0, + + NULL, + + 0, + + &byteswritten, + + NULL); + + errcode = GetLastError(); + + + + if(errcode == 0) return(TRUE); + + if(errcode == 21) return(FALSE); // Device not ready? (Valid error) + + + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso device: Trouble detecting drive status (STORAGE)!"); + + PrintError("CDVDiso device", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(FALSE); + +} // END DeviceTrayStatusStorage() + + + + + +BOOL DeviceTrayStatusCDRom() { + + BOOL boolresult; + + DWORD byteswritten; + + DWORD errcode; + + + + // Note: Unlike other calls, CHECK_VERIFY is not waited on. At this point, + + // this is the only way to detect if a disc is ready for action. + + + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_CDROM_CHECK_VERIFY, + + NULL, + + 0, + + NULL, + + 0, + + &byteswritten, + + NULL); + + errcode = GetLastError(); + + + + if(errcode == 0) return(TRUE); + + if(errcode == 21) return(FALSE); // Device not ready? (Valid error) + + + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso device: Trouble detecting drive status (CDROM)!"); + + PrintError("CDVDiso device", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(FALSE); + +} // END DeviceTrayStatusCDRom() + + + + + +BOOL DeviceTrayStatusDisk() { + + BOOL boolresult; + + DWORD byteswritten; + + DWORD errcode; + + + + // Note: Unlike other calls, CHECK_VERIFY is not waited on. At this point, + + // this is the only way to detect if a disc is ready for action. + + + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_DISK_CHECK_VERIFY, + + NULL, + + 0, + + NULL, + + 0, + + &byteswritten, + + NULL); + + errcode = GetLastError(); + + + + if(errcode == 0) return(TRUE); + + if(errcode == 21) return(FALSE); // Device not ready? (Valid error) + + + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso device: Trouble detecting drive status (DISK)!"); + + PrintError("CDVDiso device", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(FALSE); + +} // END DeviceTrayStatusDisk() + + + + + +s32 DeviceTrayStatus() { + + BOOL boolresult; + + + + if(devicehandle == NULL) return(-1); + + if(devicehandle == INVALID_HANDLE_VALUE) return(-1); + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso device: DeviceTrayStatus()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + switch(traystatusmethod) { + + case 1: + + boolresult = DeviceTrayStatusStorage(); + + break; + + case 2: + + boolresult = DeviceTrayStatusCDRom(); + + break; + + case 3: + + boolresult = DeviceTrayStatusDisk(); + + break; + + default: + + boolresult = FALSE; + + break; + + } // ENDSWITCH traystatusmethod- One method already working? Try it again. + + + + if(boolresult == FALSE) { + + traystatusmethod = 0; + + boolresult = DeviceTrayStatusStorage(); + + if(boolresult == TRUE) { + + traystatusmethod = 1; + + } else { + + boolresult = DeviceTrayStatusCDRom(); + + if(boolresult == TRUE) { + + traystatusmethod = 2; + + } else { + + boolresult = DeviceTrayStatusDisk(); + + if(boolresult == TRUE) traystatusmethod = 3; + + } // ENDIF- Did we succeed with CDRom? + + } // ENDIF- Did we succeed with Storage? + + } // Single call to already working test just failed? Test them all. + + + + if(boolresult == FALSE) { + + if(traystatus == CDVD_TRAY_CLOSE) { + + traystatus = CDVD_TRAY_OPEN; + + DeviceClose(); + + DeviceOpen(); + + InitDisc(); + + } // ENDIF- Just opened? clear disc info + + return(traystatus); + + } // ENDIF- Still failed? Assume no disc in drive then. + + + + if(traystatus == CDVD_TRAY_OPEN) { + + traystatus = CDVD_TRAY_CLOSE; + + DeviceGetDiskType(); + + return(traystatus); + + } // ENDIF- Just closed? Get disc information + + + + return(traystatus); + +} // END DeviceTrayStatus() + + + + + +s32 DeviceTrayOpen() { + + BOOL boolresult; + + DWORD byteswritten; + + DWORD errcode; + + + + if(devicehandle == NULL) return(-1); + + if(devicehandle == INVALID_HANDLE_VALUE) return(-1); + + + + if(traystatus == CDVD_TRAY_OPEN) return(0); + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso device: DeviceOpenTray()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_STORAGE_EJECT_MEDIA, + + NULL, + + 0, + + NULL, + + 0, + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso device: Couldn't signal media to eject! (STORAGE)"); + + PrintError("CDVDiso device", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + + +// boolresult = DeviceIoControl(devicehandle, + +// IOCTL_DISK_EJECT_MEDIA, + +// NULL, + +// 0, + +// NULL, + +// 0, + +// &byteswritten, + +// NULL); + +// } // ENDIF- Storage Call failed? Try Disk call. + + + +// if(boolresult == FALSE) { + +// #ifdef VERBOSE_WARNING_DEVICE + +// PrintLog("CDVDiso device: Couldn't signal media to eject! (DISK)"); + +// PrintError("CDVDiso device", errcode); + +// #endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Disk Call failed as well? Give it up. + + + + return(0); + +} // END DeviceTrayOpen() + + + + + +s32 DeviceTrayClose() { + + BOOL boolresult; + + DWORD byteswritten; + + DWORD errcode; + + + + if(devicehandle == NULL) return(-1); + + if(devicehandle == INVALID_HANDLE_VALUE) return(-1); + + + + if(traystatus == CDVD_TRAY_CLOSE) return(0); + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDiso device: DeviceCloseTray()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_STORAGE_LOAD_MEDIA, + + NULL, + + 0, + + NULL, + + 0, + + &byteswritten, + + NULL); + + errcode = FinishCommand(boolresult); + + + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDiso device: Couldn't signal media to load! (STORAGE)"); + + PrintError("CDVDiso device", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + +// boolresult = DeviceIoControl(devicehandle, + +// IOCTL_CDROM_LOAD_MEDIA, + +// NULL, + +// 0, + +// NULL, + +// 0, + +// &byteswritten, + +// NULL); + +// } // ENDIF- Storage call failed. CDRom call? + + + +// if(boolresult == FALSE) { + +// errcode = GetLastError(); + +// #ifdef VERBOSE_WARNING_DEVICE + +// PrintLog("CDVDiso device: Couldn't signal media to load! (CDROM)"); + +// PrintError("CDVDiso device", errcode); + +// #endif /* VERBOSE_WARNING_DEVICE */ + +// boolresult = DeviceIoControl(devicehandle, + +// IOCTL_DISK_LOAD_MEDIA, + +// NULL, + +// 0, + +// NULL, + +// 0, + +// &byteswritten, + +// NULL); + +// } // ENDIF- CDRom call failed. Disk call? + + + +// if(boolresult == FALSE) { + +// #ifdef VERBOSE_WARNING_DEVICE + +// PrintLog("CDVDiso device: Couldn't signal media to load! (DISK)"); + +// PrintError("CDVDiso device", errcode); + +// #endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Media not available? + + + + return(0); + +} // END DeviceTrayClose() + diff --git a/plugins/CDVDisoEFP/src/Win32/device.h b/plugins/CDVDisoEFP/src/Win32/device.h index 608f13dd86..6a4034fb76 100644 --- a/plugins/CDVDisoEFP/src/Win32/device.h +++ b/plugins/CDVDisoEFP/src/Win32/device.h @@ -1,64 +1,128 @@ -/* device.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - -#ifndef __DEVICE_H__ -#define __DEVICE_H__ - - -#include // BOOL, DWORD - -#include // time_t - -#define CDVDdefs -#include "../PS2Edefs.h" - - -// #define VERBOSE_FUNCTION_DEVICE -// #define VERBOSE_WARNING_DEVICE -#define VERBOSE_DISC_TYPE -#define VERBOSE_DISC_INFO - - -extern HANDLE devicehandle; -extern OVERLAPPED waitevent; - -extern time_t lasttime; -extern s32 traystatus; -extern s32 disctype; -extern char tocbuffer[]; - - -extern void DeviceInit(); -extern void InitDisc(); -extern s32 DiscInserted(); -extern DWORD FinishCommand(BOOL boolresult); - -extern s32 DeviceOpen(); -extern void DeviceClose(); -extern s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer); -extern s32 DeviceBufferOffset(); -extern s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd); -extern s32 DeviceGetDiskType(); -extern s32 DeviceTrayStatus(); -extern s32 DeviceTrayOpen(); -extern s32 DeviceTrayClose(); - - -#endif /* __DEVICE_H__ */ +/* device.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + +#ifndef __DEVICE_H__ + +#define __DEVICE_H__ + + + + + +#include // BOOL, DWORD + + + +#include // time_t + + + +#define CDVDdefs + +#include "../PS2Edefs.h" + + + + + +// #define VERBOSE_FUNCTION_DEVICE + +// #define VERBOSE_WARNING_DEVICE + +#define VERBOSE_DISC_TYPE + +#define VERBOSE_DISC_INFO + + + + + +extern HANDLE devicehandle; + +extern OVERLAPPED waitevent; + + + +extern time_t lasttime; + +extern s32 traystatus; + +extern s32 disctype; + +extern char tocbuffer[]; + + + + + +extern void DeviceInit(); + +extern void InitDisc(); + +extern s32 DiscInserted(); + +extern DWORD FinishCommand(BOOL boolresult); + + + +extern s32 DeviceOpen(); + +extern void DeviceClose(); + +extern s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer); + +extern s32 DeviceBufferOffset(); + +extern s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd); + +extern s32 DeviceGetDiskType(); + +extern s32 DeviceTrayStatus(); + +extern s32 DeviceTrayOpen(); + +extern s32 DeviceTrayClose(); + + + + + +#endif /* __DEVICE_H__ */ + diff --git a/plugins/CDVDisoEFP/src/Win32/devicebox.c b/plugins/CDVDisoEFP/src/Win32/devicebox.c index c5c25fc3d8..1749908a8b 100644 --- a/plugins/CDVDisoEFP/src/Win32/devicebox.c +++ b/plugins/CDVDisoEFP/src/Win32/devicebox.c @@ -1,818 +1,818 @@ -/* devicebox.c - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#include - -#include // ComboBox_AddString() - -#include // NULL - - - -#include // sprintf() - -#include // strcpy() - -#include // stat() - -#include // stat() - -#include // stat() - - - -#define CDVDdefs - -#include "PS2Edefs.h" - - - -#include "conf.h" - -#include "device.h" - -#include "isofile.h" - -#include "isocompress.h" // compressdesc[] - -// #include "imagetype.h" // imagedata[].name - -#include "multifile.h" // multinames[] - -#include "toc.h" - -#include "progressbox.h" - -#include "mainbox.h" - -#include "screens.h" - -#include "devicebox.h" - - - - - -HWND deviceboxwindow; - - - - - -void DeviceBoxDestroy() { - - if(deviceboxwindow != NULL) { - - EndDialog(deviceboxwindow, FALSE); - - deviceboxwindow = NULL; - - } // ENDIF- Do we have a Main Window still? - -} // END DeviceBoxDestroy() - - - - - -void DeviceBoxUnfocus() { - - // gtk_widget_set_sensitive(devicebox.device, FALSE); - - // gtk_widget_set_sensitive(devicebox.file, FALSE); - - // gtk_widget_set_sensitive(devicebox.selectbutton, FALSE); - - // gtk_widget_set_sensitive(devicebox.compress, FALSE); - - // gtk_widget_set_sensitive(devicebox.multi, FALSE); - - // gtk_widget_set_sensitive(devicebox.okbutton, FALSE); - - // gtk_widget_set_sensitive(devicebox.cancelbutton, FALSE); - - ShowWindow(deviceboxwindow, SW_HIDE); - -} // END DeviceBoxUnfocus() - - - - - -void DeviceBoxDeviceEvent() { - - char tempdevice[256]; - - struct stat filestat; - - int returnval; - - - - GetDlgItemText(deviceboxwindow, IDC_0302, tempdevice, 256); - - returnval = stat(tempdevice, &filestat); - - if(returnval == -1) { - - SetDlgItemText(deviceboxwindow, IDC_0303, "Device Type: ---"); - - return; - - } // ENDIF- Not a name of any sort? - - - - if(S_ISDIR(filestat.st_mode) != 0) { - - SetDlgItemText(deviceboxwindow, IDC_0303, "Device Type: Not a device"); - - return; - - } // ENDIF- Not a regular file? - - - - SetDlgItemText(deviceboxwindow, IDC_0303, "Device Type: Device Likely"); - - return; - -} // END DeviceBoxDeviceEvent() - - - - - -void DeviceBoxFileEvent() { - - int returnval; - - char templine[256]; - - struct IsoFile *tempfile; - - - - GetDlgItemText(deviceboxwindow, IDC_0305, templine, 256); - - returnval = IsIsoFile(templine); - - if(returnval == -1) { - - SetDlgItemText(deviceboxwindow, IDC_0307, "File Type: ---"); - - return; - - } // ENDIF- Not a name of any sort? - - - - if(returnval == -2) { - - SetDlgItemText(deviceboxwindow, IDC_0307, "File Type: Not a file"); - - return; - - } // ENDIF- Not a regular file? - - - - if(returnval == -3) { - - SetDlgItemText(deviceboxwindow, IDC_0307, "File Type: Not a valid image file"); - - return; - - } // ENDIF- Not an image file? - - - - if(returnval == -4) { - - SetDlgItemText(deviceboxwindow, IDC_0307, "File Type: Missing Table File (will rebuild)"); - - return; - - } // ENDIF- Not a regular file? - - - - tempfile = IsoFileOpenForRead(templine); - - sprintf(templine, "File Type: %s%s%s", - - multinames[tempfile->multi], - - tempfile->imagename, - - compressdesc[tempfile->compress]); - - SetDlgItemText(deviceboxwindow, IDC_0307, templine); - - tempfile = IsoFileClose(tempfile); - - return; - -} // END DeviceBoxFileEvent() - - - - - -void DeviceBoxRefocus() { - - DeviceBoxDeviceEvent(); - - DeviceBoxFileEvent(); - - - - // gtk_widget_set_sensitive(devicebox.device, TRUE); - - // gtk_widget_set_sensitive(devicebox.file, TRUE); - - // gtk_widget_set_sensitive(devicebox.selectbutton, TRUE); - - // gtk_widget_set_sensitive(devicebox.compress, TRUE); - - // gtk_widget_set_sensitive(devicebox.multi, TRUE); - - // gtk_widget_set_sensitive(devicebox.okbutton, TRUE); - - // gtk_widget_set_sensitive(devicebox.cancelbutton, TRUE); - - // gtk_window_set_focus(GTK_WINDOW(devicebox.window), devicebox.file); - - ShowWindow(deviceboxwindow, SW_SHOW); - - SetActiveWindow(deviceboxwindow); - -} // END DeviceBoxRefocus() - - - - - -void DeviceBoxCancelEvent() { - - // ShowWindow(deviceboxwindow, SW_HIDE); - - DeviceBoxDestroy(); - - MainBoxRefocus(); - - return; - -} // END DeviceBoxCancelEvent() - - - - - -void DeviceBoxOKEvent() { - - char templine[256]; - - u8 tempbuffer[2352]; - - struct IsoFile *tofile; - - s32 retval; - - cdvdTD cdvdtd; - - int stop; - - HWND tempitem; - - int compressmethod; - - int multi; - - int imagetype; - - int i; - - - - DeviceBoxUnfocus(); - - - - GetDlgItemText(deviceboxwindow, IDC_0302, conf.devicename, 256); - - retval = DeviceOpen(); - - if(retval != 0) { - - DeviceClose(); - - DeviceBoxRefocus(); - - MessageBox(deviceboxwindow, - - "Could not open the device", - - "CDVDisoEFP Message", - - MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); - - return; - - } // ENDIF- Trouble opening device? Abort here. - - - - DeviceTrayStatus(); - - retval = DiscInserted(); - - if(retval != 0) { - - DeviceClose(); - - DeviceBoxRefocus(); - - MessageBox(deviceboxwindow, - - "No disc in the device\r\nPlease put a disc in and try again.", - - "CDVDisoEFP Message", - - MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); - - return; - - } // ENDIF- Trouble opening device? Abort here. - - - - retval = DeviceGetTD(0, &cdvdtd); // Fish for Ending Sector - - if(retval < 0) { - - DeviceClose(); - - DeviceBoxRefocus(); - - MessageBox(deviceboxwindow, - - "Could not retrieve disc sector size", - - "CDVDisoEFP Message", - - MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); - - return; - - } // ENDIF- Trouble getting disc sector count? - - - - tempitem = GetDlgItem(deviceboxwindow, IDC_0309); - - compressmethod = ComboBox_GetCurSel(tempitem); - - tempitem = NULL; - - if(compressmethod > 0) compressmethod += 2; - - - - multi = 0; - - if(IsDlgButtonChecked(deviceboxwindow, IDC_0311)) multi = 1; - - - - imagetype = 0; - - if((disctype != CDVD_TYPE_PS2DVD) && - - (disctype != CDVD_TYPE_DVDV)) imagetype = 8; - - - - GetDlgItemText(deviceboxwindow, IDC_0305, templine, 256); - - tofile = IsoFileOpenForWrite(templine, - - imagetype, - - multi, - - compressmethod); - - if(tofile == NULL) { - - DeviceClose(); - - DeviceBoxRefocus(); - - MessageBox(deviceboxwindow, - - "Could not create the new ISO file", - - "CDVDisoEFP Message", - - MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); - - return; - - } // ENDIF- Trouble opening the ISO file? - - - - // Open Progress Bar - - sprintf(templine, "%s -> %s", conf.devicename, tofile->name); - - ProgressBoxStart(templine, (off64_t) cdvdtd.lsn); - - - - tofile->cdvdtype = disctype; - - for(i = 0; i < 2048; i++) tofile->toc[i] = tocbuffer[i]; - - - - stop = 0; - - mainboxstop = 0; - - progressboxstop = 0; - - while((stop == 0) && (tofile->sectorpos < cdvdtd.lsn)) { - - if(imagetype == 0) { - - retval = DeviceReadTrack((u32) tofile->sectorpos, - - CDVD_MODE_2048, - - tempbuffer); - - } else { - - retval = DeviceReadTrack((u32) tofile->sectorpos, - - CDVD_MODE_2352, - - tempbuffer); - - } // ENDIF- Are we reading a DVD sector? (Or a CD sector?) - - if(retval < 0) { - - for(i = 0; i < 2352; i++) { - - tempbuffer[i] = 0; - - } // NEXT i- Zeroing the buffer - - } // ENDIF- Trouble reading next block? - - retval = IsoFileWrite(tofile, tempbuffer); - - if(retval < 0) { - - MessageBox(deviceboxwindow, - - "Trouble writing new file", - - "CDVDisoEFP Message", - - MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); - - stop = 1; - - } // ENDIF- Trouble writing out the next block? - - - - ProgressBoxTick(tofile->sectorpos); - - - - if(mainboxstop != 0) stop = 2; - - if(progressboxstop != 0) stop = 2; - - } // ENDWHILE- No reason found to stop... - - - - ProgressBoxStop(); - - - - if(stop == 0) { - - if(tofile->multi == 1) tofile->name[tofile->multipos] = '0'; // First file - - strcpy(templine, tofile->name); - - } // ENDIF- Did we succeed with the transfer? - - - - DeviceClose(); - - if(stop == 0) { - - IsoSaveTOC(tofile); - - tofile = IsoFileClose(tofile); - - SetDlgItemText(mainboxwindow, IDC_0202, templine); - - } else { - - tofile = IsoFileCloseAndDelete(tofile); - - } // ENDIF- (Failed to complete writing file? Get rid of the garbage files.) - - - - DeviceBoxRefocus(); - - if(stop == 0) DeviceBoxCancelEvent(); - - return; - -} // END DeviceBoxOKEvent() - - - - - -void DeviceBoxBrowseEvent() { - - OPENFILENAME filebox; - - char newfilename[256]; - - BOOL returnbool; - - - - filebox.lStructSize = sizeof(filebox); - - filebox.hwndOwner = deviceboxwindow; - - filebox.hInstance = NULL; - - filebox.lpstrFilter = fileselection; - - filebox.lpstrCustomFilter = NULL; - - filebox.nFilterIndex = 0; - - filebox.lpstrFile = newfilename; - - filebox.nMaxFile = 256; - - filebox.lpstrFileTitle = NULL; - - filebox.nMaxFileTitle = 0; - - filebox.lpstrInitialDir = NULL; - - filebox.lpstrTitle = NULL; - - filebox.Flags = OFN_PATHMUSTEXIST - - | OFN_NOCHANGEDIR - - | OFN_HIDEREADONLY; - - filebox.nFileOffset = 0; - - filebox.nFileExtension = 0; - - filebox.lpstrDefExt = NULL; - - filebox.lCustData = 0; - - filebox.lpfnHook = NULL; - - filebox.lpTemplateName = NULL; - - - - GetDlgItemText(deviceboxwindow, IDC_0305, newfilename, 256); - - returnbool = GetOpenFileName(&filebox); - - if(returnbool != FALSE) { - - SetDlgItemText(deviceboxwindow, IDC_0305, newfilename); - - } // ENDIF- User actually selected a name? Save it. - - - - return; - -} // END DeviceBoxBrowseEvent() - - - - - -void DeviceBoxDisplay() { - - char templine[256]; - - HWND itemptr; - - int itemcount; - - - - // Adjust Window Position? - - - - SetDlgItemText(deviceboxwindow, IDC_0302, conf.devicename); - - - - // DeviceBoxDeviceEvent(); // Needed? - - - - GetDlgItemText(mainboxwindow, IDC_0202, templine, 256); - - SetDlgItemText(deviceboxwindow, IDC_0305, templine); - - - - // DeviceBoxFileEvent(); // Needed? - - - - itemptr = GetDlgItem(deviceboxwindow, IDC_0309); // Compression Combo - - itemcount = 0; - - while(compressnames[itemcount] != NULL) { - - ComboBox_AddString(itemptr, compressnames[itemcount]); - - itemcount++; - - } // ENDWHILE- loading compression types into combo box - - ComboBox_SetCurSel(itemptr, 0); // First Selection? - - itemptr = NULL; - - - - CheckDlgButton(deviceboxwindow, IDC_0311, FALSE); // Start unchecked - - - - DeviceInit(); // Initialize device access - -} // END DeviceBoxDisplay() - - - - - -BOOL CALLBACK DeviceBoxCallback(HWND window, - - UINT msg, - - WPARAM param, - - LPARAM param2) { - - switch(msg) { - - case WM_INITDIALOG: - - deviceboxwindow = window; - - DeviceBoxDisplay(); // Final touches to this window - - return(FALSE); // Let Windows display this window - - break; - - - - case WM_CLOSE: // The "X" in the upper right corner was hit. - - DeviceBoxCancelEvent(); - - return(TRUE); - - break; - - - - case WM_COMMAND: - - switch(LOWORD(param)) { - - case IDC_0302: // Device Edit Box - - DeviceBoxDeviceEvent(); - - return(FALSE); - - break; - - - - case IDC_0305: // Filename Edit Box - - DeviceBoxFileEvent(); - - return(FALSE); - - break; - - - - case IDC_0306: // "Browse" Button - - DeviceBoxBrowseEvent(); - - return(TRUE); - - break; - - - - case IDC_0312: // "Make File" Button - - DeviceBoxOKEvent(); - - return(TRUE); - - break; - - - - case IDC_0313: // "Cancel" Button - - DeviceBoxCancelEvent(); - - return(TRUE); - - break; - - } // ENDSWITCH param- Which object got the message? - - } // ENDSWITCH msg- What message has been sent to this window? - - - - return(FALSE); - -} // END DeviceBoxCallback() - +/* devicebox.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + +#include // ComboBox_AddString() + +#include // NULL + + + +#include // sprintf() + +#include // strcpy() + +#include // stat() + +#include // stat() + +#include // stat() + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + +#include "conf.h" + +#include "device.h" + +#include "isofile.h" + +#include "isocompress.h" // compressdesc[] + +// #include "imagetype.h" // imagedata[].name + +#include "multifile.h" // multinames[] + +#include "toc.h" + +#include "progressbox.h" + +#include "mainbox.h" + +#include "screens.h" + +#include "devicebox.h" + + + + + +HWND deviceboxwindow; + + + + + +void DeviceBoxDestroy() { + + if(deviceboxwindow != NULL) { + + EndDialog(deviceboxwindow, FALSE); + + deviceboxwindow = NULL; + + } // ENDIF- Do we have a Main Window still? + +} // END DeviceBoxDestroy() + + + + + +void DeviceBoxUnfocus() { + + // gtk_widget_set_sensitive(devicebox.device, FALSE); + + // gtk_widget_set_sensitive(devicebox.file, FALSE); + + // gtk_widget_set_sensitive(devicebox.selectbutton, FALSE); + + // gtk_widget_set_sensitive(devicebox.compress, FALSE); + + // gtk_widget_set_sensitive(devicebox.multi, FALSE); + + // gtk_widget_set_sensitive(devicebox.okbutton, FALSE); + + // gtk_widget_set_sensitive(devicebox.cancelbutton, FALSE); + + ShowWindow(deviceboxwindow, SW_HIDE); + +} // END DeviceBoxUnfocus() + + + + + +void DeviceBoxDeviceEvent() { + + char tempdevice[256]; + + struct stat filestat; + + int returnval; + + + + GetDlgItemText(deviceboxwindow, IDC_0302, tempdevice, 256); + + returnval = stat(tempdevice, &filestat); + + if(returnval == -1) { + + SetDlgItemText(deviceboxwindow, IDC_0303, "Device Type: ---"); + + return; + + } // ENDIF- Not a name of any sort? + + + + if(S_ISDIR(filestat.st_mode) != 0) { + + SetDlgItemText(deviceboxwindow, IDC_0303, "Device Type: Not a device"); + + return; + + } // ENDIF- Not a regular file? + + + + SetDlgItemText(deviceboxwindow, IDC_0303, "Device Type: Device Likely"); + + return; + +} // END DeviceBoxDeviceEvent() + + + + + +void DeviceBoxFileEvent() { + + int returnval; + + char templine[256]; + + struct IsoFile *tempfile; + + + + GetDlgItemText(deviceboxwindow, IDC_0305, templine, 256); + + returnval = IsIsoFile(templine); + + if(returnval == -1) { + + SetDlgItemText(deviceboxwindow, IDC_0307, "File Type: ---"); + + return; + + } // ENDIF- Not a name of any sort? + + + + if(returnval == -2) { + + SetDlgItemText(deviceboxwindow, IDC_0307, "File Type: Not a file"); + + return; + + } // ENDIF- Not a regular file? + + + + if(returnval == -3) { + + SetDlgItemText(deviceboxwindow, IDC_0307, "File Type: Not a valid image file"); + + return; + + } // ENDIF- Not an image file? + + + + if(returnval == -4) { + + SetDlgItemText(deviceboxwindow, IDC_0307, "File Type: Missing Table File (will rebuild)"); + + return; + + } // ENDIF- Not a regular file? + + + + tempfile = IsoFileOpenForRead(templine); + + sprintf(templine, "File Type: %s%s%s", + + multinames[tempfile->multi], + + tempfile->imagename, + + compressdesc[tempfile->compress]); + + SetDlgItemText(deviceboxwindow, IDC_0307, templine); + + tempfile = IsoFileClose(tempfile); + + return; + +} // END DeviceBoxFileEvent() + + + + + +void DeviceBoxRefocus() { + + DeviceBoxDeviceEvent(); + + DeviceBoxFileEvent(); + + + + // gtk_widget_set_sensitive(devicebox.device, TRUE); + + // gtk_widget_set_sensitive(devicebox.file, TRUE); + + // gtk_widget_set_sensitive(devicebox.selectbutton, TRUE); + + // gtk_widget_set_sensitive(devicebox.compress, TRUE); + + // gtk_widget_set_sensitive(devicebox.multi, TRUE); + + // gtk_widget_set_sensitive(devicebox.okbutton, TRUE); + + // gtk_widget_set_sensitive(devicebox.cancelbutton, TRUE); + + // gtk_window_set_focus(GTK_WINDOW(devicebox.window), devicebox.file); + + ShowWindow(deviceboxwindow, SW_SHOW); + + SetActiveWindow(deviceboxwindow); + +} // END DeviceBoxRefocus() + + + + + +void DeviceBoxCancelEvent() { + + // ShowWindow(deviceboxwindow, SW_HIDE); + + DeviceBoxDestroy(); + + MainBoxRefocus(); + + return; + +} // END DeviceBoxCancelEvent() + + + + + +void DeviceBoxOKEvent() { + + char templine[256]; + + u8 tempbuffer[2352]; + + struct IsoFile *tofile; + + s32 retval; + + cdvdTD cdvdtd; + + int stop; + + HWND tempitem; + + int compressmethod; + + int multi; + + int imagetype; + + int i; + + + + DeviceBoxUnfocus(); + + + + GetDlgItemText(deviceboxwindow, IDC_0302, conf.devicename, 256); + + retval = DeviceOpen(); + + if(retval != 0) { + + DeviceClose(); + + DeviceBoxRefocus(); + + MessageBox(deviceboxwindow, + + "Could not open the device", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + return; + + } // ENDIF- Trouble opening device? Abort here. + + + + DeviceTrayStatus(); + + retval = DiscInserted(); + + if(retval != 0) { + + DeviceClose(); + + DeviceBoxRefocus(); + + MessageBox(deviceboxwindow, + + "No disc in the device\r\nPlease put a disc in and try again.", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + return; + + } // ENDIF- Trouble opening device? Abort here. + + + + retval = DeviceGetTD(0, &cdvdtd); // Fish for Ending Sector + + if(retval < 0) { + + DeviceClose(); + + DeviceBoxRefocus(); + + MessageBox(deviceboxwindow, + + "Could not retrieve disc sector size", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + return; + + } // ENDIF- Trouble getting disc sector count? + + + + tempitem = GetDlgItem(deviceboxwindow, IDC_0309); + + compressmethod = ComboBox_GetCurSel(tempitem); + + tempitem = NULL; + + if(compressmethod > 0) compressmethod += 2; + + + + multi = 0; + + if(IsDlgButtonChecked(deviceboxwindow, IDC_0311)) multi = 1; + + + + imagetype = 0; + + if((disctype != CDVD_TYPE_PS2DVD) && + + (disctype != CDVD_TYPE_DVDV)) imagetype = 8; + + + + GetDlgItemText(deviceboxwindow, IDC_0305, templine, 256); + + tofile = IsoFileOpenForWrite(templine, + + imagetype, + + multi, + + compressmethod); + + if(tofile == NULL) { + + DeviceClose(); + + DeviceBoxRefocus(); + + MessageBox(deviceboxwindow, + + "Could not create the new ISO file", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + return; + + } // ENDIF- Trouble opening the ISO file? + + + + // Open Progress Bar + + sprintf(templine, "%s -> %s", conf.devicename, tofile->name); + + ProgressBoxStart(templine, (off64_t) cdvdtd.lsn); + + + + tofile->cdvdtype = disctype; + + for(i = 0; i < 2048; i++) tofile->toc[i] = tocbuffer[i]; + + + + stop = 0; + + mainboxstop = 0; + + progressboxstop = 0; + + while((stop == 0) && (tofile->sectorpos < cdvdtd.lsn)) { + + if(imagetype == 0) { + + retval = DeviceReadTrack((u32) tofile->sectorpos, + + CDVD_MODE_2048, + + tempbuffer); + + } else { + + retval = DeviceReadTrack((u32) tofile->sectorpos, + + CDVD_MODE_2352, + + tempbuffer); + + } // ENDIF- Are we reading a DVD sector? (Or a CD sector?) + + if(retval < 0) { + + for(i = 0; i < 2352; i++) { + + tempbuffer[i] = 0; + + } // NEXT i- Zeroing the buffer + + } // ENDIF- Trouble reading next block? + + retval = IsoFileWrite(tofile, tempbuffer); + + if(retval < 0) { + + MessageBox(deviceboxwindow, + + "Trouble writing new file", + + "CDVDisoEFP Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + stop = 1; + + } // ENDIF- Trouble writing out the next block? + + + + ProgressBoxTick(tofile->sectorpos); + + + + if(mainboxstop != 0) stop = 2; + + if(progressboxstop != 0) stop = 2; + + } // ENDWHILE- No reason found to stop... + + + + ProgressBoxStop(); + + + + if(stop == 0) { + + if(tofile->multi == 1) tofile->name[tofile->multipos] = '0'; // First file + + strcpy(templine, tofile->name); + + } // ENDIF- Did we succeed with the transfer? + + + + DeviceClose(); + + if(stop == 0) { + + IsoSaveTOC(tofile); + + tofile = IsoFileClose(tofile); + + SetDlgItemText(mainboxwindow, IDC_0202, templine); + + } else { + + tofile = IsoFileCloseAndDelete(tofile); + + } // ENDIF- (Failed to complete writing file? Get rid of the garbage files.) + + + + DeviceBoxRefocus(); + + if(stop == 0) DeviceBoxCancelEvent(); + + return; + +} // END DeviceBoxOKEvent() + + + + + +void DeviceBoxBrowseEvent() { + + OPENFILENAME filebox; + + char newfilename[256]; + + BOOL returnbool; + + + + filebox.lStructSize = sizeof(filebox); + + filebox.hwndOwner = deviceboxwindow; + + filebox.hInstance = NULL; + + filebox.lpstrFilter = fileselection; + + filebox.lpstrCustomFilter = NULL; + + filebox.nFilterIndex = 0; + + filebox.lpstrFile = newfilename; + + filebox.nMaxFile = 256; + + filebox.lpstrFileTitle = NULL; + + filebox.nMaxFileTitle = 0; + + filebox.lpstrInitialDir = NULL; + + filebox.lpstrTitle = NULL; + + filebox.Flags = OFN_PATHMUSTEXIST + + | OFN_NOCHANGEDIR + + | OFN_HIDEREADONLY; + + filebox.nFileOffset = 0; + + filebox.nFileExtension = 0; + + filebox.lpstrDefExt = NULL; + + filebox.lCustData = 0; + + filebox.lpfnHook = NULL; + + filebox.lpTemplateName = NULL; + + + + GetDlgItemText(deviceboxwindow, IDC_0305, newfilename, 256); + + returnbool = GetOpenFileName(&filebox); + + if(returnbool != FALSE) { + + SetDlgItemText(deviceboxwindow, IDC_0305, newfilename); + + } // ENDIF- User actually selected a name? Save it. + + + + return; + +} // END DeviceBoxBrowseEvent() + + + + + +void DeviceBoxDisplay() { + + char templine[256]; + + HWND itemptr; + + int itemcount; + + + + // Adjust Window Position? + + + + SetDlgItemText(deviceboxwindow, IDC_0302, conf.devicename); + + + + // DeviceBoxDeviceEvent(); // Needed? + + + + GetDlgItemText(mainboxwindow, IDC_0202, templine, 256); + + SetDlgItemText(deviceboxwindow, IDC_0305, templine); + + + + // DeviceBoxFileEvent(); // Needed? + + + + itemptr = GetDlgItem(deviceboxwindow, IDC_0309); // Compression Combo + + itemcount = 0; + + while(compressnames[itemcount] != NULL) { + + ComboBox_AddString(itemptr, compressnames[itemcount]); + + itemcount++; + + } // ENDWHILE- loading compression types into combo box + + ComboBox_SetCurSel(itemptr, 0); // First Selection? + + itemptr = NULL; + + + + CheckDlgButton(deviceboxwindow, IDC_0311, FALSE); // Start unchecked + + + + DeviceInit(); // Initialize device access + +} // END DeviceBoxDisplay() + + + + + +BOOL CALLBACK DeviceBoxCallback(HWND window, + + UINT msg, + + WPARAM param, + + LPARAM param2) { + + switch(msg) { + + case WM_INITDIALOG: + + deviceboxwindow = window; + + DeviceBoxDisplay(); // Final touches to this window + + return(FALSE); // Let Windows display this window + + break; + + + + case WM_CLOSE: // The "X" in the upper right corner was hit. + + DeviceBoxCancelEvent(); + + return(TRUE); + + break; + + + + case WM_COMMAND: + + switch(LOWORD(param)) { + + case IDC_0302: // Device Edit Box + + DeviceBoxDeviceEvent(); + + return(FALSE); + + break; + + + + case IDC_0305: // Filename Edit Box + + DeviceBoxFileEvent(); + + return(FALSE); + + break; + + + + case IDC_0306: // "Browse" Button + + DeviceBoxBrowseEvent(); + + return(TRUE); + + break; + + + + case IDC_0312: // "Make File" Button + + DeviceBoxOKEvent(); + + return(TRUE); + + break; + + + + case IDC_0313: // "Cancel" Button + + DeviceBoxCancelEvent(); + + return(TRUE); + + break; + + } // ENDSWITCH param- Which object got the message? + + } // ENDSWITCH msg- What message has been sent to this window? + + + + return(FALSE); + +} // END DeviceBoxCallback() + diff --git a/plugins/CDVDisoEFP/src/Win32/devicebox.h b/plugins/CDVDisoEFP/src/Win32/devicebox.h index bf699f5d1d..aa693e3e98 100644 --- a/plugins/CDVDisoEFP/src/Win32/devicebox.h +++ b/plugins/CDVDisoEFP/src/Win32/devicebox.h @@ -1,41 +1,82 @@ -/* devicebox.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef DEVICEBOX_H -#define DEVICEBOX_H - - -#include // HWND - - -extern HWND deviceboxwindow; - -extern void DeviceBoxDestroy(); -// extern void DeviceBoxUnfocus(); -extern void DeviceBoxRefocus(); -extern void DeviceBoxDisplay(); -extern BOOL CALLBACK DeviceBoxCallback(HWND window, - UINT msg, - WPARAM param, - LPARAM param2); - - -#endif /* DEVICEBOX_H */ +/* devicebox.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef DEVICEBOX_H + +#define DEVICEBOX_H + + + + + +#include // HWND + + + + + +extern HWND deviceboxwindow; + + + +extern void DeviceBoxDestroy(); + +// extern void DeviceBoxUnfocus(); + +extern void DeviceBoxRefocus(); + +extern void DeviceBoxDisplay(); + +extern BOOL CALLBACK DeviceBoxCallback(HWND window, + + UINT msg, + + WPARAM param, + + LPARAM param2); + + + + + +#endif /* DEVICEBOX_H */ + diff --git a/plugins/CDVDisoEFP/src/Win32/logfile.c b/plugins/CDVDisoEFP/src/Win32/logfile.c index 28f82eb088..8d1226e298 100644 --- a/plugins/CDVDisoEFP/src/Win32/logfile.c +++ b/plugins/CDVDisoEFP/src/Win32/logfile.c @@ -1,119 +1,238 @@ -/* logfile.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include - -// #include // open() -// #include // mkdir() -#include // NULL -#include // vsprintf() -#include // va_start(), va_end(), vsprintf() -// #include // open() -// #include // open() - -#include "logfile.h" - - -HANDLE logfile; -char logfiletemp[2048]; - - -void InitLog() { - // Token comment line -#ifdef VERBOSE_LOGFILE - CreateDirectory("logs", NULL); - - DeleteFile("logs\\CDVDlog.txt"); - logfile = NULL; -#endif /* VERBOSE LOGFILE */ -} // END InitLog(); - - -int OpenLog() { - // Token comment line -#ifdef VERBOSE_LOGFILE - logfile = CreateFile("logs\\CDVDlog.txt", - GENERIC_WRITE, - 0, - NULL, - CREATE_ALWAYS, - FILE_FLAG_SEQUENTIAL_SCAN, - NULL); - if(logfile == INVALID_HANDLE_VALUE) { - logfile = NULL; - return(-1); - } // ENDIF- Failed to open? Say so. -#endif /* VERBOSE LOGFILE */ - - return(0); -} // END OpenLog(); - - -void CloseLog() { - // Token comment line -#ifdef VERBOSE_LOGFILE - if(logfile != NULL) { - CloseHandle(logfile); - logfile = NULL; - } // ENDIF- Is the log file actually open? Close it. -#endif /* VERBOSE LOGFILE */ -} // END CloseLog() - - -void PrintLog(const char *fmt, ...) { - DWORD byteswritten; - - // Token comment line -#ifdef VERBOSE_LOGFILE - va_list list; - int len; - - if(logfile == NULL) return; // Log file not open... yet. - - va_start(list, fmt); - vsprintf(logfiletemp, fmt, list); - va_end(list); - - len = 0; - while((len < 2048) && (logfiletemp[len] != 0)) len++; - if((len > 0) && (logfiletemp[len-1] == '\n')) len--; - if((len > 0) && (logfiletemp[len-1] == '\r')) len--; - logfiletemp[len] = 0; // Slice off the last "\r\n"... - - WriteFile(logfile, logfiletemp, len, &byteswritten, NULL); - WriteFile(logfile, "\r\n", 2, &byteswritten, NULL); -#endif /* VERBOSE LOGFILE */ -} // END PrintLog() - -void PrintError(const char *header, DWORD errcode) { -#ifdef VERBOSE_LOGFILE - TCHAR errmsg[256]; - - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | 80, - NULL, - errcode, - 0, - errmsg, - 256, - NULL); - PrintLog("%s: (%u) %s", header, errcode, errmsg); -#endif /* VERBOSE_WARNING_DEVICE */ -} // END PrintError() +/* logfile.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + + + +// #include // open() + +// #include // mkdir() + +#include // NULL + +#include // vsprintf() + +#include // va_start(), va_end(), vsprintf() + +// #include // open() + +// #include // open() + + + +#include "logfile.h" + + + + + +HANDLE logfile; + +char logfiletemp[2048]; + + + + + +void InitLog() { + + // Token comment line + +#ifdef VERBOSE_LOGFILE + + CreateDirectory("logs", NULL); + + + + DeleteFile("logs\\CDVDlog.txt"); + + logfile = NULL; + +#endif /* VERBOSE LOGFILE */ + +} // END InitLog(); + + + + + +int OpenLog() { + + // Token comment line + +#ifdef VERBOSE_LOGFILE + + logfile = CreateFile("logs\\CDVDlog.txt", + + GENERIC_WRITE, + + 0, + + NULL, + + CREATE_ALWAYS, + + FILE_FLAG_SEQUENTIAL_SCAN, + + NULL); + + if(logfile == INVALID_HANDLE_VALUE) { + + logfile = NULL; + + return(-1); + + } // ENDIF- Failed to open? Say so. + +#endif /* VERBOSE LOGFILE */ + + + + return(0); + +} // END OpenLog(); + + + + + +void CloseLog() { + + // Token comment line + +#ifdef VERBOSE_LOGFILE + + if(logfile != NULL) { + + CloseHandle(logfile); + + logfile = NULL; + + } // ENDIF- Is the log file actually open? Close it. + +#endif /* VERBOSE LOGFILE */ + +} // END CloseLog() + + + + + +void PrintLog(const char *fmt, ...) { + + DWORD byteswritten; + + + + // Token comment line + +#ifdef VERBOSE_LOGFILE + + va_list list; + + int len; + + + + if(logfile == NULL) return; // Log file not open... yet. + + + + va_start(list, fmt); + + vsprintf(logfiletemp, fmt, list); + + va_end(list); + + + + len = 0; + + while((len < 2048) && (logfiletemp[len] != 0)) len++; + + if((len > 0) && (logfiletemp[len-1] == '\n')) len--; + + if((len > 0) && (logfiletemp[len-1] == '\r')) len--; + + logfiletemp[len] = 0; // Slice off the last "\r\n"... + + + + WriteFile(logfile, logfiletemp, len, &byteswritten, NULL); + + WriteFile(logfile, "\r\n", 2, &byteswritten, NULL); + +#endif /* VERBOSE LOGFILE */ + +} // END PrintLog() + + + +void PrintError(const char *header, DWORD errcode) { + +#ifdef VERBOSE_LOGFILE + + TCHAR errmsg[256]; + + + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | 80, + + NULL, + + errcode, + + 0, + + errmsg, + + 256, + + NULL); + + PrintLog("%s: (%u) %s", header, errcode, errmsg); + +#endif /* VERBOSE_WARNING_DEVICE */ + +} // END PrintError() + diff --git a/plugins/CDVDisoEFP/src/Win32/logfile.h b/plugins/CDVDisoEFP/src/Win32/logfile.h index ff6e3b0c1c..3efaad8f4d 100644 --- a/plugins/CDVDisoEFP/src/Win32/logfile.h +++ b/plugins/CDVDisoEFP/src/Win32/logfile.h @@ -1,39 +1,78 @@ -/* logfile.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef LOGFILE_H -#define LOGFILE_H - - -#include // Just for DWORD - - -#define VERBOSE_LOGFILE - - -extern void InitLog(); -extern int OpenLog(); -extern void CloseLog(); -extern void PrintLog(const char *format, ...); -extern void PrintError(const char *header, DWORD errcode); - - -#endif /* LOGFILE_H */ +/* logfile.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef LOGFILE_H + +#define LOGFILE_H + + + + + +#include // Just for DWORD + + + + + +#define VERBOSE_LOGFILE + + + + + +extern void InitLog(); + +extern int OpenLog(); + +extern void CloseLog(); + +extern void PrintLog(const char *format, ...); + +extern void PrintError(const char *header, DWORD errcode); + + + + + +#endif /* LOGFILE_H */ + diff --git a/plugins/CDVDisoEFP/src/Win32/mainbox.c b/plugins/CDVDisoEFP/src/Win32/mainbox.c index fe5488497e..2b831829b4 100644 --- a/plugins/CDVDisoEFP/src/Win32/mainbox.c +++ b/plugins/CDVDisoEFP/src/Win32/mainbox.c @@ -1,309 +1,309 @@ -/* mainbox.c - * Copyright (C) 2002-2005 CDVDiso 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include // Button_ -#include // NULL - -#include // sprintf() -#include // strcpy() - -#include "conf.h" -#include "isofile.h" -#include "isocompress.h" // compressdesc[] -// #include "imagetype.h" // imagedata[].name -#include "multifile.h" // multinames[] -#include "tablerebuild.h" // IsoTableRebuild() -#include "devicebox.h" -#include "conversionbox.h" -#include "progressbox.h" -#include "screens.h" // DLG_, IDC_ -#include "CDVDiso.h" // progmodule -#include "mainbox.h" - - -const char fileselection[] = "\Disc Image Files (*.bin,*.img,*.iso,*.nrg)\0*.bin;*.img;*.iso;*.nrg\0\All Files (*.*)\0*.*\0\\0\0"; - - -HWND mainboxwindow; -int mainboxstop; - - -void MainBoxDestroy() { - if(progressboxwindow != NULL) { - ProgressBoxDestroy(); - } // ENDIF- Do we have a Progress Window still? - - if(mainboxwindow != NULL) { - EndDialog(mainboxwindow, FALSE); - mainboxwindow = NULL; - } // ENDIF- Do we have a Main Window still? -} // END MainBoxDestroy() - - -void MainBoxUnfocus() { - // EnableWindow(?) - // gtk_widget_set_sensitive(mainbox.file, FALSE); - // gtk_widget_set_sensitive(mainbox.selectbutton, FALSE); - // gtk_widget_set_sensitive(mainbox.okbutton, FALSE); - // gtk_widget_set_sensitive(mainbox.devbutton, FALSE); - // gtk_widget_set_sensitive(mainbox.convbutton, FALSE); - ShowWindow(mainboxwindow, SW_HIDE); -} // END MainBoxUnfocus() - - -void MainBoxFileEvent() { - int returnval; - char templine[256]; - struct IsoFile *tempfile; - - GetDlgItemText(mainboxwindow, IDC_0202, templine, 256); - returnval = IsIsoFile(templine); - if(returnval == -1) { - SetDlgItemText(mainboxwindow, IDC_0204, "File Type: ---"); - return; - } // ENDIF- Not a name of any sort? - - if(returnval == -2) { - SetDlgItemText(mainboxwindow, IDC_0204, "File Type: Not a file"); - return; - } // ENDIF- Not a regular file? - - if(returnval == -3) { - SetDlgItemText(mainboxwindow, IDC_0204, "File Type: Not a valid image file"); - return; - } // ENDIF- Not an Image file? - - if(returnval == -4) { - SetDlgItemText(mainboxwindow, IDC_0204, "File Type: Missing Table File (will rebuild)"); - return; - } // ENDIF- Missing Compression seek table? - - tempfile = IsoFileOpenForRead(templine); - sprintf(templine, "File Type: %s%s%s", - multinames[tempfile->multi], - tempfile->imagename, - compressdesc[tempfile->compress]); - SetDlgItemText(mainboxwindow, IDC_0204, templine); - tempfile = IsoFileClose(tempfile); - return; -} // END MainBoxFileEvent() - - -void MainBoxRefocus() { - MainBoxFileEvent(); - - // gtk_widget_set_sensitive(mainbox.file, TRUE); - // gtk_widget_set_sensitive(mainbox.selectbutton, TRUE); - // gtk_widget_set_sensitive(mainbox.okbutton, TRUE); - // gtk_widget_set_sensitive(mainbox.devbutton, TRUE); - // gtk_widget_set_sensitive(mainbox.convbutton, TRUE); - // gtk_window_set_focus(GTK_WINDOW(mainbox.window), mainbox.file); - // ShowWindow(mainboxwindow, SW_RESTORE); // and/or, SW_SHOW? SW_SHOWNORMAL? - ShowWindow(mainboxwindow, SW_SHOW); - SetActiveWindow(mainboxwindow); -} // END MainBoxRefocus() - - -void MainBoxCancelEvent() { - mainboxstop = 1; // Halt all long processess... - - MainBoxDestroy(); - return; -} // END MainBoxCancelEvent() - - -void MainBoxOKEvent() { - char tempisoname[256]; - - MainBoxUnfocus(); - - GetDlgItemText(mainboxwindow, IDC_0202, tempisoname, 256); - if(*(tempisoname) != 0) { - if(IsIsoFile(tempisoname) == -4) { - IsoTableRebuild(tempisoname); - MainBoxRefocus(); - return; - } // ENDIF- Do we need to rebuild an image file's index before using it? - - if(IsIsoFile(tempisoname) < 0) { - MainBoxRefocus(); - MessageBox(mainboxwindow, - "Not a Valid Image File.", - "CDVDisoEFP Message", - MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); - return; - } // ENDIF- Not an ISO file? Message and Stop here. - } // ENDIF- Do we have a name to check out? - - strcpy(conf.isoname, tempisoname); - if(Button_GetCheck(GetDlgItem(mainboxwindow, IDC_0209)) == BST_UNCHECKED) { - conf.startconfigure = 0; // FALSE - } else { - conf.startconfigure = 1; // TRUE - } // ENDIF- Was this checkbox unchecked? - if(Button_GetCheck(GetDlgItem(mainboxwindow, IDC_0210)) == BST_UNCHECKED) { - conf.restartconfigure = 0; // FALSE - } else { - conf.restartconfigure = 1; // TRUE - } // ENDIF- Was this checkbox unchecked? - SaveConf(); - - MainBoxCancelEvent(); - return; -} // END MainBoxOKEvent() - - -void MainBoxBrowseEvent() { - OPENFILENAME filebox; - char newfilename[256]; - BOOL returnbool; - - filebox.lStructSize = sizeof(filebox); - filebox.hwndOwner = mainboxwindow; - filebox.hInstance = NULL; - filebox.lpstrFilter = fileselection; - filebox.lpstrCustomFilter = NULL; - filebox.nFilterIndex = 0; - filebox.lpstrFile = newfilename; - filebox.nMaxFile = 256; - filebox.lpstrFileTitle = NULL; - filebox.nMaxFileTitle = 0; - filebox.lpstrInitialDir = NULL; - filebox.lpstrTitle = NULL; - filebox.Flags = OFN_FILEMUSTEXIST - | OFN_NOCHANGEDIR - | OFN_HIDEREADONLY; - filebox.nFileOffset = 0; - filebox.nFileExtension = 0; - filebox.lpstrDefExt = NULL; - filebox.lCustData = 0; - filebox.lpfnHook = NULL; - filebox.lpTemplateName = NULL; - - GetDlgItemText(mainboxwindow, IDC_0202, newfilename, 256); - returnbool = GetOpenFileName(&filebox); - if(returnbool != FALSE) { - SetDlgItemText(mainboxwindow, IDC_0202, newfilename); - } // ENDIF- User actually selected a name? Save it. - - return; -} // END MainBoxBrowseEvent() - - -void MainBoxDeviceEvent() { - MainBoxUnfocus(); - - DialogBox(progmodule, - MAKEINTRESOURCE(DLG_0300), - mainboxwindow, - (DLGPROC)DeviceBoxCallback); - return; -} // END MainBoxBrowseEvent() - - -void MainBoxConversionEvent() { - MainBoxUnfocus(); - - DialogBox(progmodule, - MAKEINTRESOURCE(DLG_0400), - mainboxwindow, - (DLGPROC)ConversionBoxCallback); - return; -} // END MainBoxBrowseEvent() - - -void MainBoxDisplay() { - LoadConf(); - - // Adjust window position? - - // We held off setting the name until now... so description would show. - SetDlgItemText(mainboxwindow, IDC_0202, conf.isoname); - if(conf.startconfigure == 0) { - Button_SetCheck(GetDlgItem(mainboxwindow, IDC_0209), BST_UNCHECKED); - } else { - Button_SetCheck(GetDlgItem(mainboxwindow, IDC_0209), BST_CHECKED); - } // ENDIF- Do we need to uncheck this box? - if(conf.restartconfigure == 0) { - Button_SetCheck(GetDlgItem(mainboxwindow, IDC_0210), BST_UNCHECKED); - } else { - Button_SetCheck(GetDlgItem(mainboxwindow, IDC_0210), BST_CHECKED); - } // ENDIF- Do we need to uncheck this box? - - // First Time - Show the window - ShowWindow(mainboxwindow, SW_SHOWNORMAL); -} // END MainBoxDisplay() - - -BOOL CALLBACK MainBoxCallback(HWND window, - UINT msg, - WPARAM param, - LPARAM param2) { - switch(msg) { - case WM_INITDIALOG: - mainboxwindow = window; - MainBoxDisplay(); // In this case, final touches to this window. - ProgressBoxDisplay(); // Create the Progress Box at this time. - return(FALSE); // And let Windows display this window. - break; - - case WM_CLOSE: // The "X" in the upper right corner was hit. - MainBoxCancelEvent(); - return(TRUE); - break; - - case WM_COMMAND: - // Do we wish to capture 'ENTER/RETURN' and/or 'ESC' here? - - switch(LOWORD(param)) { - case IDC_0202: // Filename Edit Box - MainBoxFileEvent(); // Describe the File's type... - return(FALSE); // Let Windows handle the actual 'edit' processing... - break; - - case IDC_0203: // "Browse" Button - MainBoxBrowseEvent(); - return(TRUE); - break; - - case IDC_0205: // "Ok" Button - MainBoxOKEvent(); - return(TRUE); - break; - - case IDC_0206: // "Get from Disc" Button - MainBoxDeviceEvent(); - return(TRUE); - break; - - case IDC_0207: // "Convert" Button - MainBoxConversionEvent(); - return(TRUE); - break; - - case IDC_0208: // "Cancel" Button - MainBoxCancelEvent(); - return(TRUE); - break; - } // ENDSWITCH param- Which object got the message? - } // ENDSWITCH msg- what message has been sent to this window? - - return(FALSE); // Not a recognized message? Tell Windows to handle it. -} // END MainBoxEventLoop() +/* mainbox.c + * Copyright (C) 2002-2005 CDVDiso 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include // Button_ +#include // NULL + +#include // sprintf() +#include // strcpy() + +#include "conf.h" +#include "isofile.h" +#include "isocompress.h" // compressdesc[] +// #include "imagetype.h" // imagedata[].name +#include "multifile.h" // multinames[] +#include "tablerebuild.h" // IsoTableRebuild() +#include "devicebox.h" +#include "conversionbox.h" +#include "progressbox.h" +#include "screens.h" // DLG_, IDC_ +#include "CDVDiso.h" // progmodule +#include "mainbox.h" + + +const char fileselection[] = "\Disc Image Files (*.bin,*.img,*.iso,*.nrg)\0*.bin;*.img;*.iso;*.nrg\0\All Files (*.*)\0*.*\0\\0\0"; + + +HWND mainboxwindow; +int mainboxstop; + + +void MainBoxDestroy() { + if(progressboxwindow != NULL) { + ProgressBoxDestroy(); + } // ENDIF- Do we have a Progress Window still? + + if(mainboxwindow != NULL) { + EndDialog(mainboxwindow, FALSE); + mainboxwindow = NULL; + } // ENDIF- Do we have a Main Window still? +} // END MainBoxDestroy() + + +void MainBoxUnfocus() { + // EnableWindow(?) + // gtk_widget_set_sensitive(mainbox.file, FALSE); + // gtk_widget_set_sensitive(mainbox.selectbutton, FALSE); + // gtk_widget_set_sensitive(mainbox.okbutton, FALSE); + // gtk_widget_set_sensitive(mainbox.devbutton, FALSE); + // gtk_widget_set_sensitive(mainbox.convbutton, FALSE); + ShowWindow(mainboxwindow, SW_HIDE); +} // END MainBoxUnfocus() + + +void MainBoxFileEvent() { + int returnval; + char templine[256]; + struct IsoFile *tempfile; + + GetDlgItemText(mainboxwindow, IDC_0202, templine, 256); + returnval = IsIsoFile(templine); + if(returnval == -1) { + SetDlgItemText(mainboxwindow, IDC_0204, "File Type: ---"); + return; + } // ENDIF- Not a name of any sort? + + if(returnval == -2) { + SetDlgItemText(mainboxwindow, IDC_0204, "File Type: Not a file"); + return; + } // ENDIF- Not a regular file? + + if(returnval == -3) { + SetDlgItemText(mainboxwindow, IDC_0204, "File Type: Not a valid image file"); + return; + } // ENDIF- Not an Image file? + + if(returnval == -4) { + SetDlgItemText(mainboxwindow, IDC_0204, "File Type: Missing Table File (will rebuild)"); + return; + } // ENDIF- Missing Compression seek table? + + tempfile = IsoFileOpenForRead(templine); + sprintf(templine, "File Type: %s%s%s", + multinames[tempfile->multi], + tempfile->imagename, + compressdesc[tempfile->compress]); + SetDlgItemText(mainboxwindow, IDC_0204, templine); + tempfile = IsoFileClose(tempfile); + return; +} // END MainBoxFileEvent() + + +void MainBoxRefocus() { + MainBoxFileEvent(); + + // gtk_widget_set_sensitive(mainbox.file, TRUE); + // gtk_widget_set_sensitive(mainbox.selectbutton, TRUE); + // gtk_widget_set_sensitive(mainbox.okbutton, TRUE); + // gtk_widget_set_sensitive(mainbox.devbutton, TRUE); + // gtk_widget_set_sensitive(mainbox.convbutton, TRUE); + // gtk_window_set_focus(GTK_WINDOW(mainbox.window), mainbox.file); + // ShowWindow(mainboxwindow, SW_RESTORE); // and/or, SW_SHOW? SW_SHOWNORMAL? + ShowWindow(mainboxwindow, SW_SHOW); + SetActiveWindow(mainboxwindow); +} // END MainBoxRefocus() + + +void MainBoxCancelEvent() { + mainboxstop = 1; // Halt all long processess... + + MainBoxDestroy(); + return; +} // END MainBoxCancelEvent() + + +void MainBoxOKEvent() { + char tempisoname[256]; + + MainBoxUnfocus(); + + GetDlgItemText(mainboxwindow, IDC_0202, tempisoname, 256); + if(*(tempisoname) != 0) { + if(IsIsoFile(tempisoname) == -4) { + IsoTableRebuild(tempisoname); + MainBoxRefocus(); + return; + } // ENDIF- Do we need to rebuild an image file's index before using it? + + if(IsIsoFile(tempisoname) < 0) { + MainBoxRefocus(); + MessageBox(mainboxwindow, + "Not a Valid Image File.", + "CDVDisoEFP Message", + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + return; + } // ENDIF- Not an ISO file? Message and Stop here. + } // ENDIF- Do we have a name to check out? + + strcpy(conf.isoname, tempisoname); + if(Button_GetCheck(GetDlgItem(mainboxwindow, IDC_0209)) == BST_UNCHECKED) { + conf.startconfigure = 0; // FALSE + } else { + conf.startconfigure = 1; // TRUE + } // ENDIF- Was this checkbox unchecked? + if(Button_GetCheck(GetDlgItem(mainboxwindow, IDC_0210)) == BST_UNCHECKED) { + conf.restartconfigure = 0; // FALSE + } else { + conf.restartconfigure = 1; // TRUE + } // ENDIF- Was this checkbox unchecked? + SaveConf(); + + MainBoxCancelEvent(); + return; +} // END MainBoxOKEvent() + + +void MainBoxBrowseEvent() { + OPENFILENAME filebox; + char newfilename[256]; + BOOL returnbool; + + filebox.lStructSize = sizeof(filebox); + filebox.hwndOwner = mainboxwindow; + filebox.hInstance = NULL; + filebox.lpstrFilter = fileselection; + filebox.lpstrCustomFilter = NULL; + filebox.nFilterIndex = 0; + filebox.lpstrFile = newfilename; + filebox.nMaxFile = 256; + filebox.lpstrFileTitle = NULL; + filebox.nMaxFileTitle = 0; + filebox.lpstrInitialDir = NULL; + filebox.lpstrTitle = NULL; + filebox.Flags = OFN_FILEMUSTEXIST + | OFN_NOCHANGEDIR + | OFN_HIDEREADONLY; + filebox.nFileOffset = 0; + filebox.nFileExtension = 0; + filebox.lpstrDefExt = NULL; + filebox.lCustData = 0; + filebox.lpfnHook = NULL; + filebox.lpTemplateName = NULL; + + GetDlgItemText(mainboxwindow, IDC_0202, newfilename, 256); + returnbool = GetOpenFileName(&filebox); + if(returnbool != FALSE) { + SetDlgItemText(mainboxwindow, IDC_0202, newfilename); + } // ENDIF- User actually selected a name? Save it. + + return; +} // END MainBoxBrowseEvent() + + +void MainBoxDeviceEvent() { + MainBoxUnfocus(); + + DialogBox(progmodule, + MAKEINTRESOURCE(DLG_0300), + mainboxwindow, + (DLGPROC)DeviceBoxCallback); + return; +} // END MainBoxBrowseEvent() + + +void MainBoxConversionEvent() { + MainBoxUnfocus(); + + DialogBox(progmodule, + MAKEINTRESOURCE(DLG_0400), + mainboxwindow, + (DLGPROC)ConversionBoxCallback); + return; +} // END MainBoxBrowseEvent() + + +void MainBoxDisplay() { + LoadConf(); + + // Adjust window position? + + // We held off setting the name until now... so description would show. + SetDlgItemText(mainboxwindow, IDC_0202, conf.isoname); + if(conf.startconfigure == 0) { + Button_SetCheck(GetDlgItem(mainboxwindow, IDC_0209), BST_UNCHECKED); + } else { + Button_SetCheck(GetDlgItem(mainboxwindow, IDC_0209), BST_CHECKED); + } // ENDIF- Do we need to uncheck this box? + if(conf.restartconfigure == 0) { + Button_SetCheck(GetDlgItem(mainboxwindow, IDC_0210), BST_UNCHECKED); + } else { + Button_SetCheck(GetDlgItem(mainboxwindow, IDC_0210), BST_CHECKED); + } // ENDIF- Do we need to uncheck this box? + + // First Time - Show the window + ShowWindow(mainboxwindow, SW_SHOWNORMAL); +} // END MainBoxDisplay() + + +BOOL CALLBACK MainBoxCallback(HWND window, + UINT msg, + WPARAM param, + LPARAM param2) { + switch(msg) { + case WM_INITDIALOG: + mainboxwindow = window; + MainBoxDisplay(); // In this case, final touches to this window. + ProgressBoxDisplay(); // Create the Progress Box at this time. + return(FALSE); // And let Windows display this window. + break; + + case WM_CLOSE: // The "X" in the upper right corner was hit. + MainBoxCancelEvent(); + return(TRUE); + break; + + case WM_COMMAND: + // Do we wish to capture 'ENTER/RETURN' and/or 'ESC' here? + + switch(LOWORD(param)) { + case IDC_0202: // Filename Edit Box + MainBoxFileEvent(); // Describe the File's type... + return(FALSE); // Let Windows handle the actual 'edit' processing... + break; + + case IDC_0203: // "Browse" Button + MainBoxBrowseEvent(); + return(TRUE); + break; + + case IDC_0205: // "Ok" Button + MainBoxOKEvent(); + return(TRUE); + break; + + case IDC_0206: // "Get from Disc" Button + MainBoxDeviceEvent(); + return(TRUE); + break; + + case IDC_0207: // "Convert" Button + MainBoxConversionEvent(); + return(TRUE); + break; + + case IDC_0208: // "Cancel" Button + MainBoxCancelEvent(); + return(TRUE); + break; + } // ENDSWITCH param- Which object got the message? + } // ENDSWITCH msg- what message has been sent to this window? + + return(FALSE); // Not a recognized message? Tell Windows to handle it. +} // END MainBoxEventLoop() diff --git a/plugins/CDVDisoEFP/src/Win32/mainbox.h b/plugins/CDVDisoEFP/src/Win32/mainbox.h index 639c9c9730..f1431054b8 100644 --- a/plugins/CDVDisoEFP/src/Win32/mainbox.h +++ b/plugins/CDVDisoEFP/src/Win32/mainbox.h @@ -1,43 +1,86 @@ -/* mainbox.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef MAINBOX_H -#define MAINBOX_H - - -#include // HWND - - -extern const char fileselection[]; - -extern HWND mainboxwindow; -extern int mainboxstop; - - -extern void MainBoxRefocus(); -extern void MainBoxDisplay(); -extern BOOL CALLBACK MainBoxCallback(HWND window, - UINT msg, - WPARAM param, - LPARAM param2); - - -#endif /* MAINBOX_H */ +/* mainbox.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef MAINBOX_H + +#define MAINBOX_H + + + + + +#include // HWND + + + + + +extern const char fileselection[]; + + + +extern HWND mainboxwindow; + +extern int mainboxstop; + + + + + +extern void MainBoxRefocus(); + +extern void MainBoxDisplay(); + +extern BOOL CALLBACK MainBoxCallback(HWND window, + + UINT msg, + + WPARAM param, + + LPARAM param2); + + + + + +#endif /* MAINBOX_H */ + diff --git a/plugins/CDVDisoEFP/src/Win32/screens.h b/plugins/CDVDisoEFP/src/Win32/screens.h index 8824d9c247..0c909a77ac 100644 --- a/plugins/CDVDisoEFP/src/Win32/screens.h +++ b/plugins/CDVDisoEFP/src/Win32/screens.h @@ -1,37 +1,74 @@ -/* Weditres generated include file. Do NOT edit */ -#include -#define DLG_0100 100 -#define IDC_0104 104 -#define DLG_0200 200 -#define IDC_0202 202 -#define IDC_0203 203 -#define IDC_0204 204 -#define IDC_0205 205 -#define IDC_0206 206 -#define IDC_0207 207 -#define IDC_0208 208 -#define IDC_0209 209 -#define IDC_0210 210 -#define DLG_0300 300 -#define IDC_0302 302 -#define IDC_0303 303 -#define IDC_0305 305 -#define IDC_0306 306 -#define IDC_0307 307 -#define IDC_0309 309 -#define IDC_0311 311 -#define IDC_0312 312 -#define IDC_0313 313 -#define DLG_0400 400 -#define IDC_0402 402 -#define IDC_0403 403 -#define IDC_0404 404 -#define IDC_0406 406 -#define IDC_0408 408 -#define IDC_0409 409 -#define IDC_0410 410 -#define DLG_0500 500 -#define IDC_0501 501 -#define IDC_0502 502 -#define IDC_0503 503 -#define IDC_0504 504 +/* Weditres generated include file. Do NOT edit */ + +#include + +#define DLG_0100 100 + +#define IDC_0104 104 + +#define DLG_0200 200 + +#define IDC_0202 202 + +#define IDC_0203 203 + +#define IDC_0204 204 + +#define IDC_0205 205 + +#define IDC_0206 206 + +#define IDC_0207 207 + +#define IDC_0208 208 + +#define IDC_0209 209 + +#define IDC_0210 210 + +#define DLG_0300 300 + +#define IDC_0302 302 + +#define IDC_0303 303 + +#define IDC_0305 305 + +#define IDC_0306 306 + +#define IDC_0307 307 + +#define IDC_0309 309 + +#define IDC_0311 311 + +#define IDC_0312 312 + +#define IDC_0313 313 + +#define DLG_0400 400 + +#define IDC_0402 402 + +#define IDC_0403 403 + +#define IDC_0404 404 + +#define IDC_0406 406 + +#define IDC_0408 408 + +#define IDC_0409 409 + +#define IDC_0410 410 + +#define DLG_0500 500 + +#define IDC_0501 501 + +#define IDC_0502 502 + +#define IDC_0503 503 + +#define IDC_0504 504 + diff --git a/plugins/CDVDisoEFP/src/Win32/tablerebuild.c b/plugins/CDVDisoEFP/src/Win32/tablerebuild.c index 090767b89d..c0b60df868 100644 --- a/plugins/CDVDisoEFP/src/Win32/tablerebuild.c +++ b/plugins/CDVDisoEFP/src/Win32/tablerebuild.c @@ -1,187 +1,374 @@ -/* tablerebuild.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // NULL -#include // sprintf() -#include // malloc() - -#include "mainbox.h" -#include "progressbox.h" -#include "isofile.h" -#include "multifile.h" -#include "isocompress.h" // CompressClose() -#include "gzipv1.h" -#include "gzipv2.h" -#include "bzip2v2.h" -#include "bzip2v3.h" -#include "actualfile.h" // ACTUALHANDLENULL - - -void IsoTableRebuild(const char *filename) { - struct IsoFile *datafile; - struct IsoFile *tablefile; - int retval; - char tempblock[65536]; - int stop; - - struct TableData table; - - datafile = IsoFileOpenForRead(filename); - - // Note: This is the start of the "Multifile" process. It's commented - // out so at least we can rebuild 1 part of a multifile at a time. - // IsoNameStripExt(datafile); - // IsoNameStripMulti(datafile); - - // Prep tablefile to hold ONLY a table (no data) - tablefile = (struct IsoFile *) malloc(sizeof(struct IsoFile)); - if(tablefile == NULL) { - datafile = IsoFileClose(datafile); - return; - } // ENDIF- Failed to allocate? Abort. - - tablefile->sectorpos = 0; - tablefile->openforread = 0; - tablefile->filebytepos = 0; - tablefile->filebytesize = 0; - tablefile->filesectorpos = 0; - tablefile->filesectorsize = 0; - tablefile->handle = ACTUALHANDLENULL; - - tablefile->namepos = 0; - while((tablefile->namepos < 255) && - (*(filename + tablefile->namepos) != 0)) { - tablefile->name[tablefile->namepos] = *(filename + tablefile->namepos); - tablefile->namepos++; - } // ENDWHILE- Copying file name into tablefile - tablefile->name[tablefile->namepos] = 0; // And 0-terminate. - - tablefile->imageheader = datafile->imageheader; - tablefile->blocksize = datafile->blocksize; - tablefile->blockoffset = datafile->blockoffset; - tablefile->cdvdtype = 0; // Not important right now. - - tablefile->compress = datafile->compress; - tablefile->compresspos = datafile->compresspos; - tablefile->numsectors = datafile->numsectors; - tablefile->tabledata = NULL; - - switch(tablefile->compress) { - case 1: - retval = GZipV1OpenTableForWrite(tablefile); - break; - case 2: - retval = -1; - break; - case 3: - retval = GZipV2OpenTableForWrite(tablefile); - break; - case 4: - retval = BZip2V2OpenTableForWrite(tablefile); - break; - case 5: - retval = BZip2V3OpenTableForWrite(tablefile); - break; - default: - retval = -1; - break; - } // ENDSWITCH compress- Which table are we writing out? - if(retval < 0) { - datafile = IsoFileClose(datafile); - return; - } // ENDIF- Failed to open table file? Abort - - sprintf(tempblock, "Rebuilding table for %s", datafile->name); - ProgressBoxStart(tempblock, datafile->filebytesize); - - stop = 0; - mainboxstop = 0; - progressboxstop = 0; - while((stop == 0) && (datafile->filebytepos < datafile->filebytesize)) { - switch(datafile->compress) { - case 1: - retval = GZipV1Read(datafile, 0, tempblock); - break; - case 2: - retval = -1; - break; - case 3: - retval = GZipV2Read(datafile, 0, tempblock); - break; - case 4: - retval = BZip2V2Read(datafile, 0, tempblock); - break; - case 5: - retval = BZip2V3Read(datafile, 0, tempblock); - break; - default: - retval = -1; - break; - } // ENDSWITCH compress- Scanning for the next complete compressed block - - if(retval <= 0) { -#ifdef FUNCTION_WARNING_TABLEREBUILD - PrintLog("CDVDiso rebuild: failed to decompress - data corrupt"); -#endif /* FUNCTION_WARNING_TABLEREBUILD */ - stop = 1; - } else { - table.offset = datafile->filebytepos - retval; - table.size = retval; - switch(tablefile->compress) { - case 1: - retval = GZipV1WriteTable(tablefile, table); - break; - case 2: - retval = -1; - break; - case 3: - retval = GZipV2WriteTable(tablefile, table); - break; - case 4: - retval = BZip2V2WriteTable(tablefile, table); - break; - case 5: - retval = BZip2V3WriteTable(tablefile, table); - break; - default: - retval = -1; - break; - } // ENDSWITCH compress- Writing out the relavent table facts - if(retval < 0) stop = 1; - } // ENDIF- Do we have a valid record to write an entry for? - - ProgressBoxTick(datafile->filebytepos); - - if(mainboxstop != 0) stop = 2; - if(progressboxstop != 0) stop = 2; - } // ENDWHILE- Read in the data file and writing a table, 1 block at a time - - ProgressBoxStop(); - - CompressClose(tablefile); // Guarentee the table is flushed and closed. - if(stop != 0) { - ActualFileDelete(tablefile->tablename); - } // ENDIF- Aborted or trouble? Delete the table file - tablefile = IsoFileClose(tablefile); - datafile = IsoFileClose(datafile); - - return; -} // END IsoTableRebuild() +/* tablerebuild.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // sprintf() + +#include // malloc() + + + +#include "mainbox.h" + +#include "progressbox.h" + +#include "isofile.h" + +#include "multifile.h" + +#include "isocompress.h" // CompressClose() + +#include "gzipv1.h" + +#include "gzipv2.h" + +#include "bzip2v2.h" + +#include "bzip2v3.h" + +#include "actualfile.h" // ACTUALHANDLENULL + + + + + +void IsoTableRebuild(const char *filename) { + + struct IsoFile *datafile; + + struct IsoFile *tablefile; + + int retval; + + char tempblock[65536]; + + int stop; + + + + struct TableData table; + + + + datafile = IsoFileOpenForRead(filename); + + + + // Note: This is the start of the "Multifile" process. It's commented + + // out so at least we can rebuild 1 part of a multifile at a time. + + // IsoNameStripExt(datafile); + + // IsoNameStripMulti(datafile); + + + + // Prep tablefile to hold ONLY a table (no data) + + tablefile = (struct IsoFile *) malloc(sizeof(struct IsoFile)); + + if(tablefile == NULL) { + + datafile = IsoFileClose(datafile); + + return; + + } // ENDIF- Failed to allocate? Abort. + + + + tablefile->sectorpos = 0; + + tablefile->openforread = 0; + + tablefile->filebytepos = 0; + + tablefile->filebytesize = 0; + + tablefile->filesectorpos = 0; + + tablefile->filesectorsize = 0; + + tablefile->handle = ACTUALHANDLENULL; + + + + tablefile->namepos = 0; + + while((tablefile->namepos < 255) && + + (*(filename + tablefile->namepos) != 0)) { + + tablefile->name[tablefile->namepos] = *(filename + tablefile->namepos); + + tablefile->namepos++; + + } // ENDWHILE- Copying file name into tablefile + + tablefile->name[tablefile->namepos] = 0; // And 0-terminate. + + + + tablefile->imageheader = datafile->imageheader; + + tablefile->blocksize = datafile->blocksize; + + tablefile->blockoffset = datafile->blockoffset; + + tablefile->cdvdtype = 0; // Not important right now. + + + + tablefile->compress = datafile->compress; + + tablefile->compresspos = datafile->compresspos; + + tablefile->numsectors = datafile->numsectors; + + tablefile->tabledata = NULL; + + + + switch(tablefile->compress) { + + case 1: + + retval = GZipV1OpenTableForWrite(tablefile); + + break; + + case 2: + + retval = -1; + + break; + + case 3: + + retval = GZipV2OpenTableForWrite(tablefile); + + break; + + case 4: + + retval = BZip2V2OpenTableForWrite(tablefile); + + break; + + case 5: + + retval = BZip2V3OpenTableForWrite(tablefile); + + break; + + default: + + retval = -1; + + break; + + } // ENDSWITCH compress- Which table are we writing out? + + if(retval < 0) { + + datafile = IsoFileClose(datafile); + + return; + + } // ENDIF- Failed to open table file? Abort + + + + sprintf(tempblock, "Rebuilding table for %s", datafile->name); + + ProgressBoxStart(tempblock, datafile->filebytesize); + + + + stop = 0; + + mainboxstop = 0; + + progressboxstop = 0; + + while((stop == 0) && (datafile->filebytepos < datafile->filebytesize)) { + + switch(datafile->compress) { + + case 1: + + retval = GZipV1Read(datafile, 0, tempblock); + + break; + + case 2: + + retval = -1; + + break; + + case 3: + + retval = GZipV2Read(datafile, 0, tempblock); + + break; + + case 4: + + retval = BZip2V2Read(datafile, 0, tempblock); + + break; + + case 5: + + retval = BZip2V3Read(datafile, 0, tempblock); + + break; + + default: + + retval = -1; + + break; + + } // ENDSWITCH compress- Scanning for the next complete compressed block + + + + if(retval <= 0) { + +#ifdef FUNCTION_WARNING_TABLEREBUILD + + PrintLog("CDVDiso rebuild: failed to decompress - data corrupt"); + +#endif /* FUNCTION_WARNING_TABLEREBUILD */ + + stop = 1; + + } else { + + table.offset = datafile->filebytepos - retval; + + table.size = retval; + + switch(tablefile->compress) { + + case 1: + + retval = GZipV1WriteTable(tablefile, table); + + break; + + case 2: + + retval = -1; + + break; + + case 3: + + retval = GZipV2WriteTable(tablefile, table); + + break; + + case 4: + + retval = BZip2V2WriteTable(tablefile, table); + + break; + + case 5: + + retval = BZip2V3WriteTable(tablefile, table); + + break; + + default: + + retval = -1; + + break; + + } // ENDSWITCH compress- Writing out the relavent table facts + + if(retval < 0) stop = 1; + + } // ENDIF- Do we have a valid record to write an entry for? + + + + ProgressBoxTick(datafile->filebytepos); + + + + if(mainboxstop != 0) stop = 2; + + if(progressboxstop != 0) stop = 2; + + } // ENDWHILE- Read in the data file and writing a table, 1 block at a time + + + + ProgressBoxStop(); + + + + CompressClose(tablefile); // Guarentee the table is flushed and closed. + + if(stop != 0) { + + ActualFileDelete(tablefile->tablename); + + } // ENDIF- Aborted or trouble? Delete the table file + + tablefile = IsoFileClose(tablefile); + + datafile = IsoFileClose(datafile); + + + + return; + +} // END IsoTableRebuild() + diff --git a/plugins/CDVDisoEFP/src/Win32/tablerebuild.h b/plugins/CDVDisoEFP/src/Win32/tablerebuild.h index 731911d29a..bac5ff9578 100644 --- a/plugins/CDVDisoEFP/src/Win32/tablerebuild.h +++ b/plugins/CDVDisoEFP/src/Win32/tablerebuild.h @@ -1,32 +1,64 @@ -/* tablerebuild.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef TABLEREBUILD_H -#define TABLEREBUILD_H - - -// #define FUNCTION_WARNING_TABLEREBUILD - - -extern void IsoTableRebuild(const char *filename); - - -#endif /* TABLEREBUILD_H */ +/* tablerebuild.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef TABLEREBUILD_H + +#define TABLEREBUILD_H + + + + + +// #define FUNCTION_WARNING_TABLEREBUILD + + + + + +extern void IsoTableRebuild(const char *filename); + + + + + +#endif /* TABLEREBUILD_H */ + diff --git a/plugins/CDVDisoEFP/src/blockv2.c b/plugins/CDVDisoEFP/src/blockv2.c index 9d7453fb76..58fa5e28c0 100644 --- a/plugins/CDVDisoEFP/src/blockv2.c +++ b/plugins/CDVDisoEFP/src/blockv2.c @@ -1,612 +1,612 @@ -/* blockv2.c - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#include // NULL - -#include // malloc() - -#include // off64_t - - - -#include "zlib/zlib.h" - - - -#include "convert.h" - -#include "logfile.h" - -#include "isofile.h" // IsoFile - -#include "isocompress.h" // TableData, TableMap - -#include "actualfile.h" - -#include "blockv2.h" - - - - - -#ifdef _WIN32 - -#pragma pack(1) - -#endif /* _WIN32 */ - - - -struct BlockV2Header { - - char id[4]; - - unsigned int blocksize; - - unsigned int numblocks; - - unsigned int blockoffset; - -#ifdef _WIN32 - -}; - -#else - -} __attribute__ ((packed)); - -#endif /* _WIN32 */ - - - -#ifdef _WIN32 - -#pragma pack() - -#endif /* _WIN32 */ - - - - - -int BlockV2OpenTableForRead(struct IsoFile *isofile) { - - int i; - - int j; - - off64_t offset; - - int tableoffset; - - int retval; - - union TableMap tablemap; - - - -#ifdef VERBOSE_FUNCTION_BLOCKV2 - - PrintLog("CDVDiso BlockV2: OpenTableForRead()"); - -#endif /* VERBOSE_FUNCTION_BLOCKV2 */ - - - - // We pre-read the WHOLE offset table. - - isofile->tabledata = (char *) malloc(isofile->filesectorsize * sizeof(struct TableData)); - - if(isofile->tabledata == NULL) { - -#ifdef VERBOSE_WARNING_BLOCKV2 - - PrintLog("CDVDiso BlockV2: Couldn't allocate internal table!"); - -#endif /* VERBOSE_WARNING_BLOCKV2 */ - - return(-1); - - } // ENDIF- Could not get enough memory to hold table data - - - - offset = sizeof(struct BlockV2Header); - - tableoffset = 0; - - for(i = 0; i < isofile->filesectorsize; i++) { - - retval = BlockV2Seek(isofile, offset); - - if(retval != 0) { - -#ifdef VERBOSE_WARNING_BLOCKV2 - - PrintLog("CDVDiso BlockV2: Failed to find sector %i!", i); - -#endif /* VERBOSE_WARNING_BLOCKV2 */ - - return(-1); - - } // ENDIF- Trouble finding a lsn id? Fail. - - - - retval = ActualFileRead(isofile->handle, - - sizeof(int), - - (char *) &j); - - if(retval != sizeof(int)) { - -#ifdef VERBOSE_WARNING_BLOCKV2 - - PrintLog("CDVDiso BlockV2: Failed to read in sector %i!", i); - -#endif /* VERBOSE_WARNING_BLOCKV2 */ - - return(-1); - - } // ENDIF- Trouble reading in a lsn id? Table damaged... fail. - - - - tablemap.table.offset = ConvertEndianUInt(j); // Actually, a lsn. - - for(j = 0; j < sizeof(struct TableData); j++) - - *(isofile->tabledata + tableoffset + j) = tablemap.ch[j]; - - offset += isofile->blocksize + 4; - - tableoffset += sizeof(struct TableData); - - } // NEXT i- reading in the sizes, and making offset as I go. - - - - isofile->tablehandle = ACTUALHANDLENULL; - - - - return(0); - -} // END BlockV2OpenTableForRead() - - - - - -int BlockV2SeekTable(struct IsoFile *isofile, off64_t sector) { - - int i; - - int tableoffset; - - union TableMap tablemap; - - off64_t filesectorstart; - - - -#ifdef VERBOSE_FUNCTION_BLOCKV2 - - PrintLog("CDVDiso BlockV2: SeekTable(%lli)", sector); - -#endif /* VERBOSE_FUNCTION_BLOCKV2 */ - - - - if((isofile->filesectorpos >= 0) && - - (isofile->filesectorpos < isofile->filesectorsize)) { - - tableoffset = isofile->filesectorpos * sizeof(struct TableData); - - for(i = 0; i < sizeof(struct TableData); i++) - - tablemap.ch[i] = *(isofile->tabledata + tableoffset + i); - - if(sector == tablemap.table.offset) { - - return(0); - - } // ENDIF- Are we already pointing at the right sector? - - - - } else { - - isofile->filesectorpos = 0; - - tablemap.table.offset = -1; - - } // ENDIF- Is the file sector pointer within table limits? - - - - filesectorstart = isofile->filesectorpos; - - isofile->filesectorpos++; - - if(isofile->filesectorpos >= isofile->filesectorsize) - - isofile->filesectorpos = 0; - - while((isofile->filesectorpos != filesectorstart) && - - (tablemap.table.offset != sector)) { - - tableoffset = isofile->filesectorpos * sizeof(struct TableData); - - for(i = 0; i < sizeof(struct TableData); i++) - - tablemap.ch[i] = *(isofile->tabledata + tableoffset + i); - - - - if(tablemap.table.offset != sector) { - - isofile->filesectorpos++; - - if(isofile->filesectorpos >= isofile->filesectorsize) - - isofile->filesectorpos = 0; - - } // ENDIF- Still didn't find it? move to next sector. - - } // ENDWHILE- Scanning through whole sector list (starting at current pos) - - - - if(isofile->filesectorpos == filesectorstart) { - - return(-1); - - } // ENDIF- Did we loop through the whole file... and not find this sector? - - - - return(0); - -} // END BlockV2SeekTable() - - - - - -int BlockV2ReadTable(struct IsoFile *isofile, struct TableData *table) { - -#ifdef VERBOSE_FUNCTION_BLOCKV2 - - PrintLog("CDVDiso BlockV2: ReadTable()"); - -#endif /* VERBOSE_FUNCTION_BLOCKV2 */ - - - - table->offset = sizeof(int) + isofile->blocksize; - - table->offset *= isofile->filesectorpos; - - table->offset += sizeof(struct BlockV2Header) + 4; - - table->size = isofile->blocksize; - - isofile->filesectorpos++; - - return(0); - -} // END BlockV2ReadTable() - - - - - -int BlockV2OpenTableForWrite(struct IsoFile *isofile) { - - return(-1); - -} // END BlockV2OpenTableForWrite() - - - - - -int BlockV2WriteTable(struct IsoFile *isofile, struct TableData table) { - - return(-1); - -} // END BlockV2WriteTable() - - - - - -int BlockV2OpenForRead(struct IsoFile *isofile) { - - int retval; - - struct BlockV2Header header; - - - -#ifdef VERBOSE_FUNCTION_BLOCKV2 - - PrintLog("CDVDiso BlockV2: OpenForRead()"); - -#endif /* VERBOSE_FUNCTION_BLOCKV2 */ - - - - isofile->handle = ActualFileOpenForRead(isofile->name); - - if(isofile->handle == ACTUALHANDLENULL) { - - return(-1); - - } // ENDIF- Couldn't open data file? Fail. - - - - isofile->filebytesize = ActualFileSize(isofile->handle); - - isofile->filebytepos = 0; - - - - isofile->imageheader = 0; - - isofile->numsectors = 1; // Sectors per block - - - - retval = ActualFileRead(isofile->handle, - - sizeof(struct BlockV2Header), - - (char *) &header); - - if(retval != sizeof(struct BlockV2Header)) { - -#ifdef VERBOSE_WARNING_BLOCKV2 - - PrintLog("CDVDiso BlockV2: Couldn't read header!"); - -#endif /* VERBOSE_WARNING_BLOCKV2 */ - - ActualFileClose(isofile->handle); - - isofile->handle = ACTUALHANDLENULL; - - return(-1); - - } // ENDIF Could not read the first sector? Fail. - - isofile->filebytepos += retval; - - - - if((header.id[0] != 'B') || - - (header.id[1] != 'D') || - - (header.id[2] != 'V') || - - (header.id[3] != '2')) { - -#ifdef VERBOSE_WARNING_BLOCKV2 - - PrintLog("CDVDiso BlockV2: Not a block dump v2 header!"); - -#endif /* VERBOSE_WARNING_BLOCKV2 */ - - ActualFileClose(isofile->handle); - - isofile->handle = ACTUALHANDLENULL; - - return(-1); - - } // ENDIF- ID for this compression type doesn't match? - - - - isofile->blocksize = ConvertEndianUInt(header.blocksize); - - // isofile->filesectorsize = ConvertEndianUInt(header.numblocks); - - isofile->blockoffset = ConvertEndianUInt(header.blockoffset); - - isofile->filesectorsize = isofile->filebytesize; - - isofile->filesectorsize -= 16; - - isofile->filesectorsize /= (isofile->blocksize + sizeof(int)); - - isofile->filesectorpos = 0; - - return(0); - -} // END BlockV2OpenForRead() - - - - - -int BlockV2Seek(struct IsoFile *isofile, off64_t position) { - - int retval; - - - -#ifdef VERBOSE_FUNCTION_BLOCKV2 - - PrintLog("CDVDiso BlockV2: Seek(%lli)", position); - -#endif /* VERBOSE_FUNCTION_BLOCKV2 */ - - - - retval = ActualFileSeek(isofile->handle, position); - - if(retval < 0) { - -#ifdef VERBOSE_WARNING_BLOCKV2 - - PrintLog("CDVDiso BlockV2: Couldn't find the start of the block!"); - -#endif /* VERBOSE_WARNING_BLOCKV2 */ - - return(-1); - - } // ENDIF- Couldn't find the data entry? Fail. - - isofile->filebytepos = position; - - return(0); - - - - return(-1); // Fail. (Due to lack of ambition?) - -} // END BlockV2Seek() - - - - - -int BlockV2Read(struct IsoFile *isofile, int bytes, char *buffer) { - - int retval; - - - -#ifdef VERBOSE_FUNCTION_BLOCKV2 - - PrintLog("CDVDiso BlockV2: Read(%i)", bytes); - -#endif /* VERBOSE_FUNCTION_BLOCKV2 */ - - - - retval = ActualFileRead(isofile->handle, isofile->blocksize, buffer); - - if(retval > 0) isofile->filebytepos += retval; - - if(retval != isofile->blocksize) { - -#ifdef VERBOSE_WARNING_BLOCKV2 - - PrintLog("CDVDiso BlockV2: Cannot read bytes! Returned: (%i)", retval); - -#endif /* VERBOSE_WARNING_BLOCKV2 */ - - return(-1); - - } // ENDIF- Trouble reading compressed sector? Abort. - - - - return(isofile->blocksize); - -} // END BlockV2Read() - - - - - -int BlockV2OpenForWrite(struct IsoFile *isofile) { - - return(-1); - -} // END BlockV2OpenForWrite() - - - - - -int BlockV2Write(struct IsoFile *isofile, char *buffer) { - - return(-1); - -} // END BlockV2Write() - - - - - -void BlockV2Close(struct IsoFile *isofile) { - -#ifdef VERBOSE_FUNCTION_BLOCKV2 - - PrintLog("CDVDiso BlockV2: Close()"); - -#endif /* VERBOSE_FUNCTION_BLOCKV2 */ - - - - if(isofile->handle != ACTUALHANDLENULL) { - - ActualFileClose(isofile->handle); - - isofile->handle = ACTUALHANDLENULL; - - } // ENDIF- Is there a data file open? Close it. - - - - if(isofile->tabledata != NULL) { - - free(isofile->tabledata); - - isofile->tabledata = NULL; - - } // ENDIF- Do we have a read-in table to clear out? - - - - return; - -} // END BlockV2Close() - +/* blockv2.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // malloc() + +#include // off64_t + + + +#include "zlib/zlib.h" + + + +#include "convert.h" + +#include "logfile.h" + +#include "isofile.h" // IsoFile + +#include "isocompress.h" // TableData, TableMap + +#include "actualfile.h" + +#include "blockv2.h" + + + + + +#ifdef _WIN32 + +#pragma pack(1) + +#endif /* _WIN32 */ + + + +struct BlockV2Header { + + char id[4]; + + unsigned int blocksize; + + unsigned int numblocks; + + unsigned int blockoffset; + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +#ifdef _WIN32 + +#pragma pack() + +#endif /* _WIN32 */ + + + + + +int BlockV2OpenTableForRead(struct IsoFile *isofile) { + + int i; + + int j; + + off64_t offset; + + int tableoffset; + + int retval; + + union TableMap tablemap; + + + +#ifdef VERBOSE_FUNCTION_BLOCKV2 + + PrintLog("CDVDiso BlockV2: OpenTableForRead()"); + +#endif /* VERBOSE_FUNCTION_BLOCKV2 */ + + + + // We pre-read the WHOLE offset table. + + isofile->tabledata = (char *) malloc(isofile->filesectorsize * sizeof(struct TableData)); + + if(isofile->tabledata == NULL) { + +#ifdef VERBOSE_WARNING_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Couldn't allocate internal table!"); + +#endif /* VERBOSE_WARNING_BLOCKV2 */ + + return(-1); + + } // ENDIF- Could not get enough memory to hold table data + + + + offset = sizeof(struct BlockV2Header); + + tableoffset = 0; + + for(i = 0; i < isofile->filesectorsize; i++) { + + retval = BlockV2Seek(isofile, offset); + + if(retval != 0) { + +#ifdef VERBOSE_WARNING_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Failed to find sector %i!", i); + +#endif /* VERBOSE_WARNING_BLOCKV2 */ + + return(-1); + + } // ENDIF- Trouble finding a lsn id? Fail. + + + + retval = ActualFileRead(isofile->handle, + + sizeof(int), + + (char *) &j); + + if(retval != sizeof(int)) { + +#ifdef VERBOSE_WARNING_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Failed to read in sector %i!", i); + +#endif /* VERBOSE_WARNING_BLOCKV2 */ + + return(-1); + + } // ENDIF- Trouble reading in a lsn id? Table damaged... fail. + + + + tablemap.table.offset = ConvertEndianUInt(j); // Actually, a lsn. + + for(j = 0; j < sizeof(struct TableData); j++) + + *(isofile->tabledata + tableoffset + j) = tablemap.ch[j]; + + offset += isofile->blocksize + 4; + + tableoffset += sizeof(struct TableData); + + } // NEXT i- reading in the sizes, and making offset as I go. + + + + isofile->tablehandle = ACTUALHANDLENULL; + + + + return(0); + +} // END BlockV2OpenTableForRead() + + + + + +int BlockV2SeekTable(struct IsoFile *isofile, off64_t sector) { + + int i; + + int tableoffset; + + union TableMap tablemap; + + off64_t filesectorstart; + + + +#ifdef VERBOSE_FUNCTION_BLOCKV2 + + PrintLog("CDVDiso BlockV2: SeekTable(%lli)", sector); + +#endif /* VERBOSE_FUNCTION_BLOCKV2 */ + + + + if((isofile->filesectorpos >= 0) && + + (isofile->filesectorpos < isofile->filesectorsize)) { + + tableoffset = isofile->filesectorpos * sizeof(struct TableData); + + for(i = 0; i < sizeof(struct TableData); i++) + + tablemap.ch[i] = *(isofile->tabledata + tableoffset + i); + + if(sector == tablemap.table.offset) { + + return(0); + + } // ENDIF- Are we already pointing at the right sector? + + + + } else { + + isofile->filesectorpos = 0; + + tablemap.table.offset = -1; + + } // ENDIF- Is the file sector pointer within table limits? + + + + filesectorstart = isofile->filesectorpos; + + isofile->filesectorpos++; + + if(isofile->filesectorpos >= isofile->filesectorsize) + + isofile->filesectorpos = 0; + + while((isofile->filesectorpos != filesectorstart) && + + (tablemap.table.offset != sector)) { + + tableoffset = isofile->filesectorpos * sizeof(struct TableData); + + for(i = 0; i < sizeof(struct TableData); i++) + + tablemap.ch[i] = *(isofile->tabledata + tableoffset + i); + + + + if(tablemap.table.offset != sector) { + + isofile->filesectorpos++; + + if(isofile->filesectorpos >= isofile->filesectorsize) + + isofile->filesectorpos = 0; + + } // ENDIF- Still didn't find it? move to next sector. + + } // ENDWHILE- Scanning through whole sector list (starting at current pos) + + + + if(isofile->filesectorpos == filesectorstart) { + + return(-1); + + } // ENDIF- Did we loop through the whole file... and not find this sector? + + + + return(0); + +} // END BlockV2SeekTable() + + + + + +int BlockV2ReadTable(struct IsoFile *isofile, struct TableData *table) { + +#ifdef VERBOSE_FUNCTION_BLOCKV2 + + PrintLog("CDVDiso BlockV2: ReadTable()"); + +#endif /* VERBOSE_FUNCTION_BLOCKV2 */ + + + + table->offset = sizeof(int) + isofile->blocksize; + + table->offset *= isofile->filesectorpos; + + table->offset += sizeof(struct BlockV2Header) + 4; + + table->size = isofile->blocksize; + + isofile->filesectorpos++; + + return(0); + +} // END BlockV2ReadTable() + + + + + +int BlockV2OpenTableForWrite(struct IsoFile *isofile) { + + return(-1); + +} // END BlockV2OpenTableForWrite() + + + + + +int BlockV2WriteTable(struct IsoFile *isofile, struct TableData table) { + + return(-1); + +} // END BlockV2WriteTable() + + + + + +int BlockV2OpenForRead(struct IsoFile *isofile) { + + int retval; + + struct BlockV2Header header; + + + +#ifdef VERBOSE_FUNCTION_BLOCKV2 + + PrintLog("CDVDiso BlockV2: OpenForRead()"); + +#endif /* VERBOSE_FUNCTION_BLOCKV2 */ + + + + isofile->handle = ActualFileOpenForRead(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + return(-1); + + } // ENDIF- Couldn't open data file? Fail. + + + + isofile->filebytesize = ActualFileSize(isofile->handle); + + isofile->filebytepos = 0; + + + + isofile->imageheader = 0; + + isofile->numsectors = 1; // Sectors per block + + + + retval = ActualFileRead(isofile->handle, + + sizeof(struct BlockV2Header), + + (char *) &header); + + if(retval != sizeof(struct BlockV2Header)) { + +#ifdef VERBOSE_WARNING_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Couldn't read header!"); + +#endif /* VERBOSE_WARNING_BLOCKV2 */ + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF Could not read the first sector? Fail. + + isofile->filebytepos += retval; + + + + if((header.id[0] != 'B') || + + (header.id[1] != 'D') || + + (header.id[2] != 'V') || + + (header.id[3] != '2')) { + +#ifdef VERBOSE_WARNING_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Not a block dump v2 header!"); + +#endif /* VERBOSE_WARNING_BLOCKV2 */ + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- ID for this compression type doesn't match? + + + + isofile->blocksize = ConvertEndianUInt(header.blocksize); + + // isofile->filesectorsize = ConvertEndianUInt(header.numblocks); + + isofile->blockoffset = ConvertEndianUInt(header.blockoffset); + + isofile->filesectorsize = isofile->filebytesize; + + isofile->filesectorsize -= 16; + + isofile->filesectorsize /= (isofile->blocksize + sizeof(int)); + + isofile->filesectorpos = 0; + + return(0); + +} // END BlockV2OpenForRead() + + + + + +int BlockV2Seek(struct IsoFile *isofile, off64_t position) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Seek(%lli)", position); + +#endif /* VERBOSE_FUNCTION_BLOCKV2 */ + + + + retval = ActualFileSeek(isofile->handle, position); + + if(retval < 0) { + +#ifdef VERBOSE_WARNING_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Couldn't find the start of the block!"); + +#endif /* VERBOSE_WARNING_BLOCKV2 */ + + return(-1); + + } // ENDIF- Couldn't find the data entry? Fail. + + isofile->filebytepos = position; + + return(0); + + + + return(-1); // Fail. (Due to lack of ambition?) + +} // END BlockV2Seek() + + + + + +int BlockV2Read(struct IsoFile *isofile, int bytes, char *buffer) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Read(%i)", bytes); + +#endif /* VERBOSE_FUNCTION_BLOCKV2 */ + + + + retval = ActualFileRead(isofile->handle, isofile->blocksize, buffer); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval != isofile->blocksize) { + +#ifdef VERBOSE_WARNING_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Cannot read bytes! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_BLOCKV2 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + + + return(isofile->blocksize); + +} // END BlockV2Read() + + + + + +int BlockV2OpenForWrite(struct IsoFile *isofile) { + + return(-1); + +} // END BlockV2OpenForWrite() + + + + + +int BlockV2Write(struct IsoFile *isofile, char *buffer) { + + return(-1); + +} // END BlockV2Write() + + + + + +void BlockV2Close(struct IsoFile *isofile) { + +#ifdef VERBOSE_FUNCTION_BLOCKV2 + + PrintLog("CDVDiso BlockV2: Close()"); + +#endif /* VERBOSE_FUNCTION_BLOCKV2 */ + + + + if(isofile->handle != ACTUALHANDLENULL) { + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + } // ENDIF- Is there a data file open? Close it. + + + + if(isofile->tabledata != NULL) { + + free(isofile->tabledata); + + isofile->tabledata = NULL; + + } // ENDIF- Do we have a read-in table to clear out? + + + + return; + +} // END BlockV2Close() + diff --git a/plugins/CDVDisoEFP/src/blockv2.h b/plugins/CDVDisoEFP/src/blockv2.h index 500e99c0e6..8ef1740d70 100644 --- a/plugins/CDVDisoEFP/src/blockv2.h +++ b/plugins/CDVDisoEFP/src/blockv2.h @@ -1,104 +1,104 @@ -/* blockv2.h - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#ifndef BLOCKV2_H - -#define BLOCKV2_H - - - - - -#include - - - -#include "isofile.h" - -#include "isocompress.h" - - - - - -// #define VERBOSE_FUNCTION_BLOCKV2 - -// #define VERBOSE_WARNING_BLOCKV2 - - - - - -extern int BlockV2OpenTableForRead(struct IsoFile *isofile); - -extern int BlockV2SeekTable(struct IsoFile *isofile, off64_t sector); - -extern int BlockV2ReadTable(struct IsoFile *isofile, struct TableData *table); - - - -extern int BlockV2OpenTableForWrite(struct IsoFile *isofile); - -extern int BlockV2WriteTable(struct IsoFile *isofile, struct TableData table); - - - -extern int BlockV2OpenForRead(struct IsoFile *isofile); - -extern int BlockV2Seek(struct IsoFile *isofile, off64_t sector); - -extern int BlockV2Read(struct IsoFile *isofile, int bytes, char *buffer); - -extern void BlockV2Close(struct IsoFile *isofile); - - - -extern int BlockV2OpenForWrite(struct IsoFile *isofile); - -extern int BlockV2Write(struct IsoFile *isofile, char *buffer); - - - - - -#endif /* BLOCKV2_H */ - +/* blockv2.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef BLOCKV2_H + +#define BLOCKV2_H + + + + + +#include + + + +#include "isofile.h" + +#include "isocompress.h" + + + + + +// #define VERBOSE_FUNCTION_BLOCKV2 + +// #define VERBOSE_WARNING_BLOCKV2 + + + + + +extern int BlockV2OpenTableForRead(struct IsoFile *isofile); + +extern int BlockV2SeekTable(struct IsoFile *isofile, off64_t sector); + +extern int BlockV2ReadTable(struct IsoFile *isofile, struct TableData *table); + + + +extern int BlockV2OpenTableForWrite(struct IsoFile *isofile); + +extern int BlockV2WriteTable(struct IsoFile *isofile, struct TableData table); + + + +extern int BlockV2OpenForRead(struct IsoFile *isofile); + +extern int BlockV2Seek(struct IsoFile *isofile, off64_t sector); + +extern int BlockV2Read(struct IsoFile *isofile, int bytes, char *buffer); + +extern void BlockV2Close(struct IsoFile *isofile); + + + +extern int BlockV2OpenForWrite(struct IsoFile *isofile); + +extern int BlockV2Write(struct IsoFile *isofile, char *buffer); + + + + + +#endif /* BLOCKV2_H */ + diff --git a/plugins/CDVDisoEFP/src/bzip2/blocksort.c b/plugins/CDVDisoEFP/src/bzip2/blocksort.c index 02554cc472..33ec9f5dcb 100644 --- a/plugins/CDVDisoEFP/src/bzip2/blocksort.c +++ b/plugins/CDVDisoEFP/src/bzip2/blocksort.c @@ -1,1141 +1,1141 @@ - -/*-------------------------------------------------------------*/ -/*--- Block sorting machinery ---*/ -/*--- blocksort.c ---*/ -/*-------------------------------------------------------------*/ - -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. - - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. - - To get some idea how the block sorting algorithms in this file - work, read my paper - On the Performance of BWT Sorting Algorithms - in Proceedings of the IEEE Data Compression Conference 2000, - Snowbird, Utah, USA, 27-30 March 2000. The main sort in this - file implements the algorithm called cache in the paper. ---*/ - - -#include "bzlib_private.h" - -/*---------------------------------------------*/ -/*--- Fallback O(N log(N)^2) sorting ---*/ -/*--- algorithm, for repetitive blocks ---*/ -/*---------------------------------------------*/ - -/*---------------------------------------------*/ -static -__inline__ -void fallbackSimpleSort ( UInt32* fmap, - UInt32* eclass, - Int32 lo, - Int32 hi ) -{ - Int32 i, j, tmp; - UInt32 ec_tmp; - - if (lo == hi) return; - - if (hi - lo > 3) { - for ( i = hi-4; i >= lo; i-- ) { - tmp = fmap[i]; - ec_tmp = eclass[tmp]; - for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 ) - fmap[j-4] = fmap[j]; - fmap[j-4] = tmp; - } - } - - for ( i = hi-1; i >= lo; i-- ) { - tmp = fmap[i]; - ec_tmp = eclass[tmp]; - for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ ) - fmap[j-1] = fmap[j]; - fmap[j-1] = tmp; - } -} - - -/*---------------------------------------------*/ -#define fswap(zz1, zz2) \ - { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } - -#define fvswap(zzp1, zzp2, zzn) \ -{ \ - Int32 yyp1 = (zzp1); \ - Int32 yyp2 = (zzp2); \ - Int32 yyn = (zzn); \ - while (yyn > 0) { \ - fswap(fmap[yyp1], fmap[yyp2]); \ - yyp1++; yyp2++; yyn--; \ - } \ -} - - -#define fmin(a,b) ((a) < (b)) ? (a) : (b) - -#define fpush(lz,hz) { stackLo[sp] = lz; \ - stackHi[sp] = hz; \ - sp++; } - -#define fpop(lz,hz) { sp--; \ - lz = stackLo[sp]; \ - hz = stackHi[sp]; } - -#define FALLBACK_QSORT_SMALL_THRESH 10 -#define FALLBACK_QSORT_STACK_SIZE 100 - - -static -void fallbackQSort3 ( UInt32* fmap, - UInt32* eclass, - Int32 loSt, - Int32 hiSt ) -{ - Int32 unLo, unHi, ltLo, gtHi, n, m; - Int32 sp, lo, hi; - UInt32 med, r, r3; - Int32 stackLo[FALLBACK_QSORT_STACK_SIZE]; - Int32 stackHi[FALLBACK_QSORT_STACK_SIZE]; - - r = 0; - - sp = 0; - fpush ( loSt, hiSt ); - - while (sp > 0) { - - AssertH ( sp < FALLBACK_QSORT_STACK_SIZE, 1004 ); - - fpop ( lo, hi ); - if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { - fallbackSimpleSort ( fmap, eclass, lo, hi ); - continue; - } - - /* Random partitioning. Median of 3 sometimes fails to - avoid bad cases. Median of 9 seems to help but - looks rather expensive. This too seems to work but - is cheaper. Guidance for the magic constants - 7621 and 32768 is taken from Sedgewick's algorithms - book, chapter 35. - */ - r = ((r * 7621) + 1) % 32768; - r3 = r % 3; - if (r3 == 0) med = eclass[fmap[lo]]; else - if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else - med = eclass[fmap[hi]]; - - unLo = ltLo = lo; - unHi = gtHi = hi; - - while (1) { - while (1) { - if (unLo > unHi) break; - n = (Int32)eclass[fmap[unLo]] - (Int32)med; - if (n == 0) { - fswap(fmap[unLo], fmap[ltLo]); - ltLo++; unLo++; - continue; - }; - if (n > 0) break; - unLo++; - } - while (1) { - if (unLo > unHi) break; - n = (Int32)eclass[fmap[unHi]] - (Int32)med; - if (n == 0) { - fswap(fmap[unHi], fmap[gtHi]); - gtHi--; unHi--; - continue; - }; - if (n < 0) break; - unHi--; - } - if (unLo > unHi) break; - fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; - } - - AssertD ( unHi == unLo-1, "fallbackQSort3(2)" ); - - if (gtHi < ltLo) continue; - - n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n); - m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m); - - n = lo + unLo - ltLo - 1; - m = hi - (gtHi - unHi) + 1; - - if (n - lo > hi - m) { - fpush ( lo, n ); - fpush ( m, hi ); - } else { - fpush ( m, hi ); - fpush ( lo, n ); - } - } -} - -#undef fmin -#undef fpush -#undef fpop -#undef fswap -#undef fvswap -#undef FALLBACK_QSORT_SMALL_THRESH -#undef FALLBACK_QSORT_STACK_SIZE - - -/*---------------------------------------------*/ -/* Pre: - nblock > 0 - eclass exists for [0 .. nblock-1] - ((UChar*)eclass) [0 .. nblock-1] holds block - ptr exists for [0 .. nblock-1] - - Post: - ((UChar*)eclass) [0 .. nblock-1] holds block - All other areas of eclass destroyed - fmap [0 .. nblock-1] holds sorted order - bhtab [ 0 .. 2+(nblock/32) ] destroyed -*/ - -#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) -#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) -#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) -#define WORD_BH(zz) bhtab[(zz) >> 5] -#define UNALIGNED_BH(zz) ((zz) & 0x01f) - -static -void fallbackSort ( UInt32* fmap, - UInt32* eclass, - UInt32* bhtab, - Int32 nblock, - Int32 verb ) -{ - Int32 ftab[257]; - Int32 ftabCopy[256]; - Int32 H, i, j, k, l, r, cc, cc1; - Int32 nNotDone; - Int32 nBhtab; - UChar* eclass8 = (UChar*)eclass; - - /*-- - Initial 1-char radix sort to generate - initial fmap and initial BH bits. - --*/ - if (verb >= 4) - VPrintf0 ( " bucket sorting ...\n" ); - for (i = 0; i < 257; i++) ftab[i] = 0; - for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; - for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; - for (i = 1; i < 257; i++) ftab[i] += ftab[i-1]; - - for (i = 0; i < nblock; i++) { - j = eclass8[i]; - k = ftab[j] - 1; - ftab[j] = k; - fmap[k] = i; - } - - nBhtab = 2 + (nblock / 32); - for (i = 0; i < nBhtab; i++) bhtab[i] = 0; - for (i = 0; i < 256; i++) SET_BH(ftab[i]); - - /*-- - Inductively refine the buckets. Kind-of an - "exponential radix sort" (!), inspired by the - Manber-Myers suffix array construction algorithm. - --*/ - - /*-- set sentinel bits for block-end detection --*/ - for (i = 0; i < 32; i++) { - SET_BH(nblock + 2*i); - CLEAR_BH(nblock + 2*i + 1); - } - - /*-- the log(N) loop --*/ - H = 1; - while (1) { - - if (verb >= 4) - VPrintf1 ( " depth %6d has ", H ); - - j = 0; - for (i = 0; i < nblock; i++) { - if (ISSET_BH(i)) j = i; - k = fmap[i] - H; if (k < 0) k += nblock; - eclass[k] = j; - } - - nNotDone = 0; - r = -1; - while (1) { - - /*-- find the next non-singleton bucket --*/ - k = r + 1; - while (ISSET_BH(k) && UNALIGNED_BH(k)) k++; - if (ISSET_BH(k)) { - while (WORD_BH(k) == 0xffffffff) k += 32; - while (ISSET_BH(k)) k++; - } - l = k - 1; - if (l >= nblock) break; - while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++; - if (!ISSET_BH(k)) { - while (WORD_BH(k) == 0x00000000) k += 32; - while (!ISSET_BH(k)) k++; - } - r = k - 1; - if (r >= nblock) break; - - /*-- now [l, r] bracket current bucket --*/ - if (r > l) { - nNotDone += (r - l + 1); - fallbackQSort3 ( fmap, eclass, l, r ); - - /*-- scan bucket and generate header bits-- */ - cc = -1; - for (i = l; i <= r; i++) { - cc1 = eclass[fmap[i]]; - if (cc != cc1) { SET_BH(i); cc = cc1; }; - } - } - } - - if (verb >= 4) - VPrintf1 ( "%6d unresolved strings\n", nNotDone ); - - H *= 2; - if (H > nblock || nNotDone == 0) break; - } - - /*-- - Reconstruct the original block in - eclass8 [0 .. nblock-1], since the - previous phase destroyed it. - --*/ - if (verb >= 4) - VPrintf0 ( " reconstructing block ...\n" ); - j = 0; - for (i = 0; i < nblock; i++) { - while (ftabCopy[j] == 0) j++; - ftabCopy[j]--; - eclass8[fmap[i]] = (UChar)j; - } - AssertH ( j < 256, 1005 ); -} - -#undef SET_BH -#undef CLEAR_BH -#undef ISSET_BH -#undef WORD_BH -#undef UNALIGNED_BH - - -/*---------------------------------------------*/ -/*--- The main, O(N^2 log(N)) sorting ---*/ -/*--- algorithm. Faster for "normal" ---*/ -/*--- non-repetitive blocks. ---*/ -/*---------------------------------------------*/ - -/*---------------------------------------------*/ -static -__inline__ -Bool mainGtU ( UInt32 i1, - UInt32 i2, - UChar* block, - UInt16* quadrant, - UInt32 nblock, - Int32* budget ) -{ - Int32 k; - UChar c1, c2; - UInt16 s1, s2; - - AssertD ( i1 != i2, "mainGtU" ); - /* 1 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 2 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 3 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 4 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 5 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 6 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 7 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 8 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 9 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 10 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 11 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 12 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - - k = nblock + 8; - - do { - /* 1 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 2 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 3 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 4 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 5 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 6 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 7 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 8 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - - if (i1 >= nblock) i1 -= nblock; - if (i2 >= nblock) i2 -= nblock; - - k -= 8; - (*budget)--; - } - while (k >= 0); - - return False; -} - - -/*---------------------------------------------*/ -/*-- - Knuth's increments seem to work better - than Incerpi-Sedgewick here. Possibly - because the number of elems to sort is - usually small, typically <= 20. ---*/ -static -Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, - 9841, 29524, 88573, 265720, - 797161, 2391484 }; - -static -void mainSimpleSort ( UInt32* ptr, - UChar* block, - UInt16* quadrant, - Int32 nblock, - Int32 lo, - Int32 hi, - Int32 d, - Int32* budget ) -{ - Int32 i, j, h, bigN, hp; - UInt32 v; - - bigN = hi - lo + 1; - if (bigN < 2) return; - - hp = 0; - while (incs[hp] < bigN) hp++; - hp--; - - for (; hp >= 0; hp--) { - h = incs[hp]; - - i = lo + h; - while (True) { - - /*-- copy 1 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while ( mainGtU ( - ptr[j-h]+d, v+d, block, quadrant, nblock, budget - ) ) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - - /*-- copy 2 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while ( mainGtU ( - ptr[j-h]+d, v+d, block, quadrant, nblock, budget - ) ) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - - /*-- copy 3 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while ( mainGtU ( - ptr[j-h]+d, v+d, block, quadrant, nblock, budget - ) ) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - - if (*budget < 0) return; - } - } -} - - -/*---------------------------------------------*/ -/*-- - The following is an implementation of - an elegant 3-way quicksort for strings, - described in a paper "Fast Algorithms for - Sorting and Searching Strings", by Robert - Sedgewick and Jon L. Bentley. ---*/ - -#define mswap(zz1, zz2) \ - { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } - -#define mvswap(zzp1, zzp2, zzn) \ -{ \ - Int32 yyp1 = (zzp1); \ - Int32 yyp2 = (zzp2); \ - Int32 yyn = (zzn); \ - while (yyn > 0) { \ - mswap(ptr[yyp1], ptr[yyp2]); \ - yyp1++; yyp2++; yyn--; \ - } \ -} - -static -__inline__ -UChar mmed3 ( UChar a, UChar b, UChar c ) -{ - UChar t; - if (a > b) { t = a; a = b; b = t; }; - if (b > c) { - b = c; - if (a > b) b = a; - } - return b; -} - -#define mmin(a,b) ((a) < (b)) ? (a) : (b) - -#define mpush(lz,hz,dz) { stackLo[sp] = lz; \ - stackHi[sp] = hz; \ - stackD [sp] = dz; \ - sp++; } - -#define mpop(lz,hz,dz) { sp--; \ - lz = stackLo[sp]; \ - hz = stackHi[sp]; \ - dz = stackD [sp]; } - - -#define mnextsize(az) (nextHi[az]-nextLo[az]) - -#define mnextswap(az,bz) \ - { Int32 tz; \ - tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ - tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ - tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; } - - -#define MAIN_QSORT_SMALL_THRESH 20 -#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) -#define MAIN_QSORT_STACK_SIZE 100 - -static -void mainQSort3 ( UInt32* ptr, - UChar* block, - UInt16* quadrant, - Int32 nblock, - Int32 loSt, - Int32 hiSt, - Int32 dSt, - Int32* budget ) -{ - Int32 unLo, unHi, ltLo, gtHi, n, m, med; - Int32 sp, lo, hi, d; - - Int32 stackLo[MAIN_QSORT_STACK_SIZE]; - Int32 stackHi[MAIN_QSORT_STACK_SIZE]; - Int32 stackD [MAIN_QSORT_STACK_SIZE]; - - Int32 nextLo[3]; - Int32 nextHi[3]; - Int32 nextD [3]; - - sp = 0; - mpush ( loSt, hiSt, dSt ); - - while (sp > 0) { - - AssertH ( sp < MAIN_QSORT_STACK_SIZE, 1001 ); - - mpop ( lo, hi, d ); - if (hi - lo < MAIN_QSORT_SMALL_THRESH || - d > MAIN_QSORT_DEPTH_THRESH) { - mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget ); - if (*budget < 0) return; - continue; - } - - med = (Int32) - mmed3 ( block[ptr[ lo ]+d], - block[ptr[ hi ]+d], - block[ptr[ (lo+hi)>>1 ]+d] ); - - unLo = ltLo = lo; - unHi = gtHi = hi; - - while (True) { - while (True) { - if (unLo > unHi) break; - n = ((Int32)block[ptr[unLo]+d]) - med; - if (n == 0) { - mswap(ptr[unLo], ptr[ltLo]); - ltLo++; unLo++; continue; - }; - if (n > 0) break; - unLo++; - } - while (True) { - if (unLo > unHi) break; - n = ((Int32)block[ptr[unHi]+d]) - med; - if (n == 0) { - mswap(ptr[unHi], ptr[gtHi]); - gtHi--; unHi--; continue; - }; - if (n < 0) break; - unHi--; - } - if (unLo > unHi) break; - mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--; - } - - AssertD ( unHi == unLo-1, "mainQSort3(2)" ); - - if (gtHi < ltLo) { - mpush(lo, hi, d+1 ); - continue; - } - - n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n); - m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m); - - n = lo + unLo - ltLo - 1; - m = hi - (gtHi - unHi) + 1; - - nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; - nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; - nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; - - if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); - if (mnextsize(1) < mnextsize(2)) mnextswap(1,2); - if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); - - AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" ); - AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" ); - - mpush (nextLo[0], nextHi[0], nextD[0]); - mpush (nextLo[1], nextHi[1], nextD[1]); - mpush (nextLo[2], nextHi[2], nextD[2]); - } -} - -#undef mswap -#undef mvswap -#undef mpush -#undef mpop -#undef mmin -#undef mnextsize -#undef mnextswap -#undef MAIN_QSORT_SMALL_THRESH -#undef MAIN_QSORT_DEPTH_THRESH -#undef MAIN_QSORT_STACK_SIZE - - -/*---------------------------------------------*/ -/* Pre: - nblock > N_OVERSHOOT - block32 exists for [0 .. nblock-1 +N_OVERSHOOT] - ((UChar*)block32) [0 .. nblock-1] holds block - ptr exists for [0 .. nblock-1] - - Post: - ((UChar*)block32) [0 .. nblock-1] holds block - All other areas of block32 destroyed - ftab [0 .. 65536 ] destroyed - ptr [0 .. nblock-1] holds sorted order - if (*budget < 0), sorting was abandoned -*/ - -#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) -#define SETMASK (1 << 21) -#define CLEARMASK (~(SETMASK)) - -static -void mainSort ( UInt32* ptr, - UChar* block, - UInt16* quadrant, - UInt32* ftab, - Int32 nblock, - Int32 verb, - Int32* budget ) -{ - Int32 i, j, k, ss, sb; - Int32 runningOrder[256]; - Bool bigDone[256]; - Int32 copyStart[256]; - Int32 copyEnd [256]; - UChar c1; - Int32 numQSorted; - UInt16 s; - if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" ); - - /*-- set up the 2-byte frequency table --*/ - for (i = 65536; i >= 0; i--) ftab[i] = 0; - - j = block[0] << 8; - i = nblock-1; - for (; i >= 3; i -= 4) { - quadrant[i] = 0; - j = (j >> 8) | ( ((UInt16)block[i]) << 8); - ftab[j]++; - quadrant[i-1] = 0; - j = (j >> 8) | ( ((UInt16)block[i-1]) << 8); - ftab[j]++; - quadrant[i-2] = 0; - j = (j >> 8) | ( ((UInt16)block[i-2]) << 8); - ftab[j]++; - quadrant[i-3] = 0; - j = (j >> 8) | ( ((UInt16)block[i-3]) << 8); - ftab[j]++; - } - for (; i >= 0; i--) { - quadrant[i] = 0; - j = (j >> 8) | ( ((UInt16)block[i]) << 8); - ftab[j]++; - } - - /*-- (emphasises close relationship of block & quadrant) --*/ - for (i = 0; i < BZ_N_OVERSHOOT; i++) { - block [nblock+i] = block[i]; - quadrant[nblock+i] = 0; - } - - if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" ); - - /*-- Complete the initial radix sort --*/ - for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1]; - - s = block[0] << 8; - i = nblock-1; - for (; i >= 3; i -= 4) { - s = (s >> 8) | (block[i] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i; - s = (s >> 8) | (block[i-1] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i-1; - s = (s >> 8) | (block[i-2] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i-2; - s = (s >> 8) | (block[i-3] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i-3; - } - for (; i >= 0; i--) { - s = (s >> 8) | (block[i] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i; - } - - /*-- - Now ftab contains the first loc of every small bucket. - Calculate the running order, from smallest to largest - big bucket. - --*/ - for (i = 0; i <= 255; i++) { - bigDone [i] = False; - runningOrder[i] = i; - } - - { - Int32 vv; - Int32 h = 1; - do h = 3 * h + 1; while (h <= 256); - do { - h = h / 3; - for (i = h; i <= 255; i++) { - vv = runningOrder[i]; - j = i; - while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) { - runningOrder[j] = runningOrder[j-h]; - j = j - h; - if (j <= (h - 1)) goto zero; - } - zero: - runningOrder[j] = vv; - } - } while (h != 1); - } - - /*-- - The main sorting loop. - --*/ - - numQSorted = 0; - - for (i = 0; i <= 255; i++) { - - /*-- - Process big buckets, starting with the least full. - Basically this is a 3-step process in which we call - mainQSort3 to sort the small buckets [ss, j], but - also make a big effort to avoid the calls if we can. - --*/ - ss = runningOrder[i]; - - /*-- - Step 1: - Complete the big bucket [ss] by quicksorting - any unsorted small buckets [ss, j], for j != ss. - Hopefully previous pointer-scanning phases have already - completed many of the small buckets [ss, j], so - we don't have to sort them at all. - --*/ - for (j = 0; j <= 255; j++) { - if (j != ss) { - sb = (ss << 8) + j; - if ( ! (ftab[sb] & SETMASK) ) { - Int32 lo = ftab[sb] & CLEARMASK; - Int32 hi = (ftab[sb+1] & CLEARMASK) - 1; - if (hi > lo) { - if (verb >= 4) - VPrintf4 ( " qsort [0x%x, 0x%x] " - "done %d this %d\n", - ss, j, numQSorted, hi - lo + 1 ); - mainQSort3 ( - ptr, block, quadrant, nblock, - lo, hi, BZ_N_RADIX, budget - ); - numQSorted += (hi - lo + 1); - if (*budget < 0) return; - } - } - ftab[sb] |= SETMASK; - } - } - - AssertH ( !bigDone[ss], 1006 ); - - /*-- - Step 2: - Now scan this big bucket [ss] so as to synthesise the - sorted order for small buckets [t, ss] for all t, - including, magically, the bucket [ss,ss] too. - This will avoid doing Real Work in subsequent Step 1's. - --*/ - { - for (j = 0; j <= 255; j++) { - copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; - copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; - } - for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { - k = ptr[j]-1; if (k < 0) k += nblock; - c1 = block[k]; - if (!bigDone[c1]) - ptr[ copyStart[c1]++ ] = k; - } - for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { - k = ptr[j]-1; if (k < 0) k += nblock; - c1 = block[k]; - if (!bigDone[c1]) - ptr[ copyEnd[c1]-- ] = k; - } - } - - AssertH ( (copyStart[ss]-1 == copyEnd[ss]) - || - /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. - Necessity for this case is demonstrated by compressing - a sequence of approximately 48.5 million of character - 251; 1.0.0/1.0.1 will then die here. */ - (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), - 1007 ) - - for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK; - - /*-- - Step 3: - The [ss] big bucket is now done. Record this fact, - and update the quadrant descriptors. Remember to - update quadrants in the overshoot area too, if - necessary. The "if (i < 255)" test merely skips - this updating for the last bucket processed, since - updating for the last bucket is pointless. - - The quadrant array provides a way to incrementally - cache sort orderings, as they appear, so as to - make subsequent comparisons in fullGtU() complete - faster. For repetitive blocks this makes a big - difference (but not big enough to be able to avoid - the fallback sorting mechanism, exponential radix sort). - - The precise meaning is: at all times: - - for 0 <= i < nblock and 0 <= j <= nblock - - if block[i] != block[j], - - then the relative values of quadrant[i] and - quadrant[j] are meaningless. - - else { - if quadrant[i] < quadrant[j] - then the string starting at i lexicographically - precedes the string starting at j - - else if quadrant[i] > quadrant[j] - then the string starting at j lexicographically - precedes the string starting at i - - else - the relative ordering of the strings starting - at i and j has not yet been determined. - } - --*/ - bigDone[ss] = True; - - if (i < 255) { - Int32 bbStart = ftab[ss << 8] & CLEARMASK; - Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; - Int32 shifts = 0; - - while ((bbSize >> shifts) > 65534) shifts++; - - for (j = bbSize-1; j >= 0; j--) { - Int32 a2update = ptr[bbStart + j]; - UInt16 qVal = (UInt16)(j >> shifts); - quadrant[a2update] = qVal; - if (a2update < BZ_N_OVERSHOOT) - quadrant[a2update + nblock] = qVal; - } - AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 ); - } - - } - - if (verb >= 4) - VPrintf3 ( " %d pointers, %d sorted, %d scanned\n", - nblock, numQSorted, nblock - numQSorted ); -} - -#undef BIGFREQ -#undef SETMASK -#undef CLEARMASK - - -/*---------------------------------------------*/ -/* Pre: - nblock > 0 - arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] - ((UChar*)arr2) [0 .. nblock-1] holds block - arr1 exists for [0 .. nblock-1] - - Post: - ((UChar*)arr2) [0 .. nblock-1] holds block - All other areas of block destroyed - ftab [ 0 .. 65536 ] destroyed - arr1 [0 .. nblock-1] holds sorted order -*/ -void BZ2_blockSort ( EState* s ) -{ - UInt32* ptr = s->ptr; - UChar* block = s->block; - UInt32* ftab = s->ftab; - Int32 nblock = s->nblock; - Int32 verb = s->verbosity; - Int32 wfact = s->workFactor; - UInt16* quadrant; - Int32 budget; - Int32 budgetInit; - Int32 i; - - if (nblock < 10000) { - fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); - } else { - /* Calculate the location for quadrant, remembering to get - the alignment right. Assumes that &(block[0]) is at least - 2-byte aligned -- this should be ok since block is really - the first section of arr2. - */ - i = nblock+BZ_N_OVERSHOOT; - if (i & 1) i++; - quadrant = (UInt16*)(&(block[i])); - - /* (wfact-1) / 3 puts the default-factor-30 - transition point at very roughly the same place as - with v0.1 and v0.9.0. - Not that it particularly matters any more, since the - resulting compressed stream is now the same regardless - of whether or not we use the main sort or fallback sort. - */ - if (wfact < 1 ) wfact = 1; - if (wfact > 100) wfact = 100; - budgetInit = nblock * ((wfact-1) / 3); - budget = budgetInit; - - mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget ); - if (verb >= 3) - VPrintf3 ( " %d work, %d block, ratio %5.2f\n", - budgetInit - budget, - nblock, - (float)(budgetInit - budget) / - (float)(nblock==0 ? 1 : nblock) ); - if (budget < 0) { - if (verb >= 2) - VPrintf0 ( " too repetitive; using fallback" - " sorting algorithm\n" ); - fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); - } - } - - s->origPtr = -1; - for (i = 0; i < s->nblock; i++) - if (ptr[i] == 0) - { s->origPtr = i; break; }; - - AssertH( s->origPtr != -1, 1003 ); -} - - -/*-------------------------------------------------------------*/ -/*--- end blocksort.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Block sorting machinery ---*/ +/*--- blocksort.c ---*/ +/*-------------------------------------------------------------*/ + +/*-- + This file is a part of bzip2 and/or libbzip2, a program and + library for lossless, block-sorting data compression. + + Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Julian Seward, Cambridge, UK. + jseward@bzip.org + bzip2/libbzip2 version 1.0 of 21 March 2000 + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the manual. + + To get some idea how the block sorting algorithms in this file + work, read my paper + On the Performance of BWT Sorting Algorithms + in Proceedings of the IEEE Data Compression Conference 2000, + Snowbird, Utah, USA, 27-30 March 2000. The main sort in this + file implements the algorithm called cache in the paper. +--*/ + + +#include "bzlib_private.h" + +/*---------------------------------------------*/ +/*--- Fallback O(N log(N)^2) sorting ---*/ +/*--- algorithm, for repetitive blocks ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +void fallbackSimpleSort ( UInt32* fmap, + UInt32* eclass, + Int32 lo, + Int32 hi ) +{ + Int32 i, j, tmp; + UInt32 ec_tmp; + + if (lo == hi) return; + + if (hi - lo > 3) { + for ( i = hi-4; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 ) + fmap[j-4] = fmap[j]; + fmap[j-4] = tmp; + } + } + + for ( i = hi-1; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ ) + fmap[j-1] = fmap[j]; + fmap[j-1] = tmp; + } +} + + +/*---------------------------------------------*/ +#define fswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define fvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + fswap(fmap[yyp1], fmap[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + + +#define fmin(a,b) ((a) < (b)) ? (a) : (b) + +#define fpush(lz,hz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + sp++; } + +#define fpop(lz,hz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; } + +#define FALLBACK_QSORT_SMALL_THRESH 10 +#define FALLBACK_QSORT_STACK_SIZE 100 + + +static +void fallbackQSort3 ( UInt32* fmap, + UInt32* eclass, + Int32 loSt, + Int32 hiSt ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m; + Int32 sp, lo, hi; + UInt32 med, r, r3; + Int32 stackLo[FALLBACK_QSORT_STACK_SIZE]; + Int32 stackHi[FALLBACK_QSORT_STACK_SIZE]; + + r = 0; + + sp = 0; + fpush ( loSt, hiSt ); + + while (sp > 0) { + + AssertH ( sp < FALLBACK_QSORT_STACK_SIZE, 1004 ); + + fpop ( lo, hi ); + if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { + fallbackSimpleSort ( fmap, eclass, lo, hi ); + continue; + } + + /* Random partitioning. Median of 3 sometimes fails to + avoid bad cases. Median of 9 seems to help but + looks rather expensive. This too seems to work but + is cheaper. Guidance for the magic constants + 7621 and 32768 is taken from Sedgewick's algorithms + book, chapter 35. + */ + r = ((r * 7621) + 1) % 32768; + r3 = r % 3; + if (r3 == 0) med = eclass[fmap[lo]]; else + if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else + med = eclass[fmap[hi]]; + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (1) { + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unLo]] - (Int32)med; + if (n == 0) { + fswap(fmap[unLo], fmap[ltLo]); + ltLo++; unLo++; + continue; + }; + if (n > 0) break; + unLo++; + } + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unHi]] - (Int32)med; + if (n == 0) { + fswap(fmap[unHi], fmap[gtHi]); + gtHi--; unHi--; + continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "fallbackQSort3(2)" ); + + if (gtHi < ltLo) continue; + + n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n); + m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + if (n - lo > hi - m) { + fpush ( lo, n ); + fpush ( m, hi ); + } else { + fpush ( m, hi ); + fpush ( lo, n ); + } + } +} + +#undef fmin +#undef fpush +#undef fpop +#undef fswap +#undef fvswap +#undef FALLBACK_QSORT_SMALL_THRESH +#undef FALLBACK_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + eclass exists for [0 .. nblock-1] + ((UChar*)eclass) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)eclass) [0 .. nblock-1] holds block + All other areas of eclass destroyed + fmap [0 .. nblock-1] holds sorted order + bhtab [ 0 .. 2+(nblock/32) ] destroyed +*/ + +#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) +#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) +#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) +#define WORD_BH(zz) bhtab[(zz) >> 5] +#define UNALIGNED_BH(zz) ((zz) & 0x01f) + +static +void fallbackSort ( UInt32* fmap, + UInt32* eclass, + UInt32* bhtab, + Int32 nblock, + Int32 verb ) +{ + Int32 ftab[257]; + Int32 ftabCopy[256]; + Int32 H, i, j, k, l, r, cc, cc1; + Int32 nNotDone; + Int32 nBhtab; + UChar* eclass8 = (UChar*)eclass; + + /*-- + Initial 1-char radix sort to generate + initial fmap and initial BH bits. + --*/ + if (verb >= 4) + VPrintf0 ( " bucket sorting ...\n" ); + for (i = 0; i < 257; i++) ftab[i] = 0; + for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; + for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; + for (i = 1; i < 257; i++) ftab[i] += ftab[i-1]; + + for (i = 0; i < nblock; i++) { + j = eclass8[i]; + k = ftab[j] - 1; + ftab[j] = k; + fmap[k] = i; + } + + nBhtab = 2 + (nblock / 32); + for (i = 0; i < nBhtab; i++) bhtab[i] = 0; + for (i = 0; i < 256; i++) SET_BH(ftab[i]); + + /*-- + Inductively refine the buckets. Kind-of an + "exponential radix sort" (!), inspired by the + Manber-Myers suffix array construction algorithm. + --*/ + + /*-- set sentinel bits for block-end detection --*/ + for (i = 0; i < 32; i++) { + SET_BH(nblock + 2*i); + CLEAR_BH(nblock + 2*i + 1); + } + + /*-- the log(N) loop --*/ + H = 1; + while (1) { + + if (verb >= 4) + VPrintf1 ( " depth %6d has ", H ); + + j = 0; + for (i = 0; i < nblock; i++) { + if (ISSET_BH(i)) j = i; + k = fmap[i] - H; if (k < 0) k += nblock; + eclass[k] = j; + } + + nNotDone = 0; + r = -1; + while (1) { + + /*-- find the next non-singleton bucket --*/ + k = r + 1; + while (ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (ISSET_BH(k)) { + while (WORD_BH(k) == 0xffffffff) k += 32; + while (ISSET_BH(k)) k++; + } + l = k - 1; + if (l >= nblock) break; + while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (!ISSET_BH(k)) { + while (WORD_BH(k) == 0x00000000) k += 32; + while (!ISSET_BH(k)) k++; + } + r = k - 1; + if (r >= nblock) break; + + /*-- now [l, r] bracket current bucket --*/ + if (r > l) { + nNotDone += (r - l + 1); + fallbackQSort3 ( fmap, eclass, l, r ); + + /*-- scan bucket and generate header bits-- */ + cc = -1; + for (i = l; i <= r; i++) { + cc1 = eclass[fmap[i]]; + if (cc != cc1) { SET_BH(i); cc = cc1; }; + } + } + } + + if (verb >= 4) + VPrintf1 ( "%6d unresolved strings\n", nNotDone ); + + H *= 2; + if (H > nblock || nNotDone == 0) break; + } + + /*-- + Reconstruct the original block in + eclass8 [0 .. nblock-1], since the + previous phase destroyed it. + --*/ + if (verb >= 4) + VPrintf0 ( " reconstructing block ...\n" ); + j = 0; + for (i = 0; i < nblock; i++) { + while (ftabCopy[j] == 0) j++; + ftabCopy[j]--; + eclass8[fmap[i]] = (UChar)j; + } + AssertH ( j < 256, 1005 ); +} + +#undef SET_BH +#undef CLEAR_BH +#undef ISSET_BH +#undef WORD_BH +#undef UNALIGNED_BH + + +/*---------------------------------------------*/ +/*--- The main, O(N^2 log(N)) sorting ---*/ +/*--- algorithm. Faster for "normal" ---*/ +/*--- non-repetitive blocks. ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +Bool mainGtU ( UInt32 i1, + UInt32 i2, + UChar* block, + UInt16* quadrant, + UInt32 nblock, + Int32* budget ) +{ + Int32 k; + UChar c1, c2; + UInt16 s1, s2; + + AssertD ( i1 != i2, "mainGtU" ); + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 9 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 10 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 11 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 12 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + + k = nblock + 8; + + do { + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + + if (i1 >= nblock) i1 -= nblock; + if (i2 >= nblock) i2 -= nblock; + + k -= 8; + (*budget)--; + } + while (k >= 0); + + return False; +} + + +/*---------------------------------------------*/ +/*-- + Knuth's increments seem to work better + than Incerpi-Sedgewick here. Possibly + because the number of elems to sort is + usually small, typically <= 20. +--*/ +static +Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, + 9841, 29524, 88573, 265720, + 797161, 2391484 }; + +static +void mainSimpleSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 lo, + Int32 hi, + Int32 d, + Int32* budget ) +{ + Int32 i, j, h, bigN, hp; + UInt32 v; + + bigN = hi - lo + 1; + if (bigN < 2) return; + + hp = 0; + while (incs[hp] < bigN) hp++; + hp--; + + for (; hp >= 0; hp--) { + h = incs[hp]; + + i = lo + h; + while (True) { + + /*-- copy 1 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 2 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 3 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + if (*budget < 0) return; + } + } +} + + +/*---------------------------------------------*/ +/*-- + The following is an implementation of + an elegant 3-way quicksort for strings, + described in a paper "Fast Algorithms for + Sorting and Searching Strings", by Robert + Sedgewick and Jon L. Bentley. +--*/ + +#define mswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define mvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + mswap(ptr[yyp1], ptr[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + +static +__inline__ +UChar mmed3 ( UChar a, UChar b, UChar c ) +{ + UChar t; + if (a > b) { t = a; a = b; b = t; }; + if (b > c) { + b = c; + if (a > b) b = a; + } + return b; +} + +#define mmin(a,b) ((a) < (b)) ? (a) : (b) + +#define mpush(lz,hz,dz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + stackD [sp] = dz; \ + sp++; } + +#define mpop(lz,hz,dz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; \ + dz = stackD [sp]; } + + +#define mnextsize(az) (nextHi[az]-nextLo[az]) + +#define mnextswap(az,bz) \ + { Int32 tz; \ + tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ + tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ + tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; } + + +#define MAIN_QSORT_SMALL_THRESH 20 +#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) +#define MAIN_QSORT_STACK_SIZE 100 + +static +void mainQSort3 ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 loSt, + Int32 hiSt, + Int32 dSt, + Int32* budget ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m, med; + Int32 sp, lo, hi, d; + + Int32 stackLo[MAIN_QSORT_STACK_SIZE]; + Int32 stackHi[MAIN_QSORT_STACK_SIZE]; + Int32 stackD [MAIN_QSORT_STACK_SIZE]; + + Int32 nextLo[3]; + Int32 nextHi[3]; + Int32 nextD [3]; + + sp = 0; + mpush ( loSt, hiSt, dSt ); + + while (sp > 0) { + + AssertH ( sp < MAIN_QSORT_STACK_SIZE, 1001 ); + + mpop ( lo, hi, d ); + if (hi - lo < MAIN_QSORT_SMALL_THRESH || + d > MAIN_QSORT_DEPTH_THRESH) { + mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget ); + if (*budget < 0) return; + continue; + } + + med = (Int32) + mmed3 ( block[ptr[ lo ]+d], + block[ptr[ hi ]+d], + block[ptr[ (lo+hi)>>1 ]+d] ); + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (True) { + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unLo]+d]) - med; + if (n == 0) { + mswap(ptr[unLo], ptr[ltLo]); + ltLo++; unLo++; continue; + }; + if (n > 0) break; + unLo++; + } + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unHi]+d]) - med; + if (n == 0) { + mswap(ptr[unHi], ptr[gtHi]); + gtHi--; unHi--; continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "mainQSort3(2)" ); + + if (gtHi < ltLo) { + mpush(lo, hi, d+1 ); + continue; + } + + n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n); + m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; + nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; + nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; + + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + if (mnextsize(1) < mnextsize(2)) mnextswap(1,2); + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + + AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" ); + AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" ); + + mpush (nextLo[0], nextHi[0], nextD[0]); + mpush (nextLo[1], nextHi[1], nextD[1]); + mpush (nextLo[2], nextHi[2], nextD[2]); + } +} + +#undef mswap +#undef mvswap +#undef mpush +#undef mpop +#undef mmin +#undef mnextsize +#undef mnextswap +#undef MAIN_QSORT_SMALL_THRESH +#undef MAIN_QSORT_DEPTH_THRESH +#undef MAIN_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > N_OVERSHOOT + block32 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)block32) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)block32) [0 .. nblock-1] holds block + All other areas of block32 destroyed + ftab [0 .. 65536 ] destroyed + ptr [0 .. nblock-1] holds sorted order + if (*budget < 0), sorting was abandoned +*/ + +#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) +#define SETMASK (1 << 21) +#define CLEARMASK (~(SETMASK)) + +static +void mainSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + UInt32* ftab, + Int32 nblock, + Int32 verb, + Int32* budget ) +{ + Int32 i, j, k, ss, sb; + Int32 runningOrder[256]; + Bool bigDone[256]; + Int32 copyStart[256]; + Int32 copyEnd [256]; + UChar c1; + Int32 numQSorted; + UInt16 s; + if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" ); + + /*-- set up the 2-byte frequency table --*/ + for (i = 65536; i >= 0; i--) ftab[i] = 0; + + j = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + quadrant[i-1] = 0; + j = (j >> 8) | ( ((UInt16)block[i-1]) << 8); + ftab[j]++; + quadrant[i-2] = 0; + j = (j >> 8) | ( ((UInt16)block[i-2]) << 8); + ftab[j]++; + quadrant[i-3] = 0; + j = (j >> 8) | ( ((UInt16)block[i-3]) << 8); + ftab[j]++; + } + for (; i >= 0; i--) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + } + + /*-- (emphasises close relationship of block & quadrant) --*/ + for (i = 0; i < BZ_N_OVERSHOOT; i++) { + block [nblock+i] = block[i]; + quadrant[nblock+i] = 0; + } + + if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" ); + + /*-- Complete the initial radix sort --*/ + for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1]; + + s = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + s = (s >> 8) | (block[i-1] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-1; + s = (s >> 8) | (block[i-2] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-2; + s = (s >> 8) | (block[i-3] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-3; + } + for (; i >= 0; i--) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + } + + /*-- + Now ftab contains the first loc of every small bucket. + Calculate the running order, from smallest to largest + big bucket. + --*/ + for (i = 0; i <= 255; i++) { + bigDone [i] = False; + runningOrder[i] = i; + } + + { + Int32 vv; + Int32 h = 1; + do h = 3 * h + 1; while (h <= 256); + do { + h = h / 3; + for (i = h; i <= 255; i++) { + vv = runningOrder[i]; + j = i; + while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) { + runningOrder[j] = runningOrder[j-h]; + j = j - h; + if (j <= (h - 1)) goto zero; + } + zero: + runningOrder[j] = vv; + } + } while (h != 1); + } + + /*-- + The main sorting loop. + --*/ + + numQSorted = 0; + + for (i = 0; i <= 255; i++) { + + /*-- + Process big buckets, starting with the least full. + Basically this is a 3-step process in which we call + mainQSort3 to sort the small buckets [ss, j], but + also make a big effort to avoid the calls if we can. + --*/ + ss = runningOrder[i]; + + /*-- + Step 1: + Complete the big bucket [ss] by quicksorting + any unsorted small buckets [ss, j], for j != ss. + Hopefully previous pointer-scanning phases have already + completed many of the small buckets [ss, j], so + we don't have to sort them at all. + --*/ + for (j = 0; j <= 255; j++) { + if (j != ss) { + sb = (ss << 8) + j; + if ( ! (ftab[sb] & SETMASK) ) { + Int32 lo = ftab[sb] & CLEARMASK; + Int32 hi = (ftab[sb+1] & CLEARMASK) - 1; + if (hi > lo) { + if (verb >= 4) + VPrintf4 ( " qsort [0x%x, 0x%x] " + "done %d this %d\n", + ss, j, numQSorted, hi - lo + 1 ); + mainQSort3 ( + ptr, block, quadrant, nblock, + lo, hi, BZ_N_RADIX, budget + ); + numQSorted += (hi - lo + 1); + if (*budget < 0) return; + } + } + ftab[sb] |= SETMASK; + } + } + + AssertH ( !bigDone[ss], 1006 ); + + /*-- + Step 2: + Now scan this big bucket [ss] so as to synthesise the + sorted order for small buckets [t, ss] for all t, + including, magically, the bucket [ss,ss] too. + This will avoid doing Real Work in subsequent Step 1's. + --*/ + { + for (j = 0; j <= 255; j++) { + copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; + copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; + } + for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyStart[c1]++ ] = k; + } + for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyEnd[c1]-- ] = k; + } + } + + AssertH ( (copyStart[ss]-1 == copyEnd[ss]) + || + /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. + Necessity for this case is demonstrated by compressing + a sequence of approximately 48.5 million of character + 251; 1.0.0/1.0.1 will then die here. */ + (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), + 1007 ) + + for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK; + + /*-- + Step 3: + The [ss] big bucket is now done. Record this fact, + and update the quadrant descriptors. Remember to + update quadrants in the overshoot area too, if + necessary. The "if (i < 255)" test merely skips + this updating for the last bucket processed, since + updating for the last bucket is pointless. + + The quadrant array provides a way to incrementally + cache sort orderings, as they appear, so as to + make subsequent comparisons in fullGtU() complete + faster. For repetitive blocks this makes a big + difference (but not big enough to be able to avoid + the fallback sorting mechanism, exponential radix sort). + + The precise meaning is: at all times: + + for 0 <= i < nblock and 0 <= j <= nblock + + if block[i] != block[j], + + then the relative values of quadrant[i] and + quadrant[j] are meaningless. + + else { + if quadrant[i] < quadrant[j] + then the string starting at i lexicographically + precedes the string starting at j + + else if quadrant[i] > quadrant[j] + then the string starting at j lexicographically + precedes the string starting at i + + else + the relative ordering of the strings starting + at i and j has not yet been determined. + } + --*/ + bigDone[ss] = True; + + if (i < 255) { + Int32 bbStart = ftab[ss << 8] & CLEARMASK; + Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; + Int32 shifts = 0; + + while ((bbSize >> shifts) > 65534) shifts++; + + for (j = bbSize-1; j >= 0; j--) { + Int32 a2update = ptr[bbStart + j]; + UInt16 qVal = (UInt16)(j >> shifts); + quadrant[a2update] = qVal; + if (a2update < BZ_N_OVERSHOOT) + quadrant[a2update + nblock] = qVal; + } + AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 ); + } + + } + + if (verb >= 4) + VPrintf3 ( " %d pointers, %d sorted, %d scanned\n", + nblock, numQSorted, nblock - numQSorted ); +} + +#undef BIGFREQ +#undef SETMASK +#undef CLEARMASK + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)arr2) [0 .. nblock-1] holds block + arr1 exists for [0 .. nblock-1] + + Post: + ((UChar*)arr2) [0 .. nblock-1] holds block + All other areas of block destroyed + ftab [ 0 .. 65536 ] destroyed + arr1 [0 .. nblock-1] holds sorted order +*/ +void BZ2_blockSort ( EState* s ) +{ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt32* ftab = s->ftab; + Int32 nblock = s->nblock; + Int32 verb = s->verbosity; + Int32 wfact = s->workFactor; + UInt16* quadrant; + Int32 budget; + Int32 budgetInit; + Int32 i; + + if (nblock < 10000) { + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } else { + /* Calculate the location for quadrant, remembering to get + the alignment right. Assumes that &(block[0]) is at least + 2-byte aligned -- this should be ok since block is really + the first section of arr2. + */ + i = nblock+BZ_N_OVERSHOOT; + if (i & 1) i++; + quadrant = (UInt16*)(&(block[i])); + + /* (wfact-1) / 3 puts the default-factor-30 + transition point at very roughly the same place as + with v0.1 and v0.9.0. + Not that it particularly matters any more, since the + resulting compressed stream is now the same regardless + of whether or not we use the main sort or fallback sort. + */ + if (wfact < 1 ) wfact = 1; + if (wfact > 100) wfact = 100; + budgetInit = nblock * ((wfact-1) / 3); + budget = budgetInit; + + mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget ); + if (verb >= 3) + VPrintf3 ( " %d work, %d block, ratio %5.2f\n", + budgetInit - budget, + nblock, + (float)(budgetInit - budget) / + (float)(nblock==0 ? 1 : nblock) ); + if (budget < 0) { + if (verb >= 2) + VPrintf0 ( " too repetitive; using fallback" + " sorting algorithm\n" ); + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } + } + + s->origPtr = -1; + for (i = 0; i < s->nblock; i++) + if (ptr[i] == 0) + { s->origPtr = i; break; }; + + AssertH( s->origPtr != -1, 1003 ); +} + + +/*-------------------------------------------------------------*/ +/*--- end blocksort.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDisoEFP/src/bzip2/bzlib.c b/plugins/CDVDisoEFP/src/bzip2/bzlib.c index 5704dc4bba..e9c1e879de 100644 --- a/plugins/CDVDisoEFP/src/bzip2/bzlib.c +++ b/plugins/CDVDisoEFP/src/bzip2/bzlib.c @@ -1,1616 +1,1616 @@ - -/*-------------------------------------------------------------*/ -/*--- Library top-level functions. ---*/ -/*--- bzlib.c ---*/ -/*-------------------------------------------------------------*/ - -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. - - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ - -/*-- - CHANGES - ~~~~~~~ - 0.9.0 -- original version. - - 0.9.0a/b -- no changes in this file. - - 0.9.0c - * made zero-length BZ_FLUSH work correctly in bzCompress(). - * fixed bzWrite/bzRead to ignore zero-length requests. - * fixed bzread to correctly handle read requests after EOF. - * wrong parameter order in call to bzDecompressInit in - bzBuffToBuffDecompress. Fixed. ---*/ - -#include "bzlib_private.h" - - -/*---------------------------------------------------*/ -/*--- Compression stuff ---*/ -/*---------------------------------------------------*/ - - -/*---------------------------------------------------*/ -#ifndef BZ_NO_STDIO -void BZ2_bz__AssertH__fail ( int errcode ) -{ - fprintf(stderr, - "\n\nbzip2/libbzip2: internal error number %d.\n" - "This is a bug in bzip2/libbzip2, %s.\n" - "Please report it to me at: jseward@bzip.org. If this happened\n" - "when you were using some program which uses libbzip2 as a\n" - "component, you should also report this bug to the author(s)\n" - "of that program. Please make an effort to report this bug;\n" - "timely and accurate bug reports eventually lead to higher\n" - "quality software. Thanks. Julian Seward, 15 February 2005.\n\n", - errcode, - BZ2_bzlibVersion() - ); - - if (errcode == 1007) { - fprintf(stderr, - "\n*** A special note about internal error number 1007 ***\n" - "\n" - "Experience suggests that a common cause of i.e. 1007\n" - "is unreliable memory or other hardware. The 1007 assertion\n" - "just happens to cross-check the results of huge numbers of\n" - "memory reads/writes, and so acts (unintendedly) as a stress\n" - "test of your memory system.\n" - "\n" - "I suggest the following: try compressing the file again,\n" - "possibly monitoring progress in detail with the -vv flag.\n" - "\n" - "* If the error cannot be reproduced, and/or happens at different\n" - " points in compression, you may have a flaky memory system.\n" - " Try a memory-test program. I have used Memtest86\n" - " (www.memtest86.com). At the time of writing it is free (GPLd).\n" - " Memtest86 tests memory much more thorougly than your BIOSs\n" - " power-on test, and may find failures that the BIOS doesn't.\n" - "\n" - "* If the error can be repeatably reproduced, this is a bug in\n" - " bzip2, and I would very much like to hear about it. Please\n" - " let me know, and, ideally, save a copy of the file causing the\n" - " problem -- without which I will be unable to investigate it.\n" - "\n" - ); - } - - exit(3); -} -#endif - - -/*---------------------------------------------------*/ -static -int bz_config_ok ( void ) -{ - if (sizeof(int) != 4) return 0; - if (sizeof(short) != 2) return 0; - if (sizeof(char) != 1) return 0; - return 1; -} - - -/*---------------------------------------------------*/ -static -void* default_bzalloc ( void* opaque, Int32 items, Int32 size ) -{ - void* v = malloc ( items * size ); - return v; -} - -static -void default_bzfree ( void* opaque, void* addr ) -{ - if (addr != NULL) free ( addr ); -} - - -/*---------------------------------------------------*/ -static -void prepare_new_block ( EState* s ) -{ - Int32 i; - s->nblock = 0; - s->numZ = 0; - s->state_out_pos = 0; - BZ_INITIALISE_CRC ( s->blockCRC ); - for (i = 0; i < 256; i++) s->inUse[i] = False; - s->blockNo++; -} - - -/*---------------------------------------------------*/ -static -void init_RL ( EState* s ) -{ - s->state_in_ch = 256; - s->state_in_len = 0; -} - - -static -Bool isempty_RL ( EState* s ) -{ - if (s->state_in_ch < 256 && s->state_in_len > 0) - return False; else - return True; -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzCompressInit) - ( bz_stream* strm, - int blockSize100k, - int verbosity, - int workFactor ) -{ - Int32 n; - EState* s; - - if (!bz_config_ok()) return BZ_CONFIG_ERROR; - - if (strm == NULL || - blockSize100k < 1 || blockSize100k > 9 || - workFactor < 0 || workFactor > 250) - return BZ_PARAM_ERROR; - - if (workFactor == 0) workFactor = 30; - if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; - if (strm->bzfree == NULL) strm->bzfree = default_bzfree; - - s = BZALLOC( sizeof(EState) ); - if (s == NULL) return BZ_MEM_ERROR; - s->strm = strm; - - s->arr1 = NULL; - s->arr2 = NULL; - s->ftab = NULL; - - n = 100000 * blockSize100k; - s->arr1 = BZALLOC( n * sizeof(UInt32) ); - s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) ); - s->ftab = BZALLOC( 65537 * sizeof(UInt32) ); - - if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) { - if (s->arr1 != NULL) BZFREE(s->arr1); - if (s->arr2 != NULL) BZFREE(s->arr2); - if (s->ftab != NULL) BZFREE(s->ftab); - if (s != NULL) BZFREE(s); - return BZ_MEM_ERROR; - } - - s->blockNo = 0; - s->state = BZ_S_INPUT; - s->mode = BZ_M_RUNNING; - s->combinedCRC = 0; - s->blockSize100k = blockSize100k; - s->nblockMAX = 100000 * blockSize100k - 19; - s->verbosity = verbosity; - s->workFactor = workFactor; - - s->block = (UChar*)s->arr2; - s->mtfv = (UInt16*)s->arr1; - s->zbits = NULL; - s->ptr = (UInt32*)s->arr1; - - strm->state = s; - strm->total_in_lo32 = 0; - strm->total_in_hi32 = 0; - strm->total_out_lo32 = 0; - strm->total_out_hi32 = 0; - init_RL ( s ); - prepare_new_block ( s ); - return BZ_OK; -} - - -/*---------------------------------------------------*/ -static -void add_pair_to_block ( EState* s ) -{ - Int32 i; - UChar ch = (UChar)(s->state_in_ch); - for (i = 0; i < s->state_in_len; i++) { - BZ_UPDATE_CRC( s->blockCRC, ch ); - } - s->inUse[s->state_in_ch] = True; - switch (s->state_in_len) { - case 1: - s->block[s->nblock] = (UChar)ch; s->nblock++; - break; - case 2: - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - break; - case 3: - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - break; - default: - s->inUse[s->state_in_len-4] = True; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = ((UChar)(s->state_in_len-4)); - s->nblock++; - break; - } -} - - -/*---------------------------------------------------*/ -static -void flush_RL ( EState* s ) -{ - if (s->state_in_ch < 256) add_pair_to_block ( s ); - init_RL ( s ); -} - - -/*---------------------------------------------------*/ -#define ADD_CHAR_TO_BLOCK(zs,zchh0) \ -{ \ - UInt32 zchh = (UInt32)(zchh0); \ - /*-- fast track the common case --*/ \ - if (zchh != zs->state_in_ch && \ - zs->state_in_len == 1) { \ - UChar ch = (UChar)(zs->state_in_ch); \ - BZ_UPDATE_CRC( zs->blockCRC, ch ); \ - zs->inUse[zs->state_in_ch] = True; \ - zs->block[zs->nblock] = (UChar)ch; \ - zs->nblock++; \ - zs->state_in_ch = zchh; \ - } \ - else \ - /*-- general, uncommon cases --*/ \ - if (zchh != zs->state_in_ch || \ - zs->state_in_len == 255) { \ - if (zs->state_in_ch < 256) \ - add_pair_to_block ( zs ); \ - zs->state_in_ch = zchh; \ - zs->state_in_len = 1; \ - } else { \ - zs->state_in_len++; \ - } \ -} - - -/*---------------------------------------------------*/ -static -Bool copy_input_until_stop ( EState* s ) -{ - Bool progress_in = False; - - if (s->mode == BZ_M_RUNNING) { - - /*-- fast track the common case --*/ - while (True) { - /*-- block full? --*/ - if (s->nblock >= s->nblockMAX) break; - /*-- no input? --*/ - if (s->strm->avail_in == 0) break; - progress_in = True; - ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); - s->strm->next_in++; - s->strm->avail_in--; - s->strm->total_in_lo32++; - if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; - } - - } else { - - /*-- general, uncommon case --*/ - while (True) { - /*-- block full? --*/ - if (s->nblock >= s->nblockMAX) break; - /*-- no input? --*/ - if (s->strm->avail_in == 0) break; - /*-- flush/finish end? --*/ - if (s->avail_in_expect == 0) break; - progress_in = True; - ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); - s->strm->next_in++; - s->strm->avail_in--; - s->strm->total_in_lo32++; - if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; - s->avail_in_expect--; - } - } - return progress_in; -} - - -/*---------------------------------------------------*/ -static -Bool copy_output_until_stop ( EState* s ) -{ - Bool progress_out = False; - - while (True) { - - /*-- no output space? --*/ - if (s->strm->avail_out == 0) break; - - /*-- block done? --*/ - if (s->state_out_pos >= s->numZ) break; - - progress_out = True; - *(s->strm->next_out) = s->zbits[s->state_out_pos]; - s->state_out_pos++; - s->strm->avail_out--; - s->strm->next_out++; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - return progress_out; -} - - -/*---------------------------------------------------*/ -static -Bool handle_compress ( bz_stream* strm ) -{ - Bool progress_in = False; - Bool progress_out = False; - EState* s = strm->state; - - while (True) { - - if (s->state == BZ_S_OUTPUT) { - progress_out |= copy_output_until_stop ( s ); - if (s->state_out_pos < s->numZ) break; - if (s->mode == BZ_M_FINISHING && - s->avail_in_expect == 0 && - isempty_RL(s)) break; - prepare_new_block ( s ); - s->state = BZ_S_INPUT; - if (s->mode == BZ_M_FLUSHING && - s->avail_in_expect == 0 && - isempty_RL(s)) break; - } - - if (s->state == BZ_S_INPUT) { - progress_in |= copy_input_until_stop ( s ); - if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { - flush_RL ( s ); - BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) ); - s->state = BZ_S_OUTPUT; - } - else - if (s->nblock >= s->nblockMAX) { - BZ2_compressBlock ( s, False ); - s->state = BZ_S_OUTPUT; - } - else - if (s->strm->avail_in == 0) { - break; - } - } - - } - - return progress_in || progress_out; -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action ) -{ - Bool progress; - EState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - preswitch: - switch (s->mode) { - - case BZ_M_IDLE: - return BZ_SEQUENCE_ERROR; - - case BZ_M_RUNNING: - if (action == BZ_RUN) { - progress = handle_compress ( strm ); - return progress ? BZ_RUN_OK : BZ_PARAM_ERROR; - } - else - if (action == BZ_FLUSH) { - s->avail_in_expect = strm->avail_in; - s->mode = BZ_M_FLUSHING; - goto preswitch; - } - else - if (action == BZ_FINISH) { - s->avail_in_expect = strm->avail_in; - s->mode = BZ_M_FINISHING; - goto preswitch; - } - else - return BZ_PARAM_ERROR; - - case BZ_M_FLUSHING: - if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR; - if (s->avail_in_expect != s->strm->avail_in) - return BZ_SEQUENCE_ERROR; - progress = handle_compress ( strm ); - if (s->avail_in_expect > 0 || !isempty_RL(s) || - s->state_out_pos < s->numZ) return BZ_FLUSH_OK; - s->mode = BZ_M_RUNNING; - return BZ_RUN_OK; - - case BZ_M_FINISHING: - if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR; - if (s->avail_in_expect != s->strm->avail_in) - return BZ_SEQUENCE_ERROR; - progress = handle_compress ( strm ); - if (!progress) return BZ_SEQUENCE_ERROR; - if (s->avail_in_expect > 0 || !isempty_RL(s) || - s->state_out_pos < s->numZ) return BZ_FINISH_OK; - s->mode = BZ_M_IDLE; - return BZ_STREAM_END; - } - return BZ_OK; /*--not reached--*/ -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm ) -{ - EState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - if (s->arr1 != NULL) BZFREE(s->arr1); - if (s->arr2 != NULL) BZFREE(s->arr2); - if (s->ftab != NULL) BZFREE(s->ftab); - BZFREE(strm->state); - - strm->state = NULL; - - return BZ_OK; -} - - -/*---------------------------------------------------*/ -/*--- Decompression stuff ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzDecompressInit) - ( bz_stream* strm, - int verbosity, - int small ) -{ - DState* s; - - if (!bz_config_ok()) return BZ_CONFIG_ERROR; - - if (strm == NULL) return BZ_PARAM_ERROR; - if (small != 0 && small != 1) return BZ_PARAM_ERROR; - if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; - - if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; - if (strm->bzfree == NULL) strm->bzfree = default_bzfree; - - s = BZALLOC( sizeof(DState) ); - if (s == NULL) return BZ_MEM_ERROR; - s->strm = strm; - strm->state = s; - s->state = BZ_X_MAGIC_1; - s->bsLive = 0; - s->bsBuff = 0; - s->calculatedCombinedCRC = 0; - strm->total_in_lo32 = 0; - strm->total_in_hi32 = 0; - strm->total_out_lo32 = 0; - strm->total_out_hi32 = 0; - s->smallDecompress = (Bool)small; - s->ll4 = NULL; - s->ll16 = NULL; - s->tt = NULL; - s->currBlockNo = 0; - s->verbosity = verbosity; - - return BZ_OK; -} - - -/*---------------------------------------------------*/ -/* Return True iff data corruption is discovered. - Returns False if there is no problem. -*/ -static -Bool unRLE_obuf_to_output_FAST ( DState* s ) -{ - UChar k1; - - if (s->blockRandomised) { - - while (True) { - /* try to finish existing run */ - while (True) { - if (s->strm->avail_out == 0) return False; - if (s->state_out_len == 0) break; - *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; - BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); - s->state_out_len--; - s->strm->next_out++; - s->strm->avail_out--; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - /* can a new run be started? */ - if (s->nblock_used == s->save_nblock+1) return False; - - /* Only caused by corrupt data stream? */ - if (s->nblock_used > s->save_nblock+1) - return True; - - s->state_out_len = 1; - s->state_out_ch = s->k0; - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 2; - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 3; - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - s->state_out_len = ((Int32)k1) + 4; - BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; - s->k0 ^= BZ_RAND_MASK; s->nblock_used++; - } - - } else { - - /* restore */ - UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; - UChar c_state_out_ch = s->state_out_ch; - Int32 c_state_out_len = s->state_out_len; - Int32 c_nblock_used = s->nblock_used; - Int32 c_k0 = s->k0; - UInt32* c_tt = s->tt; - UInt32 c_tPos = s->tPos; - char* cs_next_out = s->strm->next_out; - unsigned int cs_avail_out = s->strm->avail_out; - /* end restore */ - - UInt32 avail_out_INIT = cs_avail_out; - Int32 s_save_nblockPP = s->save_nblock+1; - unsigned int total_out_lo32_old; - - while (True) { - - /* try to finish existing run */ - if (c_state_out_len > 0) { - while (True) { - if (cs_avail_out == 0) goto return_notr; - if (c_state_out_len == 1) break; - *( (UChar*)(cs_next_out) ) = c_state_out_ch; - BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); - c_state_out_len--; - cs_next_out++; - cs_avail_out--; - } - s_state_out_len_eq_one: - { - if (cs_avail_out == 0) { - c_state_out_len = 1; goto return_notr; - }; - *( (UChar*)(cs_next_out) ) = c_state_out_ch; - BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); - cs_next_out++; - cs_avail_out--; - } - } - /* Only caused by corrupt data stream? */ - if (c_nblock_used > s_save_nblockPP) - return True; - - /* can a new run be started? */ - if (c_nblock_used == s_save_nblockPP) { - c_state_out_len = 0; goto return_notr; - }; - c_state_out_ch = c_k0; - BZ_GET_FAST_C(k1); c_nblock_used++; - if (k1 != c_k0) { - c_k0 = k1; goto s_state_out_len_eq_one; - }; - if (c_nblock_used == s_save_nblockPP) - goto s_state_out_len_eq_one; - - c_state_out_len = 2; - BZ_GET_FAST_C(k1); c_nblock_used++; - if (c_nblock_used == s_save_nblockPP) continue; - if (k1 != c_k0) { c_k0 = k1; continue; }; - - c_state_out_len = 3; - BZ_GET_FAST_C(k1); c_nblock_used++; - if (c_nblock_used == s_save_nblockPP) continue; - if (k1 != c_k0) { c_k0 = k1; continue; }; - - BZ_GET_FAST_C(k1); c_nblock_used++; - c_state_out_len = ((Int32)k1) + 4; - BZ_GET_FAST_C(c_k0); c_nblock_used++; - } - - return_notr: - total_out_lo32_old = s->strm->total_out_lo32; - s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); - if (s->strm->total_out_lo32 < total_out_lo32_old) - s->strm->total_out_hi32++; - - /* save */ - s->calculatedBlockCRC = c_calculatedBlockCRC; - s->state_out_ch = c_state_out_ch; - s->state_out_len = c_state_out_len; - s->nblock_used = c_nblock_used; - s->k0 = c_k0; - s->tt = c_tt; - s->tPos = c_tPos; - s->strm->next_out = cs_next_out; - s->strm->avail_out = cs_avail_out; - /* end save */ - } - return False; -} - - - -/*---------------------------------------------------*/ -__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) -{ - Int32 nb, na, mid; - nb = 0; - na = 256; - do { - mid = (nb + na) >> 1; - if (indx >= cftab[mid]) nb = mid; else na = mid; - } - while (na - nb != 1); - return nb; -} - - -/*---------------------------------------------------*/ -/* Return True iff data corruption is discovered. - Returns False if there is no problem. -*/ -static -Bool unRLE_obuf_to_output_SMALL ( DState* s ) -{ - UChar k1; - - if (s->blockRandomised) { - - while (True) { - /* try to finish existing run */ - while (True) { - if (s->strm->avail_out == 0) return False; - if (s->state_out_len == 0) break; - *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; - BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); - s->state_out_len--; - s->strm->next_out++; - s->strm->avail_out--; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - /* can a new run be started? */ - if (s->nblock_used == s->save_nblock+1) return False; - - /* Only caused by corrupt data stream? */ - if (s->nblock_used > s->save_nblock+1) - return True; - - s->state_out_len = 1; - s->state_out_ch = s->k0; - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 2; - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 3; - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - s->state_out_len = ((Int32)k1) + 4; - BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; - s->k0 ^= BZ_RAND_MASK; s->nblock_used++; - } - - } else { - - while (True) { - /* try to finish existing run */ - while (True) { - if (s->strm->avail_out == 0) return False; - if (s->state_out_len == 0) break; - *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; - BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); - s->state_out_len--; - s->strm->next_out++; - s->strm->avail_out--; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - /* can a new run be started? */ - if (s->nblock_used == s->save_nblock+1) return False; - - /* Only caused by corrupt data stream? */ - if (s->nblock_used > s->save_nblock+1) - return True; - - s->state_out_len = 1; - s->state_out_ch = s->k0; - BZ_GET_SMALL(k1); s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 2; - BZ_GET_SMALL(k1); s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 3; - BZ_GET_SMALL(k1); s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - BZ_GET_SMALL(k1); s->nblock_used++; - s->state_out_len = ((Int32)k1) + 4; - BZ_GET_SMALL(s->k0); s->nblock_used++; - } - - } -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) -{ - Bool corrupt; - DState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - while (True) { - if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; - if (s->state == BZ_X_OUTPUT) { - if (s->smallDecompress) - corrupt = unRLE_obuf_to_output_SMALL ( s ); else - corrupt = unRLE_obuf_to_output_FAST ( s ); - if (corrupt) return BZ_DATA_ERROR; - if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { - BZ_FINALISE_CRC ( s->calculatedBlockCRC ); - if (s->verbosity >= 3) - VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, - s->calculatedBlockCRC ); - if (s->verbosity >= 2) VPrintf0 ( "]" ); - if (s->calculatedBlockCRC != s->storedBlockCRC) - return BZ_DATA_ERROR; - s->calculatedCombinedCRC - = (s->calculatedCombinedCRC << 1) | - (s->calculatedCombinedCRC >> 31); - s->calculatedCombinedCRC ^= s->calculatedBlockCRC; - s->state = BZ_X_BLKHDR_1; - } else { - return BZ_OK; - } - } - if (s->state >= BZ_X_MAGIC_1) { - Int32 r = BZ2_decompress ( s ); - if (r == BZ_STREAM_END) { - if (s->verbosity >= 3) - VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x", - s->storedCombinedCRC, s->calculatedCombinedCRC ); - if (s->calculatedCombinedCRC != s->storedCombinedCRC) - return BZ_DATA_ERROR; - return r; - } - if (s->state != BZ_X_OUTPUT) return r; - } - } - - AssertH ( 0, 6001 ); - - return 0; /*NOTREACHED*/ -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) -{ - DState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - if (s->tt != NULL) BZFREE(s->tt); - if (s->ll16 != NULL) BZFREE(s->ll16); - if (s->ll4 != NULL) BZFREE(s->ll4); - - BZFREE(strm->state); - strm->state = NULL; - - return BZ_OK; -} - - -#ifndef BZ_NO_STDIO -/*---------------------------------------------------*/ -/*--- File I/O stuff ---*/ -/*---------------------------------------------------*/ - -#define BZ_SETERR(eee) \ -{ \ - if (bzerror != NULL) *bzerror = eee; \ - if (bzf != NULL) bzf->lastErr = eee; \ -} - -typedef - struct { - FILE* handle; - Char buf[BZ_MAX_UNUSED]; - Int32 bufN; - Bool writing; - bz_stream strm; - Int32 lastErr; - Bool initialisedOk; - } - bzFile; - - -/*---------------------------------------------*/ -static Bool myfeof ( FILE* f ) -{ - Int32 c = fgetc ( f ); - if (c == EOF) return True; - ungetc ( c, f ); - return False; -} - - -/*---------------------------------------------------*/ -BZFILE* BZ_API(BZ2_bzWriteOpen) - ( int* bzerror, - FILE* f, - int blockSize100k, - int verbosity, - int workFactor ) -{ - Int32 ret; - bzFile* bzf = NULL; - - BZ_SETERR(BZ_OK); - - if (f == NULL || - (blockSize100k < 1 || blockSize100k > 9) || - (workFactor < 0 || workFactor > 250) || - (verbosity < 0 || verbosity > 4)) - { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; - - if (ferror(f)) - { BZ_SETERR(BZ_IO_ERROR); return NULL; }; - - bzf = malloc ( sizeof(bzFile) ); - if (bzf == NULL) - { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; - - BZ_SETERR(BZ_OK); - bzf->initialisedOk = False; - bzf->bufN = 0; - bzf->handle = f; - bzf->writing = True; - bzf->strm.bzalloc = NULL; - bzf->strm.bzfree = NULL; - bzf->strm.opaque = NULL; - - if (workFactor == 0) workFactor = 30; - ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, - verbosity, workFactor ); - if (ret != BZ_OK) - { BZ_SETERR(ret); free(bzf); return NULL; }; - - bzf->strm.avail_in = 0; - bzf->initialisedOk = True; - return bzf; -} - - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzWrite) - ( int* bzerror, - BZFILE* b, - void* buf, - int len ) -{ - Int32 n, n2, ret; - bzFile* bzf = (bzFile*)b; - - BZ_SETERR(BZ_OK); - if (bzf == NULL || buf == NULL || len < 0) - { BZ_SETERR(BZ_PARAM_ERROR); return; }; - if (!(bzf->writing)) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - - if (len == 0) - { BZ_SETERR(BZ_OK); return; }; - - bzf->strm.avail_in = len; - bzf->strm.next_in = buf; - - while (True) { - bzf->strm.avail_out = BZ_MAX_UNUSED; - bzf->strm.next_out = bzf->buf; - ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN ); - if (ret != BZ_RUN_OK) - { BZ_SETERR(ret); return; }; - - if (bzf->strm.avail_out < BZ_MAX_UNUSED) { - n = BZ_MAX_UNUSED - bzf->strm.avail_out; - n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), - n, bzf->handle ); - if (n != n2 || ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - } - - if (bzf->strm.avail_in == 0) - { BZ_SETERR(BZ_OK); return; }; - } -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzWriteClose) - ( int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in, - unsigned int* nbytes_out ) -{ - BZ2_bzWriteClose64 ( bzerror, b, abandon, - nbytes_in, NULL, nbytes_out, NULL ); -} - - -void BZ_API(BZ2_bzWriteClose64) - ( int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in_lo32, - unsigned int* nbytes_in_hi32, - unsigned int* nbytes_out_lo32, - unsigned int* nbytes_out_hi32 ) -{ - Int32 n, n2, ret; - bzFile* bzf = (bzFile*)b; - - if (bzf == NULL) - { BZ_SETERR(BZ_OK); return; }; - if (!(bzf->writing)) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - - if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0; - if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0; - if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0; - if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0; - - if ((!abandon) && bzf->lastErr == BZ_OK) { - while (True) { - bzf->strm.avail_out = BZ_MAX_UNUSED; - bzf->strm.next_out = bzf->buf; - ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH ); - if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) - { BZ_SETERR(ret); return; }; - - if (bzf->strm.avail_out < BZ_MAX_UNUSED) { - n = BZ_MAX_UNUSED - bzf->strm.avail_out; - n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), - n, bzf->handle ); - if (n != n2 || ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - } - - if (ret == BZ_STREAM_END) break; - } - } - - if ( !abandon && !ferror ( bzf->handle ) ) { - fflush ( bzf->handle ); - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - } - - if (nbytes_in_lo32 != NULL) - *nbytes_in_lo32 = bzf->strm.total_in_lo32; - if (nbytes_in_hi32 != NULL) - *nbytes_in_hi32 = bzf->strm.total_in_hi32; - if (nbytes_out_lo32 != NULL) - *nbytes_out_lo32 = bzf->strm.total_out_lo32; - if (nbytes_out_hi32 != NULL) - *nbytes_out_hi32 = bzf->strm.total_out_hi32; - - BZ_SETERR(BZ_OK); - BZ2_bzCompressEnd ( &(bzf->strm) ); - free ( bzf ); -} - - -/*---------------------------------------------------*/ -BZFILE* BZ_API(BZ2_bzReadOpen) - ( int* bzerror, - FILE* f, - int verbosity, - int small, - void* unused, - int nUnused ) -{ - bzFile* bzf = NULL; - int ret; - - BZ_SETERR(BZ_OK); - - if (f == NULL || - (small != 0 && small != 1) || - (verbosity < 0 || verbosity > 4) || - (unused == NULL && nUnused != 0) || - (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) - { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; - - if (ferror(f)) - { BZ_SETERR(BZ_IO_ERROR); return NULL; }; - - bzf = malloc ( sizeof(bzFile) ); - if (bzf == NULL) - { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; - - BZ_SETERR(BZ_OK); - - bzf->initialisedOk = False; - bzf->handle = f; - bzf->bufN = 0; - bzf->writing = False; - bzf->strm.bzalloc = NULL; - bzf->strm.bzfree = NULL; - bzf->strm.opaque = NULL; - - while (nUnused > 0) { - bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; - unused = ((void*)( 1 + ((UChar*)(unused)) )); - nUnused--; - } - - ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); - if (ret != BZ_OK) - { BZ_SETERR(ret); free(bzf); return NULL; }; - - bzf->strm.avail_in = bzf->bufN; - bzf->strm.next_in = bzf->buf; - - bzf->initialisedOk = True; - return bzf; -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) -{ - bzFile* bzf = (bzFile*)b; - - BZ_SETERR(BZ_OK); - if (bzf == NULL) - { BZ_SETERR(BZ_OK); return; }; - - if (bzf->writing) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - - if (bzf->initialisedOk) - (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); - free ( bzf ); -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzRead) - ( int* bzerror, - BZFILE* b, - void* buf, - int len ) -{ - Int32 n, ret; - bzFile* bzf = (bzFile*)b; - - BZ_SETERR(BZ_OK); - - if (bzf == NULL || buf == NULL || len < 0) - { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; - - if (bzf->writing) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; - - if (len == 0) - { BZ_SETERR(BZ_OK); return 0; }; - - bzf->strm.avail_out = len; - bzf->strm.next_out = buf; - - while (True) { - - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return 0; }; - - if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { - n = fread ( bzf->buf, sizeof(UChar), - BZ_MAX_UNUSED, bzf->handle ); - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return 0; }; - bzf->bufN = n; - bzf->strm.avail_in = bzf->bufN; - bzf->strm.next_in = bzf->buf; - } - - ret = BZ2_bzDecompress ( &(bzf->strm) ); - - if (ret != BZ_OK && ret != BZ_STREAM_END) - { BZ_SETERR(ret); return 0; }; - - if (ret == BZ_OK && myfeof(bzf->handle) && - bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) - { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; - - if (ret == BZ_STREAM_END) - { BZ_SETERR(BZ_STREAM_END); - return len - bzf->strm.avail_out; }; - if (bzf->strm.avail_out == 0) - { BZ_SETERR(BZ_OK); return len; }; - - } - - return 0; /*not reached*/ -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzReadGetUnused) - ( int* bzerror, - BZFILE* b, - void** unused, - int* nUnused ) -{ - bzFile* bzf = (bzFile*)b; - if (bzf == NULL) - { BZ_SETERR(BZ_PARAM_ERROR); return; }; - if (bzf->lastErr != BZ_STREAM_END) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - if (unused == NULL || nUnused == NULL) - { BZ_SETERR(BZ_PARAM_ERROR); return; }; - - BZ_SETERR(BZ_OK); - *nUnused = bzf->strm.avail_in; - *unused = bzf->strm.next_in; -} -#endif - - -/*---------------------------------------------------*/ -/*--- Misc convenience stuff ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzBuffToBuffCompress) - ( char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int blockSize100k, - int verbosity, - int workFactor ) -{ - bz_stream strm; - int ret; - - if (dest == NULL || destLen == NULL || - source == NULL || - blockSize100k < 1 || blockSize100k > 9 || - verbosity < 0 || verbosity > 4 || - workFactor < 0 || workFactor > 250) - return BZ_PARAM_ERROR; - - if (workFactor == 0) workFactor = 30; - strm.bzalloc = NULL; - strm.bzfree = NULL; - strm.opaque = NULL; - ret = BZ2_bzCompressInit ( &strm, blockSize100k, - verbosity, workFactor ); - if (ret != BZ_OK) return ret; - - strm.next_in = source; - strm.next_out = dest; - strm.avail_in = sourceLen; - strm.avail_out = *destLen; - - ret = BZ2_bzCompress ( &strm, BZ_FINISH ); - if (ret == BZ_FINISH_OK) goto output_overflow; - if (ret != BZ_STREAM_END) goto errhandler; - - /* normal termination */ - *destLen -= strm.avail_out; - BZ2_bzCompressEnd ( &strm ); - return BZ_OK; - - output_overflow: - BZ2_bzCompressEnd ( &strm ); - return BZ_OUTBUFF_FULL; - - errhandler: - BZ2_bzCompressEnd ( &strm ); - return ret; -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzBuffToBuffDecompress) - ( char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int small, - int verbosity ) -{ - bz_stream strm; - int ret; - - if (dest == NULL || destLen == NULL || - source == NULL || - (small != 0 && small != 1) || - verbosity < 0 || verbosity > 4) - return BZ_PARAM_ERROR; - - strm.bzalloc = NULL; - strm.bzfree = NULL; - strm.opaque = NULL; - ret = BZ2_bzDecompressInit ( &strm, verbosity, small ); - if (ret != BZ_OK) return ret; - - strm.next_in = source; - strm.next_out = dest; - strm.avail_in = sourceLen; - strm.avail_out = *destLen; - - ret = BZ2_bzDecompress ( &strm ); - if (ret == BZ_OK) goto output_overflow_or_eof; - if (ret != BZ_STREAM_END) goto errhandler; - - /* normal termination */ - *destLen -= strm.avail_out; - BZ2_bzDecompressEnd ( &strm ); - return BZ_OK; - - output_overflow_or_eof: - if (strm.avail_out > 0) { - BZ2_bzDecompressEnd ( &strm ); - return BZ_UNEXPECTED_EOF; - } else { - BZ2_bzDecompressEnd ( &strm ); - return BZ_OUTBUFF_FULL; - }; - - errhandler: - BZ2_bzDecompressEnd ( &strm ); - return ret; -} - - -/*---------------------------------------------------*/ -/*-- - Code contributed by Yoshioka Tsuneo - (QWF00133@niftyserve.or.jp/tsuneo-y@is.aist-nara.ac.jp), - to support better zlib compatibility. - This code is not _officially_ part of libbzip2 (yet); - I haven't tested it, documented it, or considered the - threading-safeness of it. - If this code breaks, please contact both Yoshioka and me. ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -/*-- - return version like "0.9.0c". ---*/ -const char * BZ_API(BZ2_bzlibVersion)(void) -{ - return BZ_VERSION; -} - - -#ifndef BZ_NO_STDIO -/*---------------------------------------------------*/ - -#if defined(_WIN32) || defined(OS2) || defined(MSDOS) -# include -# include -# define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY) -#else -# define SET_BINARY_MODE(file) -#endif -static -BZFILE * bzopen_or_bzdopen - ( const char *path, /* no use when bzdopen */ - int fd, /* no use when bzdopen */ - const char *mode, - int open_mode) /* bzopen: 0, bzdopen:1 */ -{ - int bzerr; - char unused[BZ_MAX_UNUSED]; - int blockSize100k = 9; - int writing = 0; - char mode2[10] = ""; - FILE *fp = NULL; - BZFILE *bzfp = NULL; - int verbosity = 0; - int workFactor = 30; - int smallMode = 0; - int nUnused = 0; - - if (mode == NULL) return NULL; - while (*mode) { - switch (*mode) { - case 'r': - writing = 0; break; - case 'w': - writing = 1; break; - case 's': - smallMode = 1; break; - default: - if (isdigit((int)(*mode))) { - blockSize100k = *mode-BZ_HDR_0; - } - } - mode++; - } - strcat(mode2, writing ? "w" : "r" ); - strcat(mode2,"b"); /* binary mode */ - - if (open_mode==0) { - if (path==NULL || strcmp(path,"")==0) { - fp = (writing ? stdout : stdin); - SET_BINARY_MODE(fp); - } else { - fp = fopen(path,mode2); - } - } else { -#ifdef BZ_STRICT_ANSI - fp = NULL; -#else - fp = fdopen(fd,mode2); -#endif - } - if (fp == NULL) return NULL; - - if (writing) { - /* Guard against total chaos and anarchy -- JRS */ - if (blockSize100k < 1) blockSize100k = 1; - if (blockSize100k > 9) blockSize100k = 9; - bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k, - verbosity,workFactor); - } else { - bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode, - unused,nUnused); - } - if (bzfp == NULL) { - if (fp != stdin && fp != stdout) fclose(fp); - return NULL; - } - return bzfp; -} - - -/*---------------------------------------------------*/ -/*-- - open file for read or write. - ex) bzopen("file","w9") - case path="" or NULL => use stdin or stdout. ---*/ -BZFILE * BZ_API(BZ2_bzopen) - ( const char *path, - const char *mode ) -{ - return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0); -} - - -/*---------------------------------------------------*/ -BZFILE * BZ_API(BZ2_bzdopen) - ( int fd, - const char *mode ) -{ - return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1); -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len ) -{ - int bzerr, nread; - if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0; - nread = BZ2_bzRead(&bzerr,b,buf,len); - if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) { - return nread; - } else { - return -1; - } -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len ) -{ - int bzerr; - - BZ2_bzWrite(&bzerr,b,buf,len); - if(bzerr == BZ_OK){ - return len; - }else{ - return -1; - } -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzflush) (BZFILE *b) -{ - /* do nothing now... */ - return 0; -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzclose) (BZFILE* b) -{ - int bzerr; - FILE *fp = ((bzFile *)b)->handle; - - if (b==NULL) {return;} - if(((bzFile*)b)->writing){ - BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); - if(bzerr != BZ_OK){ - BZ2_bzWriteClose(NULL,b,1,NULL,NULL); - } - }else{ - BZ2_bzReadClose(&bzerr,b); - } - if(fp!=stdin && fp!=stdout){ - fclose(fp); - } -} - - -/*---------------------------------------------------*/ -/*-- - return last error code ---*/ -static char *bzerrorstrings[] = { - "OK" - ,"SEQUENCE_ERROR" - ,"PARAM_ERROR" - ,"MEM_ERROR" - ,"DATA_ERROR" - ,"DATA_ERROR_MAGIC" - ,"IO_ERROR" - ,"UNEXPECTED_EOF" - ,"OUTBUFF_FULL" - ,"CONFIG_ERROR" - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ -}; - - -const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum) -{ - int err = ((bzFile *)b)->lastErr; - - if(err>0) err = 0; - *errnum = err; - return bzerrorstrings[err*-1]; -} -#endif - - -/*-------------------------------------------------------------*/ -/*--- end bzlib.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Library top-level functions. ---*/ +/*--- bzlib.c ---*/ +/*-------------------------------------------------------------*/ + +/*-- + This file is a part of bzip2 and/or libbzip2, a program and + library for lossless, block-sorting data compression. + + Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Julian Seward, Cambridge, UK. + jseward@bzip.org + bzip2/libbzip2 version 1.0 of 21 March 2000 + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the manual. +--*/ + +/*-- + CHANGES + ~~~~~~~ + 0.9.0 -- original version. + + 0.9.0a/b -- no changes in this file. + + 0.9.0c + * made zero-length BZ_FLUSH work correctly in bzCompress(). + * fixed bzWrite/bzRead to ignore zero-length requests. + * fixed bzread to correctly handle read requests after EOF. + * wrong parameter order in call to bzDecompressInit in + bzBuffToBuffDecompress. Fixed. +--*/ + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Compression stuff ---*/ +/*---------------------------------------------------*/ + + +/*---------------------------------------------------*/ +#ifndef BZ_NO_STDIO +void BZ2_bz__AssertH__fail ( int errcode ) +{ + fprintf(stderr, + "\n\nbzip2/libbzip2: internal error number %d.\n" + "This is a bug in bzip2/libbzip2, %s.\n" + "Please report it to me at: jseward@bzip.org. If this happened\n" + "when you were using some program which uses libbzip2 as a\n" + "component, you should also report this bug to the author(s)\n" + "of that program. Please make an effort to report this bug;\n" + "timely and accurate bug reports eventually lead to higher\n" + "quality software. Thanks. Julian Seward, 15 February 2005.\n\n", + errcode, + BZ2_bzlibVersion() + ); + + if (errcode == 1007) { + fprintf(stderr, + "\n*** A special note about internal error number 1007 ***\n" + "\n" + "Experience suggests that a common cause of i.e. 1007\n" + "is unreliable memory or other hardware. The 1007 assertion\n" + "just happens to cross-check the results of huge numbers of\n" + "memory reads/writes, and so acts (unintendedly) as a stress\n" + "test of your memory system.\n" + "\n" + "I suggest the following: try compressing the file again,\n" + "possibly monitoring progress in detail with the -vv flag.\n" + "\n" + "* If the error cannot be reproduced, and/or happens at different\n" + " points in compression, you may have a flaky memory system.\n" + " Try a memory-test program. I have used Memtest86\n" + " (www.memtest86.com). At the time of writing it is free (GPLd).\n" + " Memtest86 tests memory much more thorougly than your BIOSs\n" + " power-on test, and may find failures that the BIOS doesn't.\n" + "\n" + "* If the error can be repeatably reproduced, this is a bug in\n" + " bzip2, and I would very much like to hear about it. Please\n" + " let me know, and, ideally, save a copy of the file causing the\n" + " problem -- without which I will be unable to investigate it.\n" + "\n" + ); + } + + exit(3); +} +#endif + + +/*---------------------------------------------------*/ +static +int bz_config_ok ( void ) +{ + if (sizeof(int) != 4) return 0; + if (sizeof(short) != 2) return 0; + if (sizeof(char) != 1) return 0; + return 1; +} + + +/*---------------------------------------------------*/ +static +void* default_bzalloc ( void* opaque, Int32 items, Int32 size ) +{ + void* v = malloc ( items * size ); + return v; +} + +static +void default_bzfree ( void* opaque, void* addr ) +{ + if (addr != NULL) free ( addr ); +} + + +/*---------------------------------------------------*/ +static +void prepare_new_block ( EState* s ) +{ + Int32 i; + s->nblock = 0; + s->numZ = 0; + s->state_out_pos = 0; + BZ_INITIALISE_CRC ( s->blockCRC ); + for (i = 0; i < 256; i++) s->inUse[i] = False; + s->blockNo++; +} + + +/*---------------------------------------------------*/ +static +void init_RL ( EState* s ) +{ + s->state_in_ch = 256; + s->state_in_len = 0; +} + + +static +Bool isempty_RL ( EState* s ) +{ + if (s->state_in_ch < 256 && s->state_in_len > 0) + return False; else + return True; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressInit) + ( bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 n; + EState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL || + blockSize100k < 1 || blockSize100k > 9 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(EState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + + s->arr1 = NULL; + s->arr2 = NULL; + s->ftab = NULL; + + n = 100000 * blockSize100k; + s->arr1 = BZALLOC( n * sizeof(UInt32) ); + s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) ); + s->ftab = BZALLOC( 65537 * sizeof(UInt32) ); + + if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) { + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + if (s != NULL) BZFREE(s); + return BZ_MEM_ERROR; + } + + s->blockNo = 0; + s->state = BZ_S_INPUT; + s->mode = BZ_M_RUNNING; + s->combinedCRC = 0; + s->blockSize100k = blockSize100k; + s->nblockMAX = 100000 * blockSize100k - 19; + s->verbosity = verbosity; + s->workFactor = workFactor; + + s->block = (UChar*)s->arr2; + s->mtfv = (UInt16*)s->arr1; + s->zbits = NULL; + s->ptr = (UInt32*)s->arr1; + + strm->state = s; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + init_RL ( s ); + prepare_new_block ( s ); + return BZ_OK; +} + + +/*---------------------------------------------------*/ +static +void add_pair_to_block ( EState* s ) +{ + Int32 i; + UChar ch = (UChar)(s->state_in_ch); + for (i = 0; i < s->state_in_len; i++) { + BZ_UPDATE_CRC( s->blockCRC, ch ); + } + s->inUse[s->state_in_ch] = True; + switch (s->state_in_len) { + case 1: + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 2: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 3: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + default: + s->inUse[s->state_in_len-4] = True; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = ((UChar)(s->state_in_len-4)); + s->nblock++; + break; + } +} + + +/*---------------------------------------------------*/ +static +void flush_RL ( EState* s ) +{ + if (s->state_in_ch < 256) add_pair_to_block ( s ); + init_RL ( s ); +} + + +/*---------------------------------------------------*/ +#define ADD_CHAR_TO_BLOCK(zs,zchh0) \ +{ \ + UInt32 zchh = (UInt32)(zchh0); \ + /*-- fast track the common case --*/ \ + if (zchh != zs->state_in_ch && \ + zs->state_in_len == 1) { \ + UChar ch = (UChar)(zs->state_in_ch); \ + BZ_UPDATE_CRC( zs->blockCRC, ch ); \ + zs->inUse[zs->state_in_ch] = True; \ + zs->block[zs->nblock] = (UChar)ch; \ + zs->nblock++; \ + zs->state_in_ch = zchh; \ + } \ + else \ + /*-- general, uncommon cases --*/ \ + if (zchh != zs->state_in_ch || \ + zs->state_in_len == 255) { \ + if (zs->state_in_ch < 256) \ + add_pair_to_block ( zs ); \ + zs->state_in_ch = zchh; \ + zs->state_in_len = 1; \ + } else { \ + zs->state_in_len++; \ + } \ +} + + +/*---------------------------------------------------*/ +static +Bool copy_input_until_stop ( EState* s ) +{ + Bool progress_in = False; + + if (s->mode == BZ_M_RUNNING) { + + /*-- fast track the common case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + } + + } else { + + /*-- general, uncommon case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + /*-- flush/finish end? --*/ + if (s->avail_in_expect == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + s->avail_in_expect--; + } + } + return progress_in; +} + + +/*---------------------------------------------------*/ +static +Bool copy_output_until_stop ( EState* s ) +{ + Bool progress_out = False; + + while (True) { + + /*-- no output space? --*/ + if (s->strm->avail_out == 0) break; + + /*-- block done? --*/ + if (s->state_out_pos >= s->numZ) break; + + progress_out = True; + *(s->strm->next_out) = s->zbits[s->state_out_pos]; + s->state_out_pos++; + s->strm->avail_out--; + s->strm->next_out++; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + return progress_out; +} + + +/*---------------------------------------------------*/ +static +Bool handle_compress ( bz_stream* strm ) +{ + Bool progress_in = False; + Bool progress_out = False; + EState* s = strm->state; + + while (True) { + + if (s->state == BZ_S_OUTPUT) { + progress_out |= copy_output_until_stop ( s ); + if (s->state_out_pos < s->numZ) break; + if (s->mode == BZ_M_FINISHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + prepare_new_block ( s ); + s->state = BZ_S_INPUT; + if (s->mode == BZ_M_FLUSHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + } + + if (s->state == BZ_S_INPUT) { + progress_in |= copy_input_until_stop ( s ); + if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { + flush_RL ( s ); + BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) ); + s->state = BZ_S_OUTPUT; + } + else + if (s->nblock >= s->nblockMAX) { + BZ2_compressBlock ( s, False ); + s->state = BZ_S_OUTPUT; + } + else + if (s->strm->avail_in == 0) { + break; + } + } + + } + + return progress_in || progress_out; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action ) +{ + Bool progress; + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + preswitch: + switch (s->mode) { + + case BZ_M_IDLE: + return BZ_SEQUENCE_ERROR; + + case BZ_M_RUNNING: + if (action == BZ_RUN) { + progress = handle_compress ( strm ); + return progress ? BZ_RUN_OK : BZ_PARAM_ERROR; + } + else + if (action == BZ_FLUSH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FLUSHING; + goto preswitch; + } + else + if (action == BZ_FINISH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FINISHING; + goto preswitch; + } + else + return BZ_PARAM_ERROR; + + case BZ_M_FLUSHING: + if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FLUSH_OK; + s->mode = BZ_M_RUNNING; + return BZ_RUN_OK; + + case BZ_M_FINISHING: + if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (!progress) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FINISH_OK; + s->mode = BZ_M_IDLE; + return BZ_STREAM_END; + } + return BZ_OK; /*--not reached--*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm ) +{ + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + BZFREE(strm->state); + + strm->state = NULL; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/*--- Decompression stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressInit) + ( bz_stream* strm, + int verbosity, + int small ) +{ + DState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL) return BZ_PARAM_ERROR; + if (small != 0 && small != 1) return BZ_PARAM_ERROR; + if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; + + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(DState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + strm->state = s; + s->state = BZ_X_MAGIC_1; + s->bsLive = 0; + s->bsBuff = 0; + s->calculatedCombinedCRC = 0; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + s->smallDecompress = (Bool)small; + s->ll4 = NULL; + s->ll16 = NULL; + s->tt = NULL; + s->currBlockNo = 0; + s->verbosity = verbosity; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_FAST ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + /* restore */ + UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; + UChar c_state_out_ch = s->state_out_ch; + Int32 c_state_out_len = s->state_out_len; + Int32 c_nblock_used = s->nblock_used; + Int32 c_k0 = s->k0; + UInt32* c_tt = s->tt; + UInt32 c_tPos = s->tPos; + char* cs_next_out = s->strm->next_out; + unsigned int cs_avail_out = s->strm->avail_out; + /* end restore */ + + UInt32 avail_out_INIT = cs_avail_out; + Int32 s_save_nblockPP = s->save_nblock+1; + unsigned int total_out_lo32_old; + + while (True) { + + /* try to finish existing run */ + if (c_state_out_len > 0) { + while (True) { + if (cs_avail_out == 0) goto return_notr; + if (c_state_out_len == 1) break; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + c_state_out_len--; + cs_next_out++; + cs_avail_out--; + } + s_state_out_len_eq_one: + { + if (cs_avail_out == 0) { + c_state_out_len = 1; goto return_notr; + }; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + cs_next_out++; + cs_avail_out--; + } + } + /* Only caused by corrupt data stream? */ + if (c_nblock_used > s_save_nblockPP) + return True; + + /* can a new run be started? */ + if (c_nblock_used == s_save_nblockPP) { + c_state_out_len = 0; goto return_notr; + }; + c_state_out_ch = c_k0; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (k1 != c_k0) { + c_k0 = k1; goto s_state_out_len_eq_one; + }; + if (c_nblock_used == s_save_nblockPP) + goto s_state_out_len_eq_one; + + c_state_out_len = 2; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + c_state_out_len = 3; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + BZ_GET_FAST_C(k1); c_nblock_used++; + c_state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST_C(c_k0); c_nblock_used++; + } + + return_notr: + total_out_lo32_old = s->strm->total_out_lo32; + s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); + if (s->strm->total_out_lo32 < total_out_lo32_old) + s->strm->total_out_hi32++; + + /* save */ + s->calculatedBlockCRC = c_calculatedBlockCRC; + s->state_out_ch = c_state_out_ch; + s->state_out_len = c_state_out_len; + s->nblock_used = c_nblock_used; + s->k0 = c_k0; + s->tt = c_tt; + s->tPos = c_tPos; + s->strm->next_out = cs_next_out; + s->strm->avail_out = cs_avail_out; + /* end save */ + } + return False; +} + + + +/*---------------------------------------------------*/ +__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) +{ + Int32 nb, na, mid; + nb = 0; + na = 256; + do { + mid = (nb + na) >> 1; + if (indx >= cftab[mid]) nb = mid; else na = mid; + } + while (na - nb != 1); + return nb; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_SMALL ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) +{ + Bool corrupt; + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + while (True) { + if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; + if (s->state == BZ_X_OUTPUT) { + if (s->smallDecompress) + corrupt = unRLE_obuf_to_output_SMALL ( s ); else + corrupt = unRLE_obuf_to_output_FAST ( s ); + if (corrupt) return BZ_DATA_ERROR; + if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { + BZ_FINALISE_CRC ( s->calculatedBlockCRC ); + if (s->verbosity >= 3) + VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, + s->calculatedBlockCRC ); + if (s->verbosity >= 2) VPrintf0 ( "]" ); + if (s->calculatedBlockCRC != s->storedBlockCRC) + return BZ_DATA_ERROR; + s->calculatedCombinedCRC + = (s->calculatedCombinedCRC << 1) | + (s->calculatedCombinedCRC >> 31); + s->calculatedCombinedCRC ^= s->calculatedBlockCRC; + s->state = BZ_X_BLKHDR_1; + } else { + return BZ_OK; + } + } + if (s->state >= BZ_X_MAGIC_1) { + Int32 r = BZ2_decompress ( s ); + if (r == BZ_STREAM_END) { + if (s->verbosity >= 3) + VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x", + s->storedCombinedCRC, s->calculatedCombinedCRC ); + if (s->calculatedCombinedCRC != s->storedCombinedCRC) + return BZ_DATA_ERROR; + return r; + } + if (s->state != BZ_X_OUTPUT) return r; + } + } + + AssertH ( 0, 6001 ); + + return 0; /*NOTREACHED*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) +{ + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->tt != NULL) BZFREE(s->tt); + if (s->ll16 != NULL) BZFREE(s->ll16); + if (s->ll4 != NULL) BZFREE(s->ll4); + + BZFREE(strm->state); + strm->state = NULL; + + return BZ_OK; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ +/*--- File I/O stuff ---*/ +/*---------------------------------------------------*/ + +#define BZ_SETERR(eee) \ +{ \ + if (bzerror != NULL) *bzerror = eee; \ + if (bzf != NULL) bzf->lastErr = eee; \ +} + +typedef + struct { + FILE* handle; + Char buf[BZ_MAX_UNUSED]; + Int32 bufN; + Bool writing; + bz_stream strm; + Int32 lastErr; + Bool initialisedOk; + } + bzFile; + + +/*---------------------------------------------*/ +static Bool myfeof ( FILE* f ) +{ + Int32 c = fgetc ( f ); + if (c == EOF) return True; + ungetc ( c, f ); + return False; +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzWriteOpen) + ( int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 ret; + bzFile* bzf = NULL; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (blockSize100k < 1 || blockSize100k > 9) || + (workFactor < 0 || workFactor > 250) || + (verbosity < 0 || verbosity > 4)) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + bzf->initialisedOk = False; + bzf->bufN = 0; + bzf->handle = f; + bzf->writing = True; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + if (workFactor == 0) workFactor = 30; + ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = 0; + bzf->initialisedOk = True; + return bzf; +} + + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWrite) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return; }; + + bzf->strm.avail_in = len; + bzf->strm.next_in = buf; + + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN ); + if (ret != BZ_RUN_OK) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (bzf->strm.avail_in == 0) + { BZ_SETERR(BZ_OK); return; }; + } +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWriteClose) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out ) +{ + BZ2_bzWriteClose64 ( bzerror, b, abandon, + nbytes_in, NULL, nbytes_out, NULL ); +} + + +void BZ_API(BZ2_bzWriteClose64) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0; + if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0; + if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0; + if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0; + + if ((!abandon) && bzf->lastErr == BZ_OK) { + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH ); + if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (ret == BZ_STREAM_END) break; + } + } + + if ( !abandon && !ferror ( bzf->handle ) ) { + fflush ( bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (nbytes_in_lo32 != NULL) + *nbytes_in_lo32 = bzf->strm.total_in_lo32; + if (nbytes_in_hi32 != NULL) + *nbytes_in_hi32 = bzf->strm.total_in_hi32; + if (nbytes_out_lo32 != NULL) + *nbytes_out_lo32 = bzf->strm.total_out_lo32; + if (nbytes_out_hi32 != NULL) + *nbytes_out_hi32 = bzf->strm.total_out_hi32; + + BZ_SETERR(BZ_OK); + BZ2_bzCompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzReadOpen) + ( int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused ) +{ + bzFile* bzf = NULL; + int ret; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (small != 0 && small != 1) || + (verbosity < 0 || verbosity > 4) || + (unused == NULL && nUnused != 0) || + (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + + bzf->initialisedOk = False; + bzf->handle = f; + bzf->bufN = 0; + bzf->writing = False; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + while (nUnused > 0) { + bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; + unused = ((void*)( 1 + ((UChar*)(unused)) )); + nUnused--; + } + + ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + + bzf->initialisedOk = True; + return bzf; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) +{ + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + + if (bzf->initialisedOk) + (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzRead) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return 0; }; + + bzf->strm.avail_out = len; + bzf->strm.next_out = buf; + + while (True) { + + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + + if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { + n = fread ( bzf->buf, sizeof(UChar), + BZ_MAX_UNUSED, bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + bzf->bufN = n; + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + } + + ret = BZ2_bzDecompress ( &(bzf->strm) ); + + if (ret != BZ_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return 0; }; + + if (ret == BZ_OK && myfeof(bzf->handle) && + bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) + { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; + + if (ret == BZ_STREAM_END) + { BZ_SETERR(BZ_STREAM_END); + return len - bzf->strm.avail_out; }; + if (bzf->strm.avail_out == 0) + { BZ_SETERR(BZ_OK); return len; }; + + } + + return 0; /*not reached*/ +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadGetUnused) + ( int* bzerror, + BZFILE* b, + void** unused, + int* nUnused ) +{ + bzFile* bzf = (bzFile*)b; + if (bzf == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (bzf->lastErr != BZ_STREAM_END) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (unused == NULL || nUnused == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + + BZ_SETERR(BZ_OK); + *nUnused = bzf->strm.avail_in; + *unused = bzf->strm.next_in; +} +#endif + + +/*---------------------------------------------------*/ +/*--- Misc convenience stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffCompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + blockSize100k < 1 || blockSize100k > 9 || + verbosity < 0 || verbosity > 4 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzCompressInit ( &strm, blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzCompress ( &strm, BZ_FINISH ); + if (ret == BZ_FINISH_OK) goto output_overflow; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzCompressEnd ( &strm ); + return BZ_OK; + + output_overflow: + BZ2_bzCompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + + errhandler: + BZ2_bzCompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffDecompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + (small != 0 && small != 1) || + verbosity < 0 || verbosity > 4) + return BZ_PARAM_ERROR; + + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzDecompressInit ( &strm, verbosity, small ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzDecompress ( &strm ); + if (ret == BZ_OK) goto output_overflow_or_eof; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzDecompressEnd ( &strm ); + return BZ_OK; + + output_overflow_or_eof: + if (strm.avail_out > 0) { + BZ2_bzDecompressEnd ( &strm ); + return BZ_UNEXPECTED_EOF; + } else { + BZ2_bzDecompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + }; + + errhandler: + BZ2_bzDecompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +/*-- + Code contributed by Yoshioka Tsuneo + (QWF00133@niftyserve.or.jp/tsuneo-y@is.aist-nara.ac.jp), + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +/*-- + return version like "0.9.0c". +--*/ +const char * BZ_API(BZ2_bzlibVersion)(void) +{ + return BZ_VERSION; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ + +#if defined(_WIN32) || defined(OS2) || defined(MSDOS) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif +static +BZFILE * bzopen_or_bzdopen + ( const char *path, /* no use when bzdopen */ + int fd, /* no use when bzdopen */ + const char *mode, + int open_mode) /* bzopen: 0, bzdopen:1 */ +{ + int bzerr; + char unused[BZ_MAX_UNUSED]; + int blockSize100k = 9; + int writing = 0; + char mode2[10] = ""; + FILE *fp = NULL; + BZFILE *bzfp = NULL; + int verbosity = 0; + int workFactor = 30; + int smallMode = 0; + int nUnused = 0; + + if (mode == NULL) return NULL; + while (*mode) { + switch (*mode) { + case 'r': + writing = 0; break; + case 'w': + writing = 1; break; + case 's': + smallMode = 1; break; + default: + if (isdigit((int)(*mode))) { + blockSize100k = *mode-BZ_HDR_0; + } + } + mode++; + } + strcat(mode2, writing ? "w" : "r" ); + strcat(mode2,"b"); /* binary mode */ + + if (open_mode==0) { + if (path==NULL || strcmp(path,"")==0) { + fp = (writing ? stdout : stdin); + SET_BINARY_MODE(fp); + } else { + fp = fopen(path,mode2); + } + } else { +#ifdef BZ_STRICT_ANSI + fp = NULL; +#else + fp = fdopen(fd,mode2); +#endif + } + if (fp == NULL) return NULL; + + if (writing) { + /* Guard against total chaos and anarchy -- JRS */ + if (blockSize100k < 1) blockSize100k = 1; + if (blockSize100k > 9) blockSize100k = 9; + bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k, + verbosity,workFactor); + } else { + bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode, + unused,nUnused); + } + if (bzfp == NULL) { + if (fp != stdin && fp != stdout) fclose(fp); + return NULL; + } + return bzfp; +} + + +/*---------------------------------------------------*/ +/*-- + open file for read or write. + ex) bzopen("file","w9") + case path="" or NULL => use stdin or stdout. +--*/ +BZFILE * BZ_API(BZ2_bzopen) + ( const char *path, + const char *mode ) +{ + return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0); +} + + +/*---------------------------------------------------*/ +BZFILE * BZ_API(BZ2_bzdopen) + ( int fd, + const char *mode ) +{ + return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len ) +{ + int bzerr, nread; + if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0; + nread = BZ2_bzRead(&bzerr,b,buf,len); + if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) { + return nread; + } else { + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len ) +{ + int bzerr; + + BZ2_bzWrite(&bzerr,b,buf,len); + if(bzerr == BZ_OK){ + return len; + }else{ + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzflush) (BZFILE *b) +{ + /* do nothing now... */ + return 0; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzclose) (BZFILE* b) +{ + int bzerr; + FILE *fp = ((bzFile *)b)->handle; + + if (b==NULL) {return;} + if(((bzFile*)b)->writing){ + BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); + if(bzerr != BZ_OK){ + BZ2_bzWriteClose(NULL,b,1,NULL,NULL); + } + }else{ + BZ2_bzReadClose(&bzerr,b); + } + if(fp!=stdin && fp!=stdout){ + fclose(fp); + } +} + + +/*---------------------------------------------------*/ +/*-- + return last error code +--*/ +static char *bzerrorstrings[] = { + "OK" + ,"SEQUENCE_ERROR" + ,"PARAM_ERROR" + ,"MEM_ERROR" + ,"DATA_ERROR" + ,"DATA_ERROR_MAGIC" + ,"IO_ERROR" + ,"UNEXPECTED_EOF" + ,"OUTBUFF_FULL" + ,"CONFIG_ERROR" + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ +}; + + +const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum) +{ + int err = ((bzFile *)b)->lastErr; + + if(err>0) err = 0; + *errnum = err; + return bzerrorstrings[err*-1]; +} +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDisoEFP/src/bzip2/bzlib.h b/plugins/CDVDisoEFP/src/bzip2/bzlib.h index d3cc8cfde1..323724394a 100644 --- a/plugins/CDVDisoEFP/src/bzip2/bzlib.h +++ b/plugins/CDVDisoEFP/src/bzip2/bzlib.h @@ -1,323 +1,323 @@ - -/*-------------------------------------------------------------*/ -/*--- Public header file for the library. ---*/ -/*--- bzlib.h ---*/ -/*-------------------------------------------------------------*/ - -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. - - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ - - -#ifndef _BZLIB_H -#define _BZLIB_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define BZ_RUN 0 -#define BZ_FLUSH 1 -#define BZ_FINISH 2 - -#define BZ_OK 0 -#define BZ_RUN_OK 1 -#define BZ_FLUSH_OK 2 -#define BZ_FINISH_OK 3 -#define BZ_STREAM_END 4 -#define BZ_SEQUENCE_ERROR (-1) -#define BZ_PARAM_ERROR (-2) -#define BZ_MEM_ERROR (-3) -#define BZ_DATA_ERROR (-4) -#define BZ_DATA_ERROR_MAGIC (-5) -#define BZ_IO_ERROR (-6) -#define BZ_UNEXPECTED_EOF (-7) -#define BZ_OUTBUFF_FULL (-8) -#define BZ_CONFIG_ERROR (-9) - -typedef - struct { - char *next_in; - unsigned int avail_in; - unsigned int total_in_lo32; - unsigned int total_in_hi32; - - char *next_out; - unsigned int avail_out; - unsigned int total_out_lo32; - unsigned int total_out_hi32; - - void *state; - - void *(*bzalloc)(void *,int,int); - void (*bzfree)(void *,void *); - void *opaque; - } - bz_stream; - - -#ifndef BZ_IMPORT -#define BZ_EXPORT -#endif - -#ifndef BZ_NO_STDIO -/* Need a definitition for FILE */ -#include -#endif - -#ifdef _WIN32 -# include -# ifdef small - /* windows.h define small to char */ -# undef small -# endif -# ifdef BZ_EXPORT -# define BZ_API(func) WINAPI func -# define BZ_EXTERN extern -# else - /* import windows dll dynamically */ -# define BZ_API(func) (WINAPI * func) -# define BZ_EXTERN -# endif -#else -# define BZ_API(func) func -# define BZ_EXTERN extern -#endif - - -/*-- Core (low-level) library functions --*/ - -BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( - bz_stream* strm, - int blockSize100k, - int verbosity, - int workFactor - ); - -BZ_EXTERN int BZ_API(BZ2_bzCompress) ( - bz_stream* strm, - int action - ); - -BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( - bz_stream* strm - ); - -BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( - bz_stream *strm, - int verbosity, - int small - ); - -BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( - bz_stream* strm - ); - -BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( - bz_stream *strm - ); - - - -/*-- High(er) level library functions --*/ - -#ifndef BZ_NO_STDIO -#define BZ_MAX_UNUSED 5000 - -typedef void BZFILE; - -BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( - int* bzerror, - FILE* f, - int verbosity, - int small, - void* unused, - int nUnused - ); - -BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( - int* bzerror, - BZFILE* b - ); - -BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( - int* bzerror, - BZFILE* b, - void** unused, - int* nUnused - ); - -BZ_EXTERN int BZ_API(BZ2_bzRead) ( - int* bzerror, - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( - int* bzerror, - FILE* f, - int blockSize100k, - int verbosity, - int workFactor - ); - -BZ_EXTERN void BZ_API(BZ2_bzWrite) ( - int* bzerror, - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( - int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in, - unsigned int* nbytes_out - ); - -BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( - int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in_lo32, - unsigned int* nbytes_in_hi32, - unsigned int* nbytes_out_lo32, - unsigned int* nbytes_out_hi32 - ); -#endif - - -/*-- Utility functions --*/ - -BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( - char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int blockSize100k, - int verbosity, - int workFactor - ); - -BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( - char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int small, - int verbosity - ); - - -/*-- - Code contributed by Yoshioka Tsuneo - (QWF00133@niftyserve.or.jp/tsuneo-y@is.aist-nara.ac.jp), - to support better zlib compatibility. - This code is not _officially_ part of libbzip2 (yet); - I haven't tested it, documented it, or considered the - threading-safeness of it. - If this code breaks, please contact both Yoshioka and me. ---*/ - -BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) ( - void - ); - -#ifndef BZ_NO_STDIO -BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) ( - const char *path, - const char *mode - ); - -BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) ( - int fd, - const char *mode - ); - -BZ_EXTERN int BZ_API(BZ2_bzread) ( - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN int BZ_API(BZ2_bzwrite) ( - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN int BZ_API(BZ2_bzflush) ( - BZFILE* b - ); - -BZ_EXTERN void BZ_API(BZ2_bzclose) ( - BZFILE* b - ); - -BZ_EXTERN const char * BZ_API(BZ2_bzerror) ( - BZFILE *b, - int *errnum - ); -#endif - -#ifdef __cplusplus -} -#endif - -#endif - -/*-------------------------------------------------------------*/ -/*--- end bzlib.h ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Public header file for the library. ---*/ +/*--- bzlib.h ---*/ +/*-------------------------------------------------------------*/ + +/*-- + This file is a part of bzip2 and/or libbzip2, a program and + library for lossless, block-sorting data compression. + + Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Julian Seward, Cambridge, UK. + jseward@bzip.org + bzip2/libbzip2 version 1.0 of 21 March 2000 + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the manual. +--*/ + + +#ifndef _BZLIB_H +#define _BZLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define BZ_RUN 0 +#define BZ_FLUSH 1 +#define BZ_FINISH 2 + +#define BZ_OK 0 +#define BZ_RUN_OK 1 +#define BZ_FLUSH_OK 2 +#define BZ_FINISH_OK 3 +#define BZ_STREAM_END 4 +#define BZ_SEQUENCE_ERROR (-1) +#define BZ_PARAM_ERROR (-2) +#define BZ_MEM_ERROR (-3) +#define BZ_DATA_ERROR (-4) +#define BZ_DATA_ERROR_MAGIC (-5) +#define BZ_IO_ERROR (-6) +#define BZ_UNEXPECTED_EOF (-7) +#define BZ_OUTBUFF_FULL (-8) +#define BZ_CONFIG_ERROR (-9) + +typedef + struct { + char *next_in; + unsigned int avail_in; + unsigned int total_in_lo32; + unsigned int total_in_hi32; + + char *next_out; + unsigned int avail_out; + unsigned int total_out_lo32; + unsigned int total_out_hi32; + + void *state; + + void *(*bzalloc)(void *,int,int); + void (*bzfree)(void *,void *); + void *opaque; + } + bz_stream; + + +#ifndef BZ_IMPORT +#define BZ_EXPORT +#endif + +#ifndef BZ_NO_STDIO +/* Need a definitition for FILE */ +#include +#endif + +#ifdef _WIN32 +# include +# ifdef small + /* windows.h define small to char */ +# undef small +# endif +# ifdef BZ_EXPORT +# define BZ_API(func) WINAPI func +# define BZ_EXTERN extern +# else + /* import windows dll dynamically */ +# define BZ_API(func) (WINAPI * func) +# define BZ_EXTERN +# endif +#else +# define BZ_API(func) func +# define BZ_EXTERN extern +#endif + + +/*-- Core (low-level) library functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( + bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompress) ( + bz_stream* strm, + int action + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( + bz_stream *strm, + int verbosity, + int small + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( + bz_stream *strm + ); + + + +/*-- High(er) level library functions --*/ + +#ifndef BZ_NO_STDIO +#define BZ_MAX_UNUSED 5000 + +typedef void BZFILE; + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( + int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( + int* bzerror, + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( + int* bzerror, + BZFILE* b, + void** unused, + int* nUnused + ); + +BZ_EXTERN int BZ_API(BZ2_bzRead) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( + int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN void BZ_API(BZ2_bzWrite) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 + ); +#endif + + +/*-- Utility functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity + ); + + +/*-- + Code contributed by Yoshioka Tsuneo + (QWF00133@niftyserve.or.jp/tsuneo-y@is.aist-nara.ac.jp), + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ + +BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) ( + void + ); + +#ifndef BZ_NO_STDIO +BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) ( + const char *path, + const char *mode + ); + +BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) ( + int fd, + const char *mode + ); + +BZ_EXTERN int BZ_API(BZ2_bzread) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzwrite) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzflush) ( + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzclose) ( + BZFILE* b + ); + +BZ_EXTERN const char * BZ_API(BZ2_bzerror) ( + BZFILE *b, + int *errnum + ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +/*-------------------------------------------------------------*/ +/*--- end bzlib.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDisoEFP/src/bzip2/bzlib_private.h b/plugins/CDVDisoEFP/src/bzip2/bzlib_private.h index 0bc1bfe7cb..ca76fe62b3 100644 --- a/plugins/CDVDisoEFP/src/bzip2/bzlib_private.h +++ b/plugins/CDVDisoEFP/src/bzip2/bzlib_private.h @@ -1,537 +1,537 @@ - -/*-------------------------------------------------------------*/ -/*--- Private header file for the library. ---*/ -/*--- bzlib_private.h ---*/ -/*-------------------------------------------------------------*/ - -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. - - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ - - -#ifndef _BZLIB_PRIVATE_H -#define _BZLIB_PRIVATE_H - -#include - -#ifndef BZ_NO_STDIO -#include -#include -#include -#endif - -#include "bzlib.h" - - - -/*-- General stuff. --*/ - -#define BZ_VERSION "1.0.3, 15-Feb-2005" - -typedef char Char; -typedef unsigned char Bool; -typedef unsigned char UChar; -typedef int Int32; -typedef unsigned int UInt32; -typedef short Int16; -typedef unsigned short UInt16; - -#define True ((Bool)1) -#define False ((Bool)0) - -#ifndef __GNUC__ -#define __inline__ /* */ -#endif - -#ifndef BZ_NO_STDIO -extern void BZ2_bz__AssertH__fail ( int errcode ); -#define AssertH(cond,errcode) \ - { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); } -#if BZ_DEBUG -#define AssertD(cond,msg) \ - { if (!(cond)) { \ - fprintf ( stderr, \ - "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\ - exit(1); \ - }} -#else -#define AssertD(cond,msg) /* */ -#endif -#define VPrintf0(zf) \ - fprintf(stderr,zf) -#define VPrintf1(zf,za1) \ - fprintf(stderr,zf,za1) -#define VPrintf2(zf,za1,za2) \ - fprintf(stderr,zf,za1,za2) -#define VPrintf3(zf,za1,za2,za3) \ - fprintf(stderr,zf,za1,za2,za3) -#define VPrintf4(zf,za1,za2,za3,za4) \ - fprintf(stderr,zf,za1,za2,za3,za4) -#define VPrintf5(zf,za1,za2,za3,za4,za5) \ - fprintf(stderr,zf,za1,za2,za3,za4,za5) -#else -extern void bz_internal_error ( int errcode ); -#define AssertH(cond,errcode) \ - { if (!(cond)) bz_internal_error ( errcode ); } -#define AssertD(cond,msg) /* */ -#define VPrintf0(zf) /* */ -#define VPrintf1(zf,za1) /* */ -#define VPrintf2(zf,za1,za2) /* */ -#define VPrintf3(zf,za1,za2,za3) /* */ -#define VPrintf4(zf,za1,za2,za3,za4) /* */ -#define VPrintf5(zf,za1,za2,za3,za4,za5) /* */ -#endif - - -#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1) -#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp)) - - -/*-- Header bytes. --*/ - -#define BZ_HDR_B 0x42 /* 'B' */ -#define BZ_HDR_Z 0x5a /* 'Z' */ -#define BZ_HDR_h 0x68 /* 'h' */ -#define BZ_HDR_0 0x30 /* '0' */ - -/*-- Constants for the back end. --*/ - -#define BZ_MAX_ALPHA_SIZE 258 -#define BZ_MAX_CODE_LEN 23 - -#define BZ_RUNA 0 -#define BZ_RUNB 1 - -#define BZ_N_GROUPS 6 -#define BZ_G_SIZE 50 -#define BZ_N_ITERS 4 - -#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) - - - -/*-- Stuff for randomising repetitive blocks. --*/ - -extern Int32 BZ2_rNums[512]; - -#define BZ_RAND_DECLS \ - Int32 rNToGo; \ - Int32 rTPos \ - -#define BZ_RAND_INIT_MASK \ - s->rNToGo = 0; \ - s->rTPos = 0 \ - -#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0) - -#define BZ_RAND_UPD_MASK \ - if (s->rNToGo == 0) { \ - s->rNToGo = BZ2_rNums[s->rTPos]; \ - s->rTPos++; \ - if (s->rTPos == 512) s->rTPos = 0; \ - } \ - s->rNToGo--; - - - -/*-- Stuff for doing CRCs. --*/ - -extern UInt32 BZ2_crc32Table[256]; - -#define BZ_INITIALISE_CRC(crcVar) \ -{ \ - crcVar = 0xffffffffL; \ -} - -#define BZ_FINALISE_CRC(crcVar) \ -{ \ - crcVar = ~(crcVar); \ -} - -#define BZ_UPDATE_CRC(crcVar,cha) \ -{ \ - crcVar = (crcVar << 8) ^ \ - BZ2_crc32Table[(crcVar >> 24) ^ \ - ((UChar)cha)]; \ -} - - - -/*-- States and modes for compression. --*/ - -#define BZ_M_IDLE 1 -#define BZ_M_RUNNING 2 -#define BZ_M_FLUSHING 3 -#define BZ_M_FINISHING 4 - -#define BZ_S_OUTPUT 1 -#define BZ_S_INPUT 2 - -#define BZ_N_RADIX 2 -#define BZ_N_QSORT 12 -#define BZ_N_SHELL 18 -#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) - - - - -/*-- Structure holding all the compression-side stuff. --*/ - -typedef - struct { - /* pointer back to the struct bz_stream */ - bz_stream* strm; - - /* mode this stream is in, and whether inputting */ - /* or outputting data */ - Int32 mode; - Int32 state; - - /* remembers avail_in when flush/finish requested */ - UInt32 avail_in_expect; - - /* for doing the block sorting */ - UInt32* arr1; - UInt32* arr2; - UInt32* ftab; - Int32 origPtr; - - /* aliases for arr1 and arr2 */ - UInt32* ptr; - UChar* block; - UInt16* mtfv; - UChar* zbits; - - /* for deciding when to use the fallback sorting algorithm */ - Int32 workFactor; - - /* run-length-encoding of the input */ - UInt32 state_in_ch; - Int32 state_in_len; - BZ_RAND_DECLS; - - /* input and output limits and current posns */ - Int32 nblock; - Int32 nblockMAX; - Int32 numZ; - Int32 state_out_pos; - - /* map of bytes used in block */ - Int32 nInUse; - Bool inUse[256]; - UChar unseqToSeq[256]; - - /* the buffer for bit stream creation */ - UInt32 bsBuff; - Int32 bsLive; - - /* block and combined CRCs */ - UInt32 blockCRC; - UInt32 combinedCRC; - - /* misc administratium */ - Int32 verbosity; - Int32 blockNo; - Int32 blockSize100k; - - /* stuff for coding the MTF values */ - Int32 nMTF; - Int32 mtfFreq [BZ_MAX_ALPHA_SIZE]; - UChar selector [BZ_MAX_SELECTORS]; - UChar selectorMtf[BZ_MAX_SELECTORS]; - - UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - /* second dimension: only 3 needed; 4 makes index calculations faster */ - UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4]; - - } - EState; - - - -/*-- externs for compression. --*/ - -extern void -BZ2_blockSort ( EState* ); - -extern void -BZ2_compressBlock ( EState*, Bool ); - -extern void -BZ2_bsInitWrite ( EState* ); - -extern void -BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 ); - -extern void -BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 ); - - - -/*-- states for decompression. --*/ - -#define BZ_X_IDLE 1 -#define BZ_X_OUTPUT 2 - -#define BZ_X_MAGIC_1 10 -#define BZ_X_MAGIC_2 11 -#define BZ_X_MAGIC_3 12 -#define BZ_X_MAGIC_4 13 -#define BZ_X_BLKHDR_1 14 -#define BZ_X_BLKHDR_2 15 -#define BZ_X_BLKHDR_3 16 -#define BZ_X_BLKHDR_4 17 -#define BZ_X_BLKHDR_5 18 -#define BZ_X_BLKHDR_6 19 -#define BZ_X_BCRC_1 20 -#define BZ_X_BCRC_2 21 -#define BZ_X_BCRC_3 22 -#define BZ_X_BCRC_4 23 -#define BZ_X_RANDBIT 24 -#define BZ_X_ORIGPTR_1 25 -#define BZ_X_ORIGPTR_2 26 -#define BZ_X_ORIGPTR_3 27 -#define BZ_X_MAPPING_1 28 -#define BZ_X_MAPPING_2 29 -#define BZ_X_SELECTOR_1 30 -#define BZ_X_SELECTOR_2 31 -#define BZ_X_SELECTOR_3 32 -#define BZ_X_CODING_1 33 -#define BZ_X_CODING_2 34 -#define BZ_X_CODING_3 35 -#define BZ_X_MTF_1 36 -#define BZ_X_MTF_2 37 -#define BZ_X_MTF_3 38 -#define BZ_X_MTF_4 39 -#define BZ_X_MTF_5 40 -#define BZ_X_MTF_6 41 -#define BZ_X_ENDHDR_2 42 -#define BZ_X_ENDHDR_3 43 -#define BZ_X_ENDHDR_4 44 -#define BZ_X_ENDHDR_5 45 -#define BZ_X_ENDHDR_6 46 -#define BZ_X_CCRC_1 47 -#define BZ_X_CCRC_2 48 -#define BZ_X_CCRC_3 49 -#define BZ_X_CCRC_4 50 - - - -/*-- Constants for the fast MTF decoder. --*/ - -#define MTFA_SIZE 4096 -#define MTFL_SIZE 16 - - - -/*-- Structure holding all the decompression-side stuff. --*/ - -typedef - struct { - /* pointer back to the struct bz_stream */ - bz_stream* strm; - - /* state indicator for this stream */ - Int32 state; - - /* for doing the final run-length decoding */ - UChar state_out_ch; - Int32 state_out_len; - Bool blockRandomised; - BZ_RAND_DECLS; - - /* the buffer for bit stream reading */ - UInt32 bsBuff; - Int32 bsLive; - - /* misc administratium */ - Int32 blockSize100k; - Bool smallDecompress; - Int32 currBlockNo; - Int32 verbosity; - - /* for undoing the Burrows-Wheeler transform */ - Int32 origPtr; - UInt32 tPos; - Int32 k0; - Int32 unzftab[256]; - Int32 nblock_used; - Int32 cftab[257]; - Int32 cftabCopy[257]; - - /* for undoing the Burrows-Wheeler transform (FAST) */ - UInt32 *tt; - - /* for undoing the Burrows-Wheeler transform (SMALL) */ - UInt16 *ll16; - UChar *ll4; - - /* stored and calculated CRCs */ - UInt32 storedBlockCRC; - UInt32 storedCombinedCRC; - UInt32 calculatedBlockCRC; - UInt32 calculatedCombinedCRC; - - /* map of bytes used in block */ - Int32 nInUse; - Bool inUse[256]; - Bool inUse16[16]; - UChar seqToUnseq[256]; - - /* for decoding the MTF values */ - UChar mtfa [MTFA_SIZE]; - Int32 mtfbase[256 / MTFL_SIZE]; - UChar selector [BZ_MAX_SELECTORS]; - UChar selectorMtf[BZ_MAX_SELECTORS]; - UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - - Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 minLens[BZ_N_GROUPS]; - - /* save area for scalars in the main decompress code */ - Int32 save_i; - Int32 save_j; - Int32 save_t; - Int32 save_alphaSize; - Int32 save_nGroups; - Int32 save_nSelectors; - Int32 save_EOB; - Int32 save_groupNo; - Int32 save_groupPos; - Int32 save_nextSym; - Int32 save_nblockMAX; - Int32 save_nblock; - Int32 save_es; - Int32 save_N; - Int32 save_curr; - Int32 save_zt; - Int32 save_zn; - Int32 save_zvec; - Int32 save_zj; - Int32 save_gSel; - Int32 save_gMinlen; - Int32* save_gLimit; - Int32* save_gBase; - Int32* save_gPerm; - - } - DState; - - - -/*-- Macros for decompression. --*/ - -#define BZ_GET_FAST(cccc) \ - s->tPos = s->tt[s->tPos]; \ - cccc = (UChar)(s->tPos & 0xff); \ - s->tPos >>= 8; - -#define BZ_GET_FAST_C(cccc) \ - c_tPos = c_tt[c_tPos]; \ - cccc = (UChar)(c_tPos & 0xff); \ - c_tPos >>= 8; - -#define SET_LL4(i,n) \ - { if (((i) & 0x1) == 0) \ - s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \ - s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ - } - -#define GET_LL4(i) \ - ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF) - -#define SET_LL(i,n) \ - { s->ll16[i] = (UInt16)(n & 0x0000ffff); \ - SET_LL4(i, n >> 16); \ - } - -#define GET_LL(i) \ - (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16)) - -#define BZ_GET_SMALL(cccc) \ - cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ - s->tPos = GET_LL(s->tPos); - - -/*-- externs for decompression. --*/ - -extern Int32 -BZ2_indexIntoF ( Int32, Int32* ); - -extern Int32 -BZ2_decompress ( DState* ); - -extern void -BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*, - Int32, Int32, Int32 ); - - -#endif - - -/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/ - -#ifdef BZ_NO_STDIO -#ifndef NULL -#define NULL 0 -#endif -#endif - - -/*-------------------------------------------------------------*/ -/*--- end bzlib_private.h ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Private header file for the library. ---*/ +/*--- bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ + +/*-- + This file is a part of bzip2 and/or libbzip2, a program and + library for lossless, block-sorting data compression. + + Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Julian Seward, Cambridge, UK. + jseward@bzip.org + bzip2/libbzip2 version 1.0 of 21 March 2000 + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the manual. +--*/ + + +#ifndef _BZLIB_PRIVATE_H +#define _BZLIB_PRIVATE_H + +#include + +#ifndef BZ_NO_STDIO +#include +#include +#include +#endif + +#include "bzlib.h" + + + +/*-- General stuff. --*/ + +#define BZ_VERSION "1.0.3, 15-Feb-2005" + +typedef char Char; +typedef unsigned char Bool; +typedef unsigned char UChar; +typedef int Int32; +typedef unsigned int UInt32; +typedef short Int16; +typedef unsigned short UInt16; + +#define True ((Bool)1) +#define False ((Bool)0) + +#ifndef __GNUC__ +#define __inline__ /* */ +#endif + +#ifndef BZ_NO_STDIO +extern void BZ2_bz__AssertH__fail ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); } +#if BZ_DEBUG +#define AssertD(cond,msg) \ + { if (!(cond)) { \ + fprintf ( stderr, \ + "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\ + exit(1); \ + }} +#else +#define AssertD(cond,msg) /* */ +#endif +#define VPrintf0(zf) \ + fprintf(stderr,zf) +#define VPrintf1(zf,za1) \ + fprintf(stderr,zf,za1) +#define VPrintf2(zf,za1,za2) \ + fprintf(stderr,zf,za1,za2) +#define VPrintf3(zf,za1,za2,za3) \ + fprintf(stderr,zf,za1,za2,za3) +#define VPrintf4(zf,za1,za2,za3,za4) \ + fprintf(stderr,zf,za1,za2,za3,za4) +#define VPrintf5(zf,za1,za2,za3,za4,za5) \ + fprintf(stderr,zf,za1,za2,za3,za4,za5) +#else +extern void bz_internal_error ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) bz_internal_error ( errcode ); } +#define AssertD(cond,msg) /* */ +#define VPrintf0(zf) /* */ +#define VPrintf1(zf,za1) /* */ +#define VPrintf2(zf,za1,za2) /* */ +#define VPrintf3(zf,za1,za2,za3) /* */ +#define VPrintf4(zf,za1,za2,za3,za4) /* */ +#define VPrintf5(zf,za1,za2,za3,za4,za5) /* */ +#endif + + +#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1) +#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp)) + + +/*-- Header bytes. --*/ + +#define BZ_HDR_B 0x42 /* 'B' */ +#define BZ_HDR_Z 0x5a /* 'Z' */ +#define BZ_HDR_h 0x68 /* 'h' */ +#define BZ_HDR_0 0x30 /* '0' */ + +/*-- Constants for the back end. --*/ + +#define BZ_MAX_ALPHA_SIZE 258 +#define BZ_MAX_CODE_LEN 23 + +#define BZ_RUNA 0 +#define BZ_RUNB 1 + +#define BZ_N_GROUPS 6 +#define BZ_G_SIZE 50 +#define BZ_N_ITERS 4 + +#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) + + + +/*-- Stuff for randomising repetitive blocks. --*/ + +extern Int32 BZ2_rNums[512]; + +#define BZ_RAND_DECLS \ + Int32 rNToGo; \ + Int32 rTPos \ + +#define BZ_RAND_INIT_MASK \ + s->rNToGo = 0; \ + s->rTPos = 0 \ + +#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0) + +#define BZ_RAND_UPD_MASK \ + if (s->rNToGo == 0) { \ + s->rNToGo = BZ2_rNums[s->rTPos]; \ + s->rTPos++; \ + if (s->rTPos == 512) s->rTPos = 0; \ + } \ + s->rNToGo--; + + + +/*-- Stuff for doing CRCs. --*/ + +extern UInt32 BZ2_crc32Table[256]; + +#define BZ_INITIALISE_CRC(crcVar) \ +{ \ + crcVar = 0xffffffffL; \ +} + +#define BZ_FINALISE_CRC(crcVar) \ +{ \ + crcVar = ~(crcVar); \ +} + +#define BZ_UPDATE_CRC(crcVar,cha) \ +{ \ + crcVar = (crcVar << 8) ^ \ + BZ2_crc32Table[(crcVar >> 24) ^ \ + ((UChar)cha)]; \ +} + + + +/*-- States and modes for compression. --*/ + +#define BZ_M_IDLE 1 +#define BZ_M_RUNNING 2 +#define BZ_M_FLUSHING 3 +#define BZ_M_FINISHING 4 + +#define BZ_S_OUTPUT 1 +#define BZ_S_INPUT 2 + +#define BZ_N_RADIX 2 +#define BZ_N_QSORT 12 +#define BZ_N_SHELL 18 +#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) + + + + +/*-- Structure holding all the compression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* mode this stream is in, and whether inputting */ + /* or outputting data */ + Int32 mode; + Int32 state; + + /* remembers avail_in when flush/finish requested */ + UInt32 avail_in_expect; + + /* for doing the block sorting */ + UInt32* arr1; + UInt32* arr2; + UInt32* ftab; + Int32 origPtr; + + /* aliases for arr1 and arr2 */ + UInt32* ptr; + UChar* block; + UInt16* mtfv; + UChar* zbits; + + /* for deciding when to use the fallback sorting algorithm */ + Int32 workFactor; + + /* run-length-encoding of the input */ + UInt32 state_in_ch; + Int32 state_in_len; + BZ_RAND_DECLS; + + /* input and output limits and current posns */ + Int32 nblock; + Int32 nblockMAX; + Int32 numZ; + Int32 state_out_pos; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + UChar unseqToSeq[256]; + + /* the buffer for bit stream creation */ + UInt32 bsBuff; + Int32 bsLive; + + /* block and combined CRCs */ + UInt32 blockCRC; + UInt32 combinedCRC; + + /* misc administratium */ + Int32 verbosity; + Int32 blockNo; + Int32 blockSize100k; + + /* stuff for coding the MTF values */ + Int32 nMTF; + Int32 mtfFreq [BZ_MAX_ALPHA_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + /* second dimension: only 3 needed; 4 makes index calculations faster */ + UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4]; + + } + EState; + + + +/*-- externs for compression. --*/ + +extern void +BZ2_blockSort ( EState* ); + +extern void +BZ2_compressBlock ( EState*, Bool ); + +extern void +BZ2_bsInitWrite ( EState* ); + +extern void +BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 ); + +extern void +BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 ); + + + +/*-- states for decompression. --*/ + +#define BZ_X_IDLE 1 +#define BZ_X_OUTPUT 2 + +#define BZ_X_MAGIC_1 10 +#define BZ_X_MAGIC_2 11 +#define BZ_X_MAGIC_3 12 +#define BZ_X_MAGIC_4 13 +#define BZ_X_BLKHDR_1 14 +#define BZ_X_BLKHDR_2 15 +#define BZ_X_BLKHDR_3 16 +#define BZ_X_BLKHDR_4 17 +#define BZ_X_BLKHDR_5 18 +#define BZ_X_BLKHDR_6 19 +#define BZ_X_BCRC_1 20 +#define BZ_X_BCRC_2 21 +#define BZ_X_BCRC_3 22 +#define BZ_X_BCRC_4 23 +#define BZ_X_RANDBIT 24 +#define BZ_X_ORIGPTR_1 25 +#define BZ_X_ORIGPTR_2 26 +#define BZ_X_ORIGPTR_3 27 +#define BZ_X_MAPPING_1 28 +#define BZ_X_MAPPING_2 29 +#define BZ_X_SELECTOR_1 30 +#define BZ_X_SELECTOR_2 31 +#define BZ_X_SELECTOR_3 32 +#define BZ_X_CODING_1 33 +#define BZ_X_CODING_2 34 +#define BZ_X_CODING_3 35 +#define BZ_X_MTF_1 36 +#define BZ_X_MTF_2 37 +#define BZ_X_MTF_3 38 +#define BZ_X_MTF_4 39 +#define BZ_X_MTF_5 40 +#define BZ_X_MTF_6 41 +#define BZ_X_ENDHDR_2 42 +#define BZ_X_ENDHDR_3 43 +#define BZ_X_ENDHDR_4 44 +#define BZ_X_ENDHDR_5 45 +#define BZ_X_ENDHDR_6 46 +#define BZ_X_CCRC_1 47 +#define BZ_X_CCRC_2 48 +#define BZ_X_CCRC_3 49 +#define BZ_X_CCRC_4 50 + + + +/*-- Constants for the fast MTF decoder. --*/ + +#define MTFA_SIZE 4096 +#define MTFL_SIZE 16 + + + +/*-- Structure holding all the decompression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* state indicator for this stream */ + Int32 state; + + /* for doing the final run-length decoding */ + UChar state_out_ch; + Int32 state_out_len; + Bool blockRandomised; + BZ_RAND_DECLS; + + /* the buffer for bit stream reading */ + UInt32 bsBuff; + Int32 bsLive; + + /* misc administratium */ + Int32 blockSize100k; + Bool smallDecompress; + Int32 currBlockNo; + Int32 verbosity; + + /* for undoing the Burrows-Wheeler transform */ + Int32 origPtr; + UInt32 tPos; + Int32 k0; + Int32 unzftab[256]; + Int32 nblock_used; + Int32 cftab[257]; + Int32 cftabCopy[257]; + + /* for undoing the Burrows-Wheeler transform (FAST) */ + UInt32 *tt; + + /* for undoing the Burrows-Wheeler transform (SMALL) */ + UInt16 *ll16; + UChar *ll4; + + /* stored and calculated CRCs */ + UInt32 storedBlockCRC; + UInt32 storedCombinedCRC; + UInt32 calculatedBlockCRC; + UInt32 calculatedCombinedCRC; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + Bool inUse16[16]; + UChar seqToUnseq[256]; + + /* for decoding the MTF values */ + UChar mtfa [MTFA_SIZE]; + Int32 mtfbase[256 / MTFL_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + + Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 minLens[BZ_N_GROUPS]; + + /* save area for scalars in the main decompress code */ + Int32 save_i; + Int32 save_j; + Int32 save_t; + Int32 save_alphaSize; + Int32 save_nGroups; + Int32 save_nSelectors; + Int32 save_EOB; + Int32 save_groupNo; + Int32 save_groupPos; + Int32 save_nextSym; + Int32 save_nblockMAX; + Int32 save_nblock; + Int32 save_es; + Int32 save_N; + Int32 save_curr; + Int32 save_zt; + Int32 save_zn; + Int32 save_zvec; + Int32 save_zj; + Int32 save_gSel; + Int32 save_gMinlen; + Int32* save_gLimit; + Int32* save_gBase; + Int32* save_gPerm; + + } + DState; + + + +/*-- Macros for decompression. --*/ + +#define BZ_GET_FAST(cccc) \ + s->tPos = s->tt[s->tPos]; \ + cccc = (UChar)(s->tPos & 0xff); \ + s->tPos >>= 8; + +#define BZ_GET_FAST_C(cccc) \ + c_tPos = c_tt[c_tPos]; \ + cccc = (UChar)(c_tPos & 0xff); \ + c_tPos >>= 8; + +#define SET_LL4(i,n) \ + { if (((i) & 0x1) == 0) \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ + } + +#define GET_LL4(i) \ + ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF) + +#define SET_LL(i,n) \ + { s->ll16[i] = (UInt16)(n & 0x0000ffff); \ + SET_LL4(i, n >> 16); \ + } + +#define GET_LL(i) \ + (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16)) + +#define BZ_GET_SMALL(cccc) \ + cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ + s->tPos = GET_LL(s->tPos); + + +/*-- externs for decompression. --*/ + +extern Int32 +BZ2_indexIntoF ( Int32, Int32* ); + +extern Int32 +BZ2_decompress ( DState* ); + +extern void +BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*, + Int32, Int32, Int32 ); + + +#endif + + +/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/ + +#ifdef BZ_NO_STDIO +#ifndef NULL +#define NULL 0 +#endif +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDisoEFP/src/bzip2/compress.c b/plugins/CDVDisoEFP/src/bzip2/compress.c index f6ff751f41..7e0c29155a 100644 --- a/plugins/CDVDisoEFP/src/bzip2/compress.c +++ b/plugins/CDVDisoEFP/src/bzip2/compress.c @@ -1,716 +1,716 @@ - -/*-------------------------------------------------------------*/ -/*--- Compression machinery (not incl block sorting) ---*/ -/*--- compress.c ---*/ -/*-------------------------------------------------------------*/ - -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. - - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ - -/*-- - CHANGES - ~~~~~~~ - 0.9.0 -- original version. - - 0.9.0a/b -- no changes in this file. - - 0.9.0c - * changed setting of nGroups in sendMTFValues() so as to - do a bit better on small files ---*/ - -#include "bzlib_private.h" - - -/*---------------------------------------------------*/ -/*--- Bit stream I/O ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -void BZ2_bsInitWrite ( EState* s ) -{ - s->bsLive = 0; - s->bsBuff = 0; -} - - -/*---------------------------------------------------*/ -static -void bsFinishWrite ( EState* s ) -{ - while (s->bsLive > 0) { - s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24); - s->numZ++; - s->bsBuff <<= 8; - s->bsLive -= 8; - } -} - - -/*---------------------------------------------------*/ -#define bsNEEDW(nz) \ -{ \ - while (s->bsLive >= 8) { \ - s->zbits[s->numZ] \ - = (UChar)(s->bsBuff >> 24); \ - s->numZ++; \ - s->bsBuff <<= 8; \ - s->bsLive -= 8; \ - } \ -} - - -/*---------------------------------------------------*/ -static -__inline__ -void bsW ( EState* s, Int32 n, UInt32 v ) -{ - bsNEEDW ( n ); - s->bsBuff |= (v << (32 - s->bsLive - n)); - s->bsLive += n; -} - - -/*---------------------------------------------------*/ -static -void bsPutUInt32 ( EState* s, UInt32 u ) -{ - bsW ( s, 8, (u >> 24) & 0xffL ); - bsW ( s, 8, (u >> 16) & 0xffL ); - bsW ( s, 8, (u >> 8) & 0xffL ); - bsW ( s, 8, u & 0xffL ); -} - - -/*---------------------------------------------------*/ -static -void bsPutUChar ( EState* s, UChar c ) -{ - bsW( s, 8, (UInt32)c ); -} - - -/*---------------------------------------------------*/ -/*--- The back end proper ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -static -void makeMaps_e ( EState* s ) -{ - Int32 i; - s->nInUse = 0; - for (i = 0; i < 256; i++) - if (s->inUse[i]) { - s->unseqToSeq[i] = s->nInUse; - s->nInUse++; - } -} - - -/*---------------------------------------------------*/ -static -void generateMTFValues ( EState* s ) -{ - UChar yy[256]; - Int32 i, j; - Int32 zPend; - Int32 wr; - Int32 EOB; - - /* - After sorting (eg, here), - s->arr1 [ 0 .. s->nblock-1 ] holds sorted order, - and - ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] - holds the original block data. - - The first thing to do is generate the MTF values, - and put them in - ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ]. - Because there are strictly fewer or equal MTF values - than block values, ptr values in this area are overwritten - with MTF values only when they are no longer needed. - - The final compressed bitstream is generated into the - area starting at - (UChar*) (&((UChar*)s->arr2)[s->nblock]) - - These storage aliases are set up in bzCompressInit(), - except for the last one, which is arranged in - compressBlock(). - */ - UInt32* ptr = s->ptr; - UChar* block = s->block; - UInt16* mtfv = s->mtfv; - - makeMaps_e ( s ); - EOB = s->nInUse+1; - - for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0; - - wr = 0; - zPend = 0; - for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i; - - for (i = 0; i < s->nblock; i++) { - UChar ll_i; - AssertD ( wr <= i, "generateMTFValues(1)" ); - j = ptr[i]-1; if (j < 0) j += s->nblock; - ll_i = s->unseqToSeq[block[j]]; - AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" ); - - if (yy[0] == ll_i) { - zPend++; - } else { - - if (zPend > 0) { - zPend--; - while (True) { - if (zPend & 1) { - mtfv[wr] = BZ_RUNB; wr++; - s->mtfFreq[BZ_RUNB]++; - } else { - mtfv[wr] = BZ_RUNA; wr++; - s->mtfFreq[BZ_RUNA]++; - } - if (zPend < 2) break; - zPend = (zPend - 2) / 2; - }; - zPend = 0; - } - { - register UChar rtmp; - register UChar* ryy_j; - register UChar rll_i; - rtmp = yy[1]; - yy[1] = yy[0]; - ryy_j = &(yy[1]); - rll_i = ll_i; - while ( rll_i != rtmp ) { - register UChar rtmp2; - ryy_j++; - rtmp2 = rtmp; - rtmp = *ryy_j; - *ryy_j = rtmp2; - }; - yy[0] = rtmp; - j = ryy_j - &(yy[0]); - mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++; - } - - } - } - - if (zPend > 0) { - zPend--; - while (True) { - if (zPend & 1) { - mtfv[wr] = BZ_RUNB; wr++; - s->mtfFreq[BZ_RUNB]++; - } else { - mtfv[wr] = BZ_RUNA; wr++; - s->mtfFreq[BZ_RUNA]++; - } - if (zPend < 2) break; - zPend = (zPend - 2) / 2; - }; - zPend = 0; - } - - mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++; - - s->nMTF = wr; -} - - -/*---------------------------------------------------*/ -#define BZ_LESSER_ICOST 0 -#define BZ_GREATER_ICOST 15 - -static -void sendMTFValues ( EState* s ) -{ - Int32 v, t, i, j, gs, ge, totc, bt, bc, iter; - Int32 nSelectors, alphaSize, minLen, maxLen, selCtr; - Int32 nGroups, nBytes; - - /*-- - UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - is a global since the decoder also needs it. - - Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - are also globals only used in this proc. - Made global to keep stack frame size small. - --*/ - - - UInt16 cost[BZ_N_GROUPS]; - Int32 fave[BZ_N_GROUPS]; - - UInt16* mtfv = s->mtfv; - - if (s->verbosity >= 3) - VPrintf3( " %d in block, %d after MTF & 1-2 coding, " - "%d+2 syms in use\n", - s->nblock, s->nMTF, s->nInUse ); - - alphaSize = s->nInUse+2; - for (t = 0; t < BZ_N_GROUPS; t++) - for (v = 0; v < alphaSize; v++) - s->len[t][v] = BZ_GREATER_ICOST; - - /*--- Decide how many coding tables to use ---*/ - AssertH ( s->nMTF > 0, 3001 ); - if (s->nMTF < 200) nGroups = 2; else - if (s->nMTF < 600) nGroups = 3; else - if (s->nMTF < 1200) nGroups = 4; else - if (s->nMTF < 2400) nGroups = 5; else - nGroups = 6; - - /*--- Generate an initial set of coding tables ---*/ - { - Int32 nPart, remF, tFreq, aFreq; - - nPart = nGroups; - remF = s->nMTF; - gs = 0; - while (nPart > 0) { - tFreq = remF / nPart; - ge = gs-1; - aFreq = 0; - while (aFreq < tFreq && ge < alphaSize-1) { - ge++; - aFreq += s->mtfFreq[ge]; - } - - if (ge > gs - && nPart != nGroups && nPart != 1 - && ((nGroups-nPart) % 2 == 1)) { - aFreq -= s->mtfFreq[ge]; - ge--; - } - - if (s->verbosity >= 3) - VPrintf5( " initial group %d, [%d .. %d], " - "has %d syms (%4.1f%%)\n", - nPart, gs, ge, aFreq, - (100.0 * (float)aFreq) / (float)(s->nMTF) ); - - for (v = 0; v < alphaSize; v++) - if (v >= gs && v <= ge) - s->len[nPart-1][v] = BZ_LESSER_ICOST; else - s->len[nPart-1][v] = BZ_GREATER_ICOST; - - nPart--; - gs = ge+1; - remF -= aFreq; - } - } - - /*--- - Iterate up to BZ_N_ITERS times to improve the tables. - ---*/ - for (iter = 0; iter < BZ_N_ITERS; iter++) { - - for (t = 0; t < nGroups; t++) fave[t] = 0; - - for (t = 0; t < nGroups; t++) - for (v = 0; v < alphaSize; v++) - s->rfreq[t][v] = 0; - - /*--- - Set up an auxiliary length table which is used to fast-track - the common case (nGroups == 6). - ---*/ - if (nGroups == 6) { - for (v = 0; v < alphaSize; v++) { - s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; - s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; - s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; - } - } - - nSelectors = 0; - totc = 0; - gs = 0; - while (True) { - - /*--- Set group start & end marks. --*/ - if (gs >= s->nMTF) break; - ge = gs + BZ_G_SIZE - 1; - if (ge >= s->nMTF) ge = s->nMTF-1; - - /*-- - Calculate the cost of this group as coded - by each of the coding tables. - --*/ - for (t = 0; t < nGroups; t++) cost[t] = 0; - - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - register UInt32 cost01, cost23, cost45; - register UInt16 icv; - cost01 = cost23 = cost45 = 0; - -# define BZ_ITER(nn) \ - icv = mtfv[gs+(nn)]; \ - cost01 += s->len_pack[icv][0]; \ - cost23 += s->len_pack[icv][1]; \ - cost45 += s->len_pack[icv][2]; \ - - BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); - BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); - BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); - BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); - BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); - BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); - BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); - BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); - BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); - BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); - -# undef BZ_ITER - - cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; - cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; - cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; - - } else { - /*--- slow version which correctly handles all situations ---*/ - for (i = gs; i <= ge; i++) { - UInt16 icv = mtfv[i]; - for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv]; - } - } - - /*-- - Find the coding table which is best for this group, - and record its identity in the selector table. - --*/ - bc = 999999999; bt = -1; - for (t = 0; t < nGroups; t++) - if (cost[t] < bc) { bc = cost[t]; bt = t; }; - totc += bc; - fave[bt]++; - s->selector[nSelectors] = bt; - nSelectors++; - - /*-- - Increment the symbol frequencies for the selected table. - --*/ - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - -# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++ - - BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); - BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); - BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); - BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); - BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); - BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); - BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); - BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); - BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); - BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); - -# undef BZ_ITUR - - } else { - /*--- slow version which correctly handles all situations ---*/ - for (i = gs; i <= ge; i++) - s->rfreq[bt][ mtfv[i] ]++; - } - - gs = ge+1; - } - if (s->verbosity >= 3) { - VPrintf2 ( " pass %d: size is %d, grp uses are ", - iter+1, totc/8 ); - for (t = 0; t < nGroups; t++) - VPrintf1 ( "%d ", fave[t] ); - VPrintf0 ( "\n" ); - } - - /*-- - Recompute the tables based on the accumulated frequencies. - --*/ - /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See - comment in huffman.c for details. */ - for (t = 0; t < nGroups; t++) - BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), - alphaSize, 17 /*20*/ ); - } - - - AssertH( nGroups < 8, 3002 ); - AssertH( nSelectors < 32768 && - nSelectors <= (2 + (900000 / BZ_G_SIZE)), - 3003 ); - - - /*--- Compute MTF values for the selectors. ---*/ - { - UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp; - for (i = 0; i < nGroups; i++) pos[i] = i; - for (i = 0; i < nSelectors; i++) { - ll_i = s->selector[i]; - j = 0; - tmp = pos[j]; - while ( ll_i != tmp ) { - j++; - tmp2 = tmp; - tmp = pos[j]; - pos[j] = tmp2; - }; - pos[0] = tmp; - s->selectorMtf[i] = j; - } - }; - - /*--- Assign actual codes for the tables. --*/ - for (t = 0; t < nGroups; t++) { - minLen = 32; - maxLen = 0; - for (i = 0; i < alphaSize; i++) { - if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; - if (s->len[t][i] < minLen) minLen = s->len[t][i]; - } - AssertH ( !(maxLen > 17 /*20*/ ), 3004 ); - AssertH ( !(minLen < 1), 3005 ); - BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), - minLen, maxLen, alphaSize ); - } - - /*--- Transmit the mapping table. ---*/ - { - Bool inUse16[16]; - for (i = 0; i < 16; i++) { - inUse16[i] = False; - for (j = 0; j < 16; j++) - if (s->inUse[i * 16 + j]) inUse16[i] = True; - } - - nBytes = s->numZ; - for (i = 0; i < 16; i++) - if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0); - - for (i = 0; i < 16; i++) - if (inUse16[i]) - for (j = 0; j < 16; j++) { - if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0); - } - - if (s->verbosity >= 3) - VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes ); - } - - /*--- Now the selectors. ---*/ - nBytes = s->numZ; - bsW ( s, 3, nGroups ); - bsW ( s, 15, nSelectors ); - for (i = 0; i < nSelectors; i++) { - for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1); - bsW(s,1,0); - } - if (s->verbosity >= 3) - VPrintf1( "selectors %d, ", s->numZ-nBytes ); - - /*--- Now the coding tables. ---*/ - nBytes = s->numZ; - - for (t = 0; t < nGroups; t++) { - Int32 curr = s->len[t][0]; - bsW ( s, 5, curr ); - for (i = 0; i < alphaSize; i++) { - while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ }; - while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ }; - bsW ( s, 1, 0 ); - } - } - - if (s->verbosity >= 3) - VPrintf1 ( "code lengths %d, ", s->numZ-nBytes ); - - /*--- And finally, the block data proper ---*/ - nBytes = s->numZ; - selCtr = 0; - gs = 0; - while (True) { - if (gs >= s->nMTF) break; - ge = gs + BZ_G_SIZE - 1; - if (ge >= s->nMTF) ge = s->nMTF-1; - AssertH ( s->selector[selCtr] < nGroups, 3006 ); - - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - UInt16 mtfv_i; - UChar* s_len_sel_selCtr - = &(s->len[s->selector[selCtr]][0]); - Int32* s_code_sel_selCtr - = &(s->code[s->selector[selCtr]][0]); - -# define BZ_ITAH(nn) \ - mtfv_i = mtfv[gs+(nn)]; \ - bsW ( s, \ - s_len_sel_selCtr[mtfv_i], \ - s_code_sel_selCtr[mtfv_i] ) - - BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); - BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); - BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); - BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); - BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); - BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); - BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); - BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); - BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); - BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); - -# undef BZ_ITAH - - } else { - /*--- slow version which correctly handles all situations ---*/ - for (i = gs; i <= ge; i++) { - bsW ( s, - s->len [s->selector[selCtr]] [mtfv[i]], - s->code [s->selector[selCtr]] [mtfv[i]] ); - } - } - - - gs = ge+1; - selCtr++; - } - AssertH( selCtr == nSelectors, 3007 ); - - if (s->verbosity >= 3) - VPrintf1( "codes %d\n", s->numZ-nBytes ); -} - - -/*---------------------------------------------------*/ -void BZ2_compressBlock ( EState* s, Bool is_last_block ) -{ - if (s->nblock > 0) { - - BZ_FINALISE_CRC ( s->blockCRC ); - s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); - s->combinedCRC ^= s->blockCRC; - if (s->blockNo > 1) s->numZ = 0; - - if (s->verbosity >= 2) - VPrintf4( " block %d: crc = 0x%08x, " - "combined CRC = 0x%08x, size = %d\n", - s->blockNo, s->blockCRC, s->combinedCRC, s->nblock ); - - BZ2_blockSort ( s ); - } - - s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]); - - /*-- If this is the first block, create the stream header. --*/ - if (s->blockNo == 1) { - BZ2_bsInitWrite ( s ); - bsPutUChar ( s, BZ_HDR_B ); - bsPutUChar ( s, BZ_HDR_Z ); - bsPutUChar ( s, BZ_HDR_h ); - bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) ); - } - - if (s->nblock > 0) { - - bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 ); - bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 ); - bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 ); - - /*-- Now the block's CRC, so it is in a known place. --*/ - bsPutUInt32 ( s, s->blockCRC ); - - /*-- - Now a single bit indicating (non-)randomisation. - As of version 0.9.5, we use a better sorting algorithm - which makes randomisation unnecessary. So always set - the randomised bit to 'no'. Of course, the decoder - still needs to be able to handle randomised blocks - so as to maintain backwards compatibility with - older versions of bzip2. - --*/ - bsW(s,1,0); - - bsW ( s, 24, s->origPtr ); - generateMTFValues ( s ); - sendMTFValues ( s ); - } - - - /*-- If this is the last block, add the stream trailer. --*/ - if (is_last_block) { - - bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 ); - bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 ); - bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 ); - bsPutUInt32 ( s, s->combinedCRC ); - if (s->verbosity >= 2) - VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC ); - bsFinishWrite ( s ); - } -} - - -/*-------------------------------------------------------------*/ -/*--- end compress.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Compression machinery (not incl block sorting) ---*/ +/*--- compress.c ---*/ +/*-------------------------------------------------------------*/ + +/*-- + This file is a part of bzip2 and/or libbzip2, a program and + library for lossless, block-sorting data compression. + + Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Julian Seward, Cambridge, UK. + jseward@bzip.org + bzip2/libbzip2 version 1.0 of 21 March 2000 + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the manual. +--*/ + +/*-- + CHANGES + ~~~~~~~ + 0.9.0 -- original version. + + 0.9.0a/b -- no changes in this file. + + 0.9.0c + * changed setting of nGroups in sendMTFValues() so as to + do a bit better on small files +--*/ + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Bit stream I/O ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +void BZ2_bsInitWrite ( EState* s ) +{ + s->bsLive = 0; + s->bsBuff = 0; +} + + +/*---------------------------------------------------*/ +static +void bsFinishWrite ( EState* s ) +{ + while (s->bsLive > 0) { + s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24); + s->numZ++; + s->bsBuff <<= 8; + s->bsLive -= 8; + } +} + + +/*---------------------------------------------------*/ +#define bsNEEDW(nz) \ +{ \ + while (s->bsLive >= 8) { \ + s->zbits[s->numZ] \ + = (UChar)(s->bsBuff >> 24); \ + s->numZ++; \ + s->bsBuff <<= 8; \ + s->bsLive -= 8; \ + } \ +} + + +/*---------------------------------------------------*/ +static +__inline__ +void bsW ( EState* s, Int32 n, UInt32 v ) +{ + bsNEEDW ( n ); + s->bsBuff |= (v << (32 - s->bsLive - n)); + s->bsLive += n; +} + + +/*---------------------------------------------------*/ +static +void bsPutUInt32 ( EState* s, UInt32 u ) +{ + bsW ( s, 8, (u >> 24) & 0xffL ); + bsW ( s, 8, (u >> 16) & 0xffL ); + bsW ( s, 8, (u >> 8) & 0xffL ); + bsW ( s, 8, u & 0xffL ); +} + + +/*---------------------------------------------------*/ +static +void bsPutUChar ( EState* s, UChar c ) +{ + bsW( s, 8, (UInt32)c ); +} + + +/*---------------------------------------------------*/ +/*--- The back end proper ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +static +void makeMaps_e ( EState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->unseqToSeq[i] = s->nInUse; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +static +void generateMTFValues ( EState* s ) +{ + UChar yy[256]; + Int32 i, j; + Int32 zPend; + Int32 wr; + Int32 EOB; + + /* + After sorting (eg, here), + s->arr1 [ 0 .. s->nblock-1 ] holds sorted order, + and + ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] + holds the original block data. + + The first thing to do is generate the MTF values, + and put them in + ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ]. + Because there are strictly fewer or equal MTF values + than block values, ptr values in this area are overwritten + with MTF values only when they are no longer needed. + + The final compressed bitstream is generated into the + area starting at + (UChar*) (&((UChar*)s->arr2)[s->nblock]) + + These storage aliases are set up in bzCompressInit(), + except for the last one, which is arranged in + compressBlock(). + */ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt16* mtfv = s->mtfv; + + makeMaps_e ( s ); + EOB = s->nInUse+1; + + for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0; + + wr = 0; + zPend = 0; + for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i; + + for (i = 0; i < s->nblock; i++) { + UChar ll_i; + AssertD ( wr <= i, "generateMTFValues(1)" ); + j = ptr[i]-1; if (j < 0) j += s->nblock; + ll_i = s->unseqToSeq[block[j]]; + AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" ); + + if (yy[0] == ll_i) { + zPend++; + } else { + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + { + register UChar rtmp; + register UChar* ryy_j; + register UChar rll_i; + rtmp = yy[1]; + yy[1] = yy[0]; + ryy_j = &(yy[1]); + rll_i = ll_i; + while ( rll_i != rtmp ) { + register UChar rtmp2; + ryy_j++; + rtmp2 = rtmp; + rtmp = *ryy_j; + *ryy_j = rtmp2; + }; + yy[0] = rtmp; + j = ryy_j - &(yy[0]); + mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++; + } + + } + } + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + + mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++; + + s->nMTF = wr; +} + + +/*---------------------------------------------------*/ +#define BZ_LESSER_ICOST 0 +#define BZ_GREATER_ICOST 15 + +static +void sendMTFValues ( EState* s ) +{ + Int32 v, t, i, j, gs, ge, totc, bt, bc, iter; + Int32 nSelectors, alphaSize, minLen, maxLen, selCtr; + Int32 nGroups, nBytes; + + /*-- + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + is a global since the decoder also needs it. + + Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + are also globals only used in this proc. + Made global to keep stack frame size small. + --*/ + + + UInt16 cost[BZ_N_GROUPS]; + Int32 fave[BZ_N_GROUPS]; + + UInt16* mtfv = s->mtfv; + + if (s->verbosity >= 3) + VPrintf3( " %d in block, %d after MTF & 1-2 coding, " + "%d+2 syms in use\n", + s->nblock, s->nMTF, s->nInUse ); + + alphaSize = s->nInUse+2; + for (t = 0; t < BZ_N_GROUPS; t++) + for (v = 0; v < alphaSize; v++) + s->len[t][v] = BZ_GREATER_ICOST; + + /*--- Decide how many coding tables to use ---*/ + AssertH ( s->nMTF > 0, 3001 ); + if (s->nMTF < 200) nGroups = 2; else + if (s->nMTF < 600) nGroups = 3; else + if (s->nMTF < 1200) nGroups = 4; else + if (s->nMTF < 2400) nGroups = 5; else + nGroups = 6; + + /*--- Generate an initial set of coding tables ---*/ + { + Int32 nPart, remF, tFreq, aFreq; + + nPart = nGroups; + remF = s->nMTF; + gs = 0; + while (nPart > 0) { + tFreq = remF / nPart; + ge = gs-1; + aFreq = 0; + while (aFreq < tFreq && ge < alphaSize-1) { + ge++; + aFreq += s->mtfFreq[ge]; + } + + if (ge > gs + && nPart != nGroups && nPart != 1 + && ((nGroups-nPart) % 2 == 1)) { + aFreq -= s->mtfFreq[ge]; + ge--; + } + + if (s->verbosity >= 3) + VPrintf5( " initial group %d, [%d .. %d], " + "has %d syms (%4.1f%%)\n", + nPart, gs, ge, aFreq, + (100.0 * (float)aFreq) / (float)(s->nMTF) ); + + for (v = 0; v < alphaSize; v++) + if (v >= gs && v <= ge) + s->len[nPart-1][v] = BZ_LESSER_ICOST; else + s->len[nPart-1][v] = BZ_GREATER_ICOST; + + nPart--; + gs = ge+1; + remF -= aFreq; + } + } + + /*--- + Iterate up to BZ_N_ITERS times to improve the tables. + ---*/ + for (iter = 0; iter < BZ_N_ITERS; iter++) { + + for (t = 0; t < nGroups; t++) fave[t] = 0; + + for (t = 0; t < nGroups; t++) + for (v = 0; v < alphaSize; v++) + s->rfreq[t][v] = 0; + + /*--- + Set up an auxiliary length table which is used to fast-track + the common case (nGroups == 6). + ---*/ + if (nGroups == 6) { + for (v = 0; v < alphaSize; v++) { + s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; + s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; + s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; + } + } + + nSelectors = 0; + totc = 0; + gs = 0; + while (True) { + + /*--- Set group start & end marks. --*/ + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + + /*-- + Calculate the cost of this group as coded + by each of the coding tables. + --*/ + for (t = 0; t < nGroups; t++) cost[t] = 0; + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + register UInt32 cost01, cost23, cost45; + register UInt16 icv; + cost01 = cost23 = cost45 = 0; + +# define BZ_ITER(nn) \ + icv = mtfv[gs+(nn)]; \ + cost01 += s->len_pack[icv][0]; \ + cost23 += s->len_pack[icv][1]; \ + cost45 += s->len_pack[icv][2]; \ + + BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); + BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); + BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); + BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); + BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); + BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); + BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); + BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); + BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); + BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); + +# undef BZ_ITER + + cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; + cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; + cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + UInt16 icv = mtfv[i]; + for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv]; + } + } + + /*-- + Find the coding table which is best for this group, + and record its identity in the selector table. + --*/ + bc = 999999999; bt = -1; + for (t = 0; t < nGroups; t++) + if (cost[t] < bc) { bc = cost[t]; bt = t; }; + totc += bc; + fave[bt]++; + s->selector[nSelectors] = bt; + nSelectors++; + + /*-- + Increment the symbol frequencies for the selected table. + --*/ + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + +# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++ + + BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); + BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); + BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); + BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); + BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); + BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); + BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); + BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); + BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); + BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); + +# undef BZ_ITUR + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) + s->rfreq[bt][ mtfv[i] ]++; + } + + gs = ge+1; + } + if (s->verbosity >= 3) { + VPrintf2 ( " pass %d: size is %d, grp uses are ", + iter+1, totc/8 ); + for (t = 0; t < nGroups; t++) + VPrintf1 ( "%d ", fave[t] ); + VPrintf0 ( "\n" ); + } + + /*-- + Recompute the tables based on the accumulated frequencies. + --*/ + /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See + comment in huffman.c for details. */ + for (t = 0; t < nGroups; t++) + BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), + alphaSize, 17 /*20*/ ); + } + + + AssertH( nGroups < 8, 3002 ); + AssertH( nSelectors < 32768 && + nSelectors <= (2 + (900000 / BZ_G_SIZE)), + 3003 ); + + + /*--- Compute MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp; + for (i = 0; i < nGroups; i++) pos[i] = i; + for (i = 0; i < nSelectors; i++) { + ll_i = s->selector[i]; + j = 0; + tmp = pos[j]; + while ( ll_i != tmp ) { + j++; + tmp2 = tmp; + tmp = pos[j]; + pos[j] = tmp2; + }; + pos[0] = tmp; + s->selectorMtf[i] = j; + } + }; + + /*--- Assign actual codes for the tables. --*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + AssertH ( !(maxLen > 17 /*20*/ ), 3004 ); + AssertH ( !(minLen < 1), 3005 ); + BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), + minLen, maxLen, alphaSize ); + } + + /*--- Transmit the mapping table. ---*/ + { + Bool inUse16[16]; + for (i = 0; i < 16; i++) { + inUse16[i] = False; + for (j = 0; j < 16; j++) + if (s->inUse[i * 16 + j]) inUse16[i] = True; + } + + nBytes = s->numZ; + for (i = 0; i < 16; i++) + if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0); + + for (i = 0; i < 16; i++) + if (inUse16[i]) + for (j = 0; j < 16; j++) { + if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0); + } + + if (s->verbosity >= 3) + VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes ); + } + + /*--- Now the selectors. ---*/ + nBytes = s->numZ; + bsW ( s, 3, nGroups ); + bsW ( s, 15, nSelectors ); + for (i = 0; i < nSelectors; i++) { + for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1); + bsW(s,1,0); + } + if (s->verbosity >= 3) + VPrintf1( "selectors %d, ", s->numZ-nBytes ); + + /*--- Now the coding tables. ---*/ + nBytes = s->numZ; + + for (t = 0; t < nGroups; t++) { + Int32 curr = s->len[t][0]; + bsW ( s, 5, curr ); + for (i = 0; i < alphaSize; i++) { + while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ }; + while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ }; + bsW ( s, 1, 0 ); + } + } + + if (s->verbosity >= 3) + VPrintf1 ( "code lengths %d, ", s->numZ-nBytes ); + + /*--- And finally, the block data proper ---*/ + nBytes = s->numZ; + selCtr = 0; + gs = 0; + while (True) { + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + AssertH ( s->selector[selCtr] < nGroups, 3006 ); + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + UInt16 mtfv_i; + UChar* s_len_sel_selCtr + = &(s->len[s->selector[selCtr]][0]); + Int32* s_code_sel_selCtr + = &(s->code[s->selector[selCtr]][0]); + +# define BZ_ITAH(nn) \ + mtfv_i = mtfv[gs+(nn)]; \ + bsW ( s, \ + s_len_sel_selCtr[mtfv_i], \ + s_code_sel_selCtr[mtfv_i] ) + + BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); + BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); + BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); + BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); + BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); + BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); + BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); + BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); + BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); + BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); + +# undef BZ_ITAH + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + bsW ( s, + s->len [s->selector[selCtr]] [mtfv[i]], + s->code [s->selector[selCtr]] [mtfv[i]] ); + } + } + + + gs = ge+1; + selCtr++; + } + AssertH( selCtr == nSelectors, 3007 ); + + if (s->verbosity >= 3) + VPrintf1( "codes %d\n", s->numZ-nBytes ); +} + + +/*---------------------------------------------------*/ +void BZ2_compressBlock ( EState* s, Bool is_last_block ) +{ + if (s->nblock > 0) { + + BZ_FINALISE_CRC ( s->blockCRC ); + s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); + s->combinedCRC ^= s->blockCRC; + if (s->blockNo > 1) s->numZ = 0; + + if (s->verbosity >= 2) + VPrintf4( " block %d: crc = 0x%08x, " + "combined CRC = 0x%08x, size = %d\n", + s->blockNo, s->blockCRC, s->combinedCRC, s->nblock ); + + BZ2_blockSort ( s ); + } + + s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]); + + /*-- If this is the first block, create the stream header. --*/ + if (s->blockNo == 1) { + BZ2_bsInitWrite ( s ); + bsPutUChar ( s, BZ_HDR_B ); + bsPutUChar ( s, BZ_HDR_Z ); + bsPutUChar ( s, BZ_HDR_h ); + bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) ); + } + + if (s->nblock > 0) { + + bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 ); + bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 ); + bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 ); + + /*-- Now the block's CRC, so it is in a known place. --*/ + bsPutUInt32 ( s, s->blockCRC ); + + /*-- + Now a single bit indicating (non-)randomisation. + As of version 0.9.5, we use a better sorting algorithm + which makes randomisation unnecessary. So always set + the randomised bit to 'no'. Of course, the decoder + still needs to be able to handle randomised blocks + so as to maintain backwards compatibility with + older versions of bzip2. + --*/ + bsW(s,1,0); + + bsW ( s, 24, s->origPtr ); + generateMTFValues ( s ); + sendMTFValues ( s ); + } + + + /*-- If this is the last block, add the stream trailer. --*/ + if (is_last_block) { + + bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 ); + bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 ); + bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 ); + bsPutUInt32 ( s, s->combinedCRC ); + if (s->verbosity >= 2) + VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC ); + bsFinishWrite ( s ); + } +} + + +/*-------------------------------------------------------------*/ +/*--- end compress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDisoEFP/src/bzip2/crctable.c b/plugins/CDVDisoEFP/src/bzip2/crctable.c index 26e424299a..b6dadfc62f 100644 --- a/plugins/CDVDisoEFP/src/bzip2/crctable.c +++ b/plugins/CDVDisoEFP/src/bzip2/crctable.c @@ -1,144 +1,144 @@ - -/*-------------------------------------------------------------*/ -/*--- Table for doing CRCs ---*/ -/*--- crctable.c ---*/ -/*-------------------------------------------------------------*/ - -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. - - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ - - -#include "bzlib_private.h" - -/*-- - I think this is an implementation of the AUTODIN-II, - Ethernet & FDDI 32-bit CRC standard. Vaguely derived - from code by Rob Warnock, in Section 51 of the - comp.compression FAQ. ---*/ - -UInt32 BZ2_crc32Table[256] = { - - /*-- Ugly, innit? --*/ - - 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, - 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, - 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, - 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, - 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, - 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, - 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, - 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, - 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, - 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, - 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, - 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, - 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, - 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, - 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, - 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, - 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, - 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, - 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, - 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, - 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, - 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, - 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, - 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, - 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, - 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, - 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, - 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, - 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, - 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, - 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, - 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, - 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, - 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, - 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, - 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, - 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, - 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, - 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, - 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, - 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, - 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, - 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, - 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, - 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, - 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, - 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, - 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, - 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, - 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, - 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, - 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, - 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, - 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, - 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, - 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, - 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, - 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, - 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, - 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, - 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, - 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, - 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, - 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L -}; - - -/*-------------------------------------------------------------*/ -/*--- end crctable.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Table for doing CRCs ---*/ +/*--- crctable.c ---*/ +/*-------------------------------------------------------------*/ + +/*-- + This file is a part of bzip2 and/or libbzip2, a program and + library for lossless, block-sorting data compression. + + Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Julian Seward, Cambridge, UK. + jseward@bzip.org + bzip2/libbzip2 version 1.0 of 21 March 2000 + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the manual. +--*/ + + +#include "bzlib_private.h" + +/*-- + I think this is an implementation of the AUTODIN-II, + Ethernet & FDDI 32-bit CRC standard. Vaguely derived + from code by Rob Warnock, in Section 51 of the + comp.compression FAQ. +--*/ + +UInt32 BZ2_crc32Table[256] = { + + /*-- Ugly, innit? --*/ + + 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, + 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, + 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, + 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, + 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, + 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, + 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, + 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, + 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, + 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, + 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, + 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, + 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, + 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, + 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, + 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, + 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, + 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, + 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, + 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, + 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, + 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, + 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, + 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, + 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, + 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, + 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, + 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, + 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, + 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, + 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, + 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, + 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, + 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, + 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, + 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, + 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, + 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, + 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, + 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, + 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, + 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, + 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, + 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, + 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, + 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, + 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, + 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, + 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, + 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, + 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, + 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, + 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, + 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, + 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, + 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, + 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, + 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, + 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, + 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, + 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, + 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, + 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, + 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L +}; + + +/*-------------------------------------------------------------*/ +/*--- end crctable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDisoEFP/src/bzip2/decompress.c b/plugins/CDVDisoEFP/src/bzip2/decompress.c index ce02afa1cc..81c3d2cc3f 100644 --- a/plugins/CDVDisoEFP/src/bzip2/decompress.c +++ b/plugins/CDVDisoEFP/src/bzip2/decompress.c @@ -1,666 +1,666 @@ - -/*-------------------------------------------------------------*/ -/*--- Decompression machinery ---*/ -/*--- decompress.c ---*/ -/*-------------------------------------------------------------*/ - -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. - - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ - - -#include "bzlib_private.h" - - -/*---------------------------------------------------*/ -static -void makeMaps_d ( DState* s ) -{ - Int32 i; - s->nInUse = 0; - for (i = 0; i < 256; i++) - if (s->inUse[i]) { - s->seqToUnseq[s->nInUse] = i; - s->nInUse++; - } -} - - -/*---------------------------------------------------*/ -#define RETURN(rrr) \ - { retVal = rrr; goto save_state_and_return; }; - -#define GET_BITS(lll,vvv,nnn) \ - case lll: s->state = lll; \ - while (True) { \ - if (s->bsLive >= nnn) { \ - UInt32 v; \ - v = (s->bsBuff >> \ - (s->bsLive-nnn)) & ((1 << nnn)-1); \ - s->bsLive -= nnn; \ - vvv = v; \ - break; \ - } \ - if (s->strm->avail_in == 0) RETURN(BZ_OK); \ - s->bsBuff \ - = (s->bsBuff << 8) | \ - ((UInt32) \ - (*((UChar*)(s->strm->next_in)))); \ - s->bsLive += 8; \ - s->strm->next_in++; \ - s->strm->avail_in--; \ - s->strm->total_in_lo32++; \ - if (s->strm->total_in_lo32 == 0) \ - s->strm->total_in_hi32++; \ - } - -#define GET_UCHAR(lll,uuu) \ - GET_BITS(lll,uuu,8) - -#define GET_BIT(lll,uuu) \ - GET_BITS(lll,uuu,1) - -/*---------------------------------------------------*/ -#define GET_MTF_VAL(label1,label2,lval) \ -{ \ - if (groupPos == 0) { \ - groupNo++; \ - if (groupNo >= nSelectors) \ - RETURN(BZ_DATA_ERROR); \ - groupPos = BZ_G_SIZE; \ - gSel = s->selector[groupNo]; \ - gMinlen = s->minLens[gSel]; \ - gLimit = &(s->limit[gSel][0]); \ - gPerm = &(s->perm[gSel][0]); \ - gBase = &(s->base[gSel][0]); \ - } \ - groupPos--; \ - zn = gMinlen; \ - GET_BITS(label1, zvec, zn); \ - while (1) { \ - if (zn > 20 /* the longest code */) \ - RETURN(BZ_DATA_ERROR); \ - if (zvec <= gLimit[zn]) break; \ - zn++; \ - GET_BIT(label2, zj); \ - zvec = (zvec << 1) | zj; \ - }; \ - if (zvec - gBase[zn] < 0 \ - || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \ - RETURN(BZ_DATA_ERROR); \ - lval = gPerm[zvec - gBase[zn]]; \ -} - - -/*---------------------------------------------------*/ -Int32 BZ2_decompress ( DState* s ) -{ - UChar uc; - Int32 retVal; - Int32 minLen, maxLen; - bz_stream* strm = s->strm; - - /* stuff that needs to be saved/restored */ - Int32 i; - Int32 j; - Int32 t; - Int32 alphaSize; - Int32 nGroups; - Int32 nSelectors; - Int32 EOB; - Int32 groupNo; - Int32 groupPos; - Int32 nextSym; - Int32 nblockMAX; - Int32 nblock; - Int32 es; - Int32 N; - Int32 curr; - Int32 zt; - Int32 zn; - Int32 zvec; - Int32 zj; - Int32 gSel; - Int32 gMinlen; - Int32* gLimit; - Int32* gBase; - Int32* gPerm; - - if (s->state == BZ_X_MAGIC_1) { - /*initialise the save area*/ - s->save_i = 0; - s->save_j = 0; - s->save_t = 0; - s->save_alphaSize = 0; - s->save_nGroups = 0; - s->save_nSelectors = 0; - s->save_EOB = 0; - s->save_groupNo = 0; - s->save_groupPos = 0; - s->save_nextSym = 0; - s->save_nblockMAX = 0; - s->save_nblock = 0; - s->save_es = 0; - s->save_N = 0; - s->save_curr = 0; - s->save_zt = 0; - s->save_zn = 0; - s->save_zvec = 0; - s->save_zj = 0; - s->save_gSel = 0; - s->save_gMinlen = 0; - s->save_gLimit = NULL; - s->save_gBase = NULL; - s->save_gPerm = NULL; - } - - /*restore from the save area*/ - i = s->save_i; - j = s->save_j; - t = s->save_t; - alphaSize = s->save_alphaSize; - nGroups = s->save_nGroups; - nSelectors = s->save_nSelectors; - EOB = s->save_EOB; - groupNo = s->save_groupNo; - groupPos = s->save_groupPos; - nextSym = s->save_nextSym; - nblockMAX = s->save_nblockMAX; - nblock = s->save_nblock; - es = s->save_es; - N = s->save_N; - curr = s->save_curr; - zt = s->save_zt; - zn = s->save_zn; - zvec = s->save_zvec; - zj = s->save_zj; - gSel = s->save_gSel; - gMinlen = s->save_gMinlen; - gLimit = s->save_gLimit; - gBase = s->save_gBase; - gPerm = s->save_gPerm; - - retVal = BZ_OK; - - switch (s->state) { - - GET_UCHAR(BZ_X_MAGIC_1, uc); - if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC); - - GET_UCHAR(BZ_X_MAGIC_2, uc); - if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC); - - GET_UCHAR(BZ_X_MAGIC_3, uc) - if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC); - - GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8) - if (s->blockSize100k < (BZ_HDR_0 + 1) || - s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC); - s->blockSize100k -= BZ_HDR_0; - - if (s->smallDecompress) { - s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) ); - s->ll4 = BZALLOC( - ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) - ); - if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR); - } else { - s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) ); - if (s->tt == NULL) RETURN(BZ_MEM_ERROR); - } - - GET_UCHAR(BZ_X_BLKHDR_1, uc); - - if (uc == 0x17) goto endhdr_2; - if (uc != 0x31) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_2, uc); - if (uc != 0x41) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_3, uc); - if (uc != 0x59) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_4, uc); - if (uc != 0x26) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_5, uc); - if (uc != 0x53) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_6, uc); - if (uc != 0x59) RETURN(BZ_DATA_ERROR); - - s->currBlockNo++; - if (s->verbosity >= 2) - VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo ); - - s->storedBlockCRC = 0; - GET_UCHAR(BZ_X_BCRC_1, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_BCRC_2, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_BCRC_3, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_BCRC_4, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - - GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1); - - s->origPtr = 0; - GET_UCHAR(BZ_X_ORIGPTR_1, uc); - s->origPtr = (s->origPtr << 8) | ((Int32)uc); - GET_UCHAR(BZ_X_ORIGPTR_2, uc); - s->origPtr = (s->origPtr << 8) | ((Int32)uc); - GET_UCHAR(BZ_X_ORIGPTR_3, uc); - s->origPtr = (s->origPtr << 8) | ((Int32)uc); - - if (s->origPtr < 0) - RETURN(BZ_DATA_ERROR); - if (s->origPtr > 10 + 100000*s->blockSize100k) - RETURN(BZ_DATA_ERROR); - - /*--- Receive the mapping table ---*/ - for (i = 0; i < 16; i++) { - GET_BIT(BZ_X_MAPPING_1, uc); - if (uc == 1) - s->inUse16[i] = True; else - s->inUse16[i] = False; - } - - for (i = 0; i < 256; i++) s->inUse[i] = False; - - for (i = 0; i < 16; i++) - if (s->inUse16[i]) - for (j = 0; j < 16; j++) { - GET_BIT(BZ_X_MAPPING_2, uc); - if (uc == 1) s->inUse[i * 16 + j] = True; - } - makeMaps_d ( s ); - if (s->nInUse == 0) RETURN(BZ_DATA_ERROR); - alphaSize = s->nInUse+2; - - /*--- Now the selectors ---*/ - GET_BITS(BZ_X_SELECTOR_1, nGroups, 3); - if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR); - GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15); - if (nSelectors < 1) RETURN(BZ_DATA_ERROR); - for (i = 0; i < nSelectors; i++) { - j = 0; - while (True) { - GET_BIT(BZ_X_SELECTOR_3, uc); - if (uc == 0) break; - j++; - if (j >= nGroups) RETURN(BZ_DATA_ERROR); - } - s->selectorMtf[i] = j; - } - - /*--- Undo the MTF values for the selectors. ---*/ - { - UChar pos[BZ_N_GROUPS], tmp, v; - for (v = 0; v < nGroups; v++) pos[v] = v; - - for (i = 0; i < nSelectors; i++) { - v = s->selectorMtf[i]; - tmp = pos[v]; - while (v > 0) { pos[v] = pos[v-1]; v--; } - pos[0] = tmp; - s->selector[i] = tmp; - } - } - - /*--- Now the coding tables ---*/ - for (t = 0; t < nGroups; t++) { - GET_BITS(BZ_X_CODING_1, curr, 5); - for (i = 0; i < alphaSize; i++) { - while (True) { - if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR); - GET_BIT(BZ_X_CODING_2, uc); - if (uc == 0) break; - GET_BIT(BZ_X_CODING_3, uc); - if (uc == 0) curr++; else curr--; - } - s->len[t][i] = curr; - } - } - - /*--- Create the Huffman decoding tables ---*/ - for (t = 0; t < nGroups; t++) { - minLen = 32; - maxLen = 0; - for (i = 0; i < alphaSize; i++) { - if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; - if (s->len[t][i] < minLen) minLen = s->len[t][i]; - } - BZ2_hbCreateDecodeTables ( - &(s->limit[t][0]), - &(s->base[t][0]), - &(s->perm[t][0]), - &(s->len[t][0]), - minLen, maxLen, alphaSize - ); - s->minLens[t] = minLen; - } - - /*--- Now the MTF values ---*/ - - EOB = s->nInUse+1; - nblockMAX = 100000 * s->blockSize100k; - groupNo = -1; - groupPos = 0; - - for (i = 0; i <= 255; i++) s->unzftab[i] = 0; - - /*-- MTF init --*/ - { - Int32 ii, jj, kk; - kk = MTFA_SIZE-1; - for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) { - for (jj = MTFL_SIZE-1; jj >= 0; jj--) { - s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj); - kk--; - } - s->mtfbase[ii] = kk + 1; - } - } - /*-- end MTF init --*/ - - nblock = 0; - GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym); - - while (True) { - - if (nextSym == EOB) break; - - if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) { - - es = -1; - N = 1; - do { - if (nextSym == BZ_RUNA) es = es + (0+1) * N; else - if (nextSym == BZ_RUNB) es = es + (1+1) * N; - N = N * 2; - GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym); - } - while (nextSym == BZ_RUNA || nextSym == BZ_RUNB); - - es++; - uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ]; - s->unzftab[uc] += es; - - if (s->smallDecompress) - while (es > 0) { - if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); - s->ll16[nblock] = (UInt16)uc; - nblock++; - es--; - } - else - while (es > 0) { - if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); - s->tt[nblock] = (UInt32)uc; - nblock++; - es--; - }; - - continue; - - } else { - - if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); - - /*-- uc = MTF ( nextSym-1 ) --*/ - { - Int32 ii, jj, kk, pp, lno, off; - UInt32 nn; - nn = (UInt32)(nextSym - 1); - - if (nn < MTFL_SIZE) { - /* avoid general-case expense */ - pp = s->mtfbase[0]; - uc = s->mtfa[pp+nn]; - while (nn > 3) { - Int32 z = pp+nn; - s->mtfa[(z) ] = s->mtfa[(z)-1]; - s->mtfa[(z)-1] = s->mtfa[(z)-2]; - s->mtfa[(z)-2] = s->mtfa[(z)-3]; - s->mtfa[(z)-3] = s->mtfa[(z)-4]; - nn -= 4; - } - while (nn > 0) { - s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; - }; - s->mtfa[pp] = uc; - } else { - /* general case */ - lno = nn / MTFL_SIZE; - off = nn % MTFL_SIZE; - pp = s->mtfbase[lno] + off; - uc = s->mtfa[pp]; - while (pp > s->mtfbase[lno]) { - s->mtfa[pp] = s->mtfa[pp-1]; pp--; - }; - s->mtfbase[lno]++; - while (lno > 0) { - s->mtfbase[lno]--; - s->mtfa[s->mtfbase[lno]] - = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1]; - lno--; - } - s->mtfbase[0]--; - s->mtfa[s->mtfbase[0]] = uc; - if (s->mtfbase[0] == 0) { - kk = MTFA_SIZE-1; - for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) { - for (jj = MTFL_SIZE-1; jj >= 0; jj--) { - s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj]; - kk--; - } - s->mtfbase[ii] = kk + 1; - } - } - } - } - /*-- end uc = MTF ( nextSym-1 ) --*/ - - s->unzftab[s->seqToUnseq[uc]]++; - if (s->smallDecompress) - s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else - s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]); - nblock++; - - GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym); - continue; - } - } - - /* Now we know what nblock is, we can do a better sanity - check on s->origPtr. - */ - if (s->origPtr < 0 || s->origPtr >= nblock) - RETURN(BZ_DATA_ERROR); - - /*-- Set up cftab to facilitate generation of T^(-1) --*/ - s->cftab[0] = 0; - for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1]; - for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1]; - for (i = 0; i <= 256; i++) { - if (s->cftab[i] < 0 || s->cftab[i] > nblock) { - /* s->cftab[i] can legitimately be == nblock */ - RETURN(BZ_DATA_ERROR); - } - } - - s->state_out_len = 0; - s->state_out_ch = 0; - BZ_INITIALISE_CRC ( s->calculatedBlockCRC ); - s->state = BZ_X_OUTPUT; - if (s->verbosity >= 2) VPrintf0 ( "rt+rld" ); - - if (s->smallDecompress) { - - /*-- Make a copy of cftab, used in generation of T --*/ - for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i]; - - /*-- compute the T vector --*/ - for (i = 0; i < nblock; i++) { - uc = (UChar)(s->ll16[i]); - SET_LL(i, s->cftabCopy[uc]); - s->cftabCopy[uc]++; - } - - /*-- Compute T^(-1) by pointer reversal on T --*/ - i = s->origPtr; - j = GET_LL(i); - do { - Int32 tmp = GET_LL(j); - SET_LL(j, i); - i = j; - j = tmp; - } - while (i != s->origPtr); - - s->tPos = s->origPtr; - s->nblock_used = 0; - if (s->blockRandomised) { - BZ_RAND_INIT_MASK; - BZ_GET_SMALL(s->k0); s->nblock_used++; - BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; - } else { - BZ_GET_SMALL(s->k0); s->nblock_used++; - } - - } else { - - /*-- compute the T^(-1) vector --*/ - for (i = 0; i < nblock; i++) { - uc = (UChar)(s->tt[i] & 0xff); - s->tt[s->cftab[uc]] |= (i << 8); - s->cftab[uc]++; - } - - s->tPos = s->tt[s->origPtr] >> 8; - s->nblock_used = 0; - if (s->blockRandomised) { - BZ_RAND_INIT_MASK; - BZ_GET_FAST(s->k0); s->nblock_used++; - BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; - } else { - BZ_GET_FAST(s->k0); s->nblock_used++; - } - - } - - RETURN(BZ_OK); - - - - endhdr_2: - - GET_UCHAR(BZ_X_ENDHDR_2, uc); - if (uc != 0x72) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_3, uc); - if (uc != 0x45) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_4, uc); - if (uc != 0x38) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_5, uc); - if (uc != 0x50) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_6, uc); - if (uc != 0x90) RETURN(BZ_DATA_ERROR); - - s->storedCombinedCRC = 0; - GET_UCHAR(BZ_X_CCRC_1, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_CCRC_2, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_CCRC_3, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_CCRC_4, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - - s->state = BZ_X_IDLE; - RETURN(BZ_STREAM_END); - - default: AssertH ( False, 4001 ); - } - - AssertH ( False, 4002 ); - - save_state_and_return: - - s->save_i = i; - s->save_j = j; - s->save_t = t; - s->save_alphaSize = alphaSize; - s->save_nGroups = nGroups; - s->save_nSelectors = nSelectors; - s->save_EOB = EOB; - s->save_groupNo = groupNo; - s->save_groupPos = groupPos; - s->save_nextSym = nextSym; - s->save_nblockMAX = nblockMAX; - s->save_nblock = nblock; - s->save_es = es; - s->save_N = N; - s->save_curr = curr; - s->save_zt = zt; - s->save_zn = zn; - s->save_zvec = zvec; - s->save_zj = zj; - s->save_gSel = gSel; - s->save_gMinlen = gMinlen; - s->save_gLimit = gLimit; - s->save_gBase = gBase; - s->save_gPerm = gPerm; - - return retVal; -} - - -/*-------------------------------------------------------------*/ -/*--- end decompress.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Decompression machinery ---*/ +/*--- decompress.c ---*/ +/*-------------------------------------------------------------*/ + +/*-- + This file is a part of bzip2 and/or libbzip2, a program and + library for lossless, block-sorting data compression. + + Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Julian Seward, Cambridge, UK. + jseward@bzip.org + bzip2/libbzip2 version 1.0 of 21 March 2000 + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the manual. +--*/ + + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +static +void makeMaps_d ( DState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->seqToUnseq[s->nInUse] = i; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +#define RETURN(rrr) \ + { retVal = rrr; goto save_state_and_return; }; + +#define GET_BITS(lll,vvv,nnn) \ + case lll: s->state = lll; \ + while (True) { \ + if (s->bsLive >= nnn) { \ + UInt32 v; \ + v = (s->bsBuff >> \ + (s->bsLive-nnn)) & ((1 << nnn)-1); \ + s->bsLive -= nnn; \ + vvv = v; \ + break; \ + } \ + if (s->strm->avail_in == 0) RETURN(BZ_OK); \ + s->bsBuff \ + = (s->bsBuff << 8) | \ + ((UInt32) \ + (*((UChar*)(s->strm->next_in)))); \ + s->bsLive += 8; \ + s->strm->next_in++; \ + s->strm->avail_in--; \ + s->strm->total_in_lo32++; \ + if (s->strm->total_in_lo32 == 0) \ + s->strm->total_in_hi32++; \ + } + +#define GET_UCHAR(lll,uuu) \ + GET_BITS(lll,uuu,8) + +#define GET_BIT(lll,uuu) \ + GET_BITS(lll,uuu,1) + +/*---------------------------------------------------*/ +#define GET_MTF_VAL(label1,label2,lval) \ +{ \ + if (groupPos == 0) { \ + groupNo++; \ + if (groupNo >= nSelectors) \ + RETURN(BZ_DATA_ERROR); \ + groupPos = BZ_G_SIZE; \ + gSel = s->selector[groupNo]; \ + gMinlen = s->minLens[gSel]; \ + gLimit = &(s->limit[gSel][0]); \ + gPerm = &(s->perm[gSel][0]); \ + gBase = &(s->base[gSel][0]); \ + } \ + groupPos--; \ + zn = gMinlen; \ + GET_BITS(label1, zvec, zn); \ + while (1) { \ + if (zn > 20 /* the longest code */) \ + RETURN(BZ_DATA_ERROR); \ + if (zvec <= gLimit[zn]) break; \ + zn++; \ + GET_BIT(label2, zj); \ + zvec = (zvec << 1) | zj; \ + }; \ + if (zvec - gBase[zn] < 0 \ + || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \ + RETURN(BZ_DATA_ERROR); \ + lval = gPerm[zvec - gBase[zn]]; \ +} + + +/*---------------------------------------------------*/ +Int32 BZ2_decompress ( DState* s ) +{ + UChar uc; + Int32 retVal; + Int32 minLen, maxLen; + bz_stream* strm = s->strm; + + /* stuff that needs to be saved/restored */ + Int32 i; + Int32 j; + Int32 t; + Int32 alphaSize; + Int32 nGroups; + Int32 nSelectors; + Int32 EOB; + Int32 groupNo; + Int32 groupPos; + Int32 nextSym; + Int32 nblockMAX; + Int32 nblock; + Int32 es; + Int32 N; + Int32 curr; + Int32 zt; + Int32 zn; + Int32 zvec; + Int32 zj; + Int32 gSel; + Int32 gMinlen; + Int32* gLimit; + Int32* gBase; + Int32* gPerm; + + if (s->state == BZ_X_MAGIC_1) { + /*initialise the save area*/ + s->save_i = 0; + s->save_j = 0; + s->save_t = 0; + s->save_alphaSize = 0; + s->save_nGroups = 0; + s->save_nSelectors = 0; + s->save_EOB = 0; + s->save_groupNo = 0; + s->save_groupPos = 0; + s->save_nextSym = 0; + s->save_nblockMAX = 0; + s->save_nblock = 0; + s->save_es = 0; + s->save_N = 0; + s->save_curr = 0; + s->save_zt = 0; + s->save_zn = 0; + s->save_zvec = 0; + s->save_zj = 0; + s->save_gSel = 0; + s->save_gMinlen = 0; + s->save_gLimit = NULL; + s->save_gBase = NULL; + s->save_gPerm = NULL; + } + + /*restore from the save area*/ + i = s->save_i; + j = s->save_j; + t = s->save_t; + alphaSize = s->save_alphaSize; + nGroups = s->save_nGroups; + nSelectors = s->save_nSelectors; + EOB = s->save_EOB; + groupNo = s->save_groupNo; + groupPos = s->save_groupPos; + nextSym = s->save_nextSym; + nblockMAX = s->save_nblockMAX; + nblock = s->save_nblock; + es = s->save_es; + N = s->save_N; + curr = s->save_curr; + zt = s->save_zt; + zn = s->save_zn; + zvec = s->save_zvec; + zj = s->save_zj; + gSel = s->save_gSel; + gMinlen = s->save_gMinlen; + gLimit = s->save_gLimit; + gBase = s->save_gBase; + gPerm = s->save_gPerm; + + retVal = BZ_OK; + + switch (s->state) { + + GET_UCHAR(BZ_X_MAGIC_1, uc); + if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_2, uc); + if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_3, uc) + if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8) + if (s->blockSize100k < (BZ_HDR_0 + 1) || + s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC); + s->blockSize100k -= BZ_HDR_0; + + if (s->smallDecompress) { + s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) ); + s->ll4 = BZALLOC( + ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) + ); + if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR); + } else { + s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) ); + if (s->tt == NULL) RETURN(BZ_MEM_ERROR); + } + + GET_UCHAR(BZ_X_BLKHDR_1, uc); + + if (uc == 0x17) goto endhdr_2; + if (uc != 0x31) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_2, uc); + if (uc != 0x41) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_3, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_4, uc); + if (uc != 0x26) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_5, uc); + if (uc != 0x53) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_6, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + + s->currBlockNo++; + if (s->verbosity >= 2) + VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo ); + + s->storedBlockCRC = 0; + GET_UCHAR(BZ_X_BCRC_1, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_2, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_3, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_4, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + + GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1); + + s->origPtr = 0; + GET_UCHAR(BZ_X_ORIGPTR_1, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_2, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_3, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + + if (s->origPtr < 0) + RETURN(BZ_DATA_ERROR); + if (s->origPtr > 10 + 100000*s->blockSize100k) + RETURN(BZ_DATA_ERROR); + + /*--- Receive the mapping table ---*/ + for (i = 0; i < 16; i++) { + GET_BIT(BZ_X_MAPPING_1, uc); + if (uc == 1) + s->inUse16[i] = True; else + s->inUse16[i] = False; + } + + for (i = 0; i < 256; i++) s->inUse[i] = False; + + for (i = 0; i < 16; i++) + if (s->inUse16[i]) + for (j = 0; j < 16; j++) { + GET_BIT(BZ_X_MAPPING_2, uc); + if (uc == 1) s->inUse[i * 16 + j] = True; + } + makeMaps_d ( s ); + if (s->nInUse == 0) RETURN(BZ_DATA_ERROR); + alphaSize = s->nInUse+2; + + /*--- Now the selectors ---*/ + GET_BITS(BZ_X_SELECTOR_1, nGroups, 3); + if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR); + GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15); + if (nSelectors < 1) RETURN(BZ_DATA_ERROR); + for (i = 0; i < nSelectors; i++) { + j = 0; + while (True) { + GET_BIT(BZ_X_SELECTOR_3, uc); + if (uc == 0) break; + j++; + if (j >= nGroups) RETURN(BZ_DATA_ERROR); + } + s->selectorMtf[i] = j; + } + + /*--- Undo the MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], tmp, v; + for (v = 0; v < nGroups; v++) pos[v] = v; + + for (i = 0; i < nSelectors; i++) { + v = s->selectorMtf[i]; + tmp = pos[v]; + while (v > 0) { pos[v] = pos[v-1]; v--; } + pos[0] = tmp; + s->selector[i] = tmp; + } + } + + /*--- Now the coding tables ---*/ + for (t = 0; t < nGroups; t++) { + GET_BITS(BZ_X_CODING_1, curr, 5); + for (i = 0; i < alphaSize; i++) { + while (True) { + if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR); + GET_BIT(BZ_X_CODING_2, uc); + if (uc == 0) break; + GET_BIT(BZ_X_CODING_3, uc); + if (uc == 0) curr++; else curr--; + } + s->len[t][i] = curr; + } + } + + /*--- Create the Huffman decoding tables ---*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + BZ2_hbCreateDecodeTables ( + &(s->limit[t][0]), + &(s->base[t][0]), + &(s->perm[t][0]), + &(s->len[t][0]), + minLen, maxLen, alphaSize + ); + s->minLens[t] = minLen; + } + + /*--- Now the MTF values ---*/ + + EOB = s->nInUse+1; + nblockMAX = 100000 * s->blockSize100k; + groupNo = -1; + groupPos = 0; + + for (i = 0; i <= 255; i++) s->unzftab[i] = 0; + + /*-- MTF init --*/ + { + Int32 ii, jj, kk; + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj); + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + /*-- end MTF init --*/ + + nblock = 0; + GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym); + + while (True) { + + if (nextSym == EOB) break; + + if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) { + + es = -1; + N = 1; + do { + if (nextSym == BZ_RUNA) es = es + (0+1) * N; else + if (nextSym == BZ_RUNB) es = es + (1+1) * N; + N = N * 2; + GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym); + } + while (nextSym == BZ_RUNA || nextSym == BZ_RUNB); + + es++; + uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ]; + s->unzftab[uc] += es; + + if (s->smallDecompress) + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->ll16[nblock] = (UInt16)uc; + nblock++; + es--; + } + else + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->tt[nblock] = (UInt32)uc; + nblock++; + es--; + }; + + continue; + + } else { + + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + + /*-- uc = MTF ( nextSym-1 ) --*/ + { + Int32 ii, jj, kk, pp, lno, off; + UInt32 nn; + nn = (UInt32)(nextSym - 1); + + if (nn < MTFL_SIZE) { + /* avoid general-case expense */ + pp = s->mtfbase[0]; + uc = s->mtfa[pp+nn]; + while (nn > 3) { + Int32 z = pp+nn; + s->mtfa[(z) ] = s->mtfa[(z)-1]; + s->mtfa[(z)-1] = s->mtfa[(z)-2]; + s->mtfa[(z)-2] = s->mtfa[(z)-3]; + s->mtfa[(z)-3] = s->mtfa[(z)-4]; + nn -= 4; + } + while (nn > 0) { + s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; + }; + s->mtfa[pp] = uc; + } else { + /* general case */ + lno = nn / MTFL_SIZE; + off = nn % MTFL_SIZE; + pp = s->mtfbase[lno] + off; + uc = s->mtfa[pp]; + while (pp > s->mtfbase[lno]) { + s->mtfa[pp] = s->mtfa[pp-1]; pp--; + }; + s->mtfbase[lno]++; + while (lno > 0) { + s->mtfbase[lno]--; + s->mtfa[s->mtfbase[lno]] + = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1]; + lno--; + } + s->mtfbase[0]--; + s->mtfa[s->mtfbase[0]] = uc; + if (s->mtfbase[0] == 0) { + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj]; + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + } + } + /*-- end uc = MTF ( nextSym-1 ) --*/ + + s->unzftab[s->seqToUnseq[uc]]++; + if (s->smallDecompress) + s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else + s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]); + nblock++; + + GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym); + continue; + } + } + + /* Now we know what nblock is, we can do a better sanity + check on s->origPtr. + */ + if (s->origPtr < 0 || s->origPtr >= nblock) + RETURN(BZ_DATA_ERROR); + + /*-- Set up cftab to facilitate generation of T^(-1) --*/ + s->cftab[0] = 0; + for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1]; + for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1]; + for (i = 0; i <= 256; i++) { + if (s->cftab[i] < 0 || s->cftab[i] > nblock) { + /* s->cftab[i] can legitimately be == nblock */ + RETURN(BZ_DATA_ERROR); + } + } + + s->state_out_len = 0; + s->state_out_ch = 0; + BZ_INITIALISE_CRC ( s->calculatedBlockCRC ); + s->state = BZ_X_OUTPUT; + if (s->verbosity >= 2) VPrintf0 ( "rt+rld" ); + + if (s->smallDecompress) { + + /*-- Make a copy of cftab, used in generation of T --*/ + for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i]; + + /*-- compute the T vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->ll16[i]); + SET_LL(i, s->cftabCopy[uc]); + s->cftabCopy[uc]++; + } + + /*-- Compute T^(-1) by pointer reversal on T --*/ + i = s->origPtr; + j = GET_LL(i); + do { + Int32 tmp = GET_LL(j); + SET_LL(j, i); + i = j; + j = tmp; + } + while (i != s->origPtr); + + s->tPos = s->origPtr; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_SMALL(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } else { + + /*-- compute the T^(-1) vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->tt[i] & 0xff); + s->tt[s->cftab[uc]] |= (i << 8); + s->cftab[uc]++; + } + + s->tPos = s->tt[s->origPtr] >> 8; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_FAST(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_FAST(s->k0); s->nblock_used++; + } + + } + + RETURN(BZ_OK); + + + + endhdr_2: + + GET_UCHAR(BZ_X_ENDHDR_2, uc); + if (uc != 0x72) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_3, uc); + if (uc != 0x45) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_4, uc); + if (uc != 0x38) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_5, uc); + if (uc != 0x50) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_6, uc); + if (uc != 0x90) RETURN(BZ_DATA_ERROR); + + s->storedCombinedCRC = 0; + GET_UCHAR(BZ_X_CCRC_1, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_2, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_3, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_4, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + + s->state = BZ_X_IDLE; + RETURN(BZ_STREAM_END); + + default: AssertH ( False, 4001 ); + } + + AssertH ( False, 4002 ); + + save_state_and_return: + + s->save_i = i; + s->save_j = j; + s->save_t = t; + s->save_alphaSize = alphaSize; + s->save_nGroups = nGroups; + s->save_nSelectors = nSelectors; + s->save_EOB = EOB; + s->save_groupNo = groupNo; + s->save_groupPos = groupPos; + s->save_nextSym = nextSym; + s->save_nblockMAX = nblockMAX; + s->save_nblock = nblock; + s->save_es = es; + s->save_N = N; + s->save_curr = curr; + s->save_zt = zt; + s->save_zn = zn; + s->save_zvec = zvec; + s->save_zj = zj; + s->save_gSel = gSel; + s->save_gMinlen = gMinlen; + s->save_gLimit = gLimit; + s->save_gBase = gBase; + s->save_gPerm = gPerm; + + return retVal; +} + + +/*-------------------------------------------------------------*/ +/*--- end decompress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDisoEFP/src/bzip2/huffman.c b/plugins/CDVDisoEFP/src/bzip2/huffman.c index a15a2591ab..5bf190be9a 100644 --- a/plugins/CDVDisoEFP/src/bzip2/huffman.c +++ b/plugins/CDVDisoEFP/src/bzip2/huffman.c @@ -1,245 +1,245 @@ - -/*-------------------------------------------------------------*/ -/*--- Huffman coding low-level stuff ---*/ -/*--- huffman.c ---*/ -/*-------------------------------------------------------------*/ - -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. - - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ - - -#include "bzlib_private.h" - -/*---------------------------------------------------*/ -#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) -#define DEPTHOF(zz1) ((zz1) & 0x000000ff) -#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) - -#define ADDWEIGHTS(zw1,zw2) \ - (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ - (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) - -#define UPHEAP(z) \ -{ \ - Int32 zz, tmp; \ - zz = z; tmp = heap[zz]; \ - while (weight[tmp] < weight[heap[zz >> 1]]) { \ - heap[zz] = heap[zz >> 1]; \ - zz >>= 1; \ - } \ - heap[zz] = tmp; \ -} - -#define DOWNHEAP(z) \ -{ \ - Int32 zz, yy, tmp; \ - zz = z; tmp = heap[zz]; \ - while (True) { \ - yy = zz << 1; \ - if (yy > nHeap) break; \ - if (yy < nHeap && \ - weight[heap[yy+1]] < weight[heap[yy]]) \ - yy++; \ - if (weight[tmp] < weight[heap[yy]]) break; \ - heap[zz] = heap[yy]; \ - zz = yy; \ - } \ - heap[zz] = tmp; \ -} - - -/*---------------------------------------------------*/ -void BZ2_hbMakeCodeLengths ( UChar *len, - Int32 *freq, - Int32 alphaSize, - Int32 maxLen ) -{ - /*-- - Nodes and heap entries run from 1. Entry 0 - for both the heap and nodes is a sentinel. - --*/ - Int32 nNodes, nHeap, n1, n2, i, j, k; - Bool tooLong; - - Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ]; - Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ]; - Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; - - for (i = 0; i < alphaSize; i++) - weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; - - while (True) { - - nNodes = alphaSize; - nHeap = 0; - - heap[0] = 0; - weight[0] = 0; - parent[0] = -2; - - for (i = 1; i <= alphaSize; i++) { - parent[i] = -1; - nHeap++; - heap[nHeap] = i; - UPHEAP(nHeap); - } - - AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 ); - - while (nHeap > 1) { - n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); - n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); - nNodes++; - parent[n1] = parent[n2] = nNodes; - weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); - parent[nNodes] = -1; - nHeap++; - heap[nHeap] = nNodes; - UPHEAP(nHeap); - } - - AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 ); - - tooLong = False; - for (i = 1; i <= alphaSize; i++) { - j = 0; - k = i; - while (parent[k] >= 0) { k = parent[k]; j++; } - len[i-1] = j; - if (j > maxLen) tooLong = True; - } - - if (! tooLong) break; - - /* 17 Oct 04: keep-going condition for the following loop used - to be 'i < alphaSize', which missed the last element, - theoretically leading to the possibility of the compressor - looping. However, this count-scaling step is only needed if - one of the generated Huffman code words is longer than - maxLen, which up to and including version 1.0.2 was 20 bits, - which is extremely unlikely. In version 1.0.3 maxLen was - changed to 17 bits, which has minimal effect on compression - ratio, but does mean this scaling step is used from time to - time, enough to verify that it works. - - This means that bzip2-1.0.3 and later will only produce - Huffman codes with a maximum length of 17 bits. However, in - order to preserve backwards compatibility with bitstreams - produced by versions pre-1.0.3, the decompressor must still - handle lengths of up to 20. */ - - for (i = 1; i <= alphaSize; i++) { - j = weight[i] >> 8; - j = 1 + (j / 2); - weight[i] = j << 8; - } - } -} - - -/*---------------------------------------------------*/ -void BZ2_hbAssignCodes ( Int32 *code, - UChar *length, - Int32 minLen, - Int32 maxLen, - Int32 alphaSize ) -{ - Int32 n, vec, i; - - vec = 0; - for (n = minLen; n <= maxLen; n++) { - for (i = 0; i < alphaSize; i++) - if (length[i] == n) { code[i] = vec; vec++; }; - vec <<= 1; - } -} - - -/*---------------------------------------------------*/ -void BZ2_hbCreateDecodeTables ( Int32 *limit, - Int32 *base, - Int32 *perm, - UChar *length, - Int32 minLen, - Int32 maxLen, - Int32 alphaSize ) -{ - Int32 pp, i, j, vec; - - pp = 0; - for (i = minLen; i <= maxLen; i++) - for (j = 0; j < alphaSize; j++) - if (length[j] == i) { perm[pp] = j; pp++; }; - - for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0; - for (i = 0; i < alphaSize; i++) base[length[i]+1]++; - - for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1]; - - for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0; - vec = 0; - - for (i = minLen; i <= maxLen; i++) { - vec += (base[i+1] - base[i]); - limit[i] = vec-1; - vec <<= 1; - } - for (i = minLen + 1; i <= maxLen; i++) - base[i] = ((limit[i-1] + 1) << 1) - base[i]; -} - - -/*-------------------------------------------------------------*/ -/*--- end huffman.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Huffman coding low-level stuff ---*/ +/*--- huffman.c ---*/ +/*-------------------------------------------------------------*/ + +/*-- + This file is a part of bzip2 and/or libbzip2, a program and + library for lossless, block-sorting data compression. + + Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Julian Seward, Cambridge, UK. + jseward@bzip.org + bzip2/libbzip2 version 1.0 of 21 March 2000 + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the manual. +--*/ + + +#include "bzlib_private.h" + +/*---------------------------------------------------*/ +#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) +#define DEPTHOF(zz1) ((zz1) & 0x000000ff) +#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) + +#define ADDWEIGHTS(zw1,zw2) \ + (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ + (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) + +#define UPHEAP(z) \ +{ \ + Int32 zz, tmp; \ + zz = z; tmp = heap[zz]; \ + while (weight[tmp] < weight[heap[zz >> 1]]) { \ + heap[zz] = heap[zz >> 1]; \ + zz >>= 1; \ + } \ + heap[zz] = tmp; \ +} + +#define DOWNHEAP(z) \ +{ \ + Int32 zz, yy, tmp; \ + zz = z; tmp = heap[zz]; \ + while (True) { \ + yy = zz << 1; \ + if (yy > nHeap) break; \ + if (yy < nHeap && \ + weight[heap[yy+1]] < weight[heap[yy]]) \ + yy++; \ + if (weight[tmp] < weight[heap[yy]]) break; \ + heap[zz] = heap[yy]; \ + zz = yy; \ + } \ + heap[zz] = tmp; \ +} + + +/*---------------------------------------------------*/ +void BZ2_hbMakeCodeLengths ( UChar *len, + Int32 *freq, + Int32 alphaSize, + Int32 maxLen ) +{ + /*-- + Nodes and heap entries run from 1. Entry 0 + for both the heap and nodes is a sentinel. + --*/ + Int32 nNodes, nHeap, n1, n2, i, j, k; + Bool tooLong; + + Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ]; + Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ]; + Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; + + for (i = 0; i < alphaSize; i++) + weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; + + while (True) { + + nNodes = alphaSize; + nHeap = 0; + + heap[0] = 0; + weight[0] = 0; + parent[0] = -2; + + for (i = 1; i <= alphaSize; i++) { + parent[i] = -1; + nHeap++; + heap[nHeap] = i; + UPHEAP(nHeap); + } + + AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 ); + + while (nHeap > 1) { + n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + nNodes++; + parent[n1] = parent[n2] = nNodes; + weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); + parent[nNodes] = -1; + nHeap++; + heap[nHeap] = nNodes; + UPHEAP(nHeap); + } + + AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 ); + + tooLong = False; + for (i = 1; i <= alphaSize; i++) { + j = 0; + k = i; + while (parent[k] >= 0) { k = parent[k]; j++; } + len[i-1] = j; + if (j > maxLen) tooLong = True; + } + + if (! tooLong) break; + + /* 17 Oct 04: keep-going condition for the following loop used + to be 'i < alphaSize', which missed the last element, + theoretically leading to the possibility of the compressor + looping. However, this count-scaling step is only needed if + one of the generated Huffman code words is longer than + maxLen, which up to and including version 1.0.2 was 20 bits, + which is extremely unlikely. In version 1.0.3 maxLen was + changed to 17 bits, which has minimal effect on compression + ratio, but does mean this scaling step is used from time to + time, enough to verify that it works. + + This means that bzip2-1.0.3 and later will only produce + Huffman codes with a maximum length of 17 bits. However, in + order to preserve backwards compatibility with bitstreams + produced by versions pre-1.0.3, the decompressor must still + handle lengths of up to 20. */ + + for (i = 1; i <= alphaSize; i++) { + j = weight[i] >> 8; + j = 1 + (j / 2); + weight[i] = j << 8; + } + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbAssignCodes ( Int32 *code, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 n, vec, i; + + vec = 0; + for (n = minLen; n <= maxLen; n++) { + for (i = 0; i < alphaSize; i++) + if (length[i] == n) { code[i] = vec; vec++; }; + vec <<= 1; + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbCreateDecodeTables ( Int32 *limit, + Int32 *base, + Int32 *perm, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 pp, i, j, vec; + + pp = 0; + for (i = minLen; i <= maxLen; i++) + for (j = 0; j < alphaSize; j++) + if (length[j] == i) { perm[pp] = j; pp++; }; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0; + for (i = 0; i < alphaSize; i++) base[length[i]+1]++; + + for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1]; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0; + vec = 0; + + for (i = minLen; i <= maxLen; i++) { + vec += (base[i+1] - base[i]); + limit[i] = vec-1; + vec <<= 1; + } + for (i = minLen + 1; i <= maxLen; i++) + base[i] = ((limit[i-1] + 1) << 1) - base[i]; +} + + +/*-------------------------------------------------------------*/ +/*--- end huffman.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDisoEFP/src/bzip2/randtable.c b/plugins/CDVDisoEFP/src/bzip2/randtable.c index 27b28d1ab8..940462d693 100644 --- a/plugins/CDVDisoEFP/src/bzip2/randtable.c +++ b/plugins/CDVDisoEFP/src/bzip2/randtable.c @@ -1,124 +1,124 @@ - -/*-------------------------------------------------------------*/ -/*--- Table for randomising repetitive blocks ---*/ -/*--- randtable.c ---*/ -/*-------------------------------------------------------------*/ - -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. - - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ - - -#include "bzlib_private.h" - - -/*---------------------------------------------*/ -Int32 BZ2_rNums[512] = { - 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, - 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, - 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, - 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, - 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, - 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, - 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, - 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, - 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, - 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, - 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, - 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, - 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, - 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, - 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, - 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, - 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, - 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, - 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, - 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, - 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, - 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, - 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, - 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, - 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, - 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, - 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, - 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, - 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, - 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, - 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, - 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, - 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, - 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, - 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, - 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, - 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, - 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, - 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, - 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, - 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, - 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, - 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, - 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, - 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, - 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, - 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, - 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, - 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, - 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, - 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, - 936, 638 -}; - - -/*-------------------------------------------------------------*/ -/*--- end randtable.c ---*/ -/*-------------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/*--- Table for randomising repetitive blocks ---*/ +/*--- randtable.c ---*/ +/*-------------------------------------------------------------*/ + +/*-- + This file is a part of bzip2 and/or libbzip2, a program and + library for lossless, block-sorting data compression. + + Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Julian Seward, Cambridge, UK. + jseward@bzip.org + bzip2/libbzip2 version 1.0 of 21 March 2000 + + This program is based on (at least) the work of: + Mike Burrows + David Wheeler + Peter Fenwick + Alistair Moffat + Radford Neal + Ian H. Witten + Robert Sedgewick + Jon L. Bentley + + For more information on these sources, see the manual. +--*/ + + +#include "bzlib_private.h" + + +/*---------------------------------------------*/ +Int32 BZ2_rNums[512] = { + 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, + 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, + 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, + 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, + 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, + 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, + 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, + 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, + 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, + 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, + 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, + 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, + 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, + 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, + 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, + 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, + 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, + 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, + 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, + 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, + 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, + 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, + 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, + 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, + 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, + 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, + 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, + 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, + 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, + 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, + 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, + 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, + 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, + 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, + 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, + 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, + 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, + 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, + 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, + 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, + 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, + 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, + 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, + 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, + 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, + 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, + 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, + 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, + 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, + 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, + 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, + 936, 638 +}; + + +/*-------------------------------------------------------------*/ +/*--- end randtable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDisoEFP/src/bzip2v2.c b/plugins/CDVDisoEFP/src/bzip2v2.c index e93811af03..5c7ef0baad 100644 --- a/plugins/CDVDisoEFP/src/bzip2v2.c +++ b/plugins/CDVDisoEFP/src/bzip2v2.c @@ -1,1052 +1,1052 @@ -/* bzip2v2.c - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#include // NULL - -#include // malloc() - -#include // off64_t - - - -#include "bzip2/bzlib.h" - - - -#include "convert.h" - -#include "logfile.h" - -#include "isofile.h" // IsoFile - -#include "isocompress.h" // TableData, TableMap - -#include "actualfile.h" - -// #include "convert.h" - -#include "bzip2v2.h" - - - - - -#ifdef _WIN32 - -#pragma pack(1) - -#endif /* _WIN32 */ - - - -struct BZip2V2Header { - - char id[4]; - - unsigned int blocksize; - - unsigned int numblocks; - - unsigned int blockoffset; - -#ifdef _WIN32 - -}; - -#else - -} __attribute__ ((packed)); - -#endif /* _WIN32 */ - - - -struct BZip2V2Table { - - unsigned int size; - -#ifdef _WIN32 - -}; - -#else - -} __attribute__ ((packed)); - -#endif /* _WIN32 */ - - - -#ifdef _WIN32 - -#pragma pack() - -#endif /* _WIN32 */ - - - - - -int BZip2V2OpenTableForRead(struct IsoFile *isofile) { - - int i; - - int j; - - char tableext[] = ".table\0"; - - off64_t numentries; - - off64_t offset; - - off64_t actual; - - int tableoffset; - - struct BZip2V2Table table; - - int retval; - - union TableMap tablemap; - - - -#ifdef VERBOSE_FUNCTION_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: OpenTableForRead()"); - -#endif /* VERBOSE_FUNCTION_BZIP2V2 */ - - - - i = 0; - - while((i < 256) && (isofile->name[i] != 0)) { - - isofile->tablename[i] = isofile->name[i]; - - i++; - - } // ENDWHILE- Copying the data name to the table name - - j = 0; - - while((i < 256) && (tableext[j] != 0)) { - - isofile->tablename[i] = tableext[j]; - - i++; - - j++; - - } // ENDWHILE- Adding the ".table" extension. - - isofile->tablename[i] = 0; // And 0-terminate. - - - - isofile->tablehandle = ActualFileOpenForRead(isofile->tablename); - - if(isofile->tablehandle == ACTUALHANDLENULL) { - -#ifdef VERBOSE_WARNING_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: Couldn't open table!"); - -#endif /* VERBOSE_WARNING_BZIP2V2 */ - - return(-2); - - } // ENDIF- Couldn't open table file? Fail. - - - - numentries = isofile->filesectorsize / 16; - - if((isofile->filesectorsize % 16) != 0) numentries++; - - offset = numentries * sizeof(struct BZip2V2Table); - - actual = ActualFileSize(isofile->tablehandle); - - if(offset != actual) { - -#ifdef VERBOSE_WARNING_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: Table not the correct size! (Should be %lli, is %lli)", - - offset, actual); - -#endif /* VERBOSE_WARNING_BZIP2V2 */ - - return(-2); - - } // ENDIF- Not the correct-sized table for the data file? Fail. - - - - // We pre-read the WHOLE offset table. - - isofile->tabledata = (char *) malloc(numentries * sizeof(struct TableData)); - - if(isofile->tabledata == NULL) { - -#ifdef VERBOSE_WARNING_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: Couldn't allocate internal table!"); - -#endif /* VERBOSE_WARNING_BZIP2V2 */ - - return(-2); - - } // ENDIF- Could not get enough memory to hold table data - - - - offset = sizeof(struct BZip2V2Header); - - tableoffset = 0; - - for(i = 0; i < numentries; i++) { - - retval = ActualFileRead(isofile->tablehandle, - - sizeof(struct BZip2V2Table), - - (char *) &table); - - if(retval != sizeof(struct BZip2V2Table)) { - -#ifdef VERBOSE_WARNING_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: Failed to read in entry %i!", i); - -#endif /* VERBOSE_WARNING_BZIP2V2 */ - - return(-2); - - } // ENDIF- Trouble reading in a size? Table damaged... fail. - - - - tablemap.table.offset = offset; - - tablemap.table.size = ConvertEndianUInt(table.size); - - for(j = 0; j < sizeof(struct TableData); j++) - - *(isofile->tabledata + tableoffset + j) = tablemap.ch[j]; - - offset += tablemap.table.size; - - tableoffset += sizeof(struct TableData); - - } // NEXT i- reading in the sizes, and making offset as I go. - - - - ActualFileClose(isofile->tablehandle); - - isofile->tablehandle = ACTUALHANDLENULL; - - return(0); - -} // END BZip2V2OpenTableForRead() - - - - - -int BZip2V2SeekTable(struct IsoFile *isofile, off64_t sector) { - -#ifdef VERBOSE_FUNCTION_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: SeekTable(%lli)", sector); - -#endif /* VERBOSE_FUNCTION_BZIP2V2 */ - - - - isofile->filesectorpos = sector; - - isofile->compsector = isofile->filesectorsize + isofile->numsectors; - - return(0); - -} // END BZip2V2SeekTable() - - - - - -int BZip2V2ReadTable(struct IsoFile *isofile, struct TableData *table) { - - off64_t target; - - union TableMap tablemap; - - off64_t i; - - - -#ifdef VERBOSE_FUNCTION_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: ReadTable()"); - -#endif /* VERBOSE_FUNCTION_BZIP2V2 */ - - - - target = (isofile->filesectorpos / isofile->numsectors) - - * sizeof(struct TableData); - - for(i = 0; i < sizeof(struct TableData); i++) - - tablemap.ch[i] = *(isofile->tabledata + target + i); - - - - table->offset = tablemap.table.offset; - - table->size = tablemap.table.size; - - return(0); - -} // END BZip2V2ReadTable() - - - - - -int BZip2V2OpenTableForWrite(struct IsoFile *isofile) { - - int i; - - int j; - - char tableext[] = ".table\0"; - - - -#ifdef VERBOSE_FUNCTION_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: OpenTableForWrite()"); - -#endif /* VERBOSE_FUNCTION_BZIP2V2 */ - - - - i = 0; - - while((i < 256) && (isofile->name[i] != 0)) { - - isofile->tablename[i] = isofile->name[i]; - - i++; - - } // ENDWHILE- Copying the data name to the table name - - j = 0; - - while((i < 256) && (tableext[j] != 0)) { - - isofile->tablename[i] = tableext[j]; - - i++; - - j++; - - } // ENDWHILE- Adding the ".table" extension. - - isofile->tablename[i] = 0; // And 0-terminate. - - - - isofile->tablehandle = ActualFileOpenForWrite(isofile->tablename); - - if(isofile->tablehandle == ACTUALHANDLENULL) { - -#ifdef VERBOSE_WARNING_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: Couldn't open table!"); - -#endif /* VERBOSE_WARNING_BZIP2V2 */ - - return(-2); - - } // ENDIF- Couldn't open table file? Fail. - - - - // isofile->filesectorsize = 0; - - return(0); - -} // END BZip2V2OpenTableForWrite() - - - - - -int BZip2V2WriteTable(struct IsoFile *isofile, struct TableData table) { - - int retval; - - struct BZip2V2Table bv2table; - - unsigned int tempint; - - - -#ifdef VERBOSE_FUNCTION_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: WriteTable(%lli, %i)", table.offset, table.size); - -#endif /* VERBOSE_FUNCTION_BZIP2V2 */ - - - - tempint = table.size; - - bv2table.size = ConvertEndianUInt(tempint); - - retval = ActualFileWrite(isofile->tablehandle, - - sizeof(struct BZip2V2Table), - - (char *) &bv2table); - - if(retval != sizeof(struct BZip2V2Table)) { - -#ifdef VERBOSE_WARNING_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: Couldn't write table entry!"); - -#endif /* VERBOSE_WARNING_BZIP2V2 */ - - return(-2); - - } // ENDIF- Trouble reading table entry? Fail. - - - - return(0); - -} // END BZip2V2WriteTable() - - - - - -int BZip2V2OpenForRead(struct IsoFile *isofile) { - - int retval; - - struct BZip2V2Header header; - - - -#ifdef VERBOSE_FUNCTION_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: OpenForRead()"); - -#endif /* VERBOSE_FUNCTION_BZIP2V2 */ - - - - isofile->handle = ActualFileOpenForRead(isofile->name); - - if(isofile->handle == ACTUALHANDLENULL) { - - return(-1); - - } // ENDIF- Couldn't open data file? Fail. - - - - isofile->filebytesize = ActualFileSize(isofile->handle); - - isofile->filebytepos = 0; - - isofile->filesectorpos = 0; - - - - isofile->imageheader = 0; - - isofile->numsectors = 16; // Sectors per block - - - - retval = ActualFileRead(isofile->handle, - - sizeof(struct BZip2V2Header), - - (char *) &header); - - if(retval != sizeof(struct BZip2V2Header)) { - -#ifdef VERBOSE_WARNING_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: Couldn't read header!"); - -#endif /* VERBOSE_WARNING_BZIP2V2 */ - - ActualFileClose(isofile->handle); - - isofile->handle = ACTUALHANDLENULL; - - return(-1); - - } // ENDIF Could not read the first sector? Fail. - - isofile->filebytepos += retval; - - - - if((header.id[0] != 'B') || - - (header.id[1] != 'Z') || - - (header.id[2] != 'V') || - - (header.id[3] != '2')) { - -#ifdef VERBOSE_WARNING_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: Not a bzip2 v2 compression header!"); - -#endif /* VERBOSE_WARNING_BZIP2V2 */ - - ActualFileClose(isofile->handle); - - isofile->handle = ACTUALHANDLENULL; - - return(-1); - - } // ENDIF- ID for this compression type doesn't match? - - - - isofile->blocksize = ConvertEndianUInt(header.blocksize); - - isofile->filesectorsize = ConvertEndianUInt(header.numblocks); - - isofile->blockoffset = ConvertEndianUInt(header.blockoffset); - - isofile->filesectorpos = 0; - - isofile->compsector = header.numblocks + isofile->numsectors; - - return(0); - -} // END BZip2V2OpenForRead() - - - - - -int BZip2V2Seek(struct IsoFile *isofile, off64_t position) { - - int retval; - - - -#ifdef VERBOSE_FUNCTION_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: Seek(%lli)", position); - -#endif /* VERBOSE_FUNCTION_BZIP2V2 */ - - - - retval = ActualFileSeek(isofile->handle, position); - - if(retval < 0) { - -#ifdef VERBOSE_WARNING_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: Couldn't find the start of the compressed block!"); - -#endif /* VERBOSE_WARNING_BZIP2V2 */ - - return(-1); - - } // ENDIF- Couldn't find the data entry? Fail. - - isofile->filebytepos = position; - - return(0); - - - - return(-1); // Fail. (Due to lack of ambition?) - -} // END BZip2V2Seek() - - - - - -int BZip2V2Read(struct IsoFile *isofile, int bytes, char *buffer) { - - int retval; - - unsigned int blocklen; - - bz_stream strm; - - unsigned int tempin; - - char tempblock[65536]; - - unsigned int tempout; - - - -#ifdef VERBOSE_FUNCTION_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: Read(%i)", bytes); - -#endif /* VERBOSE_FUNCTION_BZIP2V2 */ - - - - if(bytes > 0) { - - retval = ActualFileRead(isofile->handle, bytes, tempblock); - - if(retval > 0) isofile->filebytepos += retval; - - if(retval != bytes) { - -#ifdef VERBOSE_WARNING_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: Cannot read bytes! Returned: (%i)", retval); - -#endif /* VERBOSE_WARNING_BZIP2V2 */ - - return(-1); - - } // ENDIF- Trouble reading compressed sector? Abort. - - - - blocklen = 65536; - - retval = BZ2_bzBuffToBuffDecompress(buffer, &blocklen, tempblock, bytes, 0, 0); - - if(retval != BZ_OK) { - -#ifdef VERBOSE_WARNING_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: Cannot decode block! Returned: (%i)", retval); - -#endif /* VERBOSE_WARNING_BZIP2V2 */ - - return(-1); - - } // ENDIF- Trouble decoding the sector? Abort. - - - - return(0); - - } // ENDIF- Do we know how many compressed bytes to get for this record? - - - - // Hmm. Don't know the compressed size? Well, we'll just have to find it. - - - - tempin = 0; - - tempout = 0; - - retval = BZ_OK; - - while((tempin < 65536) && (tempout < isofile->blocksize * isofile->numsectors)) { - - strm.bzalloc = NULL; - - strm.bzfree = NULL; - - strm.opaque = NULL; - - retval = BZ2_bzDecompressInit ( &strm, 0, 0 ); - - if (retval != BZ_OK) return(-1); - - - - strm.next_out = buffer; - - - - strm.avail_in = tempin; - - strm.avail_out = 65536; - - - - retval = BZ_OK; - - while((tempin < 65536) && (retval == BZ_OK)) { - - retval = ActualFileRead(isofile->handle, 1, &tempblock[tempin]); - - if(retval != 1) { - -#ifdef VERBOSE_WARNING_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: Cannot read a byte! Returned: (%i)", retval); - -#endif /* VERBOSE_WARNING_BZIP2V2 */ - - BZ2_bzDecompressEnd(&strm); - - return(-1); - - } // ENDIF- Trouble reading a piece of compressed sector? Abort. - - tempin++; - - strm.avail_in++; - - - - strm.next_in = &tempblock[tempin - strm.avail_in]; - - retval = BZ2_bzDecompress(&strm); - - } // ENDWHILE- trying to uncompress an increasingly filled buffer - - tempout = 65536 - strm.avail_out; - - BZ2_bzDecompressEnd(&strm); - - - - } // ENDWHILE- trying to uncompress a whole buffer - - if(retval != BZ_STREAM_END) { - -#ifdef VERBOSE_WARNING_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: Failed to decode block! (Returned %i", retval); - -#endif /* VERBOSE_WARNING_BZIP2V2 */ - - return(-1); - - } // ENDIF- Not a clean cutoff of a buffer? Say so. - - - - if(tempin == 65536) return(-1); - - isofile->filebytepos += tempin; - - return(tempin); // Send out # of compressed bytes (to record in table) - -} // END BZip2V2Read() - - - - - -int BZip2V2OpenForWrite(struct IsoFile *isofile) { - - char garbage[sizeof(struct BZip2V2Header)]; - - int i; - - - - if(isofile == NULL) return(-1); - - - -#ifdef VERBOSE_FUNCTION_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: OpenForWrite()"); - -#endif /* VERBOSE_FUNCTION_BZIP2V2 */ - - - - isofile->handle = ActualFileOpenForWrite(isofile->name); - - if(isofile->handle == ACTUALHANDLENULL) { - - return(-1); - - } // ENDIF- Couldn't open data file? Fail. - - for(i = 0; i < sizeof(struct BZip2V2Header); i++) garbage[i] = 0; - - ActualFileWrite(isofile->handle, sizeof(struct BZip2V2Header), garbage); - - - - isofile->filebytesize = 0; - - isofile->filebytepos = sizeof(struct BZip2V2Header); - - isofile->numsectors = 16; - - isofile->filesectorsize = 0; - - isofile->filesectorpos = 0; - - isofile->compsector = 0; - - return(0); - -} // END BZip2V2OpenForWrite() - - - - - -int BZip2V2Write(struct IsoFile *isofile, char *buffer) { - - int retval; - - unsigned int blocklen; - - char tempblock[65536]; - - - -#ifdef VERBOSE_FUNCTION_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: Write()"); - -#endif /* VERBOSE_FUNCTION_BZIP2V2 */ - - - - blocklen = 65536; - - retval = BZ2_bzBuffToBuffCompress(tempblock, - - &blocklen, - - buffer, - - isofile->blocksize * isofile->numsectors, - - 9, 0, 250); - - if(retval != BZ_OK) { - -#ifdef VERBOSE_FUNCTION_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: Cannot encode block! Returned: (%i)", retval); - -#endif /* VERBOSE_FUNCTION_BZIP2V2 */ - - return(-1); - - } // ENDIF- Trouble compressing a block? Abort. - - - - retval = ActualFileWrite(isofile->handle, blocklen, tempblock); - - if(retval > 0) isofile->filebytepos += retval; - - if(retval < blocklen) { - -#ifdef VERBOSE_FUNCTION_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: Cannot write bytes! Returned: (%i out of %llu)", - - retval, blocklen); - -#endif /* VERBOSE_FUNCTION_BZIP2V2 */ - - return(-1); - - } // ENDIF- Trouble writing out the compressed block? Abort. - - - - return(blocklen); // Not in list? Fail. - -} // END BZip2V2Write() - - - - - -void BZip2V2Close(struct IsoFile *isofile) { - - struct BZip2V2Header header; - - struct TableData table; - - int compptr; - - int i; - - int retval; - - - -#ifdef VERBOSE_FUNCTION_BZIP2V2 - - PrintLog("CDVDiso BZip2V2: Close()"); - -#endif /* VERBOSE_FUNCTION_BZIP2V2 */ - - - - if((isofile->tablehandle != ACTUALHANDLENULL) && - - (isofile->handle != ACTUALHANDLENULL)) { - - if(isofile->openforread == 0) { - - if(isofile->compsector != isofile->filesectorpos) { - - compptr = isofile->filesectorpos - isofile->compsector; - - compptr *= isofile->blocksize; - - for(i = compptr; i < 65536; i++) isofile->compblock[i] = 0; - - retval = BZip2V2Write(isofile, isofile->compblock); - - table.offset = isofile->filebytepos - retval; - - table.size = retval; - - BZip2V2WriteTable(isofile, table); - - isofile->compsector = isofile->filesectorpos; - - } // ENDIF - still have buffers to write? - - } // ENDIF- Opened for write? Don't forget to flush the file buffer! - - } // ENDIF- Are both the data file and table files open? - - - - if(isofile->tablehandle != ACTUALHANDLENULL) { - - ActualFileClose(isofile->tablehandle); - - isofile->tablehandle = ACTUALHANDLENULL; - - } // ENDIF- Is there a table file open? Close it. - - - - if(isofile->handle != ACTUALHANDLENULL) { - - if(isofile->openforread == 0) { - - if(isofile->compsector != isofile->filesectorpos) { - - compptr = isofile->filesectorpos - isofile->compsector; - - compptr *= isofile->blocksize; - - for(i = compptr; i < 65536; i++) isofile->compblock[i] = 0; - - BZip2V2Write(isofile, isofile->compblock); - - } // ENDIF - still have buffers to write? - - header.id[0] = 'B'; - - header.id[1] = 'Z'; - - header.id[2] = 'V'; - - header.id[3] = '2'; - - header.blocksize = ConvertEndianUInt(isofile->blocksize); - - header.numblocks = ConvertEndianUInt(isofile->filesectorsize); - - header.blockoffset = ConvertEndianUInt(isofile->blockoffset); - - ActualFileSeek(isofile->handle, 0); - - ActualFileWrite(isofile->handle, - - sizeof(struct BZip2V2Header), - - (char *) &header); - - } // ENDIF- Opened for write? Don't forget to update the header block! - - - - ActualFileClose(isofile->handle); - - isofile->handle = ACTUALHANDLENULL; - - } // ENDIF- Is there a data file open? Close it. - - - - if(isofile->tabledata != NULL) { - - free(isofile->tabledata); - - isofile->tabledata = NULL; - - } // ENDIF- Do we have a read-in table to clear out? - - - - return; - -} // END BZip2V2Close() - +/* bzip2v2.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // malloc() + +#include // off64_t + + + +#include "bzip2/bzlib.h" + + + +#include "convert.h" + +#include "logfile.h" + +#include "isofile.h" // IsoFile + +#include "isocompress.h" // TableData, TableMap + +#include "actualfile.h" + +// #include "convert.h" + +#include "bzip2v2.h" + + + + + +#ifdef _WIN32 + +#pragma pack(1) + +#endif /* _WIN32 */ + + + +struct BZip2V2Header { + + char id[4]; + + unsigned int blocksize; + + unsigned int numblocks; + + unsigned int blockoffset; + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +struct BZip2V2Table { + + unsigned int size; + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +#ifdef _WIN32 + +#pragma pack() + +#endif /* _WIN32 */ + + + + + +int BZip2V2OpenTableForRead(struct IsoFile *isofile) { + + int i; + + int j; + + char tableext[] = ".table\0"; + + off64_t numentries; + + off64_t offset; + + off64_t actual; + + int tableoffset; + + struct BZip2V2Table table; + + int retval; + + union TableMap tablemap; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: OpenTableForRead()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + i = 0; + + while((i < 256) && (isofile->name[i] != 0)) { + + isofile->tablename[i] = isofile->name[i]; + + i++; + + } // ENDWHILE- Copying the data name to the table name + + j = 0; + + while((i < 256) && (tableext[j] != 0)) { + + isofile->tablename[i] = tableext[j]; + + i++; + + j++; + + } // ENDWHILE- Adding the ".table" extension. + + isofile->tablename[i] = 0; // And 0-terminate. + + + + isofile->tablehandle = ActualFileOpenForRead(isofile->tablename); + + if(isofile->tablehandle == ACTUALHANDLENULL) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Couldn't open table!"); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-2); + + } // ENDIF- Couldn't open table file? Fail. + + + + numentries = isofile->filesectorsize / 16; + + if((isofile->filesectorsize % 16) != 0) numentries++; + + offset = numentries * sizeof(struct BZip2V2Table); + + actual = ActualFileSize(isofile->tablehandle); + + if(offset != actual) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Table not the correct size! (Should be %lli, is %lli)", + + offset, actual); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-2); + + } // ENDIF- Not the correct-sized table for the data file? Fail. + + + + // We pre-read the WHOLE offset table. + + isofile->tabledata = (char *) malloc(numentries * sizeof(struct TableData)); + + if(isofile->tabledata == NULL) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Couldn't allocate internal table!"); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-2); + + } // ENDIF- Could not get enough memory to hold table data + + + + offset = sizeof(struct BZip2V2Header); + + tableoffset = 0; + + for(i = 0; i < numentries; i++) { + + retval = ActualFileRead(isofile->tablehandle, + + sizeof(struct BZip2V2Table), + + (char *) &table); + + if(retval != sizeof(struct BZip2V2Table)) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Failed to read in entry %i!", i); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-2); + + } // ENDIF- Trouble reading in a size? Table damaged... fail. + + + + tablemap.table.offset = offset; + + tablemap.table.size = ConvertEndianUInt(table.size); + + for(j = 0; j < sizeof(struct TableData); j++) + + *(isofile->tabledata + tableoffset + j) = tablemap.ch[j]; + + offset += tablemap.table.size; + + tableoffset += sizeof(struct TableData); + + } // NEXT i- reading in the sizes, and making offset as I go. + + + + ActualFileClose(isofile->tablehandle); + + isofile->tablehandle = ACTUALHANDLENULL; + + return(0); + +} // END BZip2V2OpenTableForRead() + + + + + +int BZip2V2SeekTable(struct IsoFile *isofile, off64_t sector) { + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: SeekTable(%lli)", sector); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + isofile->filesectorpos = sector; + + isofile->compsector = isofile->filesectorsize + isofile->numsectors; + + return(0); + +} // END BZip2V2SeekTable() + + + + + +int BZip2V2ReadTable(struct IsoFile *isofile, struct TableData *table) { + + off64_t target; + + union TableMap tablemap; + + off64_t i; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: ReadTable()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + target = (isofile->filesectorpos / isofile->numsectors) + + * sizeof(struct TableData); + + for(i = 0; i < sizeof(struct TableData); i++) + + tablemap.ch[i] = *(isofile->tabledata + target + i); + + + + table->offset = tablemap.table.offset; + + table->size = tablemap.table.size; + + return(0); + +} // END BZip2V2ReadTable() + + + + + +int BZip2V2OpenTableForWrite(struct IsoFile *isofile) { + + int i; + + int j; + + char tableext[] = ".table\0"; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: OpenTableForWrite()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + i = 0; + + while((i < 256) && (isofile->name[i] != 0)) { + + isofile->tablename[i] = isofile->name[i]; + + i++; + + } // ENDWHILE- Copying the data name to the table name + + j = 0; + + while((i < 256) && (tableext[j] != 0)) { + + isofile->tablename[i] = tableext[j]; + + i++; + + j++; + + } // ENDWHILE- Adding the ".table" extension. + + isofile->tablename[i] = 0; // And 0-terminate. + + + + isofile->tablehandle = ActualFileOpenForWrite(isofile->tablename); + + if(isofile->tablehandle == ACTUALHANDLENULL) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Couldn't open table!"); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-2); + + } // ENDIF- Couldn't open table file? Fail. + + + + // isofile->filesectorsize = 0; + + return(0); + +} // END BZip2V2OpenTableForWrite() + + + + + +int BZip2V2WriteTable(struct IsoFile *isofile, struct TableData table) { + + int retval; + + struct BZip2V2Table bv2table; + + unsigned int tempint; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: WriteTable(%lli, %i)", table.offset, table.size); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + tempint = table.size; + + bv2table.size = ConvertEndianUInt(tempint); + + retval = ActualFileWrite(isofile->tablehandle, + + sizeof(struct BZip2V2Table), + + (char *) &bv2table); + + if(retval != sizeof(struct BZip2V2Table)) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Couldn't write table entry!"); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-2); + + } // ENDIF- Trouble reading table entry? Fail. + + + + return(0); + +} // END BZip2V2WriteTable() + + + + + +int BZip2V2OpenForRead(struct IsoFile *isofile) { + + int retval; + + struct BZip2V2Header header; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: OpenForRead()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + isofile->handle = ActualFileOpenForRead(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + return(-1); + + } // ENDIF- Couldn't open data file? Fail. + + + + isofile->filebytesize = ActualFileSize(isofile->handle); + + isofile->filebytepos = 0; + + isofile->filesectorpos = 0; + + + + isofile->imageheader = 0; + + isofile->numsectors = 16; // Sectors per block + + + + retval = ActualFileRead(isofile->handle, + + sizeof(struct BZip2V2Header), + + (char *) &header); + + if(retval != sizeof(struct BZip2V2Header)) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Couldn't read header!"); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF Could not read the first sector? Fail. + + isofile->filebytepos += retval; + + + + if((header.id[0] != 'B') || + + (header.id[1] != 'Z') || + + (header.id[2] != 'V') || + + (header.id[3] != '2')) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Not a bzip2 v2 compression header!"); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- ID for this compression type doesn't match? + + + + isofile->blocksize = ConvertEndianUInt(header.blocksize); + + isofile->filesectorsize = ConvertEndianUInt(header.numblocks); + + isofile->blockoffset = ConvertEndianUInt(header.blockoffset); + + isofile->filesectorpos = 0; + + isofile->compsector = header.numblocks + isofile->numsectors; + + return(0); + +} // END BZip2V2OpenForRead() + + + + + +int BZip2V2Seek(struct IsoFile *isofile, off64_t position) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Seek(%lli)", position); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + retval = ActualFileSeek(isofile->handle, position); + + if(retval < 0) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Couldn't find the start of the compressed block!"); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-1); + + } // ENDIF- Couldn't find the data entry? Fail. + + isofile->filebytepos = position; + + return(0); + + + + return(-1); // Fail. (Due to lack of ambition?) + +} // END BZip2V2Seek() + + + + + +int BZip2V2Read(struct IsoFile *isofile, int bytes, char *buffer) { + + int retval; + + unsigned int blocklen; + + bz_stream strm; + + unsigned int tempin; + + char tempblock[65536]; + + unsigned int tempout; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Read(%i)", bytes); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + if(bytes > 0) { + + retval = ActualFileRead(isofile->handle, bytes, tempblock); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval != bytes) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Cannot read bytes! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + + + blocklen = 65536; + + retval = BZ2_bzBuffToBuffDecompress(buffer, &blocklen, tempblock, bytes, 0, 0); + + if(retval != BZ_OK) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Cannot decode block! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-1); + + } // ENDIF- Trouble decoding the sector? Abort. + + + + return(0); + + } // ENDIF- Do we know how many compressed bytes to get for this record? + + + + // Hmm. Don't know the compressed size? Well, we'll just have to find it. + + + + tempin = 0; + + tempout = 0; + + retval = BZ_OK; + + while((tempin < 65536) && (tempout < isofile->blocksize * isofile->numsectors)) { + + strm.bzalloc = NULL; + + strm.bzfree = NULL; + + strm.opaque = NULL; + + retval = BZ2_bzDecompressInit ( &strm, 0, 0 ); + + if (retval != BZ_OK) return(-1); + + + + strm.next_out = buffer; + + + + strm.avail_in = tempin; + + strm.avail_out = 65536; + + + + retval = BZ_OK; + + while((tempin < 65536) && (retval == BZ_OK)) { + + retval = ActualFileRead(isofile->handle, 1, &tempblock[tempin]); + + if(retval != 1) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Cannot read a byte! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + BZ2_bzDecompressEnd(&strm); + + return(-1); + + } // ENDIF- Trouble reading a piece of compressed sector? Abort. + + tempin++; + + strm.avail_in++; + + + + strm.next_in = &tempblock[tempin - strm.avail_in]; + + retval = BZ2_bzDecompress(&strm); + + } // ENDWHILE- trying to uncompress an increasingly filled buffer + + tempout = 65536 - strm.avail_out; + + BZ2_bzDecompressEnd(&strm); + + + + } // ENDWHILE- trying to uncompress a whole buffer + + if(retval != BZ_STREAM_END) { + +#ifdef VERBOSE_WARNING_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Failed to decode block! (Returned %i", retval); + +#endif /* VERBOSE_WARNING_BZIP2V2 */ + + return(-1); + + } // ENDIF- Not a clean cutoff of a buffer? Say so. + + + + if(tempin == 65536) return(-1); + + isofile->filebytepos += tempin; + + return(tempin); // Send out # of compressed bytes (to record in table) + +} // END BZip2V2Read() + + + + + +int BZip2V2OpenForWrite(struct IsoFile *isofile) { + + char garbage[sizeof(struct BZip2V2Header)]; + + int i; + + + + if(isofile == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: OpenForWrite()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + isofile->handle = ActualFileOpenForWrite(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + return(-1); + + } // ENDIF- Couldn't open data file? Fail. + + for(i = 0; i < sizeof(struct BZip2V2Header); i++) garbage[i] = 0; + + ActualFileWrite(isofile->handle, sizeof(struct BZip2V2Header), garbage); + + + + isofile->filebytesize = 0; + + isofile->filebytepos = sizeof(struct BZip2V2Header); + + isofile->numsectors = 16; + + isofile->filesectorsize = 0; + + isofile->filesectorpos = 0; + + isofile->compsector = 0; + + return(0); + +} // END BZip2V2OpenForWrite() + + + + + +int BZip2V2Write(struct IsoFile *isofile, char *buffer) { + + int retval; + + unsigned int blocklen; + + char tempblock[65536]; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Write()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + blocklen = 65536; + + retval = BZ2_bzBuffToBuffCompress(tempblock, + + &blocklen, + + buffer, + + isofile->blocksize * isofile->numsectors, + + 9, 0, 250); + + if(retval != BZ_OK) { + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Cannot encode block! Returned: (%i)", retval); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + return(-1); + + } // ENDIF- Trouble compressing a block? Abort. + + + + retval = ActualFileWrite(isofile->handle, blocklen, tempblock); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval < blocklen) { + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Cannot write bytes! Returned: (%i out of %llu)", + + retval, blocklen); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + return(-1); + + } // ENDIF- Trouble writing out the compressed block? Abort. + + + + return(blocklen); // Not in list? Fail. + +} // END BZip2V2Write() + + + + + +void BZip2V2Close(struct IsoFile *isofile) { + + struct BZip2V2Header header; + + struct TableData table; + + int compptr; + + int i; + + int retval; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V2 + + PrintLog("CDVDiso BZip2V2: Close()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V2 */ + + + + if((isofile->tablehandle != ACTUALHANDLENULL) && + + (isofile->handle != ACTUALHANDLENULL)) { + + if(isofile->openforread == 0) { + + if(isofile->compsector != isofile->filesectorpos) { + + compptr = isofile->filesectorpos - isofile->compsector; + + compptr *= isofile->blocksize; + + for(i = compptr; i < 65536; i++) isofile->compblock[i] = 0; + + retval = BZip2V2Write(isofile, isofile->compblock); + + table.offset = isofile->filebytepos - retval; + + table.size = retval; + + BZip2V2WriteTable(isofile, table); + + isofile->compsector = isofile->filesectorpos; + + } // ENDIF - still have buffers to write? + + } // ENDIF- Opened for write? Don't forget to flush the file buffer! + + } // ENDIF- Are both the data file and table files open? + + + + if(isofile->tablehandle != ACTUALHANDLENULL) { + + ActualFileClose(isofile->tablehandle); + + isofile->tablehandle = ACTUALHANDLENULL; + + } // ENDIF- Is there a table file open? Close it. + + + + if(isofile->handle != ACTUALHANDLENULL) { + + if(isofile->openforread == 0) { + + if(isofile->compsector != isofile->filesectorpos) { + + compptr = isofile->filesectorpos - isofile->compsector; + + compptr *= isofile->blocksize; + + for(i = compptr; i < 65536; i++) isofile->compblock[i] = 0; + + BZip2V2Write(isofile, isofile->compblock); + + } // ENDIF - still have buffers to write? + + header.id[0] = 'B'; + + header.id[1] = 'Z'; + + header.id[2] = 'V'; + + header.id[3] = '2'; + + header.blocksize = ConvertEndianUInt(isofile->blocksize); + + header.numblocks = ConvertEndianUInt(isofile->filesectorsize); + + header.blockoffset = ConvertEndianUInt(isofile->blockoffset); + + ActualFileSeek(isofile->handle, 0); + + ActualFileWrite(isofile->handle, + + sizeof(struct BZip2V2Header), + + (char *) &header); + + } // ENDIF- Opened for write? Don't forget to update the header block! + + + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + } // ENDIF- Is there a data file open? Close it. + + + + if(isofile->tabledata != NULL) { + + free(isofile->tabledata); + + isofile->tabledata = NULL; + + } // ENDIF- Do we have a read-in table to clear out? + + + + return; + +} // END BZip2V2Close() + diff --git a/plugins/CDVDisoEFP/src/bzip2v2.h b/plugins/CDVDisoEFP/src/bzip2v2.h index 8ecd464ce4..55c667a2ce 100644 --- a/plugins/CDVDisoEFP/src/bzip2v2.h +++ b/plugins/CDVDisoEFP/src/bzip2v2.h @@ -1,104 +1,104 @@ -/* bzip2v2.h - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#ifndef BZIP2V2_H - -#define BZIP2V2_H - - - - - -#include - - - -#include "isofile.h" - -#include "isocompress.h" - - - - - -// #define VERBOSE_FUNCTION_BZIP2V2 - -// #define VERBOSE_WARNING_BZIP2V2 - - - - - -extern int BZip2V2OpenTableForRead(struct IsoFile *isofile); - -extern int BZip2V2SeekTable(struct IsoFile *isofile, off64_t sector); - -extern int BZip2V2ReadTable(struct IsoFile *isofile, struct TableData *table); - - - -extern int BZip2V2OpenTableForWrite(struct IsoFile *isofile); - -extern int BZip2V2WriteTable(struct IsoFile *isofile, struct TableData table); - - - -extern int BZip2V2OpenForRead(struct IsoFile *isofile); - -extern int BZip2V2Seek(struct IsoFile *isofile, off64_t sector); - -extern int BZip2V2Read(struct IsoFile *isofile, int bytes, char *buffer); - -extern void BZip2V2Close(struct IsoFile *isofile); - - - -extern int BZip2V2OpenForWrite(struct IsoFile *isofile); - -extern int BZip2V2Write(struct IsoFile *isofile, char *buffer); - - - - - -#endif /* BZIP2V2_H */ - +/* bzip2v2.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef BZIP2V2_H + +#define BZIP2V2_H + + + + + +#include + + + +#include "isofile.h" + +#include "isocompress.h" + + + + + +// #define VERBOSE_FUNCTION_BZIP2V2 + +// #define VERBOSE_WARNING_BZIP2V2 + + + + + +extern int BZip2V2OpenTableForRead(struct IsoFile *isofile); + +extern int BZip2V2SeekTable(struct IsoFile *isofile, off64_t sector); + +extern int BZip2V2ReadTable(struct IsoFile *isofile, struct TableData *table); + + + +extern int BZip2V2OpenTableForWrite(struct IsoFile *isofile); + +extern int BZip2V2WriteTable(struct IsoFile *isofile, struct TableData table); + + + +extern int BZip2V2OpenForRead(struct IsoFile *isofile); + +extern int BZip2V2Seek(struct IsoFile *isofile, off64_t sector); + +extern int BZip2V2Read(struct IsoFile *isofile, int bytes, char *buffer); + +extern void BZip2V2Close(struct IsoFile *isofile); + + + +extern int BZip2V2OpenForWrite(struct IsoFile *isofile); + +extern int BZip2V2Write(struct IsoFile *isofile, char *buffer); + + + + + +#endif /* BZIP2V2_H */ + diff --git a/plugins/CDVDisoEFP/src/bzip2v3.c b/plugins/CDVDisoEFP/src/bzip2v3.c index 2c1b2539c7..590c5f6d99 100644 --- a/plugins/CDVDisoEFP/src/bzip2v3.c +++ b/plugins/CDVDisoEFP/src/bzip2v3.c @@ -1,968 +1,968 @@ -/* bzip2v3.c - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#include // NULL - -#include // malloc() - -#include // off64_t - - - -#include "bzip2/bzlib.h" - - - -#include "convert.h" - -#include "logfile.h" - -#include "isofile.h" // IsoFile - -#include "isocompress.h" // TableData, TableMap - -#include "actualfile.h" - -#include "convert.h" - -#include "bzip2v3.h" - - - - - -#ifdef _WIN32 - -#pragma pack(1) - -#endif /* _WIN32 */ - - - -struct BZip2V3Header { - - char id[4]; - - unsigned short blocksize; - - off64_t numblocks; - - unsigned short blockoffset; - -#ifdef _WIN32 - -}; - -#else - -} __attribute__ ((packed)); - -#endif /* _WIN32 */ - - - -struct BZip2V3Table { - - off64_t offset; - -#ifdef _WIN32 - -}; - -#else - -} __attribute__ ((packed)); - -#endif /* _WIN32 */ - - - -#ifdef _WIN32 - -#pragma pack() - -#endif /* _WIN32 */ - - - - - -int BZip2V3OpenTableForRead(struct IsoFile *isofile) { - - int i; - - int j; - - char tableext[] = ".table\0"; - - off64_t numentries; - - off64_t offset; - - off64_t actual; - - - -#ifdef VERBOSE_FUNCTION_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: OpenTableForRead()"); - -#endif /* VERBOSE_FUNCTION_BZIP2V3 */ - - - - i = 0; - - while((i < 256) && (isofile->name[i] != 0)) { - - isofile->tablename[i] = isofile->name[i]; - - i++; - - } // ENDWHILE- Copying the data name to the table name - - j = 0; - - while((i < 256) && (tableext[j] != 0)) { - - isofile->tablename[i] = tableext[j]; - - i++; - - j++; - - } // ENDWHILE- Adding the ".table" extension. - - isofile->tablename[i] = 0; // And 0-terminate. - - - - isofile->tablehandle = ActualFileOpenForRead(isofile->tablename); - - if(isofile->tablehandle == ACTUALHANDLENULL) { - -#ifdef VERBOSE_WARNING_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: Couldn't open table!"); - -#endif /* VERBOSE_WARNING_BZIP2V3 */ - - return(-2); - - } // ENDIF- Couldn't open table file? Fail. - - - - numentries = isofile->filesectorsize / isofile->numsectors; - - if((isofile->filesectorsize % isofile->numsectors) != 0) numentries++; - - offset = numentries * sizeof(struct BZip2V3Table); - - actual = ActualFileSize(isofile->tablehandle); - - if(offset != actual) { - -#ifdef VERBOSE_WARNING_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: Table not the correct size! (Should be %lli, is %lli)", - - offset, actual); - -#endif /* VERBOSE_WARNING_BZIP2V3 */ - - return(-2); - - } // ENDIF- Not the correct-sized table for the data file? Fail. - - - - return(0); - -} // END BZip2V3OpenTableForRead() - - - - - -int BZip2V3SeekTable(struct IsoFile *isofile, off64_t sector) { - - off64_t target; - - int retval; - - - -#ifdef VERBOSE_FUNCTION_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: SeekTable(%lli)", sector); - -#endif /* VERBOSE_FUNCTION_BZIP2V3 */ - - - - target = sector / isofile->numsectors; - - target *= sizeof(struct BZip2V3Table); - - retval = ActualFileSeek(isofile->tablehandle, target); - - if(retval < 0) { - -#ifdef VERBOSE_WARNING_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: Couldn't find sector!"); - -#endif /* VERBOSE_WARNING_BZIP2V3 */ - - return(-2); - - } // ENDIF- Trouble finding the place? Fail. - - - - isofile->filesectorpos = sector; - - isofile->compsector = isofile->filesectorsize + isofile->numsectors; - - return(0); - -} // END BZip2V3SeekTable() - - - - - -int BZip2V3ReadTable(struct IsoFile *isofile, struct TableData *table) { - - int retval; - - struct BZip2V3Table temptable; - - - -#ifdef VERBOSE_FUNCTION_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: ReadTable()"); - -#endif /* VERBOSE_FUNCTION_BZIP2V3 */ - - - - retval = ActualFileRead(isofile->tablehandle, - - sizeof(struct BZip2V3Table), - - (char *) &temptable); - - if(retval != sizeof(struct BZip2V3Table)) { - -#ifdef VERBOSE_WARNING_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: Couldn't read table entry!"); - -#endif /* VERBOSE_WARNING_BZIP2V3 */ - - return(-2); - - } // ENDIF- Trouble reading table entry? Fail. - - - - table->offset = ConvertEndianOffset(temptable.offset); - - table->size = 0; - - return(0); - -} // END BZip2V3ReadTable() - - - - - -int BZip2V3OpenTableForWrite(struct IsoFile *isofile) { - - int i; - - int j; - - char tableext[] = ".table\0"; - - - -#ifdef VERBOSE_FUNCTION_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: OpenTableForWrite()"); - -#endif /* VERBOSE_FUNCTION_BZIP2V3 */ - - - - i = 0; - - while((i < 256) && (isofile->name[i] != 0)) { - - isofile->tablename[i] = isofile->name[i]; - - i++; - - } // ENDWHILE- Copying the data name to the table name - - j = 0; - - while((i < 256) && (tableext[j] != 0)) { - - isofile->tablename[i] = tableext[j]; - - i++; - - j++; - - } // ENDWHILE- Adding the ".table" extension. - - isofile->tablename[i] = 0; // And 0-terminate. - - - - isofile->tablehandle = ActualFileOpenForWrite(isofile->tablename); - - if(isofile->tablehandle == ACTUALHANDLENULL) { - -#ifdef VERBOSE_WARNING_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: Couldn't open table!"); - -#endif /* VERBOSE_WARNING_BZIP2V3 */ - - return(-2); - - } // ENDIF- Couldn't open table file? Fail. - - - - // isofile->filesectorsize = 0; - - return(0); - -} // END BZip2V3OpenTableForWrite() - - - - - -int BZip2V3WriteTable(struct IsoFile *isofile, struct TableData table) { - - int retval; - - struct BZip2V3Table bv3table; - - - -#ifdef VERBOSE_FUNCTION_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: WriteTable(%lli, %i)", table.offset, table.size); - -#endif /* VERBOSE_FUNCTION_BZIP2V3 */ - - - - bv3table.offset = ConvertEndianOffset(table.offset); - - retval = ActualFileWrite(isofile->tablehandle, - - sizeof(struct BZip2V3Table), - - (char *) &bv3table); - - if(retval != sizeof(struct BZip2V3Table)) { - -#ifdef VERBOSE_WARNING_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: Couldn't write table entry!"); - -#endif /* VERBOSE_WARNING_BZIP2V3 */ - - return(-2); - - } // ENDIF- Trouble reading table entry? Fail. - - - - return(0); - -} // END BZip2V3WriteTable() - - - - - -int BZip2V3OpenForRead(struct IsoFile *isofile) { - - int retval; - - struct BZip2V3Header header; - - - -#ifdef VERBOSE_FUNCTION_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: OpenForRead()"); - -#endif /* VERBOSE_FUNCTION_BZIP2V3 */ - - - - isofile->handle = ActualFileOpenForRead(isofile->name); - - if(isofile->handle == ACTUALHANDLENULL) { - - return(-1); - - } // ENDIF- Couldn't open data file? Fail. - - - - isofile->filebytesize = ActualFileSize(isofile->handle); - - isofile->filebytepos = 0; - - isofile->filesectorpos = 0; - - - - isofile->imageheader = 0; - - - - retval = ActualFileRead(isofile->handle, - - sizeof(struct BZip2V3Header), - - (char *) &header); - - if(retval != sizeof(struct BZip2V3Header)) { - -#ifdef VERBOSE_WARNING_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: Couldn't read header!"); - -#endif /* VERBOSE_WARNING_BZIP2V3 */ - - ActualFileClose(isofile->handle); - - isofile->handle = ACTUALHANDLENULL; - - return(-1); - - } // ENDIF Could not read the first sector? Fail. - - isofile->filebytepos += retval; - - - - if((header.id[0] != 'B') || - - (header.id[1] != 'Z') || - - (header.id[2] != 'V') || - - (header.id[3] != '3')) { - -#ifdef VERBOSE_WARNING_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: Not a bzip2 v3 compression header!"); - -#endif /* VERBOSE_WARNING_BZIP2V3 */ - - ActualFileClose(isofile->handle); - - isofile->handle = ACTUALHANDLENULL; - - return(-1); - - } // ENDIF- ID for this compression type doesn't match? - - - - isofile->blocksize = ConvertEndianUShort(header.blocksize); - - isofile->filesectorsize = ConvertEndianOffset(header.numblocks); - - isofile->blockoffset = ConvertEndianUShort(header.blockoffset); - - isofile->numsectors = (65536 / isofile->blocksize) - 1; - - isofile->filesectorpos = 0; - - isofile->compsector = header.numblocks + isofile->numsectors; - - return(0); - -} // END BZip2V3OpenForRead() - - - - - -int BZip2V3Seek(struct IsoFile *isofile, off64_t position) { - - int retval; - - - -#ifdef VERBOSE_FUNCTION_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: Seek(%lli)", position); - -#endif /* VERBOSE_FUNCTION_BZIP2V3 */ - - - - retval = ActualFileSeek(isofile->handle, position); - - if(retval < 0) { - -#ifdef VERBOSE_WARNING_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: Couldn't find the start of the compressed block!"); - -#endif /* VERBOSE_WARNING_BZIP2V3 */ - - return(-1); - - } // ENDIF- Couldn't find the data entry? Fail. - - isofile->filebytepos = position; - - return(0); - - - - return(-1); // Fail. (Due to lack of ambition?) - -} // END BZip2V3Seek() - - - - - -int BZip2V3Read(struct IsoFile *isofile, int bytes, char *buffer) { - - int retval; - - unsigned short tempsize; - - char tempblock[65536]; - - unsigned int blocklen; - - - -#ifdef VERBOSE_FUNCTION_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: Read()"); - -#endif /* VERBOSE_FUNCTION_BZIP2V3 */ - - - - retval = ActualFileRead(isofile->handle, - - sizeof(unsigned short), - - (char *) &tempsize); - - if(retval > 0) isofile->filebytepos += retval; - - if(retval != sizeof(unsigned short)) { - -#ifdef VERBOSE_WARNING_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: Cannot read bytes! Returned: (%i)", retval); - -#endif /* VERBOSE_WARNING_BZIP2V3 */ - - return(-1); - - } // ENDIF- Trouble reading compressed sector? Abort. - - tempsize = ConvertEndianUShort(tempsize); - - - - retval = ActualFileRead(isofile->handle, tempsize, tempblock); - - if(retval > 0) isofile->filebytepos += retval; - - if(retval != tempsize) { - -#ifdef VERBOSE_WARNING_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: Cannot read bytes! Returned: (%i)", retval); - -#endif /* VERBOSE_WARNING_BZIP2V3 */ - - return(-1); - - } // ENDIF- Trouble reading compressed sector? Abort. - - - - blocklen = 65536; - - retval = BZ2_bzBuffToBuffDecompress(buffer, &blocklen, tempblock, tempsize, 0, 0); - - if(retval != BZ_OK) { - -#ifdef VERBOSE_WARNING_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: Cannot decode block! Returned: (%i)", retval); - -#endif /* VERBOSE_WARNING_BZIP2V3 */ - - return(-1); - - } // ENDIF- Trouble decoding the sector? Abort. - - - - return(tempsize + sizeof(unsigned short)); - -} // END BZip2V3Read() - - - - - -int BZip2V3OpenForWrite(struct IsoFile *isofile) { - - char garbage[sizeof(struct BZip2V3Header)]; - - int i; - - - - if(isofile == NULL) return(-1); - - - -#ifdef VERBOSE_FUNCTION_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: OpenForWrite()"); - -#endif /* VERBOSE_FUNCTION_BZIP2V3 */ - - - - isofile->handle = ActualFileOpenForWrite(isofile->name); - - if(isofile->handle == ACTUALHANDLENULL) { - - return(-1); - - } // ENDIF- Couldn't open data file? Fail. - - for(i = 0; i < sizeof(struct BZip2V3Header); i++) garbage[i] = 0; - - ActualFileWrite(isofile->handle, sizeof(struct BZip2V3Header), garbage); - - - - isofile->filebytesize = 0; - - isofile->filebytepos = sizeof(struct BZip2V3Header); - - isofile->numsectors = (65536 / isofile->blocksize) - 1; - - isofile->filesectorsize = 0; - - isofile->filesectorpos = 0; - - isofile->compsector = 0; - - return(0); - -} // END BZip2V3OpenForWrite() - - - - - -int BZip2V3Write(struct IsoFile *isofile, char *buffer) { - - int retval; - - unsigned int blocklen; - - char tempblock[65536]; - - unsigned short tempsize; - - - -#ifdef VERBOSE_FUNCTION_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: Write()"); - -#endif /* VERBOSE_FUNCTION_BZIP2V3 */ - - - - blocklen = 65536; - - retval = BZ2_bzBuffToBuffCompress(tempblock, - - &blocklen, - - buffer, - - isofile->blocksize * isofile->numsectors, - - 9, 0, 250); - - if(retval != BZ_OK) { - -#ifdef VERBOSE_FUNCTION_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: Cannot encode block! Returned: (%i)", retval); - -#endif /* VERBOSE_FUNCTION_BZIP2V3 */ - - return(-1); - - } // ENDIF- Trouble compressing a block? Abort. - - - - tempsize = blocklen; - - tempsize = ConvertEndianUShort(tempsize); - - retval = ActualFileWrite(isofile->handle, - - sizeof(unsigned short), - - (char *) &tempsize); - - if(retval > 0) isofile->filebytepos += retval; - - if(retval < sizeof(unsigned short)) { - -#ifdef VERBOSE_FUNCTION_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: Cannot write bytes! Returned: (%i out of %llu)", - - retval, sizeof(unsigned short)); - -#endif /* VERBOSE_FUNCTION_BZIP2V3 */ - - return(-1); - - } // ENDIF- Trouble writing out the compressed block? Abort. - - - - - - retval = ActualFileWrite(isofile->handle, blocklen, tempblock); - - if(retval > 0) isofile->filebytepos += retval; - - if(retval < blocklen) { - -#ifdef VERBOSE_FUNCTION_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: Cannot write bytes! Returned: (%i out of %llu)", - - retval, blocklen); - -#endif /* VERBOSE_FUNCTION_BZIP2V3 */ - - return(-1); - - } // ENDIF- Trouble writing out the compressed block? Abort. - - - - return(blocklen + sizeof(unsigned short)); // Not in list? Fail. - -} // END BZip2V3Write() - - - - - -void BZip2V3Close(struct IsoFile *isofile) { - - struct BZip2V3Header header; - - struct TableData table; - - int compptr; - - int i; - - int retval; - - unsigned short tempsize; - - - -#ifdef VERBOSE_FUNCTION_BZIP2V3 - - PrintLog("CDVDiso BZip2V3: Close()"); - -#endif /* VERBOSE_FUNCTION_BZIP2V3 */ - - - - if((isofile->tablehandle != ACTUALHANDLENULL) && - - (isofile->handle != ACTUALHANDLENULL)) { - - if(isofile->openforread == 0) { - - if(isofile->compsector != isofile->filesectorpos) { - - compptr = isofile->filesectorpos - isofile->compsector; - - compptr *= isofile->blocksize; - - for(i = compptr; i < 65536; i++) isofile->compblock[i] = 0; - - retval = BZip2V3Write(isofile, isofile->compblock); - - table.offset = isofile->filebytepos - retval; - - table.size = retval; - - BZip2V3WriteTable(isofile, table); - - isofile->compsector = isofile->filesectorpos; - - } // ENDIF - still have buffers to write? - - } // ENDIF- Opened for write? Don't forget to flush the file buffer! - - } // ENDIF- Both data file and table file are open? - - - - if(isofile->tablehandle != ACTUALHANDLENULL) { - - ActualFileClose(isofile->tablehandle); - - isofile->tablehandle = ACTUALHANDLENULL; - - } // ENDIF- Is there a table file open? Close it. - - - - if(isofile->handle != ACTUALHANDLENULL) { - - if(isofile->openforread == 0) { - - if(isofile->compsector != isofile->filesectorpos) { - - compptr = isofile->filesectorpos - isofile->compsector; - - compptr *= isofile->blocksize; - - for(i = compptr; i < 65536; i++) isofile->compblock[i] = 0; - - BZip2V3Write(isofile, isofile->compblock); - - } // ENDIF - still have buffers to write? - - header.id[0] = 'B'; - - header.id[1] = 'Z'; - - header.id[2] = 'V'; - - header.id[3] = '3'; - - tempsize = isofile->blocksize; - - header.blocksize = ConvertEndianUShort(tempsize); - - header.numblocks = ConvertEndianOffset(isofile->filesectorsize); - - tempsize = isofile->blockoffset; - - header.blockoffset = ConvertEndianUShort(tempsize); - - ActualFileSeek(isofile->handle, 0); - - ActualFileWrite(isofile->handle, - - sizeof(struct BZip2V3Header), - - (char *) &header); - - } // ENDIF- Opened for write? Don't forget to update the header block! - - - - ActualFileClose(isofile->handle); - - isofile->handle = ACTUALHANDLENULL; - - } // ENDIF- Is there a data file open? Close it. - - - - if(isofile->tabledata != NULL) { - - free(isofile->tabledata); - - isofile->tabledata = NULL; - - } // ENDIF- Do we have a read-in table to clear out? - - - - return; - -} // END BZip2V3Close() - +/* bzip2v3.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // malloc() + +#include // off64_t + + + +#include "bzip2/bzlib.h" + + + +#include "convert.h" + +#include "logfile.h" + +#include "isofile.h" // IsoFile + +#include "isocompress.h" // TableData, TableMap + +#include "actualfile.h" + +#include "convert.h" + +#include "bzip2v3.h" + + + + + +#ifdef _WIN32 + +#pragma pack(1) + +#endif /* _WIN32 */ + + + +struct BZip2V3Header { + + char id[4]; + + unsigned short blocksize; + + off64_t numblocks; + + unsigned short blockoffset; + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +struct BZip2V3Table { + + off64_t offset; + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +#ifdef _WIN32 + +#pragma pack() + +#endif /* _WIN32 */ + + + + + +int BZip2V3OpenTableForRead(struct IsoFile *isofile) { + + int i; + + int j; + + char tableext[] = ".table\0"; + + off64_t numentries; + + off64_t offset; + + off64_t actual; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: OpenTableForRead()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + i = 0; + + while((i < 256) && (isofile->name[i] != 0)) { + + isofile->tablename[i] = isofile->name[i]; + + i++; + + } // ENDWHILE- Copying the data name to the table name + + j = 0; + + while((i < 256) && (tableext[j] != 0)) { + + isofile->tablename[i] = tableext[j]; + + i++; + + j++; + + } // ENDWHILE- Adding the ".table" extension. + + isofile->tablename[i] = 0; // And 0-terminate. + + + + isofile->tablehandle = ActualFileOpenForRead(isofile->tablename); + + if(isofile->tablehandle == ACTUALHANDLENULL) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Couldn't open table!"); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-2); + + } // ENDIF- Couldn't open table file? Fail. + + + + numentries = isofile->filesectorsize / isofile->numsectors; + + if((isofile->filesectorsize % isofile->numsectors) != 0) numentries++; + + offset = numentries * sizeof(struct BZip2V3Table); + + actual = ActualFileSize(isofile->tablehandle); + + if(offset != actual) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Table not the correct size! (Should be %lli, is %lli)", + + offset, actual); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-2); + + } // ENDIF- Not the correct-sized table for the data file? Fail. + + + + return(0); + +} // END BZip2V3OpenTableForRead() + + + + + +int BZip2V3SeekTable(struct IsoFile *isofile, off64_t sector) { + + off64_t target; + + int retval; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: SeekTable(%lli)", sector); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + target = sector / isofile->numsectors; + + target *= sizeof(struct BZip2V3Table); + + retval = ActualFileSeek(isofile->tablehandle, target); + + if(retval < 0) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Couldn't find sector!"); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-2); + + } // ENDIF- Trouble finding the place? Fail. + + + + isofile->filesectorpos = sector; + + isofile->compsector = isofile->filesectorsize + isofile->numsectors; + + return(0); + +} // END BZip2V3SeekTable() + + + + + +int BZip2V3ReadTable(struct IsoFile *isofile, struct TableData *table) { + + int retval; + + struct BZip2V3Table temptable; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: ReadTable()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + retval = ActualFileRead(isofile->tablehandle, + + sizeof(struct BZip2V3Table), + + (char *) &temptable); + + if(retval != sizeof(struct BZip2V3Table)) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Couldn't read table entry!"); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-2); + + } // ENDIF- Trouble reading table entry? Fail. + + + + table->offset = ConvertEndianOffset(temptable.offset); + + table->size = 0; + + return(0); + +} // END BZip2V3ReadTable() + + + + + +int BZip2V3OpenTableForWrite(struct IsoFile *isofile) { + + int i; + + int j; + + char tableext[] = ".table\0"; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: OpenTableForWrite()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + i = 0; + + while((i < 256) && (isofile->name[i] != 0)) { + + isofile->tablename[i] = isofile->name[i]; + + i++; + + } // ENDWHILE- Copying the data name to the table name + + j = 0; + + while((i < 256) && (tableext[j] != 0)) { + + isofile->tablename[i] = tableext[j]; + + i++; + + j++; + + } // ENDWHILE- Adding the ".table" extension. + + isofile->tablename[i] = 0; // And 0-terminate. + + + + isofile->tablehandle = ActualFileOpenForWrite(isofile->tablename); + + if(isofile->tablehandle == ACTUALHANDLENULL) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Couldn't open table!"); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-2); + + } // ENDIF- Couldn't open table file? Fail. + + + + // isofile->filesectorsize = 0; + + return(0); + +} // END BZip2V3OpenTableForWrite() + + + + + +int BZip2V3WriteTable(struct IsoFile *isofile, struct TableData table) { + + int retval; + + struct BZip2V3Table bv3table; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: WriteTable(%lli, %i)", table.offset, table.size); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + bv3table.offset = ConvertEndianOffset(table.offset); + + retval = ActualFileWrite(isofile->tablehandle, + + sizeof(struct BZip2V3Table), + + (char *) &bv3table); + + if(retval != sizeof(struct BZip2V3Table)) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Couldn't write table entry!"); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-2); + + } // ENDIF- Trouble reading table entry? Fail. + + + + return(0); + +} // END BZip2V3WriteTable() + + + + + +int BZip2V3OpenForRead(struct IsoFile *isofile) { + + int retval; + + struct BZip2V3Header header; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: OpenForRead()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + isofile->handle = ActualFileOpenForRead(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + return(-1); + + } // ENDIF- Couldn't open data file? Fail. + + + + isofile->filebytesize = ActualFileSize(isofile->handle); + + isofile->filebytepos = 0; + + isofile->filesectorpos = 0; + + + + isofile->imageheader = 0; + + + + retval = ActualFileRead(isofile->handle, + + sizeof(struct BZip2V3Header), + + (char *) &header); + + if(retval != sizeof(struct BZip2V3Header)) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Couldn't read header!"); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF Could not read the first sector? Fail. + + isofile->filebytepos += retval; + + + + if((header.id[0] != 'B') || + + (header.id[1] != 'Z') || + + (header.id[2] != 'V') || + + (header.id[3] != '3')) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Not a bzip2 v3 compression header!"); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- ID for this compression type doesn't match? + + + + isofile->blocksize = ConvertEndianUShort(header.blocksize); + + isofile->filesectorsize = ConvertEndianOffset(header.numblocks); + + isofile->blockoffset = ConvertEndianUShort(header.blockoffset); + + isofile->numsectors = (65536 / isofile->blocksize) - 1; + + isofile->filesectorpos = 0; + + isofile->compsector = header.numblocks + isofile->numsectors; + + return(0); + +} // END BZip2V3OpenForRead() + + + + + +int BZip2V3Seek(struct IsoFile *isofile, off64_t position) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Seek(%lli)", position); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + retval = ActualFileSeek(isofile->handle, position); + + if(retval < 0) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Couldn't find the start of the compressed block!"); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-1); + + } // ENDIF- Couldn't find the data entry? Fail. + + isofile->filebytepos = position; + + return(0); + + + + return(-1); // Fail. (Due to lack of ambition?) + +} // END BZip2V3Seek() + + + + + +int BZip2V3Read(struct IsoFile *isofile, int bytes, char *buffer) { + + int retval; + + unsigned short tempsize; + + char tempblock[65536]; + + unsigned int blocklen; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Read()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + retval = ActualFileRead(isofile->handle, + + sizeof(unsigned short), + + (char *) &tempsize); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval != sizeof(unsigned short)) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Cannot read bytes! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + tempsize = ConvertEndianUShort(tempsize); + + + + retval = ActualFileRead(isofile->handle, tempsize, tempblock); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval != tempsize) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Cannot read bytes! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + + + blocklen = 65536; + + retval = BZ2_bzBuffToBuffDecompress(buffer, &blocklen, tempblock, tempsize, 0, 0); + + if(retval != BZ_OK) { + +#ifdef VERBOSE_WARNING_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Cannot decode block! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_BZIP2V3 */ + + return(-1); + + } // ENDIF- Trouble decoding the sector? Abort. + + + + return(tempsize + sizeof(unsigned short)); + +} // END BZip2V3Read() + + + + + +int BZip2V3OpenForWrite(struct IsoFile *isofile) { + + char garbage[sizeof(struct BZip2V3Header)]; + + int i; + + + + if(isofile == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: OpenForWrite()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + isofile->handle = ActualFileOpenForWrite(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + return(-1); + + } // ENDIF- Couldn't open data file? Fail. + + for(i = 0; i < sizeof(struct BZip2V3Header); i++) garbage[i] = 0; + + ActualFileWrite(isofile->handle, sizeof(struct BZip2V3Header), garbage); + + + + isofile->filebytesize = 0; + + isofile->filebytepos = sizeof(struct BZip2V3Header); + + isofile->numsectors = (65536 / isofile->blocksize) - 1; + + isofile->filesectorsize = 0; + + isofile->filesectorpos = 0; + + isofile->compsector = 0; + + return(0); + +} // END BZip2V3OpenForWrite() + + + + + +int BZip2V3Write(struct IsoFile *isofile, char *buffer) { + + int retval; + + unsigned int blocklen; + + char tempblock[65536]; + + unsigned short tempsize; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Write()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + blocklen = 65536; + + retval = BZ2_bzBuffToBuffCompress(tempblock, + + &blocklen, + + buffer, + + isofile->blocksize * isofile->numsectors, + + 9, 0, 250); + + if(retval != BZ_OK) { + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Cannot encode block! Returned: (%i)", retval); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + return(-1); + + } // ENDIF- Trouble compressing a block? Abort. + + + + tempsize = blocklen; + + tempsize = ConvertEndianUShort(tempsize); + + retval = ActualFileWrite(isofile->handle, + + sizeof(unsigned short), + + (char *) &tempsize); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval < sizeof(unsigned short)) { + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Cannot write bytes! Returned: (%i out of %llu)", + + retval, sizeof(unsigned short)); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + return(-1); + + } // ENDIF- Trouble writing out the compressed block? Abort. + + + + + + retval = ActualFileWrite(isofile->handle, blocklen, tempblock); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval < blocklen) { + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Cannot write bytes! Returned: (%i out of %llu)", + + retval, blocklen); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + return(-1); + + } // ENDIF- Trouble writing out the compressed block? Abort. + + + + return(blocklen + sizeof(unsigned short)); // Not in list? Fail. + +} // END BZip2V3Write() + + + + + +void BZip2V3Close(struct IsoFile *isofile) { + + struct BZip2V3Header header; + + struct TableData table; + + int compptr; + + int i; + + int retval; + + unsigned short tempsize; + + + +#ifdef VERBOSE_FUNCTION_BZIP2V3 + + PrintLog("CDVDiso BZip2V3: Close()"); + +#endif /* VERBOSE_FUNCTION_BZIP2V3 */ + + + + if((isofile->tablehandle != ACTUALHANDLENULL) && + + (isofile->handle != ACTUALHANDLENULL)) { + + if(isofile->openforread == 0) { + + if(isofile->compsector != isofile->filesectorpos) { + + compptr = isofile->filesectorpos - isofile->compsector; + + compptr *= isofile->blocksize; + + for(i = compptr; i < 65536; i++) isofile->compblock[i] = 0; + + retval = BZip2V3Write(isofile, isofile->compblock); + + table.offset = isofile->filebytepos - retval; + + table.size = retval; + + BZip2V3WriteTable(isofile, table); + + isofile->compsector = isofile->filesectorpos; + + } // ENDIF - still have buffers to write? + + } // ENDIF- Opened for write? Don't forget to flush the file buffer! + + } // ENDIF- Both data file and table file are open? + + + + if(isofile->tablehandle != ACTUALHANDLENULL) { + + ActualFileClose(isofile->tablehandle); + + isofile->tablehandle = ACTUALHANDLENULL; + + } // ENDIF- Is there a table file open? Close it. + + + + if(isofile->handle != ACTUALHANDLENULL) { + + if(isofile->openforread == 0) { + + if(isofile->compsector != isofile->filesectorpos) { + + compptr = isofile->filesectorpos - isofile->compsector; + + compptr *= isofile->blocksize; + + for(i = compptr; i < 65536; i++) isofile->compblock[i] = 0; + + BZip2V3Write(isofile, isofile->compblock); + + } // ENDIF - still have buffers to write? + + header.id[0] = 'B'; + + header.id[1] = 'Z'; + + header.id[2] = 'V'; + + header.id[3] = '3'; + + tempsize = isofile->blocksize; + + header.blocksize = ConvertEndianUShort(tempsize); + + header.numblocks = ConvertEndianOffset(isofile->filesectorsize); + + tempsize = isofile->blockoffset; + + header.blockoffset = ConvertEndianUShort(tempsize); + + ActualFileSeek(isofile->handle, 0); + + ActualFileWrite(isofile->handle, + + sizeof(struct BZip2V3Header), + + (char *) &header); + + } // ENDIF- Opened for write? Don't forget to update the header block! + + + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + } // ENDIF- Is there a data file open? Close it. + + + + if(isofile->tabledata != NULL) { + + free(isofile->tabledata); + + isofile->tabledata = NULL; + + } // ENDIF- Do we have a read-in table to clear out? + + + + return; + +} // END BZip2V3Close() + diff --git a/plugins/CDVDisoEFP/src/bzip2v3.h b/plugins/CDVDisoEFP/src/bzip2v3.h index ab54e7c567..467534a0fd 100644 --- a/plugins/CDVDisoEFP/src/bzip2v3.h +++ b/plugins/CDVDisoEFP/src/bzip2v3.h @@ -1,104 +1,104 @@ -/* bzip2v3.h - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#ifndef BZIP2V3_H - -#define BZIP2V3_H - - - - - -#include - - - -#include "isofile.h" - -#include "isocompress.h" - - - - - -// #define VERBOSE_FUNCTION_BZIP2V3 - -// #define VERBOSE_WARNING_BZIP2V3 - - - - - -extern int BZip2V3OpenTableForRead(struct IsoFile *isofile); - -extern int BZip2V3SeekTable(struct IsoFile *isofile, off64_t sector); - -extern int BZip2V3ReadTable(struct IsoFile *isofile, struct TableData *table); - - - -extern int BZip2V3OpenTableForWrite(struct IsoFile *isofile); - -extern int BZip2V3WriteTable(struct IsoFile *isofile, struct TableData table); - - - -extern int BZip2V3OpenForRead(struct IsoFile *isofile); - -extern int BZip2V3Seek(struct IsoFile *isofile, off64_t sector); - -extern int BZip2V3Read(struct IsoFile *isofile, int bytes, char *buffer); - -extern void BZip2V3Close(struct IsoFile *isofile); - - - -extern int BZip2V3OpenForWrite(struct IsoFile *isofile); - -extern int BZip2V3Write(struct IsoFile *isofile, char *buffer); - - - - - -#endif /* BZIP2V3_H */ - +/* bzip2v3.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef BZIP2V3_H + +#define BZIP2V3_H + + + + + +#include + + + +#include "isofile.h" + +#include "isocompress.h" + + + + + +// #define VERBOSE_FUNCTION_BZIP2V3 + +// #define VERBOSE_WARNING_BZIP2V3 + + + + + +extern int BZip2V3OpenTableForRead(struct IsoFile *isofile); + +extern int BZip2V3SeekTable(struct IsoFile *isofile, off64_t sector); + +extern int BZip2V3ReadTable(struct IsoFile *isofile, struct TableData *table); + + + +extern int BZip2V3OpenTableForWrite(struct IsoFile *isofile); + +extern int BZip2V3WriteTable(struct IsoFile *isofile, struct TableData table); + + + +extern int BZip2V3OpenForRead(struct IsoFile *isofile); + +extern int BZip2V3Seek(struct IsoFile *isofile, off64_t sector); + +extern int BZip2V3Read(struct IsoFile *isofile, int bytes, char *buffer); + +extern void BZip2V3Close(struct IsoFile *isofile); + + + +extern int BZip2V3OpenForWrite(struct IsoFile *isofile); + +extern int BZip2V3Write(struct IsoFile *isofile, char *buffer); + + + + + +#endif /* BZIP2V3_H */ + diff --git a/plugins/CDVDisoEFP/src/convert.c b/plugins/CDVDisoEFP/src/convert.c index 5edbe9ea3f..1f41c4f2f6 100644 --- a/plugins/CDVDisoEFP/src/convert.c +++ b/plugins/CDVDisoEFP/src/convert.c @@ -1,118 +1,118 @@ -/* convert.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include -#include - -#include "convert.h" - - -off64_t ConvertEndianOffset(off64_t number) { -#ifndef CONVERTLITTLEENDIAN - union { - off64_t n; - char c[sizeof(off64_t)]; - } oldnumber, newnumber; - int i; - - oldnumber.n = number; - for(i = 0; i < sizeof(off64_t); i++) - newnumber.c[i] = oldnumber.c[sizeof(off64_t) - 1 - i]; - return(newnumber.n); -#else - return(number); -#endif /* CONVERTLITTLEENDIAN */ -} // END ConvertEndianOffset() - - -unsigned int ConvertEndianUInt(unsigned int number) { -#ifndef CONVERTLITTLEENDIAN - union { - unsigned int n; - char c[sizeof(unsigned int)]; - } oldnumber, newnumber; - int i; - - oldnumber.n = number; - for(i = 0; i < sizeof(unsigned int); i++) - newnumber.c[i] = oldnumber.c[sizeof(unsigned int) - 1 - i]; - return(newnumber.n); -#else - return(number); -#endif /* CONVERTLITTLEENDIAN */ -} // END ConvertEndianUInt() - - -unsigned short ConvertEndianUShort(unsigned short number) { -#ifndef CONVERTLITTLEENDIAN - union { - unsigned short n; - char c[sizeof(unsigned short)]; - } oldnumber, newnumber; - int i; - - oldnumber.n = number; - for(i = 0; i < sizeof(unsigned short); i++) - newnumber.c[i] = oldnumber.c[sizeof(unsigned short) - 1 - i]; - return(newnumber.n); -#else - return(number); -#endif /* CONVERTLITTLEENDIAN */ -} // END ConvertEndianUShort() - - -// Note: deposits M/S/F data in buffer[0]/[1]/[2] respectively. -void LBAtoMSF(unsigned long lsn, char *buffer) { - unsigned long templsn; - - if(lsn >= 0xFFFFFFFF - 150) { - *(buffer + 2) = 75-1; - *(buffer + 1) = 60-1; - *(buffer) = 100-1; - } // ENDIF- Out of range? - - templsn = lsn; - templsn += 150; // 2 second offset (75 Frames * 2 Seconds) - *(buffer + 2) = templsn % 75; // Remainder in frames - templsn -= *(buffer + 2); - templsn /= 75; - *(buffer + 1) = templsn % 60; // Remainder in seconds - templsn -= *(buffer + 1); - templsn /= 60; - *(buffer) = templsn; // Leftover quotient in minutes -} // END LBAtoMSF() - - -unsigned long MSFtoLBA(char *buffer) { - unsigned long templsn; - - if(buffer == NULL) return(0xFFFFFFFF); - - templsn = *(buffer); // Minutes - templsn *= 60; - templsn += *(buffer + 1); // Seconds - templsn *= 75; - templsn += *(buffer + 2); // Frames - if(templsn < 150) return(0xFFFFFFFF); - templsn -= 150; // Offset - - return(templsn); -} // END MSFtoLBA() +/* convert.c + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#include +#include + +#include "convert.h" + + +off64_t ConvertEndianOffset(off64_t number) { +#ifndef CONVERTLITTLEENDIAN + union { + off64_t n; + char c[sizeof(off64_t)]; + } oldnumber, newnumber; + int i; + + oldnumber.n = number; + for(i = 0; i < sizeof(off64_t); i++) + newnumber.c[i] = oldnumber.c[sizeof(off64_t) - 1 - i]; + return(newnumber.n); +#else + return(number); +#endif /* CONVERTLITTLEENDIAN */ +} // END ConvertEndianOffset() + + +unsigned int ConvertEndianUInt(unsigned int number) { +#ifndef CONVERTLITTLEENDIAN + union { + unsigned int n; + char c[sizeof(unsigned int)]; + } oldnumber, newnumber; + int i; + + oldnumber.n = number; + for(i = 0; i < sizeof(unsigned int); i++) + newnumber.c[i] = oldnumber.c[sizeof(unsigned int) - 1 - i]; + return(newnumber.n); +#else + return(number); +#endif /* CONVERTLITTLEENDIAN */ +} // END ConvertEndianUInt() + + +unsigned short ConvertEndianUShort(unsigned short number) { +#ifndef CONVERTLITTLEENDIAN + union { + unsigned short n; + char c[sizeof(unsigned short)]; + } oldnumber, newnumber; + int i; + + oldnumber.n = number; + for(i = 0; i < sizeof(unsigned short); i++) + newnumber.c[i] = oldnumber.c[sizeof(unsigned short) - 1 - i]; + return(newnumber.n); +#else + return(number); +#endif /* CONVERTLITTLEENDIAN */ +} // END ConvertEndianUShort() + + +// Note: deposits M/S/F data in buffer[0]/[1]/[2] respectively. +void LBAtoMSF(unsigned long lsn, char *buffer) { + unsigned long templsn; + + if(lsn >= 0xFFFFFFFF - 150) { + *(buffer + 2) = 75-1; + *(buffer + 1) = 60-1; + *(buffer) = 100-1; + } // ENDIF- Out of range? + + templsn = lsn; + templsn += 150; // 2 second offset (75 Frames * 2 Seconds) + *(buffer + 2) = templsn % 75; // Remainder in frames + templsn -= *(buffer + 2); + templsn /= 75; + *(buffer + 1) = templsn % 60; // Remainder in seconds + templsn -= *(buffer + 1); + templsn /= 60; + *(buffer) = templsn; // Leftover quotient in minutes +} // END LBAtoMSF() + + +unsigned long MSFtoLBA(char *buffer) { + unsigned long templsn; + + if(buffer == NULL) return(0xFFFFFFFF); + + templsn = *(buffer); // Minutes + templsn *= 60; + templsn += *(buffer + 1); // Seconds + templsn *= 75; + templsn += *(buffer + 2); // Frames + if(templsn < 150) return(0xFFFFFFFF); + templsn -= 150; // Offset + + return(templsn); +} // END MSFtoLBA() diff --git a/plugins/CDVDisoEFP/src/convert.h b/plugins/CDVDisoEFP/src/convert.h index 3933382a0a..8eb4bda61f 100644 --- a/plugins/CDVDisoEFP/src/convert.h +++ b/plugins/CDVDisoEFP/src/convert.h @@ -1,50 +1,50 @@ -/* convert.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef CONVERT_H -#define CONVERT_H - - -#include // off64_t -#include "PS2Etypes.h" -#ifdef __linux__ -#include "endian.h" -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define CONVERTLITTLEENDIAN -#endif /* __BYTE_ORDER */ -#endif /* __linux__ */ - -#ifdef _WIN32 -#define CONVERTLITTLEENDIAN -#endif /* _WIN32 */ - -#define HEXTOBCD(i) (((i)/10*16) + ((i)%10)) -#define BCDTOHEX(i) (((i)/16*10) + ((i)%16)) - - -extern off64_t ConvertEndianOffset(off64_t number); -extern unsigned int ConvertEndianUInt(unsigned int number); -extern unsigned short ConvertEndianUShort(unsigned short number); - -extern void LBAtoMSF(unsigned long lsn, char *buffer); -extern unsigned long MSFtoLBA(char *buffer); - -#endif /* CONVERT_H */ +/* convert.h + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + + +#ifndef CONVERT_H +#define CONVERT_H + + +#include // off64_t +#include "PS2Etypes.h" +#ifdef __linux__ +#include "endian.h" +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define CONVERTLITTLEENDIAN +#endif /* __BYTE_ORDER */ +#endif /* __linux__ */ + +#ifdef _WIN32 +#define CONVERTLITTLEENDIAN +#endif /* _WIN32 */ + +#define HEXTOBCD(i) (((i)/10*16) + ((i)%10)) +#define BCDTOHEX(i) (((i)/16*10) + ((i)%16)) + + +extern off64_t ConvertEndianOffset(off64_t number); +extern unsigned int ConvertEndianUInt(unsigned int number); +extern unsigned short ConvertEndianUShort(unsigned short number); + +extern void LBAtoMSF(unsigned long lsn, char *buffer); +extern unsigned long MSFtoLBA(char *buffer); + +#endif /* CONVERT_H */ diff --git a/plugins/CDVDisoEFP/src/ecma119.c b/plugins/CDVDisoEFP/src/ecma119.c index 24f2e4eb1c..44ac3ae57d 100644 --- a/plugins/CDVDisoEFP/src/ecma119.c +++ b/plugins/CDVDisoEFP/src/ecma119.c @@ -1,59 +1,118 @@ -/* ecma119.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include - -// #ifndef __LINUX__ -// #ifdef __linux__ -// #define __LINUX__ -// #endif /* __linux__ */ -// #endif /* No __LINUX__ */ - -// #define CDVDdefs -// #include "PS2Edefs.h" - -#include "ecma119.h" - - -const char ECMA119VolumeIDstdid[] = "CD001\0"; - - -int ValidateECMA119PrimaryVolume(struct ECMA119PrimaryVolume *volume) { - int i; - - if(volume == NULL) return(-1); - - // Volume ID - if(volume->id.voltype != 1) return(-1); // Incorrect volume type - if(volume->id.version != 1) return(-1); // Not a Standard Version? - i = 0; - while((ECMA119VolumeIDstdid[i] != 0) && - (ECMA119VolumeIDstdid[i] == volume->id.stdid[i])) i++; - if(ECMA119VolumeIDstdid[i] != 0) return(-1); // "CD001" did not match? - - // Looks like numblocksle might give us maximum sector count... - // Looks like blocksizele can be compared to blocksize stored in isofile... - - return(0); -} // END ValidateECMA119PrimaryVolume() - - -// Not sure the Partition Volume will be much help... +/* ecma119.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + + + +// #ifndef __LINUX__ + +// #ifdef __linux__ + +// #define __LINUX__ + +// #endif /* __linux__ */ + +// #endif /* No __LINUX__ */ + + + +// #define CDVDdefs + +// #include "PS2Edefs.h" + + + +#include "ecma119.h" + + + + + +const char ECMA119VolumeIDstdid[] = "CD001\0"; + + + + + +int ValidateECMA119PrimaryVolume(struct ECMA119PrimaryVolume *volume) { + + int i; + + + + if(volume == NULL) return(-1); + + + + // Volume ID + + if(volume->id.voltype != 1) return(-1); // Incorrect volume type + + if(volume->id.version != 1) return(-1); // Not a Standard Version? + + i = 0; + + while((ECMA119VolumeIDstdid[i] != 0) && + + (ECMA119VolumeIDstdid[i] == volume->id.stdid[i])) i++; + + if(ECMA119VolumeIDstdid[i] != 0) return(-1); // "CD001" did not match? + + + + // Looks like numblocksle might give us maximum sector count... + + // Looks like blocksizele can be compared to blocksize stored in isofile... + + + + return(0); + +} // END ValidateECMA119PrimaryVolume() + + + + + +// Not sure the Partition Volume will be much help... + diff --git a/plugins/CDVDisoEFP/src/ecma119.h b/plugins/CDVDisoEFP/src/ecma119.h index 494e65908e..1207d8e133 100644 --- a/plugins/CDVDisoEFP/src/ecma119.h +++ b/plugins/CDVDisoEFP/src/ecma119.h @@ -1,468 +1,468 @@ -/* ecma119.h - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#ifndef ECMA119_H - -#define ECMA119_H - - - - - -// #ifndef __LINUX__ - -// #ifdef __linux__ - -// #define __LINUX__ - -// #endif /* __linux__ */ - -// #endif /* No __LINUX__ */ - - - -// #define CDVDdefs - -// #include "PS2Edefs.h" - - - - - -// ECMA119 was sent to ISO to be fast-tracked into ISO 9660 - -// ECMA119 can be found at http://www.ecma.ch, somewhere. - - - -// Throughout these definitions, number pairs in both big-endian and - -// little-endian varieties are stored next to each other. To separate - -// the pairs a 'le' suffix has been attached to little-endian numbers, and - -// a 'be' suffix to big-endian ones. - - - -// All 'unused' entries should be set to (or tested for) 0x00. - - - - - -#ifdef _WIN32 - -#pragma pack(1) - -#endif /* _WIN32 */ - - - -struct ECMA119ASCIITime { - - char year[4]; - - char month[2]; - - char day[2]; - - char hour[2]; - - char min[2]; - - char sec[2]; - - char hundredthsec[2]; - - char offsetgmt; // 15 min intervals, from -48 to +52 - -#ifdef _WIN32 - -}; - -#else - -} __attribute__ ((packed)); - -#endif /* _WIN32 */ - - - -struct ECMA119DateTime { - - unsigned char year; // 1900+year, that is. - - unsigned char month; - - unsigned char day; - - unsigned char hour; - - unsigned char minute; - - unsigned char sec; - - signed char offsetgmt; // In 15 min intervals, from -48 to +52 - -#ifdef _WIN32 - -}; - -#else - -} __attribute__ ((packed)); - -#endif /* _WIN32 */ - - - -struct ECMA119DirectoryRecord { - - unsigned char reclen; // Length of this record - - unsigned char attlen; // Extended Attribute Record Length - - - - unsigned long externlocle; // Location of Extent - - unsigned long externlocbe; - - - - struct ECMA119DateTime recorded; // Recording Date and Time - - - - unsigned char flags; // File Flags - - unsigned char interleave; // Interleave Gap Size - - - - unsigned short seqnole; // Volume Sequence No. - - unsigned short seqnobe; - - - - unsigned short idlen; - - char id[223]; - - // Note: sometimes a OS uses the end of this record for it's own use. - -#ifdef _WIN32 - -}; - -#else - -} __attribute__ ((packed)); - -#endif /* _WIN32 */ - - - -struct ECMA119RootDirectoryRecord { - - unsigned char reclen; // Length of this record - - unsigned char attlen; // Extended Attribute Record Length - - - - unsigned long externlocle; // Location of Extent - - unsigned long externlocbe; - - - - struct ECMA119DateTime recorded; // Recording Date and Time - - - - unsigned char flags; // File Flags - - unsigned char interleave; // Interleave Gap Size - - - - unsigned short seqnole; // Volume Sequence No. - - unsigned short seqnobe; - - - - unsigned short idlen; - - char id[1]; // Probably for the '.' (But I'm just guessing :) - -#ifdef _WIN32 - -}; - -#else - -} __attribute__ ((packed)); - -#endif /* _WIN32 */ - - - -struct ECMA119VolumeID { - - unsigned char voltype; - - // 0 = Boot Record - - // 1 = Primary Volume Descriptor (PrimaryVolume below) - - // 2 = Supplementary Volume Descriptor - - // 3 = Partition Descriptor (PartitionVolume below) - - // 4 - 254 Reserved - - // 255 = End-of-Descriptor-Set - - - - char stdid[5]; // Standard Identifier. Always "CD001" - - - - unsigned char version; - -#ifdef _WIN32 - -}; - -#else - -} __attribute__ ((packed)); - -#endif /* _WIN32 */ - - - -struct ECMA119PrimaryVolume { - - struct ECMA119VolumeID id; - - // id.voltype should be 1 (for this type of volume) - - // id.version should be 1 (standard) - - - - char unused1; - - - - char systemid[32]; - - char volumeid[32]; - - - - char unused2[8]; - - - - unsigned long numblocksle; // Total logical blocks. (on Media? or just - - unsigned long numblocksbe; // in volume?) - - - - char unused3[32]; - - - - unsigned short volumesetsizele; // Volume Set size of the volume. (?) - - unsigned short volumesetsizebe; - - - - unsigned short ordinalle; // Count of which descriptor this is in the Volume - - unsigned short ordinalbe; // set. - - - - unsigned short blocksizele; // Size of a Logical Block - - unsigned short blocksizebe; - - - - unsigned long pathtablesizele; // Path Table Size - - unsigned long pathtablesizebe; - - - - unsigned long typelpathtablelocation; // (le) Location of a Type L Path Table - - - - unsigned long typelopttablelocation; // (le) Location of an Optional Type L - - - - unsigned long typempathtablelocation; // (be) Location of a Type M Path Table - - - - unsigned long typemopttablelocation; // (be) Location of an Optional Type M - - - - struct ECMA119RootDirectoryRecord root; - - - - char volumesetid[128]; // Volume Set ID - - - - char publisher[128]; // Publisher - - - - char datapreparer[128]; // Data Preparer - - - - char application[128]; // Application ID - - - - char copyrightfile[37]; // Copyright File Identifier - - - - char abstractfile[37]; // Abstract File Identifier - - - - char bibliograchicfile[37]; // Bibliographic File Identifier - - - - struct ECMA119ASCIITime volcreatedate; // Date Created - - struct ECMA119ASCIITime volmodifydate; // Last Date Modified - - struct ECMA119ASCIITime volexpiredate; // Date data expires - - struct ECMA119ASCIITime voleffectivedata; // Date data becomes accurate (effective) - - - - unsigned char filestructversion; // File Structure Version - - // Should be 1 = Standard - - - - char unused4; - - - - char applicationuse[512]; // For use by an application - - - - char unused5[653]; // Rounds this out to 2048 bytes... - -#ifdef _WIN32 - -}; - -#else - -} __attribute__ ((packed)); - -#endif /* _WIN32 */ - - - -// struct ECMA119PartitionVolume { - -// struct ECMA119VolumeID id; - -// #ifdef _WIN32 - -// }; - -// #else - -// } __attribute__ ((packed)); - -// #endif /* _WIN32 */ - - - -#ifdef _WIN32 - -#pragma pack() - -#endif /* _WIN32 */ - - - - - -extern int ValidateECMA119PrimaryVolume(struct ECMA119PrimaryVolume *volume); - -// extern int ValidateECMA119PartitionVolume(struct ECMA119PartitionVolume volume); - - - - - -#endif /* ECMA119_H */ - +/* ecma119.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef ECMA119_H + +#define ECMA119_H + + + + + +// #ifndef __LINUX__ + +// #ifdef __linux__ + +// #define __LINUX__ + +// #endif /* __linux__ */ + +// #endif /* No __LINUX__ */ + + + +// #define CDVDdefs + +// #include "PS2Edefs.h" + + + + + +// ECMA119 was sent to ISO to be fast-tracked into ISO 9660 + +// ECMA119 can be found at http://www.ecma.ch, somewhere. + + + +// Throughout these definitions, number pairs in both big-endian and + +// little-endian varieties are stored next to each other. To separate + +// the pairs a 'le' suffix has been attached to little-endian numbers, and + +// a 'be' suffix to big-endian ones. + + + +// All 'unused' entries should be set to (or tested for) 0x00. + + + + + +#ifdef _WIN32 + +#pragma pack(1) + +#endif /* _WIN32 */ + + + +struct ECMA119ASCIITime { + + char year[4]; + + char month[2]; + + char day[2]; + + char hour[2]; + + char min[2]; + + char sec[2]; + + char hundredthsec[2]; + + char offsetgmt; // 15 min intervals, from -48 to +52 + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +struct ECMA119DateTime { + + unsigned char year; // 1900+year, that is. + + unsigned char month; + + unsigned char day; + + unsigned char hour; + + unsigned char minute; + + unsigned char sec; + + signed char offsetgmt; // In 15 min intervals, from -48 to +52 + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +struct ECMA119DirectoryRecord { + + unsigned char reclen; // Length of this record + + unsigned char attlen; // Extended Attribute Record Length + + + + unsigned long externlocle; // Location of Extent + + unsigned long externlocbe; + + + + struct ECMA119DateTime recorded; // Recording Date and Time + + + + unsigned char flags; // File Flags + + unsigned char interleave; // Interleave Gap Size + + + + unsigned short seqnole; // Volume Sequence No. + + unsigned short seqnobe; + + + + unsigned short idlen; + + char id[223]; + + // Note: sometimes a OS uses the end of this record for it's own use. + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +struct ECMA119RootDirectoryRecord { + + unsigned char reclen; // Length of this record + + unsigned char attlen; // Extended Attribute Record Length + + + + unsigned long externlocle; // Location of Extent + + unsigned long externlocbe; + + + + struct ECMA119DateTime recorded; // Recording Date and Time + + + + unsigned char flags; // File Flags + + unsigned char interleave; // Interleave Gap Size + + + + unsigned short seqnole; // Volume Sequence No. + + unsigned short seqnobe; + + + + unsigned short idlen; + + char id[1]; // Probably for the '.' (But I'm just guessing :) + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +struct ECMA119VolumeID { + + unsigned char voltype; + + // 0 = Boot Record + + // 1 = Primary Volume Descriptor (PrimaryVolume below) + + // 2 = Supplementary Volume Descriptor + + // 3 = Partition Descriptor (PartitionVolume below) + + // 4 - 254 Reserved + + // 255 = End-of-Descriptor-Set + + + + char stdid[5]; // Standard Identifier. Always "CD001" + + + + unsigned char version; + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +struct ECMA119PrimaryVolume { + + struct ECMA119VolumeID id; + + // id.voltype should be 1 (for this type of volume) + + // id.version should be 1 (standard) + + + + char unused1; + + + + char systemid[32]; + + char volumeid[32]; + + + + char unused2[8]; + + + + unsigned long numblocksle; // Total logical blocks. (on Media? or just + + unsigned long numblocksbe; // in volume?) + + + + char unused3[32]; + + + + unsigned short volumesetsizele; // Volume Set size of the volume. (?) + + unsigned short volumesetsizebe; + + + + unsigned short ordinalle; // Count of which descriptor this is in the Volume + + unsigned short ordinalbe; // set. + + + + unsigned short blocksizele; // Size of a Logical Block + + unsigned short blocksizebe; + + + + unsigned long pathtablesizele; // Path Table Size + + unsigned long pathtablesizebe; + + + + unsigned long typelpathtablelocation; // (le) Location of a Type L Path Table + + + + unsigned long typelopttablelocation; // (le) Location of an Optional Type L + + + + unsigned long typempathtablelocation; // (be) Location of a Type M Path Table + + + + unsigned long typemopttablelocation; // (be) Location of an Optional Type M + + + + struct ECMA119RootDirectoryRecord root; + + + + char volumesetid[128]; // Volume Set ID + + + + char publisher[128]; // Publisher + + + + char datapreparer[128]; // Data Preparer + + + + char application[128]; // Application ID + + + + char copyrightfile[37]; // Copyright File Identifier + + + + char abstractfile[37]; // Abstract File Identifier + + + + char bibliograchicfile[37]; // Bibliographic File Identifier + + + + struct ECMA119ASCIITime volcreatedate; // Date Created + + struct ECMA119ASCIITime volmodifydate; // Last Date Modified + + struct ECMA119ASCIITime volexpiredate; // Date data expires + + struct ECMA119ASCIITime voleffectivedata; // Date data becomes accurate (effective) + + + + unsigned char filestructversion; // File Structure Version + + // Should be 1 = Standard + + + + char unused4; + + + + char applicationuse[512]; // For use by an application + + + + char unused5[653]; // Rounds this out to 2048 bytes... + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +// struct ECMA119PartitionVolume { + +// struct ECMA119VolumeID id; + +// #ifdef _WIN32 + +// }; + +// #else + +// } __attribute__ ((packed)); + +// #endif /* _WIN32 */ + + + +#ifdef _WIN32 + +#pragma pack() + +#endif /* _WIN32 */ + + + + + +extern int ValidateECMA119PrimaryVolume(struct ECMA119PrimaryVolume *volume); + +// extern int ValidateECMA119PartitionVolume(struct ECMA119PartitionVolume volume); + + + + + +#endif /* ECMA119_H */ + diff --git a/plugins/CDVDisoEFP/src/gzipv1.c b/plugins/CDVDisoEFP/src/gzipv1.c index bdd73de01d..9c8d438525 100644 --- a/plugins/CDVDisoEFP/src/gzipv1.c +++ b/plugins/CDVDisoEFP/src/gzipv1.c @@ -1,844 +1,844 @@ -/* gzipv1.c - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#include // NULL - - - -#include "zlib/zlib.h" - - - -#include "convert.h" - -#include "logfile.h" - -#include "isofile.h" - -#include "isocompress.h" // TableData - -#include "actualfile.h" - -#include "gzipv1.h" - - - - - -#ifdef _WIN32 - -#pragma pack(1) - -#endif /* _WIN32 */ - - - -struct GZipV1Table { - - unsigned int offset; // Data file position - - unsigned short size; // of Compressed data - -#ifdef _WIN32 - -}; - -#else - -} __attribute__ ((packed)); - -#endif /* _WIN32 */ - - - -#ifdef _WIN32 - -#pragma pack() - -#endif /* _WIN32 */ - - - - - -int GZipV1OpenTableForRead(struct IsoFile *isofile) { - - int i; - - int j; - - char tableext[] = ".table\0"; - - - -#ifdef VERBOSE_FUNCTION_GZIPV1 - - PrintLog("CDVDiso GZipV1: OpenTableForRead()"); - -#endif /* VERBOSE_FUNCTION_GZIPV1 */ - - - - i = 0; - - while((i < 256) && (isofile->name[i] != 0)) { - - isofile->tablename[i] = isofile->name[i]; - - i++; - - } // ENDWHILE- Copying the data name to the table name - - j = 0; - - while((i < 256) && (tableext[j] != 0)) { - - isofile->tablename[i] = tableext[j]; - - i++; - - j++; - - } // ENDWHILE- Adding the ".table" extension. - - isofile->tablename[i] = 0; // And 0-terminate. - - - - isofile->tablehandle = ActualFileOpenForRead(isofile->tablename); - - if(isofile->tablehandle == ACTUALHANDLENULL) { - -#ifdef VERBOSE_WARNING_GZIPV1 - - PrintLog("CDVDiso GZipV1: Couldn't open table!"); - -#endif /* VERBOSE_WARNING_GZIPV1 */ - - return(-2); - - } // ENDIF- Couldn't open table file? Fail. - - - - isofile->filesectorsize = ActualFileSize(isofile->tablehandle) - - / sizeof(struct GZipV1Table); - - - - return(0); - -} // END GZipV1OpenTableForRead() - - - - - -int GZipV1SeekTable(struct IsoFile *isofile, off64_t sector) { - - off64_t target; - - int retval; - - - -#ifdef VERBOSE_FUNCTION_GZIPV1 - - PrintLog("CDVDiso GZipV1: SeekTable(%lli)", sector); - -#endif /* VERBOSE_FUNCTION_GZIPV1 */ - - - - target = sector * sizeof(struct GZipV1Table); - - retval = ActualFileSeek(isofile->tablehandle, target); - - if(retval < 0) { - -#ifdef VERBOSE_WARNING_GZIPV1 - - PrintLog("CDVDiso GZipV1: Couldn't find sector!"); - -#endif /* VERBOSE_WARNING_GZIPV1 */ - - return(-2); - - } // ENDIF- Trouble finding the place? Fail. - - - - isofile->filesectorpos = sector; - - return(0); - -} // END GZipV1SeekTable() - - - - - -int GZipV1ReadTable(struct IsoFile *isofile, struct TableData *table) { - - int retval; - - struct GZipV1Table temptable; - - - -#ifdef VERBOSE_FUNCTION_GZIPV1 - - PrintLog("CDVDiso GZipV1: ReadTable()"); - -#endif /* VERBOSE_FUNCTION_GZIPV1 */ - - - - retval = ActualFileRead(isofile->tablehandle, - - sizeof(struct GZipV1Table), - - (char *) &temptable); - - if(retval != sizeof(struct GZipV1Table)) { - -#ifdef VERBOSE_WARNING_GZIPV1 - - PrintLog("CDVDiso GZipV1: Couldn't read table entry!"); - -#endif /* VERBOSE_WARNING_GZIPV1 */ - - return(-2); - - } // ENDIF- Trouble reading table entry? Fail. - - - - table->offset = ConvertEndianUInt(temptable.offset); - - table->size = ConvertEndianUShort(temptable.size); - - isofile->filesectorpos++; - - return(0); - -} // END GZipV1ReadTable() - - - - - -int GZipV1OpenTableForWrite(struct IsoFile *isofile) { - - int i; - - int j; - - char tableext[] = ".table\0"; - - - -#ifdef VERBOSE_FUNCTION_GZIPV1 - - PrintLog("CDVDiso GZipV1: OpenTableForWrite()"); - -#endif /* VERBOSE_FUNCTION_GZIPV1 */ - - - - i = 0; - - while((i < 256) && (isofile->name[i] != 0)) { - - isofile->tablename[i] = isofile->name[i]; - - i++; - - } // ENDWHILE- Copying the data name to the table name - - j = 0; - - while((i < 256) && (tableext[j] != 0)) { - - isofile->tablename[i] = tableext[j]; - - i++; - - j++; - - } // ENDWHILE- Adding the ".table" extension. - - isofile->tablename[i] = 0; // And 0-terminate. - - - - isofile->tablehandle = ActualFileOpenForWrite(isofile->tablename); - - if(isofile->tablehandle == ACTUALHANDLENULL) { - -#ifdef VERBOSE_WARNING_GZIPV1 - - PrintLog("CDVDiso GZipV1: Couldn't open table!"); - -#endif /* VERBOSE_WARNING_GZIPV1 */ - - return(-2); - - } // ENDIF- Couldn't open table file? Fail. - - - - isofile->filesectorsize = 0; - - return(0); - -} // END GZipV1OpenTableForWrite() - - - - - -int GZipV1WriteTable(struct IsoFile *isofile, struct TableData table) { - - int retval; - - struct GZipV1Table temptable; - - unsigned int tempint; - - - -#ifdef VERBOSE_FUNCTION_GZIPV1 - - PrintLog("CDVDiso GZipV1: WriteTable(%lli, %i)", table.offset, table.size); - -#endif /* VERBOSE_FUNCTION_GZIPV1 */ - - - - tempint = table.offset; - - temptable.offset = ConvertEndianUInt(tempint); - - temptable.size = ConvertEndianUShort(table.size); - - retval = ActualFileWrite(isofile->tablehandle, - - sizeof(struct GZipV1Table), - - (char *) &temptable); - - if(retval != sizeof(struct GZipV1Table)) { - -#ifdef VERBOSE_WARNING_GZIPV1 - - PrintLog("CDVDiso GZipV1: Couldn't write table entry!"); - -#endif /* VERBOSE_WARNING_GZIPV1 */ - - return(-2); - - } // ENDIF- Trouble reading table entry? Fail. - - - - return(0); - -} // END GZipV1WriteTable() - - - - - -int GZipV1OpenForRead(struct IsoFile *isofile) { - - int retval; - - char tempblock[2448]; - - - -#ifdef VERBOSE_FUNCTION_GZIPV1 - - PrintLog("CDVDiso GZipV1: OpenForRead()"); - -#endif /* VERBOSE_FUNCTION_GZIPV1 */ - - - - isofile->handle = ActualFileOpenForRead(isofile->name); - - if(isofile->handle == ACTUALHANDLENULL) { - - return(-1); - - } // ENDIF- Couldn't open data file? Fail. - - - - isofile->filebytesize = ActualFileSize(isofile->handle); - - isofile->filebytepos = 0; - - isofile->filesectorpos = 0; - - - - isofile->imageheader = 0; - - isofile->blocksize = 2352; - - isofile->blockoffset = 0; // Don't panic. "imagetype.c" will test later. - - isofile->numsectors = 1; // Sectors per block - - - - retval = GZipV1Read(isofile, 2448, tempblock); - - if(retval != 0) { - -#ifdef VERBOSE_WARNING_GZIPV1 - - PrintLog("CDVDiso GZipV1: Couldn't decode the first block. Not compressed?"); - -#endif /* VERBOSE_WARNING_GZIPV1 */ - - ActualFileClose(isofile->handle); - - isofile->handle = ACTUALHANDLENULL; - - return(-1); - - } // ENDIF Could not read the first sector? Fail. - - - - ActualFileSeek(isofile->handle, 0); // Restart at top of file - - isofile->filebytepos = 0; - - isofile->filesectorpos = 0; - - return(0); - -} // END GZipV1OpenForRead() - - - - - -int GZipV1Seek(struct IsoFile *isofile, off64_t position) { - - int retval; - - - -#ifdef VERBOSE_FUNCTION_GZIPV1 - - PrintLog("CDVDiso GZipV1: Seek(%lli)", position); - -#endif /* VERBOSE_FUNCTION_GZIPV1 */ - - - - retval = ActualFileSeek(isofile->handle, position); - - if(retval < 0) { - -#ifdef VERBOSE_WARNING_GZIPV1 - - PrintLog("CDVDiso GZipV1: Couldn't find the start of the compressed block!"); - -#endif /* VERBOSE_WARNING_GZIPV1 */ - - return(-1); - - } // ENDIF- Couldn't find the data entry? Fail. - - isofile->filebytepos = position; - - return(0); - - - - return(-1); // Fail. (Due to lack of ambition?) - -} // END GZipV1Seek() - - - - - -int GZipV1Read(struct IsoFile *isofile, int bytes, char *buffer) { - - int retval; - - unsigned long blocklen; - - z_stream strm; - - unsigned long tempin; - - char tempblock[2800]; - - unsigned long tempout; - - - -#ifdef VERBOSE_FUNCTION_GZIPV1 - - PrintLog("CDVDiso GZipV1: Read(%i)", bytes); - -#endif /* VERBOSE_FUNCTION_GZIPV1 */ - - - - if(bytes > 0) { - - retval = ActualFileRead(isofile->handle, bytes, tempblock); - - if(retval > 0) isofile->filebytepos += retval; - - if(retval != bytes) { - -#ifdef VERBOSE_WARNING_GZIPV1 - - PrintLog("CDVDiso GZipV1: Cannot read bytes! Returned: (%i)", retval); - -#endif /* VERBOSE_WARNING_GZIPV1 */ - - return(-1); - - } // ENDIF- Trouble reading compressed sector? Abort. - - - - blocklen = isofile->blocksize; - - retval = uncompress(buffer, &blocklen, tempblock, bytes); - - if(retval != Z_OK) { - -#ifdef VERBOSE_WARNING_GZIPV1 - - PrintLog("CDVDiso GZipV1: Cannot decode block! Returned: (%i)", retval); - -#endif /* VERBOSE_WARNING_GZIPV1 */ - - return(-1); - - } // ENDIF- Trouble decoding the sector? Abort. - - - - return(0); - - } // ENDIF- Do we know how many compressed bytes to get for this record? - - - - // Hmm. Don't know the compressed size? Well, we'll just have to find it. - - - - tempin = 0; - - tempout = 0; - - retval = Z_OK; - - while((tempin < 2800) && (tempout < 2352)) { - - - - strm.zalloc = (alloc_func)0; - - strm.zfree = (free_func)0; - - - - strm.next_in = tempblock; - - strm.next_out = buffer; - - - - strm.avail_in = tempin; - - strm.avail_out = 2800; - - - - retval = inflateInit(&strm); - - if (retval != Z_OK) return(-1); - - - - while((tempin < 2800) && (retval == Z_OK)) { - - retval = ActualFileRead(isofile->handle, 1, &tempblock[tempin]); - - if(retval != 1) { - -#ifdef VERBOSE_WARNING_GZIPV1 - - PrintLog("CDVDiso GZipV1: Cannot read a byte! Returned: (%i)", retval); - -#endif /* VERBOSE_WARNING_GZIPV1 */ - - return(-1); - - } // ENDIF- Trouble reading compressed sector? Abort. - - tempin++; - - strm.avail_in++; - - - - strm.next_in = &tempblock[tempin - strm.avail_in]; - - retval = inflate(&strm, Z_NO_FLUSH); - - } // ENDWHILE- trying to uncompress an increasingly filled buffer - - tempout = strm.total_out; - - inflateEnd(&strm); - -#ifdef VERBOSE_FUNCTION_GZIPV1 - - PrintLog("CDVDiso GZipV1: tempin=%lu tempout=%lu retval=%i", - - tempin, tempout, retval); - -#endif /* VERBOSE_FUNCTION_GZIPV1 */ - - - - } // ENDWHILE- trying to uncompress a whole buffer - - if(retval != Z_STREAM_END) { - -#ifdef VERBOSE_WARNING_GZIPV1 - - PrintLog("CDVDiso GZipV1: Failed to decode block! Returned: (%i)", retval); - -#endif /* VERBOSE_WARNING_GZIPV1 */ - - return(-1); - - } // ENDIF- Trouble reading compressed sector? Abort. - - - - if(tempin == 2800) { - -#ifdef VERBOSE_WARNING_GZIPV1 - - PrintLog("CDVDiso GZipV1: Overfilled input buffer for only %llu bytes!", tempout); - -#endif /* VERBOSE_WARNING_GZIPV1 */ - - return(-1); - - } // ENDIF- Trouble reading compressed sector? Abort. - - isofile->filebytepos += tempin; - - return(tempin); // Send out # of compressed bytes (to record in table) - -} // END GZipV1Read() - - - - - -int GZipV1OpenForWrite(struct IsoFile *isofile) { - - if(isofile == NULL) return(-1); - - - -#ifdef VERBOSE_FUNCTION_GZIPV1 - - PrintLog("CDVDiso GZipV1: OpenForWrite()"); - -#endif /* VERBOSE_FUNCTION_GZIPV1 */ - - - - isofile->handle = ActualFileOpenForWrite(isofile->name); - - if(isofile->handle == ACTUALHANDLENULL) { - - return(-1); - - } // ENDIF- Couldn't open data file? Fail. - - - - isofile->filebytesize = 0; - - isofile->filebytepos = 0; - - return(0); - -} // END GZipV1OpenForWrite() - - - - - -int GZipV1Write(struct IsoFile *isofile, char *buffer) { - - int retval; - - unsigned long blocklen; - - char tempblock[2800]; - - - -#ifdef VERBOSE_FUNCTION_GZIPV1 - - PrintLog("CDVDiso GZipV1: Write()"); - -#endif /* VERBOSE_FUNCTION_GZIPV1 */ - - - - blocklen = 2800; - - retval = compress2(tempblock, &blocklen, - - buffer, 2352, - - Z_BEST_COMPRESSION); - - if(retval != Z_OK) { - -#ifdef VERBOSE_FUNCTION_GZIPV1 - - PrintLog("CDVDiso GZipV1: Cannot encode block! Returned: (%i)", retval); - -#endif /* VERBOSE_FUNCTION_GZIPV1 */ - - return(-1); - - } // ENDIF- Trouble compressing a block? Abort. - - - - retval = ActualFileWrite(isofile->handle, blocklen, tempblock); - - if(retval > 0) isofile->filebytepos += retval; - - if(retval < blocklen) { - -#ifdef VERBOSE_FUNCTION_GZIPV1 - - PrintLog("CDVDiso GZipV1: Cannot write bytes! Returned: (%i out of %llu)", - - retval, blocklen); - -#endif /* VERBOSE_FUNCTION_GZIPV1 */ - - return(-1); - - } // ENDIF- Trouble writing out the compressed block? Abort. - - isofile->filesectorpos++; - - - - return(blocklen); - -} // END GZipV1Write() - - - - - -void GZipV1Close(struct IsoFile *isofile) { - -#ifdef VERBOSE_FUNCTION_GZIPV1 - - PrintLog("CDVDiso GZipV1: Close()"); - -#endif /* VERBOSE_FUNCTION_GZIPV1 */ - - - - // Flush Write data... if any was held in the compression block area. - - // In this case, though... nothing's held there. - - - - if(isofile->tablehandle != ACTUALHANDLENULL) { - - ActualFileClose(isofile->tablehandle); - - isofile->tablehandle = ACTUALHANDLENULL; - - } // ENDIF- Is there a table file open? Close it. - - - - if(isofile->handle != ACTUALHANDLENULL) { - - ActualFileClose(isofile->handle); - - isofile->handle = ACTUALHANDLENULL; - - } // ENDIF- Is there a data file open? Close it. - - - - return; - -} // END GZipV1Close() - +/* gzipv1.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + + + +#include "zlib/zlib.h" + + + +#include "convert.h" + +#include "logfile.h" + +#include "isofile.h" + +#include "isocompress.h" // TableData + +#include "actualfile.h" + +#include "gzipv1.h" + + + + + +#ifdef _WIN32 + +#pragma pack(1) + +#endif /* _WIN32 */ + + + +struct GZipV1Table { + + unsigned int offset; // Data file position + + unsigned short size; // of Compressed data + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +#ifdef _WIN32 + +#pragma pack() + +#endif /* _WIN32 */ + + + + + +int GZipV1OpenTableForRead(struct IsoFile *isofile) { + + int i; + + int j; + + char tableext[] = ".table\0"; + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: OpenTableForRead()"); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + i = 0; + + while((i < 256) && (isofile->name[i] != 0)) { + + isofile->tablename[i] = isofile->name[i]; + + i++; + + } // ENDWHILE- Copying the data name to the table name + + j = 0; + + while((i < 256) && (tableext[j] != 0)) { + + isofile->tablename[i] = tableext[j]; + + i++; + + j++; + + } // ENDWHILE- Adding the ".table" extension. + + isofile->tablename[i] = 0; // And 0-terminate. + + + + isofile->tablehandle = ActualFileOpenForRead(isofile->tablename); + + if(isofile->tablehandle == ACTUALHANDLENULL) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Couldn't open table!"); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-2); + + } // ENDIF- Couldn't open table file? Fail. + + + + isofile->filesectorsize = ActualFileSize(isofile->tablehandle) + + / sizeof(struct GZipV1Table); + + + + return(0); + +} // END GZipV1OpenTableForRead() + + + + + +int GZipV1SeekTable(struct IsoFile *isofile, off64_t sector) { + + off64_t target; + + int retval; + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: SeekTable(%lli)", sector); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + target = sector * sizeof(struct GZipV1Table); + + retval = ActualFileSeek(isofile->tablehandle, target); + + if(retval < 0) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Couldn't find sector!"); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-2); + + } // ENDIF- Trouble finding the place? Fail. + + + + isofile->filesectorpos = sector; + + return(0); + +} // END GZipV1SeekTable() + + + + + +int GZipV1ReadTable(struct IsoFile *isofile, struct TableData *table) { + + int retval; + + struct GZipV1Table temptable; + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: ReadTable()"); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + retval = ActualFileRead(isofile->tablehandle, + + sizeof(struct GZipV1Table), + + (char *) &temptable); + + if(retval != sizeof(struct GZipV1Table)) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Couldn't read table entry!"); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-2); + + } // ENDIF- Trouble reading table entry? Fail. + + + + table->offset = ConvertEndianUInt(temptable.offset); + + table->size = ConvertEndianUShort(temptable.size); + + isofile->filesectorpos++; + + return(0); + +} // END GZipV1ReadTable() + + + + + +int GZipV1OpenTableForWrite(struct IsoFile *isofile) { + + int i; + + int j; + + char tableext[] = ".table\0"; + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: OpenTableForWrite()"); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + i = 0; + + while((i < 256) && (isofile->name[i] != 0)) { + + isofile->tablename[i] = isofile->name[i]; + + i++; + + } // ENDWHILE- Copying the data name to the table name + + j = 0; + + while((i < 256) && (tableext[j] != 0)) { + + isofile->tablename[i] = tableext[j]; + + i++; + + j++; + + } // ENDWHILE- Adding the ".table" extension. + + isofile->tablename[i] = 0; // And 0-terminate. + + + + isofile->tablehandle = ActualFileOpenForWrite(isofile->tablename); + + if(isofile->tablehandle == ACTUALHANDLENULL) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Couldn't open table!"); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-2); + + } // ENDIF- Couldn't open table file? Fail. + + + + isofile->filesectorsize = 0; + + return(0); + +} // END GZipV1OpenTableForWrite() + + + + + +int GZipV1WriteTable(struct IsoFile *isofile, struct TableData table) { + + int retval; + + struct GZipV1Table temptable; + + unsigned int tempint; + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: WriteTable(%lli, %i)", table.offset, table.size); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + tempint = table.offset; + + temptable.offset = ConvertEndianUInt(tempint); + + temptable.size = ConvertEndianUShort(table.size); + + retval = ActualFileWrite(isofile->tablehandle, + + sizeof(struct GZipV1Table), + + (char *) &temptable); + + if(retval != sizeof(struct GZipV1Table)) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Couldn't write table entry!"); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-2); + + } // ENDIF- Trouble reading table entry? Fail. + + + + return(0); + +} // END GZipV1WriteTable() + + + + + +int GZipV1OpenForRead(struct IsoFile *isofile) { + + int retval; + + char tempblock[2448]; + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: OpenForRead()"); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + isofile->handle = ActualFileOpenForRead(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + return(-1); + + } // ENDIF- Couldn't open data file? Fail. + + + + isofile->filebytesize = ActualFileSize(isofile->handle); + + isofile->filebytepos = 0; + + isofile->filesectorpos = 0; + + + + isofile->imageheader = 0; + + isofile->blocksize = 2352; + + isofile->blockoffset = 0; // Don't panic. "imagetype.c" will test later. + + isofile->numsectors = 1; // Sectors per block + + + + retval = GZipV1Read(isofile, 2448, tempblock); + + if(retval != 0) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Couldn't decode the first block. Not compressed?"); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF Could not read the first sector? Fail. + + + + ActualFileSeek(isofile->handle, 0); // Restart at top of file + + isofile->filebytepos = 0; + + isofile->filesectorpos = 0; + + return(0); + +} // END GZipV1OpenForRead() + + + + + +int GZipV1Seek(struct IsoFile *isofile, off64_t position) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: Seek(%lli)", position); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + retval = ActualFileSeek(isofile->handle, position); + + if(retval < 0) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Couldn't find the start of the compressed block!"); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-1); + + } // ENDIF- Couldn't find the data entry? Fail. + + isofile->filebytepos = position; + + return(0); + + + + return(-1); // Fail. (Due to lack of ambition?) + +} // END GZipV1Seek() + + + + + +int GZipV1Read(struct IsoFile *isofile, int bytes, char *buffer) { + + int retval; + + unsigned long blocklen; + + z_stream strm; + + unsigned long tempin; + + char tempblock[2800]; + + unsigned long tempout; + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: Read(%i)", bytes); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + if(bytes > 0) { + + retval = ActualFileRead(isofile->handle, bytes, tempblock); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval != bytes) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Cannot read bytes! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + + + blocklen = isofile->blocksize; + + retval = uncompress(buffer, &blocklen, tempblock, bytes); + + if(retval != Z_OK) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Cannot decode block! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-1); + + } // ENDIF- Trouble decoding the sector? Abort. + + + + return(0); + + } // ENDIF- Do we know how many compressed bytes to get for this record? + + + + // Hmm. Don't know the compressed size? Well, we'll just have to find it. + + + + tempin = 0; + + tempout = 0; + + retval = Z_OK; + + while((tempin < 2800) && (tempout < 2352)) { + + + + strm.zalloc = (alloc_func)0; + + strm.zfree = (free_func)0; + + + + strm.next_in = tempblock; + + strm.next_out = buffer; + + + + strm.avail_in = tempin; + + strm.avail_out = 2800; + + + + retval = inflateInit(&strm); + + if (retval != Z_OK) return(-1); + + + + while((tempin < 2800) && (retval == Z_OK)) { + + retval = ActualFileRead(isofile->handle, 1, &tempblock[tempin]); + + if(retval != 1) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Cannot read a byte! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + tempin++; + + strm.avail_in++; + + + + strm.next_in = &tempblock[tempin - strm.avail_in]; + + retval = inflate(&strm, Z_NO_FLUSH); + + } // ENDWHILE- trying to uncompress an increasingly filled buffer + + tempout = strm.total_out; + + inflateEnd(&strm); + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: tempin=%lu tempout=%lu retval=%i", + + tempin, tempout, retval); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + } // ENDWHILE- trying to uncompress a whole buffer + + if(retval != Z_STREAM_END) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Failed to decode block! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + + + if(tempin == 2800) { + +#ifdef VERBOSE_WARNING_GZIPV1 + + PrintLog("CDVDiso GZipV1: Overfilled input buffer for only %llu bytes!", tempout); + +#endif /* VERBOSE_WARNING_GZIPV1 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + isofile->filebytepos += tempin; + + return(tempin); // Send out # of compressed bytes (to record in table) + +} // END GZipV1Read() + + + + + +int GZipV1OpenForWrite(struct IsoFile *isofile) { + + if(isofile == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: OpenForWrite()"); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + isofile->handle = ActualFileOpenForWrite(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + return(-1); + + } // ENDIF- Couldn't open data file? Fail. + + + + isofile->filebytesize = 0; + + isofile->filebytepos = 0; + + return(0); + +} // END GZipV1OpenForWrite() + + + + + +int GZipV1Write(struct IsoFile *isofile, char *buffer) { + + int retval; + + unsigned long blocklen; + + char tempblock[2800]; + + + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: Write()"); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + blocklen = 2800; + + retval = compress2(tempblock, &blocklen, + + buffer, 2352, + + Z_BEST_COMPRESSION); + + if(retval != Z_OK) { + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: Cannot encode block! Returned: (%i)", retval); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + return(-1); + + } // ENDIF- Trouble compressing a block? Abort. + + + + retval = ActualFileWrite(isofile->handle, blocklen, tempblock); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval < blocklen) { + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: Cannot write bytes! Returned: (%i out of %llu)", + + retval, blocklen); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + return(-1); + + } // ENDIF- Trouble writing out the compressed block? Abort. + + isofile->filesectorpos++; + + + + return(blocklen); + +} // END GZipV1Write() + + + + + +void GZipV1Close(struct IsoFile *isofile) { + +#ifdef VERBOSE_FUNCTION_GZIPV1 + + PrintLog("CDVDiso GZipV1: Close()"); + +#endif /* VERBOSE_FUNCTION_GZIPV1 */ + + + + // Flush Write data... if any was held in the compression block area. + + // In this case, though... nothing's held there. + + + + if(isofile->tablehandle != ACTUALHANDLENULL) { + + ActualFileClose(isofile->tablehandle); + + isofile->tablehandle = ACTUALHANDLENULL; + + } // ENDIF- Is there a table file open? Close it. + + + + if(isofile->handle != ACTUALHANDLENULL) { + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + } // ENDIF- Is there a data file open? Close it. + + + + return; + +} // END GZipV1Close() + diff --git a/plugins/CDVDisoEFP/src/gzipv1.h b/plugins/CDVDisoEFP/src/gzipv1.h index c47981fc07..7127cc2e91 100644 --- a/plugins/CDVDisoEFP/src/gzipv1.h +++ b/plugins/CDVDisoEFP/src/gzipv1.h @@ -1,104 +1,104 @@ -/* gzipv1.h - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#ifndef GZIPV1_H - -#define GZIPV1_H - - - - - -#include - - - -#include "isofile.h" - -#include "isocompress.h" - - - - - -// #define VERBOSE_FUNCTION_GZIPV1 - -// #define VERBOSE_WARNING_GZIPV1 - - - - - -extern int GZipV1OpenTableForRead(struct IsoFile *isofile); - -extern int GZipV1SeekTable(struct IsoFile *isofile, off64_t sector); - -extern int GZipV1ReadTable(struct IsoFile *isofile, struct TableData *table); - - - -extern int GZipV1OpenTableForWrite(struct IsoFile *isofile); - -extern int GZipV1WriteTable(struct IsoFile *isofile, struct TableData table); - - - -extern int GZipV1OpenForRead(struct IsoFile *isofile); - -extern int GZipV1Seek(struct IsoFile *isofile, off64_t sector); - -extern int GZipV1Read(struct IsoFile *isofile, int bytes, char *buffer); - -extern void GZipV1Close(struct IsoFile *isofile); - - - -extern int GZipV1OpenForWrite(struct IsoFile *isofile); - -extern int GZipV1Write(struct IsoFile *isofile, char *buffer); - - - - - -#endif /* GZIPV1_H */ - +/* gzipv1.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef GZIPV1_H + +#define GZIPV1_H + + + + + +#include + + + +#include "isofile.h" + +#include "isocompress.h" + + + + + +// #define VERBOSE_FUNCTION_GZIPV1 + +// #define VERBOSE_WARNING_GZIPV1 + + + + + +extern int GZipV1OpenTableForRead(struct IsoFile *isofile); + +extern int GZipV1SeekTable(struct IsoFile *isofile, off64_t sector); + +extern int GZipV1ReadTable(struct IsoFile *isofile, struct TableData *table); + + + +extern int GZipV1OpenTableForWrite(struct IsoFile *isofile); + +extern int GZipV1WriteTable(struct IsoFile *isofile, struct TableData table); + + + +extern int GZipV1OpenForRead(struct IsoFile *isofile); + +extern int GZipV1Seek(struct IsoFile *isofile, off64_t sector); + +extern int GZipV1Read(struct IsoFile *isofile, int bytes, char *buffer); + +extern void GZipV1Close(struct IsoFile *isofile); + + + +extern int GZipV1OpenForWrite(struct IsoFile *isofile); + +extern int GZipV1Write(struct IsoFile *isofile, char *buffer); + + + + + +#endif /* GZIPV1_H */ + diff --git a/plugins/CDVDisoEFP/src/gzipv2.c b/plugins/CDVDisoEFP/src/gzipv2.c index 3a82174ba4..548050c5f6 100644 --- a/plugins/CDVDisoEFP/src/gzipv2.c +++ b/plugins/CDVDisoEFP/src/gzipv2.c @@ -1,980 +1,980 @@ -/* gzipv2.c - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#include // NULL - -#include // malloc() - -#include // off64_t - - - -#include "zlib/zlib.h" - - - -#include "convert.h" - -#include "logfile.h" - -#include "isofile.h" // IsoFile - -#include "isocompress.h" // TableData, TableMap - -#include "actualfile.h" - -#include "gzipv2.h" - - - - - -#ifdef _WIN32 - -#pragma pack(1) - -#endif /* _WIN32 */ - - - -struct GZipV2Header { - - char id[4]; - - unsigned int blocksize; - - unsigned int numblocks; - - unsigned int blockoffset; - -#ifdef _WIN32 - -}; - -#else - -} __attribute__ ((packed)); - -#endif /* _WIN32 */ - - - -struct GZipV2Table { - - unsigned int size; - -#ifdef _WIN32 - -}; - -#else - -} __attribute__ ((packed)); - -#endif /* _WIN32 */ - - - -#ifdef _WIN32 - -#pragma pack() - -#endif /* _WIN32 */ - - - - - -int GZipV2OpenTableForRead(struct IsoFile *isofile) { - - int i; - - int j; - - char tableext[] = ".table\0"; - - off64_t offset; - - off64_t actual; - - int tableoffset; - - struct GZipV2Table table; - - int retval; - - union TableMap tablemap; - - - -#ifdef VERBOSE_FUNCTION_GZIPV2 - - PrintLog("CDVDiso GZipV2: OpenTableForRead()"); - -#endif /* VERBOSE_FUNCTION_GZIPV2 */ - - - - i = 0; - - while((i < 256) && (isofile->name[i] != 0)) { - - isofile->tablename[i] = isofile->name[i]; - - i++; - - } // ENDWHILE- Copying the data name to the table name - - j = 0; - - while((i < 256) && (tableext[j] != 0)) { - - isofile->tablename[i] = tableext[j]; - - i++; - - j++; - - } // ENDWHILE- Adding the ".table" extension. - - isofile->tablename[i] = 0; // And 0-terminate. - - - - isofile->tablehandle = ActualFileOpenForRead(isofile->tablename); - - if(isofile->tablehandle == ACTUALHANDLENULL) { - -#ifdef VERBOSE_WARNING_GZIPV2 - - PrintLog("CDVDiso GZipV2: Couldn't open table!"); - -#endif /* VERBOSE_WARNING_GZIPV2 */ - - return(-2); - - } // ENDIF- Couldn't open table file? Fail. - - - - offset = isofile->filesectorsize * sizeof(struct GZipV2Table); - - actual = ActualFileSize(isofile->tablehandle); - - if(offset != actual) { - -#ifdef VERBOSE_WARNING_GZIPV2 - - PrintLog("CDVDiso GZipV2: Table not the correct size! (Should be %lli, is %lli)", - - offset, actual); - -#endif /* VERBOSE_WARNING_GZIPV2 */ - - return(-2); - - } // ENDIF- Not the correct-sized table for the data file? Fail. - - - - // We pre-read the WHOLE offset table. - - isofile->tabledata = (char *) malloc(isofile->filesectorsize * sizeof(struct TableData)); - - if(isofile->tabledata == NULL) { - -#ifdef VERBOSE_WARNING_GZIPV2 - - PrintLog("CDVDiso GZipV2: Couldn't allocate internal table!"); - -#endif /* VERBOSE_WARNING_GZIPV2 */ - - return(-2); - - } // ENDIF- Could not get enough memory to hold table data - - - - offset = sizeof(struct GZipV2Header); - - tableoffset = 0; - - for(i = 0; i < isofile->filesectorsize; i++) { - - retval = ActualFileRead(isofile->tablehandle, - - sizeof(struct GZipV2Table), - - (char *) &table); - - if(retval != sizeof(struct GZipV2Table)) { - -#ifdef VERBOSE_WARNING_GZIPV2 - - PrintLog("CDVDiso GZipV2: Failed to read in sector %i!", i); - -#endif /* VERBOSE_WARNING_GZIPV2 */ - - return(-2); - - } // ENDIF- Trouble reading in a size? Table damaged... fail. - - - - tablemap.table.offset = offset; - - tablemap.table.size = ConvertEndianUInt(table.size); - - for(j = 0; j < sizeof(struct TableData); j++) - - *(isofile->tabledata + tableoffset + j) = tablemap.ch[j]; - - offset += table.size; - - tableoffset += sizeof(struct TableData); - - } // NEXT i- reading in the sizes, and making offset as I go. - - - - ActualFileClose(isofile->tablehandle); - - isofile->tablehandle = ACTUALHANDLENULL; - - return(0); - -} // END GZipV2OpenTableForRead() - - - - - -int GZipV2SeekTable(struct IsoFile *isofile, off64_t sector) { - -#ifdef VERBOSE_FUNCTION_GZIPV2 - - PrintLog("CDVDiso GZipV2: SeekTable(%lli)", sector); - -#endif /* VERBOSE_FUNCTION_GZIPV2 */ - - - - isofile->filesectorpos = sector; - - return(0); - -} // END GZipV2SeekTable() - - - - - -int GZipV2ReadTable(struct IsoFile *isofile, struct TableData *table) { - - off64_t target; - - union TableMap tablemap; - - off64_t i; - - - -#ifdef VERBOSE_FUNCTION_GZIPV2 - - PrintLog("CDVDiso GZipV2: ReadTable()"); - -#endif /* VERBOSE_FUNCTION_GZIPV2 */ - - - - target = isofile->filesectorpos * sizeof(struct TableData); - - for(i = 0; i < sizeof(struct TableData); i++) - - tablemap.ch[i] = *(isofile->tabledata + target + i); - - - - table->offset = tablemap.table.offset; - - table->size = tablemap.table.size; - - isofile->filesectorpos++; - - return(0); - -} // END GZipV2ReadTable() - - - - - -int GZipV2OpenTableForWrite(struct IsoFile *isofile) { - - int i; - - int j; - - char tableext[] = ".table\0"; - - - -#ifdef VERBOSE_FUNCTION_GZIPV2 - - PrintLog("CDVDiso GZipV2: OpenTableForWrite()"); - -#endif /* VERBOSE_FUNCTION_GZIPV2 */ - - - - i = 0; - - while((i < 256) && (isofile->name[i] != 0)) { - - isofile->tablename[i] = isofile->name[i]; - - i++; - - } // ENDWHILE- Copying the data name to the table name - - j = 0; - - while((i < 256) && (tableext[j] != 0)) { - - isofile->tablename[i] = tableext[j]; - - i++; - - j++; - - } // ENDWHILE- Adding the ".table" extension. - - isofile->tablename[i] = 0; // And 0-terminate. - - - - isofile->tablehandle = ActualFileOpenForWrite(isofile->tablename); - - if(isofile->tablehandle == ACTUALHANDLENULL) { - -#ifdef VERBOSE_WARNING_GZIPV2 - - PrintLog("CDVDiso GZipV2: Couldn't open table!"); - -#endif /* VERBOSE_WARNING_GZIPV2 */ - - return(-2); - - } // ENDIF- Couldn't open table file? Fail. - - - - isofile->filesectorsize = 0; - - return(0); - -} // END GZipV2OpenTableForWrite() - - - - - -int GZipV2WriteTable(struct IsoFile *isofile, struct TableData table) { - - int retval; - - struct GZipV2Table gv2table; - - unsigned int tempint; - - - -#ifdef VERBOSE_FUNCTION_GZIPV2 - - PrintLog("CDVDiso GZipV2: WriteTable(%lli, %i)", table.offset, table.size); - -#endif /* VERBOSE_FUNCTION_GZIPV2 */ - - - - tempint = table.size; - - gv2table.size = ConvertEndianUInt(tempint); - - retval = ActualFileWrite(isofile->tablehandle, - - sizeof(struct GZipV2Table), - - (char *) &gv2table); - - if(retval != sizeof(unsigned int)) { - -#ifdef VERBOSE_WARNING_GZIPV2 - - PrintLog("CDVDiso GZipV2: Couldn't write table entry!"); - -#endif /* VERBOSE_WARNING_GZIPV2 */ - - return(-2); - - } // ENDIF- Trouble reading table entry? Fail. - - - - return(0); - -} // END GZipV2WriteTable() - - - - - -int GZipV2OpenForRead(struct IsoFile *isofile) { - - int retval; - - struct GZipV2Header header; - - - -#ifdef VERBOSE_FUNCTION_GZIPV2 - - PrintLog("CDVDiso GZipV2: OpenForRead()"); - -#endif /* VERBOSE_FUNCTION_GZIPV2 */ - - - - isofile->handle = ActualFileOpenForRead(isofile->name); - - if(isofile->handle == ACTUALHANDLENULL) { - - return(-1); - - } // ENDIF- Couldn't open data file? Fail. - - - - isofile->filebytesize = ActualFileSize(isofile->handle); - - isofile->filebytepos = 0; - - isofile->filesectorpos = 0; - - - - isofile->imageheader = 0; - - isofile->numsectors = 1; // Sectors per block - - - - retval = ActualFileRead(isofile->handle, - - sizeof(struct GZipV2Header), - - (char *) &header); - - if(retval != sizeof(struct GZipV2Header)) { - -#ifdef VERBOSE_WARNING_GZIPV2 - - PrintLog("CDVDiso GZipV2: Couldn't read header!"); - -#endif /* VERBOSE_WARNING_GZIPV2 */ - - ActualFileClose(isofile->handle); - - isofile->handle = ACTUALHANDLENULL; - - return(-1); - - } // ENDIF Could not read the first sector? Fail. - - isofile->filebytepos += retval; - - - - if((header.id[0] != 'Z') || - - (header.id[1] != ' ') || - - (header.id[2] != 'V') || - - (header.id[3] != '2')) { - -#ifdef VERBOSE_WARNING_GZIPV2 - - PrintLog("CDVDiso GZipV2: Not a gzip v2 compression header!"); - -#endif /* VERBOSE_WARNING_GZIPV2 */ - - ActualFileClose(isofile->handle); - - isofile->handle = ACTUALHANDLENULL; - - return(-1); - - } // ENDIF- ID for this compression type doesn't match? - - - - isofile->blocksize = ConvertEndianUInt(header.blocksize); - - isofile->filesectorsize = ConvertEndianUInt(header.numblocks); - - isofile->blockoffset = ConvertEndianUInt(header.blockoffset); - - isofile->filesectorpos = 0; - - return(0); - -} // END GZipV2OpenForRead() - - - - - -int GZipV2Seek(struct IsoFile *isofile, off64_t position) { - - int retval; - - - -#ifdef VERBOSE_FUNCTION_GZIPV2 - - PrintLog("CDVDiso GZipV2: Seek(%lli)", position); - -#endif /* VERBOSE_FUNCTION_GZIPV2 */ - - - - retval = ActualFileSeek(isofile->handle, position); - - if(retval < 0) { - -#ifdef VERBOSE_WARNING_GZIPV2 - - PrintLog("CDVDiso GZipV2: Couldn't find the start of the compressed block!"); - -#endif /* VERBOSE_WARNING_GZIPV2 */ - - return(-1); - - } // ENDIF- Couldn't find the data entry? Fail. - - isofile->filebytepos = position; - - return(0); - - - - return(-1); // Fail. (Due to lack of ambition?) - -} // END GZipV2Seek() - - - - - -int GZipV2Read(struct IsoFile *isofile, int bytes, char *buffer) { - - int retval; - - unsigned long blocklen; - - z_stream strm; - - unsigned long tempin; - - char tempblock[2800]; - - unsigned long tempout; - - - -#ifdef VERBOSE_FUNCTION_GZIPV2 - - PrintLog("CDVDiso GZipV2: Read(%i)", bytes); - -#endif /* VERBOSE_FUNCTION_GZIPV2 */ - - - - if(bytes > 0) { - - retval = ActualFileRead(isofile->handle, bytes, tempblock); - - if(retval > 0) isofile->filebytepos += retval; - - if(retval != bytes) { - -#ifdef VERBOSE_WARNING_GZIPV2 - - PrintLog("CDVDiso GZipV2: Cannot read bytes! Returned: (%i)", retval); - -#endif /* VERBOSE_WARNING_GZIPV2 */ - - return(-1); - - } // ENDIF- Trouble reading compressed sector? Abort. - - - - blocklen = isofile->blocksize; - - retval = uncompress(buffer, &blocklen, tempblock, bytes); - - if(retval != Z_OK) { - -#ifdef VERBOSE_WARNING_GZIPV2 - - PrintLog("CDVDiso GZipV2: Cannot decode block! Returned: (%i)", retval); - -#endif /* VERBOSE_WARNING_GZIPV2 */ - - return(-1); - - } // ENDIF- Trouble decoding the sector? Abort. - - - - return(0); - - } // ENDIF- Do we know how many compressed bytes to get for this record? - - - - // Hmm. Don't know the compressed size? Well, we'll just have to find it. - - - - tempin = 0; - - tempout = 0; - - retval = Z_OK; - - while((tempin < 2800) && (tempout < isofile->blocksize * isofile->numsectors)) { - - - - strm.zalloc = (alloc_func)0; - - strm.zfree = (free_func)0; - - - - strm.next_in = tempblock; - - strm.next_out = buffer; - - - - strm.avail_in = tempin; - - strm.avail_out = 2800; - - - - retval = inflateInit(&strm); - - if (retval != Z_OK) return(-1); - - - - while((tempin < 2800) && (retval == Z_OK)) { - - retval = ActualFileRead(isofile->handle, 1, &tempblock[tempin]); - - if(retval != 1) { - -#ifdef VERBOSE_FUNCTION_GZIPV2 - - PrintLog("CDVDiso GZipV2: Cannot read a byte! Returned: (%i)", retval); - -#endif /* VERBOSE_FUNCTION_GZIPV2 */ - - return(-1); - - } // ENDIF- Trouble reading compressed sector? Abort. - - tempin++; - - strm.avail_in++; - - - - strm.next_in = &tempblock[tempin - strm.avail_in]; - - retval = inflate(&strm, Z_NO_FLUSH); - - } // ENDWHILE- trying to uncompress an increasingly filled buffer - - tempout = 2800 - strm.avail_out; - - inflateEnd(&strm); - - - - } // ENDWHILE- trying to uncompress a whole buffer - - if(retval != Z_STREAM_END) return(-1); - - - - if(tempin == 2800) return(-1); - - isofile->filebytepos += tempin; - - return(tempin); // Send out # of compressed bytes (to record in table) - -} // END GZipV2Read() - - - - - -int GZipV2OpenForWrite(struct IsoFile *isofile) { - - char garbage[sizeof(struct GZipV2Header)]; - - int i; - - - - if(isofile == NULL) return(-1); - - - -#ifdef VERBOSE_FUNCTION_GZIPV2 - - PrintLog("CDVDiso GZipV2: OpenForWrite()"); - -#endif /* VERBOSE_FUNCTION_GZIPV2 */ - - - - isofile->handle = ActualFileOpenForWrite(isofile->name); - - if(isofile->handle == ACTUALHANDLENULL) { - - return(-1); - - } // ENDIF- Couldn't open data file? Fail. - - for(i = 0; i < sizeof(struct GZipV2Header); i++) garbage[i] = 0; - - ActualFileWrite(isofile->handle, sizeof(struct GZipV2Header), garbage); - - - - isofile->filebytesize = 0; - - isofile->filebytepos = sizeof(struct GZipV2Header); - - isofile->filesectorpos = 0; - - isofile->filesectorsize = 0; - - return(0); - -} // END GZipV2OpenForWrite() - - - - - -int GZipV2Write(struct IsoFile *isofile, char *buffer) { - - int retval; - - unsigned long blocklen; - - char tempblock[2800]; - - - -#ifdef VERBOSE_FUNCTION_GZIPV2 - - PrintLog("CDVDiso GZipV2: Write()"); - -#endif /* VERBOSE_FUNCTION_GZIPV2 */ - - - - blocklen = 2800; - - retval = compress2(tempblock, &blocklen, - - buffer, isofile->blocksize, - - Z_BEST_COMPRESSION); - - if(retval != Z_OK) { - -#ifdef VERBOSE_FUNCTION_GZIPV2 - - PrintLog("CDVDiso GZipV2: Cannot encode block! Returned: (%i)", retval); - -#endif /* VERBOSE_FUNCTION_GZIPV2 */ - - return(-1); - - } // ENDIF- Trouble compressing a block? Abort. - - - - retval = ActualFileWrite(isofile->handle, blocklen, tempblock); - - if(retval > 0) isofile->filebytepos += retval; - - if(retval < blocklen) { - -#ifdef VERBOSE_FUNCTION_GZIPV2 - - PrintLog("CDVDiso GZipV2: Cannot write bytes! Returned: (%i out of %llu)", - - retval, blocklen); - -#endif /* VERBOSE_FUNCTION_GZIPV2 */ - - return(-1); - - } // ENDIF- Trouble writing out the compressed block? Abort. - - isofile->filesectorpos++; - - - - return(blocklen); // Not in list? Fail. - -} // END GZipV2Write() - - - - - -void GZipV2Close(struct IsoFile *isofile) { - - struct GZipV2Header header; - - unsigned int tempint; - - - -#ifdef VERBOSE_FUNCTION_GZIPV2 - - PrintLog("CDVDiso GZipV2: Close()"); - -#endif /* VERBOSE_FUNCTION_GZIPV2 */ - - - - if(isofile->tablehandle != ACTUALHANDLENULL) { - - ActualFileClose(isofile->tablehandle); - - isofile->tablehandle = ACTUALHANDLENULL; - - } // ENDIF- Is there a table file open? Close it. - - - - if(isofile->handle != ACTUALHANDLENULL) { - - if(isofile->openforread == 0) { - - header.id[0] = 'Z'; - - header.id[1] = ' '; - - header.id[2] = 'V'; - - header.id[3] = '2'; - - tempint = isofile->blocksize; - - header.blocksize = ConvertEndianUInt(tempint); - - tempint = isofile->filesectorsize; - - header.numblocks = ConvertEndianUInt(tempint); - - tempint = isofile->blockoffset; - - header.blockoffset = ConvertEndianUInt(tempint); - - ActualFileSeek(isofile->handle, 0); - - ActualFileWrite(isofile->handle, - - sizeof(struct GZipV2Header), - - (char *) &header); - - } // ENDIF- Opened for write? Don't forget to update the header block! - - - - ActualFileClose(isofile->handle); - - isofile->handle = ACTUALHANDLENULL; - - } // ENDIF- Is there a data file open? Close it. - - - - if(isofile->tabledata != NULL) { - - free(isofile->tabledata); - - isofile->tabledata = NULL; - - } // ENDIF- Do we have a read-in table to clear out? - - - - return; - -} // END GZipV2Close() - +/* gzipv2.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // malloc() + +#include // off64_t + + + +#include "zlib/zlib.h" + + + +#include "convert.h" + +#include "logfile.h" + +#include "isofile.h" // IsoFile + +#include "isocompress.h" // TableData, TableMap + +#include "actualfile.h" + +#include "gzipv2.h" + + + + + +#ifdef _WIN32 + +#pragma pack(1) + +#endif /* _WIN32 */ + + + +struct GZipV2Header { + + char id[4]; + + unsigned int blocksize; + + unsigned int numblocks; + + unsigned int blockoffset; + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +struct GZipV2Table { + + unsigned int size; + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +#ifdef _WIN32 + +#pragma pack() + +#endif /* _WIN32 */ + + + + + +int GZipV2OpenTableForRead(struct IsoFile *isofile) { + + int i; + + int j; + + char tableext[] = ".table\0"; + + off64_t offset; + + off64_t actual; + + int tableoffset; + + struct GZipV2Table table; + + int retval; + + union TableMap tablemap; + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: OpenTableForRead()"); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + i = 0; + + while((i < 256) && (isofile->name[i] != 0)) { + + isofile->tablename[i] = isofile->name[i]; + + i++; + + } // ENDWHILE- Copying the data name to the table name + + j = 0; + + while((i < 256) && (tableext[j] != 0)) { + + isofile->tablename[i] = tableext[j]; + + i++; + + j++; + + } // ENDWHILE- Adding the ".table" extension. + + isofile->tablename[i] = 0; // And 0-terminate. + + + + isofile->tablehandle = ActualFileOpenForRead(isofile->tablename); + + if(isofile->tablehandle == ACTUALHANDLENULL) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Couldn't open table!"); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + return(-2); + + } // ENDIF- Couldn't open table file? Fail. + + + + offset = isofile->filesectorsize * sizeof(struct GZipV2Table); + + actual = ActualFileSize(isofile->tablehandle); + + if(offset != actual) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Table not the correct size! (Should be %lli, is %lli)", + + offset, actual); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + return(-2); + + } // ENDIF- Not the correct-sized table for the data file? Fail. + + + + // We pre-read the WHOLE offset table. + + isofile->tabledata = (char *) malloc(isofile->filesectorsize * sizeof(struct TableData)); + + if(isofile->tabledata == NULL) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Couldn't allocate internal table!"); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + return(-2); + + } // ENDIF- Could not get enough memory to hold table data + + + + offset = sizeof(struct GZipV2Header); + + tableoffset = 0; + + for(i = 0; i < isofile->filesectorsize; i++) { + + retval = ActualFileRead(isofile->tablehandle, + + sizeof(struct GZipV2Table), + + (char *) &table); + + if(retval != sizeof(struct GZipV2Table)) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Failed to read in sector %i!", i); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + return(-2); + + } // ENDIF- Trouble reading in a size? Table damaged... fail. + + + + tablemap.table.offset = offset; + + tablemap.table.size = ConvertEndianUInt(table.size); + + for(j = 0; j < sizeof(struct TableData); j++) + + *(isofile->tabledata + tableoffset + j) = tablemap.ch[j]; + + offset += table.size; + + tableoffset += sizeof(struct TableData); + + } // NEXT i- reading in the sizes, and making offset as I go. + + + + ActualFileClose(isofile->tablehandle); + + isofile->tablehandle = ACTUALHANDLENULL; + + return(0); + +} // END GZipV2OpenTableForRead() + + + + + +int GZipV2SeekTable(struct IsoFile *isofile, off64_t sector) { + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: SeekTable(%lli)", sector); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + isofile->filesectorpos = sector; + + return(0); + +} // END GZipV2SeekTable() + + + + + +int GZipV2ReadTable(struct IsoFile *isofile, struct TableData *table) { + + off64_t target; + + union TableMap tablemap; + + off64_t i; + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: ReadTable()"); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + target = isofile->filesectorpos * sizeof(struct TableData); + + for(i = 0; i < sizeof(struct TableData); i++) + + tablemap.ch[i] = *(isofile->tabledata + target + i); + + + + table->offset = tablemap.table.offset; + + table->size = tablemap.table.size; + + isofile->filesectorpos++; + + return(0); + +} // END GZipV2ReadTable() + + + + + +int GZipV2OpenTableForWrite(struct IsoFile *isofile) { + + int i; + + int j; + + char tableext[] = ".table\0"; + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: OpenTableForWrite()"); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + i = 0; + + while((i < 256) && (isofile->name[i] != 0)) { + + isofile->tablename[i] = isofile->name[i]; + + i++; + + } // ENDWHILE- Copying the data name to the table name + + j = 0; + + while((i < 256) && (tableext[j] != 0)) { + + isofile->tablename[i] = tableext[j]; + + i++; + + j++; + + } // ENDWHILE- Adding the ".table" extension. + + isofile->tablename[i] = 0; // And 0-terminate. + + + + isofile->tablehandle = ActualFileOpenForWrite(isofile->tablename); + + if(isofile->tablehandle == ACTUALHANDLENULL) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Couldn't open table!"); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + return(-2); + + } // ENDIF- Couldn't open table file? Fail. + + + + isofile->filesectorsize = 0; + + return(0); + +} // END GZipV2OpenTableForWrite() + + + + + +int GZipV2WriteTable(struct IsoFile *isofile, struct TableData table) { + + int retval; + + struct GZipV2Table gv2table; + + unsigned int tempint; + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: WriteTable(%lli, %i)", table.offset, table.size); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + tempint = table.size; + + gv2table.size = ConvertEndianUInt(tempint); + + retval = ActualFileWrite(isofile->tablehandle, + + sizeof(struct GZipV2Table), + + (char *) &gv2table); + + if(retval != sizeof(unsigned int)) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Couldn't write table entry!"); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + return(-2); + + } // ENDIF- Trouble reading table entry? Fail. + + + + return(0); + +} // END GZipV2WriteTable() + + + + + +int GZipV2OpenForRead(struct IsoFile *isofile) { + + int retval; + + struct GZipV2Header header; + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: OpenForRead()"); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + isofile->handle = ActualFileOpenForRead(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + return(-1); + + } // ENDIF- Couldn't open data file? Fail. + + + + isofile->filebytesize = ActualFileSize(isofile->handle); + + isofile->filebytepos = 0; + + isofile->filesectorpos = 0; + + + + isofile->imageheader = 0; + + isofile->numsectors = 1; // Sectors per block + + + + retval = ActualFileRead(isofile->handle, + + sizeof(struct GZipV2Header), + + (char *) &header); + + if(retval != sizeof(struct GZipV2Header)) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Couldn't read header!"); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF Could not read the first sector? Fail. + + isofile->filebytepos += retval; + + + + if((header.id[0] != 'Z') || + + (header.id[1] != ' ') || + + (header.id[2] != 'V') || + + (header.id[3] != '2')) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Not a gzip v2 compression header!"); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- ID for this compression type doesn't match? + + + + isofile->blocksize = ConvertEndianUInt(header.blocksize); + + isofile->filesectorsize = ConvertEndianUInt(header.numblocks); + + isofile->blockoffset = ConvertEndianUInt(header.blockoffset); + + isofile->filesectorpos = 0; + + return(0); + +} // END GZipV2OpenForRead() + + + + + +int GZipV2Seek(struct IsoFile *isofile, off64_t position) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: Seek(%lli)", position); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + retval = ActualFileSeek(isofile->handle, position); + + if(retval < 0) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Couldn't find the start of the compressed block!"); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + return(-1); + + } // ENDIF- Couldn't find the data entry? Fail. + + isofile->filebytepos = position; + + return(0); + + + + return(-1); // Fail. (Due to lack of ambition?) + +} // END GZipV2Seek() + + + + + +int GZipV2Read(struct IsoFile *isofile, int bytes, char *buffer) { + + int retval; + + unsigned long blocklen; + + z_stream strm; + + unsigned long tempin; + + char tempblock[2800]; + + unsigned long tempout; + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: Read(%i)", bytes); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + if(bytes > 0) { + + retval = ActualFileRead(isofile->handle, bytes, tempblock); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval != bytes) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Cannot read bytes! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + + + blocklen = isofile->blocksize; + + retval = uncompress(buffer, &blocklen, tempblock, bytes); + + if(retval != Z_OK) { + +#ifdef VERBOSE_WARNING_GZIPV2 + + PrintLog("CDVDiso GZipV2: Cannot decode block! Returned: (%i)", retval); + +#endif /* VERBOSE_WARNING_GZIPV2 */ + + return(-1); + + } // ENDIF- Trouble decoding the sector? Abort. + + + + return(0); + + } // ENDIF- Do we know how many compressed bytes to get for this record? + + + + // Hmm. Don't know the compressed size? Well, we'll just have to find it. + + + + tempin = 0; + + tempout = 0; + + retval = Z_OK; + + while((tempin < 2800) && (tempout < isofile->blocksize * isofile->numsectors)) { + + + + strm.zalloc = (alloc_func)0; + + strm.zfree = (free_func)0; + + + + strm.next_in = tempblock; + + strm.next_out = buffer; + + + + strm.avail_in = tempin; + + strm.avail_out = 2800; + + + + retval = inflateInit(&strm); + + if (retval != Z_OK) return(-1); + + + + while((tempin < 2800) && (retval == Z_OK)) { + + retval = ActualFileRead(isofile->handle, 1, &tempblock[tempin]); + + if(retval != 1) { + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: Cannot read a byte! Returned: (%i)", retval); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + return(-1); + + } // ENDIF- Trouble reading compressed sector? Abort. + + tempin++; + + strm.avail_in++; + + + + strm.next_in = &tempblock[tempin - strm.avail_in]; + + retval = inflate(&strm, Z_NO_FLUSH); + + } // ENDWHILE- trying to uncompress an increasingly filled buffer + + tempout = 2800 - strm.avail_out; + + inflateEnd(&strm); + + + + } // ENDWHILE- trying to uncompress a whole buffer + + if(retval != Z_STREAM_END) return(-1); + + + + if(tempin == 2800) return(-1); + + isofile->filebytepos += tempin; + + return(tempin); // Send out # of compressed bytes (to record in table) + +} // END GZipV2Read() + + + + + +int GZipV2OpenForWrite(struct IsoFile *isofile) { + + char garbage[sizeof(struct GZipV2Header)]; + + int i; + + + + if(isofile == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: OpenForWrite()"); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + isofile->handle = ActualFileOpenForWrite(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + return(-1); + + } // ENDIF- Couldn't open data file? Fail. + + for(i = 0; i < sizeof(struct GZipV2Header); i++) garbage[i] = 0; + + ActualFileWrite(isofile->handle, sizeof(struct GZipV2Header), garbage); + + + + isofile->filebytesize = 0; + + isofile->filebytepos = sizeof(struct GZipV2Header); + + isofile->filesectorpos = 0; + + isofile->filesectorsize = 0; + + return(0); + +} // END GZipV2OpenForWrite() + + + + + +int GZipV2Write(struct IsoFile *isofile, char *buffer) { + + int retval; + + unsigned long blocklen; + + char tempblock[2800]; + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: Write()"); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + blocklen = 2800; + + retval = compress2(tempblock, &blocklen, + + buffer, isofile->blocksize, + + Z_BEST_COMPRESSION); + + if(retval != Z_OK) { + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: Cannot encode block! Returned: (%i)", retval); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + return(-1); + + } // ENDIF- Trouble compressing a block? Abort. + + + + retval = ActualFileWrite(isofile->handle, blocklen, tempblock); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval < blocklen) { + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: Cannot write bytes! Returned: (%i out of %llu)", + + retval, blocklen); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + return(-1); + + } // ENDIF- Trouble writing out the compressed block? Abort. + + isofile->filesectorpos++; + + + + return(blocklen); // Not in list? Fail. + +} // END GZipV2Write() + + + + + +void GZipV2Close(struct IsoFile *isofile) { + + struct GZipV2Header header; + + unsigned int tempint; + + + +#ifdef VERBOSE_FUNCTION_GZIPV2 + + PrintLog("CDVDiso GZipV2: Close()"); + +#endif /* VERBOSE_FUNCTION_GZIPV2 */ + + + + if(isofile->tablehandle != ACTUALHANDLENULL) { + + ActualFileClose(isofile->tablehandle); + + isofile->tablehandle = ACTUALHANDLENULL; + + } // ENDIF- Is there a table file open? Close it. + + + + if(isofile->handle != ACTUALHANDLENULL) { + + if(isofile->openforread == 0) { + + header.id[0] = 'Z'; + + header.id[1] = ' '; + + header.id[2] = 'V'; + + header.id[3] = '2'; + + tempint = isofile->blocksize; + + header.blocksize = ConvertEndianUInt(tempint); + + tempint = isofile->filesectorsize; + + header.numblocks = ConvertEndianUInt(tempint); + + tempint = isofile->blockoffset; + + header.blockoffset = ConvertEndianUInt(tempint); + + ActualFileSeek(isofile->handle, 0); + + ActualFileWrite(isofile->handle, + + sizeof(struct GZipV2Header), + + (char *) &header); + + } // ENDIF- Opened for write? Don't forget to update the header block! + + + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + } // ENDIF- Is there a data file open? Close it. + + + + if(isofile->tabledata != NULL) { + + free(isofile->tabledata); + + isofile->tabledata = NULL; + + } // ENDIF- Do we have a read-in table to clear out? + + + + return; + +} // END GZipV2Close() + diff --git a/plugins/CDVDisoEFP/src/gzipv2.h b/plugins/CDVDisoEFP/src/gzipv2.h index b91219c737..c6d1d5d330 100644 --- a/plugins/CDVDisoEFP/src/gzipv2.h +++ b/plugins/CDVDisoEFP/src/gzipv2.h @@ -1,104 +1,104 @@ -/* gzipv2.h - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#ifndef GZIPV2_H - -#define GZIPV2_H - - - - - -#include - - - -#include "isofile.h" - -#include "isocompress.h" - - - - - -// #define VERBOSE_FUNCTION_GZIPV2 - -// #define VERBOSE_WARNING_GZIPV2 - - - - - -extern int GZipV2OpenTableForRead(struct IsoFile *isofile); - -extern int GZipV2SeekTable(struct IsoFile *isofile, off64_t sector); - -extern int GZipV2ReadTable(struct IsoFile *isofile, struct TableData *table); - - - -extern int GZipV2OpenTableForWrite(struct IsoFile *isofile); - -extern int GZipV2WriteTable(struct IsoFile *isofile, struct TableData table); - - - -extern int GZipV2OpenForRead(struct IsoFile *isofile); - -extern int GZipV2Seek(struct IsoFile *isofile, off64_t sector); - -extern int GZipV2Read(struct IsoFile *isofile, int bytes, char *buffer); - -extern void GZipV2Close(struct IsoFile *isofile); - - - -extern int GZipV2OpenForWrite(struct IsoFile *isofile); - -extern int GZipV2Write(struct IsoFile *isofile, char *buffer); - - - - - -#endif /* GZIPV2_H */ - +/* gzipv2.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef GZIPV2_H + +#define GZIPV2_H + + + + + +#include + + + +#include "isofile.h" + +#include "isocompress.h" + + + + + +// #define VERBOSE_FUNCTION_GZIPV2 + +// #define VERBOSE_WARNING_GZIPV2 + + + + + +extern int GZipV2OpenTableForRead(struct IsoFile *isofile); + +extern int GZipV2SeekTable(struct IsoFile *isofile, off64_t sector); + +extern int GZipV2ReadTable(struct IsoFile *isofile, struct TableData *table); + + + +extern int GZipV2OpenTableForWrite(struct IsoFile *isofile); + +extern int GZipV2WriteTable(struct IsoFile *isofile, struct TableData table); + + + +extern int GZipV2OpenForRead(struct IsoFile *isofile); + +extern int GZipV2Seek(struct IsoFile *isofile, off64_t sector); + +extern int GZipV2Read(struct IsoFile *isofile, int bytes, char *buffer); + +extern void GZipV2Close(struct IsoFile *isofile); + + + +extern int GZipV2OpenForWrite(struct IsoFile *isofile); + +extern int GZipV2Write(struct IsoFile *isofile, char *buffer); + + + + + +#endif /* GZIPV2_H */ + diff --git a/plugins/CDVDisoEFP/src/imagetype.c b/plugins/CDVDisoEFP/src/imagetype.c index 8b6785f6a0..4c7924f58a 100644 --- a/plugins/CDVDisoEFP/src/imagetype.c +++ b/plugins/CDVDisoEFP/src/imagetype.c @@ -1,306 +1,306 @@ -/* imagetype.c - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#include // NULL - -#include // off64_t - - - -// #ifndef __LINUX__ - -// #ifdef __linux__ - -// #define __LINUX__ - -// #endif /* __linux__ */ - -// #endif /* No __LINUX__ */ - - - -// #define CDVDdefs - -// #include "PS2Edefs.h" - - - -#include "isofile.h" - -#include "actualfile.h" - -#include "imagetype.h" - - - - - -// Based (mostly) off of florin's CDVDbin detection code, twice removed - -// with some additions from the header. - -struct ImageTypes imagedata[] = { - - { "ISO 2048", 2048, 0, 0, 0 }, - - { "YellowBook 2064", 2064, 0, 16, 1 }, - - { "RAW 2064", 2064, 0, 0, 2 }, - - { "GreenBook 2072", 2072, 0, 24, 3 }, - - { "RAW 2072", 2072, 0, 0, 4 }, - - { "RAW 2324", 2324, 0, 0, 5 }, - - { "RAW 2328", 2328, 0, 0, 6 }, - - { "RAW 2336", 2336, 0, 0, 7 }, - - { "GreenBook 2352", 2352, 0, 24, 8 }, - - { "YellowBook 2352", 2352, 0, 16, 9 }, - - { "RedBook 2352", 2352, 0, 0, 10 }, - - { "RAWQ 2448", 2448, 0, 0, 11 }, - - - - { "NERO ISO 2048", 2048, 150*2048, 0, 0 }, - - { "NERO GreenBook 2352", 2352, 150*2352, 24, 8 }, - - { "NERO YellowBook 2352", 2352, 150*2352, 16, 9 }, - - { "NERO RedBook 2352", 2352, 150*2352, 0, 10 }, - - { "NERO RAWQ 2448", 2448, 150*2448, 0, 11 }, - - - - { "Alt ISO 2048", 2048, 8, 0, 0 }, - - { "Alt RAW 2336", 2336, 8, 0, 7 }, - - { "Alt GreenBook 2352", 2352, 8, 24, 8 }, - - { "Alt YellowBook 2352", 2352, 8, 16, 9 }, - - { "Alt RedBook 2352", 2352, 8, 0, 10 }, - - { "Alt RAWQ 2448", 2448, 8, 0, 11 }, - - { NULL, 0, 0, 0, 0 } - -}; - - - - - -#define REDBOOK2352 10 - - - - - -void GetImageType(struct IsoFile *isofile, int imagetype) { - - int temptype; - - int i; - - - - temptype = imagetype; - - if((temptype < 0) || (temptype > 22)) temptype = REDBOOK2352; - - - - i = 0; - - while((i < 40) && (*(imagedata[temptype].name + i) != 0)) { - - isofile->imagename[i] = *(imagedata[temptype].name + i); - - i++; - - } // ENDWHILE- filling in the image name - - isofile->imagename[i] = 0; // And 0-terminate. - - - - isofile->blocksize = imagedata[temptype].blocksize; - - isofile->imageheader = imagedata[temptype].fileoffset; - - isofile->blockoffset = imagedata[temptype].dataoffset; - -} // END GetImageType() - - - - - -int GetImageTypeConvertTo(int imagetype) { - - return(imagedata[imagetype].conversiontype); - -} // END GetImageTypeConvertTo() - - - - - -int DetectImageType(struct IsoFile *isofile) { - - char comparestr[] = "CD001"; - - int newtype; - - off64_t targetpos; - - char teststr[2448]; - - int dataoffset; - - int i; - - int retval; - - - - newtype = 0; - - if(isofile->compress > 0) { - - IsoFileSeek(isofile, 16); - - IsoFileRead(isofile, teststr); - - - - while(imagedata[newtype].name != NULL) { - - if((isofile->blocksize == imagedata[newtype].blocksize) && - - (isofile->imageheader == imagedata[newtype].fileoffset)) { - - dataoffset = imagedata[newtype].dataoffset + 1; - - i = 0; - - while((i < 5) && (teststr[dataoffset + i] == comparestr[i])) i++; - - if(i == 5) { - - GetImageType(isofile, newtype); - - return(newtype); - - } // ENDIF- Did we find a match? - - } // ENDIF- Do these pieces match the compression storage pieces? - - newtype++; - - } // ENDWHILE- looking for the image type that fits the stats - - - - } else { - - while(imagedata[newtype].name != NULL) { - - targetpos = (16 * imagedata[newtype].blocksize) - - + imagedata[newtype].fileoffset - - + imagedata[newtype].dataoffset - - + 1; // Moves to start of string - - retval = ActualFileSeek(isofile->handle, targetpos); - - if(retval == 0) { - - retval = ActualFileRead(isofile->handle, 5, teststr); - - if(retval == 5) { - - i = 0; - - while((i < 5) && (teststr[i] == comparestr[i])) i++; - - if(i == 5) { - - ActualFileSeek(isofile->handle, isofile->imageheader); - - GetImageType(isofile, newtype); - - return(newtype); - - } // ENDIF- Did we find a match? - - } // ENDIF- Could we read in the test string? Cool! Test it. - - } // ENDIF- Could actually get to this point? - - newtype++; - - } // ENDWHILE- looking for the directory header string "CD001" - - ActualFileSeek(isofile->handle, isofile->imageheader); - - } // ENDIF- Do we match type to compression stats? (Or search against raw data?) - - - - GetImageType(isofile, REDBOOK2352); - - return(REDBOOK2352); // Couldn't find it? Guess it's RAW 2352, then. (Audio CD?) - -} // END ImageDetect() - +/* imagetype.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // off64_t + + + +// #ifndef __LINUX__ + +// #ifdef __linux__ + +// #define __LINUX__ + +// #endif /* __linux__ */ + +// #endif /* No __LINUX__ */ + + + +// #define CDVDdefs + +// #include "PS2Edefs.h" + + + +#include "isofile.h" + +#include "actualfile.h" + +#include "imagetype.h" + + + + + +// Based (mostly) off of florin's CDVDbin detection code, twice removed + +// with some additions from the header. + +struct ImageTypes imagedata[] = { + + { "ISO 2048", 2048, 0, 0, 0 }, + + { "YellowBook 2064", 2064, 0, 16, 1 }, + + { "RAW 2064", 2064, 0, 0, 2 }, + + { "GreenBook 2072", 2072, 0, 24, 3 }, + + { "RAW 2072", 2072, 0, 0, 4 }, + + { "RAW 2324", 2324, 0, 0, 5 }, + + { "RAW 2328", 2328, 0, 0, 6 }, + + { "RAW 2336", 2336, 0, 0, 7 }, + + { "GreenBook 2352", 2352, 0, 24, 8 }, + + { "YellowBook 2352", 2352, 0, 16, 9 }, + + { "RedBook 2352", 2352, 0, 0, 10 }, + + { "RAWQ 2448", 2448, 0, 0, 11 }, + + + + { "NERO ISO 2048", 2048, 150*2048, 0, 0 }, + + { "NERO GreenBook 2352", 2352, 150*2352, 24, 8 }, + + { "NERO YellowBook 2352", 2352, 150*2352, 16, 9 }, + + { "NERO RedBook 2352", 2352, 150*2352, 0, 10 }, + + { "NERO RAWQ 2448", 2448, 150*2448, 0, 11 }, + + + + { "Alt ISO 2048", 2048, 8, 0, 0 }, + + { "Alt RAW 2336", 2336, 8, 0, 7 }, + + { "Alt GreenBook 2352", 2352, 8, 24, 8 }, + + { "Alt YellowBook 2352", 2352, 8, 16, 9 }, + + { "Alt RedBook 2352", 2352, 8, 0, 10 }, + + { "Alt RAWQ 2448", 2448, 8, 0, 11 }, + + { NULL, 0, 0, 0, 0 } + +}; + + + + + +#define REDBOOK2352 10 + + + + + +void GetImageType(struct IsoFile *isofile, int imagetype) { + + int temptype; + + int i; + + + + temptype = imagetype; + + if((temptype < 0) || (temptype > 22)) temptype = REDBOOK2352; + + + + i = 0; + + while((i < 40) && (*(imagedata[temptype].name + i) != 0)) { + + isofile->imagename[i] = *(imagedata[temptype].name + i); + + i++; + + } // ENDWHILE- filling in the image name + + isofile->imagename[i] = 0; // And 0-terminate. + + + + isofile->blocksize = imagedata[temptype].blocksize; + + isofile->imageheader = imagedata[temptype].fileoffset; + + isofile->blockoffset = imagedata[temptype].dataoffset; + +} // END GetImageType() + + + + + +int GetImageTypeConvertTo(int imagetype) { + + return(imagedata[imagetype].conversiontype); + +} // END GetImageTypeConvertTo() + + + + + +int DetectImageType(struct IsoFile *isofile) { + + char comparestr[] = "CD001"; + + int newtype; + + off64_t targetpos; + + char teststr[2448]; + + int dataoffset; + + int i; + + int retval; + + + + newtype = 0; + + if(isofile->compress > 0) { + + IsoFileSeek(isofile, 16); + + IsoFileRead(isofile, teststr); + + + + while(imagedata[newtype].name != NULL) { + + if((isofile->blocksize == imagedata[newtype].blocksize) && + + (isofile->imageheader == imagedata[newtype].fileoffset)) { + + dataoffset = imagedata[newtype].dataoffset + 1; + + i = 0; + + while((i < 5) && (teststr[dataoffset + i] == comparestr[i])) i++; + + if(i == 5) { + + GetImageType(isofile, newtype); + + return(newtype); + + } // ENDIF- Did we find a match? + + } // ENDIF- Do these pieces match the compression storage pieces? + + newtype++; + + } // ENDWHILE- looking for the image type that fits the stats + + + + } else { + + while(imagedata[newtype].name != NULL) { + + targetpos = (16 * imagedata[newtype].blocksize) + + + imagedata[newtype].fileoffset + + + imagedata[newtype].dataoffset + + + 1; // Moves to start of string + + retval = ActualFileSeek(isofile->handle, targetpos); + + if(retval == 0) { + + retval = ActualFileRead(isofile->handle, 5, teststr); + + if(retval == 5) { + + i = 0; + + while((i < 5) && (teststr[i] == comparestr[i])) i++; + + if(i == 5) { + + ActualFileSeek(isofile->handle, isofile->imageheader); + + GetImageType(isofile, newtype); + + return(newtype); + + } // ENDIF- Did we find a match? + + } // ENDIF- Could we read in the test string? Cool! Test it. + + } // ENDIF- Could actually get to this point? + + newtype++; + + } // ENDWHILE- looking for the directory header string "CD001" + + ActualFileSeek(isofile->handle, isofile->imageheader); + + } // ENDIF- Do we match type to compression stats? (Or search against raw data?) + + + + GetImageType(isofile, REDBOOK2352); + + return(REDBOOK2352); // Couldn't find it? Guess it's RAW 2352, then. (Audio CD?) + +} // END ImageDetect() + diff --git a/plugins/CDVDisoEFP/src/imagetype.h b/plugins/CDVDisoEFP/src/imagetype.h index 20448cc053..af531b6200 100644 --- a/plugins/CDVDisoEFP/src/imagetype.h +++ b/plugins/CDVDisoEFP/src/imagetype.h @@ -1,112 +1,112 @@ -/* imagetype.h - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#ifndef IMAGETYPE_H - -#define IMAGETYPE_H - - - - - -// #ifndef __LINUX__ - -// #ifdef __linux__ - -// #define __LINUX__ - -// #endif /* __linux__ */ - -// #endif /* No __LINUX__ */ - - - -// #define CDVDdefs - -// #include "PS2Edefs.h" - - - -#include "isofile.h" - - - - - -struct ImageTypes { - - char *name; - - off64_t blocksize; - - off64_t fileoffset; - - int dataoffset; - - int conversiontype; // For conversionbox to write a new file as. - -}; - - - -// Note: Worked around since a failure occurred with MSVCRT.DLL. It couldn't - -// printf a char string inside an array of structures. Don't know why. - -// extern struct ImageTypes imagedata[]; - - - - - -extern void GetImageType(struct IsoFile *isofile, int imagetype); - -extern int GetImageTypeConvertTo(int imagetype); - -extern int DetectImageType(struct IsoFile *isofile); - - - - - -#endif /* IMAGETYPE_H */ - +/* imagetype.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef IMAGETYPE_H + +#define IMAGETYPE_H + + + + + +// #ifndef __LINUX__ + +// #ifdef __linux__ + +// #define __LINUX__ + +// #endif /* __linux__ */ + +// #endif /* No __LINUX__ */ + + + +// #define CDVDdefs + +// #include "PS2Edefs.h" + + + +#include "isofile.h" + + + + + +struct ImageTypes { + + char *name; + + off64_t blocksize; + + off64_t fileoffset; + + int dataoffset; + + int conversiontype; // For conversionbox to write a new file as. + +}; + + + +// Note: Worked around since a failure occurred with MSVCRT.DLL. It couldn't + +// printf a char string inside an array of structures. Don't know why. + +// extern struct ImageTypes imagedata[]; + + + + + +extern void GetImageType(struct IsoFile *isofile, int imagetype); + +extern int GetImageTypeConvertTo(int imagetype); + +extern int DetectImageType(struct IsoFile *isofile); + + + + + +#endif /* IMAGETYPE_H */ + diff --git a/plugins/CDVDisoEFP/src/ini.c b/plugins/CDVDisoEFP/src/ini.c index a00dac8f38..f1bc58746f 100644 --- a/plugins/CDVDisoEFP/src/ini.c +++ b/plugins/CDVDisoEFP/src/ini.c @@ -1,689 +1,1378 @@ -/* ini.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // NULL -#include // sprintf() - -#include "logfile.h" -#include "actualfile.h" -#include "ini.h" - - -const char INIext[] = ".ini"; -const char INInewext[] = ".new"; - - -// Returns: position where new extensions should be added. -int INIRemoveExt(char *argname, char *tempname) { - int i; - int j; - int k; - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: RemoveExt(%s)", argname); -#endif /* VERBOSE_FUNCTION_INI */ - - i = 0; - while((i <= INIMAXLEN) && (*(argname + i) != 0)) { - *(tempname + i) = *(argname + i); - i++; - } // ENDWHILE- Copying the argument name into a temporary area; - *(tempname + i) = 0; // And 0-terminate - k = i; - k--; - - j = 0; - while((j <= INIMAXLEN) && (INIext[j] != 0)) j++; - j--; - - while((j >= 0) && (*(tempname + k) == INIext[j])) { - k--; - j--; - } // ENDWHILE- Comparing the ending characters to the INI ext. - if(j < 0) { - k++; - i = k; - *(tempname + i) = 0; // 0-terminate, cutting off ".ini" - } // ENDIF- Do we have a match? Then remove the end chars. - - return(i); -} // END INIRemoveExt() - - -void INIAddInExt(char *tempname, int temppos) { - int i; - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: AddInExt(%s, %i)", tempname, temppos); -#endif /* VERBOSE_FUNCTION_INI */ - - i = 0; - while((i + temppos < INIMAXLEN) && (INIext[i] != 0)) { - *(tempname + temppos + i) = INIext[i]; - i++; - } // ENDWHILE- Attaching extenstion to filename - *(tempname + temppos + i) = 0; // And 0-terminate -} // END INIAddInExt() - - -void INIAddOutExt(char *tempname, int temppos) { - int i; - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: AddOutExt(%s, %i)", tempname, temppos); -#endif /* VERBOSE_FUNCTION_INI */ - - i = 0; - while((i + temppos < INIMAXLEN) && (INInewext[i] != 0)) { - *(tempname + temppos + i) = INInewext[i]; - i++; - } // ENDWHILE- Attaching extenstion to filename - *(tempname + temppos + i) = 0; // And 0-terminate -} // END INIAddInExt() - - -// Returns number of bytes read to get line (0 means end-of-file) -int INIReadLine(ACTUALHANDLE infile, char *buffer) { - int charcount; - int i; - char tempin[2]; - int retflag; - int retval; - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: ReadLine()"); -#endif /* VERBOSE_FUNCTION_INI */ - - charcount = 0; - i = 0; - tempin[1] = 0; - retflag = 0; - - while((i < INIMAXLEN) && (retflag < 2)) { - retval = ActualFileRead(infile, 1, tempin); - charcount++; - if(retval != 1) { - retflag = 2; - charcount--; - - } else if(tempin[0] == '\n') { - retflag = 2; - - } else if(tempin[0] >= ' ') { - *(buffer + i) = tempin[0]; - i++; - } // ENDLONGIF- How do we react to the next character? - } // ENDWHILE- Loading up on characters until an End-of-Line appears - *(buffer + i) = 0; // And 0-terminate - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: Line: %s", buffer); -#endif /* VERBOSE_FUNCTION_INI */ - - return(charcount); -} // END INIReadLine() -// Note: Do we need to back-skip a char if something other \n follows \r? - - -// Returns: number of bytes to get to start of section (or -1) -int INIFindSection(ACTUALHANDLE infile, char *section) { - int charcount; - int i; - int retflag; - int retval; - char scanbuffer[INIMAXLEN+1]; - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: FindSection(%s)", section); -#endif /* VERBOSE_FUNCTION_INI */ - - charcount = 0; - retflag = 0; - - while(retflag == 0) { - retval = INIReadLine(infile, scanbuffer); - if(retval == 0) return(-1); // EOF? Stop here. - - if(scanbuffer[0] == '[') { - i = 0; - while((i < INIMAXLEN) && - (*(section + i) != 0) && - (*(section + i) == scanbuffer[i + 1])) i++; - if((i < INIMAXLEN - 2) && (*(section + i) == 0)) { - if((scanbuffer[i + 1] == ']') && (scanbuffer[i + 2] == 0)) { - retflag = 1; - } // ENDIF- End marks look good? Return successful. - } // ENDIF- Do we have a section match? - } // ENDIF- Does this look like a section header? - - if(retflag == 0) charcount += retval; - } // ENDWHILE- Scanning lines for the correct [Section] header. - - return(charcount); -} // END INIFindSection() - - -// Returns: number of bytes to get to start of keyword (or -1) -int INIFindKeyword(ACTUALHANDLE infile, char *keyword, char *buffer) { - int charcount; - int i; - int j; - int retflag; - int retval; - char scanbuffer[INIMAXLEN+1]; - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: FindKeyword(%s)", keyword); -#endif /* VERBOSE_FUNCTION_INI */ - - charcount = 0; - retflag = 0; - - while(retflag == 0) { - retval = INIReadLine(infile, scanbuffer); - if(retval == 0) return(-1); // EOF? Stop here. - if(scanbuffer[0] == '[') return(-1); // New section? Stop here. - - i = 0; - while((i < INIMAXLEN) && - (*(keyword + i) != 0) && - (*(keyword + i) == scanbuffer[i])) i++; - if((i < INIMAXLEN - 2) && (*(keyword + i) == 0)) { - if(scanbuffer[i] == '=') { - retflag = 1; - if(buffer != NULL) { - i++; - j = 0; - while((i < INIMAXLEN) && (scanbuffer[i] != 0)) { - *(buffer + j) = scanbuffer[i]; - i++; - j++; - } // ENDWHILE- Copying the value out to the outbound buffer. - *(buffer + j) = 0; // And 0-terminate. - } // ENDIF- Return the value as well? - } // ENDIF- End marks look good? Return successful. - } // ENDIF- Do we have a section match? - - if(retflag == 0) charcount += retval; - } // ENDWHILE- Scanning lines for the correct [Section] header. - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: Value: %s", buffer); -#endif /* VERBOSE_FUNCTION_INI */ - - return(charcount); -} // END INIFindKeyWord() - - -// Returns: number of bytes left to write... (from charcount back) -int INICopy(ACTUALHANDLE infile, ACTUALHANDLE outfile, int charcount) { - char buffer[4096]; - int i; - int chunk; - int retval; - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: Copy(%i)", charcount); -#endif /* VERBOSE_FUNCTION_INI */ - - i = charcount; - chunk = 4096; - if(i < chunk) chunk = i; - while(chunk > 0) { - retval = ActualFileRead(infile, chunk, buffer); - if(retval <= 0) return(i); // Trouble? Stop here. - if(retval < chunk) chunk = retval; // Short block? Note it. - - retval = ActualFileWrite(outfile, chunk, buffer); - if(retval <= 0) return(i); // Trouble? Stop here. - i -= retval; - if(retval < chunk) return(i); // Short block written? Stop here. - - chunk = 4096; - if(i < chunk) chunk = i; - } // ENDWHILE- Copying a section of file across, one chunk at a time. - - return(0); -} // END INICopyToPos() - - -int INISaveString(char *file, char *section, char *keyword, char *value) { - char inname[INIMAXLEN+1]; - char outname[INIMAXLEN+1]; - int filepos; - ACTUALHANDLE infile; - ACTUALHANDLE outfile; - int i; - int retval; - char templine[INIMAXLEN+1]; - - if(file == NULL) return(-1); - if(section == NULL) return(-1); - if(keyword == NULL) return(-1); - if(value == NULL) return(-1); - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: SaveString(%s, %s, %s, %s)", - file, section, keyword, value); -#endif /* VERBOSE_FUNCTION_INI */ - - filepos = INIRemoveExt(file, inname); - for(i = 0; i <= filepos; i++) outname[i] = inname[i]; - INIAddInExt(inname, filepos); - INIAddOutExt(outname, filepos); - - filepos = 0; - infile = ActualFileOpenForRead(inname); - if(infile == ACTUALHANDLENULL) { -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: creating new file"); -#endif /* VERBOSE_FUNCTION_INI */ - outfile = ActualFileOpenForWrite(inname); - if(outfile == ACTUALHANDLENULL) return(-1); // Just a bad name? Abort. - - sprintf(templine, "[%s]\r\n", section); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - if(retval < i) { - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(inname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - - sprintf(templine, "%s=%s\r\n", keyword, value); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - if(retval < i) { - ActualFileDelete(inname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - return(0); - } // ENDIF- No input file? Create a brand new .ini file then. - - retval = INIFindSection(infile, section); - if(retval < 0) { -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: creating new section"); -#endif /* VERBOSE_FUNCTION_INI */ - outfile = ActualFileOpenForWrite(outname); - if(outfile == ACTUALHANDLENULL) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't open a temp file? Abort - - ActualFileSeek(infile, 0); // Move ini to beginning of file... - INICopy(infile, outfile, 0x0FFFFFFF); // Copy the whole file out... - - sprintf(templine, "\r\n[%s]\r\n", section); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - if(retval < i) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - - sprintf(templine, "%s=%s\r\n", keyword, value); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - if(retval < i) { - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - - ActualFileDelete(inname); - ActualFileRename(outname, inname); - return(0); - } // ENDIF- Couldn't find the section? Make a new one! - - filepos = retval; - ActualFileSeek(infile, filepos); - filepos += INIReadLine(infile, templine); // Get section line's byte count - - retval = INIFindKeyword(infile, keyword, NULL); - if(retval < 0) { -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: creating new keyword"); -#endif /* VERBOSE_FUNCTION_INI */ - ActualFileSeek(infile, filepos); - retval = INIReadLine(infile, templine); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0) && (templine[i] != '=')) i++; - while((retval > 0) && (templine[i] == '=')) { - filepos += retval; - retval = INIReadLine(infile, templine); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0) && (templine[i] != '=')) i++; - } // ENDWHILE- skimming to the bottom of the section - - outfile = ActualFileOpenForWrite(outname); - if(outfile == ACTUALHANDLENULL) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't open a temp file? Abort - - ActualFileSeek(infile, 0); - retval = INICopy(infile, outfile, filepos); - if(retval > 0) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing everything up to keyword? Abort. - - sprintf(templine, "%s=%s\r\n", keyword, value); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - if(retval < i) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - - } else { -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: replacing keyword"); -#endif /* VERBOSE_FUNCTION_INI */ - filepos += retval; // Position just before old version of keyword - - outfile = ActualFileOpenForWrite(outname); - if(outfile == ACTUALHANDLENULL) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't open a temp file? Abort - - ActualFileSeek(infile, 0); - retval = INICopy(infile, outfile, filepos); - if(retval > 0) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing everything up to keyword? Abort. - - INIReadLine(infile, templine); // Read past old keyword/value... - - // Replace with new value - sprintf(templine, "%s=%s\r\n", keyword, value); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - if(retval < i) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - } // ENDIF- Need to add a new keyword? - - INICopy(infile, outfile, 0xFFFFFFF); // Write out rest of file - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(inname); - ActualFileRename(outname, inname); - return(0); -} // END INISaveString() - - -int INILoadString(char *file, char *section, char *keyword, char *buffer) { - char inname[INIMAXLEN+1]; - int filepos; - ACTUALHANDLE infile; - int retval; - - if(file == NULL) return(-1); - if(section == NULL) return(-1); - if(keyword == NULL) return(-1); - if(buffer == NULL) return(-1); - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: LoadString(%s, %s, %s)", - file, section, keyword); -#endif /* VERBOSE_FUNCTION_INI */ - - filepos = INIRemoveExt(file, inname); - INIAddInExt(inname, filepos); - - filepos = 0; - infile = ActualFileOpenForRead(inname); - if(infile == ACTUALHANDLENULL) return(-1); - - retval = INIFindSection(infile, section); - if(retval < 0) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Didn't find it? Abort. - - retval = INIFindKeyword(infile, keyword, buffer); - if(retval < 0) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Didn't find it? Abort. - - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(0); -} // END INILoadString() - - -int INIRemove(char *file, char *section, char *keyword) { - char inname[INIMAXLEN+1]; - char outname[INIMAXLEN+1]; - int filepos; - ACTUALHANDLE infile; - ACTUALHANDLE outfile; - char templine[INIMAXLEN+1]; - int i; - int retval; - - if(file == NULL) return(-1); - if(section == NULL) return(-1); - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: Remove(%s, %s, %s)", - file, section, keyword); -#endif /* VERBOSE_FUNCTION_INI */ - - filepos = INIRemoveExt(file, inname); - for(i = 0; i <= filepos; i++) outname[i] = inname[i]; - INIAddInExt(inname, filepos); - INIAddOutExt(outname, filepos); - - infile = ActualFileOpenForRead(inname); - if(infile == ACTUALHANDLENULL) return(-1); - - retval = INIFindSection(infile, section); - if(retval == -1) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't even find the section? Abort - - filepos = retval; - if(keyword == NULL) { -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: removing section"); -#endif /* VERBOSE_FUNCTION_INI */ - outfile = ActualFileOpenForWrite(outname); - if(outfile == ACTUALHANDLENULL) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't open a temp file? Abort - - ActualFileSeek(infile, 0); - retval = INICopy(infile, outfile, filepos); - if(retval > 0) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing everything up to the section? Abort. - - templine[0] = 0; - retval = 1; - while((retval > 0) && (templine[0] != '[')) { - retval = INIReadLine(infile, templine); - } // ENDWHILE- Read to the start of the next section... or EOF. - - if(templine[0] == '[') { - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - if(retval < i) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - } // ENDIF- Are there other sections after this one? Save them then. - - } else { - filepos = retval; - ActualFileSeek(infile, filepos); - filepos += INIReadLine(infile, templine); // Get section line's byte count - - retval = INIFindKeyword(infile, keyword, NULL); - if(retval == -1) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't find the keyword? Abort - filepos += retval; - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: removing keyword"); -#endif /* VERBOSE_FUNCTION_INI */ - outfile = ActualFileOpenForWrite(outname); - if(outfile == ACTUALHANDLENULL) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't open a temp file? Abort - - ActualFileSeek(infile, 0); - retval = INICopy(infile, outfile, filepos); - if(retval > 0) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing everything up to keyword? Abort. - - INIReadLine(infile, templine); // Read (and discard) the keyword line - } // ENDIF- Wipe out the whole section? Or just a keyword? - - INICopy(infile, outfile, 0xFFFFFFF); // Write out rest of file - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(inname); - ActualFileRename(outname, inname); - return(0); -} // END INIRemove() - - -int INISaveUInt(char *file, char *section, char *keyword, unsigned int value) { - char numvalue[INIMAXLEN+1]; - - sprintf(numvalue, "%u", value); - return(INISaveString(file, section, keyword, numvalue)); -} // END INISaveUInt() - - -int INILoadUInt(char *file, char *section, char *keyword, unsigned int *buffer) { - char numvalue[INIMAXLEN+1]; - int retval; - unsigned int value; - // unsigned int sign; // Not needed in unsigned numbers - int pos; - - if(buffer == NULL) return(-1); - *(buffer) = 0; - - retval = INILoadString(file, section, keyword, numvalue); - if(retval < 0) return(retval); - - value = 0; - // sign = 1; // Start positive - pos = 0; - - // Note: skip leading spaces? (Shouldn't have to, I hope) - - // if(numvalue[pos] == '-') { - // pos++; - // sign = -1; - // } // ENDIF- Negative sign check - - while((pos < INIMAXLEN) && (numvalue[pos] != 0)) { - if(value > (0xFFFFFFFF / 10)) return(-1); // Overflow? - - if((numvalue[pos] >= '0') && (numvalue[pos] <= '9')) { - value *= 10; - value += numvalue[pos] - '0'; - pos++; - } else { - numvalue[pos] = 0; - } // ENDIF- Add a digit in? Or stop searching for digits? - } // ENDWHILE- Adding digits of info to our ever-increasing value - - // value *= sign - *(buffer) = value; - return(0); -} // END INILoadUInt() +/* ini.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // sprintf() + + + +#include "logfile.h" + +#include "actualfile.h" + +#include "ini.h" + + + + + +const char INIext[] = ".ini"; + +const char INInewext[] = ".new"; + + + + + +// Returns: position where new extensions should be added. + +int INIRemoveExt(char *argname, char *tempname) { + + int i; + + int j; + + int k; + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: RemoveExt(%s)", argname); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + i = 0; + + while((i <= INIMAXLEN) && (*(argname + i) != 0)) { + + *(tempname + i) = *(argname + i); + + i++; + + } // ENDWHILE- Copying the argument name into a temporary area; + + *(tempname + i) = 0; // And 0-terminate + + k = i; + + k--; + + + + j = 0; + + while((j <= INIMAXLEN) && (INIext[j] != 0)) j++; + + j--; + + + + while((j >= 0) && (*(tempname + k) == INIext[j])) { + + k--; + + j--; + + } // ENDWHILE- Comparing the ending characters to the INI ext. + + if(j < 0) { + + k++; + + i = k; + + *(tempname + i) = 0; // 0-terminate, cutting off ".ini" + + } // ENDIF- Do we have a match? Then remove the end chars. + + + + return(i); + +} // END INIRemoveExt() + + + + + +void INIAddInExt(char *tempname, int temppos) { + + int i; + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: AddInExt(%s, %i)", tempname, temppos); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + i = 0; + + while((i + temppos < INIMAXLEN) && (INIext[i] != 0)) { + + *(tempname + temppos + i) = INIext[i]; + + i++; + + } // ENDWHILE- Attaching extenstion to filename + + *(tempname + temppos + i) = 0; // And 0-terminate + +} // END INIAddInExt() + + + + + +void INIAddOutExt(char *tempname, int temppos) { + + int i; + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: AddOutExt(%s, %i)", tempname, temppos); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + i = 0; + + while((i + temppos < INIMAXLEN) && (INInewext[i] != 0)) { + + *(tempname + temppos + i) = INInewext[i]; + + i++; + + } // ENDWHILE- Attaching extenstion to filename + + *(tempname + temppos + i) = 0; // And 0-terminate + +} // END INIAddInExt() + + + + + +// Returns number of bytes read to get line (0 means end-of-file) + +int INIReadLine(ACTUALHANDLE infile, char *buffer) { + + int charcount; + + int i; + + char tempin[2]; + + int retflag; + + int retval; + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: ReadLine()"); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + charcount = 0; + + i = 0; + + tempin[1] = 0; + + retflag = 0; + + + + while((i < INIMAXLEN) && (retflag < 2)) { + + retval = ActualFileRead(infile, 1, tempin); + + charcount++; + + if(retval != 1) { + + retflag = 2; + + charcount--; + + + + } else if(tempin[0] == '\n') { + + retflag = 2; + + + + } else if(tempin[0] >= ' ') { + + *(buffer + i) = tempin[0]; + + i++; + + } // ENDLONGIF- How do we react to the next character? + + } // ENDWHILE- Loading up on characters until an End-of-Line appears + + *(buffer + i) = 0; // And 0-terminate + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: Line: %s", buffer); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + return(charcount); + +} // END INIReadLine() + +// Note: Do we need to back-skip a char if something other \n follows \r? + + + + + +// Returns: number of bytes to get to start of section (or -1) + +int INIFindSection(ACTUALHANDLE infile, char *section) { + + int charcount; + + int i; + + int retflag; + + int retval; + + char scanbuffer[INIMAXLEN+1]; + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: FindSection(%s)", section); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + charcount = 0; + + retflag = 0; + + + + while(retflag == 0) { + + retval = INIReadLine(infile, scanbuffer); + + if(retval == 0) return(-1); // EOF? Stop here. + + + + if(scanbuffer[0] == '[') { + + i = 0; + + while((i < INIMAXLEN) && + + (*(section + i) != 0) && + + (*(section + i) == scanbuffer[i + 1])) i++; + + if((i < INIMAXLEN - 2) && (*(section + i) == 0)) { + + if((scanbuffer[i + 1] == ']') && (scanbuffer[i + 2] == 0)) { + + retflag = 1; + + } // ENDIF- End marks look good? Return successful. + + } // ENDIF- Do we have a section match? + + } // ENDIF- Does this look like a section header? + + + + if(retflag == 0) charcount += retval; + + } // ENDWHILE- Scanning lines for the correct [Section] header. + + + + return(charcount); + +} // END INIFindSection() + + + + + +// Returns: number of bytes to get to start of keyword (or -1) + +int INIFindKeyword(ACTUALHANDLE infile, char *keyword, char *buffer) { + + int charcount; + + int i; + + int j; + + int retflag; + + int retval; + + char scanbuffer[INIMAXLEN+1]; + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: FindKeyword(%s)", keyword); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + charcount = 0; + + retflag = 0; + + + + while(retflag == 0) { + + retval = INIReadLine(infile, scanbuffer); + + if(retval == 0) return(-1); // EOF? Stop here. + + if(scanbuffer[0] == '[') return(-1); // New section? Stop here. + + + + i = 0; + + while((i < INIMAXLEN) && + + (*(keyword + i) != 0) && + + (*(keyword + i) == scanbuffer[i])) i++; + + if((i < INIMAXLEN - 2) && (*(keyword + i) == 0)) { + + if(scanbuffer[i] == '=') { + + retflag = 1; + + if(buffer != NULL) { + + i++; + + j = 0; + + while((i < INIMAXLEN) && (scanbuffer[i] != 0)) { + + *(buffer + j) = scanbuffer[i]; + + i++; + + j++; + + } // ENDWHILE- Copying the value out to the outbound buffer. + + *(buffer + j) = 0; // And 0-terminate. + + } // ENDIF- Return the value as well? + + } // ENDIF- End marks look good? Return successful. + + } // ENDIF- Do we have a section match? + + + + if(retflag == 0) charcount += retval; + + } // ENDWHILE- Scanning lines for the correct [Section] header. + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: Value: %s", buffer); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + return(charcount); + +} // END INIFindKeyWord() + + + + + +// Returns: number of bytes left to write... (from charcount back) + +int INICopy(ACTUALHANDLE infile, ACTUALHANDLE outfile, int charcount) { + + char buffer[4096]; + + int i; + + int chunk; + + int retval; + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: Copy(%i)", charcount); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + i = charcount; + + chunk = 4096; + + if(i < chunk) chunk = i; + + while(chunk > 0) { + + retval = ActualFileRead(infile, chunk, buffer); + + if(retval <= 0) return(i); // Trouble? Stop here. + + if(retval < chunk) chunk = retval; // Short block? Note it. + + + + retval = ActualFileWrite(outfile, chunk, buffer); + + if(retval <= 0) return(i); // Trouble? Stop here. + + i -= retval; + + if(retval < chunk) return(i); // Short block written? Stop here. + + + + chunk = 4096; + + if(i < chunk) chunk = i; + + } // ENDWHILE- Copying a section of file across, one chunk at a time. + + + + return(0); + +} // END INICopyToPos() + + + + + +int INISaveString(char *file, char *section, char *keyword, char *value) { + + char inname[INIMAXLEN+1]; + + char outname[INIMAXLEN+1]; + + int filepos; + + ACTUALHANDLE infile; + + ACTUALHANDLE outfile; + + int i; + + int retval; + + char templine[INIMAXLEN+1]; + + + + if(file == NULL) return(-1); + + if(section == NULL) return(-1); + + if(keyword == NULL) return(-1); + + if(value == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: SaveString(%s, %s, %s, %s)", + + file, section, keyword, value); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + filepos = INIRemoveExt(file, inname); + + for(i = 0; i <= filepos; i++) outname[i] = inname[i]; + + INIAddInExt(inname, filepos); + + INIAddOutExt(outname, filepos); + + + + filepos = 0; + + infile = ActualFileOpenForRead(inname); + + if(infile == ACTUALHANDLENULL) { + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: creating new file"); + +#endif /* VERBOSE_FUNCTION_INI */ + + outfile = ActualFileOpenForWrite(inname); + + if(outfile == ACTUALHANDLENULL) return(-1); // Just a bad name? Abort. + + + + sprintf(templine, "[%s]\r\n", section); + + i = 0; + + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + + retval = ActualFileWrite(outfile, i, templine); + + if(retval < i) { + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(inname); + + return(-1); + + } // ENDIF- Trouble writing it out? Abort. + + + + sprintf(templine, "%s=%s\r\n", keyword, value); + + i = 0; + + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + + retval = ActualFileWrite(outfile, i, templine); + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + if(retval < i) { + + ActualFileDelete(inname); + + return(-1); + + } // ENDIF- Trouble writing it out? Abort. + + return(0); + + } // ENDIF- No input file? Create a brand new .ini file then. + + + + retval = INIFindSection(infile, section); + + if(retval < 0) { + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: creating new section"); + +#endif /* VERBOSE_FUNCTION_INI */ + + outfile = ActualFileOpenForWrite(outname); + + if(outfile == ACTUALHANDLENULL) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- Couldn't open a temp file? Abort + + + + ActualFileSeek(infile, 0); // Move ini to beginning of file... + + INICopy(infile, outfile, 0x0FFFFFFF); // Copy the whole file out... + + + + sprintf(templine, "\r\n[%s]\r\n", section); + + i = 0; + + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + + retval = ActualFileWrite(outfile, i, templine); + + if(retval < i) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(outname); + + return(-1); + + } // ENDIF- Trouble writing it out? Abort. + + + + sprintf(templine, "%s=%s\r\n", keyword, value); + + i = 0; + + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + + retval = ActualFileWrite(outfile, i, templine); + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + if(retval < i) { + + ActualFileDelete(outname); + + return(-1); + + } // ENDIF- Trouble writing it out? Abort. + + + + ActualFileDelete(inname); + + ActualFileRename(outname, inname); + + return(0); + + } // ENDIF- Couldn't find the section? Make a new one! + + + + filepos = retval; + + ActualFileSeek(infile, filepos); + + filepos += INIReadLine(infile, templine); // Get section line's byte count + + + + retval = INIFindKeyword(infile, keyword, NULL); + + if(retval < 0) { + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: creating new keyword"); + +#endif /* VERBOSE_FUNCTION_INI */ + + ActualFileSeek(infile, filepos); + + retval = INIReadLine(infile, templine); + + i = 0; + + while((i < INIMAXLEN) && (templine[i] != 0) && (templine[i] != '=')) i++; + + while((retval > 0) && (templine[i] == '=')) { + + filepos += retval; + + retval = INIReadLine(infile, templine); + + i = 0; + + while((i < INIMAXLEN) && (templine[i] != 0) && (templine[i] != '=')) i++; + + } // ENDWHILE- skimming to the bottom of the section + + + + outfile = ActualFileOpenForWrite(outname); + + if(outfile == ACTUALHANDLENULL) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- Couldn't open a temp file? Abort + + + + ActualFileSeek(infile, 0); + + retval = INICopy(infile, outfile, filepos); + + if(retval > 0) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(outname); + + return(-1); + + } // ENDIF- Trouble writing everything up to keyword? Abort. + + + + sprintf(templine, "%s=%s\r\n", keyword, value); + + i = 0; + + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + + retval = ActualFileWrite(outfile, i, templine); + + if(retval < i) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(outname); + + return(-1); + + } // ENDIF- Trouble writing it out? Abort. + + + + } else { + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: replacing keyword"); + +#endif /* VERBOSE_FUNCTION_INI */ + + filepos += retval; // Position just before old version of keyword + + + + outfile = ActualFileOpenForWrite(outname); + + if(outfile == ACTUALHANDLENULL) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- Couldn't open a temp file? Abort + + + + ActualFileSeek(infile, 0); + + retval = INICopy(infile, outfile, filepos); + + if(retval > 0) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(outname); + + return(-1); + + } // ENDIF- Trouble writing everything up to keyword? Abort. + + + + INIReadLine(infile, templine); // Read past old keyword/value... + + + + // Replace with new value + + sprintf(templine, "%s=%s\r\n", keyword, value); + + i = 0; + + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + + retval = ActualFileWrite(outfile, i, templine); + + if(retval < i) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(outname); + + return(-1); + + } // ENDIF- Trouble writing it out? Abort. + + } // ENDIF- Need to add a new keyword? + + + + INICopy(infile, outfile, 0xFFFFFFF); // Write out rest of file + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(inname); + + ActualFileRename(outname, inname); + + return(0); + +} // END INISaveString() + + + + + +int INILoadString(char *file, char *section, char *keyword, char *buffer) { + + char inname[INIMAXLEN+1]; + + int filepos; + + ACTUALHANDLE infile; + + int retval; + + + + if(file == NULL) return(-1); + + if(section == NULL) return(-1); + + if(keyword == NULL) return(-1); + + if(buffer == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: LoadString(%s, %s, %s)", + + file, section, keyword); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + filepos = INIRemoveExt(file, inname); + + INIAddInExt(inname, filepos); + + + + filepos = 0; + + infile = ActualFileOpenForRead(inname); + + if(infile == ACTUALHANDLENULL) return(-1); + + + + retval = INIFindSection(infile, section); + + if(retval < 0) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- Didn't find it? Abort. + + + + retval = INIFindKeyword(infile, keyword, buffer); + + if(retval < 0) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- Didn't find it? Abort. + + + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(0); + +} // END INILoadString() + + + + + +int INIRemove(char *file, char *section, char *keyword) { + + char inname[INIMAXLEN+1]; + + char outname[INIMAXLEN+1]; + + int filepos; + + ACTUALHANDLE infile; + + ACTUALHANDLE outfile; + + char templine[INIMAXLEN+1]; + + int i; + + int retval; + + + + if(file == NULL) return(-1); + + if(section == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: Remove(%s, %s, %s)", + + file, section, keyword); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + filepos = INIRemoveExt(file, inname); + + for(i = 0; i <= filepos; i++) outname[i] = inname[i]; + + INIAddInExt(inname, filepos); + + INIAddOutExt(outname, filepos); + + + + infile = ActualFileOpenForRead(inname); + + if(infile == ACTUALHANDLENULL) return(-1); + + + + retval = INIFindSection(infile, section); + + if(retval == -1) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- Couldn't even find the section? Abort + + + + filepos = retval; + + if(keyword == NULL) { + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: removing section"); + +#endif /* VERBOSE_FUNCTION_INI */ + + outfile = ActualFileOpenForWrite(outname); + + if(outfile == ACTUALHANDLENULL) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- Couldn't open a temp file? Abort + + + + ActualFileSeek(infile, 0); + + retval = INICopy(infile, outfile, filepos); + + if(retval > 0) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(outname); + + return(-1); + + } // ENDIF- Trouble writing everything up to the section? Abort. + + + + templine[0] = 0; + + retval = 1; + + while((retval > 0) && (templine[0] != '[')) { + + retval = INIReadLine(infile, templine); + + } // ENDWHILE- Read to the start of the next section... or EOF. + + + + if(templine[0] == '[') { + + i = 0; + + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + + retval = ActualFileWrite(outfile, i, templine); + + if(retval < i) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(outname); + + return(-1); + + } // ENDIF- Trouble writing it out? Abort. + + } // ENDIF- Are there other sections after this one? Save them then. + + + + } else { + + filepos = retval; + + ActualFileSeek(infile, filepos); + + filepos += INIReadLine(infile, templine); // Get section line's byte count + + + + retval = INIFindKeyword(infile, keyword, NULL); + + if(retval == -1) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- Couldn't find the keyword? Abort + + filepos += retval; + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: removing keyword"); + +#endif /* VERBOSE_FUNCTION_INI */ + + outfile = ActualFileOpenForWrite(outname); + + if(outfile == ACTUALHANDLENULL) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- Couldn't open a temp file? Abort + + + + ActualFileSeek(infile, 0); + + retval = INICopy(infile, outfile, filepos); + + if(retval > 0) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(outname); + + return(-1); + + } // ENDIF- Trouble writing everything up to keyword? Abort. + + + + INIReadLine(infile, templine); // Read (and discard) the keyword line + + } // ENDIF- Wipe out the whole section? Or just a keyword? + + + + INICopy(infile, outfile, 0xFFFFFFF); // Write out rest of file + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(inname); + + ActualFileRename(outname, inname); + + return(0); + +} // END INIRemove() + + + + + +int INISaveUInt(char *file, char *section, char *keyword, unsigned int value) { + + char numvalue[INIMAXLEN+1]; + + + + sprintf(numvalue, "%u", value); + + return(INISaveString(file, section, keyword, numvalue)); + +} // END INISaveUInt() + + + + + +int INILoadUInt(char *file, char *section, char *keyword, unsigned int *buffer) { + + char numvalue[INIMAXLEN+1]; + + int retval; + + unsigned int value; + + // unsigned int sign; // Not needed in unsigned numbers + + int pos; + + + + if(buffer == NULL) return(-1); + + *(buffer) = 0; + + + + retval = INILoadString(file, section, keyword, numvalue); + + if(retval < 0) return(retval); + + + + value = 0; + + // sign = 1; // Start positive + + pos = 0; + + + + // Note: skip leading spaces? (Shouldn't have to, I hope) + + + + // if(numvalue[pos] == '-') { + + // pos++; + + // sign = -1; + + // } // ENDIF- Negative sign check + + + + while((pos < INIMAXLEN) && (numvalue[pos] != 0)) { + + if(value > (0xFFFFFFFF / 10)) return(-1); // Overflow? + + + + if((numvalue[pos] >= '0') && (numvalue[pos] <= '9')) { + + value *= 10; + + value += numvalue[pos] - '0'; + + pos++; + + } else { + + numvalue[pos] = 0; + + } // ENDIF- Add a digit in? Or stop searching for digits? + + } // ENDWHILE- Adding digits of info to our ever-increasing value + + + + // value *= sign + + *(buffer) = value; + + return(0); + +} // END INILoadUInt() + diff --git a/plugins/CDVDisoEFP/src/ini.h b/plugins/CDVDisoEFP/src/ini.h index fbd2349cf5..a666f99659 100644 --- a/plugins/CDVDisoEFP/src/ini.h +++ b/plugins/CDVDisoEFP/src/ini.h @@ -1,64 +1,128 @@ -/* ini.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef INI_H -#define INI_H - - -// #ifndef __LINUX__ -// #ifdef __linux__ -// #define __LINUX__ -// #endif /* __linux__ */ -// #endif /* No __LINUX__ */ - -// #define CDVDdefs -// #include "PS2Edefs.h" - - -// File format: -// [section] -// keyword=value - -// file - Name of the INI file -// section - Section within the file -// keyword - Identifier for a value -// value - value to store with a keyword in a section in the file -// buffer - place to retrieve the value of a keyword - -// return values: 0 = success, -1 = failure - - -// #define VERBOSE_FUNCTION_INI - -#define INIMAXLEN 255 - - -extern int INISaveString(char *file, char *section, char *keyword, char *value); -extern int INILoadString(char *file, char *section, char *keyword, char *buffer); - -extern int INISaveUInt(char *file, char *section, char *keyword, unsigned int value); -extern int INILoadUInt(char *file, char *section, char *keyword, unsigned int *buffer); - -// NULL in the keyword below removes the whole section. -extern int INIRemove(char *file, char *section, char *keyword); - - -#endif /* INI_H */ +/* ini.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef INI_H + +#define INI_H + + + + + +// #ifndef __LINUX__ + +// #ifdef __linux__ + +// #define __LINUX__ + +// #endif /* __linux__ */ + +// #endif /* No __LINUX__ */ + + + +// #define CDVDdefs + +// #include "PS2Edefs.h" + + + + + +// File format: + +// [section] + +// keyword=value + + + +// file - Name of the INI file + +// section - Section within the file + +// keyword - Identifier for a value + +// value - value to store with a keyword in a section in the file + +// buffer - place to retrieve the value of a keyword + + + +// return values: 0 = success, -1 = failure + + + + + +// #define VERBOSE_FUNCTION_INI + + + +#define INIMAXLEN 255 + + + + + +extern int INISaveString(char *file, char *section, char *keyword, char *value); + +extern int INILoadString(char *file, char *section, char *keyword, char *buffer); + + + +extern int INISaveUInt(char *file, char *section, char *keyword, unsigned int value); + +extern int INILoadUInt(char *file, char *section, char *keyword, unsigned int *buffer); + + + +// NULL in the keyword below removes the whole section. + +extern int INIRemove(char *file, char *section, char *keyword); + + + + + +#endif /* INI_H */ + diff --git a/plugins/CDVDisoEFP/src/isocompress.c b/plugins/CDVDisoEFP/src/isocompress.c index 5385342027..4ed3c21579 100644 --- a/plugins/CDVDisoEFP/src/isocompress.c +++ b/plugins/CDVDisoEFP/src/isocompress.c @@ -1,914 +1,914 @@ -/* isocompress.c - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#include // NULL - - - -// #ifndef __LINUX__ - -// #ifdef __linux__ - -// #define __LINUX__ - -// #endif /* __linux__ */ - -// #endif /* No __LINUX__ */ - - - -// #define CDVDdefs - -// #include "PS2Edefs.h" - - - -#include "logfile.h" - -#include "isofile.h" - -#include "actualfile.h" - -#include "gzipv1.h" - -#include "blockv2.h" - -#include "gzipv2.h" - -#include "bzip2v2.h" - -#include "bzip2v3.h" - -#include "isocompress.h" - - - - - -const char *compressnames[] = { - - "No Compression", - - ".Z (zlib) for speed", - - ".BZ2 (bzip2) for speed", - - ".bz2 (bzip2) for size", - - NULL }; // Compress types 0, 3, 4, and 5 - - - -const char *compressdesc[] = { - - "", - - " zlib orig", - - " block.dump", - - " zlib speed", - - " bzip2 speed", - - " bzip2 size", - - NULL }; - - - -const char *compressid[] = { - - "BVD2", - - "Z V2", - - "BZV2", - - "BZV3", - - NULL }; // Starts at compress type 2 - - - -struct CompressExt compressext[] = { - - { ".z", 1 }, - - { ".Z", 1 }, - - { ".bz2", 5 }, - - { ".BZ2", 3 }, - - { ".bZ2", 3 }, - - { ".Bz2", 3 }, - - { ".bz", 3 }, - - { ".BZ", 3 }, - - { ".bZ", 3 }, - - { ".Bz", 3 }, - - { ".dump", 2 }, - - { NULL, 0 } - -}; - - - - - -int IsoNameStripCompress(struct IsoFile *isofile) { - - int tempext; - - int tempnamepos; - - int tempextpos; - - int retmethod; - - - - retmethod = 0; - - tempext = 0; - - while(compressext[tempext].name != NULL) { - - tempextpos = 0; - - while(*(compressext[tempext].name + tempextpos) != 0) tempextpos++; - - - - tempnamepos = isofile->namepos; - - while((tempnamepos > 0) && (tempextpos > 0) && - - (isofile->name[tempnamepos - 1] == *(compressext[tempext].name + tempextpos - 1))) { - - tempnamepos--; - - tempextpos--; - - } // ENDWHILE- Comparing one extension to the end of the file name - - if(tempextpos == 0) { - - isofile->namepos = tempnamepos; // Move name pointer in front of ext. - - return(compressext[tempext].method); // Found a match... say which one. - - } else { - - tempext++; // Next ext in the list to test... - - } // ENDIF- Did we find a match? - - } // ENDWHILE- looking through extension list - - - - return(0); // No compress extension found. - -} // END IsoNameStripCompress() - - - - - -int CompressOpenForRead(struct IsoFile *isofile) { - - int retval; - - - -#ifdef VERBOSE_FUNCTION_ISOCOMPRESS - - PrintLog("CDVDiso compress: OpenForRead()"); - -#endif /* VERBOSE_FUNCTION_ISOCOMPRESS */ - - - - switch(isofile->compress) { - - case 1: - - retval = GZipV1OpenForRead(isofile); - - if(retval >= 0) retval = GZipV1OpenTableForRead(isofile); - - break; - - case 2: - - retval = BlockV2OpenForRead(isofile); - - if(retval >= 0) retval = BlockV2OpenTableForRead(isofile); - - break; - - case 3: - - retval = GZipV2OpenForRead(isofile); - - if(retval >= 0) retval = GZipV2OpenTableForRead(isofile); - - break; - - case 4: - - retval = BZip2V2OpenForRead(isofile); - - if(retval >= 0) retval = BZip2V2OpenTableForRead(isofile); - - break; - - case 5: - - retval = BZip2V3OpenForRead(isofile); - - if(retval >= 0) retval = BZip2V3OpenTableForRead(isofile); - - break; - - default: - - retval = -1; - - break; - - } // ENDSWITCH compress- which method do we try to get header info from? - - - - return(retval); - -} // END CompressOpenForRead() - - - - - -int CompressSeek(struct IsoFile *isofile, off64_t sector) { - - int retval; - - - -#ifdef VERBOSE_FUNCTION_ISOCOMPRESS - - PrintLog("CDVDiso compress: Seek(%lli)", sector); - -#endif /* VERBOSE_FUNCTION_ISOCOMPRESS */ - - - - switch(isofile->compress) { - - case 1: - - retval = GZipV1SeekTable(isofile, sector); - - break; - - case 2: - - retval = BlockV2SeekTable(isofile, sector); - - break; - - case 3: - - retval = GZipV2SeekTable(isofile, sector); - - break; - - case 4: - - retval = BZip2V2SeekTable(isofile, sector); - - break; - - case 5: - - retval = BZip2V3SeekTable(isofile, sector); - - break; - - default: - - retval = -1; - - break; - - } // ENDSWITCH compress- which method do we try to get header info from? - - - - return(retval); - -} // END CompressSeek() - - - - - -int CompressRead(struct IsoFile *isofile, char *buffer) { - - struct TableData table; - - int retval; - - int compptr; - - int i; - - - -#ifdef VERBOSE_FUNCTION_ISOCOMPRESS - - PrintLog("CDVDiso compress: Read()"); - -#endif /* VERBOSE_FUNCTION_ISOCOMPRESS */ - - - - switch(isofile->compress) { - - case 1: - - retval = GZipV1ReadTable(isofile, &table); - - if(retval >= 0) { - - if(table.offset != isofile->filebytepos) { - - retval = GZipV1Seek(isofile, table.offset); - - } // ENDIF- The data file not in position? - - } // ENDIF- Did we get a table entry? - - if(retval >= 0) { - - retval = GZipV1Read(isofile, table.size, buffer); - - } // ENDIF- Are we still on track? - - break; - - - - case 2: - - retval = BlockV2ReadTable(isofile, &table); - - if(retval >= 0) { - - if(table.offset != isofile->filebytepos) { - - retval = BlockV2Seek(isofile, table.offset); - - } // ENDIF- The data file not in position? - - } // ENDIF- Did we get a table entry? - - if(retval >= 0) { - - retval = BlockV2Read(isofile, table.size, buffer); - - } // ENDIF- Are we still on track? - - break; - - - - - - case 3: - - retval = GZipV2ReadTable(isofile, &table); - - if(retval >= 0) { - - if(table.offset != isofile->filebytepos) { - - retval = GZipV2Seek(isofile, table.offset); - - } // ENDIF- The data file not in position? - - } // ENDIF- Did we get a table entry? - - if(retval >= 0) { - - retval = GZipV2Read(isofile, table.size, buffer); - - } // ENDIF- Are we still on track? - - break; - - - - case 4: - - retval = 0; - - if((isofile->filesectorpos < isofile->compsector) || - - (isofile->filesectorpos > isofile->compsector + isofile->numsectors - 1)) { - - - - retval = BZip2V2ReadTable(isofile, &table); - - if(retval >= 0) { - - if(table.offset != isofile->filebytepos) { - - retval = BZip2V2Seek(isofile, table.offset); - - } // ENDIF- The data file not in position? - - } // ENDIF- Did we get a table entry? - - if(retval >= 0) { - - retval = BZip2V2Read(isofile, table.size, isofile->compblock); - - isofile->compsector = isofile->filesectorpos / isofile->numsectors; - - isofile->compsector *= isofile->numsectors; - - } // ENDIF- Are we still on track? - - } // ENDIF- Did we have to read in another block? - - - - if(retval >= 0) { - - compptr = isofile->filesectorpos - isofile->compsector; - - compptr *= isofile->blocksize; - - if((compptr < 0) || (compptr > (65535 - isofile->blocksize))) { - - retval = -1; - - } else { - - for(i = 0; i < isofile->blocksize; i++) - - *(buffer + i) = isofile->compblock[compptr + i]; - - isofile->filesectorpos++; - - } // ENDIF- Not a good buffer pointer? Say so. - - } // ENDIF- Do we have a valid buffer to draw from? - - break; - - - - case 5: - - retval = 0; - - if((isofile->filesectorpos < isofile->compsector) || - - (isofile->filesectorpos > isofile->compsector + isofile->numsectors - 1)) { - - - - if(isofile->filesectorpos != isofile->compsector + isofile->numsectors) { - - retval = BZip2V3ReadTable(isofile, &table); - - if(retval >= 0) { - - if(table.offset != isofile->filebytepos) { - - retval = BZip2V3Seek(isofile, table.offset); - - } // ENDIF- The data file not in position? - - } // ENDIF- Did we get a table entry? - - } // ENDIF- Not the next block in the batch? Seek then. - - - - if(retval >= 0) { - - retval = BZip2V3Read(isofile, 0, isofile->compblock); - - isofile->compsector = isofile->filesectorpos / isofile->numsectors; - - isofile->compsector *= isofile->numsectors; - - } // ENDIF- Are we still on track? - - } // ENDIF- Did we have to read in another block? - - - - if(retval >= 0) { - - compptr = isofile->filesectorpos - isofile->compsector; - - compptr *= isofile->blocksize; - - if((compptr < 0) || (compptr > (65535 - isofile->blocksize))) { - - retval = -1; - - } else { - - for(i = 0; i < isofile->blocksize; i++) - - *(buffer + i) = isofile->compblock[compptr + i]; - - isofile->filesectorpos++; - - } // ENDIF- Not a good buffer pointer? Say so. - - } // ENDIF- Do we have a valid buffer to draw from? - - break; - - - - default: - - retval = -1; - - break; - - } // ENDSWITCH compress- which method do we try to get header info from? - - - - if(retval >= 0) retval = isofile->blocksize; - - return(retval); - -} // END CompressRead() - - - - - -void CompressClose(struct IsoFile *isofile) { - - int retval; - - - -#ifdef VERBOSE_FUNCTION_ISOCOMPRESS - - PrintLog("CDVDiso compress: Close()"); - -#endif /* VERBOSE_FUNCTION_ISOCOMPRESS */ - - - - switch(isofile->compress) { - - case 1: - - GZipV1Close(isofile); - - break; - - case 2: - - BlockV2Close(isofile); - - break; - - case 3: - - GZipV2Close(isofile); - - break; - - case 4: - - BZip2V2Close(isofile); - - break; - - case 5: - - BZip2V3Close(isofile); - - break; - - default: - - retval = -1; - - break; - - } // ENDSWITCH compress- which method do we try to get header info from? - - - - return; - -} // END CompressClose() - - - - - -int CompressOpenForWrite(struct IsoFile *isofile) { - - int retval; - - - -#ifdef VERBOSE_FUNCTION_ISOCOMPRESS - - PrintLog("CDVDiso compress: OpenForWrite()"); - -#endif /* VERBOSE_FUNCTION_ISOCOMPRESS */ - - - - switch(isofile->compress) { - - case 1: - - retval = GZipV1OpenForWrite(isofile); - - if(retval >= 0) retval = GZipV1OpenTableForWrite(isofile); - - break; - - case 2: - - retval = -1; - - break; - - case 3: - - retval = GZipV2OpenForWrite(isofile); - - if(retval >= 0) retval = GZipV2OpenTableForWrite(isofile); - - break; - - case 4: - - retval = BZip2V2OpenForWrite(isofile); - - if(retval >= 0) retval = BZip2V2OpenTableForWrite(isofile); - - break; - - case 5: - - retval = BZip2V3OpenForWrite(isofile); - - if(retval >= 0) retval = BZip2V3OpenTableForWrite(isofile); - - break; - - default: - - retval = -1; - - break; - - } // ENDSWITCH compress- which method do we try to get header info from? - - - - return(retval); - -} // END CompressOpenForWrite() - - - - - -int CompressWrite(struct IsoFile *isofile, char *buffer) { - - struct TableData table; - - int compptr; - - int retval; - - int i; - - - -#ifdef VERBOSE_FUNCTION_ISOCOMPRESS - - PrintLog("CDVDiso compress: Write()"); - -#endif /* VERBOSE_FUNCTION_ISOCOMPRESS */ - - - - switch(isofile->compress) { - - case 1: - - retval = GZipV1Write(isofile, buffer); - - if(retval > 0) { - - table.offset = isofile->filebytepos - retval; - - table.size = retval; - - retval = GZipV1WriteTable(isofile, table); - - } // ENDIF- Wrote the data out? Update the table as well. - - break; - - - - case 2: - - retval = -1; - - break; - - - - case 3: - - retval = GZipV2Write(isofile, buffer); - - if(retval > 0) { - - table.offset = isofile->filebytepos - retval; - - table.size = retval; - - retval = GZipV2WriteTable(isofile, table); - - } // ENDIF- Wrote the data out? Update the table as well. - - break; - - - - case 4: - - retval = 0; - - if((isofile->filesectorpos < isofile->compsector) || - - (isofile->filesectorpos > isofile->compsector + isofile->numsectors - 1)) { - - retval = BZip2V2Write(isofile, isofile->compblock); - - isofile->compsector += isofile->numsectors; - - if(retval > 0) { - - table.offset = isofile->filebytepos - retval; - - table.size = retval; - - retval = BZip2V2WriteTable(isofile, table); - - } // ENDIF- Wrote the data out? Update the table as well. - - } // ENDIF- Do we have a full buffer to write out? - - - - if(retval >= 0) { - - compptr = isofile->filesectorpos - isofile->compsector; - - compptr *= isofile->blocksize; - - for(i = 0; i < isofile->blocksize; i++) - - isofile->compblock[compptr + i] = *(buffer + i); - - } // ENDIF- Do we have a valid buffer to draw from? - - isofile->filesectorpos++; - - break; - - - - case 5: - - retval = 0; - - if((isofile->filesectorpos < isofile->compsector) || - - (isofile->filesectorpos > isofile->compsector + isofile->numsectors - 1)) { - - retval = BZip2V3Write(isofile, isofile->compblock); - - isofile->compsector += isofile->numsectors; - - if(retval > 0) { - - table.offset = isofile->filebytepos - retval; - - table.size = retval; - - retval = BZip2V3WriteTable(isofile, table); - - } // ENDIF- Wrote the data out? Update the table as well. - - } // ENDIF- Do we have a full buffer to write out? - - - - if(retval >= 0) { - - compptr = isofile->filesectorpos - isofile->compsector; - - compptr *= isofile->blocksize; - - for(i = 0; i < isofile->blocksize; i++) - - isofile->compblock[compptr + i] = *(buffer + i); - - } // ENDIF- Do we have a valid buffer to draw from? - - isofile->filesectorpos++; - - break; - - - - default: - - retval = -1; - - break; - - } // ENDSWITCH compress- which method do we try to get header info from? - - - - if(retval >= 0) retval = isofile->blocksize; - - return(retval); - -} // END CompressWrite() - +/* isocompress.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + + + +// #ifndef __LINUX__ + +// #ifdef __linux__ + +// #define __LINUX__ + +// #endif /* __linux__ */ + +// #endif /* No __LINUX__ */ + + + +// #define CDVDdefs + +// #include "PS2Edefs.h" + + + +#include "logfile.h" + +#include "isofile.h" + +#include "actualfile.h" + +#include "gzipv1.h" + +#include "blockv2.h" + +#include "gzipv2.h" + +#include "bzip2v2.h" + +#include "bzip2v3.h" + +#include "isocompress.h" + + + + + +const char *compressnames[] = { + + "No Compression", + + ".Z (zlib) for speed", + + ".BZ2 (bzip2) for speed", + + ".bz2 (bzip2) for size", + + NULL }; // Compress types 0, 3, 4, and 5 + + + +const char *compressdesc[] = { + + "", + + " zlib orig", + + " block.dump", + + " zlib speed", + + " bzip2 speed", + + " bzip2 size", + + NULL }; + + + +const char *compressid[] = { + + "BVD2", + + "Z V2", + + "BZV2", + + "BZV3", + + NULL }; // Starts at compress type 2 + + + +struct CompressExt compressext[] = { + + { ".z", 1 }, + + { ".Z", 1 }, + + { ".bz2", 5 }, + + { ".BZ2", 3 }, + + { ".bZ2", 3 }, + + { ".Bz2", 3 }, + + { ".bz", 3 }, + + { ".BZ", 3 }, + + { ".bZ", 3 }, + + { ".Bz", 3 }, + + { ".dump", 2 }, + + { NULL, 0 } + +}; + + + + + +int IsoNameStripCompress(struct IsoFile *isofile) { + + int tempext; + + int tempnamepos; + + int tempextpos; + + int retmethod; + + + + retmethod = 0; + + tempext = 0; + + while(compressext[tempext].name != NULL) { + + tempextpos = 0; + + while(*(compressext[tempext].name + tempextpos) != 0) tempextpos++; + + + + tempnamepos = isofile->namepos; + + while((tempnamepos > 0) && (tempextpos > 0) && + + (isofile->name[tempnamepos - 1] == *(compressext[tempext].name + tempextpos - 1))) { + + tempnamepos--; + + tempextpos--; + + } // ENDWHILE- Comparing one extension to the end of the file name + + if(tempextpos == 0) { + + isofile->namepos = tempnamepos; // Move name pointer in front of ext. + + return(compressext[tempext].method); // Found a match... say which one. + + } else { + + tempext++; // Next ext in the list to test... + + } // ENDIF- Did we find a match? + + } // ENDWHILE- looking through extension list + + + + return(0); // No compress extension found. + +} // END IsoNameStripCompress() + + + + + +int CompressOpenForRead(struct IsoFile *isofile) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_ISOCOMPRESS + + PrintLog("CDVDiso compress: OpenForRead()"); + +#endif /* VERBOSE_FUNCTION_ISOCOMPRESS */ + + + + switch(isofile->compress) { + + case 1: + + retval = GZipV1OpenForRead(isofile); + + if(retval >= 0) retval = GZipV1OpenTableForRead(isofile); + + break; + + case 2: + + retval = BlockV2OpenForRead(isofile); + + if(retval >= 0) retval = BlockV2OpenTableForRead(isofile); + + break; + + case 3: + + retval = GZipV2OpenForRead(isofile); + + if(retval >= 0) retval = GZipV2OpenTableForRead(isofile); + + break; + + case 4: + + retval = BZip2V2OpenForRead(isofile); + + if(retval >= 0) retval = BZip2V2OpenTableForRead(isofile); + + break; + + case 5: + + retval = BZip2V3OpenForRead(isofile); + + if(retval >= 0) retval = BZip2V3OpenTableForRead(isofile); + + break; + + default: + + retval = -1; + + break; + + } // ENDSWITCH compress- which method do we try to get header info from? + + + + return(retval); + +} // END CompressOpenForRead() + + + + + +int CompressSeek(struct IsoFile *isofile, off64_t sector) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_ISOCOMPRESS + + PrintLog("CDVDiso compress: Seek(%lli)", sector); + +#endif /* VERBOSE_FUNCTION_ISOCOMPRESS */ + + + + switch(isofile->compress) { + + case 1: + + retval = GZipV1SeekTable(isofile, sector); + + break; + + case 2: + + retval = BlockV2SeekTable(isofile, sector); + + break; + + case 3: + + retval = GZipV2SeekTable(isofile, sector); + + break; + + case 4: + + retval = BZip2V2SeekTable(isofile, sector); + + break; + + case 5: + + retval = BZip2V3SeekTable(isofile, sector); + + break; + + default: + + retval = -1; + + break; + + } // ENDSWITCH compress- which method do we try to get header info from? + + + + return(retval); + +} // END CompressSeek() + + + + + +int CompressRead(struct IsoFile *isofile, char *buffer) { + + struct TableData table; + + int retval; + + int compptr; + + int i; + + + +#ifdef VERBOSE_FUNCTION_ISOCOMPRESS + + PrintLog("CDVDiso compress: Read()"); + +#endif /* VERBOSE_FUNCTION_ISOCOMPRESS */ + + + + switch(isofile->compress) { + + case 1: + + retval = GZipV1ReadTable(isofile, &table); + + if(retval >= 0) { + + if(table.offset != isofile->filebytepos) { + + retval = GZipV1Seek(isofile, table.offset); + + } // ENDIF- The data file not in position? + + } // ENDIF- Did we get a table entry? + + if(retval >= 0) { + + retval = GZipV1Read(isofile, table.size, buffer); + + } // ENDIF- Are we still on track? + + break; + + + + case 2: + + retval = BlockV2ReadTable(isofile, &table); + + if(retval >= 0) { + + if(table.offset != isofile->filebytepos) { + + retval = BlockV2Seek(isofile, table.offset); + + } // ENDIF- The data file not in position? + + } // ENDIF- Did we get a table entry? + + if(retval >= 0) { + + retval = BlockV2Read(isofile, table.size, buffer); + + } // ENDIF- Are we still on track? + + break; + + + + + + case 3: + + retval = GZipV2ReadTable(isofile, &table); + + if(retval >= 0) { + + if(table.offset != isofile->filebytepos) { + + retval = GZipV2Seek(isofile, table.offset); + + } // ENDIF- The data file not in position? + + } // ENDIF- Did we get a table entry? + + if(retval >= 0) { + + retval = GZipV2Read(isofile, table.size, buffer); + + } // ENDIF- Are we still on track? + + break; + + + + case 4: + + retval = 0; + + if((isofile->filesectorpos < isofile->compsector) || + + (isofile->filesectorpos > isofile->compsector + isofile->numsectors - 1)) { + + + + retval = BZip2V2ReadTable(isofile, &table); + + if(retval >= 0) { + + if(table.offset != isofile->filebytepos) { + + retval = BZip2V2Seek(isofile, table.offset); + + } // ENDIF- The data file not in position? + + } // ENDIF- Did we get a table entry? + + if(retval >= 0) { + + retval = BZip2V2Read(isofile, table.size, isofile->compblock); + + isofile->compsector = isofile->filesectorpos / isofile->numsectors; + + isofile->compsector *= isofile->numsectors; + + } // ENDIF- Are we still on track? + + } // ENDIF- Did we have to read in another block? + + + + if(retval >= 0) { + + compptr = isofile->filesectorpos - isofile->compsector; + + compptr *= isofile->blocksize; + + if((compptr < 0) || (compptr > (65535 - isofile->blocksize))) { + + retval = -1; + + } else { + + for(i = 0; i < isofile->blocksize; i++) + + *(buffer + i) = isofile->compblock[compptr + i]; + + isofile->filesectorpos++; + + } // ENDIF- Not a good buffer pointer? Say so. + + } // ENDIF- Do we have a valid buffer to draw from? + + break; + + + + case 5: + + retval = 0; + + if((isofile->filesectorpos < isofile->compsector) || + + (isofile->filesectorpos > isofile->compsector + isofile->numsectors - 1)) { + + + + if(isofile->filesectorpos != isofile->compsector + isofile->numsectors) { + + retval = BZip2V3ReadTable(isofile, &table); + + if(retval >= 0) { + + if(table.offset != isofile->filebytepos) { + + retval = BZip2V3Seek(isofile, table.offset); + + } // ENDIF- The data file not in position? + + } // ENDIF- Did we get a table entry? + + } // ENDIF- Not the next block in the batch? Seek then. + + + + if(retval >= 0) { + + retval = BZip2V3Read(isofile, 0, isofile->compblock); + + isofile->compsector = isofile->filesectorpos / isofile->numsectors; + + isofile->compsector *= isofile->numsectors; + + } // ENDIF- Are we still on track? + + } // ENDIF- Did we have to read in another block? + + + + if(retval >= 0) { + + compptr = isofile->filesectorpos - isofile->compsector; + + compptr *= isofile->blocksize; + + if((compptr < 0) || (compptr > (65535 - isofile->blocksize))) { + + retval = -1; + + } else { + + for(i = 0; i < isofile->blocksize; i++) + + *(buffer + i) = isofile->compblock[compptr + i]; + + isofile->filesectorpos++; + + } // ENDIF- Not a good buffer pointer? Say so. + + } // ENDIF- Do we have a valid buffer to draw from? + + break; + + + + default: + + retval = -1; + + break; + + } // ENDSWITCH compress- which method do we try to get header info from? + + + + if(retval >= 0) retval = isofile->blocksize; + + return(retval); + +} // END CompressRead() + + + + + +void CompressClose(struct IsoFile *isofile) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_ISOCOMPRESS + + PrintLog("CDVDiso compress: Close()"); + +#endif /* VERBOSE_FUNCTION_ISOCOMPRESS */ + + + + switch(isofile->compress) { + + case 1: + + GZipV1Close(isofile); + + break; + + case 2: + + BlockV2Close(isofile); + + break; + + case 3: + + GZipV2Close(isofile); + + break; + + case 4: + + BZip2V2Close(isofile); + + break; + + case 5: + + BZip2V3Close(isofile); + + break; + + default: + + retval = -1; + + break; + + } // ENDSWITCH compress- which method do we try to get header info from? + + + + return; + +} // END CompressClose() + + + + + +int CompressOpenForWrite(struct IsoFile *isofile) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_ISOCOMPRESS + + PrintLog("CDVDiso compress: OpenForWrite()"); + +#endif /* VERBOSE_FUNCTION_ISOCOMPRESS */ + + + + switch(isofile->compress) { + + case 1: + + retval = GZipV1OpenForWrite(isofile); + + if(retval >= 0) retval = GZipV1OpenTableForWrite(isofile); + + break; + + case 2: + + retval = -1; + + break; + + case 3: + + retval = GZipV2OpenForWrite(isofile); + + if(retval >= 0) retval = GZipV2OpenTableForWrite(isofile); + + break; + + case 4: + + retval = BZip2V2OpenForWrite(isofile); + + if(retval >= 0) retval = BZip2V2OpenTableForWrite(isofile); + + break; + + case 5: + + retval = BZip2V3OpenForWrite(isofile); + + if(retval >= 0) retval = BZip2V3OpenTableForWrite(isofile); + + break; + + default: + + retval = -1; + + break; + + } // ENDSWITCH compress- which method do we try to get header info from? + + + + return(retval); + +} // END CompressOpenForWrite() + + + + + +int CompressWrite(struct IsoFile *isofile, char *buffer) { + + struct TableData table; + + int compptr; + + int retval; + + int i; + + + +#ifdef VERBOSE_FUNCTION_ISOCOMPRESS + + PrintLog("CDVDiso compress: Write()"); + +#endif /* VERBOSE_FUNCTION_ISOCOMPRESS */ + + + + switch(isofile->compress) { + + case 1: + + retval = GZipV1Write(isofile, buffer); + + if(retval > 0) { + + table.offset = isofile->filebytepos - retval; + + table.size = retval; + + retval = GZipV1WriteTable(isofile, table); + + } // ENDIF- Wrote the data out? Update the table as well. + + break; + + + + case 2: + + retval = -1; + + break; + + + + case 3: + + retval = GZipV2Write(isofile, buffer); + + if(retval > 0) { + + table.offset = isofile->filebytepos - retval; + + table.size = retval; + + retval = GZipV2WriteTable(isofile, table); + + } // ENDIF- Wrote the data out? Update the table as well. + + break; + + + + case 4: + + retval = 0; + + if((isofile->filesectorpos < isofile->compsector) || + + (isofile->filesectorpos > isofile->compsector + isofile->numsectors - 1)) { + + retval = BZip2V2Write(isofile, isofile->compblock); + + isofile->compsector += isofile->numsectors; + + if(retval > 0) { + + table.offset = isofile->filebytepos - retval; + + table.size = retval; + + retval = BZip2V2WriteTable(isofile, table); + + } // ENDIF- Wrote the data out? Update the table as well. + + } // ENDIF- Do we have a full buffer to write out? + + + + if(retval >= 0) { + + compptr = isofile->filesectorpos - isofile->compsector; + + compptr *= isofile->blocksize; + + for(i = 0; i < isofile->blocksize; i++) + + isofile->compblock[compptr + i] = *(buffer + i); + + } // ENDIF- Do we have a valid buffer to draw from? + + isofile->filesectorpos++; + + break; + + + + case 5: + + retval = 0; + + if((isofile->filesectorpos < isofile->compsector) || + + (isofile->filesectorpos > isofile->compsector + isofile->numsectors - 1)) { + + retval = BZip2V3Write(isofile, isofile->compblock); + + isofile->compsector += isofile->numsectors; + + if(retval > 0) { + + table.offset = isofile->filebytepos - retval; + + table.size = retval; + + retval = BZip2V3WriteTable(isofile, table); + + } // ENDIF- Wrote the data out? Update the table as well. + + } // ENDIF- Do we have a full buffer to write out? + + + + if(retval >= 0) { + + compptr = isofile->filesectorpos - isofile->compsector; + + compptr *= isofile->blocksize; + + for(i = 0; i < isofile->blocksize; i++) + + isofile->compblock[compptr + i] = *(buffer + i); + + } // ENDIF- Do we have a valid buffer to draw from? + + isofile->filesectorpos++; + + break; + + + + default: + + retval = -1; + + break; + + } // ENDSWITCH compress- which method do we try to get header info from? + + + + if(retval >= 0) retval = isofile->blocksize; + + return(retval); + +} // END CompressWrite() + diff --git a/plugins/CDVDisoEFP/src/isocompress.h b/plugins/CDVDisoEFP/src/isocompress.h index f566d0f43c..f7fecfd6b9 100644 --- a/plugins/CDVDisoEFP/src/isocompress.h +++ b/plugins/CDVDisoEFP/src/isocompress.h @@ -1,158 +1,158 @@ -/* isocompress.h - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#ifndef ISOCOMPRESS_H - -#define ISOCOMPRESS_H - - - - - -#include - - - -#include "isofile.h" - -#include "actualfile.h" - - - - - -// #define VERBOSE_FUNCTION_ISOCOMPRESS - -// #define VERBOSE_WARNING_ISOCOMPRESS - - - - - -struct CompressExt { - - const char *name; - - int method; - -}; - - - -#ifdef _WIN32 - -#pragma pack(1) - -#endif /* _WIN32 */ - - - -struct TableData { - - off64_t offset; - - unsigned short size; - -#ifdef _WIN32 - -}; - -#else - -} __attribute__ ((packed)); - -#endif /* _WIN32 */ - - - -union TableMap { - - struct TableData table; - - char ch[sizeof(struct TableData)]; - -}; - - - - - -extern const char *compressnames[]; - -extern const char *compressdesc[]; - - - -extern struct CompressExt compressext[]; - - - - - -extern int IsoNameStripCompress(struct IsoFile *isofile); - - - -// 0 = success, -1 = Failure w/data, -2 = Failure w/table - -extern int CompressOpenForRead(struct IsoFile *isofile); - - - -extern int CompressSeek(struct IsoFile *isofile, off64_t sector); - -extern int CompressRead(struct IsoFile *isofile, char *buffer); - -extern void CompressClose(struct IsoFile *isofile); - - - -extern int CompressOpenForWrite(struct IsoFile *isofile); - -extern int CompressWrite(struct IsoFile *isofile, char *buffer); - - - - - -#endif /* ISOCOMPRESS_H */ - +/* isocompress.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef ISOCOMPRESS_H + +#define ISOCOMPRESS_H + + + + + +#include + + + +#include "isofile.h" + +#include "actualfile.h" + + + + + +// #define VERBOSE_FUNCTION_ISOCOMPRESS + +// #define VERBOSE_WARNING_ISOCOMPRESS + + + + + +struct CompressExt { + + const char *name; + + int method; + +}; + + + +#ifdef _WIN32 + +#pragma pack(1) + +#endif /* _WIN32 */ + + + +struct TableData { + + off64_t offset; + + unsigned short size; + +#ifdef _WIN32 + +}; + +#else + +} __attribute__ ((packed)); + +#endif /* _WIN32 */ + + + +union TableMap { + + struct TableData table; + + char ch[sizeof(struct TableData)]; + +}; + + + + + +extern const char *compressnames[]; + +extern const char *compressdesc[]; + + + +extern struct CompressExt compressext[]; + + + + + +extern int IsoNameStripCompress(struct IsoFile *isofile); + + + +// 0 = success, -1 = Failure w/data, -2 = Failure w/table + +extern int CompressOpenForRead(struct IsoFile *isofile); + + + +extern int CompressSeek(struct IsoFile *isofile, off64_t sector); + +extern int CompressRead(struct IsoFile *isofile, char *buffer); + +extern void CompressClose(struct IsoFile *isofile); + + + +extern int CompressOpenForWrite(struct IsoFile *isofile); + +extern int CompressWrite(struct IsoFile *isofile, char *buffer); + + + + + +#endif /* ISOCOMPRESS_H */ + diff --git a/plugins/CDVDisoEFP/src/isofile.c b/plugins/CDVDisoEFP/src/isofile.c index a655b597d2..5122c58c41 100644 --- a/plugins/CDVDisoEFP/src/isofile.c +++ b/plugins/CDVDisoEFP/src/isofile.c @@ -1,1292 +1,1292 @@ -/* isofile.c - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#include // NULL - -#include // malloc() - -#include // off64_t - - - -#ifndef __LINUX__ - -#ifdef __linux__ - -#define __LINUX__ - -#endif /* __linux__ */ - -#endif /* No __LINUX__ */ - -#define CDVDdefs - -#include "PS2Edefs.h" - - - -#include "logfile.h" - -#include "multifile.h" - -#include "isocompress.h" - -#include "actualfile.h" - -#include "imagetype.h" - -#include "toc.h" - -#include "ecma119.h" - -#include "isofile.h" - - - - - -const char *isofileext[] = { - - ".iso", - - ".bin", - - ".img", - - NULL - -}; - - - -const char *cdname = "CD-XA001\0"; - -const char *playstationid = "PLAYSTATION\0"; - -// const char ps1/2name? - - - -// Internal functions - - - -void IsoNameStripExt(struct IsoFile *isofile) { - - int tempext; - - int tempnamepos; - - int tempextpos; - - - - tempext = 0; - - while(isofileext[tempext] != NULL) { - - tempextpos = 0; - - while(*(isofileext[tempext] + tempextpos) != 0) tempextpos++; - - - - tempnamepos = isofile->namepos; - - while((tempnamepos > 0) && (tempextpos > 0) && - - (isofile->name[tempnamepos - 1] == *(isofileext[tempext] + tempextpos - 1))) { - - tempnamepos--; - - tempextpos--; - - } // ENDWHILE- Comparing one extension to the end of the file name - - if(tempextpos == 0) { - - isofile->namepos = tempnamepos; // Move name pointer in front of ext. - - tempext = 0; // ... and test the list all over again. - - } else { - - tempext++; // Next ext in the list to test... - - } // ENDIF- Did we find a match? - - } // ENDWHILE- looking through extension list - -} // END IsoNameStripExt() - - - - - -// External functions - - - -struct IsoFile *IsoFileOpenForRead(const char *filename) { - - struct IsoFile *newfile; - - int retval; - - int i; - - char tempblock[2448]; - - struct tocTN toctn; - - struct tocTD toctd; - -// union { - -// struct ECMA119PrimaryVolume vol; - -// char ch[sizeof(struct ECMA119PrimaryVolume)]; - -// } *volcheck; - - union { - - struct ECMA119PrimaryVolume *vol; - - char *ch; - - } volcheck; - - - - newfile = NULL; - - - - if(filename == NULL) return(NULL); - - - -#ifdef VERBOSE_FUNCTION_ISOFILE - - PrintLog("CDVD isofile: IsoFileOpenForRead(%s)", filename); - -#endif /* VERBOSE_FUNCTION_ISOFILE */ - - - - newfile = (struct IsoFile *) malloc(sizeof(struct IsoFile)); - - if(newfile == NULL) return(NULL); - - - - newfile->sectorpos = 0; - - newfile->openforread = 1; // Read-only ISO - - newfile->filebytepos = 0; - - newfile->filesectorpos = 0; - - newfile->blocksize = 0; // Flags as non-detected yet (Compress vs. Image) - - newfile->tabledata = NULL; - - - - newfile->namepos = 0; - - while((newfile->namepos < 255) && - - (*(filename + newfile->namepos) != 0)) { - - newfile->name[newfile->namepos] = *(filename + newfile->namepos); - - newfile->namepos++; - - } // ENDWHILE- copying the file name in... - - newfile->name[newfile->namepos] = 0; // And 0-terminate. - - - - IsoNameStripExt(newfile); // Ex: -I00.Z[.bin] - - - - // File Compression name detection - - newfile->compress = IsoNameStripCompress(newfile); // Ex: -I00.bin[.Z] - - newfile->compresspos = newfile->namepos; - - - - // Test File name compression - - retval = -1; - - if(newfile->compress > 0) { - - retval = CompressOpenForRead(newfile); - - if(retval == -1) CompressClose(newfile); - - } // ENDIF- Have a compression type hint? Test it out - - - - if(retval == -1) { - - newfile->compress = 5; - - while((newfile->compress > 0) && (retval == -1)) { - - retval = CompressOpenForRead(newfile); - - if(retval == -1) { - - CompressClose(newfile); - - newfile->compress--; - - } // ENDIF- Failed to open? Close it... and try the next one. - - } // ENDWHILE- Trying to find a compression scheme that will work... - - - - if(newfile->compress == 0) { - - newfile->handle = ActualFileOpenForRead(newfile->name); - - if(newfile->handle == ACTUALHANDLENULL) { - - free(newfile); - - newfile = NULL; - - return(NULL); - - } // ENDIF- Failed to open? Abort. - - newfile->filebytesize = ActualFileSize(newfile->handle); - - } // ENDIF- No compression? Open it uncompressed. - - } // ENDIF- Temp- failed to open? Abort... - - - - // Compressed data file with no table? Return prematurely... - - // Condition detection: compress > 0, tablehandle == ACTUALHANDLENULL - - if(retval == -2) { - -#ifdef VERBOSE_FUNCTION_ISOFILE - - PrintLog("CDVD isofile: Data file with no table!"); - -#endif /* VERBOSE_FUNCTION_ISOFILE */ - - return(newfile); - - } // ENDIF- - - - - newfile->imagetype = DetectImageType(newfile); - - - - if(newfile->compress == 0) { - - newfile->filesectorsize = newfile->filebytesize / newfile->blocksize; - - } // ENDIF- Now that blocksize is known, raw file sectors can be figured out - - - - IsoNameStripExt(newfile); // Ex: -I00[.bin].Z - - - - IsoNameStripMulti(newfile); // Ex: [-I00].bin.Z - - - -#ifdef VERBOSE_DISC_INFO - - PrintLog("CDVD isofile: Filename: %s", filename); - - if(newfile->multi > 0) PrintLog("CDVD isofile: Multiple <2GB files."); - - PrintLog("CDVD isofile: Compression Method: %s", - - compressdesc[newfile->compress]); - - PrintLog("CDVD isofile: Image Type: %s", - - newfile->imagename); - - PrintLog("CDVD isofile: Block Size: %lli", newfile->blocksize); - - PrintLog("CDVD isofile: Total Sectors (of first file): %lli", - - newfile->filesectorsize); - -#endif /* VERBOSE_DISC_INFO */ - - - - // Load a TOC from a .toc file (is there is one) - - retval = IsoLoadTOC(newfile); - - if(retval == 0) return(newfile); - - - - // Get the volume sector for disc type test - - retval = IsoFileSeek(newfile, 16); - - if(retval < 0) { - - newfile = IsoFileClose(newfile); - - return(NULL); - - } // ENDIF- Could not find the directory sector? Abort. - - retval = IsoFileRead(newfile, tempblock); - - if(retval < 0) { - - newfile = IsoFileClose(newfile); - - return(NULL); - - } // ENDIF- Could not read the directory sector? Abort. - - - - volcheck.ch = tempblock; - - volcheck.ch += newfile->blockoffset; - - if(ValidateECMA119PrimaryVolume(volcheck.vol) != 0) { - -#ifdef VERBOSE_DISC_INFO - - PrintLog("CDVD isofile: Not an ISO9660 disc! Music CD perhaps?"); - -#endif /* VERBOSE_DISC_INFO */ - - newfile->cdvdtype = CDVD_TYPE_CDDA; - - - - } else { - - // Is this a playstation image? - - i = 0; - - while((*(playstationid + i) != 0) && - - (*(playstationid + i) == tempblock[newfile->blockoffset + 8 + i])) i++; - - if(*(playstationid + i) != 0) { - -#ifdef VERBOSE_DISC_INFO - - PrintLog("CDVD isofile: Not a Playstation Disc!"); - -#endif /* VERBOSE_DISC_INFO */ - - newfile->cdvdtype = CDVD_TYPE_DVDV; - - } else { - - newfile->cdvdtype = CDVD_TYPE_PS2DVD; - - } // ENDIF- Is this not a Playstation 1 image? - - // Sidenote: if the emulator is just playing Playstation 2 images, we could - - // just invalidate the image file right here. - - } // ENDIF- Not an ISO9660 disc? Assume Music CD. - - - - if(newfile->cdvdtype == CDVD_TYPE_PS2DVD) { - - // Is this a Playstation CD image? - - i = 0; - - while((*(cdname + i) != 0) && - - (*(cdname + i) == tempblock[newfile->blockoffset + 1024 + i])) i++; - - if(*(cdname + i) == 0) { - - newfile->cdvdtype = CDVD_TYPE_PSCD; - -#ifdef VERBOSE_DISC_INFO - - PrintLog("CDVD isofile: Image is a Playstation 1 CD."); - -#endif /* VERBOSE_DISC_INFO */ - - } else { - - if(newfile->blocksize != 2048) { - - newfile->cdvdtype = CDVD_TYPE_PS2CD; - -#ifdef VERBOSE_DISC_INFO - - PrintLog("CDVD isofile: Image is a Playstation 2 CD."); - -#endif /* VERBOSE_DISC_INFO */ - - } else { - -#ifdef VERBOSE_DISC_INFO - - PrintLog("CDVD isofile: Image is a DVD."); - -#endif /* VERBOSE_DISC_INFO */ - - } // ENDIF- Is the blocksize not 2048? CD image then. - - } // ENDIF- Is this a PS1 CD image? - - } // ENDIF- Is this a Playstation image? - - volcheck.ch = NULL; - - - - if((newfile->cdvdtype == CDVD_TYPE_DVDV) && - - (newfile->blocksize == 2352)) newfile->cdvdtype = CDVD_TYPE_CDDA; - - - - // Slap together a TOC based on the above guesswork. - - IsoInitTOC(newfile); - - if((newfile->cdvdtype != CDVD_TYPE_PS2DVD) && - - (newfile->cdvdtype != CDVD_TYPE_DVDV)) { - - toctn.strack = 1; - - toctn.etrack = 1; - - IsoAddTNToTOC(newfile, toctn); - - - - toctd.type = 0; - - toctd.lsn = newfile->filesectorsize; - - IsoAddTDToTOC(newfile, 0xAA, toctd); - - - - toctd.type = 0; // ? - - if(newfile->cdvdtype == CDVD_TYPE_CDDA) { - - toctd.type = CDVD_AUDIO_TRACK; // Music track assumed - - } else { - - toctd.type = CDVD_MODE1_TRACK; // Data track assumed - - } // ENDIF- Is this track a music or data track? - - toctd.lsn = 0; - - IsoAddTDToTOC(newfile, 1, toctd); - - } // ENDIF- Is this a CD? Single track for all sectors - - - - return(newfile); - -} // END IsoFileOpenForRead() - - - - - -int IsIsoFile(const char *filename) { - - int retval; - - struct IsoFile *tempfile; - - - -#ifdef VERBOSE_FUNCTION_ISOFILE - - PrintLog("CDVD isofile: IsIsoFile()"); - -#endif /* VERBOSE_FUNCTION_ISOFILE */ - - - - retval = IsActualFile(filename); - - if(retval < 0) return(retval); // Not a regular file? Report it. - - - - tempfile = NULL; - - tempfile = IsoFileOpenForRead(filename); - - if(tempfile == NULL) return(-3); // Not an image file? Report it. - - - - retval = 0; - - if((tempfile->compress > 0) && - - (tempfile->tablehandle == ACTUALHANDLENULL) && - - (tempfile->tabledata == NULL)) retval = -4; - - - - tempfile = IsoFileClose(tempfile); - - return(retval); - -} // END IsIsoFile() - - - - - -int IsoFileSeek(struct IsoFile *file, off64_t sector) { - - int retval; - - - - if(file == NULL) return(-1); - - if(sector < 0) return(-1); - - - - if(sector == file->sectorpos) return(0); - - - -#ifdef VERBOSE_FUNCTION_ISOFILE - - PrintLog("CDVD isofile: IsoFileSeek(%llu)", sector); - -#endif /* VERBOSE_FUNCTION_ISOFILE */ - - - - if(file->multi > 0) { - - retval = MultiFileSeek(file, sector); - - } else if(file->compress > 0) { - - retval = CompressSeek(file, sector); - - } else { - - retval = ActualFileSeek(file->handle, - - (sector * file->blocksize) + file->imageheader); - - if(retval == 0) { - - file->filesectorpos = sector; - - file->filebytepos = (sector * file->blocksize) + file->imageheader; - - } // ENDIF- Succeeded? Adjust internal pointers - - } // ENDLONGIF- Seek right file? Or compressed block? Or Raw block? - - - - if(retval < 0) { - -#ifdef VERBOSE_FUNCTION_ISOFILE - - PrintLog("CDVD isofile: Trouble finding the sector!"); - -#endif /* VERBOSE_FUNCTION_ISOFILE */ - - return(-1); - - } // ENDIF- Trouble reading the block? Say so! - - - - file->sectorpos = sector; - - return(0); - -} // END IsoFileSeek() - - - - - -int IsoFileRead(struct IsoFile *file, char *block) { - - int retval; - - - - if(file == NULL) return(-1); - - if(block == NULL) return(-1); - - if(file->openforread == 0) return(-1); - - - -#ifdef VERBOSE_FUNCTION_ISOFILE - - PrintLog("CDVD isofile: IsoFileRead(%i)", file->blocksize); - -#endif /* VERBOSE_FUNCTION_ISOFILE */ - - - - if(file->multi > 0) { - - retval = MultiFileRead(file, block); - - } else if(file->compress > 0) { - - retval = CompressRead(file, block); - - } else { - - if(file->sectorpos >= file->filesectorsize) return(-1); - - retval = ActualFileRead(file->handle, - - file->blocksize, - - block); - - if(retval > 0) file->filebytepos += retval; - - if(retval == file->blocksize) file->filesectorpos++; - - } // ENDLONGIF- Read right file? Or compressed block? Or Raw block? - - - - if(retval < 0) { - -#ifdef VERBOSE_FUNCTION_ISOFILE - - PrintLog("CDVD isofile: Trouble reading the sector!"); - -#endif /* VERBOSE_FUNCTION_ISOFILE */ - - return(-1); - - } // ENDIF- Trouble reading the block? Say so! - - - - if(retval < file->blocksize) { - -#ifdef VERBOSE_FUNCTION_ISOFILE - - PrintLog("CDVD isofile: Short block! Got %i out of %i bytes", - - retval, file->blocksize); - -#endif /* VERBOSE_FUNCTION_ISOFILE */ - - return(-1); - - } // ENDIF- Didn't get enough bytes? Say so! - - - - file->sectorpos++; - - return(0); - -} // END IsoFileRead() - - - - - -struct IsoFile *IsoFileClose(struct IsoFile *file) { - - if(file == NULL) return(NULL); - - - - if(file->handle != ACTUALHANDLENULL) { - -#ifdef VERBOSE_FUNCTION_ISOFILE - - PrintLog("CDVD isofile: IsoFileClose()"); - -#endif /* VERBOSE_FUNCTION_ISOFILE */ - - - - if(file->compress > 0) { - - CompressClose(file); - - } else { - - ActualFileClose(file->handle); - - file->handle = ACTUALHANDLENULL; - - } // ENDIF- Compressed File? Close (and flush) compression too. - - } // ENDIF- Open Handle? Close the file - - - - free(file); - - return(NULL); - -} // END IsoFileClose() - - - - - -struct IsoFile *IsoFileOpenForWrite(const char *filename, - - int imagetype, - - int multi, - - int compress) { - - struct IsoFile *newfile; - - - - newfile = NULL; - - - - if(filename == NULL) return(NULL); - - if((imagetype < 0) || (imagetype > 11)) return(NULL); - - if((compress < 0) || (compress > 5)) return(NULL); - - - -#ifdef VERBOSE_FUNCTION_ISOFILE - - PrintLog("CDVD isofile: IsoFileOpenForWrite()"); - -#endif /* VERBOSE_FUNCTION_ISOFILE */ - - - - newfile = (struct IsoFile *) malloc(sizeof(struct IsoFile)); - - if(newfile == NULL) return(NULL); - - - - newfile->sectorpos = 0; - - newfile->openforread = 0; // Write-only file - - newfile->filebytesize = 0; - - newfile->filebytepos = 0; - - newfile->filesectorsize = 0; - - newfile->filesectorpos = 0; - - - - // if(toc != NULL) { - - // for(i = 0; i < 2048; i++) newfile->toc[i] = *(toc + i); - - // } else { - - // for(i = 0; i < 2048; i++) newfile->toc[i] = 0; - - // } // ENDIF- Do we have a PS2 Table of Contents to save out as well? - - - - newfile->namepos = 0; - - while((newfile->namepos < 255) && - - (*(filename + newfile->namepos) != 0)) { - - newfile->name[newfile->namepos] = *(filename + newfile->namepos); - - newfile->namepos++; - - } // ENDWHILE- copying the file name in... - - newfile->name[newfile->namepos] = 0; // And 0-terminate. - - - - IsoNameStripExt(newfile); - - IsoNameStripCompress(newfile); - - IsoNameStripExt(newfile); - - IsoNameStripMulti(newfile); - - newfile->name[newfile->namepos] = 0; // And 0-terminate. - - - - newfile->imagetype = imagetype; - - GetImageType(newfile, imagetype); - - newfile->cdvdtype = CDVD_TYPE_PS2DVD; // Does it matter here? Nope. - - - - newfile->multi = multi; - - if(newfile->multi > 0) { - - newfile->name[newfile->namepos + 0] = '-'; - - newfile->name[newfile->namepos + 1] = 'I'; - - newfile->name[newfile->namepos + 2] = '0'; - - newfile->name[newfile->namepos + 3] = '0'; - - newfile->name[newfile->namepos + 4] = 0; - - newfile->multipos = newfile->namepos + 3; - - newfile->namepos += 4; - - newfile->multistart = 0; - - newfile->multiend = 0; - - newfile->multinow = 0; - - newfile->multioffset = 0; - - newfile->multisectorend[0] = 0; - - } // ENDIF- Are we creating a multi-file? - - - - newfile->compress = compress; - - switch(newfile->compress) { - - case 1: - - case 3: - - newfile->name[newfile->namepos + 0] = '.'; - - newfile->name[newfile->namepos + 1] = 'Z'; - - newfile->name[newfile->namepos + 2] = 0; - - newfile->namepos += 2; - - break; - - - - case 2: - - newfile->name[newfile->namepos + 0] = '.'; - - newfile->name[newfile->namepos + 1] = 'd'; - - newfile->name[newfile->namepos + 2] = 'u'; - - newfile->name[newfile->namepos + 3] = 'm'; - - newfile->name[newfile->namepos + 4] = 'p'; - - newfile->name[newfile->namepos + 5] = 0; - - newfile->namepos += 5; - - break; - - - - case 4: - - newfile->name[newfile->namepos + 0] = '.'; - - newfile->name[newfile->namepos + 1] = 'B'; - - newfile->name[newfile->namepos + 2] = 'Z'; - - newfile->name[newfile->namepos + 3] = '2'; - - newfile->name[newfile->namepos + 4] = 0; - - newfile->namepos += 4; - - break; - - - - case 5: - - newfile->name[newfile->namepos + 0] = '.'; - - newfile->name[newfile->namepos + 1] = 'b'; - - newfile->name[newfile->namepos + 2] = 'z'; - - newfile->name[newfile->namepos + 3] = '2'; - - newfile->name[newfile->namepos + 4] = 0; - - newfile->namepos += 4; - - break; - - - - case 0: - - default: - - break; - - } // ENDSWITCH compress- which compression extension should we add on? - - - - newfile->name[newfile->namepos + 0] = '.'; - - newfile->name[newfile->namepos + 4] = 0; - - if(newfile->blocksize == 2048) { - - newfile->name[newfile->namepos + 1] = 'i'; - - newfile->name[newfile->namepos + 2] = 's'; - - newfile->name[newfile->namepos + 3] = 'o'; - - } else { - - newfile->name[newfile->namepos + 1] = 'b'; - - newfile->name[newfile->namepos + 2] = 'i'; - - newfile->name[newfile->namepos + 3] = 'n'; - - } // ENDIF- Is this a true ISO (or just a raw BIN file?) - - newfile->namepos += 4; - - - - if(IsActualFile(newfile->name) == 0) { - - free(newfile); - - newfile = NULL; - - return(NULL); - - } // ENDIF- Does the destination file already exist? - - - - if(newfile->compress > 0) { - - CompressOpenForWrite(newfile); - - if((newfile->handle != ACTUALHANDLENULL) && - - (newfile->tablehandle == ACTUALHANDLENULL)) { - - ActualFileClose(newfile->handle); - - newfile->handle = ACTUALHANDLENULL; - - } // ENDIF Data file created, but table file stopped? Close and remove data - - } else { - - newfile->handle = ActualFileOpenForWrite(newfile->name); - - } // ENDIF- Writing out a compressed file? - - - - if(newfile->handle == ACTUALHANDLENULL) { - - free(newfile); - - newfile = NULL; - - return(NULL); - - } // ENDIF- Couldn't create file? Abort - - - - return(newfile); - -} // END IsoFileOpenForWrite() - - - - - -int IsoFileWrite(struct IsoFile *file, char *block) { - - int byteswritten; - - - - if(file == NULL) return(-1); - - if(block == NULL) return(-1); - - if(file->openforread == 1) return(-1); - - - -#ifdef VERBOSE_FUNCTION_ISOFILE - - PrintLog("CDVD isofile: IsoFileWrite()"); - -#endif /* VERBOSE_FUNCTION_ISOFILE */ - - - - byteswritten = 0; - - if(file->multi > 0) { - - byteswritten = MultiFileWrite(file, block); - - } else if(file->compress > 0) { - - byteswritten = CompressWrite(file, block); - - } else { - - byteswritten = ActualFileWrite(file->handle, - - file->blocksize, - - block); - - if(byteswritten > 0) file->filebytepos += byteswritten; - - if(byteswritten == file->blocksize) file->filesectorpos++; - - } // ENDLONGIF- Write to different file? Compressed block? or Raw? - - if(byteswritten < 0) { - -#ifdef VERBOSE_FUNCTION_ISOFILE - - PrintLog("CDVD isofile: Trouble writing the sector!"); - -#endif /* VERBOSE_FUNCTION_ISOFILE */ - - return(-1); - - } // ENDIF- Trouble reading the block? Say so! - - if(file->filebytepos > file->filebytesize) - - file->filebytesize = file->filebytepos; - - - - if(byteswritten < file->blocksize) { - -#ifdef VERBOSE_FUNCTION_ISOFILE - - PrintLog("CDVD isofile: Short block! Wrote %i out of %i bytes", - - byteswritten, file->blocksize); - -#endif /* VERBOSE_FUNCTION_ISOFILE */ - - return(-1); - - } // ENDIF- Didn't write enough bytes? Say so! - - if(file->filesectorpos > file->filesectorsize) - - file->filesectorsize = file->filesectorpos; - - - - file->sectorpos++; - - return(0); - -} // END IsoFileWrite() - - - - - -struct IsoFile *IsoFileCloseAndDelete(struct IsoFile *file) { - - int i; - - - - if(file == NULL) return(NULL); - - - - if(file->handle != ACTUALHANDLENULL) { - -#ifdef VERBOSE_FUNCTION_ISOFILE - - PrintLog("CDVD isofile: IsoFileCloseAndDelete()"); - -#endif /* VERBOSE_FUNCTION_ISOFILE */ - - - - if(file->compress > 0) { - - CompressClose(file); - - } else { - - ActualFileClose(file->handle); - - file->handle = ACTUALHANDLENULL; - - } // ENDIF- Compressed File? Close (and flush) compression too. - - } // ENDIF- Open Handle? Close the file - - - - if(file->multi == 1) { - - for(i = file->multistart; i <= file->multiend; i++) { - - file->name[file->multipos] = '0' + i; - - ActualFileDelete(file->name); - - if(file->compress > 0) { - - file->tablename[file->multipos] = '0' + i; - - ActualFileDelete(file->tablename); - - } // ENDIF- Get the table file too? - - } // NEXT i- iterate through each multi-file name, removing it. - - } else { - - ActualFileDelete(file->name); - - if(file->compress > 0) { - - ActualFileDelete(file->tablename); - - } // ENDIF- Get the table file too? - - } // ENDIF- Do we have to remove multiple files? - - - - free(file); - - return(NULL); - -} // END IsoFileCloseAndDelete() - +/* isofile.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // malloc() + +#include // off64_t + + + +#ifndef __LINUX__ + +#ifdef __linux__ + +#define __LINUX__ + +#endif /* __linux__ */ + +#endif /* No __LINUX__ */ + +#define CDVDdefs + +#include "PS2Edefs.h" + + + +#include "logfile.h" + +#include "multifile.h" + +#include "isocompress.h" + +#include "actualfile.h" + +#include "imagetype.h" + +#include "toc.h" + +#include "ecma119.h" + +#include "isofile.h" + + + + + +const char *isofileext[] = { + + ".iso", + + ".bin", + + ".img", + + NULL + +}; + + + +const char *cdname = "CD-XA001\0"; + +const char *playstationid = "PLAYSTATION\0"; + +// const char ps1/2name? + + + +// Internal functions + + + +void IsoNameStripExt(struct IsoFile *isofile) { + + int tempext; + + int tempnamepos; + + int tempextpos; + + + + tempext = 0; + + while(isofileext[tempext] != NULL) { + + tempextpos = 0; + + while(*(isofileext[tempext] + tempextpos) != 0) tempextpos++; + + + + tempnamepos = isofile->namepos; + + while((tempnamepos > 0) && (tempextpos > 0) && + + (isofile->name[tempnamepos - 1] == *(isofileext[tempext] + tempextpos - 1))) { + + tempnamepos--; + + tempextpos--; + + } // ENDWHILE- Comparing one extension to the end of the file name + + if(tempextpos == 0) { + + isofile->namepos = tempnamepos; // Move name pointer in front of ext. + + tempext = 0; // ... and test the list all over again. + + } else { + + tempext++; // Next ext in the list to test... + + } // ENDIF- Did we find a match? + + } // ENDWHILE- looking through extension list + +} // END IsoNameStripExt() + + + + + +// External functions + + + +struct IsoFile *IsoFileOpenForRead(const char *filename) { + + struct IsoFile *newfile; + + int retval; + + int i; + + char tempblock[2448]; + + struct tocTN toctn; + + struct tocTD toctd; + +// union { + +// struct ECMA119PrimaryVolume vol; + +// char ch[sizeof(struct ECMA119PrimaryVolume)]; + +// } *volcheck; + + union { + + struct ECMA119PrimaryVolume *vol; + + char *ch; + + } volcheck; + + + + newfile = NULL; + + + + if(filename == NULL) return(NULL); + + + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: IsoFileOpenForRead(%s)", filename); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + + + newfile = (struct IsoFile *) malloc(sizeof(struct IsoFile)); + + if(newfile == NULL) return(NULL); + + + + newfile->sectorpos = 0; + + newfile->openforread = 1; // Read-only ISO + + newfile->filebytepos = 0; + + newfile->filesectorpos = 0; + + newfile->blocksize = 0; // Flags as non-detected yet (Compress vs. Image) + + newfile->tabledata = NULL; + + + + newfile->namepos = 0; + + while((newfile->namepos < 255) && + + (*(filename + newfile->namepos) != 0)) { + + newfile->name[newfile->namepos] = *(filename + newfile->namepos); + + newfile->namepos++; + + } // ENDWHILE- copying the file name in... + + newfile->name[newfile->namepos] = 0; // And 0-terminate. + + + + IsoNameStripExt(newfile); // Ex: -I00.Z[.bin] + + + + // File Compression name detection + + newfile->compress = IsoNameStripCompress(newfile); // Ex: -I00.bin[.Z] + + newfile->compresspos = newfile->namepos; + + + + // Test File name compression + + retval = -1; + + if(newfile->compress > 0) { + + retval = CompressOpenForRead(newfile); + + if(retval == -1) CompressClose(newfile); + + } // ENDIF- Have a compression type hint? Test it out + + + + if(retval == -1) { + + newfile->compress = 5; + + while((newfile->compress > 0) && (retval == -1)) { + + retval = CompressOpenForRead(newfile); + + if(retval == -1) { + + CompressClose(newfile); + + newfile->compress--; + + } // ENDIF- Failed to open? Close it... and try the next one. + + } // ENDWHILE- Trying to find a compression scheme that will work... + + + + if(newfile->compress == 0) { + + newfile->handle = ActualFileOpenForRead(newfile->name); + + if(newfile->handle == ACTUALHANDLENULL) { + + free(newfile); + + newfile = NULL; + + return(NULL); + + } // ENDIF- Failed to open? Abort. + + newfile->filebytesize = ActualFileSize(newfile->handle); + + } // ENDIF- No compression? Open it uncompressed. + + } // ENDIF- Temp- failed to open? Abort... + + + + // Compressed data file with no table? Return prematurely... + + // Condition detection: compress > 0, tablehandle == ACTUALHANDLENULL + + if(retval == -2) { + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: Data file with no table!"); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + return(newfile); + + } // ENDIF- + + + + newfile->imagetype = DetectImageType(newfile); + + + + if(newfile->compress == 0) { + + newfile->filesectorsize = newfile->filebytesize / newfile->blocksize; + + } // ENDIF- Now that blocksize is known, raw file sectors can be figured out + + + + IsoNameStripExt(newfile); // Ex: -I00[.bin].Z + + + + IsoNameStripMulti(newfile); // Ex: [-I00].bin.Z + + + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD isofile: Filename: %s", filename); + + if(newfile->multi > 0) PrintLog("CDVD isofile: Multiple <2GB files."); + + PrintLog("CDVD isofile: Compression Method: %s", + + compressdesc[newfile->compress]); + + PrintLog("CDVD isofile: Image Type: %s", + + newfile->imagename); + + PrintLog("CDVD isofile: Block Size: %lli", newfile->blocksize); + + PrintLog("CDVD isofile: Total Sectors (of first file): %lli", + + newfile->filesectorsize); + +#endif /* VERBOSE_DISC_INFO */ + + + + // Load a TOC from a .toc file (is there is one) + + retval = IsoLoadTOC(newfile); + + if(retval == 0) return(newfile); + + + + // Get the volume sector for disc type test + + retval = IsoFileSeek(newfile, 16); + + if(retval < 0) { + + newfile = IsoFileClose(newfile); + + return(NULL); + + } // ENDIF- Could not find the directory sector? Abort. + + retval = IsoFileRead(newfile, tempblock); + + if(retval < 0) { + + newfile = IsoFileClose(newfile); + + return(NULL); + + } // ENDIF- Could not read the directory sector? Abort. + + + + volcheck.ch = tempblock; + + volcheck.ch += newfile->blockoffset; + + if(ValidateECMA119PrimaryVolume(volcheck.vol) != 0) { + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD isofile: Not an ISO9660 disc! Music CD perhaps?"); + +#endif /* VERBOSE_DISC_INFO */ + + newfile->cdvdtype = CDVD_TYPE_CDDA; + + + + } else { + + // Is this a playstation image? + + i = 0; + + while((*(playstationid + i) != 0) && + + (*(playstationid + i) == tempblock[newfile->blockoffset + 8 + i])) i++; + + if(*(playstationid + i) != 0) { + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD isofile: Not a Playstation Disc!"); + +#endif /* VERBOSE_DISC_INFO */ + + newfile->cdvdtype = CDVD_TYPE_DVDV; + + } else { + + newfile->cdvdtype = CDVD_TYPE_PS2DVD; + + } // ENDIF- Is this not a Playstation 1 image? + + // Sidenote: if the emulator is just playing Playstation 2 images, we could + + // just invalidate the image file right here. + + } // ENDIF- Not an ISO9660 disc? Assume Music CD. + + + + if(newfile->cdvdtype == CDVD_TYPE_PS2DVD) { + + // Is this a Playstation CD image? + + i = 0; + + while((*(cdname + i) != 0) && + + (*(cdname + i) == tempblock[newfile->blockoffset + 1024 + i])) i++; + + if(*(cdname + i) == 0) { + + newfile->cdvdtype = CDVD_TYPE_PSCD; + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD isofile: Image is a Playstation 1 CD."); + +#endif /* VERBOSE_DISC_INFO */ + + } else { + + if(newfile->blocksize != 2048) { + + newfile->cdvdtype = CDVD_TYPE_PS2CD; + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD isofile: Image is a Playstation 2 CD."); + +#endif /* VERBOSE_DISC_INFO */ + + } else { + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD isofile: Image is a DVD."); + +#endif /* VERBOSE_DISC_INFO */ + + } // ENDIF- Is the blocksize not 2048? CD image then. + + } // ENDIF- Is this a PS1 CD image? + + } // ENDIF- Is this a Playstation image? + + volcheck.ch = NULL; + + + + if((newfile->cdvdtype == CDVD_TYPE_DVDV) && + + (newfile->blocksize == 2352)) newfile->cdvdtype = CDVD_TYPE_CDDA; + + + + // Slap together a TOC based on the above guesswork. + + IsoInitTOC(newfile); + + if((newfile->cdvdtype != CDVD_TYPE_PS2DVD) && + + (newfile->cdvdtype != CDVD_TYPE_DVDV)) { + + toctn.strack = 1; + + toctn.etrack = 1; + + IsoAddTNToTOC(newfile, toctn); + + + + toctd.type = 0; + + toctd.lsn = newfile->filesectorsize; + + IsoAddTDToTOC(newfile, 0xAA, toctd); + + + + toctd.type = 0; // ? + + if(newfile->cdvdtype == CDVD_TYPE_CDDA) { + + toctd.type = CDVD_AUDIO_TRACK; // Music track assumed + + } else { + + toctd.type = CDVD_MODE1_TRACK; // Data track assumed + + } // ENDIF- Is this track a music or data track? + + toctd.lsn = 0; + + IsoAddTDToTOC(newfile, 1, toctd); + + } // ENDIF- Is this a CD? Single track for all sectors + + + + return(newfile); + +} // END IsoFileOpenForRead() + + + + + +int IsIsoFile(const char *filename) { + + int retval; + + struct IsoFile *tempfile; + + + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: IsIsoFile()"); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + + + retval = IsActualFile(filename); + + if(retval < 0) return(retval); // Not a regular file? Report it. + + + + tempfile = NULL; + + tempfile = IsoFileOpenForRead(filename); + + if(tempfile == NULL) return(-3); // Not an image file? Report it. + + + + retval = 0; + + if((tempfile->compress > 0) && + + (tempfile->tablehandle == ACTUALHANDLENULL) && + + (tempfile->tabledata == NULL)) retval = -4; + + + + tempfile = IsoFileClose(tempfile); + + return(retval); + +} // END IsIsoFile() + + + + + +int IsoFileSeek(struct IsoFile *file, off64_t sector) { + + int retval; + + + + if(file == NULL) return(-1); + + if(sector < 0) return(-1); + + + + if(sector == file->sectorpos) return(0); + + + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: IsoFileSeek(%llu)", sector); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + + + if(file->multi > 0) { + + retval = MultiFileSeek(file, sector); + + } else if(file->compress > 0) { + + retval = CompressSeek(file, sector); + + } else { + + retval = ActualFileSeek(file->handle, + + (sector * file->blocksize) + file->imageheader); + + if(retval == 0) { + + file->filesectorpos = sector; + + file->filebytepos = (sector * file->blocksize) + file->imageheader; + + } // ENDIF- Succeeded? Adjust internal pointers + + } // ENDLONGIF- Seek right file? Or compressed block? Or Raw block? + + + + if(retval < 0) { + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: Trouble finding the sector!"); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + return(-1); + + } // ENDIF- Trouble reading the block? Say so! + + + + file->sectorpos = sector; + + return(0); + +} // END IsoFileSeek() + + + + + +int IsoFileRead(struct IsoFile *file, char *block) { + + int retval; + + + + if(file == NULL) return(-1); + + if(block == NULL) return(-1); + + if(file->openforread == 0) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: IsoFileRead(%i)", file->blocksize); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + + + if(file->multi > 0) { + + retval = MultiFileRead(file, block); + + } else if(file->compress > 0) { + + retval = CompressRead(file, block); + + } else { + + if(file->sectorpos >= file->filesectorsize) return(-1); + + retval = ActualFileRead(file->handle, + + file->blocksize, + + block); + + if(retval > 0) file->filebytepos += retval; + + if(retval == file->blocksize) file->filesectorpos++; + + } // ENDLONGIF- Read right file? Or compressed block? Or Raw block? + + + + if(retval < 0) { + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: Trouble reading the sector!"); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + return(-1); + + } // ENDIF- Trouble reading the block? Say so! + + + + if(retval < file->blocksize) { + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: Short block! Got %i out of %i bytes", + + retval, file->blocksize); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + return(-1); + + } // ENDIF- Didn't get enough bytes? Say so! + + + + file->sectorpos++; + + return(0); + +} // END IsoFileRead() + + + + + +struct IsoFile *IsoFileClose(struct IsoFile *file) { + + if(file == NULL) return(NULL); + + + + if(file->handle != ACTUALHANDLENULL) { + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: IsoFileClose()"); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + + + if(file->compress > 0) { + + CompressClose(file); + + } else { + + ActualFileClose(file->handle); + + file->handle = ACTUALHANDLENULL; + + } // ENDIF- Compressed File? Close (and flush) compression too. + + } // ENDIF- Open Handle? Close the file + + + + free(file); + + return(NULL); + +} // END IsoFileClose() + + + + + +struct IsoFile *IsoFileOpenForWrite(const char *filename, + + int imagetype, + + int multi, + + int compress) { + + struct IsoFile *newfile; + + + + newfile = NULL; + + + + if(filename == NULL) return(NULL); + + if((imagetype < 0) || (imagetype > 11)) return(NULL); + + if((compress < 0) || (compress > 5)) return(NULL); + + + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: IsoFileOpenForWrite()"); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + + + newfile = (struct IsoFile *) malloc(sizeof(struct IsoFile)); + + if(newfile == NULL) return(NULL); + + + + newfile->sectorpos = 0; + + newfile->openforread = 0; // Write-only file + + newfile->filebytesize = 0; + + newfile->filebytepos = 0; + + newfile->filesectorsize = 0; + + newfile->filesectorpos = 0; + + + + // if(toc != NULL) { + + // for(i = 0; i < 2048; i++) newfile->toc[i] = *(toc + i); + + // } else { + + // for(i = 0; i < 2048; i++) newfile->toc[i] = 0; + + // } // ENDIF- Do we have a PS2 Table of Contents to save out as well? + + + + newfile->namepos = 0; + + while((newfile->namepos < 255) && + + (*(filename + newfile->namepos) != 0)) { + + newfile->name[newfile->namepos] = *(filename + newfile->namepos); + + newfile->namepos++; + + } // ENDWHILE- copying the file name in... + + newfile->name[newfile->namepos] = 0; // And 0-terminate. + + + + IsoNameStripExt(newfile); + + IsoNameStripCompress(newfile); + + IsoNameStripExt(newfile); + + IsoNameStripMulti(newfile); + + newfile->name[newfile->namepos] = 0; // And 0-terminate. + + + + newfile->imagetype = imagetype; + + GetImageType(newfile, imagetype); + + newfile->cdvdtype = CDVD_TYPE_PS2DVD; // Does it matter here? Nope. + + + + newfile->multi = multi; + + if(newfile->multi > 0) { + + newfile->name[newfile->namepos + 0] = '-'; + + newfile->name[newfile->namepos + 1] = 'I'; + + newfile->name[newfile->namepos + 2] = '0'; + + newfile->name[newfile->namepos + 3] = '0'; + + newfile->name[newfile->namepos + 4] = 0; + + newfile->multipos = newfile->namepos + 3; + + newfile->namepos += 4; + + newfile->multistart = 0; + + newfile->multiend = 0; + + newfile->multinow = 0; + + newfile->multioffset = 0; + + newfile->multisectorend[0] = 0; + + } // ENDIF- Are we creating a multi-file? + + + + newfile->compress = compress; + + switch(newfile->compress) { + + case 1: + + case 3: + + newfile->name[newfile->namepos + 0] = '.'; + + newfile->name[newfile->namepos + 1] = 'Z'; + + newfile->name[newfile->namepos + 2] = 0; + + newfile->namepos += 2; + + break; + + + + case 2: + + newfile->name[newfile->namepos + 0] = '.'; + + newfile->name[newfile->namepos + 1] = 'd'; + + newfile->name[newfile->namepos + 2] = 'u'; + + newfile->name[newfile->namepos + 3] = 'm'; + + newfile->name[newfile->namepos + 4] = 'p'; + + newfile->name[newfile->namepos + 5] = 0; + + newfile->namepos += 5; + + break; + + + + case 4: + + newfile->name[newfile->namepos + 0] = '.'; + + newfile->name[newfile->namepos + 1] = 'B'; + + newfile->name[newfile->namepos + 2] = 'Z'; + + newfile->name[newfile->namepos + 3] = '2'; + + newfile->name[newfile->namepos + 4] = 0; + + newfile->namepos += 4; + + break; + + + + case 5: + + newfile->name[newfile->namepos + 0] = '.'; + + newfile->name[newfile->namepos + 1] = 'b'; + + newfile->name[newfile->namepos + 2] = 'z'; + + newfile->name[newfile->namepos + 3] = '2'; + + newfile->name[newfile->namepos + 4] = 0; + + newfile->namepos += 4; + + break; + + + + case 0: + + default: + + break; + + } // ENDSWITCH compress- which compression extension should we add on? + + + + newfile->name[newfile->namepos + 0] = '.'; + + newfile->name[newfile->namepos + 4] = 0; + + if(newfile->blocksize == 2048) { + + newfile->name[newfile->namepos + 1] = 'i'; + + newfile->name[newfile->namepos + 2] = 's'; + + newfile->name[newfile->namepos + 3] = 'o'; + + } else { + + newfile->name[newfile->namepos + 1] = 'b'; + + newfile->name[newfile->namepos + 2] = 'i'; + + newfile->name[newfile->namepos + 3] = 'n'; + + } // ENDIF- Is this a true ISO (or just a raw BIN file?) + + newfile->namepos += 4; + + + + if(IsActualFile(newfile->name) == 0) { + + free(newfile); + + newfile = NULL; + + return(NULL); + + } // ENDIF- Does the destination file already exist? + + + + if(newfile->compress > 0) { + + CompressOpenForWrite(newfile); + + if((newfile->handle != ACTUALHANDLENULL) && + + (newfile->tablehandle == ACTUALHANDLENULL)) { + + ActualFileClose(newfile->handle); + + newfile->handle = ACTUALHANDLENULL; + + } // ENDIF Data file created, but table file stopped? Close and remove data + + } else { + + newfile->handle = ActualFileOpenForWrite(newfile->name); + + } // ENDIF- Writing out a compressed file? + + + + if(newfile->handle == ACTUALHANDLENULL) { + + free(newfile); + + newfile = NULL; + + return(NULL); + + } // ENDIF- Couldn't create file? Abort + + + + return(newfile); + +} // END IsoFileOpenForWrite() + + + + + +int IsoFileWrite(struct IsoFile *file, char *block) { + + int byteswritten; + + + + if(file == NULL) return(-1); + + if(block == NULL) return(-1); + + if(file->openforread == 1) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: IsoFileWrite()"); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + + + byteswritten = 0; + + if(file->multi > 0) { + + byteswritten = MultiFileWrite(file, block); + + } else if(file->compress > 0) { + + byteswritten = CompressWrite(file, block); + + } else { + + byteswritten = ActualFileWrite(file->handle, + + file->blocksize, + + block); + + if(byteswritten > 0) file->filebytepos += byteswritten; + + if(byteswritten == file->blocksize) file->filesectorpos++; + + } // ENDLONGIF- Write to different file? Compressed block? or Raw? + + if(byteswritten < 0) { + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: Trouble writing the sector!"); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + return(-1); + + } // ENDIF- Trouble reading the block? Say so! + + if(file->filebytepos > file->filebytesize) + + file->filebytesize = file->filebytepos; + + + + if(byteswritten < file->blocksize) { + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: Short block! Wrote %i out of %i bytes", + + byteswritten, file->blocksize); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + return(-1); + + } // ENDIF- Didn't write enough bytes? Say so! + + if(file->filesectorpos > file->filesectorsize) + + file->filesectorsize = file->filesectorpos; + + + + file->sectorpos++; + + return(0); + +} // END IsoFileWrite() + + + + + +struct IsoFile *IsoFileCloseAndDelete(struct IsoFile *file) { + + int i; + + + + if(file == NULL) return(NULL); + + + + if(file->handle != ACTUALHANDLENULL) { + +#ifdef VERBOSE_FUNCTION_ISOFILE + + PrintLog("CDVD isofile: IsoFileCloseAndDelete()"); + +#endif /* VERBOSE_FUNCTION_ISOFILE */ + + + + if(file->compress > 0) { + + CompressClose(file); + + } else { + + ActualFileClose(file->handle); + + file->handle = ACTUALHANDLENULL; + + } // ENDIF- Compressed File? Close (and flush) compression too. + + } // ENDIF- Open Handle? Close the file + + + + if(file->multi == 1) { + + for(i = file->multistart; i <= file->multiend; i++) { + + file->name[file->multipos] = '0' + i; + + ActualFileDelete(file->name); + + if(file->compress > 0) { + + file->tablename[file->multipos] = '0' + i; + + ActualFileDelete(file->tablename); + + } // ENDIF- Get the table file too? + + } // NEXT i- iterate through each multi-file name, removing it. + + } else { + + ActualFileDelete(file->name); + + if(file->compress > 0) { + + ActualFileDelete(file->tablename); + + } // ENDIF- Get the table file too? + + } // ENDIF- Do we have to remove multiple files? + + + + free(file); + + return(NULL); + +} // END IsoFileCloseAndDelete() + diff --git a/plugins/CDVDisoEFP/src/isofile.h b/plugins/CDVDisoEFP/src/isofile.h index 93dff0e6c7..b522fd04cf 100644 --- a/plugins/CDVDisoEFP/src/isofile.h +++ b/plugins/CDVDisoEFP/src/isofile.h @@ -1,246 +1,246 @@ -/* isofile.h - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#ifndef ISOFILE_H - -#define ISOFILE_H - - - - - -#include // off64_t - - - -#include "actualfile.h" - - - - - -// #define VERBOSE_FUNCTION_ISOFILE - -#define VERBOSE_DISC_INFO - - - - - -struct IsoFile { - - // *** Primary Data area - - char name[256]; - - int namepos; // Used for detection of components within name - - ACTUALHANDLE handle; - - off64_t sectorpos; // Overall. - - // blocks (char [2352]) provided by users - - - - // *** Derived Stats from Primary Data - - int openforread; // 1 = Yes, 0 = No - - off64_t filebytesize; - - off64_t filebytepos; - - off64_t filesectorsize; - - off64_t filesectorpos; - - int cdvdtype; // for GetDiskType call - - char toc[2048]; // for GetTOC call - - - - // From imagetype.h - - int imagetype; - - char imagename[40]; - - off64_t imageheader; // Header bytes in every file... - - off64_t blocksize; // sized to add quickly to other off64_t counters - - int blockoffset; // Where to place data in block - - - - // from isocompress.h - - int compress; // Compression Method used (0 = none, 1...) - - int compresspos; // Start pos of ".Z", ".BZ", etc... - - char tablename[256]; - - ACTUALHANDLE tablehandle; - - char compblock[65536]; // Temporary storage of uncompressed sectors. - - off64_t compsector; // First sector of the compblock[] - - off64_t numsectors; // Number of sectors in a compression block - - char *tabledata; // Table holding area - - - - // From multifile.h - - int multi; // 0 = Single File, 1 = Multiple Files - - int multipos; // Position of Multi # ('0'-'9') - - off64_t multisectorend[10]; // Ending sector of each file... - - off64_t multioffset; // To help with seek calls. Sector offset. - - int multistart; // Starting file number (0-1) - - int multiend; // Ending file number (?-9) - - int multinow; // Current open file number - - - - // *** (Specific) Compression Data area - -}; - - - - - -// Read-only section - -// IsoFiles opened for read are treated as random-access files - - - -extern int IsIsoFile(const char *filename); - -// Returns an image type (positive or zero) or an error (negative) - - - -extern struct IsoFile *IsoFileOpenForRead(const char *filename); - -// Will seek blocksize and compression method on it's own. - - - -extern int IsoFileSeek(struct IsoFile *file, off64_t sector); - -// Sector, not byte. - - - -extern int IsoFileRead(struct IsoFile *file, char *block); - -// Buffers should be at least of "blocksize" size. 2352 bytes, please. - - - - - -// Write-only section - -// IsoFiles opened for write are treated as sequential files (still written - -// out a block at a time, though, to be read in later as random-access) - -// No plans are made to make writes random-access at this time. - - - -extern struct IsoFile *IsoFileOpenForWrite(const char *filename, - - int imagetype, - - int multi, - - int compress); - - - -extern int IsoFileWrite(struct IsoFile *file, char *block); - -// Uncompressed buffers, please. - -// Will compress with this call (if it's necessary.) - - - - - -// Calls used for all Isofiles - - - -extern struct IsoFile *IsoFileClose(struct IsoFile *file); - -// Use return variable to NULL the file pointer. - -// Ex: lastfile = IsoFileClose(lastfile); - - - -extern struct IsoFile *IsoFileCloseAndDelete(struct IsoFile *file); - -// For failure to finish writing out a file(set). - - - - - -#endif /* ISOFILE_H */ - +/* isofile.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef ISOFILE_H + +#define ISOFILE_H + + + + + +#include // off64_t + + + +#include "actualfile.h" + + + + + +// #define VERBOSE_FUNCTION_ISOFILE + +#define VERBOSE_DISC_INFO + + + + + +struct IsoFile { + + // *** Primary Data area + + char name[256]; + + int namepos; // Used for detection of components within name + + ACTUALHANDLE handle; + + off64_t sectorpos; // Overall. + + // blocks (char [2352]) provided by users + + + + // *** Derived Stats from Primary Data + + int openforread; // 1 = Yes, 0 = No + + off64_t filebytesize; + + off64_t filebytepos; + + off64_t filesectorsize; + + off64_t filesectorpos; + + int cdvdtype; // for GetDiskType call + + char toc[2048]; // for GetTOC call + + + + // From imagetype.h + + int imagetype; + + char imagename[40]; + + off64_t imageheader; // Header bytes in every file... + + off64_t blocksize; // sized to add quickly to other off64_t counters + + int blockoffset; // Where to place data in block + + + + // from isocompress.h + + int compress; // Compression Method used (0 = none, 1...) + + int compresspos; // Start pos of ".Z", ".BZ", etc... + + char tablename[256]; + + ACTUALHANDLE tablehandle; + + char compblock[65536]; // Temporary storage of uncompressed sectors. + + off64_t compsector; // First sector of the compblock[] + + off64_t numsectors; // Number of sectors in a compression block + + char *tabledata; // Table holding area + + + + // From multifile.h + + int multi; // 0 = Single File, 1 = Multiple Files + + int multipos; // Position of Multi # ('0'-'9') + + off64_t multisectorend[10]; // Ending sector of each file... + + off64_t multioffset; // To help with seek calls. Sector offset. + + int multistart; // Starting file number (0-1) + + int multiend; // Ending file number (?-9) + + int multinow; // Current open file number + + + + // *** (Specific) Compression Data area + +}; + + + + + +// Read-only section + +// IsoFiles opened for read are treated as random-access files + + + +extern int IsIsoFile(const char *filename); + +// Returns an image type (positive or zero) or an error (negative) + + + +extern struct IsoFile *IsoFileOpenForRead(const char *filename); + +// Will seek blocksize and compression method on it's own. + + + +extern int IsoFileSeek(struct IsoFile *file, off64_t sector); + +// Sector, not byte. + + + +extern int IsoFileRead(struct IsoFile *file, char *block); + +// Buffers should be at least of "blocksize" size. 2352 bytes, please. + + + + + +// Write-only section + +// IsoFiles opened for write are treated as sequential files (still written + +// out a block at a time, though, to be read in later as random-access) + +// No plans are made to make writes random-access at this time. + + + +extern struct IsoFile *IsoFileOpenForWrite(const char *filename, + + int imagetype, + + int multi, + + int compress); + + + +extern int IsoFileWrite(struct IsoFile *file, char *block); + +// Uncompressed buffers, please. + +// Will compress with this call (if it's necessary.) + + + + + +// Calls used for all Isofiles + + + +extern struct IsoFile *IsoFileClose(struct IsoFile *file); + +// Use return variable to NULL the file pointer. + +// Ex: lastfile = IsoFileClose(lastfile); + + + +extern struct IsoFile *IsoFileCloseAndDelete(struct IsoFile *file); + +// For failure to finish writing out a file(set). + + + + + +#endif /* ISOFILE_H */ + diff --git a/plugins/CDVDisoEFP/src/multifile.c b/plugins/CDVDisoEFP/src/multifile.c index 9c261740df..5d9d16fa55 100644 --- a/plugins/CDVDisoEFP/src/multifile.c +++ b/plugins/CDVDisoEFP/src/multifile.c @@ -1,578 +1,578 @@ -/* multifile.c - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#include // NULL - -#include // off64_t - - - -// #ifndef __LINUX__ - -// #ifdef __linux__ - -// #define __LINUX__ - -// #endif /* __linux__ */ - -// #endif /* No __LINUX__ */ - - - -// #define CDVDdefs - -// #include "PS2Edefs.h" - - - -#include "logfile.h" - -#include "isofile.h" - -#include "isocompress.h" - -#include "actualfile.h" - -#include "multifile.h" - - - - - -#define FILESIZELIMIT 2000000000 - - - - - -char *multinames[] = { - - "", - - "Multiple ", - - NULL }; - - - - - -void IsoNameStripMulti(struct IsoFile *isofile) { - - isofile->multi = 0; - - if(isofile->namepos < 2) return; // Not enough digits - - if(isofile->name[isofile->namepos - 1] < '0') return; // Ex: -I0[0] - - if(isofile->name[isofile->namepos - 1] > '1') return; // Ex: -I0[1] - - if(isofile->name[isofile->namepos - 2] != '0') return; // Ex: -I[0]0 - - - - isofile->multi = 1; - - isofile->multipos = isofile->namepos - 1; - - isofile->namepos -= 2; - - isofile->multistart = isofile->name[isofile->multipos] - '0'; - - isofile->multiend = isofile->multistart; - - isofile->multinow = isofile->multistart; - - isofile->multisectorend[0] = 0; // Sometimes the file name starts with '1' - - isofile->multisectorend[isofile->multistart] = isofile->filesectorsize; - - isofile->multioffset = 0; - - - - if(isofile->namepos < 1) return; - - if(isofile->name[isofile->namepos - 1] != 'I') return; // Ex: -[I]00 - - isofile->namepos--; - - - - if(isofile->namepos < 2) return; // Filename doesn't start with '-' - - if(isofile->name[isofile->namepos - 1] != '-') return; // Ex: [-]I00 - - isofile->namepos--; - - - - return; - -} // END IsoNameStripMulti() - - - - - -int MultiFileSeek(struct IsoFile *isofile, off64_t sector) { - - int multinext; - - int retval; - - off64_t tempfilesector; - - - -#ifdef VERBOSE_FUNCTION_MULTIFILE - - PrintLog("CDVD multifile: MultiFileSeek(%llu)", sector); - -#endif /* VERBOSE_FUNCTION_MULTIFILE */ - - - - multinext = isofile->multinow; - - - - // Do we need to back up a file or so? - - while((multinext > isofile->multistart) && - - (sector < isofile->multisectorend[multinext - 1])) multinext--; - - - - // Do we need to go forward a file or two (that we know about?) - - while((multinext < isofile->multiend) && - - (sector >= isofile->multisectorend[multinext])) multinext++; - - - - // Do we need to go forward a file or two (that we *don't* know about?) - - while((multinext < 9) && - - (sector >= isofile->multisectorend[multinext])) { - - if(isofile->compress > 0) { - - CompressClose(isofile); - - } else { - - ActualFileClose(isofile->handle); - - isofile->handle = ACTUALHANDLENULL; - - } // ENDIF- Close a compressed file? (or an uncompressed one?) - - - - multinext++; - - - - isofile->name[isofile->multipos] = '0' + multinext; - - if(isofile->compress > 0) { - - retval = CompressOpenForRead(isofile); - - - - } else { - - isofile->handle = ActualFileOpenForRead(isofile->name); - - retval = 0; - - if(isofile->handle == ACTUALHANDLENULL) { - - retval = -1; - - - - } else { - - isofile->filebytesize = ActualFileSize(isofile->handle); - - isofile->filesectorsize = isofile->filebytesize / isofile->blocksize; - - isofile->filebytepos = 0; - - isofile->filesectorpos = 0; - - } // ENDIF- Failed to open the file raw? - - } // ENDIF- Compressed or non-compressed? What a question. - - - - if(retval < 0) { - - if(isofile->compress > 0) { - - CompressClose(isofile); - - } else { - - ActualFileClose(isofile->handle); - - isofile->handle = ACTUALHANDLENULL; - - } // ENDIF- Close a compressed file? (or an uncompressed one?) - - - - multinext--; - - - - isofile->name[isofile->multipos] = '0' + multinext; - - if(isofile->compress > 0) { - - CompressOpenForRead(isofile); - - } else { - - isofile->handle = ActualFileOpenForRead(isofile->name); - - isofile->filebytesize = ActualFileSize(isofile->handle); - - isofile->filesectorsize = isofile->filebytesize / isofile->blocksize; - - isofile->filebytepos = 0; - - isofile->filesectorpos = 0; - - } // ENDIF- Compressed or non-compressed? What a question. - - - - isofile->multinow = multinext; - - if(isofile->multinow == 0) { - - isofile->multioffset = 0; - - } else { - - isofile->multioffset = isofile->multisectorend[isofile->multinow - 1]; - - } // ENDIF- At the start of the list? Offset 0. - - return(-1); - - } // ENDIF- Failed to open next in series? Revert and abort. - - - - isofile->multinow = multinext; - - isofile->multiend = multinext; - - isofile->multioffset = isofile->multisectorend[multinext - 1]; - - isofile->multisectorend[multinext] = isofile->multisectorend[multinext - 1] - - + isofile->filesectorsize; - -#ifdef VERBOSE_DISC_INFO - - PrintLog("CDVD multifile: File %i opened, %llu sectors found (%llu sectors total)", - - multinext, - - isofile->filesectorsize, - - isofile->multisectorend[multinext]); - -#endif /* VERBOSE_DISC_INFO */ - - } // ENDWHILE- searching through new files for a high enough end-mark - - - - if(multinext != isofile->multinow) { - -#ifdef VERBOSE_WARNING_MULTIFILE - - PrintLog("CDVD multifile: Changing to File %i", multinext); - -#endif /* VERBOSE_WARNING_MULTIFILE */ - - if(isofile->compress > 0) { - - CompressClose(isofile); - - } else { - - ActualFileClose(isofile->handle); - - isofile->handle = ACTUALHANDLENULL; - - } // ENDIF- Close a compressed file? (or an uncompressed one?) - - - - isofile->name[isofile->multipos] = '0' + multinext; - - if(isofile->compress > 0) { - - CompressOpenForRead(isofile); - - } else { - - isofile->handle = ActualFileOpenForRead(isofile->name); - - if(isofile->handle == ACTUALHANDLENULL) return(-1); // Couldn't re-open? - - isofile->filebytesize = ActualFileSize(isofile->handle); - - isofile->filesectorsize = isofile->filebytesize / isofile->blocksize; - - isofile->filebytepos = 0; - - isofile->filesectorpos = 0; - - } // ENDIF- Compressed or non-compressed? What a question. - - - - isofile->multinow = multinext; - - if(multinext == 0) { - - isofile->multioffset = 0; - - } else { - - isofile->multioffset = isofile->multisectorend[multinext - 1]; - - } // ENDIF- At the start of the list? Offset 0. - - } // ENDIF- Not looking at the same file? Change to the new one. - - - - tempfilesector = sector - isofile->multioffset; - - if(isofile->compress > 0) { - - return(CompressSeek(isofile, tempfilesector)); - - } else { - - retval = ActualFileSeek(isofile->handle, - - (tempfilesector * isofile->blocksize) - - + isofile->imageheader); - - if(retval == 0) { - - isofile->filesectorpos = sector; - - isofile->filebytepos = (sector * isofile->blocksize) - - + isofile->imageheader; - - } // ENDIF- Sucessful? Adjust internals - - return(retval); - - } // ENDIF- Seek a position in a compressed file? - -} // END MultiFileSeek() - - - - - -int MultiFileRead(struct IsoFile *isofile, char *block) { - - int retval; - - - -#ifdef VERBOSE_FUNCTION_MULTIFILE - - PrintLog("CDVD multifile: MultiFileRead()"); - -#endif /* VERBOSE_FUNCTION_MULTIFILE */ - - - - if(isofile->filesectorpos >= isofile->filesectorsize) - - MultiFileSeek(isofile, isofile->sectorpos); - - - - if(isofile->compress > 0) { - - return(CompressRead(isofile, block)); - - } else { - - retval = ActualFileRead(isofile->handle, isofile->blocksize, block); - - if(retval > 0) isofile->filebytepos += retval; - - if(retval == isofile->blocksize) isofile->filesectorpos++; - - return(retval); - - } // ENDIF- Read a compressed sector? - -} // END MultiFileRead() - - - - - -int MultiFileWrite(struct IsoFile *isofile, char *block) { - - int retval; - - - -#ifdef VERBOSE_FUNCTION_MULTIFILE - - PrintLog("CDVD multifile: MultiFileWrite()"); - -#endif /* VERBOSE_FUNCTION_MULTIFILE */ - - - - if(isofile->filebytesize + isofile->blocksize > FILESIZELIMIT) { - - if(isofile->compress > 0) { - - CompressClose(isofile); - - } else { - - ActualFileClose(isofile->handle); - - isofile->handle = ACTUALHANDLENULL; - - } // ENDIF- Close a compressed file? (or an uncompressed one?) - - if(isofile->multinow == 9) return(-1); // Over 10 files? Overflow! - - - - isofile->multioffset += isofile->filesectorsize; - - isofile->multinow++; - - isofile->multiend++; - -#ifdef VERBOSE_WARNING_MULTIFILE - - PrintLog("CDVD multifile: Changing to File %i", isofile->multinow); - -#endif /* VERBOSE_WARNING_MULTIFILE */ - - - - isofile->name[isofile->multipos] = '0' + isofile->multinow; - - if(isofile->compress > 0) { - - retval = CompressOpenForWrite(isofile); - - } else { - - isofile->handle = ActualFileOpenForWrite(isofile->name); - - if(isofile->handle == ACTUALHANDLENULL) { - - retval = -1; - - } else { - - retval = 0; - - isofile->filebytesize = 0; - - isofile->filesectorsize = 0; - - isofile->filebytepos = 0; - - isofile->filesectorpos = 0; - - } // ENDIF- Trouble opening next file? - - } // ENDIF- Opening the next compressed file? (Or uncompressed?) - - if(retval < 0) return(-1); // Couldn't open another file? Abort. - - } // ENDIF- Hit the size limit? Move on to next file... - - - - if(isofile->compress > 0) { - - return(CompressWrite(isofile, block)); - - } else { - - retval = ActualFileWrite(isofile->handle, isofile->blocksize, block); - - if(retval > 0) isofile->filebytepos += retval; - - if(retval == isofile->blocksize) isofile->filesectorpos++; - - return(retval); - - } // ENDIF- Write a compressed sector? - -} // END MultiFileWrite() - +/* multifile.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // off64_t + + + +// #ifndef __LINUX__ + +// #ifdef __linux__ + +// #define __LINUX__ + +// #endif /* __linux__ */ + +// #endif /* No __LINUX__ */ + + + +// #define CDVDdefs + +// #include "PS2Edefs.h" + + + +#include "logfile.h" + +#include "isofile.h" + +#include "isocompress.h" + +#include "actualfile.h" + +#include "multifile.h" + + + + + +#define FILESIZELIMIT 2000000000 + + + + + +char *multinames[] = { + + "", + + "Multiple ", + + NULL }; + + + + + +void IsoNameStripMulti(struct IsoFile *isofile) { + + isofile->multi = 0; + + if(isofile->namepos < 2) return; // Not enough digits + + if(isofile->name[isofile->namepos - 1] < '0') return; // Ex: -I0[0] + + if(isofile->name[isofile->namepos - 1] > '1') return; // Ex: -I0[1] + + if(isofile->name[isofile->namepos - 2] != '0') return; // Ex: -I[0]0 + + + + isofile->multi = 1; + + isofile->multipos = isofile->namepos - 1; + + isofile->namepos -= 2; + + isofile->multistart = isofile->name[isofile->multipos] - '0'; + + isofile->multiend = isofile->multistart; + + isofile->multinow = isofile->multistart; + + isofile->multisectorend[0] = 0; // Sometimes the file name starts with '1' + + isofile->multisectorend[isofile->multistart] = isofile->filesectorsize; + + isofile->multioffset = 0; + + + + if(isofile->namepos < 1) return; + + if(isofile->name[isofile->namepos - 1] != 'I') return; // Ex: -[I]00 + + isofile->namepos--; + + + + if(isofile->namepos < 2) return; // Filename doesn't start with '-' + + if(isofile->name[isofile->namepos - 1] != '-') return; // Ex: [-]I00 + + isofile->namepos--; + + + + return; + +} // END IsoNameStripMulti() + + + + + +int MultiFileSeek(struct IsoFile *isofile, off64_t sector) { + + int multinext; + + int retval; + + off64_t tempfilesector; + + + +#ifdef VERBOSE_FUNCTION_MULTIFILE + + PrintLog("CDVD multifile: MultiFileSeek(%llu)", sector); + +#endif /* VERBOSE_FUNCTION_MULTIFILE */ + + + + multinext = isofile->multinow; + + + + // Do we need to back up a file or so? + + while((multinext > isofile->multistart) && + + (sector < isofile->multisectorend[multinext - 1])) multinext--; + + + + // Do we need to go forward a file or two (that we know about?) + + while((multinext < isofile->multiend) && + + (sector >= isofile->multisectorend[multinext])) multinext++; + + + + // Do we need to go forward a file or two (that we *don't* know about?) + + while((multinext < 9) && + + (sector >= isofile->multisectorend[multinext])) { + + if(isofile->compress > 0) { + + CompressClose(isofile); + + } else { + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + } // ENDIF- Close a compressed file? (or an uncompressed one?) + + + + multinext++; + + + + isofile->name[isofile->multipos] = '0' + multinext; + + if(isofile->compress > 0) { + + retval = CompressOpenForRead(isofile); + + + + } else { + + isofile->handle = ActualFileOpenForRead(isofile->name); + + retval = 0; + + if(isofile->handle == ACTUALHANDLENULL) { + + retval = -1; + + + + } else { + + isofile->filebytesize = ActualFileSize(isofile->handle); + + isofile->filesectorsize = isofile->filebytesize / isofile->blocksize; + + isofile->filebytepos = 0; + + isofile->filesectorpos = 0; + + } // ENDIF- Failed to open the file raw? + + } // ENDIF- Compressed or non-compressed? What a question. + + + + if(retval < 0) { + + if(isofile->compress > 0) { + + CompressClose(isofile); + + } else { + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + } // ENDIF- Close a compressed file? (or an uncompressed one?) + + + + multinext--; + + + + isofile->name[isofile->multipos] = '0' + multinext; + + if(isofile->compress > 0) { + + CompressOpenForRead(isofile); + + } else { + + isofile->handle = ActualFileOpenForRead(isofile->name); + + isofile->filebytesize = ActualFileSize(isofile->handle); + + isofile->filesectorsize = isofile->filebytesize / isofile->blocksize; + + isofile->filebytepos = 0; + + isofile->filesectorpos = 0; + + } // ENDIF- Compressed or non-compressed? What a question. + + + + isofile->multinow = multinext; + + if(isofile->multinow == 0) { + + isofile->multioffset = 0; + + } else { + + isofile->multioffset = isofile->multisectorend[isofile->multinow - 1]; + + } // ENDIF- At the start of the list? Offset 0. + + return(-1); + + } // ENDIF- Failed to open next in series? Revert and abort. + + + + isofile->multinow = multinext; + + isofile->multiend = multinext; + + isofile->multioffset = isofile->multisectorend[multinext - 1]; + + isofile->multisectorend[multinext] = isofile->multisectorend[multinext - 1] + + + isofile->filesectorsize; + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD multifile: File %i opened, %llu sectors found (%llu sectors total)", + + multinext, + + isofile->filesectorsize, + + isofile->multisectorend[multinext]); + +#endif /* VERBOSE_DISC_INFO */ + + } // ENDWHILE- searching through new files for a high enough end-mark + + + + if(multinext != isofile->multinow) { + +#ifdef VERBOSE_WARNING_MULTIFILE + + PrintLog("CDVD multifile: Changing to File %i", multinext); + +#endif /* VERBOSE_WARNING_MULTIFILE */ + + if(isofile->compress > 0) { + + CompressClose(isofile); + + } else { + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + } // ENDIF- Close a compressed file? (or an uncompressed one?) + + + + isofile->name[isofile->multipos] = '0' + multinext; + + if(isofile->compress > 0) { + + CompressOpenForRead(isofile); + + } else { + + isofile->handle = ActualFileOpenForRead(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) return(-1); // Couldn't re-open? + + isofile->filebytesize = ActualFileSize(isofile->handle); + + isofile->filesectorsize = isofile->filebytesize / isofile->blocksize; + + isofile->filebytepos = 0; + + isofile->filesectorpos = 0; + + } // ENDIF- Compressed or non-compressed? What a question. + + + + isofile->multinow = multinext; + + if(multinext == 0) { + + isofile->multioffset = 0; + + } else { + + isofile->multioffset = isofile->multisectorend[multinext - 1]; + + } // ENDIF- At the start of the list? Offset 0. + + } // ENDIF- Not looking at the same file? Change to the new one. + + + + tempfilesector = sector - isofile->multioffset; + + if(isofile->compress > 0) { + + return(CompressSeek(isofile, tempfilesector)); + + } else { + + retval = ActualFileSeek(isofile->handle, + + (tempfilesector * isofile->blocksize) + + + isofile->imageheader); + + if(retval == 0) { + + isofile->filesectorpos = sector; + + isofile->filebytepos = (sector * isofile->blocksize) + + + isofile->imageheader; + + } // ENDIF- Sucessful? Adjust internals + + return(retval); + + } // ENDIF- Seek a position in a compressed file? + +} // END MultiFileSeek() + + + + + +int MultiFileRead(struct IsoFile *isofile, char *block) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_MULTIFILE + + PrintLog("CDVD multifile: MultiFileRead()"); + +#endif /* VERBOSE_FUNCTION_MULTIFILE */ + + + + if(isofile->filesectorpos >= isofile->filesectorsize) + + MultiFileSeek(isofile, isofile->sectorpos); + + + + if(isofile->compress > 0) { + + return(CompressRead(isofile, block)); + + } else { + + retval = ActualFileRead(isofile->handle, isofile->blocksize, block); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval == isofile->blocksize) isofile->filesectorpos++; + + return(retval); + + } // ENDIF- Read a compressed sector? + +} // END MultiFileRead() + + + + + +int MultiFileWrite(struct IsoFile *isofile, char *block) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_MULTIFILE + + PrintLog("CDVD multifile: MultiFileWrite()"); + +#endif /* VERBOSE_FUNCTION_MULTIFILE */ + + + + if(isofile->filebytesize + isofile->blocksize > FILESIZELIMIT) { + + if(isofile->compress > 0) { + + CompressClose(isofile); + + } else { + + ActualFileClose(isofile->handle); + + isofile->handle = ACTUALHANDLENULL; + + } // ENDIF- Close a compressed file? (or an uncompressed one?) + + if(isofile->multinow == 9) return(-1); // Over 10 files? Overflow! + + + + isofile->multioffset += isofile->filesectorsize; + + isofile->multinow++; + + isofile->multiend++; + +#ifdef VERBOSE_WARNING_MULTIFILE + + PrintLog("CDVD multifile: Changing to File %i", isofile->multinow); + +#endif /* VERBOSE_WARNING_MULTIFILE */ + + + + isofile->name[isofile->multipos] = '0' + isofile->multinow; + + if(isofile->compress > 0) { + + retval = CompressOpenForWrite(isofile); + + } else { + + isofile->handle = ActualFileOpenForWrite(isofile->name); + + if(isofile->handle == ACTUALHANDLENULL) { + + retval = -1; + + } else { + + retval = 0; + + isofile->filebytesize = 0; + + isofile->filesectorsize = 0; + + isofile->filebytepos = 0; + + isofile->filesectorpos = 0; + + } // ENDIF- Trouble opening next file? + + } // ENDIF- Opening the next compressed file? (Or uncompressed?) + + if(retval < 0) return(-1); // Couldn't open another file? Abort. + + } // ENDIF- Hit the size limit? Move on to next file... + + + + if(isofile->compress > 0) { + + return(CompressWrite(isofile, block)); + + } else { + + retval = ActualFileWrite(isofile->handle, isofile->blocksize, block); + + if(retval > 0) isofile->filebytepos += retval; + + if(retval == isofile->blocksize) isofile->filesectorpos++; + + return(retval); + + } // ENDIF- Write a compressed sector? + +} // END MultiFileWrite() + diff --git a/plugins/CDVDisoEFP/src/multifile.h b/plugins/CDVDisoEFP/src/multifile.h index 66b81778a5..d46a397ff3 100644 --- a/plugins/CDVDisoEFP/src/multifile.h +++ b/plugins/CDVDisoEFP/src/multifile.h @@ -1,106 +1,106 @@ -/* multifile.h - - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - * - - * PCSX2 members can be contacted through their website at www.pcsx2.net. - - */ - - - - - -#ifndef MULTIFILE_H - -#define MULTIFILE_H - - - - - -// #ifndef __LINUX__ - -// #ifdef __linux__ - -// #define __LINUX__ - -// #endif /* __linux__ */ - -// #endif /* No __LINUX__ */ - - - -// #define CDVDdefs - -// #include "PS2Edefs.h" - - - -#include "isofile.h" - - - - - -// #define VERBOSE_FUNCTION_MULTIFILE - -// #define VERBOSE_WARNING_MULTIFILE - - - - - -extern char *multinames[]; - - - - - -extern void IsoNameStripMulti(struct IsoFile *isofile); - - - -extern int MultiFileSeek(struct IsoFile *isofile, off64_t sector); - -extern int MultiFileRead(struct IsoFile *isofile, char *block); - - - -extern int MultiFileWrite(struct IsoFile *isofile, char *block); - - - - - -#endif /* MULTIFILE_H */ - +/* multifile.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef MULTIFILE_H + +#define MULTIFILE_H + + + + + +// #ifndef __LINUX__ + +// #ifdef __linux__ + +// #define __LINUX__ + +// #endif /* __linux__ */ + +// #endif /* No __LINUX__ */ + + + +// #define CDVDdefs + +// #include "PS2Edefs.h" + + + +#include "isofile.h" + + + + + +// #define VERBOSE_FUNCTION_MULTIFILE + +// #define VERBOSE_WARNING_MULTIFILE + + + + + +extern char *multinames[]; + + + + + +extern void IsoNameStripMulti(struct IsoFile *isofile); + + + +extern int MultiFileSeek(struct IsoFile *isofile, off64_t sector); + +extern int MultiFileRead(struct IsoFile *isofile, char *block); + + + +extern int MultiFileWrite(struct IsoFile *isofile, char *block); + + + + + +#endif /* MULTIFILE_H */ + diff --git a/plugins/CDVDisoEFP/src/version.c b/plugins/CDVDisoEFP/src/version.c index f8d053f30f..44ebe48aa5 100644 --- a/plugins/CDVDisoEFP/src/version.c +++ b/plugins/CDVDisoEFP/src/version.c @@ -1,36 +1,72 @@ -/* version.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef __LINUX__ -#ifdef __linux__ -#define __LINUX__ -#endif /* __linux__ */ -#endif /* No __LINUX__ */ - -#define CDVDdefs -#include "PS2Edefs.h" - - -char *libname = "EFP Iso CDVD Driver"; - -const unsigned char version = PS2E_CDVD_VERSION; -const unsigned char revision = 0; -const unsigned char build = 6; +/* version.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef __LINUX__ + +#ifdef __linux__ + +#define __LINUX__ + +#endif /* __linux__ */ + +#endif /* No __LINUX__ */ + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + + + +char *libname = "EFP Iso CDVD Driver"; + + + +const unsigned char version = PS2E_CDVD_VERSION; + +const unsigned char revision = 0; + +const unsigned char build = 6; + diff --git a/plugins/CDVDisoEFP/src/version.h b/plugins/CDVDisoEFP/src/version.h index 774ce3b29a..2fb4b2751c 100644 --- a/plugins/CDVDisoEFP/src/version.h +++ b/plugins/CDVDisoEFP/src/version.h @@ -1,43 +1,86 @@ -/* version.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef VERSION_H -#define VERSION_H - - -#ifndef __LINUX__ -#ifdef __linux__ -#define __LINUX__ -#endif /* __linux__ */ -#endif /* No __LINUX__ */ - -#define CDVDdefs -#include "PS2Edefs.h" - - -extern char *libname; - -extern const unsigned char version; -extern const unsigned char revision; -extern const unsigned char build; - - -#endif /* VERSION_H */ +/* version.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef VERSION_H + +#define VERSION_H + + + + + +#ifndef __LINUX__ + +#ifdef __linux__ + +#define __LINUX__ + +#endif /* __linux__ */ + +#endif /* No __LINUX__ */ + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + + + +extern char *libname; + + + +extern const unsigned char version; + +extern const unsigned char revision; + +extern const unsigned char build; + + + + + +#endif /* VERSION_H */ + diff --git a/plugins/CDVDisoEFP/src/zlib/adler32.c b/plugins/CDVDisoEFP/src/zlib/adler32.c index bc0842f01b..20dd55c94b 100644 --- a/plugins/CDVDisoEFP/src/zlib/adler32.c +++ b/plugins/CDVDisoEFP/src/zlib/adler32.c @@ -1,74 +1,74 @@ -/* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id: adler32.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -#define BASE 65521UL /* largest prime smaller than 65536 */ -#define NMAX 5552 -/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ - -#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} -#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); -#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); -#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); -#define DO16(buf) DO8(buf,0); DO8(buf,8); - -#ifdef NO_DIVIDE -# define MOD(a) \ - do { \ - if (a >= (BASE << 16)) a -= (BASE << 16); \ - if (a >= (BASE << 15)) a -= (BASE << 15); \ - if (a >= (BASE << 14)) a -= (BASE << 14); \ - if (a >= (BASE << 13)) a -= (BASE << 13); \ - if (a >= (BASE << 12)) a -= (BASE << 12); \ - if (a >= (BASE << 11)) a -= (BASE << 11); \ - if (a >= (BASE << 10)) a -= (BASE << 10); \ - if (a >= (BASE << 9)) a -= (BASE << 9); \ - if (a >= (BASE << 8)) a -= (BASE << 8); \ - if (a >= (BASE << 7)) a -= (BASE << 7); \ - if (a >= (BASE << 6)) a -= (BASE << 6); \ - if (a >= (BASE << 5)) a -= (BASE << 5); \ - if (a >= (BASE << 4)) a -= (BASE << 4); \ - if (a >= (BASE << 3)) a -= (BASE << 3); \ - if (a >= (BASE << 2)) a -= (BASE << 2); \ - if (a >= (BASE << 1)) a -= (BASE << 1); \ - if (a >= BASE) a -= BASE; \ - } while (0) -#else -# define MOD(a) a %= BASE -#endif - -/* ========================================================================= */ -uLong ZEXPORT adler32(adler, buf, len) - uLong adler; - const Bytef *buf; - uInt len; -{ - unsigned long s1 = adler & 0xffff; - unsigned long s2 = (adler >> 16) & 0xffff; - int k; - - if (buf == Z_NULL) return 1L; - - while (len > 0) { - k = len < NMAX ? (int)len : NMAX; - len -= k; - while (k >= 16) { - DO16(buf); - buf += 16; - k -= 16; - } - if (k != 0) do { - s1 += *buf++; - s2 += s1; - } while (--k); - MOD(s1); - MOD(s2); - } - return (s2 << 16) | s1; -} +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: adler32.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? (int)len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + MOD(s1); + MOD(s2); + } + return (s2 << 16) | s1; +} diff --git a/plugins/CDVDisoEFP/src/zlib/compress.c b/plugins/CDVDisoEFP/src/zlib/compress.c index e7ea2c518b..87910ef046 100644 --- a/plugins/CDVDisoEFP/src/zlib/compress.c +++ b/plugins/CDVDisoEFP/src/zlib/compress.c @@ -1,79 +1,79 @@ -/* compress.c -- compress a memory buffer - * Copyright (C) 1995-2002 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id: compress.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -/* =========================================================================== - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least 0.1% larger than sourceLen plus - 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ -int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; - int level; -{ - z_stream stream; - int err; - - stream.next_in = (Bytef*)source; - stream.avail_in = (uInt)sourceLen; -#ifdef MAXSEG_64K - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; -#endif - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; - - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - stream.opaque = (voidpf)0; - - err = deflateInit(&stream, level); - if (err != Z_OK) return err; - - err = deflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - deflateEnd(&stream); - return err == Z_OK ? Z_BUF_ERROR : err; - } - *destLen = stream.total_out; - - err = deflateEnd(&stream); - return err; -} - -/* =========================================================================== - */ -int ZEXPORT compress (dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ - return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); -} - -/* =========================================================================== - If the default memLevel or windowBits for deflateInit() is changed, then - this function needs to be updated. - */ -uLong ZEXPORT compressBound (sourceLen) - uLong sourceLen; -{ - return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; -} +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: compress.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/plugins/CDVDisoEFP/src/zlib/crc32.c b/plugins/CDVDisoEFP/src/zlib/crc32.c index aa8b984a34..39db700d64 100644 --- a/plugins/CDVDisoEFP/src/zlib/crc32.c +++ b/plugins/CDVDisoEFP/src/zlib/crc32.c @@ -1,311 +1,311 @@ -/* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Thanks to Rodney Brown for his contribution of faster - * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing - * tables for updating the shift register in one step with three exclusive-ors - * instead of four steps with four exclusive-ors. This results about a factor - * of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. - */ - -/* @(#) $Id: crc32.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ - -#ifdef MAKECRCH -# include -# ifndef DYNAMIC_CRC_TABLE -# define DYNAMIC_CRC_TABLE -# endif /* !DYNAMIC_CRC_TABLE */ -#endif /* MAKECRCH */ - -#include "zutil.h" /* for STDC and FAR definitions */ - -#define local static - -/* Find a four-byte integer type for crc32_little() and crc32_big(). */ -#ifndef NOBYFOUR -# ifdef STDC /* need ANSI C limits.h to determine sizes */ -# include -# define BYFOUR -# if (UINT_MAX == 0xffffffffUL) - typedef unsigned int u4; -# else -# if (ULONG_MAX == 0xffffffffUL) - typedef unsigned long u4; -# else -# if (USHRT_MAX == 0xffffffffUL) - typedef unsigned short u4; -# else -# undef BYFOUR /* can't find a four-byte integer type! */ -# endif -# endif -# endif -# endif /* STDC */ -#endif /* !NOBYFOUR */ - -/* Definitions for doing the crc four data bytes at a time. */ -#ifdef BYFOUR -# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ - (((w)&0xff00)<<8)+(((w)&0xff)<<24)) - local unsigned long crc32_little OF((unsigned long, - const unsigned char FAR *, unsigned)); - local unsigned long crc32_big OF((unsigned long, - const unsigned char FAR *, unsigned)); -# define TBLS 8 -#else -# define TBLS 1 -#endif /* BYFOUR */ - -#ifdef DYNAMIC_CRC_TABLE - -local int crc_table_empty = 1; -local unsigned long FAR crc_table[TBLS][256]; -local void make_crc_table OF((void)); -#ifdef MAKECRCH - local void write_table OF((FILE *, const unsigned long FAR *)); -#endif /* MAKECRCH */ - -/* - Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: - x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. - - Polynomials over GF(2) are represented in binary, one bit per coefficient, - with the lowest powers in the most significant bit. Then adding polynomials - is just exclusive-or, and multiplying a polynomial by x is a right shift by - one. If we call the above polynomial p, and represent a byte as the - polynomial q, also with the lowest power in the most significant bit (so the - byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, - where a mod b means the remainder after dividing a by b. - - This calculation is done using the shift-register method of multiplying and - taking the remainder. The register is initialized to zero, and for each - incoming bit, x^32 is added mod p to the register if the bit is a one (where - x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by - x (which is shifting right by one and adding x^32 mod p if the bit shifted - out is a one). We start with the highest power (least significant bit) of - q and repeat for all eight bits of q. - - The first table is simply the CRC of all possible eight bit values. This is - all the information needed to generate CRCs on data a byte at a time for all - combinations of CRC register values and incoming bytes. The remaining tables - allow for word-at-a-time CRC calculation for both big-endian and little- - endian machines, where a word is four bytes. -*/ -local void make_crc_table() -{ - unsigned long c; - int n, k; - unsigned long poly; /* polynomial exclusive-or pattern */ - /* terms of polynomial defining this crc (except x^32): */ - static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - /* make exclusive-or pattern from polynomial (0xedb88320UL) */ - poly = 0UL; - for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) - poly |= 1UL << (31 - p[n]); - - /* generate a crc for every 8-bit value */ - for (n = 0; n < 256; n++) { - c = (unsigned long)n; - for (k = 0; k < 8; k++) - c = c & 1 ? poly ^ (c >> 1) : c >> 1; - crc_table[0][n] = c; - } - -#ifdef BYFOUR - /* generate crc for each value followed by one, two, and three zeros, and - then the byte reversal of those as well as the first table */ - for (n = 0; n < 256; n++) { - c = crc_table[0][n]; - crc_table[4][n] = REV(c); - for (k = 1; k < 4; k++) { - c = crc_table[0][c & 0xff] ^ (c >> 8); - crc_table[k][n] = c; - crc_table[k + 4][n] = REV(c); - } - } -#endif /* BYFOUR */ - - crc_table_empty = 0; - -#ifdef MAKECRCH - /* write out CRC tables to crc32.h */ - { - FILE *out; - - out = fopen("crc32.h", "w"); - if (out == NULL) return; - fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); - fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); - fprintf(out, "local const unsigned long FAR "); - fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); - write_table(out, crc_table[0]); -# ifdef BYFOUR - fprintf(out, "#ifdef BYFOUR\n"); - for (k = 1; k < 8; k++) { - fprintf(out, " },\n {\n"); - write_table(out, crc_table[k]); - } - fprintf(out, "#endif\n"); -# endif /* BYFOUR */ - fprintf(out, " }\n};\n"); - fclose(out); - } -#endif /* MAKECRCH */ -} - -#ifdef MAKECRCH -local void write_table(out, table) - FILE *out; - const unsigned long FAR *table; -{ - int n; - - for (n = 0; n < 256; n++) - fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], - n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); -} -#endif /* MAKECRCH */ - -#else /* !DYNAMIC_CRC_TABLE */ -/* ======================================================================== - * Tables of CRC-32s of all single-byte values, made by make_crc_table(). - */ -#include "crc32.h" -#endif /* DYNAMIC_CRC_TABLE */ - -/* ========================================================================= - * This function can be used by asm versions of crc32() - */ -const unsigned long FAR * ZEXPORT get_crc_table() -{ -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) make_crc_table(); -#endif /* DYNAMIC_CRC_TABLE */ - return (const unsigned long FAR *)crc_table; -} - -/* ========================================================================= */ -#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) -#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 - -/* ========================================================================= */ -unsigned long ZEXPORT crc32(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - if (buf == Z_NULL) return 0UL; - -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); -#endif /* DYNAMIC_CRC_TABLE */ - -#ifdef BYFOUR - if (sizeof(void *) == sizeof(ptrdiff_t)) { - u4 endian; - - endian = 1; - if (*((unsigned char *)(&endian))) - return crc32_little(crc, buf, len); - else - return crc32_big(crc, buf, len); - } -#endif /* BYFOUR */ - crc = crc ^ 0xffffffffUL; - while (len >= 8) { - DO8; - len -= 8; - } - if (len) do { - DO1; - } while (--len); - return crc ^ 0xffffffffUL; -} - -#ifdef BYFOUR - -/* ========================================================================= */ -#define DOLIT4 c ^= *buf4++; \ - c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ - crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] -#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 - -/* ========================================================================= */ -local unsigned long crc32_little(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - register u4 c; - register const u4 FAR *buf4; - - c = (u4)crc; - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - len--; - } - - buf4 = (const u4 FAR *)buf; - while (len >= 32) { - DOLIT32; - len -= 32; - } - while (len >= 4) { - DOLIT4; - len -= 4; - } - buf = (const unsigned char FAR *)buf4; - - if (len) do { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - } while (--len); - c = ~c; - return (unsigned long)c; -} - -/* ========================================================================= */ -#define DOBIG4 c ^= *++buf4; \ - c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ - crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] -#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 - -/* ========================================================================= */ -local unsigned long crc32_big(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - register u4 c; - register const u4 FAR *buf4; - - c = REV((u4)crc); - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - len--; - } - - buf4 = (const u4 FAR *)buf; - buf4--; - while (len >= 32) { - DOBIG32; - len -= 32; - } - while (len >= 4) { - DOBIG4; - len -= 4; - } - buf4++; - buf = (const unsigned char FAR *)buf4; - - if (len) do { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - } while (--len); - c = ~c; - return (unsigned long)(REV(c)); -} - -#endif /* BYFOUR */ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results about a factor + * of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id: crc32.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +#ifdef DYNAMIC_CRC_TABLE + +local int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ + +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, and + then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ diff --git a/plugins/CDVDisoEFP/src/zlib/crc32.h b/plugins/CDVDisoEFP/src/zlib/crc32.h index 5de49bc978..8053b6117c 100644 --- a/plugins/CDVDisoEFP/src/zlib/crc32.h +++ b/plugins/CDVDisoEFP/src/zlib/crc32.h @@ -1,441 +1,441 @@ -/* crc32.h -- tables for rapid CRC calculation - * Generated automatically by crc32.c - */ - -local const unsigned long FAR crc_table[TBLS][256] = -{ - { - 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, - 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, - 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, - 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, - 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, - 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, - 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, - 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, - 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, - 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, - 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, - 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, - 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, - 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, - 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, - 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, - 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, - 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, - 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, - 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, - 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, - 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, - 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, - 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, - 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, - 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, - 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, - 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, - 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, - 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, - 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, - 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, - 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, - 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, - 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, - 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, - 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, - 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, - 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, - 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, - 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, - 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, - 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, - 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, - 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, - 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, - 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, - 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, - 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, - 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, - 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, - 0x2d02ef8dUL -#ifdef BYFOUR - }, - { - 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, - 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, - 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, - 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, - 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, - 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, - 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, - 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, - 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, - 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, - 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, - 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, - 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, - 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, - 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, - 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, - 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, - 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, - 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, - 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, - 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, - 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, - 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, - 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, - 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, - 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, - 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, - 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, - 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, - 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, - 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, - 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, - 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, - 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, - 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, - 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, - 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, - 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, - 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, - 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, - 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, - 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, - 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, - 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, - 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, - 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, - 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, - 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, - 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, - 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, - 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, - 0x9324fd72UL - }, - { - 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, - 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, - 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, - 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, - 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, - 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, - 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, - 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, - 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, - 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, - 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, - 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, - 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, - 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, - 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, - 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, - 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, - 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, - 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, - 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, - 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, - 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, - 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, - 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, - 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, - 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, - 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, - 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, - 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, - 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, - 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, - 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, - 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, - 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, - 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, - 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, - 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, - 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, - 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, - 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, - 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, - 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, - 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, - 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, - 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, - 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, - 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, - 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, - 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, - 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, - 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, - 0xbe9834edUL - }, - { - 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, - 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, - 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, - 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, - 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, - 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, - 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, - 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, - 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, - 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, - 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, - 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, - 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, - 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, - 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, - 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, - 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, - 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, - 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, - 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, - 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, - 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, - 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, - 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, - 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, - 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, - 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, - 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, - 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, - 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, - 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, - 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, - 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, - 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, - 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, - 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, - 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, - 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, - 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, - 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, - 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, - 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, - 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, - 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, - 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, - 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, - 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, - 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, - 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, - 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, - 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, - 0xde0506f1UL - }, - { - 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, - 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, - 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, - 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, - 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, - 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, - 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, - 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, - 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, - 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, - 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, - 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, - 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, - 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, - 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, - 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, - 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, - 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, - 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, - 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, - 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, - 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, - 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, - 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, - 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, - 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, - 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, - 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, - 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, - 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, - 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, - 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, - 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, - 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, - 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, - 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, - 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, - 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, - 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, - 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, - 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, - 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, - 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, - 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, - 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, - 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, - 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, - 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, - 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, - 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, - 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, - 0x8def022dUL - }, - { - 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, - 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, - 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, - 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, - 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, - 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, - 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, - 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, - 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, - 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, - 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, - 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, - 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, - 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, - 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, - 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, - 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, - 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, - 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, - 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, - 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, - 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, - 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, - 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, - 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, - 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, - 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, - 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, - 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, - 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, - 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, - 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, - 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, - 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, - 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, - 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, - 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, - 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, - 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, - 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, - 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, - 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, - 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, - 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, - 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, - 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, - 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, - 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, - 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, - 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, - 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, - 0x72fd2493UL - }, - { - 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, - 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, - 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, - 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, - 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, - 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, - 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, - 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, - 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, - 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, - 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, - 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, - 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, - 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, - 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, - 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, - 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, - 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, - 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, - 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, - 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, - 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, - 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, - 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, - 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, - 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, - 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, - 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, - 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, - 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, - 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, - 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, - 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, - 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, - 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, - 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, - 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, - 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, - 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, - 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, - 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, - 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, - 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, - 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, - 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, - 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, - 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, - 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, - 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, - 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, - 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, - 0xed3498beUL - }, - { - 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, - 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, - 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, - 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, - 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, - 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, - 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, - 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, - 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, - 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, - 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, - 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, - 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, - 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, - 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, - 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, - 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, - 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, - 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, - 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, - 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, - 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, - 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, - 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, - 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, - 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, - 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, - 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, - 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, - 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, - 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, - 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, - 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, - 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, - 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, - 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, - 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, - 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, - 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, - 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, - 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, - 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, - 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, - 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, - 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, - 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, - 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, - 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, - 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, - 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, - 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, - 0xf10605deUL -#endif - } -}; +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/plugins/CDVDisoEFP/src/zlib/deflate.c b/plugins/CDVDisoEFP/src/zlib/deflate.c index efe7b63aba..10374817ad 100644 --- a/plugins/CDVDisoEFP/src/zlib/deflate.c +++ b/plugins/CDVDisoEFP/src/zlib/deflate.c @@ -1,1502 +1,1502 @@ -/* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process depends on being able to identify portions - * of the input text which are identical to earlier input (within a - * sliding window trailing behind the input currently being processed). - * - * The most straightforward technique turns out to be the fastest for - * most input files: try all possible matches and select the longest. - * The key feature of this algorithm is that insertions into the string - * dictionary are very simple and thus fast, and deletions are avoided - * completely. Insertions are performed at each input character, whereas - * string matches are performed only when the previous match ends. So it - * is preferable to spend more time in matches to allow very fast string - * insertions and avoid deletions. The matching algorithm for small - * strings is inspired from that of Rabin & Karp. A brute force approach - * is used to find longer strings when a small match has been found. - * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze - * (by Leonid Broukhis). - * A previous version of this file used a more sophisticated algorithm - * (by Fiala and Greene) which is guaranteed to run in linear amortized - * time, but has a larger average cost, uses more memory and is patented. - * However the F&G algorithm may be faster for some highly redundant - * files if the parameter max_chain_length (described below) is too large. - * - * ACKNOWLEDGEMENTS - * - * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and - * I found it in 'freeze' written by Leonid Broukhis. - * Thanks to many people for bug reports and testing. - * - * REFERENCES - * - * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". - * Available in http://www.ietf.org/rfc/rfc1951.txt - * - * A description of the Rabin and Karp algorithm is given in the book - * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. - * - * Fiala,E.R., and Greene,D.H. - * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 - * - */ - -/* @(#) $Id: deflate.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ - -#include "deflate.h" - -const char deflate_copyright[] = - " deflate 1.2.1 Copyright 1995-2003 Jean-loup Gailly "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* =========================================================================== - * Function prototypes. - */ -typedef enum { - need_more, /* block not completed, need more input or more output */ - block_done, /* block flush performed */ - finish_started, /* finish started, need only more output at next deflate */ - finish_done /* finish done, accept no more input or output */ -} block_state; - -typedef block_state (*compress_func) OF((deflate_state *s, int flush)); -/* Compression function. Returns the block state after the call. */ - -local void fill_window OF((deflate_state *s)); -local block_state deflate_stored OF((deflate_state *s, int flush)); -local block_state deflate_fast OF((deflate_state *s, int flush)); -#ifndef FASTEST -local block_state deflate_slow OF((deflate_state *s, int flush)); -#endif -local void lm_init OF((deflate_state *s)); -local void putShortMSB OF((deflate_state *s, uInt b)); -local void flush_pending OF((z_streamp strm)); -local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); -#ifndef FASTEST -#ifdef ASMV - void match_init OF((void)); /* asm code initialization */ - uInt longest_match OF((deflate_state *s, IPos cur_match)); -#else -local uInt longest_match OF((deflate_state *s, IPos cur_match)); -#endif -#endif -local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); - -#ifdef DEBUG -local void check_match OF((deflate_state *s, IPos start, IPos match, - int length)); -#endif - -/* =========================================================================== - * Local data - */ - -#define NIL 0 -/* Tail of hash chains */ - -#ifndef TOO_FAR -# define TOO_FAR 4096 -#endif -/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -/* Values for max_lazy_match, good_match and max_chain_length, depending on - * the desired pack level (0..9). The values given below have been tuned to - * exclude worst case performance for pathological files. Better values may be - * found for specific files. - */ -typedef struct config_s { - ush good_length; /* reduce lazy search above this match length */ - ush max_lazy; /* do not perform lazy search above this match length */ - ush nice_length; /* quit search above this match length */ - ush max_chain; - compress_func func; -} config; - -#ifdef FASTEST -local const config configuration_table[2] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ -#else -local const config configuration_table[10] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ -/* 2 */ {4, 5, 16, 8, deflate_fast}, -/* 3 */ {4, 6, 32, 32, deflate_fast}, - -/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ -/* 5 */ {8, 16, 32, 32, deflate_slow}, -/* 6 */ {8, 16, 128, 128, deflate_slow}, -/* 7 */ {8, 32, 128, 256, deflate_slow}, -/* 8 */ {32, 128, 258, 1024, deflate_slow}, -/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ -#endif - -/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 - * For deflate_fast() (levels <= 3) good is ignored and lazy has a different - * meaning. - */ - -#define EQUAL 0 -/* result of memcmp for equal strings */ - -#ifndef NO_DUMMY_DECL -struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ -#endif - -/* =========================================================================== - * Update a hash value with the given input byte - * IN assertion: all calls to to UPDATE_HASH are made with consecutive - * input characters, so that a running hash key can be computed from the - * previous key instead of complete recalculation each time. - */ -#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) - - -/* =========================================================================== - * Insert string str in the dictionary and set match_head to the previous head - * of the hash chain (the most recent string with same hash key). Return - * the previous length of the hash chain. - * If this file is compiled with -DFASTEST, the compression level is forced - * to 1, and no hash chains are maintained. - * IN assertion: all calls to to INSERT_STRING are made with consecutive - * input characters and the first MIN_MATCH bytes of str are valid - * (except for the last MIN_MATCH-1 bytes of the input file). - */ -#ifdef FASTEST -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - match_head = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) -#else -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) -#endif - -/* =========================================================================== - * Initialize the hash table (avoiding 64K overflow for 16 bit systems). - * prev[] will be initialized on the fly. - */ -#define CLEAR_HASH(s) \ - s->head[s->hash_size-1] = NIL; \ - zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); - -/* ========================================================================= */ -int ZEXPORT deflateInit_(strm, level, version, stream_size) - z_streamp strm; - int level; - const char *version; - int stream_size; -{ - return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, version, stream_size); - /* To do: ignore strm->next_in if we use it as window */ -} - -/* ========================================================================= */ -int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, - version, stream_size) - z_streamp strm; - int level; - int method; - int windowBits; - int memLevel; - int strategy; - const char *version; - int stream_size; -{ - deflate_state *s; - int wrap = 1; - static const char my_version[] = ZLIB_VERSION; - - ushf *overlay; - /* We overlay pending_buf and d_buf+l_buf. This works since the average - * output size for (length,distance) codes is <= 24 bits. - */ - - if (version == Z_NULL || version[0] != my_version[0] || - stream_size != sizeof(z_stream)) { - return Z_VERSION_ERROR; - } - if (strm == Z_NULL) return Z_STREAM_ERROR; - - strm->msg = Z_NULL; - if (strm->zalloc == (alloc_func)0) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; - -#ifdef FASTEST - if (level != 0) level = 1; -#else - if (level == Z_DEFAULT_COMPRESSION) level = 6; -#endif - - if (windowBits < 0) { /* suppress zlib wrapper */ - wrap = 0; - windowBits = -windowBits; - } -#ifdef GZIP - else if (windowBits > 15) { - wrap = 2; /* write gzip wrapper instead */ - windowBits -= 16; - } -#endif - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || - windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_RLE) { - return Z_STREAM_ERROR; - } - if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ - s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); - if (s == Z_NULL) return Z_MEM_ERROR; - strm->state = (struct internal_state FAR *)s; - s->strm = strm; - - s->wrap = wrap; - s->w_bits = windowBits; - s->w_size = 1 << s->w_bits; - s->w_mask = s->w_size - 1; - - s->hash_bits = memLevel + 7; - s->hash_size = 1 << s->hash_bits; - s->hash_mask = s->hash_size - 1; - s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); - - s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); - s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); - s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); - - s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ - - overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); - s->pending_buf = (uchf *) overlay; - s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); - - if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || - s->pending_buf == Z_NULL) { - s->status = FINISH_STATE; - strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); - deflateEnd (strm); - return Z_MEM_ERROR; - } - s->d_buf = overlay + s->lit_bufsize/sizeof(ush); - s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; - - s->level = level; - s->strategy = strategy; - s->method = (Byte)method; - - return deflateReset(strm); -} - -/* ========================================================================= */ -int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) - z_streamp strm; - const Bytef *dictionary; - uInt dictLength; -{ - deflate_state *s; - uInt length = dictLength; - uInt n; - IPos hash_head = 0; - - if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || - strm->state->wrap == 2 || - (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) - return Z_STREAM_ERROR; - - s = strm->state; - if (s->wrap) - strm->adler = adler32(strm->adler, dictionary, dictLength); - - if (length < MIN_MATCH) return Z_OK; - if (length > MAX_DIST(s)) { - length = MAX_DIST(s); -#ifndef USE_DICT_HEAD - dictionary += dictLength - length; /* use the tail of the dictionary */ -#endif - } - zmemcpy(s->window, dictionary, length); - s->strstart = length; - s->block_start = (long)length; - - /* Insert all strings in the hash table (except for the last two bytes). - * s->lookahead stays null, so s->ins_h will be recomputed at the next - * call of fill_window. - */ - s->ins_h = s->window[0]; - UPDATE_HASH(s, s->ins_h, s->window[1]); - for (n = 0; n <= length - MIN_MATCH; n++) { - INSERT_STRING(s, n, hash_head); - } - if (hash_head) hash_head = 0; /* to make compiler happy */ - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateReset (strm) - z_streamp strm; -{ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL || - strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { - return Z_STREAM_ERROR; - } - - strm->total_in = strm->total_out = 0; - strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ - strm->data_type = Z_UNKNOWN; - - s = (deflate_state *)strm->state; - s->pending = 0; - s->pending_out = s->pending_buf; - - if (s->wrap < 0) { - s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ - } - s->status = s->wrap ? INIT_STATE : BUSY_STATE; - strm->adler = -#ifdef GZIP - s->wrap == 2 ? crc32(0L, Z_NULL, 0) : -#endif - adler32(0L, Z_NULL, 0); - s->last_flush = Z_NO_FLUSH; - - _tr_init(s); - lm_init(s); - - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflatePrime (strm, bits, value) - z_streamp strm; - int bits; - int value; -{ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - strm->state->bi_valid = bits; - strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateParams(strm, level, strategy) - z_streamp strm; - int level; - int strategy; -{ - deflate_state *s; - compress_func func; - int err = Z_OK; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - s = strm->state; - -#ifdef FASTEST - if (level != 0) level = 1; -#else - if (level == Z_DEFAULT_COMPRESSION) level = 6; -#endif - if (level < 0 || level > 9 || strategy < 0 || strategy > Z_RLE) { - return Z_STREAM_ERROR; - } - func = configuration_table[s->level].func; - - if (func != configuration_table[level].func && strm->total_in != 0) { - /* Flush the last buffer: */ - err = deflate(strm, Z_PARTIAL_FLUSH); - } - if (s->level != level) { - s->level = level; - s->max_lazy_match = configuration_table[level].max_lazy; - s->good_match = configuration_table[level].good_length; - s->nice_match = configuration_table[level].nice_length; - s->max_chain_length = configuration_table[level].max_chain; - } - s->strategy = strategy; - return err; -} - -/* ========================================================================= - * For the default windowBits of 15 and memLevel of 8, this function returns - * a close to exact, as well as small, upper bound on the compressed size. - * They are coded as constants here for a reason--if the #define's are - * changed, then this function needs to be changed as well. The return - * value for 15 and 8 only works for those exact settings. - * - * For any setting other than those defaults for windowBits and memLevel, - * the value returned is a conservative worst case for the maximum expansion - * resulting from using fixed blocks instead of stored blocks, which deflate - * can emit on compressed data for some combinations of the parameters. - * - * This function could be more sophisticated to provide closer upper bounds - * for every combination of windowBits and memLevel, as well as wrap. - * But even the conservative upper bound of about 14% expansion does not - * seem onerous for output buffer allocation. - */ -uLong ZEXPORT deflateBound(strm, sourceLen) - z_streamp strm; - uLong sourceLen; -{ - deflate_state *s; - uLong destLen; - - /* conservative upper bound */ - destLen = sourceLen + - ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; - - /* if can't get parameters, return conservative bound */ - if (strm == Z_NULL || strm->state == Z_NULL) - return destLen; - - /* if not default parameters, return conservative bound */ - s = strm->state; - if (s->w_bits != 15 || s->hash_bits != 8 + 7) - return destLen; - - /* default settings: return tight bound for that case */ - return compressBound(sourceLen); -} - -/* ========================================================================= - * Put a short in the pending buffer. The 16-bit value is put in MSB order. - * IN assertion: the stream state is correct and there is enough room in - * pending_buf. - */ -local void putShortMSB (s, b) - deflate_state *s; - uInt b; -{ - put_byte(s, (Byte)(b >> 8)); - put_byte(s, (Byte)(b & 0xff)); -} - -/* ========================================================================= - * Flush as much pending output as possible. All deflate() output goes - * through this function so some applications may wish to modify it - * to avoid allocating a large strm->next_out buffer and copying into it. - * (See also read_buf()). - */ -local void flush_pending(strm) - z_streamp strm; -{ - unsigned len = strm->state->pending; - - if (len > strm->avail_out) len = strm->avail_out; - if (len == 0) return; - - zmemcpy(strm->next_out, strm->state->pending_out, len); - strm->next_out += len; - strm->state->pending_out += len; - strm->total_out += len; - strm->avail_out -= len; - strm->state->pending -= len; - if (strm->state->pending == 0) { - strm->state->pending_out = strm->state->pending_buf; - } -} - -/* ========================================================================= */ -int ZEXPORT deflate (strm, flush) - z_streamp strm; - int flush; -{ - int old_flush; /* value of flush param for previous deflate call */ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL || - flush > Z_FINISH || flush < 0) { - return Z_STREAM_ERROR; - } - s = strm->state; - - if (strm->next_out == Z_NULL || - (strm->next_in == Z_NULL && strm->avail_in != 0) || - (s->status == FINISH_STATE && flush != Z_FINISH)) { - ERR_RETURN(strm, Z_STREAM_ERROR); - } - if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); - - s->strm = strm; /* just in case */ - old_flush = s->last_flush; - s->last_flush = flush; - - /* Write the header */ - if (s->status == INIT_STATE) { -#ifdef GZIP - if (s->wrap == 2) { - put_byte(s, 31); - put_byte(s, 139); - put_byte(s, 8); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, 255); - s->status = BUSY_STATE; - strm->adler = crc32(0L, Z_NULL, 0); - } - else -#endif - { - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; - uInt level_flags; - - if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) - level_flags = 0; - else if (s->level < 6) - level_flags = 1; - else if (s->level == 6) - level_flags = 2; - else - level_flags = 3; - header |= (level_flags << 6); - if (s->strstart != 0) header |= PRESET_DICT; - header += 31 - (header % 31); - - s->status = BUSY_STATE; - putShortMSB(s, header); - - /* Save the adler32 of the preset dictionary: */ - if (s->strstart != 0) { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - strm->adler = adler32(0L, Z_NULL, 0); - } - } - - /* Flush as much pending output as possible */ - if (s->pending != 0) { - flush_pending(strm); - if (strm->avail_out == 0) { - /* Since avail_out is 0, deflate will be called again with - * more output space, but possibly with both pending and - * avail_in equal to zero. There won't be anything to do, - * but this is not an error situation so make sure we - * return OK instead of BUF_ERROR at next call of deflate: - */ - s->last_flush = -1; - return Z_OK; - } - - /* Make sure there is something to do and avoid duplicate consecutive - * flushes. For repeated and useless calls with Z_FINISH, we keep - * returning Z_STREAM_END instead of Z_BUF_ERROR. - */ - } else if (strm->avail_in == 0 && flush <= old_flush && - flush != Z_FINISH) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* User must not provide more input after the first FINISH: */ - if (s->status == FINISH_STATE && strm->avail_in != 0) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* Start a new block or continue the current one. - */ - if (strm->avail_in != 0 || s->lookahead != 0 || - (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { - block_state bstate; - - bstate = (*(configuration_table[s->level].func))(s, flush); - - if (bstate == finish_started || bstate == finish_done) { - s->status = FINISH_STATE; - } - if (bstate == need_more || bstate == finish_started) { - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ - } - return Z_OK; - /* If flush != Z_NO_FLUSH && avail_out == 0, the next call - * of deflate should use the same flush parameter to make sure - * that the flush is complete. So we don't have to output an - * empty block here, this will be done at next call. This also - * ensures that for a very small output buffer, we emit at most - * one empty block. - */ - } - if (bstate == block_done) { - if (flush == Z_PARTIAL_FLUSH) { - _tr_align(s); - } else { /* FULL_FLUSH or SYNC_FLUSH */ - _tr_stored_block(s, (char*)0, 0L, 0); - /* For a full flush, this empty block will be recognized - * as a special marker by inflate_sync(). - */ - if (flush == Z_FULL_FLUSH) { - CLEAR_HASH(s); /* forget history */ - } - } - flush_pending(strm); - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ - return Z_OK; - } - } - } - Assert(strm->avail_out > 0, "bug2"); - - if (flush != Z_FINISH) return Z_OK; - if (s->wrap <= 0) return Z_STREAM_END; - - /* Write the trailer */ -#ifdef GZIP - if (s->wrap == 2) { - put_byte(s, (Byte)(strm->adler & 0xff)); - put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); - put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); - put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); - put_byte(s, (Byte)(strm->total_in & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); - } - else -#endif - { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - flush_pending(strm); - /* If avail_out is zero, the application will call deflate again - * to flush the rest. - */ - if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ - return s->pending != 0 ? Z_OK : Z_STREAM_END; -} - -/* ========================================================================= */ -int ZEXPORT deflateEnd (strm) - z_streamp strm; -{ - int status; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - - status = strm->state->status; - if (status != INIT_STATE && status != BUSY_STATE && - status != FINISH_STATE) { - return Z_STREAM_ERROR; - } - - /* Deallocate in reverse order of allocations: */ - TRY_FREE(strm, strm->state->pending_buf); - TRY_FREE(strm, strm->state->head); - TRY_FREE(strm, strm->state->prev); - TRY_FREE(strm, strm->state->window); - - ZFREE(strm, strm->state); - strm->state = Z_NULL; - - return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; -} - -/* ========================================================================= - * Copy the source state to the destination state. - * To simplify the source, this is not supported for 16-bit MSDOS (which - * doesn't have enough memory anyway to duplicate compression states). - */ -int ZEXPORT deflateCopy (dest, source) - z_streamp dest; - z_streamp source; -{ -#ifdef MAXSEG_64K - return Z_STREAM_ERROR; -#else - deflate_state *ds; - deflate_state *ss; - ushf *overlay; - - - if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { - return Z_STREAM_ERROR; - } - - ss = source->state; - - *dest = *source; - - ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); - if (ds == Z_NULL) return Z_MEM_ERROR; - dest->state = (struct internal_state FAR *) ds; - *ds = *ss; - ds->strm = dest; - - ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); - ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); - ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); - overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); - ds->pending_buf = (uchf *) overlay; - - if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || - ds->pending_buf == Z_NULL) { - deflateEnd (dest); - return Z_MEM_ERROR; - } - /* following zmemcpy do not work for 16-bit MSDOS */ - zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); - zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); - zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); - zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); - - ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); - ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); - ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; - - ds->l_desc.dyn_tree = ds->dyn_ltree; - ds->d_desc.dyn_tree = ds->dyn_dtree; - ds->bl_desc.dyn_tree = ds->bl_tree; - - return Z_OK; -#endif /* MAXSEG_64K */ -} - -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->next_in buffer and copying from it. - * (See also flush_pending()). - */ -local int read_buf(strm, buf, size) - z_streamp strm; - Bytef *buf; - unsigned size; -{ - unsigned len = strm->avail_in; - - if (len > size) len = size; - if (len == 0) return 0; - - strm->avail_in -= len; - - if (strm->state->wrap == 1) { - strm->adler = adler32(strm->adler, strm->next_in, len); - } -#ifdef GZIP - else if (strm->state->wrap == 2) { - strm->adler = crc32(strm->adler, strm->next_in, len); - } -#endif - zmemcpy(buf, strm->next_in, len); - strm->next_in += len; - strm->total_in += len; - - return (int)len; -} - -/* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ -local void lm_init (s) - deflate_state *s; -{ - s->window_size = (ulg)2L*s->w_size; - - CLEAR_HASH(s); - - /* Set the default configuration parameters: - */ - s->max_lazy_match = configuration_table[s->level].max_lazy; - s->good_match = configuration_table[s->level].good_length; - s->nice_match = configuration_table[s->level].nice_length; - s->max_chain_length = configuration_table[s->level].max_chain; - - s->strstart = 0; - s->block_start = 0L; - s->lookahead = 0; - s->match_length = s->prev_length = MIN_MATCH-1; - s->match_available = 0; - s->ins_h = 0; -#ifdef ASMV - match_init(); /* initialize the asm code */ -#endif -} - -#ifndef FASTEST -/* =========================================================================== - * Set match_start to the longest match starting at the given string and - * return its length. Matches shorter or equal to prev_length are discarded, - * in which case the result is equal to prev_length and match_start is - * garbage. - * IN assertions: cur_match is the head of the hash chain for the current - * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 - * OUT assertion: the match length is not greater than s->lookahead. - */ -#ifndef ASMV -/* For 80x86 and 680x0, an optimized version will be provided in match.asm or - * match.S. The code will be functionally equivalent. - */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - unsigned chain_length = s->max_chain_length;/* max hash chain length */ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - int best_len = s->prev_length; /* best match length so far */ - int nice_match = s->nice_match; /* stop if match long enough */ - IPos limit = s->strstart > (IPos)MAX_DIST(s) ? - s->strstart - (IPos)MAX_DIST(s) : NIL; - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0. - */ - Posf *prev = s->prev; - uInt wmask = s->w_mask; - -#ifdef UNALIGNED_OK - /* Compare two bytes at a time. Note: this is not always beneficial. - * Try with and without -DUNALIGNED_OK to check. - */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; - register ush scan_start = *(ushf*)scan; - register ush scan_end = *(ushf*)(scan+best_len-1); -#else - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - register Byte scan_end1 = scan[best_len-1]; - register Byte scan_end = scan[best_len]; -#endif - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - /* Do not waste too much time if we already have a good match: */ - if (s->prev_length >= s->good_match) { - chain_length >>= 2; - } - /* Do not look for matches beyond the end of the input. This is necessary - * to make deflate deterministic. - */ - if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - do { - Assert(cur_match < s->strstart, "no future"); - match = s->window + cur_match; - - /* Skip to next match if the match length cannot increase - * or if the match length is less than 2: - */ -#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) - /* This code assumes sizeof(unsigned short) == 2. Do not use - * UNALIGNED_OK if your compiler uses a different size. - */ - if (*(ushf*)(match+best_len-1) != scan_end || - *(ushf*)match != scan_start) continue; - - /* It is not necessary to compare scan[2] and match[2] since they are - * always equal when the other bytes match, given that the hash keys - * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at - * strstart+3, +5, ... up to strstart+257. We check for insufficient - * lookahead only every 4th comparison; the 128th check will be made - * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is - * necessary to put more guard bytes at the end of the window, or - * to check more often for insufficient lookahead. - */ - Assert(scan[2] == match[2], "scan[2]?"); - scan++, match++; - do { - } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - scan < strend); - /* The funny "do {}" generates better code on most compilers */ - - /* Here, scan <= window+strstart+257 */ - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - if (*scan == *match) scan++; - - len = (MAX_MATCH - 1) - (int)(strend-scan); - scan = strend - (MAX_MATCH-1); - -#else /* UNALIGNED_OK */ - - if (match[best_len] != scan_end || - match[best_len-1] != scan_end1 || - *match != *scan || - *++match != scan[1]) continue; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match++; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - scan = strend - MAX_MATCH; - -#endif /* UNALIGNED_OK */ - - if (len > best_len) { - s->match_start = cur_match; - best_len = len; - if (len >= nice_match) break; -#ifdef UNALIGNED_OK - scan_end = *(ushf*)(scan+best_len-1); -#else - scan_end1 = scan[best_len-1]; - scan_end = scan[best_len]; -#endif - } - } while ((cur_match = prev[cur_match & wmask]) > limit - && --chain_length != 0); - - if ((uInt)best_len <= s->lookahead) return (uInt)best_len; - return s->lookahead; -} -#endif /* ASMV */ -#endif /* FASTEST */ - -/* --------------------------------------------------------------------------- - * Optimized version for level == 1 or strategy == Z_RLE only - */ -local uInt longest_match_fast(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - Assert(cur_match < s->strstart, "no future"); - - match = s->window + cur_match; - - /* Return failure if the match length is less than 2: - */ - if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match += 2; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - - if (len < MIN_MATCH) return MIN_MATCH - 1; - - s->match_start = cur_match; - return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; -} - -#ifdef DEBUG -/* =========================================================================== - * Check that the match at match_start is indeed a match. - */ -local void check_match(s, start, match, length) - deflate_state *s; - IPos start, match; - int length; -{ - /* check that the match is indeed a match */ - if (zmemcmp(s->window + match, - s->window + start, length) != EQUAL) { - fprintf(stderr, " start %u, match %u, length %d\n", - start, match, length); - do { - fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); - } while (--length != 0); - z_error("invalid match"); - } - if (z_verbose > 1) { - fprintf(stderr,"\\[%d,%d]", start-match, length); - do { putc(s->window[start++], stderr); } while (--length != 0); - } -} -#else -# define check_match(s, start, match, length) -#endif /* DEBUG */ - -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ -local void fill_window(s) - deflate_state *s; -{ - register unsigned n, m; - register Posf *p; - unsigned more; /* Amount of free space at the end of the window. */ - uInt wsize = s->w_size; - - do { - more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); - - /* Deal with !@#$% 64K limit: */ - if (sizeof(int) <= 2) { - if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - more = wsize; - - } else if (more == (unsigned)(-1)) { - /* Very unlikely, but possible on 16 bit machine if - * strstart == 0 && lookahead == 1 (input done a byte at time) - */ - more--; - } - } - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (s->strstart >= wsize+MAX_DIST(s)) { - - zmemcpy(s->window, s->window+wsize, (unsigned)wsize); - s->match_start -= wsize; - s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ - s->block_start -= (long) wsize; - - /* Slide the hash table (could be avoided with 32 bit values - at the expense of memory usage). We slide even when level == 0 - to keep the hash table consistent if we switch back to level > 0 - later. (Using level 0 permanently is not an optimal usage of - zlib, so we don't care about this pathological case.) - */ - n = s->hash_size; - p = &s->head[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - } while (--n); - - n = wsize; -#ifndef FASTEST - p = &s->prev[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); -#endif - more += wsize; - } - if (s->strm->avail_in == 0) return; - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - Assert(more >= 2, "more < 2"); - - n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); - s->lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s->lookahead >= MIN_MATCH) { - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ - - } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); -} - -/* =========================================================================== - * Flush the current block, with given end-of-file flag. - * IN assertion: strstart is set to the end of the current match. - */ -#define FLUSH_BLOCK_ONLY(s, eof) { \ - _tr_flush_block(s, (s->block_start >= 0L ? \ - (charf *)&s->window[(unsigned)s->block_start] : \ - (charf *)Z_NULL), \ - (ulg)((long)s->strstart - s->block_start), \ - (eof)); \ - s->block_start = s->strstart; \ - flush_pending(s->strm); \ - Tracev((stderr,"[FLUSH]")); \ -} - -/* Same but force premature exit if necessary. */ -#define FLUSH_BLOCK(s, eof) { \ - FLUSH_BLOCK_ONLY(s, eof); \ - if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ -} - -/* =========================================================================== - * Copy without compression as much as possible from the input stream, return - * the current block state. - * This function does not insert new strings in the dictionary since - * uncompressible data is probably not useful. This function is used - * only for the level=0 compression option. - * NOTE: this function should be optimized to avoid extra copying from - * window to pending_buf. - */ -local block_state deflate_stored(s, flush) - deflate_state *s; - int flush; -{ - /* Stored blocks are limited to 0xffff bytes, pending_buf is limited - * to pending_buf_size, and each stored block has a 5 byte header: - */ - ulg max_block_size = 0xffff; - ulg max_start; - - if (max_block_size > s->pending_buf_size - 5) { - max_block_size = s->pending_buf_size - 5; - } - - /* Copy as much as possible from input to output: */ - for (;;) { - /* Fill the window as much as possible: */ - if (s->lookahead <= 1) { - - Assert(s->strstart < s->w_size+MAX_DIST(s) || - s->block_start >= (long)s->w_size, "slide too late"); - - fill_window(s); - if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; - - if (s->lookahead == 0) break; /* flush the current block */ - } - Assert(s->block_start >= 0L, "block gone"); - - s->strstart += s->lookahead; - s->lookahead = 0; - - /* Emit a stored block if pending_buf will be full: */ - max_start = s->block_start + max_block_size; - if (s->strstart == 0 || (ulg)s->strstart >= max_start) { - /* strstart == 0 is possible when wraparound on 16-bit machine */ - s->lookahead = (uInt)(s->strstart - max_start); - s->strstart = (uInt)max_start; - FLUSH_BLOCK(s, 0); - } - /* Flush if we may have to slide, otherwise block_start may become - * negative and the data will be gone: - */ - if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { - FLUSH_BLOCK(s, 0); - } - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} - -/* =========================================================================== - * Compress as much as possible from the input stream, return the current - * block state. - * This function does not perform lazy evaluation of matches and inserts - * new strings in the dictionary only for unmatched strings or for short - * matches. It is used only for the fast compression options. - */ -local block_state deflate_fast(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head = NIL; /* head of the hash chain */ - int bflush; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - * At this point we have always match_length < MIN_MATCH - */ - if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ -#ifdef FASTEST - if ((s->strategy < Z_HUFFMAN_ONLY) || - (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { - s->match_length = longest_match_fast (s, hash_head); - } -#else - if (s->strategy < Z_HUFFMAN_ONLY) { - s->match_length = longest_match (s, hash_head); - } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { - s->match_length = longest_match_fast (s, hash_head); - } -#endif - /* longest_match() or longest_match_fast() sets match_start */ - } - if (s->match_length >= MIN_MATCH) { - check_match(s, s->strstart, s->match_start, s->match_length); - - _tr_tally_dist(s, s->strstart - s->match_start, - s->match_length - MIN_MATCH, bflush); - - s->lookahead -= s->match_length; - - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ -#ifndef FASTEST - if (s->match_length <= s->max_insert_length && - s->lookahead >= MIN_MATCH) { - s->match_length--; /* string at strstart already in table */ - do { - s->strstart++; - INSERT_STRING(s, s->strstart, hash_head); - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. - */ - } while (--s->match_length != 0); - s->strstart++; - } else -#endif - { - s->strstart += s->match_length; - s->match_length = 0; - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not - * matter since it will be recomputed at next deflate call. - */ - } - } else { - /* No match, output a literal byte */ - Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - } - if (bflush) FLUSH_BLOCK(s, 0); - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} - -#ifndef FASTEST -/* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ -local block_state deflate_slow(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head = NIL; /* head of hash chain */ - int bflush; /* set if current block must be flushed */ - - /* Process the input block. */ - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - */ - s->prev_length = s->match_length, s->prev_match = s->match_start; - s->match_length = MIN_MATCH-1; - - if (hash_head != NIL && s->prev_length < s->max_lazy_match && - s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - if (s->strategy < Z_HUFFMAN_ONLY) { - s->match_length = longest_match (s, hash_head); - } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { - s->match_length = longest_match_fast (s, hash_head); - } - /* longest_match() or longest_match_fast() sets match_start */ - - if (s->match_length <= 5 && (s->strategy == Z_FILTERED -#if TOO_FAR <= 32767 - || (s->match_length == MIN_MATCH && - s->strstart - s->match_start > TOO_FAR) -#endif - )) { - - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - s->match_length = MIN_MATCH-1; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { - uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; - /* Do not insert strings in hash table beyond this. */ - - check_match(s, s->strstart-1, s->prev_match, s->prev_length); - - _tr_tally_dist(s, s->strstart -1 - s->prev_match, - s->prev_length - MIN_MATCH, bflush); - - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not - * enough lookahead, the last two strings are not inserted in - * the hash table. - */ - s->lookahead -= s->prev_length-1; - s->prev_length -= 2; - do { - if (++s->strstart <= max_insert) { - INSERT_STRING(s, s->strstart, hash_head); - } - } while (--s->prev_length != 0); - s->match_available = 0; - s->match_length = MIN_MATCH-1; - s->strstart++; - - if (bflush) FLUSH_BLOCK(s, 0); - - } else if (s->match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - if (bflush) { - FLUSH_BLOCK_ONLY(s, 0); - } - s->strstart++; - s->lookahead--; - if (s->strm->avail_out == 0) return need_more; - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - s->match_available = 1; - s->strstart++; - s->lookahead--; - } - } - Assert (flush != Z_NO_FLUSH, "no flush?"); - if (s->match_available) { - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - s->match_available = 0; - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} -#endif /* FASTEST */ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id: deflate.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.1 Copyright 1995-2003 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_RLE) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); +#ifndef USE_DICT_HEAD + dictionary += dictLength - length; /* use the tail of the dictionary */ +#endif + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_RLE) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, 255); + s->status = BUSY_STATE; + strm->adler = crc32(0L, Z_NULL, 0); + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + *dest = *source; + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + *ds = *ss; + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy < Z_HUFFMAN_ONLY) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy < Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy < Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ diff --git a/plugins/CDVDisoEFP/src/zlib/deflate.h b/plugins/CDVDisoEFP/src/zlib/deflate.h index 26775e9d12..08aa37c792 100644 --- a/plugins/CDVDisoEFP/src/zlib/deflate.h +++ b/plugins/CDVDisoEFP/src/zlib/deflate.h @@ -1,326 +1,326 @@ -/* deflate.h -- internal compression state - * Copyright (C) 1995-2002 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id: deflate.h,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ - -#ifndef DEFLATE_H -#define DEFLATE_H - -#include "zutil.h" - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer creation by deflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip encoding - should be left enabled. */ -#ifndef NO_GZIP -# define GZIP -#endif - -/* =========================================================================== - * Internal compression state. - */ - -#define LENGTH_CODES 29 -/* number of length codes, not counting the special END_BLOCK code */ - -#define LITERALS 256 -/* number of literal bytes 0..255 */ - -#define L_CODES (LITERALS+1+LENGTH_CODES) -/* number of Literal or Length codes, including the END_BLOCK code */ - -#define D_CODES 30 -/* number of distance codes */ - -#define BL_CODES 19 -/* number of codes used to transfer the bit lengths */ - -#define HEAP_SIZE (2*L_CODES+1) -/* maximum heap size */ - -#define MAX_BITS 15 -/* All codes must not exceed MAX_BITS bits */ - -#define INIT_STATE 42 -#define BUSY_STATE 113 -#define FINISH_STATE 666 -/* Stream status */ - - -/* Data structure describing a single value and its code string. */ -typedef struct ct_data_s { - union { - ush freq; /* frequency count */ - ush code; /* bit string */ - } fc; - union { - ush dad; /* father node in Huffman tree */ - ush len; /* length of bit string */ - } dl; -} FAR ct_data; - -#define Freq fc.freq -#define Code fc.code -#define Dad dl.dad -#define Len dl.len - -typedef struct static_tree_desc_s static_tree_desc; - -typedef struct tree_desc_s { - ct_data *dyn_tree; /* the dynamic tree */ - int max_code; /* largest code with non zero frequency */ - static_tree_desc *stat_desc; /* the corresponding static tree */ -} FAR tree_desc; - -typedef ush Pos; -typedef Pos FAR Posf; -typedef unsigned IPos; - -/* A Pos is an index in the character window. We use short instead of int to - * save space in the various tables. IPos is used only for parameter passing. - */ - -typedef struct internal_state { - z_streamp strm; /* pointer back to this zlib stream */ - int status; /* as the name implies */ - Bytef *pending_buf; /* output still pending */ - ulg pending_buf_size; /* size of pending_buf */ - Bytef *pending_out; /* next pending byte to output to the stream */ - int pending; /* nb of bytes in the pending buffer */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - Byte data_type; /* UNKNOWN, BINARY or ASCII */ - Byte method; /* STORED (for zip only) or DEFLATED */ - int last_flush; /* value of flush param for previous deflate call */ - - /* used by deflate.c: */ - - uInt w_size; /* LZ77 window size (32K by default) */ - uInt w_bits; /* log2(w_size) (8..16) */ - uInt w_mask; /* w_size - 1 */ - - Bytef *window; - /* Sliding window. Input bytes are read into the second half of the window, - * and move to the first half later to keep a dictionary of at least wSize - * bytes. With this organization, matches are limited to a distance of - * wSize-MAX_MATCH bytes, but this ensures that IO is always - * performed with a length multiple of the block size. Also, it limits - * the window size to 64K, which is quite useful on MSDOS. - * To do: use the user input buffer as sliding window. - */ - - ulg window_size; - /* Actual size of window: 2*wSize, except when the user input buffer - * is directly used as sliding window. - */ - - Posf *prev; - /* Link to older string with same hash index. To limit the size of this - * array to 64K, this link is maintained only for the last 32K strings. - * An index in this array is thus a window index modulo 32K. - */ - - Posf *head; /* Heads of the hash chains or NIL. */ - - uInt ins_h; /* hash index of string to be inserted */ - uInt hash_size; /* number of elements in hash table */ - uInt hash_bits; /* log2(hash_size) */ - uInt hash_mask; /* hash_size-1 */ - - uInt hash_shift; - /* Number of bits by which ins_h must be shifted at each input - * step. It must be such that after MIN_MATCH steps, the oldest - * byte no longer takes part in the hash key, that is: - * hash_shift * MIN_MATCH >= hash_bits - */ - - long block_start; - /* Window position at the beginning of the current output block. Gets - * negative when the window is moved backwards. - */ - - uInt match_length; /* length of best match */ - IPos prev_match; /* previous match */ - int match_available; /* set if previous match exists */ - uInt strstart; /* start of string to insert */ - uInt match_start; /* start of matching string */ - uInt lookahead; /* number of valid bytes ahead in window */ - - uInt prev_length; - /* Length of the best match at previous step. Matches not greater than this - * are discarded. This is used in the lazy match evaluation. - */ - - uInt max_chain_length; - /* To speed up deflation, hash chains are never searched beyond this - * length. A higher limit improves compression ratio but degrades the - * speed. - */ - - uInt max_lazy_match; - /* Attempt to find a better match only when the current match is strictly - * smaller than this value. This mechanism is used only for compression - * levels >= 4. - */ -# define max_insert_length max_lazy_match - /* Insert new strings in the hash table only if the match length is not - * greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 3. - */ - - int level; /* compression level (1..9) */ - int strategy; /* favor or force Huffman coding*/ - - uInt good_match; - /* Use a faster search when the previous match is longer than this */ - - int nice_match; /* Stop searching when current match exceeds this */ - - /* used by trees.c: */ - /* Didn't use ct_data typedef below to supress compiler warning */ - struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ - struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ - struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ - - struct tree_desc_s l_desc; /* desc. for literal tree */ - struct tree_desc_s d_desc; /* desc. for distance tree */ - struct tree_desc_s bl_desc; /* desc. for bit length tree */ - - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ - int heap_len; /* number of elements in the heap */ - int heap_max; /* element of largest frequency */ - /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - * The same heap array is used to build all trees. - */ - - uch depth[2*L_CODES+1]; - /* Depth of each subtree used as tie breaker for trees of equal frequency - */ - - uchf *l_buf; /* buffer for literals or lengths */ - - uInt lit_bufsize; - /* Size of match buffer for literals/lengths. There are 4 reasons for - * limiting lit_bufsize to 64K: - * - frequencies can be kept in 16 bit counters - * - if compression is not successful for the first block, all input - * data is still in the window so we can still emit a stored block even - * when input comes from standard input. (This can also be done for - * all blocks if lit_bufsize is not greater than 32K.) - * - if compression is not successful for a file smaller than 64K, we can - * even emit a stored file instead of a stored block (saving 5 bytes). - * This is applicable only for zip (not gzip or zlib). - * - creating new Huffman trees less frequently may not provide fast - * adaptation to changes in the input data statistics. (Take for - * example a binary file with poorly compressible code followed by - * a highly compressible string table.) Smaller buffer sizes give - * fast adaptation but have of course the overhead of transmitting - * trees more frequently. - * - I can't count above 4 - */ - - uInt last_lit; /* running index in l_buf */ - - ushf *d_buf; - /* Buffer for distances. To simplify the code, d_buf and l_buf have - * the same number of elements. To use different lengths, an extra flag - * array would be necessary. - */ - - ulg opt_len; /* bit length of current block with optimal trees */ - ulg static_len; /* bit length of current block with static trees */ - uInt matches; /* number of string matches in current block */ - int last_eob_len; /* bit length of EOB code for last block */ - -#ifdef DEBUG - ulg compressed_len; /* total bit length of compressed file mod 2^32 */ - ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ -#endif - - ush bi_buf; - /* Output buffer. bits are inserted starting at the bottom (least - * significant bits). - */ - int bi_valid; - /* Number of valid bits in bi_buf. All bits above the last valid bit - * are always zero. - */ - -} FAR deflate_state; - -/* Output a byte on the stream. - * IN assertion: there is enough room in pending_buf. - */ -#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} - - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) -/* In order to simplify the code, particularly on 16 bit machines, match - * distances are limited to MAX_DIST instead of WSIZE. - */ - - /* in trees.c */ -void _tr_init OF((deflate_state *s)); -int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); -void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); -void _tr_align OF((deflate_state *s)); -void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); - -#define d_code(dist) \ - ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) -/* Mapping from a distance to a distance code. dist is the distance - 1 and - * must not have side effects. _dist_code[256] and _dist_code[257] are never - * used. - */ - -#ifndef DEBUG -/* Inline versions of _tr_tally for speed: */ - -#if defined(GEN_TREES_H) || !defined(STDC) - extern uch _length_code[]; - extern uch _dist_code[]; -#else - extern const uch _length_code[]; - extern const uch _dist_code[]; -#endif - -# define _tr_tally_lit(s, c, flush) \ - { uch cc = (c); \ - s->d_buf[s->last_lit] = 0; \ - s->l_buf[s->last_lit++] = cc; \ - s->dyn_ltree[cc].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -# define _tr_tally_dist(s, distance, length, flush) \ - { uch len = (length); \ - ush dist = (distance); \ - s->d_buf[s->last_lit] = dist; \ - s->l_buf[s->last_lit++] = len; \ - dist--; \ - s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ - s->dyn_dtree[d_code(dist)].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -#else -# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) -# define _tr_tally_dist(s, distance, length, flush) \ - flush = _tr_tally(s, distance, length) -#endif - -#endif /* DEFLATE_H */ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2002 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: deflate.h,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + int pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + Byte data_type; /* UNKNOWN, BINARY or ASCII */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/plugins/CDVDisoEFP/src/zlib/gzio.c b/plugins/CDVDisoEFP/src/zlib/gzio.c index 4cfd64fc45..89d40993f5 100644 --- a/plugins/CDVDisoEFP/src/zlib/gzio.c +++ b/plugins/CDVDisoEFP/src/zlib/gzio.c @@ -1,1005 +1,1005 @@ -/* gzio.c -- IO on .gz files - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. - */ - -/* @(#) $Id: gzio.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ - -#include - -#include "zutil.h" - -#ifdef NO_DEFLATE /* for compatiblity with old definition */ -# define NO_GZCOMPRESS -#endif - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -#ifndef Z_BUFSIZE -# ifdef MAXSEG_64K -# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ -# else -# define Z_BUFSIZE 16384 -# endif -#endif -#ifndef Z_PRINTF_BUFSIZE -# define Z_PRINTF_BUFSIZE 4096 -#endif - -#ifdef __MVS__ -# pragma map (fdopen , "\174\174FDOPEN") - FILE *fdopen(int, const char *); -#endif - -#ifndef STDC -extern voidp malloc OF((uInt size)); -extern void free OF((voidpf ptr)); -#endif - -#define ALLOC(size) malloc(size) -#define TRYFREE(p) {if (p) free(p);} - -static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ - -/* gzip flag byte */ -#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ -#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ -#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ -#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ -#define COMMENT 0x10 /* bit 4 set: file comment present */ -#define RESERVED 0xE0 /* bits 5..7: reserved */ - -typedef struct gz_stream { - z_stream stream; - int z_err; /* error code for last stream operation */ - int z_eof; /* set if end of input file */ - FILE *file; /* .gz file */ - Byte *inbuf; /* input buffer */ - Byte *outbuf; /* output buffer */ - uLong crc; /* crc32 of uncompressed data */ - char *msg; /* error message */ - char *path; /* path name for debugging only */ - int transparent; /* 1 if input file is not a .gz file */ - char mode; /* 'w' or 'r' */ - z_off_t start; /* start of compressed data in file (header skipped) */ - z_off_t in; /* bytes into deflate or inflate */ - z_off_t out; /* bytes out of deflate or inflate */ - int back; /* one character push-back */ - int last; /* true if push-back is last character */ -} gz_stream; - - -local gzFile gz_open OF((const char *path, const char *mode, int fd)); -local int do_flush OF((gzFile file, int flush)); -local int get_byte OF((gz_stream *s)); -local void check_header OF((gz_stream *s)); -local int destroy OF((gz_stream *s)); -local void putLong OF((FILE *file, uLong x)); -local uLong getLong OF((gz_stream *s)); - -/* =========================================================================== - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb"). The file is given either by file descriptor - or path name (if fd == -1). - gz_open returns NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). -*/ -local gzFile gz_open (path, mode, fd) - const char *path; - const char *mode; - int fd; -{ - int err; - int level = Z_DEFAULT_COMPRESSION; /* compression level */ - int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ - char *p = (char*)mode; - gz_stream *s; - char fmode[80]; /* copy of mode, without the compression level */ - char *m = fmode; - - if (!path || !mode) return Z_NULL; - - s = (gz_stream *)ALLOC(sizeof(gz_stream)); - if (!s) return Z_NULL; - - s->stream.zalloc = (alloc_func)0; - s->stream.zfree = (free_func)0; - s->stream.opaque = (voidpf)0; - s->stream.next_in = s->inbuf = Z_NULL; - s->stream.next_out = s->outbuf = Z_NULL; - s->stream.avail_in = s->stream.avail_out = 0; - s->file = NULL; - s->z_err = Z_OK; - s->z_eof = 0; - s->in = 0; - s->out = 0; - s->back = EOF; - s->crc = crc32(0L, Z_NULL, 0); - s->msg = NULL; - s->transparent = 0; - - s->path = (char*)ALLOC(strlen(path)+1); - if (s->path == NULL) { - return destroy(s), (gzFile)Z_NULL; - } - strcpy(s->path, path); /* do this early for debugging */ - - s->mode = '\0'; - do { - if (*p == 'r') s->mode = 'r'; - if (*p == 'w' || *p == 'a') s->mode = 'w'; - if (*p >= '0' && *p <= '9') { - level = *p - '0'; - } else if (*p == 'f') { - strategy = Z_FILTERED; - } else if (*p == 'h') { - strategy = Z_HUFFMAN_ONLY; - } else if (*p == 'R') { - strategy = Z_RLE; - } else { - *m++ = *p; /* copy the mode */ - } - } while (*p++ && m != fmode + sizeof(fmode)); - if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - err = Z_STREAM_ERROR; -#else - err = deflateInit2(&(s->stream), level, - Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); - /* windowBits is passed < 0 to suppress zlib header */ - - s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); -#endif - if (err != Z_OK || s->outbuf == Z_NULL) { - return destroy(s), (gzFile)Z_NULL; - } - } else { - s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); - - err = inflateInit2(&(s->stream), -MAX_WBITS); - /* windowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are - * present after the compressed stream. - */ - if (err != Z_OK || s->inbuf == Z_NULL) { - return destroy(s), (gzFile)Z_NULL; - } - } - s->stream.avail_out = Z_BUFSIZE; - - errno = 0; - s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); - - if (s->file == NULL) { - return destroy(s), (gzFile)Z_NULL; - } - if (s->mode == 'w') { - /* Write a very simple .gz header: - */ - fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], - Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); - s->start = 10L; - /* We use 10L instead of ftell(s->file) to because ftell causes an - * fflush on some systems. This version of the library doesn't use - * start anyway in write mode, so this initialization is not - * necessary. - */ - } else { - check_header(s); /* skip the .gz header */ - s->start = ftell(s->file) - s->stream.avail_in; - } - - return (gzFile)s; -} - -/* =========================================================================== - Opens a gzip (.gz) file for reading or writing. -*/ -gzFile ZEXPORT gzopen (path, mode) - const char *path; - const char *mode; -{ - return gz_open (path, mode, -1); -} - -/* =========================================================================== - Associate a gzFile with the file descriptor fd. fd is not dup'ed here - to mimic the behavio(u)r of fdopen. -*/ -gzFile ZEXPORT gzdopen (fd, mode) - int fd; - const char *mode; -{ - char name[20]; - - if (fd < 0) return (gzFile)Z_NULL; - sprintf(name, "", fd); /* for debugging */ - - return gz_open (name, mode, fd); -} - -/* =========================================================================== - * Update the compression level and strategy - */ -int ZEXPORT gzsetparams (file, level, strategy) - gzFile file; - int level; - int strategy; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - /* Make room to allow flushing */ - if (s->stream.avail_out == 0) { - - s->stream.next_out = s->outbuf; - if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { - s->z_err = Z_ERRNO; - } - s->stream.avail_out = Z_BUFSIZE; - } - - return deflateParams (&(s->stream), level, strategy); -} - -/* =========================================================================== - Read a byte from a gz_stream; update next_in and avail_in. Return EOF - for end of file. - IN assertion: the stream s has been sucessfully opened for reading. -*/ -local int get_byte(s) - gz_stream *s; -{ - if (s->z_eof) return EOF; - if (s->stream.avail_in == 0) { - errno = 0; - s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); - if (s->stream.avail_in == 0) { - s->z_eof = 1; - if (ferror(s->file)) s->z_err = Z_ERRNO; - return EOF; - } - s->stream.next_in = s->inbuf; - } - s->stream.avail_in--; - return *(s->stream.next_in)++; -} - -/* =========================================================================== - Check the gzip header of a gz_stream opened for reading. Set the stream - mode to transparent if the gzip magic header is not present; set s->err - to Z_DATA_ERROR if the magic header is present but the rest of the header - is incorrect. - IN assertion: the stream s has already been created sucessfully; - s->stream.avail_in is zero for the first time, but may be non-zero - for concatenated .gz files. -*/ -local void check_header(s) - gz_stream *s; -{ - int method; /* method byte */ - int flags; /* flags byte */ - uInt len; - int c; - - /* Assure two bytes in the buffer so we can peek ahead -- handle case - where first byte of header is at the end of the buffer after the last - gzip segment */ - len = s->stream.avail_in; - if (len < 2) { - if (len) s->inbuf[0] = s->stream.next_in[0]; - errno = 0; - len = fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); - if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; - s->stream.avail_in += len; - s->stream.next_in = s->inbuf; - if (s->stream.avail_in < 2) { - s->transparent = s->stream.avail_in; - return; - } - } - - /* Peek ahead to check the gzip magic header */ - if (s->stream.next_in[0] != gz_magic[0] || - s->stream.next_in[1] != gz_magic[1]) { - s->transparent = 1; - return; - } - s->stream.avail_in -= 2; - s->stream.next_in += 2; - - /* Check the rest of the gzip header */ - method = get_byte(s); - flags = get_byte(s); - if (method != Z_DEFLATED || (flags & RESERVED) != 0) { - s->z_err = Z_DATA_ERROR; - return; - } - - /* Discard time, xflags and OS code: */ - for (len = 0; len < 6; len++) (void)get_byte(s); - - if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ - len = (uInt)get_byte(s); - len += ((uInt)get_byte(s))<<8; - /* len is garbage if EOF but the loop below will quit anyway */ - while (len-- != 0 && get_byte(s) != EOF) ; - } - if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ - while ((c = get_byte(s)) != 0 && c != EOF) ; - } - if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ - while ((c = get_byte(s)) != 0 && c != EOF) ; - } - if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ - for (len = 0; len < 2; len++) (void)get_byte(s); - } - s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; -} - - /* =========================================================================== - * Cleanup then free the given gz_stream. Return a zlib error code. - Try freeing in the reverse order of allocations. - */ -local int destroy (s) - gz_stream *s; -{ - int err = Z_OK; - - if (!s) return Z_STREAM_ERROR; - - TRYFREE(s->msg); - - if (s->stream.state != NULL) { - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - err = Z_STREAM_ERROR; -#else - err = deflateEnd(&(s->stream)); -#endif - } else if (s->mode == 'r') { - err = inflateEnd(&(s->stream)); - } - } - if (s->file != NULL && fclose(s->file)) { -#ifdef ESPIPE - if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ -#endif - err = Z_ERRNO; - } - if (s->z_err < 0) err = s->z_err; - - TRYFREE(s->inbuf); - TRYFREE(s->outbuf); - TRYFREE(s->path); - TRYFREE(s); - return err; -} - -/* =========================================================================== - Reads the given number of uncompressed bytes from the compressed file. - gzread returns the number of bytes actually read (0 for end of file). -*/ -int ZEXPORT gzread (file, buf, len) - gzFile file; - voidp buf; - unsigned len; -{ - gz_stream *s = (gz_stream*)file; - Bytef *start = (Bytef*)buf; /* starting point for crc computation */ - Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ - - if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; - - if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; - if (s->z_err == Z_STREAM_END) return 0; /* EOF */ - - next_out = (Byte*)buf; - s->stream.next_out = (Bytef*)buf; - s->stream.avail_out = len; - - if (s->stream.avail_out && s->back != EOF) { - *next_out++ = s->back; - s->stream.next_out++; - s->stream.avail_out--; - s->back = EOF; - s->out++; - if (s->last) { - s->z_err = Z_STREAM_END; - return 1; - } - } - - while (s->stream.avail_out != 0) { - - if (s->transparent) { - /* Copy first the lookahead bytes: */ - uInt n = s->stream.avail_in; - if (n > s->stream.avail_out) n = s->stream.avail_out; - if (n > 0) { - zmemcpy(s->stream.next_out, s->stream.next_in, n); - next_out += n; - s->stream.next_out = next_out; - s->stream.next_in += n; - s->stream.avail_out -= n; - s->stream.avail_in -= n; - } - if (s->stream.avail_out > 0) { - s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, - s->file); - } - len -= s->stream.avail_out; - s->in += len; - s->out += len; - if (len == 0) s->z_eof = 1; - return (int)len; - } - if (s->stream.avail_in == 0 && !s->z_eof) { - - errno = 0; - s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); - if (s->stream.avail_in == 0) { - s->z_eof = 1; - if (ferror(s->file)) { - s->z_err = Z_ERRNO; - break; - } - } - s->stream.next_in = s->inbuf; - } - s->in += s->stream.avail_in; - s->out += s->stream.avail_out; - s->z_err = inflate(&(s->stream), Z_NO_FLUSH); - s->in -= s->stream.avail_in; - s->out -= s->stream.avail_out; - - if (s->z_err == Z_STREAM_END) { - /* Check CRC and original size */ - s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); - start = s->stream.next_out; - - if (getLong(s) != s->crc) { - s->z_err = Z_DATA_ERROR; - } else { - (void)getLong(s); - /* The uncompressed length returned by above getlong() may be - * different from s->out in case of concatenated .gz files. - * Check for such files: - */ - check_header(s); - if (s->z_err == Z_OK) { - inflateReset(&(s->stream)); - s->crc = crc32(0L, Z_NULL, 0); - } - } - } - if (s->z_err != Z_OK || s->z_eof) break; - } - s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); - - return (int)(len - s->stream.avail_out); -} - - -/* =========================================================================== - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. -*/ -int ZEXPORT gzgetc(file) - gzFile file; -{ - unsigned char c; - - return gzread(file, &c, 1) == 1 ? c : -1; -} - - -/* =========================================================================== - Push one byte back onto the stream. -*/ -int ZEXPORT gzungetc(c, file) - int c; - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; - s->back = c; - s->out--; - s->last = (s->z_err == Z_STREAM_END); - if (s->last) s->z_err = Z_OK; - s->z_eof = 0; - return c; -} - - -/* =========================================================================== - Reads bytes from the compressed file until len-1 characters are - read, or a newline character is read and transferred to buf, or an - end-of-file condition is encountered. The string is then terminated - with a null character. - gzgets returns buf, or Z_NULL in case of error. - - The current implementation is not optimized at all. -*/ -char * ZEXPORT gzgets(file, buf, len) - gzFile file; - char *buf; - int len; -{ - char *b = buf; - if (buf == Z_NULL || len <= 0) return Z_NULL; - - while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; - *buf = '\0'; - return b == buf && len > 0 ? Z_NULL : b; -} - - -#ifndef NO_GZCOMPRESS -/* =========================================================================== - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of bytes actually written (0 in case of error). -*/ -int ZEXPORT gzwrite (file, buf, len) - gzFile file; - voidpc buf; - unsigned len; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - s->stream.next_in = (Bytef*)buf; - s->stream.avail_in = len; - - while (s->stream.avail_in != 0) { - - if (s->stream.avail_out == 0) { - - s->stream.next_out = s->outbuf; - if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { - s->z_err = Z_ERRNO; - break; - } - s->stream.avail_out = Z_BUFSIZE; - } - s->in += s->stream.avail_in; - s->out += s->stream.avail_out; - s->z_err = deflate(&(s->stream), Z_NO_FLUSH); - s->in -= s->stream.avail_in; - s->out -= s->stream.avail_out; - if (s->z_err != Z_OK) break; - } - s->crc = crc32(s->crc, (const Bytef *)buf, len); - - return (int)(len - s->stream.avail_in); -} - - -/* =========================================================================== - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). -*/ -#ifdef STDC -#include - -int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) -{ - char buf[Z_PRINTF_BUFSIZE]; - va_list va; - int len; - - buf[sizeof(buf) - 1] = 0; - va_start(va, format); -#ifdef NO_vsnprintf -# ifdef HAS_vsprintf_void - (void)vsprintf(buf, format, va); - va_end(va); - for (len = 0; len < sizeof(buf); len++) - if (buf[len] == 0) break; -# else - len = vsprintf(buf, format, va); - va_end(va); -# endif -#else -# ifdef HAS_vsnprintf_void - (void)vsnprintf(buf, sizeof(buf), format, va); - va_end(va); - len = strlen(buf); -# else - len = vsnprintf(buf, sizeof(buf), format, va); - va_end(va); -# endif -#endif - if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) - return 0; - return gzwrite(file, buf, (unsigned)len); -} -#else /* not ANSI C */ - -int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) - gzFile file; - const char *format; - int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; -{ - char buf[Z_PRINTF_BUFSIZE]; - int len; - - buf[sizeof(buf) - 1] = 0; -#ifdef NO_snprintf -# ifdef HAS_sprintf_void - sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); - for (len = 0; len < sizeof(buf); len++) - if (buf[len] == 0) break; -# else - len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); -# endif -#else -# ifdef HAS_snprintf_void - snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); - len = strlen(buf); -# else - len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); -# endif -#endif - if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) - return 0; - return gzwrite(file, buf, len); -} -#endif - -/* =========================================================================== - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. -*/ -int ZEXPORT gzputc(file, c) - gzFile file; - int c; -{ - unsigned char cc = (unsigned char) c; /* required for big endian systems */ - - return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; -} - - -/* =========================================================================== - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. -*/ -int ZEXPORT gzputs(file, s) - gzFile file; - const char *s; -{ - return gzwrite(file, (char*)s, (unsigned)strlen(s)); -} - - -/* =========================================================================== - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. -*/ -local int do_flush (file, flush) - gzFile file; - int flush; -{ - uInt len; - int done = 0; - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - s->stream.avail_in = 0; /* should be zero already anyway */ - - for (;;) { - len = Z_BUFSIZE - s->stream.avail_out; - - if (len != 0) { - if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { - s->z_err = Z_ERRNO; - return Z_ERRNO; - } - s->stream.next_out = s->outbuf; - s->stream.avail_out = Z_BUFSIZE; - } - if (done) break; - s->out += s->stream.avail_out; - s->z_err = deflate(&(s->stream), flush); - s->out -= s->stream.avail_out; - - /* Ignore the second of two consecutive flushes: */ - if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; - - /* deflate has finished flushing only when it hasn't used up - * all the available space in the output buffer: - */ - done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); - - if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; - } - return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; -} - -int ZEXPORT gzflush (file, flush) - gzFile file; - int flush; -{ - gz_stream *s = (gz_stream*)file; - int err = do_flush (file, flush); - - if (err) return err; - fflush(s->file); - return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; -} -#endif /* NO_GZCOMPRESS */ - -/* =========================================================================== - Sets the starting position for the next gzread or gzwrite on the given - compressed file. The offset represents a number of bytes in the - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error. - SEEK_END is not implemented, returns error. - In this version of the library, gzseek can be extremely slow. -*/ -z_off_t ZEXPORT gzseek (file, offset, whence) - gzFile file; - z_off_t offset; - int whence; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || whence == SEEK_END || - s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { - return -1L; - } - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - return -1L; -#else - if (whence == SEEK_SET) { - offset -= s->in; - } - if (offset < 0) return -1L; - - /* At this point, offset is the number of zero bytes to write. */ - if (s->inbuf == Z_NULL) { - s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ - if (s->inbuf == Z_NULL) return -1L; - zmemzero(s->inbuf, Z_BUFSIZE); - } - while (offset > 0) { - uInt size = Z_BUFSIZE; - if (offset < Z_BUFSIZE) size = (uInt)offset; - - size = gzwrite(file, s->inbuf, size); - if (size == 0) return -1L; - - offset -= size; - } - return s->in; -#endif - } - /* Rest of function is for reading only */ - - /* compute absolute position */ - if (whence == SEEK_CUR) { - offset += s->out; - } - if (offset < 0) return -1L; - - if (s->transparent) { - /* map to fseek */ - s->back = EOF; - s->stream.avail_in = 0; - s->stream.next_in = s->inbuf; - if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; - - s->in = s->out = offset; - return offset; - } - - /* For a negative seek, rewind and use positive seek */ - if (offset >= s->out) { - offset -= s->out; - } else if (gzrewind(file) < 0) { - return -1L; - } - /* offset is now the number of bytes to skip. */ - - if (offset != 0 && s->outbuf == Z_NULL) { - s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); - if (s->outbuf == Z_NULL) return -1L; - } - if (offset && s->back != EOF) { - s->back = EOF; - s->out++; - offset--; - if (s->last) s->z_err = Z_STREAM_END; - } - while (offset > 0) { - int size = Z_BUFSIZE; - if (offset < Z_BUFSIZE) size = (int)offset; - - size = gzread(file, s->outbuf, (uInt)size); - if (size <= 0) return -1L; - offset -= size; - } - return s->out; -} - -/* =========================================================================== - Rewinds input file. -*/ -int ZEXPORT gzrewind (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'r') return -1; - - s->z_err = Z_OK; - s->z_eof = 0; - s->back = EOF; - s->stream.avail_in = 0; - s->stream.next_in = s->inbuf; - s->crc = crc32(0L, Z_NULL, 0); - if (!s->transparent) (void)inflateReset(&s->stream); - s->in = 0; - s->out = 0; - return fseek(s->file, s->start, SEEK_SET); -} - -/* =========================================================================== - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. -*/ -z_off_t ZEXPORT gztell (file) - gzFile file; -{ - return gzseek(file, 0L, SEEK_CUR); -} - -/* =========================================================================== - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. -*/ -int ZEXPORT gzeof (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - /* With concatenated compressed files that can have embedded - * crc trailers, z_eof is no longer the only/best indicator of EOF - * on a gz_stream. Handle end-of-stream error explicitly here. - */ - if (s == NULL || s->mode != 'r') return 0; - if (s->z_eof) return 1; - return s->z_err == Z_STREAM_END; -} - -/* =========================================================================== - Outputs a long in LSB order to the given file -*/ -local void putLong (file, x) - FILE *file; - uLong x; -{ - int n; - for (n = 0; n < 4; n++) { - fputc((int)(x & 0xff), file); - x >>= 8; - } -} - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets z_err in case - of error. -*/ -local uLong getLong (s) - gz_stream *s; -{ - uLong x = (uLong)get_byte(s); - int c; - - x += ((uLong)get_byte(s))<<8; - x += ((uLong)get_byte(s))<<16; - c = get_byte(s); - if (c == EOF) s->z_err = Z_DATA_ERROR; - x += ((uLong)c)<<24; - return x; -} - -/* =========================================================================== - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. -*/ -int ZEXPORT gzclose (file) - gzFile file; -{ - int err; - gz_stream *s = (gz_stream*)file; - - if (s == NULL) return Z_STREAM_ERROR; - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - return Z_STREAM_ERROR; -#else - err = do_flush (file, Z_FINISH); - if (err != Z_OK) return destroy((gz_stream*)file); - - putLong (s->file, s->crc); - putLong (s->file, (uLong)(s->in & 0xffffffff)); -#endif - } - return destroy((gz_stream*)file); -} - -/* =========================================================================== - Returns the error message for the last error which occured on the - given compressed file. errnum is set to zlib error number. If an - error occured in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. -*/ -const char * ZEXPORT gzerror (file, errnum) - gzFile file; - int *errnum; -{ - char *m; - gz_stream *s = (gz_stream*)file; - - if (s == NULL) { - *errnum = Z_STREAM_ERROR; - return (const char*)ERR_MSG(Z_STREAM_ERROR); - } - *errnum = s->z_err; - if (*errnum == Z_OK) return (const char*)""; - - m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); - - if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); - - TRYFREE(s->msg); - s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); - if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); - strcpy(s->msg, s->path); - strcat(s->msg, ": "); - strcat(s->msg, m); - return (const char*)s->msg; -} - -/* =========================================================================== - Clear the error and end-of-file flags, and do the same for the real file. -*/ -void ZEXPORT gzclearerr (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL) return; - if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; - s->z_eof = 0; - clearerr(s->file); -} +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id: gzio.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#include + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatiblity with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[20]; + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, + s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + int err; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + err = do_flush (file, Z_FINISH); + if (err != Z_OK) return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +/* =========================================================================== + Returns the error message for the last error which occured on the + given compressed file. errnum is set to zlib error number. If an + error occured in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/plugins/CDVDisoEFP/src/zlib/infback.c b/plugins/CDVDisoEFP/src/zlib/infback.c index 5cf5d22cf9..110b03b857 100644 --- a/plugins/CDVDisoEFP/src/zlib/infback.c +++ b/plugins/CDVDisoEFP/src/zlib/infback.c @@ -1,619 +1,619 @@ -/* infback.c -- inflate using a call-back interface - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - This code is largely copied from inflate.c. Normally either infback.o or - inflate.o would be linked into an application--not both. The interface - with inffast.c is retained so that optimized assembler-coded versions of - inflate_fast() can be used with either inflate.c or infback.c. - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -/* function prototypes */ -local void fixedtables OF((struct inflate_state FAR *state)); - -/* - strm provides memory allocation functions in zalloc and zfree, or - Z_NULL to use the library memory allocation functions. - - windowBits is in the range 8..15, and window is a user-supplied - window and output buffer that is 2**windowBits bytes. - */ -int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) -z_stream FAR *strm; -int windowBits; -unsigned char FAR *window; -const char *version; -int stream_size; -{ - struct inflate_state FAR *state; - - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != (int)(sizeof(z_stream))) - return Z_VERSION_ERROR; - if (strm == Z_NULL || window == Z_NULL || - windowBits < 8 || windowBits > 15) - return Z_STREAM_ERROR; - strm->msg = Z_NULL; /* in case we return an error */ - if (strm->zalloc == (alloc_func)0) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; - state = (struct inflate_state FAR *)ZALLOC(strm, 1, - sizeof(struct inflate_state)); - if (state == Z_NULL) return Z_MEM_ERROR; - Tracev((stderr, "inflate: allocated\n")); - strm->state = (voidpf)state; - state->wbits = windowBits; - state->wsize = 1U << windowBits; - state->window = window; - state->write = 0; - state->whave = 0; - return Z_OK; -} - -/* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ -#ifdef BUILDFIXED - static int virgin = 1; - static code *lenfix, *distfix; - static code fixed[544]; - - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - unsigned sym, bits; - static code *next; - - /* literal/length table */ - sym = 0; - while (sym < 144) state->lens[sym++] = 8; - while (sym < 256) state->lens[sym++] = 9; - while (sym < 280) state->lens[sym++] = 7; - while (sym < 288) state->lens[sym++] = 8; - next = fixed; - lenfix = next; - bits = 9; - inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); - - /* distance table */ - sym = 0; - while (sym < 32) state->lens[sym++] = 5; - distfix = next; - bits = 5; - inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); - - /* do this just once */ - virgin = 0; - } -#else /* !BUILDFIXED */ -# include "inffixed.h" -#endif /* BUILDFIXED */ - state->lencode = lenfix; - state->lenbits = 9; - state->distcode = distfix; - state->distbits = 5; -} - -/* Macros for inflateBack(): */ - -/* Load returned state from inflate_fast() */ -#define LOAD() \ - do { \ - put = strm->next_out; \ - left = strm->avail_out; \ - next = strm->next_in; \ - have = strm->avail_in; \ - hold = state->hold; \ - bits = state->bits; \ - } while (0) - -/* Set state from registers for inflate_fast() */ -#define RESTORE() \ - do { \ - strm->next_out = put; \ - strm->avail_out = left; \ - strm->next_in = next; \ - strm->avail_in = have; \ - state->hold = hold; \ - state->bits = bits; \ - } while (0) - -/* Clear the input bit accumulator */ -#define INITBITS() \ - do { \ - hold = 0; \ - bits = 0; \ - } while (0) - -/* Assure that some input is available. If input is requested, but denied, - then return a Z_BUF_ERROR from inflateBack(). */ -#define PULL() \ - do { \ - if (have == 0) { \ - have = in(in_desc, &next); \ - if (have == 0) { \ - next = Z_NULL; \ - ret = Z_BUF_ERROR; \ - goto inf_leave; \ - } \ - } \ - } while (0) - -/* Get a byte of input into the bit accumulator, or return from inflateBack() - with an error if there is no input available. */ -#define PULLBYTE() \ - do { \ - PULL(); \ - have--; \ - hold += (unsigned long)(*next++) << bits; \ - bits += 8; \ - } while (0) - -/* Assure that there are at least n bits in the bit accumulator. If there is - not enough available input to do that, then return from inflateBack() with - an error. */ -#define NEEDBITS(n) \ - do { \ - while (bits < (unsigned)(n)) \ - PULLBYTE(); \ - } while (0) - -/* Return the low n bits of the bit accumulator (n < 16) */ -#define BITS(n) \ - ((unsigned)hold & ((1U << (n)) - 1)) - -/* Remove n bits from the bit accumulator */ -#define DROPBITS(n) \ - do { \ - hold >>= (n); \ - bits -= (unsigned)(n); \ - } while (0) - -/* Remove zero to seven bits as needed to go to a byte boundary */ -#define BYTEBITS() \ - do { \ - hold >>= bits & 7; \ - bits -= bits & 7; \ - } while (0) - -/* Assure that some output space is available, by writing out the window - if it's full. If the write fails, return from inflateBack() with a - Z_BUF_ERROR. */ -#define ROOM() \ - do { \ - if (left == 0) { \ - put = state->window; \ - left = state->wsize; \ - state->whave = left; \ - if (out(out_desc, put, left)) { \ - ret = Z_BUF_ERROR; \ - goto inf_leave; \ - } \ - } \ - } while (0) - -/* - strm provides the memory allocation functions and window buffer on input, - and provides information on the unused input on return. For Z_DATA_ERROR - returns, strm will also provide an error message. - - in() and out() are the call-back input and output functions. When - inflateBack() needs more input, it calls in(). When inflateBack() has - filled the window with output, or when it completes with data in the - window, it calls out() to write out the data. The application must not - change the provided input until in() is called again or inflateBack() - returns. The application must not change the window/output buffer until - inflateBack() returns. - - in() and out() are called with a descriptor parameter provided in the - inflateBack() call. This parameter can be a structure that provides the - information required to do the read or write, as well as accumulated - information on the input and output such as totals and check values. - - in() should return zero on failure. out() should return non-zero on - failure. If either in() or out() fails, than inflateBack() returns a - Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it - was in() or out() that caused in the error. Otherwise, inflateBack() - returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format - error, or Z_MEM_ERROR if it could not allocate memory for the state. - inflateBack() can also return Z_STREAM_ERROR if the input parameters - are not correct, i.e. strm is Z_NULL or the state was not initialized. - */ -int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) -z_stream FAR *strm; -in_func in; -void FAR *in_desc; -out_func out; -void FAR *out_desc; -{ - struct inflate_state FAR *state; - unsigned char FAR *next; /* next input */ - unsigned char FAR *put; /* next output */ - unsigned have, left; /* available input and output */ - unsigned long hold; /* bit buffer */ - unsigned bits; /* bits in bit buffer */ - unsigned copy; /* number of stored or match bytes to copy */ - unsigned char FAR *from; /* where to copy match bytes from */ - code this; /* current decoding table entry */ - code last; /* parent table entry */ - unsigned len; /* length to copy for repeats, bits to drop */ - int ret; /* return code */ - static const unsigned short order[19] = /* permutation of code lengths */ - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - /* Check that the strm exists and that the state was initialized */ - if (strm == Z_NULL || strm->state == Z_NULL) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - - /* Reset the state */ - strm->msg = Z_NULL; - state->mode = TYPE; - state->last = 0; - state->whave = 0; - next = strm->next_in; - have = next != Z_NULL ? strm->avail_in : 0; - hold = 0; - bits = 0; - put = state->window; - left = state->wsize; - - /* Inflate until end of block marked as last */ - for (;;) - switch (state->mode) { - case TYPE: - /* determine and dispatch block type */ - if (state->last) { - BYTEBITS(); - state->mode = DONE; - break; - } - NEEDBITS(3); - state->last = BITS(1); - DROPBITS(1); - switch (BITS(2)) { - case 0: /* stored block */ - Tracev((stderr, "inflate: stored block%s\n", - state->last ? " (last)" : "")); - state->mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - Tracev((stderr, "inflate: fixed codes block%s\n", - state->last ? " (last)" : "")); - state->mode = LEN; /* decode codes */ - break; - case 2: /* dynamic block */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - state->last ? " (last)" : "")); - state->mode = TABLE; - break; - case 3: - strm->msg = (char *)"invalid block type"; - state->mode = BAD; - } - DROPBITS(2); - break; - - case STORED: - /* get and verify stored block length */ - BYTEBITS(); /* go to byte boundary */ - NEEDBITS(32); - if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - strm->msg = (char *)"invalid stored block lengths"; - state->mode = BAD; - break; - } - state->length = (unsigned)hold & 0xffff; - Tracev((stderr, "inflate: stored length %u\n", - state->length)); - INITBITS(); - - /* copy stored block from input to output */ - while (state->length != 0) { - copy = state->length; - PULL(); - ROOM(); - if (copy > have) copy = have; - if (copy > left) copy = left; - zmemcpy(put, next, copy); - have -= copy; - next += copy; - left -= copy; - put += copy; - state->length -= copy; - } - Tracev((stderr, "inflate: stored end\n")); - state->mode = TYPE; - break; - - case TABLE: - /* get dynamic table entries descriptor */ - NEEDBITS(14); - state->nlen = BITS(5) + 257; - DROPBITS(5); - state->ndist = BITS(5) + 1; - DROPBITS(5); - state->ncode = BITS(4) + 4; - DROPBITS(4); -#ifndef PKZIP_BUG_WORKAROUND - if (state->nlen > 286 || state->ndist > 30) { - strm->msg = (char *)"too many length or distance symbols"; - state->mode = BAD; - break; - } -#endif - Tracev((stderr, "inflate: table sizes ok\n")); - - /* get code length code lengths (not a typo) */ - state->have = 0; - while (state->have < state->ncode) { - NEEDBITS(3); - state->lens[order[state->have++]] = (unsigned short)BITS(3); - DROPBITS(3); - } - while (state->have < 19) - state->lens[order[state->have++]] = 0; - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 7; - ret = inflate_table(CODES, state->lens, 19, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid code lengths set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: code lengths ok\n")); - - /* get length and distance code code lengths */ - state->have = 0; - while (state->have < state->nlen + state->ndist) { - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.val < 16) { - NEEDBITS(this.bits); - DROPBITS(this.bits); - state->lens[state->have++] = this.val; - } - else { - if (this.val == 16) { - NEEDBITS(this.bits + 2); - DROPBITS(this.bits); - if (state->have == 0) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - len = (unsigned)(state->lens[state->have - 1]); - copy = 3 + BITS(2); - DROPBITS(2); - } - else if (this.val == 17) { - NEEDBITS(this.bits + 3); - DROPBITS(this.bits); - len = 0; - copy = 3 + BITS(3); - DROPBITS(3); - } - else { - NEEDBITS(this.bits + 7); - DROPBITS(this.bits); - len = 0; - copy = 11 + BITS(7); - DROPBITS(7); - } - if (state->have + copy > state->nlen + state->ndist) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - while (copy--) - state->lens[state->have++] = (unsigned short)len; - } - } - - /* build code tables */ - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 9; - ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid literal/lengths set"; - state->mode = BAD; - break; - } - state->distcode = (code const FAR *)(state->next); - state->distbits = 6; - ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, - &(state->next), &(state->distbits), state->work); - if (ret) { - strm->msg = (char *)"invalid distances set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: codes ok\n")); - state->mode = LEN; - - case LEN: - /* use inflate_fast() if we have enough input and output */ - if (have >= 6 && left >= 258) { - RESTORE(); - if (state->whave < state->wsize) - state->whave = state->wsize - left; - inflate_fast(strm, state->wsize); - LOAD(); - break; - } - - /* get a literal, length, or end-of-block code */ - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.op && (this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->lencode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - state->length = (unsigned)this.val; - - /* process literal */ - if (this.op == 0) { - Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", this.val)); - ROOM(); - *put++ = (unsigned char)(state->length); - left--; - state->mode = LEN; - break; - } - - /* process end of block */ - if (this.op & 32) { - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - - /* invalid code */ - if (this.op & 64) { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - - /* length code -- get extra bits, if any */ - state->extra = (unsigned)(this.op) & 15; - if (state->extra != 0) { - NEEDBITS(state->extra); - state->length += BITS(state->extra); - DROPBITS(state->extra); - } - Tracevv((stderr, "inflate: length %u\n", state->length)); - - /* get distance code */ - for (;;) { - this = state->distcode[BITS(state->distbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if ((this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->distcode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - if (this.op & 64) { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - state->offset = (unsigned)this.val; - - /* get distance extra bits, if any */ - state->extra = (unsigned)(this.op) & 15; - if (state->extra != 0) { - NEEDBITS(state->extra); - state->offset += BITS(state->extra); - DROPBITS(state->extra); - } - if (state->offset > state->wsize - (state->whave < state->wsize ? - left : 0)) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - Tracevv((stderr, "inflate: distance %u\n", state->offset)); - - /* copy match from window to output */ - do { - ROOM(); - copy = state->wsize - state->offset; - if (copy < left) { - from = put + copy; - copy = left - copy; - } - else { - from = put - state->offset; - copy = left; - } - if (copy > state->length) copy = state->length; - state->length -= copy; - left -= copy; - do { - *put++ = *from++; - } while (--copy); - } while (state->length != 0); - break; - - case DONE: - /* inflate stream terminated properly -- write leftover output */ - ret = Z_STREAM_END; - if (left < state->wsize) { - if (out(out_desc, state->window, state->wsize - left)) - ret = Z_BUF_ERROR; - } - goto inf_leave; - - case BAD: - ret = Z_DATA_ERROR; - goto inf_leave; - - default: /* can't happen, but makes compilers happy */ - ret = Z_STREAM_ERROR; - goto inf_leave; - } - - /* Return unused input */ - inf_leave: - strm->next_in = next; - strm->avail_in = have; - return ret; -} - -int ZEXPORT inflateBackEnd(strm) -z_stream FAR *strm; -{ - if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) - return Z_STREAM_ERROR; - ZFREE(strm, strm->state); - strm->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; -} +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_stream FAR *strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_stream FAR *strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_stream FAR *strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/plugins/CDVDisoEFP/src/zlib/inffast.c b/plugins/CDVDisoEFP/src/zlib/inffast.c index 63aa4402fc..c716440a92 100644 --- a/plugins/CDVDisoEFP/src/zlib/inffast.c +++ b/plugins/CDVDisoEFP/src/zlib/inffast.c @@ -1,305 +1,305 @@ -/* inffast.c -- fast decoding - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -#ifndef ASMINF - -/* Allow machine dependent optimization for post-increment or pre-increment. - Based on testing to date, - Pre-increment preferred for: - - PowerPC G3 (Adler) - - MIPS R5000 (Randers-Pehrson) - Post-increment preferred for: - - none - No measurable difference: - - Pentium III (Anderson) - - 68060 (Nikl) - */ -#ifdef POSTINC -# define OFF 0 -# define PUP(a) *(a)++ -#else -# define OFF 1 -# define PUP(a) *++(a) -#endif - -/* - Decode literal, length, and distance codes and write out the resulting - literal and match bytes until either not enough input or output is - available, an end-of-block is encountered, or a data error is encountered. - When large enough input and output buffers are supplied to inflate(), for - example, a 16K input buffer and a 64K output buffer, more than 95% of the - inflate execution time is spent in this routine. - - Entry assumptions: - - state->mode == LEN - strm->avail_in >= 6 - strm->avail_out >= 258 - start >= strm->avail_out - state->bits < 8 - - On return, state->mode is one of: - - LEN -- ran out of enough output space or enough available input - TYPE -- reached end of block code, inflate() to interpret next block - BAD -- error in block data - - Notes: - - - The maximum input bits used by a length/distance pair is 15 bits for the - length code, 5 bits for the length extra, 15 bits for the distance code, - and 13 bits for the distance extra. This totals 48 bits, or six bytes. - Therefore if strm->avail_in >= 6, then there is enough input to avoid - checking for available input while decoding. - - - The maximum bytes that a single length/distance pair can output is 258 - bytes, which is the maximum length that can be coded. inflate_fast() - requires strm->avail_out >= 258 for each loop to avoid checking for - output space. - */ -void inflate_fast(strm, start) -z_streamp strm; -unsigned start; /* inflate()'s starting value for strm->avail_out */ -{ - struct inflate_state FAR *state; - unsigned char FAR *in; /* local strm->next_in */ - unsigned char FAR *last; /* while in < last, enough input available */ - unsigned char FAR *out; /* local strm->next_out */ - unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ - unsigned char FAR *end; /* while out < end, enough space available */ - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned write; /* window write index */ - unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ - unsigned long hold; /* local strm->hold */ - unsigned bits; /* local strm->bits */ - code const FAR *lcode; /* local strm->lencode */ - code const FAR *dcode; /* local strm->distcode */ - unsigned lmask; /* mask for first level of length codes */ - unsigned dmask; /* mask for first level of distance codes */ - code this; /* retrieved table entry */ - unsigned op; /* code bits, operation, extra bits, or */ - /* window position, window bytes to copy */ - unsigned len; /* match length, unused bytes */ - unsigned dist; /* match distance */ - unsigned char FAR *from; /* where to copy match from */ - - /* copy state to local variables */ - state = (struct inflate_state FAR *)strm->state; - in = strm->next_in - OFF; - last = in + (strm->avail_in - 5); - out = strm->next_out - OFF; - beg = out - (start - strm->avail_out); - end = out + (strm->avail_out - 257); - wsize = state->wsize; - whave = state->whave; - write = state->write; - window = state->window; - hold = state->hold; - bits = state->bits; - lcode = state->lencode; - dcode = state->distcode; - lmask = (1U << state->lenbits) - 1; - dmask = (1U << state->distbits) - 1; - - /* decode literals and length/distances until end-of-block or not enough - input data or output space */ - do { - if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - this = lcode[hold & lmask]; - dolen: - op = (unsigned)(this.bits); - hold >>= op; - bits -= op; - op = (unsigned)(this.op); - if (op == 0) { /* literal */ - Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", this.val)); - PUP(out) = (unsigned char)(this.val); - } - else if (op & 16) { /* length base */ - len = (unsigned)(this.val); - op &= 15; /* number of extra bits */ - if (op) { - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - len += (unsigned)hold & ((1U << op) - 1); - hold >>= op; - bits -= op; - } - Tracevv((stderr, "inflate: length %u\n", len)); - if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - this = dcode[hold & dmask]; - dodist: - op = (unsigned)(this.bits); - hold >>= op; - bits -= op; - op = (unsigned)(this.op); - if (op & 16) { /* distance base */ - dist = (unsigned)(this.val); - op &= 15; /* number of extra bits */ - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - } - dist += (unsigned)hold & ((1U << op) - 1); - hold >>= op; - bits -= op; - Tracevv((stderr, "inflate: distance %u\n", dist)); - op = (unsigned)(out - beg); /* max distance in output */ - if (dist > op) { /* see if copy from window */ - op = dist - op; /* distance back in window */ - if (op > whave) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - from = window - OFF; - if (write == 0) { /* very common case */ - from += wsize - op; - if (op < len) { /* some from window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - else if (write < op) { /* wrap around window */ - from += wsize + write - op; - op -= write; - if (op < len) { /* some from end of window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = window - OFF; - if (write < len) { /* some from start of window */ - op = write; - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - } - else { /* contiguous in window */ - from += write - op; - if (op < len) { /* some from window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - while (len > 2) { - PUP(out) = PUP(from); - PUP(out) = PUP(from); - PUP(out) = PUP(from); - len -= 3; - } - if (len) { - PUP(out) = PUP(from); - if (len > 1) - PUP(out) = PUP(from); - } - } - else { - from = out - dist; /* copy direct from output */ - do { /* minimum length is three */ - PUP(out) = PUP(from); - PUP(out) = PUP(from); - PUP(out) = PUP(from); - len -= 3; - } while (len > 2); - if (len) { - PUP(out) = PUP(from); - if (len > 1) - PUP(out) = PUP(from); - } - } - } - else if ((op & 64) == 0) { /* 2nd level distance code */ - this = dcode[this.val + (hold & ((1U << op) - 1))]; - goto dodist; - } - else { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - } - else if ((op & 64) == 0) { /* 2nd level length code */ - this = lcode[this.val + (hold & ((1U << op) - 1))]; - goto dolen; - } - else if (op & 32) { /* end-of-block */ - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - else { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - } while (in < last && out < end); - - /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ - len = bits >> 3; - in -= len; - bits -= len << 3; - hold &= (1U << bits) - 1; - - /* update state and return */ - strm->next_in = in + OFF; - strm->next_out = out + OFF; - strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); - strm->avail_out = (unsigned)(out < end ? - 257 + (end - out) : 257 - (out - end)); - state->hold = hold; - state->bits = bits; - return; -} - -/* - inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - - Using bit fields for code structure - - Different op definition to avoid & for extra bits (do & for table bits) - - Three separate decoding do-loops for direct, window, and write == 0 - - Special case for distance > 1 copies to do overlapped load and store copy - - Explicit branch predictions (based on measured branch probabilities) - - Deferring match copy and interspersed it with decoding subsequent codes - - Swapping literal/length else - - Swapping window/direct else - - Larger unrolled copy loops (three is about right) - - Moving len -= 3 statement into middle of loop - */ - -#endif /* !ASMINF */ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - 68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/plugins/CDVDisoEFP/src/zlib/inffast.h b/plugins/CDVDisoEFP/src/zlib/inffast.h index 614fa7877d..1e88d2d97b 100644 --- a/plugins/CDVDisoEFP/src/zlib/inffast.h +++ b/plugins/CDVDisoEFP/src/zlib/inffast.h @@ -1,11 +1,11 @@ -/* inffast.h -- header to use inffast.c - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -void inflate_fast OF((z_streamp strm, unsigned start)); +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/plugins/CDVDisoEFP/src/zlib/inffixed.h b/plugins/CDVDisoEFP/src/zlib/inffixed.h index 423d5c5b50..75ed4b5978 100644 --- a/plugins/CDVDisoEFP/src/zlib/inffixed.h +++ b/plugins/CDVDisoEFP/src/zlib/inffixed.h @@ -1,94 +1,94 @@ - /* inffixed.h -- table for decoding fixed codes - * Generated automatically by makefixed(). - */ - - /* WARNING: this file should *not* be used by applications. It - is part of the implementation of the compression library and - is subject to change. Applications should only use zlib.h. - */ - - static const code lenfix[512] = { - {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, - {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, - {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, - {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, - {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, - {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, - {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, - {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, - {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, - {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, - {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, - {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, - {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, - {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, - {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, - {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, - {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, - {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, - {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, - {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, - {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, - {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, - {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, - {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, - {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, - {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, - {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, - {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, - {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, - {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, - {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, - {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, - {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, - {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, - {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, - {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, - {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, - {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, - {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, - {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, - {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, - {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, - {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, - {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, - {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, - {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, - {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, - {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, - {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, - {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, - {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, - {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, - {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, - {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, - {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, - {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, - {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, - {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, - {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, - {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, - {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, - {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, - {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, - {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, - {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, - {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, - {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, - {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, - {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, - {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, - {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, - {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, - {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, - {0,9,255} - }; - - static const code distfix[32] = { - {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, - {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, - {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, - {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, - {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, - {22,5,193},{64,5,0} - }; + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/plugins/CDVDisoEFP/src/zlib/inflate.c b/plugins/CDVDisoEFP/src/zlib/inflate.c index 71fe3ccd0e..a53b5c7446 100644 --- a/plugins/CDVDisoEFP/src/zlib/inflate.c +++ b/plugins/CDVDisoEFP/src/zlib/inflate.c @@ -1,1270 +1,1270 @@ -/* inflate.c -- zlib decompression - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * Change history: - * - * 1.2.beta0 24 Nov 2002 - * - First version -- complete rewrite of inflate to simplify code, avoid - * creation of window when not needed, minimize use of window when it is - * needed, make inffast.c even faster, implement gzip decoding, and to - * improve code readability and style over the previous zlib inflate code - * - * 1.2.beta1 25 Nov 2002 - * - Use pointers for available input and output checking in inffast.c - * - Remove input and output counters in inffast.c - * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 - * - Remove unnecessary second byte pull from length extra in inffast.c - * - Unroll direct copy to three copies per loop in inffast.c - * - * 1.2.beta2 4 Dec 2002 - * - Change external routine names to reduce potential conflicts - * - Correct filename to inffixed.h for fixed tables in inflate.c - * - Make hbuf[] unsigned char to match parameter type in inflate.c - * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) - * to avoid negation problem on Alphas (64 bit) in inflate.c - * - * 1.2.beta3 22 Dec 2002 - * - Add comments on state->bits assertion in inffast.c - * - Add comments on op field in inftrees.h - * - Fix bug in reuse of allocated window after inflateReset() - * - Remove bit fields--back to byte structure for speed - * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths - * - Change post-increments to pre-increments in inflate_fast(), PPC biased? - * - Add compile time option, POSTINC, to use post-increments instead (Intel?) - * - Make MATCH copy in inflate() much faster for when inflate_fast() not used - * - Use local copies of stream next and avail values, as well as local bit - * buffer and bit count in inflate()--for speed when inflate_fast() not used - * - * 1.2.beta4 1 Jan 2003 - * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings - * - Move a comment on output buffer sizes from inffast.c to inflate.c - * - Add comments in inffast.c to introduce the inflate_fast() routine - * - Rearrange window copies in inflate_fast() for speed and simplification - * - Unroll last copy for window match in inflate_fast() - * - Use local copies of window variables in inflate_fast() for speed - * - Pull out common write == 0 case for speed in inflate_fast() - * - Make op and len in inflate_fast() unsigned for consistency - * - Add FAR to lcode and dcode declarations in inflate_fast() - * - Simplified bad distance check in inflate_fast() - * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new - * source file infback.c to provide a call-back interface to inflate for - * programs like gzip and unzip -- uses window as output buffer to avoid - * window copying - * - * 1.2.beta5 1 Jan 2003 - * - Improved inflateBack() interface to allow the caller to provide initial - * input in strm. - * - Fixed stored blocks bug in inflateBack() - * - * 1.2.beta6 4 Jan 2003 - * - Added comments in inffast.c on effectiveness of POSTINC - * - Typecasting all around to reduce compiler warnings - * - Changed loops from while (1) or do {} while (1) to for (;;), again to - * make compilers happy - * - Changed type of window in inflateBackInit() to unsigned char * - * - * 1.2.beta7 27 Jan 2003 - * - Changed many types to unsigned or unsigned short to avoid warnings - * - Added inflateCopy() function - * - * 1.2.0 9 Mar 2003 - * - Changed inflateBack() interface to provide separate opaque descriptors - * for the in() and out() functions - * - Changed inflateBack() argument and in_func typedef to swap the length - * and buffer address return values for the input function - * - Check next_in and next_out for Z_NULL on entry to inflate() - * - * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -#ifdef MAKEFIXED -# ifndef BUILDFIXED -# define BUILDFIXED -# endif -#endif - -/* function prototypes */ -local void fixedtables OF((struct inflate_state FAR *state)); -local int updatewindow OF((z_streamp strm, unsigned out)); -#ifdef BUILDFIXED - void makefixed OF((void)); -#endif -local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, - unsigned len)); - -int ZEXPORT inflateReset(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - strm->total_in = strm->total_out = state->total = 0; - strm->msg = Z_NULL; - state->mode = HEAD; - state->last = 0; - state->havedict = 0; - state->wsize = 0; - state->whave = 0; - state->hold = 0; - state->bits = 0; - state->lencode = state->distcode = state->next = state->codes; - Tracev((stderr, "inflate: reset\n")); - return Z_OK; -} - -int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) -z_streamp strm; -int windowBits; -const char *version; -int stream_size; -{ - struct inflate_state FAR *state; - - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != (int)(sizeof(z_stream))) - return Z_VERSION_ERROR; - if (strm == Z_NULL) return Z_STREAM_ERROR; - strm->msg = Z_NULL; /* in case we return an error */ - if (strm->zalloc == (alloc_func)0) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; - state = (struct inflate_state FAR *) - ZALLOC(strm, 1, sizeof(struct inflate_state)); - if (state == Z_NULL) return Z_MEM_ERROR; - Tracev((stderr, "inflate: allocated\n")); - strm->state = (voidpf)state; - if (windowBits < 0) { - state->wrap = 0; - windowBits = -windowBits; - } - else { - state->wrap = (windowBits >> 4) + 1; -#ifdef GUNZIP - if (windowBits < 48) windowBits &= 15; -#endif - } - if (windowBits < 8 || windowBits > 15) { - ZFREE(strm, state); - strm->state = Z_NULL; - return Z_STREAM_ERROR; - } - state->wbits = (unsigned)windowBits; - state->window = Z_NULL; - return inflateReset(strm); -} - -int ZEXPORT inflateInit_(strm, version, stream_size) -z_streamp strm; -const char *version; -int stream_size; -{ - return inflateInit2_(strm, DEF_WBITS, version, stream_size); -} - -/* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ -#ifdef BUILDFIXED - static int virgin = 1; - static code *lenfix, *distfix; - static code fixed[544]; - - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - unsigned sym, bits; - static code *next; - - /* literal/length table */ - sym = 0; - while (sym < 144) state->lens[sym++] = 8; - while (sym < 256) state->lens[sym++] = 9; - while (sym < 280) state->lens[sym++] = 7; - while (sym < 288) state->lens[sym++] = 8; - next = fixed; - lenfix = next; - bits = 9; - inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); - - /* distance table */ - sym = 0; - while (sym < 32) state->lens[sym++] = 5; - distfix = next; - bits = 5; - inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); - - /* do this just once */ - virgin = 0; - } -#else /* !BUILDFIXED */ -# include "inffixed.h" -#endif /* BUILDFIXED */ - state->lencode = lenfix; - state->lenbits = 9; - state->distcode = distfix; - state->distbits = 5; -} - -#ifdef MAKEFIXED -#include - -/* - Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also - defines BUILDFIXED, so the tables are built on the fly. makefixed() writes - those tables to stdout, which would be piped to inffixed.h. A small program - can simply call makefixed to do this: - - void makefixed(void); - - int main(void) - { - makefixed(); - return 0; - } - - Then that can be linked with zlib built with MAKEFIXED defined and run: - - a.out > inffixed.h - */ -void makefixed() -{ - unsigned low, size; - struct inflate_state state; - - fixedtables(&state); - puts(" /* inffixed.h -- table for decoding fixed codes"); - puts(" * Generated automatically by makefixed()."); - puts(" */"); - puts(""); - puts(" /* WARNING: this file should *not* be used by applications."); - puts(" It is part of the implementation of this library and is"); - puts(" subject to change. Applications should only use zlib.h."); - puts(" */"); - puts(""); - size = 1U << 9; - printf(" static const code lenfix[%u] = {", size); - low = 0; - for (;;) { - if ((low % 7) == 0) printf("\n "); - printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, - state.lencode[low].val); - if (++low == size) break; - putchar(','); - } - puts("\n };"); - size = 1U << 5; - printf("\n static const code distfix[%u] = {", size); - low = 0; - for (;;) { - if ((low % 6) == 0) printf("\n "); - printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, - state.distcode[low].val); - if (++low == size) break; - putchar(','); - } - puts("\n };"); -} -#endif /* MAKEFIXED */ - -/* - Update the window with the last wsize (normally 32K) bytes written before - returning. If window does not exist yet, create it. This is only called - when a window is already in use, or when output has been written during this - inflate call, but the end of the deflate stream has not been reached yet. - It is also called to create a window for dictionary data when a dictionary - is loaded. - - Providing output buffers larger than 32K to inflate() should provide a speed - advantage, since only the last 32K of output is copied to the sliding window - upon return from inflate(), and since all distances after the first 32K of - output will fall in the output data, making match copies simpler and faster. - The advantage may be dependent on the size of the processor's data caches. - */ -local int updatewindow(strm, out) -z_streamp strm; -unsigned out; -{ - struct inflate_state FAR *state; - unsigned copy, dist; - - state = (struct inflate_state FAR *)strm->state; - - /* if it hasn't been done already, allocate space for the window */ - if (state->window == Z_NULL) { - state->window = (unsigned char FAR *) - ZALLOC(strm, 1U << state->wbits, - sizeof(unsigned char)); - if (state->window == Z_NULL) return 1; - } - - /* if window not in use yet, initialize */ - if (state->wsize == 0) { - state->wsize = 1U << state->wbits; - state->write = 0; - state->whave = 0; - } - - /* copy state->wsize or less output bytes into the circular window */ - copy = out - strm->avail_out; - if (copy >= state->wsize) { - zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); - state->write = 0; - state->whave = state->wsize; - } - else { - dist = state->wsize - state->write; - if (dist > copy) dist = copy; - zmemcpy(state->window + state->write, strm->next_out - copy, dist); - copy -= dist; - if (copy) { - zmemcpy(state->window, strm->next_out - copy, copy); - state->write = copy; - state->whave = state->wsize; - } - else { - state->write += dist; - if (state->write == state->wsize) state->write = 0; - if (state->whave < state->wsize) state->whave += dist; - } - } - return 0; -} - -/* Macros for inflate(): */ - -/* check function to use adler32() for zlib or crc32() for gzip */ -#ifdef GUNZIP -# define UPDATE(check, buf, len) \ - (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) -#else -# define UPDATE(check, buf, len) adler32(check, buf, len) -#endif - -/* check macros for header crc */ -#ifdef GUNZIP -# define CRC2(check, word) \ - do { \ - hbuf[0] = (unsigned char)(word); \ - hbuf[1] = (unsigned char)((word) >> 8); \ - check = crc32(check, hbuf, 2); \ - } while (0) - -# define CRC4(check, word) \ - do { \ - hbuf[0] = (unsigned char)(word); \ - hbuf[1] = (unsigned char)((word) >> 8); \ - hbuf[2] = (unsigned char)((word) >> 16); \ - hbuf[3] = (unsigned char)((word) >> 24); \ - check = crc32(check, hbuf, 4); \ - } while (0) -#endif - -/* Load registers with state in inflate() for speed */ -#define LOAD() \ - do { \ - put = strm->next_out; \ - left = strm->avail_out; \ - next = strm->next_in; \ - have = strm->avail_in; \ - hold = state->hold; \ - bits = state->bits; \ - } while (0) - -/* Restore state from registers in inflate() */ -#define RESTORE() \ - do { \ - strm->next_out = put; \ - strm->avail_out = left; \ - strm->next_in = next; \ - strm->avail_in = have; \ - state->hold = hold; \ - state->bits = bits; \ - } while (0) - -/* Clear the input bit accumulator */ -#define INITBITS() \ - do { \ - hold = 0; \ - bits = 0; \ - } while (0) - -/* Get a byte of input into the bit accumulator, or return from inflate() - if there is no input available. */ -#define PULLBYTE() \ - do { \ - if (have == 0) goto inf_leave; \ - have--; \ - hold += (unsigned long)(*next++) << bits; \ - bits += 8; \ - } while (0) - -/* Assure that there are at least n bits in the bit accumulator. If there is - not enough available input to do that, then return from inflate(). */ -#define NEEDBITS(n) \ - do { \ - while (bits < (unsigned)(n)) \ - PULLBYTE(); \ - } while (0) - -/* Return the low n bits of the bit accumulator (n < 16) */ -#define BITS(n) \ - ((unsigned)hold & ((1U << (n)) - 1)) - -/* Remove n bits from the bit accumulator */ -#define DROPBITS(n) \ - do { \ - hold >>= (n); \ - bits -= (unsigned)(n); \ - } while (0) - -/* Remove zero to seven bits as needed to go to a byte boundary */ -#define BYTEBITS() \ - do { \ - hold >>= bits & 7; \ - bits -= bits & 7; \ - } while (0) - -/* Reverse the bytes in a 32-bit value */ -#define REVERSE(q) \ - ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ - (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) - -/* - inflate() uses a state machine to process as much input data and generate as - much output data as possible before returning. The state machine is - structured roughly as follows: - - for (;;) switch (state) { - ... - case STATEn: - if (not enough input data or output space to make progress) - return; - ... make progress ... - state = STATEm; - break; - ... - } - - so when inflate() is called again, the same case is attempted again, and - if the appropriate resources are provided, the machine proceeds to the - next state. The NEEDBITS() macro is usually the way the state evaluates - whether it can proceed or should return. NEEDBITS() does the return if - the requested bits are not available. The typical use of the BITS macros - is: - - NEEDBITS(n); - ... do something with BITS(n) ... - DROPBITS(n); - - where NEEDBITS(n) either returns from inflate() if there isn't enough - input left to load n bits into the accumulator, or it continues. BITS(n) - gives the low n bits in the accumulator. When done, DROPBITS(n) drops - the low n bits off the accumulator. INITBITS() clears the accumulator - and sets the number of available bits to zero. BYTEBITS() discards just - enough bits to put the accumulator on a byte boundary. After BYTEBITS() - and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. - - NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return - if there is no input available. The decoding of variable length codes uses - PULLBYTE() directly in order to pull just enough bytes to decode the next - code, and no more. - - Some states loop until they get enough input, making sure that enough - state information is maintained to continue the loop where it left off - if NEEDBITS() returns in the loop. For example, want, need, and keep - would all have to actually be part of the saved state in case NEEDBITS() - returns: - - case STATEw: - while (want < need) { - NEEDBITS(n); - keep[want++] = BITS(n); - DROPBITS(n); - } - state = STATEx; - case STATEx: - - As shown above, if the next state is also the next case, then the break - is omitted. - - A state may also return if there is not enough output space available to - complete that state. Those states are copying stored data, writing a - literal byte, and copying a matching string. - - When returning, a "goto inf_leave" is used to update the total counters, - update the check value, and determine whether any progress has been made - during that inflate() call in order to return the proper return code. - Progress is defined as a change in either strm->avail_in or strm->avail_out. - When there is a window, goto inf_leave will update the window with the last - output written. If a goto inf_leave occurs in the middle of decompression - and there is no window currently, goto inf_leave will create one and copy - output to the window for the next call of inflate(). - - In this implementation, the flush parameter of inflate() only affects the - return code (per zlib.h). inflate() always writes as much as possible to - strm->next_out, given the space available and the provided input--the effect - documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers - the allocation of and copying into a sliding window until necessary, which - provides the effect documented in zlib.h for Z_FINISH when the entire input - stream available. So the only thing the flush parameter actually does is: - when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it - will return Z_BUF_ERROR if it has not reached the end of the stream. - */ - -int ZEXPORT inflate(strm, flush) -z_streamp strm; -int flush; -{ - struct inflate_state FAR *state; - unsigned char FAR *next; /* next input */ - unsigned char FAR *put; /* next output */ - unsigned have, left; /* available input and output */ - unsigned long hold; /* bit buffer */ - unsigned bits; /* bits in bit buffer */ - unsigned in, out; /* save starting available input and output */ - unsigned copy; /* number of stored or match bytes to copy */ - unsigned char FAR *from; /* where to copy match bytes from */ - code this; /* current decoding table entry */ - code last; /* parent table entry */ - unsigned len; /* length to copy for repeats, bits to drop */ - int ret; /* return code */ -#ifdef GUNZIP - unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ -#endif - static const unsigned short order[19] = /* permutation of code lengths */ - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || - (strm->next_in == Z_NULL && strm->avail_in != 0)) - return Z_STREAM_ERROR; - - state = (struct inflate_state FAR *)strm->state; - if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ - LOAD(); - in = have; - out = left; - ret = Z_OK; - for (;;) - switch (state->mode) { - case HEAD: - if (state->wrap == 0) { - state->mode = TYPEDO; - break; - } - NEEDBITS(16); -#ifdef GUNZIP - if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ - state->check = crc32(0L, Z_NULL, 0); - CRC2(state->check, hold); - INITBITS(); - state->mode = FLAGS; - break; - } - state->flags = 0; /* expect zlib header */ - if (!(state->wrap & 1) || /* check if zlib header allowed */ -#else - if ( -#endif - ((BITS(8) << 8) + (hold >> 8)) % 31) { - strm->msg = (char *)"incorrect header check"; - state->mode = BAD; - break; - } - if (BITS(4) != Z_DEFLATED) { - strm->msg = (char *)"unknown compression method"; - state->mode = BAD; - break; - } - DROPBITS(4); - if (BITS(4) + 8 > state->wbits) { - strm->msg = (char *)"invalid window size"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: zlib header ok\n")); - strm->adler = state->check = adler32(0L, Z_NULL, 0); - state->mode = hold & 0x200 ? DICTID : TYPE; - INITBITS(); - break; -#ifdef GUNZIP - case FLAGS: - NEEDBITS(16); - state->flags = (int)(hold); - if ((state->flags & 0xff) != Z_DEFLATED) { - strm->msg = (char *)"unknown compression method"; - state->mode = BAD; - break; - } - if (state->flags & 0xe000) { - strm->msg = (char *)"unknown header flags set"; - state->mode = BAD; - break; - } - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - state->mode = TIME; - case TIME: - NEEDBITS(32); - if (state->flags & 0x0200) CRC4(state->check, hold); - INITBITS(); - state->mode = OS; - case OS: - NEEDBITS(16); - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - state->mode = EXLEN; - case EXLEN: - if (state->flags & 0x0400) { - NEEDBITS(16); - state->length = (unsigned)(hold); - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - } - state->mode = EXTRA; - case EXTRA: - if (state->flags & 0x0400) { - copy = state->length; - if (copy > have) copy = have; - if (copy) { - if (state->flags & 0x0200) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - state->length -= copy; - } - if (state->length) goto inf_leave; - } - state->mode = NAME; - case NAME: - if (state->flags & 0x0800) { - if (have == 0) goto inf_leave; - copy = 0; - do { - len = (unsigned)(next[copy++]); - } while (len && copy < have); - if (state->flags & 0x02000) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - if (len) goto inf_leave; - } - state->mode = COMMENT; - case COMMENT: - if (state->flags & 0x1000) { - if (have == 0) goto inf_leave; - copy = 0; - do { - len = (unsigned)(next[copy++]); - } while (len && copy < have); - if (state->flags & 0x02000) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - if (len) goto inf_leave; - } - state->mode = HCRC; - case HCRC: - if (state->flags & 0x0200) { - NEEDBITS(16); - if (hold != (state->check & 0xffff)) { - strm->msg = (char *)"header crc mismatch"; - state->mode = BAD; - break; - } - INITBITS(); - } - strm->adler = state->check = crc32(0L, Z_NULL, 0); - state->mode = TYPE; - break; -#endif - case DICTID: - NEEDBITS(32); - strm->adler = state->check = REVERSE(hold); - INITBITS(); - state->mode = DICT; - case DICT: - if (state->havedict == 0) { - RESTORE(); - return Z_NEED_DICT; - } - strm->adler = state->check = adler32(0L, Z_NULL, 0); - state->mode = TYPE; - case TYPE: - if (flush == Z_BLOCK) goto inf_leave; - case TYPEDO: - if (state->last) { - BYTEBITS(); - state->mode = CHECK; - break; - } - NEEDBITS(3); - state->last = BITS(1); - DROPBITS(1); - switch (BITS(2)) { - case 0: /* stored block */ - Tracev((stderr, "inflate: stored block%s\n", - state->last ? " (last)" : "")); - state->mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - Tracev((stderr, "inflate: fixed codes block%s\n", - state->last ? " (last)" : "")); - state->mode = LEN; /* decode codes */ - break; - case 2: /* dynamic block */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - state->last ? " (last)" : "")); - state->mode = TABLE; - break; - case 3: - strm->msg = (char *)"invalid block type"; - state->mode = BAD; - } - DROPBITS(2); - break; - case STORED: - BYTEBITS(); /* go to byte boundary */ - NEEDBITS(32); - if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - strm->msg = (char *)"invalid stored block lengths"; - state->mode = BAD; - break; - } - state->length = (unsigned)hold & 0xffff; - Tracev((stderr, "inflate: stored length %u\n", - state->length)); - INITBITS(); - state->mode = COPY; - case COPY: - copy = state->length; - if (copy) { - if (copy > have) copy = have; - if (copy > left) copy = left; - if (copy == 0) goto inf_leave; - zmemcpy(put, next, copy); - have -= copy; - next += copy; - left -= copy; - put += copy; - state->length -= copy; - break; - } - Tracev((stderr, "inflate: stored end\n")); - state->mode = TYPE; - break; - case TABLE: - NEEDBITS(14); - state->nlen = BITS(5) + 257; - DROPBITS(5); - state->ndist = BITS(5) + 1; - DROPBITS(5); - state->ncode = BITS(4) + 4; - DROPBITS(4); -#ifndef PKZIP_BUG_WORKAROUND - if (state->nlen > 286 || state->ndist > 30) { - strm->msg = (char *)"too many length or distance symbols"; - state->mode = BAD; - break; - } -#endif - Tracev((stderr, "inflate: table sizes ok\n")); - state->have = 0; - state->mode = LENLENS; - case LENLENS: - while (state->have < state->ncode) { - NEEDBITS(3); - state->lens[order[state->have++]] = (unsigned short)BITS(3); - DROPBITS(3); - } - while (state->have < 19) - state->lens[order[state->have++]] = 0; - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 7; - ret = inflate_table(CODES, state->lens, 19, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid code lengths set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: code lengths ok\n")); - state->have = 0; - state->mode = CODELENS; - case CODELENS: - while (state->have < state->nlen + state->ndist) { - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.val < 16) { - NEEDBITS(this.bits); - DROPBITS(this.bits); - state->lens[state->have++] = this.val; - } - else { - if (this.val == 16) { - NEEDBITS(this.bits + 2); - DROPBITS(this.bits); - if (state->have == 0) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - len = state->lens[state->have - 1]; - copy = 3 + BITS(2); - DROPBITS(2); - } - else if (this.val == 17) { - NEEDBITS(this.bits + 3); - DROPBITS(this.bits); - len = 0; - copy = 3 + BITS(3); - DROPBITS(3); - } - else { - NEEDBITS(this.bits + 7); - DROPBITS(this.bits); - len = 0; - copy = 11 + BITS(7); - DROPBITS(7); - } - if (state->have + copy > state->nlen + state->ndist) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - while (copy--) - state->lens[state->have++] = (unsigned short)len; - } - } - - /* build code tables */ - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 9; - ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid literal/lengths set"; - state->mode = BAD; - break; - } - state->distcode = (code const FAR *)(state->next); - state->distbits = 6; - ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, - &(state->next), &(state->distbits), state->work); - if (ret) { - strm->msg = (char *)"invalid distances set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: codes ok\n")); - state->mode = LEN; - case LEN: - if (have >= 6 && left >= 258) { - RESTORE(); - inflate_fast(strm, out); - LOAD(); - break; - } - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.op && (this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->lencode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - state->length = (unsigned)this.val; - if ((int)(this.op) == 0) { - Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", this.val)); - state->mode = LIT; - break; - } - if (this.op & 32) { - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - if (this.op & 64) { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - state->extra = (unsigned)(this.op) & 15; - state->mode = LENEXT; - case LENEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->length += BITS(state->extra); - DROPBITS(state->extra); - } - Tracevv((stderr, "inflate: length %u\n", state->length)); - state->mode = DIST; - case DIST: - for (;;) { - this = state->distcode[BITS(state->distbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if ((this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->distcode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - if (this.op & 64) { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - state->offset = (unsigned)this.val; - state->extra = (unsigned)(this.op) & 15; - state->mode = DISTEXT; - case DISTEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->offset += BITS(state->extra); - DROPBITS(state->extra); - } - if (state->offset > state->whave + out - left) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - Tracevv((stderr, "inflate: distance %u\n", state->offset)); - state->mode = MATCH; - case MATCH: - if (left == 0) goto inf_leave; - copy = out - left; - if (state->offset > copy) { /* copy from window */ - copy = state->offset - copy; - if (copy > state->write) { - copy -= state->write; - from = state->window + (state->wsize - copy); - } - else - from = state->window + (state->write - copy); - if (copy > state->length) copy = state->length; - } - else { /* copy from output */ - from = put - state->offset; - copy = state->length; - } - if (copy > left) copy = left; - left -= copy; - state->length -= copy; - do { - *put++ = *from++; - } while (--copy); - if (state->length == 0) state->mode = LEN; - break; - case LIT: - if (left == 0) goto inf_leave; - *put++ = (unsigned char)(state->length); - left--; - state->mode = LEN; - break; - case CHECK: - if (state->wrap) { - NEEDBITS(32); - out -= left; - strm->total_out += out; - state->total += out; - if (out) - strm->adler = state->check = - UPDATE(state->check, put - out, out); - out = left; - if (( -#ifdef GUNZIP - state->flags ? hold : -#endif - REVERSE(hold)) != state->check) { - strm->msg = (char *)"incorrect data check"; - state->mode = BAD; - break; - } - INITBITS(); - Tracev((stderr, "inflate: check matches trailer\n")); - } -#ifdef GUNZIP - state->mode = LENGTH; - case LENGTH: - if (state->wrap && state->flags) { - NEEDBITS(32); - if (hold != (state->total & 0xffffffffUL)) { - strm->msg = (char *)"incorrect length check"; - state->mode = BAD; - break; - } - INITBITS(); - Tracev((stderr, "inflate: length matches trailer\n")); - } -#endif - state->mode = DONE; - case DONE: - ret = Z_STREAM_END; - goto inf_leave; - case BAD: - ret = Z_DATA_ERROR; - goto inf_leave; - case MEM: - return Z_MEM_ERROR; - case SYNC: - default: - return Z_STREAM_ERROR; - } - - /* - Return from inflate(), updating the total counts and the check value. - If there was no progress during the inflate() call, return a buffer - error. Call updatewindow() to create and/or update the window state. - Note: a memory error from inflate() is non-recoverable. - */ - inf_leave: - RESTORE(); - if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) - if (updatewindow(strm, out)) { - state->mode = MEM; - return Z_MEM_ERROR; - } - in -= strm->avail_in; - out -= strm->avail_out; - strm->total_in += in; - strm->total_out += out; - state->total += out; - if (state->wrap && out) - strm->adler = state->check = - UPDATE(state->check, strm->next_out - out, out); - strm->data_type = state->bits + (state->last ? 64 : 0) + - (state->mode == TYPE ? 128 : 0); - if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) - ret = Z_BUF_ERROR; - return ret; -} - -int ZEXPORT inflateEnd(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (state->window != Z_NULL) ZFREE(strm, state->window); - ZFREE(strm, strm->state); - strm->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; -} - -int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) -z_streamp strm; -const Bytef *dictionary; -uInt dictLength; -{ - struct inflate_state FAR *state; - unsigned long id; - - /* check state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (state->mode != DICT) return Z_STREAM_ERROR; - - /* check for correct dictionary id */ - id = adler32(0L, Z_NULL, 0); - id = adler32(id, dictionary, dictLength); - if (id != state->check) return Z_DATA_ERROR; - - /* copy dictionary to window */ - if (updatewindow(strm, strm->avail_out)) { - state->mode = MEM; - return Z_MEM_ERROR; - } - if (dictLength > state->wsize) { - zmemcpy(state->window, dictionary + dictLength - state->wsize, - state->wsize); - state->whave = state->wsize; - } - else { - zmemcpy(state->window + state->wsize - dictLength, dictionary, - dictLength); - state->whave = dictLength; - } - state->havedict = 1; - Tracev((stderr, "inflate: dictionary set\n")); - return Z_OK; -} - -/* - Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found - or when out of input. When called, *have is the number of pattern bytes - found in order so far, in 0..3. On return *have is updated to the new - state. If on return *have equals four, then the pattern was found and the - return value is how many bytes were read including the last byte of the - pattern. If *have is less than four, then the pattern has not been found - yet and the return value is len. In the latter case, syncsearch() can be - called again with more data and the *have state. *have is initialized to - zero for the first call. - */ -local unsigned syncsearch(have, buf, len) -unsigned FAR *have; -unsigned char FAR *buf; -unsigned len; -{ - unsigned got; - unsigned next; - - got = *have; - next = 0; - while (next < len && got < 4) { - if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) - got++; - else if (buf[next]) - got = 0; - else - got = 4 - got; - next++; - } - *have = got; - return next; -} - -int ZEXPORT inflateSync(strm) -z_streamp strm; -{ - unsigned len; /* number of bytes to look at or looked at */ - unsigned long in, out; /* temporary to save total_in and total_out */ - unsigned char buf[4]; /* to restore bit buffer to byte string */ - struct inflate_state FAR *state; - - /* check parameters */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; - - /* if first time, start search in bit buffer */ - if (state->mode != SYNC) { - state->mode = SYNC; - state->hold <<= state->bits & 7; - state->bits -= state->bits & 7; - len = 0; - while (state->bits >= 8) { - buf[len++] = (unsigned char)(state->hold); - state->hold >>= 8; - state->bits -= 8; - } - state->have = 0; - syncsearch(&(state->have), buf, len); - } - - /* search available input */ - len = syncsearch(&(state->have), strm->next_in, strm->avail_in); - strm->avail_in -= len; - strm->next_in += len; - strm->total_in += len; - - /* return no joy or set up to restart inflate() on a new block */ - if (state->have != 4) return Z_DATA_ERROR; - in = strm->total_in; out = strm->total_out; - inflateReset(strm); - strm->total_in = in; strm->total_out = out; - state->mode = TYPE; - return Z_OK; -} - -/* - Returns true if inflate is currently at the end of a block generated by - Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP - implementation to provide an additional safety check. PPP uses - Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored - block. When decompressing, PPP checks that at the end of input packet, - inflate is waiting for these length bytes. - */ -int ZEXPORT inflateSyncPoint(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - return state->mode == STORED && state->bits == 0; -} - -int ZEXPORT inflateCopy(dest, source) -z_streamp dest; -z_streamp source; -{ - struct inflate_state FAR *state; - struct inflate_state FAR *copy; - unsigned char FAR *window; - - /* check input */ - if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || - source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)source->state; - - /* allocate space */ - copy = (struct inflate_state FAR *) - ZALLOC(source, 1, sizeof(struct inflate_state)); - if (copy == Z_NULL) return Z_MEM_ERROR; - window = Z_NULL; - if (state->window != Z_NULL) { - window = (unsigned char FAR *) - ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); - if (window == Z_NULL) { - ZFREE(source, copy); - return Z_MEM_ERROR; - } - } - - /* copy state */ - *dest = *source; - *copy = *state; - copy->lencode = copy->codes + (state->lencode - state->codes); - copy->distcode = copy->codes + (state->distcode - state->codes); - copy->next = copy->codes + (state->next - state->codes); - if (window != Z_NULL) - zmemcpy(window, state->window, 1U << state->wbits); - copy->window = window; - dest->state = (voidpf)copy; - return Z_OK; -} +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->wsize = 0; + state->whave = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + if (BITS(4) + 8 > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + } while (len && copy < have); + if (state->flags & 0x02000) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + } while (len && copy < have); + if (state->flags & 0x02000) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->mode != DICT) return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) return Z_DATA_ERROR; + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + *dest = *source; + *copy = *state; + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) + zmemcpy(window, state->window, 1U << state->wbits); + copy->window = window; + dest->state = (voidpf)copy; + return Z_OK; +} diff --git a/plugins/CDVDisoEFP/src/zlib/inflate.h b/plugins/CDVDisoEFP/src/zlib/inflate.h index b6965127b9..9a12c8fd29 100644 --- a/plugins/CDVDisoEFP/src/zlib/inflate.h +++ b/plugins/CDVDisoEFP/src/zlib/inflate.h @@ -1,117 +1,117 @@ -/* inflate.h -- internal inflate state definition - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer decoding by inflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip decoding - should be left enabled. */ -#ifndef NO_GZIP -# define GUNZIP -#endif - -/* Possible inflate modes between inflate() calls */ -typedef enum { - HEAD, /* i: waiting for magic header */ -#ifdef GUNZIP - FLAGS, /* i: waiting for method and flags (gzip) */ - TIME, /* i: waiting for modification time (gzip) */ - OS, /* i: waiting for extra flags and operating system (gzip) */ - EXLEN, /* i: waiting for extra length (gzip) */ - EXTRA, /* i: waiting for extra bytes (gzip) */ - NAME, /* i: waiting for end of file name (gzip) */ - COMMENT, /* i: waiting for end of comment (gzip) */ - HCRC, /* i: waiting for header crc (gzip) */ -#endif - DICTID, /* i: waiting for dictionary check value */ - DICT, /* waiting for inflateSetDictionary() call */ - TYPE, /* i: waiting for type bits, including last-flag bit */ - TYPEDO, /* i: same, but skip check to exit inflate on new block */ - STORED, /* i: waiting for stored size (length and complement) */ - COPY, /* i/o: waiting for input or output to copy stored block */ - TABLE, /* i: waiting for dynamic block table lengths */ - LENLENS, /* i: waiting for code length code lengths */ - CODELENS, /* i: waiting for length/lit and distance code lengths */ - LEN, /* i: waiting for length/lit code */ - LENEXT, /* i: waiting for length extra bits */ - DIST, /* i: waiting for distance code */ - DISTEXT, /* i: waiting for distance extra bits */ - MATCH, /* o: waiting for output space to copy string */ - LIT, /* o: waiting for output space to write literal */ - CHECK, /* i: waiting for 32-bit check value */ -#ifdef GUNZIP - LENGTH, /* i: waiting for 32-bit length (gzip) */ -#endif - DONE, /* finished check, done -- remain here until reset */ - BAD, /* got a data error -- remain here until reset */ - MEM, /* got an inflate() memory error -- remain here until reset */ - SYNC /* looking for synchronization bytes to restart inflate() */ -} inflate_mode; - -/* - State transitions between above modes - - - (most modes can go to the BAD or MEM mode -- not shown for clarity) - - Process header: - HEAD -> (gzip) or (zlib) - (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME - NAME -> COMMENT -> HCRC -> TYPE - (zlib) -> DICTID or TYPE - DICTID -> DICT -> TYPE - Read deflate blocks: - TYPE -> STORED or TABLE or LEN or CHECK - STORED -> COPY -> TYPE - TABLE -> LENLENS -> CODELENS -> LEN - Read deflate codes: - LEN -> LENEXT or LIT or TYPE - LENEXT -> DIST -> DISTEXT -> MATCH -> LEN - LIT -> LEN - Process trailer: - CHECK -> LENGTH -> DONE - */ - -/* state maintained between inflate() calls. Approximately 7K bytes. */ -struct inflate_state { - inflate_mode mode; /* current inflate mode */ - int last; /* true if processing last block */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - int havedict; /* true if dictionary provided */ - int flags; /* gzip header method and flags (0 if zlib) */ - unsigned long check; /* protected copy of check value */ - unsigned long total; /* protected copy of output count */ - /* sliding window */ - unsigned wbits; /* log base 2 of requested window size */ - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned write; /* window write index */ - unsigned char FAR *window; /* allocated sliding window, if needed */ - /* bit accumulator */ - unsigned long hold; /* input bit accumulator */ - unsigned bits; /* number of bits in "in" */ - /* for string and stored block copying */ - unsigned length; /* literal or length of data to copy */ - unsigned offset; /* distance back to copy string from */ - /* for table and code decoding */ - unsigned extra; /* extra bits needed */ - /* fixed and dynamic code tables */ - code const FAR *lencode; /* starting table for length/literal codes */ - code const FAR *distcode; /* starting table for distance codes */ - unsigned lenbits; /* index bits for lencode */ - unsigned distbits; /* index bits for distcode */ - /* dynamic table building */ - unsigned ncode; /* number of code length code lengths */ - unsigned nlen; /* number of length code lengths */ - unsigned ndist; /* number of distance code lengths */ - unsigned have; /* number of code lengths in lens[] */ - code FAR *next; /* next available space in codes[] */ - unsigned short lens[320]; /* temporary storage for code lengths */ - unsigned short work[288]; /* work area for code table building */ - code codes[ENOUGH]; /* space for code tables */ -}; +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ +#ifdef GUNZIP + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ +#endif + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ +#ifdef GUNZIP + LENGTH, /* i: waiting for 32-bit length (gzip) */ +#endif + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/plugins/CDVDisoEFP/src/zlib/inftrees.c b/plugins/CDVDisoEFP/src/zlib/inftrees.c index 55fd27b601..3bb56398e1 100644 --- a/plugins/CDVDisoEFP/src/zlib/inftrees.c +++ b/plugins/CDVDisoEFP/src/zlib/inftrees.c @@ -1,321 +1,321 @@ -/* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" - -#define MAXBITS 15 - -const char inflate_copyright[] = - " inflate 1.2.1 Copyright 1995-2003 Mark Adler "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* - Build a set of tables to decode the provided canonical Huffman code. - The code lengths are lens[0..codes-1]. The result starts at *table, - whose indices are 0..2^bits-1. work is a writable array of at least - lens shorts, which is used as a work area. type is the type of code - to be generated, CODES, LENS, or DISTS. On return, zero is success, - -1 is an invalid code, and +1 means that ENOUGH isn't enough. table - on return points to the next available entry's address. bits is the - requested root table index bits, and on return it is the actual root - table index bits. It will differ if the request is greater than the - longest code or if it is less than the shortest code. - */ -int inflate_table(type, lens, codes, table, bits, work) -codetype type; -unsigned short FAR *lens; -unsigned codes; -code FAR * FAR *table; -unsigned FAR *bits; -unsigned short FAR *work; -{ - unsigned len; /* a code's length in bits */ - unsigned sym; /* index of code symbols */ - unsigned min, max; /* minimum and maximum code lengths */ - unsigned root; /* number of index bits for root table */ - unsigned curr; /* number of index bits for current table */ - unsigned drop; /* code bits to drop for sub-table */ - int left; /* number of prefix codes available */ - unsigned used; /* code entries in table used */ - unsigned huff; /* Huffman code */ - unsigned incr; /* for incrementing code, index */ - unsigned fill; /* index for replicating entries */ - unsigned low; /* low bits for current root entry */ - unsigned mask; /* mask for low root bits */ - code this; /* table entry for duplication */ - code FAR *next; /* next available space in table */ - const unsigned short FAR *base; /* base value table to use */ - const unsigned short FAR *extra; /* extra bits table to use */ - int end; /* use base and extra for symbol > end */ - unsigned short count[MAXBITS+1]; /* number of codes of each length */ - unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ - static const unsigned short lbase[31] = { /* Length codes 257..285 base */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - static const unsigned short lext[31] = { /* Length codes 257..285 extra */ - 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 76, 66}; - static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577, 0, 0}; - static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ - 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, - 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, - 28, 28, 29, 29, 64, 64}; - - /* - Process a set of code lengths to create a canonical Huffman code. The - code lengths are lens[0..codes-1]. Each length corresponds to the - symbols 0..codes-1. The Huffman code is generated by first sorting the - symbols by length from short to long, and retaining the symbol order - for codes with equal lengths. Then the code starts with all zero bits - for the first code of the shortest length, and the codes are integer - increments for the same length, and zeros are appended as the length - increases. For the deflate format, these bits are stored backwards - from their more natural integer increment ordering, and so when the - decoding tables are built in the large loop below, the integer codes - are incremented backwards. - - This routine assumes, but does not check, that all of the entries in - lens[] are in the range 0..MAXBITS. The caller must assure this. - 1..MAXBITS is interpreted as that code length. zero means that that - symbol does not occur in this code. - - The codes are sorted by computing a count of codes for each length, - creating from that a table of starting indices for each length in the - sorted table, and then entering the symbols in order in the sorted - table. The sorted table is work[], with that space being provided by - the caller. - - The length counts are used for other purposes as well, i.e. finding - the minimum and maximum length codes, determining if there are any - codes at all, checking for a valid set of lengths, and looking ahead - at length counts to determine sub-table sizes when building the - decoding tables. - */ - - /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ - for (len = 0; len <= MAXBITS; len++) - count[len] = 0; - for (sym = 0; sym < codes; sym++) - count[lens[sym]]++; - - /* bound code lengths, force root to be within code lengths */ - root = *bits; - for (max = MAXBITS; max >= 1; max--) - if (count[max] != 0) break; - if (root > max) root = max; - if (max == 0) return -1; /* no codes! */ - for (min = 1; min <= MAXBITS; min++) - if (count[min] != 0) break; - if (root < min) root = min; - - /* check for an over-subscribed or incomplete set of lengths */ - left = 1; - for (len = 1; len <= MAXBITS; len++) { - left <<= 1; - left -= count[len]; - if (left < 0) return -1; /* over-subscribed */ - } - if (left > 0 && (type == CODES || (codes - count[0] != 1))) - return -1; /* incomplete set */ - - /* generate offsets into symbol table for each length for sorting */ - offs[1] = 0; - for (len = 1; len < MAXBITS; len++) - offs[len + 1] = offs[len] + count[len]; - - /* sort symbols by length, by symbol order within each length */ - for (sym = 0; sym < codes; sym++) - if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; - - /* - Create and fill in decoding tables. In this loop, the table being - filled is at next and has curr index bits. The code being used is huff - with length len. That code is converted to an index by dropping drop - bits off of the bottom. For codes where len is less than drop + curr, - those top drop + curr - len bits are incremented through all values to - fill the table with replicated entries. - - root is the number of index bits for the root table. When len exceeds - root, sub-tables are created pointed to by the root entry with an index - of the low root bits of huff. This is saved in low to check for when a - new sub-table should be started. drop is zero when the root table is - being filled, and drop is root when sub-tables are being filled. - - When a new sub-table is needed, it is necessary to look ahead in the - code lengths to determine what size sub-table is needed. The length - counts are used for this, and so count[] is decremented as codes are - entered in the tables. - - used keeps track of how many table entries have been allocated from the - provided *table space. It is checked when a LENS table is being made - against the space in *table, ENOUGH, minus the maximum space needed by - the worst case distance code, MAXD. This should never happen, but the - sufficiency of ENOUGH has not been proven exhaustively, hence the check. - This assumes that when type == LENS, bits == 9. - - sym increments through all symbols, and the loop terminates when - all codes of length max, i.e. all codes, have been processed. This - routine permits incomplete codes, so another loop after this one fills - in the rest of the decoding tables with invalid code markers. - */ - - /* set up for code type */ - switch (type) { - case CODES: - base = extra = work; /* dummy value--not used */ - end = 19; - break; - case LENS: - base = lbase; - base -= 257; - extra = lext; - extra -= 257; - end = 256; - break; - default: /* DISTS */ - base = dbase; - extra = dext; - end = -1; - } - - /* initialize state for loop */ - huff = 0; /* starting code */ - sym = 0; /* starting code symbol */ - len = min; /* starting code length */ - next = *table; /* current table to fill in */ - curr = root; /* current table index bits */ - drop = 0; /* current bits to drop from code for index */ - low = (unsigned)(-1); /* trigger new sub-table when len > root */ - used = 1U << root; /* use root table entries */ - mask = used - 1; /* mask for comparing low */ - - /* check available table space */ - if (type == LENS && used >= ENOUGH - MAXD) - return 1; - - /* process all codes and make table entries */ - for (;;) { - /* create table entry */ - this.bits = (unsigned char)(len - drop); - if ((int)(work[sym]) < end) { - this.op = (unsigned char)0; - this.val = work[sym]; - } - else if ((int)(work[sym]) > end) { - this.op = (unsigned char)(extra[work[sym]]); - this.val = base[work[sym]]; - } - else { - this.op = (unsigned char)(32 + 64); /* end of block */ - this.val = 0; - } - - /* replicate for those indices with low len bits equal to huff */ - incr = 1U << (len - drop); - fill = 1U << curr; - do { - fill -= incr; - next[(huff >> drop) + fill] = this; - } while (fill != 0); - - /* backwards increment the len-bit code huff */ - incr = 1U << (len - 1); - while (huff & incr) - incr >>= 1; - if (incr != 0) { - huff &= incr - 1; - huff += incr; - } - else - huff = 0; - - /* go to next symbol, update count, len */ - sym++; - if (--(count[len]) == 0) { - if (len == max) break; - len = lens[work[sym]]; - } - - /* create new sub-table if needed */ - if (len > root && (huff & mask) != low) { - /* if first time, transition to sub-tables */ - if (drop == 0) - drop = root; - - /* increment past last table */ - next += 1U << curr; - - /* determine length of next table */ - curr = len - drop; - left = (int)(1 << curr); - while (curr + drop < max) { - left -= count[curr + drop]; - if (left <= 0) break; - curr++; - left <<= 1; - } - - /* check for enough space */ - used += 1U << curr; - if (type == LENS && used >= ENOUGH - MAXD) - return 1; - - /* point entry in root table to sub-table */ - low = huff & mask; - (*table)[low].op = (unsigned char)curr; - (*table)[low].bits = (unsigned char)root; - (*table)[low].val = (unsigned short)(next - *table); - } - } - - /* - Fill in rest of table for incomplete codes. This loop is similar to the - loop above in incrementing huff for table indices. It is assumed that - len is equal to curr + drop, so there is no loop needed to increment - through high index bits. When the current sub-table is filled, the loop - drops back to the root table to fill in any remaining entries there. - */ - this.op = (unsigned char)64; /* invalid code marker */ - this.bits = (unsigned char)(len - drop); - this.val = (unsigned short)0; - while (huff != 0) { - /* when done with sub-table, drop back to root table */ - if (drop != 0 && (huff & mask) != low) { - drop = 0; - len = root; - next = *table; - curr = root; - this.bits = (unsigned char)len; - } - - /* put invalid code marker in table */ - next[huff >> drop] = this; - - /* backwards increment the len-bit code huff */ - incr = 1U << (len - 1); - while (huff & incr) - incr >>= 1; - if (incr != 0) { - huff &= incr - 1; - huff += incr; - } - else - huff = 0; - } - - /* set return parameters */ - *table += used; - *bits = root; - return 0; -} +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.1 Copyright 1995-2003 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 76, 66}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) return -1; /* no codes! */ + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || (codes - count[0] != 1))) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += 1U << curr; + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + curr = root; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/plugins/CDVDisoEFP/src/zlib/inftrees.h b/plugins/CDVDisoEFP/src/zlib/inftrees.h index 1dbfe53a6a..82d365a7e9 100644 --- a/plugins/CDVDisoEFP/src/zlib/inftrees.h +++ b/plugins/CDVDisoEFP/src/zlib/inftrees.h @@ -1,55 +1,55 @@ -/* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* Structure for decoding tables. Each entry provides either the - information needed to do the operation requested by the code that - indexed that table entry, or it provides a pointer to another - table that indexes more bits of the code. op indicates whether - the entry is a pointer to another table, a literal, a length or - distance, an end-of-block, or an invalid code. For a table - pointer, the low four bits of op is the number of index bits of - that table. For a length or distance, the low four bits of op - is the number of extra bits to get after the code. bits is - the number of bits in this code or part of the code to drop off - of the bit buffer. val is the actual byte to output in the case - of a literal, the base length or distance, or the offset from - the current table to the next table. Each entry is four bytes. */ -typedef struct { - unsigned char op; /* operation, extra bits, table bits */ - unsigned char bits; /* bits in this part of the code */ - unsigned short val; /* offset in table or code value */ -} code; - -/* op values as set by inflate_table(): - 00000000 - literal - 0000tttt - table link, tttt != 0 is the number of table index bits - 0001eeee - length or distance, eeee is the number of extra bits - 01100000 - end of block - 01000000 - invalid code - */ - -/* Maximum size of dynamic tree. The maximum found in a long but non- - exhaustive search was 1004 code structures (850 for length/literals - and 154 for distances, the latter actually the result of an - exhaustive search). The true maximum is not known, but the value - below is more than safe. */ -#define ENOUGH 1440 -#define MAXD 154 - -/* Type of code to build for inftable() */ -typedef enum { - CODES, - LENS, - DISTS -} codetype; - -extern int inflate_table OF((codetype type, unsigned short FAR *lens, - unsigned codes, code FAR * FAR *table, - unsigned FAR *bits, unsigned short FAR *work)); +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 code structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 1440 +#define MAXD 154 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/plugins/CDVDisoEFP/src/zlib/trees.c b/plugins/CDVDisoEFP/src/zlib/trees.c index d0bce9f2f1..b0c6e41c70 100644 --- a/plugins/CDVDisoEFP/src/zlib/trees.c +++ b/plugins/CDVDisoEFP/src/zlib/trees.c @@ -1,1215 +1,1215 @@ -/* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2003 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process uses several Huffman trees. The more - * common source values are represented by shorter bit sequences. - * - * Each code tree is stored in a compressed form which is itself - * a Huffman encoding of the lengths of all the code strings (in - * ascending order by source values). The actual code strings are - * reconstructed from the lengths in the inflate process, as described - * in the deflate specification. - * - * REFERENCES - * - * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". - * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc - * - * Storer, James A. - * Data Compression: Methods and Theory, pp. 49-50. - * Computer Science Press, 1988. ISBN 0-7167-8156-5. - * - * Sedgewick, R. - * Algorithms, p290. - * Addison-Wesley, 1983. ISBN 0-201-06672-6. - */ - -/* @(#) $Id: trees.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ - -/* #define GEN_TREES_H */ - -#include "deflate.h" - -#ifdef DEBUG -# include -#endif - -/* =========================================================================== - * Constants - */ - -#define MAX_BL_BITS 7 -/* Bit length codes must not exceed MAX_BL_BITS bits */ - -#define END_BLOCK 256 -/* end of block literal code */ - -#define REP_3_6 16 -/* repeat previous bit length 3-6 times (2 bits of repeat count) */ - -#define REPZ_3_10 17 -/* repeat a zero length 3-10 times (3 bits of repeat count) */ - -#define REPZ_11_138 18 -/* repeat a zero length 11-138 times (7 bits of repeat count) */ - -local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ - = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; - -local const int extra_dbits[D_CODES] /* extra bits for each distance code */ - = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ - = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; - -local const uch bl_order[BL_CODES] - = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; -/* The lengths of the bit length codes are sent in order of decreasing - * probability, to avoid transmitting the lengths for unused bit length codes. - */ - -#define Buf_size (8 * 2*sizeof(char)) -/* Number of bits used within bi_buf. (bi_buf might be implemented on - * more than 16 bits on some systems.) - */ - -/* =========================================================================== - * Local data. These are initialized only once. - */ - -#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ - -#if defined(GEN_TREES_H) || !defined(STDC) -/* non ANSI compilers may not accept trees.h */ - -local ct_data static_ltree[L_CODES+2]; -/* The static literal tree. Since the bit lengths are imposed, there is no - * need for the L_CODES extra codes used during heap construction. However - * The codes 286 and 287 are needed to build a canonical tree (see _tr_init - * below). - */ - -local ct_data static_dtree[D_CODES]; -/* The static distance tree. (Actually a trivial tree since all codes use - * 5 bits.) - */ - -uch _dist_code[DIST_CODE_LEN]; -/* Distance codes. The first 256 values correspond to the distances - * 3 .. 258, the last 256 values correspond to the top 8 bits of - * the 15 bit distances. - */ - -uch _length_code[MAX_MATCH-MIN_MATCH+1]; -/* length code for each normalized match length (0 == MIN_MATCH) */ - -local int base_length[LENGTH_CODES]; -/* First normalized length for each code (0 = MIN_MATCH) */ - -local int base_dist[D_CODES]; -/* First normalized distance for each code (0 = distance of 1) */ - -#else -# include "trees.h" -#endif /* GEN_TREES_H */ - -struct static_tree_desc_s { - const ct_data *static_tree; /* static tree or NULL */ - const intf *extra_bits; /* extra bits for each code or NULL */ - int extra_base; /* base index for extra_bits */ - int elems; /* max number of elements in the tree */ - int max_length; /* max bit length for the codes */ -}; - -local static_tree_desc static_l_desc = -{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; - -local static_tree_desc static_d_desc = -{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; - -local static_tree_desc static_bl_desc = -{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; - -/* =========================================================================== - * Local (static) routines in this file. - */ - -local void tr_static_init OF((void)); -local void init_block OF((deflate_state *s)); -local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); -local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); -local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); -local void build_tree OF((deflate_state *s, tree_desc *desc)); -local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local int build_bl_tree OF((deflate_state *s)); -local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, - int blcodes)); -local void compress_block OF((deflate_state *s, ct_data *ltree, - ct_data *dtree)); -local void set_data_type OF((deflate_state *s)); -local unsigned bi_reverse OF((unsigned value, int length)); -local void bi_windup OF((deflate_state *s)); -local void bi_flush OF((deflate_state *s)); -local void copy_block OF((deflate_state *s, charf *buf, unsigned len, - int header)); - -#ifdef GEN_TREES_H -local void gen_trees_header OF((void)); -#endif - -#ifndef DEBUG -# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) - /* Send a code of the given tree. c and tree must not have side effects */ - -#else /* DEBUG */ -# define send_code(s, c, tree) \ - { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ - send_bits(s, tree[c].Code, tree[c].Len); } -#endif - -/* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ -#define put_short(s, w) { \ - put_byte(s, (uch)((w) & 0xff)); \ - put_byte(s, (uch)((ush)(w) >> 8)); \ -} - -/* =========================================================================== - * Send a value on a given number of bits. - * IN assertion: length <= 16 and value fits in length bits. - */ -#ifdef DEBUG -local void send_bits OF((deflate_state *s, int value, int length)); - -local void send_bits(s, value, length) - deflate_state *s; - int value; /* value to send */ - int length; /* number of bits */ -{ - Tracevv((stderr," l %2d v %4x ", length, value)); - Assert(length > 0 && length <= 15, "invalid length"); - s->bits_sent += (ulg)length; - - /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) - * unused bits in value. - */ - if (s->bi_valid > (int)Buf_size - length) { - s->bi_buf |= (value << s->bi_valid); - put_short(s, s->bi_buf); - s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); - s->bi_valid += length - Buf_size; - } else { - s->bi_buf |= value << s->bi_valid; - s->bi_valid += length; - } -} -#else /* !DEBUG */ - -#define send_bits(s, value, length) \ -{ int len = length;\ - if (s->bi_valid > (int)Buf_size - len) {\ - int val = value;\ - s->bi_buf |= (val << s->bi_valid);\ - put_short(s, s->bi_buf);\ - s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ - s->bi_valid += len - Buf_size;\ - } else {\ - s->bi_buf |= (value) << s->bi_valid;\ - s->bi_valid += len;\ - }\ -} -#endif /* DEBUG */ - - -/* the arguments must not have side effects */ - -/* =========================================================================== - * Initialize the various 'constant' tables. - */ -local void tr_static_init() -{ -#if defined(GEN_TREES_H) || !defined(STDC) - static int static_init_done = 0; - int n; /* iterates over tree elements */ - int bits; /* bit counter */ - int length; /* length value */ - int code; /* code value */ - int dist; /* distance index */ - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - if (static_init_done) return; - - /* For some embedded targets, global variables are not initialized: */ - static_l_desc.static_tree = static_ltree; - static_l_desc.extra_bits = extra_lbits; - static_d_desc.static_tree = static_dtree; - static_d_desc.extra_bits = extra_dbits; - static_bl_desc.extra_bits = extra_blbits; - - /* Initialize the mapping length (0..255) -> length code (0..28) */ - length = 0; - for (code = 0; code < LENGTH_CODES-1; code++) { - base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ - dist = 0; - for (code = 0 ; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ - for ( ; code < D_CODES; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { - _dist_code[256 + dist++] = (uch)code; - } - } - Assert (dist == 256, "tr_static_init: 256+dist != 512"); - - /* Construct the codes of the static literal tree */ - for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; - n = 0; - while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; - while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; - while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; - while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; - /* Codes 286 and 287 do not exist, but we must include them in the - * tree construction to get a canonical Huffman tree (longest code - * all ones) - */ - gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); - - /* The static distance tree is trivial: */ - for (n = 0; n < D_CODES; n++) { - static_dtree[n].Len = 5; - static_dtree[n].Code = bi_reverse((unsigned)n, 5); - } - static_init_done = 1; - -# ifdef GEN_TREES_H - gen_trees_header(); -# endif -#endif /* defined(GEN_TREES_H) || !defined(STDC) */ -} - -/* =========================================================================== - * Genererate the file trees.h describing the static trees. - */ -#ifdef GEN_TREES_H -# ifndef DEBUG -# include -# endif - -# define SEPARATOR(i, last, width) \ - ((i) == (last)? "\n};\n\n" : \ - ((i) % (width) == (width)-1 ? ",\n" : ", ")) - -void gen_trees_header() -{ - FILE *header = fopen("trees.h", "w"); - int i; - - Assert (header != NULL, "Can't open trees.h"); - fprintf(header, - "/* header created automatically with -DGEN_TREES_H */\n\n"); - - fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); - for (i = 0; i < L_CODES+2; i++) { - fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, - static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); - } - - fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); - for (i = 0; i < D_CODES; i++) { - fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, - static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); - } - - fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); - for (i = 0; i < DIST_CODE_LEN; i++) { - fprintf(header, "%2u%s", _dist_code[i], - SEPARATOR(i, DIST_CODE_LEN-1, 20)); - } - - fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); - for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { - fprintf(header, "%2u%s", _length_code[i], - SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); - } - - fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); - for (i = 0; i < LENGTH_CODES; i++) { - fprintf(header, "%1u%s", base_length[i], - SEPARATOR(i, LENGTH_CODES-1, 20)); - } - - fprintf(header, "local const int base_dist[D_CODES] = {\n"); - for (i = 0; i < D_CODES; i++) { - fprintf(header, "%5u%s", base_dist[i], - SEPARATOR(i, D_CODES-1, 10)); - } - - fclose(header); -} -#endif /* GEN_TREES_H */ - -/* =========================================================================== - * Initialize the tree data structures for a new zlib stream. - */ -void _tr_init(s) - deflate_state *s; -{ - tr_static_init(); - - s->l_desc.dyn_tree = s->dyn_ltree; - s->l_desc.stat_desc = &static_l_desc; - - s->d_desc.dyn_tree = s->dyn_dtree; - s->d_desc.stat_desc = &static_d_desc; - - s->bl_desc.dyn_tree = s->bl_tree; - s->bl_desc.stat_desc = &static_bl_desc; - - s->bi_buf = 0; - s->bi_valid = 0; - s->last_eob_len = 8; /* enough lookahead for inflate */ -#ifdef DEBUG - s->compressed_len = 0L; - s->bits_sent = 0L; -#endif - - /* Initialize the first block of the first file: */ - init_block(s); -} - -/* =========================================================================== - * Initialize a new block. - */ -local void init_block(s) - deflate_state *s; -{ - int n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; - for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; - for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; - - s->dyn_ltree[END_BLOCK].Freq = 1; - s->opt_len = s->static_len = 0L; - s->last_lit = s->matches = 0; -} - -#define SMALLEST 1 -/* Index within the heap array of least frequent node in the Huffman tree */ - - -/* =========================================================================== - * Remove the smallest element from the heap and recreate the heap with - * one less element. Updates heap and heap_len. - */ -#define pqremove(s, tree, top) \ -{\ - top = s->heap[SMALLEST]; \ - s->heap[SMALLEST] = s->heap[s->heap_len--]; \ - pqdownheap(s, tree, SMALLEST); \ -} - -/* =========================================================================== - * Compares to subtrees, using the tree depth as tie breaker when - * the subtrees have equal frequency. This minimizes the worst case length. - */ -#define smaller(tree, n, m, depth) \ - (tree[n].Freq < tree[m].Freq || \ - (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) - -/* =========================================================================== - * Restore the heap property by moving down the tree starting at node k, - * exchanging a node with the smallest of its two sons if necessary, stopping - * when the heap property is re-established (each father smaller than its - * two sons). - */ -local void pqdownheap(s, tree, k) - deflate_state *s; - ct_data *tree; /* the tree to restore */ - int k; /* node to move down */ -{ - int v = s->heap[k]; - int j = k << 1; /* left son of k */ - while (j <= s->heap_len) { - /* Set j to the smallest of the two sons: */ - if (j < s->heap_len && - smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { - j++; - } - /* Exit if v is smaller than both sons */ - if (smaller(tree, v, s->heap[j], s->depth)) break; - - /* Exchange v with the smallest son */ - s->heap[k] = s->heap[j]; k = j; - - /* And continue down the tree, setting j to the left son of k */ - j <<= 1; - } - s->heap[k] = v; -} - -/* =========================================================================== - * Compute the optimal bit lengths for a tree and update the total bit length - * for the current block. - * IN assertion: the fields freq and dad are set, heap[heap_max] and - * above are the tree nodes sorted by increasing frequency. - * OUT assertions: the field len is set to the optimal bit length, the - * array bl_count contains the frequencies for each bit length. - * The length opt_len is updated; static_len is also updated if stree is - * not null. - */ -local void gen_bitlen(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ -{ - ct_data *tree = desc->dyn_tree; - int max_code = desc->max_code; - const ct_data *stree = desc->stat_desc->static_tree; - const intf *extra = desc->stat_desc->extra_bits; - int base = desc->stat_desc->extra_base; - int max_length = desc->stat_desc->max_length; - int h; /* heap index */ - int n, m; /* iterate over the tree elements */ - int bits; /* bit length */ - int xbits; /* extra bits */ - ush f; /* frequency */ - int overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; - - /* In a first pass, compute the optimal bit lengths (which may - * overflow in the case of the bit length tree). - */ - tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - - for (h = s->heap_max+1; h < HEAP_SIZE; h++) { - n = s->heap[h]; - bits = tree[tree[n].Dad].Len + 1; - if (bits > max_length) bits = max_length, overflow++; - tree[n].Len = (ush)bits; - /* We overwrite tree[n].Dad which is no longer needed */ - - if (n > max_code) continue; /* not a leaf node */ - - s->bl_count[bits]++; - xbits = 0; - if (n >= base) xbits = extra[n-base]; - f = tree[n].Freq; - s->opt_len += (ulg)f * (bits + xbits); - if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); - } - if (overflow == 0) return; - - Trace((stderr,"\nbit length overflow\n")); - /* This happens for example on obj2 and pic of the Calgary corpus */ - - /* Find the first bit length which could increase: */ - do { - bits = max_length-1; - while (s->bl_count[bits] == 0) bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ - s->bl_count[max_length]--; - /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] - */ - overflow -= 2; - } while (overflow > 0); - - /* Now recompute all bit lengths, scanning in increasing frequency. - * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - * lengths instead of fixing only the wrong ones. This idea is taken - * from 'ar' written by Haruhiko Okumura.) - */ - for (bits = max_length; bits != 0; bits--) { - n = s->bl_count[bits]; - while (n != 0) { - m = s->heap[--h]; - if (m > max_code) continue; - if (tree[m].Len != (unsigned) bits) { - Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); - s->opt_len += ((long)bits - (long)tree[m].Len) - *(long)tree[m].Freq; - tree[m].Len = (ush)bits; - } - n--; - } - } -} - -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -local void gen_codes (tree, max_code, bl_count) - ct_data *tree; /* the tree to decorate */ - int max_code; /* largest code with non zero frequency */ - ushf *bl_count; /* number of codes at each bit length */ -{ - ush next_code[MAX_BITS+1]; /* next code value for each bit length */ - ush code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (code + bl_count[bits-1]) << 1; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; - const ct_data *stree = desc->stat_desc->static_tree; - int elems = desc->stat_desc->elems; - int n, m; /* iterate over heap elements */ - int max_code = -1; /* largest code with non zero frequency */ - int node; /* new node being created */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - s->heap_len = 0, s->heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) { - if (tree[n].Freq != 0) { - s->heap[++(s->heap_len)] = max_code = n; - s->depth[n] = 0; - } else { - tree[n].Len = 0; - } - } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (s->heap_len < 2) { - node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); - tree[node].Freq = 1; - s->depth[node] = 0; - s->opt_len--; if (stree) s->static_len -= stree[node].Len; - /* node is 0 or 1 so it does not have extra bits */ - } - desc->max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - node = elems; /* next internal node of the tree */ - do { - pqremove(s, tree, n); /* n = node of least frequency */ - m = s->heap[SMALLEST]; /* m = node of next least frequency */ - - s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ - s->heap[--(s->heap_max)] = m; - - /* Create a new node father of n and m */ - tree[node].Freq = tree[n].Freq + tree[m].Freq; - s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? - s->depth[n] : s->depth[m]) + 1); - tree[n].Dad = tree[m].Dad = (ush)node; -#ifdef DUMP_BL_TREE - if (tree == s->bl_tree) { - fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", - node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); - } -#endif - /* and insert the new node in the heap */ - s->heap[SMALLEST] = node++; - pqdownheap(s, tree, SMALLEST); - - } while (s->heap_len >= 2); - - s->heap[--(s->heap_max)] = s->heap[SMALLEST]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen(s, (tree_desc *)desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes ((ct_data *)tree, max_code, s->bl_count); -} - -/* =========================================================================== - * Scan a literal or distance tree to determine the frequencies of the codes - * in the bit length tree. - */ -local void scan_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].Len = (ush)0xffff; /* guard */ - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - s->bl_tree[curlen].Freq += count; - } else if (curlen != 0) { - if (curlen != prevlen) s->bl_tree[curlen].Freq++; - s->bl_tree[REP_3_6].Freq++; - } else if (count <= 10) { - s->bl_tree[REPZ_3_10].Freq++; - } else { - s->bl_tree[REPZ_11_138].Freq++; - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Send a literal or distance tree in compressed form, using the codes in - * bl_tree. - */ -local void send_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - /* tree[max_code+1].Len = -1; */ /* guard already set */ - if (nextlen == 0) max_count = 138, min_count = 3; - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - do { send_code(s, curlen, s->bl_tree); } while (--count != 0); - - } else if (curlen != 0) { - if (curlen != prevlen) { - send_code(s, curlen, s->bl_tree); count--; - } - Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); - - } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); - - } else { - send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Construct the Huffman tree for the bit lengths and return the index in - * bl_order of the last bit length code to send. - */ -local int build_bl_tree(s) - deflate_state *s; -{ - int max_blindex; /* index of last bit length code of non zero freq */ - - /* Determine the bit length frequencies for literal and distance trees */ - scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); - scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); - - /* Build the bit length tree: */ - build_tree(s, (tree_desc *)(&(s->bl_desc))); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - */ - - /* Determine the number of bit length codes to send. The pkzip format - * requires that at least 4 bit length codes be sent. (appnote.txt says - * 3 but the actual value used is 4.) - */ - for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { - if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; - } - /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*(max_blindex+1) + 5+5+4; - Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", - s->opt_len, s->static_len)); - - return max_blindex; -} - -/* =========================================================================== - * Send the header for a block using dynamic Huffman trees: the counts, the - * lengths of the bit length codes, the literal tree and the distance tree. - * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - */ -local void send_all_trees(s, lcodes, dcodes, blcodes) - deflate_state *s; - int lcodes, dcodes, blcodes; /* number of codes for each tree */ -{ - int rank; /* index in bl_order */ - - Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); - Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, - "too many codes"); - Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ - for (rank = 0; rank < blcodes; rank++) { - Tracev((stderr, "\nbl code %2d ", bl_order[rank])); - send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); - } - Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ - Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ - Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); -} - -/* =========================================================================== - * Send a stored block - */ -void _tr_stored_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ -{ - send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ -#ifdef DEBUG - s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; - s->compressed_len += (stored_len + 4) << 3; -#endif - copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ -} - -/* =========================================================================== - * Send one empty static block to give enough lookahead for inflate. - * This takes 10 bits, of which 7 may remain in the bit buffer. - * The current inflate code requires 9 bits of lookahead. If the - * last two codes for the previous block (real code plus EOB) were coded - * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode - * the last real code. In this case we send two empty static blocks instead - * of one. (There are no problems if the previous block is stored or fixed.) - * To simplify the code, we assume the worst case of last real code encoded - * on one bit only. - */ -void _tr_align(s) - deflate_state *s; -{ - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); -#ifdef DEBUG - s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ -#endif - bi_flush(s); - /* Of the 10 bits for the empty block, we have already sent - * (10 - bi_valid) bits. The lookahead for the last real code (before - * the EOB of the previous block) was thus at least one plus the length - * of the EOB plus what we have just sent of the empty static block. - */ - if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); -#ifdef DEBUG - s->compressed_len += 10L; -#endif - bi_flush(s); - } - s->last_eob_len = 7; -} - -/* =========================================================================== - * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. - */ -void _tr_flush_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block, or NULL if too old */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ -{ - ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ - int max_blindex = 0; /* index of last bit length code of non zero freq */ - - /* Build the Huffman trees unless a stored block is forced */ - if (s->level > 0) { - - /* Check if the file is ascii or binary */ - if (s->data_type == Z_UNKNOWN) set_data_type(s); - - /* Construct the literal and distance trees */ - build_tree(s, (tree_desc *)(&(s->l_desc))); - Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - - build_tree(s, (tree_desc *)(&(s->d_desc))); - Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ - - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(s); - - /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; - - Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", - opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - s->last_lit)); - - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; - - } else { - Assert(buf != (char*)0, "lost buf"); - opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ - } - -#ifdef FORCE_STORED - if (buf != (char*)0) { /* force stored block */ -#else - if (stored_len+4 <= opt_lenb && buf != (char*)0) { - /* 4: two words for the lengths */ -#endif - /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - * Otherwise we can't have processed more than WSIZE input bytes since - * the last block flush, because compression would have been - * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - * transform a block into a stored block. - */ - _tr_stored_block(s, buf, stored_len, eof); - -#ifdef FORCE_STATIC - } else if (static_lenb >= 0) { /* force static trees */ -#else - } else if (static_lenb == opt_lenb) { -#endif - send_bits(s, (STATIC_TREES<<1)+eof, 3); - compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); -#ifdef DEBUG - s->compressed_len += 3 + s->static_len; -#endif - } else { - send_bits(s, (DYN_TREES<<1)+eof, 3); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, - max_blindex+1); - compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); -#ifdef DEBUG - s->compressed_len += 3 + s->opt_len; -#endif - } - Assert (s->compressed_len == s->bits_sent, "bad compressed size"); - /* The above check is made mod 2^32, for files larger than 512 MB - * and uLong implemented on 32 bits. - */ - init_block(s); - - if (eof) { - bi_windup(s); -#ifdef DEBUG - s->compressed_len += 7; /* align on byte boundary */ -#endif - } - Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - s->compressed_len-7*eof)); -} - -/* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ -int _tr_tally (s, dist, lc) - deflate_state *s; - unsigned dist; /* distance of matched string */ - unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ -{ - s->d_buf[s->last_lit] = (ush)dist; - s->l_buf[s->last_lit++] = (uch)lc; - if (dist == 0) { - /* lc is the unmatched char */ - s->dyn_ltree[lc].Freq++; - } else { - s->matches++; - /* Here, lc is the match length - MIN_MATCH */ - dist--; /* dist = match distance - 1 */ - Assert((ush)dist < (ush)MAX_DIST(s) && - (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && - (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - - s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; - s->dyn_dtree[d_code(dist)].Freq++; - } - -#ifdef TRUNCATE_BLOCK - /* Try to guess if it is profitable to stop the current block here */ - if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { - /* Compute an upper bound for the compressed length */ - ulg out_length = (ulg)s->last_lit*8L; - ulg in_length = (ulg)((long)s->strstart - s->block_start); - int dcode; - for (dcode = 0; dcode < D_CODES; dcode++) { - out_length += (ulg)s->dyn_dtree[dcode].Freq * - (5L+extra_dbits[dcode]); - } - out_length >>= 3; - Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", - s->last_lit, in_length, out_length, - 100L - out_length*100L/in_length)); - if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; - } -#endif - return (s->last_lit == s->lit_bufsize-1); - /* We avoid equality with lit_bufsize because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ -} - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -local void compress_block(s, ltree, dtree) - deflate_state *s; - ct_data *ltree; /* literal tree */ - ct_data *dtree; /* distance tree */ -{ - unsigned dist; /* distance of matched string */ - int lc; /* match length or unmatched char (if dist == 0) */ - unsigned lx = 0; /* running index in l_buf */ - unsigned code; /* the code to send */ - int extra; /* number of extra bits to send */ - - if (s->last_lit != 0) do { - dist = s->d_buf[lx]; - lc = s->l_buf[lx++]; - if (dist == 0) { - send_code(s, lc, ltree); /* send a literal byte */ - Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = _length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra != 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra != 0) { - dist -= base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ - Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, - "pendingBuf overflow"); - - } while (lx < s->last_lit); - - send_code(s, END_BLOCK, ltree); - s->last_eob_len = ltree[END_BLOCK].Len; -} - -/* =========================================================================== - * Set the data type to ASCII or BINARY, using a crude approximation: - * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. - * IN assertion: the fields freq of dyn_ltree are set and the total of all - * frequencies does not exceed 64K (to fit in an int on 16 bit machines). - */ -local void set_data_type(s) - deflate_state *s; -{ - int n = 0; - unsigned ascii_freq = 0; - unsigned bin_freq = 0; - while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; - while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; - while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; - s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); -} - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -local unsigned bi_reverse(code, len) - unsigned code; /* the value to invert */ - int len; /* its bit length */ -{ - register unsigned res = 0; - do { - res |= code & 1; - code >>= 1, res <<= 1; - } while (--len > 0); - return res >> 1; -} - -/* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ -local void bi_flush(s) - deflate_state *s; -{ - if (s->bi_valid == 16) { - put_short(s, s->bi_buf); - s->bi_buf = 0; - s->bi_valid = 0; - } else if (s->bi_valid >= 8) { - put_byte(s, (Byte)s->bi_buf); - s->bi_buf >>= 8; - s->bi_valid -= 8; - } -} - -/* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ -local void bi_windup(s) - deflate_state *s; -{ - if (s->bi_valid > 8) { - put_short(s, s->bi_buf); - } else if (s->bi_valid > 0) { - put_byte(s, (Byte)s->bi_buf); - } - s->bi_buf = 0; - s->bi_valid = 0; -#ifdef DEBUG - s->bits_sent = (s->bits_sent+7) & ~7; -#endif -} - -/* =========================================================================== - * Copy a stored block, storing first the length and its - * one's complement if requested. - */ -local void copy_block(s, buf, len, header) - deflate_state *s; - charf *buf; /* the input data */ - unsigned len; /* its length */ - int header; /* true if block header must be written */ -{ - bi_windup(s); /* align on byte boundary */ - s->last_eob_len = 8; /* enough lookahead for inflate */ - - if (header) { - put_short(s, (ush)len); - put_short(s, (ush)~len); -#ifdef DEBUG - s->bits_sent += 2*16; -#endif - } -#ifdef DEBUG - s->bits_sent += (ulg)len<<3; -#endif - while (len--) { - put_byte(s, *buf++); - } -} +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2003 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id: trees.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if (tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is ascii or binary */ + if (s->data_type == Z_UNKNOWN) set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +local void set_data_type(s) + deflate_state *s; +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; + while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; + while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; + s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/plugins/CDVDisoEFP/src/zlib/trees.h b/plugins/CDVDisoEFP/src/zlib/trees.h index 1ca868b848..72facf900f 100644 --- a/plugins/CDVDisoEFP/src/zlib/trees.h +++ b/plugins/CDVDisoEFP/src/zlib/trees.h @@ -1,128 +1,128 @@ -/* header created automatically with -DGEN_TREES_H */ - -local const ct_data static_ltree[L_CODES+2] = { -{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, -{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, -{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, -{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, -{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, -{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, -{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, -{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, -{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, -{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, -{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, -{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, -{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, -{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, -{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, -{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, -{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, -{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, -{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, -{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, -{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, -{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, -{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, -{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, -{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, -{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, -{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, -{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, -{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, -{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, -{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, -{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, -{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, -{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, -{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, -{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, -{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, -{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, -{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, -{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, -{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, -{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, -{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, -{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, -{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, -{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, -{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, -{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, -{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, -{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, -{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, -{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, -{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, -{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, -{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, -{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, -{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, -{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} -}; - -local const ct_data static_dtree[D_CODES] = { -{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, -{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, -{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, -{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, -{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, -{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} -}; - -const uch _dist_code[DIST_CODE_LEN] = { - 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, - 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, -10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, -11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, -12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, -18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 -}; - -const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, -13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, -17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, -19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, -21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, -22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 -}; - -local const int base_length[LENGTH_CODES] = { -0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, -64, 80, 96, 112, 128, 160, 192, 224, 0 -}; - -local const int base_dist[D_CODES] = { - 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, - 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, - 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 -}; - +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/plugins/CDVDisoEFP/src/zlib/uncompr.c b/plugins/CDVDisoEFP/src/zlib/uncompr.c index 82ebef75f8..12eec9fec9 100644 --- a/plugins/CDVDisoEFP/src/zlib/uncompr.c +++ b/plugins/CDVDisoEFP/src/zlib/uncompr.c @@ -1,61 +1,61 @@ -/* uncompr.c -- decompress a memory buffer - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id: uncompr.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -/* =========================================================================== - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted. -*/ -int ZEXPORT uncompress (dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ - z_stream stream; - int err; - - stream.next_in = (Bytef*)source; - stream.avail_in = (uInt)sourceLen; - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; - - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; - - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - - err = inflateInit(&stream); - if (err != Z_OK) return err; - - err = inflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - inflateEnd(&stream); - if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) - return Z_DATA_ERROR; - return err; - } - *destLen = stream.total_out; - - err = inflateEnd(&stream); - return err; -} +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: uncompr.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/plugins/CDVDisoEFP/src/zlib/zconf.h b/plugins/CDVDisoEFP/src/zlib/zconf.h index f4cfc216e1..9f0453756a 100644 --- a/plugins/CDVDisoEFP/src/zlib/zconf.h +++ b/plugins/CDVDisoEFP/src/zlib/zconf.h @@ -1,323 +1,323 @@ -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id: zconf.h,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ - -#ifndef ZCONF_H -#define ZCONF_H - -/* - * If you *really* need a unique prefix for all types and library functions, - * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. - */ -#ifdef Z_PREFIX -# define deflateInit_ z_deflateInit_ -# define deflate z_deflate -# define deflateEnd z_deflateEnd -# define inflateInit_ z_inflateInit_ -# define inflate z_inflate -# define inflateEnd z_inflateEnd -# define deflateInit2_ z_deflateInit2_ -# define deflateSetDictionary z_deflateSetDictionary -# define deflateCopy z_deflateCopy -# define deflateReset z_deflateReset -# define deflatePrime z_deflatePrime -# define deflateParams z_deflateParams -# define deflateBound z_deflateBound -# define inflateInit2_ z_inflateInit2_ -# define inflateSetDictionary z_inflateSetDictionary -# define inflateSync z_inflateSync -# define inflateSyncPoint z_inflateSyncPoint -# define inflateCopy z_inflateCopy -# define inflateReset z_inflateReset -# define compress z_compress -# define compress2 z_compress2 -# define compressBound z_compressBound -# define uncompress z_uncompress -# define adler32 z_adler32 -# define crc32 z_crc32 -# define get_crc_table z_get_crc_table - -# define Byte z_Byte -# define uInt z_uInt -# define uLong z_uLong -# define Bytef z_Bytef -# define charf z_charf -# define intf z_intf -# define uIntf z_uIntf -# define uLongf z_uLongf -# define voidpf z_voidpf -# define voidp z_voidp -#endif - -#if defined(__MSDOS__) && !defined(MSDOS) -# define MSDOS -#endif -#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) -# define OS2 -#endif -#if defined(_WINDOWS) && !defined(WINDOWS) -# define WINDOWS -#endif -#if (defined(_WIN32) || defined(_WIN32)) && !defined(WIN32) -# define WIN32 -#endif -#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) -# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) -# ifndef SYS16BIT -# define SYS16BIT -# endif -# endif -#endif - -/* - * Compile with -DMAXSEG_64K if the alloc function cannot allocate more - * than 64k bytes at a time (needed on systems with 16-bit int). - */ -#ifdef SYS16BIT -# define MAXSEG_64K -#endif -#ifdef MSDOS -# define UNALIGNED_OK -#endif - -#ifdef __STDC_VERSION__ -# ifndef STDC -# define STDC -# endif -# if __STDC_VERSION__ >= 199901L -# ifndef STDC99 -# define STDC99 -# endif -# endif -#endif -#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) -# define STDC -#endif -#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) -# define STDC -#endif -#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) -# define STDC -#endif -#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) -# define STDC -#endif - -#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ -# define STDC -#endif - -#ifndef STDC -# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ -# define const /* note: need a more gentle solution here */ -# endif -#endif - -/* Some Mac compilers merge all .h files incorrectly: */ -#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) -# define NO_DUMMY_DECL -#endif - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# ifdef MAXSEG_64K -# define MAX_MEM_LEVEL 8 -# else -# define MAX_MEM_LEVEL 9 -# endif -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2. - * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files - * created by gzip. (Files created by minigzip can still be extracted by - * gzip.) - */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - (1 << (windowBits+2)) + (1 << (memLevel+9)) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects. -*/ - - /* Type declarations */ - -#ifndef OF /* function prototypes */ -# ifdef STDC -# define OF(args) args -# else -# define OF(args) () -# endif -#endif - -/* The following definitions for FAR are needed only for MSDOS mixed - * model programming (small or medium model with some far allocations). - * This was tested only with MSC; for other MSDOS compilers you may have - * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, - * just define FAR to be empty. - */ -#ifdef SYS16BIT -# if defined(M_I86SM) || defined(M_I86MM) - /* MSC small or medium model */ -# define SMALL_MEDIUM -# ifdef _MSC_VER -# define FAR _far -# else -# define FAR far -# endif -# endif -# if (defined(__SMALL__) || defined(__MEDIUM__)) - /* Turbo C small or medium model */ -# define SMALL_MEDIUM -# ifdef __BORLANDC__ -# define FAR _far -# else -# define FAR far -# endif -# endif -#endif - -#if defined(WINDOWS) || defined(WIN32) - /* If building or using zlib as a DLL, define ZLIB_DLL. - * This is not mandatory, but it offers a little performance increase. - */ -# ifdef ZLIB_DLL -# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) -# ifdef ZLIB_INTERNAL -# define ZEXTERN extern __declspec(dllexport) -# else -# define ZEXTERN extern __declspec(dllimport) -# endif -# endif -# endif /* ZLIB_DLL */ - /* If building or using zlib with the WINAPI/WINAPIV calling convention, - * define ZLIB_WINAPI. - * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. - */ -# ifdef ZLIB_WINAPI -# ifdef FAR -# undef FAR -# endif -# include - /* No need for _export, use ZLIB.DEF instead. */ - /* For complete Windows compatibility, use WINAPI, not __stdcall. */ -# define ZEXPORT WINAPI -# ifdef WIN32 -# define ZEXPORTVA WINAPIV -# else -# define ZEXPORTVA FAR CDECL -# endif -# endif -#endif - -#if defined (__BEOS__) -# ifdef ZLIB_DLL -# ifdef ZLIB_INTERNAL -# define ZEXPORT __declspec(dllexport) -# define ZEXPORTVA __declspec(dllexport) -# else -# define ZEXPORT __declspec(dllimport) -# define ZEXPORTVA __declspec(dllimport) -# endif -# endif -#endif - -#ifndef ZEXTERN -# define ZEXTERN extern -#endif -#ifndef ZEXPORT -# define ZEXPORT -#endif -#ifndef ZEXPORTVA -# define ZEXPORTVA -#endif - -#ifndef FAR -# define FAR -#endif - -#if !defined(__MACTYPES__) -typedef unsigned char Byte; /* 8 bits */ -#endif -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ - -#ifdef SMALL_MEDIUM - /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ -# define Bytef Byte FAR -#else - typedef Byte FAR Bytef; -#endif -typedef char FAR charf; -typedef int FAR intf; -typedef uInt FAR uIntf; -typedef uLong FAR uLongf; - -#ifdef STDC - typedef void const *voidpc; - typedef void FAR *voidpf; - typedef void *voidp; -#else - typedef Byte const *voidpc; - typedef Byte FAR *voidpf; - typedef Byte *voidp; -#endif - -#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ -# include /* for off_t */ -# include /* for SEEK_* and off_t */ -# ifdef VMS -# include /* for off_t */ -# endif -# define z_off_t off_t -#endif -#ifndef SEEK_SET -# define SEEK_SET 0 /* Seek from beginning of file. */ -# define SEEK_CUR 1 /* Seek from current position. */ -# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ -#endif -#ifndef z_off_t -# define z_off_t long -#endif - -#if defined(__OS400__) -#define NO_vsnprintf -#endif - -#if defined(__MVS__) -# define NO_vsnprintf -# ifdef FAR -# undef FAR -# endif -#endif - -/* MVS linker does not support external names larger than 8 bytes */ -#if defined(__MVS__) -# pragma map(deflateInit_,"DEIN") -# pragma map(deflateInit2_,"DEIN2") -# pragma map(deflateEnd,"DEEND") -# pragma map(deflateBound,"DEBND") -# pragma map(inflateInit_,"ININ") -# pragma map(inflateInit2_,"ININ2") -# pragma map(inflateEnd,"INEND") -# pragma map(inflateSync,"INSY") -# pragma map(inflateSetDictionary,"INSEDI") -# pragma map(compressBound,"CMBND") -# pragma map(inflate_table,"INTABL") -# pragma map(inflate_fast,"INFA") -# pragma map(inflate_copyright,"INCOPY") -#endif - -#endif /* ZCONF_H */ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.h,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflatePrime z_deflatePrime +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if (defined(_WIN32) || defined(_WIN32)) && !defined(WIN32) +# define WIN32 +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +#define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/plugins/CDVDisoEFP/src/zlib/zlib.h b/plugins/CDVDisoEFP/src/zlib/zlib.h index d54ac9433f..92edf96ff3 100644 --- a/plugins/CDVDisoEFP/src/zlib/zlib.h +++ b/plugins/CDVDisoEFP/src/zlib/zlib.h @@ -1,1200 +1,1200 @@ -/* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.1, November 17th, 2003 - - Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - - - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). -*/ - -#ifndef ZLIB_H -#define ZLIB_H - -#include "zconf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define ZLIB_VERSION "1.2.1" -#define ZLIB_VERNUM 0x1210 - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed - data. This version of the library supports only one compression method - (deflation) but other algorithms will be added later and will have the same - stream interface. - - Compression can be done in a single step if the buffers are large - enough (for example if an input file is mmap'ed), or can be done by - repeated calls of the compression function. In the latter case, the - application must provide more input and/or consume the output - (providing more output space) before each call. - - The compressed data format used by the in-memory functions is the zlib - format, which is a zlib wrapper documented in RFC 1950, wrapped around a - deflate stream, which is itself documented in RFC 1951. - - The library also supports reading and writing files in gzip (.gz) format - with an interface similar to that of stdio using the functions that start - with "gz". The gzip format is different from the zlib format. gzip is a - gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. - - The zlib format was designed to be compact and fast for use in memory - and on communications channels. The gzip format was designed for single- - file compression on file systems, has a larger header than zlib to maintain - directory information, and uses a different, slower check method than zlib. - - This library does not provide any functions to write gzip files in memory. - However such functions could be easily written using zlib's deflate function, - the documentation in the gzip RFC, and the examples in gzio.c. - - The library does not install any signal handler. The decoder checks - the consistency of the compressed data, so the library should never - crash even in case of corrupted input. -*/ - -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address)); - -struct internal_state; - -typedef struct z_stream_s { - Bytef *next_in; /* next input byte */ - uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total nb of input bytes read so far */ - - Bytef *next_out; /* next output byte should be put there */ - uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total nb of bytes output so far */ - - char *msg; /* last error message, NULL if no error */ - struct internal_state FAR *state; /* not visible by applications */ - - alloc_func zalloc; /* used to allocate the internal state */ - free_func zfree; /* used to free the internal state */ - voidpf opaque; /* private data object passed to zalloc and zfree */ - - int data_type; /* best guess about the data type: ascii or binary */ - uLong adler; /* adler32 value of the uncompressed data */ - uLong reserved; /* reserved for future use */ -} z_stream; - -typedef z_stream FAR *z_streamp; - -/* - The application must update next_in and avail_in when avail_in has - dropped to zero. It must update next_out and avail_out when avail_out - has dropped to zero. The application must initialize zalloc, zfree and - opaque before calling the init function. All other fields are set by the - compression library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - If zlib is used in a multi-threaded application, zalloc and zfree must be - thread safe. - - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this - if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, - pointers returned by zalloc for objects of exactly 65536 bytes *must* - have their offset normalized to zero. The default allocation function - provided by this library ensures this (see zutil.c). To reduce memory - requirements and avoid any allocation of 64K objects, at the expense of - compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or - progress reports. After compression, total_in holds the total size of - the uncompressed data and may be saved for use in the decompressor - (particularly if the decompressor wants to decompress everything in - a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ -#define Z_SYNC_FLUSH 2 -#define Z_FULL_FLUSH 3 -#define Z_FINISH 4 -#define Z_BLOCK 5 -/* Allowed flush values; see deflate() and inflate() below for details */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_NEED_DICT 2 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -#define Z_VERSION_ERROR (-6) -/* Return codes for the compression/decompression functions. Negative - * values are errors, positive values are used for special but normal events. - */ - -#define Z_NO_COMPRESSION 0 -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_RLE 3 -#define Z_DEFAULT_STRATEGY 0 -/* compression strategy; see deflateInit2() below for details */ - -#define Z_BINARY 0 -#define Z_ASCII 1 -#define Z_UNKNOWN 2 -/* Possible values of the data_type field (though see inflate()) */ - -#define Z_DEFLATED 8 -/* The deflate compression method (the only one supported in this version) */ - -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - -#define zlib_version zlibVersion() -/* for compatibility with versions < 1.0.2 */ - - /* basic functions */ - -ZEXTERN const char * ZEXPORT zlibVersion OF((void)); -/* The application can compare zlibVersion and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is - not compatible with the zlib.h header file used by the application. - This check is automatically made by deflateInit and inflateInit. - */ - -/* -ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); - - Initializes the internal stream state for compression. The fields - zalloc, zfree and opaque must be initialized before by the caller. - If zalloc and zfree are set to Z_NULL, deflateInit updates them to - use default allocation functions. - - The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: - 1 gives best speed, 9 gives best compression, 0 gives no compression at - all (the input data is simply copied a block at a time). - Z_DEFAULT_COMPRESSION requests a default compromise between speed and - compression (currently equivalent to level 6). - - deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if level is not a valid compression level, - Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible - with the version assumed by the caller (ZLIB_VERSION). - msg is set to null if there is no error message. deflateInit does not - perform any compression: this will be done by deflate(). -*/ - - -ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); -/* - deflate compresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce some - output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. deflate performs one or both of the - following actions: - - - Compress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in and avail_in are updated and - processing will resume at this point for the next call of deflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. This action is forced if the parameter flush is non zero. - Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary (in interactive applications). - Some output may be provided even if flush is not set. - - Before the call of deflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating avail_in or avail_out accordingly; avail_out - should never be zero before the call. The application can consume the - compressed output when it wants, for example when the output buffer is full - (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK - and with zero avail_out, it must be called again after making room in the - output buffer because there might be more output pending. - - If the parameter flush is set to Z_SYNC_FLUSH, all pending output is - flushed to the output buffer and the output is aligned on a byte boundary, so - that the decompressor can get all input data available so far. (In particular - avail_in is zero after the call if enough output space has been provided - before the call.) Flushing may degrade compression for some compression - algorithms and so it should be used only when necessary. - - If flush is set to Z_FULL_FLUSH, all output is flushed as with - Z_SYNC_FLUSH, and the compression state is reset so that decompression can - restart from this point if previous compressed data has been damaged or if - random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - the compression. - - If deflate returns with avail_out == 0, this function must be called again - with the same value of the flush parameter and more output space (updated - avail_out), until the flush is complete (deflate returns with non-zero - avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that - avail_out is greater than six to avoid repeated flush markers due to - avail_out == 0 on return. - - If the parameter flush is set to Z_FINISH, pending input is processed, - pending output is flushed and deflate returns with Z_STREAM_END if there - was enough output space; if deflate returns with Z_OK, this function must be - called again with Z_FINISH and more output space (updated avail_out) but no - more input data, until it returns with Z_STREAM_END or an error. After - deflate has returned Z_STREAM_END, the only possible operations on the - stream are deflateReset or deflateEnd. - - Z_FINISH can be used immediately after deflateInit if all the compression - is to be done in a single step. In this case, avail_out must be at least - the value returned by deflateBound (see below). If deflate does not return - Z_STREAM_END, then it must be called again as described above. - - deflate() sets strm->adler to the adler32 checksum of all input read - so far (that is, total_in bytes). - - deflate() may update data_type if it can make a good guess about - the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered - binary. This field is only for information purposes and does not affect - the compression algorithm in any manner. - - deflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if all input has been - consumed and all output has been produced (only when flush is set to - Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible - (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not - fatal, and deflate() can be called again with more input and more output - space to continue compressing. -*/ - - -ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the - stream state was inconsistent, Z_DATA_ERROR if the stream was freed - prematurely (some input or output was discarded). In the error case, - msg may be set but then points to a static string (which must not be - deallocated). -*/ - - -/* -ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); - - Initializes the internal stream state for decompression. The fields - next_in, avail_in, zalloc, zfree and opaque must be initialized before by - the caller. If next_in is not Z_NULL and avail_in is large enough (the exact - value depends on the compression method), inflateInit determines the - compression method from the zlib header and allocates all data structures - accordingly; otherwise the allocation will be deferred to the first call of - inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to - use default allocation functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller. msg is set to null if there is no error - message. inflateInit does not perform any decompression apart from reading - the zlib header if present: this will be done by inflate(). (So next_in and - avail_in may be modified, but next_out and avail_out are unchanged.) -*/ - - -ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); -/* - inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce - some output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. inflate performs one or both of the - following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing - will resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() provides as much output as possible, until there - is no more input data or no more space in the output buffer (see below - about the flush parameter). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating the next_* and avail_* values accordingly. - The application can consume the uncompressed output when it wants, for - example when the output buffer is full (avail_out == 0), or after each - call of inflate(). If inflate returns Z_OK and with zero avail_out, it - must be called again after making room in the output buffer because there - might be more output pending. - - The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, - Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much - output as possible to the output buffer. Z_BLOCK requests that inflate() stop - if and when it get to the next deflate block boundary. When decoding the zlib - or gzip format, this will cause inflate() to return immediately after the - header and before the first block. When doing a raw inflate, inflate() will - go ahead and process the first block, and will return when it gets to the end - of that block, or when it runs out of data. - - The Z_BLOCK option assists in appending to or combining deflate streams. - Also to assist in this, on return inflate() will set strm->data_type to the - number of unused bits in the last byte taken from strm->next_in, plus 64 - if inflate() is currently decoding the last block in the deflate stream, - plus 128 if inflate() returned immediately after decoding an end-of-block - code or decoding the complete header up to just before the first byte of the - deflate stream. The end-of-block will not be indicated until all of the - uncompressed data from that block has been written to strm->next_out. The - number of unused bits may in general be greater than seven, except when - bit 7 of data_type is set, in which case the number of unused bits will be - less than eight. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step - (a single call of inflate), the parameter flush should be set to - Z_FINISH. In this case all pending input is processed and all pending - output is flushed; avail_out must be large enough to hold all the - uncompressed data. (The size of the uncompressed data may have been saved - by the compressor for this purpose.) The next operation on this stream must - be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster approach - may be used for the single inflate() call. - - In this implementation, inflate() always flushes as much output as - possible to the output buffer, and always uses the faster approach on the - first call. So the only effect of the flush parameter in this implementation - is on the return value of inflate(), as noted below, or when it returns early - because Z_BLOCK is used. - - If a preset dictionary is needed after this call (see inflateSetDictionary - below), inflate sets strm-adler to the adler32 checksum of the dictionary - chosen by the compressor and returns Z_NEED_DICT; otherwise it sets - strm->adler to the adler32 checksum of all output produced so far (that is, - total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described - below. At the end of the stream, inflate() checks that its computed adler32 - checksum is equal to that saved by the compressor and returns Z_STREAM_END - only if the checksum is correct. - - inflate() will decompress and check either zlib-wrapped or gzip-wrapped - deflate data. The header type is detected automatically. Any information - contained in the gzip header is not retained, so applications that need that - information should instead use raw inflate, see inflateInit2() below, or - inflateBack() and perform their own processing of the gzip header and - trailer. - - inflate() returns Z_OK if some progress has been made (more input processed - or more output produced), Z_STREAM_END if the end of the compressed data has - been reached and all uncompressed output has been produced, Z_NEED_DICT if a - preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect check - value), Z_STREAM_ERROR if the stream structure was inconsistent (for example - if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, - Z_BUF_ERROR if no progress is possible or if there was not enough room in the - output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and - inflate() can be called again with more input and more output space to - continue decompressing. If Z_DATA_ERROR is returned, the application may then - call inflateSync() to look for a good compression block if a partial recovery - of the data is desired. -*/ - - -ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). -*/ - - /* Advanced functions */ - -/* - The following functions are needed only in some special applications. -*/ - -/* -ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); - - This is another version of deflateInit with more compression options. The - fields next_in, zalloc, zfree and opaque must be initialized before by - the caller. - - The method parameter is the compression method. It must be Z_DEFLATED in - this version of the library. - - The windowBits parameter is the base two logarithm of the window size - (the size of the history buffer). It should be in the range 8..15 for this - version of the library. Larger values of this parameter result in better - compression at the expense of memory usage. The default value is 15 if - deflateInit is used instead. - - windowBits can also be -8..-15 for raw deflate. In this case, -windowBits - determines the window size. deflate() will then generate raw deflate data - with no zlib header or trailer, and will not compute an adler32 check value. - - windowBits can also be greater than 15 for optional gzip encoding. Add - 16 to windowBits to write a simple gzip header and trailer around the - compressed data instead of a zlib wrapper. The gzip header will have no - file name, no extra data, no comment, no modification time (set to zero), - no header crc, and the operating system will be set to 255 (unknown). - - The memLevel parameter specifies how much memory should be allocated - for the internal compression state. memLevel=1 uses minimum memory but - is slow and reduces compression ratio; memLevel=9 uses maximum memory - for optimal speed. The default value is 8. See zconf.h for total memory - usage as a function of windowBits and memLevel. - - The strategy parameter is used to tune the compression algorithm. Use the - value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match), or Z_RLE to limit match distances to one (run-length - encoding). Filtered data consists mostly of small values with a somewhat - random distribution. In this case, the compression algorithm is tuned to - compress them better. The effect of Z_FILTERED is to force more Huffman - coding and less string matching; it is somewhat intermediate between - Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as - Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy - parameter only affects the compression ratio but not the correctness of the - compressed output even if it is not set appropriately. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid - method). msg is set to null if there is no error message. deflateInit2 does - not perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the compression dictionary from the given byte sequence - without producing any compressed output. This function must be called - immediately after deflateInit, deflateInit2 or deflateReset, before any - call of deflate. The compressor and decompressor must use exactly the same - dictionary (see inflateSetDictionary). - - The dictionary should consist of strings (byte sequences) that are likely - to be encountered later in the data to be compressed, with the most commonly - used strings preferably put towards the end of the dictionary. Using a - dictionary is most useful when the data to be compressed is short and can be - predicted with good accuracy; the data can then be compressed better than - with the default empty dictionary. - - Depending on the size of the compression data structures selected by - deflateInit or deflateInit2, a part of the dictionary may in effect be - discarded, for example if the dictionary is larger than the window size in - deflate or deflate2. Thus the strings most likely to be useful should be - put at the end of the dictionary, not at the front. - - Upon return of this function, strm->adler is set to the adler32 value - of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The adler32 value - applies to the whole dictionary even if only a subset of the dictionary is - actually used by the compressor.) If a raw deflate was requested, then the - adler32 value is not computed and strm->adler is not set. - - deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent (for example if deflate has already been called for this stream - or if the compression method is bsort). deflateSetDictionary does not - perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when several compression strategies will be - tried, for example when there are several ways of pre-processing the input - data with a filter. The streams that will be discarded should then be freed - by calling deflateEnd. Note that deflateCopy duplicates the internal - compression state which can be quite large, so this strategy is slow and - can consume lots of memory. - - deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); -/* - This function is equivalent to deflateEnd followed by deflateInit, - but does not free and reallocate all the internal compression state. - The stream will keep the same compression level and any other attributes - that may have been set by deflateInit2. - - deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, - int level, - int strategy)); -/* - Dynamically update the compression level and compression strategy. The - interpretation of level and strategy is as in deflateInit2. This can be - used to switch between compression and straight copy of the input data, or - to switch to a different kind of input data requiring a different - strategy. If the compression level is changed, the input available so far - is compressed with the old level (and may be flushed); the new level will - take effect only at the next call of deflate(). - - Before the call of deflateParams, the stream state must be set as for - a call of deflate(), since the currently available input may have to - be compressed and flushed. In particular, strm->avail_out must be non-zero. - - deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source - stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR - if strm->avail_out was zero. -*/ - -ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, - uLong sourceLen)); -/* - deflateBound() returns an upper bound on the compressed size after - deflation of sourceLen bytes. It must be called after deflateInit() - or deflateInit2(). This would be used to allocate an output buffer - for deflation in a single pass, and so would be called before deflate(). -*/ - -ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - deflatePrime() inserts bits in the deflate output stream. The intent - is that this function is used to start off the deflate output with the - bits leftover from a previous deflate stream when appending to it. As such, - this function can only be used for raw deflate, and must be used before the - first deflate() call after a deflateInit2() or deflateReset(). bits must be - less than or equal to 16, and that many of the least significant bits of - value will be inserted in the output. - - deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, - int windowBits)); - - This is another version of inflateInit with an extra parameter. The - fields next_in, avail_in, zalloc, zfree and opaque must be initialized - before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library. The default value is 15 if inflateInit is used - instead. windowBits must be greater than or equal to the windowBits value - provided to deflateInit2() while compressing, or it must be equal to 15 if - deflateInit2() was not used. If a compressed stream with a larger window - size is given as input, inflate() will return with the error code - Z_DATA_ERROR instead of trying to allocate a larger window. - - windowBits can also be -8..-15 for raw inflate. In this case, -windowBits - determines the window size. inflate() will then process raw deflate data, - not looking for a zlib or gzip header, not generating a check value, and not - looking for any check values for comparison at the end of the stream. This - is for use with other formats that use the deflate compressed data format - such as zip. Those formats provide their own check values. If a custom - format is developed using the raw deflate format for compressed data, it is - recommended that a check value such as an adler32 or a crc32 be applied to - the uncompressed data as is done in the zlib, gzip, and zip formats. For - most applications, the zlib format should be used as is. Note that comments - above on the use in deflateInit2() applies to the magnitude of windowBits. - - windowBits can also be greater than 15 for optional gzip decoding. Add - 32 to windowBits to enable zlib and gzip decoding with automatic header - detection, or add 16 to decode only the gzip format (the zlib format will - return a Z_DATA_ERROR). - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative - memLevel). msg is set to null if there is no error message. inflateInit2 - does not perform any decompression apart from reading the zlib header if - present: this will be done by inflate(). (So next_in and avail_in may be - modified, but next_out and avail_out are unchanged.) -*/ - -ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate - if this call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the adler32 value returned by this call of - inflate. The compressor and decompressor must use exactly the same - dictionary (see deflateSetDictionary). - - inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect adler32 value). inflateSetDictionary does not - perform any decompression: this will be done by subsequent calls of - inflate(). -*/ - -ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); -/* - Skips invalid compressed data until a full flush point (see above the - description of deflate with Z_FULL_FLUSH) can be found, or until all - available input is skipped. No output is provided. - - inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR - if no more input was provided, Z_DATA_ERROR if no flush point has been found, - or Z_STREAM_ERROR if the stream structure was inconsistent. In the success - case, the application may save the current current value of total_in which - indicates where valid compressed data was found. In the error case, the - application may repeatedly call inflateSync, providing more input each time, - until success or end of the input data. -*/ - -ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when randomly accessing a large stream. The - first pass through the stream can periodically record the inflate state, - allowing restarting inflate at those points when randomly accessing the - stream. - - inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); -/* - This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate all the internal decompression state. - The stream will keep attributes that may have been set by inflateInit2. - - inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -/* -ZEXTERN int ZEXPORT inflateBackInit OF((z_stream FAR *strm, int windowBits, - unsigned char FAR *window)); - - Initialize the internal stream state for decompression using inflateBack() - calls. The fields zalloc, zfree and opaque in strm must be initialized - before the call. If zalloc and zfree are Z_NULL, then the default library- - derived memory allocation routines are used. windowBits is the base two - logarithm of the window size, in the range 8..15. window is a caller - supplied buffer of that size. Except for special applications where it is - assured that deflate was used with small window sizes, windowBits must be 15 - and a 32K byte window must be supplied to be able to decompress general - deflate streams. - - See inflateBack() for the usage of these routines. - - inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of - the paramaters are invalid, Z_MEM_ERROR if the internal state could not - be allocated, or Z_VERSION_ERROR if the version of the library does not - match the version of the header file. -*/ - -typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); -typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); - -ZEXTERN int ZEXPORT inflateBack OF((z_stream FAR *strm, - in_func in, void FAR *in_desc, - out_func out, void FAR *out_desc)); -/* - inflateBack() does a raw inflate with a single call using a call-back - interface for input and output. This is more efficient than inflate() for - file i/o applications in that it avoids copying between the output and the - sliding window by simply making the window itself the output buffer. This - function trusts the application to not change the output buffer passed by - the output function, at least until inflateBack() returns. - - inflateBackInit() must be called first to allocate the internal state - and to initialize the state with the user-provided window buffer. - inflateBack() may then be used multiple times to inflate a complete, raw - deflate stream with each call. inflateBackEnd() is then called to free - the allocated state. - - A raw deflate stream is one with no zlib or gzip header or trailer. - This routine would normally be used in a utility that reads zip or gzip - files and writes out uncompressed files. The utility would decode the - header and process the trailer on its own, hence this routine expects - only the raw deflate stream to decompress. This is different from the - normal behavior of inflate(), which expects either a zlib or gzip header and - trailer around the deflate stream. - - inflateBack() uses two subroutines supplied by the caller that are then - called by inflateBack() for input and output. inflateBack() calls those - routines until it reads a complete deflate stream and writes out all of the - uncompressed data, or until it encounters an error. The function's - parameters and return types are defined above in the in_func and out_func - typedefs. inflateBack() will call in(in_desc, &buf) which should return the - number of bytes of provided input, and a pointer to that input in buf. If - there is no input available, in() must return zero--buf is ignored in that - case--and inflateBack() will return a buffer error. inflateBack() will call - out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() - should return zero on success, or non-zero on failure. If out() returns - non-zero, inflateBack() will return with an error. Neither in() nor out() - are permitted to change the contents of the window provided to - inflateBackInit(), which is also the buffer that out() uses to write from. - The length written by out() will be at most the window size. Any non-zero - amount of input may be provided by in(). - - For convenience, inflateBack() can be provided input on the first call by - setting strm->next_in and strm->avail_in. If that input is exhausted, then - in() will be called. Therefore strm->next_in must be initialized before - calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called - immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in - must also be initialized, and then if strm->avail_in is not zero, input will - initially be taken from strm->next_in[0 .. strm->avail_in - 1]. - - The in_desc and out_desc parameters of inflateBack() is passed as the - first parameter of in() and out() respectively when they are called. These - descriptors can be optionally used to pass any information that the caller- - supplied in() and out() functions need to do their job. - - On return, inflateBack() will set strm->next_in and strm->avail_in to - pass back any unused input that was provided by the last in() call. The - return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR - if in() or out() returned an error, Z_DATA_ERROR if there was a format - error in the deflate stream (in which case strm->msg is set to indicate the - nature of the error), or Z_STREAM_ERROR if the stream was not properly - initialized. In the case of Z_BUF_ERROR, an input or output error can be - distinguished using strm->next_in which will be Z_NULL only if in() returned - an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to - out() returning non-zero. (in() will always be called before out(), so - strm->next_in is assured to be defined if out() returns non-zero.) Note - that inflateBack() cannot return Z_OK. -*/ - -ZEXTERN int ZEXPORT inflateBackEnd OF((z_stream FAR *strm)); -/* - All memory allocated by inflateBackInit() is freed. - - inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream - state was inconsistent. -*/ - -ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); -/* Return flags indicating compile-time options. - - Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: - 1.0: size of uInt - 3.2: size of uLong - 5.4: size of voidpf (pointer) - 7.6: size of z_off_t - - Compiler, assembler, and debug options: - 8: DEBUG - 9: ASMV or ASMINF -- use ASM code - 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention - 11: 0 (reserved) - - One-time table building (smaller code, but not thread-safe if true): - 12: BUILDFIXED -- build static block decoding tables when needed - 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed - 14,15: 0 (reserved) - - Library content (indicates missing functionality): - 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking - deflate code when not needed) - 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect - and decode gzip streams (to avoid linking crc code) - 18-19: 0 (reserved) - - Operation variations (changes in library functionality): - 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate - 21: FASTEST -- deflate algorithm with only one, lowest compression level - 22,23: 0 (reserved) - - The sprintf variant used by gzprintf (zero is best): - 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format - 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! - 26: 0 = returns value, 1 = void -- 1 means inferred string length returned - - Remainder: - 27-31: 0 (reserved) - */ - - - /* utility functions */ - -/* - The following utility functions are implemented on top of the - basic stream-oriented functions. To simplify the interface, some - default options are assumed (compression level and memory usage, - standard memory allocation functions). The source code of these - utility functions can easily be modified if you need special options. -*/ - -ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Compresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be at least the value returned - by compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - This function can be used to compress a whole file at once if the - input file is mmap'ed. - compress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer. -*/ - -ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen, - int level)); -/* - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least the value returned by - compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ - -ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); -/* - compressBound() returns an upper bound on the compressed size after - compress() or compress2() on sourceLen bytes. It would be used before - a compress() or compress2() call to allocate the destination buffer. -*/ - -ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. -*/ - - -typedef voidp gzFile; - -ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); -/* - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb") but can also include a compression level - ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for - Huffman only compression as in "wb1h", or 'R' for run-length encoding - as in "wb1R". (See the description of deflateInit2 for more information - about the strategy parameter.) - - gzopen can be used to read a file which is not in gzip format; in this - case gzread will directly read from the file without decompression. - - gzopen returns NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). */ - -ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); -/* - gzdopen() associates a gzFile with the file descriptor fd. File - descriptors are obtained from calls like open, dup, creat, pipe or - fileno (in the file has been previously opened with fopen). - The mode parameter is as in gzopen. - The next call of gzclose on the returned gzFile will also close the - file descriptor fd, just like fclose(fdopen(fd), mode) closes the file - descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). - gzdopen returns NULL if there was insufficient memory to allocate - the (de)compression state. -*/ - -ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); -/* - Dynamically update the compression level or strategy. See the description - of deflateInit2 for the meaning of these parameters. - gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not - opened for writing. -*/ - -ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); -/* - Reads the given number of uncompressed bytes from the compressed file. - If the input file was not in gzip format, gzread copies the given number - of bytes into the buffer. - gzread returns the number of uncompressed bytes actually read (0 for - end of file, -1 for error). */ - -ZEXTERN int ZEXPORT gzwrite OF((gzFile file, - voidpc buf, unsigned len)); -/* - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of uncompressed bytes actually written - (0 in case of error). -*/ - -ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); -/* - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). The number of - uncompressed bytes written is limited to 4095. The caller should assure that - this limit is not exceeded. If it is exceeded, then gzprintf() will return - return an error (0) with nothing written. In this case, there may also be a - buffer overflow with unpredictable consequences, which is possible only if - zlib was compiled with the insecure functions sprintf() or vsprintf() - because the secure snprintf() or vsnprintf() functions were not available. -*/ - -ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); -/* - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. -*/ - -ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); -/* - Reads bytes from the compressed file until len-1 characters are read, or - a newline character is read and transferred to buf, or an end-of-file - condition is encountered. The string is then terminated with a null - character. - gzgets returns buf, or Z_NULL in case of error. -*/ - -ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); -/* - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. -*/ - -ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); -/* - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. -*/ - -ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); -/* - Push one character back onto the stream to be read again later. - Only one character of push-back is allowed. gzungetc() returns the - character pushed, or -1 on failure. gzungetc() will fail if a - character has been pushed but not read yet, or if c is -1. The pushed - character will be discarded if the stream is repositioned with gzseek() - or gzrewind(). -*/ - -ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); -/* - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. The return value is the zlib - error number (see function gzerror below). gzflush returns Z_OK if - the flush parameter is Z_FINISH and all output could be flushed. - gzflush should be called only when strictly necessary because it can - degrade compression. -*/ - -ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, - z_off_t offset, int whence)); -/* - Sets the starting position for the next gzread or gzwrite on the - given compressed file. The offset represents a number of bytes in the - uncompressed data stream. The whence parameter is defined as in lseek(2); - the value SEEK_END is not supported. - If the file is opened for reading, this function is emulated but can be - extremely slow. If the file is opened for writing, only forward seeks are - supported; gzseek then compresses a sequence of zeroes up to the new - starting position. - - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error, in - particular if the file is opened for writing and the new starting position - would be before the current position. -*/ - -ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); -/* - Rewinds the given file. This function is supported only for reading. - - gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) -*/ - -ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); -/* - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. - - gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) -*/ - -ZEXTERN int ZEXPORT gzeof OF((gzFile file)); -/* - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. -*/ - -ZEXTERN int ZEXPORT gzclose OF((gzFile file)); -/* - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. The return value is the zlib - error number (see function gzerror below). -*/ - -ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); -/* - Returns the error message for the last error which occurred on the - given compressed file. errnum is set to zlib error number. If an - error occurred in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. -*/ - -ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); -/* - Clears the error and end-of-file flags for file. This is analogous to the - clearerr() function in stdio. This is useful for continuing to read a gzip - file that is being written concurrently. -*/ - - /* checksum functions */ - -/* - These functions are not related to compression but are exported - anyway because they might be useful in applications using the - compression library. -*/ - -ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); - -/* - Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. If buf is NULL, this function returns - the required initial value for the checksum. - An Adler-32 checksum is almost as reliable as a CRC32 but can be computed - much faster. Usage example: - - uLong adler = adler32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - adler = adler32(adler, buffer, length); - } - if (adler != original_adler) error(); -*/ - -ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); -/* - Update a running crc with the bytes buf[0..len-1] and return the updated - crc. If buf is NULL, this function returns the required initial value - for the crc. Pre- and post-conditioning (one's complement) is performed - within this function so it shouldn't be done by the application. - Usage example: - - uLong crc = crc32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - crc = crc32(crc, buffer, length); - } - if (crc != original_crc) error(); -*/ - - - /* various hacks, don't look :) */ - -/* deflateInit and inflateInit are macros to allow checking the zlib version - * and the compiler's view of z_stream: - */ -ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy, const char *version, - int stream_size)); -ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateBackInit_ OF((z_stream FAR *strm, int windowBits, - unsigned char FAR *window, - const char *version, - int stream_size)); -#define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) -#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) -#define inflateBackInit(strm, windowBits, window) \ - inflateBackInit_((strm), (windowBits), (window), \ - ZLIB_VERSION, sizeof(z_stream)) - - -#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) - struct internal_state {int dummy;}; /* hack for buggy compilers */ -#endif - -ZEXTERN const char * ZEXPORT zError OF((int err)); -ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); -ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); - -#ifdef __cplusplus -} -#endif - -#endif /* ZLIB_H */ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.1, November 17th, 2003 + + Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.1" +#define ZLIB_VERNUM 0x1210 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by the in-memory functions is the zlib + format, which is a zlib wrapper documented in RFC 1950, wrapped around a + deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + This library does not provide any functions to write gzip files in memory. + However such functions could be easily written using zlib's deflate function, + the documentation in the gzip RFC, and the examples in gzio.c. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it get to the next deflate block boundary. When decoding the zlib + or gzip format, this will cause inflate() to return immediately after the + header and before the first block. When doing a raw inflate, inflate() will + go ahead and process the first block, and will return when it gets to the end + of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_stream FAR *strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_stream FAR *strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int err)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/plugins/CDVDisoEFP/src/zlib/zutil.c b/plugins/CDVDisoEFP/src/zlib/zutil.c index db137f8a48..646f572d59 100644 --- a/plugins/CDVDisoEFP/src/zlib/zutil.c +++ b/plugins/CDVDisoEFP/src/zlib/zutil.c @@ -1,319 +1,319 @@ -/* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id: zutil.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ - -#include "zutil.h" - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -#ifndef STDC -extern void exit OF((int)); -#endif - -const char * const z_errmsg[10] = { -"need dictionary", /* Z_NEED_DICT 2 */ -"stream end", /* Z_STREAM_END 1 */ -"", /* Z_OK 0 */ -"file error", /* Z_ERRNO (-1) */ -"stream error", /* Z_STREAM_ERROR (-2) */ -"data error", /* Z_DATA_ERROR (-3) */ -"insufficient memory", /* Z_MEM_ERROR (-4) */ -"buffer error", /* Z_BUF_ERROR (-5) */ -"incompatible version",/* Z_VERSION_ERROR (-6) */ -""}; - - -const char * ZEXPORT zlibVersion() -{ - return ZLIB_VERSION; -} - -uLong ZEXPORT zlibCompileFlags() -{ - uLong flags; - - flags = 0; - switch (sizeof(uInt)) { - case 2: break; - case 4: flags += 1; break; - case 8: flags += 2; break; - default: flags += 3; - } - switch (sizeof(uLong)) { - case 2: break; - case 4: flags += 1 << 2; break; - case 8: flags += 2 << 2; break; - default: flags += 3 << 2; - } - switch (sizeof(voidpf)) { - case 2: break; - case 4: flags += 1 << 4; break; - case 8: flags += 2 << 4; break; - default: flags += 3 << 4; - } - switch (sizeof(z_off_t)) { - case 2: break; - case 4: flags += 1 << 6; break; - case 8: flags += 2 << 6; break; - default: flags += 3 << 6; - } -#ifdef DEBUG - flags += 1 << 8; -#endif -#if defined(ASMV) || defined(ASMINF) - flags += 1 << 9; -#endif -#ifdef ZLIB_WINAPI - flags += 1 << 10; -#endif -#ifdef BUILDFIXED - flags += 1 << 12; -#endif -#ifdef DYNAMIC_CRC_TABLE - flags += 1 << 13; -#endif -#ifdef NO_GZCOMPRESS - flags += 1 << 16; -#endif -#ifdef NO_GZIP - flags += 1 << 17; -#endif -#ifdef PKZIP_BUG_WORKAROUND - flags += 1 << 20; -#endif -#ifdef FASTEST - flags += 1 << 21; -#endif -#ifdef STDC -# ifdef NO_vsnprintf - flags += 1 << 25; -# ifdef HAS_vsprintf_void - flags += 1 << 26; -# endif -# else -# ifdef HAS_vsnprintf_void - flags += 1 << 26; -# endif -# endif -#else - flags += 1 << 24; -# ifdef NO_snprintf - flags += 1 << 25; -# ifdef HAS_sprintf_void - flags += 1 << 26; -# endif -# else -# ifdef HAS_snprintf_void - flags += 1 << 26; -# endif -# endif -#endif - return flags; -} - -#ifdef DEBUG - -# ifndef verbose -# define verbose 0 -# endif -int z_verbose = verbose; - -void z_error (m) - char *m; -{ - fprintf(stderr, "%s\n", m); - exit(1); -} -#endif - -/* exported to allow conversion of error code to string for compress() and - * uncompress() - */ -const char * ZEXPORT zError(err) - int err; -{ - return ERR_MSG(err); -} - -#if defined(_WIN32_WCE) - /* does not exist on WCE */ - int errno = 0; -#endif - -#ifndef HAVE_MEMCPY - -void zmemcpy(dest, source, len) - Bytef* dest; - const Bytef* source; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = *source++; /* ??? to be unrolled */ - } while (--len != 0); -} - -int zmemcmp(s1, s2, len) - const Bytef* s1; - const Bytef* s2; - uInt len; -{ - uInt j; - - for (j = 0; j < len; j++) { - if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; - } - return 0; -} - -void zmemzero(dest, len) - Bytef* dest; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = 0; /* ??? to be unrolled */ - } while (--len != 0); -} -#endif - - -#ifdef SYS16BIT - -#ifdef __TURBOC__ -/* Turbo C in 16-bit mode */ - -# define MY_ZCALLOC - -/* Turbo C malloc() does not allow dynamic allocation of 64K bytes - * and farmalloc(64K) returns a pointer with an offset of 8, so we - * must fix the pointer. Warning: the pointer must be put back to its - * original form in order to free it, use zcfree(). - */ - -#define MAX_PTR 10 -/* 10*64K = 640K */ - -local int next_ptr = 0; - -typedef struct ptr_table_s { - voidpf org_ptr; - voidpf new_ptr; -} ptr_table; - -local ptr_table table[MAX_PTR]; -/* This table is used to remember the original form of pointers - * to large buffers (64K). Such pointers are normalized with a zero offset. - * Since MSDOS is not a preemptive multitasking OS, this table is not - * protected from concurrent access. This hack doesn't work anyway on - * a protected system like OS/2. Use Microsoft C instead. - */ - -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - voidpf buf = opaque; /* just to make some compilers happy */ - ulg bsize = (ulg)items*size; - - /* If we allocate less than 65520 bytes, we assume that farmalloc - * will return a usable pointer which doesn't have to be normalized. - */ - if (bsize < 65520L) { - buf = farmalloc(bsize); - if (*(ush*)&buf != 0) return buf; - } else { - buf = farmalloc(bsize + 16L); - } - if (buf == NULL || next_ptr >= MAX_PTR) return NULL; - table[next_ptr].org_ptr = buf; - - /* Normalize the pointer to seg:0 */ - *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; - *(ush*)&buf = 0; - table[next_ptr++].new_ptr = buf; - return buf; -} - -void zcfree (voidpf opaque, voidpf ptr) -{ - int n; - if (*(ush*)&ptr != 0) { /* object < 64K */ - farfree(ptr); - return; - } - /* Find the original pointer */ - for (n = 0; n < next_ptr; n++) { - if (ptr != table[n].new_ptr) continue; - - farfree(table[n].org_ptr); - while (++n < next_ptr) { - table[n-1] = table[n]; - } - next_ptr--; - return; - } - ptr = opaque; /* just to make some compilers happy */ - Assert(0, "zcfree: ptr not found"); -} - -#endif /* __TURBOC__ */ - - -#ifdef M_I86 -/* Microsoft C in 16-bit mode */ - -# define MY_ZCALLOC - -#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) -# define _halloc halloc -# define _hfree hfree -#endif - -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - if (opaque) opaque = 0; /* to make compiler happy */ - return _halloc((long)items, size); -} - -void zcfree (voidpf opaque, voidpf ptr) -{ - if (opaque) opaque = 0; /* to make compiler happy */ - _hfree(ptr); -} - -#endif /* M_I86 */ - -#endif /* SYS16BIT */ - - -#ifndef MY_ZCALLOC /* Any system without a special alloc function */ - -#ifndef STDC -extern voidp malloc OF((uInt size)); -extern voidp calloc OF((uInt items, uInt size)); -extern void free OF((voidpf ptr)); -#endif - -voidpf zcalloc (opaque, items, size) - voidpf opaque; - unsigned items; - unsigned size; -{ - if (opaque) items += size - size; /* make compiler happy */ - return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : - (voidpf)calloc(items, size); -} - -void zcfree (opaque, ptr) - voidpf opaque; - voidpf ptr; -{ - free(ptr); - if (opaque) return; /* make compiler happy */ -} - -#endif /* MY_ZCALLOC */ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zutil.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef STDC +extern void exit OF((int)); +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1 << 16; +#endif +#ifdef NO_GZIP + flags += 1 << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1 << 20; +#endif +#ifdef FASTEST + flags += 1 << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1 << 25; +# ifdef HAS_vsprintf_void + flags += 1 << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1 << 26; +# endif +# endif +#else + flags += 1 << 24; +# ifdef NO_snprintf + flags += 1 << 25; +# ifdef HAS_sprintf_void + flags += 1 << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1 << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* does not exist on WCE */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/plugins/CDVDisoEFP/src/zlib/zutil.h b/plugins/CDVDisoEFP/src/zlib/zutil.h index e300f7c767..d0f21d6d86 100644 --- a/plugins/CDVDisoEFP/src/zlib/zutil.h +++ b/plugins/CDVDisoEFP/src/zlib/zutil.h @@ -1,258 +1,258 @@ -/* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id: zutil.h,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ - -#ifndef ZUTIL_H -#define ZUTIL_H - -#define ZLIB_INTERNAL -#include "zlib.h" - -#ifdef STDC -# include -# include -# include -#endif -#ifdef NO_ERRNO_H - extern int errno; -#else -# include -#endif - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -typedef unsigned char uch; -typedef uch FAR uchf; -typedef unsigned short ush; -typedef ush FAR ushf; -typedef unsigned long ulg; - -extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ -/* (size given to avoid silly warnings with Visual C++) */ - -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] - -#define ERR_RETURN(strm,err) \ - return (strm->msg = (char*)ERR_MSG(err), (err)) -/* To be used only when the state is known to be valid */ - - /* common constants */ - -#ifndef DEF_WBITS -# define DEF_WBITS MAX_WBITS -#endif -/* default windowBits for decompression. MAX_WBITS is for compression only */ - -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -/* default memLevel */ - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - -#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ - - /* target dependencies */ - -#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) -# define OS_CODE 0x00 -# if defined(__TURBOC__) || defined(__BORLANDC__) -# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) - /* Allow compilation with ANSI keywords only enabled */ - void _Cdecl farfree( void *block ); - void *_Cdecl farmalloc( unsigned long nbytes ); -# else -# include -# endif -# else /* MSC or DJGPP */ -# include -# endif -#endif - -#ifdef AMIGA -# define OS_CODE 0x01 -#endif - -#if defined(VAXC) || defined(VMS) -# define OS_CODE 0x02 -# define F_OPEN(name, mode) \ - fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") -#endif - -#if defined(ATARI) || defined(atarist) -# define OS_CODE 0x05 -#endif - -#ifdef OS2 -# define OS_CODE 0x06 -#endif - -#if defined(MACOS) || defined(TARGET_OS_MAC) -# define OS_CODE 0x07 -# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os -# include /* for fdopen */ -# else -# ifndef fdopen -# define fdopen(fd,mode) NULL /* No fdopen() */ -# endif -# endif -#endif - -#ifdef TOPS20 -# define OS_CODE 0x0a -#endif - -#ifdef WIN32 -# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ -# define OS_CODE 0x0b -# endif -#endif - -#ifdef __50SERIES /* Prime/PRIMOS */ -# define OS_CODE 0x0f -#endif - -#if defined(_BEOS_) || defined(RISCOS) -# define fdopen(fd,mode) NULL /* No fdopen() */ -#endif - -#if (defined(_MSC_VER) && (_MSC_VER > 600)) -# if defined(_WIN32_WCE) -# define fdopen(fd,mode) NULL /* No fdopen() */ -# ifndef _PTRDIFF_T_DEFINED - typedef int ptrdiff_t; -# define _PTRDIFF_T_DEFINED -# endif -# else -# define fdopen(fd,type) _fdopen(fd,type) -# endif -#endif - - /* common defaults */ - -#ifndef OS_CODE -# define OS_CODE 0x03 /* assume Unix */ -#endif - -#ifndef F_OPEN -# define F_OPEN(name, mode) fopen((name), (mode)) -#endif - - /* functions */ - -#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif -#if defined(__CYGWIN__) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif -#ifndef HAVE_VSNPRINTF -# ifdef MSDOS - /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), - but for now we just assume it doesn't. */ -# define NO_vsnprintf -# endif -# ifdef __TURBOC__ -# define NO_vsnprintf -# endif -# ifdef WIN32 - /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ -# if !defined(vsnprintf) && !defined(NO_vsnprintf) -# define vsnprintf _vsnprintf -# endif -# endif -# ifdef __SASC -# define NO_vsnprintf -# endif -#endif - -#ifdef HAVE_STRERROR - extern char *strerror OF((int)); -# define zstrerror(errnum) strerror(errnum) -#else -# define zstrerror(errnum) "" -#endif - -#if defined(pyr) -# define NO_MEMCPY -#endif -#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) - /* Use our own functions for small and medium model with MSC <= 5.0. - * You may have to use the same strategy for Borland C (untested). - * The __SC__ check is for Symantec. - */ -# define NO_MEMCPY -#endif -#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) -# define HAVE_MEMCPY -#endif -#ifdef HAVE_MEMCPY -# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ -# define zmemcpy _fmemcpy -# define zmemcmp _fmemcmp -# define zmemzero(dest, len) _fmemset(dest, 0, len) -# else -# define zmemcpy memcpy -# define zmemcmp memcmp -# define zmemzero(dest, len) memset(dest, 0, len) -# endif -#else - extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); - extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); - extern void zmemzero OF((Bytef* dest, uInt len)); -#endif - -/* Diagnostic functions */ -#ifdef DEBUG -# include - extern int z_verbose; - extern void z_error OF((char *m)); -# define Assert(cond,msg) {if(!(cond)) z_error(msg);} -# define Trace(x) {if (z_verbose>=0) fprintf x ;} -# define Tracev(x) {if (z_verbose>0) fprintf x ;} -# define Tracevv(x) {if (z_verbose>1) fprintf x ;} -# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} -# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - - -voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); -void zcfree OF((voidpf opaque, voidpf ptr)); - -#define ZALLOC(strm, items, size) \ - (*((strm)->zalloc))((strm)->opaque, (items), (size)) -#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) -#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} - -#endif /* ZUTIL_H */ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: zutil.h,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/plugins/CDVDlinuz/Src/Linux/CD.c b/plugins/CDVDlinuz/Src/Linux/CD.c index ab5796c8c3..c9918f29af 100644 --- a/plugins/CDVDlinuz/Src/Linux/CD.c +++ b/plugins/CDVDlinuz/Src/Linux/CD.c @@ -1,367 +1,734 @@ -/* CD.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - -#include // errno -#include // NULL -#include // strerror() -#include // open() -#include // ioctl() -#include // open() -#include // lseek(), open() -#include // close(), lseek(), (sleep()) - -#include // CD/DVD based ioctl() and defines. - -#include "../convert.h" -#include "logfile.h" -#include "device.h" -#include "CD.h" - - -// Constants -u8 *playstationcdname = "PLAYSTATION\0"; -u8 *ps1name = "CD-XA001\0"; - -// CD-ROM temp storage structures (see linux/cdrom.h for details) -struct cdrom_tochdr cdheader; -struct cdrom_tocentry cdtrack; -struct cdrom_subchnl subchannel; -u8 cdtempbuffer[2352]; - -int cdmode; // mode of last CDVDreadTrack call (important for CDs) - - -// Internal Functions - -void InitCDSectorInfo() { - cdmode = -1; -} // END InitSectorInfo(); - - -// Function Calls from CDVD.c - -void InitCDInfo() { - InitCDSectorInfo(); -} // END InitDiscType() - -s32 CDreadTrack(u32 lsn, int mode, u8 *buffer) { - s32 s32result; - -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: CDreadTrack(%i)", lsn); -#endif /* VERBOSE_FUNCTION */ - - s32result = 0; - - if(buffer == NULL) return(-1); - - // The CD way of figuring out where to read. - LBAtoMSF(lsn, buffer); - - switch(mode) { - case CDVD_MODE_2048: - case CDVD_MODE_2328: - case CDVD_MODE_2340: - case CDVD_MODE_2352: - errno = 4; // Interrupted system call... (simulated the first time) - while(errno == 4) { - errno = 0; - s32result = ioctl(devicehandle, CDROMREADRAW, buffer); - } // ENDWHILE- Continually being interrupted by the system... - break; - case CDVD_MODE_2368: // Unimplemented... as yet. - default: -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Unknown Mode %i", mode); -#endif /* VERBOSE_WARNINGS */ - return(-1); // Illegal Read Mode? Abort - break; - } // ENDSWITCH- Which read mode should we choose? - if((s32result == -1) || (errno != 0)) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Error reading CD: %i:%s", errno, strerror(errno)); -#endif /* VERBOSE_WARNINGS */ - InitCDSectorInfo(); - return(-1); - } // ENDIF- Trouble getting a track count? - - cdmode = mode; // Save mode for buffer positioning later. - return(0); // Call accomplished -} // END CDreadTrack() - -s32 CDgetBufferOffset() { -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: CDgetBufferOffset()"); -#endif /* VERBOSE_FUNCTION */ - - switch(cdmode) { - case CDVD_MODE_2048: - return(0+24); - case CDVD_MODE_2328: - return(0+24); - case CDVD_MODE_2340: - return(0+12); - case CDVD_MODE_2352: - return(0+0); - case CDVD_MODE_2368: // Unimplemented... as yet. - default: -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Unknown Mode %i", cdmode); -#endif /* VERBOSE_WARNINGS */ - return(0); // Not to worry. for now. - } // ENDSWITCH- where should we put the buffer pointer? -} // END CDgetBuffer() - -// I, personally, don't see the big deal with SubQ -// However, sooner or later I'll incorporate it into the Cache Buffer system -// (backward compatibility, and all that) -s32 CDreadSubQ(u32 lsn, cdvdSubQ *subq) { - int tempmode; - s32 s32result; - - s32result = 0; - -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: CDreadSubQ()"); -#endif /* VERBOSE_FUNCTION */ - - tempmode = cdmode; - if(tempmode == -1) tempmode = CDVD_MODE_2352; - CDreadTrack(lsn, tempmode, cdtempbuffer); - if((s32result == -1) || (errno != 0)) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Error prepping CD SubQ: %i:%s", errno, strerror(errno)); -#endif /* VERBOSE_WARNINGS */ - return(s32result); - } // ENDIF- Trouble? - - subchannel.cdsc_format = CDROM_MSF; - s32result = ioctl(devicehandle, CDROMSUBCHNL, &subchannel); - if((s32result == -1) || (errno != 0)) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Error reading CD SubQ: %i:%s", errno, strerror(errno)); -#endif /* VERBOSE_WARNINGS */ - return(s32result); - } // ENDIF- Trouble? - - if(subq != NULL) { - subq->mode = subchannel.cdsc_adr; - subq->ctrl = subchannel.cdsc_ctrl; - subq->trackNum = subchannel.cdsc_trk; - subq->trackIndex = subchannel.cdsc_ind; - subq->trackM = subchannel.cdsc_reladdr.msf.minute; - subq->trackS = subchannel.cdsc_reladdr.msf.second; - subq->trackF = subchannel.cdsc_reladdr.msf.frame; - subq->discM = subchannel.cdsc_absaddr.msf.minute; - subq->discS = subchannel.cdsc_absaddr.msf.second; - subq->discF = subchannel.cdsc_absaddr.msf.frame; - } // ENDIF- Did the caller want all this data? - - return(0); -} // END CDVDreadSubQ() - -s32 CDgetTN(cdvdTN *cdvdtn) { -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: CDgetTN()"); -#endif /* VERBOSE_FUNCTION */ - - if(cdvdtn != NULL) { - cdvdtn->strack = cdheader.cdth_trk0; - cdvdtn->etrack = cdheader.cdth_trk1; - } // ENDIF- programmer actually WANTS this info? - - return(0); // Call accomplished -} // END CDVDgetTN() - -s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd) { - u8 j; - u16 k; - char temptime[3]; - -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: CDgetTD()"); -#endif /* VERBOSE_FUNCTION */ - - j = newtrack; - if(j == CDROM_LEADOUT) j = 0; - - if(j == 0) { - k = 27; - } else { - k = j * 10 + 37; - } // ENDIF- Where to start hunting for this number? - - if(cdvdtd != NULL) { - cdvdtd->type = tocbuffer[j*10 + 30]; - - temptime[0] = BCDTOHEX(tocbuffer[k]); - temptime[1] = BCDTOHEX(tocbuffer[k + 1]); - temptime[2] = BCDTOHEX(tocbuffer[k + 2]); - cdvdtd->lsn = MSFtoLBA(temptime); - } // ENDIF- Does the caller REALLY want this data? - - return(0); // Call accomplished -} // END CDVDgetTD() - -s32 CALLBACK CDgetDiskType(s32 ioctldisktype) { - s32 offset; - s32 s32result; - int i; - u8 j; - int tempdisctype; - - offset = 0; - errno = 0; - i = 0; - j = 0; - tempdisctype = CDVD_TYPE_UNKNOWN; - -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: CDgetDiskType()"); -#endif /* VERBOSE_FUNCTION */ - - s32result = CDreadTrack(16, CDVD_MODE_2352, cdtempbuffer); - if((s32result != 0) || (errno != 0)) { - return(-1); - } // ENDIF- Cannot read the CD's ISO9660 volume sector? Abort - disctype = CDVD_TYPE_DETCTCD; - - switch(ioctldisktype) { - case CDS_AUDIO: -#ifdef VERBOSE_DISC_TYPE - PrintLog("CDVD driver: Detected CDDA Audio disc."); -#endif /* VERBOSE_DISC_TYPE */ - tempdisctype = CDVD_TYPE_CDDA; - tocbuffer[0] = 0x01; - break; - - case CDS_DATA_1: - case CDS_MIXED: -#ifdef VERBOSE_DISC_TYPE - PrintLog("CDVD driver: Detected CD disc."); -#endif /* VERBOSE_DISC_TYPE */ - tocbuffer[0] = 0x41; - - CDreadTrack(16, CDVD_MODE_2048, cdtempbuffer); - offset = CDgetBufferOffset(); - i = 0; - while((*(playstationcdname + i) != 0) && - (*(playstationcdname + i) == cdtempbuffer[offset + 8 + i])) i++; - if(*(playstationcdname + i) == 0) { - i = 0; - while((*(ps1name + i) != 0) && - (*(ps1name + i) == cdtempbuffer[offset + 1024 + i])) i++; - if(*(ps1name + i) == 0) { -#ifdef VERBOSE_DISC_TYPE - PrintLog("CDVD driver: Detected Playstation CD disc."); -#endif /* VERBOSE_DISC_TYPE */ - tempdisctype = CDVD_TYPE_PSCD; - } else { -#ifdef VERBOSE_DISC_TYPE - PrintLog("CDVD driver: Detected Playstation 2 CD disc."); -#endif /* VERBOSE_DISC_TYPE */ - tempdisctype = CDVD_TYPE_PS2CD; - } // ENDIF- Did we find the CD ident? (For Playstation 1 CDs) - } else { - tempdisctype = CDVD_TYPE_UNKNOWN; - } // ENDIF- Did we find the Playstation name? - break; - - default: - return(-1); - } // ENDSWITCH- What has ioctl disc type come up with? - - // Collect TN data - cdheader.cdth_trk0 = 0; - cdheader.cdth_trk1 = 0; - - s32result = ioctl(devicehandle, CDROMREADTOCHDR, &cdheader); - if((s32result == -1) || (errno != 0)) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Error reading TN: (%i) %i:%s", - s32result, errno, strerror(errno)); -#endif /* VERBOSE_WARNINGS */ - cdheader.cdth_trk0 = 1; - cdheader.cdth_trk1 = 1; - } // ENDIF- Failed to read in track count? Assume 1 track. -#ifdef VERBOSE_DISC_INFO - PrintLog("CDVD driver: Track Number Range: %i-%i", - cdheader.cdth_trk0, cdheader.cdth_trk1); -#endif /* VERBOSE_DISC_INFO */ - tocbuffer[2] = 0xA0; - tocbuffer[7] = HEXTOBCD(cdheader.cdth_trk0); - tocbuffer[12] = 0xA1; - tocbuffer[17] = HEXTOBCD(cdheader.cdth_trk1); - - // Collect disc TD data - cdtrack.cdte_track = CDROM_LEADOUT; - cdtrack.cdte_format = CDROM_LBA; - s32result = ioctl(devicehandle, CDROMREADTOCENTRY, &cdtrack); - if((s32result == -1) || (errno != 0)) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Error reading TD for disc: (%i) %i:%s", - s32result, errno, strerror(errno)); -#endif /* VERBOSE_WARNINGS */ - return(-1); - } // ENDIF- Trouble getting a track count? - - LBAtoMSF(cdtrack.cdte_addr.lba, &tocbuffer[27]); -#ifdef VERBOSE_DISC_INFO - PrintLog("CDVD driver: Total Time: %i:%i", - tocbuffer[27], tocbuffer[28]); -#endif /* VERBOSE_DISC_INFO */ - tocbuffer[27] = HEXTOBCD(tocbuffer[27]); - tocbuffer[28] = HEXTOBCD(tocbuffer[28]); - tocbuffer[29] = HEXTOBCD(tocbuffer[29]); - - // Collect track TD data - for(j = cdheader.cdth_trk0; j <= cdheader.cdth_trk1; j++) { - cdtrack.cdte_track = j; // j-1? - cdtrack.cdte_format = CDROM_LBA; - s32result = ioctl(devicehandle, CDROMREADTOCENTRY, &cdtrack); - if((s32result == -1) || (errno != 0)) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD driver: Error reading TD for track %i: (%i) %i:%s", - j, s32result, errno, strerror(errno)); -#endif /* VERBOSE_WARNINGS */ - // No more here... - - } else { - LBAtoMSF(cdtrack.cdte_addr.lba, &tocbuffer[j*10 + 37]); -#ifdef VERBOSE_DISC_INFO - PrintLog("CDVD driver: Track %i: Data Mode %i Disc Start Time:%i:%i.%i\n", - j, - cdtrack.cdte_datamode, - tocbuffer[j*10+37], - tocbuffer[j*10+38], - tocbuffer[j*10+39]); -#endif /* VERBOSE_DISC_INFO */ - tocbuffer[j*10 + 30] = cdtrack.cdte_datamode; - tocbuffer[j*10 + 32] = HEXTOBCD(j); - tocbuffer[j*10 + 37] = HEXTOBCD(tocbuffer[j*10 + 37]); - tocbuffer[j*10 + 38] = HEXTOBCD(tocbuffer[j*10 + 38]); - tocbuffer[j*10 + 39] = HEXTOBCD(tocbuffer[j*10 + 39]); - } // ENDIF- Trouble getting a track count? - } // NEXT j- Reading each track's info in turn - - errno = 0; - disctype = tempdisctype; // Trigger the fact we have the info (finally) - return(disctype); -} // END CDVDgetDiskType() +/* CD.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + +#include // errno + +#include // NULL + +#include // strerror() + +#include // open() + +#include // ioctl() + +#include // open() + +#include // lseek(), open() + +#include // close(), lseek(), (sleep()) + + + +#include // CD/DVD based ioctl() and defines. + + + +#include "../convert.h" + +#include "logfile.h" + +#include "device.h" + +#include "CD.h" + + + + + +// Constants + +u8 *playstationcdname = "PLAYSTATION\0"; + +u8 *ps1name = "CD-XA001\0"; + + + +// CD-ROM temp storage structures (see linux/cdrom.h for details) + +struct cdrom_tochdr cdheader; + +struct cdrom_tocentry cdtrack; + +struct cdrom_subchnl subchannel; + +u8 cdtempbuffer[2352]; + + + +int cdmode; // mode of last CDVDreadTrack call (important for CDs) + + + + + +// Internal Functions + + + +void InitCDSectorInfo() { + + cdmode = -1; + +} // END InitSectorInfo(); + + + + + +// Function Calls from CDVD.c + + + +void InitCDInfo() { + + InitCDSectorInfo(); + +} // END InitDiscType() + + + +s32 CDreadTrack(u32 lsn, int mode, u8 *buffer) { + + s32 s32result; + + + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: CDreadTrack(%i)", lsn); + +#endif /* VERBOSE_FUNCTION */ + + + + s32result = 0; + + + + if(buffer == NULL) return(-1); + + + + // The CD way of figuring out where to read. + + LBAtoMSF(lsn, buffer); + + + + switch(mode) { + + case CDVD_MODE_2048: + + case CDVD_MODE_2328: + + case CDVD_MODE_2340: + + case CDVD_MODE_2352: + + errno = 4; // Interrupted system call... (simulated the first time) + + while(errno == 4) { + + errno = 0; + + s32result = ioctl(devicehandle, CDROMREADRAW, buffer); + + } // ENDWHILE- Continually being interrupted by the system... + + break; + + case CDVD_MODE_2368: // Unimplemented... as yet. + + default: + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Unknown Mode %i", mode); + +#endif /* VERBOSE_WARNINGS */ + + return(-1); // Illegal Read Mode? Abort + + break; + + } // ENDSWITCH- Which read mode should we choose? + + if((s32result == -1) || (errno != 0)) { + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Error reading CD: %i:%s", errno, strerror(errno)); + +#endif /* VERBOSE_WARNINGS */ + + InitCDSectorInfo(); + + return(-1); + + } // ENDIF- Trouble getting a track count? + + + + cdmode = mode; // Save mode for buffer positioning later. + + return(0); // Call accomplished + +} // END CDreadTrack() + + + +s32 CDgetBufferOffset() { + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: CDgetBufferOffset()"); + +#endif /* VERBOSE_FUNCTION */ + + + + switch(cdmode) { + + case CDVD_MODE_2048: + + return(0+24); + + case CDVD_MODE_2328: + + return(0+24); + + case CDVD_MODE_2340: + + return(0+12); + + case CDVD_MODE_2352: + + return(0+0); + + case CDVD_MODE_2368: // Unimplemented... as yet. + + default: + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Unknown Mode %i", cdmode); + +#endif /* VERBOSE_WARNINGS */ + + return(0); // Not to worry. for now. + + } // ENDSWITCH- where should we put the buffer pointer? + +} // END CDgetBuffer() + + + +// I, personally, don't see the big deal with SubQ + +// However, sooner or later I'll incorporate it into the Cache Buffer system + +// (backward compatibility, and all that) + +s32 CDreadSubQ(u32 lsn, cdvdSubQ *subq) { + + int tempmode; + + s32 s32result; + + + + s32result = 0; + + + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: CDreadSubQ()"); + +#endif /* VERBOSE_FUNCTION */ + + + + tempmode = cdmode; + + if(tempmode == -1) tempmode = CDVD_MODE_2352; + + CDreadTrack(lsn, tempmode, cdtempbuffer); + + if((s32result == -1) || (errno != 0)) { + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Error prepping CD SubQ: %i:%s", errno, strerror(errno)); + +#endif /* VERBOSE_WARNINGS */ + + return(s32result); + + } // ENDIF- Trouble? + + + + subchannel.cdsc_format = CDROM_MSF; + + s32result = ioctl(devicehandle, CDROMSUBCHNL, &subchannel); + + if((s32result == -1) || (errno != 0)) { + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Error reading CD SubQ: %i:%s", errno, strerror(errno)); + +#endif /* VERBOSE_WARNINGS */ + + return(s32result); + + } // ENDIF- Trouble? + + + + if(subq != NULL) { + + subq->mode = subchannel.cdsc_adr; + + subq->ctrl = subchannel.cdsc_ctrl; + + subq->trackNum = subchannel.cdsc_trk; + + subq->trackIndex = subchannel.cdsc_ind; + + subq->trackM = subchannel.cdsc_reladdr.msf.minute; + + subq->trackS = subchannel.cdsc_reladdr.msf.second; + + subq->trackF = subchannel.cdsc_reladdr.msf.frame; + + subq->discM = subchannel.cdsc_absaddr.msf.minute; + + subq->discS = subchannel.cdsc_absaddr.msf.second; + + subq->discF = subchannel.cdsc_absaddr.msf.frame; + + } // ENDIF- Did the caller want all this data? + + + + return(0); + +} // END CDVDreadSubQ() + + + +s32 CDgetTN(cdvdTN *cdvdtn) { + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: CDgetTN()"); + +#endif /* VERBOSE_FUNCTION */ + + + + if(cdvdtn != NULL) { + + cdvdtn->strack = cdheader.cdth_trk0; + + cdvdtn->etrack = cdheader.cdth_trk1; + + } // ENDIF- programmer actually WANTS this info? + + + + return(0); // Call accomplished + +} // END CDVDgetTN() + + + +s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd) { + + u8 j; + + u16 k; + + char temptime[3]; + + + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: CDgetTD()"); + +#endif /* VERBOSE_FUNCTION */ + + + + j = newtrack; + + if(j == CDROM_LEADOUT) j = 0; + + + + if(j == 0) { + + k = 27; + + } else { + + k = j * 10 + 37; + + } // ENDIF- Where to start hunting for this number? + + + + if(cdvdtd != NULL) { + + cdvdtd->type = tocbuffer[j*10 + 30]; + + + + temptime[0] = BCDTOHEX(tocbuffer[k]); + + temptime[1] = BCDTOHEX(tocbuffer[k + 1]); + + temptime[2] = BCDTOHEX(tocbuffer[k + 2]); + + cdvdtd->lsn = MSFtoLBA(temptime); + + } // ENDIF- Does the caller REALLY want this data? + + + + return(0); // Call accomplished + +} // END CDVDgetTD() + + + +s32 CALLBACK CDgetDiskType(s32 ioctldisktype) { + + s32 offset; + + s32 s32result; + + int i; + + u8 j; + + int tempdisctype; + + + + offset = 0; + + errno = 0; + + i = 0; + + j = 0; + + tempdisctype = CDVD_TYPE_UNKNOWN; + + + +#ifdef VERBOSE_FUNCTION + + PrintLog("CDVD driver: CDgetDiskType()"); + +#endif /* VERBOSE_FUNCTION */ + + + + s32result = CDreadTrack(16, CDVD_MODE_2352, cdtempbuffer); + + if((s32result != 0) || (errno != 0)) { + + return(-1); + + } // ENDIF- Cannot read the CD's ISO9660 volume sector? Abort + + disctype = CDVD_TYPE_DETCTCD; + + + + switch(ioctldisktype) { + + case CDS_AUDIO: + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("CDVD driver: Detected CDDA Audio disc."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_CDDA; + + tocbuffer[0] = 0x01; + + break; + + + + case CDS_DATA_1: + + case CDS_MIXED: + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("CDVD driver: Detected CD disc."); + +#endif /* VERBOSE_DISC_TYPE */ + + tocbuffer[0] = 0x41; + + + + CDreadTrack(16, CDVD_MODE_2048, cdtempbuffer); + + offset = CDgetBufferOffset(); + + i = 0; + + while((*(playstationcdname + i) != 0) && + + (*(playstationcdname + i) == cdtempbuffer[offset + 8 + i])) i++; + + if(*(playstationcdname + i) == 0) { + + i = 0; + + while((*(ps1name + i) != 0) && + + (*(ps1name + i) == cdtempbuffer[offset + 1024 + i])) i++; + + if(*(ps1name + i) == 0) { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("CDVD driver: Detected Playstation CD disc."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_PSCD; + + } else { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("CDVD driver: Detected Playstation 2 CD disc."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_PS2CD; + + } // ENDIF- Did we find the CD ident? (For Playstation 1 CDs) + + } else { + + tempdisctype = CDVD_TYPE_UNKNOWN; + + } // ENDIF- Did we find the Playstation name? + + break; + + + + default: + + return(-1); + + } // ENDSWITCH- What has ioctl disc type come up with? + + + + // Collect TN data + + cdheader.cdth_trk0 = 0; + + cdheader.cdth_trk1 = 0; + + + + s32result = ioctl(devicehandle, CDROMREADTOCHDR, &cdheader); + + if((s32result == -1) || (errno != 0)) { + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Error reading TN: (%i) %i:%s", + + s32result, errno, strerror(errno)); + +#endif /* VERBOSE_WARNINGS */ + + cdheader.cdth_trk0 = 1; + + cdheader.cdth_trk1 = 1; + + } // ENDIF- Failed to read in track count? Assume 1 track. + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD driver: Track Number Range: %i-%i", + + cdheader.cdth_trk0, cdheader.cdth_trk1); + +#endif /* VERBOSE_DISC_INFO */ + + tocbuffer[2] = 0xA0; + + tocbuffer[7] = HEXTOBCD(cdheader.cdth_trk0); + + tocbuffer[12] = 0xA1; + + tocbuffer[17] = HEXTOBCD(cdheader.cdth_trk1); + + + + // Collect disc TD data + + cdtrack.cdte_track = CDROM_LEADOUT; + + cdtrack.cdte_format = CDROM_LBA; + + s32result = ioctl(devicehandle, CDROMREADTOCENTRY, &cdtrack); + + if((s32result == -1) || (errno != 0)) { + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Error reading TD for disc: (%i) %i:%s", + + s32result, errno, strerror(errno)); + +#endif /* VERBOSE_WARNINGS */ + + return(-1); + + } // ENDIF- Trouble getting a track count? + + + + LBAtoMSF(cdtrack.cdte_addr.lba, &tocbuffer[27]); + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD driver: Total Time: %i:%i", + + tocbuffer[27], tocbuffer[28]); + +#endif /* VERBOSE_DISC_INFO */ + + tocbuffer[27] = HEXTOBCD(tocbuffer[27]); + + tocbuffer[28] = HEXTOBCD(tocbuffer[28]); + + tocbuffer[29] = HEXTOBCD(tocbuffer[29]); + + + + // Collect track TD data + + for(j = cdheader.cdth_trk0; j <= cdheader.cdth_trk1; j++) { + + cdtrack.cdte_track = j; // j-1? + + cdtrack.cdte_format = CDROM_LBA; + + s32result = ioctl(devicehandle, CDROMREADTOCENTRY, &cdtrack); + + if((s32result == -1) || (errno != 0)) { + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVD driver: Error reading TD for track %i: (%i) %i:%s", + + j, s32result, errno, strerror(errno)); + +#endif /* VERBOSE_WARNINGS */ + + // No more here... + + + + } else { + + LBAtoMSF(cdtrack.cdte_addr.lba, &tocbuffer[j*10 + 37]); + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVD driver: Track %i: Data Mode %i Disc Start Time:%i:%i.%i\n", + + j, + + cdtrack.cdte_datamode, + + tocbuffer[j*10+37], + + tocbuffer[j*10+38], + + tocbuffer[j*10+39]); + +#endif /* VERBOSE_DISC_INFO */ + + tocbuffer[j*10 + 30] = cdtrack.cdte_datamode; + + tocbuffer[j*10 + 32] = HEXTOBCD(j); + + tocbuffer[j*10 + 37] = HEXTOBCD(tocbuffer[j*10 + 37]); + + tocbuffer[j*10 + 38] = HEXTOBCD(tocbuffer[j*10 + 38]); + + tocbuffer[j*10 + 39] = HEXTOBCD(tocbuffer[j*10 + 39]); + + } // ENDIF- Trouble getting a track count? + + } // NEXT j- Reading each track's info in turn + + + + errno = 0; + + disctype = tempdisctype; // Trigger the fact we have the info (finally) + + return(disctype); + +} // END CDVDgetDiskType() + diff --git a/plugins/CDVDlinuz/Src/Linux/CD.h b/plugins/CDVDlinuz/Src/Linux/CD.h index 2546cbaabd..0f8f6f485e 100644 --- a/plugins/CDVDlinuz/Src/Linux/CD.h +++ b/plugins/CDVDlinuz/Src/Linux/CD.h @@ -1,46 +1,92 @@ -/* CD.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - -#ifndef __CD_H__ -#define __CD_H__ - - -#ifndef __LINUX__ -#ifdef __linux__ -#define __LINUX__ -#endif /* __linux__ */ -#endif /* No __LINUX__ */ - -#define CDVDdefs -#include "../PS2Edefs.h" - - -// Exported Functions - -extern void InitCDInfo(); -extern s32 CDreadTrack(u32 lsn, int mode, u8 *buffer); -extern s32 CDgetBufferOffset(); -extern s32 CDreadSubQ(u32 lsn, cdvdSubQ *subq); -extern s32 CDgetTN(cdvdTN *cdvdtn); -extern s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd); -extern s32 CDgetDiskType(s32 ioctldisktype); - - -#endif /* __CD_H__ */ +/* CD.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + +#ifndef __CD_H__ + +#define __CD_H__ + + + + + +#ifndef __LINUX__ + +#ifdef __linux__ + +#define __LINUX__ + +#endif /* __linux__ */ + +#endif /* No __LINUX__ */ + + + +#define CDVDdefs + +#include "../PS2Edefs.h" + + + + + +// Exported Functions + + + +extern void InitCDInfo(); + +extern s32 CDreadTrack(u32 lsn, int mode, u8 *buffer); + +extern s32 CDgetBufferOffset(); + +extern s32 CDreadSubQ(u32 lsn, cdvdSubQ *subq); + +extern s32 CDgetTN(cdvdTN *cdvdtn); + +extern s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd); + +extern s32 CDgetDiskType(s32 ioctldisktype); + + + + + +#endif /* __CD_H__ */ + diff --git a/plugins/CDVDlinuz/Src/Linux/CDVDlinuz.c b/plugins/CDVDlinuz/Src/Linux/CDVDlinuz.c index 7ff0daa844..88f93bc804 100644 --- a/plugins/CDVDlinuz/Src/Linux/CDVDlinuz.c +++ b/plugins/CDVDlinuz/Src/Linux/CDVDlinuz.c @@ -1,368 +1,368 @@ /* CDVDlinuz.c - * Copyright (C) 2002-2005 CDVDlinuz 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include // errno -#include // open() -#include // NULL -#include // printf() -#include // getenv(), system() -#include // strerror(), sprintf() -#include // ioctl() -#include // stat() -#include // stat() -#include // time_t, time(), struct timeval -#include // stat() - -#ifndef __LINUX__ -#ifdef __linux__ -#define __LINUX__ -#endif /* __linux__ */ -#endif /* No __LINUX__ */ - -#define CDVDdefs -#include "PS2Edefs.h" -// #include "PS2Etypes.h" - -#include "CDVDlinuz.h" - -#include "buffer.h" -#include "conf.h" -#include "logfile.h" -#include "CD.h" // InitCDInfo() -#include "DVD.h" // InitDVDInfo() -#include "device.h" - -#include "../version.h" - - -// Globals - -time_t lasttime; - - -// Interface Functions - -u32 CALLBACK PS2EgetLibType() { - return(PS2E_LT_CDVD); // Library Type CDVD -} // END PS2EgetLibType() - - -u32 CALLBACK PS2EgetLibVersion2(u32 type) { - return((version<<16)|(revision<<8)|build); -} // END PS2EgetLibVersion2() - - -char* CALLBACK PS2EgetLibName() { - return(libname); -} // END PS2EgetLibName() - - -s32 CALLBACK CDVDinit() { - errno = 0; - - InitLog(); - if(OpenLog() != 0) return(-1); - -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD interface: CDVDinit()"); -#endif /* VERBOSE_FUNCTION */ - - InitConf(); - - devicehandle = -1; - devicecapability = 0; - lasttime = time(NULL); - - // Initialize DVD.c and CD.c as well - InitDisc(); - InitDVDInfo(); - InitCDInfo(); - - return(0); -} // END CDVDinit() - - -void CALLBACK CDVDshutdown() { -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD interface: CDVDshutdown()"); -#endif /* VERBOSE_FUNCTION */ - - DeviceClose(); - CloseLog(); -} // END CDVDshutdown() - - -s32 CALLBACK CDVDopen(const char* pTitleFilename) { - s32 s32result; - -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD interface: CDVDopen()"); -#endif /* VERBOSE_FUNCTION */ - - InitBuffer(); - - LoadConf(); - - errno = 0; - s32result = DeviceOpen(); - if(s32result != 0) return(s32result); - if(errno != 0) return(-1); - - return(0); -} // END CDVDopen(); - - -void CALLBACK CDVDclose() { -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD interface: CDVDclose()"); -#endif /* VERBOSE_FUNCTION */ - - DeviceClose(); -} // END CDVDclose() - - -s32 CALLBACK CDVDreadTrack(u32 lsn, int mode) { - s32 s32result; - -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD interface: CDVDreadTrack(%i)", lsn); -#endif /* VERBOSE_FUNCTION */ - - s32result = 0; - errno = 0; - - if(DiscInserted() == -1) return(-1); - - if(userbuffer < BUFFERMAX) { - if((bufferlist[userbuffer].lsn == lsn) && - (bufferlist[userbuffer].mode == mode)) { - return(0); - } // ENDIF- And it's the right one? - } // ENDIF- Are we already pointing at the buffer? - - userbuffer = FindListBuffer(lsn); - if(userbuffer < BUFFERMAX) { - if((bufferlist[userbuffer].lsn == lsn) && - (bufferlist[userbuffer].mode == mode)) { - return(0); - } // ENDIF- And it was the right one? - } // ENDIF- Was a buffer found in the cache? - - replacebuffer++; - if(replacebuffer >= BUFFERMAX) replacebuffer = 0; - userbuffer = replacebuffer; - - if(bufferlist[replacebuffer].upsort != 0xffff) { - RemoveListBuffer(replacebuffer); - } // ENDIF- Reference already in place? Remove it. - - s32result = DeviceReadTrack(lsn, mode, bufferlist[replacebuffer].buffer); - bufferlist[replacebuffer].lsn = lsn; - bufferlist[replacebuffer].mode = mode; - bufferlist[replacebuffer].offset = DeviceBufferOffset(); - - if((s32result != 0) || (errno != 0)) { - bufferlist[replacebuffer].mode = -1; // Error! flag buffer as such. - } else { - if((disctype != CDVD_TYPE_PS2DVD) && (disctype != CDVD_TYPE_DVDV)) { - if(mode == CDVD_MODE_2352) { - CDreadSubQ(lsn, &bufferlist[replacebuffer].subq); - errno = 0; - } // ENDIF- Read subq as well? - } // ENDIF- Read a DVD buffer or a CD buffer? - } // ENDIF-Read ok? Fill out rest of buffer info. - AddListBuffer(replacebuffer); - return(s32result); -} // END CDVDreadTrack() - - -u8* CALLBACK CDVDgetBuffer() { -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD interface: CDVDgetBuffer()"); -#endif /* VERBOSE_FUNCTION */ - - if(DiscInserted() == -1) return(NULL); - - if(userbuffer == 0xffff) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD interface: Not pointing to a buffer!"); -#endif /* VERBOSE_WARNINGS */ - return(NULL); // No buffer reference? - } // ENDIF- user buffer not pointing at anything? Abort - - if(bufferlist[userbuffer].mode < 0) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD interface: Error in buffer!"); -#endif /* VERBOSE_WARNINGS */ - return(NULL); // Bad Sector? - } // ENDIF- Trouble reading physical sector? Tell them. - - return(bufferlist[userbuffer].buffer + bufferlist[userbuffer].offset); -} // END CDVDgetBuffer() - - -// Note: without the lsn, I could pull the SubQ data directly from -// the stored buffer (in buffer.h). Oh, well. -s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ *subq) { -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD interface: CDVDreadSubQ(%i)", lsn); -#endif /* VERBOSE_FUNCTION */ - - if(DiscInserted() == -1) return(-1); - - // DVDs don't have SubQ data - if(disctype == CDVD_TYPE_PS2DVD) return(-1); - if(disctype == CDVD_TYPE_DVDV) return(-1); - - return(CDreadSubQ(lsn, subq)); -} // END CDVDreadSubQ() - - -s32 CALLBACK CDVDgetTN(cdvdTN *cdvdtn) { -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD interface: CDVDgetTN()"); -#endif /* VERBOSE_FUNCTION */ - - if(DiscInserted() == -1) return(-1); - - if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { - return(DVDgetTN(cdvdtn)); - } else { - return(CDgetTN(cdvdtn)); - } // ENDIF- Are we looking at a DVD? -} // END CDVDgetTN() - - -s32 CALLBACK CDVDgetTD(u8 newtrack, cdvdTD *cdvdtd) { -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD interface: CDVDgetTD()"); -#endif /* VERBOSE_FUNCTION */ - - if(DiscInserted() == -1) return(-1); - - if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { - return(DVDgetTD(newtrack, cdvdtd)); - } else { - return(CDgetTD(newtrack, cdvdtd)); - } // ENDIF- Are we looking at a DVD? -} // END CDVDgetTD() - - -s32 CALLBACK CDVDgetTOC(void *toc) { - // A structure to fill in, or at least some documentation on what - // the PS2 expects from this call would be more helpful than a - // "void *". - - union { - void *voidptr; - u8 *u8ptr; - } tocptr; - s32 i; - -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD interface: CDVDgetTOC()"); -#endif /* VERBOSE_FUNCTION */ - - if(toc == NULL) return(-1); - if(DiscInserted() == -1) return(-1); - - tocptr.voidptr = toc; - for(i = 0; i < 1024; i++) *(tocptr.u8ptr + i) = tocbuffer[i]; - tocptr.voidptr = NULL; - - return(0); -} // END CDVDgetTOC() - - -s32 CALLBACK CDVDgetDiskType() { -#ifdef VERBOSE_FUNCTION - // Called way too often in boot part of bios to be left in. - // PrintLog("CDVD interface: CDVDgetDiskType()"); -#endif /* VERBOSE_FUNCTION */ - - if(lasttime != time(NULL)) { - lasttime = time(NULL); - DeviceTrayStatus(); - } // ENDIF- Has enough time passed between calls? - - return(disctype); -} // END CDVDgetDiskType() - - -s32 CALLBACK CDVDgetTrayStatus() { -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD interface: CDVDgetTrayStatus()"); -#endif /* VERBOSE_FUNCTION */ - - if(lasttime != time(NULL)) { - lasttime = time(NULL); - DeviceTrayStatus(); - } // ENDIF- Has enough time passed between calls? - - return(traystatus); -} // END CDVDgetTrayStatus() - - -s32 CALLBACK CDVDctrlTrayOpen() { -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD interface: CDVDctrlTrayOpen()"); -#endif /* VERBOSE_FUNCTION */ - - return(DeviceTrayOpen()); -} // END CDVDctrlTrayOpen() - - -s32 CALLBACK CDVDctrlTrayClose() { -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD interface: CDVDctrlTrayClose()"); -#endif /* VERBOSE_FUNCTION */ - - return(DeviceTrayClose()); -} // END CDVDctrlTrayClose() - - -void CALLBACK CDVDconfigure() { - ExecCfg("configure"); -} // END CDVDconfigure() - - -void CALLBACK CDVDabout() { - ExecCfg("about"); -} // END CDVDabout() - - -s32 CALLBACK CDVDtest() { - s32 s32result; - - errno = 0; - - if(devicehandle != -1) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVD interface: Device already open"); -#endif /* VERBOSE_WARNINGS */ - return(0); - } // ENDIF- Is the CD/DVD already in use? That's fine. - -#ifdef VERBOSE_FUNCTION - PrintLog("CDVD driver: CDVDtest()"); -#endif /* VERBOSE_FUNCTION */ - - s32result = DeviceOpen(); - DeviceClose(); - return(s32result); -} // END CDVDtest() + * Copyright (C) 2002-2005 CDVDlinuz 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include // errno +#include // open() +#include // NULL +#include // printf() +#include // getenv(), system() +#include // strerror(), sprintf() +#include // ioctl() +#include // stat() +#include // stat() +#include // time_t, time(), struct timeval +#include // stat() + +#ifndef __LINUX__ +#ifdef __linux__ +#define __LINUX__ +#endif /* __linux__ */ +#endif /* No __LINUX__ */ + +#define CDVDdefs +#include "PS2Edefs.h" +// #include "PS2Etypes.h" + +#include "CDVDlinuz.h" + +#include "buffer.h" +#include "conf.h" +#include "logfile.h" +#include "CD.h" // InitCDInfo() +#include "DVD.h" // InitDVDInfo() +#include "device.h" + +#include "../version.h" + + +// Globals + +time_t lasttime; + + +// Interface Functions + +u32 CALLBACK PS2EgetLibType() { + return(PS2E_LT_CDVD); // Library Type CDVD +} // END PS2EgetLibType() + + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return((version<<16)|(revision<<8)|build); +} // END PS2EgetLibVersion2() + + +char* CALLBACK PS2EgetLibName() { + return(libname); +} // END PS2EgetLibName() + + +s32 CALLBACK CDVDinit() { + errno = 0; + + InitLog(); + if(OpenLog() != 0) return(-1); + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDinit()"); +#endif /* VERBOSE_FUNCTION */ + + InitConf(); + + devicehandle = -1; + devicecapability = 0; + lasttime = time(NULL); + + // Initialize DVD.c and CD.c as well + InitDisc(); + InitDVDInfo(); + InitCDInfo(); + + return(0); +} // END CDVDinit() + + +void CALLBACK CDVDshutdown() { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDshutdown()"); +#endif /* VERBOSE_FUNCTION */ + + DeviceClose(); + CloseLog(); +} // END CDVDshutdown() + + +s32 CALLBACK CDVDopen(const char* pTitleFilename) { + s32 s32result; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDopen()"); +#endif /* VERBOSE_FUNCTION */ + + InitBuffer(); + + LoadConf(); + + errno = 0; + s32result = DeviceOpen(); + if(s32result != 0) return(s32result); + if(errno != 0) return(-1); + + return(0); +} // END CDVDopen(); + + +void CALLBACK CDVDclose() { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDclose()"); +#endif /* VERBOSE_FUNCTION */ + + DeviceClose(); +} // END CDVDclose() + + +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode) { + s32 s32result; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDreadTrack(%i)", lsn); +#endif /* VERBOSE_FUNCTION */ + + s32result = 0; + errno = 0; + + if(DiscInserted() == -1) return(-1); + + if(userbuffer < BUFFERMAX) { + if((bufferlist[userbuffer].lsn == lsn) && + (bufferlist[userbuffer].mode == mode)) { + return(0); + } // ENDIF- And it's the right one? + } // ENDIF- Are we already pointing at the buffer? + + userbuffer = FindListBuffer(lsn); + if(userbuffer < BUFFERMAX) { + if((bufferlist[userbuffer].lsn == lsn) && + (bufferlist[userbuffer].mode == mode)) { + return(0); + } // ENDIF- And it was the right one? + } // ENDIF- Was a buffer found in the cache? + + replacebuffer++; + if(replacebuffer >= BUFFERMAX) replacebuffer = 0; + userbuffer = replacebuffer; + + if(bufferlist[replacebuffer].upsort != 0xffff) { + RemoveListBuffer(replacebuffer); + } // ENDIF- Reference already in place? Remove it. + + s32result = DeviceReadTrack(lsn, mode, bufferlist[replacebuffer].buffer); + bufferlist[replacebuffer].lsn = lsn; + bufferlist[replacebuffer].mode = mode; + bufferlist[replacebuffer].offset = DeviceBufferOffset(); + + if((s32result != 0) || (errno != 0)) { + bufferlist[replacebuffer].mode = -1; // Error! flag buffer as such. + } else { + if((disctype != CDVD_TYPE_PS2DVD) && (disctype != CDVD_TYPE_DVDV)) { + if(mode == CDVD_MODE_2352) { + CDreadSubQ(lsn, &bufferlist[replacebuffer].subq); + errno = 0; + } // ENDIF- Read subq as well? + } // ENDIF- Read a DVD buffer or a CD buffer? + } // ENDIF-Read ok? Fill out rest of buffer info. + AddListBuffer(replacebuffer); + return(s32result); +} // END CDVDreadTrack() + + +u8* CALLBACK CDVDgetBuffer() { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDgetBuffer()"); +#endif /* VERBOSE_FUNCTION */ + + if(DiscInserted() == -1) return(NULL); + + if(userbuffer == 0xffff) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD interface: Not pointing to a buffer!"); +#endif /* VERBOSE_WARNINGS */ + return(NULL); // No buffer reference? + } // ENDIF- user buffer not pointing at anything? Abort + + if(bufferlist[userbuffer].mode < 0) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD interface: Error in buffer!"); +#endif /* VERBOSE_WARNINGS */ + return(NULL); // Bad Sector? + } // ENDIF- Trouble reading physical sector? Tell them. + + return(bufferlist[userbuffer].buffer + bufferlist[userbuffer].offset); +} // END CDVDgetBuffer() + + +// Note: without the lsn, I could pull the SubQ data directly from +// the stored buffer (in buffer.h). Oh, well. +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ *subq) { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDreadSubQ(%i)", lsn); +#endif /* VERBOSE_FUNCTION */ + + if(DiscInserted() == -1) return(-1); + + // DVDs don't have SubQ data + if(disctype == CDVD_TYPE_PS2DVD) return(-1); + if(disctype == CDVD_TYPE_DVDV) return(-1); + + return(CDreadSubQ(lsn, subq)); +} // END CDVDreadSubQ() + + +s32 CALLBACK CDVDgetTN(cdvdTN *cdvdtn) { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDgetTN()"); +#endif /* VERBOSE_FUNCTION */ + + if(DiscInserted() == -1) return(-1); + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + return(DVDgetTN(cdvdtn)); + } else { + return(CDgetTN(cdvdtn)); + } // ENDIF- Are we looking at a DVD? +} // END CDVDgetTN() + + +s32 CALLBACK CDVDgetTD(u8 newtrack, cdvdTD *cdvdtd) { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDgetTD()"); +#endif /* VERBOSE_FUNCTION */ + + if(DiscInserted() == -1) return(-1); + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + return(DVDgetTD(newtrack, cdvdtd)); + } else { + return(CDgetTD(newtrack, cdvdtd)); + } // ENDIF- Are we looking at a DVD? +} // END CDVDgetTD() + + +s32 CALLBACK CDVDgetTOC(void *toc) { + // A structure to fill in, or at least some documentation on what + // the PS2 expects from this call would be more helpful than a + // "void *". + + union { + void *voidptr; + u8 *u8ptr; + } tocptr; + s32 i; + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDgetTOC()"); +#endif /* VERBOSE_FUNCTION */ + + if(toc == NULL) return(-1); + if(DiscInserted() == -1) return(-1); + + tocptr.voidptr = toc; + for(i = 0; i < 1024; i++) *(tocptr.u8ptr + i) = tocbuffer[i]; + tocptr.voidptr = NULL; + + return(0); +} // END CDVDgetTOC() + + +s32 CALLBACK CDVDgetDiskType() { +#ifdef VERBOSE_FUNCTION + // Called way too often in boot part of bios to be left in. + // PrintLog("CDVD interface: CDVDgetDiskType()"); +#endif /* VERBOSE_FUNCTION */ + + if(lasttime != time(NULL)) { + lasttime = time(NULL); + DeviceTrayStatus(); + } // ENDIF- Has enough time passed between calls? + + return(disctype); +} // END CDVDgetDiskType() + + +s32 CALLBACK CDVDgetTrayStatus() { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDgetTrayStatus()"); +#endif /* VERBOSE_FUNCTION */ + + if(lasttime != time(NULL)) { + lasttime = time(NULL); + DeviceTrayStatus(); + } // ENDIF- Has enough time passed between calls? + + return(traystatus); +} // END CDVDgetTrayStatus() + + +s32 CALLBACK CDVDctrlTrayOpen() { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDctrlTrayOpen()"); +#endif /* VERBOSE_FUNCTION */ + + return(DeviceTrayOpen()); +} // END CDVDctrlTrayOpen() + + +s32 CALLBACK CDVDctrlTrayClose() { +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD interface: CDVDctrlTrayClose()"); +#endif /* VERBOSE_FUNCTION */ + + return(DeviceTrayClose()); +} // END CDVDctrlTrayClose() + + +void CALLBACK CDVDconfigure() { + ExecCfg("configure"); +} // END CDVDconfigure() + + +void CALLBACK CDVDabout() { + ExecCfg("about"); +} // END CDVDabout() + + +s32 CALLBACK CDVDtest() { + s32 s32result; + + errno = 0; + + if(devicehandle != -1) { +#ifdef VERBOSE_WARNINGS + PrintLog("CDVD interface: Device already open"); +#endif /* VERBOSE_WARNINGS */ + return(0); + } // ENDIF- Is the CD/DVD already in use? That's fine. + +#ifdef VERBOSE_FUNCTION + PrintLog("CDVD driver: CDVDtest()"); +#endif /* VERBOSE_FUNCTION */ + + s32result = DeviceOpen(); + DeviceClose(); + return(s32result); +} // END CDVDtest() diff --git a/plugins/CDVDlinuz/Src/Linux/CDVDlinuz.h b/plugins/CDVDlinuz/Src/Linux/CDVDlinuz.h index 69a4add14d..8fb8fb94fe 100644 --- a/plugins/CDVDlinuz/Src/Linux/CDVDlinuz.h +++ b/plugins/CDVDlinuz/Src/Linux/CDVDlinuz.h @@ -1,31 +1,62 @@ -/* CDVDlinuz.h - * Copyright (C) 2002-2005 CDVDlinuz 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __CDVDLINUZ_H__ -#define __CDVDLINUZ_H__ - - -// #define VERBOSE_WARNINGS -// #define VERBOSE_FUNCTION -#define VERBOSE_DISC_INFO -#define VERBOSE_DISC_TYPE - -#define READ_AHEAD_BUFFERS 32 - - -#endif /* __CDVDLINUZ_H__ */ +/* CDVDlinuz.h + + * Copyright (C) 2002-2005 CDVDlinuz 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + */ + + + +#ifndef __CDVDLINUZ_H__ + +#define __CDVDLINUZ_H__ + + + + + +// #define VERBOSE_WARNINGS + +// #define VERBOSE_FUNCTION + +#define VERBOSE_DISC_INFO + +#define VERBOSE_DISC_TYPE + + + +#define READ_AHEAD_BUFFERS 32 + + + + + +#endif /* __CDVDLINUZ_H__ */ + diff --git a/plugins/CDVDlinuz/Src/Linux/DVD.h b/plugins/CDVDlinuz/Src/Linux/DVD.h index 7dbc1c7c0d..d3837b8520 100644 --- a/plugins/CDVDlinuz/Src/Linux/DVD.h +++ b/plugins/CDVDlinuz/Src/Linux/DVD.h @@ -1,45 +1,90 @@ -/* DVD.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - -#ifndef __DVD_H__ -#define __DVD_H__ - - -#ifndef __LINUX__ -#ifdef __linux__ -#define __LINUX__ -#endif /* __linux__ */ -#endif /* No __LINUX__ */ - -#define CDVDdefs -#include "PS2Edefs.h" - - -// Exported Functions - -extern void HexDump(u8 *strptr, u8 count); -extern void InitDVDInfo(); -extern s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer); -extern s32 DVDgetTN(cdvdTN *cdvdtn); -extern s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd); -extern s32 DVDgetDiskType(s32 ioctldisktype); - - -#endif /* __DVD_H__ */ +/* DVD.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + +#ifndef __DVD_H__ + +#define __DVD_H__ + + + + + +#ifndef __LINUX__ + +#ifdef __linux__ + +#define __LINUX__ + +#endif /* __linux__ */ + +#endif /* No __LINUX__ */ + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + + + +// Exported Functions + + + +extern void HexDump(u8 *strptr, u8 count); + +extern void InitDVDInfo(); + +extern s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer); + +extern s32 DVDgetTN(cdvdTN *cdvdtn); + +extern s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd); + +extern s32 DVDgetDiskType(s32 ioctldisktype); + + + + + +#endif /* __DVD_H__ */ + diff --git a/plugins/CDVDlinuz/Src/Linux/aboutbox.c b/plugins/CDVDlinuz/Src/Linux/aboutbox.c index 9408d0bc8e..1e29dc1900 100644 --- a/plugins/CDVDlinuz/Src/Linux/aboutbox.c +++ b/plugins/CDVDlinuz/Src/Linux/aboutbox.c @@ -1,106 +1,212 @@ -/* aboutbox.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // NULL -#include // sprintf() - -#include // gtk_button_new_with_label() -#include // gtk_container_add() -#include // gtk_hbutton_box_new() -#include // gtk_label_new() -#include // gtk_init(), gtk_main(), gtk_main_quit() -#include // gtk_vbox_new() -#include // gtk_window_new() - -#include "version.h" -#include "aboutbox.h" - - -struct AboutBoxData aboutbox; - - -gint AboutBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - if(aboutbox.window != NULL) { - gtk_widget_destroy(aboutbox.window); - aboutbox.window = NULL; - } // ENDIF- Do we have an About Box still? - - gtk_main_quit(); - return(TRUE); -} // END AboutBoxCancelEvent() - - -void AboutBoxDisplay() { - GtkWidget *item; - GtkWidget *container; - GtkWidget *vbox1; - char templine[256]; - - aboutbox.window = NULL; - aboutbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_container_set_border_width(GTK_CONTAINER(aboutbox.window), 5); - gtk_window_set_title(GTK_WINDOW(aboutbox.window), "About CDVDlinuz"); - gtk_window_set_position(GTK_WINDOW(aboutbox.window), GTK_WIN_POS_CENTER); - gtk_window_set_modal(GTK_WINDOW(aboutbox.window), TRUE); - gtk_window_set_resizable(GTK_WINDOW(aboutbox.window), FALSE); - - g_signal_connect(G_OBJECT(aboutbox.window), "delete_event", - G_CALLBACK(AboutBoxCancelEvent), NULL); - - vbox1 = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(aboutbox.window), vbox1); - gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); - gtk_widget_show(vbox1); - - sprintf(templine, "%s v%i.%i", libname, revision, build); - item = gtk_label_new(templine); - gtk_box_pack_start(GTK_BOX(vbox1), item, FALSE, FALSE, 0); - gtk_widget_show(item); - item = NULL; - - item = gtk_label_new("Current Author: efp"); - gtk_box_pack_start(GTK_BOX(vbox1), item, FALSE, FALSE, 0); - gtk_widget_show(item); - item = NULL; - - item = gtk_label_new("Original code by: linuzappz & shadow"); - gtk_box_pack_start(GTK_BOX(vbox1), item, FALSE, FALSE, 0); - gtk_widget_show(item); - item = NULL; - - container = gtk_hbutton_box_new(); - gtk_box_pack_start(GTK_BOX(vbox1), container, TRUE, TRUE, 0); - gtk_widget_show(container); - - item = gtk_button_new_with_label("Ok"); - gtk_container_add(GTK_CONTAINER(container), item); - GTK_WIDGET_SET_FLAGS(item, GTK_CAN_DEFAULT); - gtk_widget_show(item); - - g_signal_connect(G_OBJECT(item), "clicked", - G_CALLBACK(AboutBoxCancelEvent), NULL); - item = NULL; - container = NULL; - vbox1 = NULL; - - gtk_widget_show(aboutbox.window); - gtk_main(); -} // END AboutDisplay() +/* aboutbox.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // sprintf() + + + +#include // gtk_button_new_with_label() + +#include // gtk_container_add() + +#include // gtk_hbutton_box_new() + +#include // gtk_label_new() + +#include // gtk_init(), gtk_main(), gtk_main_quit() + +#include // gtk_vbox_new() + +#include // gtk_window_new() + + + +#include "version.h" + +#include "aboutbox.h" + + + + + +struct AboutBoxData aboutbox; + + + + + +gint AboutBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + if(aboutbox.window != NULL) { + + gtk_widget_destroy(aboutbox.window); + + aboutbox.window = NULL; + + } // ENDIF- Do we have an About Box still? + + + + gtk_main_quit(); + + return(TRUE); + +} // END AboutBoxCancelEvent() + + + + + +void AboutBoxDisplay() { + + GtkWidget *item; + + GtkWidget *container; + + GtkWidget *vbox1; + + char templine[256]; + + + + aboutbox.window = NULL; + + aboutbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + gtk_container_set_border_width(GTK_CONTAINER(aboutbox.window), 5); + + gtk_window_set_title(GTK_WINDOW(aboutbox.window), "About CDVDlinuz"); + + gtk_window_set_position(GTK_WINDOW(aboutbox.window), GTK_WIN_POS_CENTER); + + gtk_window_set_modal(GTK_WINDOW(aboutbox.window), TRUE); + + gtk_window_set_resizable(GTK_WINDOW(aboutbox.window), FALSE); + + + + g_signal_connect(G_OBJECT(aboutbox.window), "delete_event", + + G_CALLBACK(AboutBoxCancelEvent), NULL); + + + + vbox1 = gtk_vbox_new(FALSE, 5); + + gtk_container_add(GTK_CONTAINER(aboutbox.window), vbox1); + + gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); + + gtk_widget_show(vbox1); + + + + sprintf(templine, "%s v%i.%i", libname, revision, build); + + item = gtk_label_new(templine); + + gtk_box_pack_start(GTK_BOX(vbox1), item, FALSE, FALSE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + item = gtk_label_new("Current Author: efp"); + + gtk_box_pack_start(GTK_BOX(vbox1), item, FALSE, FALSE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + item = gtk_label_new("Original code by: linuzappz & shadow"); + + gtk_box_pack_start(GTK_BOX(vbox1), item, FALSE, FALSE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + container = gtk_hbutton_box_new(); + + gtk_box_pack_start(GTK_BOX(vbox1), container, TRUE, TRUE, 0); + + gtk_widget_show(container); + + + + item = gtk_button_new_with_label("Ok"); + + gtk_container_add(GTK_CONTAINER(container), item); + + GTK_WIDGET_SET_FLAGS(item, GTK_CAN_DEFAULT); + + gtk_widget_show(item); + + + + g_signal_connect(G_OBJECT(item), "clicked", + + G_CALLBACK(AboutBoxCancelEvent), NULL); + + item = NULL; + + container = NULL; + + vbox1 = NULL; + + + + gtk_widget_show(aboutbox.window); + + gtk_main(); + +} // END AboutDisplay() + diff --git a/plugins/CDVDlinuz/Src/Linux/aboutbox.h b/plugins/CDVDlinuz/Src/Linux/aboutbox.h index bf1df52ca0..feabf93790 100644 --- a/plugins/CDVDlinuz/Src/Linux/aboutbox.h +++ b/plugins/CDVDlinuz/Src/Linux/aboutbox.h @@ -1,39 +1,78 @@ -/* aboutbox.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef ABOUTBOX_H -#define ABOUTBOX_H - - -#include - - -struct AboutBoxData { - GtkWidget *window; // GtkWindow - About Box -}; - -extern struct AboutBoxData aboutbox; - - -extern void AboutBoxDisplay(); - - -#endif /* ABOUTBOX_H */ +/* aboutbox.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef ABOUTBOX_H + +#define ABOUTBOX_H + + + + + +#include + + + + + +struct AboutBoxData { + + GtkWidget *window; // GtkWindow - About Box + +}; + + + +extern struct AboutBoxData aboutbox; + + + + + +extern void AboutBoxDisplay(); + + + + + +#endif /* ABOUTBOX_H */ + diff --git a/plugins/CDVDlinuz/Src/Linux/actualfile.c b/plugins/CDVDlinuz/Src/Linux/actualfile.c index 64eaa69a7b..947cbe3a6c 100644 --- a/plugins/CDVDlinuz/Src/Linux/actualfile.c +++ b/plugins/CDVDlinuz/Src/Linux/actualfile.c @@ -1,222 +1,444 @@ -/* actualfile.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // errno -#include // open() -#include // rename() -#include // strerror() -#include // stat64(), open(), fstat() -#include // stat64(), open(), fstat(), lseek64() -#include // stat64(), fstat(), lseek64(), read(), close(), write() -// unlink() - -#include "logfile.h" -#include "actualfile.h" - - -int IsActualFile(const char *filename) { - int retval; - struct stat64 filestat; - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: IsActualFile(%s)", filename); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - errno = 0; - retval = stat64(filename, &filestat); - if((retval < 0) || (errno != 0)) { -#ifdef VERBOSE_WARNING_ACTUALFILE - PrintLog("CDVDiso file: Error retrieving stats on %s", filename); - PrintLog("CDVDiso file: %i:%s\n", errno, strerror(errno)); -#endif /* VERBOSE_WARNING_ACTUALFILE */ - return(-1); // Name doesn't exist. - } // ENDIF- Trouble getting stat on a file? - - if(S_ISREG(filestat.st_mode) == 0) return(-2); // Not a regular file. - return(0); // Yep, that's a file. -} // END IsActualFile() - - -void ActualFileDelete(const char *filename) { -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileDelete(%s)", filename); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - unlink(filename); -} // END ActualFileDelete() - - -void ActualFileRename(const char *origname, const char *newname) { -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileRename(%s->%s)", origname, newname); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - rename(origname, newname); - return; -} // END ActualFileRename() - - -ACTUALHANDLE ActualFileOpenForRead(const char *filename) { - int newhandle; - - if(filename == NULL) return(-1); - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileOpenForRead(%s)", filename); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - errno = 0; - newhandle = open(filename, O_RDONLY | O_LARGEFILE); - if((newhandle < 0) || (errno != 0)) { -#ifdef VERBOSE_WARNING_ACTUALFILE - PrintLog("CDVDiso file: Error opening file %s\n", filename); - PrintLog("CDVDiso file: (%i) %i:%s\n", newhandle, errno, strerror(errno)); -#endif /* VERBOSE_WARNING_ACTUALFILE */ - return(-1); - } // ENDIF- Error? Abort - - return(newhandle); -} // END ActualFileOpenForRead() - - -off64_t ActualFileSize(ACTUALHANDLE handle) { - int retval; - struct stat64 filestat; - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileSize()\n"); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - errno = 0; - retval = fstat64(handle, &filestat); - if((retval < 0) || (errno != 0)) return(-1); // Name doesn't exist. - return(filestat.st_size); -} // END ActualFileSize() - - -int ActualFileSeek(ACTUALHANDLE handle, off64_t position) { - off64_t moved; - - if(handle < 0) return(-1); - if(position < 0) return(-1); // Maybe... position = 0? - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileSeek(%lli)", position); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - errno = 0; - moved = lseek64(handle, position, SEEK_SET); - if(errno != 0) { -#ifdef VERBOSE_WARNING_ACTUALFILE - PrintLog("CDVDiso file: Error on seek (%lli)", position); - PrintLog("CDVDiso file: %i:%s\n", errno, strerror(errno)); -#endif /* VERBOSE_WARNING_ACTUALFILE */ - return(-1); - } // ENDIF- Error? Abort - - return(0); -} // END ActualFileSeek() - - -int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer) { - int retval; - - if(handle == ACTUALHANDLENULL) return(-1); - if(bytes < 1) return(-1); - if(buffer == NULL) return(-1); - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileRead(%i)", bytes); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - errno = 0; - retval = read(handle, buffer, bytes); - if((retval < 0) || (errno != 0)) { -#ifdef VERBOSE_WARNING_ACTUALFILE - PrintLog("CDVDiso file: Error reading from file!"); - PrintLog("CDVDiso file: %i:%s", errno, strerror(errno)); -#endif /* VERBOSE_WARNING_ACTUALFILE */ - // return(-1); - } // ENDIF- Error? Abort - - return(retval); // Send back how many bytes read -} // END ActualFileRead() - - -void ActualFileClose(ACTUALHANDLE handle) { - if(handle < 0) return; - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileClose()"); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - errno = 0; - close(handle); - return; -} // END ActualFileClose() - - -ACTUALHANDLE ActualFileOpenForWrite(const char *filename) { - int newhandle; - - if(filename == NULL) return(-1); - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileOpenForWrite(%s)", filename); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - errno = 0; - newhandle = open(filename, O_WRONLY | O_CREAT | O_LARGEFILE, 0644); - if((newhandle < 0) || (errno != 0)) { -#ifdef VERBOSE_WARNING_ACTUALFILE - PrintLog("CDVDiso file: Error opening file %s", filename); - PrintLog("CDVDiso file: (%i) %i:%s", newhandle, errno, strerror(errno)); -#endif /* VERBOSE_WARNING_ACTUALFILE */ - return(-1); - } // ENDIF- Error? Abort - - return(newhandle); -} // END ActualFileOpenForWrite() - - -int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer) { - int retval; - - if(handle < 0) return(-1); - if(bytes < 1) return(-1); - if(buffer == NULL) return(-1); - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileWrite(%i)", bytes); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - errno = 0; - retval = write(handle, buffer, bytes); - if((retval < 0) || (errno != 0)) { -#ifdef VERBOSE_WARNING_ACTUALFILE - PrintLog("CDVDiso file: Error writing to file!"); - PrintLog("CDVDiso file: %i:%s", errno, strerror(errno)); -#endif /* VERBOSE_WARNING_ACTUALFILE */ - // return(-1); - } // ENDIF- Error? Abort - - return(retval); // Send back how many bytes written -} // END ActualFileWrite() +/* actualfile.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // errno + +#include // open() + +#include // rename() + +#include // strerror() + +#include // stat64(), open(), fstat() + +#include // stat64(), open(), fstat(), lseek64() + +#include // stat64(), fstat(), lseek64(), read(), close(), write() + +// unlink() + + + +#include "logfile.h" + +#include "actualfile.h" + + + + + +int IsActualFile(const char *filename) { + + int retval; + + struct stat64 filestat; + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: IsActualFile(%s)", filename); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + errno = 0; + + retval = stat64(filename, &filestat); + + if((retval < 0) || (errno != 0)) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error retrieving stats on %s", filename); + + PrintLog("CDVDiso file: %i:%s\n", errno, strerror(errno)); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + return(-1); // Name doesn't exist. + + } // ENDIF- Trouble getting stat on a file? + + + + if(S_ISREG(filestat.st_mode) == 0) return(-2); // Not a regular file. + + return(0); // Yep, that's a file. + +} // END IsActualFile() + + + + + +void ActualFileDelete(const char *filename) { + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileDelete(%s)", filename); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + unlink(filename); + +} // END ActualFileDelete() + + + + + +void ActualFileRename(const char *origname, const char *newname) { + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileRename(%s->%s)", origname, newname); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + rename(origname, newname); + + return; + +} // END ActualFileRename() + + + + + +ACTUALHANDLE ActualFileOpenForRead(const char *filename) { + + int newhandle; + + + + if(filename == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileOpenForRead(%s)", filename); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + errno = 0; + + newhandle = open(filename, O_RDONLY | O_LARGEFILE); + + if((newhandle < 0) || (errno != 0)) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error opening file %s\n", filename); + + PrintLog("CDVDiso file: (%i) %i:%s\n", newhandle, errno, strerror(errno)); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + return(-1); + + } // ENDIF- Error? Abort + + + + return(newhandle); + +} // END ActualFileOpenForRead() + + + + + +off64_t ActualFileSize(ACTUALHANDLE handle) { + + int retval; + + struct stat64 filestat; + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileSize()\n"); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + errno = 0; + + retval = fstat64(handle, &filestat); + + if((retval < 0) || (errno != 0)) return(-1); // Name doesn't exist. + + return(filestat.st_size); + +} // END ActualFileSize() + + + + + +int ActualFileSeek(ACTUALHANDLE handle, off64_t position) { + + off64_t moved; + + + + if(handle < 0) return(-1); + + if(position < 0) return(-1); // Maybe... position = 0? + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileSeek(%lli)", position); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + errno = 0; + + moved = lseek64(handle, position, SEEK_SET); + + if(errno != 0) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error on seek (%lli)", position); + + PrintLog("CDVDiso file: %i:%s\n", errno, strerror(errno)); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + return(-1); + + } // ENDIF- Error? Abort + + + + return(0); + +} // END ActualFileSeek() + + + + + +int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer) { + + int retval; + + + + if(handle == ACTUALHANDLENULL) return(-1); + + if(bytes < 1) return(-1); + + if(buffer == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileRead(%i)", bytes); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + errno = 0; + + retval = read(handle, buffer, bytes); + + if((retval < 0) || (errno != 0)) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error reading from file!"); + + PrintLog("CDVDiso file: %i:%s", errno, strerror(errno)); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + // return(-1); + + } // ENDIF- Error? Abort + + + + return(retval); // Send back how many bytes read + +} // END ActualFileRead() + + + + + +void ActualFileClose(ACTUALHANDLE handle) { + + if(handle < 0) return; + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileClose()"); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + errno = 0; + + close(handle); + + return; + +} // END ActualFileClose() + + + + + +ACTUALHANDLE ActualFileOpenForWrite(const char *filename) { + + int newhandle; + + + + if(filename == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileOpenForWrite(%s)", filename); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + errno = 0; + + newhandle = open(filename, O_WRONLY | O_CREAT | O_LARGEFILE, 0644); + + if((newhandle < 0) || (errno != 0)) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error opening file %s", filename); + + PrintLog("CDVDiso file: (%i) %i:%s", newhandle, errno, strerror(errno)); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + return(-1); + + } // ENDIF- Error? Abort + + + + return(newhandle); + +} // END ActualFileOpenForWrite() + + + + + +int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer) { + + int retval; + + + + if(handle < 0) return(-1); + + if(bytes < 1) return(-1); + + if(buffer == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileWrite(%i)", bytes); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + errno = 0; + + retval = write(handle, buffer, bytes); + + if((retval < 0) || (errno != 0)) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error writing to file!"); + + PrintLog("CDVDiso file: %i:%s", errno, strerror(errno)); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + // return(-1); + + } // ENDIF- Error? Abort + + + + return(retval); // Send back how many bytes written + +} // END ActualFileWrite() + diff --git a/plugins/CDVDlinuz/Src/Linux/actualfile.h b/plugins/CDVDlinuz/Src/Linux/actualfile.h index a678b634d6..b7a72df55f 100644 --- a/plugins/CDVDlinuz/Src/Linux/actualfile.h +++ b/plugins/CDVDlinuz/Src/Linux/actualfile.h @@ -1,50 +1,100 @@ -/* actualfile.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef ACTUALFILE_H -#define ACTUALFILE_H - - -#include // off64_t - - -#define ACTUALHANDLE int -#define ACTUALHANDLENULL -1 - -// #define VERBOSE_FUNCTION_ACTUALFILE -// #define VERBOSE_WARNING_ACTUALFILE - - -extern int IsActualFile(const char *filename); -extern void ActualFileDelete(const char *filename); -extern void ActualFileRename(const char *origname, const char *newname); - -extern ACTUALHANDLE ActualFileOpenForRead(const char *filename); -extern off64_t ActualFileSize(ACTUALHANDLE handle); -extern int ActualFileSeek(ACTUALHANDLE handle, off64_t position); -extern int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer); -extern void ActualFileClose(ACTUALHANDLE handle); - -extern ACTUALHANDLE ActualFileOpenForWrite(const char *filename); -extern int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer); - - -#endif /* ACTUALFILE_H */ +/* actualfile.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef ACTUALFILE_H + +#define ACTUALFILE_H + + + + + +#include // off64_t + + + + + +#define ACTUALHANDLE int + +#define ACTUALHANDLENULL -1 + + + +// #define VERBOSE_FUNCTION_ACTUALFILE + +// #define VERBOSE_WARNING_ACTUALFILE + + + + + +extern int IsActualFile(const char *filename); + +extern void ActualFileDelete(const char *filename); + +extern void ActualFileRename(const char *origname, const char *newname); + + + +extern ACTUALHANDLE ActualFileOpenForRead(const char *filename); + +extern off64_t ActualFileSize(ACTUALHANDLE handle); + +extern int ActualFileSeek(ACTUALHANDLE handle, off64_t position); + +extern int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer); + +extern void ActualFileClose(ACTUALHANDLE handle); + + + +extern ACTUALHANDLE ActualFileOpenForWrite(const char *filename); + +extern int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer); + + + + + +#endif /* ACTUALFILE_H */ + diff --git a/plugins/CDVDlinuz/Src/Linux/conf.c b/plugins/CDVDlinuz/Src/Linux/conf.c index 330af46023..6183a871d1 100644 --- a/plugins/CDVDlinuz/Src/Linux/conf.c +++ b/plugins/CDVDlinuz/Src/Linux/conf.c @@ -1,184 +1,184 @@ /* conf.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - -#include // errno -#include // NULL -#include // sprintf() -#include // getenv() -#include // strerror() -#include // mkdir(), stat() -#include // mkdir(), stat() -#include // stat() - -// #define CDVDdefs -// #include "../PS2Edefs.h" -#include "logfile.h" -#include "../ini.h" -#include "conf.h" - - -const char *cfgname[] = { \ - "./cfg/cfgCDVDlinuz", \ - "../cfg/cfgCDVDlinuz", \ - "./plugins/cfgCDVDlinuz", \ - "../plugins/cfgCDVDlinuz", \ - "./cfgCDVDlinuz", \ - "../cfgCDVDlinuz", \ - NULL }; - -const char *confnames[] = { "Device", NULL }; -const u8 defaultdevice[] = DEFAULT_DEVICE; -const char defaulthome[] = "../inis"; -const char defaultdirectory[] = ".PS2E"; -const char defaultfile[] = "CDVDlinuz.ini"; - -char confdirname[256]; -char conffilename[256]; - -CDVDconf conf; - - -void ExecCfg(char *arg) { - int nameptr; - struct stat filestat; - char templine[256]; - -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVDiso interface: ExecCfg(%s)", arg); -#endif /* VERBOSE FUNCTION_CONF */ - errno = 0; - nameptr = 0; - while((cfgname[nameptr] != NULL) && - (stat(cfgname[nameptr], &filestat) == -1)) nameptr++; - errno = 0; - - if(cfgname[nameptr] == NULL) { -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVDiso interface: Couldn't find configuration program!"); -#endif /* VERBOSE_FUNCTION_CONF */ - return; - } // ENDIF- Did not find the executable? - - sprintf(templine, "%s %s", cfgname[nameptr], arg); - system(templine); -} // END ExecCfg() - - -void InitConf() { - int i; - int pos; - char *envptr; - -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVD config: InitConf()"); -#endif /* VERBOSE_FUNCTION_CONF */ - - i = 0; - while((i < 255) && defaultdevice[i] != 0) { - conf.devicename[i] = defaultdevice[i]; - i++; - } // ENDWHILE- copying the default CD/DVD name in - conf.devicename[i] = 0; // 0-terminate the device name - - // Locating directory and file positions - pos = 0; - envptr = getenv("HOME"); - if(envptr == NULL) { - // = - i = 0; - while((pos < 253) && (defaulthome[i] != 0)) { - confdirname[pos] = defaulthome[i]; - conffilename[pos] = defaulthome[i]; - pos++; - i++; - } // NEXT- putting a default place to store configuration data - - } else { - // = / - i = 0; - while((pos < 253) && (*(envptr + i) != 0)) { - confdirname[pos] = *(envptr + i); - conffilename[pos] = *(envptr + i); - pos++; - i++; - } // ENDWHILE- copying home directory info in - - if(confdirname[pos-1] != '/') { - confdirname[pos] = '/'; - conffilename[pos] = '/'; - pos++; - } // ENDIF- No directory separator here? Add one. - - i = 0; - while((pos < 253) && (defaultdirectory[i] != 0)) { - confdirname[pos] = defaultdirectory[i]; - conffilename[pos] = defaultdirectory[i]; - pos++; - i++; - } // NEXT- putting a default place to store configuration data - } // ENDIF- No Home directory? - - confdirname[pos] = 0; // Directory reference finished - - // += / - if(conffilename[pos-1] != '/') { - conffilename[pos] = '/'; - pos++; - } // ENDIF- No directory separator here? Add one. - - i = 0; - while((pos < 253) && (defaultfile[i] != 0)) { - conffilename[pos] = defaultfile[i]; - pos++; - i++; - } // NEXT- putting a default place to store configuration data - - conffilename[pos] = 0; // File reference finished - -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVD config: Directory: %s\n", confdirname); - PrintLog("CDVD config: File: %s\n", conffilename); -#endif /* VERBOSE_FUNCTION_CONF */ -} // END InitConf() - - -void LoadConf() { - int retval; - -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVD config: LoadConf()\n"); -#endif /* VERBOSE_FUNCTION_CONF */ - - retval = INILoadString(conffilename, "Settings", "Device", conf.devicename); - if(retval < 0) { - sprintf(conf.devicename, "/dev/dvd"); - } // ENDIF- Couldn't find keyword? Fill in a default -} // END LoadConf() - - -void SaveConf() { -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVD config: SaveConf()\n"); -#endif /* VERBOSE_FUNCTION_CONF */ - - mkdir(confdirname, 0755); - - INISaveString(conffilename, "Settings", "Device", conf.devicename); -} // END SaveConf() + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * PCSX2 members can be contacted through their website at www.pcsx2.net. + */ + +#include // errno +#include // NULL +#include // sprintf() +#include // getenv() +#include // strerror() +#include // mkdir(), stat() +#include // mkdir(), stat() +#include // stat() + +// #define CDVDdefs +// #include "../PS2Edefs.h" +#include "logfile.h" +#include "../ini.h" +#include "conf.h" + + +const char *cfgname[] = { \ + "./cfg/cfgCDVDlinuz", \ + "../cfg/cfgCDVDlinuz", \ + "./plugins/cfgCDVDlinuz", \ + "../plugins/cfgCDVDlinuz", \ + "./cfgCDVDlinuz", \ + "../cfgCDVDlinuz", \ + NULL }; + +const char *confnames[] = { "Device", NULL }; +const u8 defaultdevice[] = DEFAULT_DEVICE; +const char defaulthome[] = "../inis"; +const char defaultdirectory[] = ".PS2E"; +const char defaultfile[] = "CDVDlinuz.ini"; + +char confdirname[256]; +char conffilename[256]; + +CDVDconf conf; + + +void ExecCfg(char *arg) { + int nameptr; + struct stat filestat; + char templine[256]; + +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVDiso interface: ExecCfg(%s)", arg); +#endif /* VERBOSE FUNCTION_CONF */ + errno = 0; + nameptr = 0; + while((cfgname[nameptr] != NULL) && + (stat(cfgname[nameptr], &filestat) == -1)) nameptr++; + errno = 0; + + if(cfgname[nameptr] == NULL) { +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVDiso interface: Couldn't find configuration program!"); +#endif /* VERBOSE_FUNCTION_CONF */ + return; + } // ENDIF- Did not find the executable? + + sprintf(templine, "%s %s", cfgname[nameptr], arg); + system(templine); +} // END ExecCfg() + + +void InitConf() { + int i; + int pos; + char *envptr; + +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: InitConf()"); +#endif /* VERBOSE_FUNCTION_CONF */ + + i = 0; + while((i < 255) && defaultdevice[i] != 0) { + conf.devicename[i] = defaultdevice[i]; + i++; + } // ENDWHILE- copying the default CD/DVD name in + conf.devicename[i] = 0; // 0-terminate the device name + + // Locating directory and file positions + pos = 0; + envptr = getenv("HOME"); + if(envptr == NULL) { + // = + i = 0; + while((pos < 253) && (defaulthome[i] != 0)) { + confdirname[pos] = defaulthome[i]; + conffilename[pos] = defaulthome[i]; + pos++; + i++; + } // NEXT- putting a default place to store configuration data + + } else { + // = / + i = 0; + while((pos < 253) && (*(envptr + i) != 0)) { + confdirname[pos] = *(envptr + i); + conffilename[pos] = *(envptr + i); + pos++; + i++; + } // ENDWHILE- copying home directory info in + + if(confdirname[pos-1] != '/') { + confdirname[pos] = '/'; + conffilename[pos] = '/'; + pos++; + } // ENDIF- No directory separator here? Add one. + + i = 0; + while((pos < 253) && (defaultdirectory[i] != 0)) { + confdirname[pos] = defaultdirectory[i]; + conffilename[pos] = defaultdirectory[i]; + pos++; + i++; + } // NEXT- putting a default place to store configuration data + } // ENDIF- No Home directory? + + confdirname[pos] = 0; // Directory reference finished + + // += / + if(conffilename[pos-1] != '/') { + conffilename[pos] = '/'; + pos++; + } // ENDIF- No directory separator here? Add one. + + i = 0; + while((pos < 253) && (defaultfile[i] != 0)) { + conffilename[pos] = defaultfile[i]; + pos++; + i++; + } // NEXT- putting a default place to store configuration data + + conffilename[pos] = 0; // File reference finished + +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: Directory: %s\n", confdirname); + PrintLog("CDVD config: File: %s\n", conffilename); +#endif /* VERBOSE_FUNCTION_CONF */ +} // END InitConf() + + +void LoadConf() { + int retval; + +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: LoadConf()\n"); +#endif /* VERBOSE_FUNCTION_CONF */ + + retval = INILoadString(conffilename, "Settings", "Device", conf.devicename); + if(retval < 0) { + sprintf(conf.devicename, "/dev/dvd"); + } // ENDIF- Couldn't find keyword? Fill in a default +} // END LoadConf() + + +void SaveConf() { +#ifdef VERBOSE_FUNCTION_CONF + PrintLog("CDVD config: SaveConf()\n"); +#endif /* VERBOSE_FUNCTION_CONF */ + + mkdir(confdirname, 0755); + + INISaveString(conffilename, "Settings", "Device", conf.devicename); +} // END SaveConf() diff --git a/plugins/CDVDlinuz/Src/Linux/conf.h b/plugins/CDVDlinuz/Src/Linux/conf.h index b66dfd05c1..eb892b0345 100644 --- a/plugins/CDVDlinuz/Src/Linux/conf.h +++ b/plugins/CDVDlinuz/Src/Linux/conf.h @@ -1,57 +1,114 @@ -/* conf.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - -#ifndef CONF_H -#define CONF_H - - -#ifndef __LINUX__ -#ifdef __linux__ -#define __LINUX__ -#endif /* __linux__ */ -#endif /* No __LINUX__ */ - -#define CDVDdefs -#include "../PS2Edefs.h" - - -#define VERBOSE_FUNCTION_CONF - - -// Configuration Data - -typedef struct { - u8 devicename[256]; -} CDVDconf; -extern CDVDconf conf; - -#define DEFAULT_DEVICE "/dev/cdrom" - - -// Configuration Functions - -extern void InitConf(); -extern void LoadConf(); -extern void SaveConf(); - -extern void ExecCfg(char *arg); - - -#endif /* CONF_H */ +/* conf.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + +#ifndef CONF_H + +#define CONF_H + + + + + +#ifndef __LINUX__ + +#ifdef __linux__ + +#define __LINUX__ + +#endif /* __linux__ */ + +#endif /* No __LINUX__ */ + + + +#define CDVDdefs + +#include "../PS2Edefs.h" + + + + + +#define VERBOSE_FUNCTION_CONF + + + + + +// Configuration Data + + + +typedef struct { + + u8 devicename[256]; + +} CDVDconf; + +extern CDVDconf conf; + + + +#define DEFAULT_DEVICE "/dev/cdrom" + + + + + +// Configuration Functions + + + +extern void InitConf(); + +extern void LoadConf(); + +extern void SaveConf(); + + + +extern void ExecCfg(char *arg); + + + + + +#endif /* CONF_H */ + diff --git a/plugins/CDVDlinuz/Src/Linux/device.h b/plugins/CDVDlinuz/Src/Linux/device.h index 0d0d8ffe49..ec38e857a5 100644 --- a/plugins/CDVDlinuz/Src/Linux/device.h +++ b/plugins/CDVDlinuz/Src/Linux/device.h @@ -1,69 +1,138 @@ -/* device.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - -#ifndef __DEVICE_H__ -#define __DEVICE_H__ - - -#include // time_t - -#ifndef __LINUX__ -#ifdef __linux__ -#define __LINUX__ -#endif /* __linux__ */ -#endif /* No __LINUX__ */ -#define CDVDdefs -#include "../PS2Edefs.h" - - -// #define VERBOSE_FUNCTION_DEVICE -// #define VERBOSE_WARNINGS -#define VERBOSE_DISC_TYPE -#define VERBOSE_DISC_INFO - - -// Device Data - -extern int devicehandle; -extern s32 devicecapability; // Need to export? - -extern time_t lasttime; -extern s32 traystatus; -extern s32 disctype; -extern u8 tocbuffer[]; - - -// Device Functions - -extern void DeviceInit(); -extern void InitDisc(); -extern s32 DiscInserted(); -extern s32 DeviceOpen(); -extern void DeviceClose(); -extern s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer); -extern s32 DeviceBufferOffset(); -extern s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd); -extern s32 DeviceGetDiskType(); -extern s32 DeviceTrayStatus(); -extern s32 DeviceTrayOpen(); -extern s32 DeviceTrayClose(); - - -#endif /* __DEVICE_H__ */ +/* device.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + +#ifndef __DEVICE_H__ + +#define __DEVICE_H__ + + + + + +#include // time_t + + + +#ifndef __LINUX__ + +#ifdef __linux__ + +#define __LINUX__ + +#endif /* __linux__ */ + +#endif /* No __LINUX__ */ + +#define CDVDdefs + +#include "../PS2Edefs.h" + + + + + +// #define VERBOSE_FUNCTION_DEVICE + +// #define VERBOSE_WARNINGS + +#define VERBOSE_DISC_TYPE + +#define VERBOSE_DISC_INFO + + + + + +// Device Data + + + +extern int devicehandle; + +extern s32 devicecapability; // Need to export? + + + +extern time_t lasttime; + +extern s32 traystatus; + +extern s32 disctype; + +extern u8 tocbuffer[]; + + + + + +// Device Functions + + + +extern void DeviceInit(); + +extern void InitDisc(); + +extern s32 DiscInserted(); + +extern s32 DeviceOpen(); + +extern void DeviceClose(); + +extern s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer); + +extern s32 DeviceBufferOffset(); + +extern s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd); + +extern s32 DeviceGetDiskType(); + +extern s32 DeviceTrayStatus(); + +extern s32 DeviceTrayOpen(); + +extern s32 DeviceTrayClose(); + + + + + +#endif /* __DEVICE_H__ */ + diff --git a/plugins/CDVDlinuz/Src/Linux/interface.c b/plugins/CDVDlinuz/Src/Linux/interface.c index 5a354d9808..006c623350 100644 --- a/plugins/CDVDlinuz/Src/Linux/interface.c +++ b/plugins/CDVDlinuz/Src/Linux/interface.c @@ -1,57 +1,114 @@ -/* interface.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // NULL -#include // sprintf() -#include // strcmp() - -#include // gtk_init(), gtk_main(), gtk_main_quit() -#include // gtk_widget_show_all() - -#include "logfile.h" -#include "conf.h" -#include "aboutbox.h" -#include "mainbox.h" - - -int main(int argc, char *argv[]) { - if(argc != 2) return(1); - - gtk_init(NULL, NULL); - - if(!strcmp(argv[1], "about")) { - AboutBoxDisplay(); - return(0); - - } else if (!strcmp(argv[1], "configure")) { - OpenLog(); - InitConf(); - LoadConf(); - MainBoxDisplay(); - - gtk_widget_show_all(mainbox.window); - gtk_main(); - CloseLog(); - return(0); - } // ENDLONGIF- Which display would you like to see? - - return(1); // No Displays chosen? Abort! -} // END main() +/* interface.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // sprintf() + +#include // strcmp() + + + +#include // gtk_init(), gtk_main(), gtk_main_quit() + +#include // gtk_widget_show_all() + + + +#include "logfile.h" + +#include "conf.h" + +#include "aboutbox.h" + +#include "mainbox.h" + + + + + +int main(int argc, char *argv[]) { + + if(argc != 2) return(1); + + + + gtk_init(NULL, NULL); + + + + if(!strcmp(argv[1], "about")) { + + AboutBoxDisplay(); + + return(0); + + + + } else if (!strcmp(argv[1], "configure")) { + + OpenLog(); + + InitConf(); + + LoadConf(); + + MainBoxDisplay(); + + + + gtk_widget_show_all(mainbox.window); + + gtk_main(); + + CloseLog(); + + return(0); + + } // ENDLONGIF- Which display would you like to see? + + + + return(1); // No Displays chosen? Abort! + +} // END main() + diff --git a/plugins/CDVDlinuz/Src/Linux/logfile.c b/plugins/CDVDlinuz/Src/Linux/logfile.c index 27c6fe879b..8fe86e3c51 100644 --- a/plugins/CDVDlinuz/Src/Linux/logfile.c +++ b/plugins/CDVDlinuz/Src/Linux/logfile.c @@ -1,90 +1,180 @@ -/* logfile.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // open -#include // vsprintf() -#include // va_start(), va_end(), vsprintf() -#include // mkdir(), open() -#include // mkdir(), open() -#include // close(), write(), unlink() - -#include "logfile.h" - - -int logfile; -char logfiletemp[2048]; - - -void InitLog() { - // Token comment line -#ifdef VERBOSE_LOGFILE - mkdir("./logs", 0755); - - unlink("./logs/CDVDlog.txt"); -#endif /* VERBOSE LOGFILE */ -} // END InitLog(); - - -int OpenLog() { - // Token comment line -#ifdef VERBOSE_LOGFILE - logfile = -1; - logfile = open("./logs/CDVDlog.txt", O_WRONLY | O_CREAT | O_APPEND, 0755); - if(logfile == -1) return(-1); -#endif /* VERBOSE LOGFILE */ - - return(0); -} // END OpenLog(); - - -void CloseLog() { - // Token comment line -#ifdef VERBOSE_LOGFILE - if(logfile != -1) { - close(logfile); - logfile = -1; - } // ENDIF- Is the log file actually open? Close it. -#endif /* VERBOSE LOGFILE */ -} // END CloseLog() - - -void PrintLog(const char *fmt, ...) { - // Token comment line -#ifdef VERBOSE_LOGFILE - va_list list; - int len; - - if(logfile == -1) return; // Log file not open. - - va_start(list, fmt); - vsprintf(logfiletemp, fmt, list); - va_end(list); - - len = 0; - while((len < 2048) && (logfiletemp[len] != 0)) len++; - if((len > 0) && (logfiletemp[len-1] == '\n')) len--; - if((len > 0) && (logfiletemp[len-1] == '\r')) len--; - logfiletemp[len] = 0; // Slice off the last "\r\n"... - - write(logfile, logfiletemp, len); - write(logfile, "\r\n", 2); // ... and write out your own. -#endif /* VERBOSE LOGFILE */ -} // END PrintLog() +/* logfile.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // open + +#include // vsprintf() + +#include // va_start(), va_end(), vsprintf() + +#include // mkdir(), open() + +#include // mkdir(), open() + +#include // close(), write(), unlink() + + + +#include "logfile.h" + + + + + +int logfile; + +char logfiletemp[2048]; + + + + + +void InitLog() { + + // Token comment line + +#ifdef VERBOSE_LOGFILE + + mkdir("./logs", 0755); + + + + unlink("./logs/CDVDlog.txt"); + +#endif /* VERBOSE LOGFILE */ + +} // END InitLog(); + + + + + +int OpenLog() { + + // Token comment line + +#ifdef VERBOSE_LOGFILE + + logfile = -1; + + logfile = open("./logs/CDVDlog.txt", O_WRONLY | O_CREAT | O_APPEND, 0755); + + if(logfile == -1) return(-1); + +#endif /* VERBOSE LOGFILE */ + + + + return(0); + +} // END OpenLog(); + + + + + +void CloseLog() { + + // Token comment line + +#ifdef VERBOSE_LOGFILE + + if(logfile != -1) { + + close(logfile); + + logfile = -1; + + } // ENDIF- Is the log file actually open? Close it. + +#endif /* VERBOSE LOGFILE */ + +} // END CloseLog() + + + + + +void PrintLog(const char *fmt, ...) { + + // Token comment line + +#ifdef VERBOSE_LOGFILE + + va_list list; + + int len; + + + + if(logfile == -1) return; // Log file not open. + + + + va_start(list, fmt); + + vsprintf(logfiletemp, fmt, list); + + va_end(list); + + + + len = 0; + + while((len < 2048) && (logfiletemp[len] != 0)) len++; + + if((len > 0) && (logfiletemp[len-1] == '\n')) len--; + + if((len > 0) && (logfiletemp[len-1] == '\r')) len--; + + logfiletemp[len] = 0; // Slice off the last "\r\n"... + + + + write(logfile, logfiletemp, len); + + write(logfile, "\r\n", 2); // ... and write out your own. + +#endif /* VERBOSE LOGFILE */ + +} // END PrintLog() + diff --git a/plugins/CDVDlinuz/Src/Linux/logfile.h b/plugins/CDVDlinuz/Src/Linux/logfile.h index 8cee990080..19d32fd3ab 100644 --- a/plugins/CDVDlinuz/Src/Linux/logfile.h +++ b/plugins/CDVDlinuz/Src/Linux/logfile.h @@ -1,35 +1,70 @@ -/* logfile.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef LOGFILE_H -#define LOGFILE_H - - -#define VERBOSE_LOGFILE - - -extern void InitLog(); -extern int OpenLog(); -extern void CloseLog(); -extern void PrintLog(const char *format, ...); - - -#endif /* LOGFILE_H */ +/* logfile.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef LOGFILE_H + +#define LOGFILE_H + + + + + +#define VERBOSE_LOGFILE + + + + + +extern void InitLog(); + +extern int OpenLog(); + +extern void CloseLog(); + +extern void PrintLog(const char *format, ...); + + + + + +#endif /* LOGFILE_H */ + diff --git a/plugins/CDVDlinuz/Src/Linux/mainbox.c b/plugins/CDVDlinuz/Src/Linux/mainbox.c index c6423e21a6..89e39f1ddf 100644 --- a/plugins/CDVDlinuz/Src/Linux/mainbox.c +++ b/plugins/CDVDlinuz/Src/Linux/mainbox.c @@ -1,187 +1,374 @@ -/* mainbox.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // NULL -#include // sprintf() -#include // strcpy() -#include // stat() -#include // stat() -#include // stat() - -#include // gtk_button_new_with_label() -#include // gtk_container_add() -#include // gtk_entry_new() -#include // gtk_hbutton_box_new() -#include // gtk_hbox_new() -#include // gtk_label_new() -#include // gtk_init(), gtk_main(), gtk_main_quit() -#include // gtk_vbox_new() -#include // gtk_window_new() - -#include "conf.h" -// #include "logfile.h" -#include "device.h" // DeviceOpen(), DeviceClose() -#include "mainbox.h" - - -struct MainBoxData mainbox; - - -void MainBoxDestroy() { - if(mainbox.window != NULL) { - gtk_widget_destroy(mainbox.window); - mainbox.window = NULL; - mainbox.device = NULL; - mainbox.desc = NULL; - } // ENDIF- Do we have a Main Window still? -} // END MainBoxDestroy() - - -void MainBoxUnfocus() { - gtk_widget_set_sensitive(mainbox.device, FALSE); - gtk_window_iconify(GTK_WINDOW(mainbox.window)); -} // END MainBoxUnfocus() - - -gint MainBoxDeviceEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - struct stat filestat; - int retval; - - retval = stat(gtk_entry_get_text(GTK_ENTRY(mainbox.device)), &filestat); - if(retval == -1) { - gtk_label_set_text(GTK_LABEL(mainbox.desc), "Device Type: ---"); - return(TRUE); - } // ENDIF- Not a name of any sort? - - if(S_ISDIR(filestat.st_mode) != 0) { - gtk_label_set_text(GTK_LABEL(mainbox.desc), "Device Type: Not a device"); - return(TRUE); - } // ENDIF- Not a regular file? - - gtk_label_set_text(GTK_LABEL(mainbox.desc), "Device Type: Device Likely"); - return(TRUE); -} // END MainBoxFileEvent() - - -void MainBoxRefocus() { - GdkEvent event; - - MainBoxDeviceEvent(NULL, event, NULL); - - gtk_widget_set_sensitive(mainbox.device, TRUE); - gtk_window_set_focus(GTK_WINDOW(mainbox.window), mainbox.device); - gtk_window_deiconify(GTK_WINDOW(mainbox.window)); -} // END MainBoxRefocus() - - -gint MainBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - MainBoxDestroy(); - - gtk_main_quit(); - return(TRUE); -} // END MainBoxCancelEvent() - - -gint MainBoxOKEvent(GtkWidget *widget, GdkEvent event, gpointer data) { - const char *tempdevice; - int retval; - - MainBoxUnfocus(); - - tempdevice = gtk_entry_get_text(GTK_ENTRY(mainbox.device)); - strcpy(conf.devicename, tempdevice); // Temporarily put in new device name - tempdevice = NULL; - if(*(conf.devicename) != 0) { - retval = DeviceOpen(); // Test by opening the device. - DeviceClose(); // Failed or not, close it. - if(retval != 0) { - MainBoxRefocus(); - return(TRUE); - } // ENDIF- Not an ISO file? Message and Stop here. - } // ENDIF- Is there an ISO file to check out? - - SaveConf(); - - MainBoxCancelEvent(widget, event, data); - return(TRUE); -} // END MainBoxOKEvent() - - -void MainBoxDisplay() { - GtkWidget *item; - GtkWidget *hbox1; - GtkWidget *vbox1; - - mainbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_container_set_border_width(GTK_CONTAINER(mainbox.window), 5); - gtk_window_set_title(GTK_WINDOW(mainbox.window), "CDVDlinuz Configuration"); - gtk_window_set_position(GTK_WINDOW(mainbox.window), GTK_WIN_POS_CENTER); - - g_signal_connect(G_OBJECT(mainbox.window), "delete_event", - G_CALLBACK(MainBoxCancelEvent), NULL); - - vbox1 = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(mainbox.window), vbox1); - gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); - gtk_widget_show(vbox1); - - hbox1 = gtk_hbox_new(FALSE, 10); - gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); - gtk_widget_show(hbox1); - - item = gtk_label_new("CD/DVD Device:"); - gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); - gtk_widget_show(item); - item = NULL; - - mainbox.device = gtk_entry_new(); - gtk_box_pack_start(GTK_BOX(hbox1), mainbox.device, TRUE, TRUE, 0); - gtk_widget_show(mainbox.device); - g_signal_connect(G_OBJECT(mainbox.device), "changed", - G_CALLBACK(MainBoxDeviceEvent), NULL); - hbox1 = NULL; - - mainbox.desc = gtk_label_new("File Type: ---"); - gtk_box_pack_start(GTK_BOX(vbox1), mainbox.desc, FALSE, FALSE, 0); - gtk_widget_show(mainbox.desc); - - hbox1 = gtk_hbutton_box_new(); - gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); - gtk_widget_show(hbox1); - - item = gtk_button_new_with_label("Ok"); - gtk_box_pack_start(GTK_BOX(hbox1), item, TRUE, TRUE, 0); - gtk_widget_show(item); - g_signal_connect(G_OBJECT(item), "clicked", - G_CALLBACK(MainBoxOKEvent), NULL); - - item = gtk_button_new_with_label("Cancel"); - gtk_box_pack_start(GTK_BOX(hbox1), item, TRUE, TRUE, 0); - gtk_widget_show(item); - g_signal_connect(G_OBJECT(item), "clicked", - G_CALLBACK(MainBoxCancelEvent), NULL); - item = NULL; - hbox1 = NULL; - vbox1 = NULL; - - // We held off setting the name until now... so description would show. - gtk_entry_set_text(GTK_ENTRY(mainbox.device), conf.devicename); -} // END MainBoxDisplay() +/* mainbox.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // sprintf() + +#include // strcpy() + +#include // stat() + +#include // stat() + +#include // stat() + + + +#include // gtk_button_new_with_label() + +#include // gtk_container_add() + +#include // gtk_entry_new() + +#include // gtk_hbutton_box_new() + +#include // gtk_hbox_new() + +#include // gtk_label_new() + +#include // gtk_init(), gtk_main(), gtk_main_quit() + +#include // gtk_vbox_new() + +#include // gtk_window_new() + + + +#include "conf.h" + +// #include "logfile.h" + +#include "device.h" // DeviceOpen(), DeviceClose() + +#include "mainbox.h" + + + + + +struct MainBoxData mainbox; + + + + + +void MainBoxDestroy() { + + if(mainbox.window != NULL) { + + gtk_widget_destroy(mainbox.window); + + mainbox.window = NULL; + + mainbox.device = NULL; + + mainbox.desc = NULL; + + } // ENDIF- Do we have a Main Window still? + +} // END MainBoxDestroy() + + + + + +void MainBoxUnfocus() { + + gtk_widget_set_sensitive(mainbox.device, FALSE); + + gtk_window_iconify(GTK_WINDOW(mainbox.window)); + +} // END MainBoxUnfocus() + + + + + +gint MainBoxDeviceEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + struct stat filestat; + + int retval; + + + + retval = stat(gtk_entry_get_text(GTK_ENTRY(mainbox.device)), &filestat); + + if(retval == -1) { + + gtk_label_set_text(GTK_LABEL(mainbox.desc), "Device Type: ---"); + + return(TRUE); + + } // ENDIF- Not a name of any sort? + + + + if(S_ISDIR(filestat.st_mode) != 0) { + + gtk_label_set_text(GTK_LABEL(mainbox.desc), "Device Type: Not a device"); + + return(TRUE); + + } // ENDIF- Not a regular file? + + + + gtk_label_set_text(GTK_LABEL(mainbox.desc), "Device Type: Device Likely"); + + return(TRUE); + +} // END MainBoxFileEvent() + + + + + +void MainBoxRefocus() { + + GdkEvent event; + + + + MainBoxDeviceEvent(NULL, event, NULL); + + + + gtk_widget_set_sensitive(mainbox.device, TRUE); + + gtk_window_set_focus(GTK_WINDOW(mainbox.window), mainbox.device); + + gtk_window_deiconify(GTK_WINDOW(mainbox.window)); + +} // END MainBoxRefocus() + + + + + +gint MainBoxCancelEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + MainBoxDestroy(); + + + + gtk_main_quit(); + + return(TRUE); + +} // END MainBoxCancelEvent() + + + + + +gint MainBoxOKEvent(GtkWidget *widget, GdkEvent event, gpointer data) { + + const char *tempdevice; + + int retval; + + + + MainBoxUnfocus(); + + + + tempdevice = gtk_entry_get_text(GTK_ENTRY(mainbox.device)); + + strcpy(conf.devicename, tempdevice); // Temporarily put in new device name + + tempdevice = NULL; + + if(*(conf.devicename) != 0) { + + retval = DeviceOpen(); // Test by opening the device. + + DeviceClose(); // Failed or not, close it. + + if(retval != 0) { + + MainBoxRefocus(); + + return(TRUE); + + } // ENDIF- Not an ISO file? Message and Stop here. + + } // ENDIF- Is there an ISO file to check out? + + + + SaveConf(); + + + + MainBoxCancelEvent(widget, event, data); + + return(TRUE); + +} // END MainBoxOKEvent() + + + + + +void MainBoxDisplay() { + + GtkWidget *item; + + GtkWidget *hbox1; + + GtkWidget *vbox1; + + + + mainbox.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + gtk_container_set_border_width(GTK_CONTAINER(mainbox.window), 5); + + gtk_window_set_title(GTK_WINDOW(mainbox.window), "CDVDlinuz Configuration"); + + gtk_window_set_position(GTK_WINDOW(mainbox.window), GTK_WIN_POS_CENTER); + + + + g_signal_connect(G_OBJECT(mainbox.window), "delete_event", + + G_CALLBACK(MainBoxCancelEvent), NULL); + + + + vbox1 = gtk_vbox_new(FALSE, 5); + + gtk_container_add(GTK_CONTAINER(mainbox.window), vbox1); + + gtk_container_set_border_width(GTK_CONTAINER(vbox1), 5); + + gtk_widget_show(vbox1); + + + + hbox1 = gtk_hbox_new(FALSE, 10); + + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + + gtk_widget_show(hbox1); + + + + item = gtk_label_new("CD/DVD Device:"); + + gtk_box_pack_start(GTK_BOX(hbox1), item, FALSE, FALSE, 0); + + gtk_widget_show(item); + + item = NULL; + + + + mainbox.device = gtk_entry_new(); + + gtk_box_pack_start(GTK_BOX(hbox1), mainbox.device, TRUE, TRUE, 0); + + gtk_widget_show(mainbox.device); + + g_signal_connect(G_OBJECT(mainbox.device), "changed", + + G_CALLBACK(MainBoxDeviceEvent), NULL); + + hbox1 = NULL; + + + + mainbox.desc = gtk_label_new("File Type: ---"); + + gtk_box_pack_start(GTK_BOX(vbox1), mainbox.desc, FALSE, FALSE, 0); + + gtk_widget_show(mainbox.desc); + + + + hbox1 = gtk_hbutton_box_new(); + + gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); + + gtk_widget_show(hbox1); + + + + item = gtk_button_new_with_label("Ok"); + + gtk_box_pack_start(GTK_BOX(hbox1), item, TRUE, TRUE, 0); + + gtk_widget_show(item); + + g_signal_connect(G_OBJECT(item), "clicked", + + G_CALLBACK(MainBoxOKEvent), NULL); + + + + item = gtk_button_new_with_label("Cancel"); + + gtk_box_pack_start(GTK_BOX(hbox1), item, TRUE, TRUE, 0); + + gtk_widget_show(item); + + g_signal_connect(G_OBJECT(item), "clicked", + + G_CALLBACK(MainBoxCancelEvent), NULL); + + item = NULL; + + hbox1 = NULL; + + vbox1 = NULL; + + + + // We held off setting the name until now... so description would show. + + gtk_entry_set_text(GTK_ENTRY(mainbox.device), conf.devicename); + +} // END MainBoxDisplay() + diff --git a/plugins/CDVDlinuz/Src/Linux/mainbox.h b/plugins/CDVDlinuz/Src/Linux/mainbox.h index c862063ee1..2c0aa24a01 100644 --- a/plugins/CDVDlinuz/Src/Linux/mainbox.h +++ b/plugins/CDVDlinuz/Src/Linux/mainbox.h @@ -1,41 +1,82 @@ -/* mainbox.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef MAINBOX_H -#define MAINBOX_H - - -#include - - -struct MainBoxData { - GtkWidget *window; // GtkWindow - GtkWidget *device; // GtkEntry - GtkWidget *desc; // GtkLabel -}; - -extern struct MainBoxData mainbox; - -// extern void MainBoxRefocus(); -extern void MainBoxDisplay(); - - -#endif /* MAINBOX_H */ +/* mainbox.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef MAINBOX_H + +#define MAINBOX_H + + + + + +#include + + + + + +struct MainBoxData { + + GtkWidget *window; // GtkWindow + + GtkWidget *device; // GtkEntry + + GtkWidget *desc; // GtkLabel + +}; + + + +extern struct MainBoxData mainbox; + + + +// extern void MainBoxRefocus(); + +extern void MainBoxDisplay(); + + + + + +#endif /* MAINBOX_H */ + diff --git a/plugins/CDVDlinuz/Src/PS2Edefs.h b/plugins/CDVDlinuz/Src/PS2Edefs.h index ef33df3686..9cdf8a147f 100644 --- a/plugins/CDVDlinuz/Src/PS2Edefs.h +++ b/plugins/CDVDlinuz/Src/PS2Edefs.h @@ -1,812 +1,812 @@ -#ifndef __PS2EDEFS_H__ -#define __PS2EDEFS_H__ - -/* - * PS2E Definitions v0.6.2 (beta) - * - * Author: linuzappz@hotmail.com - * shadowpcsx2@yahoo.gr - * florinsasu@hotmail.com - */ - -/* - Notes: - * Since this is still beta things may change. - - * OSflags: - __LINUX__ (linux OS) - _WIN32 (win32 OS) - - * common return values (for ie. GSinit): - 0 - success - -1 - error - - * reserved keys: - F1 to F10 are reserved for the emulator - - * plugins should NOT change the current - working directory. - (on win32, add flag OFN_NOCHANGEDIR for - GetOpenFileName) - -*/ - -#include "PS2Etypes.h" - -#ifdef __LINUX__ -#define CALLBACK -#else -#include -#endif - - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ - defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ - defined(USBdefs) || defined(FWdefs) -#define COMMONdefs -#endif - -// PS2EgetLibType returns (may be OR'd) -#define PS2E_LT_GS 0x01 -#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- -#define PS2E_LT_SPU2 0x04 -#define PS2E_LT_CDVD 0x08 -#define PS2E_LT_DEV9 0x10 -#define PS2E_LT_USB 0x20 -#define PS2E_LT_FW 0x40 -#define PS2E_LT_SIO 0x80 - -// PS2EgetLibVersion2 (high 16 bits) -#define PS2E_GS_VERSION 0x0006 -#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- -#define PS2E_SPU2_VERSION 0x0005 -#define PS2E_CDVD_VERSION 0x0005 -#define PS2E_DEV9_VERSION 0x0003 -#define PS2E_USB_VERSION 0x0003 -#define PS2E_FW_VERSION 0x0002 -#define PS2E_SIO_VERSION 0x0001 -#ifdef COMMONdefs - -u32 CALLBACK PS2EgetLibType(void); -u32 CALLBACK PS2EgetLibVersion2(u32 type); -char* CALLBACK PS2EgetLibName(void); - -#endif - -// key values: -/* key values must be OS dependant: - win32: the VK_XXX will be used (WinUser) - linux: the XK_XXX will be used (XFree86) -*/ - -// event values: -#define KEYPRESS 1 -#define KEYRELEASE 2 - -typedef struct { - u32 key; - u32 event; -} keyEvent; - -// for 64bit compilers -typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; - -// plugin types -#define SIO_TYPE_PAD 0x00000001 -#define SIO_TYPE_MTAP 0x00000004 -#define SIO_TYPE_RM 0x00000040 -#define SIO_TYPE_MC 0x00000100 - -typedef int (CALLBACK * SIOchangeSlotCB)(int slot); - -typedef struct { - u8 ctrl:4; // control and mode bits - u8 mode:4; // control and mode bits - u8 trackNum; // current track number (1 to 99) - u8 trackIndex; // current index within track (0 to 99) - u8 trackM; // current minute location on the disc (BCD encoded) - u8 trackS; // current sector location on the disc (BCD encoded) - u8 trackF; // current frame location on the disc (BCD encoded) - u8 pad; // unused - u8 discM; // current minute offset from first track (BCD encoded) - u8 discS; // current sector offset from first track (BCD encoded) - u8 discF; // current frame offset from first track (BCD encoded) -} cdvdSubQ; - -typedef struct { // NOT bcd coded - u32 lsn; - u8 type; -} cdvdTD; - -typedef struct { - u8 strack; //number of the first track (usually 1) - u8 etrack; //number of the last track -} cdvdTN; - -// CDVDreadTrack mode values: -#define CDVD_MODE_2352 0 // full 2352 bytes -#define CDVD_MODE_2340 1 // skip sync (12) bytes -#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq - -// CDVDgetDiskType returns: -#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc -#define CDVD_TYPE_DVDV 0xfe // DVD Video -#define CDVD_TYPE_CDDA 0xfd // Audio CD -#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD -#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) -#define CDVD_TYPE_PS2CD 0x12 // PS2 CD -#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) -#define CDVD_TYPE_PSCD 0x10 // PS CD -#define CDVD_TYPE_UNKNOWN 0x05 // Unknown -#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided -#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided -#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd -#define CDVD_TYPE_DETCT 0x01 // Detecting -#define CDVD_TYPE_NODISC 0x00 // No Disc - -// CDVDgetTrayStatus returns: -#define CDVD_TRAY_CLOSE 0x00 -#define CDVD_TRAY_OPEN 0x01 - -// cdvdTD.type (track types for cds) -#define CDVD_AUDIO_TRACK 0x01 -#define CDVD_MODE1_TRACK 0x41 -#define CDVD_MODE2_TRACK 0x61 - -#define CDVD_AUDIO_MASK 0x00 -#define CDVD_DATA_MASK 0x40 -// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) - -typedef void (*DEV9callback)(int cycles); -typedef int (*DEV9handler)(void); - -typedef void (*USBcallback)(int cycles); -typedef int (*USBhandler)(void); - -// freeze modes: -#define FREEZE_LOAD 0 -#define FREEZE_SAVE 1 -#define FREEZE_SIZE 2 - -typedef struct { - char name[8]; - void *common; -} GSdriverInfo; - -#ifdef _WIN32 -typedef struct { // unsupported values must be set to zero - HWND hWnd; - HMENU hMenu; - HWND hStatusWnd; -} winInfo; -#endif - -/* GS plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef GSdefs - -// basic funcs - -s32 CALLBACK GSinit(); -s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); -void CALLBACK GSclose(); -void CALLBACK GSshutdown(); -void CALLBACK GSvsync(int field); -void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); -void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); -void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); -void CALLBACK GSgifSoftReset(u32 mask); -void CALLBACK GSreadFIFO(u64 *mem); -void CALLBACK GSreadFIFO2(u64 *mem, int qwc); - -// extended funcs - -// GSkeyEvent gets called when there is a keyEvent from the PAD plugin -void CALLBACK GSkeyEvent(keyEvent *ev); -void CALLBACK GSchangeSaveState(int, const char* filename); -void CALLBACK GSmakeSnapshot(char *path); -void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); -void CALLBACK GSirqCallback(void (*callback)()); -void CALLBACK GSprintf(int timeout, char *fmt, ...); -void CALLBACK GSsetBaseMem(void*); -void CALLBACK GSsetGameCRC(int); - -// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done -void CALLBACK GSsetFrameSkip(int frameskip); - -void CALLBACK GSreset(); -void CALLBACK GSwriteCSR(u32 value); -void CALLBACK GSgetDriverInfo(GSdriverInfo *info); -#ifdef _WIN32 -s32 CALLBACK GSsetWindowInfo(winInfo *info); -#endif -s32 CALLBACK GSfreeze(int mode, freezeData *data); -void CALLBACK GSconfigure(); -void CALLBACK GSabout(); -s32 CALLBACK GStest(); - -#endif - -/* PAD plugin API -=[ OBSOLETE ]=- */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef PADdefs - -// basic funcs - -s32 CALLBACK PADinit(u32 flags); -s32 CALLBACK PADopen(void *pDsp); -void CALLBACK PADclose(); -void CALLBACK PADshutdown(); -// PADkeyEvent is called every vsync (return NULL if no event) -keyEvent* CALLBACK PADkeyEvent(); -u8 CALLBACK PADstartPoll(int pad); -u8 CALLBACK PADpoll(u8 value); -// returns: 1 if supported pad1 -// 2 if supported pad2 -// 3 if both are supported -u32 CALLBACK PADquery(); - -// extended funcs - -void CALLBACK PADgsDriverInfo(GSdriverInfo *info); -void CALLBACK PADconfigure(); -void CALLBACK PADabout(); -s32 CALLBACK PADtest(); - -#endif - -/* SIO plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SIOdefs - -// basic funcs - -s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); -s32 CALLBACK SIOopen(void *pDsp); -void CALLBACK SIOclose(); -void CALLBACK SIOshutdown(); -u8 CALLBACK SIOstartPoll(u8 value); -u8 CALLBACK SIOpoll(u8 value); -// returns: SIO_TYPE_{PAD,MTAP,RM,MC} -u32 CALLBACK SIOquery(); - -// extended funcs - -void CALLBACK SIOconfigure(); -void CALLBACK SIOabout(); -s32 CALLBACK SIOtest(); - -#endif - -/* SPU2 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SPU2defs - -// basic funcs - -s32 CALLBACK SPU2init(); -s32 CALLBACK SPU2open(void *pDsp); -void CALLBACK SPU2close(); -void CALLBACK SPU2shutdown(); -void CALLBACK SPU2write(u32 mem, u16 value); -u16 CALLBACK SPU2read(u32 mem); -void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA4(); -void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); -void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA7(); -u32 CALLBACK SPU2ReadMemAddr(int core); -void CALLBACK SPU2WriteMemAddr(int core,u32 value); -void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); -// extended funcs - -void CALLBACK SPU2async(u32 cycles); -s32 CALLBACK SPU2freeze(int mode, freezeData *data); -void CALLBACK SPU2configure(); -void CALLBACK SPU2about(); -s32 CALLBACK SPU2test(); - -#endif - -/* CDVD plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef CDVDdefs - -// basic funcs - -s32 CALLBACK CDVDinit(); -s32 CALLBACK CDVDopen(const char* pTitleFilename); -void CALLBACK CDVDclose(); -void CALLBACK CDVDshutdown(); -s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); - -// return can be NULL (for async modes) -u8* CALLBACK CDVDgetBuffer(); - -s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) -s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information -s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type -s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc -s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx -s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx -s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray -s32 CALLBACK CDVDctrlTrayClose(); //close disc tray - -// extended funcs - -void CALLBACK CDVDconfigure(); -void CALLBACK CDVDabout(); -s32 CALLBACK CDVDtest(); -void CALLBACK CDVDnewDiskCB(void (*callback)()); - -#endif - -/* DEV9 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef DEV9defs - -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK DEV9init(); -s32 CALLBACK DEV9open(void *pDsp); -void CALLBACK DEV9close(); -void CALLBACK DEV9shutdown(); -u8 CALLBACK DEV9read8(u32 addr); -u16 CALLBACK DEV9read16(u32 addr); -u32 CALLBACK DEV9read32(u32 addr); -void CALLBACK DEV9write8(u32 addr, u8 value); -void CALLBACK DEV9write16(u32 addr, u16 value); -void CALLBACK DEV9write32(u32 addr, u32 value); -void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); -void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK DEV9irqCallback(DEV9callback callback); -DEV9handler CALLBACK DEV9irqHandler(void); - -// extended funcs - -s32 CALLBACK DEV9freeze(int mode, freezeData *data); -void CALLBACK DEV9configure(); -void CALLBACK DEV9about(); -s32 CALLBACK DEV9test(); - -#endif - -/* USB plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef USBdefs - -// basic funcs - -s32 CALLBACK USBinit(); -s32 CALLBACK USBopen(void *pDsp); -void CALLBACK USBclose(); -void CALLBACK USBshutdown(); -u8 CALLBACK USBread8(u32 addr); -u16 CALLBACK USBread16(u32 addr); -u32 CALLBACK USBread32(u32 addr); -void CALLBACK USBwrite8(u32 addr, u8 value); -void CALLBACK USBwrite16(u32 addr, u16 value); -void CALLBACK USBwrite32(u32 addr, u32 value); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK USBirqCallback(USBcallback callback); -USBhandler CALLBACK USBirqHandler(void); -void CALLBACK USBsetRAM(void *mem); - -// extended funcs - -s32 CALLBACK USBfreeze(int mode, freezeData *data); -void CALLBACK USBconfigure(); -void CALLBACK USBabout(); -s32 CALLBACK USBtest(); - -#endif - -/* FW plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef FWdefs -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK FWinit(); -s32 CALLBACK FWopen(void *pDsp); -void CALLBACK FWclose(); -void CALLBACK FWshutdown(); -u32 CALLBACK FWread32(u32 addr); -void CALLBACK FWwrite32(u32 addr, u32 value); -void CALLBACK FWirqCallback(void (*callback)()); - -// extended funcs - -s32 CALLBACK FWfreeze(int mode, freezeData *data); -void CALLBACK FWconfigure(); -void CALLBACK FWabout(); -s32 CALLBACK FWtest(); -#endif - -// might be useful for emulators -#ifdef PLUGINtypedefs - -typedef u32 (CALLBACK* _PS2EgetLibType)(void); -typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); -typedef char*(CALLBACK* _PS2EgetLibName)(void); - -// GS -// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _GSinit)(); -typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); -typedef void (CALLBACK* _GSclose)(); -typedef void (CALLBACK* _GSshutdown)(); -typedef void (CALLBACK* _GSvsync)(int field); -typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); -typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); -typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); -typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); - -typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); -typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); -typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); -typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); -typedef void (CALLBACK* _GSsetBaseMem)(void*); -typedef void (CALLBACK* _GSsetGameCRC)(int); -typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); -typedef void (CALLBACK* _GSreset)(); -typedef void (CALLBACK* _GSwriteCSR)(u32 value); -typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); -#ifdef _WIN32 -typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); -#endif -typedef void (CALLBACK* _GSmakeSnapshot)(char *path); -typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); -typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _GSconfigure)(); -typedef s32 (CALLBACK* _GStest)(); -typedef void (CALLBACK* _GSabout)(); - -// PAD -typedef s32 (CALLBACK* _PADinit)(u32 flags); -typedef s32 (CALLBACK* _PADopen)(void *pDsp); -typedef void (CALLBACK* _PADclose)(); -typedef void (CALLBACK* _PADshutdown)(); -typedef keyEvent* (CALLBACK* _PADkeyEvent)(); -typedef u8 (CALLBACK* _PADstartPoll)(int pad); -typedef u8 (CALLBACK* _PADpoll)(u8 value); -typedef u32 (CALLBACK* _PADquery)(); - -typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); -typedef void (CALLBACK* _PADconfigure)(); -typedef s32 (CALLBACK* _PADtest)(); -typedef void (CALLBACK* _PADabout)(); - -// SIO -typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); -typedef s32 (CALLBACK* _SIOopen)(void *pDsp); -typedef void (CALLBACK* _SIOclose)(); -typedef void (CALLBACK* _SIOshutdown)(); -typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); -typedef u8 (CALLBACK* _SIOpoll)(u8 value); -typedef u32 (CALLBACK* _SIOquery)(); - -typedef void (CALLBACK* _SIOconfigure)(); -typedef s32 (CALLBACK* _SIOtest)(); -typedef void (CALLBACK* _SIOabout)(); - -// SPU2 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _SPU2init)(); -typedef s32 (CALLBACK* _SPU2open)(void *pDsp); -typedef void (CALLBACK* _SPU2close)(); -typedef void (CALLBACK* _SPU2shutdown)(); -typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); -typedef u16 (CALLBACK* _SPU2read)(u32 mem); -typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA4)(); -typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA7)(); -typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); -typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); -typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); -typedef void (CALLBACK* _SPU2async)(u32 cycles); -typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _SPU2configure)(); -typedef s32 (CALLBACK* _SPU2test)(); -typedef void (CALLBACK* _SPU2about)(); - -// CDVD -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _CDVDinit)(); -typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); -typedef void (CALLBACK* _CDVDclose)(); -typedef void (CALLBACK* _CDVDshutdown)(); -typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); -typedef u8* (CALLBACK* _CDVDgetBuffer)(); -typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); -typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); -typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); -typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); -typedef s32 (CALLBACK* _CDVDgetDiskType)(); -typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); -typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); -typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); - -typedef void (CALLBACK* _CDVDconfigure)(); -typedef s32 (CALLBACK* _CDVDtest)(); -typedef void (CALLBACK* _CDVDabout)(); -typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); - -// DEV9 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _DEV9init)(); -typedef s32 (CALLBACK* _DEV9open)(void *pDsp); -typedef void (CALLBACK* _DEV9close)(); -typedef void (CALLBACK* _DEV9shutdown)(); -typedef u8 (CALLBACK* _DEV9read8)(u32 mem); -typedef u16 (CALLBACK* _DEV9read16)(u32 mem); -typedef u32 (CALLBACK* _DEV9read32)(u32 mem); -typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); -typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); -typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); -typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); -typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); - -typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _DEV9configure)(); -typedef s32 (CALLBACK* _DEV9test)(); -typedef void (CALLBACK* _DEV9about)(); - -// USB -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _USBinit)(); -typedef s32 (CALLBACK* _USBopen)(void *pDsp); -typedef void (CALLBACK* _USBclose)(); -typedef void (CALLBACK* _USBshutdown)(); -typedef u8 (CALLBACK* _USBread8)(u32 mem); -typedef u16 (CALLBACK* _USBread16)(u32 mem); -typedef u32 (CALLBACK* _USBread32)(u32 mem); -typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); -typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); -typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); -typedef USBhandler (CALLBACK* _USBirqHandler)(void); -typedef void (CALLBACK* _USBsetRAM)(void *mem); - -typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _USBconfigure)(); -typedef s32 (CALLBACK* _USBtest)(); -typedef void (CALLBACK* _USBabout)(); - -//FW -typedef s32 (CALLBACK* _FWinit)(); -typedef s32 (CALLBACK* _FWopen)(void *pDsp); -typedef void (CALLBACK* _FWclose)(); -typedef void (CALLBACK* _FWshutdown)(); -typedef u32 (CALLBACK* _FWread32)(u32 mem); -typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); - -typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _FWconfigure)(); -typedef s32 (CALLBACK* _FWtest)(); -typedef void (CALLBACK* _FWabout)(); - -#endif - -#ifdef PLUGINfuncs - -// GS -_GSinit GSinit; -_GSopen GSopen; -_GSclose GSclose; -_GSshutdown GSshutdown; -_GSvsync GSvsync; -_GSgifTransfer1 GSgifTransfer1; -_GSgifTransfer2 GSgifTransfer2; -_GSgifTransfer3 GSgifTransfer3; -_GSgifSoftReset GSgifSoftReset; -_GSreadFIFO GSreadFIFO; -_GSreadFIFO2 GSreadFIFO2; - -_GSkeyEvent GSkeyEvent; -_GSchangeSaveState GSchangeSaveState; -_GSmakeSnapshot GSmakeSnapshot; -_GSmakeSnapshot2 GSmakeSnapshot2; -_GSirqCallback GSirqCallback; -_GSprintf GSprintf; -_GSsetBaseMem GSsetBaseMem; -_GSsetGameCRC GSsetGameCRC; -_GSsetFrameSkip GSsetFrameSkip; -_GSreset GSreset; -_GSwriteCSR GSwriteCSR; -_GSgetDriverInfo GSgetDriverInfo; -#ifdef _WIN32 -_GSsetWindowInfo GSsetWindowInfo; -#endif -_GSfreeze GSfreeze; -_GSconfigure GSconfigure; -_GStest GStest; -_GSabout GSabout; - -// PAD1 -_PADinit PAD1init; -_PADopen PAD1open; -_PADclose PAD1close; -_PADshutdown PAD1shutdown; -_PADkeyEvent PAD1keyEvent; -_PADstartPoll PAD1startPoll; -_PADpoll PAD1poll; -_PADquery PAD1query; - -_PADgsDriverInfo PAD1gsDriverInfo; -_PADconfigure PAD1configure; -_PADtest PAD1test; -_PADabout PAD1about; - -// PAD2 -_PADinit PAD2init; -_PADopen PAD2open; -_PADclose PAD2close; -_PADshutdown PAD2shutdown; -_PADkeyEvent PAD2keyEvent; -_PADstartPoll PAD2startPoll; -_PADpoll PAD2poll; -_PADquery PAD2query; - -_PADgsDriverInfo PAD2gsDriverInfo; -_PADconfigure PAD2configure; -_PADtest PAD2test; -_PADabout PAD2about; - -// SIO[2] -_SIOinit SIOinit[2][9]; -_SIOopen SIOopen[2][9]; -_SIOclose SIOclose[2][9]; -_SIOshutdown SIOshutdown[2][9]; -_SIOstartPoll SIOstartPoll[2][9]; -_SIOpoll SIOpoll[2][9]; -_SIOquery SIOquery[2][9]; - -_SIOconfigure SIOconfigure[2][9]; -_SIOtest SIOtest[2][9]; -_SIOabout SIOabout[2][9]; - -// SPU2 -_SPU2init SPU2init; -_SPU2open SPU2open; -_SPU2close SPU2close; -_SPU2shutdown SPU2shutdown; -_SPU2write SPU2write; -_SPU2read SPU2read; -_SPU2readDMA4Mem SPU2readDMA4Mem; -_SPU2writeDMA4Mem SPU2writeDMA4Mem; -_SPU2interruptDMA4 SPU2interruptDMA4; -_SPU2readDMA7Mem SPU2readDMA7Mem; -_SPU2writeDMA7Mem SPU2writeDMA7Mem; -_SPU2interruptDMA7 SPU2interruptDMA7; -_SPU2ReadMemAddr SPU2ReadMemAddr; -_SPU2WriteMemAddr SPU2WriteMemAddr; -_SPU2irqCallback SPU2irqCallback; - -_SPU2async SPU2async; -_SPU2freeze SPU2freeze; -_SPU2configure SPU2configure; -_SPU2test SPU2test; -_SPU2about SPU2about; - -// CDVD -_CDVDinit CDVDinit; -_CDVDopen CDVDopen; -_CDVDclose CDVDclose; -_CDVDshutdown CDVDshutdown; -_CDVDreadTrack CDVDreadTrack; -_CDVDgetBuffer CDVDgetBuffer; -_CDVDreadSubQ CDVDreadSubQ; -_CDVDgetTN CDVDgetTN; -_CDVDgetTD CDVDgetTD; -_CDVDgetTOC CDVDgetTOC; -_CDVDgetDiskType CDVDgetDiskType; -_CDVDgetTrayStatus CDVDgetTrayStatus; -_CDVDctrlTrayOpen CDVDctrlTrayOpen; -_CDVDctrlTrayClose CDVDctrlTrayClose; - -_CDVDconfigure CDVDconfigure; -_CDVDtest CDVDtest; -_CDVDabout CDVDabout; -_CDVDnewDiskCB CDVDnewDiskCB; - -// DEV9 -_DEV9init DEV9init; -_DEV9open DEV9open; -_DEV9close DEV9close; -_DEV9shutdown DEV9shutdown; -_DEV9read8 DEV9read8; -_DEV9read16 DEV9read16; -_DEV9read32 DEV9read32; -_DEV9write8 DEV9write8; -_DEV9write16 DEV9write16; -_DEV9write32 DEV9write32; -_DEV9readDMA8Mem DEV9readDMA8Mem; -_DEV9writeDMA8Mem DEV9writeDMA8Mem; -_DEV9irqCallback DEV9irqCallback; -_DEV9irqHandler DEV9irqHandler; - -_DEV9configure DEV9configure; -_DEV9freeze DEV9freeze; -_DEV9test DEV9test; -_DEV9about DEV9about; - -// USB -_USBinit USBinit; -_USBopen USBopen; -_USBclose USBclose; -_USBshutdown USBshutdown; -_USBread8 USBread8; -_USBread16 USBread16; -_USBread32 USBread32; -_USBwrite8 USBwrite8; -_USBwrite16 USBwrite16; -_USBwrite32 USBwrite32; -_USBirqCallback USBirqCallback; -_USBirqHandler USBirqHandler; -_USBsetRAM USBsetRAM; - -_USBconfigure USBconfigure; -_USBfreeze USBfreeze; -_USBtest USBtest; -_USBabout USBabout; - -// FW -_FWinit FWinit; -_FWopen FWopen; -_FWclose FWclose; -_FWshutdown FWshutdown; -_FWread32 FWread32; -_FWwrite32 FWwrite32; -_FWirqCallback FWirqCallback; - -_FWconfigure FWconfigure; -_FWfreeze FWfreeze; -_FWtest FWtest; -_FWabout FWabout; -#endif - -#endif /* __PS2EDEFS_H__ */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/CDVDlinuz/Src/PS2Etypes.h b/plugins/CDVDlinuz/Src/PS2Etypes.h index 1d605708aa..4e59015022 100644 --- a/plugins/CDVDlinuz/Src/PS2Etypes.h +++ b/plugins/CDVDlinuz/Src/PS2Etypes.h @@ -1,43 +1,86 @@ -#ifndef __PS2ETYPES_H__ -#define __PS2ETYPES_H__ - -// Basic types -#if defined(__MSCW32__) - -typedef __int8 s8; -typedef __int16 s16; -typedef __int32 s32; -typedef __int64 s64; - -typedef unsigned __int8 u8; -typedef unsigned __int16 u16; -typedef unsigned __int32 u32; -typedef unsigned __int64 u64; - -#if defined(__x86_64__) -typedef u64 uptr; -#else -typedef u32 uptr; -#endif - -#elif defined(__LINUX__) || defined(__MINGW32__) - -typedef char s8; -typedef short s16; -typedef int s32; -typedef long long s64; - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long long u64; - -#if defined(__x86_64__) -typedef u64 uptr; -#else -typedef u32 uptr; -#endif - -#endif - -#endif /* __PS2ETYPES_H__ */ +#ifndef __PS2ETYPES_H__ + +#define __PS2ETYPES_H__ + + + +// Basic types + +#if defined(__MSCW32__) + + + +typedef __int8 s8; + +typedef __int16 s16; + +typedef __int32 s32; + +typedef __int64 s64; + + + +typedef unsigned __int8 u8; + +typedef unsigned __int16 u16; + +typedef unsigned __int32 u32; + +typedef unsigned __int64 u64; + + + +#if defined(__x86_64__) + +typedef u64 uptr; + +#else + +typedef u32 uptr; + +#endif + + + +#elif defined(__LINUX__) || defined(__MINGW32__) + + + +typedef char s8; + +typedef short s16; + +typedef int s32; + +typedef long long s64; + + + +typedef unsigned char u8; + +typedef unsigned short u16; + +typedef unsigned int u32; + +typedef unsigned long long u64; + + + +#if defined(__x86_64__) + +typedef u64 uptr; + +#else + +typedef u32 uptr; + +#endif + + + +#endif + + + +#endif /* __PS2ETYPES_H__ */ + diff --git a/plugins/CDVDlinuz/Src/Win32/CD.c b/plugins/CDVDlinuz/Src/Win32/CD.c index 24c64999b3..d70edb089b 100644 --- a/plugins/CDVDlinuz/Src/Win32/CD.c +++ b/plugins/CDVDlinuz/Src/Win32/CD.c @@ -1,387 +1,774 @@ -/* CD.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include -#include // IOCTL_CDROM... - -#include // off64_t - -#define CDVDdefs -#include "PS2Edefs.h" - -#include "logfile.h" -#include "../convert.h" // MSFtoLBA(), HEXTOBCD() -#include "actualfile.h" -#include "device.h" // tocbuffer[], FinishCommand() -#include "CD.h" - - -int actualcdmode; // -1=ReadFile, 0=YellowMode2, 1=XAForm2, 2=CDDA -DWORD cdblocksize; // 2048 to 2352 -int cdoffset; // 0, 8, 16, or 24 -int cdmode; - - -void InitCDInfo() { - actualcdmode = -1; - cdblocksize = 2048; - cdmode = -1; -} // END InitCDInfo() - - -s32 CDreadTrackPass(u32 lsn, int mode, u8 *buffer) { - RAW_READ_INFO rawinfo; - BOOL boolresult; - DWORD byteswritten; - DWORD errcode; - LARGE_INTEGER targetpos; - int i; - - if((actualcdmode < -1) || (actualcdmode > 2)) return(-1); - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDlinuz CD: CDreadTrack(%llu, %i)", lsn, actualcdmode); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - if(actualcdmode >= 0) { - rawinfo.DiskOffset.QuadPart = lsn * 2048; // Yes, 2048. - rawinfo.SectorCount = 1; - rawinfo.TrackMode = actualcdmode; - boolresult = DeviceIoControl(devicehandle, - IOCTL_CDROM_RAW_READ, - &rawinfo, - sizeof(RAW_READ_INFO), - buffer, - 2352, - &byteswritten, - &waitevent); - errcode = FinishCommand(boolresult); - - if(errcode != 0) { -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDlinuz CD: Couldn't read a sector raw!"); - PrintError("CDVDlinuz CD", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - return(-1); - } // ENDIF- Couldn't read a raw sector? Maybe not a CD. - - } else { - targetpos.QuadPart = lsn * 2048; - waitevent.Offset = targetpos.LowPart; - waitevent.OffsetHigh = targetpos.HighPart; - - boolresult = ReadFile(devicehandle, - buffer + 24, - 2048, - &byteswritten, - &waitevent); - errcode = FinishCommand(boolresult); - - if(errcode != 0) { -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDlinuz CD: Couldn't read a cooked sector!"); - PrintError("CDVDlinuz CD", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - return(-1); - } // ENDIF- Trouble with seek? Report it. - - for(i = 0; i < 24; i++) *(buffer + i) = 0; - for(i = 24 + 2048; i < 2352; i++) *(buffer + i) = 0; - } // ENDIF- Could we read a raw sector? Read another one! - - if(boolresult == FALSE) { - boolresult = GetOverlappedResult(devicehandle, - &waitevent, - &byteswritten, - FALSE); - } // ENDIF- Did the initial call not complete? Get byteswritten for - // the completed call. - - if(byteswritten < 2048) { -#ifdef VERBOSE_WARNING_DEVICE - errcode = GetLastError(); - PrintLog("CDVDlinuz CD: Short block! only got %u out of %u bytes", - byteswritten, cdblocksize); - PrintError("CDVDlinuz CD", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - return(-1); - } // ENDIF- Couldn't read a raw sector? Maybe not a CD. - - cdmode = mode; - cdblocksize = byteswritten; - return(0); -} // END CDreadTrackPass() - - -s32 CDreadTrack(u32 lsn, int mode, u8 *buffer) { - int retval; - int lastmode; - int i; - - retval = CDreadTrackPass(lsn, mode, buffer); - if(retval >= 0) return(retval); - -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDlinuz CD: Same mode doesn't work. Scanning..."); -#endif /* VERBOSE_WARNING_DEVICE */ - - lastmode = actualcdmode; - actualcdmode = 2; - while(actualcdmode >= -1) { - retval = CDreadTrackPass(lsn, mode, buffer); - if(retval >= 0) return(retval); - actualcdmode--; - } // ENDWHILE- Searching each mode for a way to read the sector - actualcdmode = lastmode; // None worked? Go back to first mode. - -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDlinuz CD: No modes work. Failing sector!"); -#endif /* VERBOSE_WARNING_DEVICE */ - - for(i = 0; i < 2352; i++) *(buffer + i) = 0; - return(-1); -} // END CDreadTrack() - - -s32 CDgetBufferOffset() { -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVD CD: CDgetBufferOffset()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - // Send a whole CDDA record in? - if((actualcdmode == CDDA) && (cdmode == CDVD_MODE_2352)) return(0); - - // Otherwise, send the start of the data block in... - return(cdoffset); -} // END CDgetBufferOffset() - - -s32 CDreadSubQ() { - return(-1); -} // END CDreadSubQ() - - -s32 CDgetTN(cdvdTN *cdvdtn) { - cdvdtn->strack = BCDTOHEX(tocbuffer[7]); - cdvdtn->etrack = BCDTOHEX(tocbuffer[17]); - return(0); -} // END CDgetTN() - - -s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd) { - u8 actualtrack; - int pos; - char temptime[3]; - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDlinuz CD: CDgetTD()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - actualtrack = newtrack; - if(actualtrack == 0xaa) actualtrack = 0; - - if(actualtrack == 0) { - cdvdtd->type = 0; - temptime[0] = BCDTOHEX(tocbuffer[27]); - temptime[1] = BCDTOHEX(tocbuffer[28]); - temptime[2] = BCDTOHEX(tocbuffer[29]); - cdvdtd->lsn = MSFtoLBA(temptime); - } else { - pos = actualtrack * 10; - pos += 30; - cdvdtd->type = tocbuffer[pos]; - temptime[0] = BCDTOHEX(tocbuffer[pos + 7]); - temptime[1] = BCDTOHEX(tocbuffer[pos + 8]); - temptime[2] = BCDTOHEX(tocbuffer[pos + 9]); - cdvdtd->lsn = MSFtoLBA(temptime); - } // ENDIF- Whole disc? (or single track?) - - return(0); -} // END CDgetTD() - - -s32 CDgetDiskType() { - CDROM_TOC cdinfo; - BOOL boolresult; - int retval; - DWORD byteswritten; - DWORD errcode; - u8 iso9660name[] = "CD001\0"; - u8 playstationname[] = "PLAYSTATION\0"; - u8 ps1name[] = "CD-XA001\0"; - u8 tempbuffer[2448]; - int tempdisctype; - int i; - int pos; - unsigned long volumesize; - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDlinuz CD: CDgetDiskType()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - tempdisctype = CDVD_TYPE_UNKNOWN; - - actualcdmode = 2; - retval = CDreadTrack(16, CDVD_MODE_2048, tempbuffer); - if(retval < 0) { - disctype = tempdisctype; - return(-1); - } // ENDIF- Couldn't read the directory sector? Abort. - - disctype = CDVD_TYPE_DETCTCD; - tempdisctype = CDVD_TYPE_CDDA; - - cdoffset = 0; - i = 0; - while((cdoffset <= 24) && (iso9660name[i] != 0)) { - i = 0; - while((iso9660name[i] != 0) && - (iso9660name[i] == tempbuffer[cdoffset + 1 + i])) i++; - if(iso9660name[i] != 0) cdoffset += 8; - } // ENDWHILE- Trying to find a working offset for a ISO9660 record. - - if(iso9660name[i] != 0) { -#ifdef VERBOSE_DISC_TYPE - PrintLog("Detected a CDDA (Music CD)."); -#endif /* VERBOSE_DISC_TYPE */ - tempdisctype = CDVD_TYPE_CDDA; - tocbuffer[0] = 0x01; - - } else { - tocbuffer[0] = 0x41; - i = 0; - while((playstationname[i] != 0) && - (playstationname[i] == tempbuffer[cdoffset + 8 + i])) i++; - if(playstationname[i] != 0) { -#ifdef VERBOSE_DISC_TYPE - PrintLog("Detected a non-Playstation CD."); -#endif /* VERBOSE_DISC_TYPE */ - tempdisctype = CDVD_TYPE_UNKNOWN; - - } else { - i = 0; - while((ps1name[i] != 0) && - (ps1name[i] == tempbuffer[cdoffset + 1024 + i])) i++; - if(ps1name[i] != 0) { -#ifdef VERBOSE_DISC_TYPE - PrintLog("Detected a Playstation 2 CD."); -#endif /* VERBOSE_DISC_TYPE */ - tempdisctype = CDVD_TYPE_PS2CD; - } else { -#ifdef VERBOSE_DISC_TYPE - PrintLog("Detected a Playstation CD."); -#endif /* VERBOSE_DISC_TYPE */ - tempdisctype = CDVD_TYPE_PSCD; - } // ENDIF- Is this not a PlayStation Disc? - } // ENDIF- Is this not a PlayStation Disc? - } // ENDIF- Is this not an ISO9660 CD? (a CDDA, in other words?) - - // Build the Fake TOC - tocbuffer[2] = 0xA0; - tocbuffer[7] = HEXTOBCD(1); // Starting Track - tocbuffer[12] = 0xA1; - tocbuffer[17] = HEXTOBCD(1); // Ending Track - - volumesize = tempbuffer[84]; // Volume size (big endian) - volumesize *= 256; - volumesize += tempbuffer[85]; - volumesize *= 256; - volumesize += tempbuffer[86]; - volumesize *= 256; - volumesize += tempbuffer[87]; -#ifdef VERBOSE_DISC_INFO - if(tempdisctype != CDVD_TYPE_CDDA) { - PrintLog("CDVDlinuz CD: ISO9660 size %llu", volumesize); - } // ENDIF- Data CD? Print size in blocks. -#endif /* VERBOSE_DISC_INFO */ - - LBAtoMSF(volumesize, &tocbuffer[27]); - tocbuffer[27] = HEXTOBCD(tocbuffer[27]); - tocbuffer[28] = HEXTOBCD(tocbuffer[28]); - tocbuffer[29] = HEXTOBCD(tocbuffer[29]); - - tocbuffer[40] = 0x02; // Data Mode - tocbuffer[42] = 0x01; // Track # - LBAtoMSF(0, &tocbuffer[47]); - tocbuffer[47] = HEXTOBCD(tocbuffer[47]); - tocbuffer[48] = HEXTOBCD(tocbuffer[48]); - tocbuffer[49] = HEXTOBCD(tocbuffer[49]); - - // Can we get the REAL TOC? - boolresult = DeviceIoControl(devicehandle, - IOCTL_CDROM_READ_TOC, - NULL, - 0, - &cdinfo, - sizeof(CDROM_TOC), - &byteswritten, - NULL); - - if(boolresult == FALSE) { -#ifdef VERBOSE_WARNING_DEVICE - errcode = GetLastError(); - PrintLog("CDVDlinuz CD: Can't get TOC!"); - PrintError("CDVDlinuz CD", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - disctype = tempdisctype; - return(disctype); - } // ENDIF- Can't read the TOC? Accept the fake TOC then. - - // Fill in the pieces of the REAL TOC. -#ifdef VERBOSE_DISC_INFO - PrintLog("CDVDlinuz CD: TOC First Track: %u Last Track: %u", - cdinfo.FirstTrack, cdinfo.LastTrack); -#endif /* VERBOSE_DISC_INFO */ - tocbuffer[7] = HEXTOBCD(cdinfo.FirstTrack); - tocbuffer[17] = HEXTOBCD(cdinfo.LastTrack); - - // for(i = cdinfo.FirstTrack; i <= cdinfo.LastTrack; i++) { - for(i = 0; i <= cdinfo.LastTrack - cdinfo.FirstTrack; i++) { -#ifdef VERBOSE_DISC_INFO - PrintLog("CDVDlinuz CD: TOC Track %u Disc Size: %u:%u.%u Data Mode %u", - cdinfo.TrackData[i].TrackNumber, - cdinfo.TrackData[i].Address[1] * 1, - cdinfo.TrackData[i].Address[2] * 1, - cdinfo.TrackData[i].Address[3] * 1, - cdinfo.TrackData[i].Control * 1); -#endif /* VERBOSE_DISC_INFO */ - pos = i * 10 + 40; - tocbuffer[pos] = cdinfo.TrackData[i].Control; - tocbuffer[pos + 2] = HEXTOBCD(i + 1); - tocbuffer[pos + 7] = HEXTOBCD(cdinfo.TrackData[i].Address[1]); - tocbuffer[pos + 8] = HEXTOBCD(cdinfo.TrackData[i].Address[2]); - tocbuffer[pos + 9] = HEXTOBCD(cdinfo.TrackData[i].Address[3]); - } // NEXT i- Transferring Track data to the PS2 TOC - - -#ifdef VERBOSE_DISC_INFO - PrintLog("CDVDlinuz CD: TOC Disc Size: %u:%u.%u", - cdinfo.TrackData[i].Address[1] * 1, - cdinfo.TrackData[i].Address[2] * 1, - cdinfo.TrackData[i].Address[3] * 1); -#endif /* VERBOSE_DISC_INFO */ - tocbuffer[27] = HEXTOBCD(cdinfo.TrackData[i].Address[1]); - tocbuffer[28] = HEXTOBCD(cdinfo.TrackData[i].Address[2]); - tocbuffer[29] = HEXTOBCD(cdinfo.TrackData[i].Address[3]); - - disctype = tempdisctype; - return(disctype); -} // END CDgetDiskType() +/* CD.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + +#include // IOCTL_CDROM... + + + +#include // off64_t + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + +#include "logfile.h" + +#include "../convert.h" // MSFtoLBA(), HEXTOBCD() + +#include "actualfile.h" + +#include "device.h" // tocbuffer[], FinishCommand() + +#include "CD.h" + + + + + +int actualcdmode; // -1=ReadFile, 0=YellowMode2, 1=XAForm2, 2=CDDA + +DWORD cdblocksize; // 2048 to 2352 + +int cdoffset; // 0, 8, 16, or 24 + +int cdmode; + + + + + +void InitCDInfo() { + + actualcdmode = -1; + + cdblocksize = 2048; + + cdmode = -1; + +} // END InitCDInfo() + + + + + +s32 CDreadTrackPass(u32 lsn, int mode, u8 *buffer) { + + RAW_READ_INFO rawinfo; + + BOOL boolresult; + + DWORD byteswritten; + + DWORD errcode; + + LARGE_INTEGER targetpos; + + int i; + + + + if((actualcdmode < -1) || (actualcdmode > 2)) return(-1); + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDlinuz CD: CDreadTrack(%llu, %i)", lsn, actualcdmode); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + if(actualcdmode >= 0) { + + rawinfo.DiskOffset.QuadPart = lsn * 2048; // Yes, 2048. + + rawinfo.SectorCount = 1; + + rawinfo.TrackMode = actualcdmode; + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_CDROM_RAW_READ, + + &rawinfo, + + sizeof(RAW_READ_INFO), + + buffer, + + 2352, + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDlinuz CD: Couldn't read a sector raw!"); + + PrintError("CDVDlinuz CD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Couldn't read a raw sector? Maybe not a CD. + + + + } else { + + targetpos.QuadPart = lsn * 2048; + + waitevent.Offset = targetpos.LowPart; + + waitevent.OffsetHigh = targetpos.HighPart; + + + + boolresult = ReadFile(devicehandle, + + buffer + 24, + + 2048, + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDlinuz CD: Couldn't read a cooked sector!"); + + PrintError("CDVDlinuz CD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Trouble with seek? Report it. + + + + for(i = 0; i < 24; i++) *(buffer + i) = 0; + + for(i = 24 + 2048; i < 2352; i++) *(buffer + i) = 0; + + } // ENDIF- Could we read a raw sector? Read another one! + + + + if(boolresult == FALSE) { + + boolresult = GetOverlappedResult(devicehandle, + + &waitevent, + + &byteswritten, + + FALSE); + + } // ENDIF- Did the initial call not complete? Get byteswritten for + + // the completed call. + + + + if(byteswritten < 2048) { + +#ifdef VERBOSE_WARNING_DEVICE + + errcode = GetLastError(); + + PrintLog("CDVDlinuz CD: Short block! only got %u out of %u bytes", + + byteswritten, cdblocksize); + + PrintError("CDVDlinuz CD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Couldn't read a raw sector? Maybe not a CD. + + + + cdmode = mode; + + cdblocksize = byteswritten; + + return(0); + +} // END CDreadTrackPass() + + + + + +s32 CDreadTrack(u32 lsn, int mode, u8 *buffer) { + + int retval; + + int lastmode; + + int i; + + + + retval = CDreadTrackPass(lsn, mode, buffer); + + if(retval >= 0) return(retval); + + + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDlinuz CD: Same mode doesn't work. Scanning..."); + +#endif /* VERBOSE_WARNING_DEVICE */ + + + + lastmode = actualcdmode; + + actualcdmode = 2; + + while(actualcdmode >= -1) { + + retval = CDreadTrackPass(lsn, mode, buffer); + + if(retval >= 0) return(retval); + + actualcdmode--; + + } // ENDWHILE- Searching each mode for a way to read the sector + + actualcdmode = lastmode; // None worked? Go back to first mode. + + + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDlinuz CD: No modes work. Failing sector!"); + +#endif /* VERBOSE_WARNING_DEVICE */ + + + + for(i = 0; i < 2352; i++) *(buffer + i) = 0; + + return(-1); + +} // END CDreadTrack() + + + + + +s32 CDgetBufferOffset() { + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVD CD: CDgetBufferOffset()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + // Send a whole CDDA record in? + + if((actualcdmode == CDDA) && (cdmode == CDVD_MODE_2352)) return(0); + + + + // Otherwise, send the start of the data block in... + + return(cdoffset); + +} // END CDgetBufferOffset() + + + + + +s32 CDreadSubQ() { + + return(-1); + +} // END CDreadSubQ() + + + + + +s32 CDgetTN(cdvdTN *cdvdtn) { + + cdvdtn->strack = BCDTOHEX(tocbuffer[7]); + + cdvdtn->etrack = BCDTOHEX(tocbuffer[17]); + + return(0); + +} // END CDgetTN() + + + + + +s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd) { + + u8 actualtrack; + + int pos; + + char temptime[3]; + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDlinuz CD: CDgetTD()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + actualtrack = newtrack; + + if(actualtrack == 0xaa) actualtrack = 0; + + + + if(actualtrack == 0) { + + cdvdtd->type = 0; + + temptime[0] = BCDTOHEX(tocbuffer[27]); + + temptime[1] = BCDTOHEX(tocbuffer[28]); + + temptime[2] = BCDTOHEX(tocbuffer[29]); + + cdvdtd->lsn = MSFtoLBA(temptime); + + } else { + + pos = actualtrack * 10; + + pos += 30; + + cdvdtd->type = tocbuffer[pos]; + + temptime[0] = BCDTOHEX(tocbuffer[pos + 7]); + + temptime[1] = BCDTOHEX(tocbuffer[pos + 8]); + + temptime[2] = BCDTOHEX(tocbuffer[pos + 9]); + + cdvdtd->lsn = MSFtoLBA(temptime); + + } // ENDIF- Whole disc? (or single track?) + + + + return(0); + +} // END CDgetTD() + + + + + +s32 CDgetDiskType() { + + CDROM_TOC cdinfo; + + BOOL boolresult; + + int retval; + + DWORD byteswritten; + + DWORD errcode; + + u8 iso9660name[] = "CD001\0"; + + u8 playstationname[] = "PLAYSTATION\0"; + + u8 ps1name[] = "CD-XA001\0"; + + u8 tempbuffer[2448]; + + int tempdisctype; + + int i; + + int pos; + + unsigned long volumesize; + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDlinuz CD: CDgetDiskType()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + tempdisctype = CDVD_TYPE_UNKNOWN; + + + + actualcdmode = 2; + + retval = CDreadTrack(16, CDVD_MODE_2048, tempbuffer); + + if(retval < 0) { + + disctype = tempdisctype; + + return(-1); + + } // ENDIF- Couldn't read the directory sector? Abort. + + + + disctype = CDVD_TYPE_DETCTCD; + + tempdisctype = CDVD_TYPE_CDDA; + + + + cdoffset = 0; + + i = 0; + + while((cdoffset <= 24) && (iso9660name[i] != 0)) { + + i = 0; + + while((iso9660name[i] != 0) && + + (iso9660name[i] == tempbuffer[cdoffset + 1 + i])) i++; + + if(iso9660name[i] != 0) cdoffset += 8; + + } // ENDWHILE- Trying to find a working offset for a ISO9660 record. + + + + if(iso9660name[i] != 0) { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("Detected a CDDA (Music CD)."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_CDDA; + + tocbuffer[0] = 0x01; + + + + } else { + + tocbuffer[0] = 0x41; + + i = 0; + + while((playstationname[i] != 0) && + + (playstationname[i] == tempbuffer[cdoffset + 8 + i])) i++; + + if(playstationname[i] != 0) { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("Detected a non-Playstation CD."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_UNKNOWN; + + + + } else { + + i = 0; + + while((ps1name[i] != 0) && + + (ps1name[i] == tempbuffer[cdoffset + 1024 + i])) i++; + + if(ps1name[i] != 0) { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("Detected a Playstation 2 CD."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_PS2CD; + + } else { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("Detected a Playstation CD."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_PSCD; + + } // ENDIF- Is this not a PlayStation Disc? + + } // ENDIF- Is this not a PlayStation Disc? + + } // ENDIF- Is this not an ISO9660 CD? (a CDDA, in other words?) + + + + // Build the Fake TOC + + tocbuffer[2] = 0xA0; + + tocbuffer[7] = HEXTOBCD(1); // Starting Track + + tocbuffer[12] = 0xA1; + + tocbuffer[17] = HEXTOBCD(1); // Ending Track + + + + volumesize = tempbuffer[84]; // Volume size (big endian) + + volumesize *= 256; + + volumesize += tempbuffer[85]; + + volumesize *= 256; + + volumesize += tempbuffer[86]; + + volumesize *= 256; + + volumesize += tempbuffer[87]; + +#ifdef VERBOSE_DISC_INFO + + if(tempdisctype != CDVD_TYPE_CDDA) { + + PrintLog("CDVDlinuz CD: ISO9660 size %llu", volumesize); + + } // ENDIF- Data CD? Print size in blocks. + +#endif /* VERBOSE_DISC_INFO */ + + + + LBAtoMSF(volumesize, &tocbuffer[27]); + + tocbuffer[27] = HEXTOBCD(tocbuffer[27]); + + tocbuffer[28] = HEXTOBCD(tocbuffer[28]); + + tocbuffer[29] = HEXTOBCD(tocbuffer[29]); + + + + tocbuffer[40] = 0x02; // Data Mode + + tocbuffer[42] = 0x01; // Track # + + LBAtoMSF(0, &tocbuffer[47]); + + tocbuffer[47] = HEXTOBCD(tocbuffer[47]); + + tocbuffer[48] = HEXTOBCD(tocbuffer[48]); + + tocbuffer[49] = HEXTOBCD(tocbuffer[49]); + + + + // Can we get the REAL TOC? + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_CDROM_READ_TOC, + + NULL, + + 0, + + &cdinfo, + + sizeof(CDROM_TOC), + + &byteswritten, + + NULL); + + + + if(boolresult == FALSE) { + +#ifdef VERBOSE_WARNING_DEVICE + + errcode = GetLastError(); + + PrintLog("CDVDlinuz CD: Can't get TOC!"); + + PrintError("CDVDlinuz CD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + disctype = tempdisctype; + + return(disctype); + + } // ENDIF- Can't read the TOC? Accept the fake TOC then. + + + + // Fill in the pieces of the REAL TOC. + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVDlinuz CD: TOC First Track: %u Last Track: %u", + + cdinfo.FirstTrack, cdinfo.LastTrack); + +#endif /* VERBOSE_DISC_INFO */ + + tocbuffer[7] = HEXTOBCD(cdinfo.FirstTrack); + + tocbuffer[17] = HEXTOBCD(cdinfo.LastTrack); + + + + // for(i = cdinfo.FirstTrack; i <= cdinfo.LastTrack; i++) { + + for(i = 0; i <= cdinfo.LastTrack - cdinfo.FirstTrack; i++) { + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVDlinuz CD: TOC Track %u Disc Size: %u:%u.%u Data Mode %u", + + cdinfo.TrackData[i].TrackNumber, + + cdinfo.TrackData[i].Address[1] * 1, + + cdinfo.TrackData[i].Address[2] * 1, + + cdinfo.TrackData[i].Address[3] * 1, + + cdinfo.TrackData[i].Control * 1); + +#endif /* VERBOSE_DISC_INFO */ + + pos = i * 10 + 40; + + tocbuffer[pos] = cdinfo.TrackData[i].Control; + + tocbuffer[pos + 2] = HEXTOBCD(i + 1); + + tocbuffer[pos + 7] = HEXTOBCD(cdinfo.TrackData[i].Address[1]); + + tocbuffer[pos + 8] = HEXTOBCD(cdinfo.TrackData[i].Address[2]); + + tocbuffer[pos + 9] = HEXTOBCD(cdinfo.TrackData[i].Address[3]); + + } // NEXT i- Transferring Track data to the PS2 TOC + + + + + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVDlinuz CD: TOC Disc Size: %u:%u.%u", + + cdinfo.TrackData[i].Address[1] * 1, + + cdinfo.TrackData[i].Address[2] * 1, + + cdinfo.TrackData[i].Address[3] * 1); + +#endif /* VERBOSE_DISC_INFO */ + + tocbuffer[27] = HEXTOBCD(cdinfo.TrackData[i].Address[1]); + + tocbuffer[28] = HEXTOBCD(cdinfo.TrackData[i].Address[2]); + + tocbuffer[29] = HEXTOBCD(cdinfo.TrackData[i].Address[3]); + + + + disctype = tempdisctype; + + return(disctype); + +} // END CDgetDiskType() + diff --git a/plugins/CDVDlinuz/Src/Win32/CD.h b/plugins/CDVDlinuz/Src/Win32/CD.h index 6bff6d8e82..2049fe764d 100644 --- a/plugins/CDVDlinuz/Src/Win32/CD.h +++ b/plugins/CDVDlinuz/Src/Win32/CD.h @@ -1,44 +1,88 @@ -/* CD.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef CD_H -#define CD_H - - -#include // DWORD - -#define CDVDdefs -#include "PS2Edefs.h" - - -extern DWORD cdblocksize; - - -extern void InitCDInfo(); -extern s32 CDreadTrack(u32 lsn, int mode, u8 *buffer); -extern s32 CDgetBufferOffset(); -extern s32 CDreadSubQ(); -extern s32 CDgetTN(cdvdTN *cdvdtn); -extern s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd); -extern s32 CDgetDiskType(); - - -#endif /* CD_H */ +/* CD.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef CD_H + +#define CD_H + + + + + +#include // DWORD + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + + + +extern DWORD cdblocksize; + + + + + +extern void InitCDInfo(); + +extern s32 CDreadTrack(u32 lsn, int mode, u8 *buffer); + +extern s32 CDgetBufferOffset(); + +extern s32 CDreadSubQ(); + +extern s32 CDgetTN(cdvdTN *cdvdtn); + +extern s32 CDgetTD(u8 newtrack, cdvdTD *cdvdtd); + +extern s32 CDgetDiskType(); + + + + + +#endif /* CD_H */ + diff --git a/plugins/CDVDlinuz/Src/Win32/CDVDlinuz.c b/plugins/CDVDlinuz/Src/Win32/CDVDlinuz.c index a4ebc64229..b106575d8b 100644 --- a/plugins/CDVDlinuz/Src/Win32/CDVDlinuz.c +++ b/plugins/CDVDlinuz/Src/Win32/CDVDlinuz.c @@ -1,434 +1,868 @@ -/* CDVDlinuz.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // BOOL, CALLBACK, APIENTRY -#include // NULL - -#include // time(), time_t - -#define CDVDdefs -#include "../PS2Edefs.h" - -#include "device.h" -#include "CD.h" -#include "DVD.h" -#include "../buffer.h" -#include "../convert.h" -#include "conf.h" -#include "logfile.h" -#include "../version.h" -#include "screens.h" -#include "mainbox.h" // Initialize mainboxwindow -#include "CDVDlinuz.h" - - -HINSTANCE progmodule; - - -BOOL APIENTRY DllMain(HANDLE hModule, - DWORD param, - LPVOID reserved) { - - - switch(param) { - case DLL_PROCESS_ATTACH: - progmodule = hModule; - // mainboxwindow = NULL; - return(TRUE); - break; - case DLL_PROCESS_DETACH: - // CDVDshutdown(); - return(TRUE); - break; - case DLL_THREAD_ATTACH: - return(TRUE); - break; - case DLL_THREAD_DETACH: - return(TRUE); - break; - } // ENDSWITCH param- What does the OS want with us? - - return(FALSE); // Wasn't on list? Wasn't handled. -} // END DllMain() - - -char* CALLBACK PS2EgetLibName() { - return(libname); -} // END PS2EgetLibName() - - -u32 CALLBACK PS2EgetLibType() { - return(PS2E_LT_CDVD); -} // END PS2getLibType() - - -u32 CALLBACK PS2EgetLibVersion2(u32 type) { - return((version << 16) | (revision << 8) | build); -} // END PS2EgetLibVersion2() - - -s32 CALLBACK CDVDinit() { - InitLog(); - if(OpenLog() != 0) return(-1); // Couldn't open Log File? Abort. - -#ifdef VERBOSE_FUNCTION_INTERFACE - PrintLog("CDVDlinuz interface: CDVDinit()"); -#endif /* VERBOSE_FUNCTION_INTERFACE */ - - InitConf(); - - DeviceInit(); - InitCDInfo(); - InitDVDInfo(); - - mainboxwindow = NULL; - - return(0); -} // END CDVDinit() - - -void CALLBACK CDVDshutdown() { -#ifdef VERBOSE_FUNCTION_INTERFACE - PrintLog("CDVDlinuz interface: CDVDshutdown()"); -#endif /* VERBOSE_FUNCTION_INTERFACE */ - - DeviceClose(); - - // Close Windows as well? (Just in case) - - CloseLog(); -} // END CDVDshutdown() - - -s32 CALLBACK CDVDopen() { - int retval; - -#ifdef VERBOSE_FUNCTION_INTERFACE - PrintLog("CDVDlinuz interface: CDVDopen()"); -#endif /* VERBOSE_FUNCTION_INTERFACE */ - - InitBuffer(); - - LoadConf(); - - retval = DeviceOpen(); - if(retval == 0) { - DeviceTrayStatus(); - } // ENDIF- Did we open the device? Poll for media. - return(retval); -} // END CDVDopen() - - -void CALLBACK CDVDclose() { -#ifdef VERBOSE_FUNCTION_INTERFACE - PrintLog("CDVDlinuz interface: CDVDclose()"); -#endif /* VERBOSE_FUNCTION_INTERFACE */ - DeviceClose(); -} // END CDVDclose() - - -s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq) { - char temptime[3]; - int i; - int pos; - u32 tracklsn; - -#ifdef VERBOSE_FUNCTION_INTERFACE - PrintLog("CDVDlinuz interface: CDVDreadSubQ()"); -#endif /* VERBOSE_FUNCTION_INTERFACE */ - - if(DiscInserted() != 0) return(-1); - - if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { - return(-1); // DVDs don't have SubQ data - } // ENDIF- Trying to get a SubQ from a DVD? - - // fake it - i = BCDTOHEX(tocbuffer[7]); - pos = i * 10; - pos += 30; - temptime[0] = BCDTOHEX(tocbuffer[pos + 7]); - temptime[1] = BCDTOHEX(tocbuffer[pos + 8]); - temptime[2] = BCDTOHEX(tocbuffer[pos + 9]); - tracklsn = MSFtoLBA(temptime); - while((i < BCDTOHEX(tocbuffer[17])) && (tracklsn < lsn)) { - i++; - pos = i * 10; - pos += 30; - temptime[0] = BCDTOHEX(tocbuffer[pos + 7]); - temptime[1] = BCDTOHEX(tocbuffer[pos + 8]); - temptime[2] = BCDTOHEX(tocbuffer[pos + 9]); - tracklsn = MSFtoLBA(temptime); - } // ENDIF- Loop through tracks searching for lsn track - i--; - - subq->ctrl = 4; - subq->mode = 1; - subq->trackNum = HEXTOBCD(i); - subq->trackIndex = HEXTOBCD(i); - - LBAtoMSF(lsn - tracklsn, temptime); - subq->trackM = HEXTOBCD(temptime[0]); - subq->trackS = HEXTOBCD(temptime[1]); - subq->trackF = HEXTOBCD(temptime[2]); - - subq->pad = 0; - - // lba_to_msf(lsn + (2*75), &min, &sec, &frm); - LBAtoMSF(lsn, temptime); - subq->discM = HEXTOBCD(temptime[0]); - subq->discS = HEXTOBCD(temptime[1]); - subq->discF = HEXTOBCD(temptime[2]); - return(0); -} // END CDVDreadSubQ() - - -s32 CALLBACK CDVDgetTN(cdvdTN *Buffer) { - -#ifdef VERBOSE_FUNCTION_INTERFACE - PrintLog("CDVDlinuz interface: CDVDgetTN()"); -#endif /* VERBOSE_FUNCTION_INTERFACE */ - - if(DiscInserted() != 0) return(-1); - - if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { - Buffer->strack = 1; - Buffer->etrack = 1; - } else { - Buffer->strack = BCDTOHEX(tocbuffer[7]); - Buffer->etrack = BCDTOHEX(tocbuffer[17]); - } // ENDIF- Retrieve track info from a DVD? (or a CD?) - - return(0); -} // END CDVDgetTN() - - -s32 CALLBACK CDVDgetTD(u8 track, cdvdTD *buffer) { -#ifdef VERBOSE_FUNCTION_INTERFACE - PrintLog("CDVDlinuz interface: CDVDgetTD()"); -#endif /* VERBOSE_FUNCTION_INTERFACE */ - - return(DeviceGetTD(track, buffer)); -} // END CDVDgetTD() - - -s32 CALLBACK CDVDgetTOC(void* toc) { - int i; - -#ifdef VERBOSE_FUNCTION_INTERFACE - PrintLog("CDVDlinuz interface: CDVDgetTOC()"); -#endif /* VERBOSE_FUNCTION_INTERFACE */ - - if(DiscInserted() != 0) return(-1); - - for(i = 0; i < 2048; i++) *(((char *) toc) + i) = tocbuffer[i]; - return(0); -} // END CDVDgetTOC() - - -s32 CALLBACK CDVDreadTrack(u32 lsn, int mode) { - int retval; - -#ifdef VERBOSE_FUNCTION_INTERFACE - PrintLog("CDVDlinuz interface: CDVDreadTrack(%u)", lsn); -#endif /* VERBOSE_FUNCTION_INTERFACE */ - - if(DiscInserted() == -1) return(-1); - - if(userbuffer < BUFFERMAX) { - if((bufferlist[userbuffer].lsn == lsn) && - (bufferlist[userbuffer].mode == mode)) { - return(0); - } // ENDIF- And it's the right one? - } // ENDIF- Are we already pointing at the buffer? - - userbuffer = FindListBuffer(lsn); - if(userbuffer < BUFFERMAX) { - if((bufferlist[userbuffer].lsn == lsn) && - (bufferlist[userbuffer].mode == mode)) { - return(0); - } // ENDIF- And it was the right one? - } // ENDIF- Was a buffer found in the cache? - - replacebuffer++; - if(replacebuffer >= BUFFERMAX) replacebuffer = 0; - userbuffer = replacebuffer; - - if(bufferlist[replacebuffer].upsort != 0xffff) { - RemoveListBuffer(replacebuffer); - } // ENDIF- Reference already in place? Remove it. - - retval = DeviceReadTrack(lsn, mode, bufferlist[replacebuffer].buffer); - bufferlist[replacebuffer].lsn = lsn; - bufferlist[replacebuffer].mode = mode; - bufferlist[replacebuffer].offset = DeviceBufferOffset(); - - if(retval != 0) { - bufferlist[replacebuffer].mode = -1; // Error! flag buffer as such. - } else { - if((disctype != CDVD_TYPE_PS2DVD) && (disctype != CDVD_TYPE_DVDV)) { - if(mode == CDVD_MODE_2352) { - CDreadSubQ(lsn, &bufferlist[replacebuffer].subq); - } // ENDIF- Read subq as well? - } // ENDIF- Read a DVD buffer or a CD buffer? - } // ENDIF-Read ok? Fill out rest of buffer info. - AddListBuffer(replacebuffer); - return(retval); -} // END CDVDreadTrack() - - -u8* CALLBACK CDVDgetBuffer() { -#ifdef VERBOSE_FUNCTION_INTERFACE - PrintLog("CDVDlinuz interface: CDVDgetBuffer()"); -#endif /* VERBOSE_FUNCTION_INTERFACE */ - - if(DiscInserted() == -1) return(NULL); - - if(userbuffer == 0xffff) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVDlinuz interface: Not pointing to a buffer!"); -#endif /* VERBOSE_WARNINGS */ - return(NULL); // No buffer reference? - } // ENDIF- user buffer not pointing at anything? Abort - - if(bufferlist[userbuffer].mode < 0) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVDlinuz interface: Error retrieving sector (ReadTrack call)"); -#endif /* VERBOSE_WARNINGS */ - return(NULL); // Bad Sector? - } // ENDIF- Trouble reading physical sector? Tell them. - - return(bufferlist[userbuffer].buffer + bufferlist[userbuffer].offset); -} // END CDVDgetBuffer() - - -s32 CALLBACK CDVDgetDiskType() { -#ifdef VERBOSE_FUNCTION_INTERFACE - PrintLog("CDVDlinuz interface: CDVDgetDiskType()"); -#endif /* VERBOSE_FUNCTION_INTERFACE */ - - if(lasttime != time(NULL)) { - lasttime = time(NULL); - DeviceTrayStatus(); - } // ENDIF- Has enough time passed between calls? - - return(disctype); -} // END CDVDgetDiskType() - - -s32 CALLBACK CDVDgetTrayStatus() { -#ifdef VERBOSE_FUNCTION_INTERFACE - PrintLog("CDVDlinuz interface: CDVDgetTrayStatus()"); -#endif /* VERBOSE_FUNCTION_INTERFACE */ - - if(lasttime != time(NULL)) { - lasttime = time(NULL); - DeviceTrayStatus(); - } // ENDIF- Has enough time passed between calls? - - return(traystatus); -} // END CDVDgetTrayStatus() - - -s32 CALLBACK CDVDctrlTrayOpen() { -#ifdef VERBOSE_FUNCTION_INTERFACE - PrintLog("CDVDlinuz interface: CDVDctrlTrayOpen()"); -#endif /* VERBOSE_FUNCTION_INTERFACE */ - - return(DeviceTrayOpen()); -} // END CDVDctrlTrayOpen() - - -s32 CALLBACK CDVDctrlTrayClose() { -#ifdef VERBOSE_FUNCTION_INTERFACE - PrintLog("CDVDlinuz interface: CDVDctrlTrayClose()"); -#endif /* VERBOSE_FUNCTION_INTERFACE */ - - return(DeviceTrayClose()); -} // END CDVDctrlTrayClose() - - -s32 CALLBACK CDVDtest() { - int retval; - - errno = 0; - - if(devicehandle != NULL) { -#ifdef VERBOSE_WARNINGS - PrintLog("CDVDlinuz interface: Device already open"); -#endif /* VERBOSE_WARNINGS */ - return(0); - } // ENDIF- Is the CD/DVD already in use? That's fine. - -#ifdef VERBOSE_FUNCTION_INTERFACE - PrintLog("CDVDlinuz interface: CDVDtest()"); -#endif /* VERBOSE_FUNCTION_INTERFACE */ - - retval = DeviceOpen(); - DeviceClose(); - return(retval); -} // END CDVDtest() - - -void CALLBACK CDVDconfigure() { - HWND lastwindow; - - lastwindow = GetActiveWindow(); - DialogBox(progmodule, - MAKEINTRESOURCE(DLG_0200), - lastwindow, - (DLGPROC)MainBoxCallback); - SetActiveWindow(lastwindow); - lastwindow = NULL; - return; -} // END CDVDconfigure() - - -BOOL CALLBACK AboutCallback(HWND window, UINT msg, WPARAM param, LPARAM param2) { - switch(msg) { - case WM_COMMAND: - switch(LOWORD(param)) { - case IDC_0104: // "Ok" Button - EndDialog(window, FALSE); - return(TRUE); - break; - } // ENDSWITCH param- Which Windows Message Command? - - case WM_CLOSE: - EndDialog(window, FALSE); - return(TRUE); - break; - } // ENDSWITCH msg- what message has been sent to this window? - - return(FALSE); // Not a recognisable message. Pass it back to the OS. -} // END AboutCallback() - -void CALLBACK CDVDabout() { - HWND lastwindow; - - lastwindow = GetActiveWindow(); - DialogBox(progmodule, - MAKEINTRESOURCE(DLG_0100), - lastwindow, - (DLGPROC)AboutCallback); - SetActiveWindow(lastwindow); - return; -} // END CDVDabout() +/* CDVDlinuz.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // BOOL, CALLBACK, APIENTRY + +#include // NULL + + + +#include // time(), time_t + + + +#define CDVDdefs + +#include "../PS2Edefs.h" + + + +#include "device.h" + +#include "CD.h" + +#include "DVD.h" + +#include "../buffer.h" + +#include "../convert.h" + +#include "conf.h" + +#include "logfile.h" + +#include "../version.h" + +#include "screens.h" + +#include "mainbox.h" // Initialize mainboxwindow + +#include "CDVDlinuz.h" + + + + + +HINSTANCE progmodule; + + + + + +BOOL APIENTRY DllMain(HANDLE hModule, + + DWORD param, + + LPVOID reserved) { + + + + + + switch(param) { + + case DLL_PROCESS_ATTACH: + + progmodule = hModule; + + // mainboxwindow = NULL; + + return(TRUE); + + break; + + case DLL_PROCESS_DETACH: + + // CDVDshutdown(); + + return(TRUE); + + break; + + case DLL_THREAD_ATTACH: + + return(TRUE); + + break; + + case DLL_THREAD_DETACH: + + return(TRUE); + + break; + + } // ENDSWITCH param- What does the OS want with us? + + + + return(FALSE); // Wasn't on list? Wasn't handled. + +} // END DllMain() + + + + + +char* CALLBACK PS2EgetLibName() { + + return(libname); + +} // END PS2EgetLibName() + + + + + +u32 CALLBACK PS2EgetLibType() { + + return(PS2E_LT_CDVD); + +} // END PS2getLibType() + + + + + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + + return((version << 16) | (revision << 8) | build); + +} // END PS2EgetLibVersion2() + + + + + +s32 CALLBACK CDVDinit() { + + InitLog(); + + if(OpenLog() != 0) return(-1); // Couldn't open Log File? Abort. + + + +#ifdef VERBOSE_FUNCTION_INTERFACE + + PrintLog("CDVDlinuz interface: CDVDinit()"); + +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + + + InitConf(); + + + + DeviceInit(); + + InitCDInfo(); + + InitDVDInfo(); + + + + mainboxwindow = NULL; + + + + return(0); + +} // END CDVDinit() + + + + + +void CALLBACK CDVDshutdown() { + +#ifdef VERBOSE_FUNCTION_INTERFACE + + PrintLog("CDVDlinuz interface: CDVDshutdown()"); + +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + + + DeviceClose(); + + + + // Close Windows as well? (Just in case) + + + + CloseLog(); + +} // END CDVDshutdown() + + + + + +s32 CALLBACK CDVDopen() { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_INTERFACE + + PrintLog("CDVDlinuz interface: CDVDopen()"); + +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + + + InitBuffer(); + + + + LoadConf(); + + + + retval = DeviceOpen(); + + if(retval == 0) { + + DeviceTrayStatus(); + + } // ENDIF- Did we open the device? Poll for media. + + return(retval); + +} // END CDVDopen() + + + + + +void CALLBACK CDVDclose() { + +#ifdef VERBOSE_FUNCTION_INTERFACE + + PrintLog("CDVDlinuz interface: CDVDclose()"); + +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + DeviceClose(); + +} // END CDVDclose() + + + + + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq) { + + char temptime[3]; + + int i; + + int pos; + + u32 tracklsn; + + + +#ifdef VERBOSE_FUNCTION_INTERFACE + + PrintLog("CDVDlinuz interface: CDVDreadSubQ()"); + +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + + + if(DiscInserted() != 0) return(-1); + + + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + + return(-1); // DVDs don't have SubQ data + + } // ENDIF- Trying to get a SubQ from a DVD? + + + + // fake it + + i = BCDTOHEX(tocbuffer[7]); + + pos = i * 10; + + pos += 30; + + temptime[0] = BCDTOHEX(tocbuffer[pos + 7]); + + temptime[1] = BCDTOHEX(tocbuffer[pos + 8]); + + temptime[2] = BCDTOHEX(tocbuffer[pos + 9]); + + tracklsn = MSFtoLBA(temptime); + + while((i < BCDTOHEX(tocbuffer[17])) && (tracklsn < lsn)) { + + i++; + + pos = i * 10; + + pos += 30; + + temptime[0] = BCDTOHEX(tocbuffer[pos + 7]); + + temptime[1] = BCDTOHEX(tocbuffer[pos + 8]); + + temptime[2] = BCDTOHEX(tocbuffer[pos + 9]); + + tracklsn = MSFtoLBA(temptime); + + } // ENDIF- Loop through tracks searching for lsn track + + i--; + + + + subq->ctrl = 4; + + subq->mode = 1; + + subq->trackNum = HEXTOBCD(i); + + subq->trackIndex = HEXTOBCD(i); + + + + LBAtoMSF(lsn - tracklsn, temptime); + + subq->trackM = HEXTOBCD(temptime[0]); + + subq->trackS = HEXTOBCD(temptime[1]); + + subq->trackF = HEXTOBCD(temptime[2]); + + + + subq->pad = 0; + + + + // lba_to_msf(lsn + (2*75), &min, &sec, &frm); + + LBAtoMSF(lsn, temptime); + + subq->discM = HEXTOBCD(temptime[0]); + + subq->discS = HEXTOBCD(temptime[1]); + + subq->discF = HEXTOBCD(temptime[2]); + + return(0); + +} // END CDVDreadSubQ() + + + + + +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer) { + + + +#ifdef VERBOSE_FUNCTION_INTERFACE + + PrintLog("CDVDlinuz interface: CDVDgetTN()"); + +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + + + if(DiscInserted() != 0) return(-1); + + + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + + Buffer->strack = 1; + + Buffer->etrack = 1; + + } else { + + Buffer->strack = BCDTOHEX(tocbuffer[7]); + + Buffer->etrack = BCDTOHEX(tocbuffer[17]); + + } // ENDIF- Retrieve track info from a DVD? (or a CD?) + + + + return(0); + +} // END CDVDgetTN() + + + + + +s32 CALLBACK CDVDgetTD(u8 track, cdvdTD *buffer) { + +#ifdef VERBOSE_FUNCTION_INTERFACE + + PrintLog("CDVDlinuz interface: CDVDgetTD()"); + +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + + + return(DeviceGetTD(track, buffer)); + +} // END CDVDgetTD() + + + + + +s32 CALLBACK CDVDgetTOC(void* toc) { + + int i; + + + +#ifdef VERBOSE_FUNCTION_INTERFACE + + PrintLog("CDVDlinuz interface: CDVDgetTOC()"); + +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + + + if(DiscInserted() != 0) return(-1); + + + + for(i = 0; i < 2048; i++) *(((char *) toc) + i) = tocbuffer[i]; + + return(0); + +} // END CDVDgetTOC() + + + + + +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode) { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_INTERFACE + + PrintLog("CDVDlinuz interface: CDVDreadTrack(%u)", lsn); + +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + + + if(DiscInserted() == -1) return(-1); + + + + if(userbuffer < BUFFERMAX) { + + if((bufferlist[userbuffer].lsn == lsn) && + + (bufferlist[userbuffer].mode == mode)) { + + return(0); + + } // ENDIF- And it's the right one? + + } // ENDIF- Are we already pointing at the buffer? + + + + userbuffer = FindListBuffer(lsn); + + if(userbuffer < BUFFERMAX) { + + if((bufferlist[userbuffer].lsn == lsn) && + + (bufferlist[userbuffer].mode == mode)) { + + return(0); + + } // ENDIF- And it was the right one? + + } // ENDIF- Was a buffer found in the cache? + + + + replacebuffer++; + + if(replacebuffer >= BUFFERMAX) replacebuffer = 0; + + userbuffer = replacebuffer; + + + + if(bufferlist[replacebuffer].upsort != 0xffff) { + + RemoveListBuffer(replacebuffer); + + } // ENDIF- Reference already in place? Remove it. + + + + retval = DeviceReadTrack(lsn, mode, bufferlist[replacebuffer].buffer); + + bufferlist[replacebuffer].lsn = lsn; + + bufferlist[replacebuffer].mode = mode; + + bufferlist[replacebuffer].offset = DeviceBufferOffset(); + + + + if(retval != 0) { + + bufferlist[replacebuffer].mode = -1; // Error! flag buffer as such. + + } else { + + if((disctype != CDVD_TYPE_PS2DVD) && (disctype != CDVD_TYPE_DVDV)) { + + if(mode == CDVD_MODE_2352) { + + CDreadSubQ(lsn, &bufferlist[replacebuffer].subq); + + } // ENDIF- Read subq as well? + + } // ENDIF- Read a DVD buffer or a CD buffer? + + } // ENDIF-Read ok? Fill out rest of buffer info. + + AddListBuffer(replacebuffer); + + return(retval); + +} // END CDVDreadTrack() + + + + + +u8* CALLBACK CDVDgetBuffer() { + +#ifdef VERBOSE_FUNCTION_INTERFACE + + PrintLog("CDVDlinuz interface: CDVDgetBuffer()"); + +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + + + if(DiscInserted() == -1) return(NULL); + + + + if(userbuffer == 0xffff) { + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVDlinuz interface: Not pointing to a buffer!"); + +#endif /* VERBOSE_WARNINGS */ + + return(NULL); // No buffer reference? + + } // ENDIF- user buffer not pointing at anything? Abort + + + + if(bufferlist[userbuffer].mode < 0) { + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVDlinuz interface: Error retrieving sector (ReadTrack call)"); + +#endif /* VERBOSE_WARNINGS */ + + return(NULL); // Bad Sector? + + } // ENDIF- Trouble reading physical sector? Tell them. + + + + return(bufferlist[userbuffer].buffer + bufferlist[userbuffer].offset); + +} // END CDVDgetBuffer() + + + + + +s32 CALLBACK CDVDgetDiskType() { + +#ifdef VERBOSE_FUNCTION_INTERFACE + + PrintLog("CDVDlinuz interface: CDVDgetDiskType()"); + +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + + + if(lasttime != time(NULL)) { + + lasttime = time(NULL); + + DeviceTrayStatus(); + + } // ENDIF- Has enough time passed between calls? + + + + return(disctype); + +} // END CDVDgetDiskType() + + + + + +s32 CALLBACK CDVDgetTrayStatus() { + +#ifdef VERBOSE_FUNCTION_INTERFACE + + PrintLog("CDVDlinuz interface: CDVDgetTrayStatus()"); + +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + + + if(lasttime != time(NULL)) { + + lasttime = time(NULL); + + DeviceTrayStatus(); + + } // ENDIF- Has enough time passed between calls? + + + + return(traystatus); + +} // END CDVDgetTrayStatus() + + + + + +s32 CALLBACK CDVDctrlTrayOpen() { + +#ifdef VERBOSE_FUNCTION_INTERFACE + + PrintLog("CDVDlinuz interface: CDVDctrlTrayOpen()"); + +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + + + return(DeviceTrayOpen()); + +} // END CDVDctrlTrayOpen() + + + + + +s32 CALLBACK CDVDctrlTrayClose() { + +#ifdef VERBOSE_FUNCTION_INTERFACE + + PrintLog("CDVDlinuz interface: CDVDctrlTrayClose()"); + +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + + + return(DeviceTrayClose()); + +} // END CDVDctrlTrayClose() + + + + + +s32 CALLBACK CDVDtest() { + + int retval; + + + + errno = 0; + + + + if(devicehandle != NULL) { + +#ifdef VERBOSE_WARNINGS + + PrintLog("CDVDlinuz interface: Device already open"); + +#endif /* VERBOSE_WARNINGS */ + + return(0); + + } // ENDIF- Is the CD/DVD already in use? That's fine. + + + +#ifdef VERBOSE_FUNCTION_INTERFACE + + PrintLog("CDVDlinuz interface: CDVDtest()"); + +#endif /* VERBOSE_FUNCTION_INTERFACE */ + + + + retval = DeviceOpen(); + + DeviceClose(); + + return(retval); + +} // END CDVDtest() + + + + + +void CALLBACK CDVDconfigure() { + + HWND lastwindow; + + + + lastwindow = GetActiveWindow(); + + DialogBox(progmodule, + + MAKEINTRESOURCE(DLG_0200), + + lastwindow, + + (DLGPROC)MainBoxCallback); + + SetActiveWindow(lastwindow); + + lastwindow = NULL; + + return; + +} // END CDVDconfigure() + + + + + +BOOL CALLBACK AboutCallback(HWND window, UINT msg, WPARAM param, LPARAM param2) { + + switch(msg) { + + case WM_COMMAND: + + switch(LOWORD(param)) { + + case IDC_0104: // "Ok" Button + + EndDialog(window, FALSE); + + return(TRUE); + + break; + + } // ENDSWITCH param- Which Windows Message Command? + + + + case WM_CLOSE: + + EndDialog(window, FALSE); + + return(TRUE); + + break; + + } // ENDSWITCH msg- what message has been sent to this window? + + + + return(FALSE); // Not a recognisable message. Pass it back to the OS. + +} // END AboutCallback() + + + +void CALLBACK CDVDabout() { + + HWND lastwindow; + + + + lastwindow = GetActiveWindow(); + + DialogBox(progmodule, + + MAKEINTRESOURCE(DLG_0100), + + lastwindow, + + (DLGPROC)AboutCallback); + + SetActiveWindow(lastwindow); + + return; + +} // END CDVDabout() + diff --git a/plugins/CDVDlinuz/Src/Win32/CDVDlinuz.h b/plugins/CDVDlinuz/Src/Win32/CDVDlinuz.h index e93973fa68..0d55d3bda6 100644 --- a/plugins/CDVDlinuz/Src/Win32/CDVDlinuz.h +++ b/plugins/CDVDlinuz/Src/Win32/CDVDlinuz.h @@ -1,40 +1,80 @@ -/* CDVDlinuz.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef CDVDLINUZ_H -#define CDVDLINUZ_H - - -#include // HINSTANCE - - -// #define VERBOSE_WARNINGS -// #define VERBOSE_FUNCTION_INTERFACE -#define VERBOSE_DISC_INFO -#define VERBOSE_DISC_TYPE - -#define READ_AHEAD_BUFFERS 32 - - -extern HINSTANCE progmodule; - - -#endif /* CDVDLINUZ_H */ +/* CDVDlinuz.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef CDVDLINUZ_H + +#define CDVDLINUZ_H + + + + + +#include // HINSTANCE + + + + + +// #define VERBOSE_WARNINGS + +// #define VERBOSE_FUNCTION_INTERFACE + +#define VERBOSE_DISC_INFO + +#define VERBOSE_DISC_TYPE + + + +#define READ_AHEAD_BUFFERS 32 + + + + + +extern HINSTANCE progmodule; + + + + + +#endif /* CDVDLINUZ_H */ + diff --git a/plugins/CDVDlinuz/Src/Win32/DVD.c b/plugins/CDVDlinuz/Src/Win32/DVD.c index 92854d6a5b..b69affde76 100644 --- a/plugins/CDVDlinuz/Src/Win32/DVD.c +++ b/plugins/CDVDlinuz/Src/Win32/DVD.c @@ -1,398 +1,796 @@ -/* DVD.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include -#include // IOCTL_DVD... - -#include // off64_t - -#define CDVDdefs -#include "PS2Edefs.h" - -#include "logfile.h" -#include "device.h" // FinishCommand() - - -struct { - DVD_DESCRIPTOR_HEADER h; - DVD_LAYER_DESCRIPTOR d; -} layer; -// DVD_LAYER_DESCRIPTOR layer; -// DVD_COPYRIGHT_DESCRIPTOR copyright; -// DVD_DISK_KEY_DESCRIPTOR disckey; -// DVD_BCA_DESCRIPTOR bca; -// DVD_MANUFACTURER_DESCRIPTOR manufact; - - -void InitDVDInfo() { - layer.d.EndDataSector = 0; -} // END InitDVDInfo() - - -s32 DVDGetStructures() { - DVD_SESSION_ID sessionid; - DVD_READ_STRUCTURE request; - DWORD byteswritten; - BOOL boolresult; - DWORD errcode; - s32 retval; - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDlinuz DVD: DVDgetStructures()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - boolresult = DeviceIoControl(devicehandle, - IOCTL_DVD_START_SESSION, - NULL, - 0, - &sessionid, - sizeof(DVD_SESSION_ID), - &byteswritten, - &waitevent); - errcode = FinishCommand(boolresult); - if(errcode != 0) { -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDlinuz DVD: Couldn't start session!"); - PrintError("CDVDlinuz DVD", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - return(-1); - } // ENDIF- Couldn't start a user session on the DVD drive? Fail. - - request.BlockByteOffset.QuadPart = 0; - request.Format = DvdPhysicalDescriptor; - request.SessionId = sessionid; - request.LayerNumber = 0; - retval = 0; - boolresult = DeviceIoControl(devicehandle, - IOCTL_DVD_READ_STRUCTURE, - &request, - sizeof(DVD_READ_STRUCTURE), - &layer, - sizeof(layer), - &byteswritten, - &waitevent); - errcode = FinishCommand(boolresult); - if(errcode != 0) { -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDlinuz DVD: Couldn't get layer data!"); - PrintError("CDVDlinuz DVD", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - retval = -1; - } // ENDIF- Couldn't get layer data? (Including DVD size) Abort. - -#ifdef VERBOSE_DISC_INFO - switch(layer.d.BookType) { - case 0: - PrintLog("CDVDlinuz DVD: Book Type: DVD-ROM"); - break; - case 1: - PrintLog("CDVDlinuz DVD: Book Type: DVD-RAM"); - break; - case 2: - PrintLog("CDVDlinuz DVD: Book Type: DVD-R"); - break; - case 3: - PrintLog("CDVDlinuz DVD: Book Type: DVD-RW"); - break; - case 9: - PrintLog("CDVDlinuz DVD: Book Type: DVD+RW"); - break; - default: - PrintLog("CDVDlinuz DVD: Book Type: Unknown (%i)", layer.d.BookType); - break; - } // ENDSWITCH- Displaying the Book Type - PrintLog("CDVDlinuz DVD: Book Version %i", layer.d.BookVersion); - switch(layer.d.MinimumRate) { - case 0: - PrintLog("CDVDlinuz DVD: Use Minimum Rate for: DVD-ROM"); - break; - case 1: - PrintLog("CDVDlinuz DVD: Use Minimum Rate for: DVD-RAM"); - break; - case 2: - PrintLog("CDVDlinuz DVD: Use Minimum Rate for: DVD-R"); - break; - case 3: - PrintLog("CDVDlinuz DVD: Use Minimum Rate for: DVD-RW"); - break; - case 9: - PrintLog("CDVDlinuz DVD: Use Minimum Rate for: DVD+RW"); - break; - default: - PrintLog("CDVDlinuz DVD: Use Minimum Rate for: Unknown (%i)", layer.d.MinimumRate); - break; - } // ENDSWITCH- Displaying the Minimum (Spin?) Rate - switch(layer.d.DiskSize) { - case 0: - PrintLog("CDVDlinuz DVD: Physical Disk Size: 120mm"); - break; - case 1: - PrintLog("CDVDlinuz DVD: Physical Disk Size: 80mm"); - break; - default: - PrintLog("CDVDlinuz DVD: Physical Disk Size: Unknown (%i)", layer.d.DiskSize); - break; - } // ENDSWITCH- What's the Disk Size? - switch(layer.d.LayerType) { - case 1: - PrintLog("CDVDlinuz DVD: Layer Type: Read-Only"); - break; - case 2: - PrintLog("CDVDlinuz DVD: Layer Type: Recordable"); - break; - case 4: - PrintLog("CDVDlinuz DVD: Layer Type: Rewritable"); - break; - default: - PrintLog("CDVDlinuz DVD: Layer Type: Unknown (%i)", layer.d.LayerType); - break; - } // ENDSWITCH- Displaying the Layer Type - switch(layer.d.TrackPath) { - case 0: - PrintLog("CDVDlinuz DVD: Track Path: PTP"); - break; - case 1: - PrintLog("CDVDlinuz DVD: Track Path: OTP"); - break; - default: - PrintLog("CDVDlinuz DVD: Track Path: Unknown (%i)", layer.d.TrackPath); - break; - } // ENDSWITCH- What's Track Path Layout? - PrintLog("CDVDlinuz DVD: Number of Layers: %i", layer.d.NumberOfLayers + 1); - switch(layer.d.TrackDensity) { - case 0: - PrintLog("CDVDlinuz DVD: Track Density: .74 m/track"); - break; - case 1: - PrintLog("CDVDlinuz DVD: Track Density: .8 m/track"); - break; - case 2: - PrintLog("CDVDlinuz DVD: Track Density: .615 m/track"); - break; - default: - PrintLog("CDVDlinuz DVD: Track Density: Unknown (%i)", layer.d.TrackDensity); - break; - } // ENDSWITCH- Displaying the Layer Type - switch(layer.d.LinearDensity) { - case 0: - PrintLog("CDVDlinuz DVD: Linear Density: .267 m/bit"); - break; - case 1: - PrintLog("CDVDlinuz DVD: Linear Density: .293 m/bit"); - break; - case 2: - PrintLog("CDVDlinuz DVD: Linear Density: .409 to .435 m/bit"); - break; - case 4: - PrintLog("CDVDlinuz DVD: Linear Density: .280 to .291 m/bit"); - break; - case 8: - PrintLog("CDVDlinuz DVD: Linear Density: .353 m/bit"); - break; - default: - PrintLog("CDVDlinuz DVD: Linear Density: Unknown (%i)", layer.d.LinearDensity); - break; - } // ENDSWITCH- Displaying the Book Type - if(layer.d.StartingDataSector == 0x30000) { - PrintLog("CDVDlinuz DVD: Starting Sector: %lu (DVD-ROM, DVD-R, DVD-RW)", - layer.d.StartingDataSector); - } else if(layer.d.StartingDataSector == 0x31000) { - PrintLog("CDVDlinuz DVD: Starting Sector: %lu (DVD-RAM, DVD+RW)", - layer.d.StartingDataSector); - } else { - PrintLog("CDVDlinuz DVD: Starting Sector: %lu", layer.d.StartingDataSector); - } // ENDLONGIF- What does the starting sector tell us? - PrintLog("CDVDlinuz DVD: End of Layer 0: %lu", layer.d.EndLayerZeroSector); - PrintLog("CDVDlinuz DVD: Ending Sector: %lu", layer.d.EndDataSector); - if(layer.d.BCAFlag != 0) PrintLog("CDVDlinuz DVD: BCA data present"); -#endif /* VERBOSE_DISC_INFO */ - - boolresult = DeviceIoControl(devicehandle, - IOCTL_DVD_END_SESSION, - &sessionid, - sizeof(DVD_SESSION_ID), - NULL, - 0, - &byteswritten, - &waitevent); - errcode = FinishCommand(boolresult); - if(errcode != 0) { -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDlinuz DVD: Couldn't end the session!"); - PrintError("CDVDlinuz DVD", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - } // ENDIF- Couldn't end the user session? Report it. - - return(retval); -} // END DVDGetStructures() - - -s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer) { - LARGE_INTEGER targetpos; - DWORD byteswritten; - BOOL boolresult; - DWORD errcode; - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDlinuz DVD: DVDreadTrack(%lu)", lsn); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - targetpos.QuadPart = lsn * 2048; - waitevent.Offset = targetpos.LowPart; - waitevent.OffsetHigh = targetpos.HighPart; - - boolresult = ReadFile(devicehandle, - buffer, - 2048, - &byteswritten, - &waitevent); - errcode = FinishCommand(boolresult); - - if(errcode != 0) { -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDlinuz DVD: Couldn't read sector!"); - PrintError("CDVDlinuz DVD", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - return(-1); - } // ENDIF- Trouble with the command? Report it. - - if(boolresult == FALSE) { - boolresult = GetOverlappedResult(devicehandle, - &waitevent, - &byteswritten, - FALSE); - } // ENDIF- Did the initial call not complete? Get byteswritten for - // the completed call. - - if(byteswritten < 2048) { -#ifdef VERBOSE_WARNING_DEVICE - errcode = GetLastError(); - PrintLog("CDVDlinuz CD: Short block! only got %u out of %u bytes", - byteswritten, 2048); - PrintError("CDVDlinuz CD", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - return(-1); - } // ENDIF- Didn't get enough bytes? Report and Abort! - - return(0); -} // END DVDreadTrack() - - -s32 DVDgetTN(cdvdTN *cdvdtn) { -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDlinuz DVD: DVDgetTN()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - if(cdvdtn != NULL) { - cdvdtn->strack = 1; - cdvdtn->etrack = 1; - } // ENDIF- Does the user really want this data? - return(0); -} // END DVDgetTN() - - -s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd) { -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDlinuz DVD: DVDgetTD()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - if((newtrack >= 2) && (newtrack != 0xAA)) return(-1); // Wrong track - - if(cdvdtd != NULL) { - cdvdtd->type = 0; - cdvdtd->lsn = layer.d.EndDataSector - layer.d.StartingDataSector + 1; - } // ENDIF- Does the user really want this data? - return(0); -} // END DVDgetTD() - - -s32 DVDgetDiskType() { - char playstationname[] = "PLAYSTATION\0"; - int retval; - s32 tempdisctype; - char tempbuffer[2048]; - int i; - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDlinuz DVD: DVDgetDiskType()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - retval = DVDGetStructures(); - if(retval < 0) return(-1); // Can't get DVD structures? Not a DVD then. - if(layer.d.EndDataSector == 0) return(-1); // Missing info? Abort. - - retval = DVDreadTrack(16, CDVD_MODE_2048, tempbuffer); - if(retval < 0) { - return(-1); - } // ENDIF- Couldn't read the ISO9660 volume track? Fail. - - tempdisctype = CDVD_TYPE_UNKNOWN; - if(layer.d.NumberOfLayers == 0) { -#ifdef VERBOSE_DISC_INFO - PrintLog("CDVDlinuz DVD: Found Single-Sided DVD."); -#endif /* VERBOSE_DISC_INFO */ - disctype = CDVD_TYPE_DETCTDVDS; - } else { -#ifdef VERBOSE_DISC_INFO - PrintLog("CDVDlinuz DVD: Found Dual-Sided DVD."); -#endif /* VERBOSE_DISC_INFO */ - disctype = CDVD_TYPE_DETCTDVDD; - } // ENDIF- Are we looking at a single layer DVD? (NumberOfLayers + 1) - - i = 0; - while((playstationname[i] != 0) && - (playstationname[i] == tempbuffer[8 + i])) i++; - if(playstationname[i] == 0) { -#ifdef VERBOSE_DISC_TYPE - PrintLog("CDVDlinuz DVD: Found Playstation 2 DVD."); -#endif /* VERBOSE_DISC_TYPE */ - tempdisctype = CDVD_TYPE_PS2DVD; - } else { -#ifdef VERBOSE_DISC_TYPE - PrintLog("CDVDlinuz DVD: Guessing it's a Video DVD."); -#endif /* VERBOSE_DISC_TYPE */ - tempdisctype = CDVD_TYPE_DVDV; - } // ENDIF- Is this a playstation disc? - - for(i = 0; i < 2048; i++) tocbuffer[i] = 0; - - if(layer.d.NumberOfLayers == 0) { - tocbuffer[0] = 0x04; - tocbuffer[4] = 0x86; - tocbuffer[5] = 0x72; - } else { - tocbuffer[0] = 0x24; - tocbuffer[4] = 0x41; - tocbuffer[5] = 0x95; - } // ENDIF- Are we looking at a single layer DVD? (NumberOfLayers + 1) - - tocbuffer[1] = 0x02; - tocbuffer[2] = 0xF2; - tocbuffer[3] = 0x00; - - tocbuffer[16] = 0x00; - tocbuffer[17] = 0x03; - tocbuffer[18] = 0x00; - tocbuffer[19] = 0x00; - - disctype = tempdisctype; - return(disctype); -} // END DVDgetDiskType() +/* DVD.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + +#include // IOCTL_DVD... + + + +#include // off64_t + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + +#include "logfile.h" + +#include "device.h" // FinishCommand() + + + + + +struct { + + DVD_DESCRIPTOR_HEADER h; + + DVD_LAYER_DESCRIPTOR d; + +} layer; + +// DVD_LAYER_DESCRIPTOR layer; + +// DVD_COPYRIGHT_DESCRIPTOR copyright; + +// DVD_DISK_KEY_DESCRIPTOR disckey; + +// DVD_BCA_DESCRIPTOR bca; + +// DVD_MANUFACTURER_DESCRIPTOR manufact; + + + + + +void InitDVDInfo() { + + layer.d.EndDataSector = 0; + +} // END InitDVDInfo() + + + + + +s32 DVDGetStructures() { + + DVD_SESSION_ID sessionid; + + DVD_READ_STRUCTURE request; + + DWORD byteswritten; + + BOOL boolresult; + + DWORD errcode; + + s32 retval; + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDlinuz DVD: DVDgetStructures()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_DVD_START_SESSION, + + NULL, + + 0, + + &sessionid, + + sizeof(DVD_SESSION_ID), + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDlinuz DVD: Couldn't start session!"); + + PrintError("CDVDlinuz DVD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Couldn't start a user session on the DVD drive? Fail. + + + + request.BlockByteOffset.QuadPart = 0; + + request.Format = DvdPhysicalDescriptor; + + request.SessionId = sessionid; + + request.LayerNumber = 0; + + retval = 0; + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_DVD_READ_STRUCTURE, + + &request, + + sizeof(DVD_READ_STRUCTURE), + + &layer, + + sizeof(layer), + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDlinuz DVD: Couldn't get layer data!"); + + PrintError("CDVDlinuz DVD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + retval = -1; + + } // ENDIF- Couldn't get layer data? (Including DVD size) Abort. + + + +#ifdef VERBOSE_DISC_INFO + + switch(layer.d.BookType) { + + case 0: + + PrintLog("CDVDlinuz DVD: Book Type: DVD-ROM"); + + break; + + case 1: + + PrintLog("CDVDlinuz DVD: Book Type: DVD-RAM"); + + break; + + case 2: + + PrintLog("CDVDlinuz DVD: Book Type: DVD-R"); + + break; + + case 3: + + PrintLog("CDVDlinuz DVD: Book Type: DVD-RW"); + + break; + + case 9: + + PrintLog("CDVDlinuz DVD: Book Type: DVD+RW"); + + break; + + default: + + PrintLog("CDVDlinuz DVD: Book Type: Unknown (%i)", layer.d.BookType); + + break; + + } // ENDSWITCH- Displaying the Book Type + + PrintLog("CDVDlinuz DVD: Book Version %i", layer.d.BookVersion); + + switch(layer.d.MinimumRate) { + + case 0: + + PrintLog("CDVDlinuz DVD: Use Minimum Rate for: DVD-ROM"); + + break; + + case 1: + + PrintLog("CDVDlinuz DVD: Use Minimum Rate for: DVD-RAM"); + + break; + + case 2: + + PrintLog("CDVDlinuz DVD: Use Minimum Rate for: DVD-R"); + + break; + + case 3: + + PrintLog("CDVDlinuz DVD: Use Minimum Rate for: DVD-RW"); + + break; + + case 9: + + PrintLog("CDVDlinuz DVD: Use Minimum Rate for: DVD+RW"); + + break; + + default: + + PrintLog("CDVDlinuz DVD: Use Minimum Rate for: Unknown (%i)", layer.d.MinimumRate); + + break; + + } // ENDSWITCH- Displaying the Minimum (Spin?) Rate + + switch(layer.d.DiskSize) { + + case 0: + + PrintLog("CDVDlinuz DVD: Physical Disk Size: 120mm"); + + break; + + case 1: + + PrintLog("CDVDlinuz DVD: Physical Disk Size: 80mm"); + + break; + + default: + + PrintLog("CDVDlinuz DVD: Physical Disk Size: Unknown (%i)", layer.d.DiskSize); + + break; + + } // ENDSWITCH- What's the Disk Size? + + switch(layer.d.LayerType) { + + case 1: + + PrintLog("CDVDlinuz DVD: Layer Type: Read-Only"); + + break; + + case 2: + + PrintLog("CDVDlinuz DVD: Layer Type: Recordable"); + + break; + + case 4: + + PrintLog("CDVDlinuz DVD: Layer Type: Rewritable"); + + break; + + default: + + PrintLog("CDVDlinuz DVD: Layer Type: Unknown (%i)", layer.d.LayerType); + + break; + + } // ENDSWITCH- Displaying the Layer Type + + switch(layer.d.TrackPath) { + + case 0: + + PrintLog("CDVDlinuz DVD: Track Path: PTP"); + + break; + + case 1: + + PrintLog("CDVDlinuz DVD: Track Path: OTP"); + + break; + + default: + + PrintLog("CDVDlinuz DVD: Track Path: Unknown (%i)", layer.d.TrackPath); + + break; + + } // ENDSWITCH- What's Track Path Layout? + + PrintLog("CDVDlinuz DVD: Number of Layers: %i", layer.d.NumberOfLayers + 1); + + switch(layer.d.TrackDensity) { + + case 0: + + PrintLog("CDVDlinuz DVD: Track Density: .74 m/track"); + + break; + + case 1: + + PrintLog("CDVDlinuz DVD: Track Density: .8 m/track"); + + break; + + case 2: + + PrintLog("CDVDlinuz DVD: Track Density: .615 m/track"); + + break; + + default: + + PrintLog("CDVDlinuz DVD: Track Density: Unknown (%i)", layer.d.TrackDensity); + + break; + + } // ENDSWITCH- Displaying the Layer Type + + switch(layer.d.LinearDensity) { + + case 0: + + PrintLog("CDVDlinuz DVD: Linear Density: .267 m/bit"); + + break; + + case 1: + + PrintLog("CDVDlinuz DVD: Linear Density: .293 m/bit"); + + break; + + case 2: + + PrintLog("CDVDlinuz DVD: Linear Density: .409 to .435 m/bit"); + + break; + + case 4: + + PrintLog("CDVDlinuz DVD: Linear Density: .280 to .291 m/bit"); + + break; + + case 8: + + PrintLog("CDVDlinuz DVD: Linear Density: .353 m/bit"); + + break; + + default: + + PrintLog("CDVDlinuz DVD: Linear Density: Unknown (%i)", layer.d.LinearDensity); + + break; + + } // ENDSWITCH- Displaying the Book Type + + if(layer.d.StartingDataSector == 0x30000) { + + PrintLog("CDVDlinuz DVD: Starting Sector: %lu (DVD-ROM, DVD-R, DVD-RW)", + + layer.d.StartingDataSector); + + } else if(layer.d.StartingDataSector == 0x31000) { + + PrintLog("CDVDlinuz DVD: Starting Sector: %lu (DVD-RAM, DVD+RW)", + + layer.d.StartingDataSector); + + } else { + + PrintLog("CDVDlinuz DVD: Starting Sector: %lu", layer.d.StartingDataSector); + + } // ENDLONGIF- What does the starting sector tell us? + + PrintLog("CDVDlinuz DVD: End of Layer 0: %lu", layer.d.EndLayerZeroSector); + + PrintLog("CDVDlinuz DVD: Ending Sector: %lu", layer.d.EndDataSector); + + if(layer.d.BCAFlag != 0) PrintLog("CDVDlinuz DVD: BCA data present"); + +#endif /* VERBOSE_DISC_INFO */ + + + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_DVD_END_SESSION, + + &sessionid, + + sizeof(DVD_SESSION_ID), + + NULL, + + 0, + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDlinuz DVD: Couldn't end the session!"); + + PrintError("CDVDlinuz DVD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + } // ENDIF- Couldn't end the user session? Report it. + + + + return(retval); + +} // END DVDGetStructures() + + + + + +s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer) { + + LARGE_INTEGER targetpos; + + DWORD byteswritten; + + BOOL boolresult; + + DWORD errcode; + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDlinuz DVD: DVDreadTrack(%lu)", lsn); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + targetpos.QuadPart = lsn * 2048; + + waitevent.Offset = targetpos.LowPart; + + waitevent.OffsetHigh = targetpos.HighPart; + + + + boolresult = ReadFile(devicehandle, + + buffer, + + 2048, + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDlinuz DVD: Couldn't read sector!"); + + PrintError("CDVDlinuz DVD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Trouble with the command? Report it. + + + + if(boolresult == FALSE) { + + boolresult = GetOverlappedResult(devicehandle, + + &waitevent, + + &byteswritten, + + FALSE); + + } // ENDIF- Did the initial call not complete? Get byteswritten for + + // the completed call. + + + + if(byteswritten < 2048) { + +#ifdef VERBOSE_WARNING_DEVICE + + errcode = GetLastError(); + + PrintLog("CDVDlinuz CD: Short block! only got %u out of %u bytes", + + byteswritten, 2048); + + PrintError("CDVDlinuz CD", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Didn't get enough bytes? Report and Abort! + + + + return(0); + +} // END DVDreadTrack() + + + + + +s32 DVDgetTN(cdvdTN *cdvdtn) { + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDlinuz DVD: DVDgetTN()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + if(cdvdtn != NULL) { + + cdvdtn->strack = 1; + + cdvdtn->etrack = 1; + + } // ENDIF- Does the user really want this data? + + return(0); + +} // END DVDgetTN() + + + + + +s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd) { + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDlinuz DVD: DVDgetTD()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + if((newtrack >= 2) && (newtrack != 0xAA)) return(-1); // Wrong track + + + + if(cdvdtd != NULL) { + + cdvdtd->type = 0; + + cdvdtd->lsn = layer.d.EndDataSector - layer.d.StartingDataSector + 1; + + } // ENDIF- Does the user really want this data? + + return(0); + +} // END DVDgetTD() + + + + + +s32 DVDgetDiskType() { + + char playstationname[] = "PLAYSTATION\0"; + + int retval; + + s32 tempdisctype; + + char tempbuffer[2048]; + + int i; + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDlinuz DVD: DVDgetDiskType()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + retval = DVDGetStructures(); + + if(retval < 0) return(-1); // Can't get DVD structures? Not a DVD then. + + if(layer.d.EndDataSector == 0) return(-1); // Missing info? Abort. + + + + retval = DVDreadTrack(16, CDVD_MODE_2048, tempbuffer); + + if(retval < 0) { + + return(-1); + + } // ENDIF- Couldn't read the ISO9660 volume track? Fail. + + + + tempdisctype = CDVD_TYPE_UNKNOWN; + + if(layer.d.NumberOfLayers == 0) { + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVDlinuz DVD: Found Single-Sided DVD."); + +#endif /* VERBOSE_DISC_INFO */ + + disctype = CDVD_TYPE_DETCTDVDS; + + } else { + +#ifdef VERBOSE_DISC_INFO + + PrintLog("CDVDlinuz DVD: Found Dual-Sided DVD."); + +#endif /* VERBOSE_DISC_INFO */ + + disctype = CDVD_TYPE_DETCTDVDD; + + } // ENDIF- Are we looking at a single layer DVD? (NumberOfLayers + 1) + + + + i = 0; + + while((playstationname[i] != 0) && + + (playstationname[i] == tempbuffer[8 + i])) i++; + + if(playstationname[i] == 0) { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("CDVDlinuz DVD: Found Playstation 2 DVD."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_PS2DVD; + + } else { + +#ifdef VERBOSE_DISC_TYPE + + PrintLog("CDVDlinuz DVD: Guessing it's a Video DVD."); + +#endif /* VERBOSE_DISC_TYPE */ + + tempdisctype = CDVD_TYPE_DVDV; + + } // ENDIF- Is this a playstation disc? + + + + for(i = 0; i < 2048; i++) tocbuffer[i] = 0; + + + + if(layer.d.NumberOfLayers == 0) { + + tocbuffer[0] = 0x04; + + tocbuffer[4] = 0x86; + + tocbuffer[5] = 0x72; + + } else { + + tocbuffer[0] = 0x24; + + tocbuffer[4] = 0x41; + + tocbuffer[5] = 0x95; + + } // ENDIF- Are we looking at a single layer DVD? (NumberOfLayers + 1) + + + + tocbuffer[1] = 0x02; + + tocbuffer[2] = 0xF2; + + tocbuffer[3] = 0x00; + + + + tocbuffer[16] = 0x00; + + tocbuffer[17] = 0x03; + + tocbuffer[18] = 0x00; + + tocbuffer[19] = 0x00; + + + + disctype = tempdisctype; + + return(disctype); + +} // END DVDgetDiskType() + diff --git a/plugins/CDVDlinuz/Src/Win32/DVD.h b/plugins/CDVDlinuz/Src/Win32/DVD.h index 3876101750..b6d05d0e29 100644 --- a/plugins/CDVDlinuz/Src/Win32/DVD.h +++ b/plugins/CDVDlinuz/Src/Win32/DVD.h @@ -1,37 +1,74 @@ -/* DVD.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef DVD_H -#define DVD_H - - -#define CDVDdefs -#include "PS2Edefs.h" - - -extern void InitDVDInfo(); -extern s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer); -extern s32 DVDgetTN(cdvdTN *cdvdtn); -extern s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd); -extern s32 DVDgetDiskType(); - - -#endif /* DVD_H */ +/* DVD.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef DVD_H + +#define DVD_H + + + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + + + +extern void InitDVDInfo(); + +extern s32 DVDreadTrack(u32 lsn, int mode, u8 *buffer); + +extern s32 DVDgetTN(cdvdTN *cdvdtn); + +extern s32 DVDgetTD(u8 newtrack, cdvdTD *cdvdtd); + +extern s32 DVDgetDiskType(); + + + + + +#endif /* DVD_H */ + diff --git a/plugins/CDVDlinuz/Src/Win32/Makefile.MinGW32 b/plugins/CDVDlinuz/Src/Win32/Makefile.MinGW32 deleted file mode 100644 index f3cf50c2e4..0000000000 --- a/plugins/CDVDlinuz/Src/Win32/Makefile.MinGW32 +++ /dev/null @@ -1,43 +0,0 @@ - -PLUGIN = CDVDlinuz.dll -PLUGINOBJS = CDVDlinuz.o mainbox.o -PLUGINHEADERS = CDVDlinuz.h mainbox.h -PLUGINFLAGS = -Wall -O2 -D_LARGEFILE64_SOURCE -I.. -I. -I.\\Win32 -PLUGINLIBS = - -# In this case, SHARED marks files that don't need Windows Display components -SHAREDOBJS = device.o CD.o DVD.o logfile.o actualfile.o conf.o \ - ..\\ini.o ..\\buffer.o ..\\version.o ..\\convert.o -SHAREDHEADERS = device.h CD.h DVD.h logfile.h actualfile.h conf.h \ - ..\\ini.h ..\\buffer.h ..\\version.h ..\\convert.h - - -CC = mingw32-gcc.exe -WINDRES = windres.exe - - -all: plugin - -release: plugin - copy $(PLUGIN) ..\\.. - -plugin: $(PLUGINOBJS) $(SHAREDOBJS) screens.res - -del $(PLUGIN) - dllwrap --def plugin.def -o $(PLUGIN) $(PLUGINOBJS) screens.res $(SHAREDOBJS) $(PLUGINLIBS) - strip --strip-unneeded --strip-debug $(PLUGIN) - -$(PLUGINOBJS) $(SHAREDOBJS): %.o: %.c - $(CC) $(PLUGINFLAGS) -c $< -o $@ - -screens.res: screens.rc - $(WINDRES) -i screens.rc -J rc -o screens.res -O coff - -.PHONY : clean allclean -clean: - -del $(PLUGINOBJS) $(PLUGIN) $(SHAREDOBJS) screens.res - -allclean: - -del $(PLUGINOBJS) $(PLUGIN) $(SHAREDOBJS) screens.res - -del temp.txt err.txt ..\\temp.txt ..\\err.txt - -del ..\\..\\$(PLUGIN) - diff --git a/plugins/CDVDlinuz/Src/Win32/actualfile.c b/plugins/CDVDlinuz/Src/Win32/actualfile.c index b2a5f23c2c..7212d1e1c1 100644 --- a/plugins/CDVDlinuz/Src/Win32/actualfile.c +++ b/plugins/CDVDlinuz/Src/Win32/actualfile.c @@ -1,253 +1,506 @@ -/* actualfile.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include - -#include // NULL - -#include "logfile.h" -#include "actualfile.h" - - -int IsActualFile(const char *filename) { - DWORD retval; - - if(filename == NULL) return(-1); - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: IsActualFile(%s)", filename); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - retval = GetFileAttributes(filename); - if(retval == INVALID_FILE_ATTRIBUTES) return(-1); // Name doesn't exist. - if((retval & FILE_ATTRIBUTE_DIRECTORY) != 0) return(-2); - - return(0); // Yep, that's a file. -} // END IsActualFile() - - -void ActualFileDelete(const char *filename) { -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileDelete(%s)", filename); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - DeleteFile(filename); -} // END ActualFileDelete() - - -void ActualFileRename(const char *origname, const char *newname) { -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileDelete(%s->%s)", origname, newname); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - MoveFile(origname, newname); - return; -} // END ActualFileRename() - - -ACTUALHANDLE ActualFileOpenForRead(const char *filename) { - HANDLE newhandle; - - if(filename == NULL) return(NULL); - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileOpenForRead(%s)", filename); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - newhandle = CreateFile(filename, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_FLAG_RANDOM_ACCESS, - NULL); - if(newhandle == INVALID_HANDLE_VALUE) { -#ifdef VERBOSE_WARNING_ACTUALFILE - PrintLog("CDVDiso file: Error opening file %s", filename); -#endif /* VERBOSE_WARNING_ACTUALFILE */ - return(NULL); - } // ENDIF- Error? Abort - - return(newhandle); -} // END ActualFileOpenForRead() - - -off64_t ActualFileSize(ACTUALHANDLE handle) { - int retval; - BY_HANDLE_FILE_INFORMATION info; - off64_t retsize; - - if(handle == NULL) return(-1); - if(handle == INVALID_HANDLE_VALUE) return(-1); - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileSize()"); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - retval = GetFileInformationByHandle(handle, &info); - if(retval == 0) return(-1); // Handle doesn't exist... - - retsize = info.nFileSizeHigh; - retsize *= 0x10000; - retsize *= 0x10000; - retsize += info.nFileSizeLow; - return(retsize); -} // END ActualFileSize() - - -int ActualFileSeek(ACTUALHANDLE handle, off64_t position) { - // int retval; - LARGE_INTEGER realpos; - DWORD errcode; - - if(handle == NULL) return(-1); - if(handle == INVALID_HANDLE_VALUE) return(-1); - if(position < 0) return(-1); - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileSeek(%llu)", position); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - realpos.QuadPart = position; -////// WinXP code for seek -// retval = SetFilePointerEx(handle, -// realpos, -// NULL, -// FILE_BEGIN); -// if(retval == 0) { - -////// Win98 code for seek - realpos.LowPart = SetFilePointer(handle, - realpos.LowPart, - &realpos.HighPart, - FILE_BEGIN); - errcode = GetLastError(); - if((realpos.LowPart == 0xFFFFFFFF) && (errcode != NO_ERROR)) { - -#ifdef VERBOSE_WARNING_ACTUALFILE - PrintLog("CDVDiso file: Error on seek (%llu)", position); - PrintError("CDVDiso file", errcode); -#endif /* VERBOSE_WARNING_ACTUALFILE */ - return(-1); - } // ENDIF- Error? Abort - - return(0); -} // END ActualFileSeek() - - -int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer) { - int retval; - DWORD bytesread; -#ifdef VERBOSE_WARNING_ACTUALFILE - DWORD errcode; -#endif /* VERBOSE_WARNING_ACTUALFILE */ - - if(handle == NULL) return(-1); - if(handle == INVALID_HANDLE_VALUE) return(-1); - if(bytes < 1) return(-1); - if(buffer == NULL) return(-1); - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileRead(%i)", bytes); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - retval = ReadFile(handle, buffer, bytes, &bytesread, NULL); - if(retval == 0) { -#ifdef VERBOSE_WARNING_ACTUALFILE - errcode = GetLastError(); - PrintLog("CDVDiso file: Error reading from file"); - PrintError("CDVDiso file", errcode); -#endif /* VERBOSE_WARNING_ACTUALFILE */ - return(-1); - } // ENDIF- Error? Abort - if(bytesread < bytes) { -#ifdef VERBOSE_WARNING_ACTUALFILE - PrintLog("CDVDiso file: Short Block! Only read %i out of %i bytes", bytesread, bytes); -#endif /* VERBOSE_WARNING_ACTUALFILE */ - } // ENDIF- Error? Abort - - return(bytesread); // Send back how many bytes read -} // END ActualFileRead() - - -void ActualFileClose(ACTUALHANDLE handle) { - if(handle == NULL) return; - if(handle == INVALID_HANDLE_VALUE) return; - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileClose()"); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - CloseHandle(handle); - return; -} // END ActualFileClose() - - -ACTUALHANDLE ActualFileOpenForWrite(const char *filename) { - HANDLE newhandle; - - if(filename == NULL) return(NULL); - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileOpenForWrite(%s)", filename); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - newhandle = CreateFile(filename, - GENERIC_WRITE, - 0, - NULL, - CREATE_ALWAYS, - FILE_FLAG_SEQUENTIAL_SCAN, - NULL); - if(newhandle == INVALID_HANDLE_VALUE) { -#ifdef VERBOSE_WARNING_ACTUALFILE - PrintLog("CDVDiso file: Error opening file %s", filename); -#endif /* VERBOSE_WARNING_ACTUALFILE */ - return(NULL); - } // ENDIF- Error? Abort - - return(newhandle); -} // END ActualFileOpenForWrite() - - -int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer) { - int retval; - DWORD byteswritten; - - if(handle == NULL) return(-1); - if(handle == INVALID_HANDLE_VALUE) return(-1); - if(bytes < 1) return(-1); - if(buffer == NULL) return(-1); - -#ifdef VERBOSE_FUNCTION_ACTUALFILE - PrintLog("CDVDiso file: ActualFileWrite(%i)", bytes); -#endif /* VERBOSE_FUNCTION_ACTUALFILE */ - - retval = WriteFile(handle, buffer, bytes, &byteswritten, NULL); - if(retval == 0) { -#ifdef VERBOSE_WARNING_ACTUALFILE - PrintLog("CDVDiso file: Error writing to file!"); -#endif /* VERBOSE_WARNING_ACTUALFILE */ - // return(-1); - } // ENDIF- Error? Abort - - return(byteswritten); // Send back how many bytes written -} // END ActualFileWrite() +/* actualfile.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + + + +#include // NULL + + + +#include "logfile.h" + +#include "actualfile.h" + + + + + +int IsActualFile(const char *filename) { + + DWORD retval; + + + + if(filename == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: IsActualFile(%s)", filename); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + retval = GetFileAttributes(filename); + + if(retval == INVALID_FILE_ATTRIBUTES) return(-1); // Name doesn't exist. + + if((retval & FILE_ATTRIBUTE_DIRECTORY) != 0) return(-2); + + + + return(0); // Yep, that's a file. + +} // END IsActualFile() + + + + + +void ActualFileDelete(const char *filename) { + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileDelete(%s)", filename); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + DeleteFile(filename); + +} // END ActualFileDelete() + + + + + +void ActualFileRename(const char *origname, const char *newname) { + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileDelete(%s->%s)", origname, newname); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + MoveFile(origname, newname); + + return; + +} // END ActualFileRename() + + + + + +ACTUALHANDLE ActualFileOpenForRead(const char *filename) { + + HANDLE newhandle; + + + + if(filename == NULL) return(NULL); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileOpenForRead(%s)", filename); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + newhandle = CreateFile(filename, + + GENERIC_READ, + + FILE_SHARE_READ, + + NULL, + + OPEN_EXISTING, + + FILE_FLAG_RANDOM_ACCESS, + + NULL); + + if(newhandle == INVALID_HANDLE_VALUE) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error opening file %s", filename); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + return(NULL); + + } // ENDIF- Error? Abort + + + + return(newhandle); + +} // END ActualFileOpenForRead() + + + + + +off64_t ActualFileSize(ACTUALHANDLE handle) { + + int retval; + + BY_HANDLE_FILE_INFORMATION info; + + off64_t retsize; + + + + if(handle == NULL) return(-1); + + if(handle == INVALID_HANDLE_VALUE) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileSize()"); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + retval = GetFileInformationByHandle(handle, &info); + + if(retval == 0) return(-1); // Handle doesn't exist... + + + + retsize = info.nFileSizeHigh; + + retsize *= 0x10000; + + retsize *= 0x10000; + + retsize += info.nFileSizeLow; + + return(retsize); + +} // END ActualFileSize() + + + + + +int ActualFileSeek(ACTUALHANDLE handle, off64_t position) { + + // int retval; + + LARGE_INTEGER realpos; + + DWORD errcode; + + + + if(handle == NULL) return(-1); + + if(handle == INVALID_HANDLE_VALUE) return(-1); + + if(position < 0) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileSeek(%llu)", position); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + realpos.QuadPart = position; + +////// WinXP code for seek + +// retval = SetFilePointerEx(handle, + +// realpos, + +// NULL, + +// FILE_BEGIN); + +// if(retval == 0) { + + + +////// Win98 code for seek + + realpos.LowPart = SetFilePointer(handle, + + realpos.LowPart, + + &realpos.HighPart, + + FILE_BEGIN); + + errcode = GetLastError(); + + if((realpos.LowPart == 0xFFFFFFFF) && (errcode != NO_ERROR)) { + + + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error on seek (%llu)", position); + + PrintError("CDVDiso file", errcode); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + return(-1); + + } // ENDIF- Error? Abort + + + + return(0); + +} // END ActualFileSeek() + + + + + +int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer) { + + int retval; + + DWORD bytesread; + +#ifdef VERBOSE_WARNING_ACTUALFILE + + DWORD errcode; + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + + + if(handle == NULL) return(-1); + + if(handle == INVALID_HANDLE_VALUE) return(-1); + + if(bytes < 1) return(-1); + + if(buffer == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileRead(%i)", bytes); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + retval = ReadFile(handle, buffer, bytes, &bytesread, NULL); + + if(retval == 0) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + errcode = GetLastError(); + + PrintLog("CDVDiso file: Error reading from file"); + + PrintError("CDVDiso file", errcode); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + return(-1); + + } // ENDIF- Error? Abort + + if(bytesread < bytes) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Short Block! Only read %i out of %i bytes", bytesread, bytes); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + } // ENDIF- Error? Abort + + + + return(bytesread); // Send back how many bytes read + +} // END ActualFileRead() + + + + + +void ActualFileClose(ACTUALHANDLE handle) { + + if(handle == NULL) return; + + if(handle == INVALID_HANDLE_VALUE) return; + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileClose()"); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + CloseHandle(handle); + + return; + +} // END ActualFileClose() + + + + + +ACTUALHANDLE ActualFileOpenForWrite(const char *filename) { + + HANDLE newhandle; + + + + if(filename == NULL) return(NULL); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileOpenForWrite(%s)", filename); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + newhandle = CreateFile(filename, + + GENERIC_WRITE, + + 0, + + NULL, + + CREATE_ALWAYS, + + FILE_FLAG_SEQUENTIAL_SCAN, + + NULL); + + if(newhandle == INVALID_HANDLE_VALUE) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error opening file %s", filename); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + return(NULL); + + } // ENDIF- Error? Abort + + + + return(newhandle); + +} // END ActualFileOpenForWrite() + + + + + +int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer) { + + int retval; + + DWORD byteswritten; + + + + if(handle == NULL) return(-1); + + if(handle == INVALID_HANDLE_VALUE) return(-1); + + if(bytes < 1) return(-1); + + if(buffer == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_ACTUALFILE + + PrintLog("CDVDiso file: ActualFileWrite(%i)", bytes); + +#endif /* VERBOSE_FUNCTION_ACTUALFILE */ + + + + retval = WriteFile(handle, buffer, bytes, &byteswritten, NULL); + + if(retval == 0) { + +#ifdef VERBOSE_WARNING_ACTUALFILE + + PrintLog("CDVDiso file: Error writing to file!"); + +#endif /* VERBOSE_WARNING_ACTUALFILE */ + + // return(-1); + + } // ENDIF- Error? Abort + + + + return(byteswritten); // Send back how many bytes written + +} // END ActualFileWrite() + diff --git a/plugins/CDVDlinuz/Src/Win32/actualfile.h b/plugins/CDVDlinuz/Src/Win32/actualfile.h index 6c215f36ed..63053f440d 100644 --- a/plugins/CDVDlinuz/Src/Win32/actualfile.h +++ b/plugins/CDVDlinuz/Src/Win32/actualfile.h @@ -1,52 +1,104 @@ -/* actualfile.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef ACTUALFILE_H -#define ACTUALFILE_H - - -#include - -#include // off64_t - - -#define ACTUALHANDLE HANDLE -#define ACTUALHANDLENULL NULL - -// #define VERBOSE_FUNCTION_ACTUALFILE -// #define VERBOSE_WARNING_ACTUALFILE - - -extern int IsActualFile(const char *filename); -extern void ActualFileDelete(const char *filename); -extern void ActualFileRename(const char *origname, const char *newname); - -extern ACTUALHANDLE ActualFileOpenForRead(const char *filename); -extern off64_t ActualFileSize(ACTUALHANDLE handle); -extern int ActualFileSeek(ACTUALHANDLE handle, off64_t position); -extern int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer); -extern void ActualFileClose(ACTUALHANDLE handle); - -extern ACTUALHANDLE ActualFileOpenForWrite(const char *filename); -extern int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer); - - -#endif /* ACTUALFILE_H */ +/* actualfile.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef ACTUALFILE_H + +#define ACTUALFILE_H + + + + + +#include + + + +#include // off64_t + + + + + +#define ACTUALHANDLE HANDLE + +#define ACTUALHANDLENULL NULL + + + +// #define VERBOSE_FUNCTION_ACTUALFILE + +// #define VERBOSE_WARNING_ACTUALFILE + + + + + +extern int IsActualFile(const char *filename); + +extern void ActualFileDelete(const char *filename); + +extern void ActualFileRename(const char *origname, const char *newname); + + + +extern ACTUALHANDLE ActualFileOpenForRead(const char *filename); + +extern off64_t ActualFileSize(ACTUALHANDLE handle); + +extern int ActualFileSeek(ACTUALHANDLE handle, off64_t position); + +extern int ActualFileRead(ACTUALHANDLE handle, int bytes, char *buffer); + +extern void ActualFileClose(ACTUALHANDLE handle); + + + +extern ACTUALHANDLE ActualFileOpenForWrite(const char *filename); + +extern int ActualFileWrite(ACTUALHANDLE handle, int bytes, char *buffer); + + + + + +#endif /* ACTUALFILE_H */ + diff --git a/plugins/CDVDlinuz/Src/Win32/conf.c b/plugins/CDVDlinuz/Src/Win32/conf.c index 1fe44672a1..4cc04c5aa6 100644 --- a/plugins/CDVDlinuz/Src/Win32/conf.c +++ b/plugins/CDVDlinuz/Src/Win32/conf.c @@ -1,175 +1,350 @@ -/* conf.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - -#include // errno -#include // NULL -#include // sprintf() -#include // getenv() -#include // strerror() -#include // mkdir(), stat() -#include // mkdir(), stat(), fork() -#include // stat(), fork(), execlp() - -#include // CreateProcess() - -// #define CDVDdefs -// #include "../PS2Edefs.h" -#include "../PS2Etypes.h" // u8 -#include "logfile.h" -#include "../ini.h" -#include "conf.h" - - -const char *confnames[] = { "Device", NULL }; -const u8 defaultdevice[] = DEFAULT_DEVICE; -const char defaulthome[] = "inis"; -const char defaultdirectory[] = "HideMe.PS2E"; -const char defaultfile[] = "CDVDlinuz.ini"; - -char confdirname[256]; -char conffilename[256]; - -CDVDconf conf; - - -void InitConf() { - DWORD retval; - int i; - int pos; - char *envptr; - -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVD config: InitConf()"); -#endif /* VERBOSE_FUNCTION_CONF */ - - i = 0; - while((i < 255) && defaultdevice[i] != 0) { - conf.devicename[i] = defaultdevice[i]; - i++; - } // ENDWHILE- copying the default CD/DVD name in - conf.devicename[i] = 0; // 0-terminate the device name - - // Locating directory and file positions - pos = 0; - envptr = NULL; - // envptr = getenv("HOME"); - if(envptr == NULL) { - // = - retval = GetCurrentDirectory(253, confdirname); - if(retval > 0) { - pos = retval; - } else { - pos = 2; - confdirname[0] = '.'; - confdirname[1] = '\\'; - } // ENDIF- Did we retrieve a directory reference? - - i = 0; - while(i < pos) { - conffilename[i] = confdirname[i]; - i++; - } // ENDWHILE- Copying dir info (so far) into file info - - if(confdirname[pos-1] != '\\') { - confdirname[pos] = '\\'; - conffilename[pos] = '\\'; - pos++; - } // ENDIF- No directory separator here? Add one. - - i = 0; - while((pos < 253) && (defaulthome[i] != 0)) { - confdirname[pos] = defaulthome[i]; - conffilename[pos] = defaulthome[i]; - pos++; - i++; - } // ENDWHILE- putting an offset where to store ini data - - } else { - // = / - i = 0; - while((pos < 253) && (*(envptr + i) != 0)) { - confdirname[pos] = *(envptr + i); - conffilename[pos] = *(envptr + i); - pos++; - i++; - } // ENDWHILE- copying home directory info in - - if(confdirname[pos-1] != '\\') { - confdirname[pos] = '\\'; - conffilename[pos] = '\\'; - pos++; - } // ENDIF- No directory separator here? Add one. - - i = 0; - while((pos < 253) && (defaultdirectory[i] != 0)) { - confdirname[pos] = defaultdirectory[i]; - conffilename[pos] = defaultdirectory[i]; - pos++; - i++; - } // NEXT- putting a default place to store configuration data - } // ENDIF- No Home directory? - - confdirname[pos] = 0; // Directory reference finished - - // += / - if(conffilename[pos-1] != '\\') { - conffilename[pos] = '\\'; - pos++; - } // ENDIF- No directory separator here? Add one. - - i = 0; - while((pos < 253) && (defaultfile[i] != 0)) { - conffilename[pos] = defaultfile[i]; - pos++; - i++; - } // NEXT- putting a default place to store configuration data - - conffilename[pos] = 0; // File reference finished - -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVD config: Directory: %s", confdirname); - PrintLog("CDVD config: File: %s", conffilename); -#endif /* VERBOSE_FUNCTION_CONF */ -} // END InitConf() - - -void LoadConf() { - int retval; - -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVD config: LoadConf()"); -#endif /* VERBOSE_FUNCTION_CONF */ - - retval = INILoadString(conffilename, "Settings", "Device", conf.devicename); - if(retval < 0) { - sprintf(conf.devicename, "D:"); - } // ENDIF- Couldn't find keyword? Fill in a default -} // END LoadConf() - - -void SaveConf() { -#ifdef VERBOSE_FUNCTION_CONF - PrintLog("CDVD config: SaveConf()"); -#endif /* VERBOSE_FUNCTION_CONF */ - - mkdir(confdirname); - - INISaveString(conffilename, "Settings", "Device", conf.devicename); -} // END SaveConf() +/* conf.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + +#include // errno + +#include // NULL + +#include // sprintf() + +#include // getenv() + +#include // strerror() + +#include // mkdir(), stat() + +#include // mkdir(), stat(), fork() + +#include // stat(), fork(), execlp() + + + +#include // CreateProcess() + + + +// #define CDVDdefs + +// #include "../PS2Edefs.h" + +#include "../PS2Etypes.h" // u8 + +#include "logfile.h" + +#include "../ini.h" + +#include "conf.h" + + + + + +const char *confnames[] = { "Device", NULL }; + +const u8 defaultdevice[] = DEFAULT_DEVICE; + +const char defaulthome[] = "inis"; + +const char defaultdirectory[] = "HideMe.PS2E"; + +const char defaultfile[] = "CDVDlinuz.ini"; + + + +char confdirname[256]; + +char conffilename[256]; + + + +CDVDconf conf; + + + + + +void InitConf() { + + DWORD retval; + + int i; + + int pos; + + char *envptr; + + + +#ifdef VERBOSE_FUNCTION_CONF + + PrintLog("CDVD config: InitConf()"); + +#endif /* VERBOSE_FUNCTION_CONF */ + + + + i = 0; + + while((i < 255) && defaultdevice[i] != 0) { + + conf.devicename[i] = defaultdevice[i]; + + i++; + + } // ENDWHILE- copying the default CD/DVD name in + + conf.devicename[i] = 0; // 0-terminate the device name + + + + // Locating directory and file positions + + pos = 0; + + envptr = NULL; + + // envptr = getenv("HOME"); + + if(envptr == NULL) { + + // = + + retval = GetCurrentDirectory(253, confdirname); + + if(retval > 0) { + + pos = retval; + + } else { + + pos = 2; + + confdirname[0] = '.'; + + confdirname[1] = '\\'; + + } // ENDIF- Did we retrieve a directory reference? + + + + i = 0; + + while(i < pos) { + + conffilename[i] = confdirname[i]; + + i++; + + } // ENDWHILE- Copying dir info (so far) into file info + + + + if(confdirname[pos-1] != '\\') { + + confdirname[pos] = '\\'; + + conffilename[pos] = '\\'; + + pos++; + + } // ENDIF- No directory separator here? Add one. + + + + i = 0; + + while((pos < 253) && (defaulthome[i] != 0)) { + + confdirname[pos] = defaulthome[i]; + + conffilename[pos] = defaulthome[i]; + + pos++; + + i++; + + } // ENDWHILE- putting an offset where to store ini data + + + + } else { + + // = / + + i = 0; + + while((pos < 253) && (*(envptr + i) != 0)) { + + confdirname[pos] = *(envptr + i); + + conffilename[pos] = *(envptr + i); + + pos++; + + i++; + + } // ENDWHILE- copying home directory info in + + + + if(confdirname[pos-1] != '\\') { + + confdirname[pos] = '\\'; + + conffilename[pos] = '\\'; + + pos++; + + } // ENDIF- No directory separator here? Add one. + + + + i = 0; + + while((pos < 253) && (defaultdirectory[i] != 0)) { + + confdirname[pos] = defaultdirectory[i]; + + conffilename[pos] = defaultdirectory[i]; + + pos++; + + i++; + + } // NEXT- putting a default place to store configuration data + + } // ENDIF- No Home directory? + + + + confdirname[pos] = 0; // Directory reference finished + + + + // += / + + if(conffilename[pos-1] != '\\') { + + conffilename[pos] = '\\'; + + pos++; + + } // ENDIF- No directory separator here? Add one. + + + + i = 0; + + while((pos < 253) && (defaultfile[i] != 0)) { + + conffilename[pos] = defaultfile[i]; + + pos++; + + i++; + + } // NEXT- putting a default place to store configuration data + + + + conffilename[pos] = 0; // File reference finished + + + +#ifdef VERBOSE_FUNCTION_CONF + + PrintLog("CDVD config: Directory: %s", confdirname); + + PrintLog("CDVD config: File: %s", conffilename); + +#endif /* VERBOSE_FUNCTION_CONF */ + +} // END InitConf() + + + + + +void LoadConf() { + + int retval; + + + +#ifdef VERBOSE_FUNCTION_CONF + + PrintLog("CDVD config: LoadConf()"); + +#endif /* VERBOSE_FUNCTION_CONF */ + + + + retval = INILoadString(conffilename, "Settings", "Device", conf.devicename); + + if(retval < 0) { + + sprintf(conf.devicename, "D:"); + + } // ENDIF- Couldn't find keyword? Fill in a default + +} // END LoadConf() + + + + + +void SaveConf() { + +#ifdef VERBOSE_FUNCTION_CONF + + PrintLog("CDVD config: SaveConf()"); + +#endif /* VERBOSE_FUNCTION_CONF */ + + + + mkdir(confdirname); + + + + INISaveString(conffilename, "Settings", "Device", conf.devicename); + +} // END SaveConf() + diff --git a/plugins/CDVDlinuz/Src/Win32/conf.h b/plugins/CDVDlinuz/Src/Win32/conf.h index 406ed03512..26daecaf12 100644 --- a/plugins/CDVDlinuz/Src/Win32/conf.h +++ b/plugins/CDVDlinuz/Src/Win32/conf.h @@ -1,49 +1,98 @@ -/* conf.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - -#ifndef CONF_H -#define CONF_H - - -#define CDVDdefs -#include "../PS2Edefs.h" - - -#define VERBOSE_FUNCTION_CONF - - -// Configuration Data - -typedef struct { - u8 devicename[256]; -} CDVDconf; -extern CDVDconf conf; - -#define DEFAULT_DEVICE "K:\\" - - -// Configuration Functions - -extern void InitConf(); -extern void LoadConf(); -extern void SaveConf(); - - -#endif /* CONF_H */ +/* conf.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + +#ifndef CONF_H + +#define CONF_H + + + + + +#define CDVDdefs + +#include "../PS2Edefs.h" + + + + + +#define VERBOSE_FUNCTION_CONF + + + + + +// Configuration Data + + + +typedef struct { + + u8 devicename[256]; + +} CDVDconf; + +extern CDVDconf conf; + + + +#define DEFAULT_DEVICE "K:\\" + + + + + +// Configuration Functions + + + +extern void InitConf(); + +extern void LoadConf(); + +extern void SaveConf(); + + + + + +#endif /* CONF_H */ + diff --git a/plugins/CDVDlinuz/Src/Win32/device.c b/plugins/CDVDlinuz/Src/Win32/device.c index 527c142978..cb5e6100db 100644 --- a/plugins/CDVDlinuz/Src/Win32/device.c +++ b/plugins/CDVDlinuz/Src/Win32/device.c @@ -1,583 +1,1166 @@ -/* device.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include -#include // IOCTL_CDROM..., IOCTL_STORAGE... -#include // IOCTL_DISK... -#include // sprintf() -#include // time_t - -#define CDVDdefs -#include "PS2Edefs.h" - -#include "logfile.h" -#include "conf.h" -#include "CD.h" -#include "DVD.h" -#include "device.h" - - -HANDLE devicehandle; -OVERLAPPED waitevent; - -time_t lasttime; -s32 traystatus; -int traystatusmethod; -s32 disctype; -char tocbuffer[2048]; - - -void DeviceInit() { - devicehandle = NULL; - waitevent.hEvent = NULL; - waitevent.Internal = 0; - waitevent.InternalHigh = 0; - waitevent.Offset = 0; - waitevent.OffsetHigh = 0; - lasttime = 0; - - InitDisc(); -} // END DeviceInit() - - -void InitDisc() { - int i; - - InitCDInfo(); - InitDVDInfo(); - traystatus = CDVD_TRAY_OPEN; - traystatusmethod = 0; // Poll all until one works - disctype = CDVD_TYPE_NODISC; - for(i = 0; i < 2048; i++) tocbuffer[i] = 0; -} // END InitDisc() - - -s32 DiscInserted() { - if(traystatus != CDVD_TRAY_CLOSE) return(-1); - - if(disctype == CDVD_TYPE_ILLEGAL) return(-1); - // if(disctype == CDVD_TYPE_UNKNOWN) return(-1); // Hmm. Let this one through? - if(disctype == CDVD_TYPE_DETCTDVDD) return(-1); - if(disctype == CDVD_TYPE_DETCTDVDS) return(-1); - if(disctype == CDVD_TYPE_DETCTCD) return(-1); - if(disctype == CDVD_TYPE_DETCT) return(-1); - if(disctype == CDVD_TYPE_NODISC) return(-1); - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDlinuz device: DiscInserted()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - return(0); -} // END DiscInserted() - - -// Returns errcode (or 0 if successful) -DWORD FinishCommand(BOOL boolresult) { - DWORD errcode; - DWORD waitcode; - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDlinuz device: FinishCommand()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - if(boolresult == TRUE) { - ResetEvent(waitevent.hEvent); - return(0); - } // ENDIF- Device is ready? Say so. - - errcode = GetLastError(); - if(errcode == ERROR_IO_PENDING) { -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDlinuz device: Waiting for completion."); -#endif /* VERBOSE_FUNCTION_DEVICE */ - waitcode = WaitForSingleObject(waitevent.hEvent, 10 * 1000); // 10 sec wait - if((waitcode == WAIT_FAILED) || (waitcode == WAIT_ABANDONED)) { - errcode = GetLastError(); - } else if(waitcode == WAIT_TIMEOUT) { - errcode = 21; - CancelIo(devicehandle); // Speculative Line - } else { - ResetEvent(waitevent.hEvent); - return(0); // Success! - } // ENDIF- Trouble waiting? (Or doesn't finish in 5 seconds?) - } // ENDIF- Should we wait for the call to finish? - - ResetEvent(waitevent.hEvent); - return(errcode); -} // END DeviceCommand() - - -s32 DeviceOpen() { - char tempname[256]; - UINT drivetype; - DWORD errcode; - - if(conf.devicename[0] == 0) return(-1); - - if(devicehandle != NULL) return(0); - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDlinuz device: DeviceOpen()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - // InitConf(); - // LoadConf(); // Should be done at least once before this call - - // Root Directory reference - if(conf.devicename[1] == 0) { - sprintf(tempname, "%s:\\", conf.devicename); - } else if((conf.devicename[1] == ':') && (conf.devicename[2] == 0)) { - sprintf(tempname, "%s\\", conf.devicename); - } else { - sprintf(tempname, "%s", conf.devicename); - } // ENDIF- Not a single drive letter? (or a letter/colon?) Copy the name in. - - drivetype = GetDriveType(tempname); - if(drivetype != DRIVE_CDROM) { -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDlinuz device: Not a CD-ROM!"); - PrintLog("CDVDlinuz device: (Came back: %u)", drivetype); - errcode = GetLastError(); - if(errcode > 0) PrintError("CDVDlinuz device", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - return(-1); - } // ENDIF- Not a CD-ROM? Say so! - // Hmm. Do we want to include DRIVE_REMOVABLE... just in case? - - // Device Reference - if(conf.devicename[1] == 0) { - sprintf(tempname, "\\\\.\\%s:", conf.devicename); - } else if((conf.devicename[1] == ':') && (conf.devicename[2] == 0)) { - sprintf(tempname, "\\\\.\\%s", conf.devicename); - } else { - sprintf(tempname, "%s", conf.devicename); - } // ENDIF- Not a single drive letter? (or a letter/colon?) Copy the name in. - - devicehandle = CreateFile(tempname, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN, - NULL); - - if(devicehandle == INVALID_HANDLE_VALUE) { -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDlinuz device: Couldn't open device read-only! Read-Write perhaps?"); - errcode = GetLastError(); - PrintError("CDVDlinuz device", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - devicehandle = CreateFile(tempname, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN, - NULL); - } // ENDIF- Couldn't open for read? Try read/write (for those drives that insist) - - if(devicehandle == INVALID_HANDLE_VALUE) { -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDlinuz device: Couldn't open device!"); - errcode = GetLastError(); - PrintError("CDVDlinuz device", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - devicehandle = NULL; - return(-1); - } // ENDIF- Couldn't open that way either? Abort. - - waitevent.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if(waitevent.hEvent == INVALID_HANDLE_VALUE) { -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDlinuz device: Couldn't open event handler!"); - errcode = GetLastError(); - PrintError("CDVDlinuz device", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - waitevent.hEvent = NULL; - CloseHandle(devicehandle); - devicehandle = NULL; - } // ENDIF- Couldn't create an "Wait for I/O" handle? Abort. - - // More here... DeviceIoControl? for Drive Capabilities - // DEVICE_CAPABILITIES? - - ////// Should be done just after the first DeviceOpen(); - // InitDisc(); // ? - // DeviceTrayStatus(); - - return(0); -} // END DeviceOpen() - - -void DeviceClose() { - if(devicehandle == NULL) return; - - if(devicehandle == INVALID_HANDLE_VALUE) { - devicehandle = NULL; - return; - } // ENDIF- Bad value? Just clear the value. - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDlinuz device: DeviceClose()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - if(waitevent.hEvent != NULL) { - if(waitevent.hEvent != INVALID_HANDLE_VALUE) { - CancelIo(devicehandle); - CloseHandle(waitevent.hEvent); - } // ENDIF- Is this handle actually open? - waitevent.hEvent = NULL; - waitevent.Offset = 0; - waitevent.OffsetHigh = 0; - } // ENDIF- Reset the event handle? - - CloseHandle(devicehandle); - devicehandle = NULL; - return; -} // END DeviceClose() - - -s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer) { - if(DiscInserted() == -1) return(-1); - - if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { - return(DVDreadTrack(lsn, mode, buffer)); - } else { - return(CDreadTrack(lsn, mode, buffer)); - } // ENDIF- Is this a DVD? -} // END DeviceReadTrack() - - -s32 DeviceBufferOffset() { - if(DiscInserted() == -1) return(-1); - - if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { - return(0); - } else { - return(CDgetBufferOffset()); - } // ENDIF- Is this a DVD? - - return(-1); -} // END DeviceBufferOffset() - - -s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd) { - if(DiscInserted() == -1) return(-1); - - if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { - return(DVDgetTD(track, cdvdtd)); - } else { - return(CDgetTD(track, cdvdtd)); - } // ENDIF- Is this a DVD? - - return(-1); -} // END DeviceGetTD() - - -s32 DeviceGetDiskType() { - s32 s32result; - - if(devicehandle == NULL) return(-1); - if(devicehandle == INVALID_HANDLE_VALUE) return(-1); - - if(traystatus == CDVD_TRAY_OPEN) return(disctype); - - if(disctype != CDVD_TYPE_NODISC) return(disctype); - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDlinuz device: DeviceGetDiskType()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - disctype = CDVD_TYPE_DETCT; - - s32result = DVDgetDiskType(); - if(s32result != -1) return(disctype); - - s32result = CDgetDiskType(); - if(s32result != -1) return(disctype); - - disctype = CDVD_TYPE_UNKNOWN; - return(disctype); -} // END DeviceGetDiskType() - - -BOOL DeviceTrayStatusStorage() { - BOOL boolresult; - DWORD byteswritten; - DWORD errcode; - - boolresult = DeviceIoControl(devicehandle, - IOCTL_STORAGE_CHECK_VERIFY, - NULL, - 0, - NULL, - 0, - &byteswritten, - NULL); - errcode = FinishCommand(boolresult); - - if(errcode == 0) return(TRUE); - if(errcode == 21) return(FALSE); // Device not ready? (Valid error) - -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDlinuz device: Trouble detecting drive status (STORAGE)!"); - PrintError("CDVDlinuz device", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - return(FALSE); -} // END DeviceTrayStatusStorage() - - -BOOL DeviceTrayStatusCDRom() { - BOOL boolresult; - DWORD byteswritten; - DWORD errcode; - - boolresult = DeviceIoControl(devicehandle, - IOCTL_CDROM_CHECK_VERIFY, - NULL, - 0, - NULL, - 0, - &byteswritten, - NULL); - errcode = FinishCommand(boolresult); - - if(errcode == 0) return(TRUE); - if(errcode == 21) return(FALSE); // Device not ready? (Valid error) - -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDlinuz device: Trouble detecting drive status (CDROM)!"); - PrintError("CDVDlinuz device", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - return(FALSE); -} // END DeviceTrayStatusCDRom() - - -BOOL DeviceTrayStatusDisk() { - BOOL boolresult; - DWORD byteswritten; - DWORD errcode; - - boolresult = DeviceIoControl(devicehandle, - IOCTL_DISK_CHECK_VERIFY, - NULL, - 0, - NULL, - 0, - &byteswritten, - NULL); - errcode = FinishCommand(boolresult); - - if(errcode == 0) return(TRUE); - if(errcode == 21) return(FALSE); // Device not ready? (Valid error) - -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDlinuz device: Trouble detecting drive status (DISK)!"); - PrintError("CDVDlinuz device", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - return(FALSE); -} // END DeviceTrayStatusDisk() - - -s32 DeviceTrayStatus() { - BOOL boolresult; - - if(devicehandle == NULL) return(-1); - if(devicehandle == INVALID_HANDLE_VALUE) return(-1); - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDlinuz device: DeviceTrayStatus()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - switch(traystatusmethod) { - case 1: - boolresult = DeviceTrayStatusStorage(); - break; - case 2: - boolresult = DeviceTrayStatusCDRom(); - break; - case 3: - boolresult = DeviceTrayStatusDisk(); - break; - default: - boolresult = FALSE; - break; - } // ENDSWITCH traystatusmethod- One method already working? Try it again. - - if(boolresult == FALSE) { - traystatusmethod = 0; - boolresult = DeviceTrayStatusStorage(); - if(boolresult == TRUE) { - traystatusmethod = 1; - } else { - boolresult = DeviceTrayStatusCDRom(); - if(boolresult == TRUE) { - traystatusmethod = 2; - } else { - boolresult = DeviceTrayStatusDisk(); - if(boolresult == TRUE) traystatusmethod = 3; - } // ENDIF- Did we succeed with CDRom? - } // ENDIF- Did we succeed with Storage? - } // Single call to already working test just failed? Test them all. - - if(boolresult == FALSE) { - if(traystatus == CDVD_TRAY_CLOSE) { -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDlinuz device: Tray just opened!"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - traystatus = CDVD_TRAY_OPEN; - DeviceClose(); - DeviceOpen(); - InitDisc(); - } // ENDIF- Just opened? clear disc info - return(traystatus); - } // ENDIF- Still failed? Assume no disc in drive then. - - if(traystatus == CDVD_TRAY_OPEN) { - traystatus = CDVD_TRAY_CLOSE; -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDlinuz device: Tray just closed!"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - DeviceGetDiskType(); - return(traystatus); - } // ENDIF- Just closed? Get disc information - - return(traystatus); -} // END DeviceTrayStatus() - - -s32 DeviceTrayOpen() { - BOOL boolresult; - DWORD byteswritten; - DWORD errcode; - - if(devicehandle == NULL) return(-1); - if(devicehandle == INVALID_HANDLE_VALUE) return(-1); - - if(traystatus == CDVD_TRAY_OPEN) return(0); - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDlinuz device: DeviceOpenTray()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - boolresult = DeviceIoControl(devicehandle, - IOCTL_STORAGE_EJECT_MEDIA, - NULL, - 0, - NULL, - 0, - &byteswritten, - &waitevent); - errcode = FinishCommand(boolresult); - - if(errcode != 0) { -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDlinuz device: Couldn't signal media to eject! (STORAGE)"); - PrintError("CDVDlinuz device", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ - -// boolresult = DeviceIoControl(devicehandle, -// IOCTL_DISK_EJECT_MEDIA, -// NULL, -// 0, -// NULL, -// 0, -// &byteswritten, -// NULL); -// } // ENDIF- Storage Call failed? Try Disk call. - -// if(boolresult == FALSE) { -// #ifdef VERBOSE_WARNING_DEVICE -// PrintLog("CDVDlinuz device: Couldn't signal media to eject! (DISK)"); -// PrintError("CDVDlinuz device", errcode); -// #endif /* VERBOSE_WARNING_DEVICE */ - return(-1); - } // ENDIF- Disk Call failed as well? Give it up. - - return(0); -} // END DeviceTrayOpen() - - -s32 DeviceTrayClose() { - BOOL boolresult; - DWORD byteswritten; - DWORD errcode; - - if(devicehandle == NULL) return(-1); - if(devicehandle == INVALID_HANDLE_VALUE) return(-1); - - if(traystatus == CDVD_TRAY_CLOSE) return(0); - -#ifdef VERBOSE_FUNCTION_DEVICE - PrintLog("CDVDlinuz device: DeviceCloseTray()"); -#endif /* VERBOSE_FUNCTION_DEVICE */ - - boolresult = DeviceIoControl(devicehandle, - IOCTL_STORAGE_LOAD_MEDIA, - NULL, - 0, - NULL, - 0, - &byteswritten, - NULL); - errcode = FinishCommand(boolresult); - - if(errcode != 0) { -#ifdef VERBOSE_WARNING_DEVICE - PrintLog("CDVDlinuz device: Couldn't signal media to load! (STORAGE)"); - PrintError("CDVDlinuz device", errcode); -#endif /* VERBOSE_WARNING_DEVICE */ -// boolresult = DeviceIoControl(devicehandle, -// IOCTL_CDROM_LOAD_MEDIA, -// NULL, -// 0, -// NULL, -// 0, -// &byteswritten, -// NULL); -// } // ENDIF- Storage call failed. CDRom call? - -// if(boolresult == FALSE) { -// errcode = GetLastError(); -// #ifdef VERBOSE_WARNING_DEVICE -// PrintLog("CDVDlinuz device: Couldn't signal media to load! (CDROM)"); -// PrintError("CDVDlinuz device", errcode); -// #endif /* VERBOSE_WARNING_DEVICE */ -// boolresult = DeviceIoControl(devicehandle, -// IOCTL_DISK_LOAD_MEDIA, -// NULL, -// 0, -// NULL, -// 0, -// &byteswritten, -// NULL); -// } // ENDIF- CDRom call failed. Disk call? - -// if(boolresult == FALSE) { -// #ifdef VERBOSE_WARNING_DEVICE -// PrintLog("CDVDlinuz device: Couldn't signal media to load! (DISK)"); -// PrintError("CDVDlinuz device", errcode); -// #endif /* VERBOSE_WARNING_DEVICE */ - return(-1); - } // ENDIF- Media not available? - - return(0); -} // END DeviceTrayClose() +/* device.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + +#include // IOCTL_CDROM..., IOCTL_STORAGE... + +#include // IOCTL_DISK... + +#include // sprintf() + +#include // time_t + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + +#include "logfile.h" + +#include "conf.h" + +#include "CD.h" + +#include "DVD.h" + +#include "device.h" + + + + + +HANDLE devicehandle; + +OVERLAPPED waitevent; + + + +time_t lasttime; + +s32 traystatus; + +int traystatusmethod; + +s32 disctype; + +char tocbuffer[2048]; + + + + + +void DeviceInit() { + + devicehandle = NULL; + + waitevent.hEvent = NULL; + + waitevent.Internal = 0; + + waitevent.InternalHigh = 0; + + waitevent.Offset = 0; + + waitevent.OffsetHigh = 0; + + lasttime = 0; + + + + InitDisc(); + +} // END DeviceInit() + + + + + +void InitDisc() { + + int i; + + + + InitCDInfo(); + + InitDVDInfo(); + + traystatus = CDVD_TRAY_OPEN; + + traystatusmethod = 0; // Poll all until one works + + disctype = CDVD_TYPE_NODISC; + + for(i = 0; i < 2048; i++) tocbuffer[i] = 0; + +} // END InitDisc() + + + + + +s32 DiscInserted() { + + if(traystatus != CDVD_TRAY_CLOSE) return(-1); + + + + if(disctype == CDVD_TYPE_ILLEGAL) return(-1); + + // if(disctype == CDVD_TYPE_UNKNOWN) return(-1); // Hmm. Let this one through? + + if(disctype == CDVD_TYPE_DETCTDVDD) return(-1); + + if(disctype == CDVD_TYPE_DETCTDVDS) return(-1); + + if(disctype == CDVD_TYPE_DETCTCD) return(-1); + + if(disctype == CDVD_TYPE_DETCT) return(-1); + + if(disctype == CDVD_TYPE_NODISC) return(-1); + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDlinuz device: DiscInserted()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + return(0); + +} // END DiscInserted() + + + + + +// Returns errcode (or 0 if successful) + +DWORD FinishCommand(BOOL boolresult) { + + DWORD errcode; + + DWORD waitcode; + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDlinuz device: FinishCommand()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + if(boolresult == TRUE) { + + ResetEvent(waitevent.hEvent); + + return(0); + + } // ENDIF- Device is ready? Say so. + + + + errcode = GetLastError(); + + if(errcode == ERROR_IO_PENDING) { + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDlinuz device: Waiting for completion."); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + waitcode = WaitForSingleObject(waitevent.hEvent, 10 * 1000); // 10 sec wait + + if((waitcode == WAIT_FAILED) || (waitcode == WAIT_ABANDONED)) { + + errcode = GetLastError(); + + } else if(waitcode == WAIT_TIMEOUT) { + + errcode = 21; + + CancelIo(devicehandle); // Speculative Line + + } else { + + ResetEvent(waitevent.hEvent); + + return(0); // Success! + + } // ENDIF- Trouble waiting? (Or doesn't finish in 5 seconds?) + + } // ENDIF- Should we wait for the call to finish? + + + + ResetEvent(waitevent.hEvent); + + return(errcode); + +} // END DeviceCommand() + + + + + +s32 DeviceOpen() { + + char tempname[256]; + + UINT drivetype; + + DWORD errcode; + + + + if(conf.devicename[0] == 0) return(-1); + + + + if(devicehandle != NULL) return(0); + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDlinuz device: DeviceOpen()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + // InitConf(); + + // LoadConf(); // Should be done at least once before this call + + + + // Root Directory reference + + if(conf.devicename[1] == 0) { + + sprintf(tempname, "%s:\\", conf.devicename); + + } else if((conf.devicename[1] == ':') && (conf.devicename[2] == 0)) { + + sprintf(tempname, "%s\\", conf.devicename); + + } else { + + sprintf(tempname, "%s", conf.devicename); + + } // ENDIF- Not a single drive letter? (or a letter/colon?) Copy the name in. + + + + drivetype = GetDriveType(tempname); + + if(drivetype != DRIVE_CDROM) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDlinuz device: Not a CD-ROM!"); + + PrintLog("CDVDlinuz device: (Came back: %u)", drivetype); + + errcode = GetLastError(); + + if(errcode > 0) PrintError("CDVDlinuz device", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Not a CD-ROM? Say so! + + // Hmm. Do we want to include DRIVE_REMOVABLE... just in case? + + + + // Device Reference + + if(conf.devicename[1] == 0) { + + sprintf(tempname, "\\\\.\\%s:", conf.devicename); + + } else if((conf.devicename[1] == ':') && (conf.devicename[2] == 0)) { + + sprintf(tempname, "\\\\.\\%s", conf.devicename); + + } else { + + sprintf(tempname, "%s", conf.devicename); + + } // ENDIF- Not a single drive letter? (or a letter/colon?) Copy the name in. + + + + devicehandle = CreateFile(tempname, + + GENERIC_READ, + + FILE_SHARE_READ, + + NULL, + + OPEN_EXISTING, + + FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN, + + NULL); + + + + if(devicehandle == INVALID_HANDLE_VALUE) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDlinuz device: Couldn't open device read-only! Read-Write perhaps?"); + + errcode = GetLastError(); + + PrintError("CDVDlinuz device", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + devicehandle = CreateFile(tempname, + + GENERIC_READ | GENERIC_WRITE, + + FILE_SHARE_READ | FILE_SHARE_WRITE, + + NULL, + + OPEN_EXISTING, + + FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN, + + NULL); + + } // ENDIF- Couldn't open for read? Try read/write (for those drives that insist) + + + + if(devicehandle == INVALID_HANDLE_VALUE) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDlinuz device: Couldn't open device!"); + + errcode = GetLastError(); + + PrintError("CDVDlinuz device", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + devicehandle = NULL; + + return(-1); + + } // ENDIF- Couldn't open that way either? Abort. + + + + waitevent.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + if(waitevent.hEvent == INVALID_HANDLE_VALUE) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDlinuz device: Couldn't open event handler!"); + + errcode = GetLastError(); + + PrintError("CDVDlinuz device", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + waitevent.hEvent = NULL; + + CloseHandle(devicehandle); + + devicehandle = NULL; + + } // ENDIF- Couldn't create an "Wait for I/O" handle? Abort. + + + + // More here... DeviceIoControl? for Drive Capabilities + + // DEVICE_CAPABILITIES? + + + + ////// Should be done just after the first DeviceOpen(); + + // InitDisc(); // ? + + // DeviceTrayStatus(); + + + + return(0); + +} // END DeviceOpen() + + + + + +void DeviceClose() { + + if(devicehandle == NULL) return; + + + + if(devicehandle == INVALID_HANDLE_VALUE) { + + devicehandle = NULL; + + return; + + } // ENDIF- Bad value? Just clear the value. + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDlinuz device: DeviceClose()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + if(waitevent.hEvent != NULL) { + + if(waitevent.hEvent != INVALID_HANDLE_VALUE) { + + CancelIo(devicehandle); + + CloseHandle(waitevent.hEvent); + + } // ENDIF- Is this handle actually open? + + waitevent.hEvent = NULL; + + waitevent.Offset = 0; + + waitevent.OffsetHigh = 0; + + } // ENDIF- Reset the event handle? + + + + CloseHandle(devicehandle); + + devicehandle = NULL; + + return; + +} // END DeviceClose() + + + + + +s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer) { + + if(DiscInserted() == -1) return(-1); + + + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + + return(DVDreadTrack(lsn, mode, buffer)); + + } else { + + return(CDreadTrack(lsn, mode, buffer)); + + } // ENDIF- Is this a DVD? + +} // END DeviceReadTrack() + + + + + +s32 DeviceBufferOffset() { + + if(DiscInserted() == -1) return(-1); + + + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + + return(0); + + } else { + + return(CDgetBufferOffset()); + + } // ENDIF- Is this a DVD? + + + + return(-1); + +} // END DeviceBufferOffset() + + + + + +s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd) { + + if(DiscInserted() == -1) return(-1); + + + + if((disctype == CDVD_TYPE_PS2DVD) || (disctype == CDVD_TYPE_DVDV)) { + + return(DVDgetTD(track, cdvdtd)); + + } else { + + return(CDgetTD(track, cdvdtd)); + + } // ENDIF- Is this a DVD? + + + + return(-1); + +} // END DeviceGetTD() + + + + + +s32 DeviceGetDiskType() { + + s32 s32result; + + + + if(devicehandle == NULL) return(-1); + + if(devicehandle == INVALID_HANDLE_VALUE) return(-1); + + + + if(traystatus == CDVD_TRAY_OPEN) return(disctype); + + + + if(disctype != CDVD_TYPE_NODISC) return(disctype); + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDlinuz device: DeviceGetDiskType()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + disctype = CDVD_TYPE_DETCT; + + + + s32result = DVDgetDiskType(); + + if(s32result != -1) return(disctype); + + + + s32result = CDgetDiskType(); + + if(s32result != -1) return(disctype); + + + + disctype = CDVD_TYPE_UNKNOWN; + + return(disctype); + +} // END DeviceGetDiskType() + + + + + +BOOL DeviceTrayStatusStorage() { + + BOOL boolresult; + + DWORD byteswritten; + + DWORD errcode; + + + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_STORAGE_CHECK_VERIFY, + + NULL, + + 0, + + NULL, + + 0, + + &byteswritten, + + NULL); + + errcode = FinishCommand(boolresult); + + + + if(errcode == 0) return(TRUE); + + if(errcode == 21) return(FALSE); // Device not ready? (Valid error) + + + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDlinuz device: Trouble detecting drive status (STORAGE)!"); + + PrintError("CDVDlinuz device", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(FALSE); + +} // END DeviceTrayStatusStorage() + + + + + +BOOL DeviceTrayStatusCDRom() { + + BOOL boolresult; + + DWORD byteswritten; + + DWORD errcode; + + + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_CDROM_CHECK_VERIFY, + + NULL, + + 0, + + NULL, + + 0, + + &byteswritten, + + NULL); + + errcode = FinishCommand(boolresult); + + + + if(errcode == 0) return(TRUE); + + if(errcode == 21) return(FALSE); // Device not ready? (Valid error) + + + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDlinuz device: Trouble detecting drive status (CDROM)!"); + + PrintError("CDVDlinuz device", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(FALSE); + +} // END DeviceTrayStatusCDRom() + + + + + +BOOL DeviceTrayStatusDisk() { + + BOOL boolresult; + + DWORD byteswritten; + + DWORD errcode; + + + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_DISK_CHECK_VERIFY, + + NULL, + + 0, + + NULL, + + 0, + + &byteswritten, + + NULL); + + errcode = FinishCommand(boolresult); + + + + if(errcode == 0) return(TRUE); + + if(errcode == 21) return(FALSE); // Device not ready? (Valid error) + + + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDlinuz device: Trouble detecting drive status (DISK)!"); + + PrintError("CDVDlinuz device", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + return(FALSE); + +} // END DeviceTrayStatusDisk() + + + + + +s32 DeviceTrayStatus() { + + BOOL boolresult; + + + + if(devicehandle == NULL) return(-1); + + if(devicehandle == INVALID_HANDLE_VALUE) return(-1); + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDlinuz device: DeviceTrayStatus()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + switch(traystatusmethod) { + + case 1: + + boolresult = DeviceTrayStatusStorage(); + + break; + + case 2: + + boolresult = DeviceTrayStatusCDRom(); + + break; + + case 3: + + boolresult = DeviceTrayStatusDisk(); + + break; + + default: + + boolresult = FALSE; + + break; + + } // ENDSWITCH traystatusmethod- One method already working? Try it again. + + + + if(boolresult == FALSE) { + + traystatusmethod = 0; + + boolresult = DeviceTrayStatusStorage(); + + if(boolresult == TRUE) { + + traystatusmethod = 1; + + } else { + + boolresult = DeviceTrayStatusCDRom(); + + if(boolresult == TRUE) { + + traystatusmethod = 2; + + } else { + + boolresult = DeviceTrayStatusDisk(); + + if(boolresult == TRUE) traystatusmethod = 3; + + } // ENDIF- Did we succeed with CDRom? + + } // ENDIF- Did we succeed with Storage? + + } // Single call to already working test just failed? Test them all. + + + + if(boolresult == FALSE) { + + if(traystatus == CDVD_TRAY_CLOSE) { + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDlinuz device: Tray just opened!"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + traystatus = CDVD_TRAY_OPEN; + + DeviceClose(); + + DeviceOpen(); + + InitDisc(); + + } // ENDIF- Just opened? clear disc info + + return(traystatus); + + } // ENDIF- Still failed? Assume no disc in drive then. + + + + if(traystatus == CDVD_TRAY_OPEN) { + + traystatus = CDVD_TRAY_CLOSE; + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDlinuz device: Tray just closed!"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + DeviceGetDiskType(); + + return(traystatus); + + } // ENDIF- Just closed? Get disc information + + + + return(traystatus); + +} // END DeviceTrayStatus() + + + + + +s32 DeviceTrayOpen() { + + BOOL boolresult; + + DWORD byteswritten; + + DWORD errcode; + + + + if(devicehandle == NULL) return(-1); + + if(devicehandle == INVALID_HANDLE_VALUE) return(-1); + + + + if(traystatus == CDVD_TRAY_OPEN) return(0); + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDlinuz device: DeviceOpenTray()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_STORAGE_EJECT_MEDIA, + + NULL, + + 0, + + NULL, + + 0, + + &byteswritten, + + &waitevent); + + errcode = FinishCommand(boolresult); + + + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDlinuz device: Couldn't signal media to eject! (STORAGE)"); + + PrintError("CDVDlinuz device", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + + + +// boolresult = DeviceIoControl(devicehandle, + +// IOCTL_DISK_EJECT_MEDIA, + +// NULL, + +// 0, + +// NULL, + +// 0, + +// &byteswritten, + +// NULL); + +// } // ENDIF- Storage Call failed? Try Disk call. + + + +// if(boolresult == FALSE) { + +// #ifdef VERBOSE_WARNING_DEVICE + +// PrintLog("CDVDlinuz device: Couldn't signal media to eject! (DISK)"); + +// PrintError("CDVDlinuz device", errcode); + +// #endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Disk Call failed as well? Give it up. + + + + return(0); + +} // END DeviceTrayOpen() + + + + + +s32 DeviceTrayClose() { + + BOOL boolresult; + + DWORD byteswritten; + + DWORD errcode; + + + + if(devicehandle == NULL) return(-1); + + if(devicehandle == INVALID_HANDLE_VALUE) return(-1); + + + + if(traystatus == CDVD_TRAY_CLOSE) return(0); + + + +#ifdef VERBOSE_FUNCTION_DEVICE + + PrintLog("CDVDlinuz device: DeviceCloseTray()"); + +#endif /* VERBOSE_FUNCTION_DEVICE */ + + + + boolresult = DeviceIoControl(devicehandle, + + IOCTL_STORAGE_LOAD_MEDIA, + + NULL, + + 0, + + NULL, + + 0, + + &byteswritten, + + NULL); + + errcode = FinishCommand(boolresult); + + + + if(errcode != 0) { + +#ifdef VERBOSE_WARNING_DEVICE + + PrintLog("CDVDlinuz device: Couldn't signal media to load! (STORAGE)"); + + PrintError("CDVDlinuz device", errcode); + +#endif /* VERBOSE_WARNING_DEVICE */ + +// boolresult = DeviceIoControl(devicehandle, + +// IOCTL_CDROM_LOAD_MEDIA, + +// NULL, + +// 0, + +// NULL, + +// 0, + +// &byteswritten, + +// NULL); + +// } // ENDIF- Storage call failed. CDRom call? + + + +// if(boolresult == FALSE) { + +// errcode = GetLastError(); + +// #ifdef VERBOSE_WARNING_DEVICE + +// PrintLog("CDVDlinuz device: Couldn't signal media to load! (CDROM)"); + +// PrintError("CDVDlinuz device", errcode); + +// #endif /* VERBOSE_WARNING_DEVICE */ + +// boolresult = DeviceIoControl(devicehandle, + +// IOCTL_DISK_LOAD_MEDIA, + +// NULL, + +// 0, + +// NULL, + +// 0, + +// &byteswritten, + +// NULL); + +// } // ENDIF- CDRom call failed. Disk call? + + + +// if(boolresult == FALSE) { + +// #ifdef VERBOSE_WARNING_DEVICE + +// PrintLog("CDVDlinuz device: Couldn't signal media to load! (DISK)"); + +// PrintError("CDVDlinuz device", errcode); + +// #endif /* VERBOSE_WARNING_DEVICE */ + + return(-1); + + } // ENDIF- Media not available? + + + + return(0); + +} // END DeviceTrayClose() + diff --git a/plugins/CDVDlinuz/Src/Win32/device.h b/plugins/CDVDlinuz/Src/Win32/device.h index 608f13dd86..6a4034fb76 100644 --- a/plugins/CDVDlinuz/Src/Win32/device.h +++ b/plugins/CDVDlinuz/Src/Win32/device.h @@ -1,64 +1,128 @@ -/* device.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - -#ifndef __DEVICE_H__ -#define __DEVICE_H__ - - -#include // BOOL, DWORD - -#include // time_t - -#define CDVDdefs -#include "../PS2Edefs.h" - - -// #define VERBOSE_FUNCTION_DEVICE -// #define VERBOSE_WARNING_DEVICE -#define VERBOSE_DISC_TYPE -#define VERBOSE_DISC_INFO - - -extern HANDLE devicehandle; -extern OVERLAPPED waitevent; - -extern time_t lasttime; -extern s32 traystatus; -extern s32 disctype; -extern char tocbuffer[]; - - -extern void DeviceInit(); -extern void InitDisc(); -extern s32 DiscInserted(); -extern DWORD FinishCommand(BOOL boolresult); - -extern s32 DeviceOpen(); -extern void DeviceClose(); -extern s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer); -extern s32 DeviceBufferOffset(); -extern s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd); -extern s32 DeviceGetDiskType(); -extern s32 DeviceTrayStatus(); -extern s32 DeviceTrayOpen(); -extern s32 DeviceTrayClose(); - - -#endif /* __DEVICE_H__ */ +/* device.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + +#ifndef __DEVICE_H__ + +#define __DEVICE_H__ + + + + + +#include // BOOL, DWORD + + + +#include // time_t + + + +#define CDVDdefs + +#include "../PS2Edefs.h" + + + + + +// #define VERBOSE_FUNCTION_DEVICE + +// #define VERBOSE_WARNING_DEVICE + +#define VERBOSE_DISC_TYPE + +#define VERBOSE_DISC_INFO + + + + + +extern HANDLE devicehandle; + +extern OVERLAPPED waitevent; + + + +extern time_t lasttime; + +extern s32 traystatus; + +extern s32 disctype; + +extern char tocbuffer[]; + + + + + +extern void DeviceInit(); + +extern void InitDisc(); + +extern s32 DiscInserted(); + +extern DWORD FinishCommand(BOOL boolresult); + + + +extern s32 DeviceOpen(); + +extern void DeviceClose(); + +extern s32 DeviceReadTrack(u32 lsn, int mode, u8 *buffer); + +extern s32 DeviceBufferOffset(); + +extern s32 DeviceGetTD(u8 track, cdvdTD *cdvdtd); + +extern s32 DeviceGetDiskType(); + +extern s32 DeviceTrayStatus(); + +extern s32 DeviceTrayOpen(); + +extern s32 DeviceTrayClose(); + + + + + +#endif /* __DEVICE_H__ */ + diff --git a/plugins/CDVDlinuz/Src/Win32/logfile.c b/plugins/CDVDlinuz/Src/Win32/logfile.c index 28f82eb088..8d1226e298 100644 --- a/plugins/CDVDlinuz/Src/Win32/logfile.c +++ b/plugins/CDVDlinuz/Src/Win32/logfile.c @@ -1,119 +1,238 @@ -/* logfile.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include - -// #include // open() -// #include // mkdir() -#include // NULL -#include // vsprintf() -#include // va_start(), va_end(), vsprintf() -// #include // open() -// #include // open() - -#include "logfile.h" - - -HANDLE logfile; -char logfiletemp[2048]; - - -void InitLog() { - // Token comment line -#ifdef VERBOSE_LOGFILE - CreateDirectory("logs", NULL); - - DeleteFile("logs\\CDVDlog.txt"); - logfile = NULL; -#endif /* VERBOSE LOGFILE */ -} // END InitLog(); - - -int OpenLog() { - // Token comment line -#ifdef VERBOSE_LOGFILE - logfile = CreateFile("logs\\CDVDlog.txt", - GENERIC_WRITE, - 0, - NULL, - CREATE_ALWAYS, - FILE_FLAG_SEQUENTIAL_SCAN, - NULL); - if(logfile == INVALID_HANDLE_VALUE) { - logfile = NULL; - return(-1); - } // ENDIF- Failed to open? Say so. -#endif /* VERBOSE LOGFILE */ - - return(0); -} // END OpenLog(); - - -void CloseLog() { - // Token comment line -#ifdef VERBOSE_LOGFILE - if(logfile != NULL) { - CloseHandle(logfile); - logfile = NULL; - } // ENDIF- Is the log file actually open? Close it. -#endif /* VERBOSE LOGFILE */ -} // END CloseLog() - - -void PrintLog(const char *fmt, ...) { - DWORD byteswritten; - - // Token comment line -#ifdef VERBOSE_LOGFILE - va_list list; - int len; - - if(logfile == NULL) return; // Log file not open... yet. - - va_start(list, fmt); - vsprintf(logfiletemp, fmt, list); - va_end(list); - - len = 0; - while((len < 2048) && (logfiletemp[len] != 0)) len++; - if((len > 0) && (logfiletemp[len-1] == '\n')) len--; - if((len > 0) && (logfiletemp[len-1] == '\r')) len--; - logfiletemp[len] = 0; // Slice off the last "\r\n"... - - WriteFile(logfile, logfiletemp, len, &byteswritten, NULL); - WriteFile(logfile, "\r\n", 2, &byteswritten, NULL); -#endif /* VERBOSE LOGFILE */ -} // END PrintLog() - -void PrintError(const char *header, DWORD errcode) { -#ifdef VERBOSE_LOGFILE - TCHAR errmsg[256]; - - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | 80, - NULL, - errcode, - 0, - errmsg, - 256, - NULL); - PrintLog("%s: (%u) %s", header, errcode, errmsg); -#endif /* VERBOSE_WARNING_DEVICE */ -} // END PrintError() +/* logfile.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + + + +// #include // open() + +// #include // mkdir() + +#include // NULL + +#include // vsprintf() + +#include // va_start(), va_end(), vsprintf() + +// #include // open() + +// #include // open() + + + +#include "logfile.h" + + + + + +HANDLE logfile; + +char logfiletemp[2048]; + + + + + +void InitLog() { + + // Token comment line + +#ifdef VERBOSE_LOGFILE + + CreateDirectory("logs", NULL); + + + + DeleteFile("logs\\CDVDlog.txt"); + + logfile = NULL; + +#endif /* VERBOSE LOGFILE */ + +} // END InitLog(); + + + + + +int OpenLog() { + + // Token comment line + +#ifdef VERBOSE_LOGFILE + + logfile = CreateFile("logs\\CDVDlog.txt", + + GENERIC_WRITE, + + 0, + + NULL, + + CREATE_ALWAYS, + + FILE_FLAG_SEQUENTIAL_SCAN, + + NULL); + + if(logfile == INVALID_HANDLE_VALUE) { + + logfile = NULL; + + return(-1); + + } // ENDIF- Failed to open? Say so. + +#endif /* VERBOSE LOGFILE */ + + + + return(0); + +} // END OpenLog(); + + + + + +void CloseLog() { + + // Token comment line + +#ifdef VERBOSE_LOGFILE + + if(logfile != NULL) { + + CloseHandle(logfile); + + logfile = NULL; + + } // ENDIF- Is the log file actually open? Close it. + +#endif /* VERBOSE LOGFILE */ + +} // END CloseLog() + + + + + +void PrintLog(const char *fmt, ...) { + + DWORD byteswritten; + + + + // Token comment line + +#ifdef VERBOSE_LOGFILE + + va_list list; + + int len; + + + + if(logfile == NULL) return; // Log file not open... yet. + + + + va_start(list, fmt); + + vsprintf(logfiletemp, fmt, list); + + va_end(list); + + + + len = 0; + + while((len < 2048) && (logfiletemp[len] != 0)) len++; + + if((len > 0) && (logfiletemp[len-1] == '\n')) len--; + + if((len > 0) && (logfiletemp[len-1] == '\r')) len--; + + logfiletemp[len] = 0; // Slice off the last "\r\n"... + + + + WriteFile(logfile, logfiletemp, len, &byteswritten, NULL); + + WriteFile(logfile, "\r\n", 2, &byteswritten, NULL); + +#endif /* VERBOSE LOGFILE */ + +} // END PrintLog() + + + +void PrintError(const char *header, DWORD errcode) { + +#ifdef VERBOSE_LOGFILE + + TCHAR errmsg[256]; + + + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | 80, + + NULL, + + errcode, + + 0, + + errmsg, + + 256, + + NULL); + + PrintLog("%s: (%u) %s", header, errcode, errmsg); + +#endif /* VERBOSE_WARNING_DEVICE */ + +} // END PrintError() + diff --git a/plugins/CDVDlinuz/Src/Win32/logfile.h b/plugins/CDVDlinuz/Src/Win32/logfile.h index ff6e3b0c1c..3efaad8f4d 100644 --- a/plugins/CDVDlinuz/Src/Win32/logfile.h +++ b/plugins/CDVDlinuz/Src/Win32/logfile.h @@ -1,39 +1,78 @@ -/* logfile.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef LOGFILE_H -#define LOGFILE_H - - -#include // Just for DWORD - - -#define VERBOSE_LOGFILE - - -extern void InitLog(); -extern int OpenLog(); -extern void CloseLog(); -extern void PrintLog(const char *format, ...); -extern void PrintError(const char *header, DWORD errcode); - - -#endif /* LOGFILE_H */ +/* logfile.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef LOGFILE_H + +#define LOGFILE_H + + + + + +#include // Just for DWORD + + + + + +#define VERBOSE_LOGFILE + + + + + +extern void InitLog(); + +extern int OpenLog(); + +extern void CloseLog(); + +extern void PrintLog(const char *format, ...); + +extern void PrintError(const char *header, DWORD errcode); + + + + + +#endif /* LOGFILE_H */ + diff --git a/plugins/CDVDlinuz/Src/Win32/mainbox.c b/plugins/CDVDlinuz/Src/Win32/mainbox.c index 0c7c9f8794..91298702e0 100644 --- a/plugins/CDVDlinuz/Src/Win32/mainbox.c +++ b/plugins/CDVDlinuz/Src/Win32/mainbox.c @@ -1,173 +1,346 @@ -/* mainbox.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include -// #include // Button_ -#include // NULL - -#include // sprintf() -#include // strcpy() -#include // stat() -#include // stat() -#include // stat() - -#include "conf.h" -#include "device.h" -// #include "imagetype.h" // imagedata[].name -#include "screens.h" // DLG_, IDC_ -#include "CDVDlinuz.h" // progmodule -#include "mainbox.h" - - -HWND mainboxwindow; - - -void MainBoxDestroy() { - if(mainboxwindow != NULL) { - EndDialog(mainboxwindow, FALSE); - mainboxwindow = NULL; - } // ENDIF- Do we have a Main Window still? -} // END MainBoxDestroy() - - -void MainBoxUnfocus() { - // EnableWindow(?) - // gtk_widget_set_sensitive(mainbox.device, FALSE); - ShowWindow(mainboxwindow, SW_HIDE); -} // END MainBoxUnfocus() - - -void MainBoxDeviceEvent() { - char tempdevice[256]; - struct stat filestat; - int returnval; - - GetDlgItemText(mainboxwindow, IDC_0202, tempdevice, 256); - returnval = stat(tempdevice, &filestat); - if(returnval == -1) { - SetDlgItemText(mainboxwindow, IDC_0203, "Device Type: ---"); - return; - } // ENDIF- Not a name of any sort? - - if(S_ISDIR(filestat.st_mode) != 0) { - SetDlgItemText(mainboxwindow, IDC_0203, "Device Type: Not a device"); - return; - } // ENDIF- Not a regular file? - - SetDlgItemText(mainboxwindow, IDC_0203, "Device Type: Device Likely"); - return; -} // END MainBoxFileEvent() - - -void MainBoxRefocus() { - MainBoxDeviceEvent(); - - // gtk_widget_set_sensitive(mainbox.device, TRUE); - // gtk_window_set_focus(GTK_WINDOW(mainbox.window), mainbox.device); - // ShowWindow(mainboxwindow, SW_RESTORE); // and/or, SW_SHOW? SW_SHOWNORMAL? - ShowWindow(mainboxwindow, SW_SHOW); - SetActiveWindow(mainboxwindow); -} // END MainBoxRefocus() - - -void MainBoxCancelEvent() { - MainBoxDestroy(); - return; -} // END MainBoxCancelEvent() - - -void MainBoxOKEvent() { - int retval; - - MainBoxUnfocus(); - - GetDlgItemText(mainboxwindow, IDC_0202, conf.devicename, 256); - retval = DeviceOpen(); - DeviceClose(); - if(retval != 0) { - MainBoxRefocus(); - MessageBox(mainboxwindow, - "Could not open the device", - "CDVDlinuz Message", - MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); - return; - } // ENDIF- Trouble opening device? Abort here. - - SaveConf(); - - MainBoxCancelEvent(); - return; -} // END MainBoxOKEvent() - - -void MainBoxDisplay() { - InitConf(); // Man, am I boiling mad! CDVDinit() should have been called first! - LoadConf(); - - // Adjust window position? - - // We held off setting the name until now... so description would show. - SetDlgItemText(mainboxwindow, IDC_0202, conf.devicename); - - // First Time - Show the window - ShowWindow(mainboxwindow, SW_SHOWNORMAL); -} // END MainBoxDisplay() - - -BOOL CALLBACK MainBoxCallback(HWND window, - UINT msg, - WPARAM param, - LPARAM param2) { - switch(msg) { - case WM_INITDIALOG: - mainboxwindow = window; - MainBoxDisplay(); // In this case, final touches to this window. - return(FALSE); // And let Windows display this window. - break; - - case WM_CLOSE: // The "X" in the upper right corner was hit. - MainBoxCancelEvent(); - return(TRUE); - break; - - case WM_COMMAND: - // Do we wish to capture 'ENTER/RETURN' and/or 'ESC' here? - - switch(LOWORD(param)) { - case IDC_0202: // Devicename Edit Box - MainBoxDeviceEvent(); // Describe the File's type... - return(FALSE); // Let Windows handle the actual 'edit' processing... - break; - - case IDC_0204: // "Ok" Button - MainBoxOKEvent(); - return(TRUE); - break; - - case IDC_0205: // "Cancel" Button - MainBoxCancelEvent(); - return(TRUE); - break; - } // ENDSWITCH param- Which object got the message? - } // ENDSWITCH msg- what message has been sent to this window? - - return(FALSE); // Not a recognized message? Tell Windows to handle it. -} // END MainBoxEventLoop() +/* mainbox.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + +// #include // Button_ + +#include // NULL + + + +#include // sprintf() + +#include // strcpy() + +#include // stat() + +#include // stat() + +#include // stat() + + + +#include "conf.h" + +#include "device.h" + +// #include "imagetype.h" // imagedata[].name + +#include "screens.h" // DLG_, IDC_ + +#include "CDVDlinuz.h" // progmodule + +#include "mainbox.h" + + + + + +HWND mainboxwindow; + + + + + +void MainBoxDestroy() { + + if(mainboxwindow != NULL) { + + EndDialog(mainboxwindow, FALSE); + + mainboxwindow = NULL; + + } // ENDIF- Do we have a Main Window still? + +} // END MainBoxDestroy() + + + + + +void MainBoxUnfocus() { + + // EnableWindow(?) + + // gtk_widget_set_sensitive(mainbox.device, FALSE); + + ShowWindow(mainboxwindow, SW_HIDE); + +} // END MainBoxUnfocus() + + + + + +void MainBoxDeviceEvent() { + + char tempdevice[256]; + + struct stat filestat; + + int returnval; + + + + GetDlgItemText(mainboxwindow, IDC_0202, tempdevice, 256); + + returnval = stat(tempdevice, &filestat); + + if(returnval == -1) { + + SetDlgItemText(mainboxwindow, IDC_0203, "Device Type: ---"); + + return; + + } // ENDIF- Not a name of any sort? + + + + if(S_ISDIR(filestat.st_mode) != 0) { + + SetDlgItemText(mainboxwindow, IDC_0203, "Device Type: Not a device"); + + return; + + } // ENDIF- Not a regular file? + + + + SetDlgItemText(mainboxwindow, IDC_0203, "Device Type: Device Likely"); + + return; + +} // END MainBoxFileEvent() + + + + + +void MainBoxRefocus() { + + MainBoxDeviceEvent(); + + + + // gtk_widget_set_sensitive(mainbox.device, TRUE); + + // gtk_window_set_focus(GTK_WINDOW(mainbox.window), mainbox.device); + + // ShowWindow(mainboxwindow, SW_RESTORE); // and/or, SW_SHOW? SW_SHOWNORMAL? + + ShowWindow(mainboxwindow, SW_SHOW); + + SetActiveWindow(mainboxwindow); + +} // END MainBoxRefocus() + + + + + +void MainBoxCancelEvent() { + + MainBoxDestroy(); + + return; + +} // END MainBoxCancelEvent() + + + + + +void MainBoxOKEvent() { + + int retval; + + + + MainBoxUnfocus(); + + + + GetDlgItemText(mainboxwindow, IDC_0202, conf.devicename, 256); + + retval = DeviceOpen(); + + DeviceClose(); + + if(retval != 0) { + + MainBoxRefocus(); + + MessageBox(mainboxwindow, + + "Could not open the device", + + "CDVDlinuz Message", + + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); + + return; + + } // ENDIF- Trouble opening device? Abort here. + + + + SaveConf(); + + + + MainBoxCancelEvent(); + + return; + +} // END MainBoxOKEvent() + + + + + +void MainBoxDisplay() { + + InitConf(); // Man, am I boiling mad! CDVDinit() should have been called first! + + LoadConf(); + + + + // Adjust window position? + + + + // We held off setting the name until now... so description would show. + + SetDlgItemText(mainboxwindow, IDC_0202, conf.devicename); + + + + // First Time - Show the window + + ShowWindow(mainboxwindow, SW_SHOWNORMAL); + +} // END MainBoxDisplay() + + + + + +BOOL CALLBACK MainBoxCallback(HWND window, + + UINT msg, + + WPARAM param, + + LPARAM param2) { + + switch(msg) { + + case WM_INITDIALOG: + + mainboxwindow = window; + + MainBoxDisplay(); // In this case, final touches to this window. + + return(FALSE); // And let Windows display this window. + + break; + + + + case WM_CLOSE: // The "X" in the upper right corner was hit. + + MainBoxCancelEvent(); + + return(TRUE); + + break; + + + + case WM_COMMAND: + + // Do we wish to capture 'ENTER/RETURN' and/or 'ESC' here? + + + + switch(LOWORD(param)) { + + case IDC_0202: // Devicename Edit Box + + MainBoxDeviceEvent(); // Describe the File's type... + + return(FALSE); // Let Windows handle the actual 'edit' processing... + + break; + + + + case IDC_0204: // "Ok" Button + + MainBoxOKEvent(); + + return(TRUE); + + break; + + + + case IDC_0205: // "Cancel" Button + + MainBoxCancelEvent(); + + return(TRUE); + + break; + + } // ENDSWITCH param- Which object got the message? + + } // ENDSWITCH msg- what message has been sent to this window? + + + + return(FALSE); // Not a recognized message? Tell Windows to handle it. + +} // END MainBoxEventLoop() + diff --git a/plugins/CDVDlinuz/Src/Win32/mainbox.h b/plugins/CDVDlinuz/Src/Win32/mainbox.h index 850ab6cdcb..e417f51944 100644 --- a/plugins/CDVDlinuz/Src/Win32/mainbox.h +++ b/plugins/CDVDlinuz/Src/Win32/mainbox.h @@ -1,42 +1,84 @@ -/* mainbox.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef MAINBOX_H -#define MAINBOX_H - - -#include // HWND - - -extern const char fileselection[]; - -extern HWND mainboxwindow; - - -extern void MainBoxRefocus(); -extern void MainBoxDisplay(); -extern BOOL CALLBACK MainBoxCallback(HWND window, - UINT msg, - WPARAM param, - LPARAM param2); - - -#endif /* MAINBOX_H */ +/* mainbox.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef MAINBOX_H + +#define MAINBOX_H + + + + + +#include // HWND + + + + + +extern const char fileselection[]; + + + +extern HWND mainboxwindow; + + + + + +extern void MainBoxRefocus(); + +extern void MainBoxDisplay(); + +extern BOOL CALLBACK MainBoxCallback(HWND window, + + UINT msg, + + WPARAM param, + + LPARAM param2); + + + + + +#endif /* MAINBOX_H */ + diff --git a/plugins/CDVDlinuz/Src/Win32/screens.h b/plugins/CDVDlinuz/Src/Win32/screens.h index 7f147436ab..3d12ffad47 100644 --- a/plugins/CDVDlinuz/Src/Win32/screens.h +++ b/plugins/CDVDlinuz/Src/Win32/screens.h @@ -1,9 +1,18 @@ -/* Weditres generated include file. Do NOT edit */ -#include -#define DLG_0100 100 -#define IDC_0104 104 -#define DLG_0200 200 -#define IDC_0202 202 -#define IDC_0203 203 -#define IDC_0204 204 -#define IDC_0205 205 +/* Weditres generated include file. Do NOT edit */ + +#include + +#define DLG_0100 100 + +#define IDC_0104 104 + +#define DLG_0200 200 + +#define IDC_0202 202 + +#define IDC_0203 203 + +#define IDC_0204 204 + +#define IDC_0205 205 + diff --git a/plugins/CDVDlinuz/Src/buffer.c b/plugins/CDVDlinuz/Src/buffer.c index 60e63e4023..d308e96c3a 100644 --- a/plugins/CDVDlinuz/Src/buffer.c +++ b/plugins/CDVDlinuz/Src/buffer.c @@ -1,525 +1,1050 @@ -/* buffer.c - * Copyright (C) 2002-2005 CDVDlinuz 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include // errno -#include // NULL -#include // printf() -#include // strerror() - -#ifndef __LINUX__ -#ifdef __linux__ -#define __LINUX__ -#endif /* __linux__ */ -#endif /* No __LINUX__ */ - -#define CDVDdefs -#include "PS2Edefs.h" - -#include "logfile.h" - -#include "buffer.h" - - -// Globals - -struct BufferSortEmpty { - u16 sortptr; -}; - -struct BufferSort { - u16 upptr; - u16 uppos; - - u32 mask; - u32 divisor; - - struct { - u8 isdata; - u16 ptr; - } lower[256]; - u16 ptrcount; - u16 firstptr; -}; - -struct BufferSortEmpty buffersortempty[BUFFERMAX]; -u16 buffersortemptystart; -u16 buffersortemptyend; - -struct BufferSort buffersort[BUFFERMAX]; -u8 buffersortstartisdata; -u16 buffersortstart; - -struct BufferList bufferlist[BUFFERMAX]; -u16 userbuffer; -u16 replacebuffer; - - -void InitBuffer() { - u16 i; - u16 j; - -#ifdef VERBOSE_FUNCTION_BUFFER - PrintLog("CDVD buffer: InitBuffer()"); -#endif /* VERBOSE_FUNCTION_BUFFER */ - - buffersortemptystart = 0; - buffersortemptyend = 0; - for(i = 0; i < BUFFERMAX; i++) { - buffersortempty[i].sortptr = i; - } // NEXT i- Saying all buffersort[] entries are open. - - buffersortstart = 0xffff; - buffersortstartisdata = 2; - for(i = 0; i < BUFFERMAX; i++) { - for(j = 0; j < 256; j++) buffersort[i].lower[j].isdata = 2; - // buffersort[i].ptrcount = 0; - } // NEXT i- Saying all buffersort[] entries are open. - - for(i = 0; i < BUFFERMAX; i++) { - bufferlist[i].upsort = 0xffff; - } // NEXT i- Clearing out the buffer pointers - userbuffer = 0xffff; - replacebuffer = BUFFERMAX - 1; -} // END InitBuffer(); - - -u16 AllocSortBuffer() { - u16 newbuffer; - -#ifdef VERBOSE_FUNCTION_BUFFER - PrintLog("CDVD buffer: AllocSortBuffer()"); -#endif /* VERBOSE_FUNCTION_BUFFER */ - - newbuffer = buffersortempty[buffersortemptyend].sortptr; - buffersortempty[buffersortemptyend].sortptr = BUFFERMAX; - buffersortemptyend++; - if(buffersortemptyend > BUFFERMAX - 1) buffersortemptyend = 0; - -#ifdef VERBOSE_FUNCTION_BUFFER - PrintLog("CDVD buffer: Sort Buffer %u", newbuffer); -#endif /* VERBOSE_FUNCTION_BUFFER */ - -#ifdef VERBOSE_WARNINGS_BUFFER - if(buffersortemptyend == buffersortemptystart) { - PrintLog("Completely out of Sort Buffers to allocate now!"); - } // ENDIF- Out of Sort Buffers? Say so! -#endif /* VERBOSE_WARNINGS_BUFFER */ - - return(newbuffer); -} // END AllocSortBuffer() - - -void ReleaseSortBuffer(u16 oldbuffer) { -#ifdef VERBOSE_FUNCTION_BUFFER - PrintLog("CDVD buffer: ReleaseSortBuffer(%u)", oldbuffer); -#endif /* VERBOSE_FUNCTION_BUFFER */ - - buffersortempty[buffersortemptystart].sortptr = oldbuffer; - buffersortemptystart++; - if(buffersortemptystart > BUFFERMAX - 1) buffersortemptystart = 0; -} // END ReleaseSortBuffer() - - -// Returns either index in buffersort... or closest insertion point. -// Make lsn == buffersort[int].lsn test for exact match -u16 FindListBuffer(u32 lsn) { - u16 current; - u8 isdata; - u32 index; - -#ifdef VERBOSE_FUNCTION_BUFFER - PrintLog("CDVD buffer: FindListBuffer(%u)", lsn); -#endif /* VERBOSE_FUNCTION_BUFFER */ - - if(buffersortstart == 0xffff) return(0xffff); // Buffer empty? Exit - - if(buffersortstartisdata == 1) { - if(bufferlist[buffersortstart].lsn != lsn) return(0xffff); - return(buffersortstart); - } // ENDIF- Only one Record in Buffer? - -#ifdef VERBOSE_FUNCTION_BUFFER - PrintLog("CDVD buffer: Searching..."); -#endif /* VERBOSE_FUNCTION_BUFFER */ - - current = buffersortstart; - isdata = 0; - while(isdata == 0) { - index = lsn; - index &= buffersort[current].mask; - index /= buffersort[current].divisor; - isdata = buffersort[current].lower[index].isdata; - current = buffersort[current].lower[index].ptr; - } // ENDWHILE- still haven't found data - - if(isdata == 2) return(0xffff); // Pointing at empty entry? - if(bufferlist[current].lsn != lsn) return(0xffff); // LSNs don't match? - -#ifdef VERBOSE_FUNCTION_BUFFER - PrintLog("CDVD buffer: Found."); -#endif /* VERBOSE_FUNCTION_BUFFER */ - return(current); -} // END FindListBuffer() - - -// Removes buffer from the buffersort list -// bufnum = The bufferlist pointer -void RemoveListBuffer(u16 bufnum) { - u16 current; - u16 currentpos; - - u16 upperlink; - u16 upperindex; - - u16 lowerlink; - u8 lowerisdata; - - u32 index; - -#ifdef VERBOSE_FUNCTION_BUFFER - PrintLog("CDVD buffer: RemoveListBuffer(%u)", bufnum); -#endif /* VERBOSE_FUNCTION_BUFFER */ - - if(bufferlist[bufnum].upsort == 0xffff) return; // No link to break. - - current = bufferlist[bufnum].upsort; - currentpos = bufferlist[bufnum].uppos; - bufferlist[bufnum].upsort = 0xffff; - - if(current == 0xfffe) { - buffersortstart = 0xffff; - buffersortstartisdata = 2; -#ifdef VERBOSE_FUNCTION_BUFFER - PrintLog("CDVD buffer: Buffer emptied"); -#endif /* VERBOSE_FUNCTION_BUFFER */ - return; - } // ENDIF- Last link broken... empty buffer now. - - lowerlink = 0xffff; - lowerisdata = 2; - - // Remove Lower Pointer - buffersort[current].lower[currentpos].isdata = 2; - if(currentpos == buffersort[current].firstptr) { - index = currentpos + 1; - while((index < 256) && (buffersort[current].lower[index].isdata == 2)) index++; - buffersort[current].firstptr = index; - } // ENDIF- Do we need to move firstptr to an active entry? - buffersort[current].ptrcount--; -#ifdef VERBOSE_FUNCTION_BUFFER - PrintLog("CDVD buffer: Pointer count for sort buffer %u: %u", - current, buffersort[current].ptrcount); -#endif /* VERBOSE_FUNCTION_BUFFER */ - if(buffersort[current].ptrcount > 1) return; // Still 2+ branches left - - // Find Lower Link - index = buffersort[current].firstptr; - lowerlink = buffersort[current].lower[index].ptr; - lowerisdata = buffersort[current].lower[index].isdata; - buffersort[current].lower[index].isdata = 2; - - // Find and Break Upper Link - upperlink = buffersort[current].upptr; - upperindex = buffersort[current].uppos; - - if(upperlink == 0xffff) { - buffersortstart = lowerlink; - buffersortstartisdata = lowerisdata; - } else { - buffersort[upperlink].lower[upperindex].ptr = lowerlink; - buffersort[upperlink].lower[upperindex].isdata = lowerisdata; - } // ENDIF- Did we hit the top of the web? - - // Break Lower Link - if(lowerisdata == 1) { - if(upperlink == 0xffff) { - bufferlist[lowerlink].upsort = 0xfffe; -#ifdef VERBOSE_FUNCTION_BUFFER - PrintLog("CDVD buffer: Buffer down to 1 record now"); -#endif /* VERBOSE_FUNCTION_BUFFER */ - } else { - bufferlist[lowerlink].upsort = upperlink; - bufferlist[lowerlink].uppos = upperindex; - } // ENDIF- Is this the last active buffersort? - } else { - buffersort[lowerlink].upptr = upperlink; - buffersort[lowerlink].uppos = upperindex; - } // ENDIF- Was this a BufferList link? - - // Cleanup in aisle 5.... - ReleaseSortBuffer(current); - return; -} // END RemoveListBuffer() - - -// Adds buffer to the buffersort list -// bufnum = The bufferlist pointer -void AddListBuffer(u16 bufnum) { - u32 newmask; - u32 newdivisor; - - u16 newbuffer; - u32 newvalue; - - u16 current; - u32 currentvalue; - u8 currentisdata; - - u16 prevbuffer; - u32 prevvalue; - - u16 comparebuffer; - u8 compareisdata; - u32 comparevalue; - -#ifdef VERBOSE_FUNCTION_BUFFER - PrintLog("CDVD buffer: AddListBuffer(%u)", bufnum); -#endif /* VERBOSE_FUNCTION_BUFFER */ - - // Already in list? Oh, re-sorting? Got it covered. - if(bufferlist[bufnum].upsort != 0xffff) RemoveListBuffer(bufnum); - - if(buffersortstartisdata == 2) { - buffersortstart = bufnum; - buffersortstartisdata = 1; - bufferlist[bufnum].upsort = 0xfffe; -#ifdef VERBOSE_FUNCTION_BUFFER - PrintLog("CDVD buffer: Buffer up to 1 record now"); -#endif /* VERBOSE_FUNCTION_BUFFER */ - return; - } // ENDIF- Empty list? Set for just 1 entry. - - if(buffersortstartisdata == 1) { - newmask = 0xff000000; - newdivisor = 0x01000000; - newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; - currentvalue = (bufferlist[buffersortstart].lsn & newmask) / newdivisor; - while((newdivisor != 0x00000001) && (newvalue == currentvalue)) { - newmask /= 0x0100; - newdivisor /= 0x0100; - newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; - currentvalue = (bufferlist[buffersortstart].lsn & newmask) / newdivisor; - } // ENDWHILE- trying to find a difference between the LSNs - - if(newvalue == currentvalue) { - bufferlist[buffersortstart].upsort = 0xffff; - bufferlist[bufnum].upsort = 0xfffe; - buffersortstart = bufnum; - return; - - } else { - newbuffer = AllocSortBuffer(); - buffersort[newbuffer].upptr = 0xffff; - buffersort[newbuffer].mask = newmask; - buffersort[newbuffer].divisor = newdivisor; - buffersort[newbuffer].lower[currentvalue].isdata = 1; - buffersort[newbuffer].lower[currentvalue].ptr = buffersortstart; - buffersort[newbuffer].lower[newvalue].isdata = 1; - buffersort[newbuffer].lower[newvalue].ptr = bufnum; - buffersort[newbuffer].ptrcount = 2; - buffersort[newbuffer].firstptr = currentvalue; - if(newvalue < buffersort[newbuffer].firstptr) - buffersort[newbuffer].firstptr = newvalue; - - bufferlist[buffersortstart].upsort = newbuffer; - bufferlist[buffersortstart].uppos = currentvalue; - buffersortstart = newbuffer; - buffersortstartisdata = 0; - - bufferlist[bufnum].upsort = newbuffer; - bufferlist[bufnum].uppos = newvalue; -#ifdef VERBOSE_FUNCTION_BUFFER - PrintLog("CDVD buffer: Buffer up to 2 records now"); -#endif /* VERBOSE_FUNCTION_BUFFER */ - return; - } // ENDIF- Same LSN? Shift pointer in response. Else, add a Sort Record. - } // ENDIF- Only 1 record? Check if we need a Sort Record. - - newmask = 0xff000000; - newdivisor = 0x01000000; - prevbuffer = 0xffff; - prevvalue = 0; - current = buffersortstart; - currentisdata = 0; - while(currentisdata == 0) { - newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; - - if(buffersort[current].mask != newmask) { - comparebuffer = current; - compareisdata = 0; - while(compareisdata == 0) { - comparevalue = buffersort[comparebuffer].firstptr; - compareisdata = buffersort[comparebuffer].lower[comparevalue].isdata; - comparebuffer = buffersort[comparebuffer].lower[comparevalue].ptr; - } // ENDWHILE- looking for an another buffer to compare to... - - comparevalue = (bufferlist[comparebuffer].lsn & newmask) / newdivisor; - if(newvalue != comparevalue) { - // Add buffersort here (comparevalue/newvalue) - newbuffer = AllocSortBuffer(); - buffersort[newbuffer].upptr = buffersort[current].upptr; - buffersort[newbuffer].uppos = buffersort[current].uppos; - buffersort[newbuffer].mask = newmask; - buffersort[newbuffer].divisor = newdivisor; - buffersort[newbuffer].lower[comparevalue].isdata = 0; - buffersort[newbuffer].lower[comparevalue].ptr = current; - buffersort[newbuffer].lower[newvalue].isdata = 1; - buffersort[newbuffer].lower[newvalue].ptr = bufnum; - buffersort[newbuffer].ptrcount = 2; - buffersort[newbuffer].firstptr = comparevalue; - if(newvalue < buffersort[newbuffer].firstptr) - buffersort[newbuffer].firstptr = newvalue; - - if(buffersort[newbuffer].upptr == 0xffff) { - buffersortstart = newbuffer; - } else { - buffersort[prevbuffer].lower[prevvalue].isdata = 0; - buffersort[prevbuffer].lower[prevvalue].ptr = newbuffer; - if(prevvalue < buffersort[prevbuffer].firstptr) - buffersort[prevbuffer].firstptr = prevvalue; - } // ENDIF- Do we need to adjust to buffersortstart connection? - buffersort[current].upptr = newbuffer; - buffersort[current].uppos = comparevalue; - bufferlist[bufnum].upsort = newbuffer; - bufferlist[bufnum].uppos = newvalue; - return; - } // ENDIF- Don't match? Add a buffersort here to say that! - - compareisdata = 0; - newmask /= 0x0100; - newdivisor /= 0x0100; - - } else { - currentisdata = buffersort[current].lower[newvalue].isdata; - prevbuffer = current; - prevvalue = newvalue; - if(currentisdata == 0) { - current = buffersort[current].lower[newvalue].ptr; - newmask /= 0x0100; - newdivisor /= 0x0100; - if(newdivisor == 0) { -#ifdef VERBOSE_WARNINGS_BUFFER - PrintLog("CDVD buffer: Mask/Divisor at 0! Index corruption! (detected in search)"); -#endif /* VERBOSE_WARNINGS_BUFFER */ - return; - } // ENDIF- The Mask went too far! Abort! (Sanity Check) - } // ENDIF- Do we have to go through another level of sort data? - } // ENDIF- We don't have a comparison on this byte? - } // ENDWHILE- looking for his level... - - if(buffersort[current].lower[newvalue].isdata == 2) { - buffersort[current].lower[newvalue].isdata = 1; - buffersort[current].lower[newvalue].ptr = bufnum; - buffersort[current].ptrcount++; - if(newvalue < buffersort[current].firstptr) - buffersort[current].firstptr = newvalue; - bufferlist[bufnum].upsort = current; - bufferlist[bufnum].uppos = newvalue; - return; - } // ENDIF- an empty slot? Fill it in. - - comparebuffer = buffersort[current].lower[newvalue].ptr; - if(bufferlist[bufnum].lsn == bufferlist[comparebuffer].lsn) { - buffersort[current].lower[newvalue].ptr = bufnum; - bufferlist[bufnum].upsort = current; - bufferlist[bufnum].uppos = newvalue; - bufferlist[comparebuffer].upsort = 0xffff; - return; - } // ENDIF- Same LSN? Replace! - - // Calc new position based on new separation markers... - newmask /= 0x0100; - newdivisor /= 0x0100; - if(newdivisor == 0) { -#ifdef VERBOSE_WARNINGS_BUFFER - PrintLog("CDVD buffer: Mask/Divisor at 0! Index corruption! (bottom add initial)"); -#endif /* VERBOSE_WARNINGS_BUFFER */ - return; - } // ENDIF- The Mask went too far! Abort! (Sanity Check) - newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; - comparevalue = (bufferlist[comparebuffer].lsn & newmask) / newdivisor; - while((newmask != 0x000000ff) && (comparevalue == newvalue)) { - newmask /= 0x0100; - newdivisor /= 0x0100; - if(newdivisor == 0) { -#ifdef VERBOSE_WARNINGS_BUFFER - PrintLog("CDVD buffer: Mask/Divisor at 0! Index corruption! (bottom add loop)"); -#endif /* VERBOSE_WARNINGS_BUFFER */ - return; - } // ENDIF- The Mask went too far! Abort! (Sanity Check) - newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; - comparevalue = (bufferlist[comparebuffer].lsn & newmask) / newdivisor; - } // ENDWHILE- continuing to scan for difference between the two numbers - - newbuffer = AllocSortBuffer(); - buffersort[newbuffer].upptr = prevbuffer; - buffersort[newbuffer].uppos = prevvalue; - buffersort[newbuffer].mask = newmask; - buffersort[newbuffer].divisor = newdivisor; - buffersort[newbuffer].lower[comparevalue].isdata = 1; - buffersort[newbuffer].lower[comparevalue].ptr = comparebuffer; - buffersort[newbuffer].lower[newvalue].isdata = 1; - buffersort[newbuffer].lower[newvalue].ptr = bufnum; - buffersort[newbuffer].ptrcount = 2; - buffersort[newbuffer].firstptr = comparevalue; - if(newvalue < buffersort[newbuffer].firstptr) - buffersort[newbuffer].firstptr = newvalue; - - buffersort[prevbuffer].lower[prevvalue].isdata = 0; - buffersort[prevbuffer].lower[prevvalue].ptr = newbuffer; - bufferlist[comparebuffer].upsort = newbuffer; - bufferlist[comparebuffer].uppos = comparevalue; - bufferlist[bufnum].upsort = newbuffer; - bufferlist[bufnum].uppos = newvalue; -} // END AddListBuffer() - -#ifdef VERBOSE_WARNINGS_BUFFER -void PrintSortBuffers() { - u16 h; - u16 i; - u16 j; - - printf("CDVD buffer: Sort Buffer Dump\n"); - printf("CDVD buffer: Top Pointer: isdata %u ptr %u\n", - buffersortstartisdata, buffersortstart); - for(i = 0; i < BUFFERMAX; i++) { - - h = 0; - while((h < BUFFERMAX) && (buffersortempty[h].sortptr != i)) h++; - - if(h == BUFFERMAX) { - printf("CDVD buffer: Sort Buffer:%u Mask:%x Divisor:%x\n", - i, buffersort[i].mask, buffersort[i].divisor); - printf("CDVD buffer: Up Ptr:%u Up Pos:%u First Down Ptr:%u Ptr Count: %u\n", - buffersort[i].upptr, - buffersort[i].uppos, - buffersort[i].firstptr, - buffersort[i].ptrcount); - printf("CDVD buffer: "); - for(j = 0; j < 256; j++) { - if(buffersort[i].lower[j].isdata == 1) printf(" D"); - if(buffersort[i].lower[j].isdata == 0) printf(" L"); - if(buffersort[i].lower[j].isdata < 2) { - printf("%u:%u", j, buffersort[i].lower[j].ptr); - } // ENDIF- We have active data? Print it. - } // NEXT j- Scanning lower 256 pointers for active ones... - printf("\n"); - } // ENDIF- Not found in inactive list? Must be active! Print it. - } // NEXT i- looking at all the Allocated Buffers... -} // END PrintSortBuffers() -#endif /* VERBOSE_WARNINGS_BUFFER */ +/* buffer.c + + * Copyright (C) 2002-2005 CDVDlinuz 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + */ + + + +#include // errno + +#include // NULL + +#include // printf() + +#include // strerror() + + + +#ifndef __LINUX__ + +#ifdef __linux__ + +#define __LINUX__ + +#endif /* __linux__ */ + +#endif /* No __LINUX__ */ + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + +#include "logfile.h" + + + +#include "buffer.h" + + + + + +// Globals + + + +struct BufferSortEmpty { + + u16 sortptr; + +}; + + + +struct BufferSort { + + u16 upptr; + + u16 uppos; + + + + u32 mask; + + u32 divisor; + + + + struct { + + u8 isdata; + + u16 ptr; + + } lower[256]; + + u16 ptrcount; + + u16 firstptr; + +}; + + + +struct BufferSortEmpty buffersortempty[BUFFERMAX]; + +u16 buffersortemptystart; + +u16 buffersortemptyend; + + + +struct BufferSort buffersort[BUFFERMAX]; + +u8 buffersortstartisdata; + +u16 buffersortstart; + + + +struct BufferList bufferlist[BUFFERMAX]; + +u16 userbuffer; + +u16 replacebuffer; + + + + + +void InitBuffer() { + + u16 i; + + u16 j; + + + +#ifdef VERBOSE_FUNCTION_BUFFER + + PrintLog("CDVD buffer: InitBuffer()"); + +#endif /* VERBOSE_FUNCTION_BUFFER */ + + + + buffersortemptystart = 0; + + buffersortemptyend = 0; + + for(i = 0; i < BUFFERMAX; i++) { + + buffersortempty[i].sortptr = i; + + } // NEXT i- Saying all buffersort[] entries are open. + + + + buffersortstart = 0xffff; + + buffersortstartisdata = 2; + + for(i = 0; i < BUFFERMAX; i++) { + + for(j = 0; j < 256; j++) buffersort[i].lower[j].isdata = 2; + + // buffersort[i].ptrcount = 0; + + } // NEXT i- Saying all buffersort[] entries are open. + + + + for(i = 0; i < BUFFERMAX; i++) { + + bufferlist[i].upsort = 0xffff; + + } // NEXT i- Clearing out the buffer pointers + + userbuffer = 0xffff; + + replacebuffer = BUFFERMAX - 1; + +} // END InitBuffer(); + + + + + +u16 AllocSortBuffer() { + + u16 newbuffer; + + + +#ifdef VERBOSE_FUNCTION_BUFFER + + PrintLog("CDVD buffer: AllocSortBuffer()"); + +#endif /* VERBOSE_FUNCTION_BUFFER */ + + + + newbuffer = buffersortempty[buffersortemptyend].sortptr; + + buffersortempty[buffersortemptyend].sortptr = BUFFERMAX; + + buffersortemptyend++; + + if(buffersortemptyend > BUFFERMAX - 1) buffersortemptyend = 0; + + + +#ifdef VERBOSE_FUNCTION_BUFFER + + PrintLog("CDVD buffer: Sort Buffer %u", newbuffer); + +#endif /* VERBOSE_FUNCTION_BUFFER */ + + + +#ifdef VERBOSE_WARNINGS_BUFFER + + if(buffersortemptyend == buffersortemptystart) { + + PrintLog("Completely out of Sort Buffers to allocate now!"); + + } // ENDIF- Out of Sort Buffers? Say so! + +#endif /* VERBOSE_WARNINGS_BUFFER */ + + + + return(newbuffer); + +} // END AllocSortBuffer() + + + + + +void ReleaseSortBuffer(u16 oldbuffer) { + +#ifdef VERBOSE_FUNCTION_BUFFER + + PrintLog("CDVD buffer: ReleaseSortBuffer(%u)", oldbuffer); + +#endif /* VERBOSE_FUNCTION_BUFFER */ + + + + buffersortempty[buffersortemptystart].sortptr = oldbuffer; + + buffersortemptystart++; + + if(buffersortemptystart > BUFFERMAX - 1) buffersortemptystart = 0; + +} // END ReleaseSortBuffer() + + + + + +// Returns either index in buffersort... or closest insertion point. + +// Make lsn == buffersort[int].lsn test for exact match + +u16 FindListBuffer(u32 lsn) { + + u16 current; + + u8 isdata; + + u32 index; + + + +#ifdef VERBOSE_FUNCTION_BUFFER + + PrintLog("CDVD buffer: FindListBuffer(%u)", lsn); + +#endif /* VERBOSE_FUNCTION_BUFFER */ + + + + if(buffersortstart == 0xffff) return(0xffff); // Buffer empty? Exit + + + + if(buffersortstartisdata == 1) { + + if(bufferlist[buffersortstart].lsn != lsn) return(0xffff); + + return(buffersortstart); + + } // ENDIF- Only one Record in Buffer? + + + +#ifdef VERBOSE_FUNCTION_BUFFER + + PrintLog("CDVD buffer: Searching..."); + +#endif /* VERBOSE_FUNCTION_BUFFER */ + + + + current = buffersortstart; + + isdata = 0; + + while(isdata == 0) { + + index = lsn; + + index &= buffersort[current].mask; + + index /= buffersort[current].divisor; + + isdata = buffersort[current].lower[index].isdata; + + current = buffersort[current].lower[index].ptr; + + } // ENDWHILE- still haven't found data + + + + if(isdata == 2) return(0xffff); // Pointing at empty entry? + + if(bufferlist[current].lsn != lsn) return(0xffff); // LSNs don't match? + + + +#ifdef VERBOSE_FUNCTION_BUFFER + + PrintLog("CDVD buffer: Found."); + +#endif /* VERBOSE_FUNCTION_BUFFER */ + + return(current); + +} // END FindListBuffer() + + + + + +// Removes buffer from the buffersort list + +// bufnum = The bufferlist pointer + +void RemoveListBuffer(u16 bufnum) { + + u16 current; + + u16 currentpos; + + + + u16 upperlink; + + u16 upperindex; + + + + u16 lowerlink; + + u8 lowerisdata; + + + + u32 index; + + + +#ifdef VERBOSE_FUNCTION_BUFFER + + PrintLog("CDVD buffer: RemoveListBuffer(%u)", bufnum); + +#endif /* VERBOSE_FUNCTION_BUFFER */ + + + + if(bufferlist[bufnum].upsort == 0xffff) return; // No link to break. + + + + current = bufferlist[bufnum].upsort; + + currentpos = bufferlist[bufnum].uppos; + + bufferlist[bufnum].upsort = 0xffff; + + + + if(current == 0xfffe) { + + buffersortstart = 0xffff; + + buffersortstartisdata = 2; + +#ifdef VERBOSE_FUNCTION_BUFFER + + PrintLog("CDVD buffer: Buffer emptied"); + +#endif /* VERBOSE_FUNCTION_BUFFER */ + + return; + + } // ENDIF- Last link broken... empty buffer now. + + + + lowerlink = 0xffff; + + lowerisdata = 2; + + + + // Remove Lower Pointer + + buffersort[current].lower[currentpos].isdata = 2; + + if(currentpos == buffersort[current].firstptr) { + + index = currentpos + 1; + + while((index < 256) && (buffersort[current].lower[index].isdata == 2)) index++; + + buffersort[current].firstptr = index; + + } // ENDIF- Do we need to move firstptr to an active entry? + + buffersort[current].ptrcount--; + +#ifdef VERBOSE_FUNCTION_BUFFER + + PrintLog("CDVD buffer: Pointer count for sort buffer %u: %u", + + current, buffersort[current].ptrcount); + +#endif /* VERBOSE_FUNCTION_BUFFER */ + + if(buffersort[current].ptrcount > 1) return; // Still 2+ branches left + + + + // Find Lower Link + + index = buffersort[current].firstptr; + + lowerlink = buffersort[current].lower[index].ptr; + + lowerisdata = buffersort[current].lower[index].isdata; + + buffersort[current].lower[index].isdata = 2; + + + + // Find and Break Upper Link + + upperlink = buffersort[current].upptr; + + upperindex = buffersort[current].uppos; + + + + if(upperlink == 0xffff) { + + buffersortstart = lowerlink; + + buffersortstartisdata = lowerisdata; + + } else { + + buffersort[upperlink].lower[upperindex].ptr = lowerlink; + + buffersort[upperlink].lower[upperindex].isdata = lowerisdata; + + } // ENDIF- Did we hit the top of the web? + + + + // Break Lower Link + + if(lowerisdata == 1) { + + if(upperlink == 0xffff) { + + bufferlist[lowerlink].upsort = 0xfffe; + +#ifdef VERBOSE_FUNCTION_BUFFER + + PrintLog("CDVD buffer: Buffer down to 1 record now"); + +#endif /* VERBOSE_FUNCTION_BUFFER */ + + } else { + + bufferlist[lowerlink].upsort = upperlink; + + bufferlist[lowerlink].uppos = upperindex; + + } // ENDIF- Is this the last active buffersort? + + } else { + + buffersort[lowerlink].upptr = upperlink; + + buffersort[lowerlink].uppos = upperindex; + + } // ENDIF- Was this a BufferList link? + + + + // Cleanup in aisle 5.... + + ReleaseSortBuffer(current); + + return; + +} // END RemoveListBuffer() + + + + + +// Adds buffer to the buffersort list + +// bufnum = The bufferlist pointer + +void AddListBuffer(u16 bufnum) { + + u32 newmask; + + u32 newdivisor; + + + + u16 newbuffer; + + u32 newvalue; + + + + u16 current; + + u32 currentvalue; + + u8 currentisdata; + + + + u16 prevbuffer; + + u32 prevvalue; + + + + u16 comparebuffer; + + u8 compareisdata; + + u32 comparevalue; + + + +#ifdef VERBOSE_FUNCTION_BUFFER + + PrintLog("CDVD buffer: AddListBuffer(%u)", bufnum); + +#endif /* VERBOSE_FUNCTION_BUFFER */ + + + + // Already in list? Oh, re-sorting? Got it covered. + + if(bufferlist[bufnum].upsort != 0xffff) RemoveListBuffer(bufnum); + + + + if(buffersortstartisdata == 2) { + + buffersortstart = bufnum; + + buffersortstartisdata = 1; + + bufferlist[bufnum].upsort = 0xfffe; + +#ifdef VERBOSE_FUNCTION_BUFFER + + PrintLog("CDVD buffer: Buffer up to 1 record now"); + +#endif /* VERBOSE_FUNCTION_BUFFER */ + + return; + + } // ENDIF- Empty list? Set for just 1 entry. + + + + if(buffersortstartisdata == 1) { + + newmask = 0xff000000; + + newdivisor = 0x01000000; + + newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; + + currentvalue = (bufferlist[buffersortstart].lsn & newmask) / newdivisor; + + while((newdivisor != 0x00000001) && (newvalue == currentvalue)) { + + newmask /= 0x0100; + + newdivisor /= 0x0100; + + newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; + + currentvalue = (bufferlist[buffersortstart].lsn & newmask) / newdivisor; + + } // ENDWHILE- trying to find a difference between the LSNs + + + + if(newvalue == currentvalue) { + + bufferlist[buffersortstart].upsort = 0xffff; + + bufferlist[bufnum].upsort = 0xfffe; + + buffersortstart = bufnum; + + return; + + + + } else { + + newbuffer = AllocSortBuffer(); + + buffersort[newbuffer].upptr = 0xffff; + + buffersort[newbuffer].mask = newmask; + + buffersort[newbuffer].divisor = newdivisor; + + buffersort[newbuffer].lower[currentvalue].isdata = 1; + + buffersort[newbuffer].lower[currentvalue].ptr = buffersortstart; + + buffersort[newbuffer].lower[newvalue].isdata = 1; + + buffersort[newbuffer].lower[newvalue].ptr = bufnum; + + buffersort[newbuffer].ptrcount = 2; + + buffersort[newbuffer].firstptr = currentvalue; + + if(newvalue < buffersort[newbuffer].firstptr) + + buffersort[newbuffer].firstptr = newvalue; + + + + bufferlist[buffersortstart].upsort = newbuffer; + + bufferlist[buffersortstart].uppos = currentvalue; + + buffersortstart = newbuffer; + + buffersortstartisdata = 0; + + + + bufferlist[bufnum].upsort = newbuffer; + + bufferlist[bufnum].uppos = newvalue; + +#ifdef VERBOSE_FUNCTION_BUFFER + + PrintLog("CDVD buffer: Buffer up to 2 records now"); + +#endif /* VERBOSE_FUNCTION_BUFFER */ + + return; + + } // ENDIF- Same LSN? Shift pointer in response. Else, add a Sort Record. + + } // ENDIF- Only 1 record? Check if we need a Sort Record. + + + + newmask = 0xff000000; + + newdivisor = 0x01000000; + + prevbuffer = 0xffff; + + prevvalue = 0; + + current = buffersortstart; + + currentisdata = 0; + + while(currentisdata == 0) { + + newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; + + + + if(buffersort[current].mask != newmask) { + + comparebuffer = current; + + compareisdata = 0; + + while(compareisdata == 0) { + + comparevalue = buffersort[comparebuffer].firstptr; + + compareisdata = buffersort[comparebuffer].lower[comparevalue].isdata; + + comparebuffer = buffersort[comparebuffer].lower[comparevalue].ptr; + + } // ENDWHILE- looking for an another buffer to compare to... + + + + comparevalue = (bufferlist[comparebuffer].lsn & newmask) / newdivisor; + + if(newvalue != comparevalue) { + + // Add buffersort here (comparevalue/newvalue) + + newbuffer = AllocSortBuffer(); + + buffersort[newbuffer].upptr = buffersort[current].upptr; + + buffersort[newbuffer].uppos = buffersort[current].uppos; + + buffersort[newbuffer].mask = newmask; + + buffersort[newbuffer].divisor = newdivisor; + + buffersort[newbuffer].lower[comparevalue].isdata = 0; + + buffersort[newbuffer].lower[comparevalue].ptr = current; + + buffersort[newbuffer].lower[newvalue].isdata = 1; + + buffersort[newbuffer].lower[newvalue].ptr = bufnum; + + buffersort[newbuffer].ptrcount = 2; + + buffersort[newbuffer].firstptr = comparevalue; + + if(newvalue < buffersort[newbuffer].firstptr) + + buffersort[newbuffer].firstptr = newvalue; + + + + if(buffersort[newbuffer].upptr == 0xffff) { + + buffersortstart = newbuffer; + + } else { + + buffersort[prevbuffer].lower[prevvalue].isdata = 0; + + buffersort[prevbuffer].lower[prevvalue].ptr = newbuffer; + + if(prevvalue < buffersort[prevbuffer].firstptr) + + buffersort[prevbuffer].firstptr = prevvalue; + + } // ENDIF- Do we need to adjust to buffersortstart connection? + + buffersort[current].upptr = newbuffer; + + buffersort[current].uppos = comparevalue; + + bufferlist[bufnum].upsort = newbuffer; + + bufferlist[bufnum].uppos = newvalue; + + return; + + } // ENDIF- Don't match? Add a buffersort here to say that! + + + + compareisdata = 0; + + newmask /= 0x0100; + + newdivisor /= 0x0100; + + + + } else { + + currentisdata = buffersort[current].lower[newvalue].isdata; + + prevbuffer = current; + + prevvalue = newvalue; + + if(currentisdata == 0) { + + current = buffersort[current].lower[newvalue].ptr; + + newmask /= 0x0100; + + newdivisor /= 0x0100; + + if(newdivisor == 0) { + +#ifdef VERBOSE_WARNINGS_BUFFER + + PrintLog("CDVD buffer: Mask/Divisor at 0! Index corruption! (detected in search)"); + +#endif /* VERBOSE_WARNINGS_BUFFER */ + + return; + + } // ENDIF- The Mask went too far! Abort! (Sanity Check) + + } // ENDIF- Do we have to go through another level of sort data? + + } // ENDIF- We don't have a comparison on this byte? + + } // ENDWHILE- looking for his level... + + + + if(buffersort[current].lower[newvalue].isdata == 2) { + + buffersort[current].lower[newvalue].isdata = 1; + + buffersort[current].lower[newvalue].ptr = bufnum; + + buffersort[current].ptrcount++; + + if(newvalue < buffersort[current].firstptr) + + buffersort[current].firstptr = newvalue; + + bufferlist[bufnum].upsort = current; + + bufferlist[bufnum].uppos = newvalue; + + return; + + } // ENDIF- an empty slot? Fill it in. + + + + comparebuffer = buffersort[current].lower[newvalue].ptr; + + if(bufferlist[bufnum].lsn == bufferlist[comparebuffer].lsn) { + + buffersort[current].lower[newvalue].ptr = bufnum; + + bufferlist[bufnum].upsort = current; + + bufferlist[bufnum].uppos = newvalue; + + bufferlist[comparebuffer].upsort = 0xffff; + + return; + + } // ENDIF- Same LSN? Replace! + + + + // Calc new position based on new separation markers... + + newmask /= 0x0100; + + newdivisor /= 0x0100; + + if(newdivisor == 0) { + +#ifdef VERBOSE_WARNINGS_BUFFER + + PrintLog("CDVD buffer: Mask/Divisor at 0! Index corruption! (bottom add initial)"); + +#endif /* VERBOSE_WARNINGS_BUFFER */ + + return; + + } // ENDIF- The Mask went too far! Abort! (Sanity Check) + + newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; + + comparevalue = (bufferlist[comparebuffer].lsn & newmask) / newdivisor; + + while((newmask != 0x000000ff) && (comparevalue == newvalue)) { + + newmask /= 0x0100; + + newdivisor /= 0x0100; + + if(newdivisor == 0) { + +#ifdef VERBOSE_WARNINGS_BUFFER + + PrintLog("CDVD buffer: Mask/Divisor at 0! Index corruption! (bottom add loop)"); + +#endif /* VERBOSE_WARNINGS_BUFFER */ + + return; + + } // ENDIF- The Mask went too far! Abort! (Sanity Check) + + newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; + + comparevalue = (bufferlist[comparebuffer].lsn & newmask) / newdivisor; + + } // ENDWHILE- continuing to scan for difference between the two numbers + + + + newbuffer = AllocSortBuffer(); + + buffersort[newbuffer].upptr = prevbuffer; + + buffersort[newbuffer].uppos = prevvalue; + + buffersort[newbuffer].mask = newmask; + + buffersort[newbuffer].divisor = newdivisor; + + buffersort[newbuffer].lower[comparevalue].isdata = 1; + + buffersort[newbuffer].lower[comparevalue].ptr = comparebuffer; + + buffersort[newbuffer].lower[newvalue].isdata = 1; + + buffersort[newbuffer].lower[newvalue].ptr = bufnum; + + buffersort[newbuffer].ptrcount = 2; + + buffersort[newbuffer].firstptr = comparevalue; + + if(newvalue < buffersort[newbuffer].firstptr) + + buffersort[newbuffer].firstptr = newvalue; + + + + buffersort[prevbuffer].lower[prevvalue].isdata = 0; + + buffersort[prevbuffer].lower[prevvalue].ptr = newbuffer; + + bufferlist[comparebuffer].upsort = newbuffer; + + bufferlist[comparebuffer].uppos = comparevalue; + + bufferlist[bufnum].upsort = newbuffer; + + bufferlist[bufnum].uppos = newvalue; + +} // END AddListBuffer() + + + +#ifdef VERBOSE_WARNINGS_BUFFER + +void PrintSortBuffers() { + + u16 h; + + u16 i; + + u16 j; + + + + printf("CDVD buffer: Sort Buffer Dump\n"); + + printf("CDVD buffer: Top Pointer: isdata %u ptr %u\n", + + buffersortstartisdata, buffersortstart); + + for(i = 0; i < BUFFERMAX; i++) { + + + + h = 0; + + while((h < BUFFERMAX) && (buffersortempty[h].sortptr != i)) h++; + + + + if(h == BUFFERMAX) { + + printf("CDVD buffer: Sort Buffer:%u Mask:%x Divisor:%x\n", + + i, buffersort[i].mask, buffersort[i].divisor); + + printf("CDVD buffer: Up Ptr:%u Up Pos:%u First Down Ptr:%u Ptr Count: %u\n", + + buffersort[i].upptr, + + buffersort[i].uppos, + + buffersort[i].firstptr, + + buffersort[i].ptrcount); + + printf("CDVD buffer: "); + + for(j = 0; j < 256; j++) { + + if(buffersort[i].lower[j].isdata == 1) printf(" D"); + + if(buffersort[i].lower[j].isdata == 0) printf(" L"); + + if(buffersort[i].lower[j].isdata < 2) { + + printf("%u:%u", j, buffersort[i].lower[j].ptr); + + } // ENDIF- We have active data? Print it. + + } // NEXT j- Scanning lower 256 pointers for active ones... + + printf("\n"); + + } // ENDIF- Not found in inactive list? Must be active! Print it. + + } // NEXT i- looking at all the Allocated Buffers... + +} // END PrintSortBuffers() + +#endif /* VERBOSE_WARNINGS_BUFFER */ + diff --git a/plugins/CDVDlinuz/Src/buffer.h b/plugins/CDVDlinuz/Src/buffer.h index fefe605061..3b2ec4d003 100644 --- a/plugins/CDVDlinuz/Src/buffer.h +++ b/plugins/CDVDlinuz/Src/buffer.h @@ -1,67 +1,134 @@ -/* buffer.h - * Copyright (C) 2002-2005 CDVDlinuz 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __BUFFER_H__ -#define __BUFFER_H__ - - -#define CDVDdefs -#include "PS2Edefs.h" - - -// #define VERBOSE_FUNCTION_BUFFER -// #define VERBOSE_WARNINGS_BUFFER - -// Remember, each buffer set is about 5k (packed. might be 4x that in-memory) -// Minimum: 16 Maximum: 32760 -#define BUFFERMAX 256 - - -// Buffer Structures - -struct BufferList { - u16 upsort; // Don't alter this variable - u16 uppos; // Don't alter this variable - - u32 lsn; - int mode; // -1 means error - u8 buffer[2368]; - u8 offset; - cdvdSubQ subq; -}; - - -// Exported Variables - -extern struct BufferList bufferlist[]; -extern u16 userbuffer; -extern u16 replacebuffer; - - -// Exported Functions - -extern void InitBuffer(); -extern u16 FindListBuffer(u32 lsn); -extern void RemoveListBuffer(u16 oldbuffer); -extern void AddListBuffer(u16 newbuffer); -#ifdef VERBOSE_WARNINGS_BUFFER -extern void PrintSortBuffers(); -#endif /* VERBOSE_WARNINGS_BUFFER */ - - -#endif /* __BUFFER_H__ */ +/* buffer.h + + * Copyright (C) 2002-2005 CDVDlinuz 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + */ + + + +#ifndef __BUFFER_H__ + +#define __BUFFER_H__ + + + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + + + +// #define VERBOSE_FUNCTION_BUFFER + +// #define VERBOSE_WARNINGS_BUFFER + + + +// Remember, each buffer set is about 5k (packed. might be 4x that in-memory) + +// Minimum: 16 Maximum: 32760 + +#define BUFFERMAX 256 + + + + + +// Buffer Structures + + + +struct BufferList { + + u16 upsort; // Don't alter this variable + + u16 uppos; // Don't alter this variable + + + + u32 lsn; + + int mode; // -1 means error + + u8 buffer[2368]; + + u8 offset; + + cdvdSubQ subq; + +}; + + + + + +// Exported Variables + + + +extern struct BufferList bufferlist[]; + +extern u16 userbuffer; + +extern u16 replacebuffer; + + + + + +// Exported Functions + + + +extern void InitBuffer(); + +extern u16 FindListBuffer(u32 lsn); + +extern void RemoveListBuffer(u16 oldbuffer); + +extern void AddListBuffer(u16 newbuffer); + +#ifdef VERBOSE_WARNINGS_BUFFER + +extern void PrintSortBuffers(); + +#endif /* VERBOSE_WARNINGS_BUFFER */ + + + + + +#endif /* __BUFFER_H__ */ + diff --git a/plugins/CDVDlinuz/Src/convert.c b/plugins/CDVDlinuz/Src/convert.c index 9e6a62a2da..7579673933 100644 --- a/plugins/CDVDlinuz/Src/convert.c +++ b/plugins/CDVDlinuz/Src/convert.c @@ -1,118 +1,236 @@ -/* convert.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include -#include - -#include "convert.h" - - -off64_t ConvertEndianOffset(off64_t number) { -#ifndef CONVERTLITTLEENDIAN - union { - off64_t n; - char c[sizeof(off64_t)]; - } oldnumber, newnumber; - int i; - - oldnumber.n = number; - for(i = 0; i < sizeof(off64_t); i++) - newnumber.c[i] = oldnumber.c[sizeof(off64_t) - 1 - i]; - return(newnumber.n); -#else - return(number); -#endif /* CONVERTLITTLEENDIAN */ -} // END ConvertEndianOffset() - - -unsigned int ConvertEndianUInt(unsigned int number) { -#ifndef CONVERTLITTLEENDIAN - union { - unsigned int n; - char c[sizeof(unsigned int)]; - } oldnumber, newnumber; - int i; - - oldnumber.n = number; - for(i = 0; i < sizeof(unsigned int); i++) - newnumber.c[i] = oldnumber.c[sizeof(unsigned int) - 1 - i]; - return(newnumber.n); -#else - return(number); -#endif /* CONVERTLITTLEENDIAN */ -} // END ConvertEndianUInt() - - -unsigned short ConvertEndianUShort(unsigned short number) { -#ifndef CONVERTLITTLEENDIAN - union { - unsigned short n; - char c[sizeof(unsigned short)]; - } oldnumber, newnumber; - int i; - - oldnumber.n = number; - for(i = 0; i < sizeof(unsigned short); i++) - newnumber.c[i] = oldnumber.c[sizeof(unsigned short) - 1 - i]; - return(newnumber.n); -#else - return(number); -#endif /* CONVERTLITTLEENDIAN */ -} // END ConvertEndianUShort() - - -// Note: deposits M/S/F data in buffer[0]/[1]/[2] respectively. -void LBAtoMSF(unsigned long lsn, char *buffer) { - unsigned long templsn; - - if(lsn >= 0xFFFFFFFF - 150) { - *(buffer + 2) = 75-1; - *(buffer + 1) = 60-1; - *(buffer) = 100-1; - } // ENDIF- Out of range? - - templsn = lsn; - templsn += 150; // 2 second offset (75 Frames * 2 Seconds) - *(buffer + 2) = templsn % 75; // Remainder in frames - templsn -= *(buffer + 2); - templsn /= 75; - *(buffer + 1) = templsn % 60; // Remainder in seconds - templsn -= *(buffer + 1); - templsn /= 60; - *(buffer) = templsn; // Leftover quotient in minutes -} // END LBAtoMSF() - - -unsigned long MSFtoLBA(char *buffer) { - unsigned long templsn; - - if(buffer == NULL) return(0xFFFFFFFF); - - templsn = *(buffer); // Minutes - templsn *= 60; - templsn += *(buffer + 1); // Seconds - templsn *= 75; - templsn += *(buffer + 2); // Frames - if(templsn < 150) return(0xFFFFFFFF); - templsn -= 150; // Offset - - return(templsn); -} // END MSFtoLBA() +/* convert.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include + +#include + + + +#include "convert.h" + + + + + +off64_t ConvertEndianOffset(off64_t number) { + +#ifndef CONVERTLITTLEENDIAN + + union { + + off64_t n; + + char c[sizeof(off64_t)]; + + } oldnumber, newnumber; + + int i; + + + + oldnumber.n = number; + + for(i = 0; i < sizeof(off64_t); i++) + + newnumber.c[i] = oldnumber.c[sizeof(off64_t) - 1 - i]; + + return(newnumber.n); + +#else + + return(number); + +#endif /* CONVERTLITTLEENDIAN */ + +} // END ConvertEndianOffset() + + + + + +unsigned int ConvertEndianUInt(unsigned int number) { + +#ifndef CONVERTLITTLEENDIAN + + union { + + unsigned int n; + + char c[sizeof(unsigned int)]; + + } oldnumber, newnumber; + + int i; + + + + oldnumber.n = number; + + for(i = 0; i < sizeof(unsigned int); i++) + + newnumber.c[i] = oldnumber.c[sizeof(unsigned int) - 1 - i]; + + return(newnumber.n); + +#else + + return(number); + +#endif /* CONVERTLITTLEENDIAN */ + +} // END ConvertEndianUInt() + + + + + +unsigned short ConvertEndianUShort(unsigned short number) { + +#ifndef CONVERTLITTLEENDIAN + + union { + + unsigned short n; + + char c[sizeof(unsigned short)]; + + } oldnumber, newnumber; + + int i; + + + + oldnumber.n = number; + + for(i = 0; i < sizeof(unsigned short); i++) + + newnumber.c[i] = oldnumber.c[sizeof(unsigned short) - 1 - i]; + + return(newnumber.n); + +#else + + return(number); + +#endif /* CONVERTLITTLEENDIAN */ + +} // END ConvertEndianUShort() + + + + + +// Note: deposits M/S/F data in buffer[0]/[1]/[2] respectively. + +void LBAtoMSF(unsigned long lsn, char *buffer) { + + unsigned long templsn; + + + + if(lsn >= 0xFFFFFFFF - 150) { + + *(buffer + 2) = 75-1; + + *(buffer + 1) = 60-1; + + *(buffer) = 100-1; + + } // ENDIF- Out of range? + + + + templsn = lsn; + + templsn += 150; // 2 second offset (75 Frames * 2 Seconds) + + *(buffer + 2) = templsn % 75; // Remainder in frames + + templsn -= *(buffer + 2); + + templsn /= 75; + + *(buffer + 1) = templsn % 60; // Remainder in seconds + + templsn -= *(buffer + 1); + + templsn /= 60; + + *(buffer) = templsn; // Leftover quotient in minutes + +} // END LBAtoMSF() + + + + + +unsigned long MSFtoLBA(char *buffer) { + + unsigned long templsn; + + + + if(buffer == NULL) return(0xFFFFFFFF); + + + + templsn = *(buffer); // Minutes + + templsn *= 60; + + templsn += *(buffer + 1); // Seconds + + templsn *= 75; + + templsn += *(buffer + 2); // Frames + + if(templsn < 150) return(0xFFFFFFFF); + + templsn -= 150; // Offset + + + + return(templsn); + +} // END MSFtoLBA() + diff --git a/plugins/CDVDlinuz/Src/convert.h b/plugins/CDVDlinuz/Src/convert.h index 0806f7bd7f..319a83c47e 100644 --- a/plugins/CDVDlinuz/Src/convert.h +++ b/plugins/CDVDlinuz/Src/convert.h @@ -1,50 +1,100 @@ -/* convert.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef CONVERT_H -#define CONVERT_H - - -#include // off64_t - -#ifdef __linux__ -#include "endian.h" -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define CONVERTLITTLEENDIAN -#endif /* __BYTE_ORDER */ -#endif /* __linux__ */ - -#ifdef __WIN32__ -#define CONVERTLITTLEENDIAN -#endif /* __WIN32__ */ - -#define HEXTOBCD(i) (((i)/10*16) + ((i)%10)) -#define BCDTOHEX(i) (((i)/16*10) + ((i)%16)) - - -extern off64_t ConvertEndianOffset(off64_t number); -extern unsigned int ConvertEndianUInt(unsigned int number); -extern unsigned short ConvertEndianUShort(unsigned short number); - -extern void LBAtoMSF(unsigned long lsn, char *buffer); -extern unsigned long MSFtoLBA(char *buffer); - -#endif /* CONVERT_H */ +/* convert.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef CONVERT_H + +#define CONVERT_H + + + + + +#include // off64_t + + + +#ifdef __linux__ + +#include "endian.h" + +#if __BYTE_ORDER == __LITTLE_ENDIAN + +#define CONVERTLITTLEENDIAN + +#endif /* __BYTE_ORDER */ + +#endif /* __linux__ */ + + + +#ifdef __WIN32__ + +#define CONVERTLITTLEENDIAN + +#endif /* __WIN32__ */ + + + +#define HEXTOBCD(i) (((i)/10*16) + ((i)%10)) + +#define BCDTOHEX(i) (((i)/16*10) + ((i)%16)) + + + + + +extern off64_t ConvertEndianOffset(off64_t number); + +extern unsigned int ConvertEndianUInt(unsigned int number); + +extern unsigned short ConvertEndianUShort(unsigned short number); + + + +extern void LBAtoMSF(unsigned long lsn, char *buffer); + +extern unsigned long MSFtoLBA(char *buffer); + + + +#endif /* CONVERT_H */ + diff --git a/plugins/CDVDlinuz/Src/ini.c b/plugins/CDVDlinuz/Src/ini.c index a00dac8f38..f1bc58746f 100644 --- a/plugins/CDVDlinuz/Src/ini.c +++ b/plugins/CDVDlinuz/Src/ini.c @@ -1,689 +1,1378 @@ -/* ini.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#include // NULL -#include // sprintf() - -#include "logfile.h" -#include "actualfile.h" -#include "ini.h" - - -const char INIext[] = ".ini"; -const char INInewext[] = ".new"; - - -// Returns: position where new extensions should be added. -int INIRemoveExt(char *argname, char *tempname) { - int i; - int j; - int k; - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: RemoveExt(%s)", argname); -#endif /* VERBOSE_FUNCTION_INI */ - - i = 0; - while((i <= INIMAXLEN) && (*(argname + i) != 0)) { - *(tempname + i) = *(argname + i); - i++; - } // ENDWHILE- Copying the argument name into a temporary area; - *(tempname + i) = 0; // And 0-terminate - k = i; - k--; - - j = 0; - while((j <= INIMAXLEN) && (INIext[j] != 0)) j++; - j--; - - while((j >= 0) && (*(tempname + k) == INIext[j])) { - k--; - j--; - } // ENDWHILE- Comparing the ending characters to the INI ext. - if(j < 0) { - k++; - i = k; - *(tempname + i) = 0; // 0-terminate, cutting off ".ini" - } // ENDIF- Do we have a match? Then remove the end chars. - - return(i); -} // END INIRemoveExt() - - -void INIAddInExt(char *tempname, int temppos) { - int i; - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: AddInExt(%s, %i)", tempname, temppos); -#endif /* VERBOSE_FUNCTION_INI */ - - i = 0; - while((i + temppos < INIMAXLEN) && (INIext[i] != 0)) { - *(tempname + temppos + i) = INIext[i]; - i++; - } // ENDWHILE- Attaching extenstion to filename - *(tempname + temppos + i) = 0; // And 0-terminate -} // END INIAddInExt() - - -void INIAddOutExt(char *tempname, int temppos) { - int i; - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: AddOutExt(%s, %i)", tempname, temppos); -#endif /* VERBOSE_FUNCTION_INI */ - - i = 0; - while((i + temppos < INIMAXLEN) && (INInewext[i] != 0)) { - *(tempname + temppos + i) = INInewext[i]; - i++; - } // ENDWHILE- Attaching extenstion to filename - *(tempname + temppos + i) = 0; // And 0-terminate -} // END INIAddInExt() - - -// Returns number of bytes read to get line (0 means end-of-file) -int INIReadLine(ACTUALHANDLE infile, char *buffer) { - int charcount; - int i; - char tempin[2]; - int retflag; - int retval; - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: ReadLine()"); -#endif /* VERBOSE_FUNCTION_INI */ - - charcount = 0; - i = 0; - tempin[1] = 0; - retflag = 0; - - while((i < INIMAXLEN) && (retflag < 2)) { - retval = ActualFileRead(infile, 1, tempin); - charcount++; - if(retval != 1) { - retflag = 2; - charcount--; - - } else if(tempin[0] == '\n') { - retflag = 2; - - } else if(tempin[0] >= ' ') { - *(buffer + i) = tempin[0]; - i++; - } // ENDLONGIF- How do we react to the next character? - } // ENDWHILE- Loading up on characters until an End-of-Line appears - *(buffer + i) = 0; // And 0-terminate - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: Line: %s", buffer); -#endif /* VERBOSE_FUNCTION_INI */ - - return(charcount); -} // END INIReadLine() -// Note: Do we need to back-skip a char if something other \n follows \r? - - -// Returns: number of bytes to get to start of section (or -1) -int INIFindSection(ACTUALHANDLE infile, char *section) { - int charcount; - int i; - int retflag; - int retval; - char scanbuffer[INIMAXLEN+1]; - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: FindSection(%s)", section); -#endif /* VERBOSE_FUNCTION_INI */ - - charcount = 0; - retflag = 0; - - while(retflag == 0) { - retval = INIReadLine(infile, scanbuffer); - if(retval == 0) return(-1); // EOF? Stop here. - - if(scanbuffer[0] == '[') { - i = 0; - while((i < INIMAXLEN) && - (*(section + i) != 0) && - (*(section + i) == scanbuffer[i + 1])) i++; - if((i < INIMAXLEN - 2) && (*(section + i) == 0)) { - if((scanbuffer[i + 1] == ']') && (scanbuffer[i + 2] == 0)) { - retflag = 1; - } // ENDIF- End marks look good? Return successful. - } // ENDIF- Do we have a section match? - } // ENDIF- Does this look like a section header? - - if(retflag == 0) charcount += retval; - } // ENDWHILE- Scanning lines for the correct [Section] header. - - return(charcount); -} // END INIFindSection() - - -// Returns: number of bytes to get to start of keyword (or -1) -int INIFindKeyword(ACTUALHANDLE infile, char *keyword, char *buffer) { - int charcount; - int i; - int j; - int retflag; - int retval; - char scanbuffer[INIMAXLEN+1]; - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: FindKeyword(%s)", keyword); -#endif /* VERBOSE_FUNCTION_INI */ - - charcount = 0; - retflag = 0; - - while(retflag == 0) { - retval = INIReadLine(infile, scanbuffer); - if(retval == 0) return(-1); // EOF? Stop here. - if(scanbuffer[0] == '[') return(-1); // New section? Stop here. - - i = 0; - while((i < INIMAXLEN) && - (*(keyword + i) != 0) && - (*(keyword + i) == scanbuffer[i])) i++; - if((i < INIMAXLEN - 2) && (*(keyword + i) == 0)) { - if(scanbuffer[i] == '=') { - retflag = 1; - if(buffer != NULL) { - i++; - j = 0; - while((i < INIMAXLEN) && (scanbuffer[i] != 0)) { - *(buffer + j) = scanbuffer[i]; - i++; - j++; - } // ENDWHILE- Copying the value out to the outbound buffer. - *(buffer + j) = 0; // And 0-terminate. - } // ENDIF- Return the value as well? - } // ENDIF- End marks look good? Return successful. - } // ENDIF- Do we have a section match? - - if(retflag == 0) charcount += retval; - } // ENDWHILE- Scanning lines for the correct [Section] header. - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: Value: %s", buffer); -#endif /* VERBOSE_FUNCTION_INI */ - - return(charcount); -} // END INIFindKeyWord() - - -// Returns: number of bytes left to write... (from charcount back) -int INICopy(ACTUALHANDLE infile, ACTUALHANDLE outfile, int charcount) { - char buffer[4096]; - int i; - int chunk; - int retval; - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: Copy(%i)", charcount); -#endif /* VERBOSE_FUNCTION_INI */ - - i = charcount; - chunk = 4096; - if(i < chunk) chunk = i; - while(chunk > 0) { - retval = ActualFileRead(infile, chunk, buffer); - if(retval <= 0) return(i); // Trouble? Stop here. - if(retval < chunk) chunk = retval; // Short block? Note it. - - retval = ActualFileWrite(outfile, chunk, buffer); - if(retval <= 0) return(i); // Trouble? Stop here. - i -= retval; - if(retval < chunk) return(i); // Short block written? Stop here. - - chunk = 4096; - if(i < chunk) chunk = i; - } // ENDWHILE- Copying a section of file across, one chunk at a time. - - return(0); -} // END INICopyToPos() - - -int INISaveString(char *file, char *section, char *keyword, char *value) { - char inname[INIMAXLEN+1]; - char outname[INIMAXLEN+1]; - int filepos; - ACTUALHANDLE infile; - ACTUALHANDLE outfile; - int i; - int retval; - char templine[INIMAXLEN+1]; - - if(file == NULL) return(-1); - if(section == NULL) return(-1); - if(keyword == NULL) return(-1); - if(value == NULL) return(-1); - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: SaveString(%s, %s, %s, %s)", - file, section, keyword, value); -#endif /* VERBOSE_FUNCTION_INI */ - - filepos = INIRemoveExt(file, inname); - for(i = 0; i <= filepos; i++) outname[i] = inname[i]; - INIAddInExt(inname, filepos); - INIAddOutExt(outname, filepos); - - filepos = 0; - infile = ActualFileOpenForRead(inname); - if(infile == ACTUALHANDLENULL) { -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: creating new file"); -#endif /* VERBOSE_FUNCTION_INI */ - outfile = ActualFileOpenForWrite(inname); - if(outfile == ACTUALHANDLENULL) return(-1); // Just a bad name? Abort. - - sprintf(templine, "[%s]\r\n", section); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - if(retval < i) { - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(inname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - - sprintf(templine, "%s=%s\r\n", keyword, value); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - if(retval < i) { - ActualFileDelete(inname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - return(0); - } // ENDIF- No input file? Create a brand new .ini file then. - - retval = INIFindSection(infile, section); - if(retval < 0) { -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: creating new section"); -#endif /* VERBOSE_FUNCTION_INI */ - outfile = ActualFileOpenForWrite(outname); - if(outfile == ACTUALHANDLENULL) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't open a temp file? Abort - - ActualFileSeek(infile, 0); // Move ini to beginning of file... - INICopy(infile, outfile, 0x0FFFFFFF); // Copy the whole file out... - - sprintf(templine, "\r\n[%s]\r\n", section); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - if(retval < i) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - - sprintf(templine, "%s=%s\r\n", keyword, value); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - if(retval < i) { - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - - ActualFileDelete(inname); - ActualFileRename(outname, inname); - return(0); - } // ENDIF- Couldn't find the section? Make a new one! - - filepos = retval; - ActualFileSeek(infile, filepos); - filepos += INIReadLine(infile, templine); // Get section line's byte count - - retval = INIFindKeyword(infile, keyword, NULL); - if(retval < 0) { -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: creating new keyword"); -#endif /* VERBOSE_FUNCTION_INI */ - ActualFileSeek(infile, filepos); - retval = INIReadLine(infile, templine); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0) && (templine[i] != '=')) i++; - while((retval > 0) && (templine[i] == '=')) { - filepos += retval; - retval = INIReadLine(infile, templine); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0) && (templine[i] != '=')) i++; - } // ENDWHILE- skimming to the bottom of the section - - outfile = ActualFileOpenForWrite(outname); - if(outfile == ACTUALHANDLENULL) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't open a temp file? Abort - - ActualFileSeek(infile, 0); - retval = INICopy(infile, outfile, filepos); - if(retval > 0) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing everything up to keyword? Abort. - - sprintf(templine, "%s=%s\r\n", keyword, value); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - if(retval < i) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - - } else { -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: replacing keyword"); -#endif /* VERBOSE_FUNCTION_INI */ - filepos += retval; // Position just before old version of keyword - - outfile = ActualFileOpenForWrite(outname); - if(outfile == ACTUALHANDLENULL) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't open a temp file? Abort - - ActualFileSeek(infile, 0); - retval = INICopy(infile, outfile, filepos); - if(retval > 0) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing everything up to keyword? Abort. - - INIReadLine(infile, templine); // Read past old keyword/value... - - // Replace with new value - sprintf(templine, "%s=%s\r\n", keyword, value); - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - if(retval < i) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - } // ENDIF- Need to add a new keyword? - - INICopy(infile, outfile, 0xFFFFFFF); // Write out rest of file - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(inname); - ActualFileRename(outname, inname); - return(0); -} // END INISaveString() - - -int INILoadString(char *file, char *section, char *keyword, char *buffer) { - char inname[INIMAXLEN+1]; - int filepos; - ACTUALHANDLE infile; - int retval; - - if(file == NULL) return(-1); - if(section == NULL) return(-1); - if(keyword == NULL) return(-1); - if(buffer == NULL) return(-1); - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: LoadString(%s, %s, %s)", - file, section, keyword); -#endif /* VERBOSE_FUNCTION_INI */ - - filepos = INIRemoveExt(file, inname); - INIAddInExt(inname, filepos); - - filepos = 0; - infile = ActualFileOpenForRead(inname); - if(infile == ACTUALHANDLENULL) return(-1); - - retval = INIFindSection(infile, section); - if(retval < 0) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Didn't find it? Abort. - - retval = INIFindKeyword(infile, keyword, buffer); - if(retval < 0) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Didn't find it? Abort. - - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(0); -} // END INILoadString() - - -int INIRemove(char *file, char *section, char *keyword) { - char inname[INIMAXLEN+1]; - char outname[INIMAXLEN+1]; - int filepos; - ACTUALHANDLE infile; - ACTUALHANDLE outfile; - char templine[INIMAXLEN+1]; - int i; - int retval; - - if(file == NULL) return(-1); - if(section == NULL) return(-1); - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: Remove(%s, %s, %s)", - file, section, keyword); -#endif /* VERBOSE_FUNCTION_INI */ - - filepos = INIRemoveExt(file, inname); - for(i = 0; i <= filepos; i++) outname[i] = inname[i]; - INIAddInExt(inname, filepos); - INIAddOutExt(outname, filepos); - - infile = ActualFileOpenForRead(inname); - if(infile == ACTUALHANDLENULL) return(-1); - - retval = INIFindSection(infile, section); - if(retval == -1) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't even find the section? Abort - - filepos = retval; - if(keyword == NULL) { -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: removing section"); -#endif /* VERBOSE_FUNCTION_INI */ - outfile = ActualFileOpenForWrite(outname); - if(outfile == ACTUALHANDLENULL) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't open a temp file? Abort - - ActualFileSeek(infile, 0); - retval = INICopy(infile, outfile, filepos); - if(retval > 0) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing everything up to the section? Abort. - - templine[0] = 0; - retval = 1; - while((retval > 0) && (templine[0] != '[')) { - retval = INIReadLine(infile, templine); - } // ENDWHILE- Read to the start of the next section... or EOF. - - if(templine[0] == '[') { - i = 0; - while((i < INIMAXLEN) && (templine[i] != 0)) i++; - retval = ActualFileWrite(outfile, i, templine); - if(retval < i) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing it out? Abort. - } // ENDIF- Are there other sections after this one? Save them then. - - } else { - filepos = retval; - ActualFileSeek(infile, filepos); - filepos += INIReadLine(infile, templine); // Get section line's byte count - - retval = INIFindKeyword(infile, keyword, NULL); - if(retval == -1) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't find the keyword? Abort - filepos += retval; - -#ifdef VERBOSE_FUNCTION_INI - PrintLog("CDVDiso ini: removing keyword"); -#endif /* VERBOSE_FUNCTION_INI */ - outfile = ActualFileOpenForWrite(outname); - if(outfile == ACTUALHANDLENULL) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - return(-1); - } // ENDIF- Couldn't open a temp file? Abort - - ActualFileSeek(infile, 0); - retval = INICopy(infile, outfile, filepos); - if(retval > 0) { - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(outname); - return(-1); - } // ENDIF- Trouble writing everything up to keyword? Abort. - - INIReadLine(infile, templine); // Read (and discard) the keyword line - } // ENDIF- Wipe out the whole section? Or just a keyword? - - INICopy(infile, outfile, 0xFFFFFFF); // Write out rest of file - ActualFileClose(infile); - infile = ACTUALHANDLENULL; - ActualFileClose(outfile); - outfile = ACTUALHANDLENULL; - ActualFileDelete(inname); - ActualFileRename(outname, inname); - return(0); -} // END INIRemove() - - -int INISaveUInt(char *file, char *section, char *keyword, unsigned int value) { - char numvalue[INIMAXLEN+1]; - - sprintf(numvalue, "%u", value); - return(INISaveString(file, section, keyword, numvalue)); -} // END INISaveUInt() - - -int INILoadUInt(char *file, char *section, char *keyword, unsigned int *buffer) { - char numvalue[INIMAXLEN+1]; - int retval; - unsigned int value; - // unsigned int sign; // Not needed in unsigned numbers - int pos; - - if(buffer == NULL) return(-1); - *(buffer) = 0; - - retval = INILoadString(file, section, keyword, numvalue); - if(retval < 0) return(retval); - - value = 0; - // sign = 1; // Start positive - pos = 0; - - // Note: skip leading spaces? (Shouldn't have to, I hope) - - // if(numvalue[pos] == '-') { - // pos++; - // sign = -1; - // } // ENDIF- Negative sign check - - while((pos < INIMAXLEN) && (numvalue[pos] != 0)) { - if(value > (0xFFFFFFFF / 10)) return(-1); // Overflow? - - if((numvalue[pos] >= '0') && (numvalue[pos] <= '9')) { - value *= 10; - value += numvalue[pos] - '0'; - pos++; - } else { - numvalue[pos] = 0; - } // ENDIF- Add a digit in? Or stop searching for digits? - } // ENDWHILE- Adding digits of info to our ever-increasing value - - // value *= sign - *(buffer) = value; - return(0); -} // END INILoadUInt() +/* ini.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#include // NULL + +#include // sprintf() + + + +#include "logfile.h" + +#include "actualfile.h" + +#include "ini.h" + + + + + +const char INIext[] = ".ini"; + +const char INInewext[] = ".new"; + + + + + +// Returns: position where new extensions should be added. + +int INIRemoveExt(char *argname, char *tempname) { + + int i; + + int j; + + int k; + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: RemoveExt(%s)", argname); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + i = 0; + + while((i <= INIMAXLEN) && (*(argname + i) != 0)) { + + *(tempname + i) = *(argname + i); + + i++; + + } // ENDWHILE- Copying the argument name into a temporary area; + + *(tempname + i) = 0; // And 0-terminate + + k = i; + + k--; + + + + j = 0; + + while((j <= INIMAXLEN) && (INIext[j] != 0)) j++; + + j--; + + + + while((j >= 0) && (*(tempname + k) == INIext[j])) { + + k--; + + j--; + + } // ENDWHILE- Comparing the ending characters to the INI ext. + + if(j < 0) { + + k++; + + i = k; + + *(tempname + i) = 0; // 0-terminate, cutting off ".ini" + + } // ENDIF- Do we have a match? Then remove the end chars. + + + + return(i); + +} // END INIRemoveExt() + + + + + +void INIAddInExt(char *tempname, int temppos) { + + int i; + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: AddInExt(%s, %i)", tempname, temppos); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + i = 0; + + while((i + temppos < INIMAXLEN) && (INIext[i] != 0)) { + + *(tempname + temppos + i) = INIext[i]; + + i++; + + } // ENDWHILE- Attaching extenstion to filename + + *(tempname + temppos + i) = 0; // And 0-terminate + +} // END INIAddInExt() + + + + + +void INIAddOutExt(char *tempname, int temppos) { + + int i; + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: AddOutExt(%s, %i)", tempname, temppos); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + i = 0; + + while((i + temppos < INIMAXLEN) && (INInewext[i] != 0)) { + + *(tempname + temppos + i) = INInewext[i]; + + i++; + + } // ENDWHILE- Attaching extenstion to filename + + *(tempname + temppos + i) = 0; // And 0-terminate + +} // END INIAddInExt() + + + + + +// Returns number of bytes read to get line (0 means end-of-file) + +int INIReadLine(ACTUALHANDLE infile, char *buffer) { + + int charcount; + + int i; + + char tempin[2]; + + int retflag; + + int retval; + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: ReadLine()"); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + charcount = 0; + + i = 0; + + tempin[1] = 0; + + retflag = 0; + + + + while((i < INIMAXLEN) && (retflag < 2)) { + + retval = ActualFileRead(infile, 1, tempin); + + charcount++; + + if(retval != 1) { + + retflag = 2; + + charcount--; + + + + } else if(tempin[0] == '\n') { + + retflag = 2; + + + + } else if(tempin[0] >= ' ') { + + *(buffer + i) = tempin[0]; + + i++; + + } // ENDLONGIF- How do we react to the next character? + + } // ENDWHILE- Loading up on characters until an End-of-Line appears + + *(buffer + i) = 0; // And 0-terminate + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: Line: %s", buffer); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + return(charcount); + +} // END INIReadLine() + +// Note: Do we need to back-skip a char if something other \n follows \r? + + + + + +// Returns: number of bytes to get to start of section (or -1) + +int INIFindSection(ACTUALHANDLE infile, char *section) { + + int charcount; + + int i; + + int retflag; + + int retval; + + char scanbuffer[INIMAXLEN+1]; + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: FindSection(%s)", section); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + charcount = 0; + + retflag = 0; + + + + while(retflag == 0) { + + retval = INIReadLine(infile, scanbuffer); + + if(retval == 0) return(-1); // EOF? Stop here. + + + + if(scanbuffer[0] == '[') { + + i = 0; + + while((i < INIMAXLEN) && + + (*(section + i) != 0) && + + (*(section + i) == scanbuffer[i + 1])) i++; + + if((i < INIMAXLEN - 2) && (*(section + i) == 0)) { + + if((scanbuffer[i + 1] == ']') && (scanbuffer[i + 2] == 0)) { + + retflag = 1; + + } // ENDIF- End marks look good? Return successful. + + } // ENDIF- Do we have a section match? + + } // ENDIF- Does this look like a section header? + + + + if(retflag == 0) charcount += retval; + + } // ENDWHILE- Scanning lines for the correct [Section] header. + + + + return(charcount); + +} // END INIFindSection() + + + + + +// Returns: number of bytes to get to start of keyword (or -1) + +int INIFindKeyword(ACTUALHANDLE infile, char *keyword, char *buffer) { + + int charcount; + + int i; + + int j; + + int retflag; + + int retval; + + char scanbuffer[INIMAXLEN+1]; + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: FindKeyword(%s)", keyword); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + charcount = 0; + + retflag = 0; + + + + while(retflag == 0) { + + retval = INIReadLine(infile, scanbuffer); + + if(retval == 0) return(-1); // EOF? Stop here. + + if(scanbuffer[0] == '[') return(-1); // New section? Stop here. + + + + i = 0; + + while((i < INIMAXLEN) && + + (*(keyword + i) != 0) && + + (*(keyword + i) == scanbuffer[i])) i++; + + if((i < INIMAXLEN - 2) && (*(keyword + i) == 0)) { + + if(scanbuffer[i] == '=') { + + retflag = 1; + + if(buffer != NULL) { + + i++; + + j = 0; + + while((i < INIMAXLEN) && (scanbuffer[i] != 0)) { + + *(buffer + j) = scanbuffer[i]; + + i++; + + j++; + + } // ENDWHILE- Copying the value out to the outbound buffer. + + *(buffer + j) = 0; // And 0-terminate. + + } // ENDIF- Return the value as well? + + } // ENDIF- End marks look good? Return successful. + + } // ENDIF- Do we have a section match? + + + + if(retflag == 0) charcount += retval; + + } // ENDWHILE- Scanning lines for the correct [Section] header. + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: Value: %s", buffer); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + return(charcount); + +} // END INIFindKeyWord() + + + + + +// Returns: number of bytes left to write... (from charcount back) + +int INICopy(ACTUALHANDLE infile, ACTUALHANDLE outfile, int charcount) { + + char buffer[4096]; + + int i; + + int chunk; + + int retval; + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: Copy(%i)", charcount); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + i = charcount; + + chunk = 4096; + + if(i < chunk) chunk = i; + + while(chunk > 0) { + + retval = ActualFileRead(infile, chunk, buffer); + + if(retval <= 0) return(i); // Trouble? Stop here. + + if(retval < chunk) chunk = retval; // Short block? Note it. + + + + retval = ActualFileWrite(outfile, chunk, buffer); + + if(retval <= 0) return(i); // Trouble? Stop here. + + i -= retval; + + if(retval < chunk) return(i); // Short block written? Stop here. + + + + chunk = 4096; + + if(i < chunk) chunk = i; + + } // ENDWHILE- Copying a section of file across, one chunk at a time. + + + + return(0); + +} // END INICopyToPos() + + + + + +int INISaveString(char *file, char *section, char *keyword, char *value) { + + char inname[INIMAXLEN+1]; + + char outname[INIMAXLEN+1]; + + int filepos; + + ACTUALHANDLE infile; + + ACTUALHANDLE outfile; + + int i; + + int retval; + + char templine[INIMAXLEN+1]; + + + + if(file == NULL) return(-1); + + if(section == NULL) return(-1); + + if(keyword == NULL) return(-1); + + if(value == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: SaveString(%s, %s, %s, %s)", + + file, section, keyword, value); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + filepos = INIRemoveExt(file, inname); + + for(i = 0; i <= filepos; i++) outname[i] = inname[i]; + + INIAddInExt(inname, filepos); + + INIAddOutExt(outname, filepos); + + + + filepos = 0; + + infile = ActualFileOpenForRead(inname); + + if(infile == ACTUALHANDLENULL) { + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: creating new file"); + +#endif /* VERBOSE_FUNCTION_INI */ + + outfile = ActualFileOpenForWrite(inname); + + if(outfile == ACTUALHANDLENULL) return(-1); // Just a bad name? Abort. + + + + sprintf(templine, "[%s]\r\n", section); + + i = 0; + + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + + retval = ActualFileWrite(outfile, i, templine); + + if(retval < i) { + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(inname); + + return(-1); + + } // ENDIF- Trouble writing it out? Abort. + + + + sprintf(templine, "%s=%s\r\n", keyword, value); + + i = 0; + + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + + retval = ActualFileWrite(outfile, i, templine); + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + if(retval < i) { + + ActualFileDelete(inname); + + return(-1); + + } // ENDIF- Trouble writing it out? Abort. + + return(0); + + } // ENDIF- No input file? Create a brand new .ini file then. + + + + retval = INIFindSection(infile, section); + + if(retval < 0) { + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: creating new section"); + +#endif /* VERBOSE_FUNCTION_INI */ + + outfile = ActualFileOpenForWrite(outname); + + if(outfile == ACTUALHANDLENULL) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- Couldn't open a temp file? Abort + + + + ActualFileSeek(infile, 0); // Move ini to beginning of file... + + INICopy(infile, outfile, 0x0FFFFFFF); // Copy the whole file out... + + + + sprintf(templine, "\r\n[%s]\r\n", section); + + i = 0; + + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + + retval = ActualFileWrite(outfile, i, templine); + + if(retval < i) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(outname); + + return(-1); + + } // ENDIF- Trouble writing it out? Abort. + + + + sprintf(templine, "%s=%s\r\n", keyword, value); + + i = 0; + + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + + retval = ActualFileWrite(outfile, i, templine); + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + if(retval < i) { + + ActualFileDelete(outname); + + return(-1); + + } // ENDIF- Trouble writing it out? Abort. + + + + ActualFileDelete(inname); + + ActualFileRename(outname, inname); + + return(0); + + } // ENDIF- Couldn't find the section? Make a new one! + + + + filepos = retval; + + ActualFileSeek(infile, filepos); + + filepos += INIReadLine(infile, templine); // Get section line's byte count + + + + retval = INIFindKeyword(infile, keyword, NULL); + + if(retval < 0) { + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: creating new keyword"); + +#endif /* VERBOSE_FUNCTION_INI */ + + ActualFileSeek(infile, filepos); + + retval = INIReadLine(infile, templine); + + i = 0; + + while((i < INIMAXLEN) && (templine[i] != 0) && (templine[i] != '=')) i++; + + while((retval > 0) && (templine[i] == '=')) { + + filepos += retval; + + retval = INIReadLine(infile, templine); + + i = 0; + + while((i < INIMAXLEN) && (templine[i] != 0) && (templine[i] != '=')) i++; + + } // ENDWHILE- skimming to the bottom of the section + + + + outfile = ActualFileOpenForWrite(outname); + + if(outfile == ACTUALHANDLENULL) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- Couldn't open a temp file? Abort + + + + ActualFileSeek(infile, 0); + + retval = INICopy(infile, outfile, filepos); + + if(retval > 0) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(outname); + + return(-1); + + } // ENDIF- Trouble writing everything up to keyword? Abort. + + + + sprintf(templine, "%s=%s\r\n", keyword, value); + + i = 0; + + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + + retval = ActualFileWrite(outfile, i, templine); + + if(retval < i) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(outname); + + return(-1); + + } // ENDIF- Trouble writing it out? Abort. + + + + } else { + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: replacing keyword"); + +#endif /* VERBOSE_FUNCTION_INI */ + + filepos += retval; // Position just before old version of keyword + + + + outfile = ActualFileOpenForWrite(outname); + + if(outfile == ACTUALHANDLENULL) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- Couldn't open a temp file? Abort + + + + ActualFileSeek(infile, 0); + + retval = INICopy(infile, outfile, filepos); + + if(retval > 0) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(outname); + + return(-1); + + } // ENDIF- Trouble writing everything up to keyword? Abort. + + + + INIReadLine(infile, templine); // Read past old keyword/value... + + + + // Replace with new value + + sprintf(templine, "%s=%s\r\n", keyword, value); + + i = 0; + + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + + retval = ActualFileWrite(outfile, i, templine); + + if(retval < i) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(outname); + + return(-1); + + } // ENDIF- Trouble writing it out? Abort. + + } // ENDIF- Need to add a new keyword? + + + + INICopy(infile, outfile, 0xFFFFFFF); // Write out rest of file + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(inname); + + ActualFileRename(outname, inname); + + return(0); + +} // END INISaveString() + + + + + +int INILoadString(char *file, char *section, char *keyword, char *buffer) { + + char inname[INIMAXLEN+1]; + + int filepos; + + ACTUALHANDLE infile; + + int retval; + + + + if(file == NULL) return(-1); + + if(section == NULL) return(-1); + + if(keyword == NULL) return(-1); + + if(buffer == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: LoadString(%s, %s, %s)", + + file, section, keyword); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + filepos = INIRemoveExt(file, inname); + + INIAddInExt(inname, filepos); + + + + filepos = 0; + + infile = ActualFileOpenForRead(inname); + + if(infile == ACTUALHANDLENULL) return(-1); + + + + retval = INIFindSection(infile, section); + + if(retval < 0) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- Didn't find it? Abort. + + + + retval = INIFindKeyword(infile, keyword, buffer); + + if(retval < 0) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- Didn't find it? Abort. + + + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(0); + +} // END INILoadString() + + + + + +int INIRemove(char *file, char *section, char *keyword) { + + char inname[INIMAXLEN+1]; + + char outname[INIMAXLEN+1]; + + int filepos; + + ACTUALHANDLE infile; + + ACTUALHANDLE outfile; + + char templine[INIMAXLEN+1]; + + int i; + + int retval; + + + + if(file == NULL) return(-1); + + if(section == NULL) return(-1); + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: Remove(%s, %s, %s)", + + file, section, keyword); + +#endif /* VERBOSE_FUNCTION_INI */ + + + + filepos = INIRemoveExt(file, inname); + + for(i = 0; i <= filepos; i++) outname[i] = inname[i]; + + INIAddInExt(inname, filepos); + + INIAddOutExt(outname, filepos); + + + + infile = ActualFileOpenForRead(inname); + + if(infile == ACTUALHANDLENULL) return(-1); + + + + retval = INIFindSection(infile, section); + + if(retval == -1) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- Couldn't even find the section? Abort + + + + filepos = retval; + + if(keyword == NULL) { + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: removing section"); + +#endif /* VERBOSE_FUNCTION_INI */ + + outfile = ActualFileOpenForWrite(outname); + + if(outfile == ACTUALHANDLENULL) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- Couldn't open a temp file? Abort + + + + ActualFileSeek(infile, 0); + + retval = INICopy(infile, outfile, filepos); + + if(retval > 0) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(outname); + + return(-1); + + } // ENDIF- Trouble writing everything up to the section? Abort. + + + + templine[0] = 0; + + retval = 1; + + while((retval > 0) && (templine[0] != '[')) { + + retval = INIReadLine(infile, templine); + + } // ENDWHILE- Read to the start of the next section... or EOF. + + + + if(templine[0] == '[') { + + i = 0; + + while((i < INIMAXLEN) && (templine[i] != 0)) i++; + + retval = ActualFileWrite(outfile, i, templine); + + if(retval < i) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(outname); + + return(-1); + + } // ENDIF- Trouble writing it out? Abort. + + } // ENDIF- Are there other sections after this one? Save them then. + + + + } else { + + filepos = retval; + + ActualFileSeek(infile, filepos); + + filepos += INIReadLine(infile, templine); // Get section line's byte count + + + + retval = INIFindKeyword(infile, keyword, NULL); + + if(retval == -1) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- Couldn't find the keyword? Abort + + filepos += retval; + + + +#ifdef VERBOSE_FUNCTION_INI + + PrintLog("CDVDiso ini: removing keyword"); + +#endif /* VERBOSE_FUNCTION_INI */ + + outfile = ActualFileOpenForWrite(outname); + + if(outfile == ACTUALHANDLENULL) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + return(-1); + + } // ENDIF- Couldn't open a temp file? Abort + + + + ActualFileSeek(infile, 0); + + retval = INICopy(infile, outfile, filepos); + + if(retval > 0) { + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(outname); + + return(-1); + + } // ENDIF- Trouble writing everything up to keyword? Abort. + + + + INIReadLine(infile, templine); // Read (and discard) the keyword line + + } // ENDIF- Wipe out the whole section? Or just a keyword? + + + + INICopy(infile, outfile, 0xFFFFFFF); // Write out rest of file + + ActualFileClose(infile); + + infile = ACTUALHANDLENULL; + + ActualFileClose(outfile); + + outfile = ACTUALHANDLENULL; + + ActualFileDelete(inname); + + ActualFileRename(outname, inname); + + return(0); + +} // END INIRemove() + + + + + +int INISaveUInt(char *file, char *section, char *keyword, unsigned int value) { + + char numvalue[INIMAXLEN+1]; + + + + sprintf(numvalue, "%u", value); + + return(INISaveString(file, section, keyword, numvalue)); + +} // END INISaveUInt() + + + + + +int INILoadUInt(char *file, char *section, char *keyword, unsigned int *buffer) { + + char numvalue[INIMAXLEN+1]; + + int retval; + + unsigned int value; + + // unsigned int sign; // Not needed in unsigned numbers + + int pos; + + + + if(buffer == NULL) return(-1); + + *(buffer) = 0; + + + + retval = INILoadString(file, section, keyword, numvalue); + + if(retval < 0) return(retval); + + + + value = 0; + + // sign = 1; // Start positive + + pos = 0; + + + + // Note: skip leading spaces? (Shouldn't have to, I hope) + + + + // if(numvalue[pos] == '-') { + + // pos++; + + // sign = -1; + + // } // ENDIF- Negative sign check + + + + while((pos < INIMAXLEN) && (numvalue[pos] != 0)) { + + if(value > (0xFFFFFFFF / 10)) return(-1); // Overflow? + + + + if((numvalue[pos] >= '0') && (numvalue[pos] <= '9')) { + + value *= 10; + + value += numvalue[pos] - '0'; + + pos++; + + } else { + + numvalue[pos] = 0; + + } // ENDIF- Add a digit in? Or stop searching for digits? + + } // ENDWHILE- Adding digits of info to our ever-increasing value + + + + // value *= sign + + *(buffer) = value; + + return(0); + +} // END INILoadUInt() + diff --git a/plugins/CDVDlinuz/Src/ini.h b/plugins/CDVDlinuz/Src/ini.h index fbd2349cf5..1bda0552df 100644 --- a/plugins/CDVDlinuz/Src/ini.h +++ b/plugins/CDVDlinuz/Src/ini.h @@ -1,64 +1,128 @@ -/* ini.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef INI_H -#define INI_H - - -// #ifndef __LINUX__ -// #ifdef __linux__ -// #define __LINUX__ -// #endif /* __linux__ */ -// #endif /* No __LINUX__ */ - -// #define CDVDdefs -// #include "PS2Edefs.h" - - -// File format: -// [section] -// keyword=value - -// file - Name of the INI file -// section - Section within the file -// keyword - Identifier for a value -// value - value to store with a keyword in a section in the file -// buffer - place to retrieve the value of a keyword - -// return values: 0 = success, -1 = failure - - -// #define VERBOSE_FUNCTION_INI - -#define INIMAXLEN 255 - - -extern int INISaveString(char *file, char *section, char *keyword, char *value); -extern int INILoadString(char *file, char *section, char *keyword, char *buffer); - -extern int INISaveUInt(char *file, char *section, char *keyword, unsigned int value); -extern int INILoadUInt(char *file, char *section, char *keyword, unsigned int *buffer); - -// NULL in the keyword below removes the whole section. -extern int INIRemove(char *file, char *section, char *keyword); - - -#endif /* INI_H */ +/* ini.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef INI_H + +#define INI_H + + + + + +// #ifndef __LINUX__ + +// #ifdef __linux__ + +// #define __LINUX__ + +// #endif /* __linux__ */ + +// #endif /* No __LINUX__ */ + + + +// #define CDVDdefs + +// #include "PS2Edefs.h" + + + + + +// File format: + +// [section] + +// keyword=value + + + +// file - Name of the INI file + +// section - Section within the file + +// keyword - Identifier for a value + +// value - value to store with a keyword in a section in the file + +// buffer - place to retrieve the value of a keyword + + + +// return values: 0 = success, -1 = failure + + + + + +// #define VERBOSE_FUNCTION_INI + + + +#define INIMAXLEN 255 + + + + + +extern int INISaveString(char *file, char *section, char *keyword, char *value); + +extern int INILoadString(char *file, char *section, char *keyword, char *buffer); + + + +extern int INISaveUInt(char *file, char *section, char *keyword, unsigned int value); + +extern int INILoadUInt(char *file, char *section, char *keyword, unsigned int *buffer); + + + +// NULL in the keyword below removes the whole section. + +extern int INIRemove(char *file, char *section, char *keyword); + + + + + +#endif /* INI_H */ + diff --git a/plugins/CDVDlinuz/Src/version.c b/plugins/CDVDlinuz/Src/version.c index c2b9b2dc87..f765058b8b 100644 --- a/plugins/CDVDlinuz/Src/version.c +++ b/plugins/CDVDlinuz/Src/version.c @@ -1,36 +1,72 @@ -/* version.c - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef __LINUX__ -#ifdef __linux__ -#define __LINUX__ -#endif /* __linux__ */ -#endif /* No __LINUX__ */ - -#define CDVDdefs -#include "PS2Edefs.h" - - -char *libname = "EFP polling CDVD Driver"; - -const unsigned char version = PS2E_CDVD_VERSION; -const unsigned char revision = 0; -const unsigned char build = 4; +/* version.c + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef __LINUX__ + +#ifdef __linux__ + +#define __LINUX__ + +#endif /* __linux__ */ + +#endif /* No __LINUX__ */ + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + + + +char *libname = "EFP polling CDVD Driver"; + + + +const unsigned char version = PS2E_CDVD_VERSION; + +const unsigned char revision = 0; + +const unsigned char build = 4; + diff --git a/plugins/CDVDlinuz/Src/version.h b/plugins/CDVDlinuz/Src/version.h index 774ce3b29a..2fb4b2751c 100644 --- a/plugins/CDVDlinuz/Src/version.h +++ b/plugins/CDVDlinuz/Src/version.h @@ -1,43 +1,86 @@ -/* version.h - * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * PCSX2 members can be contacted through their website at www.pcsx2.net. - */ - - -#ifndef VERSION_H -#define VERSION_H - - -#ifndef __LINUX__ -#ifdef __linux__ -#define __LINUX__ -#endif /* __linux__ */ -#endif /* No __LINUX__ */ - -#define CDVDdefs -#include "PS2Edefs.h" - - -extern char *libname; - -extern const unsigned char version; -extern const unsigned char revision; -extern const unsigned char build; - - -#endif /* VERSION_H */ +/* version.h + + * Copyright (C) 2002-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + * + + * PCSX2 members can be contacted through their website at www.pcsx2.net. + + */ + + + + + +#ifndef VERSION_H + +#define VERSION_H + + + + + +#ifndef __LINUX__ + +#ifdef __linux__ + +#define __LINUX__ + +#endif /* __linux__ */ + +#endif /* No __LINUX__ */ + + + +#define CDVDdefs + +#include "PS2Edefs.h" + + + + + +extern char *libname; + + + +extern const unsigned char version; + +extern const unsigned char revision; + +extern const unsigned char build; + + + + + +#endif /* VERSION_H */ + diff --git a/plugins/CDVDnull/Src/CDVD.c b/plugins/CDVDnull/Src/CDVD.c index 5f338b6983..b5fcc2166f 100644 --- a/plugins/CDVDnull/Src/CDVD.c +++ b/plugins/CDVDnull/Src/CDVD.c @@ -1,146 +1,146 @@ -#include - -#include "CDVD.h" - - -char *LibName = "CDVDnull Driver"; - -const unsigned char version = PS2E_CDVD_VERSION; -const unsigned char revision = 0; -const unsigned char build = 6; - - -char* CALLBACK PS2EgetLibName() { - return LibName; -} - -u32 CALLBACK PS2EgetLibType() { - return PS2E_LT_CDVD; -} - -u32 CALLBACK PS2EgetLibVersion2(u32 type) { - return (version << 16) | (revision << 8) | build; -} - -#ifdef _WIN32 -void SysMessage(char *fmt, ...) { - va_list list; - char tmp[512]; - - va_start(list,fmt); - vsprintf(tmp,fmt,list); - va_end(list); - - MessageBox(0, tmp, "CDVDnull Msg", 0); -} -#else - -void SysMessage(char *fmt, ...) { - /*GtkWidget *Ok,*Txt; - GtkWidget *Box,*Box1; - va_list list; - char msg[512]; - - va_start(list, fmt); - vsprintf(msg, fmt, list); - va_end(list); - - if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; - - MsgDlg = gtk_window_new (GTK_WINDOW_POPUP); - gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); - gtk_window_set_title(GTK_WINDOW(MsgDlg), "GSsoft Msg"); - gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); - - Box = gtk_vbox_new(5, 0); - gtk_container_add(GTK_CONTAINER(MsgDlg), Box); - gtk_widget_show(Box); - - Txt = gtk_label_new(msg); - - gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); - gtk_widget_show(Txt); - - Box1 = gtk_hbutton_box_new(); - gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); - gtk_widget_show(Box1); - - Ok = gtk_button_new_with_label("Ok"); - gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); - gtk_container_add(GTK_CONTAINER(Box1), Ok); - GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); - gtk_widget_show(Ok); - - gtk_widget_show(MsgDlg); - - gtk_main();*/ -} - -#endif - -s32 CALLBACK CDVDinit() { - return 0; -} - -s32 CALLBACK CDVDopen(const char* pTitle) { - return 0; -} - -void CALLBACK CDVDclose() { -} - -void CALLBACK CDVDshutdown() { -} - -s32 CALLBACK CDVDreadTrack(u32 lsn, int mode) { - return -1; -} - -// return can be NULL (for async modes) -u8* CALLBACK CDVDgetBuffer() { - return NULL; -} - -s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq) { - return -1; -} - -s32 CALLBACK CDVDgetTN(cdvdTN *Buffer) { - return -1; -} - -s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer) { - return -1; -} - -s32 CALLBACK CDVDgetTOC(void* toc) { - return -1; -} - -s32 CALLBACK CDVDgetDiskType() { - return CDVD_TYPE_NODISC; -} - -s32 CALLBACK CDVDgetTrayStatus() { - return CDVD_TRAY_CLOSE; -} - -s32 CALLBACK CDVDctrlTrayOpen() { - return 0; -} - -s32 CALLBACK CDVDctrlTrayClose() { - return 0; -} - -void CALLBACK CDVDconfigure() { - SysMessage("Nothing to Configure"); -} - -void CALLBACK CDVDabout() { - SysMessage("%s %d.%d", LibName, revision, build); -} - -s32 CALLBACK CDVDtest() { - return 0; -} +#include + +#include "CDVD.h" + + +char *LibName = "CDVDnull Driver"; + +const unsigned char version = PS2E_CDVD_VERSION; +const unsigned char revision = 0; +const unsigned char build = 6; + + +char* CALLBACK PS2EgetLibName() { + return LibName; +} + +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_CDVD; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (version << 16) | (revision << 8) | build; +} + +#ifdef _WIN32 +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + + MessageBox(0, tmp, "CDVDnull Msg", 0); +} +#else + +void SysMessage(char *fmt, ...) { + /*GtkWidget *Ok,*Txt; + GtkWidget *Box,*Box1; + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + MsgDlg = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "GSsoft Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); + + Box = gtk_vbox_new(5, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main();*/ +} + +#endif + +s32 CALLBACK CDVDinit() { + return 0; +} + +s32 CALLBACK CDVDopen(const char* pTitle) { + return 0; +} + +void CALLBACK CDVDclose() { +} + +void CALLBACK CDVDshutdown() { +} + +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode) { + return -1; +} + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer() { + return NULL; +} + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq) { + return -1; +} + +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer) { + return -1; +} + +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer) { + return -1; +} + +s32 CALLBACK CDVDgetTOC(void* toc) { + return -1; +} + +s32 CALLBACK CDVDgetDiskType() { + return CDVD_TYPE_NODISC; +} + +s32 CALLBACK CDVDgetTrayStatus() { + return CDVD_TRAY_CLOSE; +} + +s32 CALLBACK CDVDctrlTrayOpen() { + return 0; +} + +s32 CALLBACK CDVDctrlTrayClose() { + return 0; +} + +void CALLBACK CDVDconfigure() { + SysMessage("Nothing to Configure"); +} + +void CALLBACK CDVDabout() { + SysMessage("%s %d.%d", LibName, revision, build); +} + +s32 CALLBACK CDVDtest() { + return 0; +} diff --git a/plugins/CDVDnull/Src/CDVD.h b/plugins/CDVDnull/Src/CDVD.h index 942449130e..e8c983e700 100644 --- a/plugins/CDVDnull/Src/CDVD.h +++ b/plugins/CDVDnull/Src/CDVD.h @@ -1,11 +1,11 @@ -#ifndef __CDVD_H__ -#define __CDVD_H__ - -#ifdef _WIN32 -#include -#endif - -#define CDVDdefs -#include "PS2Edefs.h" - -#endif /* __CDVD_H__ */ +#ifndef __CDVD_H__ +#define __CDVD_H__ + +#ifdef _WIN32 +#include +#endif + +#define CDVDdefs +#include "PS2Edefs.h" + +#endif /* __CDVD_H__ */ diff --git a/plugins/CDVDnull/Src/Makefile b/plugins/CDVDnull/Src/Makefile index 8331e1cee4..f16d9ace67 100644 --- a/plugins/CDVDnull/Src/Makefile +++ b/plugins/CDVDnull/Src/Makefile @@ -1,50 +1,50 @@ -# -# Makefile for MINGW32 -# - - -all: cdvdnull -install: all - -PLUGIN = libCDVDnull.so - -CC = gcc -NASM = nasmw -RM = rm -f -AR = ar -STRIP = strip -RC = windres - -OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing -FLAGS = -DENABLE_NLS -DPACKAGE=\"pcsx2\" -RC1FLAGS = -LIBS = -RESOBJ = cdvdnull.o - -OBJS = CDVD.o - - -DEPS:= $(OBJS:.o=.d) - -CFLAGS = -Wall ${OPTIMIZE} -I. -I/usr/local/include ${FLAGS} -fPIC - -cdvdnull: ${OBJS} -# dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} ${LIBS} - ${CC} -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} - ${STRIP} ${PLUGIN} - -.PHONY: clean cdvdnull - -clean: - ${RM} ${OBJS} ${DEPS} ${PCSX2} - -%.o: %.asm - ${NASM} ${ASMFLAGS} -o $@ $< - -%.o: %.c - ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) - -${RESOBJ}: CDVDnull.rc - ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< - --include ${DEPS} +# +# Makefile for MINGW32 +# + + +all: cdvdnull +install: all + +PLUGIN = libCDVDnull.so + +CC = gcc +NASM = nasmw +RM = rm -f +AR = ar +STRIP = strip +RC = windres + +OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing +FLAGS = -DENABLE_NLS -DPACKAGE=\"pcsx2\" +RC1FLAGS = +LIBS = +RESOBJ = cdvdnull.o + +OBJS = CDVD.o + + +DEPS:= $(OBJS:.o=.d) + +CFLAGS = -Wall ${OPTIMIZE} -I. -I/usr/local/include ${FLAGS} -fPIC + +cdvdnull: ${OBJS} +# dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} ${LIBS} + ${CC} -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + ${STRIP} ${PLUGIN} + +.PHONY: clean cdvdnull + +clean: + ${RM} ${OBJS} ${DEPS} ${PCSX2} + +%.o: %.asm + ${NASM} ${ASMFLAGS} -o $@ $< + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +${RESOBJ}: CDVDnull.rc + ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< + +-include ${DEPS} diff --git a/plugins/CDVDnull/Src/PS2Edefs.h b/plugins/CDVDnull/Src/PS2Edefs.h index 3e9707049b..9b6d49a2f3 100644 --- a/plugins/CDVDnull/Src/PS2Edefs.h +++ b/plugins/CDVDnull/Src/PS2Edefs.h @@ -1,827 +1,827 @@ -#ifndef __PS2EDEFS_H__ -#define __PS2EDEFS_H__ - -/* - * PS2E Definitions v0.6.2 (beta) - * - * Author: linuzappz@hotmail.com - * shadowpcsx2@yahoo.gr - * florinsasu@hotmail.com - */ - -/* - Notes: - * Since this is still beta things may change. - - * OSflags: - __LINUX__ (linux OS) - _WIN32 (win32 OS) - - * common return values (for ie. GSinit): - 0 - success - -1 - error - - * reserved keys: - F1 to F10 are reserved for the emulator - - * plugins should NOT change the current - working directory. - (on win32, add flag OFN_NOCHANGEDIR for - GetOpenFileName) - -*/ - -#include "PS2Etypes.h" - -#ifdef __LINUX__ -#define CALLBACK -#else -#include -#endif - - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ - defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ - defined(USBdefs) || defined(FWdefs) -#define COMMONdefs -#endif - -// PS2EgetLibType returns (may be OR'd) -#define PS2E_LT_GS 0x01 -#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- -#define PS2E_LT_SPU2 0x04 -#define PS2E_LT_CDVD 0x08 -#define PS2E_LT_DEV9 0x10 -#define PS2E_LT_USB 0x20 -#define PS2E_LT_FW 0x40 -#define PS2E_LT_SIO 0x80 - -// PS2EgetLibVersion2 (high 16 bits) -#define PS2E_GS_VERSION 0x0006 -#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- -#define PS2E_SPU2_VERSION 0x0005 -#define PS2E_CDVD_VERSION 0x0005 -#define PS2E_DEV9_VERSION 0x0003 -#define PS2E_USB_VERSION 0x0003 -#define PS2E_FW_VERSION 0x0002 -#define PS2E_SIO_VERSION 0x0001 -#ifdef COMMONdefs - -u32 CALLBACK PS2EgetLibType(void); -u32 CALLBACK PS2EgetLibVersion2(u32 type); -char* CALLBACK PS2EgetLibName(void); - -#endif - -// key values: -/* key values must be OS dependant: - win32: the VK_XXX will be used (WinUser) - linux: the XK_XXX will be used (XFree86) -*/ - -// event values: -#define KEYPRESS 1 -#define KEYRELEASE 2 - -typedef struct { - u32 key; - u32 event; -} keyEvent; - -// for 64bit compilers -typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; - -// plugin types -#define SIO_TYPE_PAD 0x00000001 -#define SIO_TYPE_MTAP 0x00000004 -#define SIO_TYPE_RM 0x00000040 -#define SIO_TYPE_MC 0x00000100 - -typedef int (CALLBACK * SIOchangeSlotCB)(int slot); - -typedef struct { - u8 ctrl:4; // control and mode bits - u8 mode:4; // control and mode bits - u8 trackNum; // current track number (1 to 99) - u8 trackIndex; // current index within track (0 to 99) - u8 trackM; // current minute location on the disc (BCD encoded) - u8 trackS; // current sector location on the disc (BCD encoded) - u8 trackF; // current frame location on the disc (BCD encoded) - u8 pad; // unused - u8 discM; // current minute offset from first track (BCD encoded) - u8 discS; // current sector offset from first track (BCD encoded) - u8 discF; // current frame offset from first track (BCD encoded) -} cdvdSubQ; - -typedef struct { // NOT bcd coded - u32 lsn; - u8 type; -} cdvdTD; - -typedef struct { - u8 strack; //number of the first track (usually 1) - u8 etrack; //number of the last track -} cdvdTN; - -// CDVDreadTrack mode values: -#define CDVD_MODE_2352 0 // full 2352 bytes -#define CDVD_MODE_2340 1 // skip sync (12) bytes -#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq - -// CDVDgetDiskType returns: -#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc -#define CDVD_TYPE_DVDV 0xfe // DVD Video -#define CDVD_TYPE_CDDA 0xfd // Audio CD -#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD -#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) -#define CDVD_TYPE_PS2CD 0x12 // PS2 CD -#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) -#define CDVD_TYPE_PSCD 0x10 // PS CD -#define CDVD_TYPE_UNKNOWN 0x05 // Unknown -#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided -#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided -#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd -#define CDVD_TYPE_DETCT 0x01 // Detecting -#define CDVD_TYPE_NODISC 0x00 // No Disc - -// CDVDgetTrayStatus returns: -#define CDVD_TRAY_CLOSE 0x00 -#define CDVD_TRAY_OPEN 0x01 - -// cdvdTD.type (track types for cds) -#define CDVD_AUDIO_TRACK 0x01 -#define CDVD_MODE1_TRACK 0x41 -#define CDVD_MODE2_TRACK 0x61 - -#define CDVD_AUDIO_MASK 0x00 -#define CDVD_DATA_MASK 0x40 -// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) - -typedef void (*DEV9callback)(int cycles); -typedef int (*DEV9handler)(void); - -typedef void (*USBcallback)(int cycles); -typedef int (*USBhandler)(void); - -// freeze modes: -#define FREEZE_LOAD 0 -#define FREEZE_SAVE 1 -#define FREEZE_SIZE 2 - -typedef struct { - char name[8]; - void *common; -} GSdriverInfo; - -#ifdef _WIN32 -typedef struct { // unsupported values must be set to zero - HWND hWnd; - HMENU hMenu; - HWND hStatusWnd; -} winInfo; -#endif - -/* GS plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef GSdefs - -// basic funcs - -s32 CALLBACK GSinit(); -s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); -void CALLBACK GSclose(); -void CALLBACK GSshutdown(); -void CALLBACK GSvsync(int field); -void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); -void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); -void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); -void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) -void CALLBACK GSgifSoftReset(u32 mask); -void CALLBACK GSreadFIFO(u64 *mem); -void CALLBACK GSreadFIFO2(u64 *mem, int qwc); - -// extended funcs - -// GSkeyEvent gets called when there is a keyEvent from the PAD plugin -void CALLBACK GSkeyEvent(keyEvent *ev); -void CALLBACK GSchangeSaveState(int, const char* filename); -void CALLBACK GSmakeSnapshot(char *path); -void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); -void CALLBACK GSirqCallback(void (*callback)()); -void CALLBACK GSprintf(int timeout, char *fmt, ...); -void CALLBACK GSsetBaseMem(void*); -void CALLBACK GSsetGameCRC(int crc, int gameoptions); - -// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done -void CALLBACK GSsetFrameSkip(int frameskip); - -void CALLBACK GSreset(); -void CALLBACK GSwriteCSR(u32 value); -void CALLBACK GSgetDriverInfo(GSdriverInfo *info); -#ifdef _WIN32 -s32 CALLBACK GSsetWindowInfo(winInfo *info); -#endif -s32 CALLBACK GSfreeze(int mode, freezeData *data); -void CALLBACK GSconfigure(); -void CALLBACK GSabout(); -s32 CALLBACK GStest(); - -#endif - -/* PAD plugin API -=[ OBSOLETE ]=- */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef PADdefs - -// basic funcs - -s32 CALLBACK PADinit(u32 flags); -s32 CALLBACK PADopen(void *pDsp); -void CALLBACK PADclose(); -void CALLBACK PADshutdown(); -// PADkeyEvent is called every vsync (return NULL if no event) -keyEvent* CALLBACK PADkeyEvent(); -u8 CALLBACK PADstartPoll(int pad); -u8 CALLBACK PADpoll(u8 value); -// returns: 1 if supported pad1 -// 2 if supported pad2 -// 3 if both are supported -u32 CALLBACK PADquery(); - -// call to give a hint to the PAD plugin to query for the keyboard state. A -// good plugin will query the OS for keyboard state ONLY in this function. -// This function is necessary when multithreading because otherwise -// the PAD plugin can get into deadlocks with the thread that really owns -// the window (and input). Note that PADupdate can be called from a different -// thread than the other functions, so mutex or other multithreading primitives -// have to be added to maintain data integrity. -void CALLBACK PADupdate(int pad); - -// extended funcs - -void CALLBACK PADgsDriverInfo(GSdriverInfo *info); -void CALLBACK PADconfigure(); -void CALLBACK PADabout(); -s32 CALLBACK PADtest(); - -#endif - -/* SIO plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SIOdefs - -// basic funcs - -s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); -s32 CALLBACK SIOopen(void *pDsp); -void CALLBACK SIOclose(); -void CALLBACK SIOshutdown(); -u8 CALLBACK SIOstartPoll(u8 value); -u8 CALLBACK SIOpoll(u8 value); -// returns: SIO_TYPE_{PAD,MTAP,RM,MC} -u32 CALLBACK SIOquery(); - -// extended funcs - -void CALLBACK SIOconfigure(); -void CALLBACK SIOabout(); -s32 CALLBACK SIOtest(); - -#endif - -/* SPU2 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SPU2defs - -// basic funcs - -s32 CALLBACK SPU2init(); -s32 CALLBACK SPU2open(void *pDsp); -void CALLBACK SPU2close(); -void CALLBACK SPU2shutdown(); -void CALLBACK SPU2write(u32 mem, u16 value); -u16 CALLBACK SPU2read(u32 mem); -void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA4(); -void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); -void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA7(); -u32 CALLBACK SPU2ReadMemAddr(int core); -void CALLBACK SPU2WriteMemAddr(int core,u32 value); -void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); -// extended funcs - -void CALLBACK SPU2async(u32 cycles); -s32 CALLBACK SPU2freeze(int mode, freezeData *data); -void CALLBACK SPU2configure(); -void CALLBACK SPU2about(); -s32 CALLBACK SPU2test(); - -#endif - -/* CDVD plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef CDVDdefs - -// basic funcs - -s32 CALLBACK CDVDinit(); -s32 CALLBACK CDVDopen(const char* pTitleFilename); -void CALLBACK CDVDclose(); -void CALLBACK CDVDshutdown(); -s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); - -// return can be NULL (for async modes) -u8* CALLBACK CDVDgetBuffer(); - -s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) -s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information -s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type -s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc -s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx -s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx -s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray -s32 CALLBACK CDVDctrlTrayClose(); //close disc tray - -// extended funcs - -void CALLBACK CDVDconfigure(); -void CALLBACK CDVDabout(); -s32 CALLBACK CDVDtest(); -void CALLBACK CDVDnewDiskCB(void (*callback)()); - -#endif - -/* DEV9 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef DEV9defs - -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK DEV9init(); -s32 CALLBACK DEV9open(void *pDsp); -void CALLBACK DEV9close(); -void CALLBACK DEV9shutdown(); -u8 CALLBACK DEV9read8(u32 addr); -u16 CALLBACK DEV9read16(u32 addr); -u32 CALLBACK DEV9read32(u32 addr); -void CALLBACK DEV9write8(u32 addr, u8 value); -void CALLBACK DEV9write16(u32 addr, u16 value); -void CALLBACK DEV9write32(u32 addr, u32 value); -void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); -void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK DEV9irqCallback(DEV9callback callback); -DEV9handler CALLBACK DEV9irqHandler(void); - -// extended funcs - -s32 CALLBACK DEV9freeze(int mode, freezeData *data); -void CALLBACK DEV9configure(); -void CALLBACK DEV9about(); -s32 CALLBACK DEV9test(); - -#endif - -/* USB plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef USBdefs - -// basic funcs - -s32 CALLBACK USBinit(); -s32 CALLBACK USBopen(void *pDsp); -void CALLBACK USBclose(); -void CALLBACK USBshutdown(); -u8 CALLBACK USBread8(u32 addr); -u16 CALLBACK USBread16(u32 addr); -u32 CALLBACK USBread32(u32 addr); -void CALLBACK USBwrite8(u32 addr, u8 value); -void CALLBACK USBwrite16(u32 addr, u16 value); -void CALLBACK USBwrite32(u32 addr, u32 value); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK USBirqCallback(USBcallback callback); -USBhandler CALLBACK USBirqHandler(void); -void CALLBACK USBsetRAM(void *mem); - -// extended funcs - -s32 CALLBACK USBfreeze(int mode, freezeData *data); -void CALLBACK USBconfigure(); -void CALLBACK USBabout(); -s32 CALLBACK USBtest(); - -#endif - -/* FW plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef FWdefs -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK FWinit(); -s32 CALLBACK FWopen(void *pDsp); -void CALLBACK FWclose(); -void CALLBACK FWshutdown(); -u32 CALLBACK FWread32(u32 addr); -void CALLBACK FWwrite32(u32 addr, u32 value); -void CALLBACK FWirqCallback(void (*callback)()); - -// extended funcs - -s32 CALLBACK FWfreeze(int mode, freezeData *data); -void CALLBACK FWconfigure(); -void CALLBACK FWabout(); -s32 CALLBACK FWtest(); -#endif - -// might be useful for emulators -#ifdef PLUGINtypedefs - -typedef u32 (CALLBACK* _PS2EgetLibType)(void); -typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); -typedef char*(CALLBACK* _PS2EgetLibName)(void); - -// GS -// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _GSinit)(); -typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); -typedef void (CALLBACK* _GSclose)(); -typedef void (CALLBACK* _GSshutdown)(); -typedef void (CALLBACK* _GSvsync)(int field); -typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); -typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) -typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); -typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); -typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); - -typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); -typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); -typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); -typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); -typedef void (CALLBACK* _GSsetBaseMem)(void*); -typedef void (CALLBACK* _GSsetGameCRC)(int, int); -typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); -typedef void (CALLBACK* _GSreset)(); -typedef void (CALLBACK* _GSwriteCSR)(u32 value); -typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); -#ifdef _WIN32 -typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); -#endif -typedef void (CALLBACK* _GSmakeSnapshot)(char *path); -typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); -typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _GSconfigure)(); -typedef s32 (CALLBACK* _GStest)(); -typedef void (CALLBACK* _GSabout)(); - -// PAD -typedef s32 (CALLBACK* _PADinit)(u32 flags); -typedef s32 (CALLBACK* _PADopen)(void *pDsp); -typedef void (CALLBACK* _PADclose)(); -typedef void (CALLBACK* _PADshutdown)(); -typedef keyEvent* (CALLBACK* _PADkeyEvent)(); -typedef u8 (CALLBACK* _PADstartPoll)(int pad); -typedef u8 (CALLBACK* _PADpoll)(u8 value); -typedef u32 (CALLBACK* _PADquery)(); -typedef void (CALLBACK* _PADupdate)(int pad); - -typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); -typedef void (CALLBACK* _PADconfigure)(); -typedef s32 (CALLBACK* _PADtest)(); -typedef void (CALLBACK* _PADabout)(); - -// SIO -typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); -typedef s32 (CALLBACK* _SIOopen)(void *pDsp); -typedef void (CALLBACK* _SIOclose)(); -typedef void (CALLBACK* _SIOshutdown)(); -typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); -typedef u8 (CALLBACK* _SIOpoll)(u8 value); -typedef u32 (CALLBACK* _SIOquery)(); - -typedef void (CALLBACK* _SIOconfigure)(); -typedef s32 (CALLBACK* _SIOtest)(); -typedef void (CALLBACK* _SIOabout)(); - -// SPU2 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _SPU2init)(); -typedef s32 (CALLBACK* _SPU2open)(void *pDsp); -typedef void (CALLBACK* _SPU2close)(); -typedef void (CALLBACK* _SPU2shutdown)(); -typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); -typedef u16 (CALLBACK* _SPU2read)(u32 mem); -typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA4)(); -typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA7)(); -typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); -typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); -typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); -typedef void (CALLBACK* _SPU2async)(u32 cycles); -typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _SPU2configure)(); -typedef s32 (CALLBACK* _SPU2test)(); -typedef void (CALLBACK* _SPU2about)(); - -// CDVD -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _CDVDinit)(); -typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); -typedef void (CALLBACK* _CDVDclose)(); -typedef void (CALLBACK* _CDVDshutdown)(); -typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); -typedef u8* (CALLBACK* _CDVDgetBuffer)(); -typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); -typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); -typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); -typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); -typedef s32 (CALLBACK* _CDVDgetDiskType)(); -typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); -typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); -typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); - -typedef void (CALLBACK* _CDVDconfigure)(); -typedef s32 (CALLBACK* _CDVDtest)(); -typedef void (CALLBACK* _CDVDabout)(); -typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); - -// DEV9 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _DEV9init)(); -typedef s32 (CALLBACK* _DEV9open)(void *pDsp); -typedef void (CALLBACK* _DEV9close)(); -typedef void (CALLBACK* _DEV9shutdown)(); -typedef u8 (CALLBACK* _DEV9read8)(u32 mem); -typedef u16 (CALLBACK* _DEV9read16)(u32 mem); -typedef u32 (CALLBACK* _DEV9read32)(u32 mem); -typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); -typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); -typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); -typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); -typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); - -typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _DEV9configure)(); -typedef s32 (CALLBACK* _DEV9test)(); -typedef void (CALLBACK* _DEV9about)(); - -// USB -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _USBinit)(); -typedef s32 (CALLBACK* _USBopen)(void *pDsp); -typedef void (CALLBACK* _USBclose)(); -typedef void (CALLBACK* _USBshutdown)(); -typedef u8 (CALLBACK* _USBread8)(u32 mem); -typedef u16 (CALLBACK* _USBread16)(u32 mem); -typedef u32 (CALLBACK* _USBread32)(u32 mem); -typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); -typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); -typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); -typedef USBhandler (CALLBACK* _USBirqHandler)(void); -typedef void (CALLBACK* _USBsetRAM)(void *mem); - -typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _USBconfigure)(); -typedef s32 (CALLBACK* _USBtest)(); -typedef void (CALLBACK* _USBabout)(); - -//FW -typedef s32 (CALLBACK* _FWinit)(); -typedef s32 (CALLBACK* _FWopen)(void *pDsp); -typedef void (CALLBACK* _FWclose)(); -typedef void (CALLBACK* _FWshutdown)(); -typedef u32 (CALLBACK* _FWread32)(u32 mem); -typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); - -typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _FWconfigure)(); -typedef s32 (CALLBACK* _FWtest)(); -typedef void (CALLBACK* _FWabout)(); - -#endif - -#ifdef PLUGINfuncs - -// GS -_GSinit GSinit; -_GSopen GSopen; -_GSclose GSclose; -_GSshutdown GSshutdown; -_GSvsync GSvsync; -_GSgifTransfer1 GSgifTransfer1; -_GSgifTransfer2 GSgifTransfer2; -_GSgifTransfer3 GSgifTransfer3; -_GSgetLastTag GSgetLastTag; -_GSgifSoftReset GSgifSoftReset; -_GSreadFIFO GSreadFIFO; -_GSreadFIFO2 GSreadFIFO2; - -_GSkeyEvent GSkeyEvent; -_GSchangeSaveState GSchangeSaveState; -_GSmakeSnapshot GSmakeSnapshot; -_GSmakeSnapshot2 GSmakeSnapshot2; -_GSirqCallback GSirqCallback; -_GSprintf GSprintf; -_GSsetBaseMem GSsetBaseMem; -_GSsetGameCRC GSsetGameCRC; -_GSsetFrameSkip GSsetFrameSkip; -_GSreset GSreset; -_GSwriteCSR GSwriteCSR; -_GSgetDriverInfo GSgetDriverInfo; -#ifdef _WIN32 -_GSsetWindowInfo GSsetWindowInfo; -#endif -_GSfreeze GSfreeze; -_GSconfigure GSconfigure; -_GStest GStest; -_GSabout GSabout; - -// PAD1 -_PADinit PAD1init; -_PADopen PAD1open; -_PADclose PAD1close; -_PADshutdown PAD1shutdown; -_PADkeyEvent PAD1keyEvent; -_PADstartPoll PAD1startPoll; -_PADpoll PAD1poll; -_PADquery PAD1query; -_PADupdate PAD1update; - -_PADgsDriverInfo PAD1gsDriverInfo; -_PADconfigure PAD1configure; -_PADtest PAD1test; -_PADabout PAD1about; - -// PAD2 -_PADinit PAD2init; -_PADopen PAD2open; -_PADclose PAD2close; -_PADshutdown PAD2shutdown; -_PADkeyEvent PAD2keyEvent; -_PADstartPoll PAD2startPoll; -_PADpoll PAD2poll; -_PADquery PAD2query; -_PADupdate PAD2update; - -_PADgsDriverInfo PAD2gsDriverInfo; -_PADconfigure PAD2configure; -_PADtest PAD2test; -_PADabout PAD2about; - -// SIO[2] -_SIOinit SIOinit[2][9]; -_SIOopen SIOopen[2][9]; -_SIOclose SIOclose[2][9]; -_SIOshutdown SIOshutdown[2][9]; -_SIOstartPoll SIOstartPoll[2][9]; -_SIOpoll SIOpoll[2][9]; -_SIOquery SIOquery[2][9]; - -_SIOconfigure SIOconfigure[2][9]; -_SIOtest SIOtest[2][9]; -_SIOabout SIOabout[2][9]; - -// SPU2 -_SPU2init SPU2init; -_SPU2open SPU2open; -_SPU2close SPU2close; -_SPU2shutdown SPU2shutdown; -_SPU2write SPU2write; -_SPU2read SPU2read; -_SPU2readDMA4Mem SPU2readDMA4Mem; -_SPU2writeDMA4Mem SPU2writeDMA4Mem; -_SPU2interruptDMA4 SPU2interruptDMA4; -_SPU2readDMA7Mem SPU2readDMA7Mem; -_SPU2writeDMA7Mem SPU2writeDMA7Mem; -_SPU2interruptDMA7 SPU2interruptDMA7; -_SPU2ReadMemAddr SPU2ReadMemAddr; -_SPU2WriteMemAddr SPU2WriteMemAddr; -_SPU2irqCallback SPU2irqCallback; - -_SPU2async SPU2async; -_SPU2freeze SPU2freeze; -_SPU2configure SPU2configure; -_SPU2test SPU2test; -_SPU2about SPU2about; - -// CDVD -_CDVDinit CDVDinit; -_CDVDopen CDVDopen; -_CDVDclose CDVDclose; -_CDVDshutdown CDVDshutdown; -_CDVDreadTrack CDVDreadTrack; -_CDVDgetBuffer CDVDgetBuffer; -_CDVDreadSubQ CDVDreadSubQ; -_CDVDgetTN CDVDgetTN; -_CDVDgetTD CDVDgetTD; -_CDVDgetTOC CDVDgetTOC; -_CDVDgetDiskType CDVDgetDiskType; -_CDVDgetTrayStatus CDVDgetTrayStatus; -_CDVDctrlTrayOpen CDVDctrlTrayOpen; -_CDVDctrlTrayClose CDVDctrlTrayClose; - -_CDVDconfigure CDVDconfigure; -_CDVDtest CDVDtest; -_CDVDabout CDVDabout; -_CDVDnewDiskCB CDVDnewDiskCB; - -// DEV9 -_DEV9init DEV9init; -_DEV9open DEV9open; -_DEV9close DEV9close; -_DEV9shutdown DEV9shutdown; -_DEV9read8 DEV9read8; -_DEV9read16 DEV9read16; -_DEV9read32 DEV9read32; -_DEV9write8 DEV9write8; -_DEV9write16 DEV9write16; -_DEV9write32 DEV9write32; -_DEV9readDMA8Mem DEV9readDMA8Mem; -_DEV9writeDMA8Mem DEV9writeDMA8Mem; -_DEV9irqCallback DEV9irqCallback; -_DEV9irqHandler DEV9irqHandler; - -_DEV9configure DEV9configure; -_DEV9freeze DEV9freeze; -_DEV9test DEV9test; -_DEV9about DEV9about; - -// USB -_USBinit USBinit; -_USBopen USBopen; -_USBclose USBclose; -_USBshutdown USBshutdown; -_USBread8 USBread8; -_USBread16 USBread16; -_USBread32 USBread32; -_USBwrite8 USBwrite8; -_USBwrite16 USBwrite16; -_USBwrite32 USBwrite32; -_USBirqCallback USBirqCallback; -_USBirqHandler USBirqHandler; -_USBsetRAM USBsetRAM; - -_USBconfigure USBconfigure; -_USBfreeze USBfreeze; -_USBtest USBtest; -_USBabout USBabout; - -// FW -_FWinit FWinit; -_FWopen FWopen; -_FWclose FWclose; -_FWshutdown FWshutdown; -_FWread32 FWread32; -_FWwrite32 FWwrite32; -_FWirqCallback FWirqCallback; - -_FWconfigure FWconfigure; -_FWfreeze FWfreeze; -_FWtest FWtest; -_FWabout FWabout; -#endif - -#endif /* __PS2EDEFS_H__ */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgetLastTag GSgetLastTag; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; +_PADupdate PAD1update; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; +_PADupdate PAD2update; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/CDVDolio/SettingsDlg.cpp b/plugins/CDVDolio/SettingsDlg.cpp index 3b4153978c..57f6281fc0 100644 --- a/plugins/CDVDolio/SettingsDlg.cpp +++ b/plugins/CDVDolio/SettingsDlg.cpp @@ -1,194 +1,194 @@ -// SettingsDlg.cpp : implementation file -// - -#include "stdafx.h" -#include "cdvd.h" -#include "SettingsDlg.h" -#include -#include - -// CSettingsDlg dialog - -IMPLEMENT_DYNAMIC(CSettingsDlg, CDialog) - -CSettingsDlg::CSettingsDlg(CWnd* pParent /*=NULL*/) - : CDialog(CSettingsDlg::IDD, pParent) - , m_iso(_T("")) -{ - -} - -CSettingsDlg::~CSettingsDlg() -{ -} - -BOOL CSettingsDlg::OnInitDialog() -{ - __super::OnInitDialog(); - - InitDrive(); - InitISO(); - - UpdateData(FALSE); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -void CSettingsDlg::InitDrive() -{ - int drive = AfxGetApp()->GetProfileInt(_T("Settings"), _T("drive"), -1); - - int sel = m_drive.GetCurSel(); - - if(sel >= 0) - { - drive = m_drive.GetItemData(sel); - } - - while(m_drive.GetCount() > 0) - { - m_drive.DeleteString(0); - } - - for(int i = 'A'; i <= 'Z'; i++) - { - CString path; - - path.Format(_T("%c:"), i); - - if(GetDriveType(path) == DRIVE_CDROM) - { - CString label = path; - - path.Format(_T("\\\\.\\%c:"), i); - - CDVD cdvd; - - if(cdvd.Open(path)) - { - CString str = cdvd.GetLabel(); - - if(str.IsEmpty()) - { - str = _T("(no label)"); - } - - label.Format(_T("[%s] %s"), CString(label), str); - } - else - { - label.Format(_T("[%s] (not detected)"), CString(label)); - } - - m_drive.SetItemData(m_drive.AddString(label), (DWORD_PTR)i); - } - } - - m_drive.SetItemData(m_drive.AddString(_T("Other...")), (DWORD_PTR)-1); - - for(int i = 0, j = m_drive.GetCount(); i < j; i++) - { - if((int)m_drive.GetItemData(i) == drive) - { - m_drive.SetCurSel(i); - - return; - } - } - - m_drive.SetCurSel(-1); -} - -void CSettingsDlg::InitISO() -{ - m_iso = AfxGetApp()->GetProfileString(_T("Settings"), _T("iso"), _T("")); -} - -void CSettingsDlg::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - DDX_Control(pDX, IDC_COMBO1, m_drive); - DDX_Text(pDX, IDC_EDIT1, m_iso); -} - -BEGIN_MESSAGE_MAP(CSettingsDlg, CDialog) - ON_BN_CLICKED(IDC_BUTTON1, &CSettingsDlg::OnBrowse) - ON_BN_CLICKED(IDOK, &CSettingsDlg::OnBnClickedOk) -END_MESSAGE_MAP() - -// CSettingsDlg message handlers - -LRESULT CSettingsDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - if(message == WM_DEVICECHANGE) - { - if(wParam == DBT_DEVICEARRIVAL || wParam == DBT_DEVICEREMOVECOMPLETE) - { - InitDrive(); - - DEV_BROADCAST_HDR* p = (DEV_BROADCAST_HDR*)lParam; - - if(p->dbch_devicetype == DBT_DEVTYP_VOLUME) - { - DEV_BROADCAST_VOLUME* v = (DEV_BROADCAST_VOLUME*)p; - - for(int i = 0; i < 32; i++) - { - if(v->dbcv_unitmask & (1 << i)) - { - TRACE(_T("%c:\n"), 'A' + i); - - // TODO - } - } - } - } - } - - return __super::WindowProc(message, wParam, lParam); -} - -void CSettingsDlg::OnBrowse() -{ - UpdateData(); - - CFileDialog fd(TRUE, NULL, m_iso, - OFN_EXPLORER | OFN_ENABLESIZING | OFN_HIDEREADONLY, - _T("ISO file|*.iso|All files|*.*|"), this); - - if(fd.DoModal() == IDOK) - { - m_iso = fd.GetPathName(); - - UpdateData(FALSE); - - for(int i = 0, j = m_drive.GetCount(); i < j; i++) - { - if((int)m_drive.GetItemData(i) < 0) - { - m_drive.SetCurSel(i); - - break; - } - } - } -} - -void CSettingsDlg::OnBnClickedOk() -{ - UpdateData(); - - int i = m_drive.GetCurSel(); - - if(i >= 0) - { - i = (int)m_drive.GetItemData(i); - } - - AfxGetApp()->WriteProfileInt(_T("Settings"), _T("drive"), i); - - AfxGetApp()->WriteProfileString(_T("Settings"), _T("iso"), m_iso); - - OnOK(); -} +// SettingsDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "cdvd.h" +#include "SettingsDlg.h" +#include +#include + +// CSettingsDlg dialog + +IMPLEMENT_DYNAMIC(CSettingsDlg, CDialog) + +CSettingsDlg::CSettingsDlg(CWnd* pParent /*=NULL*/) + : CDialog(CSettingsDlg::IDD, pParent) + , m_iso(_T("")) +{ + +} + +CSettingsDlg::~CSettingsDlg() +{ +} + +BOOL CSettingsDlg::OnInitDialog() +{ + __super::OnInitDialog(); + + InitDrive(); + InitISO(); + + UpdateData(FALSE); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CSettingsDlg::InitDrive() +{ + int drive = AfxGetApp()->GetProfileInt(_T("Settings"), _T("drive"), -1); + + int sel = m_drive.GetCurSel(); + + if(sel >= 0) + { + drive = m_drive.GetItemData(sel); + } + + while(m_drive.GetCount() > 0) + { + m_drive.DeleteString(0); + } + + for(int i = 'A'; i <= 'Z'; i++) + { + CString path; + + path.Format(_T("%c:"), i); + + if(GetDriveType(path) == DRIVE_CDROM) + { + CString label = path; + + path.Format(_T("\\\\.\\%c:"), i); + + CDVD cdvd; + + if(cdvd.Open(path)) + { + CString str = cdvd.GetLabel(); + + if(str.IsEmpty()) + { + str = _T("(no label)"); + } + + label.Format(_T("[%s] %s"), CString(label), str); + } + else + { + label.Format(_T("[%s] (not detected)"), CString(label)); + } + + m_drive.SetItemData(m_drive.AddString(label), (DWORD_PTR)i); + } + } + + m_drive.SetItemData(m_drive.AddString(_T("Other...")), (DWORD_PTR)-1); + + for(int i = 0, j = m_drive.GetCount(); i < j; i++) + { + if((int)m_drive.GetItemData(i) == drive) + { + m_drive.SetCurSel(i); + + return; + } + } + + m_drive.SetCurSel(-1); +} + +void CSettingsDlg::InitISO() +{ + m_iso = AfxGetApp()->GetProfileString(_T("Settings"), _T("iso"), _T("")); +} + +void CSettingsDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Control(pDX, IDC_COMBO1, m_drive); + DDX_Text(pDX, IDC_EDIT1, m_iso); +} + +BEGIN_MESSAGE_MAP(CSettingsDlg, CDialog) + ON_BN_CLICKED(IDC_BUTTON1, &CSettingsDlg::OnBrowse) + ON_BN_CLICKED(IDOK, &CSettingsDlg::OnBnClickedOk) +END_MESSAGE_MAP() + +// CSettingsDlg message handlers + +LRESULT CSettingsDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + if(message == WM_DEVICECHANGE) + { + if(wParam == DBT_DEVICEARRIVAL || wParam == DBT_DEVICEREMOVECOMPLETE) + { + InitDrive(); + + DEV_BROADCAST_HDR* p = (DEV_BROADCAST_HDR*)lParam; + + if(p->dbch_devicetype == DBT_DEVTYP_VOLUME) + { + DEV_BROADCAST_VOLUME* v = (DEV_BROADCAST_VOLUME*)p; + + for(int i = 0; i < 32; i++) + { + if(v->dbcv_unitmask & (1 << i)) + { + TRACE(_T("%c:\n"), 'A' + i); + + // TODO + } + } + } + } + } + + return __super::WindowProc(message, wParam, lParam); +} + +void CSettingsDlg::OnBrowse() +{ + UpdateData(); + + CFileDialog fd(TRUE, NULL, m_iso, + OFN_EXPLORER | OFN_ENABLESIZING | OFN_HIDEREADONLY, + _T("ISO file|*.iso|All files|*.*|"), this); + + if(fd.DoModal() == IDOK) + { + m_iso = fd.GetPathName(); + + UpdateData(FALSE); + + for(int i = 0, j = m_drive.GetCount(); i < j; i++) + { + if((int)m_drive.GetItemData(i) < 0) + { + m_drive.SetCurSel(i); + + break; + } + } + } +} + +void CSettingsDlg::OnBnClickedOk() +{ + UpdateData(); + + int i = m_drive.GetCurSel(); + + if(i >= 0) + { + i = (int)m_drive.GetItemData(i); + } + + AfxGetApp()->WriteProfileInt(_T("Settings"), _T("drive"), i); + + AfxGetApp()->WriteProfileString(_T("Settings"), _T("iso"), m_iso); + + OnOK(); +} diff --git a/plugins/CDVDolio/SettingsDlg.h b/plugins/CDVDolio/SettingsDlg.h index f2b4f5a79d..af06248c42 100644 --- a/plugins/CDVDolio/SettingsDlg.h +++ b/plugins/CDVDolio/SettingsDlg.h @@ -1,35 +1,35 @@ -#pragma once -#include "afxwin.h" -#include "resource.h" - -// CSettingsDlg dialog - -class CSettingsDlg : public CDialog -{ - DECLARE_DYNAMIC(CSettingsDlg) - -protected: - void InitDrive(); - void InitISO(); - -public: - CSettingsDlg(CWnd* pParent = NULL); // standard constructor - virtual ~CSettingsDlg(); - - virtual BOOL OnInitDialog(); - - enum { IDD = IDD_CONFIG }; - - CComboBox m_drive; - CString m_iso; - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - - DECLARE_MESSAGE_MAP() - - LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); - - afx_msg void OnBrowse(); - afx_msg void OnBnClickedOk(); -}; +#pragma once +#include "afxwin.h" +#include "resource.h" + +// CSettingsDlg dialog + +class CSettingsDlg : public CDialog +{ + DECLARE_DYNAMIC(CSettingsDlg) + +protected: + void InitDrive(); + void InitISO(); + +public: + CSettingsDlg(CWnd* pParent = NULL); // standard constructor + virtual ~CSettingsDlg(); + + virtual BOOL OnInitDialog(); + + enum { IDD = IDD_CONFIG }; + + CComboBox m_drive; + CString m_iso; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + + DECLARE_MESSAGE_MAP() + + LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + + afx_msg void OnBrowse(); + afx_msg void OnBnClickedOk(); +}; diff --git a/plugins/CDVDolio/cdvd.cpp b/plugins/CDVDolio/cdvd.cpp index 03f347db43..1568bf3777 100644 --- a/plugins/CDVDolio/cdvd.cpp +++ b/plugins/CDVDolio/cdvd.cpp @@ -1,391 +1,391 @@ -/* - * Copyright (C) 2007 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "cdvd.h" -#include "SettingsDlg.h" -#include - -#ifdef _DEBUG -#define new DEBUG_NEW -#endif - -// -// Note! -// -// If this DLL is dynamically linked against the MFC -// DLLs, any functions exported from this DLL which -// call into MFC must have the AFX_MANAGE_STATE macro -// added at the very beginning of the function. -// -// For example: -// -// extern "C" BOOL PASCAL EXPORT ExportedFunction() -// { -// AFX_MANAGE_STATE(AfxGetStaticModuleState()); -// // normal function body here -// } -// -// It is very important that this macro appear in each -// function, prior to any calls into MFC. This means that -// it must appear as the first statement within the -// function, even before any object variable declarations -// as their constructors may generate calls into the MFC -// DLL. -// -// Please see MFC Technical Notes 33 and 58 for additional -// details. -// - -BEGIN_MESSAGE_MAP(cdvdApp, CWinApp) -END_MESSAGE_MAP() - -cdvdApp::cdvdApp() -{ -} - -cdvdApp theApp; - -BOOL cdvdApp::InitInstance() -{ - __super::InitInstance(); - - SetRegistryKey(_T("Gabest")); - - return TRUE; -} - -// - -#define PS2E_LT_CDVD 0x08 -#define PS2E_CDVD_VERSION 0x0005 - -EXPORT_C_(UINT32) PS2EgetLibType() -{ - return PS2E_LT_CDVD; -} - -EXPORT_C_(char*) PS2EgetLibName() -{ - return "CDVDolio"; // olio = OverLapped I/O (duh) -} - -EXPORT_C_(UINT32) PS2EgetLibVersion2(UINT32 type) -{ - const UINT32 revision = 0; - const UINT32 build = 1; - const UINT32 minor = 0; - - return (build << 0) | (revision << 8) | (PS2E_CDVD_VERSION << 16) | (minor << 24); -} - -// - -CDVD::CDVD() - : m_hFile(INVALID_HANDLE_VALUE) -{ - memset(&m_overlapped, 0, sizeof(m_overlapped)); - m_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - m_cache.pending = false; - m_cache.count = 0; -} - -CDVD::~CDVD() -{ - CloseHandle(m_overlapped.hEvent); -} - -LARGE_INTEGER CDVD::MakeOffset(int lsn) -{ - LARGE_INTEGER offset; - offset.QuadPart = (LONGLONG)lsn * m_block.size + m_block.offset; - return offset; -} - -bool CDVD::SyncRead(int lsn) -{ - return Read(lsn) && GetBuffer(); -} - -bool CDVD::Open(CString path) -{ - m_label.Empty(); - - DWORD share = FILE_SHARE_READ; - DWORD flags = FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OVERLAPPED; - - m_hFile = CreateFile(path, GENERIC_READ, share, NULL, OPEN_EXISTING, flags, (HANDLE)NULL); - - if(m_hFile == INVALID_HANDLE_VALUE) - { - return false; - } - - m_block.count = 0; - m_block.size = 2048; - m_block.offset = 0; - - GET_LENGTH_INFORMATION info; - DWORD ret = 0; - - if(GetFileSizeEx(m_hFile, &info.Length) || DeviceIoControl(m_hFile, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &info, sizeof(info), &ret, NULL)) - { - m_block.count = (int)(info.Length.QuadPart / m_block.size); - } - else - { - Close(); - - return false; - } - - if(!SyncRead(16) || memcmp(&m_buff[24 + 1], "CD001", 5) != 0) - { - Close(); - - return false; - } - - m_label = CString(CStringA((char*)&m_buff[24 + 40], 32)); - m_label.Trim(); - - // m_block.count = *(DWORD*)&m_buff[24 + 80]; - - return true; -} - -void CDVD::Close() -{ - if(m_hFile != INVALID_HANDLE_VALUE) - { - CancelIo(m_hFile); - CloseHandle(m_hFile); - m_hFile = INVALID_HANDLE_VALUE; - } - - m_cache.pending = false; - m_cache.count = 0; - - m_label.Empty(); -} - -CString CDVD::GetLabel() -{ - return m_label; -} - -bool CDVD::Read(int lsn, int mode) -{ - if(mode != CDVD_MODE_2048) return false; - - if(lsn < 0) lsn += m_block.count; - - if(lsn < 0 || lsn >= m_block.count) return false; - - if(m_cache.pending) - { - CancelIo(m_hFile); - ResetEvent(m_overlapped.hEvent); - m_cache.pending = false; - } - - if(lsn >= m_cache.start && lsn < m_cache.start + m_cache.count) - { - memcpy(&m_buff[24], &m_cache.buff[(lsn - m_cache.start) * 2048], 2048); - - return true; - } - - m_cache.pending = true; - m_cache.start = lsn; - m_cache.count = min(CACHE_BLOCK_COUNT, m_block.count - m_cache.start); - - LARGE_INTEGER offset = MakeOffset(lsn); - - m_overlapped.Offset = offset.LowPart; - m_overlapped.OffsetHigh = offset.HighPart; - - if(!ReadFile(m_hFile, m_cache.buff, m_cache.count * 2048, NULL, &m_overlapped)) - { - switch(GetLastError()) - { - case ERROR_IO_PENDING: - break; - case ERROR_HANDLE_EOF: - return false; - } - } - - return true; -} - -BYTE* CDVD::GetBuffer() -{ - DWORD size = 0; - - if(m_cache.pending) - { - if(GetOverlappedResult(m_hFile, &m_overlapped, &size, TRUE)) - { - memcpy(&m_buff[24], m_cache.buff, 2048); - - m_cache.pending = false; - } - else - { - return NULL; - } - } - - return &m_buff[24]; -} - -UINT32 CDVD::GetTN(cdvdTN* buff) -{ - buff->strack = 1; - buff->etrack = 1; - - return 0; -} - -UINT32 CDVD::GetTD(BYTE track, cdvdTD* buff) -{ - if(track == 0) - { - buff->lsn = m_block.count; - } - else - { - buff->type = CDVD_MODE1_TRACK; - buff->lsn = 0; - } - - return 0; -} - -static CDVD s_cdvd; - -// - -EXPORT_C_(UINT32) CDVDinit() -{ - return 0; -} - -EXPORT_C CDVDshutdown() -{ -} - -EXPORT_C_(UINT32) CDVDopen(const char* title) -{ - CString path; - - int i = AfxGetApp()->GetProfileInt(_T("Settings"), _T("drive"), -1); - - if(i >= 'A' && i <= 'Z') - { - path.Format(_T("\\\\.\\%c:"), i); - } - else - { - path = AfxGetApp()->GetProfileString(_T("Settings"), _T("iso"), _T("")); - } - - return s_cdvd.Open(path) ? 0 : -1; -} - -EXPORT_C CDVDclose() -{ - s_cdvd.Close(); -} - -EXPORT_C_(UINT32) CDVDreadTrack(int lsn, int mode) -{ - return s_cdvd.Read(lsn, mode) ? 0 : -1; -} - -EXPORT_C_(BYTE*) CDVDgetBuffer() -{ - return s_cdvd.GetBuffer(); -} - -EXPORT_C_(UINT32) CDVDreadSubQ(UINT32 lsn, cdvdSubQ* subq) -{ - return -1; -} - -EXPORT_C_(UINT32) CDVDgetTN(cdvdTN* buff) -{ - return s_cdvd.GetTN(buff); -} - -EXPORT_C_(UINT32) CDVDgetTD(BYTE track, cdvdTD* buff) -{ - return s_cdvd.GetTD(track, buff); -} - -EXPORT_C_(UINT32) CDVDgetTOC(void* toc) -{ - return -1; // TODO -} - -EXPORT_C_(UINT32) CDVDgetDiskType() -{ - return CDVD_TYPE_PS2DVD; // TODO -} - -EXPORT_C_(UINT32) CDVDgetTrayStatus() -{ - return CDVD_TRAY_CLOSE; -} - -EXPORT_C_(UINT32) CDVDctrlTrayOpen() -{ - return 0; -} - -EXPORT_C_(UINT32) CDVDctrlTrayClose() -{ - return 0; -} - -EXPORT_C CDVDconfigure() -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - CSettingsDlg dlg; - - if(IDOK == dlg.DoModal()) - { - CDVDshutdown(); - CDVDinit(); - } -} - -EXPORT_C CDVDabout() -{ -} - -EXPORT_C_(UINT32) CDVDtest() -{ - return 0; -} - +/* + * Copyright (C) 2007 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "cdvd.h" +#include "SettingsDlg.h" +#include + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + +// +// Note! +// +// If this DLL is dynamically linked against the MFC +// DLLs, any functions exported from this DLL which +// call into MFC must have the AFX_MANAGE_STATE macro +// added at the very beginning of the function. +// +// For example: +// +// extern "C" BOOL PASCAL EXPORT ExportedFunction() +// { +// AFX_MANAGE_STATE(AfxGetStaticModuleState()); +// // normal function body here +// } +// +// It is very important that this macro appear in each +// function, prior to any calls into MFC. This means that +// it must appear as the first statement within the +// function, even before any object variable declarations +// as their constructors may generate calls into the MFC +// DLL. +// +// Please see MFC Technical Notes 33 and 58 for additional +// details. +// + +BEGIN_MESSAGE_MAP(cdvdApp, CWinApp) +END_MESSAGE_MAP() + +cdvdApp::cdvdApp() +{ +} + +cdvdApp theApp; + +BOOL cdvdApp::InitInstance() +{ + __super::InitInstance(); + + SetRegistryKey(_T("Gabest")); + + return TRUE; +} + +// + +#define PS2E_LT_CDVD 0x08 +#define PS2E_CDVD_VERSION 0x0005 + +EXPORT_C_(UINT32) PS2EgetLibType() +{ + return PS2E_LT_CDVD; +} + +EXPORT_C_(char*) PS2EgetLibName() +{ + return "CDVDolio"; // olio = OverLapped I/O (duh) +} + +EXPORT_C_(UINT32) PS2EgetLibVersion2(UINT32 type) +{ + const UINT32 revision = 0; + const UINT32 build = 1; + const UINT32 minor = 0; + + return (build << 0) | (revision << 8) | (PS2E_CDVD_VERSION << 16) | (minor << 24); +} + +// + +CDVD::CDVD() + : m_hFile(INVALID_HANDLE_VALUE) +{ + memset(&m_overlapped, 0, sizeof(m_overlapped)); + m_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + m_cache.pending = false; + m_cache.count = 0; +} + +CDVD::~CDVD() +{ + CloseHandle(m_overlapped.hEvent); +} + +LARGE_INTEGER CDVD::MakeOffset(int lsn) +{ + LARGE_INTEGER offset; + offset.QuadPart = (LONGLONG)lsn * m_block.size + m_block.offset; + return offset; +} + +bool CDVD::SyncRead(int lsn) +{ + return Read(lsn) && GetBuffer(); +} + +bool CDVD::Open(CString path) +{ + m_label.Empty(); + + DWORD share = FILE_SHARE_READ; + DWORD flags = FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OVERLAPPED; + + m_hFile = CreateFile(path, GENERIC_READ, share, NULL, OPEN_EXISTING, flags, (HANDLE)NULL); + + if(m_hFile == INVALID_HANDLE_VALUE) + { + return false; + } + + m_block.count = 0; + m_block.size = 2048; + m_block.offset = 0; + + GET_LENGTH_INFORMATION info; + DWORD ret = 0; + + if(GetFileSizeEx(m_hFile, &info.Length) || DeviceIoControl(m_hFile, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &info, sizeof(info), &ret, NULL)) + { + m_block.count = (int)(info.Length.QuadPart / m_block.size); + } + else + { + Close(); + + return false; + } + + if(!SyncRead(16) || memcmp(&m_buff[24 + 1], "CD001", 5) != 0) + { + Close(); + + return false; + } + + m_label = CString(CStringA((char*)&m_buff[24 + 40], 32)); + m_label.Trim(); + + // m_block.count = *(DWORD*)&m_buff[24 + 80]; + + return true; +} + +void CDVD::Close() +{ + if(m_hFile != INVALID_HANDLE_VALUE) + { + CancelIo(m_hFile); + CloseHandle(m_hFile); + m_hFile = INVALID_HANDLE_VALUE; + } + + m_cache.pending = false; + m_cache.count = 0; + + m_label.Empty(); +} + +CString CDVD::GetLabel() +{ + return m_label; +} + +bool CDVD::Read(int lsn, int mode) +{ + if(mode != CDVD_MODE_2048) return false; + + if(lsn < 0) lsn += m_block.count; + + if(lsn < 0 || lsn >= m_block.count) return false; + + if(m_cache.pending) + { + CancelIo(m_hFile); + ResetEvent(m_overlapped.hEvent); + m_cache.pending = false; + } + + if(lsn >= m_cache.start && lsn < m_cache.start + m_cache.count) + { + memcpy(&m_buff[24], &m_cache.buff[(lsn - m_cache.start) * 2048], 2048); + + return true; + } + + m_cache.pending = true; + m_cache.start = lsn; + m_cache.count = min(CACHE_BLOCK_COUNT, m_block.count - m_cache.start); + + LARGE_INTEGER offset = MakeOffset(lsn); + + m_overlapped.Offset = offset.LowPart; + m_overlapped.OffsetHigh = offset.HighPart; + + if(!ReadFile(m_hFile, m_cache.buff, m_cache.count * 2048, NULL, &m_overlapped)) + { + switch(GetLastError()) + { + case ERROR_IO_PENDING: + break; + case ERROR_HANDLE_EOF: + return false; + } + } + + return true; +} + +BYTE* CDVD::GetBuffer() +{ + DWORD size = 0; + + if(m_cache.pending) + { + if(GetOverlappedResult(m_hFile, &m_overlapped, &size, TRUE)) + { + memcpy(&m_buff[24], m_cache.buff, 2048); + + m_cache.pending = false; + } + else + { + return NULL; + } + } + + return &m_buff[24]; +} + +UINT32 CDVD::GetTN(cdvdTN* buff) +{ + buff->strack = 1; + buff->etrack = 1; + + return 0; +} + +UINT32 CDVD::GetTD(BYTE track, cdvdTD* buff) +{ + if(track == 0) + { + buff->lsn = m_block.count; + } + else + { + buff->type = CDVD_MODE1_TRACK; + buff->lsn = 0; + } + + return 0; +} + +static CDVD s_cdvd; + +// + +EXPORT_C_(UINT32) CDVDinit() +{ + return 0; +} + +EXPORT_C CDVDshutdown() +{ +} + +EXPORT_C_(UINT32) CDVDopen(const char* title) +{ + CString path; + + int i = AfxGetApp()->GetProfileInt(_T("Settings"), _T("drive"), -1); + + if(i >= 'A' && i <= 'Z') + { + path.Format(_T("\\\\.\\%c:"), i); + } + else + { + path = AfxGetApp()->GetProfileString(_T("Settings"), _T("iso"), _T("")); + } + + return s_cdvd.Open(path) ? 0 : -1; +} + +EXPORT_C CDVDclose() +{ + s_cdvd.Close(); +} + +EXPORT_C_(UINT32) CDVDreadTrack(int lsn, int mode) +{ + return s_cdvd.Read(lsn, mode) ? 0 : -1; +} + +EXPORT_C_(BYTE*) CDVDgetBuffer() +{ + return s_cdvd.GetBuffer(); +} + +EXPORT_C_(UINT32) CDVDreadSubQ(UINT32 lsn, cdvdSubQ* subq) +{ + return -1; +} + +EXPORT_C_(UINT32) CDVDgetTN(cdvdTN* buff) +{ + return s_cdvd.GetTN(buff); +} + +EXPORT_C_(UINT32) CDVDgetTD(BYTE track, cdvdTD* buff) +{ + return s_cdvd.GetTD(track, buff); +} + +EXPORT_C_(UINT32) CDVDgetTOC(void* toc) +{ + return -1; // TODO +} + +EXPORT_C_(UINT32) CDVDgetDiskType() +{ + return CDVD_TYPE_PS2DVD; // TODO +} + +EXPORT_C_(UINT32) CDVDgetTrayStatus() +{ + return CDVD_TRAY_CLOSE; +} + +EXPORT_C_(UINT32) CDVDctrlTrayOpen() +{ + return 0; +} + +EXPORT_C_(UINT32) CDVDctrlTrayClose() +{ + return 0; +} + +EXPORT_C CDVDconfigure() +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + CSettingsDlg dlg; + + if(IDOK == dlg.DoModal()) + { + CDVDshutdown(); + CDVDinit(); + } +} + +EXPORT_C CDVDabout() +{ +} + +EXPORT_C_(UINT32) CDVDtest() +{ + return 0; +} + diff --git a/plugins/CDVDolio/cdvd.h b/plugins/CDVDolio/cdvd.h index 1d9a8a5a51..26d6c9c97b 100644 --- a/plugins/CDVDolio/cdvd.h +++ b/plugins/CDVDolio/cdvd.h @@ -1,136 +1,136 @@ -/* - * Copyright (C) 2007 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#ifndef __AFXWIN_H__ - #error include 'stdafx.h' before including this file for PCH -#endif - -class cdvdApp : public CWinApp -{ -public: - cdvdApp(); - -public: - virtual BOOL InitInstance(); - - DECLARE_MESSAGE_MAP() -}; - -// - -struct cdvdSubQ -{ - BYTE ctrl:4; // control and mode bits - BYTE mode:4; // control and mode bits - BYTE trackNum; // current track number (1 to 99) - BYTE trackIndex; // current index within track (0 to 99) - BYTE trackM; // current minute location on the disc (BCD encoded) - BYTE trackS; // current sector location on the disc (BCD encoded) - BYTE trackF; // current frame location on the disc (BCD encoded) - BYTE pad; // unused - BYTE discM; // current minute offset from first track (BCD encoded) - BYTE discS; // current sector offset from first track (BCD encoded) - BYTE discF; // current frame offset from first track (BCD encoded) -}; - -struct cdvdTD // NOT bcd coded -{ - UINT32 lsn; - BYTE type; -}; - -struct cdvdTN -{ - BYTE strack; // number of the first track (usually 1) - BYTE etrack; // number of the last track -}; - -// CDVDreadTrack mode values: - -#define CDVD_MODE_2352 0 // full 2352 bytes -#define CDVD_MODE_2340 1 // skip sync (12) bytes -#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq - -// CDVDgetDiskType returns: - -#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc -#define CDVD_TYPE_DVDV 0xfe // DVD Video -#define CDVD_TYPE_CDDA 0xfd // Audio CD -#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD -#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) -#define CDVD_TYPE_PS2CD 0x12 // PS2 CD -#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) -#define CDVD_TYPE_PSCD 0x10 // PS CD -#define CDVD_TYPE_UNKNOWN 0x05 // Unknown -#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided -#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided -#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd -#define CDVD_TYPE_DETCT 0x01 // Detecting -#define CDVD_TYPE_NODISC 0x00 // No Disc - -// CDVDgetTrayStatus returns: - -#define CDVD_TRAY_CLOSE 0x00 -#define CDVD_TRAY_OPEN 0x01 - -// cdvdTD.type (track types for cds) - -#define CDVD_AUDIO_TRACK 0x01 -#define CDVD_MODE1_TRACK 0x41 -#define CDVD_MODE2_TRACK 0x61 - -#define CDVD_AUDIO_MASK 0x00 -#define CDVD_DATA_MASK 0x40 -// CDROM_DATA_TRACK 0x04 // do not enable this! (from linux kernel) - -// - -#define CACHE_BLOCK_COUNT 16 - -class CDVD -{ - HANDLE m_hFile; - CString m_label; - OVERLAPPED m_overlapped; - struct {int count, size, offset;} m_block; - struct {BYTE buff[2048 * CACHE_BLOCK_COUNT]; bool pending; int start, count;} m_cache; - BYTE m_buff[2352]; - - LARGE_INTEGER MakeOffset(int lsn); - bool SyncRead(int lsn); - -public: - CDVD(); - virtual ~CDVD(); - - bool Open(CString path); - void Close(); - CString GetLabel(); - bool Read(int lsn, int mode = CDVD_MODE_2048); - BYTE* GetBuffer(); - UINT32 GetTN(cdvdTN* buff); - UINT32 GetTD(BYTE track, cdvdTD* buff); -}; - +/* + * Copyright (C) 2007 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +class cdvdApp : public CWinApp +{ +public: + cdvdApp(); + +public: + virtual BOOL InitInstance(); + + DECLARE_MESSAGE_MAP() +}; + +// + +struct cdvdSubQ +{ + BYTE ctrl:4; // control and mode bits + BYTE mode:4; // control and mode bits + BYTE trackNum; // current track number (1 to 99) + BYTE trackIndex; // current index within track (0 to 99) + BYTE trackM; // current minute location on the disc (BCD encoded) + BYTE trackS; // current sector location on the disc (BCD encoded) + BYTE trackF; // current frame location on the disc (BCD encoded) + BYTE pad; // unused + BYTE discM; // current minute offset from first track (BCD encoded) + BYTE discS; // current sector offset from first track (BCD encoded) + BYTE discF; // current frame offset from first track (BCD encoded) +}; + +struct cdvdTD // NOT bcd coded +{ + UINT32 lsn; + BYTE type; +}; + +struct cdvdTN +{ + BYTE strack; // number of the first track (usually 1) + BYTE etrack; // number of the last track +}; + +// CDVDreadTrack mode values: + +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: + +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: + +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) + +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 // do not enable this! (from linux kernel) + +// + +#define CACHE_BLOCK_COUNT 16 + +class CDVD +{ + HANDLE m_hFile; + CString m_label; + OVERLAPPED m_overlapped; + struct {int count, size, offset;} m_block; + struct {BYTE buff[2048 * CACHE_BLOCK_COUNT]; bool pending; int start, count;} m_cache; + BYTE m_buff[2352]; + + LARGE_INTEGER MakeOffset(int lsn); + bool SyncRead(int lsn); + +public: + CDVD(); + virtual ~CDVD(); + + bool Open(CString path); + void Close(); + CString GetLabel(); + bool Read(int lsn, int mode = CDVD_MODE_2048); + BYTE* GetBuffer(); + UINT32 GetTN(cdvdTN* buff); + UINT32 GetTD(BYTE track, cdvdTD* buff); +}; + diff --git a/plugins/CDVDolio/resource.h b/plugins/CDVDolio/resource.h index 1aef423d7d..0ddcc4bde5 100644 --- a/plugins/CDVDolio/resource.h +++ b/plugins/CDVDolio/resource.h @@ -1,20 +1,20 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by cdvd.rc -// -#define IDC_COMBO1 2000 -#define IDC_RADIO1 2001 -#define IDC_EDIT1 2003 -#define IDC_BUTTON1 2004 -#define IDD_CONFIG 10000 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 10001 -#define _APS_NEXT_COMMAND_VALUE 32768 -#define _APS_NEXT_CONTROL_VALUE 2005 -#define _APS_NEXT_SYMED_VALUE 5000 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by cdvd.rc +// +#define IDC_COMBO1 2000 +#define IDC_RADIO1 2001 +#define IDC_EDIT1 2003 +#define IDC_BUTTON1 2004 +#define IDD_CONFIG 10000 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 10001 +#define _APS_NEXT_COMMAND_VALUE 32768 +#define _APS_NEXT_CONTROL_VALUE 2005 +#define _APS_NEXT_SYMED_VALUE 5000 +#endif +#endif diff --git a/plugins/CDVDolio/stdafx.cpp b/plugins/CDVDolio/stdafx.cpp index 12e706a21a..e48c42db5b 100644 --- a/plugins/CDVDolio/stdafx.cpp +++ b/plugins/CDVDolio/stdafx.cpp @@ -1,8 +1,8 @@ -// stdafx.cpp : source file that includes just the standard includes -// xpad.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" - -// TODO: reference any additional headers you need in STDAFX.H -// and not in this file +// stdafx.cpp : source file that includes just the standard includes +// xpad.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/plugins/CDVDolio/stdafx.h b/plugins/CDVDolio/stdafx.h index 9158292864..3f39fe0d2a 100644 --- a/plugins/CDVDolio/stdafx.h +++ b/plugins/CDVDolio/stdafx.h @@ -1,63 +1,63 @@ -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, but -// are changed infrequently - -#pragma once - -#pragma warning(disable: 4996) - -#ifndef VC_EXTRALEAN -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers -#endif - -// Modify the following defines if you have to target a platform prior to the ones specified below. -// Refer to MSDN for the latest info on corresponding values for different platforms. -#ifndef WINVER // Allow use of features specific to Windows 95 and Windows NT 4 or later. -#define WINVER 0x0510 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later. -#endif - -#ifndef _WIN32_WINNT // Allow use of features specific to Windows NT 4 or later. -#define _WIN32_WINNT 0x0400 // Change this to the appropriate value to target Windows 2000 or later. -#endif - -#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later. -#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. -#endif - -#ifndef _WIN32_IE // Allow use of features specific to IE 4.0 or later. -#define _WIN32_IE 0x0400 // Change this to the appropriate value to target IE 5.0 or later. -#endif - -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit - -#include // MFC core and standard components -//#include // MFC extensions -#ifndef _AFX_NO_AFXCMN_SUPPORT -#include // MFC support for Windows Common Controls -#endif // _AFX_NO_AFXCMN_SUPPORT -//#include -#include -#include -#include -#include - -#define countof(a) (sizeof(a)/sizeof(a[0])) - -#define EXPORT_C extern "C" __declspec(dllexport) void __stdcall -#define EXPORT_C_(type) extern "C" __declspec(dllexport) type __stdcall - -#ifndef RESTRICT - #ifdef __INTEL_COMPILER - #define RESTRICT restrict - #elif _MSC_VER >= 1400 - #define RESTRICT __restrict - #else - #define RESTRICT - #endif -#endif - -#pragma warning(disable : 4995 4324 4100) - -#ifdef _M_SSE -#error No SSE please! -#endif +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently + +#pragma once + +#pragma warning(disable: 4996) + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers +#endif + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef WINVER // Allow use of features specific to Windows 95 and Windows NT 4 or later. +#define WINVER 0x0510 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later. +#endif + +#ifndef _WIN32_WINNT // Allow use of features specific to Windows NT 4 or later. +#define _WIN32_WINNT 0x0400 // Change this to the appropriate value to target Windows 2000 or later. +#endif + +#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later. +#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. +#endif + +#ifndef _WIN32_IE // Allow use of features specific to IE 4.0 or later. +#define _WIN32_IE 0x0400 // Change this to the appropriate value to target IE 5.0 or later. +#endif + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit + +#include // MFC core and standard components +//#include // MFC extensions +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT +//#include +#include +#include +#include +#include + +#define countof(a) (sizeof(a)/sizeof(a[0])) + +#define EXPORT_C extern "C" __declspec(dllexport) void __stdcall +#define EXPORT_C_(type) extern "C" __declspec(dllexport) type __stdcall + +#ifndef RESTRICT + #ifdef __INTEL_COMPILER + #define RESTRICT restrict + #elif _MSC_VER >= 1400 + #define RESTRICT __restrict + #else + #define RESTRICT + #endif +#endif + +#pragma warning(disable : 4995 4324 4100) + +#ifdef _M_SSE +#error No SSE please! +#endif diff --git a/plugins/CDVDolio/svnrev_template.h b/plugins/CDVDolio/svnrev_template.h index 678f7916d3..c8806d96ae 100644 --- a/plugins/CDVDolio/svnrev_template.h +++ b/plugins/CDVDolio/svnrev_template.h @@ -1,2 +1,2 @@ -#define SVN_REV $WCREV$ +#define SVN_REV $WCREV$ #define SVN_MODS $WCMODS?1:0$ \ No newline at end of file diff --git a/plugins/CDVDpeops/CDVDiso.c b/plugins/CDVDpeops/CDVDiso.c index d15d1ff55c..cc71e30655 100644 --- a/plugins/CDVDpeops/CDVDiso.c +++ b/plugins/CDVDpeops/CDVDiso.c @@ -1,822 +1,822 @@ -/* - * Original code from libcdvd by Hiryu & Sjeep (C) 2002 - * Modified by Florin for PCSX2 emu - * Fixed CdRead by linuzappz - */ - -#include -#ifdef __LINUX__ -#define strnicmp strncasecmp -#endif - -#include "CDVDiso.h" -#include "CDVDisodrv.h" - -struct dir_toc_data{ - unsigned int start_LBA; - unsigned int num_sectors; - unsigned int num_entries; - unsigned int current_entry; - unsigned int current_sector; - unsigned int current_sector_offset; - unsigned int inc_dirs; - unsigned char extension_list[128+1]; -}; - -//static u8 cdVolDescriptor[2048]; -static struct dir_toc_data getDirTocData; -static struct cdVolDesc CDVolDesc; - -void _splitpath2(const char *constpath, char *dir, char *fname){ - // 255 char max path-length is an ISO9660 restriction - // we must change this for Joliet or relaxed iso restriction support - static char pathcopy[1024+1]; - - char* slash; - - strncpy(pathcopy, constpath, 1024); - - slash = strrchr (pathcopy, '/'); - - // if the path doesn't contain a '/' then look for a '\' - if (!slash) - slash = strrchr (pathcopy, (int)'\\'); - - // if a slash was found - if (slash != NULL) - { - // null terminate the path - slash[0] = 0; - // and copy the path into 'dir' - strncpy(dir, pathcopy, 1024); - dir[255]=0; - - // copy the filename into 'fname' - strncpy(fname, slash+1, 128); - fname[128]=0; - } - else - { - dir[0] = 0; - - strncpy(fname, pathcopy, 128); - fname[128]=0; - } - -} - -// Used in findfile -int tolower(int c); -int strcasecmp(const char *s1, const char *s2){ - while (*s1 != '\0' && tolower(*s1) == tolower(*s2)) - { - s1++; - s2++; - } - - return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2); -} - -// Copy a TOC Entry from the CD native format to our tidier format -void TocEntryCopy(struct TocEntry* tocEntry, struct dirTocEntry* internalTocEntry){ - int i; - int filenamelen; - - tocEntry->fileSize = internalTocEntry->fileSize; - tocEntry->fileLBA = internalTocEntry->fileLBA; - tocEntry->fileProperties = internalTocEntry->fileProperties; - memcpy(tocEntry->date, internalTocEntry->dateStamp, 7); - - if (CDVolDesc.filesystemType == 2){ - // This is a Joliet Filesystem, so use Unicode to ISO string copy - - filenamelen = internalTocEntry->filenameLength/2; - - if (!(tocEntry->fileProperties & 0x02)){ - // strip the ;1 from the filename -// filenamelen -= 2;//(Florin) nah, do not strip ;1 - } - - for (i=0; i < filenamelen; i++) - tocEntry->filename[i] = internalTocEntry->filename[(i<<1)+1]; - - tocEntry->filename[filenamelen] = 0; - } - else{ - filenamelen = internalTocEntry->filenameLength; - - if (!(tocEntry->fileProperties & 0x02)){ - // strip the ;1 from the filename -// filenamelen -= 2;//(Florin) nah, do not strip ;1 - } - - // use normal string copy - strncpy(tocEntry->filename,internalTocEntry->filename,128); - tocEntry->filename[filenamelen] = 0; - } -} - -// Check if a TOC Entry matches our extension list -int TocEntryCompare(char* filename, char* extensions){ - static char ext_list[129]; - - char* token; - - char* ext_point; - - strncpy(ext_list,extensions,128); - ext_list[128]=0; - - token = strtok( ext_list, " ," ); - while( token != NULL ) - { - // if 'token' matches extension of 'filename' - // then return a match - ext_point = strrchr(filename,'.'); - - if (strnicmp(ext_point, token, strlen(token)) == 0) - return (TRUE); - - /* Get next token: */ - token = strtok( NULL, " ," ); - } - - // If not match found then return FALSE - return (FALSE); - -} - -#define CD_SECS 60 /* seconds per minute */ -#define CD_FRAMES 75 /* frames per second */ -#define CD_MSF_OFFSET 150 /* MSF numbering offset of first frame */ - -int CdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode){ - u32 i; - u8* buff; - int rmode; - - switch (mode->datapattern) { - case CdSecS2048: - rmode = CDVD_MODE_2048; break; - case CdSecS2328: - rmode = CDVD_MODE_2328; break; - case CdSecS2340: - rmode = CDVD_MODE_2340; break; - default: - return 0; - } - - for (i=0; idatapattern){ - case CdSecS2048: - memcpy((void*)((uptr)buf+2048*i), buff, 2048);break;//only data - case CdSecS2328: - memcpy((void*)((uptr)buf+2328*i), buff, 2328);break;//without sync & head & sub - case CdSecS2340: - memcpy((void*)((uptr)buf+2340*i), buff, 2340);break;//without sync - } - } - return 1; -} - -int DvdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode){ - u32 i; - u8* buff; - - for (i=lsn; i<(lsn+sectors); i++){ - if (CDVDreadTrack(i, CDVD_MODE_2048)==-1) - return 0; - buff = CDVDgetBuffer(); - if (buff==NULL) return 0; - -// switch (mode->datapattern){ -// case CdSecS2064: - ((u32*)buf)[0] = i + 0x30000; - memcpy((u8*)buf+12, buff, 2048); - (u8*)buf+= 2064; break; -// default: -// return 0; -// } - } - - return 1; -} - -/************************************************************** -* The functions below are not exported for normal file-system * -* operations, but are used by the file-system operations, and * -* may also be exported for use via RPC * -**************************************************************/ - -int CDVD_GetVolumeDescriptor(void){ - // Read until we find the last valid Volume Descriptor - int volDescSector; - - static struct cdVolDesc localVolDesc; - -#ifdef DEBUG - printf("CDVD_GetVolumeDescriptor called\n"); -#endif - - for (volDescSector = 16; volDescSector<20; volDescSector++) - { - CdRead(volDescSector,1,&localVolDesc,&cdReadMode); -// CdSync(0x00); - - // If this is still a volume Descriptor - if (strncmp(localVolDesc.volID, "CD001", 5) == 0) - { - if ((localVolDesc.filesystemType == 1) || - (localVolDesc.filesystemType == 2)) - { - memcpy(&CDVolDesc, &localVolDesc, sizeof(struct cdVolDesc)); - } - } - else - break; - } - -#ifdef DEBUG - if (CDVolDesc.filesystemType == 1) - printf("CD FileSystem is ISO9660\n"); - else if (CDVolDesc.filesystemType == 2) - printf("CD FileSystem is Joliet\n"); - else printf("Could not detect CD FileSystem type\n"); -#endif -// CdStop(); - - return TRUE; -} - -int CDVD_findfile(char* fname, struct TocEntry* tocEntry){ - static char filename[128+1]; - static char pathname[1024+1]; - static char toc[2048]; - char* dirname; - - - static struct TocEntry localTocEntry; // used for internal checking only - - int found_dir; - - int num_dir_sectors; - int current_sector; - - int dir_lba; - - struct dirTocEntry* tocEntryPointer; - -#ifdef DEBUG - printf("CDVD_findfile called\n"); -#endif - - //make sure we have good cdReadMode - cdReadMode.trycount = 0; - cdReadMode.spindlctrl = CdSpinStm; - cdReadMode.datapattern = CdSecS2048; - - _splitpath2(fname, pathname, filename); - - // Find the TOC for a specific directory - if (CDVD_GetVolumeDescriptor() != TRUE){ -#ifdef RPC_LOG - RPC_LOG("Could not get CD Volume Descriptor\n"); -#endif - return -1; - } - - // Read the TOC of the root directory - if (CdRead(CDVolDesc.rootToc.tocLBA,1,toc,&cdReadMode) != TRUE){ -#ifdef RPC_LOG - RPC_LOG("Couldn't Read from CD !\n"); -#endif - return -1; - } - //CdSync(0x00); - - // point the tocEntryPointer at the first real toc entry - (char*)tocEntryPointer = toc; - - num_dir_sectors = (tocEntryPointer->fileSize+2047) >> 11; //round up fix - current_sector = tocEntryPointer->fileLBA; - - (char*)tocEntryPointer += tocEntryPointer->length; - (char*)tocEntryPointer += tocEntryPointer->length; - - - localTocEntry.fileLBA = CDVolDesc.rootToc.tocLBA; - // while (there are more dir names in the path) - dirname = strtok( pathname, "\\/" ); - - while( dirname != NULL ) - { - found_dir = FALSE; -/* - while(tocEntryPointer->length > 0) - { - // while there are still more directory entries then search through - // for the one we want - - if (tocEntryPointer->fileProperties & 0x02) - { - // Copy the CD format TOC Entry to our format - TocEntryCopy(&localTocEntry, tocEntryPointer); - - // If this TOC Entry is a directory, - // then see if it has the right name - if (strcasecmp(dirname,localTocEntry.filename) == 0) - { - // if the name matches then we've found the directory - found_dir = TRUE; - break; - } - } - - // point to the next entry - (char*)tocEntryPointer += tocEntryPointer->length; - } -*/ - while(1) - { - if ((tocEntryPointer->length == 0) || (((char*)tocEntryPointer-toc)>=2048)) - { - num_dir_sectors--; - - if (num_dir_sectors > 0) - { - // If we've run out of entries, but arent on the last sector - // then load another sector - - current_sector++; - if (CdRead(current_sector,1,toc,&cdReadMode) != TRUE) - { - return -1; - } -// CdSync(0x00); - - (char*)tocEntryPointer = toc; - } - else - { - // Couldnt find the directory, and got to end of directory - return -1; - } - } - - - if (tocEntryPointer->fileProperties & 0x02) - { - TocEntryCopy(&localTocEntry, tocEntryPointer); - - // If this TOC Entry is a directory, - // then see if it has the right name - if (strcmp(dirname,localTocEntry.filename) == 0) - { - // if the name matches then we've found the directory - found_dir = TRUE; - break; - } - } - - // point to the next entry - (char*)tocEntryPointer += tocEntryPointer->length; - } - - // If we havent found the directory name we wanted then fail - if (found_dir != TRUE) - { - return -1; - } - - // Get next directory name - dirname = strtok( NULL, "\\/" ); - - // Read the TOC of the found subdirectory - if (CdRead(localTocEntry.fileLBA,1,toc,&cdReadMode) != TRUE) - { - return -1; - } -// CdSync(0x00); - - num_dir_sectors = (localTocEntry.fileSize+2047) >> 11; //round up fix - current_sector = localTocEntry.fileLBA; - - // and point the tocEntryPointer at the first real toc entry - (char*)tocEntryPointer = toc; - (char*)tocEntryPointer += tocEntryPointer->length; - (char*)tocEntryPointer += tocEntryPointer->length; - } - - (char*)tocEntryPointer = toc; - - num_dir_sectors = (tocEntryPointer->fileSize+2047) >> 11; //round up fix - dir_lba = tocEntryPointer->fileLBA; - - (char*)tocEntryPointer = toc; - (char*)tocEntryPointer += tocEntryPointer->length; - (char*)tocEntryPointer += tocEntryPointer->length; - - while (num_dir_sectors > 0) - { - while(tocEntryPointer->length != 0) - { - // Copy the CD format TOC Entry to our format - TocEntryCopy(&localTocEntry, tocEntryPointer); - - if ((strnicmp(localTocEntry.filename, filename, strlen(filename)) == 0) || - ((filename[strlen(filename)-2] == ';') && - (localTocEntry.filename[strlen(localTocEntry.filename)-2] == ';') && - (strnicmp(localTocEntry.filename, filename, strlen(filename)-2) == 0))) - { - // if the filename matches then copy the toc Entry - tocEntry->fileLBA = localTocEntry.fileLBA; - tocEntry->fileProperties = localTocEntry.fileProperties; - tocEntry->fileSize = localTocEntry.fileSize; - - strcpy(tocEntry->filename, localTocEntry.filename); - memcpy(tocEntry->date, localTocEntry.date, 7); - -#ifdef DEBUG - printf("CDVD_findfile: found file\n"); -#endif - - return TRUE; - } - - (char*)tocEntryPointer += tocEntryPointer->length; - } - - num_dir_sectors--; - - if (num_dir_sectors > 0) - { - dir_lba++; - - if (CdRead(dir_lba,1,toc,&cdReadMode) != TRUE){ - return -1; - } -// CdSync(0x00); - - (char*)tocEntryPointer = toc; - } - } - - return FALSE; -} - -// This is the RPC-ready function which takes the request to start the tocEntry retrieval -int CDVD_GetDir_RPC_request(char* pathname, char* extensions, unsigned int inc_dirs){ -// int dir_depth = 1; - static char toc[2048]; - char* dirname; - int found_dir; - int num_dir_sectors; - unsigned int toc_entry_num; - struct dirTocEntry* tocEntryPointer; - static struct TocEntry localTocEntry; - int current_sector; - - // store the extension list statically for the retrieve function - strncpy(getDirTocData.extension_list, extensions, 128); - getDirTocData.extension_list[128]=0; - - getDirTocData.inc_dirs = inc_dirs; - - // Find the TOC for a specific directory - if (CDVD_GetVolumeDescriptor() != TRUE){ -#ifdef RPC_LOG - RPC_LOG("[RPC:cdvd] Could not get CD Volume Descriptor\n"); -#endif - return -1; - } - -#ifdef RPC_LOG - RPC_LOG("[RPC:cdvd] Getting Directory Listing for: \"%s\"\n", pathname); -#endif - - // Read the TOC of the root directory - if (CdRead(CDVolDesc.rootToc.tocLBA,1,toc,&cdReadMode) != TRUE){ -#ifdef RPC_LOG - RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); -#endif - return -1; - } - //CdSync(0x00); - - // point the tocEntryPointer at the first real toc entry - (char*)tocEntryPointer = toc; - - num_dir_sectors = (tocEntryPointer->fileSize+2047) >> 11; - current_sector = tocEntryPointer->fileLBA; - - (char*)tocEntryPointer += tocEntryPointer->length; - (char*)tocEntryPointer += tocEntryPointer->length; - - // use strtok to get the next dir name - - // if there isnt one, then assume we want the LBA - // for the current one, and exit the while loop - - // if there is another dir name then increment dir_depth - // and look through dir table entries until we find the right name - // if we dont find the right name - // before finding an entry at a higher level (lower num), then return nothing - - localTocEntry.fileLBA = CDVolDesc.rootToc.tocLBA; - - // while (there are more dir names in the path) - dirname = strtok( pathname, "\\/" ); - while( dirname != NULL ){ - found_dir = FALSE; - - while(1){ - if ((tocEntryPointer->length == 0) || (((char*)tocEntryPointer-toc)>=2048)) { - num_dir_sectors--; - - if (num_dir_sectors > 0){ - // If we've run out of entries, but arent on the last sector - // then load another sector - - current_sector++; - if (CdRead(current_sector,1,toc,&cdReadMode) != TRUE){ -#ifdef RPC_LOG - RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); -#endif - return -1; - } - //CdSync(0x00); - - (char*)tocEntryPointer = toc; - } - else{ - // Couldnt find the directory, and got to end of directory - return -1; - } - } - - if (tocEntryPointer->fileProperties & 0x02){ - TocEntryCopy(&localTocEntry, tocEntryPointer); - - // If this TOC Entry is a directory, - // then see if it has the right name - if (strcmp(dirname,localTocEntry.filename) == 0){ - // if the name matches then we've found the directory - found_dir = TRUE; -#ifdef RPC_LOG - RPC_LOG("[RPC: ] Found directory %s in subdir at sector %d\n",dirname,current_sector); - RPC_LOG("[RPC: ] LBA of found subdirectory = %d\n",localTocEntry.fileLBA); -#endif - break; - } - } - - // point to the next entry - (char*)tocEntryPointer += tocEntryPointer->length; - } - - // If we havent found the directory name we wanted then fail - if (found_dir != TRUE) - return -1; - - // Get next directory name - dirname = strtok( NULL, "\\/" ); - - // Read the TOC of the found subdirectory - if (CdRead(localTocEntry.fileLBA,1,toc,&cdReadMode) != TRUE){ -#ifdef RPC_LOG - RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); -#endif - return -1; - } - //CdSync(0x00); - - num_dir_sectors = (localTocEntry.fileSize+2047) >> 11; - current_sector = localTocEntry.fileLBA; - - // and point the tocEntryPointer at the first real toc entry - (char*)tocEntryPointer = toc; - (char*)tocEntryPointer += tocEntryPointer->length; - (char*)tocEntryPointer += tocEntryPointer->length; - } - - // We know how much data we need to read in from the DirTocHeader - // but we need to read in at least 1 sector before we can get this value - - // Now we need to COUNT the number of entries (dont do anything with info at this point) - // so set the tocEntryPointer to point to the first actual file entry - - // This is a bit of a waste of reads since we're not actually copying the data out yet, - // but we dont know how big this TOC might be, so we cant allocate a specific size - - (char*)tocEntryPointer = toc; - - // Need to STORE the start LBA and number of Sectors, for use by the retrieve func. - getDirTocData.start_LBA = localTocEntry.fileLBA; - getDirTocData.num_sectors = (tocEntryPointer->fileSize+2047) >> 11; - getDirTocData.num_entries = 0; - getDirTocData.current_entry = 0; - getDirTocData.current_sector = getDirTocData.start_LBA; - getDirTocData.current_sector_offset = 0; - - num_dir_sectors = getDirTocData.num_sectors; - - (char*)tocEntryPointer = toc; - (char*)tocEntryPointer += tocEntryPointer->length; - (char*)tocEntryPointer += tocEntryPointer->length; - - toc_entry_num=0; - - while(1){ - if ((tocEntryPointer->length == 0) || (((char*)tocEntryPointer-toc)>=2048)){ - // decrease the number of dirs remaining - num_dir_sectors--; - - if (num_dir_sectors > 0){ - // If we've run out of entries, but arent on the last sector - // then load another sector - getDirTocData.current_sector++; - - if (CdRead(getDirTocData.current_sector,1,toc,&cdReadMode) != TRUE){ -#ifdef RPC_LOG - RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); -#endif - return -1; - } - //CdSync(0x00); - - (char*)tocEntryPointer = toc; - -// continue; - } - else{ - getDirTocData.num_entries = toc_entry_num; - getDirTocData.current_sector = getDirTocData.start_LBA; - return (toc_entry_num); - } - } - - // We've found a file/dir in this directory - // now check if it matches our extension list (if there is one) - TocEntryCopy(&localTocEntry, tocEntryPointer); - - if (localTocEntry.fileProperties & 0x02){ - // If this is a subdir, then check if we want to include subdirs - if (getDirTocData.inc_dirs){ - toc_entry_num++; - } - } - else{ - if (strlen(getDirTocData.extension_list) > 0){ - if (TocEntryCompare(localTocEntry.filename, getDirTocData.extension_list) == TRUE){ - // increment the number of matching entries counter - toc_entry_num++; - } - } - else{ - toc_entry_num++; - } - } - - (char*)tocEntryPointer += tocEntryPointer->length; - - } - - - // THIS SHOULD BE UNREACHABLE - - // since we are trying to count ALL matching entries, rather than upto a limit - - - // STORE total number of TOC entries - getDirTocData.num_entries = toc_entry_num; - getDirTocData.current_sector = getDirTocData.start_LBA; - - - // we've reached the toc entry limit, so return how many we've done - return (toc_entry_num); - -} - -// This function can be called repeatedly after CDVD_GetDir_RPC_request to get the actual entries -// buffer (tocEntry) must be 18KB in size, and this will be filled with a maximum of 128 entries in one go -int CDVD_GetDir_RPC_get_entries(struct TocEntry tocEntry[], int req_entries){ - static char toc[2048]; - int toc_entry_num; - - struct dirTocEntry* tocEntryPointer; - - if (CdRead(getDirTocData.current_sector,1,toc,&cdReadMode) != TRUE){ -#ifdef RPC_LOG - RPC_LOG("[RPC:cdvd] Couldn't Read from CD !\n"); -#endif - return -1; - } - //CdSync(0x00); - - if (getDirTocData.current_entry == 0){ - // if this is the first read then make sure we point to the first real entry - (char*)tocEntryPointer = toc; - (char*)tocEntryPointer += tocEntryPointer->length; - (char*)tocEntryPointer += tocEntryPointer->length; - - getDirTocData.current_sector_offset = (char*)tocEntryPointer - toc; - } - else{ - (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; - } - - if (req_entries > 128) - req_entries = 128; - - for (toc_entry_num=0; toc_entry_num < req_entries;){ - if ((tocEntryPointer->length == 0) || (getDirTocData.current_sector_offset >= 2048)){ - // decrease the number of dirs remaining - getDirTocData.num_sectors--; - - if (getDirTocData.num_sectors > 0){ - // If we've run out of entries, but arent on the last sector - // then load another sector - getDirTocData.current_sector++; - - if (CdRead(getDirTocData.current_sector,1,toc,&cdReadMode) != TRUE){ -#ifdef RPC_LOG - RPC_LOG("[RPC:cdvd] Couldn't Read from CD !\n"); -#endif - return -1; - } - //CdSync(0x00); - - getDirTocData.current_sector_offset = 0; - (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; - -// continue; - } - else{ - return (toc_entry_num); - } - } - - // This must be incremented even if the filename doesnt match extension list - getDirTocData.current_entry++; - - // We've found a file in this directory - // now check if it matches our extension list (if there is one) - - // Copy the entry regardless, as it makes the comparison easier - // if it doesn't match then it will just be overwritten - TocEntryCopy(&tocEntry[toc_entry_num], tocEntryPointer); - - if (tocEntry[toc_entry_num].fileProperties & 0x02){ - // If this is a subdir, then check if we want to include subdirs - if (getDirTocData.inc_dirs) { - toc_entry_num++; - } - - getDirTocData.current_sector_offset += tocEntryPointer->length; - (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; - } - else{ - if (strlen(getDirTocData.extension_list) > 0){ - if (TocEntryCompare(tocEntry[toc_entry_num].filename, getDirTocData.extension_list) == TRUE){ - // increment the number of matching entries counter - toc_entry_num++; - } - - getDirTocData.current_sector_offset += tocEntryPointer->length; - (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; - - } - else{ - toc_entry_num++; - getDirTocData.current_sector_offset += tocEntryPointer->length; - (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; - } - } -/* - if (strlen(getDirTocData.extension_list) > 0) - { - if (TocEntryCompare(tocEntry[toc_entry_num].filename, getDirTocData.extension_list) == TRUE) - { - - // increment this here, rather than in the main for loop - // since this should count the number of matching entries - toc_entry_num++; - } - - getDirTocData.current_sector_offset += tocEntryPointer->length; - (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; - } - else - { - toc_entry_num++; - getDirTocData.current_sector_offset += tocEntryPointer->length; - (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; - } -*/ - } - return (toc_entry_num); -} +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Modified by Florin for PCSX2 emu + * Fixed CdRead by linuzappz + */ + +#include +#ifdef __LINUX__ +#define strnicmp strncasecmp +#endif + +#include "CDVDiso.h" +#include "CDVDisodrv.h" + +struct dir_toc_data{ + unsigned int start_LBA; + unsigned int num_sectors; + unsigned int num_entries; + unsigned int current_entry; + unsigned int current_sector; + unsigned int current_sector_offset; + unsigned int inc_dirs; + unsigned char extension_list[128+1]; +}; + +//static u8 cdVolDescriptor[2048]; +static struct dir_toc_data getDirTocData; +static struct cdVolDesc CDVolDesc; + +void _splitpath2(const char *constpath, char *dir, char *fname){ + // 255 char max path-length is an ISO9660 restriction + // we must change this for Joliet or relaxed iso restriction support + static char pathcopy[1024+1]; + + char* slash; + + strncpy(pathcopy, constpath, 1024); + + slash = strrchr (pathcopy, '/'); + + // if the path doesn't contain a '/' then look for a '\' + if (!slash) + slash = strrchr (pathcopy, (int)'\\'); + + // if a slash was found + if (slash != NULL) + { + // null terminate the path + slash[0] = 0; + // and copy the path into 'dir' + strncpy(dir, pathcopy, 1024); + dir[255]=0; + + // copy the filename into 'fname' + strncpy(fname, slash+1, 128); + fname[128]=0; + } + else + { + dir[0] = 0; + + strncpy(fname, pathcopy, 128); + fname[128]=0; + } + +} + +// Used in findfile +int tolower(int c); +int strcasecmp(const char *s1, const char *s2){ + while (*s1 != '\0' && tolower(*s1) == tolower(*s2)) + { + s1++; + s2++; + } + + return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2); +} + +// Copy a TOC Entry from the CD native format to our tidier format +void TocEntryCopy(struct TocEntry* tocEntry, struct dirTocEntry* internalTocEntry){ + int i; + int filenamelen; + + tocEntry->fileSize = internalTocEntry->fileSize; + tocEntry->fileLBA = internalTocEntry->fileLBA; + tocEntry->fileProperties = internalTocEntry->fileProperties; + memcpy(tocEntry->date, internalTocEntry->dateStamp, 7); + + if (CDVolDesc.filesystemType == 2){ + // This is a Joliet Filesystem, so use Unicode to ISO string copy + + filenamelen = internalTocEntry->filenameLength/2; + + if (!(tocEntry->fileProperties & 0x02)){ + // strip the ;1 from the filename +// filenamelen -= 2;//(Florin) nah, do not strip ;1 + } + + for (i=0; i < filenamelen; i++) + tocEntry->filename[i] = internalTocEntry->filename[(i<<1)+1]; + + tocEntry->filename[filenamelen] = 0; + } + else{ + filenamelen = internalTocEntry->filenameLength; + + if (!(tocEntry->fileProperties & 0x02)){ + // strip the ;1 from the filename +// filenamelen -= 2;//(Florin) nah, do not strip ;1 + } + + // use normal string copy + strncpy(tocEntry->filename,internalTocEntry->filename,128); + tocEntry->filename[filenamelen] = 0; + } +} + +// Check if a TOC Entry matches our extension list +int TocEntryCompare(char* filename, char* extensions){ + static char ext_list[129]; + + char* token; + + char* ext_point; + + strncpy(ext_list,extensions,128); + ext_list[128]=0; + + token = strtok( ext_list, " ," ); + while( token != NULL ) + { + // if 'token' matches extension of 'filename' + // then return a match + ext_point = strrchr(filename,'.'); + + if (strnicmp(ext_point, token, strlen(token)) == 0) + return (TRUE); + + /* Get next token: */ + token = strtok( NULL, " ," ); + } + + // If not match found then return FALSE + return (FALSE); + +} + +#define CD_SECS 60 /* seconds per minute */ +#define CD_FRAMES 75 /* frames per second */ +#define CD_MSF_OFFSET 150 /* MSF numbering offset of first frame */ + +int CdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode){ + u32 i; + u8* buff; + int rmode; + + switch (mode->datapattern) { + case CdSecS2048: + rmode = CDVD_MODE_2048; break; + case CdSecS2328: + rmode = CDVD_MODE_2328; break; + case CdSecS2340: + rmode = CDVD_MODE_2340; break; + default: + return 0; + } + + for (i=0; idatapattern){ + case CdSecS2048: + memcpy((void*)((uptr)buf+2048*i), buff, 2048);break;//only data + case CdSecS2328: + memcpy((void*)((uptr)buf+2328*i), buff, 2328);break;//without sync & head & sub + case CdSecS2340: + memcpy((void*)((uptr)buf+2340*i), buff, 2340);break;//without sync + } + } + return 1; +} + +int DvdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode){ + u32 i; + u8* buff; + + for (i=lsn; i<(lsn+sectors); i++){ + if (CDVDreadTrack(i, CDVD_MODE_2048)==-1) + return 0; + buff = CDVDgetBuffer(); + if (buff==NULL) return 0; + +// switch (mode->datapattern){ +// case CdSecS2064: + ((u32*)buf)[0] = i + 0x30000; + memcpy((u8*)buf+12, buff, 2048); + (u8*)buf+= 2064; break; +// default: +// return 0; +// } + } + + return 1; +} + +/************************************************************** +* The functions below are not exported for normal file-system * +* operations, but are used by the file-system operations, and * +* may also be exported for use via RPC * +**************************************************************/ + +int CDVD_GetVolumeDescriptor(void){ + // Read until we find the last valid Volume Descriptor + int volDescSector; + + static struct cdVolDesc localVolDesc; + +#ifdef DEBUG + printf("CDVD_GetVolumeDescriptor called\n"); +#endif + + for (volDescSector = 16; volDescSector<20; volDescSector++) + { + CdRead(volDescSector,1,&localVolDesc,&cdReadMode); +// CdSync(0x00); + + // If this is still a volume Descriptor + if (strncmp(localVolDesc.volID, "CD001", 5) == 0) + { + if ((localVolDesc.filesystemType == 1) || + (localVolDesc.filesystemType == 2)) + { + memcpy(&CDVolDesc, &localVolDesc, sizeof(struct cdVolDesc)); + } + } + else + break; + } + +#ifdef DEBUG + if (CDVolDesc.filesystemType == 1) + printf("CD FileSystem is ISO9660\n"); + else if (CDVolDesc.filesystemType == 2) + printf("CD FileSystem is Joliet\n"); + else printf("Could not detect CD FileSystem type\n"); +#endif +// CdStop(); + + return TRUE; +} + +int CDVD_findfile(char* fname, struct TocEntry* tocEntry){ + static char filename[128+1]; + static char pathname[1024+1]; + static char toc[2048]; + char* dirname; + + + static struct TocEntry localTocEntry; // used for internal checking only + + int found_dir; + + int num_dir_sectors; + int current_sector; + + int dir_lba; + + struct dirTocEntry* tocEntryPointer; + +#ifdef DEBUG + printf("CDVD_findfile called\n"); +#endif + + //make sure we have good cdReadMode + cdReadMode.trycount = 0; + cdReadMode.spindlctrl = CdSpinStm; + cdReadMode.datapattern = CdSecS2048; + + _splitpath2(fname, pathname, filename); + + // Find the TOC for a specific directory + if (CDVD_GetVolumeDescriptor() != TRUE){ +#ifdef RPC_LOG + RPC_LOG("Could not get CD Volume Descriptor\n"); +#endif + return -1; + } + + // Read the TOC of the root directory + if (CdRead(CDVolDesc.rootToc.tocLBA,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + // point the tocEntryPointer at the first real toc entry + (char*)tocEntryPointer = toc; + + num_dir_sectors = (tocEntryPointer->fileSize+2047) >> 11; //round up fix + current_sector = tocEntryPointer->fileLBA; + + (char*)tocEntryPointer += tocEntryPointer->length; + (char*)tocEntryPointer += tocEntryPointer->length; + + + localTocEntry.fileLBA = CDVolDesc.rootToc.tocLBA; + // while (there are more dir names in the path) + dirname = strtok( pathname, "\\/" ); + + while( dirname != NULL ) + { + found_dir = FALSE; +/* + while(tocEntryPointer->length > 0) + { + // while there are still more directory entries then search through + // for the one we want + + if (tocEntryPointer->fileProperties & 0x02) + { + // Copy the CD format TOC Entry to our format + TocEntryCopy(&localTocEntry, tocEntryPointer); + + // If this TOC Entry is a directory, + // then see if it has the right name + if (strcasecmp(dirname,localTocEntry.filename) == 0) + { + // if the name matches then we've found the directory + found_dir = TRUE; + break; + } + } + + // point to the next entry + (char*)tocEntryPointer += tocEntryPointer->length; + } +*/ + while(1) + { + if ((tocEntryPointer->length == 0) || (((char*)tocEntryPointer-toc)>=2048)) + { + num_dir_sectors--; + + if (num_dir_sectors > 0) + { + // If we've run out of entries, but arent on the last sector + // then load another sector + + current_sector++; + if (CdRead(current_sector,1,toc,&cdReadMode) != TRUE) + { + return -1; + } +// CdSync(0x00); + + (char*)tocEntryPointer = toc; + } + else + { + // Couldnt find the directory, and got to end of directory + return -1; + } + } + + + if (tocEntryPointer->fileProperties & 0x02) + { + TocEntryCopy(&localTocEntry, tocEntryPointer); + + // If this TOC Entry is a directory, + // then see if it has the right name + if (strcmp(dirname,localTocEntry.filename) == 0) + { + // if the name matches then we've found the directory + found_dir = TRUE; + break; + } + } + + // point to the next entry + (char*)tocEntryPointer += tocEntryPointer->length; + } + + // If we havent found the directory name we wanted then fail + if (found_dir != TRUE) + { + return -1; + } + + // Get next directory name + dirname = strtok( NULL, "\\/" ); + + // Read the TOC of the found subdirectory + if (CdRead(localTocEntry.fileLBA,1,toc,&cdReadMode) != TRUE) + { + return -1; + } +// CdSync(0x00); + + num_dir_sectors = (localTocEntry.fileSize+2047) >> 11; //round up fix + current_sector = localTocEntry.fileLBA; + + // and point the tocEntryPointer at the first real toc entry + (char*)tocEntryPointer = toc; + (char*)tocEntryPointer += tocEntryPointer->length; + (char*)tocEntryPointer += tocEntryPointer->length; + } + + (char*)tocEntryPointer = toc; + + num_dir_sectors = (tocEntryPointer->fileSize+2047) >> 11; //round up fix + dir_lba = tocEntryPointer->fileLBA; + + (char*)tocEntryPointer = toc; + (char*)tocEntryPointer += tocEntryPointer->length; + (char*)tocEntryPointer += tocEntryPointer->length; + + while (num_dir_sectors > 0) + { + while(tocEntryPointer->length != 0) + { + // Copy the CD format TOC Entry to our format + TocEntryCopy(&localTocEntry, tocEntryPointer); + + if ((strnicmp(localTocEntry.filename, filename, strlen(filename)) == 0) || + ((filename[strlen(filename)-2] == ';') && + (localTocEntry.filename[strlen(localTocEntry.filename)-2] == ';') && + (strnicmp(localTocEntry.filename, filename, strlen(filename)-2) == 0))) + { + // if the filename matches then copy the toc Entry + tocEntry->fileLBA = localTocEntry.fileLBA; + tocEntry->fileProperties = localTocEntry.fileProperties; + tocEntry->fileSize = localTocEntry.fileSize; + + strcpy(tocEntry->filename, localTocEntry.filename); + memcpy(tocEntry->date, localTocEntry.date, 7); + +#ifdef DEBUG + printf("CDVD_findfile: found file\n"); +#endif + + return TRUE; + } + + (char*)tocEntryPointer += tocEntryPointer->length; + } + + num_dir_sectors--; + + if (num_dir_sectors > 0) + { + dir_lba++; + + if (CdRead(dir_lba,1,toc,&cdReadMode) != TRUE){ + return -1; + } +// CdSync(0x00); + + (char*)tocEntryPointer = toc; + } + } + + return FALSE; +} + +// This is the RPC-ready function which takes the request to start the tocEntry retrieval +int CDVD_GetDir_RPC_request(char* pathname, char* extensions, unsigned int inc_dirs){ +// int dir_depth = 1; + static char toc[2048]; + char* dirname; + int found_dir; + int num_dir_sectors; + unsigned int toc_entry_num; + struct dirTocEntry* tocEntryPointer; + static struct TocEntry localTocEntry; + int current_sector; + + // store the extension list statically for the retrieve function + strncpy(getDirTocData.extension_list, extensions, 128); + getDirTocData.extension_list[128]=0; + + getDirTocData.inc_dirs = inc_dirs; + + // Find the TOC for a specific directory + if (CDVD_GetVolumeDescriptor() != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC:cdvd] Could not get CD Volume Descriptor\n"); +#endif + return -1; + } + +#ifdef RPC_LOG + RPC_LOG("[RPC:cdvd] Getting Directory Listing for: \"%s\"\n", pathname); +#endif + + // Read the TOC of the root directory + if (CdRead(CDVolDesc.rootToc.tocLBA,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + // point the tocEntryPointer at the first real toc entry + (char*)tocEntryPointer = toc; + + num_dir_sectors = (tocEntryPointer->fileSize+2047) >> 11; + current_sector = tocEntryPointer->fileLBA; + + (char*)tocEntryPointer += tocEntryPointer->length; + (char*)tocEntryPointer += tocEntryPointer->length; + + // use strtok to get the next dir name + + // if there isnt one, then assume we want the LBA + // for the current one, and exit the while loop + + // if there is another dir name then increment dir_depth + // and look through dir table entries until we find the right name + // if we dont find the right name + // before finding an entry at a higher level (lower num), then return nothing + + localTocEntry.fileLBA = CDVolDesc.rootToc.tocLBA; + + // while (there are more dir names in the path) + dirname = strtok( pathname, "\\/" ); + while( dirname != NULL ){ + found_dir = FALSE; + + while(1){ + if ((tocEntryPointer->length == 0) || (((char*)tocEntryPointer-toc)>=2048)) { + num_dir_sectors--; + + if (num_dir_sectors > 0){ + // If we've run out of entries, but arent on the last sector + // then load another sector + + current_sector++; + if (CdRead(current_sector,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + (char*)tocEntryPointer = toc; + } + else{ + // Couldnt find the directory, and got to end of directory + return -1; + } + } + + if (tocEntryPointer->fileProperties & 0x02){ + TocEntryCopy(&localTocEntry, tocEntryPointer); + + // If this TOC Entry is a directory, + // then see if it has the right name + if (strcmp(dirname,localTocEntry.filename) == 0){ + // if the name matches then we've found the directory + found_dir = TRUE; +#ifdef RPC_LOG + RPC_LOG("[RPC: ] Found directory %s in subdir at sector %d\n",dirname,current_sector); + RPC_LOG("[RPC: ] LBA of found subdirectory = %d\n",localTocEntry.fileLBA); +#endif + break; + } + } + + // point to the next entry + (char*)tocEntryPointer += tocEntryPointer->length; + } + + // If we havent found the directory name we wanted then fail + if (found_dir != TRUE) + return -1; + + // Get next directory name + dirname = strtok( NULL, "\\/" ); + + // Read the TOC of the found subdirectory + if (CdRead(localTocEntry.fileLBA,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + num_dir_sectors = (localTocEntry.fileSize+2047) >> 11; + current_sector = localTocEntry.fileLBA; + + // and point the tocEntryPointer at the first real toc entry + (char*)tocEntryPointer = toc; + (char*)tocEntryPointer += tocEntryPointer->length; + (char*)tocEntryPointer += tocEntryPointer->length; + } + + // We know how much data we need to read in from the DirTocHeader + // but we need to read in at least 1 sector before we can get this value + + // Now we need to COUNT the number of entries (dont do anything with info at this point) + // so set the tocEntryPointer to point to the first actual file entry + + // This is a bit of a waste of reads since we're not actually copying the data out yet, + // but we dont know how big this TOC might be, so we cant allocate a specific size + + (char*)tocEntryPointer = toc; + + // Need to STORE the start LBA and number of Sectors, for use by the retrieve func. + getDirTocData.start_LBA = localTocEntry.fileLBA; + getDirTocData.num_sectors = (tocEntryPointer->fileSize+2047) >> 11; + getDirTocData.num_entries = 0; + getDirTocData.current_entry = 0; + getDirTocData.current_sector = getDirTocData.start_LBA; + getDirTocData.current_sector_offset = 0; + + num_dir_sectors = getDirTocData.num_sectors; + + (char*)tocEntryPointer = toc; + (char*)tocEntryPointer += tocEntryPointer->length; + (char*)tocEntryPointer += tocEntryPointer->length; + + toc_entry_num=0; + + while(1){ + if ((tocEntryPointer->length == 0) || (((char*)tocEntryPointer-toc)>=2048)){ + // decrease the number of dirs remaining + num_dir_sectors--; + + if (num_dir_sectors > 0){ + // If we've run out of entries, but arent on the last sector + // then load another sector + getDirTocData.current_sector++; + + if (CdRead(getDirTocData.current_sector,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC: ] Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + (char*)tocEntryPointer = toc; + +// continue; + } + else{ + getDirTocData.num_entries = toc_entry_num; + getDirTocData.current_sector = getDirTocData.start_LBA; + return (toc_entry_num); + } + } + + // We've found a file/dir in this directory + // now check if it matches our extension list (if there is one) + TocEntryCopy(&localTocEntry, tocEntryPointer); + + if (localTocEntry.fileProperties & 0x02){ + // If this is a subdir, then check if we want to include subdirs + if (getDirTocData.inc_dirs){ + toc_entry_num++; + } + } + else{ + if (strlen(getDirTocData.extension_list) > 0){ + if (TocEntryCompare(localTocEntry.filename, getDirTocData.extension_list) == TRUE){ + // increment the number of matching entries counter + toc_entry_num++; + } + } + else{ + toc_entry_num++; + } + } + + (char*)tocEntryPointer += tocEntryPointer->length; + + } + + + // THIS SHOULD BE UNREACHABLE - + // since we are trying to count ALL matching entries, rather than upto a limit + + + // STORE total number of TOC entries + getDirTocData.num_entries = toc_entry_num; + getDirTocData.current_sector = getDirTocData.start_LBA; + + + // we've reached the toc entry limit, so return how many we've done + return (toc_entry_num); + +} + +// This function can be called repeatedly after CDVD_GetDir_RPC_request to get the actual entries +// buffer (tocEntry) must be 18KB in size, and this will be filled with a maximum of 128 entries in one go +int CDVD_GetDir_RPC_get_entries(struct TocEntry tocEntry[], int req_entries){ + static char toc[2048]; + int toc_entry_num; + + struct dirTocEntry* tocEntryPointer; + + if (CdRead(getDirTocData.current_sector,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC:cdvd] Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + if (getDirTocData.current_entry == 0){ + // if this is the first read then make sure we point to the first real entry + (char*)tocEntryPointer = toc; + (char*)tocEntryPointer += tocEntryPointer->length; + (char*)tocEntryPointer += tocEntryPointer->length; + + getDirTocData.current_sector_offset = (char*)tocEntryPointer - toc; + } + else{ + (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; + } + + if (req_entries > 128) + req_entries = 128; + + for (toc_entry_num=0; toc_entry_num < req_entries;){ + if ((tocEntryPointer->length == 0) || (getDirTocData.current_sector_offset >= 2048)){ + // decrease the number of dirs remaining + getDirTocData.num_sectors--; + + if (getDirTocData.num_sectors > 0){ + // If we've run out of entries, but arent on the last sector + // then load another sector + getDirTocData.current_sector++; + + if (CdRead(getDirTocData.current_sector,1,toc,&cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[RPC:cdvd] Couldn't Read from CD !\n"); +#endif + return -1; + } + //CdSync(0x00); + + getDirTocData.current_sector_offset = 0; + (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; + +// continue; + } + else{ + return (toc_entry_num); + } + } + + // This must be incremented even if the filename doesnt match extension list + getDirTocData.current_entry++; + + // We've found a file in this directory + // now check if it matches our extension list (if there is one) + + // Copy the entry regardless, as it makes the comparison easier + // if it doesn't match then it will just be overwritten + TocEntryCopy(&tocEntry[toc_entry_num], tocEntryPointer); + + if (tocEntry[toc_entry_num].fileProperties & 0x02){ + // If this is a subdir, then check if we want to include subdirs + if (getDirTocData.inc_dirs) { + toc_entry_num++; + } + + getDirTocData.current_sector_offset += tocEntryPointer->length; + (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; + } + else{ + if (strlen(getDirTocData.extension_list) > 0){ + if (TocEntryCompare(tocEntry[toc_entry_num].filename, getDirTocData.extension_list) == TRUE){ + // increment the number of matching entries counter + toc_entry_num++; + } + + getDirTocData.current_sector_offset += tocEntryPointer->length; + (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; + + } + else{ + toc_entry_num++; + getDirTocData.current_sector_offset += tocEntryPointer->length; + (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; + } + } +/* + if (strlen(getDirTocData.extension_list) > 0) + { + if (TocEntryCompare(tocEntry[toc_entry_num].filename, getDirTocData.extension_list) == TRUE) + { + + // increment this here, rather than in the main for loop + // since this should count the number of matching entries + toc_entry_num++; + } + + getDirTocData.current_sector_offset += tocEntryPointer->length; + (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; + } + else + { + toc_entry_num++; + getDirTocData.current_sector_offset += tocEntryPointer->length; + (char*)tocEntryPointer = toc + getDirTocData.current_sector_offset; + } +*/ + } + return (toc_entry_num); +} diff --git a/plugins/CDVDpeops/CDVDiso.h b/plugins/CDVDpeops/CDVDiso.h index 72b0552280..b68178402b 100644 --- a/plugins/CDVDpeops/CDVDiso.h +++ b/plugins/CDVDpeops/CDVDiso.h @@ -1,131 +1,131 @@ -/* - * Original code from libcdvd by Hiryu & Sjeep (C) 2002 - * Modified by Florin for PCSX2 emu - */ - -#ifndef __CDVDISO_H__ -#define __CDVDISO_H__ - -#include "CDVDlib.h" - -int CDVD_findfile(char* fname, struct TocEntry* tocEntry); -int CDVD_GetDir_RPC_request(char* pathname, char* extensions, unsigned int inc_dirs); -int CDVD_GetDir_RPC_get_entries(struct TocEntry tocEntry[], int req_entries); - -#if defined(__WIN32__) -#pragma pack(1) -#endif - -struct rootDirTocHeader -{ - u16 length; //+00 - u32 tocLBA; //+02 - u32 tocLBA_bigend; //+06 - u32 tocSize; //+0A - u32 tocSize_bigend; //+0E - u8 dateStamp[8]; //+12 - u8 reserved[6]; //+1A - u8 reserved2; //+20 - u8 reserved3; //+21 -#if defined(__WIN32__) -}; //+22 -#else -} __attribute__((packed)); -#endif - -struct asciiDate -{ - char year[4]; - char month[2]; - char day[2]; - char hours[2]; - char minutes[2]; - char seconds[2]; - char hundreths[2]; - char terminator[1]; -#if defined(__WIN32__) -}; -#else -} __attribute__((packed)); -#endif - -struct cdVolDesc -{ - u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL - u8 volID[5]; // "CD001" - u8 reserved2; - u8 reserved3; - u8 sysIdName[32]; - u8 volName[32]; // The ISO9660 Volume Name - u8 reserved5[8]; - u32 volSize; // Volume Size - u32 volSizeBig; // Volume Size Big-Endian - u8 reserved6[32]; - u32 unknown1; - u32 unknown1_bigend; - u16 volDescSize; //+80 - u16 volDescSize_bigend; //+82 - u32 unknown3; //+84 - u32 unknown3_bigend; //+88 - u32 priDirTableLBA; // LBA of Primary Dir Table //+8C - u32 reserved7; //+90 - u32 secDirTableLBA; // LBA of Secondary Dir Table //+94 - u32 reserved8; //+98 - struct rootDirTocHeader rootToc; - u8 volSetName[128]; - u8 publisherName[128]; - u8 preparerName[128]; - u8 applicationName[128]; - u8 copyrightFileName[37]; - u8 abstractFileName[37]; - u8 bibliographyFileName[37]; - struct asciiDate creationDate; - struct asciiDate modificationDate; - struct asciiDate effectiveDate; - struct asciiDate expirationDate; - u8 reserved10; - u8 reserved11[1166]; -#if defined(__WIN32__) -}; -#else -} __attribute__((packed)); -#endif - -struct dirTableEntry -{ - u8 dirNameLength; - u8 reserved; - u32 dirTOCLBA; - u16 dirDepth; - u8 dirName[32]; -#if defined(__WIN32__) -}; -#else -} __attribute__((packed)); -#endif - -struct dirTocEntry -{ - short length; - unsigned int fileLBA; - unsigned int fileLBA_bigend; - unsigned int fileSize; - unsigned int fileSize_bigend; - unsigned char dateStamp[6]; - unsigned char reserved1; - unsigned char fileProperties; - unsigned char reserved2[6]; - unsigned char filenameLength; - unsigned char filename[128]; -#if defined(__WIN32__) -}; -#else -} __attribute__((packed)); -#endif // This is the internal format on the CD -// TocEntry structure contains only the important stuff needed for export - -#if defined(__WIN32__) -#pragma pack() -#endif - -#endif//__CDVDISO_H__ +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Modified by Florin for PCSX2 emu + */ + +#ifndef __CDVDISO_H__ +#define __CDVDISO_H__ + +#include "CDVDlib.h" + +int CDVD_findfile(char* fname, struct TocEntry* tocEntry); +int CDVD_GetDir_RPC_request(char* pathname, char* extensions, unsigned int inc_dirs); +int CDVD_GetDir_RPC_get_entries(struct TocEntry tocEntry[], int req_entries); + +#if defined(__WIN32__) +#pragma pack(1) +#endif + +struct rootDirTocHeader +{ + u16 length; //+00 + u32 tocLBA; //+02 + u32 tocLBA_bigend; //+06 + u32 tocSize; //+0A + u32 tocSize_bigend; //+0E + u8 dateStamp[8]; //+12 + u8 reserved[6]; //+1A + u8 reserved2; //+20 + u8 reserved3; //+21 +#if defined(__WIN32__) +}; //+22 +#else +} __attribute__((packed)); +#endif + +struct asciiDate +{ + char year[4]; + char month[2]; + char day[2]; + char hours[2]; + char minutes[2]; + char seconds[2]; + char hundreths[2]; + char terminator[1]; +#if defined(__WIN32__) +}; +#else +} __attribute__((packed)); +#endif + +struct cdVolDesc +{ + u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL + u8 volID[5]; // "CD001" + u8 reserved2; + u8 reserved3; + u8 sysIdName[32]; + u8 volName[32]; // The ISO9660 Volume Name + u8 reserved5[8]; + u32 volSize; // Volume Size + u32 volSizeBig; // Volume Size Big-Endian + u8 reserved6[32]; + u32 unknown1; + u32 unknown1_bigend; + u16 volDescSize; //+80 + u16 volDescSize_bigend; //+82 + u32 unknown3; //+84 + u32 unknown3_bigend; //+88 + u32 priDirTableLBA; // LBA of Primary Dir Table //+8C + u32 reserved7; //+90 + u32 secDirTableLBA; // LBA of Secondary Dir Table //+94 + u32 reserved8; //+98 + struct rootDirTocHeader rootToc; + u8 volSetName[128]; + u8 publisherName[128]; + u8 preparerName[128]; + u8 applicationName[128]; + u8 copyrightFileName[37]; + u8 abstractFileName[37]; + u8 bibliographyFileName[37]; + struct asciiDate creationDate; + struct asciiDate modificationDate; + struct asciiDate effectiveDate; + struct asciiDate expirationDate; + u8 reserved10; + u8 reserved11[1166]; +#if defined(__WIN32__) +}; +#else +} __attribute__((packed)); +#endif + +struct dirTableEntry +{ + u8 dirNameLength; + u8 reserved; + u32 dirTOCLBA; + u16 dirDepth; + u8 dirName[32]; +#if defined(__WIN32__) +}; +#else +} __attribute__((packed)); +#endif + +struct dirTocEntry +{ + short length; + unsigned int fileLBA; + unsigned int fileLBA_bigend; + unsigned int fileSize; + unsigned int fileSize_bigend; + unsigned char dateStamp[6]; + unsigned char reserved1; + unsigned char fileProperties; + unsigned char reserved2[6]; + unsigned char filenameLength; + unsigned char filename[128]; +#if defined(__WIN32__) +}; +#else +} __attribute__((packed)); +#endif // This is the internal format on the CD +// TocEntry structure contains only the important stuff needed for export + +#if defined(__WIN32__) +#pragma pack() +#endif + +#endif//__CDVDISO_H__ diff --git a/plugins/CDVDpeops/CDVDisodrv.c b/plugins/CDVDpeops/CDVDisodrv.c index 180f89c189..25ef2edc24 100644 --- a/plugins/CDVDpeops/CDVDisodrv.c +++ b/plugins/CDVDpeops/CDVDisodrv.c @@ -1,264 +1,264 @@ -/* - * Original code from libcdvd by Hiryu & Sjeep (C) 2002 - * Modified by Florin for PCSX2 emu - */ - -#include - -#include "CDVDlib.h" -#include "CDVDiso.h" -#include "CDVDisodrv.h" - -CdRMode cdReadMode; - -struct fdtable{ -//int fd; - int fileSize; - int LBA; - int filePos; -}; - -static struct fdtable fd_table[16]; -static int fd_used[16]; -static int files_open=0; -static int inited=FALSE; - -/************************************************************* -* The functions below are the normal file-system operations, * -* used to provide a standard filesystem interface * -*************************************************************/ - -////////////////////////////////////////////////////////////////////// -// CDVDFS_init -// called by 80000592 sceCdInit() -////////////////////////////////////////////////////////////////////// -void CDVDFS_init(){ - - if (inited) return;//might change in the future as a param; forceInit/Reset - -#ifdef RPC_LOG - RPC_LOG("[CDVDisodrv:init] CDVD Filesystem v1.00\n"); - RPC_LOG("[CDVDisodrv ] \tby A.Lee (aka Hiryu) & Nicholas Van Veen (aka Sjeep)\n"); - RPC_LOG("[CDVDisodrv ] Initializing '%s' file driver.\n", "cdfs"); -#endif - - //CdInit(0); already called by plugin loading system ;) - - cdReadMode.trycount = 0; - cdReadMode.spindlctrl = CdSpinStm; - cdReadMode.datapattern = CdSecS2048; //isofs driver only needs - //2KB sectors - - memset(fd_table, 0, sizeof(fd_table)); - memset(fd_used, 0, 16*sizeof(int)); - - inited = TRUE; - - return; -} - -////////////////////////////////////////////////////////////////////// -// CDVDFS_open -// called by 80000001 fileio_open for devices: "cdrom:", "cdrom0:" -////////////////////////////////////////////////////////////////////// -int CDVDFS_open(char *name, int mode){ - register int j; - static struct TocEntry tocEntry; - - // check if the file exists - if (CDVD_findfile(name, &tocEntry) != TRUE) - return -1; - - if(mode != 1) return -2; //SCE_RDONLY - - // set up a new file descriptor - for(j=0; j < 16; j++) if(fd_used[j] == 0) break; - if(j >= 16) return -3; - - fd_used[j] = 1; - files_open++; - -#ifdef RPC_LOG - RPC_LOG("[CDVDisodrv:open] internal fd=%d\n", j); -#endif - - fd_table[j].fileSize = tocEntry.fileSize; - fd_table[j].LBA = tocEntry.fileLBA; - fd_table[j].filePos = 0; - -#ifdef RPC_LOG - RPC_LOG("[CDVDisodrv ] tocEntry.fileSize = %d\n",tocEntry.fileSize); -#endif - - return j; -} - -////////////////////////////////////////////////////////////////////// -// CDVDFS_lseek -// called by 80000001 fileio_lseek for devices: "cdrom:", "cdrom0:" -////////////////////////////////////////////////////////////////////// -int CDVDFS_lseek(int fd, int offset, int whence){ - - if ((fd >= 16) || (fd_used[fd]==0)){ -#ifdef RPC_LOG - RPC_LOG("[CDVDisodrv:lseek] ERROR: File does not appear to be open!\n"); -#endif - return -1; - } - - switch(whence){ - case SEEK_SET: - fd_table[fd].filePos = offset; - break; - - case SEEK_CUR: - fd_table[fd].filePos += offset; - break; - - case SEEK_END: - fd_table[fd].filePos = fd_table[fd].fileSize + offset; - break; - - default: - return -1; - } - - if (fd_table[fd].filePos < 0) - fd_table[fd].filePos = 0; - - if (fd_table[fd].filePos > fd_table[fd].fileSize) - fd_table[fd].filePos = fd_table[fd].fileSize; - - return fd_table[fd].filePos; -} - -////////////////////////////////////////////////////////////////////// -// CDVDFS_read -// called by 80000001 fileio_read for devices: "cdrom:", "cdrom0:", "cdfs:" -////////////////////////////////////////////////////////////////////// -int CDVDFS_read( int fd, char *buffer, int size ){ -// int start_sector; - int off_sector; -// int num_sectors; - - //static char local_buffer[2024*2048]; //4MB - static char lb[2048]; //2KB - //Start, Aligned, End - int ssector, asector, esector; - int ssize=0, asize, esize; - - if ((fd >= 16) || (fd_used[fd]==0)){ -#ifdef RPC_LOG - RPC_LOG("[CDVDisodrv:read] ERROR: File does not appear to be open!\n"); -#endif - return -1; - } - - // A few sanity checks - if (fd_table[fd].filePos > fd_table[fd].fileSize){ - // We cant start reading from past the beginning of the file - return 0; // File exists but we couldnt read anything from it - } - - if ((fd_table[fd].filePos + size) > fd_table[fd].fileSize) - size = fd_table[fd].fileSize - fd_table[fd].filePos; - - // Now work out where we want to start reading from - asector = ssector = fd_table[fd].LBA + (fd_table[fd].filePos >> 11); - off_sector = (fd_table[fd].filePos & 0x7FF); - if (off_sector){ - ssize = min(2048 - off_sector, size); - size -= ssize; - asector++; - } - asize = size & 0xFFFFF800; - esize = size & 0x000007FF; - esector=asector + (asize >> 11); - size += ssize; - -#ifdef RPC_LOG - RPC_LOG("[CDVDisodrv:read] read sectors 0x%08X to 0x%08X\n", ssector, esector-(esize==0)); -#endif - - if (ssize){ if (CdRead(ssector, 1, lb, &cdReadMode) != TRUE){ -#ifdef RPC_LOG - RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); -#endif - return 0; - } - memcpy(buffer, lb + off_sector, ssize); - } - if (asize) if (CdRead(asector, asize >> 11, buffer+ssize, &cdReadMode) != TRUE){ -#ifdef RPC_LOG - RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); -#endif - return 0; - } - if (esize){ if (CdRead(esector, 1, lb, &cdReadMode) != TRUE){ -#ifdef RPC_LOG - RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); -#endif - return 0; - } - memcpy(buffer+ssize+asize, lb, esize); - } -/*********************** - // Now work out where we want to start reading from - start_sector = fd_table[fd].LBA + (fd_table[fd].filePos >> 11); - off_sector = (fd_table[fd].filePos & 0x7FF); - num_sectors = ((off_sector + size) >> 11) + 1; - -#ifdef RPC_LOG - RPC_LOG("[CDVDisodrv:read] read sectors 0x%08X to 0x%08X\n",start_sector,start_sector+num_sectors); -#endif - - // Read the data (we only ever get 16KB max request at once) - if (CdRead(start_sector, num_sectors, local_buffer, &cdReadMode) != TRUE){ -#ifdef RPC_LOG - //RPC_LOG("sector = %d, start sector = %d\n",sector,start_sector); - RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); -#endif - return 0; - } - //CdSync(0); hm, a wait function maybe... - - memcpy(buffer,local_buffer+off_sector,size); -**************************/ - fd_table[fd].filePos += size; - - return (size); -} - -////////////////////////////////////////////////////////////////////// -// CDVDFS_write -// called by 80000001 fileio_write for devices: "cdrom:", "cdrom0:" -// hehe, this ain't a CD writing option :D -////////////////////////////////////////////////////////////////////// -int CDVDFS_write( int fd, char * buffer, int size ){ - if(size == 0) return 0; - else return -1; -} - -////////////////////////////////////////////////////////////////////// -// CDVDFS_close -// called by 80000001 fileio_close for devices: "cdrom:", "cdrom0:" -////////////////////////////////////////////////////////////////////// -int CDVDFS_close( int fd){ - - if ((fd >= 16) || (fd_used[fd]==0)){ -#ifdef RPC_LOG - RPC_LOG("[CDVDisodrv:close] ERROR: File does not appear to be open!\n"); -#endif - return -1; - } - -#ifdef RPC_LOG - RPC_LOG("[CDVDisodrv:close] internal fd %d\n", fd); -#endif - - fd_used[fd] = 0; - files_open--; - - return 0; -} - +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Modified by Florin for PCSX2 emu + */ + +#include + +#include "CDVDlib.h" +#include "CDVDiso.h" +#include "CDVDisodrv.h" + +CdRMode cdReadMode; + +struct fdtable{ +//int fd; + int fileSize; + int LBA; + int filePos; +}; + +static struct fdtable fd_table[16]; +static int fd_used[16]; +static int files_open=0; +static int inited=FALSE; + +/************************************************************* +* The functions below are the normal file-system operations, * +* used to provide a standard filesystem interface * +*************************************************************/ + +////////////////////////////////////////////////////////////////////// +// CDVDFS_init +// called by 80000592 sceCdInit() +////////////////////////////////////////////////////////////////////// +void CDVDFS_init(){ + + if (inited) return;//might change in the future as a param; forceInit/Reset + +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:init] CDVD Filesystem v1.00\n"); + RPC_LOG("[CDVDisodrv ] \tby A.Lee (aka Hiryu) & Nicholas Van Veen (aka Sjeep)\n"); + RPC_LOG("[CDVDisodrv ] Initializing '%s' file driver.\n", "cdfs"); +#endif + + //CdInit(0); already called by plugin loading system ;) + + cdReadMode.trycount = 0; + cdReadMode.spindlctrl = CdSpinStm; + cdReadMode.datapattern = CdSecS2048; //isofs driver only needs + //2KB sectors + + memset(fd_table, 0, sizeof(fd_table)); + memset(fd_used, 0, 16*sizeof(int)); + + inited = TRUE; + + return; +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_open +// called by 80000001 fileio_open for devices: "cdrom:", "cdrom0:" +////////////////////////////////////////////////////////////////////// +int CDVDFS_open(char *name, int mode){ + register int j; + static struct TocEntry tocEntry; + + // check if the file exists + if (CDVD_findfile(name, &tocEntry) != TRUE) + return -1; + + if(mode != 1) return -2; //SCE_RDONLY + + // set up a new file descriptor + for(j=0; j < 16; j++) if(fd_used[j] == 0) break; + if(j >= 16) return -3; + + fd_used[j] = 1; + files_open++; + +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:open] internal fd=%d\n", j); +#endif + + fd_table[j].fileSize = tocEntry.fileSize; + fd_table[j].LBA = tocEntry.fileLBA; + fd_table[j].filePos = 0; + +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv ] tocEntry.fileSize = %d\n",tocEntry.fileSize); +#endif + + return j; +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_lseek +// called by 80000001 fileio_lseek for devices: "cdrom:", "cdrom0:" +////////////////////////////////////////////////////////////////////// +int CDVDFS_lseek(int fd, int offset, int whence){ + + if ((fd >= 16) || (fd_used[fd]==0)){ +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:lseek] ERROR: File does not appear to be open!\n"); +#endif + return -1; + } + + switch(whence){ + case SEEK_SET: + fd_table[fd].filePos = offset; + break; + + case SEEK_CUR: + fd_table[fd].filePos += offset; + break; + + case SEEK_END: + fd_table[fd].filePos = fd_table[fd].fileSize + offset; + break; + + default: + return -1; + } + + if (fd_table[fd].filePos < 0) + fd_table[fd].filePos = 0; + + if (fd_table[fd].filePos > fd_table[fd].fileSize) + fd_table[fd].filePos = fd_table[fd].fileSize; + + return fd_table[fd].filePos; +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_read +// called by 80000001 fileio_read for devices: "cdrom:", "cdrom0:", "cdfs:" +////////////////////////////////////////////////////////////////////// +int CDVDFS_read( int fd, char *buffer, int size ){ +// int start_sector; + int off_sector; +// int num_sectors; + + //static char local_buffer[2024*2048]; //4MB + static char lb[2048]; //2KB + //Start, Aligned, End + int ssector, asector, esector; + int ssize=0, asize, esize; + + if ((fd >= 16) || (fd_used[fd]==0)){ +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:read] ERROR: File does not appear to be open!\n"); +#endif + return -1; + } + + // A few sanity checks + if (fd_table[fd].filePos > fd_table[fd].fileSize){ + // We cant start reading from past the beginning of the file + return 0; // File exists but we couldnt read anything from it + } + + if ((fd_table[fd].filePos + size) > fd_table[fd].fileSize) + size = fd_table[fd].fileSize - fd_table[fd].filePos; + + // Now work out where we want to start reading from + asector = ssector = fd_table[fd].LBA + (fd_table[fd].filePos >> 11); + off_sector = (fd_table[fd].filePos & 0x7FF); + if (off_sector){ + ssize = min(2048 - off_sector, size); + size -= ssize; + asector++; + } + asize = size & 0xFFFFF800; + esize = size & 0x000007FF; + esector=asector + (asize >> 11); + size += ssize; + +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:read] read sectors 0x%08X to 0x%08X\n", ssector, esector-(esize==0)); +#endif + + if (ssize){ if (CdRead(ssector, 1, lb, &cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); +#endif + return 0; + } + memcpy(buffer, lb + off_sector, ssize); + } + if (asize) if (CdRead(asector, asize >> 11, buffer+ssize, &cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); +#endif + return 0; + } + if (esize){ if (CdRead(esector, 1, lb, &cdReadMode) != TRUE){ +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); +#endif + return 0; + } + memcpy(buffer+ssize+asize, lb, esize); + } +/*********************** + // Now work out where we want to start reading from + start_sector = fd_table[fd].LBA + (fd_table[fd].filePos >> 11); + off_sector = (fd_table[fd].filePos & 0x7FF); + num_sectors = ((off_sector + size) >> 11) + 1; + +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:read] read sectors 0x%08X to 0x%08X\n",start_sector,start_sector+num_sectors); +#endif + + // Read the data (we only ever get 16KB max request at once) + if (CdRead(start_sector, num_sectors, local_buffer, &cdReadMode) != TRUE){ +#ifdef RPC_LOG + //RPC_LOG("sector = %d, start sector = %d\n",sector,start_sector); + RPC_LOG("[CDVDisodrv: ] Couldn't Read from file for some reason\n"); +#endif + return 0; + } + //CdSync(0); hm, a wait function maybe... + + memcpy(buffer,local_buffer+off_sector,size); +**************************/ + fd_table[fd].filePos += size; + + return (size); +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_write +// called by 80000001 fileio_write for devices: "cdrom:", "cdrom0:" +// hehe, this ain't a CD writing option :D +////////////////////////////////////////////////////////////////////// +int CDVDFS_write( int fd, char * buffer, int size ){ + if(size == 0) return 0; + else return -1; +} + +////////////////////////////////////////////////////////////////////// +// CDVDFS_close +// called by 80000001 fileio_close for devices: "cdrom:", "cdrom0:" +////////////////////////////////////////////////////////////////////// +int CDVDFS_close( int fd){ + + if ((fd >= 16) || (fd_used[fd]==0)){ +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:close] ERROR: File does not appear to be open!\n"); +#endif + return -1; + } + +#ifdef RPC_LOG + RPC_LOG("[CDVDisodrv:close] internal fd %d\n", fd); +#endif + + fd_used[fd] = 0; + files_open--; + + return 0; +} + diff --git a/plugins/CDVDpeops/CDVDisodrv.h b/plugins/CDVDpeops/CDVDisodrv.h index dcf8545a86..6cfaa14e0b 100644 --- a/plugins/CDVDpeops/CDVDisodrv.h +++ b/plugins/CDVDpeops/CDVDisodrv.h @@ -1,22 +1,22 @@ -/* - * Original code from libcdvd by Hiryu & Sjeep (C) 2002 - * Modified by Florin for PCSX2 emu - */ - -#ifndef __CDVDISODRV_H__ -#define __CDVDISODRV_H__ - -//#include "Common.h" -#include "CDVDlib.h" - -extern CdRMode cdReadMode; - -/* Filing-system exported functions */ -void CDVDFS_init(); -int CDVDFS_open(char *name, int mode); -int CDVDFS_lseek(int fd, int offset, int whence); -int CDVDFS_read( int fd, char * buffer, int size ); -int CDVDFS_write( int fd, char * buffer, int size ); -int CDVDFS_close( int fd); - -#endif//__CDVDISODRV_H__ +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Modified by Florin for PCSX2 emu + */ + +#ifndef __CDVDISODRV_H__ +#define __CDVDISODRV_H__ + +//#include "Common.h" +#include "CDVDlib.h" + +extern CdRMode cdReadMode; + +/* Filing-system exported functions */ +void CDVDFS_init(); +int CDVDFS_open(char *name, int mode); +int CDVDFS_lseek(int fd, int offset, int whence); +int CDVDFS_read( int fd, char * buffer, int size ); +int CDVDFS_write( int fd, char * buffer, int size ); +int CDVDFS_close( int fd); + +#endif//__CDVDISODRV_H__ diff --git a/plugins/CDVDpeops/CDVDlib.h b/plugins/CDVDpeops/CDVDlib.h index f2c2f87fb8..14d672da1d 100644 --- a/plugins/CDVDpeops/CDVDlib.h +++ b/plugins/CDVDpeops/CDVDlib.h @@ -1,189 +1,189 @@ -/* - * Original code from libcdvd by Hiryu & Sjeep (C) 2002 - * Linux kernel headers - * Modified by Florin for PCSX2 emu - */ - -#ifndef _CDVDLIB_H -#define _CDVDLIB_H - -#define __WIN32__ -#define __MSCW32__ -#define CDVDdefs -#include "PS2Etypes.h" -#include "PS2Edefs.h" - -// Macros for READ Data pattan -#define CdSecS2048 0 // sector size 2048 -#define CdSecS2328 1 // sector size 2328 -#define CdSecS2340 2 // sector size 2340 - -//#define CD_FRAMESIZE_RAW1 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE) /*2340*/ -//#define CD_FRAMESIZE_RAW0 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE-CD_HEAD_SIZE) /*2336*/ -//#define CD_HEAD_SIZE 4 /* header (address) bytes per raw data frame */ -//#define CD_SUBHEAD_SIZE 8 /* subheader bytes per raw XA data frame */ -//#define CD_XA_HEAD (CD_HEAD_SIZE+CD_SUBHEAD_SIZE) /* "before data" part of raw XA frame */ - -/* - * A CD-ROM physical sector size is 2048, 2052, 2056, 2324, 2332, 2336, - * 2340, or 2352 bytes long. - * Sector types of the standard CD-ROM data formats: - * - * format sector type user data size (bytes) - * ----------------------------------------------------------------------------- - * 1 (Red Book) CD-DA 2352 (CD_FRAMESIZE_RAW) - * 2 (Yellow Book) Mode1 Form1 2048 (CD_FRAMESIZE) - * 3 (Yellow Book) Mode1 Form2 2336 (CD_FRAMESIZE_RAW0) - * 4 (Green Book) Mode2 Form1 2048 (CD_FRAMESIZE) - * 5 (Green Book) Mode2 Form2 2328 (2324+4 spare bytes) - * - * - * The layout of the standard CD-ROM data formats: - * ----------------------------------------------------------------------------- - * - audio (red): | audio_sample_bytes | - * | 2352 | - * - * - data (yellow, mode1): | sync - head - data - EDC - zero - ECC | - * | 12 - 4 - 2048 - 4 - 8 - 276 | - * - * - data (yellow, mode2): | sync - head - data | - * | 12 - 4 - 2336 | - * - * - XA data (green, mode2 form1): | sync - head - sub - data - EDC - ECC | - * | 12 - 4 - 8 - 2048 - 4 - 276 | - * - * - XA data (green, mode2 form2): | sync - head - sub - data - Spare | - * | 12 - 4 - 8 - 2324 - 4 | - * - */ - -// Macros for Spindle control -#define CdSpinMax 0 -#define CdSpinNom 1 // Starts reading data at maximum rotational velocity and if a read error occurs, the rotational velocity is reduced. -#define CdSpinStm 0 // Recommended stream rotation speed. - -// Macros for TrayReq -#define CdTrayOpen 0 -#define CdTrayClose 1 -#define CdTrayCheck 2 - -/* - * Macros for sceCdGetDiskType() //comments translated from japanese;) - */ -#define SCECdIllgalMedia 0xff - /* ILIMEDIA (Illegal Media) - A non-PS / non-PS2 Disc. */ -#define SCECdDVDV 0xfe - /* DVDV (DVD Video) - A non-PS / non-PS2 Disc, but a DVD Video Disc */ -#define SCECdCDDA 0xfd - /* CDDA (CD DA) - A non-PS / non-PS2 Disc that include a DA track */ -#define SCECdPS2DVD 0x14 - /* PS2DVD PS2 consumer DVD. */ -#define SCECdPS2CDDA 0x13 - /* PS2CDDA PS2 consumer CD that includes a DA track */ -#define SCECdPS2CD 0x12 - /* PS2CD PS2 consumer CD that does not include a DA track */ -#define SCECdPSCDDA 0x11 - /* PSCDDA PS CD that includes a DA track */ -#define SCECdPSCD 0x10 - /* PSCD PS CD that does not include a DA track */ -#define SCECdDETCT 0x01 - /* DETCT (Detecting) Disc distinction action */ -#define SCECdNODISC 0x00 - /* NODISC (No disc) No disc entered */ - -/* - * Media mode - */ -#define SCECdCD 1 -#define SCECdDVD 2 - -typedef struct { - u8 stat; // 0: normal. Any other: error - u8 second; // second (BCD value) - u8 minute; // minute (BCD value) - u8 hour; // hour (BCD value) - u8 week; // week (BCD value) - u8 day; // day (BCD value) - u8 month; // month (BCD value) - u8 year; // year (BCD value) -} CdCLOCK; - -typedef struct { - u32 lsn; // Logical sector number of file - u32 size; // File size (in bytes) - char name[16]; // Filename - u8 date[8]; // 1th: Seconds - // 2th: Minutes - // 3th: Hours - // 4th: Date - // 5th: Month - // 6th 7th: Year (4 digits) -} CdlFILE; - -typedef struct { - u8 minute; // Minutes - u8 second; // Seconds - u8 sector; // Sector - u8 track; // Track number -} CdlLOCCD; - -typedef struct { - u8 trycount; // Read try count (No. of error retries + 1) (0 - 255) - u8 spindlctrl; // SCECdSpinStm: Recommended stream rotation speed. - // SCECdSpinNom: Starts reading data at maximum rotational velocity and if a read error occurs, the rotational velocity is reduced. - u8 datapattern; // SCECdSecS2048: Data size 2048 bytes - // SCECdSecS2328: 2328 bytes - // SCECdSecS2340: 2340 bytes - u8 pad; // Padding data produced by alignment. -} CdRMode; - -#if defined(__WIN32__) -#pragma pack(1) -#endif - -struct TocEntry -{ - u32 fileLBA; - u32 fileSize; - u8 fileProperties; - u8 padding1[3]; - u8 filename[128+1]; - u8 date[7]; -#if defined(__WIN32__) -}; -#else -} __attribute__((packed)); -#endif - -#if defined(__WIN32__) -#pragma pack() -#endif - -int CDVD_findfile(char* fname, struct TocEntry* tocEntry); -/* -int CdBreak(void); -int CdCallback( void (*func)() ); -int CdDiskReady(int mode); -int CdGetDiskType(void); -int CdGetError(void); -u32 CdGetReadPos(void); -int CdGetToc(u8 *toc); -int CdInit(int init_mode); -CdlLOCCD *CdIntToPos(int i, CdlLOCCD *p); -int CdPause(void); -int CdPosToInt(CdlLOCCD *p);*/ -int CdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode); -int DvdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode); -/*int CdReadClock(CdCLOCK *rtc); -int CdSearchFile (CdlFILE *fp, const char *name); -int CdSeek(u32 lsn); -int CdStandby(void); -int CdStatus(void); -int CdStop(void); -int CdSync(int mode); -int CdTrayReq(int mode, u32 *traycnt); -*/ -#endif // _CDVDLIB_H +/* + * Original code from libcdvd by Hiryu & Sjeep (C) 2002 + * Linux kernel headers + * Modified by Florin for PCSX2 emu + */ + +#ifndef _CDVDLIB_H +#define _CDVDLIB_H + +#define __WIN32__ +#define __MSCW32__ +#define CDVDdefs +#include "PS2Etypes.h" +#include "PS2Edefs.h" + +// Macros for READ Data pattan +#define CdSecS2048 0 // sector size 2048 +#define CdSecS2328 1 // sector size 2328 +#define CdSecS2340 2 // sector size 2340 + +//#define CD_FRAMESIZE_RAW1 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE) /*2340*/ +//#define CD_FRAMESIZE_RAW0 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE-CD_HEAD_SIZE) /*2336*/ +//#define CD_HEAD_SIZE 4 /* header (address) bytes per raw data frame */ +//#define CD_SUBHEAD_SIZE 8 /* subheader bytes per raw XA data frame */ +//#define CD_XA_HEAD (CD_HEAD_SIZE+CD_SUBHEAD_SIZE) /* "before data" part of raw XA frame */ + +/* + * A CD-ROM physical sector size is 2048, 2052, 2056, 2324, 2332, 2336, + * 2340, or 2352 bytes long. + * Sector types of the standard CD-ROM data formats: + * + * format sector type user data size (bytes) + * ----------------------------------------------------------------------------- + * 1 (Red Book) CD-DA 2352 (CD_FRAMESIZE_RAW) + * 2 (Yellow Book) Mode1 Form1 2048 (CD_FRAMESIZE) + * 3 (Yellow Book) Mode1 Form2 2336 (CD_FRAMESIZE_RAW0) + * 4 (Green Book) Mode2 Form1 2048 (CD_FRAMESIZE) + * 5 (Green Book) Mode2 Form2 2328 (2324+4 spare bytes) + * + * + * The layout of the standard CD-ROM data formats: + * ----------------------------------------------------------------------------- + * - audio (red): | audio_sample_bytes | + * | 2352 | + * + * - data (yellow, mode1): | sync - head - data - EDC - zero - ECC | + * | 12 - 4 - 2048 - 4 - 8 - 276 | + * + * - data (yellow, mode2): | sync - head - data | + * | 12 - 4 - 2336 | + * + * - XA data (green, mode2 form1): | sync - head - sub - data - EDC - ECC | + * | 12 - 4 - 8 - 2048 - 4 - 276 | + * + * - XA data (green, mode2 form2): | sync - head - sub - data - Spare | + * | 12 - 4 - 8 - 2324 - 4 | + * + */ + +// Macros for Spindle control +#define CdSpinMax 0 +#define CdSpinNom 1 // Starts reading data at maximum rotational velocity and if a read error occurs, the rotational velocity is reduced. +#define CdSpinStm 0 // Recommended stream rotation speed. + +// Macros for TrayReq +#define CdTrayOpen 0 +#define CdTrayClose 1 +#define CdTrayCheck 2 + +/* + * Macros for sceCdGetDiskType() //comments translated from japanese;) + */ +#define SCECdIllgalMedia 0xff + /* ILIMEDIA (Illegal Media) + A non-PS / non-PS2 Disc. */ +#define SCECdDVDV 0xfe + /* DVDV (DVD Video) + A non-PS / non-PS2 Disc, but a DVD Video Disc */ +#define SCECdCDDA 0xfd + /* CDDA (CD DA) + A non-PS / non-PS2 Disc that include a DA track */ +#define SCECdPS2DVD 0x14 + /* PS2DVD PS2 consumer DVD. */ +#define SCECdPS2CDDA 0x13 + /* PS2CDDA PS2 consumer CD that includes a DA track */ +#define SCECdPS2CD 0x12 + /* PS2CD PS2 consumer CD that does not include a DA track */ +#define SCECdPSCDDA 0x11 + /* PSCDDA PS CD that includes a DA track */ +#define SCECdPSCD 0x10 + /* PSCD PS CD that does not include a DA track */ +#define SCECdDETCT 0x01 + /* DETCT (Detecting) Disc distinction action */ +#define SCECdNODISC 0x00 + /* NODISC (No disc) No disc entered */ + +/* + * Media mode + */ +#define SCECdCD 1 +#define SCECdDVD 2 + +typedef struct { + u8 stat; // 0: normal. Any other: error + u8 second; // second (BCD value) + u8 minute; // minute (BCD value) + u8 hour; // hour (BCD value) + u8 week; // week (BCD value) + u8 day; // day (BCD value) + u8 month; // month (BCD value) + u8 year; // year (BCD value) +} CdCLOCK; + +typedef struct { + u32 lsn; // Logical sector number of file + u32 size; // File size (in bytes) + char name[16]; // Filename + u8 date[8]; // 1th: Seconds + // 2th: Minutes + // 3th: Hours + // 4th: Date + // 5th: Month + // 6th 7th: Year (4 digits) +} CdlFILE; + +typedef struct { + u8 minute; // Minutes + u8 second; // Seconds + u8 sector; // Sector + u8 track; // Track number +} CdlLOCCD; + +typedef struct { + u8 trycount; // Read try count (No. of error retries + 1) (0 - 255) + u8 spindlctrl; // SCECdSpinStm: Recommended stream rotation speed. + // SCECdSpinNom: Starts reading data at maximum rotational velocity and if a read error occurs, the rotational velocity is reduced. + u8 datapattern; // SCECdSecS2048: Data size 2048 bytes + // SCECdSecS2328: 2328 bytes + // SCECdSecS2340: 2340 bytes + u8 pad; // Padding data produced by alignment. +} CdRMode; + +#if defined(__WIN32__) +#pragma pack(1) +#endif + +struct TocEntry +{ + u32 fileLBA; + u32 fileSize; + u8 fileProperties; + u8 padding1[3]; + u8 filename[128+1]; + u8 date[7]; +#if defined(__WIN32__) +}; +#else +} __attribute__((packed)); +#endif + +#if defined(__WIN32__) +#pragma pack() +#endif + +int CDVD_findfile(char* fname, struct TocEntry* tocEntry); +/* +int CdBreak(void); +int CdCallback( void (*func)() ); +int CdDiskReady(int mode); +int CdGetDiskType(void); +int CdGetError(void); +u32 CdGetReadPos(void); +int CdGetToc(u8 *toc); +int CdInit(int init_mode); +CdlLOCCD *CdIntToPos(int i, CdlLOCCD *p); +int CdPause(void); +int CdPosToInt(CdlLOCCD *p);*/ +int CdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode); +int DvdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode); +/*int CdReadClock(CdCLOCK *rtc); +int CdSearchFile (CdlFILE *fp, const char *name); +int CdSeek(u32 lsn); +int CdStandby(void); +int CdStatus(void); +int CdStop(void); +int CdSync(int mode); +int CdTrayReq(int mode, u32 *traycnt); +*/ +#endif // _CDVDLIB_H diff --git a/plugins/CDVDpeops/Cdr.c b/plugins/CDVDpeops/Cdr.c index fd38b659de..9cf269ca72 100644 --- a/plugins/CDVDpeops/Cdr.c +++ b/plugins/CDVDpeops/Cdr.c @@ -1,935 +1,935 @@ -/*************************************************************************** - cdr.c - description - ------------------- - begin : Sun Nov 16 2003 - copyright : (C) 2003 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2004/12/25 - Pete -// - added an hack in CDVDgetTD for big dvds -// -// 2003/11/16 - Pete -// - generic cleanup for the Peops cdvd release -// -//*************************************************************************// - -///////////////////////////////////////////////////////// - -#include "stdafx.h" -#include -#include "resource.h" -#define _IN_CDR -#include "externals.h" -#define CDVDdefs -#include "PS2Etypes.h" -#include "PS2Edefs.h" -#include "libiso.h" - -#ifdef DBGOUT -#define SMALLDEBUG 1 -#include -#endif - -///////////////////////////////////////////////////////// -// PCSX2 CDVD interface: - -EXPORT_GCC char * CALLBACK PS2EgetLibName(); -EXPORT_GCC unsigned long CALLBACK PS2EgetLibType(); -EXPORT_GCC unsigned long CALLBACK PS2EgetLibVersion2(unsigned long type); -EXPORT_GCC long CALLBACK CDVDinit(); -EXPORT_GCC void CALLBACK CDVDshutdown(); -EXPORT_GCC long CALLBACK CDVDopen(const char* pTitle); -EXPORT_GCC void CALLBACK CDVDclose(); -EXPORT_GCC long CALLBACK CDVDtest(); -EXPORT_GCC long CALLBACK CDVDreadTrack(unsigned long lsn, int mode); -EXPORT_GCC unsigned char * CALLBACK CDVDgetBuffer(); -EXPORT_GCC long CALLBACK CDVDgetTN(cdvdTN *Buffer); -EXPORT_GCC long CALLBACK CDVDgetTD(unsigned char track, cdvdTD *Buffer); -EXPORT_GCC long CALLBACK CDVDgetDiskType(); -EXPORT_GCC long CALLBACK CDVDgetTrayStatus(); - -///////////////////////////////////////////////////////// - -const unsigned char version = PS2E_CDVD_VERSION; -const unsigned char revision = 1; -const unsigned char build = 3; - -#ifdef _DEBUG -char *libraryName = "P.E.Op.S. CDVD (Debug, CDDA mod)"; -#else -char *libraryName = "P.E.Op.S. CDVD (CDDA mod)"; -#endif - -///////////////////////////////////////////////////////// - -BOOL bIsOpen=FALSE; // flag: open called once -BOOL bCDDAPlay=FALSE; // flag: audio is playing -int iCDROK=0; // !=0: cd is ok -int iCDType=CDVD_TYPE_UNKNOWN; // CD/DVD -int iCheckTrayStatus=0; // if 0 : report tray as closed, else try a real check -void *fdump; - -///////////////////////////////////////////////////////// -// usual info funcs - -EXPORT_GCC char * CALLBACK PS2EgetLibName() -{ - return libraryName; -} - -EXPORT_GCC unsigned long CALLBACK PS2EgetLibType() -{ - return PS2E_LT_CDVD; -} - -EXPORT_GCC unsigned long CALLBACK PS2EgetLibVersion2(unsigned long type) -{ - return version<<16|revision<<8|build; -} -/* -EXPORT_GCC unsigned long CALLBACK PS2EgetCpuPlatform(void) -{ - return PS2E_X86; -// return PS2E_X86_64; -}*/ - -s32 msf_to_lba(u8 m, u8 s, u8 f) { - u32 lsn; - lsn = f; - lsn+=(s - 2) * 75; - lsn+= m * 75 * 60; - return lsn; -} - -void lba_to_msf(s32 lba, u8* m, u8* s, u8* f) { - lba += 150; - *m = (u8)(lba / (60*75)); - *s = (u8)((lba / 75) % 60); - *f = (u8)(lba % 75); -} - -///////////////////////////////////////////////////////// -// init: called once at library load - -EXPORT_GCC long CALLBACK CDVDinit() -{ - szSUBF[0]=0; // just init the filename buffers - szPPF[0] =0; - return 0; -} - -///////////////////////////////////////////////////////// -// shutdown: called once at final exit - -EXPORT_GCC void CALLBACK CDVDshutdown() -{ -} - -///////////////////////////////////////////////////////// -// open: called, when games starts/cd has been changed - -int CheckDiskType(int baseType); - -EXPORT_GCC long CALLBACK CDVDopen(const char* pTitle) -{ - int i,audioTracks,dataTracks; - cdvdTD T; - if(bIsOpen) // double-open check (if the main emu coder doesn't know what he is doing ;) - { - if(iCDROK<=0) return -1; - else return 0; - } - - bIsOpen=TRUE; // ok, open func called once - - ReadConfig(); // read user config - - BuildPPFCache(); // build ppf cache - - BuildSUBCache(); // build sub cache - - CreateREADBufs(); // setup generic read buffers - - CreateGenEvent(); // create read event - - iCDROK=OpenGenCD(iCD_AD,iCD_TA,iCD_LU); // generic open, setup read func - - if(iCDROK<=0) {iCDROK=0;return -1;} - - ReadTOC(); // read the toc - - SetGenCDSpeed(0); // try to change the reading speed (if wanted) - - iCDType=CDVD_TYPE_UNKNOWN; // let's look after the disc type - // (funny stuff taken from Xobro's/Florin's bin plugin) - if(CDVDreadTrack(16,CDVD_MODE_2048)==0) - { - struct cdVolDesc *volDesc; - volDesc=(struct cdVolDesc *)CDVDgetBuffer(); - if(volDesc) - { - -//todo: CDVD_TYPE_CDDA - - if(volDesc->rootToc.tocSize==2048) - iCDType = CDVD_TYPE_DETCTCD; - else iCDType = CDVD_TYPE_DETCTDVDS; - } - } - - fprintf(stderr," * CDVD Disk Open: %d tracks (%d to %d):\n",sTOC.cLastTrack-sTOC.cFirstTrack+1,sTOC.cFirstTrack,sTOC.cLastTrack); - - audioTracks=dataTracks=0; - for(i=sTOC.cFirstTrack;i<=sTOC.cLastTrack;i++) - { - CDVDgetTD(i,&T); - if(T.type==CDVD_AUDIO_TRACK) { - audioTracks++; - fprintf(stderr," * * Track %d: Audio (%d sectors)\n",i,T.lsn); - } - else { - dataTracks++; - fprintf(stderr," * * Track %d: Data (Mode %d) (%d sectors)\n",i,((T.type==CDVD_MODE1_TRACK)?1:2),T.lsn); - } - } - if((dataTracks==0)&&(audioTracks>0)) - iCDType=CDVD_TYPE_CDDA; - else if(dataTracks>0) - iCDType=CheckDiskType(iCDType); - - if((iCDType==CDVD_TYPE_ILLEGAL)&&(audioTracks>0)) - iCDType=CDVD_TYPE_CDDA; - else if((iCDType==CDVD_TYPE_PS2CD)&&(audioTracks>0)) - iCDType=CDVD_TYPE_PS2CDDA; - else if((iCDType==CDVD_TYPE_PSCD)&&(audioTracks>0)) - iCDType=CDVD_TYPE_PSCDDA; - - switch(iCDType) { - case CDVD_TYPE_ILLEGAL: // Illegal Disc - fprintf(stderr," * Disk Type: Illegal Disk.\n");break; - case CDVD_TYPE_DVDV: // DVD Video - fprintf(stderr," * Disk Type: DVD Video.\n");break; - case CDVD_TYPE_CDDA: // Audio CD - fprintf(stderr," * Disk Type: CDDA.\n");break; - case CDVD_TYPE_PS2DVD: // PS2 DVD - fprintf(stderr," * Disk Type: PS2 DVD.\n");break; - case CDVD_TYPE_PS2CDDA: // PS2 CD (with audio) - fprintf(stderr," * Disk Type: PS2 CD+Audio.\n");break; - case CDVD_TYPE_PS2CD: // PS2 CD - fprintf(stderr," * Disk Type: PS2 CD.\n");break; - case CDVD_TYPE_PSCDDA: // PS CD (with audio) - fprintf(stderr," * Disk Type: PS1 CD+Audio.\n");break; - case CDVD_TYPE_PSCD: // PS CD - fprintf(stderr," * Disk Type: PS1 CD.\n");break; - case CDVD_TYPE_UNKNOWN: // Unknown - fprintf(stderr," * Disk Type: Unknown.\n");break; - case CDVD_TYPE_NODISC: // No Disc - fprintf(stderr," * Disk Type: No Disc.\n");break; - } - -/* if (iBlockDump)*/ { -// fdump = isoCreate("block.dump", ISOFLAGS_BLOCKDUMP); - fdump = NULL; - if (fdump) { - cdvdTD buf; - CDVDgetTD(0, &buf); - isoSetFormat(fdump, 0, 2352, buf.lsn); - } - } /*else { - fdump = NULL; - }*/ - - - return 0; // ok, done -} - -///////////////////////////////////////////////////////// -// close: called when emulation stops - -EXPORT_GCC void CALLBACK CDVDclose() -{ - if(!bIsOpen) return; // no open? no close... - - if (fdump != NULL) { - isoClose(fdump); - } - bIsOpen=FALSE; // no more open - - LockGenCDAccess(); // make sure that no more reading is happening - - if(iCDROK) // cd was ok? - { - if(bCDDAPlay) {DoCDDAPlay(0);bCDDAPlay=FALSE;} // -> cdda playing? stop it - SetGenCDSpeed(1); // -> repair speed - CloseGenCD(); // -> cd not used anymore - } - - UnlockGenCDAccess(); - - FreeREADBufs(); // free read bufs - FreeGenEvent(); // free event - FreePPFCache(); // free ppf cache - FreeSUBCache(); // free sub cache -} - -///////////////////////////////////////////////////////// -// test: ah, well, always fine - -EXPORT_GCC long CALLBACK CDVDtest() -{ - return 0; -} - -///////////////////////////////////////////////////////// -// readSubQ: read subq from disc (only cds have subq data) -EXPORT_GCC long CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq) -{ - u8 min, sec, frm; - - if(!bIsOpen) CDVDopen("DVD"); // usual checks - if(!iCDROK) return -1; - - // fake it - subq->ctrl = 4; - subq->mode = 1; - subq->trackNum = itob(1); - subq->trackIndex= itob(1); - - lba_to_msf(lsn, &min, &sec, &frm); - subq->trackM = itob(min); - subq->trackS = itob(sec); - subq->trackF = itob(frm); - - subq->pad = 0; - - lba_to_msf(lsn + (2*75), &min, &sec, &frm); - subq->discM = itob(min); - subq->discS = itob(sec); - subq->discF = itob(frm); - return 0; -} - -///////////////////////////////////////////////////////// -// gettoc: ps2 style TOC -static int layer1start = -1; -EXPORT_GCC long CALLBACK CDVDgetTOC(void* toc) -{ - u32 type; - u8* tocBuff = (u8*)toc; - - if(!bIsOpen) CDVDopen("DVD"); // not open? funny emu... - - if(!iCDROK) return -1; // cd not ok? - - type = CDVDgetDiskType(); - - if( type == CDVD_TYPE_DVDV || - type == CDVD_TYPE_PS2DVD) - { - u32 lastaddr; - - // get dvd structure format - // scsi command 0x43 - memset(tocBuff, 0, 2048); - - lastaddr = GetLastTrack1Addr(); - if(layer1start > 0 || (layer1start != -2 && lastaddr > 0x280000) ) { - int off = 0; - FRAMEBUF* f = (FRAMEBUF*)malloc(sizeof(FRAMEBUF)); - - f->dwBufLen = iUsedBlockSize; - f->dwFrameCnt = 1; - - - // dual sided - tocBuff[ 0] = 0x24; - tocBuff[ 1] = 0x02; - tocBuff[ 2] = 0xF2; - tocBuff[ 3] = 0x00; - tocBuff[ 4] = 0x41; - tocBuff[ 5] = 0x95; - - tocBuff[14] = 0x60; // dual sided, ptp - - tocBuff[16] = 0x00; - tocBuff[17] = 0x03; - tocBuff[18] = 0x00; - tocBuff[19] = 0x00; - - if( layer1start == -1 ) { - // search for it - printf("PeopsCDVD: searching for layer1... "); - for(layer1start = (lastaddr/2-0x10)&~0xf; layer1start < 0x200010; layer1start += 16) { - f->dwFrame = layer1start; - if( pReadFunc(TRUE,f) != SS_COMP ) { - layer1start = 0x200010; - break; - } - // CD001 - if( f->BufData[off+1] == 0x43 && f->BufData[off+2] == 0x44 && f->BufData[off+3] == 0x30 && f->BufData[off+4] == 0x30 && f->BufData[off+5] == 0x31 ) { - break; - } - } - - if( layer1start >= 0x200010 ) { - printf("Couldn't find second layer on dual layer... ignoring\n"); - // fake it - tocBuff[ 0] = 0x04; - tocBuff[ 1] = 0x02; - tocBuff[ 2] = 0xF2; - tocBuff[ 3] = 0x00; - tocBuff[ 4] = 0x86; - tocBuff[ 5] = 0x72; - - tocBuff[16] = 0x00; - tocBuff[17] = 0x03; - tocBuff[18] = 0x00; - tocBuff[19] = 0x00; - layer1start = -2; - return 0; - } - - printf("found at 0x%8.8x\n", layer1start); - layer1start = layer1start+0x30000-1; - } - - tocBuff[20] = layer1start>>24; - tocBuff[21] = (layer1start>>16)&0xff; - tocBuff[22] = (layer1start>>8)&0xff; - tocBuff[23] = (layer1start>>0)&0xff; - - free(f); - } - else { - // fake it - tocBuff[ 0] = 0x04; - tocBuff[ 1] = 0x02; - tocBuff[ 2] = 0xF2; - tocBuff[ 3] = 0x00; - tocBuff[ 4] = 0x86; - tocBuff[ 5] = 0x72; - - tocBuff[16] = 0x00; - tocBuff[17] = 0x03; - tocBuff[18] = 0x00; - tocBuff[19] = 0x00; - } - } - else if(type == CDVD_TYPE_CDDA || - type == CDVD_TYPE_PS2CDDA || - type == CDVD_TYPE_PS2CD || - type == CDVD_TYPE_PSCDDA || - type == CDVD_TYPE_PSCD) - { - // cd toc - // (could be replaced by 1 command that reads the full toc) - u8 min, sec, frm,i; - s32 err; - cdvdTN diskInfo; - cdvdTD trackInfo; - memset(tocBuff, 0, 1024); - if (CDVDgetTN(&diskInfo) == -1) { diskInfo.etrack = 0;diskInfo.strack = 1; } - if (CDVDgetTD(0, &trackInfo) == -1) trackInfo.lsn = 0; - - tocBuff[0] = 0x41; - tocBuff[1] = 0x00; - - //Number of FirstTrack - tocBuff[2] = 0xA0; - tocBuff[7] = itob(diskInfo.strack); - - //Number of LastTrack - tocBuff[12] = 0xA1; - tocBuff[17] = itob(diskInfo.etrack); - - //DiskLength - lba_to_msf(trackInfo.lsn, &min, &sec, &frm); - tocBuff[22] = 0xA2; - tocBuff[27] = itob(min); - tocBuff[28] = itob(sec); - tocBuff[29] = itob(frm); - - fprintf(stderr,"Track 0: %d mins %d secs %d frames\n",min,sec,frm); - - for (i=diskInfo.strack; i<=diskInfo.etrack; i++) - { - err = CDVDgetTD(i, &trackInfo); - lba_to_msf(trackInfo.lsn, &min, &sec, &frm); - tocBuff[i*10+30] = trackInfo.type; - tocBuff[i*10+32] = err == -1 ? 0 : itob(i); //number - tocBuff[i*10+37] = itob(min); - tocBuff[i*10+38] = itob(sec); - tocBuff[i*10+39] = itob(frm); - fprintf(stderr,"Track %d: %d mins %d secs %d frames\n",i,min,sec,frm); - } - } - else - return -1; - - return 0; -} - -///////////////////////////////////////////////////////// -// gettn: first/last track num - -EXPORT_GCC long CALLBACK CDVDgetTN(cdvdTN *Buffer) -{ - if(!bIsOpen) CDVDopen("DVD"); // not open? funny emu... - - if(!iCDROK) // cd not ok? - { - Buffer->strack=1; - Buffer->etrack=1; - return -1; - } - - ReadTOC(); // read the TOC - - Buffer->strack=sTOC.cFirstTrack; // get the infos - Buffer->etrack=sTOC.cLastTrack; - - return 0; -} - -///////////////////////////////////////////////////////// -// gettd: track addr - -EXPORT_GCC long CALLBACK CDVDgetTD(unsigned char track, cdvdTD *Buffer) -{ - unsigned long lu,i; - unsigned char buffer[2352]; - unsigned char *buf; - u8 t1; - - if(!bIsOpen) CDVDopen("DVD"); // not open? funny emu... - - if(!iCDROK) return -1; // cd not ok? bye - - ReadTOC(); // read toc - -/* -// PSEmu style: - if(track==0) // 0 = last track - { - lu=reOrder(sTOC.tracks[sTOC.cLastTrack].lAddr); - addr2time(lu,buffer); - } - else // others: track n - { - lu=reOrder(sTOC.tracks[track-1].lAddr); - addr2time(lu,buffer); - } - - Buffer->minute = buffer[1]; - Buffer->second = buffer[2]; - Buffer->frame = buffer[3]; - Buffer->type = iCDType; -#ifdef DBGOUT - auxprintf("Read Toc %d: %u\n",track,lu); -#endif -*/ - - lu=0; - if(track==0) - lu=reOrder(sTOC.tracks[sTOC.cLastTrack].lAddr); - else - lu=reOrder(sTOC.tracks[track].lAddr); - //addr2time(lu,buffer); - - Buffer->lsn=lu; - - if(track==0) - Buffer->type = iCDType; - else - { - lu=0; - for(i=sTOC.cFirstTrack;itype=t1; - } - - return 0; -} - -///////////////////////////////////////////////////////// -// readtrack: start reading at given address - -EXPORT_GCC long CALLBACK CDVDreadTrack(unsigned long lsn, int mode) -{ - if(!bIsOpen) CDVDopen("DVD"); // usual checks - if(!iCDROK) return -1; - if(bCDDAPlay) bCDDAPlay=FALSE; - -#ifdef DBGOUT - auxprintf("Read Track %u: %d\n",lsn,mode); -#endif - - lLastAccessedAddr=lsn; // store read track values (for getbuffer) - iLastAccessedMode=mode; - - if(!pReadTrackFunc(lLastAccessedAddr)) // start reading - return -1; - - return 0; -} - -///////////////////////////////////////////////////////// -// getbuffer: will be called after readtrack, to get ptr -// to data - -// small helper buffer to get bigger block sizes -unsigned char cDataAndSub[2368]; - -EXPORT_GCC unsigned char * CALLBACK CDVDgetBuffer() -{ - unsigned char * pbuffer; - - if(!bIsOpen) CDVDopen("DVD"); - - if(pGetPtrFunc) pGetPtrFunc(); // get ptr on thread modes - - pbuffer=pCurrReadBuf; // init buffer pointer - if (fdump != NULL) { - isoWriteBlock(fdump, pbuffer, lLastAccessedAddr); - } - - if(iLastAccessedMode!=iUsedMode) - { - switch(iLastAccessedMode) // what does the emu want? - {//------------------------------------------------// - case CDVD_MODE_2048: - { - if(iUsedBlockSize==2352) pbuffer+=24; - }break; - //------------------------------------------------// - case CDVD_MODE_2352: - { - if(iUsedBlockSize==2048) - { - memset(cDataAndSub,0,2368); - memcpy(cDataAndSub+24,pbuffer,2048); - pbuffer=cDataAndSub; - } - }break; - //------------------------------------------------// - case CDVD_MODE_2340: - { - if(iUsedBlockSize==2048) - { - memset(cDataAndSub,0,2368); - memcpy(cDataAndSub+12,pbuffer,2048); - pbuffer=cDataAndSub; - } - else pbuffer+=12; - }break; - //------------------------------------------------// - case CDVD_MODE_2328: - { - if(iUsedBlockSize==2048) - { - memset(cDataAndSub,0,2368); - memcpy(cDataAndSub+0,pbuffer,2048); - pbuffer=cDataAndSub; - } - else pbuffer+=24; - }break; - //------------------------------------------------// - case CDVD_MODE_2368: - { - if(iUsedBlockSize==2048) - { - memset(cDataAndSub,0,2368); - memcpy(cDataAndSub+24,pbuffer,2048); - pbuffer=cDataAndSub; - -/* -// NO SUBCHANNEL SUPPORT RIGHT NOW!!! - { - if(subHead) // some sub file? - CheckSUBCache(lLastAccessedAddr); // -> get cached subs - else - if(iUseSubReading!=1 && pCurrSubBuf) // no direct cd sub read? - FakeSubData(lLastAccessedAddr); // -> fake the data - memcpy(cDataAndSub,pCurrReadBuf,2352); - if(pCurrSubBuf) - memcpy(cDataAndSub+2352,pCurrSubBuf+12,16); - pbuffer=cDataAndSub; - } -*/ - - } - }break; - //------------------------------------------------// - } - } - -#ifdef DBGOUT - auxprintf("get buf %d\n",iLastAccessedMode); - -/* -{ - int k; - for(k=0;k<2352;k++) - auxprintf("%02x ",*(pbuffer+k)); - auxprintf("\n\n"); -} -*/ -#endif - - return pbuffer; -} - -///////////////////////////////////////////////////////// - -EXPORT_GCC long CALLBACK CDVDgetDiskType() -{ - return iCDType; -} - -///////////////////////////////////////////////////////// -// CDVDgetTrayStatus - -EXPORT_GCC long CALLBACK CDVDgetTrayStatus() -{ - static time_t to=0; - static long lLastTrayState=CDVD_TRAY_CLOSE; - - if(to==time(NULL)) return lLastTrayState; // we only check once per second - to = time(NULL); - - lLastTrayState=CDVD_TRAY_CLOSE; // init state with "closed" - - if(iCheckTrayStatus) // user really want a tray check - { - int iStatus; - - LockGenCDAccess(); // make sure that no more reading is happening - iStatus=GetSCSIStatus(iCD_AD,iCD_TA,iCD_LU); // get device status - UnlockGenCDAccess(); - - if(iStatus==SS_ERR) - lLastTrayState=CDVD_TRAY_OPEN; - } - -#ifdef DBGOUT -auxprintf("check %d -> %d\n",to,lLastTrayState); -#endif - - - return lLastTrayState; -} - -EXPORT_GCC s32 CALLBACK CDVDctrlTrayOpen() { - return 0; -} - -EXPORT_GCC s32 CALLBACK CDVDctrlTrayClose() { - return 0; -} - - - -///////////////////////////////////////////////////////// -// configure: shows config window - -EXPORT_GCC void CALLBACK CDVDconfigure() -{ - if(iCDROK) // mmm... someone has already called Open? bad - {MessageBeep((UINT)-1);return;} - - CreateGenEvent(); // we need an event handle - - DialogBox(hInst,MAKEINTRESOURCE(IDD_CONFIG), // call dialog - GetActiveWindow(),(DLGPROC)CDRDlgProc); - - FreeGenEvent(); // free event handle -} - -///////////////////////////////////////////////////////// -// about: shows about window - -EXPORT_GCC void CALLBACK CDVDabout() -{ - DialogBox(hInst,MAKEINTRESOURCE(IDD_ABOUT), - GetActiveWindow(),(DLGPROC)AboutDlgProc); -} - -///////////////////////////////////////////////////////// -///////////////////////////////////////////////////////// -///////////////////////////////////////////////////////// - -/* -// CURRENTLY UNUSED OLD STUFF FROM PSX CD PLUGIN: - -///////////////////////////////////////////////////////// -// audioplay: PLAYSECTOR is NOT BCD coded !!! - -EXPORT_GCC long CALLBACK CDRplay(unsigned char * sector) -{ - if(!bIsOpen) CDVDopen(); - if(!iCDROK) return PSE_ERR_FATAL; - - if(!DoCDDAPlay(time2addr(sector))) // start playing - return PSE_CDR_ERR_NOREAD; - - bCDDAPlay=TRUE; // raise flag: we are playing - - return PSE_CDR_ERR_SUCCESS; -} - -///////////////////////////////////////////////////////// -// audiostop: stops cdda playing - -EXPORT_GCC long CALLBACK CDRstop(void) -{ - if(!bCDDAPlay) return PSE_ERR_FATAL; - - DoCDDAPlay(0); // stop cdda - - bCDDAPlay=FALSE; // reset flag: no more playing - - return PSE_CDR_ERR_SUCCESS; -} - -///////////////////////////////////////////////////////// -// getdriveletter - -EXPORT_GCC char CALLBACK CDRgetDriveLetter(void) -{ - if(!iCDROK) return 0; // not open? no way to get the letter - - if(iInterfaceMode==2 || iInterfaceMode==3) // w2k/xp: easy - { - return MapIOCTLDriveLetter(iCD_AD,iCD_TA,iCD_LU); - } - else // but with aspi??? - { // -> no idea yet (maybe registry read...pfff) - } - - return 0; -} - -///////////////////////////////////////////////////////// -// getstatus: pcsx func... poorly supported here -// problem is: func will be called often, which -// would block all of my cdr reading if I would use -// lotsa scsi commands - -struct CdrStat -{ - unsigned long Type; - unsigned long Status; - unsigned char Time[3]; // current playing time -}; - -struct CdrStat ostat; - -// reads cdr status -// type: -// 0x00 - unknown -// 0x01 - data -// 0x02 - audio -// 0xff - no cdrom -// status: -// 0x00 - unknown -// 0x02 - error -// 0x08 - seek error -// 0x10 - shell open -// 0x20 - reading -// 0x40 - seeking -// 0x80 - playing -// time: -// byte 0 - minute -// byte 1 - second -// byte 2 - frame - - -EXPORT_GCC long CALLBACK CDRgetStatus(struct CdrStat *stat) -{ - int iStatus; - static time_t to; - - if(!bCDDAPlay) // if not playing update stat only once in a second - { - if(to get pos - stat->Type = 0x02; // -> audio - if(pB) - { - stat->Status|=0x80; // --> playing flag - stat->Time[0]=pB[18]; // --> and curr play time - stat->Time[1]=pB[19]; - stat->Time[2]=pB[20]; - } - } - else // cdda not playing? - { - stat->Type = 0x01; // -> data - } - - LockGenCDAccess(); // make sure that no more reading is happening - iStatus=GetSCSIStatus(iCD_AD,iCD_TA,iCD_LU); // get device status - UnlockGenCDAccess(); - - if(iStatus==SS_ERR) - { // no cdrom? - stat->Type = 0xff; - stat->Status|= 0x10; - } - - memcpy(&ostat, stat, sizeof(struct CdrStat)); - - return 0; -} - -///////////////////////////////////////////////////////// -*/ +/*************************************************************************** + cdr.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/12/25 - Pete +// - added an hack in CDVDgetTD for big dvds +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops cdvd release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#include +#include "resource.h" +#define _IN_CDR +#include "externals.h" +#define CDVDdefs +#include "PS2Etypes.h" +#include "PS2Edefs.h" +#include "libiso.h" + +#ifdef DBGOUT +#define SMALLDEBUG 1 +#include +#endif + +///////////////////////////////////////////////////////// +// PCSX2 CDVD interface: + +EXPORT_GCC char * CALLBACK PS2EgetLibName(); +EXPORT_GCC unsigned long CALLBACK PS2EgetLibType(); +EXPORT_GCC unsigned long CALLBACK PS2EgetLibVersion2(unsigned long type); +EXPORT_GCC long CALLBACK CDVDinit(); +EXPORT_GCC void CALLBACK CDVDshutdown(); +EXPORT_GCC long CALLBACK CDVDopen(const char* pTitle); +EXPORT_GCC void CALLBACK CDVDclose(); +EXPORT_GCC long CALLBACK CDVDtest(); +EXPORT_GCC long CALLBACK CDVDreadTrack(unsigned long lsn, int mode); +EXPORT_GCC unsigned char * CALLBACK CDVDgetBuffer(); +EXPORT_GCC long CALLBACK CDVDgetTN(cdvdTN *Buffer); +EXPORT_GCC long CALLBACK CDVDgetTD(unsigned char track, cdvdTD *Buffer); +EXPORT_GCC long CALLBACK CDVDgetDiskType(); +EXPORT_GCC long CALLBACK CDVDgetTrayStatus(); + +///////////////////////////////////////////////////////// + +const unsigned char version = PS2E_CDVD_VERSION; +const unsigned char revision = 1; +const unsigned char build = 3; + +#ifdef _DEBUG +char *libraryName = "P.E.Op.S. CDVD (Debug, CDDA mod)"; +#else +char *libraryName = "P.E.Op.S. CDVD (CDDA mod)"; +#endif + +///////////////////////////////////////////////////////// + +BOOL bIsOpen=FALSE; // flag: open called once +BOOL bCDDAPlay=FALSE; // flag: audio is playing +int iCDROK=0; // !=0: cd is ok +int iCDType=CDVD_TYPE_UNKNOWN; // CD/DVD +int iCheckTrayStatus=0; // if 0 : report tray as closed, else try a real check +void *fdump; + +///////////////////////////////////////////////////////// +// usual info funcs + +EXPORT_GCC char * CALLBACK PS2EgetLibName() +{ + return libraryName; +} + +EXPORT_GCC unsigned long CALLBACK PS2EgetLibType() +{ + return PS2E_LT_CDVD; +} + +EXPORT_GCC unsigned long CALLBACK PS2EgetLibVersion2(unsigned long type) +{ + return version<<16|revision<<8|build; +} +/* +EXPORT_GCC unsigned long CALLBACK PS2EgetCpuPlatform(void) +{ + return PS2E_X86; +// return PS2E_X86_64; +}*/ + +s32 msf_to_lba(u8 m, u8 s, u8 f) { + u32 lsn; + lsn = f; + lsn+=(s - 2) * 75; + lsn+= m * 75 * 60; + return lsn; +} + +void lba_to_msf(s32 lba, u8* m, u8* s, u8* f) { + lba += 150; + *m = (u8)(lba / (60*75)); + *s = (u8)((lba / 75) % 60); + *f = (u8)(lba % 75); +} + +///////////////////////////////////////////////////////// +// init: called once at library load + +EXPORT_GCC long CALLBACK CDVDinit() +{ + szSUBF[0]=0; // just init the filename buffers + szPPF[0] =0; + return 0; +} + +///////////////////////////////////////////////////////// +// shutdown: called once at final exit + +EXPORT_GCC void CALLBACK CDVDshutdown() +{ +} + +///////////////////////////////////////////////////////// +// open: called, when games starts/cd has been changed + +int CheckDiskType(int baseType); + +EXPORT_GCC long CALLBACK CDVDopen(const char* pTitle) +{ + int i,audioTracks,dataTracks; + cdvdTD T; + if(bIsOpen) // double-open check (if the main emu coder doesn't know what he is doing ;) + { + if(iCDROK<=0) return -1; + else return 0; + } + + bIsOpen=TRUE; // ok, open func called once + + ReadConfig(); // read user config + + BuildPPFCache(); // build ppf cache + + BuildSUBCache(); // build sub cache + + CreateREADBufs(); // setup generic read buffers + + CreateGenEvent(); // create read event + + iCDROK=OpenGenCD(iCD_AD,iCD_TA,iCD_LU); // generic open, setup read func + + if(iCDROK<=0) {iCDROK=0;return -1;} + + ReadTOC(); // read the toc + + SetGenCDSpeed(0); // try to change the reading speed (if wanted) + + iCDType=CDVD_TYPE_UNKNOWN; // let's look after the disc type + // (funny stuff taken from Xobro's/Florin's bin plugin) + if(CDVDreadTrack(16,CDVD_MODE_2048)==0) + { + struct cdVolDesc *volDesc; + volDesc=(struct cdVolDesc *)CDVDgetBuffer(); + if(volDesc) + { + +//todo: CDVD_TYPE_CDDA + + if(volDesc->rootToc.tocSize==2048) + iCDType = CDVD_TYPE_DETCTCD; + else iCDType = CDVD_TYPE_DETCTDVDS; + } + } + + fprintf(stderr," * CDVD Disk Open: %d tracks (%d to %d):\n",sTOC.cLastTrack-sTOC.cFirstTrack+1,sTOC.cFirstTrack,sTOC.cLastTrack); + + audioTracks=dataTracks=0; + for(i=sTOC.cFirstTrack;i<=sTOC.cLastTrack;i++) + { + CDVDgetTD(i,&T); + if(T.type==CDVD_AUDIO_TRACK) { + audioTracks++; + fprintf(stderr," * * Track %d: Audio (%d sectors)\n",i,T.lsn); + } + else { + dataTracks++; + fprintf(stderr," * * Track %d: Data (Mode %d) (%d sectors)\n",i,((T.type==CDVD_MODE1_TRACK)?1:2),T.lsn); + } + } + if((dataTracks==0)&&(audioTracks>0)) + iCDType=CDVD_TYPE_CDDA; + else if(dataTracks>0) + iCDType=CheckDiskType(iCDType); + + if((iCDType==CDVD_TYPE_ILLEGAL)&&(audioTracks>0)) + iCDType=CDVD_TYPE_CDDA; + else if((iCDType==CDVD_TYPE_PS2CD)&&(audioTracks>0)) + iCDType=CDVD_TYPE_PS2CDDA; + else if((iCDType==CDVD_TYPE_PSCD)&&(audioTracks>0)) + iCDType=CDVD_TYPE_PSCDDA; + + switch(iCDType) { + case CDVD_TYPE_ILLEGAL: // Illegal Disc + fprintf(stderr," * Disk Type: Illegal Disk.\n");break; + case CDVD_TYPE_DVDV: // DVD Video + fprintf(stderr," * Disk Type: DVD Video.\n");break; + case CDVD_TYPE_CDDA: // Audio CD + fprintf(stderr," * Disk Type: CDDA.\n");break; + case CDVD_TYPE_PS2DVD: // PS2 DVD + fprintf(stderr," * Disk Type: PS2 DVD.\n");break; + case CDVD_TYPE_PS2CDDA: // PS2 CD (with audio) + fprintf(stderr," * Disk Type: PS2 CD+Audio.\n");break; + case CDVD_TYPE_PS2CD: // PS2 CD + fprintf(stderr," * Disk Type: PS2 CD.\n");break; + case CDVD_TYPE_PSCDDA: // PS CD (with audio) + fprintf(stderr," * Disk Type: PS1 CD+Audio.\n");break; + case CDVD_TYPE_PSCD: // PS CD + fprintf(stderr," * Disk Type: PS1 CD.\n");break; + case CDVD_TYPE_UNKNOWN: // Unknown + fprintf(stderr," * Disk Type: Unknown.\n");break; + case CDVD_TYPE_NODISC: // No Disc + fprintf(stderr," * Disk Type: No Disc.\n");break; + } + +/* if (iBlockDump)*/ { +// fdump = isoCreate("block.dump", ISOFLAGS_BLOCKDUMP); + fdump = NULL; + if (fdump) { + cdvdTD buf; + CDVDgetTD(0, &buf); + isoSetFormat(fdump, 0, 2352, buf.lsn); + } + } /*else { + fdump = NULL; + }*/ + + + return 0; // ok, done +} + +///////////////////////////////////////////////////////// +// close: called when emulation stops + +EXPORT_GCC void CALLBACK CDVDclose() +{ + if(!bIsOpen) return; // no open? no close... + + if (fdump != NULL) { + isoClose(fdump); + } + bIsOpen=FALSE; // no more open + + LockGenCDAccess(); // make sure that no more reading is happening + + if(iCDROK) // cd was ok? + { + if(bCDDAPlay) {DoCDDAPlay(0);bCDDAPlay=FALSE;} // -> cdda playing? stop it + SetGenCDSpeed(1); // -> repair speed + CloseGenCD(); // -> cd not used anymore + } + + UnlockGenCDAccess(); + + FreeREADBufs(); // free read bufs + FreeGenEvent(); // free event + FreePPFCache(); // free ppf cache + FreeSUBCache(); // free sub cache +} + +///////////////////////////////////////////////////////// +// test: ah, well, always fine + +EXPORT_GCC long CALLBACK CDVDtest() +{ + return 0; +} + +///////////////////////////////////////////////////////// +// readSubQ: read subq from disc (only cds have subq data) +EXPORT_GCC long CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq) +{ + u8 min, sec, frm; + + if(!bIsOpen) CDVDopen("DVD"); // usual checks + if(!iCDROK) return -1; + + // fake it + subq->ctrl = 4; + subq->mode = 1; + subq->trackNum = itob(1); + subq->trackIndex= itob(1); + + lba_to_msf(lsn, &min, &sec, &frm); + subq->trackM = itob(min); + subq->trackS = itob(sec); + subq->trackF = itob(frm); + + subq->pad = 0; + + lba_to_msf(lsn + (2*75), &min, &sec, &frm); + subq->discM = itob(min); + subq->discS = itob(sec); + subq->discF = itob(frm); + return 0; +} + +///////////////////////////////////////////////////////// +// gettoc: ps2 style TOC +static int layer1start = -1; +EXPORT_GCC long CALLBACK CDVDgetTOC(void* toc) +{ + u32 type; + u8* tocBuff = (u8*)toc; + + if(!bIsOpen) CDVDopen("DVD"); // not open? funny emu... + + if(!iCDROK) return -1; // cd not ok? + + type = CDVDgetDiskType(); + + if( type == CDVD_TYPE_DVDV || + type == CDVD_TYPE_PS2DVD) + { + u32 lastaddr; + + // get dvd structure format + // scsi command 0x43 + memset(tocBuff, 0, 2048); + + lastaddr = GetLastTrack1Addr(); + if(layer1start > 0 || (layer1start != -2 && lastaddr > 0x280000) ) { + int off = 0; + FRAMEBUF* f = (FRAMEBUF*)malloc(sizeof(FRAMEBUF)); + + f->dwBufLen = iUsedBlockSize; + f->dwFrameCnt = 1; + + + // dual sided + tocBuff[ 0] = 0x24; + tocBuff[ 1] = 0x02; + tocBuff[ 2] = 0xF2; + tocBuff[ 3] = 0x00; + tocBuff[ 4] = 0x41; + tocBuff[ 5] = 0x95; + + tocBuff[14] = 0x60; // dual sided, ptp + + tocBuff[16] = 0x00; + tocBuff[17] = 0x03; + tocBuff[18] = 0x00; + tocBuff[19] = 0x00; + + if( layer1start == -1 ) { + // search for it + printf("PeopsCDVD: searching for layer1... "); + for(layer1start = (lastaddr/2-0x10)&~0xf; layer1start < 0x200010; layer1start += 16) { + f->dwFrame = layer1start; + if( pReadFunc(TRUE,f) != SS_COMP ) { + layer1start = 0x200010; + break; + } + // CD001 + if( f->BufData[off+1] == 0x43 && f->BufData[off+2] == 0x44 && f->BufData[off+3] == 0x30 && f->BufData[off+4] == 0x30 && f->BufData[off+5] == 0x31 ) { + break; + } + } + + if( layer1start >= 0x200010 ) { + printf("Couldn't find second layer on dual layer... ignoring\n"); + // fake it + tocBuff[ 0] = 0x04; + tocBuff[ 1] = 0x02; + tocBuff[ 2] = 0xF2; + tocBuff[ 3] = 0x00; + tocBuff[ 4] = 0x86; + tocBuff[ 5] = 0x72; + + tocBuff[16] = 0x00; + tocBuff[17] = 0x03; + tocBuff[18] = 0x00; + tocBuff[19] = 0x00; + layer1start = -2; + return 0; + } + + printf("found at 0x%8.8x\n", layer1start); + layer1start = layer1start+0x30000-1; + } + + tocBuff[20] = layer1start>>24; + tocBuff[21] = (layer1start>>16)&0xff; + tocBuff[22] = (layer1start>>8)&0xff; + tocBuff[23] = (layer1start>>0)&0xff; + + free(f); + } + else { + // fake it + tocBuff[ 0] = 0x04; + tocBuff[ 1] = 0x02; + tocBuff[ 2] = 0xF2; + tocBuff[ 3] = 0x00; + tocBuff[ 4] = 0x86; + tocBuff[ 5] = 0x72; + + tocBuff[16] = 0x00; + tocBuff[17] = 0x03; + tocBuff[18] = 0x00; + tocBuff[19] = 0x00; + } + } + else if(type == CDVD_TYPE_CDDA || + type == CDVD_TYPE_PS2CDDA || + type == CDVD_TYPE_PS2CD || + type == CDVD_TYPE_PSCDDA || + type == CDVD_TYPE_PSCD) + { + // cd toc + // (could be replaced by 1 command that reads the full toc) + u8 min, sec, frm,i; + s32 err; + cdvdTN diskInfo; + cdvdTD trackInfo; + memset(tocBuff, 0, 1024); + if (CDVDgetTN(&diskInfo) == -1) { diskInfo.etrack = 0;diskInfo.strack = 1; } + if (CDVDgetTD(0, &trackInfo) == -1) trackInfo.lsn = 0; + + tocBuff[0] = 0x41; + tocBuff[1] = 0x00; + + //Number of FirstTrack + tocBuff[2] = 0xA0; + tocBuff[7] = itob(diskInfo.strack); + + //Number of LastTrack + tocBuff[12] = 0xA1; + tocBuff[17] = itob(diskInfo.etrack); + + //DiskLength + lba_to_msf(trackInfo.lsn, &min, &sec, &frm); + tocBuff[22] = 0xA2; + tocBuff[27] = itob(min); + tocBuff[28] = itob(sec); + tocBuff[29] = itob(frm); + + fprintf(stderr,"Track 0: %d mins %d secs %d frames\n",min,sec,frm); + + for (i=diskInfo.strack; i<=diskInfo.etrack; i++) + { + err = CDVDgetTD(i, &trackInfo); + lba_to_msf(trackInfo.lsn, &min, &sec, &frm); + tocBuff[i*10+30] = trackInfo.type; + tocBuff[i*10+32] = err == -1 ? 0 : itob(i); //number + tocBuff[i*10+37] = itob(min); + tocBuff[i*10+38] = itob(sec); + tocBuff[i*10+39] = itob(frm); + fprintf(stderr,"Track %d: %d mins %d secs %d frames\n",i,min,sec,frm); + } + } + else + return -1; + + return 0; +} + +///////////////////////////////////////////////////////// +// gettn: first/last track num + +EXPORT_GCC long CALLBACK CDVDgetTN(cdvdTN *Buffer) +{ + if(!bIsOpen) CDVDopen("DVD"); // not open? funny emu... + + if(!iCDROK) // cd not ok? + { + Buffer->strack=1; + Buffer->etrack=1; + return -1; + } + + ReadTOC(); // read the TOC + + Buffer->strack=sTOC.cFirstTrack; // get the infos + Buffer->etrack=sTOC.cLastTrack; + + return 0; +} + +///////////////////////////////////////////////////////// +// gettd: track addr + +EXPORT_GCC long CALLBACK CDVDgetTD(unsigned char track, cdvdTD *Buffer) +{ + unsigned long lu,i; + unsigned char buffer[2352]; + unsigned char *buf; + u8 t1; + + if(!bIsOpen) CDVDopen("DVD"); // not open? funny emu... + + if(!iCDROK) return -1; // cd not ok? bye + + ReadTOC(); // read toc + +/* +// PSEmu style: + if(track==0) // 0 = last track + { + lu=reOrder(sTOC.tracks[sTOC.cLastTrack].lAddr); + addr2time(lu,buffer); + } + else // others: track n + { + lu=reOrder(sTOC.tracks[track-1].lAddr); + addr2time(lu,buffer); + } + + Buffer->minute = buffer[1]; + Buffer->second = buffer[2]; + Buffer->frame = buffer[3]; + Buffer->type = iCDType; +#ifdef DBGOUT + auxprintf("Read Toc %d: %u\n",track,lu); +#endif +*/ + + lu=0; + if(track==0) + lu=reOrder(sTOC.tracks[sTOC.cLastTrack].lAddr); + else + lu=reOrder(sTOC.tracks[track].lAddr); + //addr2time(lu,buffer); + + Buffer->lsn=lu; + + if(track==0) + Buffer->type = iCDType; + else + { + lu=0; + for(i=sTOC.cFirstTrack;itype=t1; + } + + return 0; +} + +///////////////////////////////////////////////////////// +// readtrack: start reading at given address + +EXPORT_GCC long CALLBACK CDVDreadTrack(unsigned long lsn, int mode) +{ + if(!bIsOpen) CDVDopen("DVD"); // usual checks + if(!iCDROK) return -1; + if(bCDDAPlay) bCDDAPlay=FALSE; + +#ifdef DBGOUT + auxprintf("Read Track %u: %d\n",lsn,mode); +#endif + + lLastAccessedAddr=lsn; // store read track values (for getbuffer) + iLastAccessedMode=mode; + + if(!pReadTrackFunc(lLastAccessedAddr)) // start reading + return -1; + + return 0; +} + +///////////////////////////////////////////////////////// +// getbuffer: will be called after readtrack, to get ptr +// to data + +// small helper buffer to get bigger block sizes +unsigned char cDataAndSub[2368]; + +EXPORT_GCC unsigned char * CALLBACK CDVDgetBuffer() +{ + unsigned char * pbuffer; + + if(!bIsOpen) CDVDopen("DVD"); + + if(pGetPtrFunc) pGetPtrFunc(); // get ptr on thread modes + + pbuffer=pCurrReadBuf; // init buffer pointer + if (fdump != NULL) { + isoWriteBlock(fdump, pbuffer, lLastAccessedAddr); + } + + if(iLastAccessedMode!=iUsedMode) + { + switch(iLastAccessedMode) // what does the emu want? + {//------------------------------------------------// + case CDVD_MODE_2048: + { + if(iUsedBlockSize==2352) pbuffer+=24; + }break; + //------------------------------------------------// + case CDVD_MODE_2352: + { + if(iUsedBlockSize==2048) + { + memset(cDataAndSub,0,2368); + memcpy(cDataAndSub+24,pbuffer,2048); + pbuffer=cDataAndSub; + } + }break; + //------------------------------------------------// + case CDVD_MODE_2340: + { + if(iUsedBlockSize==2048) + { + memset(cDataAndSub,0,2368); + memcpy(cDataAndSub+12,pbuffer,2048); + pbuffer=cDataAndSub; + } + else pbuffer+=12; + }break; + //------------------------------------------------// + case CDVD_MODE_2328: + { + if(iUsedBlockSize==2048) + { + memset(cDataAndSub,0,2368); + memcpy(cDataAndSub+0,pbuffer,2048); + pbuffer=cDataAndSub; + } + else pbuffer+=24; + }break; + //------------------------------------------------// + case CDVD_MODE_2368: + { + if(iUsedBlockSize==2048) + { + memset(cDataAndSub,0,2368); + memcpy(cDataAndSub+24,pbuffer,2048); + pbuffer=cDataAndSub; + +/* +// NO SUBCHANNEL SUPPORT RIGHT NOW!!! + { + if(subHead) // some sub file? + CheckSUBCache(lLastAccessedAddr); // -> get cached subs + else + if(iUseSubReading!=1 && pCurrSubBuf) // no direct cd sub read? + FakeSubData(lLastAccessedAddr); // -> fake the data + memcpy(cDataAndSub,pCurrReadBuf,2352); + if(pCurrSubBuf) + memcpy(cDataAndSub+2352,pCurrSubBuf+12,16); + pbuffer=cDataAndSub; + } +*/ + + } + }break; + //------------------------------------------------// + } + } + +#ifdef DBGOUT + auxprintf("get buf %d\n",iLastAccessedMode); + +/* +{ + int k; + for(k=0;k<2352;k++) + auxprintf("%02x ",*(pbuffer+k)); + auxprintf("\n\n"); +} +*/ +#endif + + return pbuffer; +} + +///////////////////////////////////////////////////////// + +EXPORT_GCC long CALLBACK CDVDgetDiskType() +{ + return iCDType; +} + +///////////////////////////////////////////////////////// +// CDVDgetTrayStatus + +EXPORT_GCC long CALLBACK CDVDgetTrayStatus() +{ + static time_t to=0; + static long lLastTrayState=CDVD_TRAY_CLOSE; + + if(to==time(NULL)) return lLastTrayState; // we only check once per second + to = time(NULL); + + lLastTrayState=CDVD_TRAY_CLOSE; // init state with "closed" + + if(iCheckTrayStatus) // user really want a tray check + { + int iStatus; + + LockGenCDAccess(); // make sure that no more reading is happening + iStatus=GetSCSIStatus(iCD_AD,iCD_TA,iCD_LU); // get device status + UnlockGenCDAccess(); + + if(iStatus==SS_ERR) + lLastTrayState=CDVD_TRAY_OPEN; + } + +#ifdef DBGOUT +auxprintf("check %d -> %d\n",to,lLastTrayState); +#endif + + + return lLastTrayState; +} + +EXPORT_GCC s32 CALLBACK CDVDctrlTrayOpen() { + return 0; +} + +EXPORT_GCC s32 CALLBACK CDVDctrlTrayClose() { + return 0; +} + + + +///////////////////////////////////////////////////////// +// configure: shows config window + +EXPORT_GCC void CALLBACK CDVDconfigure() +{ + if(iCDROK) // mmm... someone has already called Open? bad + {MessageBeep((UINT)-1);return;} + + CreateGenEvent(); // we need an event handle + + DialogBox(hInst,MAKEINTRESOURCE(IDD_CONFIG), // call dialog + GetActiveWindow(),(DLGPROC)CDRDlgProc); + + FreeGenEvent(); // free event handle +} + +///////////////////////////////////////////////////////// +// about: shows about window + +EXPORT_GCC void CALLBACK CDVDabout() +{ + DialogBox(hInst,MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(),(DLGPROC)AboutDlgProc); +} + +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// + +/* +// CURRENTLY UNUSED OLD STUFF FROM PSX CD PLUGIN: + +///////////////////////////////////////////////////////// +// audioplay: PLAYSECTOR is NOT BCD coded !!! + +EXPORT_GCC long CALLBACK CDRplay(unsigned char * sector) +{ + if(!bIsOpen) CDVDopen(); + if(!iCDROK) return PSE_ERR_FATAL; + + if(!DoCDDAPlay(time2addr(sector))) // start playing + return PSE_CDR_ERR_NOREAD; + + bCDDAPlay=TRUE; // raise flag: we are playing + + return PSE_CDR_ERR_SUCCESS; +} + +///////////////////////////////////////////////////////// +// audiostop: stops cdda playing + +EXPORT_GCC long CALLBACK CDRstop(void) +{ + if(!bCDDAPlay) return PSE_ERR_FATAL; + + DoCDDAPlay(0); // stop cdda + + bCDDAPlay=FALSE; // reset flag: no more playing + + return PSE_CDR_ERR_SUCCESS; +} + +///////////////////////////////////////////////////////// +// getdriveletter + +EXPORT_GCC char CALLBACK CDRgetDriveLetter(void) +{ + if(!iCDROK) return 0; // not open? no way to get the letter + + if(iInterfaceMode==2 || iInterfaceMode==3) // w2k/xp: easy + { + return MapIOCTLDriveLetter(iCD_AD,iCD_TA,iCD_LU); + } + else // but with aspi??? + { // -> no idea yet (maybe registry read...pfff) + } + + return 0; +} + +///////////////////////////////////////////////////////// +// getstatus: pcsx func... poorly supported here +// problem is: func will be called often, which +// would block all of my cdr reading if I would use +// lotsa scsi commands + +struct CdrStat +{ + unsigned long Type; + unsigned long Status; + unsigned char Time[3]; // current playing time +}; + +struct CdrStat ostat; + +// reads cdr status +// type: +// 0x00 - unknown +// 0x01 - data +// 0x02 - audio +// 0xff - no cdrom +// status: +// 0x00 - unknown +// 0x02 - error +// 0x08 - seek error +// 0x10 - shell open +// 0x20 - reading +// 0x40 - seeking +// 0x80 - playing +// time: +// byte 0 - minute +// byte 1 - second +// byte 2 - frame + + +EXPORT_GCC long CALLBACK CDRgetStatus(struct CdrStat *stat) +{ + int iStatus; + static time_t to; + + if(!bCDDAPlay) // if not playing update stat only once in a second + { + if(to get pos + stat->Type = 0x02; // -> audio + if(pB) + { + stat->Status|=0x80; // --> playing flag + stat->Time[0]=pB[18]; // --> and curr play time + stat->Time[1]=pB[19]; + stat->Time[2]=pB[20]; + } + } + else // cdda not playing? + { + stat->Type = 0x01; // -> data + } + + LockGenCDAccess(); // make sure that no more reading is happening + iStatus=GetSCSIStatus(iCD_AD,iCD_TA,iCD_LU); // get device status + UnlockGenCDAccess(); + + if(iStatus==SS_ERR) + { // no cdrom? + stat->Type = 0xff; + stat->Status|= 0x10; + } + + memcpy(&ostat, stat, sizeof(struct CdrStat)); + + return 0; +} + +///////////////////////////////////////////////////////// +*/ diff --git a/plugins/CDVDpeops/Cfg.c b/plugins/CDVDpeops/Cfg.c index c7ac3bca0f..6afa604f8a 100644 --- a/plugins/CDVDpeops/Cfg.c +++ b/plugins/CDVDpeops/Cfg.c @@ -1,527 +1,527 @@ -/*************************************************************************** - cfg.c - description - ------------------- - begin : Sun Nov 16 2003 - copyright : (C) 2003 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2003/11/16 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -//////////////////////////////////////////////////////////////////////// - -#include "stdafx.h" -#include "resource.h" -#define _IN_CFG -#include "externals.h" - -//////////////////////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////////////////////////// -// read config from registry - -void ReadConfig(void) -{ - HKEY myKey;DWORD temp,type,size; - - // init values - - iCD_AD=-1; - iCD_TA=-1; - iCD_LU=-1; - iRType=0; - iUseSpeedLimit=0; - iSpeedLimit=2; - iNoWait=0; - iMaxRetry=5; - iShowReadErr=0; - iUsePPF=0; - iUseSubReading=0; - iUseDataCache=0; - iCheckTrayStatus=0; - memset(szPPF,0,260); - memset(szSUBF,0,260); - - // read values - - if (RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\PS2Eplugin\\CDVD\\CDVDPeops",0,KEY_ALL_ACCESS,&myKey)==ERROR_SUCCESS) - { - size = 4; - if(RegQueryValueEx(myKey,"Adapter",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iCD_AD=(int)temp; - size = 4; - if(RegQueryValueEx(myKey,"Target",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iCD_TA=(int)temp; - size = 4; - if(RegQueryValueEx(myKey,"LUN",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iCD_LU=(int)temp; - size = 4; - if(RegQueryValueEx(myKey,"UseCaching",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iUseCaching=(int)temp; - size = 4; - if(RegQueryValueEx(myKey,"UseDataCache",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iUseDataCache=(int)temp; - size = 4; - if(RegQueryValueEx(myKey,"UseSpeedLimit",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iUseSpeedLimit=(int)temp; - size = 4; - if(RegQueryValueEx(myKey,"SpeedLimit",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iSpeedLimit=(int)temp; - size = 4; - if(RegQueryValueEx(myKey,"NoWait",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iNoWait=(int)temp; - size = 4; - if(RegQueryValueEx(myKey,"CheckTrayStatus",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iCheckTrayStatus=(int)temp; - size = 4; - if(RegQueryValueEx(myKey,"MaxRetry",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iMaxRetry=(int)temp; - size = 4; - if(RegQueryValueEx(myKey,"ShowReadErr",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iShowReadErr=(int)temp; - size = 4; - if(RegQueryValueEx(myKey,"UsePPF",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iUsePPF=(int)temp; - size = 4; - if(RegQueryValueEx(myKey,"UseSubReading",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iUseSubReading=(int)temp; - size=259; - RegQueryValueEx(myKey,"PPFFile",0,&type,(LPBYTE)szPPF,&size); - size=259; - RegQueryValueEx(myKey,"SCFile",0,&type,(LPBYTE)szSUBF,&size); - - RegCloseKey(myKey); - } - - // disabled for now - iUsePPF=0; -} - -//////////////////////////////////////////////////////////////////////// -// write user config - -void WriteConfig(void) -{ - HKEY myKey;DWORD myDisp,temp; - - RegCreateKeyEx(HKEY_CURRENT_USER,"Software\\PS2Eplugin\\CDVD\\CDVDPeops",0,NULL,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&myKey,&myDisp); - temp=iInterfaceMode; - RegSetValueEx(myKey,"InterfaceMode",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - temp=iCD_AD; - RegSetValueEx(myKey,"Adapter",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - temp=iCD_TA; - RegSetValueEx(myKey,"Target",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - temp=iCD_LU; - RegSetValueEx(myKey,"LUN",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - temp=iUseCaching; - RegSetValueEx(myKey,"UseCaching",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - temp=iUseDataCache; - RegSetValueEx(myKey,"UseDataCache",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - temp=iUseSpeedLimit; - RegSetValueEx(myKey,"UseSpeedLimit",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - temp=iSpeedLimit; - RegSetValueEx(myKey,"SpeedLimit",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - temp=iNoWait; - RegSetValueEx(myKey,"NoWait",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - temp=iCheckTrayStatus ; - RegSetValueEx(myKey,"CheckTrayStatus",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - temp=iMaxRetry; - RegSetValueEx(myKey,"MaxRetry",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - temp=iShowReadErr; - RegSetValueEx(myKey,"ShowReadErr",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - temp=iUsePPF; - RegSetValueEx(myKey,"UsePPF",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - temp=iUseSubReading; - RegSetValueEx(myKey,"UseSubReading",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - - RegSetValueEx(myKey,"PPFFile",0,REG_BINARY,(LPBYTE)szPPF,259); - RegSetValueEx(myKey,"SCFile",0,REG_BINARY,(LPBYTE)szSUBF,259); - - RegCloseKey(myKey); -} - -//////////////////////////////////////////////////////////////////////// -// choose ppf/sbi/m3s file name - -void OnChooseFile(HWND hW,int iFType) -{ - OPENFILENAME ofn;char szB[260];BOOL b; - - ofn.lStructSize=sizeof(OPENFILENAME); - ofn.hwndOwner=hW; - ofn.hInstance=NULL; - if(iFType==0) ofn.lpstrFilter="PPF Files\0*.PPF\0\0\0"; - else if(iFType==1) ofn.lpstrFilter="SBI Files\0*.SBI\0M3S Files\0*.M3S\0\0\0"; - else if(iFType==2) ofn.lpstrFilter="SUB Files\0*.SUB\0\0\0"; - else if(iFType==3) ofn.lpstrFilter="SBI Files\0*.SBI\0\0\0"; - else ofn.lpstrFilter="M3S Files\0*.M3S\0\0\0"; - - ofn.lpstrCustomFilter=NULL; - ofn.nMaxCustFilter=0; - ofn.nFilterIndex=0; - if(iFType==0) GetDlgItemText(hW,IDC_PPFFILE,szB,259); - else if(iFType==1) GetDlgItemText(hW,IDC_SUBFILE,szB,259); - else if(iFType==2) GetDlgItemText(hW,IDC_SUBFILEEDIT,szB,259); - else if(iFType==3) GetDlgItemText(hW,IDC_OUTFILEEDIT,szB,259); - else GetDlgItemText(hW,IDC_OUTFILEEDIT,szB,259); - - ofn.lpstrFile=szB; - ofn.nMaxFile=259; - ofn.lpstrFileTitle=NULL; - ofn.nMaxFileTitle=0; - ofn.lpstrInitialDir=NULL; - ofn.lpstrTitle=NULL; - if(iFType<3) - ofn.Flags=OFN_FILEMUSTEXIST|OFN_NOCHANGEDIR|OFN_HIDEREADONLY; - else - ofn.Flags=OFN_CREATEPROMPT|OFN_NOCHANGEDIR|OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT; - ofn.nFileOffset=0; - ofn.nFileExtension=0; - ofn.lpstrDefExt=0; - ofn.lCustData=0; - ofn.lpfnHook=NULL; - ofn.lpTemplateName=NULL; - - if(iFType<3) - b=GetOpenFileName(&ofn); - else b=GetSaveFileName(&ofn); - - if(b) - { - if(iFType==0) SetDlgItemText(hW,IDC_PPFFILE,szB); - else if(iFType==1) SetDlgItemText(hW,IDC_SUBFILE,szB); - else if(iFType==2) SetDlgItemText(hW,IDC_SUBFILEEDIT,szB); - else if(iFType==3) SetDlgItemText(hW,IDC_OUTFILEEDIT,szB); - else SetDlgItemText(hW,IDC_OUTFILEEDIT,szB); - } -} - -//////////////////////////////////////////////////////////////////////// -// file drive combo - -void EnumDrives(HWND hW) -{ - HWND hWC;char szB[256];int i=0,k=0,iNum; - char * p, * pBuf, * pN; - - hWC=GetDlgItem(hW,IDC_DRIVE); - ComboBox_ResetContent(hWC); - ComboBox_AddString(hWC,"NONE"); // add always existing 'none' - - wsprintf(szB,"[%d:%d:%d",iCD_AD,iCD_TA,iCD_LU); // make current user info text - - pN=pBuf=(char *)malloc(32768); - memset(pBuf,0,32768); - iNum=GetGenCDDrives(pBuf); // get the system cd drives list - - for(i=0;i add drive name - p=strchr(pN,']'); - if(p) - { - *p=0; - if(strcmp(szB,pN)==0) k=i+1; // -> is it the current user drive? sel it - *p=']'; - } - pN+=strlen(pN)+1; // next drive in buffer - } - - free(pBuf); - - ComboBox_SetCurSel(hWC,k); // do the drive sel -} - -//////////////////////////////////////////////////////////////////////// -// get curr selected drive - -void GetCDRInfos(HWND hW,int * iA, int * iT,int * iL) -{ - HWND hWC=GetDlgItem(hW,IDC_DRIVE); - char szB[256];int i;char * p; - - i=ComboBox_GetCurSel(hWC); - if(i<=0) // none selected - { - *iA=-1;*iT=-1;*iL=-1; - MessageBox(hW,"Please select a cdrom drive!","Config error",MB_OK|MB_ICONINFORMATION); - return; - } - - ComboBox_GetLBText(hWC,i,szB); // get cd text - p=szB+1; - *iA=atoi(p); // get AD,TA,LU - p=strchr(szB,':')+1; - *iT=atoi(p); - p=strchr(p,':')+1; - *iL=atoi(p); -} - -//////////////////////////////////////////////////////////////////////// -// interface mode has changed - -void OnIMode(HWND hW) -{ - HWND hWC=GetDlgItem(hW,IDC_IMODE); - int iM = ComboBox_GetCurSel(hWC); - - GetCDRInfos(hW,&iCD_AD,&iCD_TA,&iCD_LU); // get sel drive - CloseGenInterface(); // close current interface - iInterfaceMode=iM; // set new interface mode - OpenGenInterface(); // open new interface - ComboBox_SetCurSel(hWC,iInterfaceMode); // sel interface again (maybe it was not supported on open) - EnumDrives(hW); // enum drives again -} - -//////////////////////////////////////////////////////////////////////// -// cache mode has changed - -void OnCache(HWND hW) -{ - HWND hWC=GetDlgItem(hW,IDC_CACHE); - if(ComboBox_GetCurSel(hWC)<=0) - ShowWindow(GetDlgItem(hW,IDC_DATACACHE),SW_HIDE); - else ShowWindow(GetDlgItem(hW,IDC_DATACACHE),SW_SHOW); -} - -//////////////////////////////////////////////////////////////////////// -// show/hide files depending on subc mode - -void ShowSubFileStuff(HWND hW) -{ - HWND hWC=GetDlgItem(hW,IDC_SUBCHAN0); - int iShow,iSel=ComboBox_GetCurSel(hWC); - - if(iSel==2) iShow=SW_SHOW; - else iShow=SW_HIDE; - - ShowWindow(GetDlgItem(hW,IDC_SFSTATIC),iShow); - ShowWindow(GetDlgItem(hW,IDC_SUBFILE),iShow); - ShowWindow(GetDlgItem(hW,IDC_CHOOSESUBF),iShow); - - if(iSel==1) - { - ComboBox_SetCurSel(GetDlgItem(hW,IDC_CACHE),0); - ShowWindow(GetDlgItem(hW,IDC_DATACACHE),SW_HIDE); - } -} - -//////////////////////////////////////////////////////////////////////// -// init dialog - -BOOL OnInitCDRDialog(HWND hW) -{ - HWND hWC;int i=0; - - ReadConfig(); // read config - - hWC=GetDlgItem(hW,IDC_IMODE); // interface - ComboBox_AddString(hWC,"NONE"); - ComboBox_AddString(hWC,"W9X/ME - ASPI scsi commands"); - ComboBox_AddString(hWC,"W2K/XP - IOCTL scsi commands"); - -// not supported with my dvd drive - DISABLED! -// ComboBox_AddString(hWC,"W2K/XP - IOCTL raw reading"); - - ComboBox_SetCurSel(hWC,iInterfaceMode); - - EnumDrives(hW); // enum drives - - hWC=GetDlgItem(hW,IDC_CACHE); // caching - ComboBox_AddString(hWC,"None - reads one sector"); - ComboBox_AddString(hWC,"Read ahead - fast, reads more sectors at once"); - ComboBox_AddString(hWC,"Async read - faster, additional asynchronous reads"); - ComboBox_AddString(hWC,"Thread read - fast with IOCTL, always async reads"); - ComboBox_AddString(hWC,"Smooth read - for drives with ps2 cd/dvd reading troubles"); - ComboBox_SetCurSel(hWC,iUseCaching); - - if(iUseDataCache) - CheckDlgButton(hW,IDC_DATACACHE,TRUE); - if(!iUseCaching) - ShowWindow(GetDlgItem(hW,IDC_DATACACHE),SW_HIDE); - - if(iUseSpeedLimit) // speed limit - CheckDlgButton(hW,IDC_SPEEDLIMIT,TRUE); - - if(iNoWait) // wait for drive - CheckDlgButton(hW,IDC_NOWAIT,TRUE); - - if(iCheckTrayStatus) // tray status - CheckDlgButton(hW,IDC_TRAYSTATE,TRUE); - - SetDlgItemInt(hW,IDC_RETRY,iMaxRetry,FALSE); // retry on error - if(iMaxRetry) CheckDlgButton(hW,IDC_TRYAGAIN,TRUE); - if(iShowReadErr) CheckDlgButton(hW,IDC_SHOWREADERR,TRUE); - - hWC=GetDlgItem(hW,IDC_SUBCHAN0); // subchannel mode - ComboBox_AddString(hWC,"Don't read subchannels"); - ComboBox_AddString(hWC,"Read subchannels (slow, few drives support it, best chances with BE mode)"); - ComboBox_AddString(hWC,"Use subchannel SBI/M3S info file (recommended)"); - ComboBox_SetCurSel(hWC,iUseSubReading); - - ShowSubFileStuff(hW); // show/hide subc controls - - hWC=GetDlgItem(hW,IDC_SPEED); // speed limit - ComboBox_AddString(hWC,"2 X"); - ComboBox_AddString(hWC,"4 X"); - ComboBox_AddString(hWC,"8 X"); - ComboBox_AddString(hWC,"16 X"); - - i=0; - if(iSpeedLimit==4) i=1; - if(iSpeedLimit==8) i=2; - if(iSpeedLimit==16) i=3; - - ComboBox_SetCurSel(hWC,i); - - if(iUsePPF) CheckDlgButton(hW,IDC_USEPPF,TRUE); // ppf - SetDlgItemText(hW,IDC_PPFFILE,szPPF); - SetDlgItemText(hW,IDC_SUBFILE,szSUBF); - - return TRUE; -} - -//////////////////////////////////////////////////////////////////////// - -void OnCDROK(HWND hW) -{ - int iA,iT,iL,iR; - HWND hWC=GetDlgItem(hW,IDC_RTYPE); - - GetCDRInfos(hW,&iA,&iT,&iL); - if(iA==-1) return; - - hWC=GetDlgItem(hW,IDC_CACHE); - iUseCaching=ComboBox_GetCurSel(hWC); - if(iUseCaching<0) iUseCaching=0; - if(iUseCaching>4) iUseCaching=4; - - iCD_AD=iA;iCD_TA=iT;iCD_LU=iL; - - if(IsDlgButtonChecked(hW,IDC_SPEEDLIMIT)) - iUseSpeedLimit=1; - else iUseSpeedLimit=0; - - iUseSubReading=0; - hWC=GetDlgItem(hW,IDC_SUBCHAN0); - iUseSubReading=ComboBox_GetCurSel(hWC); - if(iUseSubReading<0) iUseSubReading=0; - if(iUseSubReading>2) iUseSubReading=2; - if(iUseSubReading==1) iUseCaching=0; - - if(IsDlgButtonChecked(hW,IDC_DATACACHE)) - iUseDataCache=1; - else iUseDataCache=0; - if(iUseCaching==0) iUseDataCache=0; - - if(IsDlgButtonChecked(hW,IDC_NOWAIT)) - iNoWait=1; - else iNoWait=0; - - if(IsDlgButtonChecked(hW,IDC_TRAYSTATE)) - iCheckTrayStatus=1; - else iCheckTrayStatus=0; - - iMaxRetry=GetDlgItemInt(hW,IDC_RETRY,NULL,FALSE); - if(iMaxRetry<1) iMaxRetry=1; - if(iMaxRetry>10) iMaxRetry=10; - if(!IsDlgButtonChecked(hW,IDC_TRYAGAIN)) iMaxRetry=0; - - if(IsDlgButtonChecked(hW,IDC_SHOWREADERR)) - iShowReadErr=1; - else iShowReadErr=0; - - hWC=GetDlgItem(hW,IDC_SPEED); - iR=ComboBox_GetCurSel(hWC); - - iSpeedLimit=2; - if(iR==1) iSpeedLimit=4; - if(iR==2) iSpeedLimit=8; - if(iR==3) iSpeedLimit=16; - - if(IsDlgButtonChecked(hW,IDC_USEPPF)) - iUsePPF=1; - else iUsePPF=0; - - GetDlgItemText(hW,IDC_PPFFILE,szPPF,259); - GetDlgItemText(hW,IDC_SUBFILE,szSUBF,259); - - WriteConfig(); // write registry - - EndDialog(hW,TRUE); -} - -//////////////////////////////////////////////////////////////////////// - -void OnCDRCancel(HWND hW) -{ - EndDialog(hW,FALSE); -} - -//////////////////////////////////////////////////////////////////////// - -BOOL CALLBACK CDRDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch(uMsg) - { - case WM_INITDIALOG: - return OnInitCDRDialog(hW); - - case WM_COMMAND: - { - switch(LOWORD(wParam)) - { - case IDC_SUBCHAN0: if(HIWORD(wParam)==CBN_SELCHANGE) - {ShowSubFileStuff(hW);return TRUE;} - case IDC_IMODE: if(HIWORD(wParam)==CBN_SELCHANGE) - {OnIMode(hW);return TRUE;} - break; - case IDC_CACHE: if(HIWORD(wParam)==CBN_SELCHANGE) - {OnCache(hW);return TRUE;} - break; - case IDCANCEL: OnCDRCancel(hW); return TRUE; - case IDOK: OnCDROK(hW); return TRUE; - case IDC_CHOOSEFILE: OnChooseFile(hW,0);return TRUE; - case IDC_CHOOSESUBF: OnChooseFile(hW,1);return TRUE; - } - } - } - return FALSE; -} - -//////////////////////////////////////////////////////////////////////// - -BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch(uMsg) - { - case WM_COMMAND: - { - switch(LOWORD(wParam)) - { - case IDCANCEL: EndDialog(hW,FALSE);return TRUE; - case IDOK: EndDialog(hW,FALSE);return TRUE; - } - } - } - return FALSE; -} - -//////////////////////////////////////////////////////////////////////// - +/*************************************************************************** + cfg.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +//////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "resource.h" +#define _IN_CFG +#include "externals.h" + +//////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// +// read config from registry + +void ReadConfig(void) +{ + HKEY myKey;DWORD temp,type,size; + + // init values + + iCD_AD=-1; + iCD_TA=-1; + iCD_LU=-1; + iRType=0; + iUseSpeedLimit=0; + iSpeedLimit=2; + iNoWait=0; + iMaxRetry=5; + iShowReadErr=0; + iUsePPF=0; + iUseSubReading=0; + iUseDataCache=0; + iCheckTrayStatus=0; + memset(szPPF,0,260); + memset(szSUBF,0,260); + + // read values + + if (RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\PS2Eplugin\\CDVD\\CDVDPeops",0,KEY_ALL_ACCESS,&myKey)==ERROR_SUCCESS) + { + size = 4; + if(RegQueryValueEx(myKey,"Adapter",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iCD_AD=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"Target",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iCD_TA=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"LUN",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iCD_LU=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"UseCaching",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iUseCaching=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"UseDataCache",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iUseDataCache=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"UseSpeedLimit",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iUseSpeedLimit=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"SpeedLimit",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iSpeedLimit=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"NoWait",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iNoWait=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"CheckTrayStatus",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iCheckTrayStatus=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"MaxRetry",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iMaxRetry=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"ShowReadErr",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iShowReadErr=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"UsePPF",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iUsePPF=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"UseSubReading",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iUseSubReading=(int)temp; + size=259; + RegQueryValueEx(myKey,"PPFFile",0,&type,(LPBYTE)szPPF,&size); + size=259; + RegQueryValueEx(myKey,"SCFile",0,&type,(LPBYTE)szSUBF,&size); + + RegCloseKey(myKey); + } + + // disabled for now + iUsePPF=0; +} + +//////////////////////////////////////////////////////////////////////// +// write user config + +void WriteConfig(void) +{ + HKEY myKey;DWORD myDisp,temp; + + RegCreateKeyEx(HKEY_CURRENT_USER,"Software\\PS2Eplugin\\CDVD\\CDVDPeops",0,NULL,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&myKey,&myDisp); + temp=iInterfaceMode; + RegSetValueEx(myKey,"InterfaceMode",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iCD_AD; + RegSetValueEx(myKey,"Adapter",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iCD_TA; + RegSetValueEx(myKey,"Target",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iCD_LU; + RegSetValueEx(myKey,"LUN",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iUseCaching; + RegSetValueEx(myKey,"UseCaching",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iUseDataCache; + RegSetValueEx(myKey,"UseDataCache",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iUseSpeedLimit; + RegSetValueEx(myKey,"UseSpeedLimit",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iSpeedLimit; + RegSetValueEx(myKey,"SpeedLimit",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iNoWait; + RegSetValueEx(myKey,"NoWait",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iCheckTrayStatus ; + RegSetValueEx(myKey,"CheckTrayStatus",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iMaxRetry; + RegSetValueEx(myKey,"MaxRetry",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iShowReadErr; + RegSetValueEx(myKey,"ShowReadErr",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iUsePPF; + RegSetValueEx(myKey,"UsePPF",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iUseSubReading; + RegSetValueEx(myKey,"UseSubReading",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + + RegSetValueEx(myKey,"PPFFile",0,REG_BINARY,(LPBYTE)szPPF,259); + RegSetValueEx(myKey,"SCFile",0,REG_BINARY,(LPBYTE)szSUBF,259); + + RegCloseKey(myKey); +} + +//////////////////////////////////////////////////////////////////////// +// choose ppf/sbi/m3s file name + +void OnChooseFile(HWND hW,int iFType) +{ + OPENFILENAME ofn;char szB[260];BOOL b; + + ofn.lStructSize=sizeof(OPENFILENAME); + ofn.hwndOwner=hW; + ofn.hInstance=NULL; + if(iFType==0) ofn.lpstrFilter="PPF Files\0*.PPF\0\0\0"; + else if(iFType==1) ofn.lpstrFilter="SBI Files\0*.SBI\0M3S Files\0*.M3S\0\0\0"; + else if(iFType==2) ofn.lpstrFilter="SUB Files\0*.SUB\0\0\0"; + else if(iFType==3) ofn.lpstrFilter="SBI Files\0*.SBI\0\0\0"; + else ofn.lpstrFilter="M3S Files\0*.M3S\0\0\0"; + + ofn.lpstrCustomFilter=NULL; + ofn.nMaxCustFilter=0; + ofn.nFilterIndex=0; + if(iFType==0) GetDlgItemText(hW,IDC_PPFFILE,szB,259); + else if(iFType==1) GetDlgItemText(hW,IDC_SUBFILE,szB,259); + else if(iFType==2) GetDlgItemText(hW,IDC_SUBFILEEDIT,szB,259); + else if(iFType==3) GetDlgItemText(hW,IDC_OUTFILEEDIT,szB,259); + else GetDlgItemText(hW,IDC_OUTFILEEDIT,szB,259); + + ofn.lpstrFile=szB; + ofn.nMaxFile=259; + ofn.lpstrFileTitle=NULL; + ofn.nMaxFileTitle=0; + ofn.lpstrInitialDir=NULL; + ofn.lpstrTitle=NULL; + if(iFType<3) + ofn.Flags=OFN_FILEMUSTEXIST|OFN_NOCHANGEDIR|OFN_HIDEREADONLY; + else + ofn.Flags=OFN_CREATEPROMPT|OFN_NOCHANGEDIR|OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT; + ofn.nFileOffset=0; + ofn.nFileExtension=0; + ofn.lpstrDefExt=0; + ofn.lCustData=0; + ofn.lpfnHook=NULL; + ofn.lpTemplateName=NULL; + + if(iFType<3) + b=GetOpenFileName(&ofn); + else b=GetSaveFileName(&ofn); + + if(b) + { + if(iFType==0) SetDlgItemText(hW,IDC_PPFFILE,szB); + else if(iFType==1) SetDlgItemText(hW,IDC_SUBFILE,szB); + else if(iFType==2) SetDlgItemText(hW,IDC_SUBFILEEDIT,szB); + else if(iFType==3) SetDlgItemText(hW,IDC_OUTFILEEDIT,szB); + else SetDlgItemText(hW,IDC_OUTFILEEDIT,szB); + } +} + +//////////////////////////////////////////////////////////////////////// +// file drive combo + +void EnumDrives(HWND hW) +{ + HWND hWC;char szB[256];int i=0,k=0,iNum; + char * p, * pBuf, * pN; + + hWC=GetDlgItem(hW,IDC_DRIVE); + ComboBox_ResetContent(hWC); + ComboBox_AddString(hWC,"NONE"); // add always existing 'none' + + wsprintf(szB,"[%d:%d:%d",iCD_AD,iCD_TA,iCD_LU); // make current user info text + + pN=pBuf=(char *)malloc(32768); + memset(pBuf,0,32768); + iNum=GetGenCDDrives(pBuf); // get the system cd drives list + + for(i=0;i add drive name + p=strchr(pN,']'); + if(p) + { + *p=0; + if(strcmp(szB,pN)==0) k=i+1; // -> is it the current user drive? sel it + *p=']'; + } + pN+=strlen(pN)+1; // next drive in buffer + } + + free(pBuf); + + ComboBox_SetCurSel(hWC,k); // do the drive sel +} + +//////////////////////////////////////////////////////////////////////// +// get curr selected drive + +void GetCDRInfos(HWND hW,int * iA, int * iT,int * iL) +{ + HWND hWC=GetDlgItem(hW,IDC_DRIVE); + char szB[256];int i;char * p; + + i=ComboBox_GetCurSel(hWC); + if(i<=0) // none selected + { + *iA=-1;*iT=-1;*iL=-1; + MessageBox(hW,"Please select a cdrom drive!","Config error",MB_OK|MB_ICONINFORMATION); + return; + } + + ComboBox_GetLBText(hWC,i,szB); // get cd text + p=szB+1; + *iA=atoi(p); // get AD,TA,LU + p=strchr(szB,':')+1; + *iT=atoi(p); + p=strchr(p,':')+1; + *iL=atoi(p); +} + +//////////////////////////////////////////////////////////////////////// +// interface mode has changed + +void OnIMode(HWND hW) +{ + HWND hWC=GetDlgItem(hW,IDC_IMODE); + int iM = ComboBox_GetCurSel(hWC); + + GetCDRInfos(hW,&iCD_AD,&iCD_TA,&iCD_LU); // get sel drive + CloseGenInterface(); // close current interface + iInterfaceMode=iM; // set new interface mode + OpenGenInterface(); // open new interface + ComboBox_SetCurSel(hWC,iInterfaceMode); // sel interface again (maybe it was not supported on open) + EnumDrives(hW); // enum drives again +} + +//////////////////////////////////////////////////////////////////////// +// cache mode has changed + +void OnCache(HWND hW) +{ + HWND hWC=GetDlgItem(hW,IDC_CACHE); + if(ComboBox_GetCurSel(hWC)<=0) + ShowWindow(GetDlgItem(hW,IDC_DATACACHE),SW_HIDE); + else ShowWindow(GetDlgItem(hW,IDC_DATACACHE),SW_SHOW); +} + +//////////////////////////////////////////////////////////////////////// +// show/hide files depending on subc mode + +void ShowSubFileStuff(HWND hW) +{ + HWND hWC=GetDlgItem(hW,IDC_SUBCHAN0); + int iShow,iSel=ComboBox_GetCurSel(hWC); + + if(iSel==2) iShow=SW_SHOW; + else iShow=SW_HIDE; + + ShowWindow(GetDlgItem(hW,IDC_SFSTATIC),iShow); + ShowWindow(GetDlgItem(hW,IDC_SUBFILE),iShow); + ShowWindow(GetDlgItem(hW,IDC_CHOOSESUBF),iShow); + + if(iSel==1) + { + ComboBox_SetCurSel(GetDlgItem(hW,IDC_CACHE),0); + ShowWindow(GetDlgItem(hW,IDC_DATACACHE),SW_HIDE); + } +} + +//////////////////////////////////////////////////////////////////////// +// init dialog + +BOOL OnInitCDRDialog(HWND hW) +{ + HWND hWC;int i=0; + + ReadConfig(); // read config + + hWC=GetDlgItem(hW,IDC_IMODE); // interface + ComboBox_AddString(hWC,"NONE"); + ComboBox_AddString(hWC,"W9X/ME - ASPI scsi commands"); + ComboBox_AddString(hWC,"W2K/XP - IOCTL scsi commands"); + +// not supported with my dvd drive - DISABLED! +// ComboBox_AddString(hWC,"W2K/XP - IOCTL raw reading"); + + ComboBox_SetCurSel(hWC,iInterfaceMode); + + EnumDrives(hW); // enum drives + + hWC=GetDlgItem(hW,IDC_CACHE); // caching + ComboBox_AddString(hWC,"None - reads one sector"); + ComboBox_AddString(hWC,"Read ahead - fast, reads more sectors at once"); + ComboBox_AddString(hWC,"Async read - faster, additional asynchronous reads"); + ComboBox_AddString(hWC,"Thread read - fast with IOCTL, always async reads"); + ComboBox_AddString(hWC,"Smooth read - for drives with ps2 cd/dvd reading troubles"); + ComboBox_SetCurSel(hWC,iUseCaching); + + if(iUseDataCache) + CheckDlgButton(hW,IDC_DATACACHE,TRUE); + if(!iUseCaching) + ShowWindow(GetDlgItem(hW,IDC_DATACACHE),SW_HIDE); + + if(iUseSpeedLimit) // speed limit + CheckDlgButton(hW,IDC_SPEEDLIMIT,TRUE); + + if(iNoWait) // wait for drive + CheckDlgButton(hW,IDC_NOWAIT,TRUE); + + if(iCheckTrayStatus) // tray status + CheckDlgButton(hW,IDC_TRAYSTATE,TRUE); + + SetDlgItemInt(hW,IDC_RETRY,iMaxRetry,FALSE); // retry on error + if(iMaxRetry) CheckDlgButton(hW,IDC_TRYAGAIN,TRUE); + if(iShowReadErr) CheckDlgButton(hW,IDC_SHOWREADERR,TRUE); + + hWC=GetDlgItem(hW,IDC_SUBCHAN0); // subchannel mode + ComboBox_AddString(hWC,"Don't read subchannels"); + ComboBox_AddString(hWC,"Read subchannels (slow, few drives support it, best chances with BE mode)"); + ComboBox_AddString(hWC,"Use subchannel SBI/M3S info file (recommended)"); + ComboBox_SetCurSel(hWC,iUseSubReading); + + ShowSubFileStuff(hW); // show/hide subc controls + + hWC=GetDlgItem(hW,IDC_SPEED); // speed limit + ComboBox_AddString(hWC,"2 X"); + ComboBox_AddString(hWC,"4 X"); + ComboBox_AddString(hWC,"8 X"); + ComboBox_AddString(hWC,"16 X"); + + i=0; + if(iSpeedLimit==4) i=1; + if(iSpeedLimit==8) i=2; + if(iSpeedLimit==16) i=3; + + ComboBox_SetCurSel(hWC,i); + + if(iUsePPF) CheckDlgButton(hW,IDC_USEPPF,TRUE); // ppf + SetDlgItemText(hW,IDC_PPFFILE,szPPF); + SetDlgItemText(hW,IDC_SUBFILE,szSUBF); + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////// + +void OnCDROK(HWND hW) +{ + int iA,iT,iL,iR; + HWND hWC=GetDlgItem(hW,IDC_RTYPE); + + GetCDRInfos(hW,&iA,&iT,&iL); + if(iA==-1) return; + + hWC=GetDlgItem(hW,IDC_CACHE); + iUseCaching=ComboBox_GetCurSel(hWC); + if(iUseCaching<0) iUseCaching=0; + if(iUseCaching>4) iUseCaching=4; + + iCD_AD=iA;iCD_TA=iT;iCD_LU=iL; + + if(IsDlgButtonChecked(hW,IDC_SPEEDLIMIT)) + iUseSpeedLimit=1; + else iUseSpeedLimit=0; + + iUseSubReading=0; + hWC=GetDlgItem(hW,IDC_SUBCHAN0); + iUseSubReading=ComboBox_GetCurSel(hWC); + if(iUseSubReading<0) iUseSubReading=0; + if(iUseSubReading>2) iUseSubReading=2; + if(iUseSubReading==1) iUseCaching=0; + + if(IsDlgButtonChecked(hW,IDC_DATACACHE)) + iUseDataCache=1; + else iUseDataCache=0; + if(iUseCaching==0) iUseDataCache=0; + + if(IsDlgButtonChecked(hW,IDC_NOWAIT)) + iNoWait=1; + else iNoWait=0; + + if(IsDlgButtonChecked(hW,IDC_TRAYSTATE)) + iCheckTrayStatus=1; + else iCheckTrayStatus=0; + + iMaxRetry=GetDlgItemInt(hW,IDC_RETRY,NULL,FALSE); + if(iMaxRetry<1) iMaxRetry=1; + if(iMaxRetry>10) iMaxRetry=10; + if(!IsDlgButtonChecked(hW,IDC_TRYAGAIN)) iMaxRetry=0; + + if(IsDlgButtonChecked(hW,IDC_SHOWREADERR)) + iShowReadErr=1; + else iShowReadErr=0; + + hWC=GetDlgItem(hW,IDC_SPEED); + iR=ComboBox_GetCurSel(hWC); + + iSpeedLimit=2; + if(iR==1) iSpeedLimit=4; + if(iR==2) iSpeedLimit=8; + if(iR==3) iSpeedLimit=16; + + if(IsDlgButtonChecked(hW,IDC_USEPPF)) + iUsePPF=1; + else iUsePPF=0; + + GetDlgItemText(hW,IDC_PPFFILE,szPPF,259); + GetDlgItemText(hW,IDC_SUBFILE,szSUBF,259); + + WriteConfig(); // write registry + + EndDialog(hW,TRUE); +} + +//////////////////////////////////////////////////////////////////////// + +void OnCDRCancel(HWND hW) +{ + EndDialog(hW,FALSE); +} + +//////////////////////////////////////////////////////////////////////// + +BOOL CALLBACK CDRDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: + return OnInitCDRDialog(hW); + + case WM_COMMAND: + { + switch(LOWORD(wParam)) + { + case IDC_SUBCHAN0: if(HIWORD(wParam)==CBN_SELCHANGE) + {ShowSubFileStuff(hW);return TRUE;} + case IDC_IMODE: if(HIWORD(wParam)==CBN_SELCHANGE) + {OnIMode(hW);return TRUE;} + break; + case IDC_CACHE: if(HIWORD(wParam)==CBN_SELCHANGE) + {OnCache(hW);return TRUE;} + break; + case IDCANCEL: OnCDRCancel(hW); return TRUE; + case IDOK: OnCDROK(hW); return TRUE; + case IDC_CHOOSEFILE: OnChooseFile(hW,0);return TRUE; + case IDC_CHOOSESUBF: OnChooseFile(hW,1);return TRUE; + } + } + } + return FALSE; +} + +//////////////////////////////////////////////////////////////////////// + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_COMMAND: + { + switch(LOWORD(wParam)) + { + case IDCANCEL: EndDialog(hW,FALSE);return TRUE; + case IDOK: EndDialog(hW,FALSE);return TRUE; + } + } + } + return FALSE; +} + +//////////////////////////////////////////////////////////////////////// + diff --git a/plugins/CDVDpeops/CheckDiskType.c b/plugins/CDVDpeops/CheckDiskType.c index 4719c3997f..256c3edadc 100644 --- a/plugins/CDVDpeops/CheckDiskType.c +++ b/plugins/CDVDpeops/CheckDiskType.c @@ -1,41 +1,41 @@ - -#include -#include "CDVDlib.h" -#include "CDVDiso.h" -#include "CDVDisodrv.h" - -int CheckDiskType(int baseType){ - int f; - char buffer[256];//if a file is longer...it should be shorter :D - char *pos; - static struct TocEntry tocEntry; - - CDVDFS_init(); - - // check if the file exists - if (CDVD_findfile("SYSTEM.CNF;1", &tocEntry) != TRUE){ - if (CDVD_findfile("VIDEO_TS/VIDEO_TS.IFO;1", &tocEntry) != TRUE) - if (CDVD_findfile("PSX.EXE;1", &tocEntry) != TRUE) - return CDVD_TYPE_ILLEGAL; - else - return CDVD_TYPE_PSCD; - else - return CDVD_TYPE_DVDV; - } - - f=CDVDFS_open("SYSTEM.CNF;1", 1); - CDVDFS_read(f, buffer, 256); - CDVDFS_close(f); - - buffer[tocEntry.fileSize]='\0'; - - pos=strstr(buffer, "BOOT2"); - if (pos==NULL){ - pos=strstr(buffer, "BOOT"); - if (pos==NULL) { - return CDVD_TYPE_ILLEGAL; - } - return CDVD_TYPE_PSCD; - } - return (baseType==CDVD_TYPE_DETCTCD)?CDVD_TYPE_PS2CD:CDVD_TYPE_PS2DVD; -} + +#include +#include "CDVDlib.h" +#include "CDVDiso.h" +#include "CDVDisodrv.h" + +int CheckDiskType(int baseType){ + int f; + char buffer[256];//if a file is longer...it should be shorter :D + char *pos; + static struct TocEntry tocEntry; + + CDVDFS_init(); + + // check if the file exists + if (CDVD_findfile("SYSTEM.CNF;1", &tocEntry) != TRUE){ + if (CDVD_findfile("VIDEO_TS/VIDEO_TS.IFO;1", &tocEntry) != TRUE) + if (CDVD_findfile("PSX.EXE;1", &tocEntry) != TRUE) + return CDVD_TYPE_ILLEGAL; + else + return CDVD_TYPE_PSCD; + else + return CDVD_TYPE_DVDV; + } + + f=CDVDFS_open("SYSTEM.CNF;1", 1); + CDVDFS_read(f, buffer, 256); + CDVDFS_close(f); + + buffer[tocEntry.fileSize]='\0'; + + pos=strstr(buffer, "BOOT2"); + if (pos==NULL){ + pos=strstr(buffer, "BOOT"); + if (pos==NULL) { + return CDVD_TYPE_ILLEGAL; + } + return CDVD_TYPE_PSCD; + } + return (baseType==CDVD_TYPE_DETCTCD)?CDVD_TYPE_PS2CD:CDVD_TYPE_PS2DVD; +} diff --git a/plugins/CDVDpeops/Ioctrl.c b/plugins/CDVDpeops/Ioctrl.c index 62a38d2960..1577e189ae 100644 --- a/plugins/CDVDpeops/Ioctrl.c +++ b/plugins/CDVDpeops/Ioctrl.c @@ -1,383 +1,383 @@ -/*************************************************************************** - ioctrl.c - description - ------------------- - begin : Sun Nov 16 2003 - copyright : (C) 2003 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2003/11/16 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -///////////////////////////////////////////////////////// - -#include "stdafx.h" -#define _IN_IOCTL -#include "externals.h" - -///////////////////////////////////////////////////////// - -HANDLE hIOCTL=NULL; // global drive file handle -DWORD dwIOCTLAttr=0; // open attribute -OVERLAPPED ovcIOCTL; // global overlapped struct -SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sptIOCTL; // global read bufs -RAW_READ_INFO rawIOCTL; - -///////////////////////////////////////////////////////// -// open drive - -void OpenIOCTLHandle(int iA,int iT,int iL) -{ - char cLetter; - - if(hIOCTL) return; - - cLetter=MapIOCTLDriveLetter(iA,iT,iL); // get drive - - if(!cLetter) return; - - hIOCTL=OpenIOCTLFile(cLetter, // open drive - (iUseCaching==2)?TRUE:FALSE); // (caching:2 -> overlapped) -} - -///////////////////////////////////////////////////////// -// close drive - -void CloseIOCTLHandle(void) -{ - if(hIOCTL) CloseHandle(hIOCTL); - hIOCTL=NULL; -} - -///////////////////////////////////////////////////////// -// get drive letter by a,t,l - -char MapIOCTLDriveLetter(int iA,int iT,int iL) -{ - char cLetter[4];int iDA,iDT,iDL;HANDLE hF; - - strcpy(cLetter,"C:\\"); - - for(cLetter[0]='C';cLetter[0]<='Z';cLetter[0]++) - { - if(GetDriveType(cLetter)==DRIVE_CDROM) - { - hF=OpenIOCTLFile(cLetter[0],FALSE); - GetIOCTLAdapter(hF,&iDA,&iDT,&iDL); - CloseHandle(hF); - if(iA==iDA && iT==iDT && iL==iDL) - return cLetter[0]; - } - } - return 0; -} - -///////////////////////////////////////////////////////// -// get cd drive list, using ioctl, not aspi - -int GetIOCTLCDDrives(char * pDList) -{ - char cLetter[4];int iDA,iDT,iDL;HANDLE hF; - int iCnt=0;char * p=pDList; - - strcpy(cLetter,"C:\\"); - - for(cLetter[0]='C';cLetter[0]<='Z';cLetter[0]++) - { - if(GetDriveType(cLetter)==DRIVE_CDROM) - { - hF=OpenIOCTLFile(cLetter[0],FALSE); - GetIOCTLAdapter(hF,&iDA,&iDT,&iDL); - CloseHandle(hF); - if(iDA!=-1 && iDT!=-1 && iDL!=-1) - { - wsprintf(p,"[%d:%d:%d] Drive %c:", - iDA,iDT,iDL,cLetter[0]); - p+=strlen(p)+1; - iCnt++; - } - } - } - - return iCnt; -} - -///////////////////////////////////////////////////////// -// open drive in sync/async mode - -HANDLE OpenIOCTLFile(char cLetter,BOOL bAsync) -{ - HANDLE hF;char szFName[16]; - OSVERSIONINFO ov;DWORD dwFlags; - - if(bAsync) dwIOCTLAttr=FILE_FLAG_OVERLAPPED; - else dwIOCTLAttr=0; - - memset(&ov,0,sizeof(OSVERSIONINFO)); - ov.dwOSVersionInfoSize=sizeof(OSVERSIONINFO); - GetVersionEx(&ov); - - if((ov.dwPlatformId==VER_PLATFORM_WIN32_NT) && - (ov.dwMajorVersion>4)) - dwFlags = GENERIC_READ|GENERIC_WRITE; // add gen write on W2k/XP - else dwFlags = GENERIC_READ; - - wsprintf(szFName, "\\\\.\\%c:",cLetter); - - hF=CreateFile(szFName,dwFlags,FILE_SHARE_READ, // open drive - NULL,OPEN_EXISTING,dwIOCTLAttr,NULL); - - if(hF==INVALID_HANDLE_VALUE) // mmm... no success? - { - dwFlags^=GENERIC_WRITE; // -> try write toggle - hF=CreateFile(szFName,dwFlags,FILE_SHARE_READ, // -> open drive again - NULL,OPEN_EXISTING,dwIOCTLAttr,NULL); - if(hF==INVALID_HANDLE_VALUE) return NULL; - } - - return hF; -} - -///////////////////////////////////////////////////////// -// get a,t,l - -void GetIOCTLAdapter(HANDLE hF,int * iDA,int * iDT,int * iDL) -{ - char szBuf[1024];PSCSI_ADDRESS pSA;DWORD dwRet; - - *iDA=*iDT=*iDL=-1; - if(hF==NULL) return; - - memset(szBuf,0,1024); - - pSA=(PSCSI_ADDRESS)szBuf; - pSA->Length=sizeof(SCSI_ADDRESS); - - if(!DeviceIoControl(hF,IOCTL_SCSI_GET_ADDRESS,NULL, - 0,pSA,sizeof(SCSI_ADDRESS), - &dwRet,NULL)) - return; - - *iDA = pSA->PortNumber; - *iDT = pSA->TargetId; - *iDL = pSA->Lun; -} - -///////////////////////////////////////////////////////// -// we fake the aspi call in ioctl scsi mode - -DWORD IOCTLSendASPI32Command(LPSRB pSRB) -{ - LPSRB_ExecSCSICmd pSC;DWORD dwRet;BOOL bStat; - - if(!pSRB) return SS_ERR; - - if(hIOCTL==NULL || - pSRB->SRB_Cmd!=SC_EXEC_SCSI_CMD) // we only fake exec aspi scsi commands - { - pSRB->SRB_Status=SS_ERR; - return SS_ERR; - } - - pSC=(LPSRB_ExecSCSICmd)pSRB; - - memset(&sptIOCTL,0,sizeof(sptIOCTL)); - - sptIOCTL.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); - sptIOCTL.spt.CdbLength = pSC->SRB_CDBLen; - sptIOCTL.spt.DataTransferLength = pSC->SRB_BufLen; - sptIOCTL.spt.TimeOutValue = 60; - sptIOCTL.spt.DataBuffer = pSC->SRB_BufPointer; - sptIOCTL.spt.SenseInfoLength = 14; - sptIOCTL.spt.TargetId = pSC->SRB_Target; - sptIOCTL.spt.Lun = pSC->SRB_Lun; - sptIOCTL.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf); - if(pSC->SRB_Flags&SRB_DIR_IN) sptIOCTL.spt.DataIn = SCSI_IOCTL_DATA_IN; - else if(pSC->SRB_Flags&SRB_DIR_OUT) sptIOCTL.spt.DataIn = SCSI_IOCTL_DATA_OUT; - else sptIOCTL.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED; - memcpy(sptIOCTL.spt.Cdb,pSC->CDBByte,pSC->SRB_CDBLen); - - if(dwIOCTLAttr==FILE_FLAG_OVERLAPPED) // async? - { - ovcIOCTL.Internal=0; - ovcIOCTL.InternalHigh=0; - ovcIOCTL.Offset=0; - ovcIOCTL.OffsetHigh=0; - ovcIOCTL.hEvent=hEvent; - bStat = DeviceIoControl(hIOCTL, - IOCTL_SCSI_PASS_THROUGH_DIRECT, - &sptIOCTL, - sizeof(sptIOCTL), - &sptIOCTL, - sizeof(sptIOCTL), - &dwRet, - &ovcIOCTL); - } - else // sync? - { - bStat = DeviceIoControl(hIOCTL, - IOCTL_SCSI_PASS_THROUGH_DIRECT, - &sptIOCTL, - sizeof(sptIOCTL), - &sptIOCTL, - sizeof(sptIOCTL), - &dwRet, - NULL); - } - - if(!bStat) // some err? - { - DWORD dwErrCode; - dwErrCode=GetLastError(); - if(dwErrCode==ERROR_IO_PENDING) // -> pending? - { - pSC->SRB_Status=SS_COMP; // --> ok - return SS_PENDING; - } - pSC->SRB_Status=SS_ERR; // -> else error - return SS_ERR; - } - - pSC->SRB_Status=SS_COMP; - return SS_COMP; -} - -///////////////////////////////////////////////////////// -// special raw mode... works on TEAC532S, for example - -DWORD ReadIOCTL_Raw(BOOL bWait,FRAMEBUF * f) -{ - DWORD dwRet;BOOL bStat; - - if(hIOCTL==NULL) return SS_ERR; - - rawIOCTL.DiskOffset.QuadPart = f->dwFrame*2048; // 2048 is needed here - rawIOCTL.SectorCount = f->dwFrameCnt; - rawIOCTL.TrackMode = XAForm2;//CDDA;//YellowMode2;//XAForm2; - - if(dwIOCTLAttr==FILE_FLAG_OVERLAPPED) // async? - { - ovcIOCTL.Internal=0; - ovcIOCTL.InternalHigh=0; - ovcIOCTL.Offset=0; - ovcIOCTL.OffsetHigh=0; - ovcIOCTL.hEvent=hEvent; - ResetEvent(hEvent); - bStat = DeviceIoControl(hIOCTL, - IOCTL_CDROM_RAW_READ, - &rawIOCTL,sizeof(RAW_READ_INFO), - &(f->BufData[0]),f->dwBufLen,//2048, - &dwRet, &ovcIOCTL); - } - else // sync? - { - bStat = DeviceIoControl(hIOCTL, - IOCTL_CDROM_RAW_READ, - &rawIOCTL,sizeof(RAW_READ_INFO), - &(f->BufData[0]),f->dwBufLen,//2048, - &dwRet,NULL); - } - - if(!bStat) - { - DWORD dwErrCode; - dwErrCode=GetLastError(); - -#ifdef DBGOUT -auxprintf("errorcode %d\n", dwErrCode); -#endif - - if(dwErrCode==ERROR_IO_PENDING) - { - // we do a wait here, not later... no real async mode anyway - // bDoWaiting=TRUE; - - WaitGenEvent(0xFFFFFFFF); - } - else - { - sx.SRB_Status=SS_ERR; - return SS_ERR; - } - } - - sx.SRB_Status=SS_COMP; - return SS_COMP; -} - -///////////////////////////////////////////////////////// -// special raw + special sub... dunno if this really -// works on any drive (teac is working, but giving unprecise -// subdata) - -DWORD ReadIOCTL_Raw_Sub(BOOL bWait,FRAMEBUF * f) -{ - DWORD dwRet;BOOL bStat; - SUB_Q_CHANNEL_DATA qd;unsigned char * p; - CDROM_SUB_Q_DATA_FORMAT qf; - - if(hIOCTL==NULL) return SS_ERR; - - rawIOCTL.DiskOffset.QuadPart = f->dwFrame*2048; - rawIOCTL.SectorCount = f->dwFrameCnt; - rawIOCTL.TrackMode = XAForm2; - - bStat = DeviceIoControl(hIOCTL, - IOCTL_CDROM_RAW_READ, - &rawIOCTL,sizeof(RAW_READ_INFO), - &(f->BufData[0]),f->dwBufLen, - &dwRet,NULL); - - if(!bStat) {sx.SRB_Status=SS_ERR;return SS_ERR;} - - qf.Format=IOCTL_CDROM_CURRENT_POSITION; - qf.Track=1; - bStat = DeviceIoControl(hIOCTL, - IOCTL_CDROM_READ_Q_CHANNEL, - &qf,sizeof(CDROM_SUB_Q_DATA_FORMAT), - &qd,sizeof(SUB_Q_CHANNEL_DATA), - &dwRet,NULL); - - p=(unsigned char*)&qd; - - SubCData[12]=(p[5]<<4)|(p[5]>>4); - SubCData[13]=p[6]; - SubCData[14]=p[7]; - SubCData[15]=p[13]; - SubCData[16]=p[14]; - SubCData[17]=p[15]; - SubCData[18]=0; - SubCData[19]=p[9]; - SubCData[20]=p[10]; - SubCData[21]=p[11]; - - SubCData[15]=itob(SubCData[15]); - SubCData[16]=itob(SubCData[16]); - SubCData[17]=itob(SubCData[17]); - - SubCData[19]=itob(SubCData[19]); - SubCData[20]=itob(SubCData[20]); - SubCData[21]=itob(SubCData[21]); - - if(!bStat) {sx.SRB_Status=SS_ERR;return SS_ERR;} - - sx.SRB_Status=SS_COMP; - return SS_COMP; -} - -///////////////////////////////////////////////////////// +/*************************************************************************** + ioctrl.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#define _IN_IOCTL +#include "externals.h" + +///////////////////////////////////////////////////////// + +HANDLE hIOCTL=NULL; // global drive file handle +DWORD dwIOCTLAttr=0; // open attribute +OVERLAPPED ovcIOCTL; // global overlapped struct +SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sptIOCTL; // global read bufs +RAW_READ_INFO rawIOCTL; + +///////////////////////////////////////////////////////// +// open drive + +void OpenIOCTLHandle(int iA,int iT,int iL) +{ + char cLetter; + + if(hIOCTL) return; + + cLetter=MapIOCTLDriveLetter(iA,iT,iL); // get drive + + if(!cLetter) return; + + hIOCTL=OpenIOCTLFile(cLetter, // open drive + (iUseCaching==2)?TRUE:FALSE); // (caching:2 -> overlapped) +} + +///////////////////////////////////////////////////////// +// close drive + +void CloseIOCTLHandle(void) +{ + if(hIOCTL) CloseHandle(hIOCTL); + hIOCTL=NULL; +} + +///////////////////////////////////////////////////////// +// get drive letter by a,t,l + +char MapIOCTLDriveLetter(int iA,int iT,int iL) +{ + char cLetter[4];int iDA,iDT,iDL;HANDLE hF; + + strcpy(cLetter,"C:\\"); + + for(cLetter[0]='C';cLetter[0]<='Z';cLetter[0]++) + { + if(GetDriveType(cLetter)==DRIVE_CDROM) + { + hF=OpenIOCTLFile(cLetter[0],FALSE); + GetIOCTLAdapter(hF,&iDA,&iDT,&iDL); + CloseHandle(hF); + if(iA==iDA && iT==iDT && iL==iDL) + return cLetter[0]; + } + } + return 0; +} + +///////////////////////////////////////////////////////// +// get cd drive list, using ioctl, not aspi + +int GetIOCTLCDDrives(char * pDList) +{ + char cLetter[4];int iDA,iDT,iDL;HANDLE hF; + int iCnt=0;char * p=pDList; + + strcpy(cLetter,"C:\\"); + + for(cLetter[0]='C';cLetter[0]<='Z';cLetter[0]++) + { + if(GetDriveType(cLetter)==DRIVE_CDROM) + { + hF=OpenIOCTLFile(cLetter[0],FALSE); + GetIOCTLAdapter(hF,&iDA,&iDT,&iDL); + CloseHandle(hF); + if(iDA!=-1 && iDT!=-1 && iDL!=-1) + { + wsprintf(p,"[%d:%d:%d] Drive %c:", + iDA,iDT,iDL,cLetter[0]); + p+=strlen(p)+1; + iCnt++; + } + } + } + + return iCnt; +} + +///////////////////////////////////////////////////////// +// open drive in sync/async mode + +HANDLE OpenIOCTLFile(char cLetter,BOOL bAsync) +{ + HANDLE hF;char szFName[16]; + OSVERSIONINFO ov;DWORD dwFlags; + + if(bAsync) dwIOCTLAttr=FILE_FLAG_OVERLAPPED; + else dwIOCTLAttr=0; + + memset(&ov,0,sizeof(OSVERSIONINFO)); + ov.dwOSVersionInfoSize=sizeof(OSVERSIONINFO); + GetVersionEx(&ov); + + if((ov.dwPlatformId==VER_PLATFORM_WIN32_NT) && + (ov.dwMajorVersion>4)) + dwFlags = GENERIC_READ|GENERIC_WRITE; // add gen write on W2k/XP + else dwFlags = GENERIC_READ; + + wsprintf(szFName, "\\\\.\\%c:",cLetter); + + hF=CreateFile(szFName,dwFlags,FILE_SHARE_READ, // open drive + NULL,OPEN_EXISTING,dwIOCTLAttr,NULL); + + if(hF==INVALID_HANDLE_VALUE) // mmm... no success? + { + dwFlags^=GENERIC_WRITE; // -> try write toggle + hF=CreateFile(szFName,dwFlags,FILE_SHARE_READ, // -> open drive again + NULL,OPEN_EXISTING,dwIOCTLAttr,NULL); + if(hF==INVALID_HANDLE_VALUE) return NULL; + } + + return hF; +} + +///////////////////////////////////////////////////////// +// get a,t,l + +void GetIOCTLAdapter(HANDLE hF,int * iDA,int * iDT,int * iDL) +{ + char szBuf[1024];PSCSI_ADDRESS pSA;DWORD dwRet; + + *iDA=*iDT=*iDL=-1; + if(hF==NULL) return; + + memset(szBuf,0,1024); + + pSA=(PSCSI_ADDRESS)szBuf; + pSA->Length=sizeof(SCSI_ADDRESS); + + if(!DeviceIoControl(hF,IOCTL_SCSI_GET_ADDRESS,NULL, + 0,pSA,sizeof(SCSI_ADDRESS), + &dwRet,NULL)) + return; + + *iDA = pSA->PortNumber; + *iDT = pSA->TargetId; + *iDL = pSA->Lun; +} + +///////////////////////////////////////////////////////// +// we fake the aspi call in ioctl scsi mode + +DWORD IOCTLSendASPI32Command(LPSRB pSRB) +{ + LPSRB_ExecSCSICmd pSC;DWORD dwRet;BOOL bStat; + + if(!pSRB) return SS_ERR; + + if(hIOCTL==NULL || + pSRB->SRB_Cmd!=SC_EXEC_SCSI_CMD) // we only fake exec aspi scsi commands + { + pSRB->SRB_Status=SS_ERR; + return SS_ERR; + } + + pSC=(LPSRB_ExecSCSICmd)pSRB; + + memset(&sptIOCTL,0,sizeof(sptIOCTL)); + + sptIOCTL.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); + sptIOCTL.spt.CdbLength = pSC->SRB_CDBLen; + sptIOCTL.spt.DataTransferLength = pSC->SRB_BufLen; + sptIOCTL.spt.TimeOutValue = 60; + sptIOCTL.spt.DataBuffer = pSC->SRB_BufPointer; + sptIOCTL.spt.SenseInfoLength = 14; + sptIOCTL.spt.TargetId = pSC->SRB_Target; + sptIOCTL.spt.Lun = pSC->SRB_Lun; + sptIOCTL.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf); + if(pSC->SRB_Flags&SRB_DIR_IN) sptIOCTL.spt.DataIn = SCSI_IOCTL_DATA_IN; + else if(pSC->SRB_Flags&SRB_DIR_OUT) sptIOCTL.spt.DataIn = SCSI_IOCTL_DATA_OUT; + else sptIOCTL.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED; + memcpy(sptIOCTL.spt.Cdb,pSC->CDBByte,pSC->SRB_CDBLen); + + if(dwIOCTLAttr==FILE_FLAG_OVERLAPPED) // async? + { + ovcIOCTL.Internal=0; + ovcIOCTL.InternalHigh=0; + ovcIOCTL.Offset=0; + ovcIOCTL.OffsetHigh=0; + ovcIOCTL.hEvent=hEvent; + bStat = DeviceIoControl(hIOCTL, + IOCTL_SCSI_PASS_THROUGH_DIRECT, + &sptIOCTL, + sizeof(sptIOCTL), + &sptIOCTL, + sizeof(sptIOCTL), + &dwRet, + &ovcIOCTL); + } + else // sync? + { + bStat = DeviceIoControl(hIOCTL, + IOCTL_SCSI_PASS_THROUGH_DIRECT, + &sptIOCTL, + sizeof(sptIOCTL), + &sptIOCTL, + sizeof(sptIOCTL), + &dwRet, + NULL); + } + + if(!bStat) // some err? + { + DWORD dwErrCode; + dwErrCode=GetLastError(); + if(dwErrCode==ERROR_IO_PENDING) // -> pending? + { + pSC->SRB_Status=SS_COMP; // --> ok + return SS_PENDING; + } + pSC->SRB_Status=SS_ERR; // -> else error + return SS_ERR; + } + + pSC->SRB_Status=SS_COMP; + return SS_COMP; +} + +///////////////////////////////////////////////////////// +// special raw mode... works on TEAC532S, for example + +DWORD ReadIOCTL_Raw(BOOL bWait,FRAMEBUF * f) +{ + DWORD dwRet;BOOL bStat; + + if(hIOCTL==NULL) return SS_ERR; + + rawIOCTL.DiskOffset.QuadPart = f->dwFrame*2048; // 2048 is needed here + rawIOCTL.SectorCount = f->dwFrameCnt; + rawIOCTL.TrackMode = XAForm2;//CDDA;//YellowMode2;//XAForm2; + + if(dwIOCTLAttr==FILE_FLAG_OVERLAPPED) // async? + { + ovcIOCTL.Internal=0; + ovcIOCTL.InternalHigh=0; + ovcIOCTL.Offset=0; + ovcIOCTL.OffsetHigh=0; + ovcIOCTL.hEvent=hEvent; + ResetEvent(hEvent); + bStat = DeviceIoControl(hIOCTL, + IOCTL_CDROM_RAW_READ, + &rawIOCTL,sizeof(RAW_READ_INFO), + &(f->BufData[0]),f->dwBufLen,//2048, + &dwRet, &ovcIOCTL); + } + else // sync? + { + bStat = DeviceIoControl(hIOCTL, + IOCTL_CDROM_RAW_READ, + &rawIOCTL,sizeof(RAW_READ_INFO), + &(f->BufData[0]),f->dwBufLen,//2048, + &dwRet,NULL); + } + + if(!bStat) + { + DWORD dwErrCode; + dwErrCode=GetLastError(); + +#ifdef DBGOUT +auxprintf("errorcode %d\n", dwErrCode); +#endif + + if(dwErrCode==ERROR_IO_PENDING) + { + // we do a wait here, not later... no real async mode anyway + // bDoWaiting=TRUE; + + WaitGenEvent(0xFFFFFFFF); + } + else + { + sx.SRB_Status=SS_ERR; + return SS_ERR; + } + } + + sx.SRB_Status=SS_COMP; + return SS_COMP; +} + +///////////////////////////////////////////////////////// +// special raw + special sub... dunno if this really +// works on any drive (teac is working, but giving unprecise +// subdata) + +DWORD ReadIOCTL_Raw_Sub(BOOL bWait,FRAMEBUF * f) +{ + DWORD dwRet;BOOL bStat; + SUB_Q_CHANNEL_DATA qd;unsigned char * p; + CDROM_SUB_Q_DATA_FORMAT qf; + + if(hIOCTL==NULL) return SS_ERR; + + rawIOCTL.DiskOffset.QuadPart = f->dwFrame*2048; + rawIOCTL.SectorCount = f->dwFrameCnt; + rawIOCTL.TrackMode = XAForm2; + + bStat = DeviceIoControl(hIOCTL, + IOCTL_CDROM_RAW_READ, + &rawIOCTL,sizeof(RAW_READ_INFO), + &(f->BufData[0]),f->dwBufLen, + &dwRet,NULL); + + if(!bStat) {sx.SRB_Status=SS_ERR;return SS_ERR;} + + qf.Format=IOCTL_CDROM_CURRENT_POSITION; + qf.Track=1; + bStat = DeviceIoControl(hIOCTL, + IOCTL_CDROM_READ_Q_CHANNEL, + &qf,sizeof(CDROM_SUB_Q_DATA_FORMAT), + &qd,sizeof(SUB_Q_CHANNEL_DATA), + &dwRet,NULL); + + p=(unsigned char*)&qd; + + SubCData[12]=(p[5]<<4)|(p[5]>>4); + SubCData[13]=p[6]; + SubCData[14]=p[7]; + SubCData[15]=p[13]; + SubCData[16]=p[14]; + SubCData[17]=p[15]; + SubCData[18]=0; + SubCData[19]=p[9]; + SubCData[20]=p[10]; + SubCData[21]=p[11]; + + SubCData[15]=itob(SubCData[15]); + SubCData[16]=itob(SubCData[16]); + SubCData[17]=itob(SubCData[17]); + + SubCData[19]=itob(SubCData[19]); + SubCData[20]=itob(SubCData[20]); + SubCData[21]=itob(SubCData[21]); + + if(!bStat) {sx.SRB_Status=SS_ERR;return SS_ERR;} + + sx.SRB_Status=SS_COMP; + return SS_COMP; +} + +///////////////////////////////////////////////////////// diff --git a/plugins/CDVDpeops/Makefile.win b/plugins/CDVDpeops/Makefile.win index c860068e9f..d0a2e1e0ba 100644 --- a/plugins/CDVDpeops/Makefile.win +++ b/plugins/CDVDpeops/Makefile.win @@ -1,72 +1,72 @@ -# Project: cdvdPeops -# Makefile created by Dev-C++ 4.9.9.0 - -CPP = g++.exe -CC = gcc.exe -WINDRES = windres.exe -RES = cdvdPeops_private.res -OBJ = Release/cdr.o Release/cdvdPeops.o Release/cfg.o Release/generic.o Release/ioctrl.o Release/ppf.o Release/read.o Release/scsi.o Release/StdAfx.o Release/sub.o Release/toc.o Release/cdda.o Release/i386.o $(RES) -LINKOBJ = Release/cdr.o Release/cdvdPeops.o Release/cfg.o Release/generic.o Release/ioctrl.o Release/ppf.o Release/read.o Release/scsi.o Release/StdAfx.o Release/sub.o Release/toc.o Release/cdda.o Release/i386.o $(RES) -LIBS = -L"D:/vs/Dev-Cpp/lib" -lkernel32 -luser32 -ladvapi32 -lcomdlg32 --add-stdcall-alias -INCS = -I"D:/vs/Dev-Cpp/include" -I"d:/vs/vc98/MFC/include" -CXXINCS = -I"D:/vs/Dev-Cpp/include/c++" -I"D:/vs/Dev-Cpp/include/c++/mingw32" -I"D:/vs/Dev-Cpp/include/c++/backward" -I"D:/vs/Dev-Cpp/include" -I"d:/vs/vc98/MFC/include" -BIN = ../../../emus/pcsx2_0.6/plugins/cdvdPeops.dll -CXXFLAGS = $(CXXINCS) -D__GNUWIN32__ -mcpu=pentium -D_M_IX86=500 -W -DWIN32 -DNDEBUG -D_WINDOWS -D_GCC -fexpensive-optimizations -O3 -CFLAGS = $(INCS) -D__GNUWIN32__ -mcpu=pentium -D_M_IX86=500 -W -DWIN32 -DNDEBUG -D_WINDOWS -D_GCC -fexpensive-optimizations -O3 - -.PHONY: all all-before all-after clean clean-custom - -all: all-before ../../../emus/pcsx2_0.6/plugins/cdvdPeops.dll all-after - - -clean: clean-custom - rm -f $(OBJ) $(BIN) - -DLLWRAP=dllwrap.exe -DEFFILE=../../../emus/pcsx2_0.6/plugins/libcdvdPeops.def -STATICLIB=../../../emus/pcsx2_0.6/plugins/libcdvdPeops.a - -$(BIN): $(LINKOBJ) - $(DLLWRAP) --output-def $(DEFFILE) --driver-name c++ --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN) - -Release/cdr.o: cdr.c - $(CC) -c cdr.c -o Release/cdr.o $(CFLAGS) - -Release/cdvdPeops.o: cdvdPeops.c - $(CC) -c cdvdPeops.c -o Release/cdvdPeops.o $(CFLAGS) - -Release/cfg.o: cfg.c - $(CC) -c cfg.c -o Release/cfg.o $(CFLAGS) - -Release/generic.o: generic.c - $(CC) -c generic.c -o Release/generic.o $(CFLAGS) - -Release/ioctrl.o: ioctrl.c - $(CC) -c ioctrl.c -o Release/ioctrl.o $(CFLAGS) - -Release/ppf.o: ppf.c - $(CC) -c ppf.c -o Release/ppf.o $(CFLAGS) - -Release/read.o: read.c - $(CC) -c read.c -o Release/read.o $(CFLAGS) - -Release/scsi.o: scsi.c - $(CC) -c scsi.c -o Release/scsi.o $(CFLAGS) - -Release/StdAfx.o: StdAfx.c - $(CC) -c StdAfx.c -o Release/StdAfx.o $(CFLAGS) - -Release/sub.o: sub.c - $(CC) -c sub.c -o Release/sub.o $(CFLAGS) - -Release/toc.o: toc.c - $(CC) -c toc.c -o Release/toc.o $(CFLAGS) - -Release/cdda.o: cdda.c - $(CC) -c cdda.c -o Release/cdda.o $(CFLAGS) - -Release/i386.o: i386.asm - nasmw.exe -f win32 -D__WIN32__ -D__i386__ i386.asm -o release\i386.o - -cdvdPeops_private.res: cdvdPeops_private.rc ../../../src/cdvdPeops/src/cdvdPeops.rc - $(WINDRES) -i cdvdPeops_private.rc -I rc -o cdvdPeops_private.res -O coff +# Project: cdvdPeops +# Makefile created by Dev-C++ 4.9.9.0 + +CPP = g++.exe +CC = gcc.exe +WINDRES = windres.exe +RES = cdvdPeops_private.res +OBJ = Release/cdr.o Release/cdvdPeops.o Release/cfg.o Release/generic.o Release/ioctrl.o Release/ppf.o Release/read.o Release/scsi.o Release/StdAfx.o Release/sub.o Release/toc.o Release/cdda.o Release/i386.o $(RES) +LINKOBJ = Release/cdr.o Release/cdvdPeops.o Release/cfg.o Release/generic.o Release/ioctrl.o Release/ppf.o Release/read.o Release/scsi.o Release/StdAfx.o Release/sub.o Release/toc.o Release/cdda.o Release/i386.o $(RES) +LIBS = -L"D:/vs/Dev-Cpp/lib" -lkernel32 -luser32 -ladvapi32 -lcomdlg32 --add-stdcall-alias +INCS = -I"D:/vs/Dev-Cpp/include" -I"d:/vs/vc98/MFC/include" +CXXINCS = -I"D:/vs/Dev-Cpp/include/c++" -I"D:/vs/Dev-Cpp/include/c++/mingw32" -I"D:/vs/Dev-Cpp/include/c++/backward" -I"D:/vs/Dev-Cpp/include" -I"d:/vs/vc98/MFC/include" +BIN = ../../../emus/pcsx2_0.6/plugins/cdvdPeops.dll +CXXFLAGS = $(CXXINCS) -D__GNUWIN32__ -mcpu=pentium -D_M_IX86=500 -W -DWIN32 -DNDEBUG -D_WINDOWS -D_GCC -fexpensive-optimizations -O3 +CFLAGS = $(INCS) -D__GNUWIN32__ -mcpu=pentium -D_M_IX86=500 -W -DWIN32 -DNDEBUG -D_WINDOWS -D_GCC -fexpensive-optimizations -O3 + +.PHONY: all all-before all-after clean clean-custom + +all: all-before ../../../emus/pcsx2_0.6/plugins/cdvdPeops.dll all-after + + +clean: clean-custom + rm -f $(OBJ) $(BIN) + +DLLWRAP=dllwrap.exe +DEFFILE=../../../emus/pcsx2_0.6/plugins/libcdvdPeops.def +STATICLIB=../../../emus/pcsx2_0.6/plugins/libcdvdPeops.a + +$(BIN): $(LINKOBJ) + $(DLLWRAP) --output-def $(DEFFILE) --driver-name c++ --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN) + +Release/cdr.o: cdr.c + $(CC) -c cdr.c -o Release/cdr.o $(CFLAGS) + +Release/cdvdPeops.o: cdvdPeops.c + $(CC) -c cdvdPeops.c -o Release/cdvdPeops.o $(CFLAGS) + +Release/cfg.o: cfg.c + $(CC) -c cfg.c -o Release/cfg.o $(CFLAGS) + +Release/generic.o: generic.c + $(CC) -c generic.c -o Release/generic.o $(CFLAGS) + +Release/ioctrl.o: ioctrl.c + $(CC) -c ioctrl.c -o Release/ioctrl.o $(CFLAGS) + +Release/ppf.o: ppf.c + $(CC) -c ppf.c -o Release/ppf.o $(CFLAGS) + +Release/read.o: read.c + $(CC) -c read.c -o Release/read.o $(CFLAGS) + +Release/scsi.o: scsi.c + $(CC) -c scsi.c -o Release/scsi.o $(CFLAGS) + +Release/StdAfx.o: StdAfx.c + $(CC) -c StdAfx.c -o Release/StdAfx.o $(CFLAGS) + +Release/sub.o: sub.c + $(CC) -c sub.c -o Release/sub.o $(CFLAGS) + +Release/toc.o: toc.c + $(CC) -c toc.c -o Release/toc.o $(CFLAGS) + +Release/cdda.o: cdda.c + $(CC) -c cdda.c -o Release/cdda.o $(CFLAGS) + +Release/i386.o: i386.asm + nasmw.exe -f win32 -D__WIN32__ -D__i386__ i386.asm -o release\i386.o + +cdvdPeops_private.res: cdvdPeops_private.rc ../../../src/cdvdPeops/src/cdvdPeops.rc + $(WINDRES) -i cdvdPeops_private.rc -I rc -o cdvdPeops_private.res -O coff diff --git a/plugins/CDVDpeops/PS2Edefs.h b/plugins/CDVDpeops/PS2Edefs.h index 48093ae147..715d21f612 100644 --- a/plugins/CDVDpeops/PS2Edefs.h +++ b/plugins/CDVDpeops/PS2Edefs.h @@ -1,789 +1,789 @@ -#ifndef __PS2EDEFS_H__ -#define __PS2EDEFS_H__ - -/* - * PS2E Definitions v0.6.2 (beta) - * - * Author: linuzappz@hotmail.com - * shadowpcsx2@yahoo.gr - * florinsasu@hotmail.com - */ - -/* - Notes: - * Since this is still beta things may change. - - * OSflags: - __LINUX__ (linux OS) - __WIN32__ (win32 OS) - - * common return values (for ie. GSinit): - 0 - success - -1 - error - - * reserved keys: - F1 to F10 are reserved for the emulator - - * plugins should NOT change the current - working directory. - (on win32, add flag OFN_NOCHANGEDIR for - GetOpenFileName) - -*/ - -#include "PS2Etypes.h" - -#ifdef __LINUX__ -#define CALLBACK -#else -#include -#endif - -/* common defines */ - -#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ - defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ - defined(USBdefs) || defined(FWdefs) -#define COMMONdefs -#endif - -// PS2EgetLibType returns (may be OR'd) -#define PS2E_LT_GS 0x01 -#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- -#define PS2E_LT_SPU2 0x04 -#define PS2E_LT_CDVD 0x08 -#define PS2E_LT_DEV9 0x10 -#define PS2E_LT_USB 0x20 -#define PS2E_LT_FW 0x40 -#define PS2E_LT_SIO 0x80 - -// PS2EgetLibVersion2 (high 16 bits) -#define PS2E_GS_VERSION 0x0006 -#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- -#define PS2E_SPU2_VERSION 0x0004 -#define PS2E_CDVD_VERSION 0x0005 -#define PS2E_DEV9_VERSION 0x0003 -#define PS2E_USB_VERSION 0x0003 -#define PS2E_FW_VERSION 0x0002 -#define PS2E_SIO_VERSION 0x0001 -#ifdef COMMONdefs - -u32 CALLBACK PS2EgetLibType(void); -u32 CALLBACK PS2EgetLibVersion2(u32 type); -char* CALLBACK PS2EgetLibName(void); - -#endif - -// key values: -/* key values must be OS dependant: - win32: the VK_XXX will be used (WinUser) - linux: the XK_XXX will be used (XFree86) -*/ - -// event values: -#define KEYPRESS 1 -#define KEYRELEASE 2 - -typedef struct { - u32 key; - u32 event; -} keyEvent; - -// plugin types -#define SIO_TYPE_PAD 0x00000001 -#define SIO_TYPE_MTAP 0x00000004 -#define SIO_TYPE_RM 0x00000040 -#define SIO_TYPE_MC 0x00000100 - -typedef int (CALLBACK * SIOchangeSlotCB)(int slot); - -typedef struct { - u8 ctrl:4; // control and mode bits - u8 mode:4; // control and mode bits - u8 trackNum; // current track number (1 to 99) - u8 trackIndex; // current index within track (0 to 99) - u8 trackM; // current minute location on the disc (BCD encoded) - u8 trackS; // current sector location on the disc (BCD encoded) - u8 trackF; // current frame location on the disc (BCD encoded) - u8 pad; // unused - u8 discM; // current minute offset from first track (BCD encoded) - u8 discS; // current sector offset from first track (BCD encoded) - u8 discF; // current frame offset from first track (BCD encoded) -} cdvdSubQ; - -typedef struct { // NOT bcd coded - u32 lsn; - u8 type; -} cdvdTD; - -typedef struct { - u8 strack; //number of the first track (usually 1) - u8 etrack; //number of the last track -} cdvdTN; - -// CDVDreadTrack mode values: -#define CDVD_MODE_2352 0 // full 2352 bytes -#define CDVD_MODE_2340 1 // skip sync (12) bytes -#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq - -// CDVDgetDiskType returns: -#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc -#define CDVD_TYPE_DVDV 0xfe // DVD Video -#define CDVD_TYPE_CDDA 0xfd // Audio CD -#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD -#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) -#define CDVD_TYPE_PS2CD 0x12 // PS2 CD -#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) -#define CDVD_TYPE_PSCD 0x10 // PS CD -#define CDVD_TYPE_UNKNOWN 0x05 // Unknown -#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided -#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided -#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd -#define CDVD_TYPE_DETCT 0x01 // Detecting -#define CDVD_TYPE_NODISC 0x00 // No Disc - -// CDVDgetTrayStatus returns: -#define CDVD_TRAY_CLOSE 0x00 -#define CDVD_TRAY_OPEN 0x01 - -// cdvdTD.type (track types for cds) -#define CDVD_AUDIO_TRACK 0x01 -#define CDVD_MODE1_TRACK 0x41 -#define CDVD_MODE2_TRACK 0x61 - -#define CDVD_AUDIO_MASK 0x00 -#define CDVD_DATA_MASK 0x40 -// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) - -typedef void (*DEV9callback)(int cycles); -typedef int (*DEV9handler)(void); - -typedef void (*USBcallback)(int cycles); -typedef int (*USBhandler)(void); - -// freeze modes: -#define FREEZE_LOAD 0 -#define FREEZE_SAVE 1 -#define FREEZE_SIZE 2 - -typedef struct { - int size; - s8 *data; -} freezeData; - -typedef struct { - char name[8]; - void *common; -} GSdriverInfo; - -#ifdef __WIN32__ -typedef struct { // unsupported values must be set to zero - HWND hWnd; - HMENU hMenu; - HWND hStatusWnd; -} winInfo; -#endif - -/* GS plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef GSdefs - -// basic funcs - -s32 CALLBACK GSinit(); -s32 CALLBACK GSopen(void *pDsp, char *Title); -void CALLBACK GSclose(); -void CALLBACK GSshutdown(); -void CALLBACK GSvsync(); -void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); -void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); -void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); -void CALLBACK GSwrite8(u32 mem, u8 value); -void CALLBACK GSwrite16(u32 mem, u16 value); -void CALLBACK GSwrite32(u32 mem, u32 value); -void CALLBACK GSwrite64(u32 mem, u64 value); -u8 CALLBACK GSread8(u32 mem); -u16 CALLBACK GSread16(u32 mem); -u32 CALLBACK GSread32(u32 mem); -u64 CALLBACK GSread64(u32 mem); -void CALLBACK GSreadFIFO(u64 *mem); - -// extended funcs - -// GSkeyEvent gets called when there is a keyEvent from the PAD plugin -void CALLBACK GSkeyEvent(keyEvent *ev); -void CALLBACK GSmakeSnapshot(char *path); -void CALLBACK GSirqCallback(void (*callback)()); -void CALLBACK GSprintf(int timeout, char *fmt, ...); -void CALLBACK GSsetCSR(u64 *csr); -void CALLBACK GSgetDriverInfo(GSdriverInfo *info); -#ifdef __WIN32__ -s32 CALLBACK GSsetWindowInfo(winInfo *info); -#endif -s32 CALLBACK GSfreeze(int mode, freezeData *data); -void CALLBACK GSconfigure(); -void CALLBACK GSabout(); -s32 CALLBACK GStest(); - -#endif - -/* PAD plugin API -=[ OBSOLETE ]=- */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef PADdefs - -// basic funcs - -s32 CALLBACK PADinit(u32 flags); -s32 CALLBACK PADopen(void *pDsp); -void CALLBACK PADclose(); -void CALLBACK PADshutdown(); -// PADkeyEvent is called every vsync (return NULL if no event) -keyEvent* CALLBACK PADkeyEvent(); -u8 CALLBACK PADstartPoll(int pad); -u8 CALLBACK PADpoll(u8 value); -// returns: 1 if supported pad1 -// 2 if supported pad2 -// 3 if both are supported -u32 CALLBACK PADquery(); - -// extended funcs - -void CALLBACK PADgsDriverInfo(GSdriverInfo *info); -void CALLBACK PADconfigure(); -void CALLBACK PADabout(); -s32 CALLBACK PADtest(); - -#endif - -/* SIO plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SIOdefs - -// basic funcs - -s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); -s32 CALLBACK SIOopen(void *pDsp); -void CALLBACK SIOclose(); -void CALLBACK SIOshutdown(); -u8 CALLBACK SIOstartPoll(u8 value); -u8 CALLBACK SIOpoll(u8 value); -// returns: SIO_TYPE_{PAD,MTAP,RM,MC} -u32 CALLBACK SIOquery(); - -// extended funcs - -void CALLBACK SIOconfigure(); -void CALLBACK SIOabout(); -s32 CALLBACK SIOtest(); - -#endif - -/* SPU2 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SPU2defs - -// basic funcs - -s32 CALLBACK SPU2init(); -s32 CALLBACK SPU2open(void *pDsp); -void CALLBACK SPU2close(); -void CALLBACK SPU2shutdown(); -void CALLBACK SPU2write(u32 mem, u16 value); -u16 CALLBACK SPU2read(u32 mem); -void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA4(); -void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); -void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA7(); -void CALLBACK SPU2irqCallback(void (*callback)()); - -// extended funcs - -void CALLBACK SPU2async(u32 cycles); -s32 CALLBACK SPU2freeze(int mode, freezeData *data); -void CALLBACK SPU2configure(); -void CALLBACK SPU2about(); -s32 CALLBACK SPU2test(); - -#endif - -/* CDVD plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef CDVDdefs - -// basic funcs - -s32 CALLBACK CDVDinit(); -s32 CALLBACK CDVDopen(); -void CALLBACK CDVDclose(); -void CALLBACK CDVDshutdown(); -s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); - -// return can be NULL (for async modes) -u8* CALLBACK CDVDgetBuffer(); - -s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) -s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information -s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type -s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc -s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx -s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx -s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray -s32 CALLBACK CDVDctrlTrayClose(); //close disc tray - -// extended funcs - -void CALLBACK CDVDconfigure(); -void CALLBACK CDVDabout(); -s32 CALLBACK CDVDtest(); -void CALLBACK CDVDnewDiskCB(void (*callback)()); - -#endif - -/* DEV9 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef DEV9defs - -// basic funcs - -s32 CALLBACK DEV9init(); -s32 CALLBACK DEV9open(void *pDsp); -void CALLBACK DEV9close(); -void CALLBACK DEV9shutdown(); -u8 CALLBACK DEV9read8(u32 addr); -u16 CALLBACK DEV9read16(u32 addr); -u32 CALLBACK DEV9read32(u32 addr); -void CALLBACK DEV9write8(u32 addr, u8 value); -void CALLBACK DEV9write16(u32 addr, u16 value); -void CALLBACK DEV9write32(u32 addr, u32 value); -void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); -void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK DEV9irqCallback(DEV9callback callback); -DEV9handler CALLBACK DEV9irqHandler(void); - -// extended funcs - -s32 CALLBACK DEV9freeze(int mode, freezeData *data); -void CALLBACK DEV9configure(); -void CALLBACK DEV9about(); -s32 CALLBACK DEV9test(); - -#endif - -/* USB plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef USBdefs - -// basic funcs - -s32 CALLBACK USBinit(); -s32 CALLBACK USBopen(void *pDsp); -void CALLBACK USBclose(); -void CALLBACK USBshutdown(); -u8 CALLBACK USBread8(u32 addr); -u16 CALLBACK USBread16(u32 addr); -u32 CALLBACK USBread32(u32 addr); -void CALLBACK USBwrite8(u32 addr, u8 value); -void CALLBACK USBwrite16(u32 addr, u16 value); -void CALLBACK USBwrite32(u32 addr, u32 value); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK USBirqCallback(USBcallback callback); -USBhandler CALLBACK USBirqHandler(void); -void CALLBACK USBsetRAM(void *mem); - -// extended funcs - -s32 CALLBACK USBfreeze(int mode, freezeData *data); -void CALLBACK USBconfigure(); -void CALLBACK USBabout(); -s32 CALLBACK USBtest(); - -#endif - -/* FW plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef FWdefs -// basic funcs - -s32 CALLBACK FWinit(); -s32 CALLBACK FWopen(void *pDsp); -void CALLBACK FWclose(); -void CALLBACK FWshutdown(); -u32 CALLBACK FWread32(u32 addr); -void CALLBACK FWwrite32(u32 addr, u32 value); -void CALLBACK FWirqCallback(void (*callback)()); - -// extended funcs - -s32 CALLBACK FWfreeze(int mode, freezeData *data); -void CALLBACK FWconfigure(); -void CALLBACK FWabout(); -s32 CALLBACK FWtest(); -#endif - -// might be useful for emulators -#ifdef PLUGINtypedefs - -typedef u32 (CALLBACK* _PS2EgetLibType)(void); -typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); -typedef char*(CALLBACK* _PS2EgetLibName)(void); - -// GS -typedef s32 (CALLBACK* _GSinit)(); -typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title); -typedef void (CALLBACK* _GSclose)(); -typedef void (CALLBACK* _GSshutdown)(); -typedef void (CALLBACK* _GSvsync)(); -typedef void (CALLBACK* _GSwrite8)(u32 mem, u8 value); -typedef void (CALLBACK* _GSwrite16)(u32 mem, u16 value); -typedef void (CALLBACK* _GSwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _GSwrite64)(u32 mem, u64 value); -typedef u8 (CALLBACK* _GSread8)(u32 mem); -typedef u16 (CALLBACK* _GSread16)(u32 mem); -typedef u32 (CALLBACK* _GSread32)(u32 mem); -typedef u64 (CALLBACK* _GSread64)(u32 mem); -typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); -typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); - -typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); -typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); -typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); -typedef void (CALLBACK* _GSsetCSR)(u64 * csr); -typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); -#ifdef __WIN32__ -typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); -#endif -typedef void (CALLBACK* _GSmakeSnapshot)(char *path); -typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _GSconfigure)(); -typedef s32 (CALLBACK* _GStest)(); -typedef void (CALLBACK* _GSabout)(); - -// PAD -typedef s32 (CALLBACK* _PADinit)(u32 flags); -typedef s32 (CALLBACK* _PADopen)(void *pDsp); -typedef void (CALLBACK* _PADclose)(); -typedef void (CALLBACK* _PADshutdown)(); -typedef keyEvent* (CALLBACK* _PADkeyEvent)(); -typedef u8 (CALLBACK* _PADstartPoll)(int pad); -typedef u8 (CALLBACK* _PADpoll)(u8 value); -typedef u32 (CALLBACK* _PADquery)(); - -typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); -typedef void (CALLBACK* _PADconfigure)(); -typedef s32 (CALLBACK* _PADtest)(); -typedef void (CALLBACK* _PADabout)(); - -// SIO -typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); -typedef s32 (CALLBACK* _SIOopen)(void *pDsp); -typedef void (CALLBACK* _SIOclose)(); -typedef void (CALLBACK* _SIOshutdown)(); -typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); -typedef u8 (CALLBACK* _SIOpoll)(u8 value); -typedef u32 (CALLBACK* _SIOquery)(); - -typedef void (CALLBACK* _SIOconfigure)(); -typedef s32 (CALLBACK* _SIOtest)(); -typedef void (CALLBACK* _SIOabout)(); - -// SPU2 -typedef s32 (CALLBACK* _SPU2init)(); -typedef s32 (CALLBACK* _SPU2open)(void *pDsp); -typedef void (CALLBACK* _SPU2close)(); -typedef void (CALLBACK* _SPU2shutdown)(); -typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); -typedef u16 (CALLBACK* _SPU2read)(u32 mem); -typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA4)(); -typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA7)(); -typedef void (CALLBACK* _SPU2irqCallback)(void (*callback)()); - -typedef void (CALLBACK* _SPU2async)(u32 cycles); -typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _SPU2configure)(); -typedef s32 (CALLBACK* _SPU2test)(); -typedef void (CALLBACK* _SPU2about)(); - -// CDVD -typedef s32 (CALLBACK* _CDVDinit)(); -typedef s32 (CALLBACK* _CDVDopen)(); -typedef void (CALLBACK* _CDVDclose)(); -typedef void (CALLBACK* _CDVDshutdown)(); -typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); -typedef u8* (CALLBACK* _CDVDgetBuffer)(); -typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); -typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); -typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); -typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); -typedef s32 (CALLBACK* _CDVDgetDiskType)(); -typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); -typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); -typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); - -typedef void (CALLBACK* _CDVDconfigure)(); -typedef s32 (CALLBACK* _CDVDtest)(); -typedef void (CALLBACK* _CDVDabout)(); -typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); - -// DEV9 -typedef s32 (CALLBACK* _DEV9init)(); -typedef s32 (CALLBACK* _DEV9open)(void *pDsp); -typedef void (CALLBACK* _DEV9close)(); -typedef void (CALLBACK* _DEV9shutdown)(); -typedef u8 (CALLBACK* _DEV9read8)(u32 mem); -typedef u16 (CALLBACK* _DEV9read16)(u32 mem); -typedef u32 (CALLBACK* _DEV9read32)(u32 mem); -typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); -typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); -typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); -typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); -typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); - -typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _DEV9configure)(); -typedef s32 (CALLBACK* _DEV9test)(); -typedef void (CALLBACK* _DEV9about)(); - -// USB -typedef s32 (CALLBACK* _USBinit)(); -typedef s32 (CALLBACK* _USBopen)(void *pDsp); -typedef void (CALLBACK* _USBclose)(); -typedef void (CALLBACK* _USBshutdown)(); -typedef u8 (CALLBACK* _USBread8)(u32 mem); -typedef u16 (CALLBACK* _USBread16)(u32 mem); -typedef u32 (CALLBACK* _USBread32)(u32 mem); -typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); -typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); -typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); -typedef USBhandler (CALLBACK* _USBirqHandler)(void); -typedef void (CALLBACK* _USBsetRAM)(void *mem); - -typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _USBconfigure)(); -typedef s32 (CALLBACK* _USBtest)(); -typedef void (CALLBACK* _USBabout)(); - -//FW -typedef s32 (CALLBACK* _FWinit)(); -typedef s32 (CALLBACK* _FWopen)(void *pDsp); -typedef void (CALLBACK* _FWclose)(); -typedef void (CALLBACK* _FWshutdown)(); -typedef u32 (CALLBACK* _FWread32)(u32 mem); -typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); - -typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _FWconfigure)(); -typedef s32 (CALLBACK* _FWtest)(); -typedef void (CALLBACK* _FWabout)(); - -#endif - -#ifdef PLUGINfuncs - -// GS -_GSinit GSinit; -_GSopen GSopen; -_GSclose GSclose; -_GSshutdown GSshutdown; -_GSvsync GSvsync; -_GSwrite8 GSwrite8; -_GSwrite16 GSwrite16; -_GSwrite32 GSwrite32; -_GSwrite64 GSwrite64; -_GSread8 GSread8; -_GSread16 GSread16; -_GSread32 GSread32; -_GSread64 GSread64; -_GSgifTransfer1 GSgifTransfer1; -_GSgifTransfer2 GSgifTransfer2; -_GSgifTransfer3 GSgifTransfer3; -_GSreadFIFO GSreadFIFO; - -_GSkeyEvent GSkeyEvent; -_GSmakeSnapshot GSmakeSnapshot; -_GSirqCallback GSirqCallback; -_GSprintf GSprintf; -_GSsetCSR GSsetCSR; -_GSgetDriverInfo GSgetDriverInfo; -#ifdef __WIN32__ -_GSsetWindowInfo GSsetWindowInfo; -#endif -_GSfreeze GSfreeze; -_GSconfigure GSconfigure; -_GStest GStest; -_GSabout GSabout; - -// PAD1 -_PADinit PAD1init; -_PADopen PAD1open; -_PADclose PAD1close; -_PADshutdown PAD1shutdown; -_PADkeyEvent PAD1keyEvent; -_PADstartPoll PAD1startPoll; -_PADpoll PAD1poll; -_PADquery PAD1query; - -_PADgsDriverInfo PAD1gsDriverInfo; -_PADconfigure PAD1configure; -_PADtest PAD1test; -_PADabout PAD1about; - -// PAD2 -_PADinit PAD2init; -_PADopen PAD2open; -_PADclose PAD2close; -_PADshutdown PAD2shutdown; -_PADkeyEvent PAD2keyEvent; -_PADstartPoll PAD2startPoll; -_PADpoll PAD2poll; -_PADquery PAD2query; - -_PADgsDriverInfo PAD2gsDriverInfo; -_PADconfigure PAD2configure; -_PADtest PAD2test; -_PADabout PAD2about; - -// SIO[2] -_SIOinit SIOinit[2][9]; -_SIOopen SIOopen[2][9]; -_SIOclose SIOclose[2][9]; -_SIOshutdown SIOshutdown[2][9]; -_SIOstartPoll SIOstartPoll[2][9]; -_SIOpoll SIOpoll[2][9]; -_SIOquery SIOquery[2][9]; - -_SIOconfigure SIOconfigure[2][9]; -_SIOtest SIOtest[2][9]; -_SIOabout SIOabout[2][9]; - -// SPU2 -_SPU2init SPU2init; -_SPU2open SPU2open; -_SPU2close SPU2close; -_SPU2shutdown SPU2shutdown; -_SPU2write SPU2write; -_SPU2read SPU2read; -_SPU2readDMA4Mem SPU2readDMA4Mem; -_SPU2writeDMA4Mem SPU2writeDMA4Mem; -_SPU2interruptDMA4 SPU2interruptDMA4; -_SPU2readDMA7Mem SPU2readDMA7Mem; -_SPU2writeDMA7Mem SPU2writeDMA7Mem; -_SPU2interruptDMA7 SPU2interruptDMA7; -_SPU2irqCallback SPU2irqCallback; - -_SPU2async SPU2async; -_SPU2freeze SPU2freeze; -_SPU2configure SPU2configure; -_SPU2test SPU2test; -_SPU2about SPU2about; - -// CDVD -_CDVDinit CDVDinit; -_CDVDopen CDVDopen; -_CDVDclose CDVDclose; -_CDVDshutdown CDVDshutdown; -_CDVDreadTrack CDVDreadTrack; -_CDVDgetBuffer CDVDgetBuffer; -_CDVDreadSubQ CDVDreadSubQ; -_CDVDgetTN CDVDgetTN; -_CDVDgetTD CDVDgetTD; -_CDVDgetTOC CDVDgetTOC; -_CDVDgetDiskType CDVDgetDiskType; -_CDVDgetTrayStatus CDVDgetTrayStatus; -_CDVDctrlTrayOpen CDVDctrlTrayOpen; -_CDVDctrlTrayClose CDVDctrlTrayClose; - -_CDVDconfigure CDVDconfigure; -_CDVDtest CDVDtest; -_CDVDabout CDVDabout; -_CDVDnewDiskCB CDVDnewDiskCB; - -// DEV9 -_DEV9init DEV9init; -_DEV9open DEV9open; -_DEV9close DEV9close; -_DEV9shutdown DEV9shutdown; -_DEV9read8 DEV9read8; -_DEV9read16 DEV9read16; -_DEV9read32 DEV9read32; -_DEV9write8 DEV9write8; -_DEV9write16 DEV9write16; -_DEV9write32 DEV9write32; -_DEV9readDMA8Mem DEV9readDMA8Mem; -_DEV9writeDMA8Mem DEV9writeDMA8Mem; -_DEV9irqCallback DEV9irqCallback; -_DEV9irqHandler DEV9irqHandler; - -_DEV9configure DEV9configure; -_DEV9freeze DEV9freeze; -_DEV9test DEV9test; -_DEV9about DEV9about; - -// USB -_USBinit USBinit; -_USBopen USBopen; -_USBclose USBclose; -_USBshutdown USBshutdown; -_USBread8 USBread8; -_USBread16 USBread16; -_USBread32 USBread32; -_USBwrite8 USBwrite8; -_USBwrite16 USBwrite16; -_USBwrite32 USBwrite32; -_USBirqCallback USBirqCallback; -_USBirqHandler USBirqHandler; -_USBsetRAM USBsetRAM; - -_USBconfigure USBconfigure; -_USBfreeze USBfreeze; -_USBtest USBtest; -_USBabout USBabout; - -// FW -_FWinit FWinit; -_FWopen FWopen; -_FWclose FWclose; -_FWshutdown FWshutdown; -_FWread32 FWread32; -_FWwrite32 FWwrite32; -_FWirqCallback FWirqCallback; - -_FWconfigure FWconfigure; -_FWfreeze FWfreeze; -_FWtest FWtest; -_FWabout FWabout; -#endif - -#endif /* __PS2EDEFS_H__ */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + __WIN32__ (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + +/* common defines */ + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0004 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + int size; + s8 *data; +} freezeData; + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef __WIN32__ +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSwrite8(u32 mem, u8 value); +void CALLBACK GSwrite16(u32 mem, u16 value); +void CALLBACK GSwrite32(u32 mem, u32 value); +void CALLBACK GSwrite64(u32 mem, u64 value); +u8 CALLBACK GSread8(u32 mem); +u16 CALLBACK GSread16(u32 mem); +u32 CALLBACK GSread32(u32 mem); +u64 CALLBACK GSread64(u32 mem); +void CALLBACK GSreadFIFO(u64 *mem); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetCSR(u64 *csr); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef __WIN32__ +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +void CALLBACK SPU2irqCallback(void (*callback)()); + +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(); +typedef void (CALLBACK* _GSwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _GSwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _GSwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _GSwrite64)(u32 mem, u64 value); +typedef u8 (CALLBACK* _GSread8)(u32 mem); +typedef u16 (CALLBACK* _GSread16)(u32 mem); +typedef u32 (CALLBACK* _GSread32)(u32 mem); +typedef u64 (CALLBACK* _GSread64)(u32 mem); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetCSR)(u64 * csr); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef __WIN32__ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*callback)()); + +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSwrite8 GSwrite8; +_GSwrite16 GSwrite16; +_GSwrite32 GSwrite32; +_GSwrite64 GSwrite64; +_GSread8 GSread8; +_GSread16 GSread16; +_GSread32 GSread32; +_GSread64 GSread64; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSreadFIFO GSreadFIFO; + +_GSkeyEvent GSkeyEvent; +_GSmakeSnapshot GSmakeSnapshot; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetCSR GSsetCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef __WIN32__ +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/CDVDpeops/PS2Etypes.h b/plugins/CDVDpeops/PS2Etypes.h index 3a63c58b85..8855e172ce 100644 --- a/plugins/CDVDpeops/PS2Etypes.h +++ b/plugins/CDVDpeops/PS2Etypes.h @@ -1,43 +1,43 @@ -#ifndef __PS2ETYPES_H__ -#define __PS2ETYPES_H__ - -// Basic types -#if defined(__MSCW32__) - -typedef __int8 s8; -typedef __int16 s16; -typedef __int32 s32; -typedef __int64 s64; - -typedef unsigned __int8 u8; -typedef unsigned __int16 u16; -typedef unsigned __int32 u32; -typedef unsigned __int64 u64; - -#if defined(__x86_64__) -typedef u64 uptr; -#else -typedef u32 uptr; -#endif - -#elif defined(__LINUX__) || defined(__MINGW32__) - -typedef char s8; -typedef short s16; -typedef int s32; -typedef long long s64; - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long long u64; - -#if defined(__x86_64__) -typedef u64 uptr; -#else -typedef u32 uptr; -#endif - -#endif - -#endif /* __PS2ETYPES_H__ */ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +// Basic types +#if defined(__MSCW32__) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#elif defined(__LINUX__) || defined(__MINGW32__) + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#if defined(__x86_64__) +typedef u64 uptr; +#else +typedef u32 uptr; +#endif + +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/CDVDpeops/Scsi.c b/plugins/CDVDpeops/Scsi.c index 7f1f9e5460..90ee8b51dd 100644 --- a/plugins/CDVDpeops/Scsi.c +++ b/plugins/CDVDpeops/Scsi.c @@ -1,1134 +1,1134 @@ -/*************************************************************************** - scsi.c - description - ------------------- - begin : Sun Nov 16 2003 - copyright : (C) 2003 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2003/11/16 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -///////////////////////////////////////////////////////// - -#include "stdafx.h" -#define _IN_SCSI -#include "externals.h" - -///////////////////////////////////////////////////////// - -SRB_ExecSCSICmd sx; // used with all (non-waiting) read funcs -BOOL bDoWaiting=FALSE; // flag for async reads - -///////////////////////////////////////////////////////// -// returns device type - -int GetSCSIDevice(int iA,int iT,int iL) -{ - SRB_GDEVBlock s;DWORD dwStatus; - - memset(&s,0,sizeof(SRB_GDEVBlock)); - s.SRB_Cmd = SC_GET_DEV_TYPE; - s.SRB_HaID = iA; - s.SRB_Target = iT; - s.SRB_Lun = iL; - - ResetEvent(hEvent); - - dwStatus=pSendASPI32Command((LPSRB)&s); - - if(dwStatus==SS_PENDING) - {WaitGenEvent(30000);dwStatus=s.SRB_Status;} - - if(dwStatus==SS_COMP) return s.SRB_DeviceType; - - return -1; -} - -///////////////////////////////////////////////////////// - -int GetSCSIStatus(int iA,int iT,int iL) -{ - SRB_ExecSCSICmd s;DWORD dwStatus; - char ret[0x324]; - - memset(&s,0,sizeof(s)); - - s.SRB_Cmd = SC_EXEC_SCSI_CMD; - s.SRB_HaId = iCD_AD; - s.SRB_Target = iCD_TA; - s.SRB_Lun = iCD_LU; - s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; - s.SRB_BufLen = 0x324; - s.SRB_BufPointer = (BYTE FAR *)ret; - s.SRB_SenseLen = 0x0E; - s.SRB_CDBLen = 0x0A; - s.SRB_PostProc = (LPVOID)hEvent; - s.CDBByte[0] = 0x00; - - ResetEvent(hEvent); - dwStatus=pSendASPI32Command((LPSRB)&s); - - if(dwStatus==SS_PENDING) WaitGenEvent(30000); - - return s.SRB_Status; -} - -///////////////////////////////////////////////////////// -// fills toc infos - -DWORD GetSCSITOC(LPTOC toc) -{ - SRB_ExecSCSICmd s;DWORD dwStatus; - - memset(&s,0,sizeof(s)); - - s.SRB_Cmd = SC_EXEC_SCSI_CMD; - s.SRB_HaId = iCD_AD; - s.SRB_Target = iCD_TA; - s.SRB_Lun = iCD_LU; - s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; - s.SRB_BufLen = 0x324; - s.SRB_BufPointer = (BYTE FAR *)toc; - s.SRB_SenseLen = 0x0E; - s.SRB_CDBLen = 0x0A; - s.SRB_PostProc = (LPVOID)hEvent; - s.CDBByte[0] = 0x43; - s.CDBByte[1] = 0x00; // 0x02 for MSF - s.CDBByte[7] = 0x03; - s.CDBByte[8] = 0x24; - - ResetEvent(hEvent); - dwStatus=pSendASPI32Command((LPSRB)&s); - - if(dwStatus==SS_PENDING) WaitGenEvent(30000); - - if(s.SRB_Status!=SS_COMP) return SS_ERR; - - return SS_COMP; -} - -///////////////////////////////////////////////////////// -// enum all cd drives into 32k buffer, return num of drives - -int GetSCSICDDrives(char * pDList) -{ - int iCnt=0,iA,iT,iL;char * p=pDList; - SRB_HAInquiry si;SRB_GDEVBlock sd; - SRB_ExecSCSICmd s;int iNumA;char szBuf[100]; - DWORD dw,dwStatus; - - if(!pGetASPI32SupportInfo) return 0; - - dw=pGetASPI32SupportInfo(); - - if(HIBYTE(LOWORD(dw))!=SS_COMP) return 0; - iNumA=(int)LOBYTE(LOWORD(dw)); - - for(iA=0;iA> 24) & 0xFF); - s.CDBByte[3] = (unsigned char)((start >> 16) & 0xFF); - s.CDBByte[4] = (unsigned char)((start >> 8) & 0xFF); - s.CDBByte[5] = (unsigned char)((start & 0xFF)); - s.CDBByte[6] = (unsigned char)((len >> 24) & 0xFF); - s.CDBByte[7] = (unsigned char)((len >> 16) & 0xFF); - s.CDBByte[8] = (unsigned char)((len >> 8) & 0xFF); - s.CDBByte[9] = (unsigned char)(len & 0xFF); - } - - ResetEvent(hEvent); - - dwStatus = pSendASPI32Command((LPSRB)&s); - - if(dwStatus==SS_PENDING) WaitGenEvent(10000); - - return s.SRB_Status; -} - -///////////////////////////////////////////////////////// -// do (unprecise) sub channel read on audio play - -unsigned char * GetSCSIAudioSub(void) -{ - SRB_ExecSCSICmd s;DWORD dwStatus; - unsigned char cB[20]; - - memset(cB,0,20); - memset(&s,0,sizeof(s)); - - s.SRB_Cmd = SC_EXEC_SCSI_CMD; - s.SRB_HaId = iCD_AD; - s.SRB_Target = iCD_TA; - s.SRB_Lun = iCD_LU; - s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; - s.SRB_SenseLen = SENSE_LEN; - - s.SRB_BufLen = 20;//44; - s.SRB_BufPointer = cB; - s.SRB_CDBLen = 10; - - s.CDBByte[0] = 0x42; - s.CDBByte[1] = (iCD_LU<<5)|2; // lun & msf - s.CDBByte[2] = 0x40; // subq - s.CDBByte[3] = 0x01; // curr pos info - s.CDBByte[6] = 0; // track number (only in isrc mode, ignored) - s.CDBByte[7] = 0; // alloc len - s.CDBByte[8] = 20;//44; - - ResetEvent(hEvent); - - dwStatus = pSendASPI32Command((LPSRB)&s); - - if(dwStatus==SS_PENDING) WaitGenEvent(WAITFOREVER); - - if(s.SRB_Status!=SS_COMP) return NULL; - - SubAData[12]=(cB[5]<<4)|(cB[5]>>4); - SubAData[13]=cB[6]; - SubAData[14]=cB[7]; - SubAData[15]=itob(cB[13]); - SubAData[16]=itob(cB[14]); - SubAData[17]=itob(cB[15]); - SubAData[18]=0; - SubAData[19]=itob(cB[9]); - SubAData[20]=itob(cB[10]); - SubAData[21]=itob(cB[11]); - - return SubAData; -} - -///////////////////////////////////////////////////////// -// test, if drive is ready (doesn't work on all drives) - -BOOL TestSCSIUnitReady(void) -{ - SRB_ExecSCSICmd s;DWORD dwStatus; - - memset(&s,0,sizeof(s)); - s.SRB_Cmd = SC_EXEC_SCSI_CMD; - s.SRB_HaId = iCD_AD; - s.SRB_Target = iCD_TA; - s.SRB_Lun = iCD_LU; - s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; - s.SRB_BufLen = 0; - s.SRB_BufPointer = 0; - s.SRB_SenseLen = SENSE_LEN; - s.SRB_CDBLen = 6; - s.SRB_PostProc = (LPVOID)hEvent; - s.CDBByte[0] = 0x00; - s.CDBByte[1] = iCD_LU << 5; - - ResetEvent(hEvent); - dwStatus = pSendASPI32Command((LPSRB)&s); - - if(dwStatus==SS_PENDING) - WaitGenEvent(1000); - - if(s.SRB_Status!=SS_COMP) - return FALSE; - - if(s.SRB_TargStat==STATUS_GOOD) return TRUE; // will always be GOOD with ioctl, so no problem here - - return FALSE; -} - -///////////////////////////////////////////////////////// -// change the read speed (not supported on all drives) - -DWORD SetSCSISpeed(DWORD dwSpeed) -{ - SRB_ExecSCSICmd s;DWORD dwStatus; - - memset(&s,0,sizeof(s)); - - s.SRB_Cmd = SC_EXEC_SCSI_CMD; - s.SRB_HaId = iCD_AD; - s.SRB_Target = iCD_TA; - s.SRB_Lun = iCD_LU; - s.SRB_Flags = SRB_DIR_OUT | SRB_EVENT_NOTIFY; - s.SRB_SenseLen = SENSE_LEN; - s.SRB_CDBLen = 12; - s.SRB_PostProc = (LPVOID)hEvent; - s.CDBByte[0] = 0xBB; - s.CDBByte[2] = (BYTE)(dwSpeed >> 8); - s.CDBByte[3] = (BYTE)dwSpeed; - - ResetEvent(hEvent); - dwStatus=pSendASPI32Command((LPSRB)&s); - - if(dwStatus==SS_PENDING) - WaitGenEvent(WAITFOREVER); - - if(s.SRB_Status!=SS_COMP) return SS_ERR; - - return SS_COMP; -} - -///////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////// -// all the different SCSI read commands can be found here -// 'bWait' is a flag, if the command should wait until -// completed, or if the func can return as soon as possible -// (async reading). Attention: 'bWait' is not really used -// in the Sub-channel commands yet (sub is done always -// blocking, and just 'one sector' reads are done, caching=0) -///////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////// -// BE: used by most ATAPI drives -///////////////////////////////////////////////////////// - -DWORD ReadSCSI_BE(BOOL bWait,FRAMEBUF * f) -{ - DWORD dwStatus; - - memset(&sx,0,sizeof(sx)); - - sx.SRB_Cmd = SC_EXEC_SCSI_CMD; - sx.SRB_HaId = iCD_AD; - sx.SRB_Target = iCD_TA; - sx.SRB_Lun = iCD_LU; - sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; - sx.SRB_BufLen = f->dwBufLen; - sx.SRB_BufPointer = &(f->BufData[0]); - sx.SRB_SenseLen = SENSE_LEN; - sx.SRB_CDBLen = 12; - sx.SRB_PostProc = (LPVOID)hEvent; - sx.CDBByte[0] = 0xBE; - //s.CDBByte[1] = 0x04; - sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); - sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); - sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); - sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); - sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); - sx.CDBByte[9] = (iRType==MODE_BE_1)?0x10:0xF8;//F0!!!!!!!!!!! - - ResetEvent(hEvent); - dwStatus=pSendASPI32Command((LPSRB)&sx); - - if(dwStatus==SS_PENDING) - { - if(bWait) WaitGenEvent(WAITFOREVER); - else - { - bDoWaiting=TRUE; - return SS_COMP; - } - } - - if(sx.SRB_Status!=SS_COMP) - return SS_ERR; - - return SS_COMP; -} - -///////////////////////////////////////////////////////// - -DWORD ReadSCSI_BE_Sub(BOOL bWait,FRAMEBUF * f) -{ - DWORD dwStatus; - - memset(&sx,0,sizeof(sx)); - sx.SRB_Cmd = SC_EXEC_SCSI_CMD; - sx.SRB_HaId = iCD_AD; - sx.SRB_Target = iCD_TA; - sx.SRB_Lun = iCD_LU; - sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; - sx.SRB_BufLen = f->dwBufLen + 16; - sx.SRB_BufPointer = &(f->BufData[0]); - sx.SRB_SenseLen = SENSE_LEN; - sx.SRB_CDBLen = 12; - sx.SRB_PostProc = (LPVOID)hEvent; - sx.CDBByte[0] = 0xBE; - //s.CDBByte[1] = 0x04; - sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); - sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); - sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); - sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); - sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); - sx.CDBByte[9] = (iRType==MODE_BE_1)?0x10:0xF8;//F0!!!!!!!!!!! - sx.CDBByte[10] = 0x2; - - ResetEvent(hEvent ); - dwStatus=pSendASPI32Command((LPSRB)&sx); - - if(dwStatus==SS_PENDING) - WaitGenEvent(WAITSUB); - - if(sx.SRB_Status!=SS_COMP) - return SS_ERR; - - memcpy(&SubCData[12],&f->BufData[2352],16); - - SubCData[15]=itob(SubCData[15]); - SubCData[16]=itob(SubCData[16]); - SubCData[17]=itob(SubCData[17]); - - SubCData[19]=itob(SubCData[19]); - SubCData[20]=itob(SubCData[20]); - SubCData[21]=itob(SubCData[21]); - - return SS_COMP; -} - -///////////////////////////////////////////////////////// -// different sub reading for lite-on ltd163d... -// 16 bytes subc data is encoded in 96 bytes... - -DWORD ReadSCSI_BE_Sub_1(BOOL bWait,FRAMEBUF * f) -{ - DWORD dwStatus; - - memset(&sx,0,sizeof(sx)); - - sx.SRB_Cmd = SC_EXEC_SCSI_CMD; - sx.SRB_HaId = iCD_AD; - sx.SRB_Target = iCD_TA; - sx.SRB_Lun = iCD_LU; - sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; - sx.SRB_BufLen = f->dwBufLen + 96; - sx.SRB_BufPointer = &(f->BufData[0]); - sx.SRB_SenseLen = SENSE_LEN; - sx.SRB_CDBLen = 12; - sx.SRB_PostProc = (LPVOID)hEvent; - sx.CDBByte[0] = 0xBE; - sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); - sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); - sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); - sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); - sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); - sx.CDBByte[9] = 0xF8; - sx.CDBByte[10] = 0x1; - - ResetEvent(hEvent); - dwStatus=pSendASPI32Command((LPSRB)&sx); - - if(dwStatus==SS_PENDING) - WaitGenEvent(WAITSUB); - - if(sx.SRB_Status!=SS_COMP) - return SS_ERR; - - DecodeSub_BE_2_1(&f->BufData[2352]); - - memcpy(&SubCData[12],&f->BufData[2352],16); - - return SS_COMP; -} - -///////////////////////////////////////////////////////// -// 28: used by most SCSI drives -///////////////////////////////////////////////////////// - -DWORD InitSCSI_28_2(void) -{ - SRB_ExecSCSICmd s;DWORD dwStatus; - int i; - BYTE init1[] = { 0, 0, 0, 0x08, 0, 0, 0, 0, 0, 0, 0x09, 0x30, 0x23, 6, 0, 0, 0, 0, 0, 0x80 }; - BYTE init2[] = { 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 9, 48, 1, 6, 32, 7, 0, 0, 0, 0 }; - - for(i=0;i<2;i++) - { - memset( &s, 0, sizeof( s ) ); - s.SRB_Cmd = SC_EXEC_SCSI_CMD; - s.SRB_HaId = iCD_AD; - s.SRB_Target = iCD_TA; - s.SRB_Lun = iCD_LU; - s.SRB_Flags = SRB_EVENT_NOTIFY; - s.SRB_BufLen = 0x14; - s.SRB_BufPointer = (i==0)?init1:init2; - s.SRB_SenseLen = SENSE_LEN; - s.SRB_CDBLen = 6; - s.SRB_PostProc = (LPVOID)hEvent; - s.CDBByte[0] = 0x15; - s.CDBByte[1] = 0x10; - s.CDBByte[4] = 0x14; - - ResetEvent(hEvent); - - dwStatus=pSendASPI32Command((LPSRB)&s); - if (dwStatus == SS_PENDING) - WaitGenEvent(WAITFOREVER); - - if(s.SRB_Status!=SS_COMP) - return SS_ERR; - } - - pDeInitFunc = DeInitSCSI_28; - - return s.SRB_Status; -} - -///////////////////////////////////////////////////////// - -DWORD InitSCSI_28_1(void) -{ - SRB_ExecSCSICmd s;DWORD dwStatus; - BYTE init1[] = { 0, 0, 0, 0x08, 0, 0, 0, 0, 0, 0, 0x09, 0x30 }; - - memset(&s,0,sizeof(s)); - s.SRB_Cmd = SC_EXEC_SCSI_CMD; - s.SRB_HaId = iCD_AD; - s.SRB_Target = iCD_TA; - s.SRB_Lun = iCD_LU; - s.SRB_Flags = SRB_EVENT_NOTIFY; - s.SRB_BufLen = 0x0C; - s.SRB_BufPointer = init1; - s.SRB_SenseLen = SENSE_LEN; - s.SRB_CDBLen = 6; - s.SRB_PostProc = (LPVOID)hEvent; - s.CDBByte[0] = 0x15; - s.CDBByte[4] = 0x0C; - - ResetEvent(hEvent); - dwStatus=pSendASPI32Command((LPSRB)&s); - if(dwStatus==SS_PENDING) - WaitGenEvent(WAITFOREVER); - - if(s.SRB_Status!=SS_COMP) - return SS_ERR; - - pDeInitFunc = DeInitSCSI_28; - - return s.SRB_Status; -} - -///////////////////////////////////////////////////////// - -DWORD InitSCSI_28_2048(void) -{ - SRB_ExecSCSICmd s;DWORD dwStatus; - BYTE init1[] = { 0, 0, 0, 0x08, 0, 0, 0, 0, 0, 0, 0x08, 0x0 }; - - pDeInitFunc = DeInitSCSI_28; - - memset(&s,0,sizeof(s)); - s.SRB_Cmd = SC_EXEC_SCSI_CMD; - s.SRB_HaId = iCD_AD; - s.SRB_Target = iCD_TA; - s.SRB_Lun = iCD_LU; - s.SRB_Flags = SRB_EVENT_NOTIFY; - s.SRB_BufLen = 0x0C; - s.SRB_BufPointer = init1; - s.SRB_SenseLen = SENSE_LEN; - s.SRB_CDBLen = 6; - s.SRB_PostProc = (LPVOID)hEvent; - s.CDBByte[0] = 0x15; - s.CDBByte[4] = 0x0C; - - ResetEvent(hEvent); - dwStatus=pSendASPI32Command((LPSRB)&s); - if(dwStatus==SS_PENDING) - WaitGenEvent(WAITFOREVER); - - if(s.SRB_Status!=SS_COMP) - return SS_ERR; - - return s.SRB_Status; -} - -///////////////////////////////////////////////////////// - -DWORD DeInitSCSI_28(void) -{ - SRB_ExecSCSICmd s;DWORD dwStatus; - BYTE init1[] = { 0, 0, 0, 8, 83, 0, 0, 0, 0, 0, 8, 0 }; - - memset(&s,0,sizeof(s)); - s.SRB_Cmd = SC_EXEC_SCSI_CMD; - s.SRB_HaId = iCD_AD; - s.SRB_Target = iCD_TA; - s.SRB_Lun = iCD_LU; - s.SRB_Flags = SRB_EVENT_NOTIFY | SRB_ENABLE_RESIDUAL_COUNT; - s.SRB_BufLen = 0x0C; - s.SRB_BufPointer = init1; - s.SRB_SenseLen = SENSE_LEN; - s.SRB_CDBLen = 6; - s.SRB_PostProc = (LPVOID)hEvent; - s.CDBByte[0] = 0x15; - s.CDBByte[4] = 0x0C; - - ResetEvent(hEvent); - dwStatus=pSendASPI32Command((LPSRB)&s); - if(dwStatus==SS_PENDING) - WaitGenEvent(WAITFOREVER); - - if(s.SRB_Status!=SS_COMP) - return SS_ERR; - - return s.SRB_Status; -} - -///////////////////////////////////////////////////////// - -DWORD ReadSCSI_28(BOOL bWait,FRAMEBUF * f) -{ - DWORD dwStatus; - - if(!pDeInitFunc) - { - if(iRType==MODE_28_2) - { - if(InitSCSI_28_2()!=SS_COMP) return SS_ERR; - } - else - { - if(InitSCSI_28_1()!=SS_COMP) return SS_ERR; - } - } - - memset(&sx,0,sizeof(sx)); - sx.SRB_Cmd = SC_EXEC_SCSI_CMD; - sx.SRB_HaId = iCD_AD; - sx.SRB_Target = iCD_TA; - sx.SRB_Lun = iCD_LU; - sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; - sx.SRB_BufLen = f->dwBufLen; - sx.SRB_BufPointer = &(f->BufData[0]); - sx.SRB_SenseLen = SENSE_LEN; - sx.SRB_CDBLen = 10; - sx.SRB_PostProc = (LPVOID)hEvent; - sx.CDBByte[0] = 0x28; // read10 command - sx.CDBByte[1] = iCD_LU << 5; - sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); - sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); - sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); - sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); - sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); - - ResetEvent(hEvent); - dwStatus=pSendASPI32Command((LPSRB)&sx); - if(dwStatus==SS_PENDING) - { - if(bWait) WaitGenEvent(WAITFOREVER); - else - { - bDoWaiting=TRUE; - return SS_COMP; - } - } - - if(sx.SRB_Status!=SS_COMP) - return SS_ERR; - - return SS_COMP; -} - -///////////////////////////////////////////////////////// -// DVD MODE - -DWORD ReadSCSI_28_2048(BOOL bWait,FRAMEBUF * f) -{ - DWORD dwStatus; - - if(!pDeInitFunc) - { - InitSCSI_28_2048(); - - //if(InitSCSI_28_2048()!=SS_COMP) return SS_ERR; - } - - memset(&sx,0,sizeof(sx)); - sx.SRB_Cmd = SC_EXEC_SCSI_CMD; - sx.SRB_HaId = iCD_AD; - sx.SRB_Target = iCD_TA; - sx.SRB_Lun = iCD_LU; - sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; - sx.SRB_BufLen = f->dwBufLen; - sx.SRB_BufPointer = &(f->BufData[0]); - sx.SRB_SenseLen = SENSE_LEN; - sx.SRB_CDBLen = 10; - sx.SRB_PostProc = (LPVOID)hEvent; - sx.CDBByte[0] = 0x28; // read10 command - sx.CDBByte[1] = iCD_LU << 5; - sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); - sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); - sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); - sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); - sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); - sx.CDBByte[9] = 0xF8; - - ResetEvent(hEvent); - dwStatus=pSendASPI32Command((LPSRB)&sx); - if(dwStatus==SS_PENDING) - { - if(bWait) WaitGenEvent(WAITFOREVER); - else - { - bDoWaiting=TRUE; - return SS_COMP; - } - } - - if(sx.SRB_Status!=SS_COMP) - return SS_ERR; - - return SS_COMP; -} - -DWORD ReadSCSI_28_2048_Ex(BOOL bWait,FRAMEBUF * f) -{ - DWORD dwStatus; - - if(!pDeInitFunc) - { - InitSCSI_28_2048(); - - //if(InitSCSI_28_2048()!=SS_COMP) return SS_ERR; - } - - memset(&sx,0,sizeof(sx)); - sx.SRB_Cmd = SC_EXEC_SCSI_CMD; - sx.SRB_HaId = iCD_AD; - sx.SRB_Target = iCD_TA; - sx.SRB_Lun = iCD_LU; - sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; - sx.SRB_BufLen = f->dwBufLen; - sx.SRB_BufPointer = &(f->BufData[0]); - sx.SRB_SenseLen = SENSE_LEN; - sx.SRB_CDBLen = 10; - sx.SRB_PostProc = (LPVOID)hEvent; - sx.CDBByte[0] = 0x28; // read10 command - sx.CDBByte[1] = iCD_LU << 5; - sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); - sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); - sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); - sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); - sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); - // NO F8 - //sx.CDBByte[9] = 0xF8; - - ResetEvent(hEvent); - dwStatus=pSendASPI32Command((LPSRB)&sx); - if(dwStatus==SS_PENDING) - { - if(bWait) WaitGenEvent(WAITFOREVER); - else - { - bDoWaiting=TRUE; - return SS_COMP; - } - } - - if(sx.SRB_Status!=SS_COMP) - return SS_ERR; - - return SS_COMP; -} - - -///////////////////////////////////////////////////////// -// stupid subc reading on Teac 532S - -char tbuf[2368]; - -DWORD ReadSCSI_28_Sub(BOOL bWait,FRAMEBUF * f) -{ - DWORD dwStatus; - - if(!pDeInitFunc) - { - if(iRType==MODE_28_2) - { - if(InitSCSI_28_2()!=SS_COMP) return SS_ERR; - } - else - { - if(InitSCSI_28_1()!=SS_COMP) return SS_ERR; - } - } - - memset(&sx,0,sizeof(sx)); - sx.SRB_Cmd = SC_EXEC_SCSI_CMD; - sx.SRB_HaId = iCD_AD; - sx.SRB_Target = iCD_TA; - sx.SRB_Lun = iCD_LU; - sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; - sx.SRB_BufLen = f->dwBufLen; - sx.SRB_BufPointer = &(f->BufData[0]); - sx.SRB_SenseLen = SENSE_LEN; - sx.SRB_CDBLen = 10; - sx.SRB_PostProc = (LPVOID)hEvent; - sx.CDBByte[0] = 0x28; // read10 - sx.CDBByte[1] = iCD_LU << 5; - sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); - sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); - sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); - sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); - sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); - - ResetEvent(hEvent); - dwStatus=pSendASPI32Command((LPSRB)&sx); - if(dwStatus==SS_PENDING) - WaitGenEvent(WAITFOREVER); - - if(sx.SRB_Status!=SS_COMP) - return SS_ERR; - - memset(&sx,0,sizeof(sx)); - sx.SRB_Cmd = SC_EXEC_SCSI_CMD; - sx.SRB_HaId = iCD_AD; - sx.SRB_Target = iCD_TA; - sx.SRB_Lun = iCD_LU; - sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; - sx.SRB_BufLen = 2368; - sx.SRB_BufPointer = tbuf; - sx.SRB_SenseLen = SENSE_LEN; - sx.SRB_CDBLen = 12; - sx.SRB_PostProc = (LPVOID)hEvent; - sx.CDBByte[0] = 0xD8; - sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); - sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); - sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); - sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); - sx.CDBByte[9] = (unsigned char)(f->dwFrameCnt & 0xFF); - sx.CDBByte[10] = 1; - - ResetEvent(hEvent); - dwStatus=pSendASPI32Command((LPSRB)&sx); - if(dwStatus==SS_PENDING) - WaitGenEvent(WAITFOREVER); - - if(sx.SRB_Status!=SS_COMP) - return SS_ERR; - - memcpy(&SubCData[12],&tbuf[2352],16); - - return SS_COMP; -} - - -///////////////////////////////////////////////////////// -// various simple scsi sub data read funcs... used for -// ripping and subread checking... first 2352 bytes can -// be trash after read, only the bytes after are important -///////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////// - -int ReadSub_BE_2(unsigned long addr,unsigned char * pBuf,int iNum) -{ - DWORD dwStatus; - - memset(&sx,0,sizeof(sx)); - sx.SRB_Cmd = SC_EXEC_SCSI_CMD; - sx.SRB_HaId = iCD_AD; - sx.SRB_Target = iCD_TA; - sx.SRB_Lun = iCD_LU; - sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; - sx.SRB_BufLen = 2368*iNum; - sx.SRB_BufPointer = pBuf; - sx.SRB_SenseLen = SENSE_LEN; - sx.SRB_CDBLen = 12; - sx.SRB_PostProc = (LPVOID)hEvent; - sx.CDBByte[0] = 0xBE; - sx.CDBByte[2] = (unsigned char)((addr >> 24) & 0xFF); - sx.CDBByte[3] = (unsigned char)((addr >> 16) & 0xFF); - sx.CDBByte[4] = (unsigned char)((addr >> 8) & 0xFF); - sx.CDBByte[5] = (unsigned char)(addr & 0xFF); - sx.CDBByte[8] = iNum; - sx.CDBByte[9] = 0xF8; - sx.CDBByte[10] = 0x2; - - ResetEvent(hEvent); - dwStatus=pSendASPI32Command( (LPSRB)&sx ); - if(dwStatus==SS_PENDING) - WaitGenEvent(WAITSUB); - - if(sx.SRB_Status!=SS_COMP) - return 0; - - return 1; -} - -///////////////////////////////////////////////////////// - -int ReadSub_BE_2_1(unsigned long addr,unsigned char * pBuf,int iNum) -{ - DWORD dwStatus; - - memset(&sx,0,sizeof(sx)); - sx.SRB_Cmd = SC_EXEC_SCSI_CMD; - sx.SRB_HaId = iCD_AD; - sx.SRB_Target = iCD_TA; - sx.SRB_Lun = iCD_LU; - sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; - sx.SRB_BufLen = 2448*iNum; // special! 96 bytes instead of 16 - sx.SRB_BufPointer = pBuf; - sx.SRB_SenseLen = SENSE_LEN; - sx.SRB_CDBLen = 12; - sx.SRB_PostProc = (LPVOID)hEvent; - sx.CDBByte[0] = 0xBE; - sx.CDBByte[2] = (unsigned char)((addr >> 24) & 0xFF); - sx.CDBByte[3] = (unsigned char)((addr >> 16) & 0xFF); - sx.CDBByte[4] = (unsigned char)((addr >> 8) & 0xFF); - sx.CDBByte[5] = (unsigned char)(addr & 0xFF); - sx.CDBByte[8] = iNum; - sx.CDBByte[9] = 0xF8; - sx.CDBByte[10] = 0x1; - - ResetEvent(hEvent); - dwStatus=pSendASPI32Command((LPSRB)&sx); - if(dwStatus==SS_PENDING) - WaitGenEvent(WAITSUB); - - if(sx.SRB_Status!=SS_COMP) - return 0; - - return 1; -} - -///////////////////////////////////////////////////////// - -int ReadSub_D8(unsigned long addr,unsigned char * pBuf,int iNum) -{ - DWORD dwStatus; - - memset(&sx,0,sizeof(sx)); - sx.SRB_Cmd = SC_EXEC_SCSI_CMD; - sx.SRB_HaId = iCD_AD; - sx.SRB_Target = iCD_TA; - sx.SRB_Lun = iCD_LU; - sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; - sx.SRB_BufLen = 2368*iNum; - sx.SRB_BufPointer = pBuf; - sx.SRB_SenseLen = SENSE_LEN; - sx.SRB_CDBLen = 12; - sx.SRB_PostProc = (LPVOID)hEvent; - sx.CDBByte[0] = 0xD8; - sx.CDBByte[2] = (unsigned char)((addr >> 24) & 0xFF); - sx.CDBByte[3] = (unsigned char)((addr >> 16) & 0xFF); - sx.CDBByte[4] = (unsigned char)((addr >> 8) & 0xFF); - sx.CDBByte[5] = (unsigned char)(addr & 0xFF); - sx.CDBByte[9] = iNum; - sx.CDBByte[10] = 1; - - ResetEvent(hEvent); - dwStatus=pSendASPI32Command((LPSRB)&sx); - if(dwStatus==SS_PENDING) - WaitGenEvent(WAITFOREVER); - - if(sx.SRB_Status!=SS_COMP) - return 0; - - return 1; -} - -///////////////////////////////////////////////////////// -// liteon subdata decoding - -void DecodeSub_BE_2_1(unsigned char * pBuf) -{ - int i,j; - unsigned char * pS=pBuf; - unsigned char c; - - for(i=0;i<12;i++) - { - c=0; - for(j=7;j>=0;j--,pS++) - { - if(*pS & 0x40) c|=(1<dwFrame = 16; // we check on addr 16 (should be available on all ps2 cds/dvds) - f->dwFrameCnt = 1; - f->dwBufLen = iBlock[i]; - - pDeInitFunc = NULL; - iRType=iModes[i]; // set global read mode - GetGenReadFunc(iRType); // get read func pointer - - for(j=0;j<3;j++) // try it 3 times - { - memset(f->BufData,0xAA,f->dwBufLen); // fill buf with AA - dwStatus=pReadFunc(TRUE,f); // do the read - -#ifdef DBGOUT -auxprintf("status %d\n",dwStatus); -#endif - - if(dwStatus!=SS_COMP) continue; // error? try again - - p=&(f->BufData[0]); - -#ifdef DBGOUT -auxprintf("check mode %d\n",i); -#endif - - for(k=0,iCnt=0;k<(int)f->dwBufLen;k+=4,p+=4) // now check the returned data - { -#ifdef DBGOUT -// auxprintf("%08x ",*((DWORD *)p)); -#endif - - if(*((DWORD *)p)==0xAAAAAAAA) // -> still AA? bad - iCnt++; - else iCnt=0; - - if(iCnt>=8) {dwStatus=SS_ERR;break;} // -> if we have found many AA's, the reading was bad - } - - if(dwStatus==SS_COMP) // reading was a success, no AA's? - { - iRType = iModes[i]; // -> set found mode - iUsedBlockSize = iBlock[i]; - if(iUsedBlockSize==2352) - iUsedMode=CDVD_MODE_2352; - else iUsedMode=CDVD_MODE_2048; - -#ifdef DBGOUT -auxprintf("mode found %d\n",i); -#endif - - return dwStatus; // -> bye - } - } - if(pDeInitFunc) pDeInitFunc(); // deinit, try next mode - } - - return dwStatus; -} - -///////////////////////////////////////////////////////// -// dummy read dunc - -DWORD ReadSCSI_Dummy(BOOL bWait,FRAMEBUF * f) -{ - return SS_ERR; -} - -///////////////////////////////////////////////////////// +/*************************************************************************** + scsi.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#define _IN_SCSI +#include "externals.h" + +///////////////////////////////////////////////////////// + +SRB_ExecSCSICmd sx; // used with all (non-waiting) read funcs +BOOL bDoWaiting=FALSE; // flag for async reads + +///////////////////////////////////////////////////////// +// returns device type + +int GetSCSIDevice(int iA,int iT,int iL) +{ + SRB_GDEVBlock s;DWORD dwStatus; + + memset(&s,0,sizeof(SRB_GDEVBlock)); + s.SRB_Cmd = SC_GET_DEV_TYPE; + s.SRB_HaID = iA; + s.SRB_Target = iT; + s.SRB_Lun = iL; + + ResetEvent(hEvent); + + dwStatus=pSendASPI32Command((LPSRB)&s); + + if(dwStatus==SS_PENDING) + {WaitGenEvent(30000);dwStatus=s.SRB_Status;} + + if(dwStatus==SS_COMP) return s.SRB_DeviceType; + + return -1; +} + +///////////////////////////////////////////////////////// + +int GetSCSIStatus(int iA,int iT,int iL) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + char ret[0x324]; + + memset(&s,0,sizeof(s)); + + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = iCD_AD; + s.SRB_Target = iCD_TA; + s.SRB_Lun = iCD_LU; + s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + s.SRB_BufLen = 0x324; + s.SRB_BufPointer = (BYTE FAR *)ret; + s.SRB_SenseLen = 0x0E; + s.SRB_CDBLen = 0x0A; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0x00; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&s); + + if(dwStatus==SS_PENDING) WaitGenEvent(30000); + + return s.SRB_Status; +} + +///////////////////////////////////////////////////////// +// fills toc infos + +DWORD GetSCSITOC(LPTOC toc) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + + memset(&s,0,sizeof(s)); + + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = iCD_AD; + s.SRB_Target = iCD_TA; + s.SRB_Lun = iCD_LU; + s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + s.SRB_BufLen = 0x324; + s.SRB_BufPointer = (BYTE FAR *)toc; + s.SRB_SenseLen = 0x0E; + s.SRB_CDBLen = 0x0A; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0x43; + s.CDBByte[1] = 0x00; // 0x02 for MSF + s.CDBByte[7] = 0x03; + s.CDBByte[8] = 0x24; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&s); + + if(dwStatus==SS_PENDING) WaitGenEvent(30000); + + if(s.SRB_Status!=SS_COMP) return SS_ERR; + + return SS_COMP; +} + +///////////////////////////////////////////////////////// +// enum all cd drives into 32k buffer, return num of drives + +int GetSCSICDDrives(char * pDList) +{ + int iCnt=0,iA,iT,iL;char * p=pDList; + SRB_HAInquiry si;SRB_GDEVBlock sd; + SRB_ExecSCSICmd s;int iNumA;char szBuf[100]; + DWORD dw,dwStatus; + + if(!pGetASPI32SupportInfo) return 0; + + dw=pGetASPI32SupportInfo(); + + if(HIBYTE(LOWORD(dw))!=SS_COMP) return 0; + iNumA=(int)LOBYTE(LOWORD(dw)); + + for(iA=0;iA> 24) & 0xFF); + s.CDBByte[3] = (unsigned char)((start >> 16) & 0xFF); + s.CDBByte[4] = (unsigned char)((start >> 8) & 0xFF); + s.CDBByte[5] = (unsigned char)((start & 0xFF)); + s.CDBByte[6] = (unsigned char)((len >> 24) & 0xFF); + s.CDBByte[7] = (unsigned char)((len >> 16) & 0xFF); + s.CDBByte[8] = (unsigned char)((len >> 8) & 0xFF); + s.CDBByte[9] = (unsigned char)(len & 0xFF); + } + + ResetEvent(hEvent); + + dwStatus = pSendASPI32Command((LPSRB)&s); + + if(dwStatus==SS_PENDING) WaitGenEvent(10000); + + return s.SRB_Status; +} + +///////////////////////////////////////////////////////// +// do (unprecise) sub channel read on audio play + +unsigned char * GetSCSIAudioSub(void) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + unsigned char cB[20]; + + memset(cB,0,20); + memset(&s,0,sizeof(s)); + + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = iCD_AD; + s.SRB_Target = iCD_TA; + s.SRB_Lun = iCD_LU; + s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + s.SRB_SenseLen = SENSE_LEN; + + s.SRB_BufLen = 20;//44; + s.SRB_BufPointer = cB; + s.SRB_CDBLen = 10; + + s.CDBByte[0] = 0x42; + s.CDBByte[1] = (iCD_LU<<5)|2; // lun & msf + s.CDBByte[2] = 0x40; // subq + s.CDBByte[3] = 0x01; // curr pos info + s.CDBByte[6] = 0; // track number (only in isrc mode, ignored) + s.CDBByte[7] = 0; // alloc len + s.CDBByte[8] = 20;//44; + + ResetEvent(hEvent); + + dwStatus = pSendASPI32Command((LPSRB)&s); + + if(dwStatus==SS_PENDING) WaitGenEvent(WAITFOREVER); + + if(s.SRB_Status!=SS_COMP) return NULL; + + SubAData[12]=(cB[5]<<4)|(cB[5]>>4); + SubAData[13]=cB[6]; + SubAData[14]=cB[7]; + SubAData[15]=itob(cB[13]); + SubAData[16]=itob(cB[14]); + SubAData[17]=itob(cB[15]); + SubAData[18]=0; + SubAData[19]=itob(cB[9]); + SubAData[20]=itob(cB[10]); + SubAData[21]=itob(cB[11]); + + return SubAData; +} + +///////////////////////////////////////////////////////// +// test, if drive is ready (doesn't work on all drives) + +BOOL TestSCSIUnitReady(void) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + + memset(&s,0,sizeof(s)); + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = iCD_AD; + s.SRB_Target = iCD_TA; + s.SRB_Lun = iCD_LU; + s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + s.SRB_BufLen = 0; + s.SRB_BufPointer = 0; + s.SRB_SenseLen = SENSE_LEN; + s.SRB_CDBLen = 6; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0x00; + s.CDBByte[1] = iCD_LU << 5; + + ResetEvent(hEvent); + dwStatus = pSendASPI32Command((LPSRB)&s); + + if(dwStatus==SS_PENDING) + WaitGenEvent(1000); + + if(s.SRB_Status!=SS_COMP) + return FALSE; + + if(s.SRB_TargStat==STATUS_GOOD) return TRUE; // will always be GOOD with ioctl, so no problem here + + return FALSE; +} + +///////////////////////////////////////////////////////// +// change the read speed (not supported on all drives) + +DWORD SetSCSISpeed(DWORD dwSpeed) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + + memset(&s,0,sizeof(s)); + + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = iCD_AD; + s.SRB_Target = iCD_TA; + s.SRB_Lun = iCD_LU; + s.SRB_Flags = SRB_DIR_OUT | SRB_EVENT_NOTIFY; + s.SRB_SenseLen = SENSE_LEN; + s.SRB_CDBLen = 12; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0xBB; + s.CDBByte[2] = (BYTE)(dwSpeed >> 8); + s.CDBByte[3] = (BYTE)dwSpeed; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&s); + + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITFOREVER); + + if(s.SRB_Status!=SS_COMP) return SS_ERR; + + return SS_COMP; +} + +///////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////// +// all the different SCSI read commands can be found here +// 'bWait' is a flag, if the command should wait until +// completed, or if the func can return as soon as possible +// (async reading). Attention: 'bWait' is not really used +// in the Sub-channel commands yet (sub is done always +// blocking, and just 'one sector' reads are done, caching=0) +///////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////// +// BE: used by most ATAPI drives +///////////////////////////////////////////////////////// + +DWORD ReadSCSI_BE(BOOL bWait,FRAMEBUF * f) +{ + DWORD dwStatus; + + memset(&sx,0,sizeof(sx)); + + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = f->dwBufLen; + sx.SRB_BufPointer = &(f->BufData[0]); + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 12; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0xBE; + //s.CDBByte[1] = 0x04; + sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); + sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); + sx.CDBByte[9] = (iRType==MODE_BE_1)?0x10:0xF8;//F0!!!!!!!!!!! + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&sx); + + if(dwStatus==SS_PENDING) + { + if(bWait) WaitGenEvent(WAITFOREVER); + else + { + bDoWaiting=TRUE; + return SS_COMP; + } + } + + if(sx.SRB_Status!=SS_COMP) + return SS_ERR; + + return SS_COMP; +} + +///////////////////////////////////////////////////////// + +DWORD ReadSCSI_BE_Sub(BOOL bWait,FRAMEBUF * f) +{ + DWORD dwStatus; + + memset(&sx,0,sizeof(sx)); + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = f->dwBufLen + 16; + sx.SRB_BufPointer = &(f->BufData[0]); + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 12; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0xBE; + //s.CDBByte[1] = 0x04; + sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); + sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); + sx.CDBByte[9] = (iRType==MODE_BE_1)?0x10:0xF8;//F0!!!!!!!!!!! + sx.CDBByte[10] = 0x2; + + ResetEvent(hEvent ); + dwStatus=pSendASPI32Command((LPSRB)&sx); + + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITSUB); + + if(sx.SRB_Status!=SS_COMP) + return SS_ERR; + + memcpy(&SubCData[12],&f->BufData[2352],16); + + SubCData[15]=itob(SubCData[15]); + SubCData[16]=itob(SubCData[16]); + SubCData[17]=itob(SubCData[17]); + + SubCData[19]=itob(SubCData[19]); + SubCData[20]=itob(SubCData[20]); + SubCData[21]=itob(SubCData[21]); + + return SS_COMP; +} + +///////////////////////////////////////////////////////// +// different sub reading for lite-on ltd163d... +// 16 bytes subc data is encoded in 96 bytes... + +DWORD ReadSCSI_BE_Sub_1(BOOL bWait,FRAMEBUF * f) +{ + DWORD dwStatus; + + memset(&sx,0,sizeof(sx)); + + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = f->dwBufLen + 96; + sx.SRB_BufPointer = &(f->BufData[0]); + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 12; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0xBE; + sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); + sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); + sx.CDBByte[9] = 0xF8; + sx.CDBByte[10] = 0x1; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&sx); + + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITSUB); + + if(sx.SRB_Status!=SS_COMP) + return SS_ERR; + + DecodeSub_BE_2_1(&f->BufData[2352]); + + memcpy(&SubCData[12],&f->BufData[2352],16); + + return SS_COMP; +} + +///////////////////////////////////////////////////////// +// 28: used by most SCSI drives +///////////////////////////////////////////////////////// + +DWORD InitSCSI_28_2(void) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + int i; + BYTE init1[] = { 0, 0, 0, 0x08, 0, 0, 0, 0, 0, 0, 0x09, 0x30, 0x23, 6, 0, 0, 0, 0, 0, 0x80 }; + BYTE init2[] = { 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 9, 48, 1, 6, 32, 7, 0, 0, 0, 0 }; + + for(i=0;i<2;i++) + { + memset( &s, 0, sizeof( s ) ); + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = iCD_AD; + s.SRB_Target = iCD_TA; + s.SRB_Lun = iCD_LU; + s.SRB_Flags = SRB_EVENT_NOTIFY; + s.SRB_BufLen = 0x14; + s.SRB_BufPointer = (i==0)?init1:init2; + s.SRB_SenseLen = SENSE_LEN; + s.SRB_CDBLen = 6; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0x15; + s.CDBByte[1] = 0x10; + s.CDBByte[4] = 0x14; + + ResetEvent(hEvent); + + dwStatus=pSendASPI32Command((LPSRB)&s); + if (dwStatus == SS_PENDING) + WaitGenEvent(WAITFOREVER); + + if(s.SRB_Status!=SS_COMP) + return SS_ERR; + } + + pDeInitFunc = DeInitSCSI_28; + + return s.SRB_Status; +} + +///////////////////////////////////////////////////////// + +DWORD InitSCSI_28_1(void) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + BYTE init1[] = { 0, 0, 0, 0x08, 0, 0, 0, 0, 0, 0, 0x09, 0x30 }; + + memset(&s,0,sizeof(s)); + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = iCD_AD; + s.SRB_Target = iCD_TA; + s.SRB_Lun = iCD_LU; + s.SRB_Flags = SRB_EVENT_NOTIFY; + s.SRB_BufLen = 0x0C; + s.SRB_BufPointer = init1; + s.SRB_SenseLen = SENSE_LEN; + s.SRB_CDBLen = 6; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0x15; + s.CDBByte[4] = 0x0C; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&s); + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITFOREVER); + + if(s.SRB_Status!=SS_COMP) + return SS_ERR; + + pDeInitFunc = DeInitSCSI_28; + + return s.SRB_Status; +} + +///////////////////////////////////////////////////////// + +DWORD InitSCSI_28_2048(void) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + BYTE init1[] = { 0, 0, 0, 0x08, 0, 0, 0, 0, 0, 0, 0x08, 0x0 }; + + pDeInitFunc = DeInitSCSI_28; + + memset(&s,0,sizeof(s)); + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = iCD_AD; + s.SRB_Target = iCD_TA; + s.SRB_Lun = iCD_LU; + s.SRB_Flags = SRB_EVENT_NOTIFY; + s.SRB_BufLen = 0x0C; + s.SRB_BufPointer = init1; + s.SRB_SenseLen = SENSE_LEN; + s.SRB_CDBLen = 6; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0x15; + s.CDBByte[4] = 0x0C; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&s); + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITFOREVER); + + if(s.SRB_Status!=SS_COMP) + return SS_ERR; + + return s.SRB_Status; +} + +///////////////////////////////////////////////////////// + +DWORD DeInitSCSI_28(void) +{ + SRB_ExecSCSICmd s;DWORD dwStatus; + BYTE init1[] = { 0, 0, 0, 8, 83, 0, 0, 0, 0, 0, 8, 0 }; + + memset(&s,0,sizeof(s)); + s.SRB_Cmd = SC_EXEC_SCSI_CMD; + s.SRB_HaId = iCD_AD; + s.SRB_Target = iCD_TA; + s.SRB_Lun = iCD_LU; + s.SRB_Flags = SRB_EVENT_NOTIFY | SRB_ENABLE_RESIDUAL_COUNT; + s.SRB_BufLen = 0x0C; + s.SRB_BufPointer = init1; + s.SRB_SenseLen = SENSE_LEN; + s.SRB_CDBLen = 6; + s.SRB_PostProc = (LPVOID)hEvent; + s.CDBByte[0] = 0x15; + s.CDBByte[4] = 0x0C; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&s); + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITFOREVER); + + if(s.SRB_Status!=SS_COMP) + return SS_ERR; + + return s.SRB_Status; +} + +///////////////////////////////////////////////////////// + +DWORD ReadSCSI_28(BOOL bWait,FRAMEBUF * f) +{ + DWORD dwStatus; + + if(!pDeInitFunc) + { + if(iRType==MODE_28_2) + { + if(InitSCSI_28_2()!=SS_COMP) return SS_ERR; + } + else + { + if(InitSCSI_28_1()!=SS_COMP) return SS_ERR; + } + } + + memset(&sx,0,sizeof(sx)); + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = f->dwBufLen; + sx.SRB_BufPointer = &(f->BufData[0]); + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 10; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0x28; // read10 command + sx.CDBByte[1] = iCD_LU << 5; + sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); + sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&sx); + if(dwStatus==SS_PENDING) + { + if(bWait) WaitGenEvent(WAITFOREVER); + else + { + bDoWaiting=TRUE; + return SS_COMP; + } + } + + if(sx.SRB_Status!=SS_COMP) + return SS_ERR; + + return SS_COMP; +} + +///////////////////////////////////////////////////////// +// DVD MODE + +DWORD ReadSCSI_28_2048(BOOL bWait,FRAMEBUF * f) +{ + DWORD dwStatus; + + if(!pDeInitFunc) + { + InitSCSI_28_2048(); + + //if(InitSCSI_28_2048()!=SS_COMP) return SS_ERR; + } + + memset(&sx,0,sizeof(sx)); + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = f->dwBufLen; + sx.SRB_BufPointer = &(f->BufData[0]); + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 10; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0x28; // read10 command + sx.CDBByte[1] = iCD_LU << 5; + sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); + sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); + sx.CDBByte[9] = 0xF8; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&sx); + if(dwStatus==SS_PENDING) + { + if(bWait) WaitGenEvent(WAITFOREVER); + else + { + bDoWaiting=TRUE; + return SS_COMP; + } + } + + if(sx.SRB_Status!=SS_COMP) + return SS_ERR; + + return SS_COMP; +} + +DWORD ReadSCSI_28_2048_Ex(BOOL bWait,FRAMEBUF * f) +{ + DWORD dwStatus; + + if(!pDeInitFunc) + { + InitSCSI_28_2048(); + + //if(InitSCSI_28_2048()!=SS_COMP) return SS_ERR; + } + + memset(&sx,0,sizeof(sx)); + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = f->dwBufLen; + sx.SRB_BufPointer = &(f->BufData[0]); + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 10; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0x28; // read10 command + sx.CDBByte[1] = iCD_LU << 5; + sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); + sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); + // NO F8 + //sx.CDBByte[9] = 0xF8; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&sx); + if(dwStatus==SS_PENDING) + { + if(bWait) WaitGenEvent(WAITFOREVER); + else + { + bDoWaiting=TRUE; + return SS_COMP; + } + } + + if(sx.SRB_Status!=SS_COMP) + return SS_ERR; + + return SS_COMP; +} + + +///////////////////////////////////////////////////////// +// stupid subc reading on Teac 532S + +char tbuf[2368]; + +DWORD ReadSCSI_28_Sub(BOOL bWait,FRAMEBUF * f) +{ + DWORD dwStatus; + + if(!pDeInitFunc) + { + if(iRType==MODE_28_2) + { + if(InitSCSI_28_2()!=SS_COMP) return SS_ERR; + } + else + { + if(InitSCSI_28_1()!=SS_COMP) return SS_ERR; + } + } + + memset(&sx,0,sizeof(sx)); + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = f->dwBufLen; + sx.SRB_BufPointer = &(f->BufData[0]); + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 10; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0x28; // read10 + sx.CDBByte[1] = iCD_LU << 5; + sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); + sx.CDBByte[8] = (unsigned char)(f->dwFrameCnt & 0xFF); + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&sx); + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITFOREVER); + + if(sx.SRB_Status!=SS_COMP) + return SS_ERR; + + memset(&sx,0,sizeof(sx)); + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = 2368; + sx.SRB_BufPointer = tbuf; + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 12; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0xD8; + sx.CDBByte[2] = (unsigned char)((f->dwFrame >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((f->dwFrame >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((f->dwFrame >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(f->dwFrame & 0xFF); + sx.CDBByte[9] = (unsigned char)(f->dwFrameCnt & 0xFF); + sx.CDBByte[10] = 1; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&sx); + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITFOREVER); + + if(sx.SRB_Status!=SS_COMP) + return SS_ERR; + + memcpy(&SubCData[12],&tbuf[2352],16); + + return SS_COMP; +} + + +///////////////////////////////////////////////////////// +// various simple scsi sub data read funcs... used for +// ripping and subread checking... first 2352 bytes can +// be trash after read, only the bytes after are important +///////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////// + +int ReadSub_BE_2(unsigned long addr,unsigned char * pBuf,int iNum) +{ + DWORD dwStatus; + + memset(&sx,0,sizeof(sx)); + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = 2368*iNum; + sx.SRB_BufPointer = pBuf; + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 12; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0xBE; + sx.CDBByte[2] = (unsigned char)((addr >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((addr >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((addr >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(addr & 0xFF); + sx.CDBByte[8] = iNum; + sx.CDBByte[9] = 0xF8; + sx.CDBByte[10] = 0x2; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command( (LPSRB)&sx ); + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITSUB); + + if(sx.SRB_Status!=SS_COMP) + return 0; + + return 1; +} + +///////////////////////////////////////////////////////// + +int ReadSub_BE_2_1(unsigned long addr,unsigned char * pBuf,int iNum) +{ + DWORD dwStatus; + + memset(&sx,0,sizeof(sx)); + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = 2448*iNum; // special! 96 bytes instead of 16 + sx.SRB_BufPointer = pBuf; + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 12; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0xBE; + sx.CDBByte[2] = (unsigned char)((addr >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((addr >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((addr >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(addr & 0xFF); + sx.CDBByte[8] = iNum; + sx.CDBByte[9] = 0xF8; + sx.CDBByte[10] = 0x1; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&sx); + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITSUB); + + if(sx.SRB_Status!=SS_COMP) + return 0; + + return 1; +} + +///////////////////////////////////////////////////////// + +int ReadSub_D8(unsigned long addr,unsigned char * pBuf,int iNum) +{ + DWORD dwStatus; + + memset(&sx,0,sizeof(sx)); + sx.SRB_Cmd = SC_EXEC_SCSI_CMD; + sx.SRB_HaId = iCD_AD; + sx.SRB_Target = iCD_TA; + sx.SRB_Lun = iCD_LU; + sx.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY; + sx.SRB_BufLen = 2368*iNum; + sx.SRB_BufPointer = pBuf; + sx.SRB_SenseLen = SENSE_LEN; + sx.SRB_CDBLen = 12; + sx.SRB_PostProc = (LPVOID)hEvent; + sx.CDBByte[0] = 0xD8; + sx.CDBByte[2] = (unsigned char)((addr >> 24) & 0xFF); + sx.CDBByte[3] = (unsigned char)((addr >> 16) & 0xFF); + sx.CDBByte[4] = (unsigned char)((addr >> 8) & 0xFF); + sx.CDBByte[5] = (unsigned char)(addr & 0xFF); + sx.CDBByte[9] = iNum; + sx.CDBByte[10] = 1; + + ResetEvent(hEvent); + dwStatus=pSendASPI32Command((LPSRB)&sx); + if(dwStatus==SS_PENDING) + WaitGenEvent(WAITFOREVER); + + if(sx.SRB_Status!=SS_COMP) + return 0; + + return 1; +} + +///////////////////////////////////////////////////////// +// liteon subdata decoding + +void DecodeSub_BE_2_1(unsigned char * pBuf) +{ + int i,j; + unsigned char * pS=pBuf; + unsigned char c; + + for(i=0;i<12;i++) + { + c=0; + for(j=7;j>=0;j--,pS++) + { + if(*pS & 0x40) c|=(1<dwFrame = 16; // we check on addr 16 (should be available on all ps2 cds/dvds) + f->dwFrameCnt = 1; + f->dwBufLen = iBlock[i]; + + pDeInitFunc = NULL; + iRType=iModes[i]; // set global read mode + GetGenReadFunc(iRType); // get read func pointer + + for(j=0;j<3;j++) // try it 3 times + { + memset(f->BufData,0xAA,f->dwBufLen); // fill buf with AA + dwStatus=pReadFunc(TRUE,f); // do the read + +#ifdef DBGOUT +auxprintf("status %d\n",dwStatus); +#endif + + if(dwStatus!=SS_COMP) continue; // error? try again + + p=&(f->BufData[0]); + +#ifdef DBGOUT +auxprintf("check mode %d\n",i); +#endif + + for(k=0,iCnt=0;k<(int)f->dwBufLen;k+=4,p+=4) // now check the returned data + { +#ifdef DBGOUT +// auxprintf("%08x ",*((DWORD *)p)); +#endif + + if(*((DWORD *)p)==0xAAAAAAAA) // -> still AA? bad + iCnt++; + else iCnt=0; + + if(iCnt>=8) {dwStatus=SS_ERR;break;} // -> if we have found many AA's, the reading was bad + } + + if(dwStatus==SS_COMP) // reading was a success, no AA's? + { + iRType = iModes[i]; // -> set found mode + iUsedBlockSize = iBlock[i]; + if(iUsedBlockSize==2352) + iUsedMode=CDVD_MODE_2352; + else iUsedMode=CDVD_MODE_2048; + +#ifdef DBGOUT +auxprintf("mode found %d\n",i); +#endif + + return dwStatus; // -> bye + } + } + if(pDeInitFunc) pDeInitFunc(); // deinit, try next mode + } + + return dwStatus; +} + +///////////////////////////////////////////////////////// +// dummy read dunc + +DWORD ReadSCSI_Dummy(BOOL bWait,FRAMEBUF * f) +{ + return SS_ERR; +} + +///////////////////////////////////////////////////////// diff --git a/plugins/CDVDpeops/StdAfx.c b/plugins/CDVDpeops/StdAfx.c index cf47398ca1..9c51841468 100644 --- a/plugins/CDVDpeops/StdAfx.c +++ b/plugins/CDVDpeops/StdAfx.c @@ -1,8 +1,8 @@ -// stdafx.cpp : source file that includes just the standard includes -// cdvdPeops.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" - -// reference any additional headers you need in STDAFX.H -// and not in this file +// stdafx.cpp : source file that includes just the standard includes +// cdvdPeops.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/plugins/CDVDpeops/StdAfx.h b/plugins/CDVDpeops/StdAfx.h index d0b6fbb405..c51aa64095 100644 --- a/plugins/CDVDpeops/StdAfx.h +++ b/plugins/CDVDpeops/StdAfx.h @@ -1,82 +1,82 @@ -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, but -// are changed infrequently -// - -#if !defined(AFX_STDAFX_H__A412EBA3_CBB9_11D6_A315_008048C61B72__INCLUDED_) -#define AFX_STDAFX_H__A412EBA3_CBB9_11D6_A315_008048C61B72__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#ifdef _GCC -#define EXPORT_GCC __declspec (dllexport) -#else -#define EXPORT_GCC -#endif - -// Insert your headers here -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// special setup for MinGW/Dev-C++ ################### // -// (I don't want to change PS2Edefs.h/PS2Etypes.h) - -#undef __WIN32__ - -typedef char s8; -typedef short s16; -typedef long s32; -#ifdef _GCC -typedef long long s64; -#else -typedef __int64 s64; -#endif - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned long u32; -#ifdef _GCC -typedef unsigned long long u64; -#else -typedef unsigned __int64 u64; -#endif - -#include "PS2Edefs.h" - -#define __WIN32__ - -// ################################################### // - - -#include "wnaspi32.h" -#include "scsidefs.h" - -#include "defines.h" -#include "cdda.h" -#include "cdr.h" -#include "cfg.h" -#include "generic.h" -#include "ioctrl.h" -#include "ppf.h" -#include "read.h" -#include "scsi.h" -#include "sub.h" -#include "toc.h" - -//#define DBGOUT - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_STDAFX_H__A412EBA3_CBB9_11D6_A315_008048C61B72__INCLUDED_) +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__A412EBA3_CBB9_11D6_A315_008048C61B72__INCLUDED_) +#define AFX_STDAFX_H__A412EBA3_CBB9_11D6_A315_008048C61B72__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifdef _GCC +#define EXPORT_GCC __declspec (dllexport) +#else +#define EXPORT_GCC +#endif + +// Insert your headers here +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// special setup for MinGW/Dev-C++ ################### // +// (I don't want to change PS2Edefs.h/PS2Etypes.h) + +#undef __WIN32__ + +typedef char s8; +typedef short s16; +typedef long s32; +#ifdef _GCC +typedef long long s64; +#else +typedef __int64 s64; +#endif + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; +#ifdef _GCC +typedef unsigned long long u64; +#else +typedef unsigned __int64 u64; +#endif + +#include "PS2Edefs.h" + +#define __WIN32__ + +// ################################################### // + + +#include "wnaspi32.h" +#include "scsidefs.h" + +#include "defines.h" +#include "cdda.h" +#include "cdr.h" +#include "cfg.h" +#include "generic.h" +#include "ioctrl.h" +#include "ppf.h" +#include "read.h" +#include "scsi.h" +#include "sub.h" +#include "toc.h" + +//#define DBGOUT + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__A412EBA3_CBB9_11D6_A315_008048C61B72__INCLUDED_) diff --git a/plugins/CDVDpeops/cdda.c b/plugins/CDVDpeops/cdda.c index dc0180b59a..184fb299a4 100644 --- a/plugins/CDVDpeops/cdda.c +++ b/plugins/CDVDpeops/cdda.c @@ -1,80 +1,80 @@ -/*************************************************************************** - cdda.c - description - ------------------- - begin : Wed Sep 18 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/09/19 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -///////////////////////////////////////////////////////// - -#include "stdafx.h" -#define _IN_CDDA -#include "externals.h" - -///////////////////////////////////////////////////////// -// starts/stops audio playing (addr==0 -> stop) -// note: no cdda support in PS2 plugins yet - -BOOL DoCDDAPlay(unsigned long addr) -{ - DWORD dw; - - LockGenCDAccess(); - - if(addr) dw=PlaySCSIAudio(addr,lMaxAddr-addr); // start playing (til end of cd) -// mmm... this stop doesn't work right -// else dw=PlayFunc(0,1); - else // funny stop... but seems to work - { - unsigned char cdb[3000]; - FRAMEBUF * f=(FRAMEBUF *)cdb; - - f->dwFrame = 16; // -> use an existing address (16 will ever exist on ps2 cds/dvds) - f->dwFrameCnt = 1; - f->dwBufLen = 2352; - - dw=pReadFunc(1,f); // -> do a simply sync read... seems to stop all audio playing - } - - UnlockGenCDAccess(); - - if(dw!=SS_COMP) return FALSE; - return TRUE; -} - -///////////////////////////////////////////////////////// -// get curr playing pos - -unsigned char * GetCDDAPlayPosition(void) -{ - unsigned char * pos; - - LockGenCDAccess(); - - pos=GetSCSIAudioSub(); // get the pos (scsi command) - - UnlockGenCDAccess(); - - return pos; -} - -///////////////////////////////////////////////////////// +/*************************************************************************** + cdda.c - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#define _IN_CDDA +#include "externals.h" + +///////////////////////////////////////////////////////// +// starts/stops audio playing (addr==0 -> stop) +// note: no cdda support in PS2 plugins yet + +BOOL DoCDDAPlay(unsigned long addr) +{ + DWORD dw; + + LockGenCDAccess(); + + if(addr) dw=PlaySCSIAudio(addr,lMaxAddr-addr); // start playing (til end of cd) +// mmm... this stop doesn't work right +// else dw=PlayFunc(0,1); + else // funny stop... but seems to work + { + unsigned char cdb[3000]; + FRAMEBUF * f=(FRAMEBUF *)cdb; + + f->dwFrame = 16; // -> use an existing address (16 will ever exist on ps2 cds/dvds) + f->dwFrameCnt = 1; + f->dwBufLen = 2352; + + dw=pReadFunc(1,f); // -> do a simply sync read... seems to stop all audio playing + } + + UnlockGenCDAccess(); + + if(dw!=SS_COMP) return FALSE; + return TRUE; +} + +///////////////////////////////////////////////////////// +// get curr playing pos + +unsigned char * GetCDDAPlayPosition(void) +{ + unsigned char * pos; + + LockGenCDAccess(); + + pos=GetSCSIAudioSub(); // get the pos (scsi command) + + UnlockGenCDAccess(); + + return pos; +} + +///////////////////////////////////////////////////////// diff --git a/plugins/CDVDpeops/cdda.h b/plugins/CDVDpeops/cdda.h index b51a8d9171..3789bb2a4c 100644 --- a/plugins/CDVDpeops/cdda.h +++ b/plugins/CDVDpeops/cdda.h @@ -1,28 +1,28 @@ -/*************************************************************************** - cdda.h - description - ------------------- - begin : Wed Sep 18 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/09/19 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -BOOL DoCDDAPlay(unsigned long addr); -unsigned char * GetCDDAPlayPosition(void); +/*************************************************************************** + cdda.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +BOOL DoCDDAPlay(unsigned long addr); +unsigned char * GetCDDAPlayPosition(void); diff --git a/plugins/CDVDpeops/cdr.h b/plugins/CDVDpeops/cdr.h index 97492cf620..9d6025b786 100644 --- a/plugins/CDVDpeops/cdr.h +++ b/plugins/CDVDpeops/cdr.h @@ -1,27 +1,27 @@ -/*************************************************************************** - cdr.h - description - ------------------- - begin : Wed Sep 18 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/09/19 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -// nothing yet +/*************************************************************************** + cdr.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +// nothing yet diff --git a/plugins/CDVDpeops/cdvdPeops.c b/plugins/CDVDpeops/cdvdPeops.c index a1e5c04966..c1bbf50831 100644 --- a/plugins/CDVDpeops/cdvdPeops.c +++ b/plugins/CDVDpeops/cdvdPeops.c @@ -1,89 +1,89 @@ -/*************************************************************************** - cdvdPeops.c - description - ------------------- - begin : Sun Nov 16 2003 - copyright : (C) 2003 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2003/11/16 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -// cdrPeops.cpp : Defines the entry point for the DLL application. -// - -#include "stdafx.h" -#include "cdvdPeops.h" -#define _IN_PEOPS -#include "externals.h" - -///////////////////////////////////////////////////////// - -HINSTANCE hInst=0; - -///////////////////////////////////////////////////////// -// get selected interface mode from registry: needed, -// if user has w2k and aspi available, so the plugin -// can know, what he wants to use - -int iGetUserInterfaceMode(void) -{ - HKEY myKey;DWORD temp;DWORD type;DWORD size; - int iRet=0; - - if(RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\PS2Eplugin\\CDVD\\CDVDPeops",0,KEY_ALL_ACCESS,&myKey)==ERROR_SUCCESS) - { - size = 4; - if(RegQueryValueEx(myKey,"InterfaceMode",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iRet=(int)temp; - RegCloseKey(myKey); - } - return iRet; -} - -///////////////////////////////////////////////////////// -// dll entry point - -BOOL APIENTRY DllMain(HANDLE hModule, - DWORD ul_reason_for_call, - LPVOID lpReserved) -{ - hInst=(HINSTANCE)hModule; - - switch (ul_reason_for_call) - {//--------------------------------------------------// - case DLL_PROCESS_ATTACH: - iInterfaceMode=iGetUserInterfaceMode(); // get interface on startup - OpenGenInterface(); // open interface (can be changed in the config window) - break; - //--------------------------------------------------// - case DLL_PROCESS_DETACH: - CloseGenInterface(); // close interface - break; - //--------------------------------------------------// - case DLL_THREAD_ATTACH: - break; - //--------------------------------------------------// - case DLL_THREAD_DETACH: - break; - //--------------------------------------------------// - } - return TRUE; -} - -///////////////////////////////////////////////////////// +/*************************************************************************** + cdvdPeops.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +// cdrPeops.cpp : Defines the entry point for the DLL application. +// + +#include "stdafx.h" +#include "cdvdPeops.h" +#define _IN_PEOPS +#include "externals.h" + +///////////////////////////////////////////////////////// + +HINSTANCE hInst=0; + +///////////////////////////////////////////////////////// +// get selected interface mode from registry: needed, +// if user has w2k and aspi available, so the plugin +// can know, what he wants to use + +int iGetUserInterfaceMode(void) +{ + HKEY myKey;DWORD temp;DWORD type;DWORD size; + int iRet=0; + + if(RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\PS2Eplugin\\CDVD\\CDVDPeops",0,KEY_ALL_ACCESS,&myKey)==ERROR_SUCCESS) + { + size = 4; + if(RegQueryValueEx(myKey,"InterfaceMode",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iRet=(int)temp; + RegCloseKey(myKey); + } + return iRet; +} + +///////////////////////////////////////////////////////// +// dll entry point + +BOOL APIENTRY DllMain(HANDLE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved) +{ + hInst=(HINSTANCE)hModule; + + switch (ul_reason_for_call) + {//--------------------------------------------------// + case DLL_PROCESS_ATTACH: + iInterfaceMode=iGetUserInterfaceMode(); // get interface on startup + OpenGenInterface(); // open interface (can be changed in the config window) + break; + //--------------------------------------------------// + case DLL_PROCESS_DETACH: + CloseGenInterface(); // close interface + break; + //--------------------------------------------------// + case DLL_THREAD_ATTACH: + break; + //--------------------------------------------------// + case DLL_THREAD_DETACH: + break; + //--------------------------------------------------// + } + return TRUE; +} + +///////////////////////////////////////////////////////// diff --git a/plugins/CDVDpeops/cdvdPeops.h b/plugins/CDVDpeops/cdvdPeops.h index 87d277e88a..2113c17558 100644 --- a/plugins/CDVDpeops/cdvdPeops.h +++ b/plugins/CDVDpeops/cdvdPeops.h @@ -1,25 +1,25 @@ -/*************************************************************************** - cdvdPeops.h - description - ------------------- - begin : Wed Nov 12 2003 - copyright : (C) 2003 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/09/19 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// +/*************************************************************************** + cdvdPeops.h - description + ------------------- + begin : Wed Nov 12 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// diff --git a/plugins/CDVDpeops/cdvdPeops_private.h b/plugins/CDVDpeops/cdvdPeops_private.h index 18a8395542..e110b93fab 100644 --- a/plugins/CDVDpeops/cdvdPeops_private.h +++ b/plugins/CDVDpeops/cdvdPeops_private.h @@ -1,23 +1,23 @@ -// THIS FILE WILL BE OVERWRITTEN BY DEV-C++! -// DO NOT EDIT! - -#ifndef CDVDPEOPS_PRIVATE_H -#define CDVDPEOPS_PRIVATE_H - -// VERSION DEFINITIONS -#define VER_STRING "0.1.1.1" -#define VER_MAJOR 0 -#define VER_MINOR 1 -#define VER_RELEASE 1 -#define VER_BUILD 1 -#define COMPANY_NAME "" -#define FILE_VERSION "0.1" -#define FILE_DESCRIPTION "Developed using the Dev-C++ IDE" -#define INTERNAL_NAME "" -#define LEGAL_COPYRIGHT "" -#define LEGAL_TRADEMARKS "" -#define ORIGINAL_FILENAME "cdvdPeops.exe" -#define PRODUCT_NAME "cdvdPeops" -#define PRODUCT_VERSION "0.1" - -#endif //CDVDPEOPS_PRIVATE_H +// THIS FILE WILL BE OVERWRITTEN BY DEV-C++! +// DO NOT EDIT! + +#ifndef CDVDPEOPS_PRIVATE_H +#define CDVDPEOPS_PRIVATE_H + +// VERSION DEFINITIONS +#define VER_STRING "0.1.1.1" +#define VER_MAJOR 0 +#define VER_MINOR 1 +#define VER_RELEASE 1 +#define VER_BUILD 1 +#define COMPANY_NAME "" +#define FILE_VERSION "0.1" +#define FILE_DESCRIPTION "Developed using the Dev-C++ IDE" +#define INTERNAL_NAME "" +#define LEGAL_COPYRIGHT "" +#define LEGAL_TRADEMARKS "" +#define ORIGINAL_FILENAME "cdvdPeops.exe" +#define PRODUCT_NAME "cdvdPeops" +#define PRODUCT_VERSION "0.1" + +#endif //CDVDPEOPS_PRIVATE_H diff --git a/plugins/CDVDpeops/cfg.h b/plugins/CDVDpeops/cfg.h index dfa285b4d5..61fdfb08b7 100644 --- a/plugins/CDVDpeops/cfg.h +++ b/plugins/CDVDpeops/cfg.h @@ -1,47 +1,47 @@ -/*************************************************************************** - cfg.h - description - ------------------- - begin : Wed Sep 18 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/09/19 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -void ReadConfig(void); -void WriteConfig(void); -void OnChooseFile(HWND hW,int iFType); -void EnumDrives(HWND hW); -void GetCDRInfos(HWND hW,int * iA, int * iT,int * iL); -void OnIMode(HWND hW); -void OnCache(HWND hW); -void ShowSubFileStuff(HWND hW); -BOOL OnInitCDRDialog(HWND hW); -void OnCDRAuto(HWND hW); -void ShowProgress(HWND hW,long lact,long lmin,long lmax); -void WriteDiffSub(FILE * xfile,int i,unsigned char * lpX,int iM,BOOL b3Min); -BOOL OnCreateSubFileEx(HWND hW,HWND hWX,BOOL b3Min); -BOOL OnCreateSubEx(HWND hW,HWND hWX,int iM,BOOL b3Min); -void StartSubReading(HWND hW,HWND hWX); -BOOL CALLBACK SubDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); -void OnCreateSub(HWND hW); -void OnCDROK(HWND hW); -void OnCDRCancel(HWND hW); -BOOL CALLBACK CDRDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); -BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); +/*************************************************************************** + cfg.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +void ReadConfig(void); +void WriteConfig(void); +void OnChooseFile(HWND hW,int iFType); +void EnumDrives(HWND hW); +void GetCDRInfos(HWND hW,int * iA, int * iT,int * iL); +void OnIMode(HWND hW); +void OnCache(HWND hW); +void ShowSubFileStuff(HWND hW); +BOOL OnInitCDRDialog(HWND hW); +void OnCDRAuto(HWND hW); +void ShowProgress(HWND hW,long lact,long lmin,long lmax); +void WriteDiffSub(FILE * xfile,int i,unsigned char * lpX,int iM,BOOL b3Min); +BOOL OnCreateSubFileEx(HWND hW,HWND hWX,BOOL b3Min); +BOOL OnCreateSubEx(HWND hW,HWND hWX,int iM,BOOL b3Min); +void StartSubReading(HWND hW,HWND hWX); +BOOL CALLBACK SubDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); +void OnCreateSub(HWND hW); +void OnCDROK(HWND hW); +void OnCDRCancel(HWND hW); +BOOL CALLBACK CDRDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); diff --git a/plugins/CDVDpeops/defines.h b/plugins/CDVDpeops/defines.h index 5ead0e7501..730165851a 100644 --- a/plugins/CDVDpeops/defines.h +++ b/plugins/CDVDpeops/defines.h @@ -1,212 +1,212 @@ -/*************************************************************************** - defines.h - description - ------------------- - begin : Wed Sep 18 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/09/19 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -///////////////////////////////////////////////////////// - -// general buffer for reading several frames - -#pragma pack(1) - -typedef struct _FRAMEBUF -{ - DWORD dwFrame; - DWORD dwFrameCnt; - DWORD dwBufLen; - unsigned char BufData[1024*1024]; -} FRAMEBUF; - -#pragma pack() - -// raw ioctl structs: - -typedef enum _TRACK_MODE_TYPE -{ - YellowMode2, - XAForm2, - CDDA -} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE; - -typedef struct _RAW_READ_INFO -{ - LARGE_INTEGER DiskOffset; - ULONG SectorCount; - TRACK_MODE_TYPE TrackMode; -} RAW_READ_INFO, *PRAW_READ_INFO; - -// sub cache: - -typedef struct -{ - long addr; - void * pNext; - unsigned char subq[10]; -} SUB_DATA; - -typedef struct -{ - long addr; - void * pNext; -} SUB_CACHE; - -// ppf cache: - -typedef struct -{ - long addr; - void * pNext; - long pos; - long anz; - // memdata -} PPF_DATA; - -typedef struct -{ - long addr; - void * pNext; -} PPF_CACHE; - -///////////////////////////////////////////////////////// - -#define MODE_BE_1 1 -#define MODE_BE_2 2 -#define MODE_28_1 3 -#define MODE_28_2 4 -#define MODE_28_2048 5 -#define MODE_28_2048_Ex 6 - -#define itob(i) ((i)/10*16 + (i)%10) -#define btoi(b) ((b)/16*10 + (b)%16) -#define itod(i) ((((i)/10)<<4) + ((i)%10)) -#define dtoi(b) ((((b)>>4)&0xf)*10 + (((b)&0xf)%10)) - -///////////////////////////////////////////////////////// - -void addr2time(unsigned long addr, unsigned char *time); -void addr2timeB(unsigned long addr, unsigned char *time); -unsigned long time2addr(unsigned char *time); -unsigned long time2addrB(unsigned char *time); -#ifdef _GCC -#define reOrder i386_reOrder -#endif -unsigned long reOrder(unsigned long value); - -///////////////////////////////////////////////////////// -// debug helper - -#ifndef _IN_CDR -#ifdef DBGOUT -void auxprintf (LPCTSTR pFormat, ...); -#endif -#endif - -///////////////////////////////////////////////////////// - -typedef DWORD (*READFUNC)(BOOL bWait,FRAMEBUF * f); -typedef DWORD (*DEINITFUNC)(void); -typedef BOOL (*READTRACKFUNC)(unsigned long addr); -typedef void (*GETPTRFUNC)(void); - -///////////////////////////////////////////////////////// - -#define WAITFOREVER 0xFFFFFFFF -#define WAITSUB 10000 -#define FRAMEBUFEXTRA 12 -#define CDSECTOR 2352 -#define MAXCACHEBLOCK 26 -#define MAXCDBUFFER (((MAXCACHEBLOCK+1)*(CDSECTOR+16))+240) - -///////////////////////////////////////////////////////// - -/* some structs from libcdvd by Hiryu & Sjeep (C) 2002 */ - -#pragma pack(1) - -struct rootDirTocHeader -{ - u16 length; //+00 - u32 tocLBA; //+02 - u32 tocLBA_bigend; //+06 - u32 tocSize; //+0A - u32 tocSize_bigend; //+0E - u8 dateStamp[8]; //+12 - u8 reserved[6]; //+1A - u8 reserved2; //+20 - u8 reserved3; //+21 -}; //+22 - -struct asciiDate -{ - char year[4]; - char month[2]; - char day[2]; - char hours[2]; - char minutes[2]; - char seconds[2]; - char hundreths[2]; - char terminator[1]; -}; - -struct cdVolDesc -{ - u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL - u8 volID[5]; // "CD001" - u8 reserved2; - u8 reserved3; - u8 sysIdName[32]; - u8 volName[32]; // The ISO9660 Volume Name - u8 reserved5[8]; - u32 volSize; // Volume Size - u32 volSizeBig; // Volume Size Big-Endian - u8 reserved6[32]; - u32 unknown1; - u32 unknown1_bigend; - u16 volDescSize; //+80 - u16 volDescSize_bigend; //+82 - u32 unknown3; //+84 - u32 unknown3_bigend; //+88 - u32 priDirTableLBA; // LBA of Primary Dir Table //+8C - u32 reserved7; //+90 - u32 secDirTableLBA; // LBA of Secondary Dir Table //+94 - u32 reserved8; //+98 - struct rootDirTocHeader rootToc; - u8 volSetName[128]; - u8 publisherName[128]; - u8 preparerName[128]; - u8 applicationName[128]; - u8 copyrightFileName[37]; - u8 abstractFileName[37]; - u8 bibliographyFileName[37]; - struct asciiDate creationDate; - struct asciiDate modificationDate; - struct asciiDate effectiveDate; - struct asciiDate expirationDate; - u8 reserved10; - u8 reserved11[1166]; -}; - -#pragma pack() - - +/*************************************************************************** + defines.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +// general buffer for reading several frames + +#pragma pack(1) + +typedef struct _FRAMEBUF +{ + DWORD dwFrame; + DWORD dwFrameCnt; + DWORD dwBufLen; + unsigned char BufData[1024*1024]; +} FRAMEBUF; + +#pragma pack() + +// raw ioctl structs: + +typedef enum _TRACK_MODE_TYPE +{ + YellowMode2, + XAForm2, + CDDA +} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE; + +typedef struct _RAW_READ_INFO +{ + LARGE_INTEGER DiskOffset; + ULONG SectorCount; + TRACK_MODE_TYPE TrackMode; +} RAW_READ_INFO, *PRAW_READ_INFO; + +// sub cache: + +typedef struct +{ + long addr; + void * pNext; + unsigned char subq[10]; +} SUB_DATA; + +typedef struct +{ + long addr; + void * pNext; +} SUB_CACHE; + +// ppf cache: + +typedef struct +{ + long addr; + void * pNext; + long pos; + long anz; + // memdata +} PPF_DATA; + +typedef struct +{ + long addr; + void * pNext; +} PPF_CACHE; + +///////////////////////////////////////////////////////// + +#define MODE_BE_1 1 +#define MODE_BE_2 2 +#define MODE_28_1 3 +#define MODE_28_2 4 +#define MODE_28_2048 5 +#define MODE_28_2048_Ex 6 + +#define itob(i) ((i)/10*16 + (i)%10) +#define btoi(b) ((b)/16*10 + (b)%16) +#define itod(i) ((((i)/10)<<4) + ((i)%10)) +#define dtoi(b) ((((b)>>4)&0xf)*10 + (((b)&0xf)%10)) + +///////////////////////////////////////////////////////// + +void addr2time(unsigned long addr, unsigned char *time); +void addr2timeB(unsigned long addr, unsigned char *time); +unsigned long time2addr(unsigned char *time); +unsigned long time2addrB(unsigned char *time); +#ifdef _GCC +#define reOrder i386_reOrder +#endif +unsigned long reOrder(unsigned long value); + +///////////////////////////////////////////////////////// +// debug helper + +#ifndef _IN_CDR +#ifdef DBGOUT +void auxprintf (LPCTSTR pFormat, ...); +#endif +#endif + +///////////////////////////////////////////////////////// + +typedef DWORD (*READFUNC)(BOOL bWait,FRAMEBUF * f); +typedef DWORD (*DEINITFUNC)(void); +typedef BOOL (*READTRACKFUNC)(unsigned long addr); +typedef void (*GETPTRFUNC)(void); + +///////////////////////////////////////////////////////// + +#define WAITFOREVER 0xFFFFFFFF +#define WAITSUB 10000 +#define FRAMEBUFEXTRA 12 +#define CDSECTOR 2352 +#define MAXCACHEBLOCK 26 +#define MAXCDBUFFER (((MAXCACHEBLOCK+1)*(CDSECTOR+16))+240) + +///////////////////////////////////////////////////////// + +/* some structs from libcdvd by Hiryu & Sjeep (C) 2002 */ + +#pragma pack(1) + +struct rootDirTocHeader +{ + u16 length; //+00 + u32 tocLBA; //+02 + u32 tocLBA_bigend; //+06 + u32 tocSize; //+0A + u32 tocSize_bigend; //+0E + u8 dateStamp[8]; //+12 + u8 reserved[6]; //+1A + u8 reserved2; //+20 + u8 reserved3; //+21 +}; //+22 + +struct asciiDate +{ + char year[4]; + char month[2]; + char day[2]; + char hours[2]; + char minutes[2]; + char seconds[2]; + char hundreths[2]; + char terminator[1]; +}; + +struct cdVolDesc +{ + u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL + u8 volID[5]; // "CD001" + u8 reserved2; + u8 reserved3; + u8 sysIdName[32]; + u8 volName[32]; // The ISO9660 Volume Name + u8 reserved5[8]; + u32 volSize; // Volume Size + u32 volSizeBig; // Volume Size Big-Endian + u8 reserved6[32]; + u32 unknown1; + u32 unknown1_bigend; + u16 volDescSize; //+80 + u16 volDescSize_bigend; //+82 + u32 unknown3; //+84 + u32 unknown3_bigend; //+88 + u32 priDirTableLBA; // LBA of Primary Dir Table //+8C + u32 reserved7; //+90 + u32 secDirTableLBA; // LBA of Secondary Dir Table //+94 + u32 reserved8; //+98 + struct rootDirTocHeader rootToc; + u8 volSetName[128]; + u8 publisherName[128]; + u8 preparerName[128]; + u8 applicationName[128]; + u8 copyrightFileName[37]; + u8 abstractFileName[37]; + u8 bibliographyFileName[37]; + struct asciiDate creationDate; + struct asciiDate modificationDate; + struct asciiDate effectiveDate; + struct asciiDate expirationDate; + u8 reserved10; + u8 reserved11[1166]; +}; + +#pragma pack() + + diff --git a/plugins/CDVDpeops/externals.h b/plugins/CDVDpeops/externals.h index 95d8d3c667..0aa118bbd1 100644 --- a/plugins/CDVDpeops/externals.h +++ b/plugins/CDVDpeops/externals.h @@ -1,177 +1,177 @@ -/*************************************************************************** - externals.h - description - ------------------- - begin : Wed Sep 18 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/09/19 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -///////////////////////////////////////////////////////// - -#ifndef _IN_CDDA - -#endif - -///////////////////////////////////////////////////////// - -#ifndef _IN_CDR - -extern BOOL bIsOpen; -extern BOOL bCDDAPlay; -extern int iCDROK; -extern char *libraryName; -extern int iCheckTrayStatus; -extern void *fdump; - -#endif - -///////////////////////////////////////////////////////// - -#ifndef _IN_PEOPS - -extern HINSTANCE hInst; - -#endif - -///////////////////////////////////////////////////////// - -#ifndef _IN_CFG - -#endif - -///////////////////////////////////////////////////////// - -#ifndef _IN_GENERIC - -extern int iCD_AD; -extern int iCD_TA; -extern int iCD_LU; -extern int iRType; -extern int iUseSpeedLimit; -extern int iSpeedLimit; -extern int iNoWait; -extern int iMaxRetry; -extern int iShowReadErr; -extern HANDLE hEvent; -extern HINSTANCE hASPI; -extern READFUNC pReadFunc; -extern DEINITFUNC pDeInitFunc; -extern int iInterfaceMode; -extern int iWantedBlockSize; -extern int iUsedBlockSize; -extern int iUsedMode; -extern int iBlockDump; - -extern DWORD (*pGetASPI32SupportInfo)(void); -extern DWORD (*pSendASPI32Command)(LPSRB); - -#endif - -///////////////////////////////////////////////////////// - -#ifndef _IN_IOCTL - -extern HANDLE hIOCTL; -extern DWORD dwIOCTLAttr; -extern OVERLAPPED ovcIOCTL; -extern SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sptIOCTL; -extern RAW_READ_INFO rawIOCTL; - -#endif - -///////////////////////////////////////////////////////// - -#ifndef _IN_PPF - -extern int iUsePPF; -extern char szPPF[]; -extern PPF_CACHE * ppfCache; -extern PPF_DATA * ppfHead; -extern int iPPFNum; - -#endif - -///////////////////////////////////////////////////////// - -#ifndef _IN_READ - -extern READTRACKFUNC pReadTrackFunc; -extern GETPTRFUNC pGetPtrFunc; - -extern int iUseCaching; -extern int iUseDataCache; -extern int iTryAsync; -extern int iBufSel; - -extern unsigned char * pMainBuffer; -extern unsigned char * pCurrReadBuf; -extern unsigned char * pFirstReadBuf; -extern unsigned char * pAsyncBuffer; - -extern unsigned long lMaxAddr; -extern unsigned long lLastAddr; -extern unsigned long lLastAsyncAddr; - -extern unsigned char * ptrBuffer[]; -extern unsigned char * pAsyncFirstReadBuf[]; -extern unsigned long lLastAccessedAddr; -extern int iLastAccessedMode; - -extern HANDLE hReadThread; -extern BOOL bThreadEnded; -extern HANDLE hThreadEvent[]; -extern HANDLE hThreadMutex[]; - -#endif - -///////////////////////////////////////////////////////// - -#ifndef _IN_SCSI - -extern SRB_ExecSCSICmd sx; -extern BOOL bDoWaiting; - -#endif - -///////////////////////////////////////////////////////// - -#ifndef _IN_SUB - -extern unsigned char * pCurrSubBuf; -extern int iUseSubReading; -extern char szSUBF[]; -extern SUB_CACHE * subCache; -extern SUB_DATA * subHead; -extern int iSUBNum; -extern unsigned char SubCData[]; -extern unsigned char SubAData[]; - -#endif - -///////////////////////////////////////////////////////// - -#ifndef _IN_TOC - -extern TOC sTOC; - -#endif - -///////////////////////////////////////////////////////// +/*************************************************************************** + externals.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#ifndef _IN_CDDA + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_CDR + +extern BOOL bIsOpen; +extern BOOL bCDDAPlay; +extern int iCDROK; +extern char *libraryName; +extern int iCheckTrayStatus; +extern void *fdump; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_PEOPS + +extern HINSTANCE hInst; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_CFG + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_GENERIC + +extern int iCD_AD; +extern int iCD_TA; +extern int iCD_LU; +extern int iRType; +extern int iUseSpeedLimit; +extern int iSpeedLimit; +extern int iNoWait; +extern int iMaxRetry; +extern int iShowReadErr; +extern HANDLE hEvent; +extern HINSTANCE hASPI; +extern READFUNC pReadFunc; +extern DEINITFUNC pDeInitFunc; +extern int iInterfaceMode; +extern int iWantedBlockSize; +extern int iUsedBlockSize; +extern int iUsedMode; +extern int iBlockDump; + +extern DWORD (*pGetASPI32SupportInfo)(void); +extern DWORD (*pSendASPI32Command)(LPSRB); + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_IOCTL + +extern HANDLE hIOCTL; +extern DWORD dwIOCTLAttr; +extern OVERLAPPED ovcIOCTL; +extern SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sptIOCTL; +extern RAW_READ_INFO rawIOCTL; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_PPF + +extern int iUsePPF; +extern char szPPF[]; +extern PPF_CACHE * ppfCache; +extern PPF_DATA * ppfHead; +extern int iPPFNum; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_READ + +extern READTRACKFUNC pReadTrackFunc; +extern GETPTRFUNC pGetPtrFunc; + +extern int iUseCaching; +extern int iUseDataCache; +extern int iTryAsync; +extern int iBufSel; + +extern unsigned char * pMainBuffer; +extern unsigned char * pCurrReadBuf; +extern unsigned char * pFirstReadBuf; +extern unsigned char * pAsyncBuffer; + +extern unsigned long lMaxAddr; +extern unsigned long lLastAddr; +extern unsigned long lLastAsyncAddr; + +extern unsigned char * ptrBuffer[]; +extern unsigned char * pAsyncFirstReadBuf[]; +extern unsigned long lLastAccessedAddr; +extern int iLastAccessedMode; + +extern HANDLE hReadThread; +extern BOOL bThreadEnded; +extern HANDLE hThreadEvent[]; +extern HANDLE hThreadMutex[]; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_SCSI + +extern SRB_ExecSCSICmd sx; +extern BOOL bDoWaiting; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_SUB + +extern unsigned char * pCurrSubBuf; +extern int iUseSubReading; +extern char szSUBF[]; +extern SUB_CACHE * subCache; +extern SUB_DATA * subHead; +extern int iSUBNum; +extern unsigned char SubCData[]; +extern unsigned char SubAData[]; + +#endif + +///////////////////////////////////////////////////////// + +#ifndef _IN_TOC + +extern TOC sTOC; + +#endif + +///////////////////////////////////////////////////////// diff --git a/plugins/CDVDpeops/generic.c b/plugins/CDVDpeops/generic.c index f54a29555d..2cdc3a497b 100644 --- a/plugins/CDVDpeops/generic.c +++ b/plugins/CDVDpeops/generic.c @@ -1,386 +1,386 @@ -/*************************************************************************** - generic.c - description - ------------------- - begin : Sun Nov 16 2003 - copyright : (C) 2003 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2004/12/25 - Pete -// - repaired time2addr/addr2time -// -// 2003/11/16 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -///////////////////////////////////////////////////////// - -#include "stdafx.h" -#define _IN_GENERIC -#include "externals.h" - -///////////////////////////////////////////////////////// - -int iCD_AD=-1; // drive address -int iCD_TA=-1; -int iCD_LU=-1; -int iRType=0; // read mode -int iUseSpeedLimit=0; // speed limit use -int iSpeedLimit=2; // speed 2x -int iNoWait=0; // wait -int iMaxRetry=5; // retry on error -int iShowReadErr=0; // show msg on error -HANDLE hEvent=NULL; // global event -HINSTANCE hASPI=NULL; // aspi lib -READFUNC pReadFunc=NULL; // read func -DEINITFUNC pDeInitFunc=NULL; // deinit func -int iInterfaceMode=1; // interface (aspi/ioctrlscsi/ioctrlraw) -int iWantedBlockSize=2352; -int iUsedBlockSize=2352; -int iUsedMode=CDVD_MODE_2352; -int iBlockDump=0; - -DWORD (*pGetASPI32SupportInfo)(void); // ptrs to aspi funcs -DWORD (*pSendASPI32Command)(LPSRB); - -///////////////////////////////////////////////////////// - -void addr2time(unsigned long addr, unsigned char *time) -{ - addr+=150; - time[3] = (unsigned char)(addr%75); - addr/=75; - time[2]=(unsigned char)(addr%60); - addr/=60; - time[1]=(unsigned char)(addr%100); - time[0]=(unsigned char)(addr/100); -} - -void addr2timeB(unsigned long addr, unsigned char *time) -{ - time[3] = itob((unsigned char)(addr%75)); - addr/=75; - time[2]=itob((unsigned char)(addr%60)); - addr/=60; - time[1]=itob((unsigned char)(addr%100)); - time[0]=itob((unsigned char)(addr/100)); -} - -unsigned long time2addr(unsigned char *time) -{ - unsigned long addr; - - addr = time[0]*100; - addr += time[1]; - addr *= 60; - - addr = (addr + time[2])*75; - addr += time[3]; - addr -= 150; - return addr; -} - -unsigned long time2addrB(unsigned char *time) -{ - unsigned long addr; - - addr = (btoi(time[0]))*100; - addr += btoi(time[1]); - addr *= 60; - addr = (addr + btoi(time[2]))*75; - addr += btoi(time[3]); - addr -= 150; - return addr; -} - -#ifndef _GCC - -#ifdef __x86_64__ -unsigned long reOrder(unsigned long value) -{ - return ((value&0xff)<<24)|((value&0xff00)<<8)|((value&0xff0000)>>8)|(value>>24); -} -#else -unsigned long reOrder(unsigned long value) -{ -#pragma warning (disable: 4035) - __asm - { - mov eax,value - bswap eax - } -} -#endif -#endif - -///////////////////////////////////////////////////////// - -void CreateGenEvent(void) -{ - hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); -} - -///////////////////////////////////////////////////////// - -void FreeGenEvent(void) -{ - if(hEvent) CloseHandle(hEvent); - hEvent=0; -} - -///////////////////////////////////////////////////////// - -DWORD WaitGenEvent(DWORD dwMS) -{ - if(hASPI) // aspi event - return WaitForSingleObject(hEvent,dwMS); - else - { // ioctl overlapped (always waiting til finished, dwMS not used) - DWORD dwR=0; - GetOverlappedResult(hIOCTL,&ovcIOCTL,&dwR,TRUE); - return 0; - } -} - -///////////////////////////////////////////////////////// - -void LockGenCDAccess(void) -{ - if(hReadThread) // thread mode? - WaitForSingleObject(hThreadMutex[0],INFINITE); // -> wait until all reading is done - else // async prefetch? - if(bDoWaiting) // -> async operation has to finish first - {WaitGenEvent(0xFFFFFFFF);bDoWaiting=FALSE;} -} - -///////////////////////////////////////////////////////// - -void UnlockGenCDAccess(void) -{ - if(hReadThread) // thread mode? - ReleaseMutex(hThreadMutex[0]); // -> we are finished with our special command, now reading can go on -} - -///////////////////////////////////////////////////////// - -void WaitUntilDriveIsReady(void) -{ - if(iNoWait==0) - { - while(TestSCSIUnitReady()==0) Sleep(500); - } -} - -///////////////////////////////////////////////////////// - -void SetGenCDSpeed(int iReset) -{ - if(iUseSpeedLimit) - { - if(bDoWaiting) // still a command running? wait - {WaitGenEvent(0xFFFFFFFF);bDoWaiting=FALSE;} - - if(iReset) SetSCSISpeed(0xFFFF); - else - if(SetSCSISpeed(176*iSpeedLimit)<=0) - { - MessageBox(GetActiveWindow(), - "Failure: cannot change the drive speed!", - "cdvdPeops... speed limitation", - MB_OK|MB_ICONEXCLAMATION); - iUseSpeedLimit=0; - } - } -} - -///////////////////////////////////////////////////////// -// checks, which direct subchannel reading type is supported - -void GetBESubReadFunc(void) -{ - unsigned char * pB=(unsigned char *)malloc(4096); - - pReadFunc = ReadSCSI_BE_Sub; // pre-init read func - - WaitUntilDriveIsReady(); // wait before first read - - ReadSub_BE_2(0,pB,1); // first (unchecked) read - if(!ReadSub_BE_2(0,pB,1)) // read again, and check this time - { // -> read failed? - if(ReadSub_BE_2_1(0,pB,1)) // -> try different sub reading - { // --> success? mmm... let us check the data - DecodeSub_BE_2_1(pB+2352); // --> decode sub - if(*(pB+2352)==0x41) // --> check the first decoded byte - pReadFunc = ReadSCSI_BE_Sub_1; // ---> wow, byte is ok - } - } - free(pB); -} - -///////////////////////////////////////////////////////// - -int GetGenReadFunc(int iRM) -{ - switch(iRM) // scsi read mode - { - // ------------------------------------------------ // - case MODE_BE_1: - case MODE_BE_2: - { - if(iUseSubReading==1) - GetBESubReadFunc(); - else pReadFunc = ReadSCSI_BE; - } break; - // ------------------------------------------------ // - case MODE_28_1: - case MODE_28_2: - { - if(iUseSubReading==1) - pReadFunc = ReadSCSI_28_Sub; - else pReadFunc = ReadSCSI_28; - } break; - // ------------------------------------------------ // - case MODE_28_2048: - { - pReadFunc = ReadSCSI_28_2048; - } break; - // ------------------------------------------------ // - case MODE_28_2048_Ex: - { - pReadFunc = ReadSCSI_28_2048_Ex; - } break; - // ------------------------------------------------ // - default: - { - pReadFunc = ReadSCSI_Dummy; - } return -3; - // ------------------------------------------------ // - } - return 1; -} - -///////////////////////////////////////////////////////// - -int OpenGenCD(int iA,int iT,int iL) -{ - pDeInitFunc = NULL; // init de-init func - pReadFunc = ReadSCSI_Dummy; // init (dummy) read func - - if(iA==-1) return -1; // not configured properly - - // -------------------------------------------------- // - - if(iInterfaceMode>1) // ioctrl interfaces? - { - OpenIOCTLHandle(iA,iT,iL); // open w2k/xp ioctrl device - if(hIOCTL==NULL) return -2; // no cdrom available - - if(iInterfaceMode==3) // special ioctl RAW mode? - { // -> get special reading funcs (non-scsi!) - if(iUseSubReading==1) - pReadFunc = ReadIOCTL_Raw_Sub; - else pReadFunc = ReadIOCTL_Raw; - - WaitUntilDriveIsReady(); - return 1; - } - } - else // aspi interface? - { - int iDevice=GetSCSIDevice(iA,iT,iL); // get device type - if(iDevice!=DTYPE_CDROM) return -2; // no cdrom? bye - } - - if(CheckSCSIReadMode()==SS_COMP) - WaitUntilDriveIsReady(); - else - { - CloseIOCTLHandle(); - return -3; - } - - return 1; -} - -///////////////////////////////////////////////////////// - -void CloseGenCD(void) -{ - iCDROK=0; // no more cd available - if(pDeInitFunc) pDeInitFunc(); // deinit, if needed - pDeInitFunc = NULL; - pReadFunc = ReadSCSI_Dummy; - CloseIOCTLHandle(); // close ioctl drive file (if used) -} - -///////////////////////////////////////////////////////// - -void OpenGenInterface(void) -{ - hASPI=NULL; - - if(iInterfaceMode==0) return; // no interface? no fun - else - if(iInterfaceMode==1) // aspi - { - hASPI=LoadLibrary("WNASPI32.DLL"); - if(hASPI) - { - pGetASPI32SupportInfo = - (DWORD(*)(void)) GetProcAddress(hASPI,"GetASPI32SupportInfo"); - pSendASPI32Command = - (DWORD(*)(LPSRB))GetProcAddress(hASPI,"SendASPI32Command"); - - if(!pGetASPI32SupportInfo || !pSendASPI32Command) - { - iInterfaceMode=0; - return; - } - } - } - else // ioctl - { - if(iInterfaceMode<2 || iInterfaceMode>3) iInterfaceMode=2; - pGetASPI32SupportInfo = NULL; - pSendASPI32Command = IOCTLSendASPI32Command; - } -} - -///////////////////////////////////////////////////////// - -void CloseGenInterface(void) -{ - pGetASPI32SupportInfo=NULL; // clear funcs - pSendASPI32Command=NULL; - - if(hASPI) // free aspi - { - FreeLibrary(hASPI); - hASPI=NULL; - } - else CloseIOCTLHandle(); // or close ioctl file -} - -///////////////////////////////////////////////////////// - -int GetGenCDDrives(char * pDList) -{ - if(hASPI) return GetSCSICDDrives(pDList); // aspi? use it - return GetIOCTLCDDrives(pDList); // or use ioctl -} - -///////////////////////////////////////////////////////// +/*************************************************************************** + generic.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/12/25 - Pete +// - repaired time2addr/addr2time +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#define _IN_GENERIC +#include "externals.h" + +///////////////////////////////////////////////////////// + +int iCD_AD=-1; // drive address +int iCD_TA=-1; +int iCD_LU=-1; +int iRType=0; // read mode +int iUseSpeedLimit=0; // speed limit use +int iSpeedLimit=2; // speed 2x +int iNoWait=0; // wait +int iMaxRetry=5; // retry on error +int iShowReadErr=0; // show msg on error +HANDLE hEvent=NULL; // global event +HINSTANCE hASPI=NULL; // aspi lib +READFUNC pReadFunc=NULL; // read func +DEINITFUNC pDeInitFunc=NULL; // deinit func +int iInterfaceMode=1; // interface (aspi/ioctrlscsi/ioctrlraw) +int iWantedBlockSize=2352; +int iUsedBlockSize=2352; +int iUsedMode=CDVD_MODE_2352; +int iBlockDump=0; + +DWORD (*pGetASPI32SupportInfo)(void); // ptrs to aspi funcs +DWORD (*pSendASPI32Command)(LPSRB); + +///////////////////////////////////////////////////////// + +void addr2time(unsigned long addr, unsigned char *time) +{ + addr+=150; + time[3] = (unsigned char)(addr%75); + addr/=75; + time[2]=(unsigned char)(addr%60); + addr/=60; + time[1]=(unsigned char)(addr%100); + time[0]=(unsigned char)(addr/100); +} + +void addr2timeB(unsigned long addr, unsigned char *time) +{ + time[3] = itob((unsigned char)(addr%75)); + addr/=75; + time[2]=itob((unsigned char)(addr%60)); + addr/=60; + time[1]=itob((unsigned char)(addr%100)); + time[0]=itob((unsigned char)(addr/100)); +} + +unsigned long time2addr(unsigned char *time) +{ + unsigned long addr; + + addr = time[0]*100; + addr += time[1]; + addr *= 60; + + addr = (addr + time[2])*75; + addr += time[3]; + addr -= 150; + return addr; +} + +unsigned long time2addrB(unsigned char *time) +{ + unsigned long addr; + + addr = (btoi(time[0]))*100; + addr += btoi(time[1]); + addr *= 60; + addr = (addr + btoi(time[2]))*75; + addr += btoi(time[3]); + addr -= 150; + return addr; +} + +#ifndef _GCC + +#ifdef __x86_64__ +unsigned long reOrder(unsigned long value) +{ + return ((value&0xff)<<24)|((value&0xff00)<<8)|((value&0xff0000)>>8)|(value>>24); +} +#else +unsigned long reOrder(unsigned long value) +{ +#pragma warning (disable: 4035) + __asm + { + mov eax,value + bswap eax + } +} +#endif +#endif + +///////////////////////////////////////////////////////// + +void CreateGenEvent(void) +{ + hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); +} + +///////////////////////////////////////////////////////// + +void FreeGenEvent(void) +{ + if(hEvent) CloseHandle(hEvent); + hEvent=0; +} + +///////////////////////////////////////////////////////// + +DWORD WaitGenEvent(DWORD dwMS) +{ + if(hASPI) // aspi event + return WaitForSingleObject(hEvent,dwMS); + else + { // ioctl overlapped (always waiting til finished, dwMS not used) + DWORD dwR=0; + GetOverlappedResult(hIOCTL,&ovcIOCTL,&dwR,TRUE); + return 0; + } +} + +///////////////////////////////////////////////////////// + +void LockGenCDAccess(void) +{ + if(hReadThread) // thread mode? + WaitForSingleObject(hThreadMutex[0],INFINITE); // -> wait until all reading is done + else // async prefetch? + if(bDoWaiting) // -> async operation has to finish first + {WaitGenEvent(0xFFFFFFFF);bDoWaiting=FALSE;} +} + +///////////////////////////////////////////////////////// + +void UnlockGenCDAccess(void) +{ + if(hReadThread) // thread mode? + ReleaseMutex(hThreadMutex[0]); // -> we are finished with our special command, now reading can go on +} + +///////////////////////////////////////////////////////// + +void WaitUntilDriveIsReady(void) +{ + if(iNoWait==0) + { + while(TestSCSIUnitReady()==0) Sleep(500); + } +} + +///////////////////////////////////////////////////////// + +void SetGenCDSpeed(int iReset) +{ + if(iUseSpeedLimit) + { + if(bDoWaiting) // still a command running? wait + {WaitGenEvent(0xFFFFFFFF);bDoWaiting=FALSE;} + + if(iReset) SetSCSISpeed(0xFFFF); + else + if(SetSCSISpeed(176*iSpeedLimit)<=0) + { + MessageBox(GetActiveWindow(), + "Failure: cannot change the drive speed!", + "cdvdPeops... speed limitation", + MB_OK|MB_ICONEXCLAMATION); + iUseSpeedLimit=0; + } + } +} + +///////////////////////////////////////////////////////// +// checks, which direct subchannel reading type is supported + +void GetBESubReadFunc(void) +{ + unsigned char * pB=(unsigned char *)malloc(4096); + + pReadFunc = ReadSCSI_BE_Sub; // pre-init read func + + WaitUntilDriveIsReady(); // wait before first read + + ReadSub_BE_2(0,pB,1); // first (unchecked) read + if(!ReadSub_BE_2(0,pB,1)) // read again, and check this time + { // -> read failed? + if(ReadSub_BE_2_1(0,pB,1)) // -> try different sub reading + { // --> success? mmm... let us check the data + DecodeSub_BE_2_1(pB+2352); // --> decode sub + if(*(pB+2352)==0x41) // --> check the first decoded byte + pReadFunc = ReadSCSI_BE_Sub_1; // ---> wow, byte is ok + } + } + free(pB); +} + +///////////////////////////////////////////////////////// + +int GetGenReadFunc(int iRM) +{ + switch(iRM) // scsi read mode + { + // ------------------------------------------------ // + case MODE_BE_1: + case MODE_BE_2: + { + if(iUseSubReading==1) + GetBESubReadFunc(); + else pReadFunc = ReadSCSI_BE; + } break; + // ------------------------------------------------ // + case MODE_28_1: + case MODE_28_2: + { + if(iUseSubReading==1) + pReadFunc = ReadSCSI_28_Sub; + else pReadFunc = ReadSCSI_28; + } break; + // ------------------------------------------------ // + case MODE_28_2048: + { + pReadFunc = ReadSCSI_28_2048; + } break; + // ------------------------------------------------ // + case MODE_28_2048_Ex: + { + pReadFunc = ReadSCSI_28_2048_Ex; + } break; + // ------------------------------------------------ // + default: + { + pReadFunc = ReadSCSI_Dummy; + } return -3; + // ------------------------------------------------ // + } + return 1; +} + +///////////////////////////////////////////////////////// + +int OpenGenCD(int iA,int iT,int iL) +{ + pDeInitFunc = NULL; // init de-init func + pReadFunc = ReadSCSI_Dummy; // init (dummy) read func + + if(iA==-1) return -1; // not configured properly + + // -------------------------------------------------- // + + if(iInterfaceMode>1) // ioctrl interfaces? + { + OpenIOCTLHandle(iA,iT,iL); // open w2k/xp ioctrl device + if(hIOCTL==NULL) return -2; // no cdrom available + + if(iInterfaceMode==3) // special ioctl RAW mode? + { // -> get special reading funcs (non-scsi!) + if(iUseSubReading==1) + pReadFunc = ReadIOCTL_Raw_Sub; + else pReadFunc = ReadIOCTL_Raw; + + WaitUntilDriveIsReady(); + return 1; + } + } + else // aspi interface? + { + int iDevice=GetSCSIDevice(iA,iT,iL); // get device type + if(iDevice!=DTYPE_CDROM) return -2; // no cdrom? bye + } + + if(CheckSCSIReadMode()==SS_COMP) + WaitUntilDriveIsReady(); + else + { + CloseIOCTLHandle(); + return -3; + } + + return 1; +} + +///////////////////////////////////////////////////////// + +void CloseGenCD(void) +{ + iCDROK=0; // no more cd available + if(pDeInitFunc) pDeInitFunc(); // deinit, if needed + pDeInitFunc = NULL; + pReadFunc = ReadSCSI_Dummy; + CloseIOCTLHandle(); // close ioctl drive file (if used) +} + +///////////////////////////////////////////////////////// + +void OpenGenInterface(void) +{ + hASPI=NULL; + + if(iInterfaceMode==0) return; // no interface? no fun + else + if(iInterfaceMode==1) // aspi + { + hASPI=LoadLibrary("WNASPI32.DLL"); + if(hASPI) + { + pGetASPI32SupportInfo = + (DWORD(*)(void)) GetProcAddress(hASPI,"GetASPI32SupportInfo"); + pSendASPI32Command = + (DWORD(*)(LPSRB))GetProcAddress(hASPI,"SendASPI32Command"); + + if(!pGetASPI32SupportInfo || !pSendASPI32Command) + { + iInterfaceMode=0; + return; + } + } + } + else // ioctl + { + if(iInterfaceMode<2 || iInterfaceMode>3) iInterfaceMode=2; + pGetASPI32SupportInfo = NULL; + pSendASPI32Command = IOCTLSendASPI32Command; + } +} + +///////////////////////////////////////////////////////// + +void CloseGenInterface(void) +{ + pGetASPI32SupportInfo=NULL; // clear funcs + pSendASPI32Command=NULL; + + if(hASPI) // free aspi + { + FreeLibrary(hASPI); + hASPI=NULL; + } + else CloseIOCTLHandle(); // or close ioctl file +} + +///////////////////////////////////////////////////////// + +int GetGenCDDrives(char * pDList) +{ + if(hASPI) return GetSCSICDDrives(pDList); // aspi? use it + return GetIOCTLCDDrives(pDList); // or use ioctl +} + +///////////////////////////////////////////////////////// diff --git a/plugins/CDVDpeops/generic.h b/plugins/CDVDpeops/generic.h index 0313e50f0b..ba40be745f 100644 --- a/plugins/CDVDpeops/generic.h +++ b/plugins/CDVDpeops/generic.h @@ -1,41 +1,41 @@ -/*************************************************************************** - generic.h - description - ------------------- - begin : Wed Sep 18 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/09/19 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -void CreateGenEvent(void); -void FreeGenEvent(void); -DWORD WaitGenEvent(DWORD dwMS); -void LockGenCDAccess(void); -void UnlockGenCDAccess(void); -void WaitUntilDriveIsReady(void); -void SetGenCDSpeed(int iReset); -void GetBESubReadFunc(void); -int GetGenReadFunc(int iRM); -int OpenGenCD(int iA,int iT,int iL); -void CloseGenCD(void); -void OpenGenInterface(void); -void CloseGenInterface(void); -int GetGenCDDrives(char * pDList); - +/*************************************************************************** + generic.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +void CreateGenEvent(void); +void FreeGenEvent(void); +DWORD WaitGenEvent(DWORD dwMS); +void LockGenCDAccess(void); +void UnlockGenCDAccess(void); +void WaitUntilDriveIsReady(void); +void SetGenCDSpeed(int iReset); +void GetBESubReadFunc(void); +int GetGenReadFunc(int iRM); +int OpenGenCD(int iA,int iT,int iL); +void CloseGenCD(void); +void OpenGenInterface(void); +void CloseGenInterface(void); +int GetGenCDDrives(char * pDList); + diff --git a/plugins/CDVDpeops/ioctrl.h b/plugins/CDVDpeops/ioctrl.h index f105c963e0..42a43c6637 100644 --- a/plugins/CDVDpeops/ioctrl.h +++ b/plugins/CDVDpeops/ioctrl.h @@ -1,35 +1,35 @@ -/*************************************************************************** - ioctrl.h - description - ------------------- - begin : Wed Sep 18 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/09/19 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -void OpenIOCTLHandle(int iA,int iT,int iL); -void CloseIOCTLHandle(void); -char MapIOCTLDriveLetter(int iA,int iT,int iL); -int GetIOCTLCDDrives(char * pDList); -HANDLE OpenIOCTLFile(char cLetter,BOOL bAsync); -void GetIOCTLAdapter(HANDLE hF,int * iDA,int * iDT,int * iDL); -DWORD IOCTLSendASPI32Command(LPSRB pSrb); -DWORD ReadIOCTL_Raw(BOOL bWait,FRAMEBUF * f); -DWORD ReadIOCTL_Raw_Sub(BOOL bWait,FRAMEBUF * f); +/*************************************************************************** + ioctrl.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +void OpenIOCTLHandle(int iA,int iT,int iL); +void CloseIOCTLHandle(void); +char MapIOCTLDriveLetter(int iA,int iT,int iL); +int GetIOCTLCDDrives(char * pDList); +HANDLE OpenIOCTLFile(char cLetter,BOOL bAsync); +void GetIOCTLAdapter(HANDLE hF,int * iDA,int * iDT,int * iDL); +DWORD IOCTLSendASPI32Command(LPSRB pSrb); +DWORD ReadIOCTL_Raw(BOOL bWait,FRAMEBUF * f); +DWORD ReadIOCTL_Raw_Sub(BOOL bWait,FRAMEBUF * f); diff --git a/plugins/CDVDpeops/libiso.h b/plugins/CDVDpeops/libiso.h index 461f792db7..640cbf3322 100644 --- a/plugins/CDVDpeops/libiso.h +++ b/plugins/CDVDpeops/libiso.h @@ -1,59 +1,59 @@ -#ifndef __LIBISO_H__ -#define __LIBISO_H__ - -#ifdef __MSCW32__ -#pragma warning(disable:4018) -#endif - +#ifndef __LIBISO_H__ +#define __LIBISO_H__ + +#ifdef __MSCW32__ +#pragma warning(disable:4018) +#endif + #define CDVDdefs #include "PS2Etypes.h" #include "PS2Edefs.h" - -#define ISOTYPE_ILLEGAL 0 -#define ISOTYPE_CD 1 -#define ISOTYPE_DVD 2 -#define ISOTYPE_AUDIO 3 - -#define ISOFLAGS_Z 0x1 -#define ISOFLAGS_Z2 0x2 -#define ISOFLAGS_BLOCKDUMP 0x4 - -#define CD_FRAMESIZE_RAW 2352 -#define DATA_SIZE (CD_FRAMESIZE_RAW-12) - -#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ -#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ - -typedef struct { - char filename[256]; - u32 type; - u32 flags; - u32 offset; - u32 blockofs; - u32 blocksize; - u32 blocks; - void *handle; - void *htable; - char *Ztable; - u32 *dtable; - int dtablesize; - char buffer[CD_FRAMESIZE_RAW * 10]; -} isoFile; - - -isoFile *isoOpen(const char *filename); -isoFile *isoCreate(const char *filename, int mode); -int isoSetFormat(isoFile *iso, int blockofs, int blocksize, int blocks); -int isoDetect(isoFile *iso); -int isoReadBlock(isoFile *iso, char *dst, int lsn); -int isoWriteBlock(isoFile *iso, char *src, int lsn); -void isoClose(isoFile *iso); - -void *_openfile(const char *filename, int flags); -u64 _tellfile(void *handle); -int _seekfile(void *handle, u64 offset, int whence); -int _readfile(void *handle, void *dst, int size); -int _writefile(void *handle, void *src, int size); -void _closefile(void *handle); - -#endif /* __LIBISO_H__ */ + +#define ISOTYPE_ILLEGAL 0 +#define ISOTYPE_CD 1 +#define ISOTYPE_DVD 2 +#define ISOTYPE_AUDIO 3 + +#define ISOFLAGS_Z 0x1 +#define ISOFLAGS_Z2 0x2 +#define ISOFLAGS_BLOCKDUMP 0x4 + +#define CD_FRAMESIZE_RAW 2352 +#define DATA_SIZE (CD_FRAMESIZE_RAW-12) + +#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ +#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ + +typedef struct { + char filename[256]; + u32 type; + u32 flags; + u32 offset; + u32 blockofs; + u32 blocksize; + u32 blocks; + void *handle; + void *htable; + char *Ztable; + u32 *dtable; + int dtablesize; + char buffer[CD_FRAMESIZE_RAW * 10]; +} isoFile; + + +isoFile *isoOpen(const char *filename); +isoFile *isoCreate(const char *filename, int mode); +int isoSetFormat(isoFile *iso, int blockofs, int blocksize, int blocks); +int isoDetect(isoFile *iso); +int isoReadBlock(isoFile *iso, char *dst, int lsn); +int isoWriteBlock(isoFile *iso, char *src, int lsn); +void isoClose(isoFile *iso); + +void *_openfile(const char *filename, int flags); +u64 _tellfile(void *handle); +int _seekfile(void *handle, u64 offset, int whence); +int _readfile(void *handle, void *dst, int size); +int _writefile(void *handle, void *src, int size); +void _closefile(void *handle); + +#endif /* __LIBISO_H__ */ diff --git a/plugins/CDVDpeops/mingw/afxres.h b/plugins/CDVDpeops/mingw/afxres.h index 060e13b308..3843ac3362 100644 --- a/plugins/CDVDpeops/mingw/afxres.h +++ b/plugins/CDVDpeops/mingw/afxres.h @@ -1,2 +1,2 @@ -#include -#define IDC_STATIC -1 +#include +#define IDC_STATIC -1 diff --git a/plugins/CDVDpeops/ppf.c b/plugins/CDVDpeops/ppf.c index c9f755da74..3a2637e5c3 100644 --- a/plugins/CDVDpeops/ppf.c +++ b/plugins/CDVDpeops/ppf.c @@ -1,353 +1,353 @@ -/*************************************************************************** - ppf.c - description - ------------------- - begin : Wed Sep 18 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2003/02/14 - Pete -// - fixed a bug reading PPF3 patches reported by Zydio -// -// 2002/09/19 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -///////////////////////////////////////////////////////// - -#include "stdafx.h" -#define _IN_PPF -#include "externals.h" - -///////////////////////////////////////////////////////// - -int iUsePPF=0; -char szPPF[260]; -PPF_CACHE * ppfCache=NULL; -PPF_DATA * ppfHead=NULL; -int iPPFNum=0; - -///////////////////////////////////////////////////////// -// works like sub cache... using a linked data list, and address array - -void FillPPFCache(void) -{ - PPF_DATA * p;PPF_CACHE * pc; - long lastaddr; - - p=ppfHead; - lastaddr=-1; - iPPFNum=0; - - while(p) - { - if(p->addr!=lastaddr) iPPFNum++; - lastaddr=p->addr; - p=(PPF_DATA *)p->pNext; - } - - if(!iPPFNum) return; - - pc=ppfCache=(PPF_CACHE *)malloc(iPPFNum*sizeof(PPF_CACHE)); - - iPPFNum--; - p=ppfHead; - lastaddr=-1; - - while(p) - { - if(p->addr!=lastaddr) - { - pc->addr=p->addr; - pc->pNext=(void *)p; - pc++; - } - lastaddr=p->addr; - p=(PPF_DATA *)p->pNext; - } -} - -///////////////////////////////////////////////////////// - -void FreePPFCache(void) -{ - PPF_DATA * p=ppfHead; - void * pn; - - while(p) - { - pn=p->pNext; - free(p); - p=(PPF_DATA *)pn; - } - ppfHead=NULL; - - if(ppfCache) free(ppfCache); - ppfCache=NULL; -} - -///////////////////////////////////////////////////////// - -void CheckPPFCache(long addr,unsigned char * pB) -{ - PPF_CACHE * pcstart, * pcend, * pcpos; - - pcstart=ppfCache; - if(addraddr) return; - pcend=ppfCache+iPPFNum; - if(addr>pcend->addr) return; - - while(1) - { - if(addr==pcend->addr) {pcpos=pcend;break;} - - pcpos=pcstart+(pcend-pcstart)/2; - if(pcpos==pcstart) break; - if(addraddr) - { - pcend=pcpos; - continue; - } - if(addr>pcpos->addr) - { - pcstart=pcpos; - continue; - } - break; - } - - if(addr==pcpos->addr) - { - PPF_DATA * p=(PPF_DATA *)pcpos->pNext; - while(p && p->addr==addr) - { - memcpy(pB+p->pos,p+1,p->anz); - p=(PPF_DATA *)p->pNext; - } - } -} - -///////////////////////////////////////////////////////// - -void AddToPPF(long ladr,long pos,long anz,char * ppfmem) -{ - if(!ppfHead) - { - ppfHead=(PPF_DATA *)malloc(sizeof(PPF_DATA)+anz); - ppfHead->addr=ladr; - ppfHead->pNext=NULL; - ppfHead->pos=pos; - ppfHead->anz=anz; - memcpy(ppfHead+1,ppfmem,anz); - iPPFNum=1; - } - else - { - PPF_DATA * p=ppfHead; - PPF_DATA * plast=NULL; - PPF_DATA * padd; - while(p) - { - if(ladraddr) break; - if(ladr==p->addr) - { - while(p && ladr==p->addr && pos>p->pos) - { - plast=p; - p=(PPF_DATA *)p->pNext; - } - break; - } - plast=p; - p=(PPF_DATA *)p->pNext; - } - padd=(PPF_DATA *)malloc(sizeof(PPF_DATA)+anz); - padd->addr=ladr; - padd->pNext=(void *)p; - padd->pos=pos; - padd->anz=anz; - memcpy(padd+1,ppfmem,anz); - iPPFNum++; - if(plast==NULL) - ppfHead=padd; - else plast->pNext=(void *)padd; - } -} - -///////////////////////////////////////////////////////// -// build ppf cache, if wanted - -void BuildPPFCache(void) -{ - FILE * ppffile; - char buffer[5]; - char method,undo=0,blockcheck=0; - int dizlen, dizyn, dizlensave=0; - char ppfmem[512]; - int count,seekpos, pos; - //unsigned char anz; - unsigned int anz; // new! avoids stupid overflows - long ladr,off,anx; - - ppfHead=NULL; - - if(iUsePPF==0) return; // no ppf cache wanted? - if(szPPF[0]==0) return; // no ppf file given? - - ppffile=fopen(szPPF, "rb"); - if(ppffile==0) - { - MessageBox(NULL,"No PPF file found!",libraryName,MB_OK); - return; - } - - memset(buffer,0,5); - fread(buffer, 3, 1, ppffile); - - if(strcmp(buffer,"PPF")) - { - MessageBox(NULL,"No PPF file format!",libraryName,MB_OK); - fclose(ppffile); - return; - } - - fseek(ppffile, 5, SEEK_SET); - fread(&method, 1, 1,ppffile); - - switch(method) - { - case 0: // ppf1 - fseek(ppffile, 0, SEEK_END); - count=ftell(ppffile); - count-=56; - seekpos=56; - break; - - case 1: // ppf2 - fseek(ppffile, -8,SEEK_END); - - memset(buffer,0,5); - fread(buffer, 4, 1,ppffile); - if(strcmp(".DIZ", buffer)) - { - dizyn=0; - } - else - { - fread(&dizlen, 4, 1, ppffile); - dizyn=1; - dizlensave=dizlen; - } - - fseek(ppffile, 56, SEEK_SET); - fread(&dizlen, 4, 1,ppffile); - fseek(ppffile, 0, SEEK_END); - count=ftell(ppffile); - if(dizyn==0) - { - count-=1084; - seekpos=1084; - } - else - { - count-=1084; - count-=38; - count-=dizlensave; - seekpos=1084; - } - break; - - case 2: // ppf3 - fseek(ppffile, 57, SEEK_SET); - fread(&blockcheck, 1, 1,ppffile); - fseek(ppffile, 58, SEEK_SET); - fread(&undo, 1, 1,ppffile); - - fseek(ppffile, -6,SEEK_END); - memset(buffer,0,5); - fread(buffer, 4, 1,ppffile); - dizlen=0; - if(!strcmp(".DIZ", buffer)) - { - fseek(ppffile, -2,SEEK_END); - fread(&dizlen, 2, 1, ppffile); - dizlen+=36; - } - - fseek(ppffile, 0, SEEK_END); - count=ftell(ppffile); - count-=dizlen; - - if(blockcheck) - { - seekpos=1084; - count-=1084; - } - else - { - seekpos=60; - count-=60; - } - - break; - - default: - fclose(ppffile); - MessageBox(NULL,"Unknown PPF format!",libraryName,MB_OK); - return; - } - - do // now do the data reading - { - fseek(ppffile, seekpos, SEEK_SET); - fread(&pos, 4, 1, ppffile); - - if(method==2) fread(buffer, 4, 1, ppffile); // skip 4 bytes on ppf3 (no int64 support here) - - anz=0; // new! init anz (since it's no unsigned char anymore) - fread(&anz, 1, 1, ppffile); - fread(ppfmem, anz, 1, ppffile); - - ladr=pos/2352; - off=pos%2352; - - if(off+anz>2352) - { - anx=off+anz-2352; - anz-=(unsigned char)anx; - AddToPPF(ladr+1,0,anx,ppfmem+anz); - } - - AddToPPF(ladr,off,anz,ppfmem); // add to link list - - if(method==2) // adjust ppf3 size - { - if(undo) anz+=anz; - anz+=4; - } - - seekpos=seekpos+5+anz; - count=count-5-anz; - } - while(count!=0); // loop til end - - fclose(ppffile); - - FillPPFCache(); // build address array -} - -///////////////////////////////////////////////////////// +/*************************************************************************** + ppf.c - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/02/14 - Pete +// - fixed a bug reading PPF3 patches reported by Zydio +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#define _IN_PPF +#include "externals.h" + +///////////////////////////////////////////////////////// + +int iUsePPF=0; +char szPPF[260]; +PPF_CACHE * ppfCache=NULL; +PPF_DATA * ppfHead=NULL; +int iPPFNum=0; + +///////////////////////////////////////////////////////// +// works like sub cache... using a linked data list, and address array + +void FillPPFCache(void) +{ + PPF_DATA * p;PPF_CACHE * pc; + long lastaddr; + + p=ppfHead; + lastaddr=-1; + iPPFNum=0; + + while(p) + { + if(p->addr!=lastaddr) iPPFNum++; + lastaddr=p->addr; + p=(PPF_DATA *)p->pNext; + } + + if(!iPPFNum) return; + + pc=ppfCache=(PPF_CACHE *)malloc(iPPFNum*sizeof(PPF_CACHE)); + + iPPFNum--; + p=ppfHead; + lastaddr=-1; + + while(p) + { + if(p->addr!=lastaddr) + { + pc->addr=p->addr; + pc->pNext=(void *)p; + pc++; + } + lastaddr=p->addr; + p=(PPF_DATA *)p->pNext; + } +} + +///////////////////////////////////////////////////////// + +void FreePPFCache(void) +{ + PPF_DATA * p=ppfHead; + void * pn; + + while(p) + { + pn=p->pNext; + free(p); + p=(PPF_DATA *)pn; + } + ppfHead=NULL; + + if(ppfCache) free(ppfCache); + ppfCache=NULL; +} + +///////////////////////////////////////////////////////// + +void CheckPPFCache(long addr,unsigned char * pB) +{ + PPF_CACHE * pcstart, * pcend, * pcpos; + + pcstart=ppfCache; + if(addraddr) return; + pcend=ppfCache+iPPFNum; + if(addr>pcend->addr) return; + + while(1) + { + if(addr==pcend->addr) {pcpos=pcend;break;} + + pcpos=pcstart+(pcend-pcstart)/2; + if(pcpos==pcstart) break; + if(addraddr) + { + pcend=pcpos; + continue; + } + if(addr>pcpos->addr) + { + pcstart=pcpos; + continue; + } + break; + } + + if(addr==pcpos->addr) + { + PPF_DATA * p=(PPF_DATA *)pcpos->pNext; + while(p && p->addr==addr) + { + memcpy(pB+p->pos,p+1,p->anz); + p=(PPF_DATA *)p->pNext; + } + } +} + +///////////////////////////////////////////////////////// + +void AddToPPF(long ladr,long pos,long anz,char * ppfmem) +{ + if(!ppfHead) + { + ppfHead=(PPF_DATA *)malloc(sizeof(PPF_DATA)+anz); + ppfHead->addr=ladr; + ppfHead->pNext=NULL; + ppfHead->pos=pos; + ppfHead->anz=anz; + memcpy(ppfHead+1,ppfmem,anz); + iPPFNum=1; + } + else + { + PPF_DATA * p=ppfHead; + PPF_DATA * plast=NULL; + PPF_DATA * padd; + while(p) + { + if(ladraddr) break; + if(ladr==p->addr) + { + while(p && ladr==p->addr && pos>p->pos) + { + plast=p; + p=(PPF_DATA *)p->pNext; + } + break; + } + plast=p; + p=(PPF_DATA *)p->pNext; + } + padd=(PPF_DATA *)malloc(sizeof(PPF_DATA)+anz); + padd->addr=ladr; + padd->pNext=(void *)p; + padd->pos=pos; + padd->anz=anz; + memcpy(padd+1,ppfmem,anz); + iPPFNum++; + if(plast==NULL) + ppfHead=padd; + else plast->pNext=(void *)padd; + } +} + +///////////////////////////////////////////////////////// +// build ppf cache, if wanted + +void BuildPPFCache(void) +{ + FILE * ppffile; + char buffer[5]; + char method,undo=0,blockcheck=0; + int dizlen, dizyn, dizlensave=0; + char ppfmem[512]; + int count,seekpos, pos; + //unsigned char anz; + unsigned int anz; // new! avoids stupid overflows + long ladr,off,anx; + + ppfHead=NULL; + + if(iUsePPF==0) return; // no ppf cache wanted? + if(szPPF[0]==0) return; // no ppf file given? + + ppffile=fopen(szPPF, "rb"); + if(ppffile==0) + { + MessageBox(NULL,"No PPF file found!",libraryName,MB_OK); + return; + } + + memset(buffer,0,5); + fread(buffer, 3, 1, ppffile); + + if(strcmp(buffer,"PPF")) + { + MessageBox(NULL,"No PPF file format!",libraryName,MB_OK); + fclose(ppffile); + return; + } + + fseek(ppffile, 5, SEEK_SET); + fread(&method, 1, 1,ppffile); + + switch(method) + { + case 0: // ppf1 + fseek(ppffile, 0, SEEK_END); + count=ftell(ppffile); + count-=56; + seekpos=56; + break; + + case 1: // ppf2 + fseek(ppffile, -8,SEEK_END); + + memset(buffer,0,5); + fread(buffer, 4, 1,ppffile); + if(strcmp(".DIZ", buffer)) + { + dizyn=0; + } + else + { + fread(&dizlen, 4, 1, ppffile); + dizyn=1; + dizlensave=dizlen; + } + + fseek(ppffile, 56, SEEK_SET); + fread(&dizlen, 4, 1,ppffile); + fseek(ppffile, 0, SEEK_END); + count=ftell(ppffile); + if(dizyn==0) + { + count-=1084; + seekpos=1084; + } + else + { + count-=1084; + count-=38; + count-=dizlensave; + seekpos=1084; + } + break; + + case 2: // ppf3 + fseek(ppffile, 57, SEEK_SET); + fread(&blockcheck, 1, 1,ppffile); + fseek(ppffile, 58, SEEK_SET); + fread(&undo, 1, 1,ppffile); + + fseek(ppffile, -6,SEEK_END); + memset(buffer,0,5); + fread(buffer, 4, 1,ppffile); + dizlen=0; + if(!strcmp(".DIZ", buffer)) + { + fseek(ppffile, -2,SEEK_END); + fread(&dizlen, 2, 1, ppffile); + dizlen+=36; + } + + fseek(ppffile, 0, SEEK_END); + count=ftell(ppffile); + count-=dizlen; + + if(blockcheck) + { + seekpos=1084; + count-=1084; + } + else + { + seekpos=60; + count-=60; + } + + break; + + default: + fclose(ppffile); + MessageBox(NULL,"Unknown PPF format!",libraryName,MB_OK); + return; + } + + do // now do the data reading + { + fseek(ppffile, seekpos, SEEK_SET); + fread(&pos, 4, 1, ppffile); + + if(method==2) fread(buffer, 4, 1, ppffile); // skip 4 bytes on ppf3 (no int64 support here) + + anz=0; // new! init anz (since it's no unsigned char anymore) + fread(&anz, 1, 1, ppffile); + fread(ppfmem, anz, 1, ppffile); + + ladr=pos/2352; + off=pos%2352; + + if(off+anz>2352) + { + anx=off+anz-2352; + anz-=(unsigned char)anx; + AddToPPF(ladr+1,0,anx,ppfmem+anz); + } + + AddToPPF(ladr,off,anz,ppfmem); // add to link list + + if(method==2) // adjust ppf3 size + { + if(undo) anz+=anz; + anz+=4; + } + + seekpos=seekpos+5+anz; + count=count-5-anz; + } + while(count!=0); // loop til end + + fclose(ppffile); + + FillPPFCache(); // build address array +} + +///////////////////////////////////////////////////////// diff --git a/plugins/CDVDpeops/ppf.h b/plugins/CDVDpeops/ppf.h index af20e48900..9421227ad0 100644 --- a/plugins/CDVDpeops/ppf.h +++ b/plugins/CDVDpeops/ppf.h @@ -1,32 +1,32 @@ -/*************************************************************************** - ppf.h - description - ------------------- - begin : Wed Sep 18 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/09/19 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -void FillPPFCache(void); -void FreePPFCache(void); -void CheckPPFCache(long addr,unsigned char * pB); -void AddToPPF(long ladr,long pos,long anz,char * ppfmem); -void BuildPPFCache(void); - +/*************************************************************************** + ppf.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +void FillPPFCache(void); +void FreePPFCache(void); +void CheckPPFCache(long addr,unsigned char * pB); +void AddToPPF(long ladr,long pos,long anz,char * ppfmem); +void BuildPPFCache(void); + diff --git a/plugins/CDVDpeops/read.c b/plugins/CDVDpeops/read.c index e0de2045a9..1f8e374e3d 100644 --- a/plugins/CDVDpeops/read.c +++ b/plugins/CDVDpeops/read.c @@ -1,910 +1,910 @@ -/*************************************************************************** - read.c - description - ------------------- - begin : Sun Nov 16 2003 - copyright : (C) 2003 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2003/11/16 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -///////////////////////////////////////////////////////// - -#include "stdafx.h" -#define _IN_READ -#include "externals.h" - -///////////////////////////////////////////////////////// - -READTRACKFUNC pReadTrackFunc=NULL; -GETPTRFUNC pGetPtrFunc=NULL; - -int iUseCaching=0; -int iTryAsync=0; -int iBufSel=0; - -unsigned char * pMainBuffer=0; -unsigned char * pCurrReadBuf=0; -unsigned char * pFirstReadBuf=0; -unsigned char * pAsyncBuffer=0; - -unsigned long lMaxAddr=0; -unsigned long lLastAddr = 0xFFFFFFFF; -unsigned long lLastAsyncAddr = 0xFFFFFFFF; -unsigned long lNeededAddr = 0xFFFFFFFF; -unsigned long lLastAccessedAddr = 0xFFFFFFFF; -int iLastAccessedMode=0; - -unsigned char * ptrBuffer[2]; -unsigned char * pAsyncFirstReadBuf[2]; - - -#define MAXQSIZE 16 -#define MAXQFETCH 8 - -unsigned long lAddrQ[MAXQSIZE]; -int iQPos=0; -int iQIdle=0; -int iQLockPos=-1; - -///////////////////////////////////////////////////////// -// thread helper vars - -HANDLE hReadThread = NULL; -BOOL bThreadEnded = FALSE; -HANDLE hThreadEvent[3]; -HANDLE hThreadMutex[2]; - -///////////////////////////////////////////////////////// -// internal MAXDATACACHE*64KB (4MB) data cache - -#define MAXDATACACHE 64 -unsigned long lDataCacheAddr[MAXDATACACHE]; -unsigned char * pDataCacheBuf[MAXDATACACHE]; -BOOL bDataCacheHit=FALSE; -int iUseDataCache=0; - -///////////////////////////////////////////////////////// -// main init func - -void CreateREADBufs(void) -{ - switch(iUseCaching) - { - case 4: iUseDataCache = 2; // use a special data cache on threadex reading - pReadTrackFunc = DoReadThreadEx; - pGetPtrFunc = GetREADThreadExPtr; break; - case 3: pReadTrackFunc = DoReadThread; - pGetPtrFunc = GetREADThreadPtr; break; - case 2: pReadTrackFunc = DoReadAsync; - pGetPtrFunc = NULL; break; - default: pReadTrackFunc = DoRead; - pGetPtrFunc = NULL; break; - } - - hThreadEvent[0]=NULL; // clear events/mutex - hThreadEvent[1]=NULL; - hThreadEvent[2]=NULL; - hThreadMutex[0]=NULL; - hThreadMutex[1]=NULL; - - AllocDataCache(); // build data cache, if wanted - - lLastAddr = 0xFFFFFFFF; - lLastAsyncAddr = 0xFFFFFFFF; - iBufSel = 0; - - if(iUseCaching) // some caching? need bigger buffer - pMainBuffer=(unsigned char *)malloc(MAXCDBUFFER); - else pMainBuffer=(unsigned char *)malloc(CDSECTOR+208+96); - - pCurrReadBuf=pFirstReadBuf=pMainBuffer+FRAMEBUFEXTRA; - - if(iUseCaching>=2) // async/thread mode - { - pAsyncBuffer=(unsigned char *)malloc(MAXCDBUFFER); - ptrBuffer[0]=pMainBuffer; - ptrBuffer[1]=pAsyncBuffer; - pAsyncFirstReadBuf[0]=pFirstReadBuf; - pAsyncFirstReadBuf[1]=pAsyncBuffer+FRAMEBUFEXTRA; - - if(iUseCaching>=3) // thread mode - { - DWORD dw; - bThreadEnded = FALSE; - - for(dw=0;dw<3;dw++) // -> create events - { - hThreadEvent[dw]=CreateEvent(NULL,TRUE,FALSE,NULL); - ResetEvent(hThreadEvent[dw]); - } - for(dw=0;dw<2;dw++) // -> create mutex - { - hThreadMutex[dw]=CreateMutex(NULL,FALSE,NULL); - } - if(iUseCaching==3) // -> create thread - hReadThread=CreateThread(NULL,0,READThread,0,0,&dw); - else - { - for(dw=0;dw signal: end thread - while(!bThreadEnded) {Sleep(5L);} // -> wait til ended - WaitForSingleObject(hThreadMutex[1],INFINITE); - ReleaseMutex(hThreadMutex[1]); - hReadThread=NULL; // -> clear handle - } - - if(hThreadEvent[0]) CloseHandle(hThreadEvent[0]); // kill events/mutex - if(hThreadEvent[1]) CloseHandle(hThreadEvent[1]); - if(hThreadEvent[2]) CloseHandle(hThreadEvent[2]); - if(hThreadMutex[0]) CloseHandle(hThreadMutex[0]); - if(hThreadMutex[1]) CloseHandle(hThreadMutex[1]); - - if(pMainBuffer) free(pMainBuffer); // free main data buf - pMainBuffer=NULL; - if(pAsyncBuffer) free(pAsyncBuffer); // free async data buf - pAsyncBuffer=NULL; - - FreeDataCache(); -} - -///////////////////////////////////////////////////////// -// retry on readng error (blocking) - -BOOL bReadRetry(FRAMEBUF * f) -{ - int iRetry=0; - - while (iRetry tell it to user - { - char szB[64]; - wsprintf(szB,"Read error on address %08lx!",f->dwFrame); - MessageBox(NULL,szB,libraryName,MB_OK); - } - return FALSE; // -> tell emu: bad - } - - return TRUE; -} - -//////////////////////////////////////////////////////// -///////////////////////////////////////////////////////// -///////////////////////////////////////////////////////// -// sync modes (caching 0 and 1) -// just reads one or more blocks, and always waits until -// reading is done -///////////////////////////////////////////////////////// - -BOOL DoRead(unsigned long addr) -{ - FRAMEBUF * f; - - //////////////////////////////////////////////////////// - - if(iUseCaching && // cache block available? - lLastAddr!=0xFFFFFFFF && - addr>=lLastAddr && // and addr in block? - addr<=(lLastAddr+MAXCACHEBLOCK)) - { - pCurrReadBuf=pFirstReadBuf+ // -> calc data ptr - ((addr-lLastAddr)*iUsedBlockSize); - if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); // -> apply ppf - return TRUE; // -> done - } - - //////////////////////////////////////////////////////// - - if(iUseDataCache && CheckDataCache(addr)) // cache used and data is in cache? set read ptr, if yes - return TRUE; // -> also fine - - //////////////////////////////////////////////////////// - - f=(FRAMEBUF *)pMainBuffer; // setup read for one sector - - f->dwFrameCnt = 1; - f->dwBufLen = iUsedBlockSize; - f->dwFrame = addr; - - pCurrReadBuf=pFirstReadBuf; - - //////////////////////////////////////////////////////// - - if(iUseCaching) // cache block? - { - if((addr+MAXCACHEBLOCK)dwFrameCnt = MAXCACHEBLOCK+1; // -> set bigger read - f->dwBufLen = (MAXCACHEBLOCK+1)*iUsedBlockSize; - lLastAddr = addr; // -> store addr of block - } - else - { - lLastAddr=0xFFFFFFFF; // no caching, no block addr - } - } - - //////////////////////////////////////////////////////// - - if(pReadFunc(TRUE,f)!=SS_COMP) // do a waiting read - { - if(!bReadRetry(f)) return FALSE; // and retry on error - } - - if(iUseDataCache && lLastAddr!=0xFFFFFFFF) // data cache used? and whole 64 k read block? - AddToDataCache(addr,pFirstReadBuf); // -> add the complete data to cache - - if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); // apply ppf - - return TRUE; -} - -///////////////////////////////////////////////////////// -///////////////////////////////////////////////////////// -///////////////////////////////////////////////////////// -// async mode (caching 2) -// this mode works fine with ASPI... -// the first read will be done sync, though, only the -// additional pre-fetching will be done async... -// well, with mdecs most reads will be prefetched, so -// speed is good... with IOCTL this mode is more like -// a 'double sync' reading, since IOCTL seems always -// to be blocking (see also notes for caching mode 3) -///////////////////////////////////////////////////////// - -BOOL DoReadAsync(unsigned long addr) -{ - FRAMEBUF * f; - - //////////////////////////////////////////////////////// - // 1. check if data is in already filled buffer - - if(lLastAddr!=0xFFFFFFFF && - addr>=lLastAddr && - addr<=(lLastAddr+MAXCACHEBLOCK)) - { - pCurrReadBuf=pAsyncFirstReadBuf[iBufSel]+ - ((addr-lLastAddr)*iUsedBlockSize); - - if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); - - iTryAsync=0; - return TRUE; - } - - //////////////////////////////////////////////////////// - // check data cache - - if(iUseDataCache && CheckDataCache(addr)) // cache used and data is in cache? set read ptr, if yes - return TRUE; // -> also fine - - //////////////////////////////////////////////////////// - // 2. not in main buffer? wait for async to be finished - - if(bDoWaiting) - { - WaitGenEvent(0xFFFFFFFF);bDoWaiting=FALSE; - if(sx.SRB_Status!=SS_COMP) lLastAsyncAddr=0xFFFFFFFF; - } - - //////////////////////////////////////////////////////// - // 3. check in asyncbuffer. if yes, swap buffers and do next async read - - if(lLastAsyncAddr!=0xFFFFFFFF && - addr>=lLastAsyncAddr && - addr<=(lLastAsyncAddr+MAXCACHEBLOCK)) - { - int iAsyncSel=iBufSel; // store old buf num - if(iBufSel==0) iBufSel=1; else iBufSel=0; // toggle to new num - - lLastAddr=lLastAsyncAddr; // set adr of block - pCurrReadBuf=pAsyncFirstReadBuf[iBufSel]+ // set data ptr - ((addr-lLastAddr)*iUsedBlockSize); - - if(iUseDataCache) // data cache used? - AddToDataCache(lLastAddr,pAsyncFirstReadBuf[iBufSel]); // -> add the complete 64k data to cache - - if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); // apply ppf - - iTryAsync=0; // data was async, reset count - addr=lLastAddr+MAXCACHEBLOCK+1; // calc adr of next prefetch - if(!((addr+MAXCACHEBLOCK)dwFrameCnt = MAXCACHEBLOCK+1; - f->dwBufLen = (MAXCACHEBLOCK+1)*iUsedBlockSize; - f->dwFrame = addr; - - lLastAsyncAddr=addr; // store prefetch addr - - if(pReadFunc(FALSE,f)!=SS_COMP) // start the async read - lLastAsyncAddr=0xFFFFFFFF; // -> if no success, no async prefetch buf available - - return TRUE; - } - - //////////////////////////////////////////////////////// - // here we do a sync read - - iBufSel=0; // read in buf 0 - - f=(FRAMEBUF *)ptrBuffer[0]; - f->dwFrame = addr; - - pCurrReadBuf=pFirstReadBuf; - - //////////////////////////////////////////////////////// - // if it's possible, we do a bigger read - - if((addr+MAXCACHEBLOCK)dwFrameCnt = MAXCACHEBLOCK+1; - f->dwBufLen = (MAXCACHEBLOCK+1)*iUsedBlockSize; - lLastAddr = addr; - } - else - { - f->dwFrameCnt = 1; - f->dwBufLen = iUsedBlockSize; - lLastAddr = 0xFFFFFFFF; - } - - //////////////////////////////////////////////////////// - // start read, wait til finished - - if(pReadFunc(TRUE,f)!=SS_COMP) - { - if(!bReadRetry(f)) return FALSE; - } - - if(iUseDataCache && lLastAddr!=0xFFFFFFFF) // data cache used? and complete 64k block? - AddToDataCache(addr,pAsyncFirstReadBuf[0]); // -> add the complete data to cache - - if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); - - //////////////////////////////////////////////////////// - // start additional async prefetch read, if it's ok - - iTryAsync++; - if(iTryAsync>1) {iTryAsync=2;return TRUE;} // prefetches seems to be useless right now, so turn them off until next real read - - addr+=MAXCACHEBLOCK+1; // prefetch addr - if(!((addr+MAXCACHEBLOCK)dwFrameCnt = MAXCACHEBLOCK+1; - f->dwBufLen = (MAXCACHEBLOCK+1)*iUsedBlockSize; - f->dwFrame = addr; - - lLastAsyncAddr= addr; - - if(pReadFunc(FALSE,f)!=SS_COMP) // start the async prefetch - lLastAsyncAddr=0xFFFFFFFF; - - return TRUE; -} - -///////////////////////////////////////////////////////// -///////////////////////////////////////////////////////// -///////////////////////////////////////////////////////// -// thread mode (caching 3) -// this mode helps with slower drives using the IOCTL -// interface (since that one seems to do always blocking -// reads, even when they are done overlapped). -// With ASPI, the thread mode performance will be more or less -// the same as with async caching mode 2... -// thread reading would be much more powerful, if the main -// emu would do: -// ... -// CDRreadTrack() -// ... do some other stuff here ... -// CDRgetBuffer() -// ... -// but lazy main emu coders seem to prefer: -// ... -// CDRreadTrack() -// CDRgetBuffer() -// ... -// so there is no time between the calls to do a good -// asynchronous read... sad, sad... -///////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////// -// reading thread... sleeps until a new read is signaled - -DWORD WINAPI READThread(LPVOID lpParameter) -{ - FRAMEBUF * f; - - while(WaitForMultipleObjects(2,hThreadEvent,FALSE, // wait until event to start (or event to end) get raised - INFINITE)==WAIT_OBJECT_0) - { - WaitForSingleObject(hThreadMutex[0],INFINITE); // read mutex: nobody else is allowed to read now - WaitForSingleObject(hThreadMutex[1],INFINITE); // variable access mutex: nobody else can change the vars now - ResetEvent(hThreadEvent[0]); // ok, kick event has been handled - SetEvent(hThreadEvent[2]); // set flag: we have started the read - - lLastAsyncAddr = lNeededAddr; // setup read and vars - f=(FRAMEBUF *)ptrBuffer[!iBufSel]; // !iSel = async buffer - f->dwFrame = lNeededAddr; - f->dwFrameCnt = min((lMaxAddr-lNeededAddr+1),(MAXCACHEBLOCK+1)); - f->dwBufLen = f->dwFrameCnt*iUsedBlockSize; - - ReleaseMutex(hThreadMutex[1]); // ok, vars have been changed, now that vars are again available for all - - if(pReadFunc(TRUE,f)!=SS_COMP) // do a blocking (sync) read - { - bReadRetry(f); // mmm... if reading fails a number of times, we don't have a chance to return 'bad' to emu with tread reading... life is hard :) - } - - ReleaseMutex(hThreadMutex[0]); // ok, read has done - } - - bThreadEnded=1; - return 0; -} - -///////////////////////////////////////////////////////// -// emu says: we need data at given addr soon... -// so, if we don't have it in any buffer, we kick a read -// ... called on CDRreadTrack() - -BOOL DoReadThread(unsigned long addr) -{ - if(!hReadThread) return FALSE; // no thread, no fun - - bDataCacheHit=FALSE; // init data cache hit flag (even if no cache is used...) - - if(lLastAddr!=0xFFFFFFFF && // data is in curr data buffer? - addr>=lLastAddr && - addr<=(lLastAddr+MAXCACHEBLOCK)) - return TRUE; // -> fine - - if(iUseDataCache && CheckDataCache(addr)) // data cache used and data is in cache? set read ptr, if yes - {bDataCacheHit=TRUE;return TRUE;} // -> and raise 'hit' flag, so we don't need to do anything in 'getbuffer' - - WaitForSingleObject(hThreadMutex[1],INFINITE); // wait to access 'buffer 1 vars' - - if(lLastAsyncAddr!=0xFFFFFFFF && // data is (or will be soon if reading is going on in thread now) in async buffer? - addr>=lLastAsyncAddr && - addr<=(lLastAsyncAddr+MAXCACHEBLOCK)) - { - ReleaseMutex(hThreadMutex[1]); // -> fine - return TRUE; - } - // data is not in buf0 and not in buf1: - lNeededAddr=addr; // set needed adr (mutex is active, so it's safe to change that) - ResetEvent(hThreadEvent[2]); // reset "read has started" flag - SetEvent(hThreadEvent[0]); // set "start read" flag... the read will start reading soon after - ReleaseMutex(hThreadMutex[1]); // done with var access - return TRUE; -} - -///////////////////////////////////////////////////////// -// emu says: gimme ptr to needed data... this will -// automatically do an async data prefetch read as well -// ... called on CDRgetBuffer() - -void GetREADThreadPtr(void) -{ - unsigned long addr=lLastAccessedAddr; - - if(bDataCacheHit) return; // if we had a data cache hit, the readbuf ptr is already fine, nothing else to do - - if(lLastAddr!=0xFFFFFFFF && // data is in buffer 0? - addr>=lLastAddr && - addr<=(lLastAddr+MAXCACHEBLOCK)) - { - pCurrReadBuf=pAsyncFirstReadBuf[iBufSel]+ // -> ok, return curr data buffer ptr - ((addr-lLastAddr)*iUsedBlockSize); - if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); - return; - } - - WaitForSingleObject(hThreadEvent[2],INFINITE); // wait until reading has started (it will take a small time after the read start kick, so we have to go sure that it has _really_ started) - WaitForSingleObject(hThreadMutex[0],INFINITE); // wait until reading has finished - - lLastAddr=lLastAsyncAddr; // move data to from async data to curr data buffer (by toggling iSel) - iBufSel=!iBufSel; - lLastAsyncAddr=0xFFFFFFFF; // nothing in async data buffer now - - lNeededAddr=addr+MAXCACHEBLOCK+1; // prefetch read addr - ResetEvent(hThreadEvent[2]); // reset "read has started" flag - SetEvent(hThreadEvent[0]); // signal for start next read - ReleaseMutex(hThreadMutex[0]); // ok, now reading in buffer 1 can start - - if(iUseDataCache) // data cache used? can be less then 64 kb with thread reading, but that doesn't matter here... will be either 64 k or (max-addr) sectors - AddToDataCache(lLastAddr, - pAsyncFirstReadBuf[iBufSel]); // -> add the complete data to cache - - pCurrReadBuf=pAsyncFirstReadBuf[iBufSel]+ // -> return the curr data buffer ptr - ((addr-lLastAddr)*iUsedBlockSize); - if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); -} - -///////////////////////////////////////////////////////// -///////////////////////////////////////////////////////// -///////////////////////////////////////////////////////// -// special thread mode (caching 4) -// this mode helps with certain drives -// basically it does the following: -// It has a queue for n prefetch reads. If the main emu is -// asking for an addr, the mode will check, if -// this addr is a) getting read right now, b) already -// in our 4 MB cache, c) already in the q. -// If no condition matches, it will add it in q... -// the same is done with the next n/2 addr blocks, so -// the q will keep the drive busy... also, if everything -// is cached (and the q is empty), we will add additional -// addresses to read, also to keep the drive busy, and to -// do the needed reading as soon as possible :) - -///////////////////////////////////////////////////////// -// reading thread... - -DWORD WINAPI READThreadEx(LPVOID lpParameter) -{ - FRAMEBUF * f; - - while(WaitForMultipleObjects(2,hThreadEvent,FALSE, // wait until event to start (or event to end) get raised - INFINITE)==WAIT_OBJECT_0) - { - while(1) - { - //------------------------------------------------// - WaitForSingleObject(hThreadMutex[1],INFINITE); // variable access mutex: nobody else can change the vars now - ResetEvent(hThreadEvent[0]); // ok, kick event has been handled - - if(lAddrQ[iQPos]==0xFFFFFFFF) // nothing to do? strange :) - {ReleaseMutex(hThreadMutex[1]);break;} - - f=(FRAMEBUF *)ptrBuffer[0]; - lNeededAddr = lAddrQ[iQPos]; // store it in 'Neededaddr' for checks outside the thread - f->dwFrame = lNeededAddr; - f->dwFrameCnt = min((lMaxAddr-f->dwFrame+1),(MAXCACHEBLOCK+1)); - f->dwBufLen = f->dwFrameCnt*iUsedBlockSize; - - lAddrQ[iQPos++]=0xFFFFFFFF; // set this slot as 'done' - if(iQPos>=MAXQSIZE) iQPos=0; // amnd inc the head pos - - ReleaseMutex(hThreadMutex[1]); // ok, vars have been changed, now that vars are again available for all - //------------------------------------------------// - WaitForSingleObject(hThreadMutex[0],INFINITE); // read mutex: nobody else is allowed to read now - if(!iCDROK) - { - ReleaseMutex(hThreadMutex[0]); - break; - } - - if(bCDDAPlay) // some cdda security... - { // it should just prevent prefetch reads happening in cdda mode, if this one breaks a 'needed' read, we are lost... - lNeededAddr=0xFFFFFFFF; // so maybe we should remove this check? mmm, we will see - ReleaseMutex(hThreadMutex[0]); - break; - } - - if(pReadFunc(TRUE,f)!=SS_COMP) // do a blocking (sync) read - { // mmm... if reading fails a number of times, we don't have a chance to return 'bad' to emu with thread reading... life is hard :) - bReadRetry(f); // but at least our 'wait for data in cache' getptr will not wait forever (just returning wrong data, ehehe) - } - - ReleaseMutex(hThreadMutex[0]); // ok, read has done - //------------------------------------------------// - WaitForSingleObject(hThreadMutex[1],INFINITE); // variable access mutex: nobody else can change the vars now - lNeededAddr=0xFFFFFFFF; // no read is now active - AddToDataCache(f->dwFrame,pFirstReadBuf); // add the complete data to cache - ReleaseMutex(hThreadMutex[1]); // ok, vars have been changed, now that vars are again available for all - //------------------------------------------------// - if(WaitForSingleObject(hThreadEvent[0],0)!=WAIT_OBJECT_0) - Sleep(1); // if nobody has started a new kick, let's sleep awhile to give Windows more room to breath - } - } - - bThreadEnded=1; - return 0; -} - -///////////////////////////////////////////////////////// -// emu says: we need data at given addr soon... -// so, if we don't have it in any buffer, we kick a read -// ... called on CDRreadTrack() - -//#define THREADEX_STRAIGHT - -BOOL DoReadThreadEx(unsigned long addr) -{ - int i,k,j=0; - - if(!hReadThread) return FALSE; // no thread, no fun - - WaitForSingleObject(hThreadMutex[1],INFINITE); // wait for data access - -//-----------------------------------------------------// -// straight reading try... should have been faster, but -// in 'real life' this approach keeps the cdrom drive -// spinning too much, giving other pc resources no room -// to breath... by increasing the thread 'Sleep' value -// the performance can get better, but then the annoying -// breaks we wanted to fight will show up again... -// so this type is disabled as long as nobody enables the -// define again :) - -#ifdef THREADEX_STRAIGHT - - if(addr>=lNeededAddr && - addr<=(lNeededAddr+MAXCACHEBLOCK)) - { - ReleaseMutex(hThreadMutex[1]); - return TRUE; - } - - for(k=0;k=lDataCacheAddr[i] && // -> addr found? - addr<=(lDataCacheAddr[i]+MAXCACHEBLOCK)) - { - if(k==0) iQLockPos=i; // -> if it's the current main addr, lock it, so no prefetch read overwrites its content - break; - } - } - if(i!=MAXDATACACHE) // found in data cache? - {addr=addr+MAXCACHEBLOCK+1;continue;} // -> do nothing with this addr, we have its content - else break; // here is the first unknown addr - } - - if(addr>=lMaxAddr) // check, if addr too big - { - ReleaseMutex(hThreadMutex[1]); - if(k==0) return FALSE; // -> if it's the main addr, there is an error - return TRUE; // -> otherwise we can't simply cache that addr - } - - for(i=0;i=lAddrQ[i] && // -> addr will be read soon? - addr<=(lAddrQ[i]+MAXCACHEBLOCK)) - { - addr=lAddrQ[i]; // --> take this aligned addr for new header - break; - } - } - - for(i=0;i=lMaxAddr) break; - } - - for(;i=lNeededAddr && // addr is getting read right now? - addr<=(lNeededAddr+MAXCACHEBLOCK)) // -> ok, we do nothing with it - {addr=addr+MAXCACHEBLOCK+1;continue;} - - for(i=0;i=lDataCacheAddr[i] && // -> addr found? - addr<=(lDataCacheAddr[i]+MAXCACHEBLOCK)) - { - if(k==0) iQLockPos=i; // -> if it's the current main addr, lock it, so no other prefetch read overwrites its content - break; - } - } - if(i!=MAXDATACACHE) // found in data cache? - {addr=addr+MAXCACHEBLOCK+1;continue;} // -> do nothing with this addr, we have its content - - for(i=0;i=lAddrQ[i] && // -> addr will be read soon? - addr<=(lAddrQ[i]+MAXCACHEBLOCK)) - { - if(k==0 && i!=iQPos) // curr needed addr is not on top of the q? - { - addr=lAddrQ[i]; // -> get the addr (our main addr is in it, but that one is more aligned to prev reads) - for(i=0;i clear whole q (we will fill the slots in that loop again) - i=MAXQSIZE; // -> sign for storing the addr in q - } - break; - } - } - if(i!=MAXQSIZE) // found in q? - {addr=addr+MAXCACHEBLOCK+1;continue;} // -> do nothing with this addr, we will have its content soon - - // not in q or data cache? - if(k==0) lAddrQ[iQPos]=addr; // -> if it's the main addr, store it on top of list - else // -> if it's a prefetch addr, try to store it elsewhere at the end of the q - { - j=iQPos; - for(i=0;i=MAXQSIZE) j=0; - } - } - - SetEvent(hThreadEvent[0]); // kick a read, if neccessary - addr=addr+MAXCACHEBLOCK+1; // next prefetch addr - if(addr>=lMaxAddr) break; // security, for detecting if we are at the end of cd - } - - //----------------------------------------------------// ok, and here's something to keep the drive busy... - - if(lAddrQ[iQPos]==0xFFFFFFFF && addr10) // more then x times? - { - iQIdle=0; - lAddrQ[iQPos]=addr; // we add the farest prefetch addr - SetEvent(hThreadEvent[0]); // and do an additional kick - } - } - else iQIdle=0; // not idling? ok - - //----------------------------------------------------// - -#endif - - ReleaseMutex(hThreadMutex[1]); - - return TRUE; -} - -///////////////////////////////////////////////////////// -// emu says: gimme ptr to needed data... this will -// automatically do an async data prefetch read as well -// ... called on CDRgetBuffer() - -void GetREADThreadExPtr(void) -{ - unsigned long addr=lLastAccessedAddr; - - while(1) - { - if(bThreadEnded) return; // main emu is already closing (thread is down)? bye - WaitForSingleObject(hThreadMutex[1],INFINITE); // wait for data access - if(CheckDataCache(addr)) // data now in cache? - { - ReleaseMutex(hThreadMutex[1]); // -> ok, done - return; - } - ReleaseMutex(hThreadMutex[1]); // else try again (no sleep here, we are blocking everything anyway) - } - -} - -///////////////////////////////////////////////////////// -///////////////////////////////////////////////////////// -///////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////// -// simple data cache - -void AllocDataCache(void) -{ - bDataCacheHit=FALSE; // init thread cache hit flag - if(!iUseCaching) iUseDataCache=0; // security: no additinal data cache, if no caching active - if(iUseDataCache) - { - int i; - for(i=0;i=MAXDATACACHE) iPos=0;} // -> don't use that pos, use next one - lDataCacheAddr[iPos]=addr; - memcpy(pDataCacheBuf[iPos],pB, - MAXCDBUFFER-FRAMEBUFEXTRA); - iPos++; if(iPos>=MAXDATACACHE) iPos=0; -} - -///////////////////////////////////////////////////////// -// easy data cache check: loop MAXDATACACHE blocks, set ptr if addr found - -BOOL CheckDataCache(unsigned long addr) -{ - int i; - - for(i=0;i=lDataCacheAddr[i] && - addr<=(lDataCacheAddr[i]+MAXCACHEBLOCK)) - { - pCurrReadBuf=pDataCacheBuf[i]+ - ((addr-lDataCacheAddr[i])*iUsedBlockSize); - if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); - return TRUE; - } - } - return FALSE; -} - -///////////////////////////////////////////////////////// - +/*************************************************************************** + read.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#define _IN_READ +#include "externals.h" + +///////////////////////////////////////////////////////// + +READTRACKFUNC pReadTrackFunc=NULL; +GETPTRFUNC pGetPtrFunc=NULL; + +int iUseCaching=0; +int iTryAsync=0; +int iBufSel=0; + +unsigned char * pMainBuffer=0; +unsigned char * pCurrReadBuf=0; +unsigned char * pFirstReadBuf=0; +unsigned char * pAsyncBuffer=0; + +unsigned long lMaxAddr=0; +unsigned long lLastAddr = 0xFFFFFFFF; +unsigned long lLastAsyncAddr = 0xFFFFFFFF; +unsigned long lNeededAddr = 0xFFFFFFFF; +unsigned long lLastAccessedAddr = 0xFFFFFFFF; +int iLastAccessedMode=0; + +unsigned char * ptrBuffer[2]; +unsigned char * pAsyncFirstReadBuf[2]; + + +#define MAXQSIZE 16 +#define MAXQFETCH 8 + +unsigned long lAddrQ[MAXQSIZE]; +int iQPos=0; +int iQIdle=0; +int iQLockPos=-1; + +///////////////////////////////////////////////////////// +// thread helper vars + +HANDLE hReadThread = NULL; +BOOL bThreadEnded = FALSE; +HANDLE hThreadEvent[3]; +HANDLE hThreadMutex[2]; + +///////////////////////////////////////////////////////// +// internal MAXDATACACHE*64KB (4MB) data cache + +#define MAXDATACACHE 64 +unsigned long lDataCacheAddr[MAXDATACACHE]; +unsigned char * pDataCacheBuf[MAXDATACACHE]; +BOOL bDataCacheHit=FALSE; +int iUseDataCache=0; + +///////////////////////////////////////////////////////// +// main init func + +void CreateREADBufs(void) +{ + switch(iUseCaching) + { + case 4: iUseDataCache = 2; // use a special data cache on threadex reading + pReadTrackFunc = DoReadThreadEx; + pGetPtrFunc = GetREADThreadExPtr; break; + case 3: pReadTrackFunc = DoReadThread; + pGetPtrFunc = GetREADThreadPtr; break; + case 2: pReadTrackFunc = DoReadAsync; + pGetPtrFunc = NULL; break; + default: pReadTrackFunc = DoRead; + pGetPtrFunc = NULL; break; + } + + hThreadEvent[0]=NULL; // clear events/mutex + hThreadEvent[1]=NULL; + hThreadEvent[2]=NULL; + hThreadMutex[0]=NULL; + hThreadMutex[1]=NULL; + + AllocDataCache(); // build data cache, if wanted + + lLastAddr = 0xFFFFFFFF; + lLastAsyncAddr = 0xFFFFFFFF; + iBufSel = 0; + + if(iUseCaching) // some caching? need bigger buffer + pMainBuffer=(unsigned char *)malloc(MAXCDBUFFER); + else pMainBuffer=(unsigned char *)malloc(CDSECTOR+208+96); + + pCurrReadBuf=pFirstReadBuf=pMainBuffer+FRAMEBUFEXTRA; + + if(iUseCaching>=2) // async/thread mode + { + pAsyncBuffer=(unsigned char *)malloc(MAXCDBUFFER); + ptrBuffer[0]=pMainBuffer; + ptrBuffer[1]=pAsyncBuffer; + pAsyncFirstReadBuf[0]=pFirstReadBuf; + pAsyncFirstReadBuf[1]=pAsyncBuffer+FRAMEBUFEXTRA; + + if(iUseCaching>=3) // thread mode + { + DWORD dw; + bThreadEnded = FALSE; + + for(dw=0;dw<3;dw++) // -> create events + { + hThreadEvent[dw]=CreateEvent(NULL,TRUE,FALSE,NULL); + ResetEvent(hThreadEvent[dw]); + } + for(dw=0;dw<2;dw++) // -> create mutex + { + hThreadMutex[dw]=CreateMutex(NULL,FALSE,NULL); + } + if(iUseCaching==3) // -> create thread + hReadThread=CreateThread(NULL,0,READThread,0,0,&dw); + else + { + for(dw=0;dw signal: end thread + while(!bThreadEnded) {Sleep(5L);} // -> wait til ended + WaitForSingleObject(hThreadMutex[1],INFINITE); + ReleaseMutex(hThreadMutex[1]); + hReadThread=NULL; // -> clear handle + } + + if(hThreadEvent[0]) CloseHandle(hThreadEvent[0]); // kill events/mutex + if(hThreadEvent[1]) CloseHandle(hThreadEvent[1]); + if(hThreadEvent[2]) CloseHandle(hThreadEvent[2]); + if(hThreadMutex[0]) CloseHandle(hThreadMutex[0]); + if(hThreadMutex[1]) CloseHandle(hThreadMutex[1]); + + if(pMainBuffer) free(pMainBuffer); // free main data buf + pMainBuffer=NULL; + if(pAsyncBuffer) free(pAsyncBuffer); // free async data buf + pAsyncBuffer=NULL; + + FreeDataCache(); +} + +///////////////////////////////////////////////////////// +// retry on readng error (blocking) + +BOOL bReadRetry(FRAMEBUF * f) +{ + int iRetry=0; + + while (iRetry tell it to user + { + char szB[64]; + wsprintf(szB,"Read error on address %08lx!",f->dwFrame); + MessageBox(NULL,szB,libraryName,MB_OK); + } + return FALSE; // -> tell emu: bad + } + + return TRUE; +} + +//////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +// sync modes (caching 0 and 1) +// just reads one or more blocks, and always waits until +// reading is done +///////////////////////////////////////////////////////// + +BOOL DoRead(unsigned long addr) +{ + FRAMEBUF * f; + + //////////////////////////////////////////////////////// + + if(iUseCaching && // cache block available? + lLastAddr!=0xFFFFFFFF && + addr>=lLastAddr && // and addr in block? + addr<=(lLastAddr+MAXCACHEBLOCK)) + { + pCurrReadBuf=pFirstReadBuf+ // -> calc data ptr + ((addr-lLastAddr)*iUsedBlockSize); + if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); // -> apply ppf + return TRUE; // -> done + } + + //////////////////////////////////////////////////////// + + if(iUseDataCache && CheckDataCache(addr)) // cache used and data is in cache? set read ptr, if yes + return TRUE; // -> also fine + + //////////////////////////////////////////////////////// + + f=(FRAMEBUF *)pMainBuffer; // setup read for one sector + + f->dwFrameCnt = 1; + f->dwBufLen = iUsedBlockSize; + f->dwFrame = addr; + + pCurrReadBuf=pFirstReadBuf; + + //////////////////////////////////////////////////////// + + if(iUseCaching) // cache block? + { + if((addr+MAXCACHEBLOCK)dwFrameCnt = MAXCACHEBLOCK+1; // -> set bigger read + f->dwBufLen = (MAXCACHEBLOCK+1)*iUsedBlockSize; + lLastAddr = addr; // -> store addr of block + } + else + { + lLastAddr=0xFFFFFFFF; // no caching, no block addr + } + } + + //////////////////////////////////////////////////////// + + if(pReadFunc(TRUE,f)!=SS_COMP) // do a waiting read + { + if(!bReadRetry(f)) return FALSE; // and retry on error + } + + if(iUseDataCache && lLastAddr!=0xFFFFFFFF) // data cache used? and whole 64 k read block? + AddToDataCache(addr,pFirstReadBuf); // -> add the complete data to cache + + if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); // apply ppf + + return TRUE; +} + +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +// async mode (caching 2) +// this mode works fine with ASPI... +// the first read will be done sync, though, only the +// additional pre-fetching will be done async... +// well, with mdecs most reads will be prefetched, so +// speed is good... with IOCTL this mode is more like +// a 'double sync' reading, since IOCTL seems always +// to be blocking (see also notes for caching mode 3) +///////////////////////////////////////////////////////// + +BOOL DoReadAsync(unsigned long addr) +{ + FRAMEBUF * f; + + //////////////////////////////////////////////////////// + // 1. check if data is in already filled buffer + + if(lLastAddr!=0xFFFFFFFF && + addr>=lLastAddr && + addr<=(lLastAddr+MAXCACHEBLOCK)) + { + pCurrReadBuf=pAsyncFirstReadBuf[iBufSel]+ + ((addr-lLastAddr)*iUsedBlockSize); + + if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); + + iTryAsync=0; + return TRUE; + } + + //////////////////////////////////////////////////////// + // check data cache + + if(iUseDataCache && CheckDataCache(addr)) // cache used and data is in cache? set read ptr, if yes + return TRUE; // -> also fine + + //////////////////////////////////////////////////////// + // 2. not in main buffer? wait for async to be finished + + if(bDoWaiting) + { + WaitGenEvent(0xFFFFFFFF);bDoWaiting=FALSE; + if(sx.SRB_Status!=SS_COMP) lLastAsyncAddr=0xFFFFFFFF; + } + + //////////////////////////////////////////////////////// + // 3. check in asyncbuffer. if yes, swap buffers and do next async read + + if(lLastAsyncAddr!=0xFFFFFFFF && + addr>=lLastAsyncAddr && + addr<=(lLastAsyncAddr+MAXCACHEBLOCK)) + { + int iAsyncSel=iBufSel; // store old buf num + if(iBufSel==0) iBufSel=1; else iBufSel=0; // toggle to new num + + lLastAddr=lLastAsyncAddr; // set adr of block + pCurrReadBuf=pAsyncFirstReadBuf[iBufSel]+ // set data ptr + ((addr-lLastAddr)*iUsedBlockSize); + + if(iUseDataCache) // data cache used? + AddToDataCache(lLastAddr,pAsyncFirstReadBuf[iBufSel]); // -> add the complete 64k data to cache + + if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); // apply ppf + + iTryAsync=0; // data was async, reset count + addr=lLastAddr+MAXCACHEBLOCK+1; // calc adr of next prefetch + if(!((addr+MAXCACHEBLOCK)dwFrameCnt = MAXCACHEBLOCK+1; + f->dwBufLen = (MAXCACHEBLOCK+1)*iUsedBlockSize; + f->dwFrame = addr; + + lLastAsyncAddr=addr; // store prefetch addr + + if(pReadFunc(FALSE,f)!=SS_COMP) // start the async read + lLastAsyncAddr=0xFFFFFFFF; // -> if no success, no async prefetch buf available + + return TRUE; + } + + //////////////////////////////////////////////////////// + // here we do a sync read + + iBufSel=0; // read in buf 0 + + f=(FRAMEBUF *)ptrBuffer[0]; + f->dwFrame = addr; + + pCurrReadBuf=pFirstReadBuf; + + //////////////////////////////////////////////////////// + // if it's possible, we do a bigger read + + if((addr+MAXCACHEBLOCK)dwFrameCnt = MAXCACHEBLOCK+1; + f->dwBufLen = (MAXCACHEBLOCK+1)*iUsedBlockSize; + lLastAddr = addr; + } + else + { + f->dwFrameCnt = 1; + f->dwBufLen = iUsedBlockSize; + lLastAddr = 0xFFFFFFFF; + } + + //////////////////////////////////////////////////////// + // start read, wait til finished + + if(pReadFunc(TRUE,f)!=SS_COMP) + { + if(!bReadRetry(f)) return FALSE; + } + + if(iUseDataCache && lLastAddr!=0xFFFFFFFF) // data cache used? and complete 64k block? + AddToDataCache(addr,pAsyncFirstReadBuf[0]); // -> add the complete data to cache + + if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); + + //////////////////////////////////////////////////////// + // start additional async prefetch read, if it's ok + + iTryAsync++; + if(iTryAsync>1) {iTryAsync=2;return TRUE;} // prefetches seems to be useless right now, so turn them off until next real read + + addr+=MAXCACHEBLOCK+1; // prefetch addr + if(!((addr+MAXCACHEBLOCK)dwFrameCnt = MAXCACHEBLOCK+1; + f->dwBufLen = (MAXCACHEBLOCK+1)*iUsedBlockSize; + f->dwFrame = addr; + + lLastAsyncAddr= addr; + + if(pReadFunc(FALSE,f)!=SS_COMP) // start the async prefetch + lLastAsyncAddr=0xFFFFFFFF; + + return TRUE; +} + +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +// thread mode (caching 3) +// this mode helps with slower drives using the IOCTL +// interface (since that one seems to do always blocking +// reads, even when they are done overlapped). +// With ASPI, the thread mode performance will be more or less +// the same as with async caching mode 2... +// thread reading would be much more powerful, if the main +// emu would do: +// ... +// CDRreadTrack() +// ... do some other stuff here ... +// CDRgetBuffer() +// ... +// but lazy main emu coders seem to prefer: +// ... +// CDRreadTrack() +// CDRgetBuffer() +// ... +// so there is no time between the calls to do a good +// asynchronous read... sad, sad... +///////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////// +// reading thread... sleeps until a new read is signaled + +DWORD WINAPI READThread(LPVOID lpParameter) +{ + FRAMEBUF * f; + + while(WaitForMultipleObjects(2,hThreadEvent,FALSE, // wait until event to start (or event to end) get raised + INFINITE)==WAIT_OBJECT_0) + { + WaitForSingleObject(hThreadMutex[0],INFINITE); // read mutex: nobody else is allowed to read now + WaitForSingleObject(hThreadMutex[1],INFINITE); // variable access mutex: nobody else can change the vars now + ResetEvent(hThreadEvent[0]); // ok, kick event has been handled + SetEvent(hThreadEvent[2]); // set flag: we have started the read + + lLastAsyncAddr = lNeededAddr; // setup read and vars + f=(FRAMEBUF *)ptrBuffer[!iBufSel]; // !iSel = async buffer + f->dwFrame = lNeededAddr; + f->dwFrameCnt = min((lMaxAddr-lNeededAddr+1),(MAXCACHEBLOCK+1)); + f->dwBufLen = f->dwFrameCnt*iUsedBlockSize; + + ReleaseMutex(hThreadMutex[1]); // ok, vars have been changed, now that vars are again available for all + + if(pReadFunc(TRUE,f)!=SS_COMP) // do a blocking (sync) read + { + bReadRetry(f); // mmm... if reading fails a number of times, we don't have a chance to return 'bad' to emu with tread reading... life is hard :) + } + + ReleaseMutex(hThreadMutex[0]); // ok, read has done + } + + bThreadEnded=1; + return 0; +} + +///////////////////////////////////////////////////////// +// emu says: we need data at given addr soon... +// so, if we don't have it in any buffer, we kick a read +// ... called on CDRreadTrack() + +BOOL DoReadThread(unsigned long addr) +{ + if(!hReadThread) return FALSE; // no thread, no fun + + bDataCacheHit=FALSE; // init data cache hit flag (even if no cache is used...) + + if(lLastAddr!=0xFFFFFFFF && // data is in curr data buffer? + addr>=lLastAddr && + addr<=(lLastAddr+MAXCACHEBLOCK)) + return TRUE; // -> fine + + if(iUseDataCache && CheckDataCache(addr)) // data cache used and data is in cache? set read ptr, if yes + {bDataCacheHit=TRUE;return TRUE;} // -> and raise 'hit' flag, so we don't need to do anything in 'getbuffer' + + WaitForSingleObject(hThreadMutex[1],INFINITE); // wait to access 'buffer 1 vars' + + if(lLastAsyncAddr!=0xFFFFFFFF && // data is (or will be soon if reading is going on in thread now) in async buffer? + addr>=lLastAsyncAddr && + addr<=(lLastAsyncAddr+MAXCACHEBLOCK)) + { + ReleaseMutex(hThreadMutex[1]); // -> fine + return TRUE; + } + // data is not in buf0 and not in buf1: + lNeededAddr=addr; // set needed adr (mutex is active, so it's safe to change that) + ResetEvent(hThreadEvent[2]); // reset "read has started" flag + SetEvent(hThreadEvent[0]); // set "start read" flag... the read will start reading soon after + ReleaseMutex(hThreadMutex[1]); // done with var access + return TRUE; +} + +///////////////////////////////////////////////////////// +// emu says: gimme ptr to needed data... this will +// automatically do an async data prefetch read as well +// ... called on CDRgetBuffer() + +void GetREADThreadPtr(void) +{ + unsigned long addr=lLastAccessedAddr; + + if(bDataCacheHit) return; // if we had a data cache hit, the readbuf ptr is already fine, nothing else to do + + if(lLastAddr!=0xFFFFFFFF && // data is in buffer 0? + addr>=lLastAddr && + addr<=(lLastAddr+MAXCACHEBLOCK)) + { + pCurrReadBuf=pAsyncFirstReadBuf[iBufSel]+ // -> ok, return curr data buffer ptr + ((addr-lLastAddr)*iUsedBlockSize); + if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); + return; + } + + WaitForSingleObject(hThreadEvent[2],INFINITE); // wait until reading has started (it will take a small time after the read start kick, so we have to go sure that it has _really_ started) + WaitForSingleObject(hThreadMutex[0],INFINITE); // wait until reading has finished + + lLastAddr=lLastAsyncAddr; // move data to from async data to curr data buffer (by toggling iSel) + iBufSel=!iBufSel; + lLastAsyncAddr=0xFFFFFFFF; // nothing in async data buffer now + + lNeededAddr=addr+MAXCACHEBLOCK+1; // prefetch read addr + ResetEvent(hThreadEvent[2]); // reset "read has started" flag + SetEvent(hThreadEvent[0]); // signal for start next read + ReleaseMutex(hThreadMutex[0]); // ok, now reading in buffer 1 can start + + if(iUseDataCache) // data cache used? can be less then 64 kb with thread reading, but that doesn't matter here... will be either 64 k or (max-addr) sectors + AddToDataCache(lLastAddr, + pAsyncFirstReadBuf[iBufSel]); // -> add the complete data to cache + + pCurrReadBuf=pAsyncFirstReadBuf[iBufSel]+ // -> return the curr data buffer ptr + ((addr-lLastAddr)*iUsedBlockSize); + if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); +} + +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +// special thread mode (caching 4) +// this mode helps with certain drives +// basically it does the following: +// It has a queue for n prefetch reads. If the main emu is +// asking for an addr, the mode will check, if +// this addr is a) getting read right now, b) already +// in our 4 MB cache, c) already in the q. +// If no condition matches, it will add it in q... +// the same is done with the next n/2 addr blocks, so +// the q will keep the drive busy... also, if everything +// is cached (and the q is empty), we will add additional +// addresses to read, also to keep the drive busy, and to +// do the needed reading as soon as possible :) + +///////////////////////////////////////////////////////// +// reading thread... + +DWORD WINAPI READThreadEx(LPVOID lpParameter) +{ + FRAMEBUF * f; + + while(WaitForMultipleObjects(2,hThreadEvent,FALSE, // wait until event to start (or event to end) get raised + INFINITE)==WAIT_OBJECT_0) + { + while(1) + { + //------------------------------------------------// + WaitForSingleObject(hThreadMutex[1],INFINITE); // variable access mutex: nobody else can change the vars now + ResetEvent(hThreadEvent[0]); // ok, kick event has been handled + + if(lAddrQ[iQPos]==0xFFFFFFFF) // nothing to do? strange :) + {ReleaseMutex(hThreadMutex[1]);break;} + + f=(FRAMEBUF *)ptrBuffer[0]; + lNeededAddr = lAddrQ[iQPos]; // store it in 'Neededaddr' for checks outside the thread + f->dwFrame = lNeededAddr; + f->dwFrameCnt = min((lMaxAddr-f->dwFrame+1),(MAXCACHEBLOCK+1)); + f->dwBufLen = f->dwFrameCnt*iUsedBlockSize; + + lAddrQ[iQPos++]=0xFFFFFFFF; // set this slot as 'done' + if(iQPos>=MAXQSIZE) iQPos=0; // amnd inc the head pos + + ReleaseMutex(hThreadMutex[1]); // ok, vars have been changed, now that vars are again available for all + //------------------------------------------------// + WaitForSingleObject(hThreadMutex[0],INFINITE); // read mutex: nobody else is allowed to read now + if(!iCDROK) + { + ReleaseMutex(hThreadMutex[0]); + break; + } + + if(bCDDAPlay) // some cdda security... + { // it should just prevent prefetch reads happening in cdda mode, if this one breaks a 'needed' read, we are lost... + lNeededAddr=0xFFFFFFFF; // so maybe we should remove this check? mmm, we will see + ReleaseMutex(hThreadMutex[0]); + break; + } + + if(pReadFunc(TRUE,f)!=SS_COMP) // do a blocking (sync) read + { // mmm... if reading fails a number of times, we don't have a chance to return 'bad' to emu with thread reading... life is hard :) + bReadRetry(f); // but at least our 'wait for data in cache' getptr will not wait forever (just returning wrong data, ehehe) + } + + ReleaseMutex(hThreadMutex[0]); // ok, read has done + //------------------------------------------------// + WaitForSingleObject(hThreadMutex[1],INFINITE); // variable access mutex: nobody else can change the vars now + lNeededAddr=0xFFFFFFFF; // no read is now active + AddToDataCache(f->dwFrame,pFirstReadBuf); // add the complete data to cache + ReleaseMutex(hThreadMutex[1]); // ok, vars have been changed, now that vars are again available for all + //------------------------------------------------// + if(WaitForSingleObject(hThreadEvent[0],0)!=WAIT_OBJECT_0) + Sleep(1); // if nobody has started a new kick, let's sleep awhile to give Windows more room to breath + } + } + + bThreadEnded=1; + return 0; +} + +///////////////////////////////////////////////////////// +// emu says: we need data at given addr soon... +// so, if we don't have it in any buffer, we kick a read +// ... called on CDRreadTrack() + +//#define THREADEX_STRAIGHT + +BOOL DoReadThreadEx(unsigned long addr) +{ + int i,k,j=0; + + if(!hReadThread) return FALSE; // no thread, no fun + + WaitForSingleObject(hThreadMutex[1],INFINITE); // wait for data access + +//-----------------------------------------------------// +// straight reading try... should have been faster, but +// in 'real life' this approach keeps the cdrom drive +// spinning too much, giving other pc resources no room +// to breath... by increasing the thread 'Sleep' value +// the performance can get better, but then the annoying +// breaks we wanted to fight will show up again... +// so this type is disabled as long as nobody enables the +// define again :) + +#ifdef THREADEX_STRAIGHT + + if(addr>=lNeededAddr && + addr<=(lNeededAddr+MAXCACHEBLOCK)) + { + ReleaseMutex(hThreadMutex[1]); + return TRUE; + } + + for(k=0;k=lDataCacheAddr[i] && // -> addr found? + addr<=(lDataCacheAddr[i]+MAXCACHEBLOCK)) + { + if(k==0) iQLockPos=i; // -> if it's the current main addr, lock it, so no prefetch read overwrites its content + break; + } + } + if(i!=MAXDATACACHE) // found in data cache? + {addr=addr+MAXCACHEBLOCK+1;continue;} // -> do nothing with this addr, we have its content + else break; // here is the first unknown addr + } + + if(addr>=lMaxAddr) // check, if addr too big + { + ReleaseMutex(hThreadMutex[1]); + if(k==0) return FALSE; // -> if it's the main addr, there is an error + return TRUE; // -> otherwise we can't simply cache that addr + } + + for(i=0;i=lAddrQ[i] && // -> addr will be read soon? + addr<=(lAddrQ[i]+MAXCACHEBLOCK)) + { + addr=lAddrQ[i]; // --> take this aligned addr for new header + break; + } + } + + for(i=0;i=lMaxAddr) break; + } + + for(;i=lNeededAddr && // addr is getting read right now? + addr<=(lNeededAddr+MAXCACHEBLOCK)) // -> ok, we do nothing with it + {addr=addr+MAXCACHEBLOCK+1;continue;} + + for(i=0;i=lDataCacheAddr[i] && // -> addr found? + addr<=(lDataCacheAddr[i]+MAXCACHEBLOCK)) + { + if(k==0) iQLockPos=i; // -> if it's the current main addr, lock it, so no other prefetch read overwrites its content + break; + } + } + if(i!=MAXDATACACHE) // found in data cache? + {addr=addr+MAXCACHEBLOCK+1;continue;} // -> do nothing with this addr, we have its content + + for(i=0;i=lAddrQ[i] && // -> addr will be read soon? + addr<=(lAddrQ[i]+MAXCACHEBLOCK)) + { + if(k==0 && i!=iQPos) // curr needed addr is not on top of the q? + { + addr=lAddrQ[i]; // -> get the addr (our main addr is in it, but that one is more aligned to prev reads) + for(i=0;i clear whole q (we will fill the slots in that loop again) + i=MAXQSIZE; // -> sign for storing the addr in q + } + break; + } + } + if(i!=MAXQSIZE) // found in q? + {addr=addr+MAXCACHEBLOCK+1;continue;} // -> do nothing with this addr, we will have its content soon + + // not in q or data cache? + if(k==0) lAddrQ[iQPos]=addr; // -> if it's the main addr, store it on top of list + else // -> if it's a prefetch addr, try to store it elsewhere at the end of the q + { + j=iQPos; + for(i=0;i=MAXQSIZE) j=0; + } + } + + SetEvent(hThreadEvent[0]); // kick a read, if neccessary + addr=addr+MAXCACHEBLOCK+1; // next prefetch addr + if(addr>=lMaxAddr) break; // security, for detecting if we are at the end of cd + } + + //----------------------------------------------------// ok, and here's something to keep the drive busy... + + if(lAddrQ[iQPos]==0xFFFFFFFF && addr10) // more then x times? + { + iQIdle=0; + lAddrQ[iQPos]=addr; // we add the farest prefetch addr + SetEvent(hThreadEvent[0]); // and do an additional kick + } + } + else iQIdle=0; // not idling? ok + + //----------------------------------------------------// + +#endif + + ReleaseMutex(hThreadMutex[1]); + + return TRUE; +} + +///////////////////////////////////////////////////////// +// emu says: gimme ptr to needed data... this will +// automatically do an async data prefetch read as well +// ... called on CDRgetBuffer() + +void GetREADThreadExPtr(void) +{ + unsigned long addr=lLastAccessedAddr; + + while(1) + { + if(bThreadEnded) return; // main emu is already closing (thread is down)? bye + WaitForSingleObject(hThreadMutex[1],INFINITE); // wait for data access + if(CheckDataCache(addr)) // data now in cache? + { + ReleaseMutex(hThreadMutex[1]); // -> ok, done + return; + } + ReleaseMutex(hThreadMutex[1]); // else try again (no sleep here, we are blocking everything anyway) + } + +} + +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// +///////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////// +// simple data cache + +void AllocDataCache(void) +{ + bDataCacheHit=FALSE; // init thread cache hit flag + if(!iUseCaching) iUseDataCache=0; // security: no additinal data cache, if no caching active + if(iUseDataCache) + { + int i; + for(i=0;i=MAXDATACACHE) iPos=0;} // -> don't use that pos, use next one + lDataCacheAddr[iPos]=addr; + memcpy(pDataCacheBuf[iPos],pB, + MAXCDBUFFER-FRAMEBUFEXTRA); + iPos++; if(iPos>=MAXDATACACHE) iPos=0; +} + +///////////////////////////////////////////////////////// +// easy data cache check: loop MAXDATACACHE blocks, set ptr if addr found + +BOOL CheckDataCache(unsigned long addr) +{ + int i; + + for(i=0;i=lDataCacheAddr[i] && + addr<=(lDataCacheAddr[i]+MAXCACHEBLOCK)) + { + pCurrReadBuf=pDataCacheBuf[i]+ + ((addr-lDataCacheAddr[i])*iUsedBlockSize); + if(ppfHead) CheckPPFCache(addr,pCurrReadBuf); + return TRUE; + } + } + return FALSE; +} + +///////////////////////////////////////////////////////// + diff --git a/plugins/CDVDpeops/read.h b/plugins/CDVDpeops/read.h index 8d475e3ebe..dbd5adaefa 100644 --- a/plugins/CDVDpeops/read.h +++ b/plugins/CDVDpeops/read.h @@ -1,41 +1,41 @@ -/*************************************************************************** - read.h - description - ------------------- - begin : Wed Sep 18 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/09/19 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -void CreateREADBufs(void); -void FreeREADBufs(void); -BOOL bReadRetry(FRAMEBUF * f); -BOOL DoReadAsync(unsigned long addr); -BOOL DoRead(unsigned long addr); -DWORD WINAPI READThread(LPVOID lpParameter); -BOOL DoReadThread(unsigned long addr); -void GetREADThreadPtr(void); -DWORD WINAPI READThreadEx(LPVOID lpParameter); -BOOL DoReadThreadEx(unsigned long addr); -void GetREADThreadExPtr(void); -void AllocDataCache(void); -void FreeDataCache(void); -void AddToDataCache(unsigned long addr,unsigned char * pB); -BOOL CheckDataCache(unsigned long addr); +/*************************************************************************** + read.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +void CreateREADBufs(void); +void FreeREADBufs(void); +BOOL bReadRetry(FRAMEBUF * f); +BOOL DoReadAsync(unsigned long addr); +BOOL DoRead(unsigned long addr); +DWORD WINAPI READThread(LPVOID lpParameter); +BOOL DoReadThread(unsigned long addr); +void GetREADThreadPtr(void); +DWORD WINAPI READThreadEx(LPVOID lpParameter); +BOOL DoReadThreadEx(unsigned long addr); +void GetREADThreadExPtr(void); +void AllocDataCache(void); +void FreeDataCache(void); +void AddToDataCache(unsigned long addr,unsigned char * pB); +BOOL CheckDataCache(unsigned long addr); diff --git a/plugins/CDVDpeops/resource.h b/plugins/CDVDpeops/resource.h index 3e2e235509..48e1c78359 100644 --- a/plugins/CDVDpeops/resource.h +++ b/plugins/CDVDpeops/resource.h @@ -1,56 +1,56 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by cdvdPeops.rc -// -#define IDD_CONFIG 101 -#define IDD_ABOUT 102 -#define IDD_SUB 104 -#define IDC_DRIVE 1000 -#define IDC_RTYPE 1001 -#define IDC_AUTO 1002 -#define IDC_CACHE 1003 -#define IDC_SPEEDLIMIT 1004 -#define IDC_SPEED 1005 -#define IDC_NOWAIT 1006 -#define IDC_RETRY 1007 -#define IDC_SHOWREADERR 1008 -#define IDC_TRYAGAIN 1009 -#define IDC_USEPPF 1010 -#define IDC_PPFFILE 1011 -#define IDC_CHOOSEFILE 1012 -#define IDC_IMODE 1013 -#define IDC_RAWTXT 1014 -#define IDC_TRAYSTATE 1014 -#define IDC_SUBCHAN0 1015 -#define IDC_SUBCHAN1 1016 -#define IDC_DATACACHE 1016 -#define IDC_SUBCHAN2 1017 -#define IDC_SUBFILE 1018 -#define IDC_CHOOSESUBF 1019 -#define IDC_CREATESUB 1020 -#define IDC_CHOOSEOUTF 1020 -#define IDC_SUBTYPE 1021 -#define IDC_SUBSTATIC 1023 -#define IDC_WAITSTATIC 1024 -#define IDC_SUBFRAME 1026 -#define IDC_SUBOUTSTATIC 1027 -#define IDC_SUBFILEEDIT 1028 -#define IDC_SUBOUTSTATIC2 1029 -#define IDC_OUTFILEEDIT 1030 -#define IDC_SUBMODE1 1031 -#define IDC_SUBMODE2 1032 -#define IDC_SUBOUTSTATIC3 1033 -#define IDC_SUBFILL 1034 -#define IDC_SUBOUTSTATIC4 1035 -#define IDC_SFSTATIC 1035 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 107 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1036 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by cdvdPeops.rc +// +#define IDD_CONFIG 101 +#define IDD_ABOUT 102 +#define IDD_SUB 104 +#define IDC_DRIVE 1000 +#define IDC_RTYPE 1001 +#define IDC_AUTO 1002 +#define IDC_CACHE 1003 +#define IDC_SPEEDLIMIT 1004 +#define IDC_SPEED 1005 +#define IDC_NOWAIT 1006 +#define IDC_RETRY 1007 +#define IDC_SHOWREADERR 1008 +#define IDC_TRYAGAIN 1009 +#define IDC_USEPPF 1010 +#define IDC_PPFFILE 1011 +#define IDC_CHOOSEFILE 1012 +#define IDC_IMODE 1013 +#define IDC_RAWTXT 1014 +#define IDC_TRAYSTATE 1014 +#define IDC_SUBCHAN0 1015 +#define IDC_SUBCHAN1 1016 +#define IDC_DATACACHE 1016 +#define IDC_SUBCHAN2 1017 +#define IDC_SUBFILE 1018 +#define IDC_CHOOSESUBF 1019 +#define IDC_CREATESUB 1020 +#define IDC_CHOOSEOUTF 1020 +#define IDC_SUBTYPE 1021 +#define IDC_SUBSTATIC 1023 +#define IDC_WAITSTATIC 1024 +#define IDC_SUBFRAME 1026 +#define IDC_SUBOUTSTATIC 1027 +#define IDC_SUBFILEEDIT 1028 +#define IDC_SUBOUTSTATIC2 1029 +#define IDC_OUTFILEEDIT 1030 +#define IDC_SUBMODE1 1031 +#define IDC_SUBMODE2 1032 +#define IDC_SUBOUTSTATIC3 1033 +#define IDC_SUBFILL 1034 +#define IDC_SUBOUTSTATIC4 1035 +#define IDC_SFSTATIC 1035 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 107 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1036 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/CDVDpeops/scsi.h b/plugins/CDVDpeops/scsi.h index 5a5603126d..f81a22450a 100644 --- a/plugins/CDVDpeops/scsi.h +++ b/plugins/CDVDpeops/scsi.h @@ -1,55 +1,55 @@ -/*************************************************************************** - scsi.h - description - ------------------- - begin : Wed Sep 18 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/09/28 - linuzappz -// - added GetSCSIStatus -// -// 2002/09/19 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -int GetSCSIDevice(int iA,int iT,int iL); -int GetSCSIStatus(int iA,int iT,int iL); -DWORD GetSCSITOC(LPTOC toc); -int GetSCSICDDrives(char * pDList); -DWORD PlaySCSIAudio(unsigned long start,unsigned long len); -unsigned char * GetSCSIAudioSub(void); -BOOL TestSCSIUnitReady(void); -DWORD SetSCSISpeed(DWORD dwSpeed); -DWORD ReadSCSI_BE(BOOL bWait,FRAMEBUF * f); -DWORD ReadSCSI_BE_Sub(BOOL bWait,FRAMEBUF * f); -DWORD ReadSCSI_BE_Sub_1(BOOL bWait,FRAMEBUF * f); -DWORD InitSCSI_28_1(void); -DWORD InitSCSI_28_2(void); -DWORD DeInitSCSI_28(void); -DWORD ReadSCSI_28(BOOL bWait,FRAMEBUF * f); -DWORD ReadSCSI_28_Sub(BOOL bWait,FRAMEBUF * f); -DWORD InitSCSI_28_2048(void); -DWORD ReadSCSI_28_2048(BOOL bWait,FRAMEBUF * f); -DWORD ReadSCSI_28_2048_Ex(BOOL bWait,FRAMEBUF * f); -int ReadSub_BE_2(unsigned long addr,unsigned char * pBuf,int iNum); -int ReadSub_BE_2_1(unsigned long addr,unsigned char * pBuf,int iNum); -int ReadSub_D8(unsigned long addr,unsigned char * pBuf,int iNum); -void DecodeSub_BE_2_1(unsigned char * pBuf); -DWORD CheckSCSIReadMode(void); -DWORD ReadSCSI_Dummy(BOOL bWait,FRAMEBUF * f); - +/*************************************************************************** + scsi.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/28 - linuzappz +// - added GetSCSIStatus +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +int GetSCSIDevice(int iA,int iT,int iL); +int GetSCSIStatus(int iA,int iT,int iL); +DWORD GetSCSITOC(LPTOC toc); +int GetSCSICDDrives(char * pDList); +DWORD PlaySCSIAudio(unsigned long start,unsigned long len); +unsigned char * GetSCSIAudioSub(void); +BOOL TestSCSIUnitReady(void); +DWORD SetSCSISpeed(DWORD dwSpeed); +DWORD ReadSCSI_BE(BOOL bWait,FRAMEBUF * f); +DWORD ReadSCSI_BE_Sub(BOOL bWait,FRAMEBUF * f); +DWORD ReadSCSI_BE_Sub_1(BOOL bWait,FRAMEBUF * f); +DWORD InitSCSI_28_1(void); +DWORD InitSCSI_28_2(void); +DWORD DeInitSCSI_28(void); +DWORD ReadSCSI_28(BOOL bWait,FRAMEBUF * f); +DWORD ReadSCSI_28_Sub(BOOL bWait,FRAMEBUF * f); +DWORD InitSCSI_28_2048(void); +DWORD ReadSCSI_28_2048(BOOL bWait,FRAMEBUF * f); +DWORD ReadSCSI_28_2048_Ex(BOOL bWait,FRAMEBUF * f); +int ReadSub_BE_2(unsigned long addr,unsigned char * pBuf,int iNum); +int ReadSub_BE_2_1(unsigned long addr,unsigned char * pBuf,int iNum); +int ReadSub_D8(unsigned long addr,unsigned char * pBuf,int iNum); +void DecodeSub_BE_2_1(unsigned char * pBuf); +DWORD CheckSCSIReadMode(void); +DWORD ReadSCSI_Dummy(BOOL bWait,FRAMEBUF * f); + diff --git a/plugins/CDVDpeops/scsidefs.h b/plugins/CDVDpeops/scsidefs.h index 180b21c546..7db5c9e612 100644 --- a/plugins/CDVDpeops/scsidefs.h +++ b/plugins/CDVDpeops/scsidefs.h @@ -1,579 +1,579 @@ -//*************************************************************************** -// -// Name: SCSIDEFS.H -// -// Description: SCSI definitions ('C' Language) -// -//*************************************************************************** - -//*************************************************************************** -// %%% TARGET STATUS VALUES %%% -//*************************************************************************** -#define STATUS_GOOD 0x00 // Status Good -#define STATUS_CHKCOND 0x02 // Check Condition -#define STATUS_CONDMET 0x04 // Condition Met -#define STATUS_BUSY 0x08 // Busy -#define STATUS_INTERM 0x10 // Intermediate -#define STATUS_INTCDMET 0x14 // Intermediate-condition met -#define STATUS_RESCONF 0x18 // Reservation conflict -#define STATUS_COMTERM 0x22 // Command Terminated -#define STATUS_QFULL 0x28 // Queue full - -//*************************************************************************** -// %%% SCSI MISCELLANEOUS EQUATES %%% -//*************************************************************************** -#define MAXLUN 7 // Maximum Logical Unit Id -#define MAXTARG 7 // Maximum Target Id -#define MAX_SCSI_LUNS 64 // Maximum Number of SCSI LUNs -#define MAX_NUM_HA 8 // Maximum Number of SCSI HA's - -//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ -// -// %%% SCSI COMMAND OPCODES %%% -// -///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ - -//*************************************************************************** -// %%% Commands for all Device Types %%% -//*************************************************************************** -#define SCSI_CHANGE_DEF 0x40 // Change Definition (Optional) -#define SCSI_COMPARE 0x39 // Compare (O) -#define SCSI_COPY 0x18 // Copy (O) -#define SCSI_COP_VERIFY 0x3A // Copy and Verify (O) -#define SCSI_INQUIRY 0x12 // Inquiry (MANDATORY) -#define SCSI_LOG_SELECT 0x4C // Log Select (O) -#define SCSI_LOG_SENSE 0x4D // Log Sense (O) -#define SCSI_MODE_SEL6 0x15 // Mode Select 6-byte (Device Specific) -#define SCSI_MODE_SEL10 0x55 // Mode Select 10-byte (Device Specific) -#define SCSI_MODE_SEN6 0x1A // Mode Sense 6-byte (Device Specific) -#define SCSI_MODE_SEN10 0x5A // Mode Sense 10-byte (Device Specific) -#define SCSI_READ_BUFF 0x3C // Read Buffer (O) -#define SCSI_REQ_SENSE 0x03 // Request Sense (MANDATORY) -#define SCSI_SEND_DIAG 0x1D // Send Diagnostic (O) -#define SCSI_TST_U_RDY 0x00 // Test Unit Ready (MANDATORY) -#define SCSI_WRITE_BUFF 0x3B // Write Buffer (O) - -//*************************************************************************** -// %%% Commands Unique to Direct Access Devices %%% -//*************************************************************************** -#define SCSI_COMPARE 0x39 // Compare (O) -#define SCSI_FORMAT 0x04 // Format Unit (MANDATORY) -#define SCSI_LCK_UN_CAC 0x36 // Lock Unlock Cache (O) -#define SCSI_PREFETCH 0x34 // Prefetch (O) -#define SCSI_MED_REMOVL 0x1E // Prevent/Allow medium Removal (O) -#define SCSI_READ6 0x08 // Read 6-byte (MANDATORY) -#define SCSI_READ10 0x28 // Read 10-byte (MANDATORY) -#define SCSI_RD_CAPAC 0x25 // Read Capacity (MANDATORY) -#define SCSI_RD_DEFECT 0x37 // Read Defect Data (O) -#define SCSI_READ_LONG 0x3E // Read Long (O) -#define SCSI_REASS_BLK 0x07 // Reassign Blocks (O) -#define SCSI_RCV_DIAG 0x1C // Receive Diagnostic Results (O) -#define SCSI_RELEASE 0x17 // Release Unit (MANDATORY) -#define SCSI_REZERO 0x01 // Rezero Unit (O) -#define SCSI_SRCH_DAT_E 0x31 // Search Data Equal (O) -#define SCSI_SRCH_DAT_H 0x30 // Search Data High (O) -#define SCSI_SRCH_DAT_L 0x32 // Search Data Low (O) -#define SCSI_SEEK6 0x0B // Seek 6-Byte (O) -#define SCSI_SEEK10 0x2B // Seek 10-Byte (O) -#define SCSI_SEND_DIAG 0x1D // Send Diagnostics (MANDATORY) -#define SCSI_SET_LIMIT 0x33 // Set Limits (O) -#define SCSI_START_STP 0x1B // Start/Stop Unit (O) -#define SCSI_SYNC_CACHE 0x35 // Synchronize Cache (O) -#define SCSI_VERIFY 0x2F // Verify (O) -#define SCSI_WRITE6 0x0A // Write 6-Byte (MANDATORY) -#define SCSI_WRITE10 0x2A // Write 10-Byte (MANDATORY) -#define SCSI_WRT_VERIFY 0x2E // Write and Verify (O) -#define SCSI_WRITE_LONG 0x3F // Write Long (O) -#define SCSI_WRITE_SAME 0x41 // Write Same (O) - -//*************************************************************************** -// %%% Commands Unique to Sequential Access Devices %%% -//*************************************************************************** -#define SCSI_ERASE 0x19 // Erase (MANDATORY) -#define SCSI_LOAD_UN 0x1B // Load/Unload (O) -#define SCSI_LOCATE 0x2B // Locate (O) -#define SCSI_RD_BLK_LIM 0x05 // Read Block Limits (MANDATORY) -#define SCSI_READ_POS 0x34 // Read Position (O) -#define SCSI_READ_REV 0x0F // Read Reverse (O) -#define SCSI_REC_BF_DAT 0x14 // Recover Buffer Data (O) -#define SCSI_RESERVE 0x16 // Reserve Unit (MANDATORY) -#define SCSI_REWIND 0x01 // Rewind (MANDATORY) -#define SCSI_SPACE 0x11 // Space (MANDATORY) -#define SCSI_VERIFY_T 0x13 // Verify (Tape) (O) -#define SCSI_WRT_FILE 0x10 // Write Filemarks (MANDATORY) - -//*************************************************************************** -// %%% Commands Unique to Printer Devices %%% -//*************************************************************************** -#define SCSI_PRINT 0x0A // Print (MANDATORY) -#define SCSI_SLEW_PNT 0x0B // Slew and Print (O) -#define SCSI_STOP_PNT 0x1B // Stop Print (O) -#define SCSI_SYNC_BUFF 0x10 // Synchronize Buffer (O) - -//*************************************************************************** -// %%% Commands Unique to Processor Devices %%% -//*************************************************************************** -#define SCSI_RECEIVE 0x08 // Receive (O) -#define SCSI_SEND 0x0A // Send (O) - -//*************************************************************************** -// %%% Commands Unique to Write-Once Devices %%% -//*************************************************************************** -#define SCSI_MEDIUM_SCN 0x38 // Medium Scan (O) -#define SCSI_SRCHDATE10 0x31 // Search Data Equal 10-Byte (O) -#define SCSI_SRCHDATE12 0xB1 // Search Data Equal 12-Byte (O) -#define SCSI_SRCHDATH10 0x30 // Search Data High 10-Byte (O) -#define SCSI_SRCHDATH12 0xB0 // Search Data High 12-Byte (O) -#define SCSI_SRCHDATL10 0x32 // Search Data Low 10-Byte (O) -#define SCSI_SRCHDATL12 0xB2 // Search Data Low 12-Byte (O) -#define SCSI_SET_LIM_10 0x33 // Set Limits 10-Byte (O) -#define SCSI_SET_LIM_12 0xB3 // Set Limits 10-Byte (O) -#define SCSI_VERIFY10 0x2F // Verify 10-Byte (O) -#define SCSI_VERIFY12 0xAF // Verify 12-Byte (O) -#define SCSI_WRITE12 0xAA // Write 12-Byte (O) -#define SCSI_WRT_VER10 0x2E // Write and Verify 10-Byte (O) -#define SCSI_WRT_VER12 0xAE // Write and Verify 12-Byte (O) - -//*************************************************************************** -// %%% Commands Unique to CD-ROM Devices %%% -//*************************************************************************** -#define SCSI_PLAYAUD_10 0x45 // Play Audio 10-Byte (O) -#define SCSI_PLAYAUD_12 0xA5 // Play Audio 12-Byte 12-Byte (O) -#define SCSI_PLAYAUDMSF 0x47 // Play Audio MSF (O) -#define SCSI_PLAYA_TKIN 0x48 // Play Audio Track/Index (O) -#define SCSI_PLYTKREL10 0x49 // Play Track Relative 10-Byte (O) -#define SCSI_PLYTKREL12 0xA9 // Play Track Relative 12-Byte (O) -#define SCSI_READCDCAP 0x25 // Read CD-ROM Capacity (MANDATORY) -#define SCSI_READHEADER 0x44 // Read Header (O) -#define SCSI_SUBCHANNEL 0x42 // Read Subchannel (O) -#define SCSI_READ_TOC 0x43 // Read TOC (O) - -//*************************************************************************** -// %%% Commands Unique to Scanner Devices %%% -//*************************************************************************** -#define SCSI_GETDBSTAT 0x34 // Get Data Buffer Status (O) -#define SCSI_GETWINDOW 0x25 // Get Window (O) -#define SCSI_OBJECTPOS 0x31 // Object Postion (O) -#define SCSI_SCAN 0x1B // Scan (O) -#define SCSI_SETWINDOW 0x24 // Set Window (MANDATORY) - -//*************************************************************************** -// %%% Commands Unique to Optical Memory Devices %%% -//*************************************************************************** -#define SCSI_UpdateBlk 0x3D // Update Block (O) - -//*************************************************************************** -// %%% Commands Unique to Medium Changer Devices %%% -//*************************************************************************** -#define SCSI_EXCHMEDIUM 0xA6 // Exchange Medium (O) -#define SCSI_INITELSTAT 0x07 // Initialize Element Status (O) -#define SCSI_POSTOELEM 0x2B // Position to Element (O) -#define SCSI_REQ_VE_ADD 0xB5 // Request Volume Element Address (O) -#define SCSI_SENDVOLTAG 0xB6 // Send Volume Tag (O) - -//*************************************************************************** -// %%% Commands Unique to Communication Devices %%% -//*************************************************************************** -#define SCSI_GET_MSG_6 0x08 // Get Message 6-Byte (MANDATORY) -#define SCSI_GET_MSG_10 0x28 // Get Message 10-Byte (O) -#define SCSI_GET_MSG_12 0xA8 // Get Message 12-Byte (O) -#define SCSI_SND_MSG_6 0x0A // Send Message 6-Byte (MANDATORY) -#define SCSI_SND_MSG_10 0x2A // Send Message 10-Byte (O) -#define SCSI_SND_MSG_12 0xAA // Send Message 12-Byte (O) - -//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ -// -// %%% END OF SCSI COMMAND OPCODES %%% -// -///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ - -//*************************************************************************** -// %%% Request Sense Data Format %%% -//*************************************************************************** -typedef struct { - - BYTE ErrorCode; // Error Code (70H or 71H) - BYTE SegmentNum; // Number of current segment descriptor - BYTE SenseKey; // Sense Key(See bit definitions too) - BYTE InfoByte0; // Information MSB - BYTE InfoByte1; // Information MID - BYTE InfoByte2; // Information MID - BYTE InfoByte3; // Information LSB - BYTE AddSenLen; // Additional Sense Length - BYTE ComSpecInf0; // Command Specific Information MSB - BYTE ComSpecInf1; // Command Specific Information MID - BYTE ComSpecInf2; // Command Specific Information MID - BYTE ComSpecInf3; // Command Specific Information LSB - BYTE AddSenseCode; // Additional Sense Code - BYTE AddSenQual; // Additional Sense Code Qualifier - BYTE FieldRepUCode; // Field Replaceable Unit Code - BYTE SenKeySpec15; // Sense Key Specific 15th byte - BYTE SenKeySpec16; // Sense Key Specific 16th byte - BYTE SenKeySpec17; // Sense Key Specific 17th byte - BYTE AddSenseBytes; // Additional Sense Bytes - -} SENSE_DATA_FMT; - -//*************************************************************************** -// %%% REQUEST SENSE ERROR CODE %%% -//*************************************************************************** -#define SERROR_CURRENT 0x70 // Current Errors -#define SERROR_DEFERED 0x71 // Deferred Errors - -//*************************************************************************** -// %%% REQUEST SENSE BIT DEFINITIONS %%% -//*************************************************************************** -#define SENSE_VALID 0x80 // Byte 0 Bit 7 -#define SENSE_FILEMRK 0x80 // Byte 2 Bit 7 -#define SENSE_EOM 0x40 // Byte 2 Bit 6 -#define SENSE_ILI 0x20 // Byte 2 Bit 5 - -//*************************************************************************** -// %%% REQUEST SENSE SENSE KEY DEFINITIONS %%% -//*************************************************************************** -#define KEY_NOSENSE 0x00 // No Sense -#define KEY_RECERROR 0x01 // Recovered Error -#define KEY_NOTREADY 0x02 // Not Ready -#define KEY_MEDIUMERR 0x03 // Medium Error -#define KEY_HARDERROR 0x04 // Hardware Error -#define KEY_ILLGLREQ 0x05 // Illegal Request -#define KEY_UNITATT 0x06 // Unit Attention -#define KEY_DATAPROT 0x07 // Data Protect -#define KEY_BLANKCHK 0x08 // Blank Check -#define KEY_VENDSPEC 0x09 // Vendor Specific -#define KEY_COPYABORT 0x0A // Copy Abort -#define KEY_EQUAL 0x0C // Equal (Search) -#define KEY_VOLOVRFLW 0x0D // Volume Overflow -#define KEY_MISCOMP 0x0E // Miscompare (Search) -#define KEY_RESERVED 0x0F // Reserved - -//*************************************************************************** -// %%% PERIPHERAL DEVICE TYPE DEFINITIONS %%% -//*************************************************************************** -#define DTYPE_DASD 0x00 // Disk Device -#define DTYPE_SEQD 0x01 // Tape Device -#define DTYPE_PRNT 0x02 // Printer -#define DTYPE_PROC 0x03 // Processor -#define DTYPE_WORM 0x04 // Write-once read-multiple -#define DTYPE_CROM 0x05 // CD-ROM device -#define DTYPE_CDROM 0x05 // CD-ROM device -#define DTYPE_SCAN 0x06 // Scanner device -#define DTYPE_OPTI 0x07 // Optical memory device -#define DTYPE_JUKE 0x08 // Medium Changer device -#define DTYPE_COMM 0x09 // Communications device -#define DTYPE_RESL 0x0A // Reserved (low) -#define DTYPE_RESH 0x1E // Reserved (high) -#define DTYPE_UNKNOWN 0x1F // Unknown or no device type - -//*************************************************************************** -// %%% ANSI APPROVED VERSION DEFINITIONS %%% -//*************************************************************************** -#define ANSI_MAYBE 0x0 // Device may or may not be ANSI approved stand -#define ANSI_SCSI1 0x1 // Device complies to ANSI X3.131-1986 (SCSI-1) -#define ANSI_SCSI2 0x2 // Device complies to SCSI-2 -#define ANSI_RESLO 0x3 // Reserved (low) -#define ANSI_RESHI 0x7 // Reserved (high) - - -//////////////////////////////////////////////////////////////// - -typedef struct { - USHORT Length; - UCHAR ScsiStatus; - UCHAR PathId; - UCHAR TargetId; - UCHAR Lun; - UCHAR CdbLength; - UCHAR SenseInfoLength; - UCHAR DataIn; - ULONG DataTransferLength; - ULONG TimeOutValue; - ULONG DataBufferOffset; - ULONG SenseInfoOffset; - UCHAR Cdb[16]; -} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH; - - -typedef struct { - USHORT Length; - UCHAR ScsiStatus; - UCHAR PathId; - UCHAR TargetId; - UCHAR Lun; - UCHAR CdbLength; - UCHAR SenseInfoLength; - UCHAR DataIn; - ULONG DataTransferLength; - ULONG TimeOutValue; - PVOID DataBuffer; - ULONG SenseInfoOffset; - UCHAR Cdb[16]; -} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT; - - -typedef struct { - SCSI_PASS_THROUGH spt; - ULONG Filler; - UCHAR ucSenseBuf[32]; - UCHAR ucDataBuf[512]; -} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS; - - -typedef struct { - SCSI_PASS_THROUGH_DIRECT spt; - ULONG Filler; - UCHAR ucSenseBuf[32]; -} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER; - - - -typedef struct { - UCHAR NumberOfLogicalUnits; - UCHAR InitiatorBusId; - ULONG InquiryDataOffset; -} SCSI_BUS_DATA, *PSCSI_BUS_DATA; - - -typedef struct { - UCHAR NumberOfBusses; - SCSI_BUS_DATA BusData[1]; -} SCSI_ADAPTER_BUS_INFO, *PSCSI_ADAPTER_BUS_INFO; - - -typedef struct { - UCHAR PathId; - UCHAR TargetId; - UCHAR Lun; - BOOLEAN DeviceClaimed; - ULONG InquiryDataLength; - ULONG NextInquiryDataOffset; - UCHAR InquiryData[1]; -} SCSI_INQUIRY_DATA, *PSCSI_INQUIRY_DATA; - - -typedef struct { - ULONG Length; - UCHAR PortNumber; - UCHAR PathId; - UCHAR TargetId; - UCHAR Lun; -} SCSI_ADDRESS, *PSCSI_ADDRESS; - - -/* - * method codes - */ -#define METHOD_BUFFERED 0 -#define METHOD_IN_DIRECT 1 -#define METHOD_OUT_DIRECT 2 -#define METHOD_NEITHER 3 - -/* - * file access values - */ -#define FILE_ANY_ACCESS 0 -#define FILE_READ_ACCESS (0x0001) -#define FILE_WRITE_ACCESS (0x0002) - - -#define IOCTL_SCSI_BASE 0x00000004 - -/* - * constants for DataIn member of SCSI_PASS_THROUGH* structures - */ -#define SCSI_IOCTL_DATA_OUT 0 -#define SCSI_IOCTL_DATA_IN 1 -#define SCSI_IOCTL_DATA_UNSPECIFIED 2 - -/* - * Standard IOCTL define - */ -#define CTL_CODE( DevType, Function, Method, Access ) ( \ - ((DevType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ -) - -#define IOCTL_SCSI_PASS_THROUGH CTL_CODE( IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS ) -#define IOCTL_SCSI_MINIPORT CTL_CODE( IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS ) -#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE( IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE( IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE( IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS ) -#define IOCTL_SCSI_GET_ADDRESS CTL_CODE( IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS ) - -#define FILE_DEVICE_MASS_STORAGE 0x0000002d -#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE - -#define IOCTL_STORAGE_CHECK_VERIFY CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_CHECK_VERIFY2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_MEDIA_REMOVAL CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_EJECT_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_LOAD_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_LOAD_MEDIA2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_RESERVE CTL_CODE(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_RELEASE CTL_CODE(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_FIND_NEW_DEVICES CTL_CODE(IOCTL_STORAGE_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define FILE_DEVICE_CD_ROM 0x00000002 -#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM -#define IOCTL_CDROM_RAW_READ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, METHOD_OUT_DIRECT, FILE_READ_ACCESS) -#define IOCTL_CDROM_READ_Q_CHANNEL CTL_CODE(IOCTL_CDROM_BASE, 0x000B, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_SEEK_AUDIO_MSF CTL_CODE(IOCTL_CDROM_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) - -typedef struct _CDROM_SEEK_AUDIO_MSF { - UCHAR M; - UCHAR S; - UCHAR F; -} CDROM_SEEK_AUDIO_MSF, *PCDROM_SEEK_AUDIO_MSF; - -// -// CD ROM Sub-Q Channel Data Format -// - -#define IOCTL_CDROM_SUB_Q_CHANNEL 0x00 -#define IOCTL_CDROM_CURRENT_POSITION 0x01 -#define IOCTL_CDROM_MEDIA_CATALOG 0x02 -#define IOCTL_CDROM_TRACK_ISRC 0x03 - -typedef struct _CDROM_SUB_Q_DATA_FORMAT { - UCHAR Format; - UCHAR Track; -} CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT; - -typedef struct _SUB_Q_HEADER { - UCHAR Reserved; - UCHAR AudioStatus; - UCHAR DataLength[2]; -} SUB_Q_HEADER, *PSUB_Q_HEADER; - -typedef struct _SUB_Q_CURRENT_POSITION { - SUB_Q_HEADER Header; - UCHAR FormatCode; - UCHAR Control : 4; - UCHAR ADR : 4; - UCHAR TrackNumber; - UCHAR IndexNumber; - UCHAR AbsoluteAddress[4]; - UCHAR TrackRelativeAddress[4]; -} SUB_Q_CURRENT_POSITION, *PSUB_Q_CURRENT_POSITION; - -typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER { - SUB_Q_HEADER Header; - UCHAR FormatCode; - UCHAR Reserved[3]; - UCHAR Reserved1 : 7; - UCHAR Mcval : 1; - UCHAR MediaCatalog[15]; -} SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER; - -typedef struct _SUB_Q_TRACK_ISRC { - SUB_Q_HEADER Header; - UCHAR FormatCode; - UCHAR Reserved0; - UCHAR Track; - UCHAR Reserved1; - UCHAR Reserved2 : 7; - UCHAR Tcval : 1; - UCHAR TrackIsrc[15]; -} SUB_Q_TRACK_ISRC, *PSUB_Q_TRACK_ISRC; - -typedef union _SUB_Q_CHANNEL_DATA { - SUB_Q_CURRENT_POSITION CurrentPosition; - SUB_Q_MEDIA_CATALOG_NUMBER MediaCatalog; - SUB_Q_TRACK_ISRC TrackIsrc; -} SUB_Q_CHANNEL_DATA, *PSUB_Q_CHANNEL_DATA; - - -// IOCTL_DISK_SET_CACHE allows the caller to get or set the state of the disk -// read/write caches. -// -// If the structure is provided as the input buffer for the ioctl the read & -// write caches will be enabled or disabled depending on the parameters -// provided. -// -// If the structure is provided as an output buffer for the ioctl the state -// of the read & write caches will be returned. If both input and outut buffers -// are provided the output buffer will contain the cache state BEFORE any -// changes are made - - -typedef enum { - EqualPriority, - KeepPrefetchedData, - KeepReadData -} DISK_CACHE_RETENTION_PRIORITY; - -#define FILE_DEVICE_DISK 0x00000007 -#define IOCTL_DISK_BASE FILE_DEVICE_DISK -#define IOCTL_DISK_GET_CACHE_INFORMATION CTL_CODE(IOCTL_DISK_BASE, 0x0035, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_SET_CACHE_INFORMATION CTL_CODE(IOCTL_DISK_BASE, 0x0036, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -typedef struct _DISK_CACHE_INFORMATION { - - // - // on return indicates that the device is capable of saving any parameters - // in non-volatile storage. On send indicates that the device should - // save the state in non-volatile storage. - // - - BOOLEAN ParametersSavable; - - // - // Indicates whether the write and read caches are enabled. - // - - BOOLEAN ReadCacheEnabled; - BOOLEAN WriteCacheEnabled; - - // - // Controls the likelyhood of data remaining in the cache depending on how - // it got there. Data cached from a READ or WRITE operation may be given - // higher, lower or equal priority to data entered into the cache for other - // means (like prefetch) - // - - DISK_CACHE_RETENTION_PRIORITY ReadRetentionPriority; - DISK_CACHE_RETENTION_PRIORITY WriteRetentionPriority; - - // - // Requests for a larger number of blocks than this may have prefetching - // disabled. If this value is set to 0 prefetch will be disabled. - // - - USHORT DisablePrefetchTransferLength; - - // - // If TRUE then ScalarPrefetch (below) will be valid. If FALSE then - // the minimum and maximum values should be treated as a block count - // (BlockPrefetch) - // - - BOOLEAN PrefetchScalar; - - // - // Contains the minimum and maximum amount of data which will be - // will be prefetched into the cache on a disk operation. This value - // may either be a scalar multiplier of the transfer length of the request, - // or an abolute number of disk blocks. PrefetchScalar (above) indicates - // which interpretation is used. - // - - union { - struct { - USHORT Minimum; - USHORT Maximum; - - // - // The maximum number of blocks which will be prefetched - useful - // with the scalar limits to set definite upper limits. - // - - USHORT MaximumBlocks; - } ScalarPrefetch; - - struct { - USHORT Minimum; - USHORT Maximum; - } BlockPrefetch; - }; - -} DISK_CACHE_INFORMATION, *PDISK_CACHE_INFORMATION; - +//*************************************************************************** +// +// Name: SCSIDEFS.H +// +// Description: SCSI definitions ('C' Language) +// +//*************************************************************************** + +//*************************************************************************** +// %%% TARGET STATUS VALUES %%% +//*************************************************************************** +#define STATUS_GOOD 0x00 // Status Good +#define STATUS_CHKCOND 0x02 // Check Condition +#define STATUS_CONDMET 0x04 // Condition Met +#define STATUS_BUSY 0x08 // Busy +#define STATUS_INTERM 0x10 // Intermediate +#define STATUS_INTCDMET 0x14 // Intermediate-condition met +#define STATUS_RESCONF 0x18 // Reservation conflict +#define STATUS_COMTERM 0x22 // Command Terminated +#define STATUS_QFULL 0x28 // Queue full + +//*************************************************************************** +// %%% SCSI MISCELLANEOUS EQUATES %%% +//*************************************************************************** +#define MAXLUN 7 // Maximum Logical Unit Id +#define MAXTARG 7 // Maximum Target Id +#define MAX_SCSI_LUNS 64 // Maximum Number of SCSI LUNs +#define MAX_NUM_HA 8 // Maximum Number of SCSI HA's + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +// +// %%% SCSI COMMAND OPCODES %%% +// +///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + +//*************************************************************************** +// %%% Commands for all Device Types %%% +//*************************************************************************** +#define SCSI_CHANGE_DEF 0x40 // Change Definition (Optional) +#define SCSI_COMPARE 0x39 // Compare (O) +#define SCSI_COPY 0x18 // Copy (O) +#define SCSI_COP_VERIFY 0x3A // Copy and Verify (O) +#define SCSI_INQUIRY 0x12 // Inquiry (MANDATORY) +#define SCSI_LOG_SELECT 0x4C // Log Select (O) +#define SCSI_LOG_SENSE 0x4D // Log Sense (O) +#define SCSI_MODE_SEL6 0x15 // Mode Select 6-byte (Device Specific) +#define SCSI_MODE_SEL10 0x55 // Mode Select 10-byte (Device Specific) +#define SCSI_MODE_SEN6 0x1A // Mode Sense 6-byte (Device Specific) +#define SCSI_MODE_SEN10 0x5A // Mode Sense 10-byte (Device Specific) +#define SCSI_READ_BUFF 0x3C // Read Buffer (O) +#define SCSI_REQ_SENSE 0x03 // Request Sense (MANDATORY) +#define SCSI_SEND_DIAG 0x1D // Send Diagnostic (O) +#define SCSI_TST_U_RDY 0x00 // Test Unit Ready (MANDATORY) +#define SCSI_WRITE_BUFF 0x3B // Write Buffer (O) + +//*************************************************************************** +// %%% Commands Unique to Direct Access Devices %%% +//*************************************************************************** +#define SCSI_COMPARE 0x39 // Compare (O) +#define SCSI_FORMAT 0x04 // Format Unit (MANDATORY) +#define SCSI_LCK_UN_CAC 0x36 // Lock Unlock Cache (O) +#define SCSI_PREFETCH 0x34 // Prefetch (O) +#define SCSI_MED_REMOVL 0x1E // Prevent/Allow medium Removal (O) +#define SCSI_READ6 0x08 // Read 6-byte (MANDATORY) +#define SCSI_READ10 0x28 // Read 10-byte (MANDATORY) +#define SCSI_RD_CAPAC 0x25 // Read Capacity (MANDATORY) +#define SCSI_RD_DEFECT 0x37 // Read Defect Data (O) +#define SCSI_READ_LONG 0x3E // Read Long (O) +#define SCSI_REASS_BLK 0x07 // Reassign Blocks (O) +#define SCSI_RCV_DIAG 0x1C // Receive Diagnostic Results (O) +#define SCSI_RELEASE 0x17 // Release Unit (MANDATORY) +#define SCSI_REZERO 0x01 // Rezero Unit (O) +#define SCSI_SRCH_DAT_E 0x31 // Search Data Equal (O) +#define SCSI_SRCH_DAT_H 0x30 // Search Data High (O) +#define SCSI_SRCH_DAT_L 0x32 // Search Data Low (O) +#define SCSI_SEEK6 0x0B // Seek 6-Byte (O) +#define SCSI_SEEK10 0x2B // Seek 10-Byte (O) +#define SCSI_SEND_DIAG 0x1D // Send Diagnostics (MANDATORY) +#define SCSI_SET_LIMIT 0x33 // Set Limits (O) +#define SCSI_START_STP 0x1B // Start/Stop Unit (O) +#define SCSI_SYNC_CACHE 0x35 // Synchronize Cache (O) +#define SCSI_VERIFY 0x2F // Verify (O) +#define SCSI_WRITE6 0x0A // Write 6-Byte (MANDATORY) +#define SCSI_WRITE10 0x2A // Write 10-Byte (MANDATORY) +#define SCSI_WRT_VERIFY 0x2E // Write and Verify (O) +#define SCSI_WRITE_LONG 0x3F // Write Long (O) +#define SCSI_WRITE_SAME 0x41 // Write Same (O) + +//*************************************************************************** +// %%% Commands Unique to Sequential Access Devices %%% +//*************************************************************************** +#define SCSI_ERASE 0x19 // Erase (MANDATORY) +#define SCSI_LOAD_UN 0x1B // Load/Unload (O) +#define SCSI_LOCATE 0x2B // Locate (O) +#define SCSI_RD_BLK_LIM 0x05 // Read Block Limits (MANDATORY) +#define SCSI_READ_POS 0x34 // Read Position (O) +#define SCSI_READ_REV 0x0F // Read Reverse (O) +#define SCSI_REC_BF_DAT 0x14 // Recover Buffer Data (O) +#define SCSI_RESERVE 0x16 // Reserve Unit (MANDATORY) +#define SCSI_REWIND 0x01 // Rewind (MANDATORY) +#define SCSI_SPACE 0x11 // Space (MANDATORY) +#define SCSI_VERIFY_T 0x13 // Verify (Tape) (O) +#define SCSI_WRT_FILE 0x10 // Write Filemarks (MANDATORY) + +//*************************************************************************** +// %%% Commands Unique to Printer Devices %%% +//*************************************************************************** +#define SCSI_PRINT 0x0A // Print (MANDATORY) +#define SCSI_SLEW_PNT 0x0B // Slew and Print (O) +#define SCSI_STOP_PNT 0x1B // Stop Print (O) +#define SCSI_SYNC_BUFF 0x10 // Synchronize Buffer (O) + +//*************************************************************************** +// %%% Commands Unique to Processor Devices %%% +//*************************************************************************** +#define SCSI_RECEIVE 0x08 // Receive (O) +#define SCSI_SEND 0x0A // Send (O) + +//*************************************************************************** +// %%% Commands Unique to Write-Once Devices %%% +//*************************************************************************** +#define SCSI_MEDIUM_SCN 0x38 // Medium Scan (O) +#define SCSI_SRCHDATE10 0x31 // Search Data Equal 10-Byte (O) +#define SCSI_SRCHDATE12 0xB1 // Search Data Equal 12-Byte (O) +#define SCSI_SRCHDATH10 0x30 // Search Data High 10-Byte (O) +#define SCSI_SRCHDATH12 0xB0 // Search Data High 12-Byte (O) +#define SCSI_SRCHDATL10 0x32 // Search Data Low 10-Byte (O) +#define SCSI_SRCHDATL12 0xB2 // Search Data Low 12-Byte (O) +#define SCSI_SET_LIM_10 0x33 // Set Limits 10-Byte (O) +#define SCSI_SET_LIM_12 0xB3 // Set Limits 10-Byte (O) +#define SCSI_VERIFY10 0x2F // Verify 10-Byte (O) +#define SCSI_VERIFY12 0xAF // Verify 12-Byte (O) +#define SCSI_WRITE12 0xAA // Write 12-Byte (O) +#define SCSI_WRT_VER10 0x2E // Write and Verify 10-Byte (O) +#define SCSI_WRT_VER12 0xAE // Write and Verify 12-Byte (O) + +//*************************************************************************** +// %%% Commands Unique to CD-ROM Devices %%% +//*************************************************************************** +#define SCSI_PLAYAUD_10 0x45 // Play Audio 10-Byte (O) +#define SCSI_PLAYAUD_12 0xA5 // Play Audio 12-Byte 12-Byte (O) +#define SCSI_PLAYAUDMSF 0x47 // Play Audio MSF (O) +#define SCSI_PLAYA_TKIN 0x48 // Play Audio Track/Index (O) +#define SCSI_PLYTKREL10 0x49 // Play Track Relative 10-Byte (O) +#define SCSI_PLYTKREL12 0xA9 // Play Track Relative 12-Byte (O) +#define SCSI_READCDCAP 0x25 // Read CD-ROM Capacity (MANDATORY) +#define SCSI_READHEADER 0x44 // Read Header (O) +#define SCSI_SUBCHANNEL 0x42 // Read Subchannel (O) +#define SCSI_READ_TOC 0x43 // Read TOC (O) + +//*************************************************************************** +// %%% Commands Unique to Scanner Devices %%% +//*************************************************************************** +#define SCSI_GETDBSTAT 0x34 // Get Data Buffer Status (O) +#define SCSI_GETWINDOW 0x25 // Get Window (O) +#define SCSI_OBJECTPOS 0x31 // Object Postion (O) +#define SCSI_SCAN 0x1B // Scan (O) +#define SCSI_SETWINDOW 0x24 // Set Window (MANDATORY) + +//*************************************************************************** +// %%% Commands Unique to Optical Memory Devices %%% +//*************************************************************************** +#define SCSI_UpdateBlk 0x3D // Update Block (O) + +//*************************************************************************** +// %%% Commands Unique to Medium Changer Devices %%% +//*************************************************************************** +#define SCSI_EXCHMEDIUM 0xA6 // Exchange Medium (O) +#define SCSI_INITELSTAT 0x07 // Initialize Element Status (O) +#define SCSI_POSTOELEM 0x2B // Position to Element (O) +#define SCSI_REQ_VE_ADD 0xB5 // Request Volume Element Address (O) +#define SCSI_SENDVOLTAG 0xB6 // Send Volume Tag (O) + +//*************************************************************************** +// %%% Commands Unique to Communication Devices %%% +//*************************************************************************** +#define SCSI_GET_MSG_6 0x08 // Get Message 6-Byte (MANDATORY) +#define SCSI_GET_MSG_10 0x28 // Get Message 10-Byte (O) +#define SCSI_GET_MSG_12 0xA8 // Get Message 12-Byte (O) +#define SCSI_SND_MSG_6 0x0A // Send Message 6-Byte (MANDATORY) +#define SCSI_SND_MSG_10 0x2A // Send Message 10-Byte (O) +#define SCSI_SND_MSG_12 0xAA // Send Message 12-Byte (O) + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +// +// %%% END OF SCSI COMMAND OPCODES %%% +// +///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + +//*************************************************************************** +// %%% Request Sense Data Format %%% +//*************************************************************************** +typedef struct { + + BYTE ErrorCode; // Error Code (70H or 71H) + BYTE SegmentNum; // Number of current segment descriptor + BYTE SenseKey; // Sense Key(See bit definitions too) + BYTE InfoByte0; // Information MSB + BYTE InfoByte1; // Information MID + BYTE InfoByte2; // Information MID + BYTE InfoByte3; // Information LSB + BYTE AddSenLen; // Additional Sense Length + BYTE ComSpecInf0; // Command Specific Information MSB + BYTE ComSpecInf1; // Command Specific Information MID + BYTE ComSpecInf2; // Command Specific Information MID + BYTE ComSpecInf3; // Command Specific Information LSB + BYTE AddSenseCode; // Additional Sense Code + BYTE AddSenQual; // Additional Sense Code Qualifier + BYTE FieldRepUCode; // Field Replaceable Unit Code + BYTE SenKeySpec15; // Sense Key Specific 15th byte + BYTE SenKeySpec16; // Sense Key Specific 16th byte + BYTE SenKeySpec17; // Sense Key Specific 17th byte + BYTE AddSenseBytes; // Additional Sense Bytes + +} SENSE_DATA_FMT; + +//*************************************************************************** +// %%% REQUEST SENSE ERROR CODE %%% +//*************************************************************************** +#define SERROR_CURRENT 0x70 // Current Errors +#define SERROR_DEFERED 0x71 // Deferred Errors + +//*************************************************************************** +// %%% REQUEST SENSE BIT DEFINITIONS %%% +//*************************************************************************** +#define SENSE_VALID 0x80 // Byte 0 Bit 7 +#define SENSE_FILEMRK 0x80 // Byte 2 Bit 7 +#define SENSE_EOM 0x40 // Byte 2 Bit 6 +#define SENSE_ILI 0x20 // Byte 2 Bit 5 + +//*************************************************************************** +// %%% REQUEST SENSE SENSE KEY DEFINITIONS %%% +//*************************************************************************** +#define KEY_NOSENSE 0x00 // No Sense +#define KEY_RECERROR 0x01 // Recovered Error +#define KEY_NOTREADY 0x02 // Not Ready +#define KEY_MEDIUMERR 0x03 // Medium Error +#define KEY_HARDERROR 0x04 // Hardware Error +#define KEY_ILLGLREQ 0x05 // Illegal Request +#define KEY_UNITATT 0x06 // Unit Attention +#define KEY_DATAPROT 0x07 // Data Protect +#define KEY_BLANKCHK 0x08 // Blank Check +#define KEY_VENDSPEC 0x09 // Vendor Specific +#define KEY_COPYABORT 0x0A // Copy Abort +#define KEY_EQUAL 0x0C // Equal (Search) +#define KEY_VOLOVRFLW 0x0D // Volume Overflow +#define KEY_MISCOMP 0x0E // Miscompare (Search) +#define KEY_RESERVED 0x0F // Reserved + +//*************************************************************************** +// %%% PERIPHERAL DEVICE TYPE DEFINITIONS %%% +//*************************************************************************** +#define DTYPE_DASD 0x00 // Disk Device +#define DTYPE_SEQD 0x01 // Tape Device +#define DTYPE_PRNT 0x02 // Printer +#define DTYPE_PROC 0x03 // Processor +#define DTYPE_WORM 0x04 // Write-once read-multiple +#define DTYPE_CROM 0x05 // CD-ROM device +#define DTYPE_CDROM 0x05 // CD-ROM device +#define DTYPE_SCAN 0x06 // Scanner device +#define DTYPE_OPTI 0x07 // Optical memory device +#define DTYPE_JUKE 0x08 // Medium Changer device +#define DTYPE_COMM 0x09 // Communications device +#define DTYPE_RESL 0x0A // Reserved (low) +#define DTYPE_RESH 0x1E // Reserved (high) +#define DTYPE_UNKNOWN 0x1F // Unknown or no device type + +//*************************************************************************** +// %%% ANSI APPROVED VERSION DEFINITIONS %%% +//*************************************************************************** +#define ANSI_MAYBE 0x0 // Device may or may not be ANSI approved stand +#define ANSI_SCSI1 0x1 // Device complies to ANSI X3.131-1986 (SCSI-1) +#define ANSI_SCSI2 0x2 // Device complies to SCSI-2 +#define ANSI_RESLO 0x3 // Reserved (low) +#define ANSI_RESHI 0x7 // Reserved (high) + + +//////////////////////////////////////////////////////////////// + +typedef struct { + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + ULONG DataBufferOffset; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH; + + +typedef struct { + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + PVOID DataBuffer; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT; + + +typedef struct { + SCSI_PASS_THROUGH spt; + ULONG Filler; + UCHAR ucSenseBuf[32]; + UCHAR ucDataBuf[512]; +} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS; + + +typedef struct { + SCSI_PASS_THROUGH_DIRECT spt; + ULONG Filler; + UCHAR ucSenseBuf[32]; +} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER; + + + +typedef struct { + UCHAR NumberOfLogicalUnits; + UCHAR InitiatorBusId; + ULONG InquiryDataOffset; +} SCSI_BUS_DATA, *PSCSI_BUS_DATA; + + +typedef struct { + UCHAR NumberOfBusses; + SCSI_BUS_DATA BusData[1]; +} SCSI_ADAPTER_BUS_INFO, *PSCSI_ADAPTER_BUS_INFO; + + +typedef struct { + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + BOOLEAN DeviceClaimed; + ULONG InquiryDataLength; + ULONG NextInquiryDataOffset; + UCHAR InquiryData[1]; +} SCSI_INQUIRY_DATA, *PSCSI_INQUIRY_DATA; + + +typedef struct { + ULONG Length; + UCHAR PortNumber; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; +} SCSI_ADDRESS, *PSCSI_ADDRESS; + + +/* + * method codes + */ +#define METHOD_BUFFERED 0 +#define METHOD_IN_DIRECT 1 +#define METHOD_OUT_DIRECT 2 +#define METHOD_NEITHER 3 + +/* + * file access values + */ +#define FILE_ANY_ACCESS 0 +#define FILE_READ_ACCESS (0x0001) +#define FILE_WRITE_ACCESS (0x0002) + + +#define IOCTL_SCSI_BASE 0x00000004 + +/* + * constants for DataIn member of SCSI_PASS_THROUGH* structures + */ +#define SCSI_IOCTL_DATA_OUT 0 +#define SCSI_IOCTL_DATA_IN 1 +#define SCSI_IOCTL_DATA_UNSPECIFIED 2 + +/* + * Standard IOCTL define + */ +#define CTL_CODE( DevType, Function, Method, Access ) ( \ + ((DevType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ +) + +#define IOCTL_SCSI_PASS_THROUGH CTL_CODE( IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS ) +#define IOCTL_SCSI_MINIPORT CTL_CODE( IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS ) +#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE( IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE( IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE( IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS ) +#define IOCTL_SCSI_GET_ADDRESS CTL_CODE( IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS ) + +#define FILE_DEVICE_MASS_STORAGE 0x0000002d +#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE + +#define IOCTL_STORAGE_CHECK_VERIFY CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_CHECK_VERIFY2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_MEDIA_REMOVAL CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_EJECT_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_LOAD_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_LOAD_MEDIA2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_RESERVE CTL_CODE(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_RELEASE CTL_CODE(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_FIND_NEW_DEVICES CTL_CODE(IOCTL_STORAGE_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define FILE_DEVICE_CD_ROM 0x00000002 +#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM +#define IOCTL_CDROM_RAW_READ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, METHOD_OUT_DIRECT, FILE_READ_ACCESS) +#define IOCTL_CDROM_READ_Q_CHANNEL CTL_CODE(IOCTL_CDROM_BASE, 0x000B, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_SEEK_AUDIO_MSF CTL_CODE(IOCTL_CDROM_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) + +typedef struct _CDROM_SEEK_AUDIO_MSF { + UCHAR M; + UCHAR S; + UCHAR F; +} CDROM_SEEK_AUDIO_MSF, *PCDROM_SEEK_AUDIO_MSF; + +// +// CD ROM Sub-Q Channel Data Format +// + +#define IOCTL_CDROM_SUB_Q_CHANNEL 0x00 +#define IOCTL_CDROM_CURRENT_POSITION 0x01 +#define IOCTL_CDROM_MEDIA_CATALOG 0x02 +#define IOCTL_CDROM_TRACK_ISRC 0x03 + +typedef struct _CDROM_SUB_Q_DATA_FORMAT { + UCHAR Format; + UCHAR Track; +} CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT; + +typedef struct _SUB_Q_HEADER { + UCHAR Reserved; + UCHAR AudioStatus; + UCHAR DataLength[2]; +} SUB_Q_HEADER, *PSUB_Q_HEADER; + +typedef struct _SUB_Q_CURRENT_POSITION { + SUB_Q_HEADER Header; + UCHAR FormatCode; + UCHAR Control : 4; + UCHAR ADR : 4; + UCHAR TrackNumber; + UCHAR IndexNumber; + UCHAR AbsoluteAddress[4]; + UCHAR TrackRelativeAddress[4]; +} SUB_Q_CURRENT_POSITION, *PSUB_Q_CURRENT_POSITION; + +typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER { + SUB_Q_HEADER Header; + UCHAR FormatCode; + UCHAR Reserved[3]; + UCHAR Reserved1 : 7; + UCHAR Mcval : 1; + UCHAR MediaCatalog[15]; +} SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER; + +typedef struct _SUB_Q_TRACK_ISRC { + SUB_Q_HEADER Header; + UCHAR FormatCode; + UCHAR Reserved0; + UCHAR Track; + UCHAR Reserved1; + UCHAR Reserved2 : 7; + UCHAR Tcval : 1; + UCHAR TrackIsrc[15]; +} SUB_Q_TRACK_ISRC, *PSUB_Q_TRACK_ISRC; + +typedef union _SUB_Q_CHANNEL_DATA { + SUB_Q_CURRENT_POSITION CurrentPosition; + SUB_Q_MEDIA_CATALOG_NUMBER MediaCatalog; + SUB_Q_TRACK_ISRC TrackIsrc; +} SUB_Q_CHANNEL_DATA, *PSUB_Q_CHANNEL_DATA; + + +// IOCTL_DISK_SET_CACHE allows the caller to get or set the state of the disk +// read/write caches. +// +// If the structure is provided as the input buffer for the ioctl the read & +// write caches will be enabled or disabled depending on the parameters +// provided. +// +// If the structure is provided as an output buffer for the ioctl the state +// of the read & write caches will be returned. If both input and outut buffers +// are provided the output buffer will contain the cache state BEFORE any +// changes are made + + +typedef enum { + EqualPriority, + KeepPrefetchedData, + KeepReadData +} DISK_CACHE_RETENTION_PRIORITY; + +#define FILE_DEVICE_DISK 0x00000007 +#define IOCTL_DISK_BASE FILE_DEVICE_DISK +#define IOCTL_DISK_GET_CACHE_INFORMATION CTL_CODE(IOCTL_DISK_BASE, 0x0035, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_SET_CACHE_INFORMATION CTL_CODE(IOCTL_DISK_BASE, 0x0036, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +typedef struct _DISK_CACHE_INFORMATION { + + // + // on return indicates that the device is capable of saving any parameters + // in non-volatile storage. On send indicates that the device should + // save the state in non-volatile storage. + // + + BOOLEAN ParametersSavable; + + // + // Indicates whether the write and read caches are enabled. + // + + BOOLEAN ReadCacheEnabled; + BOOLEAN WriteCacheEnabled; + + // + // Controls the likelyhood of data remaining in the cache depending on how + // it got there. Data cached from a READ or WRITE operation may be given + // higher, lower or equal priority to data entered into the cache for other + // means (like prefetch) + // + + DISK_CACHE_RETENTION_PRIORITY ReadRetentionPriority; + DISK_CACHE_RETENTION_PRIORITY WriteRetentionPriority; + + // + // Requests for a larger number of blocks than this may have prefetching + // disabled. If this value is set to 0 prefetch will be disabled. + // + + USHORT DisablePrefetchTransferLength; + + // + // If TRUE then ScalarPrefetch (below) will be valid. If FALSE then + // the minimum and maximum values should be treated as a block count + // (BlockPrefetch) + // + + BOOLEAN PrefetchScalar; + + // + // Contains the minimum and maximum amount of data which will be + // will be prefetched into the cache on a disk operation. This value + // may either be a scalar multiplier of the transfer length of the request, + // or an abolute number of disk blocks. PrefetchScalar (above) indicates + // which interpretation is used. + // + + union { + struct { + USHORT Minimum; + USHORT Maximum; + + // + // The maximum number of blocks which will be prefetched - useful + // with the scalar limits to set definite upper limits. + // + + USHORT MaximumBlocks; + } ScalarPrefetch; + + struct { + USHORT Minimum; + USHORT Maximum; + } BlockPrefetch; + }; + +} DISK_CACHE_INFORMATION, *PDISK_CACHE_INFORMATION; + diff --git a/plugins/CDVDpeops/sub.c b/plugins/CDVDpeops/sub.c index 073ecf7d8c..e7a7b7b444 100644 --- a/plugins/CDVDpeops/sub.c +++ b/plugins/CDVDpeops/sub.c @@ -1,321 +1,321 @@ -/*************************************************************************** - sub.c - description - ------------------- - begin : Sun Nov 16 2003 - copyright : (C) 2003 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2003/11/16 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -///////////////////////////////////////////////////////// - -#include "stdafx.h" -#define _IN_SUB -#include "externals.h" - -/* TODO (#1#): SUB CHANNEL STUFF */ - -///////////////////////////////////////////////////////// - -unsigned char * pCurrSubBuf=NULL; // ptr to emu sub data (or NULL) -int iUseSubReading=0; // subdata support (by file or directly) -char szSUBF[260]; // sub file name -SUB_CACHE * subCache=NULL; // cache memory -SUB_DATA * subHead=NULL; -int iSUBNum=0; // number of subdata cached -unsigned char SubCData[96]; // global data subc buffer -unsigned char SubAData[96]; // global audio subc buffer - -///////////////////////////////////////////////////////// - -void BuildSUBCache(void) -{ - FILE * subfile; - unsigned char buffer[16], * p; - SUB_DATA * plast=NULL,* px; - - if(iUseSubReading) // some subreading wanted? - { - if(iUseSubReading==1) iUseCaching=0; // -> direct read? no caching done, only 1 sector reads - memset(SubCData,0,96); // -> init subc - pCurrSubBuf=SubCData; // -> set global ptr - } - else // no plugin subreading? - { - pCurrSubBuf=NULL; // -> return NULL as subc buffer to emu - } - - memset(SubAData,0,96); // init audio subc buffer - - if(iUseSubReading!=2) return; // no subfile wanted? - if(szSUBF[0]==0) return; // no filename given? - - subfile=fopen(szSUBF, "rb"); // open subfile - if(subfile==0) - { - MessageBox(NULL,"No SBI/M3S file found!",libraryName,MB_OK); - return; - } - - memset(buffer,0,5); // read header - fread(buffer, 4, 1, subfile); - - iSUBNum=0;subHead=NULL; - - if(strcmp((char *)buffer,"SBI")==0) // ah, SBI file - { - while(fread(buffer, 4, 1, subfile)==1) // -> read record header - { - iSUBNum++; // -> one more sub cache block - px=(SUB_DATA *)malloc(sizeof(SUB_DATA)); // -> get cache buff -//!!!!!!!!!!!!!!!!!!!!!!!!!!!! // -> and fill it... - -/* TODO (#1#): addr2time subchannel */ - - - px->addr=time2addrB(buffer); - - px->pNext=NULL; - - px->subq[0]=0x41; - px->subq[1]=0x01; - px->subq[2]=0x01; - p=&px->subq[3]; - addr2timeB(px->addr,p); - px->subq[6]=0x00; - p=&px->subq[7]; - addr2timeB(px->addr+150,p); - - if(buffer[3]==1) - { - fread(px->subq,10, 1, subfile); - } - else if(buffer[3]==2) - { - fread(&px->subq[3],3, 1, subfile); - } - else if(buffer[3]==3) - { - fread(&px->subq[7],3, 1, subfile); - } - - if(plast==NULL) // add new cache block to linked list - { - plast=subHead=px; - } - else - { - plast->pNext=px;plast=px; - } - } - } - else // M3S file? - { // -> read data, and store all - unsigned char min,sec,frame,xmin,xsec,xframe; // -> subs which are different from - BOOL b1,b2,goon=TRUE;int iNum=0; // -> the expected calculated values - - xmin=2; - xsec=58; - xframe=0; - min=3; - sec=0; - frame=0; - - fread(buffer+4, 12, 1, subfile); - do - { - if(itod(min) != buffer[7]|| - itod(sec) != buffer[8]|| - itod(frame) != buffer[9]) - b1=TRUE; else b1=FALSE; - - if(itod(xmin) != buffer[3]|| - itod(xsec) != buffer[4]|| - itod(xframe) != buffer[5]) - b2=TRUE; else b2=FALSE; - - if(buffer[1]!=1) b1=b2=TRUE; - if(buffer[2]!=1) b1=b2=TRUE; - - if(b1 || b2) - { - iSUBNum++; - px=(SUB_DATA *)malloc(sizeof(SUB_DATA)); - px->pNext=NULL; - memcpy(px->subq,buffer,10); - buffer[7]=itod(min); - buffer[8]=itod(sec); - buffer[9]=itod(frame); -//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - px->addr=time2addrB(&buffer[7]); - - if(plast==NULL) - {plast=subHead=px;} - else {plast->pNext=px;plast=px;} - } - - xframe=xframe+1; - if(xframe>74) - { - xsec+=1; - xframe-=75; - if(xsec>59) - { - xmin+=1; - xsec-=60; - if(xmin>99) - { - goon=FALSE; - } - } - } - - frame=frame+1; - if(frame>74) - { - sec+=1; - frame-=75; - if(sec>59) - { - min+=1; - sec-=60; - if(min>99) - { - goon=FALSE; - } - } - } - iNum++; - if(iNum>(60*75)) goon=FALSE; - } - while(goon && (fread(buffer, 16, 1, subfile)==1)); - - if(iNum!=(60*75)) goon=FALSE; - else - if(iSUBNum==(60*75)) goon=FALSE; - - if(!goon) - { - MessageBox(NULL,"Bad SBI/M3S file!",libraryName,MB_OK); - fclose(subfile); - FreeSUBCache(); - return; - } - } - - subCache=NULL; - if(iSUBNum) // something in cache? - { // -> create an array with the used addresses, for fast searching access - SUB_CACHE * psc;int i; - subCache=(SUB_CACHE *)malloc(iSUBNum*sizeof(SUB_CACHE)); - psc=subCache;px=subHead; - for(i=0;ipNext) - { - psc->addr = px->addr; - psc->pNext = (void *)px; - } - iSUBNum--; - } - - fclose(subfile); -} - -///////////////////////////////////////////////////////// -// func for calculating 'right' subdata - -void FakeSubData(unsigned long adr) -{ - SubCData[12]=0x41; - SubCData[13]=0x01; - SubCData[14]=0x01; - - /* TODO (#1#): addr2time fake sub data - */ - - -//!!!!!!!!!!!!!!!!!!!!!!!???? - addr2timeB(adr, &SubCData[15]); -// SubCData[18]=0x00; - addr2timeB(adr+150,&SubCData[19]); -} - -///////////////////////////////////////////////////////// -// check, if for a given addr we have special subdata in cache - -void CheckSUBCache(long addr) -{ - SUB_CACHE * pcstart, * pcend, * pcpos; - - pcstart=subCache; // ptrs to address arrays (start/end) - pcend =subCache+iSUBNum; - - if(addr>=pcstart->addr && // easy check, if given addr is between start/end - addr<=pcend->addr) - { - while(1) // now search for sub - { - if(addr==pcend->addr) {pcpos=pcend;break;} // got it! break - - pcpos=pcstart+(pcend-pcstart)/2; // get the 'middle' address - if(pcpos==pcstart) break; // no more checks can be done - if(addraddr) // look further... - { - pcend=pcpos; - continue; - } - if(addr>pcpos->addr) - { - pcstart=pcpos; - continue; - } - break; - } - - if(addr==pcpos->addr) // found some cached data? - { - SUB_DATA * p=(SUB_DATA *)pcpos->pNext; // -> ptr to data - memcpy(&SubCData[12],p->subq,10); // -> get the data - return; // -> done - } - } - - FakeSubData(addr); // no subcdata avail, so fake right one -} - -///////////////////////////////////////////////////////// -// free all sub cache bufs - -void FreeSUBCache(void) -{ - SUB_DATA * p=subHead; - void * pn; - while(p) - { - pn=p->pNext; - free(p); - p=(SUB_DATA *)pn; - } - subHead=NULL; - - if(subCache) free(subCache); - subCache=NULL; -} - -///////////////////////////////////////////////////////// +/*************************************************************************** + sub.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#define _IN_SUB +#include "externals.h" + +/* TODO (#1#): SUB CHANNEL STUFF */ + +///////////////////////////////////////////////////////// + +unsigned char * pCurrSubBuf=NULL; // ptr to emu sub data (or NULL) +int iUseSubReading=0; // subdata support (by file or directly) +char szSUBF[260]; // sub file name +SUB_CACHE * subCache=NULL; // cache memory +SUB_DATA * subHead=NULL; +int iSUBNum=0; // number of subdata cached +unsigned char SubCData[96]; // global data subc buffer +unsigned char SubAData[96]; // global audio subc buffer + +///////////////////////////////////////////////////////// + +void BuildSUBCache(void) +{ + FILE * subfile; + unsigned char buffer[16], * p; + SUB_DATA * plast=NULL,* px; + + if(iUseSubReading) // some subreading wanted? + { + if(iUseSubReading==1) iUseCaching=0; // -> direct read? no caching done, only 1 sector reads + memset(SubCData,0,96); // -> init subc + pCurrSubBuf=SubCData; // -> set global ptr + } + else // no plugin subreading? + { + pCurrSubBuf=NULL; // -> return NULL as subc buffer to emu + } + + memset(SubAData,0,96); // init audio subc buffer + + if(iUseSubReading!=2) return; // no subfile wanted? + if(szSUBF[0]==0) return; // no filename given? + + subfile=fopen(szSUBF, "rb"); // open subfile + if(subfile==0) + { + MessageBox(NULL,"No SBI/M3S file found!",libraryName,MB_OK); + return; + } + + memset(buffer,0,5); // read header + fread(buffer, 4, 1, subfile); + + iSUBNum=0;subHead=NULL; + + if(strcmp((char *)buffer,"SBI")==0) // ah, SBI file + { + while(fread(buffer, 4, 1, subfile)==1) // -> read record header + { + iSUBNum++; // -> one more sub cache block + px=(SUB_DATA *)malloc(sizeof(SUB_DATA)); // -> get cache buff +//!!!!!!!!!!!!!!!!!!!!!!!!!!!! // -> and fill it... + +/* TODO (#1#): addr2time subchannel */ + + + px->addr=time2addrB(buffer); + + px->pNext=NULL; + + px->subq[0]=0x41; + px->subq[1]=0x01; + px->subq[2]=0x01; + p=&px->subq[3]; + addr2timeB(px->addr,p); + px->subq[6]=0x00; + p=&px->subq[7]; + addr2timeB(px->addr+150,p); + + if(buffer[3]==1) + { + fread(px->subq,10, 1, subfile); + } + else if(buffer[3]==2) + { + fread(&px->subq[3],3, 1, subfile); + } + else if(buffer[3]==3) + { + fread(&px->subq[7],3, 1, subfile); + } + + if(plast==NULL) // add new cache block to linked list + { + plast=subHead=px; + } + else + { + plast->pNext=px;plast=px; + } + } + } + else // M3S file? + { // -> read data, and store all + unsigned char min,sec,frame,xmin,xsec,xframe; // -> subs which are different from + BOOL b1,b2,goon=TRUE;int iNum=0; // -> the expected calculated values + + xmin=2; + xsec=58; + xframe=0; + min=3; + sec=0; + frame=0; + + fread(buffer+4, 12, 1, subfile); + do + { + if(itod(min) != buffer[7]|| + itod(sec) != buffer[8]|| + itod(frame) != buffer[9]) + b1=TRUE; else b1=FALSE; + + if(itod(xmin) != buffer[3]|| + itod(xsec) != buffer[4]|| + itod(xframe) != buffer[5]) + b2=TRUE; else b2=FALSE; + + if(buffer[1]!=1) b1=b2=TRUE; + if(buffer[2]!=1) b1=b2=TRUE; + + if(b1 || b2) + { + iSUBNum++; + px=(SUB_DATA *)malloc(sizeof(SUB_DATA)); + px->pNext=NULL; + memcpy(px->subq,buffer,10); + buffer[7]=itod(min); + buffer[8]=itod(sec); + buffer[9]=itod(frame); +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + px->addr=time2addrB(&buffer[7]); + + if(plast==NULL) + {plast=subHead=px;} + else {plast->pNext=px;plast=px;} + } + + xframe=xframe+1; + if(xframe>74) + { + xsec+=1; + xframe-=75; + if(xsec>59) + { + xmin+=1; + xsec-=60; + if(xmin>99) + { + goon=FALSE; + } + } + } + + frame=frame+1; + if(frame>74) + { + sec+=1; + frame-=75; + if(sec>59) + { + min+=1; + sec-=60; + if(min>99) + { + goon=FALSE; + } + } + } + iNum++; + if(iNum>(60*75)) goon=FALSE; + } + while(goon && (fread(buffer, 16, 1, subfile)==1)); + + if(iNum!=(60*75)) goon=FALSE; + else + if(iSUBNum==(60*75)) goon=FALSE; + + if(!goon) + { + MessageBox(NULL,"Bad SBI/M3S file!",libraryName,MB_OK); + fclose(subfile); + FreeSUBCache(); + return; + } + } + + subCache=NULL; + if(iSUBNum) // something in cache? + { // -> create an array with the used addresses, for fast searching access + SUB_CACHE * psc;int i; + subCache=(SUB_CACHE *)malloc(iSUBNum*sizeof(SUB_CACHE)); + psc=subCache;px=subHead; + for(i=0;ipNext) + { + psc->addr = px->addr; + psc->pNext = (void *)px; + } + iSUBNum--; + } + + fclose(subfile); +} + +///////////////////////////////////////////////////////// +// func for calculating 'right' subdata + +void FakeSubData(unsigned long adr) +{ + SubCData[12]=0x41; + SubCData[13]=0x01; + SubCData[14]=0x01; + + /* TODO (#1#): addr2time fake sub data + */ + + +//!!!!!!!!!!!!!!!!!!!!!!!???? + addr2timeB(adr, &SubCData[15]); +// SubCData[18]=0x00; + addr2timeB(adr+150,&SubCData[19]); +} + +///////////////////////////////////////////////////////// +// check, if for a given addr we have special subdata in cache + +void CheckSUBCache(long addr) +{ + SUB_CACHE * pcstart, * pcend, * pcpos; + + pcstart=subCache; // ptrs to address arrays (start/end) + pcend =subCache+iSUBNum; + + if(addr>=pcstart->addr && // easy check, if given addr is between start/end + addr<=pcend->addr) + { + while(1) // now search for sub + { + if(addr==pcend->addr) {pcpos=pcend;break;} // got it! break + + pcpos=pcstart+(pcend-pcstart)/2; // get the 'middle' address + if(pcpos==pcstart) break; // no more checks can be done + if(addraddr) // look further... + { + pcend=pcpos; + continue; + } + if(addr>pcpos->addr) + { + pcstart=pcpos; + continue; + } + break; + } + + if(addr==pcpos->addr) // found some cached data? + { + SUB_DATA * p=(SUB_DATA *)pcpos->pNext; // -> ptr to data + memcpy(&SubCData[12],p->subq,10); // -> get the data + return; // -> done + } + } + + FakeSubData(addr); // no subcdata avail, so fake right one +} + +///////////////////////////////////////////////////////// +// free all sub cache bufs + +void FreeSUBCache(void) +{ + SUB_DATA * p=subHead; + void * pn; + while(p) + { + pn=p->pNext; + free(p); + p=(SUB_DATA *)pn; + } + subHead=NULL; + + if(subCache) free(subCache); + subCache=NULL; +} + +///////////////////////////////////////////////////////// diff --git a/plugins/CDVDpeops/sub.h b/plugins/CDVDpeops/sub.h index 50aa7d6167..1f5cb4dccd 100644 --- a/plugins/CDVDpeops/sub.h +++ b/plugins/CDVDpeops/sub.h @@ -1,30 +1,30 @@ -/*************************************************************************** - sub.h - description - ------------------- - begin : Wed Sep 18 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/09/19 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -void BuildSUBCache(void); -void FakeSubData(unsigned long adr); -void CheckSUBCache(long addr); -void FreeSUBCache(void); +/*************************************************************************** + sub.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +void BuildSUBCache(void); +void FakeSubData(unsigned long adr); +void CheckSUBCache(long addr); +void FreeSUBCache(void); diff --git a/plugins/CDVDpeops/toc.c b/plugins/CDVDpeops/toc.c index a7e23f9f23..03dfb23a97 100644 --- a/plugins/CDVDpeops/toc.c +++ b/plugins/CDVDpeops/toc.c @@ -1,105 +1,105 @@ -/*************************************************************************** - toc.c - description - ------------------- - begin : Sun Nov 16 2003 - copyright : (C) 2003 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2003/11/16 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -///////////////////////////////////////////////////////// - -#include "stdafx.h" -#define _IN_TOC -#include "externals.h" - -///////////////////////////////////////////////////////// - -TOC sTOC; - -///////////////////////////////////////////////////////// -// read toc - - -void ReadTOC(void) -{ - unsigned char xbuffer[4];DWORD dwStatus; - - LockGenCDAccess(); - - memset(&(sTOC),0,sizeof(sTOC)); // init toc infos - - dwStatus=GetSCSITOC((LPTOC)&sTOC); // get toc by scsi... may change that for ioctrl in xp/2k? - - UnlockGenCDAccess(); - - if(dwStatus!=SS_COMP) return; - -#ifdef DBGOUT - auxprintf("TOC Last %d, max %08x,%08x\n",sTOC.cLastTrack,sTOC.tracks[sTOC.cLastTrack].lAddr,reOrder(sTOC.tracks[sTOC.cLastTrack].lAddr)); -#endif - // re-order it to psemu pro standards - addr2time(reOrder(sTOC.tracks[sTOC.cLastTrack].lAddr),xbuffer); - -#ifdef DBGOUT - auxprintf("TOC %d, %d, %d, %d\n", - xbuffer[0],xbuffer[1],xbuffer[2],xbuffer[3] ); -#endif - - xbuffer[0]=itob(xbuffer[0]); - xbuffer[1]=itob(xbuffer[1]); - xbuffer[2]=itob(xbuffer[2]); - xbuffer[3]=itob(xbuffer[3]); - lMaxAddr=time2addrB(xbuffer); // get max data adr -} - -///////////////////////////////////////////////////////// -// get the highest address of first (=data) track - -unsigned long GetLastTrack1Addr(void) -{ - unsigned char xbuffer[4];DWORD dwStatus; - unsigned long lmax; - TOC xTOC; - - LockGenCDAccess(); - - memset(&(xTOC),0,sizeof(xTOC)); - - dwStatus=GetSCSITOC((LPTOC)&xTOC); - - UnlockGenCDAccess(); - - if(dwStatus!=SS_COMP) return 0; - - addr2time(reOrder(xTOC.tracks[1].lAddr),xbuffer); - - xbuffer[0]=itob(xbuffer[0]); - xbuffer[1]=itob(xbuffer[1]); - xbuffer[2]=itob(xbuffer[2]); - xbuffer[3]=itob(xbuffer[3]); - - lmax=time2addrB(xbuffer); - if(lmax<150) return 0; - - return lmax-150; -} - -///////////////////////////////////////////////////////// +/*************************************************************************** + toc.c - description + ------------------- + begin : Sun Nov 16 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/11/16 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +///////////////////////////////////////////////////////// + +#include "stdafx.h" +#define _IN_TOC +#include "externals.h" + +///////////////////////////////////////////////////////// + +TOC sTOC; + +///////////////////////////////////////////////////////// +// read toc + + +void ReadTOC(void) +{ + unsigned char xbuffer[4];DWORD dwStatus; + + LockGenCDAccess(); + + memset(&(sTOC),0,sizeof(sTOC)); // init toc infos + + dwStatus=GetSCSITOC((LPTOC)&sTOC); // get toc by scsi... may change that for ioctrl in xp/2k? + + UnlockGenCDAccess(); + + if(dwStatus!=SS_COMP) return; + +#ifdef DBGOUT + auxprintf("TOC Last %d, max %08x,%08x\n",sTOC.cLastTrack,sTOC.tracks[sTOC.cLastTrack].lAddr,reOrder(sTOC.tracks[sTOC.cLastTrack].lAddr)); +#endif + // re-order it to psemu pro standards + addr2time(reOrder(sTOC.tracks[sTOC.cLastTrack].lAddr),xbuffer); + +#ifdef DBGOUT + auxprintf("TOC %d, %d, %d, %d\n", + xbuffer[0],xbuffer[1],xbuffer[2],xbuffer[3] ); +#endif + + xbuffer[0]=itob(xbuffer[0]); + xbuffer[1]=itob(xbuffer[1]); + xbuffer[2]=itob(xbuffer[2]); + xbuffer[3]=itob(xbuffer[3]); + lMaxAddr=time2addrB(xbuffer); // get max data adr +} + +///////////////////////////////////////////////////////// +// get the highest address of first (=data) track + +unsigned long GetLastTrack1Addr(void) +{ + unsigned char xbuffer[4];DWORD dwStatus; + unsigned long lmax; + TOC xTOC; + + LockGenCDAccess(); + + memset(&(xTOC),0,sizeof(xTOC)); + + dwStatus=GetSCSITOC((LPTOC)&xTOC); + + UnlockGenCDAccess(); + + if(dwStatus!=SS_COMP) return 0; + + addr2time(reOrder(xTOC.tracks[1].lAddr),xbuffer); + + xbuffer[0]=itob(xbuffer[0]); + xbuffer[1]=itob(xbuffer[1]); + xbuffer[2]=itob(xbuffer[2]); + xbuffer[3]=itob(xbuffer[3]); + + lmax=time2addrB(xbuffer); + if(lmax<150) return 0; + + return lmax-150; +} + +///////////////////////////////////////////////////////// diff --git a/plugins/CDVDpeops/toc.h b/plugins/CDVDpeops/toc.h index 03d31c357b..712c57c7aa 100644 --- a/plugins/CDVDpeops/toc.h +++ b/plugins/CDVDpeops/toc.h @@ -1,28 +1,28 @@ -/*************************************************************************** - toc.h - description - ------------------- - begin : Wed Sep 18 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/09/19 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -void ReadTOC(void); -unsigned long GetLastTrack1Addr(void); +/*************************************************************************** + toc.h - description + ------------------- + begin : Wed Sep 18 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/09/19 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +void ReadTOC(void); +unsigned long GetLastTrack1Addr(void); diff --git a/plugins/CDVDpeops/wnaspi32.h b/plugins/CDVDpeops/wnaspi32.h index fabc0f33b3..bbb919c0dd 100644 --- a/plugins/CDVDpeops/wnaspi32.h +++ b/plugins/CDVDpeops/wnaspi32.h @@ -131,20 +131,20 @@ SRB_HAInquiry, *PSRB_HAInquiry, FAR *LPSRB_HAInquiry; //***************************************************************************** // %%% SRB - GET DEVICE TYPE - SC_GET_DEV_TYPE (1) %%% //***************************************************************************** - -typedef struct -{ - BYTE SRB_Cmd; /* 00/000 ASPI cmd code == SC_GET_DEV_TYPE */ - BYTE SRB_Status; /* 01/001 ASPI command status byte */ - BYTE SRB_HaID; /* 02/002 ASPI host adapter number */ - BYTE SRB_Flags; /* 03/003 Reserved, must = 0 */ - DWORD SRB_Hdr_Rsvd; /* 04/004 Reserved, must = 0 */ - BYTE SRB_Target; /* 08/008 Target's SCSI ID */ - BYTE SRB_Lun; /* 09/009 Target's LUN number */ - BYTE SRB_DeviceType; /* 0a/010 Target's peripheral device type */ - BYTE SRB_Rsvd1; /* 0b/011 Reserved, must = 0 */ - BYTE pad[68]; -} SRB_GDEVBlock, *PSRB_GDEVBlock, FAR *LPSRB_GDEVBlock; + +typedef struct +{ + BYTE SRB_Cmd; /* 00/000 ASPI cmd code == SC_GET_DEV_TYPE */ + BYTE SRB_Status; /* 01/001 ASPI command status byte */ + BYTE SRB_HaID; /* 02/002 ASPI host adapter number */ + BYTE SRB_Flags; /* 03/003 Reserved, must = 0 */ + DWORD SRB_Hdr_Rsvd; /* 04/004 Reserved, must = 0 */ + BYTE SRB_Target; /* 08/008 Target's SCSI ID */ + BYTE SRB_Lun; /* 09/009 Target's LUN number */ + BYTE SRB_DeviceType; /* 0a/010 Target's peripheral device type */ + BYTE SRB_Rsvd1; /* 0b/011 Reserved, must = 0 */ + BYTE pad[68]; +} SRB_GDEVBlock, *PSRB_GDEVBlock, FAR *LPSRB_GDEVBlock; //***************************************************************************** // %%% SRB - EXECUTE SCSI COMMAND - SC_EXEC_SCSI_CMD (2) %%% @@ -273,40 +273,40 @@ typedef struct tag_ASPI32BUFF // Offset DWORD AB_Reserved; // 0C/012 Reserved } ASPI32BUFF, *PASPI32BUFF, FAR *LPASPI32BUFF; - -//***************************************************************************** -// %%% TOC structures %%% -//***************************************************************************** - -typedef struct -{ - unsigned char reserved1; - unsigned char cAdrCtrl; - unsigned char cTrackNum; - unsigned char reserved2; - unsigned long lAddr; -} TOC_TRACK; - -typedef struct -{ - unsigned short usTocDataLen; - unsigned char cFirstTrack; - unsigned char cLastTrack; - TOC_TRACK tracks[100]; -} TOC, *PTOC, FAR *LPTOC; + +//***************************************************************************** +// %%% TOC structures %%% +//***************************************************************************** + +typedef struct +{ + unsigned char reserved1; + unsigned char cAdrCtrl; + unsigned char cTrackNum; + unsigned char reserved2; + unsigned long lAddr; +} TOC_TRACK; + +typedef struct +{ + unsigned short usTocDataLen; + unsigned char cFirstTrack; + unsigned char cLastTrack; + TOC_TRACK tracks[100]; +} TOC, *PTOC, FAR *LPTOC; //***************************************************************************** // %%% PROTOTYPES - User Callable ASPI for Win32 Functions %%% //***************************************************************************** - -typedef struct -{ - BYTE SRB_Cmd; - BYTE SRB_Status; - BYTE SRB_HaId; - BYTE SRB_Flags; - DWORD SRB_Hdr_Rsvd; -} SRB, *PSRB, FAR *LPSRB; + +typedef struct +{ + BYTE SRB_Cmd; + BYTE SRB_Status; + BYTE SRB_HaId; + BYTE SRB_Flags; + DWORD SRB_Hdr_Rsvd; +} SRB, *PSRB, FAR *LPSRB; #if defined(__BORLANDC__) diff --git a/plugins/FWnull/FW.c b/plugins/FWnull/FW.c index 37aeda8107..800d1575f8 100644 --- a/plugins/FWnull/FW.c +++ b/plugins/FWnull/FW.c @@ -1,147 +1,147 @@ -/* FWnull - * Copyright (C) 2004-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include - -#include "FW.h" - -const unsigned char version = PS2E_FW_VERSION; -const unsigned char revision = 0; -const unsigned char build = 4; // increase that with each version - -static char *libraryName = "FWnull Driver"; - -s8 *fwregs; - -#define fwRs32(mem) (*(s32*)&fwregs[(mem) & 0xffff]) -#define fwRu32(mem) (*(u32*)&fwregs[(mem) & 0xffff]) - - -u32 CALLBACK PS2EgetLibType() { - return PS2E_LT_FW; -} - -char* CALLBACK PS2EgetLibName() { - return libraryName; -} - -u32 CALLBACK PS2EgetLibVersion2(u32 type) { - return (version<<16) | (revision<<8) | build; -} - -void __Log(char *fmt, ...) { - va_list list; - - if (!conf.Log || fwLog == NULL) return; - - va_start(list, fmt); - vfprintf(fwLog, fmt, list); - va_end(list); -} - -s32 CALLBACK FWinit() { - LoadConfig(); -#ifdef FW_LOG - fwLog = fopen("logs/fwLog.txt", "w"); - if (fwLog) setvbuf(fwLog, NULL, _IONBF, 0); - FW_LOG("FWnull plugin version %d,%d\n",revision,build); - FW_LOG("FW init\n"); -#endif - - fwregs = (s8*)malloc(0x10000); - if (fwregs == NULL) { - SysMessage("Error allocating Memory\n"); return -1; - } - - return 0; -} - -void CALLBACK FWshutdown() { - free(fwregs); - -#ifdef FW_LOG - if (fwLog) fclose(fwLog); -#endif -} - -s32 CALLBACK FWopen(void *pDsp) { -#ifdef FW_LOG - FW_LOG("FW open\n"); -#endif - -#ifdef _WIN32 -#else - Display* dsp = *(Display**)pDsp; -#endif - - return 0; -} - -void CALLBACK FWclose() { -} - - - - -u32 CALLBACK FWread32(u32 addr) { - u32 ret=0; - - switch (addr) { - case 0x1f808410: - ret = 0x8; - break; - - default: - ret = fwRu32(addr); - } -#ifdef FW_LOG - FW_LOG("FW read mem 0x%x: 0x%x\n", addr, ret); -#endif - - return ret; -} - - - -void CALLBACK FWwrite32(u32 addr, u32 value) { - switch (addr) { - default: - fwRu32(addr) = value; - break; - } -#ifdef FW_LOG - FW_LOG("FW write mem 0x%x: 0x%x\n", addr, value); -#endif -} - -void CALLBACK FWirqCallback(void (*callback)()) { - FWirq = callback; -} - - -s32 CALLBACK FWfreeze(int mode, freezeData *data) { - return 0; -} - - -s32 CALLBACK FWtest() { - return 0; -} - +/* FWnull + * Copyright (C) 2004-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include "FW.h" + +const unsigned char version = PS2E_FW_VERSION; +const unsigned char revision = 0; +const unsigned char build = 4; // increase that with each version + +static char *libraryName = "FWnull Driver"; + +s8 *fwregs; + +#define fwRs32(mem) (*(s32*)&fwregs[(mem) & 0xffff]) +#define fwRu32(mem) (*(u32*)&fwregs[(mem) & 0xffff]) + + +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_FW; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (version<<16) | (revision<<8) | build; +} + +void __Log(char *fmt, ...) { + va_list list; + + if (!conf.Log || fwLog == NULL) return; + + va_start(list, fmt); + vfprintf(fwLog, fmt, list); + va_end(list); +} + +s32 CALLBACK FWinit() { + LoadConfig(); +#ifdef FW_LOG + fwLog = fopen("logs/fwLog.txt", "w"); + if (fwLog) setvbuf(fwLog, NULL, _IONBF, 0); + FW_LOG("FWnull plugin version %d,%d\n",revision,build); + FW_LOG("FW init\n"); +#endif + + fwregs = (s8*)malloc(0x10000); + if (fwregs == NULL) { + SysMessage("Error allocating Memory\n"); return -1; + } + + return 0; +} + +void CALLBACK FWshutdown() { + free(fwregs); + +#ifdef FW_LOG + if (fwLog) fclose(fwLog); +#endif +} + +s32 CALLBACK FWopen(void *pDsp) { +#ifdef FW_LOG + FW_LOG("FW open\n"); +#endif + +#ifdef _WIN32 +#else + Display* dsp = *(Display**)pDsp; +#endif + + return 0; +} + +void CALLBACK FWclose() { +} + + + + +u32 CALLBACK FWread32(u32 addr) { + u32 ret=0; + + switch (addr) { + case 0x1f808410: + ret = 0x8; + break; + + default: + ret = fwRu32(addr); + } +#ifdef FW_LOG + FW_LOG("FW read mem 0x%x: 0x%x\n", addr, ret); +#endif + + return ret; +} + + + +void CALLBACK FWwrite32(u32 addr, u32 value) { + switch (addr) { + default: + fwRu32(addr) = value; + break; + } +#ifdef FW_LOG + FW_LOG("FW write mem 0x%x: 0x%x\n", addr, value); +#endif +} + +void CALLBACK FWirqCallback(void (*callback)()) { + FWirq = callback; +} + + +s32 CALLBACK FWfreeze(int mode, freezeData *data) { + return 0; +} + + +s32 CALLBACK FWtest() { + return 0; +} + diff --git a/plugins/FWnull/FW.h b/plugins/FWnull/FW.h index e124d356ac..56d23fcd2d 100644 --- a/plugins/FWnull/FW.h +++ b/plugins/FWnull/FW.h @@ -1,59 +1,59 @@ -/* FWnull - * Copyright (C) 2004-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef __FW_H__ -#define __FW_H__ - -#include - -#define FWdefs -#include "PS2Edefs.h" - -#ifdef _WIN32 - -#include -#include - -#else - -#include -#include - -#define __inline inline - -#endif - -#define FW_LOG __Log - -typedef struct { - int Log; -} Config; - -Config conf; -void (*FWirq)(); - -void SaveConfig(); -void LoadConfig(); - -FILE *fwLog; -void __Log(char *fmt, ...); - -void SysMessage(char *fmt, ...); - -#endif +/* FWnull + * Copyright (C) 2004-2005 PCSX2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __FW_H__ +#define __FW_H__ + +#include + +#define FWdefs +#include "PS2Edefs.h" + +#ifdef _WIN32 + +#include +#include + +#else + +#include +#include + +#define __inline inline + +#endif + +#define FW_LOG __Log + +typedef struct { + int Log; +} Config; + +Config conf; +void (*FWirq)(); + +void SaveConfig(); +void LoadConfig(); + +FILE *fwLog; +void __Log(char *fmt, ...); + +void SysMessage(char *fmt, ...); + +#endif diff --git a/plugins/FWnull/Linux/Config.c b/plugins/FWnull/Linux/Config.c index 3eda6eb98f..70fc156cd5 100644 --- a/plugins/FWnull/Linux/Config.c +++ b/plugins/FWnull/Linux/Config.c @@ -1,51 +1,51 @@ -/* FireWire - * Copyright (C) 2002-2004 USBlinuz 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include - -#include "FW.h" - -void LoadConfig() { - FILE *f; - char cfg[256]; - - sprintf(cfg, "%s/.PS2E/FWnull.cfg", getenv("HOME")); - f = fopen(cfg, "r"); - if (f == NULL) { - return; - } - fclose(f); -} - -void SaveConfig() { - FILE *f; - char cfg[256]; - - sprintf(cfg, "%s/.PS2E", getenv("HOME")); - mkdir(cfg, 0755); - sprintf(cfg, "%s/.PS2E/FWnull.cfg", getenv("HOME")); - f = fopen(cfg, "w"); - if (f == NULL) - return; - fclose(f); -} - +/* FireWire + * Copyright (C) 2002-2004 USBlinuz 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include "FW.h" + +void LoadConfig() { + FILE *f; + char cfg[256]; + + sprintf(cfg, "%s/.PS2E/FWnull.cfg", getenv("HOME")); + f = fopen(cfg, "r"); + if (f == NULL) { + return; + } + fclose(f); +} + +void SaveConfig() { + FILE *f; + char cfg[256]; + + sprintf(cfg, "%s/.PS2E", getenv("HOME")); + mkdir(cfg, 0755); + sprintf(cfg, "%s/.PS2E/FWnull.cfg", getenv("HOME")); + f = fopen(cfg, "w"); + if (f == NULL) + return; + fclose(f); +} + diff --git a/plugins/FWnull/Linux/Config.h b/plugins/FWnull/Linux/Config.h index 9eb36474fd..21577711de 100644 --- a/plugins/FWnull/Linux/Config.h +++ b/plugins/FWnull/Linux/Config.h @@ -1,20 +1,20 @@ -/* USBlinuz - * Copyright (C) 2002-2004 USBlinuz 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -void SaveConf(); -void LoadConf(); +/* USBlinuz + * Copyright (C) 2002-2004 USBlinuz 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +void SaveConf(); +void LoadConf(); diff --git a/plugins/FWnull/Linux/Linux.c b/plugins/FWnull/Linux/Linux.c index 9a70105daa..c0f41fa3ce 100644 --- a/plugins/FWnull/Linux/Linux.c +++ b/plugins/FWnull/Linux/Linux.c @@ -1,75 +1,75 @@ -/* FireWire - * Copyright (C) 2002-2004 FireWire 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "FW.h" - -int ExecCfg(char *arg) { - char cfg[256]; - struct stat buf; - - strcpy(cfg, "./cfgFWnull"); - if (stat(cfg, &buf) != -1) { - sprintf(cfg, "%s %s", cfg, arg); - return system(cfg); - } - - strcpy(cfg, "./cfg/cfgFWnull"); - if (stat(cfg, &buf) != -1) { - sprintf(cfg, "%s %s", cfg, arg); - return system(cfg); - } - - sprintf(cfg, "%s/cfgFWnull", getenv("HOME")); - if (stat(cfg, &buf) != -1) { - sprintf(cfg, "%s %s", cfg, arg); - return system(cfg); - } - - printf("cfgFWnull file not found!\n"); - return -1; -} - -void SysMessage(char *fmt, ...) { - va_list list; - char msg[512]; - char cmd[512]; - - va_start(list, fmt); - vsprintf(msg, fmt, list); - va_end(list); - - sprintf(cmd, "message \"%s\"", msg); - ExecCfg(cmd); -} - -void FWconfigure() { - ExecCfg("configure"); -} - -void FWabout() { - ExecCfg("about"); -} - +/* FireWire + * Copyright (C) 2002-2004 FireWire 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "FW.h" + +int ExecCfg(char *arg) { + char cfg[256]; + struct stat buf; + + strcpy(cfg, "./cfgFWnull"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + strcpy(cfg, "./cfg/cfgFWnull"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + sprintf(cfg, "%s/cfgFWnull", getenv("HOME")); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + printf("cfgFWnull file not found!\n"); + return -1; +} + +void SysMessage(char *fmt, ...) { + va_list list; + char msg[512]; + char cmd[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + sprintf(cmd, "message \"%s\"", msg); + ExecCfg(cmd); +} + +void FWconfigure() { + ExecCfg("configure"); +} + +void FWabout() { + ExecCfg("about"); +} + diff --git a/plugins/FWnull/Linux/Makefile b/plugins/FWnull/Linux/Makefile index 28665dbbe7..a5b50b8dc5 100644 --- a/plugins/FWnull/Linux/Makefile +++ b/plugins/FWnull/Linux/Makefile @@ -1,35 +1,35 @@ - -PLUGIN = libFWnull.so -CFG = cfgFWnull -CFLAGS+= -fPIC -Wall -I. -I.. -O3 -fomit-frame-pointer -fno-strict-aliasing -OBJS = ../FW.o -OBJS+= Linux.o Config.o -CFGOBJS = conf.o interface.o support.o Config.o -DEPS:= $(OBJS:.o=.d) -CFGDEPS:= $(CFGOBJS:.o=.d) -LIBS = -lpthread -CFLAGS+= $(shell pkg-config --cflags gtk+-2.0) -D__LINUX__ -CFGLIBS = $(shell pkg-config --libs gtk+-2.0) - -CC = gcc - -all: plugin cfg -install: all - -plugin: ${OBJS} - rm -f ${PLUGIN} - ${CC} -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} - strip --strip-unneeded --strip-debug ${PLUGIN} - -cfg: ${CFGOBJS} - rm -f ${CFG} - ${CC} ${CFLAGS} ${CFGOBJS} -o ${CFG} ${CFGLIBS} - strip ${CFG} - -clean: - rm -f ${OBJS} ${DEPS} ${CFGOBJS} ${CFGDEPS} ${PLUGIN} ${CFG} - -%.o: %.c - ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) - --include ${DEPS} + +PLUGIN = libFWnull.so +CFG = cfgFWnull +CFLAGS+= -fPIC -Wall -I. -I.. -O3 -fomit-frame-pointer -fno-strict-aliasing +OBJS = ../FW.o +OBJS+= Linux.o Config.o +CFGOBJS = conf.o interface.o support.o Config.o +DEPS:= $(OBJS:.o=.d) +CFGDEPS:= $(CFGOBJS:.o=.d) +LIBS = -lpthread +CFLAGS+= $(shell pkg-config --cflags gtk+-2.0) -D__LINUX__ +CFGLIBS = $(shell pkg-config --libs gtk+-2.0) + +CC = gcc + +all: plugin cfg +install: all + +plugin: ${OBJS} + rm -f ${PLUGIN} + ${CC} -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + strip --strip-unneeded --strip-debug ${PLUGIN} + +cfg: ${CFGOBJS} + rm -f ${CFG} + ${CC} ${CFLAGS} ${CFGOBJS} -o ${CFG} ${CFGLIBS} + strip ${CFG} + +clean: + rm -f ${OBJS} ${DEPS} ${CFGOBJS} ${CFGDEPS} ${PLUGIN} ${CFG} + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +-include ${DEPS} diff --git a/plugins/FWnull/Linux/callbacks.h b/plugins/FWnull/Linux/callbacks.h index 22cf74a988..e606c242f0 100644 --- a/plugins/FWnull/Linux/callbacks.h +++ b/plugins/FWnull/Linux/callbacks.h @@ -1,14 +1,14 @@ -#include - - -void -OnConf_Ok (GtkButton *button, - gpointer user_data); - -void -OnConf_Cancel (GtkButton *button, - gpointer user_data); - -void -OnAbout_Ok (GtkButton *button, - gpointer user_data); +#include + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data); + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data); + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data); diff --git a/plugins/FWnull/Linux/interface.c b/plugins/FWnull/Linux/interface.c index a73c0861ed..10dcc15912 100644 --- a/plugins/FWnull/Linux/interface.c +++ b/plugins/FWnull/Linux/interface.c @@ -1,219 +1,219 @@ -/* - * DO NOT EDIT THIS FILE - it is generated by Glade. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include - -#include -#include - -#include "callbacks.h" -#include "interface.h" -#include "support.h" - -GtkWidget* -create_Config (void) -{ - GtkWidget *Config; - GtkWidget *vbox1; - GtkWidget *frame2; - GtkWidget *hbox1; - GtkWidget *label4; - GtkWidget *GtkCombo_Eth; - GtkWidget *combo_entry1; - GtkWidget *frame3; - GtkWidget *hbox2; - GtkWidget *label5; - GtkWidget *GtkCombo_Hdd; - GtkWidget *entry1; - GtkWidget *hbuttonbox1; - GtkWidget *button1; - GtkWidget *button2; - - Config = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_object_set_data (GTK_OBJECT (Config), "Config", Config); - gtk_container_set_border_width (GTK_CONTAINER (Config), 5); - gtk_window_set_title (GTK_WINDOW (Config), "DEV9config"); - gtk_window_set_position (GTK_WINDOW (Config), GTK_WIN_POS_CENTER); - - vbox1 = gtk_vbox_new (FALSE, 5); - gtk_widget_ref (vbox1); - gtk_object_set_data_full (GTK_OBJECT (Config), "vbox1", vbox1, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox1); - gtk_container_add (GTK_CONTAINER (Config), vbox1); - gtk_container_set_border_width (GTK_CONTAINER (vbox1), 5); - - frame2 = gtk_frame_new ("Ethernet"); - gtk_widget_ref (frame2); - gtk_object_set_data_full (GTK_OBJECT (Config), "frame2", frame2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (frame2); - gtk_box_pack_start (GTK_BOX (vbox1), frame2, TRUE, TRUE, 0); - - hbox1 = gtk_hbox_new (TRUE, 5); - gtk_widget_ref (hbox1); - gtk_object_set_data_full (GTK_OBJECT (Config), "hbox1", hbox1, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbox1); - gtk_container_add (GTK_CONTAINER (frame2), hbox1); - gtk_container_set_border_width (GTK_CONTAINER (hbox1), 5); - - label4 = gtk_label_new ("Device:"); - gtk_widget_ref (label4); - gtk_object_set_data_full (GTK_OBJECT (Config), "label4", label4, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label4); - gtk_box_pack_start (GTK_BOX (hbox1), label4, FALSE, FALSE, 0); - - GtkCombo_Eth = gtk_combo_new (); - gtk_widget_ref (GtkCombo_Eth); - gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Eth", GtkCombo_Eth, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (GtkCombo_Eth); - gtk_box_pack_start (GTK_BOX (hbox1), GtkCombo_Eth, FALSE, FALSE, 0); - gtk_widget_set_usize (GtkCombo_Eth, 130, -2); - - combo_entry1 = GTK_COMBO (GtkCombo_Eth)->entry; - gtk_widget_ref (combo_entry1); - gtk_object_set_data_full (GTK_OBJECT (Config), "combo_entry1", combo_entry1, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (combo_entry1); - - frame3 = gtk_frame_new ("Hdd"); - gtk_widget_ref (frame3); - gtk_object_set_data_full (GTK_OBJECT (Config), "frame3", frame3, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (frame3); - gtk_box_pack_start (GTK_BOX (vbox1), frame3, TRUE, TRUE, 0); - - hbox2 = gtk_hbox_new (TRUE, 5); - gtk_widget_ref (hbox2); - gtk_object_set_data_full (GTK_OBJECT (Config), "hbox2", hbox2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbox2); - gtk_container_add (GTK_CONTAINER (frame3), hbox2); - gtk_container_set_border_width (GTK_CONTAINER (hbox2), 5); - - label5 = gtk_label_new ("Device:"); - gtk_widget_ref (label5); - gtk_object_set_data_full (GTK_OBJECT (Config), "label5", label5, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label5); - gtk_box_pack_start (GTK_BOX (hbox2), label5, FALSE, FALSE, 0); - - GtkCombo_Hdd = gtk_combo_new (); - gtk_widget_ref (GtkCombo_Hdd); - gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Hdd", GtkCombo_Hdd, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (GtkCombo_Hdd); - gtk_box_pack_start (GTK_BOX (hbox2), GtkCombo_Hdd, FALSE, FALSE, 0); - gtk_widget_set_usize (GtkCombo_Hdd, 130, -2); - - entry1 = GTK_COMBO (GtkCombo_Hdd)->entry; - gtk_widget_ref (entry1); - gtk_object_set_data_full (GTK_OBJECT (Config), "entry1", entry1, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (entry1); - - hbuttonbox1 = gtk_hbutton_box_new (); - gtk_widget_ref (hbuttonbox1); - gtk_object_set_data_full (GTK_OBJECT (Config), "hbuttonbox1", hbuttonbox1, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbuttonbox1); - gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox1, TRUE, TRUE, 0); - - button1 = gtk_button_new_with_label ("Ok"); - gtk_widget_ref (button1); - gtk_object_set_data_full (GTK_OBJECT (Config), "button1", button1, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (button1); - gtk_container_add (GTK_CONTAINER (hbuttonbox1), button1); - GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT); - - button2 = gtk_button_new_with_label ("Cancel"); - gtk_widget_ref (button2); - gtk_object_set_data_full (GTK_OBJECT (Config), "button2", button2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (button2); - gtk_container_add (GTK_CONTAINER (hbuttonbox1), button2); - GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT); - - gtk_signal_connect (GTK_OBJECT (button1), "clicked", - GTK_SIGNAL_FUNC (OnConf_Ok), - NULL); - gtk_signal_connect (GTK_OBJECT (button2), "clicked", - GTK_SIGNAL_FUNC (OnConf_Cancel), - NULL); - - return Config; -} - -GtkWidget* -create_About (void) -{ - GtkWidget *About; - GtkWidget *vbox2; - GtkWidget *label2; - GtkWidget *label3; - GtkWidget *hbuttonbox2; - GtkWidget *button3; - - About = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_object_set_data (GTK_OBJECT (About), "About", About); - gtk_container_set_border_width (GTK_CONTAINER (About), 5); - gtk_window_set_title (GTK_WINDOW (About), "DEV9about"); - gtk_window_set_position (GTK_WINDOW (About), GTK_WIN_POS_CENTER); - - vbox2 = gtk_vbox_new (FALSE, 5); - gtk_widget_ref (vbox2); - gtk_object_set_data_full (GTK_OBJECT (About), "vbox2", vbox2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox2); - gtk_container_add (GTK_CONTAINER (About), vbox2); - gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); - - label2 = gtk_label_new ("DEV9linuz Driver"); - gtk_widget_ref (label2); - gtk_object_set_data_full (GTK_OBJECT (About), "label2", label2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label2); - gtk_box_pack_start (GTK_BOX (vbox2), label2, FALSE, FALSE, 0); - - label3 = gtk_label_new ("Author: linuzappz "); - gtk_widget_ref (label3); - gtk_object_set_data_full (GTK_OBJECT (About), "label3", label3, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label3); - gtk_box_pack_start (GTK_BOX (vbox2), label3, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (label3), GTK_JUSTIFY_LEFT); - - hbuttonbox2 = gtk_hbutton_box_new (); - gtk_widget_ref (hbuttonbox2); - gtk_object_set_data_full (GTK_OBJECT (About), "hbuttonbox2", hbuttonbox2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbuttonbox2); - gtk_box_pack_start (GTK_BOX (vbox2), hbuttonbox2, TRUE, TRUE, 0); - - button3 = gtk_button_new_with_label ("Ok"); - gtk_widget_ref (button3); - gtk_object_set_data_full (GTK_OBJECT (About), "button3", button3, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (button3); - gtk_container_add (GTK_CONTAINER (hbuttonbox2), button3); - GTK_WIDGET_SET_FLAGS (button3, GTK_CAN_DEFAULT); - - gtk_signal_connect (GTK_OBJECT (button3), "clicked", - GTK_SIGNAL_FUNC (OnAbout_Ok), - NULL); - - return About; -} - +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +GtkWidget* +create_Config (void) +{ + GtkWidget *Config; + GtkWidget *vbox1; + GtkWidget *frame2; + GtkWidget *hbox1; + GtkWidget *label4; + GtkWidget *GtkCombo_Eth; + GtkWidget *combo_entry1; + GtkWidget *frame3; + GtkWidget *hbox2; + GtkWidget *label5; + GtkWidget *GtkCombo_Hdd; + GtkWidget *entry1; + GtkWidget *hbuttonbox1; + GtkWidget *button1; + GtkWidget *button2; + + Config = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (Config), "Config", Config); + gtk_container_set_border_width (GTK_CONTAINER (Config), 5); + gtk_window_set_title (GTK_WINDOW (Config), "DEV9config"); + gtk_window_set_position (GTK_WINDOW (Config), GTK_WIN_POS_CENTER); + + vbox1 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox1", vbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox1); + gtk_container_add (GTK_CONTAINER (Config), vbox1); + gtk_container_set_border_width (GTK_CONTAINER (vbox1), 5); + + frame2 = gtk_frame_new ("Ethernet"); + gtk_widget_ref (frame2); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame2", frame2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame2); + gtk_box_pack_start (GTK_BOX (vbox1), frame2, TRUE, TRUE, 0); + + hbox1 = gtk_hbox_new (TRUE, 5); + gtk_widget_ref (hbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox1", hbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox1); + gtk_container_add (GTK_CONTAINER (frame2), hbox1); + gtk_container_set_border_width (GTK_CONTAINER (hbox1), 5); + + label4 = gtk_label_new ("Device:"); + gtk_widget_ref (label4); + gtk_object_set_data_full (GTK_OBJECT (Config), "label4", label4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label4); + gtk_box_pack_start (GTK_BOX (hbox1), label4, FALSE, FALSE, 0); + + GtkCombo_Eth = gtk_combo_new (); + gtk_widget_ref (GtkCombo_Eth); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Eth", GtkCombo_Eth, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_Eth); + gtk_box_pack_start (GTK_BOX (hbox1), GtkCombo_Eth, FALSE, FALSE, 0); + gtk_widget_set_usize (GtkCombo_Eth, 130, -2); + + combo_entry1 = GTK_COMBO (GtkCombo_Eth)->entry; + gtk_widget_ref (combo_entry1); + gtk_object_set_data_full (GTK_OBJECT (Config), "combo_entry1", combo_entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo_entry1); + + frame3 = gtk_frame_new ("Hdd"); + gtk_widget_ref (frame3); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame3", frame3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame3); + gtk_box_pack_start (GTK_BOX (vbox1), frame3, TRUE, TRUE, 0); + + hbox2 = gtk_hbox_new (TRUE, 5); + gtk_widget_ref (hbox2); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox2", hbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox2); + gtk_container_add (GTK_CONTAINER (frame3), hbox2); + gtk_container_set_border_width (GTK_CONTAINER (hbox2), 5); + + label5 = gtk_label_new ("Device:"); + gtk_widget_ref (label5); + gtk_object_set_data_full (GTK_OBJECT (Config), "label5", label5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label5); + gtk_box_pack_start (GTK_BOX (hbox2), label5, FALSE, FALSE, 0); + + GtkCombo_Hdd = gtk_combo_new (); + gtk_widget_ref (GtkCombo_Hdd); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Hdd", GtkCombo_Hdd, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_Hdd); + gtk_box_pack_start (GTK_BOX (hbox2), GtkCombo_Hdd, FALSE, FALSE, 0); + gtk_widget_set_usize (GtkCombo_Hdd, 130, -2); + + entry1 = GTK_COMBO (GtkCombo_Hdd)->entry; + gtk_widget_ref (entry1); + gtk_object_set_data_full (GTK_OBJECT (Config), "entry1", entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (entry1); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbuttonbox1", hbuttonbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox1); + gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox1, TRUE, TRUE, 0); + + button1 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button1); + gtk_object_set_data_full (GTK_OBJECT (Config), "button1", button1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button1); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button1); + GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT); + + button2 = gtk_button_new_with_label ("Cancel"); + gtk_widget_ref (button2); + gtk_object_set_data_full (GTK_OBJECT (Config), "button2", button2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button2); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button2); + GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (button1), "clicked", + GTK_SIGNAL_FUNC (OnConf_Ok), + NULL); + gtk_signal_connect (GTK_OBJECT (button2), "clicked", + GTK_SIGNAL_FUNC (OnConf_Cancel), + NULL); + + return Config; +} + +GtkWidget* +create_About (void) +{ + GtkWidget *About; + GtkWidget *vbox2; + GtkWidget *label2; + GtkWidget *label3; + GtkWidget *hbuttonbox2; + GtkWidget *button3; + + About = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (About), "About", About); + gtk_container_set_border_width (GTK_CONTAINER (About), 5); + gtk_window_set_title (GTK_WINDOW (About), "DEV9about"); + gtk_window_set_position (GTK_WINDOW (About), GTK_WIN_POS_CENTER); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox2); + gtk_object_set_data_full (GTK_OBJECT (About), "vbox2", vbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (About), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + label2 = gtk_label_new ("DEV9linuz Driver"); + gtk_widget_ref (label2); + gtk_object_set_data_full (GTK_OBJECT (About), "label2", label2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label2); + gtk_box_pack_start (GTK_BOX (vbox2), label2, FALSE, FALSE, 0); + + label3 = gtk_label_new ("Author: linuzappz "); + gtk_widget_ref (label3); + gtk_object_set_data_full (GTK_OBJECT (About), "label3", label3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label3); + gtk_box_pack_start (GTK_BOX (vbox2), label3, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label3), GTK_JUSTIFY_LEFT); + + hbuttonbox2 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox2); + gtk_object_set_data_full (GTK_OBJECT (About), "hbuttonbox2", hbuttonbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox2); + gtk_box_pack_start (GTK_BOX (vbox2), hbuttonbox2, TRUE, TRUE, 0); + + button3 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button3); + gtk_object_set_data_full (GTK_OBJECT (About), "button3", button3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button3); + gtk_container_add (GTK_CONTAINER (hbuttonbox2), button3); + GTK_WIDGET_SET_FLAGS (button3, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (button3), "clicked", + GTK_SIGNAL_FUNC (OnAbout_Ok), + NULL); + + return About; +} + diff --git a/plugins/FWnull/Linux/interface.h b/plugins/FWnull/Linux/interface.h index ab0cb1a886..69c303ba3b 100644 --- a/plugins/FWnull/Linux/interface.h +++ b/plugins/FWnull/Linux/interface.h @@ -1,6 +1,6 @@ -/* - * DO NOT EDIT THIS FILE - it is generated by Glade. - */ - -GtkWidget* create_Config (void); -GtkWidget* create_About (void); +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_Config (void); +GtkWidget* create_About (void); diff --git a/plugins/FWnull/Linux/support.c b/plugins/FWnull/Linux/support.c index b053ba6f6d..65007c9217 100644 --- a/plugins/FWnull/Linux/support.c +++ b/plugins/FWnull/Linux/support.c @@ -1,162 +1,162 @@ -/* - * DO NOT EDIT THIS FILE - it is generated by Glade. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include - -#include - -#include "support.h" - -/* This is an internally used function to check if a pixmap file exists. */ -static gchar* check_file_exists (const gchar *directory, - const gchar *filename); - -/* This is an internally used function to create pixmaps. */ -static GtkWidget* create_dummy_pixmap (GtkWidget *widget); - -GtkWidget* -lookup_widget (GtkWidget *widget, - const gchar *widget_name) -{ - GtkWidget *parent, *found_widget; - - for (;;) - { - if (GTK_IS_MENU (widget)) - parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); - else - parent = widget->parent; - if (parent == NULL) - break; - widget = parent; - } - - found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget), - widget_name); - if (!found_widget) - g_warning ("Widget not found: %s", widget_name); - return found_widget; -} - -/* This is a dummy pixmap we use when a pixmap can't be found. */ -static char *dummy_pixmap_xpm[] = { -/* columns rows colors chars-per-pixel */ -"1 1 1 1", -" c None", -/* pixels */ -" " -}; - -/* This is an internally used function to create pixmaps. */ -static GtkWidget* -create_dummy_pixmap (GtkWidget *widget) -{ - GdkColormap *colormap; - GdkPixmap *gdkpixmap; - GdkBitmap *mask; - GtkWidget *pixmap; - - colormap = gtk_widget_get_colormap (widget); - gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, - NULL, dummy_pixmap_xpm); - if (gdkpixmap == NULL) - g_error ("Couldn't create replacement pixmap."); - pixmap = gtk_pixmap_new (gdkpixmap, mask); - gdk_pixmap_unref (gdkpixmap); - gdk_bitmap_unref (mask); - return pixmap; -} - -static GList *pixmaps_directories = NULL; - -/* Use this function to set the directory containing installed pixmaps. */ -void -add_pixmap_directory (const gchar *directory) -{ - pixmaps_directories = g_list_prepend (pixmaps_directories, - g_strdup (directory)); -} - -/* This is an internally used function to create pixmaps. */ -GtkWidget* -create_pixmap (GtkWidget *widget, - const gchar *filename) -{ - gchar *found_filename = NULL; - GdkColormap *colormap; - GdkPixmap *gdkpixmap; - GdkBitmap *mask; - GtkWidget *pixmap; - GList *elem; - - if (!filename || !filename[0]) - return create_dummy_pixmap (widget); - - /* We first try any pixmaps directories set by the application. */ - elem = pixmaps_directories; - while (elem) - { - found_filename = check_file_exists ((gchar*)elem->data, filename); - if (found_filename) - break; - elem = elem->next; - } - - /* If we haven't found the pixmap, try the source directory. */ - if (!found_filename) - { - found_filename = check_file_exists ("pixmaps", filename); - } - - if (!found_filename) - { - g_warning ("Couldn't find pixmap file: %s", filename); - return create_dummy_pixmap (widget); - } - - colormap = gtk_widget_get_colormap (widget); - gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask, - NULL, found_filename); - if (gdkpixmap == NULL) - { - g_warning ("Error loading pixmap file: %s", found_filename); - g_free (found_filename); - return create_dummy_pixmap (widget); - } - g_free (found_filename); - pixmap = gtk_pixmap_new (gdkpixmap, mask); - gdk_pixmap_unref (gdkpixmap); - gdk_bitmap_unref (mask); - return pixmap; -} - -/* This is an internally used function to check if a pixmap file exists. */ -static gchar* -check_file_exists (const gchar *directory, - const gchar *filename) -{ - gchar *full_filename; - struct stat s; - gint status; - - full_filename = (gchar*) g_malloc (strlen (directory) + 1 - + strlen (filename) + 1); - strcpy (full_filename, directory); - strcat (full_filename, G_DIR_SEPARATOR_S); - strcat (full_filename, filename); - - status = stat (full_filename, &s); - if (status == 0 && S_ISREG (s.st_mode)) - return full_filename; - g_free (full_filename); - return NULL; -} - +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include + +#include "support.h" + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* check_file_exists (const gchar *directory, + const gchar *filename); + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* create_dummy_pixmap (GtkWidget *widget); + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +/* This is a dummy pixmap we use when a pixmap can't be found. */ +static char *dummy_pixmap_xpm[] = { +/* columns rows colors chars-per-pixel */ +"1 1 1 1", +" c None", +/* pixels */ +" " +}; + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* +create_dummy_pixmap (GtkWidget *widget) +{ + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, + NULL, dummy_pixmap_xpm); + if (gdkpixmap == NULL) + g_error ("Couldn't create replacement pixmap."); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *found_filename = NULL; + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + GList *elem; + + if (!filename || !filename[0]) + return create_dummy_pixmap (widget); + + /* We first try any pixmaps directories set by the application. */ + elem = pixmaps_directories; + while (elem) + { + found_filename = check_file_exists ((gchar*)elem->data, filename); + if (found_filename) + break; + elem = elem->next; + } + + /* If we haven't found the pixmap, try the source directory. */ + if (!found_filename) + { + found_filename = check_file_exists ("pixmaps", filename); + } + + if (!found_filename) + { + g_warning ("Couldn't find pixmap file: %s", filename); + return create_dummy_pixmap (widget); + } + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask, + NULL, found_filename); + if (gdkpixmap == NULL) + { + g_warning ("Error loading pixmap file: %s", found_filename); + g_free (found_filename); + return create_dummy_pixmap (widget); + } + g_free (found_filename); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* +check_file_exists (const gchar *directory, + const gchar *filename) +{ + gchar *full_filename; + struct stat s; + gint status; + + full_filename = (gchar*) g_malloc (strlen (directory) + 1 + + strlen (filename) + 1); + strcpy (full_filename, directory); + strcat (full_filename, G_DIR_SEPARATOR_S); + strcat (full_filename, filename); + + status = stat (full_filename, &s); + if (status == 0 && S_ISREG (s.st_mode)) + return full_filename; + g_free (full_filename); + return NULL; +} + diff --git a/plugins/FWnull/Linux/support.h b/plugins/FWnull/Linux/support.h index 886615901b..aee31f935d 100644 --- a/plugins/FWnull/Linux/support.h +++ b/plugins/FWnull/Linux/support.h @@ -1,38 +1,38 @@ -/* - * DO NOT EDIT THIS FILE - it is generated by Glade. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -/* - * Public Functions. - */ - -/* - * This function returns a widget in a component created by Glade. - * Call it with the toplevel widget in the component (i.e. a window/dialog), - * or alternatively any widget in the component, and the name of the widget - * you want returned. - */ -GtkWidget* lookup_widget (GtkWidget *widget, - const gchar *widget_name); - -/* get_widget() is deprecated. Use lookup_widget instead. */ -#define get_widget lookup_widget - -/* Use this function to set the directory containing installed pixmaps. */ -void add_pixmap_directory (const gchar *directory); - - -/* - * Private Functions. - */ - -/* This is used to create the pixmaps in the interface. */ -GtkWidget* create_pixmap (GtkWidget *widget, - const gchar *filename); - +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + +/* get_widget() is deprecated. Use lookup_widget instead. */ +#define get_widget lookup_widget + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + diff --git a/plugins/FWnull/PS2Edefs.h b/plugins/FWnull/PS2Edefs.h index b2f76c96de..34bfdf54f2 100644 --- a/plugins/FWnull/PS2Edefs.h +++ b/plugins/FWnull/PS2Edefs.h @@ -1,848 +1,848 @@ -#ifndef __PS2EDEFS_H__ -#define __PS2EDEFS_H__ - -/* - * PS2E Definitions v0.6.2 (beta) - * - * Author: linuzappz@hotmail.com - * shadowpcsx2@yahoo.gr - * florinsasu@hotmail.com - */ - -/* - Notes: - * Since this is still beta things may change. - - * OSflags: - __LINUX__ (linux OS) - _WIN32 (win32 OS) - - * common return values (for ie. GSinit): - 0 - success - -1 - error - - * reserved keys: - F1 to F10 are reserved for the emulator - - * plugins should NOT change the current - working directory. - (on win32, add flag OFN_NOCHANGEDIR for - GetOpenFileName) - -*/ - -#include "PS2Etypes.h" - -#ifdef __LINUX__ -#define CALLBACK -#else -#include -#endif - - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ - defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ - defined(USBdefs) || defined(FWdefs) -#define COMMONdefs -#endif - -// PS2EgetLibType returns (may be OR'd) -#define PS2E_LT_GS 0x01 -#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- -#define PS2E_LT_SPU2 0x04 -#define PS2E_LT_CDVD 0x08 -#define PS2E_LT_DEV9 0x10 -#define PS2E_LT_USB 0x20 -#define PS2E_LT_FW 0x40 -#define PS2E_LT_SIO 0x80 - -// PS2EgetLibVersion2 (high 16 bits) -#define PS2E_GS_VERSION 0x0006 -#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- -#define PS2E_SPU2_VERSION 0x0005 -#define PS2E_CDVD_VERSION 0x0005 -#define PS2E_DEV9_VERSION 0x0003 -#define PS2E_USB_VERSION 0x0003 -#define PS2E_FW_VERSION 0x0002 -#define PS2E_SIO_VERSION 0x0001 -#ifdef COMMONdefs - -u32 CALLBACK PS2EgetLibType(void); -u32 CALLBACK PS2EgetLibVersion2(u32 type); -char* CALLBACK PS2EgetLibName(void); - -#endif - -// key values: -/* key values must be OS dependant: - win32: the VK_XXX will be used (WinUser) - linux: the XK_XXX will be used (XFree86) -*/ - -// event values: -#define KEYPRESS 1 -#define KEYRELEASE 2 - -typedef struct { - u32 key; - u32 event; -} keyEvent; - -// for 64bit compilers -typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; - -// plugin types -#define SIO_TYPE_PAD 0x00000001 -#define SIO_TYPE_MTAP 0x00000004 -#define SIO_TYPE_RM 0x00000040 -#define SIO_TYPE_MC 0x00000100 - -typedef int (CALLBACK * SIOchangeSlotCB)(int slot); - -typedef struct { - u8 ctrl:4; // control and mode bits - u8 mode:4; // control and mode bits - u8 trackNum; // current track number (1 to 99) - u8 trackIndex; // current index within track (0 to 99) - u8 trackM; // current minute location on the disc (BCD encoded) - u8 trackS; // current sector location on the disc (BCD encoded) - u8 trackF; // current frame location on the disc (BCD encoded) - u8 pad; // unused - u8 discM; // current minute offset from first track (BCD encoded) - u8 discS; // current sector offset from first track (BCD encoded) - u8 discF; // current frame offset from first track (BCD encoded) -} cdvdSubQ; - -typedef struct { // NOT bcd coded - u32 lsn; - u8 type; -} cdvdTD; - -typedef struct { - u8 strack; //number of the first track (usually 1) - u8 etrack; //number of the last track -} cdvdTN; - -// CDVDreadTrack mode values: -#define CDVD_MODE_2352 0 // full 2352 bytes -#define CDVD_MODE_2340 1 // skip sync (12) bytes -#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq - -// CDVDgetDiskType returns: -#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc -#define CDVD_TYPE_DVDV 0xfe // DVD Video -#define CDVD_TYPE_CDDA 0xfd // Audio CD -#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD -#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) -#define CDVD_TYPE_PS2CD 0x12 // PS2 CD -#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) -#define CDVD_TYPE_PSCD 0x10 // PS CD -#define CDVD_TYPE_UNKNOWN 0x05 // Unknown -#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided -#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided -#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd -#define CDVD_TYPE_DETCT 0x01 // Detecting -#define CDVD_TYPE_NODISC 0x00 // No Disc - -// CDVDgetTrayStatus returns: -#define CDVD_TRAY_CLOSE 0x00 -#define CDVD_TRAY_OPEN 0x01 - -// cdvdTD.type (track types for cds) -#define CDVD_AUDIO_TRACK 0x01 -#define CDVD_MODE1_TRACK 0x41 -#define CDVD_MODE2_TRACK 0x61 - -#define CDVD_AUDIO_MASK 0x00 -#define CDVD_DATA_MASK 0x40 -// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) - -typedef void (*DEV9callback)(int cycles); -typedef int (*DEV9handler)(void); - -typedef void (*USBcallback)(int cycles); -typedef int (*USBhandler)(void); - -// freeze modes: -#define FREEZE_LOAD 0 -#define FREEZE_SAVE 1 -#define FREEZE_SIZE 2 - -typedef struct { - char name[8]; - void *common; -} GSdriverInfo; - -#ifdef _WIN32 -typedef struct { // unsupported values must be set to zero - HWND hWnd; - HMENU hMenu; - HWND hStatusWnd; -} winInfo; -#endif - -/* GS plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef GSdefs - -// basic funcs - -s32 CALLBACK GSinit(); -s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); -void CALLBACK GSclose(); -void CALLBACK GSshutdown(); -void CALLBACK GSvsync(int field); -void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); -void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); -void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); -void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) -void CALLBACK GSgifSoftReset(u32 mask); -void CALLBACK GSreadFIFO(u64 *mem); -void CALLBACK GSreadFIFO2(u64 *mem, int qwc); - -// extended funcs - -// GSkeyEvent gets called when there is a keyEvent from the PAD plugin -void CALLBACK GSkeyEvent(keyEvent *ev); -void CALLBACK GSchangeSaveState(int, const char* filename); -void CALLBACK GSmakeSnapshot(char *path); -void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); -void CALLBACK GSirqCallback(void (*callback)()); -void CALLBACK GSprintf(int timeout, char *fmt, ...); -void CALLBACK GSsetBaseMem(void*); -void CALLBACK GSsetGameCRC(int crc, int gameoptions); - -// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done -void CALLBACK GSsetFrameSkip(int frameskip); - -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK GSsetupRecording(int start, void* pData); - -void CALLBACK GSreset(); -void CALLBACK GSwriteCSR(u32 value); -void CALLBACK GSgetDriverInfo(GSdriverInfo *info); -#ifdef _WIN32 -s32 CALLBACK GSsetWindowInfo(winInfo *info); -#endif -s32 CALLBACK GSfreeze(int mode, freezeData *data); -void CALLBACK GSconfigure(); -void CALLBACK GSabout(); -s32 CALLBACK GStest(); - -#endif - -/* PAD plugin API -=[ OBSOLETE ]=- */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef PADdefs - -// basic funcs - -s32 CALLBACK PADinit(u32 flags); -s32 CALLBACK PADopen(void *pDsp); -void CALLBACK PADclose(); -void CALLBACK PADshutdown(); -// PADkeyEvent is called every vsync (return NULL if no event) -keyEvent* CALLBACK PADkeyEvent(); -u8 CALLBACK PADstartPoll(int pad); -u8 CALLBACK PADpoll(u8 value); -// returns: 1 if supported pad1 -// 2 if supported pad2 -// 3 if both are supported -u32 CALLBACK PADquery(); - -// call to give a hint to the PAD plugin to query for the keyboard state. A -// good plugin will query the OS for keyboard state ONLY in this function. -// This function is necessary when multithreading because otherwise -// the PAD plugin can get into deadlocks with the thread that really owns -// the window (and input). Note that PADupdate can be called from a different -// thread than the other functions, so mutex or other multithreading primitives -// have to be added to maintain data integrity. -void CALLBACK PADupdate(int pad); - -// extended funcs - -void CALLBACK PADgsDriverInfo(GSdriverInfo *info); -void CALLBACK PADconfigure(); -void CALLBACK PADabout(); -s32 CALLBACK PADtest(); - -#endif - -/* SIO plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SIOdefs - -// basic funcs - -s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); -s32 CALLBACK SIOopen(void *pDsp); -void CALLBACK SIOclose(); -void CALLBACK SIOshutdown(); -u8 CALLBACK SIOstartPoll(u8 value); -u8 CALLBACK SIOpoll(u8 value); -// returns: SIO_TYPE_{PAD,MTAP,RM,MC} -u32 CALLBACK SIOquery(); - -// extended funcs - -void CALLBACK SIOconfigure(); -void CALLBACK SIOabout(); -s32 CALLBACK SIOtest(); - -#endif - -/* SPU2 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SPU2defs - -// basic funcs - -s32 CALLBACK SPU2init(); -s32 CALLBACK SPU2open(void *pDsp); -void CALLBACK SPU2close(); -void CALLBACK SPU2shutdown(); -void CALLBACK SPU2write(u32 mem, u16 value); -u16 CALLBACK SPU2read(u32 mem); -void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA4(); -void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); -void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); - -// all addresses passed by dma will be pointers to the array starting at baseaddr -// This function is necessary to successfully save and reload the spu2 state -void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); - -void CALLBACK SPU2interruptDMA7(); -u32 CALLBACK SPU2ReadMemAddr(int core); -void CALLBACK SPU2WriteMemAddr(int core,u32 value); -void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); - -// extended funcs -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK SPU2setupRecording(int start, void* pData); - -void CALLBACK SPU2async(u32 cycles); -s32 CALLBACK SPU2freeze(int mode, freezeData *data); -void CALLBACK SPU2configure(); -void CALLBACK SPU2about(); -s32 CALLBACK SPU2test(); - -#endif - -/* CDVD plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef CDVDdefs - -// basic funcs - -s32 CALLBACK CDVDinit(); -s32 CALLBACK CDVDopen(const char* pTitleFilename); -void CALLBACK CDVDclose(); -void CALLBACK CDVDshutdown(); -s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); - -// return can be NULL (for async modes) -u8* CALLBACK CDVDgetBuffer(); - -s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) -s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information -s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type -s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc -s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx -s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx -s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray -s32 CALLBACK CDVDctrlTrayClose(); //close disc tray - -// extended funcs - -void CALLBACK CDVDconfigure(); -void CALLBACK CDVDabout(); -s32 CALLBACK CDVDtest(); -void CALLBACK CDVDnewDiskCB(void (*callback)()); - -#endif - -/* DEV9 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef DEV9defs - -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK DEV9init(); -s32 CALLBACK DEV9open(void *pDsp); -void CALLBACK DEV9close(); -void CALLBACK DEV9shutdown(); -u8 CALLBACK DEV9read8(u32 addr); -u16 CALLBACK DEV9read16(u32 addr); -u32 CALLBACK DEV9read32(u32 addr); -void CALLBACK DEV9write8(u32 addr, u8 value); -void CALLBACK DEV9write16(u32 addr, u16 value); -void CALLBACK DEV9write32(u32 addr, u32 value); -void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); -void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK DEV9irqCallback(DEV9callback callback); -DEV9handler CALLBACK DEV9irqHandler(void); - -// extended funcs - -s32 CALLBACK DEV9freeze(int mode, freezeData *data); -void CALLBACK DEV9configure(); -void CALLBACK DEV9about(); -s32 CALLBACK DEV9test(); - -#endif - -/* USB plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef USBdefs - -// basic funcs - -s32 CALLBACK USBinit(); -s32 CALLBACK USBopen(void *pDsp); -void CALLBACK USBclose(); -void CALLBACK USBshutdown(); -u8 CALLBACK USBread8(u32 addr); -u16 CALLBACK USBread16(u32 addr); -u32 CALLBACK USBread32(u32 addr); -void CALLBACK USBwrite8(u32 addr, u8 value); -void CALLBACK USBwrite16(u32 addr, u16 value); -void CALLBACK USBwrite32(u32 addr, u32 value); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK USBirqCallback(USBcallback callback); -USBhandler CALLBACK USBirqHandler(void); -void CALLBACK USBsetRAM(void *mem); - -// extended funcs - -s32 CALLBACK USBfreeze(int mode, freezeData *data); -void CALLBACK USBconfigure(); -void CALLBACK USBabout(); -s32 CALLBACK USBtest(); - -#endif - -/* FW plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef FWdefs -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK FWinit(); -s32 CALLBACK FWopen(void *pDsp); -void CALLBACK FWclose(); -void CALLBACK FWshutdown(); -u32 CALLBACK FWread32(u32 addr); -void CALLBACK FWwrite32(u32 addr, u32 value); -void CALLBACK FWirqCallback(void (*callback)()); - -// extended funcs - -s32 CALLBACK FWfreeze(int mode, freezeData *data); -void CALLBACK FWconfigure(); -void CALLBACK FWabout(); -s32 CALLBACK FWtest(); -#endif - -// might be useful for emulators -#ifdef PLUGINtypedefs - -typedef u32 (CALLBACK* _PS2EgetLibType)(void); -typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); -typedef char*(CALLBACK* _PS2EgetLibName)(void); - -// GS -// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _GSinit)(); -typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); -typedef void (CALLBACK* _GSclose)(); -typedef void (CALLBACK* _GSshutdown)(); -typedef void (CALLBACK* _GSvsync)(int field); -typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); -typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) -typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); -typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); -typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); - -typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); -typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); -typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); -typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); -typedef void (CALLBACK* _GSsetBaseMem)(void*); -typedef void (CALLBACK* _GSsetGameCRC)(int, int); -typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); -typedef int (CALLBACK* _GSsetupRecording)(int, void*); -typedef void (CALLBACK* _GSreset)(); -typedef void (CALLBACK* _GSwriteCSR)(u32 value); -typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); -#ifdef _WIN32 -typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); -#endif -typedef void (CALLBACK* _GSmakeSnapshot)(char *path); -typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); -typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _GSconfigure)(); -typedef s32 (CALLBACK* _GStest)(); -typedef void (CALLBACK* _GSabout)(); - -// PAD -typedef s32 (CALLBACK* _PADinit)(u32 flags); -typedef s32 (CALLBACK* _PADopen)(void *pDsp); -typedef void (CALLBACK* _PADclose)(); -typedef void (CALLBACK* _PADshutdown)(); -typedef keyEvent* (CALLBACK* _PADkeyEvent)(); -typedef u8 (CALLBACK* _PADstartPoll)(int pad); -typedef u8 (CALLBACK* _PADpoll)(u8 value); -typedef u32 (CALLBACK* _PADquery)(); -typedef void (CALLBACK* _PADupdate)(int pad); - -typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); -typedef void (CALLBACK* _PADconfigure)(); -typedef s32 (CALLBACK* _PADtest)(); -typedef void (CALLBACK* _PADabout)(); - -// SIO -typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); -typedef s32 (CALLBACK* _SIOopen)(void *pDsp); -typedef void (CALLBACK* _SIOclose)(); -typedef void (CALLBACK* _SIOshutdown)(); -typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); -typedef u8 (CALLBACK* _SIOpoll)(u8 value); -typedef u32 (CALLBACK* _SIOquery)(); - -typedef void (CALLBACK* _SIOconfigure)(); -typedef s32 (CALLBACK* _SIOtest)(); -typedef void (CALLBACK* _SIOabout)(); - -// SPU2 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _SPU2init)(); -typedef s32 (CALLBACK* _SPU2open)(void *pDsp); -typedef void (CALLBACK* _SPU2close)(); -typedef void (CALLBACK* _SPU2shutdown)(); -typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); -typedef u16 (CALLBACK* _SPU2read)(u32 mem); -typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA4)(); -typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); -typedef void (CALLBACK* _SPU2interruptDMA7)(); -typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); -typedef int (CALLBACK* _SPU2setupRecording)(int, void*); -typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); -typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); -typedef void (CALLBACK* _SPU2async)(u32 cycles); -typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _SPU2configure)(); -typedef s32 (CALLBACK* _SPU2test)(); -typedef void (CALLBACK* _SPU2about)(); - -// CDVD -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _CDVDinit)(); -typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); -typedef void (CALLBACK* _CDVDclose)(); -typedef void (CALLBACK* _CDVDshutdown)(); -typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); -typedef u8* (CALLBACK* _CDVDgetBuffer)(); -typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); -typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); -typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); -typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); -typedef s32 (CALLBACK* _CDVDgetDiskType)(); -typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); -typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); -typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); - -typedef void (CALLBACK* _CDVDconfigure)(); -typedef s32 (CALLBACK* _CDVDtest)(); -typedef void (CALLBACK* _CDVDabout)(); -typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); - -// DEV9 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _DEV9init)(); -typedef s32 (CALLBACK* _DEV9open)(void *pDsp); -typedef void (CALLBACK* _DEV9close)(); -typedef void (CALLBACK* _DEV9shutdown)(); -typedef u8 (CALLBACK* _DEV9read8)(u32 mem); -typedef u16 (CALLBACK* _DEV9read16)(u32 mem); -typedef u32 (CALLBACK* _DEV9read32)(u32 mem); -typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); -typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); -typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); -typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); -typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); - -typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _DEV9configure)(); -typedef s32 (CALLBACK* _DEV9test)(); -typedef void (CALLBACK* _DEV9about)(); - -// USB -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _USBinit)(); -typedef s32 (CALLBACK* _USBopen)(void *pDsp); -typedef void (CALLBACK* _USBclose)(); -typedef void (CALLBACK* _USBshutdown)(); -typedef u8 (CALLBACK* _USBread8)(u32 mem); -typedef u16 (CALLBACK* _USBread16)(u32 mem); -typedef u32 (CALLBACK* _USBread32)(u32 mem); -typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); -typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); -typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); -typedef USBhandler (CALLBACK* _USBirqHandler)(void); -typedef void (CALLBACK* _USBsetRAM)(void *mem); - -typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _USBconfigure)(); -typedef s32 (CALLBACK* _USBtest)(); -typedef void (CALLBACK* _USBabout)(); - -//FW -typedef s32 (CALLBACK* _FWinit)(); -typedef s32 (CALLBACK* _FWopen)(void *pDsp); -typedef void (CALLBACK* _FWclose)(); -typedef void (CALLBACK* _FWshutdown)(); -typedef u32 (CALLBACK* _FWread32)(u32 mem); -typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); - -typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _FWconfigure)(); -typedef s32 (CALLBACK* _FWtest)(); -typedef void (CALLBACK* _FWabout)(); - -#endif - -#ifdef PLUGINfuncs - -// GS -_GSinit GSinit; -_GSopen GSopen; -_GSclose GSclose; -_GSshutdown GSshutdown; -_GSvsync GSvsync; -_GSgifTransfer1 GSgifTransfer1; -_GSgifTransfer2 GSgifTransfer2; -_GSgifTransfer3 GSgifTransfer3; -_GSgetLastTag GSgetLastTag; -_GSgifSoftReset GSgifSoftReset; -_GSreadFIFO GSreadFIFO; -_GSreadFIFO2 GSreadFIFO2; - -_GSkeyEvent GSkeyEvent; -_GSchangeSaveState GSchangeSaveState; -_GSmakeSnapshot GSmakeSnapshot; -_GSmakeSnapshot2 GSmakeSnapshot2; -_GSirqCallback GSirqCallback; -_GSprintf GSprintf; -_GSsetBaseMem GSsetBaseMem; -_GSsetGameCRC GSsetGameCRC; -_GSsetFrameSkip GSsetFrameSkip; -_GSsetupRecording GSsetupRecording; -_GSreset GSreset; -_GSwriteCSR GSwriteCSR; -_GSgetDriverInfo GSgetDriverInfo; -#ifdef _WIN32 -_GSsetWindowInfo GSsetWindowInfo; -#endif -_GSfreeze GSfreeze; -_GSconfigure GSconfigure; -_GStest GStest; -_GSabout GSabout; - -// PAD1 -_PADinit PAD1init; -_PADopen PAD1open; -_PADclose PAD1close; -_PADshutdown PAD1shutdown; -_PADkeyEvent PAD1keyEvent; -_PADstartPoll PAD1startPoll; -_PADpoll PAD1poll; -_PADquery PAD1query; -_PADupdate PAD1update; - -_PADgsDriverInfo PAD1gsDriverInfo; -_PADconfigure PAD1configure; -_PADtest PAD1test; -_PADabout PAD1about; - -// PAD2 -_PADinit PAD2init; -_PADopen PAD2open; -_PADclose PAD2close; -_PADshutdown PAD2shutdown; -_PADkeyEvent PAD2keyEvent; -_PADstartPoll PAD2startPoll; -_PADpoll PAD2poll; -_PADquery PAD2query; -_PADupdate PAD2update; - -_PADgsDriverInfo PAD2gsDriverInfo; -_PADconfigure PAD2configure; -_PADtest PAD2test; -_PADabout PAD2about; - -// SIO[2] -_SIOinit SIOinit[2][9]; -_SIOopen SIOopen[2][9]; -_SIOclose SIOclose[2][9]; -_SIOshutdown SIOshutdown[2][9]; -_SIOstartPoll SIOstartPoll[2][9]; -_SIOpoll SIOpoll[2][9]; -_SIOquery SIOquery[2][9]; - -_SIOconfigure SIOconfigure[2][9]; -_SIOtest SIOtest[2][9]; -_SIOabout SIOabout[2][9]; - -// SPU2 -_SPU2init SPU2init; -_SPU2open SPU2open; -_SPU2close SPU2close; -_SPU2shutdown SPU2shutdown; -_SPU2write SPU2write; -_SPU2read SPU2read; -_SPU2readDMA4Mem SPU2readDMA4Mem; -_SPU2writeDMA4Mem SPU2writeDMA4Mem; -_SPU2interruptDMA4 SPU2interruptDMA4; -_SPU2readDMA7Mem SPU2readDMA7Mem; -_SPU2writeDMA7Mem SPU2writeDMA7Mem; -_SPU2setDMABaseAddr SPU2setDMABaseAddr; -_SPU2interruptDMA7 SPU2interruptDMA7; -_SPU2ReadMemAddr SPU2ReadMemAddr; -_SPU2setupRecording SPU2setupRecording; -_SPU2WriteMemAddr SPU2WriteMemAddr; -_SPU2irqCallback SPU2irqCallback; - -_SPU2async SPU2async; -_SPU2freeze SPU2freeze; -_SPU2configure SPU2configure; -_SPU2test SPU2test; -_SPU2about SPU2about; - -// CDVD -_CDVDinit CDVDinit; -_CDVDopen CDVDopen; -_CDVDclose CDVDclose; -_CDVDshutdown CDVDshutdown; -_CDVDreadTrack CDVDreadTrack; -_CDVDgetBuffer CDVDgetBuffer; -_CDVDreadSubQ CDVDreadSubQ; -_CDVDgetTN CDVDgetTN; -_CDVDgetTD CDVDgetTD; -_CDVDgetTOC CDVDgetTOC; -_CDVDgetDiskType CDVDgetDiskType; -_CDVDgetTrayStatus CDVDgetTrayStatus; -_CDVDctrlTrayOpen CDVDctrlTrayOpen; -_CDVDctrlTrayClose CDVDctrlTrayClose; - -_CDVDconfigure CDVDconfigure; -_CDVDtest CDVDtest; -_CDVDabout CDVDabout; -_CDVDnewDiskCB CDVDnewDiskCB; - -// DEV9 -_DEV9init DEV9init; -_DEV9open DEV9open; -_DEV9close DEV9close; -_DEV9shutdown DEV9shutdown; -_DEV9read8 DEV9read8; -_DEV9read16 DEV9read16; -_DEV9read32 DEV9read32; -_DEV9write8 DEV9write8; -_DEV9write16 DEV9write16; -_DEV9write32 DEV9write32; -_DEV9readDMA8Mem DEV9readDMA8Mem; -_DEV9writeDMA8Mem DEV9writeDMA8Mem; -_DEV9irqCallback DEV9irqCallback; -_DEV9irqHandler DEV9irqHandler; - -_DEV9configure DEV9configure; -_DEV9freeze DEV9freeze; -_DEV9test DEV9test; -_DEV9about DEV9about; - -// USB -_USBinit USBinit; -_USBopen USBopen; -_USBclose USBclose; -_USBshutdown USBshutdown; -_USBread8 USBread8; -_USBread16 USBread16; -_USBread32 USBread32; -_USBwrite8 USBwrite8; -_USBwrite16 USBwrite16; -_USBwrite32 USBwrite32; -_USBirqCallback USBirqCallback; -_USBirqHandler USBirqHandler; -_USBsetRAM USBsetRAM; - -_USBconfigure USBconfigure; -_USBfreeze USBfreeze; -_USBtest USBtest; -_USBabout USBabout; - -// FW -_FWinit FWinit; -_FWopen FWopen; -_FWclose FWclose; -_FWshutdown FWshutdown; -_FWread32 FWread32; -_FWwrite32 FWwrite32; -_FWirqCallback FWirqCallback; - -_FWconfigure FWconfigure; -_FWfreeze FWfreeze; -_FWtest FWtest; -_FWabout FWabout; -#endif - -#endif /* __PS2EDEFS_H__ */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgetLastTag GSgetLastTag; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSsetupRecording GSsetupRecording; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; +_PADupdate PAD1update; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; +_PADupdate PAD2update; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2setDMABaseAddr SPU2setDMABaseAddr; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2setupRecording SPU2setupRecording; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/FWnull/Win32/Config.c b/plugins/FWnull/Win32/Config.c index d1b14598aa..4090db202c 100644 --- a/plugins/FWnull/Win32/Config.c +++ b/plugins/FWnull/Win32/Config.c @@ -1,51 +1,51 @@ -#include - -#include "FW.h" - -extern HINSTANCE hInst; -void SaveConfig() -{ - - Config *Conf1 = &conf; - char *szTemp; - char szIniFile[256], szValue[256]; - - GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); - szTemp = strrchr(szIniFile, '\\'); - - if(!szTemp) return; - strcpy(szTemp, "\\inis\\fwnull.ini"); - sprintf(szValue,"%u",Conf1->Log); - WritePrivateProfileString("Interface", "Logging",szValue,szIniFile); - -} - -void LoadConfig() { - FILE *fp; - - - Config *Conf1 = &conf; - char *szTemp; - char szIniFile[256], szValue[256]; - - GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); - szTemp = strrchr(szIniFile, '\\'); - - if(!szTemp) return ; - strcpy(szTemp, "\\inis\\fwnull.ini"); - fp=fopen("inis\\fwnull.ini","rt");//check if firewirenull.ini really exists - if (!fp) - { - CreateDirectory("inis",NULL); - memset(&conf, 0, sizeof(conf)); - conf.Log = 0;//default value - SaveConfig();//save and return - return ; - } - fclose(fp); - GetPrivateProfileString("Interface", "Logging", NULL, szValue, 20, szIniFile); - Conf1->Log = strtoul(szValue, NULL, 10); - return ; - -} - +#include + +#include "FW.h" + +extern HINSTANCE hInst; +void SaveConfig() +{ + + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\fwnull.ini"); + sprintf(szValue,"%u",Conf1->Log); + WritePrivateProfileString("Interface", "Logging",szValue,szIniFile); + +} + +void LoadConfig() { + FILE *fp; + + + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return ; + strcpy(szTemp, "\\inis\\fwnull.ini"); + fp=fopen("inis\\fwnull.ini","rt");//check if firewirenull.ini really exists + if (!fp) + { + CreateDirectory("inis",NULL); + memset(&conf, 0, sizeof(conf)); + conf.Log = 0;//default value + SaveConfig();//save and return + return ; + } + fclose(fp); + GetPrivateProfileString("Interface", "Logging", NULL, szValue, 20, szIniFile); + Conf1->Log = strtoul(szValue, NULL, 10); + return ; + +} + diff --git a/plugins/FWnull/Win32/Makefile b/plugins/FWnull/Win32/Makefile index 82afda1120..afa9da3337 100644 --- a/plugins/FWnull/Win32/Makefile +++ b/plugins/FWnull/Win32/Makefile @@ -1,29 +1,29 @@ - -RC = windres -STRIP = strip - -PLUGIN = FWnull.dll -CFLAGS = -Wall -O2 -fomit-frame-pointer -I.. -D__WIN32__ -D__MINGW32__ -LIBS = -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 -RESOBJ = FireWireNull.o -OBJS = ../FW.o Config.o Win32.o ${RESOBJ} - -DEPS:= $(OBJS:.o=.d) - -all: plugin - -plugin: ${OBJS} - dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} ${LIBS} -# ${CC} -shared -Wl,--kill-at,--output-def,plugin.def ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} - ${STRIP} ${PLUGIN} - -.PHONY: clear plugin - -clean: - rm -f ${OBJS} ${DEPS} ${PLUGIN} - -${RESOBJ}: FireWireNull.rc - ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< - --include ${DEPS} - + +RC = windres +STRIP = strip + +PLUGIN = FWnull.dll +CFLAGS = -Wall -O2 -fomit-frame-pointer -I.. -D__WIN32__ -D__MINGW32__ +LIBS = -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 +RESOBJ = FireWireNull.o +OBJS = ../FW.o Config.o Win32.o ${RESOBJ} + +DEPS:= $(OBJS:.o=.d) + +all: plugin + +plugin: ${OBJS} + dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} ${LIBS} +# ${CC} -shared -Wl,--kill-at,--output-def,plugin.def ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + ${STRIP} ${PLUGIN} + +.PHONY: clear plugin + +clean: + rm -f ${OBJS} ${DEPS} ${PLUGIN} + +${RESOBJ}: FireWireNull.rc + ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< + +-include ${DEPS} + diff --git a/plugins/FWnull/Win32/Win32.c b/plugins/FWnull/Win32/Win32.c index 205bb8fac9..b3815ed22f 100644 --- a/plugins/FWnull/Win32/Win32.c +++ b/plugins/FWnull/Win32/Win32.c @@ -1,81 +1,81 @@ -#include -#include -#include - - -#include "resource.h" -#include "FW.h" - -HINSTANCE hInst; - -void SysMessage(char *fmt, ...) { - va_list list; - char tmp[512]; - - va_start(list,fmt); - vsprintf(tmp,fmt,list); - va_end(list); - MessageBox(0, tmp, "FW Plugin Msg", 0); -} - -BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { - - switch(uMsg) { - case WM_INITDIALOG: - LoadConfig(); - if (conf.Log) CheckDlgButton(hW, IDC_LOGGING, TRUE); - return TRUE; - - case WM_COMMAND: - switch(LOWORD(wParam)) { - case IDCANCEL: - EndDialog(hW, TRUE); - return TRUE; - case IDOK: - if (IsDlgButtonChecked(hW, IDC_LOGGING)) - conf.Log = 1; - else conf.Log = 0; - SaveConfig(); - EndDialog(hW, FALSE); - return TRUE; - } - } - return FALSE; -} - -BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { - switch(uMsg) { - case WM_INITDIALOG: - return TRUE; - - case WM_COMMAND: - switch(LOWORD(wParam)) { - case IDOK: - EndDialog(hW, FALSE); - return TRUE; - } - } - return FALSE; -} - -void CALLBACK FWconfigure() { - DialogBox(hInst, - MAKEINTRESOURCE(IDD_CONFIG), - GetActiveWindow(), - (DLGPROC)ConfigureDlgProc); -} - -void CALLBACK FWabout() { - DialogBox(hInst, - MAKEINTRESOURCE(IDD_ABOUT), - GetActiveWindow(), - (DLGPROC)AboutDlgProc); -} - -BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT - DWORD dwReason, - LPVOID lpReserved) { - hInst = (HINSTANCE)hModule; - return TRUE; // very quick :) -} - +#include +#include +#include + + +#include "resource.h" +#include "FW.h" + +HINSTANCE hInst; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "FW Plugin Msg", 0); +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + + switch(uMsg) { + case WM_INITDIALOG: + LoadConfig(); + if (conf.Log) CheckDlgButton(hW, IDC_LOGGING, TRUE); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + case IDOK: + if (IsDlgButtonChecked(hW, IDC_LOGGING)) + conf.Log = 1; + else conf.Log = 0; + SaveConfig(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +void CALLBACK FWconfigure() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); +} + +void CALLBACK FWabout() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc); +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + diff --git a/plugins/FWnull/Win32/afxresmw.h b/plugins/FWnull/Win32/afxresmw.h index 8a4b9df35b..99eace37c4 100644 --- a/plugins/FWnull/Win32/afxresmw.h +++ b/plugins/FWnull/Win32/afxresmw.h @@ -1,5 +1,5 @@ - -#include -#include - -#define IDC_STATIC (-1) + +#include +#include + +#define IDC_STATIC (-1) diff --git a/plugins/FWnull/Win32/resource.h b/plugins/FWnull/Win32/resource.h index f8ab2765f1..6ea8fead11 100644 --- a/plugins/FWnull/Win32/resource.h +++ b/plugins/FWnull/Win32/resource.h @@ -1,21 +1,21 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by FireWireNull.rc -// -#define IDD_CONFDLG 101 -#define IDD_CONFIG 101 -#define IDD_ABOUT 103 -#define IDC_NAME 1000 -#define IDC_CHECK1 1007 -#define IDC_LOGGING 1007 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 105 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1008 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by FireWireNull.rc +// +#define IDD_CONFDLG 101 +#define IDD_CONFIG 101 +#define IDD_ABOUT 103 +#define IDC_NAME 1000 +#define IDC_CHECK1 1007 +#define IDC_LOGGING 1007 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1008 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/GSdx/GPU.cpp b/plugins/GSdx/GPU.cpp index 8b13096eb6..d9ea74a71c 100644 --- a/plugins/GSdx/GPU.cpp +++ b/plugins/GSdx/GPU.cpp @@ -1,306 +1,306 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GSUtil.h" -#include "GPURendererSW.h" -#include "GSDevice7.h" -#include "GSDevice9.h" -#include "GSDevice10.h" -#include "GPUSettingsDlg.h" - -#define PSE_LT_GPU 2 - -static HRESULT s_hr = E_FAIL; -static GPURendererBase* s_gpu = NULL; - -EXPORT_C_(UINT32) PSEgetLibType() -{ - return PSE_LT_GPU; -} - -EXPORT_C_(char*) PSEgetLibName() -{ - return GSUtil::GetLibName(); -} - -EXPORT_C_(UINT32) PSEgetLibVersion() -{ - static const UINT32 version = 1; - static const UINT32 revision = 1; - - return version << 16 | revision << 8 | PLUGIN_VERSION; -} - -EXPORT_C_(INT32) GPUinit() -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - // TODO - - return 0; -} - -EXPORT_C_(INT32) GPUshutdown() -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - // TODO - - return 0; -} - -EXPORT_C_(INT32) GPUclose() -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - delete s_gpu; - - s_gpu = NULL; - - if(SUCCEEDED(s_hr)) - { - ::CoUninitialize(); - - s_hr = E_FAIL; - } - - return 0; -} - -EXPORT_C_(INT32) GPUopen(HWND hWnd) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - if(!GSUtil::CheckDirectX() || !GSUtil::CheckSSE()) - { - return -1; - } - - GPUclose(); - - GPURendererSettings rs; - - rs.m_filter = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("filter"), 0); - rs.m_dither = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("dithering"), 1); - rs.m_aspectratio = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("AspectRatio"), 1); - rs.m_vsync = !!AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("vsync"), FALSE); - rs.m_scale.cx = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("scale_x"), 0); - rs.m_scale.cy = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("scale_y"), 0); - - int threads = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("swthreads"), 1); - - int renderer = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("Renderer"), 1); - - switch(renderer) - { - default: - case 0: s_gpu = new GPURendererSW(rs, threads); break; - case 1: s_gpu = new GPURendererSW(rs, threads); break; - case 2: s_gpu = new GPURendererSW(rs, threads); break; - // TODO: case 3: s_gpu = new GPURendererNull(rs, threads); break; - } - - s_hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED); - - if(!s_gpu->Create(hWnd)) - { - GPUclose(); - - return -1; - } - - return 0; -} - -EXPORT_C_(INT32) GPUconfigure() -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - GPUSettingsDlg dlg; - - if(IDOK == dlg.DoModal()) - { - GPUshutdown(); - GPUinit(); - } - - return 0; -} - -EXPORT_C_(INT32) GPUtest() -{ - // TODO - - return 0; -} - -EXPORT_C GPUabout() -{ - // TODO -} - -EXPORT_C GPUwriteDataMem(const BYTE* mem, UINT32 size) -{ - s_gpu->WriteData(mem, size); -} - -EXPORT_C GPUwriteData(UINT32 data) -{ - s_gpu->WriteData((BYTE*)&data, 1); -} - -EXPORT_C GPUreadDataMem(BYTE* mem, UINT32 size) -{ - s_gpu->ReadData(mem, size); -} - -EXPORT_C_(UINT32) GPUreadData() -{ - UINT32 data = 0; - - s_gpu->ReadData((BYTE*)&data, 1); - - return data; -} - -EXPORT_C GPUwriteStatus(UINT32 status) -{ - s_gpu->WriteStatus(status); -} - -EXPORT_C_(UINT32) GPUreadStatus() -{ - return s_gpu->ReadStatus(); -} - -EXPORT_C_(UINT32) GPUdmaChain(const BYTE* mem, UINT32 addr) -{ - // TODO - - UINT32 last[3]; - - memset(last, 0xff, sizeof(last)); - - do - { - if(addr == last[1] || addr == last[2]) break; - (addr < last[0] ? last[1] : last[2]) = addr; - last[0] = addr; - - BYTE size = mem[addr + 3]; - - if(size > 0) - { - s_gpu->WriteData(&mem[addr + 4], size); - } - - addr = *(UINT32*)&mem[addr] & 0xffffff; - } - while(addr != 0xffffff); - - return 0; -} - -EXPORT_C_(UINT32) GPUgetMode() -{ - // TODO - - return 0; -} - -EXPORT_C GPUsetMode(UINT32) -{ - // TODO -} - -EXPORT_C GPUupdateLace() -{ - s_gpu->VSync(); -} - -EXPORT_C GPUmakeSnapshot() -{ - LPCTSTR path = _T("C:\\"); // TODO - - s_gpu->MakeSnapshot(path); -} - -EXPORT_C GPUdisplayText(char* text) -{ - // TODO -} - -EXPORT_C GPUdisplayFlags(UINT32 flags) -{ - // TODO -} - -EXPORT_C_(INT32) GPUfreeze(UINT32 type, GPUFreezeData* data) -{ - if(!data || data->version != 1) - { - return 0; - } - - if(type == 0) - { - s_gpu->Defrost(data); - - return 1; - } - else if(type == 1) - { - s_gpu->Freeze(data); - - return 1; - } - else if(type == 2) - { - int slot = *(int*)data + 1; - - if(slot < 1 || slot > 9) - { - return 0; - } - - // TODO - - return 1; - } - - return 0; -} - -EXPORT_C GPUgetScreenPic(BYTE* mem) -{ - // TODO -} - -EXPORT_C GPUshowScreenPic(BYTE* mem) -{ - // TODO -} - -EXPORT_C GPUcursor(int player, int x, int y) -{ - // TODO +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSUtil.h" +#include "GPURendererSW.h" +#include "GSDevice7.h" +#include "GSDevice9.h" +#include "GSDevice10.h" +#include "GPUSettingsDlg.h" + +#define PSE_LT_GPU 2 + +static HRESULT s_hr = E_FAIL; +static GPURendererBase* s_gpu = NULL; + +EXPORT_C_(UINT32) PSEgetLibType() +{ + return PSE_LT_GPU; +} + +EXPORT_C_(char*) PSEgetLibName() +{ + return GSUtil::GetLibName(); +} + +EXPORT_C_(UINT32) PSEgetLibVersion() +{ + static const UINT32 version = 1; + static const UINT32 revision = 1; + + return version << 16 | revision << 8 | PLUGIN_VERSION; +} + +EXPORT_C_(INT32) GPUinit() +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + // TODO + + return 0; +} + +EXPORT_C_(INT32) GPUshutdown() +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + // TODO + + return 0; +} + +EXPORT_C_(INT32) GPUclose() +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + delete s_gpu; + + s_gpu = NULL; + + if(SUCCEEDED(s_hr)) + { + ::CoUninitialize(); + + s_hr = E_FAIL; + } + + return 0; +} + +EXPORT_C_(INT32) GPUopen(HWND hWnd) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + if(!GSUtil::CheckDirectX() || !GSUtil::CheckSSE()) + { + return -1; + } + + GPUclose(); + + GPURendererSettings rs; + + rs.m_filter = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("filter"), 0); + rs.m_dither = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("dithering"), 1); + rs.m_aspectratio = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("AspectRatio"), 1); + rs.m_vsync = !!AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("vsync"), FALSE); + rs.m_scale.cx = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("scale_x"), 0); + rs.m_scale.cy = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("scale_y"), 0); + + int threads = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("swthreads"), 1); + + int renderer = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("Renderer"), 1); + + switch(renderer) + { + default: + case 0: s_gpu = new GPURendererSW(rs, threads); break; + case 1: s_gpu = new GPURendererSW(rs, threads); break; + case 2: s_gpu = new GPURendererSW(rs, threads); break; + // TODO: case 3: s_gpu = new GPURendererNull(rs, threads); break; + } + + s_hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED); + + if(!s_gpu->Create(hWnd)) + { + GPUclose(); + + return -1; + } + + return 0; +} + +EXPORT_C_(INT32) GPUconfigure() +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + GPUSettingsDlg dlg; + + if(IDOK == dlg.DoModal()) + { + GPUshutdown(); + GPUinit(); + } + + return 0; +} + +EXPORT_C_(INT32) GPUtest() +{ + // TODO + + return 0; +} + +EXPORT_C GPUabout() +{ + // TODO +} + +EXPORT_C GPUwriteDataMem(const BYTE* mem, UINT32 size) +{ + s_gpu->WriteData(mem, size); +} + +EXPORT_C GPUwriteData(UINT32 data) +{ + s_gpu->WriteData((BYTE*)&data, 1); +} + +EXPORT_C GPUreadDataMem(BYTE* mem, UINT32 size) +{ + s_gpu->ReadData(mem, size); +} + +EXPORT_C_(UINT32) GPUreadData() +{ + UINT32 data = 0; + + s_gpu->ReadData((BYTE*)&data, 1); + + return data; +} + +EXPORT_C GPUwriteStatus(UINT32 status) +{ + s_gpu->WriteStatus(status); +} + +EXPORT_C_(UINT32) GPUreadStatus() +{ + return s_gpu->ReadStatus(); +} + +EXPORT_C_(UINT32) GPUdmaChain(const BYTE* mem, UINT32 addr) +{ + // TODO + + UINT32 last[3]; + + memset(last, 0xff, sizeof(last)); + + do + { + if(addr == last[1] || addr == last[2]) break; + (addr < last[0] ? last[1] : last[2]) = addr; + last[0] = addr; + + BYTE size = mem[addr + 3]; + + if(size > 0) + { + s_gpu->WriteData(&mem[addr + 4], size); + } + + addr = *(UINT32*)&mem[addr] & 0xffffff; + } + while(addr != 0xffffff); + + return 0; +} + +EXPORT_C_(UINT32) GPUgetMode() +{ + // TODO + + return 0; +} + +EXPORT_C GPUsetMode(UINT32) +{ + // TODO +} + +EXPORT_C GPUupdateLace() +{ + s_gpu->VSync(); +} + +EXPORT_C GPUmakeSnapshot() +{ + LPCTSTR path = _T("C:\\"); // TODO + + s_gpu->MakeSnapshot(path); +} + +EXPORT_C GPUdisplayText(char* text) +{ + // TODO +} + +EXPORT_C GPUdisplayFlags(UINT32 flags) +{ + // TODO +} + +EXPORT_C_(INT32) GPUfreeze(UINT32 type, GPUFreezeData* data) +{ + if(!data || data->version != 1) + { + return 0; + } + + if(type == 0) + { + s_gpu->Defrost(data); + + return 1; + } + else if(type == 1) + { + s_gpu->Freeze(data); + + return 1; + } + else if(type == 2) + { + int slot = *(int*)data + 1; + + if(slot < 1 || slot > 9) + { + return 0; + } + + // TODO + + return 1; + } + + return 0; +} + +EXPORT_C GPUgetScreenPic(BYTE* mem) +{ + // TODO +} + +EXPORT_C GPUshowScreenPic(BYTE* mem) +{ + // TODO +} + +EXPORT_C GPUcursor(int player, int x, int y) +{ + // TODO } \ No newline at end of file diff --git a/plugins/GSdx/GPU.h b/plugins/GSdx/GPU.h index 4a2ada7b66..d341870565 100644 --- a/plugins/GSdx/GPU.h +++ b/plugins/GSdx/GPU.h @@ -1,276 +1,276 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#pragma pack(push, 1) - -#include "GS.h" - -enum -{ - GPU_POLYGON = 1, - GPU_LINE = 2, - GPU_SPRITE = 3, -}; - -REG32_(GPUReg, STATUS) - UINT32 TX:4; - UINT32 TY:1; - UINT32 ABR:2; - UINT32 TP:2; - UINT32 DTD:1; - UINT32 DFE:1; - UINT32 MD:1; - UINT32 ME:1; - UINT32 _PAD0:3; - UINT32 WIDTH1:1; - UINT32 WIDTH0:2; - UINT32 HEIGHT:1; - UINT32 ISPAL:1; - UINT32 ISRGB24:1; - UINT32 ISINTER:1; - UINT32 DEN:1; - UINT32 _PAD1:2; - UINT32 IDLE:1; - UINT32 IMG:1; - UINT32 COM:1; - UINT32 DMA:2; - UINT32 LCF:1; - /* - UINT32 TX:4; - UINT32 TY:1; - UINT32 ABR:2; - UINT32 TP:2; - UINT32 DTD:1; - UINT32 DFE:1; - UINT32 PBW:1; - UINT32 PBC:1; - UINT32 _PAD0:3; - UINT32 HRES2:1; - UINT32 HRES1:2; - UINT32 VRES:1; - UINT32 ISPAL:1; - UINT32 ISRGB24:1; - UINT32 ISINTER:1; - UINT32 ISSTOP:1; - UINT32 _PAD1:1; - UINT32 DMARDY:1; - UINT32 IDIDLE:1; - UINT32 DATARDY:1; - UINT32 ISEMPTY:1; - UINT32 TMODE:2; - UINT32 ODE:1; - */ -REG_END - -REG32_(GPUReg, PACKET) - UINT32 _PAD:24; - UINT32 OPTION:5; - UINT32 TYPE:3; -REG_END - -REG32_(GPUReg, PRIM) - UINT32 VTX:24; - UINT32 TGE:1; - UINT32 ABE:1; - UINT32 TME:1; - UINT32 _PAD2:1; - UINT32 IIP:1; - UINT32 TYPE:3; -REG_END - -REG32_(GPUReg, POLYGON) - UINT32 _PAD:24; - UINT32 TGE:1; - UINT32 ABE:1; - UINT32 TME:1; - UINT32 VTX:1; - UINT32 IIP:1; - UINT32 TYPE:3; -REG_END - -REG32_(GPUReg, LINE) - UINT32 _PAD:24; - UINT32 ZERO1:1; - UINT32 ABE:1; - UINT32 ZERO2:1; - UINT32 PLL:1; - UINT32 IIP:1; - UINT32 TYPE:3; -REG_END - -REG32_(GPUReg, SPRITE) - UINT32 _PAD:24; - UINT32 ZERO:1; - UINT32 ABE:1; - UINT32 TME:1; - UINT32 SIZE:2; - UINT32 TYPE:3; -REG_END - -REG32_(GPUReg, RESET) - UINT32 _PAD:32; -REG_END - -REG32_(GPUReg, DEN) - UINT32 DEN:1; - UINT32 _PAD:31; -REG_END - -REG32_(GPUReg, DMA) - UINT32 DMA:2; - UINT32 _PAD:30; -REG_END - -REG32_(GPUReg, DAREA) - UINT32 X:10; - UINT32 Y:9; - UINT32 _PAD:13; -REG_END - -REG32_(GPUReg, DHRANGE) - UINT32 X1:12; - UINT32 X2:12; - UINT32 _PAD:8; -REG_END - -REG32_(GPUReg, DVRANGE) - UINT32 Y1:10; - UINT32 Y2:11; - UINT32 _PAD:11; -REG_END - -REG32_(GPUReg, DMODE) - UINT32 WIDTH0:2; - UINT32 HEIGHT:1; - UINT32 ISPAL:1; - UINT32 ISRGB24:1; - UINT32 ISINTER:1; - UINT32 WIDTH1:1; - UINT32 REVERSE:1; - UINT32 _PAD:24; -REG_END - -REG32_(GPUReg, GPUINFO) - UINT32 PARAM:24; - UINT32 _PAD:8; -REG_END - -REG32_(GPUReg, MODE) - UINT32 TX:4; - UINT32 TY:1; - UINT32 ABR:2; - UINT32 TP:2; - UINT32 DTD:1; - UINT32 DFE:1; - UINT32 _PAD:21; -REG_END - -REG32_(GPUReg, MASK) - UINT32 MD:1; - UINT32 ME:1; - UINT32 _PAD:30; -REG_END - -REG32_(GPUReg, DRAREA) - UINT32 X:10; - UINT32 Y:10; - UINT32 _PAD:12; -REG_END - -REG32_(GPUReg, DROFF) - INT32 X:11; - INT32 Y:11; - INT32 _PAD:10; -REG_END - -REG32_(GPUReg, RGB) - UINT32 R:8; - UINT32 G:8; - UINT32 B:8; - UINT32 _PAD:8; -REG_END - -REG32_(GPUReg, XY) - INT32 X:11; - INT32 _PAD1:5; - INT32 Y:11; - INT32 _PAD2:5; -REG_END - -REG32_(GPUReg, UV) - UINT32 U:8; - UINT32 V:8; - UINT32 _PAD:16; -REG_END - -REG32_(GPUReg, TWIN) - UINT32 TWW:5; - UINT32 TWH:5; - UINT32 TWX:5; - UINT32 TWY:5; - UINT32 _PAD:12; -REG_END - -REG32_(GPUReg, CLUT) - UINT32 _PAD1:16; - UINT32 X:6; - UINT32 Y:9; - UINT32 _PAD2:1; -REG_END - -REG32_SET(GPUReg) - GPURegSTATUS STATUS; - GPURegPACKET PACKET; - GPURegPRIM PRIM; - GPURegPOLYGON POLYGON; - GPURegLINE LINE; - GPURegSPRITE SPRITE; - GPURegRESET RESET; - GPURegDEN DEN; - GPURegDMA DMA; - GPURegDAREA DAREA; - GPURegDHRANGE DHRANGE; - GPURegDVRANGE DVRANGE; - GPURegDMODE DMODE; - GPURegGPUINFO GPUINFO; - GPURegMODE MODE; - GPURegMASK MASK; - GPURegDRAREA DRAREA; - GPURegDROFF DROFF; - GPURegRGB RGB; - GPURegXY XY; - GPURegUV UV; - GPURegTWIN TWIN; - GPURegCLUT CLUT; -REG_SET_END - -struct GPUFreezeData -{ - UINT32 version; // == 1 - UINT32 status; - UINT32 control[256]; - UINT16 vram[1024 * 1024]; -}; - -#pragma pack(pop) - +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#pragma pack(push, 1) + +#include "GS.h" + +enum +{ + GPU_POLYGON = 1, + GPU_LINE = 2, + GPU_SPRITE = 3, +}; + +REG32_(GPUReg, STATUS) + UINT32 TX:4; + UINT32 TY:1; + UINT32 ABR:2; + UINT32 TP:2; + UINT32 DTD:1; + UINT32 DFE:1; + UINT32 MD:1; + UINT32 ME:1; + UINT32 _PAD0:3; + UINT32 WIDTH1:1; + UINT32 WIDTH0:2; + UINT32 HEIGHT:1; + UINT32 ISPAL:1; + UINT32 ISRGB24:1; + UINT32 ISINTER:1; + UINT32 DEN:1; + UINT32 _PAD1:2; + UINT32 IDLE:1; + UINT32 IMG:1; + UINT32 COM:1; + UINT32 DMA:2; + UINT32 LCF:1; + /* + UINT32 TX:4; + UINT32 TY:1; + UINT32 ABR:2; + UINT32 TP:2; + UINT32 DTD:1; + UINT32 DFE:1; + UINT32 PBW:1; + UINT32 PBC:1; + UINT32 _PAD0:3; + UINT32 HRES2:1; + UINT32 HRES1:2; + UINT32 VRES:1; + UINT32 ISPAL:1; + UINT32 ISRGB24:1; + UINT32 ISINTER:1; + UINT32 ISSTOP:1; + UINT32 _PAD1:1; + UINT32 DMARDY:1; + UINT32 IDIDLE:1; + UINT32 DATARDY:1; + UINT32 ISEMPTY:1; + UINT32 TMODE:2; + UINT32 ODE:1; + */ +REG_END + +REG32_(GPUReg, PACKET) + UINT32 _PAD:24; + UINT32 OPTION:5; + UINT32 TYPE:3; +REG_END + +REG32_(GPUReg, PRIM) + UINT32 VTX:24; + UINT32 TGE:1; + UINT32 ABE:1; + UINT32 TME:1; + UINT32 _PAD2:1; + UINT32 IIP:1; + UINT32 TYPE:3; +REG_END + +REG32_(GPUReg, POLYGON) + UINT32 _PAD:24; + UINT32 TGE:1; + UINT32 ABE:1; + UINT32 TME:1; + UINT32 VTX:1; + UINT32 IIP:1; + UINT32 TYPE:3; +REG_END + +REG32_(GPUReg, LINE) + UINT32 _PAD:24; + UINT32 ZERO1:1; + UINT32 ABE:1; + UINT32 ZERO2:1; + UINT32 PLL:1; + UINT32 IIP:1; + UINT32 TYPE:3; +REG_END + +REG32_(GPUReg, SPRITE) + UINT32 _PAD:24; + UINT32 ZERO:1; + UINT32 ABE:1; + UINT32 TME:1; + UINT32 SIZE:2; + UINT32 TYPE:3; +REG_END + +REG32_(GPUReg, RESET) + UINT32 _PAD:32; +REG_END + +REG32_(GPUReg, DEN) + UINT32 DEN:1; + UINT32 _PAD:31; +REG_END + +REG32_(GPUReg, DMA) + UINT32 DMA:2; + UINT32 _PAD:30; +REG_END + +REG32_(GPUReg, DAREA) + UINT32 X:10; + UINT32 Y:9; + UINT32 _PAD:13; +REG_END + +REG32_(GPUReg, DHRANGE) + UINT32 X1:12; + UINT32 X2:12; + UINT32 _PAD:8; +REG_END + +REG32_(GPUReg, DVRANGE) + UINT32 Y1:10; + UINT32 Y2:11; + UINT32 _PAD:11; +REG_END + +REG32_(GPUReg, DMODE) + UINT32 WIDTH0:2; + UINT32 HEIGHT:1; + UINT32 ISPAL:1; + UINT32 ISRGB24:1; + UINT32 ISINTER:1; + UINT32 WIDTH1:1; + UINT32 REVERSE:1; + UINT32 _PAD:24; +REG_END + +REG32_(GPUReg, GPUINFO) + UINT32 PARAM:24; + UINT32 _PAD:8; +REG_END + +REG32_(GPUReg, MODE) + UINT32 TX:4; + UINT32 TY:1; + UINT32 ABR:2; + UINT32 TP:2; + UINT32 DTD:1; + UINT32 DFE:1; + UINT32 _PAD:21; +REG_END + +REG32_(GPUReg, MASK) + UINT32 MD:1; + UINT32 ME:1; + UINT32 _PAD:30; +REG_END + +REG32_(GPUReg, DRAREA) + UINT32 X:10; + UINT32 Y:10; + UINT32 _PAD:12; +REG_END + +REG32_(GPUReg, DROFF) + INT32 X:11; + INT32 Y:11; + INT32 _PAD:10; +REG_END + +REG32_(GPUReg, RGB) + UINT32 R:8; + UINT32 G:8; + UINT32 B:8; + UINT32 _PAD:8; +REG_END + +REG32_(GPUReg, XY) + INT32 X:11; + INT32 _PAD1:5; + INT32 Y:11; + INT32 _PAD2:5; +REG_END + +REG32_(GPUReg, UV) + UINT32 U:8; + UINT32 V:8; + UINT32 _PAD:16; +REG_END + +REG32_(GPUReg, TWIN) + UINT32 TWW:5; + UINT32 TWH:5; + UINT32 TWX:5; + UINT32 TWY:5; + UINT32 _PAD:12; +REG_END + +REG32_(GPUReg, CLUT) + UINT32 _PAD1:16; + UINT32 X:6; + UINT32 Y:9; + UINT32 _PAD2:1; +REG_END + +REG32_SET(GPUReg) + GPURegSTATUS STATUS; + GPURegPACKET PACKET; + GPURegPRIM PRIM; + GPURegPOLYGON POLYGON; + GPURegLINE LINE; + GPURegSPRITE SPRITE; + GPURegRESET RESET; + GPURegDEN DEN; + GPURegDMA DMA; + GPURegDAREA DAREA; + GPURegDHRANGE DHRANGE; + GPURegDVRANGE DVRANGE; + GPURegDMODE DMODE; + GPURegGPUINFO GPUINFO; + GPURegMODE MODE; + GPURegMASK MASK; + GPURegDRAREA DRAREA; + GPURegDROFF DROFF; + GPURegRGB RGB; + GPURegXY XY; + GPURegUV UV; + GPURegTWIN TWIN; + GPURegCLUT CLUT; +REG_SET_END + +struct GPUFreezeData +{ + UINT32 version; // == 1 + UINT32 status; + UINT32 control[256]; + UINT16 vram[1024 * 1024]; +}; + +#pragma pack(pop) + diff --git a/plugins/GSdx/GPUDrawScanline.cpp b/plugins/GSdx/GPUDrawScanline.cpp index 253bcd7653..38a4044bfb 100644 --- a/plugins/GSdx/GPUDrawScanline.cpp +++ b/plugins/GSdx/GPUDrawScanline.cpp @@ -1,910 +1,910 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GPUDrawScanline.h" - -GPUDrawScanline::GPUDrawScanline(GPUState* state, int id) - : m_state(state) - , m_id(id) -{ -} - -GPUDrawScanline::~GPUDrawScanline() -{ -} - -void GPUDrawScanline::BeginDraw(const GSRasterizerData* data, Functions* f) -{ - GPUDrawingEnvironment& env = m_state->m_env; - - const GPUScanlineParam* p = (const GPUScanlineParam*)data->param; - - m_env.sel = p->sel; - - m_env.mem = &m_state->m_mem; - - if(m_env.sel.tme) - { - m_env.tex = p->tex; - m_env.clut = p->clut; - - if(m_env.sel.twin) - { - DWORD u, v; - - u = ~(env.TWIN.TWW << 3) & 0xff; - v = ~(env.TWIN.TWH << 3) & 0xff; - - m_env.u[0] = GSVector4i((u << 16) | u); - m_env.v[0] = GSVector4i((v << 16) | v); - - u = env.TWIN.TWX << 3; - v = env.TWIN.TWY << 3; - - m_env.u[1] = GSVector4i((u << 16) | u) & ~m_env.u[0]; - m_env.v[1] = GSVector4i((v << 16) | v) & ~m_env.v[0]; - } - } - - m_env.a = GSVector4i(env.PRIM.ABE ? 0xffffffff : 0); - m_env.md = GSVector4i(env.STATUS.MD ? 0x80008000 : 0); - - f->sl = m_ds.Lookup(m_env.sel); - - f->sr = NULL; // TODO - - DWORD sel = 0; - - sel |= (data->primclass == GS_SPRITE_CLASS ? 1 : 0) << 0; - sel |= m_env.sel.tme << 1; - sel |= m_env.sel.iip << 2; - - f->sp = m_sp.Lookup(sel); -} - -template -void GPUDrawScanline::SetupPrim(const GSVertexSW* vertices, const GSVertexSW& dscan) -{ - if(m_env.sel.tme && !m_env.sel.twin) - { - if(sprite) - { - GSVector4i t; - - t = (GSVector4i(vertices[1].t) >> 8) - GSVector4i::x00000001(); - t = t.ps32(t); - t = t.upl16(t); - - m_env.u[2] = t.xxxx(); - m_env.v[2] = t.yyyy(); - } - else - { - m_env.u[2] = GSVector4i::x00ff(); - m_env.v[2] = GSVector4i::x00ff(); - } - } - - GSVector4 ps0123 = GSVector4::ps0123(); - GSVector4 ps4567 = GSVector4::ps4567(); - - GSVector4 dt = dscan.t; - GSVector4 dc = dscan.c; - - GSVector4i dtc8 = GSVector4i(dt * 8.0f).ps32(GSVector4i(dc * 8.0f)); - - if(tme) - { - m_env.dst8 = dtc8.upl16(dtc8); - - m_env.ds = GSVector4i(dt.xxxx() * ps0123).ps32(GSVector4i(dt.xxxx() * ps4567)); - m_env.dt = GSVector4i(dt.yyyy() * ps0123).ps32(GSVector4i(dt.yyyy() * ps4567)); - } - - if(iip) - { - m_env.dc8 = dtc8.uph16(dtc8); - - m_env.dr = GSVector4i(dc.xxxx() * ps0123).ps32(GSVector4i(dc.xxxx() * ps4567)); - m_env.dg = GSVector4i(dc.yyyy() * ps0123).ps32(GSVector4i(dc.yyyy() * ps4567)); - m_env.db = GSVector4i(dc.zzzz() * ps0123).ps32(GSVector4i(dc.zzzz() * ps4567)); - } -} -void GPUDrawScanline::SampleTexture(DWORD ltf, DWORD tlu, DWORD twin, GSVector4i& test, const GSVector4i& s, const GSVector4i& t, GSVector4i* c) -{ - const void* RESTRICT tex = m_env.tex; - const WORD* RESTRICT clut = m_env.clut; - - if(ltf) - { - GSVector4i u = s.sub16(GSVector4i(0x00200020)); // - 0.125f - GSVector4i v = t.sub16(GSVector4i(0x00200020)); // - 0.125f - - GSVector4i u0 = u.srl16(8); - GSVector4i v0 = v.srl16(8); - - GSVector4i u1 = u0.add16(GSVector4i::x0001()); - GSVector4i v1 = v0.add16(GSVector4i::x0001()); - - GSVector4i uf = (u & GSVector4i::x00ff()) << 7; - GSVector4i vf = (v & GSVector4i::x00ff()) << 7; - - if(twin) - { - u0 = (u0 & m_env.u[0]).add16(m_env.u[1]); - v0 = (v0 & m_env.v[0]).add16(m_env.v[1]); - u1 = (u1 & m_env.u[0]).add16(m_env.u[1]); - v1 = (v1 & m_env.v[0]).add16(m_env.v[1]); - } - else - { - u0 = u0.min_i16(m_env.u[2]); - v0 = v0.min_i16(m_env.v[2]); - u1 = u1.min_i16(m_env.u[2]); - v1 = v1.min_i16(m_env.v[2]); - } - - GSVector4i addr00 = v0.sll16(8) | u0; - GSVector4i addr01 = v0.sll16(8) | u1; - GSVector4i addr10 = v1.sll16(8) | u0; - GSVector4i addr11 = v1.sll16(8) | u1; - - GSVector4i c00, c01, c10, c11; - - if(tlu) - { - c00 = addr00.gather16_16((const BYTE*)tex, clut); - c01 = addr01.gather16_16((const BYTE*)tex, clut); - c10 = addr10.gather16_16((const BYTE*)tex, clut); - c11 = addr11.gather16_16((const BYTE*)tex, clut); - } - else - { - c00 = addr00.gather16_16((const WORD*)tex); - c01 = addr01.gather16_16((const WORD*)tex); - c10 = addr00.gather16_16((const WORD*)tex); - c11 = addr01.gather16_16((const WORD*)tex); - } - - GSVector4i r00 = (c00 & 0x001f001f) << 3; - GSVector4i r01 = (c01 & 0x001f001f) << 3; - GSVector4i r10 = (c10 & 0x001f001f) << 3; - GSVector4i r11 = (c11 & 0x001f001f) << 3; - - r00 = r00.lerp16<0>(r01, uf); - r10 = r10.lerp16<0>(r11, uf); - c[0] = r00.lerp16<0>(r10, vf); - - GSVector4i g00 = (c00 & 0x03e003e0) >> 2; - GSVector4i g01 = (c01 & 0x03e003e0) >> 2; - GSVector4i g10 = (c10 & 0x03e003e0) >> 2; - GSVector4i g11 = (c11 & 0x03e003e0) >> 2; - - g00 = g00.lerp16<0>(g01, uf); - g10 = g10.lerp16<0>(g11, uf); - c[1] = g00.lerp16<0>(g10, vf); - - GSVector4i b00 = (c00 & 0x7c007c00) >> 7; - GSVector4i b01 = (c01 & 0x7c007c00) >> 7; - GSVector4i b10 = (c10 & 0x7c007c00) >> 7; - GSVector4i b11 = (c11 & 0x7c007c00) >> 7; - - b00 = b00.lerp16<0>(b01, uf); - b10 = b10.lerp16<0>(b11, uf); - c[2] = b00.lerp16<0>(b10, vf); - - GSVector4i a00 = (c00 & 0x80008000) >> 8; - GSVector4i a01 = (c01 & 0x80008000) >> 8; - GSVector4i a10 = (c10 & 0x80008000) >> 8; - GSVector4i a11 = (c11 & 0x80008000) >> 8; - - a00 = a00.lerp16<0>(a01, uf); - a10 = a10.lerp16<0>(a11, uf); - c[3] = a00.lerp16<0>(a10, vf).gt16(GSVector4i::zero()); - - // mask out blank pixels (not perfect) - - test |= - c[0].eq16(GSVector4i::zero()) & - c[1].eq16(GSVector4i::zero()) & - c[2].eq16(GSVector4i::zero()) & - c[3].eq16(GSVector4i::zero()); - } - else - { - GSVector4i u = s.srl16(8); - GSVector4i v = t.srl16(8); - - if(twin) - { - u = (u & m_env.u[0]).add16(m_env.u[1]); - v = (v & m_env.v[0]).add16(m_env.v[1]); - } - else - { - u = u.min_i16(m_env.u[2]); - v = v.min_i16(m_env.v[2]); - } - - GSVector4i addr = v.sll16(8) | u; - - GSVector4i c00; - - if(tlu) - { - c00 = addr.gather16_16((const BYTE*)tex, clut); - } - else - { - c00 = addr.gather16_16((const WORD*)tex); - } - - test |= c00.eq16(GSVector4i::zero()); // mask out blank pixels - - c[0] = (c00 & 0x001f001f) << 3; - c[1] = (c00 & 0x03e003e0) >> 2; - c[2] = (c00 & 0x7c007c00) >> 7; - c[3] = c00.sra16(15); - } -} - -void GPUDrawScanline::ColorTFX(DWORD tfx, const GSVector4i& r, const GSVector4i& g, const GSVector4i& b, GSVector4i* c) -{ - switch(tfx) - { - case 0: // none (tfx = 0) - case 1: // none (tfx = tge) - c[0] = r.srl16(7); - c[1] = g.srl16(7); - c[2] = b.srl16(7); - break; - case 2: // modulate (tfx = tme | tge) - c[0] = c[0].modulate16<1>(r).clamp8(); - c[1] = c[1].modulate16<1>(g).clamp8(); - c[2] = c[2].modulate16<1>(b).clamp8(); - break; - case 3: // decal (tfx = tme) - break; - default: - __assume(0); - } -} - -void GPUDrawScanline::AlphaBlend(UINT32 abr, UINT32 tme, const GSVector4i& d, GSVector4i* c) -{ - GSVector4i r = (d & 0x001f001f) << 3; - GSVector4i g = (d & 0x03e003e0) >> 2; - GSVector4i b = (d & 0x7c007c00) >> 7; - - switch(abr) - { - case 0: - r = r.avg8(c[0]); - g = g.avg8(c[0]); - b = b.avg8(c[0]); - break; - case 1: - r = r.addus8(c[0]); - g = g.addus8(c[1]); - b = b.addus8(c[2]); - break; - case 2: - r = r.subus8(c[0]); - g = g.subus8(c[1]); - b = b.subus8(c[2]); - break; - case 3: - r = r.addus8(c[0].srl16(2)); - g = g.addus8(c[1].srl16(2)); - b = b.addus8(c[2].srl16(2)); - break; - default: - __assume(0); - } - - if(tme) // per pixel - { - c[0] = c[0].blend8(r, c[3]); - c[1] = c[1].blend8(g, c[3]); - c[2] = c[2].blend8(b, c[3]); - } - else - { - c[0] = r; - c[1] = g; - c[2] = b; - c[3] = GSVector4i::zero(); - } -} - -void GPUDrawScanline::WriteFrame(WORD* RESTRICT fb, const GSVector4i& test, const GSVector4i* c, int pixels) -{ - GSVector4i r = (c[0] & 0x00f800f8) >> 3; - GSVector4i g = (c[1] & 0x00f800f8) << 2; - GSVector4i b = (c[2] & 0x00f800f8) << 7; - GSVector4i a = (c[3] & 0x00800080) << 8; - - GSVector4i s = r | g | b | a | m_env.md; - - int i = 0; - - do - { - if(test.u16[i] == 0) - { - fb[i] = s.u16[i]; - } - } - while(++i < pixels); -} - -// - -__declspec(align(16)) static WORD s_dither[4][16] = -{ - {7, 0, 6, 1, 7, 0, 6, 1, 7, 0, 6, 1, 7, 0, 6, 1}, - {2, 5, 3, 4, 2, 5, 3, 4, 2, 5, 3, 4, 2, 5, 3, 4}, - {1, 6, 0, 7, 1, 6, 0, 7, 1, 6, 0, 7, 1, 6, 0, 7}, - {4, 3, 5, 2, 4, 3, 5, 2, 4, 3, 5, 2, 4, 3, 5, 2}, -}; - -void GPUDrawScanline::DrawScanline(int top, int left, int right, const GSVertexSW& v) -{ - GSVector4i s, t; - GSVector4i r, g, b; - - if(m_env.sel.tme) - { - GSVector4i vt = GSVector4i(v.t).xxzzl(); - - s = vt.xxxx().add16(m_env.ds); - t = vt.yyyy().add16(m_env.dt); - } - - GSVector4i vc = GSVector4i(v.c).xxzzlh(); - - r = vc.xxxx(); - g = vc.yyyy(); - b = vc.zzzz(); - - if(m_env.sel.iip) - { - r = r.add16(m_env.dr); - g = g.add16(m_env.dg); - b = b.add16(m_env.db); - } - - GSVector4i dither; - - if(m_env.sel.dtd) - { - dither = GSVector4i::load(&s_dither[top & 3][left & 3]); - } - - int steps = right - left; - - WORD* fb = m_env.mem->GetPixelAddress(left, top); - - while(1) - { - do - { - int pixels = GSVector4i::min_i16(steps, 8); - - GSVector4i test = GSVector4i::zero(); - - GSVector4i d = GSVector4i::zero(); - - if(m_env.sel.rfb) // me | abe - { - d = GSVector4i::load(fb); - - if(m_env.sel.me) - { - test = d.sra16(15); - - if(test.alltrue()) - { - continue; - } - } - } - - GSVector4i c[4]; - - if(m_env.sel.tme) - { - SampleTexture(m_env.sel.ltf, m_env.sel.tlu, m_env.sel.twin, test, s, t, c); - } - - ColorTFX(m_env.sel.tfx, r, g, b, c); - - if(m_env.sel.abe) - { - AlphaBlend(m_env.sel.abr, m_env.sel.tme, d, c); - } - - if(m_env.sel.dtd) - { - c[0] = c[0].addus8(dither); - c[1] = c[1].addus8(dither); - c[2] = c[2].addus8(dither); - } - - WriteFrame(fb, test, c, pixels); - } - while(0); - - if(steps <= 8) break; - - steps -= 8; - - fb += 8; - - if(m_env.sel.tme) - { - GSVector4i dst8 = m_env.dst8; - - s = s.add16(dst8.xxxx()); - t = t.add16(dst8.yyyy()); - } - - if(m_env.sel.iip) - { - GSVector4i dc8 = m_env.dc8; - - r = r.add16(dc8.xxxx()); - g = g.add16(dc8.yyyy()); - b = b.add16(dc8.zzzz()); - } - } -} - -template -void GPUDrawScanline::DrawScanlineEx(int top, int left, int right, const GSVertexSW& v) -{ - DWORD iip = (sel >> 0) & 1; - DWORD me = (sel >> 1) & 1; - DWORD abe = (sel >> 2) & 1; - DWORD abr = (sel >> 3) & 3; - // DWORD tge = (sel >> 5) & 1; - DWORD tme = (sel >> 6) & 1; - DWORD twin = (sel >> 7) & 1; - DWORD rfb = (sel >> 1) & 3; - DWORD tfx = (sel >> 5) & 3; - - GSVector4i s, t; - GSVector4i r, g, b; - - if(tme) - { - GSVector4i vt = GSVector4i(v.t).xxzzl(); - - s = vt.xxxx().add16(m_env.ds); - t = vt.yyyy().add16(m_env.dt); - } - - GSVector4i vc = GSVector4i(v.c).xxzzlh(); - - r = vc.xxxx(); - g = vc.yyyy(); - b = vc.zzzz(); - - if(iip) - { - r = r.add16(m_env.dr); - g = g.add16(m_env.dg); - b = b.add16(m_env.db); - } - - GSVector4i dither; - - if(m_env.sel.dtd) - { - dither = GSVector4i::load(&s_dither[top & 3][left & 3]); - } - - int steps = right - left; - - WORD* fb = m_env.mem->GetPixelAddress(left, top); - - while(1) - { - do - { - int pixels = GSVector4i::min_i16(steps, 8); - - GSVector4i test = GSVector4i::zero(); - - GSVector4i d = GSVector4i::zero(); - - if(rfb) // me | abe - { - d = GSVector4i::load(fb); - - if(me) - { - test = d.sra16(15); - - if(test.alltrue()) - { - continue; - } - } - } - - GSVector4i c[4]; - - if(tme) - { - SampleTexture(m_env.sel.ltf, m_env.sel.tlu, twin, test, s, t, c); - } - - ColorTFX(tfx, r, g, b, c); - - if(abe) - { - AlphaBlend(abr, tme, d, c); - } - - if(m_env.sel.dtd) - { - c[0] = c[0].addus8(dither); - c[1] = c[1].addus8(dither); - c[2] = c[2].addus8(dither); - } - - WriteFrame(fb, test, c, pixels); - } - while(0); - - if(steps <= 8) break; - - steps -= 8; - - fb += 8; - - if(tme) - { - GSVector4i dst8 = m_env.dst8; - - s = s.add16(dst8.xxxx()); - t = t.add16(dst8.yyyy()); - } - - if(iip) - { - GSVector4i dc8 = m_env.dc8; - - r = r.add16(dc8.xxxx()); - g = g.add16(dc8.yyyy()); - b = b.add16(dc8.zzzz()); - } - } -} - -GPUDrawScanline::GPUDrawScanlineMap::GPUDrawScanlineMap() -{ - for(int i = 0; i < countof(m_default); i++) - { - m_default[i] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanline; - } - - #ifdef FAST_DRAWSCANLINE - - m_default[0x00] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x00>; - m_default[0x01] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x01>; - m_default[0x02] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x02>; - m_default[0x03] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x03>; - m_default[0x04] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x04>; - m_default[0x05] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x05>; - m_default[0x06] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x06>; - m_default[0x07] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x07>; - m_default[0x08] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x08>; - m_default[0x09] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x09>; - m_default[0x0a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0a>; - m_default[0x0b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0b>; - m_default[0x0c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0c>; - m_default[0x0d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0d>; - m_default[0x0e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0e>; - m_default[0x0f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0f>; - m_default[0x10] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x10>; - m_default[0x11] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x11>; - m_default[0x12] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x12>; - m_default[0x13] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x13>; - m_default[0x14] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x14>; - m_default[0x15] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x15>; - m_default[0x16] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x16>; - m_default[0x17] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x17>; - m_default[0x18] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x18>; - m_default[0x19] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x19>; - m_default[0x1a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1a>; - m_default[0x1b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1b>; - m_default[0x1c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1c>; - m_default[0x1d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1d>; - m_default[0x1e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1e>; - m_default[0x1f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1f>; - m_default[0x20] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x20>; - m_default[0x21] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x21>; - m_default[0x22] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x22>; - m_default[0x23] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x23>; - m_default[0x24] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x24>; - m_default[0x25] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x25>; - m_default[0x26] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x26>; - m_default[0x27] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x27>; - m_default[0x28] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x28>; - m_default[0x29] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x29>; - m_default[0x2a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2a>; - m_default[0x2b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2b>; - m_default[0x2c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2c>; - m_default[0x2d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2d>; - m_default[0x2e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2e>; - m_default[0x2f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2f>; - m_default[0x30] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x30>; - m_default[0x31] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x31>; - m_default[0x32] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x32>; - m_default[0x33] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x33>; - m_default[0x34] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x34>; - m_default[0x35] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x35>; - m_default[0x36] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x36>; - m_default[0x37] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x37>; - m_default[0x38] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x38>; - m_default[0x39] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x39>; - m_default[0x3a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3a>; - m_default[0x3b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3b>; - m_default[0x3c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3c>; - m_default[0x3d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3d>; - m_default[0x3e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3e>; - m_default[0x3f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3f>; - m_default[0x40] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x40>; - m_default[0x41] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x41>; - m_default[0x42] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x42>; - m_default[0x43] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x43>; - m_default[0x44] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x44>; - m_default[0x45] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x45>; - m_default[0x46] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x46>; - m_default[0x47] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x47>; - m_default[0x48] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x48>; - m_default[0x49] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x49>; - m_default[0x4a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4a>; - m_default[0x4b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4b>; - m_default[0x4c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4c>; - m_default[0x4d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4d>; - m_default[0x4e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4e>; - m_default[0x4f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4f>; - m_default[0x50] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x50>; - m_default[0x51] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x51>; - m_default[0x52] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x52>; - m_default[0x53] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x53>; - m_default[0x54] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x54>; - m_default[0x55] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x55>; - m_default[0x56] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x56>; - m_default[0x57] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x57>; - m_default[0x58] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x58>; - m_default[0x59] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x59>; - m_default[0x5a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5a>; - m_default[0x5b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5b>; - m_default[0x5c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5c>; - m_default[0x5d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5d>; - m_default[0x5e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5e>; - m_default[0x5f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5f>; - m_default[0x60] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x60>; - m_default[0x61] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x61>; - m_default[0x62] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x62>; - m_default[0x63] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x63>; - m_default[0x64] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x64>; - m_default[0x65] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x65>; - m_default[0x66] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x66>; - m_default[0x67] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x67>; - m_default[0x68] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x68>; - m_default[0x69] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x69>; - m_default[0x6a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6a>; - m_default[0x6b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6b>; - m_default[0x6c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6c>; - m_default[0x6d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6d>; - m_default[0x6e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6e>; - m_default[0x6f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6f>; - m_default[0x70] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x70>; - m_default[0x71] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x71>; - m_default[0x72] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x72>; - m_default[0x73] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x73>; - m_default[0x74] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x74>; - m_default[0x75] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x75>; - m_default[0x76] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x76>; - m_default[0x77] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x77>; - m_default[0x78] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x78>; - m_default[0x79] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x79>; - m_default[0x7a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7a>; - m_default[0x7b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7b>; - m_default[0x7c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7c>; - m_default[0x7d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7d>; - m_default[0x7e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7e>; - m_default[0x7f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7f>; - m_default[0x80] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x80>; - m_default[0x81] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x81>; - m_default[0x82] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x82>; - m_default[0x83] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x83>; - m_default[0x84] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x84>; - m_default[0x85] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x85>; - m_default[0x86] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x86>; - m_default[0x87] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x87>; - m_default[0x88] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x88>; - m_default[0x89] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x89>; - m_default[0x8a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8a>; - m_default[0x8b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8b>; - m_default[0x8c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8c>; - m_default[0x8d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8d>; - m_default[0x8e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8e>; - m_default[0x8f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8f>; - m_default[0x90] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x90>; - m_default[0x91] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x91>; - m_default[0x92] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x92>; - m_default[0x93] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x93>; - m_default[0x94] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x94>; - m_default[0x95] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x95>; - m_default[0x96] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x96>; - m_default[0x97] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x97>; - m_default[0x98] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x98>; - m_default[0x99] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x99>; - m_default[0x9a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9a>; - m_default[0x9b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9b>; - m_default[0x9c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9c>; - m_default[0x9d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9d>; - m_default[0x9e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9e>; - m_default[0x9f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9f>; - m_default[0xa0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa0>; - m_default[0xa1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa1>; - m_default[0xa2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa2>; - m_default[0xa3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa3>; - m_default[0xa4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa4>; - m_default[0xa5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa5>; - m_default[0xa6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa6>; - m_default[0xa7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa7>; - m_default[0xa8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa8>; - m_default[0xa9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa9>; - m_default[0xaa] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xaa>; - m_default[0xab] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xab>; - m_default[0xac] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xac>; - m_default[0xad] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xad>; - m_default[0xae] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xae>; - m_default[0xaf] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xaf>; - m_default[0xb0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb0>; - m_default[0xb1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb1>; - m_default[0xb2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb2>; - m_default[0xb3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb3>; - m_default[0xb4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb4>; - m_default[0xb5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb5>; - m_default[0xb6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb6>; - m_default[0xb7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb7>; - m_default[0xb8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb8>; - m_default[0xb9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb9>; - m_default[0xba] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xba>; - m_default[0xbb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbb>; - m_default[0xbc] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbc>; - m_default[0xbd] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbd>; - m_default[0xbe] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbe>; - m_default[0xbf] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbf>; - m_default[0xc0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc0>; - m_default[0xc1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc1>; - m_default[0xc2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc2>; - m_default[0xc3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc3>; - m_default[0xc4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc4>; - m_default[0xc5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc5>; - m_default[0xc6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc6>; - m_default[0xc7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc7>; - m_default[0xc8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc8>; - m_default[0xc9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc9>; - m_default[0xca] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xca>; - m_default[0xcb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xcb>; - m_default[0xcc] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xcc>; - m_default[0xcd] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xcd>; - m_default[0xce] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xce>; - m_default[0xcf] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xcf>; - m_default[0xd0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd0>; - m_default[0xd1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd1>; - m_default[0xd2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd2>; - m_default[0xd3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd3>; - m_default[0xd4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd4>; - m_default[0xd5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd5>; - m_default[0xd6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd6>; - m_default[0xd7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd7>; - m_default[0xd8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd8>; - m_default[0xd9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd9>; - m_default[0xda] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xda>; - m_default[0xdb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xdb>; - m_default[0xdc] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xdc>; - m_default[0xdd] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xdd>; - m_default[0xde] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xde>; - m_default[0xdf] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xdf>; - m_default[0xe0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe0>; - m_default[0xe1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe1>; - m_default[0xe2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe2>; - m_default[0xe3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe3>; - m_default[0xe4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe4>; - m_default[0xe5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe5>; - m_default[0xe6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe6>; - m_default[0xe7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe7>; - m_default[0xe8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe8>; - m_default[0xe9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe9>; - m_default[0xea] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xea>; - m_default[0xeb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xeb>; - m_default[0xec] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xec>; - m_default[0xed] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xed>; - m_default[0xee] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xee>; - m_default[0xef] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xef>; - m_default[0xf0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf0>; - m_default[0xf1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf1>; - m_default[0xf2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf2>; - m_default[0xf3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf3>; - m_default[0xf4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf4>; - m_default[0xf5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf5>; - m_default[0xf6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf6>; - m_default[0xf7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf7>; - m_default[0xf8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf8>; - m_default[0xf9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf9>; - m_default[0xfa] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfa>; - m_default[0xfb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfb>; - m_default[0xfc] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfc>; - m_default[0xfd] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfd>; - m_default[0xfe] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfe>; - m_default[0xff] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xff>; - - #endif -} - -IDrawScanline::DrawScanlinePtr GPUDrawScanline::GPUDrawScanlineMap::GetDefaultFunction(DWORD dw) -{ - GPUScanlineSelector sel; - - sel.dw = dw; - - return m_default[sel]; -} - -// - -GPUDrawScanline::GPUSetupPrimMap::GPUSetupPrimMap() -{ - #define InitSP_IIP(sprite, tme, iip) \ - m_default[sprite][tme][iip] = (SetupPrimPtr)&GPUDrawScanline::SetupPrim; \ - - #define InitSP_TME(sprite, tme) \ - InitSP_IIP(sprite, tme, 0) \ - InitSP_IIP(sprite, tme, 1) \ - - #define InitSP_SPRITE(sprite) \ - InitSP_TME(sprite, 0) \ - InitSP_TME(sprite, 1) \ - - InitSP_SPRITE(0); - InitSP_SPRITE(1); -} - -IDrawScanline::SetupPrimPtr GPUDrawScanline::GPUSetupPrimMap::GetDefaultFunction(DWORD dw) -{ - DWORD sprite = (dw >> 0) & 1; - DWORD tme = (dw >> 1) & 1; - DWORD iip = (dw >> 2) & 1; - - return m_default[sprite][tme][iip]; -} - +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GPUDrawScanline.h" + +GPUDrawScanline::GPUDrawScanline(GPUState* state, int id) + : m_state(state) + , m_id(id) +{ +} + +GPUDrawScanline::~GPUDrawScanline() +{ +} + +void GPUDrawScanline::BeginDraw(const GSRasterizerData* data, Functions* f) +{ + GPUDrawingEnvironment& env = m_state->m_env; + + const GPUScanlineParam* p = (const GPUScanlineParam*)data->param; + + m_env.sel = p->sel; + + m_env.mem = &m_state->m_mem; + + if(m_env.sel.tme) + { + m_env.tex = p->tex; + m_env.clut = p->clut; + + if(m_env.sel.twin) + { + DWORD u, v; + + u = ~(env.TWIN.TWW << 3) & 0xff; + v = ~(env.TWIN.TWH << 3) & 0xff; + + m_env.u[0] = GSVector4i((u << 16) | u); + m_env.v[0] = GSVector4i((v << 16) | v); + + u = env.TWIN.TWX << 3; + v = env.TWIN.TWY << 3; + + m_env.u[1] = GSVector4i((u << 16) | u) & ~m_env.u[0]; + m_env.v[1] = GSVector4i((v << 16) | v) & ~m_env.v[0]; + } + } + + m_env.a = GSVector4i(env.PRIM.ABE ? 0xffffffff : 0); + m_env.md = GSVector4i(env.STATUS.MD ? 0x80008000 : 0); + + f->sl = m_ds.Lookup(m_env.sel); + + f->sr = NULL; // TODO + + DWORD sel = 0; + + sel |= (data->primclass == GS_SPRITE_CLASS ? 1 : 0) << 0; + sel |= m_env.sel.tme << 1; + sel |= m_env.sel.iip << 2; + + f->sp = m_sp.Lookup(sel); +} + +template +void GPUDrawScanline::SetupPrim(const GSVertexSW* vertices, const GSVertexSW& dscan) +{ + if(m_env.sel.tme && !m_env.sel.twin) + { + if(sprite) + { + GSVector4i t; + + t = (GSVector4i(vertices[1].t) >> 8) - GSVector4i::x00000001(); + t = t.ps32(t); + t = t.upl16(t); + + m_env.u[2] = t.xxxx(); + m_env.v[2] = t.yyyy(); + } + else + { + m_env.u[2] = GSVector4i::x00ff(); + m_env.v[2] = GSVector4i::x00ff(); + } + } + + GSVector4 ps0123 = GSVector4::ps0123(); + GSVector4 ps4567 = GSVector4::ps4567(); + + GSVector4 dt = dscan.t; + GSVector4 dc = dscan.c; + + GSVector4i dtc8 = GSVector4i(dt * 8.0f).ps32(GSVector4i(dc * 8.0f)); + + if(tme) + { + m_env.dst8 = dtc8.upl16(dtc8); + + m_env.ds = GSVector4i(dt.xxxx() * ps0123).ps32(GSVector4i(dt.xxxx() * ps4567)); + m_env.dt = GSVector4i(dt.yyyy() * ps0123).ps32(GSVector4i(dt.yyyy() * ps4567)); + } + + if(iip) + { + m_env.dc8 = dtc8.uph16(dtc8); + + m_env.dr = GSVector4i(dc.xxxx() * ps0123).ps32(GSVector4i(dc.xxxx() * ps4567)); + m_env.dg = GSVector4i(dc.yyyy() * ps0123).ps32(GSVector4i(dc.yyyy() * ps4567)); + m_env.db = GSVector4i(dc.zzzz() * ps0123).ps32(GSVector4i(dc.zzzz() * ps4567)); + } +} +void GPUDrawScanline::SampleTexture(DWORD ltf, DWORD tlu, DWORD twin, GSVector4i& test, const GSVector4i& s, const GSVector4i& t, GSVector4i* c) +{ + const void* RESTRICT tex = m_env.tex; + const WORD* RESTRICT clut = m_env.clut; + + if(ltf) + { + GSVector4i u = s.sub16(GSVector4i(0x00200020)); // - 0.125f + GSVector4i v = t.sub16(GSVector4i(0x00200020)); // - 0.125f + + GSVector4i u0 = u.srl16(8); + GSVector4i v0 = v.srl16(8); + + GSVector4i u1 = u0.add16(GSVector4i::x0001()); + GSVector4i v1 = v0.add16(GSVector4i::x0001()); + + GSVector4i uf = (u & GSVector4i::x00ff()) << 7; + GSVector4i vf = (v & GSVector4i::x00ff()) << 7; + + if(twin) + { + u0 = (u0 & m_env.u[0]).add16(m_env.u[1]); + v0 = (v0 & m_env.v[0]).add16(m_env.v[1]); + u1 = (u1 & m_env.u[0]).add16(m_env.u[1]); + v1 = (v1 & m_env.v[0]).add16(m_env.v[1]); + } + else + { + u0 = u0.min_i16(m_env.u[2]); + v0 = v0.min_i16(m_env.v[2]); + u1 = u1.min_i16(m_env.u[2]); + v1 = v1.min_i16(m_env.v[2]); + } + + GSVector4i addr00 = v0.sll16(8) | u0; + GSVector4i addr01 = v0.sll16(8) | u1; + GSVector4i addr10 = v1.sll16(8) | u0; + GSVector4i addr11 = v1.sll16(8) | u1; + + GSVector4i c00, c01, c10, c11; + + if(tlu) + { + c00 = addr00.gather16_16((const BYTE*)tex, clut); + c01 = addr01.gather16_16((const BYTE*)tex, clut); + c10 = addr10.gather16_16((const BYTE*)tex, clut); + c11 = addr11.gather16_16((const BYTE*)tex, clut); + } + else + { + c00 = addr00.gather16_16((const WORD*)tex); + c01 = addr01.gather16_16((const WORD*)tex); + c10 = addr00.gather16_16((const WORD*)tex); + c11 = addr01.gather16_16((const WORD*)tex); + } + + GSVector4i r00 = (c00 & 0x001f001f) << 3; + GSVector4i r01 = (c01 & 0x001f001f) << 3; + GSVector4i r10 = (c10 & 0x001f001f) << 3; + GSVector4i r11 = (c11 & 0x001f001f) << 3; + + r00 = r00.lerp16<0>(r01, uf); + r10 = r10.lerp16<0>(r11, uf); + c[0] = r00.lerp16<0>(r10, vf); + + GSVector4i g00 = (c00 & 0x03e003e0) >> 2; + GSVector4i g01 = (c01 & 0x03e003e0) >> 2; + GSVector4i g10 = (c10 & 0x03e003e0) >> 2; + GSVector4i g11 = (c11 & 0x03e003e0) >> 2; + + g00 = g00.lerp16<0>(g01, uf); + g10 = g10.lerp16<0>(g11, uf); + c[1] = g00.lerp16<0>(g10, vf); + + GSVector4i b00 = (c00 & 0x7c007c00) >> 7; + GSVector4i b01 = (c01 & 0x7c007c00) >> 7; + GSVector4i b10 = (c10 & 0x7c007c00) >> 7; + GSVector4i b11 = (c11 & 0x7c007c00) >> 7; + + b00 = b00.lerp16<0>(b01, uf); + b10 = b10.lerp16<0>(b11, uf); + c[2] = b00.lerp16<0>(b10, vf); + + GSVector4i a00 = (c00 & 0x80008000) >> 8; + GSVector4i a01 = (c01 & 0x80008000) >> 8; + GSVector4i a10 = (c10 & 0x80008000) >> 8; + GSVector4i a11 = (c11 & 0x80008000) >> 8; + + a00 = a00.lerp16<0>(a01, uf); + a10 = a10.lerp16<0>(a11, uf); + c[3] = a00.lerp16<0>(a10, vf).gt16(GSVector4i::zero()); + + // mask out blank pixels (not perfect) + + test |= + c[0].eq16(GSVector4i::zero()) & + c[1].eq16(GSVector4i::zero()) & + c[2].eq16(GSVector4i::zero()) & + c[3].eq16(GSVector4i::zero()); + } + else + { + GSVector4i u = s.srl16(8); + GSVector4i v = t.srl16(8); + + if(twin) + { + u = (u & m_env.u[0]).add16(m_env.u[1]); + v = (v & m_env.v[0]).add16(m_env.v[1]); + } + else + { + u = u.min_i16(m_env.u[2]); + v = v.min_i16(m_env.v[2]); + } + + GSVector4i addr = v.sll16(8) | u; + + GSVector4i c00; + + if(tlu) + { + c00 = addr.gather16_16((const BYTE*)tex, clut); + } + else + { + c00 = addr.gather16_16((const WORD*)tex); + } + + test |= c00.eq16(GSVector4i::zero()); // mask out blank pixels + + c[0] = (c00 & 0x001f001f) << 3; + c[1] = (c00 & 0x03e003e0) >> 2; + c[2] = (c00 & 0x7c007c00) >> 7; + c[3] = c00.sra16(15); + } +} + +void GPUDrawScanline::ColorTFX(DWORD tfx, const GSVector4i& r, const GSVector4i& g, const GSVector4i& b, GSVector4i* c) +{ + switch(tfx) + { + case 0: // none (tfx = 0) + case 1: // none (tfx = tge) + c[0] = r.srl16(7); + c[1] = g.srl16(7); + c[2] = b.srl16(7); + break; + case 2: // modulate (tfx = tme | tge) + c[0] = c[0].modulate16<1>(r).clamp8(); + c[1] = c[1].modulate16<1>(g).clamp8(); + c[2] = c[2].modulate16<1>(b).clamp8(); + break; + case 3: // decal (tfx = tme) + break; + default: + __assume(0); + } +} + +void GPUDrawScanline::AlphaBlend(UINT32 abr, UINT32 tme, const GSVector4i& d, GSVector4i* c) +{ + GSVector4i r = (d & 0x001f001f) << 3; + GSVector4i g = (d & 0x03e003e0) >> 2; + GSVector4i b = (d & 0x7c007c00) >> 7; + + switch(abr) + { + case 0: + r = r.avg8(c[0]); + g = g.avg8(c[0]); + b = b.avg8(c[0]); + break; + case 1: + r = r.addus8(c[0]); + g = g.addus8(c[1]); + b = b.addus8(c[2]); + break; + case 2: + r = r.subus8(c[0]); + g = g.subus8(c[1]); + b = b.subus8(c[2]); + break; + case 3: + r = r.addus8(c[0].srl16(2)); + g = g.addus8(c[1].srl16(2)); + b = b.addus8(c[2].srl16(2)); + break; + default: + __assume(0); + } + + if(tme) // per pixel + { + c[0] = c[0].blend8(r, c[3]); + c[1] = c[1].blend8(g, c[3]); + c[2] = c[2].blend8(b, c[3]); + } + else + { + c[0] = r; + c[1] = g; + c[2] = b; + c[3] = GSVector4i::zero(); + } +} + +void GPUDrawScanline::WriteFrame(WORD* RESTRICT fb, const GSVector4i& test, const GSVector4i* c, int pixels) +{ + GSVector4i r = (c[0] & 0x00f800f8) >> 3; + GSVector4i g = (c[1] & 0x00f800f8) << 2; + GSVector4i b = (c[2] & 0x00f800f8) << 7; + GSVector4i a = (c[3] & 0x00800080) << 8; + + GSVector4i s = r | g | b | a | m_env.md; + + int i = 0; + + do + { + if(test.u16[i] == 0) + { + fb[i] = s.u16[i]; + } + } + while(++i < pixels); +} + +// + +__declspec(align(16)) static WORD s_dither[4][16] = +{ + {7, 0, 6, 1, 7, 0, 6, 1, 7, 0, 6, 1, 7, 0, 6, 1}, + {2, 5, 3, 4, 2, 5, 3, 4, 2, 5, 3, 4, 2, 5, 3, 4}, + {1, 6, 0, 7, 1, 6, 0, 7, 1, 6, 0, 7, 1, 6, 0, 7}, + {4, 3, 5, 2, 4, 3, 5, 2, 4, 3, 5, 2, 4, 3, 5, 2}, +}; + +void GPUDrawScanline::DrawScanline(int top, int left, int right, const GSVertexSW& v) +{ + GSVector4i s, t; + GSVector4i r, g, b; + + if(m_env.sel.tme) + { + GSVector4i vt = GSVector4i(v.t).xxzzl(); + + s = vt.xxxx().add16(m_env.ds); + t = vt.yyyy().add16(m_env.dt); + } + + GSVector4i vc = GSVector4i(v.c).xxzzlh(); + + r = vc.xxxx(); + g = vc.yyyy(); + b = vc.zzzz(); + + if(m_env.sel.iip) + { + r = r.add16(m_env.dr); + g = g.add16(m_env.dg); + b = b.add16(m_env.db); + } + + GSVector4i dither; + + if(m_env.sel.dtd) + { + dither = GSVector4i::load(&s_dither[top & 3][left & 3]); + } + + int steps = right - left; + + WORD* fb = m_env.mem->GetPixelAddress(left, top); + + while(1) + { + do + { + int pixels = GSVector4i::min_i16(steps, 8); + + GSVector4i test = GSVector4i::zero(); + + GSVector4i d = GSVector4i::zero(); + + if(m_env.sel.rfb) // me | abe + { + d = GSVector4i::load(fb); + + if(m_env.sel.me) + { + test = d.sra16(15); + + if(test.alltrue()) + { + continue; + } + } + } + + GSVector4i c[4]; + + if(m_env.sel.tme) + { + SampleTexture(m_env.sel.ltf, m_env.sel.tlu, m_env.sel.twin, test, s, t, c); + } + + ColorTFX(m_env.sel.tfx, r, g, b, c); + + if(m_env.sel.abe) + { + AlphaBlend(m_env.sel.abr, m_env.sel.tme, d, c); + } + + if(m_env.sel.dtd) + { + c[0] = c[0].addus8(dither); + c[1] = c[1].addus8(dither); + c[2] = c[2].addus8(dither); + } + + WriteFrame(fb, test, c, pixels); + } + while(0); + + if(steps <= 8) break; + + steps -= 8; + + fb += 8; + + if(m_env.sel.tme) + { + GSVector4i dst8 = m_env.dst8; + + s = s.add16(dst8.xxxx()); + t = t.add16(dst8.yyyy()); + } + + if(m_env.sel.iip) + { + GSVector4i dc8 = m_env.dc8; + + r = r.add16(dc8.xxxx()); + g = g.add16(dc8.yyyy()); + b = b.add16(dc8.zzzz()); + } + } +} + +template +void GPUDrawScanline::DrawScanlineEx(int top, int left, int right, const GSVertexSW& v) +{ + DWORD iip = (sel >> 0) & 1; + DWORD me = (sel >> 1) & 1; + DWORD abe = (sel >> 2) & 1; + DWORD abr = (sel >> 3) & 3; + // DWORD tge = (sel >> 5) & 1; + DWORD tme = (sel >> 6) & 1; + DWORD twin = (sel >> 7) & 1; + DWORD rfb = (sel >> 1) & 3; + DWORD tfx = (sel >> 5) & 3; + + GSVector4i s, t; + GSVector4i r, g, b; + + if(tme) + { + GSVector4i vt = GSVector4i(v.t).xxzzl(); + + s = vt.xxxx().add16(m_env.ds); + t = vt.yyyy().add16(m_env.dt); + } + + GSVector4i vc = GSVector4i(v.c).xxzzlh(); + + r = vc.xxxx(); + g = vc.yyyy(); + b = vc.zzzz(); + + if(iip) + { + r = r.add16(m_env.dr); + g = g.add16(m_env.dg); + b = b.add16(m_env.db); + } + + GSVector4i dither; + + if(m_env.sel.dtd) + { + dither = GSVector4i::load(&s_dither[top & 3][left & 3]); + } + + int steps = right - left; + + WORD* fb = m_env.mem->GetPixelAddress(left, top); + + while(1) + { + do + { + int pixels = GSVector4i::min_i16(steps, 8); + + GSVector4i test = GSVector4i::zero(); + + GSVector4i d = GSVector4i::zero(); + + if(rfb) // me | abe + { + d = GSVector4i::load(fb); + + if(me) + { + test = d.sra16(15); + + if(test.alltrue()) + { + continue; + } + } + } + + GSVector4i c[4]; + + if(tme) + { + SampleTexture(m_env.sel.ltf, m_env.sel.tlu, twin, test, s, t, c); + } + + ColorTFX(tfx, r, g, b, c); + + if(abe) + { + AlphaBlend(abr, tme, d, c); + } + + if(m_env.sel.dtd) + { + c[0] = c[0].addus8(dither); + c[1] = c[1].addus8(dither); + c[2] = c[2].addus8(dither); + } + + WriteFrame(fb, test, c, pixels); + } + while(0); + + if(steps <= 8) break; + + steps -= 8; + + fb += 8; + + if(tme) + { + GSVector4i dst8 = m_env.dst8; + + s = s.add16(dst8.xxxx()); + t = t.add16(dst8.yyyy()); + } + + if(iip) + { + GSVector4i dc8 = m_env.dc8; + + r = r.add16(dc8.xxxx()); + g = g.add16(dc8.yyyy()); + b = b.add16(dc8.zzzz()); + } + } +} + +GPUDrawScanline::GPUDrawScanlineMap::GPUDrawScanlineMap() +{ + for(int i = 0; i < countof(m_default); i++) + { + m_default[i] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanline; + } + + #ifdef FAST_DRAWSCANLINE + + m_default[0x00] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x00>; + m_default[0x01] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x01>; + m_default[0x02] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x02>; + m_default[0x03] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x03>; + m_default[0x04] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x04>; + m_default[0x05] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x05>; + m_default[0x06] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x06>; + m_default[0x07] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x07>; + m_default[0x08] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x08>; + m_default[0x09] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x09>; + m_default[0x0a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0a>; + m_default[0x0b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0b>; + m_default[0x0c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0c>; + m_default[0x0d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0d>; + m_default[0x0e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0e>; + m_default[0x0f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0f>; + m_default[0x10] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x10>; + m_default[0x11] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x11>; + m_default[0x12] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x12>; + m_default[0x13] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x13>; + m_default[0x14] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x14>; + m_default[0x15] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x15>; + m_default[0x16] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x16>; + m_default[0x17] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x17>; + m_default[0x18] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x18>; + m_default[0x19] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x19>; + m_default[0x1a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1a>; + m_default[0x1b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1b>; + m_default[0x1c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1c>; + m_default[0x1d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1d>; + m_default[0x1e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1e>; + m_default[0x1f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1f>; + m_default[0x20] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x20>; + m_default[0x21] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x21>; + m_default[0x22] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x22>; + m_default[0x23] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x23>; + m_default[0x24] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x24>; + m_default[0x25] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x25>; + m_default[0x26] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x26>; + m_default[0x27] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x27>; + m_default[0x28] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x28>; + m_default[0x29] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x29>; + m_default[0x2a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2a>; + m_default[0x2b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2b>; + m_default[0x2c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2c>; + m_default[0x2d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2d>; + m_default[0x2e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2e>; + m_default[0x2f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2f>; + m_default[0x30] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x30>; + m_default[0x31] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x31>; + m_default[0x32] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x32>; + m_default[0x33] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x33>; + m_default[0x34] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x34>; + m_default[0x35] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x35>; + m_default[0x36] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x36>; + m_default[0x37] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x37>; + m_default[0x38] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x38>; + m_default[0x39] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x39>; + m_default[0x3a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3a>; + m_default[0x3b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3b>; + m_default[0x3c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3c>; + m_default[0x3d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3d>; + m_default[0x3e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3e>; + m_default[0x3f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3f>; + m_default[0x40] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x40>; + m_default[0x41] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x41>; + m_default[0x42] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x42>; + m_default[0x43] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x43>; + m_default[0x44] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x44>; + m_default[0x45] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x45>; + m_default[0x46] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x46>; + m_default[0x47] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x47>; + m_default[0x48] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x48>; + m_default[0x49] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x49>; + m_default[0x4a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4a>; + m_default[0x4b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4b>; + m_default[0x4c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4c>; + m_default[0x4d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4d>; + m_default[0x4e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4e>; + m_default[0x4f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4f>; + m_default[0x50] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x50>; + m_default[0x51] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x51>; + m_default[0x52] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x52>; + m_default[0x53] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x53>; + m_default[0x54] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x54>; + m_default[0x55] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x55>; + m_default[0x56] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x56>; + m_default[0x57] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x57>; + m_default[0x58] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x58>; + m_default[0x59] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x59>; + m_default[0x5a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5a>; + m_default[0x5b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5b>; + m_default[0x5c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5c>; + m_default[0x5d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5d>; + m_default[0x5e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5e>; + m_default[0x5f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5f>; + m_default[0x60] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x60>; + m_default[0x61] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x61>; + m_default[0x62] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x62>; + m_default[0x63] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x63>; + m_default[0x64] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x64>; + m_default[0x65] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x65>; + m_default[0x66] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x66>; + m_default[0x67] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x67>; + m_default[0x68] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x68>; + m_default[0x69] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x69>; + m_default[0x6a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6a>; + m_default[0x6b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6b>; + m_default[0x6c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6c>; + m_default[0x6d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6d>; + m_default[0x6e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6e>; + m_default[0x6f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6f>; + m_default[0x70] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x70>; + m_default[0x71] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x71>; + m_default[0x72] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x72>; + m_default[0x73] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x73>; + m_default[0x74] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x74>; + m_default[0x75] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x75>; + m_default[0x76] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x76>; + m_default[0x77] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x77>; + m_default[0x78] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x78>; + m_default[0x79] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x79>; + m_default[0x7a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7a>; + m_default[0x7b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7b>; + m_default[0x7c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7c>; + m_default[0x7d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7d>; + m_default[0x7e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7e>; + m_default[0x7f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7f>; + m_default[0x80] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x80>; + m_default[0x81] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x81>; + m_default[0x82] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x82>; + m_default[0x83] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x83>; + m_default[0x84] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x84>; + m_default[0x85] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x85>; + m_default[0x86] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x86>; + m_default[0x87] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x87>; + m_default[0x88] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x88>; + m_default[0x89] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x89>; + m_default[0x8a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8a>; + m_default[0x8b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8b>; + m_default[0x8c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8c>; + m_default[0x8d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8d>; + m_default[0x8e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8e>; + m_default[0x8f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8f>; + m_default[0x90] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x90>; + m_default[0x91] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x91>; + m_default[0x92] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x92>; + m_default[0x93] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x93>; + m_default[0x94] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x94>; + m_default[0x95] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x95>; + m_default[0x96] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x96>; + m_default[0x97] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x97>; + m_default[0x98] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x98>; + m_default[0x99] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x99>; + m_default[0x9a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9a>; + m_default[0x9b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9b>; + m_default[0x9c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9c>; + m_default[0x9d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9d>; + m_default[0x9e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9e>; + m_default[0x9f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9f>; + m_default[0xa0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa0>; + m_default[0xa1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa1>; + m_default[0xa2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa2>; + m_default[0xa3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa3>; + m_default[0xa4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa4>; + m_default[0xa5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa5>; + m_default[0xa6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa6>; + m_default[0xa7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa7>; + m_default[0xa8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa8>; + m_default[0xa9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa9>; + m_default[0xaa] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xaa>; + m_default[0xab] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xab>; + m_default[0xac] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xac>; + m_default[0xad] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xad>; + m_default[0xae] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xae>; + m_default[0xaf] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xaf>; + m_default[0xb0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb0>; + m_default[0xb1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb1>; + m_default[0xb2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb2>; + m_default[0xb3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb3>; + m_default[0xb4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb4>; + m_default[0xb5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb5>; + m_default[0xb6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb6>; + m_default[0xb7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb7>; + m_default[0xb8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb8>; + m_default[0xb9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb9>; + m_default[0xba] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xba>; + m_default[0xbb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbb>; + m_default[0xbc] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbc>; + m_default[0xbd] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbd>; + m_default[0xbe] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbe>; + m_default[0xbf] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbf>; + m_default[0xc0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc0>; + m_default[0xc1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc1>; + m_default[0xc2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc2>; + m_default[0xc3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc3>; + m_default[0xc4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc4>; + m_default[0xc5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc5>; + m_default[0xc6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc6>; + m_default[0xc7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc7>; + m_default[0xc8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc8>; + m_default[0xc9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc9>; + m_default[0xca] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xca>; + m_default[0xcb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xcb>; + m_default[0xcc] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xcc>; + m_default[0xcd] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xcd>; + m_default[0xce] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xce>; + m_default[0xcf] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xcf>; + m_default[0xd0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd0>; + m_default[0xd1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd1>; + m_default[0xd2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd2>; + m_default[0xd3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd3>; + m_default[0xd4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd4>; + m_default[0xd5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd5>; + m_default[0xd6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd6>; + m_default[0xd7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd7>; + m_default[0xd8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd8>; + m_default[0xd9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd9>; + m_default[0xda] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xda>; + m_default[0xdb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xdb>; + m_default[0xdc] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xdc>; + m_default[0xdd] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xdd>; + m_default[0xde] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xde>; + m_default[0xdf] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xdf>; + m_default[0xe0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe0>; + m_default[0xe1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe1>; + m_default[0xe2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe2>; + m_default[0xe3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe3>; + m_default[0xe4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe4>; + m_default[0xe5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe5>; + m_default[0xe6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe6>; + m_default[0xe7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe7>; + m_default[0xe8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe8>; + m_default[0xe9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe9>; + m_default[0xea] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xea>; + m_default[0xeb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xeb>; + m_default[0xec] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xec>; + m_default[0xed] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xed>; + m_default[0xee] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xee>; + m_default[0xef] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xef>; + m_default[0xf0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf0>; + m_default[0xf1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf1>; + m_default[0xf2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf2>; + m_default[0xf3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf3>; + m_default[0xf4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf4>; + m_default[0xf5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf5>; + m_default[0xf6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf6>; + m_default[0xf7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf7>; + m_default[0xf8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf8>; + m_default[0xf9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf9>; + m_default[0xfa] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfa>; + m_default[0xfb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfb>; + m_default[0xfc] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfc>; + m_default[0xfd] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfd>; + m_default[0xfe] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfe>; + m_default[0xff] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xff>; + + #endif +} + +IDrawScanline::DrawScanlinePtr GPUDrawScanline::GPUDrawScanlineMap::GetDefaultFunction(DWORD dw) +{ + GPUScanlineSelector sel; + + sel.dw = dw; + + return m_default[sel]; +} + +// + +GPUDrawScanline::GPUSetupPrimMap::GPUSetupPrimMap() +{ + #define InitSP_IIP(sprite, tme, iip) \ + m_default[sprite][tme][iip] = (SetupPrimPtr)&GPUDrawScanline::SetupPrim; \ + + #define InitSP_TME(sprite, tme) \ + InitSP_IIP(sprite, tme, 0) \ + InitSP_IIP(sprite, tme, 1) \ + + #define InitSP_SPRITE(sprite) \ + InitSP_TME(sprite, 0) \ + InitSP_TME(sprite, 1) \ + + InitSP_SPRITE(0); + InitSP_SPRITE(1); +} + +IDrawScanline::SetupPrimPtr GPUDrawScanline::GPUSetupPrimMap::GetDefaultFunction(DWORD dw) +{ + DWORD sprite = (dw >> 0) & 1; + DWORD tme = (dw >> 1) & 1; + DWORD iip = (dw >> 2) & 1; + + return m_default[sprite][tme][iip]; +} + diff --git a/plugins/GSdx/GPUDrawScanline.h b/plugins/GSdx/GPUDrawScanline.h index 87bb3228e0..5651580007 100644 --- a/plugins/GSdx/GPUDrawScanline.h +++ b/plugins/GSdx/GPUDrawScanline.h @@ -1,146 +1,146 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GPUState.h" -#include "GSRasterizer.h" -#include "GSAlignedClass.h" - -union GPUScanlineSelector -{ - struct - { - DWORD iip:1; // 0 - DWORD me:1; // 1 - DWORD abe:1; // 2 - DWORD abr:2; // 3 - DWORD tge:1; // 5 - DWORD tme:1; // 6 - DWORD twin:1; // 7 - DWORD tlu:1; // 8 - DWORD dtd:1; // 9 - DWORD ltf:1; // 10 - // DWORD dte:1: // 11 - }; - - struct - { - DWORD _pad1:1; // 0 - DWORD rfb:2; // 1 - DWORD _pad2:2; // 3 - DWORD tfx:2; // 5 - }; - - DWORD dw; - - operator DWORD() {return dw & 0xff;} -}; - -__declspec(align(16)) struct GPUScanlineEnvironment -{ - GPUScanlineSelector sel; - - GPULocalMemory* mem; - const void* tex; - const WORD* clut; - - GSVector4i u[3]; - GSVector4i v[3]; - - GSVector4i a; - GSVector4i md; // similar to gs fba - - GSVector4i ds, dt, dst8; - GSVector4i dr, dg, db, dc8; -}; - -__declspec(align(16)) struct GPUScanlineParam -{ - GPUScanlineSelector sel; - - const void* tex; - const WORD* clut; -}; - -class GPUDrawScanline : public GSAlignedClass<16>, public IDrawScanline -{ - GPUScanlineEnvironment m_env; - - // - - class GPUDrawScanlineMap : public GSFunctionMap - { - DrawScanlinePtr m_default[256]; - - public: - GPUDrawScanlineMap(); - - DrawScanlinePtr GetDefaultFunction(DWORD dw); - }; - - GPUDrawScanlineMap m_ds; - - // - - class GPUSetupPrimMap : public GSFunctionMap - { - SetupPrimPtr m_default[2][2][2]; - - public: - GPUSetupPrimMap(); - - SetupPrimPtr GetDefaultFunction(DWORD dw); - }; - - GPUSetupPrimMap m_sp; - - // - - template - void SetupPrim(const GSVertexSW* vertices, const GSVertexSW& dscan); - - // - - __forceinline void SampleTexture(DWORD ltf, DWORD tlu, DWORD twin, GSVector4i& test, const GSVector4i& s, const GSVector4i& t, GSVector4i* c); - __forceinline void ColorTFX(DWORD tfx, const GSVector4i& r, const GSVector4i& g, const GSVector4i& b, GSVector4i* c); - __forceinline void AlphaBlend(UINT32 abr, UINT32 tme, const GSVector4i& d, GSVector4i* c); - __forceinline void WriteFrame(WORD* RESTRICT fb, const GSVector4i& test, const GSVector4i* c, int pixels); - - void DrawScanline(int top, int left, int right, const GSVertexSW& v); - - template - void DrawScanlineEx(int top, int left, int right, const GSVertexSW& v); - -protected: - GPUState* m_state; - int m_id; - -public: - GPUDrawScanline(GPUState* state, int id); - virtual ~GPUDrawScanline(); - - // IDrawScanline - - void BeginDraw(const GSRasterizerData* data, Functions* f); - void EndDraw(const GSRasterizerStats& stats) {} - void PrintStats() {} -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GPUState.h" +#include "GSRasterizer.h" +#include "GSAlignedClass.h" + +union GPUScanlineSelector +{ + struct + { + DWORD iip:1; // 0 + DWORD me:1; // 1 + DWORD abe:1; // 2 + DWORD abr:2; // 3 + DWORD tge:1; // 5 + DWORD tme:1; // 6 + DWORD twin:1; // 7 + DWORD tlu:1; // 8 + DWORD dtd:1; // 9 + DWORD ltf:1; // 10 + // DWORD dte:1: // 11 + }; + + struct + { + DWORD _pad1:1; // 0 + DWORD rfb:2; // 1 + DWORD _pad2:2; // 3 + DWORD tfx:2; // 5 + }; + + DWORD dw; + + operator DWORD() {return dw & 0xff;} +}; + +__declspec(align(16)) struct GPUScanlineEnvironment +{ + GPUScanlineSelector sel; + + GPULocalMemory* mem; + const void* tex; + const WORD* clut; + + GSVector4i u[3]; + GSVector4i v[3]; + + GSVector4i a; + GSVector4i md; // similar to gs fba + + GSVector4i ds, dt, dst8; + GSVector4i dr, dg, db, dc8; +}; + +__declspec(align(16)) struct GPUScanlineParam +{ + GPUScanlineSelector sel; + + const void* tex; + const WORD* clut; +}; + +class GPUDrawScanline : public GSAlignedClass<16>, public IDrawScanline +{ + GPUScanlineEnvironment m_env; + + // + + class GPUDrawScanlineMap : public GSFunctionMap + { + DrawScanlinePtr m_default[256]; + + public: + GPUDrawScanlineMap(); + + DrawScanlinePtr GetDefaultFunction(DWORD dw); + }; + + GPUDrawScanlineMap m_ds; + + // + + class GPUSetupPrimMap : public GSFunctionMap + { + SetupPrimPtr m_default[2][2][2]; + + public: + GPUSetupPrimMap(); + + SetupPrimPtr GetDefaultFunction(DWORD dw); + }; + + GPUSetupPrimMap m_sp; + + // + + template + void SetupPrim(const GSVertexSW* vertices, const GSVertexSW& dscan); + + // + + __forceinline void SampleTexture(DWORD ltf, DWORD tlu, DWORD twin, GSVector4i& test, const GSVector4i& s, const GSVector4i& t, GSVector4i* c); + __forceinline void ColorTFX(DWORD tfx, const GSVector4i& r, const GSVector4i& g, const GSVector4i& b, GSVector4i* c); + __forceinline void AlphaBlend(UINT32 abr, UINT32 tme, const GSVector4i& d, GSVector4i* c); + __forceinline void WriteFrame(WORD* RESTRICT fb, const GSVector4i& test, const GSVector4i* c, int pixels); + + void DrawScanline(int top, int left, int right, const GSVertexSW& v); + + template + void DrawScanlineEx(int top, int left, int right, const GSVertexSW& v); + +protected: + GPUState* m_state; + int m_id; + +public: + GPUDrawScanline(GPUState* state, int id); + virtual ~GPUDrawScanline(); + + // IDrawScanline + + void BeginDraw(const GSRasterizerData* data, Functions* f); + void EndDraw(const GSRasterizerStats& stats) {} + void PrintStats() {} +}; diff --git a/plugins/GSdx/GPUDrawingEnvironment.h b/plugins/GSdx/GPUDrawingEnvironment.h index 2a5cd1b6e5..e42064a450 100644 --- a/plugins/GSdx/GPUDrawingEnvironment.h +++ b/plugins/GSdx/GPUDrawingEnvironment.h @@ -1,81 +1,81 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GPU.h" - -#pragma pack(push, 1) - -__declspec(align(16)) class GPUDrawingEnvironment -{ -public: - GPURegSTATUS STATUS; - GPURegPRIM PRIM; - GPURegDAREA DAREA; - GPURegDHRANGE DHRANGE; - GPURegDVRANGE DVRANGE; - GPURegDRAREA DRAREATL; - GPURegDRAREA DRAREABR; - GPURegDROFF DROFF; - GPURegTWIN TWIN; - GPURegCLUT CLUT; - - GPUDrawingEnvironment() - { - Reset(); - } - - void Reset() - { - memset(this, 0, sizeof(*this)); - - STATUS.IDLE = 1; - STATUS.COM = 1; - STATUS.WIDTH0 = 1; - DVRANGE.Y1 = 16; - DVRANGE.Y2 = 256; - } - - CRect GetDisplayRect() - { - static int s_width[] = {256, 320, 512, 640, 368, 384, 512, 640}; - static int s_height[] = {240, 480}; - - CRect r; - - r.left = DAREA.X & ~7; // FIXME - r.top = DAREA.Y; - r.right = r.left + s_width[(STATUS.WIDTH1 << 2) | STATUS.WIDTH0]; - r.bottom = r.top + (DVRANGE.Y2 - DVRANGE.Y1) * s_height[STATUS.HEIGHT] / 240; - - r &= CRect(0, 0, 1024, 512); - - return r; - } - - int GetFPS() - { - return STATUS.ISPAL ? 50 : 60; - } -}; - -#pragma pack(pop) +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GPU.h" + +#pragma pack(push, 1) + +__declspec(align(16)) class GPUDrawingEnvironment +{ +public: + GPURegSTATUS STATUS; + GPURegPRIM PRIM; + GPURegDAREA DAREA; + GPURegDHRANGE DHRANGE; + GPURegDVRANGE DVRANGE; + GPURegDRAREA DRAREATL; + GPURegDRAREA DRAREABR; + GPURegDROFF DROFF; + GPURegTWIN TWIN; + GPURegCLUT CLUT; + + GPUDrawingEnvironment() + { + Reset(); + } + + void Reset() + { + memset(this, 0, sizeof(*this)); + + STATUS.IDLE = 1; + STATUS.COM = 1; + STATUS.WIDTH0 = 1; + DVRANGE.Y1 = 16; + DVRANGE.Y2 = 256; + } + + CRect GetDisplayRect() + { + static int s_width[] = {256, 320, 512, 640, 368, 384, 512, 640}; + static int s_height[] = {240, 480}; + + CRect r; + + r.left = DAREA.X & ~7; // FIXME + r.top = DAREA.Y; + r.right = r.left + s_width[(STATUS.WIDTH1 << 2) | STATUS.WIDTH0]; + r.bottom = r.top + (DVRANGE.Y2 - DVRANGE.Y1) * s_height[STATUS.HEIGHT] / 240; + + r &= CRect(0, 0, 1024, 512); + + return r; + } + + int GetFPS() + { + return STATUS.ISPAL ? 50 : 60; + } +}; + +#pragma pack(pop) diff --git a/plugins/GSdx/GPULocalMemory.cpp b/plugins/GSdx/GPULocalMemory.cpp index b2d718e766..56cf0d1510 100644 --- a/plugins/GSdx/GPULocalMemory.cpp +++ b/plugins/GSdx/GPULocalMemory.cpp @@ -1,666 +1,666 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GPULocalMemory.h" - -const GSVector4i GPULocalMemory::m_xxxa(0x00008000); -const GSVector4i GPULocalMemory::m_xxbx(0x00007c00); -const GSVector4i GPULocalMemory::m_xgxx(0x000003e0); -const GSVector4i GPULocalMemory::m_rxxx(0x0000001f); - -GPULocalMemory::GPULocalMemory(const CSize& scale) -{ - m_scale.cx = min(max(scale.cx, 0), 2); - m_scale.cy = min(max(scale.cy, 0), 2); - - // - - int size = (1 << (12 + 11)) * sizeof(WORD); - - m_vm = (WORD*)VirtualAlloc(NULL, size * 2, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - - memset(m_vm, 0, size); - - // - - m_clut.buff = m_vm + size; - m_clut.dirty = true; - - // - - size = 256 * 256 * (1 + 1 + 4) * 32; - - m_texture.buff[0] = (BYTE*)VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - m_texture.buff[1] = m_texture.buff[0] + 256 * 256 * 32; - m_texture.buff[2] = m_texture.buff[1] + 256 * 256 * 32; - - memset(m_texture.buff[0], 0, size); - - memset(m_texture.valid, 0, sizeof(m_texture.valid)); - - for(int y = 0, offset = 0; y < 2; y++) - { - for(int x = 0; x < 16; x++, offset += 256 * 256) - { - m_texture.page[0][y][x] = &((BYTE*)m_texture.buff[0])[offset]; - m_texture.page[1][y][x] = &((BYTE*)m_texture.buff[1])[offset]; - } - } - - for(int y = 0, offset = 0; y < 2; y++) - { - for(int x = 0; x < 16; x++, offset += 256 * 256) - { - m_texture.page[2][y][x] = &((DWORD*)m_texture.buff[2])[offset]; - } - } -} - -GPULocalMemory::~GPULocalMemory() -{ - VirtualFree(m_vm, 0, MEM_RELEASE); - - VirtualFree(m_texture.buff[0], 0, MEM_RELEASE); -} - -const WORD* GPULocalMemory::GetCLUT(int tp, int cx, int cy) -{ - if(m_clut.dirty || m_clut.tp != tp || m_clut.cx != cx || m_clut.cy != cy) - { - WORD* src = GetPixelAddressScaled(cx << 4, cy); - WORD* dst = m_clut.buff; - - // TODO: at normal horizontal resolution just return src - - if(m_scale.cx == 0) - { - memcpy(dst, src, (tp == 0 ? 16 : 256) * 2); - } - else if(m_scale.cx == 1) - { - if(tp == 0) - { - for(int i = 0; i < 16; i++) - { - dst[i] = src[i * 2]; - } - } - else if(tp == 1) - { - for(int i = 0; i < 256; i++) - { - dst[i] = src[i * 2]; - } - } - } - else if(m_scale.cx == 2) - { - if(tp == 0) - { - for(int i = 0; i < 16; i++) - { - dst[i] = src[i * 4]; - } - } - else if(tp == 1) - { - for(int i = 0; i < 256; i++) - { - dst[i] = src[i * 4]; - } - } - } - else - { - ASSERT(0); - } - - m_clut.tp = tp; - m_clut.cx = cx; - m_clut.cy = cy; - m_clut.dirty = false; - } - - return m_clut.buff; -} - -const void* GPULocalMemory::GetTexture(int tp, int tx, int ty) -{ - if(tp == 3) - { - ASSERT(0); - - return NULL; - } - - void* buff = m_texture.page[tp][ty][tx]; - - UINT32 flag = 1 << tx; - - if((m_texture.valid[tp][ty] & flag) == 0) - { - int bpp = 0; - - switch(tp) - { - case 0: - ReadPage4(tx, ty, (BYTE*)buff); - bpp = 4; - break; - case 1: - ReadPage8(tx, ty, (BYTE*)buff); - bpp = 8; - break; - case 2: - case 3: - ReadPage16(tx, ty, (WORD*)buff); - bpp = 16; - default: - // FIXME: __assume(0); // vc9 generates bogus code in release mode - break; - } - - // TODO: m_state->m_perfmon.Put(GSPerfMon::Unswizzle, 256 * 256 * bpp >> 3); - - m_texture.valid[tp][ty] |= flag; - } - - return buff; -} - -void GPULocalMemory::Invalidate(const CRect& r) -{ - if(!m_clut.dirty) - { - if(r.top <= m_clut.cy && m_clut.cy < r.bottom) - { - int left = m_clut.cx << 4; - int right = left + (m_clut.tp == 0 ? 16 : 256); - - if(r.left < right && r.right > left) - { - m_clut.dirty = true; - } - } - } - - for(int y = 0, ye = min(r.bottom, 512), j = 0; y < ye; y += 256, j++) - { - if(r.top >= y + 256) continue; - - for(int x = 0, xe = min(r.right, 1024), i = 0; x < xe; x += 64, i++) - { - DWORD flag = 1 << i; - - if(r.left >= x + 256) continue; - - m_texture.valid[2][j] &= ~flag; - - if(r.left >= x + 128) continue; - - m_texture.valid[1][j] &= ~flag; - - if(r.left >= x + 64) continue; - - m_texture.valid[0][j] &= ~flag; - } - } -} - -void GPULocalMemory::FillRect(const CRect& r, WORD c) -{ - Invalidate(r); - - WORD* RESTRICT dst = GetPixelAddressScaled(r.left, r.top); - - int w = r.Width() << m_scale.cx; - int h = r.Height() << m_scale.cy; - - int pitch = GetWidth(); - - for(int j = 0; j < h; j++, dst += pitch) - { - for(int i = 0; i < w; i++) - { - dst[i] = c; - } - } -} - -void GPULocalMemory::WriteRect(const CRect& r, const WORD* RESTRICT src) -{ - Invalidate(r); - - WORD* RESTRICT dst = GetPixelAddressScaled(r.left, r.top); - - int w = r.Width(); - int h = r.Height(); - - int pitch = GetWidth(); - - if(m_scale.cx == 0) - { - for(int j = 0; j < h; j++, src += w) - { - for(int k = 1 << m_scale.cy; k >= 1; k--, dst += pitch) - { - memcpy(dst, src, w * 2); - } - } - } - else if(m_scale.cx == 1) - { - for(int j = 0; j < h; j++, src += w) - { - for(int k = 1 << m_scale.cy; k >= 1; k--, dst += pitch) - { - for(int i = 0; i < w; i++) - { - dst[i * 2 + 0] = src[i]; - dst[i * 2 + 1] = src[i]; - } - } - } - } - else if(m_scale.cx == 2) - { - for(int j = 0; j < h; j++, src += w) - { - for(int k = 1 << m_scale.cy; k >= 1; k--, dst += pitch) - { - for(int i = 0; i < w; i++) - { - dst[i * 4 + 0] = src[i]; - dst[i * 4 + 1] = src[i]; - dst[i * 4 + 2] = src[i]; - dst[i * 4 + 3] = src[i]; - } - } - } - } - else - { - ASSERT(0); - } -} - -void GPULocalMemory::ReadRect(const CRect& r, WORD* RESTRICT dst) -{ - WORD* RESTRICT src = GetPixelAddressScaled(r.left, r.top); - - int w = r.Width(); - int h = r.Height(); - - int pitch = GetWidth() << m_scale.cy; - - if(m_scale.cx == 0) - { - for(int j = 0; j < h; j++, src += pitch, dst += w) - { - memcpy(dst, src, w * 2); - } - } - else if(m_scale.cx == 1) - { - for(int j = 0; j < h; j++, src += pitch, dst += w) - { - for(int i = 0; i < w; i++) - { - dst[i] = src[i * 2]; - } - } - } - else if(m_scale.cx == 2) - { - for(int j = 0; j < h; j++, src += pitch, dst += w) - { - for(int i = 0; i < w; i++) - { - dst[i] = src[i * 4]; - } - } - } - else - { - ASSERT(0); - } -} - -void GPULocalMemory::MoveRect(const CPoint& src, const CPoint& dst, int w, int h) -{ - Invalidate(CRect(dst, CSize(w, h))); - - WORD* s = GetPixelAddressScaled(src.x, src.y); - WORD* d = GetPixelAddressScaled(dst.x, dst.y); - - w <<= m_scale.cx; - h <<= m_scale.cy; - - int pitch = GetWidth(); - - for(int i = 0; i < h; i++, s += pitch, d += pitch) - { - memcpy(d, s, w * sizeof(WORD)); - } -} - -void GPULocalMemory::ReadPage4(int tx, int ty, BYTE* RESTRICT dst) -{ - WORD* src = GetPixelAddressScaled(tx << 6, ty << 8); - - int pitch = GetWidth() << m_scale.cy; - - if(m_scale.cx == 0) - { - for(int j = 0; j < 256; j++, src += pitch, dst += 256) - { - for(int i = 0; i < 64; i++) - { - dst[i * 4 + 0] = (src[i] >> 0) & 0xf; - dst[i * 4 + 1] = (src[i] >> 4) & 0xf; - dst[i * 4 + 2] = (src[i] >> 8) & 0xf; - dst[i * 4 + 3] = (src[i] >> 12) & 0xf; - } - } - } - else if(m_scale.cx == 1) - { - for(int j = 0; j < 256; j++, src += pitch, dst += 256) - { - for(int i = 0; i < 64; i++) - { - dst[i * 4 + 0] = (src[i * 2] >> 0) & 0xf; - dst[i * 4 + 1] = (src[i * 2] >> 4) & 0xf; - dst[i * 4 + 2] = (src[i * 2] >> 8) & 0xf; - dst[i * 4 + 3] = (src[i * 2] >> 12) & 0xf; - } - } - } - else if(m_scale.cx == 2) - { - for(int j = 0; j < 256; j++, src += pitch, dst += 256) - { - for(int i = 0; i < 64; i++) - { - dst[i * 4 + 0] = (src[i * 4] >> 0) & 0xf; - dst[i * 4 + 1] = (src[i * 4] >> 4) & 0xf; - dst[i * 4 + 2] = (src[i * 4] >> 8) & 0xf; - dst[i * 4 + 3] = (src[i * 4] >> 12) & 0xf; - } - } - } - else - { - ASSERT(0); - } -} - -void GPULocalMemory::ReadPage8(int tx, int ty, BYTE* RESTRICT dst) -{ - WORD* src = GetPixelAddressScaled(tx << 6, ty << 8); - - int pitch = GetWidth() << m_scale.cy; - - if(m_scale.cx == 0) - { - for(int j = 0; j < 256; j++, src += pitch, dst += 256) - { - memcpy(dst, src, 256); - } - } - else if(m_scale.cx == 1) - { - for(int j = 0; j < 256; j++, src += pitch, dst += 256) - { - for(int i = 0; i < 128; i++) - { - ((WORD*)dst)[i] = src[i * 2]; - } - } - } - else if(m_scale.cx == 2) - { - for(int j = 0; j < 256; j++, src += pitch, dst += 256) - { - for(int i = 0; i < 128; i++) - { - ((WORD*)dst)[i] = src[i * 4]; - } - } - } - else - { - ASSERT(0); - } -} - -void GPULocalMemory::ReadPage16(int tx, int ty, WORD* RESTRICT dst) -{ - WORD* src = GetPixelAddressScaled(tx << 6, ty << 8); - - int pitch = GetWidth() << m_scale.cy; - - if(m_scale.cx == 0) - { - for(int j = 0; j < 256; j++, src += pitch, dst += 256) - { - memcpy(dst, src, 512); - } - } - else if(m_scale.cx == 1) - { - for(int j = 0; j < 256; j++, src += pitch, dst += 256) - { - for(int i = 0; i < 256; i++) - { - dst[i] = src[i * 2]; - } - } - } - else if(m_scale.cx == 2) - { - for(int j = 0; j < 256; j++, src += pitch, dst += 256) - { - for(int i = 0; i < 256; i++) - { - dst[i] = src[i * 4]; - } - } - } - else - { - ASSERT(0); - } -} - -void GPULocalMemory::ReadFrame32(const CRect& r, DWORD* RESTRICT dst, bool rgb24) -{ - WORD* src = GetPixelAddress(r.left, r.top); - - int pitch = GetWidth(); - - if(rgb24) - { - for(int i = r.top; i < r.bottom; i++, src += pitch, dst += pitch) - { - Expand24(src, dst, r.Width()); - } - } - else - { - for(int i = r.top; i < r.bottom; i++, src += pitch, dst += pitch) - { - Expand16(src, dst, r.Width()); - } - } -} - -void GPULocalMemory::Expand16(const WORD* RESTRICT src, DWORD* RESTRICT dst, int pixels) -{ - GSVector4i rm = m_rxxx; - GSVector4i gm = m_xgxx; - GSVector4i bm = m_xxbx; - GSVector4i am = m_xxxa; - - GSVector4i* s = (GSVector4i*)src; - GSVector4i* d = (GSVector4i*)dst; - - for(int i = 0, j = pixels >> 3; i < j; i++) - { - GSVector4i c = s[i]; - - GSVector4i l = c.upl16(); - GSVector4i h = c.uph16(); - - d[i * 2 + 0] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | ((l & am) << 16); - d[i * 2 + 1] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | ((h & am) << 16); - } -} - -void GPULocalMemory::Expand24(const WORD* RESTRICT src, DWORD* RESTRICT dst, int pixels) -{ - BYTE* s = (BYTE*)src; - - if(m_scale.cx == 0) - { - for(int i = 0; i < pixels; i += 2, s += 6) - { - dst[i + 0] = (s[2] << 16) | (s[1] << 8) | s[0]; - dst[i + 1] = (s[5] << 16) | (s[4] << 8) | s[3]; - } - } - else if(m_scale.cx == 1) - { - for(int i = 0; i < pixels; i += 4, s += 12) - { - dst[i + 0] = dst[i + 1] = (s[4] << 16) | (s[1] << 8) | s[0]; - dst[i + 2] = dst[i + 3] = (s[9] << 16) | (s[8] << 8) | s[5]; - } - } - else if(m_scale.cx == 2) - { - for(int i = 0; i < pixels; i += 8, s += 24) - { - dst[i + 0] = dst[i + 1] = dst[i + 2] = dst[i + 3] = (s[8] << 16) | (s[1] << 8) | s[0]; - dst[i + 4] = dst[i + 5] = dst[i + 6] = dst[i + 7] = (s[17] << 16) | (s[16] << 8) | s[9]; - } - } - else - { - ASSERT(0); - } -} - -void GPULocalMemory::SaveBMP(LPCTSTR path, CRect r, int tp, int cx, int cy) -{ - r.left <<= m_scale.cx; - r.top <<= m_scale.cy; - r.right <<= m_scale.cx; - r.bottom <<= m_scale.cy; - - r.left &= ~1; - r.right &= ~1; - - if(FILE* fp = _tfopen(path, _T("wb"))) - { - BITMAPINFOHEADER bih; - memset(&bih, 0, sizeof(bih)); - bih.biSize = sizeof(bih); - bih.biWidth = r.Width(); - bih.biHeight = r.Height(); - bih.biPlanes = 1; - bih.biBitCount = 32; - bih.biCompression = BI_RGB; - bih.biSizeImage = bih.biWidth * bih.biHeight * 4; - - BITMAPFILEHEADER bfh; - memset(&bfh, 0, sizeof(bfh)); - bfh.bfType = 'MB'; - bfh.bfOffBits = sizeof(bfh) + sizeof(bih); - bfh.bfSize = bfh.bfOffBits + bih.biSizeImage; - bfh.bfReserved1 = bfh.bfReserved2 = 0; - - fwrite(&bfh, 1, sizeof(bfh), fp); - fwrite(&bih, 1, sizeof(bih), fp); - - int pitch = GetWidth(); - - WORD* buff = (WORD*)_aligned_malloc(pitch * sizeof(WORD), 16); - DWORD* buff32 = (DWORD*)_aligned_malloc(pitch * sizeof(DWORD), 16); - WORD* src = GetPixelAddress(r.left, r.bottom - 1); - const WORD* clut = GetCLUT(tp, cx, cy); - - for(int j = r.bottom - 1; j >= r.top; j--, src -= pitch) - { - switch(tp) - { - case 0: // 4 bpp - - for(int i = 0, k = r.Width() / 2; i < k; i++) - { - buff[i * 2 + 0] = clut[((BYTE*)src)[i] & 0xf]; - buff[i * 2 + 1] = clut[((BYTE*)src)[i] >> 4]; - } - - break; - - case 1: // 8 bpp - - for(int i = 0, k = r.Width(); i < k; i++) - { - buff[i] = clut[((BYTE*)src)[i]]; - } - - break; - - case 2: // 16 bpp; - - for(int i = 0, k = r.Width(); i < k; i++) - { - buff[i] = src[i]; - } - - break; - - case 3: // 24 bpp - - // TODO - - break; - } - - Expand16(buff, buff32, r.Width()); - - for(int i = 0, k = r.Width(); i < k; i++) - { - buff32[i] = (buff32[i] & 0xff00ff00) | ((buff32[i] & 0x00ff0000) >> 16) | ((buff32[i] & 0x000000ff) << 16); - } - - fwrite(buff32, 1, r.Width() * 4, fp); - } - - _aligned_free(buff); - _aligned_free(buff32); - - fclose(fp); - } -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GPULocalMemory.h" + +const GSVector4i GPULocalMemory::m_xxxa(0x00008000); +const GSVector4i GPULocalMemory::m_xxbx(0x00007c00); +const GSVector4i GPULocalMemory::m_xgxx(0x000003e0); +const GSVector4i GPULocalMemory::m_rxxx(0x0000001f); + +GPULocalMemory::GPULocalMemory(const CSize& scale) +{ + m_scale.cx = min(max(scale.cx, 0), 2); + m_scale.cy = min(max(scale.cy, 0), 2); + + // + + int size = (1 << (12 + 11)) * sizeof(WORD); + + m_vm = (WORD*)VirtualAlloc(NULL, size * 2, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + + memset(m_vm, 0, size); + + // + + m_clut.buff = m_vm + size; + m_clut.dirty = true; + + // + + size = 256 * 256 * (1 + 1 + 4) * 32; + + m_texture.buff[0] = (BYTE*)VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + m_texture.buff[1] = m_texture.buff[0] + 256 * 256 * 32; + m_texture.buff[2] = m_texture.buff[1] + 256 * 256 * 32; + + memset(m_texture.buff[0], 0, size); + + memset(m_texture.valid, 0, sizeof(m_texture.valid)); + + for(int y = 0, offset = 0; y < 2; y++) + { + for(int x = 0; x < 16; x++, offset += 256 * 256) + { + m_texture.page[0][y][x] = &((BYTE*)m_texture.buff[0])[offset]; + m_texture.page[1][y][x] = &((BYTE*)m_texture.buff[1])[offset]; + } + } + + for(int y = 0, offset = 0; y < 2; y++) + { + for(int x = 0; x < 16; x++, offset += 256 * 256) + { + m_texture.page[2][y][x] = &((DWORD*)m_texture.buff[2])[offset]; + } + } +} + +GPULocalMemory::~GPULocalMemory() +{ + VirtualFree(m_vm, 0, MEM_RELEASE); + + VirtualFree(m_texture.buff[0], 0, MEM_RELEASE); +} + +const WORD* GPULocalMemory::GetCLUT(int tp, int cx, int cy) +{ + if(m_clut.dirty || m_clut.tp != tp || m_clut.cx != cx || m_clut.cy != cy) + { + WORD* src = GetPixelAddressScaled(cx << 4, cy); + WORD* dst = m_clut.buff; + + // TODO: at normal horizontal resolution just return src + + if(m_scale.cx == 0) + { + memcpy(dst, src, (tp == 0 ? 16 : 256) * 2); + } + else if(m_scale.cx == 1) + { + if(tp == 0) + { + for(int i = 0; i < 16; i++) + { + dst[i] = src[i * 2]; + } + } + else if(tp == 1) + { + for(int i = 0; i < 256; i++) + { + dst[i] = src[i * 2]; + } + } + } + else if(m_scale.cx == 2) + { + if(tp == 0) + { + for(int i = 0; i < 16; i++) + { + dst[i] = src[i * 4]; + } + } + else if(tp == 1) + { + for(int i = 0; i < 256; i++) + { + dst[i] = src[i * 4]; + } + } + } + else + { + ASSERT(0); + } + + m_clut.tp = tp; + m_clut.cx = cx; + m_clut.cy = cy; + m_clut.dirty = false; + } + + return m_clut.buff; +} + +const void* GPULocalMemory::GetTexture(int tp, int tx, int ty) +{ + if(tp == 3) + { + ASSERT(0); + + return NULL; + } + + void* buff = m_texture.page[tp][ty][tx]; + + UINT32 flag = 1 << tx; + + if((m_texture.valid[tp][ty] & flag) == 0) + { + int bpp = 0; + + switch(tp) + { + case 0: + ReadPage4(tx, ty, (BYTE*)buff); + bpp = 4; + break; + case 1: + ReadPage8(tx, ty, (BYTE*)buff); + bpp = 8; + break; + case 2: + case 3: + ReadPage16(tx, ty, (WORD*)buff); + bpp = 16; + default: + // FIXME: __assume(0); // vc9 generates bogus code in release mode + break; + } + + // TODO: m_state->m_perfmon.Put(GSPerfMon::Unswizzle, 256 * 256 * bpp >> 3); + + m_texture.valid[tp][ty] |= flag; + } + + return buff; +} + +void GPULocalMemory::Invalidate(const CRect& r) +{ + if(!m_clut.dirty) + { + if(r.top <= m_clut.cy && m_clut.cy < r.bottom) + { + int left = m_clut.cx << 4; + int right = left + (m_clut.tp == 0 ? 16 : 256); + + if(r.left < right && r.right > left) + { + m_clut.dirty = true; + } + } + } + + for(int y = 0, ye = min(r.bottom, 512), j = 0; y < ye; y += 256, j++) + { + if(r.top >= y + 256) continue; + + for(int x = 0, xe = min(r.right, 1024), i = 0; x < xe; x += 64, i++) + { + DWORD flag = 1 << i; + + if(r.left >= x + 256) continue; + + m_texture.valid[2][j] &= ~flag; + + if(r.left >= x + 128) continue; + + m_texture.valid[1][j] &= ~flag; + + if(r.left >= x + 64) continue; + + m_texture.valid[0][j] &= ~flag; + } + } +} + +void GPULocalMemory::FillRect(const CRect& r, WORD c) +{ + Invalidate(r); + + WORD* RESTRICT dst = GetPixelAddressScaled(r.left, r.top); + + int w = r.Width() << m_scale.cx; + int h = r.Height() << m_scale.cy; + + int pitch = GetWidth(); + + for(int j = 0; j < h; j++, dst += pitch) + { + for(int i = 0; i < w; i++) + { + dst[i] = c; + } + } +} + +void GPULocalMemory::WriteRect(const CRect& r, const WORD* RESTRICT src) +{ + Invalidate(r); + + WORD* RESTRICT dst = GetPixelAddressScaled(r.left, r.top); + + int w = r.Width(); + int h = r.Height(); + + int pitch = GetWidth(); + + if(m_scale.cx == 0) + { + for(int j = 0; j < h; j++, src += w) + { + for(int k = 1 << m_scale.cy; k >= 1; k--, dst += pitch) + { + memcpy(dst, src, w * 2); + } + } + } + else if(m_scale.cx == 1) + { + for(int j = 0; j < h; j++, src += w) + { + for(int k = 1 << m_scale.cy; k >= 1; k--, dst += pitch) + { + for(int i = 0; i < w; i++) + { + dst[i * 2 + 0] = src[i]; + dst[i * 2 + 1] = src[i]; + } + } + } + } + else if(m_scale.cx == 2) + { + for(int j = 0; j < h; j++, src += w) + { + for(int k = 1 << m_scale.cy; k >= 1; k--, dst += pitch) + { + for(int i = 0; i < w; i++) + { + dst[i * 4 + 0] = src[i]; + dst[i * 4 + 1] = src[i]; + dst[i * 4 + 2] = src[i]; + dst[i * 4 + 3] = src[i]; + } + } + } + } + else + { + ASSERT(0); + } +} + +void GPULocalMemory::ReadRect(const CRect& r, WORD* RESTRICT dst) +{ + WORD* RESTRICT src = GetPixelAddressScaled(r.left, r.top); + + int w = r.Width(); + int h = r.Height(); + + int pitch = GetWidth() << m_scale.cy; + + if(m_scale.cx == 0) + { + for(int j = 0; j < h; j++, src += pitch, dst += w) + { + memcpy(dst, src, w * 2); + } + } + else if(m_scale.cx == 1) + { + for(int j = 0; j < h; j++, src += pitch, dst += w) + { + for(int i = 0; i < w; i++) + { + dst[i] = src[i * 2]; + } + } + } + else if(m_scale.cx == 2) + { + for(int j = 0; j < h; j++, src += pitch, dst += w) + { + for(int i = 0; i < w; i++) + { + dst[i] = src[i * 4]; + } + } + } + else + { + ASSERT(0); + } +} + +void GPULocalMemory::MoveRect(const CPoint& src, const CPoint& dst, int w, int h) +{ + Invalidate(CRect(dst, CSize(w, h))); + + WORD* s = GetPixelAddressScaled(src.x, src.y); + WORD* d = GetPixelAddressScaled(dst.x, dst.y); + + w <<= m_scale.cx; + h <<= m_scale.cy; + + int pitch = GetWidth(); + + for(int i = 0; i < h; i++, s += pitch, d += pitch) + { + memcpy(d, s, w * sizeof(WORD)); + } +} + +void GPULocalMemory::ReadPage4(int tx, int ty, BYTE* RESTRICT dst) +{ + WORD* src = GetPixelAddressScaled(tx << 6, ty << 8); + + int pitch = GetWidth() << m_scale.cy; + + if(m_scale.cx == 0) + { + for(int j = 0; j < 256; j++, src += pitch, dst += 256) + { + for(int i = 0; i < 64; i++) + { + dst[i * 4 + 0] = (src[i] >> 0) & 0xf; + dst[i * 4 + 1] = (src[i] >> 4) & 0xf; + dst[i * 4 + 2] = (src[i] >> 8) & 0xf; + dst[i * 4 + 3] = (src[i] >> 12) & 0xf; + } + } + } + else if(m_scale.cx == 1) + { + for(int j = 0; j < 256; j++, src += pitch, dst += 256) + { + for(int i = 0; i < 64; i++) + { + dst[i * 4 + 0] = (src[i * 2] >> 0) & 0xf; + dst[i * 4 + 1] = (src[i * 2] >> 4) & 0xf; + dst[i * 4 + 2] = (src[i * 2] >> 8) & 0xf; + dst[i * 4 + 3] = (src[i * 2] >> 12) & 0xf; + } + } + } + else if(m_scale.cx == 2) + { + for(int j = 0; j < 256; j++, src += pitch, dst += 256) + { + for(int i = 0; i < 64; i++) + { + dst[i * 4 + 0] = (src[i * 4] >> 0) & 0xf; + dst[i * 4 + 1] = (src[i * 4] >> 4) & 0xf; + dst[i * 4 + 2] = (src[i * 4] >> 8) & 0xf; + dst[i * 4 + 3] = (src[i * 4] >> 12) & 0xf; + } + } + } + else + { + ASSERT(0); + } +} + +void GPULocalMemory::ReadPage8(int tx, int ty, BYTE* RESTRICT dst) +{ + WORD* src = GetPixelAddressScaled(tx << 6, ty << 8); + + int pitch = GetWidth() << m_scale.cy; + + if(m_scale.cx == 0) + { + for(int j = 0; j < 256; j++, src += pitch, dst += 256) + { + memcpy(dst, src, 256); + } + } + else if(m_scale.cx == 1) + { + for(int j = 0; j < 256; j++, src += pitch, dst += 256) + { + for(int i = 0; i < 128; i++) + { + ((WORD*)dst)[i] = src[i * 2]; + } + } + } + else if(m_scale.cx == 2) + { + for(int j = 0; j < 256; j++, src += pitch, dst += 256) + { + for(int i = 0; i < 128; i++) + { + ((WORD*)dst)[i] = src[i * 4]; + } + } + } + else + { + ASSERT(0); + } +} + +void GPULocalMemory::ReadPage16(int tx, int ty, WORD* RESTRICT dst) +{ + WORD* src = GetPixelAddressScaled(tx << 6, ty << 8); + + int pitch = GetWidth() << m_scale.cy; + + if(m_scale.cx == 0) + { + for(int j = 0; j < 256; j++, src += pitch, dst += 256) + { + memcpy(dst, src, 512); + } + } + else if(m_scale.cx == 1) + { + for(int j = 0; j < 256; j++, src += pitch, dst += 256) + { + for(int i = 0; i < 256; i++) + { + dst[i] = src[i * 2]; + } + } + } + else if(m_scale.cx == 2) + { + for(int j = 0; j < 256; j++, src += pitch, dst += 256) + { + for(int i = 0; i < 256; i++) + { + dst[i] = src[i * 4]; + } + } + } + else + { + ASSERT(0); + } +} + +void GPULocalMemory::ReadFrame32(const CRect& r, DWORD* RESTRICT dst, bool rgb24) +{ + WORD* src = GetPixelAddress(r.left, r.top); + + int pitch = GetWidth(); + + if(rgb24) + { + for(int i = r.top; i < r.bottom; i++, src += pitch, dst += pitch) + { + Expand24(src, dst, r.Width()); + } + } + else + { + for(int i = r.top; i < r.bottom; i++, src += pitch, dst += pitch) + { + Expand16(src, dst, r.Width()); + } + } +} + +void GPULocalMemory::Expand16(const WORD* RESTRICT src, DWORD* RESTRICT dst, int pixels) +{ + GSVector4i rm = m_rxxx; + GSVector4i gm = m_xgxx; + GSVector4i bm = m_xxbx; + GSVector4i am = m_xxxa; + + GSVector4i* s = (GSVector4i*)src; + GSVector4i* d = (GSVector4i*)dst; + + for(int i = 0, j = pixels >> 3; i < j; i++) + { + GSVector4i c = s[i]; + + GSVector4i l = c.upl16(); + GSVector4i h = c.uph16(); + + d[i * 2 + 0] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | ((l & am) << 16); + d[i * 2 + 1] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | ((h & am) << 16); + } +} + +void GPULocalMemory::Expand24(const WORD* RESTRICT src, DWORD* RESTRICT dst, int pixels) +{ + BYTE* s = (BYTE*)src; + + if(m_scale.cx == 0) + { + for(int i = 0; i < pixels; i += 2, s += 6) + { + dst[i + 0] = (s[2] << 16) | (s[1] << 8) | s[0]; + dst[i + 1] = (s[5] << 16) | (s[4] << 8) | s[3]; + } + } + else if(m_scale.cx == 1) + { + for(int i = 0; i < pixels; i += 4, s += 12) + { + dst[i + 0] = dst[i + 1] = (s[4] << 16) | (s[1] << 8) | s[0]; + dst[i + 2] = dst[i + 3] = (s[9] << 16) | (s[8] << 8) | s[5]; + } + } + else if(m_scale.cx == 2) + { + for(int i = 0; i < pixels; i += 8, s += 24) + { + dst[i + 0] = dst[i + 1] = dst[i + 2] = dst[i + 3] = (s[8] << 16) | (s[1] << 8) | s[0]; + dst[i + 4] = dst[i + 5] = dst[i + 6] = dst[i + 7] = (s[17] << 16) | (s[16] << 8) | s[9]; + } + } + else + { + ASSERT(0); + } +} + +void GPULocalMemory::SaveBMP(LPCTSTR path, CRect r, int tp, int cx, int cy) +{ + r.left <<= m_scale.cx; + r.top <<= m_scale.cy; + r.right <<= m_scale.cx; + r.bottom <<= m_scale.cy; + + r.left &= ~1; + r.right &= ~1; + + if(FILE* fp = _tfopen(path, _T("wb"))) + { + BITMAPINFOHEADER bih; + memset(&bih, 0, sizeof(bih)); + bih.biSize = sizeof(bih); + bih.biWidth = r.Width(); + bih.biHeight = r.Height(); + bih.biPlanes = 1; + bih.biBitCount = 32; + bih.biCompression = BI_RGB; + bih.biSizeImage = bih.biWidth * bih.biHeight * 4; + + BITMAPFILEHEADER bfh; + memset(&bfh, 0, sizeof(bfh)); + bfh.bfType = 'MB'; + bfh.bfOffBits = sizeof(bfh) + sizeof(bih); + bfh.bfSize = bfh.bfOffBits + bih.biSizeImage; + bfh.bfReserved1 = bfh.bfReserved2 = 0; + + fwrite(&bfh, 1, sizeof(bfh), fp); + fwrite(&bih, 1, sizeof(bih), fp); + + int pitch = GetWidth(); + + WORD* buff = (WORD*)_aligned_malloc(pitch * sizeof(WORD), 16); + DWORD* buff32 = (DWORD*)_aligned_malloc(pitch * sizeof(DWORD), 16); + WORD* src = GetPixelAddress(r.left, r.bottom - 1); + const WORD* clut = GetCLUT(tp, cx, cy); + + for(int j = r.bottom - 1; j >= r.top; j--, src -= pitch) + { + switch(tp) + { + case 0: // 4 bpp + + for(int i = 0, k = r.Width() / 2; i < k; i++) + { + buff[i * 2 + 0] = clut[((BYTE*)src)[i] & 0xf]; + buff[i * 2 + 1] = clut[((BYTE*)src)[i] >> 4]; + } + + break; + + case 1: // 8 bpp + + for(int i = 0, k = r.Width(); i < k; i++) + { + buff[i] = clut[((BYTE*)src)[i]]; + } + + break; + + case 2: // 16 bpp; + + for(int i = 0, k = r.Width(); i < k; i++) + { + buff[i] = src[i]; + } + + break; + + case 3: // 24 bpp + + // TODO + + break; + } + + Expand16(buff, buff32, r.Width()); + + for(int i = 0, k = r.Width(); i < k; i++) + { + buff32[i] = (buff32[i] & 0xff00ff00) | ((buff32[i] & 0x00ff0000) >> 16) | ((buff32[i] & 0x000000ff) << 16); + } + + fwrite(buff32, 1, r.Width() * 4, fp); + } + + _aligned_free(buff); + _aligned_free(buff32); + + fclose(fp); + } +} diff --git a/plugins/GSdx/GPULocalMemory.h b/plugins/GSdx/GPULocalMemory.h index 85e90155a1..4d7111e7d4 100644 --- a/plugins/GSdx/GPULocalMemory.h +++ b/plugins/GSdx/GPULocalMemory.h @@ -1,85 +1,85 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GPU.h" -#include "GSVector.h" - -class GPULocalMemory -{ - static const GSVector4i m_xxxa; - static const GSVector4i m_xxbx; - static const GSVector4i m_xgxx; - static const GSVector4i m_rxxx; - - WORD* m_vm; - - struct - { - WORD* buff; - int tp, cx, cy; - bool dirty; - } m_clut; - - struct - { - BYTE* buff[3]; - void* page[3][2][16]; - WORD valid[3][2]; - } m_texture; - - CSize m_scale; - -public: - GPULocalMemory(const CSize& scale); - virtual ~GPULocalMemory(); - - CSize GetScale() {return m_scale;} - int GetWidth() {return 1 << (10 + m_scale.cx);} - int GetHeight() {return 1 << (9 + m_scale.cy);} - - WORD* GetPixelAddress(int x, int y) const {return &m_vm[(y << (10 + m_scale.cx)) + x];} - WORD* GetPixelAddressScaled(int x, int y) const {return &m_vm[((y << m_scale.cy) << (10 + m_scale.cx)) + (x << m_scale.cx)];} - - const WORD* GetCLUT(int tp, int cx, int cy); - const void* GetTexture(int tp, int tx, int ty); - - void Invalidate(const CRect& r); - - void FillRect(const CRect& r, WORD c); - void WriteRect(const CRect& r, const WORD* RESTRICT src); - void ReadRect(const CRect& r, WORD* RESTRICT dst); - void MoveRect(const CPoint& src, const CPoint& dst, int w, int h); - - void ReadPage4(int tx, int ty, BYTE* RESTRICT dst); - void ReadPage8(int tx, int ty, BYTE* RESTRICT dst); - void ReadPage16(int tx, int ty, WORD* RESTRICT dst); - - void ReadFrame32(const CRect& r, DWORD* RESTRICT dst, bool rgb24); - - void Expand16(const WORD* RESTRICT src, DWORD* RESTRICT dst, int pixels); - void Expand24(const WORD* RESTRICT src, DWORD* RESTRICT dst, int pixels); - - void SaveBMP(LPCTSTR path, CRect r, int tp, int cx, int cy); -}; - +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GPU.h" +#include "GSVector.h" + +class GPULocalMemory +{ + static const GSVector4i m_xxxa; + static const GSVector4i m_xxbx; + static const GSVector4i m_xgxx; + static const GSVector4i m_rxxx; + + WORD* m_vm; + + struct + { + WORD* buff; + int tp, cx, cy; + bool dirty; + } m_clut; + + struct + { + BYTE* buff[3]; + void* page[3][2][16]; + WORD valid[3][2]; + } m_texture; + + CSize m_scale; + +public: + GPULocalMemory(const CSize& scale); + virtual ~GPULocalMemory(); + + CSize GetScale() {return m_scale;} + int GetWidth() {return 1 << (10 + m_scale.cx);} + int GetHeight() {return 1 << (9 + m_scale.cy);} + + WORD* GetPixelAddress(int x, int y) const {return &m_vm[(y << (10 + m_scale.cx)) + x];} + WORD* GetPixelAddressScaled(int x, int y) const {return &m_vm[((y << m_scale.cy) << (10 + m_scale.cx)) + (x << m_scale.cx)];} + + const WORD* GetCLUT(int tp, int cx, int cy); + const void* GetTexture(int tp, int tx, int ty); + + void Invalidate(const CRect& r); + + void FillRect(const CRect& r, WORD c); + void WriteRect(const CRect& r, const WORD* RESTRICT src); + void ReadRect(const CRect& r, WORD* RESTRICT dst); + void MoveRect(const CPoint& src, const CPoint& dst, int w, int h); + + void ReadPage4(int tx, int ty, BYTE* RESTRICT dst); + void ReadPage8(int tx, int ty, BYTE* RESTRICT dst); + void ReadPage16(int tx, int ty, WORD* RESTRICT dst); + + void ReadFrame32(const CRect& r, DWORD* RESTRICT dst, bool rgb24); + + void Expand16(const WORD* RESTRICT src, DWORD* RESTRICT dst, int pixels); + void Expand24(const WORD* RESTRICT src, DWORD* RESTRICT dst, int pixels); + + void SaveBMP(LPCTSTR path, CRect r, int tp, int cx, int cy); +}; + #pragma warning(default: 4244) \ No newline at end of file diff --git a/plugins/GSdx/GPURenderer.cpp b/plugins/GSdx/GPURenderer.cpp index d53b3cc612..8680530c07 100644 --- a/plugins/GSdx/GPURenderer.cpp +++ b/plugins/GSdx/GPURenderer.cpp @@ -1,25 +1,25 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GPURenderer.h" - +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GPURenderer.h" + CAtlMap GPURendererBase::m_wnd2gpu; \ No newline at end of file diff --git a/plugins/GSdx/GPURenderer.h b/plugins/GSdx/GPURenderer.h index b45abd91bf..96ff0df01f 100644 --- a/plugins/GSdx/GPURenderer.h +++ b/plugins/GSdx/GPURenderer.h @@ -1,399 +1,399 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GPUState.h" -#include "GSVertexList.h" - -struct GPURendererSettings -{ - int m_filter; - int m_dither; - int m_aspectratio; - bool m_vsync; - CSize m_scale; -}; - -class GPURendererBase : public GPUState, protected GPURendererSettings -{ -protected: - HWND m_hWnd; - WNDPROC m_wndproc; - static CAtlMap m_wnd2gpu; - - static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) - { - if(CAtlMap::CPair* pair = m_wnd2gpu.Lookup(hWnd)) - { - return pair->m_value->OnMessage(message, wParam, lParam); - } - - ASSERT(0); - - return 0; - } - - LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam) - { - if(message == WM_KEYUP) - { - if(wParam == VK_DELETE) - { - m_filter = (m_filter + 1) % 3; - return 0; - } - - if(wParam == VK_END) - { - m_dither = m_dither ? 0 : 1; - return 0; - } - - if(wParam == VK_NEXT) - { - m_aspectratio = (m_aspectratio + 1) % 3; - return 0; - } - } - - return m_wndproc(m_hWnd, message, wParam, lParam); - } - -public: - GPURendererBase(const GPURendererSettings& rs) - : GPUState(rs.m_scale) - , m_hWnd(NULL) - , m_wndproc(NULL) - { - m_filter = rs.m_filter; - m_dither = rs.m_dither; - m_aspectratio = rs.m_aspectratio; - m_vsync = rs.m_vsync; - m_scale = m_mem.GetScale(); - } - - virtual ~GPURendererBase() - { - if(m_wndproc) - { - SetWindowLongPtr(m_hWnd, GWLP_WNDPROC, (LONG_PTR)m_wndproc); - - m_wnd2gpu.RemoveKey(m_hWnd); - } - } - - virtual bool Create(HWND hWnd) - { - m_hWnd = hWnd; - - m_wndproc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC); - SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)WndProc); - m_wnd2gpu.SetAt(hWnd, this); - - DWORD style = GetWindowLong(hWnd, GWL_STYLE); - style |= WS_OVERLAPPEDWINDOW; - SetWindowLong(hWnd, GWL_STYLE, style); - UpdateWindow(hWnd); - - ShowWindow(hWnd, SW_SHOWNORMAL); - - return true; - } - - virtual void VSync() = 0; - virtual bool MakeSnapshot(LPCTSTR path) = 0; -}; - -template -class GPURenderer : public GPURendererBase -{ -protected: - typedef typename Device::Texture Texture; - - Vertex* m_vertices; - int m_count; - int m_maxcount; - GSVertexList m_vl; - - void Reset() - { - m_count = 0; - m_vl.RemoveAll(); - - __super::Reset(); - } - - void VertexKick() - { - if(m_vl.GetCount() < m_env.PRIM.VTX) - { - return; - } - - if(m_count > m_maxcount) - { - m_maxcount = max(10000, m_maxcount * 3/2); - m_vertices = (Vertex*)_aligned_realloc(m_vertices, sizeof(Vertex) * m_maxcount, 16); - m_maxcount -= 100; - } - - Vertex* v = &m_vertices[m_count]; - - int count = 0; - - switch(m_env.PRIM.TYPE) - { - case GPU_POLYGON: - m_vl.GetAt(0, v[0]); - m_vl.GetAt(1, v[1]); - m_vl.GetAt(2, v[2]); - m_vl.RemoveAll(); - count = 3; - break; - case GPU_LINE: - m_vl.GetAt(0, v[0]); - m_vl.GetAt(1, v[1]); - m_vl.RemoveAll(); - count = 2; - break; - case GPU_SPRITE: - m_vl.GetAt(0, v[0]); - m_vl.GetAt(1, v[1]); - m_vl.RemoveAll(); - count = 2; - break; - default: - ASSERT(0); - m_vl.RemoveAll(); - count = 0; - break; - } - - (this->*m_fpDrawingKickHandlers[m_env.PRIM.TYPE])(v, count); - - m_count += count; - } - - typedef void (GPURenderer::*DrawingKickHandler)(Vertex* v, int& count); - - DrawingKickHandler m_fpDrawingKickHandlers[4]; - - void DrawingKickNull(Vertex* v, int& count) - { - ASSERT(0); - } - - void ResetPrim() - { - m_vl.RemoveAll(); - } - - void FlushPrim() - { - if(m_count > 0) - { - /* - Dump(_T("db")); - - if(m_env.PRIM.TME) - { - CRect r; - - r.left = m_env.STATUS.TX << 6; - r.top = m_env.STATUS.TY << 8; - r.right = r.left + 256; - r.bottom = r.top + 256; - - CString str; - str.Format(_T("da_%d_%d_%d_%d_%d"), m_env.STATUS.TP, r); - Dump(str, m_env.STATUS.TP, r, false); - } - */ - - Draw(); - - m_count = 0; - - //Dump(_T("dc"), false); - } - } - - virtual void ResetDevice() {} - virtual void Draw() = 0; - virtual bool GetOutput(Texture& t) = 0; - - bool Merge() - { - Texture st[2]; - - if(!GetOutput(st[0])) - { - return false; - } - - CSize s; - - s.cx = st[0].GetWidth(); - s.cy = st[0].GetHeight(); - - GSVector4 sr[2]; - - sr[0].x = 0; - sr[0].y = 0; - sr[0].z = 1.0f; - sr[0].w = 1.0f; - - GSVector4 dr[2]; - - dr[0].x = 0; - dr[0].y = 0; - dr[0].z = (float)s.cx; - dr[0].w = (float)s.cy; - - GSVector4 c(0, 0, 0, 1); - - m_dev.Merge(st, sr, dr, s, 1, 1, c); - - return true; - } - -public: - Device m_dev; - -public: - GPURenderer(const GPURendererSettings& rs) - : GPURendererBase(rs) - , m_count(0) - , m_maxcount(10000) - { - m_vertices = (Vertex*)_aligned_malloc(sizeof(Vertex) * m_maxcount, 16); - m_maxcount -= 100; - - for(int i = 0; i < countof(m_fpDrawingKickHandlers); i++) - { - m_fpDrawingKickHandlers[i] = &GPURenderer::DrawingKickNull; - } - } - - virtual ~GPURenderer() - { - if(m_vertices) _aligned_free(m_vertices); - } - - virtual bool Create(HWND hWnd) - { - if(!__super::Create(hWnd)) - { - return false; - } - - if(!m_dev.Create(hWnd, m_vsync)) - { - return false; - } - - Reset(); - - return true; - } - - virtual void VSync() - { - GSPerfMonAutoTimer pmat(m_perfmon); - - // m_env.STATUS.LCF = ~m_env.STATUS.LCF; // ? - - if(!IsWindow(m_hWnd)) - { - return; - } - - Flush(); - - m_perfmon.Put(GSPerfMon::Frame); - - if(!Merge()) - { - return; - } - - // osd - - static UINT64 s_frame = 0; - static CString s_stats; - - if(m_perfmon.GetFrame() - s_frame >= 30) - { - m_perfmon.Update(); - - s_frame = m_perfmon.GetFrame(); - - double fps = 1000.0f / m_perfmon.Get(GSPerfMon::Frame); - - CRect r = m_env.GetDisplayRect(); - - int w = r.Width() << m_scale.cx; - int h = r.Height() << m_scale.cy; - - s_stats.Format( - _T("%I64d | %d x %d | %.2f fps (%d%%) | %d/%d | %d%% CPU | %.2f | %.2f"), - m_perfmon.GetFrame(), w, h, fps, (int)(100.0 * fps / m_env.GetFPS()), - (int)m_perfmon.Get(GSPerfMon::Prim), - (int)m_perfmon.Get(GSPerfMon::Draw), - m_perfmon.CPU(), - m_perfmon.Get(GSPerfMon::Swizzle) / 1024, - m_perfmon.Get(GSPerfMon::Unswizzle) / 1024 - ); - - double fillrate = m_perfmon.Get(GSPerfMon::Fillrate); - - if(fillrate > 0) - { - s_stats.Format(_T("%s | %.2f mpps"), CString(s_stats), fps * fillrate / (1024 * 1024)); - } - - SetWindowText(m_hWnd, s_stats); - } - - if(m_dev.IsLost()) - { - ResetDevice(); - } - - CRect r; - - GetClientRect(m_hWnd, &r); - - GSUtil::FitRect(r, m_aspectratio); - - m_dev.Present(r); - } - - virtual bool MakeSnapshot(LPCTSTR path) - { - CString fn; - - fn.Format(_T("%s_%s"), path, CTime::GetCurrentTime().Format(_T("%Y%m%d%H%M%S"))); - - return m_dev.SaveCurrent(fn + _T(".bmp")); - } -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GPUState.h" +#include "GSVertexList.h" + +struct GPURendererSettings +{ + int m_filter; + int m_dither; + int m_aspectratio; + bool m_vsync; + CSize m_scale; +}; + +class GPURendererBase : public GPUState, protected GPURendererSettings +{ +protected: + HWND m_hWnd; + WNDPROC m_wndproc; + static CAtlMap m_wnd2gpu; + + static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) + { + if(CAtlMap::CPair* pair = m_wnd2gpu.Lookup(hWnd)) + { + return pair->m_value->OnMessage(message, wParam, lParam); + } + + ASSERT(0); + + return 0; + } + + LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam) + { + if(message == WM_KEYUP) + { + if(wParam == VK_DELETE) + { + m_filter = (m_filter + 1) % 3; + return 0; + } + + if(wParam == VK_END) + { + m_dither = m_dither ? 0 : 1; + return 0; + } + + if(wParam == VK_NEXT) + { + m_aspectratio = (m_aspectratio + 1) % 3; + return 0; + } + } + + return m_wndproc(m_hWnd, message, wParam, lParam); + } + +public: + GPURendererBase(const GPURendererSettings& rs) + : GPUState(rs.m_scale) + , m_hWnd(NULL) + , m_wndproc(NULL) + { + m_filter = rs.m_filter; + m_dither = rs.m_dither; + m_aspectratio = rs.m_aspectratio; + m_vsync = rs.m_vsync; + m_scale = m_mem.GetScale(); + } + + virtual ~GPURendererBase() + { + if(m_wndproc) + { + SetWindowLongPtr(m_hWnd, GWLP_WNDPROC, (LONG_PTR)m_wndproc); + + m_wnd2gpu.RemoveKey(m_hWnd); + } + } + + virtual bool Create(HWND hWnd) + { + m_hWnd = hWnd; + + m_wndproc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC); + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)WndProc); + m_wnd2gpu.SetAt(hWnd, this); + + DWORD style = GetWindowLong(hWnd, GWL_STYLE); + style |= WS_OVERLAPPEDWINDOW; + SetWindowLong(hWnd, GWL_STYLE, style); + UpdateWindow(hWnd); + + ShowWindow(hWnd, SW_SHOWNORMAL); + + return true; + } + + virtual void VSync() = 0; + virtual bool MakeSnapshot(LPCTSTR path) = 0; +}; + +template +class GPURenderer : public GPURendererBase +{ +protected: + typedef typename Device::Texture Texture; + + Vertex* m_vertices; + int m_count; + int m_maxcount; + GSVertexList m_vl; + + void Reset() + { + m_count = 0; + m_vl.RemoveAll(); + + __super::Reset(); + } + + void VertexKick() + { + if(m_vl.GetCount() < m_env.PRIM.VTX) + { + return; + } + + if(m_count > m_maxcount) + { + m_maxcount = max(10000, m_maxcount * 3/2); + m_vertices = (Vertex*)_aligned_realloc(m_vertices, sizeof(Vertex) * m_maxcount, 16); + m_maxcount -= 100; + } + + Vertex* v = &m_vertices[m_count]; + + int count = 0; + + switch(m_env.PRIM.TYPE) + { + case GPU_POLYGON: + m_vl.GetAt(0, v[0]); + m_vl.GetAt(1, v[1]); + m_vl.GetAt(2, v[2]); + m_vl.RemoveAll(); + count = 3; + break; + case GPU_LINE: + m_vl.GetAt(0, v[0]); + m_vl.GetAt(1, v[1]); + m_vl.RemoveAll(); + count = 2; + break; + case GPU_SPRITE: + m_vl.GetAt(0, v[0]); + m_vl.GetAt(1, v[1]); + m_vl.RemoveAll(); + count = 2; + break; + default: + ASSERT(0); + m_vl.RemoveAll(); + count = 0; + break; + } + + (this->*m_fpDrawingKickHandlers[m_env.PRIM.TYPE])(v, count); + + m_count += count; + } + + typedef void (GPURenderer::*DrawingKickHandler)(Vertex* v, int& count); + + DrawingKickHandler m_fpDrawingKickHandlers[4]; + + void DrawingKickNull(Vertex* v, int& count) + { + ASSERT(0); + } + + void ResetPrim() + { + m_vl.RemoveAll(); + } + + void FlushPrim() + { + if(m_count > 0) + { + /* + Dump(_T("db")); + + if(m_env.PRIM.TME) + { + CRect r; + + r.left = m_env.STATUS.TX << 6; + r.top = m_env.STATUS.TY << 8; + r.right = r.left + 256; + r.bottom = r.top + 256; + + CString str; + str.Format(_T("da_%d_%d_%d_%d_%d"), m_env.STATUS.TP, r); + Dump(str, m_env.STATUS.TP, r, false); + } + */ + + Draw(); + + m_count = 0; + + //Dump(_T("dc"), false); + } + } + + virtual void ResetDevice() {} + virtual void Draw() = 0; + virtual bool GetOutput(Texture& t) = 0; + + bool Merge() + { + Texture st[2]; + + if(!GetOutput(st[0])) + { + return false; + } + + CSize s; + + s.cx = st[0].GetWidth(); + s.cy = st[0].GetHeight(); + + GSVector4 sr[2]; + + sr[0].x = 0; + sr[0].y = 0; + sr[0].z = 1.0f; + sr[0].w = 1.0f; + + GSVector4 dr[2]; + + dr[0].x = 0; + dr[0].y = 0; + dr[0].z = (float)s.cx; + dr[0].w = (float)s.cy; + + GSVector4 c(0, 0, 0, 1); + + m_dev.Merge(st, sr, dr, s, 1, 1, c); + + return true; + } + +public: + Device m_dev; + +public: + GPURenderer(const GPURendererSettings& rs) + : GPURendererBase(rs) + , m_count(0) + , m_maxcount(10000) + { + m_vertices = (Vertex*)_aligned_malloc(sizeof(Vertex) * m_maxcount, 16); + m_maxcount -= 100; + + for(int i = 0; i < countof(m_fpDrawingKickHandlers); i++) + { + m_fpDrawingKickHandlers[i] = &GPURenderer::DrawingKickNull; + } + } + + virtual ~GPURenderer() + { + if(m_vertices) _aligned_free(m_vertices); + } + + virtual bool Create(HWND hWnd) + { + if(!__super::Create(hWnd)) + { + return false; + } + + if(!m_dev.Create(hWnd, m_vsync)) + { + return false; + } + + Reset(); + + return true; + } + + virtual void VSync() + { + GSPerfMonAutoTimer pmat(m_perfmon); + + // m_env.STATUS.LCF = ~m_env.STATUS.LCF; // ? + + if(!IsWindow(m_hWnd)) + { + return; + } + + Flush(); + + m_perfmon.Put(GSPerfMon::Frame); + + if(!Merge()) + { + return; + } + + // osd + + static UINT64 s_frame = 0; + static CString s_stats; + + if(m_perfmon.GetFrame() - s_frame >= 30) + { + m_perfmon.Update(); + + s_frame = m_perfmon.GetFrame(); + + double fps = 1000.0f / m_perfmon.Get(GSPerfMon::Frame); + + CRect r = m_env.GetDisplayRect(); + + int w = r.Width() << m_scale.cx; + int h = r.Height() << m_scale.cy; + + s_stats.Format( + _T("%I64d | %d x %d | %.2f fps (%d%%) | %d/%d | %d%% CPU | %.2f | %.2f"), + m_perfmon.GetFrame(), w, h, fps, (int)(100.0 * fps / m_env.GetFPS()), + (int)m_perfmon.Get(GSPerfMon::Prim), + (int)m_perfmon.Get(GSPerfMon::Draw), + m_perfmon.CPU(), + m_perfmon.Get(GSPerfMon::Swizzle) / 1024, + m_perfmon.Get(GSPerfMon::Unswizzle) / 1024 + ); + + double fillrate = m_perfmon.Get(GSPerfMon::Fillrate); + + if(fillrate > 0) + { + s_stats.Format(_T("%s | %.2f mpps"), CString(s_stats), fps * fillrate / (1024 * 1024)); + } + + SetWindowText(m_hWnd, s_stats); + } + + if(m_dev.IsLost()) + { + ResetDevice(); + } + + CRect r; + + GetClientRect(m_hWnd, &r); + + GSUtil::FitRect(r, m_aspectratio); + + m_dev.Present(r); + } + + virtual bool MakeSnapshot(LPCTSTR path) + { + CString fn; + + fn.Format(_T("%s_%s"), path, CTime::GetCurrentTime().Format(_T("%Y%m%d%H%M%S"))); + + return m_dev.SaveCurrent(fn + _T(".bmp")); + } +}; diff --git a/plugins/GSdx/GPURendererSW.cpp b/plugins/GSdx/GPURendererSW.cpp index 3a8505e2da..71e1d083f6 100644 --- a/plugins/GSdx/GPURendererSW.cpp +++ b/plugins/GSdx/GPURendererSW.cpp @@ -1,23 +1,23 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GPURendererSW.h" +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GPURendererSW.h" diff --git a/plugins/GSdx/GPURendererSW.h b/plugins/GSdx/GPURendererSW.h index be69912b22..1cf3fdfe03 100644 --- a/plugins/GSdx/GPURendererSW.h +++ b/plugins/GSdx/GPURendererSW.h @@ -1,218 +1,218 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GPURenderer.h" -#include "GPUDrawScanline.h" - -template -class GPURendererSW : public GPURenderer -{ -protected: - GSRasterizerList m_rl; - Texture m_texture; - - void ResetDevice() - { - m_texture = Texture(); - } - - bool GetOutput(Texture& t) - { - CRect r = m_env.GetDisplayRect(); - - r.left <<= m_scale.cx; - r.top <<= m_scale.cy; - r.right <<= m_scale.cx; - r.bottom <<= m_scale.cy; - - // TODO - static DWORD* buff = (DWORD*)_aligned_malloc(m_mem.GetWidth() * m_mem.GetHeight() * sizeof(DWORD), 16); - - m_mem.ReadFrame32(r, buff, !!m_env.STATUS.ISRGB24); - - r.OffsetRect(-r.TopLeft()); - - if(m_texture.GetWidth() != r.Width() || m_texture.GetHeight() != r.Height()) - { - m_texture = Texture(); - } - - if(!m_texture && !m_dev.CreateTexture(m_texture, r.Width(), r.Height())) - { - return false; - } - - m_texture.Update(r, buff, m_mem.GetWidth() * sizeof(DWORD)); - - t = m_texture; - - return true; - } - - void VertexKick() - { - GSVertexSW& v = m_vl.AddTail(); - - // TODO: x/y + off.x/y should wrap around at +/-1024 - - int x = (int)(m_v.XY.X + m_env.DROFF.X) << m_scale.cx; - int y = (int)(m_v.XY.Y + m_env.DROFF.Y) << m_scale.cy; - - int s = m_v.UV.X; - int t = m_v.UV.Y; - - GSVector4 pt(x, y, s, t); - - v.p = pt.xyxy(GSVector4::zero()); - v.t = (pt.zwzw(GSVector4::zero()) + GSVector4(0.125f)) * 256.0f; - v.c = GSVector4((DWORD)m_v.RGB.ai32) * 128.0f; - - __super::VertexKick(); - } - - void DrawingKickTriangle(GSVertexSW* v, int& count) - { - // TODO - } - - void DrawingKickLine(GSVertexSW* v, int& count) - { - // TODO - } - - void DrawingKickSprite(GSVertexSW* v, int& count) - { - // TODO - } - - GSVector4i GetScissor() - { - GSVector4i v; - - v.x = (int)m_env.DRAREATL.X << m_scale.cx; - v.y = (int)m_env.DRAREATL.Y << m_scale.cy; - v.z = min((int)(m_env.DRAREABR.X + 1) << m_scale.cx, m_mem.GetWidth()); - v.w = min((int)(m_env.DRAREABR.Y + 1) << m_scale.cy, m_mem.GetHeight()); - - return v; - } - - void Draw() - { - const GPUDrawingEnvironment& env = m_env; - - // - - GPUScanlineParam p; - - p.sel.dw = 0; - p.sel.iip = env.PRIM.IIP; - p.sel.me = env.STATUS.ME; - p.sel.abe = env.PRIM.ABE; - p.sel.abr = env.STATUS.ABR; - p.sel.tge = env.PRIM.TGE; - p.sel.tme = env.PRIM.TME; - p.sel.tlu = env.STATUS.TP < 2; - p.sel.twin = (env.TWIN.ai32 & 0xfffff) != 0; - p.sel.dtd = m_dither ? env.STATUS.DTD : 0; - p.sel.ltf = m_filter == 1 && env.PRIM.TYPE == GPU_POLYGON || m_filter == 2 ? 1 : 0; - - if(env.PRIM.TME) - { - const void* t = m_mem.GetTexture(env.STATUS.TP, env.STATUS.TX, env.STATUS.TY); - - if(!t) {ASSERT(0); return;} - - p.tex = t; - p.clut = m_mem.GetCLUT(env.STATUS.TP, env.CLUT.X, env.CLUT.Y); - } - - // - - GSRasterizerData data; - - data.scissor = GetScissor(); - data.vertices = m_vertices; - data.count = m_count; - data.param = &p; - - switch(env.PRIM.TYPE) - { - case GPU_POLYGON: data.primclass = GS_TRIANGLE_CLASS; break; - case GPU_LINE: data.primclass = GS_LINE_CLASS; break; - case GPU_SPRITE: data.primclass = GS_SPRITE_CLASS; break; - default: __assume(0); - } - - m_rl.Draw(&data); - - GSRasterizerStats stats; - - m_rl.GetStats(stats); - - m_perfmon.Put(GSPerfMon::Draw, 1); - m_perfmon.Put(GSPerfMon::Prim, stats.prims); - m_perfmon.Put(GSPerfMon::Fillrate, stats.pixels); - - // TODO - - { - GSVector4 tl(+1e10f); - GSVector4 br(-1e10f); - - for(int i = 0, j = m_count; i < j; i++) - { - GSVector4 p = m_vertices[i].p; - - tl = tl.minv(p); - br = br.maxv(p); - } - - GSVector4i scissor = data.scissor; - - CRect r; - - r.left = max(scissor.x, min(scissor.z, (int)tl.x)) >> m_scale.cx; - r.top = max(scissor.y, min(scissor.w, (int)tl.y)) >> m_scale.cy; - r.right = max(scissor.x, min(scissor.z, (int)br.x)) >> m_scale.cx; - r.bottom = max(scissor.y, min(scissor.w, (int)br.y)) >> m_scale.cy; - - Invalidate(r); - } - } - -public: - GPURendererSW(const GPURendererSettings& rs, int threads) - : GPURenderer(rs) - { - m_rl.Create(this, threads); - - m_fpDrawingKickHandlers[GPU_POLYGON] = (DrawingKickHandler)&GPURendererSW::DrawingKickTriangle; - m_fpDrawingKickHandlers[GPU_LINE] = (DrawingKickHandler)&GPURendererSW::DrawingKickLine; - m_fpDrawingKickHandlers[GPU_SPRITE] = (DrawingKickHandler)&GPURendererSW::DrawingKickSprite; - } - - virtual ~GPURendererSW() - { - } -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GPURenderer.h" +#include "GPUDrawScanline.h" + +template +class GPURendererSW : public GPURenderer +{ +protected: + GSRasterizerList m_rl; + Texture m_texture; + + void ResetDevice() + { + m_texture = Texture(); + } + + bool GetOutput(Texture& t) + { + CRect r = m_env.GetDisplayRect(); + + r.left <<= m_scale.cx; + r.top <<= m_scale.cy; + r.right <<= m_scale.cx; + r.bottom <<= m_scale.cy; + + // TODO + static DWORD* buff = (DWORD*)_aligned_malloc(m_mem.GetWidth() * m_mem.GetHeight() * sizeof(DWORD), 16); + + m_mem.ReadFrame32(r, buff, !!m_env.STATUS.ISRGB24); + + r.OffsetRect(-r.TopLeft()); + + if(m_texture.GetWidth() != r.Width() || m_texture.GetHeight() != r.Height()) + { + m_texture = Texture(); + } + + if(!m_texture && !m_dev.CreateTexture(m_texture, r.Width(), r.Height())) + { + return false; + } + + m_texture.Update(r, buff, m_mem.GetWidth() * sizeof(DWORD)); + + t = m_texture; + + return true; + } + + void VertexKick() + { + GSVertexSW& v = m_vl.AddTail(); + + // TODO: x/y + off.x/y should wrap around at +/-1024 + + int x = (int)(m_v.XY.X + m_env.DROFF.X) << m_scale.cx; + int y = (int)(m_v.XY.Y + m_env.DROFF.Y) << m_scale.cy; + + int s = m_v.UV.X; + int t = m_v.UV.Y; + + GSVector4 pt(x, y, s, t); + + v.p = pt.xyxy(GSVector4::zero()); + v.t = (pt.zwzw(GSVector4::zero()) + GSVector4(0.125f)) * 256.0f; + v.c = GSVector4((DWORD)m_v.RGB.ai32) * 128.0f; + + __super::VertexKick(); + } + + void DrawingKickTriangle(GSVertexSW* v, int& count) + { + // TODO + } + + void DrawingKickLine(GSVertexSW* v, int& count) + { + // TODO + } + + void DrawingKickSprite(GSVertexSW* v, int& count) + { + // TODO + } + + GSVector4i GetScissor() + { + GSVector4i v; + + v.x = (int)m_env.DRAREATL.X << m_scale.cx; + v.y = (int)m_env.DRAREATL.Y << m_scale.cy; + v.z = min((int)(m_env.DRAREABR.X + 1) << m_scale.cx, m_mem.GetWidth()); + v.w = min((int)(m_env.DRAREABR.Y + 1) << m_scale.cy, m_mem.GetHeight()); + + return v; + } + + void Draw() + { + const GPUDrawingEnvironment& env = m_env; + + // + + GPUScanlineParam p; + + p.sel.dw = 0; + p.sel.iip = env.PRIM.IIP; + p.sel.me = env.STATUS.ME; + p.sel.abe = env.PRIM.ABE; + p.sel.abr = env.STATUS.ABR; + p.sel.tge = env.PRIM.TGE; + p.sel.tme = env.PRIM.TME; + p.sel.tlu = env.STATUS.TP < 2; + p.sel.twin = (env.TWIN.ai32 & 0xfffff) != 0; + p.sel.dtd = m_dither ? env.STATUS.DTD : 0; + p.sel.ltf = m_filter == 1 && env.PRIM.TYPE == GPU_POLYGON || m_filter == 2 ? 1 : 0; + + if(env.PRIM.TME) + { + const void* t = m_mem.GetTexture(env.STATUS.TP, env.STATUS.TX, env.STATUS.TY); + + if(!t) {ASSERT(0); return;} + + p.tex = t; + p.clut = m_mem.GetCLUT(env.STATUS.TP, env.CLUT.X, env.CLUT.Y); + } + + // + + GSRasterizerData data; + + data.scissor = GetScissor(); + data.vertices = m_vertices; + data.count = m_count; + data.param = &p; + + switch(env.PRIM.TYPE) + { + case GPU_POLYGON: data.primclass = GS_TRIANGLE_CLASS; break; + case GPU_LINE: data.primclass = GS_LINE_CLASS; break; + case GPU_SPRITE: data.primclass = GS_SPRITE_CLASS; break; + default: __assume(0); + } + + m_rl.Draw(&data); + + GSRasterizerStats stats; + + m_rl.GetStats(stats); + + m_perfmon.Put(GSPerfMon::Draw, 1); + m_perfmon.Put(GSPerfMon::Prim, stats.prims); + m_perfmon.Put(GSPerfMon::Fillrate, stats.pixels); + + // TODO + + { + GSVector4 tl(+1e10f); + GSVector4 br(-1e10f); + + for(int i = 0, j = m_count; i < j; i++) + { + GSVector4 p = m_vertices[i].p; + + tl = tl.minv(p); + br = br.maxv(p); + } + + GSVector4i scissor = data.scissor; + + CRect r; + + r.left = max(scissor.x, min(scissor.z, (int)tl.x)) >> m_scale.cx; + r.top = max(scissor.y, min(scissor.w, (int)tl.y)) >> m_scale.cy; + r.right = max(scissor.x, min(scissor.z, (int)br.x)) >> m_scale.cx; + r.bottom = max(scissor.y, min(scissor.w, (int)br.y)) >> m_scale.cy; + + Invalidate(r); + } + } + +public: + GPURendererSW(const GPURendererSettings& rs, int threads) + : GPURenderer(rs) + { + m_rl.Create(this, threads); + + m_fpDrawingKickHandlers[GPU_POLYGON] = (DrawingKickHandler)&GPURendererSW::DrawingKickTriangle; + m_fpDrawingKickHandlers[GPU_LINE] = (DrawingKickHandler)&GPURendererSW::DrawingKickLine; + m_fpDrawingKickHandlers[GPU_SPRITE] = (DrawingKickHandler)&GPURendererSW::DrawingKickSprite; + } + + virtual ~GPURendererSW() + { + } +}; diff --git a/plugins/GSdx/GPUSettingsDlg.cpp b/plugins/GSdx/GPUSettingsDlg.cpp index cccf108944..0d937ad0f2 100644 --- a/plugins/GSdx/GPUSettingsDlg.cpp +++ b/plugins/GSdx/GPUSettingsDlg.cpp @@ -1,301 +1,301 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GSdx.h" -#include "GSUtil.h" -#include "GPUSettingsDlg.h" -#include -#include - -GSSetting GPUSettingsDlg::g_renderers[] = -{ - {0, _T("Direct3D7 (Software)"), NULL}, - {1, _T("Direct3D9 (Software)"), NULL}, - {2, _T("Direct3D10 (Software)"), NULL}, -// {3, _T("Null (Null)"), NULL}, -}; - -GSSetting GPUSettingsDlg::g_psversion[] = -{ - {D3DPS_VERSION(3, 0), _T("Pixel Shader 3.0"), NULL}, - {D3DPS_VERSION(2, 0), _T("Pixel Shader 2.0"), NULL}, - //{D3DPS_VERSION(1, 4), _T("Pixel Shader 1.4"), NULL}, - //{D3DPS_VERSION(1, 1), _T("Pixel Shader 1.1"), NULL}, - //{D3DPS_VERSION(0, 0), _T("Fixed Pipeline (bogus)"), NULL}, -}; - -GSSetting GPUSettingsDlg::g_filter[] = -{ - {0, _T("Nearest"), NULL}, - {1, _T("Bilinear (polygons only)"), NULL}, - {2, _T("Bilinear"), NULL}, -}; - -GSSetting GPUSettingsDlg::g_dithering[] = -{ - {0, _T("Disabled"), NULL}, - {1, _T("Auto"), NULL}, -}; - -GSSetting GPUSettingsDlg::g_aspectratio[] = -{ - {0, _T("Stretch"), NULL}, - {1, _T("4:3"), NULL}, - {2, _T("16:9"), NULL}, -}; - -GSSetting GPUSettingsDlg::g_internalresolution[] = -{ - {0 | (0 << 2), _T("H x 1 - V x 1"), NULL}, - {1 | (0 << 2), _T("H x 2 - V x 1"), NULL}, - {0 | (1 << 2), _T("H x 1 - V x 2"), NULL}, - {1 | (1 << 2), _T("H x 2 - V x 2"), NULL}, - {2 | (1 << 2), _T("H x 4 - V x 2"), NULL}, - {1 | (2 << 2), _T("H x 2 - V x 4"), NULL}, - {2 | (2 << 2), _T("H x 4 - V x 4"), NULL}, -}; - -IMPLEMENT_DYNAMIC(GPUSettingsDlg, CDialog) - -GPUSettingsDlg::GPUSettingsDlg(CWnd* pParent /*=NULL*/) - : CDialog(GPUSettingsDlg::IDD, pParent) -{ - -} - -GPUSettingsDlg::~GPUSettingsDlg() -{ -} - -LRESULT GPUSettingsDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - LRESULT ret = __super::DefWindowProc(message, wParam, lParam); - - if(message == WM_INITDIALOG) - { - SendMessage(WM_KICKIDLE); - } - - return ret; -} - -void GPUSettingsDlg::DoDataExchange(CDataExchange* pDX) -{ - __super::DoDataExchange(pDX); - DDX_Control(pDX, IDC_COMBO3, m_resolution); - DDX_Control(pDX, IDC_COMBO1, m_renderer); - DDX_Control(pDX, IDC_COMBO4, m_psversion); - DDX_Control(pDX, IDC_COMBO2, m_filter); - DDX_Control(pDX, IDC_COMBO5, m_dithering); - DDX_Control(pDX, IDC_COMBO6, m_aspectratio); - DDX_Control(pDX, IDC_COMBO7, m_internalresolution); - DDX_Control(pDX, IDC_SPIN3, m_swthreads); - DDX_Control(pDX, IDC_EDIT3, m_swthreadsedit); -} - -BEGIN_MESSAGE_MAP(GPUSettingsDlg, CDialog) - ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle) - ON_UPDATE_COMMAND_UI(IDC_COMBO4, OnUpdateD3D9Options) - ON_UPDATE_COMMAND_UI(IDC_COMBO7, OnUpdateSWOptions) - ON_UPDATE_COMMAND_UI(IDC_SPIN3, OnUpdateSWOptions) - ON_UPDATE_COMMAND_UI(IDC_EDIT3, OnUpdateSWOptions) - ON_CBN_SELCHANGE(IDC_COMBO1, &GPUSettingsDlg::OnCbnSelchangeCombo1) -END_MESSAGE_MAP() - -void GPUSettingsDlg::OnKickIdle() -{ - UpdateDialogControls(this, false); -} - -BOOL GPUSettingsDlg::OnInitDialog() -{ - __super::OnInitDialog(); - - CWinApp* pApp = AfxGetApp(); - - D3DCAPS9 caps; - memset(&caps, 0, sizeof(caps)); - caps.PixelShaderVersion = D3DPS_VERSION(0, 0); - - m_modes.RemoveAll(); - - // windowed - - { - D3DDISPLAYMODE mode; - memset(&mode, 0, sizeof(mode)); - m_modes.AddTail(mode); - - int iItem = m_resolution.AddString(_T("Windowed")); - m_resolution.SetItemDataPtr(iItem, m_modes.GetTailPosition()); - m_resolution.SetCurSel(iItem); - } - - // fullscreen - - if(CComPtr d3d = Direct3DCreate9(D3D_SDK_VERSION)) - { - UINT ModeWidth = pApp->GetProfileInt(_T("Settings"), _T("ModeWidth"), 0); - UINT ModeHeight = pApp->GetProfileInt(_T("Settings"), _T("ModeHeight"), 0); - UINT ModeRefreshRate = pApp->GetProfileInt(_T("Settings"), _T("ModeRefreshRate"), 0); - - UINT nModes = d3d->GetAdapterModeCount(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8); - - for(UINT i = 0; i < nModes; i++) - { - D3DDISPLAYMODE mode; - - if(S_OK == d3d->EnumAdapterModes(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8, i, &mode)) - { - CString str; - str.Format(_T("%dx%d %dHz"), mode.Width, mode.Height, mode.RefreshRate); - int iItem = m_resolution.AddString(str); - - m_modes.AddTail(mode); - m_resolution.SetItemDataPtr(iItem, m_modes.GetTailPosition()); - - if(ModeWidth == mode.Width && ModeHeight == mode.Height && ModeRefreshRate == mode.RefreshRate) - { - m_resolution.SetCurSel(iItem); - } - } - } - - d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps); - } - - bool isdx10avail = GSUtil::IsDirect3D10Available(); - - CAtlArray renderers; - - for(size_t i = 0; i < countof(g_renderers); i++) - { - if(i == 2 && !isdx10avail) continue; - - renderers.Add(g_renderers[i]); - } - - GSSetting::InitComboBox(renderers.GetData(), renderers.GetCount(), m_renderer, pApp->GetProfileInt(_T("GPUSettings"), _T("Renderer"), 1)); - GSSetting::InitComboBox(g_psversion, countof(g_psversion), m_psversion, pApp->GetProfileInt(_T("Settings"), _T("PixelShaderVersion2"), D3DPS_VERSION(2, 0)), caps.PixelShaderVersion); - GSSetting::InitComboBox(g_filter, countof(g_filter), m_filter, pApp->GetProfileInt(_T("GPUSettings"), _T("filter"), 0)); - GSSetting::InitComboBox(g_dithering, countof(g_dithering), m_dithering, pApp->GetProfileInt(_T("GPUSettings"), _T("dithering"), 1)); - GSSetting::InitComboBox(g_aspectratio, countof(g_aspectratio), m_aspectratio, pApp->GetProfileInt(_T("GPUSettings"), _T("AspectRatio"), 1)); - GSSetting::InitComboBox(g_internalresolution, countof(g_internalresolution), m_internalresolution, pApp->GetProfileInt(_T("GPUSettings"), _T("scale_x"), 0) | (pApp->GetProfileInt(_T("GPUSettings"), _T("scale_y"), 0) << 2)); - - - OnCbnSelchangeCombo1(); - - // - - m_swthreads.SetRange(1, 16); - m_swthreads.SetPos(pApp->GetProfileInt(_T("GPUSettings"), _T("swthreads"), 1)); - - // - - UpdateData(FALSE); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -void GPUSettingsDlg::OnOK() -{ - CWinApp* pApp = AfxGetApp(); - - UpdateData(); - - if(m_resolution.GetCurSel() >= 0) - { - D3DDISPLAYMODE& mode = m_modes.GetAt((POSITION)m_resolution.GetItemData(m_resolution.GetCurSel())); - pApp->WriteProfileInt(_T("Settings"), _T("ModeWidth"), mode.Width); - pApp->WriteProfileInt(_T("Settings"), _T("ModeHeight"), mode.Height); - pApp->WriteProfileInt(_T("Settings"), _T("ModeRefreshRate"), mode.RefreshRate); - } - - if(m_renderer.GetCurSel() >= 0) - { - pApp->WriteProfileInt(_T("GPUSettings"), _T("Renderer"), (DWORD)m_renderer.GetItemData(m_renderer.GetCurSel())); - } - - if(m_psversion.GetCurSel() >= 0) - { - pApp->WriteProfileInt(_T("Settings"), _T("PixelShaderVersion2"), (DWORD)m_psversion.GetItemData(m_psversion.GetCurSel())); - } - - if(m_filter.GetCurSel() >= 0) - { - pApp->WriteProfileInt(_T("GPUSettings"), _T("filter"), (DWORD)m_filter.GetItemData(m_filter.GetCurSel())); - } - - if(m_dithering.GetCurSel() >= 0) - { - pApp->WriteProfileInt(_T("GPUSettings"), _T("dithering"), (DWORD)m_dithering.GetItemData(m_dithering.GetCurSel())); - } - - if(m_aspectratio.GetCurSel() >= 0) - { - pApp->WriteProfileInt(_T("GPUSettings"), _T("AspectRatio"), (DWORD)m_aspectratio.GetItemData(m_aspectratio.GetCurSel())); - } - - if(m_internalresolution.GetCurSel() >= 0) - { - DWORD value = (DWORD)m_internalresolution.GetItemData(m_internalresolution.GetCurSel()); - - pApp->WriteProfileInt(_T("GPUSettings"), _T("scale_x"), value & 3); - pApp->WriteProfileInt(_T("GPUSettings"), _T("scale_y"), (value >> 2) & 3); - } - - pApp->WriteProfileInt(_T("GPUSettings"), _T("swthreads"), m_swthreads.GetPos()); - - __super::OnOK(); -} - -void GPUSettingsDlg::OnUpdateResolution(CCmdUI* pCmdUI) -{ - UpdateData(); - - int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel()); - - pCmdUI->Enable(i == 1); -} - -void GPUSettingsDlg::OnUpdateD3D9Options(CCmdUI* pCmdUI) -{ - int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel()); - - pCmdUI->Enable(i == 1); -} - -void GPUSettingsDlg::OnUpdateSWOptions(CCmdUI* pCmdUI) -{ - int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel()); - - pCmdUI->Enable(i >= 0 && i <= 2); -} - -void GPUSettingsDlg::OnCbnSelchangeCombo1() -{ - int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel()); - - GetDlgItem(IDC_LOGO9)->ShowWindow(i == 1 ? SW_SHOW : SW_HIDE); - GetDlgItem(IDC_LOGO10)->ShowWindow(i == 2 ? SW_SHOW : SW_HIDE); -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSdx.h" +#include "GSUtil.h" +#include "GPUSettingsDlg.h" +#include +#include + +GSSetting GPUSettingsDlg::g_renderers[] = +{ + {0, _T("Direct3D7 (Software)"), NULL}, + {1, _T("Direct3D9 (Software)"), NULL}, + {2, _T("Direct3D10 (Software)"), NULL}, +// {3, _T("Null (Null)"), NULL}, +}; + +GSSetting GPUSettingsDlg::g_psversion[] = +{ + {D3DPS_VERSION(3, 0), _T("Pixel Shader 3.0"), NULL}, + {D3DPS_VERSION(2, 0), _T("Pixel Shader 2.0"), NULL}, + //{D3DPS_VERSION(1, 4), _T("Pixel Shader 1.4"), NULL}, + //{D3DPS_VERSION(1, 1), _T("Pixel Shader 1.1"), NULL}, + //{D3DPS_VERSION(0, 0), _T("Fixed Pipeline (bogus)"), NULL}, +}; + +GSSetting GPUSettingsDlg::g_filter[] = +{ + {0, _T("Nearest"), NULL}, + {1, _T("Bilinear (polygons only)"), NULL}, + {2, _T("Bilinear"), NULL}, +}; + +GSSetting GPUSettingsDlg::g_dithering[] = +{ + {0, _T("Disabled"), NULL}, + {1, _T("Auto"), NULL}, +}; + +GSSetting GPUSettingsDlg::g_aspectratio[] = +{ + {0, _T("Stretch"), NULL}, + {1, _T("4:3"), NULL}, + {2, _T("16:9"), NULL}, +}; + +GSSetting GPUSettingsDlg::g_internalresolution[] = +{ + {0 | (0 << 2), _T("H x 1 - V x 1"), NULL}, + {1 | (0 << 2), _T("H x 2 - V x 1"), NULL}, + {0 | (1 << 2), _T("H x 1 - V x 2"), NULL}, + {1 | (1 << 2), _T("H x 2 - V x 2"), NULL}, + {2 | (1 << 2), _T("H x 4 - V x 2"), NULL}, + {1 | (2 << 2), _T("H x 2 - V x 4"), NULL}, + {2 | (2 << 2), _T("H x 4 - V x 4"), NULL}, +}; + +IMPLEMENT_DYNAMIC(GPUSettingsDlg, CDialog) + +GPUSettingsDlg::GPUSettingsDlg(CWnd* pParent /*=NULL*/) + : CDialog(GPUSettingsDlg::IDD, pParent) +{ + +} + +GPUSettingsDlg::~GPUSettingsDlg() +{ +} + +LRESULT GPUSettingsDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + LRESULT ret = __super::DefWindowProc(message, wParam, lParam); + + if(message == WM_INITDIALOG) + { + SendMessage(WM_KICKIDLE); + } + + return ret; +} + +void GPUSettingsDlg::DoDataExchange(CDataExchange* pDX) +{ + __super::DoDataExchange(pDX); + DDX_Control(pDX, IDC_COMBO3, m_resolution); + DDX_Control(pDX, IDC_COMBO1, m_renderer); + DDX_Control(pDX, IDC_COMBO4, m_psversion); + DDX_Control(pDX, IDC_COMBO2, m_filter); + DDX_Control(pDX, IDC_COMBO5, m_dithering); + DDX_Control(pDX, IDC_COMBO6, m_aspectratio); + DDX_Control(pDX, IDC_COMBO7, m_internalresolution); + DDX_Control(pDX, IDC_SPIN3, m_swthreads); + DDX_Control(pDX, IDC_EDIT3, m_swthreadsedit); +} + +BEGIN_MESSAGE_MAP(GPUSettingsDlg, CDialog) + ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle) + ON_UPDATE_COMMAND_UI(IDC_COMBO4, OnUpdateD3D9Options) + ON_UPDATE_COMMAND_UI(IDC_COMBO7, OnUpdateSWOptions) + ON_UPDATE_COMMAND_UI(IDC_SPIN3, OnUpdateSWOptions) + ON_UPDATE_COMMAND_UI(IDC_EDIT3, OnUpdateSWOptions) + ON_CBN_SELCHANGE(IDC_COMBO1, &GPUSettingsDlg::OnCbnSelchangeCombo1) +END_MESSAGE_MAP() + +void GPUSettingsDlg::OnKickIdle() +{ + UpdateDialogControls(this, false); +} + +BOOL GPUSettingsDlg::OnInitDialog() +{ + __super::OnInitDialog(); + + CWinApp* pApp = AfxGetApp(); + + D3DCAPS9 caps; + memset(&caps, 0, sizeof(caps)); + caps.PixelShaderVersion = D3DPS_VERSION(0, 0); + + m_modes.RemoveAll(); + + // windowed + + { + D3DDISPLAYMODE mode; + memset(&mode, 0, sizeof(mode)); + m_modes.AddTail(mode); + + int iItem = m_resolution.AddString(_T("Windowed")); + m_resolution.SetItemDataPtr(iItem, m_modes.GetTailPosition()); + m_resolution.SetCurSel(iItem); + } + + // fullscreen + + if(CComPtr d3d = Direct3DCreate9(D3D_SDK_VERSION)) + { + UINT ModeWidth = pApp->GetProfileInt(_T("Settings"), _T("ModeWidth"), 0); + UINT ModeHeight = pApp->GetProfileInt(_T("Settings"), _T("ModeHeight"), 0); + UINT ModeRefreshRate = pApp->GetProfileInt(_T("Settings"), _T("ModeRefreshRate"), 0); + + UINT nModes = d3d->GetAdapterModeCount(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8); + + for(UINT i = 0; i < nModes; i++) + { + D3DDISPLAYMODE mode; + + if(S_OK == d3d->EnumAdapterModes(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8, i, &mode)) + { + CString str; + str.Format(_T("%dx%d %dHz"), mode.Width, mode.Height, mode.RefreshRate); + int iItem = m_resolution.AddString(str); + + m_modes.AddTail(mode); + m_resolution.SetItemDataPtr(iItem, m_modes.GetTailPosition()); + + if(ModeWidth == mode.Width && ModeHeight == mode.Height && ModeRefreshRate == mode.RefreshRate) + { + m_resolution.SetCurSel(iItem); + } + } + } + + d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps); + } + + bool isdx10avail = GSUtil::IsDirect3D10Available(); + + CAtlArray renderers; + + for(size_t i = 0; i < countof(g_renderers); i++) + { + if(i == 2 && !isdx10avail) continue; + + renderers.Add(g_renderers[i]); + } + + GSSetting::InitComboBox(renderers.GetData(), renderers.GetCount(), m_renderer, pApp->GetProfileInt(_T("GPUSettings"), _T("Renderer"), 1)); + GSSetting::InitComboBox(g_psversion, countof(g_psversion), m_psversion, pApp->GetProfileInt(_T("Settings"), _T("PixelShaderVersion2"), D3DPS_VERSION(2, 0)), caps.PixelShaderVersion); + GSSetting::InitComboBox(g_filter, countof(g_filter), m_filter, pApp->GetProfileInt(_T("GPUSettings"), _T("filter"), 0)); + GSSetting::InitComboBox(g_dithering, countof(g_dithering), m_dithering, pApp->GetProfileInt(_T("GPUSettings"), _T("dithering"), 1)); + GSSetting::InitComboBox(g_aspectratio, countof(g_aspectratio), m_aspectratio, pApp->GetProfileInt(_T("GPUSettings"), _T("AspectRatio"), 1)); + GSSetting::InitComboBox(g_internalresolution, countof(g_internalresolution), m_internalresolution, pApp->GetProfileInt(_T("GPUSettings"), _T("scale_x"), 0) | (pApp->GetProfileInt(_T("GPUSettings"), _T("scale_y"), 0) << 2)); + + + OnCbnSelchangeCombo1(); + + // + + m_swthreads.SetRange(1, 16); + m_swthreads.SetPos(pApp->GetProfileInt(_T("GPUSettings"), _T("swthreads"), 1)); + + // + + UpdateData(FALSE); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void GPUSettingsDlg::OnOK() +{ + CWinApp* pApp = AfxGetApp(); + + UpdateData(); + + if(m_resolution.GetCurSel() >= 0) + { + D3DDISPLAYMODE& mode = m_modes.GetAt((POSITION)m_resolution.GetItemData(m_resolution.GetCurSel())); + pApp->WriteProfileInt(_T("Settings"), _T("ModeWidth"), mode.Width); + pApp->WriteProfileInt(_T("Settings"), _T("ModeHeight"), mode.Height); + pApp->WriteProfileInt(_T("Settings"), _T("ModeRefreshRate"), mode.RefreshRate); + } + + if(m_renderer.GetCurSel() >= 0) + { + pApp->WriteProfileInt(_T("GPUSettings"), _T("Renderer"), (DWORD)m_renderer.GetItemData(m_renderer.GetCurSel())); + } + + if(m_psversion.GetCurSel() >= 0) + { + pApp->WriteProfileInt(_T("Settings"), _T("PixelShaderVersion2"), (DWORD)m_psversion.GetItemData(m_psversion.GetCurSel())); + } + + if(m_filter.GetCurSel() >= 0) + { + pApp->WriteProfileInt(_T("GPUSettings"), _T("filter"), (DWORD)m_filter.GetItemData(m_filter.GetCurSel())); + } + + if(m_dithering.GetCurSel() >= 0) + { + pApp->WriteProfileInt(_T("GPUSettings"), _T("dithering"), (DWORD)m_dithering.GetItemData(m_dithering.GetCurSel())); + } + + if(m_aspectratio.GetCurSel() >= 0) + { + pApp->WriteProfileInt(_T("GPUSettings"), _T("AspectRatio"), (DWORD)m_aspectratio.GetItemData(m_aspectratio.GetCurSel())); + } + + if(m_internalresolution.GetCurSel() >= 0) + { + DWORD value = (DWORD)m_internalresolution.GetItemData(m_internalresolution.GetCurSel()); + + pApp->WriteProfileInt(_T("GPUSettings"), _T("scale_x"), value & 3); + pApp->WriteProfileInt(_T("GPUSettings"), _T("scale_y"), (value >> 2) & 3); + } + + pApp->WriteProfileInt(_T("GPUSettings"), _T("swthreads"), m_swthreads.GetPos()); + + __super::OnOK(); +} + +void GPUSettingsDlg::OnUpdateResolution(CCmdUI* pCmdUI) +{ + UpdateData(); + + int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel()); + + pCmdUI->Enable(i == 1); +} + +void GPUSettingsDlg::OnUpdateD3D9Options(CCmdUI* pCmdUI) +{ + int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel()); + + pCmdUI->Enable(i == 1); +} + +void GPUSettingsDlg::OnUpdateSWOptions(CCmdUI* pCmdUI) +{ + int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel()); + + pCmdUI->Enable(i >= 0 && i <= 2); +} + +void GPUSettingsDlg::OnCbnSelchangeCombo1() +{ + int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel()); + + GetDlgItem(IDC_LOGO9)->ShowWindow(i == 1 ? SW_SHOW : SW_HIDE); + GetDlgItem(IDC_LOGO10)->ShowWindow(i == 2 ? SW_SHOW : SW_HIDE); +} diff --git a/plugins/GSdx/GPUSettingsDlg.h b/plugins/GSdx/GPUSettingsDlg.h index b91e9f496b..4602ef685b 100644 --- a/plugins/GSdx/GPUSettingsDlg.h +++ b/plugins/GSdx/GPUSettingsDlg.h @@ -1,71 +1,71 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSSetting.h" -#include "resource.h" - -class GPUSettingsDlg : public CDialog -{ - DECLARE_DYNAMIC(GPUSettingsDlg) - -private: - CAtlList m_modes; - -public: - GPUSettingsDlg(CWnd* pParent = NULL); // standard constructor - virtual ~GPUSettingsDlg(); - - static GSSetting g_renderers[]; - static GSSetting g_psversion[]; - static GSSetting g_filter[]; - static GSSetting g_dithering[]; - static GSSetting g_aspectratio[]; - static GSSetting g_internalresolution[]; - -// Dialog Data - enum { IDD = IDD_GPUCONFIG }; - CComboBox m_resolution; - CComboBox m_renderer; - CComboBox m_psversion; - CComboBox m_filter; - CComboBox m_dithering; - CComboBox m_aspectratio; - CComboBox m_internalresolution; - CSpinButtonCtrl m_swthreads; - CEdit m_swthreadsedit; - -protected: - virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam); - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnInitDialog(); - virtual void OnOK(); - - DECLARE_MESSAGE_MAP() - -public: - afx_msg void OnKickIdle(); - afx_msg void OnUpdateResolution(CCmdUI* pCmdUI); - afx_msg void OnUpdateD3D9Options(CCmdUI* pCmdUI); - afx_msg void OnUpdateSWOptions(CCmdUI* pCmdUI); - afx_msg void OnCbnSelchangeCombo1(); -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSSetting.h" +#include "resource.h" + +class GPUSettingsDlg : public CDialog +{ + DECLARE_DYNAMIC(GPUSettingsDlg) + +private: + CAtlList m_modes; + +public: + GPUSettingsDlg(CWnd* pParent = NULL); // standard constructor + virtual ~GPUSettingsDlg(); + + static GSSetting g_renderers[]; + static GSSetting g_psversion[]; + static GSSetting g_filter[]; + static GSSetting g_dithering[]; + static GSSetting g_aspectratio[]; + static GSSetting g_internalresolution[]; + +// Dialog Data + enum { IDD = IDD_GPUCONFIG }; + CComboBox m_resolution; + CComboBox m_renderer; + CComboBox m_psversion; + CComboBox m_filter; + CComboBox m_dithering; + CComboBox m_aspectratio; + CComboBox m_internalresolution; + CSpinButtonCtrl m_swthreads; + CEdit m_swthreadsedit; + +protected: + virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam); + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + virtual void OnOK(); + + DECLARE_MESSAGE_MAP() + +public: + afx_msg void OnKickIdle(); + afx_msg void OnUpdateResolution(CCmdUI* pCmdUI); + afx_msg void OnUpdateD3D9Options(CCmdUI* pCmdUI); + afx_msg void OnUpdateSWOptions(CCmdUI* pCmdUI); + afx_msg void OnCbnSelchangeCombo1(); +}; diff --git a/plugins/GSdx/GPUState.cpp b/plugins/GSdx/GPUState.cpp index da59192a73..8aa4d30ea3 100644 --- a/plugins/GSdx/GPUState.cpp +++ b/plugins/GSdx/GPUState.cpp @@ -1,747 +1,747 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GPUState.h" - -GPUState::GPUState(const CSize& scale) - : m_mem(scale) - , s_n(0) -{ - memset(m_status, 0, sizeof(m_status)); - - for(int i = 0; i < countof(m_fpGPUStatusCommandHandlers); i++) - { - m_fpGPUStatusCommandHandlers[i] = &GPUState::SCH_Null; - } - - m_fpGPUStatusCommandHandlers[0x00] = &GPUState::SCH_ResetGPU; - m_fpGPUStatusCommandHandlers[0x01] = &GPUState::SCH_ResetCommandBuffer; - m_fpGPUStatusCommandHandlers[0x02] = &GPUState::SCH_ResetIRQ; - m_fpGPUStatusCommandHandlers[0x03] = &GPUState::SCH_DisplayEnable; - m_fpGPUStatusCommandHandlers[0x04] = &GPUState::SCH_DMASetup; - m_fpGPUStatusCommandHandlers[0x05] = &GPUState::SCH_StartOfDisplayArea; - m_fpGPUStatusCommandHandlers[0x06] = &GPUState::SCH_HorizontalDisplayRange; - m_fpGPUStatusCommandHandlers[0x07] = &GPUState::SCH_VerticalDisplayRange; - m_fpGPUStatusCommandHandlers[0x08] = &GPUState::SCH_DisplayMode; - m_fpGPUStatusCommandHandlers[0x10] = &GPUState::SCH_GPUInfo; - - m_fpGPUPacketHandler[0] = &GPUState::PH_Command; - m_fpGPUPacketHandler[1] = &GPUState::PH_Polygon; - m_fpGPUPacketHandler[2] = &GPUState::PH_Line; - m_fpGPUPacketHandler[3] = &GPUState::PH_Sprite; - m_fpGPUPacketHandler[4] = &GPUState::PH_Move; - m_fpGPUPacketHandler[5] = &GPUState::PH_Write; - m_fpGPUPacketHandler[6] = &GPUState::PH_Read; - m_fpGPUPacketHandler[7] = &GPUState::PH_Environment; - - Reset(); -} - -GPUState::~GPUState() -{ -} - -void GPUState::Reset() -{ - m_env.Reset(); - - m_mem.Invalidate(CRect(0, 0, 1024, 512)); - - memset(&m_v, 0, sizeof(m_v)); -} - -void GPUState::Flush() -{ - FlushPrim(); -} - -void GPUState::SetPrim(GPUReg* r) -{ - if(m_env.PRIM.TYPE != r->PRIM.TYPE) - { - ResetPrim(); - } - - GPURegPRIM PRIM = r->PRIM; - - PRIM.VTX = 0; - - switch(r->PRIM.TYPE) - { - case GPU_POLYGON: - PRIM.ai32 = (r->PRIM.ai32 & 0xF7000000) | 3; // TYPE IIP TME ABE TGE - break; - case GPU_LINE: - PRIM.ai32 = (r->PRIM.ai32 & 0xF2000000) | 2; // TYPE IIP ABE - PRIM.TGE = 1; // ? - break; - case GPU_SPRITE: - PRIM.ai32 = (r->PRIM.ai32 & 0xE7000000) | 2; // TYPE TME ABE TGE - break; - } - - if(m_env.PRIM.ai32 != PRIM.ai32) - { - Flush(); - - m_env.PRIM = PRIM; - } -} - -void GPUState::SetCLUT(GPUReg* r) -{ - UINT32 mask = 0xFFFF0000; // X Y - - UINT32 value = (m_env.CLUT.ai32 & ~mask) | (r->ai32 & mask); - - if(m_env.CLUT.ai32 != value) - { - Flush(); - - m_env.CLUT.ai32 = value; - } -} - -void GPUState::SetTPAGE(GPUReg* r) -{ - UINT32 mask = 0x000001FF; // TP ABR TY TX - - UINT32 value = (m_env.STATUS.ai32 & ~mask) | ((r->ai32 >> 16) & mask); - - if(m_env.STATUS.ai32 != value) - { - Flush(); - - m_env.STATUS.ai32 = value; - } -} - -void GPUState::Invalidate(const CRect& r) -{ - m_mem.Invalidate(r); -} - -void GPUState::WriteData(const BYTE* mem, UINT32 size) -{ - GSPerfMonAutoTimer pmat(m_perfmon); - - size <<= 2; - - m_write.Append(mem, size); - - int i = 0; - - while(i < m_write.bytes) - { - GPUReg* r = (GPUReg*)&m_write.buff[i]; - - int ret = (this->*m_fpGPUPacketHandler[r->PACKET.TYPE])(r, (m_write.bytes - i) >> 2); - - if(ret == 0) return; // need more data - - i += ret << 2; - } - - m_write.Remove(i); -} - -void GPUState::ReadData(BYTE* mem, UINT32 size) -{ - GSPerfMonAutoTimer pmat(m_perfmon); - - int remaining = m_read.bytes - m_read.cur; - - int bytes = (int)size << 2; - - if(bytes > remaining) - { - // ASSERT(0); - - TRACE(_T("WARNING: ReadData\n")); - - // memset(&mem[remaining], 0, bytes - remaining); - - bytes = remaining; - } - - memcpy(mem, &m_read.buff[m_read.cur], bytes); - - m_read.cur += bytes; - - if(m_read.cur >= m_read.bytes) - { - m_env.STATUS.IMG = 0; - } -} - -void GPUState::WriteStatus(UINT32 status) -{ - GSPerfMonAutoTimer pmat(m_perfmon); - - UINT32 b = status >> 24; - - m_status[b] = status; - - (this->*m_fpGPUStatusCommandHandlers[b])((GPUReg*)&status); -} - -UINT32 GPUState::ReadStatus() -{ - GSPerfMonAutoTimer pmat(m_perfmon); - - m_env.STATUS.LCF = ~m_env.STATUS.LCF; // ? - - return m_env.STATUS.ai32; -} - -void GPUState::Freeze(GPUFreezeData* data) -{ - data->status = m_env.STATUS.ai32; - memcpy(data->control, m_status, 256 * 4); - m_mem.ReadRect(CRect(0, 0, 1024, 512), data->vram); -} - -void GPUState::Defrost(const GPUFreezeData* data) -{ - m_env.STATUS.ai32 = data->status; - memcpy(m_status, data->control, 256 * 4); - m_mem.WriteRect(CRect(0, 0, 1024, 512), data->vram); - - for(int i = 0; i <= 8; i++) - { - WriteStatus(m_status[i]); - } -} - -void GPUState::SCH_Null(GPUReg* r) -{ - ASSERT(0); -} - -void GPUState::SCH_ResetGPU(GPUReg* r) -{ - Reset(); -} - -void GPUState::SCH_ResetCommandBuffer(GPUReg* r) -{ - // ? -} - -void GPUState::SCH_ResetIRQ(GPUReg* r) -{ - // ? -} - -void GPUState::SCH_DisplayEnable(GPUReg* r) -{ - m_env.STATUS.DEN = r->DEN.DEN; -} - -void GPUState::SCH_DMASetup(GPUReg* r) -{ - m_env.STATUS.DMA = r->DMA.DMA; -} - -void GPUState::SCH_StartOfDisplayArea(GPUReg* r) -{ - m_env.DAREA = r->DAREA; -} - -void GPUState::SCH_HorizontalDisplayRange(GPUReg* r) -{ - m_env.DHRANGE = r->DHRANGE; -} - -void GPUState::SCH_VerticalDisplayRange(GPUReg* r) -{ - m_env.DVRANGE = r->DVRANGE; -} - -void GPUState::SCH_DisplayMode(GPUReg* r) -{ - m_env.STATUS.WIDTH0 = r->DMODE.WIDTH0; - m_env.STATUS.HEIGHT = r->DMODE.HEIGHT; - m_env.STATUS.ISPAL = r->DMODE.ISPAL; - m_env.STATUS.ISRGB24 = r->DMODE.ISRGB24; - m_env.STATUS.ISINTER = r->DMODE.ISINTER; - m_env.STATUS.WIDTH1 = r->DMODE.WIDTH1; -} - -void GPUState::SCH_GPUInfo(GPUReg* r) -{ - UINT32 value = 0; - - switch(r->GPUINFO.PARAM) - { - case 0x2: - value = m_env.TWIN.ai32; - break; - case 0x0: - case 0x1: - case 0x3: - value = m_env.DRAREATL.ai32; - break; - case 0x4: - value = m_env.DRAREABR.ai32; - break; - case 0x5: - case 0x6: - value = m_env.DROFF.ai32; - break; - case 0x7: - value = 2; - break; - case 0x8: - case 0xf: - value = 0xBFC03720; // ? - break; - default: - ASSERT(0); - break; - } - - m_read.RemoveAll(); - m_read.Append((BYTE*)&value, 4); - m_read.cur = 0; -} - -int GPUState::PH_Command(GPUReg* r, int size) -{ - switch(r->PACKET.OPTION) - { - case 0: // ??? - - return 1; - - case 1: // clear cache - - return 1; - - case 2: // fillrect - - if(size < 3) return 0; - - Flush(); - - CRect r2; - - r2.left = r[1].XY.X; - r2.top = r[1].XY.Y; - r2.right = r2.left + r[2].XY.X; - r2.bottom = r2.top + r[2].XY.Y; - - WORD c = (WORD)(((r[0].RGB.R >> 3) << 10) | ((r[0].RGB.R >> 3) << 5) | (r[0].RGB.R >> 3)); - - m_mem.FillRect(r2, c); - - Invalidate(r2); - - Dump(_T("f")); - - return 3; - } - - ASSERT(0); - - return 1; -} - -int GPUState::PH_Polygon(GPUReg* r, int size) -{ - int required = 1; - - int vertices = r[0].POLYGON.VTX ? 4 : 3; - - required += vertices; - - if(r[0].POLYGON.TME) required += vertices; - - if(r[0].POLYGON.IIP) required += vertices - 1; - - if(size < required) return 0; - - // - - SetPrim(r); - - if(r[0].POLYGON.TME) - { - SetCLUT(&r[2]); - - SetTPAGE(&r[r[0].POLYGON.IIP ? 5 : 4]); - } - - // - - GPUVertex v[4]; - - for(int i = 0, j = 0; j < vertices; j++) - { - v[j].RGB = r[r[0].POLYGON.IIP ? i : 0].RGB; - - if(j == 0 || r[0].POLYGON.IIP) i++; - - v[j].XY = r[i++].XY; - - if(r[0].POLYGON.TME) - { - v[j].UV.X = r[i].UV.U; - v[j].UV.Y = r[i].UV.V; - - i++; - } - } - - for(int i = 0; i <= vertices - 3; i++) - { - for(int j = 0; j < 3; j++) - { - m_v = v[i + j]; - - VertexKick(); - } - } - - // - - return required; -} - -int GPUState::PH_Line(GPUReg* r, int size) -{ - int required = 1; - - int vertices = 0; - - if(r->LINE.PLL) - { - required++; - - for(int i = 1; i < size; i++) - { - if(r[i].ai32 == 0x55555555) - { - vertices = i - 1; - } - } - - if(vertices < 2) - { - return 0; - } - } - else - { - vertices = 2; - } - - required += vertices; - - if(r->LINE.IIP) required += vertices - 1; - - // - - SetPrim(r); - - // - - for(int i = 0, j = 0; j < vertices; j++) - { - if(j >= 2) VertexKick(); - - m_v.RGB = r[r[0].LINE.IIP ? i : 0].RGB; - - if(j == 0 || r[0].LINE.IIP) i++; - - m_v.XY = r[i++].XY; - - VertexKick(); - } - - // - - return required; -} - -int GPUState::PH_Sprite(GPUReg* r, int size) -{ - int required = 2; - - if(r[0].SPRITE.TME) required++; - if(r[0].SPRITE.SIZE == 0) required++; - - if(size < required) return 0; - - // - - SetPrim(r); - - if(r[0].SPRITE.TME) - { - SetCLUT(&r[2]); - } - - // - - int i = 0; - - m_v.RGB = r[i++].RGB; - - m_v.XY = r[i++].XY; - - if(r[0].SPRITE.TME) - { - m_v.UV.X = r[i].UV.U; - m_v.UV.Y = r[i].UV.V; - - i++; - } - - VertexKick(); - - int w = 0; - int h = 0; - - switch(r[0].SPRITE.SIZE) - { - case 0: w = r[i].XY.X; h = r[i].XY.Y; i++; break; - case 1: w = h = 1; break; - case 2: w = h = 8; break; - case 3: w = h = 16; break; - default: __assume(0); - } - - m_v.XY.X += w; - m_v.XY.Y += h; - - if(r[0].SPRITE.TME) - { - m_v.UV.X += w; - m_v.UV.Y += h; - } - - VertexKick(); - - // - - return required; -} - -int GPUState::PH_Move(GPUReg* r, int size) -{ - if(size < 4) return 0; - - Flush(); - - CPoint src, dst; - - src.x = r[1].XY.X; - src.y = r[1].XY.Y; - - dst.x = r[2].XY.X; - dst.y = r[2].XY.Y; - - int w = r[3].XY.X; - int h = r[3].XY.Y; - - m_mem.MoveRect(src, dst, w, h); - - Invalidate(CRect(dst, CSize(w, h))); - - // Dump(_T("m")); - - return 4; -} - -int GPUState::PH_Write(GPUReg* r, int size) -{ - if(size < 3) return 0; - - int w = r[2].XY.X; - int h = r[2].XY.Y; - - int required = 3 + ((w * h + 1) >> 1); - - if(size < required) return 0; - - Flush(); - - CRect r2; - - r2.left = r[1].XY.X; - r2.top = r[1].XY.Y; - r2.right = r2.left + w; - r2.bottom = r2.top + h; - - m_mem.WriteRect(r2, (const WORD*)&r[3]); - - Invalidate(r2); - - Dump(_T("w")); - - m_perfmon.Put(GSPerfMon::Swizzle, w * h * 2); - - return required; -} - -int GPUState::PH_Read(GPUReg* r, int size) -{ - if(size < 3) return 0; - - Flush(); - - int w = r[2].XY.X; - int h = r[2].XY.Y; - - CRect r2; - - r2.left = r[1].XY.X; - r2.top = r[1].XY.Y; - r2.right = r2.left + w; - r2.bottom = r2.top + h; - - m_read.bytes = ((w * h + 1) & ~1) * 2; - m_read.cur = 0; - m_read.Reserve(m_read.bytes); - - m_mem.ReadRect(r2, (WORD*)m_read.buff); - - Dump(_T("r")); - - m_env.STATUS.IMG = 1; - - return 3; -} - -int GPUState::PH_Environment(GPUReg* r, int size) -{ - Flush(); // TODO: only call when something really changes - - switch(r->PACKET.OPTION) - { - case 1: // draw mode setting - - m_env.STATUS.TX = r->MODE.TX; - m_env.STATUS.TY = r->MODE.TY; - m_env.STATUS.ABR = r->MODE.ABR; - m_env.STATUS.TP = r->MODE.TP; - m_env.STATUS.DTD = r->MODE.DTD; - m_env.STATUS.DFE = r->MODE.DFE; - - return 1; - - case 2: // texture window setting - - m_env.TWIN = r->TWIN; - - return 1; - - case 3: // set drawing area top left - - m_env.DRAREATL = r->DRAREA; - - return 1; - - case 4: // set drawing area bottom right - - m_env.DRAREABR = r->DRAREA; - - return 1; - - case 5: // drawing offset - - m_env.DROFF = r->DROFF; - - return 1; - - case 6: // mask setting - - m_env.STATUS.MD = r->MASK.MD; - m_env.STATUS.ME = r->MASK.ME; - - return 1; - } - - ASSERT(0); - - return 1; -} - -// - -GPUState::Buffer::Buffer() -{ - bytes = 0; - maxbytes = 4096; - buff = (BYTE*)_aligned_malloc(maxbytes, 16); - cur = 0; -} - -GPUState::Buffer::~Buffer() -{ - _aligned_free(buff); -} - -void GPUState::Buffer::Reserve(int size) -{ - if(size > maxbytes) - { - maxbytes = (maxbytes + size + 1023) & ~1023; - - buff = (BYTE*)_aligned_realloc(buff, maxbytes, 16); - } -} - -void GPUState::Buffer::Append(const BYTE* src, int size) -{ - Reserve(bytes + (int)size); - - memcpy(&buff[bytes], src, size); - - bytes += size; -} - -void GPUState::Buffer::Remove(int size) -{ - ASSERT(size <= bytes); - - if(size < bytes) - { - memmove(&buff[0], &buff[size], bytes - size); - - bytes -= size; - } - else - { - bytes = 0; - } - - #ifdef DEBUG - memset(&buff[bytes], 0xff, maxbytes - bytes); - #endif -} - -void GPUState::Buffer::RemoveAll() -{ - bytes = 0; -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GPUState.h" + +GPUState::GPUState(const CSize& scale) + : m_mem(scale) + , s_n(0) +{ + memset(m_status, 0, sizeof(m_status)); + + for(int i = 0; i < countof(m_fpGPUStatusCommandHandlers); i++) + { + m_fpGPUStatusCommandHandlers[i] = &GPUState::SCH_Null; + } + + m_fpGPUStatusCommandHandlers[0x00] = &GPUState::SCH_ResetGPU; + m_fpGPUStatusCommandHandlers[0x01] = &GPUState::SCH_ResetCommandBuffer; + m_fpGPUStatusCommandHandlers[0x02] = &GPUState::SCH_ResetIRQ; + m_fpGPUStatusCommandHandlers[0x03] = &GPUState::SCH_DisplayEnable; + m_fpGPUStatusCommandHandlers[0x04] = &GPUState::SCH_DMASetup; + m_fpGPUStatusCommandHandlers[0x05] = &GPUState::SCH_StartOfDisplayArea; + m_fpGPUStatusCommandHandlers[0x06] = &GPUState::SCH_HorizontalDisplayRange; + m_fpGPUStatusCommandHandlers[0x07] = &GPUState::SCH_VerticalDisplayRange; + m_fpGPUStatusCommandHandlers[0x08] = &GPUState::SCH_DisplayMode; + m_fpGPUStatusCommandHandlers[0x10] = &GPUState::SCH_GPUInfo; + + m_fpGPUPacketHandler[0] = &GPUState::PH_Command; + m_fpGPUPacketHandler[1] = &GPUState::PH_Polygon; + m_fpGPUPacketHandler[2] = &GPUState::PH_Line; + m_fpGPUPacketHandler[3] = &GPUState::PH_Sprite; + m_fpGPUPacketHandler[4] = &GPUState::PH_Move; + m_fpGPUPacketHandler[5] = &GPUState::PH_Write; + m_fpGPUPacketHandler[6] = &GPUState::PH_Read; + m_fpGPUPacketHandler[7] = &GPUState::PH_Environment; + + Reset(); +} + +GPUState::~GPUState() +{ +} + +void GPUState::Reset() +{ + m_env.Reset(); + + m_mem.Invalidate(CRect(0, 0, 1024, 512)); + + memset(&m_v, 0, sizeof(m_v)); +} + +void GPUState::Flush() +{ + FlushPrim(); +} + +void GPUState::SetPrim(GPUReg* r) +{ + if(m_env.PRIM.TYPE != r->PRIM.TYPE) + { + ResetPrim(); + } + + GPURegPRIM PRIM = r->PRIM; + + PRIM.VTX = 0; + + switch(r->PRIM.TYPE) + { + case GPU_POLYGON: + PRIM.ai32 = (r->PRIM.ai32 & 0xF7000000) | 3; // TYPE IIP TME ABE TGE + break; + case GPU_LINE: + PRIM.ai32 = (r->PRIM.ai32 & 0xF2000000) | 2; // TYPE IIP ABE + PRIM.TGE = 1; // ? + break; + case GPU_SPRITE: + PRIM.ai32 = (r->PRIM.ai32 & 0xE7000000) | 2; // TYPE TME ABE TGE + break; + } + + if(m_env.PRIM.ai32 != PRIM.ai32) + { + Flush(); + + m_env.PRIM = PRIM; + } +} + +void GPUState::SetCLUT(GPUReg* r) +{ + UINT32 mask = 0xFFFF0000; // X Y + + UINT32 value = (m_env.CLUT.ai32 & ~mask) | (r->ai32 & mask); + + if(m_env.CLUT.ai32 != value) + { + Flush(); + + m_env.CLUT.ai32 = value; + } +} + +void GPUState::SetTPAGE(GPUReg* r) +{ + UINT32 mask = 0x000001FF; // TP ABR TY TX + + UINT32 value = (m_env.STATUS.ai32 & ~mask) | ((r->ai32 >> 16) & mask); + + if(m_env.STATUS.ai32 != value) + { + Flush(); + + m_env.STATUS.ai32 = value; + } +} + +void GPUState::Invalidate(const CRect& r) +{ + m_mem.Invalidate(r); +} + +void GPUState::WriteData(const BYTE* mem, UINT32 size) +{ + GSPerfMonAutoTimer pmat(m_perfmon); + + size <<= 2; + + m_write.Append(mem, size); + + int i = 0; + + while(i < m_write.bytes) + { + GPUReg* r = (GPUReg*)&m_write.buff[i]; + + int ret = (this->*m_fpGPUPacketHandler[r->PACKET.TYPE])(r, (m_write.bytes - i) >> 2); + + if(ret == 0) return; // need more data + + i += ret << 2; + } + + m_write.Remove(i); +} + +void GPUState::ReadData(BYTE* mem, UINT32 size) +{ + GSPerfMonAutoTimer pmat(m_perfmon); + + int remaining = m_read.bytes - m_read.cur; + + int bytes = (int)size << 2; + + if(bytes > remaining) + { + // ASSERT(0); + + TRACE(_T("WARNING: ReadData\n")); + + // memset(&mem[remaining], 0, bytes - remaining); + + bytes = remaining; + } + + memcpy(mem, &m_read.buff[m_read.cur], bytes); + + m_read.cur += bytes; + + if(m_read.cur >= m_read.bytes) + { + m_env.STATUS.IMG = 0; + } +} + +void GPUState::WriteStatus(UINT32 status) +{ + GSPerfMonAutoTimer pmat(m_perfmon); + + UINT32 b = status >> 24; + + m_status[b] = status; + + (this->*m_fpGPUStatusCommandHandlers[b])((GPUReg*)&status); +} + +UINT32 GPUState::ReadStatus() +{ + GSPerfMonAutoTimer pmat(m_perfmon); + + m_env.STATUS.LCF = ~m_env.STATUS.LCF; // ? + + return m_env.STATUS.ai32; +} + +void GPUState::Freeze(GPUFreezeData* data) +{ + data->status = m_env.STATUS.ai32; + memcpy(data->control, m_status, 256 * 4); + m_mem.ReadRect(CRect(0, 0, 1024, 512), data->vram); +} + +void GPUState::Defrost(const GPUFreezeData* data) +{ + m_env.STATUS.ai32 = data->status; + memcpy(m_status, data->control, 256 * 4); + m_mem.WriteRect(CRect(0, 0, 1024, 512), data->vram); + + for(int i = 0; i <= 8; i++) + { + WriteStatus(m_status[i]); + } +} + +void GPUState::SCH_Null(GPUReg* r) +{ + ASSERT(0); +} + +void GPUState::SCH_ResetGPU(GPUReg* r) +{ + Reset(); +} + +void GPUState::SCH_ResetCommandBuffer(GPUReg* r) +{ + // ? +} + +void GPUState::SCH_ResetIRQ(GPUReg* r) +{ + // ? +} + +void GPUState::SCH_DisplayEnable(GPUReg* r) +{ + m_env.STATUS.DEN = r->DEN.DEN; +} + +void GPUState::SCH_DMASetup(GPUReg* r) +{ + m_env.STATUS.DMA = r->DMA.DMA; +} + +void GPUState::SCH_StartOfDisplayArea(GPUReg* r) +{ + m_env.DAREA = r->DAREA; +} + +void GPUState::SCH_HorizontalDisplayRange(GPUReg* r) +{ + m_env.DHRANGE = r->DHRANGE; +} + +void GPUState::SCH_VerticalDisplayRange(GPUReg* r) +{ + m_env.DVRANGE = r->DVRANGE; +} + +void GPUState::SCH_DisplayMode(GPUReg* r) +{ + m_env.STATUS.WIDTH0 = r->DMODE.WIDTH0; + m_env.STATUS.HEIGHT = r->DMODE.HEIGHT; + m_env.STATUS.ISPAL = r->DMODE.ISPAL; + m_env.STATUS.ISRGB24 = r->DMODE.ISRGB24; + m_env.STATUS.ISINTER = r->DMODE.ISINTER; + m_env.STATUS.WIDTH1 = r->DMODE.WIDTH1; +} + +void GPUState::SCH_GPUInfo(GPUReg* r) +{ + UINT32 value = 0; + + switch(r->GPUINFO.PARAM) + { + case 0x2: + value = m_env.TWIN.ai32; + break; + case 0x0: + case 0x1: + case 0x3: + value = m_env.DRAREATL.ai32; + break; + case 0x4: + value = m_env.DRAREABR.ai32; + break; + case 0x5: + case 0x6: + value = m_env.DROFF.ai32; + break; + case 0x7: + value = 2; + break; + case 0x8: + case 0xf: + value = 0xBFC03720; // ? + break; + default: + ASSERT(0); + break; + } + + m_read.RemoveAll(); + m_read.Append((BYTE*)&value, 4); + m_read.cur = 0; +} + +int GPUState::PH_Command(GPUReg* r, int size) +{ + switch(r->PACKET.OPTION) + { + case 0: // ??? + + return 1; + + case 1: // clear cache + + return 1; + + case 2: // fillrect + + if(size < 3) return 0; + + Flush(); + + CRect r2; + + r2.left = r[1].XY.X; + r2.top = r[1].XY.Y; + r2.right = r2.left + r[2].XY.X; + r2.bottom = r2.top + r[2].XY.Y; + + WORD c = (WORD)(((r[0].RGB.R >> 3) << 10) | ((r[0].RGB.R >> 3) << 5) | (r[0].RGB.R >> 3)); + + m_mem.FillRect(r2, c); + + Invalidate(r2); + + Dump(_T("f")); + + return 3; + } + + ASSERT(0); + + return 1; +} + +int GPUState::PH_Polygon(GPUReg* r, int size) +{ + int required = 1; + + int vertices = r[0].POLYGON.VTX ? 4 : 3; + + required += vertices; + + if(r[0].POLYGON.TME) required += vertices; + + if(r[0].POLYGON.IIP) required += vertices - 1; + + if(size < required) return 0; + + // + + SetPrim(r); + + if(r[0].POLYGON.TME) + { + SetCLUT(&r[2]); + + SetTPAGE(&r[r[0].POLYGON.IIP ? 5 : 4]); + } + + // + + GPUVertex v[4]; + + for(int i = 0, j = 0; j < vertices; j++) + { + v[j].RGB = r[r[0].POLYGON.IIP ? i : 0].RGB; + + if(j == 0 || r[0].POLYGON.IIP) i++; + + v[j].XY = r[i++].XY; + + if(r[0].POLYGON.TME) + { + v[j].UV.X = r[i].UV.U; + v[j].UV.Y = r[i].UV.V; + + i++; + } + } + + for(int i = 0; i <= vertices - 3; i++) + { + for(int j = 0; j < 3; j++) + { + m_v = v[i + j]; + + VertexKick(); + } + } + + // + + return required; +} + +int GPUState::PH_Line(GPUReg* r, int size) +{ + int required = 1; + + int vertices = 0; + + if(r->LINE.PLL) + { + required++; + + for(int i = 1; i < size; i++) + { + if(r[i].ai32 == 0x55555555) + { + vertices = i - 1; + } + } + + if(vertices < 2) + { + return 0; + } + } + else + { + vertices = 2; + } + + required += vertices; + + if(r->LINE.IIP) required += vertices - 1; + + // + + SetPrim(r); + + // + + for(int i = 0, j = 0; j < vertices; j++) + { + if(j >= 2) VertexKick(); + + m_v.RGB = r[r[0].LINE.IIP ? i : 0].RGB; + + if(j == 0 || r[0].LINE.IIP) i++; + + m_v.XY = r[i++].XY; + + VertexKick(); + } + + // + + return required; +} + +int GPUState::PH_Sprite(GPUReg* r, int size) +{ + int required = 2; + + if(r[0].SPRITE.TME) required++; + if(r[0].SPRITE.SIZE == 0) required++; + + if(size < required) return 0; + + // + + SetPrim(r); + + if(r[0].SPRITE.TME) + { + SetCLUT(&r[2]); + } + + // + + int i = 0; + + m_v.RGB = r[i++].RGB; + + m_v.XY = r[i++].XY; + + if(r[0].SPRITE.TME) + { + m_v.UV.X = r[i].UV.U; + m_v.UV.Y = r[i].UV.V; + + i++; + } + + VertexKick(); + + int w = 0; + int h = 0; + + switch(r[0].SPRITE.SIZE) + { + case 0: w = r[i].XY.X; h = r[i].XY.Y; i++; break; + case 1: w = h = 1; break; + case 2: w = h = 8; break; + case 3: w = h = 16; break; + default: __assume(0); + } + + m_v.XY.X += w; + m_v.XY.Y += h; + + if(r[0].SPRITE.TME) + { + m_v.UV.X += w; + m_v.UV.Y += h; + } + + VertexKick(); + + // + + return required; +} + +int GPUState::PH_Move(GPUReg* r, int size) +{ + if(size < 4) return 0; + + Flush(); + + CPoint src, dst; + + src.x = r[1].XY.X; + src.y = r[1].XY.Y; + + dst.x = r[2].XY.X; + dst.y = r[2].XY.Y; + + int w = r[3].XY.X; + int h = r[3].XY.Y; + + m_mem.MoveRect(src, dst, w, h); + + Invalidate(CRect(dst, CSize(w, h))); + + // Dump(_T("m")); + + return 4; +} + +int GPUState::PH_Write(GPUReg* r, int size) +{ + if(size < 3) return 0; + + int w = r[2].XY.X; + int h = r[2].XY.Y; + + int required = 3 + ((w * h + 1) >> 1); + + if(size < required) return 0; + + Flush(); + + CRect r2; + + r2.left = r[1].XY.X; + r2.top = r[1].XY.Y; + r2.right = r2.left + w; + r2.bottom = r2.top + h; + + m_mem.WriteRect(r2, (const WORD*)&r[3]); + + Invalidate(r2); + + Dump(_T("w")); + + m_perfmon.Put(GSPerfMon::Swizzle, w * h * 2); + + return required; +} + +int GPUState::PH_Read(GPUReg* r, int size) +{ + if(size < 3) return 0; + + Flush(); + + int w = r[2].XY.X; + int h = r[2].XY.Y; + + CRect r2; + + r2.left = r[1].XY.X; + r2.top = r[1].XY.Y; + r2.right = r2.left + w; + r2.bottom = r2.top + h; + + m_read.bytes = ((w * h + 1) & ~1) * 2; + m_read.cur = 0; + m_read.Reserve(m_read.bytes); + + m_mem.ReadRect(r2, (WORD*)m_read.buff); + + Dump(_T("r")); + + m_env.STATUS.IMG = 1; + + return 3; +} + +int GPUState::PH_Environment(GPUReg* r, int size) +{ + Flush(); // TODO: only call when something really changes + + switch(r->PACKET.OPTION) + { + case 1: // draw mode setting + + m_env.STATUS.TX = r->MODE.TX; + m_env.STATUS.TY = r->MODE.TY; + m_env.STATUS.ABR = r->MODE.ABR; + m_env.STATUS.TP = r->MODE.TP; + m_env.STATUS.DTD = r->MODE.DTD; + m_env.STATUS.DFE = r->MODE.DFE; + + return 1; + + case 2: // texture window setting + + m_env.TWIN = r->TWIN; + + return 1; + + case 3: // set drawing area top left + + m_env.DRAREATL = r->DRAREA; + + return 1; + + case 4: // set drawing area bottom right + + m_env.DRAREABR = r->DRAREA; + + return 1; + + case 5: // drawing offset + + m_env.DROFF = r->DROFF; + + return 1; + + case 6: // mask setting + + m_env.STATUS.MD = r->MASK.MD; + m_env.STATUS.ME = r->MASK.ME; + + return 1; + } + + ASSERT(0); + + return 1; +} + +// + +GPUState::Buffer::Buffer() +{ + bytes = 0; + maxbytes = 4096; + buff = (BYTE*)_aligned_malloc(maxbytes, 16); + cur = 0; +} + +GPUState::Buffer::~Buffer() +{ + _aligned_free(buff); +} + +void GPUState::Buffer::Reserve(int size) +{ + if(size > maxbytes) + { + maxbytes = (maxbytes + size + 1023) & ~1023; + + buff = (BYTE*)_aligned_realloc(buff, maxbytes, 16); + } +} + +void GPUState::Buffer::Append(const BYTE* src, int size) +{ + Reserve(bytes + (int)size); + + memcpy(&buff[bytes], src, size); + + bytes += size; +} + +void GPUState::Buffer::Remove(int size) +{ + ASSERT(size <= bytes); + + if(size < bytes) + { + memmove(&buff[0], &buff[size], bytes - size); + + bytes -= size; + } + else + { + bytes = 0; + } + + #ifdef DEBUG + memset(&buff[bytes], 0xff, maxbytes - bytes); + #endif +} + +void GPUState::Buffer::RemoveAll() +{ + bytes = 0; +} diff --git a/plugins/GSdx/GPUState.h b/plugins/GSdx/GPUState.h index 68d1eadd84..8888dd7ce3 100644 --- a/plugins/GSdx/GPUState.h +++ b/plugins/GSdx/GPUState.h @@ -1,143 +1,143 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GPU.h" -#include "GPUDrawingEnvironment.h" -#include "GPULocalMemory.h" -#include "GPUVertex.h" -#include "GSAlignedClass.h" -#include "GSUtil.h" -#include "GSPerfMon.h" - -class GPUState : public GSAlignedClass<16> -{ - typedef void (GPUState::*GPUStatusCommandHandler)(GPUReg* r); - - GPUStatusCommandHandler m_fpGPUStatusCommandHandlers[256]; - - void SCH_Null(GPUReg* r); - void SCH_ResetGPU(GPUReg* r); - void SCH_ResetCommandBuffer(GPUReg* r); - void SCH_ResetIRQ(GPUReg* r); - void SCH_DisplayEnable(GPUReg* r); - void SCH_DMASetup(GPUReg* r); - void SCH_StartOfDisplayArea(GPUReg* r); - void SCH_HorizontalDisplayRange(GPUReg* r); - void SCH_VerticalDisplayRange(GPUReg* r); - void SCH_DisplayMode(GPUReg* r); - void SCH_GPUInfo(GPUReg* r); - - typedef int (GPUState::*GPUPacketHandler)(GPUReg* r, int size); - - GPUPacketHandler m_fpGPUPacketHandler[8]; - - int PH_Command(GPUReg* r, int size); - int PH_Polygon(GPUReg* r, int size); - int PH_Line(GPUReg* r, int size); - int PH_Sprite(GPUReg* r, int size); - int PH_Move(GPUReg* r, int size); - int PH_Write(GPUReg* r, int size); - int PH_Read(GPUReg* r, int size); - int PH_Environment(GPUReg* r, int size); - - class Buffer - { - public: - int bytes; - int maxbytes; - BYTE* buff; - int cur; - - public: - Buffer(); - ~Buffer(); - void Reserve(int size); - void Append(const BYTE* src, int size); - void Remove(int size); - void RemoveAll(); - }; - - Buffer m_write; - Buffer m_read; - - void SetPrim(GPUReg* r); - void SetCLUT(GPUReg* r); - void SetTPAGE(GPUReg* r); - -protected: - - int s_n; - - void Dump(LPCTSTR s, UINT32 TP, const CRect& r, int inc = true) - { - //if(m_perfmon.GetFrame() < 1000) - //if((m_env.TWIN.ai32 & 0xfffff) == 0) - //if(!m_env.STATUS.ME && !m_env.STATUS.MD) - return; - - if(inc) s_n++; - - //if(s_n < 86) return; - - int dir = 1; -#ifdef DEBUG - dir = 2; -#endif - CString str; - str.Format(_T("c:\\temp%d\\%04d_%s.bmp"), dir, s_n, s); - m_mem.SaveBMP(str, r, TP, m_env.CLUT.X, m_env.CLUT.Y); - } - - void Dump(LPCTSTR s, int inc = true) - { - Dump(s, 2, CRect(0, 0, 1024, 512), inc); - } - -public: - GPUDrawingEnvironment m_env; - GPULocalMemory m_mem; - GPUVertex m_v; - GSPerfMon m_perfmon; - UINT32 m_status[256]; - -public: - GPUState(const CSize& scale); - virtual ~GPUState(); - - virtual void Reset(); - virtual void Flush(); - virtual void FlushPrim() = 0; - virtual void ResetPrim() = 0; - virtual void VertexKick() = 0; - virtual void Invalidate(const CRect& r); - - void WriteData(const BYTE* mem, UINT32 size); - void ReadData(BYTE* mem, UINT32 size); - - void WriteStatus(UINT32 status); - UINT32 ReadStatus(); - - void Freeze(GPUFreezeData* data); - void Defrost(const GPUFreezeData* data); -}; - +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GPU.h" +#include "GPUDrawingEnvironment.h" +#include "GPULocalMemory.h" +#include "GPUVertex.h" +#include "GSAlignedClass.h" +#include "GSUtil.h" +#include "GSPerfMon.h" + +class GPUState : public GSAlignedClass<16> +{ + typedef void (GPUState::*GPUStatusCommandHandler)(GPUReg* r); + + GPUStatusCommandHandler m_fpGPUStatusCommandHandlers[256]; + + void SCH_Null(GPUReg* r); + void SCH_ResetGPU(GPUReg* r); + void SCH_ResetCommandBuffer(GPUReg* r); + void SCH_ResetIRQ(GPUReg* r); + void SCH_DisplayEnable(GPUReg* r); + void SCH_DMASetup(GPUReg* r); + void SCH_StartOfDisplayArea(GPUReg* r); + void SCH_HorizontalDisplayRange(GPUReg* r); + void SCH_VerticalDisplayRange(GPUReg* r); + void SCH_DisplayMode(GPUReg* r); + void SCH_GPUInfo(GPUReg* r); + + typedef int (GPUState::*GPUPacketHandler)(GPUReg* r, int size); + + GPUPacketHandler m_fpGPUPacketHandler[8]; + + int PH_Command(GPUReg* r, int size); + int PH_Polygon(GPUReg* r, int size); + int PH_Line(GPUReg* r, int size); + int PH_Sprite(GPUReg* r, int size); + int PH_Move(GPUReg* r, int size); + int PH_Write(GPUReg* r, int size); + int PH_Read(GPUReg* r, int size); + int PH_Environment(GPUReg* r, int size); + + class Buffer + { + public: + int bytes; + int maxbytes; + BYTE* buff; + int cur; + + public: + Buffer(); + ~Buffer(); + void Reserve(int size); + void Append(const BYTE* src, int size); + void Remove(int size); + void RemoveAll(); + }; + + Buffer m_write; + Buffer m_read; + + void SetPrim(GPUReg* r); + void SetCLUT(GPUReg* r); + void SetTPAGE(GPUReg* r); + +protected: + + int s_n; + + void Dump(LPCTSTR s, UINT32 TP, const CRect& r, int inc = true) + { + //if(m_perfmon.GetFrame() < 1000) + //if((m_env.TWIN.ai32 & 0xfffff) == 0) + //if(!m_env.STATUS.ME && !m_env.STATUS.MD) + return; + + if(inc) s_n++; + + //if(s_n < 86) return; + + int dir = 1; +#ifdef DEBUG + dir = 2; +#endif + CString str; + str.Format(_T("c:\\temp%d\\%04d_%s.bmp"), dir, s_n, s); + m_mem.SaveBMP(str, r, TP, m_env.CLUT.X, m_env.CLUT.Y); + } + + void Dump(LPCTSTR s, int inc = true) + { + Dump(s, 2, CRect(0, 0, 1024, 512), inc); + } + +public: + GPUDrawingEnvironment m_env; + GPULocalMemory m_mem; + GPUVertex m_v; + GSPerfMon m_perfmon; + UINT32 m_status[256]; + +public: + GPUState(const CSize& scale); + virtual ~GPUState(); + + virtual void Reset(); + virtual void Flush(); + virtual void FlushPrim() = 0; + virtual void ResetPrim() = 0; + virtual void VertexKick() = 0; + virtual void Invalidate(const CRect& r); + + void WriteData(const BYTE* mem, UINT32 size); + void ReadData(BYTE* mem, UINT32 size); + + void WriteStatus(UINT32 status); + UINT32 ReadStatus(); + + void Freeze(GPUFreezeData* data); + void Defrost(const GPUFreezeData* data); +}; + diff --git a/plugins/GSdx/GPUVertex.h b/plugins/GSdx/GPUVertex.h index 7ae86ca426..cb0c4a3049 100644 --- a/plugins/GSdx/GPUVertex.h +++ b/plugins/GSdx/GPUVertex.h @@ -1,51 +1,51 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GPU.h" -#include "GSVector.h" - -#pragma pack(push, 1) - -__declspec(align(16)) struct GPUVertex -{ - union - { - struct - { - GPURegRGB RGB; - GPURegXY XY; - GPURegXY UV; - }; - - struct {__m128i m128i;}; - struct {__m128 m128;}; - }; - - GPUVertex() {memset(this, 0, sizeof(*this));} -}; - -struct GPUVertexNull -{ -}; - -#pragma pack(pop) +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GPU.h" +#include "GSVector.h" + +#pragma pack(push, 1) + +__declspec(align(16)) struct GPUVertex +{ + union + { + struct + { + GPURegRGB RGB; + GPURegXY XY; + GPURegXY UV; + }; + + struct {__m128i m128i;}; + struct {__m128 m128;}; + }; + + GPUVertex() {memset(this, 0, sizeof(*this));} +}; + +struct GPUVertexNull +{ +}; + +#pragma pack(pop) diff --git a/plugins/GSdx/GS.cpp b/plugins/GSdx/GS.cpp index 02aeb9e006..062fbd24c2 100644 --- a/plugins/GSdx/GS.cpp +++ b/plugins/GSdx/GS.cpp @@ -1,589 +1,589 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GSUtil.h" -#include "GSRendererHW9.h" -#include "GSRendererHW10.h" -#include "GSRendererSW.h" -#include "GSRendererNull.h" -#include "GSSettingsDlg.h" - -#define PS2E_LT_GS 0x01 -#define PS2E_GS_VERSION 0x0006 -#define PS2E_X86 0x01 // 32 bit -#define PS2E_X86_64 0x02 // 64 bit - -static HRESULT s_hr = E_FAIL; -static GSRendererBase* s_gs = NULL; -static void (*s_irq)() = NULL; -static BYTE* s_basemem = NULL; - -EXPORT_C_(UINT32) PS2EgetLibType() -{ - return PS2E_LT_GS; -} - -EXPORT_C_(char*) PS2EgetLibName() -{ - return GSUtil::GetLibName(); -} - -EXPORT_C_(UINT32) PS2EgetLibVersion2(UINT32 type) -{ - const UINT32 revision = 0; - const UINT32 build = 1; - - return (build << 0) | (revision << 8) | (PS2E_GS_VERSION << 16) | (PLUGIN_VERSION << 24); -} - -EXPORT_C_(UINT32) PS2EgetCpuPlatform() -{ -#if _M_AMD64 - return PS2E_X86_64; -#else - return PS2E_X86; -#endif -} - -EXPORT_C GSsetBaseMem(BYTE* mem) -{ - s_basemem = mem - 0x12000000; -} - -EXPORT_C_(INT32) GSinit() -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - return 0; -} - -EXPORT_C GSshutdown() -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); -} - -EXPORT_C GSclose() -{ - delete s_gs; - - s_gs = NULL; - - if(SUCCEEDED(s_hr)) - { - ::CoUninitialize(); - - s_hr = E_FAIL; - } -} - -static INT32 GSopen(void* dsp, char* title, int mt, int renderer) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - if(!GSUtil::CheckDirectX() || !GSUtil::CheckSSE()) - { - return -1; - } - - GSclose(); - - // TODO - - int nloophack = AfxGetApp()->GetProfileInt(_T("Settings"), _T("nloophack"), 2); - - GSRendererSettings rs; - - rs.m_interlace = AfxGetApp()->GetProfileInt(_T("Settings"), _T("interlace"), 0); - rs.m_aspectratio = AfxGetApp()->GetProfileInt(_T("Settings"), _T("aspectratio"), 1); - rs.m_filter = AfxGetApp()->GetProfileInt(_T("Settings"), _T("filter"), 1); - rs.m_vsync = !!AfxGetApp()->GetProfileInt(_T("Settings"), _T("vsync"), FALSE); - rs.m_nativeres = !!AfxGetApp()->GetProfileInt(_T("Settings"), _T("nativeres"), FALSE); - - int threads = AfxGetApp()->GetProfileInt(_T("Settings"), _T("swthreads"), 1); - - switch(renderer) - { - default: - case 0: s_gs = new GSRendererHW9(s_basemem, !!mt, s_irq, nloophack, rs); break; - case 1: s_gs = new GSRendererSW(s_basemem, !!mt, s_irq, nloophack, rs, threads); break; - case 2: s_gs = new GSRendererNull(s_basemem, !!mt, s_irq, nloophack, rs); break; - case 3: s_gs = new GSRendererHW10(s_basemem, !!mt, s_irq, nloophack, rs); break; - case 4: s_gs = new GSRendererSW(s_basemem, !!mt, s_irq, nloophack, rs, threads); break; - case 5: s_gs = new GSRendererNull(s_basemem, !!mt, s_irq, nloophack, rs); break; - case 6: s_gs = new GSRendererSW(s_basemem, !!mt, s_irq, nloophack, rs, threads); break; - case 7: s_gs = new GSRendererNull(s_basemem, !!mt, s_irq, nloophack, rs); break; - } - - s_hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED); - - if(!s_gs->Create(CString(title))) - { - GSclose(); - - return -1; - } - - s_gs->m_wnd.Show(); - - *(HWND*)dsp = s_gs->m_wnd; - - // if(mt) _mm_setcsr(MXCSR); - - return 0; -} - -EXPORT_C_(INT32) GSopen(void* dsp, char* title, int mt) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - int renderer = AfxGetApp()->GetProfileInt(_T("Settings"), _T("renderer"), 0); - - return GSopen(dsp, title, mt, renderer); -} - -EXPORT_C GSreset() -{ - s_gs->Reset(); -} - -EXPORT_C GSgifSoftReset(int mask) -{ - s_gs->SoftReset((BYTE)mask); -} - -EXPORT_C GSwriteCSR(UINT32 csr) -{ - s_gs->WriteCSR(csr); -} - -EXPORT_C GSreadFIFO(BYTE* mem) -{ - s_gs->ReadFIFO(mem, 1); -} - -EXPORT_C GSreadFIFO2(BYTE* mem, UINT32 size) -{ - s_gs->ReadFIFO(mem, size); -} - -EXPORT_C GSgifTransfer1(BYTE* mem, UINT32 addr) -{ - s_gs->Transfer<0>(mem + addr, (0x4000 - addr) / 16); -} - -EXPORT_C GSgifTransfer2(BYTE* mem, UINT32 size) -{ - s_gs->Transfer<1>(mem, size); -} - -EXPORT_C GSgifTransfer3(BYTE* mem, UINT32 size) -{ - s_gs->Transfer<2>(mem, size); -} - -EXPORT_C GSvsync(int field) -{ - s_gs->VSync(field); -} - -EXPORT_C_(UINT32) GSmakeSnapshot(char* path) -{ - return s_gs->MakeSnapshot(CString(path) + _T("gsdx")); -} - -EXPORT_C GSkeyEvent(keyEvent* ev) -{ -} - -EXPORT_C_(INT32) GSfreeze(int mode, GSFreezeData* data) -{ - if(mode == FREEZE_SAVE) - { - return s_gs->Freeze(data, false); - } - else if(mode == FREEZE_SIZE) - { - return s_gs->Freeze(data, true); - } - else if(mode == FREEZE_LOAD) - { - return s_gs->Defrost(data); - } - - return 0; -} - -EXPORT_C GSconfigure() -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - GSSettingsDlg dlg; - - if(IDOK == dlg.DoModal()) - { - GSshutdown(); - GSinit(); - } -} - -EXPORT_C_(INT32) GStest() -{ - return 0; - - // TODO - - /* - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - CComPtr dev; - - return SUCCEEDED(D3D10CreateDevice(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, 0, D3D10_SDK_VERSION, &dev)) ? 0 : -1; - */ -} - -EXPORT_C GSabout() -{ -} - -EXPORT_C GSirqCallback(void (*irq)()) -{ - s_irq = irq; -} - -EXPORT_C GSsetGameCRC(DWORD crc, int options) -{ - s_gs->SetGameCRC(crc, options); -} - -EXPORT_C GSgetLastTag(UINT32* tag) -{ - s_gs->GetLastTag(tag); -} - -EXPORT_C GSsetFrameSkip(int frameskip) -{ - s_gs->SetFrameSkip(frameskip); -} - -EXPORT_C GSReplay(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) -{ - int renderer = -1; - - { - char* start = lpszCmdLine; - char* end = NULL; - long n = strtol(lpszCmdLine, &end, 10); - if(end > start) {renderer = n; lpszCmdLine = end;} - } - - while(*lpszCmdLine == ' ') lpszCmdLine++; - - ::SetPriorityClass(::GetCurrentProcess(), HIGH_PRIORITY_CLASS); - - CAtlArray buff; - - if(FILE* fp = fopen(lpszCmdLine, "rb")) - { - GSinit(); - - BYTE regs[0x2000]; - GSsetBaseMem(regs); - - HWND hWnd = NULL; - GSopen(&hWnd, _T(""), true, renderer); - - DWORD crc; - fread(&crc, 4, 1, fp); - GSsetGameCRC(crc, 0); - - GSFreezeData fd; - fread(&fd.size, 4, 1, fp); - fd.data = new BYTE[fd.size]; - fread(fd.data, fd.size, 1, fp); - GSfreeze(FREEZE_LOAD, &fd); - delete [] fd.data; - - fread(regs, 0x2000, 1, fp); - - long start = ftell(fp); - - unsigned int index, size, addr; - - GSvsync(1); - - while(1) - { - switch(fgetc(fp)) - { - case EOF: - fseek(fp, start, 0); - if(!IsWindowVisible(hWnd)) return; - break; - case 0: - index = fgetc(fp); - fread(&size, 4, 1, fp); - switch(index) - { - case 0: - if(buff.GetCount() < 0x4000) buff.SetCount(0x4000); - addr = 0x4000 - size; - fread(buff.GetData() + addr, size, 1, fp); - GSgifTransfer1(buff.GetData(), addr); - break; - case 1: - if(buff.GetCount() < size) buff.SetCount(size); - fread(buff.GetData(), size, 1, fp); - GSgifTransfer2(buff.GetData(), size / 16); - break; - case 2: - if(buff.GetCount() < size) buff.SetCount(size); - fread(buff.GetData(), size, 1, fp); - GSgifTransfer3(buff.GetData(), size / 16); - break; - } - break; - case 1: - GSvsync(fgetc(fp)); - if(!IsWindowVisible(hWnd)) return; - break; - case 2: - fread(&size, 4, 1, fp); - if(buff.GetCount() < size) buff.SetCount(size); - GSreadFIFO2(buff.GetData(), size / 16); - break; - case 3: - fread(regs, 0x2000, 1, fp); - break; - default: - return; - } - } - - GSclose(); - - GSshutdown(); - - fclose(fp); - } -} - -EXPORT_C GSBenchmark(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) -{ - ::SetPriorityClass(::GetCurrentProcess(), HIGH_PRIORITY_CLASS); - - FILE* file = _tfopen(_T("c:\\log.txt"), _T("a")); - - _ftprintf(file, _T("-------------------------\n\n")); - - if(1) - { - GSLocalMemory mem; - - static struct {int psm; LPCSTR name;} s_format[] = - { - {PSM_PSMCT32, "32"}, - {PSM_PSMCT24, "24"}, - {PSM_PSMCT16, "16"}, - {PSM_PSMCT16S, "16S"}, - {PSM_PSMT8, "8"}, - {PSM_PSMT4, "4"}, - {PSM_PSMT8H, "8H"}, - {PSM_PSMT4HL, "4HL"}, - {PSM_PSMT4HH, "4HH"}, - {PSM_PSMZ32, "32Z"}, - {PSM_PSMZ24, "24Z"}, - {PSM_PSMZ16, "16Z"}, - {PSM_PSMZ16S, "16ZS"}, - }; - - BYTE* ptr = (BYTE*)_aligned_malloc(1024 * 1024 * 4, 16); - - for(int i = 0; i < 1024 * 1024 * 4; i++) ptr[i] = (BYTE)i; - - // - - for(int tbw = 5; tbw <= 10; tbw++) - { - int n = 256 << ((10 - tbw) * 2); - - int w = 1 << tbw; - int h = 1 << tbw; - - _ftprintf(file, _T("%d x %d\n\n"), w, h); - - for(int i = 0; i < countof(s_format); i++) - { - const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[s_format[i].psm]; - - GSLocalMemory::writeImage wi = psm.wi; - GSLocalMemory::readImage ri = psm.ri; - GSLocalMemory::readTexture rtx = psm.rtx; - GSLocalMemory::readTexture rtxP = psm.rtxP; - - GIFRegBITBLTBUF BITBLTBUF; - - BITBLTBUF.SBP = 0; - BITBLTBUF.SBW = w / 64; - BITBLTBUF.SPSM = s_format[i].psm; - BITBLTBUF.DBP = 0; - BITBLTBUF.DBW = w / 64; - BITBLTBUF.DPSM = s_format[i].psm; - - GIFRegTRXPOS TRXPOS; - - TRXPOS.SSAX = 0; - TRXPOS.SSAY = 0; - TRXPOS.DSAX = 0; - TRXPOS.DSAY = 0; - - GIFRegTRXREG TRXREG; - - TRXREG.RRW = w; - TRXREG.RRH = h; - - CRect r(0, 0, w, h); - - GIFRegTEX0 TEX0; - - TEX0.TBP0 = 0; - TEX0.TBW = w / 64; - - GIFRegTEXA TEXA; - - TEXA.TA0 = 0; - TEXA.TA1 = 0x80; - TEXA.AEM = 0; - - int trlen = w * h * psm.trbpp / 8; - int len = w * h * psm.bpp / 8; - - clock_t start, end; - - _ftprintf(file, _T("[%4s] "), s_format[i].name); - - start = clock(); - - for(int j = 0; j < n; j++) - { - int x = 0; - int y = 0; - - (mem.*wi)(x, y, ptr, trlen, BITBLTBUF, TRXPOS, TRXREG); - } - - end = clock(); - - _ftprintf(file, _T("%6d %6d | "), (int)((float)trlen * n / (end - start) / 1000), (int)((float)(w * h) * n / (end - start) / 1000)); - - start = clock(); - - for(int j = 0; j < n; j++) - { - int x = 0; - int y = 0; - - (mem.*ri)(x, y, ptr, trlen, BITBLTBUF, TRXPOS, TRXREG); - } - - end = clock(); - - _ftprintf(file, _T("%6d %6d | "), (int)((float)trlen * n / (end - start) / 1000), (int)((float)(w * h) * n / (end - start) / 1000)); - - start = clock(); - - for(int j = 0; j < n; j++) - { - (mem.*rtx)(r, ptr, w * 4, TEX0, TEXA); - } - - end = clock(); - - _ftprintf(file, _T("%6d %6d "), (int)((float)len * n / (end - start) / 1000), (int)((float)(w * h) * n / (end - start) / 1000)); - - if(psm.pal > 0) - { - start = clock(); - - for(int j = 0; j < n; j++) - { - (mem.*rtxP)(r, ptr, w, TEX0, TEXA); - } - - end = clock(); - - _ftprintf(file, _T("| %6d %6d "), (int)((float)len * n / (end - start) / 1000), (int)((float)(w * h) * n / (end - start) / 1000)); - } - - _ftprintf(file, _T("\n")); - - fflush(file); - } - - _ftprintf(file, _T("\n")); - } - - _aligned_free(ptr); - } - - // - - if(0) - { - GSLocalMemory mem; - - BYTE* ptr = (BYTE*)_aligned_malloc(1024 * 1024 * 4, 16); - - for(int i = 0; i < 1024 * 1024 * 4; i++) ptr[i] = (BYTE)i; - - const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[PSM_PSMCT32]; - - GSLocalMemory::writeImage wi = psm.wi; - - GIFRegBITBLTBUF BITBLTBUF; - - BITBLTBUF.DBP = 0; - BITBLTBUF.DBW = 32; - BITBLTBUF.DPSM = PSM_PSMCT32; - - GIFRegTRXPOS TRXPOS; - - TRXPOS.DSAX = 0; - TRXPOS.DSAY = 1; - - GIFRegTRXREG TRXREG; - - TRXREG.RRW = 256; - TRXREG.RRH = 256; - - int trlen = 256 * 256 * psm.trbpp / 8; - - int x = 0; - int y = 0; - - (mem.*wi)(x, y, ptr, trlen, BITBLTBUF, TRXPOS, TRXREG); - } - - // - - fclose(file); -} - +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSUtil.h" +#include "GSRendererHW9.h" +#include "GSRendererHW10.h" +#include "GSRendererSW.h" +#include "GSRendererNull.h" +#include "GSSettingsDlg.h" + +#define PS2E_LT_GS 0x01 +#define PS2E_GS_VERSION 0x0006 +#define PS2E_X86 0x01 // 32 bit +#define PS2E_X86_64 0x02 // 64 bit + +static HRESULT s_hr = E_FAIL; +static GSRendererBase* s_gs = NULL; +static void (*s_irq)() = NULL; +static BYTE* s_basemem = NULL; + +EXPORT_C_(UINT32) PS2EgetLibType() +{ + return PS2E_LT_GS; +} + +EXPORT_C_(char*) PS2EgetLibName() +{ + return GSUtil::GetLibName(); +} + +EXPORT_C_(UINT32) PS2EgetLibVersion2(UINT32 type) +{ + const UINT32 revision = 0; + const UINT32 build = 1; + + return (build << 0) | (revision << 8) | (PS2E_GS_VERSION << 16) | (PLUGIN_VERSION << 24); +} + +EXPORT_C_(UINT32) PS2EgetCpuPlatform() +{ +#if _M_AMD64 + return PS2E_X86_64; +#else + return PS2E_X86; +#endif +} + +EXPORT_C GSsetBaseMem(BYTE* mem) +{ + s_basemem = mem - 0x12000000; +} + +EXPORT_C_(INT32) GSinit() +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + return 0; +} + +EXPORT_C GSshutdown() +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); +} + +EXPORT_C GSclose() +{ + delete s_gs; + + s_gs = NULL; + + if(SUCCEEDED(s_hr)) + { + ::CoUninitialize(); + + s_hr = E_FAIL; + } +} + +static INT32 GSopen(void* dsp, char* title, int mt, int renderer) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + if(!GSUtil::CheckDirectX() || !GSUtil::CheckSSE()) + { + return -1; + } + + GSclose(); + + // TODO + + int nloophack = AfxGetApp()->GetProfileInt(_T("Settings"), _T("nloophack"), 2); + + GSRendererSettings rs; + + rs.m_interlace = AfxGetApp()->GetProfileInt(_T("Settings"), _T("interlace"), 0); + rs.m_aspectratio = AfxGetApp()->GetProfileInt(_T("Settings"), _T("aspectratio"), 1); + rs.m_filter = AfxGetApp()->GetProfileInt(_T("Settings"), _T("filter"), 1); + rs.m_vsync = !!AfxGetApp()->GetProfileInt(_T("Settings"), _T("vsync"), FALSE); + rs.m_nativeres = !!AfxGetApp()->GetProfileInt(_T("Settings"), _T("nativeres"), FALSE); + + int threads = AfxGetApp()->GetProfileInt(_T("Settings"), _T("swthreads"), 1); + + switch(renderer) + { + default: + case 0: s_gs = new GSRendererHW9(s_basemem, !!mt, s_irq, nloophack, rs); break; + case 1: s_gs = new GSRendererSW(s_basemem, !!mt, s_irq, nloophack, rs, threads); break; + case 2: s_gs = new GSRendererNull(s_basemem, !!mt, s_irq, nloophack, rs); break; + case 3: s_gs = new GSRendererHW10(s_basemem, !!mt, s_irq, nloophack, rs); break; + case 4: s_gs = new GSRendererSW(s_basemem, !!mt, s_irq, nloophack, rs, threads); break; + case 5: s_gs = new GSRendererNull(s_basemem, !!mt, s_irq, nloophack, rs); break; + case 6: s_gs = new GSRendererSW(s_basemem, !!mt, s_irq, nloophack, rs, threads); break; + case 7: s_gs = new GSRendererNull(s_basemem, !!mt, s_irq, nloophack, rs); break; + } + + s_hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED); + + if(!s_gs->Create(CString(title))) + { + GSclose(); + + return -1; + } + + s_gs->m_wnd.Show(); + + *(HWND*)dsp = s_gs->m_wnd; + + // if(mt) _mm_setcsr(MXCSR); + + return 0; +} + +EXPORT_C_(INT32) GSopen(void* dsp, char* title, int mt) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + int renderer = AfxGetApp()->GetProfileInt(_T("Settings"), _T("renderer"), 0); + + return GSopen(dsp, title, mt, renderer); +} + +EXPORT_C GSreset() +{ + s_gs->Reset(); +} + +EXPORT_C GSgifSoftReset(int mask) +{ + s_gs->SoftReset((BYTE)mask); +} + +EXPORT_C GSwriteCSR(UINT32 csr) +{ + s_gs->WriteCSR(csr); +} + +EXPORT_C GSreadFIFO(BYTE* mem) +{ + s_gs->ReadFIFO(mem, 1); +} + +EXPORT_C GSreadFIFO2(BYTE* mem, UINT32 size) +{ + s_gs->ReadFIFO(mem, size); +} + +EXPORT_C GSgifTransfer1(BYTE* mem, UINT32 addr) +{ + s_gs->Transfer<0>(mem + addr, (0x4000 - addr) / 16); +} + +EXPORT_C GSgifTransfer2(BYTE* mem, UINT32 size) +{ + s_gs->Transfer<1>(mem, size); +} + +EXPORT_C GSgifTransfer3(BYTE* mem, UINT32 size) +{ + s_gs->Transfer<2>(mem, size); +} + +EXPORT_C GSvsync(int field) +{ + s_gs->VSync(field); +} + +EXPORT_C_(UINT32) GSmakeSnapshot(char* path) +{ + return s_gs->MakeSnapshot(CString(path) + _T("gsdx")); +} + +EXPORT_C GSkeyEvent(keyEvent* ev) +{ +} + +EXPORT_C_(INT32) GSfreeze(int mode, GSFreezeData* data) +{ + if(mode == FREEZE_SAVE) + { + return s_gs->Freeze(data, false); + } + else if(mode == FREEZE_SIZE) + { + return s_gs->Freeze(data, true); + } + else if(mode == FREEZE_LOAD) + { + return s_gs->Defrost(data); + } + + return 0; +} + +EXPORT_C GSconfigure() +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + GSSettingsDlg dlg; + + if(IDOK == dlg.DoModal()) + { + GSshutdown(); + GSinit(); + } +} + +EXPORT_C_(INT32) GStest() +{ + return 0; + + // TODO + + /* + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + CComPtr dev; + + return SUCCEEDED(D3D10CreateDevice(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, 0, D3D10_SDK_VERSION, &dev)) ? 0 : -1; + */ +} + +EXPORT_C GSabout() +{ +} + +EXPORT_C GSirqCallback(void (*irq)()) +{ + s_irq = irq; +} + +EXPORT_C GSsetGameCRC(DWORD crc, int options) +{ + s_gs->SetGameCRC(crc, options); +} + +EXPORT_C GSgetLastTag(UINT32* tag) +{ + s_gs->GetLastTag(tag); +} + +EXPORT_C GSsetFrameSkip(int frameskip) +{ + s_gs->SetFrameSkip(frameskip); +} + +EXPORT_C GSReplay(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) +{ + int renderer = -1; + + { + char* start = lpszCmdLine; + char* end = NULL; + long n = strtol(lpszCmdLine, &end, 10); + if(end > start) {renderer = n; lpszCmdLine = end;} + } + + while(*lpszCmdLine == ' ') lpszCmdLine++; + + ::SetPriorityClass(::GetCurrentProcess(), HIGH_PRIORITY_CLASS); + + CAtlArray buff; + + if(FILE* fp = fopen(lpszCmdLine, "rb")) + { + GSinit(); + + BYTE regs[0x2000]; + GSsetBaseMem(regs); + + HWND hWnd = NULL; + GSopen(&hWnd, _T(""), true, renderer); + + DWORD crc; + fread(&crc, 4, 1, fp); + GSsetGameCRC(crc, 0); + + GSFreezeData fd; + fread(&fd.size, 4, 1, fp); + fd.data = new BYTE[fd.size]; + fread(fd.data, fd.size, 1, fp); + GSfreeze(FREEZE_LOAD, &fd); + delete [] fd.data; + + fread(regs, 0x2000, 1, fp); + + long start = ftell(fp); + + unsigned int index, size, addr; + + GSvsync(1); + + while(1) + { + switch(fgetc(fp)) + { + case EOF: + fseek(fp, start, 0); + if(!IsWindowVisible(hWnd)) return; + break; + case 0: + index = fgetc(fp); + fread(&size, 4, 1, fp); + switch(index) + { + case 0: + if(buff.GetCount() < 0x4000) buff.SetCount(0x4000); + addr = 0x4000 - size; + fread(buff.GetData() + addr, size, 1, fp); + GSgifTransfer1(buff.GetData(), addr); + break; + case 1: + if(buff.GetCount() < size) buff.SetCount(size); + fread(buff.GetData(), size, 1, fp); + GSgifTransfer2(buff.GetData(), size / 16); + break; + case 2: + if(buff.GetCount() < size) buff.SetCount(size); + fread(buff.GetData(), size, 1, fp); + GSgifTransfer3(buff.GetData(), size / 16); + break; + } + break; + case 1: + GSvsync(fgetc(fp)); + if(!IsWindowVisible(hWnd)) return; + break; + case 2: + fread(&size, 4, 1, fp); + if(buff.GetCount() < size) buff.SetCount(size); + GSreadFIFO2(buff.GetData(), size / 16); + break; + case 3: + fread(regs, 0x2000, 1, fp); + break; + default: + return; + } + } + + GSclose(); + + GSshutdown(); + + fclose(fp); + } +} + +EXPORT_C GSBenchmark(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) +{ + ::SetPriorityClass(::GetCurrentProcess(), HIGH_PRIORITY_CLASS); + + FILE* file = _tfopen(_T("c:\\log.txt"), _T("a")); + + _ftprintf(file, _T("-------------------------\n\n")); + + if(1) + { + GSLocalMemory mem; + + static struct {int psm; LPCSTR name;} s_format[] = + { + {PSM_PSMCT32, "32"}, + {PSM_PSMCT24, "24"}, + {PSM_PSMCT16, "16"}, + {PSM_PSMCT16S, "16S"}, + {PSM_PSMT8, "8"}, + {PSM_PSMT4, "4"}, + {PSM_PSMT8H, "8H"}, + {PSM_PSMT4HL, "4HL"}, + {PSM_PSMT4HH, "4HH"}, + {PSM_PSMZ32, "32Z"}, + {PSM_PSMZ24, "24Z"}, + {PSM_PSMZ16, "16Z"}, + {PSM_PSMZ16S, "16ZS"}, + }; + + BYTE* ptr = (BYTE*)_aligned_malloc(1024 * 1024 * 4, 16); + + for(int i = 0; i < 1024 * 1024 * 4; i++) ptr[i] = (BYTE)i; + + // + + for(int tbw = 5; tbw <= 10; tbw++) + { + int n = 256 << ((10 - tbw) * 2); + + int w = 1 << tbw; + int h = 1 << tbw; + + _ftprintf(file, _T("%d x %d\n\n"), w, h); + + for(int i = 0; i < countof(s_format); i++) + { + const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[s_format[i].psm]; + + GSLocalMemory::writeImage wi = psm.wi; + GSLocalMemory::readImage ri = psm.ri; + GSLocalMemory::readTexture rtx = psm.rtx; + GSLocalMemory::readTexture rtxP = psm.rtxP; + + GIFRegBITBLTBUF BITBLTBUF; + + BITBLTBUF.SBP = 0; + BITBLTBUF.SBW = w / 64; + BITBLTBUF.SPSM = s_format[i].psm; + BITBLTBUF.DBP = 0; + BITBLTBUF.DBW = w / 64; + BITBLTBUF.DPSM = s_format[i].psm; + + GIFRegTRXPOS TRXPOS; + + TRXPOS.SSAX = 0; + TRXPOS.SSAY = 0; + TRXPOS.DSAX = 0; + TRXPOS.DSAY = 0; + + GIFRegTRXREG TRXREG; + + TRXREG.RRW = w; + TRXREG.RRH = h; + + CRect r(0, 0, w, h); + + GIFRegTEX0 TEX0; + + TEX0.TBP0 = 0; + TEX0.TBW = w / 64; + + GIFRegTEXA TEXA; + + TEXA.TA0 = 0; + TEXA.TA1 = 0x80; + TEXA.AEM = 0; + + int trlen = w * h * psm.trbpp / 8; + int len = w * h * psm.bpp / 8; + + clock_t start, end; + + _ftprintf(file, _T("[%4s] "), s_format[i].name); + + start = clock(); + + for(int j = 0; j < n; j++) + { + int x = 0; + int y = 0; + + (mem.*wi)(x, y, ptr, trlen, BITBLTBUF, TRXPOS, TRXREG); + } + + end = clock(); + + _ftprintf(file, _T("%6d %6d | "), (int)((float)trlen * n / (end - start) / 1000), (int)((float)(w * h) * n / (end - start) / 1000)); + + start = clock(); + + for(int j = 0; j < n; j++) + { + int x = 0; + int y = 0; + + (mem.*ri)(x, y, ptr, trlen, BITBLTBUF, TRXPOS, TRXREG); + } + + end = clock(); + + _ftprintf(file, _T("%6d %6d | "), (int)((float)trlen * n / (end - start) / 1000), (int)((float)(w * h) * n / (end - start) / 1000)); + + start = clock(); + + for(int j = 0; j < n; j++) + { + (mem.*rtx)(r, ptr, w * 4, TEX0, TEXA); + } + + end = clock(); + + _ftprintf(file, _T("%6d %6d "), (int)((float)len * n / (end - start) / 1000), (int)((float)(w * h) * n / (end - start) / 1000)); + + if(psm.pal > 0) + { + start = clock(); + + for(int j = 0; j < n; j++) + { + (mem.*rtxP)(r, ptr, w, TEX0, TEXA); + } + + end = clock(); + + _ftprintf(file, _T("| %6d %6d "), (int)((float)len * n / (end - start) / 1000), (int)((float)(w * h) * n / (end - start) / 1000)); + } + + _ftprintf(file, _T("\n")); + + fflush(file); + } + + _ftprintf(file, _T("\n")); + } + + _aligned_free(ptr); + } + + // + + if(0) + { + GSLocalMemory mem; + + BYTE* ptr = (BYTE*)_aligned_malloc(1024 * 1024 * 4, 16); + + for(int i = 0; i < 1024 * 1024 * 4; i++) ptr[i] = (BYTE)i; + + const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[PSM_PSMCT32]; + + GSLocalMemory::writeImage wi = psm.wi; + + GIFRegBITBLTBUF BITBLTBUF; + + BITBLTBUF.DBP = 0; + BITBLTBUF.DBW = 32; + BITBLTBUF.DPSM = PSM_PSMCT32; + + GIFRegTRXPOS TRXPOS; + + TRXPOS.DSAX = 0; + TRXPOS.DSAY = 1; + + GIFRegTRXREG TRXREG; + + TRXREG.RRW = 256; + TRXREG.RRH = 256; + + int trlen = 256 * 256 * psm.trbpp / 8; + + int x = 0; + int y = 0; + + (mem.*wi)(x, y, ptr, trlen, BITBLTBUF, TRXPOS, TRXREG); + } + + // + + fclose(file); +} + diff --git a/plugins/GSdx/GS.h b/plugins/GSdx/GS.h index 6623688670..51652646b2 100644 --- a/plugins/GSdx/GS.h +++ b/plugins/GSdx/GS.h @@ -1,1101 +1,1101 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - * Special Notes: - * - * Register definitions and most of the enums originate from sps2dev-0.4.0 - * Copyright (C) 2002 Terratron Technologies Inc. All Rights Reserved. - * - */ - -#pragma once - -#define PLUGIN_VERSION 14 - -#include "GSVector.h" - -#pragma pack(push, 1) - -// -// sps2registers.h -// - -enum GS_REG -{ - GS_PMODE = 0x12000000, - GS_SMODE1 = 0x12000010, - GS_SMODE2 = 0x12000020, - GS_SRFSH = 0x12000030, - GS_SYNCH1 = 0x12000040, - GS_SYNCH2 = 0x12000050, - GS_SYNCV = 0x12000060, - GS_DISPFB1 = 0x12000070, - GS_DISPLAY1 = 0x12000080, - GS_DISPFB2 = 0x12000090, - GS_DISPLAY2 = 0x120000a0, - GS_EXTBUF = 0x120000b0, - GS_EXTDATA = 0x120000c0, - GS_EXTWRITE = 0x120000d0, - GS_BGCOLOR = 0x120000e0, - GS_UNKNOWN = 0x12000400, - GS_CSR = 0x12001000, - GS_IMR = 0x12001010, - GS_BUSDIR = 0x12001040, - GS_SIGLBLID = 0x12001080 -}; - -enum GS_PRIM -{ - GS_POINTLIST = 0, - GS_LINELIST = 1, - GS_LINESTRIP = 2, - GS_TRIANGLELIST = 3, - GS_TRIANGLESTRIP = 4, - GS_TRIANGLEFAN = 5, - GS_SPRITE = 6, - GS_INVALID = 7, -}; - -enum GS_PRIM_CLASS -{ - GS_POINT_CLASS = 0, - GS_LINE_CLASS = 1, - GS_TRIANGLE_CLASS = 2, - GS_SPRITE_CLASS = 3, - GS_INVALID_CLASS = 7, -}; - -enum GIF_REG -{ - GIF_REG_PRIM = 0x00, - GIF_REG_RGBA = 0x01, - GIF_REG_STQ = 0x02, - GIF_REG_UV = 0x03, - GIF_REG_XYZF2 = 0x04, - GIF_REG_XYZ2 = 0x05, - GIF_REG_TEX0_1 = 0x06, - GIF_REG_TEX0_2 = 0x07, - GIF_REG_CLAMP_1 = 0x08, - GIF_REG_CLAMP_2 = 0x09, - GIF_REG_FOG = 0x0a, - GIF_REG_XYZF3 = 0x0c, - GIF_REG_XYZ3 = 0x0d, - GIF_REG_A_D = 0x0e, - GIF_REG_NOP = 0x0f, -}; - -enum GIF_A_D_REG -{ - GIF_A_D_REG_PRIM = 0x00, - GIF_A_D_REG_RGBAQ = 0x01, - GIF_A_D_REG_ST = 0x02, - GIF_A_D_REG_UV = 0x03, - GIF_A_D_REG_XYZF2 = 0x04, - GIF_A_D_REG_XYZ2 = 0x05, - GIF_A_D_REG_TEX0_1 = 0x06, - GIF_A_D_REG_TEX0_2 = 0x07, - GIF_A_D_REG_CLAMP_1 = 0x08, - GIF_A_D_REG_CLAMP_2 = 0x09, - GIF_A_D_REG_FOG = 0x0a, - GIF_A_D_REG_XYZF3 = 0x0c, - GIF_A_D_REG_XYZ3 = 0x0d, - GIF_A_D_REG_NOP = 0x0f, - GIF_A_D_REG_TEX1_1 = 0x14, - GIF_A_D_REG_TEX1_2 = 0x15, - GIF_A_D_REG_TEX2_1 = 0x16, - GIF_A_D_REG_TEX2_2 = 0x17, - GIF_A_D_REG_XYOFFSET_1 = 0x18, - GIF_A_D_REG_XYOFFSET_2 = 0x19, - GIF_A_D_REG_PRMODECONT = 0x1a, - GIF_A_D_REG_PRMODE = 0x1b, - GIF_A_D_REG_TEXCLUT = 0x1c, - GIF_A_D_REG_SCANMSK = 0x22, - GIF_A_D_REG_MIPTBP1_1 = 0x34, - GIF_A_D_REG_MIPTBP1_2 = 0x35, - GIF_A_D_REG_MIPTBP2_1 = 0x36, - GIF_A_D_REG_MIPTBP2_2 = 0x37, - GIF_A_D_REG_TEXA = 0x3b, - GIF_A_D_REG_FOGCOL = 0x3d, - GIF_A_D_REG_TEXFLUSH = 0x3f, - GIF_A_D_REG_SCISSOR_1 = 0x40, - GIF_A_D_REG_SCISSOR_2 = 0x41, - GIF_A_D_REG_ALPHA_1 = 0x42, - GIF_A_D_REG_ALPHA_2 = 0x43, - GIF_A_D_REG_DIMX = 0x44, - GIF_A_D_REG_DTHE = 0x45, - GIF_A_D_REG_COLCLAMP = 0x46, - GIF_A_D_REG_TEST_1 = 0x47, - GIF_A_D_REG_TEST_2 = 0x48, - GIF_A_D_REG_PABE = 0x49, - GIF_A_D_REG_FBA_1 = 0x4a, - GIF_A_D_REG_FBA_2 = 0x4b, - GIF_A_D_REG_FRAME_1 = 0x4c, - GIF_A_D_REG_FRAME_2 = 0x4d, - GIF_A_D_REG_ZBUF_1 = 0x4e, - GIF_A_D_REG_ZBUF_2 = 0x4f, - GIF_A_D_REG_BITBLTBUF = 0x50, - GIF_A_D_REG_TRXPOS = 0x51, - GIF_A_D_REG_TRXREG = 0x52, - GIF_A_D_REG_TRXDIR = 0x53, - GIF_A_D_REG_HWREG = 0x54, - GIF_A_D_REG_SIGNAL = 0x60, - GIF_A_D_REG_FINISH = 0x61, - GIF_A_D_REG_LABEL = 0x62, -}; - -enum GIF_FLG -{ - GIF_FLG_PACKED = 0, - GIF_FLG_REGLIST = 1, - GIF_FLG_IMAGE = 2, - GIF_FLG_IMAGE2 = 3 -}; - -enum GS_PSM -{ - PSM_PSMCT32 = 0, // 0000-0000 - PSM_PSMCT24 = 1, // 0000-0001 - PSM_PSMCT16 = 2, // 0000-0010 - PSM_PSMCT16S = 10, // 0000-1010 - PSM_PSMT8 = 19, // 0001-0011 - PSM_PSMT4 = 20, // 0001-0100 - PSM_PSMT8H = 27, // 0001-1011 - PSM_PSMT4HL = 36, // 0010-0100 - PSM_PSMT4HH = 44, // 0010-1100 - PSM_PSMZ32 = 48, // 0011-0000 - PSM_PSMZ24 = 49, // 0011-0001 - PSM_PSMZ16 = 50, // 0011-0010 - PSM_PSMZ16S = 58, // 0011-1010 -}; - -enum GS_TFX -{ - TFX_MODULATE = 0, - TFX_DECAL = 1, - TFX_HIGHLIGHT = 2, - TFX_HIGHLIGHT2 = 3, - TFX_NONE = 4, -}; - -enum GS_CLAMP -{ - CLAMP_REPEAT = 0, - CLAMP_CLAMP = 1, - CLAMP_REGION_CLAMP = 2, - CLAMP_REGION_REPEAT = 3, -}; - -enum GS_ZTST -{ - ZTST_NEVER = 0, - ZTST_ALWAYS = 1, - ZTST_GEQUAL = 2, - ZTST_GREATER = 3, -}; - -enum GS_ATST -{ - ATST_NEVER = 0, - ATST_ALWAYS = 1, - ATST_LESS = 2, - ATST_LEQUAL = 3, - ATST_EQUAL = 4, - ATST_GEQUAL = 5, - ATST_GREATER = 6, - ATST_NOTEQUAL = 7, -}; - -enum GS_AFAIL -{ - AFAIL_KEEP = 0, - AFAIL_FB_ONLY = 1, - AFAIL_ZB_ONLY = 2, - AFAIL_RGB_ONLY = 3, -}; - -// -// sps2regstructs.h -// - -#define REG32(name) \ -union name \ -{ \ - UINT32 ai32; \ - struct { \ - -#define REG64(name) \ -union name \ -{ \ - UINT64 i64; \ - UINT32 ai32[2]; \ - void operator = (const GSVector4i& v) {GSVector4i::storel(this, v);} \ - operator GSVector4i() const {return GSVector4i::loadl(this);} \ - struct { \ - -#define REG128(name)\ -union name \ -{ \ - UINT64 ai64[2]; \ - UINT32 ai32[4]; \ - struct { \ - -#define REG32_(prefix, name) REG32(prefix##name) -#define REG64_(prefix, name) REG64(prefix##name) -#define REG128_(prefix, name) REG128(prefix##name) - -#define REG_END }; }; -#define REG_END2 }; - -#define REG32_SET(name) \ -union name \ -{ \ - UINT32 ai32; \ - -#define REG64_SET(name) \ -union name \ -{ \ - UINT64 i64; \ - UINT32 ai32[2]; \ - -#define REG128_SET(name)\ -union name \ -{ \ - __m128i ai128; \ - UINT64 ai64[2]; \ - UINT32 ai32[4]; \ - -#define REG_SET_END }; - -REG64_(GSReg, BGCOLOR) - UINT32 R:8; - UINT32 G:8; - UINT32 B:8; - UINT32 _PAD1:8; - UINT32 _PAD2:32; -REG_END - -REG64_(GSReg, BUSDIR) - UINT32 DIR:1; - UINT32 _PAD1:31; - UINT32 _PAD2:32; -REG_END - -REG64_(GSReg, CSR) - UINT32 rSIGNAL:1; - UINT32 rFINISH:1; - UINT32 rHSINT:1; - UINT32 rVSINT:1; - UINT32 rEDWINT:1; - UINT32 rZERO1:1; - UINT32 rZERO2:1; - UINT32 r_PAD1:1; - UINT32 rFLUSH:1; - UINT32 rRESET:1; - UINT32 r_PAD2:2; - UINT32 rNFIELD:1; - UINT32 rFIELD:1; - UINT32 rFIFO:2; - UINT32 rREV:8; - UINT32 rID:8; - UINT32 wSIGNAL:1; - UINT32 wFINISH:1; - UINT32 wHSINT:1; - UINT32 wVSINT:1; - UINT32 wEDWINT:1; - UINT32 wZERO1:1; - UINT32 wZERO2:1; - UINT32 w_PAD1:1; - UINT32 wFLUSH:1; - UINT32 wRESET:1; - UINT32 w_PAD2:2; - UINT32 wNFIELD:1; - UINT32 wFIELD:1; - UINT32 wFIFO:2; - UINT32 wREV:8; - UINT32 wID:8; -REG_END - -REG64_(GSReg, DISPFB) // (-1/2) - UINT32 FBP:9; - UINT32 FBW:6; - UINT32 PSM:5; - UINT32 _PAD:12; - UINT32 DBX:11; - UINT32 DBY:11; - UINT32 _PAD2:10; -REG_END2 - UINT32 Block() {return FBP<<5;} -REG_END2 - -REG64_(GSReg, DISPLAY) // (-1/2) - UINT32 DX:12; - UINT32 DY:11; - UINT32 MAGH:4; - UINT32 MAGV:2; - UINT32 _PAD:3; - UINT32 DW:12; - UINT32 DH:11; - UINT32 _PAD2:9; -REG_END - -REG64_(GSReg, EXTBUF) - UINT32 EXBP:14; - UINT32 EXBW:6; - UINT32 FBIN:2; - UINT32 WFFMD:1; - UINT32 EMODA:2; - UINT32 EMODC:2; - UINT32 _PAD1:5; - UINT32 WDX:11; - UINT32 WDY:11; - UINT32 _PAD2:10; -REG_END - -REG64_(GSReg, EXTDATA) - UINT32 SX:12; - UINT32 SY:11; - UINT32 SMPH:4; - UINT32 SMPV:2; - UINT32 _PAD1:3; - UINT32 WW:12; - UINT32 WH:11; - UINT32 _PAD2:9; -REG_END - -REG64_(GSReg, EXTWRITE) - UINT32 WRITE:1; - UINT32 _PAD1:31; - UINT32 _PAD2:32; -REG_END - -REG64_(GSReg, IMR) - UINT32 _PAD1:8; - UINT32 SIGMSK:1; - UINT32 FINISHMSK:1; - UINT32 HSMSK:1; - UINT32 VSMSK:1; - UINT32 EDWMSK:1; - UINT32 _PAD2:19; - UINT32 _PAD3:32; -REG_END - -REG64_(GSReg, PMODE) - UINT32 EN1:1; - UINT32 EN2:1; - UINT32 CRTMD:3; - UINT32 MMOD:1; - UINT32 AMOD:1; - UINT32 SLBG:1; - UINT32 ALP:8; - UINT32 _PAD:16; - UINT32 _PAD1:32; -REG_END - -REG64_(GSReg, SIGLBLID) - UINT32 SIGID:32; - UINT32 LBLID:32; -REG_END - -REG64_(GSReg, SMODE1) - UINT32 RC:3; - UINT32 LC:7; - UINT32 T1248:2; - UINT32 SLCK:1; - UINT32 CMOD:2; - UINT32 EX:1; - UINT32 PRST:1; - UINT32 SINT:1; - UINT32 XPCK:1; - UINT32 PCK2:2; - UINT32 SPML:4; - UINT32 GCONT:1; // YCrCb - UINT32 PHS:1; - UINT32 PVS:1; - UINT32 PEHS:1; - UINT32 PEVS:1; - UINT32 CLKSEL:2; - UINT32 NVCK:1; - UINT32 SLCK2:1; - UINT32 VCKSEL:2; - UINT32 VHP:1; - UINT32 _PAD1:27; -REG_END - -/* - -// pal - -CLKSEL=1 CMOD=3 EX=0 GCONT=0 LC=32 NVCK=1 PCK2=0 PEHS=0 PEVS=0 PHS=0 PRST=1 PVS=0 RC=4 SINT=0 SLCK=0 SLCK2=1 SPML=4 T1248=1 VCKSEL=1 VHP=0 XPCK=0 - -// ntsc - -CLKSEL=1 CMOD=2 EX=0 GCONT=0 LC=32 NVCK=1 PCK2=0 PEHS=0 PEVS=0 PHS=0 PRST=1 PVS=0 RC=4 SINT=0 SLCK=0 SLCK2=1 SPML=4 T1248=1 VCKSEL=1 VHP=0 XPCK=0 - -// ntsc progressive (SoTC) - -CLKSEL=1 CMOD=0 EX=0 GCONT=0 LC=32 NVCK=1 PCK2=0 PEHS=0 PEVS=0 PHS=0 PRST=1 PVS=0 RC=4 SINT=0 SLCK=0 SLCK2=1 SPML=2 T1248=1 VCKSEL=1 VHP=1 XPCK=0 - -*/ - -REG64_(GSReg, SMODE2) - UINT32 INT:1; - UINT32 FFMD:1; - UINT32 DPMS:2; - UINT32 _PAD2:28; - UINT32 _PAD3:32; -REG_END - -REG64_SET(GSReg) - GSRegBGCOLOR BGCOLOR; - GSRegBUSDIR BUSDIR; - GSRegCSR CSR; - GSRegDISPFB DISPFB; - GSRegDISPLAY DISPLAY; - GSRegEXTBUF EXTBUF; - GSRegEXTDATA EXTDATA; - GSRegEXTWRITE EXTWRITE; - GSRegIMR IMR; - GSRegPMODE PMODE; - GSRegSIGLBLID SIGLBLID; - GSRegSMODE1 SMODE1; - GSRegSMODE2 SMODE2; -REG_SET_END - -// -// sps2tags.h -// - -#define SET_GIF_REG(gifTag, iRegNo, uiValue) \ - {((GIFTag*)&gifTag)->ai64[1] |= (((uiValue) & 0xf) << ((iRegNo) << 2));} - -#ifdef _M_AMD64 -#define GET_GIF_REG(tag, reg) \ - (((tag).ai64[1] >> ((reg) << 2)) & 0xf) -#else -#define GET_GIF_REG(tag, reg) \ - (((tag).ai32[2 + ((reg) >> 3)] >> (((reg) & 7) << 2)) & 0xf) -#endif - -// -// GIFTag - -REG128(GIFTag) - UINT32 NLOOP:15; - UINT32 EOP:1; - UINT32 _PAD1:16; - UINT32 _PAD2:14; - UINT32 PRE:1; - UINT32 PRIM:11; - UINT32 FLG:2; // enum GIF_FLG - UINT32 NREG:4; - UINT64 REGS:64; -REG_END - -// GIFReg - -REG64_(GIFReg, ALPHA) - UINT32 A:2; - UINT32 B:2; - UINT32 C:2; - UINT32 D:2; - UINT32 _PAD1:24; - UINT32 FIX:8; - UINT32 _PAD2:24; -REG_END2 - __forceinline bool IsOpaque() const {return (A == B || C == 2 && FIX == 0) && D == 0 || (A == 0 && B == 2 && C == 2 && D == 2 && FIX == 0x80);} // output will be Cs/As -REG_END2 - -REG64_(GIFReg, BITBLTBUF) - UINT32 SBP:14; - UINT32 _PAD1:2; - UINT32 SBW:6; - UINT32 _PAD2:2; - UINT32 SPSM:6; - UINT32 _PAD3:2; - UINT32 DBP:14; - UINT32 _PAD4:2; - UINT32 DBW:6; - UINT32 _PAD5:2; - UINT32 DPSM:6; - UINT32 _PAD6:2; -REG_END - -REG64_(GIFReg, CLAMP) -union -{ - struct - { - UINT32 WMS:2; - UINT32 WMT:2; - UINT32 MINU:10; - UINT32 MAXU:10; - UINT32 _PAD1:8; - UINT32 _PAD2:2; - UINT32 MAXV:10; - UINT32 _PAD3:20; - }; - - struct - { - UINT64 _PAD4:24; - UINT64 MINV:10; - UINT64 _PAD5:30; - }; -}; -REG_END - -REG64_(GIFReg, COLCLAMP) - UINT32 CLAMP:1; - UINT32 _PAD1:31; - UINT32 _PAD2:32; -REG_END - -REG64_(GIFReg, DIMX) - UINT32 DM00:3; - UINT32 _PAD00:1; - UINT32 DM01:3; - UINT32 _PAD01:1; - UINT32 DM02:3; - UINT32 _PAD02:1; - UINT32 DM03:3; - UINT32 _PAD03:1; - - UINT32 DM10:3; - UINT32 _PAD10:1; - UINT32 DM11:3; - UINT32 _PAD11:1; - UINT32 DM12:3; - UINT32 _PAD12:1; - UINT32 DM13:3; - UINT32 _PAD13:1; - - UINT32 DM20:3; - UINT32 _PAD20:1; - UINT32 DM21:3; - UINT32 _PAD21:1; - UINT32 DM22:3; - UINT32 _PAD22:1; - UINT32 DM23:3; - UINT32 _PAD23:1; - - UINT32 DM30:3; - UINT32 _PAD30:1; - UINT32 DM31:3; - UINT32 _PAD31:1; - UINT32 DM32:3; - UINT32 _PAD32:1; - UINT32 DM33:3; - UINT32 _PAD33:1; -REG_END - -REG64_(GIFReg, DTHE) - UINT32 DTHE:1; - UINT32 _PAD1:31; - UINT32 _PAD2:32; -REG_END - -REG64_(GIFReg, FBA) - UINT32 FBA:1; - UINT32 _PAD1:31; - UINT32 _PAD2:32; -REG_END - -REG64_(GIFReg, FINISH) - UINT32 _PAD1:32; - UINT32 _PAD2:32; -REG_END - -REG64_(GIFReg, FOG) - UINT32 _PAD1:32; - UINT32 _PAD2:24; - UINT32 F:8; -REG_END - -REG64_(GIFReg, FOGCOL) - UINT32 FCR:8; - UINT32 FCG:8; - UINT32 FCB:8; - UINT32 _PAD1:8; - UINT32 _PAD2:32; -REG_END - -REG64_(GIFReg, FRAME) - UINT32 FBP:9; - UINT32 _PAD1:7; - UINT32 FBW:6; - UINT32 _PAD2:2; - UINT32 PSM:6; - UINT32 _PAD3:2; - UINT32 FBMSK:32; -REG_END2 - UINT32 Block() const {return FBP << 5;} -REG_END2 - -REG64_(GIFReg, HWREG) - UINT32 DATA_LOWER:32; - UINT32 DATA_UPPER:32; -REG_END - -REG64_(GIFReg, LABEL) - UINT32 ID:32; - UINT32 IDMSK:32; -REG_END - -REG64_(GIFReg, MIPTBP1) - UINT64 TBP1:14; - UINT64 TBW1:6; - UINT64 TBP2:14; - UINT64 TBW2:6; - UINT64 TBP3:14; - UINT64 TBW3:6; - UINT64 _PAD:4; -REG_END - -REG64_(GIFReg, MIPTBP2) - UINT64 TBP4:14; - UINT64 TBW4:6; - UINT64 TBP5:14; - UINT64 TBW5:6; - UINT64 TBP6:14; - UINT64 TBW6:6; - UINT64 _PAD:4; -REG_END - -REG64_(GIFReg, NOP) - UINT32 _PAD1:32; - UINT32 _PAD2:32; -REG_END - -REG64_(GIFReg, PABE) - UINT32 PABE:1; - UINT32 _PAD1:31; - UINT32 _PAD2:32; -REG_END - -REG64_(GIFReg, PRIM) - UINT32 PRIM:3; - UINT32 IIP:1; - UINT32 TME:1; - UINT32 FGE:1; - UINT32 ABE:1; - UINT32 AA1:1; - UINT32 FST:1; - UINT32 CTXT:1; - UINT32 FIX:1; - UINT32 _PAD1:21; - UINT32 _PAD2:32; -REG_END - -REG64_(GIFReg, PRMODE) - UINT32 _PRIM:3; - UINT32 IIP:1; - UINT32 TME:1; - UINT32 FGE:1; - UINT32 ABE:1; - UINT32 AA1:1; - UINT32 FST:1; - UINT32 CTXT:1; - UINT32 FIX:1; - UINT32 _PAD2:21; - UINT32 _PAD3:32; -REG_END - -REG64_(GIFReg, PRMODECONT) - UINT32 AC:1; - UINT32 _PAD1:31; - UINT32 _PAD2:32; -REG_END - -REG64_(GIFReg, RGBAQ) - UINT32 R:8; - UINT32 G:8; - UINT32 B:8; - UINT32 A:8; - float Q; -REG_END - -REG64_(GIFReg, SCANMSK) - UINT32 MSK:2; - UINT32 _PAD1:30; - UINT32 _PAD2:32; -REG_END - -REG64_(GIFReg, SCISSOR) - UINT32 SCAX0:11; - UINT32 _PAD1:5; - UINT32 SCAX1:11; - UINT32 _PAD2:5; - UINT32 SCAY0:11; - UINT32 _PAD3:5; - UINT32 SCAY1:11; - UINT32 _PAD4:5; -REG_END - -REG64_(GIFReg, SIGNAL) - UINT32 ID:32; - UINT32 IDMSK:32; -REG_END - -REG64_(GIFReg, ST) - float S; - float T; -REG_END - -REG64_(GIFReg, TEST) - UINT32 ATE:1; - UINT32 ATST:3; - UINT32 AREF:8; - UINT32 AFAIL:2; - UINT32 DATE:1; - UINT32 DATM:1; - UINT32 ZTE:1; - UINT32 ZTST:2; - UINT32 _PAD1:13; - UINT32 _PAD2:32; -REG_END2 - __forceinline bool DoFirstPass() {return !ATE || ATST != 0;} // not all pixels fail automatically - __forceinline bool DoSecondPass() {return ATE && ATST != 1 && AFAIL != 0;} // pixels may fail, write fb/z - __forceinline bool NoSecondPass() {return ATE && ATST != 1 && AFAIL == 0;} // pixels may fail, no output -REG_END2 - -REG64_(GIFReg, TEX0) -union -{ - struct - { - UINT32 TBP0:14; - UINT32 TBW:6; - UINT32 PSM:6; - UINT32 TW:4; - UINT32 _PAD1:2; - UINT32 _PAD2:2; - UINT32 TCC:1; - UINT32 TFX:2; - UINT32 CBP:14; - UINT32 CPSM:4; - UINT32 CSM:1; - UINT32 CSA:5; - UINT32 CLD:3; - }; - - struct - { - UINT64 _PAD3:30; - UINT64 TH:4; - UINT64 _PAD4:30; - }; -}; -REG_END - -REG64_(GIFReg, TEX1) - UINT32 LCM:1; - UINT32 _PAD1:1; - UINT32 MXL:3; - UINT32 MMAG:1; - UINT32 MMIN:3; - UINT32 MTBA:1; - UINT32 _PAD2:9; - UINT32 L:2; - UINT32 _PAD3:11; - UINT32 K:12; - UINT32 _PAD4:20; -REG_END2 - bool IsLinear() const - { - bool mmag = (MMAG & 1); - bool mmin = (MMIN == 1) || (MMIN & 4); - - return !LCM ? mmag || mmin : K <= 0 ? mmag : mmin; - } -REG_END2 - -REG64_(GIFReg, TEX2) - UINT32 _PAD1:20; - UINT32 PSM:6; - UINT32 _PAD2:6; - UINT32 _PAD3:5; - UINT32 CBP:14; - UINT32 CPSM:4; - UINT32 CSM:1; - UINT32 CSA:5; - UINT32 CLD:3; -REG_END - -REG64_(GIFReg, TEXA) - UINT32 TA0:8; - UINT32 _PAD1:7; - UINT32 AEM:1; - UINT32 _PAD2:16; - UINT32 TA1:8; - UINT32 _PAD3:24; -REG_END - -REG64_(GIFReg, TEXCLUT) - UINT32 CBW:6; - UINT32 COU:6; - UINT32 COV:10; - UINT32 _PAD1:10; - UINT32 _PAD2:32; -REG_END - -REG64_(GIFReg, TEXFLUSH) - UINT32 _PAD1:32; - UINT32 _PAD2:32; -REG_END - -REG64_(GIFReg, TRXDIR) - UINT32 XDIR:2; - UINT32 _PAD1:30; - UINT32 _PAD2:32; -REG_END - -REG64_(GIFReg, TRXPOS) - UINT32 SSAX:11; - UINT32 _PAD1:5; - UINT32 SSAY:11; - UINT32 _PAD2:5; - UINT32 DSAX:11; - UINT32 _PAD3:5; - UINT32 DSAY:11; - UINT32 DIR:2; - UINT32 _PAD4:3; -REG_END - -REG64_(GIFReg, TRXREG) - UINT32 RRW:12; - UINT32 _PAD1:20; - UINT32 RRH:12; - UINT32 _PAD2:20; -REG_END - -// GSState::GIFPackedRegHandlerUV and GSState::GIFRegHandlerUV will make sure that the _PAD1/2 bits are set to zero - -REG64_(GIFReg, UV) - UINT32 U:16; -// UINT32 _PAD1:2; - UINT32 V:16; -// UINT32 _PAD2:2; - UINT32 _PAD3:32; -REG_END - -// GSState::GIFRegHandlerXYOFFSET will make sure that the _PAD1/2 bits are set to zero - -REG64_(GIFReg, XYOFFSET) - UINT32 OFX; // :16; UINT32 _PAD1:16; - UINT32 OFY; // :16; UINT32 _PAD2:16; -REG_END - -REG64_(GIFReg, XYZ) - UINT32 X:16; - UINT32 Y:16; - UINT32 Z:32; -REG_END - -REG64_(GIFReg, XYZF) - UINT32 X:16; - UINT32 Y:16; - UINT32 Z:24; - UINT32 F:8; -REG_END - -REG64_(GIFReg, ZBUF) - UINT32 ZBP:9; - UINT32 _PAD1:15; - // UINT32 PSM:4; - // UINT32 _PAD2:4; - UINT32 PSM:6; - UINT32 _PAD2:2; - UINT32 ZMSK:1; - UINT32 _PAD3:31; -REG_END2 - UINT32 Block() const {return ZBP << 5;} -REG_END2 - -REG64_SET(GIFReg) - GIFRegALPHA ALPHA; - GIFRegBITBLTBUF BITBLTBUF; - GIFRegCLAMP CLAMP; - GIFRegCOLCLAMP COLCLAMP; - GIFRegDIMX DIMX; - GIFRegDTHE DTHE; - GIFRegFBA FBA; - GIFRegFINISH FINISH; - GIFRegFOG FOG; - GIFRegFOGCOL FOGCOL; - GIFRegFRAME FRAME; - GIFRegHWREG HWREG; - GIFRegLABEL LABEL; - GIFRegMIPTBP1 MIPTBP1; - GIFRegMIPTBP2 MIPTBP2; - GIFRegNOP NOP; - GIFRegPABE PABE; - GIFRegPRIM PRIM; - GIFRegPRMODE PRMODE; - GIFRegPRMODECONT PRMODECONT; - GIFRegRGBAQ RGBAQ; - GIFRegSCANMSK SCANMSK; - GIFRegSCISSOR SCISSOR; - GIFRegSIGNAL SIGNAL; - GIFRegST ST; - GIFRegTEST TEST; - GIFRegTEX0 TEX0; - GIFRegTEX1 TEX1; - GIFRegTEX2 TEX2; - GIFRegTEXA TEXA; - GIFRegTEXCLUT TEXCLUT; - GIFRegTEXFLUSH TEXFLUSH; - GIFRegTRXDIR TRXDIR; - GIFRegTRXPOS TRXPOS; - GIFRegTRXREG TRXREG; - GIFRegUV UV; - GIFRegXYOFFSET XYOFFSET; - GIFRegXYZ XYZ; - GIFRegXYZF XYZF; - GIFRegZBUF ZBUF; -REG_SET_END - -// GIFPacked - -REG128_(GIFPacked, PRIM) - UINT32 PRIM:11; - UINT32 _PAD1:21; - UINT32 _PAD2:32; - UINT32 _PAD3:32; - UINT32 _PAD4:32; -REG_END - -REG128_(GIFPacked, RGBA) - UINT32 R:8; - UINT32 _PAD1:24; - UINT32 G:8; - UINT32 _PAD2:24; - UINT32 B:8; - UINT32 _PAD3:24; - UINT32 A:8; - UINT32 _PAD4:24; -REG_END - -REG128_(GIFPacked, STQ) - float S; - float T; - float Q; - UINT32 _PAD1:32; -REG_END - -REG128_(GIFPacked, UV) - UINT32 U:14; - UINT32 _PAD1:18; - UINT32 V:14; - UINT32 _PAD2:18; - UINT32 _PAD3:32; - UINT32 _PAD4:32; -REG_END - -REG128_(GIFPacked, XYZF2) - UINT32 X:16; - UINT32 _PAD1:16; - UINT32 Y:16; - UINT32 _PAD2:16; - UINT32 _PAD3:4; - UINT32 Z:24; - UINT32 _PAD4:4; - UINT32 _PAD5:4; - UINT32 F:8; - UINT32 _PAD6:3; - UINT32 ADC:1; - UINT32 _PAD7:16; -REG_END - -REG128_(GIFPacked, XYZ2) - UINT32 X:16; - UINT32 _PAD1:16; - UINT32 Y:16; - UINT32 _PAD2:16; - UINT32 Z:32; - UINT32 _PAD3:15; - UINT32 ADC:1; - UINT32 _PAD4:16; -REG_END - -REG128_(GIFPacked, FOG) - UINT32 _PAD1:32; - UINT32 _PAD2:32; - UINT32 _PAD3:32; - UINT32 _PAD4:4; - UINT32 F:8; - UINT32 _PAD5:20; -REG_END - -REG128_(GIFPacked, A_D) - UINT64 DATA:64; - UINT32 ADDR:8; // enum GIF_A_D_REG - UINT32 _PAD1:24; - UINT32 _PAD2:32; -REG_END - -REG128_(GIFPacked, NOP) - UINT32 _PAD1:32; - UINT32 _PAD2:32; - UINT32 _PAD3:32; - UINT32 _PAD4:32; -REG_END - -REG128_SET(GIFPackedReg) - GIFReg r; - GIFPackedPRIM PRIM; - GIFPackedRGBA RGBA; - GIFPackedSTQ STQ; - GIFPackedUV UV; - GIFPackedXYZF2 XYZF2; - GIFPackedXYZ2 XYZ2; - GIFPackedFOG FOG; - GIFPackedA_D A_D; - GIFPackedNOP NOP; -REG_SET_END - -__declspec(align(16)) struct GIFPath -{ - GIFTag tag; - UINT32 nreg; - UINT32 _pad[3]; - GSVector4i regs; - - void SetTag(const void* mem) - { - GSVector4i v = GSVector4i::load(mem); - GSVector4i::store(&tag, v); - nreg = 0; - regs = v.uph8(v >> 4) & 0x0f0f0f0f; - } - - DWORD GetReg() - { - return regs.u8[nreg]; // (DWORD)GET_GIF_REG(tag, nreg); - } -}; - -#pragma pack(pop) - -enum {KEYPRESS=1, KEYRELEASE=2}; -struct keyEvent {UINT32 key, event;}; - -enum {FREEZE_LOAD=0, FREEZE_SAVE=1, FREEZE_SIZE=2}; -struct GSFreezeData {int size; BYTE* data;}; - -enum stateType {ST_WRITE, ST_TRANSFER, ST_VSYNC}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * Special Notes: + * + * Register definitions and most of the enums originate from sps2dev-0.4.0 + * Copyright (C) 2002 Terratron Technologies Inc. All Rights Reserved. + * + */ + +#pragma once + +#define PLUGIN_VERSION 14 + +#include "GSVector.h" + +#pragma pack(push, 1) + +// +// sps2registers.h +// + +enum GS_REG +{ + GS_PMODE = 0x12000000, + GS_SMODE1 = 0x12000010, + GS_SMODE2 = 0x12000020, + GS_SRFSH = 0x12000030, + GS_SYNCH1 = 0x12000040, + GS_SYNCH2 = 0x12000050, + GS_SYNCV = 0x12000060, + GS_DISPFB1 = 0x12000070, + GS_DISPLAY1 = 0x12000080, + GS_DISPFB2 = 0x12000090, + GS_DISPLAY2 = 0x120000a0, + GS_EXTBUF = 0x120000b0, + GS_EXTDATA = 0x120000c0, + GS_EXTWRITE = 0x120000d0, + GS_BGCOLOR = 0x120000e0, + GS_UNKNOWN = 0x12000400, + GS_CSR = 0x12001000, + GS_IMR = 0x12001010, + GS_BUSDIR = 0x12001040, + GS_SIGLBLID = 0x12001080 +}; + +enum GS_PRIM +{ + GS_POINTLIST = 0, + GS_LINELIST = 1, + GS_LINESTRIP = 2, + GS_TRIANGLELIST = 3, + GS_TRIANGLESTRIP = 4, + GS_TRIANGLEFAN = 5, + GS_SPRITE = 6, + GS_INVALID = 7, +}; + +enum GS_PRIM_CLASS +{ + GS_POINT_CLASS = 0, + GS_LINE_CLASS = 1, + GS_TRIANGLE_CLASS = 2, + GS_SPRITE_CLASS = 3, + GS_INVALID_CLASS = 7, +}; + +enum GIF_REG +{ + GIF_REG_PRIM = 0x00, + GIF_REG_RGBA = 0x01, + GIF_REG_STQ = 0x02, + GIF_REG_UV = 0x03, + GIF_REG_XYZF2 = 0x04, + GIF_REG_XYZ2 = 0x05, + GIF_REG_TEX0_1 = 0x06, + GIF_REG_TEX0_2 = 0x07, + GIF_REG_CLAMP_1 = 0x08, + GIF_REG_CLAMP_2 = 0x09, + GIF_REG_FOG = 0x0a, + GIF_REG_XYZF3 = 0x0c, + GIF_REG_XYZ3 = 0x0d, + GIF_REG_A_D = 0x0e, + GIF_REG_NOP = 0x0f, +}; + +enum GIF_A_D_REG +{ + GIF_A_D_REG_PRIM = 0x00, + GIF_A_D_REG_RGBAQ = 0x01, + GIF_A_D_REG_ST = 0x02, + GIF_A_D_REG_UV = 0x03, + GIF_A_D_REG_XYZF2 = 0x04, + GIF_A_D_REG_XYZ2 = 0x05, + GIF_A_D_REG_TEX0_1 = 0x06, + GIF_A_D_REG_TEX0_2 = 0x07, + GIF_A_D_REG_CLAMP_1 = 0x08, + GIF_A_D_REG_CLAMP_2 = 0x09, + GIF_A_D_REG_FOG = 0x0a, + GIF_A_D_REG_XYZF3 = 0x0c, + GIF_A_D_REG_XYZ3 = 0x0d, + GIF_A_D_REG_NOP = 0x0f, + GIF_A_D_REG_TEX1_1 = 0x14, + GIF_A_D_REG_TEX1_2 = 0x15, + GIF_A_D_REG_TEX2_1 = 0x16, + GIF_A_D_REG_TEX2_2 = 0x17, + GIF_A_D_REG_XYOFFSET_1 = 0x18, + GIF_A_D_REG_XYOFFSET_2 = 0x19, + GIF_A_D_REG_PRMODECONT = 0x1a, + GIF_A_D_REG_PRMODE = 0x1b, + GIF_A_D_REG_TEXCLUT = 0x1c, + GIF_A_D_REG_SCANMSK = 0x22, + GIF_A_D_REG_MIPTBP1_1 = 0x34, + GIF_A_D_REG_MIPTBP1_2 = 0x35, + GIF_A_D_REG_MIPTBP2_1 = 0x36, + GIF_A_D_REG_MIPTBP2_2 = 0x37, + GIF_A_D_REG_TEXA = 0x3b, + GIF_A_D_REG_FOGCOL = 0x3d, + GIF_A_D_REG_TEXFLUSH = 0x3f, + GIF_A_D_REG_SCISSOR_1 = 0x40, + GIF_A_D_REG_SCISSOR_2 = 0x41, + GIF_A_D_REG_ALPHA_1 = 0x42, + GIF_A_D_REG_ALPHA_2 = 0x43, + GIF_A_D_REG_DIMX = 0x44, + GIF_A_D_REG_DTHE = 0x45, + GIF_A_D_REG_COLCLAMP = 0x46, + GIF_A_D_REG_TEST_1 = 0x47, + GIF_A_D_REG_TEST_2 = 0x48, + GIF_A_D_REG_PABE = 0x49, + GIF_A_D_REG_FBA_1 = 0x4a, + GIF_A_D_REG_FBA_2 = 0x4b, + GIF_A_D_REG_FRAME_1 = 0x4c, + GIF_A_D_REG_FRAME_2 = 0x4d, + GIF_A_D_REG_ZBUF_1 = 0x4e, + GIF_A_D_REG_ZBUF_2 = 0x4f, + GIF_A_D_REG_BITBLTBUF = 0x50, + GIF_A_D_REG_TRXPOS = 0x51, + GIF_A_D_REG_TRXREG = 0x52, + GIF_A_D_REG_TRXDIR = 0x53, + GIF_A_D_REG_HWREG = 0x54, + GIF_A_D_REG_SIGNAL = 0x60, + GIF_A_D_REG_FINISH = 0x61, + GIF_A_D_REG_LABEL = 0x62, +}; + +enum GIF_FLG +{ + GIF_FLG_PACKED = 0, + GIF_FLG_REGLIST = 1, + GIF_FLG_IMAGE = 2, + GIF_FLG_IMAGE2 = 3 +}; + +enum GS_PSM +{ + PSM_PSMCT32 = 0, // 0000-0000 + PSM_PSMCT24 = 1, // 0000-0001 + PSM_PSMCT16 = 2, // 0000-0010 + PSM_PSMCT16S = 10, // 0000-1010 + PSM_PSMT8 = 19, // 0001-0011 + PSM_PSMT4 = 20, // 0001-0100 + PSM_PSMT8H = 27, // 0001-1011 + PSM_PSMT4HL = 36, // 0010-0100 + PSM_PSMT4HH = 44, // 0010-1100 + PSM_PSMZ32 = 48, // 0011-0000 + PSM_PSMZ24 = 49, // 0011-0001 + PSM_PSMZ16 = 50, // 0011-0010 + PSM_PSMZ16S = 58, // 0011-1010 +}; + +enum GS_TFX +{ + TFX_MODULATE = 0, + TFX_DECAL = 1, + TFX_HIGHLIGHT = 2, + TFX_HIGHLIGHT2 = 3, + TFX_NONE = 4, +}; + +enum GS_CLAMP +{ + CLAMP_REPEAT = 0, + CLAMP_CLAMP = 1, + CLAMP_REGION_CLAMP = 2, + CLAMP_REGION_REPEAT = 3, +}; + +enum GS_ZTST +{ + ZTST_NEVER = 0, + ZTST_ALWAYS = 1, + ZTST_GEQUAL = 2, + ZTST_GREATER = 3, +}; + +enum GS_ATST +{ + ATST_NEVER = 0, + ATST_ALWAYS = 1, + ATST_LESS = 2, + ATST_LEQUAL = 3, + ATST_EQUAL = 4, + ATST_GEQUAL = 5, + ATST_GREATER = 6, + ATST_NOTEQUAL = 7, +}; + +enum GS_AFAIL +{ + AFAIL_KEEP = 0, + AFAIL_FB_ONLY = 1, + AFAIL_ZB_ONLY = 2, + AFAIL_RGB_ONLY = 3, +}; + +// +// sps2regstructs.h +// + +#define REG32(name) \ +union name \ +{ \ + UINT32 ai32; \ + struct { \ + +#define REG64(name) \ +union name \ +{ \ + UINT64 i64; \ + UINT32 ai32[2]; \ + void operator = (const GSVector4i& v) {GSVector4i::storel(this, v);} \ + operator GSVector4i() const {return GSVector4i::loadl(this);} \ + struct { \ + +#define REG128(name)\ +union name \ +{ \ + UINT64 ai64[2]; \ + UINT32 ai32[4]; \ + struct { \ + +#define REG32_(prefix, name) REG32(prefix##name) +#define REG64_(prefix, name) REG64(prefix##name) +#define REG128_(prefix, name) REG128(prefix##name) + +#define REG_END }; }; +#define REG_END2 }; + +#define REG32_SET(name) \ +union name \ +{ \ + UINT32 ai32; \ + +#define REG64_SET(name) \ +union name \ +{ \ + UINT64 i64; \ + UINT32 ai32[2]; \ + +#define REG128_SET(name)\ +union name \ +{ \ + __m128i ai128; \ + UINT64 ai64[2]; \ + UINT32 ai32[4]; \ + +#define REG_SET_END }; + +REG64_(GSReg, BGCOLOR) + UINT32 R:8; + UINT32 G:8; + UINT32 B:8; + UINT32 _PAD1:8; + UINT32 _PAD2:32; +REG_END + +REG64_(GSReg, BUSDIR) + UINT32 DIR:1; + UINT32 _PAD1:31; + UINT32 _PAD2:32; +REG_END + +REG64_(GSReg, CSR) + UINT32 rSIGNAL:1; + UINT32 rFINISH:1; + UINT32 rHSINT:1; + UINT32 rVSINT:1; + UINT32 rEDWINT:1; + UINT32 rZERO1:1; + UINT32 rZERO2:1; + UINT32 r_PAD1:1; + UINT32 rFLUSH:1; + UINT32 rRESET:1; + UINT32 r_PAD2:2; + UINT32 rNFIELD:1; + UINT32 rFIELD:1; + UINT32 rFIFO:2; + UINT32 rREV:8; + UINT32 rID:8; + UINT32 wSIGNAL:1; + UINT32 wFINISH:1; + UINT32 wHSINT:1; + UINT32 wVSINT:1; + UINT32 wEDWINT:1; + UINT32 wZERO1:1; + UINT32 wZERO2:1; + UINT32 w_PAD1:1; + UINT32 wFLUSH:1; + UINT32 wRESET:1; + UINT32 w_PAD2:2; + UINT32 wNFIELD:1; + UINT32 wFIELD:1; + UINT32 wFIFO:2; + UINT32 wREV:8; + UINT32 wID:8; +REG_END + +REG64_(GSReg, DISPFB) // (-1/2) + UINT32 FBP:9; + UINT32 FBW:6; + UINT32 PSM:5; + UINT32 _PAD:12; + UINT32 DBX:11; + UINT32 DBY:11; + UINT32 _PAD2:10; +REG_END2 + UINT32 Block() {return FBP<<5;} +REG_END2 + +REG64_(GSReg, DISPLAY) // (-1/2) + UINT32 DX:12; + UINT32 DY:11; + UINT32 MAGH:4; + UINT32 MAGV:2; + UINT32 _PAD:3; + UINT32 DW:12; + UINT32 DH:11; + UINT32 _PAD2:9; +REG_END + +REG64_(GSReg, EXTBUF) + UINT32 EXBP:14; + UINT32 EXBW:6; + UINT32 FBIN:2; + UINT32 WFFMD:1; + UINT32 EMODA:2; + UINT32 EMODC:2; + UINT32 _PAD1:5; + UINT32 WDX:11; + UINT32 WDY:11; + UINT32 _PAD2:10; +REG_END + +REG64_(GSReg, EXTDATA) + UINT32 SX:12; + UINT32 SY:11; + UINT32 SMPH:4; + UINT32 SMPV:2; + UINT32 _PAD1:3; + UINT32 WW:12; + UINT32 WH:11; + UINT32 _PAD2:9; +REG_END + +REG64_(GSReg, EXTWRITE) + UINT32 WRITE:1; + UINT32 _PAD1:31; + UINT32 _PAD2:32; +REG_END + +REG64_(GSReg, IMR) + UINT32 _PAD1:8; + UINT32 SIGMSK:1; + UINT32 FINISHMSK:1; + UINT32 HSMSK:1; + UINT32 VSMSK:1; + UINT32 EDWMSK:1; + UINT32 _PAD2:19; + UINT32 _PAD3:32; +REG_END + +REG64_(GSReg, PMODE) + UINT32 EN1:1; + UINT32 EN2:1; + UINT32 CRTMD:3; + UINT32 MMOD:1; + UINT32 AMOD:1; + UINT32 SLBG:1; + UINT32 ALP:8; + UINT32 _PAD:16; + UINT32 _PAD1:32; +REG_END + +REG64_(GSReg, SIGLBLID) + UINT32 SIGID:32; + UINT32 LBLID:32; +REG_END + +REG64_(GSReg, SMODE1) + UINT32 RC:3; + UINT32 LC:7; + UINT32 T1248:2; + UINT32 SLCK:1; + UINT32 CMOD:2; + UINT32 EX:1; + UINT32 PRST:1; + UINT32 SINT:1; + UINT32 XPCK:1; + UINT32 PCK2:2; + UINT32 SPML:4; + UINT32 GCONT:1; // YCrCb + UINT32 PHS:1; + UINT32 PVS:1; + UINT32 PEHS:1; + UINT32 PEVS:1; + UINT32 CLKSEL:2; + UINT32 NVCK:1; + UINT32 SLCK2:1; + UINT32 VCKSEL:2; + UINT32 VHP:1; + UINT32 _PAD1:27; +REG_END + +/* + +// pal + +CLKSEL=1 CMOD=3 EX=0 GCONT=0 LC=32 NVCK=1 PCK2=0 PEHS=0 PEVS=0 PHS=0 PRST=1 PVS=0 RC=4 SINT=0 SLCK=0 SLCK2=1 SPML=4 T1248=1 VCKSEL=1 VHP=0 XPCK=0 + +// ntsc + +CLKSEL=1 CMOD=2 EX=0 GCONT=0 LC=32 NVCK=1 PCK2=0 PEHS=0 PEVS=0 PHS=0 PRST=1 PVS=0 RC=4 SINT=0 SLCK=0 SLCK2=1 SPML=4 T1248=1 VCKSEL=1 VHP=0 XPCK=0 + +// ntsc progressive (SoTC) + +CLKSEL=1 CMOD=0 EX=0 GCONT=0 LC=32 NVCK=1 PCK2=0 PEHS=0 PEVS=0 PHS=0 PRST=1 PVS=0 RC=4 SINT=0 SLCK=0 SLCK2=1 SPML=2 T1248=1 VCKSEL=1 VHP=1 XPCK=0 + +*/ + +REG64_(GSReg, SMODE2) + UINT32 INT:1; + UINT32 FFMD:1; + UINT32 DPMS:2; + UINT32 _PAD2:28; + UINT32 _PAD3:32; +REG_END + +REG64_SET(GSReg) + GSRegBGCOLOR BGCOLOR; + GSRegBUSDIR BUSDIR; + GSRegCSR CSR; + GSRegDISPFB DISPFB; + GSRegDISPLAY DISPLAY; + GSRegEXTBUF EXTBUF; + GSRegEXTDATA EXTDATA; + GSRegEXTWRITE EXTWRITE; + GSRegIMR IMR; + GSRegPMODE PMODE; + GSRegSIGLBLID SIGLBLID; + GSRegSMODE1 SMODE1; + GSRegSMODE2 SMODE2; +REG_SET_END + +// +// sps2tags.h +// + +#define SET_GIF_REG(gifTag, iRegNo, uiValue) \ + {((GIFTag*)&gifTag)->ai64[1] |= (((uiValue) & 0xf) << ((iRegNo) << 2));} + +#ifdef _M_AMD64 +#define GET_GIF_REG(tag, reg) \ + (((tag).ai64[1] >> ((reg) << 2)) & 0xf) +#else +#define GET_GIF_REG(tag, reg) \ + (((tag).ai32[2 + ((reg) >> 3)] >> (((reg) & 7) << 2)) & 0xf) +#endif + +// +// GIFTag + +REG128(GIFTag) + UINT32 NLOOP:15; + UINT32 EOP:1; + UINT32 _PAD1:16; + UINT32 _PAD2:14; + UINT32 PRE:1; + UINT32 PRIM:11; + UINT32 FLG:2; // enum GIF_FLG + UINT32 NREG:4; + UINT64 REGS:64; +REG_END + +// GIFReg + +REG64_(GIFReg, ALPHA) + UINT32 A:2; + UINT32 B:2; + UINT32 C:2; + UINT32 D:2; + UINT32 _PAD1:24; + UINT32 FIX:8; + UINT32 _PAD2:24; +REG_END2 + __forceinline bool IsOpaque() const {return (A == B || C == 2 && FIX == 0) && D == 0 || (A == 0 && B == 2 && C == 2 && D == 2 && FIX == 0x80);} // output will be Cs/As +REG_END2 + +REG64_(GIFReg, BITBLTBUF) + UINT32 SBP:14; + UINT32 _PAD1:2; + UINT32 SBW:6; + UINT32 _PAD2:2; + UINT32 SPSM:6; + UINT32 _PAD3:2; + UINT32 DBP:14; + UINT32 _PAD4:2; + UINT32 DBW:6; + UINT32 _PAD5:2; + UINT32 DPSM:6; + UINT32 _PAD6:2; +REG_END + +REG64_(GIFReg, CLAMP) +union +{ + struct + { + UINT32 WMS:2; + UINT32 WMT:2; + UINT32 MINU:10; + UINT32 MAXU:10; + UINT32 _PAD1:8; + UINT32 _PAD2:2; + UINT32 MAXV:10; + UINT32 _PAD3:20; + }; + + struct + { + UINT64 _PAD4:24; + UINT64 MINV:10; + UINT64 _PAD5:30; + }; +}; +REG_END + +REG64_(GIFReg, COLCLAMP) + UINT32 CLAMP:1; + UINT32 _PAD1:31; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, DIMX) + UINT32 DM00:3; + UINT32 _PAD00:1; + UINT32 DM01:3; + UINT32 _PAD01:1; + UINT32 DM02:3; + UINT32 _PAD02:1; + UINT32 DM03:3; + UINT32 _PAD03:1; + + UINT32 DM10:3; + UINT32 _PAD10:1; + UINT32 DM11:3; + UINT32 _PAD11:1; + UINT32 DM12:3; + UINT32 _PAD12:1; + UINT32 DM13:3; + UINT32 _PAD13:1; + + UINT32 DM20:3; + UINT32 _PAD20:1; + UINT32 DM21:3; + UINT32 _PAD21:1; + UINT32 DM22:3; + UINT32 _PAD22:1; + UINT32 DM23:3; + UINT32 _PAD23:1; + + UINT32 DM30:3; + UINT32 _PAD30:1; + UINT32 DM31:3; + UINT32 _PAD31:1; + UINT32 DM32:3; + UINT32 _PAD32:1; + UINT32 DM33:3; + UINT32 _PAD33:1; +REG_END + +REG64_(GIFReg, DTHE) + UINT32 DTHE:1; + UINT32 _PAD1:31; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, FBA) + UINT32 FBA:1; + UINT32 _PAD1:31; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, FINISH) + UINT32 _PAD1:32; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, FOG) + UINT32 _PAD1:32; + UINT32 _PAD2:24; + UINT32 F:8; +REG_END + +REG64_(GIFReg, FOGCOL) + UINT32 FCR:8; + UINT32 FCG:8; + UINT32 FCB:8; + UINT32 _PAD1:8; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, FRAME) + UINT32 FBP:9; + UINT32 _PAD1:7; + UINT32 FBW:6; + UINT32 _PAD2:2; + UINT32 PSM:6; + UINT32 _PAD3:2; + UINT32 FBMSK:32; +REG_END2 + UINT32 Block() const {return FBP << 5;} +REG_END2 + +REG64_(GIFReg, HWREG) + UINT32 DATA_LOWER:32; + UINT32 DATA_UPPER:32; +REG_END + +REG64_(GIFReg, LABEL) + UINT32 ID:32; + UINT32 IDMSK:32; +REG_END + +REG64_(GIFReg, MIPTBP1) + UINT64 TBP1:14; + UINT64 TBW1:6; + UINT64 TBP2:14; + UINT64 TBW2:6; + UINT64 TBP3:14; + UINT64 TBW3:6; + UINT64 _PAD:4; +REG_END + +REG64_(GIFReg, MIPTBP2) + UINT64 TBP4:14; + UINT64 TBW4:6; + UINT64 TBP5:14; + UINT64 TBW5:6; + UINT64 TBP6:14; + UINT64 TBW6:6; + UINT64 _PAD:4; +REG_END + +REG64_(GIFReg, NOP) + UINT32 _PAD1:32; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, PABE) + UINT32 PABE:1; + UINT32 _PAD1:31; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, PRIM) + UINT32 PRIM:3; + UINT32 IIP:1; + UINT32 TME:1; + UINT32 FGE:1; + UINT32 ABE:1; + UINT32 AA1:1; + UINT32 FST:1; + UINT32 CTXT:1; + UINT32 FIX:1; + UINT32 _PAD1:21; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, PRMODE) + UINT32 _PRIM:3; + UINT32 IIP:1; + UINT32 TME:1; + UINT32 FGE:1; + UINT32 ABE:1; + UINT32 AA1:1; + UINT32 FST:1; + UINT32 CTXT:1; + UINT32 FIX:1; + UINT32 _PAD2:21; + UINT32 _PAD3:32; +REG_END + +REG64_(GIFReg, PRMODECONT) + UINT32 AC:1; + UINT32 _PAD1:31; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, RGBAQ) + UINT32 R:8; + UINT32 G:8; + UINT32 B:8; + UINT32 A:8; + float Q; +REG_END + +REG64_(GIFReg, SCANMSK) + UINT32 MSK:2; + UINT32 _PAD1:30; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, SCISSOR) + UINT32 SCAX0:11; + UINT32 _PAD1:5; + UINT32 SCAX1:11; + UINT32 _PAD2:5; + UINT32 SCAY0:11; + UINT32 _PAD3:5; + UINT32 SCAY1:11; + UINT32 _PAD4:5; +REG_END + +REG64_(GIFReg, SIGNAL) + UINT32 ID:32; + UINT32 IDMSK:32; +REG_END + +REG64_(GIFReg, ST) + float S; + float T; +REG_END + +REG64_(GIFReg, TEST) + UINT32 ATE:1; + UINT32 ATST:3; + UINT32 AREF:8; + UINT32 AFAIL:2; + UINT32 DATE:1; + UINT32 DATM:1; + UINT32 ZTE:1; + UINT32 ZTST:2; + UINT32 _PAD1:13; + UINT32 _PAD2:32; +REG_END2 + __forceinline bool DoFirstPass() {return !ATE || ATST != 0;} // not all pixels fail automatically + __forceinline bool DoSecondPass() {return ATE && ATST != 1 && AFAIL != 0;} // pixels may fail, write fb/z + __forceinline bool NoSecondPass() {return ATE && ATST != 1 && AFAIL == 0;} // pixels may fail, no output +REG_END2 + +REG64_(GIFReg, TEX0) +union +{ + struct + { + UINT32 TBP0:14; + UINT32 TBW:6; + UINT32 PSM:6; + UINT32 TW:4; + UINT32 _PAD1:2; + UINT32 _PAD2:2; + UINT32 TCC:1; + UINT32 TFX:2; + UINT32 CBP:14; + UINT32 CPSM:4; + UINT32 CSM:1; + UINT32 CSA:5; + UINT32 CLD:3; + }; + + struct + { + UINT64 _PAD3:30; + UINT64 TH:4; + UINT64 _PAD4:30; + }; +}; +REG_END + +REG64_(GIFReg, TEX1) + UINT32 LCM:1; + UINT32 _PAD1:1; + UINT32 MXL:3; + UINT32 MMAG:1; + UINT32 MMIN:3; + UINT32 MTBA:1; + UINT32 _PAD2:9; + UINT32 L:2; + UINT32 _PAD3:11; + UINT32 K:12; + UINT32 _PAD4:20; +REG_END2 + bool IsLinear() const + { + bool mmag = (MMAG & 1); + bool mmin = (MMIN == 1) || (MMIN & 4); + + return !LCM ? mmag || mmin : K <= 0 ? mmag : mmin; + } +REG_END2 + +REG64_(GIFReg, TEX2) + UINT32 _PAD1:20; + UINT32 PSM:6; + UINT32 _PAD2:6; + UINT32 _PAD3:5; + UINT32 CBP:14; + UINT32 CPSM:4; + UINT32 CSM:1; + UINT32 CSA:5; + UINT32 CLD:3; +REG_END + +REG64_(GIFReg, TEXA) + UINT32 TA0:8; + UINT32 _PAD1:7; + UINT32 AEM:1; + UINT32 _PAD2:16; + UINT32 TA1:8; + UINT32 _PAD3:24; +REG_END + +REG64_(GIFReg, TEXCLUT) + UINT32 CBW:6; + UINT32 COU:6; + UINT32 COV:10; + UINT32 _PAD1:10; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, TEXFLUSH) + UINT32 _PAD1:32; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, TRXDIR) + UINT32 XDIR:2; + UINT32 _PAD1:30; + UINT32 _PAD2:32; +REG_END + +REG64_(GIFReg, TRXPOS) + UINT32 SSAX:11; + UINT32 _PAD1:5; + UINT32 SSAY:11; + UINT32 _PAD2:5; + UINT32 DSAX:11; + UINT32 _PAD3:5; + UINT32 DSAY:11; + UINT32 DIR:2; + UINT32 _PAD4:3; +REG_END + +REG64_(GIFReg, TRXREG) + UINT32 RRW:12; + UINT32 _PAD1:20; + UINT32 RRH:12; + UINT32 _PAD2:20; +REG_END + +// GSState::GIFPackedRegHandlerUV and GSState::GIFRegHandlerUV will make sure that the _PAD1/2 bits are set to zero + +REG64_(GIFReg, UV) + UINT32 U:16; +// UINT32 _PAD1:2; + UINT32 V:16; +// UINT32 _PAD2:2; + UINT32 _PAD3:32; +REG_END + +// GSState::GIFRegHandlerXYOFFSET will make sure that the _PAD1/2 bits are set to zero + +REG64_(GIFReg, XYOFFSET) + UINT32 OFX; // :16; UINT32 _PAD1:16; + UINT32 OFY; // :16; UINT32 _PAD2:16; +REG_END + +REG64_(GIFReg, XYZ) + UINT32 X:16; + UINT32 Y:16; + UINT32 Z:32; +REG_END + +REG64_(GIFReg, XYZF) + UINT32 X:16; + UINT32 Y:16; + UINT32 Z:24; + UINT32 F:8; +REG_END + +REG64_(GIFReg, ZBUF) + UINT32 ZBP:9; + UINT32 _PAD1:15; + // UINT32 PSM:4; + // UINT32 _PAD2:4; + UINT32 PSM:6; + UINT32 _PAD2:2; + UINT32 ZMSK:1; + UINT32 _PAD3:31; +REG_END2 + UINT32 Block() const {return ZBP << 5;} +REG_END2 + +REG64_SET(GIFReg) + GIFRegALPHA ALPHA; + GIFRegBITBLTBUF BITBLTBUF; + GIFRegCLAMP CLAMP; + GIFRegCOLCLAMP COLCLAMP; + GIFRegDIMX DIMX; + GIFRegDTHE DTHE; + GIFRegFBA FBA; + GIFRegFINISH FINISH; + GIFRegFOG FOG; + GIFRegFOGCOL FOGCOL; + GIFRegFRAME FRAME; + GIFRegHWREG HWREG; + GIFRegLABEL LABEL; + GIFRegMIPTBP1 MIPTBP1; + GIFRegMIPTBP2 MIPTBP2; + GIFRegNOP NOP; + GIFRegPABE PABE; + GIFRegPRIM PRIM; + GIFRegPRMODE PRMODE; + GIFRegPRMODECONT PRMODECONT; + GIFRegRGBAQ RGBAQ; + GIFRegSCANMSK SCANMSK; + GIFRegSCISSOR SCISSOR; + GIFRegSIGNAL SIGNAL; + GIFRegST ST; + GIFRegTEST TEST; + GIFRegTEX0 TEX0; + GIFRegTEX1 TEX1; + GIFRegTEX2 TEX2; + GIFRegTEXA TEXA; + GIFRegTEXCLUT TEXCLUT; + GIFRegTEXFLUSH TEXFLUSH; + GIFRegTRXDIR TRXDIR; + GIFRegTRXPOS TRXPOS; + GIFRegTRXREG TRXREG; + GIFRegUV UV; + GIFRegXYOFFSET XYOFFSET; + GIFRegXYZ XYZ; + GIFRegXYZF XYZF; + GIFRegZBUF ZBUF; +REG_SET_END + +// GIFPacked + +REG128_(GIFPacked, PRIM) + UINT32 PRIM:11; + UINT32 _PAD1:21; + UINT32 _PAD2:32; + UINT32 _PAD3:32; + UINT32 _PAD4:32; +REG_END + +REG128_(GIFPacked, RGBA) + UINT32 R:8; + UINT32 _PAD1:24; + UINT32 G:8; + UINT32 _PAD2:24; + UINT32 B:8; + UINT32 _PAD3:24; + UINT32 A:8; + UINT32 _PAD4:24; +REG_END + +REG128_(GIFPacked, STQ) + float S; + float T; + float Q; + UINT32 _PAD1:32; +REG_END + +REG128_(GIFPacked, UV) + UINT32 U:14; + UINT32 _PAD1:18; + UINT32 V:14; + UINT32 _PAD2:18; + UINT32 _PAD3:32; + UINT32 _PAD4:32; +REG_END + +REG128_(GIFPacked, XYZF2) + UINT32 X:16; + UINT32 _PAD1:16; + UINT32 Y:16; + UINT32 _PAD2:16; + UINT32 _PAD3:4; + UINT32 Z:24; + UINT32 _PAD4:4; + UINT32 _PAD5:4; + UINT32 F:8; + UINT32 _PAD6:3; + UINT32 ADC:1; + UINT32 _PAD7:16; +REG_END + +REG128_(GIFPacked, XYZ2) + UINT32 X:16; + UINT32 _PAD1:16; + UINT32 Y:16; + UINT32 _PAD2:16; + UINT32 Z:32; + UINT32 _PAD3:15; + UINT32 ADC:1; + UINT32 _PAD4:16; +REG_END + +REG128_(GIFPacked, FOG) + UINT32 _PAD1:32; + UINT32 _PAD2:32; + UINT32 _PAD3:32; + UINT32 _PAD4:4; + UINT32 F:8; + UINT32 _PAD5:20; +REG_END + +REG128_(GIFPacked, A_D) + UINT64 DATA:64; + UINT32 ADDR:8; // enum GIF_A_D_REG + UINT32 _PAD1:24; + UINT32 _PAD2:32; +REG_END + +REG128_(GIFPacked, NOP) + UINT32 _PAD1:32; + UINT32 _PAD2:32; + UINT32 _PAD3:32; + UINT32 _PAD4:32; +REG_END + +REG128_SET(GIFPackedReg) + GIFReg r; + GIFPackedPRIM PRIM; + GIFPackedRGBA RGBA; + GIFPackedSTQ STQ; + GIFPackedUV UV; + GIFPackedXYZF2 XYZF2; + GIFPackedXYZ2 XYZ2; + GIFPackedFOG FOG; + GIFPackedA_D A_D; + GIFPackedNOP NOP; +REG_SET_END + +__declspec(align(16)) struct GIFPath +{ + GIFTag tag; + UINT32 nreg; + UINT32 _pad[3]; + GSVector4i regs; + + void SetTag(const void* mem) + { + GSVector4i v = GSVector4i::load(mem); + GSVector4i::store(&tag, v); + nreg = 0; + regs = v.uph8(v >> 4) & 0x0f0f0f0f; + } + + DWORD GetReg() + { + return regs.u8[nreg]; // (DWORD)GET_GIF_REG(tag, nreg); + } +}; + +#pragma pack(pop) + +enum {KEYPRESS=1, KEYRELEASE=2}; +struct keyEvent {UINT32 key, event;}; + +enum {FREEZE_LOAD=0, FREEZE_SAVE=1, FREEZE_SIZE=2}; +struct GSFreezeData {int size; BYTE* data;}; + +enum stateType {ST_WRITE, ST_TRANSFER, ST_VSYNC}; diff --git a/plugins/GSdx/GSAlignedClass.cpp b/plugins/GSdx/GSAlignedClass.cpp index e9cca21b8a..ac15a82f96 100644 --- a/plugins/GSdx/GSAlignedClass.cpp +++ b/plugins/GSdx/GSAlignedClass.cpp @@ -1,23 +1,23 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSAlignedClass.h" +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSAlignedClass.h" diff --git a/plugins/GSdx/GSAlignedClass.h b/plugins/GSdx/GSAlignedClass.h index 69ee8d1025..4f9136ebd1 100644 --- a/plugins/GSdx/GSAlignedClass.h +++ b/plugins/GSdx/GSAlignedClass.h @@ -1,48 +1,48 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -template class GSAlignedClass -{ -public: - GSAlignedClass() {} - - void* operator new (size_t size) - { - return _aligned_malloc(size, i); - } - - void operator delete (void* p) - { - _aligned_free(p); - } - - void* operator new [] (size_t size) - { - return _aligned_malloc(size, i); - } - - void operator delete [] (void* p) - { - _aligned_free(p); - } -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +template class GSAlignedClass +{ +public: + GSAlignedClass() {} + + void* operator new (size_t size) + { + return _aligned_malloc(size, i); + } + + void operator delete (void* p) + { + _aligned_free(p); + } + + void* operator new [] (size_t size) + { + return _aligned_malloc(size, i); + } + + void operator delete [] (void* p) + { + _aligned_free(p); + } +}; diff --git a/plugins/GSdx/GSBlock.cpp b/plugins/GSdx/GSBlock.cpp index 1a8554290f..86ef7c428d 100644 --- a/plugins/GSdx/GSBlock.cpp +++ b/plugins/GSdx/GSBlock.cpp @@ -1,37 +1,37 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSBlock.h" - -const GSVector4i GSBlock::m_r16mask(0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15); -const GSVector4i GSBlock::m_r8mask(0, 4, 2, 6, 8, 12, 10, 14, 1, 5, 3, 7, 9, 13, 11, 15); -const GSVector4i GSBlock::m_r4mask(0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15); - -const GSVector4i GSBlock::m_xxxa(0x00008000); -const GSVector4i GSBlock::m_xxbx(0x00007c00); -const GSVector4i GSBlock::m_xgxx(0x000003e0); -const GSVector4i GSBlock::m_rxxx(0x0000001f); - -const GSVector4i GSBlock::m_uw8hmask0 = GSVector4i(0, 0, 0, 0, 1, 1, 1, 1, 8, 8, 8, 8, 9, 9, 9, 9); -const GSVector4i GSBlock::m_uw8hmask1 = GSVector4i(2, 2, 2, 2, 3, 3, 3, 3, 10, 10, 10, 10, 11, 11, 11, 11); -const GSVector4i GSBlock::m_uw8hmask2 = GSVector4i(4, 4, 4, 4, 5, 5, 5, 5, 12, 12, 12, 12, 13, 13, 13, 13); -const GSVector4i GSBlock::m_uw8hmask3 = GSVector4i(6, 6, 6, 6, 7, 7, 7, 7, 14, 14, 14, 14, 15, 15, 15, 15); +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSBlock.h" + +const GSVector4i GSBlock::m_r16mask(0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15); +const GSVector4i GSBlock::m_r8mask(0, 4, 2, 6, 8, 12, 10, 14, 1, 5, 3, 7, 9, 13, 11, 15); +const GSVector4i GSBlock::m_r4mask(0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15); + +const GSVector4i GSBlock::m_xxxa(0x00008000); +const GSVector4i GSBlock::m_xxbx(0x00007c00); +const GSVector4i GSBlock::m_xgxx(0x000003e0); +const GSVector4i GSBlock::m_rxxx(0x0000001f); + +const GSVector4i GSBlock::m_uw8hmask0 = GSVector4i(0, 0, 0, 0, 1, 1, 1, 1, 8, 8, 8, 8, 9, 9, 9, 9); +const GSVector4i GSBlock::m_uw8hmask1 = GSVector4i(2, 2, 2, 2, 3, 3, 3, 3, 10, 10, 10, 10, 11, 11, 11, 11); +const GSVector4i GSBlock::m_uw8hmask2 = GSVector4i(4, 4, 4, 4, 5, 5, 5, 5, 12, 12, 12, 12, 13, 13, 13, 13); +const GSVector4i GSBlock::m_uw8hmask3 = GSVector4i(6, 6, 6, 6, 7, 7, 7, 7, 14, 14, 14, 14, 15, 15, 15, 15); diff --git a/plugins/GSdx/GSBlock.h b/plugins/GSdx/GSBlock.h index 6885b07f21..1ba4c4d667 100644 --- a/plugins/GSdx/GSBlock.h +++ b/plugins/GSdx/GSBlock.h @@ -1,2289 +1,2289 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GS.h" -#include "GSTables.h" -#include "GSVector.h" - -class GSBlock -{ - static const GSVector4i m_r16mask; - static const GSVector4i m_r8mask; - static const GSVector4i m_r4mask; - - static const GSVector4i m_xxxa; - static const GSVector4i m_xxbx; - static const GSVector4i m_xgxx; - static const GSVector4i m_rxxx; - - static const GSVector4i m_uw8hmask0; - static const GSVector4i m_uw8hmask1; - static const GSVector4i m_uw8hmask2; - static const GSVector4i m_uw8hmask3; - -public: - template __forceinline static void WriteColumn32(BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) - { - #if _M_SSE >= 0x200 - - const GSVector4i* s0 = (const GSVector4i*)&src[srcpitch * 0]; - const GSVector4i* s1 = (const GSVector4i*)&src[srcpitch * 1]; - - GSVector4i v0 = GSVector4i::load(&s0[0]); - GSVector4i v1 = GSVector4i::load(&s0[1]); - GSVector4i v2 = GSVector4i::load(&s1[0]); - GSVector4i v3 = GSVector4i::load(&s1[1]); - - GSVector4i::sw64(v0, v2, v1, v3); - - if(mask == 0xffffffff) - { - ((GSVector4i*)dst)[i * 4 + 0] = v0; - ((GSVector4i*)dst)[i * 4 + 1] = v1; - ((GSVector4i*)dst)[i * 4 + 2] = v2; - ((GSVector4i*)dst)[i * 4 + 3] = v3; - } - else - { - GSVector4i v4((int)mask); - - #if _M_SSE >= 0x401 - - if(mask == 0xff000000 || mask == 0x00ffffff) - { - ((GSVector4i*)dst)[i * 4 + 0] = ((GSVector4i*)dst)[i * 4 + 0].blend8(v0, v4); - ((GSVector4i*)dst)[i * 4 + 1] = ((GSVector4i*)dst)[i * 4 + 1].blend8(v1, v4); - ((GSVector4i*)dst)[i * 4 + 2] = ((GSVector4i*)dst)[i * 4 + 2].blend8(v2, v4); - ((GSVector4i*)dst)[i * 4 + 3] = ((GSVector4i*)dst)[i * 4 + 3].blend8(v3, v4); - } - else - { - - #endif - - ((GSVector4i*)dst)[i * 4 + 0] = ((GSVector4i*)dst)[i * 4 + 0].blend(v0, v4); - ((GSVector4i*)dst)[i * 4 + 1] = ((GSVector4i*)dst)[i * 4 + 1].blend(v1, v4); - ((GSVector4i*)dst)[i * 4 + 2] = ((GSVector4i*)dst)[i * 4 + 2].blend(v2, v4); - ((GSVector4i*)dst)[i * 4 + 3] = ((GSVector4i*)dst)[i * 4 + 3].blend(v3, v4); - - #if _M_SSE >= 0x401 - - } - - #endif - } - - #else - - const BYTE* d = &columnTable32[(i & 3) << 1][0]; - - for(int j = 0; j < 2; j++, d += 8, src += srcpitch) - { - for(int i = 0; i < 8; i++) - { - if(mask == 0xffffffff) - { - ((DWORD*)dst)[d[i]] = ((DWORD*)src)[i]; - } - else - { - ((DWORD*)dst)[d[i]] = (((DWORD*)dst)[d[i]] & ~mask) | (((DWORD*)src)[i] & mask); - } - } - } - - #endif - } - - template __forceinline static void WriteColumn16(BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) - { - #if _M_SSE >= 0x200 - - const GSVector4i* s0 = (const GSVector4i*)&src[srcpitch * 0]; - const GSVector4i* s1 = (const GSVector4i*)&src[srcpitch * 1]; - - GSVector4i v0 = GSVector4i::load(&s0[0]); - GSVector4i v1 = GSVector4i::load(&s0[1]); - GSVector4i v2 = GSVector4i::load(&s1[0]); - GSVector4i v3 = GSVector4i::load(&s1[1]); - - GSVector4i::sw16(v0, v1, v2, v3); - GSVector4i::sw64(v0, v1, v2, v3); - - ((GSVector4i*)dst)[i * 4 + 0] = v0; - ((GSVector4i*)dst)[i * 4 + 1] = v2; - ((GSVector4i*)dst)[i * 4 + 2] = v1; - ((GSVector4i*)dst)[i * 4 + 3] = v3; - - #else - - const BYTE* d = &columnTable16[(i & 3) << 1][0]; - - for(int j = 0; j < 2; j++, d += 16, src += srcpitch) - { - for(int i = 0; i < 16; i++) - { - ((WORD*)dst)[d[i]] = ((WORD*)src)[i]; - } - } - - #endif - } - - template __forceinline static void WriteColumn8(BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) - { - #if _M_SSE >= 0x200 - - GSVector4i v0 = GSVector4i::load(&src[srcpitch * 0]); - GSVector4i v1 = GSVector4i::load(&src[srcpitch * 1]); - GSVector4i v2 = GSVector4i::load(&src[srcpitch * 2]); - GSVector4i v3 = GSVector4i::load(&src[srcpitch * 3]); - - if((i & 1) == 0) - { - v2 = v2.yxwz(); - v3 = v3.yxwz(); - } - else - { - v0 = v0.yxwz(); - v1 = v1.yxwz(); - } - - GSVector4i::sw8(v0, v2, v1, v3); - GSVector4i::sw16(v0, v1, v2, v3); - GSVector4i::sw64(v0, v1, v2, v3); - - ((GSVector4i*)dst)[i * 4 + 0] = v0; - ((GSVector4i*)dst)[i * 4 + 1] = v2; - ((GSVector4i*)dst)[i * 4 + 2] = v1; - ((GSVector4i*)dst)[i * 4 + 3] = v3; - - #else - - const BYTE* d = &columnTable8[(i & 3) << 2][0]; - - for(int j = 0; j < 4; j++, d += 16, src += srcpitch) - { - for(int i = 0; i < 16; i++) - { - dst[d[i]] = src[i]; - } - } - - #endif - } - - template __forceinline static void WriteColumn4(BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) - { - // TODO: pshufb - - #if _M_SSE >= 0x200 - - GSVector4i v0 = GSVector4i::load(&src[srcpitch * 0]); - GSVector4i v1 = GSVector4i::load(&src[srcpitch * 1]); - GSVector4i v2 = GSVector4i::load(&src[srcpitch * 2]); - GSVector4i v3 = GSVector4i::load(&src[srcpitch * 3]); - - if((i & 1) == 0) - { - v2 = v2.yxwzlh(); - v3 = v3.yxwzlh(); - } - else - { - v0 = v0.yxwzlh(); - v1 = v1.yxwzlh(); - } - - GSVector4i::sw4(v0, v2, v1, v3); - GSVector4i::sw8(v0, v1, v2, v3); - GSVector4i::sw8(v0, v2, v1, v3); - GSVector4i::sw64(v0, v2, v1, v3); - - ((GSVector4i*)dst)[i * 4 + 0] = v0; - ((GSVector4i*)dst)[i * 4 + 1] = v1; - ((GSVector4i*)dst)[i * 4 + 2] = v2; - ((GSVector4i*)dst)[i * 4 + 3] = v3; - - #else - - const WORD* d = &columnTable4[(i & 3) << 2][0]; - - for(int j = 0; j < 4; j++, d += 32, src += srcpitch) - { - for(int i = 0; i < 32; i++) - { - DWORD addr = d[i]; - BYTE c = (src[i >> 1] >> ((i & 1) << 2)) & 0x0f; - DWORD shift = (addr & 1) << 2; - dst[addr >> 1] = (dst[addr >> 1] & (0xf0 >> shift)) | (c << shift); - } - } - - #endif - } - - template static void WriteColumn32(int y, BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) - { - switch((y >> 1) & 3) - { - case 0: WriteColumn32<0, aligned, mask>(dst, src, srcpitch); break; - case 1: WriteColumn32<1, aligned, mask>(dst, src, srcpitch); break; - case 2: WriteColumn32<2, aligned, mask>(dst, src, srcpitch); break; - case 3: WriteColumn32<3, aligned, mask>(dst, src, srcpitch); break; - default: __assume(0); - } - } - - template static void WriteColumn16(int y, BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) - { - switch((y >> 1) & 3) - { - case 0: WriteColumn16<0, aligned>(dst, src, srcpitch); break; - case 1: WriteColumn16<1, aligned>(dst, src, srcpitch); break; - case 2: WriteColumn16<2, aligned>(dst, src, srcpitch); break; - case 3: WriteColumn16<3, aligned>(dst, src, srcpitch); break; - default: __assume(0); - } - } - - template static void WriteColumn8(int y, BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) - { - switch((y >> 2) & 3) - { - case 0: WriteColumn8<0, aligned>(dst, src, srcpitch); break; - case 1: WriteColumn8<1, aligned>(dst, src, srcpitch); break; - case 2: WriteColumn8<2, aligned>(dst, src, srcpitch); break; - case 3: WriteColumn8<3, aligned>(dst, src, srcpitch); break; - default: __assume(0); - } - } - - template static void WriteColumn4(int y, BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) - { - switch((y >> 2) & 3) - { - case 0: WriteColumn4<0, aligned>(dst, src, srcpitch); break; - case 1: WriteColumn4<1, aligned>(dst, src, srcpitch); break; - case 2: WriteColumn4<2, aligned>(dst, src, srcpitch); break; - case 3: WriteColumn4<3, aligned>(dst, src, srcpitch); break; - default: __assume(0); - } - } - - template static void WriteBlock32(BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) - { - #if _M_SSE >= 0x200 - - WriteColumn32<0, aligned, mask>(dst, src, srcpitch); - src += srcpitch * 2; - WriteColumn32<1, aligned, mask>(dst, src, srcpitch); - src += srcpitch * 2; - WriteColumn32<2, aligned, mask>(dst, src, srcpitch); - src += srcpitch * 2; - WriteColumn32<3, aligned, mask>(dst, src, srcpitch); - - #else - - const BYTE* d = &columnTable32[0][0]; - - for(int j = 0; j < 8; j++, d += 8, src += srcpitch) - { - for(int i = 0; i < 8; i++) - { - if(mask == 0xffffffff) - { - ((DWORD*)dst)[d[i]] = ((DWORD*)src)[i]; - } - else - { - ((DWORD*)dst)[d[i]] = (((DWORD*)dst)[d[i]] & ~mask) | (((DWORD*)src)[i] & mask); - } - } - } - - #endif - } - - template static void WriteBlock16(BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) - { - #if _M_SSE >= 0x200 - - WriteColumn16<0, aligned>(dst, src, srcpitch); - src += srcpitch * 2; - WriteColumn16<1, aligned>(dst, src, srcpitch); - src += srcpitch * 2; - WriteColumn16<2, aligned>(dst, src, srcpitch); - src += srcpitch * 2; - WriteColumn16<3, aligned>(dst, src, srcpitch); - - #else - - const BYTE* d = &columnTable16[0][0]; - - for(int j = 0; j < 8; j++, d += 16, src += srcpitch) - { - for(int i = 0; i < 16; i++) - { - ((WORD*)dst)[d[i]] = ((WORD*)src)[i]; - } - } - - #endif - } - - template static void WriteBlock8(BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) - { - #if _M_SSE >= 0x200 - - WriteColumn8<0, aligned>(dst, src, srcpitch); - src += srcpitch * 4; - WriteColumn8<1, aligned>(dst, src, srcpitch); - src += srcpitch * 4; - WriteColumn8<2, aligned>(dst, src, srcpitch); - src += srcpitch * 4; - WriteColumn8<3, aligned>(dst, src, srcpitch); - - #else - - const BYTE* d = &columnTable8[0][0]; - - for(int j = 0; j < 16; j++, d += 16, src += srcpitch) - { - for(int i = 0; i < 16; i++) - { - dst[d[i]] = src[i]; - } - } - - #endif - } - - template static void WriteBlock4(BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) - { - #if _M_SSE >= 0x200 - - WriteColumn4<0, aligned>(dst, src, srcpitch); - src += srcpitch * 4; - WriteColumn4<1, aligned>(dst, src, srcpitch); - src += srcpitch * 4; - WriteColumn4<2, aligned>(dst, src, srcpitch); - src += srcpitch * 4; - WriteColumn4<3, aligned>(dst, src, srcpitch); - - #else - - const WORD* d = &columnTable4[0][0]; - - for(int j = 0; j < 16; j++, d += 32, src += srcpitch) - { - for(int i = 0; i < 32; i++) - { - DWORD addr = d[i]; - BYTE c = (src[i >> 1] >> ((i & 1) << 2)) & 0x0f; - DWORD shift = (addr & 1) << 2; - dst[addr >> 1] = (dst[addr >> 1] & (0xf0 >> shift)) | (c << shift); - } - } - - #endif - } - - template __forceinline static void ReadColumn32(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) - { - #if _M_SSE >= 0x200 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i v0 = s[i * 4 + 0]; - GSVector4i v1 = s[i * 4 + 1]; - GSVector4i v2 = s[i * 4 + 2]; - GSVector4i v3 = s[i * 4 + 3]; - - GSVector4i::sw64(v0, v1, v2, v3); - - GSVector4i* d0 = (GSVector4i*)&dst[dstpitch * 0]; - GSVector4i* d1 = (GSVector4i*)&dst[dstpitch * 1]; - - GSVector4i::store(&d0[0], v0); - GSVector4i::store(&d0[1], v1); - GSVector4i::store(&d1[0], v2); - GSVector4i::store(&d1[1], v3); - - #else - - const BYTE* s = &columnTable32[(i & 3) << 1][0]; - - for(int j = 0; j < 2; j++, s += 8, dst += dstpitch) - { - for(int i = 0; i < 8; i++) - { - ((DWORD*)dst)[i] = ((DWORD*)src)[s[i]]; - } - } - - #endif - } - - template __forceinline static void ReadColumn16(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) - { - #if _M_SSE >= 0x301 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i v0 = s[i * 4 + 0].shuffle8(m_r16mask); - GSVector4i v1 = s[i * 4 + 1].shuffle8(m_r16mask); - GSVector4i v2 = s[i * 4 + 2].shuffle8(m_r16mask); - GSVector4i v3 = s[i * 4 + 3].shuffle8(m_r16mask); - - GSVector4i::sw32(v0, v1, v2, v3); - GSVector4i::sw64(v0, v1, v2, v3); - - GSVector4i* d0 = (GSVector4i*)&dst[dstpitch * 0]; - GSVector4i* d1 = (GSVector4i*)&dst[dstpitch * 1]; - - GSVector4i::store(&d0[0], v0); - GSVector4i::store(&d0[1], v2); - GSVector4i::store(&d1[0], v1); - GSVector4i::store(&d1[1], v3); - - #elif _M_SSE >= 0x200 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i v0 = s[i * 4 + 0]; - GSVector4i v1 = s[i * 4 + 1]; - GSVector4i v2 = s[i * 4 + 2]; - GSVector4i v3 = s[i * 4 + 3]; - - GSVector4i::sw16(v0, v1, v2, v3); - GSVector4i::sw32(v0, v1, v2, v3); - GSVector4i::sw16(v0, v2, v1, v3); - - GSVector4i* d0 = (GSVector4i*)&dst[dstpitch * 0]; - GSVector4i* d1 = (GSVector4i*)&dst[dstpitch * 1]; - - GSVector4i::store(&d0[0], v0); - GSVector4i::store(&d0[1], v1); - GSVector4i::store(&d1[0], v2); - GSVector4i::store(&d1[1], v3); - - #else - - const BYTE* s = &columnTable16[(i & 3) << 1][0]; - - for(int j = 0; j < 2; j++, s += 16, dst += dstpitch) - { - for(int i = 0; i < 16; i++) - { - ((WORD*)dst)[i] = ((WORD*)src)[s[i]]; - } - } - - #endif - } - - template __forceinline static void ReadColumn8(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) - { - #if _M_SSE >= 0x301 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i v0, v1, v2, v3; - - if((i & 1) == 0) - { - v0 = s[i * 4 + 0]; - v1 = s[i * 4 + 1]; - v2 = s[i * 4 + 2]; - v3 = s[i * 4 + 3]; - } - else - { - v2 = s[i * 4 + 0]; - v3 = s[i * 4 + 1]; - v0 = s[i * 4 + 2]; - v1 = s[i * 4 + 3]; - } - - v0 = v0.shuffle8(m_r8mask); - v1 = v1.shuffle8(m_r8mask); - v2 = v2.shuffle8(m_r8mask); - v3 = v3.shuffle8(m_r8mask); - - GSVector4i::sw16(v0, v1, v2, v3); - GSVector4i::sw32(v0, v1, v3, v2); - - GSVector4i::store(&dst[dstpitch * 0], v0); - GSVector4i::store(&dst[dstpitch * 1], v3); - GSVector4i::store(&dst[dstpitch * 2], v1); - GSVector4i::store(&dst[dstpitch * 3], v2); - - #elif _M_SSE >= 0x200 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i v0 = s[i * 4 + 0]; - GSVector4i v1 = s[i * 4 + 1]; - GSVector4i v2 = s[i * 4 + 2]; - GSVector4i v3 = s[i * 4 + 3]; - - GSVector4i::sw8(v0, v1, v2, v3); - GSVector4i::sw16(v0, v1, v2, v3); - GSVector4i::sw8(v0, v2, v1, v3); - GSVector4i::sw64(v0, v1, v2, v3); - - if((i & 1) == 0) - { - v2 = v2.yxwz(); - v3 = v3.yxwz(); - } - else - { - v0 = v0.yxwz(); - v1 = v1.yxwz(); - } - - GSVector4i::store(&dst[dstpitch * 0], v0); - GSVector4i::store(&dst[dstpitch * 1], v1); - GSVector4i::store(&dst[dstpitch * 2], v2); - GSVector4i::store(&dst[dstpitch * 3], v3); - - #else - - const BYTE* s = &columnTable8[(i & 3) << 2][0]; - - for(int j = 0; j < 4; j++, s += 16, dst += dstpitch) - { - for(int i = 0; i < 16; i++) - { - dst[i] = src[s[i]]; - } - } - - #endif - } - - template __forceinline static void ReadColumn4(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) - { - #if _M_SSE >= 0x301 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i v0 = s[i * 4 + 0].xzyw(); - GSVector4i v1 = s[i * 4 + 1].xzyw(); - GSVector4i v2 = s[i * 4 + 2].xzyw(); - GSVector4i v3 = s[i * 4 + 3].xzyw(); - - GSVector4i::sw64(v0, v1, v2, v3); - GSVector4i::sw4(v0, v2, v1, v3); - GSVector4i::sw8(v0, v1, v2, v3); - - v0 = v0.shuffle8(m_r4mask); - v1 = v1.shuffle8(m_r4mask); - v2 = v2.shuffle8(m_r4mask); - v3 = v3.shuffle8(m_r4mask); - - if((i & 1) == 0) - { - GSVector4i::sw16rh(v0, v1, v2, v3); - } - else - { - GSVector4i::sw16rl(v0, v1, v2, v3); - } - - GSVector4i::store(&dst[dstpitch * 0], v0); - GSVector4i::store(&dst[dstpitch * 1], v1); - GSVector4i::store(&dst[dstpitch * 2], v2); - GSVector4i::store(&dst[dstpitch * 3], v3); - - #elif _M_SSE >= 0x200 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i v0 = s[i * 4 + 0]; - GSVector4i v1 = s[i * 4 + 1]; - GSVector4i v2 = s[i * 4 + 2]; - GSVector4i v3 = s[i * 4 + 3]; - - GSVector4i::sw32(v0, v1, v2, v3); - GSVector4i::sw32(v0, v1, v2, v3); - GSVector4i::sw4(v0, v2, v1, v3); - GSVector4i::sw8(v0, v1, v2, v3); - GSVector4i::sw16(v0, v2, v1, v3); - - v0 = v0.xzyw(); - v1 = v1.xzyw(); - v2 = v2.xzyw(); - v3 = v3.xzyw(); - - GSVector4i::sw64(v0, v1, v2, v3); - - if((i & 1) == 0) - { - v2 = v2.yxwzlh(); - v3 = v3.yxwzlh(); - } - else - { - v0 = v0.yxwzlh(); - v1 = v1.yxwzlh(); - } - - GSVector4i::store(&dst[dstpitch * 0], v0); - GSVector4i::store(&dst[dstpitch * 1], v1); - GSVector4i::store(&dst[dstpitch * 2], v2); - GSVector4i::store(&dst[dstpitch * 3], v3); - - #else - - const WORD* s = &columnTable4[(i & 3) << 2][0]; - - for(int j = 0; j < 4; j++, s += 32, dst += dstpitch) - { - for(int i = 0; i < 32; i++) - { - DWORD addr = s[i]; - BYTE c = (src[addr >> 1] >> ((addr & 1) << 2)) & 0x0f; - int shift = (i & 1) << 2; - dst[i >> 1] = (dst[i >> 1] & (0xf0 >> shift)) | (c << shift); - } - } - - #endif - } - - template static void ReadColumn32(int y, const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) - { - switch((y >> 1) & 3) - { - case 0: ReadColumn32<0, aligned>(src, dst, dstpitch); break; - case 1: ReadColumn32<1, aligned>(src, dst, dstpitch); break; - case 2: ReadColumn32<2, aligned>(src, dst, dstpitch); break; - case 3: ReadColumn32<3, aligned>(src, dst, dstpitch); break; - default: __assume(0); - } - } - - template static void ReadColumn16(int y, const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) - { - switch((y >> 1) & 3) - { - case 0: ReadColumn16<0, aligned>(src, dst, dstpitch); break; - case 1: ReadColumn16<1, aligned>(src, dst, dstpitch); break; - case 2: ReadColumn16<2, aligned>(src, dst, dstpitch); break; - case 3: ReadColumn16<3, aligned>(src, dst, dstpitch); break; - default: __assume(0); - } - } - - template static void ReadColumn8(int y, const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) - { - switch((y >> 2) & 3) - { - case 0: ReadColumn8<0, aligned>(src, dst, dstpitch); break; - case 1: ReadColumn8<1, aligned>(src, dst, dstpitch); break; - case 2: ReadColumn8<2, aligned>(src, dst, dstpitch); break; - case 3: ReadColumn8<3, aligned>(src, dst, dstpitch); break; - default: __assume(0); - } - } - - template static void ReadColumn4(int y, const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) - { - switch((y >> 2) & 3) - { - case 0: ReadColumn4<0, aligned>(src, dst, dstpitch); break; - case 1: ReadColumn4<1, aligned>(src, dst, dstpitch); break; - case 2: ReadColumn4<2, aligned>(src, dst, dstpitch); break; - case 3: ReadColumn4<3, aligned>(src, dst, dstpitch); break; - default: __assume(0); - } - } - - template static void ReadBlock32(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) - { - #if _M_SSE >= 0x200 - - ReadColumn32<0, aligned>(src, dst, dstpitch); - dst += dstpitch * 2; - ReadColumn32<1, aligned>(src, dst, dstpitch); - dst += dstpitch * 2; - ReadColumn32<2, aligned>(src, dst, dstpitch); - dst += dstpitch * 2; - ReadColumn32<3, aligned>(src, dst, dstpitch); - - #else - - const BYTE* s = &columnTable32[0][0]; - - for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) - { - for(int i = 0; i < 8; i++) - { - ((DWORD*)dst)[i] = ((DWORD*)src)[s[i]]; - } - } - - #endif - } - - template static void ReadBlock16(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) - { - #if _M_SSE >= 0x200 - - ReadColumn16<0, aligned>(src, dst, dstpitch); - dst += dstpitch * 2; - ReadColumn16<1, aligned>(src, dst, dstpitch); - dst += dstpitch * 2; - ReadColumn16<2, aligned>(src, dst, dstpitch); - dst += dstpitch * 2; - ReadColumn16<3, aligned>(src, dst, dstpitch); - - #else - - const BYTE* s = &columnTable16[0][0]; - - for(int j = 0; j < 8; j++, s += 16, dst += dstpitch) - { - for(int i = 0; i < 16; i++) - { - ((WORD*)dst)[i] = ((WORD*)src)[s[i]]; - } - } - - #endif - } - - template static void ReadBlock8(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) - { - #if _M_SSE >= 0x200 - - ReadColumn8<0, aligned>(src, dst, dstpitch); - dst += dstpitch * 4; - ReadColumn8<1, aligned>(src, dst, dstpitch); - dst += dstpitch * 4; - ReadColumn8<2, aligned>(src, dst, dstpitch); - dst += dstpitch * 4; - ReadColumn8<3, aligned>(src, dst, dstpitch); - - #else - - const BYTE* s = &columnTable8[0][0]; - - for(int j = 0; j < 16; j++, s += 16, dst += dstpitch) - { - for(int i = 0; i < 16; i++) - { - dst[i] = src[s[i]]; - } - } - - #endif - } - - template static void ReadBlock4(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) - { - #if _M_SSE >= 0x200 - - ReadColumn4<0, aligned>(src, dst, dstpitch); - dst += dstpitch * 4; - ReadColumn4<1, aligned>(src, dst, dstpitch); - dst += dstpitch * 4; - ReadColumn4<2, aligned>(src, dst, dstpitch); - dst += dstpitch * 4; - ReadColumn4<3, aligned>(src, dst, dstpitch); - - #else - - const WORD* s = &columnTable4[0][0]; - - for(int j = 0; j < 16; j++, s += 32, dst += dstpitch) - { - for(int i = 0; i < 32; i++) - { - DWORD addr = s[i]; - BYTE c = (src[addr >> 1] >> ((addr & 1) << 2)) & 0x0f; - int shift = (i & 1) << 2; - dst[i >> 1] = (dst[i >> 1] & (0xf0 >> shift)) | (c << shift); - } - } - - #endif - } - - __forceinline static void ReadBlock4P(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) - { - #if _M_SSE >= 0x200 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i v0, v1, v2, v3; - - GSVector4i mask(0x0f0f0f0f); - - for(int i = 0; i < 2; i++) - { - // col 0, 2 - - v0 = s[i * 8 + 0]; - v1 = s[i * 8 + 1]; - v2 = s[i * 8 + 2]; - v3 = s[i * 8 + 3]; - - GSVector4i::sw8(v0, v1, v2, v3); - GSVector4i::sw16(v0, v1, v2, v3); - GSVector4i::sw8(v0, v2, v1, v3); - - GSVector4i::store(&dst[dstpitch * 0 + 0], (v0 & mask)); - GSVector4i::store(&dst[dstpitch * 0 + 16], (v1 & mask)); - GSVector4i::store(&dst[dstpitch * 1 + 0], (v2 & mask)); - GSVector4i::store(&dst[dstpitch * 1 + 16], (v3 & mask)); - - dst += dstpitch * 2; - - GSVector4i::store(&dst[dstpitch * 0 + 0], (v0.andnot(mask)).yxwz() >> 4); - GSVector4i::store(&dst[dstpitch * 0 + 16], (v1.andnot(mask)).yxwz() >> 4); - GSVector4i::store(&dst[dstpitch * 1 + 0], (v2.andnot(mask)).yxwz() >> 4); - GSVector4i::store(&dst[dstpitch * 1 + 16], (v3.andnot(mask)).yxwz() >> 4); - - dst += dstpitch * 2; - - // col 1, 3 - - v0 = s[i * 8 + 4]; - v1 = s[i * 8 + 5]; - v2 = s[i * 8 + 6]; - v3 = s[i * 8 + 7]; - - GSVector4i::sw8(v0, v1, v2, v3); - GSVector4i::sw16(v0, v1, v2, v3); - GSVector4i::sw8(v0, v2, v1, v3); - - GSVector4i::store(&dst[dstpitch * 0 + 0], (v0 & mask).yxwz()); - GSVector4i::store(&dst[dstpitch * 0 + 16], (v1 & mask).yxwz()); - GSVector4i::store(&dst[dstpitch * 1 + 0], (v2 & mask).yxwz()); - GSVector4i::store(&dst[dstpitch * 1 + 16], (v3 & mask).yxwz()); - - dst += dstpitch * 2; - - GSVector4i::store(&dst[dstpitch * 0 + 0], (v0.andnot(mask)) >> 4); - GSVector4i::store(&dst[dstpitch * 0 + 16], (v1.andnot(mask)) >> 4); - GSVector4i::store(&dst[dstpitch * 1 + 0], (v2.andnot(mask)) >> 4); - GSVector4i::store(&dst[dstpitch * 1 + 16], (v3.andnot(mask)) >> 4); - - dst += dstpitch * 2; - } - - #else - - // TODO - - #endif - } - - __forceinline static void ReadBlock8HP(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) - { - #if _M_SSE >= 0x200 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i v0, v1, v2, v3; - - for(int i = 0; i < 4; i++) - { - v0 = s[i * 4 + 0]; - v1 = s[i * 4 + 1]; - v2 = s[i * 4 + 2]; - v3 = s[i * 4 + 3]; - - GSVector4i::sw64(v0, v1, v2, v3); - - v0 = ((v0 >> 24).ps32(v1 >> 24)).pu16((v2 >> 24).ps32(v3 >> 24)); - - GSVector4i::storel(dst, v0); - - dst += dstpitch; - - GSVector4i::storeh(dst, v0); - - dst += dstpitch; - } - - #else - - const BYTE* s = &columnTable32[0][0]; - - for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) - { - for(int i = 0; i < 8; i++) - { - ((BYTE*)dst)[i] = ((DWORD*)src)[s[i]] >> 24; - } - } - - #endif - } - - __forceinline static void ReadBlock4HLP(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) - { - #if _M_SSE >= 0x200 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i v0, v1, v2, v3; - - GSVector4i mask(0x0f0f0f0f); - - for(int i = 0; i < 4; i++) - { - v0 = s[i * 4 + 0]; - v1 = s[i * 4 + 1]; - v2 = s[i * 4 + 2]; - v3 = s[i * 4 + 3]; - - GSVector4i::sw64(v0, v1, v2, v3); - - v0 = ((v0 >> 24).ps32(v1 >> 24)).pu16((v2 >> 24).ps32(v3 >> 24)) & mask; - - GSVector4i::storel(dst, v0); - - dst += dstpitch; - - GSVector4i::storeh(dst, v0); - - dst += dstpitch; - } - - #else - - const BYTE* s = &columnTable32[0][0]; - - for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) - { - for(int i = 0; i < 8; i++) - { - ((BYTE*)dst)[i] = (((DWORD*)src)[s[i]] >> 24) & 0xf; - } - } - - #endif - } - - __forceinline static void ReadBlock4HHP(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) - { - #if _M_SSE >= 0x200 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i v0, v1, v2, v3; - - for(int i = 0; i < 4; i++) - { - v0 = s[i * 4 + 0]; - v1 = s[i * 4 + 1]; - v2 = s[i * 4 + 2]; - v3 = s[i * 4 + 3]; - - GSVector4i::sw64(v0, v1, v2, v3); - - v0 = ((v0 >> 28).ps32(v1 >> 28)).pu16((v2 >> 28).ps32(v3 >> 28)); - - GSVector4i::storel(dst, v0); - - dst += dstpitch; - - GSVector4i::storeh(dst, v0); - - dst += dstpitch; - } - - #else - - const BYTE* s = &columnTable32[0][0]; - - for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) - { - for(int i = 0; i < 8; i++) - { - ((BYTE*)dst)[i] = ((DWORD*)src)[s[i]] >> 28; - } - } - - #endif - } - - static void UnpackBlock24(const BYTE* RESTRICT src, int srcpitch, DWORD* RESTRICT dst) - { - #if _M_SSE >= 0x200 - - GSVector4i mask = GSVector4i::x00ffffff(); - - for(int i = 0; i < 4; i++, src += srcpitch * 2) - { - GSVector4i v0 = GSVector4i::load(src); - GSVector4i v1 = GSVector4i::load(src + 16, src + srcpitch); - GSVector4i v2 = GSVector4i::load(src + srcpitch + 8); - - ((GSVector4i*)dst)[i * 4 + 0] = v0.upl32(v0.srl<3>()).upl64(v0.srl<6>().upl32(v0.srl<9>())) & mask; - - v0 = v0.srl<12>(v1); - - ((GSVector4i*)dst)[i * 4 + 1] = v0.upl32(v0.srl<3>()).upl64(v0.srl<6>().upl32(v0.srl<9>())) & mask; - - v0 = v1.srl<8>(v2); - - ((GSVector4i*)dst)[i * 4 + 2] = v0.upl32(v0.srl<3>()).upl64(v0.srl<6>().upl32(v0.srl<9>())) & mask; - - v0 = v2.srl<4>(); - - ((GSVector4i*)dst)[i * 4 + 3] = v0.upl32(v0.srl<3>()).upl64(v0.srl<6>().upl32(v0.srl<9>())) & mask; - } - - #else - - for(int j = 0, diff = srcpitch - 8 * 3; j < 8; j++, src += diff, dst += 8) - { - for(int i = 0; i < 8; i++, src += 3) - { - dst[i] = (src[2] << 16) | (src[1] << 8) | src[0]; - } - } - - #endif - } - - static void UnpackBlock8H(const BYTE* RESTRICT src, int srcpitch, DWORD* RESTRICT dst) - { - #if _M_SSE >= 0x200 - - GSVector4i zero = GSVector4i::zero(); - - for(int i = 0; i < 4; i++, src += srcpitch * 2) - { - GSVector4i v = GSVector4i::load(src, src + srcpitch); - - GSVector4i v0 = zero.upl8(v); - GSVector4i v1 = zero.uph8(v); - - ((GSVector4i*)dst)[i * 4 + 0] = zero.upl16(v0); - ((GSVector4i*)dst)[i * 4 + 1] = zero.uph16(v0); - ((GSVector4i*)dst)[i * 4 + 2] = zero.upl16(v1); - ((GSVector4i*)dst)[i * 4 + 3] = zero.uph16(v1); - } - - #else - - for(int j = 0; j < 8; j++, src += srcpitch, dst += 8) - { - for(int i = 0; i < 8; i++) - { - dst[i] = src[i] << 24; - } - } - - #endif - } - - static void UnpackBlock4HL(const BYTE* RESTRICT src, int srcpitch, DWORD* RESTRICT dst) - { - #if _M_SSE >= 0x200 - - GSVector4i zero = GSVector4i::zero(); - GSVector4i mask(0x0f0f0f0f); - - for(int i = 0; i < 2; i++, src += srcpitch * 4) - { - GSVector4i v( - *(DWORD*)&src[srcpitch * 0], - *(DWORD*)&src[srcpitch * 1], - *(DWORD*)&src[srcpitch * 2], - *(DWORD*)&src[srcpitch * 3]); - - GSVector4i lo = v & mask; - GSVector4i hi = (v >> 4) & mask; - - GSVector4i v0 = lo.upl8(hi); - GSVector4i v1 = lo.uph8(hi); - - GSVector4i v2 = zero.upl8(v0); - GSVector4i v3 = zero.uph8(v0); - GSVector4i v4 = zero.upl8(v1); - GSVector4i v5 = zero.uph8(v1); - - ((GSVector4i*)dst)[i * 8 + 0] = zero.upl16(v2); - ((GSVector4i*)dst)[i * 8 + 1] = zero.uph16(v2); - ((GSVector4i*)dst)[i * 8 + 2] = zero.upl16(v3); - ((GSVector4i*)dst)[i * 8 + 3] = zero.uph16(v3); - ((GSVector4i*)dst)[i * 8 + 4] = zero.upl16(v4); - ((GSVector4i*)dst)[i * 8 + 5] = zero.uph16(v4); - ((GSVector4i*)dst)[i * 8 + 6] = zero.upl16(v5); - ((GSVector4i*)dst)[i * 8 + 7] = zero.uph16(v5); - } - - #else - - for(int j = 0; j < 8; j++, src += srcpitch, dst += 8) - { - for(int i = 0; i < 4; i++) - { - dst[i * 2 + 0] = (src[i] & 0x0f) << 24; - dst[i * 2 + 1] = (src[i] & 0xf0) << 20; - } - } - - #endif - } - - static void UnpackBlock4HH(const BYTE* RESTRICT src, int srcpitch, DWORD* RESTRICT dst) - { - #if _M_SSE >= 0x200 - - GSVector4i zero = GSVector4i::zero(); - GSVector4i mask(0xf0f0f0f0); - - for(int i = 0; i < 2; i++, src += srcpitch * 4) - { - GSVector4i v( - *(DWORD*)&src[srcpitch * 0], - *(DWORD*)&src[srcpitch * 1], - *(DWORD*)&src[srcpitch * 2], - *(DWORD*)&src[srcpitch * 3]); - - GSVector4i lo = (v << 4) & mask; - GSVector4i hi = v & mask; - - GSVector4i v0 = lo.upl8(hi); - GSVector4i v1 = lo.uph8(hi); - - GSVector4i v2 = zero.upl8(v0); - GSVector4i v3 = zero.uph8(v0); - GSVector4i v4 = zero.upl8(v1); - GSVector4i v5 = zero.uph8(v1); - - ((GSVector4i*)dst)[i * 8 + 0] = zero.upl16(v2); - ((GSVector4i*)dst)[i * 8 + 1] = zero.uph16(v2); - ((GSVector4i*)dst)[i * 8 + 2] = zero.upl16(v3); - ((GSVector4i*)dst)[i * 8 + 3] = zero.uph16(v3); - ((GSVector4i*)dst)[i * 8 + 4] = zero.upl16(v4); - ((GSVector4i*)dst)[i * 8 + 5] = zero.uph16(v4); - ((GSVector4i*)dst)[i * 8 + 6] = zero.upl16(v5); - ((GSVector4i*)dst)[i * 8 + 7] = zero.uph16(v5); - } - - #else - - for(int j = 0; j < 8; j++, src += srcpitch, dst += 8) - { - for(int i = 0; i < 4; i++) - { - dst[i * 2 + 0] = (src[i] & 0x0f) << 28; - dst[i * 2 + 1] = (src[i] & 0xf0) << 24; - } - } - - #endif - } - - template static void ExpandBlock24(const DWORD* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const GIFRegTEXA& TEXA) - { - #if _M_SSE >= 0x200 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i TA0(TEXA.TA0 << 24); - GSVector4i mask = GSVector4i::x00ffffff(); - - for(int i = 0; i < 4; i++, dst += dstpitch * 2) - { - GSVector4i v0 = s[i * 4 + 0] & mask; - GSVector4i v1 = s[i * 4 + 1] & mask; - GSVector4i v2 = s[i * 4 + 2] & mask; - GSVector4i v3 = s[i * 4 + 3] & mask; - - GSVector4i* d0 = (GSVector4i*)&dst[dstpitch * 0]; - GSVector4i* d1 = (GSVector4i*)&dst[dstpitch * 1]; - - if(AEM) - { - d0[0] = v0 | TA0.andnot(v0 == GSVector4i::zero()); // TA0 & (v0 != GSVector4i::zero()) - d0[1] = v1 | TA0.andnot(v1 == GSVector4i::zero()); // TA0 & (v1 != GSVector4i::zero()) - d1[0] = v2 | TA0.andnot(v2 == GSVector4i::zero()); // TA0 & (v2 != GSVector4i::zero()) - d1[1] = v3 | TA0.andnot(v3 == GSVector4i::zero()); // TA0 & (v3 != GSVector4i::zero()) - } - else - { - d0[0] = v0 | TA0; - d0[1] = v1 | TA0; - d1[0] = v2 | TA0; - d1[1] = v3 | TA0; - } - } - - #else - - DWORD TA0 = TEXA.TA0 << 24; - - for(int j = 0; j < 8; j++, src += 8, dst += dstpitch) - { - for(int i = 0; i < 8; i++) - { - DWORD c = src[i] & 0xffffff; - - if(AEM) - { - ((DWORD*)dst)[i] = c | (c ? TA0 : 0); - } - else - { - ((DWORD*)dst)[i] = c | TA0; - } - } - } - - #endif - } - - static void ExpandBlock16(const WORD* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const GIFRegTEXA& TEXA) // do not inline, uses too many xmm regs - { - #if _M_SSE >= 0x200 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i TA0(TEXA.TA0 << 24); - GSVector4i TA1(TEXA.TA1 << 24); - GSVector4i rm = m_rxxx; - GSVector4i gm = m_xgxx; - GSVector4i bm = m_xxbx; - // GSVector4i am = m_xxxa; - GSVector4i l, h; - - if(TEXA.AEM) - { - for(int i = 0; i < 8; i++, dst += dstpitch) - { - GSVector4i v0 = s[i * 2 + 0]; -/* - l = v0.upl16(); - h = v0.uph16(); - - ((GSVector4i*)dst)[0] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | TA1.blend(TA0, l < am).andnot(l == GSVector4i::zero()); - ((GSVector4i*)dst)[1] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | TA1.blend(TA0, h < am).andnot(h == GSVector4i::zero()); -*/ - l = v0.upl16(v0); - h = v0.uph16(v0); - - ((GSVector4i*)dst)[0] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | TA0.blend8(TA1, l.sra16(15)).andnot(l == GSVector4i::zero()); - ((GSVector4i*)dst)[1] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | TA0.blend8(TA1, h.sra16(15)).andnot(h == GSVector4i::zero()); - - GSVector4i v1 = s[i * 2 + 1]; -/* - l = v1.upl16(); - h = v1.uph16(); - - ((GSVector4i*)dst)[2] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | TA1.blend(TA0, l < am).andnot(l == GSVector4i::zero()); - ((GSVector4i*)dst)[3] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | TA1.blend(TA0, h < am).andnot(h == GSVector4i::zero()); -*/ - l = v1.upl16(v1); - h = v1.uph16(v1); - - ((GSVector4i*)dst)[2] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | TA0.blend8(TA1, l.sra16(15)).andnot(l == GSVector4i::zero()); - ((GSVector4i*)dst)[3] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | TA0.blend8(TA1, h.sra16(15)).andnot(h == GSVector4i::zero()); - } - } - else - { - for(int i = 0; i < 8; i++, dst += dstpitch) - { - GSVector4i v0 = s[i * 2 + 0]; -/* - l = v0.upl16(); - h = v0.uph16(); - - ((GSVector4i*)dst)[0] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | TA1.blend(TA0, l < am); - ((GSVector4i*)dst)[1] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | TA1.blend(TA0, h < am); -*/ - l = v0.upl16(v0); - h = v0.uph16(v0); - - ((GSVector4i*)dst)[0] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | TA0.blend(TA1, l.sra16(15)); - ((GSVector4i*)dst)[1] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | TA0.blend(TA1, h.sra16(15)); - - GSVector4i v1 = s[i * 2 + 1]; -/* - l = v1.upl16(); - h = v1.uph16(); - - ((GSVector4i*)dst)[2] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | TA1.blend(TA0, l < am); - ((GSVector4i*)dst)[3] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | TA1.blend(TA0, h < am); -*/ - l = v1.upl16(v1); - h = v1.uph16(v1); - - ((GSVector4i*)dst)[2] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | TA0.blend(TA1, l.sra16(15)); - ((GSVector4i*)dst)[3] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | TA0.blend(TA1, h.sra16(15)); - } - } - - #else - - DWORD TA0 = TEXA.TA0 << 24; - DWORD TA1 = TEXA.TA1 << 24; - - if(TEXA.AEM) - { - for(int j = 0; j < 8; j++, src += 16, dst += dstpitch) - { - for(int i = 0; i < 16; i++) - { - ((DWORD*)dst)[i] = ((src[i] & 0x8000) ? TA1 : src[i] ? TA0 : 0) | ((src[i] & 0x7c00) << 9) | ((src[i] & 0x03e0) << 6) | ((src[i] & 0x001f) << 3); - } - } - } - else - { - for(int j = 0; j < 8; j++, src += 16, dst += dstpitch) - { - for(int i = 0; i < 16; i++) - { - ((DWORD*)dst)[i] = ((src[i] & 0x8000) ? TA1 : TA0) | ((src[i] & 0x7c00) << 9) | ((src[i] & 0x03e0) << 6) | ((src[i] & 0x001f) << 3); - } - } - } - - #endif - } - - __forceinline static void ExpandBlock8_32(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) - { - for(int j = 0; j < 16; j++, dst += dstpitch) - { - ((const GSVector4i*)src)[j].gather32_8(pal, (GSVector4i*)dst); - } - } - - __forceinline static void ExpandBlock8_16(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) - { - for(int j = 0; j < 16; j++, dst += dstpitch) - { - ((const GSVector4i*)src)[j].gather16_8(pal, (GSVector4i*)dst); - } - } - - __forceinline static void ExpandBlock4_32(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const UINT64* RESTRICT pal) - { - for(int j = 0; j < 16; j++, dst += dstpitch) - { - ((const GSVector4i*)src)[j].gather64_8(pal, (GSVector4i*)dst); - } - } - - __forceinline static void ExpandBlock4_16(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const UINT64* RESTRICT pal) - { - for(int j = 0; j < 16; j++, dst += dstpitch) - { - ((const GSVector4i*)src)[j].gather32_8(pal, (GSVector4i*)dst); - } - } - - __forceinline static void ExpandBlock8H_32(DWORD* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) - { - for(int j = 0; j < 8; j++, dst += dstpitch) - { - const GSVector4i* s = (const GSVector4i*)src; - - ((GSVector4i*)dst)[0] = (s[j * 2 + 0] >> 24).gather32_32<>(pal); - ((GSVector4i*)dst)[1] = (s[j * 2 + 1] >> 24).gather32_32<>(pal); - } - } - - __forceinline static void ExpandBlock8H_16(DWORD* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) - { - for(int j = 0; j < 8; j++, dst += dstpitch) - { - #if _M_SSE >= 0x401 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i v0 = (s[j * 2 + 0] >> 24).gather32_32<>(pal); - GSVector4i v1 = (s[j * 2 + 1] >> 24).gather32_32<>(pal); - - ((GSVector4i*)dst)[0] = v0.pu32(v1); - - #else - - for(int i = 0; i < 8; i++) - { - ((WORD*)dst)[i] = (WORD)pal[src[j * 8 + i] >> 24]; - } - - #endif - } - } - - __forceinline static void ExpandBlock4HL_32(DWORD* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) - { - for(int j = 0; j < 8; j++, dst += dstpitch) - { - const GSVector4i* s = (const GSVector4i*)src; - - ((GSVector4i*)dst)[0] = ((s[j * 2 + 0] >> 24) & 0xf).gather32_32<>(pal); - ((GSVector4i*)dst)[1] = ((s[j * 2 + 1] >> 24) & 0xf).gather32_32<>(pal); - } - } - - __forceinline static void ExpandBlock4HL_16(DWORD* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) - { - for(int j = 0; j < 8; j++, dst += dstpitch) - { - #if _M_SSE >= 0x401 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i v0 = ((s[j * 2 + 0] >> 24) & 0xf).gather32_32<>(pal); - GSVector4i v1 = ((s[j * 2 + 1] >> 24) & 0xf).gather32_32<>(pal); - - ((GSVector4i*)dst)[0] = v0.pu32(v1); - - #else - - for(int i = 0; i < 8; i++) - { - ((WORD*)dst)[i] = (WORD)pal[(src[j * 8 + i] >> 24) & 0xf]; - } - - #endif - } - } - - __forceinline static void ExpandBlock4HH_32(DWORD* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) - { - for(int j = 0; j < 8; j++, dst += dstpitch) - { - const GSVector4i* s = (const GSVector4i*)src; - - ((GSVector4i*)dst)[0] = (s[j * 2 + 0] >> 28).gather32_32<>(pal); - ((GSVector4i*)dst)[1] = (s[j * 2 + 1] >> 28).gather32_32<>(pal); - } - } - - __forceinline static void ExpandBlock4HH_16(DWORD* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) - { - for(int j = 0; j < 8; j++, dst += dstpitch) - { - #if _M_SSE >= 0x401 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i v0 = (s[j * 2 + 0] >> 28).gather32_32<>(pal); - GSVector4i v1 = (s[j * 2 + 1] >> 28).gather32_32<>(pal); - - ((GSVector4i*)dst)[0] = v0.pu32(v1); - - #else - - for(int i = 0; i < 8; i++) - { - ((WORD*)dst)[i] = (WORD)pal[src[j * 8 + i] >> 28]; - } - - #endif - } - } - - __forceinline static void UnpackAndWriteBlock24(const BYTE* RESTRICT src, int srcpitch, BYTE* RESTRICT dst) - { - #if _M_SSE >= 0x200 - - GSVector4i mask(0x00ffffff); - - for(int i = 0; i < 4; i++, src += srcpitch * 2) - { - GSVector4i v4 = GSVector4i::load(src); - GSVector4i v5 = GSVector4i::load(src + 16, src + srcpitch); - GSVector4i v6 = GSVector4i::load(src + srcpitch + 8); - - GSVector4i v0 = v4.upl32(v4.srl<3>()).upl64(v4.srl<6>().upl32(v4.srl<9>())); - - v4 = v4.srl<12>(v5); - - GSVector4i v1 = v4.upl32(v4.srl<3>()).upl64(v4.srl<6>().upl32(v4.srl<9>())); - - v4 = v5.srl<8>(v6); - - GSVector4i v2 = v4.upl32(v4.srl<3>()).upl64(v4.srl<6>().upl32(v4.srl<9>())); - - v4 = v6.srl<4>(); - - GSVector4i v3 = v4.upl32(v4.srl<3>()).upl64(v4.srl<6>().upl32(v4.srl<9>())); - - GSVector4i::sw64(v0, v2, v1, v3); - - #ifdef _M_AMD64 - - ((GSVector4i*)dst)[i * 4 + 0] = ((GSVector4i*)dst)[i * 4 + 0].blend8(v0, mask); - ((GSVector4i*)dst)[i * 4 + 1] = ((GSVector4i*)dst)[i * 4 + 1].blend8(v1, mask); - ((GSVector4i*)dst)[i * 4 + 2] = ((GSVector4i*)dst)[i * 4 + 2].blend8(v2, mask); - ((GSVector4i*)dst)[i * 4 + 3] = ((GSVector4i*)dst)[i * 4 + 3].blend8(v3, mask); - - #else - - // here blend is faster than blend8 because vc8 has a little problem optimizing register usage for pblendvb (3rd op must be xmm0) - - ((GSVector4i*)dst)[i * 4 + 0] = ((GSVector4i*)dst)[i * 4 + 0].blend(v0, mask); - ((GSVector4i*)dst)[i * 4 + 1] = ((GSVector4i*)dst)[i * 4 + 1].blend(v1, mask); - ((GSVector4i*)dst)[i * 4 + 2] = ((GSVector4i*)dst)[i * 4 + 2].blend(v2, mask); - ((GSVector4i*)dst)[i * 4 + 3] = ((GSVector4i*)dst)[i * 4 + 3].blend(v3, mask); - - #endif - } - - #else - - const BYTE* d = &columnTable32[0][0]; - - for(int j = 0, diff = srcpitch - 8 * 3; j < 8; j++, src += diff, d += 8) - { - for(int i = 0; i < 8; i++, src += 3) - { - ((DWORD*)dst)[d[i]] = (((DWORD*)dst)[d[i]] & ~0x00ffffff) | (src[2] << 16) | (src[1] << 8) | src[0]; - } - } - - #endif - } - - __forceinline static void UnpackAndWriteBlock8H(const BYTE* RESTRICT src, int srcpitch, BYTE* RESTRICT dst) - { - #if _M_SSE >= 0x301 - - GSVector4i mask(0xff000000); - - GSVector4i mask0 = m_uw8hmask0; - GSVector4i mask1 = m_uw8hmask1; - GSVector4i mask2 = m_uw8hmask2; - GSVector4i mask3 = m_uw8hmask3; - - for(int i = 0; i < 4; i++, src += srcpitch * 2) - { - GSVector4i v4 = GSVector4i::load(src, src + srcpitch); - - GSVector4i v0 = v4.shuffle8(mask0); - GSVector4i v1 = v4.shuffle8(mask1); - GSVector4i v2 = v4.shuffle8(mask2); - GSVector4i v3 = v4.shuffle8(mask3); - - ((GSVector4i*)dst)[i * 4 + 0] = ((GSVector4i*)dst)[i * 4 + 0].blend8(v0, mask); - ((GSVector4i*)dst)[i * 4 + 1] = ((GSVector4i*)dst)[i * 4 + 1].blend8(v1, mask); - ((GSVector4i*)dst)[i * 4 + 2] = ((GSVector4i*)dst)[i * 4 + 2].blend8(v2, mask); - ((GSVector4i*)dst)[i * 4 + 3] = ((GSVector4i*)dst)[i * 4 + 3].blend8(v3, mask); - } - - #elif _M_SSE >= 0x200 - - GSVector4i mask(0xff000000); - - for(int i = 0; i < 4; i++, src += srcpitch * 2) - { - GSVector4i v4 = GSVector4i::load(src, src + srcpitch); - - GSVector4i v5 = v4.upl8(v4); - GSVector4i v6 = v4.uph8(v4); - - GSVector4i v0 = v5.upl16(v5); - GSVector4i v1 = v5.uph16(v5); - GSVector4i v2 = v6.upl16(v6); - GSVector4i v3 = v6.uph16(v6); - - GSVector4i::sw64(v0, v2, v1, v3); - - ((GSVector4i*)dst)[i * 4 + 0] = ((GSVector4i*)dst)[i * 4 + 0].blend8(v0, mask); - ((GSVector4i*)dst)[i * 4 + 1] = ((GSVector4i*)dst)[i * 4 + 1].blend8(v1, mask); - ((GSVector4i*)dst)[i * 4 + 2] = ((GSVector4i*)dst)[i * 4 + 2].blend8(v2, mask); - ((GSVector4i*)dst)[i * 4 + 3] = ((GSVector4i*)dst)[i * 4 + 3].blend8(v3, mask); - } - - #else - - const BYTE* d = &columnTable32[0][0]; - - for(int j = 0; j < 8; j++, src += srcpitch, dst += 8) - { - for(int i = 0; i < 8; i++) - { - ((DWORD*)dst)[d[i]] = (((DWORD*)dst)[d[i]] & ~0xff000000) | (src[i] << 24); - } - } - - #endif - } - - __forceinline static void UnpackAndWriteBlock4HL(const BYTE* RESTRICT src, int srcpitch, BYTE* RESTRICT dst) - { - #if _M_SSE >= 0x301 - - GSVector4i mask(0x0f0f0f0f); - GSVector4i mask0 = m_uw8hmask0; - GSVector4i mask1 = m_uw8hmask1; - GSVector4i mask2 = m_uw8hmask2; - GSVector4i mask3 = m_uw8hmask3; - GSVector4i mask4(0x0f000000); - - for(int i = 0; i < 2; i++, src += srcpitch * 4) - { - GSVector4i v( - *(DWORD*)&src[srcpitch * 0], - *(DWORD*)&src[srcpitch * 1], - *(DWORD*)&src[srcpitch * 2], - *(DWORD*)&src[srcpitch * 3]); - - GSVector4i lo = v & mask; - GSVector4i hi = (v >> 4) & mask; - - { - GSVector4i v4 = lo.upl8(hi); - - GSVector4i v0 = v4.shuffle8(mask0); - GSVector4i v1 = v4.shuffle8(mask1); - GSVector4i v2 = v4.shuffle8(mask2); - GSVector4i v3 = v4.shuffle8(mask3); - - ((GSVector4i*)dst)[i * 8 + 0] = ((GSVector4i*)dst)[i * 8 + 0].blend(v0, mask4); - ((GSVector4i*)dst)[i * 8 + 1] = ((GSVector4i*)dst)[i * 8 + 1].blend(v1, mask4); - ((GSVector4i*)dst)[i * 8 + 2] = ((GSVector4i*)dst)[i * 8 + 2].blend(v2, mask4); - ((GSVector4i*)dst)[i * 8 + 3] = ((GSVector4i*)dst)[i * 8 + 3].blend(v3, mask4); - } - - { - GSVector4i v4 = lo.uph8(hi); - - GSVector4i v0 = v4.shuffle8(mask0); - GSVector4i v1 = v4.shuffle8(mask1); - GSVector4i v2 = v4.shuffle8(mask2); - GSVector4i v3 = v4.shuffle8(mask3); - - ((GSVector4i*)dst)[i * 8 + 4] = ((GSVector4i*)dst)[i * 8 + 4].blend(v0, mask4); - ((GSVector4i*)dst)[i * 8 + 5] = ((GSVector4i*)dst)[i * 8 + 5].blend(v1, mask4); - ((GSVector4i*)dst)[i * 8 + 6] = ((GSVector4i*)dst)[i * 8 + 6].blend(v2, mask4); - ((GSVector4i*)dst)[i * 8 + 7] = ((GSVector4i*)dst)[i * 8 + 7].blend(v3, mask4); - } - } - - #elif _M_SSE >= 0x200 -/* - __declspec(align(16)) DWORD block[8 * 8]; - - UnpackBlock4HL(src, srcpitch, block); - - WriteBlock32(dst, (BYTE*)block, sizeof(block) / 8); -*/ - GSVector4i mask(0x0f0f0f0f); - GSVector4i mask2(0x0f000000); - - for(int i = 0; i < 2; i++, src += srcpitch * 4) - { - GSVector4i v( - *(DWORD*)&src[srcpitch * 0], - *(DWORD*)&src[srcpitch * 1], - *(DWORD*)&src[srcpitch * 2], - *(DWORD*)&src[srcpitch * 3]); - - GSVector4i lo = v & mask; - GSVector4i hi = (v >> 4) & mask; - - { - GSVector4i v4 = lo.upl8(hi); - - GSVector4i v5 = v4.upl8(v4); - GSVector4i v6 = v4.uph8(v4); - - GSVector4i v0 = v5.upl16(v5); - GSVector4i v1 = v5.uph16(v5); - GSVector4i v2 = v6.upl16(v6); - GSVector4i v3 = v6.uph16(v6); - - GSVector4i::sw64(v0, v2, v1, v3); - - ((GSVector4i*)dst)[i * 8 + 0] = ((GSVector4i*)dst)[i * 8 + 0].blend(v0, mask2); - ((GSVector4i*)dst)[i * 8 + 1] = ((GSVector4i*)dst)[i * 8 + 1].blend(v1, mask2); - ((GSVector4i*)dst)[i * 8 + 2] = ((GSVector4i*)dst)[i * 8 + 2].blend(v2, mask2); - ((GSVector4i*)dst)[i * 8 + 3] = ((GSVector4i*)dst)[i * 8 + 3].blend(v3, mask2); - } - - { - GSVector4i v4 = lo.uph8(hi); - - GSVector4i v5 = v4.upl8(v4); - GSVector4i v6 = v4.uph8(v4); - - GSVector4i v0 = v5.upl16(v5); - GSVector4i v1 = v5.uph16(v5); - GSVector4i v2 = v6.upl16(v6); - GSVector4i v3 = v6.uph16(v6); - - GSVector4i::sw64(v0, v2, v1, v3); - - ((GSVector4i*)dst)[i * 8 + 4] = ((GSVector4i*)dst)[i * 8 + 4].blend(v0, mask2); - ((GSVector4i*)dst)[i * 8 + 5] = ((GSVector4i*)dst)[i * 8 + 5].blend(v1, mask2); - ((GSVector4i*)dst)[i * 8 + 6] = ((GSVector4i*)dst)[i * 8 + 6].blend(v2, mask2); - ((GSVector4i*)dst)[i * 8 + 7] = ((GSVector4i*)dst)[i * 8 + 7].blend(v3, mask2); - } - } - - #else - - const BYTE* d = &columnTable32[0][0]; - - for(int j = 0; j < 8; j++, d += 8, src += srcpitch) - { - for(int i = 0; i < 4; i++) - { - ((DWORD*)dst)[d[i * 2 + 0]] = (((DWORD*)dst)[d[i * 2 + 0]] & ~0x0f000000) | ((src[i] & 0x0f) << 24); - ((DWORD*)dst)[d[i * 2 + 1]] = (((DWORD*)dst)[d[i * 2 + 1]] & ~0x0f000000) | ((src[i] & 0xf0) << 20); - } - } - - #endif - } - - __forceinline static void UnpackAndWriteBlock4HH(const BYTE* RESTRICT src, int srcpitch, BYTE* RESTRICT dst) - { - #if _M_SSE >= 0x301 - - GSVector4i mask(0xf0f0f0f0); - GSVector4i mask0 = m_uw8hmask0; - GSVector4i mask1 = m_uw8hmask1; - GSVector4i mask2 = m_uw8hmask2; - GSVector4i mask3 = m_uw8hmask3; - GSVector4i mask4(0xf0000000); - - for(int i = 0; i < 2; i++, src += srcpitch * 4) - { - GSVector4i v( - *(DWORD*)&src[srcpitch * 0], - *(DWORD*)&src[srcpitch * 1], - *(DWORD*)&src[srcpitch * 2], - *(DWORD*)&src[srcpitch * 3]); - - GSVector4i lo = (v << 4) & mask; - GSVector4i hi = v & mask; - - { - GSVector4i v4 = lo.upl8(hi); - - GSVector4i v0 = v4.shuffle8(mask0); - GSVector4i v1 = v4.shuffle8(mask1); - GSVector4i v2 = v4.shuffle8(mask2); - GSVector4i v3 = v4.shuffle8(mask3); - - ((GSVector4i*)dst)[i * 8 + 0] = ((GSVector4i*)dst)[i * 8 + 0].blend(v0, mask4); - ((GSVector4i*)dst)[i * 8 + 1] = ((GSVector4i*)dst)[i * 8 + 1].blend(v1, mask4); - ((GSVector4i*)dst)[i * 8 + 2] = ((GSVector4i*)dst)[i * 8 + 2].blend(v2, mask4); - ((GSVector4i*)dst)[i * 8 + 3] = ((GSVector4i*)dst)[i * 8 + 3].blend(v3, mask4); - } - - { - GSVector4i v4 = lo.uph8(hi); - - GSVector4i v0 = v4.shuffle8(mask0); - GSVector4i v1 = v4.shuffle8(mask1); - GSVector4i v2 = v4.shuffle8(mask2); - GSVector4i v3 = v4.shuffle8(mask3); - - ((GSVector4i*)dst)[i * 8 + 4] = ((GSVector4i*)dst)[i * 8 + 4].blend(v0, mask4); - ((GSVector4i*)dst)[i * 8 + 5] = ((GSVector4i*)dst)[i * 8 + 5].blend(v1, mask4); - ((GSVector4i*)dst)[i * 8 + 6] = ((GSVector4i*)dst)[i * 8 + 6].blend(v2, mask4); - ((GSVector4i*)dst)[i * 8 + 7] = ((GSVector4i*)dst)[i * 8 + 7].blend(v3, mask4); - } - } - - #elif _M_SSE >= 0x200 -/* - __declspec(align(16)) DWORD block[8 * 8]; - - UnpackBlock4HH(src, srcpitch, block); - - WriteBlock32(dst, (BYTE*)block, sizeof(block) / 8); -*/ - GSVector4i mask(0xf0f0f0f0); - GSVector4i mask2(0xf0000000); - - for(int i = 0; i < 2; i++, src += srcpitch * 4) - { - GSVector4i v( - *(DWORD*)&src[srcpitch * 0], - *(DWORD*)&src[srcpitch * 1], - *(DWORD*)&src[srcpitch * 2], - *(DWORD*)&src[srcpitch * 3]); - - GSVector4i lo = (v << 4) & mask; - GSVector4i hi = v & mask; - - { - GSVector4i v4 = lo.upl8(hi); - - GSVector4i v5 = v4.upl8(v4); - GSVector4i v6 = v4.uph8(v4); - - GSVector4i v0 = v5.upl16(v5); - GSVector4i v1 = v5.uph16(v5); - GSVector4i v2 = v6.upl16(v6); - GSVector4i v3 = v6.uph16(v6); - - GSVector4i::sw64(v0, v2, v1, v3); - - ((GSVector4i*)dst)[i * 8 + 0] = ((GSVector4i*)dst)[i * 8 + 0].blend(v0, mask2); - ((GSVector4i*)dst)[i * 8 + 1] = ((GSVector4i*)dst)[i * 8 + 1].blend(v1, mask2); - ((GSVector4i*)dst)[i * 8 + 2] = ((GSVector4i*)dst)[i * 8 + 2].blend(v2, mask2); - ((GSVector4i*)dst)[i * 8 + 3] = ((GSVector4i*)dst)[i * 8 + 3].blend(v3, mask2); - } - - { - GSVector4i v4 = lo.uph8(hi); - - GSVector4i v5 = v4.upl8(v4); - GSVector4i v6 = v4.uph8(v4); - - GSVector4i v0 = v5.upl16(v5); - GSVector4i v1 = v5.uph16(v5); - GSVector4i v2 = v6.upl16(v6); - GSVector4i v3 = v6.uph16(v6); - - GSVector4i::sw64(v0, v2, v1, v3); - - ((GSVector4i*)dst)[i * 8 + 4] = ((GSVector4i*)dst)[i * 8 + 4].blend(v0, mask2); - ((GSVector4i*)dst)[i * 8 + 5] = ((GSVector4i*)dst)[i * 8 + 5].blend(v1, mask2); - ((GSVector4i*)dst)[i * 8 + 6] = ((GSVector4i*)dst)[i * 8 + 6].blend(v2, mask2); - ((GSVector4i*)dst)[i * 8 + 7] = ((GSVector4i*)dst)[i * 8 + 7].blend(v3, mask2); - } - } - - #else - - const BYTE* d = &columnTable32[0][0]; - - for(int j = 0; j < 8; j++, d += 8, src += srcpitch) - { - for(int i = 0; i < 4; i++) - { - ((DWORD*)dst)[d[i * 2 + 0]] = (((DWORD*)dst)[d[i * 2 + 0]] & ~0xf0000000) | ((src[i] & 0x0f) << 28); - ((DWORD*)dst)[d[i * 2 + 1]] = (((DWORD*)dst)[d[i * 2 + 1]] & ~0xf0000000) | ((src[i] & 0xf0) << 24); - } - } - - #endif - } - - template __forceinline static void ReadAndExpandBlock24(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const GIFRegTEXA& TEXA) - { - #if _M_SSE >= 0x200 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i TA0(TEXA.TA0 << 24); - GSVector4i mask = GSVector4i::x00ffffff(); - - for(int i = 0; i < 4; i++, dst += dstpitch * 2) - { - GSVector4i v0 = s[i * 4 + 0]; - GSVector4i v1 = s[i * 4 + 1]; - GSVector4i v2 = s[i * 4 + 2]; - GSVector4i v3 = s[i * 4 + 3]; - - GSVector4i::sw64(v0, v1, v2, v3); - - v0 &= mask; - v1 &= mask; - v2 &= mask; - v3 &= mask; - - GSVector4i* d0 = (GSVector4i*)&dst[dstpitch * 0]; - GSVector4i* d1 = (GSVector4i*)&dst[dstpitch * 1]; - - if(AEM) - { - d0[0] = v0 | TA0.andnot(v0 == GSVector4i::zero()); // TA0 & (v0 != GSVector4i::zero()) - d0[1] = v1 | TA0.andnot(v1 == GSVector4i::zero()); // TA0 & (v1 != GSVector4i::zero()) - d1[0] = v2 | TA0.andnot(v2 == GSVector4i::zero()); // TA0 & (v2 != GSVector4i::zero()) - d1[1] = v3 | TA0.andnot(v3 == GSVector4i::zero()); // TA0 & (v3 != GSVector4i::zero()) - } - else - { - d0[0] = v0 | TA0; - d0[1] = v1 | TA0; - d1[0] = v2 | TA0; - d1[1] = v3 | TA0; - } - } - - #else - - DWORD TA0 = TEXA.TA0 << 24; - - const BYTE* s = &columnTable32[0][0]; - - for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) - { - for(int i = 0; i < 8; i++) - { - DWORD c = ((DWORD*)src)[s[i]] & 0xffffff; - - if(AEM) - { - ((DWORD*)dst)[i] = c | (c ? TA0 : 0); - } - else - { - ((DWORD*)dst)[i] = c | TA0; - } - } - } - - #endif - } - - __forceinline static void ReadAndExpandBlock8_32(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) - { - #if _M_SSE >= 0x401 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i v0, v1, v2, v3; - GSVector4i mask = m_r8mask; - - for(int i = 0; i < 2; i++) - { - v0 = s[i * 8 + 0].shuffle8(mask); - v1 = s[i * 8 + 1].shuffle8(mask); - v2 = s[i * 8 + 2].shuffle8(mask); - v3 = s[i * 8 + 3].shuffle8(mask); - - GSVector4i::sw16(v0, v1, v2, v3); - GSVector4i::sw32(v0, v1, v3, v2); - - v0.gather32_8<>(pal, (GSVector4i*)dst); - dst += dstpitch; - v3.gather32_8<>(pal, (GSVector4i*)dst); - dst += dstpitch; - v1.gather32_8<>(pal, (GSVector4i*)dst); - dst += dstpitch; - v2.gather32_8<>(pal, (GSVector4i*)dst); - dst += dstpitch; - - v2 = s[i * 8 + 4].shuffle8(mask); - v3 = s[i * 8 + 5].shuffle8(mask); - v0 = s[i * 8 + 6].shuffle8(mask); - v1 = s[i * 8 + 7].shuffle8(mask); - - GSVector4i::sw16(v0, v1, v2, v3); - GSVector4i::sw32(v0, v1, v3, v2); - - v0.gather32_8<>(pal, (GSVector4i*)dst); - dst += dstpitch; - v3.gather32_8<>(pal, (GSVector4i*)dst); - dst += dstpitch; - v1.gather32_8<>(pal, (GSVector4i*)dst); - dst += dstpitch; - v2.gather32_8<>(pal, (GSVector4i*)dst); - dst += dstpitch; - } - - #elif _M_SSE >= 0x200 - - __declspec(align(16)) BYTE block[16 * 16]; - - ReadBlock8(src, (BYTE*)block, sizeof(block) / 16); - - ExpandBlock8_32(block, dst, dstpitch, pal); - - #else - - const BYTE* s = &columnTable8[0][0]; - - for(int j = 0; j < 16; j++, s += 16, dst += dstpitch) - { - for(int i = 0; i < 16; i++) - { - ((DWORD*)dst)[i] = pal[src[s[i]]]; - } - } - - #endif - } - - // TODO: ReadAndExpandBlock8_16 - - __forceinline static void ReadAndExpandBlock4_32(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const UINT64* RESTRICT pal) - { - #if _M_SSE >= 0x401 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i v0, v1, v2, v3; - GSVector4i mask = m_r4mask; - - for(int i = 0; i < 2; i++) - { - v0 = s[i * 8 + 0].xzyw(); - v1 = s[i * 8 + 1].xzyw(); - v2 = s[i * 8 + 2].xzyw(); - v3 = s[i * 8 + 3].xzyw(); - - GSVector4i::sw64(v0, v1, v2, v3); - GSVector4i::sw4(v0, v2, v1, v3); - GSVector4i::sw8(v0, v1, v2, v3); - - v0 = v0.shuffle8(mask); - v1 = v1.shuffle8(mask); - v2 = v2.shuffle8(mask); - v3 = v3.shuffle8(mask); - - GSVector4i::sw16rh(v0, v1, v2, v3); - - v0.gather64_8<>(pal, (GSVector4i*)dst); - dst += dstpitch; - v1.gather64_8<>(pal, (GSVector4i*)dst); - dst += dstpitch; - v2.gather64_8<>(pal, (GSVector4i*)dst); - dst += dstpitch; - v3.gather64_8<>(pal, (GSVector4i*)dst); - dst += dstpitch; - - v0 = s[i * 8 + 4].xzyw(); - v1 = s[i * 8 + 5].xzyw(); - v2 = s[i * 8 + 6].xzyw(); - v3 = s[i * 8 + 7].xzyw(); - - GSVector4i::sw64(v0, v1, v2, v3); - GSVector4i::sw4(v0, v2, v1, v3); - GSVector4i::sw8(v0, v1, v2, v3); - - v0 = v0.shuffle8(mask); - v1 = v1.shuffle8(mask); - v2 = v2.shuffle8(mask); - v3 = v3.shuffle8(mask); - - GSVector4i::sw16rl(v0, v1, v2, v3); - - v0.gather64_8<>(pal, (GSVector4i*)dst); - dst += dstpitch; - v1.gather64_8<>(pal, (GSVector4i*)dst); - dst += dstpitch; - v2.gather64_8<>(pal, (GSVector4i*)dst); - dst += dstpitch; - v3.gather64_8<>(pal, (GSVector4i*)dst); - dst += dstpitch; - } - - #elif _M_SSE >= 0x200 - - __declspec(align(16)) BYTE block[(32 / 2) * 16]; - - ReadBlock4(src, (BYTE*)block, sizeof(block) / 16); - - ExpandBlock4_32(block, dst, dstpitch, pal); - - #else - - const WORD* s = &columnTable4[0][0]; - - for(int j = 0; j < 16; j++, s += 32, dst += dstpitch) - { - for(int i = 0; i < 16; i++) - { - BYTE a0 = s[i * 2 + 0]; - BYTE a1 = s[i * 2 + 1]; - - BYTE c0 = (src[a0 >> 1] >> ((a0 & 1) << 2)) & 0x0f; - BYTE c1 = (src[a1 >> 1] >> ((a1 & 1) << 2)) & 0x0f; - - ((UINT64*)dst)[i] = pal[(c1 << 4) | c0]; - } - } - - #endif - } - - // TODO: ReadAndExpandBlock4_16 - - __forceinline static void ReadAndExpandBlock8H_32(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) - { - #if _M_SSE >= 0x401 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i v0, v1, v2, v3; - - for(int i = 0; i < 4; i++) - { - v0 = s[i * 4 + 0]; - v1 = s[i * 4 + 1]; - v2 = s[i * 4 + 2]; - v3 = s[i * 4 + 3]; - - GSVector4i::sw64(v0, v1, v2, v3); - - (v0 >> 24).gather32_32<>(pal, (GSVector4i*)&dst[0]); - (v1 >> 24).gather32_32<>(pal, (GSVector4i*)&dst[16]); - - dst += dstpitch; - - (v2 >> 24).gather32_32<>(pal, (GSVector4i*)&dst[0]); - (v3 >> 24).gather32_32<>(pal, (GSVector4i*)&dst[16]); - - dst += dstpitch; - } - - #elif _M_SSE >= 0x200 - - __declspec(align(16)) DWORD block[8 * 8]; - - ReadBlock32(src, (BYTE*)block, sizeof(block) / 8); - - ExpandBlock8H_32(block, dst, dstpitch, pal); - - #else - - const BYTE* s = &columnTable32[0][0]; - - for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) - { - for(int i = 0; i < 8; i++) - { - ((DWORD*)dst)[i] = pal[((DWORD*)src)[s[i]] >> 24]; - } - } - - #endif - } - - // TODO: ReadAndExpandBlock8H_16 - - __forceinline static void ReadAndExpandBlock4HL_32(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) - { - #if _M_SSE >= 0x401 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i v0, v1, v2, v3; - - for(int i = 0; i < 4; i++) - { - v0 = s[i * 4 + 0]; - v1 = s[i * 4 + 1]; - v2 = s[i * 4 + 2]; - v3 = s[i * 4 + 3]; - - GSVector4i::sw64(v0, v1, v2, v3); - - ((v0 >> 24) & 0xf).gather32_32<>(pal, (GSVector4i*)&dst[0]); - ((v1 >> 24) & 0xf).gather32_32<>(pal, (GSVector4i*)&dst[16]); - - dst += dstpitch; - - ((v2 >> 24) & 0xf).gather32_32<>(pal, (GSVector4i*)&dst[0]); - ((v3 >> 24) & 0xf).gather32_32<>(pal, (GSVector4i*)&dst[16]); - - dst += dstpitch; - } - - #elif _M_SSE >= 0x200 - - __declspec(align(16)) DWORD block[8 * 8]; - - ReadBlock32(src, (BYTE*)block, sizeof(block) / 8); - - ExpandBlock4HL_32(block, dst, dstpitch, pal); - - #else - - const BYTE* s = &columnTable32[0][0]; - - for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) - { - for(int i = 0; i < 8; i++) - { - ((DWORD*)dst)[i] = pal[(((DWORD*)src)[s[i]] >> 24) & 0xf]; - } - } - - #endif - } - - // TODO: ReadAndExpandBlock4HL_16 - - __forceinline static void ReadAndExpandBlock4HH_32(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) - { - #if _M_SSE >= 0x401 - - const GSVector4i* s = (const GSVector4i*)src; - - GSVector4i v0, v1, v2, v3; - - for(int i = 0; i < 4; i++) - { - v0 = s[i * 4 + 0]; - v1 = s[i * 4 + 1]; - v2 = s[i * 4 + 2]; - v3 = s[i * 4 + 3]; - - GSVector4i::sw64(v0, v1, v2, v3); - - (v0 >> 28).gather32_32<>(pal, (GSVector4i*)&dst[0]); - (v1 >> 28).gather32_32<>(pal, (GSVector4i*)&dst[16]); - - dst += dstpitch; - - (v2 >> 28).gather32_32<>(pal, (GSVector4i*)&dst[0]); - (v3 >> 28).gather32_32<>(pal, (GSVector4i*)&dst[16]); - - dst += dstpitch; - } - - #elif _M_SSE >= 0x200 - - __declspec(align(16)) DWORD block[8 * 8]; - - ReadBlock32(src, (BYTE*)block, sizeof(block) / 8); - - ExpandBlock4HH_32(block, dst, dstpitch, pal); - - #else - - const BYTE* s = &columnTable32[0][0]; - - for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) - { - for(int i = 0; i < 8; i++) - { - ((DWORD*)dst)[i] = pal[((DWORD*)src)[s[i]] >> 28]; - } - } - - #endif - } - - // TODO: ReadAndExpandBlock4HH_16 -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GS.h" +#include "GSTables.h" +#include "GSVector.h" + +class GSBlock +{ + static const GSVector4i m_r16mask; + static const GSVector4i m_r8mask; + static const GSVector4i m_r4mask; + + static const GSVector4i m_xxxa; + static const GSVector4i m_xxbx; + static const GSVector4i m_xgxx; + static const GSVector4i m_rxxx; + + static const GSVector4i m_uw8hmask0; + static const GSVector4i m_uw8hmask1; + static const GSVector4i m_uw8hmask2; + static const GSVector4i m_uw8hmask3; + +public: + template __forceinline static void WriteColumn32(BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) + { + #if _M_SSE >= 0x200 + + const GSVector4i* s0 = (const GSVector4i*)&src[srcpitch * 0]; + const GSVector4i* s1 = (const GSVector4i*)&src[srcpitch * 1]; + + GSVector4i v0 = GSVector4i::load(&s0[0]); + GSVector4i v1 = GSVector4i::load(&s0[1]); + GSVector4i v2 = GSVector4i::load(&s1[0]); + GSVector4i v3 = GSVector4i::load(&s1[1]); + + GSVector4i::sw64(v0, v2, v1, v3); + + if(mask == 0xffffffff) + { + ((GSVector4i*)dst)[i * 4 + 0] = v0; + ((GSVector4i*)dst)[i * 4 + 1] = v1; + ((GSVector4i*)dst)[i * 4 + 2] = v2; + ((GSVector4i*)dst)[i * 4 + 3] = v3; + } + else + { + GSVector4i v4((int)mask); + + #if _M_SSE >= 0x401 + + if(mask == 0xff000000 || mask == 0x00ffffff) + { + ((GSVector4i*)dst)[i * 4 + 0] = ((GSVector4i*)dst)[i * 4 + 0].blend8(v0, v4); + ((GSVector4i*)dst)[i * 4 + 1] = ((GSVector4i*)dst)[i * 4 + 1].blend8(v1, v4); + ((GSVector4i*)dst)[i * 4 + 2] = ((GSVector4i*)dst)[i * 4 + 2].blend8(v2, v4); + ((GSVector4i*)dst)[i * 4 + 3] = ((GSVector4i*)dst)[i * 4 + 3].blend8(v3, v4); + } + else + { + + #endif + + ((GSVector4i*)dst)[i * 4 + 0] = ((GSVector4i*)dst)[i * 4 + 0].blend(v0, v4); + ((GSVector4i*)dst)[i * 4 + 1] = ((GSVector4i*)dst)[i * 4 + 1].blend(v1, v4); + ((GSVector4i*)dst)[i * 4 + 2] = ((GSVector4i*)dst)[i * 4 + 2].blend(v2, v4); + ((GSVector4i*)dst)[i * 4 + 3] = ((GSVector4i*)dst)[i * 4 + 3].blend(v3, v4); + + #if _M_SSE >= 0x401 + + } + + #endif + } + + #else + + const BYTE* d = &columnTable32[(i & 3) << 1][0]; + + for(int j = 0; j < 2; j++, d += 8, src += srcpitch) + { + for(int i = 0; i < 8; i++) + { + if(mask == 0xffffffff) + { + ((DWORD*)dst)[d[i]] = ((DWORD*)src)[i]; + } + else + { + ((DWORD*)dst)[d[i]] = (((DWORD*)dst)[d[i]] & ~mask) | (((DWORD*)src)[i] & mask); + } + } + } + + #endif + } + + template __forceinline static void WriteColumn16(BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) + { + #if _M_SSE >= 0x200 + + const GSVector4i* s0 = (const GSVector4i*)&src[srcpitch * 0]; + const GSVector4i* s1 = (const GSVector4i*)&src[srcpitch * 1]; + + GSVector4i v0 = GSVector4i::load(&s0[0]); + GSVector4i v1 = GSVector4i::load(&s0[1]); + GSVector4i v2 = GSVector4i::load(&s1[0]); + GSVector4i v3 = GSVector4i::load(&s1[1]); + + GSVector4i::sw16(v0, v1, v2, v3); + GSVector4i::sw64(v0, v1, v2, v3); + + ((GSVector4i*)dst)[i * 4 + 0] = v0; + ((GSVector4i*)dst)[i * 4 + 1] = v2; + ((GSVector4i*)dst)[i * 4 + 2] = v1; + ((GSVector4i*)dst)[i * 4 + 3] = v3; + + #else + + const BYTE* d = &columnTable16[(i & 3) << 1][0]; + + for(int j = 0; j < 2; j++, d += 16, src += srcpitch) + { + for(int i = 0; i < 16; i++) + { + ((WORD*)dst)[d[i]] = ((WORD*)src)[i]; + } + } + + #endif + } + + template __forceinline static void WriteColumn8(BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) + { + #if _M_SSE >= 0x200 + + GSVector4i v0 = GSVector4i::load(&src[srcpitch * 0]); + GSVector4i v1 = GSVector4i::load(&src[srcpitch * 1]); + GSVector4i v2 = GSVector4i::load(&src[srcpitch * 2]); + GSVector4i v3 = GSVector4i::load(&src[srcpitch * 3]); + + if((i & 1) == 0) + { + v2 = v2.yxwz(); + v3 = v3.yxwz(); + } + else + { + v0 = v0.yxwz(); + v1 = v1.yxwz(); + } + + GSVector4i::sw8(v0, v2, v1, v3); + GSVector4i::sw16(v0, v1, v2, v3); + GSVector4i::sw64(v0, v1, v2, v3); + + ((GSVector4i*)dst)[i * 4 + 0] = v0; + ((GSVector4i*)dst)[i * 4 + 1] = v2; + ((GSVector4i*)dst)[i * 4 + 2] = v1; + ((GSVector4i*)dst)[i * 4 + 3] = v3; + + #else + + const BYTE* d = &columnTable8[(i & 3) << 2][0]; + + for(int j = 0; j < 4; j++, d += 16, src += srcpitch) + { + for(int i = 0; i < 16; i++) + { + dst[d[i]] = src[i]; + } + } + + #endif + } + + template __forceinline static void WriteColumn4(BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) + { + // TODO: pshufb + + #if _M_SSE >= 0x200 + + GSVector4i v0 = GSVector4i::load(&src[srcpitch * 0]); + GSVector4i v1 = GSVector4i::load(&src[srcpitch * 1]); + GSVector4i v2 = GSVector4i::load(&src[srcpitch * 2]); + GSVector4i v3 = GSVector4i::load(&src[srcpitch * 3]); + + if((i & 1) == 0) + { + v2 = v2.yxwzlh(); + v3 = v3.yxwzlh(); + } + else + { + v0 = v0.yxwzlh(); + v1 = v1.yxwzlh(); + } + + GSVector4i::sw4(v0, v2, v1, v3); + GSVector4i::sw8(v0, v1, v2, v3); + GSVector4i::sw8(v0, v2, v1, v3); + GSVector4i::sw64(v0, v2, v1, v3); + + ((GSVector4i*)dst)[i * 4 + 0] = v0; + ((GSVector4i*)dst)[i * 4 + 1] = v1; + ((GSVector4i*)dst)[i * 4 + 2] = v2; + ((GSVector4i*)dst)[i * 4 + 3] = v3; + + #else + + const WORD* d = &columnTable4[(i & 3) << 2][0]; + + for(int j = 0; j < 4; j++, d += 32, src += srcpitch) + { + for(int i = 0; i < 32; i++) + { + DWORD addr = d[i]; + BYTE c = (src[i >> 1] >> ((i & 1) << 2)) & 0x0f; + DWORD shift = (addr & 1) << 2; + dst[addr >> 1] = (dst[addr >> 1] & (0xf0 >> shift)) | (c << shift); + } + } + + #endif + } + + template static void WriteColumn32(int y, BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) + { + switch((y >> 1) & 3) + { + case 0: WriteColumn32<0, aligned, mask>(dst, src, srcpitch); break; + case 1: WriteColumn32<1, aligned, mask>(dst, src, srcpitch); break; + case 2: WriteColumn32<2, aligned, mask>(dst, src, srcpitch); break; + case 3: WriteColumn32<3, aligned, mask>(dst, src, srcpitch); break; + default: __assume(0); + } + } + + template static void WriteColumn16(int y, BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) + { + switch((y >> 1) & 3) + { + case 0: WriteColumn16<0, aligned>(dst, src, srcpitch); break; + case 1: WriteColumn16<1, aligned>(dst, src, srcpitch); break; + case 2: WriteColumn16<2, aligned>(dst, src, srcpitch); break; + case 3: WriteColumn16<3, aligned>(dst, src, srcpitch); break; + default: __assume(0); + } + } + + template static void WriteColumn8(int y, BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) + { + switch((y >> 2) & 3) + { + case 0: WriteColumn8<0, aligned>(dst, src, srcpitch); break; + case 1: WriteColumn8<1, aligned>(dst, src, srcpitch); break; + case 2: WriteColumn8<2, aligned>(dst, src, srcpitch); break; + case 3: WriteColumn8<3, aligned>(dst, src, srcpitch); break; + default: __assume(0); + } + } + + template static void WriteColumn4(int y, BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) + { + switch((y >> 2) & 3) + { + case 0: WriteColumn4<0, aligned>(dst, src, srcpitch); break; + case 1: WriteColumn4<1, aligned>(dst, src, srcpitch); break; + case 2: WriteColumn4<2, aligned>(dst, src, srcpitch); break; + case 3: WriteColumn4<3, aligned>(dst, src, srcpitch); break; + default: __assume(0); + } + } + + template static void WriteBlock32(BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) + { + #if _M_SSE >= 0x200 + + WriteColumn32<0, aligned, mask>(dst, src, srcpitch); + src += srcpitch * 2; + WriteColumn32<1, aligned, mask>(dst, src, srcpitch); + src += srcpitch * 2; + WriteColumn32<2, aligned, mask>(dst, src, srcpitch); + src += srcpitch * 2; + WriteColumn32<3, aligned, mask>(dst, src, srcpitch); + + #else + + const BYTE* d = &columnTable32[0][0]; + + for(int j = 0; j < 8; j++, d += 8, src += srcpitch) + { + for(int i = 0; i < 8; i++) + { + if(mask == 0xffffffff) + { + ((DWORD*)dst)[d[i]] = ((DWORD*)src)[i]; + } + else + { + ((DWORD*)dst)[d[i]] = (((DWORD*)dst)[d[i]] & ~mask) | (((DWORD*)src)[i] & mask); + } + } + } + + #endif + } + + template static void WriteBlock16(BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) + { + #if _M_SSE >= 0x200 + + WriteColumn16<0, aligned>(dst, src, srcpitch); + src += srcpitch * 2; + WriteColumn16<1, aligned>(dst, src, srcpitch); + src += srcpitch * 2; + WriteColumn16<2, aligned>(dst, src, srcpitch); + src += srcpitch * 2; + WriteColumn16<3, aligned>(dst, src, srcpitch); + + #else + + const BYTE* d = &columnTable16[0][0]; + + for(int j = 0; j < 8; j++, d += 16, src += srcpitch) + { + for(int i = 0; i < 16; i++) + { + ((WORD*)dst)[d[i]] = ((WORD*)src)[i]; + } + } + + #endif + } + + template static void WriteBlock8(BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) + { + #if _M_SSE >= 0x200 + + WriteColumn8<0, aligned>(dst, src, srcpitch); + src += srcpitch * 4; + WriteColumn8<1, aligned>(dst, src, srcpitch); + src += srcpitch * 4; + WriteColumn8<2, aligned>(dst, src, srcpitch); + src += srcpitch * 4; + WriteColumn8<3, aligned>(dst, src, srcpitch); + + #else + + const BYTE* d = &columnTable8[0][0]; + + for(int j = 0; j < 16; j++, d += 16, src += srcpitch) + { + for(int i = 0; i < 16; i++) + { + dst[d[i]] = src[i]; + } + } + + #endif + } + + template static void WriteBlock4(BYTE* RESTRICT dst, const BYTE* RESTRICT src, int srcpitch) + { + #if _M_SSE >= 0x200 + + WriteColumn4<0, aligned>(dst, src, srcpitch); + src += srcpitch * 4; + WriteColumn4<1, aligned>(dst, src, srcpitch); + src += srcpitch * 4; + WriteColumn4<2, aligned>(dst, src, srcpitch); + src += srcpitch * 4; + WriteColumn4<3, aligned>(dst, src, srcpitch); + + #else + + const WORD* d = &columnTable4[0][0]; + + for(int j = 0; j < 16; j++, d += 32, src += srcpitch) + { + for(int i = 0; i < 32; i++) + { + DWORD addr = d[i]; + BYTE c = (src[i >> 1] >> ((i & 1) << 2)) & 0x0f; + DWORD shift = (addr & 1) << 2; + dst[addr >> 1] = (dst[addr >> 1] & (0xf0 >> shift)) | (c << shift); + } + } + + #endif + } + + template __forceinline static void ReadColumn32(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) + { + #if _M_SSE >= 0x200 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i v0 = s[i * 4 + 0]; + GSVector4i v1 = s[i * 4 + 1]; + GSVector4i v2 = s[i * 4 + 2]; + GSVector4i v3 = s[i * 4 + 3]; + + GSVector4i::sw64(v0, v1, v2, v3); + + GSVector4i* d0 = (GSVector4i*)&dst[dstpitch * 0]; + GSVector4i* d1 = (GSVector4i*)&dst[dstpitch * 1]; + + GSVector4i::store(&d0[0], v0); + GSVector4i::store(&d0[1], v1); + GSVector4i::store(&d1[0], v2); + GSVector4i::store(&d1[1], v3); + + #else + + const BYTE* s = &columnTable32[(i & 3) << 1][0]; + + for(int j = 0; j < 2; j++, s += 8, dst += dstpitch) + { + for(int i = 0; i < 8; i++) + { + ((DWORD*)dst)[i] = ((DWORD*)src)[s[i]]; + } + } + + #endif + } + + template __forceinline static void ReadColumn16(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) + { + #if _M_SSE >= 0x301 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i v0 = s[i * 4 + 0].shuffle8(m_r16mask); + GSVector4i v1 = s[i * 4 + 1].shuffle8(m_r16mask); + GSVector4i v2 = s[i * 4 + 2].shuffle8(m_r16mask); + GSVector4i v3 = s[i * 4 + 3].shuffle8(m_r16mask); + + GSVector4i::sw32(v0, v1, v2, v3); + GSVector4i::sw64(v0, v1, v2, v3); + + GSVector4i* d0 = (GSVector4i*)&dst[dstpitch * 0]; + GSVector4i* d1 = (GSVector4i*)&dst[dstpitch * 1]; + + GSVector4i::store(&d0[0], v0); + GSVector4i::store(&d0[1], v2); + GSVector4i::store(&d1[0], v1); + GSVector4i::store(&d1[1], v3); + + #elif _M_SSE >= 0x200 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i v0 = s[i * 4 + 0]; + GSVector4i v1 = s[i * 4 + 1]; + GSVector4i v2 = s[i * 4 + 2]; + GSVector4i v3 = s[i * 4 + 3]; + + GSVector4i::sw16(v0, v1, v2, v3); + GSVector4i::sw32(v0, v1, v2, v3); + GSVector4i::sw16(v0, v2, v1, v3); + + GSVector4i* d0 = (GSVector4i*)&dst[dstpitch * 0]; + GSVector4i* d1 = (GSVector4i*)&dst[dstpitch * 1]; + + GSVector4i::store(&d0[0], v0); + GSVector4i::store(&d0[1], v1); + GSVector4i::store(&d1[0], v2); + GSVector4i::store(&d1[1], v3); + + #else + + const BYTE* s = &columnTable16[(i & 3) << 1][0]; + + for(int j = 0; j < 2; j++, s += 16, dst += dstpitch) + { + for(int i = 0; i < 16; i++) + { + ((WORD*)dst)[i] = ((WORD*)src)[s[i]]; + } + } + + #endif + } + + template __forceinline static void ReadColumn8(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) + { + #if _M_SSE >= 0x301 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i v0, v1, v2, v3; + + if((i & 1) == 0) + { + v0 = s[i * 4 + 0]; + v1 = s[i * 4 + 1]; + v2 = s[i * 4 + 2]; + v3 = s[i * 4 + 3]; + } + else + { + v2 = s[i * 4 + 0]; + v3 = s[i * 4 + 1]; + v0 = s[i * 4 + 2]; + v1 = s[i * 4 + 3]; + } + + v0 = v0.shuffle8(m_r8mask); + v1 = v1.shuffle8(m_r8mask); + v2 = v2.shuffle8(m_r8mask); + v3 = v3.shuffle8(m_r8mask); + + GSVector4i::sw16(v0, v1, v2, v3); + GSVector4i::sw32(v0, v1, v3, v2); + + GSVector4i::store(&dst[dstpitch * 0], v0); + GSVector4i::store(&dst[dstpitch * 1], v3); + GSVector4i::store(&dst[dstpitch * 2], v1); + GSVector4i::store(&dst[dstpitch * 3], v2); + + #elif _M_SSE >= 0x200 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i v0 = s[i * 4 + 0]; + GSVector4i v1 = s[i * 4 + 1]; + GSVector4i v2 = s[i * 4 + 2]; + GSVector4i v3 = s[i * 4 + 3]; + + GSVector4i::sw8(v0, v1, v2, v3); + GSVector4i::sw16(v0, v1, v2, v3); + GSVector4i::sw8(v0, v2, v1, v3); + GSVector4i::sw64(v0, v1, v2, v3); + + if((i & 1) == 0) + { + v2 = v2.yxwz(); + v3 = v3.yxwz(); + } + else + { + v0 = v0.yxwz(); + v1 = v1.yxwz(); + } + + GSVector4i::store(&dst[dstpitch * 0], v0); + GSVector4i::store(&dst[dstpitch * 1], v1); + GSVector4i::store(&dst[dstpitch * 2], v2); + GSVector4i::store(&dst[dstpitch * 3], v3); + + #else + + const BYTE* s = &columnTable8[(i & 3) << 2][0]; + + for(int j = 0; j < 4; j++, s += 16, dst += dstpitch) + { + for(int i = 0; i < 16; i++) + { + dst[i] = src[s[i]]; + } + } + + #endif + } + + template __forceinline static void ReadColumn4(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) + { + #if _M_SSE >= 0x301 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i v0 = s[i * 4 + 0].xzyw(); + GSVector4i v1 = s[i * 4 + 1].xzyw(); + GSVector4i v2 = s[i * 4 + 2].xzyw(); + GSVector4i v3 = s[i * 4 + 3].xzyw(); + + GSVector4i::sw64(v0, v1, v2, v3); + GSVector4i::sw4(v0, v2, v1, v3); + GSVector4i::sw8(v0, v1, v2, v3); + + v0 = v0.shuffle8(m_r4mask); + v1 = v1.shuffle8(m_r4mask); + v2 = v2.shuffle8(m_r4mask); + v3 = v3.shuffle8(m_r4mask); + + if((i & 1) == 0) + { + GSVector4i::sw16rh(v0, v1, v2, v3); + } + else + { + GSVector4i::sw16rl(v0, v1, v2, v3); + } + + GSVector4i::store(&dst[dstpitch * 0], v0); + GSVector4i::store(&dst[dstpitch * 1], v1); + GSVector4i::store(&dst[dstpitch * 2], v2); + GSVector4i::store(&dst[dstpitch * 3], v3); + + #elif _M_SSE >= 0x200 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i v0 = s[i * 4 + 0]; + GSVector4i v1 = s[i * 4 + 1]; + GSVector4i v2 = s[i * 4 + 2]; + GSVector4i v3 = s[i * 4 + 3]; + + GSVector4i::sw32(v0, v1, v2, v3); + GSVector4i::sw32(v0, v1, v2, v3); + GSVector4i::sw4(v0, v2, v1, v3); + GSVector4i::sw8(v0, v1, v2, v3); + GSVector4i::sw16(v0, v2, v1, v3); + + v0 = v0.xzyw(); + v1 = v1.xzyw(); + v2 = v2.xzyw(); + v3 = v3.xzyw(); + + GSVector4i::sw64(v0, v1, v2, v3); + + if((i & 1) == 0) + { + v2 = v2.yxwzlh(); + v3 = v3.yxwzlh(); + } + else + { + v0 = v0.yxwzlh(); + v1 = v1.yxwzlh(); + } + + GSVector4i::store(&dst[dstpitch * 0], v0); + GSVector4i::store(&dst[dstpitch * 1], v1); + GSVector4i::store(&dst[dstpitch * 2], v2); + GSVector4i::store(&dst[dstpitch * 3], v3); + + #else + + const WORD* s = &columnTable4[(i & 3) << 2][0]; + + for(int j = 0; j < 4; j++, s += 32, dst += dstpitch) + { + for(int i = 0; i < 32; i++) + { + DWORD addr = s[i]; + BYTE c = (src[addr >> 1] >> ((addr & 1) << 2)) & 0x0f; + int shift = (i & 1) << 2; + dst[i >> 1] = (dst[i >> 1] & (0xf0 >> shift)) | (c << shift); + } + } + + #endif + } + + template static void ReadColumn32(int y, const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) + { + switch((y >> 1) & 3) + { + case 0: ReadColumn32<0, aligned>(src, dst, dstpitch); break; + case 1: ReadColumn32<1, aligned>(src, dst, dstpitch); break; + case 2: ReadColumn32<2, aligned>(src, dst, dstpitch); break; + case 3: ReadColumn32<3, aligned>(src, dst, dstpitch); break; + default: __assume(0); + } + } + + template static void ReadColumn16(int y, const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) + { + switch((y >> 1) & 3) + { + case 0: ReadColumn16<0, aligned>(src, dst, dstpitch); break; + case 1: ReadColumn16<1, aligned>(src, dst, dstpitch); break; + case 2: ReadColumn16<2, aligned>(src, dst, dstpitch); break; + case 3: ReadColumn16<3, aligned>(src, dst, dstpitch); break; + default: __assume(0); + } + } + + template static void ReadColumn8(int y, const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) + { + switch((y >> 2) & 3) + { + case 0: ReadColumn8<0, aligned>(src, dst, dstpitch); break; + case 1: ReadColumn8<1, aligned>(src, dst, dstpitch); break; + case 2: ReadColumn8<2, aligned>(src, dst, dstpitch); break; + case 3: ReadColumn8<3, aligned>(src, dst, dstpitch); break; + default: __assume(0); + } + } + + template static void ReadColumn4(int y, const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) + { + switch((y >> 2) & 3) + { + case 0: ReadColumn4<0, aligned>(src, dst, dstpitch); break; + case 1: ReadColumn4<1, aligned>(src, dst, dstpitch); break; + case 2: ReadColumn4<2, aligned>(src, dst, dstpitch); break; + case 3: ReadColumn4<3, aligned>(src, dst, dstpitch); break; + default: __assume(0); + } + } + + template static void ReadBlock32(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) + { + #if _M_SSE >= 0x200 + + ReadColumn32<0, aligned>(src, dst, dstpitch); + dst += dstpitch * 2; + ReadColumn32<1, aligned>(src, dst, dstpitch); + dst += dstpitch * 2; + ReadColumn32<2, aligned>(src, dst, dstpitch); + dst += dstpitch * 2; + ReadColumn32<3, aligned>(src, dst, dstpitch); + + #else + + const BYTE* s = &columnTable32[0][0]; + + for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) + { + for(int i = 0; i < 8; i++) + { + ((DWORD*)dst)[i] = ((DWORD*)src)[s[i]]; + } + } + + #endif + } + + template static void ReadBlock16(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) + { + #if _M_SSE >= 0x200 + + ReadColumn16<0, aligned>(src, dst, dstpitch); + dst += dstpitch * 2; + ReadColumn16<1, aligned>(src, dst, dstpitch); + dst += dstpitch * 2; + ReadColumn16<2, aligned>(src, dst, dstpitch); + dst += dstpitch * 2; + ReadColumn16<3, aligned>(src, dst, dstpitch); + + #else + + const BYTE* s = &columnTable16[0][0]; + + for(int j = 0; j < 8; j++, s += 16, dst += dstpitch) + { + for(int i = 0; i < 16; i++) + { + ((WORD*)dst)[i] = ((WORD*)src)[s[i]]; + } + } + + #endif + } + + template static void ReadBlock8(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) + { + #if _M_SSE >= 0x200 + + ReadColumn8<0, aligned>(src, dst, dstpitch); + dst += dstpitch * 4; + ReadColumn8<1, aligned>(src, dst, dstpitch); + dst += dstpitch * 4; + ReadColumn8<2, aligned>(src, dst, dstpitch); + dst += dstpitch * 4; + ReadColumn8<3, aligned>(src, dst, dstpitch); + + #else + + const BYTE* s = &columnTable8[0][0]; + + for(int j = 0; j < 16; j++, s += 16, dst += dstpitch) + { + for(int i = 0; i < 16; i++) + { + dst[i] = src[s[i]]; + } + } + + #endif + } + + template static void ReadBlock4(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) + { + #if _M_SSE >= 0x200 + + ReadColumn4<0, aligned>(src, dst, dstpitch); + dst += dstpitch * 4; + ReadColumn4<1, aligned>(src, dst, dstpitch); + dst += dstpitch * 4; + ReadColumn4<2, aligned>(src, dst, dstpitch); + dst += dstpitch * 4; + ReadColumn4<3, aligned>(src, dst, dstpitch); + + #else + + const WORD* s = &columnTable4[0][0]; + + for(int j = 0; j < 16; j++, s += 32, dst += dstpitch) + { + for(int i = 0; i < 32; i++) + { + DWORD addr = s[i]; + BYTE c = (src[addr >> 1] >> ((addr & 1) << 2)) & 0x0f; + int shift = (i & 1) << 2; + dst[i >> 1] = (dst[i >> 1] & (0xf0 >> shift)) | (c << shift); + } + } + + #endif + } + + __forceinline static void ReadBlock4P(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) + { + #if _M_SSE >= 0x200 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i v0, v1, v2, v3; + + GSVector4i mask(0x0f0f0f0f); + + for(int i = 0; i < 2; i++) + { + // col 0, 2 + + v0 = s[i * 8 + 0]; + v1 = s[i * 8 + 1]; + v2 = s[i * 8 + 2]; + v3 = s[i * 8 + 3]; + + GSVector4i::sw8(v0, v1, v2, v3); + GSVector4i::sw16(v0, v1, v2, v3); + GSVector4i::sw8(v0, v2, v1, v3); + + GSVector4i::store(&dst[dstpitch * 0 + 0], (v0 & mask)); + GSVector4i::store(&dst[dstpitch * 0 + 16], (v1 & mask)); + GSVector4i::store(&dst[dstpitch * 1 + 0], (v2 & mask)); + GSVector4i::store(&dst[dstpitch * 1 + 16], (v3 & mask)); + + dst += dstpitch * 2; + + GSVector4i::store(&dst[dstpitch * 0 + 0], (v0.andnot(mask)).yxwz() >> 4); + GSVector4i::store(&dst[dstpitch * 0 + 16], (v1.andnot(mask)).yxwz() >> 4); + GSVector4i::store(&dst[dstpitch * 1 + 0], (v2.andnot(mask)).yxwz() >> 4); + GSVector4i::store(&dst[dstpitch * 1 + 16], (v3.andnot(mask)).yxwz() >> 4); + + dst += dstpitch * 2; + + // col 1, 3 + + v0 = s[i * 8 + 4]; + v1 = s[i * 8 + 5]; + v2 = s[i * 8 + 6]; + v3 = s[i * 8 + 7]; + + GSVector4i::sw8(v0, v1, v2, v3); + GSVector4i::sw16(v0, v1, v2, v3); + GSVector4i::sw8(v0, v2, v1, v3); + + GSVector4i::store(&dst[dstpitch * 0 + 0], (v0 & mask).yxwz()); + GSVector4i::store(&dst[dstpitch * 0 + 16], (v1 & mask).yxwz()); + GSVector4i::store(&dst[dstpitch * 1 + 0], (v2 & mask).yxwz()); + GSVector4i::store(&dst[dstpitch * 1 + 16], (v3 & mask).yxwz()); + + dst += dstpitch * 2; + + GSVector4i::store(&dst[dstpitch * 0 + 0], (v0.andnot(mask)) >> 4); + GSVector4i::store(&dst[dstpitch * 0 + 16], (v1.andnot(mask)) >> 4); + GSVector4i::store(&dst[dstpitch * 1 + 0], (v2.andnot(mask)) >> 4); + GSVector4i::store(&dst[dstpitch * 1 + 16], (v3.andnot(mask)) >> 4); + + dst += dstpitch * 2; + } + + #else + + // TODO + + #endif + } + + __forceinline static void ReadBlock8HP(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) + { + #if _M_SSE >= 0x200 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i v0, v1, v2, v3; + + for(int i = 0; i < 4; i++) + { + v0 = s[i * 4 + 0]; + v1 = s[i * 4 + 1]; + v2 = s[i * 4 + 2]; + v3 = s[i * 4 + 3]; + + GSVector4i::sw64(v0, v1, v2, v3); + + v0 = ((v0 >> 24).ps32(v1 >> 24)).pu16((v2 >> 24).ps32(v3 >> 24)); + + GSVector4i::storel(dst, v0); + + dst += dstpitch; + + GSVector4i::storeh(dst, v0); + + dst += dstpitch; + } + + #else + + const BYTE* s = &columnTable32[0][0]; + + for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) + { + for(int i = 0; i < 8; i++) + { + ((BYTE*)dst)[i] = ((DWORD*)src)[s[i]] >> 24; + } + } + + #endif + } + + __forceinline static void ReadBlock4HLP(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) + { + #if _M_SSE >= 0x200 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i v0, v1, v2, v3; + + GSVector4i mask(0x0f0f0f0f); + + for(int i = 0; i < 4; i++) + { + v0 = s[i * 4 + 0]; + v1 = s[i * 4 + 1]; + v2 = s[i * 4 + 2]; + v3 = s[i * 4 + 3]; + + GSVector4i::sw64(v0, v1, v2, v3); + + v0 = ((v0 >> 24).ps32(v1 >> 24)).pu16((v2 >> 24).ps32(v3 >> 24)) & mask; + + GSVector4i::storel(dst, v0); + + dst += dstpitch; + + GSVector4i::storeh(dst, v0); + + dst += dstpitch; + } + + #else + + const BYTE* s = &columnTable32[0][0]; + + for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) + { + for(int i = 0; i < 8; i++) + { + ((BYTE*)dst)[i] = (((DWORD*)src)[s[i]] >> 24) & 0xf; + } + } + + #endif + } + + __forceinline static void ReadBlock4HHP(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch) + { + #if _M_SSE >= 0x200 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i v0, v1, v2, v3; + + for(int i = 0; i < 4; i++) + { + v0 = s[i * 4 + 0]; + v1 = s[i * 4 + 1]; + v2 = s[i * 4 + 2]; + v3 = s[i * 4 + 3]; + + GSVector4i::sw64(v0, v1, v2, v3); + + v0 = ((v0 >> 28).ps32(v1 >> 28)).pu16((v2 >> 28).ps32(v3 >> 28)); + + GSVector4i::storel(dst, v0); + + dst += dstpitch; + + GSVector4i::storeh(dst, v0); + + dst += dstpitch; + } + + #else + + const BYTE* s = &columnTable32[0][0]; + + for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) + { + for(int i = 0; i < 8; i++) + { + ((BYTE*)dst)[i] = ((DWORD*)src)[s[i]] >> 28; + } + } + + #endif + } + + static void UnpackBlock24(const BYTE* RESTRICT src, int srcpitch, DWORD* RESTRICT dst) + { + #if _M_SSE >= 0x200 + + GSVector4i mask = GSVector4i::x00ffffff(); + + for(int i = 0; i < 4; i++, src += srcpitch * 2) + { + GSVector4i v0 = GSVector4i::load(src); + GSVector4i v1 = GSVector4i::load(src + 16, src + srcpitch); + GSVector4i v2 = GSVector4i::load(src + srcpitch + 8); + + ((GSVector4i*)dst)[i * 4 + 0] = v0.upl32(v0.srl<3>()).upl64(v0.srl<6>().upl32(v0.srl<9>())) & mask; + + v0 = v0.srl<12>(v1); + + ((GSVector4i*)dst)[i * 4 + 1] = v0.upl32(v0.srl<3>()).upl64(v0.srl<6>().upl32(v0.srl<9>())) & mask; + + v0 = v1.srl<8>(v2); + + ((GSVector4i*)dst)[i * 4 + 2] = v0.upl32(v0.srl<3>()).upl64(v0.srl<6>().upl32(v0.srl<9>())) & mask; + + v0 = v2.srl<4>(); + + ((GSVector4i*)dst)[i * 4 + 3] = v0.upl32(v0.srl<3>()).upl64(v0.srl<6>().upl32(v0.srl<9>())) & mask; + } + + #else + + for(int j = 0, diff = srcpitch - 8 * 3; j < 8; j++, src += diff, dst += 8) + { + for(int i = 0; i < 8; i++, src += 3) + { + dst[i] = (src[2] << 16) | (src[1] << 8) | src[0]; + } + } + + #endif + } + + static void UnpackBlock8H(const BYTE* RESTRICT src, int srcpitch, DWORD* RESTRICT dst) + { + #if _M_SSE >= 0x200 + + GSVector4i zero = GSVector4i::zero(); + + for(int i = 0; i < 4; i++, src += srcpitch * 2) + { + GSVector4i v = GSVector4i::load(src, src + srcpitch); + + GSVector4i v0 = zero.upl8(v); + GSVector4i v1 = zero.uph8(v); + + ((GSVector4i*)dst)[i * 4 + 0] = zero.upl16(v0); + ((GSVector4i*)dst)[i * 4 + 1] = zero.uph16(v0); + ((GSVector4i*)dst)[i * 4 + 2] = zero.upl16(v1); + ((GSVector4i*)dst)[i * 4 + 3] = zero.uph16(v1); + } + + #else + + for(int j = 0; j < 8; j++, src += srcpitch, dst += 8) + { + for(int i = 0; i < 8; i++) + { + dst[i] = src[i] << 24; + } + } + + #endif + } + + static void UnpackBlock4HL(const BYTE* RESTRICT src, int srcpitch, DWORD* RESTRICT dst) + { + #if _M_SSE >= 0x200 + + GSVector4i zero = GSVector4i::zero(); + GSVector4i mask(0x0f0f0f0f); + + for(int i = 0; i < 2; i++, src += srcpitch * 4) + { + GSVector4i v( + *(DWORD*)&src[srcpitch * 0], + *(DWORD*)&src[srcpitch * 1], + *(DWORD*)&src[srcpitch * 2], + *(DWORD*)&src[srcpitch * 3]); + + GSVector4i lo = v & mask; + GSVector4i hi = (v >> 4) & mask; + + GSVector4i v0 = lo.upl8(hi); + GSVector4i v1 = lo.uph8(hi); + + GSVector4i v2 = zero.upl8(v0); + GSVector4i v3 = zero.uph8(v0); + GSVector4i v4 = zero.upl8(v1); + GSVector4i v5 = zero.uph8(v1); + + ((GSVector4i*)dst)[i * 8 + 0] = zero.upl16(v2); + ((GSVector4i*)dst)[i * 8 + 1] = zero.uph16(v2); + ((GSVector4i*)dst)[i * 8 + 2] = zero.upl16(v3); + ((GSVector4i*)dst)[i * 8 + 3] = zero.uph16(v3); + ((GSVector4i*)dst)[i * 8 + 4] = zero.upl16(v4); + ((GSVector4i*)dst)[i * 8 + 5] = zero.uph16(v4); + ((GSVector4i*)dst)[i * 8 + 6] = zero.upl16(v5); + ((GSVector4i*)dst)[i * 8 + 7] = zero.uph16(v5); + } + + #else + + for(int j = 0; j < 8; j++, src += srcpitch, dst += 8) + { + for(int i = 0; i < 4; i++) + { + dst[i * 2 + 0] = (src[i] & 0x0f) << 24; + dst[i * 2 + 1] = (src[i] & 0xf0) << 20; + } + } + + #endif + } + + static void UnpackBlock4HH(const BYTE* RESTRICT src, int srcpitch, DWORD* RESTRICT dst) + { + #if _M_SSE >= 0x200 + + GSVector4i zero = GSVector4i::zero(); + GSVector4i mask(0xf0f0f0f0); + + for(int i = 0; i < 2; i++, src += srcpitch * 4) + { + GSVector4i v( + *(DWORD*)&src[srcpitch * 0], + *(DWORD*)&src[srcpitch * 1], + *(DWORD*)&src[srcpitch * 2], + *(DWORD*)&src[srcpitch * 3]); + + GSVector4i lo = (v << 4) & mask; + GSVector4i hi = v & mask; + + GSVector4i v0 = lo.upl8(hi); + GSVector4i v1 = lo.uph8(hi); + + GSVector4i v2 = zero.upl8(v0); + GSVector4i v3 = zero.uph8(v0); + GSVector4i v4 = zero.upl8(v1); + GSVector4i v5 = zero.uph8(v1); + + ((GSVector4i*)dst)[i * 8 + 0] = zero.upl16(v2); + ((GSVector4i*)dst)[i * 8 + 1] = zero.uph16(v2); + ((GSVector4i*)dst)[i * 8 + 2] = zero.upl16(v3); + ((GSVector4i*)dst)[i * 8 + 3] = zero.uph16(v3); + ((GSVector4i*)dst)[i * 8 + 4] = zero.upl16(v4); + ((GSVector4i*)dst)[i * 8 + 5] = zero.uph16(v4); + ((GSVector4i*)dst)[i * 8 + 6] = zero.upl16(v5); + ((GSVector4i*)dst)[i * 8 + 7] = zero.uph16(v5); + } + + #else + + for(int j = 0; j < 8; j++, src += srcpitch, dst += 8) + { + for(int i = 0; i < 4; i++) + { + dst[i * 2 + 0] = (src[i] & 0x0f) << 28; + dst[i * 2 + 1] = (src[i] & 0xf0) << 24; + } + } + + #endif + } + + template static void ExpandBlock24(const DWORD* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const GIFRegTEXA& TEXA) + { + #if _M_SSE >= 0x200 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i TA0(TEXA.TA0 << 24); + GSVector4i mask = GSVector4i::x00ffffff(); + + for(int i = 0; i < 4; i++, dst += dstpitch * 2) + { + GSVector4i v0 = s[i * 4 + 0] & mask; + GSVector4i v1 = s[i * 4 + 1] & mask; + GSVector4i v2 = s[i * 4 + 2] & mask; + GSVector4i v3 = s[i * 4 + 3] & mask; + + GSVector4i* d0 = (GSVector4i*)&dst[dstpitch * 0]; + GSVector4i* d1 = (GSVector4i*)&dst[dstpitch * 1]; + + if(AEM) + { + d0[0] = v0 | TA0.andnot(v0 == GSVector4i::zero()); // TA0 & (v0 != GSVector4i::zero()) + d0[1] = v1 | TA0.andnot(v1 == GSVector4i::zero()); // TA0 & (v1 != GSVector4i::zero()) + d1[0] = v2 | TA0.andnot(v2 == GSVector4i::zero()); // TA0 & (v2 != GSVector4i::zero()) + d1[1] = v3 | TA0.andnot(v3 == GSVector4i::zero()); // TA0 & (v3 != GSVector4i::zero()) + } + else + { + d0[0] = v0 | TA0; + d0[1] = v1 | TA0; + d1[0] = v2 | TA0; + d1[1] = v3 | TA0; + } + } + + #else + + DWORD TA0 = TEXA.TA0 << 24; + + for(int j = 0; j < 8; j++, src += 8, dst += dstpitch) + { + for(int i = 0; i < 8; i++) + { + DWORD c = src[i] & 0xffffff; + + if(AEM) + { + ((DWORD*)dst)[i] = c | (c ? TA0 : 0); + } + else + { + ((DWORD*)dst)[i] = c | TA0; + } + } + } + + #endif + } + + static void ExpandBlock16(const WORD* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const GIFRegTEXA& TEXA) // do not inline, uses too many xmm regs + { + #if _M_SSE >= 0x200 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i TA0(TEXA.TA0 << 24); + GSVector4i TA1(TEXA.TA1 << 24); + GSVector4i rm = m_rxxx; + GSVector4i gm = m_xgxx; + GSVector4i bm = m_xxbx; + // GSVector4i am = m_xxxa; + GSVector4i l, h; + + if(TEXA.AEM) + { + for(int i = 0; i < 8; i++, dst += dstpitch) + { + GSVector4i v0 = s[i * 2 + 0]; +/* + l = v0.upl16(); + h = v0.uph16(); + + ((GSVector4i*)dst)[0] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | TA1.blend(TA0, l < am).andnot(l == GSVector4i::zero()); + ((GSVector4i*)dst)[1] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | TA1.blend(TA0, h < am).andnot(h == GSVector4i::zero()); +*/ + l = v0.upl16(v0); + h = v0.uph16(v0); + + ((GSVector4i*)dst)[0] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | TA0.blend8(TA1, l.sra16(15)).andnot(l == GSVector4i::zero()); + ((GSVector4i*)dst)[1] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | TA0.blend8(TA1, h.sra16(15)).andnot(h == GSVector4i::zero()); + + GSVector4i v1 = s[i * 2 + 1]; +/* + l = v1.upl16(); + h = v1.uph16(); + + ((GSVector4i*)dst)[2] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | TA1.blend(TA0, l < am).andnot(l == GSVector4i::zero()); + ((GSVector4i*)dst)[3] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | TA1.blend(TA0, h < am).andnot(h == GSVector4i::zero()); +*/ + l = v1.upl16(v1); + h = v1.uph16(v1); + + ((GSVector4i*)dst)[2] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | TA0.blend8(TA1, l.sra16(15)).andnot(l == GSVector4i::zero()); + ((GSVector4i*)dst)[3] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | TA0.blend8(TA1, h.sra16(15)).andnot(h == GSVector4i::zero()); + } + } + else + { + for(int i = 0; i < 8; i++, dst += dstpitch) + { + GSVector4i v0 = s[i * 2 + 0]; +/* + l = v0.upl16(); + h = v0.uph16(); + + ((GSVector4i*)dst)[0] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | TA1.blend(TA0, l < am); + ((GSVector4i*)dst)[1] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | TA1.blend(TA0, h < am); +*/ + l = v0.upl16(v0); + h = v0.uph16(v0); + + ((GSVector4i*)dst)[0] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | TA0.blend(TA1, l.sra16(15)); + ((GSVector4i*)dst)[1] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | TA0.blend(TA1, h.sra16(15)); + + GSVector4i v1 = s[i * 2 + 1]; +/* + l = v1.upl16(); + h = v1.uph16(); + + ((GSVector4i*)dst)[2] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | TA1.blend(TA0, l < am); + ((GSVector4i*)dst)[3] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | TA1.blend(TA0, h < am); +*/ + l = v1.upl16(v1); + h = v1.uph16(v1); + + ((GSVector4i*)dst)[2] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | TA0.blend(TA1, l.sra16(15)); + ((GSVector4i*)dst)[3] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | TA0.blend(TA1, h.sra16(15)); + } + } + + #else + + DWORD TA0 = TEXA.TA0 << 24; + DWORD TA1 = TEXA.TA1 << 24; + + if(TEXA.AEM) + { + for(int j = 0; j < 8; j++, src += 16, dst += dstpitch) + { + for(int i = 0; i < 16; i++) + { + ((DWORD*)dst)[i] = ((src[i] & 0x8000) ? TA1 : src[i] ? TA0 : 0) | ((src[i] & 0x7c00) << 9) | ((src[i] & 0x03e0) << 6) | ((src[i] & 0x001f) << 3); + } + } + } + else + { + for(int j = 0; j < 8; j++, src += 16, dst += dstpitch) + { + for(int i = 0; i < 16; i++) + { + ((DWORD*)dst)[i] = ((src[i] & 0x8000) ? TA1 : TA0) | ((src[i] & 0x7c00) << 9) | ((src[i] & 0x03e0) << 6) | ((src[i] & 0x001f) << 3); + } + } + } + + #endif + } + + __forceinline static void ExpandBlock8_32(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) + { + for(int j = 0; j < 16; j++, dst += dstpitch) + { + ((const GSVector4i*)src)[j].gather32_8(pal, (GSVector4i*)dst); + } + } + + __forceinline static void ExpandBlock8_16(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) + { + for(int j = 0; j < 16; j++, dst += dstpitch) + { + ((const GSVector4i*)src)[j].gather16_8(pal, (GSVector4i*)dst); + } + } + + __forceinline static void ExpandBlock4_32(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const UINT64* RESTRICT pal) + { + for(int j = 0; j < 16; j++, dst += dstpitch) + { + ((const GSVector4i*)src)[j].gather64_8(pal, (GSVector4i*)dst); + } + } + + __forceinline static void ExpandBlock4_16(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const UINT64* RESTRICT pal) + { + for(int j = 0; j < 16; j++, dst += dstpitch) + { + ((const GSVector4i*)src)[j].gather32_8(pal, (GSVector4i*)dst); + } + } + + __forceinline static void ExpandBlock8H_32(DWORD* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) + { + for(int j = 0; j < 8; j++, dst += dstpitch) + { + const GSVector4i* s = (const GSVector4i*)src; + + ((GSVector4i*)dst)[0] = (s[j * 2 + 0] >> 24).gather32_32<>(pal); + ((GSVector4i*)dst)[1] = (s[j * 2 + 1] >> 24).gather32_32<>(pal); + } + } + + __forceinline static void ExpandBlock8H_16(DWORD* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) + { + for(int j = 0; j < 8; j++, dst += dstpitch) + { + #if _M_SSE >= 0x401 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i v0 = (s[j * 2 + 0] >> 24).gather32_32<>(pal); + GSVector4i v1 = (s[j * 2 + 1] >> 24).gather32_32<>(pal); + + ((GSVector4i*)dst)[0] = v0.pu32(v1); + + #else + + for(int i = 0; i < 8; i++) + { + ((WORD*)dst)[i] = (WORD)pal[src[j * 8 + i] >> 24]; + } + + #endif + } + } + + __forceinline static void ExpandBlock4HL_32(DWORD* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) + { + for(int j = 0; j < 8; j++, dst += dstpitch) + { + const GSVector4i* s = (const GSVector4i*)src; + + ((GSVector4i*)dst)[0] = ((s[j * 2 + 0] >> 24) & 0xf).gather32_32<>(pal); + ((GSVector4i*)dst)[1] = ((s[j * 2 + 1] >> 24) & 0xf).gather32_32<>(pal); + } + } + + __forceinline static void ExpandBlock4HL_16(DWORD* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) + { + for(int j = 0; j < 8; j++, dst += dstpitch) + { + #if _M_SSE >= 0x401 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i v0 = ((s[j * 2 + 0] >> 24) & 0xf).gather32_32<>(pal); + GSVector4i v1 = ((s[j * 2 + 1] >> 24) & 0xf).gather32_32<>(pal); + + ((GSVector4i*)dst)[0] = v0.pu32(v1); + + #else + + for(int i = 0; i < 8; i++) + { + ((WORD*)dst)[i] = (WORD)pal[(src[j * 8 + i] >> 24) & 0xf]; + } + + #endif + } + } + + __forceinline static void ExpandBlock4HH_32(DWORD* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) + { + for(int j = 0; j < 8; j++, dst += dstpitch) + { + const GSVector4i* s = (const GSVector4i*)src; + + ((GSVector4i*)dst)[0] = (s[j * 2 + 0] >> 28).gather32_32<>(pal); + ((GSVector4i*)dst)[1] = (s[j * 2 + 1] >> 28).gather32_32<>(pal); + } + } + + __forceinline static void ExpandBlock4HH_16(DWORD* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) + { + for(int j = 0; j < 8; j++, dst += dstpitch) + { + #if _M_SSE >= 0x401 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i v0 = (s[j * 2 + 0] >> 28).gather32_32<>(pal); + GSVector4i v1 = (s[j * 2 + 1] >> 28).gather32_32<>(pal); + + ((GSVector4i*)dst)[0] = v0.pu32(v1); + + #else + + for(int i = 0; i < 8; i++) + { + ((WORD*)dst)[i] = (WORD)pal[src[j * 8 + i] >> 28]; + } + + #endif + } + } + + __forceinline static void UnpackAndWriteBlock24(const BYTE* RESTRICT src, int srcpitch, BYTE* RESTRICT dst) + { + #if _M_SSE >= 0x200 + + GSVector4i mask(0x00ffffff); + + for(int i = 0; i < 4; i++, src += srcpitch * 2) + { + GSVector4i v4 = GSVector4i::load(src); + GSVector4i v5 = GSVector4i::load(src + 16, src + srcpitch); + GSVector4i v6 = GSVector4i::load(src + srcpitch + 8); + + GSVector4i v0 = v4.upl32(v4.srl<3>()).upl64(v4.srl<6>().upl32(v4.srl<9>())); + + v4 = v4.srl<12>(v5); + + GSVector4i v1 = v4.upl32(v4.srl<3>()).upl64(v4.srl<6>().upl32(v4.srl<9>())); + + v4 = v5.srl<8>(v6); + + GSVector4i v2 = v4.upl32(v4.srl<3>()).upl64(v4.srl<6>().upl32(v4.srl<9>())); + + v4 = v6.srl<4>(); + + GSVector4i v3 = v4.upl32(v4.srl<3>()).upl64(v4.srl<6>().upl32(v4.srl<9>())); + + GSVector4i::sw64(v0, v2, v1, v3); + + #ifdef _M_AMD64 + + ((GSVector4i*)dst)[i * 4 + 0] = ((GSVector4i*)dst)[i * 4 + 0].blend8(v0, mask); + ((GSVector4i*)dst)[i * 4 + 1] = ((GSVector4i*)dst)[i * 4 + 1].blend8(v1, mask); + ((GSVector4i*)dst)[i * 4 + 2] = ((GSVector4i*)dst)[i * 4 + 2].blend8(v2, mask); + ((GSVector4i*)dst)[i * 4 + 3] = ((GSVector4i*)dst)[i * 4 + 3].blend8(v3, mask); + + #else + + // here blend is faster than blend8 because vc8 has a little problem optimizing register usage for pblendvb (3rd op must be xmm0) + + ((GSVector4i*)dst)[i * 4 + 0] = ((GSVector4i*)dst)[i * 4 + 0].blend(v0, mask); + ((GSVector4i*)dst)[i * 4 + 1] = ((GSVector4i*)dst)[i * 4 + 1].blend(v1, mask); + ((GSVector4i*)dst)[i * 4 + 2] = ((GSVector4i*)dst)[i * 4 + 2].blend(v2, mask); + ((GSVector4i*)dst)[i * 4 + 3] = ((GSVector4i*)dst)[i * 4 + 3].blend(v3, mask); + + #endif + } + + #else + + const BYTE* d = &columnTable32[0][0]; + + for(int j = 0, diff = srcpitch - 8 * 3; j < 8; j++, src += diff, d += 8) + { + for(int i = 0; i < 8; i++, src += 3) + { + ((DWORD*)dst)[d[i]] = (((DWORD*)dst)[d[i]] & ~0x00ffffff) | (src[2] << 16) | (src[1] << 8) | src[0]; + } + } + + #endif + } + + __forceinline static void UnpackAndWriteBlock8H(const BYTE* RESTRICT src, int srcpitch, BYTE* RESTRICT dst) + { + #if _M_SSE >= 0x301 + + GSVector4i mask(0xff000000); + + GSVector4i mask0 = m_uw8hmask0; + GSVector4i mask1 = m_uw8hmask1; + GSVector4i mask2 = m_uw8hmask2; + GSVector4i mask3 = m_uw8hmask3; + + for(int i = 0; i < 4; i++, src += srcpitch * 2) + { + GSVector4i v4 = GSVector4i::load(src, src + srcpitch); + + GSVector4i v0 = v4.shuffle8(mask0); + GSVector4i v1 = v4.shuffle8(mask1); + GSVector4i v2 = v4.shuffle8(mask2); + GSVector4i v3 = v4.shuffle8(mask3); + + ((GSVector4i*)dst)[i * 4 + 0] = ((GSVector4i*)dst)[i * 4 + 0].blend8(v0, mask); + ((GSVector4i*)dst)[i * 4 + 1] = ((GSVector4i*)dst)[i * 4 + 1].blend8(v1, mask); + ((GSVector4i*)dst)[i * 4 + 2] = ((GSVector4i*)dst)[i * 4 + 2].blend8(v2, mask); + ((GSVector4i*)dst)[i * 4 + 3] = ((GSVector4i*)dst)[i * 4 + 3].blend8(v3, mask); + } + + #elif _M_SSE >= 0x200 + + GSVector4i mask(0xff000000); + + for(int i = 0; i < 4; i++, src += srcpitch * 2) + { + GSVector4i v4 = GSVector4i::load(src, src + srcpitch); + + GSVector4i v5 = v4.upl8(v4); + GSVector4i v6 = v4.uph8(v4); + + GSVector4i v0 = v5.upl16(v5); + GSVector4i v1 = v5.uph16(v5); + GSVector4i v2 = v6.upl16(v6); + GSVector4i v3 = v6.uph16(v6); + + GSVector4i::sw64(v0, v2, v1, v3); + + ((GSVector4i*)dst)[i * 4 + 0] = ((GSVector4i*)dst)[i * 4 + 0].blend8(v0, mask); + ((GSVector4i*)dst)[i * 4 + 1] = ((GSVector4i*)dst)[i * 4 + 1].blend8(v1, mask); + ((GSVector4i*)dst)[i * 4 + 2] = ((GSVector4i*)dst)[i * 4 + 2].blend8(v2, mask); + ((GSVector4i*)dst)[i * 4 + 3] = ((GSVector4i*)dst)[i * 4 + 3].blend8(v3, mask); + } + + #else + + const BYTE* d = &columnTable32[0][0]; + + for(int j = 0; j < 8; j++, src += srcpitch, dst += 8) + { + for(int i = 0; i < 8; i++) + { + ((DWORD*)dst)[d[i]] = (((DWORD*)dst)[d[i]] & ~0xff000000) | (src[i] << 24); + } + } + + #endif + } + + __forceinline static void UnpackAndWriteBlock4HL(const BYTE* RESTRICT src, int srcpitch, BYTE* RESTRICT dst) + { + #if _M_SSE >= 0x301 + + GSVector4i mask(0x0f0f0f0f); + GSVector4i mask0 = m_uw8hmask0; + GSVector4i mask1 = m_uw8hmask1; + GSVector4i mask2 = m_uw8hmask2; + GSVector4i mask3 = m_uw8hmask3; + GSVector4i mask4(0x0f000000); + + for(int i = 0; i < 2; i++, src += srcpitch * 4) + { + GSVector4i v( + *(DWORD*)&src[srcpitch * 0], + *(DWORD*)&src[srcpitch * 1], + *(DWORD*)&src[srcpitch * 2], + *(DWORD*)&src[srcpitch * 3]); + + GSVector4i lo = v & mask; + GSVector4i hi = (v >> 4) & mask; + + { + GSVector4i v4 = lo.upl8(hi); + + GSVector4i v0 = v4.shuffle8(mask0); + GSVector4i v1 = v4.shuffle8(mask1); + GSVector4i v2 = v4.shuffle8(mask2); + GSVector4i v3 = v4.shuffle8(mask3); + + ((GSVector4i*)dst)[i * 8 + 0] = ((GSVector4i*)dst)[i * 8 + 0].blend(v0, mask4); + ((GSVector4i*)dst)[i * 8 + 1] = ((GSVector4i*)dst)[i * 8 + 1].blend(v1, mask4); + ((GSVector4i*)dst)[i * 8 + 2] = ((GSVector4i*)dst)[i * 8 + 2].blend(v2, mask4); + ((GSVector4i*)dst)[i * 8 + 3] = ((GSVector4i*)dst)[i * 8 + 3].blend(v3, mask4); + } + + { + GSVector4i v4 = lo.uph8(hi); + + GSVector4i v0 = v4.shuffle8(mask0); + GSVector4i v1 = v4.shuffle8(mask1); + GSVector4i v2 = v4.shuffle8(mask2); + GSVector4i v3 = v4.shuffle8(mask3); + + ((GSVector4i*)dst)[i * 8 + 4] = ((GSVector4i*)dst)[i * 8 + 4].blend(v0, mask4); + ((GSVector4i*)dst)[i * 8 + 5] = ((GSVector4i*)dst)[i * 8 + 5].blend(v1, mask4); + ((GSVector4i*)dst)[i * 8 + 6] = ((GSVector4i*)dst)[i * 8 + 6].blend(v2, mask4); + ((GSVector4i*)dst)[i * 8 + 7] = ((GSVector4i*)dst)[i * 8 + 7].blend(v3, mask4); + } + } + + #elif _M_SSE >= 0x200 +/* + __declspec(align(16)) DWORD block[8 * 8]; + + UnpackBlock4HL(src, srcpitch, block); + + WriteBlock32(dst, (BYTE*)block, sizeof(block) / 8); +*/ + GSVector4i mask(0x0f0f0f0f); + GSVector4i mask2(0x0f000000); + + for(int i = 0; i < 2; i++, src += srcpitch * 4) + { + GSVector4i v( + *(DWORD*)&src[srcpitch * 0], + *(DWORD*)&src[srcpitch * 1], + *(DWORD*)&src[srcpitch * 2], + *(DWORD*)&src[srcpitch * 3]); + + GSVector4i lo = v & mask; + GSVector4i hi = (v >> 4) & mask; + + { + GSVector4i v4 = lo.upl8(hi); + + GSVector4i v5 = v4.upl8(v4); + GSVector4i v6 = v4.uph8(v4); + + GSVector4i v0 = v5.upl16(v5); + GSVector4i v1 = v5.uph16(v5); + GSVector4i v2 = v6.upl16(v6); + GSVector4i v3 = v6.uph16(v6); + + GSVector4i::sw64(v0, v2, v1, v3); + + ((GSVector4i*)dst)[i * 8 + 0] = ((GSVector4i*)dst)[i * 8 + 0].blend(v0, mask2); + ((GSVector4i*)dst)[i * 8 + 1] = ((GSVector4i*)dst)[i * 8 + 1].blend(v1, mask2); + ((GSVector4i*)dst)[i * 8 + 2] = ((GSVector4i*)dst)[i * 8 + 2].blend(v2, mask2); + ((GSVector4i*)dst)[i * 8 + 3] = ((GSVector4i*)dst)[i * 8 + 3].blend(v3, mask2); + } + + { + GSVector4i v4 = lo.uph8(hi); + + GSVector4i v5 = v4.upl8(v4); + GSVector4i v6 = v4.uph8(v4); + + GSVector4i v0 = v5.upl16(v5); + GSVector4i v1 = v5.uph16(v5); + GSVector4i v2 = v6.upl16(v6); + GSVector4i v3 = v6.uph16(v6); + + GSVector4i::sw64(v0, v2, v1, v3); + + ((GSVector4i*)dst)[i * 8 + 4] = ((GSVector4i*)dst)[i * 8 + 4].blend(v0, mask2); + ((GSVector4i*)dst)[i * 8 + 5] = ((GSVector4i*)dst)[i * 8 + 5].blend(v1, mask2); + ((GSVector4i*)dst)[i * 8 + 6] = ((GSVector4i*)dst)[i * 8 + 6].blend(v2, mask2); + ((GSVector4i*)dst)[i * 8 + 7] = ((GSVector4i*)dst)[i * 8 + 7].blend(v3, mask2); + } + } + + #else + + const BYTE* d = &columnTable32[0][0]; + + for(int j = 0; j < 8; j++, d += 8, src += srcpitch) + { + for(int i = 0; i < 4; i++) + { + ((DWORD*)dst)[d[i * 2 + 0]] = (((DWORD*)dst)[d[i * 2 + 0]] & ~0x0f000000) | ((src[i] & 0x0f) << 24); + ((DWORD*)dst)[d[i * 2 + 1]] = (((DWORD*)dst)[d[i * 2 + 1]] & ~0x0f000000) | ((src[i] & 0xf0) << 20); + } + } + + #endif + } + + __forceinline static void UnpackAndWriteBlock4HH(const BYTE* RESTRICT src, int srcpitch, BYTE* RESTRICT dst) + { + #if _M_SSE >= 0x301 + + GSVector4i mask(0xf0f0f0f0); + GSVector4i mask0 = m_uw8hmask0; + GSVector4i mask1 = m_uw8hmask1; + GSVector4i mask2 = m_uw8hmask2; + GSVector4i mask3 = m_uw8hmask3; + GSVector4i mask4(0xf0000000); + + for(int i = 0; i < 2; i++, src += srcpitch * 4) + { + GSVector4i v( + *(DWORD*)&src[srcpitch * 0], + *(DWORD*)&src[srcpitch * 1], + *(DWORD*)&src[srcpitch * 2], + *(DWORD*)&src[srcpitch * 3]); + + GSVector4i lo = (v << 4) & mask; + GSVector4i hi = v & mask; + + { + GSVector4i v4 = lo.upl8(hi); + + GSVector4i v0 = v4.shuffle8(mask0); + GSVector4i v1 = v4.shuffle8(mask1); + GSVector4i v2 = v4.shuffle8(mask2); + GSVector4i v3 = v4.shuffle8(mask3); + + ((GSVector4i*)dst)[i * 8 + 0] = ((GSVector4i*)dst)[i * 8 + 0].blend(v0, mask4); + ((GSVector4i*)dst)[i * 8 + 1] = ((GSVector4i*)dst)[i * 8 + 1].blend(v1, mask4); + ((GSVector4i*)dst)[i * 8 + 2] = ((GSVector4i*)dst)[i * 8 + 2].blend(v2, mask4); + ((GSVector4i*)dst)[i * 8 + 3] = ((GSVector4i*)dst)[i * 8 + 3].blend(v3, mask4); + } + + { + GSVector4i v4 = lo.uph8(hi); + + GSVector4i v0 = v4.shuffle8(mask0); + GSVector4i v1 = v4.shuffle8(mask1); + GSVector4i v2 = v4.shuffle8(mask2); + GSVector4i v3 = v4.shuffle8(mask3); + + ((GSVector4i*)dst)[i * 8 + 4] = ((GSVector4i*)dst)[i * 8 + 4].blend(v0, mask4); + ((GSVector4i*)dst)[i * 8 + 5] = ((GSVector4i*)dst)[i * 8 + 5].blend(v1, mask4); + ((GSVector4i*)dst)[i * 8 + 6] = ((GSVector4i*)dst)[i * 8 + 6].blend(v2, mask4); + ((GSVector4i*)dst)[i * 8 + 7] = ((GSVector4i*)dst)[i * 8 + 7].blend(v3, mask4); + } + } + + #elif _M_SSE >= 0x200 +/* + __declspec(align(16)) DWORD block[8 * 8]; + + UnpackBlock4HH(src, srcpitch, block); + + WriteBlock32(dst, (BYTE*)block, sizeof(block) / 8); +*/ + GSVector4i mask(0xf0f0f0f0); + GSVector4i mask2(0xf0000000); + + for(int i = 0; i < 2; i++, src += srcpitch * 4) + { + GSVector4i v( + *(DWORD*)&src[srcpitch * 0], + *(DWORD*)&src[srcpitch * 1], + *(DWORD*)&src[srcpitch * 2], + *(DWORD*)&src[srcpitch * 3]); + + GSVector4i lo = (v << 4) & mask; + GSVector4i hi = v & mask; + + { + GSVector4i v4 = lo.upl8(hi); + + GSVector4i v5 = v4.upl8(v4); + GSVector4i v6 = v4.uph8(v4); + + GSVector4i v0 = v5.upl16(v5); + GSVector4i v1 = v5.uph16(v5); + GSVector4i v2 = v6.upl16(v6); + GSVector4i v3 = v6.uph16(v6); + + GSVector4i::sw64(v0, v2, v1, v3); + + ((GSVector4i*)dst)[i * 8 + 0] = ((GSVector4i*)dst)[i * 8 + 0].blend(v0, mask2); + ((GSVector4i*)dst)[i * 8 + 1] = ((GSVector4i*)dst)[i * 8 + 1].blend(v1, mask2); + ((GSVector4i*)dst)[i * 8 + 2] = ((GSVector4i*)dst)[i * 8 + 2].blend(v2, mask2); + ((GSVector4i*)dst)[i * 8 + 3] = ((GSVector4i*)dst)[i * 8 + 3].blend(v3, mask2); + } + + { + GSVector4i v4 = lo.uph8(hi); + + GSVector4i v5 = v4.upl8(v4); + GSVector4i v6 = v4.uph8(v4); + + GSVector4i v0 = v5.upl16(v5); + GSVector4i v1 = v5.uph16(v5); + GSVector4i v2 = v6.upl16(v6); + GSVector4i v3 = v6.uph16(v6); + + GSVector4i::sw64(v0, v2, v1, v3); + + ((GSVector4i*)dst)[i * 8 + 4] = ((GSVector4i*)dst)[i * 8 + 4].blend(v0, mask2); + ((GSVector4i*)dst)[i * 8 + 5] = ((GSVector4i*)dst)[i * 8 + 5].blend(v1, mask2); + ((GSVector4i*)dst)[i * 8 + 6] = ((GSVector4i*)dst)[i * 8 + 6].blend(v2, mask2); + ((GSVector4i*)dst)[i * 8 + 7] = ((GSVector4i*)dst)[i * 8 + 7].blend(v3, mask2); + } + } + + #else + + const BYTE* d = &columnTable32[0][0]; + + for(int j = 0; j < 8; j++, d += 8, src += srcpitch) + { + for(int i = 0; i < 4; i++) + { + ((DWORD*)dst)[d[i * 2 + 0]] = (((DWORD*)dst)[d[i * 2 + 0]] & ~0xf0000000) | ((src[i] & 0x0f) << 28); + ((DWORD*)dst)[d[i * 2 + 1]] = (((DWORD*)dst)[d[i * 2 + 1]] & ~0xf0000000) | ((src[i] & 0xf0) << 24); + } + } + + #endif + } + + template __forceinline static void ReadAndExpandBlock24(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const GIFRegTEXA& TEXA) + { + #if _M_SSE >= 0x200 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i TA0(TEXA.TA0 << 24); + GSVector4i mask = GSVector4i::x00ffffff(); + + for(int i = 0; i < 4; i++, dst += dstpitch * 2) + { + GSVector4i v0 = s[i * 4 + 0]; + GSVector4i v1 = s[i * 4 + 1]; + GSVector4i v2 = s[i * 4 + 2]; + GSVector4i v3 = s[i * 4 + 3]; + + GSVector4i::sw64(v0, v1, v2, v3); + + v0 &= mask; + v1 &= mask; + v2 &= mask; + v3 &= mask; + + GSVector4i* d0 = (GSVector4i*)&dst[dstpitch * 0]; + GSVector4i* d1 = (GSVector4i*)&dst[dstpitch * 1]; + + if(AEM) + { + d0[0] = v0 | TA0.andnot(v0 == GSVector4i::zero()); // TA0 & (v0 != GSVector4i::zero()) + d0[1] = v1 | TA0.andnot(v1 == GSVector4i::zero()); // TA0 & (v1 != GSVector4i::zero()) + d1[0] = v2 | TA0.andnot(v2 == GSVector4i::zero()); // TA0 & (v2 != GSVector4i::zero()) + d1[1] = v3 | TA0.andnot(v3 == GSVector4i::zero()); // TA0 & (v3 != GSVector4i::zero()) + } + else + { + d0[0] = v0 | TA0; + d0[1] = v1 | TA0; + d1[0] = v2 | TA0; + d1[1] = v3 | TA0; + } + } + + #else + + DWORD TA0 = TEXA.TA0 << 24; + + const BYTE* s = &columnTable32[0][0]; + + for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) + { + for(int i = 0; i < 8; i++) + { + DWORD c = ((DWORD*)src)[s[i]] & 0xffffff; + + if(AEM) + { + ((DWORD*)dst)[i] = c | (c ? TA0 : 0); + } + else + { + ((DWORD*)dst)[i] = c | TA0; + } + } + } + + #endif + } + + __forceinline static void ReadAndExpandBlock8_32(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) + { + #if _M_SSE >= 0x401 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i v0, v1, v2, v3; + GSVector4i mask = m_r8mask; + + for(int i = 0; i < 2; i++) + { + v0 = s[i * 8 + 0].shuffle8(mask); + v1 = s[i * 8 + 1].shuffle8(mask); + v2 = s[i * 8 + 2].shuffle8(mask); + v3 = s[i * 8 + 3].shuffle8(mask); + + GSVector4i::sw16(v0, v1, v2, v3); + GSVector4i::sw32(v0, v1, v3, v2); + + v0.gather32_8<>(pal, (GSVector4i*)dst); + dst += dstpitch; + v3.gather32_8<>(pal, (GSVector4i*)dst); + dst += dstpitch; + v1.gather32_8<>(pal, (GSVector4i*)dst); + dst += dstpitch; + v2.gather32_8<>(pal, (GSVector4i*)dst); + dst += dstpitch; + + v2 = s[i * 8 + 4].shuffle8(mask); + v3 = s[i * 8 + 5].shuffle8(mask); + v0 = s[i * 8 + 6].shuffle8(mask); + v1 = s[i * 8 + 7].shuffle8(mask); + + GSVector4i::sw16(v0, v1, v2, v3); + GSVector4i::sw32(v0, v1, v3, v2); + + v0.gather32_8<>(pal, (GSVector4i*)dst); + dst += dstpitch; + v3.gather32_8<>(pal, (GSVector4i*)dst); + dst += dstpitch; + v1.gather32_8<>(pal, (GSVector4i*)dst); + dst += dstpitch; + v2.gather32_8<>(pal, (GSVector4i*)dst); + dst += dstpitch; + } + + #elif _M_SSE >= 0x200 + + __declspec(align(16)) BYTE block[16 * 16]; + + ReadBlock8(src, (BYTE*)block, sizeof(block) / 16); + + ExpandBlock8_32(block, dst, dstpitch, pal); + + #else + + const BYTE* s = &columnTable8[0][0]; + + for(int j = 0; j < 16; j++, s += 16, dst += dstpitch) + { + for(int i = 0; i < 16; i++) + { + ((DWORD*)dst)[i] = pal[src[s[i]]]; + } + } + + #endif + } + + // TODO: ReadAndExpandBlock8_16 + + __forceinline static void ReadAndExpandBlock4_32(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const UINT64* RESTRICT pal) + { + #if _M_SSE >= 0x401 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i v0, v1, v2, v3; + GSVector4i mask = m_r4mask; + + for(int i = 0; i < 2; i++) + { + v0 = s[i * 8 + 0].xzyw(); + v1 = s[i * 8 + 1].xzyw(); + v2 = s[i * 8 + 2].xzyw(); + v3 = s[i * 8 + 3].xzyw(); + + GSVector4i::sw64(v0, v1, v2, v3); + GSVector4i::sw4(v0, v2, v1, v3); + GSVector4i::sw8(v0, v1, v2, v3); + + v0 = v0.shuffle8(mask); + v1 = v1.shuffle8(mask); + v2 = v2.shuffle8(mask); + v3 = v3.shuffle8(mask); + + GSVector4i::sw16rh(v0, v1, v2, v3); + + v0.gather64_8<>(pal, (GSVector4i*)dst); + dst += dstpitch; + v1.gather64_8<>(pal, (GSVector4i*)dst); + dst += dstpitch; + v2.gather64_8<>(pal, (GSVector4i*)dst); + dst += dstpitch; + v3.gather64_8<>(pal, (GSVector4i*)dst); + dst += dstpitch; + + v0 = s[i * 8 + 4].xzyw(); + v1 = s[i * 8 + 5].xzyw(); + v2 = s[i * 8 + 6].xzyw(); + v3 = s[i * 8 + 7].xzyw(); + + GSVector4i::sw64(v0, v1, v2, v3); + GSVector4i::sw4(v0, v2, v1, v3); + GSVector4i::sw8(v0, v1, v2, v3); + + v0 = v0.shuffle8(mask); + v1 = v1.shuffle8(mask); + v2 = v2.shuffle8(mask); + v3 = v3.shuffle8(mask); + + GSVector4i::sw16rl(v0, v1, v2, v3); + + v0.gather64_8<>(pal, (GSVector4i*)dst); + dst += dstpitch; + v1.gather64_8<>(pal, (GSVector4i*)dst); + dst += dstpitch; + v2.gather64_8<>(pal, (GSVector4i*)dst); + dst += dstpitch; + v3.gather64_8<>(pal, (GSVector4i*)dst); + dst += dstpitch; + } + + #elif _M_SSE >= 0x200 + + __declspec(align(16)) BYTE block[(32 / 2) * 16]; + + ReadBlock4(src, (BYTE*)block, sizeof(block) / 16); + + ExpandBlock4_32(block, dst, dstpitch, pal); + + #else + + const WORD* s = &columnTable4[0][0]; + + for(int j = 0; j < 16; j++, s += 32, dst += dstpitch) + { + for(int i = 0; i < 16; i++) + { + BYTE a0 = s[i * 2 + 0]; + BYTE a1 = s[i * 2 + 1]; + + BYTE c0 = (src[a0 >> 1] >> ((a0 & 1) << 2)) & 0x0f; + BYTE c1 = (src[a1 >> 1] >> ((a1 & 1) << 2)) & 0x0f; + + ((UINT64*)dst)[i] = pal[(c1 << 4) | c0]; + } + } + + #endif + } + + // TODO: ReadAndExpandBlock4_16 + + __forceinline static void ReadAndExpandBlock8H_32(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) + { + #if _M_SSE >= 0x401 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i v0, v1, v2, v3; + + for(int i = 0; i < 4; i++) + { + v0 = s[i * 4 + 0]; + v1 = s[i * 4 + 1]; + v2 = s[i * 4 + 2]; + v3 = s[i * 4 + 3]; + + GSVector4i::sw64(v0, v1, v2, v3); + + (v0 >> 24).gather32_32<>(pal, (GSVector4i*)&dst[0]); + (v1 >> 24).gather32_32<>(pal, (GSVector4i*)&dst[16]); + + dst += dstpitch; + + (v2 >> 24).gather32_32<>(pal, (GSVector4i*)&dst[0]); + (v3 >> 24).gather32_32<>(pal, (GSVector4i*)&dst[16]); + + dst += dstpitch; + } + + #elif _M_SSE >= 0x200 + + __declspec(align(16)) DWORD block[8 * 8]; + + ReadBlock32(src, (BYTE*)block, sizeof(block) / 8); + + ExpandBlock8H_32(block, dst, dstpitch, pal); + + #else + + const BYTE* s = &columnTable32[0][0]; + + for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) + { + for(int i = 0; i < 8; i++) + { + ((DWORD*)dst)[i] = pal[((DWORD*)src)[s[i]] >> 24]; + } + } + + #endif + } + + // TODO: ReadAndExpandBlock8H_16 + + __forceinline static void ReadAndExpandBlock4HL_32(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) + { + #if _M_SSE >= 0x401 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i v0, v1, v2, v3; + + for(int i = 0; i < 4; i++) + { + v0 = s[i * 4 + 0]; + v1 = s[i * 4 + 1]; + v2 = s[i * 4 + 2]; + v3 = s[i * 4 + 3]; + + GSVector4i::sw64(v0, v1, v2, v3); + + ((v0 >> 24) & 0xf).gather32_32<>(pal, (GSVector4i*)&dst[0]); + ((v1 >> 24) & 0xf).gather32_32<>(pal, (GSVector4i*)&dst[16]); + + dst += dstpitch; + + ((v2 >> 24) & 0xf).gather32_32<>(pal, (GSVector4i*)&dst[0]); + ((v3 >> 24) & 0xf).gather32_32<>(pal, (GSVector4i*)&dst[16]); + + dst += dstpitch; + } + + #elif _M_SSE >= 0x200 + + __declspec(align(16)) DWORD block[8 * 8]; + + ReadBlock32(src, (BYTE*)block, sizeof(block) / 8); + + ExpandBlock4HL_32(block, dst, dstpitch, pal); + + #else + + const BYTE* s = &columnTable32[0][0]; + + for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) + { + for(int i = 0; i < 8; i++) + { + ((DWORD*)dst)[i] = pal[(((DWORD*)src)[s[i]] >> 24) & 0xf]; + } + } + + #endif + } + + // TODO: ReadAndExpandBlock4HL_16 + + __forceinline static void ReadAndExpandBlock4HH_32(const BYTE* RESTRICT src, BYTE* RESTRICT dst, int dstpitch, const DWORD* RESTRICT pal) + { + #if _M_SSE >= 0x401 + + const GSVector4i* s = (const GSVector4i*)src; + + GSVector4i v0, v1, v2, v3; + + for(int i = 0; i < 4; i++) + { + v0 = s[i * 4 + 0]; + v1 = s[i * 4 + 1]; + v2 = s[i * 4 + 2]; + v3 = s[i * 4 + 3]; + + GSVector4i::sw64(v0, v1, v2, v3); + + (v0 >> 28).gather32_32<>(pal, (GSVector4i*)&dst[0]); + (v1 >> 28).gather32_32<>(pal, (GSVector4i*)&dst[16]); + + dst += dstpitch; + + (v2 >> 28).gather32_32<>(pal, (GSVector4i*)&dst[0]); + (v3 >> 28).gather32_32<>(pal, (GSVector4i*)&dst[16]); + + dst += dstpitch; + } + + #elif _M_SSE >= 0x200 + + __declspec(align(16)) DWORD block[8 * 8]; + + ReadBlock32(src, (BYTE*)block, sizeof(block) / 8); + + ExpandBlock4HH_32(block, dst, dstpitch, pal); + + #else + + const BYTE* s = &columnTable32[0][0]; + + for(int j = 0; j < 8; j++, s += 8, dst += dstpitch) + { + for(int i = 0; i < 8; i++) + { + ((DWORD*)dst)[i] = pal[((DWORD*)src)[s[i]] >> 28]; + } + } + + #endif + } + + // TODO: ReadAndExpandBlock4HH_16 +}; diff --git a/plugins/GSdx/GSCapture.cpp b/plugins/GSdx/GSCapture.cpp index 75249b468d..bd1ccca41e 100644 --- a/plugins/GSdx/GSCapture.cpp +++ b/plugins/GSdx/GSCapture.cpp @@ -1,539 +1,539 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSCapture.h" -#include "GSVector.h" - -// -// GSSource -// - -#ifdef __INTEL_COMPILER -interface __declspec(uuid("59C193BB-C520-41F3-BC1D-E245B80A86FA")) -#else -[uuid("59C193BB-C520-41F3-BC1D-E245B80A86FA")] interface -#endif -IGSSource : public IUnknown -{ - STDMETHOD(DeliverNewSegment)() PURE; - STDMETHOD(DeliverFrame)(const void* bits, int pitch, bool rgba) PURE; - STDMETHOD(DeliverEOS)() PURE; -}; - -#ifdef __INTEL_COMPILER -class __declspec(uuid("F8BB6F4F-0965-4ED4-BA74-C6A01E6E6C77")) -#else -[uuid("F8BB6F4F-0965-4ED4-BA74-C6A01E6E6C77")] class -#endif -GSSource : public CBaseFilter, private CCritSec, public IGSSource -{ - CSize m_size; - REFERENCE_TIME m_atpf; - REFERENCE_TIME m_now; - - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) - { - return - QI(IGSSource) - __super::NonDelegatingQueryInterface(riid, ppv); - } - - class GSSourceOutputPin : public CBaseOutputPin - { - CSize m_size; - CAtlArray m_mts; - - public: - GSSourceOutputPin(CSize size, REFERENCE_TIME atpf, CBaseFilter* pFilter, CCritSec* pLock, HRESULT& hr) - : CBaseOutputPin("GSSourceOutputPin", pFilter, pLock, &hr, L"Output") - , m_size(size) - { - CMediaType mt; - mt.majortype = MEDIATYPE_Video; - mt.formattype = FORMAT_VideoInfo; - - VIDEOINFOHEADER vih; - memset(&vih, 0, sizeof(vih)); - vih.AvgTimePerFrame = atpf; - vih.bmiHeader.biSize = sizeof(vih.bmiHeader); - vih.bmiHeader.biWidth = m_size.cx; - vih.bmiHeader.biHeight = m_size.cy; - - #if _M_SSE >= 0x200 - - // YUY2 - - mt.subtype = MEDIASUBTYPE_YUY2; - mt.lSampleSize = m_size.cx * m_size.cy * 2; - - vih.bmiHeader.biCompression = '2YUY'; - vih.bmiHeader.biPlanes = 1; - vih.bmiHeader.biBitCount = 16; - vih.bmiHeader.biSizeImage = m_size.cx * m_size.cy * 2; - mt.SetFormat((BYTE*)&vih, sizeof(vih)); - - m_mts.Add(mt); - - #endif - - // RGB32 - - mt.subtype = MEDIASUBTYPE_RGB32; - mt.lSampleSize = m_size.cx * m_size.cy * 4; - - vih.bmiHeader.biCompression = BI_RGB; - vih.bmiHeader.biPlanes = 1; - vih.bmiHeader.biBitCount = 32; - vih.bmiHeader.biSizeImage = m_size.cx * m_size.cy * 4; - mt.SetFormat((BYTE*)&vih, sizeof(vih)); - - m_mts.Add(mt); - } - - HRESULT GSSourceOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) - { - ASSERT(pAlloc && pProperties); - - HRESULT hr; - - pProperties->cBuffers = 1; - pProperties->cbBuffer = m_mt.lSampleSize; - - ALLOCATOR_PROPERTIES Actual; - - if(FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) - { - return hr; - } - - if(Actual.cbBuffer < pProperties->cbBuffer) - { - return E_FAIL; - } - - ASSERT(Actual.cBuffers == pProperties->cBuffers); - - return S_OK; - } - - HRESULT CheckMediaType(const CMediaType* pmt) - { - for(int i = 0, j = m_mts.GetCount(); i < j; i++) - { - if(m_mts[i].majortype == pmt->majortype && m_mts[i].subtype == pmt->subtype) - { - return S_OK; - } - } - - return E_FAIL; - } - - HRESULT GetMediaType(int i, CMediaType* pmt) - { - CheckPointer(pmt, E_POINTER); - - if(i < 0) return E_INVALIDARG; - if(i > 1) return VFW_S_NO_MORE_ITEMS; - - *pmt = m_mts[i]; - - return S_OK; - } - - STDMETHODIMP Notify(IBaseFilter* pSender, Quality q) - { - return E_NOTIMPL; - } - - const CMediaType& CurrentMediaType() - { - return m_mt; - } - }; - - CAutoPtr m_output; - -public: - - GSSource(int w, int h, int fps, IUnknown* pUnk, HRESULT& hr) - : CBaseFilter(NAME("GSSource"), pUnk, this, __uuidof(this), &hr) - , m_output(NULL) - , m_size(w, h) - , m_atpf(10000000i64 / fps) - , m_now(0) - { - m_output.Attach(new GSSourceOutputPin(m_size, m_atpf, this, this, hr)); - - // FIXME - if(fps == 60) m_atpf = 166834; // = 10000000i64 / 59.94 - } - - DECLARE_IUNKNOWN; - - int GetPinCount() - { - return 1; - } - - CBasePin* GetPin(int n) - { - return n == 0 ? m_output.m_p : NULL; - } - - // IGSSource - - STDMETHODIMP DeliverNewSegment() - { - m_now = 0; - - return m_output->DeliverNewSegment(0, _I64_MAX, 1.0); - } - - STDMETHODIMP DeliverFrame(const void* bits, int pitch, bool rgba) - { - if(!m_output || !m_output->IsConnected()) - { - return E_UNEXPECTED; - } - - CComPtr sample; - - if(FAILED(m_output->GetDeliveryBuffer(&sample, NULL, NULL, 0))) - { - return E_FAIL; - } - - REFERENCE_TIME start = m_now; - REFERENCE_TIME stop = m_now + m_atpf; - - sample->SetTime(&start, &stop); - sample->SetSyncPoint(TRUE); - - const CMediaType& mt = m_output->CurrentMediaType(); - - BYTE* src = (BYTE*)bits; - - BYTE* dst = NULL; - sample->GetPointer(&dst); - - int w = m_size.cx; - int h = m_size.cy; - int srcpitch = pitch; - - #if _M_SSE >= 0x200 - - if(mt.subtype == MEDIASUBTYPE_YUY2) - { - int dstpitch = ((VIDEOINFOHEADER*)mt.Format())->bmiHeader.biWidth * 2; - - const GSVector4 ys(0.098f, 0.504f, 0.257f, 0.0f); - const GSVector4 us(0.439f / 2, -0.291f / 2, -0.148f / 2, 0.0f); - const GSVector4 vs(-0.071f / 2, -0.368f / 2, 0.439f / 2, 0.0f); - const GSVector4 offset(16, 128, 16, 128); - - if(rgba) - { - for(int j = 0; j < h; j++, dst += dstpitch, src += srcpitch) - { - DWORD* s = (DWORD*)src; - WORD* d = (WORD*)dst; - - for(int i = 0; i < w; i += 2) - { - GSVector4 c0 = GSVector4(s[i + 0]); - GSVector4 c1 = GSVector4(s[i + 1]); - GSVector4 c2 = c0 + c1; - - GSVector4 lo = (c0 * ys).hadd(c2 * vs); - GSVector4 hi = (c1 * ys).hadd(c2 * us); - - GSVector4 c = lo.hadd(hi) + offset; - - *((DWORD*)&d[i]) = GSVector4i(c).rgba32(); - } - } - } - else - { - for(int j = 0; j < h; j++, dst += dstpitch, src += srcpitch) - { - DWORD* s = (DWORD*)src; - WORD* d = (WORD*)dst; - - for(int i = 0; i < w; i += 2) - { - GSVector4 c0 = GSVector4(s[i + 0]).zyxw(); - GSVector4 c1 = GSVector4(s[i + 1]).zyxw(); - GSVector4 c2 = c0 + c1; - - GSVector4 lo = (c0 * ys).hadd(c2 * vs); - GSVector4 hi = (c1 * ys).hadd(c2 * us); - - GSVector4 c = lo.hadd(hi) + offset; - - *((DWORD*)&d[i]) = GSVector4i(c).rgba32(); - } - } - } - } - else - - #endif - - if(mt.subtype == MEDIASUBTYPE_RGB32) - { - int dstpitch = ((VIDEOINFOHEADER*)mt.Format())->bmiHeader.biWidth * 4; - - dst += dstpitch * (h - 1); - dstpitch = -dstpitch; - - for(int j = 0; j < h; j++, dst += dstpitch, src += srcpitch) - { - if(rgba) - { - #if _M_SSE >= 0x301 - - GSVector4i* s = (GSVector4i*)src; - GSVector4i* d = (GSVector4i*)dst; - - GSVector4i mask(2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15); - - for(int i = 0, w4 = w >> 2; i < w4; i++) - { - d[i] = s[i].shuffle8(mask); - } - - #elif _M_SSE >= 0x200 - - GSVector4i* s = (GSVector4i*)src; - GSVector4i* d = (GSVector4i*)dst; - - for(int i = 0, w4 = w >> 2; i < w4; i++) - { - d[i] = ((s[i] & 0x00ff0000) >> 16) | ((s[i] & 0x000000ff) << 16) | (s[i] & 0x0000ff00); - } - - #else - - DWORD* s = (DWORD*)src; - DWORD* d = (DWORD*)dst; - - for(int i = 0; i < w; i++) - { - d[i] = ((s[i] & 0x00ff0000) >> 16) | ((s[i] & 0x000000ff) << 16) | (s[i] & 0x0000ff00); - } - - #endif - } - else - { - memcpy(dst, src, w * 4); - } - } - } - else - { - return E_FAIL; - } - - if(FAILED(m_output->Deliver(sample))) - { - return E_FAIL; - } - - m_now = stop; - - return S_OK; - } - - STDMETHODIMP DeliverEOS() - { - return m_output->DeliverEndOfStream(); - } -}; - -// -// GSCapture -// - -GSCapture::GSCapture() - : m_capturing(false) -{ -} - -GSCapture::~GSCapture() -{ - EndCapture(); -} - -#define BeginEnumPins(pBaseFilter, pEnumPins, pPin) \ - {CComPtr pEnumPins; \ - if(pBaseFilter && SUCCEEDED(pBaseFilter->EnumPins(&pEnumPins))) \ - { \ - for(CComPtr pPin; S_OK == pEnumPins->Next(1, &pPin, 0); pPin = NULL) \ - { \ - -#define EndEnumPins }}} - -static IPin* GetFirstPin(IBaseFilter* pBF, PIN_DIRECTION dir) -{ - if(!pBF) return(NULL); - - BeginEnumPins(pBF, pEP, pPin) - { - PIN_DIRECTION dir2; - pPin->QueryDirection(&dir2); - if(dir == dir2) - { - IPin* pRet = pPin.Detach(); - pRet->Release(); - return(pRet); - } - } - EndEnumPins - - return(NULL); -} - -bool GSCapture::BeginCapture(int fps) -{ - CAutoLock cAutoLock(this); - - ASSERT(fps != 0); - - EndCapture(); - - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - GSCaptureDlg dlg; - - if(IDOK != dlg.DoModal()) return false; - - m_size.cx = (dlg.m_width + 7) & ~7; - m_size.cy = (dlg.m_height + 7) & ~7; - - // - - HRESULT hr; - - CComPtr cgb; - CComPtr mux; - - if(FAILED(hr = m_graph.CoCreateInstance(CLSID_FilterGraph)) - || FAILED(hr = cgb.CoCreateInstance(CLSID_CaptureGraphBuilder2)) - || FAILED(hr = cgb->SetFiltergraph(m_graph)) - || FAILED(hr = cgb->SetOutputFileName(&MEDIASUBTYPE_Avi, CStringW(dlg.m_filename), &mux, NULL))) - { - return false; - } - - m_src = new GSSource(m_size.cx, m_size.cy, fps, NULL, hr); - - if(FAILED(hr = m_graph->AddFilter(m_src, L"Source")) - || FAILED(hr = m_graph->AddFilter(dlg.m_enc, L"Encoder"))) - { - return false; - } - - if(FAILED(hr = m_graph->ConnectDirect(GetFirstPin(m_src, PINDIR_OUTPUT), GetFirstPin(dlg.m_enc, PINDIR_INPUT), NULL)) - || FAILED(hr = m_graph->ConnectDirect(GetFirstPin(dlg.m_enc, PINDIR_OUTPUT), GetFirstPin(mux, PINDIR_INPUT), NULL))) - { - return false; - } - - BeginEnumFilters(m_graph, pEF, pBF) - { - CFilterInfo fi; - pBF->QueryFilterInfo(&fi); - printf("Filter [%p]: %s\n", pBF.p, CStringA(fi.achName)); - - BeginEnumPins(pBF, pEP, pPin) - { - CComPtr pPinTo; - pPin->ConnectedTo(&pPinTo); - - CPinInfo pi; - pPin->QueryPinInfo(&pi); - printf("- Pin [%p - %p]: %s (%s)\n", pPin.p, pPinTo.p, CStringA(pi.achName), pi.dir ? "out" : "in"); - - BeginEnumMediaTypes(pPin, pEMT, pmt) - { - } - EndEnumMediaTypes(pmt) - } - EndEnumPins - } - EndEnumFilters - - hr = CComQIPtr(m_graph)->Run(); - - CComQIPtr(m_src)->DeliverNewSegment(); - - m_capturing = true; - - return true; -} - -bool GSCapture::DeliverFrame(const void* bits, int pitch, bool rgba) -{ - CAutoLock cAutoLock(this); - - if(bits == NULL || pitch == 0) - { - ASSERT(0); - - return false; - } - - if(m_src) - { - CComQIPtr(m_src)->DeliverFrame(bits, pitch, rgba); - - return true; - } - - return false; -} - -bool GSCapture::EndCapture() -{ - CAutoLock cAutoLock(this); - - if(m_src) - { - CComQIPtr(m_src)->DeliverEOS(); - - m_src = NULL; - } - - if(m_graph) - { - CComQIPtr(m_graph)->Stop(); - - m_graph = NULL; - } - - m_capturing = false; - - return true; -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSCapture.h" +#include "GSVector.h" + +// +// GSSource +// + +#ifdef __INTEL_COMPILER +interface __declspec(uuid("59C193BB-C520-41F3-BC1D-E245B80A86FA")) +#else +[uuid("59C193BB-C520-41F3-BC1D-E245B80A86FA")] interface +#endif +IGSSource : public IUnknown +{ + STDMETHOD(DeliverNewSegment)() PURE; + STDMETHOD(DeliverFrame)(const void* bits, int pitch, bool rgba) PURE; + STDMETHOD(DeliverEOS)() PURE; +}; + +#ifdef __INTEL_COMPILER +class __declspec(uuid("F8BB6F4F-0965-4ED4-BA74-C6A01E6E6C77")) +#else +[uuid("F8BB6F4F-0965-4ED4-BA74-C6A01E6E6C77")] class +#endif +GSSource : public CBaseFilter, private CCritSec, public IGSSource +{ + CSize m_size; + REFERENCE_TIME m_atpf; + REFERENCE_TIME m_now; + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) + { + return + QI(IGSSource) + __super::NonDelegatingQueryInterface(riid, ppv); + } + + class GSSourceOutputPin : public CBaseOutputPin + { + CSize m_size; + CAtlArray m_mts; + + public: + GSSourceOutputPin(CSize size, REFERENCE_TIME atpf, CBaseFilter* pFilter, CCritSec* pLock, HRESULT& hr) + : CBaseOutputPin("GSSourceOutputPin", pFilter, pLock, &hr, L"Output") + , m_size(size) + { + CMediaType mt; + mt.majortype = MEDIATYPE_Video; + mt.formattype = FORMAT_VideoInfo; + + VIDEOINFOHEADER vih; + memset(&vih, 0, sizeof(vih)); + vih.AvgTimePerFrame = atpf; + vih.bmiHeader.biSize = sizeof(vih.bmiHeader); + vih.bmiHeader.biWidth = m_size.cx; + vih.bmiHeader.biHeight = m_size.cy; + + #if _M_SSE >= 0x200 + + // YUY2 + + mt.subtype = MEDIASUBTYPE_YUY2; + mt.lSampleSize = m_size.cx * m_size.cy * 2; + + vih.bmiHeader.biCompression = '2YUY'; + vih.bmiHeader.biPlanes = 1; + vih.bmiHeader.biBitCount = 16; + vih.bmiHeader.biSizeImage = m_size.cx * m_size.cy * 2; + mt.SetFormat((BYTE*)&vih, sizeof(vih)); + + m_mts.Add(mt); + + #endif + + // RGB32 + + mt.subtype = MEDIASUBTYPE_RGB32; + mt.lSampleSize = m_size.cx * m_size.cy * 4; + + vih.bmiHeader.biCompression = BI_RGB; + vih.bmiHeader.biPlanes = 1; + vih.bmiHeader.biBitCount = 32; + vih.bmiHeader.biSizeImage = m_size.cx * m_size.cy * 4; + mt.SetFormat((BYTE*)&vih, sizeof(vih)); + + m_mts.Add(mt); + } + + HRESULT GSSourceOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) + { + ASSERT(pAlloc && pProperties); + + HRESULT hr; + + pProperties->cBuffers = 1; + pProperties->cbBuffer = m_mt.lSampleSize; + + ALLOCATOR_PROPERTIES Actual; + + if(FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) + { + return hr; + } + + if(Actual.cbBuffer < pProperties->cbBuffer) + { + return E_FAIL; + } + + ASSERT(Actual.cBuffers == pProperties->cBuffers); + + return S_OK; + } + + HRESULT CheckMediaType(const CMediaType* pmt) + { + for(int i = 0, j = m_mts.GetCount(); i < j; i++) + { + if(m_mts[i].majortype == pmt->majortype && m_mts[i].subtype == pmt->subtype) + { + return S_OK; + } + } + + return E_FAIL; + } + + HRESULT GetMediaType(int i, CMediaType* pmt) + { + CheckPointer(pmt, E_POINTER); + + if(i < 0) return E_INVALIDARG; + if(i > 1) return VFW_S_NO_MORE_ITEMS; + + *pmt = m_mts[i]; + + return S_OK; + } + + STDMETHODIMP Notify(IBaseFilter* pSender, Quality q) + { + return E_NOTIMPL; + } + + const CMediaType& CurrentMediaType() + { + return m_mt; + } + }; + + CAutoPtr m_output; + +public: + + GSSource(int w, int h, int fps, IUnknown* pUnk, HRESULT& hr) + : CBaseFilter(NAME("GSSource"), pUnk, this, __uuidof(this), &hr) + , m_output(NULL) + , m_size(w, h) + , m_atpf(10000000i64 / fps) + , m_now(0) + { + m_output.Attach(new GSSourceOutputPin(m_size, m_atpf, this, this, hr)); + + // FIXME + if(fps == 60) m_atpf = 166834; // = 10000000i64 / 59.94 + } + + DECLARE_IUNKNOWN; + + int GetPinCount() + { + return 1; + } + + CBasePin* GetPin(int n) + { + return n == 0 ? m_output.m_p : NULL; + } + + // IGSSource + + STDMETHODIMP DeliverNewSegment() + { + m_now = 0; + + return m_output->DeliverNewSegment(0, _I64_MAX, 1.0); + } + + STDMETHODIMP DeliverFrame(const void* bits, int pitch, bool rgba) + { + if(!m_output || !m_output->IsConnected()) + { + return E_UNEXPECTED; + } + + CComPtr sample; + + if(FAILED(m_output->GetDeliveryBuffer(&sample, NULL, NULL, 0))) + { + return E_FAIL; + } + + REFERENCE_TIME start = m_now; + REFERENCE_TIME stop = m_now + m_atpf; + + sample->SetTime(&start, &stop); + sample->SetSyncPoint(TRUE); + + const CMediaType& mt = m_output->CurrentMediaType(); + + BYTE* src = (BYTE*)bits; + + BYTE* dst = NULL; + sample->GetPointer(&dst); + + int w = m_size.cx; + int h = m_size.cy; + int srcpitch = pitch; + + #if _M_SSE >= 0x200 + + if(mt.subtype == MEDIASUBTYPE_YUY2) + { + int dstpitch = ((VIDEOINFOHEADER*)mt.Format())->bmiHeader.biWidth * 2; + + const GSVector4 ys(0.098f, 0.504f, 0.257f, 0.0f); + const GSVector4 us(0.439f / 2, -0.291f / 2, -0.148f / 2, 0.0f); + const GSVector4 vs(-0.071f / 2, -0.368f / 2, 0.439f / 2, 0.0f); + const GSVector4 offset(16, 128, 16, 128); + + if(rgba) + { + for(int j = 0; j < h; j++, dst += dstpitch, src += srcpitch) + { + DWORD* s = (DWORD*)src; + WORD* d = (WORD*)dst; + + for(int i = 0; i < w; i += 2) + { + GSVector4 c0 = GSVector4(s[i + 0]); + GSVector4 c1 = GSVector4(s[i + 1]); + GSVector4 c2 = c0 + c1; + + GSVector4 lo = (c0 * ys).hadd(c2 * vs); + GSVector4 hi = (c1 * ys).hadd(c2 * us); + + GSVector4 c = lo.hadd(hi) + offset; + + *((DWORD*)&d[i]) = GSVector4i(c).rgba32(); + } + } + } + else + { + for(int j = 0; j < h; j++, dst += dstpitch, src += srcpitch) + { + DWORD* s = (DWORD*)src; + WORD* d = (WORD*)dst; + + for(int i = 0; i < w; i += 2) + { + GSVector4 c0 = GSVector4(s[i + 0]).zyxw(); + GSVector4 c1 = GSVector4(s[i + 1]).zyxw(); + GSVector4 c2 = c0 + c1; + + GSVector4 lo = (c0 * ys).hadd(c2 * vs); + GSVector4 hi = (c1 * ys).hadd(c2 * us); + + GSVector4 c = lo.hadd(hi) + offset; + + *((DWORD*)&d[i]) = GSVector4i(c).rgba32(); + } + } + } + } + else + + #endif + + if(mt.subtype == MEDIASUBTYPE_RGB32) + { + int dstpitch = ((VIDEOINFOHEADER*)mt.Format())->bmiHeader.biWidth * 4; + + dst += dstpitch * (h - 1); + dstpitch = -dstpitch; + + for(int j = 0; j < h; j++, dst += dstpitch, src += srcpitch) + { + if(rgba) + { + #if _M_SSE >= 0x301 + + GSVector4i* s = (GSVector4i*)src; + GSVector4i* d = (GSVector4i*)dst; + + GSVector4i mask(2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15); + + for(int i = 0, w4 = w >> 2; i < w4; i++) + { + d[i] = s[i].shuffle8(mask); + } + + #elif _M_SSE >= 0x200 + + GSVector4i* s = (GSVector4i*)src; + GSVector4i* d = (GSVector4i*)dst; + + for(int i = 0, w4 = w >> 2; i < w4; i++) + { + d[i] = ((s[i] & 0x00ff0000) >> 16) | ((s[i] & 0x000000ff) << 16) | (s[i] & 0x0000ff00); + } + + #else + + DWORD* s = (DWORD*)src; + DWORD* d = (DWORD*)dst; + + for(int i = 0; i < w; i++) + { + d[i] = ((s[i] & 0x00ff0000) >> 16) | ((s[i] & 0x000000ff) << 16) | (s[i] & 0x0000ff00); + } + + #endif + } + else + { + memcpy(dst, src, w * 4); + } + } + } + else + { + return E_FAIL; + } + + if(FAILED(m_output->Deliver(sample))) + { + return E_FAIL; + } + + m_now = stop; + + return S_OK; + } + + STDMETHODIMP DeliverEOS() + { + return m_output->DeliverEndOfStream(); + } +}; + +// +// GSCapture +// + +GSCapture::GSCapture() + : m_capturing(false) +{ +} + +GSCapture::~GSCapture() +{ + EndCapture(); +} + +#define BeginEnumPins(pBaseFilter, pEnumPins, pPin) \ + {CComPtr pEnumPins; \ + if(pBaseFilter && SUCCEEDED(pBaseFilter->EnumPins(&pEnumPins))) \ + { \ + for(CComPtr pPin; S_OK == pEnumPins->Next(1, &pPin, 0); pPin = NULL) \ + { \ + +#define EndEnumPins }}} + +static IPin* GetFirstPin(IBaseFilter* pBF, PIN_DIRECTION dir) +{ + if(!pBF) return(NULL); + + BeginEnumPins(pBF, pEP, pPin) + { + PIN_DIRECTION dir2; + pPin->QueryDirection(&dir2); + if(dir == dir2) + { + IPin* pRet = pPin.Detach(); + pRet->Release(); + return(pRet); + } + } + EndEnumPins + + return(NULL); +} + +bool GSCapture::BeginCapture(int fps) +{ + CAutoLock cAutoLock(this); + + ASSERT(fps != 0); + + EndCapture(); + + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + GSCaptureDlg dlg; + + if(IDOK != dlg.DoModal()) return false; + + m_size.cx = (dlg.m_width + 7) & ~7; + m_size.cy = (dlg.m_height + 7) & ~7; + + // + + HRESULT hr; + + CComPtr cgb; + CComPtr mux; + + if(FAILED(hr = m_graph.CoCreateInstance(CLSID_FilterGraph)) + || FAILED(hr = cgb.CoCreateInstance(CLSID_CaptureGraphBuilder2)) + || FAILED(hr = cgb->SetFiltergraph(m_graph)) + || FAILED(hr = cgb->SetOutputFileName(&MEDIASUBTYPE_Avi, CStringW(dlg.m_filename), &mux, NULL))) + { + return false; + } + + m_src = new GSSource(m_size.cx, m_size.cy, fps, NULL, hr); + + if(FAILED(hr = m_graph->AddFilter(m_src, L"Source")) + || FAILED(hr = m_graph->AddFilter(dlg.m_enc, L"Encoder"))) + { + return false; + } + + if(FAILED(hr = m_graph->ConnectDirect(GetFirstPin(m_src, PINDIR_OUTPUT), GetFirstPin(dlg.m_enc, PINDIR_INPUT), NULL)) + || FAILED(hr = m_graph->ConnectDirect(GetFirstPin(dlg.m_enc, PINDIR_OUTPUT), GetFirstPin(mux, PINDIR_INPUT), NULL))) + { + return false; + } + + BeginEnumFilters(m_graph, pEF, pBF) + { + CFilterInfo fi; + pBF->QueryFilterInfo(&fi); + printf("Filter [%p]: %s\n", pBF.p, CStringA(fi.achName)); + + BeginEnumPins(pBF, pEP, pPin) + { + CComPtr pPinTo; + pPin->ConnectedTo(&pPinTo); + + CPinInfo pi; + pPin->QueryPinInfo(&pi); + printf("- Pin [%p - %p]: %s (%s)\n", pPin.p, pPinTo.p, CStringA(pi.achName), pi.dir ? "out" : "in"); + + BeginEnumMediaTypes(pPin, pEMT, pmt) + { + } + EndEnumMediaTypes(pmt) + } + EndEnumPins + } + EndEnumFilters + + hr = CComQIPtr(m_graph)->Run(); + + CComQIPtr(m_src)->DeliverNewSegment(); + + m_capturing = true; + + return true; +} + +bool GSCapture::DeliverFrame(const void* bits, int pitch, bool rgba) +{ + CAutoLock cAutoLock(this); + + if(bits == NULL || pitch == 0) + { + ASSERT(0); + + return false; + } + + if(m_src) + { + CComQIPtr(m_src)->DeliverFrame(bits, pitch, rgba); + + return true; + } + + return false; +} + +bool GSCapture::EndCapture() +{ + CAutoLock cAutoLock(this); + + if(m_src) + { + CComQIPtr(m_src)->DeliverEOS(); + + m_src = NULL; + } + + if(m_graph) + { + CComQIPtr(m_graph)->Stop(); + + m_graph = NULL; + } + + m_capturing = false; + + return true; +} diff --git a/plugins/GSdx/GSCaptureDlg.cpp b/plugins/GSdx/GSCaptureDlg.cpp index e5a4f36ccf..8dcd094875 100644 --- a/plugins/GSdx/GSCaptureDlg.cpp +++ b/plugins/GSdx/GSCaptureDlg.cpp @@ -1,243 +1,243 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include -#include "GSCaptureDlg.h" - -// GSCaptureDlg dialog - -IMPLEMENT_DYNAMIC(GSCaptureDlg, CDialog) -GSCaptureDlg::GSCaptureDlg(CWnd* pParent /*=NULL*/) - : CDialog(GSCaptureDlg::IDD, pParent) -{ - m_width = AfxGetApp()->GetProfileInt(_T("Capture"), _T("Width"), 640); - m_height = AfxGetApp()->GetProfileInt(_T("Capture"), _T("Height"), 480); - m_filename = AfxGetApp()->GetProfileString(_T("Capture"), _T("FileName")); -} - -GSCaptureDlg::~GSCaptureDlg() -{ -} - -int GSCaptureDlg::GetSelCodec(Codec& c) -{ - int iSel = m_codeclist.GetCurSel(); - - if(iSel < 0) return 0; - - POSITION pos = (POSITION)m_codeclist.GetItemDataPtr(iSel); - - if(pos == NULL) return 2; - - c = m_codecs.GetAt(pos); - - if(!c.filter) - { - c.moniker->BindToObject(NULL, NULL, __uuidof(IBaseFilter), (void**)&c.filter); - - if(!c.filter) return 0; - } - - return 1; -} - -LRESULT GSCaptureDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - LRESULT ret = __super::DefWindowProc(message, wParam, lParam); - - if(message == WM_INITDIALOG) SendMessage(WM_KICKIDLE); - - return(ret); -} - -void GSCaptureDlg::DoDataExchange(CDataExchange* pDX) -{ - __super::DoDataExchange(pDX); - - DDX_Text(pDX, IDC_EDIT1, m_filename); - DDX_Control(pDX, IDC_COMBO1, m_codeclist); - DDX_Text(pDX, IDC_EDIT2, m_width); - DDX_Text(pDX, IDC_EDIT4, m_height); -} - -BOOL GSCaptureDlg::OnInitDialog() -{ - __super::OnInitDialog(); - - m_codecs.RemoveAll(); - - m_codeclist.ResetContent(); - m_codeclist.SetItemDataPtr(m_codeclist.AddString(_T("Uncompressed")), NULL); - - BeginEnumSysDev(CLSID_VideoCompressorCategory, moniker) - { - Codec c; - c.moniker = moniker; - - LPOLESTR strName = NULL; - if(FAILED(moniker->GetDisplayName(NULL, NULL, &strName))) - continue; - - c.DisplayName = strName; - CoTaskMemFree(strName); - - CComPtr pPB; - moniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPB); - - CComVariant var; - if(FAILED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL))) - continue; - - c.FriendlyName = var.bstrVal; - - CStringW str = CStringW(c.DisplayName).MakeLower(); - CString prefix; - if(str.Find(L"@device:dmo:") == 0) prefix = _T("(DMO) "); - else if(str.Find(L"@device:sw:") == 0) prefix = _T("(DS) "); - else if(str.Find(L"@device:cm:") == 0) prefix = _T("(VfW) "); - c.FriendlyName = prefix + c.FriendlyName; - - m_codeclist.SetItemDataPtr(m_codeclist.AddString(c.FriendlyName), m_codecs.AddTail(c)); - } - EndEnumSysDev - - // - - CString DisplayNameToFind = AfxGetApp()->GetProfileString(_T("Capture"), _T("VideoCodecDisplayName")); - - for(int i = 0; i < m_codeclist.GetCount(); i++) - { - CString DisplayName; - - POSITION pos = (POSITION)m_codeclist.GetItemDataPtr(i); - - if(pos) DisplayName = m_codecs.GetAt(pos).DisplayName; - - if(DisplayName == DisplayNameToFind) - { - m_codeclist.SetCurSel(i); - break; - } - } - - // - - UpdateData(FALSE); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -BEGIN_MESSAGE_MAP(GSCaptureDlg, CDialog) - ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle) - ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedButton1) - ON_BN_CLICKED(IDC_BUTTON2, OnBnClickedButton2) - ON_UPDATE_COMMAND_UI(IDC_BUTTON2, OnUpdateButton2) - ON_BN_CLICKED(IDOK, OnBnClickedOk) - ON_UPDATE_COMMAND_UI(IDOK, OnUpdateOK) -END_MESSAGE_MAP() - -// GSCaptureDlg message handlers - -void GSCaptureDlg::OnKickIdle() -{ - UpdateDialogControls(this, false); -} - -void GSCaptureDlg::OnBnClickedButton1() -{ - UpdateData(); - - DWORD flags = OFN_EXPLORER|OFN_ENABLESIZING|OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST; - - CFileDialog fd(FALSE, _T("avi"), m_filename, flags, _T("Avi files (*.avi)|*.avi||"), this, 0); - - if(fd.DoModal() == IDOK) - { - m_filename = fd.GetPathName(); - - UpdateData(FALSE); - } -} - -void GSCaptureDlg::OnBnClickedButton2() -{ - Codec c; - - if(GetSelCodec(c) != 1) return; - - if(CComQIPtr pSPP = c.filter) - { - CAUUID caGUID; - - memset(&caGUID, 0, sizeof(caGUID)); - - if(SUCCEEDED(pSPP->GetPages(&caGUID))) - { - IUnknown* lpUnk = NULL; - pSPP.QueryInterface(&lpUnk); - OleCreatePropertyFrame(m_hWnd, 0, 0, CStringW(c.FriendlyName), 1, (IUnknown**)&lpUnk, caGUID.cElems, caGUID.pElems, 0, 0, NULL); - lpUnk->Release(); - - if(caGUID.pElems) CoTaskMemFree(caGUID.pElems); - } - } - else if(CComQIPtr pAMVfWCD = c.filter) - { - if(pAMVfWCD->ShowDialog(VfwCompressDialog_QueryConfig, NULL) == S_OK) - { - pAMVfWCD->ShowDialog(VfwCompressDialog_Config, m_hWnd); - } - } -} - -void GSCaptureDlg::OnUpdateButton2(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(m_codeclist.GetCurSel() >= 0 && m_codeclist.GetItemDataPtr(m_codeclist.GetCurSel()) != NULL); -} - -void GSCaptureDlg::OnBnClickedOk() -{ - UpdateData(); - - Codec c; - - if(GetSelCodec(c) == 0) return; - - m_enc = c.filter; - - AfxGetApp()->WriteProfileInt(_T("Capture"), _T("Width"), m_width); - AfxGetApp()->WriteProfileInt(_T("Capture"), _T("Height"), m_height); - AfxGetApp()->WriteProfileString(_T("Capture"), _T("FileName"), m_filename); - AfxGetApp()->WriteProfileString(_T("Capture"), _T("VideoCodecDisplayName"), CString(c.DisplayName)); - - OnOK(); -} - -void GSCaptureDlg::OnUpdateOK(CCmdUI* pCmdUI) -{ - CString str; - - GetDlgItem(IDC_EDIT1)->GetWindowText(str); - - pCmdUI->Enable(!str.IsEmpty() && m_codeclist.GetCurSel() >= 0); -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include +#include "GSCaptureDlg.h" + +// GSCaptureDlg dialog + +IMPLEMENT_DYNAMIC(GSCaptureDlg, CDialog) +GSCaptureDlg::GSCaptureDlg(CWnd* pParent /*=NULL*/) + : CDialog(GSCaptureDlg::IDD, pParent) +{ + m_width = AfxGetApp()->GetProfileInt(_T("Capture"), _T("Width"), 640); + m_height = AfxGetApp()->GetProfileInt(_T("Capture"), _T("Height"), 480); + m_filename = AfxGetApp()->GetProfileString(_T("Capture"), _T("FileName")); +} + +GSCaptureDlg::~GSCaptureDlg() +{ +} + +int GSCaptureDlg::GetSelCodec(Codec& c) +{ + int iSel = m_codeclist.GetCurSel(); + + if(iSel < 0) return 0; + + POSITION pos = (POSITION)m_codeclist.GetItemDataPtr(iSel); + + if(pos == NULL) return 2; + + c = m_codecs.GetAt(pos); + + if(!c.filter) + { + c.moniker->BindToObject(NULL, NULL, __uuidof(IBaseFilter), (void**)&c.filter); + + if(!c.filter) return 0; + } + + return 1; +} + +LRESULT GSCaptureDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + LRESULT ret = __super::DefWindowProc(message, wParam, lParam); + + if(message == WM_INITDIALOG) SendMessage(WM_KICKIDLE); + + return(ret); +} + +void GSCaptureDlg::DoDataExchange(CDataExchange* pDX) +{ + __super::DoDataExchange(pDX); + + DDX_Text(pDX, IDC_EDIT1, m_filename); + DDX_Control(pDX, IDC_COMBO1, m_codeclist); + DDX_Text(pDX, IDC_EDIT2, m_width); + DDX_Text(pDX, IDC_EDIT4, m_height); +} + +BOOL GSCaptureDlg::OnInitDialog() +{ + __super::OnInitDialog(); + + m_codecs.RemoveAll(); + + m_codeclist.ResetContent(); + m_codeclist.SetItemDataPtr(m_codeclist.AddString(_T("Uncompressed")), NULL); + + BeginEnumSysDev(CLSID_VideoCompressorCategory, moniker) + { + Codec c; + c.moniker = moniker; + + LPOLESTR strName = NULL; + if(FAILED(moniker->GetDisplayName(NULL, NULL, &strName))) + continue; + + c.DisplayName = strName; + CoTaskMemFree(strName); + + CComPtr pPB; + moniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPB); + + CComVariant var; + if(FAILED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL))) + continue; + + c.FriendlyName = var.bstrVal; + + CStringW str = CStringW(c.DisplayName).MakeLower(); + CString prefix; + if(str.Find(L"@device:dmo:") == 0) prefix = _T("(DMO) "); + else if(str.Find(L"@device:sw:") == 0) prefix = _T("(DS) "); + else if(str.Find(L"@device:cm:") == 0) prefix = _T("(VfW) "); + c.FriendlyName = prefix + c.FriendlyName; + + m_codeclist.SetItemDataPtr(m_codeclist.AddString(c.FriendlyName), m_codecs.AddTail(c)); + } + EndEnumSysDev + + // + + CString DisplayNameToFind = AfxGetApp()->GetProfileString(_T("Capture"), _T("VideoCodecDisplayName")); + + for(int i = 0; i < m_codeclist.GetCount(); i++) + { + CString DisplayName; + + POSITION pos = (POSITION)m_codeclist.GetItemDataPtr(i); + + if(pos) DisplayName = m_codecs.GetAt(pos).DisplayName; + + if(DisplayName == DisplayNameToFind) + { + m_codeclist.SetCurSel(i); + break; + } + } + + // + + UpdateData(FALSE); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +BEGIN_MESSAGE_MAP(GSCaptureDlg, CDialog) + ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle) + ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedButton1) + ON_BN_CLICKED(IDC_BUTTON2, OnBnClickedButton2) + ON_UPDATE_COMMAND_UI(IDC_BUTTON2, OnUpdateButton2) + ON_BN_CLICKED(IDOK, OnBnClickedOk) + ON_UPDATE_COMMAND_UI(IDOK, OnUpdateOK) +END_MESSAGE_MAP() + +// GSCaptureDlg message handlers + +void GSCaptureDlg::OnKickIdle() +{ + UpdateDialogControls(this, false); +} + +void GSCaptureDlg::OnBnClickedButton1() +{ + UpdateData(); + + DWORD flags = OFN_EXPLORER|OFN_ENABLESIZING|OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST; + + CFileDialog fd(FALSE, _T("avi"), m_filename, flags, _T("Avi files (*.avi)|*.avi||"), this, 0); + + if(fd.DoModal() == IDOK) + { + m_filename = fd.GetPathName(); + + UpdateData(FALSE); + } +} + +void GSCaptureDlg::OnBnClickedButton2() +{ + Codec c; + + if(GetSelCodec(c) != 1) return; + + if(CComQIPtr pSPP = c.filter) + { + CAUUID caGUID; + + memset(&caGUID, 0, sizeof(caGUID)); + + if(SUCCEEDED(pSPP->GetPages(&caGUID))) + { + IUnknown* lpUnk = NULL; + pSPP.QueryInterface(&lpUnk); + OleCreatePropertyFrame(m_hWnd, 0, 0, CStringW(c.FriendlyName), 1, (IUnknown**)&lpUnk, caGUID.cElems, caGUID.pElems, 0, 0, NULL); + lpUnk->Release(); + + if(caGUID.pElems) CoTaskMemFree(caGUID.pElems); + } + } + else if(CComQIPtr pAMVfWCD = c.filter) + { + if(pAMVfWCD->ShowDialog(VfwCompressDialog_QueryConfig, NULL) == S_OK) + { + pAMVfWCD->ShowDialog(VfwCompressDialog_Config, m_hWnd); + } + } +} + +void GSCaptureDlg::OnUpdateButton2(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(m_codeclist.GetCurSel() >= 0 && m_codeclist.GetItemDataPtr(m_codeclist.GetCurSel()) != NULL); +} + +void GSCaptureDlg::OnBnClickedOk() +{ + UpdateData(); + + Codec c; + + if(GetSelCodec(c) == 0) return; + + m_enc = c.filter; + + AfxGetApp()->WriteProfileInt(_T("Capture"), _T("Width"), m_width); + AfxGetApp()->WriteProfileInt(_T("Capture"), _T("Height"), m_height); + AfxGetApp()->WriteProfileString(_T("Capture"), _T("FileName"), m_filename); + AfxGetApp()->WriteProfileString(_T("Capture"), _T("VideoCodecDisplayName"), CString(c.DisplayName)); + + OnOK(); +} + +void GSCaptureDlg::OnUpdateOK(CCmdUI* pCmdUI) +{ + CString str; + + GetDlgItem(IDC_EDIT1)->GetWindowText(str); + + pCmdUI->Enable(!str.IsEmpty() && m_codeclist.GetCurSel() >= 0); +} diff --git a/plugins/GSdx/GSCaptureDlg.h b/plugins/GSdx/GSCaptureDlg.h index 1ea328ac31..419b0cd62a 100644 --- a/plugins/GSdx/GSCaptureDlg.h +++ b/plugins/GSdx/GSCaptureDlg.h @@ -1,73 +1,73 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "resource.h" -#include "baseclasses/streams.h" - -// GSCaptureDlg dialog - -class GSCaptureDlg : public CDialog -{ - DECLARE_DYNAMIC(GSCaptureDlg) - -private: - struct Codec - { - CComPtr moniker; - CComPtr filter; - CString FriendlyName; - CComBSTR DisplayName; - }; - - CAtlList m_codecs; - - int GetSelCodec(Codec& c); - -public: - GSCaptureDlg(CWnd* pParent = NULL); // standard constructor - virtual ~GSCaptureDlg(); - - CComPtr m_enc; - -// Dialog Data - enum { IDD = IDD_CAPTURE }; - CString m_filename; - CComboBox m_codeclist; - -protected: - virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam); - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnInitDialog(); - - DECLARE_MESSAGE_MAP() - -public: - afx_msg void OnKickIdle(); - afx_msg void OnBnClickedButton1(); - afx_msg void OnBnClickedButton2(); - afx_msg void OnUpdateButton2(CCmdUI* pCmdUI); - afx_msg void OnBnClickedOk(); - afx_msg void OnUpdateOK(CCmdUI* pCmdUI); - int m_width; - int m_height; -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "resource.h" +#include "baseclasses/streams.h" + +// GSCaptureDlg dialog + +class GSCaptureDlg : public CDialog +{ + DECLARE_DYNAMIC(GSCaptureDlg) + +private: + struct Codec + { + CComPtr moniker; + CComPtr filter; + CString FriendlyName; + CComBSTR DisplayName; + }; + + CAtlList m_codecs; + + int GetSelCodec(Codec& c); + +public: + GSCaptureDlg(CWnd* pParent = NULL); // standard constructor + virtual ~GSCaptureDlg(); + + CComPtr m_enc; + +// Dialog Data + enum { IDD = IDD_CAPTURE }; + CString m_filename; + CComboBox m_codeclist; + +protected: + virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam); + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + + DECLARE_MESSAGE_MAP() + +public: + afx_msg void OnKickIdle(); + afx_msg void OnBnClickedButton1(); + afx_msg void OnBnClickedButton2(); + afx_msg void OnUpdateButton2(CCmdUI* pCmdUI); + afx_msg void OnBnClickedOk(); + afx_msg void OnUpdateOK(CCmdUI* pCmdUI); + int m_width; + int m_height; +}; diff --git a/plugins/GSdx/GSClut.cpp b/plugins/GSdx/GSClut.cpp index 7cbc883e78..d850ac266f 100644 --- a/plugins/GSdx/GSClut.cpp +++ b/plugins/GSdx/GSClut.cpp @@ -1,869 +1,869 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSClut.h" -#include "GSLocalMemory.h" - -GSClut::GSClut(const GSLocalMemory* mem) - : m_mem(mem) -{ - BYTE* p = (BYTE*)VirtualAlloc(NULL, 2 * 4096, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - - m_clut = (WORD*)&p[0]; // 1k + 1k for buffer overruns (sfex: PSM == PSM_PSMT8, CPSM == PSM_PSMCT32, CSA != 0) - m_buff32 = (DWORD*)&p[2048]; // 1k - m_buff64 = (UINT64*)&p[4096]; // 2k - m_write.dirty = true; - m_read.dirty = true; - - for(int i = 0; i < 16; i++) - { - for(int j = 0; j < 64; j++) - { - m_wc[0][i][j] = &GSClut::WriteCLUT_NULL; - m_wc[1][i][j] = &GSClut::WriteCLUT_NULL; - } - } - - m_wc[0][PSM_PSMCT32][PSM_PSMT8] = &GSClut::WriteCLUT32_I8_CSM1; - m_wc[0][PSM_PSMCT32][PSM_PSMT8H] = &GSClut::WriteCLUT32_I8_CSM1; - m_wc[0][PSM_PSMCT32][PSM_PSMT4] = &GSClut::WriteCLUT32_I4_CSM1; - m_wc[0][PSM_PSMCT32][PSM_PSMT4HL] = &GSClut::WriteCLUT32_I4_CSM1; - m_wc[0][PSM_PSMCT32][PSM_PSMT4HH] = &GSClut::WriteCLUT32_I4_CSM1; - m_wc[0][PSM_PSMCT24][PSM_PSMT8] = &GSClut::WriteCLUT32_I8_CSM1; - m_wc[0][PSM_PSMCT24][PSM_PSMT8H] = &GSClut::WriteCLUT32_I8_CSM1; - m_wc[0][PSM_PSMCT24][PSM_PSMT4] = &GSClut::WriteCLUT32_I4_CSM1; - m_wc[0][PSM_PSMCT24][PSM_PSMT4HL] = &GSClut::WriteCLUT32_I4_CSM1; - m_wc[0][PSM_PSMCT24][PSM_PSMT4HH] = &GSClut::WriteCLUT32_I4_CSM1; - m_wc[0][PSM_PSMCT16][PSM_PSMT8] = &GSClut::WriteCLUT16_I8_CSM1; - m_wc[0][PSM_PSMCT16][PSM_PSMT8H] = &GSClut::WriteCLUT16_I8_CSM1; - m_wc[0][PSM_PSMCT16][PSM_PSMT4] = &GSClut::WriteCLUT16_I4_CSM1; - m_wc[0][PSM_PSMCT16][PSM_PSMT4HL] = &GSClut::WriteCLUT16_I4_CSM1; - m_wc[0][PSM_PSMCT16][PSM_PSMT4HH] = &GSClut::WriteCLUT16_I4_CSM1; - m_wc[0][PSM_PSMCT16S][PSM_PSMT8] = &GSClut::WriteCLUT16S_I8_CSM1; - m_wc[0][PSM_PSMCT16S][PSM_PSMT8H] = &GSClut::WriteCLUT16S_I8_CSM1; - m_wc[0][PSM_PSMCT16S][PSM_PSMT4] = &GSClut::WriteCLUT16S_I4_CSM1; - m_wc[0][PSM_PSMCT16S][PSM_PSMT4HL] = &GSClut::WriteCLUT16S_I4_CSM1; - m_wc[0][PSM_PSMCT16S][PSM_PSMT4HH] = &GSClut::WriteCLUT16S_I4_CSM1; - - m_wc[1][PSM_PSMCT32][PSM_PSMT8] = &GSClut::WriteCLUT32_CSM2<256>; - m_wc[1][PSM_PSMCT32][PSM_PSMT8H] = &GSClut::WriteCLUT32_CSM2<256>; - m_wc[1][PSM_PSMCT32][PSM_PSMT4] = &GSClut::WriteCLUT32_CSM2<16>; - m_wc[1][PSM_PSMCT32][PSM_PSMT4HL] = &GSClut::WriteCLUT32_CSM2<16>; - m_wc[1][PSM_PSMCT32][PSM_PSMT4HH] = &GSClut::WriteCLUT32_CSM2<16>; - m_wc[1][PSM_PSMCT24][PSM_PSMT8] = &GSClut::WriteCLUT32_CSM2<256>; - m_wc[1][PSM_PSMCT24][PSM_PSMT8H] = &GSClut::WriteCLUT32_CSM2<256>; - m_wc[1][PSM_PSMCT24][PSM_PSMT4] = &GSClut::WriteCLUT32_CSM2<16>; - m_wc[1][PSM_PSMCT24][PSM_PSMT4HL] = &GSClut::WriteCLUT32_CSM2<16>; - m_wc[1][PSM_PSMCT24][PSM_PSMT4HH] = &GSClut::WriteCLUT32_CSM2<16>; - m_wc[1][PSM_PSMCT16][PSM_PSMT8] = &GSClut::WriteCLUT16_CSM2<256>; - m_wc[1][PSM_PSMCT16][PSM_PSMT8H] = &GSClut::WriteCLUT16_CSM2<256>; - m_wc[1][PSM_PSMCT16][PSM_PSMT4] = &GSClut::WriteCLUT16_CSM2<16>; - m_wc[1][PSM_PSMCT16][PSM_PSMT4HL] = &GSClut::WriteCLUT16_CSM2<16>; - m_wc[1][PSM_PSMCT16][PSM_PSMT4HH] = &GSClut::WriteCLUT16_CSM2<16>; - m_wc[1][PSM_PSMCT16S][PSM_PSMT8] = &GSClut::WriteCLUT16S_CSM2<256>; - m_wc[1][PSM_PSMCT16S][PSM_PSMT8H] = &GSClut::WriteCLUT16S_CSM2<256>; - m_wc[1][PSM_PSMCT16S][PSM_PSMT4] = &GSClut::WriteCLUT16S_CSM2<16>; - m_wc[1][PSM_PSMCT16S][PSM_PSMT4HL] = &GSClut::WriteCLUT16S_CSM2<16>; - m_wc[1][PSM_PSMCT16S][PSM_PSMT4HH] = &GSClut::WriteCLUT16S_CSM2<16>; -} - -GSClut::~GSClut() -{ - VirtualFree(m_clut, 0, MEM_RELEASE); -} - -void GSClut::Invalidate() -{ - m_write.dirty = true; -} - -bool GSClut::WriteTest(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) -{ - switch(TEX0.CLD) - { - case 0: return false; - case 1: break; - case 2: m_CBP[0] = TEX0.CBP; break; - case 3: m_CBP[1] = TEX0.CBP; break; - case 4: if(m_CBP[0] == TEX0.CBP) return false; m_CBP[0] = TEX0.CBP; break; - case 5: if(m_CBP[1] == TEX0.CBP) return false; m_CBP[1] = TEX0.CBP; break; - case 6: ASSERT(0); return false; - case 7: ASSERT(0); return false; - default: __assume(0); - } - - return m_write.IsDirty(TEX0, TEXCLUT); -} - -void GSClut::Write(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) -{ - m_write.TEX0 = TEX0; - m_write.TEXCLUT = TEXCLUT; - m_write.dirty = false; - m_read.dirty = true; - - (this->*m_wc[TEX0.CSM][TEX0.CPSM][TEX0.PSM])(TEX0, TEXCLUT); -} - -void GSClut::WriteCLUT32_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) -{ - ASSERT(TEX0.CSA == 0); - - WriteCLUT_T32_I8_CSM1(&m_mem->m_vm32[m_mem->BlockAddress32(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4)); -} - -void GSClut::WriteCLUT32_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) -{ - ASSERT(TEX0.CSA < 16); - - GSVector4i dummy; // this just forces stack alignment and enables inlining the next call - - WriteCLUT_T32_I4_CSM1(&m_mem->m_vm32[m_mem->BlockAddress32(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4)); -} - -void GSClut::WriteCLUT16_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) -{ - ASSERT(TEX0.CSA < 16); - - WriteCLUT_T16_I8_CSM1(&m_mem->m_vm16[m_mem->BlockAddress16(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4)); -} - -void GSClut::WriteCLUT16_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) -{ - ASSERT(TEX0.CSA < 32); - - WriteCLUT_T16_I4_CSM1(&m_mem->m_vm16[m_mem->BlockAddress16(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4)); -} - -void GSClut::WriteCLUT16S_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) -{ - WriteCLUT_T16_I8_CSM1(&m_mem->m_vm16[m_mem->BlockAddress16S(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4)); -} - -void GSClut::WriteCLUT16S_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) -{ - WriteCLUT_T16_I4_CSM1(&m_mem->m_vm16[m_mem->BlockAddress16S(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4)); -} - -template void GSClut::WriteCLUT32_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) -{ - WORD* RESTRICT clut = m_clut + (TEX0.CSA << 4); - - DWORD base = m_mem->PixelAddress32(0, TEXCLUT.COV, TEX0.CBP, TEXCLUT.CBW); - int* offset = &m_mem->rowOffset32[TEXCLUT.COU << 4]; - - for(int i = 0; i < n; i++) - { - DWORD c = m_mem->ReadPixel32(base + offset[i]); - - clut[i] = (WORD)(c & 0xffff); - clut[i + 256] = (WORD)(c >> 16); - } -} - -template void GSClut::WriteCLUT16_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) -{ - WORD* RESTRICT clut = m_clut + (TEX0.CSA << 4); - - DWORD base = m_mem->PixelAddress16(0, TEXCLUT.COV, TEX0.CBP, TEXCLUT.CBW); - int* offset = &m_mem->rowOffset16[TEXCLUT.COU << 4]; - - for(int i = 0; i < n; i++) - { - clut[i] = (WORD)m_mem->ReadPixel16(base + offset[i]); - } -} - -template void GSClut::WriteCLUT16S_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) -{ - WORD* RESTRICT clut = m_clut + (TEX0.CSA << 4); - - DWORD base = m_mem->PixelAddress16S(0, TEXCLUT.COV, TEX0.CBP, TEXCLUT.CBW); - int* offset = &m_mem->rowOffset16S[TEXCLUT.COU << 4]; - - for(int i = 0; i < n; i++) - { - clut[i] = (WORD)m_mem->ReadPixel16(base + offset[i]); - } -} - -void GSClut::Read(const GIFRegTEX0& TEX0) -{ - if(m_read.IsDirty(TEX0)) - { - m_read.TEX0 = TEX0; - m_read.dirty = false; - - WORD* clut = m_clut + (TEX0.CSA << 4); - - if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24) - { - switch(TEX0.PSM) - { - case PSM_PSMT8: - case PSM_PSMT8H: - ReadCLUT_T32_I8(clut, m_buff32); - break; - case PSM_PSMT4: - case PSM_PSMT4HL: - case PSM_PSMT4HH: - ReadCLUT_T32_I4(clut, m_buff32, m_buff64); - break; - } - } - else if(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S) - { - switch(TEX0.PSM) - { - case PSM_PSMT8: - case PSM_PSMT8H: - ReadCLUT_T16_I8(clut, m_buff32); - break; - case PSM_PSMT4: - case PSM_PSMT4HL: - case PSM_PSMT4HH: - ReadCLUT_T16_I4(clut, m_buff32, m_buff64); - break; - } - } - } -} - -void GSClut::Read32(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) -{ - if(m_read.IsDirty(TEX0, TEXA)) - { - m_read.TEX0 = TEX0; - m_read.TEXA = TEXA; - m_read.dirty = false; - m_read.adirty = true; - - WORD* clut = m_clut + (TEX0.CSA << 4); - - if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24) - { - switch(TEX0.PSM) - { - case PSM_PSMT8: - case PSM_PSMT8H: - ReadCLUT_T32_I8(clut, m_buff32); - break; - case PSM_PSMT4: - case PSM_PSMT4HL: - case PSM_PSMT4HH: - // TODO: merge these functions - ReadCLUT_T32_I4(clut, m_buff32); - ExpandCLUT64_T32_I8(m_buff32, (UINT64*)m_buff64); // sw renderer does not need m_buff64 anymore - break; - } - } - else if(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S) - { - switch(TEX0.PSM) - { - case PSM_PSMT8: - case PSM_PSMT8H: - Expand16(clut, m_buff32, 256, TEXA); - break; - case PSM_PSMT4: - case PSM_PSMT4HL: - case PSM_PSMT4HH: - // TODO: merge these functions - Expand16(clut, m_buff32, 16, TEXA); - ExpandCLUT64_T32_I8(m_buff32, (UINT64*)m_buff64); // sw renderer does not need m_buff64 anymore - break; - } - } - } -} - -void GSClut::GetAlphaMinMax32(int& amin, int& amax) -{ - // call only after Read32 - - ASSERT(!m_read.dirty); - - if(m_read.adirty) - { - m_read.adirty = false; - - // DWORD bpp = GSLocalMemory::m_psm[m_read.TEX0.PSM].trbpp; - DWORD cbpp = GSLocalMemory::m_psm[m_read.TEX0.CPSM].trbpp; - DWORD pal = GSLocalMemory::m_psm[m_read.TEX0.PSM].pal; - - if(cbpp == 24 && m_read.TEXA.AEM == 0) - { - m_read.amin = m_read.TEXA.TA0; - m_read.amax = m_read.TEXA.TA0; - } - else - { - int amin = 255; - int amax = 0; - - const GSVector4i* p = (const GSVector4i*)m_buff32; - - for(int i = 0, j = pal >> 4; i < j; i++) - { - GSVector4i v0 = (p[i * 4 + 0] >> 24).ps32(p[i * 4 + 1] >> 24); - GSVector4i v1 = (p[i * 4 + 2] >> 24).ps32(p[i * 4 + 3] >> 24); - - GSVector4i v2 = v0.min_i16(v1); - GSVector4i v3 = v0.max_i16(v1); - - v2 = v2.min_i16(v2.zwxy()); - v3 = v3.max_i16(v3.zwxy()); - v2 = v2.min_i16(v2.zwxyl()); - v3 = v3.max_i16(v3.zwxyl()); - v2 = v2.min_i16(v2.yxwzl()); - v3 = v3.max_i16(v3.yxwzl()); - - amin = min(amin, v2.extract16<0>()); - amax = max(amax, v3.extract16<0>()); - } - - m_read.amin = amin; - m_read.amax = amax; - } - } - - amin = m_read.amin; - amax = m_read.amax; -} - -// - -void GSClut::WriteCLUT_T32_I8_CSM1(const DWORD* RESTRICT src, WORD* RESTRICT clut) -{ - #if _M_SSE >= 0x200 - - for(int i = 0; i < 64; i += 16) - { - WriteCLUT_T32_I4_CSM1(&src[i + 0], &clut[i * 2 + 0]); - WriteCLUT_T32_I4_CSM1(&src[i + 64], &clut[i * 2 + 16]); - WriteCLUT_T32_I4_CSM1(&src[i + 128], &clut[i * 2 + 128]); - WriteCLUT_T32_I4_CSM1(&src[i + 192], &clut[i * 2 + 144]); - } - - #else - - for(int j = 0; j < 2; j++, src += 128, clut += 128) - { - for(int i = 0; i < 128; i++) - { - DWORD c = src[clutTableT32I8[i]]; - clut[i] = (WORD)(c & 0xffff); - clut[i + 256] = (WORD)(c >> 16); - } - } - - #endif -} - -__forceinline void GSClut::WriteCLUT_T32_I4_CSM1(const DWORD* RESTRICT src, WORD* RESTRICT clut) -{ - #if _M_SSE >= 0x200 - - GSVector4i* s = (GSVector4i*)src; - GSVector4i* d = (GSVector4i*)clut; - - GSVector4i v0 = s[0]; - GSVector4i v1 = s[1]; - GSVector4i v2 = s[2]; - GSVector4i v3 = s[3]; - - GSVector4i::sw64(v0, v1, v2, v3); - GSVector4i::sw16(v0, v1, v2, v3); - GSVector4i::sw16(v0, v2, v1, v3); - GSVector4i::sw16(v0, v1, v2, v3); - - d[0] = v0; - d[1] = v1; - d[32] = v2; - d[33] = v3; - - #else - - for(int i = 0; i < 16; i++) - { - DWORD c = src[clutTableT32I4[i]]; - clut[i] = (WORD)(c & 0xffff); - clut[i + 256] = (WORD)(c >> 16); - } - - #endif -} - -void GSClut::WriteCLUT_T16_I8_CSM1(const WORD* RESTRICT src, WORD* RESTRICT clut) -{ - #if _M_SSE >= 0x200 - - GSVector4i* s = (GSVector4i*)src; - GSVector4i* d = (GSVector4i*)clut; - - for(int i = 0; i < 32; i += 4) - { - GSVector4i v0 = s[i + 0]; - GSVector4i v1 = s[i + 1]; - GSVector4i v2 = s[i + 2]; - GSVector4i v3 = s[i + 3]; - - GSVector4i::sw16(v0, v1, v2, v3); - GSVector4i::sw32(v0, v1, v2, v3); - GSVector4i::sw16(v0, v2, v1, v3); - - d[i + 0] = v0; - d[i + 1] = v2; - d[i + 2] = v1; - d[i + 3] = v3; - } - - #else - - for(int j = 0; j < 8; j++, src += 32, clut += 32) - { - for(int i = 0; i < 32; i++) - { - clut[i] = src[clutTableT16I8[i]]; - } - } - - #endif -} - -__forceinline void GSClut::WriteCLUT_T16_I4_CSM1(const WORD* RESTRICT src, WORD* RESTRICT clut) -{ - for(int i = 0; i < 16; i++) - { - clut[i] = src[clutTableT16I4[i]]; - } -} - -void GSClut::ReadCLUT_T32_I8(const WORD* RESTRICT clut, DWORD* RESTRICT dst) -{ - #if _M_SSE >= 0x200 - - for(int i = 0; i < 256; i += 16) - { - ReadCLUT_T32_I4(&clut[i], &dst[i]); - } - - #else - - for(int i = 0; i < 256; i++) - { - dst[i] = ((DWORD)clut[i + 256] << 16) | clut[i]; - } - - #endif -} - -__forceinline void GSClut::ReadCLUT_T32_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst) -{ - #if _M_SSE >= 0x200 - - GSVector4i* s = (GSVector4i*)clut; - GSVector4i* d = (GSVector4i*)dst; - - GSVector4i v0 = s[0]; - GSVector4i v1 = s[1]; - GSVector4i v2 = s[32]; - GSVector4i v3 = s[33]; - - GSVector4i::sw16(v0, v2, v1, v3); - - d[0] = v0; - d[1] = v1; - d[2] = v2; - d[3] = v3; - - #else - - for(int i = 0; i < 16; i++) - { - dst[i] = ((DWORD)clut[i + 256] << 16) | clut[i]; - } - - #endif -} - -__forceinline void GSClut::ReadCLUT_T32_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst32, UINT64* RESTRICT dst64) -{ - #if _M_SSE >= 0x200 - - GSVector4i* s = (GSVector4i*)clut; - GSVector4i* d32 = (GSVector4i*)dst32; - GSVector4i* d64 = (GSVector4i*)dst64; - - GSVector4i s0 = s[0]; - GSVector4i s1 = s[1]; - GSVector4i s2 = s[32]; - GSVector4i s3 = s[33]; - - GSVector4i::sw16(s0, s2, s1, s3); - - d32[0] = s0; - d32[1] = s1; - d32[2] = s2; - d32[3] = s3; - - ExpandCLUT64_T32(s0, s0, s1, s2, s3, &d64[0]); - ExpandCLUT64_T32(s1, s0, s1, s2, s3, &d64[32]); - ExpandCLUT64_T32(s2, s0, s1, s2, s3, &d64[64]); - ExpandCLUT64_T32(s3, s0, s1, s2, s3, &d64[96]); - - #else - - for(int i = 0; i < 16; i++) - { - dst[i] = ((DWORD)clut[i + 256] << 16) | clut[i]; - } - - DWORD* d = (DWORD*)dst64; - - for(int j = 0; j < 16; j++, d += 32) - { - DWORD hi = dst32[j]; - - for(int i = 0; i < 16; i++) - { - d[i * 2 + 0] = dst32[i]; - d[i * 2 + 1] = hi; - } - } - - #endif -} - -void GSClut::ReadCLUT_T16_I8(const WORD* RESTRICT clut, DWORD* RESTRICT dst) -{ - #if _M_SSE >= 0x200 - - for(int i = 0; i < 256; i += 16) - { - ReadCLUT_T16_I4(&clut[i], &dst[i]); - } - - #else - - for(int i = 0; i < 256; i++) - { - dst[i] = (DWORD)clut[i]; - } - - #endif -} - -__forceinline void GSClut::ReadCLUT_T16_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst) -{ - #if _M_SSE >= 0x200 - - GSVector4i* s = (GSVector4i*)clut; - GSVector4i* d = (GSVector4i*)dst; - - GSVector4i v0 = s[0]; - GSVector4i v1 = s[1]; - - d[0] = v0.upl16(); - d[1] = v0.uph16(); - d[2] = v1.upl16(); - d[3] = v1.uph16(); - - #else - - for(int i = 0; i < 16; i++) - { - dst[i] = (DWORD)clut[i]; - } - - #endif -} - -__forceinline void GSClut::ReadCLUT_T16_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst32, UINT64* RESTRICT dst64) -{ - #if _M_SSE >= 0x200 - - GSVector4i* s = (GSVector4i*)clut; - GSVector4i* d32 = (GSVector4i*)dst32; - GSVector4i* d64 = (GSVector4i*)dst64; - - GSVector4i v0 = s[0]; - GSVector4i v1 = s[1]; - - GSVector4i s0 = v0.upl16(); - GSVector4i s1 = v0.uph16(); - GSVector4i s2 = v1.upl16(); - GSVector4i s3 = v1.uph16(); - - d32[0] = s0; - d32[1] = s1; - d32[2] = s2; - d32[3] = s3; - - ExpandCLUT64_T16(s0, s0, s1, s2, s3, &d64[0]); - ExpandCLUT64_T16(s1, s0, s1, s2, s3, &d64[32]); - ExpandCLUT64_T16(s2, s0, s1, s2, s3, &d64[64]); - ExpandCLUT64_T16(s3, s0, s1, s2, s3, &d64[96]); - - #else - - for(int i = 0; i < 16; i++) - { - dst32[i] = (DWORD)clut[i]; - } - - DWORD* d = (DWORD*)dst64; - - for(int j = 0; j < 16; j++, d += 32) - { - DWORD hi = dst32[j] << 16; - - for(int i = 0; i < 16; i++) - { - d[i * 2 + 0] = hi | (dst32[i] & 0xffff); - } - } - - #endif -} - -void GSClut::ExpandCLUT64_T32_I8(const DWORD* RESTRICT src, UINT64* RESTRICT dst) -{ - #if _M_SSE >= 0x200 - - GSVector4i* s = (GSVector4i*)src; - GSVector4i* d = (GSVector4i*)dst; - - GSVector4i s0 = s[0]; - GSVector4i s1 = s[1]; - GSVector4i s2 = s[2]; - GSVector4i s3 = s[3]; - - ExpandCLUT64_T32(s0, s0, s1, s2, s3, &d[0]); - ExpandCLUT64_T32(s1, s0, s1, s2, s3, &d[32]); - ExpandCLUT64_T32(s2, s0, s1, s2, s3, &d[64]); - ExpandCLUT64_T32(s3, s0, s1, s2, s3, &d[96]); - - #else - - DWORD* d = (DWORD*)dst; - - for(int j = 0; j < 16; j++, d += 32) - { - DWORD hi = src[j]; - - for(int i = 0; i < 16; i++) - { - d[i * 2 + 0] = src[i]; - d[i * 2 + 1] = hi; - } - } - - #endif -} - -__forceinline void GSClut::ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst) -{ - ExpandCLUT64_T32(hi.xxxx(), lo0, &dst[0]); - ExpandCLUT64_T32(hi.xxxx(), lo1, &dst[2]); - ExpandCLUT64_T32(hi.xxxx(), lo2, &dst[4]); - ExpandCLUT64_T32(hi.xxxx(), lo3, &dst[6]); - ExpandCLUT64_T32(hi.yyyy(), lo0, &dst[8]); - ExpandCLUT64_T32(hi.yyyy(), lo1, &dst[10]); - ExpandCLUT64_T32(hi.yyyy(), lo2, &dst[12]); - ExpandCLUT64_T32(hi.yyyy(), lo3, &dst[14]); - ExpandCLUT64_T32(hi.zzzz(), lo0, &dst[16]); - ExpandCLUT64_T32(hi.zzzz(), lo1, &dst[18]); - ExpandCLUT64_T32(hi.zzzz(), lo2, &dst[20]); - ExpandCLUT64_T32(hi.zzzz(), lo3, &dst[22]); - ExpandCLUT64_T32(hi.wwww(), lo0, &dst[24]); - ExpandCLUT64_T32(hi.wwww(), lo1, &dst[26]); - ExpandCLUT64_T32(hi.wwww(), lo2, &dst[28]); - ExpandCLUT64_T32(hi.wwww(), lo3, &dst[30]); -} - -__forceinline void GSClut::ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst) -{ - dst[0] = lo.upl32(hi); - dst[1] = lo.uph32(hi); -} - -void GSClut::ExpandCLUT64_T16_I8(const DWORD* RESTRICT src, UINT64* RESTRICT dst) -{ - #if _M_SSE >= 0x200 - - GSVector4i* s = (GSVector4i*)src; - GSVector4i* d = (GSVector4i*)dst; - - GSVector4i s0 = s[0]; - GSVector4i s1 = s[1]; - GSVector4i s2 = s[2]; - GSVector4i s3 = s[3]; - - ExpandCLUT64_T16(s0, s0, s1, s2, s3, &d[0]); - ExpandCLUT64_T16(s1, s0, s1, s2, s3, &d[32]); - ExpandCLUT64_T16(s2, s0, s1, s2, s3, &d[64]); - ExpandCLUT64_T16(s3, s0, s1, s2, s3, &d[96]); - - #else - - DWORD* d = (DWORD*)dst; - - for(int j = 0; j < 16; j++, d += 32) - { - DWORD hi = src[j] << 16; - - for(int i = 0; i < 16; i++) - { - d[i * 2 + 0] = hi | (src[i] & 0xffff); - } - } - - #endif -} - -__forceinline void GSClut::ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst) -{ - ExpandCLUT64_T16(hi.xxxx(), lo0, &dst[0]); - ExpandCLUT64_T16(hi.xxxx(), lo1, &dst[2]); - ExpandCLUT64_T16(hi.xxxx(), lo2, &dst[4]); - ExpandCLUT64_T16(hi.xxxx(), lo3, &dst[6]); - ExpandCLUT64_T16(hi.yyyy(), lo0, &dst[8]); - ExpandCLUT64_T16(hi.yyyy(), lo1, &dst[10]); - ExpandCLUT64_T16(hi.yyyy(), lo2, &dst[12]); - ExpandCLUT64_T16(hi.yyyy(), lo3, &dst[14]); - ExpandCLUT64_T16(hi.zzzz(), lo0, &dst[16]); - ExpandCLUT64_T16(hi.zzzz(), lo1, &dst[18]); - ExpandCLUT64_T16(hi.zzzz(), lo2, &dst[20]); - ExpandCLUT64_T16(hi.zzzz(), lo3, &dst[22]); - ExpandCLUT64_T16(hi.wwww(), lo0, &dst[24]); - ExpandCLUT64_T16(hi.wwww(), lo1, &dst[26]); - ExpandCLUT64_T16(hi.wwww(), lo2, &dst[28]); - ExpandCLUT64_T16(hi.wwww(), lo3, &dst[30]); -} - -__forceinline void GSClut::ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst) -{ - dst[0] = lo.upl16(hi); - dst[1] = lo.uph16(hi); -} - -// TODO - -static const GSVector4i s_am(0x00008000); -static const GSVector4i s_bm(0x00007c00); -static const GSVector4i s_gm(0x000003e0); -static const GSVector4i s_rm(0x0000001f); - -void GSClut::Expand16(const WORD* RESTRICT src, DWORD* RESTRICT dst, int w, const GIFRegTEXA& TEXA) -{ - #if _M_SSE >= 0x200 - - ASSERT((w & 7) == 0); - - const GSVector4i rm = s_rm; - const GSVector4i gm = s_gm; - const GSVector4i bm = s_bm; - // const GSVector4i am = s_am; - - GSVector4i TA0(TEXA.TA0 << 24); - GSVector4i TA1(TEXA.TA1 << 24); - - GSVector4i c, cl, ch; - - const GSVector4i* s = (const GSVector4i*)src; - GSVector4i* d = (GSVector4i*)dst; - - if(!TEXA.AEM) - { - for(int i = 0, j = w >> 3; i < j; i++) - { - c = s[i]; - /* - cl = c.upl16(); - ch = c.uph16(); - d[i * 2 + 0] = ((cl & rm) << 3) | ((cl & gm) << 6) | ((cl & bm) << 9) | TA1.blend(TA0, cl < am); - d[i * 2 + 1] = ((ch & rm) << 3) | ((ch & gm) << 6) | ((ch & bm) << 9) | TA1.blend(TA0, ch < am); - */ - cl = c.upl16(c); - ch = c.uph16(c); - d[i * 2 + 0] = ((cl & rm) << 3) | ((cl & gm) << 6) | ((cl & bm) << 9) | TA0.blend8(TA1, cl.sra16(15)); - d[i * 2 + 1] = ((ch & rm) << 3) | ((ch & gm) << 6) | ((ch & bm) << 9) | TA0.blend8(TA1, ch.sra16(15)); - } - } - else - { - for(int i = 0, j = w >> 3; i < j; i++) - { - c = s[i]; - /* - cl = c.upl16(); - ch = c.uph16(); - d[i * 2 + 0] = ((cl & rm) << 3) | ((cl & gm) << 6) | ((cl & bm) << 9) | TA1.blend(TA0, cl < am).andnot(cl == GSVector4i::zero()); - d[i * 2 + 1] = ((ch & rm) << 3) | ((ch & gm) << 6) | ((ch & bm) << 9) | TA1.blend(TA0, ch < am).andnot(ch == GSVector4i::zero()); - */ - cl = c.upl16(c); - ch = c.uph16(c); - d[i * 2 + 0] = ((cl & rm) << 3) | ((cl & gm) << 6) | ((cl & bm) << 9) | TA0.blend8(TA1, cl.sra16(15)).andnot(cl == GSVector4i::zero()); - d[i * 2 + 1] = ((ch & rm) << 3) | ((ch & gm) << 6) | ((ch & bm) << 9) | TA0.blend8(TA1, ch.sra16(15)).andnot(ch == GSVector4i::zero()); - } - } - - #else - - DWORD TA0 = (DWORD)TEXA.TA0 << 24; - DWORD TA1 = (DWORD)TEXA.TA1 << 24; - - if(!TEXA.AEM) - { - for(int i = 0; i < w; i++) - { - dst[i] = ((src[i] & 0x8000) ? TA1 : TA0) | ((src[i] & 0x7c00) << 9) | ((src[i] & 0x03e0) << 6) | ((src[i] & 0x001f) << 3); - } - } - else - { - for(int i = 0; i < w; i++) - { - dst[i] = ((src[i] & 0x8000) ? TA1 : src[i] ? TA0 : 0) | ((src[i] & 0x7c00) << 9) | ((src[i] & 0x03e0) << 6) | ((src[i] & 0x001f) << 3); - } - } - - #endif -} - -// - -bool GSClut::WriteState::IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) -{ - return dirty || !(GSVector4i::load(this) == GSVector4i::load(&TEX0, &TEXCLUT)).alltrue(); -} - -bool GSClut::ReadState::IsDirty(const GIFRegTEX0& TEX0) -{ - return dirty || !(GSVector4i::load(this) == GSVector4i::load(&TEX0, &this->TEXA)).alltrue(); -} - -bool GSClut::ReadState::IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) -{ - return dirty || !(GSVector4i::load(this) == GSVector4i::load(&TEX0, &TEXA)).alltrue(); -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSClut.h" +#include "GSLocalMemory.h" + +GSClut::GSClut(const GSLocalMemory* mem) + : m_mem(mem) +{ + BYTE* p = (BYTE*)VirtualAlloc(NULL, 2 * 4096, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + + m_clut = (WORD*)&p[0]; // 1k + 1k for buffer overruns (sfex: PSM == PSM_PSMT8, CPSM == PSM_PSMCT32, CSA != 0) + m_buff32 = (DWORD*)&p[2048]; // 1k + m_buff64 = (UINT64*)&p[4096]; // 2k + m_write.dirty = true; + m_read.dirty = true; + + for(int i = 0; i < 16; i++) + { + for(int j = 0; j < 64; j++) + { + m_wc[0][i][j] = &GSClut::WriteCLUT_NULL; + m_wc[1][i][j] = &GSClut::WriteCLUT_NULL; + } + } + + m_wc[0][PSM_PSMCT32][PSM_PSMT8] = &GSClut::WriteCLUT32_I8_CSM1; + m_wc[0][PSM_PSMCT32][PSM_PSMT8H] = &GSClut::WriteCLUT32_I8_CSM1; + m_wc[0][PSM_PSMCT32][PSM_PSMT4] = &GSClut::WriteCLUT32_I4_CSM1; + m_wc[0][PSM_PSMCT32][PSM_PSMT4HL] = &GSClut::WriteCLUT32_I4_CSM1; + m_wc[0][PSM_PSMCT32][PSM_PSMT4HH] = &GSClut::WriteCLUT32_I4_CSM1; + m_wc[0][PSM_PSMCT24][PSM_PSMT8] = &GSClut::WriteCLUT32_I8_CSM1; + m_wc[0][PSM_PSMCT24][PSM_PSMT8H] = &GSClut::WriteCLUT32_I8_CSM1; + m_wc[0][PSM_PSMCT24][PSM_PSMT4] = &GSClut::WriteCLUT32_I4_CSM1; + m_wc[0][PSM_PSMCT24][PSM_PSMT4HL] = &GSClut::WriteCLUT32_I4_CSM1; + m_wc[0][PSM_PSMCT24][PSM_PSMT4HH] = &GSClut::WriteCLUT32_I4_CSM1; + m_wc[0][PSM_PSMCT16][PSM_PSMT8] = &GSClut::WriteCLUT16_I8_CSM1; + m_wc[0][PSM_PSMCT16][PSM_PSMT8H] = &GSClut::WriteCLUT16_I8_CSM1; + m_wc[0][PSM_PSMCT16][PSM_PSMT4] = &GSClut::WriteCLUT16_I4_CSM1; + m_wc[0][PSM_PSMCT16][PSM_PSMT4HL] = &GSClut::WriteCLUT16_I4_CSM1; + m_wc[0][PSM_PSMCT16][PSM_PSMT4HH] = &GSClut::WriteCLUT16_I4_CSM1; + m_wc[0][PSM_PSMCT16S][PSM_PSMT8] = &GSClut::WriteCLUT16S_I8_CSM1; + m_wc[0][PSM_PSMCT16S][PSM_PSMT8H] = &GSClut::WriteCLUT16S_I8_CSM1; + m_wc[0][PSM_PSMCT16S][PSM_PSMT4] = &GSClut::WriteCLUT16S_I4_CSM1; + m_wc[0][PSM_PSMCT16S][PSM_PSMT4HL] = &GSClut::WriteCLUT16S_I4_CSM1; + m_wc[0][PSM_PSMCT16S][PSM_PSMT4HH] = &GSClut::WriteCLUT16S_I4_CSM1; + + m_wc[1][PSM_PSMCT32][PSM_PSMT8] = &GSClut::WriteCLUT32_CSM2<256>; + m_wc[1][PSM_PSMCT32][PSM_PSMT8H] = &GSClut::WriteCLUT32_CSM2<256>; + m_wc[1][PSM_PSMCT32][PSM_PSMT4] = &GSClut::WriteCLUT32_CSM2<16>; + m_wc[1][PSM_PSMCT32][PSM_PSMT4HL] = &GSClut::WriteCLUT32_CSM2<16>; + m_wc[1][PSM_PSMCT32][PSM_PSMT4HH] = &GSClut::WriteCLUT32_CSM2<16>; + m_wc[1][PSM_PSMCT24][PSM_PSMT8] = &GSClut::WriteCLUT32_CSM2<256>; + m_wc[1][PSM_PSMCT24][PSM_PSMT8H] = &GSClut::WriteCLUT32_CSM2<256>; + m_wc[1][PSM_PSMCT24][PSM_PSMT4] = &GSClut::WriteCLUT32_CSM2<16>; + m_wc[1][PSM_PSMCT24][PSM_PSMT4HL] = &GSClut::WriteCLUT32_CSM2<16>; + m_wc[1][PSM_PSMCT24][PSM_PSMT4HH] = &GSClut::WriteCLUT32_CSM2<16>; + m_wc[1][PSM_PSMCT16][PSM_PSMT8] = &GSClut::WriteCLUT16_CSM2<256>; + m_wc[1][PSM_PSMCT16][PSM_PSMT8H] = &GSClut::WriteCLUT16_CSM2<256>; + m_wc[1][PSM_PSMCT16][PSM_PSMT4] = &GSClut::WriteCLUT16_CSM2<16>; + m_wc[1][PSM_PSMCT16][PSM_PSMT4HL] = &GSClut::WriteCLUT16_CSM2<16>; + m_wc[1][PSM_PSMCT16][PSM_PSMT4HH] = &GSClut::WriteCLUT16_CSM2<16>; + m_wc[1][PSM_PSMCT16S][PSM_PSMT8] = &GSClut::WriteCLUT16S_CSM2<256>; + m_wc[1][PSM_PSMCT16S][PSM_PSMT8H] = &GSClut::WriteCLUT16S_CSM2<256>; + m_wc[1][PSM_PSMCT16S][PSM_PSMT4] = &GSClut::WriteCLUT16S_CSM2<16>; + m_wc[1][PSM_PSMCT16S][PSM_PSMT4HL] = &GSClut::WriteCLUT16S_CSM2<16>; + m_wc[1][PSM_PSMCT16S][PSM_PSMT4HH] = &GSClut::WriteCLUT16S_CSM2<16>; +} + +GSClut::~GSClut() +{ + VirtualFree(m_clut, 0, MEM_RELEASE); +} + +void GSClut::Invalidate() +{ + m_write.dirty = true; +} + +bool GSClut::WriteTest(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) +{ + switch(TEX0.CLD) + { + case 0: return false; + case 1: break; + case 2: m_CBP[0] = TEX0.CBP; break; + case 3: m_CBP[1] = TEX0.CBP; break; + case 4: if(m_CBP[0] == TEX0.CBP) return false; m_CBP[0] = TEX0.CBP; break; + case 5: if(m_CBP[1] == TEX0.CBP) return false; m_CBP[1] = TEX0.CBP; break; + case 6: ASSERT(0); return false; + case 7: ASSERT(0); return false; + default: __assume(0); + } + + return m_write.IsDirty(TEX0, TEXCLUT); +} + +void GSClut::Write(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) +{ + m_write.TEX0 = TEX0; + m_write.TEXCLUT = TEXCLUT; + m_write.dirty = false; + m_read.dirty = true; + + (this->*m_wc[TEX0.CSM][TEX0.CPSM][TEX0.PSM])(TEX0, TEXCLUT); +} + +void GSClut::WriteCLUT32_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) +{ + ASSERT(TEX0.CSA == 0); + + WriteCLUT_T32_I8_CSM1(&m_mem->m_vm32[m_mem->BlockAddress32(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4)); +} + +void GSClut::WriteCLUT32_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) +{ + ASSERT(TEX0.CSA < 16); + + GSVector4i dummy; // this just forces stack alignment and enables inlining the next call + + WriteCLUT_T32_I4_CSM1(&m_mem->m_vm32[m_mem->BlockAddress32(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4)); +} + +void GSClut::WriteCLUT16_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) +{ + ASSERT(TEX0.CSA < 16); + + WriteCLUT_T16_I8_CSM1(&m_mem->m_vm16[m_mem->BlockAddress16(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4)); +} + +void GSClut::WriteCLUT16_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) +{ + ASSERT(TEX0.CSA < 32); + + WriteCLUT_T16_I4_CSM1(&m_mem->m_vm16[m_mem->BlockAddress16(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4)); +} + +void GSClut::WriteCLUT16S_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) +{ + WriteCLUT_T16_I8_CSM1(&m_mem->m_vm16[m_mem->BlockAddress16S(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4)); +} + +void GSClut::WriteCLUT16S_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) +{ + WriteCLUT_T16_I4_CSM1(&m_mem->m_vm16[m_mem->BlockAddress16S(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4)); +} + +template void GSClut::WriteCLUT32_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) +{ + WORD* RESTRICT clut = m_clut + (TEX0.CSA << 4); + + DWORD base = m_mem->PixelAddress32(0, TEXCLUT.COV, TEX0.CBP, TEXCLUT.CBW); + int* offset = &m_mem->rowOffset32[TEXCLUT.COU << 4]; + + for(int i = 0; i < n; i++) + { + DWORD c = m_mem->ReadPixel32(base + offset[i]); + + clut[i] = (WORD)(c & 0xffff); + clut[i + 256] = (WORD)(c >> 16); + } +} + +template void GSClut::WriteCLUT16_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) +{ + WORD* RESTRICT clut = m_clut + (TEX0.CSA << 4); + + DWORD base = m_mem->PixelAddress16(0, TEXCLUT.COV, TEX0.CBP, TEXCLUT.CBW); + int* offset = &m_mem->rowOffset16[TEXCLUT.COU << 4]; + + for(int i = 0; i < n; i++) + { + clut[i] = (WORD)m_mem->ReadPixel16(base + offset[i]); + } +} + +template void GSClut::WriteCLUT16S_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) +{ + WORD* RESTRICT clut = m_clut + (TEX0.CSA << 4); + + DWORD base = m_mem->PixelAddress16S(0, TEXCLUT.COV, TEX0.CBP, TEXCLUT.CBW); + int* offset = &m_mem->rowOffset16S[TEXCLUT.COU << 4]; + + for(int i = 0; i < n; i++) + { + clut[i] = (WORD)m_mem->ReadPixel16(base + offset[i]); + } +} + +void GSClut::Read(const GIFRegTEX0& TEX0) +{ + if(m_read.IsDirty(TEX0)) + { + m_read.TEX0 = TEX0; + m_read.dirty = false; + + WORD* clut = m_clut + (TEX0.CSA << 4); + + if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24) + { + switch(TEX0.PSM) + { + case PSM_PSMT8: + case PSM_PSMT8H: + ReadCLUT_T32_I8(clut, m_buff32); + break; + case PSM_PSMT4: + case PSM_PSMT4HL: + case PSM_PSMT4HH: + ReadCLUT_T32_I4(clut, m_buff32, m_buff64); + break; + } + } + else if(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S) + { + switch(TEX0.PSM) + { + case PSM_PSMT8: + case PSM_PSMT8H: + ReadCLUT_T16_I8(clut, m_buff32); + break; + case PSM_PSMT4: + case PSM_PSMT4HL: + case PSM_PSMT4HH: + ReadCLUT_T16_I4(clut, m_buff32, m_buff64); + break; + } + } + } +} + +void GSClut::Read32(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) +{ + if(m_read.IsDirty(TEX0, TEXA)) + { + m_read.TEX0 = TEX0; + m_read.TEXA = TEXA; + m_read.dirty = false; + m_read.adirty = true; + + WORD* clut = m_clut + (TEX0.CSA << 4); + + if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24) + { + switch(TEX0.PSM) + { + case PSM_PSMT8: + case PSM_PSMT8H: + ReadCLUT_T32_I8(clut, m_buff32); + break; + case PSM_PSMT4: + case PSM_PSMT4HL: + case PSM_PSMT4HH: + // TODO: merge these functions + ReadCLUT_T32_I4(clut, m_buff32); + ExpandCLUT64_T32_I8(m_buff32, (UINT64*)m_buff64); // sw renderer does not need m_buff64 anymore + break; + } + } + else if(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S) + { + switch(TEX0.PSM) + { + case PSM_PSMT8: + case PSM_PSMT8H: + Expand16(clut, m_buff32, 256, TEXA); + break; + case PSM_PSMT4: + case PSM_PSMT4HL: + case PSM_PSMT4HH: + // TODO: merge these functions + Expand16(clut, m_buff32, 16, TEXA); + ExpandCLUT64_T32_I8(m_buff32, (UINT64*)m_buff64); // sw renderer does not need m_buff64 anymore + break; + } + } + } +} + +void GSClut::GetAlphaMinMax32(int& amin, int& amax) +{ + // call only after Read32 + + ASSERT(!m_read.dirty); + + if(m_read.adirty) + { + m_read.adirty = false; + + // DWORD bpp = GSLocalMemory::m_psm[m_read.TEX0.PSM].trbpp; + DWORD cbpp = GSLocalMemory::m_psm[m_read.TEX0.CPSM].trbpp; + DWORD pal = GSLocalMemory::m_psm[m_read.TEX0.PSM].pal; + + if(cbpp == 24 && m_read.TEXA.AEM == 0) + { + m_read.amin = m_read.TEXA.TA0; + m_read.amax = m_read.TEXA.TA0; + } + else + { + int amin = 255; + int amax = 0; + + const GSVector4i* p = (const GSVector4i*)m_buff32; + + for(int i = 0, j = pal >> 4; i < j; i++) + { + GSVector4i v0 = (p[i * 4 + 0] >> 24).ps32(p[i * 4 + 1] >> 24); + GSVector4i v1 = (p[i * 4 + 2] >> 24).ps32(p[i * 4 + 3] >> 24); + + GSVector4i v2 = v0.min_i16(v1); + GSVector4i v3 = v0.max_i16(v1); + + v2 = v2.min_i16(v2.zwxy()); + v3 = v3.max_i16(v3.zwxy()); + v2 = v2.min_i16(v2.zwxyl()); + v3 = v3.max_i16(v3.zwxyl()); + v2 = v2.min_i16(v2.yxwzl()); + v3 = v3.max_i16(v3.yxwzl()); + + amin = min(amin, v2.extract16<0>()); + amax = max(amax, v3.extract16<0>()); + } + + m_read.amin = amin; + m_read.amax = amax; + } + } + + amin = m_read.amin; + amax = m_read.amax; +} + +// + +void GSClut::WriteCLUT_T32_I8_CSM1(const DWORD* RESTRICT src, WORD* RESTRICT clut) +{ + #if _M_SSE >= 0x200 + + for(int i = 0; i < 64; i += 16) + { + WriteCLUT_T32_I4_CSM1(&src[i + 0], &clut[i * 2 + 0]); + WriteCLUT_T32_I4_CSM1(&src[i + 64], &clut[i * 2 + 16]); + WriteCLUT_T32_I4_CSM1(&src[i + 128], &clut[i * 2 + 128]); + WriteCLUT_T32_I4_CSM1(&src[i + 192], &clut[i * 2 + 144]); + } + + #else + + for(int j = 0; j < 2; j++, src += 128, clut += 128) + { + for(int i = 0; i < 128; i++) + { + DWORD c = src[clutTableT32I8[i]]; + clut[i] = (WORD)(c & 0xffff); + clut[i + 256] = (WORD)(c >> 16); + } + } + + #endif +} + +__forceinline void GSClut::WriteCLUT_T32_I4_CSM1(const DWORD* RESTRICT src, WORD* RESTRICT clut) +{ + #if _M_SSE >= 0x200 + + GSVector4i* s = (GSVector4i*)src; + GSVector4i* d = (GSVector4i*)clut; + + GSVector4i v0 = s[0]; + GSVector4i v1 = s[1]; + GSVector4i v2 = s[2]; + GSVector4i v3 = s[3]; + + GSVector4i::sw64(v0, v1, v2, v3); + GSVector4i::sw16(v0, v1, v2, v3); + GSVector4i::sw16(v0, v2, v1, v3); + GSVector4i::sw16(v0, v1, v2, v3); + + d[0] = v0; + d[1] = v1; + d[32] = v2; + d[33] = v3; + + #else + + for(int i = 0; i < 16; i++) + { + DWORD c = src[clutTableT32I4[i]]; + clut[i] = (WORD)(c & 0xffff); + clut[i + 256] = (WORD)(c >> 16); + } + + #endif +} + +void GSClut::WriteCLUT_T16_I8_CSM1(const WORD* RESTRICT src, WORD* RESTRICT clut) +{ + #if _M_SSE >= 0x200 + + GSVector4i* s = (GSVector4i*)src; + GSVector4i* d = (GSVector4i*)clut; + + for(int i = 0; i < 32; i += 4) + { + GSVector4i v0 = s[i + 0]; + GSVector4i v1 = s[i + 1]; + GSVector4i v2 = s[i + 2]; + GSVector4i v3 = s[i + 3]; + + GSVector4i::sw16(v0, v1, v2, v3); + GSVector4i::sw32(v0, v1, v2, v3); + GSVector4i::sw16(v0, v2, v1, v3); + + d[i + 0] = v0; + d[i + 1] = v2; + d[i + 2] = v1; + d[i + 3] = v3; + } + + #else + + for(int j = 0; j < 8; j++, src += 32, clut += 32) + { + for(int i = 0; i < 32; i++) + { + clut[i] = src[clutTableT16I8[i]]; + } + } + + #endif +} + +__forceinline void GSClut::WriteCLUT_T16_I4_CSM1(const WORD* RESTRICT src, WORD* RESTRICT clut) +{ + for(int i = 0; i < 16; i++) + { + clut[i] = src[clutTableT16I4[i]]; + } +} + +void GSClut::ReadCLUT_T32_I8(const WORD* RESTRICT clut, DWORD* RESTRICT dst) +{ + #if _M_SSE >= 0x200 + + for(int i = 0; i < 256; i += 16) + { + ReadCLUT_T32_I4(&clut[i], &dst[i]); + } + + #else + + for(int i = 0; i < 256; i++) + { + dst[i] = ((DWORD)clut[i + 256] << 16) | clut[i]; + } + + #endif +} + +__forceinline void GSClut::ReadCLUT_T32_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst) +{ + #if _M_SSE >= 0x200 + + GSVector4i* s = (GSVector4i*)clut; + GSVector4i* d = (GSVector4i*)dst; + + GSVector4i v0 = s[0]; + GSVector4i v1 = s[1]; + GSVector4i v2 = s[32]; + GSVector4i v3 = s[33]; + + GSVector4i::sw16(v0, v2, v1, v3); + + d[0] = v0; + d[1] = v1; + d[2] = v2; + d[3] = v3; + + #else + + for(int i = 0; i < 16; i++) + { + dst[i] = ((DWORD)clut[i + 256] << 16) | clut[i]; + } + + #endif +} + +__forceinline void GSClut::ReadCLUT_T32_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst32, UINT64* RESTRICT dst64) +{ + #if _M_SSE >= 0x200 + + GSVector4i* s = (GSVector4i*)clut; + GSVector4i* d32 = (GSVector4i*)dst32; + GSVector4i* d64 = (GSVector4i*)dst64; + + GSVector4i s0 = s[0]; + GSVector4i s1 = s[1]; + GSVector4i s2 = s[32]; + GSVector4i s3 = s[33]; + + GSVector4i::sw16(s0, s2, s1, s3); + + d32[0] = s0; + d32[1] = s1; + d32[2] = s2; + d32[3] = s3; + + ExpandCLUT64_T32(s0, s0, s1, s2, s3, &d64[0]); + ExpandCLUT64_T32(s1, s0, s1, s2, s3, &d64[32]); + ExpandCLUT64_T32(s2, s0, s1, s2, s3, &d64[64]); + ExpandCLUT64_T32(s3, s0, s1, s2, s3, &d64[96]); + + #else + + for(int i = 0; i < 16; i++) + { + dst[i] = ((DWORD)clut[i + 256] << 16) | clut[i]; + } + + DWORD* d = (DWORD*)dst64; + + for(int j = 0; j < 16; j++, d += 32) + { + DWORD hi = dst32[j]; + + for(int i = 0; i < 16; i++) + { + d[i * 2 + 0] = dst32[i]; + d[i * 2 + 1] = hi; + } + } + + #endif +} + +void GSClut::ReadCLUT_T16_I8(const WORD* RESTRICT clut, DWORD* RESTRICT dst) +{ + #if _M_SSE >= 0x200 + + for(int i = 0; i < 256; i += 16) + { + ReadCLUT_T16_I4(&clut[i], &dst[i]); + } + + #else + + for(int i = 0; i < 256; i++) + { + dst[i] = (DWORD)clut[i]; + } + + #endif +} + +__forceinline void GSClut::ReadCLUT_T16_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst) +{ + #if _M_SSE >= 0x200 + + GSVector4i* s = (GSVector4i*)clut; + GSVector4i* d = (GSVector4i*)dst; + + GSVector4i v0 = s[0]; + GSVector4i v1 = s[1]; + + d[0] = v0.upl16(); + d[1] = v0.uph16(); + d[2] = v1.upl16(); + d[3] = v1.uph16(); + + #else + + for(int i = 0; i < 16; i++) + { + dst[i] = (DWORD)clut[i]; + } + + #endif +} + +__forceinline void GSClut::ReadCLUT_T16_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst32, UINT64* RESTRICT dst64) +{ + #if _M_SSE >= 0x200 + + GSVector4i* s = (GSVector4i*)clut; + GSVector4i* d32 = (GSVector4i*)dst32; + GSVector4i* d64 = (GSVector4i*)dst64; + + GSVector4i v0 = s[0]; + GSVector4i v1 = s[1]; + + GSVector4i s0 = v0.upl16(); + GSVector4i s1 = v0.uph16(); + GSVector4i s2 = v1.upl16(); + GSVector4i s3 = v1.uph16(); + + d32[0] = s0; + d32[1] = s1; + d32[2] = s2; + d32[3] = s3; + + ExpandCLUT64_T16(s0, s0, s1, s2, s3, &d64[0]); + ExpandCLUT64_T16(s1, s0, s1, s2, s3, &d64[32]); + ExpandCLUT64_T16(s2, s0, s1, s2, s3, &d64[64]); + ExpandCLUT64_T16(s3, s0, s1, s2, s3, &d64[96]); + + #else + + for(int i = 0; i < 16; i++) + { + dst32[i] = (DWORD)clut[i]; + } + + DWORD* d = (DWORD*)dst64; + + for(int j = 0; j < 16; j++, d += 32) + { + DWORD hi = dst32[j] << 16; + + for(int i = 0; i < 16; i++) + { + d[i * 2 + 0] = hi | (dst32[i] & 0xffff); + } + } + + #endif +} + +void GSClut::ExpandCLUT64_T32_I8(const DWORD* RESTRICT src, UINT64* RESTRICT dst) +{ + #if _M_SSE >= 0x200 + + GSVector4i* s = (GSVector4i*)src; + GSVector4i* d = (GSVector4i*)dst; + + GSVector4i s0 = s[0]; + GSVector4i s1 = s[1]; + GSVector4i s2 = s[2]; + GSVector4i s3 = s[3]; + + ExpandCLUT64_T32(s0, s0, s1, s2, s3, &d[0]); + ExpandCLUT64_T32(s1, s0, s1, s2, s3, &d[32]); + ExpandCLUT64_T32(s2, s0, s1, s2, s3, &d[64]); + ExpandCLUT64_T32(s3, s0, s1, s2, s3, &d[96]); + + #else + + DWORD* d = (DWORD*)dst; + + for(int j = 0; j < 16; j++, d += 32) + { + DWORD hi = src[j]; + + for(int i = 0; i < 16; i++) + { + d[i * 2 + 0] = src[i]; + d[i * 2 + 1] = hi; + } + } + + #endif +} + +__forceinline void GSClut::ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst) +{ + ExpandCLUT64_T32(hi.xxxx(), lo0, &dst[0]); + ExpandCLUT64_T32(hi.xxxx(), lo1, &dst[2]); + ExpandCLUT64_T32(hi.xxxx(), lo2, &dst[4]); + ExpandCLUT64_T32(hi.xxxx(), lo3, &dst[6]); + ExpandCLUT64_T32(hi.yyyy(), lo0, &dst[8]); + ExpandCLUT64_T32(hi.yyyy(), lo1, &dst[10]); + ExpandCLUT64_T32(hi.yyyy(), lo2, &dst[12]); + ExpandCLUT64_T32(hi.yyyy(), lo3, &dst[14]); + ExpandCLUT64_T32(hi.zzzz(), lo0, &dst[16]); + ExpandCLUT64_T32(hi.zzzz(), lo1, &dst[18]); + ExpandCLUT64_T32(hi.zzzz(), lo2, &dst[20]); + ExpandCLUT64_T32(hi.zzzz(), lo3, &dst[22]); + ExpandCLUT64_T32(hi.wwww(), lo0, &dst[24]); + ExpandCLUT64_T32(hi.wwww(), lo1, &dst[26]); + ExpandCLUT64_T32(hi.wwww(), lo2, &dst[28]); + ExpandCLUT64_T32(hi.wwww(), lo3, &dst[30]); +} + +__forceinline void GSClut::ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst) +{ + dst[0] = lo.upl32(hi); + dst[1] = lo.uph32(hi); +} + +void GSClut::ExpandCLUT64_T16_I8(const DWORD* RESTRICT src, UINT64* RESTRICT dst) +{ + #if _M_SSE >= 0x200 + + GSVector4i* s = (GSVector4i*)src; + GSVector4i* d = (GSVector4i*)dst; + + GSVector4i s0 = s[0]; + GSVector4i s1 = s[1]; + GSVector4i s2 = s[2]; + GSVector4i s3 = s[3]; + + ExpandCLUT64_T16(s0, s0, s1, s2, s3, &d[0]); + ExpandCLUT64_T16(s1, s0, s1, s2, s3, &d[32]); + ExpandCLUT64_T16(s2, s0, s1, s2, s3, &d[64]); + ExpandCLUT64_T16(s3, s0, s1, s2, s3, &d[96]); + + #else + + DWORD* d = (DWORD*)dst; + + for(int j = 0; j < 16; j++, d += 32) + { + DWORD hi = src[j] << 16; + + for(int i = 0; i < 16; i++) + { + d[i * 2 + 0] = hi | (src[i] & 0xffff); + } + } + + #endif +} + +__forceinline void GSClut::ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst) +{ + ExpandCLUT64_T16(hi.xxxx(), lo0, &dst[0]); + ExpandCLUT64_T16(hi.xxxx(), lo1, &dst[2]); + ExpandCLUT64_T16(hi.xxxx(), lo2, &dst[4]); + ExpandCLUT64_T16(hi.xxxx(), lo3, &dst[6]); + ExpandCLUT64_T16(hi.yyyy(), lo0, &dst[8]); + ExpandCLUT64_T16(hi.yyyy(), lo1, &dst[10]); + ExpandCLUT64_T16(hi.yyyy(), lo2, &dst[12]); + ExpandCLUT64_T16(hi.yyyy(), lo3, &dst[14]); + ExpandCLUT64_T16(hi.zzzz(), lo0, &dst[16]); + ExpandCLUT64_T16(hi.zzzz(), lo1, &dst[18]); + ExpandCLUT64_T16(hi.zzzz(), lo2, &dst[20]); + ExpandCLUT64_T16(hi.zzzz(), lo3, &dst[22]); + ExpandCLUT64_T16(hi.wwww(), lo0, &dst[24]); + ExpandCLUT64_T16(hi.wwww(), lo1, &dst[26]); + ExpandCLUT64_T16(hi.wwww(), lo2, &dst[28]); + ExpandCLUT64_T16(hi.wwww(), lo3, &dst[30]); +} + +__forceinline void GSClut::ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst) +{ + dst[0] = lo.upl16(hi); + dst[1] = lo.uph16(hi); +} + +// TODO + +static const GSVector4i s_am(0x00008000); +static const GSVector4i s_bm(0x00007c00); +static const GSVector4i s_gm(0x000003e0); +static const GSVector4i s_rm(0x0000001f); + +void GSClut::Expand16(const WORD* RESTRICT src, DWORD* RESTRICT dst, int w, const GIFRegTEXA& TEXA) +{ + #if _M_SSE >= 0x200 + + ASSERT((w & 7) == 0); + + const GSVector4i rm = s_rm; + const GSVector4i gm = s_gm; + const GSVector4i bm = s_bm; + // const GSVector4i am = s_am; + + GSVector4i TA0(TEXA.TA0 << 24); + GSVector4i TA1(TEXA.TA1 << 24); + + GSVector4i c, cl, ch; + + const GSVector4i* s = (const GSVector4i*)src; + GSVector4i* d = (GSVector4i*)dst; + + if(!TEXA.AEM) + { + for(int i = 0, j = w >> 3; i < j; i++) + { + c = s[i]; + /* + cl = c.upl16(); + ch = c.uph16(); + d[i * 2 + 0] = ((cl & rm) << 3) | ((cl & gm) << 6) | ((cl & bm) << 9) | TA1.blend(TA0, cl < am); + d[i * 2 + 1] = ((ch & rm) << 3) | ((ch & gm) << 6) | ((ch & bm) << 9) | TA1.blend(TA0, ch < am); + */ + cl = c.upl16(c); + ch = c.uph16(c); + d[i * 2 + 0] = ((cl & rm) << 3) | ((cl & gm) << 6) | ((cl & bm) << 9) | TA0.blend8(TA1, cl.sra16(15)); + d[i * 2 + 1] = ((ch & rm) << 3) | ((ch & gm) << 6) | ((ch & bm) << 9) | TA0.blend8(TA1, ch.sra16(15)); + } + } + else + { + for(int i = 0, j = w >> 3; i < j; i++) + { + c = s[i]; + /* + cl = c.upl16(); + ch = c.uph16(); + d[i * 2 + 0] = ((cl & rm) << 3) | ((cl & gm) << 6) | ((cl & bm) << 9) | TA1.blend(TA0, cl < am).andnot(cl == GSVector4i::zero()); + d[i * 2 + 1] = ((ch & rm) << 3) | ((ch & gm) << 6) | ((ch & bm) << 9) | TA1.blend(TA0, ch < am).andnot(ch == GSVector4i::zero()); + */ + cl = c.upl16(c); + ch = c.uph16(c); + d[i * 2 + 0] = ((cl & rm) << 3) | ((cl & gm) << 6) | ((cl & bm) << 9) | TA0.blend8(TA1, cl.sra16(15)).andnot(cl == GSVector4i::zero()); + d[i * 2 + 1] = ((ch & rm) << 3) | ((ch & gm) << 6) | ((ch & bm) << 9) | TA0.blend8(TA1, ch.sra16(15)).andnot(ch == GSVector4i::zero()); + } + } + + #else + + DWORD TA0 = (DWORD)TEXA.TA0 << 24; + DWORD TA1 = (DWORD)TEXA.TA1 << 24; + + if(!TEXA.AEM) + { + for(int i = 0; i < w; i++) + { + dst[i] = ((src[i] & 0x8000) ? TA1 : TA0) | ((src[i] & 0x7c00) << 9) | ((src[i] & 0x03e0) << 6) | ((src[i] & 0x001f) << 3); + } + } + else + { + for(int i = 0; i < w; i++) + { + dst[i] = ((src[i] & 0x8000) ? TA1 : src[i] ? TA0 : 0) | ((src[i] & 0x7c00) << 9) | ((src[i] & 0x03e0) << 6) | ((src[i] & 0x001f) << 3); + } + } + + #endif +} + +// + +bool GSClut::WriteState::IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) +{ + return dirty || !(GSVector4i::load(this) == GSVector4i::load(&TEX0, &TEXCLUT)).alltrue(); +} + +bool GSClut::ReadState::IsDirty(const GIFRegTEX0& TEX0) +{ + return dirty || !(GSVector4i::load(this) == GSVector4i::load(&TEX0, &this->TEXA)).alltrue(); +} + +bool GSClut::ReadState::IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) +{ + return dirty || !(GSVector4i::load(this) == GSVector4i::load(&TEX0, &TEXA)).alltrue(); +} diff --git a/plugins/GSdx/GSClut.h b/plugins/GSdx/GSClut.h index 98f34d8538..9c7fa4241a 100644 --- a/plugins/GSdx/GSClut.h +++ b/plugins/GSdx/GSClut.h @@ -1,110 +1,110 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GS.h" -#include "GSVector.h" -#include "GSTables.h" -#include "GSAlignedClass.h" - -class GSLocalMemory; - -__declspec(align(16)) class GSClut : public GSAlignedClass<16> -{ - const GSLocalMemory* m_mem; - - DWORD m_CBP[2]; - WORD* m_clut; - DWORD* m_buff32; - UINT64* m_buff64; - - __declspec(align(16)) struct WriteState - { - GIFRegTEX0 TEX0; - GIFRegTEXCLUT TEXCLUT; - bool dirty; - bool IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); - } m_write; - - __declspec(align(16)) struct ReadState - { - GIFRegTEX0 TEX0; - GIFRegTEXA TEXA; - bool dirty; - bool adirty; - int amin, amax; - bool IsDirty(const GIFRegTEX0& TEX0); - bool IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA); - } m_read; - - typedef void (GSClut::*writeCLUT)(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); - - writeCLUT m_wc[2][16][64]; - - void WriteCLUT32_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); - void WriteCLUT32_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); - void WriteCLUT16_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); - void WriteCLUT16_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); - void WriteCLUT16S_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); - void WriteCLUT16S_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); - - template void WriteCLUT32_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); - template void WriteCLUT16_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); - template void WriteCLUT16S_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); - - void WriteCLUT_NULL(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) {} - - static void WriteCLUT_T32_I8_CSM1(const DWORD* RESTRICT src, WORD* RESTRICT clut); - static void WriteCLUT_T32_I4_CSM1(const DWORD* RESTRICT src, WORD* RESTRICT clut); - static void WriteCLUT_T16_I8_CSM1(const WORD* RESTRICT src, WORD* RESTRICT clut); - static void WriteCLUT_T16_I4_CSM1(const WORD* RESTRICT src, WORD* RESTRICT clut); - static void ReadCLUT_T32_I8(const WORD* RESTRICT clut, DWORD* RESTRICT dst); - static void ReadCLUT_T32_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst); - static void ReadCLUT_T32_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst32, UINT64* RESTRICT dst64); - static void ReadCLUT_T16_I8(const WORD* RESTRICT clut, DWORD* RESTRICT dst); - static void ReadCLUT_T16_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst); - static void ReadCLUT_T16_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst32, UINT64* RESTRICT dst64); - static void ExpandCLUT64_T32_I8(const DWORD* RESTRICT src, UINT64* RESTRICT dst); - static void ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst); - static void ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst); - static void ExpandCLUT64_T16_I8(const DWORD* RESTRICT src, UINT64* RESTRICT dst); - static void ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst); - static void ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst); - - static void Expand16(const WORD* RESTRICT src, DWORD* RESTRICT dst, int w, const GIFRegTEXA& TEXA); - -public: - GSClut(const GSLocalMemory* mem); - virtual ~GSClut(); - - void Invalidate(); - bool WriteTest(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); - void Write(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); - void Read(const GIFRegTEX0& TEX0); - void Read32(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA); - void GetAlphaMinMax32(int& amin, int& amax); - - DWORD operator [] (size_t i) const {return m_buff32[i];} - - operator const DWORD*() const {return m_buff32;} - operator const UINT64*() const {return m_buff64;} -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GS.h" +#include "GSVector.h" +#include "GSTables.h" +#include "GSAlignedClass.h" + +class GSLocalMemory; + +__declspec(align(16)) class GSClut : public GSAlignedClass<16> +{ + const GSLocalMemory* m_mem; + + DWORD m_CBP[2]; + WORD* m_clut; + DWORD* m_buff32; + UINT64* m_buff64; + + __declspec(align(16)) struct WriteState + { + GIFRegTEX0 TEX0; + GIFRegTEXCLUT TEXCLUT; + bool dirty; + bool IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); + } m_write; + + __declspec(align(16)) struct ReadState + { + GIFRegTEX0 TEX0; + GIFRegTEXA TEXA; + bool dirty; + bool adirty; + int amin, amax; + bool IsDirty(const GIFRegTEX0& TEX0); + bool IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA); + } m_read; + + typedef void (GSClut::*writeCLUT)(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); + + writeCLUT m_wc[2][16][64]; + + void WriteCLUT32_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); + void WriteCLUT32_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); + void WriteCLUT16_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); + void WriteCLUT16_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); + void WriteCLUT16S_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); + void WriteCLUT16S_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); + + template void WriteCLUT32_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); + template void WriteCLUT16_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); + template void WriteCLUT16S_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); + + void WriteCLUT_NULL(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) {} + + static void WriteCLUT_T32_I8_CSM1(const DWORD* RESTRICT src, WORD* RESTRICT clut); + static void WriteCLUT_T32_I4_CSM1(const DWORD* RESTRICT src, WORD* RESTRICT clut); + static void WriteCLUT_T16_I8_CSM1(const WORD* RESTRICT src, WORD* RESTRICT clut); + static void WriteCLUT_T16_I4_CSM1(const WORD* RESTRICT src, WORD* RESTRICT clut); + static void ReadCLUT_T32_I8(const WORD* RESTRICT clut, DWORD* RESTRICT dst); + static void ReadCLUT_T32_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst); + static void ReadCLUT_T32_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst32, UINT64* RESTRICT dst64); + static void ReadCLUT_T16_I8(const WORD* RESTRICT clut, DWORD* RESTRICT dst); + static void ReadCLUT_T16_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst); + static void ReadCLUT_T16_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst32, UINT64* RESTRICT dst64); + static void ExpandCLUT64_T32_I8(const DWORD* RESTRICT src, UINT64* RESTRICT dst); + static void ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst); + static void ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst); + static void ExpandCLUT64_T16_I8(const DWORD* RESTRICT src, UINT64* RESTRICT dst); + static void ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst); + static void ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst); + + static void Expand16(const WORD* RESTRICT src, DWORD* RESTRICT dst, int w, const GIFRegTEXA& TEXA); + +public: + GSClut(const GSLocalMemory* mem); + virtual ~GSClut(); + + void Invalidate(); + bool WriteTest(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); + void Write(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); + void Read(const GIFRegTEX0& TEX0); + void Read32(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA); + void GetAlphaMinMax32(int& amin, int& amax); + + DWORD operator [] (size_t i) const {return m_buff32[i];} + + operator const DWORD*() const {return m_buff32;} + operator const UINT64*() const {return m_buff64;} +}; diff --git a/plugins/GSdx/GSCrc.cpp b/plugins/GSdx/GSCrc.cpp index 96d37f5a83..dfa3d1cec9 100644 --- a/plugins/GSdx/GSCrc.cpp +++ b/plugins/GSdx/GSCrc.cpp @@ -1,143 +1,143 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSCrc.h" - -CRC::Game CRC::m_games[] = -{ - {0x00000000, None, Unknown, false}, - {0x2113EA2E, MetalSlug6, Unknown, false}, - {0x42E05BAF, TomoyoAfter, JP, false}, - {0x7800DC84, Clannad, JP, false}, - {0xa39517ab, FFX, EU, true}, - {0xa39517ae, FFX, FR, true}, - {0x941bb7d9, FFX, DE, true}, - {0xa39517a9, FFX, IT, true}, - {0x941bb7de, FFX, ES, true}, - {0xb4414ea1, FFX, RU, true}, - {0xee97db5b, FFX, RU, true}, - {0xaec495cc, FFX, RU, true}, - {0xbb3d833a, FFX, US, true}, - {0x6a4efe60, FFX, JP, true}, - {0x3866ca7e, FFX, ASIA, true}, // int. - {0x658597e2, FFX, JP, true}, // int. - {0x9aac5309, FFX2, EU, true}, - {0x9aac530c, FFX2, FR, true}, - {0x9aac530a, FFX2, FR, true}, // ? - {0x9aac530d, FFX2, DE, true}, - {0x9aac530b, FFX2, IT, true}, - {0x48fe0c71, FFX2, US, true}, - {0xe1fd9a2d, FFX2, JP, true}, // int. - {0x78da0252, FFXII, EU, false}, - {0xc1274668, FFXII, EU, false}, - {0xdc2a467e, FFXII, EU, false}, - {0xca284668, FFXII, EU, false}, - {0x280AD120, FFXII, JP, false}, - {0x8BE3D7B2, ShadowHearts, Unknown, false}, - {0xDEFA4763, ShadowHearts, US, false}, - {0x21068223, Okami, US, false}, - {0x891f223f, Okami, FR, false}, - {0xC5DEFEA0, Okami, JP, false}, - {0x053D2239, MetalGearSolid3, US, false}, - {0x086273D2, MetalGearSolid3, FR, false}, - {0x26A6E286, MetalGearSolid3, EU, false}, - {0xAA31B5BF, MetalGearSolid3, Unknown, false}, - {0x9F185CE1, MetalGearSolid3, Unknown, false}, - {0x98D4BC93, MetalGearSolid3, EU, false}, - {0x86BC3040, MetalGearSolid3, US, false}, //Subsistance disc 1 - {0x0481AD8A, MetalGearSolid3, JP, false}, - {0x278722BF, DBZBT2, US, false}, - {0xFE961D28, DBZBT2, US, false}, - {0x0393B6BE, DBZBT2, EU, false}, - {0xE2F289ED, DBZBT2, JP, false}, // Sparking Neo! - {0x35AA84D1, DBZBT2, Unknown, false}, - {0x428113C2, DBZBT3, US, false}, - {0xA422BB13, DBZBT3, EU, false}, - {0x983c53d2, DBZBT3, Unknown, false}, - {0x72B3802A, SFEX3, US, false}, - {0x71521863, SFEX3, US, false}, - {0x28703748, Bully, US, false}, - {0xC78A495D, BullyCC, US, false}, - {0xC19A374E, SoTC, US, false}, - {0x7D8F539A, SoTC, EU, false}, - {0x3122B508, OnePieceGrandAdventure, US, false}, - {0x6F8545DB, ICO, US, false}, - {0xB01A4C95, ICO, JP, false}, - {0x5C991F4E, ICO, Unknown, false}, - {0xAEAD1CA3, GT4, JP, false}, - {0x44A61C8F, GT4, Unknown, false}, - {0x0086E35B, GT4, Unknown, false}, - {0x77E61C8A, GT4, Unknown, false}, - {0xC164550A, WildArms5, JPUNDUB, false}, - {0xC1640D2C, WildArms5, US, false}, - {0x0FCF8FE4, WildArms5, EU, false}, - {0x2294D322, WildArms5, JP, false}, - {0x565B6170, WildArms5, JP, false}, - {0x8B029334, Manhunt2, Unknown, false}, - {0x09F49E37, CrashBandicootWoC, Unknown, false}, - {0x013E349D, ResidentEvil4, US, false}, - {0x6BA2F6B9, ResidentEvil4, Unknown, false}, - {0x60FA8C69, ResidentEvil4, JP, false}, - {0x72E1E60E, Spartan, Unknown, false}, - {0x5ED8FB53, AceCombat4, JP, false}, - {0x1B9B7563, AceCombat4, Unknown, false}, - {0xEC432B24, Drakengard2, Unknown, false}, - {0xFC46EA61, Tekken5, JP, false}, - {0x1F88EE37, Tekken5, Unknown, false}, - {0x652050D2, Tekken5, Unknown, false}, - {0x9E98B8AE, IkkiTousen, JP, false}, - {0xD6385328, GodOfWar, US, false}, - {0xFB0E6D72, GodOfWar, EU, false}, - {0xA61A4C6D, GodOfWar, Unknown, false}, - {0xE23D532B, GodOfWar, Unknown, false}, - {0x2F123FD8, GodOfWar2, RU, false}, - {0x5D482F18, JackieChanAdv, Unknown, false}, - {0xf0a6d880, HarvestMoon, US, true}, - {0x75c01a04, NamcoXCapcom, US, false}, - {0xBF6F101F, GiTS, US, false}, - {0xA5768F53, GiTS, JP, false}, - {0x6BF11378, Onimusha3, US, false}, - {0xF442260C, MajokkoALaMode2, JP, false}, - {0x14FE77F7, TalesOfAbyss, US, false}, - {0x045D77E9, TalesOfAbyss, US, false}, // undub - {0xAA5EC3A3, TalesOfAbyss, JP, false}, -}; - -CAtlMap CRC::m_map; - -CRC::Game CRC::Lookup(DWORD crc) -{ - if(m_map.IsEmpty()) - { - for(int i = 0; i < countof(m_games); i++) - { - m_map[m_games[i].crc] = &m_games[i]; - } - } - - if(CAtlMap::CPair* pair = m_map.Lookup(crc)) - { - return *pair->m_value; - } - - return m_games[0]; -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSCrc.h" + +CRC::Game CRC::m_games[] = +{ + {0x00000000, None, Unknown, false}, + {0x2113EA2E, MetalSlug6, Unknown, false}, + {0x42E05BAF, TomoyoAfter, JP, false}, + {0x7800DC84, Clannad, JP, false}, + {0xa39517ab, FFX, EU, true}, + {0xa39517ae, FFX, FR, true}, + {0x941bb7d9, FFX, DE, true}, + {0xa39517a9, FFX, IT, true}, + {0x941bb7de, FFX, ES, true}, + {0xb4414ea1, FFX, RU, true}, + {0xee97db5b, FFX, RU, true}, + {0xaec495cc, FFX, RU, true}, + {0xbb3d833a, FFX, US, true}, + {0x6a4efe60, FFX, JP, true}, + {0x3866ca7e, FFX, ASIA, true}, // int. + {0x658597e2, FFX, JP, true}, // int. + {0x9aac5309, FFX2, EU, true}, + {0x9aac530c, FFX2, FR, true}, + {0x9aac530a, FFX2, FR, true}, // ? + {0x9aac530d, FFX2, DE, true}, + {0x9aac530b, FFX2, IT, true}, + {0x48fe0c71, FFX2, US, true}, + {0xe1fd9a2d, FFX2, JP, true}, // int. + {0x78da0252, FFXII, EU, false}, + {0xc1274668, FFXII, EU, false}, + {0xdc2a467e, FFXII, EU, false}, + {0xca284668, FFXII, EU, false}, + {0x280AD120, FFXII, JP, false}, + {0x8BE3D7B2, ShadowHearts, Unknown, false}, + {0xDEFA4763, ShadowHearts, US, false}, + {0x21068223, Okami, US, false}, + {0x891f223f, Okami, FR, false}, + {0xC5DEFEA0, Okami, JP, false}, + {0x053D2239, MetalGearSolid3, US, false}, + {0x086273D2, MetalGearSolid3, FR, false}, + {0x26A6E286, MetalGearSolid3, EU, false}, + {0xAA31B5BF, MetalGearSolid3, Unknown, false}, + {0x9F185CE1, MetalGearSolid3, Unknown, false}, + {0x98D4BC93, MetalGearSolid3, EU, false}, + {0x86BC3040, MetalGearSolid3, US, false}, //Subsistance disc 1 + {0x0481AD8A, MetalGearSolid3, JP, false}, + {0x278722BF, DBZBT2, US, false}, + {0xFE961D28, DBZBT2, US, false}, + {0x0393B6BE, DBZBT2, EU, false}, + {0xE2F289ED, DBZBT2, JP, false}, // Sparking Neo! + {0x35AA84D1, DBZBT2, Unknown, false}, + {0x428113C2, DBZBT3, US, false}, + {0xA422BB13, DBZBT3, EU, false}, + {0x983c53d2, DBZBT3, Unknown, false}, + {0x72B3802A, SFEX3, US, false}, + {0x71521863, SFEX3, US, false}, + {0x28703748, Bully, US, false}, + {0xC78A495D, BullyCC, US, false}, + {0xC19A374E, SoTC, US, false}, + {0x7D8F539A, SoTC, EU, false}, + {0x3122B508, OnePieceGrandAdventure, US, false}, + {0x6F8545DB, ICO, US, false}, + {0xB01A4C95, ICO, JP, false}, + {0x5C991F4E, ICO, Unknown, false}, + {0xAEAD1CA3, GT4, JP, false}, + {0x44A61C8F, GT4, Unknown, false}, + {0x0086E35B, GT4, Unknown, false}, + {0x77E61C8A, GT4, Unknown, false}, + {0xC164550A, WildArms5, JPUNDUB, false}, + {0xC1640D2C, WildArms5, US, false}, + {0x0FCF8FE4, WildArms5, EU, false}, + {0x2294D322, WildArms5, JP, false}, + {0x565B6170, WildArms5, JP, false}, + {0x8B029334, Manhunt2, Unknown, false}, + {0x09F49E37, CrashBandicootWoC, Unknown, false}, + {0x013E349D, ResidentEvil4, US, false}, + {0x6BA2F6B9, ResidentEvil4, Unknown, false}, + {0x60FA8C69, ResidentEvil4, JP, false}, + {0x72E1E60E, Spartan, Unknown, false}, + {0x5ED8FB53, AceCombat4, JP, false}, + {0x1B9B7563, AceCombat4, Unknown, false}, + {0xEC432B24, Drakengard2, Unknown, false}, + {0xFC46EA61, Tekken5, JP, false}, + {0x1F88EE37, Tekken5, Unknown, false}, + {0x652050D2, Tekken5, Unknown, false}, + {0x9E98B8AE, IkkiTousen, JP, false}, + {0xD6385328, GodOfWar, US, false}, + {0xFB0E6D72, GodOfWar, EU, false}, + {0xA61A4C6D, GodOfWar, Unknown, false}, + {0xE23D532B, GodOfWar, Unknown, false}, + {0x2F123FD8, GodOfWar2, RU, false}, + {0x5D482F18, JackieChanAdv, Unknown, false}, + {0xf0a6d880, HarvestMoon, US, true}, + {0x75c01a04, NamcoXCapcom, US, false}, + {0xBF6F101F, GiTS, US, false}, + {0xA5768F53, GiTS, JP, false}, + {0x6BF11378, Onimusha3, US, false}, + {0xF442260C, MajokkoALaMode2, JP, false}, + {0x14FE77F7, TalesOfAbyss, US, false}, + {0x045D77E9, TalesOfAbyss, US, false}, // undub + {0xAA5EC3A3, TalesOfAbyss, JP, false}, +}; + +CAtlMap CRC::m_map; + +CRC::Game CRC::Lookup(DWORD crc) +{ + if(m_map.IsEmpty()) + { + for(int i = 0; i < countof(m_games); i++) + { + m_map[m_games[i].crc] = &m_games[i]; + } + } + + if(CAtlMap::CPair* pair = m_map.Lookup(crc)) + { + return *pair->m_value; + } + + return m_games[0]; +} diff --git a/plugins/GSdx/GSCrc.h b/plugins/GSdx/GSCrc.h index ec637787eb..89efaf71d8 100644 --- a/plugins/GSdx/GSCrc.h +++ b/plugins/GSdx/GSCrc.h @@ -1,98 +1,98 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -class CRC -{ -public: - enum Title - { - None, - MetalSlug6, - TomoyoAfter, - Clannad, - FFX, - FFX2, - FFXII, - ShadowHearts, - Okami, - MetalGearSolid3, - DBZBT2, - DBZBT3, - SFEX3, - Bully, - BullyCC, - SoTC, - OnePieceGrandAdventure, - ICO, - GT4, - WildArms5, - Manhunt2, - CrashBandicootWoC, - ResidentEvil4, - Spartan, - AceCombat4, - Drakengard2, - Tekken5, - IkkiTousen, - GodOfWar, - GodOfWar2, - JackieChanAdv, - HarvestMoon, - NamcoXCapcom, - GiTS, - Onimusha3, - MajokkoALaMode2, - TalesOfAbyss, - TitleCount - }; - - enum Region - { - Unknown, - US, - EU, - JP, - JPUNDUB, - RU, - FR, - DE, - IT, - ES, - ASIA - }; - - struct Game - { - DWORD crc; - Title title; - Region region; - bool nloophack; - }; - -private: - static Game m_games[]; - static CAtlMap m_map; - -public: - static Game Lookup(DWORD crc); -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +class CRC +{ +public: + enum Title + { + None, + MetalSlug6, + TomoyoAfter, + Clannad, + FFX, + FFX2, + FFXII, + ShadowHearts, + Okami, + MetalGearSolid3, + DBZBT2, + DBZBT3, + SFEX3, + Bully, + BullyCC, + SoTC, + OnePieceGrandAdventure, + ICO, + GT4, + WildArms5, + Manhunt2, + CrashBandicootWoC, + ResidentEvil4, + Spartan, + AceCombat4, + Drakengard2, + Tekken5, + IkkiTousen, + GodOfWar, + GodOfWar2, + JackieChanAdv, + HarvestMoon, + NamcoXCapcom, + GiTS, + Onimusha3, + MajokkoALaMode2, + TalesOfAbyss, + TitleCount + }; + + enum Region + { + Unknown, + US, + EU, + JP, + JPUNDUB, + RU, + FR, + DE, + IT, + ES, + ASIA + }; + + struct Game + { + DWORD crc; + Title title; + Region region; + bool nloophack; + }; + +private: + static Game m_games[]; + static CAtlMap m_map; + +public: + static Game Lookup(DWORD crc); +}; diff --git a/plugins/GSdx/GSDevice.cpp b/plugins/GSdx/GSDevice.cpp index a421ba71f2..fe40a0da83 100644 --- a/plugins/GSdx/GSDevice.cpp +++ b/plugins/GSdx/GSDevice.cpp @@ -1,23 +1,23 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSDevice.h" +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSDevice.h" diff --git a/plugins/GSdx/GSDevice.h b/plugins/GSdx/GSDevice.h index cb07eb2af0..e21f5ffdc4 100644 --- a/plugins/GSdx/GSDevice.h +++ b/plugins/GSdx/GSDevice.h @@ -1,244 +1,244 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSTexture.h" -#include "GSVertex.h" - -#pragma pack(push, 1) - -struct MergeConstantBuffer -{ - GSVector4 BGColor; - - struct MergeConstantBuffer() {memset(this, 0, sizeof(*this));} -}; - -struct InterlaceConstantBuffer -{ - GSVector2 ZrH; - float hH; - float _pad[1]; - - struct InterlaceConstantBuffer() {memset(this, 0, sizeof(*this));} -}; - -#pragma pack(pop) - -template class GSDevice -{ - CAtlList m_pool; - -protected: - HWND m_hWnd; - bool m_vsync; - Texture m_backbuffer; - Texture m_merge; - Texture m_weavebob; - Texture m_blend; - Texture m_1x1; - Texture m_current; - - bool Fetch(int type, Texture& t, int w, int h, int format) - { - Recycle(t); - - for(POSITION pos = m_pool.GetHeadPosition(); pos; m_pool.GetNext(pos)) - { - const Texture& t2 = m_pool.GetAt(pos); - - if(t2.GetType() == type && t2.GetWidth() == w && t2.GetHeight() == h && t2.GetFormat() == format) - { - t = t2; - - m_pool.RemoveAt(pos); - - return true; - } - } - - return Create(type, t, w, h, format); - } - - virtual bool Create(int type, Texture& t, int w, int h, int format) = 0; - virtual void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c) = 0; - virtual void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset) = 0; - -public: - GSDevice() : m_hWnd(NULL) - { - } - - virtual ~GSDevice() - { - } - - virtual bool Create(HWND hWnd, bool vsync) - { - m_hWnd = hWnd; - m_vsync = vsync; - - return true; - } - - virtual bool Reset(int w, int h, bool fs) - { - m_pool.RemoveAll(); - m_backbuffer = Texture(); - m_merge = Texture(); - m_weavebob = Texture(); - m_blend = Texture(); - m_1x1 = Texture(); - m_current = Texture(); - - return true; - } - - virtual bool IsLost() = 0; - - virtual void Present(const CRect& r) = 0; - - virtual void BeginScene() = 0; - - virtual void EndScene() = 0; - - virtual void Draw(LPCTSTR str) = 0; - - virtual bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0) = 0; - - virtual void ClearRenderTarget(Texture& t, const GSVector4& c) = 0; - - virtual void ClearRenderTarget(Texture& t, DWORD c) = 0; - - virtual void ClearDepth(Texture& t, float c) = 0; - - virtual void ClearStencil(Texture& t, BYTE c) = 0; - - virtual bool CreateRenderTarget(Texture& t, int w, int h, int format = 0) - { - return Fetch(GSTexture::RenderTarget, t, w, h, format); - } - - virtual bool CreateDepthStencil(Texture& t, int w, int h, int format = 0) - { - return Fetch(GSTexture::DepthStencil, t, w, h, format); - } - - virtual bool CreateTexture(Texture& t, int w, int h, int format = 0) - { - return Fetch(GSTexture::Texture, t, w, h, format); - } - - virtual bool CreateOffscreen(Texture& t, int w, int h, int format = 0) - { - return Fetch(GSTexture::Offscreen, t, w, h, format); - } - - void Recycle(Texture& t) - { - if(t) - { - m_pool.AddHead(t); - - while(m_pool.GetCount() > 200) - { - m_pool.RemoveTail(); - } - - t = Texture(); - } - } - - bool SaveCurrent(LPCTSTR fn) - { - return m_current.Save(fn); - } - - void GetCurrent(Texture& t) - { - t = m_current; - } - - void Merge(Texture* st, GSVector4* sr, GSVector4* dr, CSize fs, bool slbg, bool mmod, GSVector4& c) - { - if(!m_merge || m_merge.GetWidth() != fs.cx || m_merge.GetHeight() != fs.cy) - { - CreateRenderTarget(m_merge, fs.cx, fs.cy); - } - - // TODO: m_1x1 - - DoMerge(st, sr, dr, m_merge, slbg, mmod, c); - - m_current = m_merge; - } - - bool Interlace(CSize ds, int field, int mode, float yoffset) - { - if(!m_weavebob || m_weavebob.GetWidth() != ds.cx || m_weavebob.GetHeight() != ds.cy) - { - CreateRenderTarget(m_weavebob, ds.cx, ds.cy); - } - - if(mode == 0 || mode == 2) // weave or blend - { - // weave first - - DoInterlace(m_merge, m_weavebob, field, false, 0); - - if(mode == 2) - { - // blend - - if(!m_blend || m_blend.GetWidth() != ds.cx || m_blend.GetHeight() != ds.cy) - { - CreateRenderTarget(m_blend, ds.cx, ds.cy); - } - - DoInterlace(m_weavebob, m_blend, 2, false, 0); - - m_current = m_blend; - } - else - { - m_current = m_weavebob; - } - } - else if(mode == 1) // bob - { - DoInterlace(m_merge, m_weavebob, 3, true, yoffset * field); - - m_current = m_weavebob; - } - else - { - m_current = m_merge; - } - - return true; - } - - virtual bool IsCurrentRGBA() - { - return true; - } -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSTexture.h" +#include "GSVertex.h" + +#pragma pack(push, 1) + +struct MergeConstantBuffer +{ + GSVector4 BGColor; + + struct MergeConstantBuffer() {memset(this, 0, sizeof(*this));} +}; + +struct InterlaceConstantBuffer +{ + GSVector2 ZrH; + float hH; + float _pad[1]; + + struct InterlaceConstantBuffer() {memset(this, 0, sizeof(*this));} +}; + +#pragma pack(pop) + +template class GSDevice +{ + CAtlList m_pool; + +protected: + HWND m_hWnd; + bool m_vsync; + Texture m_backbuffer; + Texture m_merge; + Texture m_weavebob; + Texture m_blend; + Texture m_1x1; + Texture m_current; + + bool Fetch(int type, Texture& t, int w, int h, int format) + { + Recycle(t); + + for(POSITION pos = m_pool.GetHeadPosition(); pos; m_pool.GetNext(pos)) + { + const Texture& t2 = m_pool.GetAt(pos); + + if(t2.GetType() == type && t2.GetWidth() == w && t2.GetHeight() == h && t2.GetFormat() == format) + { + t = t2; + + m_pool.RemoveAt(pos); + + return true; + } + } + + return Create(type, t, w, h, format); + } + + virtual bool Create(int type, Texture& t, int w, int h, int format) = 0; + virtual void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c) = 0; + virtual void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset) = 0; + +public: + GSDevice() : m_hWnd(NULL) + { + } + + virtual ~GSDevice() + { + } + + virtual bool Create(HWND hWnd, bool vsync) + { + m_hWnd = hWnd; + m_vsync = vsync; + + return true; + } + + virtual bool Reset(int w, int h, bool fs) + { + m_pool.RemoveAll(); + m_backbuffer = Texture(); + m_merge = Texture(); + m_weavebob = Texture(); + m_blend = Texture(); + m_1x1 = Texture(); + m_current = Texture(); + + return true; + } + + virtual bool IsLost() = 0; + + virtual void Present(const CRect& r) = 0; + + virtual void BeginScene() = 0; + + virtual void EndScene() = 0; + + virtual void Draw(LPCTSTR str) = 0; + + virtual bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0) = 0; + + virtual void ClearRenderTarget(Texture& t, const GSVector4& c) = 0; + + virtual void ClearRenderTarget(Texture& t, DWORD c) = 0; + + virtual void ClearDepth(Texture& t, float c) = 0; + + virtual void ClearStencil(Texture& t, BYTE c) = 0; + + virtual bool CreateRenderTarget(Texture& t, int w, int h, int format = 0) + { + return Fetch(GSTexture::RenderTarget, t, w, h, format); + } + + virtual bool CreateDepthStencil(Texture& t, int w, int h, int format = 0) + { + return Fetch(GSTexture::DepthStencil, t, w, h, format); + } + + virtual bool CreateTexture(Texture& t, int w, int h, int format = 0) + { + return Fetch(GSTexture::Texture, t, w, h, format); + } + + virtual bool CreateOffscreen(Texture& t, int w, int h, int format = 0) + { + return Fetch(GSTexture::Offscreen, t, w, h, format); + } + + void Recycle(Texture& t) + { + if(t) + { + m_pool.AddHead(t); + + while(m_pool.GetCount() > 200) + { + m_pool.RemoveTail(); + } + + t = Texture(); + } + } + + bool SaveCurrent(LPCTSTR fn) + { + return m_current.Save(fn); + } + + void GetCurrent(Texture& t) + { + t = m_current; + } + + void Merge(Texture* st, GSVector4* sr, GSVector4* dr, CSize fs, bool slbg, bool mmod, GSVector4& c) + { + if(!m_merge || m_merge.GetWidth() != fs.cx || m_merge.GetHeight() != fs.cy) + { + CreateRenderTarget(m_merge, fs.cx, fs.cy); + } + + // TODO: m_1x1 + + DoMerge(st, sr, dr, m_merge, slbg, mmod, c); + + m_current = m_merge; + } + + bool Interlace(CSize ds, int field, int mode, float yoffset) + { + if(!m_weavebob || m_weavebob.GetWidth() != ds.cx || m_weavebob.GetHeight() != ds.cy) + { + CreateRenderTarget(m_weavebob, ds.cx, ds.cy); + } + + if(mode == 0 || mode == 2) // weave or blend + { + // weave first + + DoInterlace(m_merge, m_weavebob, field, false, 0); + + if(mode == 2) + { + // blend + + if(!m_blend || m_blend.GetWidth() != ds.cx || m_blend.GetHeight() != ds.cy) + { + CreateRenderTarget(m_blend, ds.cx, ds.cy); + } + + DoInterlace(m_weavebob, m_blend, 2, false, 0); + + m_current = m_blend; + } + else + { + m_current = m_weavebob; + } + } + else if(mode == 1) // bob + { + DoInterlace(m_merge, m_weavebob, 3, true, yoffset * field); + + m_current = m_weavebob; + } + else + { + m_current = m_merge; + } + + return true; + } + + virtual bool IsCurrentRGBA() + { + return true; + } +}; diff --git a/plugins/GSdx/GSDevice10.cpp b/plugins/GSdx/GSDevice10.cpp index 15a3326161..5cd874a69d 100644 --- a/plugins/GSdx/GSDevice10.cpp +++ b/plugins/GSdx/GSDevice10.cpp @@ -1,833 +1,833 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GSDevice10.h" -#include "resource.h" - -GSDevice10::GSDevice10() - : m_vb(NULL) - , m_vb_stride(0) - , m_layout(NULL) - , m_topology(D3D10_PRIMITIVE_TOPOLOGY_UNDEFINED) - , m_vs(NULL) - , m_vs_cb(NULL) - , m_gs(NULL) - , m_ps(NULL) - , m_ps_cb(NULL) - , m_scissor(0, 0, 0, 0) - , m_viewport(0, 0) - , m_dss(NULL) - , m_sref(0) - , m_bs(NULL) - , m_bf(-1) - , m_rtv(NULL) - , m_dsv(NULL) -{ - memset(m_ps_srv, 0, sizeof(m_ps_srv)); - memset(m_ps_ss, 0, sizeof(m_ps_ss)); -} - -GSDevice10::~GSDevice10() -{ -} - -bool GSDevice10::Create(HWND hWnd, bool vsync) -{ - if(!__super::Create(hWnd, vsync)) - { - return false; - } - - HRESULT hr; - - DXGI_SWAP_CHAIN_DESC scd; - D3D10_BUFFER_DESC bd; - D3D10_SAMPLER_DESC sd; - D3D10_DEPTH_STENCIL_DESC dsd; - D3D10_RASTERIZER_DESC rd; - D3D10_BLEND_DESC bsd; - - memset(&scd, 0, sizeof(scd)); - - scd.BufferCount = 2; - scd.BufferDesc.Width = 1; - scd.BufferDesc.Height = 1; - scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - //scd.BufferDesc.RefreshRate.Numerator = 60; - //scd.BufferDesc.RefreshRate.Denominator = 1; - scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - scd.OutputWindow = hWnd; - scd.SampleDesc.Count = 1; - scd.SampleDesc.Quality = 0; - scd.Windowed = TRUE; - - UINT flags = 0; - -#ifdef DEBUG - flags |= D3D10_CREATE_DEVICE_DEBUG; -#endif - - hr = D3D10CreateDeviceAndSwapChain(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, flags, D3D10_SDK_VERSION, &scd, &m_swapchain, &m_dev); - - if(FAILED(hr)) return false; - - // font -/* - // TODO: the driver crashes on alt-enter when using a font... - - D3DX10_FONT_DESC fd; - memset(&fd, 0, sizeof(fd)); - _tcscpy(fd.FaceName, _T("Arial")); - fd.Height = 20; - D3DX10CreateFontIndirect(m_dev, &fd, &m_font); -*/ - // convert - - D3D10_INPUT_ELEMENT_DESC il_convert[] = - { - {"POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0}, - {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D10_INPUT_PER_VERTEX_DATA, 0}, - }; - - hr = CompileShader(IDR_CONVERT10_FX, "vs_main", NULL, &m_convert.vs, il_convert, countof(il_convert), &m_convert.il); - - for(int i = 0; i < countof(m_convert.ps); i++) - { - CStringA main; - main.Format("ps_main%d", i); - hr = CompileShader(IDR_CONVERT10_FX, main, NULL, &m_convert.ps[i]); - } - - memset(&bd, 0, sizeof(bd)); - - bd.Usage = D3D10_USAGE_DEFAULT; - bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; - bd.CPUAccessFlags = 0; - bd.MiscFlags = 0; - bd.ByteWidth = 4 * sizeof(GSVertexPT1); - - hr = m_dev->CreateBuffer(&bd, NULL, &m_convert.vb); - - memset(&dsd, 0, sizeof(dsd)); - - dsd.DepthEnable = false; - dsd.StencilEnable = false; - - hr = m_dev->CreateDepthStencilState(&dsd, &m_convert.dss); - - memset(&bsd, 0, sizeof(bsd)); - - bsd.BlendEnable[0] = false; - bsd.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL; - - hr = m_dev->CreateBlendState(&bsd, &m_convert.bs); - - // merge - - memset(&bd, 0, sizeof(bd)); - - bd.ByteWidth = sizeof(MergeConstantBuffer); - bd.Usage = D3D10_USAGE_DEFAULT; - bd.BindFlags = D3D10_BIND_CONSTANT_BUFFER; - bd.CPUAccessFlags = 0; - bd.MiscFlags = 0; - - hr = m_dev->CreateBuffer(&bd, NULL, &m_merge.cb); - - for(int i = 0; i < countof(m_merge.ps); i++) - { - CStringA main; - main.Format("ps_main%d", i); - hr = CompileShader(IDR_MERGE10_FX, main, NULL, &m_merge.ps[i]); - } - - memset(&bsd, 0, sizeof(bsd)); - - bsd.BlendEnable[0] = true; - bsd.BlendOp = D3D10_BLEND_OP_ADD; - bsd.SrcBlend = D3D10_BLEND_SRC_ALPHA; - bsd.DestBlend = D3D10_BLEND_INV_SRC_ALPHA; - bsd.BlendOpAlpha = D3D10_BLEND_OP_ADD; - bsd.SrcBlendAlpha = D3D10_BLEND_ONE; - bsd.DestBlendAlpha = D3D10_BLEND_ZERO; - bsd.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL; - - hr = m_dev->CreateBlendState(&bsd, &m_merge.bs); - - // interlace - - memset(&bd, 0, sizeof(bd)); - - bd.ByteWidth = sizeof(InterlaceConstantBuffer); - bd.Usage = D3D10_USAGE_DEFAULT; - bd.BindFlags = D3D10_BIND_CONSTANT_BUFFER; - bd.CPUAccessFlags = 0; - bd.MiscFlags = 0; - - hr = m_dev->CreateBuffer(&bd, NULL, &m_interlace.cb); - - for(int i = 0; i < countof(m_interlace.ps); i++) - { - CStringA main; - main.Format("ps_main%d", i); - hr = CompileShader(IDR_INTERLACE10_FX, main, NULL, &m_interlace.ps[i]); - } - - // - - memset(&rd, 0, sizeof(rd)); - - rd.FillMode = D3D10_FILL_SOLID; - rd.CullMode = D3D10_CULL_NONE; - rd.FrontCounterClockwise = false; - rd.DepthBias = false; - rd.DepthBiasClamp = 0; - rd.SlopeScaledDepthBias = 0; - rd.DepthClipEnable = false; // ??? - rd.ScissorEnable = true; - rd.MultisampleEnable = false; - rd.AntialiasedLineEnable = false; - - hr = m_dev->CreateRasterizerState(&rd, &m_rs); - - m_dev->RSSetState(m_rs); - - // - - memset(&sd, 0, sizeof(sd)); - - sd.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR; - sd.AddressU = D3D10_TEXTURE_ADDRESS_CLAMP; - sd.AddressV = D3D10_TEXTURE_ADDRESS_CLAMP; - sd.AddressW = D3D10_TEXTURE_ADDRESS_CLAMP; - sd.MaxLOD = FLT_MAX; - sd.MaxAnisotropy = 16; - sd.ComparisonFunc = D3D10_COMPARISON_NEVER; - - hr = m_dev->CreateSamplerState(&sd, &m_convert.ln); - - sd.Filter = D3D10_FILTER_MIN_MAG_MIP_POINT; - - hr = m_dev->CreateSamplerState(&sd, &m_convert.pt); - - // - - Reset(1, 1, true); - - // -/* - if(!m_mergefx.Create(this)) - { - return false; - } -*/ - // - - return true; -} - -bool GSDevice10::Reset(int w, int h, bool fs) -{ - if(!__super::Reset(w, h, fs)) - return false; - - DXGI_SWAP_CHAIN_DESC scd; - memset(&scd, 0, sizeof(scd)); - m_swapchain->GetDesc(&scd); - m_swapchain->ResizeBuffers(scd.BufferCount, w, h, scd.BufferDesc.Format, 0); - - CComPtr backbuffer; - m_swapchain->GetBuffer(0, __uuidof(ID3D10Texture2D), (void**)&backbuffer); - m_backbuffer = Texture(backbuffer); - - return true; -} - -void GSDevice10::Present(const CRect& r) -{ - CRect cr; - - GetClientRect(m_hWnd, &cr); - - if(m_backbuffer.GetWidth() != cr.Width() || m_backbuffer.GetHeight() != cr.Height()) - { - Reset(cr.Width(), cr.Height(), false); - } - - float color[4] = {0, 0, 0, 0}; - - m_dev->ClearRenderTargetView(m_backbuffer, color); - - if(m_current) - { - StretchRect(m_current, m_backbuffer, GSVector4(r)); - } - - m_swapchain->Present(m_vsync ? 1 : 0, 0); -} - -void GSDevice10::BeginScene() -{ -} - -void GSDevice10::EndScene() -{ - PSSetShaderResources(NULL, NULL); - - // not clearing the rt/ds gives a little fps boost in complex games (5-10%) - - // OMSetRenderTargets(NULL, NULL); -} - -void GSDevice10::Draw(LPCTSTR str) -{ - /* - BOOL fs; - CComPtr target; - - m_swapchain->GetFullscreenState(&fs, &target); - - if(fs) - { - BeginScene(); - - OMSetRenderTargets(m_backbuffer, NULL); - - CRect r(0, 0, m_backbuffer.GetWidth(), m_backbuffer.GetHeight()); - - D3DCOLOR c = D3DCOLOR_ARGB(255, 0, 255, 0); - - if(m_font->DrawText(NULL, str, -1, &r, DT_CALCRECT|DT_LEFT|DT_WORDBREAK, c)) - { - m_font->DrawText(NULL, str, -1, &r, DT_LEFT|DT_WORDBREAK, c); - } - - EndScene(); - } - */ -} - -bool GSDevice10::CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format) -{ - dst = Texture(); - - if(format == 0) - { - format = DXGI_FORMAT_R8G8B8A8_UNORM; - } - - if(format != DXGI_FORMAT_R8G8B8A8_UNORM && format != DXGI_FORMAT_R16_UINT) - { - ASSERT(0); - - return false; - } - - Texture rt; - - if(CreateRenderTarget(rt, w, h, format)) - { - GSVector4 dr(0, 0, w, h); - - StretchRect(src, sr, rt, dr, m_convert.ps[format == DXGI_FORMAT_R16_UINT ? 1 : 0], NULL); - - if(CreateOffscreen(dst, w, h, format)) - { - m_dev->CopyResource(dst, rt); - } - } - - Recycle(rt); - - return !!dst; -} - -void GSDevice10::ClearRenderTarget(Texture& t, const GSVector4& c) -{ - m_dev->ClearRenderTargetView(t, c.v); -} - -void GSDevice10::ClearRenderTarget(Texture& t, DWORD c) -{ - GSVector4 color = GSVector4(c) * (1.0f / 255); - - m_dev->ClearRenderTargetView(t, color.v); -} - -void GSDevice10::ClearDepth(Texture& t, float c) -{ - m_dev->ClearDepthStencilView(t, D3D10_CLEAR_DEPTH, c, 0); -} - -void GSDevice10::ClearStencil(Texture& t, BYTE c) -{ - m_dev->ClearDepthStencilView(t, D3D10_CLEAR_STENCIL, 0, c); -} - -bool GSDevice10::Create(int type, Texture& t, int w, int h, int format) -{ - HRESULT hr; - - D3D10_TEXTURE2D_DESC desc; - - memset(&desc, 0, sizeof(desc)); - - desc.Width = w; - desc.Height = h; - desc.Format = (DXGI_FORMAT)format; - desc.MipLevels = 1; - desc.ArraySize = 1; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D10_USAGE_DEFAULT; - - switch(type) - { - case GSTexture::RenderTarget: - desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; - break; - case GSTexture::DepthStencil: - desc.BindFlags = D3D10_BIND_DEPTH_STENCIL; - break; - case GSTexture::Texture: - desc.BindFlags = D3D10_BIND_SHADER_RESOURCE; - break; - case GSTexture::Offscreen: - desc.Usage = D3D10_USAGE_STAGING; - desc.CPUAccessFlags |= D3D10_CPU_ACCESS_READ | D3D10_CPU_ACCESS_WRITE; - break; - } - - CComPtr texture; - - hr = m_dev->CreateTexture2D(&desc, NULL, &texture); - - if(SUCCEEDED(hr)) - { - t = Texture(texture); - - switch(type) - { - case GSTexture::RenderTarget: - ClearRenderTarget(t, 0); - break; - case GSTexture::DepthStencil: - ClearDepth(t, 0); - break; - } - - return true; - } - - return false; -} - -bool GSDevice10::CreateRenderTarget(Texture& t, int w, int h, int format) -{ - return __super::CreateRenderTarget(t, w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM); -} - -bool GSDevice10::CreateDepthStencil(Texture& t, int w, int h, int format) -{ - return __super::CreateDepthStencil(t, w, h, format ? format : DXGI_FORMAT_D32_FLOAT_S8X24_UINT); -} - -bool GSDevice10::CreateTexture(Texture& t, int w, int h, int format) -{ - return __super::CreateTexture(t, w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM); -} - -bool GSDevice10::CreateOffscreen(Texture& t, int w, int h, int format) -{ - return __super::CreateOffscreen(t, w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM); -} - -void GSDevice10::DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c) -{ - ClearRenderTarget(dt, c); - - if(st[1] && !slbg) - { - StretchRect(st[1], sr[1], dt, dr[1], m_merge.ps[0], NULL, true); - } - - if(st[0]) - { - m_dev->UpdateSubresource(m_merge.cb, 0, NULL, &c, 0, 0); - - StretchRect(st[0], sr[0], dt, dr[0], m_merge.ps[mmod ? 1 : 0], m_merge.cb, m_merge.bs, true); - } -} - -void GSDevice10::DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset) -{ - GSVector4 sr(0, 0, 1, 1); - GSVector4 dr(0.0f, yoffset, (float)dt.GetWidth(), (float)dt.GetHeight() + yoffset); - - InterlaceConstantBuffer cb; - - cb.ZrH = GSVector2(0, 1.0f / dt.GetHeight()); - cb.hH = (float)dt.GetHeight() / 2; - - m_dev->UpdateSubresource(m_interlace.cb, 0, NULL, &cb, 0, 0); - - StretchRect(st, sr, dt, dr, m_interlace.ps[shader], m_interlace.cb, linear); -} - -void GSDevice10::IASetVertexBuffer(ID3D10Buffer* vb, UINT stride) -{ - if(m_vb != vb || m_vb_stride != stride) - { - UINT offset = 0; - - m_dev->IASetVertexBuffers(0, 1, &vb, &stride, &offset); - - m_vb = vb; - m_vb_stride = stride; - } -} - -void GSDevice10::IASetInputLayout(ID3D10InputLayout* layout) -{ - if(m_layout != layout) - { - m_dev->IASetInputLayout(layout); - - m_layout = layout; - } -} - -void GSDevice10::IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY topology) -{ - if(m_topology != topology) - { - m_dev->IASetPrimitiveTopology(topology); - - m_topology = topology; - } -} - -void GSDevice10::VSSetShader(ID3D10VertexShader* vs, ID3D10Buffer* vs_cb) -{ - if(m_vs != vs) - { - m_dev->VSSetShader(vs); - - m_vs = vs; - } - - if(m_vs_cb != vs_cb) - { - m_dev->VSSetConstantBuffers(0, 1, &vs_cb); - - m_vs_cb = vs_cb; - } -} - -void GSDevice10::GSSetShader(ID3D10GeometryShader* gs) -{ - if(m_gs != gs) - { - m_dev->GSSetShader(gs); - - m_gs = gs; - } -} - -void GSDevice10::PSSetShaderResources(ID3D10ShaderResourceView* srv0, ID3D10ShaderResourceView* srv1) -{ - if(m_ps_srv[0] != srv0 || m_ps_srv[1] != srv1) - { - ID3D10ShaderResourceView* srvs[] = {srv0, srv1}; - - m_dev->PSSetShaderResources(0, 2, srvs); - - m_ps_srv[0] = srv0; - m_ps_srv[1] = srv1; - } -} - -void GSDevice10::PSSetShader(ID3D10PixelShader* ps, ID3D10Buffer* ps_cb) -{ - if(m_ps != ps) - { - m_dev->PSSetShader(ps); - - m_ps = ps; - } - - if(m_ps_cb != ps_cb) - { - m_dev->PSSetConstantBuffers(0, 1, &ps_cb); - - m_ps_cb = ps_cb; - } -} - -void GSDevice10::PSSetSamplerState(ID3D10SamplerState* ss0, ID3D10SamplerState* ss1) -{ - if(m_ps_ss[0] != ss0 || m_ps_ss[1] != ss1) - { - ID3D10SamplerState* sss[] = {ss0, ss1}; - - m_dev->PSSetSamplers(0, 2, sss); - - m_ps_ss[0] = ss0; - m_ps_ss[1] = ss1; - } -} - -void GSDevice10::RSSet(int width, int height, const RECT* scissor) -{ - if(m_viewport.cx != width || m_viewport.cy != height) - { - D3D10_VIEWPORT vp; - - memset(&vp, 0, sizeof(vp)); - - vp.TopLeftX = 0; - vp.TopLeftY = 0; - vp.Width = width; - vp.Height = height; - vp.MinDepth = 0.0f; - vp.MaxDepth = 1.0f; - - m_dev->RSSetViewports(1, &vp); - - m_viewport = CSize(width, height); - } - - CRect r = scissor ? *scissor : CRect(0, 0, width, height); - - if(m_scissor != r) - { - m_dev->RSSetScissorRects(1, &r); - - m_scissor = r; - } -} - -void GSDevice10::OMSetDepthStencilState(ID3D10DepthStencilState* dss, UINT sref) -{ - if(m_dss != dss || m_sref != sref) - { - m_dev->OMSetDepthStencilState(dss, sref); - - m_dss = dss; - m_sref = sref; - } -} - -void GSDevice10::OMSetBlendState(ID3D10BlendState* bs, float bf) -{ - if(m_bs != bs || m_bf != bf) - { - float BlendFactor[] = {bf, bf, bf, 0}; - - m_dev->OMSetBlendState(bs, BlendFactor, 0xffffffff); - - m_bs = bs; - m_bf = bf; - } -} - -void GSDevice10::OMSetRenderTargets(ID3D10RenderTargetView* rtv, ID3D10DepthStencilView* dsv) -{ - if(m_rtv != rtv || m_dsv != dsv) - { - m_dev->OMSetRenderTargets(1, &rtv, dsv); - - m_rtv = rtv; - m_dsv = dsv; - } -} - -void GSDevice10::DrawPrimitive(UINT count, UINT start) -{ - m_dev->Draw(count, start); -} - -void GSDevice10::StretchRect(Texture& st, Texture& dt, const GSVector4& dr, bool linear) -{ - StretchRect(st, GSVector4(0, 0, 1, 1), dt, dr, linear); -} - -void GSDevice10::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, bool linear) -{ - StretchRect(st, sr, dt, dr, m_convert.ps[0], NULL, linear); -} - -void GSDevice10::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, bool linear) -{ - StretchRect(st, sr, dt, dr, ps, ps_cb, m_convert.bs, linear); -} - -void GSDevice10::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, ID3D10BlendState* bs, bool linear) -{ - BeginScene(); - - // om - - OMSetDepthStencilState(m_convert.dss, 0); - OMSetBlendState(bs, 0); - OMSetRenderTargets(dt, NULL); - - // ia - - float left = dr.x * 2 / dt.GetWidth() - 1.0f; - float top = 1.0f - dr.y * 2 / dt.GetHeight(); - float right = dr.z * 2 / dt.GetWidth() - 1.0f; - float bottom = 1.0f - dr.w * 2 / dt.GetHeight(); - - GSVertexPT1 vertices[] = - { - {GSVector4(left, top, 0.5f, 1.0f), GSVector2(sr.x, sr.y)}, - {GSVector4(right, top, 0.5f, 1.0f), GSVector2(sr.z, sr.y)}, - {GSVector4(left, bottom, 0.5f, 1.0f), GSVector2(sr.x, sr.w)}, - {GSVector4(right, bottom, 0.5f, 1.0f), GSVector2(sr.z, sr.w)}, - }; - - D3D10_BOX box = {0, 0, 0, sizeof(vertices), 1, 1}; - - m_dev->UpdateSubresource(m_convert.vb, 0, &box, vertices, 0, 0); - - IASetVertexBuffer(m_convert.vb, sizeof(vertices[0])); - IASetInputLayout(m_convert.il); - IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - - // vs - - VSSetShader(m_convert.vs, NULL); - - // gs - - GSSetShader(NULL); - - // ps - - PSSetShader(ps, ps_cb); - PSSetSamplerState(linear ? m_convert.ln : m_convert.pt, NULL); - PSSetShaderResources(st, NULL); - - // rs - - RSSet(dt.GetWidth(), dt.GetHeight()); - - // - - DrawPrimitive(countof(vertices)); - - // - - EndScene(); -} - -HRESULT GSDevice10::CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10VertexShader** ps, D3D10_INPUT_ELEMENT_DESC* layout, int count, ID3D10InputLayout** il) -{ - HRESULT hr; - - CComPtr shader, error; - - hr = D3DX10CompileFromResource(AfxGetInstanceHandle(), MAKEINTRESOURCE(id), NULL, macro, NULL, entry, "vs_4_0", 0, 0, NULL, &shader, &error, NULL); - - if(error) - { - TRACE(_T("%s\n"), CString((LPCSTR)error->GetBufferPointer())); - } - - if(FAILED(hr)) - { - return hr; - } - - hr = m_dev->CreateVertexShader((DWORD*)shader->GetBufferPointer(), shader->GetBufferSize(), ps); - - if(FAILED(hr)) - { - return hr; - } - - hr = m_dev->CreateInputLayout(layout, count, shader->GetBufferPointer(), shader->GetBufferSize(), il); - - if(FAILED(hr)) - { - return hr; - } - - return hr; -} - -HRESULT GSDevice10::CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10GeometryShader** gs) -{ - HRESULT hr; - - CComPtr shader, error; - - hr = D3DX10CompileFromResource(AfxGetInstanceHandle(), MAKEINTRESOURCE(id), NULL, macro, NULL, entry, "gs_4_0", 0, 0, NULL, &shader, &error, NULL); - - if(error) - { - TRACE(_T("%s\n"), CString((LPCSTR)error->GetBufferPointer())); - } - - if(FAILED(hr)) - { - return hr; - } - - hr = m_dev->CreateGeometryShader((DWORD*)shader->GetBufferPointer(), shader->GetBufferSize(), gs); - - if(FAILED(hr)) - { - return hr; - } - - return hr; -} - -HRESULT GSDevice10::CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10PixelShader** ps) -{ - HRESULT hr; - - CComPtr shader, error; - - hr = D3DX10CompileFromResource(AfxGetInstanceHandle(), MAKEINTRESOURCE(id), NULL, macro, NULL, entry, "ps_4_0", 0, 0, NULL, &shader, &error, NULL); - - if(error) - { - TRACE(_T("%s\n"), CString((LPCSTR)error->GetBufferPointer())); - } - - if(FAILED(hr)) - { - return hr; - } - - hr = m_dev->CreatePixelShader((DWORD*)shader->GetBufferPointer(), shader->GetBufferSize(), ps); - - if(FAILED(hr)) - { - return hr; - } - - return hr; -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSDevice10.h" +#include "resource.h" + +GSDevice10::GSDevice10() + : m_vb(NULL) + , m_vb_stride(0) + , m_layout(NULL) + , m_topology(D3D10_PRIMITIVE_TOPOLOGY_UNDEFINED) + , m_vs(NULL) + , m_vs_cb(NULL) + , m_gs(NULL) + , m_ps(NULL) + , m_ps_cb(NULL) + , m_scissor(0, 0, 0, 0) + , m_viewport(0, 0) + , m_dss(NULL) + , m_sref(0) + , m_bs(NULL) + , m_bf(-1) + , m_rtv(NULL) + , m_dsv(NULL) +{ + memset(m_ps_srv, 0, sizeof(m_ps_srv)); + memset(m_ps_ss, 0, sizeof(m_ps_ss)); +} + +GSDevice10::~GSDevice10() +{ +} + +bool GSDevice10::Create(HWND hWnd, bool vsync) +{ + if(!__super::Create(hWnd, vsync)) + { + return false; + } + + HRESULT hr; + + DXGI_SWAP_CHAIN_DESC scd; + D3D10_BUFFER_DESC bd; + D3D10_SAMPLER_DESC sd; + D3D10_DEPTH_STENCIL_DESC dsd; + D3D10_RASTERIZER_DESC rd; + D3D10_BLEND_DESC bsd; + + memset(&scd, 0, sizeof(scd)); + + scd.BufferCount = 2; + scd.BufferDesc.Width = 1; + scd.BufferDesc.Height = 1; + scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + //scd.BufferDesc.RefreshRate.Numerator = 60; + //scd.BufferDesc.RefreshRate.Denominator = 1; + scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + scd.OutputWindow = hWnd; + scd.SampleDesc.Count = 1; + scd.SampleDesc.Quality = 0; + scd.Windowed = TRUE; + + UINT flags = 0; + +#ifdef DEBUG + flags |= D3D10_CREATE_DEVICE_DEBUG; +#endif + + hr = D3D10CreateDeviceAndSwapChain(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, flags, D3D10_SDK_VERSION, &scd, &m_swapchain, &m_dev); + + if(FAILED(hr)) return false; + + // font +/* + // TODO: the driver crashes on alt-enter when using a font... + + D3DX10_FONT_DESC fd; + memset(&fd, 0, sizeof(fd)); + _tcscpy(fd.FaceName, _T("Arial")); + fd.Height = 20; + D3DX10CreateFontIndirect(m_dev, &fd, &m_font); +*/ + // convert + + D3D10_INPUT_ELEMENT_DESC il_convert[] = + { + {"POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0}, + {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D10_INPUT_PER_VERTEX_DATA, 0}, + }; + + hr = CompileShader(IDR_CONVERT10_FX, "vs_main", NULL, &m_convert.vs, il_convert, countof(il_convert), &m_convert.il); + + for(int i = 0; i < countof(m_convert.ps); i++) + { + CStringA main; + main.Format("ps_main%d", i); + hr = CompileShader(IDR_CONVERT10_FX, main, NULL, &m_convert.ps[i]); + } + + memset(&bd, 0, sizeof(bd)); + + bd.Usage = D3D10_USAGE_DEFAULT; + bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; + bd.CPUAccessFlags = 0; + bd.MiscFlags = 0; + bd.ByteWidth = 4 * sizeof(GSVertexPT1); + + hr = m_dev->CreateBuffer(&bd, NULL, &m_convert.vb); + + memset(&dsd, 0, sizeof(dsd)); + + dsd.DepthEnable = false; + dsd.StencilEnable = false; + + hr = m_dev->CreateDepthStencilState(&dsd, &m_convert.dss); + + memset(&bsd, 0, sizeof(bsd)); + + bsd.BlendEnable[0] = false; + bsd.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL; + + hr = m_dev->CreateBlendState(&bsd, &m_convert.bs); + + // merge + + memset(&bd, 0, sizeof(bd)); + + bd.ByteWidth = sizeof(MergeConstantBuffer); + bd.Usage = D3D10_USAGE_DEFAULT; + bd.BindFlags = D3D10_BIND_CONSTANT_BUFFER; + bd.CPUAccessFlags = 0; + bd.MiscFlags = 0; + + hr = m_dev->CreateBuffer(&bd, NULL, &m_merge.cb); + + for(int i = 0; i < countof(m_merge.ps); i++) + { + CStringA main; + main.Format("ps_main%d", i); + hr = CompileShader(IDR_MERGE10_FX, main, NULL, &m_merge.ps[i]); + } + + memset(&bsd, 0, sizeof(bsd)); + + bsd.BlendEnable[0] = true; + bsd.BlendOp = D3D10_BLEND_OP_ADD; + bsd.SrcBlend = D3D10_BLEND_SRC_ALPHA; + bsd.DestBlend = D3D10_BLEND_INV_SRC_ALPHA; + bsd.BlendOpAlpha = D3D10_BLEND_OP_ADD; + bsd.SrcBlendAlpha = D3D10_BLEND_ONE; + bsd.DestBlendAlpha = D3D10_BLEND_ZERO; + bsd.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL; + + hr = m_dev->CreateBlendState(&bsd, &m_merge.bs); + + // interlace + + memset(&bd, 0, sizeof(bd)); + + bd.ByteWidth = sizeof(InterlaceConstantBuffer); + bd.Usage = D3D10_USAGE_DEFAULT; + bd.BindFlags = D3D10_BIND_CONSTANT_BUFFER; + bd.CPUAccessFlags = 0; + bd.MiscFlags = 0; + + hr = m_dev->CreateBuffer(&bd, NULL, &m_interlace.cb); + + for(int i = 0; i < countof(m_interlace.ps); i++) + { + CStringA main; + main.Format("ps_main%d", i); + hr = CompileShader(IDR_INTERLACE10_FX, main, NULL, &m_interlace.ps[i]); + } + + // + + memset(&rd, 0, sizeof(rd)); + + rd.FillMode = D3D10_FILL_SOLID; + rd.CullMode = D3D10_CULL_NONE; + rd.FrontCounterClockwise = false; + rd.DepthBias = false; + rd.DepthBiasClamp = 0; + rd.SlopeScaledDepthBias = 0; + rd.DepthClipEnable = false; // ??? + rd.ScissorEnable = true; + rd.MultisampleEnable = false; + rd.AntialiasedLineEnable = false; + + hr = m_dev->CreateRasterizerState(&rd, &m_rs); + + m_dev->RSSetState(m_rs); + + // + + memset(&sd, 0, sizeof(sd)); + + sd.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR; + sd.AddressU = D3D10_TEXTURE_ADDRESS_CLAMP; + sd.AddressV = D3D10_TEXTURE_ADDRESS_CLAMP; + sd.AddressW = D3D10_TEXTURE_ADDRESS_CLAMP; + sd.MaxLOD = FLT_MAX; + sd.MaxAnisotropy = 16; + sd.ComparisonFunc = D3D10_COMPARISON_NEVER; + + hr = m_dev->CreateSamplerState(&sd, &m_convert.ln); + + sd.Filter = D3D10_FILTER_MIN_MAG_MIP_POINT; + + hr = m_dev->CreateSamplerState(&sd, &m_convert.pt); + + // + + Reset(1, 1, true); + + // +/* + if(!m_mergefx.Create(this)) + { + return false; + } +*/ + // + + return true; +} + +bool GSDevice10::Reset(int w, int h, bool fs) +{ + if(!__super::Reset(w, h, fs)) + return false; + + DXGI_SWAP_CHAIN_DESC scd; + memset(&scd, 0, sizeof(scd)); + m_swapchain->GetDesc(&scd); + m_swapchain->ResizeBuffers(scd.BufferCount, w, h, scd.BufferDesc.Format, 0); + + CComPtr backbuffer; + m_swapchain->GetBuffer(0, __uuidof(ID3D10Texture2D), (void**)&backbuffer); + m_backbuffer = Texture(backbuffer); + + return true; +} + +void GSDevice10::Present(const CRect& r) +{ + CRect cr; + + GetClientRect(m_hWnd, &cr); + + if(m_backbuffer.GetWidth() != cr.Width() || m_backbuffer.GetHeight() != cr.Height()) + { + Reset(cr.Width(), cr.Height(), false); + } + + float color[4] = {0, 0, 0, 0}; + + m_dev->ClearRenderTargetView(m_backbuffer, color); + + if(m_current) + { + StretchRect(m_current, m_backbuffer, GSVector4(r)); + } + + m_swapchain->Present(m_vsync ? 1 : 0, 0); +} + +void GSDevice10::BeginScene() +{ +} + +void GSDevice10::EndScene() +{ + PSSetShaderResources(NULL, NULL); + + // not clearing the rt/ds gives a little fps boost in complex games (5-10%) + + // OMSetRenderTargets(NULL, NULL); +} + +void GSDevice10::Draw(LPCTSTR str) +{ + /* + BOOL fs; + CComPtr target; + + m_swapchain->GetFullscreenState(&fs, &target); + + if(fs) + { + BeginScene(); + + OMSetRenderTargets(m_backbuffer, NULL); + + CRect r(0, 0, m_backbuffer.GetWidth(), m_backbuffer.GetHeight()); + + D3DCOLOR c = D3DCOLOR_ARGB(255, 0, 255, 0); + + if(m_font->DrawText(NULL, str, -1, &r, DT_CALCRECT|DT_LEFT|DT_WORDBREAK, c)) + { + m_font->DrawText(NULL, str, -1, &r, DT_LEFT|DT_WORDBREAK, c); + } + + EndScene(); + } + */ +} + +bool GSDevice10::CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format) +{ + dst = Texture(); + + if(format == 0) + { + format = DXGI_FORMAT_R8G8B8A8_UNORM; + } + + if(format != DXGI_FORMAT_R8G8B8A8_UNORM && format != DXGI_FORMAT_R16_UINT) + { + ASSERT(0); + + return false; + } + + Texture rt; + + if(CreateRenderTarget(rt, w, h, format)) + { + GSVector4 dr(0, 0, w, h); + + StretchRect(src, sr, rt, dr, m_convert.ps[format == DXGI_FORMAT_R16_UINT ? 1 : 0], NULL); + + if(CreateOffscreen(dst, w, h, format)) + { + m_dev->CopyResource(dst, rt); + } + } + + Recycle(rt); + + return !!dst; +} + +void GSDevice10::ClearRenderTarget(Texture& t, const GSVector4& c) +{ + m_dev->ClearRenderTargetView(t, c.v); +} + +void GSDevice10::ClearRenderTarget(Texture& t, DWORD c) +{ + GSVector4 color = GSVector4(c) * (1.0f / 255); + + m_dev->ClearRenderTargetView(t, color.v); +} + +void GSDevice10::ClearDepth(Texture& t, float c) +{ + m_dev->ClearDepthStencilView(t, D3D10_CLEAR_DEPTH, c, 0); +} + +void GSDevice10::ClearStencil(Texture& t, BYTE c) +{ + m_dev->ClearDepthStencilView(t, D3D10_CLEAR_STENCIL, 0, c); +} + +bool GSDevice10::Create(int type, Texture& t, int w, int h, int format) +{ + HRESULT hr; + + D3D10_TEXTURE2D_DESC desc; + + memset(&desc, 0, sizeof(desc)); + + desc.Width = w; + desc.Height = h; + desc.Format = (DXGI_FORMAT)format; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D10_USAGE_DEFAULT; + + switch(type) + { + case GSTexture::RenderTarget: + desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; + break; + case GSTexture::DepthStencil: + desc.BindFlags = D3D10_BIND_DEPTH_STENCIL; + break; + case GSTexture::Texture: + desc.BindFlags = D3D10_BIND_SHADER_RESOURCE; + break; + case GSTexture::Offscreen: + desc.Usage = D3D10_USAGE_STAGING; + desc.CPUAccessFlags |= D3D10_CPU_ACCESS_READ | D3D10_CPU_ACCESS_WRITE; + break; + } + + CComPtr texture; + + hr = m_dev->CreateTexture2D(&desc, NULL, &texture); + + if(SUCCEEDED(hr)) + { + t = Texture(texture); + + switch(type) + { + case GSTexture::RenderTarget: + ClearRenderTarget(t, 0); + break; + case GSTexture::DepthStencil: + ClearDepth(t, 0); + break; + } + + return true; + } + + return false; +} + +bool GSDevice10::CreateRenderTarget(Texture& t, int w, int h, int format) +{ + return __super::CreateRenderTarget(t, w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM); +} + +bool GSDevice10::CreateDepthStencil(Texture& t, int w, int h, int format) +{ + return __super::CreateDepthStencil(t, w, h, format ? format : DXGI_FORMAT_D32_FLOAT_S8X24_UINT); +} + +bool GSDevice10::CreateTexture(Texture& t, int w, int h, int format) +{ + return __super::CreateTexture(t, w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM); +} + +bool GSDevice10::CreateOffscreen(Texture& t, int w, int h, int format) +{ + return __super::CreateOffscreen(t, w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM); +} + +void GSDevice10::DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c) +{ + ClearRenderTarget(dt, c); + + if(st[1] && !slbg) + { + StretchRect(st[1], sr[1], dt, dr[1], m_merge.ps[0], NULL, true); + } + + if(st[0]) + { + m_dev->UpdateSubresource(m_merge.cb, 0, NULL, &c, 0, 0); + + StretchRect(st[0], sr[0], dt, dr[0], m_merge.ps[mmod ? 1 : 0], m_merge.cb, m_merge.bs, true); + } +} + +void GSDevice10::DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset) +{ + GSVector4 sr(0, 0, 1, 1); + GSVector4 dr(0.0f, yoffset, (float)dt.GetWidth(), (float)dt.GetHeight() + yoffset); + + InterlaceConstantBuffer cb; + + cb.ZrH = GSVector2(0, 1.0f / dt.GetHeight()); + cb.hH = (float)dt.GetHeight() / 2; + + m_dev->UpdateSubresource(m_interlace.cb, 0, NULL, &cb, 0, 0); + + StretchRect(st, sr, dt, dr, m_interlace.ps[shader], m_interlace.cb, linear); +} + +void GSDevice10::IASetVertexBuffer(ID3D10Buffer* vb, UINT stride) +{ + if(m_vb != vb || m_vb_stride != stride) + { + UINT offset = 0; + + m_dev->IASetVertexBuffers(0, 1, &vb, &stride, &offset); + + m_vb = vb; + m_vb_stride = stride; + } +} + +void GSDevice10::IASetInputLayout(ID3D10InputLayout* layout) +{ + if(m_layout != layout) + { + m_dev->IASetInputLayout(layout); + + m_layout = layout; + } +} + +void GSDevice10::IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY topology) +{ + if(m_topology != topology) + { + m_dev->IASetPrimitiveTopology(topology); + + m_topology = topology; + } +} + +void GSDevice10::VSSetShader(ID3D10VertexShader* vs, ID3D10Buffer* vs_cb) +{ + if(m_vs != vs) + { + m_dev->VSSetShader(vs); + + m_vs = vs; + } + + if(m_vs_cb != vs_cb) + { + m_dev->VSSetConstantBuffers(0, 1, &vs_cb); + + m_vs_cb = vs_cb; + } +} + +void GSDevice10::GSSetShader(ID3D10GeometryShader* gs) +{ + if(m_gs != gs) + { + m_dev->GSSetShader(gs); + + m_gs = gs; + } +} + +void GSDevice10::PSSetShaderResources(ID3D10ShaderResourceView* srv0, ID3D10ShaderResourceView* srv1) +{ + if(m_ps_srv[0] != srv0 || m_ps_srv[1] != srv1) + { + ID3D10ShaderResourceView* srvs[] = {srv0, srv1}; + + m_dev->PSSetShaderResources(0, 2, srvs); + + m_ps_srv[0] = srv0; + m_ps_srv[1] = srv1; + } +} + +void GSDevice10::PSSetShader(ID3D10PixelShader* ps, ID3D10Buffer* ps_cb) +{ + if(m_ps != ps) + { + m_dev->PSSetShader(ps); + + m_ps = ps; + } + + if(m_ps_cb != ps_cb) + { + m_dev->PSSetConstantBuffers(0, 1, &ps_cb); + + m_ps_cb = ps_cb; + } +} + +void GSDevice10::PSSetSamplerState(ID3D10SamplerState* ss0, ID3D10SamplerState* ss1) +{ + if(m_ps_ss[0] != ss0 || m_ps_ss[1] != ss1) + { + ID3D10SamplerState* sss[] = {ss0, ss1}; + + m_dev->PSSetSamplers(0, 2, sss); + + m_ps_ss[0] = ss0; + m_ps_ss[1] = ss1; + } +} + +void GSDevice10::RSSet(int width, int height, const RECT* scissor) +{ + if(m_viewport.cx != width || m_viewport.cy != height) + { + D3D10_VIEWPORT vp; + + memset(&vp, 0, sizeof(vp)); + + vp.TopLeftX = 0; + vp.TopLeftY = 0; + vp.Width = width; + vp.Height = height; + vp.MinDepth = 0.0f; + vp.MaxDepth = 1.0f; + + m_dev->RSSetViewports(1, &vp); + + m_viewport = CSize(width, height); + } + + CRect r = scissor ? *scissor : CRect(0, 0, width, height); + + if(m_scissor != r) + { + m_dev->RSSetScissorRects(1, &r); + + m_scissor = r; + } +} + +void GSDevice10::OMSetDepthStencilState(ID3D10DepthStencilState* dss, UINT sref) +{ + if(m_dss != dss || m_sref != sref) + { + m_dev->OMSetDepthStencilState(dss, sref); + + m_dss = dss; + m_sref = sref; + } +} + +void GSDevice10::OMSetBlendState(ID3D10BlendState* bs, float bf) +{ + if(m_bs != bs || m_bf != bf) + { + float BlendFactor[] = {bf, bf, bf, 0}; + + m_dev->OMSetBlendState(bs, BlendFactor, 0xffffffff); + + m_bs = bs; + m_bf = bf; + } +} + +void GSDevice10::OMSetRenderTargets(ID3D10RenderTargetView* rtv, ID3D10DepthStencilView* dsv) +{ + if(m_rtv != rtv || m_dsv != dsv) + { + m_dev->OMSetRenderTargets(1, &rtv, dsv); + + m_rtv = rtv; + m_dsv = dsv; + } +} + +void GSDevice10::DrawPrimitive(UINT count, UINT start) +{ + m_dev->Draw(count, start); +} + +void GSDevice10::StretchRect(Texture& st, Texture& dt, const GSVector4& dr, bool linear) +{ + StretchRect(st, GSVector4(0, 0, 1, 1), dt, dr, linear); +} + +void GSDevice10::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, bool linear) +{ + StretchRect(st, sr, dt, dr, m_convert.ps[0], NULL, linear); +} + +void GSDevice10::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, bool linear) +{ + StretchRect(st, sr, dt, dr, ps, ps_cb, m_convert.bs, linear); +} + +void GSDevice10::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, ID3D10BlendState* bs, bool linear) +{ + BeginScene(); + + // om + + OMSetDepthStencilState(m_convert.dss, 0); + OMSetBlendState(bs, 0); + OMSetRenderTargets(dt, NULL); + + // ia + + float left = dr.x * 2 / dt.GetWidth() - 1.0f; + float top = 1.0f - dr.y * 2 / dt.GetHeight(); + float right = dr.z * 2 / dt.GetWidth() - 1.0f; + float bottom = 1.0f - dr.w * 2 / dt.GetHeight(); + + GSVertexPT1 vertices[] = + { + {GSVector4(left, top, 0.5f, 1.0f), GSVector2(sr.x, sr.y)}, + {GSVector4(right, top, 0.5f, 1.0f), GSVector2(sr.z, sr.y)}, + {GSVector4(left, bottom, 0.5f, 1.0f), GSVector2(sr.x, sr.w)}, + {GSVector4(right, bottom, 0.5f, 1.0f), GSVector2(sr.z, sr.w)}, + }; + + D3D10_BOX box = {0, 0, 0, sizeof(vertices), 1, 1}; + + m_dev->UpdateSubresource(m_convert.vb, 0, &box, vertices, 0, 0); + + IASetVertexBuffer(m_convert.vb, sizeof(vertices[0])); + IASetInputLayout(m_convert.il); + IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + + // vs + + VSSetShader(m_convert.vs, NULL); + + // gs + + GSSetShader(NULL); + + // ps + + PSSetShader(ps, ps_cb); + PSSetSamplerState(linear ? m_convert.ln : m_convert.pt, NULL); + PSSetShaderResources(st, NULL); + + // rs + + RSSet(dt.GetWidth(), dt.GetHeight()); + + // + + DrawPrimitive(countof(vertices)); + + // + + EndScene(); +} + +HRESULT GSDevice10::CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10VertexShader** ps, D3D10_INPUT_ELEMENT_DESC* layout, int count, ID3D10InputLayout** il) +{ + HRESULT hr; + + CComPtr shader, error; + + hr = D3DX10CompileFromResource(AfxGetInstanceHandle(), MAKEINTRESOURCE(id), NULL, macro, NULL, entry, "vs_4_0", 0, 0, NULL, &shader, &error, NULL); + + if(error) + { + TRACE(_T("%s\n"), CString((LPCSTR)error->GetBufferPointer())); + } + + if(FAILED(hr)) + { + return hr; + } + + hr = m_dev->CreateVertexShader((DWORD*)shader->GetBufferPointer(), shader->GetBufferSize(), ps); + + if(FAILED(hr)) + { + return hr; + } + + hr = m_dev->CreateInputLayout(layout, count, shader->GetBufferPointer(), shader->GetBufferSize(), il); + + if(FAILED(hr)) + { + return hr; + } + + return hr; +} + +HRESULT GSDevice10::CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10GeometryShader** gs) +{ + HRESULT hr; + + CComPtr shader, error; + + hr = D3DX10CompileFromResource(AfxGetInstanceHandle(), MAKEINTRESOURCE(id), NULL, macro, NULL, entry, "gs_4_0", 0, 0, NULL, &shader, &error, NULL); + + if(error) + { + TRACE(_T("%s\n"), CString((LPCSTR)error->GetBufferPointer())); + } + + if(FAILED(hr)) + { + return hr; + } + + hr = m_dev->CreateGeometryShader((DWORD*)shader->GetBufferPointer(), shader->GetBufferSize(), gs); + + if(FAILED(hr)) + { + return hr; + } + + return hr; +} + +HRESULT GSDevice10::CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10PixelShader** ps) +{ + HRESULT hr; + + CComPtr shader, error; + + hr = D3DX10CompileFromResource(AfxGetInstanceHandle(), MAKEINTRESOURCE(id), NULL, macro, NULL, entry, "ps_4_0", 0, 0, NULL, &shader, &error, NULL); + + if(error) + { + TRACE(_T("%s\n"), CString((LPCSTR)error->GetBufferPointer())); + } + + if(FAILED(hr)) + { + return hr; + } + + hr = m_dev->CreatePixelShader((DWORD*)shader->GetBufferPointer(), shader->GetBufferSize(), ps); + + if(FAILED(hr)) + { + return hr; + } + + return hr; +} diff --git a/plugins/GSdx/GSDevice10.h b/plugins/GSdx/GSDevice10.h index b45e82f499..55124884de 100644 --- a/plugins/GSdx/GSDevice10.h +++ b/plugins/GSdx/GSDevice10.h @@ -1,147 +1,147 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSDevice.h" -#include "GSTexture10.h" - -class GSDevice10 : public GSDevice -{ -public: - typedef GSTexture10 Texture; - -private: - // state cache - - ID3D10Buffer* m_vb; - UINT m_vb_count; - UINT m_vb_stride; - ID3D10InputLayout* m_layout; - D3D10_PRIMITIVE_TOPOLOGY m_topology; - ID3D10VertexShader* m_vs; - ID3D10Buffer* m_vs_cb; - ID3D10GeometryShader* m_gs; - ID3D10ShaderResourceView* m_ps_srv[2]; - ID3D10PixelShader* m_ps; - ID3D10Buffer* m_ps_cb; - ID3D10SamplerState* m_ps_ss[2]; - CSize m_viewport; - CRect m_scissor; - ID3D10DepthStencilState* m_dss; - UINT m_sref; - ID3D10BlendState* m_bs; - float m_bf; - ID3D10RenderTargetView* m_rtv; - ID3D10DepthStencilView* m_dsv; - - // - - bool Create(int type, Texture& t, int w, int h, int format); - void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c); - void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset = 0); - - // - - CComPtr m_dev; - CComPtr m_swapchain; - CComPtr m_font; - -public: // TODO - CComPtr m_rs; - - struct - { - CComPtr vb; - CComPtr il; - CComPtr vs; - CComPtr ps[5]; - CComPtr ln; - CComPtr pt; - CComPtr dss; - CComPtr bs; - } m_convert; - - struct - { - CComPtr ps[2]; - CComPtr cb; - CComPtr bs; - } m_merge; - - struct - { - CComPtr ps[4]; - CComPtr cb; - } m_interlace; - -public: - GSDevice10(); - virtual ~GSDevice10(); - - bool Create(HWND hWnd, bool vsync); - bool Reset(int w, int h, bool fs); - bool IsLost() {return false;} - void Present(const CRect& r); - void BeginScene(); - void EndScene(); - void Draw(LPCTSTR str); - bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0); - - void ClearRenderTarget(Texture& t, const GSVector4& c); - void ClearRenderTarget(Texture& t, DWORD c); - void ClearDepth(Texture& t, float c); - void ClearStencil(Texture& t, BYTE c); - - bool CreateRenderTarget(Texture& t, int w, int h, int format = 0); - bool CreateDepthStencil(Texture& t, int w, int h, int format = 0); - bool CreateTexture(Texture& t, int w, int h, int format = 0); - bool CreateOffscreen(Texture& t, int w, int h, int format = 0); - - ID3D10Device* operator->() {return m_dev;} - operator ID3D10Device*() {return m_dev;} - - void IASetVertexBuffer(ID3D10Buffer* vb, UINT stride); - void IASetInputLayout(ID3D10InputLayout* layout); - void IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY topology); - void VSSetShader(ID3D10VertexShader* vs, ID3D10Buffer* vs_cb); - void GSSetShader(ID3D10GeometryShader* gs); - void PSSetShaderResources(ID3D10ShaderResourceView* srv0, ID3D10ShaderResourceView* srv1); - void PSSetShader(ID3D10PixelShader* ps, ID3D10Buffer* ps_cb); - void PSSetSamplerState(ID3D10SamplerState* ss0, ID3D10SamplerState* ss1); - void RSSet(int width, int height, const RECT* scissor = NULL); - void OMSetDepthStencilState(ID3D10DepthStencilState* dss, UINT sref); - void OMSetBlendState(ID3D10BlendState* bs, float bf); - void OMSetRenderTargets(ID3D10RenderTargetView* rtv, ID3D10DepthStencilView* dsv); - void DrawPrimitive(UINT count, UINT start = 0); - - void StretchRect(Texture& st, Texture& dt, const GSVector4& dr, bool linear = true); - void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, bool linear = true); - void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, bool linear = true); - void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, ID3D10BlendState* bs, bool linear = true); - - HRESULT CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10VertexShader** vs, D3D10_INPUT_ELEMENT_DESC* layout, int count, ID3D10InputLayout** il); - HRESULT CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10GeometryShader** gs); - HRESULT CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10PixelShader** ps); - - // TODO - bool SaveToFileD32S8X24(ID3D10Texture2D* ds, LPCTSTR fn); -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSDevice.h" +#include "GSTexture10.h" + +class GSDevice10 : public GSDevice +{ +public: + typedef GSTexture10 Texture; + +private: + // state cache + + ID3D10Buffer* m_vb; + UINT m_vb_count; + UINT m_vb_stride; + ID3D10InputLayout* m_layout; + D3D10_PRIMITIVE_TOPOLOGY m_topology; + ID3D10VertexShader* m_vs; + ID3D10Buffer* m_vs_cb; + ID3D10GeometryShader* m_gs; + ID3D10ShaderResourceView* m_ps_srv[2]; + ID3D10PixelShader* m_ps; + ID3D10Buffer* m_ps_cb; + ID3D10SamplerState* m_ps_ss[2]; + CSize m_viewport; + CRect m_scissor; + ID3D10DepthStencilState* m_dss; + UINT m_sref; + ID3D10BlendState* m_bs; + float m_bf; + ID3D10RenderTargetView* m_rtv; + ID3D10DepthStencilView* m_dsv; + + // + + bool Create(int type, Texture& t, int w, int h, int format); + void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c); + void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset = 0); + + // + + CComPtr m_dev; + CComPtr m_swapchain; + CComPtr m_font; + +public: // TODO + CComPtr m_rs; + + struct + { + CComPtr vb; + CComPtr il; + CComPtr vs; + CComPtr ps[5]; + CComPtr ln; + CComPtr pt; + CComPtr dss; + CComPtr bs; + } m_convert; + + struct + { + CComPtr ps[2]; + CComPtr cb; + CComPtr bs; + } m_merge; + + struct + { + CComPtr ps[4]; + CComPtr cb; + } m_interlace; + +public: + GSDevice10(); + virtual ~GSDevice10(); + + bool Create(HWND hWnd, bool vsync); + bool Reset(int w, int h, bool fs); + bool IsLost() {return false;} + void Present(const CRect& r); + void BeginScene(); + void EndScene(); + void Draw(LPCTSTR str); + bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0); + + void ClearRenderTarget(Texture& t, const GSVector4& c); + void ClearRenderTarget(Texture& t, DWORD c); + void ClearDepth(Texture& t, float c); + void ClearStencil(Texture& t, BYTE c); + + bool CreateRenderTarget(Texture& t, int w, int h, int format = 0); + bool CreateDepthStencil(Texture& t, int w, int h, int format = 0); + bool CreateTexture(Texture& t, int w, int h, int format = 0); + bool CreateOffscreen(Texture& t, int w, int h, int format = 0); + + ID3D10Device* operator->() {return m_dev;} + operator ID3D10Device*() {return m_dev;} + + void IASetVertexBuffer(ID3D10Buffer* vb, UINT stride); + void IASetInputLayout(ID3D10InputLayout* layout); + void IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY topology); + void VSSetShader(ID3D10VertexShader* vs, ID3D10Buffer* vs_cb); + void GSSetShader(ID3D10GeometryShader* gs); + void PSSetShaderResources(ID3D10ShaderResourceView* srv0, ID3D10ShaderResourceView* srv1); + void PSSetShader(ID3D10PixelShader* ps, ID3D10Buffer* ps_cb); + void PSSetSamplerState(ID3D10SamplerState* ss0, ID3D10SamplerState* ss1); + void RSSet(int width, int height, const RECT* scissor = NULL); + void OMSetDepthStencilState(ID3D10DepthStencilState* dss, UINT sref); + void OMSetBlendState(ID3D10BlendState* bs, float bf); + void OMSetRenderTargets(ID3D10RenderTargetView* rtv, ID3D10DepthStencilView* dsv); + void DrawPrimitive(UINT count, UINT start = 0); + + void StretchRect(Texture& st, Texture& dt, const GSVector4& dr, bool linear = true); + void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, bool linear = true); + void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, bool linear = true); + void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, ID3D10BlendState* bs, bool linear = true); + + HRESULT CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10VertexShader** vs, D3D10_INPUT_ELEMENT_DESC* layout, int count, ID3D10InputLayout** il); + HRESULT CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10GeometryShader** gs); + HRESULT CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10PixelShader** ps); + + // TODO + bool SaveToFileD32S8X24(ID3D10Texture2D* ds, LPCTSTR fn); +}; diff --git a/plugins/GSdx/GSDevice7.cpp b/plugins/GSdx/GSDevice7.cpp index b60cbba059..8ca5a59f36 100644 --- a/plugins/GSdx/GSDevice7.cpp +++ b/plugins/GSdx/GSDevice7.cpp @@ -1,241 +1,241 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -// dumb device implementation, only good for simple image output - -#include "stdafx.h" -#include "GSDevice7.h" - -GSDevice7::GSDevice7() -{ -} - -GSDevice7::~GSDevice7() -{ -} - -bool GSDevice7::Create(HWND hWnd, bool vsync) -{ - if(!__super::Create(hWnd, vsync)) - { - return false; - } - - if(FAILED(DirectDrawCreateEx(NULL, (VOID**)&m_dd, IID_IDirectDraw7, NULL))) - { - return false; - } - - // TODO: fullscreen - - if(FAILED(m_dd->SetCooperativeLevel(hWnd, DDSCL_NORMAL))) - { - return false; - } - - DDSURFACEDESC2 desc; - - memset(&desc, 0, sizeof(desc)); - - desc.dwSize = sizeof(desc); - desc.dwFlags = DDSD_CAPS; - desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - - if(FAILED(m_dd->CreateSurface(&desc, &m_primary, NULL))) - { - return false; - } - - CComPtr clipper; - - if(FAILED(m_dd->CreateClipper(0, &clipper, NULL)) - || FAILED(clipper->SetHWnd(0, hWnd)) - || FAILED(m_primary->SetClipper(clipper))) - { - return false; - } - - Reset(1, 1, true); - - return true; -} - -bool GSDevice7::Reset(int w, int h, bool fs) -{ - if(!__super::Reset(w, h, fs)) - return false; - - m_backbuffer = NULL; - - DDSURFACEDESC2 desc; - - memset(&desc, 0, sizeof(desc)); - - desc.dwSize = sizeof(desc); - desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; - desc.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_3DDEVICE; - desc.dwWidth = w; - desc.dwHeight = h; - - if(FAILED(m_dd->CreateSurface(&desc, &m_backbuffer, NULL))) - { - return false; - } - - CComPtr clipper; - - if(FAILED(m_dd->CreateClipper(0, &clipper, NULL))) - { - return false; - } - - { - // ??? - - HRGN hrgn = CreateRectRgn(0, 0, w, h); - - BYTE buff[1024]; - - GetRegionData(hrgn, sizeof(buff), (RGNDATA*)buff); - - DeleteObject(hrgn); - - clipper->SetClipList((RGNDATA*)buff, 0); - - if(FAILED(m_backbuffer->SetClipper(clipper))) - { - return false; - } - } - - return true; -} - -void GSDevice7::Present(const CRect& r) -{ - HRESULT hr; - - CRect cr; - GetClientRect(m_hWnd, &cr); - - DDSURFACEDESC2 desc; - memset(&desc, 0, sizeof(desc)); - desc.dwSize = sizeof(desc); - - hr = m_backbuffer->GetSurfaceDesc(&desc); - - if(desc.dwWidth != cr.Width() || desc.dwHeight != cr.Height()) - { - Reset(cr.Width(), cr.Height(), false); - } - - DDBLTFX fx; - - memset(&fx, 0, sizeof(fx)); - - fx.dwSize = sizeof(fx); - fx.dwFillColor = 0; - - hr = m_backbuffer->Blt(NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &fx); - - CRect r2 = r; - - hr = m_backbuffer->Blt(&r2, m_merge, NULL, DDBLT_WAIT, NULL); - - r2 = cr; - - MapWindowPoints(m_hWnd, HWND_DESKTOP, (POINT*)&r2, 2); - - if(m_vsync) - { - hr = m_dd->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL); - } - - hr = m_primary->Blt(&r2, m_backbuffer, &cr, DDBLT_WAIT, NULL); - - if(hr == DDERR_SURFACELOST) - { - // TODO - - HRESULT hr = m_dd->TestCooperativeLevel(); - - if(hr == DDERR_WRONGMODE) - { - } - } -} - -bool GSDevice7::Create(int type, Texture& t, int w, int h, int format) -{ - HRESULT hr; - - t = Texture(); - - DDSURFACEDESC2 desc; - - memset(&desc, 0, sizeof(desc)); - - desc.dwSize = sizeof(desc); - desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; - desc.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY; - desc.dwWidth = w; - desc.dwHeight = h; - desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat); - desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS; - desc.ddpfPixelFormat.dwRGBBitCount = 32; - desc.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000; - desc.ddpfPixelFormat.dwRBitMask = 0x00ff0000; - desc.ddpfPixelFormat.dwGBitMask = 0x0000ff00; - desc.ddpfPixelFormat.dwBBitMask = 0x000000ff; - - CComPtr system, video; - - switch(type) - { - case GSTexture::RenderTarget: - case GSTexture::DepthStencil: - case GSTexture::Texture: - desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; - if(FAILED(hr = m_dd->CreateSurface(&desc, &system, NULL))) return false; - desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY; - if(FAILED(hr = m_dd->CreateSurface(&desc, &video, NULL))) return false; - t = Texture(type, system, video); - break; - case GSTexture::Offscreen: - desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; - if(FAILED(hr = m_dd->CreateSurface(&desc, &system, NULL))) return false; - t = Texture(type, system); - break; - } - - return !!t; -} - -void GSDevice7::DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c) -{ - HRESULT hr; - - hr = dt->Blt(NULL, st[0], NULL, DDBLT_WAIT, NULL); -} - -void GSDevice7::DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset) -{ -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +// dumb device implementation, only good for simple image output + +#include "stdafx.h" +#include "GSDevice7.h" + +GSDevice7::GSDevice7() +{ +} + +GSDevice7::~GSDevice7() +{ +} + +bool GSDevice7::Create(HWND hWnd, bool vsync) +{ + if(!__super::Create(hWnd, vsync)) + { + return false; + } + + if(FAILED(DirectDrawCreateEx(NULL, (VOID**)&m_dd, IID_IDirectDraw7, NULL))) + { + return false; + } + + // TODO: fullscreen + + if(FAILED(m_dd->SetCooperativeLevel(hWnd, DDSCL_NORMAL))) + { + return false; + } + + DDSURFACEDESC2 desc; + + memset(&desc, 0, sizeof(desc)); + + desc.dwSize = sizeof(desc); + desc.dwFlags = DDSD_CAPS; + desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + + if(FAILED(m_dd->CreateSurface(&desc, &m_primary, NULL))) + { + return false; + } + + CComPtr clipper; + + if(FAILED(m_dd->CreateClipper(0, &clipper, NULL)) + || FAILED(clipper->SetHWnd(0, hWnd)) + || FAILED(m_primary->SetClipper(clipper))) + { + return false; + } + + Reset(1, 1, true); + + return true; +} + +bool GSDevice7::Reset(int w, int h, bool fs) +{ + if(!__super::Reset(w, h, fs)) + return false; + + m_backbuffer = NULL; + + DDSURFACEDESC2 desc; + + memset(&desc, 0, sizeof(desc)); + + desc.dwSize = sizeof(desc); + desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + desc.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_3DDEVICE; + desc.dwWidth = w; + desc.dwHeight = h; + + if(FAILED(m_dd->CreateSurface(&desc, &m_backbuffer, NULL))) + { + return false; + } + + CComPtr clipper; + + if(FAILED(m_dd->CreateClipper(0, &clipper, NULL))) + { + return false; + } + + { + // ??? + + HRGN hrgn = CreateRectRgn(0, 0, w, h); + + BYTE buff[1024]; + + GetRegionData(hrgn, sizeof(buff), (RGNDATA*)buff); + + DeleteObject(hrgn); + + clipper->SetClipList((RGNDATA*)buff, 0); + + if(FAILED(m_backbuffer->SetClipper(clipper))) + { + return false; + } + } + + return true; +} + +void GSDevice7::Present(const CRect& r) +{ + HRESULT hr; + + CRect cr; + GetClientRect(m_hWnd, &cr); + + DDSURFACEDESC2 desc; + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + + hr = m_backbuffer->GetSurfaceDesc(&desc); + + if(desc.dwWidth != cr.Width() || desc.dwHeight != cr.Height()) + { + Reset(cr.Width(), cr.Height(), false); + } + + DDBLTFX fx; + + memset(&fx, 0, sizeof(fx)); + + fx.dwSize = sizeof(fx); + fx.dwFillColor = 0; + + hr = m_backbuffer->Blt(NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &fx); + + CRect r2 = r; + + hr = m_backbuffer->Blt(&r2, m_merge, NULL, DDBLT_WAIT, NULL); + + r2 = cr; + + MapWindowPoints(m_hWnd, HWND_DESKTOP, (POINT*)&r2, 2); + + if(m_vsync) + { + hr = m_dd->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL); + } + + hr = m_primary->Blt(&r2, m_backbuffer, &cr, DDBLT_WAIT, NULL); + + if(hr == DDERR_SURFACELOST) + { + // TODO + + HRESULT hr = m_dd->TestCooperativeLevel(); + + if(hr == DDERR_WRONGMODE) + { + } + } +} + +bool GSDevice7::Create(int type, Texture& t, int w, int h, int format) +{ + HRESULT hr; + + t = Texture(); + + DDSURFACEDESC2 desc; + + memset(&desc, 0, sizeof(desc)); + + desc.dwSize = sizeof(desc); + desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; + desc.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY; + desc.dwWidth = w; + desc.dwHeight = h; + desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat); + desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS; + desc.ddpfPixelFormat.dwRGBBitCount = 32; + desc.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000; + desc.ddpfPixelFormat.dwRBitMask = 0x00ff0000; + desc.ddpfPixelFormat.dwGBitMask = 0x0000ff00; + desc.ddpfPixelFormat.dwBBitMask = 0x000000ff; + + CComPtr system, video; + + switch(type) + { + case GSTexture::RenderTarget: + case GSTexture::DepthStencil: + case GSTexture::Texture: + desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; + if(FAILED(hr = m_dd->CreateSurface(&desc, &system, NULL))) return false; + desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY; + if(FAILED(hr = m_dd->CreateSurface(&desc, &video, NULL))) return false; + t = Texture(type, system, video); + break; + case GSTexture::Offscreen: + desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; + if(FAILED(hr = m_dd->CreateSurface(&desc, &system, NULL))) return false; + t = Texture(type, system); + break; + } + + return !!t; +} + +void GSDevice7::DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c) +{ + HRESULT hr; + + hr = dt->Blt(NULL, st[0], NULL, DDBLT_WAIT, NULL); +} + +void GSDevice7::DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset) +{ +} diff --git a/plugins/GSdx/GSDevice7.h b/plugins/GSdx/GSDevice7.h index 2afbce261f..94823dbf88 100644 --- a/plugins/GSdx/GSDevice7.h +++ b/plugins/GSdx/GSDevice7.h @@ -1,58 +1,58 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSDevice.h" -#include "GSTexture7.h" - -class GSDevice7 : public GSDevice -{ -public: - typedef GSTexture7 Texture; - -private: - CComPtr m_dd; - CComPtr m_primary; - CComPtr m_backbuffer; - - bool Create(int type, Texture& t, int w, int h, int format); - void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c); - void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset = 0); - -public: - GSDevice7(); - virtual ~GSDevice7(); - - bool Create(HWND hWnd, bool vsync); - bool Reset(int w, int h, bool fs); - bool IsLost() {return false;} - void Present(const CRect& r); - void BeginScene() {} - void EndScene() {} - void Draw(LPCTSTR str) {} - bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0) {return false;} - - void ClearRenderTarget(Texture& t, const GSVector4& c) {} - void ClearRenderTarget(Texture& t, DWORD c) {} - void ClearDepth(Texture& t, float c) {} - void ClearStencil(Texture& t, BYTE c) {} -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSDevice.h" +#include "GSTexture7.h" + +class GSDevice7 : public GSDevice +{ +public: + typedef GSTexture7 Texture; + +private: + CComPtr m_dd; + CComPtr m_primary; + CComPtr m_backbuffer; + + bool Create(int type, Texture& t, int w, int h, int format); + void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c); + void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset = 0); + +public: + GSDevice7(); + virtual ~GSDevice7(); + + bool Create(HWND hWnd, bool vsync); + bool Reset(int w, int h, bool fs); + bool IsLost() {return false;} + void Present(const CRect& r); + void BeginScene() {} + void EndScene() {} + void Draw(LPCTSTR str) {} + bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0) {return false;} + + void ClearRenderTarget(Texture& t, const GSVector4& c) {} + void ClearRenderTarget(Texture& t, DWORD c) {} + void ClearDepth(Texture& t, float c) {} + void ClearStencil(Texture& t, BYTE c) {} +}; diff --git a/plugins/GSdx/GSDevice9.cpp b/plugins/GSdx/GSDevice9.cpp index 57d9f198bf..f8414a36e0 100644 --- a/plugins/GSdx/GSDevice9.cpp +++ b/plugins/GSdx/GSDevice9.cpp @@ -1,1062 +1,1062 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GSDevice9.h" -#include "resource.h" - -GSDevice9::GSDevice9() - : m_vb(NULL) - , m_vb_count(0) - , m_vb_vertices(NULL) - , m_vb_stride(0) - , m_layout(NULL) - , m_topology((D3DPRIMITIVETYPE)0) - , m_vs(NULL) - , m_vs_cb(NULL) - , m_vs_cb_len(0) - , m_ps(NULL) - , m_ps_cb(NULL) - , m_ps_cb_len(0) - , m_ps_ss(NULL) - , m_scissor(0, 0, 0, 0) - , m_dss(NULL) - , m_sref(0) - , m_bs(NULL) - , m_bf(0xffffffff) - , m_rtv(NULL) - , m_dsv(NULL) -{ - memset(&m_pp, 0, sizeof(m_pp)); - memset(&m_ddcaps, 0, sizeof(m_ddcaps)); - memset(&m_d3dcaps, 0, sizeof(m_d3dcaps)); - memset(m_ps_srvs, 0, sizeof(m_ps_srvs)); -} - -GSDevice9::~GSDevice9() -{ - if(m_vs_cb) _aligned_free(m_vs_cb); - if(m_ps_cb) _aligned_free(m_ps_cb); -} - -bool GSDevice9::Create(HWND hWnd, bool vsync) -{ - if(!__super::Create(hWnd, vsync)) - { - return false; - } - - HRESULT hr; - - // dd - - CComPtr dd; - - hr = DirectDrawCreateEx(0, (void**)&dd, IID_IDirectDraw7, 0); - - if(FAILED(hr)) return false; - - memset(&m_ddcaps, 0, sizeof(m_ddcaps)); - - m_ddcaps.dwSize = sizeof(DDCAPS); - - hr = dd->GetCaps(&m_ddcaps, NULL); - - if(FAILED(hr)) return false; - - dd = NULL; - - // d3d - - m_d3d = Direct3DCreate9(D3D_SDK_VERSION); - - if(!m_d3d) return false; - - hr = m_d3d->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24S8); - - if(FAILED(hr)) return false; - - hr = m_d3d->CheckDepthStencilMatch(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_D24S8); - - if(FAILED(hr)) return false; - - memset(&m_d3dcaps, 0, sizeof(m_d3dcaps)); - - m_d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &m_d3dcaps); - - bool fs = AfxGetApp()->GetProfileInt(_T("Settings"), _T("ModeWidth"), 0) > 0; - - if(!Reset(1, 1, fs)) return false; - - m_dev->Clear(0, NULL, D3DCLEAR_TARGET, 0, 1.0f, 0); - - // shaders - - DWORD psver = AfxGetApp()->GetProfileInt(_T("Settings"), _T("PixelShaderVersion2"), D3DPS_VERSION(2, 0)); - - if(psver > m_d3dcaps.PixelShaderVersion) - { - CString str; - - str.Format(_T("Supported pixel shader version is too low!\n\nSupported: %d.%d\nSelected: %d.%d"), - D3DSHADER_VERSION_MAJOR(m_d3dcaps.PixelShaderVersion), D3DSHADER_VERSION_MINOR(m_d3dcaps.PixelShaderVersion), - D3DSHADER_VERSION_MAJOR(psver), D3DSHADER_VERSION_MINOR(psver)); - - AfxMessageBox(str); - - return false; - } - - m_d3dcaps.PixelShaderVersion = min(psver, m_d3dcaps.PixelShaderVersion); - m_d3dcaps.VertexShaderVersion = m_d3dcaps.PixelShaderVersion & ~0x10000; - - // convert - - static const D3DVERTEXELEMENT9 il_convert[] = - { - {0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, - {0, 16, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, - D3DDECL_END() - }; - - CompileShader(IDR_CONVERT9_FX, "vs_main", NULL, &m_convert.vs, il_convert, countof(il_convert), &m_convert.il); - - for(int i = 0; i < countof(m_convert.ps); i++) - { - CStringA main; - main.Format("ps_main%d", i); - CompileShader(IDR_CONVERT9_FX, main, NULL, &m_convert.ps[i]); - } - - m_convert.dss.DepthEnable = false; - m_convert.dss.StencilEnable = false; - - m_convert.bs.BlendEnable = false; - m_convert.bs.RenderTargetWriteMask = D3DCOLORWRITEENABLE_RGBA; - - m_convert.ln.FilterMin[0] = D3DTEXF_LINEAR; - m_convert.ln.FilterMag[0] = D3DTEXF_LINEAR; - m_convert.ln.FilterMin[1] = D3DTEXF_LINEAR; - m_convert.ln.FilterMag[1] = D3DTEXF_LINEAR; - m_convert.ln.AddressU = D3DTADDRESS_CLAMP; - m_convert.ln.AddressV = D3DTADDRESS_CLAMP; - - m_convert.pt.FilterMin[0] = D3DTEXF_POINT; - m_convert.pt.FilterMag[0] = D3DTEXF_POINT; - m_convert.pt.FilterMin[1] = D3DTEXF_POINT; - m_convert.pt.FilterMag[1] = D3DTEXF_POINT; - m_convert.pt.AddressU = D3DTADDRESS_CLAMP; - m_convert.pt.AddressV = D3DTADDRESS_CLAMP; - - // merge - - for(int i = 0; i < countof(m_merge.ps); i++) - { - CStringA main; - main.Format("ps_main%d", i); - CompileShader(IDR_MERGE9_FX, main, NULL, &m_merge.ps[i]); - } - - m_merge.bs.BlendEnable = true; - m_merge.bs.BlendOp = D3DBLENDOP_ADD; - m_merge.bs.SrcBlend = D3DBLEND_SRCALPHA; - m_merge.bs.DestBlend = D3DBLEND_INVSRCALPHA; - m_merge.bs.BlendOpAlpha = D3DBLENDOP_ADD; - m_merge.bs.SrcBlendAlpha = D3DBLEND_ONE; - m_merge.bs.DestBlendAlpha = D3DBLEND_ZERO; - m_merge.bs.RenderTargetWriteMask = D3DCOLORWRITEENABLE_RGBA; - - // interlace - - for(int i = 0; i < countof(m_interlace.ps); i++) - { - CStringA main; - main.Format("ps_main%d", i); - CompileShader(IDR_INTERLACE9_FX, main, NULL, &m_interlace.ps[i]); - } - - // - - return true; -} - -bool GSDevice9::Reset(int w, int h, bool fs) -{ - if(!__super::Reset(w, h, fs)) - return false; - - HRESULT hr; - - if(!m_d3d) return false; - - if(m_swapchain && !fs && m_pp.Windowed) - { - m_swapchain = NULL; - - m_pp.BackBufferWidth = w; - m_pp.BackBufferHeight = h; - - hr = m_dev->CreateAdditionalSwapChain(&m_pp, &m_swapchain); - - if(FAILED(hr)) return false; - - CComPtr backbuffer; - hr = m_swapchain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &backbuffer); - m_backbuffer = Texture(backbuffer); - - return true; - } - - m_swapchain = NULL; - m_backbuffer = Texture(); - if(m_font) m_font->OnLostDevice(); - m_font = NULL; - - if(m_vs_cb) _aligned_free(m_vs_cb); - if(m_ps_cb) _aligned_free(m_ps_cb); - - m_vb = NULL; - m_vb_stride = 0; - m_layout = NULL; - m_vs = NULL; - m_vs_cb = NULL; - m_vs_cb_len = 0; - m_ps = NULL; - m_ps_cb = NULL; - m_ps_cb_len = 0; - m_ps_ss = NULL; - m_scissor = CRect(0, 0, 0, 0); - m_dss = NULL; - m_sref = 0; - m_bs = NULL; - m_bf = 0xffffffff; - m_rtv = NULL; - m_dsv = NULL; - - memset(&m_pp, 0, sizeof(m_pp)); - - m_pp.Windowed = TRUE; - m_pp.hDeviceWindow = m_hWnd; - m_pp.SwapEffect = D3DSWAPEFFECT_FLIP; - m_pp.BackBufferFormat = D3DFMT_X8R8G8B8; - m_pp.BackBufferWidth = 1; - m_pp.BackBufferHeight = 1; - m_pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; - - if(m_vsync) - { - m_pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; - } - - if(!!AfxGetApp()->GetProfileInt(_T("Settings"), _T("tvout"), FALSE)) - { - m_pp.Flags |= D3DPRESENTFLAG_VIDEO; - } - - int mw = AfxGetApp()->GetProfileInt(_T("Settings"), _T("ModeWidth"), 0); - int mh = AfxGetApp()->GetProfileInt(_T("Settings"), _T("ModeHeight"), 0); - int mrr = AfxGetApp()->GetProfileInt(_T("Settings"), _T("ModeRefreshRate"), 0); - - if(fs && mw > 0 && mh > 0 && mrr >= 0) - { - m_pp.Windowed = FALSE; - m_pp.BackBufferWidth = mw; - m_pp.BackBufferHeight = mh; - // m_pp.FullScreen_RefreshRateInHz = mrr; - - ::SetWindowLong(m_hWnd, GWL_STYLE, ::GetWindowLong(m_hWnd, GWL_STYLE) & ~(WS_CAPTION|WS_THICKFRAME)); - ::SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); - ::SetMenu(m_hWnd, NULL); - } - - if(!m_dev) - { - UINT flags = D3DCREATE_MULTITHREADED | (m_d3dcaps.VertexProcessingCaps ? D3DCREATE_HARDWARE_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING); - - hr = m_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, flags, &m_pp, &m_dev); - - if(FAILED(hr)) return false; - } - else - { - hr = m_dev->Reset(&m_pp); - - if(FAILED(hr)) - { - if(D3DERR_DEVICELOST == hr) - { - Sleep(1000); - - hr = m_dev->Reset(&m_pp); - } - - if(FAILED(hr)) return false; - } - } - - if(m_pp.Windowed) - { - m_pp.BackBufferWidth = 1; - m_pp.BackBufferHeight = 1; - - hr = m_dev->CreateAdditionalSwapChain(&m_pp, &m_swapchain); - - if(FAILED(hr)) return false; - } - - CComPtr backbuffer; - - if(m_swapchain) - { - hr = m_swapchain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &backbuffer); - } - else - { - hr = m_dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer); - } - - m_backbuffer = Texture(backbuffer); - - D3DXFONT_DESC fd; - memset(&fd, 0, sizeof(fd)); - _tcscpy(fd.FaceName, _T("Arial")); - fd.Height = 20; - D3DXCreateFontIndirect(m_dev, &fd, &m_font); - - m_dev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - m_dev->SetRenderState(D3DRS_LIGHTING, FALSE); - m_dev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); - m_dev->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); - - return true; -} - -bool GSDevice9::IsLost() -{ - HRESULT hr = m_dev->TestCooperativeLevel(); - - return hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICENOTRESET; -} - -void GSDevice9::Present(const CRect& r) -{ - CRect cr; - - GetClientRect(m_hWnd, &cr); - - if(m_backbuffer.GetWidth() != cr.Width() || m_backbuffer.GetHeight() != cr.Height()) - { - Reset(cr.Width(), cr.Height(), false); - } - - OMSetRenderTargets(m_backbuffer, NULL); - - m_dev->Clear(0, NULL, D3DCLEAR_TARGET, 0, 1.0f, 0); - - if(m_current) - { - StretchRect(m_current, m_backbuffer, GSVector4(r)); - } - - if(m_swapchain) - { - m_swapchain->Present(NULL, NULL, NULL, NULL, 0); - } - else - { - m_dev->Present(NULL, NULL, NULL, NULL); - } -} - -void GSDevice9::BeginScene() -{ - m_dev->BeginScene(); -} - -void GSDevice9::EndScene() -{ - m_dev->EndScene(); -} - -void GSDevice9::Draw(LPCTSTR str) -{ - /* - if(!m_pp.Windowed) - { - BeginScene(); - - OMSetRenderTargets(m_backbuffer, NULL); - - CRect r(0, 0, m_backbuffer.GetWidth(), m_backbuffer.GetHeight()); - - D3DCOLOR c = D3DCOLOR_ARGB(255, 0, 255, 0); - - if(m_font->DrawText(NULL, str, -1, &r, DT_CALCRECT|DT_LEFT|DT_WORDBREAK, c)) - { - m_font->DrawText(NULL, str, -1, &r, DT_LEFT|DT_WORDBREAK, c); - } - - EndScene(); - } - */ -} - -bool GSDevice9::CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format) -{ - dst = Texture(); - - if(format == 0) - { - format = D3DFMT_A8R8G8B8; - } - - if(format != D3DFMT_A8R8G8B8) - { - ASSERT(0); - - return false; - } - - Texture rt; - - if(CreateRenderTarget(rt, w, h, format)) - { - GSVector4 dr(0, 0, w, h); - - StretchRect(src, sr, rt, dr, m_convert.ps[1], NULL, 0); - - if(CreateOffscreen(dst, w, h, format)) - { - m_dev->GetRenderTargetData(rt, dst); - } - } - - Recycle(rt); - - return !!dst; -} - -void GSDevice9::ClearRenderTarget(Texture& t, const GSVector4& c) -{ - ClearRenderTarget(t, D3DCOLOR_RGBA((BYTE)(c.r * 255 + 0.5f), (BYTE)(c.g * 255 + 0.5f), (BYTE)(c.b * 255 + 0.5f), (BYTE)(c.a * 255 + 0.5f))); -} - -void GSDevice9::ClearRenderTarget(Texture& t, DWORD c) -{ - CComPtr surface; - m_dev->GetRenderTarget(0, &surface); - m_dev->SetRenderTarget(0, t); - m_dev->Clear(0, NULL, D3DCLEAR_TARGET, c, 0, 0); - m_dev->SetRenderTarget(0, surface); -} - -void GSDevice9::ClearDepth(Texture& t, float c) -{ - CComPtr surface; - m_dev->GetDepthStencilSurface(&surface); - m_dev->SetDepthStencilSurface(t); - m_dev->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0, c, 0); - m_dev->SetDepthStencilSurface(surface); -} - -void GSDevice9::ClearStencil(Texture& t, BYTE c) -{ - CComPtr surface; - m_dev->GetDepthStencilSurface(&surface); - m_dev->SetDepthStencilSurface(t); - m_dev->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 0, c); - m_dev->SetDepthStencilSurface(surface); -} - -bool GSDevice9::Create(int type, Texture& t, int w, int h, int format) -{ - HRESULT hr; - - CComPtr texture; - CComPtr surface; - - switch(type) - { - case GSTexture::RenderTarget: - hr = m_dev->CreateTexture(w, h, 1, D3DUSAGE_RENDERTARGET, (D3DFORMAT)format, D3DPOOL_DEFAULT, &texture, NULL); - break; - case GSTexture::DepthStencil: - hr = m_dev->CreateDepthStencilSurface(w, h, (D3DFORMAT)format, D3DMULTISAMPLE_NONE, 0, FALSE, &surface, NULL); - break; - case GSTexture::Texture: - hr = m_dev->CreateTexture(w, h, 1, 0, (D3DFORMAT)format, D3DPOOL_MANAGED, &texture, NULL); - break; - case GSTexture::Offscreen: - hr = m_dev->CreateOffscreenPlainSurface(w, h, (D3DFORMAT)format, D3DPOOL_SYSTEMMEM, &surface, NULL); - break; - } - - if(surface) - { - t = Texture(surface); - } - - if(texture) - { - t = Texture(texture); - } - - if(t) - { - switch(type) - { - case GSTexture::RenderTarget: - ClearRenderTarget(t, 0); - break; - case GSTexture::DepthStencil: - ClearDepth(t, 0); - break; - } - - return t; - } - - return false; -} - -bool GSDevice9::CreateRenderTarget(Texture& t, int w, int h, int format) -{ - return __super::CreateRenderTarget(t, w, h, format ? format : D3DFMT_A8R8G8B8); -} - -bool GSDevice9::CreateDepthStencil(Texture& t, int w, int h, int format) -{ - return __super::CreateDepthStencil(t, w, h, format ? format : D3DFMT_D24S8); -} - -bool GSDevice9::CreateTexture(Texture& t, int w, int h, int format) -{ - return __super::CreateTexture(t, w, h, format ? format : D3DFMT_A8R8G8B8); -} - -bool GSDevice9::CreateOffscreen(Texture& t, int w, int h, int format) -{ - return __super::CreateOffscreen(t, w, h, format ? format : D3DFMT_A8R8G8B8); -} - -void GSDevice9::DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c) -{ - ClearRenderTarget(dt, c); - - if(st[1] && !slbg) - { - StretchRect(st[1], sr[1], dt, dr[1], m_merge.ps[0], NULL, true); - } - - if(st[0]) - { - MergeConstantBuffer cb; - - cb.BGColor = c; - - StretchRect(st[0], sr[0], dt, dr[0], m_merge.ps[mmod ? 1 : 0], (const float*)&cb, 1, &m_merge.bs, true); - } -} - -void GSDevice9::DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset) -{ - GSVector4 sr(0, 0, 1, 1); - GSVector4 dr(0.0f, yoffset, (float)dt.GetWidth(), (float)dt.GetHeight() + yoffset); - - InterlaceConstantBuffer cb; - - cb.ZrH = GSVector2(0, 1.0f / dt.GetHeight()); - cb.hH = (float)dt.GetHeight() / 2; - - StretchRect(st, sr, dt, dr, m_interlace.ps[shader], (const float*)&cb, 1, linear); -} -/* -void GSDevice9::IASetVertexBuffer(IDirect3DVertexBuffer9* vb, UINT count, const void* vertices, UINT stride) -{ - void* data = NULL; - - if(SUCCEEDED(vb->Lock(0, count * stride, &data, D3DLOCK_DISCARD))) - { - memcpy(data, vertices, count * stride); - - vb->Unlock(); - } - - if(m_vb != vb || m_vb_stride != stride) - { - m_dev->SetStreamSource(0, vb, 0, stride); - - m_vb = vb; - m_vb_stride = stride; - } -} -*/ -void GSDevice9::IASetVertexBuffer(UINT count, const void* vertices, UINT stride) -{ - m_vb_count = count; - m_vb_vertices = vertices; - m_vb_stride = stride; -} - -void GSDevice9::IASetInputLayout(IDirect3DVertexDeclaration9* layout) -{ - // TODO: get rid of all SetFVF before enabling this - - // if(m_layout != layout) - { - m_dev->SetVertexDeclaration(layout); - - // m_layout = layout; - } -} - -void GSDevice9::IASetPrimitiveTopology(D3DPRIMITIVETYPE topology) -{ - m_topology = topology; -} - -void GSDevice9::VSSetShader(IDirect3DVertexShader9* vs, const float* vs_cb, int vs_cb_len) -{ - if(m_vs != vs) - { - m_dev->SetVertexShader(vs); - - m_vs = vs; - } - - if(vs_cb && vs_cb_len > 0) - { - int size = vs_cb_len * sizeof(float) * 4; - - if(m_vs_cb_len != vs_cb_len || m_vs_cb == NULL || memcmp(m_vs_cb, vs_cb, size)) - { - if(m_vs_cb == NULL || m_vs_cb_len < vs_cb_len) - { - if(m_vs_cb) _aligned_free(m_vs_cb); - - m_vs_cb = (float*)_aligned_malloc(size, 16); - } - - memcpy(m_vs_cb, vs_cb, size); - - m_dev->SetVertexShaderConstantF(0, vs_cb, vs_cb_len); - - m_vs_cb_len = vs_cb_len; - } - } -} - -void GSDevice9::PSSetShaderResources(IDirect3DTexture9* srv0, IDirect3DTexture9* srv1) -{ - if(m_ps_srvs[0] != srv0) - { - m_dev->SetTexture(0, srv0); - - m_ps_srvs[0] = srv0; - } - - if(m_ps_srvs[1] != srv1) - { - m_dev->SetTexture(1, srv1); - - m_ps_srvs[1] = srv1; - } -} - -void GSDevice9::PSSetShader(IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len) -{ - if(m_ps != ps) - { - m_dev->SetPixelShader(ps); - - m_ps = ps; - } - - if(ps_cb && ps_cb_len > 0) - { - int size = ps_cb_len * sizeof(float) * 4; - - if(m_ps_cb_len != ps_cb_len || m_ps_cb == NULL || memcmp(m_ps_cb, ps_cb, size)) - { - if(m_ps_cb == NULL || m_ps_cb_len < ps_cb_len) - { - if(m_ps_cb) _aligned_free(m_ps_cb); - - m_ps_cb = (float*)_aligned_malloc(size, 16); - } - - memcpy(m_ps_cb, ps_cb, size); - - m_dev->SetPixelShaderConstantF(0, ps_cb, ps_cb_len); - - m_ps_cb_len = ps_cb_len; - } - } -} - -void GSDevice9::PSSetSamplerState(Direct3DSamplerState9* ss) -{ - if(ss && m_ps_ss != ss) - { - m_dev->SetSamplerState(0, D3DSAMP_ADDRESSU, ss->AddressU); - m_dev->SetSamplerState(0, D3DSAMP_ADDRESSV, ss->AddressV); - m_dev->SetSamplerState(1, D3DSAMP_ADDRESSU, ss->AddressU); - m_dev->SetSamplerState(1, D3DSAMP_ADDRESSV, ss->AddressV); - m_dev->SetSamplerState(2, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); - m_dev->SetSamplerState(2, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); - m_dev->SetSamplerState(3, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); - m_dev->SetSamplerState(3, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); - m_dev->SetSamplerState(0, D3DSAMP_MINFILTER, ss->FilterMin[0]); - m_dev->SetSamplerState(0, D3DSAMP_MAGFILTER, ss->FilterMag[0]); - m_dev->SetSamplerState(1, D3DSAMP_MINFILTER, ss->FilterMin[1]); - m_dev->SetSamplerState(1, D3DSAMP_MAGFILTER, ss->FilterMag[1]); - m_dev->SetSamplerState(2, D3DSAMP_MINFILTER, D3DTEXF_POINT); - m_dev->SetSamplerState(2, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - m_dev->SetSamplerState(3, D3DSAMP_MINFILTER, D3DTEXF_POINT); - m_dev->SetSamplerState(3, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - - m_ps_ss = ss; - } -} - -void GSDevice9::RSSet(int width, int height, const RECT* scissor) -{ - CRect r = scissor ? *scissor : CRect(0, 0, width, height); - - if(m_scissor != r) - { - m_dev->SetScissorRect(&r); - - m_scissor = r; - } -} - -void GSDevice9::OMSetDepthStencilState(Direct3DDepthStencilState9* dss, UINT sref) -{ - if(m_dss != dss || m_sref != sref) - { - m_dev->SetRenderState(D3DRS_ZENABLE, dss->DepthEnable); - m_dev->SetRenderState(D3DRS_ZWRITEENABLE, dss->DepthWriteMask); - - if(dss->DepthEnable) - { - m_dev->SetRenderState(D3DRS_ZFUNC, dss->DepthFunc); - } - - m_dev->SetRenderState(D3DRS_STENCILENABLE, dss->StencilEnable); - - if(dss->StencilEnable) - { - m_dev->SetRenderState(D3DRS_STENCILMASK, dss->StencilReadMask); - m_dev->SetRenderState(D3DRS_STENCILWRITEMASK, dss->StencilWriteMask); - m_dev->SetRenderState(D3DRS_STENCILFUNC, dss->StencilFunc); - m_dev->SetRenderState(D3DRS_STENCILPASS, dss->StencilPassOp); - m_dev->SetRenderState(D3DRS_STENCILFAIL, dss->StencilFailOp); - m_dev->SetRenderState(D3DRS_STENCILZFAIL, dss->StencilDepthFailOp); - m_dev->SetRenderState(D3DRS_STENCILREF, sref); - } - - m_dss = dss; - m_sref = sref; - } -} - -void GSDevice9::OMSetBlendState(Direct3DBlendState9* bs, DWORD bf) -{ - if(m_bs != bs || m_bf != bf) - { - m_dev->SetRenderState(D3DRS_ALPHABLENDENABLE, bs->BlendEnable); - - if(bs->BlendEnable) - { - m_dev->SetRenderState(D3DRS_BLENDOP, bs->BlendOp); - m_dev->SetRenderState(D3DRS_SRCBLEND, bs->SrcBlend); - m_dev->SetRenderState(D3DRS_DESTBLEND, bs->DestBlend); - m_dev->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); - m_dev->SetRenderState(D3DRS_BLENDOPALPHA, bs->BlendOpAlpha); - m_dev->SetRenderState(D3DRS_SRCBLENDALPHA, bs->SrcBlendAlpha); - m_dev->SetRenderState(D3DRS_DESTBLENDALPHA, bs->DestBlendAlpha); - m_dev->SetRenderState(D3DRS_BLENDFACTOR, bf); - } - - m_dev->SetRenderState(D3DRS_COLORWRITEENABLE, bs->RenderTargetWriteMask); - - m_bs = bs; - m_bf = bf; - } -} - -void GSDevice9::OMSetRenderTargets(IDirect3DSurface9* rtv, IDirect3DSurface9* dsv) -{ - if(m_rtv != rtv) - { - m_dev->SetRenderTarget(0, rtv); - - m_rtv = rtv; - } - - if(m_dsv != dsv) - { - m_dev->SetDepthStencilSurface(dsv); - - m_dsv = dsv; - } -} - -void GSDevice9::DrawPrimitive() -{ - int prims = 0; - - switch(m_topology) - { - case D3DPT_TRIANGLELIST: - prims = m_vb_count / 3; - break; - case D3DPT_LINELIST: - prims = m_vb_count / 2; - break; - case D3DPT_POINTLIST: - prims = m_vb_count; - break; - case D3DPT_TRIANGLESTRIP: - case D3DPT_TRIANGLEFAN: - prims = m_vb_count - 2; - break; - case D3DPT_LINESTRIP: - prims = m_vb_count - 1; - break; - } - - m_dev->DrawPrimitiveUP(m_topology, prims, m_vb_vertices, m_vb_stride); -} - -void GSDevice9::StretchRect(Texture& st, Texture& dt, const GSVector4& dr, bool linear) -{ - StretchRect(st, GSVector4(0, 0, 1, 1), dt, dr, linear); -} - -void GSDevice9::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, bool linear) -{ - StretchRect(st, sr, dt, dr, m_convert.ps[0], NULL, 0, linear); -} - -void GSDevice9::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, bool linear) -{ - StretchRect(st, sr, dt, dr, ps, ps_cb, ps_cb_len, &m_convert.bs, linear); -} - -void GSDevice9::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, Direct3DBlendState9* bs, bool linear) -{ - BeginScene(); - - // om - - OMSetDepthStencilState(&m_convert.dss, 0); - OMSetBlendState(bs, 0); - OMSetRenderTargets(dt, NULL); - - // ia - - float left = dr.x * 2 / dt.GetWidth() - 1.0f; - float top = 1.0f - dr.y * 2 / dt.GetHeight(); - float right = dr.z * 2 / dt.GetWidth() - 1.0f; - float bottom = 1.0f - dr.w * 2 / dt.GetHeight(); - - GSVertexPT1 vertices[] = - { - {GSVector4(left, top, 0.5f, 1.0f), GSVector2(sr.x, sr.y)}, - {GSVector4(right, top, 0.5f, 1.0f), GSVector2(sr.z, sr.y)}, - {GSVector4(left, bottom, 0.5f, 1.0f), GSVector2(sr.x, sr.w)}, - {GSVector4(right, bottom, 0.5f, 1.0f), GSVector2(sr.z, sr.w)}, - }; - - for(int i = 0; i < countof(vertices); i++) - { - vertices[i].p.x -= 1.0f / dt.GetWidth(); - vertices[i].p.y += 1.0f / dt.GetHeight(); - } - - IASetVertexBuffer(4, vertices); - IASetInputLayout(m_convert.il); - IASetPrimitiveTopology(D3DPT_TRIANGLESTRIP); - - // vs - - VSSetShader(m_convert.vs, NULL, 0); - - // ps - - PSSetShader(ps, ps_cb, ps_cb_len); - PSSetSamplerState(linear ? &m_convert.ln : &m_convert.pt); - PSSetShaderResources(st, NULL); - - // rs - - RSSet(dt.GetWidth(), dt.GetHeight()); - - // - - DrawPrimitive(); - - // - - EndScene(); -} - -// FIXME: D3DXCompileShaderFromResource of d3dx9 v37 (march 2008) calls GetFullPathName on id for some reason and then crashes - -static HRESULT LoadShader(UINT id, LPCSTR& data, DWORD& size) -{ - CComPtr shader, error; - - HRSRC hRes = FindResource(AfxGetResourceHandle(), MAKEINTRESOURCE(id), RT_RCDATA); - - if(!hRes) return E_FAIL; - - size = SizeofResource(AfxGetResourceHandle(), hRes); - - if(size == 0) return E_FAIL; - - HGLOBAL hResData = LoadResource(AfxGetResourceHandle(), hRes); - - if(!hResData) return E_FAIL; - - data = (LPCSTR)LockResource(hResData); - - return S_OK; -} - -HRESULT GSDevice9::CompileShader(UINT id, LPCSTR entry, const D3DXMACRO* macro, IDirect3DVertexShader9** vs, const D3DVERTEXELEMENT9* layout, int count, IDirect3DVertexDeclaration9** il) -{ - LPCSTR target; - - if(m_d3dcaps.VertexShaderVersion >= D3DVS_VERSION(3, 0)) - { - target = "vs_3_0"; - } - else if(m_d3dcaps.VertexShaderVersion >= D3DVS_VERSION(2, 0)) - { - target = "vs_2_0"; - } - else - { - return E_FAIL; - } - - HRESULT hr; - - CComPtr shader, error; - - // FIXME: hr = D3DXCompileShaderFromResource(AfxGetResourceHandle(), MAKEINTRESOURCE(id), macro, NULL, entry, target, 0, &shader, &error, NULL); - - LPCSTR data; - DWORD size; - - hr = LoadShader(id, data, size); - - if(FAILED(hr)) return E_FAIL; - - hr = D3DXCompileShader(data, size, macro, NULL, entry, target, 0, &shader, &error, NULL); - - if(SUCCEEDED(hr)) - { - hr = m_dev->CreateVertexShader((DWORD*)shader->GetBufferPointer(), vs); - } - else if(error) - { - LPCSTR msg = (LPCSTR)error->GetBufferPointer(); - - TRACE(_T("%s\n"), CString(msg)); - } - - ASSERT(SUCCEEDED(hr)); - - if(FAILED(hr)) - { - return hr; - } - - hr = m_dev->CreateVertexDeclaration(layout, il); - - if(FAILED(hr)) - { - return hr; - } - - return S_OK; -} - -HRESULT GSDevice9::CompileShader(UINT id, LPCSTR entry, const D3DXMACRO* macro, IDirect3DPixelShader9** ps) -{ - LPCSTR target = NULL; - UINT flags = 0; - - if(m_d3dcaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) - { - target = "ps_3_0"; - flags |= D3DXSHADER_AVOID_FLOW_CONTROL; - } - else if(m_d3dcaps.PixelShaderVersion >= D3DPS_VERSION(2, 0)) - { - target = "ps_2_0"; - } - else - { - return false; - } - - HRESULT hr; - - CComPtr shader, error; - - // FIXME: hr = D3DXCompileShaderFromResource(AfxGetResourceHandle(), MAKEINTRESOURCE(id), macro, NULL, entry, target, flags, &shader, &error, NULL); - - LPCSTR data; - DWORD size; - - hr = LoadShader(id, data, size); - - if(FAILED(hr)) return E_FAIL; - - hr = D3DXCompileShader(data, size, macro, NULL, entry, target, 0, &shader, &error, NULL); - - if(SUCCEEDED(hr)) - { - hr = m_dev->CreatePixelShader((DWORD*)shader->GetBufferPointer(), ps); - - ASSERT(SUCCEEDED(hr)); - } - else if(error) - { - LPCSTR msg = (LPCSTR)error->GetBufferPointer(); - - TRACE(_T("%s\n"), CString(msg)); - } - - ASSERT(SUCCEEDED(hr)); - - if(FAILED(hr)) - { - return hr; - } - - return S_OK; -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSDevice9.h" +#include "resource.h" + +GSDevice9::GSDevice9() + : m_vb(NULL) + , m_vb_count(0) + , m_vb_vertices(NULL) + , m_vb_stride(0) + , m_layout(NULL) + , m_topology((D3DPRIMITIVETYPE)0) + , m_vs(NULL) + , m_vs_cb(NULL) + , m_vs_cb_len(0) + , m_ps(NULL) + , m_ps_cb(NULL) + , m_ps_cb_len(0) + , m_ps_ss(NULL) + , m_scissor(0, 0, 0, 0) + , m_dss(NULL) + , m_sref(0) + , m_bs(NULL) + , m_bf(0xffffffff) + , m_rtv(NULL) + , m_dsv(NULL) +{ + memset(&m_pp, 0, sizeof(m_pp)); + memset(&m_ddcaps, 0, sizeof(m_ddcaps)); + memset(&m_d3dcaps, 0, sizeof(m_d3dcaps)); + memset(m_ps_srvs, 0, sizeof(m_ps_srvs)); +} + +GSDevice9::~GSDevice9() +{ + if(m_vs_cb) _aligned_free(m_vs_cb); + if(m_ps_cb) _aligned_free(m_ps_cb); +} + +bool GSDevice9::Create(HWND hWnd, bool vsync) +{ + if(!__super::Create(hWnd, vsync)) + { + return false; + } + + HRESULT hr; + + // dd + + CComPtr dd; + + hr = DirectDrawCreateEx(0, (void**)&dd, IID_IDirectDraw7, 0); + + if(FAILED(hr)) return false; + + memset(&m_ddcaps, 0, sizeof(m_ddcaps)); + + m_ddcaps.dwSize = sizeof(DDCAPS); + + hr = dd->GetCaps(&m_ddcaps, NULL); + + if(FAILED(hr)) return false; + + dd = NULL; + + // d3d + + m_d3d = Direct3DCreate9(D3D_SDK_VERSION); + + if(!m_d3d) return false; + + hr = m_d3d->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24S8); + + if(FAILED(hr)) return false; + + hr = m_d3d->CheckDepthStencilMatch(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_D24S8); + + if(FAILED(hr)) return false; + + memset(&m_d3dcaps, 0, sizeof(m_d3dcaps)); + + m_d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &m_d3dcaps); + + bool fs = AfxGetApp()->GetProfileInt(_T("Settings"), _T("ModeWidth"), 0) > 0; + + if(!Reset(1, 1, fs)) return false; + + m_dev->Clear(0, NULL, D3DCLEAR_TARGET, 0, 1.0f, 0); + + // shaders + + DWORD psver = AfxGetApp()->GetProfileInt(_T("Settings"), _T("PixelShaderVersion2"), D3DPS_VERSION(2, 0)); + + if(psver > m_d3dcaps.PixelShaderVersion) + { + CString str; + + str.Format(_T("Supported pixel shader version is too low!\n\nSupported: %d.%d\nSelected: %d.%d"), + D3DSHADER_VERSION_MAJOR(m_d3dcaps.PixelShaderVersion), D3DSHADER_VERSION_MINOR(m_d3dcaps.PixelShaderVersion), + D3DSHADER_VERSION_MAJOR(psver), D3DSHADER_VERSION_MINOR(psver)); + + AfxMessageBox(str); + + return false; + } + + m_d3dcaps.PixelShaderVersion = min(psver, m_d3dcaps.PixelShaderVersion); + m_d3dcaps.VertexShaderVersion = m_d3dcaps.PixelShaderVersion & ~0x10000; + + // convert + + static const D3DVERTEXELEMENT9 il_convert[] = + { + {0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, + {0, 16, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, + D3DDECL_END() + }; + + CompileShader(IDR_CONVERT9_FX, "vs_main", NULL, &m_convert.vs, il_convert, countof(il_convert), &m_convert.il); + + for(int i = 0; i < countof(m_convert.ps); i++) + { + CStringA main; + main.Format("ps_main%d", i); + CompileShader(IDR_CONVERT9_FX, main, NULL, &m_convert.ps[i]); + } + + m_convert.dss.DepthEnable = false; + m_convert.dss.StencilEnable = false; + + m_convert.bs.BlendEnable = false; + m_convert.bs.RenderTargetWriteMask = D3DCOLORWRITEENABLE_RGBA; + + m_convert.ln.FilterMin[0] = D3DTEXF_LINEAR; + m_convert.ln.FilterMag[0] = D3DTEXF_LINEAR; + m_convert.ln.FilterMin[1] = D3DTEXF_LINEAR; + m_convert.ln.FilterMag[1] = D3DTEXF_LINEAR; + m_convert.ln.AddressU = D3DTADDRESS_CLAMP; + m_convert.ln.AddressV = D3DTADDRESS_CLAMP; + + m_convert.pt.FilterMin[0] = D3DTEXF_POINT; + m_convert.pt.FilterMag[0] = D3DTEXF_POINT; + m_convert.pt.FilterMin[1] = D3DTEXF_POINT; + m_convert.pt.FilterMag[1] = D3DTEXF_POINT; + m_convert.pt.AddressU = D3DTADDRESS_CLAMP; + m_convert.pt.AddressV = D3DTADDRESS_CLAMP; + + // merge + + for(int i = 0; i < countof(m_merge.ps); i++) + { + CStringA main; + main.Format("ps_main%d", i); + CompileShader(IDR_MERGE9_FX, main, NULL, &m_merge.ps[i]); + } + + m_merge.bs.BlendEnable = true; + m_merge.bs.BlendOp = D3DBLENDOP_ADD; + m_merge.bs.SrcBlend = D3DBLEND_SRCALPHA; + m_merge.bs.DestBlend = D3DBLEND_INVSRCALPHA; + m_merge.bs.BlendOpAlpha = D3DBLENDOP_ADD; + m_merge.bs.SrcBlendAlpha = D3DBLEND_ONE; + m_merge.bs.DestBlendAlpha = D3DBLEND_ZERO; + m_merge.bs.RenderTargetWriteMask = D3DCOLORWRITEENABLE_RGBA; + + // interlace + + for(int i = 0; i < countof(m_interlace.ps); i++) + { + CStringA main; + main.Format("ps_main%d", i); + CompileShader(IDR_INTERLACE9_FX, main, NULL, &m_interlace.ps[i]); + } + + // + + return true; +} + +bool GSDevice9::Reset(int w, int h, bool fs) +{ + if(!__super::Reset(w, h, fs)) + return false; + + HRESULT hr; + + if(!m_d3d) return false; + + if(m_swapchain && !fs && m_pp.Windowed) + { + m_swapchain = NULL; + + m_pp.BackBufferWidth = w; + m_pp.BackBufferHeight = h; + + hr = m_dev->CreateAdditionalSwapChain(&m_pp, &m_swapchain); + + if(FAILED(hr)) return false; + + CComPtr backbuffer; + hr = m_swapchain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &backbuffer); + m_backbuffer = Texture(backbuffer); + + return true; + } + + m_swapchain = NULL; + m_backbuffer = Texture(); + if(m_font) m_font->OnLostDevice(); + m_font = NULL; + + if(m_vs_cb) _aligned_free(m_vs_cb); + if(m_ps_cb) _aligned_free(m_ps_cb); + + m_vb = NULL; + m_vb_stride = 0; + m_layout = NULL; + m_vs = NULL; + m_vs_cb = NULL; + m_vs_cb_len = 0; + m_ps = NULL; + m_ps_cb = NULL; + m_ps_cb_len = 0; + m_ps_ss = NULL; + m_scissor = CRect(0, 0, 0, 0); + m_dss = NULL; + m_sref = 0; + m_bs = NULL; + m_bf = 0xffffffff; + m_rtv = NULL; + m_dsv = NULL; + + memset(&m_pp, 0, sizeof(m_pp)); + + m_pp.Windowed = TRUE; + m_pp.hDeviceWindow = m_hWnd; + m_pp.SwapEffect = D3DSWAPEFFECT_FLIP; + m_pp.BackBufferFormat = D3DFMT_X8R8G8B8; + m_pp.BackBufferWidth = 1; + m_pp.BackBufferHeight = 1; + m_pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + + if(m_vsync) + { + m_pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; + } + + if(!!AfxGetApp()->GetProfileInt(_T("Settings"), _T("tvout"), FALSE)) + { + m_pp.Flags |= D3DPRESENTFLAG_VIDEO; + } + + int mw = AfxGetApp()->GetProfileInt(_T("Settings"), _T("ModeWidth"), 0); + int mh = AfxGetApp()->GetProfileInt(_T("Settings"), _T("ModeHeight"), 0); + int mrr = AfxGetApp()->GetProfileInt(_T("Settings"), _T("ModeRefreshRate"), 0); + + if(fs && mw > 0 && mh > 0 && mrr >= 0) + { + m_pp.Windowed = FALSE; + m_pp.BackBufferWidth = mw; + m_pp.BackBufferHeight = mh; + // m_pp.FullScreen_RefreshRateInHz = mrr; + + ::SetWindowLong(m_hWnd, GWL_STYLE, ::GetWindowLong(m_hWnd, GWL_STYLE) & ~(WS_CAPTION|WS_THICKFRAME)); + ::SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + ::SetMenu(m_hWnd, NULL); + } + + if(!m_dev) + { + UINT flags = D3DCREATE_MULTITHREADED | (m_d3dcaps.VertexProcessingCaps ? D3DCREATE_HARDWARE_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING); + + hr = m_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, flags, &m_pp, &m_dev); + + if(FAILED(hr)) return false; + } + else + { + hr = m_dev->Reset(&m_pp); + + if(FAILED(hr)) + { + if(D3DERR_DEVICELOST == hr) + { + Sleep(1000); + + hr = m_dev->Reset(&m_pp); + } + + if(FAILED(hr)) return false; + } + } + + if(m_pp.Windowed) + { + m_pp.BackBufferWidth = 1; + m_pp.BackBufferHeight = 1; + + hr = m_dev->CreateAdditionalSwapChain(&m_pp, &m_swapchain); + + if(FAILED(hr)) return false; + } + + CComPtr backbuffer; + + if(m_swapchain) + { + hr = m_swapchain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &backbuffer); + } + else + { + hr = m_dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer); + } + + m_backbuffer = Texture(backbuffer); + + D3DXFONT_DESC fd; + memset(&fd, 0, sizeof(fd)); + _tcscpy(fd.FaceName, _T("Arial")); + fd.Height = 20; + D3DXCreateFontIndirect(m_dev, &fd, &m_font); + + m_dev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + m_dev->SetRenderState(D3DRS_LIGHTING, FALSE); + m_dev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + m_dev->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); + + return true; +} + +bool GSDevice9::IsLost() +{ + HRESULT hr = m_dev->TestCooperativeLevel(); + + return hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICENOTRESET; +} + +void GSDevice9::Present(const CRect& r) +{ + CRect cr; + + GetClientRect(m_hWnd, &cr); + + if(m_backbuffer.GetWidth() != cr.Width() || m_backbuffer.GetHeight() != cr.Height()) + { + Reset(cr.Width(), cr.Height(), false); + } + + OMSetRenderTargets(m_backbuffer, NULL); + + m_dev->Clear(0, NULL, D3DCLEAR_TARGET, 0, 1.0f, 0); + + if(m_current) + { + StretchRect(m_current, m_backbuffer, GSVector4(r)); + } + + if(m_swapchain) + { + m_swapchain->Present(NULL, NULL, NULL, NULL, 0); + } + else + { + m_dev->Present(NULL, NULL, NULL, NULL); + } +} + +void GSDevice9::BeginScene() +{ + m_dev->BeginScene(); +} + +void GSDevice9::EndScene() +{ + m_dev->EndScene(); +} + +void GSDevice9::Draw(LPCTSTR str) +{ + /* + if(!m_pp.Windowed) + { + BeginScene(); + + OMSetRenderTargets(m_backbuffer, NULL); + + CRect r(0, 0, m_backbuffer.GetWidth(), m_backbuffer.GetHeight()); + + D3DCOLOR c = D3DCOLOR_ARGB(255, 0, 255, 0); + + if(m_font->DrawText(NULL, str, -1, &r, DT_CALCRECT|DT_LEFT|DT_WORDBREAK, c)) + { + m_font->DrawText(NULL, str, -1, &r, DT_LEFT|DT_WORDBREAK, c); + } + + EndScene(); + } + */ +} + +bool GSDevice9::CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format) +{ + dst = Texture(); + + if(format == 0) + { + format = D3DFMT_A8R8G8B8; + } + + if(format != D3DFMT_A8R8G8B8) + { + ASSERT(0); + + return false; + } + + Texture rt; + + if(CreateRenderTarget(rt, w, h, format)) + { + GSVector4 dr(0, 0, w, h); + + StretchRect(src, sr, rt, dr, m_convert.ps[1], NULL, 0); + + if(CreateOffscreen(dst, w, h, format)) + { + m_dev->GetRenderTargetData(rt, dst); + } + } + + Recycle(rt); + + return !!dst; +} + +void GSDevice9::ClearRenderTarget(Texture& t, const GSVector4& c) +{ + ClearRenderTarget(t, D3DCOLOR_RGBA((BYTE)(c.r * 255 + 0.5f), (BYTE)(c.g * 255 + 0.5f), (BYTE)(c.b * 255 + 0.5f), (BYTE)(c.a * 255 + 0.5f))); +} + +void GSDevice9::ClearRenderTarget(Texture& t, DWORD c) +{ + CComPtr surface; + m_dev->GetRenderTarget(0, &surface); + m_dev->SetRenderTarget(0, t); + m_dev->Clear(0, NULL, D3DCLEAR_TARGET, c, 0, 0); + m_dev->SetRenderTarget(0, surface); +} + +void GSDevice9::ClearDepth(Texture& t, float c) +{ + CComPtr surface; + m_dev->GetDepthStencilSurface(&surface); + m_dev->SetDepthStencilSurface(t); + m_dev->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0, c, 0); + m_dev->SetDepthStencilSurface(surface); +} + +void GSDevice9::ClearStencil(Texture& t, BYTE c) +{ + CComPtr surface; + m_dev->GetDepthStencilSurface(&surface); + m_dev->SetDepthStencilSurface(t); + m_dev->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 0, c); + m_dev->SetDepthStencilSurface(surface); +} + +bool GSDevice9::Create(int type, Texture& t, int w, int h, int format) +{ + HRESULT hr; + + CComPtr texture; + CComPtr surface; + + switch(type) + { + case GSTexture::RenderTarget: + hr = m_dev->CreateTexture(w, h, 1, D3DUSAGE_RENDERTARGET, (D3DFORMAT)format, D3DPOOL_DEFAULT, &texture, NULL); + break; + case GSTexture::DepthStencil: + hr = m_dev->CreateDepthStencilSurface(w, h, (D3DFORMAT)format, D3DMULTISAMPLE_NONE, 0, FALSE, &surface, NULL); + break; + case GSTexture::Texture: + hr = m_dev->CreateTexture(w, h, 1, 0, (D3DFORMAT)format, D3DPOOL_MANAGED, &texture, NULL); + break; + case GSTexture::Offscreen: + hr = m_dev->CreateOffscreenPlainSurface(w, h, (D3DFORMAT)format, D3DPOOL_SYSTEMMEM, &surface, NULL); + break; + } + + if(surface) + { + t = Texture(surface); + } + + if(texture) + { + t = Texture(texture); + } + + if(t) + { + switch(type) + { + case GSTexture::RenderTarget: + ClearRenderTarget(t, 0); + break; + case GSTexture::DepthStencil: + ClearDepth(t, 0); + break; + } + + return t; + } + + return false; +} + +bool GSDevice9::CreateRenderTarget(Texture& t, int w, int h, int format) +{ + return __super::CreateRenderTarget(t, w, h, format ? format : D3DFMT_A8R8G8B8); +} + +bool GSDevice9::CreateDepthStencil(Texture& t, int w, int h, int format) +{ + return __super::CreateDepthStencil(t, w, h, format ? format : D3DFMT_D24S8); +} + +bool GSDevice9::CreateTexture(Texture& t, int w, int h, int format) +{ + return __super::CreateTexture(t, w, h, format ? format : D3DFMT_A8R8G8B8); +} + +bool GSDevice9::CreateOffscreen(Texture& t, int w, int h, int format) +{ + return __super::CreateOffscreen(t, w, h, format ? format : D3DFMT_A8R8G8B8); +} + +void GSDevice9::DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c) +{ + ClearRenderTarget(dt, c); + + if(st[1] && !slbg) + { + StretchRect(st[1], sr[1], dt, dr[1], m_merge.ps[0], NULL, true); + } + + if(st[0]) + { + MergeConstantBuffer cb; + + cb.BGColor = c; + + StretchRect(st[0], sr[0], dt, dr[0], m_merge.ps[mmod ? 1 : 0], (const float*)&cb, 1, &m_merge.bs, true); + } +} + +void GSDevice9::DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset) +{ + GSVector4 sr(0, 0, 1, 1); + GSVector4 dr(0.0f, yoffset, (float)dt.GetWidth(), (float)dt.GetHeight() + yoffset); + + InterlaceConstantBuffer cb; + + cb.ZrH = GSVector2(0, 1.0f / dt.GetHeight()); + cb.hH = (float)dt.GetHeight() / 2; + + StretchRect(st, sr, dt, dr, m_interlace.ps[shader], (const float*)&cb, 1, linear); +} +/* +void GSDevice9::IASetVertexBuffer(IDirect3DVertexBuffer9* vb, UINT count, const void* vertices, UINT stride) +{ + void* data = NULL; + + if(SUCCEEDED(vb->Lock(0, count * stride, &data, D3DLOCK_DISCARD))) + { + memcpy(data, vertices, count * stride); + + vb->Unlock(); + } + + if(m_vb != vb || m_vb_stride != stride) + { + m_dev->SetStreamSource(0, vb, 0, stride); + + m_vb = vb; + m_vb_stride = stride; + } +} +*/ +void GSDevice9::IASetVertexBuffer(UINT count, const void* vertices, UINT stride) +{ + m_vb_count = count; + m_vb_vertices = vertices; + m_vb_stride = stride; +} + +void GSDevice9::IASetInputLayout(IDirect3DVertexDeclaration9* layout) +{ + // TODO: get rid of all SetFVF before enabling this + + // if(m_layout != layout) + { + m_dev->SetVertexDeclaration(layout); + + // m_layout = layout; + } +} + +void GSDevice9::IASetPrimitiveTopology(D3DPRIMITIVETYPE topology) +{ + m_topology = topology; +} + +void GSDevice9::VSSetShader(IDirect3DVertexShader9* vs, const float* vs_cb, int vs_cb_len) +{ + if(m_vs != vs) + { + m_dev->SetVertexShader(vs); + + m_vs = vs; + } + + if(vs_cb && vs_cb_len > 0) + { + int size = vs_cb_len * sizeof(float) * 4; + + if(m_vs_cb_len != vs_cb_len || m_vs_cb == NULL || memcmp(m_vs_cb, vs_cb, size)) + { + if(m_vs_cb == NULL || m_vs_cb_len < vs_cb_len) + { + if(m_vs_cb) _aligned_free(m_vs_cb); + + m_vs_cb = (float*)_aligned_malloc(size, 16); + } + + memcpy(m_vs_cb, vs_cb, size); + + m_dev->SetVertexShaderConstantF(0, vs_cb, vs_cb_len); + + m_vs_cb_len = vs_cb_len; + } + } +} + +void GSDevice9::PSSetShaderResources(IDirect3DTexture9* srv0, IDirect3DTexture9* srv1) +{ + if(m_ps_srvs[0] != srv0) + { + m_dev->SetTexture(0, srv0); + + m_ps_srvs[0] = srv0; + } + + if(m_ps_srvs[1] != srv1) + { + m_dev->SetTexture(1, srv1); + + m_ps_srvs[1] = srv1; + } +} + +void GSDevice9::PSSetShader(IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len) +{ + if(m_ps != ps) + { + m_dev->SetPixelShader(ps); + + m_ps = ps; + } + + if(ps_cb && ps_cb_len > 0) + { + int size = ps_cb_len * sizeof(float) * 4; + + if(m_ps_cb_len != ps_cb_len || m_ps_cb == NULL || memcmp(m_ps_cb, ps_cb, size)) + { + if(m_ps_cb == NULL || m_ps_cb_len < ps_cb_len) + { + if(m_ps_cb) _aligned_free(m_ps_cb); + + m_ps_cb = (float*)_aligned_malloc(size, 16); + } + + memcpy(m_ps_cb, ps_cb, size); + + m_dev->SetPixelShaderConstantF(0, ps_cb, ps_cb_len); + + m_ps_cb_len = ps_cb_len; + } + } +} + +void GSDevice9::PSSetSamplerState(Direct3DSamplerState9* ss) +{ + if(ss && m_ps_ss != ss) + { + m_dev->SetSamplerState(0, D3DSAMP_ADDRESSU, ss->AddressU); + m_dev->SetSamplerState(0, D3DSAMP_ADDRESSV, ss->AddressV); + m_dev->SetSamplerState(1, D3DSAMP_ADDRESSU, ss->AddressU); + m_dev->SetSamplerState(1, D3DSAMP_ADDRESSV, ss->AddressV); + m_dev->SetSamplerState(2, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + m_dev->SetSamplerState(2, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + m_dev->SetSamplerState(3, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + m_dev->SetSamplerState(3, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + m_dev->SetSamplerState(0, D3DSAMP_MINFILTER, ss->FilterMin[0]); + m_dev->SetSamplerState(0, D3DSAMP_MAGFILTER, ss->FilterMag[0]); + m_dev->SetSamplerState(1, D3DSAMP_MINFILTER, ss->FilterMin[1]); + m_dev->SetSamplerState(1, D3DSAMP_MAGFILTER, ss->FilterMag[1]); + m_dev->SetSamplerState(2, D3DSAMP_MINFILTER, D3DTEXF_POINT); + m_dev->SetSamplerState(2, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + m_dev->SetSamplerState(3, D3DSAMP_MINFILTER, D3DTEXF_POINT); + m_dev->SetSamplerState(3, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + + m_ps_ss = ss; + } +} + +void GSDevice9::RSSet(int width, int height, const RECT* scissor) +{ + CRect r = scissor ? *scissor : CRect(0, 0, width, height); + + if(m_scissor != r) + { + m_dev->SetScissorRect(&r); + + m_scissor = r; + } +} + +void GSDevice9::OMSetDepthStencilState(Direct3DDepthStencilState9* dss, UINT sref) +{ + if(m_dss != dss || m_sref != sref) + { + m_dev->SetRenderState(D3DRS_ZENABLE, dss->DepthEnable); + m_dev->SetRenderState(D3DRS_ZWRITEENABLE, dss->DepthWriteMask); + + if(dss->DepthEnable) + { + m_dev->SetRenderState(D3DRS_ZFUNC, dss->DepthFunc); + } + + m_dev->SetRenderState(D3DRS_STENCILENABLE, dss->StencilEnable); + + if(dss->StencilEnable) + { + m_dev->SetRenderState(D3DRS_STENCILMASK, dss->StencilReadMask); + m_dev->SetRenderState(D3DRS_STENCILWRITEMASK, dss->StencilWriteMask); + m_dev->SetRenderState(D3DRS_STENCILFUNC, dss->StencilFunc); + m_dev->SetRenderState(D3DRS_STENCILPASS, dss->StencilPassOp); + m_dev->SetRenderState(D3DRS_STENCILFAIL, dss->StencilFailOp); + m_dev->SetRenderState(D3DRS_STENCILZFAIL, dss->StencilDepthFailOp); + m_dev->SetRenderState(D3DRS_STENCILREF, sref); + } + + m_dss = dss; + m_sref = sref; + } +} + +void GSDevice9::OMSetBlendState(Direct3DBlendState9* bs, DWORD bf) +{ + if(m_bs != bs || m_bf != bf) + { + m_dev->SetRenderState(D3DRS_ALPHABLENDENABLE, bs->BlendEnable); + + if(bs->BlendEnable) + { + m_dev->SetRenderState(D3DRS_BLENDOP, bs->BlendOp); + m_dev->SetRenderState(D3DRS_SRCBLEND, bs->SrcBlend); + m_dev->SetRenderState(D3DRS_DESTBLEND, bs->DestBlend); + m_dev->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + m_dev->SetRenderState(D3DRS_BLENDOPALPHA, bs->BlendOpAlpha); + m_dev->SetRenderState(D3DRS_SRCBLENDALPHA, bs->SrcBlendAlpha); + m_dev->SetRenderState(D3DRS_DESTBLENDALPHA, bs->DestBlendAlpha); + m_dev->SetRenderState(D3DRS_BLENDFACTOR, bf); + } + + m_dev->SetRenderState(D3DRS_COLORWRITEENABLE, bs->RenderTargetWriteMask); + + m_bs = bs; + m_bf = bf; + } +} + +void GSDevice9::OMSetRenderTargets(IDirect3DSurface9* rtv, IDirect3DSurface9* dsv) +{ + if(m_rtv != rtv) + { + m_dev->SetRenderTarget(0, rtv); + + m_rtv = rtv; + } + + if(m_dsv != dsv) + { + m_dev->SetDepthStencilSurface(dsv); + + m_dsv = dsv; + } +} + +void GSDevice9::DrawPrimitive() +{ + int prims = 0; + + switch(m_topology) + { + case D3DPT_TRIANGLELIST: + prims = m_vb_count / 3; + break; + case D3DPT_LINELIST: + prims = m_vb_count / 2; + break; + case D3DPT_POINTLIST: + prims = m_vb_count; + break; + case D3DPT_TRIANGLESTRIP: + case D3DPT_TRIANGLEFAN: + prims = m_vb_count - 2; + break; + case D3DPT_LINESTRIP: + prims = m_vb_count - 1; + break; + } + + m_dev->DrawPrimitiveUP(m_topology, prims, m_vb_vertices, m_vb_stride); +} + +void GSDevice9::StretchRect(Texture& st, Texture& dt, const GSVector4& dr, bool linear) +{ + StretchRect(st, GSVector4(0, 0, 1, 1), dt, dr, linear); +} + +void GSDevice9::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, bool linear) +{ + StretchRect(st, sr, dt, dr, m_convert.ps[0], NULL, 0, linear); +} + +void GSDevice9::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, bool linear) +{ + StretchRect(st, sr, dt, dr, ps, ps_cb, ps_cb_len, &m_convert.bs, linear); +} + +void GSDevice9::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, Direct3DBlendState9* bs, bool linear) +{ + BeginScene(); + + // om + + OMSetDepthStencilState(&m_convert.dss, 0); + OMSetBlendState(bs, 0); + OMSetRenderTargets(dt, NULL); + + // ia + + float left = dr.x * 2 / dt.GetWidth() - 1.0f; + float top = 1.0f - dr.y * 2 / dt.GetHeight(); + float right = dr.z * 2 / dt.GetWidth() - 1.0f; + float bottom = 1.0f - dr.w * 2 / dt.GetHeight(); + + GSVertexPT1 vertices[] = + { + {GSVector4(left, top, 0.5f, 1.0f), GSVector2(sr.x, sr.y)}, + {GSVector4(right, top, 0.5f, 1.0f), GSVector2(sr.z, sr.y)}, + {GSVector4(left, bottom, 0.5f, 1.0f), GSVector2(sr.x, sr.w)}, + {GSVector4(right, bottom, 0.5f, 1.0f), GSVector2(sr.z, sr.w)}, + }; + + for(int i = 0; i < countof(vertices); i++) + { + vertices[i].p.x -= 1.0f / dt.GetWidth(); + vertices[i].p.y += 1.0f / dt.GetHeight(); + } + + IASetVertexBuffer(4, vertices); + IASetInputLayout(m_convert.il); + IASetPrimitiveTopology(D3DPT_TRIANGLESTRIP); + + // vs + + VSSetShader(m_convert.vs, NULL, 0); + + // ps + + PSSetShader(ps, ps_cb, ps_cb_len); + PSSetSamplerState(linear ? &m_convert.ln : &m_convert.pt); + PSSetShaderResources(st, NULL); + + // rs + + RSSet(dt.GetWidth(), dt.GetHeight()); + + // + + DrawPrimitive(); + + // + + EndScene(); +} + +// FIXME: D3DXCompileShaderFromResource of d3dx9 v37 (march 2008) calls GetFullPathName on id for some reason and then crashes + +static HRESULT LoadShader(UINT id, LPCSTR& data, DWORD& size) +{ + CComPtr shader, error; + + HRSRC hRes = FindResource(AfxGetResourceHandle(), MAKEINTRESOURCE(id), RT_RCDATA); + + if(!hRes) return E_FAIL; + + size = SizeofResource(AfxGetResourceHandle(), hRes); + + if(size == 0) return E_FAIL; + + HGLOBAL hResData = LoadResource(AfxGetResourceHandle(), hRes); + + if(!hResData) return E_FAIL; + + data = (LPCSTR)LockResource(hResData); + + return S_OK; +} + +HRESULT GSDevice9::CompileShader(UINT id, LPCSTR entry, const D3DXMACRO* macro, IDirect3DVertexShader9** vs, const D3DVERTEXELEMENT9* layout, int count, IDirect3DVertexDeclaration9** il) +{ + LPCSTR target; + + if(m_d3dcaps.VertexShaderVersion >= D3DVS_VERSION(3, 0)) + { + target = "vs_3_0"; + } + else if(m_d3dcaps.VertexShaderVersion >= D3DVS_VERSION(2, 0)) + { + target = "vs_2_0"; + } + else + { + return E_FAIL; + } + + HRESULT hr; + + CComPtr shader, error; + + // FIXME: hr = D3DXCompileShaderFromResource(AfxGetResourceHandle(), MAKEINTRESOURCE(id), macro, NULL, entry, target, 0, &shader, &error, NULL); + + LPCSTR data; + DWORD size; + + hr = LoadShader(id, data, size); + + if(FAILED(hr)) return E_FAIL; + + hr = D3DXCompileShader(data, size, macro, NULL, entry, target, 0, &shader, &error, NULL); + + if(SUCCEEDED(hr)) + { + hr = m_dev->CreateVertexShader((DWORD*)shader->GetBufferPointer(), vs); + } + else if(error) + { + LPCSTR msg = (LPCSTR)error->GetBufferPointer(); + + TRACE(_T("%s\n"), CString(msg)); + } + + ASSERT(SUCCEEDED(hr)); + + if(FAILED(hr)) + { + return hr; + } + + hr = m_dev->CreateVertexDeclaration(layout, il); + + if(FAILED(hr)) + { + return hr; + } + + return S_OK; +} + +HRESULT GSDevice9::CompileShader(UINT id, LPCSTR entry, const D3DXMACRO* macro, IDirect3DPixelShader9** ps) +{ + LPCSTR target = NULL; + UINT flags = 0; + + if(m_d3dcaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) + { + target = "ps_3_0"; + flags |= D3DXSHADER_AVOID_FLOW_CONTROL; + } + else if(m_d3dcaps.PixelShaderVersion >= D3DPS_VERSION(2, 0)) + { + target = "ps_2_0"; + } + else + { + return false; + } + + HRESULT hr; + + CComPtr shader, error; + + // FIXME: hr = D3DXCompileShaderFromResource(AfxGetResourceHandle(), MAKEINTRESOURCE(id), macro, NULL, entry, target, flags, &shader, &error, NULL); + + LPCSTR data; + DWORD size; + + hr = LoadShader(id, data, size); + + if(FAILED(hr)) return E_FAIL; + + hr = D3DXCompileShader(data, size, macro, NULL, entry, target, 0, &shader, &error, NULL); + + if(SUCCEEDED(hr)) + { + hr = m_dev->CreatePixelShader((DWORD*)shader->GetBufferPointer(), ps); + + ASSERT(SUCCEEDED(hr)); + } + else if(error) + { + LPCSTR msg = (LPCSTR)error->GetBufferPointer(); + + TRACE(_T("%s\n"), CString(msg)); + } + + ASSERT(SUCCEEDED(hr)); + + if(FAILED(hr)) + { + return hr; + } + + return S_OK; +} diff --git a/plugins/GSdx/GSDevice9.h b/plugins/GSdx/GSDevice9.h index 0a4fe10e43..5a16aa0106 100644 --- a/plugins/GSdx/GSDevice9.h +++ b/plugins/GSdx/GSDevice9.h @@ -1,192 +1,192 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSDevice.h" -#include "GSTexture9.h" - -struct Direct3DSamplerState9 -{ - D3DTEXTUREFILTERTYPE FilterMin[2]; - D3DTEXTUREFILTERTYPE FilterMag[2]; - D3DTEXTUREADDRESS AddressU; - D3DTEXTUREADDRESS AddressV; -}; - -struct Direct3DDepthStencilState9 -{ - BOOL DepthEnable; - BOOL DepthWriteMask; - D3DCMPFUNC DepthFunc; - BOOL StencilEnable; - UINT8 StencilReadMask; - UINT8 StencilWriteMask; - D3DSTENCILOP StencilFailOp; - D3DSTENCILOP StencilDepthFailOp; - D3DSTENCILOP StencilPassOp; - D3DCMPFUNC StencilFunc; -}; - -struct Direct3DBlendState9 -{ - BOOL BlendEnable; - D3DBLEND SrcBlend; - D3DBLEND DestBlend; - D3DBLENDOP BlendOp; - D3DBLEND SrcBlendAlpha; - D3DBLEND DestBlendAlpha; - D3DBLENDOP BlendOpAlpha; - UINT8 RenderTargetWriteMask; -}; - -class GSDevice9 : public GSDevice -{ -public: - typedef GSTexture9 Texture; - -private: - // state cache - - IDirect3DVertexBuffer9* m_vb; - UINT m_vb_count; - const void* m_vb_vertices; - UINT m_vb_stride; - IDirect3DVertexDeclaration9* m_layout; - D3DPRIMITIVETYPE m_topology; - IDirect3DVertexShader9* m_vs; - float* m_vs_cb; - int m_vs_cb_len; - IDirect3DTexture9* m_ps_srvs[2]; - IDirect3DPixelShader9* m_ps; - float* m_ps_cb; - int m_ps_cb_len; - Direct3DSamplerState9* m_ps_ss; - CRect m_scissor; - Direct3DDepthStencilState9* m_dss; - UINT m_sref; - Direct3DBlendState9* m_bs; - DWORD m_bf; - IDirect3DSurface9* m_rtv; - IDirect3DSurface9* m_dsv; - - // - - bool Create(int type, Texture& t, int w, int h, int format); - void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c); - void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset = 0); - - // - - DDCAPS m_ddcaps; - D3DCAPS9 m_d3dcaps; - CComPtr m_d3d; - CComPtr m_dev; - CComPtr m_swapchain; - Texture m_backbuffer; - -public: // TODO - D3DPRESENT_PARAMETERS m_pp; - CComPtr m_font; - - struct - { - CComPtr vs; - CComPtr il; - CComPtr ps[5]; - Direct3DSamplerState9 ln; - Direct3DSamplerState9 pt; - Direct3DDepthStencilState9 dss; - Direct3DBlendState9 bs; - } m_convert; - - struct - { - CComPtr ps[2]; - Direct3DBlendState9 bs; - } m_merge; - - struct - { - CComPtr ps[4]; - } m_interlace; - -public: - GSDevice9(); - virtual ~GSDevice9(); - - bool Create(HWND hWnd, bool vsync); - bool Reset(int w, int h, bool fs); - bool IsLost(); - void Present(const CRect& r); - void BeginScene(); - void EndScene(); - void Draw(LPCTSTR str); - bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0); - - void ClearRenderTarget(Texture& t, const GSVector4& c); - void ClearRenderTarget(Texture& t, DWORD c); - void ClearDepth(Texture& t, float c); - void ClearStencil(Texture& t, BYTE c); - - bool CreateRenderTarget(Texture& t, int w, int h, int format = 0); - bool CreateDepthStencil(Texture& t, int w, int h, int format = 0); - bool CreateTexture(Texture& t, int w, int h, int format = 0); - bool CreateOffscreen(Texture& t, int w, int h, int format = 0); - - IDirect3DDevice9* operator->() {return m_dev;} - operator IDirect3DDevice9*() {return m_dev;} - - // TODO: void IASetVertexBuffer(IDirect3DVertexBuffer9* vb, UINT count, const void* vertices, UINT stride); - void IASetVertexBuffer(UINT count, const void* vertices, UINT stride); - void IASetInputLayout(IDirect3DVertexDeclaration9* layout); - void IASetPrimitiveTopology(D3DPRIMITIVETYPE topology); - void VSSetShader(IDirect3DVertexShader9* vs, const float* vs_cb, int vs_cb_len); - void PSSetShaderResources(IDirect3DTexture9* srv0, IDirect3DTexture9* srv1); - void PSSetShader(IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len); - void PSSetSamplerState(Direct3DSamplerState9* ss); - void RSSet(int width, int height, const RECT* scissor = NULL); - void OMSetDepthStencilState(Direct3DDepthStencilState9* dss, UINT sref); - void OMSetBlendState(Direct3DBlendState9* bs, DWORD bf); - void OMSetRenderTargets(IDirect3DSurface9* rtv, IDirect3DSurface9* dsv); - void DrawPrimitive(); - - template void IASetVertexBuffer(UINT count, T* vertices) - { - IASetVertexBuffer(count, vertices, sizeof(T)); - } - - void StretchRect(Texture& st, Texture& dt, const GSVector4& dr, bool linear = true); - void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, bool linear = true); - void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, bool linear = true); - void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, Direct3DBlendState9* bs, bool linear = true); - - HRESULT CompileShader(UINT id, LPCSTR entry, const D3DXMACRO* macro, IDirect3DVertexShader9** vs, const D3DVERTEXELEMENT9* layout, int count, IDirect3DVertexDeclaration9** il); - HRESULT CompileShader(UINT id, LPCSTR entry, const D3DXMACRO* macro, IDirect3DPixelShader9** ps); - - virtual bool IsCurrentRGBA() - { - return false; - } - - // TODO - bool SaveToFileD24S8(IDirect3DSurface9* ds, LPCTSTR fn); -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSDevice.h" +#include "GSTexture9.h" + +struct Direct3DSamplerState9 +{ + D3DTEXTUREFILTERTYPE FilterMin[2]; + D3DTEXTUREFILTERTYPE FilterMag[2]; + D3DTEXTUREADDRESS AddressU; + D3DTEXTUREADDRESS AddressV; +}; + +struct Direct3DDepthStencilState9 +{ + BOOL DepthEnable; + BOOL DepthWriteMask; + D3DCMPFUNC DepthFunc; + BOOL StencilEnable; + UINT8 StencilReadMask; + UINT8 StencilWriteMask; + D3DSTENCILOP StencilFailOp; + D3DSTENCILOP StencilDepthFailOp; + D3DSTENCILOP StencilPassOp; + D3DCMPFUNC StencilFunc; +}; + +struct Direct3DBlendState9 +{ + BOOL BlendEnable; + D3DBLEND SrcBlend; + D3DBLEND DestBlend; + D3DBLENDOP BlendOp; + D3DBLEND SrcBlendAlpha; + D3DBLEND DestBlendAlpha; + D3DBLENDOP BlendOpAlpha; + UINT8 RenderTargetWriteMask; +}; + +class GSDevice9 : public GSDevice +{ +public: + typedef GSTexture9 Texture; + +private: + // state cache + + IDirect3DVertexBuffer9* m_vb; + UINT m_vb_count; + const void* m_vb_vertices; + UINT m_vb_stride; + IDirect3DVertexDeclaration9* m_layout; + D3DPRIMITIVETYPE m_topology; + IDirect3DVertexShader9* m_vs; + float* m_vs_cb; + int m_vs_cb_len; + IDirect3DTexture9* m_ps_srvs[2]; + IDirect3DPixelShader9* m_ps; + float* m_ps_cb; + int m_ps_cb_len; + Direct3DSamplerState9* m_ps_ss; + CRect m_scissor; + Direct3DDepthStencilState9* m_dss; + UINT m_sref; + Direct3DBlendState9* m_bs; + DWORD m_bf; + IDirect3DSurface9* m_rtv; + IDirect3DSurface9* m_dsv; + + // + + bool Create(int type, Texture& t, int w, int h, int format); + void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c); + void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset = 0); + + // + + DDCAPS m_ddcaps; + D3DCAPS9 m_d3dcaps; + CComPtr m_d3d; + CComPtr m_dev; + CComPtr m_swapchain; + Texture m_backbuffer; + +public: // TODO + D3DPRESENT_PARAMETERS m_pp; + CComPtr m_font; + + struct + { + CComPtr vs; + CComPtr il; + CComPtr ps[5]; + Direct3DSamplerState9 ln; + Direct3DSamplerState9 pt; + Direct3DDepthStencilState9 dss; + Direct3DBlendState9 bs; + } m_convert; + + struct + { + CComPtr ps[2]; + Direct3DBlendState9 bs; + } m_merge; + + struct + { + CComPtr ps[4]; + } m_interlace; + +public: + GSDevice9(); + virtual ~GSDevice9(); + + bool Create(HWND hWnd, bool vsync); + bool Reset(int w, int h, bool fs); + bool IsLost(); + void Present(const CRect& r); + void BeginScene(); + void EndScene(); + void Draw(LPCTSTR str); + bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0); + + void ClearRenderTarget(Texture& t, const GSVector4& c); + void ClearRenderTarget(Texture& t, DWORD c); + void ClearDepth(Texture& t, float c); + void ClearStencil(Texture& t, BYTE c); + + bool CreateRenderTarget(Texture& t, int w, int h, int format = 0); + bool CreateDepthStencil(Texture& t, int w, int h, int format = 0); + bool CreateTexture(Texture& t, int w, int h, int format = 0); + bool CreateOffscreen(Texture& t, int w, int h, int format = 0); + + IDirect3DDevice9* operator->() {return m_dev;} + operator IDirect3DDevice9*() {return m_dev;} + + // TODO: void IASetVertexBuffer(IDirect3DVertexBuffer9* vb, UINT count, const void* vertices, UINT stride); + void IASetVertexBuffer(UINT count, const void* vertices, UINT stride); + void IASetInputLayout(IDirect3DVertexDeclaration9* layout); + void IASetPrimitiveTopology(D3DPRIMITIVETYPE topology); + void VSSetShader(IDirect3DVertexShader9* vs, const float* vs_cb, int vs_cb_len); + void PSSetShaderResources(IDirect3DTexture9* srv0, IDirect3DTexture9* srv1); + void PSSetShader(IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len); + void PSSetSamplerState(Direct3DSamplerState9* ss); + void RSSet(int width, int height, const RECT* scissor = NULL); + void OMSetDepthStencilState(Direct3DDepthStencilState9* dss, UINT sref); + void OMSetBlendState(Direct3DBlendState9* bs, DWORD bf); + void OMSetRenderTargets(IDirect3DSurface9* rtv, IDirect3DSurface9* dsv); + void DrawPrimitive(); + + template void IASetVertexBuffer(UINT count, T* vertices) + { + IASetVertexBuffer(count, vertices, sizeof(T)); + } + + void StretchRect(Texture& st, Texture& dt, const GSVector4& dr, bool linear = true); + void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, bool linear = true); + void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, bool linear = true); + void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, Direct3DBlendState9* bs, bool linear = true); + + HRESULT CompileShader(UINT id, LPCSTR entry, const D3DXMACRO* macro, IDirect3DVertexShader9** vs, const D3DVERTEXELEMENT9* layout, int count, IDirect3DVertexDeclaration9** il); + HRESULT CompileShader(UINT id, LPCSTR entry, const D3DXMACRO* macro, IDirect3DPixelShader9** ps); + + virtual bool IsCurrentRGBA() + { + return false; + } + + // TODO + bool SaveToFileD24S8(IDirect3DSurface9* ds, LPCTSTR fn); +}; diff --git a/plugins/GSdx/GSDeviceNull.cpp b/plugins/GSdx/GSDeviceNull.cpp index 695293f97e..4d8aa3b8b3 100644 --- a/plugins/GSdx/GSDeviceNull.cpp +++ b/plugins/GSdx/GSDeviceNull.cpp @@ -1,50 +1,50 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GSDeviceNull.h" - -bool GSDeviceNull::Create(HWND hWnd, bool vsync) -{ - if(!__super::Create(hWnd, vsync)) - { - return false; - } - - Reset(1, 1, true); - - return true; -} - -bool GSDeviceNull::Reset(int w, int h, bool fs) -{ - if(!__super::Reset(w, h, fs)) - return false; - - return true; -} - -bool GSDeviceNull::Create(int type, Texture& t, int w, int h, int format) -{ - t = Texture(type, w, h, format); - - return true; -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSDeviceNull.h" + +bool GSDeviceNull::Create(HWND hWnd, bool vsync) +{ + if(!__super::Create(hWnd, vsync)) + { + return false; + } + + Reset(1, 1, true); + + return true; +} + +bool GSDeviceNull::Reset(int w, int h, bool fs) +{ + if(!__super::Reset(w, h, fs)) + return false; + + return true; +} + +bool GSDeviceNull::Create(int type, Texture& t, int w, int h, int format) +{ + t = Texture(type, w, h, format); + + return true; +} diff --git a/plugins/GSdx/GSDeviceNull.h b/plugins/GSdx/GSDeviceNull.h index 01bb3261d6..e2782f1228 100644 --- a/plugins/GSdx/GSDeviceNull.h +++ b/plugins/GSdx/GSDeviceNull.h @@ -1,53 +1,53 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSDevice.h" -#include "GSTextureNull.h" - -class GSDeviceNull : public GSDevice -{ -public: - typedef GSTextureNull Texture; - -private: - bool Create(int type, Texture& t, int w, int h, int format); - void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c) {} - void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset = 0) {} - -public: - GSDeviceNull() {} - - bool Create(HWND hWnd, bool vsync); - bool Reset(int w, int h, bool fs); - bool IsLost() {return false;} - void Present(const CRect& r) {} - void BeginScene() {} - void EndScene() {} - void Draw(LPCTSTR str) {} - bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0) {return false;} - - void ClearRenderTarget(Texture& t, const GSVector4& c) {} - void ClearRenderTarget(Texture& t, DWORD c) {} - void ClearDepth(Texture& t, float c) {} - void ClearStencil(Texture& t, BYTE c) {} -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSDevice.h" +#include "GSTextureNull.h" + +class GSDeviceNull : public GSDevice +{ +public: + typedef GSTextureNull Texture; + +private: + bool Create(int type, Texture& t, int w, int h, int format); + void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c) {} + void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset = 0) {} + +public: + GSDeviceNull() {} + + bool Create(HWND hWnd, bool vsync); + bool Reset(int w, int h, bool fs); + bool IsLost() {return false;} + void Present(const CRect& r) {} + void BeginScene() {} + void EndScene() {} + void Draw(LPCTSTR str) {} + bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0) {return false;} + + void ClearRenderTarget(Texture& t, const GSVector4& c) {} + void ClearRenderTarget(Texture& t, DWORD c) {} + void ClearDepth(Texture& t, float c) {} + void ClearStencil(Texture& t, BYTE c) {} +}; diff --git a/plugins/GSdx/GSDirtyRect.cpp b/plugins/GSdx/GSDirtyRect.cpp index 672bad9edb..1d8b7ff123 100644 --- a/plugins/GSdx/GSDirtyRect.cpp +++ b/plugins/GSdx/GSDirtyRect.cpp @@ -1,70 +1,70 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSDirtyRect.h" - -GSDirtyRect::GSDirtyRect() - : m_psm(PSM_PSMCT32) - , m_rect(0, 0, 0, 0) -{ -} - -GSDirtyRect::GSDirtyRect(DWORD psm, CRect rect) -{ - m_psm = psm; - m_rect = rect; -} - -CRect GSDirtyRect::GetDirtyRect(const GIFRegTEX0& TEX0) -{ - CRect r = m_rect; - - CSize src = GSLocalMemory::m_psm[m_psm].bs; - - r.left = (r.left) & ~(src.cx-1); - r.right = (r.right + (src.cx-1) /* + 1 */) & ~(src.cx-1); - r.top = (r.top) & ~(src.cy-1); - r.bottom = (r.bottom + (src.cy-1) /* + 1 */) & ~(src.cy-1); - - if(m_psm != TEX0.PSM) - { - CSize dst = GSLocalMemory::m_psm[TEX0.PSM].bs; - - r.left = MulDiv(m_rect.left, dst.cx, src.cx); - r.right = MulDiv(m_rect.right, dst.cx, src.cx); - r.top = MulDiv(m_rect.top, dst.cy, src.cy); - r.bottom = MulDiv(m_rect.bottom, dst.cy, src.cy); - } - - return r; -} - -// - -CRect GSDirtyRectList::GetDirtyRect(const GIFRegTEX0& TEX0, CSize size) -{ - if(IsEmpty()) return CRect(0, 0, 0, 0); - CRect r(INT_MAX, INT_MAX, 0, 0); - POSITION pos = GetHeadPosition(); - while(pos) r |= GetNext(pos).GetDirtyRect(TEX0); - return r & CRect(0, 0, size.cx, size.cy); -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSDirtyRect.h" + +GSDirtyRect::GSDirtyRect() + : m_psm(PSM_PSMCT32) + , m_rect(0, 0, 0, 0) +{ +} + +GSDirtyRect::GSDirtyRect(DWORD psm, CRect rect) +{ + m_psm = psm; + m_rect = rect; +} + +CRect GSDirtyRect::GetDirtyRect(const GIFRegTEX0& TEX0) +{ + CRect r = m_rect; + + CSize src = GSLocalMemory::m_psm[m_psm].bs; + + r.left = (r.left) & ~(src.cx-1); + r.right = (r.right + (src.cx-1) /* + 1 */) & ~(src.cx-1); + r.top = (r.top) & ~(src.cy-1); + r.bottom = (r.bottom + (src.cy-1) /* + 1 */) & ~(src.cy-1); + + if(m_psm != TEX0.PSM) + { + CSize dst = GSLocalMemory::m_psm[TEX0.PSM].bs; + + r.left = MulDiv(m_rect.left, dst.cx, src.cx); + r.right = MulDiv(m_rect.right, dst.cx, src.cx); + r.top = MulDiv(m_rect.top, dst.cy, src.cy); + r.bottom = MulDiv(m_rect.bottom, dst.cy, src.cy); + } + + return r; +} + +// + +CRect GSDirtyRectList::GetDirtyRect(const GIFRegTEX0& TEX0, CSize size) +{ + if(IsEmpty()) return CRect(0, 0, 0, 0); + CRect r(INT_MAX, INT_MAX, 0, 0); + POSITION pos = GetHeadPosition(); + while(pos) r |= GetNext(pos).GetDirtyRect(TEX0); + return r & CRect(0, 0, size.cx, size.cy); +} diff --git a/plugins/GSdx/GSDirtyRect.h b/plugins/GSdx/GSDirtyRect.h index 0babdb494a..8e6f5734df 100644 --- a/plugins/GSdx/GSDirtyRect.h +++ b/plugins/GSdx/GSDirtyRect.h @@ -1,42 +1,42 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSLocalMemory.h" - -class GSDirtyRect -{ - DWORD m_psm; - CRect m_rect; - -public: - GSDirtyRect(); - GSDirtyRect(DWORD psm, CRect rect); - CRect GetDirtyRect(const GIFRegTEX0& TEX0); -}; - -class GSDirtyRectList : public CAtlList -{ -public: - GSDirtyRectList() {} - CRect GetDirtyRect(const GIFRegTEX0& TEX0, CSize size); +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSLocalMemory.h" + +class GSDirtyRect +{ + DWORD m_psm; + CRect m_rect; + +public: + GSDirtyRect(); + GSDirtyRect(DWORD psm, CRect rect); + CRect GetDirtyRect(const GIFRegTEX0& TEX0); +}; + +class GSDirtyRectList : public CAtlList +{ +public: + GSDirtyRectList() {} + CRect GetDirtyRect(const GIFRegTEX0& TEX0, CSize size); }; \ No newline at end of file diff --git a/plugins/GSdx/GSDrawScanline.cpp b/plugins/GSdx/GSDrawScanline.cpp index b62052deb5..2f6d19063c 100644 --- a/plugins/GSdx/GSDrawScanline.cpp +++ b/plugins/GSdx/GSDrawScanline.cpp @@ -1,2845 +1,2845 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSDrawScanline.h" -#include "GSTextureCacheSW.h" - -GSDrawScanline::GSDrawScanline(GSState* state, int id) - : m_state(state) - , m_id(id) -{ - memset(&m_env, 0, sizeof(m_env)); -} - -GSDrawScanline::~GSDrawScanline() -{ -} - -void GSDrawScanline::BeginDraw(const GSRasterizerData* data, Functions* f) -{ - GSDrawingEnvironment& env = m_state->m_env; - GSDrawingContext* context = m_state->m_context; - - const GSScanlineParam* p = (const GSScanlineParam*)data->param; - - m_env.sel = p->sel; - - m_env.vm = p->vm; - m_env.fbr = p->fbo->row; - m_env.zbr = p->zbo->row; - m_env.fbc = p->fbo->col; - m_env.zbc = p->zbo->col; - m_env.fzbr = p->fzbo->row; - m_env.fzbc = p->fzbo->col; - m_env.fm = GSVector4i(p->fm); - m_env.zm = GSVector4i(p->zm); - m_env.datm = context->TEST.DATM ? GSVector4i::x80000000() : GSVector4i::zero(); - m_env.colclamp = env.COLCLAMP.CLAMP ? GSVector4i::xffffffff() : GSVector4i::x00ff(); - m_env.fba = context->FBA.FBA ? GSVector4i::x80000000() : GSVector4i::zero(); - m_env.aref = GSVector4i((int)context->TEST.AREF); - m_env.afix = GSVector4i((int)context->ALPHA.FIX << 16); - m_env.afix2 = m_env.afix.yywwlh().sll16(7); - m_env.frb = GSVector4i((int)env.FOGCOL.ai32[0] & 0x00ff00ff); - m_env.fga = GSVector4i((int)(env.FOGCOL.ai32[0] >> 8) & 0x00ff00ff); - - if(m_env.sel.fpsm == 1) - { - m_env.fm |= GSVector4i::xff000000(); - } - else if(m_env.sel.fpsm == 2) - { - GSVector4i rb = m_env.fm & 0x00f800f8; - GSVector4i ga = m_env.fm & 0x8000f800; - - m_env.fm = (ga >> 16) | (rb >> 9) | (ga >> 6) | (rb >> 3) | GSVector4i::xffff0000(); - } - - if(m_env.sel.zpsm == 1) - { - m_env.zm |= GSVector4i::xff000000(); - } - else if(m_env.sel.zpsm == 2) - { - m_env.zm |= GSVector4i::xffff0000(); - } - - if(m_env.sel.atst == ATST_LESS) - { - m_env.sel.atst = ATST_LEQUAL; - - m_env.aref -= GSVector4i::x00000001(); - } - else if(m_env.sel.atst == ATST_GREATER) - { - m_env.sel.atst = ATST_GEQUAL; - - m_env.aref += GSVector4i::x00000001(); - } - - if(m_env.sel.tfx != TFX_NONE) - { - m_env.tex = p->tex; - m_env.clut = p->clut; - m_env.tw = p->tw; - - unsigned short tw = (unsigned short)(1 << context->TEX0.TW); - unsigned short th = (unsigned short)(1 << context->TEX0.TH); - - switch(context->CLAMP.WMS) - { - case CLAMP_REPEAT: - m_env.t.min.u16[0] = tw - 1; - m_env.t.max.u16[0] = 0; - m_env.t.mask.u32[0] = 0xffffffff; - break; - case CLAMP_CLAMP: - m_env.t.min.u16[0] = 0; - m_env.t.max.u16[0] = tw - 1; - m_env.t.mask.u32[0] = 0; - break; - case CLAMP_REGION_CLAMP: - m_env.t.min.u16[0] = min(context->CLAMP.MINU, tw - 1); - m_env.t.max.u16[0] = min(context->CLAMP.MAXU, tw - 1); - m_env.t.mask.u32[0] = 0; - break; - case CLAMP_REGION_REPEAT: - m_env.t.min.u16[0] = context->CLAMP.MINU; - m_env.t.max.u16[0] = context->CLAMP.MAXU; - m_env.t.mask.u32[0] = 0xffffffff; - break; - default: - __assume(0); - } - - switch(context->CLAMP.WMT) - { - case CLAMP_REPEAT: - m_env.t.min.u16[4] = th - 1; - m_env.t.max.u16[4] = 0; - m_env.t.mask.u32[2] = 0xffffffff; - break; - case CLAMP_CLAMP: - m_env.t.min.u16[4] = 0; - m_env.t.max.u16[4] = th - 1; - m_env.t.mask.u32[2] = 0; - break; - case CLAMP_REGION_CLAMP: - m_env.t.min.u16[4] = min(context->CLAMP.MINV, th - 1); - m_env.t.max.u16[4] = min(context->CLAMP.MAXV, th - 1); // ffx anima summon scene, when the anchor appears (th = 256, maxv > 256) - m_env.t.mask.u32[2] = 0; - break; - case CLAMP_REGION_REPEAT: - m_env.t.min.u16[4] = context->CLAMP.MINV; - m_env.t.max.u16[4] = context->CLAMP.MAXV; - m_env.t.mask.u32[2] = 0xffffffff; - break; - default: - __assume(0); - } - - m_env.t.min = m_env.t.min.xxxxlh(); - m_env.t.max = m_env.t.max.xxxxlh(); - m_env.t.mask = m_env.t.mask.xxzz(); - } - - // - - f->sl = m_ds.Lookup(m_env.sel); - - // - - if(m_env.sel.IsSolidRect()) - { - f->sr = (DrawSolidRectPtr)&GSDrawScanline::DrawSolidRect; - } - - // - - DWORD sel = 0; - - if(data->primclass != GS_POINT_CLASS) - { - sel |= (m_env.sel.ztst ? 1 : 0) << 0; - sel |= m_env.sel.fge << 1; - sel |= (m_env.sel.tfx != TFX_NONE ? 1 : 0) << 2; - sel |= m_env.sel.fst << 3; - sel |= m_env.sel.iip << 4; - } - - f->sp = m_sp.Lookup(sel); -} - -void GSDrawScanline::EndDraw(const GSRasterizerStats& stats) -{ - m_ds.UpdateStats(stats, m_state->m_perfmon.GetFrame()); -} - -template -void GSDrawScanline::SetupPrim(const GSVertexSW* vertices, const GSVertexSW& dscan) -{ - // p - - GSVector4 p = dscan.p; - - GSVector4 dz = p.zzzz(); - GSVector4 df = p.wwww(); - - if(zbe) - { - m_env.d4.z = dz * 4.0f; - } - - if(fge) - { - m_env.d4.f = GSVector4i(df * 4.0f).xxzzlh(); - } - - for(int i = 0; i < 4; i++) - { - GSVector4 v = m_shift[i]; - - if(zbe) - { - m_env.d[i].z = dz * v; - } - - if(fge) - { - m_env.d[i].f = GSVector4i(df * v).xxzzlh(); - } - } - - if(iip == 0) // should be sprite == 1, but close enough - { - GSVector4 p = vertices[0].p; - - if(zbe) - { - GSVector4 z = p.zzzz(); - - m_env.p.z = (GSVector4i(z * 0.5f) << 1) | (GSVector4i(z) & GSVector4i::x00000001()); - } - - if(fge) - { - m_env.p.f = GSVector4i(p).zzzzh().zzzz(); - } - } - - // t - - if(tme) - { - GSVector4 t = dscan.t; - - if(fst) - { - m_env.d4.st = GSVector4i(t * 4.0f); - - GSVector4 ds = t.xxxx(); - GSVector4 dt = t.yyyy(); - - for(int i = 0; i < 4; i++) - { - GSVector4 v = m_shift[i]; - - m_env.d[i].si = GSVector4i(ds * v); - m_env.d[i].ti = GSVector4i(dt * v); - } - } - else - { - m_env.d4.stq = t * 4.0f; - - GSVector4 ds = t.xxxx(); - GSVector4 dt = t.yyyy(); - GSVector4 dq = t.zzzz(); - - for(int i = 0; i < 4; i++) - { - GSVector4 v = m_shift[i]; - - m_env.d[i].s = ds * v; - m_env.d[i].t = dt * v; - m_env.d[i].q = dq * v; - } - } - } - - // c - - if(iip) - { - GSVector4 c = dscan.c; - - m_env.d4.c = GSVector4i(c * 4.0f).xzyw().ps32(); - - GSVector4 dr = c.xxxx(); - GSVector4 dg = c.yyyy(); - GSVector4 db = c.zzzz(); - GSVector4 da = c.wwww(); - - for(int i = 0; i < 4; i++) - { - GSVector4 v = m_shift[i]; - - GSVector4i rg = GSVector4i(dr * v).ps32(GSVector4i(dg * v)); - GSVector4i ba = GSVector4i(db * v).ps32(GSVector4i(da * v)); - - m_env.d[i].rb = rg.upl16(ba); - m_env.d[i].ga = rg.uph16(ba); - } - } - else - { - GSVector4i rgba = GSVector4i(vertices[0].c); - - GSVector4i rbga = rgba.upl16(rgba.zwxy()); - - if(tme == 0) - { - rbga = rbga.srl16(7); - - DWORD abe = m_env.sel.abe & 0x3f; // a, b, c - - DWORD abea = m_env.sel.abea; - DWORD abeb = m_env.sel.abeb; - DWORD abec = m_env.sel.abec; - DWORD abed = m_env.sel.abed; - - if(fge == 0 && abe != 0x3f && !(abe & 0x15) && abea != abeb) // 0x15 = 010101b => a, b, c != 1 - { - GSVector4i c[4]; - - c[0] = rbga; - c[1] = rgba.zzzzh().zzzz(); - c[2] = GSVector4i::zero(); - c[3] = m_env.afix2; - - GSVector4i cc = GSVector4i::lerp16<1>(c[abea], c[abeb], c[abec + 1]); - - if(abed == 0) - { - cc = cc.add16(c[0]); - } - - m_env.c2.rb = cc.xxxx(); - m_env.c2.ga = cc.zzzz().mix16(c[1].srl16(7)); - } - } - - m_env.c.rb = rbga.xxxx(); - m_env.c.ga = rbga.zzzz(); - } -} - -GSVector4i GSDrawScanline::Wrap(const GSVector4i& t) -{ - GSVector4i clamp = t.sat_i16(m_env.t.min, m_env.t.max); - GSVector4i repeat = (t & m_env.t.min) | m_env.t.max; - - return clamp.blend8(repeat, m_env.t.mask); -} - -void GSDrawScanline::SampleTexture(DWORD ltf, DWORD tlu, const GSVector4i& u, const GSVector4i& v, GSVector4i* c) -{ - const void* RESTRICT tex = m_env.tex; - const DWORD* RESTRICT clut = m_env.clut; - const DWORD tw = m_env.tw; - - GSVector4i uv = u.sra32(16).ps32(v.sra32(16)); - - GSVector4i c00, c01, c10, c11; - - if(ltf) - { - GSVector4i uf = u.xxzzlh().srl16(1); - GSVector4i vf = v.xxzzlh().srl16(1); - - GSVector4i uv0 = Wrap(uv); - GSVector4i uv1 = Wrap(uv.add16(GSVector4i::x0001())); - - GSVector4i y0 = uv0.uph16() << tw; - GSVector4i y1 = uv1.uph16() << tw; - GSVector4i x0 = uv0.upl16(); - GSVector4i x1 = uv1.upl16(); - - GSVector4i addr00 = y0 + x0; - GSVector4i addr01 = y0 + x1; - GSVector4i addr10 = y1 + x0; - GSVector4i addr11 = y1 + x1; - - if(tlu) - { - c00 = addr00.gather32_32((const BYTE*)tex, clut); - c01 = addr01.gather32_32((const BYTE*)tex, clut); - c10 = addr10.gather32_32((const BYTE*)tex, clut); - c11 = addr11.gather32_32((const BYTE*)tex, clut); - } - else - { - c00 = addr00.gather32_32((const DWORD*)tex); - c01 = addr01.gather32_32((const DWORD*)tex); - c10 = addr10.gather32_32((const DWORD*)tex); - c11 = addr11.gather32_32((const DWORD*)tex); - } - - GSVector4i mask = GSVector4i::x00ff(); - - GSVector4i rb00 = c00 & mask; - GSVector4i rb01 = c01 & mask; - GSVector4i rb10 = c10 & mask; - GSVector4i rb11 = c11 & mask; - - rb00 = rb00.lerp16<0>(rb01, uf); - rb10 = rb10.lerp16<0>(rb11, uf); - rb00 = rb00.lerp16<0>(rb10, vf); - - c[0] = rb00; - - GSVector4i ga00 = (c00 >> 8) & mask; - GSVector4i ga01 = (c01 >> 8) & mask; - GSVector4i ga10 = (c10 >> 8) & mask; - GSVector4i ga11 = (c11 >> 8) & mask; - - ga00 = ga00.lerp16<0>(ga01, uf); - ga10 = ga10.lerp16<0>(ga11, uf); - ga00 = ga00.lerp16<0>(ga10, vf); - - c[1] = ga00; - } - else - { - GSVector4i uv0 = Wrap(uv); - - GSVector4i addr00 = (uv0.uph16() << tw) + uv0.upl16(); - - if(tlu) - { - c00 = addr00.gather32_32((const BYTE*)tex, clut); - } - else - { - c00 = addr00.gather32_32((const DWORD*)tex); - } - - GSVector4i mask = GSVector4i::x00ff(); - - c[0] = c00 & mask; - c[1] = (c00 >> 8) & mask; - } -} - -void GSDrawScanline::ColorTFX(DWORD iip, DWORD tfx, const GSVector4i& rbf, const GSVector4i& gaf, GSVector4i& rbt, GSVector4i& gat) -{ - GSVector4i rb = iip ? rbf : m_env.c.rb; - GSVector4i ga = iip ? gaf : m_env.c.ga; - - GSVector4i af; - - switch(tfx) - { - case TFX_MODULATE: - rbt = rbt.modulate16<1>(rb).clamp8(); - break; - case TFX_DECAL: - break; - case TFX_HIGHLIGHT: - case TFX_HIGHLIGHT2: - af = ga.yywwlh().srl16(7); - rbt = rbt.modulate16<1>(rb).add16(af).clamp8(); - gat = gat.modulate16<1>(ga).add16(af).clamp8().mix16(gat); - break; - case TFX_NONE: - rbt = iip ? rb.srl16(7) : rb; - break; - default: - __assume(0); - } -} - -void GSDrawScanline::AlphaTFX(DWORD iip, DWORD tfx, DWORD tcc, const GSVector4i& gaf, GSVector4i& gat) -{ - GSVector4i ga = iip ? gaf : m_env.c.ga; - - switch(tfx) - { - case TFX_MODULATE: - gat = gat.modulate16<1>(ga).clamp8(); // mul16hrs rounds and breaks fogging in resident evil 4 (only modulate16<0> uses mul16hrs, but watch out) - if(!tcc) gat = gat.mix16(ga.srl16(7)); - break; - case TFX_DECAL: - break; - case TFX_HIGHLIGHT: - gat = gat.mix16(!tcc ? ga.srl16(7) : gat.addus8(ga.srl16(7))); - break; - case TFX_HIGHLIGHT2: - if(!tcc) gat = gat.mix16(ga.srl16(7)); - break; - case TFX_NONE: - gat = iip ? ga.srl16(7) : ga; - break; - default: - __assume(0); - } -} - -void GSDrawScanline::Fog(DWORD fge, const GSVector4i& f, GSVector4i& rb, GSVector4i& ga) -{ - if(fge) - { - rb = m_env.frb.lerp16<0>(rb, f); - ga = m_env.fga.lerp16<0>(ga, f).mix16(ga); - } -} - -bool GSDrawScanline::TestZ(DWORD zpsm, DWORD ztst, const GSVector4i& zs, const GSVector4i& zd, GSVector4i& test) -{ - if(ztst > 1) - { - GSVector4i o = GSVector4i::x80000000(zs); - - GSVector4i zso = zs - o; - GSVector4i zdo; - - switch(zpsm) - { - case 0: zdo = zd - o; break; - case 1: zdo = (zd & GSVector4i::x00ffffff(zs)) - o; break; - case 2: zdo = (zd & GSVector4i::x0000ffff(zs)) - o; break; - } - - switch(ztst) - { - case ZTST_GEQUAL: test |= zso < zdo; break; - case ZTST_GREATER: test |= zso <= zdo; break; - default: __assume(0); - } - - if(test.alltrue()) - { - return false; - } - } - - return true; -} - -bool GSDrawScanline::TestAlpha(DWORD atst, DWORD afail, const GSVector4i& ga, GSVector4i& fm, GSVector4i& zm, GSVector4i& test) -{ - if(atst != ATST_ALWAYS) - { - GSVector4i t; - - switch(atst) - { - case ATST_NEVER: t = GSVector4i::xffffffff(); break; - case ATST_ALWAYS: t = GSVector4i::zero(); break; - case ATST_LESS: - case ATST_LEQUAL: t = (ga >> 16) > m_env.aref; break; - case ATST_EQUAL: t = (ga >> 16) != m_env.aref; break; - case ATST_GEQUAL: - case ATST_GREATER: t = (ga >> 16) < m_env.aref; break; - case ATST_NOTEQUAL: t = (ga >> 16) == m_env.aref; break; - default: __assume(0); - } - - switch(afail) - { - case AFAIL_KEEP: - test |= t; - if(test.alltrue()) return false; - break; - case AFAIL_FB_ONLY: - zm |= t; - break; - case AFAIL_ZB_ONLY: - fm |= t; - break; - case AFAIL_RGB_ONLY: - fm |= t & GSVector4i::xff000000(); - zm |= t; - break; - default: - __assume(0); - } - } - - return true; -} - -bool GSDrawScanline::TestDestAlpha(DWORD fpsm, DWORD date, const GSVector4i& fd, GSVector4i& test) -{ - if(date) - { - switch(fpsm) - { - case 0: - test |= (fd ^ m_env.datm).sra32(31); - if(test.alltrue()) return false; - case 1: - break; - case 2: - test |= ((fd << 16) ^ m_env.datm).sra32(31); - if(test.alltrue()) return false; - case 3: - break; - default: - __assume(0); - } - } - - return true; -} - -void GSDrawScanline::ReadPixel(int psm, int addr, GSVector4i& c) const -{ - WORD* vm16 = (WORD*)m_env.vm; - - if(psm != 3) - { - c = GSVector4i::load(&vm16[addr], &vm16[addr + 8]); - } -} - -void GSDrawScanline::WritePixel(int psm, WORD* RESTRICT vm16, DWORD c) -{ - DWORD* RESTRICT vm32 = (DWORD*)vm16; - - switch(psm) - { - case 0: *vm32 = c; break; - case 1: *vm32 = (*vm32 & 0xff000000) | (c & 0x00ffffff); break; - case 2: *vm16 = (WORD)c; break; - } -} - -void GSDrawScanline::WriteFrame(int fpsm, int rfb, GSVector4i* c, const GSVector4i& fd, const GSVector4i& fm, int addr, int fzm) -{ - WORD* RESTRICT vm16 = (WORD*)m_env.vm; - - c[0] &= m_env.colclamp; - c[1] &= m_env.colclamp; - - GSVector4i fs = c[0].upl16(c[1]).pu16(c[0].uph16(c[1])); - - if(fpsm != 1) - { - fs |= m_env.fba; - } - - if(fpsm == 2) - { - GSVector4i rb = fs & 0x00f800f8; - GSVector4i ga = fs & 0x8000f800; - - fs = (ga >> 16) | (rb >> 9) | (ga >> 6) | (rb >> 3); - } - - if(rfb) - { - fs = fs.blend(fd, fm); - - if(fpsm < 2) - { - if(fzm & 0x03) GSVector4i::storel(&vm16[addr + 0], fs); - if(fzm & 0x0c) GSVector4i::storeh(&vm16[addr + 8], fs); - - return; - } - } - - if(fzm & 0x01) WritePixel(fpsm, &vm16[addr + 0], fs.extract32<0>()); - if(fzm & 0x02) WritePixel(fpsm, &vm16[addr + 2], fs.extract32<1>()); - if(fzm & 0x04) WritePixel(fpsm, &vm16[addr + 8], fs.extract32<2>()); - if(fzm & 0x08) WritePixel(fpsm, &vm16[addr + 10], fs.extract32<3>()); -} - -void GSDrawScanline::WriteZBuf(int zpsm, int ztst, const GSVector4i& z, const GSVector4i& zd, const GSVector4i& zm, int addr, int fzm) -{ - if(ztst == 0) return; - - WORD* RESTRICT vm16 = (WORD*)m_env.vm; - - GSVector4i zs = z; - - if(ztst > 1) - { - if(zpsm < 2) - { - zs = zs.blend8(zd, zm); - - if(fzm & 0x30) GSVector4i::storel(&vm16[addr + 0], zs); - if(fzm & 0xc0) GSVector4i::storeh(&vm16[addr + 8], zs); - - return; - } - } - - if(fzm & 0x10) WritePixel(zpsm, &vm16[addr + 0], zs.extract32<0>()); - if(fzm & 0x20) WritePixel(zpsm, &vm16[addr + 2], zs.extract32<1>()); - if(fzm & 0x40) WritePixel(zpsm, &vm16[addr + 8], zs.extract32<2>()); - if(fzm & 0x80) WritePixel(zpsm, &vm16[addr + 10], zs.extract32<3>()); -} - -template -void GSDrawScanline::DrawScanline(int top, int left, int right, const GSVertexSW& v) -{ - int skip = left & 3; - - left -= skip; - - int steps = right - left - 4; - - GSVector4i test = m_test[skip] | m_test[7 + (steps & (steps >> 31))]; - - // - - GSVector2i fza_base; - GSVector2i* fza_offset; - - GSVector4 z, s, t, q; - GSVector4i si, ti, f, rb, ga; - - // fza - - fza_base = m_env.fzbr[top]; - fza_offset = &m_env.fzbc[left >> 2]; - - // v.p - - GSVector4 vp = v.p; - - z = vp.zzzz() + m_env.d[skip].z; - f = GSVector4i(vp).zzzzh().zzzz().add16(m_env.d[skip].f); - - // v.t - - GSVector4 vt = v.t; - - if(m_env.sel.fst) - { - GSVector4i vti(vt); - - si = vti.xxxx() + m_env.d[skip].si; - ti = vti.yyyy() + m_env.d[skip].ti; - } - else - { - s = vt.xxxx() + m_env.d[skip].s; - t = vt.yyyy() + m_env.d[skip].t; - q = vt.zzzz() + m_env.d[skip].q; - } - - // v.c - - if(iip) - { - GSVector4i vc = GSVector4i(v.c); - - vc = vc.upl16(vc.zwxy()); - - rb = vc.xxxx().add16(m_env.d[skip].rb); - ga = vc.zzzz().add16(m_env.d[skip].ga); - } - - // - - while(1) - { - do - { - int fa = fza_base.x + fza_offset->x; - int za = fza_base.y + fza_offset->y; - - GSVector4i zs = (GSVector4i(z * 0.5f) << 1) | (GSVector4i(z) & GSVector4i::x00000001()); - GSVector4i zd; - - if(ztst > 1) - { - ReadPixel(zpsm, za, zd); - - if(!TestZ(zpsm, ztst, zs, zd, test)) - { - continue; - } - } - - GSVector4i c[6]; - - if(m_env.sel.tfx != TFX_NONE) - { - GSVector4i u, v; - - if(m_env.sel.fst) - { - u = si; - v = ti; - } - else - { - GSVector4 w = q.rcp(); - - u = GSVector4i(s * w); - v = GSVector4i(t * w); - - if(m_env.sel.ltf) - { - u -= 0x8000; - v -= 0x8000; - } - } - - SampleTexture(m_env.sel.ltf, m_env.sel.tlu, u, v, c); - } - - AlphaTFX(iip, m_env.sel.tfx, m_env.sel.tcc, ga, c[1]); - - GSVector4i fm = m_env.fm; - GSVector4i zm = m_env.zm; - - if(!TestAlpha(m_env.sel.atst, m_env.sel.afail, c[1], fm, zm, test)) - { - continue; - } - - ColorTFX(iip, m_env.sel.tfx, rb, ga, c[0], c[1]); - - Fog(m_env.sel.fge, f, c[0], c[1]); - - GSVector4i fd; - - if(m_env.sel.rfb) - { - ReadPixel(fpsm, fa, fd); - - if(!TestDestAlpha(fpsm, m_env.sel.date, fd, test)) - { - continue; - } - } - - fm |= test; - zm |= test; - - int fzm = ~(fm == GSVector4i::xffffffff()).ps32(zm == GSVector4i::xffffffff()).ps32().mask(); - - WriteZBuf(zpsm, ztst, zs, zd, zm, za, fzm); - - if(m_env.sel.abe != 255) - { - GSVector4i mask = GSVector4i::x00ff(fd); - - switch(fpsm) - { - case 0: - c[2] = fd & mask; - c[3] = (fd >> 8) & mask; - break; - case 1: - c[2] = fd & mask; - c[3] = (fd >> 8) & mask; - c[3] = c[3].mix16(GSVector4i(0x00800000)); - break; - case 2: - c[2] = ((fd & 0x7c00) << 9) | ((fd & 0x001f) << 3); - c[3] = ((fd & 0x8000) << 8) | ((fd & 0x03e0) >> 2); - break; - } - - c[4] = GSVector4::zero(); - c[5] = m_env.afix; - - DWORD abea = m_env.sel.abea; - DWORD abeb = m_env.sel.abeb; - DWORD abec = m_env.sel.abec; - DWORD abed = m_env.sel.abed; - - GSVector4i a = c[abec * 2 + 1].yywwlh().sll16(7); - - GSVector4i rb = GSVector4i::lerp16<1>(c[abea * 2 + 0], c[abeb * 2 + 0], a, c[abed * 2 + 0]); - GSVector4i ga = GSVector4i::lerp16<1>(c[abea * 2 + 1], c[abeb * 2 + 1], a, c[abed * 2 + 1]); - - if(m_env.sel.pabe) - { - mask = (c[1] << 8).sra32(31); - - rb = c[0].blend8(rb, mask); - ga = c[1].blend8(ga, mask); - } - - c[0] = rb; - c[1] = ga.mix16(c[1]); - } - - WriteFrame(fpsm, m_env.sel.rfb, c, fd, fm, fa, fzm); - } - while(0); - - if(steps <= 0) break; - - steps -= 4; - - test = m_test[7 + (steps & (steps >> 31))]; - - fza_offset++; - - z += m_env.d4.z; - f = f.add16(m_env.d4.f); - - if(m_env.sel.fst) - { - GSVector4i st = m_env.d4.st; - - si += st.xxxx(); - ti += st.yyyy(); - } - else - { - GSVector4 stq = m_env.d4.stq; - - s += stq.xxxx(); - t += stq.yyyy(); - q += stq.zzzz(); - } - - if(iip) - { - GSVector4i c = m_env.d4.c; - - rb = rb.add16(c.xxxx()); - ga = ga.add16(c.yyyy()); - } - } -} - -template -void GSDrawScanline::DrawScanlineEx(int top, int left, int right, const GSVertexSW& v) -{ - const DWORD fpsm = (sel >> 0) & 3; - const DWORD zpsm = (sel >> 2) & 3; - const DWORD ztst = (sel >> 4) & 3; - const DWORD atst = (sel >> 6) & 7; - const DWORD afail = (sel >> 9) & 3; - const DWORD iip = (sel >> 11) & 1; - const DWORD tfx = (sel >> 12) & 7; - const DWORD tcc = (sel >> 15) & 1; - const DWORD fst = (sel >> 16) & 1; - const DWORD ltf = (sel >> 17) & 1; - const DWORD tlu = (sel >> 18) & 1; - const DWORD fge = (sel >> 19) & 1; - const DWORD date = (sel >> 20) & 1; - const DWORD abe = (sel >> 21) & 255; - const DWORD abea = (sel >> 21) & 3; - const DWORD abeb = (sel >> 23) & 3; - const DWORD abec = (sel >> 25) & 3; - const DWORD abed = (sel >> 27) & 3; - const DWORD pabe = (sel >> 29) & 1; - const DWORD rfb = (sel >> 30) & 1; - const DWORD sprite = (sel >> 31) & 1; - - // - - int skip = left & 3; - - left -= skip; - - int steps = right - left - 4; - - GSVector4i test = m_test[skip] | m_test[7 + (steps & (steps >> 31))]; - - // - - GSVector2i fza_base; - GSVector2i* fza_offset; - - GSVector4 z, s, t, q; - GSVector4i zi, si, ti, f, rb, ga; - - // fza - - fza_base = m_env.fzbr[top]; - fza_offset = &m_env.fzbc[left >> 2]; - - // v.p - - GSVector4 vp = v.p; - - if(sprite) - { - zi = m_env.p.z; - f = m_env.p.f; - } - else - { - z = vp.zzzz() + m_env.d[skip].z; - f = GSVector4i(vp).zzzzh().zzzz().add16(m_env.d[skip].f); - } - - // v.t - - GSVector4 vt = v.t; - - if(fst) - { - GSVector4i vti(vt); - - si = vti.xxxx(); - ti = vti.yyyy(); - - si += m_env.d[skip].si; - if(!sprite) ti += m_env.d[skip].ti; - } - else - { - s = vt.xxxx() + m_env.d[skip].s; - t = vt.yyyy() + m_env.d[skip].t; - q = vt.zzzz() + m_env.d[skip].q; - } - - // v.c - - if(iip) - { - GSVector4i vc = GSVector4i(v.c); - - vc = vc.upl16(vc.zwxy()); - - rb = vc.xxxx().add16(m_env.d[skip].rb); - ga = vc.zzzz().add16(m_env.d[skip].ga); - } - - // - - while(1) - { - do - { - int fa = fza_base.x + fza_offset->x; - int za = fza_base.y + fza_offset->y; - - GSVector4i zs = sprite ? zi : (GSVector4i(z * 0.5f) << 1) | (GSVector4i(z) & GSVector4i::x00000001()); - GSVector4i zd; - - if(ztst > 1) - { - ReadPixel(zpsm, za, zd); - - if(!TestZ(zpsm, ztst, zs, zd, test)) - { - continue; - } - } - - GSVector4i c[6]; - - if(tfx != TFX_NONE) - { - GSVector4i u, v; - - if(fst) - { - u = si; - v = ti; - } - else - { - GSVector4 w = q.rcp(); - - u = GSVector4i(s * w); - v = GSVector4i(t * w); - - if(ltf) - { - u -= 0x8000; - v -= 0x8000; - } - } - - SampleTexture(ltf, tlu, u, v, c); - } - - AlphaTFX(iip, tfx, tcc, ga, c[1]); - - GSVector4i fm = m_env.fm; - GSVector4i zm = m_env.zm; - - if(!TestAlpha(atst, afail, c[1], fm, zm, test)) - { - continue; - } - - ColorTFX(iip, tfx, rb, ga, c[0], c[1]); - - Fog(fge, f, c[0], c[1]); - - GSVector4i fd; - - if(rfb) - { - ReadPixel(fpsm, fa, fd); - - if(!TestDestAlpha(fpsm, date, fd, test)) - { - continue; - } - } - - fm |= test; - zm |= test; - - int fzm = ~(fm == GSVector4i::xffffffff()).ps32(zm == GSVector4i::xffffffff()).ps32().mask(); - - WriteZBuf(zpsm, ztst, zs, zd, zm, za, fzm); - - if(abe != 255) - { - GSVector4i mask = GSVector4i::x00ff(fd); - - switch(fpsm) - { - case 0: - case 1: - c[2] = fd & mask; - c[3] = (fd >> 8) & mask; - break; - case 2: - c[2] = ((fd & 0x7c00) << 9) | ((fd & 0x001f) << 3); - c[3] = ((fd & 0x8000) << 8) | ((fd & 0x03e0) >> 2); - break; - } - - c[4] = GSVector4::zero(); - c[5] = GSVector4::zero(); - - GSVector4i rb, ga; - - if(tfx == TFX_NONE && fge == 0 && abea != 1 && abeb != 1 && abec != 1 && abea != abeb) - { - c[0] = m_env.c2.rb; - c[1] = m_env.c2.ga; - - rb = c[0]; - ga = c[1]; - - if(abed == 1) - { - rb = rb.add16(c[2]); - ga = ga.add16(c[3]); - } - } - else - { - if(abea != abeb) - { - rb = c[abea * 2 + 0]; - ga = c[abea * 2 + 1]; - - if(abeb < 2) - { - rb = rb.sub16(c[abeb * 2 + 0]); - ga = ga.sub16(c[abeb * 2 + 1]); - } - - if(!(fpsm == 1 && abec == 1)) - { - GSVector4i a = abec < 2 ? c[abec * 2 + 1].yywwlh().sll16(7) : m_env.afix2; - - rb = rb.modulate16<1>(a); - ga = ga.modulate16<1>(a); - } - - if(abed < 2) - { - rb = rb.add16(c[abed * 2 + 0]); - ga = ga.add16(c[abed * 2 + 1]); - } - } - else - { - rb = c[abed * 2 + 0]; - ga = c[abed * 2 + 1]; - } - } - - if(pabe) - { - mask = (c[1] << 8).sra32(31); - - rb = c[0].blend8(rb, mask); - ga = c[1].blend8(ga, mask); - } - - c[0] = rb; - c[1] = ga.mix16(c[1]); - } - - WriteFrame(fpsm, rfb, c, fd, fm, fa, fzm); - } - while(0); - - if(steps <= 0) break; - - steps -= 4; - - test = m_test[7 + (steps & (steps >> 31))]; - - fza_offset++; - - if(!sprite) - { - z += m_env.d4.z; - f = f.add16(m_env.d4.f); - } - - if(fst) - { - GSVector4i st = m_env.d4.st; - - si += st.xxxx(); - if(!sprite) ti += st.yyyy(); - } - else - { - GSVector4 stq = m_env.d4.stq; - - s += stq.xxxx(); - t += stq.yyyy(); - q += stq.zzzz(); - } - - if(iip) - { - GSVector4i c = m_env.d4.c; - - rb = rb.add16(c.xxxx()); - ga = ga.add16(c.yyyy()); - } - } -} - -void GSDrawScanline::DrawSolidRect(const GSVector4i& r, const GSVertexSW& v) -{ -/* -static FILE* s_fp = NULL; -if(!s_fp) s_fp = fopen("c:\\log2.txt", "w"); -__int64 start = __rdtsc(); -int size = (r.z - r.x) * (r.w - r.y); -*/ - ASSERT(r.y >= 0); - ASSERT(r.w >= 0); - - // FIXME: sometimes the frame and z buffer may overlap, the outcome is undefined - - DWORD m; - - m = m_env.zm.u32[0]; - - if(m != 0xffffffff) - { - DWORD z = (DWORD)(float)v.p.z; - - if(m_env.sel.zpsm != 2) - { - if(m == 0) - { - DrawSolidRectT(m_env.zbr, m_env.zbc[0], r, z, m); - } - else - { - DrawSolidRectT(m_env.zbr, m_env.zbc[0], r, z, m); - } - } - else - { - if(m == 0) - { - DrawSolidRectT(m_env.zbr, m_env.zbc[0], r, z, m); - } - else - { - DrawSolidRectT(m_env.zbr, m_env.zbc[0], r, z, m); - } - } - } - - m = m_env.fm.u32[0]; - - if(m != 0xffffffff) - { - DWORD c = (GSVector4i(v.c) >> 7).rgba32(); - - if(m_state->m_context->FBA.FBA) - { - c |= 0x80000000; - } - - if(m_env.sel.fpsm != 2) - { - if(m == 0) - { - DrawSolidRectT(m_env.fbr, m_env.fbc[0], r, c, m); - } - else - { - DrawSolidRectT(m_env.fbr, m_env.fbc[0], r, c, m); - } - } - else - { - c = ((c & 0xf8) >> 3) | ((c & 0xf800) >> 6) | ((c & 0xf80000) >> 9) | ((c & 0x80000000) >> 16); - - if(m == 0) - { - DrawSolidRectT(m_env.fbr, m_env.fbc[0], r, c, m); - } - else - { - DrawSolidRectT(m_env.fbr, m_env.fbc[0], r, c, m); - } - } - } -/* -__int64 stop = __rdtsc(); -fprintf(s_fp, "%I64d => %I64d = %I64d (%d,%d - %d,%d) %d\n", start, stop, stop - start, r.x, r.y, r.z, r.w, size); -*/ -} - -template -void GSDrawScanline::DrawSolidRectT(const GSVector4i* row, int* col, const GSVector4i& r, DWORD c, DWORD m) -{ - if(m == 0xffffffff) return; - - GSVector4i color((int)c); - GSVector4i mask((int)m); - - if(sizeof(T) == sizeof(WORD)) - { - color = color.xxzzlh(); - mask = mask.xxzzlh(); - } - - color = color.andnot(mask); - - GSVector4i bm(8 * 4 / sizeof(T) - 1, 8 - 1); - GSVector4i br = (r + bm).andnot(bm.xyxy()); - - FillRect(row, col, GSVector4i(r.x, r.y, r.z, br.y), c, m); - FillRect(row, col, GSVector4i(r.x, br.w, r.z, r.w), c, m); - - if(r.x < br.x || br.z < r.z) - { - FillRect(row, col, GSVector4i(r.x, br.y, br.x, br.w), c, m); - FillRect(row, col, GSVector4i(br.z, br.y, r.z, br.w), c, m); - } - - FillBlock(row, col, br, color, mask); -} - -template -void GSDrawScanline::FillRect(const GSVector4i* row, int* col, const GSVector4i& r, DWORD c, DWORD m) -{ - if(r.x >= r.z) return; - - for(int y = r.y; y < r.w; y++) - { - DWORD base = row[y].x; - - for(int x = r.x; x < r.z; x++) - { - T* p = &((T*)m_env.vm)[base + col[x]]; - - *p = (T)(!masked ? c : (c | (*p & m))); - } - } -} - -template -void GSDrawScanline::FillBlock(const GSVector4i* row, int* col, const GSVector4i& r, const GSVector4i& c, const GSVector4i& m) -{ - if(r.x >= r.z) return; - - for(int y = r.y; y < r.w; y += 8) - { - DWORD base = row[y].x; - - for(int x = r.x; x < r.z; x += 8 * 4 / sizeof(T)) - { - GSVector4i* p = (GSVector4i*)&((T*)m_env.vm)[base + col[x]]; - - for(int i = 0; i < 16; i += 4) - { - p[i + 0] = !masked ? c : (c | (p[i + 0] & m)); - p[i + 1] = !masked ? c : (c | (p[i + 1] & m)); - p[i + 2] = !masked ? c : (c | (p[i + 2] & m)); - p[i + 3] = !masked ? c : (c | (p[i + 3] & m)); - } - } - } -} - -// - -GSDrawScanline::GSDrawScanlineMap::GSDrawScanlineMap() -{ - // w00t :P - - #define InitDS_IIP(fpsm, zpsm, ztst, iip) \ - m_default[fpsm][zpsm][ztst][iip] = (DrawScanlinePtr)&GSDrawScanline::DrawScanline; \ - - #define InitDS_ZTST(fpsm, zpsm, ztst) \ - InitDS_IIP(fpsm, zpsm, ztst, 0) \ - InitDS_IIP(fpsm, zpsm, ztst, 1) \ - - #define InitDS(fpsm, zpsm) \ - InitDS_ZTST(fpsm, zpsm, 0) \ - InitDS_ZTST(fpsm, zpsm, 1) \ - InitDS_ZTST(fpsm, zpsm, 2) \ - InitDS_ZTST(fpsm, zpsm, 3) \ - - InitDS(0, 0); - InitDS(0, 1); - InitDS(0, 2); - InitDS(0, 3); - InitDS(1, 0); - InitDS(1, 1); - InitDS(1, 2); - InitDS(1, 3); - InitDS(2, 0); - InitDS(2, 1); - InitDS(2, 2); - InitDS(2, 3); - InitDS(3, 0); - InitDS(3, 1); - InitDS(3, 2); - - #define InitDS_Sel(sel) \ - SetAt(sel, (DrawScanlinePtr)&GSDrawScanline::DrawScanlineEx<##sel##>); - - #ifdef FAST_DRAWSCANLINE - - // bios - - InitDS_Sel(0x1fe04850); // 8.99% - InitDS_Sel(0x1fe28870); // 26.46% - InitDS_Sel(0x1fe38050); // 12.95% - InitDS_Sel(0x1fe38060); // 8.59% - InitDS_Sel(0x48428050); // 8.86% - InitDS_Sel(0x48428060); // 6.30% - InitDS_Sel(0x48804860); // 28.07% - InitDS_Sel(0x49028060); // 6.31% - InitDS_Sel(0x4902904c); // 5.46% - InitDS_Sel(0x4b02804c); // 5.11% - InitDS_Sel(0x4c804050); // 9.08% - InitDS_Sel(0x4d038864); // 114.89% - InitDS_Sel(0x9fe39064); // 14.72% - InitDS_Sel(0xc8804050); // 8.58% - InitDS_Sel(0xc9004050); // 8.69% - InitDS_Sel(0xc9039050); // 17.17% - InitDS_Sel(0xcc804050); // 8.16% - InitDS_Sel(0xcd019050); // 85.40% - - // ffx - - InitDS_Sel(0x11020865); // 9.81% - InitDS_Sel(0x1fe68875); // 9.90% - InitDS_Sel(0x1fe69075); // 15.13% - InitDS_Sel(0x1fe84075); // 5.16% - InitDS_Sel(0x1fee8075); // 5.98% - InitDS_Sel(0x1fee8875); // 43.94% - InitDS_Sel(0x1fee8876); // 22.75% - InitDS_Sel(0x1fee8975); // 5.70% - InitDS_Sel(0x48404865); // 20.31% - InitDS_Sel(0x48468865); // 8.18% - InitDS_Sel(0x48478065); // 17.47% - InitDS_Sel(0x48820965); // 7.89% - InitDS_Sel(0x48830875); // 5.84% - InitDS_Sel(0x48868865); // 5.44% - InitDS_Sel(0x48868965); // 9.13% - InitDS_Sel(0x48878165); // 28.27% - InitDS_Sel(0x488f89f5); // 20.19% - InitDS_Sel(0x488f89f6); // 27.92% - InitDS_Sel(0x49068065); // 7.68% - InitDS_Sel(0x49068865); // 20.15% - InitDS_Sel(0x49068965); // 8.65% - InitDS_Sel(0x49078065); // 14.00% - InitDS_Sel(0x49078165); // 5.63% - InitDS_Sel(0xc883004d); // 22.42% - InitDS_Sel(0xc887814d); // 9.20% - InitDS_Sel(0xc8878165); // 71.18% - InitDS_Sel(0xc8879065); // 26.05% - InitDS_Sel(0xc887914d); // 8.40% - InitDS_Sel(0xc88791e5); // 82.67% - InitDS_Sel(0xc9078065); // 8.00% - InitDS_Sel(0xcc819055); // 14.54% - InitDS_Sel(0xcc839065); // 7.41% - InitDS_Sel(0xd5204055); // 34.58% - InitDS_Sel(0x48804855); // 11.77% - InitDS_Sel(0x48804865); // 12.94% - InitDS_Sel(0x488e8965); // 5.04% - InitDS_Sel(0x49004875); // 11.36% - InitDS_Sel(0x9100404d); // 8.54% - InitDS_Sel(0x9fe78075); // 18.54% - InitDS_Sel(0x9fe78155); // 13.08% - InitDS_Sel(0xcd078075); // 9.47% - - // ffx-2 - - InitDS_Sel(0x110a8965); // 17.40% - InitDS_Sel(0x1fe30069); // 17.38% - InitDS_Sel(0x1fe5884d); // 11.56% - InitDS_Sel(0x48468965); // 79.89% - InitDS_Sel(0x4881884d); // 5.61% - InitDS_Sel(0x488781f5); // 5.84% - InitDS_Sel(0x4890404c); // 108.44% - InitDS_Sel(0x4893084c); // 24.74% - InitDS_Sel(0x49004859); // 48.72% - InitDS_Sel(0x49004865); // 13.08% - InitDS_Sel(0x49004869); // 22.94% - InitDS_Sel(0x4900494d); // 470.30% - InitDS_Sel(0x4907814d); // 14.15% - InitDS_Sel(0x49078865); // 21.56% - InitDS_Sel(0x49078965); // 11.37% - InitDS_Sel(0x490e8165); // 15.52% - InitDS_Sel(0xc8478165); // 10.44% - InitDS_Sel(0xc8804055); // 36.58% - InitDS_Sel(0xc881004d); // 13.53% - InitDS_Sel(0xc8830055); // 23.97% - InitDS_Sel(0xc885004d); // 14.32% - InitDS_Sel(0xc893004c); // 136.83% - InitDS_Sel(0xc895004c); // 16.48% - InitDS_Sel(0xc9004055); // 13.92% - InitDS_Sel(0xc9004059); // 15.87% - InitDS_Sel(0xc9004065); // 18.61% - InitDS_Sel(0xc9059155); // 13.56% - InitDS_Sel(0xc907814d); // 15.06% - InitDS_Sel(0xc9078165); // 12.21% - InitDS_Sel(0xcc804055); // 16.51% - InitDS_Sel(0xcc850055); // 17.01% - InitDS_Sel(0xc88581cd); // 7.32% - InitDS_Sel(0xc88581e5); // 5.41% - - // ffxii - - InitDS_Sel(0x1fe6804c); // 9.05% - InitDS_Sel(0x1fe68064); // 5.11% - InitDS_Sel(0x1fe6884c); // 14.58% - InitDS_Sel(0x1fee8864); // 88.41% - InitDS_Sel(0x1fee8964); // 33.72% - InitDS_Sel(0x48404064); // 30.72% - InitDS_Sel(0x4847004c); // 17.41% - InitDS_Sel(0x48828864); // 6.06% - InitDS_Sel(0x4883004c); // 20.10% - InitDS_Sel(0x4883084c); // 12.37% - InitDS_Sel(0x4886804c); // 5.10% - InitDS_Sel(0x4887084c); // 226.61% - InitDS_Sel(0x48878064); // 7.39% - InitDS_Sel(0x488e8b64); // 16.26% - InitDS_Sel(0x48904064); // 29.47% - InitDS_Sel(0x49004064); // 9.31% - InitDS_Sel(0x49078064); // 28.77% - InitDS_Sel(0x5fe0404c); // 70.30% - InitDS_Sel(0x9fe3904c); // 10.16% - InitDS_Sel(0xc887004c); // 18.63% - InitDS_Sel(0xc8878064); // 19.71% - InitDS_Sel(0xc887904c); // 13.03% - InitDS_Sel(0xc9278064); // 39.54% - - // kingdom hearts - - InitDS_Sel(0x4840404c); // 15.00% - InitDS_Sel(0x48830874); // 14.41% - InitDS_Sel(0x48868154); // 7.22% - InitDS_Sel(0x4886884c); // 28.13% - InitDS_Sel(0x4886904c); // 16.66% - InitDS_Sel(0x490e8974); // 59.46% - InitDS_Sel(0xc8818054); // 13.73% - InitDS_Sel(0xc8858054); // 11.63% - InitDS_Sel(0xc9004054); // 14.66% - - // kingdom hearts 2 - - InitDS_Sel(0x48804060); // 19.75% - InitDS_Sel(0x488a8964); // 20.35% - InitDS_Sel(0x9fe39054); // 16.04% - InitDS_Sel(0xc8810054); // 28.27% - InitDS_Sel(0xcc83004d); // 53.63% - InitDS_Sel(0xcd03004d); // 20.55% - - // persona 3 - - InitDS_Sel(0x484e8068); // 29.91% - InitDS_Sel(0x4881804c); // 18.16% - InitDS_Sel(0x4881904c); // 24.90% - InitDS_Sel(0x490e8068); // 5.82% - InitDS_Sel(0x4b07904c); // 59.21% - InitDS_Sel(0x4d47834c); // 29.42% - InitDS_Sel(0x4d47934c); // 27.37% - InitDS_Sel(0xca43004c); // 17.88% - InitDS_Sel(0xcb07934c); // 11.38% - InitDS_Sel(0xcd47804c); // 106.54% - InitDS_Sel(0xcd47834c); // 104.37% - - // persona 4 - - InitDS_Sel(0x1fe04058); // 23.41% - InitDS_Sel(0x4840484c); // 24.66% - InitDS_Sel(0x4881834c); // 21.87% - InitDS_Sel(0x4881934c); // 21.68% - InitDS_Sel(0x48828368); // 9.84% - InitDS_Sel(0x48868f68); // 29.84% - InitDS_Sel(0x48879168); // 5.74% - InitDS_Sel(0x49068868); // 18.43% - InitDS_Sel(0x49078068); // 63.62% - InitDS_Sel(0x49079068); // 57.82% - InitDS_Sel(0x490e8868); // 22.88% - InitDS_Sel(0x4a47804c); // 68.03% - InitDS_Sel(0x4a47904c); // 20.99% - InitDS_Sel(0x4a80404c); // 190.06% - InitDS_Sel(0x4a83004c); // 25.28% - InitDS_Sel(0x4a87804c); // 26.31% - InitDS_Sel(0x4a878068); // 29.36% - InitDS_Sel(0x4a878868); // 23.13% - InitDS_Sel(0x4a879068); // 11.16% - InitDS_Sel(0x4b00404c); // 111.77% - InitDS_Sel(0x4b07804c); // 23.00% - InitDS_Sel(0x4b07884c); // 21.15% - InitDS_Sel(0x5fe04058); // 37.01% - InitDS_Sel(0x5fe04858); // 87.23% - - // sfex3 - - InitDS_Sel(0x1fe04868); // 8.37% - InitDS_Sel(0x1fe6b068); // 16.21% - InitDS_Sel(0x1fe6b868); // 6.50% - InitDS_Sel(0x41268068); // 8.16% - InitDS_Sel(0x41269068); // 9.51% - InitDS_Sel(0x4886b068); // 20.50% - InitDS_Sel(0x4886b868); // 35.05% - InitDS_Sel(0x49079078); // 6.90% - InitDS_Sel(0x4c868068); // 5.48% - InitDS_Sel(0x4c868868); // 6.05% - InitDS_Sel(0x9fe1004e); // 6.98% - InitDS_Sel(0x9fe3004e); // 13.33% - InitDS_Sel(0xc8859058); // 10.74% - InitDS_Sel(0xcc804058); // 8.15% - InitDS_Sel(0xcd404058); // 5.04% - - // gt4 - - InitDS_Sel(0x1fee8164); // 7.38% - InitDS_Sel(0x488e8f64); // 7.09% - InitDS_Sel(0x488e9764); // 31.70% - InitDS_Sel(0x4b1a8864); // 5.45% - InitDS_Sel(0x5fe3904e); // 8.54% - - // katamary damacy - - InitDS_Sel(0x488e89e4); // 10.50% - InitDS_Sel(0x488e91d4); // 18.22% - InitDS_Sel(0xc88181cc); // 7.69% - InitDS_Sel(0xc8904054); // 12.39% - - // grandia 3 - - InitDS_Sel(0x1fe0404e); // 7.99% - InitDS_Sel(0x48868360); // 5.62% - InitDS_Sel(0x48868860); // 8.40% - InitDS_Sel(0x48869360); // 7.19% - InitDS_Sel(0x4887884c); // 5.93% - InitDS_Sel(0x488a8060); // 12.82% - InitDS_Sel(0x488e8360); // 26.69% - InitDS_Sel(0x488e8b60); // 32.33% - InitDS_Sel(0x488e8f60); // 15.38% - InitDS_Sel(0x488e9060); // 7.52% - InitDS_Sel(0x50368060); // 9.24% - InitDS_Sel(0xc8878070); // 37.81% - InitDS_Sel(0xcc81804c); // 46.79% - InitDS_Sel(0xcc839060); // 55.67% - - // rumble roses - - InitDS_Sel(0x1fe78064); // 26.70% - InitDS_Sel(0x1fe79064); // 9.93% - InitDS_Sel(0x4880484c); // 6.38% - InitDS_Sel(0x48838164); // 11.01% - InitDS_Sel(0x4887b864); // 35.30% - InitDS_Sel(0x488e8164); // 5.23% - InitDS_Sel(0x4900484c); // 8.86% - InitDS_Sel(0x49078864); // 7.98% - InitDS_Sel(0x490e8964); // 8.26% - InitDS_Sel(0x9fe3004d); // 8.92% - InitDS_Sel(0xc8838164); // 14.00% - InitDS_Sel(0xc8878164); // 15.96% - InitDS_Sel(0xcc830064); // 35.39% - - // dmc - - InitDS_Sel(0x4423904c); // 7.89% - InitDS_Sel(0x4427904c); // 17.05% - InitDS_Sel(0x45204078); // 9.08% - InitDS_Sel(0x4c87914c); // 40.48% - InitDS_Sel(0x54204078); // 9.09% - InitDS_Sel(0x9fe39058); // 7.17% - InitDS_Sel(0x9fe78068); // 9.28% - InitDS_Sel(0xc427904c); // 8.30% - InitDS_Sel(0xc520404c); // 8.11% - InitDS_Sel(0xc8804078); // 6.11% - InitDS_Sel(0xc8810068); // 7.80% - InitDS_Sel(0xc8830068); // 10.05% - InitDS_Sel(0xcc43804c); // 17.32% - InitDS_Sel(0xd420404c); // 8.03% - - // xenosaga 2 - - InitDS_Sel(0x1fee804c); // 15.39% - InitDS_Sel(0x49079064); // 31.08% - InitDS_Sel(0x51229064); // 8.86% - InitDS_Sel(0xc8804074); // 16.71% - InitDS_Sel(0xc9079054); // 17.35% - InitDS_Sel(0xcc804054); // 14.57% - InitDS_Sel(0xcc839054); // 24.04% - InitDS_Sel(0xcd004054); // 14.54% - - // nfs mw - - InitDS_Sel(0x1fe68068); // 18.10% - InitDS_Sel(0x1fe6806a); // 6.75% - InitDS_Sel(0x1fe68164); // 5.78% - InitDS_Sel(0x1fe68868); // 117.99% - InitDS_Sel(0x1fe68964); // 48.41% - InitDS_Sel(0x4883804e); // 7.16% - InitDS_Sel(0x48868868); // 46.01% - InitDS_Sel(0x4b004064); // 22.82% - InitDS_Sel(0x4b004068); // 33.12% - InitDS_Sel(0x4b004864); // 21.73% - InitDS_Sel(0x4b004868); // 37.86% - InitDS_Sel(0x4b028064); // 20.96% - InitDS_Sel(0x4b028068); // 30.53% - InitDS_Sel(0x4b028864); // 24.64% - InitDS_Sel(0x4b028868); // 31.04% - InitDS_Sel(0x4b038064); // 13.05% - InitDS_Sel(0xc805904c); // 17.04% - InitDS_Sel(0xc9078064); // 13.78% - InitDS_Sel(0xc927904c); // 18.78% - InitDS_Sel(0xcc83004c); // 5.32% - InitDS_Sel(0xcc83804c); // 19.33% - InitDS_Sel(0xcc83804e); // 5.85% - InitDS_Sel(0xcd03914c); // 12.00% - InitDS_Sel(0xd127904c); // 18.81% - InitDS_Sel(0xdfe19064); // 27.63% - - // berserk - - InitDS_Sel(0x48804064); // 41.22% - InitDS_Sel(0x48878864); // 41.61% - InitDS_Sel(0x488e8064); // 32.85% - InitDS_Sel(0x488e8964); // 33.35% - InitDS_Sel(0x49004874); // 10.91% - InitDS_Sel(0x4c8e8864); // 11.27% - InitDS_Sel(0x4c8fb864); // 5.61% - InitDS_Sel(0xc8804064); // 14.54% - InitDS_Sel(0xc8830064); // 24.60% - InitDS_Sel(0xcd03004c); // 31.16% - InitDS_Sel(0xdfe3004c); // 7.40% - InitDS_Sel(0xdfe3904c); // 18.00% - - // castlevania - - InitDS_Sel(0x1fe78868); // 19.07% - InitDS_Sel(0x48878868); // 85.08% - InitDS_Sel(0x4d00407a); // 17.23% - InitDS_Sel(0x9fe1004c); // 9.10% - InitDS_Sel(0x9fe3904e); // 16.38% - InitDS_Sel(0x9fe5904c); // 11.74% - InitDS_Sel(0xc8804068); // 13.17% - InitDS_Sel(0xc881004e); // 17.78% - InitDS_Sel(0xca80404c); // 8.43% - InitDS_Sel(0xdfe3804c); // 17.00% - - // okami - - InitDS_Sel(0x48804058); // 10.29% - InitDS_Sel(0x48878058); // 11.71% - InitDS_Sel(0x48878168); // 250.79% - InitDS_Sel(0x488e8068); // 20.22% - InitDS_Sel(0x488e8868); // 32.58% - InitDS_Sel(0x488e8968); // 29.40% - InitDS_Sel(0x49078168); // 13.87% - InitDS_Sel(0x9fe18058); // 10.94% - InitDS_Sel(0xc5218058); // 26.94% - InitDS_Sel(0xc881804c); // 11.98% - InitDS_Sel(0xc8839158); // 22.61% - InitDS_Sel(0xc8878158); // 8.98% - InitDS_Sel(0xc8878168); // 9.05% - InitDS_Sel(0xc8879168); // 6.53% - InitDS_Sel(0xc9078168); // 15.66% - InitDS_Sel(0xca83804c); // 16.89% - InitDS_Sel(0xcc43904c); // 77.10% - InitDS_Sel(0xdfe59068); // 64.26% - - // bully - - InitDS_Sel(0x110e8864); // 65.16% - InitDS_Sel(0x110e8964); // 50.07% - InitDS_Sel(0x4d068064); // 23.14% - InitDS_Sel(0x4d068364); // 21.42% - InitDS_Sel(0x4d068864); // 22.79% - InitDS_Sel(0x9fe04077); // 8.61% - InitDS_Sel(0xc901004c); // 22.07% - InitDS_Sel(0xca83904c); // 51.08% - InitDS_Sel(0xd480404d); // 15.61% - InitDS_Sel(0xd501904e); // 37.30% - - // culdcept - - InitDS_Sel(0x1fe04866); // 15.93% - InitDS_Sel(0x1fe2a9e6); // 55.93% - InitDS_Sel(0x9fe391e6); // 31.07% - InitDS_Sel(0x9fe3a1e6); // 9.26% - InitDS_Sel(0x9fe591e6); // 9.73% - InitDS_Sel(0xc88181e6); // 9.89% - InitDS_Sel(0x1fe2a1e6); // 15.71% - InitDS_Sel(0x49004866); // 5.05% - InitDS_Sel(0x4d02a1e6); // 15.31% - InitDS_Sel(0x9fe191e6); // 5.64% - InitDS_Sel(0x9fe59066); // 20.56% - InitDS_Sel(0x9fe991e6); // 19.59% - InitDS_Sel(0xcd0381e6); // 5.84% - - // suikoden 5 - - InitDS_Sel(0x00428868); // 14.32% - InitDS_Sel(0x40428868); // 20.87% - InitDS_Sel(0x4846804c); // 27.56% - InitDS_Sel(0x48819368); // 26.24% - InitDS_Sel(0x48828b68); // 29.80% - InitDS_Sel(0x48829368); // 22.30% - InitDS_Sel(0x48858368); // 8.44% - InitDS_Sel(0x48858b68); // 6.10% - InitDS_Sel(0x48859068); // 22.77% - InitDS_Sel(0x48859368); // 7.35% - InitDS_Sel(0x48869068); // 30.96% - InitDS_Sel(0x48878b68); // 5.18% - InitDS_Sel(0x48879368); // 10.31% - InitDS_Sel(0x488a8b68); // 11.73% - InitDS_Sel(0x49028868); // 14.35% - InitDS_Sel(0x4906804c); // 30.53% - InitDS_Sel(0x4d068868); // 33.72% - InitDS_Sel(0x4d0e8868); // 34.68% - - // dq8 - - InitDS_Sel(0x48830064); // 8.11% - InitDS_Sel(0x48869164); // 12.03% - InitDS_Sel(0x490a8164); // 5.03% - InitDS_Sel(0x490e904c); // 19.05% - InitDS_Sel(0x490f904c); // 15.81% - InitDS_Sel(0x9103b04c); // 5.05% - InitDS_Sel(0xc840404c); // 15.86% - InitDS_Sel(0xc883914c); // 5.84% - InitDS_Sel(0xc885804c); // 22.07% - InitDS_Sel(0xc8859054); // 9.61% - InitDS_Sel(0xc8c3804c); // 36.23% - InitDS_Sel(0xdfe3904e); // 5.49% - - // resident evil 4 - - InitDS_Sel(0x1fe04057); // 6.33% - InitDS_Sel(0x48868064); // 7.84% - InitDS_Sel(0x4886814c); // 5.42% - InitDS_Sel(0x48868164); // 12.98% - InitDS_Sel(0x48868864); // 39.04% - InitDS_Sel(0x48868964); // 10.15% - InitDS_Sel(0x48878164); // 64.35% - InitDS_Sel(0x4b068064); // 6.74% - InitDS_Sel(0x9fe18064); // 11.81% - InitDS_Sel(0xc880404c); // 8.39% - InitDS_Sel(0xc883814c); // 13.71% - InitDS_Sel(0xc885904c); // 11.74% - InitDS_Sel(0xc887804c); // 25.43% - InitDS_Sel(0xc887814c); // 17.68% - InitDS_Sel(0xc903904c); // 15.89% - InitDS_Sel(0xc907814c); // 10.74% - InitDS_Sel(0xcc879064); // 25.97% - InitDS_Sel(0xcd004064); // 70.25% - InitDS_Sel(0xcd03904c); // 23.53% - InitDS_Sel(0xcd07814c); // 8.41% - InitDS_Sel(0xd483904c); // 6.04% - InitDS_Sel(0xdfe1904e); // 19.81% - InitDS_Sel(0xdfe5904c); // 12.52% - - // tomoyo after - - InitDS_Sel(0x48404868); // 30.60% - InitDS_Sel(0x9fe38059); // 21.23% - InitDS_Sel(0x9fe39059); // 20.70% - InitDS_Sel(0xc8478068); // 8.06% - InitDS_Sel(0xc8818068); // 26.07% - InitDS_Sel(0xc9058068); // 15.90% - InitDS_Sel(0xca858068); // 14.66% - - // .hack redemption - - InitDS_Sel(0x1fe04864); // 5.01% - InitDS_Sel(0x48404074); // 6.97% - InitDS_Sel(0x48469064); // 20.80% - InitDS_Sel(0x48478064); // 8.87% - InitDS_Sel(0x48804864); // 5.94% - InitDS_Sel(0x48869364); // 22.39% - InitDS_Sel(0x488e9064); // 23.49% - InitDS_Sel(0x49004074); // 6.95% - InitDS_Sel(0x49004864); // 7.26% - InitDS_Sel(0xc123004c); // 17.86% - InitDS_Sel(0xc8478064); // 8.89% - InitDS_Sel(0xc8804054); // 13.68% - InitDS_Sel(0xc903004c); // 16.45% - InitDS_Sel(0xcc41804c); // 11.98% - InitDS_Sel(0xdfe1004c); // 11.81% - - // wild arms 4 - - InitDS_Sel(0x9fe19050); // 6.28% - InitDS_Sel(0x9fe58064); // 11.45% - InitDS_Sel(0x9fe59064); // 10.01% - InitDS_Sel(0xc8404064); // 22.23% - InitDS_Sel(0xccc0404c); // 10.08% - InitDS_Sel(0xccc04064); // 5.64% - InitDS_Sel(0xcd07804c); // 39.49% - InitDS_Sel(0xcd078164); // 19.54% - InitDS_Sel(0xcd45804c); // 5.23% - InitDS_Sel(0xdfe19054); // 17.70% - - // wild arms 5 - - InitDS_Sel(0x4885884c); // 6.64% - InitDS_Sel(0x4887904c); // 25.66% - InitDS_Sel(0x488e8764); // 25.45% - InitDS_Sel(0x48c68864); // 6.46% - InitDS_Sel(0x9fe3804c); // 7.00% - InitDS_Sel(0xc845804c); // 14.03% - InitDS_Sel(0xdfe39054); // 19.69% - - // shadow of the colossus - - InitDS_Sel(0x4883804c); // 184.84% - InitDS_Sel(0x48868b64); // 12.88% - InitDS_Sel(0x48869064); // 27.18% - InitDS_Sel(0x48878364); // 23.80% - InitDS_Sel(0x48879064); // 27.06% - InitDS_Sel(0x48879364); // 16.89% - InitDS_Sel(0x488e8864); // 148.99% - InitDS_Sel(0x488e9364); // 5.28% - InitDS_Sel(0x490e8064); // 66.50% - InitDS_Sel(0x490e8864); // 8.82% - InitDS_Sel(0x490f8064); // 8.23% - InitDS_Sel(0x4d004064); // 88.17% - InitDS_Sel(0x9fe04064); // 9.69% - InitDS_Sel(0x9fe1004d); // 10.39% - InitDS_Sel(0x9fe3904d); // 15.56% - InitDS_Sel(0xc883804c); // 45.16% - InitDS_Sel(0xc883904c); // 5.41% - InitDS_Sel(0xc8938064); // 45.66% - InitDS_Sel(0xc8939064); // 15.27% - InitDS_Sel(0xc900404c); // 8.73% - InitDS_Sel(0xc9004064); // 51.37% - InitDS_Sel(0xc903804c); // 35.17% - InitDS_Sel(0xca83004c); // 17.37% - InitDS_Sel(0xcc030064); // 21.25% - InitDS_Sel(0xcc80404c); // 9.19% - - // tales of rebirth - - InitDS_Sel(0x48404054); // 10.33% - InitDS_Sel(0x48878054); // 75.33% - InitDS_Sel(0x48878b64); // 10.17% - InitDS_Sel(0x4c838854); // 15.15% - InitDS_Sel(0xc8478054); // 13.29% - InitDS_Sel(0xc88b9054); // 7.08% - InitDS_Sel(0xcc838064); // 16.57% - - // digital devil saga - - InitDS_Sel(0x48804050); // 6.18% - InitDS_Sel(0x48868870); // 5.80% - InitDS_Sel(0x488e8860); // 22.08% - InitDS_Sel(0x4907884c); // 28.15% - InitDS_Sel(0x9fe39070); // 5.89% - - // dbzbt2 - - InitDS_Sel(0x4906884c); // 17.04% - InitDS_Sel(0x4c904064); // 28.94% - InitDS_Sel(0xc8878074); // 26.80% - InitDS_Sel(0xc9078054); // 22.93% - - // dbzbt3 - - InitDS_Sel(0x489081e4); // 11.25% - InitDS_Sel(0x48968864); // 16.90% - InitDS_Sel(0x4c469064); // 14.83% - InitDS_Sel(0x4c80404c); // 6.99% - InitDS_Sel(0x4c869064); // 15.61% - InitDS_Sel(0xc88391cc); // 12.45% - InitDS_Sel(0xc885904e); // 16.45% - InitDS_Sel(0xc8859074); // 15.19% - InitDS_Sel(0xc905904c); // 27.52% - InitDS_Sel(0xc917804c); // 5.66% - InitDS_Sel(0xca40404c); // 10.86% - InitDS_Sel(0xcc45904e); // 33.93% - InitDS_Sel(0xcc80404e); // 12.83% - InitDS_Sel(0xcc8391cc); // 25.49% - - // dbz iw - - InitDS_Sel(0x1fe48864); // 11.22% - InitDS_Sel(0x1fe49064); // 5.09% - InitDS_Sel(0x1fec8864); // 26.53% - InitDS_Sel(0x1fec8964); // 6.54% - InitDS_Sel(0x48808064); // 7.90% - InitDS_Sel(0x48848064); // 5.32% - InitDS_Sel(0x48848864); // 18.43% - InitDS_Sel(0x48858064); // 20.14% - InitDS_Sel(0x48859064); // 13.97% - InitDS_Sel(0x49058064); // 9.97% - InitDS_Sel(0x49084064); // 9.60% - InitDS_Sel(0x9fe19064); // 17.67% - InitDS_Sel(0xc881004c); // 16.40% - InitDS_Sel(0xc8858064); // 38.16% - InitDS_Sel(0xc8859064); // 26.38% - InitDS_Sel(0xc88d8064); // 7.05% - InitDS_Sel(0xc88d9064); // 15.38% - InitDS_Sel(0xc9058064); // 12.95% - InitDS_Sel(0xc9084064); // 14.20% - InitDS_Sel(0xc90d8064); // 21.35% - InitDS_Sel(0xcd404054); // 18.85% - - // disgaea 2 - - InitDS_Sel(0x1fe04064); // 5.51% - InitDS_Sel(0x1fe69074); // 8.82% - InitDS_Sel(0x48878964); // 65.93% - InitDS_Sel(0xc8879164); // 5.09% - - // gradius 5 - - InitDS_Sel(0x48868968); // 40.64% - InitDS_Sel(0x48878968); // 7.97% - InitDS_Sel(0x49078968); // 7.80% - InitDS_Sel(0x490e884c); // 37.26% - InitDS_Sel(0x5fe68068); // 32.99% - InitDS_Sel(0x5fe68968); // 15.59% - InitDS_Sel(0x5fee8168); // 5.25% - InitDS_Sel(0x5fee8868); // 36.64% - InitDS_Sel(0x5fee8968); // 16.28% - InitDS_Sel(0x5ffe8868); // 6.67% - InitDS_Sel(0xdfe3814c); // 24.29% - - // tales of abyss - - InitDS_Sel(0x1fe39368); // 7.47% - InitDS_Sel(0x4885804c); // 14.27% - InitDS_Sel(0x48868068); // 11.14% - InitDS_Sel(0x4886934c); // 6.41% - InitDS_Sel(0x4887834c); // 8.90% - InitDS_Sel(0x488e8368); // 13.35% - InitDS_Sel(0x48cf89e8); // 39.25% - InitDS_Sel(0x4903834c); // 21.04% - InitDS_Sel(0x490c8b68); // 15.04% - InitDS_Sel(0x490e8b68); // 8.05% - InitDS_Sel(0x490f89e8); // 39.57% - InitDS_Sel(0x4d03914c); // 18.97% - InitDS_Sel(0xc121004c); // 26.59% - InitDS_Sel(0xc887934c); // 5.73% - InitDS_Sel(0xdfe59078); // 21.43% - - // Gundam Seed Destiny OMNI VS ZAFT II PLUS - - InitDS_Sel(0x1fe68075); // 27.61% - InitDS_Sel(0x4880484d); // 13.50% - InitDS_Sel(0x48878075); // 8.16% - InitDS_Sel(0x48878375); // 8.66% - InitDS_Sel(0x4887884d); // 17.82% - InitDS_Sel(0x48878b75); // 53.12% - InitDS_Sel(0x488e8075); // 42.24% - InitDS_Sel(0x488e8375); // 35.32% - InitDS_Sel(0x488e8875); // 25.59% - InitDS_Sel(0x488e8b75); // 51.44% - InitDS_Sel(0x488e9075); // 16.57% - InitDS_Sel(0x49068075); // 35.78% - InitDS_Sel(0x4906884d); // 6.37% - InitDS_Sel(0x490e8375); // 31.56% - InitDS_Sel(0x490e8875); // 35.20% - InitDS_Sel(0x490e8b75); // 38.85% - InitDS_Sel(0x9fe19075); // 20.98% - InitDS_Sel(0xc8878075); // 14.30% - - // nba 2k8 - - InitDS_Sel(0x1fe04056); // 15.57% - InitDS_Sel(0x1fe38966); // 28.88% - InitDS_Sel(0x1fe39156); // 25.28% - InitDS_Sel(0x1fe60866); // 5.67% - InitDS_Sel(0x1fe68866); // 5.75% - InitDS_Sel(0x48838166); // 10.93% - InitDS_Sel(0x48868066); // 7.59% - InitDS_Sel(0x48868166); // 10.44% - InitDS_Sel(0x48868866); // 42.03% - InitDS_Sel(0x48868966); // 30.06% - InitDS_Sel(0x48869166); // 6.52% - InitDS_Sel(0x48879066); // 10.60% - InitDS_Sel(0x49028966); // 7.28% - InitDS_Sel(0x49068066); // 31.37% - InitDS_Sel(0x49068966); // 11.65% - InitDS_Sel(0x49068976); // 45.50% - InitDS_Sel(0x5fe68866); // 22.26% - InitDS_Sel(0x9fe79066); // 28.38% - InitDS_Sel(0xc8879166); // 6.42% - InitDS_Sel(0xdfe79066); // 30.98% - - // onimusha 3 - - InitDS_Sel(0x1fee004c); // 5.11% - InitDS_Sel(0x1fee0868); // 42.66% - InitDS_Sel(0x1fee8968); // 7.76% - InitDS_Sel(0x48878068); // 24.27% - InitDS_Sel(0x48c28368); // 5.97% - InitDS_Sel(0x4903884c); // 28.26% - InitDS_Sel(0x49068068); // 9.53% - InitDS_Sel(0x4d05884c); // 6.59% - InitDS_Sel(0x5fe04078); // 29.53% - InitDS_Sel(0x9fe18068); // 5.38% - InitDS_Sel(0xc8839168); // 6.59% - InitDS_Sel(0xcc81904c); // 5.21% - InitDS_Sel(0xcc878168); // 7.18% - InitDS_Sel(0xcd004068); // 28.32% - InitDS_Sel(0xcd03804c); // 7.20% - InitDS_Sel(0xd425904c); // 5.69% - InitDS_Sel(0xdfe78368); // 6.71% - InitDS_Sel(0xdfe7904c); // 8.43% - InitDS_Sel(0xdfe79368); // 9.36% - - // resident evil code veronica - - InitDS_Sel(0x1fee8168); // 9.31% - InitDS_Sel(0x1fee8868); // 6.75% - InitDS_Sel(0x48804068); // 12.40% - InitDS_Sel(0x48804868); // 41.21% - InitDS_Sel(0x48804b68); // 7.16% - InitDS_Sel(0x9fe39068); // 17.58% - InitDS_Sel(0x9fe79068); // 25.03% - InitDS_Sel(0x9fe79168); // 25.89% - InitDS_Sel(0xc8878068); // 29.01% - InitDS_Sel(0xc8878368); // 11.44% - InitDS_Sel(0xc8879368); // 6.59% - InitDS_Sel(0xcc819058); // 23.03% - - // armored core 3 - - InitDS_Sel(0x1fe84074); // 6.66% - InitDS_Sel(0x1fee0874); // 59.28% - InitDS_Sel(0x48404854); // 7.27% - InitDS_Sel(0x48878074); // 10.32% - InitDS_Sel(0x48878874); // 16.96% - InitDS_Sel(0x488e8074); // 25.40% - InitDS_Sel(0x490e8074); // 79.82% - InitDS_Sel(0x4c4e8074); // 23.05% - InitDS_Sel(0x4d0b0864); // 5.94% - InitDS_Sel(0x4d0e8074); // 8.44% - InitDS_Sel(0xc8404054); // 9.47% - InitDS_Sel(0xc8850054); // 11.54% - InitDS_Sel(0xc88581d4); // 6.72% - InitDS_Sel(0xc88791d4); // 6.83% - InitDS_Sel(0xc9059054); // 13.98% - InitDS_Sel(0xc9078074); // 9.60% - - // aerial planet - - InitDS_Sel(0x4886894c); // 18.07% - InitDS_Sel(0x488e814c); // 16.96% - InitDS_Sel(0x4c868074); // 46.13% - InitDS_Sel(0x4c868874); // 7.71% - InitDS_Sel(0x4c868934); // 19.26% - InitDS_Sel(0x4c8e8074); // 12.50% - InitDS_Sel(0x4c8e8874); // 27.69% - InitDS_Sel(0x4cc0404c); // 15.74% - InitDS_Sel(0xc820404c); // 16.32% - InitDS_Sel(0xc8478164); // 11.12% - InitDS_Sel(0xc847914c); // 7.70% - InitDS_Sel(0xc887914c); // 8.85% - - // one piece grand battle 3 - - InitDS_Sel(0x48804054); // 12.28% - InitDS_Sel(0x48878854); // 12.62% - InitDS_Sel(0x49068174); // 5.54% - InitDS_Sel(0x49068874); // 28.97% - InitDS_Sel(0x49068964); // 16.11% - InitDS_Sel(0x49078174); // 11.17% - InitDS_Sel(0x9fe1904e); // 10.23% - InitDS_Sel(0xc8839054); // 21.50% - InitDS_Sel(0xc8878054); // 6.54% - InitDS_Sel(0xc8879054); // 10.18% - InitDS_Sel(0xc9078174); // 8.49% - InitDS_Sel(0xcac0404c); // 9.30% - InitDS_Sel(0xcc41904c); // 12.33% - InitDS_Sel(0xcc4190cc); // 7.21% - InitDS_Sel(0xd321914c); // 7.10% - - // one piece grand adventure - - InitDS_Sel(0x1fe0404c); // 5.18% - InitDS_Sel(0x48829164); // 12.79% - InitDS_Sel(0x48849164); // 11.67% - InitDS_Sel(0x48869154); // 5.38% - InitDS_Sel(0x48878154); // 5.01% - InitDS_Sel(0x48879154); // 5.57% - InitDS_Sel(0x49078964); // 151.46% - InitDS_Sel(0xc421814c); // 7.73% - InitDS_Sel(0xc843b04c); // 21.62% - - // shadow hearts - - InitDS_Sel(0x1fe6904c); // 5.97% - InitDS_Sel(0x48868078); // 9.90% - InitDS_Sel(0x48868778); // 9.59% - InitDS_Sel(0x49004058); // 7.20% - InitDS_Sel(0x49030058); // 40.18% - InitDS_Sel(0x4c870878); // 6.19% - InitDS_Sel(0x9fe3004c); // 20.51% - InitDS_Sel(0xc8804058); // 9.57% - InitDS_Sel(0xc881904e); // 5.29% - InitDS_Sel(0xc8819168); // 13.94% - InitDS_Sel(0xc8839058); // 12.53% - InitDS_Sel(0xc8878058); // 13.80% - InitDS_Sel(0xc8879058); // 9.68% - InitDS_Sel(0xc9039058); // 12.08% - InitDS_Sel(0xc9078068); // 29.18% - - // the punisher - - InitDS_Sel(0x48420864); // 5.88% - InitDS_Sel(0x48468864); // 8.39% - InitDS_Sel(0x48868764); // 16.69% - InitDS_Sel(0x4886bf64); // 14.77% - InitDS_Sel(0x49068064); // 7.90% - InitDS_Sel(0x4906904c); // 14.02% - InitDS_Sel(0x4d068f64); // 12.33% - InitDS_Sel(0x5fe68f64); // 62.24% - InitDS_Sel(0xc880474c); // 20.85% - InitDS_Sel(0xc883974c); // 6.07% - InitDS_Sel(0xc887874c); // 8.47% - InitDS_Sel(0xc887974c); // 10.36% - InitDS_Sel(0xdfe3974c); // 21.42% - - // guitar hero - - InitDS_Sel(0x1fe0407b); // 6.67% - InitDS_Sel(0x1fe6887a); // 9.08% - InitDS_Sel(0x4880484e); // 34.74% - InitDS_Sel(0x4886807a); // 6.73% - InitDS_Sel(0x4886887a); // 47.23% - InitDS_Sel(0x4886907a); // 5.53% - InitDS_Sel(0x4886956a); // 8.71% - InitDS_Sel(0x4887854e); // 6.67% - InitDS_Sel(0x4887887a); // 31.33% - InitDS_Sel(0x4887954e); // 20.26% - InitDS_Sel(0x488a917a); // 33.17% - InitDS_Sel(0x488e887a); // 80.36% - InitDS_Sel(0x488e8d7a); // 5.16% - InitDS_Sel(0x4906806a); // 23.53% - InitDS_Sel(0x4906886a); // 5.02% - InitDS_Sel(0x4d06a06a); // 22.00% - InitDS_Sel(0x4d06a86a); // 15.44% - InitDS_Sel(0x4d0ea06a); // 5.08% - InitDS_Sel(0x9503204e); // 22.47% - InitDS_Sel(0x9fe3906a); // 12.46% - InitDS_Sel(0xc887855a); // 5.09% - InitDS_Sel(0xc887857a); // 27.54% - InitDS_Sel(0xcd03204e); // 70.62% - InitDS_Sel(0xcd07806a); // 8.94% - - // ico - - InitDS_Sel(0x1fe28060); // 16.14% - InitDS_Sel(0x1fe68860); // 47.91% - InitDS_Sel(0x48868060); // 10.32% - InitDS_Sel(0x48868b60); // 94.89% - InitDS_Sel(0x49068b60); // 10.26% - InitDS_Sel(0x4c468b60); // 41.67% - InitDS_Sel(0x4c478860); // 11.90% - InitDS_Sel(0x4d004060); // 102.46% - InitDS_Sel(0x4d028060); // 17.75% - InitDS_Sel(0x4d068360); // 16.19% - InitDS_Sel(0x4d068860); // 18.08% - InitDS_Sel(0x4d068b60); // 223.13% - InitDS_Sel(0x4d078360); // 5.55% - InitDS_Sel(0x9fe04060); // 7.09% - InitDS_Sel(0x9fe380cc); // 16.22% - InitDS_Sel(0x9fe3a04c); // 47.14% - InitDS_Sel(0xc8859060); // 13.85% - InitDS_Sel(0xc893814c); // 40.77% - InitDS_Sel(0xc9004060); // 6.15% - InitDS_Sel(0xcd078060); // 5.49% - InitDS_Sel(0xcd078360); // 9.27% - - // kuon - - InitDS_Sel(0x1fee0865); // 19.11% - InitDS_Sel(0x48860065); // 26.44% - InitDS_Sel(0x48860865); // 24.38% - InitDS_Sel(0x48868365); // 18.01% - InitDS_Sel(0x48868b65); // 31.33% - InitDS_Sel(0x488e0865); // 39.97% - InitDS_Sel(0x488e0b65); // 20.78% - InitDS_Sel(0x488e8b65); // 12.26% - InitDS_Sel(0x4c429065); // 25.89% - InitDS_Sel(0x4d068365); // 9.17% - InitDS_Sel(0xc847004d); // 13.35% - InitDS_Sel(0xc887004d); // 17.53% - InitDS_Sel(0xc8870065); // 28.03% - InitDS_Sel(0xc907004d); // 18.64% - InitDS_Sel(0xc9070065); // 5.21% - - // hxh - - InitDS_Sel(0x1fe04876); // 7.16% - InitDS_Sel(0x1fee8076); // 9.68% - InitDS_Sel(0x1fee8976); // 17.11% - InitDS_Sel(0x9fe04076); // 5.37% - InitDS_Sel(0x9fe79176); // 6.77% - InitDS_Sel(0xc8804076); // 6.64% - InitDS_Sel(0xc8838176); // 6.95% - InitDS_Sel(0xc8839176); // 6.85% - InitDS_Sel(0xc8878076); // 5.29% - - // grandia extreme - - InitDS_Sel(0x1fe3884c); // 27.03% - InitDS_Sel(0x45269070); // 5.74% - InitDS_Sel(0x452e9070); // 7.25% - InitDS_Sel(0x48868070); // 13.25% - InitDS_Sel(0x48869070); // 24.24% - InitDS_Sel(0x48878370); // 22.45% - InitDS_Sel(0x48879070); // 21.66% - InitDS_Sel(0x48879370); // 13.17% - InitDS_Sel(0x4888404c); // 12.23% - InitDS_Sel(0x48884050); // 15.68% - InitDS_Sel(0x488e8870); // 44.66% - InitDS_Sel(0x488e8b70); // 45.62% - InitDS_Sel(0x488e9370); // 14.64% - InitDS_Sel(0x9fe3934c); // 16.61% - InitDS_Sel(0xcc81934c); // 62.20% - - // enthusia - - InitDS_Sel(0x1fe04854); // 23.33% - InitDS_Sel(0x1fe60064); // 5.72% - InitDS_Sel(0x1fe60068); // 5.03% - InitDS_Sel(0x1fee0064); // 7.51% - InitDS_Sel(0x1fee0864); // 15.47% - InitDS_Sel(0x48860f64); // 9.63% - InitDS_Sel(0x48868f64); // 29.41% - InitDS_Sel(0x488e0f64); // 11.80% - InitDS_Sel(0x49068864); // 23.63% - InitDS_Sel(0x4b020864); // 13.40% - InitDS_Sel(0x4b060064); // 11.39% - InitDS_Sel(0x4b060864); // 8.38% - InitDS_Sel(0x4b068864); // 14.03% - InitDS_Sel(0x9fe79064); // 13.49% - InitDS_Sel(0xcd40404c); // 11.10% - - // ys 1/2 eternal story - - // bloody roar - - InitDS_Sel(0x48810068); // 25.54% - InitDS_Sel(0x48848068); // 68.60% - InitDS_Sel(0x488789e8); // 10.83% - InitDS_Sel(0x488791e8); // 11.18% - InitDS_Sel(0x49004068); // 9.51% - InitDS_Sel(0x49004868); // 6.95% - InitDS_Sel(0x49018368); // 15.01% - InitDS_Sel(0x49019368); // 13.90% - InitDS_Sel(0x4b068068); // 13.98% - InitDS_Sel(0x4b068868); // 14.29% - InitDS_Sel(0x4c469068); // 9.71% - - // ferrari f355 challenge - - InitDS_Sel(0x489e8064); // 9.07% - InitDS_Sel(0x489e8b64); // 8.01% - InitDS_Sel(0x5fe04064); // 10.07% - InitDS_Sel(0x5fe04068); // 13.01% - InitDS_Sel(0x5fe04868); // 6.33% - InitDS_Sel(0x5fe60064); // 10.58% - InitDS_Sel(0x5fee0064); // 14.14% - InitDS_Sel(0x5fee0864); // 21.09% - InitDS_Sel(0x5feeb864); // 7.78% - InitDS_Sel(0x5ff60064); // 16.67% - InitDS_Sel(0x5ffe0064); // 17.43% - InitDS_Sel(0x5ffe0864); // 23.98% - InitDS_Sel(0xc8858168); // 54.96% - InitDS_Sel(0xc890404c); // 6.30% - InitDS_Sel(0xdfef0064); // 8.68% - - // king of fighters xi - - InitDS_Sel(0x488589e8); // 110.21% - InitDS_Sel(0x488591e8); // 55.38% - InitDS_Sel(0xf4819050); // 12.12% - - // mana khemia - - InitDS_Sel(0x488e8369); // 96.11% - InitDS_Sel(0xc880404d); // 12.30% - InitDS_Sel(0xc881804d); // 16.48% - InitDS_Sel(0xc8819059); // 22.73% - InitDS_Sel(0xc885904d); // 12.36% - InitDS_Sel(0xc907804d); // 59.32% - InitDS_Sel(0xc90f8369); // 7.80% - - // ar tonelico 2 - - InitDS_Sel(0x484f8369); // 7.55% - InitDS_Sel(0x488e8069); // 22.13% - InitDS_Sel(0x488e9069); // 33.42% - InitDS_Sel(0x488e9369); // 103.56% - InitDS_Sel(0x488f8369); // 23.74% - InitDS_Sel(0x490f8369); // 29.15% - InitDS_Sel(0xc885804d); // 5.80% - InitDS_Sel(0xc887804d); // 7.94% - InitDS_Sel(0xc88f9369); // 13.74% - InitDS_Sel(0xc905904d); // 6.23% - - // rouge galaxy - - InitDS_Sel(0x1fe0484c); // 6.12% - InitDS_Sel(0x484e8164); // 53.09% - InitDS_Sel(0x48879054); // 47.81% - InitDS_Sel(0x488b0964); // 95.23% - InitDS_Sel(0x490e8164); // 24.34% - InitDS_Sel(0x490e9164); // 5.24% - InitDS_Sel(0xc8858154); // 18.49% - InitDS_Sel(0xdff0404c); // 7.47% - - // mobile suit gundam seed battle assault 3 - - InitDS_Sel(0x49004854); // 7.22% - InitDS_Sel(0x4c804054); // 12.92% - InitDS_Sel(0x5fee8074); // 14.87% - InitDS_Sel(0x5fee8874); // 58.09% - InitDS_Sel(0x5fee9174); // 5.15% - InitDS_Sel(0xc88390cc); // 21.42% - InitDS_Sel(0xc88791cc); // 6.20% - InitDS_Sel(0xc90781cc); // 12.73% - InitDS_Sel(0xcc81004d); // 11.15% - - // hajime no ippo all stars - - InitDS_Sel(0x48848868); // 7.31% - InitDS_Sel(0x48848b68); // 6.25% - InitDS_Sel(0x48858868); // 6.71% - InitDS_Sel(0x488c8b68); // 16.70% - - // hajime no ippo 2 - - InitDS_Sel(0x1fe04068); // 11.95% - InitDS_Sel(0x4881004c); // 20.37% - InitDS_Sel(0x48839368); // 31.79% - InitDS_Sel(0x48858068); // 55.12% - InitDS_Sel(0x48868b68); // 23.49% - InitDS_Sel(0x48878368); // 6.54% - InitDS_Sel(0x48879068); // 29.98% - InitDS_Sel(0x488c8068); // 10.13% - InitDS_Sel(0x488c8868); // 16.20% - InitDS_Sel(0x488e8b68); // 38.97% - InitDS_Sel(0x488e9068); // 7.20% - InitDS_Sel(0x488e9368); // 13.42% - InitDS_Sel(0x49028b68); // 48.16% - InitDS_Sel(0x4b0e8068); // 5.51% - InitDS_Sel(0x4b0e8868); // 14.85% - InitDS_Sel(0x4d0e8068); // 7.65% - InitDS_Sel(0xc8859068); // 21.31% - - // virtual tennis 2 - - InitDS_Sel(0x488049e5); // 5.52% - InitDS_Sel(0x48868075); // 28.20% - InitDS_Sel(0x48868875); // 20.93% - InitDS_Sel(0x4c8781f5); // 11.54% - InitDS_Sel(0x9540404d); // 6.25% - InitDS_Sel(0xc8859065); // 11.57% - - // crash wrath of cortex - - InitDS_Sel(0x1fe20864); // 15.87% - InitDS_Sel(0x48828764); // 9.14% - InitDS_Sel(0x48828f64); // 18.80% - InitDS_Sel(0x48838364); // 12.07% - InitDS_Sel(0x48838f64); // 5.84% - InitDS_Sel(0x49028f64); // 16.48% - InitDS_Sel(0x49038f64); // 34.44% - InitDS_Sel(0x9fe78064); // 11.75% - InitDS_Sel(0xc8818364); // 9.12% - InitDS_Sel(0xc9030064); // 100.90% - InitDS_Sel(0xca838364); // 8.86% - InitDS_Sel(0xcd05834c); // 8.90% - - // sbam 2 - - // remember 11 - - // prince of tennis - - InitDS_Sel(0x4888484c); // 5.28% - InitDS_Sel(0x488d8164); // 30.73% - InitDS_Sel(0x488d9164); // 23.46% - InitDS_Sel(0xc885914c); // 5.01% - InitDS_Sel(0xc8859164); // 7.79% - InitDS_Sel(0xc88d8164); // 5.33% - InitDS_Sel(0xc88d9164); // 26.18% - InitDS_Sel(0xc8958164); // 10.14% - InitDS_Sel(0xc89d814c); // 7.09% - InitDS_Sel(0xcd458064); // 13.67% - - // ar tonelico - - InitDS_Sel(0x48868369); // 17.29% - InitDS_Sel(0x48869369); // 16.05% - InitDS_Sel(0x488f9369); // 6.07% - InitDS_Sel(0x49078b69); // 54.61% - InitDS_Sel(0x490f8069); // 54.79% - InitDS_Sel(0x490f9369); // 5.20% - InitDS_Sel(0xc8804069); // 16.59% - InitDS_Sel(0xc8878069); // 32.09% - InitDS_Sel(0xc8878369); // 14.18% - InitDS_Sel(0xc8879069); // 31.83% - InitDS_Sel(0xc8879369); // 12.02% - InitDS_Sel(0xc9038069); // 245.53% - - // dbz sagas - - InitDS_Sel(0x48828964); // 38.72% - InitDS_Sel(0x488e9164); // 10.98% - InitDS_Sel(0x54229164); // 6.16% - - // tourist trophy - - InitDS_Sel(0x1fe84064); // 14.21% - InitDS_Sel(0x1fee8064); // 23.50% - InitDS_Sel(0x1fee9064); // 13.72% - InitDS_Sel(0x488a8064); // 10.03% - InitDS_Sel(0x488e8065); // 16.63% - InitDS_Sel(0x488e9065); // 16.00% - InitDS_Sel(0x5fe3804c); // 8.34% - InitDS_Sel(0x5fe3904c); // 7.65% - InitDS_Sel(0x5fee8164); // 7.66% - InitDS_Sel(0x9fe1904c); // 9.19% - InitDS_Sel(0x9fe1904d); // 6.10% - InitDS_Sel(0x9fe3804d); // 9.23% - InitDS_Sel(0x9fe5904d); // 7.20% - InitDS_Sel(0x9fe7804d); // 5.30% - InitDS_Sel(0x9fe7904d); // 5.67% - InitDS_Sel(0xc88181d4); // 11.57% - InitDS_Sel(0xc881904d); // 7.00% - InitDS_Sel(0xc88191d4); // 12.53% - InitDS_Sel(0xc887904d); // 5.13% - InitDS_Sel(0xcb03804c); // 21.06% - InitDS_Sel(0xcc81904d); // 13.48% - InitDS_Sel(0xcc83804d); // 10.28% - InitDS_Sel(0xcc83904c); // 34.42% - InitDS_Sel(0xcc83904d); // 10.24% - InitDS_Sel(0xcc87904d); // 33.01% - InitDS_Sel(0xcd05804c); // 17.24% - InitDS_Sel(0xd520404c); // 9.81% - InitDS_Sel(0xdfe1904c); // 7.52% - InitDS_Sel(0xdfe5804c); // 7.14% - - // svr2k8 - - InitDS_Sel(0x1fe79066); // 13.17% - InitDS_Sel(0x4880404c); // 7.49% - InitDS_Sel(0x4887804c); // 5.40% - InitDS_Sel(0x4887814c); // 9.08% - InitDS_Sel(0x488a0064); // 5.41% - InitDS_Sel(0x4900404c); // 12.53% - InitDS_Sel(0x490e8364); // 30.80% - InitDS_Sel(0x4c97b874); // 15.16% - InitDS_Sel(0xc887834c); // 7.67% - - // tokyo bus guide - - InitDS_Sel(0x1fe04070); // 13.22% - InitDS_Sel(0x1fe04870); // 13.56% - InitDS_Sel(0x1fee8170); // 10.70% - InitDS_Sel(0x1fee8970); // 60.13% - InitDS_Sel(0x1fee89f0); // 51.01% - InitDS_Sel(0x48804870); // 12.85% - InitDS_Sel(0x488a8850); // 21.74% - InitDS_Sel(0xc8804070); // 13.67% - InitDS_Sel(0xc8879070); // 35.52% - InitDS_Sel(0xc88791f0); // 18.61% - - // 12riven - - // xenosaga - - InitDS_Sel(0x1fe38054); // 67.22% - InitDS_Sel(0x1fe38074); // 25.86% - InitDS_Sel(0x48478164); // 32.61% - InitDS_Sel(0x48804964); // 7.12% - InitDS_Sel(0x49078164); // 25.05% - InitDS_Sel(0x4c818134); // 10.06% - InitDS_Sel(0x4d069064); // 98.01% - InitDS_Sel(0x4d084864); // 13.35% - InitDS_Sel(0x5fe04074); // 61.58% - InitDS_Sel(0x5fe68864); // 39.80% - InitDS_Sel(0x5fee8864); // 45.95% - InitDS_Sel(0x9fe04074); // 9.60% - InitDS_Sel(0x9fe1804c); // 9.55% - InitDS_Sel(0x9fe19074); // 16.03% - InitDS_Sel(0xc8819054); // 35.54% - InitDS_Sel(0xc8830074); // 47.20% - InitDS_Sel(0xc8858164); // 7.84% - InitDS_Sel(0xc9078164); // 154.58% - InitDS_Sel(0xcc819074); // 19.87% - InitDS_Sel(0xcd00404c); // 31.81% - InitDS_Sel(0xd5204064); // 14.68% - InitDS_Sel(0xdfe04074); // 14.26% - - // mgs3s1 - - InitDS_Sel(0x482e8864); // 18.14% - InitDS_Sel(0x484e8864); // 10.00% - InitDS_Sel(0x48868364); // 94.90% - InitDS_Sel(0x488e8364); // 15.82% - InitDS_Sel(0x488f8064); // 5.31% - InitDS_Sel(0x49268864); // 6.73% - InitDS_Sel(0x4b0e8864); // 8.35% - InitDS_Sel(0x4b0e8b64); // 6.23% - InitDS_Sel(0x9fe1804d); // 9.13% - InitDS_Sel(0x9fe7904c); // 11.17% - InitDS_Sel(0xc8804364); // 5.24% - InitDS_Sel(0xc8819364); // 19.10% - InitDS_Sel(0xc883004c); // 17.25% - InitDS_Sel(0xc8878364); // 12.09% - InitDS_Sel(0xc8879064); // 22.53% - InitDS_Sel(0xcc830074); // 54.93% - InitDS_Sel(0xcd079364); // 5.24% - InitDS_Sel(0xcd404074); // 9.03% - - // god of war - - // gta sa - - InitDS_Sel(0x1fe84864); // 6.23% - InitDS_Sel(0x48810064); // 14.67% - InitDS_Sel(0x49004054); // 16.40% - InitDS_Sel(0x4d07804c); // 15.09% - InitDS_Sel(0x4d078864); // 9.54% - InitDS_Sel(0x4d0c8864); // 8.71% - - // haunting ground - - InitDS_Sel(0x1fe68864); // 38.74% - InitDS_Sel(0x1fe689e4); // 44.79% - InitDS_Sel(0x488689e4); // 5.03% - InitDS_Sel(0xc843904c); // 16.66% - InitDS_Sel(0xc88791e4); // 22.86% - InitDS_Sel(0xcc23804c); // 16.80% - InitDS_Sel(0xcd01904c); // 82.27% - InitDS_Sel(0xdfe04064); // 14.73% - InitDS_Sel(0xdff1904e); // 14.38% - - // odin sphere - - InitDS_Sel(0x4880404d); // 7.35% - InitDS_Sel(0x4885804d); // 6.02% - InitDS_Sel(0x4885904c); // 11.56% - InitDS_Sel(0x488f904c); // 6.59% - InitDS_Sel(0x488f904d); // 6.69% - InitDS_Sel(0x4907804d); // 5.71% - InitDS_Sel(0x4907884d); // 9.45% - InitDS_Sel(0xc881904c); // 5.36% - - // kingdom hearts re:com - - InitDS_Sel(0x1fe04078); // 9.88% - InitDS_Sel(0x1fee884c); // 17.61% - InitDS_Sel(0x4880494c); // 6.46% - InitDS_Sel(0x48868974); // 11.43% - InitDS_Sel(0x488a8164); // 6.28% - InitDS_Sel(0x488e804c); // 6.41% - InitDS_Sel(0x488e874c); // 6.02% - InitDS_Sel(0x4906814c); // 33.35% - InitDS_Sel(0x4906894c); // 44.97% - InitDS_Sel(0x49068974); // 15.85% - InitDS_Sel(0x4907894c); // 16.25% - InitDS_Sel(0x49078974); // 6.45% - InitDS_Sel(0x9fe10054); // 14.10% - InitDS_Sel(0x9fe3814d); // 14.12% - InitDS_Sel(0x9fe3914d); // 17.86% - InitDS_Sel(0xc885814c); // 7.69% - InitDS_Sel(0xc907804c); // 8.56% - InitDS_Sel(0xcd404064); // 9.28% - InitDS_Sel(0xd120404c); // 9.47% - - // hyper street fighter 2 anniversary edition - - // star ocean 3 - - InitDS_Sel(0x49068164); // 57.66% - InitDS_Sel(0x9fe30064); // 24.77% - InitDS_Sel(0x9fe38065); // 28.18% - InitDS_Sel(0xc8839164); // 37.72% - InitDS_Sel(0xc920404c); // 11.35% - - // aura for laura - - InitDS_Sel(0x1fe38070); // 31.10% - InitDS_Sel(0x1fe3904c); // 19.62% - InitDS_Sel(0x1fe39050); // 5.19% - InitDS_Sel(0x1fe68070); // 19.79% - InitDS_Sel(0x1fe78070); // 112.75% - InitDS_Sel(0x1fe79070); // 65.97% - InitDS_Sel(0x1fefb04c); // 17.85% - InitDS_Sel(0x9fe38050); // 11.45% - InitDS_Sel(0x9fe39050); // 11.01% - InitDS_Sel(0x9fe78050); // 12.31% - InitDS_Sel(0xc523804c); // 106.80% - InitDS_Sel(0xc8839050); // 14.31% - InitDS_Sel(0xc9038050); // 6.72% - InitDS_Sel(0xc9058050); // 291.44% - InitDS_Sel(0xcc818050); // 49.07% - InitDS_Sel(0xd5204050); // 7.22% - - #endif -} - -IDrawScanline::DrawScanlinePtr GSDrawScanline::GSDrawScanlineMap::GetDefaultFunction(DWORD dw) -{ - GSScanlineSelector sel; - - sel.dw = dw; - - return m_default[sel.fpsm][sel.zpsm][sel.ztst][sel.iip]; -} - -void GSDrawScanline::GSDrawScanlineMap::PrintStats() -{ - __super::PrintStats(); - - if(FILE* fp = fopen("c:\\1.txt", "w")) - { - POSITION pos = m_map_active.GetHeadPosition(); - - while(pos) - { - DWORD dw; - ActivePtr* p; - - m_map_active.GetNextAssoc(pos, dw, p); - - if(m_map.Lookup(dw)) - { - continue; - } - - GSScanlineSelector sel; - - sel.dw = dw; - - if(p->frames > 30 && !sel.IsSolidRect()) - { - int tpf = (int)((p->ticks / p->frames) * 10000 / (3000000000 / 60)); // 3 GHz, 60 fps - - if(tpf >= 500) - { - _ftprintf(fp, _T("InitDS_Sel(0x%08x); // %6.2f%%\n"), sel.dw, (float)tpf / 100); - } - } - } - - fclose(fp); - } -} - -// - -GSDrawScanline::GSSetupPrimMap::GSSetupPrimMap() -{ - #define InitSP_IIP(zbe, fge, tme, fst, iip) \ - m_default[zbe][fge][tme][fst][iip] = (SetupPrimPtr)&GSDrawScanline::SetupPrim; \ - - #define InitSP_FST(zbe, fge, tme, fst) \ - InitSP_IIP(zbe, fge, tme, fst, 0) \ - InitSP_IIP(zbe, fge, tme, fst, 1) \ - - #define InitSP_TME(zbe, fge, tme) \ - InitSP_FST(zbe, fge, tme, 0) \ - InitSP_FST(zbe, fge, tme, 1) \ - - #define InitSP_FGE(zbe, fge) \ - InitSP_TME(zbe, fge, 0) \ - InitSP_TME(zbe, fge, 1) \ - - #define InitSP_ZBE(zbe) \ - InitSP_FGE(zbe, 0) \ - InitSP_FGE(zbe, 1) \ - - InitSP_ZBE(0); - InitSP_ZBE(1); -} - -IDrawScanline::SetupPrimPtr GSDrawScanline::GSSetupPrimMap::GetDefaultFunction(DWORD dw) -{ - DWORD zbe = (dw >> 0) & 1; - DWORD fge = (dw >> 1) & 1; - DWORD tme = (dw >> 2) & 1; - DWORD fst = (dw >> 3) & 1; - DWORD iip = (dw >> 4) & 1; - - return m_default[zbe][fge][tme][fst][iip]; -} - -// - -const GSVector4 GSDrawScanline::m_shift[4] = -{ - GSVector4(0.0f, 1.0f, 2.0f, 3.0f), - GSVector4(-1.0f, 0.0f, 1.0f, 2.0f), - GSVector4(-2.0f, -1.0f, 0.0f, 1.0f), - GSVector4(-3.0f, -2.0f, -1.0f, 0.0f), -}; - -const GSVector4i GSDrawScanline::m_test[8] = -{ - GSVector4i::zero(), - GSVector4i(0xffffffff, 0x00000000, 0x00000000, 0x00000000), - GSVector4i(0xffffffff, 0xffffffff, 0x00000000, 0x00000000), - GSVector4i(0xffffffff, 0xffffffff, 0xffffffff, 0x00000000), - GSVector4i(0x00000000, 0xffffffff, 0xffffffff, 0xffffffff), - GSVector4i(0x00000000, 0x00000000, 0xffffffff, 0xffffffff), - GSVector4i(0x00000000, 0x00000000, 0x00000000, 0xffffffff), - GSVector4i::zero(), -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSDrawScanline.h" +#include "GSTextureCacheSW.h" + +GSDrawScanline::GSDrawScanline(GSState* state, int id) + : m_state(state) + , m_id(id) +{ + memset(&m_env, 0, sizeof(m_env)); +} + +GSDrawScanline::~GSDrawScanline() +{ +} + +void GSDrawScanline::BeginDraw(const GSRasterizerData* data, Functions* f) +{ + GSDrawingEnvironment& env = m_state->m_env; + GSDrawingContext* context = m_state->m_context; + + const GSScanlineParam* p = (const GSScanlineParam*)data->param; + + m_env.sel = p->sel; + + m_env.vm = p->vm; + m_env.fbr = p->fbo->row; + m_env.zbr = p->zbo->row; + m_env.fbc = p->fbo->col; + m_env.zbc = p->zbo->col; + m_env.fzbr = p->fzbo->row; + m_env.fzbc = p->fzbo->col; + m_env.fm = GSVector4i(p->fm); + m_env.zm = GSVector4i(p->zm); + m_env.datm = context->TEST.DATM ? GSVector4i::x80000000() : GSVector4i::zero(); + m_env.colclamp = env.COLCLAMP.CLAMP ? GSVector4i::xffffffff() : GSVector4i::x00ff(); + m_env.fba = context->FBA.FBA ? GSVector4i::x80000000() : GSVector4i::zero(); + m_env.aref = GSVector4i((int)context->TEST.AREF); + m_env.afix = GSVector4i((int)context->ALPHA.FIX << 16); + m_env.afix2 = m_env.afix.yywwlh().sll16(7); + m_env.frb = GSVector4i((int)env.FOGCOL.ai32[0] & 0x00ff00ff); + m_env.fga = GSVector4i((int)(env.FOGCOL.ai32[0] >> 8) & 0x00ff00ff); + + if(m_env.sel.fpsm == 1) + { + m_env.fm |= GSVector4i::xff000000(); + } + else if(m_env.sel.fpsm == 2) + { + GSVector4i rb = m_env.fm & 0x00f800f8; + GSVector4i ga = m_env.fm & 0x8000f800; + + m_env.fm = (ga >> 16) | (rb >> 9) | (ga >> 6) | (rb >> 3) | GSVector4i::xffff0000(); + } + + if(m_env.sel.zpsm == 1) + { + m_env.zm |= GSVector4i::xff000000(); + } + else if(m_env.sel.zpsm == 2) + { + m_env.zm |= GSVector4i::xffff0000(); + } + + if(m_env.sel.atst == ATST_LESS) + { + m_env.sel.atst = ATST_LEQUAL; + + m_env.aref -= GSVector4i::x00000001(); + } + else if(m_env.sel.atst == ATST_GREATER) + { + m_env.sel.atst = ATST_GEQUAL; + + m_env.aref += GSVector4i::x00000001(); + } + + if(m_env.sel.tfx != TFX_NONE) + { + m_env.tex = p->tex; + m_env.clut = p->clut; + m_env.tw = p->tw; + + unsigned short tw = (unsigned short)(1 << context->TEX0.TW); + unsigned short th = (unsigned short)(1 << context->TEX0.TH); + + switch(context->CLAMP.WMS) + { + case CLAMP_REPEAT: + m_env.t.min.u16[0] = tw - 1; + m_env.t.max.u16[0] = 0; + m_env.t.mask.u32[0] = 0xffffffff; + break; + case CLAMP_CLAMP: + m_env.t.min.u16[0] = 0; + m_env.t.max.u16[0] = tw - 1; + m_env.t.mask.u32[0] = 0; + break; + case CLAMP_REGION_CLAMP: + m_env.t.min.u16[0] = min(context->CLAMP.MINU, tw - 1); + m_env.t.max.u16[0] = min(context->CLAMP.MAXU, tw - 1); + m_env.t.mask.u32[0] = 0; + break; + case CLAMP_REGION_REPEAT: + m_env.t.min.u16[0] = context->CLAMP.MINU; + m_env.t.max.u16[0] = context->CLAMP.MAXU; + m_env.t.mask.u32[0] = 0xffffffff; + break; + default: + __assume(0); + } + + switch(context->CLAMP.WMT) + { + case CLAMP_REPEAT: + m_env.t.min.u16[4] = th - 1; + m_env.t.max.u16[4] = 0; + m_env.t.mask.u32[2] = 0xffffffff; + break; + case CLAMP_CLAMP: + m_env.t.min.u16[4] = 0; + m_env.t.max.u16[4] = th - 1; + m_env.t.mask.u32[2] = 0; + break; + case CLAMP_REGION_CLAMP: + m_env.t.min.u16[4] = min(context->CLAMP.MINV, th - 1); + m_env.t.max.u16[4] = min(context->CLAMP.MAXV, th - 1); // ffx anima summon scene, when the anchor appears (th = 256, maxv > 256) + m_env.t.mask.u32[2] = 0; + break; + case CLAMP_REGION_REPEAT: + m_env.t.min.u16[4] = context->CLAMP.MINV; + m_env.t.max.u16[4] = context->CLAMP.MAXV; + m_env.t.mask.u32[2] = 0xffffffff; + break; + default: + __assume(0); + } + + m_env.t.min = m_env.t.min.xxxxlh(); + m_env.t.max = m_env.t.max.xxxxlh(); + m_env.t.mask = m_env.t.mask.xxzz(); + } + + // + + f->sl = m_ds.Lookup(m_env.sel); + + // + + if(m_env.sel.IsSolidRect()) + { + f->sr = (DrawSolidRectPtr)&GSDrawScanline::DrawSolidRect; + } + + // + + DWORD sel = 0; + + if(data->primclass != GS_POINT_CLASS) + { + sel |= (m_env.sel.ztst ? 1 : 0) << 0; + sel |= m_env.sel.fge << 1; + sel |= (m_env.sel.tfx != TFX_NONE ? 1 : 0) << 2; + sel |= m_env.sel.fst << 3; + sel |= m_env.sel.iip << 4; + } + + f->sp = m_sp.Lookup(sel); +} + +void GSDrawScanline::EndDraw(const GSRasterizerStats& stats) +{ + m_ds.UpdateStats(stats, m_state->m_perfmon.GetFrame()); +} + +template +void GSDrawScanline::SetupPrim(const GSVertexSW* vertices, const GSVertexSW& dscan) +{ + // p + + GSVector4 p = dscan.p; + + GSVector4 dz = p.zzzz(); + GSVector4 df = p.wwww(); + + if(zbe) + { + m_env.d4.z = dz * 4.0f; + } + + if(fge) + { + m_env.d4.f = GSVector4i(df * 4.0f).xxzzlh(); + } + + for(int i = 0; i < 4; i++) + { + GSVector4 v = m_shift[i]; + + if(zbe) + { + m_env.d[i].z = dz * v; + } + + if(fge) + { + m_env.d[i].f = GSVector4i(df * v).xxzzlh(); + } + } + + if(iip == 0) // should be sprite == 1, but close enough + { + GSVector4 p = vertices[0].p; + + if(zbe) + { + GSVector4 z = p.zzzz(); + + m_env.p.z = (GSVector4i(z * 0.5f) << 1) | (GSVector4i(z) & GSVector4i::x00000001()); + } + + if(fge) + { + m_env.p.f = GSVector4i(p).zzzzh().zzzz(); + } + } + + // t + + if(tme) + { + GSVector4 t = dscan.t; + + if(fst) + { + m_env.d4.st = GSVector4i(t * 4.0f); + + GSVector4 ds = t.xxxx(); + GSVector4 dt = t.yyyy(); + + for(int i = 0; i < 4; i++) + { + GSVector4 v = m_shift[i]; + + m_env.d[i].si = GSVector4i(ds * v); + m_env.d[i].ti = GSVector4i(dt * v); + } + } + else + { + m_env.d4.stq = t * 4.0f; + + GSVector4 ds = t.xxxx(); + GSVector4 dt = t.yyyy(); + GSVector4 dq = t.zzzz(); + + for(int i = 0; i < 4; i++) + { + GSVector4 v = m_shift[i]; + + m_env.d[i].s = ds * v; + m_env.d[i].t = dt * v; + m_env.d[i].q = dq * v; + } + } + } + + // c + + if(iip) + { + GSVector4 c = dscan.c; + + m_env.d4.c = GSVector4i(c * 4.0f).xzyw().ps32(); + + GSVector4 dr = c.xxxx(); + GSVector4 dg = c.yyyy(); + GSVector4 db = c.zzzz(); + GSVector4 da = c.wwww(); + + for(int i = 0; i < 4; i++) + { + GSVector4 v = m_shift[i]; + + GSVector4i rg = GSVector4i(dr * v).ps32(GSVector4i(dg * v)); + GSVector4i ba = GSVector4i(db * v).ps32(GSVector4i(da * v)); + + m_env.d[i].rb = rg.upl16(ba); + m_env.d[i].ga = rg.uph16(ba); + } + } + else + { + GSVector4i rgba = GSVector4i(vertices[0].c); + + GSVector4i rbga = rgba.upl16(rgba.zwxy()); + + if(tme == 0) + { + rbga = rbga.srl16(7); + + DWORD abe = m_env.sel.abe & 0x3f; // a, b, c + + DWORD abea = m_env.sel.abea; + DWORD abeb = m_env.sel.abeb; + DWORD abec = m_env.sel.abec; + DWORD abed = m_env.sel.abed; + + if(fge == 0 && abe != 0x3f && !(abe & 0x15) && abea != abeb) // 0x15 = 010101b => a, b, c != 1 + { + GSVector4i c[4]; + + c[0] = rbga; + c[1] = rgba.zzzzh().zzzz(); + c[2] = GSVector4i::zero(); + c[3] = m_env.afix2; + + GSVector4i cc = GSVector4i::lerp16<1>(c[abea], c[abeb], c[abec + 1]); + + if(abed == 0) + { + cc = cc.add16(c[0]); + } + + m_env.c2.rb = cc.xxxx(); + m_env.c2.ga = cc.zzzz().mix16(c[1].srl16(7)); + } + } + + m_env.c.rb = rbga.xxxx(); + m_env.c.ga = rbga.zzzz(); + } +} + +GSVector4i GSDrawScanline::Wrap(const GSVector4i& t) +{ + GSVector4i clamp = t.sat_i16(m_env.t.min, m_env.t.max); + GSVector4i repeat = (t & m_env.t.min) | m_env.t.max; + + return clamp.blend8(repeat, m_env.t.mask); +} + +void GSDrawScanline::SampleTexture(DWORD ltf, DWORD tlu, const GSVector4i& u, const GSVector4i& v, GSVector4i* c) +{ + const void* RESTRICT tex = m_env.tex; + const DWORD* RESTRICT clut = m_env.clut; + const DWORD tw = m_env.tw; + + GSVector4i uv = u.sra32(16).ps32(v.sra32(16)); + + GSVector4i c00, c01, c10, c11; + + if(ltf) + { + GSVector4i uf = u.xxzzlh().srl16(1); + GSVector4i vf = v.xxzzlh().srl16(1); + + GSVector4i uv0 = Wrap(uv); + GSVector4i uv1 = Wrap(uv.add16(GSVector4i::x0001())); + + GSVector4i y0 = uv0.uph16() << tw; + GSVector4i y1 = uv1.uph16() << tw; + GSVector4i x0 = uv0.upl16(); + GSVector4i x1 = uv1.upl16(); + + GSVector4i addr00 = y0 + x0; + GSVector4i addr01 = y0 + x1; + GSVector4i addr10 = y1 + x0; + GSVector4i addr11 = y1 + x1; + + if(tlu) + { + c00 = addr00.gather32_32((const BYTE*)tex, clut); + c01 = addr01.gather32_32((const BYTE*)tex, clut); + c10 = addr10.gather32_32((const BYTE*)tex, clut); + c11 = addr11.gather32_32((const BYTE*)tex, clut); + } + else + { + c00 = addr00.gather32_32((const DWORD*)tex); + c01 = addr01.gather32_32((const DWORD*)tex); + c10 = addr10.gather32_32((const DWORD*)tex); + c11 = addr11.gather32_32((const DWORD*)tex); + } + + GSVector4i mask = GSVector4i::x00ff(); + + GSVector4i rb00 = c00 & mask; + GSVector4i rb01 = c01 & mask; + GSVector4i rb10 = c10 & mask; + GSVector4i rb11 = c11 & mask; + + rb00 = rb00.lerp16<0>(rb01, uf); + rb10 = rb10.lerp16<0>(rb11, uf); + rb00 = rb00.lerp16<0>(rb10, vf); + + c[0] = rb00; + + GSVector4i ga00 = (c00 >> 8) & mask; + GSVector4i ga01 = (c01 >> 8) & mask; + GSVector4i ga10 = (c10 >> 8) & mask; + GSVector4i ga11 = (c11 >> 8) & mask; + + ga00 = ga00.lerp16<0>(ga01, uf); + ga10 = ga10.lerp16<0>(ga11, uf); + ga00 = ga00.lerp16<0>(ga10, vf); + + c[1] = ga00; + } + else + { + GSVector4i uv0 = Wrap(uv); + + GSVector4i addr00 = (uv0.uph16() << tw) + uv0.upl16(); + + if(tlu) + { + c00 = addr00.gather32_32((const BYTE*)tex, clut); + } + else + { + c00 = addr00.gather32_32((const DWORD*)tex); + } + + GSVector4i mask = GSVector4i::x00ff(); + + c[0] = c00 & mask; + c[1] = (c00 >> 8) & mask; + } +} + +void GSDrawScanline::ColorTFX(DWORD iip, DWORD tfx, const GSVector4i& rbf, const GSVector4i& gaf, GSVector4i& rbt, GSVector4i& gat) +{ + GSVector4i rb = iip ? rbf : m_env.c.rb; + GSVector4i ga = iip ? gaf : m_env.c.ga; + + GSVector4i af; + + switch(tfx) + { + case TFX_MODULATE: + rbt = rbt.modulate16<1>(rb).clamp8(); + break; + case TFX_DECAL: + break; + case TFX_HIGHLIGHT: + case TFX_HIGHLIGHT2: + af = ga.yywwlh().srl16(7); + rbt = rbt.modulate16<1>(rb).add16(af).clamp8(); + gat = gat.modulate16<1>(ga).add16(af).clamp8().mix16(gat); + break; + case TFX_NONE: + rbt = iip ? rb.srl16(7) : rb; + break; + default: + __assume(0); + } +} + +void GSDrawScanline::AlphaTFX(DWORD iip, DWORD tfx, DWORD tcc, const GSVector4i& gaf, GSVector4i& gat) +{ + GSVector4i ga = iip ? gaf : m_env.c.ga; + + switch(tfx) + { + case TFX_MODULATE: + gat = gat.modulate16<1>(ga).clamp8(); // mul16hrs rounds and breaks fogging in resident evil 4 (only modulate16<0> uses mul16hrs, but watch out) + if(!tcc) gat = gat.mix16(ga.srl16(7)); + break; + case TFX_DECAL: + break; + case TFX_HIGHLIGHT: + gat = gat.mix16(!tcc ? ga.srl16(7) : gat.addus8(ga.srl16(7))); + break; + case TFX_HIGHLIGHT2: + if(!tcc) gat = gat.mix16(ga.srl16(7)); + break; + case TFX_NONE: + gat = iip ? ga.srl16(7) : ga; + break; + default: + __assume(0); + } +} + +void GSDrawScanline::Fog(DWORD fge, const GSVector4i& f, GSVector4i& rb, GSVector4i& ga) +{ + if(fge) + { + rb = m_env.frb.lerp16<0>(rb, f); + ga = m_env.fga.lerp16<0>(ga, f).mix16(ga); + } +} + +bool GSDrawScanline::TestZ(DWORD zpsm, DWORD ztst, const GSVector4i& zs, const GSVector4i& zd, GSVector4i& test) +{ + if(ztst > 1) + { + GSVector4i o = GSVector4i::x80000000(zs); + + GSVector4i zso = zs - o; + GSVector4i zdo; + + switch(zpsm) + { + case 0: zdo = zd - o; break; + case 1: zdo = (zd & GSVector4i::x00ffffff(zs)) - o; break; + case 2: zdo = (zd & GSVector4i::x0000ffff(zs)) - o; break; + } + + switch(ztst) + { + case ZTST_GEQUAL: test |= zso < zdo; break; + case ZTST_GREATER: test |= zso <= zdo; break; + default: __assume(0); + } + + if(test.alltrue()) + { + return false; + } + } + + return true; +} + +bool GSDrawScanline::TestAlpha(DWORD atst, DWORD afail, const GSVector4i& ga, GSVector4i& fm, GSVector4i& zm, GSVector4i& test) +{ + if(atst != ATST_ALWAYS) + { + GSVector4i t; + + switch(atst) + { + case ATST_NEVER: t = GSVector4i::xffffffff(); break; + case ATST_ALWAYS: t = GSVector4i::zero(); break; + case ATST_LESS: + case ATST_LEQUAL: t = (ga >> 16) > m_env.aref; break; + case ATST_EQUAL: t = (ga >> 16) != m_env.aref; break; + case ATST_GEQUAL: + case ATST_GREATER: t = (ga >> 16) < m_env.aref; break; + case ATST_NOTEQUAL: t = (ga >> 16) == m_env.aref; break; + default: __assume(0); + } + + switch(afail) + { + case AFAIL_KEEP: + test |= t; + if(test.alltrue()) return false; + break; + case AFAIL_FB_ONLY: + zm |= t; + break; + case AFAIL_ZB_ONLY: + fm |= t; + break; + case AFAIL_RGB_ONLY: + fm |= t & GSVector4i::xff000000(); + zm |= t; + break; + default: + __assume(0); + } + } + + return true; +} + +bool GSDrawScanline::TestDestAlpha(DWORD fpsm, DWORD date, const GSVector4i& fd, GSVector4i& test) +{ + if(date) + { + switch(fpsm) + { + case 0: + test |= (fd ^ m_env.datm).sra32(31); + if(test.alltrue()) return false; + case 1: + break; + case 2: + test |= ((fd << 16) ^ m_env.datm).sra32(31); + if(test.alltrue()) return false; + case 3: + break; + default: + __assume(0); + } + } + + return true; +} + +void GSDrawScanline::ReadPixel(int psm, int addr, GSVector4i& c) const +{ + WORD* vm16 = (WORD*)m_env.vm; + + if(psm != 3) + { + c = GSVector4i::load(&vm16[addr], &vm16[addr + 8]); + } +} + +void GSDrawScanline::WritePixel(int psm, WORD* RESTRICT vm16, DWORD c) +{ + DWORD* RESTRICT vm32 = (DWORD*)vm16; + + switch(psm) + { + case 0: *vm32 = c; break; + case 1: *vm32 = (*vm32 & 0xff000000) | (c & 0x00ffffff); break; + case 2: *vm16 = (WORD)c; break; + } +} + +void GSDrawScanline::WriteFrame(int fpsm, int rfb, GSVector4i* c, const GSVector4i& fd, const GSVector4i& fm, int addr, int fzm) +{ + WORD* RESTRICT vm16 = (WORD*)m_env.vm; + + c[0] &= m_env.colclamp; + c[1] &= m_env.colclamp; + + GSVector4i fs = c[0].upl16(c[1]).pu16(c[0].uph16(c[1])); + + if(fpsm != 1) + { + fs |= m_env.fba; + } + + if(fpsm == 2) + { + GSVector4i rb = fs & 0x00f800f8; + GSVector4i ga = fs & 0x8000f800; + + fs = (ga >> 16) | (rb >> 9) | (ga >> 6) | (rb >> 3); + } + + if(rfb) + { + fs = fs.blend(fd, fm); + + if(fpsm < 2) + { + if(fzm & 0x03) GSVector4i::storel(&vm16[addr + 0], fs); + if(fzm & 0x0c) GSVector4i::storeh(&vm16[addr + 8], fs); + + return; + } + } + + if(fzm & 0x01) WritePixel(fpsm, &vm16[addr + 0], fs.extract32<0>()); + if(fzm & 0x02) WritePixel(fpsm, &vm16[addr + 2], fs.extract32<1>()); + if(fzm & 0x04) WritePixel(fpsm, &vm16[addr + 8], fs.extract32<2>()); + if(fzm & 0x08) WritePixel(fpsm, &vm16[addr + 10], fs.extract32<3>()); +} + +void GSDrawScanline::WriteZBuf(int zpsm, int ztst, const GSVector4i& z, const GSVector4i& zd, const GSVector4i& zm, int addr, int fzm) +{ + if(ztst == 0) return; + + WORD* RESTRICT vm16 = (WORD*)m_env.vm; + + GSVector4i zs = z; + + if(ztst > 1) + { + if(zpsm < 2) + { + zs = zs.blend8(zd, zm); + + if(fzm & 0x30) GSVector4i::storel(&vm16[addr + 0], zs); + if(fzm & 0xc0) GSVector4i::storeh(&vm16[addr + 8], zs); + + return; + } + } + + if(fzm & 0x10) WritePixel(zpsm, &vm16[addr + 0], zs.extract32<0>()); + if(fzm & 0x20) WritePixel(zpsm, &vm16[addr + 2], zs.extract32<1>()); + if(fzm & 0x40) WritePixel(zpsm, &vm16[addr + 8], zs.extract32<2>()); + if(fzm & 0x80) WritePixel(zpsm, &vm16[addr + 10], zs.extract32<3>()); +} + +template +void GSDrawScanline::DrawScanline(int top, int left, int right, const GSVertexSW& v) +{ + int skip = left & 3; + + left -= skip; + + int steps = right - left - 4; + + GSVector4i test = m_test[skip] | m_test[7 + (steps & (steps >> 31))]; + + // + + GSVector2i fza_base; + GSVector2i* fza_offset; + + GSVector4 z, s, t, q; + GSVector4i si, ti, f, rb, ga; + + // fza + + fza_base = m_env.fzbr[top]; + fza_offset = &m_env.fzbc[left >> 2]; + + // v.p + + GSVector4 vp = v.p; + + z = vp.zzzz() + m_env.d[skip].z; + f = GSVector4i(vp).zzzzh().zzzz().add16(m_env.d[skip].f); + + // v.t + + GSVector4 vt = v.t; + + if(m_env.sel.fst) + { + GSVector4i vti(vt); + + si = vti.xxxx() + m_env.d[skip].si; + ti = vti.yyyy() + m_env.d[skip].ti; + } + else + { + s = vt.xxxx() + m_env.d[skip].s; + t = vt.yyyy() + m_env.d[skip].t; + q = vt.zzzz() + m_env.d[skip].q; + } + + // v.c + + if(iip) + { + GSVector4i vc = GSVector4i(v.c); + + vc = vc.upl16(vc.zwxy()); + + rb = vc.xxxx().add16(m_env.d[skip].rb); + ga = vc.zzzz().add16(m_env.d[skip].ga); + } + + // + + while(1) + { + do + { + int fa = fza_base.x + fza_offset->x; + int za = fza_base.y + fza_offset->y; + + GSVector4i zs = (GSVector4i(z * 0.5f) << 1) | (GSVector4i(z) & GSVector4i::x00000001()); + GSVector4i zd; + + if(ztst > 1) + { + ReadPixel(zpsm, za, zd); + + if(!TestZ(zpsm, ztst, zs, zd, test)) + { + continue; + } + } + + GSVector4i c[6]; + + if(m_env.sel.tfx != TFX_NONE) + { + GSVector4i u, v; + + if(m_env.sel.fst) + { + u = si; + v = ti; + } + else + { + GSVector4 w = q.rcp(); + + u = GSVector4i(s * w); + v = GSVector4i(t * w); + + if(m_env.sel.ltf) + { + u -= 0x8000; + v -= 0x8000; + } + } + + SampleTexture(m_env.sel.ltf, m_env.sel.tlu, u, v, c); + } + + AlphaTFX(iip, m_env.sel.tfx, m_env.sel.tcc, ga, c[1]); + + GSVector4i fm = m_env.fm; + GSVector4i zm = m_env.zm; + + if(!TestAlpha(m_env.sel.atst, m_env.sel.afail, c[1], fm, zm, test)) + { + continue; + } + + ColorTFX(iip, m_env.sel.tfx, rb, ga, c[0], c[1]); + + Fog(m_env.sel.fge, f, c[0], c[1]); + + GSVector4i fd; + + if(m_env.sel.rfb) + { + ReadPixel(fpsm, fa, fd); + + if(!TestDestAlpha(fpsm, m_env.sel.date, fd, test)) + { + continue; + } + } + + fm |= test; + zm |= test; + + int fzm = ~(fm == GSVector4i::xffffffff()).ps32(zm == GSVector4i::xffffffff()).ps32().mask(); + + WriteZBuf(zpsm, ztst, zs, zd, zm, za, fzm); + + if(m_env.sel.abe != 255) + { + GSVector4i mask = GSVector4i::x00ff(fd); + + switch(fpsm) + { + case 0: + c[2] = fd & mask; + c[3] = (fd >> 8) & mask; + break; + case 1: + c[2] = fd & mask; + c[3] = (fd >> 8) & mask; + c[3] = c[3].mix16(GSVector4i(0x00800000)); + break; + case 2: + c[2] = ((fd & 0x7c00) << 9) | ((fd & 0x001f) << 3); + c[3] = ((fd & 0x8000) << 8) | ((fd & 0x03e0) >> 2); + break; + } + + c[4] = GSVector4::zero(); + c[5] = m_env.afix; + + DWORD abea = m_env.sel.abea; + DWORD abeb = m_env.sel.abeb; + DWORD abec = m_env.sel.abec; + DWORD abed = m_env.sel.abed; + + GSVector4i a = c[abec * 2 + 1].yywwlh().sll16(7); + + GSVector4i rb = GSVector4i::lerp16<1>(c[abea * 2 + 0], c[abeb * 2 + 0], a, c[abed * 2 + 0]); + GSVector4i ga = GSVector4i::lerp16<1>(c[abea * 2 + 1], c[abeb * 2 + 1], a, c[abed * 2 + 1]); + + if(m_env.sel.pabe) + { + mask = (c[1] << 8).sra32(31); + + rb = c[0].blend8(rb, mask); + ga = c[1].blend8(ga, mask); + } + + c[0] = rb; + c[1] = ga.mix16(c[1]); + } + + WriteFrame(fpsm, m_env.sel.rfb, c, fd, fm, fa, fzm); + } + while(0); + + if(steps <= 0) break; + + steps -= 4; + + test = m_test[7 + (steps & (steps >> 31))]; + + fza_offset++; + + z += m_env.d4.z; + f = f.add16(m_env.d4.f); + + if(m_env.sel.fst) + { + GSVector4i st = m_env.d4.st; + + si += st.xxxx(); + ti += st.yyyy(); + } + else + { + GSVector4 stq = m_env.d4.stq; + + s += stq.xxxx(); + t += stq.yyyy(); + q += stq.zzzz(); + } + + if(iip) + { + GSVector4i c = m_env.d4.c; + + rb = rb.add16(c.xxxx()); + ga = ga.add16(c.yyyy()); + } + } +} + +template +void GSDrawScanline::DrawScanlineEx(int top, int left, int right, const GSVertexSW& v) +{ + const DWORD fpsm = (sel >> 0) & 3; + const DWORD zpsm = (sel >> 2) & 3; + const DWORD ztst = (sel >> 4) & 3; + const DWORD atst = (sel >> 6) & 7; + const DWORD afail = (sel >> 9) & 3; + const DWORD iip = (sel >> 11) & 1; + const DWORD tfx = (sel >> 12) & 7; + const DWORD tcc = (sel >> 15) & 1; + const DWORD fst = (sel >> 16) & 1; + const DWORD ltf = (sel >> 17) & 1; + const DWORD tlu = (sel >> 18) & 1; + const DWORD fge = (sel >> 19) & 1; + const DWORD date = (sel >> 20) & 1; + const DWORD abe = (sel >> 21) & 255; + const DWORD abea = (sel >> 21) & 3; + const DWORD abeb = (sel >> 23) & 3; + const DWORD abec = (sel >> 25) & 3; + const DWORD abed = (sel >> 27) & 3; + const DWORD pabe = (sel >> 29) & 1; + const DWORD rfb = (sel >> 30) & 1; + const DWORD sprite = (sel >> 31) & 1; + + // + + int skip = left & 3; + + left -= skip; + + int steps = right - left - 4; + + GSVector4i test = m_test[skip] | m_test[7 + (steps & (steps >> 31))]; + + // + + GSVector2i fza_base; + GSVector2i* fza_offset; + + GSVector4 z, s, t, q; + GSVector4i zi, si, ti, f, rb, ga; + + // fza + + fza_base = m_env.fzbr[top]; + fza_offset = &m_env.fzbc[left >> 2]; + + // v.p + + GSVector4 vp = v.p; + + if(sprite) + { + zi = m_env.p.z; + f = m_env.p.f; + } + else + { + z = vp.zzzz() + m_env.d[skip].z; + f = GSVector4i(vp).zzzzh().zzzz().add16(m_env.d[skip].f); + } + + // v.t + + GSVector4 vt = v.t; + + if(fst) + { + GSVector4i vti(vt); + + si = vti.xxxx(); + ti = vti.yyyy(); + + si += m_env.d[skip].si; + if(!sprite) ti += m_env.d[skip].ti; + } + else + { + s = vt.xxxx() + m_env.d[skip].s; + t = vt.yyyy() + m_env.d[skip].t; + q = vt.zzzz() + m_env.d[skip].q; + } + + // v.c + + if(iip) + { + GSVector4i vc = GSVector4i(v.c); + + vc = vc.upl16(vc.zwxy()); + + rb = vc.xxxx().add16(m_env.d[skip].rb); + ga = vc.zzzz().add16(m_env.d[skip].ga); + } + + // + + while(1) + { + do + { + int fa = fza_base.x + fza_offset->x; + int za = fza_base.y + fza_offset->y; + + GSVector4i zs = sprite ? zi : (GSVector4i(z * 0.5f) << 1) | (GSVector4i(z) & GSVector4i::x00000001()); + GSVector4i zd; + + if(ztst > 1) + { + ReadPixel(zpsm, za, zd); + + if(!TestZ(zpsm, ztst, zs, zd, test)) + { + continue; + } + } + + GSVector4i c[6]; + + if(tfx != TFX_NONE) + { + GSVector4i u, v; + + if(fst) + { + u = si; + v = ti; + } + else + { + GSVector4 w = q.rcp(); + + u = GSVector4i(s * w); + v = GSVector4i(t * w); + + if(ltf) + { + u -= 0x8000; + v -= 0x8000; + } + } + + SampleTexture(ltf, tlu, u, v, c); + } + + AlphaTFX(iip, tfx, tcc, ga, c[1]); + + GSVector4i fm = m_env.fm; + GSVector4i zm = m_env.zm; + + if(!TestAlpha(atst, afail, c[1], fm, zm, test)) + { + continue; + } + + ColorTFX(iip, tfx, rb, ga, c[0], c[1]); + + Fog(fge, f, c[0], c[1]); + + GSVector4i fd; + + if(rfb) + { + ReadPixel(fpsm, fa, fd); + + if(!TestDestAlpha(fpsm, date, fd, test)) + { + continue; + } + } + + fm |= test; + zm |= test; + + int fzm = ~(fm == GSVector4i::xffffffff()).ps32(zm == GSVector4i::xffffffff()).ps32().mask(); + + WriteZBuf(zpsm, ztst, zs, zd, zm, za, fzm); + + if(abe != 255) + { + GSVector4i mask = GSVector4i::x00ff(fd); + + switch(fpsm) + { + case 0: + case 1: + c[2] = fd & mask; + c[3] = (fd >> 8) & mask; + break; + case 2: + c[2] = ((fd & 0x7c00) << 9) | ((fd & 0x001f) << 3); + c[3] = ((fd & 0x8000) << 8) | ((fd & 0x03e0) >> 2); + break; + } + + c[4] = GSVector4::zero(); + c[5] = GSVector4::zero(); + + GSVector4i rb, ga; + + if(tfx == TFX_NONE && fge == 0 && abea != 1 && abeb != 1 && abec != 1 && abea != abeb) + { + c[0] = m_env.c2.rb; + c[1] = m_env.c2.ga; + + rb = c[0]; + ga = c[1]; + + if(abed == 1) + { + rb = rb.add16(c[2]); + ga = ga.add16(c[3]); + } + } + else + { + if(abea != abeb) + { + rb = c[abea * 2 + 0]; + ga = c[abea * 2 + 1]; + + if(abeb < 2) + { + rb = rb.sub16(c[abeb * 2 + 0]); + ga = ga.sub16(c[abeb * 2 + 1]); + } + + if(!(fpsm == 1 && abec == 1)) + { + GSVector4i a = abec < 2 ? c[abec * 2 + 1].yywwlh().sll16(7) : m_env.afix2; + + rb = rb.modulate16<1>(a); + ga = ga.modulate16<1>(a); + } + + if(abed < 2) + { + rb = rb.add16(c[abed * 2 + 0]); + ga = ga.add16(c[abed * 2 + 1]); + } + } + else + { + rb = c[abed * 2 + 0]; + ga = c[abed * 2 + 1]; + } + } + + if(pabe) + { + mask = (c[1] << 8).sra32(31); + + rb = c[0].blend8(rb, mask); + ga = c[1].blend8(ga, mask); + } + + c[0] = rb; + c[1] = ga.mix16(c[1]); + } + + WriteFrame(fpsm, rfb, c, fd, fm, fa, fzm); + } + while(0); + + if(steps <= 0) break; + + steps -= 4; + + test = m_test[7 + (steps & (steps >> 31))]; + + fza_offset++; + + if(!sprite) + { + z += m_env.d4.z; + f = f.add16(m_env.d4.f); + } + + if(fst) + { + GSVector4i st = m_env.d4.st; + + si += st.xxxx(); + if(!sprite) ti += st.yyyy(); + } + else + { + GSVector4 stq = m_env.d4.stq; + + s += stq.xxxx(); + t += stq.yyyy(); + q += stq.zzzz(); + } + + if(iip) + { + GSVector4i c = m_env.d4.c; + + rb = rb.add16(c.xxxx()); + ga = ga.add16(c.yyyy()); + } + } +} + +void GSDrawScanline::DrawSolidRect(const GSVector4i& r, const GSVertexSW& v) +{ +/* +static FILE* s_fp = NULL; +if(!s_fp) s_fp = fopen("c:\\log2.txt", "w"); +__int64 start = __rdtsc(); +int size = (r.z - r.x) * (r.w - r.y); +*/ + ASSERT(r.y >= 0); + ASSERT(r.w >= 0); + + // FIXME: sometimes the frame and z buffer may overlap, the outcome is undefined + + DWORD m; + + m = m_env.zm.u32[0]; + + if(m != 0xffffffff) + { + DWORD z = (DWORD)(float)v.p.z; + + if(m_env.sel.zpsm != 2) + { + if(m == 0) + { + DrawSolidRectT(m_env.zbr, m_env.zbc[0], r, z, m); + } + else + { + DrawSolidRectT(m_env.zbr, m_env.zbc[0], r, z, m); + } + } + else + { + if(m == 0) + { + DrawSolidRectT(m_env.zbr, m_env.zbc[0], r, z, m); + } + else + { + DrawSolidRectT(m_env.zbr, m_env.zbc[0], r, z, m); + } + } + } + + m = m_env.fm.u32[0]; + + if(m != 0xffffffff) + { + DWORD c = (GSVector4i(v.c) >> 7).rgba32(); + + if(m_state->m_context->FBA.FBA) + { + c |= 0x80000000; + } + + if(m_env.sel.fpsm != 2) + { + if(m == 0) + { + DrawSolidRectT(m_env.fbr, m_env.fbc[0], r, c, m); + } + else + { + DrawSolidRectT(m_env.fbr, m_env.fbc[0], r, c, m); + } + } + else + { + c = ((c & 0xf8) >> 3) | ((c & 0xf800) >> 6) | ((c & 0xf80000) >> 9) | ((c & 0x80000000) >> 16); + + if(m == 0) + { + DrawSolidRectT(m_env.fbr, m_env.fbc[0], r, c, m); + } + else + { + DrawSolidRectT(m_env.fbr, m_env.fbc[0], r, c, m); + } + } + } +/* +__int64 stop = __rdtsc(); +fprintf(s_fp, "%I64d => %I64d = %I64d (%d,%d - %d,%d) %d\n", start, stop, stop - start, r.x, r.y, r.z, r.w, size); +*/ +} + +template +void GSDrawScanline::DrawSolidRectT(const GSVector4i* row, int* col, const GSVector4i& r, DWORD c, DWORD m) +{ + if(m == 0xffffffff) return; + + GSVector4i color((int)c); + GSVector4i mask((int)m); + + if(sizeof(T) == sizeof(WORD)) + { + color = color.xxzzlh(); + mask = mask.xxzzlh(); + } + + color = color.andnot(mask); + + GSVector4i bm(8 * 4 / sizeof(T) - 1, 8 - 1); + GSVector4i br = (r + bm).andnot(bm.xyxy()); + + FillRect(row, col, GSVector4i(r.x, r.y, r.z, br.y), c, m); + FillRect(row, col, GSVector4i(r.x, br.w, r.z, r.w), c, m); + + if(r.x < br.x || br.z < r.z) + { + FillRect(row, col, GSVector4i(r.x, br.y, br.x, br.w), c, m); + FillRect(row, col, GSVector4i(br.z, br.y, r.z, br.w), c, m); + } + + FillBlock(row, col, br, color, mask); +} + +template +void GSDrawScanline::FillRect(const GSVector4i* row, int* col, const GSVector4i& r, DWORD c, DWORD m) +{ + if(r.x >= r.z) return; + + for(int y = r.y; y < r.w; y++) + { + DWORD base = row[y].x; + + for(int x = r.x; x < r.z; x++) + { + T* p = &((T*)m_env.vm)[base + col[x]]; + + *p = (T)(!masked ? c : (c | (*p & m))); + } + } +} + +template +void GSDrawScanline::FillBlock(const GSVector4i* row, int* col, const GSVector4i& r, const GSVector4i& c, const GSVector4i& m) +{ + if(r.x >= r.z) return; + + for(int y = r.y; y < r.w; y += 8) + { + DWORD base = row[y].x; + + for(int x = r.x; x < r.z; x += 8 * 4 / sizeof(T)) + { + GSVector4i* p = (GSVector4i*)&((T*)m_env.vm)[base + col[x]]; + + for(int i = 0; i < 16; i += 4) + { + p[i + 0] = !masked ? c : (c | (p[i + 0] & m)); + p[i + 1] = !masked ? c : (c | (p[i + 1] & m)); + p[i + 2] = !masked ? c : (c | (p[i + 2] & m)); + p[i + 3] = !masked ? c : (c | (p[i + 3] & m)); + } + } + } +} + +// + +GSDrawScanline::GSDrawScanlineMap::GSDrawScanlineMap() +{ + // w00t :P + + #define InitDS_IIP(fpsm, zpsm, ztst, iip) \ + m_default[fpsm][zpsm][ztst][iip] = (DrawScanlinePtr)&GSDrawScanline::DrawScanline; \ + + #define InitDS_ZTST(fpsm, zpsm, ztst) \ + InitDS_IIP(fpsm, zpsm, ztst, 0) \ + InitDS_IIP(fpsm, zpsm, ztst, 1) \ + + #define InitDS(fpsm, zpsm) \ + InitDS_ZTST(fpsm, zpsm, 0) \ + InitDS_ZTST(fpsm, zpsm, 1) \ + InitDS_ZTST(fpsm, zpsm, 2) \ + InitDS_ZTST(fpsm, zpsm, 3) \ + + InitDS(0, 0); + InitDS(0, 1); + InitDS(0, 2); + InitDS(0, 3); + InitDS(1, 0); + InitDS(1, 1); + InitDS(1, 2); + InitDS(1, 3); + InitDS(2, 0); + InitDS(2, 1); + InitDS(2, 2); + InitDS(2, 3); + InitDS(3, 0); + InitDS(3, 1); + InitDS(3, 2); + + #define InitDS_Sel(sel) \ + SetAt(sel, (DrawScanlinePtr)&GSDrawScanline::DrawScanlineEx<##sel##>); + + #ifdef FAST_DRAWSCANLINE + + // bios + + InitDS_Sel(0x1fe04850); // 8.99% + InitDS_Sel(0x1fe28870); // 26.46% + InitDS_Sel(0x1fe38050); // 12.95% + InitDS_Sel(0x1fe38060); // 8.59% + InitDS_Sel(0x48428050); // 8.86% + InitDS_Sel(0x48428060); // 6.30% + InitDS_Sel(0x48804860); // 28.07% + InitDS_Sel(0x49028060); // 6.31% + InitDS_Sel(0x4902904c); // 5.46% + InitDS_Sel(0x4b02804c); // 5.11% + InitDS_Sel(0x4c804050); // 9.08% + InitDS_Sel(0x4d038864); // 114.89% + InitDS_Sel(0x9fe39064); // 14.72% + InitDS_Sel(0xc8804050); // 8.58% + InitDS_Sel(0xc9004050); // 8.69% + InitDS_Sel(0xc9039050); // 17.17% + InitDS_Sel(0xcc804050); // 8.16% + InitDS_Sel(0xcd019050); // 85.40% + + // ffx + + InitDS_Sel(0x11020865); // 9.81% + InitDS_Sel(0x1fe68875); // 9.90% + InitDS_Sel(0x1fe69075); // 15.13% + InitDS_Sel(0x1fe84075); // 5.16% + InitDS_Sel(0x1fee8075); // 5.98% + InitDS_Sel(0x1fee8875); // 43.94% + InitDS_Sel(0x1fee8876); // 22.75% + InitDS_Sel(0x1fee8975); // 5.70% + InitDS_Sel(0x48404865); // 20.31% + InitDS_Sel(0x48468865); // 8.18% + InitDS_Sel(0x48478065); // 17.47% + InitDS_Sel(0x48820965); // 7.89% + InitDS_Sel(0x48830875); // 5.84% + InitDS_Sel(0x48868865); // 5.44% + InitDS_Sel(0x48868965); // 9.13% + InitDS_Sel(0x48878165); // 28.27% + InitDS_Sel(0x488f89f5); // 20.19% + InitDS_Sel(0x488f89f6); // 27.92% + InitDS_Sel(0x49068065); // 7.68% + InitDS_Sel(0x49068865); // 20.15% + InitDS_Sel(0x49068965); // 8.65% + InitDS_Sel(0x49078065); // 14.00% + InitDS_Sel(0x49078165); // 5.63% + InitDS_Sel(0xc883004d); // 22.42% + InitDS_Sel(0xc887814d); // 9.20% + InitDS_Sel(0xc8878165); // 71.18% + InitDS_Sel(0xc8879065); // 26.05% + InitDS_Sel(0xc887914d); // 8.40% + InitDS_Sel(0xc88791e5); // 82.67% + InitDS_Sel(0xc9078065); // 8.00% + InitDS_Sel(0xcc819055); // 14.54% + InitDS_Sel(0xcc839065); // 7.41% + InitDS_Sel(0xd5204055); // 34.58% + InitDS_Sel(0x48804855); // 11.77% + InitDS_Sel(0x48804865); // 12.94% + InitDS_Sel(0x488e8965); // 5.04% + InitDS_Sel(0x49004875); // 11.36% + InitDS_Sel(0x9100404d); // 8.54% + InitDS_Sel(0x9fe78075); // 18.54% + InitDS_Sel(0x9fe78155); // 13.08% + InitDS_Sel(0xcd078075); // 9.47% + + // ffx-2 + + InitDS_Sel(0x110a8965); // 17.40% + InitDS_Sel(0x1fe30069); // 17.38% + InitDS_Sel(0x1fe5884d); // 11.56% + InitDS_Sel(0x48468965); // 79.89% + InitDS_Sel(0x4881884d); // 5.61% + InitDS_Sel(0x488781f5); // 5.84% + InitDS_Sel(0x4890404c); // 108.44% + InitDS_Sel(0x4893084c); // 24.74% + InitDS_Sel(0x49004859); // 48.72% + InitDS_Sel(0x49004865); // 13.08% + InitDS_Sel(0x49004869); // 22.94% + InitDS_Sel(0x4900494d); // 470.30% + InitDS_Sel(0x4907814d); // 14.15% + InitDS_Sel(0x49078865); // 21.56% + InitDS_Sel(0x49078965); // 11.37% + InitDS_Sel(0x490e8165); // 15.52% + InitDS_Sel(0xc8478165); // 10.44% + InitDS_Sel(0xc8804055); // 36.58% + InitDS_Sel(0xc881004d); // 13.53% + InitDS_Sel(0xc8830055); // 23.97% + InitDS_Sel(0xc885004d); // 14.32% + InitDS_Sel(0xc893004c); // 136.83% + InitDS_Sel(0xc895004c); // 16.48% + InitDS_Sel(0xc9004055); // 13.92% + InitDS_Sel(0xc9004059); // 15.87% + InitDS_Sel(0xc9004065); // 18.61% + InitDS_Sel(0xc9059155); // 13.56% + InitDS_Sel(0xc907814d); // 15.06% + InitDS_Sel(0xc9078165); // 12.21% + InitDS_Sel(0xcc804055); // 16.51% + InitDS_Sel(0xcc850055); // 17.01% + InitDS_Sel(0xc88581cd); // 7.32% + InitDS_Sel(0xc88581e5); // 5.41% + + // ffxii + + InitDS_Sel(0x1fe6804c); // 9.05% + InitDS_Sel(0x1fe68064); // 5.11% + InitDS_Sel(0x1fe6884c); // 14.58% + InitDS_Sel(0x1fee8864); // 88.41% + InitDS_Sel(0x1fee8964); // 33.72% + InitDS_Sel(0x48404064); // 30.72% + InitDS_Sel(0x4847004c); // 17.41% + InitDS_Sel(0x48828864); // 6.06% + InitDS_Sel(0x4883004c); // 20.10% + InitDS_Sel(0x4883084c); // 12.37% + InitDS_Sel(0x4886804c); // 5.10% + InitDS_Sel(0x4887084c); // 226.61% + InitDS_Sel(0x48878064); // 7.39% + InitDS_Sel(0x488e8b64); // 16.26% + InitDS_Sel(0x48904064); // 29.47% + InitDS_Sel(0x49004064); // 9.31% + InitDS_Sel(0x49078064); // 28.77% + InitDS_Sel(0x5fe0404c); // 70.30% + InitDS_Sel(0x9fe3904c); // 10.16% + InitDS_Sel(0xc887004c); // 18.63% + InitDS_Sel(0xc8878064); // 19.71% + InitDS_Sel(0xc887904c); // 13.03% + InitDS_Sel(0xc9278064); // 39.54% + + // kingdom hearts + + InitDS_Sel(0x4840404c); // 15.00% + InitDS_Sel(0x48830874); // 14.41% + InitDS_Sel(0x48868154); // 7.22% + InitDS_Sel(0x4886884c); // 28.13% + InitDS_Sel(0x4886904c); // 16.66% + InitDS_Sel(0x490e8974); // 59.46% + InitDS_Sel(0xc8818054); // 13.73% + InitDS_Sel(0xc8858054); // 11.63% + InitDS_Sel(0xc9004054); // 14.66% + + // kingdom hearts 2 + + InitDS_Sel(0x48804060); // 19.75% + InitDS_Sel(0x488a8964); // 20.35% + InitDS_Sel(0x9fe39054); // 16.04% + InitDS_Sel(0xc8810054); // 28.27% + InitDS_Sel(0xcc83004d); // 53.63% + InitDS_Sel(0xcd03004d); // 20.55% + + // persona 3 + + InitDS_Sel(0x484e8068); // 29.91% + InitDS_Sel(0x4881804c); // 18.16% + InitDS_Sel(0x4881904c); // 24.90% + InitDS_Sel(0x490e8068); // 5.82% + InitDS_Sel(0x4b07904c); // 59.21% + InitDS_Sel(0x4d47834c); // 29.42% + InitDS_Sel(0x4d47934c); // 27.37% + InitDS_Sel(0xca43004c); // 17.88% + InitDS_Sel(0xcb07934c); // 11.38% + InitDS_Sel(0xcd47804c); // 106.54% + InitDS_Sel(0xcd47834c); // 104.37% + + // persona 4 + + InitDS_Sel(0x1fe04058); // 23.41% + InitDS_Sel(0x4840484c); // 24.66% + InitDS_Sel(0x4881834c); // 21.87% + InitDS_Sel(0x4881934c); // 21.68% + InitDS_Sel(0x48828368); // 9.84% + InitDS_Sel(0x48868f68); // 29.84% + InitDS_Sel(0x48879168); // 5.74% + InitDS_Sel(0x49068868); // 18.43% + InitDS_Sel(0x49078068); // 63.62% + InitDS_Sel(0x49079068); // 57.82% + InitDS_Sel(0x490e8868); // 22.88% + InitDS_Sel(0x4a47804c); // 68.03% + InitDS_Sel(0x4a47904c); // 20.99% + InitDS_Sel(0x4a80404c); // 190.06% + InitDS_Sel(0x4a83004c); // 25.28% + InitDS_Sel(0x4a87804c); // 26.31% + InitDS_Sel(0x4a878068); // 29.36% + InitDS_Sel(0x4a878868); // 23.13% + InitDS_Sel(0x4a879068); // 11.16% + InitDS_Sel(0x4b00404c); // 111.77% + InitDS_Sel(0x4b07804c); // 23.00% + InitDS_Sel(0x4b07884c); // 21.15% + InitDS_Sel(0x5fe04058); // 37.01% + InitDS_Sel(0x5fe04858); // 87.23% + + // sfex3 + + InitDS_Sel(0x1fe04868); // 8.37% + InitDS_Sel(0x1fe6b068); // 16.21% + InitDS_Sel(0x1fe6b868); // 6.50% + InitDS_Sel(0x41268068); // 8.16% + InitDS_Sel(0x41269068); // 9.51% + InitDS_Sel(0x4886b068); // 20.50% + InitDS_Sel(0x4886b868); // 35.05% + InitDS_Sel(0x49079078); // 6.90% + InitDS_Sel(0x4c868068); // 5.48% + InitDS_Sel(0x4c868868); // 6.05% + InitDS_Sel(0x9fe1004e); // 6.98% + InitDS_Sel(0x9fe3004e); // 13.33% + InitDS_Sel(0xc8859058); // 10.74% + InitDS_Sel(0xcc804058); // 8.15% + InitDS_Sel(0xcd404058); // 5.04% + + // gt4 + + InitDS_Sel(0x1fee8164); // 7.38% + InitDS_Sel(0x488e8f64); // 7.09% + InitDS_Sel(0x488e9764); // 31.70% + InitDS_Sel(0x4b1a8864); // 5.45% + InitDS_Sel(0x5fe3904e); // 8.54% + + // katamary damacy + + InitDS_Sel(0x488e89e4); // 10.50% + InitDS_Sel(0x488e91d4); // 18.22% + InitDS_Sel(0xc88181cc); // 7.69% + InitDS_Sel(0xc8904054); // 12.39% + + // grandia 3 + + InitDS_Sel(0x1fe0404e); // 7.99% + InitDS_Sel(0x48868360); // 5.62% + InitDS_Sel(0x48868860); // 8.40% + InitDS_Sel(0x48869360); // 7.19% + InitDS_Sel(0x4887884c); // 5.93% + InitDS_Sel(0x488a8060); // 12.82% + InitDS_Sel(0x488e8360); // 26.69% + InitDS_Sel(0x488e8b60); // 32.33% + InitDS_Sel(0x488e8f60); // 15.38% + InitDS_Sel(0x488e9060); // 7.52% + InitDS_Sel(0x50368060); // 9.24% + InitDS_Sel(0xc8878070); // 37.81% + InitDS_Sel(0xcc81804c); // 46.79% + InitDS_Sel(0xcc839060); // 55.67% + + // rumble roses + + InitDS_Sel(0x1fe78064); // 26.70% + InitDS_Sel(0x1fe79064); // 9.93% + InitDS_Sel(0x4880484c); // 6.38% + InitDS_Sel(0x48838164); // 11.01% + InitDS_Sel(0x4887b864); // 35.30% + InitDS_Sel(0x488e8164); // 5.23% + InitDS_Sel(0x4900484c); // 8.86% + InitDS_Sel(0x49078864); // 7.98% + InitDS_Sel(0x490e8964); // 8.26% + InitDS_Sel(0x9fe3004d); // 8.92% + InitDS_Sel(0xc8838164); // 14.00% + InitDS_Sel(0xc8878164); // 15.96% + InitDS_Sel(0xcc830064); // 35.39% + + // dmc + + InitDS_Sel(0x4423904c); // 7.89% + InitDS_Sel(0x4427904c); // 17.05% + InitDS_Sel(0x45204078); // 9.08% + InitDS_Sel(0x4c87914c); // 40.48% + InitDS_Sel(0x54204078); // 9.09% + InitDS_Sel(0x9fe39058); // 7.17% + InitDS_Sel(0x9fe78068); // 9.28% + InitDS_Sel(0xc427904c); // 8.30% + InitDS_Sel(0xc520404c); // 8.11% + InitDS_Sel(0xc8804078); // 6.11% + InitDS_Sel(0xc8810068); // 7.80% + InitDS_Sel(0xc8830068); // 10.05% + InitDS_Sel(0xcc43804c); // 17.32% + InitDS_Sel(0xd420404c); // 8.03% + + // xenosaga 2 + + InitDS_Sel(0x1fee804c); // 15.39% + InitDS_Sel(0x49079064); // 31.08% + InitDS_Sel(0x51229064); // 8.86% + InitDS_Sel(0xc8804074); // 16.71% + InitDS_Sel(0xc9079054); // 17.35% + InitDS_Sel(0xcc804054); // 14.57% + InitDS_Sel(0xcc839054); // 24.04% + InitDS_Sel(0xcd004054); // 14.54% + + // nfs mw + + InitDS_Sel(0x1fe68068); // 18.10% + InitDS_Sel(0x1fe6806a); // 6.75% + InitDS_Sel(0x1fe68164); // 5.78% + InitDS_Sel(0x1fe68868); // 117.99% + InitDS_Sel(0x1fe68964); // 48.41% + InitDS_Sel(0x4883804e); // 7.16% + InitDS_Sel(0x48868868); // 46.01% + InitDS_Sel(0x4b004064); // 22.82% + InitDS_Sel(0x4b004068); // 33.12% + InitDS_Sel(0x4b004864); // 21.73% + InitDS_Sel(0x4b004868); // 37.86% + InitDS_Sel(0x4b028064); // 20.96% + InitDS_Sel(0x4b028068); // 30.53% + InitDS_Sel(0x4b028864); // 24.64% + InitDS_Sel(0x4b028868); // 31.04% + InitDS_Sel(0x4b038064); // 13.05% + InitDS_Sel(0xc805904c); // 17.04% + InitDS_Sel(0xc9078064); // 13.78% + InitDS_Sel(0xc927904c); // 18.78% + InitDS_Sel(0xcc83004c); // 5.32% + InitDS_Sel(0xcc83804c); // 19.33% + InitDS_Sel(0xcc83804e); // 5.85% + InitDS_Sel(0xcd03914c); // 12.00% + InitDS_Sel(0xd127904c); // 18.81% + InitDS_Sel(0xdfe19064); // 27.63% + + // berserk + + InitDS_Sel(0x48804064); // 41.22% + InitDS_Sel(0x48878864); // 41.61% + InitDS_Sel(0x488e8064); // 32.85% + InitDS_Sel(0x488e8964); // 33.35% + InitDS_Sel(0x49004874); // 10.91% + InitDS_Sel(0x4c8e8864); // 11.27% + InitDS_Sel(0x4c8fb864); // 5.61% + InitDS_Sel(0xc8804064); // 14.54% + InitDS_Sel(0xc8830064); // 24.60% + InitDS_Sel(0xcd03004c); // 31.16% + InitDS_Sel(0xdfe3004c); // 7.40% + InitDS_Sel(0xdfe3904c); // 18.00% + + // castlevania + + InitDS_Sel(0x1fe78868); // 19.07% + InitDS_Sel(0x48878868); // 85.08% + InitDS_Sel(0x4d00407a); // 17.23% + InitDS_Sel(0x9fe1004c); // 9.10% + InitDS_Sel(0x9fe3904e); // 16.38% + InitDS_Sel(0x9fe5904c); // 11.74% + InitDS_Sel(0xc8804068); // 13.17% + InitDS_Sel(0xc881004e); // 17.78% + InitDS_Sel(0xca80404c); // 8.43% + InitDS_Sel(0xdfe3804c); // 17.00% + + // okami + + InitDS_Sel(0x48804058); // 10.29% + InitDS_Sel(0x48878058); // 11.71% + InitDS_Sel(0x48878168); // 250.79% + InitDS_Sel(0x488e8068); // 20.22% + InitDS_Sel(0x488e8868); // 32.58% + InitDS_Sel(0x488e8968); // 29.40% + InitDS_Sel(0x49078168); // 13.87% + InitDS_Sel(0x9fe18058); // 10.94% + InitDS_Sel(0xc5218058); // 26.94% + InitDS_Sel(0xc881804c); // 11.98% + InitDS_Sel(0xc8839158); // 22.61% + InitDS_Sel(0xc8878158); // 8.98% + InitDS_Sel(0xc8878168); // 9.05% + InitDS_Sel(0xc8879168); // 6.53% + InitDS_Sel(0xc9078168); // 15.66% + InitDS_Sel(0xca83804c); // 16.89% + InitDS_Sel(0xcc43904c); // 77.10% + InitDS_Sel(0xdfe59068); // 64.26% + + // bully + + InitDS_Sel(0x110e8864); // 65.16% + InitDS_Sel(0x110e8964); // 50.07% + InitDS_Sel(0x4d068064); // 23.14% + InitDS_Sel(0x4d068364); // 21.42% + InitDS_Sel(0x4d068864); // 22.79% + InitDS_Sel(0x9fe04077); // 8.61% + InitDS_Sel(0xc901004c); // 22.07% + InitDS_Sel(0xca83904c); // 51.08% + InitDS_Sel(0xd480404d); // 15.61% + InitDS_Sel(0xd501904e); // 37.30% + + // culdcept + + InitDS_Sel(0x1fe04866); // 15.93% + InitDS_Sel(0x1fe2a9e6); // 55.93% + InitDS_Sel(0x9fe391e6); // 31.07% + InitDS_Sel(0x9fe3a1e6); // 9.26% + InitDS_Sel(0x9fe591e6); // 9.73% + InitDS_Sel(0xc88181e6); // 9.89% + InitDS_Sel(0x1fe2a1e6); // 15.71% + InitDS_Sel(0x49004866); // 5.05% + InitDS_Sel(0x4d02a1e6); // 15.31% + InitDS_Sel(0x9fe191e6); // 5.64% + InitDS_Sel(0x9fe59066); // 20.56% + InitDS_Sel(0x9fe991e6); // 19.59% + InitDS_Sel(0xcd0381e6); // 5.84% + + // suikoden 5 + + InitDS_Sel(0x00428868); // 14.32% + InitDS_Sel(0x40428868); // 20.87% + InitDS_Sel(0x4846804c); // 27.56% + InitDS_Sel(0x48819368); // 26.24% + InitDS_Sel(0x48828b68); // 29.80% + InitDS_Sel(0x48829368); // 22.30% + InitDS_Sel(0x48858368); // 8.44% + InitDS_Sel(0x48858b68); // 6.10% + InitDS_Sel(0x48859068); // 22.77% + InitDS_Sel(0x48859368); // 7.35% + InitDS_Sel(0x48869068); // 30.96% + InitDS_Sel(0x48878b68); // 5.18% + InitDS_Sel(0x48879368); // 10.31% + InitDS_Sel(0x488a8b68); // 11.73% + InitDS_Sel(0x49028868); // 14.35% + InitDS_Sel(0x4906804c); // 30.53% + InitDS_Sel(0x4d068868); // 33.72% + InitDS_Sel(0x4d0e8868); // 34.68% + + // dq8 + + InitDS_Sel(0x48830064); // 8.11% + InitDS_Sel(0x48869164); // 12.03% + InitDS_Sel(0x490a8164); // 5.03% + InitDS_Sel(0x490e904c); // 19.05% + InitDS_Sel(0x490f904c); // 15.81% + InitDS_Sel(0x9103b04c); // 5.05% + InitDS_Sel(0xc840404c); // 15.86% + InitDS_Sel(0xc883914c); // 5.84% + InitDS_Sel(0xc885804c); // 22.07% + InitDS_Sel(0xc8859054); // 9.61% + InitDS_Sel(0xc8c3804c); // 36.23% + InitDS_Sel(0xdfe3904e); // 5.49% + + // resident evil 4 + + InitDS_Sel(0x1fe04057); // 6.33% + InitDS_Sel(0x48868064); // 7.84% + InitDS_Sel(0x4886814c); // 5.42% + InitDS_Sel(0x48868164); // 12.98% + InitDS_Sel(0x48868864); // 39.04% + InitDS_Sel(0x48868964); // 10.15% + InitDS_Sel(0x48878164); // 64.35% + InitDS_Sel(0x4b068064); // 6.74% + InitDS_Sel(0x9fe18064); // 11.81% + InitDS_Sel(0xc880404c); // 8.39% + InitDS_Sel(0xc883814c); // 13.71% + InitDS_Sel(0xc885904c); // 11.74% + InitDS_Sel(0xc887804c); // 25.43% + InitDS_Sel(0xc887814c); // 17.68% + InitDS_Sel(0xc903904c); // 15.89% + InitDS_Sel(0xc907814c); // 10.74% + InitDS_Sel(0xcc879064); // 25.97% + InitDS_Sel(0xcd004064); // 70.25% + InitDS_Sel(0xcd03904c); // 23.53% + InitDS_Sel(0xcd07814c); // 8.41% + InitDS_Sel(0xd483904c); // 6.04% + InitDS_Sel(0xdfe1904e); // 19.81% + InitDS_Sel(0xdfe5904c); // 12.52% + + // tomoyo after + + InitDS_Sel(0x48404868); // 30.60% + InitDS_Sel(0x9fe38059); // 21.23% + InitDS_Sel(0x9fe39059); // 20.70% + InitDS_Sel(0xc8478068); // 8.06% + InitDS_Sel(0xc8818068); // 26.07% + InitDS_Sel(0xc9058068); // 15.90% + InitDS_Sel(0xca858068); // 14.66% + + // .hack redemption + + InitDS_Sel(0x1fe04864); // 5.01% + InitDS_Sel(0x48404074); // 6.97% + InitDS_Sel(0x48469064); // 20.80% + InitDS_Sel(0x48478064); // 8.87% + InitDS_Sel(0x48804864); // 5.94% + InitDS_Sel(0x48869364); // 22.39% + InitDS_Sel(0x488e9064); // 23.49% + InitDS_Sel(0x49004074); // 6.95% + InitDS_Sel(0x49004864); // 7.26% + InitDS_Sel(0xc123004c); // 17.86% + InitDS_Sel(0xc8478064); // 8.89% + InitDS_Sel(0xc8804054); // 13.68% + InitDS_Sel(0xc903004c); // 16.45% + InitDS_Sel(0xcc41804c); // 11.98% + InitDS_Sel(0xdfe1004c); // 11.81% + + // wild arms 4 + + InitDS_Sel(0x9fe19050); // 6.28% + InitDS_Sel(0x9fe58064); // 11.45% + InitDS_Sel(0x9fe59064); // 10.01% + InitDS_Sel(0xc8404064); // 22.23% + InitDS_Sel(0xccc0404c); // 10.08% + InitDS_Sel(0xccc04064); // 5.64% + InitDS_Sel(0xcd07804c); // 39.49% + InitDS_Sel(0xcd078164); // 19.54% + InitDS_Sel(0xcd45804c); // 5.23% + InitDS_Sel(0xdfe19054); // 17.70% + + // wild arms 5 + + InitDS_Sel(0x4885884c); // 6.64% + InitDS_Sel(0x4887904c); // 25.66% + InitDS_Sel(0x488e8764); // 25.45% + InitDS_Sel(0x48c68864); // 6.46% + InitDS_Sel(0x9fe3804c); // 7.00% + InitDS_Sel(0xc845804c); // 14.03% + InitDS_Sel(0xdfe39054); // 19.69% + + // shadow of the colossus + + InitDS_Sel(0x4883804c); // 184.84% + InitDS_Sel(0x48868b64); // 12.88% + InitDS_Sel(0x48869064); // 27.18% + InitDS_Sel(0x48878364); // 23.80% + InitDS_Sel(0x48879064); // 27.06% + InitDS_Sel(0x48879364); // 16.89% + InitDS_Sel(0x488e8864); // 148.99% + InitDS_Sel(0x488e9364); // 5.28% + InitDS_Sel(0x490e8064); // 66.50% + InitDS_Sel(0x490e8864); // 8.82% + InitDS_Sel(0x490f8064); // 8.23% + InitDS_Sel(0x4d004064); // 88.17% + InitDS_Sel(0x9fe04064); // 9.69% + InitDS_Sel(0x9fe1004d); // 10.39% + InitDS_Sel(0x9fe3904d); // 15.56% + InitDS_Sel(0xc883804c); // 45.16% + InitDS_Sel(0xc883904c); // 5.41% + InitDS_Sel(0xc8938064); // 45.66% + InitDS_Sel(0xc8939064); // 15.27% + InitDS_Sel(0xc900404c); // 8.73% + InitDS_Sel(0xc9004064); // 51.37% + InitDS_Sel(0xc903804c); // 35.17% + InitDS_Sel(0xca83004c); // 17.37% + InitDS_Sel(0xcc030064); // 21.25% + InitDS_Sel(0xcc80404c); // 9.19% + + // tales of rebirth + + InitDS_Sel(0x48404054); // 10.33% + InitDS_Sel(0x48878054); // 75.33% + InitDS_Sel(0x48878b64); // 10.17% + InitDS_Sel(0x4c838854); // 15.15% + InitDS_Sel(0xc8478054); // 13.29% + InitDS_Sel(0xc88b9054); // 7.08% + InitDS_Sel(0xcc838064); // 16.57% + + // digital devil saga + + InitDS_Sel(0x48804050); // 6.18% + InitDS_Sel(0x48868870); // 5.80% + InitDS_Sel(0x488e8860); // 22.08% + InitDS_Sel(0x4907884c); // 28.15% + InitDS_Sel(0x9fe39070); // 5.89% + + // dbzbt2 + + InitDS_Sel(0x4906884c); // 17.04% + InitDS_Sel(0x4c904064); // 28.94% + InitDS_Sel(0xc8878074); // 26.80% + InitDS_Sel(0xc9078054); // 22.93% + + // dbzbt3 + + InitDS_Sel(0x489081e4); // 11.25% + InitDS_Sel(0x48968864); // 16.90% + InitDS_Sel(0x4c469064); // 14.83% + InitDS_Sel(0x4c80404c); // 6.99% + InitDS_Sel(0x4c869064); // 15.61% + InitDS_Sel(0xc88391cc); // 12.45% + InitDS_Sel(0xc885904e); // 16.45% + InitDS_Sel(0xc8859074); // 15.19% + InitDS_Sel(0xc905904c); // 27.52% + InitDS_Sel(0xc917804c); // 5.66% + InitDS_Sel(0xca40404c); // 10.86% + InitDS_Sel(0xcc45904e); // 33.93% + InitDS_Sel(0xcc80404e); // 12.83% + InitDS_Sel(0xcc8391cc); // 25.49% + + // dbz iw + + InitDS_Sel(0x1fe48864); // 11.22% + InitDS_Sel(0x1fe49064); // 5.09% + InitDS_Sel(0x1fec8864); // 26.53% + InitDS_Sel(0x1fec8964); // 6.54% + InitDS_Sel(0x48808064); // 7.90% + InitDS_Sel(0x48848064); // 5.32% + InitDS_Sel(0x48848864); // 18.43% + InitDS_Sel(0x48858064); // 20.14% + InitDS_Sel(0x48859064); // 13.97% + InitDS_Sel(0x49058064); // 9.97% + InitDS_Sel(0x49084064); // 9.60% + InitDS_Sel(0x9fe19064); // 17.67% + InitDS_Sel(0xc881004c); // 16.40% + InitDS_Sel(0xc8858064); // 38.16% + InitDS_Sel(0xc8859064); // 26.38% + InitDS_Sel(0xc88d8064); // 7.05% + InitDS_Sel(0xc88d9064); // 15.38% + InitDS_Sel(0xc9058064); // 12.95% + InitDS_Sel(0xc9084064); // 14.20% + InitDS_Sel(0xc90d8064); // 21.35% + InitDS_Sel(0xcd404054); // 18.85% + + // disgaea 2 + + InitDS_Sel(0x1fe04064); // 5.51% + InitDS_Sel(0x1fe69074); // 8.82% + InitDS_Sel(0x48878964); // 65.93% + InitDS_Sel(0xc8879164); // 5.09% + + // gradius 5 + + InitDS_Sel(0x48868968); // 40.64% + InitDS_Sel(0x48878968); // 7.97% + InitDS_Sel(0x49078968); // 7.80% + InitDS_Sel(0x490e884c); // 37.26% + InitDS_Sel(0x5fe68068); // 32.99% + InitDS_Sel(0x5fe68968); // 15.59% + InitDS_Sel(0x5fee8168); // 5.25% + InitDS_Sel(0x5fee8868); // 36.64% + InitDS_Sel(0x5fee8968); // 16.28% + InitDS_Sel(0x5ffe8868); // 6.67% + InitDS_Sel(0xdfe3814c); // 24.29% + + // tales of abyss + + InitDS_Sel(0x1fe39368); // 7.47% + InitDS_Sel(0x4885804c); // 14.27% + InitDS_Sel(0x48868068); // 11.14% + InitDS_Sel(0x4886934c); // 6.41% + InitDS_Sel(0x4887834c); // 8.90% + InitDS_Sel(0x488e8368); // 13.35% + InitDS_Sel(0x48cf89e8); // 39.25% + InitDS_Sel(0x4903834c); // 21.04% + InitDS_Sel(0x490c8b68); // 15.04% + InitDS_Sel(0x490e8b68); // 8.05% + InitDS_Sel(0x490f89e8); // 39.57% + InitDS_Sel(0x4d03914c); // 18.97% + InitDS_Sel(0xc121004c); // 26.59% + InitDS_Sel(0xc887934c); // 5.73% + InitDS_Sel(0xdfe59078); // 21.43% + + // Gundam Seed Destiny OMNI VS ZAFT II PLUS + + InitDS_Sel(0x1fe68075); // 27.61% + InitDS_Sel(0x4880484d); // 13.50% + InitDS_Sel(0x48878075); // 8.16% + InitDS_Sel(0x48878375); // 8.66% + InitDS_Sel(0x4887884d); // 17.82% + InitDS_Sel(0x48878b75); // 53.12% + InitDS_Sel(0x488e8075); // 42.24% + InitDS_Sel(0x488e8375); // 35.32% + InitDS_Sel(0x488e8875); // 25.59% + InitDS_Sel(0x488e8b75); // 51.44% + InitDS_Sel(0x488e9075); // 16.57% + InitDS_Sel(0x49068075); // 35.78% + InitDS_Sel(0x4906884d); // 6.37% + InitDS_Sel(0x490e8375); // 31.56% + InitDS_Sel(0x490e8875); // 35.20% + InitDS_Sel(0x490e8b75); // 38.85% + InitDS_Sel(0x9fe19075); // 20.98% + InitDS_Sel(0xc8878075); // 14.30% + + // nba 2k8 + + InitDS_Sel(0x1fe04056); // 15.57% + InitDS_Sel(0x1fe38966); // 28.88% + InitDS_Sel(0x1fe39156); // 25.28% + InitDS_Sel(0x1fe60866); // 5.67% + InitDS_Sel(0x1fe68866); // 5.75% + InitDS_Sel(0x48838166); // 10.93% + InitDS_Sel(0x48868066); // 7.59% + InitDS_Sel(0x48868166); // 10.44% + InitDS_Sel(0x48868866); // 42.03% + InitDS_Sel(0x48868966); // 30.06% + InitDS_Sel(0x48869166); // 6.52% + InitDS_Sel(0x48879066); // 10.60% + InitDS_Sel(0x49028966); // 7.28% + InitDS_Sel(0x49068066); // 31.37% + InitDS_Sel(0x49068966); // 11.65% + InitDS_Sel(0x49068976); // 45.50% + InitDS_Sel(0x5fe68866); // 22.26% + InitDS_Sel(0x9fe79066); // 28.38% + InitDS_Sel(0xc8879166); // 6.42% + InitDS_Sel(0xdfe79066); // 30.98% + + // onimusha 3 + + InitDS_Sel(0x1fee004c); // 5.11% + InitDS_Sel(0x1fee0868); // 42.66% + InitDS_Sel(0x1fee8968); // 7.76% + InitDS_Sel(0x48878068); // 24.27% + InitDS_Sel(0x48c28368); // 5.97% + InitDS_Sel(0x4903884c); // 28.26% + InitDS_Sel(0x49068068); // 9.53% + InitDS_Sel(0x4d05884c); // 6.59% + InitDS_Sel(0x5fe04078); // 29.53% + InitDS_Sel(0x9fe18068); // 5.38% + InitDS_Sel(0xc8839168); // 6.59% + InitDS_Sel(0xcc81904c); // 5.21% + InitDS_Sel(0xcc878168); // 7.18% + InitDS_Sel(0xcd004068); // 28.32% + InitDS_Sel(0xcd03804c); // 7.20% + InitDS_Sel(0xd425904c); // 5.69% + InitDS_Sel(0xdfe78368); // 6.71% + InitDS_Sel(0xdfe7904c); // 8.43% + InitDS_Sel(0xdfe79368); // 9.36% + + // resident evil code veronica + + InitDS_Sel(0x1fee8168); // 9.31% + InitDS_Sel(0x1fee8868); // 6.75% + InitDS_Sel(0x48804068); // 12.40% + InitDS_Sel(0x48804868); // 41.21% + InitDS_Sel(0x48804b68); // 7.16% + InitDS_Sel(0x9fe39068); // 17.58% + InitDS_Sel(0x9fe79068); // 25.03% + InitDS_Sel(0x9fe79168); // 25.89% + InitDS_Sel(0xc8878068); // 29.01% + InitDS_Sel(0xc8878368); // 11.44% + InitDS_Sel(0xc8879368); // 6.59% + InitDS_Sel(0xcc819058); // 23.03% + + // armored core 3 + + InitDS_Sel(0x1fe84074); // 6.66% + InitDS_Sel(0x1fee0874); // 59.28% + InitDS_Sel(0x48404854); // 7.27% + InitDS_Sel(0x48878074); // 10.32% + InitDS_Sel(0x48878874); // 16.96% + InitDS_Sel(0x488e8074); // 25.40% + InitDS_Sel(0x490e8074); // 79.82% + InitDS_Sel(0x4c4e8074); // 23.05% + InitDS_Sel(0x4d0b0864); // 5.94% + InitDS_Sel(0x4d0e8074); // 8.44% + InitDS_Sel(0xc8404054); // 9.47% + InitDS_Sel(0xc8850054); // 11.54% + InitDS_Sel(0xc88581d4); // 6.72% + InitDS_Sel(0xc88791d4); // 6.83% + InitDS_Sel(0xc9059054); // 13.98% + InitDS_Sel(0xc9078074); // 9.60% + + // aerial planet + + InitDS_Sel(0x4886894c); // 18.07% + InitDS_Sel(0x488e814c); // 16.96% + InitDS_Sel(0x4c868074); // 46.13% + InitDS_Sel(0x4c868874); // 7.71% + InitDS_Sel(0x4c868934); // 19.26% + InitDS_Sel(0x4c8e8074); // 12.50% + InitDS_Sel(0x4c8e8874); // 27.69% + InitDS_Sel(0x4cc0404c); // 15.74% + InitDS_Sel(0xc820404c); // 16.32% + InitDS_Sel(0xc8478164); // 11.12% + InitDS_Sel(0xc847914c); // 7.70% + InitDS_Sel(0xc887914c); // 8.85% + + // one piece grand battle 3 + + InitDS_Sel(0x48804054); // 12.28% + InitDS_Sel(0x48878854); // 12.62% + InitDS_Sel(0x49068174); // 5.54% + InitDS_Sel(0x49068874); // 28.97% + InitDS_Sel(0x49068964); // 16.11% + InitDS_Sel(0x49078174); // 11.17% + InitDS_Sel(0x9fe1904e); // 10.23% + InitDS_Sel(0xc8839054); // 21.50% + InitDS_Sel(0xc8878054); // 6.54% + InitDS_Sel(0xc8879054); // 10.18% + InitDS_Sel(0xc9078174); // 8.49% + InitDS_Sel(0xcac0404c); // 9.30% + InitDS_Sel(0xcc41904c); // 12.33% + InitDS_Sel(0xcc4190cc); // 7.21% + InitDS_Sel(0xd321914c); // 7.10% + + // one piece grand adventure + + InitDS_Sel(0x1fe0404c); // 5.18% + InitDS_Sel(0x48829164); // 12.79% + InitDS_Sel(0x48849164); // 11.67% + InitDS_Sel(0x48869154); // 5.38% + InitDS_Sel(0x48878154); // 5.01% + InitDS_Sel(0x48879154); // 5.57% + InitDS_Sel(0x49078964); // 151.46% + InitDS_Sel(0xc421814c); // 7.73% + InitDS_Sel(0xc843b04c); // 21.62% + + // shadow hearts + + InitDS_Sel(0x1fe6904c); // 5.97% + InitDS_Sel(0x48868078); // 9.90% + InitDS_Sel(0x48868778); // 9.59% + InitDS_Sel(0x49004058); // 7.20% + InitDS_Sel(0x49030058); // 40.18% + InitDS_Sel(0x4c870878); // 6.19% + InitDS_Sel(0x9fe3004c); // 20.51% + InitDS_Sel(0xc8804058); // 9.57% + InitDS_Sel(0xc881904e); // 5.29% + InitDS_Sel(0xc8819168); // 13.94% + InitDS_Sel(0xc8839058); // 12.53% + InitDS_Sel(0xc8878058); // 13.80% + InitDS_Sel(0xc8879058); // 9.68% + InitDS_Sel(0xc9039058); // 12.08% + InitDS_Sel(0xc9078068); // 29.18% + + // the punisher + + InitDS_Sel(0x48420864); // 5.88% + InitDS_Sel(0x48468864); // 8.39% + InitDS_Sel(0x48868764); // 16.69% + InitDS_Sel(0x4886bf64); // 14.77% + InitDS_Sel(0x49068064); // 7.90% + InitDS_Sel(0x4906904c); // 14.02% + InitDS_Sel(0x4d068f64); // 12.33% + InitDS_Sel(0x5fe68f64); // 62.24% + InitDS_Sel(0xc880474c); // 20.85% + InitDS_Sel(0xc883974c); // 6.07% + InitDS_Sel(0xc887874c); // 8.47% + InitDS_Sel(0xc887974c); // 10.36% + InitDS_Sel(0xdfe3974c); // 21.42% + + // guitar hero + + InitDS_Sel(0x1fe0407b); // 6.67% + InitDS_Sel(0x1fe6887a); // 9.08% + InitDS_Sel(0x4880484e); // 34.74% + InitDS_Sel(0x4886807a); // 6.73% + InitDS_Sel(0x4886887a); // 47.23% + InitDS_Sel(0x4886907a); // 5.53% + InitDS_Sel(0x4886956a); // 8.71% + InitDS_Sel(0x4887854e); // 6.67% + InitDS_Sel(0x4887887a); // 31.33% + InitDS_Sel(0x4887954e); // 20.26% + InitDS_Sel(0x488a917a); // 33.17% + InitDS_Sel(0x488e887a); // 80.36% + InitDS_Sel(0x488e8d7a); // 5.16% + InitDS_Sel(0x4906806a); // 23.53% + InitDS_Sel(0x4906886a); // 5.02% + InitDS_Sel(0x4d06a06a); // 22.00% + InitDS_Sel(0x4d06a86a); // 15.44% + InitDS_Sel(0x4d0ea06a); // 5.08% + InitDS_Sel(0x9503204e); // 22.47% + InitDS_Sel(0x9fe3906a); // 12.46% + InitDS_Sel(0xc887855a); // 5.09% + InitDS_Sel(0xc887857a); // 27.54% + InitDS_Sel(0xcd03204e); // 70.62% + InitDS_Sel(0xcd07806a); // 8.94% + + // ico + + InitDS_Sel(0x1fe28060); // 16.14% + InitDS_Sel(0x1fe68860); // 47.91% + InitDS_Sel(0x48868060); // 10.32% + InitDS_Sel(0x48868b60); // 94.89% + InitDS_Sel(0x49068b60); // 10.26% + InitDS_Sel(0x4c468b60); // 41.67% + InitDS_Sel(0x4c478860); // 11.90% + InitDS_Sel(0x4d004060); // 102.46% + InitDS_Sel(0x4d028060); // 17.75% + InitDS_Sel(0x4d068360); // 16.19% + InitDS_Sel(0x4d068860); // 18.08% + InitDS_Sel(0x4d068b60); // 223.13% + InitDS_Sel(0x4d078360); // 5.55% + InitDS_Sel(0x9fe04060); // 7.09% + InitDS_Sel(0x9fe380cc); // 16.22% + InitDS_Sel(0x9fe3a04c); // 47.14% + InitDS_Sel(0xc8859060); // 13.85% + InitDS_Sel(0xc893814c); // 40.77% + InitDS_Sel(0xc9004060); // 6.15% + InitDS_Sel(0xcd078060); // 5.49% + InitDS_Sel(0xcd078360); // 9.27% + + // kuon + + InitDS_Sel(0x1fee0865); // 19.11% + InitDS_Sel(0x48860065); // 26.44% + InitDS_Sel(0x48860865); // 24.38% + InitDS_Sel(0x48868365); // 18.01% + InitDS_Sel(0x48868b65); // 31.33% + InitDS_Sel(0x488e0865); // 39.97% + InitDS_Sel(0x488e0b65); // 20.78% + InitDS_Sel(0x488e8b65); // 12.26% + InitDS_Sel(0x4c429065); // 25.89% + InitDS_Sel(0x4d068365); // 9.17% + InitDS_Sel(0xc847004d); // 13.35% + InitDS_Sel(0xc887004d); // 17.53% + InitDS_Sel(0xc8870065); // 28.03% + InitDS_Sel(0xc907004d); // 18.64% + InitDS_Sel(0xc9070065); // 5.21% + + // hxh + + InitDS_Sel(0x1fe04876); // 7.16% + InitDS_Sel(0x1fee8076); // 9.68% + InitDS_Sel(0x1fee8976); // 17.11% + InitDS_Sel(0x9fe04076); // 5.37% + InitDS_Sel(0x9fe79176); // 6.77% + InitDS_Sel(0xc8804076); // 6.64% + InitDS_Sel(0xc8838176); // 6.95% + InitDS_Sel(0xc8839176); // 6.85% + InitDS_Sel(0xc8878076); // 5.29% + + // grandia extreme + + InitDS_Sel(0x1fe3884c); // 27.03% + InitDS_Sel(0x45269070); // 5.74% + InitDS_Sel(0x452e9070); // 7.25% + InitDS_Sel(0x48868070); // 13.25% + InitDS_Sel(0x48869070); // 24.24% + InitDS_Sel(0x48878370); // 22.45% + InitDS_Sel(0x48879070); // 21.66% + InitDS_Sel(0x48879370); // 13.17% + InitDS_Sel(0x4888404c); // 12.23% + InitDS_Sel(0x48884050); // 15.68% + InitDS_Sel(0x488e8870); // 44.66% + InitDS_Sel(0x488e8b70); // 45.62% + InitDS_Sel(0x488e9370); // 14.64% + InitDS_Sel(0x9fe3934c); // 16.61% + InitDS_Sel(0xcc81934c); // 62.20% + + // enthusia + + InitDS_Sel(0x1fe04854); // 23.33% + InitDS_Sel(0x1fe60064); // 5.72% + InitDS_Sel(0x1fe60068); // 5.03% + InitDS_Sel(0x1fee0064); // 7.51% + InitDS_Sel(0x1fee0864); // 15.47% + InitDS_Sel(0x48860f64); // 9.63% + InitDS_Sel(0x48868f64); // 29.41% + InitDS_Sel(0x488e0f64); // 11.80% + InitDS_Sel(0x49068864); // 23.63% + InitDS_Sel(0x4b020864); // 13.40% + InitDS_Sel(0x4b060064); // 11.39% + InitDS_Sel(0x4b060864); // 8.38% + InitDS_Sel(0x4b068864); // 14.03% + InitDS_Sel(0x9fe79064); // 13.49% + InitDS_Sel(0xcd40404c); // 11.10% + + // ys 1/2 eternal story + + // bloody roar + + InitDS_Sel(0x48810068); // 25.54% + InitDS_Sel(0x48848068); // 68.60% + InitDS_Sel(0x488789e8); // 10.83% + InitDS_Sel(0x488791e8); // 11.18% + InitDS_Sel(0x49004068); // 9.51% + InitDS_Sel(0x49004868); // 6.95% + InitDS_Sel(0x49018368); // 15.01% + InitDS_Sel(0x49019368); // 13.90% + InitDS_Sel(0x4b068068); // 13.98% + InitDS_Sel(0x4b068868); // 14.29% + InitDS_Sel(0x4c469068); // 9.71% + + // ferrari f355 challenge + + InitDS_Sel(0x489e8064); // 9.07% + InitDS_Sel(0x489e8b64); // 8.01% + InitDS_Sel(0x5fe04064); // 10.07% + InitDS_Sel(0x5fe04068); // 13.01% + InitDS_Sel(0x5fe04868); // 6.33% + InitDS_Sel(0x5fe60064); // 10.58% + InitDS_Sel(0x5fee0064); // 14.14% + InitDS_Sel(0x5fee0864); // 21.09% + InitDS_Sel(0x5feeb864); // 7.78% + InitDS_Sel(0x5ff60064); // 16.67% + InitDS_Sel(0x5ffe0064); // 17.43% + InitDS_Sel(0x5ffe0864); // 23.98% + InitDS_Sel(0xc8858168); // 54.96% + InitDS_Sel(0xc890404c); // 6.30% + InitDS_Sel(0xdfef0064); // 8.68% + + // king of fighters xi + + InitDS_Sel(0x488589e8); // 110.21% + InitDS_Sel(0x488591e8); // 55.38% + InitDS_Sel(0xf4819050); // 12.12% + + // mana khemia + + InitDS_Sel(0x488e8369); // 96.11% + InitDS_Sel(0xc880404d); // 12.30% + InitDS_Sel(0xc881804d); // 16.48% + InitDS_Sel(0xc8819059); // 22.73% + InitDS_Sel(0xc885904d); // 12.36% + InitDS_Sel(0xc907804d); // 59.32% + InitDS_Sel(0xc90f8369); // 7.80% + + // ar tonelico 2 + + InitDS_Sel(0x484f8369); // 7.55% + InitDS_Sel(0x488e8069); // 22.13% + InitDS_Sel(0x488e9069); // 33.42% + InitDS_Sel(0x488e9369); // 103.56% + InitDS_Sel(0x488f8369); // 23.74% + InitDS_Sel(0x490f8369); // 29.15% + InitDS_Sel(0xc885804d); // 5.80% + InitDS_Sel(0xc887804d); // 7.94% + InitDS_Sel(0xc88f9369); // 13.74% + InitDS_Sel(0xc905904d); // 6.23% + + // rouge galaxy + + InitDS_Sel(0x1fe0484c); // 6.12% + InitDS_Sel(0x484e8164); // 53.09% + InitDS_Sel(0x48879054); // 47.81% + InitDS_Sel(0x488b0964); // 95.23% + InitDS_Sel(0x490e8164); // 24.34% + InitDS_Sel(0x490e9164); // 5.24% + InitDS_Sel(0xc8858154); // 18.49% + InitDS_Sel(0xdff0404c); // 7.47% + + // mobile suit gundam seed battle assault 3 + + InitDS_Sel(0x49004854); // 7.22% + InitDS_Sel(0x4c804054); // 12.92% + InitDS_Sel(0x5fee8074); // 14.87% + InitDS_Sel(0x5fee8874); // 58.09% + InitDS_Sel(0x5fee9174); // 5.15% + InitDS_Sel(0xc88390cc); // 21.42% + InitDS_Sel(0xc88791cc); // 6.20% + InitDS_Sel(0xc90781cc); // 12.73% + InitDS_Sel(0xcc81004d); // 11.15% + + // hajime no ippo all stars + + InitDS_Sel(0x48848868); // 7.31% + InitDS_Sel(0x48848b68); // 6.25% + InitDS_Sel(0x48858868); // 6.71% + InitDS_Sel(0x488c8b68); // 16.70% + + // hajime no ippo 2 + + InitDS_Sel(0x1fe04068); // 11.95% + InitDS_Sel(0x4881004c); // 20.37% + InitDS_Sel(0x48839368); // 31.79% + InitDS_Sel(0x48858068); // 55.12% + InitDS_Sel(0x48868b68); // 23.49% + InitDS_Sel(0x48878368); // 6.54% + InitDS_Sel(0x48879068); // 29.98% + InitDS_Sel(0x488c8068); // 10.13% + InitDS_Sel(0x488c8868); // 16.20% + InitDS_Sel(0x488e8b68); // 38.97% + InitDS_Sel(0x488e9068); // 7.20% + InitDS_Sel(0x488e9368); // 13.42% + InitDS_Sel(0x49028b68); // 48.16% + InitDS_Sel(0x4b0e8068); // 5.51% + InitDS_Sel(0x4b0e8868); // 14.85% + InitDS_Sel(0x4d0e8068); // 7.65% + InitDS_Sel(0xc8859068); // 21.31% + + // virtual tennis 2 + + InitDS_Sel(0x488049e5); // 5.52% + InitDS_Sel(0x48868075); // 28.20% + InitDS_Sel(0x48868875); // 20.93% + InitDS_Sel(0x4c8781f5); // 11.54% + InitDS_Sel(0x9540404d); // 6.25% + InitDS_Sel(0xc8859065); // 11.57% + + // crash wrath of cortex + + InitDS_Sel(0x1fe20864); // 15.87% + InitDS_Sel(0x48828764); // 9.14% + InitDS_Sel(0x48828f64); // 18.80% + InitDS_Sel(0x48838364); // 12.07% + InitDS_Sel(0x48838f64); // 5.84% + InitDS_Sel(0x49028f64); // 16.48% + InitDS_Sel(0x49038f64); // 34.44% + InitDS_Sel(0x9fe78064); // 11.75% + InitDS_Sel(0xc8818364); // 9.12% + InitDS_Sel(0xc9030064); // 100.90% + InitDS_Sel(0xca838364); // 8.86% + InitDS_Sel(0xcd05834c); // 8.90% + + // sbam 2 + + // remember 11 + + // prince of tennis + + InitDS_Sel(0x4888484c); // 5.28% + InitDS_Sel(0x488d8164); // 30.73% + InitDS_Sel(0x488d9164); // 23.46% + InitDS_Sel(0xc885914c); // 5.01% + InitDS_Sel(0xc8859164); // 7.79% + InitDS_Sel(0xc88d8164); // 5.33% + InitDS_Sel(0xc88d9164); // 26.18% + InitDS_Sel(0xc8958164); // 10.14% + InitDS_Sel(0xc89d814c); // 7.09% + InitDS_Sel(0xcd458064); // 13.67% + + // ar tonelico + + InitDS_Sel(0x48868369); // 17.29% + InitDS_Sel(0x48869369); // 16.05% + InitDS_Sel(0x488f9369); // 6.07% + InitDS_Sel(0x49078b69); // 54.61% + InitDS_Sel(0x490f8069); // 54.79% + InitDS_Sel(0x490f9369); // 5.20% + InitDS_Sel(0xc8804069); // 16.59% + InitDS_Sel(0xc8878069); // 32.09% + InitDS_Sel(0xc8878369); // 14.18% + InitDS_Sel(0xc8879069); // 31.83% + InitDS_Sel(0xc8879369); // 12.02% + InitDS_Sel(0xc9038069); // 245.53% + + // dbz sagas + + InitDS_Sel(0x48828964); // 38.72% + InitDS_Sel(0x488e9164); // 10.98% + InitDS_Sel(0x54229164); // 6.16% + + // tourist trophy + + InitDS_Sel(0x1fe84064); // 14.21% + InitDS_Sel(0x1fee8064); // 23.50% + InitDS_Sel(0x1fee9064); // 13.72% + InitDS_Sel(0x488a8064); // 10.03% + InitDS_Sel(0x488e8065); // 16.63% + InitDS_Sel(0x488e9065); // 16.00% + InitDS_Sel(0x5fe3804c); // 8.34% + InitDS_Sel(0x5fe3904c); // 7.65% + InitDS_Sel(0x5fee8164); // 7.66% + InitDS_Sel(0x9fe1904c); // 9.19% + InitDS_Sel(0x9fe1904d); // 6.10% + InitDS_Sel(0x9fe3804d); // 9.23% + InitDS_Sel(0x9fe5904d); // 7.20% + InitDS_Sel(0x9fe7804d); // 5.30% + InitDS_Sel(0x9fe7904d); // 5.67% + InitDS_Sel(0xc88181d4); // 11.57% + InitDS_Sel(0xc881904d); // 7.00% + InitDS_Sel(0xc88191d4); // 12.53% + InitDS_Sel(0xc887904d); // 5.13% + InitDS_Sel(0xcb03804c); // 21.06% + InitDS_Sel(0xcc81904d); // 13.48% + InitDS_Sel(0xcc83804d); // 10.28% + InitDS_Sel(0xcc83904c); // 34.42% + InitDS_Sel(0xcc83904d); // 10.24% + InitDS_Sel(0xcc87904d); // 33.01% + InitDS_Sel(0xcd05804c); // 17.24% + InitDS_Sel(0xd520404c); // 9.81% + InitDS_Sel(0xdfe1904c); // 7.52% + InitDS_Sel(0xdfe5804c); // 7.14% + + // svr2k8 + + InitDS_Sel(0x1fe79066); // 13.17% + InitDS_Sel(0x4880404c); // 7.49% + InitDS_Sel(0x4887804c); // 5.40% + InitDS_Sel(0x4887814c); // 9.08% + InitDS_Sel(0x488a0064); // 5.41% + InitDS_Sel(0x4900404c); // 12.53% + InitDS_Sel(0x490e8364); // 30.80% + InitDS_Sel(0x4c97b874); // 15.16% + InitDS_Sel(0xc887834c); // 7.67% + + // tokyo bus guide + + InitDS_Sel(0x1fe04070); // 13.22% + InitDS_Sel(0x1fe04870); // 13.56% + InitDS_Sel(0x1fee8170); // 10.70% + InitDS_Sel(0x1fee8970); // 60.13% + InitDS_Sel(0x1fee89f0); // 51.01% + InitDS_Sel(0x48804870); // 12.85% + InitDS_Sel(0x488a8850); // 21.74% + InitDS_Sel(0xc8804070); // 13.67% + InitDS_Sel(0xc8879070); // 35.52% + InitDS_Sel(0xc88791f0); // 18.61% + + // 12riven + + // xenosaga + + InitDS_Sel(0x1fe38054); // 67.22% + InitDS_Sel(0x1fe38074); // 25.86% + InitDS_Sel(0x48478164); // 32.61% + InitDS_Sel(0x48804964); // 7.12% + InitDS_Sel(0x49078164); // 25.05% + InitDS_Sel(0x4c818134); // 10.06% + InitDS_Sel(0x4d069064); // 98.01% + InitDS_Sel(0x4d084864); // 13.35% + InitDS_Sel(0x5fe04074); // 61.58% + InitDS_Sel(0x5fe68864); // 39.80% + InitDS_Sel(0x5fee8864); // 45.95% + InitDS_Sel(0x9fe04074); // 9.60% + InitDS_Sel(0x9fe1804c); // 9.55% + InitDS_Sel(0x9fe19074); // 16.03% + InitDS_Sel(0xc8819054); // 35.54% + InitDS_Sel(0xc8830074); // 47.20% + InitDS_Sel(0xc8858164); // 7.84% + InitDS_Sel(0xc9078164); // 154.58% + InitDS_Sel(0xcc819074); // 19.87% + InitDS_Sel(0xcd00404c); // 31.81% + InitDS_Sel(0xd5204064); // 14.68% + InitDS_Sel(0xdfe04074); // 14.26% + + // mgs3s1 + + InitDS_Sel(0x482e8864); // 18.14% + InitDS_Sel(0x484e8864); // 10.00% + InitDS_Sel(0x48868364); // 94.90% + InitDS_Sel(0x488e8364); // 15.82% + InitDS_Sel(0x488f8064); // 5.31% + InitDS_Sel(0x49268864); // 6.73% + InitDS_Sel(0x4b0e8864); // 8.35% + InitDS_Sel(0x4b0e8b64); // 6.23% + InitDS_Sel(0x9fe1804d); // 9.13% + InitDS_Sel(0x9fe7904c); // 11.17% + InitDS_Sel(0xc8804364); // 5.24% + InitDS_Sel(0xc8819364); // 19.10% + InitDS_Sel(0xc883004c); // 17.25% + InitDS_Sel(0xc8878364); // 12.09% + InitDS_Sel(0xc8879064); // 22.53% + InitDS_Sel(0xcc830074); // 54.93% + InitDS_Sel(0xcd079364); // 5.24% + InitDS_Sel(0xcd404074); // 9.03% + + // god of war + + // gta sa + + InitDS_Sel(0x1fe84864); // 6.23% + InitDS_Sel(0x48810064); // 14.67% + InitDS_Sel(0x49004054); // 16.40% + InitDS_Sel(0x4d07804c); // 15.09% + InitDS_Sel(0x4d078864); // 9.54% + InitDS_Sel(0x4d0c8864); // 8.71% + + // haunting ground + + InitDS_Sel(0x1fe68864); // 38.74% + InitDS_Sel(0x1fe689e4); // 44.79% + InitDS_Sel(0x488689e4); // 5.03% + InitDS_Sel(0xc843904c); // 16.66% + InitDS_Sel(0xc88791e4); // 22.86% + InitDS_Sel(0xcc23804c); // 16.80% + InitDS_Sel(0xcd01904c); // 82.27% + InitDS_Sel(0xdfe04064); // 14.73% + InitDS_Sel(0xdff1904e); // 14.38% + + // odin sphere + + InitDS_Sel(0x4880404d); // 7.35% + InitDS_Sel(0x4885804d); // 6.02% + InitDS_Sel(0x4885904c); // 11.56% + InitDS_Sel(0x488f904c); // 6.59% + InitDS_Sel(0x488f904d); // 6.69% + InitDS_Sel(0x4907804d); // 5.71% + InitDS_Sel(0x4907884d); // 9.45% + InitDS_Sel(0xc881904c); // 5.36% + + // kingdom hearts re:com + + InitDS_Sel(0x1fe04078); // 9.88% + InitDS_Sel(0x1fee884c); // 17.61% + InitDS_Sel(0x4880494c); // 6.46% + InitDS_Sel(0x48868974); // 11.43% + InitDS_Sel(0x488a8164); // 6.28% + InitDS_Sel(0x488e804c); // 6.41% + InitDS_Sel(0x488e874c); // 6.02% + InitDS_Sel(0x4906814c); // 33.35% + InitDS_Sel(0x4906894c); // 44.97% + InitDS_Sel(0x49068974); // 15.85% + InitDS_Sel(0x4907894c); // 16.25% + InitDS_Sel(0x49078974); // 6.45% + InitDS_Sel(0x9fe10054); // 14.10% + InitDS_Sel(0x9fe3814d); // 14.12% + InitDS_Sel(0x9fe3914d); // 17.86% + InitDS_Sel(0xc885814c); // 7.69% + InitDS_Sel(0xc907804c); // 8.56% + InitDS_Sel(0xcd404064); // 9.28% + InitDS_Sel(0xd120404c); // 9.47% + + // hyper street fighter 2 anniversary edition + + // star ocean 3 + + InitDS_Sel(0x49068164); // 57.66% + InitDS_Sel(0x9fe30064); // 24.77% + InitDS_Sel(0x9fe38065); // 28.18% + InitDS_Sel(0xc8839164); // 37.72% + InitDS_Sel(0xc920404c); // 11.35% + + // aura for laura + + InitDS_Sel(0x1fe38070); // 31.10% + InitDS_Sel(0x1fe3904c); // 19.62% + InitDS_Sel(0x1fe39050); // 5.19% + InitDS_Sel(0x1fe68070); // 19.79% + InitDS_Sel(0x1fe78070); // 112.75% + InitDS_Sel(0x1fe79070); // 65.97% + InitDS_Sel(0x1fefb04c); // 17.85% + InitDS_Sel(0x9fe38050); // 11.45% + InitDS_Sel(0x9fe39050); // 11.01% + InitDS_Sel(0x9fe78050); // 12.31% + InitDS_Sel(0xc523804c); // 106.80% + InitDS_Sel(0xc8839050); // 14.31% + InitDS_Sel(0xc9038050); // 6.72% + InitDS_Sel(0xc9058050); // 291.44% + InitDS_Sel(0xcc818050); // 49.07% + InitDS_Sel(0xd5204050); // 7.22% + + #endif +} + +IDrawScanline::DrawScanlinePtr GSDrawScanline::GSDrawScanlineMap::GetDefaultFunction(DWORD dw) +{ + GSScanlineSelector sel; + + sel.dw = dw; + + return m_default[sel.fpsm][sel.zpsm][sel.ztst][sel.iip]; +} + +void GSDrawScanline::GSDrawScanlineMap::PrintStats() +{ + __super::PrintStats(); + + if(FILE* fp = fopen("c:\\1.txt", "w")) + { + POSITION pos = m_map_active.GetHeadPosition(); + + while(pos) + { + DWORD dw; + ActivePtr* p; + + m_map_active.GetNextAssoc(pos, dw, p); + + if(m_map.Lookup(dw)) + { + continue; + } + + GSScanlineSelector sel; + + sel.dw = dw; + + if(p->frames > 30 && !sel.IsSolidRect()) + { + int tpf = (int)((p->ticks / p->frames) * 10000 / (3000000000 / 60)); // 3 GHz, 60 fps + + if(tpf >= 500) + { + _ftprintf(fp, _T("InitDS_Sel(0x%08x); // %6.2f%%\n"), sel.dw, (float)tpf / 100); + } + } + } + + fclose(fp); + } +} + +// + +GSDrawScanline::GSSetupPrimMap::GSSetupPrimMap() +{ + #define InitSP_IIP(zbe, fge, tme, fst, iip) \ + m_default[zbe][fge][tme][fst][iip] = (SetupPrimPtr)&GSDrawScanline::SetupPrim; \ + + #define InitSP_FST(zbe, fge, tme, fst) \ + InitSP_IIP(zbe, fge, tme, fst, 0) \ + InitSP_IIP(zbe, fge, tme, fst, 1) \ + + #define InitSP_TME(zbe, fge, tme) \ + InitSP_FST(zbe, fge, tme, 0) \ + InitSP_FST(zbe, fge, tme, 1) \ + + #define InitSP_FGE(zbe, fge) \ + InitSP_TME(zbe, fge, 0) \ + InitSP_TME(zbe, fge, 1) \ + + #define InitSP_ZBE(zbe) \ + InitSP_FGE(zbe, 0) \ + InitSP_FGE(zbe, 1) \ + + InitSP_ZBE(0); + InitSP_ZBE(1); +} + +IDrawScanline::SetupPrimPtr GSDrawScanline::GSSetupPrimMap::GetDefaultFunction(DWORD dw) +{ + DWORD zbe = (dw >> 0) & 1; + DWORD fge = (dw >> 1) & 1; + DWORD tme = (dw >> 2) & 1; + DWORD fst = (dw >> 3) & 1; + DWORD iip = (dw >> 4) & 1; + + return m_default[zbe][fge][tme][fst][iip]; +} + +// + +const GSVector4 GSDrawScanline::m_shift[4] = +{ + GSVector4(0.0f, 1.0f, 2.0f, 3.0f), + GSVector4(-1.0f, 0.0f, 1.0f, 2.0f), + GSVector4(-2.0f, -1.0f, 0.0f, 1.0f), + GSVector4(-3.0f, -2.0f, -1.0f, 0.0f), +}; + +const GSVector4i GSDrawScanline::m_test[8] = +{ + GSVector4i::zero(), + GSVector4i(0xffffffff, 0x00000000, 0x00000000, 0x00000000), + GSVector4i(0xffffffff, 0xffffffff, 0x00000000, 0x00000000), + GSVector4i(0xffffffff, 0xffffffff, 0xffffffff, 0x00000000), + GSVector4i(0x00000000, 0xffffffff, 0xffffffff, 0xffffffff), + GSVector4i(0x00000000, 0x00000000, 0xffffffff, 0xffffffff), + GSVector4i(0x00000000, 0x00000000, 0x00000000, 0xffffffff), + GSVector4i::zero(), +}; diff --git a/plugins/GSdx/GSDrawScanline.h b/plugins/GSdx/GSDrawScanline.h index 8d63a29191..5e84bf371c 100644 --- a/plugins/GSdx/GSDrawScanline.h +++ b/plugins/GSdx/GSDrawScanline.h @@ -1,217 +1,217 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSState.h" -#include "GSRasterizer.h" -#include "GSAlignedClass.h" - -union GSScanlineSelector -{ - struct - { - DWORD fpsm:2; // 0 - DWORD zpsm:2; // 2 - DWORD ztst:2; // 4 (0: off, 1: write, 2: test (ge), 3: test (g)) - DWORD atst:3; // 6 - DWORD afail:2; // 9 - DWORD iip:1; // 11 - DWORD tfx:3; // 12 - DWORD tcc:1; // 15 - DWORD fst:1; // 16 - DWORD ltf:1; // 17 - DWORD tlu:1; // 18 - DWORD fge:1; // 19 - DWORD date:1; // 20 - DWORD abea:2; // 21 - DWORD abeb:2; // 23 - DWORD abec:2; // 25 - DWORD abed:2; // 27 - DWORD pabe:1; // 29 - DWORD rfb:1; // 30 - DWORD sprite:1; // 31 - }; - - struct - { - DWORD _pad1:21; - DWORD abe:8; - DWORD _pad2:3; - }; - - DWORD dw; - - operator DWORD() {return dw;} - - bool IsSolidRect() - { - return sprite - && iip == 0 - && tfx == TFX_NONE - && abe == 255 - && ztst <= 1 - && atst <= 1 - && date == 0 - && fge == 0; - } -}; - -__declspec(align(16)) struct GSScanlineEnvironment -{ - GSScanlineSelector sel; - - void* vm; - const void* tex; - const DWORD* clut; - DWORD tw; - - GSVector4i* fbr; - GSVector4i* zbr; - int** fbc; - int** zbc; - GSVector2i* fzbr; - GSVector2i* fzbc; - - GSVector4i fm, zm; - struct {GSVector4i min, max, mask;} t; // [u] x 4 [v] x 4 - GSVector4i datm; - GSVector4i colclamp; - GSVector4i fba; - GSVector4i aref; - GSVector4i afix, afix2; - GSVector4i frb, fga; - - struct {GSVector4 z, s, t, q; GSVector4i rb, ga, f, si, ti, _pad[3];} d[4]; - struct {GSVector4 z, stq; GSVector4i c, f, st;} d4; - struct {GSVector4i rb, ga;} c; - struct {GSVector4i z, f;} p; - struct {GSVector4i rb, ga;} c2; -}; - -__declspec(align(16)) struct GSScanlineParam -{ - GSScanlineSelector sel; - - void* vm; - const void* tex; - const DWORD* clut; - DWORD tw; - - GSLocalMemory::Offset* fbo; - GSLocalMemory::Offset* zbo; - GSLocalMemory::Offset4* fzbo; - - DWORD fm, zm; -}; - -class GSDrawScanline : public GSAlignedClass<16>, public IDrawScanline -{ - GSScanlineEnvironment m_env; - - static const GSVector4 m_shift[4]; - static const GSVector4i m_test[8]; - - // - - class GSDrawScanlineMap : public GSFunctionMap - { - DrawScanlinePtr m_default[4][4][4][2]; - - public: - GSDrawScanlineMap(); - - DrawScanlinePtr GetDefaultFunction(DWORD dw); - - void PrintStats(); - }; - - GSDrawScanlineMap m_ds; - - // - - class GSSetupPrimMap : public GSFunctionMap - { - SetupPrimPtr m_default[2][2][2][2][2]; - - public: - GSSetupPrimMap(); - - SetupPrimPtr GetDefaultFunction(DWORD dw); - }; - - GSSetupPrimMap m_sp; - - // - - template - void SetupPrim(const GSVertexSW* vertices, const GSVertexSW& dscan); - - // - - __forceinline GSVector4i Wrap(const GSVector4i& t); - - __forceinline void SampleTexture(DWORD ltf, DWORD tlu, const GSVector4i& u, const GSVector4i& v, GSVector4i* c); - __forceinline void ColorTFX(DWORD iip, DWORD tfx, const GSVector4i& rbf, const GSVector4i& gaf, GSVector4i& rbt, GSVector4i& gat); - __forceinline void AlphaTFX(DWORD iip, DWORD tfx, DWORD tcc, const GSVector4i& gaf, GSVector4i& gat); - __forceinline void Fog(DWORD fge, const GSVector4i& f, GSVector4i& rb, GSVector4i& ga); - __forceinline bool TestZ(DWORD zpsm, DWORD ztst, const GSVector4i& zs, const GSVector4i& zd, GSVector4i& test); - __forceinline bool TestAlpha(DWORD atst, DWORD afail, const GSVector4i& ga, GSVector4i& fm, GSVector4i& zm, GSVector4i& test); - __forceinline bool TestDestAlpha(DWORD fpsm, DWORD date, const GSVector4i& fd, GSVector4i& test); - - __forceinline void ReadPixel(int psm, int addr, GSVector4i& c) const; - __forceinline static void WritePixel(int psm, WORD* RESTRICT vm16, DWORD c); - __forceinline void WriteFrame(int fpsm, int rfb, GSVector4i* c, const GSVector4i& fd, const GSVector4i& fm, int addr, int fzm); - __forceinline void WriteZBuf(int zpsm, int ztst, const GSVector4i& z, const GSVector4i& zd, const GSVector4i& zm, int addr, int fzm); - - template - void DrawScanline(int top, int left, int right, const GSVertexSW& v); - - template - void DrawScanlineEx(int top, int left, int right, const GSVertexSW& v); - - // - - void DrawSolidRect(const GSVector4i& r, const GSVertexSW& v); - - template - void DrawSolidRectT(const GSVector4i* row, int* col, const GSVector4i& r, DWORD c, DWORD m); - - template - __forceinline void FillRect(const GSVector4i* row, int* col, const GSVector4i& r, DWORD c, DWORD m); - - template - __forceinline void FillBlock(const GSVector4i* row, int* col, const GSVector4i& r, const GSVector4i& c, const GSVector4i& m); - -protected: - GSState* m_state; - int m_id; - -public: - GSDrawScanline(GSState* state, int id); - virtual ~GSDrawScanline(); - - // IDrawScanline - - void BeginDraw(const GSRasterizerData* data, Functions* f); - void EndDraw(const GSRasterizerStats& stats); - void PrintStats() {m_ds.PrintStats();} -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSState.h" +#include "GSRasterizer.h" +#include "GSAlignedClass.h" + +union GSScanlineSelector +{ + struct + { + DWORD fpsm:2; // 0 + DWORD zpsm:2; // 2 + DWORD ztst:2; // 4 (0: off, 1: write, 2: test (ge), 3: test (g)) + DWORD atst:3; // 6 + DWORD afail:2; // 9 + DWORD iip:1; // 11 + DWORD tfx:3; // 12 + DWORD tcc:1; // 15 + DWORD fst:1; // 16 + DWORD ltf:1; // 17 + DWORD tlu:1; // 18 + DWORD fge:1; // 19 + DWORD date:1; // 20 + DWORD abea:2; // 21 + DWORD abeb:2; // 23 + DWORD abec:2; // 25 + DWORD abed:2; // 27 + DWORD pabe:1; // 29 + DWORD rfb:1; // 30 + DWORD sprite:1; // 31 + }; + + struct + { + DWORD _pad1:21; + DWORD abe:8; + DWORD _pad2:3; + }; + + DWORD dw; + + operator DWORD() {return dw;} + + bool IsSolidRect() + { + return sprite + && iip == 0 + && tfx == TFX_NONE + && abe == 255 + && ztst <= 1 + && atst <= 1 + && date == 0 + && fge == 0; + } +}; + +__declspec(align(16)) struct GSScanlineEnvironment +{ + GSScanlineSelector sel; + + void* vm; + const void* tex; + const DWORD* clut; + DWORD tw; + + GSVector4i* fbr; + GSVector4i* zbr; + int** fbc; + int** zbc; + GSVector2i* fzbr; + GSVector2i* fzbc; + + GSVector4i fm, zm; + struct {GSVector4i min, max, mask;} t; // [u] x 4 [v] x 4 + GSVector4i datm; + GSVector4i colclamp; + GSVector4i fba; + GSVector4i aref; + GSVector4i afix, afix2; + GSVector4i frb, fga; + + struct {GSVector4 z, s, t, q; GSVector4i rb, ga, f, si, ti, _pad[3];} d[4]; + struct {GSVector4 z, stq; GSVector4i c, f, st;} d4; + struct {GSVector4i rb, ga;} c; + struct {GSVector4i z, f;} p; + struct {GSVector4i rb, ga;} c2; +}; + +__declspec(align(16)) struct GSScanlineParam +{ + GSScanlineSelector sel; + + void* vm; + const void* tex; + const DWORD* clut; + DWORD tw; + + GSLocalMemory::Offset* fbo; + GSLocalMemory::Offset* zbo; + GSLocalMemory::Offset4* fzbo; + + DWORD fm, zm; +}; + +class GSDrawScanline : public GSAlignedClass<16>, public IDrawScanline +{ + GSScanlineEnvironment m_env; + + static const GSVector4 m_shift[4]; + static const GSVector4i m_test[8]; + + // + + class GSDrawScanlineMap : public GSFunctionMap + { + DrawScanlinePtr m_default[4][4][4][2]; + + public: + GSDrawScanlineMap(); + + DrawScanlinePtr GetDefaultFunction(DWORD dw); + + void PrintStats(); + }; + + GSDrawScanlineMap m_ds; + + // + + class GSSetupPrimMap : public GSFunctionMap + { + SetupPrimPtr m_default[2][2][2][2][2]; + + public: + GSSetupPrimMap(); + + SetupPrimPtr GetDefaultFunction(DWORD dw); + }; + + GSSetupPrimMap m_sp; + + // + + template + void SetupPrim(const GSVertexSW* vertices, const GSVertexSW& dscan); + + // + + __forceinline GSVector4i Wrap(const GSVector4i& t); + + __forceinline void SampleTexture(DWORD ltf, DWORD tlu, const GSVector4i& u, const GSVector4i& v, GSVector4i* c); + __forceinline void ColorTFX(DWORD iip, DWORD tfx, const GSVector4i& rbf, const GSVector4i& gaf, GSVector4i& rbt, GSVector4i& gat); + __forceinline void AlphaTFX(DWORD iip, DWORD tfx, DWORD tcc, const GSVector4i& gaf, GSVector4i& gat); + __forceinline void Fog(DWORD fge, const GSVector4i& f, GSVector4i& rb, GSVector4i& ga); + __forceinline bool TestZ(DWORD zpsm, DWORD ztst, const GSVector4i& zs, const GSVector4i& zd, GSVector4i& test); + __forceinline bool TestAlpha(DWORD atst, DWORD afail, const GSVector4i& ga, GSVector4i& fm, GSVector4i& zm, GSVector4i& test); + __forceinline bool TestDestAlpha(DWORD fpsm, DWORD date, const GSVector4i& fd, GSVector4i& test); + + __forceinline void ReadPixel(int psm, int addr, GSVector4i& c) const; + __forceinline static void WritePixel(int psm, WORD* RESTRICT vm16, DWORD c); + __forceinline void WriteFrame(int fpsm, int rfb, GSVector4i* c, const GSVector4i& fd, const GSVector4i& fm, int addr, int fzm); + __forceinline void WriteZBuf(int zpsm, int ztst, const GSVector4i& z, const GSVector4i& zd, const GSVector4i& zm, int addr, int fzm); + + template + void DrawScanline(int top, int left, int right, const GSVertexSW& v); + + template + void DrawScanlineEx(int top, int left, int right, const GSVertexSW& v); + + // + + void DrawSolidRect(const GSVector4i& r, const GSVertexSW& v); + + template + void DrawSolidRectT(const GSVector4i* row, int* col, const GSVector4i& r, DWORD c, DWORD m); + + template + __forceinline void FillRect(const GSVector4i* row, int* col, const GSVector4i& r, DWORD c, DWORD m); + + template + __forceinline void FillBlock(const GSVector4i* row, int* col, const GSVector4i& r, const GSVector4i& c, const GSVector4i& m); + +protected: + GSState* m_state; + int m_id; + +public: + GSDrawScanline(GSState* state, int id); + virtual ~GSDrawScanline(); + + // IDrawScanline + + void BeginDraw(const GSRasterizerData* data, Functions* f); + void EndDraw(const GSRasterizerStats& stats); + void PrintStats() {m_ds.PrintStats();} +}; diff --git a/plugins/GSdx/GSDrawingContext.h b/plugins/GSdx/GSDrawingContext.h index 86cfae4855..0f72f2f930 100644 --- a/plugins/GSdx/GSDrawingContext.h +++ b/plugins/GSdx/GSDrawingContext.h @@ -1,115 +1,115 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GS.h" -#include "GSLocalMemory.h" - -#pragma pack(push, 1) - -__declspec(align(16)) class GSDrawingContext -{ -public: - GIFRegXYOFFSET XYOFFSET; - GIFRegTEX0 TEX0; - GIFRegTEX1 TEX1; - GIFRegTEX2 TEX2; - GIFRegCLAMP CLAMP; - GIFRegMIPTBP1 MIPTBP1; - GIFRegMIPTBP2 MIPTBP2; - GIFRegSCISSOR SCISSOR; - GIFRegALPHA ALPHA; - GIFRegTEST TEST; - GIFRegFBA FBA; - GIFRegFRAME FRAME; - GIFRegZBUF ZBUF; - - __declspec(align(16)) struct - { - GSVector4i dx10; - GSVector4 dx9; - GSVector4 in; - GSVector4 ex; - } scissor; - - GSDrawingContext() - { - Reset(); - } - - void Reset() - { - memset(&XYOFFSET, 0, sizeof(XYOFFSET)); - memset(&TEX0, 0, sizeof(TEX0)); - memset(&TEX1, 0, sizeof(TEX1)); - memset(&TEX2, 0, sizeof(TEX2)); - memset(&CLAMP, 0, sizeof(CLAMP)); - memset(&MIPTBP1, 0, sizeof(MIPTBP1)); - memset(&MIPTBP2, 0, sizeof(MIPTBP2)); - memset(&SCISSOR, 0, sizeof(SCISSOR)); - memset(&ALPHA, 0, sizeof(ALPHA)); - memset(&TEST, 0, sizeof(TEST)); - memset(&FBA, 0, sizeof(FBA)); - memset(&FRAME, 0, sizeof(FRAME)); - memset(&ZBUF, 0, sizeof(ZBUF)); - } - - void UpdateScissor() - { - scissor.dx10 = GSVector4i( - (int)((SCISSOR.SCAX0 << 4) + XYOFFSET.OFX), - (int)((SCISSOR.SCAY0 << 4) + XYOFFSET.OFY), - (int)((SCISSOR.SCAX1 << 4) + XYOFFSET.OFX), - (int)((SCISSOR.SCAY1 << 4) + XYOFFSET.OFY)); - - scissor.dx9 = GSVector4(scissor.dx10); - - scissor.in = GSVector4( - (int)SCISSOR.SCAX0, - (int)SCISSOR.SCAY0, - (int)SCISSOR.SCAX1 + 1, - (int)SCISSOR.SCAY1 + 1); - - scissor.ex = GSVector4i( - (int)SCISSOR.SCAX0, - (int)SCISSOR.SCAY0, - (int)SCISSOR.SCAX1, - (int)SCISSOR.SCAY1); - } - - bool DepthRead() const - { - return TEST.ZTE && TEST.ZTST >= 2; - } - - bool DepthWrite() const - { - if(TEST.ATE && TEST.ATST == ATST_NEVER && TEST.AFAIL != AFAIL_ZB_ONLY) // alpha test, all pixels fail, z buffer is not updated - { - return false; - } - - return ZBUF.ZMSK == 0 && TEST.ZTE != 0; // ZTE == 0 is bug on the real hardware, write is blocked then - } -}; - +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GS.h" +#include "GSLocalMemory.h" + +#pragma pack(push, 1) + +__declspec(align(16)) class GSDrawingContext +{ +public: + GIFRegXYOFFSET XYOFFSET; + GIFRegTEX0 TEX0; + GIFRegTEX1 TEX1; + GIFRegTEX2 TEX2; + GIFRegCLAMP CLAMP; + GIFRegMIPTBP1 MIPTBP1; + GIFRegMIPTBP2 MIPTBP2; + GIFRegSCISSOR SCISSOR; + GIFRegALPHA ALPHA; + GIFRegTEST TEST; + GIFRegFBA FBA; + GIFRegFRAME FRAME; + GIFRegZBUF ZBUF; + + __declspec(align(16)) struct + { + GSVector4i dx10; + GSVector4 dx9; + GSVector4 in; + GSVector4 ex; + } scissor; + + GSDrawingContext() + { + Reset(); + } + + void Reset() + { + memset(&XYOFFSET, 0, sizeof(XYOFFSET)); + memset(&TEX0, 0, sizeof(TEX0)); + memset(&TEX1, 0, sizeof(TEX1)); + memset(&TEX2, 0, sizeof(TEX2)); + memset(&CLAMP, 0, sizeof(CLAMP)); + memset(&MIPTBP1, 0, sizeof(MIPTBP1)); + memset(&MIPTBP2, 0, sizeof(MIPTBP2)); + memset(&SCISSOR, 0, sizeof(SCISSOR)); + memset(&ALPHA, 0, sizeof(ALPHA)); + memset(&TEST, 0, sizeof(TEST)); + memset(&FBA, 0, sizeof(FBA)); + memset(&FRAME, 0, sizeof(FRAME)); + memset(&ZBUF, 0, sizeof(ZBUF)); + } + + void UpdateScissor() + { + scissor.dx10 = GSVector4i( + (int)((SCISSOR.SCAX0 << 4) + XYOFFSET.OFX), + (int)((SCISSOR.SCAY0 << 4) + XYOFFSET.OFY), + (int)((SCISSOR.SCAX1 << 4) + XYOFFSET.OFX), + (int)((SCISSOR.SCAY1 << 4) + XYOFFSET.OFY)); + + scissor.dx9 = GSVector4(scissor.dx10); + + scissor.in = GSVector4( + (int)SCISSOR.SCAX0, + (int)SCISSOR.SCAY0, + (int)SCISSOR.SCAX1 + 1, + (int)SCISSOR.SCAY1 + 1); + + scissor.ex = GSVector4i( + (int)SCISSOR.SCAX0, + (int)SCISSOR.SCAY0, + (int)SCISSOR.SCAX1, + (int)SCISSOR.SCAY1); + } + + bool DepthRead() const + { + return TEST.ZTE && TEST.ZTST >= 2; + } + + bool DepthWrite() const + { + if(TEST.ATE && TEST.ATST == ATST_NEVER && TEST.AFAIL != AFAIL_ZB_ONLY) // alpha test, all pixels fail, z buffer is not updated + { + return false; + } + + return ZBUF.ZMSK == 0 && TEST.ZTE != 0; // ZTE == 0 is bug on the real hardware, write is blocked then + } +}; + #pragma pack(pop) \ No newline at end of file diff --git a/plugins/GSdx/GSDrawingEnvironment.h b/plugins/GSdx/GSDrawingEnvironment.h index 2ac74cdb3c..604d95ac4d 100644 --- a/plugins/GSdx/GSDrawingEnvironment.h +++ b/plugins/GSdx/GSDrawingEnvironment.h @@ -1,77 +1,77 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GS.h" - -#pragma pack(push, 1) - -__declspec(align(16)) class GSDrawingEnvironment -{ -public: - GIFRegPRIM PRIM; - GIFRegPRMODE PRMODE; - GIFRegPRMODECONT PRMODECONT; - GIFRegTEXCLUT TEXCLUT; - GIFRegSCANMSK SCANMSK; - GIFRegTEXA TEXA; - GIFRegFOGCOL FOGCOL; - GIFRegDIMX DIMX; - GIFRegDTHE DTHE; - GIFRegCOLCLAMP COLCLAMP; - GIFRegPABE PABE; - GIFRegBITBLTBUF BITBLTBUF; - GIFRegTRXDIR TRXDIR; - GIFRegTRXPOS TRXPOS; - GIFRegTRXREG TRXREG; - GIFRegTRXREG TRXREG2; - GSDrawingContext CTXT[2]; - - GSDrawingEnvironment() - { - } - - void Reset() - { - memset(&PRIM, 0, sizeof(PRIM)); - memset(&PRMODE, 0, sizeof(PRMODE)); - memset(&PRMODECONT, 0, sizeof(PRMODECONT)); - memset(&TEXCLUT, 0, sizeof(TEXCLUT)); - memset(&SCANMSK, 0, sizeof(SCANMSK)); - memset(&TEXA, 0, sizeof(TEXA)); - memset(&FOGCOL, 0, sizeof(FOGCOL)); - memset(&DIMX, 0, sizeof(DIMX)); - memset(&DTHE, 0, sizeof(DTHE)); - memset(&COLCLAMP, 0, sizeof(COLCLAMP)); - memset(&PABE, 0, sizeof(PABE)); - memset(&BITBLTBUF, 0, sizeof(BITBLTBUF)); - memset(&TRXDIR, 0, sizeof(TRXDIR)); - memset(&TRXPOS, 0, sizeof(TRXPOS)); - memset(&TRXREG, 0, sizeof(TRXREG)); - memset(&TRXREG2, 0, sizeof(TRXREG2)); - - CTXT[0].Reset(); - CTXT[1].Reset(); - } -}; - -#pragma pack(pop) +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GS.h" + +#pragma pack(push, 1) + +__declspec(align(16)) class GSDrawingEnvironment +{ +public: + GIFRegPRIM PRIM; + GIFRegPRMODE PRMODE; + GIFRegPRMODECONT PRMODECONT; + GIFRegTEXCLUT TEXCLUT; + GIFRegSCANMSK SCANMSK; + GIFRegTEXA TEXA; + GIFRegFOGCOL FOGCOL; + GIFRegDIMX DIMX; + GIFRegDTHE DTHE; + GIFRegCOLCLAMP COLCLAMP; + GIFRegPABE PABE; + GIFRegBITBLTBUF BITBLTBUF; + GIFRegTRXDIR TRXDIR; + GIFRegTRXPOS TRXPOS; + GIFRegTRXREG TRXREG; + GIFRegTRXREG TRXREG2; + GSDrawingContext CTXT[2]; + + GSDrawingEnvironment() + { + } + + void Reset() + { + memset(&PRIM, 0, sizeof(PRIM)); + memset(&PRMODE, 0, sizeof(PRMODE)); + memset(&PRMODECONT, 0, sizeof(PRMODECONT)); + memset(&TEXCLUT, 0, sizeof(TEXCLUT)); + memset(&SCANMSK, 0, sizeof(SCANMSK)); + memset(&TEXA, 0, sizeof(TEXA)); + memset(&FOGCOL, 0, sizeof(FOGCOL)); + memset(&DIMX, 0, sizeof(DIMX)); + memset(&DTHE, 0, sizeof(DTHE)); + memset(&COLCLAMP, 0, sizeof(COLCLAMP)); + memset(&PABE, 0, sizeof(PABE)); + memset(&BITBLTBUF, 0, sizeof(BITBLTBUF)); + memset(&TRXDIR, 0, sizeof(TRXDIR)); + memset(&TRXPOS, 0, sizeof(TRXPOS)); + memset(&TRXREG, 0, sizeof(TRXREG)); + memset(&TRXREG2, 0, sizeof(TRXREG2)); + + CTXT[0].Reset(); + CTXT[1].Reset(); + } +}; + +#pragma pack(pop) diff --git a/plugins/GSdx/GSDump.cpp b/plugins/GSdx/GSDump.cpp index 050365f498..5d14920cdc 100644 --- a/plugins/GSdx/GSDump.cpp +++ b/plugins/GSdx/GSDump.cpp @@ -1,88 +1,88 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSDump.h" - -GSDump::GSDump() - : m_fp(NULL) -{ -} - -GSDump::~GSDump() -{ - if(m_fp) - { - fclose(m_fp); - } -} - -void GSDump::Open(LPCTSTR fn, DWORD crc, const GSFreezeData& fd, const void* regs) -{ - m_fp = _tfopen(fn, _T("wb")); - m_vsyncs = 0; - - if(m_fp) - { - fwrite(&crc, 4, 1, m_fp); - fwrite(&fd.size, 4, 1, m_fp); - fwrite(fd.data, fd.size, 1, m_fp); - fwrite(regs, 0x2000, 1, m_fp); - } -} - -void GSDump::Transfer(int index, BYTE* mem, size_t size) -{ - if(m_fp && size > 0) - { - fputc(0, m_fp); - fputc(index, m_fp); - fwrite(&size, 4, 1, m_fp); - fwrite(mem, size, 1, m_fp); - } -} - -void GSDump::ReadFIFO(UINT32 size) -{ - if(m_fp && size > 0) - { - fputc(2, m_fp); - fwrite(&size, 4, 1, m_fp); - } -} - -void GSDump::VSync(int field, bool last, const void* regs) -{ - if(m_fp) - { - fputc(3, m_fp); - fwrite(regs, 0x2000, 1, m_fp); - - fputc(1, m_fp); - fputc(field, m_fp); - - if((++m_vsyncs & 1) == 0 && last) - { - fclose(m_fp); - m_fp = NULL; - } - } -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSDump.h" + +GSDump::GSDump() + : m_fp(NULL) +{ +} + +GSDump::~GSDump() +{ + if(m_fp) + { + fclose(m_fp); + } +} + +void GSDump::Open(LPCTSTR fn, DWORD crc, const GSFreezeData& fd, const void* regs) +{ + m_fp = _tfopen(fn, _T("wb")); + m_vsyncs = 0; + + if(m_fp) + { + fwrite(&crc, 4, 1, m_fp); + fwrite(&fd.size, 4, 1, m_fp); + fwrite(fd.data, fd.size, 1, m_fp); + fwrite(regs, 0x2000, 1, m_fp); + } +} + +void GSDump::Transfer(int index, BYTE* mem, size_t size) +{ + if(m_fp && size > 0) + { + fputc(0, m_fp); + fputc(index, m_fp); + fwrite(&size, 4, 1, m_fp); + fwrite(mem, size, 1, m_fp); + } +} + +void GSDump::ReadFIFO(UINT32 size) +{ + if(m_fp && size > 0) + { + fputc(2, m_fp); + fwrite(&size, 4, 1, m_fp); + } +} + +void GSDump::VSync(int field, bool last, const void* regs) +{ + if(m_fp) + { + fputc(3, m_fp); + fwrite(regs, 0x2000, 1, m_fp); + + fputc(1, m_fp); + fputc(field, m_fp); + + if((++m_vsyncs & 1) == 0 && last) + { + fclose(m_fp); + m_fp = NULL; + } + } +} diff --git a/plugins/GSdx/GSDump.h b/plugins/GSdx/GSDump.h index da6cb74898..fe96423ffe 100644 --- a/plugins/GSdx/GSDump.h +++ b/plugins/GSdx/GSDump.h @@ -1,59 +1,59 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GS.h" - -/* - -Dump file format: -- [crc/4] [state size/4] [state data/size] [PMODE/0x2000] [id/1] [data/?] .. [id/1] [data/?] - -Transfer data (id == 0) -- [0/1] [path index/1] [size/4] [data/size] - -VSync data (id == 1) -- [1/1] [field/1] - -ReadFIFO2 data (id == 2) -- [2/1] [size/?] - -Regs data (id == 3) -- [PMODE/0x2000] - -*/ - -class GSDump -{ - FILE* m_fp; - int m_vsyncs; - -public: - GSDump(); - virtual ~GSDump(); - - void Open(LPCTSTR fn, DWORD crc, const GSFreezeData& fd, const void* regs); - void ReadFIFO(UINT32 size); - void Transfer(int index, BYTE* mem, size_t size); - void VSync(int field, bool last, const void* regs); - operator bool() {return m_fp != NULL;} -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GS.h" + +/* + +Dump file format: +- [crc/4] [state size/4] [state data/size] [PMODE/0x2000] [id/1] [data/?] .. [id/1] [data/?] + +Transfer data (id == 0) +- [0/1] [path index/1] [size/4] [data/size] + +VSync data (id == 1) +- [1/1] [field/1] + +ReadFIFO2 data (id == 2) +- [2/1] [size/?] + +Regs data (id == 3) +- [PMODE/0x2000] + +*/ + +class GSDump +{ + FILE* m_fp; + int m_vsyncs; + +public: + GSDump(); + virtual ~GSDump(); + + void Open(LPCTSTR fn, DWORD crc, const GSFreezeData& fd, const void* regs); + void ReadFIFO(UINT32 size); + void Transfer(int index, BYTE* mem, size_t size); + void VSync(int field, bool last, const void* regs); + operator bool() {return m_fp != NULL;} +}; diff --git a/plugins/GSdx/GSFunctionMap.cpp b/plugins/GSdx/GSFunctionMap.cpp index 37cd38e946..48e77b465e 100644 --- a/plugins/GSdx/GSFunctionMap.cpp +++ b/plugins/GSdx/GSFunctionMap.cpp @@ -1,24 +1,24 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSFunctionMap.h" - +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSFunctionMap.h" + diff --git a/plugins/GSdx/GSFunctionMap.h b/plugins/GSdx/GSFunctionMap.h index 8867311ebc..48e8133196 100644 --- a/plugins/GSdx/GSFunctionMap.h +++ b/plugins/GSdx/GSFunctionMap.h @@ -1,161 +1,161 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GS.h" - -struct GSRasterizerStats -{ - __int64 ticks; - int prims, pixels; - - GSRasterizerStats() - { - Reset(); - } - - void Reset() - { - ticks = 0; - pixels = prims = 0; - } -}; - -template class GSFunctionMap -{ -protected: - struct ActivePtr - { - UINT64 frame, frames; - __int64 ticks, pixels; - T f; - }; - - CRBMap m_map; - CRBMap m_map_active; - ActivePtr* m_active; - - virtual T GetDefaultFunction(DWORD sel) = 0; - -public: - GSFunctionMap() - : m_active(NULL) - { - } - - virtual ~GSFunctionMap() - { - POSITION pos = m_map_active.GetHeadPosition(); - - while(pos) - { - delete m_map_active.GetNextValue(pos); - } - - m_map_active.RemoveAll(); - } - - void SetAt(DWORD sel, T f) - { - m_map.SetAt(sel, f); - } - - T Lookup(DWORD sel) - { - m_active = NULL; - - if(!m_map_active.Lookup(sel, m_active)) - { - CRBMap::CPair* pair = m_map.Lookup(sel); - - ActivePtr* p = new ActivePtr(); - - memset(p, 0, sizeof(*p)); - - p->frame = (UINT64)-1; - - p->f = pair ? pair->m_value : GetDefaultFunction(sel); - - m_map_active.SetAt(sel, p); - - m_active = p; - } - - return m_active->f; - } - - void UpdateStats(const GSRasterizerStats& stats, UINT64 frame) - { - if(m_active) - { - if(m_active->frame != frame) - { - m_active->frame = frame; - m_active->frames++; - } - - m_active->pixels += stats.pixels; - m_active->ticks += stats.ticks; - } - } - - virtual void PrintStats() - { - __int64 ttpf = 0; - - POSITION pos = m_map_active.GetHeadPosition(); - - while(pos) - { - ActivePtr* p = m_map_active.GetNextValue(pos); - - if(p->frames) - { - ttpf += p->ticks / p->frames; - } - } - - pos = m_map_active.GetHeadPosition(); - - while(pos) - { - DWORD sel; - ActivePtr* p; - - m_map_active.GetNextAssoc(pos, sel, p); - - if(p->frames > 0) - { - __int64 tpp = p->pixels > 0 ? p->ticks / p->pixels : 0; - __int64 tpf = p->frames > 0 ? p->ticks / p->frames : 0; - __int64 ppf = p->frames > 0 ? p->pixels / p->frames : 0; - - printf("[%08x]%c %6.2f%% | %5.2f%% | f %4I64d | p %10I64d | tpp %4I64d | tpf %9I64d | ppf %7I64d\n", - sel, !m_map.Lookup(sel) ? '*' : ' ', - (float)(tpf * 10000 / 50000000) / 100, - (float)(tpf * 10000 / ttpf) / 100, - p->frames, p->pixels, - tpp, tpf, ppf); - } - } - } -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GS.h" + +struct GSRasterizerStats +{ + __int64 ticks; + int prims, pixels; + + GSRasterizerStats() + { + Reset(); + } + + void Reset() + { + ticks = 0; + pixels = prims = 0; + } +}; + +template class GSFunctionMap +{ +protected: + struct ActivePtr + { + UINT64 frame, frames; + __int64 ticks, pixels; + T f; + }; + + CRBMap m_map; + CRBMap m_map_active; + ActivePtr* m_active; + + virtual T GetDefaultFunction(DWORD sel) = 0; + +public: + GSFunctionMap() + : m_active(NULL) + { + } + + virtual ~GSFunctionMap() + { + POSITION pos = m_map_active.GetHeadPosition(); + + while(pos) + { + delete m_map_active.GetNextValue(pos); + } + + m_map_active.RemoveAll(); + } + + void SetAt(DWORD sel, T f) + { + m_map.SetAt(sel, f); + } + + T Lookup(DWORD sel) + { + m_active = NULL; + + if(!m_map_active.Lookup(sel, m_active)) + { + CRBMap::CPair* pair = m_map.Lookup(sel); + + ActivePtr* p = new ActivePtr(); + + memset(p, 0, sizeof(*p)); + + p->frame = (UINT64)-1; + + p->f = pair ? pair->m_value : GetDefaultFunction(sel); + + m_map_active.SetAt(sel, p); + + m_active = p; + } + + return m_active->f; + } + + void UpdateStats(const GSRasterizerStats& stats, UINT64 frame) + { + if(m_active) + { + if(m_active->frame != frame) + { + m_active->frame = frame; + m_active->frames++; + } + + m_active->pixels += stats.pixels; + m_active->ticks += stats.ticks; + } + } + + virtual void PrintStats() + { + __int64 ttpf = 0; + + POSITION pos = m_map_active.GetHeadPosition(); + + while(pos) + { + ActivePtr* p = m_map_active.GetNextValue(pos); + + if(p->frames) + { + ttpf += p->ticks / p->frames; + } + } + + pos = m_map_active.GetHeadPosition(); + + while(pos) + { + DWORD sel; + ActivePtr* p; + + m_map_active.GetNextAssoc(pos, sel, p); + + if(p->frames > 0) + { + __int64 tpp = p->pixels > 0 ? p->ticks / p->pixels : 0; + __int64 tpf = p->frames > 0 ? p->ticks / p->frames : 0; + __int64 ppf = p->frames > 0 ? p->pixels / p->frames : 0; + + printf("[%08x]%c %6.2f%% | %5.2f%% | f %4I64d | p %10I64d | tpp %4I64d | tpf %9I64d | ppf %7I64d\n", + sel, !m_map.Lookup(sel) ? '*' : ' ', + (float)(tpf * 10000 / 50000000) / 100, + (float)(tpf * 10000 / ttpf) / 100, + p->frames, p->pixels, + tpp, tpf, ppf); + } + } + } +}; diff --git a/plugins/GSdx/GSLocalMemory.cpp b/plugins/GSdx/GSLocalMemory.cpp index 80c66b6c7e..27a26e46a2 100644 --- a/plugins/GSdx/GSLocalMemory.cpp +++ b/plugins/GSdx/GSLocalMemory.cpp @@ -1,2399 +1,2399 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - * Special Notes: - * - * Based on Page.c from GSSoft - * Copyright (C) 2002-2004 GSsoft Team - * - */ - -#include "StdAfx.h" -#include "GSLocalMemory.h" - -#define ASSERT_BLOCK(r, w, h) \ - ASSERT((r).Width() >= w && (r).Height() >= h && !((r).left&(w-1)) && !((r).top&(h-1)) && !((r).right&(w-1)) && !((r).bottom&(h-1))); \ - -#define FOREACH_BLOCK_START(w, h, bpp) \ - DWORD bp = TEX0.TBP0; \ - DWORD bw = TEX0.TBW; \ - int offset = dstpitch * h - (r.right - r.left) * bpp / 8; \ - for(int y = r.top; y < r.bottom; y += h, dst += offset) \ - { ASSERT_BLOCK(r, w, h); \ - for(int x = r.left; x < r.right; x += w, dst += w * bpp / 8) \ - { \ - -#define FOREACH_BLOCK_END }} - -// - -DWORD GSLocalMemory::pageOffset32[32][32][64]; -DWORD GSLocalMemory::pageOffset32Z[32][32][64]; -DWORD GSLocalMemory::pageOffset16[32][64][64]; -DWORD GSLocalMemory::pageOffset16S[32][64][64]; -DWORD GSLocalMemory::pageOffset16Z[32][64][64]; -DWORD GSLocalMemory::pageOffset16SZ[32][64][64]; -DWORD GSLocalMemory::pageOffset8[32][64][128]; -DWORD GSLocalMemory::pageOffset4[32][128][128]; - -int GSLocalMemory::rowOffset32[2048]; -int GSLocalMemory::rowOffset32Z[2048]; -int GSLocalMemory::rowOffset16[2048]; -int GSLocalMemory::rowOffset16S[2048]; -int GSLocalMemory::rowOffset16Z[2048]; -int GSLocalMemory::rowOffset16SZ[2048]; -int GSLocalMemory::rowOffset8[2][2048]; -int GSLocalMemory::rowOffset4[2][2048]; - -// - -DWORD GSLocalMemory::m_xtbl[1024]; -DWORD GSLocalMemory::m_ytbl[1024]; - -// - -GSLocalMemory::psm_t GSLocalMemory::m_psm[64]; - -// - -GSLocalMemory::GSLocalMemory() - : m_clut(this) -{ - m_vm8 = (BYTE*)VirtualAlloc(NULL, m_vmsize * 2, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - - memset(m_vm8, 0, m_vmsize); - - for(int bp = 0; bp < 32; bp++) - { - for(int y = 0; y < 32; y++) for(int x = 0; x < 64; x++) - { - pageOffset32[bp][y][x] = PixelAddressOrg32(x, y, bp, 0); - pageOffset32Z[bp][y][x] = PixelAddressOrg32Z(x, y, bp, 0); - } - - for(int y = 0; y < 64; y++) for(int x = 0; x < 64; x++) - { - pageOffset16[bp][y][x] = PixelAddressOrg16(x, y, bp, 0); - pageOffset16S[bp][y][x] = PixelAddressOrg16S(x, y, bp, 0); - pageOffset16Z[bp][y][x] = PixelAddressOrg16Z(x, y, bp, 0); - pageOffset16SZ[bp][y][x] = PixelAddressOrg16SZ(x, y, bp, 0); - } - - for(int y = 0; y < 64; y++) for(int x = 0; x < 128; x++) - { - pageOffset8[bp][y][x] = PixelAddressOrg8(x, y, bp, 0); - } - - for(int y = 0; y < 128; y++) for(int x = 0; x < 128; x++) - { - pageOffset4[bp][y][x] = PixelAddressOrg4(x, y, bp, 0); - } - } - - for(int x = 0; x < countof(rowOffset32); x++) - { - rowOffset32[x] = (int)PixelAddress32(x, 0, 0, 32) - (int)PixelAddress32(0, 0, 0, 32); - } - - for(int x = 0; x < countof(rowOffset32Z); x++) - { - rowOffset32Z[x] = (int)PixelAddress32Z(x, 0, 0, 32) - (int)PixelAddress32Z(0, 0, 0, 32); - } - - for(int x = 0; x < countof(rowOffset16); x++) - { - rowOffset16[x] = (int)PixelAddress16(x, 0, 0, 32) - (int)PixelAddress16(0, 0, 0, 32); - } - - for(int x = 0; x < countof(rowOffset16S); x++) - { - rowOffset16S[x] = (int)PixelAddress16S(x, 0, 0, 32) - (int)PixelAddress16S(0, 0, 0, 32); - } - - for(int x = 0; x < countof(rowOffset16Z); x++) - { - rowOffset16Z[x] = (int)PixelAddress16Z(x, 0, 0, 32) - (int)PixelAddress16Z(0, 0, 0, 32); - } - - for(int x = 0; x < countof(rowOffset16SZ); x++) - { - rowOffset16SZ[x] = (int)PixelAddress16SZ(x, 0, 0, 32) - (int)PixelAddress16SZ(0, 0, 0, 32); - } - - for(int x = 0; x < countof(rowOffset8[0]); x++) - { - rowOffset8[0][x] = (int)PixelAddress8(x, 0, 0, 32) - (int)PixelAddress8(0, 0, 0, 32), - rowOffset8[1][x] = (int)PixelAddress8(x, 2, 0, 32) - (int)PixelAddress8(0, 2, 0, 32); - } - - for(int x = 0; x < countof(rowOffset4[0]); x++) - { - rowOffset4[0][x] = (int)PixelAddress4(x, 0, 0, 32) - (int)PixelAddress4(0, 0, 0, 32), - rowOffset4[1][x] = (int)PixelAddress4(x, 2, 0, 32) - (int)PixelAddress4(0, 2, 0, 32); - } - - for(int i = 0; i < countof(m_psm); i++) - { - m_psm[i].pa = &GSLocalMemory::PixelAddress32; - m_psm[i].ba = &GSLocalMemory::BlockAddress32; - m_psm[i].pga = &GSLocalMemory::PageAddress32; - m_psm[i].pgn = &GSLocalMemory::PageNumber32; - m_psm[i].rp = &GSLocalMemory::ReadPixel32; - m_psm[i].rpa = &GSLocalMemory::ReadPixel32; - m_psm[i].wp = &GSLocalMemory::WritePixel32; - m_psm[i].wpa = &GSLocalMemory::WritePixel32; - m_psm[i].rt = &GSLocalMemory::ReadTexel32; - m_psm[i].rtNP = &GSLocalMemory::ReadTexel32; - m_psm[i].rta = &GSLocalMemory::ReadTexel32; - m_psm[i].wfa = &GSLocalMemory::WritePixel32; - m_psm[i].wi = &GSLocalMemory::WriteImage; - m_psm[i].ri = &GSLocalMemory::ReadImageX; // TODO - m_psm[i].rtx = &GSLocalMemory::ReadTexture32; - m_psm[i].rtxNP = &GSLocalMemory::ReadTexture32; - m_psm[i].rtxP = &GSLocalMemory::ReadTexture32; - m_psm[i].bpp = m_psm[i].trbpp = 32; - m_psm[i].pal = 0; - m_psm[i].bs = CSize(8, 8); - m_psm[i].pgs = CSize(64, 32); - for(int j = 0; j < 8; j++) m_psm[i].rowOffset[j] = rowOffset32; - } - - m_psm[PSM_PSMCT16].pa = &GSLocalMemory::PixelAddress16; - m_psm[PSM_PSMCT16S].pa = &GSLocalMemory::PixelAddress16S; - m_psm[PSM_PSMT8].pa = &GSLocalMemory::PixelAddress8; - m_psm[PSM_PSMT4].pa = &GSLocalMemory::PixelAddress4; - m_psm[PSM_PSMZ32].pa = &GSLocalMemory::PixelAddress32Z; - m_psm[PSM_PSMZ24].pa = &GSLocalMemory::PixelAddress32Z; - m_psm[PSM_PSMZ16].pa = &GSLocalMemory::PixelAddress16Z; - m_psm[PSM_PSMZ16S].pa = &GSLocalMemory::PixelAddress16SZ; - - m_psm[PSM_PSMCT16].ba = &GSLocalMemory::BlockAddress16; - m_psm[PSM_PSMCT16S].ba = &GSLocalMemory::BlockAddress16S; - m_psm[PSM_PSMT8].ba = &GSLocalMemory::BlockAddress8; - m_psm[PSM_PSMT4].ba = &GSLocalMemory::BlockAddress4; - m_psm[PSM_PSMZ32].ba = &GSLocalMemory::BlockAddress32Z; - m_psm[PSM_PSMZ24].ba = &GSLocalMemory::BlockAddress32Z; - m_psm[PSM_PSMZ16].ba = &GSLocalMemory::BlockAddress16Z; - m_psm[PSM_PSMZ16S].ba = &GSLocalMemory::BlockAddress16SZ; - - m_psm[PSM_PSMCT16].pga = &GSLocalMemory::PageAddress16; - m_psm[PSM_PSMCT16S].pga = &GSLocalMemory::PageAddress16; - m_psm[PSM_PSMZ16].pga = &GSLocalMemory::PageAddress16; - m_psm[PSM_PSMZ16S].pga = &GSLocalMemory::PageAddress16; - m_psm[PSM_PSMT8].pga = &GSLocalMemory::PageAddress8; - m_psm[PSM_PSMT4].pga = &GSLocalMemory::PageAddress4; - - m_psm[PSM_PSMCT16].pgn = &GSLocalMemory::PageNumber16; - m_psm[PSM_PSMCT16S].pgn = &GSLocalMemory::PageNumber16; - m_psm[PSM_PSMZ16].pgn = &GSLocalMemory::PageNumber16; - m_psm[PSM_PSMZ16S].pgn = &GSLocalMemory::PageNumber16; - m_psm[PSM_PSMT8].pgn = &GSLocalMemory::PageNumber8; - m_psm[PSM_PSMT4].pgn = &GSLocalMemory::PageNumber4; - - m_psm[PSM_PSMCT24].rp = &GSLocalMemory::ReadPixel24; - m_psm[PSM_PSMCT16].rp = &GSLocalMemory::ReadPixel16; - m_psm[PSM_PSMCT16S].rp = &GSLocalMemory::ReadPixel16S; - m_psm[PSM_PSMT8].rp = &GSLocalMemory::ReadPixel8; - m_psm[PSM_PSMT4].rp = &GSLocalMemory::ReadPixel4; - m_psm[PSM_PSMT8H].rp = &GSLocalMemory::ReadPixel8H; - m_psm[PSM_PSMT4HL].rp = &GSLocalMemory::ReadPixel4HL; - m_psm[PSM_PSMT4HH].rp = &GSLocalMemory::ReadPixel4HH; - m_psm[PSM_PSMZ32].rp = &GSLocalMemory::ReadPixel32Z; - m_psm[PSM_PSMZ24].rp = &GSLocalMemory::ReadPixel24Z; - m_psm[PSM_PSMZ16].rp = &GSLocalMemory::ReadPixel16Z; - m_psm[PSM_PSMZ16S].rp = &GSLocalMemory::ReadPixel16SZ; - - m_psm[PSM_PSMCT24].rpa = &GSLocalMemory::ReadPixel24; - m_psm[PSM_PSMCT16].rpa = &GSLocalMemory::ReadPixel16; - m_psm[PSM_PSMCT16S].rpa = &GSLocalMemory::ReadPixel16; - m_psm[PSM_PSMT8].rpa = &GSLocalMemory::ReadPixel8; - m_psm[PSM_PSMT4].rpa = &GSLocalMemory::ReadPixel4; - m_psm[PSM_PSMT8H].rpa = &GSLocalMemory::ReadPixel8H; - m_psm[PSM_PSMT4HL].rpa = &GSLocalMemory::ReadPixel4HL; - m_psm[PSM_PSMT4HH].rpa = &GSLocalMemory::ReadPixel4HH; - m_psm[PSM_PSMZ32].rpa = &GSLocalMemory::ReadPixel32; - m_psm[PSM_PSMZ24].rpa = &GSLocalMemory::ReadPixel24; - m_psm[PSM_PSMZ16].rpa = &GSLocalMemory::ReadPixel16; - m_psm[PSM_PSMZ16S].rpa = &GSLocalMemory::ReadPixel16; - - m_psm[PSM_PSMCT32].wp = &GSLocalMemory::WritePixel32; - m_psm[PSM_PSMCT24].wp = &GSLocalMemory::WritePixel24; - m_psm[PSM_PSMCT16].wp = &GSLocalMemory::WritePixel16; - m_psm[PSM_PSMCT16S].wp = &GSLocalMemory::WritePixel16S; - m_psm[PSM_PSMT8].wp = &GSLocalMemory::WritePixel8; - m_psm[PSM_PSMT4].wp = &GSLocalMemory::WritePixel4; - m_psm[PSM_PSMT8H].wp = &GSLocalMemory::WritePixel8H; - m_psm[PSM_PSMT4HL].wp = &GSLocalMemory::WritePixel4HL; - m_psm[PSM_PSMT4HH].wp = &GSLocalMemory::WritePixel4HH; - m_psm[PSM_PSMZ32].wp = &GSLocalMemory::WritePixel32Z; - m_psm[PSM_PSMZ24].wp = &GSLocalMemory::WritePixel24Z; - m_psm[PSM_PSMZ16].wp = &GSLocalMemory::WritePixel16Z; - m_psm[PSM_PSMZ16S].wp = &GSLocalMemory::WritePixel16SZ; - - m_psm[PSM_PSMCT32].wpa = &GSLocalMemory::WritePixel32; - m_psm[PSM_PSMCT24].wpa = &GSLocalMemory::WritePixel24; - m_psm[PSM_PSMCT16].wpa = &GSLocalMemory::WritePixel16; - m_psm[PSM_PSMCT16S].wpa = &GSLocalMemory::WritePixel16; - m_psm[PSM_PSMT8].wpa = &GSLocalMemory::WritePixel8; - m_psm[PSM_PSMT4].wpa = &GSLocalMemory::WritePixel4; - m_psm[PSM_PSMT8H].wpa = &GSLocalMemory::WritePixel8H; - m_psm[PSM_PSMT4HL].wpa = &GSLocalMemory::WritePixel4HL; - m_psm[PSM_PSMT4HH].wpa = &GSLocalMemory::WritePixel4HH; - m_psm[PSM_PSMZ32].wpa = &GSLocalMemory::WritePixel32; - m_psm[PSM_PSMZ24].wpa = &GSLocalMemory::WritePixel24; - m_psm[PSM_PSMZ16].wpa = &GSLocalMemory::WritePixel16; - m_psm[PSM_PSMZ16S].wpa = &GSLocalMemory::WritePixel16; - - m_psm[PSM_PSMCT24].rt = &GSLocalMemory::ReadTexel24; - m_psm[PSM_PSMCT16].rt = &GSLocalMemory::ReadTexel16; - m_psm[PSM_PSMCT16S].rt = &GSLocalMemory::ReadTexel16S; - m_psm[PSM_PSMT8].rt = &GSLocalMemory::ReadTexel8; - m_psm[PSM_PSMT4].rt = &GSLocalMemory::ReadTexel4; - m_psm[PSM_PSMT8H].rt = &GSLocalMemory::ReadTexel8H; - m_psm[PSM_PSMT4HL].rt = &GSLocalMemory::ReadTexel4HL; - m_psm[PSM_PSMT4HH].rt = &GSLocalMemory::ReadTexel4HH; - m_psm[PSM_PSMZ32].rt = &GSLocalMemory::ReadTexel32Z; - m_psm[PSM_PSMZ24].rt = &GSLocalMemory::ReadTexel24Z; - m_psm[PSM_PSMZ16].rt = &GSLocalMemory::ReadTexel16Z; - m_psm[PSM_PSMZ16S].rt = &GSLocalMemory::ReadTexel16SZ; - - m_psm[PSM_PSMCT24].rta = &GSLocalMemory::ReadTexel24; - m_psm[PSM_PSMCT16].rta = &GSLocalMemory::ReadTexel16; - m_psm[PSM_PSMCT16S].rta = &GSLocalMemory::ReadTexel16; - m_psm[PSM_PSMT8].rta = &GSLocalMemory::ReadTexel8; - m_psm[PSM_PSMT4].rta = &GSLocalMemory::ReadTexel4; - m_psm[PSM_PSMT8H].rta = &GSLocalMemory::ReadTexel8H; - m_psm[PSM_PSMT4HL].rta = &GSLocalMemory::ReadTexel4HL; - m_psm[PSM_PSMT4HH].rta = &GSLocalMemory::ReadTexel4HH; - m_psm[PSM_PSMZ24].rta = &GSLocalMemory::ReadTexel24; - m_psm[PSM_PSMZ16].rta = &GSLocalMemory::ReadTexel16; - m_psm[PSM_PSMZ16S].rta = &GSLocalMemory::ReadTexel16; - - m_psm[PSM_PSMCT24].wfa = &GSLocalMemory::WritePixel24; - m_psm[PSM_PSMCT16].wfa = &GSLocalMemory::WriteFrame16; - m_psm[PSM_PSMCT16S].wfa = &GSLocalMemory::WriteFrame16; - m_psm[PSM_PSMZ24].wfa = &GSLocalMemory::WritePixel24; - m_psm[PSM_PSMZ16].wfa = &GSLocalMemory::WriteFrame16; - m_psm[PSM_PSMZ16S].wfa = &GSLocalMemory::WriteFrame16; - - m_psm[PSM_PSMCT16].rtNP = &GSLocalMemory::ReadTexel16NP; - m_psm[PSM_PSMCT16S].rtNP = &GSLocalMemory::ReadTexel16SNP; - m_psm[PSM_PSMT8].rtNP = &GSLocalMemory::ReadTexel8; - m_psm[PSM_PSMT4].rtNP = &GSLocalMemory::ReadTexel4; - m_psm[PSM_PSMT8H].rtNP = &GSLocalMemory::ReadTexel8H; - m_psm[PSM_PSMT4HL].rtNP = &GSLocalMemory::ReadTexel4HL; - m_psm[PSM_PSMT4HH].rtNP = &GSLocalMemory::ReadTexel4HH; - m_psm[PSM_PSMZ32].rtNP = &GSLocalMemory::ReadTexel32Z; - m_psm[PSM_PSMZ24].rtNP = &GSLocalMemory::ReadTexel24Z; - m_psm[PSM_PSMZ16].rtNP = &GSLocalMemory::ReadTexel16ZNP; - m_psm[PSM_PSMZ16S].rtNP = &GSLocalMemory::ReadTexel16SZNP; - - m_psm[PSM_PSMCT24].wi = &GSLocalMemory::WriteImage24; // TODO - m_psm[PSM_PSMCT16].wi = &GSLocalMemory::WriteImage; - m_psm[PSM_PSMCT16S].wi = &GSLocalMemory::WriteImage; - m_psm[PSM_PSMT8].wi = &GSLocalMemory::WriteImage; - m_psm[PSM_PSMT4].wi = &GSLocalMemory::WriteImage; - m_psm[PSM_PSMT8H].wi = &GSLocalMemory::WriteImage8H; // TODO - m_psm[PSM_PSMT4HL].wi = &GSLocalMemory::WriteImage4HL; // TODO - m_psm[PSM_PSMT4HH].wi = &GSLocalMemory::WriteImage4HH; // TODO - m_psm[PSM_PSMZ32].wi = &GSLocalMemory::WriteImage; - m_psm[PSM_PSMZ24].wi = &GSLocalMemory::WriteImage24Z; // TODO - m_psm[PSM_PSMZ16].wi = &GSLocalMemory::WriteImage; - m_psm[PSM_PSMZ16S].wi = &GSLocalMemory::WriteImage; - - m_psm[PSM_PSMCT24].rtx = &GSLocalMemory::ReadTexture24; - m_psm[PSM_PSMCT16].rtx = &GSLocalMemory::ReadTexture16; - m_psm[PSM_PSMCT16S].rtx = &GSLocalMemory::ReadTexture16S; - m_psm[PSM_PSMT8].rtx = &GSLocalMemory::ReadTexture8; - m_psm[PSM_PSMT4].rtx = &GSLocalMemory::ReadTexture4; - m_psm[PSM_PSMT8H].rtx = &GSLocalMemory::ReadTexture8H; - m_psm[PSM_PSMT4HL].rtx = &GSLocalMemory::ReadTexture4HL; - m_psm[PSM_PSMT4HH].rtx = &GSLocalMemory::ReadTexture4HH; - m_psm[PSM_PSMZ32].rtx = &GSLocalMemory::ReadTexture32Z; - m_psm[PSM_PSMZ24].rtx = &GSLocalMemory::ReadTexture24Z; - m_psm[PSM_PSMZ16].rtx = &GSLocalMemory::ReadTexture16Z; - m_psm[PSM_PSMZ16S].rtx = &GSLocalMemory::ReadTexture16SZ; - - m_psm[PSM_PSMCT16].rtxNP = &GSLocalMemory::ReadTexture16NP; - m_psm[PSM_PSMCT16S].rtxNP = &GSLocalMemory::ReadTexture16SNP; - m_psm[PSM_PSMT8].rtxNP = &GSLocalMemory::ReadTexture8NP; - m_psm[PSM_PSMT4].rtxNP = &GSLocalMemory::ReadTexture4NP; - m_psm[PSM_PSMT8H].rtxNP = &GSLocalMemory::ReadTexture8HNP; - m_psm[PSM_PSMT4HL].rtxNP = &GSLocalMemory::ReadTexture4HLNP; - m_psm[PSM_PSMT4HH].rtxNP = &GSLocalMemory::ReadTexture4HHNP; - m_psm[PSM_PSMZ32].rtxNP = &GSLocalMemory::ReadTexture32Z; - m_psm[PSM_PSMZ24].rtxNP = &GSLocalMemory::ReadTexture24Z; - m_psm[PSM_PSMZ16].rtxNP = &GSLocalMemory::ReadTexture16ZNP; - m_psm[PSM_PSMZ16S].rtxNP = &GSLocalMemory::ReadTexture16SZNP; - - m_psm[PSM_PSMT8].rtxP = &GSLocalMemory::ReadTexture8P; - m_psm[PSM_PSMT4].rtxP = &GSLocalMemory::ReadTexture4P; - m_psm[PSM_PSMT8H].rtxP = &GSLocalMemory::ReadTexture8HP; - m_psm[PSM_PSMT4HL].rtxP = &GSLocalMemory::ReadTexture4HLP; - m_psm[PSM_PSMT4HH].rtxP = &GSLocalMemory::ReadTexture4HHP; - - m_psm[PSM_PSMT8].pal = m_psm[PSM_PSMT8H].pal = 256; - m_psm[PSM_PSMT4].pal = m_psm[PSM_PSMT4HL].pal = m_psm[PSM_PSMT4HH].pal = 16; - - m_psm[PSM_PSMCT16].bpp = m_psm[PSM_PSMCT16S].bpp = 16; - m_psm[PSM_PSMT8].bpp = 8; - m_psm[PSM_PSMT4].bpp = 4; - m_psm[PSM_PSMZ16].bpp = m_psm[PSM_PSMZ16S].bpp = 16; - - m_psm[PSM_PSMCT24].trbpp = 24; - m_psm[PSM_PSMCT16].trbpp = m_psm[PSM_PSMCT16S].trbpp = 16; - m_psm[PSM_PSMT8].trbpp = m_psm[PSM_PSMT8H].trbpp = 8; - m_psm[PSM_PSMT4].trbpp = m_psm[PSM_PSMT4HL].trbpp = m_psm[PSM_PSMT4HH].trbpp = 4; - m_psm[PSM_PSMZ24].trbpp = 24; - m_psm[PSM_PSMZ16].trbpp = m_psm[PSM_PSMZ16S].trbpp = 16; - - m_psm[PSM_PSMCT16].bs = m_psm[PSM_PSMCT16S].bs = CSize(16, 8); - m_psm[PSM_PSMT8].bs = CSize(16, 16); - m_psm[PSM_PSMT4].bs = CSize(32, 16); - m_psm[PSM_PSMZ16].bs = m_psm[PSM_PSMZ16S].bs = CSize(16, 8); - - m_psm[PSM_PSMCT16].pgs = m_psm[PSM_PSMCT16S].pgs = CSize(64, 64); - m_psm[PSM_PSMT8].pgs = CSize(128, 64); - m_psm[PSM_PSMT4].pgs = CSize(128, 128); - m_psm[PSM_PSMZ16].pgs = m_psm[PSM_PSMZ16S].pgs = CSize(64, 64); - - for(int i = 0; i < 8; i++) m_psm[PSM_PSMCT16].rowOffset[i] = rowOffset16; - for(int i = 0; i < 8; i++) m_psm[PSM_PSMCT16S].rowOffset[i] = rowOffset16S; - for(int i = 0; i < 8; i++) m_psm[PSM_PSMT8].rowOffset[i] = rowOffset8[((i + 2) >> 2) & 1]; - for(int i = 0; i < 8; i++) m_psm[PSM_PSMT4].rowOffset[i] = rowOffset4[((i + 2) >> 2) & 1]; - for(int i = 0; i < 8; i++) m_psm[PSM_PSMZ32].rowOffset[i] = rowOffset32Z; - for(int i = 0; i < 8; i++) m_psm[PSM_PSMZ24].rowOffset[i] = rowOffset32Z; - for(int i = 0; i < 8; i++) m_psm[PSM_PSMZ16].rowOffset[i] = rowOffset16Z; - for(int i = 0; i < 8; i++) m_psm[PSM_PSMZ16S].rowOffset[i] = rowOffset16SZ; -} - -GSLocalMemory::~GSLocalMemory() -{ - VirtualFree(m_vm8, 0, MEM_RELEASE); - - POSITION pos = m_omap.GetHeadPosition(); - - while(pos) - { - Offset* o = m_omap.GetNextValue(pos); - - for(int i = 0; i < countof(o->col); i++) - { - _aligned_free(o->col); - } - - _aligned_free(o); - } - - m_omap.RemoveAll(); - - pos = m_o4map.GetHeadPosition(); - - while(pos) - { - _aligned_free(m_o4map.GetNextValue(pos)); - } - - m_o4map.RemoveAll(); -} - -GSLocalMemory::Offset* GSLocalMemory::GetOffset(DWORD bp, DWORD bw, DWORD psm) -{ - if(bw == 0) {ASSERT(0); return NULL;} - - ASSERT(m_psm[psm].bpp > 8); // only for 16/24/32/8h/4hh/4hl formats where all columns are the same - - DWORD hash = bp | (bw << 14) | (psm << 20); - - if(CRBMap::CPair* pair = m_omap.Lookup(hash)) - { - return pair->m_value; - } - - Offset* o = (Offset*)_aligned_malloc(sizeof(Offset), 16); - - o->hash = hash; - - pixelAddress pa = m_psm[psm].pa; - - for(int i = 0; i < 2048; i++) - { - o->row[i] = GSVector4i((int)pa(0, i, bp, bw)); - } - - int* p = (int*)_aligned_malloc(sizeof(int) * (2048 + 3) * 4, 16); - - for(int i = 0; i < 4; i++) - { - o->col[i] = &p[2048 * i + ((4 - (i & 3)) & 3)]; - - memcpy(o->col[i], m_psm[psm].rowOffset[0], sizeof(int) * 2048); - } - - m_omap.SetAt(hash, o); - - return o; -} - -GSLocalMemory::Offset4* GSLocalMemory::GetOffset4(const GIFRegFRAME& FRAME, const GIFRegZBUF& ZBUF) -{ - DWORD fbp = FRAME.Block(); - DWORD zbp = ZBUF.Block(); - DWORD fpsm = FRAME.PSM; - DWORD zpsm = ZBUF.PSM; - DWORD bw = FRAME.FBW; - - ASSERT(m_psm[fpsm].trbpp > 8 || m_psm[zpsm].trbpp > 8); - - // "(psm & 0x0f) ^ ((psm & 0xf0) >> 2)" creates 4 bit unique identifiers for render target formats (only) - - DWORD fpsm_hash = (fpsm & 0x0f) ^ ((fpsm & 0x30) >> 2); - DWORD zpsm_hash = (zpsm & 0x0f) ^ ((zpsm & 0x30) >> 2); - - DWORD hash = (FRAME.FBP << 0) | (ZBUF.ZBP << 9) | (bw << 18) | (fpsm_hash << 24) | (zpsm_hash << 28); - - if(CRBMap::CPair* pair = m_o4map.Lookup(hash)) - { - return pair->m_value; - } - - Offset4* o = (Offset4*)_aligned_malloc(sizeof(Offset4), 16); - - o->hash = hash; - - pixelAddress fpa = m_psm[fpsm].pa; - pixelAddress zpa = m_psm[zpsm].pa; - - int fs = m_psm[fpsm].bpp >> 5; - int zs = m_psm[zpsm].bpp >> 5; - - for(int i = 0; i < 2048; i++) - { - o->row[i].x = (int)fpa(0, i, fbp, bw) << fs; - o->row[i].y = (int)zpa(0, i, zbp, bw) << zs; - } - - for(int i = 0; i < 512; i++) - { - o->col[i].x = m_psm[fpsm].rowOffset[0][i * 4] << fs; - o->col[i].y = m_psm[zpsm].rowOffset[0][i * 4] << zs; - } - - m_o4map.SetAt(hash, o); - - return o; -} - -bool GSLocalMemory::FillRect(const GSVector4i& r, DWORD c, DWORD psm, DWORD bp, DWORD bw) -{ - const psm_t& tbl = m_psm[psm]; - - writePixel wp = tbl.wp; - pixelAddress ba = tbl.ba; - - int w = tbl.bs.cx; - int h = tbl.bs.cy; - int bpp = tbl.bpp; - - int shift = 0; - - switch(bpp) - { - case 32: shift = 0; break; - case 16: shift = 1; c = (c & 0xffff) * 0x00010001; break; - case 8: shift = 2; c = (c & 0xff) * 0x01010101; break; - case 4: shift = 3; c = (c & 0xf) * 0x11111111; break; - } - - CRect clip; - - clip.left = (r.x + (w - 1)) & ~(w - 1); - clip.top = (r.y + (h - 1)) & ~(h - 1); - clip.right = r.z & ~(w - 1); - clip.bottom = r.w & ~(h - 1); - - for(int y = r.y; y < clip.top; y++) - { - for(int x = r.x; x < r.z; x++) - { - (this->*wp)(x, y, c, bp, bw); - } - } - - for(int y = clip.bottom; y < r.w; y++) - { - for(int x = r.x; x < r.z; x++) - { - (this->*wp)(x, y, c, bp, bw); - } - } - - if(r.x < clip.left || clip.right < r.z) - { - for(int y = clip.top; y < clip.bottom; y += h) - { - for(int ys = y, ye = y + h; ys < ye; ys++) - { - for(int x = r.x; x < clip.left; x++) - { - (this->*wp)(x, ys, c, bp, bw); - } - - for(int x = clip.right; x < r.z; x++) - { - (this->*wp)(x, ys, c, bp, bw); - } - } - } - } - - if(psm == PSM_PSMCT24 || psm == PSM_PSMZ24) - { - #if _M_SSE >= 0x200 - - GSVector4i c128(c); - GSVector4i mask(0x00ffffff); - - for(int y = clip.top; y < clip.bottom; y += h) - { - for(int x = clip.left; x < clip.right; x += w) - { - GSVector4i* p = (GSVector4i*)&m_vm8[ba(x, y, bp, bw) << 2 >> shift]; - - for(int i = 0; i < 16; i += 4) - { - p[i + 0] = p[i + 0].blend8(c128, mask); - p[i + 1] = p[i + 1].blend8(c128, mask); - p[i + 2] = p[i + 2].blend8(c128, mask); - p[i + 3] = p[i + 3].blend8(c128, mask); - } - } - } - - #else - - c &= 0x00ffffff; - - for(int y = clip.top; y < clip.bottom; y += h) - { - for(int x = clip.left; x < clip.right; x += w) - { - DWORD* p = &m_vm32[ba(x, y, bp, bw)]; - - for(int i = 0; i < 64; i += 4) - { - p[i + 0] = (p[i + 0] & 0xff000000) | c; - p[i + 1] = (p[i + 1] & 0xff000000) | c; - p[i + 2] = (p[i + 2] & 0xff000000) | c; - p[i + 3] = (p[i + 3] & 0xff000000) | c; - } - } - } - - #endif - } - else - { - #if _M_SSE >= 0x200 - - GSVector4i c128(c); - - for(int y = clip.top; y < clip.bottom; y += h) - { - for(int x = clip.left; x < clip.right; x += w) - { - GSVector4i* p = (GSVector4i*)&m_vm8[ba(x, y, bp, bw) << 2 >> shift]; - - for(int i = 0; i < 16; i += 4) - { - p[i + 0] = c128; - p[i + 1] = c128; - p[i + 2] = c128; - p[i + 3] = c128; - } - } - } - - #else - - for(int y = clip.top; y < clip.bottom; y += h) - { - for(int x = clip.left; x < clip.right; x += w) - { - DWORD* p = (DWORD*)&m_vm8[ba(x, y, bp, bw) << 2 >> shift]; - - for(int i = 0; i < 64; i += 4) - { - p[i + 0] = c; - p[i + 1] = c; - p[i + 2] = c; - p[i + 3] = c; - } - } - } - - #endif - } - - return true; -} - -//////////////////// - -template -void GSLocalMemory::WriteImageColumn(int l, int r, int y, int h, BYTE* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF) -{ - DWORD bp = BITBLTBUF.DBP; - DWORD bw = BITBLTBUF.DBW; - - const int csy = bsy / 4; - - for(int offset = srcpitch * csy; h >= csy; h -= csy, y += csy, src += offset) - { - for(int x = l; x < r; x += bsx) - { - switch(psm) - { - case PSM_PSMCT32: WriteColumn32(y, (BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], &src[x * 4], srcpitch); break; - case PSM_PSMCT16: WriteColumn16(y, (BYTE*)&m_vm16[BlockAddress16(x, y, bp, bw)], &src[x * 2], srcpitch); break; - case PSM_PSMCT16S: WriteColumn16(y, (BYTE*)&m_vm16[BlockAddress16S(x, y, bp, bw)], &src[x * 2], srcpitch); break; - case PSM_PSMT8: WriteColumn8(y, (BYTE*)&m_vm8[BlockAddress8(x, y, bp, bw)], &src[x], srcpitch); break; - case PSM_PSMT4: WriteColumn4(y, (BYTE*)&m_vm8[BlockAddress4(x, y, bp, bw) >> 1], &src[x >> 1], srcpitch); break; - case PSM_PSMZ32: WriteColumn32(y, (BYTE*)&m_vm32[BlockAddress32Z(x, y, bp, bw)], &src[x * 4], srcpitch); break; - case PSM_PSMZ16: WriteColumn16(y, (BYTE*)&m_vm16[BlockAddress16Z(x, y, bp, bw)], &src[x * 2], srcpitch); break; - case PSM_PSMZ16S: WriteColumn16(y, (BYTE*)&m_vm16[BlockAddress16SZ(x, y, bp, bw)], &src[x * 2], srcpitch); break; - // TODO - default: __assume(0); - } - } - } -} - -template -void GSLocalMemory::WriteImageBlock(int l, int r, int y, int h, BYTE* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF) -{ - DWORD bp = BITBLTBUF.DBP; - DWORD bw = BITBLTBUF.DBW; - - for(int offset = srcpitch * bsy; h >= bsy; h -= bsy, y += bsy, src += offset) - { - for(int x = l; x < r; x += bsx) - { - switch(psm) - { - case PSM_PSMCT32: WriteBlock32((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], &src[x * 4], srcpitch); break; - case PSM_PSMCT16: WriteBlock16((BYTE*)&m_vm16[BlockAddress16(x, y, bp, bw)], &src[x * 2], srcpitch); break; - case PSM_PSMCT16S: WriteBlock16((BYTE*)&m_vm16[BlockAddress16S(x, y, bp, bw)], &src[x * 2], srcpitch); break; - case PSM_PSMT8: WriteBlock8((BYTE*)&m_vm8[BlockAddress8(x, y, bp, bw)], &src[x], srcpitch); break; - case PSM_PSMT4: WriteBlock4((BYTE*)&m_vm8[BlockAddress4(x, y, bp, bw) >> 1], &src[x >> 1], srcpitch); break; - case PSM_PSMZ32: WriteBlock32((BYTE*)&m_vm32[BlockAddress32Z(x, y, bp, bw)], &src[x * 4], srcpitch); break; - case PSM_PSMZ16: WriteBlock16((BYTE*)&m_vm16[BlockAddress16Z(x, y, bp, bw)], &src[x * 2], srcpitch); break; - case PSM_PSMZ16S: WriteBlock16((BYTE*)&m_vm16[BlockAddress16SZ(x, y, bp, bw)], &src[x * 2], srcpitch); break; - // TODO - default: __assume(0); - } - } - } -} - -template -void GSLocalMemory::WriteImageLeftRight(int l, int r, int y, int h, BYTE* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF) -{ - DWORD bp = BITBLTBUF.DBP; - DWORD bw = BITBLTBUF.DBW; - - for(; h > 0; y++, h--, src += srcpitch) - { - for(int x = l; x < r; x++) - { - switch(psm) - { - case PSM_PSMCT32: WritePixel32(x, y, *(DWORD*)&src[x * 4], bp, bw); break; - case PSM_PSMCT16: WritePixel16(x, y, *(WORD*)&src[x * 2], bp, bw); break; - case PSM_PSMCT16S: WritePixel16S(x, y, *(WORD*)&src[x * 2], bp, bw); break; - case PSM_PSMT8: WritePixel8(x, y, src[x], bp, bw); break; - case PSM_PSMT4: WritePixel4(x, y, src[x >> 1] >> ((x & 1) << 2), bp, bw); break; - case PSM_PSMZ32: WritePixel32Z(x, y, *(DWORD*)&src[x * 4], bp, bw); break; - case PSM_PSMZ16: WritePixel16Z(x, y, *(WORD*)&src[x * 2], bp, bw); break; - case PSM_PSMZ16S: WritePixel16SZ(x, y, *(WORD*)&src[x * 2], bp, bw); break; - // TODO - default: __assume(0); - } - } - } -} - -template -void GSLocalMemory::WriteImageTopBottom(int l, int r, int y, int h, BYTE* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF) -{ - __declspec(align(16)) BYTE buff[64]; // merge buffer for one column - - DWORD bp = BITBLTBUF.DBP; - DWORD bw = BITBLTBUF.DBW; - - const int csy = bsy / 4; - - // merge incomplete column - - int y2 = y & (csy - 1); - - if(y2 > 0) - { - int h2 = min(h, csy - y2); - - for(int x = l; x < r; x += bsx) - { - BYTE* dst = NULL; - - switch(psm) - { - case PSM_PSMCT32: dst = (BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)]; break; - case PSM_PSMCT16: dst = (BYTE*)&m_vm16[BlockAddress16(x, y, bp, bw)]; break; - case PSM_PSMCT16S: dst = (BYTE*)&m_vm16[BlockAddress16S(x, y, bp, bw)]; break; - case PSM_PSMT8: dst = (BYTE*)&m_vm8[BlockAddress8(x, y, bp, bw)]; break; - case PSM_PSMT4: dst = (BYTE*)&m_vm8[BlockAddress4(x, y, bp, bw) >> 1]; break; - case PSM_PSMZ32: dst = (BYTE*)&m_vm32[BlockAddress32Z(x, y, bp, bw)]; break; - case PSM_PSMZ16: dst = (BYTE*)&m_vm16[BlockAddress16Z(x, y, bp, bw)]; break; - case PSM_PSMZ16S: dst = (BYTE*)&m_vm16[BlockAddress16SZ(x, y, bp, bw)]; break; - // TODO - default: __assume(0); - } - - switch(psm) - { - case PSM_PSMCT32: - case PSM_PSMZ32: - ReadColumn32(y, dst, buff, 32); - memcpy(&buff[32], &src[x * 4], 32); - WriteColumn32(y, dst, buff, 32); - break; - case PSM_PSMCT16: - case PSM_PSMCT16S: - case PSM_PSMZ16: - case PSM_PSMZ16S: - ReadColumn16(y, dst, buff, 32); - memcpy(&buff[32], &src[x * 2], 32); - WriteColumn16(y, dst, buff, 32); - break; - case PSM_PSMT8: - ReadColumn8(y, dst, buff, 16); - memcpy(&buff[y2 * 16], &src[x], h2 * 16); - WriteColumn8(y, dst, buff, 16); - break; - case PSM_PSMT4: - ReadColumn4(y, dst, buff, 16); - memcpy(&buff[y2 * 16], &src[x >> 1], h2 * 16); - WriteColumn4(y, dst, buff, 16); - break; - // TODO - default: - __assume(0); - } - } - - src += srcpitch * h2; - y += h2; - h -= h2; - } - - // write whole columns - - { - int h2 = h & ~(csy - 1); - - if(h2 > 0) - { - if(((DWORD_PTR)&src[l * trbpp >> 3] & 15) == 0 && (srcpitch & 15) == 0) - { - WriteImageColumn(l, r, y, h2, src, srcpitch, BITBLTBUF); - } - else - { - WriteImageColumn(l, r, y, h2, src, srcpitch, BITBLTBUF); - } - - src += srcpitch * h2; - y += h2; - h -= h2; - } - } - - // merge incomplete column - - if(h >= 1) - { - for(int x = l; x < r; x += bsx) - { - BYTE* dst = NULL; - - switch(psm) - { - case PSM_PSMCT32: dst = (BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)]; break; - case PSM_PSMCT16: dst = (BYTE*)&m_vm16[BlockAddress16(x, y, bp, bw)]; break; - case PSM_PSMCT16S: dst = (BYTE*)&m_vm16[BlockAddress16S(x, y, bp, bw)]; break; - case PSM_PSMT8: dst = (BYTE*)&m_vm8[BlockAddress8(x, y, bp, bw)]; break; - case PSM_PSMT4: dst = (BYTE*)&m_vm8[BlockAddress4(x, y, bp, bw) >> 1]; break; - case PSM_PSMZ32: dst = (BYTE*)&m_vm32[BlockAddress32Z(x, y, bp, bw)]; break; - case PSM_PSMZ16: dst = (BYTE*)&m_vm16[BlockAddress16Z(x, y, bp, bw)]; break; - case PSM_PSMZ16S: dst = (BYTE*)&m_vm16[BlockAddress16SZ(x, y, bp, bw)]; break; - // TODO - default: __assume(0); - } - - switch(psm) - { - case PSM_PSMCT32: - case PSM_PSMZ32: - ReadColumn32(y, dst, buff, 32); - memcpy(&buff[0], &src[x * 4], 32); - WriteColumn32(y, dst, buff, 32); - break; - case PSM_PSMCT16: - case PSM_PSMCT16S: - case PSM_PSMZ16: - case PSM_PSMZ16S: - ReadColumn16(y, dst, buff, 32); - memcpy(&buff[0], &src[x * 2], 32); - WriteColumn16(y, dst, buff, 32); - break; - case PSM_PSMT8: - ReadColumn8(y, dst, buff, 16); - memcpy(&buff[0], &src[x], h * 16); - WriteColumn8(y, dst, buff, 16); - break; - case PSM_PSMT4: - ReadColumn4(y, dst, buff, 16); - memcpy(&buff[0], &src[x >> 1], h * 16); - WriteColumn4(y, dst, buff, 16); - break; - // TODO - default: - __assume(0); - } - } - } -} - -template -void GSLocalMemory::WriteImage(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) -{ - if(TRXREG.RRW == 0) return; - - int l = (int)TRXPOS.DSAX; - int r = (int)TRXREG.RRW; - - // finish the incomplete row first - - if(tx != l) - { - int n = min(len, (r - tx) * trbpp >> 3); - WriteImageX(tx, ty, src, n, BITBLTBUF, TRXPOS, TRXREG); - src += n; - len -= n; - } - - int la = (l + (bsx - 1)) & ~(bsx - 1); - int ra = r & ~(bsx - 1); - int srcpitch = (r - l) * trbpp >> 3; - int h = len / srcpitch; - - // transfer width >= block width, and there is at least one full row - - if(ra - la >= bsx && h > 0) - { - BYTE* s = &src[-l * trbpp >> 3]; - - src += srcpitch * h; - len -= srcpitch * h; - - // left part - - if(l < la) - { - WriteImageLeftRight(l, la, ty, h, s, srcpitch, BITBLTBUF); - } - - // right part - - if(ra < r) - { - WriteImageLeftRight(ra, r, ty, h, s, srcpitch, BITBLTBUF); - } - - // horizontally aligned part - - if(la < ra) - { - // top part - - { - int h2 = min(h, bsy - (ty & (bsy - 1))); - - if(h2 < bsy) - { - WriteImageTopBottom(la, ra, ty, h2, s, srcpitch, BITBLTBUF); - - s += srcpitch * h2; - ty += h2; - h -= h2; - } - } - - // horizontally and vertically aligned part - - { - int h2 = h & ~(bsy - 1); - - if(h2 > 0) - { - if(((DWORD_PTR)&s[la * trbpp >> 3] & 15) == 0 && (srcpitch & 15) == 0) - { - WriteImageBlock(la, ra, ty, h2, s, srcpitch, BITBLTBUF); - } - else - { - WriteImageBlock(la, ra, ty, h2, s, srcpitch, BITBLTBUF); - } - - s += srcpitch * h2; - ty += h2; - h -= h2; - } - } - - // bottom part - - if(h > 0) - { - WriteImageTopBottom(la, ra, ty, h, s, srcpitch, BITBLTBUF); - - // s += srcpitch * h; - ty += h; - // h -= h; - } - } - } - - // the rest - - if(len > 0) - { - WriteImageX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); - } -} - - -#define IsTopLeftAligned(dsax, tx, ty, bw, bh) \ - ((((int)dsax) & ((bw)-1)) == 0 && ((tx) & ((bw)-1)) == 0 && ((int)dsax) == (tx) && ((ty) & ((bh)-1)) == 0) - -void GSLocalMemory::WriteImage24(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) -{ - if(TRXREG.RRW == 0) return; - - DWORD bp = BITBLTBUF.DBP; - DWORD bw = BITBLTBUF.DBW; - - int tw = TRXREG.RRW, srcpitch = (TRXREG.RRW - TRXPOS.DSAX) * 3; - int th = len / srcpitch; - - bool aligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8); - - if(!aligned || (tw & 7) || (th & 7) || (len % srcpitch)) - { - // TODO - - WriteImageX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); - } - else - { - th += ty; - - for(int y = ty; y < th; y += 8, src += srcpitch * 8) - { - for(int x = tx; x < tw; x += 8) - { - UnpackAndWriteBlock24(src + (x - tx) * 3, srcpitch, (BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)]); - } - } - - ty = th; - } -} -void GSLocalMemory::WriteImage8H(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) -{ - if(TRXREG.RRW == 0) return; - - DWORD bp = BITBLTBUF.DBP; - DWORD bw = BITBLTBUF.DBW; - - int tw = TRXREG.RRW, srcpitch = TRXREG.RRW - TRXPOS.DSAX; - int th = len / srcpitch; - - bool aligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8); - - if(!aligned || (tw & 7) || (th & 7) || (len % srcpitch)) - { - // TODO - - WriteImageX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); - } - else - { - th += ty; - - for(int y = ty; y < th; y += 8, src += srcpitch * 8) - { - for(int x = tx; x < tw; x += 8) - { - UnpackAndWriteBlock8H(src + (x - tx), srcpitch, (BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)]); - } - } - - ty = th; - } -} - -void GSLocalMemory::WriteImage4HL(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) -{ - if(TRXREG.RRW == 0) return; - - DWORD bp = BITBLTBUF.DBP; - DWORD bw = BITBLTBUF.DBW; - - int tw = TRXREG.RRW, srcpitch = (TRXREG.RRW - TRXPOS.DSAX) / 2; - int th = len / srcpitch; - - bool aligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8); - - if(!aligned || (tw & 7) || (th & 7) || (len % srcpitch)) - { - // TODO - - WriteImageX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); - } - else - { - th += ty; - - for(int y = ty; y < th; y += 8, src += srcpitch * 8) - { - for(int x = tx; x < tw; x += 8) - { - UnpackAndWriteBlock4HL(src + (x - tx) / 2, srcpitch, (BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)]); - } - } - - ty = th; - } -} - -void GSLocalMemory::WriteImage4HH(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) -{ - if(TRXREG.RRW == 0) return; - - DWORD bp = BITBLTBUF.DBP; - DWORD bw = BITBLTBUF.DBW; - - int tw = TRXREG.RRW, srcpitch = (TRXREG.RRW - TRXPOS.DSAX) / 2; - int th = len / srcpitch; - - bool aligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8); - - if(!aligned || (tw & 7) || (th & 7) || (len % srcpitch)) - { - // TODO - - WriteImageX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); - } - else - { - th += ty; - - for(int y = ty; y < th; y += 8, src += srcpitch * 8) - { - for(int x = tx; x < tw; x += 8) - { - UnpackAndWriteBlock4HH(src + (x - tx) / 2, srcpitch, (BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)]); - } - } - - ty = th; - } -} -void GSLocalMemory::WriteImage24Z(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) -{ - if(TRXREG.RRW == 0) return; - - DWORD bp = BITBLTBUF.DBP; - DWORD bw = BITBLTBUF.DBW; - - int tw = TRXREG.RRW, srcpitch = (TRXREG.RRW - TRXPOS.DSAX) * 3; - int th = len / srcpitch; - - bool aligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8); - - if(!aligned || (tw & 7) || (th & 7) || (len % srcpitch)) - { - // TODO - - WriteImageX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); - } - else - { - th += ty; - - for(int y = ty; y < th; y += 8, src += srcpitch * 8) - { - for(int x = tx; x < tw; x += 8) - { - UnpackAndWriteBlock24(src + (x - tx) * 3, srcpitch, (BYTE*)&m_vm32[BlockAddress32Z(x, y, bp, bw)]); - } - } - - ty = th; - } -} -void GSLocalMemory::WriteImageX(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) -{ - if(len <= 0) return; - - // if(ty >= (int)TRXREG.RRH) {ASSERT(0); return;} - - BYTE* pb = (BYTE*)src; - WORD* pw = (WORD*)src; - DWORD* pd = (DWORD*)src; - - DWORD bp = BITBLTBUF.DBP; - DWORD bw = BITBLTBUF.DBW; - psm_t* psm = &m_psm[BITBLTBUF.DPSM]; - - int x = tx; - int y = ty; - int sx = (int)TRXPOS.DSAX; - int ex = (int)TRXREG.RRW; - - switch(BITBLTBUF.DPSM) - { - case PSM_PSMCT32: - case PSM_PSMZ32: - - len /= 4; - - while(len > 0) - { - DWORD addr = psm->pa(0, y, bp, bw); - int* offset = psm->rowOffset[y & 7]; - - for(; len > 0 && x < ex; len--, x++, pd++) - { - WritePixel32(addr + offset[x], *pd); - } - - if(x == ex) {x = sx; y++;} - } - - break; - - case PSM_PSMCT24: - case PSM_PSMZ24: - - len /= 3; - - while(len > 0) - { - DWORD addr = psm->pa(0, y, bp, bw); - int* offset = psm->rowOffset[y & 7]; - - for(; len > 0 && x < ex; len--, x++, pb += 3) - { - WritePixel24(addr + offset[x], *(DWORD*)pb); - } - - if(x == ex) {x = sx; y++;} - } - - break; - - case PSM_PSMCT16: - case PSM_PSMCT16S: - case PSM_PSMZ16: - case PSM_PSMZ16S: - - len /= 2; - - while(len > 0) - { - DWORD addr = psm->pa(0, y, bp, bw); - int* offset = psm->rowOffset[y & 7]; - - for(; len > 0 && x < ex; len--, x++, pw++) - { - WritePixel16(addr + offset[x], *pw); - } - - if(x == ex) {x = sx; y++;} - } - - break; - - case PSM_PSMT8: - - while(len > 0) - { - DWORD addr = psm->pa(0, y, bp, bw); - int* offset = psm->rowOffset[y & 7]; - - for(; len > 0 && x < ex; len--, x++, pb++) - { - WritePixel8(addr + offset[x], *pb); - } - - if(x == ex) {x = sx; y++;} - } - - break; - - case PSM_PSMT4: - - while(len > 0) - { - DWORD addr = psm->pa(0, y, bp, bw); - int* offset = psm->rowOffset[y & 7]; - - for(; len > 0 && x < ex; len--, x += 2, pb++) - { - WritePixel4(addr + offset[x + 0], *pb & 0xf); - WritePixel4(addr + offset[x + 1], *pb >> 4); - } - - if(x == ex) {x = sx; y++;} - } - - break; - - case PSM_PSMT8H: - - while(len > 0) - { - DWORD addr = psm->pa(0, y, bp, bw); - int* offset = psm->rowOffset[y & 7]; - - for(; len > 0 && x < ex; len--, x++, pb++) - { - WritePixel8H(addr + offset[x], *pb); - } - - if(x == ex) {x = sx; y++;} - } - - break; - - case PSM_PSMT4HL: - - while(len > 0) - { - DWORD addr = psm->pa(0, y, bp, bw); - int* offset = psm->rowOffset[y & 7]; - - for(; len > 0 && x < ex; len--, x += 2, pb++) - { - WritePixel4HL(addr + offset[x + 0], *pb & 0xf); - WritePixel4HL(addr + offset[x + 1], *pb >> 4); - } - - if(x == ex) {x = sx; y++;} - } - - break; - - case PSM_PSMT4HH: - - while(len > 0) - { - DWORD addr = psm->pa(0, y, bp, bw); - int* offset = psm->rowOffset[y & 7]; - - for(; len > 0 && x < ex; len--, x += 2, pb++) - { - WritePixel4HH(addr + offset[x + 0], *pb & 0xf); - WritePixel4HH(addr + offset[x + 1], *pb >> 4); - } - - if(x == ex) {x = sx; y++;} - } - - break; - } - - tx = x; - ty = y; -} - -// - -void GSLocalMemory::ReadImageX(int& tx, int& ty, BYTE* dst, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) const -{ - if(len <= 0) return; - - // if(ty >= (int)TRXREG.RRH) {ASSERT(0); return;} - - BYTE* pb = (BYTE*)dst; - WORD* pw = (WORD*)dst; - DWORD* pd = (DWORD*)dst; - - DWORD bp = BITBLTBUF.SBP; - DWORD bw = BITBLTBUF.SBW; - psm_t* psm = &m_psm[BITBLTBUF.SPSM]; - - int x = tx; - int y = ty; - int sx = (int)TRXPOS.SSAX; - int ex = (int)TRXREG.RRW; - - switch(BITBLTBUF.SPSM) - { - case PSM_PSMCT32: - case PSM_PSMZ32: - - len /= 4; - - while(len > 0) - { - DWORD addr = psm->pa(0, y, bp, bw); - int* offset = psm->rowOffset[y & 7]; - - for(; len > 0 && x < ex; len--, x++, pd++) - { - *pd = ReadPixel32(addr + offset[x]); - } - - if(x == ex) {x = sx; y++;} - } - - break; - - case PSM_PSMCT24: - case PSM_PSMZ24: - - len /= 3; - - while(len > 0) - { - DWORD addr = psm->pa(0, y, bp, bw); - int* offset = psm->rowOffset[y & 7]; - - for(; len > 0 && x < ex; len--, x++, pb += 3) - { - DWORD dw = ReadPixel32(addr + offset[x]); - - pb[0] = ((BYTE*)&dw)[0]; - pb[1] = ((BYTE*)&dw)[1]; - pb[2] = ((BYTE*)&dw)[2]; - } - - if(x == ex) {x = sx; y++;} - } - - break; - - case PSM_PSMCT16: - case PSM_PSMCT16S: - case PSM_PSMZ16: - case PSM_PSMZ16S: - - len /= 2; - - while(len > 0) - { - DWORD addr = psm->pa(0, y, bp, bw); - int* offset = psm->rowOffset[y & 7]; - - for(; len > 0 && x < ex; len--, x++, pw++) - { - *pw = ReadPixel16(addr + offset[x]); - } - - if(x == ex) {x = sx; y++;} - } - - break; - - case PSM_PSMT8: - - while(len > 0) - { - DWORD addr = psm->pa(0, y, bp, bw); - int* offset = psm->rowOffset[y & 7]; - - for(; len > 0 && x < ex; len--, x++, pb++) - { - *pb = ReadPixel8(addr + offset[x]); - } - - if(x == ex) {x = sx; y++;} - } - - break; - - case PSM_PSMT4: - - while(len > 0) - { - DWORD addr = psm->pa(0, y, bp, bw); - int* offset = psm->rowOffset[y & 7]; - - for(; len > 0 && x < ex; len--, x += 2, pb++) - { - *pb = ReadPixel4(addr + offset[x + 0]) | (ReadPixel4(addr + offset[x + 1]) << 4); - } - - if(x == ex) {x = sx; y++;} - } - - break; - - case PSM_PSMT8H: - - while(len > 0) - { - DWORD addr = psm->pa(0, y, bp, bw); - int* offset = psm->rowOffset[y & 7]; - - for(; len > 0 && x < ex; len--, x++, pb++) - { - *pb = ReadPixel8H(addr + offset[x]); - } - - if(x == ex) {x = sx; y++;} - } - - break; - - case PSM_PSMT4HL: - - while(len > 0) - { - DWORD addr = psm->pa(0, y, bp, bw); - int* offset = psm->rowOffset[y & 7]; - - for(; len > 0 && x < ex; len--, x += 2, pb++) - { - *pb = ReadPixel4HL(addr + offset[x + 0]) | (ReadPixel4HL(addr + offset[x + 1]) << 4); - } - - if(x == ex) {x = sx; y++;} - } - - break; - - case PSM_PSMT4HH: - - while(len > 0) - { - DWORD addr = psm->pa(0, y, bp, bw); - int* offset = psm->rowOffset[y & 7]; - - for(; len > 0 && x < ex; len--, x += 2, pb++) - { - *pb = ReadPixel4HH(addr + offset[x + 0]) | (ReadPixel4HH(addr + offset[x + 1]) << 4); - } - - if(x == ex) {x = sx; y++;} - } - - break; - } - - tx = x; - ty = y; -} - -/////////////////// - -void GSLocalMemory::ReadTexture32(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - FOREACH_BLOCK_START(8, 8, 32) - { - ReadBlock32((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch); - } - FOREACH_BLOCK_END - -} - -void GSLocalMemory::ReadTexture24(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - if(TEXA.AEM) - { - FOREACH_BLOCK_START(8, 8, 32) - { - ReadAndExpandBlock24((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch, TEXA); - } - FOREACH_BLOCK_END - } - else - { - FOREACH_BLOCK_START(8, 8, 32) - { - ReadAndExpandBlock24((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch, TEXA); - } - FOREACH_BLOCK_END - } -} - -void GSLocalMemory::ReadTexture16(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - __declspec(align(16)) WORD block[16 * 8]; - - FOREACH_BLOCK_START(16, 8, 32) - { - ReadBlock16((BYTE*)&m_vm16[BlockAddress16(x, y, bp, bw)], (BYTE*)block, sizeof(block) / 8); - - ExpandBlock16(block, dst, dstpitch, TEXA); - } - FOREACH_BLOCK_END -} - -void GSLocalMemory::ReadTexture16S(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - __declspec(align(16)) WORD block[16 * 8]; - - FOREACH_BLOCK_START(16, 8, 32) - { - ReadBlock16((BYTE*)&m_vm16[BlockAddress16S(x, y, bp, bw)], (BYTE*)block, sizeof(block) / 8); - - ExpandBlock16(block, dst, dstpitch, TEXA); - } - FOREACH_BLOCK_END -} - -void GSLocalMemory::ReadTexture8(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - const DWORD* pal = m_clut; - - FOREACH_BLOCK_START(16, 16, 32) - { - ReadAndExpandBlock8_32((BYTE*)&m_vm8[BlockAddress8(x, y, bp, bw)], dst, dstpitch, pal); - } - FOREACH_BLOCK_END -} - -void GSLocalMemory::ReadTexture4(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - const UINT64* pal = m_clut; - - FOREACH_BLOCK_START(32, 16, 32) - { - ReadAndExpandBlock4_32((BYTE*)&m_vm8[BlockAddress4(x, y, bp, bw) >> 1], dst, dstpitch, pal); - } - FOREACH_BLOCK_END -} - -void GSLocalMemory::ReadTexture8H(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - const DWORD* pal = m_clut; - - FOREACH_BLOCK_START(8, 8, 32) - { - ReadAndExpandBlock8H_32((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch, pal); - } - FOREACH_BLOCK_END -} - -void GSLocalMemory::ReadTexture4HL(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - const DWORD* pal = m_clut; - - FOREACH_BLOCK_START(8, 8, 32) - { - ReadAndExpandBlock4HL_32((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch, pal); - } - FOREACH_BLOCK_END -} - -void GSLocalMemory::ReadTexture4HH(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - const DWORD* pal = m_clut; - - FOREACH_BLOCK_START(8, 8, 32) - { - ReadAndExpandBlock4HH_32((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch, pal); - } - FOREACH_BLOCK_END -} - -void GSLocalMemory::ReadTexture32Z(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - FOREACH_BLOCK_START(8, 8, 32) - { - ReadBlock32((BYTE*)&m_vm32[BlockAddress32Z(x, y, bp, bw)], dst, dstpitch); - } - FOREACH_BLOCK_END -} - -void GSLocalMemory::ReadTexture24Z(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - if(TEXA.AEM) - { - FOREACH_BLOCK_START(8, 8, 32) - { - ReadAndExpandBlock24((BYTE*)&m_vm32[BlockAddress32Z(x, y, bp, bw)], dst, dstpitch, TEXA); - } - FOREACH_BLOCK_END - } - else - { - FOREACH_BLOCK_START(8, 8, 32) - { - ReadAndExpandBlock24((BYTE*)&m_vm32[BlockAddress32Z(x, y, bp, bw)], dst, dstpitch, TEXA); - } - FOREACH_BLOCK_END - } -} - -void GSLocalMemory::ReadTexture16Z(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - __declspec(align(16)) WORD block[16 * 8]; - - FOREACH_BLOCK_START(16, 8, 32) - { - ReadBlock16((BYTE*)&m_vm16[BlockAddress16Z(x, y, bp, bw)], (BYTE*)block, sizeof(block) / 8); - - ExpandBlock16(block, dst, dstpitch, TEXA); - } - FOREACH_BLOCK_END -} - -void GSLocalMemory::ReadTexture16SZ(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - __declspec(align(16)) WORD block[16 * 8]; - - FOREACH_BLOCK_START(16, 8, 32) - { - ReadBlock16((BYTE*)&m_vm16[BlockAddress16SZ(x, y, bp, bw)], (BYTE*)block, sizeof(block) / 8); - - ExpandBlock16(block, dst, dstpitch, TEXA); - } - FOREACH_BLOCK_END -} - -/////////////////// - -void GSLocalMemory::ReadTexture(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP) -{ - readTexture rtx = m_psm[TEX0.PSM].rtx; - readTexel rt = m_psm[TEX0.PSM].rt; - CSize bs = m_psm[TEX0.PSM].bs; - - if(r.Width() < bs.cx || r.Height() < bs.cy - || (r.left & (bs.cx-1)) || (r.top & (bs.cy-1)) - || (r.right & (bs.cx-1)) || (r.bottom & (bs.cy-1)) - || (CLAMP.WMS == 3) || (CLAMP.WMT == 3)) - { - ReadTexture(r, dst, dstpitch, TEX0, TEXA, CLAMP, rt, rtx); - } - else - { - (this->*rtx)(r, dst, dstpitch, TEX0, TEXA); - } -} - -void GSLocalMemory::ReadTextureNC(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP) -{ - readTexture rtx = m_psm[TEX0.PSM].rtx; - readTexel rt = m_psm[TEX0.PSM].rt; - CSize bs = m_psm[TEX0.PSM].bs; - - if(r.Width() < bs.cx || r.Height() < bs.cy - || (r.left & (bs.cx-1)) || (r.top & (bs.cy-1)) - || (r.right & (bs.cx-1)) || (r.bottom & (bs.cy-1))) - { - ReadTextureNC(r, dst, dstpitch, TEX0, TEXA, rt, rtx); - } - else - { - (this->*rtx)(r, dst, dstpitch, TEX0, TEXA); - } -} -/////////////////// - -void GSLocalMemory::ReadTexture16NP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - FOREACH_BLOCK_START(16, 8, 16) - { - ReadBlock16((BYTE*)&m_vm16[BlockAddress16(x, y, bp, bw)], dst, dstpitch); - } - FOREACH_BLOCK_END -} - -void GSLocalMemory::ReadTexture16SNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - FOREACH_BLOCK_START(16, 8, 16) - { - ReadBlock16((BYTE*)&m_vm16[BlockAddress16S(x, y, bp, bw)], dst, dstpitch); - } - FOREACH_BLOCK_END -} - -void GSLocalMemory::ReadTexture8NP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - const DWORD* pal = m_clut; - - if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24) - { - FOREACH_BLOCK_START(16, 16, 32) - { - ReadAndExpandBlock8_32((BYTE*)&m_vm8[BlockAddress8(x, y, bp, bw)], dst, dstpitch, pal); - } - FOREACH_BLOCK_END - } - else - { - ASSERT(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S); - - __declspec(align(16)) BYTE block[16 * 16]; - - FOREACH_BLOCK_START(16, 16, 16) - { - ReadBlock8(&m_vm8[BlockAddress8(x, y, bp, bw)], (BYTE*)block, sizeof(block) / 16); - - ExpandBlock8_16(block, dst, dstpitch, pal); - } - FOREACH_BLOCK_END - } -} - -void GSLocalMemory::ReadTexture4NP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - const UINT64* pal = m_clut; - - if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24) - { - FOREACH_BLOCK_START(32, 16, 32) - { - ReadAndExpandBlock4_32(&m_vm8[BlockAddress4(x, y, bp, bw) >> 1], dst, dstpitch, pal); - } - FOREACH_BLOCK_END - } - else - { - ASSERT(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S); - - __declspec(align(16)) BYTE block[(32 / 2) * 16]; - - FOREACH_BLOCK_START(32, 16, 16) - { - ReadBlock4(&m_vm8[BlockAddress4(x, y, bp, bw)>>1], (BYTE*)block, sizeof(block) / 16); - - ExpandBlock4_16(block, dst, dstpitch, pal); - } - FOREACH_BLOCK_END - } -} - -void GSLocalMemory::ReadTexture8HNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - const DWORD* pal = m_clut; - - if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24) - { - FOREACH_BLOCK_START(8, 8, 32) - { - ReadAndExpandBlock8H_32((const BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch, pal); - } - FOREACH_BLOCK_END - } - else - { - ASSERT(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S); - - __declspec(align(16)) DWORD block[8 * 8]; - - FOREACH_BLOCK_START(8, 8, 16) - { - ReadBlock32((const BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], (BYTE*)block, sizeof(block) / 8); - - ExpandBlock8H_16(block, dst, dstpitch, pal); - } - FOREACH_BLOCK_END - } -} - -void GSLocalMemory::ReadTexture4HLNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - const DWORD* pal = m_clut; - - if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24) - { - FOREACH_BLOCK_START(8, 8, 32) - { - ReadAndExpandBlock4HL_32((const BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch, pal); - } - FOREACH_BLOCK_END - } - else - { - ASSERT(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S); - - __declspec(align(16)) DWORD block[8 * 8]; - - FOREACH_BLOCK_START(8, 8, 16) - { - ReadBlock32((const BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], (BYTE*)block, sizeof(block) / 8); - - ExpandBlock4HL_16(block, dst, dstpitch, pal); - } - FOREACH_BLOCK_END - } -} - -void GSLocalMemory::ReadTexture4HHNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - const DWORD* pal = m_clut; - - if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24) - { - FOREACH_BLOCK_START(8, 8, 32) - { - ReadAndExpandBlock4HH_32((const BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch, pal); - } - FOREACH_BLOCK_END - } - else - { - ASSERT(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S); - - __declspec(align(16)) DWORD block[8 * 8]; - - FOREACH_BLOCK_START(8, 8, 16) - { - ReadBlock32((const BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], (BYTE*)block, sizeof(block) / 8); - - ExpandBlock4HH_16(block, dst, dstpitch, pal); - } - FOREACH_BLOCK_END - } -} - -void GSLocalMemory::ReadTexture16ZNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - FOREACH_BLOCK_START(16, 8, 16) - { - ReadBlock16((const BYTE*)&m_vm16[BlockAddress16Z(x, y, bp, bw)], dst, dstpitch); - } - FOREACH_BLOCK_END -} - -void GSLocalMemory::ReadTexture16SZNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - FOREACH_BLOCK_START(16, 8, 16) - { - ReadBlock16((const BYTE*)&m_vm16[BlockAddress16SZ(x, y, bp, bw)], dst, dstpitch); - } - FOREACH_BLOCK_END -} - -/////////////////// - -void GSLocalMemory::ReadTextureNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP) -{ - readTexture rtx = m_psm[TEX0.PSM].rtxNP; - readTexel rt = m_psm[TEX0.PSM].rtNP; - CSize bs = m_psm[TEX0.PSM].bs; - - if(r.Width() < bs.cx || r.Height() < bs.cy - || (r.left & (bs.cx-1)) || (r.top & (bs.cy-1)) - || (r.right & (bs.cx-1)) || (r.bottom & (bs.cy-1)) - || (CLAMP.WMS == 3) || (CLAMP.WMT == 3)) - { - DWORD psm = TEX0.PSM; - - switch(psm) - { - case PSM_PSMT8: - case PSM_PSMT8H: - case PSM_PSMT4: - case PSM_PSMT4HL: - case PSM_PSMT4HH: - psm = TEX0.CPSM; - break; - } - - switch(psm) - { - default: - case PSM_PSMCT32: - case PSM_PSMCT24: - ReadTexture(r, dst, dstpitch, TEX0, TEXA, CLAMP, rt, rtx); - break; - case PSM_PSMCT16: - case PSM_PSMCT16S: - ReadTexture(r, dst, dstpitch, TEX0, TEXA, CLAMP, rt, rtx); - break; - } - } - else - { - (this->*rtx)(r, dst, dstpitch, TEX0, TEXA); - } -} - -void GSLocalMemory::ReadTextureNPNC(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP) -{ - readTexture rtx = m_psm[TEX0.PSM].rtxNP; - readTexel rt = m_psm[TEX0.PSM].rtNP; - CSize bs = m_psm[TEX0.PSM].bs; - - if(r.Width() < bs.cx || r.Height() < bs.cy - || (r.left & (bs.cx-1)) || (r.top & (bs.cy-1)) - || (r.right & (bs.cx-1)) || (r.bottom & (bs.cy-1))) - { - DWORD psm = TEX0.PSM; - - switch(psm) - { - case PSM_PSMT8: - case PSM_PSMT8H: - case PSM_PSMT4: - case PSM_PSMT4HL: - case PSM_PSMT4HH: - psm = TEX0.CPSM; - break; - } - - switch(psm) - { - default: - case PSM_PSMCT32: - case PSM_PSMCT24: - ReadTextureNC(r, dst, dstpitch, TEX0, TEXA, rt, rtx); - break; - case PSM_PSMCT16: - case PSM_PSMCT16S: - ReadTextureNC(r, dst, dstpitch, TEX0, TEXA, rt, rtx); - break; - } - } - else - { - (this->*rtx)(r, dst, dstpitch, TEX0, TEXA); - } -} - -// 32/8 - -void GSLocalMemory::ReadTexture8P(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - FOREACH_BLOCK_START(16, 16, 8) - { - ReadBlock8(&m_vm8[BlockAddress8(x, y, bp, bw)], dst, dstpitch); - } - FOREACH_BLOCK_END -} - -void GSLocalMemory::ReadTexture4P(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - FOREACH_BLOCK_START(32, 16, 8) - { - ReadBlock4P(&m_vm8[BlockAddress4(x, y, bp, bw) >> 1], dst, dstpitch); - } - FOREACH_BLOCK_END -} - -void GSLocalMemory::ReadTexture8HP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - FOREACH_BLOCK_START(8, 8, 8) - { - ReadBlock8HP((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch); - } - FOREACH_BLOCK_END -} - -void GSLocalMemory::ReadTexture4HLP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - FOREACH_BLOCK_START(8, 8, 8) - { - ReadBlock4HLP((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch); - } - FOREACH_BLOCK_END -} - -void GSLocalMemory::ReadTexture4HHP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const -{ - FOREACH_BLOCK_START(8, 8, 8) - { - ReadBlock4HHP((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch); - } - FOREACH_BLOCK_END -} - -// - -template -void GSLocalMemory::ReadTexture(CRect r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, readTexel rt, readTexture rtx) -{ - // TODO: this is a mess, make it more simple - - DWORD wms = CLAMP.WMS, wmt = CLAMP.WMT; - DWORD minu = CLAMP.MINU, maxu = CLAMP.MAXU; - DWORD minv = CLAMP.MINV, maxv = CLAMP.MAXV; - - CSize bs = m_psm[TEX0.PSM].bs; - - int bsxm = bs.cx - 1; - int bsym = bs.cy - 1; - - if(wms == 3 || wmt == 3) - { - if(wms == 3 && wmt == 3) - { - int w = minu + 1; - int h = minv + 1; - - w = (w + bsxm) & ~bsxm; - h = (h + bsym) & ~bsym; - - if(w % bs.cx == 0 && maxu % bs.cx == 0 && h % bs.cy == 0 && maxv % bs.cy == 0) - { -// printf("!!! 1 wms = %d, wmt = %d, %3x %3x %3x %3x, %d %d - %d %d\n", wms, wmt, minu, maxu, minv, maxv, r.left, r.top, r.right, r.bottom); - - T* buff = (T*)_aligned_malloc(w * h * sizeof(T), 16); - - (this->*rtx)(CRect(CPoint(maxu, maxv), CSize(w, h)), (BYTE*)buff, w * sizeof(T), TEX0, TEXA); - - dst -= r.left * sizeof(T); - -// int left = (r.left + minu) & ~minu; -// int right = r.right & ~minu; - - for(int y = r.top; y < r.bottom; y++, dst += dstpitch) - { - T* src = &buff[(y & minv) * w]; - - int x = r.left; -/* - for(; x < left; x++) - { - ((T*)dst)[x] = src[x & minu]; - } - - for(; x < right; x += minu + 1) - { - memcpy(&((T*)dst)[x], src, sizeof(T) * (minu + 1)); - } -*/ - for(; x < r.right; x++) - { - ((T*)dst)[x] = src[x & minu]; - } - } - - _aligned_free(buff); - - return; - } - } - - if(wms == 2) - { - int left = r.left; - r.left = min(r.right, max(r.left, (int)minu)); - r.right = max(r.left, min(r.right, (int)maxu + 1)); - dst += (r.left - left) * sizeof(T); - } - - if(wmt == 2) - { - int top = r.top; - r.top = min(r.bottom, max(r.top, (int)minv)); - r.bottom = max(r.top, min(r.bottom, (int)maxv + 1)); - dst += (r.top - top) * dstpitch; - } - - if(wms == 3 && wmt != 3) - { - int w = ((minu + 1) + bsxm) & ~bsxm; - - if(w % bs.cx == 0 && maxu % bs.cx == 0) - { -// printf("!!! 2 wms = %d, wmt = %d, %3x %3x %3x %3x, %d %d - %d %d\n", wms, wmt, minu, maxu, minv, maxv, r.left, r.top, r.right, r.bottom); - int top = r.top & ~bsym; - int bottom = (r.bottom + bsym) & ~bsym; - - int h = bottom - top; - - T* buff = (T*)_aligned_malloc(w * h * sizeof(T), 16); - - (this->*rtx)(CRect(CPoint(maxu, top), CSize(w, h)), (BYTE*)buff, w * sizeof(T), TEX0, TEXA); - - dst -= r.left * sizeof(T); - -// int left = (r.left + minu) & ~minu; -// int right = r.right & ~minu; - - for(int y = r.top; y < r.bottom; y++, dst += dstpitch) - { - T* src = &buff[(y - top) * w]; - - int x = r.left; -/* - for(; x < left; x++) - { - ((T*)dst)[x] = src[x & minu]; - } - - for(; x < right; x += minu + 1) - { - memcpy(&((T*)dst)[x], src, sizeof(T) * (minu + 1)); - } -*/ - for(; x < r.right; x++) - { - ((T*)dst)[x] = src[x & minu]; - } - } - - _aligned_free(buff); - - return; - } - } - - if(wms != 3 && wmt == 3) - { - int h = (minv + 1 + bsym) & ~bsym; - - if(h % bs.cy == 0 && maxv % bs.cy == 0) - { -// printf("!!! 3 wms = %d, wmt = %d, %3x %3x %3x %3x, %d %d - %d %d\n", wms, wmt, minu, maxu, minv, maxv, r.left, r.top, r.right, r.bottom); - int left = r.left & ~bsxm; - int right = (r.right + bsxm) & ~bsxm; - - int w = right - left; - - T* buff = (T*)_aligned_malloc(w * h * sizeof(T), 16); - - (this->*rtx)(CRect(CPoint(left, maxv), CSize(w, h)), (BYTE*)buff, w * sizeof(T), TEX0, TEXA); - - for(int y = r.top; y < r.bottom; y++, dst += dstpitch) - { - T* src = &buff[(y & minv) * w + (r.left - left)]; - - memcpy(dst, src, sizeof(T) * r.Width()); - } - - _aligned_free(buff); - - return; - } - } - - switch(wms) - { - default: for(int x = r.left; x < r.right; x++) m_xtbl[x] = x; break; - case 3: for(int x = r.left; x < r.right; x++) m_xtbl[x] = (x & minu) | maxu; break; - } - - switch(wmt) - { - default: for(int y = r.top; y < r.bottom; y++) m_ytbl[y] = y; break; - case 3: for(int y = r.top; y < r.bottom; y++) m_ytbl[y] = (y & minv) | maxv; break; - } - -// printf("!!! 4 wms = %d, wmt = %d, %3x %3x %3x %3x, %d %d - %d %d\n", wms, wmt, minu, maxu, minv, maxv, r.left, r.top, r.right, r.bottom); - - for(int y = r.top; y < r.bottom; y++, dst += dstpitch) - for(int x = r.left, i = 0; x < r.right; x++, i++) - ((T*)dst)[i] = (T)(this->*rt)(m_xtbl[x], m_ytbl[y], TEX0, TEXA); - } - else - { - // find a block-aligned rect that fits between r and the region clamped area (if any) - - CRect r1 = r; - CRect r2 = r; - - r1.left = (r1.left + bsxm) & ~bsxm; - r1.top = (r1.top + bsym) & ~bsym; - r1.right = r1.right & ~bsxm; - r1.bottom = r1.bottom & ~bsym; - - if(wms == 2 && minu < maxu) - { - r2.left = minu & ~bsxm; - r2.right = (maxu + bsxm) & ~bsxm; - } - - if(wmt == 2 && minv < maxv) - { - r2.top = minv & ~bsym; - r2.bottom = (maxv + bsym) & ~bsym; - } - - CRect cr = r1 & r2; - - bool aligned = ((DWORD_PTR)(dst + (cr.left - r.left) * sizeof(T)) & 0xf) == 0; - - if(cr.left >= cr.right && cr.top >= cr.bottom || !aligned) - { - // TODO: expand r to block size, read into temp buffer, copy to r (like above) - -if(!aligned) printf("unaligned memory pointer passed to ReadTexture\n"); - -// printf("!!! 5 wms = %d, wmt = %d, %3x %3x %3x %3x, %d %d - %d %d\n", wms, wmt, minu, maxu, minv, maxv, r.left, r.top, r.right, r.bottom); - - for(int y = r.top; y < r.bottom; y++, dst += dstpitch) - for(int x = r.left, i = 0; x < r.right; x++, i++) - ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); - } - else - { -// printf("!!! 6 wms = %d, wmt = %d, %3x %3x %3x %3x, %d %d - %d %d\n", wms, wmt, minu, maxu, minv, maxv, r.left, r.top, r.right, r.bottom); - - for(int y = r.top; y < cr.top; y++, dst += dstpitch) - for(int x = r.left, i = 0; x < r.right; x++, i++) - ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); - - if(!cr.IsRectEmpty()) - { - (this->*rtx)(cr, dst + (cr.left - r.left) * sizeof(T), dstpitch, TEX0, TEXA); - } - - for(int y = cr.top; y < cr.bottom; y++, dst += dstpitch) - { - for(int x = r.left, i = 0; x < cr.left; x++, i++) - ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); - for(int x = cr.right, i = x - r.left; x < r.right; x++, i++) - ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); - } - - for(int y = cr.bottom; y < r.bottom; y++, dst += dstpitch) - for(int x = r.left, i = 0; x < r.right; x++, i++) - ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); - } - } -} - -template -void GSLocalMemory::ReadTextureNC(CRect r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, readTexel rt, readTexture rtx) -{ - CSize bs = m_psm[TEX0.PSM].bs; - - int bsxm = bs.cx - 1; - int bsym = bs.cy - 1; - - CRect cr; - - cr.left = (r.left + bsxm) & ~bsxm; - cr.top = (r.top + bsym) & ~bsym; - cr.right = r.right & ~bsxm; - cr.bottom = r.bottom & ~bsym; - - bool aligned = ((DWORD_PTR)(dst + (cr.left - r.left) * sizeof(T)) & 0xf) == 0; - - if(cr.left >= cr.right && cr.top >= cr.bottom || !aligned) - { - // TODO: expand r to block size, read into temp buffer, copy to r (like above) - -if(!aligned) printf("unaligned memory pointer passed to ReadTexture\n"); - - for(int y = r.top; y < r.bottom; y++, dst += dstpitch) - for(int x = r.left, i = 0; x < r.right; x++, i++) - ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); - } - else - { - for(int y = r.top; y < cr.top; y++, dst += dstpitch) - for(int x = r.left, i = 0; x < r.right; x++, i++) - ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); - - if(!cr.IsRectEmpty()) - (this->*rtx)(cr, dst + (cr.left - r.left) * sizeof(T), dstpitch, TEX0, TEXA); - - for(int y = cr.top; y < cr.bottom; y++, dst += dstpitch) - { - for(int x = r.left, i = 0; x < cr.left; x++, i++) - ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); - for(int x = cr.right, i = x - r.left; x < r.right; x++, i++) - ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); - } - - for(int y = cr.bottom; y < r.bottom; y++, dst += dstpitch) - for(int x = r.left, i = 0; x < r.right; x++, i++) - ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); - } -} - -HRESULT GSLocalMemory::SaveBMP(LPCTSTR fn, DWORD bp, DWORD bw, DWORD psm, int w, int h) -{ - int pitch = w * 4; - int size = pitch * h; - void* bits = ::_aligned_malloc(size, 16); - - GIFRegTEX0 TEX0; - - TEX0.TBP0 = bp; - TEX0.TBW = bw; - TEX0.PSM = psm; - - GIFRegTEXA TEXA; - - TEXA.AEM = 0; - TEXA.TA0 = 0; - TEXA.TA1 = 0x80; - - // (this->*m_psm[TEX0.PSM].rtx)(CRect(0, 0, w, h), bits, pitch, TEX0, TEXA); - - readPixel rp = m_psm[psm].rp; - - BYTE* p = (BYTE*)bits; - - for(int j = h-1; j >= 0; j--, p += pitch) - for(int i = 0; i < w; i++) - ((DWORD*)p)[i] = (this->*rp)(i, j, TEX0.TBP0, TEX0.TBW); - - if(FILE* fp = _tfopen(fn, _T("wb"))) - { - BITMAPINFOHEADER bih; - memset(&bih, 0, sizeof(bih)); - bih.biSize = sizeof(bih); - bih.biWidth = w; - bih.biHeight = h; - bih.biPlanes = 1; - bih.biBitCount = 32; - bih.biCompression = BI_RGB; - bih.biSizeImage = size; - - BITMAPFILEHEADER bfh; - memset(&bfh, 0, sizeof(bfh)); - bfh.bfType = 'MB'; - bfh.bfOffBits = sizeof(bfh) + sizeof(bih); - bfh.bfSize = bfh.bfOffBits + size; - bfh.bfReserved1 = bfh.bfReserved2 = 0; - - fwrite(&bfh, 1, sizeof(bfh), fp); - fwrite(&bih, 1, sizeof(bih), fp); - fwrite(bits, 1, size, fp); - - fclose(fp); - } - - ::_aligned_free(bits); - - return true; -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * Special Notes: + * + * Based on Page.c from GSSoft + * Copyright (C) 2002-2004 GSsoft Team + * + */ + +#include "StdAfx.h" +#include "GSLocalMemory.h" + +#define ASSERT_BLOCK(r, w, h) \ + ASSERT((r).Width() >= w && (r).Height() >= h && !((r).left&(w-1)) && !((r).top&(h-1)) && !((r).right&(w-1)) && !((r).bottom&(h-1))); \ + +#define FOREACH_BLOCK_START(w, h, bpp) \ + DWORD bp = TEX0.TBP0; \ + DWORD bw = TEX0.TBW; \ + int offset = dstpitch * h - (r.right - r.left) * bpp / 8; \ + for(int y = r.top; y < r.bottom; y += h, dst += offset) \ + { ASSERT_BLOCK(r, w, h); \ + for(int x = r.left; x < r.right; x += w, dst += w * bpp / 8) \ + { \ + +#define FOREACH_BLOCK_END }} + +// + +DWORD GSLocalMemory::pageOffset32[32][32][64]; +DWORD GSLocalMemory::pageOffset32Z[32][32][64]; +DWORD GSLocalMemory::pageOffset16[32][64][64]; +DWORD GSLocalMemory::pageOffset16S[32][64][64]; +DWORD GSLocalMemory::pageOffset16Z[32][64][64]; +DWORD GSLocalMemory::pageOffset16SZ[32][64][64]; +DWORD GSLocalMemory::pageOffset8[32][64][128]; +DWORD GSLocalMemory::pageOffset4[32][128][128]; + +int GSLocalMemory::rowOffset32[2048]; +int GSLocalMemory::rowOffset32Z[2048]; +int GSLocalMemory::rowOffset16[2048]; +int GSLocalMemory::rowOffset16S[2048]; +int GSLocalMemory::rowOffset16Z[2048]; +int GSLocalMemory::rowOffset16SZ[2048]; +int GSLocalMemory::rowOffset8[2][2048]; +int GSLocalMemory::rowOffset4[2][2048]; + +// + +DWORD GSLocalMemory::m_xtbl[1024]; +DWORD GSLocalMemory::m_ytbl[1024]; + +// + +GSLocalMemory::psm_t GSLocalMemory::m_psm[64]; + +// + +GSLocalMemory::GSLocalMemory() + : m_clut(this) +{ + m_vm8 = (BYTE*)VirtualAlloc(NULL, m_vmsize * 2, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + + memset(m_vm8, 0, m_vmsize); + + for(int bp = 0; bp < 32; bp++) + { + for(int y = 0; y < 32; y++) for(int x = 0; x < 64; x++) + { + pageOffset32[bp][y][x] = PixelAddressOrg32(x, y, bp, 0); + pageOffset32Z[bp][y][x] = PixelAddressOrg32Z(x, y, bp, 0); + } + + for(int y = 0; y < 64; y++) for(int x = 0; x < 64; x++) + { + pageOffset16[bp][y][x] = PixelAddressOrg16(x, y, bp, 0); + pageOffset16S[bp][y][x] = PixelAddressOrg16S(x, y, bp, 0); + pageOffset16Z[bp][y][x] = PixelAddressOrg16Z(x, y, bp, 0); + pageOffset16SZ[bp][y][x] = PixelAddressOrg16SZ(x, y, bp, 0); + } + + for(int y = 0; y < 64; y++) for(int x = 0; x < 128; x++) + { + pageOffset8[bp][y][x] = PixelAddressOrg8(x, y, bp, 0); + } + + for(int y = 0; y < 128; y++) for(int x = 0; x < 128; x++) + { + pageOffset4[bp][y][x] = PixelAddressOrg4(x, y, bp, 0); + } + } + + for(int x = 0; x < countof(rowOffset32); x++) + { + rowOffset32[x] = (int)PixelAddress32(x, 0, 0, 32) - (int)PixelAddress32(0, 0, 0, 32); + } + + for(int x = 0; x < countof(rowOffset32Z); x++) + { + rowOffset32Z[x] = (int)PixelAddress32Z(x, 0, 0, 32) - (int)PixelAddress32Z(0, 0, 0, 32); + } + + for(int x = 0; x < countof(rowOffset16); x++) + { + rowOffset16[x] = (int)PixelAddress16(x, 0, 0, 32) - (int)PixelAddress16(0, 0, 0, 32); + } + + for(int x = 0; x < countof(rowOffset16S); x++) + { + rowOffset16S[x] = (int)PixelAddress16S(x, 0, 0, 32) - (int)PixelAddress16S(0, 0, 0, 32); + } + + for(int x = 0; x < countof(rowOffset16Z); x++) + { + rowOffset16Z[x] = (int)PixelAddress16Z(x, 0, 0, 32) - (int)PixelAddress16Z(0, 0, 0, 32); + } + + for(int x = 0; x < countof(rowOffset16SZ); x++) + { + rowOffset16SZ[x] = (int)PixelAddress16SZ(x, 0, 0, 32) - (int)PixelAddress16SZ(0, 0, 0, 32); + } + + for(int x = 0; x < countof(rowOffset8[0]); x++) + { + rowOffset8[0][x] = (int)PixelAddress8(x, 0, 0, 32) - (int)PixelAddress8(0, 0, 0, 32), + rowOffset8[1][x] = (int)PixelAddress8(x, 2, 0, 32) - (int)PixelAddress8(0, 2, 0, 32); + } + + for(int x = 0; x < countof(rowOffset4[0]); x++) + { + rowOffset4[0][x] = (int)PixelAddress4(x, 0, 0, 32) - (int)PixelAddress4(0, 0, 0, 32), + rowOffset4[1][x] = (int)PixelAddress4(x, 2, 0, 32) - (int)PixelAddress4(0, 2, 0, 32); + } + + for(int i = 0; i < countof(m_psm); i++) + { + m_psm[i].pa = &GSLocalMemory::PixelAddress32; + m_psm[i].ba = &GSLocalMemory::BlockAddress32; + m_psm[i].pga = &GSLocalMemory::PageAddress32; + m_psm[i].pgn = &GSLocalMemory::PageNumber32; + m_psm[i].rp = &GSLocalMemory::ReadPixel32; + m_psm[i].rpa = &GSLocalMemory::ReadPixel32; + m_psm[i].wp = &GSLocalMemory::WritePixel32; + m_psm[i].wpa = &GSLocalMemory::WritePixel32; + m_psm[i].rt = &GSLocalMemory::ReadTexel32; + m_psm[i].rtNP = &GSLocalMemory::ReadTexel32; + m_psm[i].rta = &GSLocalMemory::ReadTexel32; + m_psm[i].wfa = &GSLocalMemory::WritePixel32; + m_psm[i].wi = &GSLocalMemory::WriteImage; + m_psm[i].ri = &GSLocalMemory::ReadImageX; // TODO + m_psm[i].rtx = &GSLocalMemory::ReadTexture32; + m_psm[i].rtxNP = &GSLocalMemory::ReadTexture32; + m_psm[i].rtxP = &GSLocalMemory::ReadTexture32; + m_psm[i].bpp = m_psm[i].trbpp = 32; + m_psm[i].pal = 0; + m_psm[i].bs = CSize(8, 8); + m_psm[i].pgs = CSize(64, 32); + for(int j = 0; j < 8; j++) m_psm[i].rowOffset[j] = rowOffset32; + } + + m_psm[PSM_PSMCT16].pa = &GSLocalMemory::PixelAddress16; + m_psm[PSM_PSMCT16S].pa = &GSLocalMemory::PixelAddress16S; + m_psm[PSM_PSMT8].pa = &GSLocalMemory::PixelAddress8; + m_psm[PSM_PSMT4].pa = &GSLocalMemory::PixelAddress4; + m_psm[PSM_PSMZ32].pa = &GSLocalMemory::PixelAddress32Z; + m_psm[PSM_PSMZ24].pa = &GSLocalMemory::PixelAddress32Z; + m_psm[PSM_PSMZ16].pa = &GSLocalMemory::PixelAddress16Z; + m_psm[PSM_PSMZ16S].pa = &GSLocalMemory::PixelAddress16SZ; + + m_psm[PSM_PSMCT16].ba = &GSLocalMemory::BlockAddress16; + m_psm[PSM_PSMCT16S].ba = &GSLocalMemory::BlockAddress16S; + m_psm[PSM_PSMT8].ba = &GSLocalMemory::BlockAddress8; + m_psm[PSM_PSMT4].ba = &GSLocalMemory::BlockAddress4; + m_psm[PSM_PSMZ32].ba = &GSLocalMemory::BlockAddress32Z; + m_psm[PSM_PSMZ24].ba = &GSLocalMemory::BlockAddress32Z; + m_psm[PSM_PSMZ16].ba = &GSLocalMemory::BlockAddress16Z; + m_psm[PSM_PSMZ16S].ba = &GSLocalMemory::BlockAddress16SZ; + + m_psm[PSM_PSMCT16].pga = &GSLocalMemory::PageAddress16; + m_psm[PSM_PSMCT16S].pga = &GSLocalMemory::PageAddress16; + m_psm[PSM_PSMZ16].pga = &GSLocalMemory::PageAddress16; + m_psm[PSM_PSMZ16S].pga = &GSLocalMemory::PageAddress16; + m_psm[PSM_PSMT8].pga = &GSLocalMemory::PageAddress8; + m_psm[PSM_PSMT4].pga = &GSLocalMemory::PageAddress4; + + m_psm[PSM_PSMCT16].pgn = &GSLocalMemory::PageNumber16; + m_psm[PSM_PSMCT16S].pgn = &GSLocalMemory::PageNumber16; + m_psm[PSM_PSMZ16].pgn = &GSLocalMemory::PageNumber16; + m_psm[PSM_PSMZ16S].pgn = &GSLocalMemory::PageNumber16; + m_psm[PSM_PSMT8].pgn = &GSLocalMemory::PageNumber8; + m_psm[PSM_PSMT4].pgn = &GSLocalMemory::PageNumber4; + + m_psm[PSM_PSMCT24].rp = &GSLocalMemory::ReadPixel24; + m_psm[PSM_PSMCT16].rp = &GSLocalMemory::ReadPixel16; + m_psm[PSM_PSMCT16S].rp = &GSLocalMemory::ReadPixel16S; + m_psm[PSM_PSMT8].rp = &GSLocalMemory::ReadPixel8; + m_psm[PSM_PSMT4].rp = &GSLocalMemory::ReadPixel4; + m_psm[PSM_PSMT8H].rp = &GSLocalMemory::ReadPixel8H; + m_psm[PSM_PSMT4HL].rp = &GSLocalMemory::ReadPixel4HL; + m_psm[PSM_PSMT4HH].rp = &GSLocalMemory::ReadPixel4HH; + m_psm[PSM_PSMZ32].rp = &GSLocalMemory::ReadPixel32Z; + m_psm[PSM_PSMZ24].rp = &GSLocalMemory::ReadPixel24Z; + m_psm[PSM_PSMZ16].rp = &GSLocalMemory::ReadPixel16Z; + m_psm[PSM_PSMZ16S].rp = &GSLocalMemory::ReadPixel16SZ; + + m_psm[PSM_PSMCT24].rpa = &GSLocalMemory::ReadPixel24; + m_psm[PSM_PSMCT16].rpa = &GSLocalMemory::ReadPixel16; + m_psm[PSM_PSMCT16S].rpa = &GSLocalMemory::ReadPixel16; + m_psm[PSM_PSMT8].rpa = &GSLocalMemory::ReadPixel8; + m_psm[PSM_PSMT4].rpa = &GSLocalMemory::ReadPixel4; + m_psm[PSM_PSMT8H].rpa = &GSLocalMemory::ReadPixel8H; + m_psm[PSM_PSMT4HL].rpa = &GSLocalMemory::ReadPixel4HL; + m_psm[PSM_PSMT4HH].rpa = &GSLocalMemory::ReadPixel4HH; + m_psm[PSM_PSMZ32].rpa = &GSLocalMemory::ReadPixel32; + m_psm[PSM_PSMZ24].rpa = &GSLocalMemory::ReadPixel24; + m_psm[PSM_PSMZ16].rpa = &GSLocalMemory::ReadPixel16; + m_psm[PSM_PSMZ16S].rpa = &GSLocalMemory::ReadPixel16; + + m_psm[PSM_PSMCT32].wp = &GSLocalMemory::WritePixel32; + m_psm[PSM_PSMCT24].wp = &GSLocalMemory::WritePixel24; + m_psm[PSM_PSMCT16].wp = &GSLocalMemory::WritePixel16; + m_psm[PSM_PSMCT16S].wp = &GSLocalMemory::WritePixel16S; + m_psm[PSM_PSMT8].wp = &GSLocalMemory::WritePixel8; + m_psm[PSM_PSMT4].wp = &GSLocalMemory::WritePixel4; + m_psm[PSM_PSMT8H].wp = &GSLocalMemory::WritePixel8H; + m_psm[PSM_PSMT4HL].wp = &GSLocalMemory::WritePixel4HL; + m_psm[PSM_PSMT4HH].wp = &GSLocalMemory::WritePixel4HH; + m_psm[PSM_PSMZ32].wp = &GSLocalMemory::WritePixel32Z; + m_psm[PSM_PSMZ24].wp = &GSLocalMemory::WritePixel24Z; + m_psm[PSM_PSMZ16].wp = &GSLocalMemory::WritePixel16Z; + m_psm[PSM_PSMZ16S].wp = &GSLocalMemory::WritePixel16SZ; + + m_psm[PSM_PSMCT32].wpa = &GSLocalMemory::WritePixel32; + m_psm[PSM_PSMCT24].wpa = &GSLocalMemory::WritePixel24; + m_psm[PSM_PSMCT16].wpa = &GSLocalMemory::WritePixel16; + m_psm[PSM_PSMCT16S].wpa = &GSLocalMemory::WritePixel16; + m_psm[PSM_PSMT8].wpa = &GSLocalMemory::WritePixel8; + m_psm[PSM_PSMT4].wpa = &GSLocalMemory::WritePixel4; + m_psm[PSM_PSMT8H].wpa = &GSLocalMemory::WritePixel8H; + m_psm[PSM_PSMT4HL].wpa = &GSLocalMemory::WritePixel4HL; + m_psm[PSM_PSMT4HH].wpa = &GSLocalMemory::WritePixel4HH; + m_psm[PSM_PSMZ32].wpa = &GSLocalMemory::WritePixel32; + m_psm[PSM_PSMZ24].wpa = &GSLocalMemory::WritePixel24; + m_psm[PSM_PSMZ16].wpa = &GSLocalMemory::WritePixel16; + m_psm[PSM_PSMZ16S].wpa = &GSLocalMemory::WritePixel16; + + m_psm[PSM_PSMCT24].rt = &GSLocalMemory::ReadTexel24; + m_psm[PSM_PSMCT16].rt = &GSLocalMemory::ReadTexel16; + m_psm[PSM_PSMCT16S].rt = &GSLocalMemory::ReadTexel16S; + m_psm[PSM_PSMT8].rt = &GSLocalMemory::ReadTexel8; + m_psm[PSM_PSMT4].rt = &GSLocalMemory::ReadTexel4; + m_psm[PSM_PSMT8H].rt = &GSLocalMemory::ReadTexel8H; + m_psm[PSM_PSMT4HL].rt = &GSLocalMemory::ReadTexel4HL; + m_psm[PSM_PSMT4HH].rt = &GSLocalMemory::ReadTexel4HH; + m_psm[PSM_PSMZ32].rt = &GSLocalMemory::ReadTexel32Z; + m_psm[PSM_PSMZ24].rt = &GSLocalMemory::ReadTexel24Z; + m_psm[PSM_PSMZ16].rt = &GSLocalMemory::ReadTexel16Z; + m_psm[PSM_PSMZ16S].rt = &GSLocalMemory::ReadTexel16SZ; + + m_psm[PSM_PSMCT24].rta = &GSLocalMemory::ReadTexel24; + m_psm[PSM_PSMCT16].rta = &GSLocalMemory::ReadTexel16; + m_psm[PSM_PSMCT16S].rta = &GSLocalMemory::ReadTexel16; + m_psm[PSM_PSMT8].rta = &GSLocalMemory::ReadTexel8; + m_psm[PSM_PSMT4].rta = &GSLocalMemory::ReadTexel4; + m_psm[PSM_PSMT8H].rta = &GSLocalMemory::ReadTexel8H; + m_psm[PSM_PSMT4HL].rta = &GSLocalMemory::ReadTexel4HL; + m_psm[PSM_PSMT4HH].rta = &GSLocalMemory::ReadTexel4HH; + m_psm[PSM_PSMZ24].rta = &GSLocalMemory::ReadTexel24; + m_psm[PSM_PSMZ16].rta = &GSLocalMemory::ReadTexel16; + m_psm[PSM_PSMZ16S].rta = &GSLocalMemory::ReadTexel16; + + m_psm[PSM_PSMCT24].wfa = &GSLocalMemory::WritePixel24; + m_psm[PSM_PSMCT16].wfa = &GSLocalMemory::WriteFrame16; + m_psm[PSM_PSMCT16S].wfa = &GSLocalMemory::WriteFrame16; + m_psm[PSM_PSMZ24].wfa = &GSLocalMemory::WritePixel24; + m_psm[PSM_PSMZ16].wfa = &GSLocalMemory::WriteFrame16; + m_psm[PSM_PSMZ16S].wfa = &GSLocalMemory::WriteFrame16; + + m_psm[PSM_PSMCT16].rtNP = &GSLocalMemory::ReadTexel16NP; + m_psm[PSM_PSMCT16S].rtNP = &GSLocalMemory::ReadTexel16SNP; + m_psm[PSM_PSMT8].rtNP = &GSLocalMemory::ReadTexel8; + m_psm[PSM_PSMT4].rtNP = &GSLocalMemory::ReadTexel4; + m_psm[PSM_PSMT8H].rtNP = &GSLocalMemory::ReadTexel8H; + m_psm[PSM_PSMT4HL].rtNP = &GSLocalMemory::ReadTexel4HL; + m_psm[PSM_PSMT4HH].rtNP = &GSLocalMemory::ReadTexel4HH; + m_psm[PSM_PSMZ32].rtNP = &GSLocalMemory::ReadTexel32Z; + m_psm[PSM_PSMZ24].rtNP = &GSLocalMemory::ReadTexel24Z; + m_psm[PSM_PSMZ16].rtNP = &GSLocalMemory::ReadTexel16ZNP; + m_psm[PSM_PSMZ16S].rtNP = &GSLocalMemory::ReadTexel16SZNP; + + m_psm[PSM_PSMCT24].wi = &GSLocalMemory::WriteImage24; // TODO + m_psm[PSM_PSMCT16].wi = &GSLocalMemory::WriteImage; + m_psm[PSM_PSMCT16S].wi = &GSLocalMemory::WriteImage; + m_psm[PSM_PSMT8].wi = &GSLocalMemory::WriteImage; + m_psm[PSM_PSMT4].wi = &GSLocalMemory::WriteImage; + m_psm[PSM_PSMT8H].wi = &GSLocalMemory::WriteImage8H; // TODO + m_psm[PSM_PSMT4HL].wi = &GSLocalMemory::WriteImage4HL; // TODO + m_psm[PSM_PSMT4HH].wi = &GSLocalMemory::WriteImage4HH; // TODO + m_psm[PSM_PSMZ32].wi = &GSLocalMemory::WriteImage; + m_psm[PSM_PSMZ24].wi = &GSLocalMemory::WriteImage24Z; // TODO + m_psm[PSM_PSMZ16].wi = &GSLocalMemory::WriteImage; + m_psm[PSM_PSMZ16S].wi = &GSLocalMemory::WriteImage; + + m_psm[PSM_PSMCT24].rtx = &GSLocalMemory::ReadTexture24; + m_psm[PSM_PSMCT16].rtx = &GSLocalMemory::ReadTexture16; + m_psm[PSM_PSMCT16S].rtx = &GSLocalMemory::ReadTexture16S; + m_psm[PSM_PSMT8].rtx = &GSLocalMemory::ReadTexture8; + m_psm[PSM_PSMT4].rtx = &GSLocalMemory::ReadTexture4; + m_psm[PSM_PSMT8H].rtx = &GSLocalMemory::ReadTexture8H; + m_psm[PSM_PSMT4HL].rtx = &GSLocalMemory::ReadTexture4HL; + m_psm[PSM_PSMT4HH].rtx = &GSLocalMemory::ReadTexture4HH; + m_psm[PSM_PSMZ32].rtx = &GSLocalMemory::ReadTexture32Z; + m_psm[PSM_PSMZ24].rtx = &GSLocalMemory::ReadTexture24Z; + m_psm[PSM_PSMZ16].rtx = &GSLocalMemory::ReadTexture16Z; + m_psm[PSM_PSMZ16S].rtx = &GSLocalMemory::ReadTexture16SZ; + + m_psm[PSM_PSMCT16].rtxNP = &GSLocalMemory::ReadTexture16NP; + m_psm[PSM_PSMCT16S].rtxNP = &GSLocalMemory::ReadTexture16SNP; + m_psm[PSM_PSMT8].rtxNP = &GSLocalMemory::ReadTexture8NP; + m_psm[PSM_PSMT4].rtxNP = &GSLocalMemory::ReadTexture4NP; + m_psm[PSM_PSMT8H].rtxNP = &GSLocalMemory::ReadTexture8HNP; + m_psm[PSM_PSMT4HL].rtxNP = &GSLocalMemory::ReadTexture4HLNP; + m_psm[PSM_PSMT4HH].rtxNP = &GSLocalMemory::ReadTexture4HHNP; + m_psm[PSM_PSMZ32].rtxNP = &GSLocalMemory::ReadTexture32Z; + m_psm[PSM_PSMZ24].rtxNP = &GSLocalMemory::ReadTexture24Z; + m_psm[PSM_PSMZ16].rtxNP = &GSLocalMemory::ReadTexture16ZNP; + m_psm[PSM_PSMZ16S].rtxNP = &GSLocalMemory::ReadTexture16SZNP; + + m_psm[PSM_PSMT8].rtxP = &GSLocalMemory::ReadTexture8P; + m_psm[PSM_PSMT4].rtxP = &GSLocalMemory::ReadTexture4P; + m_psm[PSM_PSMT8H].rtxP = &GSLocalMemory::ReadTexture8HP; + m_psm[PSM_PSMT4HL].rtxP = &GSLocalMemory::ReadTexture4HLP; + m_psm[PSM_PSMT4HH].rtxP = &GSLocalMemory::ReadTexture4HHP; + + m_psm[PSM_PSMT8].pal = m_psm[PSM_PSMT8H].pal = 256; + m_psm[PSM_PSMT4].pal = m_psm[PSM_PSMT4HL].pal = m_psm[PSM_PSMT4HH].pal = 16; + + m_psm[PSM_PSMCT16].bpp = m_psm[PSM_PSMCT16S].bpp = 16; + m_psm[PSM_PSMT8].bpp = 8; + m_psm[PSM_PSMT4].bpp = 4; + m_psm[PSM_PSMZ16].bpp = m_psm[PSM_PSMZ16S].bpp = 16; + + m_psm[PSM_PSMCT24].trbpp = 24; + m_psm[PSM_PSMCT16].trbpp = m_psm[PSM_PSMCT16S].trbpp = 16; + m_psm[PSM_PSMT8].trbpp = m_psm[PSM_PSMT8H].trbpp = 8; + m_psm[PSM_PSMT4].trbpp = m_psm[PSM_PSMT4HL].trbpp = m_psm[PSM_PSMT4HH].trbpp = 4; + m_psm[PSM_PSMZ24].trbpp = 24; + m_psm[PSM_PSMZ16].trbpp = m_psm[PSM_PSMZ16S].trbpp = 16; + + m_psm[PSM_PSMCT16].bs = m_psm[PSM_PSMCT16S].bs = CSize(16, 8); + m_psm[PSM_PSMT8].bs = CSize(16, 16); + m_psm[PSM_PSMT4].bs = CSize(32, 16); + m_psm[PSM_PSMZ16].bs = m_psm[PSM_PSMZ16S].bs = CSize(16, 8); + + m_psm[PSM_PSMCT16].pgs = m_psm[PSM_PSMCT16S].pgs = CSize(64, 64); + m_psm[PSM_PSMT8].pgs = CSize(128, 64); + m_psm[PSM_PSMT4].pgs = CSize(128, 128); + m_psm[PSM_PSMZ16].pgs = m_psm[PSM_PSMZ16S].pgs = CSize(64, 64); + + for(int i = 0; i < 8; i++) m_psm[PSM_PSMCT16].rowOffset[i] = rowOffset16; + for(int i = 0; i < 8; i++) m_psm[PSM_PSMCT16S].rowOffset[i] = rowOffset16S; + for(int i = 0; i < 8; i++) m_psm[PSM_PSMT8].rowOffset[i] = rowOffset8[((i + 2) >> 2) & 1]; + for(int i = 0; i < 8; i++) m_psm[PSM_PSMT4].rowOffset[i] = rowOffset4[((i + 2) >> 2) & 1]; + for(int i = 0; i < 8; i++) m_psm[PSM_PSMZ32].rowOffset[i] = rowOffset32Z; + for(int i = 0; i < 8; i++) m_psm[PSM_PSMZ24].rowOffset[i] = rowOffset32Z; + for(int i = 0; i < 8; i++) m_psm[PSM_PSMZ16].rowOffset[i] = rowOffset16Z; + for(int i = 0; i < 8; i++) m_psm[PSM_PSMZ16S].rowOffset[i] = rowOffset16SZ; +} + +GSLocalMemory::~GSLocalMemory() +{ + VirtualFree(m_vm8, 0, MEM_RELEASE); + + POSITION pos = m_omap.GetHeadPosition(); + + while(pos) + { + Offset* o = m_omap.GetNextValue(pos); + + for(int i = 0; i < countof(o->col); i++) + { + _aligned_free(o->col); + } + + _aligned_free(o); + } + + m_omap.RemoveAll(); + + pos = m_o4map.GetHeadPosition(); + + while(pos) + { + _aligned_free(m_o4map.GetNextValue(pos)); + } + + m_o4map.RemoveAll(); +} + +GSLocalMemory::Offset* GSLocalMemory::GetOffset(DWORD bp, DWORD bw, DWORD psm) +{ + if(bw == 0) {ASSERT(0); return NULL;} + + ASSERT(m_psm[psm].bpp > 8); // only for 16/24/32/8h/4hh/4hl formats where all columns are the same + + DWORD hash = bp | (bw << 14) | (psm << 20); + + if(CRBMap::CPair* pair = m_omap.Lookup(hash)) + { + return pair->m_value; + } + + Offset* o = (Offset*)_aligned_malloc(sizeof(Offset), 16); + + o->hash = hash; + + pixelAddress pa = m_psm[psm].pa; + + for(int i = 0; i < 2048; i++) + { + o->row[i] = GSVector4i((int)pa(0, i, bp, bw)); + } + + int* p = (int*)_aligned_malloc(sizeof(int) * (2048 + 3) * 4, 16); + + for(int i = 0; i < 4; i++) + { + o->col[i] = &p[2048 * i + ((4 - (i & 3)) & 3)]; + + memcpy(o->col[i], m_psm[psm].rowOffset[0], sizeof(int) * 2048); + } + + m_omap.SetAt(hash, o); + + return o; +} + +GSLocalMemory::Offset4* GSLocalMemory::GetOffset4(const GIFRegFRAME& FRAME, const GIFRegZBUF& ZBUF) +{ + DWORD fbp = FRAME.Block(); + DWORD zbp = ZBUF.Block(); + DWORD fpsm = FRAME.PSM; + DWORD zpsm = ZBUF.PSM; + DWORD bw = FRAME.FBW; + + ASSERT(m_psm[fpsm].trbpp > 8 || m_psm[zpsm].trbpp > 8); + + // "(psm & 0x0f) ^ ((psm & 0xf0) >> 2)" creates 4 bit unique identifiers for render target formats (only) + + DWORD fpsm_hash = (fpsm & 0x0f) ^ ((fpsm & 0x30) >> 2); + DWORD zpsm_hash = (zpsm & 0x0f) ^ ((zpsm & 0x30) >> 2); + + DWORD hash = (FRAME.FBP << 0) | (ZBUF.ZBP << 9) | (bw << 18) | (fpsm_hash << 24) | (zpsm_hash << 28); + + if(CRBMap::CPair* pair = m_o4map.Lookup(hash)) + { + return pair->m_value; + } + + Offset4* o = (Offset4*)_aligned_malloc(sizeof(Offset4), 16); + + o->hash = hash; + + pixelAddress fpa = m_psm[fpsm].pa; + pixelAddress zpa = m_psm[zpsm].pa; + + int fs = m_psm[fpsm].bpp >> 5; + int zs = m_psm[zpsm].bpp >> 5; + + for(int i = 0; i < 2048; i++) + { + o->row[i].x = (int)fpa(0, i, fbp, bw) << fs; + o->row[i].y = (int)zpa(0, i, zbp, bw) << zs; + } + + for(int i = 0; i < 512; i++) + { + o->col[i].x = m_psm[fpsm].rowOffset[0][i * 4] << fs; + o->col[i].y = m_psm[zpsm].rowOffset[0][i * 4] << zs; + } + + m_o4map.SetAt(hash, o); + + return o; +} + +bool GSLocalMemory::FillRect(const GSVector4i& r, DWORD c, DWORD psm, DWORD bp, DWORD bw) +{ + const psm_t& tbl = m_psm[psm]; + + writePixel wp = tbl.wp; + pixelAddress ba = tbl.ba; + + int w = tbl.bs.cx; + int h = tbl.bs.cy; + int bpp = tbl.bpp; + + int shift = 0; + + switch(bpp) + { + case 32: shift = 0; break; + case 16: shift = 1; c = (c & 0xffff) * 0x00010001; break; + case 8: shift = 2; c = (c & 0xff) * 0x01010101; break; + case 4: shift = 3; c = (c & 0xf) * 0x11111111; break; + } + + CRect clip; + + clip.left = (r.x + (w - 1)) & ~(w - 1); + clip.top = (r.y + (h - 1)) & ~(h - 1); + clip.right = r.z & ~(w - 1); + clip.bottom = r.w & ~(h - 1); + + for(int y = r.y; y < clip.top; y++) + { + for(int x = r.x; x < r.z; x++) + { + (this->*wp)(x, y, c, bp, bw); + } + } + + for(int y = clip.bottom; y < r.w; y++) + { + for(int x = r.x; x < r.z; x++) + { + (this->*wp)(x, y, c, bp, bw); + } + } + + if(r.x < clip.left || clip.right < r.z) + { + for(int y = clip.top; y < clip.bottom; y += h) + { + for(int ys = y, ye = y + h; ys < ye; ys++) + { + for(int x = r.x; x < clip.left; x++) + { + (this->*wp)(x, ys, c, bp, bw); + } + + for(int x = clip.right; x < r.z; x++) + { + (this->*wp)(x, ys, c, bp, bw); + } + } + } + } + + if(psm == PSM_PSMCT24 || psm == PSM_PSMZ24) + { + #if _M_SSE >= 0x200 + + GSVector4i c128(c); + GSVector4i mask(0x00ffffff); + + for(int y = clip.top; y < clip.bottom; y += h) + { + for(int x = clip.left; x < clip.right; x += w) + { + GSVector4i* p = (GSVector4i*)&m_vm8[ba(x, y, bp, bw) << 2 >> shift]; + + for(int i = 0; i < 16; i += 4) + { + p[i + 0] = p[i + 0].blend8(c128, mask); + p[i + 1] = p[i + 1].blend8(c128, mask); + p[i + 2] = p[i + 2].blend8(c128, mask); + p[i + 3] = p[i + 3].blend8(c128, mask); + } + } + } + + #else + + c &= 0x00ffffff; + + for(int y = clip.top; y < clip.bottom; y += h) + { + for(int x = clip.left; x < clip.right; x += w) + { + DWORD* p = &m_vm32[ba(x, y, bp, bw)]; + + for(int i = 0; i < 64; i += 4) + { + p[i + 0] = (p[i + 0] & 0xff000000) | c; + p[i + 1] = (p[i + 1] & 0xff000000) | c; + p[i + 2] = (p[i + 2] & 0xff000000) | c; + p[i + 3] = (p[i + 3] & 0xff000000) | c; + } + } + } + + #endif + } + else + { + #if _M_SSE >= 0x200 + + GSVector4i c128(c); + + for(int y = clip.top; y < clip.bottom; y += h) + { + for(int x = clip.left; x < clip.right; x += w) + { + GSVector4i* p = (GSVector4i*)&m_vm8[ba(x, y, bp, bw) << 2 >> shift]; + + for(int i = 0; i < 16; i += 4) + { + p[i + 0] = c128; + p[i + 1] = c128; + p[i + 2] = c128; + p[i + 3] = c128; + } + } + } + + #else + + for(int y = clip.top; y < clip.bottom; y += h) + { + for(int x = clip.left; x < clip.right; x += w) + { + DWORD* p = (DWORD*)&m_vm8[ba(x, y, bp, bw) << 2 >> shift]; + + for(int i = 0; i < 64; i += 4) + { + p[i + 0] = c; + p[i + 1] = c; + p[i + 2] = c; + p[i + 3] = c; + } + } + } + + #endif + } + + return true; +} + +//////////////////// + +template +void GSLocalMemory::WriteImageColumn(int l, int r, int y, int h, BYTE* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF) +{ + DWORD bp = BITBLTBUF.DBP; + DWORD bw = BITBLTBUF.DBW; + + const int csy = bsy / 4; + + for(int offset = srcpitch * csy; h >= csy; h -= csy, y += csy, src += offset) + { + for(int x = l; x < r; x += bsx) + { + switch(psm) + { + case PSM_PSMCT32: WriteColumn32(y, (BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], &src[x * 4], srcpitch); break; + case PSM_PSMCT16: WriteColumn16(y, (BYTE*)&m_vm16[BlockAddress16(x, y, bp, bw)], &src[x * 2], srcpitch); break; + case PSM_PSMCT16S: WriteColumn16(y, (BYTE*)&m_vm16[BlockAddress16S(x, y, bp, bw)], &src[x * 2], srcpitch); break; + case PSM_PSMT8: WriteColumn8(y, (BYTE*)&m_vm8[BlockAddress8(x, y, bp, bw)], &src[x], srcpitch); break; + case PSM_PSMT4: WriteColumn4(y, (BYTE*)&m_vm8[BlockAddress4(x, y, bp, bw) >> 1], &src[x >> 1], srcpitch); break; + case PSM_PSMZ32: WriteColumn32(y, (BYTE*)&m_vm32[BlockAddress32Z(x, y, bp, bw)], &src[x * 4], srcpitch); break; + case PSM_PSMZ16: WriteColumn16(y, (BYTE*)&m_vm16[BlockAddress16Z(x, y, bp, bw)], &src[x * 2], srcpitch); break; + case PSM_PSMZ16S: WriteColumn16(y, (BYTE*)&m_vm16[BlockAddress16SZ(x, y, bp, bw)], &src[x * 2], srcpitch); break; + // TODO + default: __assume(0); + } + } + } +} + +template +void GSLocalMemory::WriteImageBlock(int l, int r, int y, int h, BYTE* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF) +{ + DWORD bp = BITBLTBUF.DBP; + DWORD bw = BITBLTBUF.DBW; + + for(int offset = srcpitch * bsy; h >= bsy; h -= bsy, y += bsy, src += offset) + { + for(int x = l; x < r; x += bsx) + { + switch(psm) + { + case PSM_PSMCT32: WriteBlock32((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], &src[x * 4], srcpitch); break; + case PSM_PSMCT16: WriteBlock16((BYTE*)&m_vm16[BlockAddress16(x, y, bp, bw)], &src[x * 2], srcpitch); break; + case PSM_PSMCT16S: WriteBlock16((BYTE*)&m_vm16[BlockAddress16S(x, y, bp, bw)], &src[x * 2], srcpitch); break; + case PSM_PSMT8: WriteBlock8((BYTE*)&m_vm8[BlockAddress8(x, y, bp, bw)], &src[x], srcpitch); break; + case PSM_PSMT4: WriteBlock4((BYTE*)&m_vm8[BlockAddress4(x, y, bp, bw) >> 1], &src[x >> 1], srcpitch); break; + case PSM_PSMZ32: WriteBlock32((BYTE*)&m_vm32[BlockAddress32Z(x, y, bp, bw)], &src[x * 4], srcpitch); break; + case PSM_PSMZ16: WriteBlock16((BYTE*)&m_vm16[BlockAddress16Z(x, y, bp, bw)], &src[x * 2], srcpitch); break; + case PSM_PSMZ16S: WriteBlock16((BYTE*)&m_vm16[BlockAddress16SZ(x, y, bp, bw)], &src[x * 2], srcpitch); break; + // TODO + default: __assume(0); + } + } + } +} + +template +void GSLocalMemory::WriteImageLeftRight(int l, int r, int y, int h, BYTE* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF) +{ + DWORD bp = BITBLTBUF.DBP; + DWORD bw = BITBLTBUF.DBW; + + for(; h > 0; y++, h--, src += srcpitch) + { + for(int x = l; x < r; x++) + { + switch(psm) + { + case PSM_PSMCT32: WritePixel32(x, y, *(DWORD*)&src[x * 4], bp, bw); break; + case PSM_PSMCT16: WritePixel16(x, y, *(WORD*)&src[x * 2], bp, bw); break; + case PSM_PSMCT16S: WritePixel16S(x, y, *(WORD*)&src[x * 2], bp, bw); break; + case PSM_PSMT8: WritePixel8(x, y, src[x], bp, bw); break; + case PSM_PSMT4: WritePixel4(x, y, src[x >> 1] >> ((x & 1) << 2), bp, bw); break; + case PSM_PSMZ32: WritePixel32Z(x, y, *(DWORD*)&src[x * 4], bp, bw); break; + case PSM_PSMZ16: WritePixel16Z(x, y, *(WORD*)&src[x * 2], bp, bw); break; + case PSM_PSMZ16S: WritePixel16SZ(x, y, *(WORD*)&src[x * 2], bp, bw); break; + // TODO + default: __assume(0); + } + } + } +} + +template +void GSLocalMemory::WriteImageTopBottom(int l, int r, int y, int h, BYTE* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF) +{ + __declspec(align(16)) BYTE buff[64]; // merge buffer for one column + + DWORD bp = BITBLTBUF.DBP; + DWORD bw = BITBLTBUF.DBW; + + const int csy = bsy / 4; + + // merge incomplete column + + int y2 = y & (csy - 1); + + if(y2 > 0) + { + int h2 = min(h, csy - y2); + + for(int x = l; x < r; x += bsx) + { + BYTE* dst = NULL; + + switch(psm) + { + case PSM_PSMCT32: dst = (BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)]; break; + case PSM_PSMCT16: dst = (BYTE*)&m_vm16[BlockAddress16(x, y, bp, bw)]; break; + case PSM_PSMCT16S: dst = (BYTE*)&m_vm16[BlockAddress16S(x, y, bp, bw)]; break; + case PSM_PSMT8: dst = (BYTE*)&m_vm8[BlockAddress8(x, y, bp, bw)]; break; + case PSM_PSMT4: dst = (BYTE*)&m_vm8[BlockAddress4(x, y, bp, bw) >> 1]; break; + case PSM_PSMZ32: dst = (BYTE*)&m_vm32[BlockAddress32Z(x, y, bp, bw)]; break; + case PSM_PSMZ16: dst = (BYTE*)&m_vm16[BlockAddress16Z(x, y, bp, bw)]; break; + case PSM_PSMZ16S: dst = (BYTE*)&m_vm16[BlockAddress16SZ(x, y, bp, bw)]; break; + // TODO + default: __assume(0); + } + + switch(psm) + { + case PSM_PSMCT32: + case PSM_PSMZ32: + ReadColumn32(y, dst, buff, 32); + memcpy(&buff[32], &src[x * 4], 32); + WriteColumn32(y, dst, buff, 32); + break; + case PSM_PSMCT16: + case PSM_PSMCT16S: + case PSM_PSMZ16: + case PSM_PSMZ16S: + ReadColumn16(y, dst, buff, 32); + memcpy(&buff[32], &src[x * 2], 32); + WriteColumn16(y, dst, buff, 32); + break; + case PSM_PSMT8: + ReadColumn8(y, dst, buff, 16); + memcpy(&buff[y2 * 16], &src[x], h2 * 16); + WriteColumn8(y, dst, buff, 16); + break; + case PSM_PSMT4: + ReadColumn4(y, dst, buff, 16); + memcpy(&buff[y2 * 16], &src[x >> 1], h2 * 16); + WriteColumn4(y, dst, buff, 16); + break; + // TODO + default: + __assume(0); + } + } + + src += srcpitch * h2; + y += h2; + h -= h2; + } + + // write whole columns + + { + int h2 = h & ~(csy - 1); + + if(h2 > 0) + { + if(((DWORD_PTR)&src[l * trbpp >> 3] & 15) == 0 && (srcpitch & 15) == 0) + { + WriteImageColumn(l, r, y, h2, src, srcpitch, BITBLTBUF); + } + else + { + WriteImageColumn(l, r, y, h2, src, srcpitch, BITBLTBUF); + } + + src += srcpitch * h2; + y += h2; + h -= h2; + } + } + + // merge incomplete column + + if(h >= 1) + { + for(int x = l; x < r; x += bsx) + { + BYTE* dst = NULL; + + switch(psm) + { + case PSM_PSMCT32: dst = (BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)]; break; + case PSM_PSMCT16: dst = (BYTE*)&m_vm16[BlockAddress16(x, y, bp, bw)]; break; + case PSM_PSMCT16S: dst = (BYTE*)&m_vm16[BlockAddress16S(x, y, bp, bw)]; break; + case PSM_PSMT8: dst = (BYTE*)&m_vm8[BlockAddress8(x, y, bp, bw)]; break; + case PSM_PSMT4: dst = (BYTE*)&m_vm8[BlockAddress4(x, y, bp, bw) >> 1]; break; + case PSM_PSMZ32: dst = (BYTE*)&m_vm32[BlockAddress32Z(x, y, bp, bw)]; break; + case PSM_PSMZ16: dst = (BYTE*)&m_vm16[BlockAddress16Z(x, y, bp, bw)]; break; + case PSM_PSMZ16S: dst = (BYTE*)&m_vm16[BlockAddress16SZ(x, y, bp, bw)]; break; + // TODO + default: __assume(0); + } + + switch(psm) + { + case PSM_PSMCT32: + case PSM_PSMZ32: + ReadColumn32(y, dst, buff, 32); + memcpy(&buff[0], &src[x * 4], 32); + WriteColumn32(y, dst, buff, 32); + break; + case PSM_PSMCT16: + case PSM_PSMCT16S: + case PSM_PSMZ16: + case PSM_PSMZ16S: + ReadColumn16(y, dst, buff, 32); + memcpy(&buff[0], &src[x * 2], 32); + WriteColumn16(y, dst, buff, 32); + break; + case PSM_PSMT8: + ReadColumn8(y, dst, buff, 16); + memcpy(&buff[0], &src[x], h * 16); + WriteColumn8(y, dst, buff, 16); + break; + case PSM_PSMT4: + ReadColumn4(y, dst, buff, 16); + memcpy(&buff[0], &src[x >> 1], h * 16); + WriteColumn4(y, dst, buff, 16); + break; + // TODO + default: + __assume(0); + } + } + } +} + +template +void GSLocalMemory::WriteImage(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) +{ + if(TRXREG.RRW == 0) return; + + int l = (int)TRXPOS.DSAX; + int r = (int)TRXREG.RRW; + + // finish the incomplete row first + + if(tx != l) + { + int n = min(len, (r - tx) * trbpp >> 3); + WriteImageX(tx, ty, src, n, BITBLTBUF, TRXPOS, TRXREG); + src += n; + len -= n; + } + + int la = (l + (bsx - 1)) & ~(bsx - 1); + int ra = r & ~(bsx - 1); + int srcpitch = (r - l) * trbpp >> 3; + int h = len / srcpitch; + + // transfer width >= block width, and there is at least one full row + + if(ra - la >= bsx && h > 0) + { + BYTE* s = &src[-l * trbpp >> 3]; + + src += srcpitch * h; + len -= srcpitch * h; + + // left part + + if(l < la) + { + WriteImageLeftRight(l, la, ty, h, s, srcpitch, BITBLTBUF); + } + + // right part + + if(ra < r) + { + WriteImageLeftRight(ra, r, ty, h, s, srcpitch, BITBLTBUF); + } + + // horizontally aligned part + + if(la < ra) + { + // top part + + { + int h2 = min(h, bsy - (ty & (bsy - 1))); + + if(h2 < bsy) + { + WriteImageTopBottom(la, ra, ty, h2, s, srcpitch, BITBLTBUF); + + s += srcpitch * h2; + ty += h2; + h -= h2; + } + } + + // horizontally and vertically aligned part + + { + int h2 = h & ~(bsy - 1); + + if(h2 > 0) + { + if(((DWORD_PTR)&s[la * trbpp >> 3] & 15) == 0 && (srcpitch & 15) == 0) + { + WriteImageBlock(la, ra, ty, h2, s, srcpitch, BITBLTBUF); + } + else + { + WriteImageBlock(la, ra, ty, h2, s, srcpitch, BITBLTBUF); + } + + s += srcpitch * h2; + ty += h2; + h -= h2; + } + } + + // bottom part + + if(h > 0) + { + WriteImageTopBottom(la, ra, ty, h, s, srcpitch, BITBLTBUF); + + // s += srcpitch * h; + ty += h; + // h -= h; + } + } + } + + // the rest + + if(len > 0) + { + WriteImageX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); + } +} + + +#define IsTopLeftAligned(dsax, tx, ty, bw, bh) \ + ((((int)dsax) & ((bw)-1)) == 0 && ((tx) & ((bw)-1)) == 0 && ((int)dsax) == (tx) && ((ty) & ((bh)-1)) == 0) + +void GSLocalMemory::WriteImage24(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) +{ + if(TRXREG.RRW == 0) return; + + DWORD bp = BITBLTBUF.DBP; + DWORD bw = BITBLTBUF.DBW; + + int tw = TRXREG.RRW, srcpitch = (TRXREG.RRW - TRXPOS.DSAX) * 3; + int th = len / srcpitch; + + bool aligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8); + + if(!aligned || (tw & 7) || (th & 7) || (len % srcpitch)) + { + // TODO + + WriteImageX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); + } + else + { + th += ty; + + for(int y = ty; y < th; y += 8, src += srcpitch * 8) + { + for(int x = tx; x < tw; x += 8) + { + UnpackAndWriteBlock24(src + (x - tx) * 3, srcpitch, (BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)]); + } + } + + ty = th; + } +} +void GSLocalMemory::WriteImage8H(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) +{ + if(TRXREG.RRW == 0) return; + + DWORD bp = BITBLTBUF.DBP; + DWORD bw = BITBLTBUF.DBW; + + int tw = TRXREG.RRW, srcpitch = TRXREG.RRW - TRXPOS.DSAX; + int th = len / srcpitch; + + bool aligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8); + + if(!aligned || (tw & 7) || (th & 7) || (len % srcpitch)) + { + // TODO + + WriteImageX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); + } + else + { + th += ty; + + for(int y = ty; y < th; y += 8, src += srcpitch * 8) + { + for(int x = tx; x < tw; x += 8) + { + UnpackAndWriteBlock8H(src + (x - tx), srcpitch, (BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)]); + } + } + + ty = th; + } +} + +void GSLocalMemory::WriteImage4HL(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) +{ + if(TRXREG.RRW == 0) return; + + DWORD bp = BITBLTBUF.DBP; + DWORD bw = BITBLTBUF.DBW; + + int tw = TRXREG.RRW, srcpitch = (TRXREG.RRW - TRXPOS.DSAX) / 2; + int th = len / srcpitch; + + bool aligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8); + + if(!aligned || (tw & 7) || (th & 7) || (len % srcpitch)) + { + // TODO + + WriteImageX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); + } + else + { + th += ty; + + for(int y = ty; y < th; y += 8, src += srcpitch * 8) + { + for(int x = tx; x < tw; x += 8) + { + UnpackAndWriteBlock4HL(src + (x - tx) / 2, srcpitch, (BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)]); + } + } + + ty = th; + } +} + +void GSLocalMemory::WriteImage4HH(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) +{ + if(TRXREG.RRW == 0) return; + + DWORD bp = BITBLTBUF.DBP; + DWORD bw = BITBLTBUF.DBW; + + int tw = TRXREG.RRW, srcpitch = (TRXREG.RRW - TRXPOS.DSAX) / 2; + int th = len / srcpitch; + + bool aligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8); + + if(!aligned || (tw & 7) || (th & 7) || (len % srcpitch)) + { + // TODO + + WriteImageX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); + } + else + { + th += ty; + + for(int y = ty; y < th; y += 8, src += srcpitch * 8) + { + for(int x = tx; x < tw; x += 8) + { + UnpackAndWriteBlock4HH(src + (x - tx) / 2, srcpitch, (BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)]); + } + } + + ty = th; + } +} +void GSLocalMemory::WriteImage24Z(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) +{ + if(TRXREG.RRW == 0) return; + + DWORD bp = BITBLTBUF.DBP; + DWORD bw = BITBLTBUF.DBW; + + int tw = TRXREG.RRW, srcpitch = (TRXREG.RRW - TRXPOS.DSAX) * 3; + int th = len / srcpitch; + + bool aligned = IsTopLeftAligned(TRXPOS.DSAX, tx, ty, 8, 8); + + if(!aligned || (tw & 7) || (th & 7) || (len % srcpitch)) + { + // TODO + + WriteImageX(tx, ty, src, len, BITBLTBUF, TRXPOS, TRXREG); + } + else + { + th += ty; + + for(int y = ty; y < th; y += 8, src += srcpitch * 8) + { + for(int x = tx; x < tw; x += 8) + { + UnpackAndWriteBlock24(src + (x - tx) * 3, srcpitch, (BYTE*)&m_vm32[BlockAddress32Z(x, y, bp, bw)]); + } + } + + ty = th; + } +} +void GSLocalMemory::WriteImageX(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) +{ + if(len <= 0) return; + + // if(ty >= (int)TRXREG.RRH) {ASSERT(0); return;} + + BYTE* pb = (BYTE*)src; + WORD* pw = (WORD*)src; + DWORD* pd = (DWORD*)src; + + DWORD bp = BITBLTBUF.DBP; + DWORD bw = BITBLTBUF.DBW; + psm_t* psm = &m_psm[BITBLTBUF.DPSM]; + + int x = tx; + int y = ty; + int sx = (int)TRXPOS.DSAX; + int ex = (int)TRXREG.RRW; + + switch(BITBLTBUF.DPSM) + { + case PSM_PSMCT32: + case PSM_PSMZ32: + + len /= 4; + + while(len > 0) + { + DWORD addr = psm->pa(0, y, bp, bw); + int* offset = psm->rowOffset[y & 7]; + + for(; len > 0 && x < ex; len--, x++, pd++) + { + WritePixel32(addr + offset[x], *pd); + } + + if(x == ex) {x = sx; y++;} + } + + break; + + case PSM_PSMCT24: + case PSM_PSMZ24: + + len /= 3; + + while(len > 0) + { + DWORD addr = psm->pa(0, y, bp, bw); + int* offset = psm->rowOffset[y & 7]; + + for(; len > 0 && x < ex; len--, x++, pb += 3) + { + WritePixel24(addr + offset[x], *(DWORD*)pb); + } + + if(x == ex) {x = sx; y++;} + } + + break; + + case PSM_PSMCT16: + case PSM_PSMCT16S: + case PSM_PSMZ16: + case PSM_PSMZ16S: + + len /= 2; + + while(len > 0) + { + DWORD addr = psm->pa(0, y, bp, bw); + int* offset = psm->rowOffset[y & 7]; + + for(; len > 0 && x < ex; len--, x++, pw++) + { + WritePixel16(addr + offset[x], *pw); + } + + if(x == ex) {x = sx; y++;} + } + + break; + + case PSM_PSMT8: + + while(len > 0) + { + DWORD addr = psm->pa(0, y, bp, bw); + int* offset = psm->rowOffset[y & 7]; + + for(; len > 0 && x < ex; len--, x++, pb++) + { + WritePixel8(addr + offset[x], *pb); + } + + if(x == ex) {x = sx; y++;} + } + + break; + + case PSM_PSMT4: + + while(len > 0) + { + DWORD addr = psm->pa(0, y, bp, bw); + int* offset = psm->rowOffset[y & 7]; + + for(; len > 0 && x < ex; len--, x += 2, pb++) + { + WritePixel4(addr + offset[x + 0], *pb & 0xf); + WritePixel4(addr + offset[x + 1], *pb >> 4); + } + + if(x == ex) {x = sx; y++;} + } + + break; + + case PSM_PSMT8H: + + while(len > 0) + { + DWORD addr = psm->pa(0, y, bp, bw); + int* offset = psm->rowOffset[y & 7]; + + for(; len > 0 && x < ex; len--, x++, pb++) + { + WritePixel8H(addr + offset[x], *pb); + } + + if(x == ex) {x = sx; y++;} + } + + break; + + case PSM_PSMT4HL: + + while(len > 0) + { + DWORD addr = psm->pa(0, y, bp, bw); + int* offset = psm->rowOffset[y & 7]; + + for(; len > 0 && x < ex; len--, x += 2, pb++) + { + WritePixel4HL(addr + offset[x + 0], *pb & 0xf); + WritePixel4HL(addr + offset[x + 1], *pb >> 4); + } + + if(x == ex) {x = sx; y++;} + } + + break; + + case PSM_PSMT4HH: + + while(len > 0) + { + DWORD addr = psm->pa(0, y, bp, bw); + int* offset = psm->rowOffset[y & 7]; + + for(; len > 0 && x < ex; len--, x += 2, pb++) + { + WritePixel4HH(addr + offset[x + 0], *pb & 0xf); + WritePixel4HH(addr + offset[x + 1], *pb >> 4); + } + + if(x == ex) {x = sx; y++;} + } + + break; + } + + tx = x; + ty = y; +} + +// + +void GSLocalMemory::ReadImageX(int& tx, int& ty, BYTE* dst, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) const +{ + if(len <= 0) return; + + // if(ty >= (int)TRXREG.RRH) {ASSERT(0); return;} + + BYTE* pb = (BYTE*)dst; + WORD* pw = (WORD*)dst; + DWORD* pd = (DWORD*)dst; + + DWORD bp = BITBLTBUF.SBP; + DWORD bw = BITBLTBUF.SBW; + psm_t* psm = &m_psm[BITBLTBUF.SPSM]; + + int x = tx; + int y = ty; + int sx = (int)TRXPOS.SSAX; + int ex = (int)TRXREG.RRW; + + switch(BITBLTBUF.SPSM) + { + case PSM_PSMCT32: + case PSM_PSMZ32: + + len /= 4; + + while(len > 0) + { + DWORD addr = psm->pa(0, y, bp, bw); + int* offset = psm->rowOffset[y & 7]; + + for(; len > 0 && x < ex; len--, x++, pd++) + { + *pd = ReadPixel32(addr + offset[x]); + } + + if(x == ex) {x = sx; y++;} + } + + break; + + case PSM_PSMCT24: + case PSM_PSMZ24: + + len /= 3; + + while(len > 0) + { + DWORD addr = psm->pa(0, y, bp, bw); + int* offset = psm->rowOffset[y & 7]; + + for(; len > 0 && x < ex; len--, x++, pb += 3) + { + DWORD dw = ReadPixel32(addr + offset[x]); + + pb[0] = ((BYTE*)&dw)[0]; + pb[1] = ((BYTE*)&dw)[1]; + pb[2] = ((BYTE*)&dw)[2]; + } + + if(x == ex) {x = sx; y++;} + } + + break; + + case PSM_PSMCT16: + case PSM_PSMCT16S: + case PSM_PSMZ16: + case PSM_PSMZ16S: + + len /= 2; + + while(len > 0) + { + DWORD addr = psm->pa(0, y, bp, bw); + int* offset = psm->rowOffset[y & 7]; + + for(; len > 0 && x < ex; len--, x++, pw++) + { + *pw = ReadPixel16(addr + offset[x]); + } + + if(x == ex) {x = sx; y++;} + } + + break; + + case PSM_PSMT8: + + while(len > 0) + { + DWORD addr = psm->pa(0, y, bp, bw); + int* offset = psm->rowOffset[y & 7]; + + for(; len > 0 && x < ex; len--, x++, pb++) + { + *pb = ReadPixel8(addr + offset[x]); + } + + if(x == ex) {x = sx; y++;} + } + + break; + + case PSM_PSMT4: + + while(len > 0) + { + DWORD addr = psm->pa(0, y, bp, bw); + int* offset = psm->rowOffset[y & 7]; + + for(; len > 0 && x < ex; len--, x += 2, pb++) + { + *pb = ReadPixel4(addr + offset[x + 0]) | (ReadPixel4(addr + offset[x + 1]) << 4); + } + + if(x == ex) {x = sx; y++;} + } + + break; + + case PSM_PSMT8H: + + while(len > 0) + { + DWORD addr = psm->pa(0, y, bp, bw); + int* offset = psm->rowOffset[y & 7]; + + for(; len > 0 && x < ex; len--, x++, pb++) + { + *pb = ReadPixel8H(addr + offset[x]); + } + + if(x == ex) {x = sx; y++;} + } + + break; + + case PSM_PSMT4HL: + + while(len > 0) + { + DWORD addr = psm->pa(0, y, bp, bw); + int* offset = psm->rowOffset[y & 7]; + + for(; len > 0 && x < ex; len--, x += 2, pb++) + { + *pb = ReadPixel4HL(addr + offset[x + 0]) | (ReadPixel4HL(addr + offset[x + 1]) << 4); + } + + if(x == ex) {x = sx; y++;} + } + + break; + + case PSM_PSMT4HH: + + while(len > 0) + { + DWORD addr = psm->pa(0, y, bp, bw); + int* offset = psm->rowOffset[y & 7]; + + for(; len > 0 && x < ex; len--, x += 2, pb++) + { + *pb = ReadPixel4HH(addr + offset[x + 0]) | (ReadPixel4HH(addr + offset[x + 1]) << 4); + } + + if(x == ex) {x = sx; y++;} + } + + break; + } + + tx = x; + ty = y; +} + +/////////////////// + +void GSLocalMemory::ReadTexture32(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + FOREACH_BLOCK_START(8, 8, 32) + { + ReadBlock32((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch); + } + FOREACH_BLOCK_END + +} + +void GSLocalMemory::ReadTexture24(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + if(TEXA.AEM) + { + FOREACH_BLOCK_START(8, 8, 32) + { + ReadAndExpandBlock24((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch, TEXA); + } + FOREACH_BLOCK_END + } + else + { + FOREACH_BLOCK_START(8, 8, 32) + { + ReadAndExpandBlock24((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch, TEXA); + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::ReadTexture16(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + __declspec(align(16)) WORD block[16 * 8]; + + FOREACH_BLOCK_START(16, 8, 32) + { + ReadBlock16((BYTE*)&m_vm16[BlockAddress16(x, y, bp, bw)], (BYTE*)block, sizeof(block) / 8); + + ExpandBlock16(block, dst, dstpitch, TEXA); + } + FOREACH_BLOCK_END +} + +void GSLocalMemory::ReadTexture16S(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + __declspec(align(16)) WORD block[16 * 8]; + + FOREACH_BLOCK_START(16, 8, 32) + { + ReadBlock16((BYTE*)&m_vm16[BlockAddress16S(x, y, bp, bw)], (BYTE*)block, sizeof(block) / 8); + + ExpandBlock16(block, dst, dstpitch, TEXA); + } + FOREACH_BLOCK_END +} + +void GSLocalMemory::ReadTexture8(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + const DWORD* pal = m_clut; + + FOREACH_BLOCK_START(16, 16, 32) + { + ReadAndExpandBlock8_32((BYTE*)&m_vm8[BlockAddress8(x, y, bp, bw)], dst, dstpitch, pal); + } + FOREACH_BLOCK_END +} + +void GSLocalMemory::ReadTexture4(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + const UINT64* pal = m_clut; + + FOREACH_BLOCK_START(32, 16, 32) + { + ReadAndExpandBlock4_32((BYTE*)&m_vm8[BlockAddress4(x, y, bp, bw) >> 1], dst, dstpitch, pal); + } + FOREACH_BLOCK_END +} + +void GSLocalMemory::ReadTexture8H(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + const DWORD* pal = m_clut; + + FOREACH_BLOCK_START(8, 8, 32) + { + ReadAndExpandBlock8H_32((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch, pal); + } + FOREACH_BLOCK_END +} + +void GSLocalMemory::ReadTexture4HL(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + const DWORD* pal = m_clut; + + FOREACH_BLOCK_START(8, 8, 32) + { + ReadAndExpandBlock4HL_32((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch, pal); + } + FOREACH_BLOCK_END +} + +void GSLocalMemory::ReadTexture4HH(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + const DWORD* pal = m_clut; + + FOREACH_BLOCK_START(8, 8, 32) + { + ReadAndExpandBlock4HH_32((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch, pal); + } + FOREACH_BLOCK_END +} + +void GSLocalMemory::ReadTexture32Z(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + FOREACH_BLOCK_START(8, 8, 32) + { + ReadBlock32((BYTE*)&m_vm32[BlockAddress32Z(x, y, bp, bw)], dst, dstpitch); + } + FOREACH_BLOCK_END +} + +void GSLocalMemory::ReadTexture24Z(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + if(TEXA.AEM) + { + FOREACH_BLOCK_START(8, 8, 32) + { + ReadAndExpandBlock24((BYTE*)&m_vm32[BlockAddress32Z(x, y, bp, bw)], dst, dstpitch, TEXA); + } + FOREACH_BLOCK_END + } + else + { + FOREACH_BLOCK_START(8, 8, 32) + { + ReadAndExpandBlock24((BYTE*)&m_vm32[BlockAddress32Z(x, y, bp, bw)], dst, dstpitch, TEXA); + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::ReadTexture16Z(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + __declspec(align(16)) WORD block[16 * 8]; + + FOREACH_BLOCK_START(16, 8, 32) + { + ReadBlock16((BYTE*)&m_vm16[BlockAddress16Z(x, y, bp, bw)], (BYTE*)block, sizeof(block) / 8); + + ExpandBlock16(block, dst, dstpitch, TEXA); + } + FOREACH_BLOCK_END +} + +void GSLocalMemory::ReadTexture16SZ(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + __declspec(align(16)) WORD block[16 * 8]; + + FOREACH_BLOCK_START(16, 8, 32) + { + ReadBlock16((BYTE*)&m_vm16[BlockAddress16SZ(x, y, bp, bw)], (BYTE*)block, sizeof(block) / 8); + + ExpandBlock16(block, dst, dstpitch, TEXA); + } + FOREACH_BLOCK_END +} + +/////////////////// + +void GSLocalMemory::ReadTexture(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP) +{ + readTexture rtx = m_psm[TEX0.PSM].rtx; + readTexel rt = m_psm[TEX0.PSM].rt; + CSize bs = m_psm[TEX0.PSM].bs; + + if(r.Width() < bs.cx || r.Height() < bs.cy + || (r.left & (bs.cx-1)) || (r.top & (bs.cy-1)) + || (r.right & (bs.cx-1)) || (r.bottom & (bs.cy-1)) + || (CLAMP.WMS == 3) || (CLAMP.WMT == 3)) + { + ReadTexture(r, dst, dstpitch, TEX0, TEXA, CLAMP, rt, rtx); + } + else + { + (this->*rtx)(r, dst, dstpitch, TEX0, TEXA); + } +} + +void GSLocalMemory::ReadTextureNC(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP) +{ + readTexture rtx = m_psm[TEX0.PSM].rtx; + readTexel rt = m_psm[TEX0.PSM].rt; + CSize bs = m_psm[TEX0.PSM].bs; + + if(r.Width() < bs.cx || r.Height() < bs.cy + || (r.left & (bs.cx-1)) || (r.top & (bs.cy-1)) + || (r.right & (bs.cx-1)) || (r.bottom & (bs.cy-1))) + { + ReadTextureNC(r, dst, dstpitch, TEX0, TEXA, rt, rtx); + } + else + { + (this->*rtx)(r, dst, dstpitch, TEX0, TEXA); + } +} +/////////////////// + +void GSLocalMemory::ReadTexture16NP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + FOREACH_BLOCK_START(16, 8, 16) + { + ReadBlock16((BYTE*)&m_vm16[BlockAddress16(x, y, bp, bw)], dst, dstpitch); + } + FOREACH_BLOCK_END +} + +void GSLocalMemory::ReadTexture16SNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + FOREACH_BLOCK_START(16, 8, 16) + { + ReadBlock16((BYTE*)&m_vm16[BlockAddress16S(x, y, bp, bw)], dst, dstpitch); + } + FOREACH_BLOCK_END +} + +void GSLocalMemory::ReadTexture8NP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + const DWORD* pal = m_clut; + + if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24) + { + FOREACH_BLOCK_START(16, 16, 32) + { + ReadAndExpandBlock8_32((BYTE*)&m_vm8[BlockAddress8(x, y, bp, bw)], dst, dstpitch, pal); + } + FOREACH_BLOCK_END + } + else + { + ASSERT(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S); + + __declspec(align(16)) BYTE block[16 * 16]; + + FOREACH_BLOCK_START(16, 16, 16) + { + ReadBlock8(&m_vm8[BlockAddress8(x, y, bp, bw)], (BYTE*)block, sizeof(block) / 16); + + ExpandBlock8_16(block, dst, dstpitch, pal); + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::ReadTexture4NP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + const UINT64* pal = m_clut; + + if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24) + { + FOREACH_BLOCK_START(32, 16, 32) + { + ReadAndExpandBlock4_32(&m_vm8[BlockAddress4(x, y, bp, bw) >> 1], dst, dstpitch, pal); + } + FOREACH_BLOCK_END + } + else + { + ASSERT(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S); + + __declspec(align(16)) BYTE block[(32 / 2) * 16]; + + FOREACH_BLOCK_START(32, 16, 16) + { + ReadBlock4(&m_vm8[BlockAddress4(x, y, bp, bw)>>1], (BYTE*)block, sizeof(block) / 16); + + ExpandBlock4_16(block, dst, dstpitch, pal); + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::ReadTexture8HNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + const DWORD* pal = m_clut; + + if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24) + { + FOREACH_BLOCK_START(8, 8, 32) + { + ReadAndExpandBlock8H_32((const BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch, pal); + } + FOREACH_BLOCK_END + } + else + { + ASSERT(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S); + + __declspec(align(16)) DWORD block[8 * 8]; + + FOREACH_BLOCK_START(8, 8, 16) + { + ReadBlock32((const BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], (BYTE*)block, sizeof(block) / 8); + + ExpandBlock8H_16(block, dst, dstpitch, pal); + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::ReadTexture4HLNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + const DWORD* pal = m_clut; + + if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24) + { + FOREACH_BLOCK_START(8, 8, 32) + { + ReadAndExpandBlock4HL_32((const BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch, pal); + } + FOREACH_BLOCK_END + } + else + { + ASSERT(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S); + + __declspec(align(16)) DWORD block[8 * 8]; + + FOREACH_BLOCK_START(8, 8, 16) + { + ReadBlock32((const BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], (BYTE*)block, sizeof(block) / 8); + + ExpandBlock4HL_16(block, dst, dstpitch, pal); + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::ReadTexture4HHNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + const DWORD* pal = m_clut; + + if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24) + { + FOREACH_BLOCK_START(8, 8, 32) + { + ReadAndExpandBlock4HH_32((const BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch, pal); + } + FOREACH_BLOCK_END + } + else + { + ASSERT(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S); + + __declspec(align(16)) DWORD block[8 * 8]; + + FOREACH_BLOCK_START(8, 8, 16) + { + ReadBlock32((const BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], (BYTE*)block, sizeof(block) / 8); + + ExpandBlock4HH_16(block, dst, dstpitch, pal); + } + FOREACH_BLOCK_END + } +} + +void GSLocalMemory::ReadTexture16ZNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + FOREACH_BLOCK_START(16, 8, 16) + { + ReadBlock16((const BYTE*)&m_vm16[BlockAddress16Z(x, y, bp, bw)], dst, dstpitch); + } + FOREACH_BLOCK_END +} + +void GSLocalMemory::ReadTexture16SZNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + FOREACH_BLOCK_START(16, 8, 16) + { + ReadBlock16((const BYTE*)&m_vm16[BlockAddress16SZ(x, y, bp, bw)], dst, dstpitch); + } + FOREACH_BLOCK_END +} + +/////////////////// + +void GSLocalMemory::ReadTextureNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP) +{ + readTexture rtx = m_psm[TEX0.PSM].rtxNP; + readTexel rt = m_psm[TEX0.PSM].rtNP; + CSize bs = m_psm[TEX0.PSM].bs; + + if(r.Width() < bs.cx || r.Height() < bs.cy + || (r.left & (bs.cx-1)) || (r.top & (bs.cy-1)) + || (r.right & (bs.cx-1)) || (r.bottom & (bs.cy-1)) + || (CLAMP.WMS == 3) || (CLAMP.WMT == 3)) + { + DWORD psm = TEX0.PSM; + + switch(psm) + { + case PSM_PSMT8: + case PSM_PSMT8H: + case PSM_PSMT4: + case PSM_PSMT4HL: + case PSM_PSMT4HH: + psm = TEX0.CPSM; + break; + } + + switch(psm) + { + default: + case PSM_PSMCT32: + case PSM_PSMCT24: + ReadTexture(r, dst, dstpitch, TEX0, TEXA, CLAMP, rt, rtx); + break; + case PSM_PSMCT16: + case PSM_PSMCT16S: + ReadTexture(r, dst, dstpitch, TEX0, TEXA, CLAMP, rt, rtx); + break; + } + } + else + { + (this->*rtx)(r, dst, dstpitch, TEX0, TEXA); + } +} + +void GSLocalMemory::ReadTextureNPNC(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP) +{ + readTexture rtx = m_psm[TEX0.PSM].rtxNP; + readTexel rt = m_psm[TEX0.PSM].rtNP; + CSize bs = m_psm[TEX0.PSM].bs; + + if(r.Width() < bs.cx || r.Height() < bs.cy + || (r.left & (bs.cx-1)) || (r.top & (bs.cy-1)) + || (r.right & (bs.cx-1)) || (r.bottom & (bs.cy-1))) + { + DWORD psm = TEX0.PSM; + + switch(psm) + { + case PSM_PSMT8: + case PSM_PSMT8H: + case PSM_PSMT4: + case PSM_PSMT4HL: + case PSM_PSMT4HH: + psm = TEX0.CPSM; + break; + } + + switch(psm) + { + default: + case PSM_PSMCT32: + case PSM_PSMCT24: + ReadTextureNC(r, dst, dstpitch, TEX0, TEXA, rt, rtx); + break; + case PSM_PSMCT16: + case PSM_PSMCT16S: + ReadTextureNC(r, dst, dstpitch, TEX0, TEXA, rt, rtx); + break; + } + } + else + { + (this->*rtx)(r, dst, dstpitch, TEX0, TEXA); + } +} + +// 32/8 + +void GSLocalMemory::ReadTexture8P(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + FOREACH_BLOCK_START(16, 16, 8) + { + ReadBlock8(&m_vm8[BlockAddress8(x, y, bp, bw)], dst, dstpitch); + } + FOREACH_BLOCK_END +} + +void GSLocalMemory::ReadTexture4P(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + FOREACH_BLOCK_START(32, 16, 8) + { + ReadBlock4P(&m_vm8[BlockAddress4(x, y, bp, bw) >> 1], dst, dstpitch); + } + FOREACH_BLOCK_END +} + +void GSLocalMemory::ReadTexture8HP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + FOREACH_BLOCK_START(8, 8, 8) + { + ReadBlock8HP((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch); + } + FOREACH_BLOCK_END +} + +void GSLocalMemory::ReadTexture4HLP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + FOREACH_BLOCK_START(8, 8, 8) + { + ReadBlock4HLP((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch); + } + FOREACH_BLOCK_END +} + +void GSLocalMemory::ReadTexture4HHP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const +{ + FOREACH_BLOCK_START(8, 8, 8) + { + ReadBlock4HHP((BYTE*)&m_vm32[BlockAddress32(x, y, bp, bw)], dst, dstpitch); + } + FOREACH_BLOCK_END +} + +// + +template +void GSLocalMemory::ReadTexture(CRect r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, readTexel rt, readTexture rtx) +{ + // TODO: this is a mess, make it more simple + + DWORD wms = CLAMP.WMS, wmt = CLAMP.WMT; + DWORD minu = CLAMP.MINU, maxu = CLAMP.MAXU; + DWORD minv = CLAMP.MINV, maxv = CLAMP.MAXV; + + CSize bs = m_psm[TEX0.PSM].bs; + + int bsxm = bs.cx - 1; + int bsym = bs.cy - 1; + + if(wms == 3 || wmt == 3) + { + if(wms == 3 && wmt == 3) + { + int w = minu + 1; + int h = minv + 1; + + w = (w + bsxm) & ~bsxm; + h = (h + bsym) & ~bsym; + + if(w % bs.cx == 0 && maxu % bs.cx == 0 && h % bs.cy == 0 && maxv % bs.cy == 0) + { +// printf("!!! 1 wms = %d, wmt = %d, %3x %3x %3x %3x, %d %d - %d %d\n", wms, wmt, minu, maxu, minv, maxv, r.left, r.top, r.right, r.bottom); + + T* buff = (T*)_aligned_malloc(w * h * sizeof(T), 16); + + (this->*rtx)(CRect(CPoint(maxu, maxv), CSize(w, h)), (BYTE*)buff, w * sizeof(T), TEX0, TEXA); + + dst -= r.left * sizeof(T); + +// int left = (r.left + minu) & ~minu; +// int right = r.right & ~minu; + + for(int y = r.top; y < r.bottom; y++, dst += dstpitch) + { + T* src = &buff[(y & minv) * w]; + + int x = r.left; +/* + for(; x < left; x++) + { + ((T*)dst)[x] = src[x & minu]; + } + + for(; x < right; x += minu + 1) + { + memcpy(&((T*)dst)[x], src, sizeof(T) * (minu + 1)); + } +*/ + for(; x < r.right; x++) + { + ((T*)dst)[x] = src[x & minu]; + } + } + + _aligned_free(buff); + + return; + } + } + + if(wms == 2) + { + int left = r.left; + r.left = min(r.right, max(r.left, (int)minu)); + r.right = max(r.left, min(r.right, (int)maxu + 1)); + dst += (r.left - left) * sizeof(T); + } + + if(wmt == 2) + { + int top = r.top; + r.top = min(r.bottom, max(r.top, (int)minv)); + r.bottom = max(r.top, min(r.bottom, (int)maxv + 1)); + dst += (r.top - top) * dstpitch; + } + + if(wms == 3 && wmt != 3) + { + int w = ((minu + 1) + bsxm) & ~bsxm; + + if(w % bs.cx == 0 && maxu % bs.cx == 0) + { +// printf("!!! 2 wms = %d, wmt = %d, %3x %3x %3x %3x, %d %d - %d %d\n", wms, wmt, minu, maxu, minv, maxv, r.left, r.top, r.right, r.bottom); + int top = r.top & ~bsym; + int bottom = (r.bottom + bsym) & ~bsym; + + int h = bottom - top; + + T* buff = (T*)_aligned_malloc(w * h * sizeof(T), 16); + + (this->*rtx)(CRect(CPoint(maxu, top), CSize(w, h)), (BYTE*)buff, w * sizeof(T), TEX0, TEXA); + + dst -= r.left * sizeof(T); + +// int left = (r.left + minu) & ~minu; +// int right = r.right & ~minu; + + for(int y = r.top; y < r.bottom; y++, dst += dstpitch) + { + T* src = &buff[(y - top) * w]; + + int x = r.left; +/* + for(; x < left; x++) + { + ((T*)dst)[x] = src[x & minu]; + } + + for(; x < right; x += minu + 1) + { + memcpy(&((T*)dst)[x], src, sizeof(T) * (minu + 1)); + } +*/ + for(; x < r.right; x++) + { + ((T*)dst)[x] = src[x & minu]; + } + } + + _aligned_free(buff); + + return; + } + } + + if(wms != 3 && wmt == 3) + { + int h = (minv + 1 + bsym) & ~bsym; + + if(h % bs.cy == 0 && maxv % bs.cy == 0) + { +// printf("!!! 3 wms = %d, wmt = %d, %3x %3x %3x %3x, %d %d - %d %d\n", wms, wmt, minu, maxu, minv, maxv, r.left, r.top, r.right, r.bottom); + int left = r.left & ~bsxm; + int right = (r.right + bsxm) & ~bsxm; + + int w = right - left; + + T* buff = (T*)_aligned_malloc(w * h * sizeof(T), 16); + + (this->*rtx)(CRect(CPoint(left, maxv), CSize(w, h)), (BYTE*)buff, w * sizeof(T), TEX0, TEXA); + + for(int y = r.top; y < r.bottom; y++, dst += dstpitch) + { + T* src = &buff[(y & minv) * w + (r.left - left)]; + + memcpy(dst, src, sizeof(T) * r.Width()); + } + + _aligned_free(buff); + + return; + } + } + + switch(wms) + { + default: for(int x = r.left; x < r.right; x++) m_xtbl[x] = x; break; + case 3: for(int x = r.left; x < r.right; x++) m_xtbl[x] = (x & minu) | maxu; break; + } + + switch(wmt) + { + default: for(int y = r.top; y < r.bottom; y++) m_ytbl[y] = y; break; + case 3: for(int y = r.top; y < r.bottom; y++) m_ytbl[y] = (y & minv) | maxv; break; + } + +// printf("!!! 4 wms = %d, wmt = %d, %3x %3x %3x %3x, %d %d - %d %d\n", wms, wmt, minu, maxu, minv, maxv, r.left, r.top, r.right, r.bottom); + + for(int y = r.top; y < r.bottom; y++, dst += dstpitch) + for(int x = r.left, i = 0; x < r.right; x++, i++) + ((T*)dst)[i] = (T)(this->*rt)(m_xtbl[x], m_ytbl[y], TEX0, TEXA); + } + else + { + // find a block-aligned rect that fits between r and the region clamped area (if any) + + CRect r1 = r; + CRect r2 = r; + + r1.left = (r1.left + bsxm) & ~bsxm; + r1.top = (r1.top + bsym) & ~bsym; + r1.right = r1.right & ~bsxm; + r1.bottom = r1.bottom & ~bsym; + + if(wms == 2 && minu < maxu) + { + r2.left = minu & ~bsxm; + r2.right = (maxu + bsxm) & ~bsxm; + } + + if(wmt == 2 && minv < maxv) + { + r2.top = minv & ~bsym; + r2.bottom = (maxv + bsym) & ~bsym; + } + + CRect cr = r1 & r2; + + bool aligned = ((DWORD_PTR)(dst + (cr.left - r.left) * sizeof(T)) & 0xf) == 0; + + if(cr.left >= cr.right && cr.top >= cr.bottom || !aligned) + { + // TODO: expand r to block size, read into temp buffer, copy to r (like above) + +if(!aligned) printf("unaligned memory pointer passed to ReadTexture\n"); + +// printf("!!! 5 wms = %d, wmt = %d, %3x %3x %3x %3x, %d %d - %d %d\n", wms, wmt, minu, maxu, minv, maxv, r.left, r.top, r.right, r.bottom); + + for(int y = r.top; y < r.bottom; y++, dst += dstpitch) + for(int x = r.left, i = 0; x < r.right; x++, i++) + ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); + } + else + { +// printf("!!! 6 wms = %d, wmt = %d, %3x %3x %3x %3x, %d %d - %d %d\n", wms, wmt, minu, maxu, minv, maxv, r.left, r.top, r.right, r.bottom); + + for(int y = r.top; y < cr.top; y++, dst += dstpitch) + for(int x = r.left, i = 0; x < r.right; x++, i++) + ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); + + if(!cr.IsRectEmpty()) + { + (this->*rtx)(cr, dst + (cr.left - r.left) * sizeof(T), dstpitch, TEX0, TEXA); + } + + for(int y = cr.top; y < cr.bottom; y++, dst += dstpitch) + { + for(int x = r.left, i = 0; x < cr.left; x++, i++) + ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); + for(int x = cr.right, i = x - r.left; x < r.right; x++, i++) + ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); + } + + for(int y = cr.bottom; y < r.bottom; y++, dst += dstpitch) + for(int x = r.left, i = 0; x < r.right; x++, i++) + ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); + } + } +} + +template +void GSLocalMemory::ReadTextureNC(CRect r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, readTexel rt, readTexture rtx) +{ + CSize bs = m_psm[TEX0.PSM].bs; + + int bsxm = bs.cx - 1; + int bsym = bs.cy - 1; + + CRect cr; + + cr.left = (r.left + bsxm) & ~bsxm; + cr.top = (r.top + bsym) & ~bsym; + cr.right = r.right & ~bsxm; + cr.bottom = r.bottom & ~bsym; + + bool aligned = ((DWORD_PTR)(dst + (cr.left - r.left) * sizeof(T)) & 0xf) == 0; + + if(cr.left >= cr.right && cr.top >= cr.bottom || !aligned) + { + // TODO: expand r to block size, read into temp buffer, copy to r (like above) + +if(!aligned) printf("unaligned memory pointer passed to ReadTexture\n"); + + for(int y = r.top; y < r.bottom; y++, dst += dstpitch) + for(int x = r.left, i = 0; x < r.right; x++, i++) + ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); + } + else + { + for(int y = r.top; y < cr.top; y++, dst += dstpitch) + for(int x = r.left, i = 0; x < r.right; x++, i++) + ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); + + if(!cr.IsRectEmpty()) + (this->*rtx)(cr, dst + (cr.left - r.left) * sizeof(T), dstpitch, TEX0, TEXA); + + for(int y = cr.top; y < cr.bottom; y++, dst += dstpitch) + { + for(int x = r.left, i = 0; x < cr.left; x++, i++) + ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); + for(int x = cr.right, i = x - r.left; x < r.right; x++, i++) + ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); + } + + for(int y = cr.bottom; y < r.bottom; y++, dst += dstpitch) + for(int x = r.left, i = 0; x < r.right; x++, i++) + ((T*)dst)[i] = (T)(this->*rt)(x, y, TEX0, TEXA); + } +} + +HRESULT GSLocalMemory::SaveBMP(LPCTSTR fn, DWORD bp, DWORD bw, DWORD psm, int w, int h) +{ + int pitch = w * 4; + int size = pitch * h; + void* bits = ::_aligned_malloc(size, 16); + + GIFRegTEX0 TEX0; + + TEX0.TBP0 = bp; + TEX0.TBW = bw; + TEX0.PSM = psm; + + GIFRegTEXA TEXA; + + TEXA.AEM = 0; + TEXA.TA0 = 0; + TEXA.TA1 = 0x80; + + // (this->*m_psm[TEX0.PSM].rtx)(CRect(0, 0, w, h), bits, pitch, TEX0, TEXA); + + readPixel rp = m_psm[psm].rp; + + BYTE* p = (BYTE*)bits; + + for(int j = h-1; j >= 0; j--, p += pitch) + for(int i = 0; i < w; i++) + ((DWORD*)p)[i] = (this->*rp)(i, j, TEX0.TBP0, TEX0.TBW); + + if(FILE* fp = _tfopen(fn, _T("wb"))) + { + BITMAPINFOHEADER bih; + memset(&bih, 0, sizeof(bih)); + bih.biSize = sizeof(bih); + bih.biWidth = w; + bih.biHeight = h; + bih.biPlanes = 1; + bih.biBitCount = 32; + bih.biCompression = BI_RGB; + bih.biSizeImage = size; + + BITMAPFILEHEADER bfh; + memset(&bfh, 0, sizeof(bfh)); + bfh.bfType = 'MB'; + bfh.bfOffBits = sizeof(bfh) + sizeof(bih); + bfh.bfSize = bfh.bfOffBits + size; + bfh.bfReserved1 = bfh.bfReserved2 = 0; + + fwrite(&bfh, 1, sizeof(bfh), fp); + fwrite(&bih, 1, sizeof(bih), fp); + fwrite(bits, 1, size, fp); + + fclose(fp); + } + + ::_aligned_free(bits); + + return true; +} diff --git a/plugins/GSdx/GSLocalMemory.h b/plugins/GSdx/GSLocalMemory.h index 6d273dcbc1..bcc18e5a6f 100644 --- a/plugins/GSdx/GSLocalMemory.h +++ b/plugins/GSdx/GSLocalMemory.h @@ -1,1009 +1,1009 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#pragma warning(disable: 4100) // warning C4100: 'TEXA' : unreferenced formal parameter - -#include "GS.h" -#include "GSTables.h" -#include "GSVector.h" -#include "GSBlock.h" -#include "GSClut.h" - -class GSLocalMemory : public GSBlock -{ -public: - typedef DWORD (*pixelAddress)(int x, int y, DWORD bp, DWORD bw); - typedef void (GSLocalMemory::*writePixel)(int x, int y, DWORD c, DWORD bp, DWORD bw); - typedef void (GSLocalMemory::*writeFrame)(int x, int y, DWORD c, DWORD bp, DWORD bw); - typedef DWORD (GSLocalMemory::*readPixel)(int x, int y, DWORD bp, DWORD bw) const; - typedef DWORD (GSLocalMemory::*readTexel)(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - typedef void (GSLocalMemory::*writePixelAddr)(DWORD addr, DWORD c); - typedef void (GSLocalMemory::*writeFrameAddr)(DWORD addr, DWORD c); - typedef DWORD (GSLocalMemory::*readPixelAddr)(DWORD addr) const; - typedef DWORD (GSLocalMemory::*readTexelAddr)(DWORD addr, const GIFRegTEXA& TEXA) const; - typedef void (GSLocalMemory::*writeImage)(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); - typedef void (GSLocalMemory::*readImage)(int& tx, int& ty, BYTE* dst, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) const; - typedef void (GSLocalMemory::*readTexture)(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - - typedef union - { - struct - { - pixelAddress pa, ba, pga, pgn; - readPixel rp; - readPixelAddr rpa; - writePixel wp; - writePixelAddr wpa; - readTexel rt, rtNP; - readTexelAddr rta; - writeFrameAddr wfa; - writeImage wi; - readImage ri; - readTexture rtx, rtxNP, rtxP; - DWORD bpp, pal, trbpp; - CSize bs, pgs; - int* rowOffset[8]; - }; - BYTE dummy[128]; - } psm_t; - - static psm_t m_psm[64]; - - static const int m_vmsize = 1024 * 1024 * 4; - - union {BYTE* m_vm8; WORD* m_vm16; DWORD* m_vm32;}; - - GSClut m_clut; - - struct Offset - { - GSVector4i row[2048]; // 0 | 0 | 0 | 0 - int* col[4]; // x | x+1 | x+2 | x+3 - DWORD hash; - }; - - struct Offset4 - { - // 16 bit offsets (m_vm16[...]) - - GSVector2i row[2048]; // f yn | z yn (n = 0 1 2 ...) - GSVector2i col[512]; // f xn | z xn (n = 0 4 8 ...) - DWORD hash; - }; - -protected: - static DWORD pageOffset32[32][32][64]; - static DWORD pageOffset32Z[32][32][64]; - static DWORD pageOffset16[32][64][64]; - static DWORD pageOffset16S[32][64][64]; - static DWORD pageOffset16Z[32][64][64]; - static DWORD pageOffset16SZ[32][64][64]; - static DWORD pageOffset8[32][64][128]; - static DWORD pageOffset4[32][128][128]; - - static int rowOffset32[2048]; - static int rowOffset32Z[2048]; - static int rowOffset16[2048]; - static int rowOffset16S[2048]; - static int rowOffset16Z[2048]; - static int rowOffset16SZ[2048]; - static int rowOffset8[2][2048]; - static int rowOffset4[2][2048]; - - __forceinline static DWORD Expand24To32(DWORD c, const GIFRegTEXA& TEXA) - { - return (((!TEXA.AEM | (c & 0xffffff)) ? TEXA.TA0 : 0) << 24) | (c & 0xffffff); - } - - __forceinline static DWORD Expand16To32(WORD c, const GIFRegTEXA& TEXA) - { - return (((c & 0x8000) ? TEXA.TA1 : (!TEXA.AEM | c) ? TEXA.TA0 : 0) << 24) | ((c & 0x7c00) << 9) | ((c & 0x03e0) << 6) | ((c & 0x001f) << 3); - } - - // TODO - - friend class GSClut; - - // - - CRBMapC m_omap; - CRBMapC m_o4map; - -public: - GSLocalMemory(); - virtual ~GSLocalMemory(); - - Offset* GetOffset(DWORD bp, DWORD bw, DWORD psm); - Offset4* GetOffset4(const GIFRegFRAME& FRAME, const GIFRegZBUF& ZBUF); - - // address - - static DWORD PageNumber32(int x, int y, DWORD bp, DWORD bw) - { - return (bp >> 5) + (y >> 5) * bw + (x >> 6); - } - - static DWORD PageNumber16(int x, int y, DWORD bp, DWORD bw) - { - return (bp >> 5) + (y >> 6) * bw + (x >> 6); - } - - static DWORD PageNumber8(int x, int y, DWORD bp, DWORD bw) - { - ASSERT((bw & 1) == 0); - - return (bp >> 5) + (y >> 6) * (bw >> 1) + (x >> 7); - } - - static DWORD PageNumber4(int x, int y, DWORD bp, DWORD bw) - { - ASSERT((bw & 1) == 0); - - return (bp >> 5) + (y >> 7) * (bw >> 1) + (x >> 7); - } - - static DWORD PageAddress32(int x, int y, DWORD bp, DWORD bw) - { - return PageNumber32(x, y, bp, bw) << 11; - } - - static DWORD PageAddress16(int x, int y, DWORD bp, DWORD bw) - { - return PageNumber16(x, y, bp, bw) << 12; - } - - static DWORD PageAddress8(int x, int y, DWORD bp, DWORD bw) - { - return PageNumber8(x, y, bp, bw) << 13; - } - - static DWORD PageAddress4(int x, int y, DWORD bp, DWORD bw) - { - return PageNumber4(x, y, bp, bw) << 14; - } - - static DWORD BlockAddress32(int x, int y, DWORD bp, DWORD bw) - { - DWORD page = bp + (y & ~0x1f) * bw + ((x >> 1) & ~0x1f); - DWORD block = blockTable32[(y >> 3) & 3][(x >> 3) & 7]; - return (page + block) << 6; - } - - static DWORD BlockAddress16(int x, int y, DWORD bp, DWORD bw) - { - DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); - DWORD block = blockTable16[(y >> 3) & 7][(x >> 4) & 3]; - return (page + block) << 7; - } - - static DWORD BlockAddress16S(int x, int y, DWORD bp, DWORD bw) - { - DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); - DWORD block = blockTable16S[(y >> 3) & 7][(x >> 4) & 3]; - return (page + block) << 7; - } - - static DWORD BlockAddress8(int x, int y, DWORD bp, DWORD bw) - { - ASSERT((bw & 1) == 0); - DWORD page = bp + ((y >> 1) & ~0x1f) * (bw >> 1) + ((x >> 2) & ~0x1f); - DWORD block = blockTable8[(y >> 4) & 3][(x >> 4) & 7]; - return (page + block) << 8; - } - - static DWORD BlockAddress4(int x, int y, DWORD bp, DWORD bw) - { - ASSERT((bw & 1) == 0); - DWORD page = bp + ((y >> 2) & ~0x1f) * (bw >> 1) + ((x >> 2) & ~0x1f); - DWORD block = blockTable4[(y >> 4) & 7][(x >> 5) & 3]; - return (page + block) << 9; - } - - static DWORD BlockAddress32Z(int x, int y, DWORD bp, DWORD bw) - { - DWORD page = bp + (y & ~0x1f) * bw + ((x >> 1) & ~0x1f); - DWORD block = blockTable32Z[(y >> 3) & 3][(x >> 3) & 7]; - return (page + block) << 6; - } - - static DWORD BlockAddress16Z(int x, int y, DWORD bp, DWORD bw) - { - DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); - DWORD block = blockTable16Z[(y >> 3) & 7][(x >> 4) & 3]; - return (page + block) << 7; - } - - static DWORD BlockAddress16SZ(int x, int y, DWORD bp, DWORD bw) - { - DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); - DWORD block = blockTable16SZ[(y >> 3) & 7][(x >> 4) & 3]; - return (page + block) << 7; - } - - static DWORD PixelAddressOrg32(int x, int y, DWORD bp, DWORD bw) - { - DWORD page = bp + (y & ~0x1f) * bw + ((x >> 1) & ~0x1f); - DWORD block = blockTable32[(y >> 3) & 3][(x >> 3) & 7]; - DWORD word = ((page + block) << 6) + columnTable32[y & 7][x & 7]; - ASSERT(word < 1024*1024); - return word; - } - - static DWORD PixelAddressOrg16(int x, int y, DWORD bp, DWORD bw) - { - DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); - DWORD block = blockTable16[(y >> 3) & 7][(x >> 4) & 3]; - DWORD word = ((page + block) << 7) + columnTable16[y & 7][x & 15]; - ASSERT(word < 1024*1024*2); - return word; - } - - static DWORD PixelAddressOrg16S(int x, int y, DWORD bp, DWORD bw) - { - DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); - DWORD block = blockTable16S[(y >> 3) & 7][(x >> 4) & 3]; - DWORD word = ((page + block) << 7) + columnTable16[y & 7][x & 15]; - ASSERT(word < 1024*1024*2); - return word; - } - - static DWORD PixelAddressOrg8(int x, int y, DWORD bp, DWORD bw) - { - ASSERT((bw & 1) == 0); - DWORD page = bp + ((y >> 1) & ~0x1f) * (bw >> 1) + ((x >> 2) & ~0x1f); - DWORD block = blockTable8[(y >> 4) & 3][(x >> 4) & 7]; - DWORD word = ((page + block) << 8) + columnTable8[y & 15][x & 15]; - ASSERT(word < 1024*1024*4); - return word; - } - - static DWORD PixelAddressOrg4(int x, int y, DWORD bp, DWORD bw) - { - ASSERT((bw & 1) == 0); - DWORD page = bp + ((y >> 2) & ~0x1f) * (bw >> 1) + ((x >> 2) & ~0x1f); - DWORD block = blockTable4[(y >> 4) & 7][(x >> 5) & 3]; - DWORD word = ((page + block) << 9) + columnTable4[y & 15][x & 31]; - ASSERT(word < 1024*1024*8); - return word; - } - - static DWORD PixelAddressOrg32Z(int x, int y, DWORD bp, DWORD bw) - { - DWORD page = bp + (y & ~0x1f) * bw + ((x >> 1) & ~0x1f); - DWORD block = blockTable32Z[(y >> 3) & 3][(x >> 3) & 7]; - DWORD word = ((page + block) << 6) + columnTable32[y & 7][x & 7]; - ASSERT(word < 1024*1024); - return word; - } - - static DWORD PixelAddressOrg16Z(int x, int y, DWORD bp, DWORD bw) - { - DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); - DWORD block = blockTable16Z[(y >> 3) & 7][(x >> 4) & 3]; - DWORD word = ((page + block) << 7) + columnTable16[y & 7][x & 15]; - ASSERT(word < 1024*1024*2); - return word; - } - - static DWORD PixelAddressOrg16SZ(int x, int y, DWORD bp, DWORD bw) - { - DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); - DWORD block = blockTable16SZ[(y >> 3) & 7][(x >> 4) & 3]; - DWORD word = ((page + block) << 7) + columnTable16[y & 7][x & 15]; - ASSERT(word < 1024*1024*2); - return word; - } - - static __forceinline DWORD PixelAddress32(int x, int y, DWORD bp, DWORD bw) - { - DWORD page = (bp >> 5) + (y >> 5) * bw + (x >> 6); - DWORD word = (page << 11) + pageOffset32[bp & 0x1f][y & 0x1f][x & 0x3f]; - return word; - } - - static __forceinline DWORD PixelAddress16(int x, int y, DWORD bp, DWORD bw) - { - DWORD page = (bp >> 5) + (y >> 6) * bw + (x >> 6); - DWORD word = (page << 12) + pageOffset16[bp & 0x1f][y & 0x3f][x & 0x3f]; - return word; - } - - static __forceinline DWORD PixelAddress16S(int x, int y, DWORD bp, DWORD bw) - { - DWORD page = (bp >> 5) + (y >> 6) * bw + (x >> 6); - DWORD word = (page << 12) + pageOffset16S[bp & 0x1f][y & 0x3f][x & 0x3f]; - return word; - } - - static __forceinline DWORD PixelAddress8(int x, int y, DWORD bp, DWORD bw) - { - ASSERT((bw & 1) == 0); - DWORD page = (bp >> 5) + (y >> 6) * (bw >> 1) + (x >> 7); - DWORD word = (page << 13) + pageOffset8[bp & 0x1f][y & 0x3f][x & 0x7f]; - return word; - } - - static __forceinline DWORD PixelAddress4(int x, int y, DWORD bp, DWORD bw) - { - ASSERT((bw & 1) == 0); - DWORD page = (bp >> 5) + (y >> 7) * (bw >> 1) + (x >> 7); - DWORD word = (page << 14) + pageOffset4[bp & 0x1f][y & 0x7f][x & 0x7f]; - return word; - } - - static __forceinline DWORD PixelAddress32Z(int x, int y, DWORD bp, DWORD bw) - { - DWORD page = (bp >> 5) + (y >> 5) * bw + (x >> 6); - DWORD word = (page << 11) + pageOffset32Z[bp & 0x1f][y & 0x1f][x & 0x3f]; - return word; - } - - static __forceinline DWORD PixelAddress16Z(int x, int y, DWORD bp, DWORD bw) - { - DWORD page = (bp >> 5) + (y >> 6) * bw + (x >> 6); - DWORD word = (page << 12) + pageOffset16Z[bp & 0x1f][y & 0x3f][x & 0x3f]; - return word; - } - - static __forceinline DWORD PixelAddress16SZ(int x, int y, DWORD bp, DWORD bw) - { - DWORD page = (bp >> 5) + (y >> 6) * bw + (x >> 6); - DWORD word = (page << 12) + pageOffset16SZ[bp & 0x1f][y & 0x3f][x & 0x3f]; - return word; - } - - // pixel R/W - - __forceinline DWORD ReadPixel32(DWORD addr) const - { - return m_vm32[addr]; - } - - __forceinline DWORD ReadPixel24(DWORD addr) const - { - return m_vm32[addr] & 0x00ffffff; - } - - __forceinline DWORD ReadPixel16(DWORD addr) const - { - return (DWORD)m_vm16[addr]; - } - - __forceinline DWORD ReadPixel8(DWORD addr) const - { - return (DWORD)m_vm8[addr]; - } - - __forceinline DWORD ReadPixel4(DWORD addr) const - { - return (m_vm8[addr >> 1] >> ((addr & 1) << 2)) & 0x0f; - } - - __forceinline DWORD ReadPixel8H(DWORD addr) const - { - return m_vm32[addr] >> 24; - } - - __forceinline DWORD ReadPixel4HL(DWORD addr) const - { - return (m_vm32[addr] >> 24) & 0x0f; - } - - __forceinline DWORD ReadPixel4HH(DWORD addr) const - { - return (m_vm32[addr] >> 28) & 0x0f; - } - - __forceinline DWORD ReadFrame24(DWORD addr) const - { - return 0x80000000 | (m_vm32[addr] & 0xffffff); - } - - __forceinline DWORD ReadFrame16(DWORD addr) const - { - DWORD c = (DWORD)m_vm16[addr]; - - return ((c & 0x8000) << 16) | ((c & 0x7c00) << 9) | ((c & 0x03e0) << 6) | ((c & 0x001f) << 3); - } - - __forceinline DWORD ReadPixel32(int x, int y, DWORD bp, DWORD bw) const - { - return ReadPixel32(PixelAddress32(x, y, bp, bw)); - } - - __forceinline DWORD ReadPixel24(int x, int y, DWORD bp, DWORD bw) const - { - return ReadPixel24(PixelAddress32(x, y, bp, bw)); - } - - __forceinline DWORD ReadPixel16(int x, int y, DWORD bp, DWORD bw) const - { - return ReadPixel16(PixelAddress16(x, y, bp, bw)); - } - - __forceinline DWORD ReadPixel16S(int x, int y, DWORD bp, DWORD bw) const - { - return ReadPixel16(PixelAddress16S(x, y, bp, bw)); - } - - __forceinline DWORD ReadPixel8(int x, int y, DWORD bp, DWORD bw) const - { - return ReadPixel8(PixelAddress8(x, y, bp, bw)); - } - - __forceinline DWORD ReadPixel4(int x, int y, DWORD bp, DWORD bw) const - { - return ReadPixel4(PixelAddress4(x, y, bp, bw)); - } - - __forceinline DWORD ReadPixel8H(int x, int y, DWORD bp, DWORD bw) const - { - return ReadPixel8H(PixelAddress32(x, y, bp, bw)); - } - - __forceinline DWORD ReadPixel4HL(int x, int y, DWORD bp, DWORD bw) const - { - return ReadPixel4HL(PixelAddress32(x, y, bp, bw)); - } - - __forceinline DWORD ReadPixel4HH(int x, int y, DWORD bp, DWORD bw) const - { - return ReadPixel4HH(PixelAddress32(x, y, bp, bw)); - } - - __forceinline DWORD ReadPixel32Z(int x, int y, DWORD bp, DWORD bw) const - { - return ReadPixel32(PixelAddress32Z(x, y, bp, bw)); - } - - __forceinline DWORD ReadPixel24Z(int x, int y, DWORD bp, DWORD bw) const - { - return ReadPixel24(PixelAddress32Z(x, y, bp, bw)); - } - - __forceinline DWORD ReadPixel16Z(int x, int y, DWORD bp, DWORD bw) const - { - return ReadPixel16(PixelAddress16Z(x, y, bp, bw)); - } - - __forceinline DWORD ReadPixel16SZ(int x, int y, DWORD bp, DWORD bw) const - { - return ReadPixel16(PixelAddress16SZ(x, y, bp, bw)); - } - - __forceinline DWORD ReadFrame24(int x, int y, DWORD bp, DWORD bw) const - { - return ReadFrame24(PixelAddress32(x, y, bp, bw)); - } - - __forceinline DWORD ReadFrame16(int x, int y, DWORD bp, DWORD bw) const - { - return ReadFrame16(PixelAddress16(x, y, bp, bw)); - } - - __forceinline DWORD ReadFrame16S(int x, int y, DWORD bp, DWORD bw) const - { - return ReadFrame16(PixelAddress16S(x, y, bp, bw)); - } - - __forceinline DWORD ReadFrame24Z(int x, int y, DWORD bp, DWORD bw) const - { - return ReadFrame24(PixelAddress32Z(x, y, bp, bw)); - } - - __forceinline DWORD ReadFrame16Z(int x, int y, DWORD bp, DWORD bw) const - { - return ReadFrame16(PixelAddress16Z(x, y, bp, bw)); - } - - __forceinline DWORD ReadFrame16SZ(int x, int y, DWORD bp, DWORD bw) const - { - return ReadFrame16(PixelAddress16SZ(x, y, bp, bw)); - } - - __forceinline void WritePixel32(DWORD addr, DWORD c) - { - m_vm32[addr] = c; - } - - __forceinline void WritePixel24(DWORD addr, DWORD c) - { - m_vm32[addr] = (m_vm32[addr] & 0xff000000) | (c & 0x00ffffff); - } - - __forceinline void WritePixel16(DWORD addr, DWORD c) - { - m_vm16[addr] = (WORD)c; - } - - __forceinline void WritePixel8(DWORD addr, DWORD c) - { - m_vm8[addr] = (BYTE)c; - } - - __forceinline void WritePixel4(DWORD addr, DWORD c) - { - int shift = (addr & 1) << 2; addr >>= 1; - - m_vm8[addr] = (BYTE)((m_vm8[addr] & (0xf0 >> shift)) | ((c & 0x0f) << shift)); - } - - __forceinline void WritePixel8H(DWORD addr, DWORD c) - { - m_vm32[addr] = (m_vm32[addr] & 0x00ffffff) | (c << 24); - } - - __forceinline void WritePixel4HL(DWORD addr, DWORD c) - { - m_vm32[addr] = (m_vm32[addr] & 0xf0ffffff) | ((c & 0x0f) << 24); - } - - __forceinline void WritePixel4HH(DWORD addr, DWORD c) - { - m_vm32[addr] = (m_vm32[addr] & 0x0fffffff) | ((c & 0x0f) << 28); - } - - __forceinline void WriteFrame16(DWORD addr, DWORD c) - { - DWORD rb = c & 0x00f800f8; - DWORD ga = c & 0x8000f800; - - WritePixel16(addr, (ga >> 16) | (rb >> 9) | (ga >> 6) | (rb >> 3)); - } - - __forceinline void WritePixel32(int x, int y, DWORD c, DWORD bp, DWORD bw) - { - WritePixel32(PixelAddress32(x, y, bp, bw), c); - } - - __forceinline void WritePixel24(int x, int y, DWORD c, DWORD bp, DWORD bw) - { - WritePixel24(PixelAddress32(x, y, bp, bw), c); - } - - __forceinline void WritePixel16(int x, int y, DWORD c, DWORD bp, DWORD bw) - { - WritePixel16(PixelAddress16(x, y, bp, bw), c); - } - - __forceinline void WritePixel16S(int x, int y, DWORD c, DWORD bp, DWORD bw) - { - WritePixel16(PixelAddress16S(x, y, bp, bw), c); - } - - __forceinline void WritePixel8(int x, int y, DWORD c, DWORD bp, DWORD bw) - { - WritePixel8(PixelAddress8(x, y, bp, bw), c); - } - - __forceinline void WritePixel4(int x, int y, DWORD c, DWORD bp, DWORD bw) - { - WritePixel4(PixelAddress4(x, y, bp, bw), c); - } - - __forceinline void WritePixel8H(int x, int y, DWORD c, DWORD bp, DWORD bw) - { - WritePixel8H(PixelAddress32(x, y, bp, bw), c); - } - - __forceinline void WritePixel4HL(int x, int y, DWORD c, DWORD bp, DWORD bw) - { - WritePixel4HL(PixelAddress32(x, y, bp, bw), c); - } - - __forceinline void WritePixel4HH(int x, int y, DWORD c, DWORD bp, DWORD bw) - { - WritePixel4HH(PixelAddress32(x, y, bp, bw), c); - } - - __forceinline void WritePixel32Z(int x, int y, DWORD c, DWORD bp, DWORD bw) - { - WritePixel32(PixelAddress32Z(x, y, bp, bw), c); - } - - __forceinline void WritePixel24Z(int x, int y, DWORD c, DWORD bp, DWORD bw) - { - WritePixel24(PixelAddress32Z(x, y, bp, bw), c); - } - - __forceinline void WritePixel16Z(int x, int y, DWORD c, DWORD bp, DWORD bw) - { - WritePixel16(PixelAddress16Z(x, y, bp, bw), c); - } - - __forceinline void WritePixel16SZ(int x, int y, DWORD c, DWORD bp, DWORD bw) - { - WritePixel16(PixelAddress16SZ(x, y, bp, bw), c); - } - - __forceinline void WriteFrame16(int x, int y, DWORD c, DWORD bp, DWORD bw) - { - WriteFrame16(PixelAddress16(x, y, bp, bw), c); - } - - __forceinline void WriteFrame16S(int x, int y, DWORD c, DWORD bp, DWORD bw) - { - WriteFrame16(PixelAddress16S(x, y, bp, bw), c); - } - - __forceinline void WriteFrame16Z(int x, int y, DWORD c, DWORD bp, DWORD bw) - { - WriteFrame16(PixelAddress16Z(x, y, bp, bw), c); - } - - __forceinline void WriteFrame16SZ(int x, int y, DWORD c, DWORD bp, DWORD bw) - { - WriteFrame16(PixelAddress16SZ(x, y, bp, bw), c); - } - - __forceinline DWORD ReadTexel32(DWORD addr, const GIFRegTEXA& TEXA) const - { - return m_vm32[addr]; - } - - __forceinline DWORD ReadTexel24(DWORD addr, const GIFRegTEXA& TEXA) const - { - return Expand24To32(m_vm32[addr], TEXA); - } - - __forceinline DWORD ReadTexel16(DWORD addr, const GIFRegTEXA& TEXA) const - { - return Expand16To32(m_vm16[addr], TEXA); - } - - __forceinline DWORD ReadTexel8(DWORD addr, const GIFRegTEXA& TEXA) const - { - return m_clut[ReadPixel8(addr)]; - } - - __forceinline DWORD ReadTexel4(DWORD addr, const GIFRegTEXA& TEXA) const - { - return m_clut[ReadPixel4(addr)]; - } - - __forceinline DWORD ReadTexel8H(DWORD addr, const GIFRegTEXA& TEXA) const - { - return m_clut[ReadPixel8H(addr)]; - } - - __forceinline DWORD ReadTexel4HL(DWORD addr, const GIFRegTEXA& TEXA) const - { - return m_clut[ReadPixel4HL(addr)]; - } - - __forceinline DWORD ReadTexel4HH(DWORD addr, const GIFRegTEXA& TEXA) const - { - return m_clut[ReadPixel4HH(addr)]; - } - - __forceinline DWORD ReadTexel32(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const - { - return ReadTexel32(PixelAddress32(x, y, TEX0.TBP0, TEX0.TBW), TEXA); - } - - __forceinline DWORD ReadTexel24(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const - { - return ReadTexel24(PixelAddress32(x, y, TEX0.TBP0, TEX0.TBW), TEXA); - } - - __forceinline DWORD ReadTexel16(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const - { - return ReadTexel16(PixelAddress16(x, y, TEX0.TBP0, TEX0.TBW), TEXA); - } - - __forceinline DWORD ReadTexel16S(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const - { - return ReadTexel16(PixelAddress16S(x, y, TEX0.TBP0, TEX0.TBW), TEXA); - } - - __forceinline DWORD ReadTexel8(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const - { - return ReadTexel8(PixelAddress8(x, y, TEX0.TBP0, TEX0.TBW), TEXA); - } - - __forceinline DWORD ReadTexel4(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const - { - return ReadTexel4(PixelAddress4(x, y, TEX0.TBP0, TEX0.TBW), TEXA); - } - - __forceinline DWORD ReadTexel8H(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const - { - return ReadTexel8H(PixelAddress32(x, y, TEX0.TBP0, TEX0.TBW), TEXA); - } - - __forceinline DWORD ReadTexel4HL(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const - { - return ReadTexel4HL(PixelAddress32(x, y, TEX0.TBP0, TEX0.TBW), TEXA); - } - - __forceinline DWORD ReadTexel4HH(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const - { - return ReadTexel4HH(PixelAddress32(x, y, TEX0.TBP0, TEX0.TBW), TEXA); - } - - __forceinline DWORD ReadTexel32Z(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const - { - return ReadTexel32(PixelAddress32Z(x, y, TEX0.TBP0, TEX0.TBW), TEXA); - } - - __forceinline DWORD ReadTexel24Z(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const - { - return ReadTexel24(PixelAddress32Z(x, y, TEX0.TBP0, TEX0.TBW), TEXA); - } - - __forceinline DWORD ReadTexel16Z(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const - { - return ReadTexel16(PixelAddress16Z(x, y, TEX0.TBP0, TEX0.TBW), TEXA); - } - - __forceinline DWORD ReadTexel16SZ(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const - { - return ReadTexel16(PixelAddress16SZ(x, y, TEX0.TBP0, TEX0.TBW), TEXA); - } - - __forceinline DWORD ReadTexel16NP(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const - { - return ReadPixel16(x, y, TEX0.TBP0, TEX0.TBW); - } - - __forceinline DWORD ReadTexel16SNP(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const - { - return ReadPixel16S(x, y, TEX0.TBP0, TEX0.TBW); - } - - __forceinline DWORD ReadTexel16ZNP(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const - { - return ReadPixel16Z(x, y, TEX0.TBP0, TEX0.TBW); - } - - __forceinline DWORD ReadTexel16SZNP(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const - { - return ReadPixel16SZ(x, y, TEX0.TBP0, TEX0.TBW); - } - - // - - __forceinline DWORD PixelAddressX(int PSM, int x, int y, DWORD bp, DWORD bw) - { - switch(PSM) - { - case PSM_PSMCT32: return PixelAddress32(x, y, bp, bw); - case PSM_PSMCT24: return PixelAddress32(x, y, bp, bw); - case PSM_PSMCT16: return PixelAddress16(x, y, bp, bw); - case PSM_PSMCT16S: return PixelAddress16S(x, y, bp, bw); - case PSM_PSMT8: return PixelAddress8(x, y, bp, bw); - case PSM_PSMT4: return PixelAddress4(x, y, bp, bw); - case PSM_PSMT8H: return PixelAddress32(x, y, bp, bw); - case PSM_PSMT4HL: return PixelAddress32(x, y, bp, bw); - case PSM_PSMT4HH: return PixelAddress32(x, y, bp, bw); - case PSM_PSMZ32: return PixelAddress32Z(x, y, bp, bw); - case PSM_PSMZ24: return PixelAddress32Z(x, y, bp, bw); - case PSM_PSMZ16: return PixelAddress16Z(x, y, bp, bw); - case PSM_PSMZ16S: return PixelAddress16SZ(x, y, bp, bw); - default: ASSERT(0); return PixelAddress32(x, y, bp, bw); - } - } - - __forceinline DWORD ReadPixelX(int PSM, DWORD addr) const - { - switch(PSM) - { - case PSM_PSMCT32: return ReadPixel32(addr); - case PSM_PSMCT24: return ReadPixel24(addr); - case PSM_PSMCT16: return ReadPixel16(addr); - case PSM_PSMCT16S: return ReadPixel16(addr); - case PSM_PSMT8: return ReadPixel8(addr); - case PSM_PSMT4: return ReadPixel4(addr); - case PSM_PSMT8H: return ReadPixel8H(addr); - case PSM_PSMT4HL: return ReadPixel4HL(addr); - case PSM_PSMT4HH: return ReadPixel4HH(addr); - case PSM_PSMZ32: return ReadPixel32(addr); - case PSM_PSMZ24: return ReadPixel24(addr); - case PSM_PSMZ16: return ReadPixel16(addr); - case PSM_PSMZ16S: return ReadPixel16(addr); - default: ASSERT(0); return ReadPixel32(addr); - } - } - - __forceinline DWORD ReadFrameX(int PSM, DWORD addr) const - { - switch(PSM) - { - case PSM_PSMCT32: return ReadPixel32(addr); - case PSM_PSMCT24: return ReadFrame24(addr); - case PSM_PSMCT16: return ReadFrame16(addr); - case PSM_PSMCT16S: return ReadFrame16(addr); - case PSM_PSMZ32: return ReadPixel32(addr); - case PSM_PSMZ24: return ReadFrame24(addr); - case PSM_PSMZ16: return ReadFrame16(addr); - case PSM_PSMZ16S: return ReadFrame16(addr); - default: ASSERT(0); return ReadPixel32(addr); - } - } - - __forceinline DWORD ReadTexelX(int PSM, DWORD addr, const GIFRegTEXA& TEXA) const - { - switch(PSM) - { - case PSM_PSMCT32: return ReadTexel32(addr, TEXA); - case PSM_PSMCT24: return ReadTexel24(addr, TEXA); - case PSM_PSMCT16: return ReadTexel16(addr, TEXA); - case PSM_PSMCT16S: return ReadTexel16(addr, TEXA); - case PSM_PSMT8: return ReadTexel8(addr, TEXA); - case PSM_PSMT4: return ReadTexel4(addr, TEXA); - case PSM_PSMT8H: return ReadTexel8H(addr, TEXA); - case PSM_PSMT4HL: return ReadTexel4HL(addr, TEXA); - case PSM_PSMT4HH: return ReadTexel4HH(addr, TEXA); - case PSM_PSMZ32: return ReadTexel32(addr, TEXA); - case PSM_PSMZ24: return ReadTexel24(addr, TEXA); - case PSM_PSMZ16: return ReadTexel16(addr, TEXA); - case PSM_PSMZ16S: return ReadTexel16(addr, TEXA); - default: ASSERT(0); return ReadTexel32(addr, TEXA); - } - } - - __forceinline DWORD ReadTexelX(int PSM, int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const - { - switch(PSM) - { - case PSM_PSMCT32: return ReadTexel32(x, y, TEX0, TEXA); - case PSM_PSMCT24: return ReadTexel24(x, y, TEX0, TEXA); - case PSM_PSMCT16: return ReadTexel16(x, y, TEX0, TEXA); - case PSM_PSMCT16S: return ReadTexel16(x, y, TEX0, TEXA); - case PSM_PSMT8: return ReadTexel8(x, y, TEX0, TEXA); - case PSM_PSMT4: return ReadTexel4(x, y, TEX0, TEXA); - case PSM_PSMT8H: return ReadTexel8H(x, y, TEX0, TEXA); - case PSM_PSMT4HL: return ReadTexel4HL(x, y, TEX0, TEXA); - case PSM_PSMT4HH: return ReadTexel4HH(x, y, TEX0, TEXA); - case PSM_PSMZ32: return ReadTexel32Z(x, y, TEX0, TEXA); - case PSM_PSMZ24: return ReadTexel24Z(x, y, TEX0, TEXA); - case PSM_PSMZ16: return ReadTexel16Z(x, y, TEX0, TEXA); - case PSM_PSMZ16S: return ReadTexel16Z(x, y, TEX0, TEXA); - default: ASSERT(0); return ReadTexel32(x, y, TEX0, TEXA); - } - } - - __forceinline void WritePixelX(int PSM, DWORD addr, DWORD c) - { - switch(PSM) - { - case PSM_PSMCT32: WritePixel32(addr, c); break; - case PSM_PSMCT24: WritePixel24(addr, c); break; - case PSM_PSMCT16: WritePixel16(addr, c); break; - case PSM_PSMCT16S: WritePixel16(addr, c); break; - case PSM_PSMT8: WritePixel8(addr, c); break; - case PSM_PSMT4: WritePixel4(addr, c); break; - case PSM_PSMT8H: WritePixel8H(addr, c); break; - case PSM_PSMT4HL: WritePixel4HL(addr, c); break; - case PSM_PSMT4HH: WritePixel4HH(addr, c); break; - case PSM_PSMZ32: WritePixel32(addr, c); break; - case PSM_PSMZ24: WritePixel24(addr, c); break; - case PSM_PSMZ16: WritePixel16(addr, c); break; - case PSM_PSMZ16S: WritePixel16(addr, c); break; - default: ASSERT(0); WritePixel32(addr, c); break; - } - } - - __forceinline void WriteFrameX(int PSM, DWORD addr, DWORD c) - { - switch(PSM) - { - case PSM_PSMCT32: WritePixel32(addr, c); break; - case PSM_PSMCT24: WritePixel24(addr, c); break; - case PSM_PSMCT16: WriteFrame16(addr, c); break; - case PSM_PSMCT16S: WriteFrame16(addr, c); break; - case PSM_PSMZ32: WritePixel32(addr, c); break; - case PSM_PSMZ24: WritePixel24(addr, c); break; - case PSM_PSMZ16: WriteFrame16(addr, c); break; - case PSM_PSMZ16S: WriteFrame16(addr, c); break; - default: ASSERT(0); WritePixel32(addr, c); break; - } - } - - // FillRect - - bool FillRect(const GSVector4i& r, DWORD c, DWORD psm, DWORD bp, DWORD bw); - - // - - template - void WriteImageColumn(int l, int r, int y, int h, BYTE* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF); - - template - void WriteImageBlock(int l, int r, int y, int h, BYTE* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF); - - template - void WriteImageLeftRight(int l, int r, int y, int h, BYTE* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF); - - template - void WriteImageTopBottom(int l, int r, int y, int h, BYTE* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF); - - template - void WriteImage(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); - - void WriteImage24(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); - void WriteImage8H(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); - void WriteImage4HL(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); - void WriteImage4HH(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); - void WriteImage24Z(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); - void WriteImageX(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); - - // TODO: ReadImage32/24/... - - void ReadImageX(int& tx, int& ty, BYTE* dst, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) const; - - // - - void ReadTexture32(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture24(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture16(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture16S(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture8(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture4(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture8H(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture4HL(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture4HH(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture32Z(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture24Z(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture16Z(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture16SZ(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - - void ReadTexture(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP); - void ReadTextureNC(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP); - - // 32/16 - - void ReadTexture16NP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture16SNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture8NP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture4NP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture8HNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture4HLNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture4HHNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture16ZNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture16SZNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - - void ReadTextureNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP); - void ReadTextureNPNC(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP); - - // 32/8 - - void ReadTexture8P(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture4P(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture8HP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture4HLP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - void ReadTexture4HHP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; - - // - - static DWORD m_xtbl[1024], m_ytbl[1024]; - - template void ReadTexture(CRect r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, readTexel rt, readTexture rtx); - template void ReadTextureNC(CRect r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, readTexel rt, readTexture rtx); - - // - - HRESULT SaveBMP(LPCTSTR fn, DWORD bp, DWORD bw, DWORD psm, int w, int h); -}; - +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#pragma warning(disable: 4100) // warning C4100: 'TEXA' : unreferenced formal parameter + +#include "GS.h" +#include "GSTables.h" +#include "GSVector.h" +#include "GSBlock.h" +#include "GSClut.h" + +class GSLocalMemory : public GSBlock +{ +public: + typedef DWORD (*pixelAddress)(int x, int y, DWORD bp, DWORD bw); + typedef void (GSLocalMemory::*writePixel)(int x, int y, DWORD c, DWORD bp, DWORD bw); + typedef void (GSLocalMemory::*writeFrame)(int x, int y, DWORD c, DWORD bp, DWORD bw); + typedef DWORD (GSLocalMemory::*readPixel)(int x, int y, DWORD bp, DWORD bw) const; + typedef DWORD (GSLocalMemory::*readTexel)(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + typedef void (GSLocalMemory::*writePixelAddr)(DWORD addr, DWORD c); + typedef void (GSLocalMemory::*writeFrameAddr)(DWORD addr, DWORD c); + typedef DWORD (GSLocalMemory::*readPixelAddr)(DWORD addr) const; + typedef DWORD (GSLocalMemory::*readTexelAddr)(DWORD addr, const GIFRegTEXA& TEXA) const; + typedef void (GSLocalMemory::*writeImage)(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); + typedef void (GSLocalMemory::*readImage)(int& tx, int& ty, BYTE* dst, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) const; + typedef void (GSLocalMemory::*readTexture)(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + + typedef union + { + struct + { + pixelAddress pa, ba, pga, pgn; + readPixel rp; + readPixelAddr rpa; + writePixel wp; + writePixelAddr wpa; + readTexel rt, rtNP; + readTexelAddr rta; + writeFrameAddr wfa; + writeImage wi; + readImage ri; + readTexture rtx, rtxNP, rtxP; + DWORD bpp, pal, trbpp; + CSize bs, pgs; + int* rowOffset[8]; + }; + BYTE dummy[128]; + } psm_t; + + static psm_t m_psm[64]; + + static const int m_vmsize = 1024 * 1024 * 4; + + union {BYTE* m_vm8; WORD* m_vm16; DWORD* m_vm32;}; + + GSClut m_clut; + + struct Offset + { + GSVector4i row[2048]; // 0 | 0 | 0 | 0 + int* col[4]; // x | x+1 | x+2 | x+3 + DWORD hash; + }; + + struct Offset4 + { + // 16 bit offsets (m_vm16[...]) + + GSVector2i row[2048]; // f yn | z yn (n = 0 1 2 ...) + GSVector2i col[512]; // f xn | z xn (n = 0 4 8 ...) + DWORD hash; + }; + +protected: + static DWORD pageOffset32[32][32][64]; + static DWORD pageOffset32Z[32][32][64]; + static DWORD pageOffset16[32][64][64]; + static DWORD pageOffset16S[32][64][64]; + static DWORD pageOffset16Z[32][64][64]; + static DWORD pageOffset16SZ[32][64][64]; + static DWORD pageOffset8[32][64][128]; + static DWORD pageOffset4[32][128][128]; + + static int rowOffset32[2048]; + static int rowOffset32Z[2048]; + static int rowOffset16[2048]; + static int rowOffset16S[2048]; + static int rowOffset16Z[2048]; + static int rowOffset16SZ[2048]; + static int rowOffset8[2][2048]; + static int rowOffset4[2][2048]; + + __forceinline static DWORD Expand24To32(DWORD c, const GIFRegTEXA& TEXA) + { + return (((!TEXA.AEM | (c & 0xffffff)) ? TEXA.TA0 : 0) << 24) | (c & 0xffffff); + } + + __forceinline static DWORD Expand16To32(WORD c, const GIFRegTEXA& TEXA) + { + return (((c & 0x8000) ? TEXA.TA1 : (!TEXA.AEM | c) ? TEXA.TA0 : 0) << 24) | ((c & 0x7c00) << 9) | ((c & 0x03e0) << 6) | ((c & 0x001f) << 3); + } + + // TODO + + friend class GSClut; + + // + + CRBMapC m_omap; + CRBMapC m_o4map; + +public: + GSLocalMemory(); + virtual ~GSLocalMemory(); + + Offset* GetOffset(DWORD bp, DWORD bw, DWORD psm); + Offset4* GetOffset4(const GIFRegFRAME& FRAME, const GIFRegZBUF& ZBUF); + + // address + + static DWORD PageNumber32(int x, int y, DWORD bp, DWORD bw) + { + return (bp >> 5) + (y >> 5) * bw + (x >> 6); + } + + static DWORD PageNumber16(int x, int y, DWORD bp, DWORD bw) + { + return (bp >> 5) + (y >> 6) * bw + (x >> 6); + } + + static DWORD PageNumber8(int x, int y, DWORD bp, DWORD bw) + { + ASSERT((bw & 1) == 0); + + return (bp >> 5) + (y >> 6) * (bw >> 1) + (x >> 7); + } + + static DWORD PageNumber4(int x, int y, DWORD bp, DWORD bw) + { + ASSERT((bw & 1) == 0); + + return (bp >> 5) + (y >> 7) * (bw >> 1) + (x >> 7); + } + + static DWORD PageAddress32(int x, int y, DWORD bp, DWORD bw) + { + return PageNumber32(x, y, bp, bw) << 11; + } + + static DWORD PageAddress16(int x, int y, DWORD bp, DWORD bw) + { + return PageNumber16(x, y, bp, bw) << 12; + } + + static DWORD PageAddress8(int x, int y, DWORD bp, DWORD bw) + { + return PageNumber8(x, y, bp, bw) << 13; + } + + static DWORD PageAddress4(int x, int y, DWORD bp, DWORD bw) + { + return PageNumber4(x, y, bp, bw) << 14; + } + + static DWORD BlockAddress32(int x, int y, DWORD bp, DWORD bw) + { + DWORD page = bp + (y & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable32[(y >> 3) & 3][(x >> 3) & 7]; + return (page + block) << 6; + } + + static DWORD BlockAddress16(int x, int y, DWORD bp, DWORD bw) + { + DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable16[(y >> 3) & 7][(x >> 4) & 3]; + return (page + block) << 7; + } + + static DWORD BlockAddress16S(int x, int y, DWORD bp, DWORD bw) + { + DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable16S[(y >> 3) & 7][(x >> 4) & 3]; + return (page + block) << 7; + } + + static DWORD BlockAddress8(int x, int y, DWORD bp, DWORD bw) + { + ASSERT((bw & 1) == 0); + DWORD page = bp + ((y >> 1) & ~0x1f) * (bw >> 1) + ((x >> 2) & ~0x1f); + DWORD block = blockTable8[(y >> 4) & 3][(x >> 4) & 7]; + return (page + block) << 8; + } + + static DWORD BlockAddress4(int x, int y, DWORD bp, DWORD bw) + { + ASSERT((bw & 1) == 0); + DWORD page = bp + ((y >> 2) & ~0x1f) * (bw >> 1) + ((x >> 2) & ~0x1f); + DWORD block = blockTable4[(y >> 4) & 7][(x >> 5) & 3]; + return (page + block) << 9; + } + + static DWORD BlockAddress32Z(int x, int y, DWORD bp, DWORD bw) + { + DWORD page = bp + (y & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable32Z[(y >> 3) & 3][(x >> 3) & 7]; + return (page + block) << 6; + } + + static DWORD BlockAddress16Z(int x, int y, DWORD bp, DWORD bw) + { + DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable16Z[(y >> 3) & 7][(x >> 4) & 3]; + return (page + block) << 7; + } + + static DWORD BlockAddress16SZ(int x, int y, DWORD bp, DWORD bw) + { + DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable16SZ[(y >> 3) & 7][(x >> 4) & 3]; + return (page + block) << 7; + } + + static DWORD PixelAddressOrg32(int x, int y, DWORD bp, DWORD bw) + { + DWORD page = bp + (y & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable32[(y >> 3) & 3][(x >> 3) & 7]; + DWORD word = ((page + block) << 6) + columnTable32[y & 7][x & 7]; + ASSERT(word < 1024*1024); + return word; + } + + static DWORD PixelAddressOrg16(int x, int y, DWORD bp, DWORD bw) + { + DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable16[(y >> 3) & 7][(x >> 4) & 3]; + DWORD word = ((page + block) << 7) + columnTable16[y & 7][x & 15]; + ASSERT(word < 1024*1024*2); + return word; + } + + static DWORD PixelAddressOrg16S(int x, int y, DWORD bp, DWORD bw) + { + DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable16S[(y >> 3) & 7][(x >> 4) & 3]; + DWORD word = ((page + block) << 7) + columnTable16[y & 7][x & 15]; + ASSERT(word < 1024*1024*2); + return word; + } + + static DWORD PixelAddressOrg8(int x, int y, DWORD bp, DWORD bw) + { + ASSERT((bw & 1) == 0); + DWORD page = bp + ((y >> 1) & ~0x1f) * (bw >> 1) + ((x >> 2) & ~0x1f); + DWORD block = blockTable8[(y >> 4) & 3][(x >> 4) & 7]; + DWORD word = ((page + block) << 8) + columnTable8[y & 15][x & 15]; + ASSERT(word < 1024*1024*4); + return word; + } + + static DWORD PixelAddressOrg4(int x, int y, DWORD bp, DWORD bw) + { + ASSERT((bw & 1) == 0); + DWORD page = bp + ((y >> 2) & ~0x1f) * (bw >> 1) + ((x >> 2) & ~0x1f); + DWORD block = blockTable4[(y >> 4) & 7][(x >> 5) & 3]; + DWORD word = ((page + block) << 9) + columnTable4[y & 15][x & 31]; + ASSERT(word < 1024*1024*8); + return word; + } + + static DWORD PixelAddressOrg32Z(int x, int y, DWORD bp, DWORD bw) + { + DWORD page = bp + (y & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable32Z[(y >> 3) & 3][(x >> 3) & 7]; + DWORD word = ((page + block) << 6) + columnTable32[y & 7][x & 7]; + ASSERT(word < 1024*1024); + return word; + } + + static DWORD PixelAddressOrg16Z(int x, int y, DWORD bp, DWORD bw) + { + DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable16Z[(y >> 3) & 7][(x >> 4) & 3]; + DWORD word = ((page + block) << 7) + columnTable16[y & 7][x & 15]; + ASSERT(word < 1024*1024*2); + return word; + } + + static DWORD PixelAddressOrg16SZ(int x, int y, DWORD bp, DWORD bw) + { + DWORD page = bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f); + DWORD block = blockTable16SZ[(y >> 3) & 7][(x >> 4) & 3]; + DWORD word = ((page + block) << 7) + columnTable16[y & 7][x & 15]; + ASSERT(word < 1024*1024*2); + return word; + } + + static __forceinline DWORD PixelAddress32(int x, int y, DWORD bp, DWORD bw) + { + DWORD page = (bp >> 5) + (y >> 5) * bw + (x >> 6); + DWORD word = (page << 11) + pageOffset32[bp & 0x1f][y & 0x1f][x & 0x3f]; + return word; + } + + static __forceinline DWORD PixelAddress16(int x, int y, DWORD bp, DWORD bw) + { + DWORD page = (bp >> 5) + (y >> 6) * bw + (x >> 6); + DWORD word = (page << 12) + pageOffset16[bp & 0x1f][y & 0x3f][x & 0x3f]; + return word; + } + + static __forceinline DWORD PixelAddress16S(int x, int y, DWORD bp, DWORD bw) + { + DWORD page = (bp >> 5) + (y >> 6) * bw + (x >> 6); + DWORD word = (page << 12) + pageOffset16S[bp & 0x1f][y & 0x3f][x & 0x3f]; + return word; + } + + static __forceinline DWORD PixelAddress8(int x, int y, DWORD bp, DWORD bw) + { + ASSERT((bw & 1) == 0); + DWORD page = (bp >> 5) + (y >> 6) * (bw >> 1) + (x >> 7); + DWORD word = (page << 13) + pageOffset8[bp & 0x1f][y & 0x3f][x & 0x7f]; + return word; + } + + static __forceinline DWORD PixelAddress4(int x, int y, DWORD bp, DWORD bw) + { + ASSERT((bw & 1) == 0); + DWORD page = (bp >> 5) + (y >> 7) * (bw >> 1) + (x >> 7); + DWORD word = (page << 14) + pageOffset4[bp & 0x1f][y & 0x7f][x & 0x7f]; + return word; + } + + static __forceinline DWORD PixelAddress32Z(int x, int y, DWORD bp, DWORD bw) + { + DWORD page = (bp >> 5) + (y >> 5) * bw + (x >> 6); + DWORD word = (page << 11) + pageOffset32Z[bp & 0x1f][y & 0x1f][x & 0x3f]; + return word; + } + + static __forceinline DWORD PixelAddress16Z(int x, int y, DWORD bp, DWORD bw) + { + DWORD page = (bp >> 5) + (y >> 6) * bw + (x >> 6); + DWORD word = (page << 12) + pageOffset16Z[bp & 0x1f][y & 0x3f][x & 0x3f]; + return word; + } + + static __forceinline DWORD PixelAddress16SZ(int x, int y, DWORD bp, DWORD bw) + { + DWORD page = (bp >> 5) + (y >> 6) * bw + (x >> 6); + DWORD word = (page << 12) + pageOffset16SZ[bp & 0x1f][y & 0x3f][x & 0x3f]; + return word; + } + + // pixel R/W + + __forceinline DWORD ReadPixel32(DWORD addr) const + { + return m_vm32[addr]; + } + + __forceinline DWORD ReadPixel24(DWORD addr) const + { + return m_vm32[addr] & 0x00ffffff; + } + + __forceinline DWORD ReadPixel16(DWORD addr) const + { + return (DWORD)m_vm16[addr]; + } + + __forceinline DWORD ReadPixel8(DWORD addr) const + { + return (DWORD)m_vm8[addr]; + } + + __forceinline DWORD ReadPixel4(DWORD addr) const + { + return (m_vm8[addr >> 1] >> ((addr & 1) << 2)) & 0x0f; + } + + __forceinline DWORD ReadPixel8H(DWORD addr) const + { + return m_vm32[addr] >> 24; + } + + __forceinline DWORD ReadPixel4HL(DWORD addr) const + { + return (m_vm32[addr] >> 24) & 0x0f; + } + + __forceinline DWORD ReadPixel4HH(DWORD addr) const + { + return (m_vm32[addr] >> 28) & 0x0f; + } + + __forceinline DWORD ReadFrame24(DWORD addr) const + { + return 0x80000000 | (m_vm32[addr] & 0xffffff); + } + + __forceinline DWORD ReadFrame16(DWORD addr) const + { + DWORD c = (DWORD)m_vm16[addr]; + + return ((c & 0x8000) << 16) | ((c & 0x7c00) << 9) | ((c & 0x03e0) << 6) | ((c & 0x001f) << 3); + } + + __forceinline DWORD ReadPixel32(int x, int y, DWORD bp, DWORD bw) const + { + return ReadPixel32(PixelAddress32(x, y, bp, bw)); + } + + __forceinline DWORD ReadPixel24(int x, int y, DWORD bp, DWORD bw) const + { + return ReadPixel24(PixelAddress32(x, y, bp, bw)); + } + + __forceinline DWORD ReadPixel16(int x, int y, DWORD bp, DWORD bw) const + { + return ReadPixel16(PixelAddress16(x, y, bp, bw)); + } + + __forceinline DWORD ReadPixel16S(int x, int y, DWORD bp, DWORD bw) const + { + return ReadPixel16(PixelAddress16S(x, y, bp, bw)); + } + + __forceinline DWORD ReadPixel8(int x, int y, DWORD bp, DWORD bw) const + { + return ReadPixel8(PixelAddress8(x, y, bp, bw)); + } + + __forceinline DWORD ReadPixel4(int x, int y, DWORD bp, DWORD bw) const + { + return ReadPixel4(PixelAddress4(x, y, bp, bw)); + } + + __forceinline DWORD ReadPixel8H(int x, int y, DWORD bp, DWORD bw) const + { + return ReadPixel8H(PixelAddress32(x, y, bp, bw)); + } + + __forceinline DWORD ReadPixel4HL(int x, int y, DWORD bp, DWORD bw) const + { + return ReadPixel4HL(PixelAddress32(x, y, bp, bw)); + } + + __forceinline DWORD ReadPixel4HH(int x, int y, DWORD bp, DWORD bw) const + { + return ReadPixel4HH(PixelAddress32(x, y, bp, bw)); + } + + __forceinline DWORD ReadPixel32Z(int x, int y, DWORD bp, DWORD bw) const + { + return ReadPixel32(PixelAddress32Z(x, y, bp, bw)); + } + + __forceinline DWORD ReadPixel24Z(int x, int y, DWORD bp, DWORD bw) const + { + return ReadPixel24(PixelAddress32Z(x, y, bp, bw)); + } + + __forceinline DWORD ReadPixel16Z(int x, int y, DWORD bp, DWORD bw) const + { + return ReadPixel16(PixelAddress16Z(x, y, bp, bw)); + } + + __forceinline DWORD ReadPixel16SZ(int x, int y, DWORD bp, DWORD bw) const + { + return ReadPixel16(PixelAddress16SZ(x, y, bp, bw)); + } + + __forceinline DWORD ReadFrame24(int x, int y, DWORD bp, DWORD bw) const + { + return ReadFrame24(PixelAddress32(x, y, bp, bw)); + } + + __forceinline DWORD ReadFrame16(int x, int y, DWORD bp, DWORD bw) const + { + return ReadFrame16(PixelAddress16(x, y, bp, bw)); + } + + __forceinline DWORD ReadFrame16S(int x, int y, DWORD bp, DWORD bw) const + { + return ReadFrame16(PixelAddress16S(x, y, bp, bw)); + } + + __forceinline DWORD ReadFrame24Z(int x, int y, DWORD bp, DWORD bw) const + { + return ReadFrame24(PixelAddress32Z(x, y, bp, bw)); + } + + __forceinline DWORD ReadFrame16Z(int x, int y, DWORD bp, DWORD bw) const + { + return ReadFrame16(PixelAddress16Z(x, y, bp, bw)); + } + + __forceinline DWORD ReadFrame16SZ(int x, int y, DWORD bp, DWORD bw) const + { + return ReadFrame16(PixelAddress16SZ(x, y, bp, bw)); + } + + __forceinline void WritePixel32(DWORD addr, DWORD c) + { + m_vm32[addr] = c; + } + + __forceinline void WritePixel24(DWORD addr, DWORD c) + { + m_vm32[addr] = (m_vm32[addr] & 0xff000000) | (c & 0x00ffffff); + } + + __forceinline void WritePixel16(DWORD addr, DWORD c) + { + m_vm16[addr] = (WORD)c; + } + + __forceinline void WritePixel8(DWORD addr, DWORD c) + { + m_vm8[addr] = (BYTE)c; + } + + __forceinline void WritePixel4(DWORD addr, DWORD c) + { + int shift = (addr & 1) << 2; addr >>= 1; + + m_vm8[addr] = (BYTE)((m_vm8[addr] & (0xf0 >> shift)) | ((c & 0x0f) << shift)); + } + + __forceinline void WritePixel8H(DWORD addr, DWORD c) + { + m_vm32[addr] = (m_vm32[addr] & 0x00ffffff) | (c << 24); + } + + __forceinline void WritePixel4HL(DWORD addr, DWORD c) + { + m_vm32[addr] = (m_vm32[addr] & 0xf0ffffff) | ((c & 0x0f) << 24); + } + + __forceinline void WritePixel4HH(DWORD addr, DWORD c) + { + m_vm32[addr] = (m_vm32[addr] & 0x0fffffff) | ((c & 0x0f) << 28); + } + + __forceinline void WriteFrame16(DWORD addr, DWORD c) + { + DWORD rb = c & 0x00f800f8; + DWORD ga = c & 0x8000f800; + + WritePixel16(addr, (ga >> 16) | (rb >> 9) | (ga >> 6) | (rb >> 3)); + } + + __forceinline void WritePixel32(int x, int y, DWORD c, DWORD bp, DWORD bw) + { + WritePixel32(PixelAddress32(x, y, bp, bw), c); + } + + __forceinline void WritePixel24(int x, int y, DWORD c, DWORD bp, DWORD bw) + { + WritePixel24(PixelAddress32(x, y, bp, bw), c); + } + + __forceinline void WritePixel16(int x, int y, DWORD c, DWORD bp, DWORD bw) + { + WritePixel16(PixelAddress16(x, y, bp, bw), c); + } + + __forceinline void WritePixel16S(int x, int y, DWORD c, DWORD bp, DWORD bw) + { + WritePixel16(PixelAddress16S(x, y, bp, bw), c); + } + + __forceinline void WritePixel8(int x, int y, DWORD c, DWORD bp, DWORD bw) + { + WritePixel8(PixelAddress8(x, y, bp, bw), c); + } + + __forceinline void WritePixel4(int x, int y, DWORD c, DWORD bp, DWORD bw) + { + WritePixel4(PixelAddress4(x, y, bp, bw), c); + } + + __forceinline void WritePixel8H(int x, int y, DWORD c, DWORD bp, DWORD bw) + { + WritePixel8H(PixelAddress32(x, y, bp, bw), c); + } + + __forceinline void WritePixel4HL(int x, int y, DWORD c, DWORD bp, DWORD bw) + { + WritePixel4HL(PixelAddress32(x, y, bp, bw), c); + } + + __forceinline void WritePixel4HH(int x, int y, DWORD c, DWORD bp, DWORD bw) + { + WritePixel4HH(PixelAddress32(x, y, bp, bw), c); + } + + __forceinline void WritePixel32Z(int x, int y, DWORD c, DWORD bp, DWORD bw) + { + WritePixel32(PixelAddress32Z(x, y, bp, bw), c); + } + + __forceinline void WritePixel24Z(int x, int y, DWORD c, DWORD bp, DWORD bw) + { + WritePixel24(PixelAddress32Z(x, y, bp, bw), c); + } + + __forceinline void WritePixel16Z(int x, int y, DWORD c, DWORD bp, DWORD bw) + { + WritePixel16(PixelAddress16Z(x, y, bp, bw), c); + } + + __forceinline void WritePixel16SZ(int x, int y, DWORD c, DWORD bp, DWORD bw) + { + WritePixel16(PixelAddress16SZ(x, y, bp, bw), c); + } + + __forceinline void WriteFrame16(int x, int y, DWORD c, DWORD bp, DWORD bw) + { + WriteFrame16(PixelAddress16(x, y, bp, bw), c); + } + + __forceinline void WriteFrame16S(int x, int y, DWORD c, DWORD bp, DWORD bw) + { + WriteFrame16(PixelAddress16S(x, y, bp, bw), c); + } + + __forceinline void WriteFrame16Z(int x, int y, DWORD c, DWORD bp, DWORD bw) + { + WriteFrame16(PixelAddress16Z(x, y, bp, bw), c); + } + + __forceinline void WriteFrame16SZ(int x, int y, DWORD c, DWORD bp, DWORD bw) + { + WriteFrame16(PixelAddress16SZ(x, y, bp, bw), c); + } + + __forceinline DWORD ReadTexel32(DWORD addr, const GIFRegTEXA& TEXA) const + { + return m_vm32[addr]; + } + + __forceinline DWORD ReadTexel24(DWORD addr, const GIFRegTEXA& TEXA) const + { + return Expand24To32(m_vm32[addr], TEXA); + } + + __forceinline DWORD ReadTexel16(DWORD addr, const GIFRegTEXA& TEXA) const + { + return Expand16To32(m_vm16[addr], TEXA); + } + + __forceinline DWORD ReadTexel8(DWORD addr, const GIFRegTEXA& TEXA) const + { + return m_clut[ReadPixel8(addr)]; + } + + __forceinline DWORD ReadTexel4(DWORD addr, const GIFRegTEXA& TEXA) const + { + return m_clut[ReadPixel4(addr)]; + } + + __forceinline DWORD ReadTexel8H(DWORD addr, const GIFRegTEXA& TEXA) const + { + return m_clut[ReadPixel8H(addr)]; + } + + __forceinline DWORD ReadTexel4HL(DWORD addr, const GIFRegTEXA& TEXA) const + { + return m_clut[ReadPixel4HL(addr)]; + } + + __forceinline DWORD ReadTexel4HH(DWORD addr, const GIFRegTEXA& TEXA) const + { + return m_clut[ReadPixel4HH(addr)]; + } + + __forceinline DWORD ReadTexel32(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const + { + return ReadTexel32(PixelAddress32(x, y, TEX0.TBP0, TEX0.TBW), TEXA); + } + + __forceinline DWORD ReadTexel24(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const + { + return ReadTexel24(PixelAddress32(x, y, TEX0.TBP0, TEX0.TBW), TEXA); + } + + __forceinline DWORD ReadTexel16(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const + { + return ReadTexel16(PixelAddress16(x, y, TEX0.TBP0, TEX0.TBW), TEXA); + } + + __forceinline DWORD ReadTexel16S(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const + { + return ReadTexel16(PixelAddress16S(x, y, TEX0.TBP0, TEX0.TBW), TEXA); + } + + __forceinline DWORD ReadTexel8(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const + { + return ReadTexel8(PixelAddress8(x, y, TEX0.TBP0, TEX0.TBW), TEXA); + } + + __forceinline DWORD ReadTexel4(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const + { + return ReadTexel4(PixelAddress4(x, y, TEX0.TBP0, TEX0.TBW), TEXA); + } + + __forceinline DWORD ReadTexel8H(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const + { + return ReadTexel8H(PixelAddress32(x, y, TEX0.TBP0, TEX0.TBW), TEXA); + } + + __forceinline DWORD ReadTexel4HL(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const + { + return ReadTexel4HL(PixelAddress32(x, y, TEX0.TBP0, TEX0.TBW), TEXA); + } + + __forceinline DWORD ReadTexel4HH(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const + { + return ReadTexel4HH(PixelAddress32(x, y, TEX0.TBP0, TEX0.TBW), TEXA); + } + + __forceinline DWORD ReadTexel32Z(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const + { + return ReadTexel32(PixelAddress32Z(x, y, TEX0.TBP0, TEX0.TBW), TEXA); + } + + __forceinline DWORD ReadTexel24Z(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const + { + return ReadTexel24(PixelAddress32Z(x, y, TEX0.TBP0, TEX0.TBW), TEXA); + } + + __forceinline DWORD ReadTexel16Z(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const + { + return ReadTexel16(PixelAddress16Z(x, y, TEX0.TBP0, TEX0.TBW), TEXA); + } + + __forceinline DWORD ReadTexel16SZ(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const + { + return ReadTexel16(PixelAddress16SZ(x, y, TEX0.TBP0, TEX0.TBW), TEXA); + } + + __forceinline DWORD ReadTexel16NP(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const + { + return ReadPixel16(x, y, TEX0.TBP0, TEX0.TBW); + } + + __forceinline DWORD ReadTexel16SNP(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const + { + return ReadPixel16S(x, y, TEX0.TBP0, TEX0.TBW); + } + + __forceinline DWORD ReadTexel16ZNP(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const + { + return ReadPixel16Z(x, y, TEX0.TBP0, TEX0.TBW); + } + + __forceinline DWORD ReadTexel16SZNP(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const + { + return ReadPixel16SZ(x, y, TEX0.TBP0, TEX0.TBW); + } + + // + + __forceinline DWORD PixelAddressX(int PSM, int x, int y, DWORD bp, DWORD bw) + { + switch(PSM) + { + case PSM_PSMCT32: return PixelAddress32(x, y, bp, bw); + case PSM_PSMCT24: return PixelAddress32(x, y, bp, bw); + case PSM_PSMCT16: return PixelAddress16(x, y, bp, bw); + case PSM_PSMCT16S: return PixelAddress16S(x, y, bp, bw); + case PSM_PSMT8: return PixelAddress8(x, y, bp, bw); + case PSM_PSMT4: return PixelAddress4(x, y, bp, bw); + case PSM_PSMT8H: return PixelAddress32(x, y, bp, bw); + case PSM_PSMT4HL: return PixelAddress32(x, y, bp, bw); + case PSM_PSMT4HH: return PixelAddress32(x, y, bp, bw); + case PSM_PSMZ32: return PixelAddress32Z(x, y, bp, bw); + case PSM_PSMZ24: return PixelAddress32Z(x, y, bp, bw); + case PSM_PSMZ16: return PixelAddress16Z(x, y, bp, bw); + case PSM_PSMZ16S: return PixelAddress16SZ(x, y, bp, bw); + default: ASSERT(0); return PixelAddress32(x, y, bp, bw); + } + } + + __forceinline DWORD ReadPixelX(int PSM, DWORD addr) const + { + switch(PSM) + { + case PSM_PSMCT32: return ReadPixel32(addr); + case PSM_PSMCT24: return ReadPixel24(addr); + case PSM_PSMCT16: return ReadPixel16(addr); + case PSM_PSMCT16S: return ReadPixel16(addr); + case PSM_PSMT8: return ReadPixel8(addr); + case PSM_PSMT4: return ReadPixel4(addr); + case PSM_PSMT8H: return ReadPixel8H(addr); + case PSM_PSMT4HL: return ReadPixel4HL(addr); + case PSM_PSMT4HH: return ReadPixel4HH(addr); + case PSM_PSMZ32: return ReadPixel32(addr); + case PSM_PSMZ24: return ReadPixel24(addr); + case PSM_PSMZ16: return ReadPixel16(addr); + case PSM_PSMZ16S: return ReadPixel16(addr); + default: ASSERT(0); return ReadPixel32(addr); + } + } + + __forceinline DWORD ReadFrameX(int PSM, DWORD addr) const + { + switch(PSM) + { + case PSM_PSMCT32: return ReadPixel32(addr); + case PSM_PSMCT24: return ReadFrame24(addr); + case PSM_PSMCT16: return ReadFrame16(addr); + case PSM_PSMCT16S: return ReadFrame16(addr); + case PSM_PSMZ32: return ReadPixel32(addr); + case PSM_PSMZ24: return ReadFrame24(addr); + case PSM_PSMZ16: return ReadFrame16(addr); + case PSM_PSMZ16S: return ReadFrame16(addr); + default: ASSERT(0); return ReadPixel32(addr); + } + } + + __forceinline DWORD ReadTexelX(int PSM, DWORD addr, const GIFRegTEXA& TEXA) const + { + switch(PSM) + { + case PSM_PSMCT32: return ReadTexel32(addr, TEXA); + case PSM_PSMCT24: return ReadTexel24(addr, TEXA); + case PSM_PSMCT16: return ReadTexel16(addr, TEXA); + case PSM_PSMCT16S: return ReadTexel16(addr, TEXA); + case PSM_PSMT8: return ReadTexel8(addr, TEXA); + case PSM_PSMT4: return ReadTexel4(addr, TEXA); + case PSM_PSMT8H: return ReadTexel8H(addr, TEXA); + case PSM_PSMT4HL: return ReadTexel4HL(addr, TEXA); + case PSM_PSMT4HH: return ReadTexel4HH(addr, TEXA); + case PSM_PSMZ32: return ReadTexel32(addr, TEXA); + case PSM_PSMZ24: return ReadTexel24(addr, TEXA); + case PSM_PSMZ16: return ReadTexel16(addr, TEXA); + case PSM_PSMZ16S: return ReadTexel16(addr, TEXA); + default: ASSERT(0); return ReadTexel32(addr, TEXA); + } + } + + __forceinline DWORD ReadTexelX(int PSM, int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const + { + switch(PSM) + { + case PSM_PSMCT32: return ReadTexel32(x, y, TEX0, TEXA); + case PSM_PSMCT24: return ReadTexel24(x, y, TEX0, TEXA); + case PSM_PSMCT16: return ReadTexel16(x, y, TEX0, TEXA); + case PSM_PSMCT16S: return ReadTexel16(x, y, TEX0, TEXA); + case PSM_PSMT8: return ReadTexel8(x, y, TEX0, TEXA); + case PSM_PSMT4: return ReadTexel4(x, y, TEX0, TEXA); + case PSM_PSMT8H: return ReadTexel8H(x, y, TEX0, TEXA); + case PSM_PSMT4HL: return ReadTexel4HL(x, y, TEX0, TEXA); + case PSM_PSMT4HH: return ReadTexel4HH(x, y, TEX0, TEXA); + case PSM_PSMZ32: return ReadTexel32Z(x, y, TEX0, TEXA); + case PSM_PSMZ24: return ReadTexel24Z(x, y, TEX0, TEXA); + case PSM_PSMZ16: return ReadTexel16Z(x, y, TEX0, TEXA); + case PSM_PSMZ16S: return ReadTexel16Z(x, y, TEX0, TEXA); + default: ASSERT(0); return ReadTexel32(x, y, TEX0, TEXA); + } + } + + __forceinline void WritePixelX(int PSM, DWORD addr, DWORD c) + { + switch(PSM) + { + case PSM_PSMCT32: WritePixel32(addr, c); break; + case PSM_PSMCT24: WritePixel24(addr, c); break; + case PSM_PSMCT16: WritePixel16(addr, c); break; + case PSM_PSMCT16S: WritePixel16(addr, c); break; + case PSM_PSMT8: WritePixel8(addr, c); break; + case PSM_PSMT4: WritePixel4(addr, c); break; + case PSM_PSMT8H: WritePixel8H(addr, c); break; + case PSM_PSMT4HL: WritePixel4HL(addr, c); break; + case PSM_PSMT4HH: WritePixel4HH(addr, c); break; + case PSM_PSMZ32: WritePixel32(addr, c); break; + case PSM_PSMZ24: WritePixel24(addr, c); break; + case PSM_PSMZ16: WritePixel16(addr, c); break; + case PSM_PSMZ16S: WritePixel16(addr, c); break; + default: ASSERT(0); WritePixel32(addr, c); break; + } + } + + __forceinline void WriteFrameX(int PSM, DWORD addr, DWORD c) + { + switch(PSM) + { + case PSM_PSMCT32: WritePixel32(addr, c); break; + case PSM_PSMCT24: WritePixel24(addr, c); break; + case PSM_PSMCT16: WriteFrame16(addr, c); break; + case PSM_PSMCT16S: WriteFrame16(addr, c); break; + case PSM_PSMZ32: WritePixel32(addr, c); break; + case PSM_PSMZ24: WritePixel24(addr, c); break; + case PSM_PSMZ16: WriteFrame16(addr, c); break; + case PSM_PSMZ16S: WriteFrame16(addr, c); break; + default: ASSERT(0); WritePixel32(addr, c); break; + } + } + + // FillRect + + bool FillRect(const GSVector4i& r, DWORD c, DWORD psm, DWORD bp, DWORD bw); + + // + + template + void WriteImageColumn(int l, int r, int y, int h, BYTE* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF); + + template + void WriteImageBlock(int l, int r, int y, int h, BYTE* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF); + + template + void WriteImageLeftRight(int l, int r, int y, int h, BYTE* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF); + + template + void WriteImageTopBottom(int l, int r, int y, int h, BYTE* src, int srcpitch, const GIFRegBITBLTBUF& BITBLTBUF); + + template + void WriteImage(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); + + void WriteImage24(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); + void WriteImage8H(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); + void WriteImage4HL(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); + void WriteImage4HH(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); + void WriteImage24Z(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); + void WriteImageX(int& tx, int& ty, BYTE* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); + + // TODO: ReadImage32/24/... + + void ReadImageX(int& tx, int& ty, BYTE* dst, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) const; + + // + + void ReadTexture32(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture24(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture16(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture16S(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture8(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture4(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture8H(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture4HL(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture4HH(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture32Z(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture24Z(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture16Z(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture16SZ(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + + void ReadTexture(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP); + void ReadTextureNC(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP); + + // 32/16 + + void ReadTexture16NP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture16SNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture8NP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture4NP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture8HNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture4HLNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture4HHNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture16ZNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture16SZNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + + void ReadTextureNP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP); + void ReadTextureNPNC(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP); + + // 32/8 + + void ReadTexture8P(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture4P(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture8HP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture4HLP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + void ReadTexture4HHP(const CRect& r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; + + // + + static DWORD m_xtbl[1024], m_ytbl[1024]; + + template void ReadTexture(CRect r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, readTexel rt, readTexture rtx); + template void ReadTextureNC(CRect r, BYTE* dst, int dstpitch, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, readTexel rt, readTexture rtx); + + // + + HRESULT SaveBMP(LPCTSTR fn, DWORD bp, DWORD bw, DWORD psm, int w, int h); +}; + #pragma warning(default: 4244) \ No newline at end of file diff --git a/plugins/GSdx/GSPerfMon.cpp b/plugins/GSdx/GSPerfMon.cpp index 9164d8c9ea..ba3aa1a809 100644 --- a/plugins/GSdx/GSPerfMon.cpp +++ b/plugins/GSdx/GSPerfMon.cpp @@ -1,103 +1,103 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GSPerfMon.h" - -extern "C" unsigned __int64 __rdtsc(); - -GSPerfMon::GSPerfMon() - : m_total(0) - , m_begin(0) - , m_frame(0) - , m_lastframe(0) - , m_count(0) -{ - memset(m_counters, 0, sizeof(m_counters)); - memset(m_stats, 0, sizeof(m_stats)); - memset(m_warnings, 0, sizeof(m_warnings)); -} - -void GSPerfMon::Put(counter_t c, double val) -{ - if(c == Frame) - { - clock_t now = clock(); - - if(m_lastframe != 0) - { - m_counters[c] += now - m_lastframe; - } - - m_lastframe = now; - m_frame++; - m_count++; - } - else - { - m_counters[c] += val; - } -} - -void GSPerfMon::Update() -{ - if(m_count > 0) - { - for(int i = 0; i < countof(m_counters); i++) - { - m_stats[i] = m_counters[i] / m_count; - } - - m_count = 0; - } - - memset(m_counters, 0, sizeof(m_counters)); -} - -void GSPerfMon::Start() -{ - m_start = __rdtsc(); - - if(m_begin == 0) - { - m_begin = m_start; - } -} - -void GSPerfMon::Stop() -{ - if(m_start > 0) - { - m_total += __rdtsc() - m_start; - m_start = 0; - } -} - -int GSPerfMon::CPU() -{ - int percent = (int)(100 * m_total / (__rdtsc() - m_begin)); - - m_begin = 0; - m_start = 0; - m_total = 0; - - return percent; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSPerfMon.h" + +extern "C" unsigned __int64 __rdtsc(); + +GSPerfMon::GSPerfMon() + : m_total(0) + , m_begin(0) + , m_frame(0) + , m_lastframe(0) + , m_count(0) +{ + memset(m_counters, 0, sizeof(m_counters)); + memset(m_stats, 0, sizeof(m_stats)); + memset(m_warnings, 0, sizeof(m_warnings)); +} + +void GSPerfMon::Put(counter_t c, double val) +{ + if(c == Frame) + { + clock_t now = clock(); + + if(m_lastframe != 0) + { + m_counters[c] += now - m_lastframe; + } + + m_lastframe = now; + m_frame++; + m_count++; + } + else + { + m_counters[c] += val; + } +} + +void GSPerfMon::Update() +{ + if(m_count > 0) + { + for(int i = 0; i < countof(m_counters); i++) + { + m_stats[i] = m_counters[i] / m_count; + } + + m_count = 0; + } + + memset(m_counters, 0, sizeof(m_counters)); +} + +void GSPerfMon::Start() +{ + m_start = __rdtsc(); + + if(m_begin == 0) + { + m_begin = m_start; + } +} + +void GSPerfMon::Stop() +{ + if(m_start > 0) + { + m_total += __rdtsc() - m_start; + m_start = 0; + } +} + +int GSPerfMon::CPU() +{ + int percent = (int)(100 * m_total / (__rdtsc() - m_begin)); + + m_begin = 0; + m_start = 0; + m_total = 0; + + return percent; } \ No newline at end of file diff --git a/plugins/GSdx/GSPerfMon.h b/plugins/GSdx/GSPerfMon.h index f1e7bb6d35..1c9b94921d 100644 --- a/plugins/GSdx/GSPerfMon.h +++ b/plugins/GSdx/GSPerfMon.h @@ -1,63 +1,63 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -class GSPerfMon -{ -public: - enum counter_t {Frame, Prim, Draw, Swizzle, Unswizzle, Fillrate, Quad, CounterLast}; - enum warning_t {DATE, PABE, ABE, COLCLAMP, DepthTexture, WarningLast}; - -protected: - double m_counters[CounterLast]; - double m_stats[CounterLast]; - bool m_warnings[WarningLast]; - UINT64 m_begin, m_total, m_start, m_frame; - clock_t m_lastframe; - int m_count; - - void Start(); - void Stop(); - - friend class GSPerfMonAutoTimer; - -public: - GSPerfMon(); - - void SetFrame(UINT64 frame) {m_frame = frame;} - UINT64 GetFrame() {return m_frame;} - void Put(counter_t c, double val = 0); - double Get(counter_t c) {return m_stats[c];} - void Put(warning_t c) {m_warnings[c] = true;} - bool Get(warning_t c) {bool b = m_warnings[c]; m_warnings[c] = false; return b;} - void Update(); - int CPU(); -}; - -class GSPerfMonAutoTimer -{ - GSPerfMon* m_pm; - -public: - GSPerfMonAutoTimer(GSPerfMon& pm) {(m_pm = &pm)->Start();} - ~GSPerfMonAutoTimer() {m_pm->Stop();} -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +class GSPerfMon +{ +public: + enum counter_t {Frame, Prim, Draw, Swizzle, Unswizzle, Fillrate, Quad, CounterLast}; + enum warning_t {DATE, PABE, ABE, COLCLAMP, DepthTexture, WarningLast}; + +protected: + double m_counters[CounterLast]; + double m_stats[CounterLast]; + bool m_warnings[WarningLast]; + UINT64 m_begin, m_total, m_start, m_frame; + clock_t m_lastframe; + int m_count; + + void Start(); + void Stop(); + + friend class GSPerfMonAutoTimer; + +public: + GSPerfMon(); + + void SetFrame(UINT64 frame) {m_frame = frame;} + UINT64 GetFrame() {return m_frame;} + void Put(counter_t c, double val = 0); + double Get(counter_t c) {return m_stats[c];} + void Put(warning_t c) {m_warnings[c] = true;} + bool Get(warning_t c) {bool b = m_warnings[c]; m_warnings[c] = false; return b;} + void Update(); + int CPU(); +}; + +class GSPerfMonAutoTimer +{ + GSPerfMon* m_pm; + +public: + GSPerfMonAutoTimer(GSPerfMon& pm) {(m_pm = &pm)->Start();} + ~GSPerfMonAutoTimer() {m_pm->Stop();} +}; diff --git a/plugins/GSdx/GSRasterizer.cpp b/plugins/GSdx/GSRasterizer.cpp index 0362ef3c69..19a5f172bb 100644 --- a/plugins/GSdx/GSRasterizer.cpp +++ b/plugins/GSdx/GSRasterizer.cpp @@ -1,726 +1,726 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSRasterizer.h" - -GSRasterizer::GSRasterizer(IDrawScanline* ds, int id, int threads) - : m_ds(ds) - , m_id(id) - , m_threads(threads) -{ -} - -GSRasterizer::~GSRasterizer() -{ - delete m_ds; -} - -void GSRasterizer::Draw(const GSRasterizerData* data) -{ - m_dsf.sl = NULL; - m_dsf.sr = NULL; - m_dsf.sp = NULL; - - m_ds->BeginDraw(data, &m_dsf); - - const GSVector4i scissor = data->scissor; - const GSVertexSW* vertices = data->vertices; - const int count = data->count; - - m_stats.Reset(); - - __int64 start = __rdtsc(); - - switch(data->primclass) - { - case GS_POINT_CLASS: - m_stats.prims = count; - for(int i = 0; i < count; i++) DrawPoint(&vertices[i], scissor); - break; - case GS_LINE_CLASS: - ASSERT(!(count & 1)); - m_stats.prims = count / 2; - for(int i = 0; i < count; i += 2) DrawLine(&vertices[i], scissor); - break; - case GS_TRIANGLE_CLASS: - ASSERT(!(count % 3)); - m_stats.prims = count / 3; - for(int i = 0; i < count; i += 3) DrawTriangle(&vertices[i], scissor); - break; - case GS_SPRITE_CLASS: - ASSERT(!(count & 1)); - m_stats.prims = count / 2; - for(int i = 0; i < count; i += 2) DrawSprite(&vertices[i], scissor); - break; - default: - __assume(0); - } - - m_stats.ticks = __rdtsc() - start; - - m_ds->EndDraw(m_stats); -} - -void GSRasterizer::GetStats(GSRasterizerStats& stats) -{ - stats = m_stats; -} - -void GSRasterizer::DrawPoint(const GSVertexSW* v, const GSVector4i& scissor) -{ - // TODO: round to closest for point, prestep for line - - GSVector4i p(v->p); - - if(scissor.x <= p.x && p.x < scissor.z && scissor.y <= p.y && p.y < scissor.w) - { - if((p.y % m_threads) == m_id) - { - (m_ds->*m_dsf.sp)(v, *v); - - (m_ds->*m_dsf.sl)(p.y, p.x, p.x + 1, *v); - - m_stats.pixels++; - } - } -} - -void GSRasterizer::DrawLine(const GSVertexSW* v, const GSVector4i& scissor) -{ - GSVertexSW dv = v[1] - v[0]; - - GSVector4 dp = dv.p.abs(); - GSVector4i dpi(dp); - - if(dpi.y == 0) - { - if(dpi.x > 0) - { - // shortcut for horizontal lines - - GSVector4 mask = (v[0].p > v[1].p).xxxx(); - - GSVertexSW l, dl; - - l.p = v[0].p.blend8(v[1].p, mask); - l.t = v[0].t.blend8(v[1].t, mask); - l.c = v[0].c.blend8(v[1].c, mask); - - GSVector4 r; - - r = v[1].p.blend8(v[0].p, mask); - - GSVector4i p(l.p); - - if(scissor.y <= p.y && p.y < scissor.w) - { - GSVertexSW dscan = dv / dv.p.xxxx(); - - (m_ds->*m_dsf.sp)(v, dscan); - - l.p = l.p.upl(r).xyzw(l.p); // r.x => l.y - - DrawTriangleSection(p.y, p.y + 1, l, dl, dscan, scissor); - } - } - - return; - } - - int i = dpi.x > dpi.y ? 0 : 1; - - GSVertexSW edge = v[0]; - GSVertexSW dedge = dv / dp.v[i]; - - // TODO: prestep + clip with the scissor - - int steps = dpi.v[i]; - - while(steps-- > 0) - { - DrawPoint(&edge, scissor); - - edge += dedge; - } -} - -static const int s_abc[8][4] = -{ - {0, 1, 2, 0}, - {1, 0, 2, 0}, - {0, 0, 0, 0}, - {1, 2, 0, 0}, - {0, 2, 1, 0}, - {0, 0, 0, 0}, - {2, 0, 1, 0}, - {2, 1, 0, 0}, -}; - -void GSRasterizer::DrawTriangle(const GSVertexSW* vertices, const GSVector4i& scissor) -{ - GSVertexSW v[3]; - - GSVector4 aabb = vertices[0].p.yyyy(vertices[1].p); - GSVector4 bccb = vertices[1].p.yyyy(vertices[2].p).xzzx(); - - int i = (aabb > bccb).mask() & 7; - - v[0] = vertices[s_abc[i][0]]; - v[1] = vertices[s_abc[i][1]]; - v[2] = vertices[s_abc[i][2]]; - - aabb = v[0].p.yyyy(v[1].p); - bccb = v[1].p.yyyy(v[2].p).xzzx(); - - i = (aabb == bccb).mask() & 7; - - switch(i) - { - case 0: // a < b < c - DrawTriangleTopBottom(v, scissor); - break; - case 1: // a == b < c - DrawTriangleBottom(v, scissor); - break; - case 4: // a < b == c - DrawTriangleTop(v, scissor); - break; - case 7: // a == b == c - break; - default: - __assume(0); - } -} - -void GSRasterizer::DrawTriangleTop(GSVertexSW* v, const GSVector4i& scissor) -{ - GSVertexSW longest; - - longest.p = v[2].p - v[1].p; - - int i = (longest.p > GSVector4::zero()).upl(longest.p == GSVector4::zero()).mask(); - - if(i & 2) return; - - i &= 1; - - GSVertexSW& l = v[0]; - GSVector4& r = v[0].p; - - GSVector4i tb(l.p.xyxy(v[2].p).ceil()); - - int top = tb.extract32<1>(); - int bottom = tb.extract32<3>(); - - if(top < scissor.y) top = scissor.y; - if(bottom > scissor.w) bottom = scissor.w; - if(top >= bottom) return; - - longest.t = v[2].t - v[1].t; - longest.c = v[2].c - v[1].c; - - GSVertexSW dscan = longest * longest.p.xxxx().rcp(); - - GSVertexSW vl = v[2 - i] - l; - GSVector4 vr = v[1 + i].p - r; - - GSVertexSW dl = vl / vl.p.yyyy(); - GSVector4 dr = vr / vr.yyyy(); - - float py = (float)top - l.p.y; - - l.p = l.p.upl(r).xyzw(l.p); // r.x => l.y - dl.p = dl.p.upl(dr).xyzw(dl.p); // dr.x => dl.y - - if(py > 0) l += dl * py; - - (m_ds->*m_dsf.sp)(v, dscan); - - DrawTriangleSection(top, bottom, l, dl, dscan, scissor); -} - -void GSRasterizer::DrawTriangleBottom(GSVertexSW* v, const GSVector4i& scissor) -{ - GSVertexSW longest; - - longest.p = v[1].p - v[0].p; - - int i = (longest.p > GSVector4::zero()).upl(longest.p == GSVector4::zero()).mask(); - - if(i & 2) return; - - i &= 1; - - GSVertexSW& l = v[1 - i]; - GSVector4& r = v[i].p; - - GSVector4i tb(l.p.xyxy(v[2].p).ceil()); - - int top = tb.extract32<1>(); - int bottom = tb.extract32<3>(); - - if(top < scissor.y) top = scissor.y; - if(bottom > scissor.w) bottom = scissor.w; - if(top >= bottom) return; - - longest.t = v[1].t - v[0].t; - longest.c = v[1].c - v[0].c; - - GSVertexSW dscan = longest * longest.p.xxxx().rcp(); - - GSVertexSW vl = v[2] - l; - GSVector4 vr = v[2].p - r; - - GSVertexSW dl = vl / vl.p.yyyy(); - GSVector4 dr = vr / vr.yyyy(); - - float py = (float)top - l.p.y; - - l.p = l.p.upl(r).xyzw(l.p); // r.x => l.y - dl.p = dl.p.upl(dr).xyzw(dl.p); // dr.x => dl.y - - if(py > 0) l += dl * py; - - (m_ds->*m_dsf.sp)(v, dscan); - - DrawTriangleSection(top, bottom, l, dl, dscan, scissor); -} - -void GSRasterizer::DrawTriangleTopBottom(GSVertexSW* v, const GSVector4i& scissor) -{ - GSVertexSW dv[3]; - - dv[0] = v[1] - v[0]; - dv[1] = v[2] - v[0]; - - GSVertexSW longest = v[0] + dv[1] * (dv[0].p / dv[1].p).yyyy() - v[1]; - - int i = (longest.p > GSVector4::zero()).upl(longest.p == GSVector4::zero()).mask(); - - if(i & 2) return; - - i &= 1; - - GSVertexSW dscan = longest * longest.p.xxxx().rcp(); - - (m_ds->*m_dsf.sp)(v, dscan); - - GSVertexSW& l = v[0]; - GSVector4 r = v[0].p; - - GSVertexSW dl; - GSVector4 dr; - - dl = dv[1 - i] / dv[1 - i].p.yyyy(); - dr = dv[i].p / dv[i].p.yyyy(); - - GSVector4i tb(v[0].p.yyyy(v[1].p).xzyy(v[2].p).ceil()); - - int top = tb.x; - int bottom = tb.y; - - if(top < scissor.y) top = scissor.y; - if(bottom > scissor.w) bottom = scissor.w; - - float py = (float)top - l.p.y; - - if(py > 0) - { - GSVector4 dy(py); - - l += dl * dy; - r += dr * dy; - } - - if(top < bottom) - { - DrawTriangleSection(top, bottom, l, dl, r, dr, dscan, scissor); - } - - if(i) - { - l = v[1]; - - dv[2] = v[2] - v[1]; - - dl = dv[2] / dv[2].p.yyyy(); - } - else - { - r = v[1].p; - - dv[2].p = v[2].p - v[1].p; - - dr = dv[2].p / dv[2].p.yyyy(); - } - - top = tb.y; - bottom = tb.z; - - if(top < scissor.y) top = scissor.y; - if(bottom > scissor.w) bottom = scissor.w; - - if(top < bottom) - { - py = (float)top - l.p.y; - - if(py > 0) l += dl * py; - - py = (float)top - r.y; - - if(py > 0) r += dr * py; - - l.p = l.p.upl(r).xyzw(l.p); // r.x => l.y - dl.p = dl.p.upl(dr).xyzw(dl.p); // dr.x => dl.y - - DrawTriangleSection(top, bottom, l, dl, dscan, scissor); - } -} - -void GSRasterizer::DrawTriangleSection(int top, int bottom, GSVertexSW& l, const GSVertexSW& dl, GSVector4& r, const GSVector4& dr, const GSVertexSW& dscan, const GSVector4i& scissor) -{ - ASSERT(top < bottom); - - while(1) - { - do - { - if((top % m_threads) == m_id) - { - GSVector4i lr(l.p.xyxy(r).ceil()); - - int left = lr.extract32<0>(); - int right = lr.extract32<2>(); - - if(left < scissor.x) left = scissor.x; - if(right > scissor.z) right = scissor.z; - - int pixels = right - left; - - if(pixels > 0) - { - m_stats.pixels += pixels; - - GSVertexSW scan; - - float px = (float)left - l.p.x; - - if(px > 0) - { - scan = l + dscan * px; - } - else - { - scan = l; - } - - (m_ds->*m_dsf.sl)(top, left, right, scan); - } - } - } - while(0); - - if(++top >= bottom) break; - - l += dl; - r += dr; - } -} - - -void GSRasterizer::DrawTriangleSection(int top, int bottom, GSVertexSW& l, const GSVertexSW& dl, const GSVertexSW& dscan, const GSVector4i& scissor) -{ - ASSERT(top < bottom); - - while(1) - { - do - { - if((top % m_threads) == m_id) - { - GSVector4i lr(l.p.ceil()); - - int left = lr.extract32<0>(); - int right = lr.extract32<1>(); - - if(left < scissor.x) left = scissor.x; - if(right > scissor.z) right = scissor.z; - - int pixels = right - left; - - if(pixels > 0) - { - m_stats.pixels += pixels; - - GSVertexSW scan; - - float px = (float)left - l.p.x; - - if(px > 0) - { - scan = l + dscan * px; - } - else - { - scan = l; - } - - (m_ds->*m_dsf.sl)(top, left, right, scan); - } - } - } - while(0); - - if(++top >= bottom) break; - - l += dl; - } -} - -void GSRasterizer::DrawSprite(const GSVertexSW* vertices, const GSVector4i& scissor) -{ - GSVertexSW v[2]; - - GSVector4 mask = (vertices[0].p < vertices[1].p).xyzw(GSVector4::zero()); - - v[0].p = vertices[1].p.blend8(vertices[0].p, mask); - v[0].t = vertices[1].t.blend8(vertices[0].t, mask); - v[0].c = vertices[1].c; - - v[1].p = vertices[0].p.blend8(vertices[1].p, mask); - v[1].t = vertices[0].t.blend8(vertices[1].t, mask); - - GSVector4i r(v[0].p.xyxy(v[1].p).ceil()); - - int& top = r.y; - int& bottom = r.w; - - int& left = r.x; - int& right = r.z; - - #if _M_SSE >= 0x401 - - r = r.sat_i32(scissor); - - if((r < r.zwzw()).mask() != 0x00ff) return; - - #else - - if(top < scissor.y) top = scissor.y; - if(bottom > scissor.w) bottom = scissor.w; - if(top >= bottom) return; - - if(left < scissor.x) left = scissor.x; - if(right > scissor.z) right = scissor.z; - if(left >= right) return; - - #endif - - GSVertexSW scan = v[0]; - - if(m_dsf.sr) - { - if(m_id == 0) - { - (m_ds->*m_dsf.sr)(r, scan); - - m_stats.pixels += (r.z - r.x) * (r.w - r.y); - } - - return; - } - - GSVector4 zero = GSVector4::zero(); - - GSVertexSW dedge, dscan; - - dedge.p = zero; - dscan.p = zero; - - dedge.c = zero; - dscan.c = zero; - - GSVertexSW dv = v[1] - v[0]; - - dedge.t = (dv.t / dv.p.yyyy()).xyxy(zero).wyww(); - dscan.t = (dv.t / dv.p.xxxx()).xyxy(zero).xwww(); - - if(scan.p.y < (float)top) scan.t += dedge.t * ((float)top - scan.p.y); - if(scan.p.x < (float)left) scan.t += dscan.t * ((float)left - scan.p.x); - - (m_ds->*m_dsf.sp)(v, dscan); - - for(; top < bottom; top++, scan.t += dedge.t) - { - if((top % m_threads) == m_id) - { - (m_ds->*m_dsf.sl)(top, left, right, scan); - - m_stats.pixels += right - left; - } - } -} - -// - -GSRasterizerMT::GSRasterizerMT(IDrawScanline* ds, int id, int threads, long* sync) - : GSRasterizer(ds, id, threads) - , m_sync(sync) - , m_exit(false) - , m_ThreadId(0) - , m_hThread(NULL) - , m_data(NULL) -{ - if(id > 0) - { - m_hThread = CreateThread(NULL, 0, StaticThreadProc, (LPVOID)this, 0, &m_ThreadId); - } -} - -GSRasterizerMT::~GSRasterizerMT() -{ - if(m_hThread != NULL) - { - m_exit = true; - - if(WaitForSingleObject(m_hThread, 5000) != WAIT_OBJECT_0) - { - TerminateThread(m_hThread, 1); - } - - CloseHandle(m_hThread); - } -} - -void GSRasterizerMT::Draw(const GSRasterizerData* data) -{ - if(m_id == 0) - { - __super::Draw(data); - } - else - { - m_data = data; - - InterlockedBitTestAndSet(m_sync, m_id); - } -} - -DWORD WINAPI GSRasterizerMT::StaticThreadProc(LPVOID lpParam) -{ - return ((GSRasterizerMT*)lpParam)->ThreadProc(); -} - -DWORD GSRasterizerMT::ThreadProc() -{ - // _mm_setcsr(MXCSR); - - while(!m_exit) - { - if(*m_sync & (1 << m_id)) - { - __super::Draw(m_data); - - InterlockedBitTestAndReset(m_sync, m_id); - } - else - { - _mm_pause(); - } - } - - return 0; -} - -// - -GSRasterizerList::GSRasterizerList() -{ - // get a whole cache line (twice the size for future cpus ;) - - m_sync = (long*)_aligned_malloc(sizeof(*m_sync), 128); - - *m_sync = 0; -} - -GSRasterizerList::~GSRasterizerList() -{ - _aligned_free(m_sync); - - FreeRasterizers(); -} - -void GSRasterizerList::FreeRasterizers() -{ - while(!IsEmpty()) - { - delete RemoveHead(); - } -} - -void GSRasterizerList::Draw(const GSRasterizerData* data) -{ - *m_sync = 0; - - m_stats.Reset(); - - __int64 start = __rdtsc(); - - POSITION pos = GetTailPosition(); - - while(pos) - { - GetPrev(pos)->Draw(data); - } - - while(*m_sync) - { - _mm_pause(); - } - - m_stats.ticks = __rdtsc() - start; - - pos = GetHeadPosition(); - - while(pos) - { - GSRasterizerStats s; - - GetNext(pos)->GetStats(s); - - m_stats.pixels += s.pixels; - m_stats.prims = max(m_stats.prims, s.prims); - } -} - -void GSRasterizerList::GetStats(GSRasterizerStats& stats) -{ - stats = m_stats; -} - -void GSRasterizerList::PrintStats() -{ - if(!IsEmpty()) - { - GetHead()->PrintStats(); - } -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSRasterizer.h" + +GSRasterizer::GSRasterizer(IDrawScanline* ds, int id, int threads) + : m_ds(ds) + , m_id(id) + , m_threads(threads) +{ +} + +GSRasterizer::~GSRasterizer() +{ + delete m_ds; +} + +void GSRasterizer::Draw(const GSRasterizerData* data) +{ + m_dsf.sl = NULL; + m_dsf.sr = NULL; + m_dsf.sp = NULL; + + m_ds->BeginDraw(data, &m_dsf); + + const GSVector4i scissor = data->scissor; + const GSVertexSW* vertices = data->vertices; + const int count = data->count; + + m_stats.Reset(); + + __int64 start = __rdtsc(); + + switch(data->primclass) + { + case GS_POINT_CLASS: + m_stats.prims = count; + for(int i = 0; i < count; i++) DrawPoint(&vertices[i], scissor); + break; + case GS_LINE_CLASS: + ASSERT(!(count & 1)); + m_stats.prims = count / 2; + for(int i = 0; i < count; i += 2) DrawLine(&vertices[i], scissor); + break; + case GS_TRIANGLE_CLASS: + ASSERT(!(count % 3)); + m_stats.prims = count / 3; + for(int i = 0; i < count; i += 3) DrawTriangle(&vertices[i], scissor); + break; + case GS_SPRITE_CLASS: + ASSERT(!(count & 1)); + m_stats.prims = count / 2; + for(int i = 0; i < count; i += 2) DrawSprite(&vertices[i], scissor); + break; + default: + __assume(0); + } + + m_stats.ticks = __rdtsc() - start; + + m_ds->EndDraw(m_stats); +} + +void GSRasterizer::GetStats(GSRasterizerStats& stats) +{ + stats = m_stats; +} + +void GSRasterizer::DrawPoint(const GSVertexSW* v, const GSVector4i& scissor) +{ + // TODO: round to closest for point, prestep for line + + GSVector4i p(v->p); + + if(scissor.x <= p.x && p.x < scissor.z && scissor.y <= p.y && p.y < scissor.w) + { + if((p.y % m_threads) == m_id) + { + (m_ds->*m_dsf.sp)(v, *v); + + (m_ds->*m_dsf.sl)(p.y, p.x, p.x + 1, *v); + + m_stats.pixels++; + } + } +} + +void GSRasterizer::DrawLine(const GSVertexSW* v, const GSVector4i& scissor) +{ + GSVertexSW dv = v[1] - v[0]; + + GSVector4 dp = dv.p.abs(); + GSVector4i dpi(dp); + + if(dpi.y == 0) + { + if(dpi.x > 0) + { + // shortcut for horizontal lines + + GSVector4 mask = (v[0].p > v[1].p).xxxx(); + + GSVertexSW l, dl; + + l.p = v[0].p.blend8(v[1].p, mask); + l.t = v[0].t.blend8(v[1].t, mask); + l.c = v[0].c.blend8(v[1].c, mask); + + GSVector4 r; + + r = v[1].p.blend8(v[0].p, mask); + + GSVector4i p(l.p); + + if(scissor.y <= p.y && p.y < scissor.w) + { + GSVertexSW dscan = dv / dv.p.xxxx(); + + (m_ds->*m_dsf.sp)(v, dscan); + + l.p = l.p.upl(r).xyzw(l.p); // r.x => l.y + + DrawTriangleSection(p.y, p.y + 1, l, dl, dscan, scissor); + } + } + + return; + } + + int i = dpi.x > dpi.y ? 0 : 1; + + GSVertexSW edge = v[0]; + GSVertexSW dedge = dv / dp.v[i]; + + // TODO: prestep + clip with the scissor + + int steps = dpi.v[i]; + + while(steps-- > 0) + { + DrawPoint(&edge, scissor); + + edge += dedge; + } +} + +static const int s_abc[8][4] = +{ + {0, 1, 2, 0}, + {1, 0, 2, 0}, + {0, 0, 0, 0}, + {1, 2, 0, 0}, + {0, 2, 1, 0}, + {0, 0, 0, 0}, + {2, 0, 1, 0}, + {2, 1, 0, 0}, +}; + +void GSRasterizer::DrawTriangle(const GSVertexSW* vertices, const GSVector4i& scissor) +{ + GSVertexSW v[3]; + + GSVector4 aabb = vertices[0].p.yyyy(vertices[1].p); + GSVector4 bccb = vertices[1].p.yyyy(vertices[2].p).xzzx(); + + int i = (aabb > bccb).mask() & 7; + + v[0] = vertices[s_abc[i][0]]; + v[1] = vertices[s_abc[i][1]]; + v[2] = vertices[s_abc[i][2]]; + + aabb = v[0].p.yyyy(v[1].p); + bccb = v[1].p.yyyy(v[2].p).xzzx(); + + i = (aabb == bccb).mask() & 7; + + switch(i) + { + case 0: // a < b < c + DrawTriangleTopBottom(v, scissor); + break; + case 1: // a == b < c + DrawTriangleBottom(v, scissor); + break; + case 4: // a < b == c + DrawTriangleTop(v, scissor); + break; + case 7: // a == b == c + break; + default: + __assume(0); + } +} + +void GSRasterizer::DrawTriangleTop(GSVertexSW* v, const GSVector4i& scissor) +{ + GSVertexSW longest; + + longest.p = v[2].p - v[1].p; + + int i = (longest.p > GSVector4::zero()).upl(longest.p == GSVector4::zero()).mask(); + + if(i & 2) return; + + i &= 1; + + GSVertexSW& l = v[0]; + GSVector4& r = v[0].p; + + GSVector4i tb(l.p.xyxy(v[2].p).ceil()); + + int top = tb.extract32<1>(); + int bottom = tb.extract32<3>(); + + if(top < scissor.y) top = scissor.y; + if(bottom > scissor.w) bottom = scissor.w; + if(top >= bottom) return; + + longest.t = v[2].t - v[1].t; + longest.c = v[2].c - v[1].c; + + GSVertexSW dscan = longest * longest.p.xxxx().rcp(); + + GSVertexSW vl = v[2 - i] - l; + GSVector4 vr = v[1 + i].p - r; + + GSVertexSW dl = vl / vl.p.yyyy(); + GSVector4 dr = vr / vr.yyyy(); + + float py = (float)top - l.p.y; + + l.p = l.p.upl(r).xyzw(l.p); // r.x => l.y + dl.p = dl.p.upl(dr).xyzw(dl.p); // dr.x => dl.y + + if(py > 0) l += dl * py; + + (m_ds->*m_dsf.sp)(v, dscan); + + DrawTriangleSection(top, bottom, l, dl, dscan, scissor); +} + +void GSRasterizer::DrawTriangleBottom(GSVertexSW* v, const GSVector4i& scissor) +{ + GSVertexSW longest; + + longest.p = v[1].p - v[0].p; + + int i = (longest.p > GSVector4::zero()).upl(longest.p == GSVector4::zero()).mask(); + + if(i & 2) return; + + i &= 1; + + GSVertexSW& l = v[1 - i]; + GSVector4& r = v[i].p; + + GSVector4i tb(l.p.xyxy(v[2].p).ceil()); + + int top = tb.extract32<1>(); + int bottom = tb.extract32<3>(); + + if(top < scissor.y) top = scissor.y; + if(bottom > scissor.w) bottom = scissor.w; + if(top >= bottom) return; + + longest.t = v[1].t - v[0].t; + longest.c = v[1].c - v[0].c; + + GSVertexSW dscan = longest * longest.p.xxxx().rcp(); + + GSVertexSW vl = v[2] - l; + GSVector4 vr = v[2].p - r; + + GSVertexSW dl = vl / vl.p.yyyy(); + GSVector4 dr = vr / vr.yyyy(); + + float py = (float)top - l.p.y; + + l.p = l.p.upl(r).xyzw(l.p); // r.x => l.y + dl.p = dl.p.upl(dr).xyzw(dl.p); // dr.x => dl.y + + if(py > 0) l += dl * py; + + (m_ds->*m_dsf.sp)(v, dscan); + + DrawTriangleSection(top, bottom, l, dl, dscan, scissor); +} + +void GSRasterizer::DrawTriangleTopBottom(GSVertexSW* v, const GSVector4i& scissor) +{ + GSVertexSW dv[3]; + + dv[0] = v[1] - v[0]; + dv[1] = v[2] - v[0]; + + GSVertexSW longest = v[0] + dv[1] * (dv[0].p / dv[1].p).yyyy() - v[1]; + + int i = (longest.p > GSVector4::zero()).upl(longest.p == GSVector4::zero()).mask(); + + if(i & 2) return; + + i &= 1; + + GSVertexSW dscan = longest * longest.p.xxxx().rcp(); + + (m_ds->*m_dsf.sp)(v, dscan); + + GSVertexSW& l = v[0]; + GSVector4 r = v[0].p; + + GSVertexSW dl; + GSVector4 dr; + + dl = dv[1 - i] / dv[1 - i].p.yyyy(); + dr = dv[i].p / dv[i].p.yyyy(); + + GSVector4i tb(v[0].p.yyyy(v[1].p).xzyy(v[2].p).ceil()); + + int top = tb.x; + int bottom = tb.y; + + if(top < scissor.y) top = scissor.y; + if(bottom > scissor.w) bottom = scissor.w; + + float py = (float)top - l.p.y; + + if(py > 0) + { + GSVector4 dy(py); + + l += dl * dy; + r += dr * dy; + } + + if(top < bottom) + { + DrawTriangleSection(top, bottom, l, dl, r, dr, dscan, scissor); + } + + if(i) + { + l = v[1]; + + dv[2] = v[2] - v[1]; + + dl = dv[2] / dv[2].p.yyyy(); + } + else + { + r = v[1].p; + + dv[2].p = v[2].p - v[1].p; + + dr = dv[2].p / dv[2].p.yyyy(); + } + + top = tb.y; + bottom = tb.z; + + if(top < scissor.y) top = scissor.y; + if(bottom > scissor.w) bottom = scissor.w; + + if(top < bottom) + { + py = (float)top - l.p.y; + + if(py > 0) l += dl * py; + + py = (float)top - r.y; + + if(py > 0) r += dr * py; + + l.p = l.p.upl(r).xyzw(l.p); // r.x => l.y + dl.p = dl.p.upl(dr).xyzw(dl.p); // dr.x => dl.y + + DrawTriangleSection(top, bottom, l, dl, dscan, scissor); + } +} + +void GSRasterizer::DrawTriangleSection(int top, int bottom, GSVertexSW& l, const GSVertexSW& dl, GSVector4& r, const GSVector4& dr, const GSVertexSW& dscan, const GSVector4i& scissor) +{ + ASSERT(top < bottom); + + while(1) + { + do + { + if((top % m_threads) == m_id) + { + GSVector4i lr(l.p.xyxy(r).ceil()); + + int left = lr.extract32<0>(); + int right = lr.extract32<2>(); + + if(left < scissor.x) left = scissor.x; + if(right > scissor.z) right = scissor.z; + + int pixels = right - left; + + if(pixels > 0) + { + m_stats.pixels += pixels; + + GSVertexSW scan; + + float px = (float)left - l.p.x; + + if(px > 0) + { + scan = l + dscan * px; + } + else + { + scan = l; + } + + (m_ds->*m_dsf.sl)(top, left, right, scan); + } + } + } + while(0); + + if(++top >= bottom) break; + + l += dl; + r += dr; + } +} + + +void GSRasterizer::DrawTriangleSection(int top, int bottom, GSVertexSW& l, const GSVertexSW& dl, const GSVertexSW& dscan, const GSVector4i& scissor) +{ + ASSERT(top < bottom); + + while(1) + { + do + { + if((top % m_threads) == m_id) + { + GSVector4i lr(l.p.ceil()); + + int left = lr.extract32<0>(); + int right = lr.extract32<1>(); + + if(left < scissor.x) left = scissor.x; + if(right > scissor.z) right = scissor.z; + + int pixels = right - left; + + if(pixels > 0) + { + m_stats.pixels += pixels; + + GSVertexSW scan; + + float px = (float)left - l.p.x; + + if(px > 0) + { + scan = l + dscan * px; + } + else + { + scan = l; + } + + (m_ds->*m_dsf.sl)(top, left, right, scan); + } + } + } + while(0); + + if(++top >= bottom) break; + + l += dl; + } +} + +void GSRasterizer::DrawSprite(const GSVertexSW* vertices, const GSVector4i& scissor) +{ + GSVertexSW v[2]; + + GSVector4 mask = (vertices[0].p < vertices[1].p).xyzw(GSVector4::zero()); + + v[0].p = vertices[1].p.blend8(vertices[0].p, mask); + v[0].t = vertices[1].t.blend8(vertices[0].t, mask); + v[0].c = vertices[1].c; + + v[1].p = vertices[0].p.blend8(vertices[1].p, mask); + v[1].t = vertices[0].t.blend8(vertices[1].t, mask); + + GSVector4i r(v[0].p.xyxy(v[1].p).ceil()); + + int& top = r.y; + int& bottom = r.w; + + int& left = r.x; + int& right = r.z; + + #if _M_SSE >= 0x401 + + r = r.sat_i32(scissor); + + if((r < r.zwzw()).mask() != 0x00ff) return; + + #else + + if(top < scissor.y) top = scissor.y; + if(bottom > scissor.w) bottom = scissor.w; + if(top >= bottom) return; + + if(left < scissor.x) left = scissor.x; + if(right > scissor.z) right = scissor.z; + if(left >= right) return; + + #endif + + GSVertexSW scan = v[0]; + + if(m_dsf.sr) + { + if(m_id == 0) + { + (m_ds->*m_dsf.sr)(r, scan); + + m_stats.pixels += (r.z - r.x) * (r.w - r.y); + } + + return; + } + + GSVector4 zero = GSVector4::zero(); + + GSVertexSW dedge, dscan; + + dedge.p = zero; + dscan.p = zero; + + dedge.c = zero; + dscan.c = zero; + + GSVertexSW dv = v[1] - v[0]; + + dedge.t = (dv.t / dv.p.yyyy()).xyxy(zero).wyww(); + dscan.t = (dv.t / dv.p.xxxx()).xyxy(zero).xwww(); + + if(scan.p.y < (float)top) scan.t += dedge.t * ((float)top - scan.p.y); + if(scan.p.x < (float)left) scan.t += dscan.t * ((float)left - scan.p.x); + + (m_ds->*m_dsf.sp)(v, dscan); + + for(; top < bottom; top++, scan.t += dedge.t) + { + if((top % m_threads) == m_id) + { + (m_ds->*m_dsf.sl)(top, left, right, scan); + + m_stats.pixels += right - left; + } + } +} + +// + +GSRasterizerMT::GSRasterizerMT(IDrawScanline* ds, int id, int threads, long* sync) + : GSRasterizer(ds, id, threads) + , m_sync(sync) + , m_exit(false) + , m_ThreadId(0) + , m_hThread(NULL) + , m_data(NULL) +{ + if(id > 0) + { + m_hThread = CreateThread(NULL, 0, StaticThreadProc, (LPVOID)this, 0, &m_ThreadId); + } +} + +GSRasterizerMT::~GSRasterizerMT() +{ + if(m_hThread != NULL) + { + m_exit = true; + + if(WaitForSingleObject(m_hThread, 5000) != WAIT_OBJECT_0) + { + TerminateThread(m_hThread, 1); + } + + CloseHandle(m_hThread); + } +} + +void GSRasterizerMT::Draw(const GSRasterizerData* data) +{ + if(m_id == 0) + { + __super::Draw(data); + } + else + { + m_data = data; + + InterlockedBitTestAndSet(m_sync, m_id); + } +} + +DWORD WINAPI GSRasterizerMT::StaticThreadProc(LPVOID lpParam) +{ + return ((GSRasterizerMT*)lpParam)->ThreadProc(); +} + +DWORD GSRasterizerMT::ThreadProc() +{ + // _mm_setcsr(MXCSR); + + while(!m_exit) + { + if(*m_sync & (1 << m_id)) + { + __super::Draw(m_data); + + InterlockedBitTestAndReset(m_sync, m_id); + } + else + { + _mm_pause(); + } + } + + return 0; +} + +// + +GSRasterizerList::GSRasterizerList() +{ + // get a whole cache line (twice the size for future cpus ;) + + m_sync = (long*)_aligned_malloc(sizeof(*m_sync), 128); + + *m_sync = 0; +} + +GSRasterizerList::~GSRasterizerList() +{ + _aligned_free(m_sync); + + FreeRasterizers(); +} + +void GSRasterizerList::FreeRasterizers() +{ + while(!IsEmpty()) + { + delete RemoveHead(); + } +} + +void GSRasterizerList::Draw(const GSRasterizerData* data) +{ + *m_sync = 0; + + m_stats.Reset(); + + __int64 start = __rdtsc(); + + POSITION pos = GetTailPosition(); + + while(pos) + { + GetPrev(pos)->Draw(data); + } + + while(*m_sync) + { + _mm_pause(); + } + + m_stats.ticks = __rdtsc() - start; + + pos = GetHeadPosition(); + + while(pos) + { + GSRasterizerStats s; + + GetNext(pos)->GetStats(s); + + m_stats.pixels += s.pixels; + m_stats.prims = max(m_stats.prims, s.prims); + } +} + +void GSRasterizerList::GetStats(GSRasterizerStats& stats) +{ + stats = m_stats; +} + +void GSRasterizerList::PrintStats() +{ + if(!IsEmpty()) + { + GetHead()->PrintStats(); + } +} diff --git a/plugins/GSdx/GSRasterizer.h b/plugins/GSdx/GSRasterizer.h index a34e33a45b..f0ba3f0d06 100644 --- a/plugins/GSdx/GSRasterizer.h +++ b/plugins/GSdx/GSRasterizer.h @@ -1,153 +1,153 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GS.h" -#include "GSVertexSW.h" -#include "GSFunctionMap.h" - -// -#define FAST_DRAWSCANLINE - -__declspec(align(16)) class GSRasterizerData -{ -public: - GSVector4i scissor; - GS_PRIM_CLASS primclass; - const GSVertexSW* vertices; - int count; - const void* param; -}; - -class IRasterizer -{ -public: - virtual ~IRasterizer() {} - - virtual void Draw(const GSRasterizerData* data) = 0; - virtual void GetStats(GSRasterizerStats& stats) = 0; - virtual void PrintStats() = 0; -}; - -class IDrawScanline -{ -public: - typedef void (IDrawScanline::*DrawScanlinePtr)(int top, int left, int right, const GSVertexSW& v); - typedef void (IDrawScanline::*DrawSolidRectPtr)(const GSVector4i& r, const GSVertexSW& v); - typedef void (IDrawScanline::*SetupPrimPtr)(const GSVertexSW* vertices, const GSVertexSW& dscan); - - struct Functions - { - DrawScanlinePtr sl; - DrawSolidRectPtr sr; - SetupPrimPtr sp; - }; - - virtual ~IDrawScanline() {} - - virtual void BeginDraw(const GSRasterizerData* data, Functions* dsf) = 0; - virtual void EndDraw(const GSRasterizerStats& stats) = 0; - virtual void PrintStats() = 0; -}; - -class GSRasterizer : public IRasterizer -{ -protected: - IDrawScanline* m_ds; - IDrawScanline::Functions m_dsf; - int m_id; - int m_threads; - GSRasterizerStats m_stats; - - void DrawPoint(const GSVertexSW* v, const GSVector4i& scissor); - void DrawLine(const GSVertexSW* v, const GSVector4i& scissor); - void DrawTriangle(const GSVertexSW* v, const GSVector4i& scissor); - void DrawSprite(const GSVertexSW* v, const GSVector4i& scissor); - - void DrawTriangleTop(GSVertexSW* v, const GSVector4i& scissor); - void DrawTriangleBottom(GSVertexSW* v, const GSVector4i& scissor); - void DrawTriangleTopBottom(GSVertexSW* v, const GSVector4i& scissor); - - __forceinline void DrawTriangleSection(int top, int bottom, GSVertexSW& l, const GSVertexSW& dl, GSVector4& r, const GSVector4& dr, const GSVertexSW& dscan, const GSVector4i& scissor); - __forceinline void DrawTriangleSection(int top, int bottom, GSVertexSW& l, const GSVertexSW& dl, const GSVertexSW& dscan, const GSVector4i& scissor); - -public: - GSRasterizer(IDrawScanline* ds, int id = 0, int threads = 0); - virtual ~GSRasterizer(); - - // IRasterizer - - void Draw(const GSRasterizerData* data); - void GetStats(GSRasterizerStats& stats); - void PrintStats() {m_ds->PrintStats();} -}; - -class GSRasterizerMT : public GSRasterizer -{ - long* m_sync; - bool m_exit; - DWORD m_ThreadId; - HANDLE m_hThread; - const GSRasterizerData* m_data; - - static DWORD WINAPI StaticThreadProc(LPVOID lpParam); - - DWORD ThreadProc(); - -public: - GSRasterizerMT(IDrawScanline* ds, int id, int threads, long* sync); - virtual ~GSRasterizerMT(); - - // IRasterizer - - void Draw(const GSRasterizerData* data); -}; - -class GSRasterizerList : protected CAtlList, public IRasterizer -{ - long* m_sync; - GSRasterizerStats m_stats; - - void FreeRasterizers(); - -public: - GSRasterizerList(); - virtual ~GSRasterizerList(); - - template void Create(T* parent, int threads) - { - FreeRasterizers(); - - threads = max(threads, 1); // TODO: min(threads, number of cpu cores) - - for(int i = 0; i < threads; i++) - { - AddTail(new GSRasterizerMT(new DS(parent, i), i, threads, m_sync)); - } - } - - // IRasterizer - - void Draw(const GSRasterizerData* data); - void GetStats(GSRasterizerStats& stats); - void PrintStats(); -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GS.h" +#include "GSVertexSW.h" +#include "GSFunctionMap.h" + +// +#define FAST_DRAWSCANLINE + +__declspec(align(16)) class GSRasterizerData +{ +public: + GSVector4i scissor; + GS_PRIM_CLASS primclass; + const GSVertexSW* vertices; + int count; + const void* param; +}; + +class IRasterizer +{ +public: + virtual ~IRasterizer() {} + + virtual void Draw(const GSRasterizerData* data) = 0; + virtual void GetStats(GSRasterizerStats& stats) = 0; + virtual void PrintStats() = 0; +}; + +class IDrawScanline +{ +public: + typedef void (IDrawScanline::*DrawScanlinePtr)(int top, int left, int right, const GSVertexSW& v); + typedef void (IDrawScanline::*DrawSolidRectPtr)(const GSVector4i& r, const GSVertexSW& v); + typedef void (IDrawScanline::*SetupPrimPtr)(const GSVertexSW* vertices, const GSVertexSW& dscan); + + struct Functions + { + DrawScanlinePtr sl; + DrawSolidRectPtr sr; + SetupPrimPtr sp; + }; + + virtual ~IDrawScanline() {} + + virtual void BeginDraw(const GSRasterizerData* data, Functions* dsf) = 0; + virtual void EndDraw(const GSRasterizerStats& stats) = 0; + virtual void PrintStats() = 0; +}; + +class GSRasterizer : public IRasterizer +{ +protected: + IDrawScanline* m_ds; + IDrawScanline::Functions m_dsf; + int m_id; + int m_threads; + GSRasterizerStats m_stats; + + void DrawPoint(const GSVertexSW* v, const GSVector4i& scissor); + void DrawLine(const GSVertexSW* v, const GSVector4i& scissor); + void DrawTriangle(const GSVertexSW* v, const GSVector4i& scissor); + void DrawSprite(const GSVertexSW* v, const GSVector4i& scissor); + + void DrawTriangleTop(GSVertexSW* v, const GSVector4i& scissor); + void DrawTriangleBottom(GSVertexSW* v, const GSVector4i& scissor); + void DrawTriangleTopBottom(GSVertexSW* v, const GSVector4i& scissor); + + __forceinline void DrawTriangleSection(int top, int bottom, GSVertexSW& l, const GSVertexSW& dl, GSVector4& r, const GSVector4& dr, const GSVertexSW& dscan, const GSVector4i& scissor); + __forceinline void DrawTriangleSection(int top, int bottom, GSVertexSW& l, const GSVertexSW& dl, const GSVertexSW& dscan, const GSVector4i& scissor); + +public: + GSRasterizer(IDrawScanline* ds, int id = 0, int threads = 0); + virtual ~GSRasterizer(); + + // IRasterizer + + void Draw(const GSRasterizerData* data); + void GetStats(GSRasterizerStats& stats); + void PrintStats() {m_ds->PrintStats();} +}; + +class GSRasterizerMT : public GSRasterizer +{ + long* m_sync; + bool m_exit; + DWORD m_ThreadId; + HANDLE m_hThread; + const GSRasterizerData* m_data; + + static DWORD WINAPI StaticThreadProc(LPVOID lpParam); + + DWORD ThreadProc(); + +public: + GSRasterizerMT(IDrawScanline* ds, int id, int threads, long* sync); + virtual ~GSRasterizerMT(); + + // IRasterizer + + void Draw(const GSRasterizerData* data); +}; + +class GSRasterizerList : protected CAtlList, public IRasterizer +{ + long* m_sync; + GSRasterizerStats m_stats; + + void FreeRasterizers(); + +public: + GSRasterizerList(); + virtual ~GSRasterizerList(); + + template void Create(T* parent, int threads) + { + FreeRasterizers(); + + threads = max(threads, 1); // TODO: min(threads, number of cpu cores) + + for(int i = 0; i < threads; i++) + { + AddTail(new GSRasterizerMT(new DS(parent, i), i, threads, m_sync)); + } + } + + // IRasterizer + + void Draw(const GSRasterizerData* data); + void GetStats(GSRasterizerStats& stats); + void PrintStats(); +}; diff --git a/plugins/GSdx/GSRenderer.cpp b/plugins/GSdx/GSRenderer.cpp index c0df5dde46..8d4460dc03 100644 --- a/plugins/GSdx/GSRenderer.cpp +++ b/plugins/GSdx/GSRenderer.cpp @@ -1,23 +1,23 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSRenderer.h" +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSRenderer.h" diff --git a/plugins/GSdx/GSRenderer.h b/plugins/GSdx/GSRenderer.h index 745106a5e2..6072b04596 100644 --- a/plugins/GSdx/GSRenderer.h +++ b/plugins/GSdx/GSRenderer.h @@ -1,594 +1,594 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSWnd.h" -#include "GSState.h" -#include "GSVertexList.h" -#include "GSSettingsDlg.h" -#include "GSCapture.h" - -struct GSRendererSettings -{ - int m_interlace; - int m_aspectratio; - int m_filter; - bool m_vsync; - bool m_nativeres; -}; - -class GSRendererBase : public GSState, protected GSRendererSettings -{ -protected: - bool m_osd; - int m_field; - - void ProcessWindowMessages() - { - MSG msg; - - memset(&msg, 0, sizeof(msg)); - - while(msg.message != WM_QUIT && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - if(OnMessage(msg)) - { - continue; - } - - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - - virtual bool OnMessage(const MSG& msg) - { - if(msg.message == WM_KEYDOWN) - { - int step = (::GetAsyncKeyState(VK_SHIFT) & 0x8000) ? -1 : 1; - - if(msg.wParam == VK_F5) - { - m_interlace = (m_interlace + 7 + step) % 7; - return true; - } - - if(msg.wParam == VK_F6) - { - m_aspectratio = (m_aspectratio + 3 + step) % 3; - return true; - } - - if(msg.wParam == VK_F7) - { - m_wnd.SetWindowText(_T("PCSX2")); - m_osd = !m_osd; - return true; - } - } - - return false; - } - -public: - GSWnd m_wnd; - -public: - GSRendererBase(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs) - : GSState(base, mt, irq, nloophack) - , m_osd(true) - , m_field(0) - { - m_interlace = rs.m_interlace; - m_aspectratio = rs.m_aspectratio; - m_filter = rs.m_filter; - m_vsync = rs.m_vsync; - m_nativeres = rs.m_nativeres; - }; - - virtual bool Create(LPCTSTR title) = 0; - virtual void VSync(int field) = 0; - virtual bool MakeSnapshot(LPCTSTR path) = 0; -}; - -template class GSRenderer : public GSRendererBase -{ -protected: - typedef typename Device::Texture Texture; - - virtual void ResetDevice() {} - virtual bool GetOutput(int i, Texture& t) = 0; - - bool Merge() - { - int baseline = INT_MAX; - - for(int i = 0; i < 2; i++) - { - if(IsEnabled(i)) - { - baseline = min(GetDisplayPos(i).y, baseline); - } - } - - CSize fs(0, 0); - CSize ds(0, 0); - - Texture st[2]; - GSVector4 sr[2]; - GSVector4 dr[2]; - - for(int i = 0; i < 2; i++) - { - if(IsEnabled(i) && GetOutput(i, st[i])) - { - CRect r = GetFrameRect(i); - - // overscan hack - - if(GetDisplaySize(i).cy > 512) // hmm - { - int y = GetDeviceSize(i).cy; - if(SMODE2->INT && SMODE2->FFMD) y /= 2; - r.bottom = r.top + y; - } - - // - - sr[i].x = st[i].m_scale.x * r.left / st[i].GetWidth(); - sr[i].y = st[i].m_scale.y * r.top / st[i].GetHeight(); - sr[i].z = st[i].m_scale.x * r.right / st[i].GetWidth(); - sr[i].w = st[i].m_scale.y * r.bottom / st[i].GetHeight(); - - GSVector2 o; - - o.x = 0; - o.y = 0; - - CPoint p = GetDisplayPos(i); - - if(p.y - baseline >= 4) // 2? - { - o.y = st[i].m_scale.y * (p.y - baseline); - } - - if(SMODE2->INT && SMODE2->FFMD) o.y /= 2; - - dr[i].x = o.x; - dr[i].y = o.y; - dr[i].z = o.x + st[i].m_scale.x * r.Width(); - dr[i].w = o.y + st[i].m_scale.y * r.Height(); - -#ifdef _M_AMD64 -// schrödinger's bug, fs will be trashed unless we access these values -CString str; -str.Format(_T("%d %f %f %f %f "), i, o.x, o.y, dr[i].z, dr[i].w); -//::MessageBox(NULL, str, _T(""), MB_OK); -#endif - fs.cx = max(fs.cx, (int)(dr[i].z + 0.5f)); - fs.cy = max(fs.cy, (int)(dr[i].w + 0.5f)); - } - } - - ds.cx = fs.cx; - ds.cy = fs.cy; - - if(SMODE2->INT && SMODE2->FFMD) ds.cy *= 2; - - bool slbg = PMODE->SLBG; - bool mmod = PMODE->MMOD; - - if(st[0] || st[1]) - { - GSVector4 c; - - c.r = (float)BGCOLOR->R / 255; - c.g = (float)BGCOLOR->G / 255; - c.b = (float)BGCOLOR->B / 255; - c.a = (float)PMODE->ALP / 255; - - m_dev.Merge(st, sr, dr, fs, slbg, mmod, c); - - if(SMODE2->INT && m_interlace > 0) - { - int field = 1 - ((m_interlace - 1) & 1); - int mode = (m_interlace - 1) >> 1; - - if(!m_dev.Interlace(ds, m_field ^ field, mode, st[1].m_scale.y)) // st[1].m_scale.y - { - return false; - } - } - } - - return true; - } - - void DoCapture() - { - if(!m_capture.IsCapturing()) - { - return; - } - - CSize size = m_capture.GetSize(); - - Texture current; - - m_dev.GetCurrent(current); - - Texture offscreen; - - if(m_dev.CopyOffscreen(current, GSVector4(0, 0, 1, 1), offscreen, size.cx, size.cy)) - { - BYTE* bits = NULL; - int pitch = 0; - - if(offscreen.Map(&bits, pitch)) - { - m_capture.DeliverFrame(bits, pitch, m_dev.IsCurrentRGBA()); - - offscreen.Unmap(); - } - - m_dev.Recycle(offscreen); - } - } - - virtual bool OnMessage(const MSG& msg) - { - if(msg.message == WM_KEYDOWN) - { - if(msg.wParam == VK_F12) - { - if(m_capture.IsCapturing()) - { - m_capture.EndCapture(); - } - else - { - m_capture.BeginCapture(GetFPS()); - } - - return true; - } - } - - return __super::OnMessage(msg); - } - -public: - Device m_dev; - bool m_psrr; - - int s_n; - bool s_dump; - bool s_save; - bool s_savez; - - GSCapture m_capture; - -public: - GSRenderer(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs, bool psrr) - : GSRendererBase(base, mt, irq, nloophack, rs) - , m_psrr(psrr) - { - s_n = 0; - s_dump = !!AfxGetApp()->GetProfileInt(_T("Debug"), _T("dump"), 0); - s_save = !!AfxGetApp()->GetProfileInt(_T("Debug"), _T("save"), 0); - s_savez = !!AfxGetApp()->GetProfileInt(_T("Debug"), _T("savez"), 0); - } - - bool Create(LPCTSTR title) - { - if(!m_wnd.Create(title)) - { - return false; - } - - if(!m_dev.Create(m_wnd, m_vsync)) - { - return false; - } - - Reset(); - - return true; - } - - void VSync(int field) - { - // printf("VSYNC\n"); - - GSPerfMonAutoTimer pmat(m_perfmon); - - m_field = !!field; - - Flush(); - - m_perfmon.Put(GSPerfMon::Frame); - - ProcessWindowMessages(); - - if(m_dump) - { - m_dump.VSync(m_field, !(::GetAsyncKeyState(VK_CONTROL) & 0x8000), PMODE); - } - - if(!Merge()) return; - - // osd - - static UINT64 s_frame = 0; - static CString s_stats; - - if(m_perfmon.GetFrame() - s_frame >= 30) - { - m_perfmon.Update(); - - s_frame = m_perfmon.GetFrame(); - - double fps = 1000.0f / m_perfmon.Get(GSPerfMon::Frame); - - s_stats.Format( - _T("%I64d | %d x %d | %.2f fps (%d%%) | %s - %s | %s | %d/%d/%d | %d%% CPU | %.2f | %.2f"), - m_perfmon.GetFrame(), GetDisplaySize().cx, GetDisplaySize().cy, fps, (int)(100.0 * fps / GetFPS()), - SMODE2->INT ? (CString(_T("Interlaced ")) + (SMODE2->FFMD ? _T("(frame)") : _T("(field)"))) : _T("Progressive"), - GSSettingsDlg::g_interlace[m_interlace].name, - GSSettingsDlg::g_aspectratio[m_aspectratio].name, - (int)m_perfmon.Get(GSPerfMon::Quad), - (int)m_perfmon.Get(GSPerfMon::Prim), - (int)m_perfmon.Get(GSPerfMon::Draw), - m_perfmon.CPU(), - m_perfmon.Get(GSPerfMon::Swizzle) / 1024, - m_perfmon.Get(GSPerfMon::Unswizzle) / 1024 - ); - - double fillrate = m_perfmon.Get(GSPerfMon::Fillrate); - - if(fillrate > 0) - { - s_stats.Format(_T("%s | %.2f mpps"), CString(s_stats), fps * fillrate / (1024 * 1024)); - } - - if(m_capture.IsCapturing()) - { - s_stats += _T(" | Recording..."); - } - - if(m_perfmon.Get(GSPerfMon::COLCLAMP)) _tprintf(_T("*** NOT SUPPORTED: color wrap ***\n")); - if(m_perfmon.Get(GSPerfMon::PABE)) _tprintf(_T("*** NOT SUPPORTED: per pixel alpha blend ***\n")); - if(m_perfmon.Get(GSPerfMon::DATE)) _tprintf(_T("*** PERFORMANCE WARNING: destination alpha test used ***\n")); - if(m_perfmon.Get(GSPerfMon::ABE)) _tprintf(_T("*** NOT SUPPORTED: alpha blending mode ***\n")); - if(m_perfmon.Get(GSPerfMon::DepthTexture)) _tprintf(_T("*** NOT SUPPORTED: depth texture ***\n")); - - m_wnd.SetWindowText(s_stats); - } - - if(m_osd) - { - m_dev.Draw(s_stats + _T("\n\nF5: interlace mode\nF6: aspect ratio\nF7: OSD")); - } - - if(m_frameskip) - { - return; - } - - // - - if(m_dev.IsLost()) - { - ResetDevice(); - } - - // - - CRect r; - - m_wnd.GetClientRect(&r); - - GSUtil::FitRect(r, m_aspectratio); - - m_dev.Present(r); - - DoCapture(); - } - - bool MakeSnapshot(LPCTSTR path) - { - CString fn; - - fn.Format(_T("%s_%s"), path, CTime::GetCurrentTime().Format(_T("%Y%m%d%H%M%S"))); - - if((::GetAsyncKeyState(VK_SHIFT) & 0x8000) && !m_dump) - { - GSFreezeData fd; - fd.size = 0; - fd.data = NULL; - Freeze(&fd, true); - fd.data = new BYTE[fd.size]; - Freeze(&fd, false); - - m_dump.Open(fn + _T(".gs"), m_crc, fd, PMODE); - - delete [] fd.data; - } - - return m_dev.SaveCurrent(fn + _T(".bmp")); - } - - virtual void MinMaxUV(int w, int h, CRect& r) {r = CRect(0, 0, w, h);} - virtual bool CanUpscale() {return !m_nativeres;} -}; - -template class GSRendererT : public GSRenderer -{ -protected: - Vertex* m_vertices; - int m_count; - int m_maxcount; - GSVertexList m_vl; - - void Reset() - { - m_count = 0; - m_vl.RemoveAll(); - - __super::Reset(); - } - - void ResetPrim() - { - m_vl.RemoveAll(); - } - - void FlushPrim() - { - if(m_count > 0) - { - /* - TRACE(_T("[%d] Draw f %05x (%d) z %05x (%d %d %d %d) t %05x %05x (%d)\n"), - (int)m_perfmon.GetFrame(), - (int)m_context->FRAME.Block(), - (int)m_context->FRAME.PSM, - (int)m_context->ZBUF.Block(), - (int)m_context->ZBUF.PSM, - m_context->TEST.ZTE, - m_context->TEST.ZTST, - m_context->ZBUF.ZMSK, - PRIM->TME ? (int)m_context->TEX0.TBP0 : 0xfffff, - PRIM->TME && m_context->TEX0.PSM > PSM_PSMCT16S ? (int)m_context->TEX0.CBP : 0xfffff, - PRIM->TME ? (int)m_context->TEX0.PSM : 0xff); - */ - - if(GSUtil::EncodePSM(m_context->FRAME.PSM) != 3 && GSUtil::EncodePSM(m_context->ZBUF.PSM) != 3) - { - // FIXME: berserk fpsm = 27 (8H) - - Draw(); - } - - m_count = 0; - } - } - - void GrowVertexBuffer() - { - m_maxcount = max(10000, m_maxcount * 3/2); - m_vertices = (Vertex*)_aligned_realloc(m_vertices, sizeof(Vertex) * m_maxcount, 16); - m_maxcount -= 100; - } - - template __forceinline Vertex* DrawingKick(bool skip, DWORD& count) - { - switch(prim) - { - case GS_POINTLIST: count = 1; break; - case GS_LINELIST: count = 2; break; - case GS_LINESTRIP: count = 2; break; - case GS_TRIANGLELIST: count = 3; break; - case GS_TRIANGLESTRIP: count = 3; break; - case GS_TRIANGLEFAN: count = 3; break; - case GS_SPRITE: count = 2; break; - case GS_INVALID: count = 1; break; - default: __assume(0); - } - - if(m_vl.GetCount() < count) - { - return NULL; - } - - if(m_count >= m_maxcount) - { - GrowVertexBuffer(); - } - - Vertex* v = &m_vertices[m_count]; - - switch(prim) - { - case GS_POINTLIST: - m_vl.GetAt(0, v[0]); - m_vl.RemoveAll(); - break; - case GS_LINELIST: - m_vl.GetAt(0, v[0]); - m_vl.GetAt(1, v[1]); - m_vl.RemoveAll(); - break; - case GS_LINESTRIP: - m_vl.GetAt(0, v[0]); - m_vl.GetAt(1, v[1]); - m_vl.RemoveAt(0, 1); - break; - case GS_TRIANGLELIST: - m_vl.GetAt(0, v[0]); - m_vl.GetAt(1, v[1]); - m_vl.GetAt(2, v[2]); - m_vl.RemoveAll(); - break; - case GS_TRIANGLESTRIP: - m_vl.GetAt(0, v[0]); - m_vl.GetAt(1, v[1]); - m_vl.GetAt(2, v[2]); - m_vl.RemoveAt(0, 2); - break; - case GS_TRIANGLEFAN: - m_vl.GetAt(0, v[0]); - m_vl.GetAt(1, v[1]); - m_vl.GetAt(2, v[2]); - m_vl.RemoveAt(1, 1); - break; - case GS_SPRITE: - m_vl.GetAt(0, v[0]); - m_vl.GetAt(1, v[1]); - m_vl.RemoveAll(); - break; - case GS_INVALID: - ASSERT(0); - m_vl.RemoveAll(); - return NULL; - default: - __assume(0); - } - - return !skip ? v : NULL; - } - - virtual void Draw() = 0; - -public: - GSRendererT(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs, bool psrr = true) - : GSRenderer(base, mt, irq, nloophack, rs, psrr) - , m_count(0) - , m_maxcount(0) - , m_vertices(NULL) - { - } - - ~GSRendererT() - { - if(m_vertices) _aligned_free(m_vertices); - } -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSWnd.h" +#include "GSState.h" +#include "GSVertexList.h" +#include "GSSettingsDlg.h" +#include "GSCapture.h" + +struct GSRendererSettings +{ + int m_interlace; + int m_aspectratio; + int m_filter; + bool m_vsync; + bool m_nativeres; +}; + +class GSRendererBase : public GSState, protected GSRendererSettings +{ +protected: + bool m_osd; + int m_field; + + void ProcessWindowMessages() + { + MSG msg; + + memset(&msg, 0, sizeof(msg)); + + while(msg.message != WM_QUIT && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + if(OnMessage(msg)) + { + continue; + } + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + virtual bool OnMessage(const MSG& msg) + { + if(msg.message == WM_KEYDOWN) + { + int step = (::GetAsyncKeyState(VK_SHIFT) & 0x8000) ? -1 : 1; + + if(msg.wParam == VK_F5) + { + m_interlace = (m_interlace + 7 + step) % 7; + return true; + } + + if(msg.wParam == VK_F6) + { + m_aspectratio = (m_aspectratio + 3 + step) % 3; + return true; + } + + if(msg.wParam == VK_F7) + { + m_wnd.SetWindowText(_T("PCSX2")); + m_osd = !m_osd; + return true; + } + } + + return false; + } + +public: + GSWnd m_wnd; + +public: + GSRendererBase(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs) + : GSState(base, mt, irq, nloophack) + , m_osd(true) + , m_field(0) + { + m_interlace = rs.m_interlace; + m_aspectratio = rs.m_aspectratio; + m_filter = rs.m_filter; + m_vsync = rs.m_vsync; + m_nativeres = rs.m_nativeres; + }; + + virtual bool Create(LPCTSTR title) = 0; + virtual void VSync(int field) = 0; + virtual bool MakeSnapshot(LPCTSTR path) = 0; +}; + +template class GSRenderer : public GSRendererBase +{ +protected: + typedef typename Device::Texture Texture; + + virtual void ResetDevice() {} + virtual bool GetOutput(int i, Texture& t) = 0; + + bool Merge() + { + int baseline = INT_MAX; + + for(int i = 0; i < 2; i++) + { + if(IsEnabled(i)) + { + baseline = min(GetDisplayPos(i).y, baseline); + } + } + + CSize fs(0, 0); + CSize ds(0, 0); + + Texture st[2]; + GSVector4 sr[2]; + GSVector4 dr[2]; + + for(int i = 0; i < 2; i++) + { + if(IsEnabled(i) && GetOutput(i, st[i])) + { + CRect r = GetFrameRect(i); + + // overscan hack + + if(GetDisplaySize(i).cy > 512) // hmm + { + int y = GetDeviceSize(i).cy; + if(SMODE2->INT && SMODE2->FFMD) y /= 2; + r.bottom = r.top + y; + } + + // + + sr[i].x = st[i].m_scale.x * r.left / st[i].GetWidth(); + sr[i].y = st[i].m_scale.y * r.top / st[i].GetHeight(); + sr[i].z = st[i].m_scale.x * r.right / st[i].GetWidth(); + sr[i].w = st[i].m_scale.y * r.bottom / st[i].GetHeight(); + + GSVector2 o; + + o.x = 0; + o.y = 0; + + CPoint p = GetDisplayPos(i); + + if(p.y - baseline >= 4) // 2? + { + o.y = st[i].m_scale.y * (p.y - baseline); + } + + if(SMODE2->INT && SMODE2->FFMD) o.y /= 2; + + dr[i].x = o.x; + dr[i].y = o.y; + dr[i].z = o.x + st[i].m_scale.x * r.Width(); + dr[i].w = o.y + st[i].m_scale.y * r.Height(); + +#ifdef _M_AMD64 +// schrödinger's bug, fs will be trashed unless we access these values +CString str; +str.Format(_T("%d %f %f %f %f "), i, o.x, o.y, dr[i].z, dr[i].w); +//::MessageBox(NULL, str, _T(""), MB_OK); +#endif + fs.cx = max(fs.cx, (int)(dr[i].z + 0.5f)); + fs.cy = max(fs.cy, (int)(dr[i].w + 0.5f)); + } + } + + ds.cx = fs.cx; + ds.cy = fs.cy; + + if(SMODE2->INT && SMODE2->FFMD) ds.cy *= 2; + + bool slbg = PMODE->SLBG; + bool mmod = PMODE->MMOD; + + if(st[0] || st[1]) + { + GSVector4 c; + + c.r = (float)BGCOLOR->R / 255; + c.g = (float)BGCOLOR->G / 255; + c.b = (float)BGCOLOR->B / 255; + c.a = (float)PMODE->ALP / 255; + + m_dev.Merge(st, sr, dr, fs, slbg, mmod, c); + + if(SMODE2->INT && m_interlace > 0) + { + int field = 1 - ((m_interlace - 1) & 1); + int mode = (m_interlace - 1) >> 1; + + if(!m_dev.Interlace(ds, m_field ^ field, mode, st[1].m_scale.y)) // st[1].m_scale.y + { + return false; + } + } + } + + return true; + } + + void DoCapture() + { + if(!m_capture.IsCapturing()) + { + return; + } + + CSize size = m_capture.GetSize(); + + Texture current; + + m_dev.GetCurrent(current); + + Texture offscreen; + + if(m_dev.CopyOffscreen(current, GSVector4(0, 0, 1, 1), offscreen, size.cx, size.cy)) + { + BYTE* bits = NULL; + int pitch = 0; + + if(offscreen.Map(&bits, pitch)) + { + m_capture.DeliverFrame(bits, pitch, m_dev.IsCurrentRGBA()); + + offscreen.Unmap(); + } + + m_dev.Recycle(offscreen); + } + } + + virtual bool OnMessage(const MSG& msg) + { + if(msg.message == WM_KEYDOWN) + { + if(msg.wParam == VK_F12) + { + if(m_capture.IsCapturing()) + { + m_capture.EndCapture(); + } + else + { + m_capture.BeginCapture(GetFPS()); + } + + return true; + } + } + + return __super::OnMessage(msg); + } + +public: + Device m_dev; + bool m_psrr; + + int s_n; + bool s_dump; + bool s_save; + bool s_savez; + + GSCapture m_capture; + +public: + GSRenderer(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs, bool psrr) + : GSRendererBase(base, mt, irq, nloophack, rs) + , m_psrr(psrr) + { + s_n = 0; + s_dump = !!AfxGetApp()->GetProfileInt(_T("Debug"), _T("dump"), 0); + s_save = !!AfxGetApp()->GetProfileInt(_T("Debug"), _T("save"), 0); + s_savez = !!AfxGetApp()->GetProfileInt(_T("Debug"), _T("savez"), 0); + } + + bool Create(LPCTSTR title) + { + if(!m_wnd.Create(title)) + { + return false; + } + + if(!m_dev.Create(m_wnd, m_vsync)) + { + return false; + } + + Reset(); + + return true; + } + + void VSync(int field) + { + // printf("VSYNC\n"); + + GSPerfMonAutoTimer pmat(m_perfmon); + + m_field = !!field; + + Flush(); + + m_perfmon.Put(GSPerfMon::Frame); + + ProcessWindowMessages(); + + if(m_dump) + { + m_dump.VSync(m_field, !(::GetAsyncKeyState(VK_CONTROL) & 0x8000), PMODE); + } + + if(!Merge()) return; + + // osd + + static UINT64 s_frame = 0; + static CString s_stats; + + if(m_perfmon.GetFrame() - s_frame >= 30) + { + m_perfmon.Update(); + + s_frame = m_perfmon.GetFrame(); + + double fps = 1000.0f / m_perfmon.Get(GSPerfMon::Frame); + + s_stats.Format( + _T("%I64d | %d x %d | %.2f fps (%d%%) | %s - %s | %s | %d/%d/%d | %d%% CPU | %.2f | %.2f"), + m_perfmon.GetFrame(), GetDisplaySize().cx, GetDisplaySize().cy, fps, (int)(100.0 * fps / GetFPS()), + SMODE2->INT ? (CString(_T("Interlaced ")) + (SMODE2->FFMD ? _T("(frame)") : _T("(field)"))) : _T("Progressive"), + GSSettingsDlg::g_interlace[m_interlace].name, + GSSettingsDlg::g_aspectratio[m_aspectratio].name, + (int)m_perfmon.Get(GSPerfMon::Quad), + (int)m_perfmon.Get(GSPerfMon::Prim), + (int)m_perfmon.Get(GSPerfMon::Draw), + m_perfmon.CPU(), + m_perfmon.Get(GSPerfMon::Swizzle) / 1024, + m_perfmon.Get(GSPerfMon::Unswizzle) / 1024 + ); + + double fillrate = m_perfmon.Get(GSPerfMon::Fillrate); + + if(fillrate > 0) + { + s_stats.Format(_T("%s | %.2f mpps"), CString(s_stats), fps * fillrate / (1024 * 1024)); + } + + if(m_capture.IsCapturing()) + { + s_stats += _T(" | Recording..."); + } + + if(m_perfmon.Get(GSPerfMon::COLCLAMP)) _tprintf(_T("*** NOT SUPPORTED: color wrap ***\n")); + if(m_perfmon.Get(GSPerfMon::PABE)) _tprintf(_T("*** NOT SUPPORTED: per pixel alpha blend ***\n")); + if(m_perfmon.Get(GSPerfMon::DATE)) _tprintf(_T("*** PERFORMANCE WARNING: destination alpha test used ***\n")); + if(m_perfmon.Get(GSPerfMon::ABE)) _tprintf(_T("*** NOT SUPPORTED: alpha blending mode ***\n")); + if(m_perfmon.Get(GSPerfMon::DepthTexture)) _tprintf(_T("*** NOT SUPPORTED: depth texture ***\n")); + + m_wnd.SetWindowText(s_stats); + } + + if(m_osd) + { + m_dev.Draw(s_stats + _T("\n\nF5: interlace mode\nF6: aspect ratio\nF7: OSD")); + } + + if(m_frameskip) + { + return; + } + + // + + if(m_dev.IsLost()) + { + ResetDevice(); + } + + // + + CRect r; + + m_wnd.GetClientRect(&r); + + GSUtil::FitRect(r, m_aspectratio); + + m_dev.Present(r); + + DoCapture(); + } + + bool MakeSnapshot(LPCTSTR path) + { + CString fn; + + fn.Format(_T("%s_%s"), path, CTime::GetCurrentTime().Format(_T("%Y%m%d%H%M%S"))); + + if((::GetAsyncKeyState(VK_SHIFT) & 0x8000) && !m_dump) + { + GSFreezeData fd; + fd.size = 0; + fd.data = NULL; + Freeze(&fd, true); + fd.data = new BYTE[fd.size]; + Freeze(&fd, false); + + m_dump.Open(fn + _T(".gs"), m_crc, fd, PMODE); + + delete [] fd.data; + } + + return m_dev.SaveCurrent(fn + _T(".bmp")); + } + + virtual void MinMaxUV(int w, int h, CRect& r) {r = CRect(0, 0, w, h);} + virtual bool CanUpscale() {return !m_nativeres;} +}; + +template class GSRendererT : public GSRenderer +{ +protected: + Vertex* m_vertices; + int m_count; + int m_maxcount; + GSVertexList m_vl; + + void Reset() + { + m_count = 0; + m_vl.RemoveAll(); + + __super::Reset(); + } + + void ResetPrim() + { + m_vl.RemoveAll(); + } + + void FlushPrim() + { + if(m_count > 0) + { + /* + TRACE(_T("[%d] Draw f %05x (%d) z %05x (%d %d %d %d) t %05x %05x (%d)\n"), + (int)m_perfmon.GetFrame(), + (int)m_context->FRAME.Block(), + (int)m_context->FRAME.PSM, + (int)m_context->ZBUF.Block(), + (int)m_context->ZBUF.PSM, + m_context->TEST.ZTE, + m_context->TEST.ZTST, + m_context->ZBUF.ZMSK, + PRIM->TME ? (int)m_context->TEX0.TBP0 : 0xfffff, + PRIM->TME && m_context->TEX0.PSM > PSM_PSMCT16S ? (int)m_context->TEX0.CBP : 0xfffff, + PRIM->TME ? (int)m_context->TEX0.PSM : 0xff); + */ + + if(GSUtil::EncodePSM(m_context->FRAME.PSM) != 3 && GSUtil::EncodePSM(m_context->ZBUF.PSM) != 3) + { + // FIXME: berserk fpsm = 27 (8H) + + Draw(); + } + + m_count = 0; + } + } + + void GrowVertexBuffer() + { + m_maxcount = max(10000, m_maxcount * 3/2); + m_vertices = (Vertex*)_aligned_realloc(m_vertices, sizeof(Vertex) * m_maxcount, 16); + m_maxcount -= 100; + } + + template __forceinline Vertex* DrawingKick(bool skip, DWORD& count) + { + switch(prim) + { + case GS_POINTLIST: count = 1; break; + case GS_LINELIST: count = 2; break; + case GS_LINESTRIP: count = 2; break; + case GS_TRIANGLELIST: count = 3; break; + case GS_TRIANGLESTRIP: count = 3; break; + case GS_TRIANGLEFAN: count = 3; break; + case GS_SPRITE: count = 2; break; + case GS_INVALID: count = 1; break; + default: __assume(0); + } + + if(m_vl.GetCount() < count) + { + return NULL; + } + + if(m_count >= m_maxcount) + { + GrowVertexBuffer(); + } + + Vertex* v = &m_vertices[m_count]; + + switch(prim) + { + case GS_POINTLIST: + m_vl.GetAt(0, v[0]); + m_vl.RemoveAll(); + break; + case GS_LINELIST: + m_vl.GetAt(0, v[0]); + m_vl.GetAt(1, v[1]); + m_vl.RemoveAll(); + break; + case GS_LINESTRIP: + m_vl.GetAt(0, v[0]); + m_vl.GetAt(1, v[1]); + m_vl.RemoveAt(0, 1); + break; + case GS_TRIANGLELIST: + m_vl.GetAt(0, v[0]); + m_vl.GetAt(1, v[1]); + m_vl.GetAt(2, v[2]); + m_vl.RemoveAll(); + break; + case GS_TRIANGLESTRIP: + m_vl.GetAt(0, v[0]); + m_vl.GetAt(1, v[1]); + m_vl.GetAt(2, v[2]); + m_vl.RemoveAt(0, 2); + break; + case GS_TRIANGLEFAN: + m_vl.GetAt(0, v[0]); + m_vl.GetAt(1, v[1]); + m_vl.GetAt(2, v[2]); + m_vl.RemoveAt(1, 1); + break; + case GS_SPRITE: + m_vl.GetAt(0, v[0]); + m_vl.GetAt(1, v[1]); + m_vl.RemoveAll(); + break; + case GS_INVALID: + ASSERT(0); + m_vl.RemoveAll(); + return NULL; + default: + __assume(0); + } + + return !skip ? v : NULL; + } + + virtual void Draw() = 0; + +public: + GSRendererT(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs, bool psrr = true) + : GSRenderer(base, mt, irq, nloophack, rs, psrr) + , m_count(0) + , m_maxcount(0) + , m_vertices(NULL) + { + } + + ~GSRendererT() + { + if(m_vertices) _aligned_free(m_vertices); + } +}; diff --git a/plugins/GSdx/GSRendererHW.cpp b/plugins/GSdx/GSRendererHW.cpp index a5fa193796..68eaca8000 100644 --- a/plugins/GSdx/GSRendererHW.cpp +++ b/plugins/GSdx/GSRendererHW.cpp @@ -1,23 +1,23 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" #include "GSRendererHW.h" \ No newline at end of file diff --git a/plugins/GSdx/GSRendererHW.h b/plugins/GSdx/GSRendererHW.h index 5296f2ea06..3fc3f346e7 100644 --- a/plugins/GSdx/GSRendererHW.h +++ b/plugins/GSdx/GSRendererHW.h @@ -1,633 +1,633 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSRenderer.h" -#include "GSTextureCache.h" -#include "GSCrc.h" - -template -class GSRendererHW : public GSRendererT -{ - TextureCache* m_tc; - int m_width; - int m_height; - int m_skip; - bool m_reset; - -protected: - void Reset() - { - // TODO: GSreset can come from the main thread too => crash - // m_tc->RemoveAll(); - - m_reset = true; - - __super::Reset(); - } - - void MinMaxUV(int w, int h, CRect& r) - { - int wms = m_context->CLAMP.WMS; - int wmt = m_context->CLAMP.WMT; - - int minu = (int)m_context->CLAMP.MINU; - int minv = (int)m_context->CLAMP.MINV; - int maxu = (int)m_context->CLAMP.MAXU; - int maxv = (int)m_context->CLAMP.MAXV; - - GSVector4i vr = GSVector4i(0, 0, w, h); - - GSVector4i wm[3]; - - if(wms + wmt < 6) - { - GSVector4 mm; - - if(m_count < 100) - { - Vertex* v = m_vertices; - - GSVector4 minv(+1e10f); - GSVector4 maxv(-1e10f); - - int i = 0; - - if(PRIM->FST) - { - for(int j = m_count - 3; i < j; i += 4) - { - GSVector4 v0 = GSVector4(v[i + 0].m128[0]); - GSVector4 v1 = GSVector4(v[i + 1].m128[0]); - GSVector4 v2 = GSVector4(v[i + 2].m128[0]); - GSVector4 v3 = GSVector4(v[i + 3].m128[0]); - - minv = minv.minv((v0.minv(v1)).minv(v2.minv(v3))); - maxv = maxv.maxv((v0.maxv(v1)).maxv(v2.maxv(v3))); - } - - for(int j = m_count; i < j; i++) - { - GSVector4 v0 = GSVector4(v[i + 0].m128[0]); - - minv = minv.minv(v0); - maxv = maxv.maxv(v0); - } - - mm = minv.xyxy(maxv) * GSVector4(16 << m_context->TEX0.TW, 16 << m_context->TEX0.TH, 16 << m_context->TEX0.TW, 16 << m_context->TEX0.TH).rcpnr(); - } - else - { - /* - for(int j = m_count - 3; i < j; i += 4) - { - GSVector4 v0 = GSVector4(v[i + 0].m128[0]) / GSVector4(v[i + 0].GetQ()); - GSVector4 v1 = GSVector4(v[i + 1].m128[0]) / GSVector4(v[i + 1].GetQ()); - GSVector4 v2 = GSVector4(v[i + 2].m128[0]) / GSVector4(v[i + 2].GetQ()); - GSVector4 v3 = GSVector4(v[i + 3].m128[0]) / GSVector4(v[i + 3].GetQ()); - - minv = minv.minv((v0.minv(v1)).minv(v2.minv(v3))); - maxv = maxv.maxv((v0.maxv(v1)).maxv(v2.maxv(v3))); - } - - for(int j = m_count; i < j; i++) - { - GSVector4 v0 = GSVector4(v[i + 0].m128[0]) / GSVector4(v[i + 0].GetQ());; - - minv = minv.minv(v0); - maxv = maxv.maxv(v0); - } - - mm = minv.xyxy(maxv); - */ - - // just can't beat the compiler generated scalar sse code with packed div or rcp - - mm.x = mm.y = +1e10; - mm.z = mm.w = -1e10; - - for(int j = m_count; i < j; i++) - { - float w = 1.0f / v[i].GetQ(); - - float x = v[i].t.x * w; - - if(x < mm.x) mm.x = x; - if(x > mm.z) mm.z = x; - - float y = v[i].t.y * w; - - if(y < mm.y) mm.y = y; - if(y > mm.w) mm.w = y; - } - } - } - else - { - mm = GSVector4(0.0f, 0.0f, 1.0f, 1.0f); - } - - GSVector4 v0 = GSVector4(vr); - GSVector4 v1 = v0.zwzw(); - - GSVector4 mmf = mm.floor(); - GSVector4 mask = mmf.xyxy() == mmf.zwzw(); - - wm[0] = GSVector4i(v0.blend8((mm - mmf) * v1, mask)); - - mm *= v1; - - wm[1] = GSVector4i(mm.sat(GSVector4::zero(), v1)); - wm[2] = GSVector4i(mm.sat(GSVector4(minu, minv, maxu, maxv))); - } - - GSVector4i v; - - switch(wms) - { - case CLAMP_REPEAT: - v = wm[0]; - if(v.x == 0 && v.z != w) v.z = w; // FIXME - vr.x = v.x; - vr.z = v.z; - break; - case CLAMP_CLAMP: - case CLAMP_REGION_CLAMP: - v = wm[wms]; - if(v.x > v.z) v.x = v.z; - vr.x = v.x; - vr.z = v.z; - break; - case CLAMP_REGION_REPEAT: - if(m_psrr) {vr.x = maxu; vr.z = vr.x + (minu + 1);} - //else {vr.x = 0; vr.z = w;} - break; - default: - __assume(0); - } - - switch(wmt) - { - case CLAMP_REPEAT: - v = wm[0]; - if(v.y == 0 && v.w != h) v.w = h; // FIXME - vr.y = v.y; - vr.w = v.w; - break; - case CLAMP_CLAMP: - case CLAMP_REGION_CLAMP: - v = wm[wmt]; - if(v.y > v.w) v.y = v.w; - vr.y = v.y; - vr.w = v.w; - break; - case CLAMP_REGION_REPEAT: - if(m_psrr) {vr.y = maxv; vr.w = vr.y + (minv + 1);} - //else {r.y = 0; r.w = w;} - break; - default: - __assume(0); - } - - r = vr; - - r.InflateRect(1, 1); // one more pixel because of bilinear filtering - - CSize bs = GSLocalMemory::m_psm[m_context->TEX0.PSM].bs; - CSize bsm(bs.cx - 1, bs.cy - 1); - - r.left = max(r.left & ~bsm.cx, 0); - r.right = min((r.right + bsm.cx) & ~bsm.cx, w); - - r.top = max(r.top & ~bsm.cy, 0); - r.bottom = min((r.bottom + bsm.cy) & ~bsm.cy, h); - } - - void VSync(int field) - { - __super::VSync(field); - - m_tc->IncAge(); - - m_skip = 0; - - if(m_reset) - { - m_tc->RemoveAll(); - - m_reset = false; - } - } - - void ResetDevice() - { - m_tc->RemoveAll(); - } - - bool GetOutput(int i, Texture& t) - { - GIFRegTEX0 TEX0; - - TEX0.TBP0 = DISPFB[i]->Block(); - TEX0.TBW = DISPFB[i]->FBW; - TEX0.PSM = DISPFB[i]->PSM; - - TRACE(_T("[%d] GetOutput %d %05x (%d)\n"), (int)m_perfmon.GetFrame(), i, (int)TEX0.TBP0, (int)TEX0.PSM); - - if(GSTextureCache::GSRenderTarget* rt = m_tc->GetRenderTarget(TEX0, m_width, m_height, true)) - { - t = rt->m_texture; - - if(s_dump) - { - CString str; - str.Format(_T("c:\\temp2\\_%05d_f%I64d_fr%d_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), i, (int)TEX0.TBP0, (int)TEX0.PSM); - if(s_save) rt->m_texture.Save(str); - } - - return true; - } - - return false; - } - - void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r) - { - TRACE(_T("[%d] InvalidateVideoMem %d,%d - %d,%d %05x (%d)\n"), (int)m_perfmon.GetFrame(), r.left, r.top, r.right, r.bottom, (int)BITBLTBUF.DBP, (int)BITBLTBUF.DPSM); - - m_tc->InvalidateVideoMem(BITBLTBUF, r); - } - - void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r) - { - TRACE(_T("[%d] InvalidateLocalMem %d,%d - %d,%d %05x (%d)\n"), (int)m_perfmon.GetFrame(), r.left, r.top, r.right, r.bottom, (int)BITBLTBUF.SBP, (int)BITBLTBUF.SPSM); - - m_tc->InvalidateLocalMem(BITBLTBUF, r); - } - - void Draw() - { - if(IsBadFrame(m_skip)) - { - return; - } - - GSDrawingEnvironment& env = m_env; - GSDrawingContext* context = m_context; - - GIFRegTEX0 TEX0; - - TEX0.TBP0 = context->FRAME.Block(); - TEX0.TBW = context->FRAME.FBW; - TEX0.PSM = context->FRAME.PSM; - - GSTextureCache::GSRenderTarget* rt = m_tc->GetRenderTarget(TEX0, m_width, m_height); - - TEX0.TBP0 = context->ZBUF.Block(); - TEX0.TBW = context->FRAME.FBW; - TEX0.PSM = context->ZBUF.PSM; - - GSTextureCache::GSDepthStencil* ds = m_tc->GetDepthStencil(TEX0, m_width, m_height); - - GSTextureCache::GSTexture* tex = NULL; - - if(PRIM->TME) - { - tex = m_tc->GetTexture(); - - if(!tex) return; - } - - if(s_dump) - { - CString str; - str.Format(_T("c:\\temp2\\_%05d_f%I64d_tex_%05x_%d_%d%d_%02x_%02x_%02x_%02x.dds"), - s_n++, m_perfmon.GetFrame(), (int)context->TEX0.TBP0, (int)context->TEX0.PSM, - (int)context->CLAMP.WMS, (int)context->CLAMP.WMT, - (int)context->CLAMP.MINU, (int)context->CLAMP.MAXU, - (int)context->CLAMP.MINV, (int)context->CLAMP.MAXV); - if(PRIM->TME) if(s_save) tex->m_texture.Save(str, true); - str.Format(_T("c:\\temp2\\_%05d_f%I64d_tpx_%05x_%d.dds"), s_n-1, m_perfmon.GetFrame(), context->TEX0.CBP, context->TEX0.CPSM); - if(PRIM->TME && tex->m_palette) if(s_save) tex->m_palette.Save(str, true); - str.Format(_T("c:\\temp2\\_%05d_f%I64d_rt0_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), context->FRAME.Block(), context->FRAME.PSM); - if(s_save) rt->m_texture.Save(str); - str.Format(_T("c:\\temp2\\_%05d_f%I64d_rz0_%05x_%d.bmp"), s_n-1, m_perfmon.GetFrame(), context->ZBUF.Block(), context->ZBUF.PSM); - if(s_savez) ds->m_texture.Save(str); - // if(s_savez) m_dev.SaveToFileD32S8X24(ds->m_texture, str); // TODO - // if(s_savez) m_dev.SaveToFileD24S8(ds->m_texture, str); // TODO - } - - int prim = PRIM->PRIM; - - if(!OverrideInput(prim, rt->m_texture, ds->m_texture, tex ? &tex->m_texture : NULL)) - { - return; - } - - Draw(prim, rt->m_texture, ds->m_texture, tex); - - OverrideOutput(); - - m_tc->InvalidateTextures(context->FRAME, context->ZBUF); - - if(s_dump) - { - CString str; - str.Format(_T("c:\\temp2\\_%05d_f%I64d_rt1_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), context->FRAME.Block(), context->FRAME.PSM); - if(s_save) rt->m_texture.Save(str); - str.Format(_T("c:\\temp2\\_%05d_f%I64d_rz1_%05x_%d.bmp"), s_n-1, m_perfmon.GetFrame(), context->ZBUF.Block(), context->ZBUF.PSM); - if(s_savez) ds->m_texture.Save(str); - // if(s_savez) m_dev.SaveToFileD32S8X24(ds->m_texture, str); // TODO - } - } - - virtual void Draw(int prim, Texture& rt, Texture& ds, typename GSTextureCache::GSTexture* tex) = 0; - - virtual bool OverrideInput(int& prim, Texture& rt, Texture& ds, Texture* t) - { - #pragma region ffxii pal video conversion - - if(m_game.title == CRC::FFXII && m_game.region == CRC::EU) - { - static DWORD* video = NULL; - static bool ok = false; - - if(prim == GS_POINTLIST && m_count >= 448*448 && m_count <= 448*512) - { - // incoming pixels are stored in columns, one column is 16x512, total res 448x512 or 448x454 - - if(!video) video = new DWORD[512*512]; - - for(int x = 0, i = 0, rows = m_count / 448; x < 448; x += 16) - { - DWORD* dst = &video[x]; - - for(int y = 0; y < rows; y++, dst += 512) - { - for(int j = 0; j < 16; j++, i++) - { - dst[j] = m_vertices[i].c0; - } - } - } - - ok = true; - - return false; - } - else if(prim == GS_LINELIST && m_count == 512*2 && ok) - { - // normally, this step would copy the video onto screen with 512 texture mapped horizontal lines, - // but we use the stored video data to create a new texture, and replace the lines with two triangles - - ok = false; - - m_dev.CreateTexture(*t, 512, 512); - - t->Update(CRect(0, 0, 448, 512), video, 512*4); - - m_vertices[0] = m_vertices[0]; - m_vertices[1] = m_vertices[1]; - m_vertices[2] = m_vertices[m_count - 2]; - m_vertices[3] = m_vertices[1]; - m_vertices[4] = m_vertices[2]; - m_vertices[5] = m_vertices[m_count - 1]; - - prim = GS_TRIANGLELIST; - m_count = 6; - - return true; - } - } - - #pragma endregion - - #pragma region ffx random battle transition (z buffer written directly, clear it now) - - if(m_game.title == CRC::FFX) - { - DWORD FBP = m_context->FRAME.Block(); - DWORD ZBP = m_context->ZBUF.Block(); - DWORD TBP = m_context->TEX0.TBP0; - - if((FBP == 0x00d00 || FBP == 0x00000) && ZBP == 0x02100 && PRIM->TME && TBP == 0x01a00 && m_context->TEX0.PSM == PSM_PSMCT16S) - { - m_dev.ClearDepth(ds, 0); - } - - return true; - } - - #pragma endregion - - #pragma region metal slug missing red channel fix - - if(m_game.title == CRC::MetalSlug6) - { - for(int i = 0, j = m_count; i < j; i++) - { - if(m_vertices[i].r == 0 && m_vertices[i].g != 0 && m_vertices[i].b != 0) - { - m_vertices[i].r = (m_vertices[i].g + m_vertices[i].b) / 2; - } - } - - return true; - } - - #pragma endregion - - #pragma region tomoyo after, clannad (palette uploaded in a point list, pure genius...) - - if(m_game.title == CRC::TomoyoAfter || m_game.title == CRC::Clannad) - { - if(prim == GS_POINTLIST && !PRIM->TME) - { - DWORD bp = m_context->FRAME.Block(); - DWORD bw = m_context->FRAME.FBW; - - if(bp >= 0x03f40 && (bp & 0x1f) == 0) - { - if(m_count == 16) - { - for(int i = 0; i < 16; i++) - { - m_vertices[i].a = m_vertices[i].a >= 0x80 ? 0xff : m_vertices[i].a * 2; - - m_mem.WritePixel32(i & 7, i >> 3, m_vertices[i].c0, bp, bw); - } - - m_mem.m_clut.Invalidate(); - - return false; - } - else if(m_count == 256) - { - for(int i = 0; i < 256; i++) - { - m_vertices[i].a = m_vertices[i].a >= 0x80 ? 0xff : m_vertices[i].a * 2; - - m_mem.WritePixel32(i & 15, i >> 4, m_vertices[i].c0, bp, bw); - } - - m_mem.m_clut.Invalidate(); - - return false; - } - else - { - ASSERT(0); - } - } - } - - return true; - } - - #pragma endregion - - return true; - } - - virtual void OverrideOutput() - { - #pragma region dbzbt2 palette readback (cannot detect yet, when fetching the texture later) - - if(m_game.title == CRC::DBZBT2) - { - DWORD FBP = m_context->FRAME.Block(); - DWORD TBP0 = m_context->TEX0.TBP0; - - if(PRIM->TME && (FBP == 0x03c00 && TBP0 == 0x03c80 || FBP == 0x03ac0 && TBP0 == 0x03b40)) - { - GIFRegBITBLTBUF BITBLTBUF; - - BITBLTBUF.SBP = FBP; - BITBLTBUF.SBW = 1; - BITBLTBUF.SPSM = PSM_PSMCT32; - - InvalidateLocalMem(BITBLTBUF, CRect(0, 0, 64, 64)); - } - } - - #pragma endregion - - #pragma region MajokkoALaMode2 palette readback - - if(m_game.title == CRC::MajokkoALaMode2) - { - DWORD FBP = m_context->FRAME.Block(); - - if(!PRIM->TME && FBP == 0x03f40) - { - GIFRegBITBLTBUF BITBLTBUF; - - BITBLTBUF.SBP = FBP; - BITBLTBUF.SBW = 1; - BITBLTBUF.SPSM = PSM_PSMCT32; - - InvalidateLocalMem(BITBLTBUF, CRect(0, 0, 16, 16)); - } - } - - #pragma endregion - } - - bool CanUpscale() - { - #pragma region dbzbt2 palette should stay 64 x 64 - - if(m_game.title == CRC::DBZBT2) - { - DWORD FBP = m_context->FRAME.Block(); - - if(FBP == 0x03c00 || FBP == 0x03ac0) - { - return false; - } - } - - #pragma endregion - - #pragma region MajokkoALaMode2 palette should stay 16 x 16 - - if(m_game.title == CRC::MajokkoALaMode2) - { - DWORD FBP = m_context->FRAME.Block(); - - if(FBP == 0x03f40) - { - return false; - } - } - - #pragma endregion - - #pragma region TalesOfAbyss full image blur and brightening - - if(m_game.title == CRC::TalesOfAbyss) - { - DWORD FBP = m_context->FRAME.Block(); - - if(FBP == 0x036e0 || FBP == 0x03560 || FBP == 0x038e0) - { - return false; - } - } - - #pragma endregion - - return __super::CanUpscale(); - } - -public: - GSRendererHW(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs, bool psrr) - : GSRendererT(base, mt, irq, nloophack, rs, psrr) - , m_width(1024) - , m_height(1024) - , m_skip(0) - , m_reset(false) - { - if(!m_nativeres) - { - m_width = AfxGetApp()->GetProfileInt(_T("Settings"), _T("resx"), m_width); - m_height = AfxGetApp()->GetProfileInt(_T("Settings"), _T("resy"), m_height); - } - - m_tc = new TextureCache(this); - } - - virtual ~GSRendererHW() - { - delete m_tc; - } - - void SetGameCRC(DWORD crc, int options) - { - __super::SetGameCRC(crc, options); - - if(m_game.title == CRC::JackieChanAdv) - { - m_width = 1280; // TODO: uses a 1280px wide 16 bit render target, but this only fixes half of the problem - } - } -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSRenderer.h" +#include "GSTextureCache.h" +#include "GSCrc.h" + +template +class GSRendererHW : public GSRendererT +{ + TextureCache* m_tc; + int m_width; + int m_height; + int m_skip; + bool m_reset; + +protected: + void Reset() + { + // TODO: GSreset can come from the main thread too => crash + // m_tc->RemoveAll(); + + m_reset = true; + + __super::Reset(); + } + + void MinMaxUV(int w, int h, CRect& r) + { + int wms = m_context->CLAMP.WMS; + int wmt = m_context->CLAMP.WMT; + + int minu = (int)m_context->CLAMP.MINU; + int minv = (int)m_context->CLAMP.MINV; + int maxu = (int)m_context->CLAMP.MAXU; + int maxv = (int)m_context->CLAMP.MAXV; + + GSVector4i vr = GSVector4i(0, 0, w, h); + + GSVector4i wm[3]; + + if(wms + wmt < 6) + { + GSVector4 mm; + + if(m_count < 100) + { + Vertex* v = m_vertices; + + GSVector4 minv(+1e10f); + GSVector4 maxv(-1e10f); + + int i = 0; + + if(PRIM->FST) + { + for(int j = m_count - 3; i < j; i += 4) + { + GSVector4 v0 = GSVector4(v[i + 0].m128[0]); + GSVector4 v1 = GSVector4(v[i + 1].m128[0]); + GSVector4 v2 = GSVector4(v[i + 2].m128[0]); + GSVector4 v3 = GSVector4(v[i + 3].m128[0]); + + minv = minv.minv((v0.minv(v1)).minv(v2.minv(v3))); + maxv = maxv.maxv((v0.maxv(v1)).maxv(v2.maxv(v3))); + } + + for(int j = m_count; i < j; i++) + { + GSVector4 v0 = GSVector4(v[i + 0].m128[0]); + + minv = minv.minv(v0); + maxv = maxv.maxv(v0); + } + + mm = minv.xyxy(maxv) * GSVector4(16 << m_context->TEX0.TW, 16 << m_context->TEX0.TH, 16 << m_context->TEX0.TW, 16 << m_context->TEX0.TH).rcpnr(); + } + else + { + /* + for(int j = m_count - 3; i < j; i += 4) + { + GSVector4 v0 = GSVector4(v[i + 0].m128[0]) / GSVector4(v[i + 0].GetQ()); + GSVector4 v1 = GSVector4(v[i + 1].m128[0]) / GSVector4(v[i + 1].GetQ()); + GSVector4 v2 = GSVector4(v[i + 2].m128[0]) / GSVector4(v[i + 2].GetQ()); + GSVector4 v3 = GSVector4(v[i + 3].m128[0]) / GSVector4(v[i + 3].GetQ()); + + minv = minv.minv((v0.minv(v1)).minv(v2.minv(v3))); + maxv = maxv.maxv((v0.maxv(v1)).maxv(v2.maxv(v3))); + } + + for(int j = m_count; i < j; i++) + { + GSVector4 v0 = GSVector4(v[i + 0].m128[0]) / GSVector4(v[i + 0].GetQ());; + + minv = minv.minv(v0); + maxv = maxv.maxv(v0); + } + + mm = minv.xyxy(maxv); + */ + + // just can't beat the compiler generated scalar sse code with packed div or rcp + + mm.x = mm.y = +1e10; + mm.z = mm.w = -1e10; + + for(int j = m_count; i < j; i++) + { + float w = 1.0f / v[i].GetQ(); + + float x = v[i].t.x * w; + + if(x < mm.x) mm.x = x; + if(x > mm.z) mm.z = x; + + float y = v[i].t.y * w; + + if(y < mm.y) mm.y = y; + if(y > mm.w) mm.w = y; + } + } + } + else + { + mm = GSVector4(0.0f, 0.0f, 1.0f, 1.0f); + } + + GSVector4 v0 = GSVector4(vr); + GSVector4 v1 = v0.zwzw(); + + GSVector4 mmf = mm.floor(); + GSVector4 mask = mmf.xyxy() == mmf.zwzw(); + + wm[0] = GSVector4i(v0.blend8((mm - mmf) * v1, mask)); + + mm *= v1; + + wm[1] = GSVector4i(mm.sat(GSVector4::zero(), v1)); + wm[2] = GSVector4i(mm.sat(GSVector4(minu, minv, maxu, maxv))); + } + + GSVector4i v; + + switch(wms) + { + case CLAMP_REPEAT: + v = wm[0]; + if(v.x == 0 && v.z != w) v.z = w; // FIXME + vr.x = v.x; + vr.z = v.z; + break; + case CLAMP_CLAMP: + case CLAMP_REGION_CLAMP: + v = wm[wms]; + if(v.x > v.z) v.x = v.z; + vr.x = v.x; + vr.z = v.z; + break; + case CLAMP_REGION_REPEAT: + if(m_psrr) {vr.x = maxu; vr.z = vr.x + (minu + 1);} + //else {vr.x = 0; vr.z = w;} + break; + default: + __assume(0); + } + + switch(wmt) + { + case CLAMP_REPEAT: + v = wm[0]; + if(v.y == 0 && v.w != h) v.w = h; // FIXME + vr.y = v.y; + vr.w = v.w; + break; + case CLAMP_CLAMP: + case CLAMP_REGION_CLAMP: + v = wm[wmt]; + if(v.y > v.w) v.y = v.w; + vr.y = v.y; + vr.w = v.w; + break; + case CLAMP_REGION_REPEAT: + if(m_psrr) {vr.y = maxv; vr.w = vr.y + (minv + 1);} + //else {r.y = 0; r.w = w;} + break; + default: + __assume(0); + } + + r = vr; + + r.InflateRect(1, 1); // one more pixel because of bilinear filtering + + CSize bs = GSLocalMemory::m_psm[m_context->TEX0.PSM].bs; + CSize bsm(bs.cx - 1, bs.cy - 1); + + r.left = max(r.left & ~bsm.cx, 0); + r.right = min((r.right + bsm.cx) & ~bsm.cx, w); + + r.top = max(r.top & ~bsm.cy, 0); + r.bottom = min((r.bottom + bsm.cy) & ~bsm.cy, h); + } + + void VSync(int field) + { + __super::VSync(field); + + m_tc->IncAge(); + + m_skip = 0; + + if(m_reset) + { + m_tc->RemoveAll(); + + m_reset = false; + } + } + + void ResetDevice() + { + m_tc->RemoveAll(); + } + + bool GetOutput(int i, Texture& t) + { + GIFRegTEX0 TEX0; + + TEX0.TBP0 = DISPFB[i]->Block(); + TEX0.TBW = DISPFB[i]->FBW; + TEX0.PSM = DISPFB[i]->PSM; + + TRACE(_T("[%d] GetOutput %d %05x (%d)\n"), (int)m_perfmon.GetFrame(), i, (int)TEX0.TBP0, (int)TEX0.PSM); + + if(GSTextureCache::GSRenderTarget* rt = m_tc->GetRenderTarget(TEX0, m_width, m_height, true)) + { + t = rt->m_texture; + + if(s_dump) + { + CString str; + str.Format(_T("c:\\temp2\\_%05d_f%I64d_fr%d_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), i, (int)TEX0.TBP0, (int)TEX0.PSM); + if(s_save) rt->m_texture.Save(str); + } + + return true; + } + + return false; + } + + void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r) + { + TRACE(_T("[%d] InvalidateVideoMem %d,%d - %d,%d %05x (%d)\n"), (int)m_perfmon.GetFrame(), r.left, r.top, r.right, r.bottom, (int)BITBLTBUF.DBP, (int)BITBLTBUF.DPSM); + + m_tc->InvalidateVideoMem(BITBLTBUF, r); + } + + void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r) + { + TRACE(_T("[%d] InvalidateLocalMem %d,%d - %d,%d %05x (%d)\n"), (int)m_perfmon.GetFrame(), r.left, r.top, r.right, r.bottom, (int)BITBLTBUF.SBP, (int)BITBLTBUF.SPSM); + + m_tc->InvalidateLocalMem(BITBLTBUF, r); + } + + void Draw() + { + if(IsBadFrame(m_skip)) + { + return; + } + + GSDrawingEnvironment& env = m_env; + GSDrawingContext* context = m_context; + + GIFRegTEX0 TEX0; + + TEX0.TBP0 = context->FRAME.Block(); + TEX0.TBW = context->FRAME.FBW; + TEX0.PSM = context->FRAME.PSM; + + GSTextureCache::GSRenderTarget* rt = m_tc->GetRenderTarget(TEX0, m_width, m_height); + + TEX0.TBP0 = context->ZBUF.Block(); + TEX0.TBW = context->FRAME.FBW; + TEX0.PSM = context->ZBUF.PSM; + + GSTextureCache::GSDepthStencil* ds = m_tc->GetDepthStencil(TEX0, m_width, m_height); + + GSTextureCache::GSTexture* tex = NULL; + + if(PRIM->TME) + { + tex = m_tc->GetTexture(); + + if(!tex) return; + } + + if(s_dump) + { + CString str; + str.Format(_T("c:\\temp2\\_%05d_f%I64d_tex_%05x_%d_%d%d_%02x_%02x_%02x_%02x.dds"), + s_n++, m_perfmon.GetFrame(), (int)context->TEX0.TBP0, (int)context->TEX0.PSM, + (int)context->CLAMP.WMS, (int)context->CLAMP.WMT, + (int)context->CLAMP.MINU, (int)context->CLAMP.MAXU, + (int)context->CLAMP.MINV, (int)context->CLAMP.MAXV); + if(PRIM->TME) if(s_save) tex->m_texture.Save(str, true); + str.Format(_T("c:\\temp2\\_%05d_f%I64d_tpx_%05x_%d.dds"), s_n-1, m_perfmon.GetFrame(), context->TEX0.CBP, context->TEX0.CPSM); + if(PRIM->TME && tex->m_palette) if(s_save) tex->m_palette.Save(str, true); + str.Format(_T("c:\\temp2\\_%05d_f%I64d_rt0_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), context->FRAME.Block(), context->FRAME.PSM); + if(s_save) rt->m_texture.Save(str); + str.Format(_T("c:\\temp2\\_%05d_f%I64d_rz0_%05x_%d.bmp"), s_n-1, m_perfmon.GetFrame(), context->ZBUF.Block(), context->ZBUF.PSM); + if(s_savez) ds->m_texture.Save(str); + // if(s_savez) m_dev.SaveToFileD32S8X24(ds->m_texture, str); // TODO + // if(s_savez) m_dev.SaveToFileD24S8(ds->m_texture, str); // TODO + } + + int prim = PRIM->PRIM; + + if(!OverrideInput(prim, rt->m_texture, ds->m_texture, tex ? &tex->m_texture : NULL)) + { + return; + } + + Draw(prim, rt->m_texture, ds->m_texture, tex); + + OverrideOutput(); + + m_tc->InvalidateTextures(context->FRAME, context->ZBUF); + + if(s_dump) + { + CString str; + str.Format(_T("c:\\temp2\\_%05d_f%I64d_rt1_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), context->FRAME.Block(), context->FRAME.PSM); + if(s_save) rt->m_texture.Save(str); + str.Format(_T("c:\\temp2\\_%05d_f%I64d_rz1_%05x_%d.bmp"), s_n-1, m_perfmon.GetFrame(), context->ZBUF.Block(), context->ZBUF.PSM); + if(s_savez) ds->m_texture.Save(str); + // if(s_savez) m_dev.SaveToFileD32S8X24(ds->m_texture, str); // TODO + } + } + + virtual void Draw(int prim, Texture& rt, Texture& ds, typename GSTextureCache::GSTexture* tex) = 0; + + virtual bool OverrideInput(int& prim, Texture& rt, Texture& ds, Texture* t) + { + #pragma region ffxii pal video conversion + + if(m_game.title == CRC::FFXII && m_game.region == CRC::EU) + { + static DWORD* video = NULL; + static bool ok = false; + + if(prim == GS_POINTLIST && m_count >= 448*448 && m_count <= 448*512) + { + // incoming pixels are stored in columns, one column is 16x512, total res 448x512 or 448x454 + + if(!video) video = new DWORD[512*512]; + + for(int x = 0, i = 0, rows = m_count / 448; x < 448; x += 16) + { + DWORD* dst = &video[x]; + + for(int y = 0; y < rows; y++, dst += 512) + { + for(int j = 0; j < 16; j++, i++) + { + dst[j] = m_vertices[i].c0; + } + } + } + + ok = true; + + return false; + } + else if(prim == GS_LINELIST && m_count == 512*2 && ok) + { + // normally, this step would copy the video onto screen with 512 texture mapped horizontal lines, + // but we use the stored video data to create a new texture, and replace the lines with two triangles + + ok = false; + + m_dev.CreateTexture(*t, 512, 512); + + t->Update(CRect(0, 0, 448, 512), video, 512*4); + + m_vertices[0] = m_vertices[0]; + m_vertices[1] = m_vertices[1]; + m_vertices[2] = m_vertices[m_count - 2]; + m_vertices[3] = m_vertices[1]; + m_vertices[4] = m_vertices[2]; + m_vertices[5] = m_vertices[m_count - 1]; + + prim = GS_TRIANGLELIST; + m_count = 6; + + return true; + } + } + + #pragma endregion + + #pragma region ffx random battle transition (z buffer written directly, clear it now) + + if(m_game.title == CRC::FFX) + { + DWORD FBP = m_context->FRAME.Block(); + DWORD ZBP = m_context->ZBUF.Block(); + DWORD TBP = m_context->TEX0.TBP0; + + if((FBP == 0x00d00 || FBP == 0x00000) && ZBP == 0x02100 && PRIM->TME && TBP == 0x01a00 && m_context->TEX0.PSM == PSM_PSMCT16S) + { + m_dev.ClearDepth(ds, 0); + } + + return true; + } + + #pragma endregion + + #pragma region metal slug missing red channel fix + + if(m_game.title == CRC::MetalSlug6) + { + for(int i = 0, j = m_count; i < j; i++) + { + if(m_vertices[i].r == 0 && m_vertices[i].g != 0 && m_vertices[i].b != 0) + { + m_vertices[i].r = (m_vertices[i].g + m_vertices[i].b) / 2; + } + } + + return true; + } + + #pragma endregion + + #pragma region tomoyo after, clannad (palette uploaded in a point list, pure genius...) + + if(m_game.title == CRC::TomoyoAfter || m_game.title == CRC::Clannad) + { + if(prim == GS_POINTLIST && !PRIM->TME) + { + DWORD bp = m_context->FRAME.Block(); + DWORD bw = m_context->FRAME.FBW; + + if(bp >= 0x03f40 && (bp & 0x1f) == 0) + { + if(m_count == 16) + { + for(int i = 0; i < 16; i++) + { + m_vertices[i].a = m_vertices[i].a >= 0x80 ? 0xff : m_vertices[i].a * 2; + + m_mem.WritePixel32(i & 7, i >> 3, m_vertices[i].c0, bp, bw); + } + + m_mem.m_clut.Invalidate(); + + return false; + } + else if(m_count == 256) + { + for(int i = 0; i < 256; i++) + { + m_vertices[i].a = m_vertices[i].a >= 0x80 ? 0xff : m_vertices[i].a * 2; + + m_mem.WritePixel32(i & 15, i >> 4, m_vertices[i].c0, bp, bw); + } + + m_mem.m_clut.Invalidate(); + + return false; + } + else + { + ASSERT(0); + } + } + } + + return true; + } + + #pragma endregion + + return true; + } + + virtual void OverrideOutput() + { + #pragma region dbzbt2 palette readback (cannot detect yet, when fetching the texture later) + + if(m_game.title == CRC::DBZBT2) + { + DWORD FBP = m_context->FRAME.Block(); + DWORD TBP0 = m_context->TEX0.TBP0; + + if(PRIM->TME && (FBP == 0x03c00 && TBP0 == 0x03c80 || FBP == 0x03ac0 && TBP0 == 0x03b40)) + { + GIFRegBITBLTBUF BITBLTBUF; + + BITBLTBUF.SBP = FBP; + BITBLTBUF.SBW = 1; + BITBLTBUF.SPSM = PSM_PSMCT32; + + InvalidateLocalMem(BITBLTBUF, CRect(0, 0, 64, 64)); + } + } + + #pragma endregion + + #pragma region MajokkoALaMode2 palette readback + + if(m_game.title == CRC::MajokkoALaMode2) + { + DWORD FBP = m_context->FRAME.Block(); + + if(!PRIM->TME && FBP == 0x03f40) + { + GIFRegBITBLTBUF BITBLTBUF; + + BITBLTBUF.SBP = FBP; + BITBLTBUF.SBW = 1; + BITBLTBUF.SPSM = PSM_PSMCT32; + + InvalidateLocalMem(BITBLTBUF, CRect(0, 0, 16, 16)); + } + } + + #pragma endregion + } + + bool CanUpscale() + { + #pragma region dbzbt2 palette should stay 64 x 64 + + if(m_game.title == CRC::DBZBT2) + { + DWORD FBP = m_context->FRAME.Block(); + + if(FBP == 0x03c00 || FBP == 0x03ac0) + { + return false; + } + } + + #pragma endregion + + #pragma region MajokkoALaMode2 palette should stay 16 x 16 + + if(m_game.title == CRC::MajokkoALaMode2) + { + DWORD FBP = m_context->FRAME.Block(); + + if(FBP == 0x03f40) + { + return false; + } + } + + #pragma endregion + + #pragma region TalesOfAbyss full image blur and brightening + + if(m_game.title == CRC::TalesOfAbyss) + { + DWORD FBP = m_context->FRAME.Block(); + + if(FBP == 0x036e0 || FBP == 0x03560 || FBP == 0x038e0) + { + return false; + } + } + + #pragma endregion + + return __super::CanUpscale(); + } + +public: + GSRendererHW(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs, bool psrr) + : GSRendererT(base, mt, irq, nloophack, rs, psrr) + , m_width(1024) + , m_height(1024) + , m_skip(0) + , m_reset(false) + { + if(!m_nativeres) + { + m_width = AfxGetApp()->GetProfileInt(_T("Settings"), _T("resx"), m_width); + m_height = AfxGetApp()->GetProfileInt(_T("Settings"), _T("resy"), m_height); + } + + m_tc = new TextureCache(this); + } + + virtual ~GSRendererHW() + { + delete m_tc; + } + + void SetGameCRC(DWORD crc, int options) + { + __super::SetGameCRC(crc, options); + + if(m_game.title == CRC::JackieChanAdv) + { + m_width = 1280; // TODO: uses a 1280px wide 16 bit render target, but this only fixes half of the problem + } + } +}; diff --git a/plugins/GSdx/GSRendererHW10.cpp b/plugins/GSdx/GSRendererHW10.cpp index 305c5f8c23..28447fbf44 100644 --- a/plugins/GSdx/GSRendererHW10.cpp +++ b/plugins/GSdx/GSRendererHW10.cpp @@ -1,586 +1,586 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GSRendererHW10.h" -#include "GSCrc.h" -#include "resource.h" - -GSRendererHW10::GSRendererHW10(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs) - : GSRendererHW(base, mt, irq, nloophack, rs, true) -{ - InitVertexKick(); -} - -bool GSRendererHW10::Create(LPCTSTR title) -{ - if(!__super::Create(title)) - return false; - - if(!m_tfx.Create(&m_dev)) - return false; - - // - - D3D10_DEPTH_STENCIL_DESC dsd; - - memset(&dsd, 0, sizeof(dsd)); - - dsd.DepthEnable = false; - dsd.StencilEnable = true; - dsd.StencilReadMask = 1; - dsd.StencilWriteMask = 1; - dsd.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS; - dsd.FrontFace.StencilPassOp = D3D10_STENCIL_OP_REPLACE; - dsd.FrontFace.StencilFailOp = D3D10_STENCIL_OP_KEEP; - dsd.FrontFace.StencilDepthFailOp = D3D10_STENCIL_OP_KEEP; - dsd.BackFace.StencilFunc = D3D10_COMPARISON_ALWAYS; - dsd.BackFace.StencilPassOp = D3D10_STENCIL_OP_REPLACE; - dsd.BackFace.StencilFailOp = D3D10_STENCIL_OP_KEEP; - dsd.BackFace.StencilDepthFailOp = D3D10_STENCIL_OP_KEEP; - - m_dev->CreateDepthStencilState(&dsd, &m_date.dss); - - D3D10_BLEND_DESC bd; - - memset(&bd, 0, sizeof(bd)); - - m_dev->CreateBlendState(&bd, &m_date.bs); - - // - - return true; -} - -template -void GSRendererHW10::VertexKick(bool skip) -{ - Vertex& dst = m_vl.AddTail(); - - dst.m128i[0] = m_v.m128i[0]; - dst.m128i[1] = m_v.m128i[1]; - - if(tme && fst) - { - GSVector4::storel(&dst.ST, m_v.GetUV()); - } - - DWORD count = 0; - - if(Vertex* v = DrawingKick(skip, count)) - { - GSVector4i scissor = m_context->scissor.dx10; - - #if _M_SSE >= 0x401 - - GSVector4i pmin, pmax, v0, v1, v2; - - switch(prim) - { - case GS_POINTLIST: - v0 = GSVector4i::load((int)v[0].p.xy).upl16(); - pmin = v0; - pmax = v0; - break; - case GS_LINELIST: - case GS_LINESTRIP: - case GS_SPRITE: - v0 = GSVector4i::load((int)v[0].p.xy); - v1 = GSVector4i::load((int)v[1].p.xy); - pmin = v0.min_u16(v1).upl16(); - pmax = v0.max_u16(v1).upl16(); - break; - case GS_TRIANGLELIST: - case GS_TRIANGLESTRIP: - case GS_TRIANGLEFAN: - v0 = GSVector4i::load((int)v[0].p.xy); - v1 = GSVector4i::load((int)v[1].p.xy); - v2 = GSVector4i::load((int)v[2].p.xy); - pmin = v0.min_u16(v1).min_u16(v2).upl16(); - pmax = v0.max_u16(v1).max_u16(v2).upl16(); - break; - } - - GSVector4i test = (pmax < scissor) | (pmin > scissor.zwxy()); - - if(test.mask() & 0xff) - { - return; - } - - #else - - switch(prim) - { - case GS_POINTLIST: - if(v[0].p.x < scissor.x - || v[0].p.x > scissor.z - || v[0].p.y < scissor.y - || v[0].p.y > scissor.w) - { - return; - } - break; - case GS_LINELIST: - case GS_LINESTRIP: - case GS_SPRITE: - if(v[0].p.x < scissor.x && v[1].p.x < scissor.x - || v[0].p.x > scissor.z && v[1].p.x > scissor.z - || v[0].p.y < scissor.y && v[1].p.y < scissor.y - || v[0].p.y > scissor.w && v[1].p.y > scissor.w) - { - return; - } - break; - case GS_TRIANGLELIST: - case GS_TRIANGLESTRIP: - case GS_TRIANGLEFAN: - if(v[0].p.x < scissor.x && v[1].p.x < scissor.x && v[2].p.x < scissor.x - || v[0].p.x > scissor.z && v[1].p.x > scissor.z && v[2].p.x > scissor.z - || v[0].p.y < scissor.y && v[1].p.y < scissor.y && v[2].p.y < scissor.y - || v[0].p.y > scissor.w && v[1].p.y > scissor.w && v[2].p.y > scissor.w) - { - return; - } - break; - } - - #endif - - m_count += count; - } -} - -void GSRendererHW10::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache::GSTexture* tex) -{ - GSDrawingEnvironment& env = m_env; - GSDrawingContext* context = m_context; -/* - if(s_dump) - { - TRACE(_T("\n")); - - TRACE(_T("PRIM = %d, ZMSK = %d, ZTE = %d, ZTST = %d, ATE = %d, ATST = %d, AFAIL = %d, AREF = %02x\n"), - PRIM->PRIM, context->ZBUF.ZMSK, - context->TEST.ZTE, context->TEST.ZTST, - context->TEST.ATE, context->TEST.ATST, context->TEST.AFAIL, context->TEST.AREF); - - for(int i = 0; i < m_count; i++) - { - TRACE(_T("[%d] %3.0f %3.0f %3.0f %3.0f\n"), i, (float)m_vertices[i].p.x / 16, (float)m_vertices[i].p.y / 16, (float)m_vertices[i].p.z, (float)m_vertices[i].a); - } - } -*/ - D3D10_PRIMITIVE_TOPOLOGY topology; - int prims = 0; - - switch(prim) - { - case GS_POINTLIST: - topology = D3D10_PRIMITIVE_TOPOLOGY_POINTLIST; - prims = m_count; - break; - case GS_LINELIST: - case GS_LINESTRIP: - case GS_SPRITE: - topology = D3D10_PRIMITIVE_TOPOLOGY_LINELIST; - prims = m_count / 2; - break; - case GS_TRIANGLELIST: - case GS_TRIANGLESTRIP: - case GS_TRIANGLEFAN: - topology = D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST; - prims = m_count / 3; - break; - default: - __assume(0); - } - - m_perfmon.Put(GSPerfMon::Prim, prims); - m_perfmon.Put(GSPerfMon::Draw, 1); - - // date - - SetupDATE(rt, ds); - - // - - m_dev.BeginScene(); - - // om - - GSTextureFX10::OMDepthStencilSelector om_dssel; - - om_dssel.zte = context->TEST.ZTE; - om_dssel.ztst = context->TEST.ZTST; - om_dssel.zwe = !context->ZBUF.ZMSK; - om_dssel.date = context->FRAME.PSM != PSM_PSMCT24 ? context->TEST.DATE : 0; - - GSTextureFX10::OMBlendSelector om_bsel; - - om_bsel.abe = PRIM->ABE || (prim == 1 || prim == 2) && PRIM->AA1; - om_bsel.a = context->ALPHA.A; - om_bsel.b = context->ALPHA.B; - om_bsel.c = context->ALPHA.C; - om_bsel.d = context->ALPHA.D; - om_bsel.wr = (context->FRAME.FBMSK & 0x000000ff) != 0x000000ff; - om_bsel.wg = (context->FRAME.FBMSK & 0x0000ff00) != 0x0000ff00; - om_bsel.wb = (context->FRAME.FBMSK & 0x00ff0000) != 0x00ff0000; - om_bsel.wa = (context->FRAME.FBMSK & 0xff000000) != 0xff000000; - - float bf = (float)(int)context->ALPHA.FIX / 0x80; - - // vs - - GSTextureFX10::VSSelector vs_sel; - - vs_sel.bpp = 0; - vs_sel.bppz = 0; - vs_sel.tme = PRIM->TME; - vs_sel.fst = PRIM->FST; - vs_sel.prim = prim; - - if(tex) - { - vs_sel.bpp = tex->m_bpp2; - } - - if(om_dssel.zte && om_dssel.ztst > 0 && om_dssel.zwe) - { - if(context->ZBUF.PSM == PSM_PSMZ24) - { - if(WrapZ(0xffffff)) - { - vs_sel.bppz = 1; - om_dssel.ztst = 1; - } - } - else if(context->ZBUF.PSM == PSM_PSMZ16 || context->ZBUF.PSM == PSM_PSMZ16S) - { - if(WrapZ(0xffff)) - { - vs_sel.bppz = 2; - om_dssel.ztst = 1; - } - } - } - - GSTextureFX10::VSConstantBuffer vs_cb; - - float sx = 2.0f * rt.m_scale.x / (rt.GetWidth() * 16); - float sy = 2.0f * rt.m_scale.y / (rt.GetHeight() * 16); - float ox = (float)(int)context->XYOFFSET.OFX; - float oy = (float)(int)context->XYOFFSET.OFY; - - vs_cb.VertexScale = GSVector4(sx, -sy, 1.0f / UINT_MAX, 0.0f); - vs_cb.VertexOffset = GSVector4(ox * sx + 1, -(oy * sy + 1), 0.0f, -1.0f); - vs_cb.TextureScale = GSVector2(1.0f, 1.0f); - - if(PRIM->TME && PRIM->FST) - { - vs_cb.TextureScale.x = 1.0f / (16 << context->TEX0.TW); - vs_cb.TextureScale.y = 1.0f / (16 << context->TEX0.TH); - } - - // gs - - GSTextureFX10::GSSelector gs_sel; - - gs_sel.iip = PRIM->IIP; - gs_sel.prim = GSUtil::GetPrimClass(prim); - - // ps - - GSTextureFX10::PSSelector ps_sel; - - ps_sel.fst = PRIM->FST; - ps_sel.wms = context->CLAMP.WMS; - ps_sel.wmt = context->CLAMP.WMT; - ps_sel.bpp = 0; - ps_sel.aem = env.TEXA.AEM; - ps_sel.tfx = context->TEX0.TFX; - ps_sel.tcc = context->TEX0.TCC; - ps_sel.ate = context->TEST.ATE; - ps_sel.atst = context->TEST.ATST; - ps_sel.fog = PRIM->FGE; - ps_sel.clr1 = om_bsel.abe && om_bsel.a == 1 && om_bsel.b == 2 && om_bsel.d == 1; - ps_sel.fba = context->FBA.FBA; - ps_sel.aout = context->FRAME.PSM == PSM_PSMCT16 || context->FRAME.PSM == PSM_PSMCT16S || (context->FRAME.FBMSK & 0xff000000) == 0x7f000000 ? 1 : 0; - - GSTextureFX10::PSSamplerSelector ps_ssel; - - ps_ssel.min = m_filter == 2 ? (context->TEX1.MMIN & 1) : m_filter; - ps_ssel.mag = m_filter == 2 ? (context->TEX1.MMAG & 1) : m_filter; - ps_ssel.tau = 0; - ps_ssel.tav = 0; - - GSTextureFX10::PSConstantBuffer ps_cb; - - ps_cb.FogColor = GSVector4(env.FOGCOL.FCR, env.FOGCOL.FCG, env.FOGCOL.FCB, 0) / 255.0f; - ps_cb.TA0 = (float)(int)env.TEXA.TA0 / 255; - ps_cb.TA1 = (float)(int)env.TEXA.TA1 / 255; - ps_cb.AREF = (float)(int)context->TEST.AREF / 255; - - if(context->TEST.ATST == 2 || context->TEST.ATST == 5) - { - ps_cb.AREF -= 0.9f/256; - } - else if(context->TEST.ATST == 3 || context->TEST.ATST == 6) - { - ps_cb.AREF += 0.9f/256; - } - - if(tex) - { - ps_sel.bpp = tex->m_bpp2; - - switch(context->CLAMP.WMS) - { - case 0: - ps_ssel.tau = 1; - break; - case 1: - ps_ssel.tau = 0; - break; - case 2: - ps_cb.MINU = ((float)(int)context->CLAMP.MINU + 0.5f) / (1 << context->TEX0.TW); - ps_cb.MAXU = ((float)(int)context->CLAMP.MAXU) / (1 << context->TEX0.TW); - ps_ssel.tau = 0; - break; - case 3: - ps_cb.UMSK = context->CLAMP.MINU; - ps_cb.UFIX = context->CLAMP.MAXU; - ps_ssel.tau = 1; - break; - default: - __assume(0); - } - - switch(context->CLAMP.WMT) - { - case 0: - ps_ssel.tav = 1; - break; - case 1: - ps_ssel.tav = 0; - break; - case 2: - ps_cb.MINV = ((float)(int)context->CLAMP.MINV + 0.5f) / (1 << context->TEX0.TH); - ps_cb.MAXV = ((float)(int)context->CLAMP.MAXV) / (1 << context->TEX0.TH); - ps_ssel.tav = 0; - break; - case 3: - ps_cb.VMSK = context->CLAMP.MINV; - ps_cb.VFIX = context->CLAMP.MAXV; - ps_ssel.tav = 1; - break; - default: - __assume(0); - } - - float w = (float)tex->m_texture.GetWidth(); - float h = (float)tex->m_texture.GetHeight(); - - ps_cb.WH = GSVector2(w, h); - ps_cb.rWrH = GSVector2(1.0f / w, 1.0f / h); - } - else - { - ps_sel.tfx = 4; - } - - // rs - - int w = rt.GetWidth(); - int h = rt.GetHeight(); - - CRect scissor = (CRect)GSVector4i(GSVector4(rt.m_scale).xyxy() * context->scissor.in) & CRect(0, 0, w, h); - - // - - m_tfx.SetupOM(om_dssel, om_bsel, bf, rt, ds); - m_tfx.SetupIA(m_vertices, m_count, topology); - m_tfx.SetupVS(vs_sel, &vs_cb); - m_tfx.SetupGS(gs_sel); - m_tfx.SetupPS(ps_sel, &ps_cb, ps_ssel, - tex ? (ID3D10ShaderResourceView*)tex->m_texture : NULL, - tex ? (ID3D10ShaderResourceView*)tex->m_palette : NULL); - m_tfx.SetupRS(w, h, scissor); - - // draw - - if(context->TEST.DoFirstPass()) - { - m_tfx.Draw(); - } - - if(context->TEST.DoSecondPass()) - { - ASSERT(!env.PABE.PABE); - - static const DWORD iatst[] = {1, 0, 5, 6, 7, 2, 3, 4}; - - ps_sel.atst = iatst[ps_sel.atst]; - - m_tfx.UpdatePS(ps_sel, &ps_cb, ps_ssel); - - bool z = om_dssel.zwe; - bool r = om_bsel.wr; - bool g = om_bsel.wg; - bool b = om_bsel.wb; - bool a = om_bsel.wa; - - switch(context->TEST.AFAIL) - { - case 0: z = r = g = b = a = false; break; // none - case 1: z = false; break; // rgba - case 2: r = g = b = a = false; break; // z - case 3: z = a = false; break; // rgb - default: __assume(0); - } - - if(z || r || g || b || a) - { - om_dssel.zwe = z; - om_bsel.wr = r; - om_bsel.wg = g; - om_bsel.wb = b; - om_bsel.wa = a; - - m_tfx.UpdateOM(om_dssel, om_bsel, bf); - - m_tfx.Draw(); - } - } - - m_dev.EndScene(); -} - -bool GSRendererHW10::WrapZ(DWORD maxz) -{ - // should only run once if z values are in the z buffer range - - for(int i = 0, j = m_count; i < j; i++) - { - if(m_vertices[i].p.z <= maxz) - { - return false; - } - } - - return true; -} - -void GSRendererHW10::SetupDATE(Texture& rt, Texture& ds) -{ - if(!m_context->TEST.DATE) return; // || (::GetAsyncKeyState(VK_CONTROL) & 0x8000) - - // sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows - - GSVector4 mm; - - // TODO - - mm = GSVector4(-1, -1, 1, 1); -/* - MinMaxXY(mm); - - int w = rt.GetWidth(); - int h = rt.GetHeight(); - - float sx = 2.0f * rt.m_scale.x / (w * 16); - float sy = 2.0f * rt.m_scale.y / (h * 16); - float ox = (float)(int)m_context->XYOFFSET.OFX; - float oy = (float)(int)m_context->XYOFFSET.OFY; - - mm.x = (mm.x - ox) * sx - 1; - mm.y = (mm.y - oy) * sy - 1; - mm.z = (mm.z - ox) * sx - 1; - mm.w = (mm.w - oy) * sy - 1; - - if(mm.x < -1) mm.x = -1; - if(mm.y < -1) mm.y = -1; - if(mm.z > +1) mm.z = +1; - if(mm.w > +1) mm.w = +1; -*/ - GSVector4 uv = (mm + 1.0f) / 2.0f; - - // - - m_dev.BeginScene(); - - // om - - GSTexture10 tmp; - - m_dev.CreateRenderTarget(tmp, rt.GetWidth(), rt.GetHeight()); - - m_dev.OMSetRenderTargets(tmp, ds); - m_dev.OMSetDepthStencilState(m_date.dss, 1); - m_dev.OMSetBlendState(m_date.bs, 0); - - m_dev->ClearDepthStencilView(ds, D3D10_CLEAR_STENCIL, 0, 0); - - // ia - - GSVertexPT1 vertices[] = - { - {GSVector4(mm.x, -mm.y, 0.5f, 1.0f), GSVector2(uv.x, uv.y)}, - {GSVector4(mm.z, -mm.y, 0.5f, 1.0f), GSVector2(uv.z, uv.y)}, - {GSVector4(mm.x, -mm.w, 0.5f, 1.0f), GSVector2(uv.x, uv.w)}, - {GSVector4(mm.z, -mm.w, 0.5f, 1.0f), GSVector2(uv.z, uv.w)}, - }; - - D3D10_BOX box = {0, 0, 0, sizeof(vertices), 1, 1}; - m_dev->UpdateSubresource(m_dev.m_convert.vb, 0, &box, vertices, 0, 0); - - m_dev.IASetVertexBuffer(m_dev.m_convert.vb, sizeof(vertices[0])); - m_dev.IASetInputLayout(m_dev.m_convert.il); - m_dev.IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - - // vs - - m_dev.VSSetShader(m_dev.m_convert.vs, NULL); - - // gs - - m_dev.GSSetShader(NULL); - - // ps - - m_dev.PSSetShaderResources(rt, NULL); - m_dev.PSSetShader(m_dev.m_convert.ps[m_context->TEST.DATM ? 2 : 3], NULL); - m_dev.PSSetSamplerState(m_dev.m_convert.pt, NULL); - - // rs - - m_dev.RSSet(tmp.GetWidth(), tmp.GetHeight()); - - // set - - m_dev.DrawPrimitive(countof(vertices)); - - // - - m_dev.EndScene(); - - m_dev.Recycle(tmp); -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSRendererHW10.h" +#include "GSCrc.h" +#include "resource.h" + +GSRendererHW10::GSRendererHW10(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs) + : GSRendererHW(base, mt, irq, nloophack, rs, true) +{ + InitVertexKick(); +} + +bool GSRendererHW10::Create(LPCTSTR title) +{ + if(!__super::Create(title)) + return false; + + if(!m_tfx.Create(&m_dev)) + return false; + + // + + D3D10_DEPTH_STENCIL_DESC dsd; + + memset(&dsd, 0, sizeof(dsd)); + + dsd.DepthEnable = false; + dsd.StencilEnable = true; + dsd.StencilReadMask = 1; + dsd.StencilWriteMask = 1; + dsd.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS; + dsd.FrontFace.StencilPassOp = D3D10_STENCIL_OP_REPLACE; + dsd.FrontFace.StencilFailOp = D3D10_STENCIL_OP_KEEP; + dsd.FrontFace.StencilDepthFailOp = D3D10_STENCIL_OP_KEEP; + dsd.BackFace.StencilFunc = D3D10_COMPARISON_ALWAYS; + dsd.BackFace.StencilPassOp = D3D10_STENCIL_OP_REPLACE; + dsd.BackFace.StencilFailOp = D3D10_STENCIL_OP_KEEP; + dsd.BackFace.StencilDepthFailOp = D3D10_STENCIL_OP_KEEP; + + m_dev->CreateDepthStencilState(&dsd, &m_date.dss); + + D3D10_BLEND_DESC bd; + + memset(&bd, 0, sizeof(bd)); + + m_dev->CreateBlendState(&bd, &m_date.bs); + + // + + return true; +} + +template +void GSRendererHW10::VertexKick(bool skip) +{ + Vertex& dst = m_vl.AddTail(); + + dst.m128i[0] = m_v.m128i[0]; + dst.m128i[1] = m_v.m128i[1]; + + if(tme && fst) + { + GSVector4::storel(&dst.ST, m_v.GetUV()); + } + + DWORD count = 0; + + if(Vertex* v = DrawingKick(skip, count)) + { + GSVector4i scissor = m_context->scissor.dx10; + + #if _M_SSE >= 0x401 + + GSVector4i pmin, pmax, v0, v1, v2; + + switch(prim) + { + case GS_POINTLIST: + v0 = GSVector4i::load((int)v[0].p.xy).upl16(); + pmin = v0; + pmax = v0; + break; + case GS_LINELIST: + case GS_LINESTRIP: + case GS_SPRITE: + v0 = GSVector4i::load((int)v[0].p.xy); + v1 = GSVector4i::load((int)v[1].p.xy); + pmin = v0.min_u16(v1).upl16(); + pmax = v0.max_u16(v1).upl16(); + break; + case GS_TRIANGLELIST: + case GS_TRIANGLESTRIP: + case GS_TRIANGLEFAN: + v0 = GSVector4i::load((int)v[0].p.xy); + v1 = GSVector4i::load((int)v[1].p.xy); + v2 = GSVector4i::load((int)v[2].p.xy); + pmin = v0.min_u16(v1).min_u16(v2).upl16(); + pmax = v0.max_u16(v1).max_u16(v2).upl16(); + break; + } + + GSVector4i test = (pmax < scissor) | (pmin > scissor.zwxy()); + + if(test.mask() & 0xff) + { + return; + } + + #else + + switch(prim) + { + case GS_POINTLIST: + if(v[0].p.x < scissor.x + || v[0].p.x > scissor.z + || v[0].p.y < scissor.y + || v[0].p.y > scissor.w) + { + return; + } + break; + case GS_LINELIST: + case GS_LINESTRIP: + case GS_SPRITE: + if(v[0].p.x < scissor.x && v[1].p.x < scissor.x + || v[0].p.x > scissor.z && v[1].p.x > scissor.z + || v[0].p.y < scissor.y && v[1].p.y < scissor.y + || v[0].p.y > scissor.w && v[1].p.y > scissor.w) + { + return; + } + break; + case GS_TRIANGLELIST: + case GS_TRIANGLESTRIP: + case GS_TRIANGLEFAN: + if(v[0].p.x < scissor.x && v[1].p.x < scissor.x && v[2].p.x < scissor.x + || v[0].p.x > scissor.z && v[1].p.x > scissor.z && v[2].p.x > scissor.z + || v[0].p.y < scissor.y && v[1].p.y < scissor.y && v[2].p.y < scissor.y + || v[0].p.y > scissor.w && v[1].p.y > scissor.w && v[2].p.y > scissor.w) + { + return; + } + break; + } + + #endif + + m_count += count; + } +} + +void GSRendererHW10::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache::GSTexture* tex) +{ + GSDrawingEnvironment& env = m_env; + GSDrawingContext* context = m_context; +/* + if(s_dump) + { + TRACE(_T("\n")); + + TRACE(_T("PRIM = %d, ZMSK = %d, ZTE = %d, ZTST = %d, ATE = %d, ATST = %d, AFAIL = %d, AREF = %02x\n"), + PRIM->PRIM, context->ZBUF.ZMSK, + context->TEST.ZTE, context->TEST.ZTST, + context->TEST.ATE, context->TEST.ATST, context->TEST.AFAIL, context->TEST.AREF); + + for(int i = 0; i < m_count; i++) + { + TRACE(_T("[%d] %3.0f %3.0f %3.0f %3.0f\n"), i, (float)m_vertices[i].p.x / 16, (float)m_vertices[i].p.y / 16, (float)m_vertices[i].p.z, (float)m_vertices[i].a); + } + } +*/ + D3D10_PRIMITIVE_TOPOLOGY topology; + int prims = 0; + + switch(prim) + { + case GS_POINTLIST: + topology = D3D10_PRIMITIVE_TOPOLOGY_POINTLIST; + prims = m_count; + break; + case GS_LINELIST: + case GS_LINESTRIP: + case GS_SPRITE: + topology = D3D10_PRIMITIVE_TOPOLOGY_LINELIST; + prims = m_count / 2; + break; + case GS_TRIANGLELIST: + case GS_TRIANGLESTRIP: + case GS_TRIANGLEFAN: + topology = D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + prims = m_count / 3; + break; + default: + __assume(0); + } + + m_perfmon.Put(GSPerfMon::Prim, prims); + m_perfmon.Put(GSPerfMon::Draw, 1); + + // date + + SetupDATE(rt, ds); + + // + + m_dev.BeginScene(); + + // om + + GSTextureFX10::OMDepthStencilSelector om_dssel; + + om_dssel.zte = context->TEST.ZTE; + om_dssel.ztst = context->TEST.ZTST; + om_dssel.zwe = !context->ZBUF.ZMSK; + om_dssel.date = context->FRAME.PSM != PSM_PSMCT24 ? context->TEST.DATE : 0; + + GSTextureFX10::OMBlendSelector om_bsel; + + om_bsel.abe = PRIM->ABE || (prim == 1 || prim == 2) && PRIM->AA1; + om_bsel.a = context->ALPHA.A; + om_bsel.b = context->ALPHA.B; + om_bsel.c = context->ALPHA.C; + om_bsel.d = context->ALPHA.D; + om_bsel.wr = (context->FRAME.FBMSK & 0x000000ff) != 0x000000ff; + om_bsel.wg = (context->FRAME.FBMSK & 0x0000ff00) != 0x0000ff00; + om_bsel.wb = (context->FRAME.FBMSK & 0x00ff0000) != 0x00ff0000; + om_bsel.wa = (context->FRAME.FBMSK & 0xff000000) != 0xff000000; + + float bf = (float)(int)context->ALPHA.FIX / 0x80; + + // vs + + GSTextureFX10::VSSelector vs_sel; + + vs_sel.bpp = 0; + vs_sel.bppz = 0; + vs_sel.tme = PRIM->TME; + vs_sel.fst = PRIM->FST; + vs_sel.prim = prim; + + if(tex) + { + vs_sel.bpp = tex->m_bpp2; + } + + if(om_dssel.zte && om_dssel.ztst > 0 && om_dssel.zwe) + { + if(context->ZBUF.PSM == PSM_PSMZ24) + { + if(WrapZ(0xffffff)) + { + vs_sel.bppz = 1; + om_dssel.ztst = 1; + } + } + else if(context->ZBUF.PSM == PSM_PSMZ16 || context->ZBUF.PSM == PSM_PSMZ16S) + { + if(WrapZ(0xffff)) + { + vs_sel.bppz = 2; + om_dssel.ztst = 1; + } + } + } + + GSTextureFX10::VSConstantBuffer vs_cb; + + float sx = 2.0f * rt.m_scale.x / (rt.GetWidth() * 16); + float sy = 2.0f * rt.m_scale.y / (rt.GetHeight() * 16); + float ox = (float)(int)context->XYOFFSET.OFX; + float oy = (float)(int)context->XYOFFSET.OFY; + + vs_cb.VertexScale = GSVector4(sx, -sy, 1.0f / UINT_MAX, 0.0f); + vs_cb.VertexOffset = GSVector4(ox * sx + 1, -(oy * sy + 1), 0.0f, -1.0f); + vs_cb.TextureScale = GSVector2(1.0f, 1.0f); + + if(PRIM->TME && PRIM->FST) + { + vs_cb.TextureScale.x = 1.0f / (16 << context->TEX0.TW); + vs_cb.TextureScale.y = 1.0f / (16 << context->TEX0.TH); + } + + // gs + + GSTextureFX10::GSSelector gs_sel; + + gs_sel.iip = PRIM->IIP; + gs_sel.prim = GSUtil::GetPrimClass(prim); + + // ps + + GSTextureFX10::PSSelector ps_sel; + + ps_sel.fst = PRIM->FST; + ps_sel.wms = context->CLAMP.WMS; + ps_sel.wmt = context->CLAMP.WMT; + ps_sel.bpp = 0; + ps_sel.aem = env.TEXA.AEM; + ps_sel.tfx = context->TEX0.TFX; + ps_sel.tcc = context->TEX0.TCC; + ps_sel.ate = context->TEST.ATE; + ps_sel.atst = context->TEST.ATST; + ps_sel.fog = PRIM->FGE; + ps_sel.clr1 = om_bsel.abe && om_bsel.a == 1 && om_bsel.b == 2 && om_bsel.d == 1; + ps_sel.fba = context->FBA.FBA; + ps_sel.aout = context->FRAME.PSM == PSM_PSMCT16 || context->FRAME.PSM == PSM_PSMCT16S || (context->FRAME.FBMSK & 0xff000000) == 0x7f000000 ? 1 : 0; + + GSTextureFX10::PSSamplerSelector ps_ssel; + + ps_ssel.min = m_filter == 2 ? (context->TEX1.MMIN & 1) : m_filter; + ps_ssel.mag = m_filter == 2 ? (context->TEX1.MMAG & 1) : m_filter; + ps_ssel.tau = 0; + ps_ssel.tav = 0; + + GSTextureFX10::PSConstantBuffer ps_cb; + + ps_cb.FogColor = GSVector4(env.FOGCOL.FCR, env.FOGCOL.FCG, env.FOGCOL.FCB, 0) / 255.0f; + ps_cb.TA0 = (float)(int)env.TEXA.TA0 / 255; + ps_cb.TA1 = (float)(int)env.TEXA.TA1 / 255; + ps_cb.AREF = (float)(int)context->TEST.AREF / 255; + + if(context->TEST.ATST == 2 || context->TEST.ATST == 5) + { + ps_cb.AREF -= 0.9f/256; + } + else if(context->TEST.ATST == 3 || context->TEST.ATST == 6) + { + ps_cb.AREF += 0.9f/256; + } + + if(tex) + { + ps_sel.bpp = tex->m_bpp2; + + switch(context->CLAMP.WMS) + { + case 0: + ps_ssel.tau = 1; + break; + case 1: + ps_ssel.tau = 0; + break; + case 2: + ps_cb.MINU = ((float)(int)context->CLAMP.MINU + 0.5f) / (1 << context->TEX0.TW); + ps_cb.MAXU = ((float)(int)context->CLAMP.MAXU) / (1 << context->TEX0.TW); + ps_ssel.tau = 0; + break; + case 3: + ps_cb.UMSK = context->CLAMP.MINU; + ps_cb.UFIX = context->CLAMP.MAXU; + ps_ssel.tau = 1; + break; + default: + __assume(0); + } + + switch(context->CLAMP.WMT) + { + case 0: + ps_ssel.tav = 1; + break; + case 1: + ps_ssel.tav = 0; + break; + case 2: + ps_cb.MINV = ((float)(int)context->CLAMP.MINV + 0.5f) / (1 << context->TEX0.TH); + ps_cb.MAXV = ((float)(int)context->CLAMP.MAXV) / (1 << context->TEX0.TH); + ps_ssel.tav = 0; + break; + case 3: + ps_cb.VMSK = context->CLAMP.MINV; + ps_cb.VFIX = context->CLAMP.MAXV; + ps_ssel.tav = 1; + break; + default: + __assume(0); + } + + float w = (float)tex->m_texture.GetWidth(); + float h = (float)tex->m_texture.GetHeight(); + + ps_cb.WH = GSVector2(w, h); + ps_cb.rWrH = GSVector2(1.0f / w, 1.0f / h); + } + else + { + ps_sel.tfx = 4; + } + + // rs + + int w = rt.GetWidth(); + int h = rt.GetHeight(); + + CRect scissor = (CRect)GSVector4i(GSVector4(rt.m_scale).xyxy() * context->scissor.in) & CRect(0, 0, w, h); + + // + + m_tfx.SetupOM(om_dssel, om_bsel, bf, rt, ds); + m_tfx.SetupIA(m_vertices, m_count, topology); + m_tfx.SetupVS(vs_sel, &vs_cb); + m_tfx.SetupGS(gs_sel); + m_tfx.SetupPS(ps_sel, &ps_cb, ps_ssel, + tex ? (ID3D10ShaderResourceView*)tex->m_texture : NULL, + tex ? (ID3D10ShaderResourceView*)tex->m_palette : NULL); + m_tfx.SetupRS(w, h, scissor); + + // draw + + if(context->TEST.DoFirstPass()) + { + m_tfx.Draw(); + } + + if(context->TEST.DoSecondPass()) + { + ASSERT(!env.PABE.PABE); + + static const DWORD iatst[] = {1, 0, 5, 6, 7, 2, 3, 4}; + + ps_sel.atst = iatst[ps_sel.atst]; + + m_tfx.UpdatePS(ps_sel, &ps_cb, ps_ssel); + + bool z = om_dssel.zwe; + bool r = om_bsel.wr; + bool g = om_bsel.wg; + bool b = om_bsel.wb; + bool a = om_bsel.wa; + + switch(context->TEST.AFAIL) + { + case 0: z = r = g = b = a = false; break; // none + case 1: z = false; break; // rgba + case 2: r = g = b = a = false; break; // z + case 3: z = a = false; break; // rgb + default: __assume(0); + } + + if(z || r || g || b || a) + { + om_dssel.zwe = z; + om_bsel.wr = r; + om_bsel.wg = g; + om_bsel.wb = b; + om_bsel.wa = a; + + m_tfx.UpdateOM(om_dssel, om_bsel, bf); + + m_tfx.Draw(); + } + } + + m_dev.EndScene(); +} + +bool GSRendererHW10::WrapZ(DWORD maxz) +{ + // should only run once if z values are in the z buffer range + + for(int i = 0, j = m_count; i < j; i++) + { + if(m_vertices[i].p.z <= maxz) + { + return false; + } + } + + return true; +} + +void GSRendererHW10::SetupDATE(Texture& rt, Texture& ds) +{ + if(!m_context->TEST.DATE) return; // || (::GetAsyncKeyState(VK_CONTROL) & 0x8000) + + // sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows + + GSVector4 mm; + + // TODO + + mm = GSVector4(-1, -1, 1, 1); +/* + MinMaxXY(mm); + + int w = rt.GetWidth(); + int h = rt.GetHeight(); + + float sx = 2.0f * rt.m_scale.x / (w * 16); + float sy = 2.0f * rt.m_scale.y / (h * 16); + float ox = (float)(int)m_context->XYOFFSET.OFX; + float oy = (float)(int)m_context->XYOFFSET.OFY; + + mm.x = (mm.x - ox) * sx - 1; + mm.y = (mm.y - oy) * sy - 1; + mm.z = (mm.z - ox) * sx - 1; + mm.w = (mm.w - oy) * sy - 1; + + if(mm.x < -1) mm.x = -1; + if(mm.y < -1) mm.y = -1; + if(mm.z > +1) mm.z = +1; + if(mm.w > +1) mm.w = +1; +*/ + GSVector4 uv = (mm + 1.0f) / 2.0f; + + // + + m_dev.BeginScene(); + + // om + + GSTexture10 tmp; + + m_dev.CreateRenderTarget(tmp, rt.GetWidth(), rt.GetHeight()); + + m_dev.OMSetRenderTargets(tmp, ds); + m_dev.OMSetDepthStencilState(m_date.dss, 1); + m_dev.OMSetBlendState(m_date.bs, 0); + + m_dev->ClearDepthStencilView(ds, D3D10_CLEAR_STENCIL, 0, 0); + + // ia + + GSVertexPT1 vertices[] = + { + {GSVector4(mm.x, -mm.y, 0.5f, 1.0f), GSVector2(uv.x, uv.y)}, + {GSVector4(mm.z, -mm.y, 0.5f, 1.0f), GSVector2(uv.z, uv.y)}, + {GSVector4(mm.x, -mm.w, 0.5f, 1.0f), GSVector2(uv.x, uv.w)}, + {GSVector4(mm.z, -mm.w, 0.5f, 1.0f), GSVector2(uv.z, uv.w)}, + }; + + D3D10_BOX box = {0, 0, 0, sizeof(vertices), 1, 1}; + m_dev->UpdateSubresource(m_dev.m_convert.vb, 0, &box, vertices, 0, 0); + + m_dev.IASetVertexBuffer(m_dev.m_convert.vb, sizeof(vertices[0])); + m_dev.IASetInputLayout(m_dev.m_convert.il); + m_dev.IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + + // vs + + m_dev.VSSetShader(m_dev.m_convert.vs, NULL); + + // gs + + m_dev.GSSetShader(NULL); + + // ps + + m_dev.PSSetShaderResources(rt, NULL); + m_dev.PSSetShader(m_dev.m_convert.ps[m_context->TEST.DATM ? 2 : 3], NULL); + m_dev.PSSetSamplerState(m_dev.m_convert.pt, NULL); + + // rs + + m_dev.RSSet(tmp.GetWidth(), tmp.GetHeight()); + + // set + + m_dev.DrawPrimitive(countof(vertices)); + + // + + m_dev.EndScene(); + + m_dev.Recycle(tmp); +} diff --git a/plugins/GSdx/GSRendererHW10.h b/plugins/GSdx/GSRendererHW10.h index 03ae5935af..b1b069ee22 100644 --- a/plugins/GSdx/GSRendererHW10.h +++ b/plugins/GSdx/GSRendererHW10.h @@ -1,56 +1,56 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSRendererHW.h" -#include "GSVertexHW.h" -#include "GSTextureCache10.h" -#include "GSTextureFX10.h" - -class GSRendererHW10 : public GSRendererHW -{ - typedef GSDevice10 Device; - typedef GSVertexHW10 Vertex; - typedef GSTextureCache10 TextureCache; - - bool WrapZ(DWORD maxz); - -protected: - GSTextureFX10 m_tfx; - - void Draw(int prim, Texture& rt, Texture& ds, GSTextureCache::GSTexture* tex); - - struct - { - CComPtr dss; - CComPtr bs; - } m_date; - - void SetupDATE(Texture& rt, Texture& ds); - -public: - GSRendererHW10(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs); - - bool Create(LPCTSTR title); - - template void VertexKick(bool skip); +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSRendererHW.h" +#include "GSVertexHW.h" +#include "GSTextureCache10.h" +#include "GSTextureFX10.h" + +class GSRendererHW10 : public GSRendererHW +{ + typedef GSDevice10 Device; + typedef GSVertexHW10 Vertex; + typedef GSTextureCache10 TextureCache; + + bool WrapZ(DWORD maxz); + +protected: + GSTextureFX10 m_tfx; + + void Draw(int prim, Texture& rt, Texture& ds, GSTextureCache::GSTexture* tex); + + struct + { + CComPtr dss; + CComPtr bs; + } m_date; + + void SetupDATE(Texture& rt, Texture& ds); + +public: + GSRendererHW10(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs); + + bool Create(LPCTSTR title); + + template void VertexKick(bool skip); }; \ No newline at end of file diff --git a/plugins/GSdx/GSRendererHW9.cpp b/plugins/GSdx/GSRendererHW9.cpp index 21950cdab3..009d924f81 100644 --- a/plugins/GSdx/GSRendererHW9.cpp +++ b/plugins/GSdx/GSRendererHW9.cpp @@ -1,594 +1,594 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GSRendererHW9.h" -#include "GSCrc.h" -#include "resource.h" - -GSRendererHW9::GSRendererHW9(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs) - : GSRendererHW(base, mt, irq, nloophack, rs, false) -{ - m_fba.enabled = !!AfxGetApp()->GetProfileInt(_T("Settings"), _T("fba"), TRUE); - m_logz = !!AfxGetApp()->GetProfileInt(_T("Settings"), _T("logz"), FALSE); - - InitVertexKick(); -} - -bool GSRendererHW9::Create(LPCTSTR title) -{ - if(!__super::Create(title)) - return false; - - if(!m_tfx.Create(&m_dev)) - return false; - - // - - memset(&m_date.dss, 0, sizeof(m_date.dss)); - - m_date.dss.StencilEnable = true; - m_date.dss.StencilReadMask = 1; - m_date.dss.StencilWriteMask = 1; - m_date.dss.StencilFunc = D3DCMP_ALWAYS; - m_date.dss.StencilPassOp = D3DSTENCILOP_REPLACE; - - memset(&m_date.bs, 0, sizeof(m_date.bs)); - - // - - memset(&m_fba.dss, 0, sizeof(m_fba.dss)); - - m_fba.dss.StencilEnable = true; - m_fba.dss.StencilReadMask = 2; - m_fba.dss.StencilWriteMask = 2; - m_fba.dss.StencilFunc = D3DCMP_EQUAL; - m_fba.dss.StencilPassOp = D3DSTENCILOP_ZERO; - m_fba.dss.StencilFailOp = D3DSTENCILOP_ZERO; - m_fba.dss.StencilDepthFailOp = D3DSTENCILOP_ZERO; - - memset(&m_fba.bs, 0, sizeof(m_fba.bs)); - - m_fba.bs.RenderTargetWriteMask = D3DCOLORWRITEENABLE_ALPHA; - - // - - return true; -} - -template -void GSRendererHW9::VertexKick(bool skip) -{ - Vertex& dst = m_vl.AddTail(); - - dst.p.x = (float)m_v.XYZ.X; - dst.p.y = (float)m_v.XYZ.Y; - dst.p.z = (float)m_v.XYZ.Z; - - dst.c0 = m_v.RGBAQ.ai32[0]; - dst.c1 = m_v.FOG.ai32[1]; - - if(tme) - { - if(fst) - { - GSVector4::storel(&dst.t, m_v.GetUV()); - } - else - { - dst.t.x = m_v.ST.S; - dst.t.y = m_v.ST.T; - dst.p.w = m_v.RGBAQ.Q; - } - } - - DWORD count = 0; - - if(Vertex* v = DrawingKick(skip, count)) - { - GSVector4 scissor = m_context->scissor.dx9; - - GSVector4 pmin, pmax; - - switch(prim) - { - case GS_POINTLIST: - pmin = v[0].p; - pmax = v[0].p; - break; - case GS_LINELIST: - case GS_LINESTRIP: - case GS_SPRITE: - pmin = v[0].p.minv(v[1].p); - pmax = v[0].p.maxv(v[1].p); - break; - case GS_TRIANGLELIST: - case GS_TRIANGLESTRIP: - case GS_TRIANGLEFAN: - pmin = v[0].p.minv(v[1].p).minv(v[2].p); - pmax = v[0].p.maxv(v[1].p).maxv(v[2].p); - break; - } - - GSVector4 test = (pmax < scissor) | (pmin > scissor.zwxy()); - - if(test.mask() & 3) - { - return; - } - - switch(prim) - { - case GS_POINTLIST: - break; - case GS_LINELIST: - case GS_LINESTRIP: - if(PRIM->IIP == 0) {v[0].c0 = v[1].c0;} - break; - case GS_TRIANGLELIST: - case GS_TRIANGLESTRIP: - case GS_TRIANGLEFAN: - if(PRIM->IIP == 0) {v[0].c0 = v[1].c0 = v[2].c0;} - break; - case GS_SPRITE: - if(PRIM->IIP == 0) {v[0].c0 = v[1].c0;} - v[0].p.z = v[1].p.z; - v[0].p.w = v[1].p.w; - v[0].c1 = v[1].c1; - v[2] = v[1]; - v[3] = v[1]; - v[1].p.y = v[0].p.y; - v[1].t.y = v[0].t.y; - v[2].p.x = v[0].p.x; - v[2].t.x = v[0].t.x; - v[4] = v[1]; - v[5] = v[2]; - count += 4; - break; - } - - m_count += count; - } -} - -void GSRendererHW9::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache::GSTexture* tex) -{ - GSDrawingEnvironment& env = m_env; - GSDrawingContext* context = m_context; - - D3DPRIMITIVETYPE topology; - int prims = 0; - - switch(prim) - { - case GS_POINTLIST: - topology = D3DPT_POINTLIST; - prims = m_count; - break; - case GS_LINELIST: - case GS_LINESTRIP: - topology = D3DPT_LINELIST; - prims = m_count / 2; - break; - case GS_TRIANGLELIST: - case GS_TRIANGLESTRIP: - case GS_TRIANGLEFAN: - case GS_SPRITE: - topology = D3DPT_TRIANGLELIST; - prims = m_count / 3; - break; - default: - __assume(0); - } - - m_perfmon.Put(GSPerfMon::Prim, prims); - m_perfmon.Put(GSPerfMon::Draw, 1); - - // date - - SetupDATE(rt, ds); - - // - - m_dev.BeginScene(); - - m_dev->SetRenderState(D3DRS_SHADEMODE, PRIM->IIP ? D3DSHADE_GOURAUD : D3DSHADE_FLAT); // TODO - - // om - - GSTextureFX9::OMDepthStencilSelector om_dssel; - - om_dssel.zte = context->TEST.ZTE; - om_dssel.ztst = context->TEST.ZTST; - om_dssel.zwe = !context->ZBUF.ZMSK; - om_dssel.date = context->FRAME.PSM != PSM_PSMCT24 ? context->TEST.DATE : 0; - om_dssel.fba = m_fba.enabled ? context->FBA.FBA : 0; - - GSTextureFX9::OMBlendSelector om_bsel; - - om_bsel.abe = PRIM->ABE || (prim == 1 || prim == 2) && PRIM->AA1; - om_bsel.a = context->ALPHA.A; - om_bsel.b = context->ALPHA.B; - om_bsel.c = context->ALPHA.C; - om_bsel.d = context->ALPHA.D; - om_bsel.wr = (context->FRAME.FBMSK & 0x000000ff) != 0x000000ff; - om_bsel.wg = (context->FRAME.FBMSK & 0x0000ff00) != 0x0000ff00; - om_bsel.wb = (context->FRAME.FBMSK & 0x00ff0000) != 0x00ff0000; - om_bsel.wa = (context->FRAME.FBMSK & 0xff000000) != 0xff000000; - - BYTE bf = context->ALPHA.FIX >= 0x80 ? 0xff : (BYTE)(context->ALPHA.FIX * 2); - - // vs - - GSTextureFX9::VSSelector vs_sel; - - vs_sel.bppz = 0; - vs_sel.tme = PRIM->TME; - vs_sel.fst = PRIM->FST; - vs_sel.logz = m_logz ? 1 : 0; - - if(om_dssel.zte && om_dssel.ztst > 0 && om_dssel.zwe) - { - if(context->ZBUF.PSM == PSM_PSMZ24) - { - if(WrapZ(0xffffff)) - { - vs_sel.bppz = 1; - om_dssel.ztst = 1; - } - } - else if(context->ZBUF.PSM == PSM_PSMZ16 || context->ZBUF.PSM == PSM_PSMZ16S) - { - if(WrapZ(0xffff)) - { - vs_sel.bppz = 2; - om_dssel.ztst = 1; - } - } - } - - GSTextureFX9::VSConstantBuffer vs_cb; - - float sx = 2.0f * rt.m_scale.x / (rt.GetWidth() * 16); - float sy = 2.0f * rt.m_scale.y / (rt.GetHeight() * 16); - float ox = (float)(int)context->XYOFFSET.OFX; - float oy = (float)(int)context->XYOFFSET.OFY; - - vs_cb.VertexScale = GSVector4(sx, -sy, 1.0f / UINT_MAX, 0.0f); - vs_cb.VertexOffset = GSVector4(ox * sx + 1, -(oy * sy + 1), 0.0f, -1.0f); - vs_cb.TextureScale = GSVector2(1.0f, 1.0f); - - if(PRIM->TME && PRIM->FST) - { - vs_cb.TextureScale.x = 1.0f / (16 << context->TEX0.TW); - vs_cb.TextureScale.y = 1.0f / (16 << context->TEX0.TH); - } - - // ps - - GSTextureFX9::PSSelector ps_sel; - - ps_sel.fst = PRIM->FST; - ps_sel.wms = context->CLAMP.WMS; - ps_sel.wmt = context->CLAMP.WMT; - ps_sel.bpp = 0; - ps_sel.aem = env.TEXA.AEM; - ps_sel.tfx = context->TEX0.TFX; - ps_sel.tcc = context->TEX0.TCC; - ps_sel.ate = context->TEST.ATE; - ps_sel.atst = context->TEST.ATST; - ps_sel.fog = PRIM->FGE; - ps_sel.clr1 = om_bsel.abe && om_bsel.a == 1 && om_bsel.b == 2 && om_bsel.d == 1; - ps_sel.rt = tex && tex->m_rendered; - - GSTextureFX9::PSSamplerSelector ps_ssel; - - ps_ssel.min = m_filter == 2 ? (context->TEX1.MMIN & 1) : m_filter; - ps_ssel.mag = m_filter == 2 ? (context->TEX1.MMAG & 1) : m_filter; - ps_ssel.tau = 0; - ps_ssel.tav = 0; - - GSTextureFX9::PSConstantBuffer ps_cb; - - ps_cb.FogColor = GSVector4(env.FOGCOL.FCR, env.FOGCOL.FCG, env.FOGCOL.FCB, 0) / 255.0f; - ps_cb.TA0 = (float)(int)env.TEXA.TA0 / 255; - ps_cb.TA1 = (float)(int)env.TEXA.TA1 / 255; - ps_cb.AREF = (float)(int)context->TEST.AREF / 255; - - if(context->TEST.ATST == 2 || context->TEST.ATST == 5) - { - ps_cb.AREF -= 0.9f/256; - } - else if(context->TEST.ATST == 3 || context->TEST.ATST == 6) - { - ps_cb.AREF += 0.9f/256; - } - - if(tex) - { - ps_sel.bpp = tex->m_bpp2; - - switch(context->CLAMP.WMS) - { - case 0: - ps_ssel.tau = 1; - break; - case 1: - ps_ssel.tau = 0; - break; - case 2: - ps_cb.MINU = ((float)(int)context->CLAMP.MINU + 0.5f) / (1 << context->TEX0.TW); - ps_cb.MAXU = ((float)(int)context->CLAMP.MAXU) / (1 << context->TEX0.TW); - ps_ssel.tau = 0; - break; - case 3: - ps_cb.UMSK = context->CLAMP.MINU; - ps_cb.UFIX = context->CLAMP.MAXU; - ps_ssel.tau = 1; - break; - default: - __assume(0); - } - - switch(context->CLAMP.WMT) - { - case 0: - ps_ssel.tav = 1; - break; - case 1: - ps_ssel.tav = 0; - break; - case 2: - ps_cb.MINV = ((float)(int)context->CLAMP.MINV + 0.5f) / (1 << context->TEX0.TH); - ps_cb.MAXV = ((float)(int)context->CLAMP.MAXV) / (1 << context->TEX0.TH); - ps_ssel.tav = 0; - break; - case 3: - ps_cb.VMSK = context->CLAMP.MINV; - ps_cb.VFIX = context->CLAMP.MAXV; - ps_ssel.tav = 1; - break; - default: - __assume(0); - } - - float w = (float)tex->m_texture.GetWidth(); - float h = (float)tex->m_texture.GetHeight(); - - ps_cb.WH = GSVector2(w, h); - ps_cb.rWrH = GSVector2(1.0f / w, 1.0f / h); - } - else - { - ps_sel.tfx = 4; - } - - // rs - - int w = rt.GetWidth(); - int h = rt.GetHeight(); - - CRect scissor = (CRect)GSVector4i(GSVector4(rt.m_scale).xyxy() * context->scissor.in) & CRect(0, 0, w, h); - - // - - m_tfx.SetupOM(om_dssel, om_bsel, bf, rt, ds); - m_tfx.SetupIA(m_vertices, m_count, topology); - m_tfx.SetupVS(vs_sel, &vs_cb); - m_tfx.SetupPS(ps_sel, &ps_cb, ps_ssel, - tex ? (IDirect3DTexture9*)tex->m_texture : NULL, - tex ? (IDirect3DTexture9*)tex->m_palette : NULL, - m_psrr); - m_tfx.SetupRS(w, h, scissor); - - // draw - - if(context->TEST.DoFirstPass()) - { - m_dev.DrawPrimitive(); - } - - if(context->TEST.DoSecondPass()) - { - ASSERT(!env.PABE.PABE); - - static const DWORD iatst[] = {1, 0, 5, 6, 7, 2, 3, 4}; - - ps_sel.atst = iatst[ps_sel.atst]; - - m_tfx.UpdatePS(ps_sel, &ps_cb, ps_ssel, m_psrr); - - bool z = om_dssel.zwe; - bool r = om_bsel.wr; - bool g = om_bsel.wg; - bool b = om_bsel.wb; - bool a = om_bsel.wa; - - switch(context->TEST.AFAIL) - { - case 0: z = r = g = b = a = false; break; // none - case 1: z = false; break; // rgba - case 2: r = g = b = a = false; break; // z - case 3: z = a = false; break; // rgb - default: __assume(0); - } - - if(z || r || g || b || a) - { - om_dssel.zwe = z; - om_bsel.wr = r; - om_bsel.wg = g; - om_bsel.wb = b; - om_bsel.wa = a; - - m_tfx.UpdateOM(om_dssel, om_bsel, bf); - - m_dev.DrawPrimitive(); - } - } - - m_dev.EndScene(); - - if(om_dssel.fba) UpdateFBA(rt); -} - -bool GSRendererHW9::WrapZ(float maxz) -{ - // should only run once if z values are in the z buffer range - - for(int i = 0, j = m_count; i < j; i++) - { - if(m_vertices[i].p.z <= maxz) - { - return false; - } - } - - return true; -} - -void GSRendererHW9::SetupDATE(Texture& rt, Texture& ds) -{ - if(!m_context->TEST.DATE) return; // || (::GetAsyncKeyState(VK_CONTROL) & 0x8000) - - // sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows - - GSVector4 mm; - - // TODO - - mm = GSVector4(-1, -1, 1, 1); -/* - MinMaxXY(mm); - - int w = rt.GetWidth(); - int h = rt.GetHeight(); - - float sx = 2.0f * rt.m_scale.x / (w * 16); - float sy = 2.0f * rt.m_scale.y / (h * 16); - float ox = (float)(int)m_context->XYOFFSET.OFX; - float oy = (float)(int)m_context->XYOFFSET.OFY; - - mm.x = (mm.x - ox) * sx - 1; - mm.y = (mm.y - oy) * sy - 1; - mm.z = (mm.z - ox) * sx - 1; - mm.w = (mm.w - oy) * sy - 1; - - if(mm.x < -1) mm.x = -1; - if(mm.y < -1) mm.y = -1; - if(mm.z > +1) mm.z = +1; - if(mm.w > +1) mm.w = +1; -*/ - GSVector4 uv = (mm + 1.0f) / 2.0f; - - // - - m_dev.BeginScene(); - - // om - - GSTexture9 tmp; - - m_dev.CreateRenderTarget(tmp, rt.GetWidth(), rt.GetHeight()); - - m_dev.OMSetRenderTargets(tmp, ds); - m_dev.OMSetDepthStencilState(&m_date.dss, 1); - m_dev.OMSetBlendState(&m_date.bs, 0); - - m_dev->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 0, 0); - - // ia - - GSVertexPT1 vertices[] = - { - {GSVector4(mm.x, -mm.y, 0.5f, 1.0f), GSVector2(uv.x, uv.y)}, - {GSVector4(mm.z, -mm.y, 0.5f, 1.0f), GSVector2(uv.z, uv.y)}, - {GSVector4(mm.x, -mm.w, 0.5f, 1.0f), GSVector2(uv.x, uv.w)}, - {GSVector4(mm.z, -mm.w, 0.5f, 1.0f), GSVector2(uv.z, uv.w)}, - }; - - m_dev.IASetVertexBuffer(4, vertices); - m_dev.IASetInputLayout(m_dev.m_convert.il); - m_dev.IASetPrimitiveTopology(D3DPT_TRIANGLESTRIP); - - // vs - - m_dev.VSSetShader(m_dev.m_convert.vs, NULL, 0); - - // ps - - m_dev.PSSetShaderResources(rt, NULL); - m_dev.PSSetShader(m_dev.m_convert.ps[m_context->TEST.DATM ? 2 : 3], NULL, 0); - m_dev.PSSetSamplerState(&m_dev.m_convert.pt); - - // rs - - m_dev.RSSet(tmp.GetWidth(), tmp.GetHeight()); - - // - - m_dev.DrawPrimitive(); - - // - - m_dev.EndScene(); - - m_dev.Recycle(tmp); -} - -void GSRendererHW9::UpdateFBA(Texture& rt) -{ - m_dev.BeginScene(); - - // om - - m_dev.OMSetDepthStencilState(&m_fba.dss, 2); - m_dev.OMSetBlendState(&m_fba.bs, 0); - - // vs - - m_dev.VSSetShader(NULL, NULL, 0); - - // ps - - m_dev.PSSetShader(m_dev.m_convert.ps[4], NULL, 0); - - // - - int w = rt.GetWidth(); - int h = rt.GetHeight(); - - GSVertexP vertices[] = - { - {GSVector4(0, 0, 0, 0)}, - {GSVector4(w, 0, 0, 0)}, - {GSVector4(0, h, 0, 0)}, - {GSVector4(w, h, 0, 0)}, - }; - - m_dev->SetFVF(D3DFVF_XYZRHW); - - m_dev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, vertices, sizeof(vertices[0])); - - // - - m_dev.EndScene(); -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSRendererHW9.h" +#include "GSCrc.h" +#include "resource.h" + +GSRendererHW9::GSRendererHW9(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs) + : GSRendererHW(base, mt, irq, nloophack, rs, false) +{ + m_fba.enabled = !!AfxGetApp()->GetProfileInt(_T("Settings"), _T("fba"), TRUE); + m_logz = !!AfxGetApp()->GetProfileInt(_T("Settings"), _T("logz"), FALSE); + + InitVertexKick(); +} + +bool GSRendererHW9::Create(LPCTSTR title) +{ + if(!__super::Create(title)) + return false; + + if(!m_tfx.Create(&m_dev)) + return false; + + // + + memset(&m_date.dss, 0, sizeof(m_date.dss)); + + m_date.dss.StencilEnable = true; + m_date.dss.StencilReadMask = 1; + m_date.dss.StencilWriteMask = 1; + m_date.dss.StencilFunc = D3DCMP_ALWAYS; + m_date.dss.StencilPassOp = D3DSTENCILOP_REPLACE; + + memset(&m_date.bs, 0, sizeof(m_date.bs)); + + // + + memset(&m_fba.dss, 0, sizeof(m_fba.dss)); + + m_fba.dss.StencilEnable = true; + m_fba.dss.StencilReadMask = 2; + m_fba.dss.StencilWriteMask = 2; + m_fba.dss.StencilFunc = D3DCMP_EQUAL; + m_fba.dss.StencilPassOp = D3DSTENCILOP_ZERO; + m_fba.dss.StencilFailOp = D3DSTENCILOP_ZERO; + m_fba.dss.StencilDepthFailOp = D3DSTENCILOP_ZERO; + + memset(&m_fba.bs, 0, sizeof(m_fba.bs)); + + m_fba.bs.RenderTargetWriteMask = D3DCOLORWRITEENABLE_ALPHA; + + // + + return true; +} + +template +void GSRendererHW9::VertexKick(bool skip) +{ + Vertex& dst = m_vl.AddTail(); + + dst.p.x = (float)m_v.XYZ.X; + dst.p.y = (float)m_v.XYZ.Y; + dst.p.z = (float)m_v.XYZ.Z; + + dst.c0 = m_v.RGBAQ.ai32[0]; + dst.c1 = m_v.FOG.ai32[1]; + + if(tme) + { + if(fst) + { + GSVector4::storel(&dst.t, m_v.GetUV()); + } + else + { + dst.t.x = m_v.ST.S; + dst.t.y = m_v.ST.T; + dst.p.w = m_v.RGBAQ.Q; + } + } + + DWORD count = 0; + + if(Vertex* v = DrawingKick(skip, count)) + { + GSVector4 scissor = m_context->scissor.dx9; + + GSVector4 pmin, pmax; + + switch(prim) + { + case GS_POINTLIST: + pmin = v[0].p; + pmax = v[0].p; + break; + case GS_LINELIST: + case GS_LINESTRIP: + case GS_SPRITE: + pmin = v[0].p.minv(v[1].p); + pmax = v[0].p.maxv(v[1].p); + break; + case GS_TRIANGLELIST: + case GS_TRIANGLESTRIP: + case GS_TRIANGLEFAN: + pmin = v[0].p.minv(v[1].p).minv(v[2].p); + pmax = v[0].p.maxv(v[1].p).maxv(v[2].p); + break; + } + + GSVector4 test = (pmax < scissor) | (pmin > scissor.zwxy()); + + if(test.mask() & 3) + { + return; + } + + switch(prim) + { + case GS_POINTLIST: + break; + case GS_LINELIST: + case GS_LINESTRIP: + if(PRIM->IIP == 0) {v[0].c0 = v[1].c0;} + break; + case GS_TRIANGLELIST: + case GS_TRIANGLESTRIP: + case GS_TRIANGLEFAN: + if(PRIM->IIP == 0) {v[0].c0 = v[1].c0 = v[2].c0;} + break; + case GS_SPRITE: + if(PRIM->IIP == 0) {v[0].c0 = v[1].c0;} + v[0].p.z = v[1].p.z; + v[0].p.w = v[1].p.w; + v[0].c1 = v[1].c1; + v[2] = v[1]; + v[3] = v[1]; + v[1].p.y = v[0].p.y; + v[1].t.y = v[0].t.y; + v[2].p.x = v[0].p.x; + v[2].t.x = v[0].t.x; + v[4] = v[1]; + v[5] = v[2]; + count += 4; + break; + } + + m_count += count; + } +} + +void GSRendererHW9::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache::GSTexture* tex) +{ + GSDrawingEnvironment& env = m_env; + GSDrawingContext* context = m_context; + + D3DPRIMITIVETYPE topology; + int prims = 0; + + switch(prim) + { + case GS_POINTLIST: + topology = D3DPT_POINTLIST; + prims = m_count; + break; + case GS_LINELIST: + case GS_LINESTRIP: + topology = D3DPT_LINELIST; + prims = m_count / 2; + break; + case GS_TRIANGLELIST: + case GS_TRIANGLESTRIP: + case GS_TRIANGLEFAN: + case GS_SPRITE: + topology = D3DPT_TRIANGLELIST; + prims = m_count / 3; + break; + default: + __assume(0); + } + + m_perfmon.Put(GSPerfMon::Prim, prims); + m_perfmon.Put(GSPerfMon::Draw, 1); + + // date + + SetupDATE(rt, ds); + + // + + m_dev.BeginScene(); + + m_dev->SetRenderState(D3DRS_SHADEMODE, PRIM->IIP ? D3DSHADE_GOURAUD : D3DSHADE_FLAT); // TODO + + // om + + GSTextureFX9::OMDepthStencilSelector om_dssel; + + om_dssel.zte = context->TEST.ZTE; + om_dssel.ztst = context->TEST.ZTST; + om_dssel.zwe = !context->ZBUF.ZMSK; + om_dssel.date = context->FRAME.PSM != PSM_PSMCT24 ? context->TEST.DATE : 0; + om_dssel.fba = m_fba.enabled ? context->FBA.FBA : 0; + + GSTextureFX9::OMBlendSelector om_bsel; + + om_bsel.abe = PRIM->ABE || (prim == 1 || prim == 2) && PRIM->AA1; + om_bsel.a = context->ALPHA.A; + om_bsel.b = context->ALPHA.B; + om_bsel.c = context->ALPHA.C; + om_bsel.d = context->ALPHA.D; + om_bsel.wr = (context->FRAME.FBMSK & 0x000000ff) != 0x000000ff; + om_bsel.wg = (context->FRAME.FBMSK & 0x0000ff00) != 0x0000ff00; + om_bsel.wb = (context->FRAME.FBMSK & 0x00ff0000) != 0x00ff0000; + om_bsel.wa = (context->FRAME.FBMSK & 0xff000000) != 0xff000000; + + BYTE bf = context->ALPHA.FIX >= 0x80 ? 0xff : (BYTE)(context->ALPHA.FIX * 2); + + // vs + + GSTextureFX9::VSSelector vs_sel; + + vs_sel.bppz = 0; + vs_sel.tme = PRIM->TME; + vs_sel.fst = PRIM->FST; + vs_sel.logz = m_logz ? 1 : 0; + + if(om_dssel.zte && om_dssel.ztst > 0 && om_dssel.zwe) + { + if(context->ZBUF.PSM == PSM_PSMZ24) + { + if(WrapZ(0xffffff)) + { + vs_sel.bppz = 1; + om_dssel.ztst = 1; + } + } + else if(context->ZBUF.PSM == PSM_PSMZ16 || context->ZBUF.PSM == PSM_PSMZ16S) + { + if(WrapZ(0xffff)) + { + vs_sel.bppz = 2; + om_dssel.ztst = 1; + } + } + } + + GSTextureFX9::VSConstantBuffer vs_cb; + + float sx = 2.0f * rt.m_scale.x / (rt.GetWidth() * 16); + float sy = 2.0f * rt.m_scale.y / (rt.GetHeight() * 16); + float ox = (float)(int)context->XYOFFSET.OFX; + float oy = (float)(int)context->XYOFFSET.OFY; + + vs_cb.VertexScale = GSVector4(sx, -sy, 1.0f / UINT_MAX, 0.0f); + vs_cb.VertexOffset = GSVector4(ox * sx + 1, -(oy * sy + 1), 0.0f, -1.0f); + vs_cb.TextureScale = GSVector2(1.0f, 1.0f); + + if(PRIM->TME && PRIM->FST) + { + vs_cb.TextureScale.x = 1.0f / (16 << context->TEX0.TW); + vs_cb.TextureScale.y = 1.0f / (16 << context->TEX0.TH); + } + + // ps + + GSTextureFX9::PSSelector ps_sel; + + ps_sel.fst = PRIM->FST; + ps_sel.wms = context->CLAMP.WMS; + ps_sel.wmt = context->CLAMP.WMT; + ps_sel.bpp = 0; + ps_sel.aem = env.TEXA.AEM; + ps_sel.tfx = context->TEX0.TFX; + ps_sel.tcc = context->TEX0.TCC; + ps_sel.ate = context->TEST.ATE; + ps_sel.atst = context->TEST.ATST; + ps_sel.fog = PRIM->FGE; + ps_sel.clr1 = om_bsel.abe && om_bsel.a == 1 && om_bsel.b == 2 && om_bsel.d == 1; + ps_sel.rt = tex && tex->m_rendered; + + GSTextureFX9::PSSamplerSelector ps_ssel; + + ps_ssel.min = m_filter == 2 ? (context->TEX1.MMIN & 1) : m_filter; + ps_ssel.mag = m_filter == 2 ? (context->TEX1.MMAG & 1) : m_filter; + ps_ssel.tau = 0; + ps_ssel.tav = 0; + + GSTextureFX9::PSConstantBuffer ps_cb; + + ps_cb.FogColor = GSVector4(env.FOGCOL.FCR, env.FOGCOL.FCG, env.FOGCOL.FCB, 0) / 255.0f; + ps_cb.TA0 = (float)(int)env.TEXA.TA0 / 255; + ps_cb.TA1 = (float)(int)env.TEXA.TA1 / 255; + ps_cb.AREF = (float)(int)context->TEST.AREF / 255; + + if(context->TEST.ATST == 2 || context->TEST.ATST == 5) + { + ps_cb.AREF -= 0.9f/256; + } + else if(context->TEST.ATST == 3 || context->TEST.ATST == 6) + { + ps_cb.AREF += 0.9f/256; + } + + if(tex) + { + ps_sel.bpp = tex->m_bpp2; + + switch(context->CLAMP.WMS) + { + case 0: + ps_ssel.tau = 1; + break; + case 1: + ps_ssel.tau = 0; + break; + case 2: + ps_cb.MINU = ((float)(int)context->CLAMP.MINU + 0.5f) / (1 << context->TEX0.TW); + ps_cb.MAXU = ((float)(int)context->CLAMP.MAXU) / (1 << context->TEX0.TW); + ps_ssel.tau = 0; + break; + case 3: + ps_cb.UMSK = context->CLAMP.MINU; + ps_cb.UFIX = context->CLAMP.MAXU; + ps_ssel.tau = 1; + break; + default: + __assume(0); + } + + switch(context->CLAMP.WMT) + { + case 0: + ps_ssel.tav = 1; + break; + case 1: + ps_ssel.tav = 0; + break; + case 2: + ps_cb.MINV = ((float)(int)context->CLAMP.MINV + 0.5f) / (1 << context->TEX0.TH); + ps_cb.MAXV = ((float)(int)context->CLAMP.MAXV) / (1 << context->TEX0.TH); + ps_ssel.tav = 0; + break; + case 3: + ps_cb.VMSK = context->CLAMP.MINV; + ps_cb.VFIX = context->CLAMP.MAXV; + ps_ssel.tav = 1; + break; + default: + __assume(0); + } + + float w = (float)tex->m_texture.GetWidth(); + float h = (float)tex->m_texture.GetHeight(); + + ps_cb.WH = GSVector2(w, h); + ps_cb.rWrH = GSVector2(1.0f / w, 1.0f / h); + } + else + { + ps_sel.tfx = 4; + } + + // rs + + int w = rt.GetWidth(); + int h = rt.GetHeight(); + + CRect scissor = (CRect)GSVector4i(GSVector4(rt.m_scale).xyxy() * context->scissor.in) & CRect(0, 0, w, h); + + // + + m_tfx.SetupOM(om_dssel, om_bsel, bf, rt, ds); + m_tfx.SetupIA(m_vertices, m_count, topology); + m_tfx.SetupVS(vs_sel, &vs_cb); + m_tfx.SetupPS(ps_sel, &ps_cb, ps_ssel, + tex ? (IDirect3DTexture9*)tex->m_texture : NULL, + tex ? (IDirect3DTexture9*)tex->m_palette : NULL, + m_psrr); + m_tfx.SetupRS(w, h, scissor); + + // draw + + if(context->TEST.DoFirstPass()) + { + m_dev.DrawPrimitive(); + } + + if(context->TEST.DoSecondPass()) + { + ASSERT(!env.PABE.PABE); + + static const DWORD iatst[] = {1, 0, 5, 6, 7, 2, 3, 4}; + + ps_sel.atst = iatst[ps_sel.atst]; + + m_tfx.UpdatePS(ps_sel, &ps_cb, ps_ssel, m_psrr); + + bool z = om_dssel.zwe; + bool r = om_bsel.wr; + bool g = om_bsel.wg; + bool b = om_bsel.wb; + bool a = om_bsel.wa; + + switch(context->TEST.AFAIL) + { + case 0: z = r = g = b = a = false; break; // none + case 1: z = false; break; // rgba + case 2: r = g = b = a = false; break; // z + case 3: z = a = false; break; // rgb + default: __assume(0); + } + + if(z || r || g || b || a) + { + om_dssel.zwe = z; + om_bsel.wr = r; + om_bsel.wg = g; + om_bsel.wb = b; + om_bsel.wa = a; + + m_tfx.UpdateOM(om_dssel, om_bsel, bf); + + m_dev.DrawPrimitive(); + } + } + + m_dev.EndScene(); + + if(om_dssel.fba) UpdateFBA(rt); +} + +bool GSRendererHW9::WrapZ(float maxz) +{ + // should only run once if z values are in the z buffer range + + for(int i = 0, j = m_count; i < j; i++) + { + if(m_vertices[i].p.z <= maxz) + { + return false; + } + } + + return true; +} + +void GSRendererHW9::SetupDATE(Texture& rt, Texture& ds) +{ + if(!m_context->TEST.DATE) return; // || (::GetAsyncKeyState(VK_CONTROL) & 0x8000) + + // sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows + + GSVector4 mm; + + // TODO + + mm = GSVector4(-1, -1, 1, 1); +/* + MinMaxXY(mm); + + int w = rt.GetWidth(); + int h = rt.GetHeight(); + + float sx = 2.0f * rt.m_scale.x / (w * 16); + float sy = 2.0f * rt.m_scale.y / (h * 16); + float ox = (float)(int)m_context->XYOFFSET.OFX; + float oy = (float)(int)m_context->XYOFFSET.OFY; + + mm.x = (mm.x - ox) * sx - 1; + mm.y = (mm.y - oy) * sy - 1; + mm.z = (mm.z - ox) * sx - 1; + mm.w = (mm.w - oy) * sy - 1; + + if(mm.x < -1) mm.x = -1; + if(mm.y < -1) mm.y = -1; + if(mm.z > +1) mm.z = +1; + if(mm.w > +1) mm.w = +1; +*/ + GSVector4 uv = (mm + 1.0f) / 2.0f; + + // + + m_dev.BeginScene(); + + // om + + GSTexture9 tmp; + + m_dev.CreateRenderTarget(tmp, rt.GetWidth(), rt.GetHeight()); + + m_dev.OMSetRenderTargets(tmp, ds); + m_dev.OMSetDepthStencilState(&m_date.dss, 1); + m_dev.OMSetBlendState(&m_date.bs, 0); + + m_dev->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 0, 0); + + // ia + + GSVertexPT1 vertices[] = + { + {GSVector4(mm.x, -mm.y, 0.5f, 1.0f), GSVector2(uv.x, uv.y)}, + {GSVector4(mm.z, -mm.y, 0.5f, 1.0f), GSVector2(uv.z, uv.y)}, + {GSVector4(mm.x, -mm.w, 0.5f, 1.0f), GSVector2(uv.x, uv.w)}, + {GSVector4(mm.z, -mm.w, 0.5f, 1.0f), GSVector2(uv.z, uv.w)}, + }; + + m_dev.IASetVertexBuffer(4, vertices); + m_dev.IASetInputLayout(m_dev.m_convert.il); + m_dev.IASetPrimitiveTopology(D3DPT_TRIANGLESTRIP); + + // vs + + m_dev.VSSetShader(m_dev.m_convert.vs, NULL, 0); + + // ps + + m_dev.PSSetShaderResources(rt, NULL); + m_dev.PSSetShader(m_dev.m_convert.ps[m_context->TEST.DATM ? 2 : 3], NULL, 0); + m_dev.PSSetSamplerState(&m_dev.m_convert.pt); + + // rs + + m_dev.RSSet(tmp.GetWidth(), tmp.GetHeight()); + + // + + m_dev.DrawPrimitive(); + + // + + m_dev.EndScene(); + + m_dev.Recycle(tmp); +} + +void GSRendererHW9::UpdateFBA(Texture& rt) +{ + m_dev.BeginScene(); + + // om + + m_dev.OMSetDepthStencilState(&m_fba.dss, 2); + m_dev.OMSetBlendState(&m_fba.bs, 0); + + // vs + + m_dev.VSSetShader(NULL, NULL, 0); + + // ps + + m_dev.PSSetShader(m_dev.m_convert.ps[4], NULL, 0); + + // + + int w = rt.GetWidth(); + int h = rt.GetHeight(); + + GSVertexP vertices[] = + { + {GSVector4(0, 0, 0, 0)}, + {GSVector4(w, 0, 0, 0)}, + {GSVector4(0, h, 0, 0)}, + {GSVector4(w, h, 0, 0)}, + }; + + m_dev->SetFVF(D3DFVF_XYZRHW); + + m_dev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, vertices, sizeof(vertices[0])); + + // + + m_dev.EndScene(); +} diff --git a/plugins/GSdx/GSRendererHW9.h b/plugins/GSdx/GSRendererHW9.h index 18fcf8fe3d..bc9c7cb030 100644 --- a/plugins/GSdx/GSRendererHW9.h +++ b/plugins/GSdx/GSRendererHW9.h @@ -1,65 +1,65 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSRendererHW.h" -#include "GSVertexHW.h" -#include "GSTextureCache9.h" -#include "GSTextureFX9.h" - -class GSRendererHW9 : public GSRendererHW -{ - typedef GSDevice9 Device; - typedef GSVertexHW9 Vertex; - typedef GSTextureCache9 TextureCache; - - bool WrapZ(float maxz); - -protected: - GSTextureFX9 m_tfx; - bool m_logz; - - void Draw(int prim, Texture& rt, Texture& ds, GSTextureCache::GSTexture* tex); - - struct - { - Direct3DDepthStencilState9 dss; - Direct3DBlendState9 bs; - } m_date; - - struct - { - bool enabled; - Direct3DDepthStencilState9 dss; - Direct3DBlendState9 bs; - } m_fba; - - void SetupDATE(Texture& rt, Texture& ds); - void UpdateFBA(Texture& rt); - -public: - GSRendererHW9(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs); - - bool Create(LPCTSTR title); - - template void VertexKick(bool skip); -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSRendererHW.h" +#include "GSVertexHW.h" +#include "GSTextureCache9.h" +#include "GSTextureFX9.h" + +class GSRendererHW9 : public GSRendererHW +{ + typedef GSDevice9 Device; + typedef GSVertexHW9 Vertex; + typedef GSTextureCache9 TextureCache; + + bool WrapZ(float maxz); + +protected: + GSTextureFX9 m_tfx; + bool m_logz; + + void Draw(int prim, Texture& rt, Texture& ds, GSTextureCache::GSTexture* tex); + + struct + { + Direct3DDepthStencilState9 dss; + Direct3DBlendState9 bs; + } m_date; + + struct + { + bool enabled; + Direct3DDepthStencilState9 dss; + Direct3DBlendState9 bs; + } m_fba; + + void SetupDATE(Texture& rt, Texture& ds); + void UpdateFBA(Texture& rt); + +public: + GSRendererHW9(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs); + + bool Create(LPCTSTR title); + + template void VertexKick(bool skip); +}; diff --git a/plugins/GSdx/GSRendererNull.cpp b/plugins/GSdx/GSRendererNull.cpp index f51c3a7cfa..5e82cc2b09 100644 --- a/plugins/GSdx/GSRendererNull.cpp +++ b/plugins/GSdx/GSRendererNull.cpp @@ -1,23 +1,23 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSRendererNull.h" +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSRendererNull.h" diff --git a/plugins/GSdx/GSRendererNull.h b/plugins/GSdx/GSRendererNull.h index a375cf963d..7af3baaa88 100644 --- a/plugins/GSdx/GSRendererNull.h +++ b/plugins/GSdx/GSRendererNull.h @@ -1,49 +1,49 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSRenderer.h" -#include "GSDeviceNull.h" - -template class GSRendererNull : public GSRendererT -{ -protected: - void Draw() - { - } - - bool GetOutput(int i, Texture& t) - { - return false; - } - -public: - GSRendererNull(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs) - : GSRendererT(base, mt, irq, nloophack, rs) - { - InitVertexKick >(); - } - - template void VertexKick(bool skip) - { - } +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSRenderer.h" +#include "GSDeviceNull.h" + +template class GSRendererNull : public GSRendererT +{ +protected: + void Draw() + { + } + + bool GetOutput(int i, Texture& t) + { + return false; + } + +public: + GSRendererNull(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs) + : GSRendererT(base, mt, irq, nloophack, rs) + { + InitVertexKick >(); + } + + template void VertexKick(bool skip) + { + } }; \ No newline at end of file diff --git a/plugins/GSdx/GSRendererSW.cpp b/plugins/GSdx/GSRendererSW.cpp index 93eaa2336e..b422422e62 100644 --- a/plugins/GSdx/GSRendererSW.cpp +++ b/plugins/GSdx/GSRendererSW.cpp @@ -1,25 +1,25 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSRendererSW.h" - -const GSVector4 g_pos_scale(1.0f / 16, 1.0f / 16, 1.0f, 128.0f); +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSRendererSW.h" + +const GSVector4 g_pos_scale(1.0f / 16, 1.0f / 16, 1.0f, 128.0f); diff --git a/plugins/GSdx/GSRendererSW.h b/plugins/GSdx/GSRendererSW.h index b1bbd571d0..e00af9d88f 100644 --- a/plugins/GSdx/GSRendererSW.h +++ b/plugins/GSdx/GSRendererSW.h @@ -1,858 +1,858 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSRenderer.h" -#include "GSTextureCacheSW.h" -#include "GSDrawScanline.h" - -extern const GSVector4 g_pos_scale; - -template -class GSRendererSW : public GSRendererT -{ -protected: - GSRasterizerList m_rl; - GSTextureCacheSW* m_tc; - GSVertexTrace m_vtrace; - Texture m_texture[2]; - bool m_reset; - - void Reset() - { - // TODO: GSreset can come from the main thread too => crash - // m_tc->RemoveAll(); - - m_reset = true; - - __super::Reset(); - } - - void VSync(int field) - { - __super::VSync(field); - - m_tc->IncAge(); - - if(m_reset) - { - m_tc->RemoveAll(); - - m_reset = false; - } - - // if((m_perfmon.GetFrame() & 255) == 0) m_rl.PrintStats(); - } - - void ResetDevice() - { - m_texture[0] = Texture(); - m_texture[1] = Texture(); - } - - bool GetOutput(int i, Texture& t) - { - CRect r(0, 0, DISPFB[i]->FBW * 64, GetFrameRect(i).bottom); - - // TODO: round up bottom - - if(m_texture[i].GetWidth() != r.Width() || m_texture[i].GetHeight() != r.Height()) - { - m_texture[i] = Texture(); - } - - if(!m_texture[i] && !m_dev.CreateTexture(m_texture[i], r.Width(), r.Height())) - { - return false; - } - - GIFRegTEX0 TEX0; - - TEX0.TBP0 = DISPFB[i]->Block(); - TEX0.TBW = DISPFB[i]->FBW; - TEX0.PSM = DISPFB[i]->PSM; - - GIFRegCLAMP CLAMP; - - CLAMP.WMS = CLAMP.WMT = 1; - - // TODO - static BYTE* buff = (BYTE*)_aligned_malloc(1024 * 1024 * 4, 16); - static int pitch = 1024 * 4; - - m_mem.ReadTexture(r, buff, pitch, TEX0, m_env.TEXA, CLAMP); - - m_texture[i].Update(r, buff, pitch); - - t = m_texture[i]; - - if(s_dump) - { - CString str; - str.Format(_T("c:\\temp1\\_%05d_f%I64d_fr%d_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), i, (int)TEX0.TBP0, (int)TEX0.PSM); - if(s_save) t.Save(str); - } - - return true; - } - - bool TryAlphaTest(DWORD& fm, DWORD& zm) - { - const GSDrawingEnvironment& env = m_env; - const GSDrawingContext* context = m_context; - - bool pass = true; - - if(context->TEST.ATST == ATST_NEVER) - { - pass = false; - } - else if(context->TEST.ATST != ATST_ALWAYS) - { - GSVector4i af = GSVector4i(m_vtrace.m_min.c.wwww(m_vtrace.m_max.c)) >> 7; - - int amin, amax; - - if(PRIM->TME && (context->TEX0.TCC || context->TEX0.TFX == TFX_DECAL)) - { - DWORD bpp = GSLocalMemory::m_psm[context->TEX0.PSM].trbpp; - DWORD cbpp = GSLocalMemory::m_psm[context->TEX0.CPSM].trbpp; - DWORD pal = GSLocalMemory::m_psm[context->TEX0.PSM].pal; - - if(bpp == 32) - { - return false; - } - else if(bpp == 24) - { - amin = env.TEXA.AEM ? 0 : env.TEXA.TA0; - amax = env.TEXA.TA0; - } - else if(bpp == 16) - { - amin = env.TEXA.AEM ? 0 : min(env.TEXA.TA0, env.TEXA.TA1); - amax = max(env.TEXA.TA0, env.TEXA.TA1); - } - else - { - m_mem.m_clut.GetAlphaMinMax32(amin, amax); - } - - switch(context->TEX0.TFX) - { - case TFX_MODULATE: - amin = (amin * af.x) >> 7; - amax = (amax * af.z) >> 7; - if(amin > 255) amin = 255; - if(amax > 255) amax = 255; - break; - case TFX_DECAL: - break; - case TFX_HIGHLIGHT: - amin = amin + af.x; - amax = amax + af.z; - if(amin > 255) amin = 255; - if(amax > 255) amax = 255; - break; - case TFX_HIGHLIGHT2: - break; - default: - __assume(0); - } - } - else - { - amin = af.x; - amax = af.z; - } - - int aref = context->TEST.AREF; - - switch(context->TEST.ATST) - { - case ATST_NEVER: - pass = false; - break; - case ATST_ALWAYS: - pass = true; - break; - case ATST_LESS: - if(amax < aref) pass = true; - else if(amin >= aref) pass = false; - else return false; - break; - case ATST_LEQUAL: - if(amax <= aref) pass = true; - else if(amin > aref) pass = false; - else return false; - break; - case ATST_EQUAL: - if(amin == aref && amax == aref) pass = true; - else if(amin > aref || amax < aref) pass = false; - else return false; - break; - case ATST_GEQUAL: - if(amin >= aref) pass = true; - else if(amax < aref) pass = false; - else return false; - break; - case ATST_GREATER: - if(amin > aref) pass = true; - else if(amax <= aref) pass = false; - else return false; - break; - case ATST_NOTEQUAL: - if(amin == aref && amax == aref) pass = false; - else if(amin > aref || amax < aref) pass = true; - else return false; - break; - default: - __assume(0); - } - } - - if(!pass) - { - switch(context->TEST.AFAIL) - { - case AFAIL_KEEP: fm = zm = 0xffffffff; break; - case AFAIL_FB_ONLY: zm = 0xffffffff; break; - case AFAIL_ZB_ONLY: fm = 0xffffffff; break; - case AFAIL_RGB_ONLY: fm |= 0xff000000; zm = 0xffffffff; break; - default: __assume(0); - } - } - - return true; - } - - void GetScanlineParam(GSScanlineParam& p, GS_PRIM_CLASS primclass) - { - const GSDrawingEnvironment& env = m_env; - const GSDrawingContext* context = m_context; - - p.vm = m_mem.m_vm32; - - p.fbo = m_mem.GetOffset(context->FRAME.Block(), context->FRAME.FBW, context->FRAME.PSM); - p.zbo = m_mem.GetOffset(context->ZBUF.Block(), context->FRAME.FBW, context->ZBUF.PSM); - p.fzbo = m_mem.GetOffset4(context->FRAME, context->ZBUF); - - p.sel.dw = 0; - - p.sel.fpsm = 3; - p.sel.zpsm = 3; - p.sel.atst = ATST_ALWAYS; - p.sel.tfx = TFX_NONE; - p.sel.abe = 255; - p.sel.sprite = primclass == GS_SPRITE_CLASS ? 1 : 0; - - p.fm = context->FRAME.FBMSK; - p.zm = context->ZBUF.ZMSK || context->TEST.ZTE == 0 ? 0xffffffff : 0; - - if(context->TEST.ZTE && context->TEST.ZTST == ZTST_NEVER) - { - p.fm = 0xffffffff; - p.zm = 0xffffffff; - } - - if(PRIM->TME) - { - m_mem.m_clut.Read32(context->TEX0, env.TEXA); - } - - if(context->TEST.ATE) - { - if(!TryAlphaTest(p.fm, p.zm)) - { - p.sel.atst = context->TEST.ATST; - p.sel.afail = context->TEST.AFAIL; - } - } - - bool fwrite = p.fm != 0xffffffff; - bool ftest = p.sel.atst != ATST_ALWAYS || context->TEST.DATE && context->FRAME.PSM != PSM_PSMCT24; - - if(fwrite || ftest) - { - p.sel.fpsm = GSUtil::EncodePSM(context->FRAME.PSM); - - if((primclass == GS_LINE_CLASS || primclass == GS_TRIANGLE_CLASS) && m_vtrace.m_eq.rgba != 15) - { - p.sel.iip = PRIM->IIP; - } - - if(PRIM->TME) - { - p.sel.tfx = context->TEX0.TFX; - p.sel.tcc = context->TEX0.TCC; - p.sel.fst = PRIM->FST; - p.sel.ltf = context->TEX1.IsLinear(); - p.sel.tlu = GSLocalMemory::m_psm[context->TEX0.PSM].pal > 0; - - if(p.sel.iip == 0 && p.sel.tfx == TFX_MODULATE && p.sel.tcc) - { - if(m_vtrace.m_eq.rgba == 15 && (m_vtrace.m_min.c == GSVector4(128.0f * 128.0f)).alltrue()) - { - // modulate does not do anything when vertex color is 0x80 - - p.sel.tfx = TFX_DECAL; - } - } - - if(p.sel.tfx == TFX_DECAL) - { - p.sel.tcc = 1; - } - - if(p.sel.fst == 0) - { - // skip per pixel division if q is constant - - GSVertexSW* v = m_vertices; - - if(m_vtrace.m_eq.q) - { - p.sel.fst = 1; - - if(v[0].t.z != 1.0f) - { - GSVector4 w = v[0].t.zzzz().rcpnr(); - - for(int i = 0, j = m_count; i < j; i++) - { - v[i].t *= w; - } - - m_vtrace.m_min.t *= w; - m_vtrace.m_max.t *= w; - } - } - else if(primclass == GS_SPRITE_CLASS) - { - p.sel.fst = 1; - - GSVector4 tmin = GSVector4(FLT_MAX); - GSVector4 tmax = GSVector4(-FLT_MAX); - - for(int i = 0, j = m_count; i < j; i += 2) - { - GSVector4 w = v[i + 1].t.zzzz().rcpnr(); - - GSVector4 v0 = v[i + 0].t * w; - GSVector4 v1 = v[i + 1].t * w; - - v[i + 0].t = v0; - v[i + 1].t = v1; - - tmin = tmin.minv(v0).minv(v1); - tmax = tmax.maxv(v0).maxv(v1); - } - - m_vtrace.m_max.t = tmax; - m_vtrace.m_min.t = tmin; - } - } - - if(p.sel.fst) - { - // if q is constant we can do the half pel shift for bilinear sampling on the vertices - - if(p.sel.ltf) - { - GSVector4 half(0x8000, 0x8000); - - GSVertexSW* v = m_vertices; - - for(int i = 0, j = m_count; i < j; i++) - { - v[i].t -= half; - } - - m_vtrace.m_min.t -= half; - m_vtrace.m_max.t += half; - } - } - /* - else - { - GSVector4 tmin = GSVector4(FLT_MAX); - GSVector4 tmax = GSVector4(-FLT_MAX); - - GSVertexSW* v = m_vertices; - - for(int i = 0, j = m_count; i < j; i++) - { - GSVector4 v0 = v[i].t * v[i].t.zzzz().rcpnr(); - - tmin = tmin.minv(v0); - tmax = tmax.maxv(v0); - } - - if(p.sel.ltf) - { - GSVector4 half(0x8000, 0x8000); - - tmin -= half; - tmax += half; - } - - m_vtrace.min.t = tmin; - m_vtrace.max.t = tmax; - } - */ - - CRect r; - - int w = 1 << context->TEX0.TW; - int h = 1 << context->TEX0.TH; - - MinMaxUV(w, h, r, p.sel.fst); - - const GSTextureCacheSW::GSTexture* t = m_tc->Lookup(context->TEX0, env.TEXA, &r); - - if(!t) {ASSERT(0); return;} - - p.tex = t->m_buff; - p.clut = m_mem.m_clut; - p.tw = t->m_tw; - } - - p.sel.fge = PRIM->FGE; - - if(context->FRAME.PSM != PSM_PSMCT24) - { - p.sel.date = context->TEST.DATE; - } - - if(PRIM->ABE) - { - if(!context->ALPHA.IsOpaque()) - { - p.sel.abe = context->ALPHA.ai32[0]; - p.sel.pabe = env.PABE.PABE; - } - } - - if(PRIM->AA1) - { - // TODO: automatic alpha blending (ABE=1, A=0 B=1 C=0 D=1) - } - - if(p.sel.date - || p.sel.abea == 1 || p.sel.abeb == 1 || p.sel.abec == 1 || p.sel.abed == 1 - || p.sel.atst != ATST_ALWAYS && p.sel.afail == AFAIL_RGB_ONLY - || p.sel.fpsm == 0 && p.fm != 0 && p.fm != 0xffffffff - || p.sel.fpsm == 1 && (p.fm & 0x00ffffff) != 0 && (p.fm & 0x00ffffff) != 0x00ffffff - || p.sel.fpsm == 2 && (p.fm & 0x80f8f8f8) != 0 && (p.fm & 0x80f8f8f8) != 0x80f8f8f8) - { - p.sel.rfb = 1; - } - } - - bool zwrite = p.zm != 0xffffffff; - bool ztest = context->TEST.ZTE && context->TEST.ZTST > 1; - - if(zwrite || ztest) - { - p.sel.zpsm = GSUtil::EncodePSM(context->ZBUF.PSM); - p.sel.ztst = ztest ? context->TEST.ZTST : 1; - } - } - - void Draw() - { - m_vtrace.Update(m_vertices, m_count); - - GS_PRIM_CLASS primclass = GSUtil::GetPrimClass(PRIM->PRIM); - - GSScanlineParam p; - - GetScanlineParam(p, primclass); - - if((p.fm & p.zm) == 0xffffffff) - { - return; - } - - if(s_dump) - { - CString str; - str.Format(_T("c:\\temp1\\_%05d_f%I64d_tex_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), (int)m_context->TEX0.TBP0, (int)m_context->TEX0.PSM); - if(PRIM->TME) if(s_save) {m_mem.SaveBMP(str, m_context->TEX0.TBP0, m_context->TEX0.TBW, m_context->TEX0.PSM, 1 << m_context->TEX0.TW, 1 << m_context->TEX0.TH);} - str.Format(_T("c:\\temp1\\_%05d_f%I64d_rt0_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), m_context->FRAME.Block(), m_context->FRAME.PSM); - if(s_save) {m_mem.SaveBMP(str, m_context->FRAME.Block(), m_context->FRAME.FBW, m_context->FRAME.PSM, GetFrameSize(1).cx, 512);}//GetFrameSize(1).cy); - str.Format(_T("c:\\temp1\\_%05d_f%I64d_rz0_%05x_%d.bmp"), s_n-1, m_perfmon.GetFrame(), m_context->ZBUF.Block(), m_context->ZBUF.PSM); - if(s_savez) {m_mem.SaveBMP(str, m_context->ZBUF.Block(), m_context->FRAME.FBW, m_context->ZBUF.PSM, GetFrameSize(1).cx, 512);} - } - - GSRasterizerData data; - - data.scissor = GSVector4i(m_context->scissor.in); - data.scissor.z = min(data.scissor.z, (int)m_context->FRAME.FBW * 64); // TODO: find a game that overflows and check which one is the right behaviour - data.primclass = primclass; - data.vertices = m_vertices; - data.count = m_count; - data.param = &p; - - m_rl.Draw(&data); - - GSRasterizerStats stats; - - m_rl.GetStats(stats); - - m_perfmon.Put(GSPerfMon::Draw, 1); - m_perfmon.Put(GSPerfMon::Prim, stats.prims); - m_perfmon.Put(GSPerfMon::Fillrate, stats.pixels); - - GSVector4i pos(m_vtrace.m_min.p.xyxy(m_vtrace.m_max.p)); - - GSVector4i scissor = data.scissor; - - CRect r; - - r.left = max(scissor.x, min(scissor.z, pos.x)); - r.top = max(scissor.y, min(scissor.w, pos.y)); - r.right = max(scissor.x, min(scissor.z, pos.z)); - r.bottom = max(scissor.y, min(scissor.w, pos.w)); - - GIFRegBITBLTBUF BITBLTBUF; - - BITBLTBUF.DBW = m_context->FRAME.FBW; - - if(p.fm != 0xffffffff) - { - BITBLTBUF.DBP = m_context->FRAME.Block(); - BITBLTBUF.DPSM = m_context->FRAME.PSM; - - m_tc->InvalidateVideoMem(BITBLTBUF, r); - } - - if(p.zm != 0xffffffff) - { - BITBLTBUF.DBP = m_context->ZBUF.Block(); - BITBLTBUF.DPSM = m_context->ZBUF.PSM; - - m_tc->InvalidateVideoMem(BITBLTBUF, r); - } - - if(s_dump) - { - CString str; - str.Format(_T("c:\\temp1\\_%05d_f%I64d_rt1_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), m_context->FRAME.Block(), m_context->FRAME.PSM); - if(s_save) {m_mem.SaveBMP(str, m_context->FRAME.Block(), m_context->FRAME.FBW, m_context->FRAME.PSM, GetFrameSize(1).cx, 512);}//GetFrameSize(1).cy); - str.Format(_T("c:\\temp1\\_%05d_f%I64d_rz1_%05x_%d.bmp"), s_n-1, m_perfmon.GetFrame(), m_context->ZBUF.Block(), m_context->ZBUF.PSM); - if(s_savez) {m_mem.SaveBMP(str, m_context->ZBUF.Block(), m_context->FRAME.FBW, m_context->ZBUF.PSM, GetFrameSize(1).cx, 512);} - } - } - - void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r) - { - m_tc->InvalidateVideoMem(BITBLTBUF, r); - } - - void MinMaxUV(int w, int h, CRect& r, DWORD fst) - { - const GSDrawingContext* context = m_context; - - int wms = context->CLAMP.WMS; - int wmt = context->CLAMP.WMT; - - int minu = (int)context->CLAMP.MINU; - int minv = (int)context->CLAMP.MINV; - int maxu = (int)context->CLAMP.MAXU; - int maxv = (int)context->CLAMP.MAXV; - - GSVector4i vr(0, 0, w, h); - - switch(wms) - { - case CLAMP_REPEAT: - break; - case CLAMP_CLAMP: - break; - case CLAMP_REGION_CLAMP: - if(vr.x < minu) vr.x = minu; - if(vr.z > maxu + 1) vr.z = maxu + 1; - break; - case CLAMP_REGION_REPEAT: - vr.x = maxu; - vr.z = vr.x + (minu + 1); - break; - default: - __assume(0); - } - - switch(wmt) - { - case CLAMP_REPEAT: - break; - case CLAMP_CLAMP: - break; - case CLAMP_REGION_CLAMP: - if(vr.y < minv) vr.y = minv; - if(vr.w > maxv + 1) vr.w = maxv + 1; - break; - case CLAMP_REGION_REPEAT: - vr.y = maxv; - vr.w = vr.y + (minv + 1); - break; - default: - __assume(0); - } - - if(fst) - { - GSVector4i uv = GSVector4i(m_vtrace.m_min.t.xyxy(m_vtrace.m_max.t)).sra32(16); -/* - int tw = context->TEX0.TW; - int th = context->TEX0.TH; - - GSVector4i u = uv & GSVector4i::xffffffff().srl32(32 - tw); - GSVector4i v = uv & GSVector4i::xffffffff().srl32(32 - th); - - GSVector4i uu = uv.sra32(tw); - GSVector4i vv = uv.sra32(th); - - int mask = (uu.upl32(vv) == uu.uph32(vv)).mask(); -*/ - switch(wms) - { - case CLAMP_REPEAT: -/* - if(mask & 0x000f) - { - if(vr.x < u.x) vr.x = u.x; - if(vr.z > u.z + 1) vr.z = u.z + 1; - } -*/ - break; - case CLAMP_CLAMP: - case CLAMP_REGION_CLAMP: - if(vr.x < uv.x) vr.x = uv.x; - if(vr.z > uv.z + 1) vr.z = uv.z + 1; - break; - case CLAMP_REGION_REPEAT: // TODO - break; - default: - __assume(0); - } - - switch(wmt) - { - case CLAMP_REPEAT: -/* - if(mask & 0xf000) - { - if(vr.y < v.y) vr.y = v.y; - if(vr.w > v.w + 1) vr.w = v.w + 1; - } -*/ - break; - case CLAMP_CLAMP: - case CLAMP_REGION_CLAMP: - if(vr.y < uv.y) vr.y = uv.y; - if(vr.w > uv.w + 1) vr.w = uv.w + 1; - break; - case CLAMP_REGION_REPEAT: // TODO - break; - default: - __assume(0); - } - } - - r = vr; - - r &= CRect(0, 0, w, h); - } - -public: - GSRendererSW(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs, int threads) - : GSRendererT(base, mt, irq, nloophack, rs) - { - m_rl.Create(this, threads); - - m_tc = new GSTextureCacheSW(this); - - InitVertexKick >(); - } - - virtual ~GSRendererSW() - { - delete m_tc; - } - - template - void VertexKick(bool skip) - { - const GSDrawingContext* context = m_context; - - GSVector4i xy = GSVector4i::load((int)m_v.XYZ.ai32[0]); - - xy = xy.insert16<3>(m_v.FOG.F); - xy = xy.upl16(); - xy -= context->XYOFFSET; - - GSVertexSW v; - - v.p = GSVector4(xy) * g_pos_scale; - - v.c = GSVector4(GSVector4i::load((int)m_v.RGBAQ.ai32[0]).u8to32() << 7); - - if(tme) - { - float q; - - if(fst) - { - v.t = GSVector4(((GSVector4i)m_v.UV).upl16() << (16 - 4)); - q = 1.0f; - } - else - { - v.t = GSVector4(m_v.ST.S, m_v.ST.T); - v.t *= GSVector4(0x10000 << context->TEX0.TW, 0x10000 << context->TEX0.TH); - q = m_v.RGBAQ.Q; - } - - v.t = v.t.xyxy(GSVector4::load(q)); - } - - GSVertexSW& dst = m_vl.AddTail(); - - dst = v; - - dst.p.z = (float)min(m_v.XYZ.Z, 0xffffff00); // max value which can survive the DWORD => float => DWORD conversion - - DWORD count = 0; - - if(GSVertexSW* v = DrawingKick(skip, count)) - { - GSVector4 pmin, pmax; - - switch(prim) - { - case GS_POINTLIST: - pmin = v[0].p; - pmax = v[0].p; - break; - case GS_LINELIST: - case GS_LINESTRIP: - case GS_SPRITE: - pmin = v[0].p.minv(v[1].p); - pmax = v[0].p.maxv(v[1].p); - break; - case GS_TRIANGLELIST: - case GS_TRIANGLESTRIP: - case GS_TRIANGLEFAN: - pmin = v[0].p.minv(v[1].p).minv(v[2].p); - pmax = v[0].p.maxv(v[1].p).maxv(v[2].p); - break; - } - - GSVector4 scissor = context->scissor.ex; - - GSVector4 test = (pmax < scissor) | (pmin > scissor.zwxy()); - - switch(prim) - { - case GS_TRIANGLELIST: - case GS_TRIANGLESTRIP: - case GS_TRIANGLEFAN: - case GS_SPRITE: - test |= pmin.ceil() == pmax.ceil(); - break; - } - - if(test.mask() & 3) - { - return; - } - - switch(prim) - { - case GS_POINTLIST: - break; - case GS_LINELIST: - case GS_LINESTRIP: - if(PRIM->IIP == 0) {v[0].c = v[1].c;} - break; - case GS_TRIANGLELIST: - case GS_TRIANGLESTRIP: - case GS_TRIANGLEFAN: - if(PRIM->IIP == 0) {v[0].c = v[2].c; v[1].c = v[2].c;} - break; - case GS_SPRITE: - break; - } - - if(m_count >= 3 && m_count < 30) - { - GSVertexSW* v = &m_vertices[m_count - 3]; - - int tl = 0; - int br = 0; - - bool isquad = false; - - switch(prim) - { - case GS_TRIANGLESTRIP: - case GS_TRIANGLEFAN: - case GS_TRIANGLELIST: - isquad = GSVertexSW::IsQuad(v, tl, br); - break; - } - - if(isquad) - { - m_count -= 3; - - if(m_count > 0) - { - tl += m_count; - br += m_count; - - Flush(); - } - - if(tl != 0) m_vertices[0] = m_vertices[tl]; - if(br != 1) m_vertices[1] = m_vertices[br]; - - m_count = 2; - - UINT32 tmp = PRIM->PRIM; - PRIM->PRIM = GS_SPRITE; - - Flush(); - - PRIM->PRIM = tmp; - - m_perfmon.Put(GSPerfMon::Quad, 1); - - return; - } - } - - m_count += count; - } - } -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSRenderer.h" +#include "GSTextureCacheSW.h" +#include "GSDrawScanline.h" + +extern const GSVector4 g_pos_scale; + +template +class GSRendererSW : public GSRendererT +{ +protected: + GSRasterizerList m_rl; + GSTextureCacheSW* m_tc; + GSVertexTrace m_vtrace; + Texture m_texture[2]; + bool m_reset; + + void Reset() + { + // TODO: GSreset can come from the main thread too => crash + // m_tc->RemoveAll(); + + m_reset = true; + + __super::Reset(); + } + + void VSync(int field) + { + __super::VSync(field); + + m_tc->IncAge(); + + if(m_reset) + { + m_tc->RemoveAll(); + + m_reset = false; + } + + // if((m_perfmon.GetFrame() & 255) == 0) m_rl.PrintStats(); + } + + void ResetDevice() + { + m_texture[0] = Texture(); + m_texture[1] = Texture(); + } + + bool GetOutput(int i, Texture& t) + { + CRect r(0, 0, DISPFB[i]->FBW * 64, GetFrameRect(i).bottom); + + // TODO: round up bottom + + if(m_texture[i].GetWidth() != r.Width() || m_texture[i].GetHeight() != r.Height()) + { + m_texture[i] = Texture(); + } + + if(!m_texture[i] && !m_dev.CreateTexture(m_texture[i], r.Width(), r.Height())) + { + return false; + } + + GIFRegTEX0 TEX0; + + TEX0.TBP0 = DISPFB[i]->Block(); + TEX0.TBW = DISPFB[i]->FBW; + TEX0.PSM = DISPFB[i]->PSM; + + GIFRegCLAMP CLAMP; + + CLAMP.WMS = CLAMP.WMT = 1; + + // TODO + static BYTE* buff = (BYTE*)_aligned_malloc(1024 * 1024 * 4, 16); + static int pitch = 1024 * 4; + + m_mem.ReadTexture(r, buff, pitch, TEX0, m_env.TEXA, CLAMP); + + m_texture[i].Update(r, buff, pitch); + + t = m_texture[i]; + + if(s_dump) + { + CString str; + str.Format(_T("c:\\temp1\\_%05d_f%I64d_fr%d_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), i, (int)TEX0.TBP0, (int)TEX0.PSM); + if(s_save) t.Save(str); + } + + return true; + } + + bool TryAlphaTest(DWORD& fm, DWORD& zm) + { + const GSDrawingEnvironment& env = m_env; + const GSDrawingContext* context = m_context; + + bool pass = true; + + if(context->TEST.ATST == ATST_NEVER) + { + pass = false; + } + else if(context->TEST.ATST != ATST_ALWAYS) + { + GSVector4i af = GSVector4i(m_vtrace.m_min.c.wwww(m_vtrace.m_max.c)) >> 7; + + int amin, amax; + + if(PRIM->TME && (context->TEX0.TCC || context->TEX0.TFX == TFX_DECAL)) + { + DWORD bpp = GSLocalMemory::m_psm[context->TEX0.PSM].trbpp; + DWORD cbpp = GSLocalMemory::m_psm[context->TEX0.CPSM].trbpp; + DWORD pal = GSLocalMemory::m_psm[context->TEX0.PSM].pal; + + if(bpp == 32) + { + return false; + } + else if(bpp == 24) + { + amin = env.TEXA.AEM ? 0 : env.TEXA.TA0; + amax = env.TEXA.TA0; + } + else if(bpp == 16) + { + amin = env.TEXA.AEM ? 0 : min(env.TEXA.TA0, env.TEXA.TA1); + amax = max(env.TEXA.TA0, env.TEXA.TA1); + } + else + { + m_mem.m_clut.GetAlphaMinMax32(amin, amax); + } + + switch(context->TEX0.TFX) + { + case TFX_MODULATE: + amin = (amin * af.x) >> 7; + amax = (amax * af.z) >> 7; + if(amin > 255) amin = 255; + if(amax > 255) amax = 255; + break; + case TFX_DECAL: + break; + case TFX_HIGHLIGHT: + amin = amin + af.x; + amax = amax + af.z; + if(amin > 255) amin = 255; + if(amax > 255) amax = 255; + break; + case TFX_HIGHLIGHT2: + break; + default: + __assume(0); + } + } + else + { + amin = af.x; + amax = af.z; + } + + int aref = context->TEST.AREF; + + switch(context->TEST.ATST) + { + case ATST_NEVER: + pass = false; + break; + case ATST_ALWAYS: + pass = true; + break; + case ATST_LESS: + if(amax < aref) pass = true; + else if(amin >= aref) pass = false; + else return false; + break; + case ATST_LEQUAL: + if(amax <= aref) pass = true; + else if(amin > aref) pass = false; + else return false; + break; + case ATST_EQUAL: + if(amin == aref && amax == aref) pass = true; + else if(amin > aref || amax < aref) pass = false; + else return false; + break; + case ATST_GEQUAL: + if(amin >= aref) pass = true; + else if(amax < aref) pass = false; + else return false; + break; + case ATST_GREATER: + if(amin > aref) pass = true; + else if(amax <= aref) pass = false; + else return false; + break; + case ATST_NOTEQUAL: + if(amin == aref && amax == aref) pass = false; + else if(amin > aref || amax < aref) pass = true; + else return false; + break; + default: + __assume(0); + } + } + + if(!pass) + { + switch(context->TEST.AFAIL) + { + case AFAIL_KEEP: fm = zm = 0xffffffff; break; + case AFAIL_FB_ONLY: zm = 0xffffffff; break; + case AFAIL_ZB_ONLY: fm = 0xffffffff; break; + case AFAIL_RGB_ONLY: fm |= 0xff000000; zm = 0xffffffff; break; + default: __assume(0); + } + } + + return true; + } + + void GetScanlineParam(GSScanlineParam& p, GS_PRIM_CLASS primclass) + { + const GSDrawingEnvironment& env = m_env; + const GSDrawingContext* context = m_context; + + p.vm = m_mem.m_vm32; + + p.fbo = m_mem.GetOffset(context->FRAME.Block(), context->FRAME.FBW, context->FRAME.PSM); + p.zbo = m_mem.GetOffset(context->ZBUF.Block(), context->FRAME.FBW, context->ZBUF.PSM); + p.fzbo = m_mem.GetOffset4(context->FRAME, context->ZBUF); + + p.sel.dw = 0; + + p.sel.fpsm = 3; + p.sel.zpsm = 3; + p.sel.atst = ATST_ALWAYS; + p.sel.tfx = TFX_NONE; + p.sel.abe = 255; + p.sel.sprite = primclass == GS_SPRITE_CLASS ? 1 : 0; + + p.fm = context->FRAME.FBMSK; + p.zm = context->ZBUF.ZMSK || context->TEST.ZTE == 0 ? 0xffffffff : 0; + + if(context->TEST.ZTE && context->TEST.ZTST == ZTST_NEVER) + { + p.fm = 0xffffffff; + p.zm = 0xffffffff; + } + + if(PRIM->TME) + { + m_mem.m_clut.Read32(context->TEX0, env.TEXA); + } + + if(context->TEST.ATE) + { + if(!TryAlphaTest(p.fm, p.zm)) + { + p.sel.atst = context->TEST.ATST; + p.sel.afail = context->TEST.AFAIL; + } + } + + bool fwrite = p.fm != 0xffffffff; + bool ftest = p.sel.atst != ATST_ALWAYS || context->TEST.DATE && context->FRAME.PSM != PSM_PSMCT24; + + if(fwrite || ftest) + { + p.sel.fpsm = GSUtil::EncodePSM(context->FRAME.PSM); + + if((primclass == GS_LINE_CLASS || primclass == GS_TRIANGLE_CLASS) && m_vtrace.m_eq.rgba != 15) + { + p.sel.iip = PRIM->IIP; + } + + if(PRIM->TME) + { + p.sel.tfx = context->TEX0.TFX; + p.sel.tcc = context->TEX0.TCC; + p.sel.fst = PRIM->FST; + p.sel.ltf = context->TEX1.IsLinear(); + p.sel.tlu = GSLocalMemory::m_psm[context->TEX0.PSM].pal > 0; + + if(p.sel.iip == 0 && p.sel.tfx == TFX_MODULATE && p.sel.tcc) + { + if(m_vtrace.m_eq.rgba == 15 && (m_vtrace.m_min.c == GSVector4(128.0f * 128.0f)).alltrue()) + { + // modulate does not do anything when vertex color is 0x80 + + p.sel.tfx = TFX_DECAL; + } + } + + if(p.sel.tfx == TFX_DECAL) + { + p.sel.tcc = 1; + } + + if(p.sel.fst == 0) + { + // skip per pixel division if q is constant + + GSVertexSW* v = m_vertices; + + if(m_vtrace.m_eq.q) + { + p.sel.fst = 1; + + if(v[0].t.z != 1.0f) + { + GSVector4 w = v[0].t.zzzz().rcpnr(); + + for(int i = 0, j = m_count; i < j; i++) + { + v[i].t *= w; + } + + m_vtrace.m_min.t *= w; + m_vtrace.m_max.t *= w; + } + } + else if(primclass == GS_SPRITE_CLASS) + { + p.sel.fst = 1; + + GSVector4 tmin = GSVector4(FLT_MAX); + GSVector4 tmax = GSVector4(-FLT_MAX); + + for(int i = 0, j = m_count; i < j; i += 2) + { + GSVector4 w = v[i + 1].t.zzzz().rcpnr(); + + GSVector4 v0 = v[i + 0].t * w; + GSVector4 v1 = v[i + 1].t * w; + + v[i + 0].t = v0; + v[i + 1].t = v1; + + tmin = tmin.minv(v0).minv(v1); + tmax = tmax.maxv(v0).maxv(v1); + } + + m_vtrace.m_max.t = tmax; + m_vtrace.m_min.t = tmin; + } + } + + if(p.sel.fst) + { + // if q is constant we can do the half pel shift for bilinear sampling on the vertices + + if(p.sel.ltf) + { + GSVector4 half(0x8000, 0x8000); + + GSVertexSW* v = m_vertices; + + for(int i = 0, j = m_count; i < j; i++) + { + v[i].t -= half; + } + + m_vtrace.m_min.t -= half; + m_vtrace.m_max.t += half; + } + } + /* + else + { + GSVector4 tmin = GSVector4(FLT_MAX); + GSVector4 tmax = GSVector4(-FLT_MAX); + + GSVertexSW* v = m_vertices; + + for(int i = 0, j = m_count; i < j; i++) + { + GSVector4 v0 = v[i].t * v[i].t.zzzz().rcpnr(); + + tmin = tmin.minv(v0); + tmax = tmax.maxv(v0); + } + + if(p.sel.ltf) + { + GSVector4 half(0x8000, 0x8000); + + tmin -= half; + tmax += half; + } + + m_vtrace.min.t = tmin; + m_vtrace.max.t = tmax; + } + */ + + CRect r; + + int w = 1 << context->TEX0.TW; + int h = 1 << context->TEX0.TH; + + MinMaxUV(w, h, r, p.sel.fst); + + const GSTextureCacheSW::GSTexture* t = m_tc->Lookup(context->TEX0, env.TEXA, &r); + + if(!t) {ASSERT(0); return;} + + p.tex = t->m_buff; + p.clut = m_mem.m_clut; + p.tw = t->m_tw; + } + + p.sel.fge = PRIM->FGE; + + if(context->FRAME.PSM != PSM_PSMCT24) + { + p.sel.date = context->TEST.DATE; + } + + if(PRIM->ABE) + { + if(!context->ALPHA.IsOpaque()) + { + p.sel.abe = context->ALPHA.ai32[0]; + p.sel.pabe = env.PABE.PABE; + } + } + + if(PRIM->AA1) + { + // TODO: automatic alpha blending (ABE=1, A=0 B=1 C=0 D=1) + } + + if(p.sel.date + || p.sel.abea == 1 || p.sel.abeb == 1 || p.sel.abec == 1 || p.sel.abed == 1 + || p.sel.atst != ATST_ALWAYS && p.sel.afail == AFAIL_RGB_ONLY + || p.sel.fpsm == 0 && p.fm != 0 && p.fm != 0xffffffff + || p.sel.fpsm == 1 && (p.fm & 0x00ffffff) != 0 && (p.fm & 0x00ffffff) != 0x00ffffff + || p.sel.fpsm == 2 && (p.fm & 0x80f8f8f8) != 0 && (p.fm & 0x80f8f8f8) != 0x80f8f8f8) + { + p.sel.rfb = 1; + } + } + + bool zwrite = p.zm != 0xffffffff; + bool ztest = context->TEST.ZTE && context->TEST.ZTST > 1; + + if(zwrite || ztest) + { + p.sel.zpsm = GSUtil::EncodePSM(context->ZBUF.PSM); + p.sel.ztst = ztest ? context->TEST.ZTST : 1; + } + } + + void Draw() + { + m_vtrace.Update(m_vertices, m_count); + + GS_PRIM_CLASS primclass = GSUtil::GetPrimClass(PRIM->PRIM); + + GSScanlineParam p; + + GetScanlineParam(p, primclass); + + if((p.fm & p.zm) == 0xffffffff) + { + return; + } + + if(s_dump) + { + CString str; + str.Format(_T("c:\\temp1\\_%05d_f%I64d_tex_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), (int)m_context->TEX0.TBP0, (int)m_context->TEX0.PSM); + if(PRIM->TME) if(s_save) {m_mem.SaveBMP(str, m_context->TEX0.TBP0, m_context->TEX0.TBW, m_context->TEX0.PSM, 1 << m_context->TEX0.TW, 1 << m_context->TEX0.TH);} + str.Format(_T("c:\\temp1\\_%05d_f%I64d_rt0_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), m_context->FRAME.Block(), m_context->FRAME.PSM); + if(s_save) {m_mem.SaveBMP(str, m_context->FRAME.Block(), m_context->FRAME.FBW, m_context->FRAME.PSM, GetFrameSize(1).cx, 512);}//GetFrameSize(1).cy); + str.Format(_T("c:\\temp1\\_%05d_f%I64d_rz0_%05x_%d.bmp"), s_n-1, m_perfmon.GetFrame(), m_context->ZBUF.Block(), m_context->ZBUF.PSM); + if(s_savez) {m_mem.SaveBMP(str, m_context->ZBUF.Block(), m_context->FRAME.FBW, m_context->ZBUF.PSM, GetFrameSize(1).cx, 512);} + } + + GSRasterizerData data; + + data.scissor = GSVector4i(m_context->scissor.in); + data.scissor.z = min(data.scissor.z, (int)m_context->FRAME.FBW * 64); // TODO: find a game that overflows and check which one is the right behaviour + data.primclass = primclass; + data.vertices = m_vertices; + data.count = m_count; + data.param = &p; + + m_rl.Draw(&data); + + GSRasterizerStats stats; + + m_rl.GetStats(stats); + + m_perfmon.Put(GSPerfMon::Draw, 1); + m_perfmon.Put(GSPerfMon::Prim, stats.prims); + m_perfmon.Put(GSPerfMon::Fillrate, stats.pixels); + + GSVector4i pos(m_vtrace.m_min.p.xyxy(m_vtrace.m_max.p)); + + GSVector4i scissor = data.scissor; + + CRect r; + + r.left = max(scissor.x, min(scissor.z, pos.x)); + r.top = max(scissor.y, min(scissor.w, pos.y)); + r.right = max(scissor.x, min(scissor.z, pos.z)); + r.bottom = max(scissor.y, min(scissor.w, pos.w)); + + GIFRegBITBLTBUF BITBLTBUF; + + BITBLTBUF.DBW = m_context->FRAME.FBW; + + if(p.fm != 0xffffffff) + { + BITBLTBUF.DBP = m_context->FRAME.Block(); + BITBLTBUF.DPSM = m_context->FRAME.PSM; + + m_tc->InvalidateVideoMem(BITBLTBUF, r); + } + + if(p.zm != 0xffffffff) + { + BITBLTBUF.DBP = m_context->ZBUF.Block(); + BITBLTBUF.DPSM = m_context->ZBUF.PSM; + + m_tc->InvalidateVideoMem(BITBLTBUF, r); + } + + if(s_dump) + { + CString str; + str.Format(_T("c:\\temp1\\_%05d_f%I64d_rt1_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), m_context->FRAME.Block(), m_context->FRAME.PSM); + if(s_save) {m_mem.SaveBMP(str, m_context->FRAME.Block(), m_context->FRAME.FBW, m_context->FRAME.PSM, GetFrameSize(1).cx, 512);}//GetFrameSize(1).cy); + str.Format(_T("c:\\temp1\\_%05d_f%I64d_rz1_%05x_%d.bmp"), s_n-1, m_perfmon.GetFrame(), m_context->ZBUF.Block(), m_context->ZBUF.PSM); + if(s_savez) {m_mem.SaveBMP(str, m_context->ZBUF.Block(), m_context->FRAME.FBW, m_context->ZBUF.PSM, GetFrameSize(1).cx, 512);} + } + } + + void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r) + { + m_tc->InvalidateVideoMem(BITBLTBUF, r); + } + + void MinMaxUV(int w, int h, CRect& r, DWORD fst) + { + const GSDrawingContext* context = m_context; + + int wms = context->CLAMP.WMS; + int wmt = context->CLAMP.WMT; + + int minu = (int)context->CLAMP.MINU; + int minv = (int)context->CLAMP.MINV; + int maxu = (int)context->CLAMP.MAXU; + int maxv = (int)context->CLAMP.MAXV; + + GSVector4i vr(0, 0, w, h); + + switch(wms) + { + case CLAMP_REPEAT: + break; + case CLAMP_CLAMP: + break; + case CLAMP_REGION_CLAMP: + if(vr.x < minu) vr.x = minu; + if(vr.z > maxu + 1) vr.z = maxu + 1; + break; + case CLAMP_REGION_REPEAT: + vr.x = maxu; + vr.z = vr.x + (minu + 1); + break; + default: + __assume(0); + } + + switch(wmt) + { + case CLAMP_REPEAT: + break; + case CLAMP_CLAMP: + break; + case CLAMP_REGION_CLAMP: + if(vr.y < minv) vr.y = minv; + if(vr.w > maxv + 1) vr.w = maxv + 1; + break; + case CLAMP_REGION_REPEAT: + vr.y = maxv; + vr.w = vr.y + (minv + 1); + break; + default: + __assume(0); + } + + if(fst) + { + GSVector4i uv = GSVector4i(m_vtrace.m_min.t.xyxy(m_vtrace.m_max.t)).sra32(16); +/* + int tw = context->TEX0.TW; + int th = context->TEX0.TH; + + GSVector4i u = uv & GSVector4i::xffffffff().srl32(32 - tw); + GSVector4i v = uv & GSVector4i::xffffffff().srl32(32 - th); + + GSVector4i uu = uv.sra32(tw); + GSVector4i vv = uv.sra32(th); + + int mask = (uu.upl32(vv) == uu.uph32(vv)).mask(); +*/ + switch(wms) + { + case CLAMP_REPEAT: +/* + if(mask & 0x000f) + { + if(vr.x < u.x) vr.x = u.x; + if(vr.z > u.z + 1) vr.z = u.z + 1; + } +*/ + break; + case CLAMP_CLAMP: + case CLAMP_REGION_CLAMP: + if(vr.x < uv.x) vr.x = uv.x; + if(vr.z > uv.z + 1) vr.z = uv.z + 1; + break; + case CLAMP_REGION_REPEAT: // TODO + break; + default: + __assume(0); + } + + switch(wmt) + { + case CLAMP_REPEAT: +/* + if(mask & 0xf000) + { + if(vr.y < v.y) vr.y = v.y; + if(vr.w > v.w + 1) vr.w = v.w + 1; + } +*/ + break; + case CLAMP_CLAMP: + case CLAMP_REGION_CLAMP: + if(vr.y < uv.y) vr.y = uv.y; + if(vr.w > uv.w + 1) vr.w = uv.w + 1; + break; + case CLAMP_REGION_REPEAT: // TODO + break; + default: + __assume(0); + } + } + + r = vr; + + r &= CRect(0, 0, w, h); + } + +public: + GSRendererSW(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs, int threads) + : GSRendererT(base, mt, irq, nloophack, rs) + { + m_rl.Create(this, threads); + + m_tc = new GSTextureCacheSW(this); + + InitVertexKick >(); + } + + virtual ~GSRendererSW() + { + delete m_tc; + } + + template + void VertexKick(bool skip) + { + const GSDrawingContext* context = m_context; + + GSVector4i xy = GSVector4i::load((int)m_v.XYZ.ai32[0]); + + xy = xy.insert16<3>(m_v.FOG.F); + xy = xy.upl16(); + xy -= context->XYOFFSET; + + GSVertexSW v; + + v.p = GSVector4(xy) * g_pos_scale; + + v.c = GSVector4(GSVector4i::load((int)m_v.RGBAQ.ai32[0]).u8to32() << 7); + + if(tme) + { + float q; + + if(fst) + { + v.t = GSVector4(((GSVector4i)m_v.UV).upl16() << (16 - 4)); + q = 1.0f; + } + else + { + v.t = GSVector4(m_v.ST.S, m_v.ST.T); + v.t *= GSVector4(0x10000 << context->TEX0.TW, 0x10000 << context->TEX0.TH); + q = m_v.RGBAQ.Q; + } + + v.t = v.t.xyxy(GSVector4::load(q)); + } + + GSVertexSW& dst = m_vl.AddTail(); + + dst = v; + + dst.p.z = (float)min(m_v.XYZ.Z, 0xffffff00); // max value which can survive the DWORD => float => DWORD conversion + + DWORD count = 0; + + if(GSVertexSW* v = DrawingKick(skip, count)) + { + GSVector4 pmin, pmax; + + switch(prim) + { + case GS_POINTLIST: + pmin = v[0].p; + pmax = v[0].p; + break; + case GS_LINELIST: + case GS_LINESTRIP: + case GS_SPRITE: + pmin = v[0].p.minv(v[1].p); + pmax = v[0].p.maxv(v[1].p); + break; + case GS_TRIANGLELIST: + case GS_TRIANGLESTRIP: + case GS_TRIANGLEFAN: + pmin = v[0].p.minv(v[1].p).minv(v[2].p); + pmax = v[0].p.maxv(v[1].p).maxv(v[2].p); + break; + } + + GSVector4 scissor = context->scissor.ex; + + GSVector4 test = (pmax < scissor) | (pmin > scissor.zwxy()); + + switch(prim) + { + case GS_TRIANGLELIST: + case GS_TRIANGLESTRIP: + case GS_TRIANGLEFAN: + case GS_SPRITE: + test |= pmin.ceil() == pmax.ceil(); + break; + } + + if(test.mask() & 3) + { + return; + } + + switch(prim) + { + case GS_POINTLIST: + break; + case GS_LINELIST: + case GS_LINESTRIP: + if(PRIM->IIP == 0) {v[0].c = v[1].c;} + break; + case GS_TRIANGLELIST: + case GS_TRIANGLESTRIP: + case GS_TRIANGLEFAN: + if(PRIM->IIP == 0) {v[0].c = v[2].c; v[1].c = v[2].c;} + break; + case GS_SPRITE: + break; + } + + if(m_count >= 3 && m_count < 30) + { + GSVertexSW* v = &m_vertices[m_count - 3]; + + int tl = 0; + int br = 0; + + bool isquad = false; + + switch(prim) + { + case GS_TRIANGLESTRIP: + case GS_TRIANGLEFAN: + case GS_TRIANGLELIST: + isquad = GSVertexSW::IsQuad(v, tl, br); + break; + } + + if(isquad) + { + m_count -= 3; + + if(m_count > 0) + { + tl += m_count; + br += m_count; + + Flush(); + } + + if(tl != 0) m_vertices[0] = m_vertices[tl]; + if(br != 1) m_vertices[1] = m_vertices[br]; + + m_count = 2; + + UINT32 tmp = PRIM->PRIM; + PRIM->PRIM = GS_SPRITE; + + Flush(); + + PRIM->PRIM = tmp; + + m_perfmon.Put(GSPerfMon::Quad, 1); + + return; + } + } + + m_count += count; + } + } +}; diff --git a/plugins/GSdx/GSSetting.cpp b/plugins/GSdx/GSSetting.cpp index 0221e7b54f..6094fb5e9b 100644 --- a/plugins/GSdx/GSSetting.cpp +++ b/plugins/GSdx/GSSetting.cpp @@ -1,24 +1,24 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSSetting.h" - +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSSetting.h" + diff --git a/plugins/GSdx/GSSetting.h b/plugins/GSdx/GSSetting.h index c771fb2243..0124dc014a 100644 --- a/plugins/GSdx/GSSetting.h +++ b/plugins/GSdx/GSSetting.h @@ -1,45 +1,45 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -struct GSSetting -{ - DWORD id; - const TCHAR* name; - const TCHAR* note; - - static void InitComboBox(const GSSetting* settings, int count, CComboBox& combobox, DWORD sel, DWORD maxid = ~0) - { - for(int i = 0; i < count; i++) - { - if(settings[i].id <= maxid) - { - CString str = settings[i].name; - if(settings[i].note != NULL) str = str + _T(" (") + settings[i].note + _T(")"); - int item = combobox.AddString(str); - combobox.SetItemData(item, settings[i].id); - if(settings[i].id == sel) combobox.SetCurSel(item); - } - } - } - -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +struct GSSetting +{ + DWORD id; + const TCHAR* name; + const TCHAR* note; + + static void InitComboBox(const GSSetting* settings, int count, CComboBox& combobox, DWORD sel, DWORD maxid = ~0) + { + for(int i = 0; i < count; i++) + { + if(settings[i].id <= maxid) + { + CString str = settings[i].name; + if(settings[i].note != NULL) str = str + _T(" (") + settings[i].note + _T(")"); + int item = combobox.AddString(str); + combobox.SetItemData(item, settings[i].id); + if(settings[i].id == sel) combobox.SetCurSel(item); + } + } + } + +}; diff --git a/plugins/GSdx/GSSettingsDlg.cpp b/plugins/GSdx/GSSettingsDlg.cpp index 903108cf52..5186208229 100644 --- a/plugins/GSdx/GSSettingsDlg.cpp +++ b/plugins/GSdx/GSSettingsDlg.cpp @@ -1,324 +1,324 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GSdx.h" -#include "GSSettingsDlg.h" -#include "GSUtil.h" -#include -#include - -GSSetting GSSettingsDlg::g_renderers[] = -{ - {0, _T("Direct3D9 (Hardware)"), NULL}, - {1, _T("Direct3D9 (Software)"), NULL}, - {2, _T("Direct3D9 (Null)"), NULL}, - {3, _T("Direct3D10 (Hardware)"), NULL}, - {4, _T("Direct3D10 (Software)"), NULL}, - {5, _T("Direct3D10 (Null)"), NULL}, - {6, _T("Null (Software)"), NULL}, - {7, _T("Null (Null)"), NULL}, -}; - -GSSetting GSSettingsDlg::g_psversion[] = -{ - {D3DPS_VERSION(3, 0), _T("Pixel Shader 3.0"), NULL}, - {D3DPS_VERSION(2, 0), _T("Pixel Shader 2.0"), NULL}, - //{D3DPS_VERSION(1, 4), _T("Pixel Shader 1.4"), NULL}, - //{D3DPS_VERSION(1, 1), _T("Pixel Shader 1.1"), NULL}, - //{D3DPS_VERSION(0, 0), _T("Fixed Pipeline (bogus)"), NULL}, -}; - -GSSetting GSSettingsDlg::g_interlace[] = -{ - {0, _T("None"), NULL}, - {1, _T("Weave tff"), _T("saw-tooth")}, - {2, _T("Weave bff"), _T("saw-tooth")}, - {3, _T("Bob tff"), _T("use blend if shaking")}, - {4, _T("Bob bff"), _T("use blend if shaking")}, - {5, _T("Blend tff"), _T("slight blur, 1/2 fps")}, - {6, _T("Blend bff"), _T("slight blur, 1/2 fps")}, -}; - -GSSetting GSSettingsDlg::g_aspectratio[] = -{ - {0, _T("Stretch"), NULL}, - {1, _T("4:3"), NULL}, - {2, _T("16:9"), NULL}, -}; - -IMPLEMENT_DYNAMIC(GSSettingsDlg, CDialog) -GSSettingsDlg::GSSettingsDlg(CWnd* pParent /*=NULL*/) - : CDialog(GSSettingsDlg::IDD, pParent) - , m_tvout(FALSE) - , m_filter(1) - , m_nloophack(2) - , m_nativeres(FALSE) - , m_vsync(FALSE) - , m_logz(FALSE) - , m_fba(TRUE) -{ -} - -GSSettingsDlg::~GSSettingsDlg() -{ -} - -LRESULT GSSettingsDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - LRESULT ret = __super::DefWindowProc(message, wParam, lParam); - - if(message == WM_INITDIALOG) - { - SendMessage(WM_KICKIDLE); - } - - return ret; -} - -void GSSettingsDlg::DoDataExchange(CDataExchange* pDX) -{ - __super::DoDataExchange(pDX); - DDX_Control(pDX, IDC_COMBO3, m_resolution); - DDX_Control(pDX, IDC_COMBO1, m_renderer); - DDX_Control(pDX, IDC_COMBO4, m_psversion); - DDX_Control(pDX, IDC_COMBO2, m_interlace); - DDX_Control(pDX, IDC_COMBO5, m_aspectratio); - DDX_Check(pDX, IDC_CHECK3, m_tvout); - DDX_Check(pDX, IDC_CHECK4, m_filter); - DDX_Check(pDX, IDC_CHECK6, m_nloophack); - DDX_Control(pDX, IDC_SPIN1, m_resx); - DDX_Control(pDX, IDC_SPIN2, m_resy); - DDX_Control(pDX, IDC_SPIN3, m_swthreads); - DDX_Check(pDX, IDC_CHECK1, m_nativeres); - DDX_Control(pDX, IDC_EDIT1, m_resxedit); - DDX_Control(pDX, IDC_EDIT2, m_resyedit); - DDX_Control(pDX, IDC_EDIT3, m_swthreadsedit); - DDX_Check(pDX, IDC_CHECK2, m_vsync); - DDX_Check(pDX, IDC_CHECK5, m_logz); - DDX_Check(pDX, IDC_CHECK7, m_fba); -} - -BEGIN_MESSAGE_MAP(GSSettingsDlg, CDialog) - ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle) - ON_UPDATE_COMMAND_UI(IDC_SPIN1, OnUpdateResolution) - ON_UPDATE_COMMAND_UI(IDC_SPIN2, OnUpdateResolution) - ON_UPDATE_COMMAND_UI(IDC_EDIT1, OnUpdateResolution) - ON_UPDATE_COMMAND_UI(IDC_EDIT2, OnUpdateResolution) - ON_UPDATE_COMMAND_UI(IDC_COMBO4, OnUpdateD3D9Options) - ON_UPDATE_COMMAND_UI(IDC_CHECK3, OnUpdateD3D9Options) - ON_UPDATE_COMMAND_UI(IDC_CHECK5, OnUpdateD3D9Options) - ON_UPDATE_COMMAND_UI(IDC_CHECK7, OnUpdateD3D9Options) - ON_UPDATE_COMMAND_UI(IDC_SPIN3, OnUpdateSWOptions) - ON_UPDATE_COMMAND_UI(IDC_EDIT3, OnUpdateSWOptions) - ON_CBN_SELCHANGE(IDC_COMBO1, &GSSettingsDlg::OnCbnSelchangeCombo1) -END_MESSAGE_MAP() - -void GSSettingsDlg::OnKickIdle() -{ - UpdateDialogControls(this, false); -} - -BOOL GSSettingsDlg::OnInitDialog() -{ - __super::OnInitDialog(); - - CWinApp* pApp = AfxGetApp(); - - D3DCAPS9 caps; - memset(&caps, 0, sizeof(caps)); - caps.PixelShaderVersion = D3DPS_VERSION(0, 0); - - m_modes.RemoveAll(); - - // windowed - - { - D3DDISPLAYMODE mode; - memset(&mode, 0, sizeof(mode)); - m_modes.AddTail(mode); - - int iItem = m_resolution.AddString(_T("Windowed")); - m_resolution.SetItemDataPtr(iItem, m_modes.GetTailPosition()); - m_resolution.SetCurSel(iItem); - } - - // fullscreen - - if(CComPtr d3d = Direct3DCreate9(D3D_SDK_VERSION)) - { - UINT ModeWidth = pApp->GetProfileInt(_T("Settings"), _T("ModeWidth"), 0); - UINT ModeHeight = pApp->GetProfileInt(_T("Settings"), _T("ModeHeight"), 0); - UINT ModeRefreshRate = pApp->GetProfileInt(_T("Settings"), _T("ModeRefreshRate"), 0); - - UINT nModes = d3d->GetAdapterModeCount(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8); - - for(UINT i = 0; i < nModes; i++) - { - D3DDISPLAYMODE mode; - - if(S_OK == d3d->EnumAdapterModes(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8, i, &mode)) - { - CString str; - str.Format(_T("%dx%d %dHz"), mode.Width, mode.Height, mode.RefreshRate); - int iItem = m_resolution.AddString(str); - - m_modes.AddTail(mode); - m_resolution.SetItemDataPtr(iItem, m_modes.GetTailPosition()); - - if(ModeWidth == mode.Width && ModeHeight == mode.Height && ModeRefreshRate == mode.RefreshRate) - { - m_resolution.SetCurSel(iItem); - } - } - } - - d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps); - } - - bool isdx10avail = GSUtil::IsDirect3D10Available(); - - CAtlArray renderers; - - for(size_t i = 0; i < countof(g_renderers); i++) - { - if(i >= 3 && i <= 5 && !isdx10avail) continue; - - renderers.Add(g_renderers[i]); - } - - GSSetting::InitComboBox(renderers.GetData(), renderers.GetCount(), m_renderer, pApp->GetProfileInt(_T("Settings"), _T("Renderer"), 0)); - GSSetting::InitComboBox(g_psversion, countof(g_psversion), m_psversion, pApp->GetProfileInt(_T("Settings"), _T("PixelShaderVersion2"), D3DPS_VERSION(2, 0)), caps.PixelShaderVersion); - GSSetting::InitComboBox(g_interlace, countof(g_interlace), m_interlace, pApp->GetProfileInt(_T("Settings"), _T("Interlace"), 0)); - GSSetting::InitComboBox(g_aspectratio, countof(g_aspectratio), m_aspectratio, pApp->GetProfileInt(_T("Settings"), _T("AspectRatio"), 1)); - - OnCbnSelchangeCombo1(); - - // - - m_filter = pApp->GetProfileInt(_T("Settings"), _T("filter"), 1); - m_tvout = pApp->GetProfileInt(_T("Settings"), _T("tvout"), FALSE); - m_nloophack = pApp->GetProfileInt(_T("Settings"), _T("nloophack"), 2); - m_vsync = !!pApp->GetProfileInt(_T("Settings"), _T("vsync"), FALSE); - m_logz = !!pApp->GetProfileInt(_T("Settings"), _T("logz"), FALSE); - m_fba = !!pApp->GetProfileInt(_T("Settings"), _T("fba"), TRUE); - - m_resx.SetRange(512, 4096); - m_resy.SetRange(512, 4096); - m_resx.SetPos(pApp->GetProfileInt(_T("Settings"), _T("resx"), 1024)); - m_resy.SetPos(pApp->GetProfileInt(_T("Settings"), _T("resy"), 1024)); - m_nativeres = !!pApp->GetProfileInt(_T("Settings"), _T("nativeres"), FALSE); - - m_resx.EnableWindow(!m_nativeres); - m_resy.EnableWindow(!m_nativeres); - m_resxedit.EnableWindow(!m_nativeres); - m_resyedit.EnableWindow(!m_nativeres); - - m_swthreads.SetRange(1, 16); - m_swthreads.SetPos(pApp->GetProfileInt(_T("Settings"), _T("swthreads"), 1)); - - // - - UpdateData(FALSE); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -void GSSettingsDlg::OnOK() -{ - CWinApp* pApp = AfxGetApp(); - - UpdateData(); - - if(m_resolution.GetCurSel() >= 0) - { - D3DDISPLAYMODE& mode = m_modes.GetAt((POSITION)m_resolution.GetItemData(m_resolution.GetCurSel())); - pApp->WriteProfileInt(_T("Settings"), _T("ModeWidth"), mode.Width); - pApp->WriteProfileInt(_T("Settings"), _T("ModeHeight"), mode.Height); - pApp->WriteProfileInt(_T("Settings"), _T("ModeRefreshRate"), mode.RefreshRate); - } - - if(m_renderer.GetCurSel() >= 0) - { - pApp->WriteProfileInt(_T("Settings"), _T("Renderer"), (DWORD)m_renderer.GetItemData(m_renderer.GetCurSel())); - } - - if(m_psversion.GetCurSel() >= 0) - { - pApp->WriteProfileInt(_T("Settings"), _T("PixelShaderVersion2"), (DWORD)m_psversion.GetItemData(m_psversion.GetCurSel())); - } - - if(m_interlace.GetCurSel() >= 0) - { - pApp->WriteProfileInt(_T("Settings"), _T("Interlace"), (DWORD)m_interlace.GetItemData(m_interlace.GetCurSel())); - } - - if(m_aspectratio.GetCurSel() >= 0) - { - pApp->WriteProfileInt(_T("Settings"), _T("AspectRatio"), (DWORD)m_aspectratio.GetItemData(m_aspectratio.GetCurSel())); - } - - pApp->WriteProfileInt(_T("Settings"), _T("filter"), m_filter); - pApp->WriteProfileInt(_T("Settings"), _T("tvout"), m_tvout); - pApp->WriteProfileInt(_T("Settings"), _T("nloophack"), m_nloophack); - pApp->WriteProfileInt(_T("Settings"), _T("vsync"), m_vsync); - pApp->WriteProfileInt(_T("Settings"), _T("logz"), m_logz); - pApp->WriteProfileInt(_T("Settings"), _T("fba"), m_fba); - - pApp->WriteProfileInt(_T("Settings"), _T("resx"), m_resx.GetPos()); - pApp->WriteProfileInt(_T("Settings"), _T("resy"), m_resy.GetPos()); - pApp->WriteProfileInt(_T("Settings"), _T("swthreads"), m_swthreads.GetPos()); - pApp->WriteProfileInt(_T("Settings"), _T("nativeres"), m_nativeres); - - __super::OnOK(); -} - -void GSSettingsDlg::OnUpdateResolution(CCmdUI* pCmdUI) -{ - UpdateData(); - - int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel()); - - pCmdUI->Enable(!m_nativeres && (i == 0 || i == 3)); -} - -void GSSettingsDlg::OnUpdateD3D9Options(CCmdUI* pCmdUI) -{ - int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel()); - - pCmdUI->Enable(i >= 0 && i <= 2); -} - -void GSSettingsDlg::OnUpdateSWOptions(CCmdUI* pCmdUI) -{ - int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel()); - - pCmdUI->Enable(i == 1 || i == 4 || i == 6); -} - -void GSSettingsDlg::OnCbnSelchangeCombo1() -{ - int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel()); - - GetDlgItem(IDC_LOGO9)->ShowWindow(i >= 0 && i <= 2 ? SW_SHOW : SW_HIDE); - GetDlgItem(IDC_LOGO10)->ShowWindow(i >= 3 && i <= 5 ? SW_SHOW : SW_HIDE); -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSdx.h" +#include "GSSettingsDlg.h" +#include "GSUtil.h" +#include +#include + +GSSetting GSSettingsDlg::g_renderers[] = +{ + {0, _T("Direct3D9 (Hardware)"), NULL}, + {1, _T("Direct3D9 (Software)"), NULL}, + {2, _T("Direct3D9 (Null)"), NULL}, + {3, _T("Direct3D10 (Hardware)"), NULL}, + {4, _T("Direct3D10 (Software)"), NULL}, + {5, _T("Direct3D10 (Null)"), NULL}, + {6, _T("Null (Software)"), NULL}, + {7, _T("Null (Null)"), NULL}, +}; + +GSSetting GSSettingsDlg::g_psversion[] = +{ + {D3DPS_VERSION(3, 0), _T("Pixel Shader 3.0"), NULL}, + {D3DPS_VERSION(2, 0), _T("Pixel Shader 2.0"), NULL}, + //{D3DPS_VERSION(1, 4), _T("Pixel Shader 1.4"), NULL}, + //{D3DPS_VERSION(1, 1), _T("Pixel Shader 1.1"), NULL}, + //{D3DPS_VERSION(0, 0), _T("Fixed Pipeline (bogus)"), NULL}, +}; + +GSSetting GSSettingsDlg::g_interlace[] = +{ + {0, _T("None"), NULL}, + {1, _T("Weave tff"), _T("saw-tooth")}, + {2, _T("Weave bff"), _T("saw-tooth")}, + {3, _T("Bob tff"), _T("use blend if shaking")}, + {4, _T("Bob bff"), _T("use blend if shaking")}, + {5, _T("Blend tff"), _T("slight blur, 1/2 fps")}, + {6, _T("Blend bff"), _T("slight blur, 1/2 fps")}, +}; + +GSSetting GSSettingsDlg::g_aspectratio[] = +{ + {0, _T("Stretch"), NULL}, + {1, _T("4:3"), NULL}, + {2, _T("16:9"), NULL}, +}; + +IMPLEMENT_DYNAMIC(GSSettingsDlg, CDialog) +GSSettingsDlg::GSSettingsDlg(CWnd* pParent /*=NULL*/) + : CDialog(GSSettingsDlg::IDD, pParent) + , m_tvout(FALSE) + , m_filter(1) + , m_nloophack(2) + , m_nativeres(FALSE) + , m_vsync(FALSE) + , m_logz(FALSE) + , m_fba(TRUE) +{ +} + +GSSettingsDlg::~GSSettingsDlg() +{ +} + +LRESULT GSSettingsDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + LRESULT ret = __super::DefWindowProc(message, wParam, lParam); + + if(message == WM_INITDIALOG) + { + SendMessage(WM_KICKIDLE); + } + + return ret; +} + +void GSSettingsDlg::DoDataExchange(CDataExchange* pDX) +{ + __super::DoDataExchange(pDX); + DDX_Control(pDX, IDC_COMBO3, m_resolution); + DDX_Control(pDX, IDC_COMBO1, m_renderer); + DDX_Control(pDX, IDC_COMBO4, m_psversion); + DDX_Control(pDX, IDC_COMBO2, m_interlace); + DDX_Control(pDX, IDC_COMBO5, m_aspectratio); + DDX_Check(pDX, IDC_CHECK3, m_tvout); + DDX_Check(pDX, IDC_CHECK4, m_filter); + DDX_Check(pDX, IDC_CHECK6, m_nloophack); + DDX_Control(pDX, IDC_SPIN1, m_resx); + DDX_Control(pDX, IDC_SPIN2, m_resy); + DDX_Control(pDX, IDC_SPIN3, m_swthreads); + DDX_Check(pDX, IDC_CHECK1, m_nativeres); + DDX_Control(pDX, IDC_EDIT1, m_resxedit); + DDX_Control(pDX, IDC_EDIT2, m_resyedit); + DDX_Control(pDX, IDC_EDIT3, m_swthreadsedit); + DDX_Check(pDX, IDC_CHECK2, m_vsync); + DDX_Check(pDX, IDC_CHECK5, m_logz); + DDX_Check(pDX, IDC_CHECK7, m_fba); +} + +BEGIN_MESSAGE_MAP(GSSettingsDlg, CDialog) + ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle) + ON_UPDATE_COMMAND_UI(IDC_SPIN1, OnUpdateResolution) + ON_UPDATE_COMMAND_UI(IDC_SPIN2, OnUpdateResolution) + ON_UPDATE_COMMAND_UI(IDC_EDIT1, OnUpdateResolution) + ON_UPDATE_COMMAND_UI(IDC_EDIT2, OnUpdateResolution) + ON_UPDATE_COMMAND_UI(IDC_COMBO4, OnUpdateD3D9Options) + ON_UPDATE_COMMAND_UI(IDC_CHECK3, OnUpdateD3D9Options) + ON_UPDATE_COMMAND_UI(IDC_CHECK5, OnUpdateD3D9Options) + ON_UPDATE_COMMAND_UI(IDC_CHECK7, OnUpdateD3D9Options) + ON_UPDATE_COMMAND_UI(IDC_SPIN3, OnUpdateSWOptions) + ON_UPDATE_COMMAND_UI(IDC_EDIT3, OnUpdateSWOptions) + ON_CBN_SELCHANGE(IDC_COMBO1, &GSSettingsDlg::OnCbnSelchangeCombo1) +END_MESSAGE_MAP() + +void GSSettingsDlg::OnKickIdle() +{ + UpdateDialogControls(this, false); +} + +BOOL GSSettingsDlg::OnInitDialog() +{ + __super::OnInitDialog(); + + CWinApp* pApp = AfxGetApp(); + + D3DCAPS9 caps; + memset(&caps, 0, sizeof(caps)); + caps.PixelShaderVersion = D3DPS_VERSION(0, 0); + + m_modes.RemoveAll(); + + // windowed + + { + D3DDISPLAYMODE mode; + memset(&mode, 0, sizeof(mode)); + m_modes.AddTail(mode); + + int iItem = m_resolution.AddString(_T("Windowed")); + m_resolution.SetItemDataPtr(iItem, m_modes.GetTailPosition()); + m_resolution.SetCurSel(iItem); + } + + // fullscreen + + if(CComPtr d3d = Direct3DCreate9(D3D_SDK_VERSION)) + { + UINT ModeWidth = pApp->GetProfileInt(_T("Settings"), _T("ModeWidth"), 0); + UINT ModeHeight = pApp->GetProfileInt(_T("Settings"), _T("ModeHeight"), 0); + UINT ModeRefreshRate = pApp->GetProfileInt(_T("Settings"), _T("ModeRefreshRate"), 0); + + UINT nModes = d3d->GetAdapterModeCount(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8); + + for(UINT i = 0; i < nModes; i++) + { + D3DDISPLAYMODE mode; + + if(S_OK == d3d->EnumAdapterModes(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8, i, &mode)) + { + CString str; + str.Format(_T("%dx%d %dHz"), mode.Width, mode.Height, mode.RefreshRate); + int iItem = m_resolution.AddString(str); + + m_modes.AddTail(mode); + m_resolution.SetItemDataPtr(iItem, m_modes.GetTailPosition()); + + if(ModeWidth == mode.Width && ModeHeight == mode.Height && ModeRefreshRate == mode.RefreshRate) + { + m_resolution.SetCurSel(iItem); + } + } + } + + d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps); + } + + bool isdx10avail = GSUtil::IsDirect3D10Available(); + + CAtlArray renderers; + + for(size_t i = 0; i < countof(g_renderers); i++) + { + if(i >= 3 && i <= 5 && !isdx10avail) continue; + + renderers.Add(g_renderers[i]); + } + + GSSetting::InitComboBox(renderers.GetData(), renderers.GetCount(), m_renderer, pApp->GetProfileInt(_T("Settings"), _T("Renderer"), 0)); + GSSetting::InitComboBox(g_psversion, countof(g_psversion), m_psversion, pApp->GetProfileInt(_T("Settings"), _T("PixelShaderVersion2"), D3DPS_VERSION(2, 0)), caps.PixelShaderVersion); + GSSetting::InitComboBox(g_interlace, countof(g_interlace), m_interlace, pApp->GetProfileInt(_T("Settings"), _T("Interlace"), 0)); + GSSetting::InitComboBox(g_aspectratio, countof(g_aspectratio), m_aspectratio, pApp->GetProfileInt(_T("Settings"), _T("AspectRatio"), 1)); + + OnCbnSelchangeCombo1(); + + // + + m_filter = pApp->GetProfileInt(_T("Settings"), _T("filter"), 1); + m_tvout = pApp->GetProfileInt(_T("Settings"), _T("tvout"), FALSE); + m_nloophack = pApp->GetProfileInt(_T("Settings"), _T("nloophack"), 2); + m_vsync = !!pApp->GetProfileInt(_T("Settings"), _T("vsync"), FALSE); + m_logz = !!pApp->GetProfileInt(_T("Settings"), _T("logz"), FALSE); + m_fba = !!pApp->GetProfileInt(_T("Settings"), _T("fba"), TRUE); + + m_resx.SetRange(512, 4096); + m_resy.SetRange(512, 4096); + m_resx.SetPos(pApp->GetProfileInt(_T("Settings"), _T("resx"), 1024)); + m_resy.SetPos(pApp->GetProfileInt(_T("Settings"), _T("resy"), 1024)); + m_nativeres = !!pApp->GetProfileInt(_T("Settings"), _T("nativeres"), FALSE); + + m_resx.EnableWindow(!m_nativeres); + m_resy.EnableWindow(!m_nativeres); + m_resxedit.EnableWindow(!m_nativeres); + m_resyedit.EnableWindow(!m_nativeres); + + m_swthreads.SetRange(1, 16); + m_swthreads.SetPos(pApp->GetProfileInt(_T("Settings"), _T("swthreads"), 1)); + + // + + UpdateData(FALSE); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void GSSettingsDlg::OnOK() +{ + CWinApp* pApp = AfxGetApp(); + + UpdateData(); + + if(m_resolution.GetCurSel() >= 0) + { + D3DDISPLAYMODE& mode = m_modes.GetAt((POSITION)m_resolution.GetItemData(m_resolution.GetCurSel())); + pApp->WriteProfileInt(_T("Settings"), _T("ModeWidth"), mode.Width); + pApp->WriteProfileInt(_T("Settings"), _T("ModeHeight"), mode.Height); + pApp->WriteProfileInt(_T("Settings"), _T("ModeRefreshRate"), mode.RefreshRate); + } + + if(m_renderer.GetCurSel() >= 0) + { + pApp->WriteProfileInt(_T("Settings"), _T("Renderer"), (DWORD)m_renderer.GetItemData(m_renderer.GetCurSel())); + } + + if(m_psversion.GetCurSel() >= 0) + { + pApp->WriteProfileInt(_T("Settings"), _T("PixelShaderVersion2"), (DWORD)m_psversion.GetItemData(m_psversion.GetCurSel())); + } + + if(m_interlace.GetCurSel() >= 0) + { + pApp->WriteProfileInt(_T("Settings"), _T("Interlace"), (DWORD)m_interlace.GetItemData(m_interlace.GetCurSel())); + } + + if(m_aspectratio.GetCurSel() >= 0) + { + pApp->WriteProfileInt(_T("Settings"), _T("AspectRatio"), (DWORD)m_aspectratio.GetItemData(m_aspectratio.GetCurSel())); + } + + pApp->WriteProfileInt(_T("Settings"), _T("filter"), m_filter); + pApp->WriteProfileInt(_T("Settings"), _T("tvout"), m_tvout); + pApp->WriteProfileInt(_T("Settings"), _T("nloophack"), m_nloophack); + pApp->WriteProfileInt(_T("Settings"), _T("vsync"), m_vsync); + pApp->WriteProfileInt(_T("Settings"), _T("logz"), m_logz); + pApp->WriteProfileInt(_T("Settings"), _T("fba"), m_fba); + + pApp->WriteProfileInt(_T("Settings"), _T("resx"), m_resx.GetPos()); + pApp->WriteProfileInt(_T("Settings"), _T("resy"), m_resy.GetPos()); + pApp->WriteProfileInt(_T("Settings"), _T("swthreads"), m_swthreads.GetPos()); + pApp->WriteProfileInt(_T("Settings"), _T("nativeres"), m_nativeres); + + __super::OnOK(); +} + +void GSSettingsDlg::OnUpdateResolution(CCmdUI* pCmdUI) +{ + UpdateData(); + + int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel()); + + pCmdUI->Enable(!m_nativeres && (i == 0 || i == 3)); +} + +void GSSettingsDlg::OnUpdateD3D9Options(CCmdUI* pCmdUI) +{ + int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel()); + + pCmdUI->Enable(i >= 0 && i <= 2); +} + +void GSSettingsDlg::OnUpdateSWOptions(CCmdUI* pCmdUI) +{ + int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel()); + + pCmdUI->Enable(i == 1 || i == 4 || i == 6); +} + +void GSSettingsDlg::OnCbnSelchangeCombo1() +{ + int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel()); + + GetDlgItem(IDC_LOGO9)->ShowWindow(i >= 0 && i <= 2 ? SW_SHOW : SW_HIDE); + GetDlgItem(IDC_LOGO10)->ShowWindow(i >= 3 && i <= 5 ? SW_SHOW : SW_HIDE); +} diff --git a/plugins/GSdx/GSSettingsDlg.h b/plugins/GSdx/GSSettingsDlg.h index 18c2e7ddd0..2cc4522dd9 100644 --- a/plugins/GSdx/GSSettingsDlg.h +++ b/plugins/GSdx/GSSettingsDlg.h @@ -1,79 +1,79 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSSetting.h" -#include "resource.h" - -class GSSettingsDlg : public CDialog -{ - DECLARE_DYNAMIC(GSSettingsDlg) - -private: - CAtlList m_modes; - -public: - GSSettingsDlg(CWnd* pParent = NULL); // standard constructor - virtual ~GSSettingsDlg(); - - static GSSetting g_renderers[]; - static GSSetting g_psversion[]; - static GSSetting g_interlace[]; - static GSSetting g_aspectratio[]; - -// Dialog Data - enum { IDD = IDD_CONFIG }; - CComboBox m_resolution; - CComboBox m_renderer; - CComboBox m_psversion; - CComboBox m_interlace; - CComboBox m_aspectratio; - BOOL m_tvout; - int m_filter; - int m_nloophack; - CSpinButtonCtrl m_resx; - CSpinButtonCtrl m_resy; - CSpinButtonCtrl m_swthreads; - BOOL m_nativeres; - CEdit m_resxedit; - CEdit m_resyedit; - CEdit m_swthreadsedit; - BOOL m_vsync; - BOOL m_logz; - BOOL m_fba; - -protected: - virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam); - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnInitDialog(); - virtual void OnOK(); - - DECLARE_MESSAGE_MAP() - -public: - afx_msg void OnKickIdle(); - afx_msg void OnUpdateResolution(CCmdUI* pCmdUI); - afx_msg void OnUpdateD3D9Options(CCmdUI* pCmdUI); - afx_msg void OnUpdateSWOptions(CCmdUI* pCmdUI); - afx_msg void OnCbnSelchangeCombo1(); -}; - +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSSetting.h" +#include "resource.h" + +class GSSettingsDlg : public CDialog +{ + DECLARE_DYNAMIC(GSSettingsDlg) + +private: + CAtlList m_modes; + +public: + GSSettingsDlg(CWnd* pParent = NULL); // standard constructor + virtual ~GSSettingsDlg(); + + static GSSetting g_renderers[]; + static GSSetting g_psversion[]; + static GSSetting g_interlace[]; + static GSSetting g_aspectratio[]; + +// Dialog Data + enum { IDD = IDD_CONFIG }; + CComboBox m_resolution; + CComboBox m_renderer; + CComboBox m_psversion; + CComboBox m_interlace; + CComboBox m_aspectratio; + BOOL m_tvout; + int m_filter; + int m_nloophack; + CSpinButtonCtrl m_resx; + CSpinButtonCtrl m_resy; + CSpinButtonCtrl m_swthreads; + BOOL m_nativeres; + CEdit m_resxedit; + CEdit m_resyedit; + CEdit m_swthreadsedit; + BOOL m_vsync; + BOOL m_logz; + BOOL m_fba; + +protected: + virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam); + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + virtual void OnOK(); + + DECLARE_MESSAGE_MAP() + +public: + afx_msg void OnKickIdle(); + afx_msg void OnUpdateResolution(CCmdUI* pCmdUI); + afx_msg void OnUpdateD3D9Options(CCmdUI* pCmdUI); + afx_msg void OnUpdateSWOptions(CCmdUI* pCmdUI); + afx_msg void OnCbnSelchangeCombo1(); +}; + diff --git a/plugins/GSdx/GSState.cpp b/plugins/GSdx/GSState.cpp index 12439b8880..ed3d181157 100644 --- a/plugins/GSdx/GSState.cpp +++ b/plugins/GSdx/GSState.cpp @@ -1,2179 +1,2179 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GSState.h" - -GSState::GSState(BYTE* base, bool mt, void (*irq)(), int nloophack) - : m_mt(mt) - , m_irq(irq) - , m_nloophack_org(nloophack) - , m_nloophack(nloophack == 1) - , m_crc(0) - , m_options(0) - , m_path3hack(0) - , m_q(1.0f) - , m_vprim(1) - , m_version(5) - , m_frameskip(0) - , m_vkf(NULL) -{ - m_sssize = 0; - - m_sssize += sizeof(m_version); - m_sssize += sizeof(m_env.PRIM); - m_sssize += sizeof(m_env.PRMODE); - m_sssize += sizeof(m_env.PRMODECONT); - m_sssize += sizeof(m_env.TEXCLUT); - m_sssize += sizeof(m_env.SCANMSK); - m_sssize += sizeof(m_env.TEXA); - m_sssize += sizeof(m_env.FOGCOL); - m_sssize += sizeof(m_env.DIMX); - m_sssize += sizeof(m_env.DTHE); - m_sssize += sizeof(m_env.COLCLAMP); - m_sssize += sizeof(m_env.PABE); - m_sssize += sizeof(m_env.BITBLTBUF); - m_sssize += sizeof(m_env.TRXDIR); - m_sssize += sizeof(m_env.TRXPOS); - m_sssize += sizeof(m_env.TRXREG); - m_sssize += sizeof(m_env.TRXREG2); - - for(int i = 0; i < 2; i++) - { - m_sssize += sizeof(m_env.CTXT[i].XYOFFSET); - m_sssize += sizeof(m_env.CTXT[i].TEX0); - m_sssize += sizeof(m_env.CTXT[i].TEX1); - m_sssize += sizeof(m_env.CTXT[i].TEX2); - m_sssize += sizeof(m_env.CTXT[i].CLAMP); - m_sssize += sizeof(m_env.CTXT[i].MIPTBP1); - m_sssize += sizeof(m_env.CTXT[i].MIPTBP2); - m_sssize += sizeof(m_env.CTXT[i].SCISSOR); - m_sssize += sizeof(m_env.CTXT[i].ALPHA); - m_sssize += sizeof(m_env.CTXT[i].TEST); - m_sssize += sizeof(m_env.CTXT[i].FBA); - m_sssize += sizeof(m_env.CTXT[i].FRAME); - m_sssize += sizeof(m_env.CTXT[i].ZBUF); - } - - m_sssize += sizeof(m_v.RGBAQ); - m_sssize += sizeof(m_v.ST); - m_sssize += sizeof(m_v.UV); - m_sssize += sizeof(m_v.XYZ); - m_sssize += sizeof(m_v.FOG); - - m_sssize += sizeof(m_x); - m_sssize += sizeof(m_y); - m_sssize += m_mem.m_vmsize; - m_sssize += (sizeof(m_path[0].tag) + sizeof(m_path[0].nreg)) * 3; - m_sssize += sizeof(m_q); - - ASSERT(base); - - PMODE = (GSRegPMODE*)(base + GS_PMODE); - SMODE1 = (GSRegSMODE1*)(base + GS_SMODE1); - SMODE2 = (GSRegSMODE2*)(base + GS_SMODE2); - // SRFSH = (GSRegPMODE*)(base + GS_SRFSH); - // SYNCH1 = (GSRegPMODE*)(base + GS_SYNCH1); - // SYNCH2 = (GSRegPMODE*)(base + GS_SYNCH2); - // SYNCV = (GSRegPMODE*)(base + GS_SYNCV); - DISPFB[0] = (GSRegDISPFB*)(base + GS_DISPFB1); - DISPFB[1] = (GSRegDISPFB*)(base + GS_DISPFB2); - DISPLAY[0] = (GSRegDISPLAY*)(base + GS_DISPLAY1); - DISPLAY[1] = (GSRegDISPLAY*)(base + GS_DISPLAY2); - EXTBUF = (GSRegEXTBUF*)(base + GS_EXTBUF); - EXTDATA = (GSRegEXTDATA*)(base + GS_EXTDATA); - EXTWRITE = (GSRegEXTWRITE*)(base + GS_EXTWRITE); - BGCOLOR = (GSRegBGCOLOR*)(base + GS_BGCOLOR); - CSR = (GSRegCSR*)(base + GS_CSR); - IMR = (GSRegIMR*)(base + GS_IMR); - BUSDIR = (GSRegBUSDIR*)(base + GS_BUSDIR); - SIGLBLID = (GSRegSIGLBLID*)(base + GS_SIGLBLID); - - PRIM = &m_env.PRIM; -// CSR->rREV = 0x20; - m_env.PRMODECONT.AC = 1; - - m_x = m_y = 0; - m_bytes = 0; - m_maxbytes = 1024 * 1024 * 4; - m_buff = (BYTE*)_aligned_malloc(m_maxbytes, 16); - - Reset(); - - ResetHandlers(); -} - -GSState::~GSState() -{ - _aligned_free(m_buff); -} - -void GSState::Reset() -{ - memset(&m_path[0], 0, sizeof(m_path[0]) * 3); - memset(&m_v, 0, sizeof(m_v)); - -// PRIM = &m_env.PRIM; -// m_env.PRMODECONT.AC = 1; - - m_env.Reset(); - - m_context = &m_env.CTXT[0]; - - InvalidateTextureCache(); -} - -void GSState::ResetHandlers() -{ - for(int i = 0; i < countof(m_fpGIFPackedRegHandlers); i++) - { - m_fpGIFPackedRegHandlers[i] = &GSState::GIFPackedRegHandlerNull; - } - - m_fpGIFPackedRegHandlers[GIF_REG_PRIM] = &GSState::GIFPackedRegHandlerPRIM; - m_fpGIFPackedRegHandlers[GIF_REG_RGBA] = &GSState::GIFPackedRegHandlerRGBA; - m_fpGIFPackedRegHandlers[GIF_REG_STQ] = &GSState::GIFPackedRegHandlerSTQ; - m_fpGIFPackedRegHandlers[GIF_REG_UV] = &GSState::GIFPackedRegHandlerUV; - m_fpGIFPackedRegHandlers[GIF_REG_XYZF2] = &GSState::GIFPackedRegHandlerXYZF2; - m_fpGIFPackedRegHandlers[GIF_REG_XYZ2] = &GSState::GIFPackedRegHandlerXYZ2; - m_fpGIFPackedRegHandlers[GIF_REG_TEX0_1] = &GSState::GIFPackedRegHandlerTEX0<0>; - m_fpGIFPackedRegHandlers[GIF_REG_TEX0_2] = &GSState::GIFPackedRegHandlerTEX0<1>; - m_fpGIFPackedRegHandlers[GIF_REG_CLAMP_1] = &GSState::GIFPackedRegHandlerCLAMP<0>; - m_fpGIFPackedRegHandlers[GIF_REG_CLAMP_2] = &GSState::GIFPackedRegHandlerCLAMP<1>; - m_fpGIFPackedRegHandlers[GIF_REG_FOG] = &GSState::GIFPackedRegHandlerFOG; - m_fpGIFPackedRegHandlers[GIF_REG_XYZF3] = &GSState::GIFPackedRegHandlerXYZF3; - m_fpGIFPackedRegHandlers[GIF_REG_XYZ3] = &GSState::GIFPackedRegHandlerXYZ3; - m_fpGIFPackedRegHandlers[GIF_REG_A_D] = &GSState::GIFPackedRegHandlerA_D; - m_fpGIFPackedRegHandlers[GIF_REG_NOP] = &GSState::GIFPackedRegHandlerNOP; - - for(int i = 0; i < countof(m_fpGIFRegHandlers); i++) - { - m_fpGIFRegHandlers[i] = &GSState::GIFRegHandlerNull; - } - - m_fpGIFRegHandlers[GIF_A_D_REG_PRIM] = &GSState::GIFRegHandlerPRIM; - m_fpGIFRegHandlers[GIF_A_D_REG_RGBAQ] = &GSState::GIFRegHandlerRGBAQ; - m_fpGIFRegHandlers[GIF_A_D_REG_ST] = &GSState::GIFRegHandlerST; - m_fpGIFRegHandlers[GIF_A_D_REG_UV] = &GSState::GIFRegHandlerUV; - m_fpGIFRegHandlers[GIF_A_D_REG_XYZF2] = &GSState::GIFRegHandlerXYZF2; - m_fpGIFRegHandlers[GIF_A_D_REG_XYZ2] = &GSState::GIFRegHandlerXYZ2; - m_fpGIFRegHandlers[GIF_A_D_REG_TEX0_1] = &GSState::GIFRegHandlerTEX0<0>; - m_fpGIFRegHandlers[GIF_A_D_REG_TEX0_2] = &GSState::GIFRegHandlerTEX0<1>; - m_fpGIFRegHandlers[GIF_A_D_REG_CLAMP_1] = &GSState::GIFRegHandlerCLAMP<0>; - m_fpGIFRegHandlers[GIF_A_D_REG_CLAMP_2] = &GSState::GIFRegHandlerCLAMP<1>; - m_fpGIFRegHandlers[GIF_A_D_REG_FOG] = &GSState::GIFRegHandlerFOG; - m_fpGIFRegHandlers[GIF_A_D_REG_XYZF3] = &GSState::GIFRegHandlerXYZF3; - m_fpGIFRegHandlers[GIF_A_D_REG_XYZ3] = &GSState::GIFRegHandlerXYZ3; - m_fpGIFRegHandlers[GIF_A_D_REG_NOP] = &GSState::GIFRegHandlerNOP; - m_fpGIFRegHandlers[GIF_A_D_REG_TEX1_1] = &GSState::GIFRegHandlerTEX1<0>; - m_fpGIFRegHandlers[GIF_A_D_REG_TEX1_2] = &GSState::GIFRegHandlerTEX1<1>; - m_fpGIFRegHandlers[GIF_A_D_REG_TEX2_1] = &GSState::GIFRegHandlerTEX2<0>; - m_fpGIFRegHandlers[GIF_A_D_REG_TEX2_2] = &GSState::GIFRegHandlerTEX2<1>; - m_fpGIFRegHandlers[GIF_A_D_REG_XYOFFSET_1] = &GSState::GIFRegHandlerXYOFFSET<0>; - m_fpGIFRegHandlers[GIF_A_D_REG_XYOFFSET_2] = &GSState::GIFRegHandlerXYOFFSET<1>; - m_fpGIFRegHandlers[GIF_A_D_REG_PRMODECONT] = &GSState::GIFRegHandlerPRMODECONT; - m_fpGIFRegHandlers[GIF_A_D_REG_PRMODE] = &GSState::GIFRegHandlerPRMODE; - m_fpGIFRegHandlers[GIF_A_D_REG_TEXCLUT] = &GSState::GIFRegHandlerTEXCLUT; - m_fpGIFRegHandlers[GIF_A_D_REG_SCANMSK] = &GSState::GIFRegHandlerSCANMSK; - m_fpGIFRegHandlers[GIF_A_D_REG_MIPTBP1_1] = &GSState::GIFRegHandlerMIPTBP1<0>; - m_fpGIFRegHandlers[GIF_A_D_REG_MIPTBP1_2] = &GSState::GIFRegHandlerMIPTBP1<1>; - m_fpGIFRegHandlers[GIF_A_D_REG_MIPTBP2_1] = &GSState::GIFRegHandlerMIPTBP2<0>; - m_fpGIFRegHandlers[GIF_A_D_REG_MIPTBP2_2] = &GSState::GIFRegHandlerMIPTBP2<1>; - m_fpGIFRegHandlers[GIF_A_D_REG_TEXA] = &GSState::GIFRegHandlerTEXA; - m_fpGIFRegHandlers[GIF_A_D_REG_FOGCOL] = &GSState::GIFRegHandlerFOGCOL; - m_fpGIFRegHandlers[GIF_A_D_REG_TEXFLUSH] = &GSState::GIFRegHandlerTEXFLUSH; - m_fpGIFRegHandlers[GIF_A_D_REG_SCISSOR_1] = &GSState::GIFRegHandlerSCISSOR<0>; - m_fpGIFRegHandlers[GIF_A_D_REG_SCISSOR_2] = &GSState::GIFRegHandlerSCISSOR<1>; - m_fpGIFRegHandlers[GIF_A_D_REG_ALPHA_1] = &GSState::GIFRegHandlerALPHA<0>; - m_fpGIFRegHandlers[GIF_A_D_REG_ALPHA_2] = &GSState::GIFRegHandlerALPHA<1>; - m_fpGIFRegHandlers[GIF_A_D_REG_DIMX] = &GSState::GIFRegHandlerDIMX; - m_fpGIFRegHandlers[GIF_A_D_REG_DTHE] = &GSState::GIFRegHandlerDTHE; - m_fpGIFRegHandlers[GIF_A_D_REG_COLCLAMP] = &GSState::GIFRegHandlerCOLCLAMP; - m_fpGIFRegHandlers[GIF_A_D_REG_TEST_1] = &GSState::GIFRegHandlerTEST<0>; - m_fpGIFRegHandlers[GIF_A_D_REG_TEST_2] = &GSState::GIFRegHandlerTEST<1>; - m_fpGIFRegHandlers[GIF_A_D_REG_PABE] = &GSState::GIFRegHandlerPABE; - m_fpGIFRegHandlers[GIF_A_D_REG_FBA_1] = &GSState::GIFRegHandlerFBA<0>; - m_fpGIFRegHandlers[GIF_A_D_REG_FBA_2] = &GSState::GIFRegHandlerFBA<1>; - m_fpGIFRegHandlers[GIF_A_D_REG_FRAME_1] = &GSState::GIFRegHandlerFRAME<0>; - m_fpGIFRegHandlers[GIF_A_D_REG_FRAME_2] = &GSState::GIFRegHandlerFRAME<1>; - m_fpGIFRegHandlers[GIF_A_D_REG_ZBUF_1] = &GSState::GIFRegHandlerZBUF<0>; - m_fpGIFRegHandlers[GIF_A_D_REG_ZBUF_2] = &GSState::GIFRegHandlerZBUF<1>; - m_fpGIFRegHandlers[GIF_A_D_REG_BITBLTBUF] = &GSState::GIFRegHandlerBITBLTBUF; - m_fpGIFRegHandlers[GIF_A_D_REG_TRXPOS] = &GSState::GIFRegHandlerTRXPOS; - m_fpGIFRegHandlers[GIF_A_D_REG_TRXREG] = &GSState::GIFRegHandlerTRXREG; - m_fpGIFRegHandlers[GIF_A_D_REG_TRXDIR] = &GSState::GIFRegHandlerTRXDIR; - m_fpGIFRegHandlers[GIF_A_D_REG_HWREG] = &GSState::GIFRegHandlerHWREG; - m_fpGIFRegHandlers[GIF_A_D_REG_SIGNAL] = &GSState::GIFRegHandlerSIGNAL; - m_fpGIFRegHandlers[GIF_A_D_REG_FINISH] = &GSState::GIFRegHandlerFINISH; - m_fpGIFRegHandlers[GIF_A_D_REG_LABEL] = &GSState::GIFRegHandlerLABEL; -} - -CPoint GSState::GetDisplayPos(int i) -{ - ASSERT(i >= 0 && i < 2); - - CPoint p; - - p.x = DISPLAY[i]->DX / (DISPLAY[i]->MAGH + 1); - p.y = DISPLAY[i]->DY / (DISPLAY[i]->MAGV + 1); - - return p; -} - -CSize GSState::GetDisplaySize(int i) -{ - ASSERT(i >= 0 && i < 2); - - CSize s; - - s.cx = (DISPLAY[i]->DW + 1) / (DISPLAY[i]->MAGH + 1); - s.cy = (DISPLAY[i]->DH + 1) / (DISPLAY[i]->MAGV + 1); - - return s; -} - -CRect GSState::GetDisplayRect(int i) -{ - return CRect(GetDisplayPos(i), GetDisplaySize(i)); -} - -CSize GSState::GetDisplayPos() -{ - return GetDisplayPos(IsEnabled(1) ? 1 : 0); -} - -CSize GSState::GetDisplaySize() -{ - return GetDisplaySize(IsEnabled(1) ? 1 : 0); -} - -CRect GSState::GetDisplayRect() -{ - return GetDisplayRect(IsEnabled(1) ? 1 : 0); -} - -CPoint GSState::GetFramePos(int i) -{ - ASSERT(i >= 0 && i < 2); - - return CPoint(DISPFB[i]->DBX, DISPFB[i]->DBY); -} - -CSize GSState::GetFrameSize(int i) -{ - CSize s = GetDisplaySize(i); - - if(SMODE2->INT && SMODE2->FFMD && s.cy > 1) s.cy >>= 1; - - return s; -} - -CRect GSState::GetFrameRect(int i) -{ - return CRect(GetFramePos(i), GetFrameSize(i)); -} - -CSize GSState::GetFramePos() -{ - return GetFramePos(IsEnabled(1) ? 1 : 0); -} - -CSize GSState::GetFrameSize() -{ - return GetFrameSize(IsEnabled(1) ? 1 : 0); -} - -CRect GSState::GetFrameRect() -{ - return GetFrameRect(IsEnabled(1) ? 1 : 0); -} - -CSize GSState::GetDeviceSize(int i) -{ - // TODO: other params of SMODE1 should affect the true device display size - - // TODO2: pal games at 60Hz - - CSize s = GetDisplaySize(i); - - if(s.cy == 2*416 || s.cy == 2*448 || s.cy == 2*512) - { - s.cy /= 2; - } - else - { - s.cy = (SMODE1->CMOD & 1) ? 512 : 448; - } - - return s; - -} - -CSize GSState::GetDeviceSize() -{ - return GetDeviceSize(IsEnabled(1) ? 1 : 0); -} - -bool GSState::IsEnabled(int i) -{ - ASSERT(i >= 0 && i < 2); - - if(i == 0 && PMODE->EN1) - { - return DISPLAY[0]->DW || DISPLAY[0]->DH; - } - else if(i == 1 && PMODE->EN2) - { - return DISPLAY[1]->DW || DISPLAY[1]->DH; - } - - return false; -} - -int GSState::GetFPS() -{ - return ((SMODE1->CMOD & 1) ? 50 : 60) / (SMODE2->INT ? 1 : 2); -} - -// GIFPackedRegHandler* - -void GSState::GIFPackedRegHandlerNull(GIFPackedReg* r) -{ - // ASSERT(0); -} - -void GSState::GIFPackedRegHandlerPRIM(GIFPackedReg* r) -{ - // ASSERT(r->r.PRIM.PRIM < 7); - - GIFRegHandlerPRIM(&r->r); -} - -void GSState::GIFPackedRegHandlerRGBA(GIFPackedReg* r) -{ - #if _M_SSE >= 0x301 - - GSVector4i mask = GSVector4i::load(0x0c080400); - GSVector4i v = GSVector4i::load(r).shuffle8(mask); - m_v.RGBAQ.ai32[0] = (UINT32)GSVector4i::store(v); - - #elif _M_SSE >= 0x200 - - GSVector4i v = GSVector4i::load(r) & GSVector4i::x000000ff(); - m_v.RGBAQ.ai32[0] = v.rgba32(); - - #else - - m_v.RGBAQ.R = r->RGBA.R; - m_v.RGBAQ.G = r->RGBA.G; - m_v.RGBAQ.B = r->RGBA.B; - m_v.RGBAQ.A = r->RGBA.A; - - #endif - - m_v.RGBAQ.Q = m_q; -} - -void GSState::GIFPackedRegHandlerSTQ(GIFPackedReg* r) -{ - #if defined(_M_AMD64) - - m_v.ST.i64 = r->ai64[0]; - - #elif _M_SSE >= 0x200 - - GSVector4i v = GSVector4i::loadl(r); - GSVector4i::storel(&m_v.ST.i64, v); - - #else - - m_v.ST.S = r->STQ.S; - m_v.ST.T = r->STQ.T; - - #endif - - m_q = r->STQ.Q; -} - -void GSState::GIFPackedRegHandlerUV(GIFPackedReg* r) -{ - #if _M_SSE >= 0x200 - - GSVector4i v = GSVector4i::loadl(r) & GSVector4i::x00003fff(); - m_v.UV.ai32[0] = (UINT32)GSVector4i::store(v.ps32(v)); - - #else - - m_v.UV.U = r->UV.U; - m_v.UV.V = r->UV.V; - - #endif -} - -void GSState::GIFPackedRegHandlerXYZF2(GIFPackedReg* r) -{ - m_v.XYZ.X = r->XYZF2.X; - m_v.XYZ.Y = r->XYZF2.Y; - m_v.XYZ.Z = r->XYZF2.Z; - m_v.FOG.F = r->XYZF2.F; - - VertexKick(r->XYZF2.ADC); -} - -void GSState::GIFPackedRegHandlerXYZ2(GIFPackedReg* r) -{ - m_v.XYZ.X = r->XYZ2.X; - m_v.XYZ.Y = r->XYZ2.Y; - m_v.XYZ.Z = r->XYZ2.Z; - - VertexKick(r->XYZ2.ADC); -} - -template void GSState::GIFPackedRegHandlerTEX0(GIFPackedReg* r) -{ - GIFRegHandlerTEX0((GIFReg*)&r->ai64[0]); -} - -template void GSState::GIFPackedRegHandlerCLAMP(GIFPackedReg* r) -{ - GIFRegHandlerCLAMP((GIFReg*)&r->ai64[0]); -} - -void GSState::GIFPackedRegHandlerFOG(GIFPackedReg* r) -{ - m_v.FOG.F = r->FOG.F; -} - -void GSState::GIFPackedRegHandlerXYZF3(GIFPackedReg* r) -{ - GIFRegHandlerXYZF3((GIFReg*)&r->ai64[0]); -} - -void GSState::GIFPackedRegHandlerXYZ3(GIFPackedReg* r) -{ - GIFRegHandlerXYZ3((GIFReg*)&r->ai64[0]); -} - -void GSState::GIFPackedRegHandlerA_D(GIFPackedReg* r) -{ - (this->*m_fpGIFRegHandlers[(BYTE)r->A_D.ADDR])(&r->r); -} - -void GSState::GIFPackedRegHandlerA_D(GIFPackedReg* r, int size) -{ - for(int i = 0; i < size; i++) - { - (this->*m_fpGIFRegHandlers[(BYTE)r[i].A_D.ADDR])(&r[i].r); - } -} - -void GSState::GIFPackedRegHandlerNOP(GIFPackedReg* r) -{ -} - -// GIFRegHandler* - -void GSState::GIFRegHandlerNull(GIFReg* r) -{ - // ASSERT(0); -} - -void GSState::GIFRegHandlerPRIM(GIFReg* r) -{ - // ASSERT(r->PRIM.PRIM < 7); - - if(GSUtil::GetPrimClass(m_env.PRIM.PRIM) == GSUtil::GetPrimClass(r->PRIM.PRIM)) - { - if(((m_env.PRIM.i64 ^ r->PRIM.i64) & ~7) != 0) - { - Flush(); - } - } - else - { - Flush(); - } - - m_env.PRIM = (GSVector4i)r->PRIM; - m_env.PRMODE._PRIM = r->PRIM.PRIM; - - m_context = &m_env.CTXT[PRIM->CTXT]; - - UpdateVertexKick(); - - ResetPrim(); -} - -void GSState::GIFRegHandlerRGBAQ(GIFReg* r) -{ - m_v.RGBAQ = (GSVector4i)r->RGBAQ; -} - -void GSState::GIFRegHandlerST(GIFReg* r) -{ - m_v.ST = (GSVector4i)r->ST; -} - -void GSState::GIFRegHandlerUV(GIFReg* r) -{ - m_v.UV.ai32[0] = r->UV.ai32[0] & 0x3fff3fff; -} - -void GSState::GIFRegHandlerXYZF2(GIFReg* r) -{ -/* - m_v.XYZ.X = r->XYZF.X; - m_v.XYZ.Y = r->XYZF.Y; - m_v.XYZ.Z = r->XYZF.Z; - m_v.FOG.F = r->XYZF.F; -*/ - m_v.XYZ.ai32[0] = r->XYZF.ai32[0]; - m_v.XYZ.ai32[1] = r->XYZF.ai32[1] & 0x00ffffff; - m_v.FOG.ai32[1] = r->XYZF.ai32[1] & 0xff000000; - - VertexKick(false); -} - -void GSState::GIFRegHandlerXYZ2(GIFReg* r) -{ - m_v.XYZ = (GSVector4i)r->XYZ; - - VertexKick(false); -} - -template void GSState::GIFRegHandlerTEX0(GIFReg* r) -{ - // even if TEX0 did not change, a new palette may have been uploaded and will overwrite the currently queued for drawing - - bool wt = m_mem.m_clut.WriteTest(r->TEX0, m_env.TEXCLUT); - - if(wt || PRIM->CTXT == i && !(m_env.CTXT[i].TEX0 == (GSVector4i)r->TEX0).alltrue()) - { - Flush(); - } - - m_env.CTXT[i].TEX0 = (GSVector4i)r->TEX0; - - if(m_env.CTXT[i].TEX0.TW > 10) m_env.CTXT[i].TEX0.TW = 10; - if(m_env.CTXT[i].TEX0.TH > 10) m_env.CTXT[i].TEX0.TH = 10; - - m_env.CTXT[i].TEX0.CPSM &= 0xa; // 1010b - - if((m_env.CTXT[i].TEX0.TBW & 1) && (m_env.CTXT[i].TEX0.PSM == PSM_PSMT8 || m_env.CTXT[i].TEX0.PSM == PSM_PSMT4)) - { - m_env.CTXT[i].TEX0.TBW &= ~1; // GS User 2.6 - } - - if(wt) - { - m_mem.m_clut.Write(m_env.CTXT[i].TEX0, m_env.TEXCLUT); - } -} - -template void GSState::GIFRegHandlerCLAMP(GIFReg* r) -{ - if(PRIM->CTXT == i && !(m_env.CTXT[i].CLAMP == (GSVector4i)r->CLAMP).alltrue()) - { - Flush(); - } - - m_env.CTXT[i].CLAMP = (GSVector4i)r->CLAMP; -} - -void GSState::GIFRegHandlerFOG(GIFReg* r) -{ - m_v.FOG = (GSVector4i)r->FOG; -} - -void GSState::GIFRegHandlerXYZF3(GIFReg* r) -{ -/* - m_v.XYZ.X = r->XYZF.X; - m_v.XYZ.Y = r->XYZF.Y; - m_v.XYZ.Z = r->XYZF.Z; - m_v.FOG.F = r->XYZF.F; -*/ - m_v.XYZ.ai32[0] = r->XYZF.ai32[0]; - m_v.XYZ.ai32[1] = r->XYZF.ai32[1] & 0x00ffffff; - m_v.FOG.ai32[1] = r->XYZF.ai32[1] & 0xff000000; - - VertexKick(true); -} - -void GSState::GIFRegHandlerXYZ3(GIFReg* r) -{ - m_v.XYZ = (GSVector4i)r->XYZ; - - VertexKick(true); -} - -void GSState::GIFRegHandlerNOP(GIFReg* r) -{ -} - -template void GSState::GIFRegHandlerTEX1(GIFReg* r) -{ - if(PRIM->CTXT == i && !(m_env.CTXT[i].TEX1 == (GSVector4i)r->TEX1).alltrue()) - { - Flush(); - } - - m_env.CTXT[i].TEX1 = (GSVector4i)r->TEX1; -} - -template void GSState::GIFRegHandlerTEX2(GIFReg* r) -{ - // m_env.CTXT[i].TEX2 = r->TEX2; // not used - - UINT64 mask = 0xFFFFFFE003F00000ui64; // TEX2 bits - - r->i64 = (r->i64 & mask) | (m_env.CTXT[i].TEX0.i64 & ~mask); - - GIFRegHandlerTEX0(r); -} - -template void GSState::GIFRegHandlerXYOFFSET(GIFReg* r) -{ - GSVector4i o = (GSVector4i)r->XYOFFSET & GSVector4i::x0000ffff(); - - if(!(m_env.CTXT[i].XYOFFSET == o).alltrue()) - { - Flush(); - } - - m_env.CTXT[i].XYOFFSET = o; - - m_env.CTXT[i].UpdateScissor(); -} - -void GSState::GIFRegHandlerPRMODECONT(GIFReg* r) -{ - if(!(m_env.PRMODECONT == (GSVector4i)r->PRMODECONT).alltrue()) - { - Flush(); - } - - m_env.PRMODECONT.AC = r->PRMODECONT.AC; - - PRIM = m_env.PRMODECONT.AC ? &m_env.PRIM : (GIFRegPRIM*)&m_env.PRMODE; - - if(PRIM->PRIM == 7) TRACE(_T("Invalid PRMODECONT/PRIM\n")); - - m_context = &m_env.CTXT[PRIM->CTXT]; - - UpdateVertexKick(); -} - -void GSState::GIFRegHandlerPRMODE(GIFReg* r) -{ - if(!m_env.PRMODECONT.AC) - { - Flush(); - } - - UINT32 _PRIM = m_env.PRMODE._PRIM; - m_env.PRMODE = (GSVector4i)r->PRMODE; - m_env.PRMODE._PRIM = _PRIM; - - m_context = &m_env.CTXT[PRIM->CTXT]; - - UpdateVertexKick(); -} - -void GSState::GIFRegHandlerTEXCLUT(GIFReg* r) -{ - if(!(m_env.TEXCLUT == (GSVector4i)r->TEXCLUT).alltrue()) - { - Flush(); - } - - m_env.TEXCLUT = (GSVector4i)r->TEXCLUT; -} - -void GSState::GIFRegHandlerSCANMSK(GIFReg* r) -{ - if(!(m_env.SCANMSK == (GSVector4i)r->SCANMSK).alltrue()) - { - Flush(); - } - - m_env.SCANMSK = (GSVector4i)r->SCANMSK; -} - -template void GSState::GIFRegHandlerMIPTBP1(GIFReg* r) -{ - if(PRIM->CTXT == i && !(m_env.CTXT[i].MIPTBP1 == (GSVector4i)r->MIPTBP1).alltrue()) - { - Flush(); - } - - m_env.CTXT[i].MIPTBP1 = (GSVector4i)r->MIPTBP1; -} - -template void GSState::GIFRegHandlerMIPTBP2(GIFReg* r) -{ - if(PRIM->CTXT == i && !(m_env.CTXT[i].MIPTBP2 == (GSVector4i)r->MIPTBP2).alltrue()) - { - Flush(); - } - - m_env.CTXT[i].MIPTBP2 = (GSVector4i)r->MIPTBP2; -} - -void GSState::GIFRegHandlerTEXA(GIFReg* r) -{ - if(!(m_env.TEXA == (GSVector4i)r->TEXA).alltrue()) - { - Flush(); - } - - m_env.TEXA = (GSVector4i)r->TEXA; -} - -void GSState::GIFRegHandlerFOGCOL(GIFReg* r) -{ - if(!(m_env.FOGCOL == (GSVector4i)r->FOGCOL).alltrue()) - { - Flush(); - } - - m_env.FOGCOL = (GSVector4i)r->FOGCOL; -} - -void GSState::GIFRegHandlerTEXFLUSH(GIFReg* r) -{ - // TRACE(_T("TEXFLUSH\n")); - - // InvalidateTextureCache(); -} - -template void GSState::GIFRegHandlerSCISSOR(GIFReg* r) -{ - if(PRIM->CTXT == i && !(m_env.CTXT[i].SCISSOR == (GSVector4i)r->SCISSOR).alltrue()) - { - Flush(); - } - - m_env.CTXT[i].SCISSOR = (GSVector4i)r->SCISSOR; - - m_env.CTXT[i].UpdateScissor(); -} - -template void GSState::GIFRegHandlerALPHA(GIFReg* r) -{ - ASSERT(r->ALPHA.A != 3); - ASSERT(r->ALPHA.B != 3); - ASSERT(r->ALPHA.C != 3); - ASSERT(r->ALPHA.D != 3); - - if(PRIM->CTXT == i && !(m_env.CTXT[i].ALPHA == (GSVector4i)r->ALPHA).alltrue()) - { - Flush(); - } - - m_env.CTXT[i].ALPHA = (GSVector4i)r->ALPHA; - - // A/B/C/D == 3? => 2 - - m_env.CTXT[i].ALPHA.ai32[0] = ((~m_env.CTXT[i].ALPHA.ai32[0] >> 1) | 0xAA) & m_env.CTXT[i].ALPHA.ai32[0]; -} - -void GSState::GIFRegHandlerDIMX(GIFReg* r) -{ - if(!(m_env.DIMX == (GSVector4i)r->DIMX).alltrue()) - { - Flush(); - } - - m_env.DIMX = (GSVector4i)r->DIMX; -} - -void GSState::GIFRegHandlerDTHE(GIFReg* r) -{ - if(!(m_env.DTHE == (GSVector4i)r->DTHE).alltrue()) - { - Flush(); - } - - m_env.DTHE = (GSVector4i)r->DTHE; -} - -void GSState::GIFRegHandlerCOLCLAMP(GIFReg* r) -{ - if(!(m_env.COLCLAMP == (GSVector4i)r->COLCLAMP).alltrue()) - { - Flush(); - } - - m_env.COLCLAMP = (GSVector4i)r->COLCLAMP; -} - -template void GSState::GIFRegHandlerTEST(GIFReg* r) -{ - if(PRIM->CTXT == i && !(m_env.CTXT[i].TEST == (GSVector4i)r->TEST).alltrue()) - { - Flush(); - } - - m_env.CTXT[i].TEST = (GSVector4i)r->TEST; -} - -void GSState::GIFRegHandlerPABE(GIFReg* r) -{ - if(!(m_env.PABE == (GSVector4i)r->PABE).alltrue()) - { - Flush(); - } - - m_env.PABE = (GSVector4i)r->PABE; -} - -template void GSState::GIFRegHandlerFBA(GIFReg* r) -{ - if(PRIM->CTXT == i && !(m_env.CTXT[i].FBA == (GSVector4i)r->FBA).alltrue()) - { - Flush(); - } - - m_env.CTXT[i].FBA = (GSVector4i)r->FBA; -} - -template void GSState::GIFRegHandlerFRAME(GIFReg* r) -{ - if(PRIM->CTXT == i && !(m_env.CTXT[i].FRAME == (GSVector4i)r->FRAME).alltrue()) - { - Flush(); - } - - m_env.CTXT[i].FRAME = (GSVector4i)r->FRAME; -} - -template void GSState::GIFRegHandlerZBUF(GIFReg* r) -{ - if(r->ZBUF.ai32[0] == 0) - { - // during startup all regs are cleared to 0 (by the bios or something), so we mask z until this register becomes valid - - r->ZBUF.ZMSK = 1; - } - - r->ZBUF.PSM |= 0x30; - - if(PRIM->CTXT == i && !(m_env.CTXT[i].ZBUF == (GSVector4i)r->ZBUF).alltrue()) - { - Flush(); - } - - m_env.CTXT[i].ZBUF = (GSVector4i)r->ZBUF; - - if(m_env.CTXT[i].ZBUF.PSM != PSM_PSMZ32 - && m_env.CTXT[i].ZBUF.PSM != PSM_PSMZ24 - && m_env.CTXT[i].ZBUF.PSM != PSM_PSMZ16 - && m_env.CTXT[i].ZBUF.PSM != PSM_PSMZ16S) - { - m_env.CTXT[i].ZBUF.PSM = PSM_PSMZ32; - } -} - -void GSState::GIFRegHandlerBITBLTBUF(GIFReg* r) -{ - if(!(m_env.BITBLTBUF == (GSVector4i)r->BITBLTBUF).alltrue()) - { - FlushWrite(); - } - - m_env.BITBLTBUF = (GSVector4i)r->BITBLTBUF; - - if((m_env.BITBLTBUF.SBW & 1) && (m_env.BITBLTBUF.SPSM == PSM_PSMT8 || m_env.BITBLTBUF.SPSM == PSM_PSMT4)) - { - m_env.BITBLTBUF.SBW &= ~1; - } - - if((m_env.BITBLTBUF.DBW & 1) && (m_env.BITBLTBUF.DPSM == PSM_PSMT8 || m_env.BITBLTBUF.DPSM == PSM_PSMT4)) - { - m_env.BITBLTBUF.DBW &= ~1; // namcoXcapcom: 5, 11, refered to as 4, 10 in TEX0.TBW later - } -} - -void GSState::GIFRegHandlerTRXPOS(GIFReg* r) -{ - if(!(m_env.TRXPOS == (GSVector4i)r->TRXPOS).alltrue()) - { - FlushWrite(); - } - - m_env.TRXPOS = (GSVector4i)r->TRXPOS; -} - -void GSState::GIFRegHandlerTRXREG(GIFReg* r) -{ - if(!(m_env.TRXREG == (GSVector4i)r->TRXREG).alltrue() || !(m_env.TRXREG2 == (GSVector4i)r->TRXREG).alltrue()) - { - FlushWrite(); - } - - m_env.TRXREG = (GSVector4i)r->TRXREG; - m_env.TRXREG2 = (GSVector4i)r->TRXREG; -} - -void GSState::GIFRegHandlerTRXDIR(GIFReg* r) -{ - Flush(); - - m_env.TRXDIR = (GSVector4i)r->TRXDIR; - - switch(m_env.TRXDIR.XDIR) - { - case 0: // host -> local - m_x = m_env.TRXPOS.DSAX; - m_y = m_env.TRXPOS.DSAY; - m_env.TRXREG.RRW = m_x + m_env.TRXREG2.RRW; - m_env.TRXREG.RRH = m_y + m_env.TRXREG2.RRH; - break; - case 1: // local -> host - m_x = m_env.TRXPOS.SSAX; - m_y = m_env.TRXPOS.SSAY; - m_env.TRXREG.RRW = m_x + m_env.TRXREG2.RRW; - m_env.TRXREG.RRH = m_y + m_env.TRXREG2.RRH; - break; - case 2: // local -> local - Move(); - break; - case 3: - ASSERT(0); - break; - } -} - -void GSState::GIFRegHandlerHWREG(GIFReg* r) -{ - ASSERT(m_env.TRXDIR.XDIR == 0); // host => local - - Write((BYTE*)r, 8); // hunting ground -} - -void GSState::GIFRegHandlerSIGNAL(GIFReg* r) -{ - if(m_mt) return; - - SIGLBLID->SIGID = (SIGLBLID->SIGID & ~r->SIGNAL.IDMSK) | (r->SIGNAL.ID & r->SIGNAL.IDMSK); - - if(CSR->wSIGNAL) CSR->rSIGNAL = 1; - if(!IMR->SIGMSK && m_irq) m_irq(); -} - -void GSState::GIFRegHandlerFINISH(GIFReg* r) -{ - if(m_mt) return; - - if(CSR->wFINISH) CSR->rFINISH = 1; - if(!IMR->FINISHMSK && m_irq) m_irq(); -} - -void GSState::GIFRegHandlerLABEL(GIFReg* r) -{ - if(m_mt) return; - - SIGLBLID->LBLID = (SIGLBLID->LBLID & ~r->LABEL.IDMSK) | (r->LABEL.ID & r->LABEL.IDMSK); -} - -// - -void GSState::Flush() -{ - FlushWrite(); - - FlushPrim(); -} - -void GSState::FlushWrite() -{ - FlushWrite(m_buff, m_bytes); - - m_bytes = 0; -} - -void GSState::FlushWrite(BYTE* mem, int len) -{ - if(len > 0) - { -/* -CSize bs = GSLocalMemory::m_psm[m_env.BITBLTBUF.DPSM].bs; - -if((m_x & (bs.cx - 1)) || (m_env.TRXREG.RRW & (bs.cx - 1)) -|| (m_y & (bs.cy - 1)) || (m_env.TRXREG.RRH & (bs.cy - 1)) -|| m_x != m_env.TRXPOS.DSAX) -{ - printf("*** [%d]: %d %d, %d %d %d %d\n", m_env.BITBLTBUF.DPSM, m_env.TRXPOS.DSAX, m_env.TRXPOS.DSAY, m_x, m_y, m_env.TRXREG.RRW, m_env.TRXREG.RRH); -} - -if((len % ((m_env.TRXREG.RRW - m_x) * GSLocalMemory::m_psm[m_env.BITBLTBUF.DPSM].trbpp / 8)) != 0) -{ - printf("*** [%d]: %d %d\n", m_env.BITBLTBUF.DPSM, len, ((m_env.TRXREG.RRW - m_x) * GSLocalMemory::m_psm[m_env.BITBLTBUF.DPSM].trbpp / 8)); -} -*/ - int y = m_y; - - GSLocalMemory::writeImage wi = GSLocalMemory::m_psm[m_env.BITBLTBUF.DPSM].wi; - - (m_mem.*wi)(m_x, m_y, mem, len, m_env.BITBLTBUF, m_env.TRXPOS, m_env.TRXREG); - - m_perfmon.Put(GSPerfMon::Swizzle, len); - - //ASSERT(m_env.TRXREG.RRH >= m_y - y); - - CRect r; - - r.left = m_env.TRXPOS.DSAX; - r.top = y; - r.right = m_env.TRXREG.RRW; - r.bottom = min(m_x == m_env.TRXPOS.DSAX ? m_y : m_y + 1, m_env.TRXREG.RRH); - - InvalidateVideoMem(m_env.BITBLTBUF, r); -/* - static int n = 0; - CString str; - str.Format(_T("c:\\temp1\\[%04d]_%05x_%d_%d_%d_%d_%d_%d.bmp"), - n++, (int)m_env.BITBLTBUF.DBP, (int)m_env.BITBLTBUF.DBW, (int)m_env.BITBLTBUF.DPSM, - r.left, r.top, r.right, r.bottom); - m_mem.SaveBMP(str, m_env.BITBLTBUF.DBP, m_env.BITBLTBUF.DBW, m_env.BITBLTBUF.DPSM, r.Width(), r.Height()); -*/ - } -} - -// - -void GSState::Write(BYTE* mem, int len) -{ -/* - TRACE(_T("Write len=%d DBP=%05x DBW=%d DPSM=%d DSAX=%d DSAY=%d RRW=%d RRH=%d\n"), - len, (int)m_env.BITBLTBUF.DBP, (int)m_env.BITBLTBUF.DBW, (int)m_env.BITBLTBUF.DPSM, - (int)m_env.TRXPOS.DSAX, (int)m_env.TRXPOS.DSAY, - (int)m_env.TRXREG.RRW, (int)m_env.TRXREG.RRH); -*/ - if(len == 0) return; - - if(m_y >= m_env.TRXREG.RRH) return; // TODO: handle overflow during writing data too (just chop len below somewhere) - - // TODO: hmmmm - - if(PRIM->TME && (m_env.BITBLTBUF.DBP == m_context->TEX0.TBP0 || m_env.BITBLTBUF.DBP == m_context->TEX0.CBP)) - { - FlushPrim(); - } - - int bpp = GSLocalMemory::m_psm[m_env.BITBLTBUF.DPSM].trbpp; - - int pitch = (m_env.TRXREG.RRW - m_env.TRXPOS.DSAX) * bpp >> 3; - - if(pitch <= 0) {ASSERT(0); return;} - - int height = len / pitch; - - if(height > m_env.TRXREG.RRH - m_env.TRXPOS.DSAY) - { - height = m_env.TRXREG.RRH - m_env.TRXPOS.DSAY; - - len = height * pitch; - } - - if(m_bytes > 0 || height < m_env.TRXREG.RRH - m_env.TRXPOS.DSAY) - { - ASSERT(len <= m_maxbytes); // more than 4mb into a 4mb local mem doesn't make sense - - len = min(m_maxbytes, len); - - if(m_bytes + len > m_maxbytes) - { - FlushWrite(); - } - - memcpy(&m_buff[m_bytes], mem, len); - - m_bytes += len; - } - else - { - FlushWrite(mem, len); - } - - m_mem.m_clut.Invalidate(); -} - -void GSState::Read(BYTE* mem, int len) -{ - /* - TRACE(_T("Read len=%d SBP=%05x SBW=%d SPSM=%d SSAX=%d SSAY=%d RRW=%d RRH=%d\n"), - len, (int)m_env.BITBLTBUF.SBP, (int)m_env.BITBLTBUF.SBW, (int)m_env.BITBLTBUF.SPSM, - (int)m_env.TRXPOS.SSAX, (int)m_env.TRXPOS.SSAY, - (int)m_env.TRXREG.RRW, (int)m_env.TRXREG.RRH); - */ - - if(m_y >= (int)m_env.TRXREG.RRH) {ASSERT(0); return;} - - if(m_x == m_env.TRXPOS.SSAX && m_y == m_env.TRXPOS.SSAY) - { - CRect r(m_env.TRXPOS.SSAX, m_env.TRXPOS.SSAY, m_env.TRXREG.RRW, m_env.TRXREG.RRH); - - InvalidateLocalMem(m_env.BITBLTBUF, r); - } - - // TODO - - m_mem.ReadImageX(m_x, m_y, mem, len, m_env.BITBLTBUF, m_env.TRXPOS, m_env.TRXREG); -} - -void GSState::Move() -{ - // ffxii uses this to move the top/bottom of the scrolling menus offscreen and then blends them back over the text to create a shading effect - // guitar hero copies the far end of the board to do a similar blend too - - GSLocalMemory::readPixel rp = GSLocalMemory::m_psm[m_env.BITBLTBUF.SPSM].rp; - GSLocalMemory::writePixel wp = GSLocalMemory::m_psm[m_env.BITBLTBUF.DPSM].wp; - - int sx = m_env.TRXPOS.SSAX; - int dx = m_env.TRXPOS.DSAX; - int sy = m_env.TRXPOS.SSAY; - int dy = m_env.TRXPOS.DSAY; - int w = m_env.TRXREG.RRW; - int h = m_env.TRXREG.RRH; - int xinc = 1; - int yinc = 1; - - if(sx < dx) sx += w-1, dx += w-1, xinc = -1; - if(sy < dy) sy += h-1, dy += h-1, yinc = -1; - - InvalidateLocalMem(m_env.BITBLTBUF, CRect(CPoint(sx, sy), CSize(w, h))); - InvalidateVideoMem(m_env.BITBLTBUF, CRect(CPoint(dx, dy), CSize(w, h))); - - // TODO: use rowOffset - - for(int y = 0; y < h; y++, sy += yinc, dy += yinc, sx -= xinc*w, dx -= xinc*w) - for(int x = 0; x < w; x++, sx += xinc, dx += xinc) - (m_mem.*wp)(dx, dy, (m_mem.*rp)(sx, sy, m_env.BITBLTBUF.SBP, m_env.BITBLTBUF.SBW), m_env.BITBLTBUF.DBP, m_env.BITBLTBUF.DBW); -} - -void GSState::SoftReset(BYTE mask) -{ - if(mask & 1) memset(&m_path[0], 0, sizeof(GIFPath)); - if(mask & 2) memset(&m_path[1], 0, sizeof(GIFPath)); - if(mask & 4) memset(&m_path[2], 0, sizeof(GIFPath)); - - m_env.TRXDIR.XDIR = 3; //-1 ; set it to invalid value - - m_q = 1; -} - -void GSState::ReadFIFO(BYTE* mem, int size) -{ - GSPerfMonAutoTimer pmat(m_perfmon); - - Flush(); - - size *= 16; - - Read(mem, size); - - if(m_dump) - { - m_dump.ReadFIFO(size); - } -} - -template void GSState::Transfer<0>(BYTE* mem, UINT32 size); -template void GSState::Transfer<1>(BYTE* mem, UINT32 size); -template void GSState::Transfer<2>(BYTE* mem, UINT32 size); - -template void GSState::Transfer(BYTE* mem, UINT32 size) -{ - GSPerfMonAutoTimer pmat(m_perfmon); - - BYTE* start = mem; - - GIFPath& path = m_path[index]; - - while(size > 0) - { - bool eop = false; - - if(path.tag.NLOOP == 0) - { - path.SetTag(mem); - - mem += sizeof(GIFTag); - size--; - - m_q = 1.0f; - - if(index == 2 && path.tag.EOP) - { - m_path3hack = 1; - } - - if(path.tag.PRE) - { - ASSERT(path.tag.FLG != GIF_FLG_IMAGE); // kingdom hearts, ffxii, tales of abyss, berserk - - if((path.tag.FLG & 2) == 0) - { - GIFReg r; - r.i64 = path.tag.PRIM; - (this->*m_fpGIFRegHandlers[GIF_A_D_REG_PRIM])(&r); - } - } - - if(path.tag.EOP) - { - eop = true; - } - else if(path.tag.NLOOP == 0) - { - if(index == 0 && m_nloophack) - { - continue; - } - - eop = true; - } - } - - if(path.tag.NLOOP > 0) - { - switch(path.tag.FLG) - { - case GIF_FLG_PACKED: - - // first try a shortcut for a very common case - - if(path.nreg == 0 && path.tag.NREG == 1 && size >= path.tag.NLOOP && path.GetReg() == GIF_REG_A_D) - { - int n = path.tag.NLOOP; - - GIFPackedRegHandlerA_D((GIFPackedReg*)mem, n); - - mem += n * sizeof(GIFPackedReg); - size -= n; - - path.tag.NLOOP = 0; - } - else - { - while(size > 0) - { - (this->*m_fpGIFPackedRegHandlers[path.GetReg()])((GIFPackedReg*)mem); - - size--; - mem += sizeof(GIFPackedReg); - - if((++path.nreg & 0xf) == path.tag.NREG) - { - path.nreg = 0; - path.tag.NLOOP--; - - if(path.tag.NLOOP == 0) - { - break; - } - } - } - } - - break; - - case GIF_FLG_REGLIST: - - size *= 2; - - while(size > 0) - { - (this->*m_fpGIFRegHandlers[path.GetReg()])((GIFReg*)mem); - - size--; - mem += sizeof(GIFReg); - - if((++path.nreg & 0xf) == path.tag.NREG) - { - path.nreg = 0; - path.tag.NLOOP--; - - if(path.tag.NLOOP == 0) - { - break; - } - } - } - - if(size & 1) mem += sizeof(GIFReg); - - size /= 2; - - break; - - case GIF_FLG_IMAGE2: // hmmm - - ASSERT(0); - - path.tag.NLOOP = 0; - - break; - - case GIF_FLG_IMAGE: - { - int len = (int)min(size, path.tag.NLOOP); - - //ASSERT(!(len&3)); - - switch(m_env.TRXDIR.XDIR) - { - case 0: - Write(mem, len * 16); - break; - case 1: - Read(mem, len * 16); - break; - case 2: - Move(); - break; - case 3: - ASSERT(0); - break; - default: - __assume(0); - } - - mem += len * 16; - path.tag.NLOOP -= len; - size -= len; - } - - break; - - default: - __assume(0); - } - } - - if(eop && ((int)size <= 0 || index == 0)) - { - break; - } - } - - // FIXME: dq8, pcsx2 error probably - - if(index == 0) - { - if(!path.tag.EOP && path.tag.NLOOP > 0) - { - path.tag.NLOOP = 0; - - TRACE(_T("path1 hack\n")); - } - } - - if(m_dump && mem > start) - { - m_dump.Transfer(index, start, mem - start); - } -} - -template static void WriteState(BYTE*& dst, T* src, size_t len = sizeof(T)) -{ - memcpy(dst, src, len); - dst += len; -} - -template static void ReadState(T* dst, BYTE*& src, size_t len = sizeof(T)) -{ - memcpy(dst, src, len); - src += len; -} - -int GSState::Freeze(GSFreezeData* fd, bool sizeonly) -{ - if(sizeonly) - { - fd->size = m_sssize; - return 0; - } - - if(!fd->data || fd->size < m_sssize) - { - return -1; - } - - Flush(); - - BYTE* data = fd->data; - - WriteState(data, &m_version); - WriteState(data, &m_env.PRIM); - WriteState(data, &m_env.PRMODE); - WriteState(data, &m_env.PRMODECONT); - WriteState(data, &m_env.TEXCLUT); - WriteState(data, &m_env.SCANMSK); - WriteState(data, &m_env.TEXA); - WriteState(data, &m_env.FOGCOL); - WriteState(data, &m_env.DIMX); - WriteState(data, &m_env.DTHE); - WriteState(data, &m_env.COLCLAMP); - WriteState(data, &m_env.PABE); - WriteState(data, &m_env.BITBLTBUF); - WriteState(data, &m_env.TRXDIR); - WriteState(data, &m_env.TRXPOS); - WriteState(data, &m_env.TRXREG); - WriteState(data, &m_env.TRXREG2); - - for(int i = 0; i < 2; i++) - { - WriteState(data, &m_env.CTXT[i].XYOFFSET); - WriteState(data, &m_env.CTXT[i].TEX0); - WriteState(data, &m_env.CTXT[i].TEX1); - WriteState(data, &m_env.CTXT[i].TEX2); - WriteState(data, &m_env.CTXT[i].CLAMP); - WriteState(data, &m_env.CTXT[i].MIPTBP1); - WriteState(data, &m_env.CTXT[i].MIPTBP2); - WriteState(data, &m_env.CTXT[i].SCISSOR); - WriteState(data, &m_env.CTXT[i].ALPHA); - WriteState(data, &m_env.CTXT[i].TEST); - WriteState(data, &m_env.CTXT[i].FBA); - WriteState(data, &m_env.CTXT[i].FRAME); - WriteState(data, &m_env.CTXT[i].ZBUF); - } - - WriteState(data, &m_v.RGBAQ); - WriteState(data, &m_v.ST); - WriteState(data, &m_v.UV); - WriteState(data, &m_v.XYZ); - WriteState(data, &m_v.FOG); - WriteState(data, &m_x); - WriteState(data, &m_y); - WriteState(data, m_mem.m_vm8, m_mem.m_vmsize); - - for(int i = 0; i < 3; i++) - { - WriteState(data, &m_path[i].tag); - WriteState(data, &m_path[i].nreg); - } - - WriteState(data, &m_q); - - return 0; -} - -int GSState::Defrost(const GSFreezeData* fd) -{ - if(!fd || !fd->data || fd->size == 0) - { - return -1; - } - - if(fd->size < m_sssize) - { - return -1; - } - - BYTE* data = fd->data; - - int version; - - ReadState(&version, data); - - if(version > m_version) - { - return -1; - } - - Flush(); - - Reset(); - - ReadState(&m_env.PRIM, data); - ReadState(&m_env.PRMODE, data); - ReadState(&m_env.PRMODECONT, data); - ReadState(&m_env.TEXCLUT, data); - ReadState(&m_env.SCANMSK, data); - ReadState(&m_env.TEXA, data); - ReadState(&m_env.FOGCOL, data); - ReadState(&m_env.DIMX, data); - ReadState(&m_env.DTHE, data); - ReadState(&m_env.COLCLAMP, data); - ReadState(&m_env.PABE, data); - ReadState(&m_env.BITBLTBUF, data); - ReadState(&m_env.TRXDIR, data); - ReadState(&m_env.TRXPOS, data); - ReadState(&m_env.TRXREG, data); - ReadState(&m_env.TRXREG2, data); - - for(int i = 0; i < 2; i++) - { - ReadState(&m_env.CTXT[i].XYOFFSET, data); - ReadState(&m_env.CTXT[i].TEX0, data); - ReadState(&m_env.CTXT[i].TEX1, data); - ReadState(&m_env.CTXT[i].TEX2, data); - ReadState(&m_env.CTXT[i].CLAMP, data); - ReadState(&m_env.CTXT[i].MIPTBP1, data); - ReadState(&m_env.CTXT[i].MIPTBP2, data); - ReadState(&m_env.CTXT[i].SCISSOR, data); - ReadState(&m_env.CTXT[i].ALPHA, data); - ReadState(&m_env.CTXT[i].TEST, data); - ReadState(&m_env.CTXT[i].FBA, data); - ReadState(&m_env.CTXT[i].FRAME, data); - ReadState(&m_env.CTXT[i].ZBUF, data); - - m_env.CTXT[i].XYOFFSET.OFX &= 0xffff; - m_env.CTXT[i].XYOFFSET.OFY &= 0xffff; - - if(version <= 4) - { - data += sizeof(DWORD) * 7; // skip - } - } - - ReadState(&m_v.RGBAQ, data); - ReadState(&m_v.ST, data); - ReadState(&m_v.UV, data); - ReadState(&m_v.XYZ, data); - ReadState(&m_v.FOG, data); - ReadState(&m_x, data); - ReadState(&m_y, data); - ReadState(m_mem.m_vm8, data, m_mem.m_vmsize); - - for(int i = 0; i < 3; i++) - { - ReadState(&m_path[i].tag, data); - ReadState(&m_path[i].nreg, data); - - m_path[i].SetTag(&m_path[i].tag); // expand regs - } - - ReadState(&m_q, data); - - PRIM = !m_env.PRMODECONT.AC ? (GIFRegPRIM*)&m_env.PRMODE : &m_env.PRIM; - - m_context = &m_env.CTXT[PRIM->CTXT]; - - UpdateVertexKick(); - - m_env.CTXT[0].UpdateScissor(); - m_env.CTXT[1].UpdateScissor(); - -m_perfmon.SetFrame(5000); - - return 0; -} - -void GSState::SetGameCRC(DWORD crc, int options) -{ - m_crc = crc; - m_options = options; - m_game = CRC::Lookup(crc); - - if(m_nloophack_org == 2) - { - m_nloophack = m_game.nloophack; - } -} - -void GSState::SetFrameSkip(int frameskip) -{ - if(m_frameskip != frameskip) - { - m_frameskip = frameskip; - - if(frameskip) - { - m_fpGIFPackedRegHandlers[GIF_REG_PRIM] = &GSState::GIFPackedRegHandlerNOP; - m_fpGIFPackedRegHandlers[GIF_REG_RGBA] = &GSState::GIFPackedRegHandlerNOP; - m_fpGIFPackedRegHandlers[GIF_REG_STQ] = &GSState::GIFPackedRegHandlerNOP; - m_fpGIFPackedRegHandlers[GIF_REG_UV] = &GSState::GIFPackedRegHandlerNOP; - m_fpGIFPackedRegHandlers[GIF_REG_XYZF2] = &GSState::GIFPackedRegHandlerNOP; - m_fpGIFPackedRegHandlers[GIF_REG_XYZ2] = &GSState::GIFPackedRegHandlerNOP; - m_fpGIFPackedRegHandlers[GIF_REG_CLAMP_1] = &GSState::GIFPackedRegHandlerNOP; - m_fpGIFPackedRegHandlers[GIF_REG_CLAMP_2] = &GSState::GIFPackedRegHandlerNOP; - m_fpGIFPackedRegHandlers[GIF_REG_FOG] = &GSState::GIFPackedRegHandlerNOP; - m_fpGIFPackedRegHandlers[GIF_REG_XYZF3] = &GSState::GIFPackedRegHandlerNOP; - m_fpGIFPackedRegHandlers[GIF_REG_XYZ3] = &GSState::GIFPackedRegHandlerNOP; - - m_fpGIFRegHandlers[GIF_A_D_REG_PRIM] = &GSState::GIFRegHandlerNOP; - m_fpGIFRegHandlers[GIF_A_D_REG_RGBAQ] = &GSState::GIFRegHandlerNOP; - m_fpGIFRegHandlers[GIF_A_D_REG_ST] = &GSState::GIFRegHandlerNOP; - m_fpGIFRegHandlers[GIF_A_D_REG_UV] = &GSState::GIFRegHandlerNOP; - m_fpGIFRegHandlers[GIF_A_D_REG_XYZF2] = &GSState::GIFRegHandlerNOP; - m_fpGIFRegHandlers[GIF_A_D_REG_XYZ2] = &GSState::GIFRegHandlerNOP; - m_fpGIFRegHandlers[GIF_A_D_REG_XYZF3] = &GSState::GIFRegHandlerNOP; - m_fpGIFRegHandlers[GIF_A_D_REG_XYZ3] = &GSState::GIFRegHandlerNOP; - m_fpGIFRegHandlers[GIF_A_D_REG_PRMODECONT] = &GSState::GIFRegHandlerNOP; - m_fpGIFRegHandlers[GIF_A_D_REG_PRMODE] = &GSState::GIFRegHandlerNOP; - } - else - { - m_fpGIFPackedRegHandlers[GIF_REG_PRIM] = &GSState::GIFPackedRegHandlerPRIM; - m_fpGIFPackedRegHandlers[GIF_REG_RGBA] = &GSState::GIFPackedRegHandlerRGBA; - m_fpGIFPackedRegHandlers[GIF_REG_STQ] = &GSState::GIFPackedRegHandlerSTQ; - m_fpGIFPackedRegHandlers[GIF_REG_UV] = &GSState::GIFPackedRegHandlerUV; - m_fpGIFPackedRegHandlers[GIF_REG_XYZF2] = &GSState::GIFPackedRegHandlerXYZF2; - m_fpGIFPackedRegHandlers[GIF_REG_XYZ2] = &GSState::GIFPackedRegHandlerXYZ2; - m_fpGIFPackedRegHandlers[GIF_REG_CLAMP_1] = &GSState::GIFPackedRegHandlerCLAMP<0>; - m_fpGIFPackedRegHandlers[GIF_REG_CLAMP_2] = &GSState::GIFPackedRegHandlerCLAMP<1>; - m_fpGIFPackedRegHandlers[GIF_REG_FOG] = &GSState::GIFPackedRegHandlerFOG; - m_fpGIFPackedRegHandlers[GIF_REG_XYZF3] = &GSState::GIFPackedRegHandlerXYZF3; - m_fpGIFPackedRegHandlers[GIF_REG_XYZ3] = &GSState::GIFPackedRegHandlerXYZ3; - - m_fpGIFRegHandlers[GIF_A_D_REG_PRIM] = &GSState::GIFRegHandlerPRIM; - m_fpGIFRegHandlers[GIF_A_D_REG_RGBAQ] = &GSState::GIFRegHandlerRGBAQ; - m_fpGIFRegHandlers[GIF_A_D_REG_ST] = &GSState::GIFRegHandlerST; - m_fpGIFRegHandlers[GIF_A_D_REG_UV] = &GSState::GIFRegHandlerUV; - m_fpGIFRegHandlers[GIF_A_D_REG_XYZF2] = &GSState::GIFRegHandlerXYZF2; - m_fpGIFRegHandlers[GIF_A_D_REG_XYZ2] = &GSState::GIFRegHandlerXYZ2; - m_fpGIFRegHandlers[GIF_A_D_REG_XYZF3] = &GSState::GIFRegHandlerXYZF3; - m_fpGIFRegHandlers[GIF_A_D_REG_XYZ3] = &GSState::GIFRegHandlerXYZ3; - m_fpGIFRegHandlers[GIF_A_D_REG_PRMODECONT] = &GSState::GIFRegHandlerPRMODECONT; - m_fpGIFRegHandlers[GIF_A_D_REG_PRMODE] = &GSState::GIFRegHandlerPRMODE; - } - } -} - -// hacks - -struct GSFrameInfo -{ - DWORD FBP; - DWORD FPSM; - bool TME; - DWORD TBP0; - DWORD TPSM; -}; - -typedef bool (*GetSkipCount)(const GSFrameInfo& fi, int& skip); - -bool GSC_Okami(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && fi.FBP == 0x00e00 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x00000 && fi.TPSM == PSM_PSMCT32) - { - skip = 1000; - } - } - else - { - if(fi.TME && fi.FBP == 0x00e00 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x03800 && fi.TPSM == PSM_PSMT4) - { - skip = 0; - } - } - - return true; -} - -bool GSC_MetalGearSolid3(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && fi.FBP == 0x02000 && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01000) && fi.TPSM == PSM_PSMCT24) - { - skip = 1000; // 76, 79 - } - else if(fi.TME && fi.FBP == 0x02800 && fi.FPSM == PSM_PSMCT24 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01000) && fi.TPSM == PSM_PSMCT32) - { - skip = 1000; // 69 - } - } - else - { - if(!fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x01000) && fi.FPSM == PSM_PSMCT32) - { - skip = 0; - } - } - - return true; -} - -bool GSC_DBZBT2(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && /*fi.FBP == 0x00000 && fi.FPSM == PSM_PSMCT16 &&*/ fi.TBP0 == 0x02000 && fi.TPSM == PSM_PSMZ16) - { - skip = 27; - } - else if(!fi.TME && fi.FBP == 0x03000 && fi.FPSM == PSM_PSMCT16) - { - skip = 10; - } - } - - return true; -} - -bool GSC_DBZBT3(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && fi.FBP == 0x01c00 && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x00e00) && fi.TPSM == PSM_PSMT8H) - { - skip = 24; // blur - } - else if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x00e00) && fi.FPSM == PSM_PSMCT32 && fi.TPSM == PSM_PSMT8H) - { - skip = 28; // outline - } - } - - return true; -} - -bool GSC_SFEX3(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && fi.FBP == 0x00f00 && fi.FPSM == PSM_PSMCT16 && (fi.TBP0 == 0x00500 || fi.TBP0 == 0x00000) && fi.TPSM == PSM_PSMCT32) - { - skip = 4; - } - } - - return true; -} - -bool GSC_Bully(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x01180) && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01180) && fi.FBP == fi.TBP0 && fi.FPSM == PSM_PSMCT32 && fi.FPSM == fi.TPSM) - { - return false; // allowed - } - - if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x01180) && fi.FPSM == PSM_PSMCT16S && fi.TBP0 == 0x02300 && fi.TPSM == PSM_PSMZ16S) - { - skip = 6; - } - } - else - { - if(!fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x01180) && fi.FPSM == PSM_PSMCT32) - { - skip = 0; - } - } - - return true; -} - -bool GSC_BullyCC(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x01180) && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01180) && fi.FBP == fi.TBP0 && fi.FPSM == PSM_PSMCT32 && fi.FPSM == fi.TPSM) - { - return false; // allowed - } - - if(!fi.TME && fi.FBP == 0x02800 && fi.FPSM == PSM_PSMCT24) - { - skip = 9; - } - } - - return true; -} -bool GSC_SoTC(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && fi.FBP == 0x02b80 && fi.FPSM == PSM_PSMCT24 && fi.TBP0 == 0x01e80 && fi.TPSM == PSM_PSMCT24) - { - skip = 9; - } - else if(fi.TME && fi.FBP == 0x01c00 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x03800 && fi.TPSM == PSM_PSMCT32) - { - skip = 8; - } - else if(fi.TME && fi.FBP == 0x01e80 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x03880 && fi.TPSM == PSM_PSMCT32) - { - skip = 8; - } - } - - return true; -} - -bool GSC_OnePieceGrandAdventure(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && fi.FBP == 0x02d00 && fi.FPSM == PSM_PSMCT16 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x00e00) && fi.TPSM == PSM_PSMCT16) - { - skip = 3; - } - } - - return true; -} - -bool GSC_ICO(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && fi.FBP == 0x00800 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x03d00 && fi.TPSM == PSM_PSMCT32) - { - skip = 3; - } - else if(fi.TME && fi.FBP == 0x00800 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x02800 && fi.TPSM == PSM_PSMT8H) - { - skip = 1; - } - } - else - { - if(fi.TME && fi.TBP0 == 0x00800 && fi.TPSM == PSM_PSMCT32) - { - skip = 0; - } - } - - return true; -} - -bool GSC_GT4(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && (fi.FBP == 0x03440 || fi.FBP >= 0x03e00) && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01400) && fi.TPSM == PSM_PSMT8) - { - skip = 880; - } - else if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x01400) && fi.FPSM == PSM_PSMCT24 && fi.TBP0 >= 0x03420 && fi.TPSM == PSM_PSMT8) - { - // TODO: removes gfx from where it is not supposed to (garage) - // skip = 58; - } - } - - return true; -} - -bool GSC_WildArms5(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && fi.FBP == 0x03100 && fi.FPSM == PSM_PSMZ32 && fi.TBP0 == 0x01c00 && fi.TPSM == PSM_PSMZ32) - { - skip = 100; - } - } - else - { - if(fi.TME && fi.FBP == 0x00e00 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x02a00 && fi.TPSM == PSM_PSMCT32) - { - skip = 1; - } - } - - return true; -} - -bool GSC_Manhunt2(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && fi.FBP == 0x03c20 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x01400 && fi.TPSM == PSM_PSMT8) - { - skip = 640; - } - } - - return true; -} - -bool GSC_CrashBandicootWoC(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x00a00) && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x00a00) && fi.FBP == fi.TBP0 && fi.FPSM == PSM_PSMCT32 && fi.FPSM == fi.TPSM) - { - return false; // allowed - } - - if(fi.TME && fi.FBP == 0x02200 && fi.FPSM == PSM_PSMZ24 && fi.TBP0 == 0x01400 && fi.TPSM == PSM_PSMZ24) - { - skip = 41; - } - } - else - { - if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x00a00) && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x03c00 && fi.TPSM == PSM_PSMCT32) - { - skip = 0; - } - else if(!fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x00a00)) - { - skip = 0; - } - } - - return true; -} - -bool GSC_ResidentEvil4(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && fi.FBP == 0x03100 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x01c00 && fi.TPSM == PSM_PSMZ24) - { - skip = 176; - } - } - - return true; -} - -bool GSC_Spartan(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && fi.FBP == 0x02000 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x00000 && fi.TPSM == PSM_PSMCT32) - { - skip = 107; - } - } - - return true; -} - -bool GSC_AceCombat4(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && fi.FBP == 0x02a00 && fi.FPSM == PSM_PSMZ24 && fi.TBP0 == 0x01600 && fi.TPSM == PSM_PSMZ24) - { - skip = 71; // clouds (z, 16-bit) - } - else if(fi.TME && fi.FBP == 0x02900 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x00000 && fi.TPSM == PSM_PSMCT24) - { - skip = 28; // blur - } - } - - return true; -} - -bool GSC_Drakengard2(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && fi.FBP == 0x026c0 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x00a00 && fi.TPSM == PSM_PSMCT32) - { - skip = 64; - } - } - - return true; -} - -bool GSC_Tekken5(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && fi.FBP == 0x02ea0 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x00000 && fi.TPSM == PSM_PSMCT32) - { - skip = 95; - } - } - - return true; -} - -bool GSC_IkkiTousen(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && fi.FBP == 0x00a80 && fi.FPSM == PSM_PSMZ24 && fi.TBP0 == 0x01180 && fi.TPSM == PSM_PSMZ24) - { - skip = 1000; // shadow (result is broken without depth copy, also includes 16 bit) - } - else if(fi.TME && fi.FBP == 0x00700 && fi.FPSM == PSM_PSMZ24 && fi.TBP0 == 0x01180 && fi.TPSM == PSM_PSMZ24) - { - skip = 11; // blur - } - } - else if(skip > 7) - { - if(fi.TME && fi.FBP == 0x00700 && fi.FPSM == PSM_PSMCT16 && fi.TBP0 == 0x00700 && fi.TPSM == PSM_PSMCT16) - { - skip = 7; // the last steps of shadow drawing - } - } - - return true; -} - -bool GSC_GodOfWar(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && fi.FBP == 0x00000 && fi.FPSM == PSM_PSMCT16 && fi.TBP0 == 0x00000 && fi.TPSM == PSM_PSMCT16) - { - skip = 30; - } - } - else - { - } - - return true; -} - -bool GSC_GiTS(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && fi.FBP == 0x01400 && fi.FPSM == PSM_PSMCT16 && fi.TBP0 == 0x02e40 && fi.TPSM == PSM_PSMCT16) - { - skip = 1315; - } - } - else - { - } - - return true; -} - -bool GSC_Onimusha3(const GSFrameInfo& fi, int& skip) -{ - if(fi.TME /*&& (fi.FBP == 0x00000 || fi.FBP == 0x00700)*/ && (fi.TBP0 == 0x01180 || fi.TBP0 == 0x00e00 || fi.TBP0 == 0x01000 || fi.TBP0 == 0x01200) && (fi.TPSM == PSM_PSMCT32 || fi.TPSM == PSM_PSMCT24)) - { - skip = 1; - } - - return true; -} - -bool GSC_TalesOfAbyss(const GSFrameInfo& fi, int& skip) -{ - if(skip == 0) - { - if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x00e00) && fi.TBP0 == 0x01c00 && fi.TPSM == PSM_PSMT8) // copies the z buffer to the alpha channel of the fb - { - skip = 1000; - } - else if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x00e00) && (fi.TBP0 == 0x03560 || fi.TBP0 == 0x038e0) && fi.TPSM == PSM_PSMCT32) - { - skip = 1; - } - } - else - { - if(fi.TME && fi.TPSM != PSM_PSMT8) - { - skip = 0; - } - } - - return true; -} - -bool GSState::IsBadFrame(int& skip) -{ - GSFrameInfo fi; - - fi.FBP = m_context->FRAME.Block(); - fi.FPSM = m_context->FRAME.PSM; - fi.TME = PRIM->TME; - fi.TBP0 = m_context->TEX0.TBP0; - fi.TPSM = m_context->TEX0.PSM; - - static GetSkipCount map[CRC::TitleCount]; - static bool inited = false; - - if(!inited) - { - inited = true; - - memset(map, 0, sizeof(map)); - - map[CRC::Okami] = GSC_Okami; - map[CRC::MetalGearSolid3] = GSC_MetalGearSolid3; - map[CRC::DBZBT2] = GSC_DBZBT2; - map[CRC::DBZBT3] = GSC_DBZBT3; - map[CRC::SFEX3] = GSC_SFEX3; - map[CRC::Bully] = GSC_Bully; - map[CRC::BullyCC] = GSC_BullyCC; - map[CRC::SoTC] = GSC_SoTC; - map[CRC::OnePieceGrandAdventure] = GSC_OnePieceGrandAdventure; - map[CRC::ICO] = GSC_ICO; - map[CRC::GT4] = GSC_GT4; - map[CRC::WildArms5] = GSC_WildArms5; - map[CRC::Manhunt2] = GSC_Manhunt2; - map[CRC::CrashBandicootWoC] = GSC_CrashBandicootWoC; - map[CRC::ResidentEvil4] = GSC_ResidentEvil4; - map[CRC::Spartan] = GSC_Spartan; - map[CRC::AceCombat4] = GSC_AceCombat4; - map[CRC::Drakengard2] = GSC_Drakengard2; - map[CRC::Tekken5] = GSC_Tekken5; - map[CRC::IkkiTousen] = GSC_IkkiTousen; - map[CRC::GodOfWar] = GSC_GodOfWar; - map[CRC::GodOfWar2] = GSC_GodOfWar; - map[CRC::GiTS] = GSC_GiTS; - map[CRC::Onimusha3] = GSC_Onimusha3; - map[CRC::TalesOfAbyss] = GSC_TalesOfAbyss; - } - - // TODO: just set gsc in SetGameCRC once - - GetSkipCount gsc = map[m_game.title]; - - if(gsc && !gsc(fi, skip)) - { - return false; - } - - if(skip == 0) - { - if(fi.TME) - { - if(GSUtil::HasSharedBits(fi.FBP, fi.FPSM, fi.TBP0, fi.TPSM)) - { - // skip = 1; - } - - // depth textures (bully, mgs3s1 intro) - - if(fi.TPSM == PSM_PSMZ32 || fi.TPSM == PSM_PSMZ24 || fi.TPSM == PSM_PSMZ16 || fi.TPSM == PSM_PSMZ16S) - { - skip = 1; - } - } - } - - if(skip > 0) - { - skip--; - - return true; - } - - return false; -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSState.h" + +GSState::GSState(BYTE* base, bool mt, void (*irq)(), int nloophack) + : m_mt(mt) + , m_irq(irq) + , m_nloophack_org(nloophack) + , m_nloophack(nloophack == 1) + , m_crc(0) + , m_options(0) + , m_path3hack(0) + , m_q(1.0f) + , m_vprim(1) + , m_version(5) + , m_frameskip(0) + , m_vkf(NULL) +{ + m_sssize = 0; + + m_sssize += sizeof(m_version); + m_sssize += sizeof(m_env.PRIM); + m_sssize += sizeof(m_env.PRMODE); + m_sssize += sizeof(m_env.PRMODECONT); + m_sssize += sizeof(m_env.TEXCLUT); + m_sssize += sizeof(m_env.SCANMSK); + m_sssize += sizeof(m_env.TEXA); + m_sssize += sizeof(m_env.FOGCOL); + m_sssize += sizeof(m_env.DIMX); + m_sssize += sizeof(m_env.DTHE); + m_sssize += sizeof(m_env.COLCLAMP); + m_sssize += sizeof(m_env.PABE); + m_sssize += sizeof(m_env.BITBLTBUF); + m_sssize += sizeof(m_env.TRXDIR); + m_sssize += sizeof(m_env.TRXPOS); + m_sssize += sizeof(m_env.TRXREG); + m_sssize += sizeof(m_env.TRXREG2); + + for(int i = 0; i < 2; i++) + { + m_sssize += sizeof(m_env.CTXT[i].XYOFFSET); + m_sssize += sizeof(m_env.CTXT[i].TEX0); + m_sssize += sizeof(m_env.CTXT[i].TEX1); + m_sssize += sizeof(m_env.CTXT[i].TEX2); + m_sssize += sizeof(m_env.CTXT[i].CLAMP); + m_sssize += sizeof(m_env.CTXT[i].MIPTBP1); + m_sssize += sizeof(m_env.CTXT[i].MIPTBP2); + m_sssize += sizeof(m_env.CTXT[i].SCISSOR); + m_sssize += sizeof(m_env.CTXT[i].ALPHA); + m_sssize += sizeof(m_env.CTXT[i].TEST); + m_sssize += sizeof(m_env.CTXT[i].FBA); + m_sssize += sizeof(m_env.CTXT[i].FRAME); + m_sssize += sizeof(m_env.CTXT[i].ZBUF); + } + + m_sssize += sizeof(m_v.RGBAQ); + m_sssize += sizeof(m_v.ST); + m_sssize += sizeof(m_v.UV); + m_sssize += sizeof(m_v.XYZ); + m_sssize += sizeof(m_v.FOG); + + m_sssize += sizeof(m_x); + m_sssize += sizeof(m_y); + m_sssize += m_mem.m_vmsize; + m_sssize += (sizeof(m_path[0].tag) + sizeof(m_path[0].nreg)) * 3; + m_sssize += sizeof(m_q); + + ASSERT(base); + + PMODE = (GSRegPMODE*)(base + GS_PMODE); + SMODE1 = (GSRegSMODE1*)(base + GS_SMODE1); + SMODE2 = (GSRegSMODE2*)(base + GS_SMODE2); + // SRFSH = (GSRegPMODE*)(base + GS_SRFSH); + // SYNCH1 = (GSRegPMODE*)(base + GS_SYNCH1); + // SYNCH2 = (GSRegPMODE*)(base + GS_SYNCH2); + // SYNCV = (GSRegPMODE*)(base + GS_SYNCV); + DISPFB[0] = (GSRegDISPFB*)(base + GS_DISPFB1); + DISPFB[1] = (GSRegDISPFB*)(base + GS_DISPFB2); + DISPLAY[0] = (GSRegDISPLAY*)(base + GS_DISPLAY1); + DISPLAY[1] = (GSRegDISPLAY*)(base + GS_DISPLAY2); + EXTBUF = (GSRegEXTBUF*)(base + GS_EXTBUF); + EXTDATA = (GSRegEXTDATA*)(base + GS_EXTDATA); + EXTWRITE = (GSRegEXTWRITE*)(base + GS_EXTWRITE); + BGCOLOR = (GSRegBGCOLOR*)(base + GS_BGCOLOR); + CSR = (GSRegCSR*)(base + GS_CSR); + IMR = (GSRegIMR*)(base + GS_IMR); + BUSDIR = (GSRegBUSDIR*)(base + GS_BUSDIR); + SIGLBLID = (GSRegSIGLBLID*)(base + GS_SIGLBLID); + + PRIM = &m_env.PRIM; +// CSR->rREV = 0x20; + m_env.PRMODECONT.AC = 1; + + m_x = m_y = 0; + m_bytes = 0; + m_maxbytes = 1024 * 1024 * 4; + m_buff = (BYTE*)_aligned_malloc(m_maxbytes, 16); + + Reset(); + + ResetHandlers(); +} + +GSState::~GSState() +{ + _aligned_free(m_buff); +} + +void GSState::Reset() +{ + memset(&m_path[0], 0, sizeof(m_path[0]) * 3); + memset(&m_v, 0, sizeof(m_v)); + +// PRIM = &m_env.PRIM; +// m_env.PRMODECONT.AC = 1; + + m_env.Reset(); + + m_context = &m_env.CTXT[0]; + + InvalidateTextureCache(); +} + +void GSState::ResetHandlers() +{ + for(int i = 0; i < countof(m_fpGIFPackedRegHandlers); i++) + { + m_fpGIFPackedRegHandlers[i] = &GSState::GIFPackedRegHandlerNull; + } + + m_fpGIFPackedRegHandlers[GIF_REG_PRIM] = &GSState::GIFPackedRegHandlerPRIM; + m_fpGIFPackedRegHandlers[GIF_REG_RGBA] = &GSState::GIFPackedRegHandlerRGBA; + m_fpGIFPackedRegHandlers[GIF_REG_STQ] = &GSState::GIFPackedRegHandlerSTQ; + m_fpGIFPackedRegHandlers[GIF_REG_UV] = &GSState::GIFPackedRegHandlerUV; + m_fpGIFPackedRegHandlers[GIF_REG_XYZF2] = &GSState::GIFPackedRegHandlerXYZF2; + m_fpGIFPackedRegHandlers[GIF_REG_XYZ2] = &GSState::GIFPackedRegHandlerXYZ2; + m_fpGIFPackedRegHandlers[GIF_REG_TEX0_1] = &GSState::GIFPackedRegHandlerTEX0<0>; + m_fpGIFPackedRegHandlers[GIF_REG_TEX0_2] = &GSState::GIFPackedRegHandlerTEX0<1>; + m_fpGIFPackedRegHandlers[GIF_REG_CLAMP_1] = &GSState::GIFPackedRegHandlerCLAMP<0>; + m_fpGIFPackedRegHandlers[GIF_REG_CLAMP_2] = &GSState::GIFPackedRegHandlerCLAMP<1>; + m_fpGIFPackedRegHandlers[GIF_REG_FOG] = &GSState::GIFPackedRegHandlerFOG; + m_fpGIFPackedRegHandlers[GIF_REG_XYZF3] = &GSState::GIFPackedRegHandlerXYZF3; + m_fpGIFPackedRegHandlers[GIF_REG_XYZ3] = &GSState::GIFPackedRegHandlerXYZ3; + m_fpGIFPackedRegHandlers[GIF_REG_A_D] = &GSState::GIFPackedRegHandlerA_D; + m_fpGIFPackedRegHandlers[GIF_REG_NOP] = &GSState::GIFPackedRegHandlerNOP; + + for(int i = 0; i < countof(m_fpGIFRegHandlers); i++) + { + m_fpGIFRegHandlers[i] = &GSState::GIFRegHandlerNull; + } + + m_fpGIFRegHandlers[GIF_A_D_REG_PRIM] = &GSState::GIFRegHandlerPRIM; + m_fpGIFRegHandlers[GIF_A_D_REG_RGBAQ] = &GSState::GIFRegHandlerRGBAQ; + m_fpGIFRegHandlers[GIF_A_D_REG_ST] = &GSState::GIFRegHandlerST; + m_fpGIFRegHandlers[GIF_A_D_REG_UV] = &GSState::GIFRegHandlerUV; + m_fpGIFRegHandlers[GIF_A_D_REG_XYZF2] = &GSState::GIFRegHandlerXYZF2; + m_fpGIFRegHandlers[GIF_A_D_REG_XYZ2] = &GSState::GIFRegHandlerXYZ2; + m_fpGIFRegHandlers[GIF_A_D_REG_TEX0_1] = &GSState::GIFRegHandlerTEX0<0>; + m_fpGIFRegHandlers[GIF_A_D_REG_TEX0_2] = &GSState::GIFRegHandlerTEX0<1>; + m_fpGIFRegHandlers[GIF_A_D_REG_CLAMP_1] = &GSState::GIFRegHandlerCLAMP<0>; + m_fpGIFRegHandlers[GIF_A_D_REG_CLAMP_2] = &GSState::GIFRegHandlerCLAMP<1>; + m_fpGIFRegHandlers[GIF_A_D_REG_FOG] = &GSState::GIFRegHandlerFOG; + m_fpGIFRegHandlers[GIF_A_D_REG_XYZF3] = &GSState::GIFRegHandlerXYZF3; + m_fpGIFRegHandlers[GIF_A_D_REG_XYZ3] = &GSState::GIFRegHandlerXYZ3; + m_fpGIFRegHandlers[GIF_A_D_REG_NOP] = &GSState::GIFRegHandlerNOP; + m_fpGIFRegHandlers[GIF_A_D_REG_TEX1_1] = &GSState::GIFRegHandlerTEX1<0>; + m_fpGIFRegHandlers[GIF_A_D_REG_TEX1_2] = &GSState::GIFRegHandlerTEX1<1>; + m_fpGIFRegHandlers[GIF_A_D_REG_TEX2_1] = &GSState::GIFRegHandlerTEX2<0>; + m_fpGIFRegHandlers[GIF_A_D_REG_TEX2_2] = &GSState::GIFRegHandlerTEX2<1>; + m_fpGIFRegHandlers[GIF_A_D_REG_XYOFFSET_1] = &GSState::GIFRegHandlerXYOFFSET<0>; + m_fpGIFRegHandlers[GIF_A_D_REG_XYOFFSET_2] = &GSState::GIFRegHandlerXYOFFSET<1>; + m_fpGIFRegHandlers[GIF_A_D_REG_PRMODECONT] = &GSState::GIFRegHandlerPRMODECONT; + m_fpGIFRegHandlers[GIF_A_D_REG_PRMODE] = &GSState::GIFRegHandlerPRMODE; + m_fpGIFRegHandlers[GIF_A_D_REG_TEXCLUT] = &GSState::GIFRegHandlerTEXCLUT; + m_fpGIFRegHandlers[GIF_A_D_REG_SCANMSK] = &GSState::GIFRegHandlerSCANMSK; + m_fpGIFRegHandlers[GIF_A_D_REG_MIPTBP1_1] = &GSState::GIFRegHandlerMIPTBP1<0>; + m_fpGIFRegHandlers[GIF_A_D_REG_MIPTBP1_2] = &GSState::GIFRegHandlerMIPTBP1<1>; + m_fpGIFRegHandlers[GIF_A_D_REG_MIPTBP2_1] = &GSState::GIFRegHandlerMIPTBP2<0>; + m_fpGIFRegHandlers[GIF_A_D_REG_MIPTBP2_2] = &GSState::GIFRegHandlerMIPTBP2<1>; + m_fpGIFRegHandlers[GIF_A_D_REG_TEXA] = &GSState::GIFRegHandlerTEXA; + m_fpGIFRegHandlers[GIF_A_D_REG_FOGCOL] = &GSState::GIFRegHandlerFOGCOL; + m_fpGIFRegHandlers[GIF_A_D_REG_TEXFLUSH] = &GSState::GIFRegHandlerTEXFLUSH; + m_fpGIFRegHandlers[GIF_A_D_REG_SCISSOR_1] = &GSState::GIFRegHandlerSCISSOR<0>; + m_fpGIFRegHandlers[GIF_A_D_REG_SCISSOR_2] = &GSState::GIFRegHandlerSCISSOR<1>; + m_fpGIFRegHandlers[GIF_A_D_REG_ALPHA_1] = &GSState::GIFRegHandlerALPHA<0>; + m_fpGIFRegHandlers[GIF_A_D_REG_ALPHA_2] = &GSState::GIFRegHandlerALPHA<1>; + m_fpGIFRegHandlers[GIF_A_D_REG_DIMX] = &GSState::GIFRegHandlerDIMX; + m_fpGIFRegHandlers[GIF_A_D_REG_DTHE] = &GSState::GIFRegHandlerDTHE; + m_fpGIFRegHandlers[GIF_A_D_REG_COLCLAMP] = &GSState::GIFRegHandlerCOLCLAMP; + m_fpGIFRegHandlers[GIF_A_D_REG_TEST_1] = &GSState::GIFRegHandlerTEST<0>; + m_fpGIFRegHandlers[GIF_A_D_REG_TEST_2] = &GSState::GIFRegHandlerTEST<1>; + m_fpGIFRegHandlers[GIF_A_D_REG_PABE] = &GSState::GIFRegHandlerPABE; + m_fpGIFRegHandlers[GIF_A_D_REG_FBA_1] = &GSState::GIFRegHandlerFBA<0>; + m_fpGIFRegHandlers[GIF_A_D_REG_FBA_2] = &GSState::GIFRegHandlerFBA<1>; + m_fpGIFRegHandlers[GIF_A_D_REG_FRAME_1] = &GSState::GIFRegHandlerFRAME<0>; + m_fpGIFRegHandlers[GIF_A_D_REG_FRAME_2] = &GSState::GIFRegHandlerFRAME<1>; + m_fpGIFRegHandlers[GIF_A_D_REG_ZBUF_1] = &GSState::GIFRegHandlerZBUF<0>; + m_fpGIFRegHandlers[GIF_A_D_REG_ZBUF_2] = &GSState::GIFRegHandlerZBUF<1>; + m_fpGIFRegHandlers[GIF_A_D_REG_BITBLTBUF] = &GSState::GIFRegHandlerBITBLTBUF; + m_fpGIFRegHandlers[GIF_A_D_REG_TRXPOS] = &GSState::GIFRegHandlerTRXPOS; + m_fpGIFRegHandlers[GIF_A_D_REG_TRXREG] = &GSState::GIFRegHandlerTRXREG; + m_fpGIFRegHandlers[GIF_A_D_REG_TRXDIR] = &GSState::GIFRegHandlerTRXDIR; + m_fpGIFRegHandlers[GIF_A_D_REG_HWREG] = &GSState::GIFRegHandlerHWREG; + m_fpGIFRegHandlers[GIF_A_D_REG_SIGNAL] = &GSState::GIFRegHandlerSIGNAL; + m_fpGIFRegHandlers[GIF_A_D_REG_FINISH] = &GSState::GIFRegHandlerFINISH; + m_fpGIFRegHandlers[GIF_A_D_REG_LABEL] = &GSState::GIFRegHandlerLABEL; +} + +CPoint GSState::GetDisplayPos(int i) +{ + ASSERT(i >= 0 && i < 2); + + CPoint p; + + p.x = DISPLAY[i]->DX / (DISPLAY[i]->MAGH + 1); + p.y = DISPLAY[i]->DY / (DISPLAY[i]->MAGV + 1); + + return p; +} + +CSize GSState::GetDisplaySize(int i) +{ + ASSERT(i >= 0 && i < 2); + + CSize s; + + s.cx = (DISPLAY[i]->DW + 1) / (DISPLAY[i]->MAGH + 1); + s.cy = (DISPLAY[i]->DH + 1) / (DISPLAY[i]->MAGV + 1); + + return s; +} + +CRect GSState::GetDisplayRect(int i) +{ + return CRect(GetDisplayPos(i), GetDisplaySize(i)); +} + +CSize GSState::GetDisplayPos() +{ + return GetDisplayPos(IsEnabled(1) ? 1 : 0); +} + +CSize GSState::GetDisplaySize() +{ + return GetDisplaySize(IsEnabled(1) ? 1 : 0); +} + +CRect GSState::GetDisplayRect() +{ + return GetDisplayRect(IsEnabled(1) ? 1 : 0); +} + +CPoint GSState::GetFramePos(int i) +{ + ASSERT(i >= 0 && i < 2); + + return CPoint(DISPFB[i]->DBX, DISPFB[i]->DBY); +} + +CSize GSState::GetFrameSize(int i) +{ + CSize s = GetDisplaySize(i); + + if(SMODE2->INT && SMODE2->FFMD && s.cy > 1) s.cy >>= 1; + + return s; +} + +CRect GSState::GetFrameRect(int i) +{ + return CRect(GetFramePos(i), GetFrameSize(i)); +} + +CSize GSState::GetFramePos() +{ + return GetFramePos(IsEnabled(1) ? 1 : 0); +} + +CSize GSState::GetFrameSize() +{ + return GetFrameSize(IsEnabled(1) ? 1 : 0); +} + +CRect GSState::GetFrameRect() +{ + return GetFrameRect(IsEnabled(1) ? 1 : 0); +} + +CSize GSState::GetDeviceSize(int i) +{ + // TODO: other params of SMODE1 should affect the true device display size + + // TODO2: pal games at 60Hz + + CSize s = GetDisplaySize(i); + + if(s.cy == 2*416 || s.cy == 2*448 || s.cy == 2*512) + { + s.cy /= 2; + } + else + { + s.cy = (SMODE1->CMOD & 1) ? 512 : 448; + } + + return s; + +} + +CSize GSState::GetDeviceSize() +{ + return GetDeviceSize(IsEnabled(1) ? 1 : 0); +} + +bool GSState::IsEnabled(int i) +{ + ASSERT(i >= 0 && i < 2); + + if(i == 0 && PMODE->EN1) + { + return DISPLAY[0]->DW || DISPLAY[0]->DH; + } + else if(i == 1 && PMODE->EN2) + { + return DISPLAY[1]->DW || DISPLAY[1]->DH; + } + + return false; +} + +int GSState::GetFPS() +{ + return ((SMODE1->CMOD & 1) ? 50 : 60) / (SMODE2->INT ? 1 : 2); +} + +// GIFPackedRegHandler* + +void GSState::GIFPackedRegHandlerNull(GIFPackedReg* r) +{ + // ASSERT(0); +} + +void GSState::GIFPackedRegHandlerPRIM(GIFPackedReg* r) +{ + // ASSERT(r->r.PRIM.PRIM < 7); + + GIFRegHandlerPRIM(&r->r); +} + +void GSState::GIFPackedRegHandlerRGBA(GIFPackedReg* r) +{ + #if _M_SSE >= 0x301 + + GSVector4i mask = GSVector4i::load(0x0c080400); + GSVector4i v = GSVector4i::load(r).shuffle8(mask); + m_v.RGBAQ.ai32[0] = (UINT32)GSVector4i::store(v); + + #elif _M_SSE >= 0x200 + + GSVector4i v = GSVector4i::load(r) & GSVector4i::x000000ff(); + m_v.RGBAQ.ai32[0] = v.rgba32(); + + #else + + m_v.RGBAQ.R = r->RGBA.R; + m_v.RGBAQ.G = r->RGBA.G; + m_v.RGBAQ.B = r->RGBA.B; + m_v.RGBAQ.A = r->RGBA.A; + + #endif + + m_v.RGBAQ.Q = m_q; +} + +void GSState::GIFPackedRegHandlerSTQ(GIFPackedReg* r) +{ + #if defined(_M_AMD64) + + m_v.ST.i64 = r->ai64[0]; + + #elif _M_SSE >= 0x200 + + GSVector4i v = GSVector4i::loadl(r); + GSVector4i::storel(&m_v.ST.i64, v); + + #else + + m_v.ST.S = r->STQ.S; + m_v.ST.T = r->STQ.T; + + #endif + + m_q = r->STQ.Q; +} + +void GSState::GIFPackedRegHandlerUV(GIFPackedReg* r) +{ + #if _M_SSE >= 0x200 + + GSVector4i v = GSVector4i::loadl(r) & GSVector4i::x00003fff(); + m_v.UV.ai32[0] = (UINT32)GSVector4i::store(v.ps32(v)); + + #else + + m_v.UV.U = r->UV.U; + m_v.UV.V = r->UV.V; + + #endif +} + +void GSState::GIFPackedRegHandlerXYZF2(GIFPackedReg* r) +{ + m_v.XYZ.X = r->XYZF2.X; + m_v.XYZ.Y = r->XYZF2.Y; + m_v.XYZ.Z = r->XYZF2.Z; + m_v.FOG.F = r->XYZF2.F; + + VertexKick(r->XYZF2.ADC); +} + +void GSState::GIFPackedRegHandlerXYZ2(GIFPackedReg* r) +{ + m_v.XYZ.X = r->XYZ2.X; + m_v.XYZ.Y = r->XYZ2.Y; + m_v.XYZ.Z = r->XYZ2.Z; + + VertexKick(r->XYZ2.ADC); +} + +template void GSState::GIFPackedRegHandlerTEX0(GIFPackedReg* r) +{ + GIFRegHandlerTEX0((GIFReg*)&r->ai64[0]); +} + +template void GSState::GIFPackedRegHandlerCLAMP(GIFPackedReg* r) +{ + GIFRegHandlerCLAMP((GIFReg*)&r->ai64[0]); +} + +void GSState::GIFPackedRegHandlerFOG(GIFPackedReg* r) +{ + m_v.FOG.F = r->FOG.F; +} + +void GSState::GIFPackedRegHandlerXYZF3(GIFPackedReg* r) +{ + GIFRegHandlerXYZF3((GIFReg*)&r->ai64[0]); +} + +void GSState::GIFPackedRegHandlerXYZ3(GIFPackedReg* r) +{ + GIFRegHandlerXYZ3((GIFReg*)&r->ai64[0]); +} + +void GSState::GIFPackedRegHandlerA_D(GIFPackedReg* r) +{ + (this->*m_fpGIFRegHandlers[(BYTE)r->A_D.ADDR])(&r->r); +} + +void GSState::GIFPackedRegHandlerA_D(GIFPackedReg* r, int size) +{ + for(int i = 0; i < size; i++) + { + (this->*m_fpGIFRegHandlers[(BYTE)r[i].A_D.ADDR])(&r[i].r); + } +} + +void GSState::GIFPackedRegHandlerNOP(GIFPackedReg* r) +{ +} + +// GIFRegHandler* + +void GSState::GIFRegHandlerNull(GIFReg* r) +{ + // ASSERT(0); +} + +void GSState::GIFRegHandlerPRIM(GIFReg* r) +{ + // ASSERT(r->PRIM.PRIM < 7); + + if(GSUtil::GetPrimClass(m_env.PRIM.PRIM) == GSUtil::GetPrimClass(r->PRIM.PRIM)) + { + if(((m_env.PRIM.i64 ^ r->PRIM.i64) & ~7) != 0) + { + Flush(); + } + } + else + { + Flush(); + } + + m_env.PRIM = (GSVector4i)r->PRIM; + m_env.PRMODE._PRIM = r->PRIM.PRIM; + + m_context = &m_env.CTXT[PRIM->CTXT]; + + UpdateVertexKick(); + + ResetPrim(); +} + +void GSState::GIFRegHandlerRGBAQ(GIFReg* r) +{ + m_v.RGBAQ = (GSVector4i)r->RGBAQ; +} + +void GSState::GIFRegHandlerST(GIFReg* r) +{ + m_v.ST = (GSVector4i)r->ST; +} + +void GSState::GIFRegHandlerUV(GIFReg* r) +{ + m_v.UV.ai32[0] = r->UV.ai32[0] & 0x3fff3fff; +} + +void GSState::GIFRegHandlerXYZF2(GIFReg* r) +{ +/* + m_v.XYZ.X = r->XYZF.X; + m_v.XYZ.Y = r->XYZF.Y; + m_v.XYZ.Z = r->XYZF.Z; + m_v.FOG.F = r->XYZF.F; +*/ + m_v.XYZ.ai32[0] = r->XYZF.ai32[0]; + m_v.XYZ.ai32[1] = r->XYZF.ai32[1] & 0x00ffffff; + m_v.FOG.ai32[1] = r->XYZF.ai32[1] & 0xff000000; + + VertexKick(false); +} + +void GSState::GIFRegHandlerXYZ2(GIFReg* r) +{ + m_v.XYZ = (GSVector4i)r->XYZ; + + VertexKick(false); +} + +template void GSState::GIFRegHandlerTEX0(GIFReg* r) +{ + // even if TEX0 did not change, a new palette may have been uploaded and will overwrite the currently queued for drawing + + bool wt = m_mem.m_clut.WriteTest(r->TEX0, m_env.TEXCLUT); + + if(wt || PRIM->CTXT == i && !(m_env.CTXT[i].TEX0 == (GSVector4i)r->TEX0).alltrue()) + { + Flush(); + } + + m_env.CTXT[i].TEX0 = (GSVector4i)r->TEX0; + + if(m_env.CTXT[i].TEX0.TW > 10) m_env.CTXT[i].TEX0.TW = 10; + if(m_env.CTXT[i].TEX0.TH > 10) m_env.CTXT[i].TEX0.TH = 10; + + m_env.CTXT[i].TEX0.CPSM &= 0xa; // 1010b + + if((m_env.CTXT[i].TEX0.TBW & 1) && (m_env.CTXT[i].TEX0.PSM == PSM_PSMT8 || m_env.CTXT[i].TEX0.PSM == PSM_PSMT4)) + { + m_env.CTXT[i].TEX0.TBW &= ~1; // GS User 2.6 + } + + if(wt) + { + m_mem.m_clut.Write(m_env.CTXT[i].TEX0, m_env.TEXCLUT); + } +} + +template void GSState::GIFRegHandlerCLAMP(GIFReg* r) +{ + if(PRIM->CTXT == i && !(m_env.CTXT[i].CLAMP == (GSVector4i)r->CLAMP).alltrue()) + { + Flush(); + } + + m_env.CTXT[i].CLAMP = (GSVector4i)r->CLAMP; +} + +void GSState::GIFRegHandlerFOG(GIFReg* r) +{ + m_v.FOG = (GSVector4i)r->FOG; +} + +void GSState::GIFRegHandlerXYZF3(GIFReg* r) +{ +/* + m_v.XYZ.X = r->XYZF.X; + m_v.XYZ.Y = r->XYZF.Y; + m_v.XYZ.Z = r->XYZF.Z; + m_v.FOG.F = r->XYZF.F; +*/ + m_v.XYZ.ai32[0] = r->XYZF.ai32[0]; + m_v.XYZ.ai32[1] = r->XYZF.ai32[1] & 0x00ffffff; + m_v.FOG.ai32[1] = r->XYZF.ai32[1] & 0xff000000; + + VertexKick(true); +} + +void GSState::GIFRegHandlerXYZ3(GIFReg* r) +{ + m_v.XYZ = (GSVector4i)r->XYZ; + + VertexKick(true); +} + +void GSState::GIFRegHandlerNOP(GIFReg* r) +{ +} + +template void GSState::GIFRegHandlerTEX1(GIFReg* r) +{ + if(PRIM->CTXT == i && !(m_env.CTXT[i].TEX1 == (GSVector4i)r->TEX1).alltrue()) + { + Flush(); + } + + m_env.CTXT[i].TEX1 = (GSVector4i)r->TEX1; +} + +template void GSState::GIFRegHandlerTEX2(GIFReg* r) +{ + // m_env.CTXT[i].TEX2 = r->TEX2; // not used + + UINT64 mask = 0xFFFFFFE003F00000ui64; // TEX2 bits + + r->i64 = (r->i64 & mask) | (m_env.CTXT[i].TEX0.i64 & ~mask); + + GIFRegHandlerTEX0(r); +} + +template void GSState::GIFRegHandlerXYOFFSET(GIFReg* r) +{ + GSVector4i o = (GSVector4i)r->XYOFFSET & GSVector4i::x0000ffff(); + + if(!(m_env.CTXT[i].XYOFFSET == o).alltrue()) + { + Flush(); + } + + m_env.CTXT[i].XYOFFSET = o; + + m_env.CTXT[i].UpdateScissor(); +} + +void GSState::GIFRegHandlerPRMODECONT(GIFReg* r) +{ + if(!(m_env.PRMODECONT == (GSVector4i)r->PRMODECONT).alltrue()) + { + Flush(); + } + + m_env.PRMODECONT.AC = r->PRMODECONT.AC; + + PRIM = m_env.PRMODECONT.AC ? &m_env.PRIM : (GIFRegPRIM*)&m_env.PRMODE; + + if(PRIM->PRIM == 7) TRACE(_T("Invalid PRMODECONT/PRIM\n")); + + m_context = &m_env.CTXT[PRIM->CTXT]; + + UpdateVertexKick(); +} + +void GSState::GIFRegHandlerPRMODE(GIFReg* r) +{ + if(!m_env.PRMODECONT.AC) + { + Flush(); + } + + UINT32 _PRIM = m_env.PRMODE._PRIM; + m_env.PRMODE = (GSVector4i)r->PRMODE; + m_env.PRMODE._PRIM = _PRIM; + + m_context = &m_env.CTXT[PRIM->CTXT]; + + UpdateVertexKick(); +} + +void GSState::GIFRegHandlerTEXCLUT(GIFReg* r) +{ + if(!(m_env.TEXCLUT == (GSVector4i)r->TEXCLUT).alltrue()) + { + Flush(); + } + + m_env.TEXCLUT = (GSVector4i)r->TEXCLUT; +} + +void GSState::GIFRegHandlerSCANMSK(GIFReg* r) +{ + if(!(m_env.SCANMSK == (GSVector4i)r->SCANMSK).alltrue()) + { + Flush(); + } + + m_env.SCANMSK = (GSVector4i)r->SCANMSK; +} + +template void GSState::GIFRegHandlerMIPTBP1(GIFReg* r) +{ + if(PRIM->CTXT == i && !(m_env.CTXT[i].MIPTBP1 == (GSVector4i)r->MIPTBP1).alltrue()) + { + Flush(); + } + + m_env.CTXT[i].MIPTBP1 = (GSVector4i)r->MIPTBP1; +} + +template void GSState::GIFRegHandlerMIPTBP2(GIFReg* r) +{ + if(PRIM->CTXT == i && !(m_env.CTXT[i].MIPTBP2 == (GSVector4i)r->MIPTBP2).alltrue()) + { + Flush(); + } + + m_env.CTXT[i].MIPTBP2 = (GSVector4i)r->MIPTBP2; +} + +void GSState::GIFRegHandlerTEXA(GIFReg* r) +{ + if(!(m_env.TEXA == (GSVector4i)r->TEXA).alltrue()) + { + Flush(); + } + + m_env.TEXA = (GSVector4i)r->TEXA; +} + +void GSState::GIFRegHandlerFOGCOL(GIFReg* r) +{ + if(!(m_env.FOGCOL == (GSVector4i)r->FOGCOL).alltrue()) + { + Flush(); + } + + m_env.FOGCOL = (GSVector4i)r->FOGCOL; +} + +void GSState::GIFRegHandlerTEXFLUSH(GIFReg* r) +{ + // TRACE(_T("TEXFLUSH\n")); + + // InvalidateTextureCache(); +} + +template void GSState::GIFRegHandlerSCISSOR(GIFReg* r) +{ + if(PRIM->CTXT == i && !(m_env.CTXT[i].SCISSOR == (GSVector4i)r->SCISSOR).alltrue()) + { + Flush(); + } + + m_env.CTXT[i].SCISSOR = (GSVector4i)r->SCISSOR; + + m_env.CTXT[i].UpdateScissor(); +} + +template void GSState::GIFRegHandlerALPHA(GIFReg* r) +{ + ASSERT(r->ALPHA.A != 3); + ASSERT(r->ALPHA.B != 3); + ASSERT(r->ALPHA.C != 3); + ASSERT(r->ALPHA.D != 3); + + if(PRIM->CTXT == i && !(m_env.CTXT[i].ALPHA == (GSVector4i)r->ALPHA).alltrue()) + { + Flush(); + } + + m_env.CTXT[i].ALPHA = (GSVector4i)r->ALPHA; + + // A/B/C/D == 3? => 2 + + m_env.CTXT[i].ALPHA.ai32[0] = ((~m_env.CTXT[i].ALPHA.ai32[0] >> 1) | 0xAA) & m_env.CTXT[i].ALPHA.ai32[0]; +} + +void GSState::GIFRegHandlerDIMX(GIFReg* r) +{ + if(!(m_env.DIMX == (GSVector4i)r->DIMX).alltrue()) + { + Flush(); + } + + m_env.DIMX = (GSVector4i)r->DIMX; +} + +void GSState::GIFRegHandlerDTHE(GIFReg* r) +{ + if(!(m_env.DTHE == (GSVector4i)r->DTHE).alltrue()) + { + Flush(); + } + + m_env.DTHE = (GSVector4i)r->DTHE; +} + +void GSState::GIFRegHandlerCOLCLAMP(GIFReg* r) +{ + if(!(m_env.COLCLAMP == (GSVector4i)r->COLCLAMP).alltrue()) + { + Flush(); + } + + m_env.COLCLAMP = (GSVector4i)r->COLCLAMP; +} + +template void GSState::GIFRegHandlerTEST(GIFReg* r) +{ + if(PRIM->CTXT == i && !(m_env.CTXT[i].TEST == (GSVector4i)r->TEST).alltrue()) + { + Flush(); + } + + m_env.CTXT[i].TEST = (GSVector4i)r->TEST; +} + +void GSState::GIFRegHandlerPABE(GIFReg* r) +{ + if(!(m_env.PABE == (GSVector4i)r->PABE).alltrue()) + { + Flush(); + } + + m_env.PABE = (GSVector4i)r->PABE; +} + +template void GSState::GIFRegHandlerFBA(GIFReg* r) +{ + if(PRIM->CTXT == i && !(m_env.CTXT[i].FBA == (GSVector4i)r->FBA).alltrue()) + { + Flush(); + } + + m_env.CTXT[i].FBA = (GSVector4i)r->FBA; +} + +template void GSState::GIFRegHandlerFRAME(GIFReg* r) +{ + if(PRIM->CTXT == i && !(m_env.CTXT[i].FRAME == (GSVector4i)r->FRAME).alltrue()) + { + Flush(); + } + + m_env.CTXT[i].FRAME = (GSVector4i)r->FRAME; +} + +template void GSState::GIFRegHandlerZBUF(GIFReg* r) +{ + if(r->ZBUF.ai32[0] == 0) + { + // during startup all regs are cleared to 0 (by the bios or something), so we mask z until this register becomes valid + + r->ZBUF.ZMSK = 1; + } + + r->ZBUF.PSM |= 0x30; + + if(PRIM->CTXT == i && !(m_env.CTXT[i].ZBUF == (GSVector4i)r->ZBUF).alltrue()) + { + Flush(); + } + + m_env.CTXT[i].ZBUF = (GSVector4i)r->ZBUF; + + if(m_env.CTXT[i].ZBUF.PSM != PSM_PSMZ32 + && m_env.CTXT[i].ZBUF.PSM != PSM_PSMZ24 + && m_env.CTXT[i].ZBUF.PSM != PSM_PSMZ16 + && m_env.CTXT[i].ZBUF.PSM != PSM_PSMZ16S) + { + m_env.CTXT[i].ZBUF.PSM = PSM_PSMZ32; + } +} + +void GSState::GIFRegHandlerBITBLTBUF(GIFReg* r) +{ + if(!(m_env.BITBLTBUF == (GSVector4i)r->BITBLTBUF).alltrue()) + { + FlushWrite(); + } + + m_env.BITBLTBUF = (GSVector4i)r->BITBLTBUF; + + if((m_env.BITBLTBUF.SBW & 1) && (m_env.BITBLTBUF.SPSM == PSM_PSMT8 || m_env.BITBLTBUF.SPSM == PSM_PSMT4)) + { + m_env.BITBLTBUF.SBW &= ~1; + } + + if((m_env.BITBLTBUF.DBW & 1) && (m_env.BITBLTBUF.DPSM == PSM_PSMT8 || m_env.BITBLTBUF.DPSM == PSM_PSMT4)) + { + m_env.BITBLTBUF.DBW &= ~1; // namcoXcapcom: 5, 11, refered to as 4, 10 in TEX0.TBW later + } +} + +void GSState::GIFRegHandlerTRXPOS(GIFReg* r) +{ + if(!(m_env.TRXPOS == (GSVector4i)r->TRXPOS).alltrue()) + { + FlushWrite(); + } + + m_env.TRXPOS = (GSVector4i)r->TRXPOS; +} + +void GSState::GIFRegHandlerTRXREG(GIFReg* r) +{ + if(!(m_env.TRXREG == (GSVector4i)r->TRXREG).alltrue() || !(m_env.TRXREG2 == (GSVector4i)r->TRXREG).alltrue()) + { + FlushWrite(); + } + + m_env.TRXREG = (GSVector4i)r->TRXREG; + m_env.TRXREG2 = (GSVector4i)r->TRXREG; +} + +void GSState::GIFRegHandlerTRXDIR(GIFReg* r) +{ + Flush(); + + m_env.TRXDIR = (GSVector4i)r->TRXDIR; + + switch(m_env.TRXDIR.XDIR) + { + case 0: // host -> local + m_x = m_env.TRXPOS.DSAX; + m_y = m_env.TRXPOS.DSAY; + m_env.TRXREG.RRW = m_x + m_env.TRXREG2.RRW; + m_env.TRXREG.RRH = m_y + m_env.TRXREG2.RRH; + break; + case 1: // local -> host + m_x = m_env.TRXPOS.SSAX; + m_y = m_env.TRXPOS.SSAY; + m_env.TRXREG.RRW = m_x + m_env.TRXREG2.RRW; + m_env.TRXREG.RRH = m_y + m_env.TRXREG2.RRH; + break; + case 2: // local -> local + Move(); + break; + case 3: + ASSERT(0); + break; + } +} + +void GSState::GIFRegHandlerHWREG(GIFReg* r) +{ + ASSERT(m_env.TRXDIR.XDIR == 0); // host => local + + Write((BYTE*)r, 8); // hunting ground +} + +void GSState::GIFRegHandlerSIGNAL(GIFReg* r) +{ + if(m_mt) return; + + SIGLBLID->SIGID = (SIGLBLID->SIGID & ~r->SIGNAL.IDMSK) | (r->SIGNAL.ID & r->SIGNAL.IDMSK); + + if(CSR->wSIGNAL) CSR->rSIGNAL = 1; + if(!IMR->SIGMSK && m_irq) m_irq(); +} + +void GSState::GIFRegHandlerFINISH(GIFReg* r) +{ + if(m_mt) return; + + if(CSR->wFINISH) CSR->rFINISH = 1; + if(!IMR->FINISHMSK && m_irq) m_irq(); +} + +void GSState::GIFRegHandlerLABEL(GIFReg* r) +{ + if(m_mt) return; + + SIGLBLID->LBLID = (SIGLBLID->LBLID & ~r->LABEL.IDMSK) | (r->LABEL.ID & r->LABEL.IDMSK); +} + +// + +void GSState::Flush() +{ + FlushWrite(); + + FlushPrim(); +} + +void GSState::FlushWrite() +{ + FlushWrite(m_buff, m_bytes); + + m_bytes = 0; +} + +void GSState::FlushWrite(BYTE* mem, int len) +{ + if(len > 0) + { +/* +CSize bs = GSLocalMemory::m_psm[m_env.BITBLTBUF.DPSM].bs; + +if((m_x & (bs.cx - 1)) || (m_env.TRXREG.RRW & (bs.cx - 1)) +|| (m_y & (bs.cy - 1)) || (m_env.TRXREG.RRH & (bs.cy - 1)) +|| m_x != m_env.TRXPOS.DSAX) +{ + printf("*** [%d]: %d %d, %d %d %d %d\n", m_env.BITBLTBUF.DPSM, m_env.TRXPOS.DSAX, m_env.TRXPOS.DSAY, m_x, m_y, m_env.TRXREG.RRW, m_env.TRXREG.RRH); +} + +if((len % ((m_env.TRXREG.RRW - m_x) * GSLocalMemory::m_psm[m_env.BITBLTBUF.DPSM].trbpp / 8)) != 0) +{ + printf("*** [%d]: %d %d\n", m_env.BITBLTBUF.DPSM, len, ((m_env.TRXREG.RRW - m_x) * GSLocalMemory::m_psm[m_env.BITBLTBUF.DPSM].trbpp / 8)); +} +*/ + int y = m_y; + + GSLocalMemory::writeImage wi = GSLocalMemory::m_psm[m_env.BITBLTBUF.DPSM].wi; + + (m_mem.*wi)(m_x, m_y, mem, len, m_env.BITBLTBUF, m_env.TRXPOS, m_env.TRXREG); + + m_perfmon.Put(GSPerfMon::Swizzle, len); + + //ASSERT(m_env.TRXREG.RRH >= m_y - y); + + CRect r; + + r.left = m_env.TRXPOS.DSAX; + r.top = y; + r.right = m_env.TRXREG.RRW; + r.bottom = min(m_x == m_env.TRXPOS.DSAX ? m_y : m_y + 1, m_env.TRXREG.RRH); + + InvalidateVideoMem(m_env.BITBLTBUF, r); +/* + static int n = 0; + CString str; + str.Format(_T("c:\\temp1\\[%04d]_%05x_%d_%d_%d_%d_%d_%d.bmp"), + n++, (int)m_env.BITBLTBUF.DBP, (int)m_env.BITBLTBUF.DBW, (int)m_env.BITBLTBUF.DPSM, + r.left, r.top, r.right, r.bottom); + m_mem.SaveBMP(str, m_env.BITBLTBUF.DBP, m_env.BITBLTBUF.DBW, m_env.BITBLTBUF.DPSM, r.Width(), r.Height()); +*/ + } +} + +// + +void GSState::Write(BYTE* mem, int len) +{ +/* + TRACE(_T("Write len=%d DBP=%05x DBW=%d DPSM=%d DSAX=%d DSAY=%d RRW=%d RRH=%d\n"), + len, (int)m_env.BITBLTBUF.DBP, (int)m_env.BITBLTBUF.DBW, (int)m_env.BITBLTBUF.DPSM, + (int)m_env.TRXPOS.DSAX, (int)m_env.TRXPOS.DSAY, + (int)m_env.TRXREG.RRW, (int)m_env.TRXREG.RRH); +*/ + if(len == 0) return; + + if(m_y >= m_env.TRXREG.RRH) return; // TODO: handle overflow during writing data too (just chop len below somewhere) + + // TODO: hmmmm + + if(PRIM->TME && (m_env.BITBLTBUF.DBP == m_context->TEX0.TBP0 || m_env.BITBLTBUF.DBP == m_context->TEX0.CBP)) + { + FlushPrim(); + } + + int bpp = GSLocalMemory::m_psm[m_env.BITBLTBUF.DPSM].trbpp; + + int pitch = (m_env.TRXREG.RRW - m_env.TRXPOS.DSAX) * bpp >> 3; + + if(pitch <= 0) {ASSERT(0); return;} + + int height = len / pitch; + + if(height > m_env.TRXREG.RRH - m_env.TRXPOS.DSAY) + { + height = m_env.TRXREG.RRH - m_env.TRXPOS.DSAY; + + len = height * pitch; + } + + if(m_bytes > 0 || height < m_env.TRXREG.RRH - m_env.TRXPOS.DSAY) + { + ASSERT(len <= m_maxbytes); // more than 4mb into a 4mb local mem doesn't make sense + + len = min(m_maxbytes, len); + + if(m_bytes + len > m_maxbytes) + { + FlushWrite(); + } + + memcpy(&m_buff[m_bytes], mem, len); + + m_bytes += len; + } + else + { + FlushWrite(mem, len); + } + + m_mem.m_clut.Invalidate(); +} + +void GSState::Read(BYTE* mem, int len) +{ + /* + TRACE(_T("Read len=%d SBP=%05x SBW=%d SPSM=%d SSAX=%d SSAY=%d RRW=%d RRH=%d\n"), + len, (int)m_env.BITBLTBUF.SBP, (int)m_env.BITBLTBUF.SBW, (int)m_env.BITBLTBUF.SPSM, + (int)m_env.TRXPOS.SSAX, (int)m_env.TRXPOS.SSAY, + (int)m_env.TRXREG.RRW, (int)m_env.TRXREG.RRH); + */ + + if(m_y >= (int)m_env.TRXREG.RRH) {ASSERT(0); return;} + + if(m_x == m_env.TRXPOS.SSAX && m_y == m_env.TRXPOS.SSAY) + { + CRect r(m_env.TRXPOS.SSAX, m_env.TRXPOS.SSAY, m_env.TRXREG.RRW, m_env.TRXREG.RRH); + + InvalidateLocalMem(m_env.BITBLTBUF, r); + } + + // TODO + + m_mem.ReadImageX(m_x, m_y, mem, len, m_env.BITBLTBUF, m_env.TRXPOS, m_env.TRXREG); +} + +void GSState::Move() +{ + // ffxii uses this to move the top/bottom of the scrolling menus offscreen and then blends them back over the text to create a shading effect + // guitar hero copies the far end of the board to do a similar blend too + + GSLocalMemory::readPixel rp = GSLocalMemory::m_psm[m_env.BITBLTBUF.SPSM].rp; + GSLocalMemory::writePixel wp = GSLocalMemory::m_psm[m_env.BITBLTBUF.DPSM].wp; + + int sx = m_env.TRXPOS.SSAX; + int dx = m_env.TRXPOS.DSAX; + int sy = m_env.TRXPOS.SSAY; + int dy = m_env.TRXPOS.DSAY; + int w = m_env.TRXREG.RRW; + int h = m_env.TRXREG.RRH; + int xinc = 1; + int yinc = 1; + + if(sx < dx) sx += w-1, dx += w-1, xinc = -1; + if(sy < dy) sy += h-1, dy += h-1, yinc = -1; + + InvalidateLocalMem(m_env.BITBLTBUF, CRect(CPoint(sx, sy), CSize(w, h))); + InvalidateVideoMem(m_env.BITBLTBUF, CRect(CPoint(dx, dy), CSize(w, h))); + + // TODO: use rowOffset + + for(int y = 0; y < h; y++, sy += yinc, dy += yinc, sx -= xinc*w, dx -= xinc*w) + for(int x = 0; x < w; x++, sx += xinc, dx += xinc) + (m_mem.*wp)(dx, dy, (m_mem.*rp)(sx, sy, m_env.BITBLTBUF.SBP, m_env.BITBLTBUF.SBW), m_env.BITBLTBUF.DBP, m_env.BITBLTBUF.DBW); +} + +void GSState::SoftReset(BYTE mask) +{ + if(mask & 1) memset(&m_path[0], 0, sizeof(GIFPath)); + if(mask & 2) memset(&m_path[1], 0, sizeof(GIFPath)); + if(mask & 4) memset(&m_path[2], 0, sizeof(GIFPath)); + + m_env.TRXDIR.XDIR = 3; //-1 ; set it to invalid value + + m_q = 1; +} + +void GSState::ReadFIFO(BYTE* mem, int size) +{ + GSPerfMonAutoTimer pmat(m_perfmon); + + Flush(); + + size *= 16; + + Read(mem, size); + + if(m_dump) + { + m_dump.ReadFIFO(size); + } +} + +template void GSState::Transfer<0>(BYTE* mem, UINT32 size); +template void GSState::Transfer<1>(BYTE* mem, UINT32 size); +template void GSState::Transfer<2>(BYTE* mem, UINT32 size); + +template void GSState::Transfer(BYTE* mem, UINT32 size) +{ + GSPerfMonAutoTimer pmat(m_perfmon); + + BYTE* start = mem; + + GIFPath& path = m_path[index]; + + while(size > 0) + { + bool eop = false; + + if(path.tag.NLOOP == 0) + { + path.SetTag(mem); + + mem += sizeof(GIFTag); + size--; + + m_q = 1.0f; + + if(index == 2 && path.tag.EOP) + { + m_path3hack = 1; + } + + if(path.tag.PRE) + { + ASSERT(path.tag.FLG != GIF_FLG_IMAGE); // kingdom hearts, ffxii, tales of abyss, berserk + + if((path.tag.FLG & 2) == 0) + { + GIFReg r; + r.i64 = path.tag.PRIM; + (this->*m_fpGIFRegHandlers[GIF_A_D_REG_PRIM])(&r); + } + } + + if(path.tag.EOP) + { + eop = true; + } + else if(path.tag.NLOOP == 0) + { + if(index == 0 && m_nloophack) + { + continue; + } + + eop = true; + } + } + + if(path.tag.NLOOP > 0) + { + switch(path.tag.FLG) + { + case GIF_FLG_PACKED: + + // first try a shortcut for a very common case + + if(path.nreg == 0 && path.tag.NREG == 1 && size >= path.tag.NLOOP && path.GetReg() == GIF_REG_A_D) + { + int n = path.tag.NLOOP; + + GIFPackedRegHandlerA_D((GIFPackedReg*)mem, n); + + mem += n * sizeof(GIFPackedReg); + size -= n; + + path.tag.NLOOP = 0; + } + else + { + while(size > 0) + { + (this->*m_fpGIFPackedRegHandlers[path.GetReg()])((GIFPackedReg*)mem); + + size--; + mem += sizeof(GIFPackedReg); + + if((++path.nreg & 0xf) == path.tag.NREG) + { + path.nreg = 0; + path.tag.NLOOP--; + + if(path.tag.NLOOP == 0) + { + break; + } + } + } + } + + break; + + case GIF_FLG_REGLIST: + + size *= 2; + + while(size > 0) + { + (this->*m_fpGIFRegHandlers[path.GetReg()])((GIFReg*)mem); + + size--; + mem += sizeof(GIFReg); + + if((++path.nreg & 0xf) == path.tag.NREG) + { + path.nreg = 0; + path.tag.NLOOP--; + + if(path.tag.NLOOP == 0) + { + break; + } + } + } + + if(size & 1) mem += sizeof(GIFReg); + + size /= 2; + + break; + + case GIF_FLG_IMAGE2: // hmmm + + ASSERT(0); + + path.tag.NLOOP = 0; + + break; + + case GIF_FLG_IMAGE: + { + int len = (int)min(size, path.tag.NLOOP); + + //ASSERT(!(len&3)); + + switch(m_env.TRXDIR.XDIR) + { + case 0: + Write(mem, len * 16); + break; + case 1: + Read(mem, len * 16); + break; + case 2: + Move(); + break; + case 3: + ASSERT(0); + break; + default: + __assume(0); + } + + mem += len * 16; + path.tag.NLOOP -= len; + size -= len; + } + + break; + + default: + __assume(0); + } + } + + if(eop && ((int)size <= 0 || index == 0)) + { + break; + } + } + + // FIXME: dq8, pcsx2 error probably + + if(index == 0) + { + if(!path.tag.EOP && path.tag.NLOOP > 0) + { + path.tag.NLOOP = 0; + + TRACE(_T("path1 hack\n")); + } + } + + if(m_dump && mem > start) + { + m_dump.Transfer(index, start, mem - start); + } +} + +template static void WriteState(BYTE*& dst, T* src, size_t len = sizeof(T)) +{ + memcpy(dst, src, len); + dst += len; +} + +template static void ReadState(T* dst, BYTE*& src, size_t len = sizeof(T)) +{ + memcpy(dst, src, len); + src += len; +} + +int GSState::Freeze(GSFreezeData* fd, bool sizeonly) +{ + if(sizeonly) + { + fd->size = m_sssize; + return 0; + } + + if(!fd->data || fd->size < m_sssize) + { + return -1; + } + + Flush(); + + BYTE* data = fd->data; + + WriteState(data, &m_version); + WriteState(data, &m_env.PRIM); + WriteState(data, &m_env.PRMODE); + WriteState(data, &m_env.PRMODECONT); + WriteState(data, &m_env.TEXCLUT); + WriteState(data, &m_env.SCANMSK); + WriteState(data, &m_env.TEXA); + WriteState(data, &m_env.FOGCOL); + WriteState(data, &m_env.DIMX); + WriteState(data, &m_env.DTHE); + WriteState(data, &m_env.COLCLAMP); + WriteState(data, &m_env.PABE); + WriteState(data, &m_env.BITBLTBUF); + WriteState(data, &m_env.TRXDIR); + WriteState(data, &m_env.TRXPOS); + WriteState(data, &m_env.TRXREG); + WriteState(data, &m_env.TRXREG2); + + for(int i = 0; i < 2; i++) + { + WriteState(data, &m_env.CTXT[i].XYOFFSET); + WriteState(data, &m_env.CTXT[i].TEX0); + WriteState(data, &m_env.CTXT[i].TEX1); + WriteState(data, &m_env.CTXT[i].TEX2); + WriteState(data, &m_env.CTXT[i].CLAMP); + WriteState(data, &m_env.CTXT[i].MIPTBP1); + WriteState(data, &m_env.CTXT[i].MIPTBP2); + WriteState(data, &m_env.CTXT[i].SCISSOR); + WriteState(data, &m_env.CTXT[i].ALPHA); + WriteState(data, &m_env.CTXT[i].TEST); + WriteState(data, &m_env.CTXT[i].FBA); + WriteState(data, &m_env.CTXT[i].FRAME); + WriteState(data, &m_env.CTXT[i].ZBUF); + } + + WriteState(data, &m_v.RGBAQ); + WriteState(data, &m_v.ST); + WriteState(data, &m_v.UV); + WriteState(data, &m_v.XYZ); + WriteState(data, &m_v.FOG); + WriteState(data, &m_x); + WriteState(data, &m_y); + WriteState(data, m_mem.m_vm8, m_mem.m_vmsize); + + for(int i = 0; i < 3; i++) + { + WriteState(data, &m_path[i].tag); + WriteState(data, &m_path[i].nreg); + } + + WriteState(data, &m_q); + + return 0; +} + +int GSState::Defrost(const GSFreezeData* fd) +{ + if(!fd || !fd->data || fd->size == 0) + { + return -1; + } + + if(fd->size < m_sssize) + { + return -1; + } + + BYTE* data = fd->data; + + int version; + + ReadState(&version, data); + + if(version > m_version) + { + return -1; + } + + Flush(); + + Reset(); + + ReadState(&m_env.PRIM, data); + ReadState(&m_env.PRMODE, data); + ReadState(&m_env.PRMODECONT, data); + ReadState(&m_env.TEXCLUT, data); + ReadState(&m_env.SCANMSK, data); + ReadState(&m_env.TEXA, data); + ReadState(&m_env.FOGCOL, data); + ReadState(&m_env.DIMX, data); + ReadState(&m_env.DTHE, data); + ReadState(&m_env.COLCLAMP, data); + ReadState(&m_env.PABE, data); + ReadState(&m_env.BITBLTBUF, data); + ReadState(&m_env.TRXDIR, data); + ReadState(&m_env.TRXPOS, data); + ReadState(&m_env.TRXREG, data); + ReadState(&m_env.TRXREG2, data); + + for(int i = 0; i < 2; i++) + { + ReadState(&m_env.CTXT[i].XYOFFSET, data); + ReadState(&m_env.CTXT[i].TEX0, data); + ReadState(&m_env.CTXT[i].TEX1, data); + ReadState(&m_env.CTXT[i].TEX2, data); + ReadState(&m_env.CTXT[i].CLAMP, data); + ReadState(&m_env.CTXT[i].MIPTBP1, data); + ReadState(&m_env.CTXT[i].MIPTBP2, data); + ReadState(&m_env.CTXT[i].SCISSOR, data); + ReadState(&m_env.CTXT[i].ALPHA, data); + ReadState(&m_env.CTXT[i].TEST, data); + ReadState(&m_env.CTXT[i].FBA, data); + ReadState(&m_env.CTXT[i].FRAME, data); + ReadState(&m_env.CTXT[i].ZBUF, data); + + m_env.CTXT[i].XYOFFSET.OFX &= 0xffff; + m_env.CTXT[i].XYOFFSET.OFY &= 0xffff; + + if(version <= 4) + { + data += sizeof(DWORD) * 7; // skip + } + } + + ReadState(&m_v.RGBAQ, data); + ReadState(&m_v.ST, data); + ReadState(&m_v.UV, data); + ReadState(&m_v.XYZ, data); + ReadState(&m_v.FOG, data); + ReadState(&m_x, data); + ReadState(&m_y, data); + ReadState(m_mem.m_vm8, data, m_mem.m_vmsize); + + for(int i = 0; i < 3; i++) + { + ReadState(&m_path[i].tag, data); + ReadState(&m_path[i].nreg, data); + + m_path[i].SetTag(&m_path[i].tag); // expand regs + } + + ReadState(&m_q, data); + + PRIM = !m_env.PRMODECONT.AC ? (GIFRegPRIM*)&m_env.PRMODE : &m_env.PRIM; + + m_context = &m_env.CTXT[PRIM->CTXT]; + + UpdateVertexKick(); + + m_env.CTXT[0].UpdateScissor(); + m_env.CTXT[1].UpdateScissor(); + +m_perfmon.SetFrame(5000); + + return 0; +} + +void GSState::SetGameCRC(DWORD crc, int options) +{ + m_crc = crc; + m_options = options; + m_game = CRC::Lookup(crc); + + if(m_nloophack_org == 2) + { + m_nloophack = m_game.nloophack; + } +} + +void GSState::SetFrameSkip(int frameskip) +{ + if(m_frameskip != frameskip) + { + m_frameskip = frameskip; + + if(frameskip) + { + m_fpGIFPackedRegHandlers[GIF_REG_PRIM] = &GSState::GIFPackedRegHandlerNOP; + m_fpGIFPackedRegHandlers[GIF_REG_RGBA] = &GSState::GIFPackedRegHandlerNOP; + m_fpGIFPackedRegHandlers[GIF_REG_STQ] = &GSState::GIFPackedRegHandlerNOP; + m_fpGIFPackedRegHandlers[GIF_REG_UV] = &GSState::GIFPackedRegHandlerNOP; + m_fpGIFPackedRegHandlers[GIF_REG_XYZF2] = &GSState::GIFPackedRegHandlerNOP; + m_fpGIFPackedRegHandlers[GIF_REG_XYZ2] = &GSState::GIFPackedRegHandlerNOP; + m_fpGIFPackedRegHandlers[GIF_REG_CLAMP_1] = &GSState::GIFPackedRegHandlerNOP; + m_fpGIFPackedRegHandlers[GIF_REG_CLAMP_2] = &GSState::GIFPackedRegHandlerNOP; + m_fpGIFPackedRegHandlers[GIF_REG_FOG] = &GSState::GIFPackedRegHandlerNOP; + m_fpGIFPackedRegHandlers[GIF_REG_XYZF3] = &GSState::GIFPackedRegHandlerNOP; + m_fpGIFPackedRegHandlers[GIF_REG_XYZ3] = &GSState::GIFPackedRegHandlerNOP; + + m_fpGIFRegHandlers[GIF_A_D_REG_PRIM] = &GSState::GIFRegHandlerNOP; + m_fpGIFRegHandlers[GIF_A_D_REG_RGBAQ] = &GSState::GIFRegHandlerNOP; + m_fpGIFRegHandlers[GIF_A_D_REG_ST] = &GSState::GIFRegHandlerNOP; + m_fpGIFRegHandlers[GIF_A_D_REG_UV] = &GSState::GIFRegHandlerNOP; + m_fpGIFRegHandlers[GIF_A_D_REG_XYZF2] = &GSState::GIFRegHandlerNOP; + m_fpGIFRegHandlers[GIF_A_D_REG_XYZ2] = &GSState::GIFRegHandlerNOP; + m_fpGIFRegHandlers[GIF_A_D_REG_XYZF3] = &GSState::GIFRegHandlerNOP; + m_fpGIFRegHandlers[GIF_A_D_REG_XYZ3] = &GSState::GIFRegHandlerNOP; + m_fpGIFRegHandlers[GIF_A_D_REG_PRMODECONT] = &GSState::GIFRegHandlerNOP; + m_fpGIFRegHandlers[GIF_A_D_REG_PRMODE] = &GSState::GIFRegHandlerNOP; + } + else + { + m_fpGIFPackedRegHandlers[GIF_REG_PRIM] = &GSState::GIFPackedRegHandlerPRIM; + m_fpGIFPackedRegHandlers[GIF_REG_RGBA] = &GSState::GIFPackedRegHandlerRGBA; + m_fpGIFPackedRegHandlers[GIF_REG_STQ] = &GSState::GIFPackedRegHandlerSTQ; + m_fpGIFPackedRegHandlers[GIF_REG_UV] = &GSState::GIFPackedRegHandlerUV; + m_fpGIFPackedRegHandlers[GIF_REG_XYZF2] = &GSState::GIFPackedRegHandlerXYZF2; + m_fpGIFPackedRegHandlers[GIF_REG_XYZ2] = &GSState::GIFPackedRegHandlerXYZ2; + m_fpGIFPackedRegHandlers[GIF_REG_CLAMP_1] = &GSState::GIFPackedRegHandlerCLAMP<0>; + m_fpGIFPackedRegHandlers[GIF_REG_CLAMP_2] = &GSState::GIFPackedRegHandlerCLAMP<1>; + m_fpGIFPackedRegHandlers[GIF_REG_FOG] = &GSState::GIFPackedRegHandlerFOG; + m_fpGIFPackedRegHandlers[GIF_REG_XYZF3] = &GSState::GIFPackedRegHandlerXYZF3; + m_fpGIFPackedRegHandlers[GIF_REG_XYZ3] = &GSState::GIFPackedRegHandlerXYZ3; + + m_fpGIFRegHandlers[GIF_A_D_REG_PRIM] = &GSState::GIFRegHandlerPRIM; + m_fpGIFRegHandlers[GIF_A_D_REG_RGBAQ] = &GSState::GIFRegHandlerRGBAQ; + m_fpGIFRegHandlers[GIF_A_D_REG_ST] = &GSState::GIFRegHandlerST; + m_fpGIFRegHandlers[GIF_A_D_REG_UV] = &GSState::GIFRegHandlerUV; + m_fpGIFRegHandlers[GIF_A_D_REG_XYZF2] = &GSState::GIFRegHandlerXYZF2; + m_fpGIFRegHandlers[GIF_A_D_REG_XYZ2] = &GSState::GIFRegHandlerXYZ2; + m_fpGIFRegHandlers[GIF_A_D_REG_XYZF3] = &GSState::GIFRegHandlerXYZF3; + m_fpGIFRegHandlers[GIF_A_D_REG_XYZ3] = &GSState::GIFRegHandlerXYZ3; + m_fpGIFRegHandlers[GIF_A_D_REG_PRMODECONT] = &GSState::GIFRegHandlerPRMODECONT; + m_fpGIFRegHandlers[GIF_A_D_REG_PRMODE] = &GSState::GIFRegHandlerPRMODE; + } + } +} + +// hacks + +struct GSFrameInfo +{ + DWORD FBP; + DWORD FPSM; + bool TME; + DWORD TBP0; + DWORD TPSM; +}; + +typedef bool (*GetSkipCount)(const GSFrameInfo& fi, int& skip); + +bool GSC_Okami(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && fi.FBP == 0x00e00 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x00000 && fi.TPSM == PSM_PSMCT32) + { + skip = 1000; + } + } + else + { + if(fi.TME && fi.FBP == 0x00e00 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x03800 && fi.TPSM == PSM_PSMT4) + { + skip = 0; + } + } + + return true; +} + +bool GSC_MetalGearSolid3(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && fi.FBP == 0x02000 && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01000) && fi.TPSM == PSM_PSMCT24) + { + skip = 1000; // 76, 79 + } + else if(fi.TME && fi.FBP == 0x02800 && fi.FPSM == PSM_PSMCT24 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01000) && fi.TPSM == PSM_PSMCT32) + { + skip = 1000; // 69 + } + } + else + { + if(!fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x01000) && fi.FPSM == PSM_PSMCT32) + { + skip = 0; + } + } + + return true; +} + +bool GSC_DBZBT2(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && /*fi.FBP == 0x00000 && fi.FPSM == PSM_PSMCT16 &&*/ fi.TBP0 == 0x02000 && fi.TPSM == PSM_PSMZ16) + { + skip = 27; + } + else if(!fi.TME && fi.FBP == 0x03000 && fi.FPSM == PSM_PSMCT16) + { + skip = 10; + } + } + + return true; +} + +bool GSC_DBZBT3(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && fi.FBP == 0x01c00 && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x00e00) && fi.TPSM == PSM_PSMT8H) + { + skip = 24; // blur + } + else if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x00e00) && fi.FPSM == PSM_PSMCT32 && fi.TPSM == PSM_PSMT8H) + { + skip = 28; // outline + } + } + + return true; +} + +bool GSC_SFEX3(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && fi.FBP == 0x00f00 && fi.FPSM == PSM_PSMCT16 && (fi.TBP0 == 0x00500 || fi.TBP0 == 0x00000) && fi.TPSM == PSM_PSMCT32) + { + skip = 4; + } + } + + return true; +} + +bool GSC_Bully(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x01180) && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01180) && fi.FBP == fi.TBP0 && fi.FPSM == PSM_PSMCT32 && fi.FPSM == fi.TPSM) + { + return false; // allowed + } + + if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x01180) && fi.FPSM == PSM_PSMCT16S && fi.TBP0 == 0x02300 && fi.TPSM == PSM_PSMZ16S) + { + skip = 6; + } + } + else + { + if(!fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x01180) && fi.FPSM == PSM_PSMCT32) + { + skip = 0; + } + } + + return true; +} + +bool GSC_BullyCC(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x01180) && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01180) && fi.FBP == fi.TBP0 && fi.FPSM == PSM_PSMCT32 && fi.FPSM == fi.TPSM) + { + return false; // allowed + } + + if(!fi.TME && fi.FBP == 0x02800 && fi.FPSM == PSM_PSMCT24) + { + skip = 9; + } + } + + return true; +} +bool GSC_SoTC(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && fi.FBP == 0x02b80 && fi.FPSM == PSM_PSMCT24 && fi.TBP0 == 0x01e80 && fi.TPSM == PSM_PSMCT24) + { + skip = 9; + } + else if(fi.TME && fi.FBP == 0x01c00 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x03800 && fi.TPSM == PSM_PSMCT32) + { + skip = 8; + } + else if(fi.TME && fi.FBP == 0x01e80 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x03880 && fi.TPSM == PSM_PSMCT32) + { + skip = 8; + } + } + + return true; +} + +bool GSC_OnePieceGrandAdventure(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && fi.FBP == 0x02d00 && fi.FPSM == PSM_PSMCT16 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x00e00) && fi.TPSM == PSM_PSMCT16) + { + skip = 3; + } + } + + return true; +} + +bool GSC_ICO(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && fi.FBP == 0x00800 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x03d00 && fi.TPSM == PSM_PSMCT32) + { + skip = 3; + } + else if(fi.TME && fi.FBP == 0x00800 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x02800 && fi.TPSM == PSM_PSMT8H) + { + skip = 1; + } + } + else + { + if(fi.TME && fi.TBP0 == 0x00800 && fi.TPSM == PSM_PSMCT32) + { + skip = 0; + } + } + + return true; +} + +bool GSC_GT4(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && (fi.FBP == 0x03440 || fi.FBP >= 0x03e00) && fi.FPSM == PSM_PSMCT32 && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x01400) && fi.TPSM == PSM_PSMT8) + { + skip = 880; + } + else if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x01400) && fi.FPSM == PSM_PSMCT24 && fi.TBP0 >= 0x03420 && fi.TPSM == PSM_PSMT8) + { + // TODO: removes gfx from where it is not supposed to (garage) + // skip = 58; + } + } + + return true; +} + +bool GSC_WildArms5(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && fi.FBP == 0x03100 && fi.FPSM == PSM_PSMZ32 && fi.TBP0 == 0x01c00 && fi.TPSM == PSM_PSMZ32) + { + skip = 100; + } + } + else + { + if(fi.TME && fi.FBP == 0x00e00 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x02a00 && fi.TPSM == PSM_PSMCT32) + { + skip = 1; + } + } + + return true; +} + +bool GSC_Manhunt2(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && fi.FBP == 0x03c20 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x01400 && fi.TPSM == PSM_PSMT8) + { + skip = 640; + } + } + + return true; +} + +bool GSC_CrashBandicootWoC(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x00a00) && (fi.TBP0 == 0x00000 || fi.TBP0 == 0x00a00) && fi.FBP == fi.TBP0 && fi.FPSM == PSM_PSMCT32 && fi.FPSM == fi.TPSM) + { + return false; // allowed + } + + if(fi.TME && fi.FBP == 0x02200 && fi.FPSM == PSM_PSMZ24 && fi.TBP0 == 0x01400 && fi.TPSM == PSM_PSMZ24) + { + skip = 41; + } + } + else + { + if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x00a00) && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x03c00 && fi.TPSM == PSM_PSMCT32) + { + skip = 0; + } + else if(!fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x00a00)) + { + skip = 0; + } + } + + return true; +} + +bool GSC_ResidentEvil4(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && fi.FBP == 0x03100 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x01c00 && fi.TPSM == PSM_PSMZ24) + { + skip = 176; + } + } + + return true; +} + +bool GSC_Spartan(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && fi.FBP == 0x02000 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x00000 && fi.TPSM == PSM_PSMCT32) + { + skip = 107; + } + } + + return true; +} + +bool GSC_AceCombat4(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && fi.FBP == 0x02a00 && fi.FPSM == PSM_PSMZ24 && fi.TBP0 == 0x01600 && fi.TPSM == PSM_PSMZ24) + { + skip = 71; // clouds (z, 16-bit) + } + else if(fi.TME && fi.FBP == 0x02900 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x00000 && fi.TPSM == PSM_PSMCT24) + { + skip = 28; // blur + } + } + + return true; +} + +bool GSC_Drakengard2(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && fi.FBP == 0x026c0 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x00a00 && fi.TPSM == PSM_PSMCT32) + { + skip = 64; + } + } + + return true; +} + +bool GSC_Tekken5(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && fi.FBP == 0x02ea0 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x00000 && fi.TPSM == PSM_PSMCT32) + { + skip = 95; + } + } + + return true; +} + +bool GSC_IkkiTousen(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && fi.FBP == 0x00a80 && fi.FPSM == PSM_PSMZ24 && fi.TBP0 == 0x01180 && fi.TPSM == PSM_PSMZ24) + { + skip = 1000; // shadow (result is broken without depth copy, also includes 16 bit) + } + else if(fi.TME && fi.FBP == 0x00700 && fi.FPSM == PSM_PSMZ24 && fi.TBP0 == 0x01180 && fi.TPSM == PSM_PSMZ24) + { + skip = 11; // blur + } + } + else if(skip > 7) + { + if(fi.TME && fi.FBP == 0x00700 && fi.FPSM == PSM_PSMCT16 && fi.TBP0 == 0x00700 && fi.TPSM == PSM_PSMCT16) + { + skip = 7; // the last steps of shadow drawing + } + } + + return true; +} + +bool GSC_GodOfWar(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && fi.FBP == 0x00000 && fi.FPSM == PSM_PSMCT16 && fi.TBP0 == 0x00000 && fi.TPSM == PSM_PSMCT16) + { + skip = 30; + } + } + else + { + } + + return true; +} + +bool GSC_GiTS(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && fi.FBP == 0x01400 && fi.FPSM == PSM_PSMCT16 && fi.TBP0 == 0x02e40 && fi.TPSM == PSM_PSMCT16) + { + skip = 1315; + } + } + else + { + } + + return true; +} + +bool GSC_Onimusha3(const GSFrameInfo& fi, int& skip) +{ + if(fi.TME /*&& (fi.FBP == 0x00000 || fi.FBP == 0x00700)*/ && (fi.TBP0 == 0x01180 || fi.TBP0 == 0x00e00 || fi.TBP0 == 0x01000 || fi.TBP0 == 0x01200) && (fi.TPSM == PSM_PSMCT32 || fi.TPSM == PSM_PSMCT24)) + { + skip = 1; + } + + return true; +} + +bool GSC_TalesOfAbyss(const GSFrameInfo& fi, int& skip) +{ + if(skip == 0) + { + if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x00e00) && fi.TBP0 == 0x01c00 && fi.TPSM == PSM_PSMT8) // copies the z buffer to the alpha channel of the fb + { + skip = 1000; + } + else if(fi.TME && (fi.FBP == 0x00000 || fi.FBP == 0x00e00) && (fi.TBP0 == 0x03560 || fi.TBP0 == 0x038e0) && fi.TPSM == PSM_PSMCT32) + { + skip = 1; + } + } + else + { + if(fi.TME && fi.TPSM != PSM_PSMT8) + { + skip = 0; + } + } + + return true; +} + +bool GSState::IsBadFrame(int& skip) +{ + GSFrameInfo fi; + + fi.FBP = m_context->FRAME.Block(); + fi.FPSM = m_context->FRAME.PSM; + fi.TME = PRIM->TME; + fi.TBP0 = m_context->TEX0.TBP0; + fi.TPSM = m_context->TEX0.PSM; + + static GetSkipCount map[CRC::TitleCount]; + static bool inited = false; + + if(!inited) + { + inited = true; + + memset(map, 0, sizeof(map)); + + map[CRC::Okami] = GSC_Okami; + map[CRC::MetalGearSolid3] = GSC_MetalGearSolid3; + map[CRC::DBZBT2] = GSC_DBZBT2; + map[CRC::DBZBT3] = GSC_DBZBT3; + map[CRC::SFEX3] = GSC_SFEX3; + map[CRC::Bully] = GSC_Bully; + map[CRC::BullyCC] = GSC_BullyCC; + map[CRC::SoTC] = GSC_SoTC; + map[CRC::OnePieceGrandAdventure] = GSC_OnePieceGrandAdventure; + map[CRC::ICO] = GSC_ICO; + map[CRC::GT4] = GSC_GT4; + map[CRC::WildArms5] = GSC_WildArms5; + map[CRC::Manhunt2] = GSC_Manhunt2; + map[CRC::CrashBandicootWoC] = GSC_CrashBandicootWoC; + map[CRC::ResidentEvil4] = GSC_ResidentEvil4; + map[CRC::Spartan] = GSC_Spartan; + map[CRC::AceCombat4] = GSC_AceCombat4; + map[CRC::Drakengard2] = GSC_Drakengard2; + map[CRC::Tekken5] = GSC_Tekken5; + map[CRC::IkkiTousen] = GSC_IkkiTousen; + map[CRC::GodOfWar] = GSC_GodOfWar; + map[CRC::GodOfWar2] = GSC_GodOfWar; + map[CRC::GiTS] = GSC_GiTS; + map[CRC::Onimusha3] = GSC_Onimusha3; + map[CRC::TalesOfAbyss] = GSC_TalesOfAbyss; + } + + // TODO: just set gsc in SetGameCRC once + + GetSkipCount gsc = map[m_game.title]; + + if(gsc && !gsc(fi, skip)) + { + return false; + } + + if(skip == 0) + { + if(fi.TME) + { + if(GSUtil::HasSharedBits(fi.FBP, fi.FPSM, fi.TBP0, fi.TPSM)) + { + // skip = 1; + } + + // depth textures (bully, mgs3s1 intro) + + if(fi.TPSM == PSM_PSMZ32 || fi.TPSM == PSM_PSMZ24 || fi.TPSM == PSM_PSMZ16 || fi.TPSM == PSM_PSMZ16S) + { + skip = 1; + } + } + } + + if(skip > 0) + { + skip--; + + return true; + } + + return false; +} diff --git a/plugins/GSdx/GSState.h b/plugins/GSdx/GSState.h index 8b5f662980..b1d805cf28 100644 --- a/plugins/GSdx/GSState.h +++ b/plugins/GSdx/GSState.h @@ -1,268 +1,268 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GS.h" -#include "GSLocalMemory.h" -#include "GSDrawingContext.h" -#include "GSDrawingEnvironment.h" -#include "GSVertex.h" -#include "GSVertexList.h" -#include "GSUtil.h" -#include "GSDirtyRect.h" -#include "GSPerfMon.h" -#include "GSVector.h" -#include "GSDevice.h" -#include "GSCrc.h" -#include "GSAlignedClass.h" -#include "GSDump.h" - -class GSState : public GSAlignedClass<16> -{ - typedef void (GSState::*GIFPackedRegHandler)(GIFPackedReg* r); - - GIFPackedRegHandler m_fpGIFPackedRegHandlers[16]; - - void GIFPackedRegHandlerNull(GIFPackedReg* r); - void GIFPackedRegHandlerPRIM(GIFPackedReg* r); - void GIFPackedRegHandlerRGBA(GIFPackedReg* r); - void GIFPackedRegHandlerSTQ(GIFPackedReg* r); - void GIFPackedRegHandlerUV(GIFPackedReg* r); - void GIFPackedRegHandlerXYZF2(GIFPackedReg* r); - void GIFPackedRegHandlerXYZ2(GIFPackedReg* r); - template void GIFPackedRegHandlerTEX0(GIFPackedReg* r); - template void GIFPackedRegHandlerCLAMP(GIFPackedReg* r); - void GIFPackedRegHandlerFOG(GIFPackedReg* r); - void GIFPackedRegHandlerXYZF3(GIFPackedReg* r); - void GIFPackedRegHandlerXYZ3(GIFPackedReg* r); - void GIFPackedRegHandlerA_D(GIFPackedReg* r); - void GIFPackedRegHandlerA_D(GIFPackedReg* r, int size); - void GIFPackedRegHandlerNOP(GIFPackedReg* r); - - typedef void (GSState::*GIFRegHandler)(GIFReg* r); - - GIFRegHandler m_fpGIFRegHandlers[256]; - - void GIFRegHandlerNull(GIFReg* r); - void GIFRegHandlerPRIM(GIFReg* r); - void GIFRegHandlerRGBAQ(GIFReg* r); - void GIFRegHandlerST(GIFReg* r); - void GIFRegHandlerUV(GIFReg* r); - void GIFRegHandlerXYZF2(GIFReg* r); - void GIFRegHandlerXYZ2(GIFReg* r); - template void GIFRegHandlerTEX0(GIFReg* r); - template void GIFRegHandlerCLAMP(GIFReg* r); - void GIFRegHandlerFOG(GIFReg* r); - void GIFRegHandlerXYZF3(GIFReg* r); - void GIFRegHandlerXYZ3(GIFReg* r); - void GIFRegHandlerNOP(GIFReg* r); - template void GIFRegHandlerTEX1(GIFReg* r); - template void GIFRegHandlerTEX2(GIFReg* r); - template void GIFRegHandlerXYOFFSET(GIFReg* r); - void GIFRegHandlerPRMODECONT(GIFReg* r); - void GIFRegHandlerPRMODE(GIFReg* r); - void GIFRegHandlerTEXCLUT(GIFReg* r); - void GIFRegHandlerSCANMSK(GIFReg* r); - template void GIFRegHandlerMIPTBP1(GIFReg* r); - template void GIFRegHandlerMIPTBP2(GIFReg* r); - void GIFRegHandlerTEXA(GIFReg* r); - void GIFRegHandlerFOGCOL(GIFReg* r); - void GIFRegHandlerTEXFLUSH(GIFReg* r); - template void GIFRegHandlerSCISSOR(GIFReg* r); - template void GIFRegHandlerALPHA(GIFReg* r); - void GIFRegHandlerDIMX(GIFReg* r); - void GIFRegHandlerDTHE(GIFReg* r); - void GIFRegHandlerCOLCLAMP(GIFReg* r); - template void GIFRegHandlerTEST(GIFReg* r); - void GIFRegHandlerPABE(GIFReg* r); - template void GIFRegHandlerFBA(GIFReg* r); - template void GIFRegHandlerFRAME(GIFReg* r); - template void GIFRegHandlerZBUF(GIFReg* r); - void GIFRegHandlerBITBLTBUF(GIFReg* r); - void GIFRegHandlerTRXPOS(GIFReg* r); - void GIFRegHandlerTRXREG(GIFReg* r); - void GIFRegHandlerTRXDIR(GIFReg* r); - void GIFRegHandlerHWREG(GIFReg* r); - void GIFRegHandlerSIGNAL(GIFReg* r); - void GIFRegHandlerFINISH(GIFReg* r); - void GIFRegHandlerLABEL(GIFReg* r); - - int m_version; - int m_sssize; - - bool m_mt; - void (*m_irq)(); - bool m_path3hack; - int m_nloophack_org; - - int m_x, m_y; - int m_bytes; - int m_maxbytes; - BYTE* m_buff; - - void FlushWrite(); - void FlushWrite(BYTE* mem, int len); - -protected: - bool IsBadFrame(int& skip); - - typedef void (GSState::*VertexKickPtr)(bool skip); - - VertexKickPtr m_vk[8][2][2]; - VertexKickPtr m_vkf; - - template void InitVertexKick() - { - m_vk[GS_POINTLIST][0][0] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_POINTLIST][0][1] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_POINTLIST][1][0] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_POINTLIST][1][1] = (VertexKickPtr)&T::VertexKick; - - m_vk[GS_LINELIST][0][0] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_LINELIST][0][1] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_LINELIST][1][0] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_LINELIST][1][1] = (VertexKickPtr)&T::VertexKick; - - m_vk[GS_LINESTRIP][0][0] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_LINESTRIP][0][1] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_LINESTRIP][1][0] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_LINESTRIP][1][1] = (VertexKickPtr)&T::VertexKick; - - m_vk[GS_TRIANGLELIST][0][0] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_TRIANGLELIST][0][1] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_TRIANGLELIST][1][0] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_TRIANGLELIST][1][1] = (VertexKickPtr)&T::VertexKick; - - m_vk[GS_TRIANGLESTRIP][0][0] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_TRIANGLESTRIP][0][1] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_TRIANGLESTRIP][1][0] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_TRIANGLESTRIP][1][1] = (VertexKickPtr)&T::VertexKick; - - m_vk[GS_TRIANGLEFAN][0][0] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_TRIANGLEFAN][0][1] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_TRIANGLEFAN][1][0] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_TRIANGLEFAN][1][1] = (VertexKickPtr)&T::VertexKick; - - m_vk[GS_SPRITE][0][0] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_SPRITE][0][1] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_SPRITE][1][0] = (VertexKickPtr)&T::VertexKick; - m_vk[GS_SPRITE][1][1] = (VertexKickPtr)&T::VertexKick; - - m_vk[GS_INVALID][0][0] = &GSState::VertexKickNull; - m_vk[GS_INVALID][0][1] = &GSState::VertexKickNull; - m_vk[GS_INVALID][1][0] = &GSState::VertexKickNull; - m_vk[GS_INVALID][1][1] = &GSState::VertexKickNull; - } - - void UpdateVertexKick() - { - m_vkf = m_vk[PRIM->PRIM][PRIM->TME][PRIM->FST]; - } - - void VertexKickNull(bool skip) - { - ASSERT(0); - } - - void VertexKick(bool skip) - { - (this->*m_vkf)(skip); - } - -public: - GIFRegPRIM* PRIM; - GSRegPMODE* PMODE; - GSRegSMODE1* SMODE1; - GSRegSMODE2* SMODE2; - GSRegDISPFB* DISPFB[2]; - GSRegDISPLAY* DISPLAY[2]; - GSRegEXTBUF* EXTBUF; - GSRegEXTDATA* EXTDATA; - GSRegEXTWRITE* EXTWRITE; - GSRegBGCOLOR* BGCOLOR; - GSRegCSR* CSR; - GSRegIMR* IMR; - GSRegBUSDIR* BUSDIR; - GSRegSIGLBLID* SIGLBLID; - - GIFPath m_path[3]; - GSLocalMemory m_mem; - GSDrawingEnvironment m_env; - GSDrawingContext* m_context; - GSVertex m_v; - float m_q; - DWORD m_vprim; - - GSPerfMon m_perfmon; - bool m_nloophack; - DWORD m_crc; - int m_options; - int m_frameskip; - CRC::Game m_game; - GSDump m_dump; - -public: - GSState(BYTE* base, bool mt, void (*irq)(), int nloophack); - virtual ~GSState(); - - void ResetHandlers(); - - CPoint GetDisplayPos(int i); - CSize GetDisplaySize(int i); - CRect GetDisplayRect(int i); - CSize GetDisplayPos(); - CSize GetDisplaySize(); - CRect GetDisplayRect(); - CPoint GetFramePos(int i); - CSize GetFrameSize(int i); - CRect GetFrameRect(int i); - CSize GetFramePos(); - CSize GetFrameSize(); - CRect GetFrameRect(); - CSize GetDeviceSize(int i); - CSize GetDeviceSize(); - bool IsEnabled(int i); - int GetFPS(); - - virtual void Reset(); - virtual void Flush(); - virtual void FlushPrim() = 0; - virtual void ResetPrim() = 0; - virtual void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r) {} - virtual void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r) {} - virtual void InvalidateTextureCache() {} - - void Move(); - void Write(BYTE* mem, int len); - void Read(BYTE* mem, int len); - - void SoftReset(BYTE mask); - void WriteCSR(UINT32 csr) {CSR->ai32[1] = csr;} - void ReadFIFO(BYTE* mem, int size); - template void Transfer(BYTE* mem, UINT32 size); - int Freeze(GSFreezeData* fd, bool sizeonly); - int Defrost(const GSFreezeData* fd); - void GetLastTag(UINT32* tag) {*tag = m_path3hack; m_path3hack = 0;} - virtual void SetGameCRC(DWORD crc, int options); - void SetFrameSkip(int frameskip); -}; - +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GS.h" +#include "GSLocalMemory.h" +#include "GSDrawingContext.h" +#include "GSDrawingEnvironment.h" +#include "GSVertex.h" +#include "GSVertexList.h" +#include "GSUtil.h" +#include "GSDirtyRect.h" +#include "GSPerfMon.h" +#include "GSVector.h" +#include "GSDevice.h" +#include "GSCrc.h" +#include "GSAlignedClass.h" +#include "GSDump.h" + +class GSState : public GSAlignedClass<16> +{ + typedef void (GSState::*GIFPackedRegHandler)(GIFPackedReg* r); + + GIFPackedRegHandler m_fpGIFPackedRegHandlers[16]; + + void GIFPackedRegHandlerNull(GIFPackedReg* r); + void GIFPackedRegHandlerPRIM(GIFPackedReg* r); + void GIFPackedRegHandlerRGBA(GIFPackedReg* r); + void GIFPackedRegHandlerSTQ(GIFPackedReg* r); + void GIFPackedRegHandlerUV(GIFPackedReg* r); + void GIFPackedRegHandlerXYZF2(GIFPackedReg* r); + void GIFPackedRegHandlerXYZ2(GIFPackedReg* r); + template void GIFPackedRegHandlerTEX0(GIFPackedReg* r); + template void GIFPackedRegHandlerCLAMP(GIFPackedReg* r); + void GIFPackedRegHandlerFOG(GIFPackedReg* r); + void GIFPackedRegHandlerXYZF3(GIFPackedReg* r); + void GIFPackedRegHandlerXYZ3(GIFPackedReg* r); + void GIFPackedRegHandlerA_D(GIFPackedReg* r); + void GIFPackedRegHandlerA_D(GIFPackedReg* r, int size); + void GIFPackedRegHandlerNOP(GIFPackedReg* r); + + typedef void (GSState::*GIFRegHandler)(GIFReg* r); + + GIFRegHandler m_fpGIFRegHandlers[256]; + + void GIFRegHandlerNull(GIFReg* r); + void GIFRegHandlerPRIM(GIFReg* r); + void GIFRegHandlerRGBAQ(GIFReg* r); + void GIFRegHandlerST(GIFReg* r); + void GIFRegHandlerUV(GIFReg* r); + void GIFRegHandlerXYZF2(GIFReg* r); + void GIFRegHandlerXYZ2(GIFReg* r); + template void GIFRegHandlerTEX0(GIFReg* r); + template void GIFRegHandlerCLAMP(GIFReg* r); + void GIFRegHandlerFOG(GIFReg* r); + void GIFRegHandlerXYZF3(GIFReg* r); + void GIFRegHandlerXYZ3(GIFReg* r); + void GIFRegHandlerNOP(GIFReg* r); + template void GIFRegHandlerTEX1(GIFReg* r); + template void GIFRegHandlerTEX2(GIFReg* r); + template void GIFRegHandlerXYOFFSET(GIFReg* r); + void GIFRegHandlerPRMODECONT(GIFReg* r); + void GIFRegHandlerPRMODE(GIFReg* r); + void GIFRegHandlerTEXCLUT(GIFReg* r); + void GIFRegHandlerSCANMSK(GIFReg* r); + template void GIFRegHandlerMIPTBP1(GIFReg* r); + template void GIFRegHandlerMIPTBP2(GIFReg* r); + void GIFRegHandlerTEXA(GIFReg* r); + void GIFRegHandlerFOGCOL(GIFReg* r); + void GIFRegHandlerTEXFLUSH(GIFReg* r); + template void GIFRegHandlerSCISSOR(GIFReg* r); + template void GIFRegHandlerALPHA(GIFReg* r); + void GIFRegHandlerDIMX(GIFReg* r); + void GIFRegHandlerDTHE(GIFReg* r); + void GIFRegHandlerCOLCLAMP(GIFReg* r); + template void GIFRegHandlerTEST(GIFReg* r); + void GIFRegHandlerPABE(GIFReg* r); + template void GIFRegHandlerFBA(GIFReg* r); + template void GIFRegHandlerFRAME(GIFReg* r); + template void GIFRegHandlerZBUF(GIFReg* r); + void GIFRegHandlerBITBLTBUF(GIFReg* r); + void GIFRegHandlerTRXPOS(GIFReg* r); + void GIFRegHandlerTRXREG(GIFReg* r); + void GIFRegHandlerTRXDIR(GIFReg* r); + void GIFRegHandlerHWREG(GIFReg* r); + void GIFRegHandlerSIGNAL(GIFReg* r); + void GIFRegHandlerFINISH(GIFReg* r); + void GIFRegHandlerLABEL(GIFReg* r); + + int m_version; + int m_sssize; + + bool m_mt; + void (*m_irq)(); + bool m_path3hack; + int m_nloophack_org; + + int m_x, m_y; + int m_bytes; + int m_maxbytes; + BYTE* m_buff; + + void FlushWrite(); + void FlushWrite(BYTE* mem, int len); + +protected: + bool IsBadFrame(int& skip); + + typedef void (GSState::*VertexKickPtr)(bool skip); + + VertexKickPtr m_vk[8][2][2]; + VertexKickPtr m_vkf; + + template void InitVertexKick() + { + m_vk[GS_POINTLIST][0][0] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_POINTLIST][0][1] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_POINTLIST][1][0] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_POINTLIST][1][1] = (VertexKickPtr)&T::VertexKick; + + m_vk[GS_LINELIST][0][0] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_LINELIST][0][1] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_LINELIST][1][0] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_LINELIST][1][1] = (VertexKickPtr)&T::VertexKick; + + m_vk[GS_LINESTRIP][0][0] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_LINESTRIP][0][1] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_LINESTRIP][1][0] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_LINESTRIP][1][1] = (VertexKickPtr)&T::VertexKick; + + m_vk[GS_TRIANGLELIST][0][0] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_TRIANGLELIST][0][1] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_TRIANGLELIST][1][0] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_TRIANGLELIST][1][1] = (VertexKickPtr)&T::VertexKick; + + m_vk[GS_TRIANGLESTRIP][0][0] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_TRIANGLESTRIP][0][1] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_TRIANGLESTRIP][1][0] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_TRIANGLESTRIP][1][1] = (VertexKickPtr)&T::VertexKick; + + m_vk[GS_TRIANGLEFAN][0][0] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_TRIANGLEFAN][0][1] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_TRIANGLEFAN][1][0] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_TRIANGLEFAN][1][1] = (VertexKickPtr)&T::VertexKick; + + m_vk[GS_SPRITE][0][0] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_SPRITE][0][1] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_SPRITE][1][0] = (VertexKickPtr)&T::VertexKick; + m_vk[GS_SPRITE][1][1] = (VertexKickPtr)&T::VertexKick; + + m_vk[GS_INVALID][0][0] = &GSState::VertexKickNull; + m_vk[GS_INVALID][0][1] = &GSState::VertexKickNull; + m_vk[GS_INVALID][1][0] = &GSState::VertexKickNull; + m_vk[GS_INVALID][1][1] = &GSState::VertexKickNull; + } + + void UpdateVertexKick() + { + m_vkf = m_vk[PRIM->PRIM][PRIM->TME][PRIM->FST]; + } + + void VertexKickNull(bool skip) + { + ASSERT(0); + } + + void VertexKick(bool skip) + { + (this->*m_vkf)(skip); + } + +public: + GIFRegPRIM* PRIM; + GSRegPMODE* PMODE; + GSRegSMODE1* SMODE1; + GSRegSMODE2* SMODE2; + GSRegDISPFB* DISPFB[2]; + GSRegDISPLAY* DISPLAY[2]; + GSRegEXTBUF* EXTBUF; + GSRegEXTDATA* EXTDATA; + GSRegEXTWRITE* EXTWRITE; + GSRegBGCOLOR* BGCOLOR; + GSRegCSR* CSR; + GSRegIMR* IMR; + GSRegBUSDIR* BUSDIR; + GSRegSIGLBLID* SIGLBLID; + + GIFPath m_path[3]; + GSLocalMemory m_mem; + GSDrawingEnvironment m_env; + GSDrawingContext* m_context; + GSVertex m_v; + float m_q; + DWORD m_vprim; + + GSPerfMon m_perfmon; + bool m_nloophack; + DWORD m_crc; + int m_options; + int m_frameskip; + CRC::Game m_game; + GSDump m_dump; + +public: + GSState(BYTE* base, bool mt, void (*irq)(), int nloophack); + virtual ~GSState(); + + void ResetHandlers(); + + CPoint GetDisplayPos(int i); + CSize GetDisplaySize(int i); + CRect GetDisplayRect(int i); + CSize GetDisplayPos(); + CSize GetDisplaySize(); + CRect GetDisplayRect(); + CPoint GetFramePos(int i); + CSize GetFrameSize(int i); + CRect GetFrameRect(int i); + CSize GetFramePos(); + CSize GetFrameSize(); + CRect GetFrameRect(); + CSize GetDeviceSize(int i); + CSize GetDeviceSize(); + bool IsEnabled(int i); + int GetFPS(); + + virtual void Reset(); + virtual void Flush(); + virtual void FlushPrim() = 0; + virtual void ResetPrim() = 0; + virtual void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r) {} + virtual void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r) {} + virtual void InvalidateTextureCache() {} + + void Move(); + void Write(BYTE* mem, int len); + void Read(BYTE* mem, int len); + + void SoftReset(BYTE mask); + void WriteCSR(UINT32 csr) {CSR->ai32[1] = csr;} + void ReadFIFO(BYTE* mem, int size); + template void Transfer(BYTE* mem, UINT32 size); + int Freeze(GSFreezeData* fd, bool sizeonly); + int Defrost(const GSFreezeData* fd); + void GetLastTag(UINT32* tag) {*tag = m_path3hack; m_path3hack = 0;} + virtual void SetGameCRC(DWORD crc, int options); + void SetFrameSkip(int frameskip); +}; + diff --git a/plugins/GSdx/GSTables.cpp b/plugins/GSdx/GSTables.cpp index ce5ef0e62f..ec0aa149e7 100644 --- a/plugins/GSdx/GSTables.cpp +++ b/plugins/GSdx/GSTables.cpp @@ -1,263 +1,263 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSTables.h" - -const BYTE blockTable32[4][8] = { - { 0, 1, 4, 5, 16, 17, 20, 21}, - { 2, 3, 6, 7, 18, 19, 22, 23}, - { 8, 9, 12, 13, 24, 25, 28, 29}, - { 10, 11, 14, 15, 26, 27, 30, 31} -}; - -const BYTE blockTable32Z[4][8] = { - { 24, 25, 28, 29, 8, 9, 12, 13}, - { 26, 27, 30, 31, 10, 11, 14, 15}, - { 16, 17, 20, 21, 0, 1, 4, 5}, - { 18, 19, 22, 23, 2, 3, 6, 7} -}; - -const BYTE blockTable16[8][4] = { - { 0, 2, 8, 10 }, - { 1, 3, 9, 11 }, - { 4, 6, 12, 14 }, - { 5, 7, 13, 15 }, - { 16, 18, 24, 26 }, - { 17, 19, 25, 27 }, - { 20, 22, 28, 30 }, - { 21, 23, 29, 31 } -}; - -const BYTE blockTable16S[8][4] = { - { 0, 2, 16, 18 }, - { 1, 3, 17, 19 }, - { 8, 10, 24, 26 }, - { 9, 11, 25, 27 }, - { 4, 6, 20, 22 }, - { 5, 7, 21, 23 }, - { 12, 14, 28, 30 }, - { 13, 15, 29, 31 } -}; - -const BYTE blockTable16Z[8][4] = { - { 24, 26, 16, 18 }, - { 25, 27, 17, 19 }, - { 28, 30, 20, 22 }, - { 29, 31, 21, 23 }, - { 8, 10, 0, 2 }, - { 9, 11, 1, 3 }, - { 12, 14, 4, 6 }, - { 13, 15, 5, 7 } -}; - -const BYTE blockTable16SZ[8][4] = { - { 24, 26, 8, 10 }, - { 25, 27, 9, 11 }, - { 16, 18, 0, 2 }, - { 17, 19, 1, 3 }, - { 28, 30, 12, 14 }, - { 29, 31, 13, 15 }, - { 20, 22, 4, 6 }, - { 21, 23, 5, 7 } -}; - -const BYTE blockTable8[4][8] = { - { 0, 1, 4, 5, 16, 17, 20, 21}, - { 2, 3, 6, 7, 18, 19, 22, 23}, - { 8, 9, 12, 13, 24, 25, 28, 29}, - { 10, 11, 14, 15, 26, 27, 30, 31} -}; - -const BYTE blockTable4[8][4] = { - { 0, 2, 8, 10 }, - { 1, 3, 9, 11 }, - { 4, 6, 12, 14 }, - { 5, 7, 13, 15 }, - { 16, 18, 24, 26 }, - { 17, 19, 25, 27 }, - { 20, 22, 28, 30 }, - { 21, 23, 29, 31 } -}; - -const BYTE columnTable32[8][8] = { - { 0, 1, 4, 5, 8, 9, 12, 13 }, - { 2, 3, 6, 7, 10, 11, 14, 15 }, - { 16, 17, 20, 21, 24, 25, 28, 29 }, - { 18, 19, 22, 23, 26, 27, 30, 31 }, - { 32, 33, 36, 37, 40, 41, 44, 45 }, - { 34, 35, 38, 39, 42, 43, 46, 47 }, - { 48, 49, 52, 53, 56, 57, 60, 61 }, - { 50, 51, 54, 55, 58, 59, 62, 63 }, -}; - -const BYTE columnTable16[8][16] = { - { 0, 2, 8, 10, 16, 18, 24, 26, - 1, 3, 9, 11, 17, 19, 25, 27 }, - { 4, 6, 12, 14, 20, 22, 28, 30, - 5, 7, 13, 15, 21, 23, 29, 31 }, - { 32, 34, 40, 42, 48, 50, 56, 58, - 33, 35, 41, 43, 49, 51, 57, 59 }, - { 36, 38, 44, 46, 52, 54, 60, 62, - 37, 39, 45, 47, 53, 55, 61, 63 }, - { 64, 66, 72, 74, 80, 82, 88, 90, - 65, 67, 73, 75, 81, 83, 89, 91 }, - { 68, 70, 76, 78, 84, 86, 92, 94, - 69, 71, 77, 79, 85, 87, 93, 95 }, - { 96, 98, 104, 106, 112, 114, 120, 122, - 97, 99, 105, 107, 113, 115, 121, 123 }, - { 100, 102, 108, 110, 116, 118, 124, 126, - 101, 103, 109, 111, 117, 119, 125, 127 }, -}; - -const BYTE columnTable8[16][16] = { - { 0, 4, 16, 20, 32, 36, 48, 52, // column 0 - 2, 6, 18, 22, 34, 38, 50, 54 }, - { 8, 12, 24, 28, 40, 44, 56, 60, - 10, 14, 26, 30, 42, 46, 58, 62 }, - { 33, 37, 49, 53, 1, 5, 17, 21, - 35, 39, 51, 55, 3, 7, 19, 23 }, - { 41, 45, 57, 61, 9, 13, 25, 29, - 43, 47, 59, 63, 11, 15, 27, 31 }, - { 96, 100, 112, 116, 64, 68, 80, 84, // column 1 - 98, 102, 114, 118, 66, 70, 82, 86 }, - { 104, 108, 120, 124, 72, 76, 88, 92, - 106, 110, 122, 126, 74, 78, 90, 94 }, - { 65, 69, 81, 85, 97, 101, 113, 117, - 67, 71, 83, 87, 99, 103, 115, 119 }, - { 73, 77, 89, 93, 105, 109, 121, 125, - 75, 79, 91, 95, 107, 111, 123, 127 }, - { 128, 132, 144, 148, 160, 164, 176, 180, // column 2 - 130, 134, 146, 150, 162, 166, 178, 182 }, - { 136, 140, 152, 156, 168, 172, 184, 188, - 138, 142, 154, 158, 170, 174, 186, 190 }, - { 161, 165, 177, 181, 129, 133, 145, 149, - 163, 167, 179, 183, 131, 135, 147, 151 }, - { 169, 173, 185, 189, 137, 141, 153, 157, - 171, 175, 187, 191, 139, 143, 155, 159 }, - { 224, 228, 240, 244, 192, 196, 208, 212, // column 3 - 226, 230, 242, 246, 194, 198, 210, 214 }, - { 232, 236, 248, 252, 200, 204, 216, 220, - 234, 238, 250, 254, 202, 206, 218, 222 }, - { 193, 197, 209, 213, 225, 229, 241, 245, - 195, 199, 211, 215, 227, 231, 243, 247 }, - { 201, 205, 217, 221, 233, 237, 249, 253, - 203, 207, 219, 223, 235, 239, 251, 255 }, -}; - -const WORD columnTable4[16][32] = { - { 0, 8, 32, 40, 64, 72, 96, 104, // column 0 - 2, 10, 34, 42, 66, 74, 98, 106, - 4, 12, 36, 44, 68, 76, 100, 108, - 6, 14, 38, 46, 70, 78, 102, 110 }, - { 16, 24, 48, 56, 80, 88, 112, 120, - 18, 26, 50, 58, 82, 90, 114, 122, - 20, 28, 52, 60, 84, 92, 116, 124, - 22, 30, 54, 62, 86, 94, 118, 126 }, - { 65, 73, 97, 105, 1, 9, 33, 41, - 67, 75, 99, 107, 3, 11, 35, 43, - 69, 77, 101, 109, 5, 13, 37, 45, - 71, 79, 103, 111, 7, 15, 39, 47 }, - { 81, 89, 113, 121, 17, 25, 49, 57, - 83, 91, 115, 123, 19, 27, 51, 59, - 85, 93, 117, 125, 21, 29, 53, 61, - 87, 95, 119, 127, 23, 31, 55, 63 }, - { 192, 200, 224, 232, 128, 136, 160, 168, // column 1 - 194, 202, 226, 234, 130, 138, 162, 170, - 196, 204, 228, 236, 132, 140, 164, 172, - 198, 206, 230, 238, 134, 142, 166, 174 }, - { 208, 216, 240, 248, 144, 152, 176, 184, - 210, 218, 242, 250, 146, 154, 178, 186, - 212, 220, 244, 252, 148, 156, 180, 188, - 214, 222, 246, 254, 150, 158, 182, 190 }, - { 129, 137, 161, 169, 193, 201, 225, 233, - 131, 139, 163, 171, 195, 203, 227, 235, - 133, 141, 165, 173, 197, 205, 229, 237, - 135, 143, 167, 175, 199, 207, 231, 239 }, - { 145, 153, 177, 185, 209, 217, 241, 249, - 147, 155, 179, 187, 211, 219, 243, 251, - 149, 157, 181, 189, 213, 221, 245, 253, - 151, 159, 183, 191, 215, 223, 247, 255 }, - { 256, 264, 288, 296, 320, 328, 352, 360, // column 2 - 258, 266, 290, 298, 322, 330, 354, 362, - 260, 268, 292, 300, 324, 332, 356, 364, - 262, 270, 294, 302, 326, 334, 358, 366 }, - { 272, 280, 304, 312, 336, 344, 368, 376, - 274, 282, 306, 314, 338, 346, 370, 378, - 276, 284, 308, 316, 340, 348, 372, 380, - 278, 286, 310, 318, 342, 350, 374, 382 }, - { 321, 329, 353, 361, 257, 265, 289, 297, - 323, 331, 355, 363, 259, 267, 291, 299, - 325, 333, 357, 365, 261, 269, 293, 301, - 327, 335, 359, 367, 263, 271, 295, 303 }, - { 337, 345, 369, 377, 273, 281, 305, 313, - 339, 347, 371, 379, 275, 283, 307, 315, - 341, 349, 373, 381, 277, 285, 309, 317, - 343, 351, 375, 383, 279, 287, 311, 319 }, - { 448, 456, 480, 488, 384, 392, 416, 424, // column 3 - 450, 458, 482, 490, 386, 394, 418, 426, - 452, 460, 484, 492, 388, 396, 420, 428, - 454, 462, 486, 494, 390, 398, 422, 430 }, - { 464, 472, 496, 504, 400, 408, 432, 440, - 466, 474, 498, 506, 402, 410, 434, 442, - 468, 476, 500, 508, 404, 412, 436, 444, - 470, 478, 502, 510, 406, 414, 438, 446 }, - { 385, 393, 417, 425, 449, 457, 481, 489, - 387, 395, 419, 427, 451, 459, 483, 491, - 389, 397, 421, 429, 453, 461, 485, 493, - 391, 399, 423, 431, 455, 463, 487, 495 }, - { 401, 409, 433, 441, 465, 473, 497, 505, - 403, 411, 435, 443, 467, 475, 499, 507, - 405, 413, 437, 445, 469, 477, 501, 509, - 407, 415, 439, 447, 471, 479, 503, 511 }, -}; - -const BYTE clutTableT32I8[128] = -{ - 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15, - 64, 65, 68, 69, 72, 73, 76, 77, 66, 67, 70, 71, 74, 75, 78, 79, - 16, 17, 20, 21, 24, 25, 28, 29, 18, 19, 22, 23, 26, 27, 30, 31, - 80, 81, 84, 85, 88, 89, 92, 93, 82, 83, 86, 87, 90, 91, 94, 95, - 32, 33, 36, 37, 40, 41, 44, 45, 34, 35, 38, 39, 42, 43, 46, 47, - 96, 97, 100, 101, 104, 105, 108, 109, 98, 99, 102, 103, 106, 107, 110, 111, - 48, 49, 52, 53, 56, 57, 60, 61, 50, 51, 54, 55, 58, 59, 62, 63, - 112, 113, 116, 117, 120, 121, 124, 125, 114, 115, 118, 119, 122, 123, 126, 127 -}; - -const BYTE clutTableT32I4[16] = -{ - 0, 1, 4, 5, 8, 9, 12, 13, - 2, 3, 6, 7, 10, 11, 14, 15 -}; - -const BYTE clutTableT16I8[32] = -{ - 0, 2, 8, 10, 16, 18, 24, 26, - 4, 6, 12, 14, 20, 22, 28, 30, - 1, 3, 9, 11, 17, 19, 25, 27, - 5, 7, 13, 15, 21, 23, 29, 31 -}; - -const BYTE clutTableT16I4[16] = -{ - 0, 2, 8, 10, 16, 18, 24, 26, - 4, 6, 12, 14, 20, 22, 28, 30 -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSTables.h" + +const BYTE blockTable32[4][8] = { + { 0, 1, 4, 5, 16, 17, 20, 21}, + { 2, 3, 6, 7, 18, 19, 22, 23}, + { 8, 9, 12, 13, 24, 25, 28, 29}, + { 10, 11, 14, 15, 26, 27, 30, 31} +}; + +const BYTE blockTable32Z[4][8] = { + { 24, 25, 28, 29, 8, 9, 12, 13}, + { 26, 27, 30, 31, 10, 11, 14, 15}, + { 16, 17, 20, 21, 0, 1, 4, 5}, + { 18, 19, 22, 23, 2, 3, 6, 7} +}; + +const BYTE blockTable16[8][4] = { + { 0, 2, 8, 10 }, + { 1, 3, 9, 11 }, + { 4, 6, 12, 14 }, + { 5, 7, 13, 15 }, + { 16, 18, 24, 26 }, + { 17, 19, 25, 27 }, + { 20, 22, 28, 30 }, + { 21, 23, 29, 31 } +}; + +const BYTE blockTable16S[8][4] = { + { 0, 2, 16, 18 }, + { 1, 3, 17, 19 }, + { 8, 10, 24, 26 }, + { 9, 11, 25, 27 }, + { 4, 6, 20, 22 }, + { 5, 7, 21, 23 }, + { 12, 14, 28, 30 }, + { 13, 15, 29, 31 } +}; + +const BYTE blockTable16Z[8][4] = { + { 24, 26, 16, 18 }, + { 25, 27, 17, 19 }, + { 28, 30, 20, 22 }, + { 29, 31, 21, 23 }, + { 8, 10, 0, 2 }, + { 9, 11, 1, 3 }, + { 12, 14, 4, 6 }, + { 13, 15, 5, 7 } +}; + +const BYTE blockTable16SZ[8][4] = { + { 24, 26, 8, 10 }, + { 25, 27, 9, 11 }, + { 16, 18, 0, 2 }, + { 17, 19, 1, 3 }, + { 28, 30, 12, 14 }, + { 29, 31, 13, 15 }, + { 20, 22, 4, 6 }, + { 21, 23, 5, 7 } +}; + +const BYTE blockTable8[4][8] = { + { 0, 1, 4, 5, 16, 17, 20, 21}, + { 2, 3, 6, 7, 18, 19, 22, 23}, + { 8, 9, 12, 13, 24, 25, 28, 29}, + { 10, 11, 14, 15, 26, 27, 30, 31} +}; + +const BYTE blockTable4[8][4] = { + { 0, 2, 8, 10 }, + { 1, 3, 9, 11 }, + { 4, 6, 12, 14 }, + { 5, 7, 13, 15 }, + { 16, 18, 24, 26 }, + { 17, 19, 25, 27 }, + { 20, 22, 28, 30 }, + { 21, 23, 29, 31 } +}; + +const BYTE columnTable32[8][8] = { + { 0, 1, 4, 5, 8, 9, 12, 13 }, + { 2, 3, 6, 7, 10, 11, 14, 15 }, + { 16, 17, 20, 21, 24, 25, 28, 29 }, + { 18, 19, 22, 23, 26, 27, 30, 31 }, + { 32, 33, 36, 37, 40, 41, 44, 45 }, + { 34, 35, 38, 39, 42, 43, 46, 47 }, + { 48, 49, 52, 53, 56, 57, 60, 61 }, + { 50, 51, 54, 55, 58, 59, 62, 63 }, +}; + +const BYTE columnTable16[8][16] = { + { 0, 2, 8, 10, 16, 18, 24, 26, + 1, 3, 9, 11, 17, 19, 25, 27 }, + { 4, 6, 12, 14, 20, 22, 28, 30, + 5, 7, 13, 15, 21, 23, 29, 31 }, + { 32, 34, 40, 42, 48, 50, 56, 58, + 33, 35, 41, 43, 49, 51, 57, 59 }, + { 36, 38, 44, 46, 52, 54, 60, 62, + 37, 39, 45, 47, 53, 55, 61, 63 }, + { 64, 66, 72, 74, 80, 82, 88, 90, + 65, 67, 73, 75, 81, 83, 89, 91 }, + { 68, 70, 76, 78, 84, 86, 92, 94, + 69, 71, 77, 79, 85, 87, 93, 95 }, + { 96, 98, 104, 106, 112, 114, 120, 122, + 97, 99, 105, 107, 113, 115, 121, 123 }, + { 100, 102, 108, 110, 116, 118, 124, 126, + 101, 103, 109, 111, 117, 119, 125, 127 }, +}; + +const BYTE columnTable8[16][16] = { + { 0, 4, 16, 20, 32, 36, 48, 52, // column 0 + 2, 6, 18, 22, 34, 38, 50, 54 }, + { 8, 12, 24, 28, 40, 44, 56, 60, + 10, 14, 26, 30, 42, 46, 58, 62 }, + { 33, 37, 49, 53, 1, 5, 17, 21, + 35, 39, 51, 55, 3, 7, 19, 23 }, + { 41, 45, 57, 61, 9, 13, 25, 29, + 43, 47, 59, 63, 11, 15, 27, 31 }, + { 96, 100, 112, 116, 64, 68, 80, 84, // column 1 + 98, 102, 114, 118, 66, 70, 82, 86 }, + { 104, 108, 120, 124, 72, 76, 88, 92, + 106, 110, 122, 126, 74, 78, 90, 94 }, + { 65, 69, 81, 85, 97, 101, 113, 117, + 67, 71, 83, 87, 99, 103, 115, 119 }, + { 73, 77, 89, 93, 105, 109, 121, 125, + 75, 79, 91, 95, 107, 111, 123, 127 }, + { 128, 132, 144, 148, 160, 164, 176, 180, // column 2 + 130, 134, 146, 150, 162, 166, 178, 182 }, + { 136, 140, 152, 156, 168, 172, 184, 188, + 138, 142, 154, 158, 170, 174, 186, 190 }, + { 161, 165, 177, 181, 129, 133, 145, 149, + 163, 167, 179, 183, 131, 135, 147, 151 }, + { 169, 173, 185, 189, 137, 141, 153, 157, + 171, 175, 187, 191, 139, 143, 155, 159 }, + { 224, 228, 240, 244, 192, 196, 208, 212, // column 3 + 226, 230, 242, 246, 194, 198, 210, 214 }, + { 232, 236, 248, 252, 200, 204, 216, 220, + 234, 238, 250, 254, 202, 206, 218, 222 }, + { 193, 197, 209, 213, 225, 229, 241, 245, + 195, 199, 211, 215, 227, 231, 243, 247 }, + { 201, 205, 217, 221, 233, 237, 249, 253, + 203, 207, 219, 223, 235, 239, 251, 255 }, +}; + +const WORD columnTable4[16][32] = { + { 0, 8, 32, 40, 64, 72, 96, 104, // column 0 + 2, 10, 34, 42, 66, 74, 98, 106, + 4, 12, 36, 44, 68, 76, 100, 108, + 6, 14, 38, 46, 70, 78, 102, 110 }, + { 16, 24, 48, 56, 80, 88, 112, 120, + 18, 26, 50, 58, 82, 90, 114, 122, + 20, 28, 52, 60, 84, 92, 116, 124, + 22, 30, 54, 62, 86, 94, 118, 126 }, + { 65, 73, 97, 105, 1, 9, 33, 41, + 67, 75, 99, 107, 3, 11, 35, 43, + 69, 77, 101, 109, 5, 13, 37, 45, + 71, 79, 103, 111, 7, 15, 39, 47 }, + { 81, 89, 113, 121, 17, 25, 49, 57, + 83, 91, 115, 123, 19, 27, 51, 59, + 85, 93, 117, 125, 21, 29, 53, 61, + 87, 95, 119, 127, 23, 31, 55, 63 }, + { 192, 200, 224, 232, 128, 136, 160, 168, // column 1 + 194, 202, 226, 234, 130, 138, 162, 170, + 196, 204, 228, 236, 132, 140, 164, 172, + 198, 206, 230, 238, 134, 142, 166, 174 }, + { 208, 216, 240, 248, 144, 152, 176, 184, + 210, 218, 242, 250, 146, 154, 178, 186, + 212, 220, 244, 252, 148, 156, 180, 188, + 214, 222, 246, 254, 150, 158, 182, 190 }, + { 129, 137, 161, 169, 193, 201, 225, 233, + 131, 139, 163, 171, 195, 203, 227, 235, + 133, 141, 165, 173, 197, 205, 229, 237, + 135, 143, 167, 175, 199, 207, 231, 239 }, + { 145, 153, 177, 185, 209, 217, 241, 249, + 147, 155, 179, 187, 211, 219, 243, 251, + 149, 157, 181, 189, 213, 221, 245, 253, + 151, 159, 183, 191, 215, 223, 247, 255 }, + { 256, 264, 288, 296, 320, 328, 352, 360, // column 2 + 258, 266, 290, 298, 322, 330, 354, 362, + 260, 268, 292, 300, 324, 332, 356, 364, + 262, 270, 294, 302, 326, 334, 358, 366 }, + { 272, 280, 304, 312, 336, 344, 368, 376, + 274, 282, 306, 314, 338, 346, 370, 378, + 276, 284, 308, 316, 340, 348, 372, 380, + 278, 286, 310, 318, 342, 350, 374, 382 }, + { 321, 329, 353, 361, 257, 265, 289, 297, + 323, 331, 355, 363, 259, 267, 291, 299, + 325, 333, 357, 365, 261, 269, 293, 301, + 327, 335, 359, 367, 263, 271, 295, 303 }, + { 337, 345, 369, 377, 273, 281, 305, 313, + 339, 347, 371, 379, 275, 283, 307, 315, + 341, 349, 373, 381, 277, 285, 309, 317, + 343, 351, 375, 383, 279, 287, 311, 319 }, + { 448, 456, 480, 488, 384, 392, 416, 424, // column 3 + 450, 458, 482, 490, 386, 394, 418, 426, + 452, 460, 484, 492, 388, 396, 420, 428, + 454, 462, 486, 494, 390, 398, 422, 430 }, + { 464, 472, 496, 504, 400, 408, 432, 440, + 466, 474, 498, 506, 402, 410, 434, 442, + 468, 476, 500, 508, 404, 412, 436, 444, + 470, 478, 502, 510, 406, 414, 438, 446 }, + { 385, 393, 417, 425, 449, 457, 481, 489, + 387, 395, 419, 427, 451, 459, 483, 491, + 389, 397, 421, 429, 453, 461, 485, 493, + 391, 399, 423, 431, 455, 463, 487, 495 }, + { 401, 409, 433, 441, 465, 473, 497, 505, + 403, 411, 435, 443, 467, 475, 499, 507, + 405, 413, 437, 445, 469, 477, 501, 509, + 407, 415, 439, 447, 471, 479, 503, 511 }, +}; + +const BYTE clutTableT32I8[128] = +{ + 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15, + 64, 65, 68, 69, 72, 73, 76, 77, 66, 67, 70, 71, 74, 75, 78, 79, + 16, 17, 20, 21, 24, 25, 28, 29, 18, 19, 22, 23, 26, 27, 30, 31, + 80, 81, 84, 85, 88, 89, 92, 93, 82, 83, 86, 87, 90, 91, 94, 95, + 32, 33, 36, 37, 40, 41, 44, 45, 34, 35, 38, 39, 42, 43, 46, 47, + 96, 97, 100, 101, 104, 105, 108, 109, 98, 99, 102, 103, 106, 107, 110, 111, + 48, 49, 52, 53, 56, 57, 60, 61, 50, 51, 54, 55, 58, 59, 62, 63, + 112, 113, 116, 117, 120, 121, 124, 125, 114, 115, 118, 119, 122, 123, 126, 127 +}; + +const BYTE clutTableT32I4[16] = +{ + 0, 1, 4, 5, 8, 9, 12, 13, + 2, 3, 6, 7, 10, 11, 14, 15 +}; + +const BYTE clutTableT16I8[32] = +{ + 0, 2, 8, 10, 16, 18, 24, 26, + 4, 6, 12, 14, 20, 22, 28, 30, + 1, 3, 9, 11, 17, 19, 25, 27, + 5, 7, 13, 15, 21, 23, 29, 31 +}; + +const BYTE clutTableT16I4[16] = +{ + 0, 2, 8, 10, 16, 18, 24, 26, + 4, 6, 12, 14, 20, 22, 28, 30 +}; diff --git a/plugins/GSdx/GSTables.h b/plugins/GSdx/GSTables.h index 90808e3e91..1ed40beea8 100644 --- a/plugins/GSdx/GSTables.h +++ b/plugins/GSdx/GSTables.h @@ -1,39 +1,39 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -extern const BYTE blockTable32[4][8]; -extern const BYTE blockTable32Z[4][8]; -extern const BYTE blockTable16[8][4]; -extern const BYTE blockTable16S[8][4]; -extern const BYTE blockTable16Z[8][4]; -extern const BYTE blockTable16SZ[8][4]; -extern const BYTE blockTable8[4][8]; -extern const BYTE blockTable4[8][4]; -extern const BYTE columnTable32[8][8]; -extern const BYTE columnTable16[8][16]; -extern const BYTE columnTable8[16][16]; -extern const WORD columnTable4[16][32]; -extern const BYTE clutTableT32I8[128]; -extern const BYTE clutTableT32I4[16]; -extern const BYTE clutTableT16I8[32]; -extern const BYTE clutTableT16I4[16]; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +extern const BYTE blockTable32[4][8]; +extern const BYTE blockTable32Z[4][8]; +extern const BYTE blockTable16[8][4]; +extern const BYTE blockTable16S[8][4]; +extern const BYTE blockTable16Z[8][4]; +extern const BYTE blockTable16SZ[8][4]; +extern const BYTE blockTable8[4][8]; +extern const BYTE blockTable4[8][4]; +extern const BYTE columnTable32[8][8]; +extern const BYTE columnTable16[8][16]; +extern const BYTE columnTable8[16][16]; +extern const WORD columnTable4[16][32]; +extern const BYTE clutTableT32I8[128]; +extern const BYTE clutTableT32I4[16]; +extern const BYTE clutTableT16I8[32]; +extern const BYTE clutTableT16I4[16]; diff --git a/plugins/GSdx/GSTexture.cpp b/plugins/GSdx/GSTexture.cpp index f87836f610..ebdbadedfa 100644 --- a/plugins/GSdx/GSTexture.cpp +++ b/plugins/GSdx/GSTexture.cpp @@ -1,23 +1,23 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSTexture.h" +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSTexture.h" diff --git a/plugins/GSdx/GSTexture.h b/plugins/GSdx/GSTexture.h index 46747022b1..fbf204ada8 100644 --- a/plugins/GSdx/GSTexture.h +++ b/plugins/GSdx/GSTexture.h @@ -1,48 +1,48 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSVector.h" - -class GSTexture -{ -public: - GSVector2 m_scale; - -public: - GSTexture() : m_scale(1, 1) {} - virtual ~GSTexture() {} - - enum {None, RenderTarget, DepthStencil, Texture, Offscreen}; - - virtual operator bool() = 0; - virtual int GetType() const = 0; - virtual int GetWidth() const = 0; - virtual int GetHeight() const = 0; - virtual int GetFormat() const = 0; - virtual bool Update(const CRect& r, const void* data, int pitch) = 0; - virtual bool Map(BYTE** bits, int& pitch, const RECT* r = NULL) = 0; - virtual void Unmap() = 0; - virtual bool Save(CString fn, bool dds = false) = 0; - - CSize GetSize() {return CSize(GetWidth(), GetHeight());} -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSVector.h" + +class GSTexture +{ +public: + GSVector2 m_scale; + +public: + GSTexture() : m_scale(1, 1) {} + virtual ~GSTexture() {} + + enum {None, RenderTarget, DepthStencil, Texture, Offscreen}; + + virtual operator bool() = 0; + virtual int GetType() const = 0; + virtual int GetWidth() const = 0; + virtual int GetHeight() const = 0; + virtual int GetFormat() const = 0; + virtual bool Update(const CRect& r, const void* data, int pitch) = 0; + virtual bool Map(BYTE** bits, int& pitch, const RECT* r = NULL) = 0; + virtual void Unmap() = 0; + virtual bool Save(CString fn, bool dds = false) = 0; + + CSize GetSize() {return CSize(GetWidth(), GetHeight());} +}; diff --git a/plugins/GSdx/GSTexture10.cpp b/plugins/GSdx/GSTexture10.cpp index de5daf89fe..615e8c25bc 100644 --- a/plugins/GSdx/GSTexture10.cpp +++ b/plugins/GSdx/GSTexture10.cpp @@ -1,210 +1,210 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GSTexture10.h" - -GSTexture10::GSTexture10() -{ - memset(&m_desc, 0, sizeof(m_desc)); -} - -GSTexture10::GSTexture10(ID3D10Texture2D* texture) - : m_texture(texture) -{ - ASSERT(m_texture); - - m_texture->GetDevice(&m_dev); - m_texture->GetDesc(&m_desc); -} - -GSTexture10::~GSTexture10() -{ -} - -GSTexture10::operator bool() -{ - return !!m_texture; -} - -int GSTexture10::GetType() const -{ - if(m_desc.BindFlags & D3D10_BIND_RENDER_TARGET) return GSTexture::RenderTarget; - if(m_desc.BindFlags & D3D10_BIND_DEPTH_STENCIL) return GSTexture::DepthStencil; - if(m_desc.BindFlags & D3D10_BIND_SHADER_RESOURCE) return GSTexture::Texture; - if(m_desc.Usage == D3D10_USAGE_STAGING) return GSTexture::Offscreen; - return GSTexture::None; -} - -int GSTexture10::GetWidth() const -{ - return m_desc.Width; -} - -int GSTexture10::GetHeight() const -{ - return m_desc.Height; -} - -int GSTexture10::GetFormat() const -{ - return m_desc.Format; -} - -bool GSTexture10::Update(const CRect& r, const void* data, int pitch) -{ - if(m_dev && m_texture) - { - D3D10_BOX box = {r.left, r.top, 0, r.right, r.bottom, 1}; - - m_dev->UpdateSubresource(m_texture, 0, &box, data, pitch, 0); - - return true; - } - - return false; -} - -bool GSTexture10::Map(BYTE** bits, int& pitch, const RECT* r) -{ - if(m_texture) - { - D3D10_MAPPED_TEXTURE2D map; - - if(SUCCEEDED(m_texture->Map(0, D3D10_MAP_READ_WRITE, 0, &map))) - { - *bits = (BYTE*)map.pData; - pitch = (int)map.RowPitch; - - return true; - } - } - - return false; -} - -void GSTexture10::Unmap() -{ - if(m_texture) - { - m_texture->Unmap(0); - } -} - -bool GSTexture10::Save(CString fn, bool dds) -{ - CComPtr res; - - if(m_desc.BindFlags & D3D10_BIND_DEPTH_STENCIL) - { - HRESULT hr; - - D3D10_TEXTURE2D_DESC desc; - - memset(&desc, 0, sizeof(desc)); - - m_texture->GetDesc(&desc); - - desc.Usage = D3D10_USAGE_STAGING; - desc.BindFlags = 0; - desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ; - - CComPtr src, dst; - - hr = m_dev->CreateTexture2D(&desc, NULL, &src); - - m_dev->CopyResource(src, m_texture); - - desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; - - hr = m_dev->CreateTexture2D(&desc, NULL, &dst); - - D3D10_MAPPED_TEXTURE2D sm, dm; - - hr = src->Map(0, D3D10_MAP_READ, 0, &sm); - hr = dst->Map(0, D3D10_MAP_WRITE, 0, &dm); - - BYTE* s = (BYTE*)sm.pData; - BYTE* d = (BYTE*)dm.pData; - - for(UINT y = 0; y < desc.Height; y++, s += sm.RowPitch, d += dm.RowPitch) - { - for(UINT x = 0; x < desc.Width; x++) - { - ((UINT*)d)[x] = (UINT)(((float*)s)[x*2] * UINT_MAX); - } - } - - src->Unmap(0); - dst->Unmap(0); - - res = dst; - } - else - { - res = m_texture; - } - - return SUCCEEDED(D3DX10SaveTextureToFile(res, dds ? D3DX10_IFF_DDS : D3DX10_IFF_BMP, fn)); -} - -ID3D10Texture2D* GSTexture10::operator->() -{ - return m_texture; -} - -GSTexture10::operator ID3D10Texture2D*() -{ - return m_texture; -} - -GSTexture10::operator ID3D10ShaderResourceView*() -{ - if(!m_srv && m_dev && m_texture) - { - m_dev->CreateShaderResourceView(m_texture, NULL, &m_srv); - } - - return m_srv; -} - -GSTexture10::operator ID3D10RenderTargetView*() -{ - ASSERT(m_dev); - - if(!m_rtv && m_dev && m_texture) - { - m_dev->CreateRenderTargetView(m_texture, NULL, &m_rtv); - } - - return m_rtv; -} - -GSTexture10::operator ID3D10DepthStencilView*() -{ - if(!m_dsv && m_dev && m_texture) - { - m_dev->CreateDepthStencilView(m_texture, NULL, &m_dsv); - } - - return m_dsv; -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSTexture10.h" + +GSTexture10::GSTexture10() +{ + memset(&m_desc, 0, sizeof(m_desc)); +} + +GSTexture10::GSTexture10(ID3D10Texture2D* texture) + : m_texture(texture) +{ + ASSERT(m_texture); + + m_texture->GetDevice(&m_dev); + m_texture->GetDesc(&m_desc); +} + +GSTexture10::~GSTexture10() +{ +} + +GSTexture10::operator bool() +{ + return !!m_texture; +} + +int GSTexture10::GetType() const +{ + if(m_desc.BindFlags & D3D10_BIND_RENDER_TARGET) return GSTexture::RenderTarget; + if(m_desc.BindFlags & D3D10_BIND_DEPTH_STENCIL) return GSTexture::DepthStencil; + if(m_desc.BindFlags & D3D10_BIND_SHADER_RESOURCE) return GSTexture::Texture; + if(m_desc.Usage == D3D10_USAGE_STAGING) return GSTexture::Offscreen; + return GSTexture::None; +} + +int GSTexture10::GetWidth() const +{ + return m_desc.Width; +} + +int GSTexture10::GetHeight() const +{ + return m_desc.Height; +} + +int GSTexture10::GetFormat() const +{ + return m_desc.Format; +} + +bool GSTexture10::Update(const CRect& r, const void* data, int pitch) +{ + if(m_dev && m_texture) + { + D3D10_BOX box = {r.left, r.top, 0, r.right, r.bottom, 1}; + + m_dev->UpdateSubresource(m_texture, 0, &box, data, pitch, 0); + + return true; + } + + return false; +} + +bool GSTexture10::Map(BYTE** bits, int& pitch, const RECT* r) +{ + if(m_texture) + { + D3D10_MAPPED_TEXTURE2D map; + + if(SUCCEEDED(m_texture->Map(0, D3D10_MAP_READ_WRITE, 0, &map))) + { + *bits = (BYTE*)map.pData; + pitch = (int)map.RowPitch; + + return true; + } + } + + return false; +} + +void GSTexture10::Unmap() +{ + if(m_texture) + { + m_texture->Unmap(0); + } +} + +bool GSTexture10::Save(CString fn, bool dds) +{ + CComPtr res; + + if(m_desc.BindFlags & D3D10_BIND_DEPTH_STENCIL) + { + HRESULT hr; + + D3D10_TEXTURE2D_DESC desc; + + memset(&desc, 0, sizeof(desc)); + + m_texture->GetDesc(&desc); + + desc.Usage = D3D10_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ; + + CComPtr src, dst; + + hr = m_dev->CreateTexture2D(&desc, NULL, &src); + + m_dev->CopyResource(src, m_texture); + + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; + + hr = m_dev->CreateTexture2D(&desc, NULL, &dst); + + D3D10_MAPPED_TEXTURE2D sm, dm; + + hr = src->Map(0, D3D10_MAP_READ, 0, &sm); + hr = dst->Map(0, D3D10_MAP_WRITE, 0, &dm); + + BYTE* s = (BYTE*)sm.pData; + BYTE* d = (BYTE*)dm.pData; + + for(UINT y = 0; y < desc.Height; y++, s += sm.RowPitch, d += dm.RowPitch) + { + for(UINT x = 0; x < desc.Width; x++) + { + ((UINT*)d)[x] = (UINT)(((float*)s)[x*2] * UINT_MAX); + } + } + + src->Unmap(0); + dst->Unmap(0); + + res = dst; + } + else + { + res = m_texture; + } + + return SUCCEEDED(D3DX10SaveTextureToFile(res, dds ? D3DX10_IFF_DDS : D3DX10_IFF_BMP, fn)); +} + +ID3D10Texture2D* GSTexture10::operator->() +{ + return m_texture; +} + +GSTexture10::operator ID3D10Texture2D*() +{ + return m_texture; +} + +GSTexture10::operator ID3D10ShaderResourceView*() +{ + if(!m_srv && m_dev && m_texture) + { + m_dev->CreateShaderResourceView(m_texture, NULL, &m_srv); + } + + return m_srv; +} + +GSTexture10::operator ID3D10RenderTargetView*() +{ + ASSERT(m_dev); + + if(!m_rtv && m_dev && m_texture) + { + m_dev->CreateRenderTargetView(m_texture, NULL, &m_rtv); + } + + return m_rtv; +} + +GSTexture10::operator ID3D10DepthStencilView*() +{ + if(!m_dsv && m_dev && m_texture) + { + m_dev->CreateDepthStencilView(m_texture, NULL, &m_dsv); + } + + return m_dsv; +} diff --git a/plugins/GSdx/GSTexture10.h b/plugins/GSdx/GSTexture10.h index b8c6c78279..9c1eb30964 100644 --- a/plugins/GSdx/GSTexture10.h +++ b/plugins/GSdx/GSTexture10.h @@ -1,57 +1,57 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSTexture.h" - -class GSTexture10 : public GSTexture -{ - CComPtr m_dev; - CComPtr m_texture; - D3D10_TEXTURE2D_DESC m_desc; - CComPtr m_srv; - CComPtr m_rtv; - CComPtr m_dsv; - -public: - GSTexture10(); - explicit GSTexture10(ID3D10Texture2D* texture); - virtual ~GSTexture10(); - - operator bool(); - - int GetType() const; - int GetWidth() const; - int GetHeight() const; - int GetFormat() const; - bool Update(const CRect& r, const void* data, int pitch); - bool Map(BYTE** bits, int& pitch, const RECT* r = NULL); - void Unmap(); - bool Save(CString fn, bool dds = false); - - ID3D10Texture2D* operator->(); // TODO: remove direct access - - operator ID3D10Texture2D*(); - operator ID3D10ShaderResourceView*(); - operator ID3D10RenderTargetView*(); - operator ID3D10DepthStencilView*(); -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSTexture.h" + +class GSTexture10 : public GSTexture +{ + CComPtr m_dev; + CComPtr m_texture; + D3D10_TEXTURE2D_DESC m_desc; + CComPtr m_srv; + CComPtr m_rtv; + CComPtr m_dsv; + +public: + GSTexture10(); + explicit GSTexture10(ID3D10Texture2D* texture); + virtual ~GSTexture10(); + + operator bool(); + + int GetType() const; + int GetWidth() const; + int GetHeight() const; + int GetFormat() const; + bool Update(const CRect& r, const void* data, int pitch); + bool Map(BYTE** bits, int& pitch, const RECT* r = NULL); + void Unmap(); + bool Save(CString fn, bool dds = false); + + ID3D10Texture2D* operator->(); // TODO: remove direct access + + operator ID3D10Texture2D*(); + operator ID3D10ShaderResourceView*(); + operator ID3D10RenderTargetView*(); + operator ID3D10DepthStencilView*(); +}; diff --git a/plugins/GSdx/GSTexture7.cpp b/plugins/GSdx/GSTexture7.cpp index dd3426494c..e69406e928 100644 --- a/plugins/GSdx/GSTexture7.cpp +++ b/plugins/GSdx/GSTexture7.cpp @@ -1,184 +1,184 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GSTexture7.h" - -GSTexture7::GSTexture7() - : m_type(GSTexture::None) -{ - memset(&m_desc, 0, sizeof(m_desc)); -} - -GSTexture7::GSTexture7(int type, IDirectDrawSurface7* system) - : m_type(type) - , m_system(system) -{ - memset(&m_desc, 0, sizeof(m_desc)); - - m_desc.dwSize = sizeof(m_desc); - - system->GetSurfaceDesc(&m_desc); -} - -GSTexture7::GSTexture7(int type, IDirectDrawSurface7* system, IDirectDrawSurface7* video) - : m_type(type) - , m_system(system) - , m_video(video) -{ - memset(&m_desc, 0, sizeof(m_desc)); - - m_desc.dwSize = sizeof(m_desc); - - video->GetSurfaceDesc(&m_desc); -} - -GSTexture7::~GSTexture7() -{ -} - -GSTexture7::operator bool() -{ - return !!m_system; -} - -int GSTexture7::GetType() const -{ - return m_type; -} - -int GSTexture7::GetWidth() const -{ - return m_desc.dwWidth; -} - -int GSTexture7::GetHeight() const -{ - return m_desc.dwHeight; -} - -int GSTexture7::GetFormat() const -{ - return (int)m_desc.ddpfPixelFormat.dwFourCC; -} - -bool GSTexture7::Update(const CRect& r, const void* data, int pitch) -{ - HRESULT hr; - - CRect r2 = r; - - DDSURFACEDESC2 desc; - - memset(&desc, 0, sizeof(desc)); - - desc.dwSize = sizeof(desc); - - if(SUCCEEDED(hr = m_system->Lock(&r2, &desc, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL))) - { - BYTE* src = (BYTE*)data; - BYTE* dst = (BYTE*)desc.lpSurface; - - int bytes = min(pitch, desc.lPitch); - - for(int i = 0, j = r.Height(); i < j; i++, src += pitch, dst += desc.lPitch) - { - // memcpy(dst, src, bytes); - - // HACK!!! - - GSVector4i* s = (GSVector4i*)src; - GSVector4i* d = (GSVector4i*)dst; - - int w = bytes >> 4; - - for(int x = 0; x < w; x++) - { - GSVector4i c = s[x]; - - c = (c & 0xff00ff00) | ((c & 0x00ff0000) >> 16) | ((c & 0x000000ff) << 16); - - d[x] = c; - } - } - - hr = m_system->Unlock(&r2); - - if(m_video) - { - hr = m_video->Blt(&r2, m_system, &r2, DDBLT_WAIT, NULL); - } - - return true; - } - - return false; -} - -bool GSTexture7::Map(BYTE** bits, int& pitch, const RECT* r) -{ - HRESULT hr; - - CRect r2 = r; - - DDSURFACEDESC2 desc; - - if(SUCCEEDED(hr = m_system->Lock(&r2, &desc, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL))) - { - *bits = (BYTE*)desc.lpSurface; - pitch = (int)desc.lPitch; - - m_lr = r; - - return true; - } - - return false; -} - -void GSTexture7::Unmap() -{ - HRESULT hr; - - hr = m_system->Unlock(NULL); - - if(m_video) - { - hr = m_video->Blt(&m_lr, m_system, &m_lr, DDBLT_WAIT, NULL); - } -} - -bool GSTexture7::Save(CString fn, bool dds) -{ - // TODO - - return false; -} - -IDirectDrawSurface7* GSTexture7::operator->() -{ - return m_video ? m_video : m_system; -} - -GSTexture7::operator IDirectDrawSurface7*() -{ - return m_video ? m_video : m_system; -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSTexture7.h" + +GSTexture7::GSTexture7() + : m_type(GSTexture::None) +{ + memset(&m_desc, 0, sizeof(m_desc)); +} + +GSTexture7::GSTexture7(int type, IDirectDrawSurface7* system) + : m_type(type) + , m_system(system) +{ + memset(&m_desc, 0, sizeof(m_desc)); + + m_desc.dwSize = sizeof(m_desc); + + system->GetSurfaceDesc(&m_desc); +} + +GSTexture7::GSTexture7(int type, IDirectDrawSurface7* system, IDirectDrawSurface7* video) + : m_type(type) + , m_system(system) + , m_video(video) +{ + memset(&m_desc, 0, sizeof(m_desc)); + + m_desc.dwSize = sizeof(m_desc); + + video->GetSurfaceDesc(&m_desc); +} + +GSTexture7::~GSTexture7() +{ +} + +GSTexture7::operator bool() +{ + return !!m_system; +} + +int GSTexture7::GetType() const +{ + return m_type; +} + +int GSTexture7::GetWidth() const +{ + return m_desc.dwWidth; +} + +int GSTexture7::GetHeight() const +{ + return m_desc.dwHeight; +} + +int GSTexture7::GetFormat() const +{ + return (int)m_desc.ddpfPixelFormat.dwFourCC; +} + +bool GSTexture7::Update(const CRect& r, const void* data, int pitch) +{ + HRESULT hr; + + CRect r2 = r; + + DDSURFACEDESC2 desc; + + memset(&desc, 0, sizeof(desc)); + + desc.dwSize = sizeof(desc); + + if(SUCCEEDED(hr = m_system->Lock(&r2, &desc, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL))) + { + BYTE* src = (BYTE*)data; + BYTE* dst = (BYTE*)desc.lpSurface; + + int bytes = min(pitch, desc.lPitch); + + for(int i = 0, j = r.Height(); i < j; i++, src += pitch, dst += desc.lPitch) + { + // memcpy(dst, src, bytes); + + // HACK!!! + + GSVector4i* s = (GSVector4i*)src; + GSVector4i* d = (GSVector4i*)dst; + + int w = bytes >> 4; + + for(int x = 0; x < w; x++) + { + GSVector4i c = s[x]; + + c = (c & 0xff00ff00) | ((c & 0x00ff0000) >> 16) | ((c & 0x000000ff) << 16); + + d[x] = c; + } + } + + hr = m_system->Unlock(&r2); + + if(m_video) + { + hr = m_video->Blt(&r2, m_system, &r2, DDBLT_WAIT, NULL); + } + + return true; + } + + return false; +} + +bool GSTexture7::Map(BYTE** bits, int& pitch, const RECT* r) +{ + HRESULT hr; + + CRect r2 = r; + + DDSURFACEDESC2 desc; + + if(SUCCEEDED(hr = m_system->Lock(&r2, &desc, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL))) + { + *bits = (BYTE*)desc.lpSurface; + pitch = (int)desc.lPitch; + + m_lr = r; + + return true; + } + + return false; +} + +void GSTexture7::Unmap() +{ + HRESULT hr; + + hr = m_system->Unlock(NULL); + + if(m_video) + { + hr = m_video->Blt(&m_lr, m_system, &m_lr, DDBLT_WAIT, NULL); + } +} + +bool GSTexture7::Save(CString fn, bool dds) +{ + // TODO + + return false; +} + +IDirectDrawSurface7* GSTexture7::operator->() +{ + return m_video ? m_video : m_system; +} + +GSTexture7::operator IDirectDrawSurface7*() +{ + return m_video ? m_video : m_system; +} diff --git a/plugins/GSdx/GSTexture7.h b/plugins/GSdx/GSTexture7.h index 2c326dc028..62eef7ea28 100644 --- a/plugins/GSdx/GSTexture7.h +++ b/plugins/GSdx/GSTexture7.h @@ -1,55 +1,55 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSTexture.h" -#include - -class GSTexture7 : public GSTexture -{ - int m_type; - CComPtr m_system; - CComPtr m_video; - DDSURFACEDESC2 m_desc; - CRect m_lr; - -public: - GSTexture7(); - explicit GSTexture7(int type, IDirectDrawSurface7* system); - GSTexture7(int type, IDirectDrawSurface7* system, IDirectDrawSurface7* video); - virtual ~GSTexture7(); - - operator bool(); - - int GetType() const; - int GetWidth() const; - int GetHeight() const; - int GetFormat() const; - bool Update(const CRect& r, const void* data, int pitch); - bool Map(BYTE** bits, int& pitch, const RECT* r = NULL); - void Unmap(); - bool Save(CString fn, bool dds = false); - - IDirectDrawSurface7* operator->(); // TODO: remove direct access - - operator IDirectDrawSurface7*(); -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSTexture.h" +#include + +class GSTexture7 : public GSTexture +{ + int m_type; + CComPtr m_system; + CComPtr m_video; + DDSURFACEDESC2 m_desc; + CRect m_lr; + +public: + GSTexture7(); + explicit GSTexture7(int type, IDirectDrawSurface7* system); + GSTexture7(int type, IDirectDrawSurface7* system, IDirectDrawSurface7* video); + virtual ~GSTexture7(); + + operator bool(); + + int GetType() const; + int GetWidth() const; + int GetHeight() const; + int GetFormat() const; + bool Update(const CRect& r, const void* data, int pitch); + bool Map(BYTE** bits, int& pitch, const RECT* r = NULL); + void Unmap(); + bool Save(CString fn, bool dds = false); + + IDirectDrawSurface7* operator->(); // TODO: remove direct access + + operator IDirectDrawSurface7*(); +}; diff --git a/plugins/GSdx/GSTexture9.cpp b/plugins/GSdx/GSTexture9.cpp index 6c020bf902..8d75cc2845 100644 --- a/plugins/GSdx/GSTexture9.cpp +++ b/plugins/GSdx/GSTexture9.cpp @@ -1,224 +1,224 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GSTexture9.h" - -GSTexture9::GSTexture9() -{ - memset(&m_desc, 0, sizeof(m_desc)); -} - -GSTexture9::GSTexture9(IDirect3DSurface9* surface) -{ - m_surface = surface; - - surface->GetDevice(&m_dev); - surface->GetDesc(&m_desc); - - if(m_desc.Type != D3DRTYPE_SURFACE) - { - HRESULT hr = surface->GetContainer(__uuidof(IDirect3DTexture9), (void**)&m_texture); - ASSERT(SUCCEEDED(hr)); - } -} - -GSTexture9::GSTexture9(IDirect3DTexture9* texture) -{ - m_texture = texture; - - texture->GetDevice(&m_dev); - texture->GetLevelDesc(0, &m_desc); - texture->GetSurfaceLevel(0, &m_surface); -} - -GSTexture9::~GSTexture9() -{ -} - -GSTexture9::operator bool() -{ - return !!m_surface; -} - -int GSTexture9::GetType() const -{ - if(m_desc.Usage & D3DUSAGE_RENDERTARGET) return GSTexture::RenderTarget; - if(m_desc.Usage & D3DUSAGE_DEPTHSTENCIL) return GSTexture::DepthStencil; - if(m_desc.Pool == D3DPOOL_MANAGED) return GSTexture::Texture; - if(m_desc.Pool == D3DPOOL_SYSTEMMEM) return GSTexture::Offscreen; - return GSTexture::None; -} - -int GSTexture9::GetWidth() const -{ - return m_desc.Width; -} - -int GSTexture9::GetHeight() const -{ - return m_desc.Height; -} - -int GSTexture9::GetFormat() const -{ - return m_desc.Format; -} - -bool GSTexture9::Update(const CRect& r, const void* data, int pitch) -{ - if(CComPtr surface = *this) - { - D3DLOCKED_RECT lr; - - if(SUCCEEDED(surface->LockRect(&lr, r, 0))) - { - BYTE* src = (BYTE*)data; - BYTE* dst = (BYTE*)lr.pBits; - - int bytes = min(pitch, lr.Pitch); - - for(int i = 0, j = r.Height(); i < j; i++, src += pitch, dst += lr.Pitch) - { - memcpy(dst, src, bytes); - } - - surface->UnlockRect(); - - return true; - } - } - - return false; -} - -bool GSTexture9::Map(BYTE** bits, int& pitch, const RECT* r) -{ - HRESULT hr; - - if(CComPtr surface = *this) - { - D3DLOCKED_RECT lr; - - if(SUCCEEDED(hr = surface->LockRect(&lr, r, 0))) - { - *bits = (BYTE*)lr.pBits; - pitch = (int)lr.Pitch; - - return true; - } - } - - return false; -} - -void GSTexture9::Unmap() -{ - if(CComPtr surface = *this) - { - surface->UnlockRect(); - } -} - -bool GSTexture9::Save(CString fn, bool dds) -{ - CComPtr res; - - if(m_desc.Usage & D3DUSAGE_DEPTHSTENCIL) - { - HRESULT hr; - - D3DSURFACE_DESC desc; - - m_surface->GetDesc(&desc); - - if(desc.Format != D3DFMT_D32F_LOCKABLE) - return false; - - CComPtr surface; - - hr = m_dev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &surface, NULL); - - D3DLOCKED_RECT slr, dlr; - - hr = m_surface->LockRect(&slr, NULL, 0); - hr = surface->LockRect(&dlr, NULL, 0); - - BYTE* s = (BYTE*)slr.pBits; - BYTE* d = (BYTE*)dlr.pBits; - - for(UINT y = 0; y < desc.Height; y++, s += slr.Pitch, d += dlr.Pitch) - { - for(UINT x = 0; x < desc.Width; x++) - { - ((float*)d)[x] = ((float*)s)[x]; - } - } - - m_surface->UnlockRect(); - surface->UnlockRect(); - - res = surface; - } - else - { - res = m_surface; - } - - if(CComQIPtr surface = res) - { - return SUCCEEDED(D3DXSaveSurfaceToFile(fn, dds ? D3DXIFF_DDS : D3DXIFF_BMP, surface, NULL, NULL)); - } - - if(CComQIPtr texture = res) - { - return SUCCEEDED(D3DXSaveTextureToFile(fn, dds ? D3DXIFF_DDS : D3DXIFF_BMP, texture, NULL)); - } - - return false; -} - -IDirect3DTexture9* GSTexture9::operator->() -{ - return m_texture; -} - -GSTexture9::operator IDirect3DSurface9*() -{ - if(m_texture && !m_surface) - { - m_texture->GetSurfaceLevel(0, &m_surface); - } - - return m_surface; -} - -GSTexture9::operator IDirect3DTexture9*() -{ - if(m_surface && !m_texture) - { - m_surface->GetContainer(__uuidof(IDirect3DTexture9), (void**)&m_texture); - - ASSERT(m_texture); - } - - return m_texture; -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSTexture9.h" + +GSTexture9::GSTexture9() +{ + memset(&m_desc, 0, sizeof(m_desc)); +} + +GSTexture9::GSTexture9(IDirect3DSurface9* surface) +{ + m_surface = surface; + + surface->GetDevice(&m_dev); + surface->GetDesc(&m_desc); + + if(m_desc.Type != D3DRTYPE_SURFACE) + { + HRESULT hr = surface->GetContainer(__uuidof(IDirect3DTexture9), (void**)&m_texture); + ASSERT(SUCCEEDED(hr)); + } +} + +GSTexture9::GSTexture9(IDirect3DTexture9* texture) +{ + m_texture = texture; + + texture->GetDevice(&m_dev); + texture->GetLevelDesc(0, &m_desc); + texture->GetSurfaceLevel(0, &m_surface); +} + +GSTexture9::~GSTexture9() +{ +} + +GSTexture9::operator bool() +{ + return !!m_surface; +} + +int GSTexture9::GetType() const +{ + if(m_desc.Usage & D3DUSAGE_RENDERTARGET) return GSTexture::RenderTarget; + if(m_desc.Usage & D3DUSAGE_DEPTHSTENCIL) return GSTexture::DepthStencil; + if(m_desc.Pool == D3DPOOL_MANAGED) return GSTexture::Texture; + if(m_desc.Pool == D3DPOOL_SYSTEMMEM) return GSTexture::Offscreen; + return GSTexture::None; +} + +int GSTexture9::GetWidth() const +{ + return m_desc.Width; +} + +int GSTexture9::GetHeight() const +{ + return m_desc.Height; +} + +int GSTexture9::GetFormat() const +{ + return m_desc.Format; +} + +bool GSTexture9::Update(const CRect& r, const void* data, int pitch) +{ + if(CComPtr surface = *this) + { + D3DLOCKED_RECT lr; + + if(SUCCEEDED(surface->LockRect(&lr, r, 0))) + { + BYTE* src = (BYTE*)data; + BYTE* dst = (BYTE*)lr.pBits; + + int bytes = min(pitch, lr.Pitch); + + for(int i = 0, j = r.Height(); i < j; i++, src += pitch, dst += lr.Pitch) + { + memcpy(dst, src, bytes); + } + + surface->UnlockRect(); + + return true; + } + } + + return false; +} + +bool GSTexture9::Map(BYTE** bits, int& pitch, const RECT* r) +{ + HRESULT hr; + + if(CComPtr surface = *this) + { + D3DLOCKED_RECT lr; + + if(SUCCEEDED(hr = surface->LockRect(&lr, r, 0))) + { + *bits = (BYTE*)lr.pBits; + pitch = (int)lr.Pitch; + + return true; + } + } + + return false; +} + +void GSTexture9::Unmap() +{ + if(CComPtr surface = *this) + { + surface->UnlockRect(); + } +} + +bool GSTexture9::Save(CString fn, bool dds) +{ + CComPtr res; + + if(m_desc.Usage & D3DUSAGE_DEPTHSTENCIL) + { + HRESULT hr; + + D3DSURFACE_DESC desc; + + m_surface->GetDesc(&desc); + + if(desc.Format != D3DFMT_D32F_LOCKABLE) + return false; + + CComPtr surface; + + hr = m_dev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &surface, NULL); + + D3DLOCKED_RECT slr, dlr; + + hr = m_surface->LockRect(&slr, NULL, 0); + hr = surface->LockRect(&dlr, NULL, 0); + + BYTE* s = (BYTE*)slr.pBits; + BYTE* d = (BYTE*)dlr.pBits; + + for(UINT y = 0; y < desc.Height; y++, s += slr.Pitch, d += dlr.Pitch) + { + for(UINT x = 0; x < desc.Width; x++) + { + ((float*)d)[x] = ((float*)s)[x]; + } + } + + m_surface->UnlockRect(); + surface->UnlockRect(); + + res = surface; + } + else + { + res = m_surface; + } + + if(CComQIPtr surface = res) + { + return SUCCEEDED(D3DXSaveSurfaceToFile(fn, dds ? D3DXIFF_DDS : D3DXIFF_BMP, surface, NULL, NULL)); + } + + if(CComQIPtr texture = res) + { + return SUCCEEDED(D3DXSaveTextureToFile(fn, dds ? D3DXIFF_DDS : D3DXIFF_BMP, texture, NULL)); + } + + return false; +} + +IDirect3DTexture9* GSTexture9::operator->() +{ + return m_texture; +} + +GSTexture9::operator IDirect3DSurface9*() +{ + if(m_texture && !m_surface) + { + m_texture->GetSurfaceLevel(0, &m_surface); + } + + return m_surface; +} + +GSTexture9::operator IDirect3DTexture9*() +{ + if(m_surface && !m_texture) + { + m_surface->GetContainer(__uuidof(IDirect3DTexture9), (void**)&m_texture); + + ASSERT(m_texture); + } + + return m_texture; +} diff --git a/plugins/GSdx/GSTexture9.h b/plugins/GSdx/GSTexture9.h index eb7a2e8bf1..c952cda68e 100644 --- a/plugins/GSdx/GSTexture9.h +++ b/plugins/GSdx/GSTexture9.h @@ -1,54 +1,54 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSTexture.h" - -class GSTexture9 : public GSTexture -{ - CComPtr m_dev; - CComPtr m_surface; - CComPtr m_texture; - D3DSURFACE_DESC m_desc; - -public: - GSTexture9(); - explicit GSTexture9(IDirect3DSurface9* surface); - explicit GSTexture9(IDirect3DTexture9* texture); - virtual ~GSTexture9(); - - operator bool(); - - int GetType() const; - int GetWidth() const; - int GetHeight() const; - int GetFormat() const; - bool Update(const CRect& r, const void* data, int pitch); - bool Map(BYTE** bits, int& pitch, const RECT* r = NULL); - void Unmap(); - bool Save(CString fn, bool dds = false); - - IDirect3DTexture9* operator->(); // TODO: remove direct access - - operator IDirect3DSurface9*(); - operator IDirect3DTexture9*(); -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSTexture.h" + +class GSTexture9 : public GSTexture +{ + CComPtr m_dev; + CComPtr m_surface; + CComPtr m_texture; + D3DSURFACE_DESC m_desc; + +public: + GSTexture9(); + explicit GSTexture9(IDirect3DSurface9* surface); + explicit GSTexture9(IDirect3DTexture9* texture); + virtual ~GSTexture9(); + + operator bool(); + + int GetType() const; + int GetWidth() const; + int GetHeight() const; + int GetFormat() const; + bool Update(const CRect& r, const void* data, int pitch); + bool Map(BYTE** bits, int& pitch, const RECT* r = NULL); + void Unmap(); + bool Save(CString fn, bool dds = false); + + IDirect3DTexture9* operator->(); // TODO: remove direct access + + operator IDirect3DSurface9*(); + operator IDirect3DTexture9*(); +}; diff --git a/plugins/GSdx/GSTextureCache.cpp b/plugins/GSdx/GSTextureCache.cpp index 89addcc544..9174325f7a 100644 --- a/plugins/GSdx/GSTextureCache.cpp +++ b/plugins/GSdx/GSTextureCache.cpp @@ -1,23 +1,23 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSTextureCache.h" +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSTextureCache.h" diff --git a/plugins/GSdx/GSTextureCache.h b/plugins/GSdx/GSTextureCache.h index 59e18bdd46..7bb853227d 100644 --- a/plugins/GSdx/GSTextureCache.h +++ b/plugins/GSdx/GSTextureCache.h @@ -1,816 +1,816 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSRenderer.h" - -template class GSTextureCache -{ - typedef typename Device::Texture Texture; - -public: - class GSSurface - { - protected: - GSRenderer* m_renderer; - - typedef typename Device::Texture Texture; - - public: - Texture m_texture; - Texture m_palette; - bool m_initpalette; - int m_age; - GSDirtyRectList m_dirty; - GIFRegTEX0 m_TEX0; - - explicit GSSurface(GSRenderer* renderer) - : m_renderer(renderer) - , m_age(0) - , m_initpalette(false) - { - m_TEX0.TBP0 = (UINT32)~0; - } - - virtual ~GSSurface() - { - m_renderer->m_dev.Recycle(m_texture); - m_renderer->m_dev.Recycle(m_palette); - } - - virtual void Update() - { - m_age = 0; - } - }; - - class GSRenderTarget : public GSSurface - { - public: - bool m_used; - - explicit GSRenderTarget(GSRenderer* renderer) - : GSSurface(renderer) - , m_used(true) - { - } - - virtual bool Create(int w, int h) - { - // FIXME: initial data should be unswizzled from local mem in Update() if dirty - - return m_renderer->m_dev.CreateRenderTarget(m_texture, w, h); - } - - virtual void Read(CRect r) = 0; - }; - - class GSDepthStencil : public GSSurface - { - public: - bool m_used; - - explicit GSDepthStencil(GSRenderer* renderer) - : GSSurface(renderer) - , m_used(false) - { - } - - virtual bool Create(int w, int h) - { - // FIXME: initial data should be unswizzled from local mem in Update() if dirty - - return m_renderer->m_dev.CreateDepthStencil(m_texture, w, h); - } - - }; - - class GSTexture : public GSSurface - { - protected: - bool GetDirtyRect(CRect& rr) - { - int w = 1 << m_TEX0.TW; - int h = 1 << m_TEX0.TH; - - CRect r(0, 0, w, h); - - POSITION pos = m_dirty.GetHeadPosition(); - - while(pos) - { - const CRect& dirty = m_dirty.GetNext(pos).GetDirtyRect(m_TEX0) & r; - - if(!(m_valid & dirty).IsRectEmpty()) - { - // find the rect having the largest area, outside dirty, inside m_valid - - CRect left(m_valid.left, m_valid.top, min(m_valid.right, dirty.left), m_valid.bottom); - CRect top(m_valid.left, m_valid.top, m_valid.right, min(m_valid.bottom, dirty.top)); - CRect right(max(m_valid.left, dirty.right), m_valid.top, m_valid.right, m_valid.bottom); - CRect bottom(m_valid.left, max(m_valid.top, dirty.bottom), m_valid.right, m_valid.bottom); - - int leftsize = !left.IsRectEmpty() ? left.Width() * left.Height() : 0; - int topsize = !top.IsRectEmpty() ? top.Width() * top.Height() : 0; - int rightsize = !right.IsRectEmpty() ? right.Width() * right.Height() : 0; - int bottomsize = !bottom.IsRectEmpty() ? bottom.Width() * bottom.Height() : 0; - - // TODO: sort - - m_valid = - leftsize > 0 ? left : - topsize > 0 ? top : - rightsize > 0 ? right : - bottomsize > 0 ? bottom : - CRect(0, 0, 0, 0); - } - } - - m_dirty.RemoveAll(); - - m_renderer->MinMaxUV(w, h, r); - - if(GSUtil::IsRectInRect(r, m_valid)) - { - return false; - } - else if(GSUtil::IsRectInRectH(r, m_valid) && (r.left >= m_valid.left || r.right <= m_valid.right)) - { - r.top = m_valid.top; - r.bottom = m_valid.bottom; - if(r.left < m_valid.left) r.right = m_valid.left; - else r.left = m_valid.right; // if(r.right > m_valid.right) - } - else if(GSUtil::IsRectInRectV(r, m_valid) && (r.top >= m_valid.top || r.bottom <= m_valid.bottom)) - { - r.left = m_valid.left; - r.right = m_valid.right; - if(r.top < m_valid.top) r.bottom = m_valid.top; - else r.top = m_valid.bottom; // if(r.bottom > m_valid.bottom) - } - else - { - r |= m_valid; - } - - if(r.IsRectEmpty()) - { - return false; - } - - rr = r; - - return true; - } - - public: - GIFRegCLAMP m_CLAMP; - DWORD* m_clut; // * - CRect m_valid; - int m_bpp; - int m_bpp2; - bool m_rendered; - - explicit GSTexture(GSRenderer* renderer) - : GSSurface(renderer) - , m_valid(0, 0, 0, 0) - , m_bpp(0) - , m_bpp2(0) - , m_rendered(false) - { - m_clut = (DWORD*)_aligned_malloc(256 * sizeof(DWORD), 16); - - memset(m_clut, 0, sizeof(m_clut)); - } - - ~GSTexture() - { - _aligned_free(m_clut); - } - - virtual bool Create() = 0; - virtual bool Create(GSRenderTarget* rt) = 0; - virtual bool Create(GSDepthStencil* ds) = 0; - }; - -protected: - GSRenderer* m_renderer; - CAtlList m_rt; - CAtlList m_ds; - CAtlList m_tex; - - template void RecycleByAge(CAtlList& l, int maxage = 60) - { - POSITION pos = l.GetHeadPosition(); - - while(pos) - { - POSITION cur = pos; - - T* t = l.GetNext(pos); - - if(++t->m_age > maxage) - { - l.RemoveAt(cur); - - delete t; - } - } - } - - virtual GSRenderTarget* CreateRenderTarget() = 0; - virtual GSDepthStencil* CreateDepthStencil() = 0; - virtual GSTexture* CreateTexture() = 0; - -public: - GSTextureCache(GSRenderer* renderer) - : m_renderer(renderer) - { - } - - virtual ~GSTextureCache() - { - RemoveAll(); - } - - void RemoveAll() - { - while(m_rt.GetCount()) delete m_rt.RemoveHead(); - while(m_ds.GetCount()) delete m_ds.RemoveHead(); - while(m_tex.GetCount()) delete m_tex.RemoveHead(); - } - - GSRenderTarget* GetRenderTarget(const GIFRegTEX0& TEX0, int w, int h, bool fb = false) - { - GSRenderTarget* rt = NULL; - - if(rt == NULL) - { - for(POSITION pos = m_rt.GetHeadPosition(); pos; m_rt.GetNext(pos)) - { - GSRenderTarget* rt2 = m_rt.GetAt(pos); - - if(rt2->m_TEX0.TBP0 == TEX0.TBP0) - { - m_rt.MoveToHead(pos); - - rt = rt2; - - if(!fb) rt->m_TEX0 = TEX0; - - rt->Update(); - - break; - } - } - } - - if(rt == NULL && fb) - { - // HACK: try to find something close to the base pointer - - for(POSITION pos = m_rt.GetHeadPosition(); pos; m_rt.GetNext(pos)) - { - GSRenderTarget* rt2 = m_rt.GetAt(pos); - - if(rt2->m_TEX0.TBP0 <= TEX0.TBP0 && TEX0.TBP0 < rt2->m_TEX0.TBP0 + 0x700 && (!rt || rt2->m_TEX0.TBP0 >= rt->m_TEX0.TBP0)) - { - rt = rt2; - } - } - - if(rt) - { - rt->Update(); - } - } - - if(rt == NULL) - { - rt = CreateRenderTarget(); - - rt->m_TEX0 = TEX0; - - if(!rt->Create(w, h)) - { - delete rt; - - return NULL; - } - - m_rt.AddHead(rt); - } - - if(m_renderer->CanUpscale()) - { - int ww = (int)(m_renderer->GetFramePos().cx + rt->m_TEX0.TBW * 64); - int hh = (int)(m_renderer->GetFramePos().cy + m_renderer->GetDisplaySize().cy); - - if(hh <= m_renderer->GetDeviceSize().cy / 2) - { - hh *= 2; - } - - if(ww > 0 && hh > 0) - { - rt->m_texture.m_scale.x = (float)w / ww; - rt->m_texture.m_scale.y = (float)h / hh; - } - } - - if(!fb) - { - rt->m_used = true; - } - - return rt; - } - - GSDepthStencil* GetDepthStencil(const GIFRegTEX0& TEX0, int w, int h) - { - GSDepthStencil* ds = NULL; - - if(ds == NULL) - { - for(POSITION pos = m_ds.GetHeadPosition(); pos; m_ds.GetNext(pos)) - { - GSDepthStencil* ds2 = m_ds.GetAt(pos); - - if(ds2->m_TEX0.TBP0 == TEX0.TBP0) - { - m_ds.MoveToHead(pos); - - ds = ds2; - - ds->m_TEX0 = TEX0; - - ds->Update(); - - break; - } - } - } - - if(ds == NULL) - { - ds = CreateDepthStencil(); - - ds->m_TEX0 = TEX0; - - if(!ds->Create(w, h)) - { - delete ds; - - return NULL; - } - - m_ds.AddHead(ds); - } - - if(m_renderer->m_context->DepthWrite()) - { - ds->m_used = true; - } - - return ds; - } - - GSTexture* GetTexture() - { - const GIFRegTEX0& TEX0 = m_renderer->m_context->TEX0; - const GIFRegCLAMP& CLAMP = m_renderer->m_context->CLAMP; - - const DWORD* clut = m_renderer->m_mem.m_clut; - const int pal = GSLocalMemory::m_psm[TEX0.PSM].pal; - - if(pal > 0) - { - m_renderer->m_mem.m_clut.Read(TEX0); - - /* - POSITION pos = m_tex.GetHeadPosition(); - - while(pos) - { - POSITION cur = pos; - - GSSurface* s = m_tex.GetNext(pos); - - if(s->m_TEX0.TBP0 == TEX0.CBP) - { - m_tex.RemoveAt(cur); - - delete s; - } - } - - pos = m_rt.GetHeadPosition(); - - while(pos) - { - POSITION cur = pos; - - GSSurface* s = m_rt.GetNext(pos); - - if(s->m_TEX0.TBP0 == TEX0.CBP) - { - m_rt.RemoveAt(cur); - - delete s; - } - } - - pos = m_ds.GetHeadPosition(); - - while(pos) - { - POSITION cur = pos; - - GSSurface* s = m_ds.GetNext(pos); - - if(s->m_TEX0.TBP0 == TEX0.CBP) - { - m_ds.RemoveAt(cur); - - delete s; - } - } - */ - } - - GSTexture* t = NULL; - - for(POSITION pos = m_tex.GetHeadPosition(); pos; m_tex.GetNext(pos)) - { - t = m_tex.GetAt(pos); - - if(GSUtil::HasSharedBits(t->m_TEX0.TBP0, t->m_TEX0.PSM, TEX0.TBP0, TEX0.PSM)) - { - if(TEX0.PSM == t->m_TEX0.PSM && TEX0.TBW == t->m_TEX0.TBW - && TEX0.TW == t->m_TEX0.TW && TEX0.TH == t->m_TEX0.TH - && (m_renderer->m_psrr || (CLAMP.WMS != 3 && t->m_CLAMP.WMS != 3 && CLAMP.WMT != 3 && t->m_CLAMP.WMT != 3 || CLAMP.i64 == t->m_CLAMP.i64)) - && (pal == 0 || TEX0.CPSM == t->m_TEX0.CPSM && GSVector4i::compare(t->m_clut, clut, pal * sizeof(clut[0])))) - { - m_tex.MoveToHead(pos); - - break; - } - } - - t = NULL; - } - - if(t == NULL) - { - for(POSITION pos = m_rt.GetHeadPosition(); pos; m_rt.GetNext(pos)) - { - GSRenderTarget* rt = m_rt.GetAt(pos); - - if(rt->m_dirty.IsEmpty() && GSUtil::HasSharedBits(rt->m_TEX0.TBP0, rt->m_TEX0.PSM, TEX0.TBP0, TEX0.PSM)) - { - t = CreateTexture(); - - if(!t->Create(rt)) - { - delete t; - - return NULL; - } - - m_tex.AddHead(t); - - break; - } - } - } - - if(t == NULL) - { - for(POSITION pos = m_ds.GetHeadPosition(); pos; m_ds.GetNext(pos)) - { - GSDepthStencil* ds = m_ds.GetAt(pos); - - if(ds->m_dirty.IsEmpty() && ds->m_used && GSUtil::HasSharedBits(ds->m_TEX0.TBP0, ds->m_TEX0.PSM, TEX0.TBP0, TEX0.PSM)) - { - t = CreateTexture(); - - if(!t->Create(ds)) - { - delete t; - - return NULL; - } - - m_tex.AddHead(t); - - break; - } - } - } - - if(t == NULL) - { - t = CreateTexture(); - - if(!t->Create()) - { - delete t; - - return NULL; - } - - m_tex.AddHead(t); - } - - if(pal > 0) - { - int size = pal * sizeof(clut[0]); - - if(t->m_palette) - { - if(t->m_initpalette) - { - memcpy(t->m_clut, clut, size); - t->m_palette.Update(CRect(0, 0, pal, 1), t->m_clut, size); - t->m_initpalette = false; - } - else - { - if(GSVector4i::update(t->m_clut, clut, size)) - { - t->m_palette.Update(CRect(0, 0, pal, 1), t->m_clut, size); - } - } - } - else - { - memcpy(t->m_clut, clut, size); - } - } - - t->Update(); - - return t; - } - - void InvalidateTextures(const GIFRegFRAME& FRAME, const GIFRegZBUF& ZBUF) - { - POSITION pos = m_tex.GetHeadPosition(); - - while(pos) - { - POSITION cur = pos; - - GSTexture* t = m_tex.GetNext(pos); - - if(GSUtil::HasSharedBits(FRAME.Block(), FRAME.PSM, t->m_TEX0.TBP0, t->m_TEX0.PSM) - || GSUtil::HasSharedBits(ZBUF.Block(), ZBUF.PSM, t->m_TEX0.TBP0, t->m_TEX0.PSM)) - { - m_tex.RemoveAt(cur); - - delete t; - } - } - } - - void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const CRect& r) - { - bool found = false; - - POSITION pos = m_tex.GetHeadPosition(); - - while(pos) - { - POSITION cur = pos; - - GSTexture* t = m_tex.GetNext(pos); - - if(GSUtil::HasSharedBits(BITBLTBUF.DBP, BITBLTBUF.DPSM, t->m_TEX0.TBP0, t->m_TEX0.PSM)) - { - if(BITBLTBUF.DBW == t->m_TEX0.TBW && !t->m_rendered) - { - t->m_dirty.AddTail(GSDirtyRect(BITBLTBUF.DPSM, r)); - - found = true; - } - else - { - m_tex.RemoveAt(cur); - - delete t; - } - } - else if(GSUtil::HasCompatibleBits(BITBLTBUF.DPSM, t->m_TEX0.PSM)) - { - if(BITBLTBUF.DBW == t->m_TEX0.TBW && !t->m_rendered) - { - int rowsize = (int)BITBLTBUF.DBW * 8192; - int offset = ((int)BITBLTBUF.DBP - (int)t->m_TEX0.TBP0) * 256; - - if(rowsize > 0 && offset % rowsize == 0) - { - int y = m_renderer->m_mem.m_psm[BITBLTBUF.DPSM].pgs.cy * offset / rowsize; - - CRect r2(r.left, r.top + y, r.right, r.bottom + y); - - int w = 1 << t->m_TEX0.TW; - int h = 1 << t->m_TEX0.TH; - - if(r2.bottom > 0 && r2.top < h && r2.right > 0 && r2.left < w) - { - t->m_dirty.AddTail(GSDirtyRect(BITBLTBUF.DPSM, r2)); - } - } - } - } - } - - pos = m_rt.GetHeadPosition(); - - while(pos) - { - POSITION cur = pos; - - GSRenderTarget* rt = m_rt.GetNext(pos); - - if(GSUtil::HasSharedBits(BITBLTBUF.DBP, BITBLTBUF.DPSM, rt->m_TEX0.TBP0, rt->m_TEX0.PSM)) - { - if(!found && GSUtil::HasCompatibleBits(BITBLTBUF.DPSM, rt->m_TEX0.PSM)) - { - rt->m_dirty.AddTail(GSDirtyRect(BITBLTBUF.DPSM, r)); - rt->m_TEX0.TBW = BITBLTBUF.DBW; - } - else - { - m_rt.RemoveAt(cur); - delete rt; - continue; - } - } - - if(GSUtil::HasSharedBits(BITBLTBUF.DPSM, rt->m_TEX0.PSM) && BITBLTBUF.DBP < rt->m_TEX0.TBP0) - { - DWORD rowsize = BITBLTBUF.DBW * 8192; - DWORD offset = (DWORD)((rt->m_TEX0.TBP0 - BITBLTBUF.DBP) * 256); - - if(rowsize > 0 && offset % rowsize == 0) - { - int y = m_renderer->m_mem.m_psm[BITBLTBUF.DPSM].pgs.cy * offset / rowsize; - - if(r.bottom >= y) - { - // TODO: do not add this rect above too - rt->m_dirty.AddTail(GSDirtyRect(BITBLTBUF.DPSM, CRect(r.left, r.top - y, r.right, r.bottom - y))); - rt->m_TEX0.TBW = BITBLTBUF.DBW; - continue; - } - } - } - } - - // copypaste for ds - - pos = m_ds.GetHeadPosition(); - - while(pos) - { - POSITION cur = pos; - - GSDepthStencil* ds = m_ds.GetNext(pos); - - if(GSUtil::HasSharedBits(BITBLTBUF.DBP, BITBLTBUF.DPSM, ds->m_TEX0.TBP0, ds->m_TEX0.PSM)) - { - if(!found && GSUtil::HasCompatibleBits(BITBLTBUF.DPSM, ds->m_TEX0.PSM)) - { - ds->m_dirty.AddTail(GSDirtyRect(BITBLTBUF.DPSM, r)); - ds->m_TEX0.TBW = BITBLTBUF.DBW; - } - else - { - m_ds.RemoveAt(cur); - delete ds; - continue; - } - } - - if(GSUtil::HasSharedBits(BITBLTBUF.DPSM, ds->m_TEX0.PSM) && BITBLTBUF.DBP < ds->m_TEX0.TBP0) - { - DWORD rowsize = BITBLTBUF.DBW * 8192; - DWORD offset = (DWORD)((ds->m_TEX0.TBP0 - BITBLTBUF.DBP) * 256); - - if(rowsize > 0 && offset % rowsize == 0) - { - int y = m_renderer->m_mem.m_psm[BITBLTBUF.DPSM].pgs.cy * offset / rowsize; - - if(r.bottom >= y) - { - // TODO: do not add this rect above too - ds->m_dirty.AddTail(GSDirtyRect(BITBLTBUF.DPSM, CRect(r.left, r.top - y, r.right, r.bottom - y))); - ds->m_TEX0.TBW = BITBLTBUF.DBW; - continue; - } - } - } - - } - } - - void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const CRect& r) - { - POSITION pos = m_rt.GetHeadPosition(); - - while(pos) - { - POSITION cur = pos; - - GSRenderTarget* rt = m_rt.GetNext(pos); - - if(GSUtil::HasSharedBits(BITBLTBUF.SBP, BITBLTBUF.SPSM, rt->m_TEX0.TBP0, rt->m_TEX0.PSM)) - { - if(GSUtil::HasCompatibleBits(BITBLTBUF.SPSM, rt->m_TEX0.PSM)) - { - rt->Read(r); - return; - } - else if(BITBLTBUF.SPSM == PSM_PSMCT32 && (rt->m_TEX0.PSM == PSM_PSMCT16 || rt->m_TEX0.PSM == PSM_PSMCT16S)) - { - // ffx-2 riku changing to her default (shoots some reflecting glass at the end), 16-bit rt read as 32-bit - - rt->Read(CRect(r.left, r.top, r.right, r.top + (r.bottom - r.top) * 2)); - return; - } - else - { - m_rt.RemoveAt(cur); - delete rt; - continue; - } - } - } -/* - // no good, ffx does a lot of readback after exiting menu, at 0x02f00 this wrongly finds rt 0x02100 (0,448 - 512,480) - - GSRenderTarget* rt2 = NULL; - int ymin = INT_MAX; - - pos = m_rt.GetHeadPosition(); - - while(pos) - { - GSRenderTarget* rt = m_rt.GetNext(pos); - - if(HasSharedBits(BITBLTBUF.SPSM, rt->m_TEX0.PSM) && BITBLTBUF.SBP > rt->m_TEX0.TBP0) - { - // ffx2 pause screen background - - DWORD rowsize = BITBLTBUF.SBW * 8192; - DWORD offset = (DWORD)((BITBLTBUF.SBP - rt->m_TEX0.TBP0) * 256); - - if(rowsize > 0 && offset % rowsize == 0) - { - int y = m_renderer->m_mem.m_psm[BITBLTBUF.SPSM].pgs.cy * offset / rowsize; - - if(y < ymin && y < 512) - { - rt2 = rt; - ymin = y; - } - } - } - } - - if(rt2) - { - rt2->Read(CRect(r.left, r.top + ymin, r.right, r.bottom + ymin)); - } - - // TODO: ds -*/ - } - - void IncAge() - { - RecycleByAge(m_tex, 2); - RecycleByAge(m_rt); - RecycleByAge(m_ds); - } -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSRenderer.h" + +template class GSTextureCache +{ + typedef typename Device::Texture Texture; + +public: + class GSSurface + { + protected: + GSRenderer* m_renderer; + + typedef typename Device::Texture Texture; + + public: + Texture m_texture; + Texture m_palette; + bool m_initpalette; + int m_age; + GSDirtyRectList m_dirty; + GIFRegTEX0 m_TEX0; + + explicit GSSurface(GSRenderer* renderer) + : m_renderer(renderer) + , m_age(0) + , m_initpalette(false) + { + m_TEX0.TBP0 = (UINT32)~0; + } + + virtual ~GSSurface() + { + m_renderer->m_dev.Recycle(m_texture); + m_renderer->m_dev.Recycle(m_palette); + } + + virtual void Update() + { + m_age = 0; + } + }; + + class GSRenderTarget : public GSSurface + { + public: + bool m_used; + + explicit GSRenderTarget(GSRenderer* renderer) + : GSSurface(renderer) + , m_used(true) + { + } + + virtual bool Create(int w, int h) + { + // FIXME: initial data should be unswizzled from local mem in Update() if dirty + + return m_renderer->m_dev.CreateRenderTarget(m_texture, w, h); + } + + virtual void Read(CRect r) = 0; + }; + + class GSDepthStencil : public GSSurface + { + public: + bool m_used; + + explicit GSDepthStencil(GSRenderer* renderer) + : GSSurface(renderer) + , m_used(false) + { + } + + virtual bool Create(int w, int h) + { + // FIXME: initial data should be unswizzled from local mem in Update() if dirty + + return m_renderer->m_dev.CreateDepthStencil(m_texture, w, h); + } + + }; + + class GSTexture : public GSSurface + { + protected: + bool GetDirtyRect(CRect& rr) + { + int w = 1 << m_TEX0.TW; + int h = 1 << m_TEX0.TH; + + CRect r(0, 0, w, h); + + POSITION pos = m_dirty.GetHeadPosition(); + + while(pos) + { + const CRect& dirty = m_dirty.GetNext(pos).GetDirtyRect(m_TEX0) & r; + + if(!(m_valid & dirty).IsRectEmpty()) + { + // find the rect having the largest area, outside dirty, inside m_valid + + CRect left(m_valid.left, m_valid.top, min(m_valid.right, dirty.left), m_valid.bottom); + CRect top(m_valid.left, m_valid.top, m_valid.right, min(m_valid.bottom, dirty.top)); + CRect right(max(m_valid.left, dirty.right), m_valid.top, m_valid.right, m_valid.bottom); + CRect bottom(m_valid.left, max(m_valid.top, dirty.bottom), m_valid.right, m_valid.bottom); + + int leftsize = !left.IsRectEmpty() ? left.Width() * left.Height() : 0; + int topsize = !top.IsRectEmpty() ? top.Width() * top.Height() : 0; + int rightsize = !right.IsRectEmpty() ? right.Width() * right.Height() : 0; + int bottomsize = !bottom.IsRectEmpty() ? bottom.Width() * bottom.Height() : 0; + + // TODO: sort + + m_valid = + leftsize > 0 ? left : + topsize > 0 ? top : + rightsize > 0 ? right : + bottomsize > 0 ? bottom : + CRect(0, 0, 0, 0); + } + } + + m_dirty.RemoveAll(); + + m_renderer->MinMaxUV(w, h, r); + + if(GSUtil::IsRectInRect(r, m_valid)) + { + return false; + } + else if(GSUtil::IsRectInRectH(r, m_valid) && (r.left >= m_valid.left || r.right <= m_valid.right)) + { + r.top = m_valid.top; + r.bottom = m_valid.bottom; + if(r.left < m_valid.left) r.right = m_valid.left; + else r.left = m_valid.right; // if(r.right > m_valid.right) + } + else if(GSUtil::IsRectInRectV(r, m_valid) && (r.top >= m_valid.top || r.bottom <= m_valid.bottom)) + { + r.left = m_valid.left; + r.right = m_valid.right; + if(r.top < m_valid.top) r.bottom = m_valid.top; + else r.top = m_valid.bottom; // if(r.bottom > m_valid.bottom) + } + else + { + r |= m_valid; + } + + if(r.IsRectEmpty()) + { + return false; + } + + rr = r; + + return true; + } + + public: + GIFRegCLAMP m_CLAMP; + DWORD* m_clut; // * + CRect m_valid; + int m_bpp; + int m_bpp2; + bool m_rendered; + + explicit GSTexture(GSRenderer* renderer) + : GSSurface(renderer) + , m_valid(0, 0, 0, 0) + , m_bpp(0) + , m_bpp2(0) + , m_rendered(false) + { + m_clut = (DWORD*)_aligned_malloc(256 * sizeof(DWORD), 16); + + memset(m_clut, 0, sizeof(m_clut)); + } + + ~GSTexture() + { + _aligned_free(m_clut); + } + + virtual bool Create() = 0; + virtual bool Create(GSRenderTarget* rt) = 0; + virtual bool Create(GSDepthStencil* ds) = 0; + }; + +protected: + GSRenderer* m_renderer; + CAtlList m_rt; + CAtlList m_ds; + CAtlList m_tex; + + template void RecycleByAge(CAtlList& l, int maxage = 60) + { + POSITION pos = l.GetHeadPosition(); + + while(pos) + { + POSITION cur = pos; + + T* t = l.GetNext(pos); + + if(++t->m_age > maxage) + { + l.RemoveAt(cur); + + delete t; + } + } + } + + virtual GSRenderTarget* CreateRenderTarget() = 0; + virtual GSDepthStencil* CreateDepthStencil() = 0; + virtual GSTexture* CreateTexture() = 0; + +public: + GSTextureCache(GSRenderer* renderer) + : m_renderer(renderer) + { + } + + virtual ~GSTextureCache() + { + RemoveAll(); + } + + void RemoveAll() + { + while(m_rt.GetCount()) delete m_rt.RemoveHead(); + while(m_ds.GetCount()) delete m_ds.RemoveHead(); + while(m_tex.GetCount()) delete m_tex.RemoveHead(); + } + + GSRenderTarget* GetRenderTarget(const GIFRegTEX0& TEX0, int w, int h, bool fb = false) + { + GSRenderTarget* rt = NULL; + + if(rt == NULL) + { + for(POSITION pos = m_rt.GetHeadPosition(); pos; m_rt.GetNext(pos)) + { + GSRenderTarget* rt2 = m_rt.GetAt(pos); + + if(rt2->m_TEX0.TBP0 == TEX0.TBP0) + { + m_rt.MoveToHead(pos); + + rt = rt2; + + if(!fb) rt->m_TEX0 = TEX0; + + rt->Update(); + + break; + } + } + } + + if(rt == NULL && fb) + { + // HACK: try to find something close to the base pointer + + for(POSITION pos = m_rt.GetHeadPosition(); pos; m_rt.GetNext(pos)) + { + GSRenderTarget* rt2 = m_rt.GetAt(pos); + + if(rt2->m_TEX0.TBP0 <= TEX0.TBP0 && TEX0.TBP0 < rt2->m_TEX0.TBP0 + 0x700 && (!rt || rt2->m_TEX0.TBP0 >= rt->m_TEX0.TBP0)) + { + rt = rt2; + } + } + + if(rt) + { + rt->Update(); + } + } + + if(rt == NULL) + { + rt = CreateRenderTarget(); + + rt->m_TEX0 = TEX0; + + if(!rt->Create(w, h)) + { + delete rt; + + return NULL; + } + + m_rt.AddHead(rt); + } + + if(m_renderer->CanUpscale()) + { + int ww = (int)(m_renderer->GetFramePos().cx + rt->m_TEX0.TBW * 64); + int hh = (int)(m_renderer->GetFramePos().cy + m_renderer->GetDisplaySize().cy); + + if(hh <= m_renderer->GetDeviceSize().cy / 2) + { + hh *= 2; + } + + if(ww > 0 && hh > 0) + { + rt->m_texture.m_scale.x = (float)w / ww; + rt->m_texture.m_scale.y = (float)h / hh; + } + } + + if(!fb) + { + rt->m_used = true; + } + + return rt; + } + + GSDepthStencil* GetDepthStencil(const GIFRegTEX0& TEX0, int w, int h) + { + GSDepthStencil* ds = NULL; + + if(ds == NULL) + { + for(POSITION pos = m_ds.GetHeadPosition(); pos; m_ds.GetNext(pos)) + { + GSDepthStencil* ds2 = m_ds.GetAt(pos); + + if(ds2->m_TEX0.TBP0 == TEX0.TBP0) + { + m_ds.MoveToHead(pos); + + ds = ds2; + + ds->m_TEX0 = TEX0; + + ds->Update(); + + break; + } + } + } + + if(ds == NULL) + { + ds = CreateDepthStencil(); + + ds->m_TEX0 = TEX0; + + if(!ds->Create(w, h)) + { + delete ds; + + return NULL; + } + + m_ds.AddHead(ds); + } + + if(m_renderer->m_context->DepthWrite()) + { + ds->m_used = true; + } + + return ds; + } + + GSTexture* GetTexture() + { + const GIFRegTEX0& TEX0 = m_renderer->m_context->TEX0; + const GIFRegCLAMP& CLAMP = m_renderer->m_context->CLAMP; + + const DWORD* clut = m_renderer->m_mem.m_clut; + const int pal = GSLocalMemory::m_psm[TEX0.PSM].pal; + + if(pal > 0) + { + m_renderer->m_mem.m_clut.Read(TEX0); + + /* + POSITION pos = m_tex.GetHeadPosition(); + + while(pos) + { + POSITION cur = pos; + + GSSurface* s = m_tex.GetNext(pos); + + if(s->m_TEX0.TBP0 == TEX0.CBP) + { + m_tex.RemoveAt(cur); + + delete s; + } + } + + pos = m_rt.GetHeadPosition(); + + while(pos) + { + POSITION cur = pos; + + GSSurface* s = m_rt.GetNext(pos); + + if(s->m_TEX0.TBP0 == TEX0.CBP) + { + m_rt.RemoveAt(cur); + + delete s; + } + } + + pos = m_ds.GetHeadPosition(); + + while(pos) + { + POSITION cur = pos; + + GSSurface* s = m_ds.GetNext(pos); + + if(s->m_TEX0.TBP0 == TEX0.CBP) + { + m_ds.RemoveAt(cur); + + delete s; + } + } + */ + } + + GSTexture* t = NULL; + + for(POSITION pos = m_tex.GetHeadPosition(); pos; m_tex.GetNext(pos)) + { + t = m_tex.GetAt(pos); + + if(GSUtil::HasSharedBits(t->m_TEX0.TBP0, t->m_TEX0.PSM, TEX0.TBP0, TEX0.PSM)) + { + if(TEX0.PSM == t->m_TEX0.PSM && TEX0.TBW == t->m_TEX0.TBW + && TEX0.TW == t->m_TEX0.TW && TEX0.TH == t->m_TEX0.TH + && (m_renderer->m_psrr || (CLAMP.WMS != 3 && t->m_CLAMP.WMS != 3 && CLAMP.WMT != 3 && t->m_CLAMP.WMT != 3 || CLAMP.i64 == t->m_CLAMP.i64)) + && (pal == 0 || TEX0.CPSM == t->m_TEX0.CPSM && GSVector4i::compare(t->m_clut, clut, pal * sizeof(clut[0])))) + { + m_tex.MoveToHead(pos); + + break; + } + } + + t = NULL; + } + + if(t == NULL) + { + for(POSITION pos = m_rt.GetHeadPosition(); pos; m_rt.GetNext(pos)) + { + GSRenderTarget* rt = m_rt.GetAt(pos); + + if(rt->m_dirty.IsEmpty() && GSUtil::HasSharedBits(rt->m_TEX0.TBP0, rt->m_TEX0.PSM, TEX0.TBP0, TEX0.PSM)) + { + t = CreateTexture(); + + if(!t->Create(rt)) + { + delete t; + + return NULL; + } + + m_tex.AddHead(t); + + break; + } + } + } + + if(t == NULL) + { + for(POSITION pos = m_ds.GetHeadPosition(); pos; m_ds.GetNext(pos)) + { + GSDepthStencil* ds = m_ds.GetAt(pos); + + if(ds->m_dirty.IsEmpty() && ds->m_used && GSUtil::HasSharedBits(ds->m_TEX0.TBP0, ds->m_TEX0.PSM, TEX0.TBP0, TEX0.PSM)) + { + t = CreateTexture(); + + if(!t->Create(ds)) + { + delete t; + + return NULL; + } + + m_tex.AddHead(t); + + break; + } + } + } + + if(t == NULL) + { + t = CreateTexture(); + + if(!t->Create()) + { + delete t; + + return NULL; + } + + m_tex.AddHead(t); + } + + if(pal > 0) + { + int size = pal * sizeof(clut[0]); + + if(t->m_palette) + { + if(t->m_initpalette) + { + memcpy(t->m_clut, clut, size); + t->m_palette.Update(CRect(0, 0, pal, 1), t->m_clut, size); + t->m_initpalette = false; + } + else + { + if(GSVector4i::update(t->m_clut, clut, size)) + { + t->m_palette.Update(CRect(0, 0, pal, 1), t->m_clut, size); + } + } + } + else + { + memcpy(t->m_clut, clut, size); + } + } + + t->Update(); + + return t; + } + + void InvalidateTextures(const GIFRegFRAME& FRAME, const GIFRegZBUF& ZBUF) + { + POSITION pos = m_tex.GetHeadPosition(); + + while(pos) + { + POSITION cur = pos; + + GSTexture* t = m_tex.GetNext(pos); + + if(GSUtil::HasSharedBits(FRAME.Block(), FRAME.PSM, t->m_TEX0.TBP0, t->m_TEX0.PSM) + || GSUtil::HasSharedBits(ZBUF.Block(), ZBUF.PSM, t->m_TEX0.TBP0, t->m_TEX0.PSM)) + { + m_tex.RemoveAt(cur); + + delete t; + } + } + } + + void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const CRect& r) + { + bool found = false; + + POSITION pos = m_tex.GetHeadPosition(); + + while(pos) + { + POSITION cur = pos; + + GSTexture* t = m_tex.GetNext(pos); + + if(GSUtil::HasSharedBits(BITBLTBUF.DBP, BITBLTBUF.DPSM, t->m_TEX0.TBP0, t->m_TEX0.PSM)) + { + if(BITBLTBUF.DBW == t->m_TEX0.TBW && !t->m_rendered) + { + t->m_dirty.AddTail(GSDirtyRect(BITBLTBUF.DPSM, r)); + + found = true; + } + else + { + m_tex.RemoveAt(cur); + + delete t; + } + } + else if(GSUtil::HasCompatibleBits(BITBLTBUF.DPSM, t->m_TEX0.PSM)) + { + if(BITBLTBUF.DBW == t->m_TEX0.TBW && !t->m_rendered) + { + int rowsize = (int)BITBLTBUF.DBW * 8192; + int offset = ((int)BITBLTBUF.DBP - (int)t->m_TEX0.TBP0) * 256; + + if(rowsize > 0 && offset % rowsize == 0) + { + int y = m_renderer->m_mem.m_psm[BITBLTBUF.DPSM].pgs.cy * offset / rowsize; + + CRect r2(r.left, r.top + y, r.right, r.bottom + y); + + int w = 1 << t->m_TEX0.TW; + int h = 1 << t->m_TEX0.TH; + + if(r2.bottom > 0 && r2.top < h && r2.right > 0 && r2.left < w) + { + t->m_dirty.AddTail(GSDirtyRect(BITBLTBUF.DPSM, r2)); + } + } + } + } + } + + pos = m_rt.GetHeadPosition(); + + while(pos) + { + POSITION cur = pos; + + GSRenderTarget* rt = m_rt.GetNext(pos); + + if(GSUtil::HasSharedBits(BITBLTBUF.DBP, BITBLTBUF.DPSM, rt->m_TEX0.TBP0, rt->m_TEX0.PSM)) + { + if(!found && GSUtil::HasCompatibleBits(BITBLTBUF.DPSM, rt->m_TEX0.PSM)) + { + rt->m_dirty.AddTail(GSDirtyRect(BITBLTBUF.DPSM, r)); + rt->m_TEX0.TBW = BITBLTBUF.DBW; + } + else + { + m_rt.RemoveAt(cur); + delete rt; + continue; + } + } + + if(GSUtil::HasSharedBits(BITBLTBUF.DPSM, rt->m_TEX0.PSM) && BITBLTBUF.DBP < rt->m_TEX0.TBP0) + { + DWORD rowsize = BITBLTBUF.DBW * 8192; + DWORD offset = (DWORD)((rt->m_TEX0.TBP0 - BITBLTBUF.DBP) * 256); + + if(rowsize > 0 && offset % rowsize == 0) + { + int y = m_renderer->m_mem.m_psm[BITBLTBUF.DPSM].pgs.cy * offset / rowsize; + + if(r.bottom >= y) + { + // TODO: do not add this rect above too + rt->m_dirty.AddTail(GSDirtyRect(BITBLTBUF.DPSM, CRect(r.left, r.top - y, r.right, r.bottom - y))); + rt->m_TEX0.TBW = BITBLTBUF.DBW; + continue; + } + } + } + } + + // copypaste for ds + + pos = m_ds.GetHeadPosition(); + + while(pos) + { + POSITION cur = pos; + + GSDepthStencil* ds = m_ds.GetNext(pos); + + if(GSUtil::HasSharedBits(BITBLTBUF.DBP, BITBLTBUF.DPSM, ds->m_TEX0.TBP0, ds->m_TEX0.PSM)) + { + if(!found && GSUtil::HasCompatibleBits(BITBLTBUF.DPSM, ds->m_TEX0.PSM)) + { + ds->m_dirty.AddTail(GSDirtyRect(BITBLTBUF.DPSM, r)); + ds->m_TEX0.TBW = BITBLTBUF.DBW; + } + else + { + m_ds.RemoveAt(cur); + delete ds; + continue; + } + } + + if(GSUtil::HasSharedBits(BITBLTBUF.DPSM, ds->m_TEX0.PSM) && BITBLTBUF.DBP < ds->m_TEX0.TBP0) + { + DWORD rowsize = BITBLTBUF.DBW * 8192; + DWORD offset = (DWORD)((ds->m_TEX0.TBP0 - BITBLTBUF.DBP) * 256); + + if(rowsize > 0 && offset % rowsize == 0) + { + int y = m_renderer->m_mem.m_psm[BITBLTBUF.DPSM].pgs.cy * offset / rowsize; + + if(r.bottom >= y) + { + // TODO: do not add this rect above too + ds->m_dirty.AddTail(GSDirtyRect(BITBLTBUF.DPSM, CRect(r.left, r.top - y, r.right, r.bottom - y))); + ds->m_TEX0.TBW = BITBLTBUF.DBW; + continue; + } + } + } + + } + } + + void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const CRect& r) + { + POSITION pos = m_rt.GetHeadPosition(); + + while(pos) + { + POSITION cur = pos; + + GSRenderTarget* rt = m_rt.GetNext(pos); + + if(GSUtil::HasSharedBits(BITBLTBUF.SBP, BITBLTBUF.SPSM, rt->m_TEX0.TBP0, rt->m_TEX0.PSM)) + { + if(GSUtil::HasCompatibleBits(BITBLTBUF.SPSM, rt->m_TEX0.PSM)) + { + rt->Read(r); + return; + } + else if(BITBLTBUF.SPSM == PSM_PSMCT32 && (rt->m_TEX0.PSM == PSM_PSMCT16 || rt->m_TEX0.PSM == PSM_PSMCT16S)) + { + // ffx-2 riku changing to her default (shoots some reflecting glass at the end), 16-bit rt read as 32-bit + + rt->Read(CRect(r.left, r.top, r.right, r.top + (r.bottom - r.top) * 2)); + return; + } + else + { + m_rt.RemoveAt(cur); + delete rt; + continue; + } + } + } +/* + // no good, ffx does a lot of readback after exiting menu, at 0x02f00 this wrongly finds rt 0x02100 (0,448 - 512,480) + + GSRenderTarget* rt2 = NULL; + int ymin = INT_MAX; + + pos = m_rt.GetHeadPosition(); + + while(pos) + { + GSRenderTarget* rt = m_rt.GetNext(pos); + + if(HasSharedBits(BITBLTBUF.SPSM, rt->m_TEX0.PSM) && BITBLTBUF.SBP > rt->m_TEX0.TBP0) + { + // ffx2 pause screen background + + DWORD rowsize = BITBLTBUF.SBW * 8192; + DWORD offset = (DWORD)((BITBLTBUF.SBP - rt->m_TEX0.TBP0) * 256); + + if(rowsize > 0 && offset % rowsize == 0) + { + int y = m_renderer->m_mem.m_psm[BITBLTBUF.SPSM].pgs.cy * offset / rowsize; + + if(y < ymin && y < 512) + { + rt2 = rt; + ymin = y; + } + } + } + } + + if(rt2) + { + rt2->Read(CRect(r.left, r.top + ymin, r.right, r.bottom + ymin)); + } + + // TODO: ds +*/ + } + + void IncAge() + { + RecycleByAge(m_tex, 2); + RecycleByAge(m_rt); + RecycleByAge(m_ds); + } +}; diff --git a/plugins/GSdx/GSTextureCache10.cpp b/plugins/GSdx/GSTextureCache10.cpp index 025478d108..68c989325f 100644 --- a/plugins/GSdx/GSTextureCache10.cpp +++ b/plugins/GSdx/GSTextureCache10.cpp @@ -1,452 +1,452 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSTextureCache10.h" - -// GSTextureCache10 - -GSTextureCache10::GSTextureCache10(GSRenderer* renderer) - : GSTextureCache(renderer) -{ -} - -// GSRenderTargetHW10 - -void GSTextureCache10::GSRenderTargetHW10::Update() -{ - __super::Update(); - - // FIXME: the union of the rects may also update wrong parts of the render target (but a lot faster :) - - CRect r = m_dirty.GetDirtyRect(m_TEX0, m_texture.GetSize()); - - m_dirty.RemoveAll(); - - if(r.IsRectEmpty()) return; - - int w = r.Width(); - int h = r.Height(); - - static BYTE* buff = (BYTE*)_aligned_malloc(1024 * 1024 * 4, 16); - static int pitch = 1024 * 4; - - GIFRegTEXA TEXA; - - TEXA.AEM = 1; - TEXA.TA0 = 0; - TEXA.TA1 = 0x80; - - GIFRegCLAMP CLAMP; - - CLAMP.WMS = 0; - CLAMP.WMT = 0; - - m_renderer->m_mem.ReadTexture(r, buff, pitch, m_TEX0, TEXA, CLAMP); - - // s->m_perfmon.Put(GSPerfMon::Unswizzle, w * h * 4); - - Texture texture; - - if(!m_renderer->m_dev.CreateTexture(texture, w, h)) - return; - - texture.Update(CRect(0, 0, w, h), buff, pitch); - - GSVector4 dr( - m_texture.m_scale.x * r.left, - m_texture.m_scale.y * r.top, - m_texture.m_scale.x * r.right, - m_texture.m_scale.y * r.bottom); - - m_renderer->m_dev.StretchRect(texture, m_texture, dr); - - m_renderer->m_dev.Recycle(texture); -} - -void GSTextureCache10::GSRenderTargetHW10::Read(CRect r) -{ - if(m_TEX0.PSM != PSM_PSMCT32 - && m_TEX0.PSM != PSM_PSMCT24 - && m_TEX0.PSM != PSM_PSMCT16 - && m_TEX0.PSM != PSM_PSMCT16S) - { - //ASSERT(0); - return; - } - - if(!m_dirty.IsEmpty()) - { - return; - } - - TRACE(_T("GSRenderTarget::Read %d,%d - %d,%d (%08x)\n"), r.left, r.top, r.right, r.bottom, m_TEX0.TBP0); - - // m_renderer->m_perfmon.Put(GSPerfMon::ReadRT, 1); - - int w = r.Width(); - int h = r.Height(); - - GSVector4 src; - - src.x = m_texture.m_scale.x * r.left / m_texture.GetWidth(); - src.y = m_texture.m_scale.y * r.top / m_texture.GetHeight(); - src.z = m_texture.m_scale.x * r.right / m_texture.GetWidth(); - src.w = m_texture.m_scale.y * r.bottom / m_texture.GetHeight(); - - DXGI_FORMAT format = m_TEX0.PSM == PSM_PSMCT16 || m_TEX0.PSM == PSM_PSMCT16S ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R8G8B8A8_UNORM; - - Texture offscreen; - - if(!m_renderer->m_dev.CopyOffscreen(m_texture, src, offscreen, w, h, format)) - return; - - BYTE* bits; - int pitch; - - if(offscreen.Map(&bits, pitch)) - { - // TODO: block level write - - DWORD bp = m_TEX0.TBP0; - DWORD bw = m_TEX0.TBW; - - GSLocalMemory::pixelAddress pa = GSLocalMemory::m_psm[m_TEX0.PSM].pa; - - if(m_TEX0.PSM == PSM_PSMCT32) - { - for(int y = r.top; y < r.bottom; y++, bits += pitch) - { - DWORD addr = pa(0, y, bp, bw); - int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7]; - - for(int x = r.left, i = 0; x < r.right; x++, i++) - { - m_renderer->m_mem.WritePixel32(addr + offset[x], ((DWORD*)bits)[i]); - } - } - } - else if(m_TEX0.PSM == PSM_PSMCT24) - { - for(int y = r.top; y < r.bottom; y++, bits += pitch) - { - DWORD addr = pa(0, y, bp, bw); - int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7]; - - for(int x = r.left, i = 0; x < r.right; x++, i++) - { - m_renderer->m_mem.WritePixel24(addr + offset[x], ((DWORD*)bits)[i]); - } - } - } - else if(m_TEX0.PSM == PSM_PSMCT16 || m_TEX0.PSM == PSM_PSMCT16S) - { - for(int y = r.top; y < r.bottom; y++, bits += pitch) - { - DWORD addr = pa(0, y, bp, bw); - int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7]; - - for(int x = r.left, i = 0; x < r.right; x++, i++) - { - m_renderer->m_mem.WritePixel16(addr + offset[x], ((WORD*)bits)[i]); - } - } - } - else - { - ASSERT(0); - } - - offscreen.Unmap(); - } - - m_renderer->m_dev.Recycle(offscreen); -} - -// GSDepthStencilHW10 - -void GSTextureCache10::GSDepthStencilHW10::Update() -{ - __super::Update(); - - // TODO -} - -// GSTextureHW10 - -bool GSTextureCache10::GSTextureHW10::Create() -{ - // m_renderer->m_perfmon.Put(GSPerfMon::WriteTexture, 1); - - m_TEX0 = m_renderer->m_context->TEX0; - m_CLAMP = m_renderer->m_context->CLAMP; - - DWORD psm = m_TEX0.PSM; - - switch(psm) - { - case PSM_PSMT8: - case PSM_PSMT8H: - case PSM_PSMT4: - case PSM_PSMT4HL: - case PSM_PSMT4HH: - psm = m_TEX0.CPSM; - break; - } - - DXGI_FORMAT format; - - switch(psm) - { - default: - TRACE(_T("Invalid TEX0.PSM/CPSM (%I64d, %I64d)\n"), m_TEX0.PSM, m_TEX0.CPSM); - case PSM_PSMCT32: - m_bpp = 32; - m_bpp2 = 0; - format = DXGI_FORMAT_R8G8B8A8_UNORM; - break; - case PSM_PSMCT24: - m_bpp = 32; - m_bpp2 = 1; - format = DXGI_FORMAT_R8G8B8A8_UNORM; - break; - case PSM_PSMCT16: - case PSM_PSMCT16S: - m_bpp = 16; - m_bpp2 = 5; - format = DXGI_FORMAT_R16_UNORM; - break; - } - - int w = 1 << m_TEX0.TW; - int h = 1 << m_TEX0.TH; - - return m_renderer->m_dev.CreateTexture(m_texture, w, h, format); -} - -bool GSTextureCache10::GSTextureHW10::Create(GSRenderTarget* rt) -{ - rt->Update(); - - // m_renderer->m_perfmon.Put(GSPerfMon::ConvertRT2T, 1); - - m_TEX0 = m_renderer->m_context->TEX0; - m_CLAMP = m_renderer->m_context->CLAMP; - m_rendered = true; - - int tw = 1 << m_TEX0.TW; - int th = 1 << m_TEX0.TH; - int tp = (int)m_TEX0.TW << 6; - - // do not round here!!! if edge becomes a black pixel and addressing mode is clamp => everything outside the clamped area turns into black (kh2 shadows) - - int w = (int)(rt->m_texture.m_scale.x * tw); - int h = (int)(rt->m_texture.m_scale.y * th); - - // pitch conversion - - if(rt->m_TEX0.TBW != m_TEX0.TBW) // && rt->m_TEX0.PSM == m_TEX0.PSM - { - // sfex3 uses this trick (bw: 10 -> 5, wraps the right side below the left) - - // ASSERT(rt->m_TEX0.TBW > m_TEX0.TBW); // otherwise scale.x need to be reduced to make the larger texture fit (TODO) - - m_renderer->m_dev.CreateRenderTarget(m_texture, rt->m_texture.GetWidth(), rt->m_texture.GetHeight()); - - int bw = 64; - int bh = m_TEX0.PSM == PSM_PSMCT32 || m_TEX0.PSM == PSM_PSMCT24 ? 32 : 64; - - int sw = (int)rt->m_TEX0.TBW << 6; - - int dw = (int)m_TEX0.TBW << 6; - int dh = 1 << m_TEX0.TH; - - if(sw != 0) - for(int dy = 0; dy < dh; dy += bh) - { - for(int dx = 0; dx < dw; dx += bw) - { - int o = dy * dw / bh + dx; - - int sx = o % sw; - int sy = o / sw; - - GSVector4 src, dst; - - src.x = rt->m_texture.m_scale.x * sx / rt->m_texture.GetWidth(); - src.y = rt->m_texture.m_scale.y * sy / rt->m_texture.GetHeight(); - src.z = rt->m_texture.m_scale.x * (sx + bw) / rt->m_texture.GetWidth(); - src.w = rt->m_texture.m_scale.y * (sy + bh) / rt->m_texture.GetHeight(); - - dst.x = rt->m_texture.m_scale.x * dx; - dst.y = rt->m_texture.m_scale.y * dy; - dst.z = rt->m_texture.m_scale.x * (dx + bw); - dst.w = rt->m_texture.m_scale.y * (dy + bh); - - m_renderer->m_dev.StretchRect(rt->m_texture, src, m_texture, dst); - - // TODO: this is quite a lot of StretchRect, do it with one Draw - } - } - } - else if(tw < tp) - { - // FIXME: timesplitters blurs the render target by blending itself over a couple of times - - if(tw == 256 && th == 128 && tp == 512 && (m_TEX0.TBP0 == 0 || m_TEX0.TBP0 == 0x00e00)) - { - return false; - } - } - - // width/height conversion - - GSVector2 scale = rt->m_texture.m_scale; - - GSVector4 dst(0, 0, w, h); - - if(w > rt->m_texture.GetWidth()) - { - scale.x = (float)rt->m_texture.GetWidth() / tw; - dst.z = (float)rt->m_texture.GetWidth() * scale.x / rt->m_texture.m_scale.x; - w = rt->m_texture.GetWidth(); - } - - if(h > rt->m_texture.GetHeight()) - { - scale.y = (float)rt->m_texture.GetHeight() / th; - dst.w = (float)rt->m_texture.GetHeight() * scale.y / rt->m_texture.m_scale.y; - h = rt->m_texture.GetHeight(); - } - - GSVector4 src(0, 0, w, h); - - Texture* st; - Texture* dt; - Texture tmp; - - if(!m_texture) - { - st = &rt->m_texture; - dt = &m_texture; - } - else - { - st = &m_texture; - dt = &tmp; - } - - m_renderer->m_dev.CreateRenderTarget(*dt, w, h); - - if(src.x == dst.x && src.y == dst.y && src.z == dst.z && src.w == dst.w) - { - D3D10_BOX box = {0, 0, 0, w, h, 1}; - - m_renderer->m_dev->CopySubresourceRegion(*dt, 0, 0, 0, 0, *st, 0, &box); - } - else - { - src.z /= st->GetWidth(); - src.w /= st->GetHeight(); - - m_renderer->m_dev.StretchRect(*st, src, *dt, dst); - } - - if(tmp) - { - m_renderer->m_dev.Recycle(m_texture); - - m_texture = tmp; - } - - m_texture.m_scale = scale; - - switch(m_TEX0.PSM) - { - case PSM_PSMCT32: - m_bpp2 = 0; - break; - case PSM_PSMCT24: - m_bpp2 = 1; - break; - case PSM_PSMCT16: - case PSM_PSMCT16S: - m_bpp2 = 2; - break; - case PSM_PSMT8H: - m_bpp2 = 3; - m_renderer->m_dev.CreateTexture(m_palette, 256, 1, m_TEX0.CPSM == PSM_PSMCT32 ? DXGI_FORMAT_R8G8B8A8_UNORM : DXGI_FORMAT_R16_UNORM); // - m_initpalette = true; - break; - case PSM_PSMT4HL: - case PSM_PSMT4HH: - ASSERT(0); // TODO - break; - } - - return true; -} - -bool GSTextureCache10::GSTextureHW10::Create(GSDepthStencil* ds) -{ - m_rendered = true; - - // TODO - - return false; -} - -void GSTextureCache10::GSTextureHW10::Update() -{ - __super::Update(); - - if(m_rendered) - { - return; - } - - CRect r; - - if(!GetDirtyRect(r)) - { - return; - } - - m_valid |= r; - - //TRACE(_T("GSTexture::Update %d,%d - %d,%d (%08x)\n"), r.left, r.top, r.right, r.bottom, m_TEX0.TBP0); - - static BYTE* bits = (BYTE*)::_aligned_malloc(1024 * 1024 * 4, 16); - int pitch = 1024 * 4; - - if(m_renderer->m_psrr) - { - m_renderer->m_mem.ReadTextureNPNC(r, bits, pitch, m_renderer->m_context->TEX0, m_renderer->m_env.TEXA, m_renderer->m_context->CLAMP); - } - else - { - m_renderer->m_mem.ReadTextureNP(r, bits, pitch, m_renderer->m_context->TEX0, m_renderer->m_env.TEXA, m_renderer->m_context->CLAMP); - } - - m_texture.Update(r, bits, pitch); - - m_renderer->m_perfmon.Put(GSPerfMon::Unswizzle, r.Width() * r.Height() * m_bpp >> 3); -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSTextureCache10.h" + +// GSTextureCache10 + +GSTextureCache10::GSTextureCache10(GSRenderer* renderer) + : GSTextureCache(renderer) +{ +} + +// GSRenderTargetHW10 + +void GSTextureCache10::GSRenderTargetHW10::Update() +{ + __super::Update(); + + // FIXME: the union of the rects may also update wrong parts of the render target (but a lot faster :) + + CRect r = m_dirty.GetDirtyRect(m_TEX0, m_texture.GetSize()); + + m_dirty.RemoveAll(); + + if(r.IsRectEmpty()) return; + + int w = r.Width(); + int h = r.Height(); + + static BYTE* buff = (BYTE*)_aligned_malloc(1024 * 1024 * 4, 16); + static int pitch = 1024 * 4; + + GIFRegTEXA TEXA; + + TEXA.AEM = 1; + TEXA.TA0 = 0; + TEXA.TA1 = 0x80; + + GIFRegCLAMP CLAMP; + + CLAMP.WMS = 0; + CLAMP.WMT = 0; + + m_renderer->m_mem.ReadTexture(r, buff, pitch, m_TEX0, TEXA, CLAMP); + + // s->m_perfmon.Put(GSPerfMon::Unswizzle, w * h * 4); + + Texture texture; + + if(!m_renderer->m_dev.CreateTexture(texture, w, h)) + return; + + texture.Update(CRect(0, 0, w, h), buff, pitch); + + GSVector4 dr( + m_texture.m_scale.x * r.left, + m_texture.m_scale.y * r.top, + m_texture.m_scale.x * r.right, + m_texture.m_scale.y * r.bottom); + + m_renderer->m_dev.StretchRect(texture, m_texture, dr); + + m_renderer->m_dev.Recycle(texture); +} + +void GSTextureCache10::GSRenderTargetHW10::Read(CRect r) +{ + if(m_TEX0.PSM != PSM_PSMCT32 + && m_TEX0.PSM != PSM_PSMCT24 + && m_TEX0.PSM != PSM_PSMCT16 + && m_TEX0.PSM != PSM_PSMCT16S) + { + //ASSERT(0); + return; + } + + if(!m_dirty.IsEmpty()) + { + return; + } + + TRACE(_T("GSRenderTarget::Read %d,%d - %d,%d (%08x)\n"), r.left, r.top, r.right, r.bottom, m_TEX0.TBP0); + + // m_renderer->m_perfmon.Put(GSPerfMon::ReadRT, 1); + + int w = r.Width(); + int h = r.Height(); + + GSVector4 src; + + src.x = m_texture.m_scale.x * r.left / m_texture.GetWidth(); + src.y = m_texture.m_scale.y * r.top / m_texture.GetHeight(); + src.z = m_texture.m_scale.x * r.right / m_texture.GetWidth(); + src.w = m_texture.m_scale.y * r.bottom / m_texture.GetHeight(); + + DXGI_FORMAT format = m_TEX0.PSM == PSM_PSMCT16 || m_TEX0.PSM == PSM_PSMCT16S ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R8G8B8A8_UNORM; + + Texture offscreen; + + if(!m_renderer->m_dev.CopyOffscreen(m_texture, src, offscreen, w, h, format)) + return; + + BYTE* bits; + int pitch; + + if(offscreen.Map(&bits, pitch)) + { + // TODO: block level write + + DWORD bp = m_TEX0.TBP0; + DWORD bw = m_TEX0.TBW; + + GSLocalMemory::pixelAddress pa = GSLocalMemory::m_psm[m_TEX0.PSM].pa; + + if(m_TEX0.PSM == PSM_PSMCT32) + { + for(int y = r.top; y < r.bottom; y++, bits += pitch) + { + DWORD addr = pa(0, y, bp, bw); + int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7]; + + for(int x = r.left, i = 0; x < r.right; x++, i++) + { + m_renderer->m_mem.WritePixel32(addr + offset[x], ((DWORD*)bits)[i]); + } + } + } + else if(m_TEX0.PSM == PSM_PSMCT24) + { + for(int y = r.top; y < r.bottom; y++, bits += pitch) + { + DWORD addr = pa(0, y, bp, bw); + int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7]; + + for(int x = r.left, i = 0; x < r.right; x++, i++) + { + m_renderer->m_mem.WritePixel24(addr + offset[x], ((DWORD*)bits)[i]); + } + } + } + else if(m_TEX0.PSM == PSM_PSMCT16 || m_TEX0.PSM == PSM_PSMCT16S) + { + for(int y = r.top; y < r.bottom; y++, bits += pitch) + { + DWORD addr = pa(0, y, bp, bw); + int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7]; + + for(int x = r.left, i = 0; x < r.right; x++, i++) + { + m_renderer->m_mem.WritePixel16(addr + offset[x], ((WORD*)bits)[i]); + } + } + } + else + { + ASSERT(0); + } + + offscreen.Unmap(); + } + + m_renderer->m_dev.Recycle(offscreen); +} + +// GSDepthStencilHW10 + +void GSTextureCache10::GSDepthStencilHW10::Update() +{ + __super::Update(); + + // TODO +} + +// GSTextureHW10 + +bool GSTextureCache10::GSTextureHW10::Create() +{ + // m_renderer->m_perfmon.Put(GSPerfMon::WriteTexture, 1); + + m_TEX0 = m_renderer->m_context->TEX0; + m_CLAMP = m_renderer->m_context->CLAMP; + + DWORD psm = m_TEX0.PSM; + + switch(psm) + { + case PSM_PSMT8: + case PSM_PSMT8H: + case PSM_PSMT4: + case PSM_PSMT4HL: + case PSM_PSMT4HH: + psm = m_TEX0.CPSM; + break; + } + + DXGI_FORMAT format; + + switch(psm) + { + default: + TRACE(_T("Invalid TEX0.PSM/CPSM (%I64d, %I64d)\n"), m_TEX0.PSM, m_TEX0.CPSM); + case PSM_PSMCT32: + m_bpp = 32; + m_bpp2 = 0; + format = DXGI_FORMAT_R8G8B8A8_UNORM; + break; + case PSM_PSMCT24: + m_bpp = 32; + m_bpp2 = 1; + format = DXGI_FORMAT_R8G8B8A8_UNORM; + break; + case PSM_PSMCT16: + case PSM_PSMCT16S: + m_bpp = 16; + m_bpp2 = 5; + format = DXGI_FORMAT_R16_UNORM; + break; + } + + int w = 1 << m_TEX0.TW; + int h = 1 << m_TEX0.TH; + + return m_renderer->m_dev.CreateTexture(m_texture, w, h, format); +} + +bool GSTextureCache10::GSTextureHW10::Create(GSRenderTarget* rt) +{ + rt->Update(); + + // m_renderer->m_perfmon.Put(GSPerfMon::ConvertRT2T, 1); + + m_TEX0 = m_renderer->m_context->TEX0; + m_CLAMP = m_renderer->m_context->CLAMP; + m_rendered = true; + + int tw = 1 << m_TEX0.TW; + int th = 1 << m_TEX0.TH; + int tp = (int)m_TEX0.TW << 6; + + // do not round here!!! if edge becomes a black pixel and addressing mode is clamp => everything outside the clamped area turns into black (kh2 shadows) + + int w = (int)(rt->m_texture.m_scale.x * tw); + int h = (int)(rt->m_texture.m_scale.y * th); + + // pitch conversion + + if(rt->m_TEX0.TBW != m_TEX0.TBW) // && rt->m_TEX0.PSM == m_TEX0.PSM + { + // sfex3 uses this trick (bw: 10 -> 5, wraps the right side below the left) + + // ASSERT(rt->m_TEX0.TBW > m_TEX0.TBW); // otherwise scale.x need to be reduced to make the larger texture fit (TODO) + + m_renderer->m_dev.CreateRenderTarget(m_texture, rt->m_texture.GetWidth(), rt->m_texture.GetHeight()); + + int bw = 64; + int bh = m_TEX0.PSM == PSM_PSMCT32 || m_TEX0.PSM == PSM_PSMCT24 ? 32 : 64; + + int sw = (int)rt->m_TEX0.TBW << 6; + + int dw = (int)m_TEX0.TBW << 6; + int dh = 1 << m_TEX0.TH; + + if(sw != 0) + for(int dy = 0; dy < dh; dy += bh) + { + for(int dx = 0; dx < dw; dx += bw) + { + int o = dy * dw / bh + dx; + + int sx = o % sw; + int sy = o / sw; + + GSVector4 src, dst; + + src.x = rt->m_texture.m_scale.x * sx / rt->m_texture.GetWidth(); + src.y = rt->m_texture.m_scale.y * sy / rt->m_texture.GetHeight(); + src.z = rt->m_texture.m_scale.x * (sx + bw) / rt->m_texture.GetWidth(); + src.w = rt->m_texture.m_scale.y * (sy + bh) / rt->m_texture.GetHeight(); + + dst.x = rt->m_texture.m_scale.x * dx; + dst.y = rt->m_texture.m_scale.y * dy; + dst.z = rt->m_texture.m_scale.x * (dx + bw); + dst.w = rt->m_texture.m_scale.y * (dy + bh); + + m_renderer->m_dev.StretchRect(rt->m_texture, src, m_texture, dst); + + // TODO: this is quite a lot of StretchRect, do it with one Draw + } + } + } + else if(tw < tp) + { + // FIXME: timesplitters blurs the render target by blending itself over a couple of times + + if(tw == 256 && th == 128 && tp == 512 && (m_TEX0.TBP0 == 0 || m_TEX0.TBP0 == 0x00e00)) + { + return false; + } + } + + // width/height conversion + + GSVector2 scale = rt->m_texture.m_scale; + + GSVector4 dst(0, 0, w, h); + + if(w > rt->m_texture.GetWidth()) + { + scale.x = (float)rt->m_texture.GetWidth() / tw; + dst.z = (float)rt->m_texture.GetWidth() * scale.x / rt->m_texture.m_scale.x; + w = rt->m_texture.GetWidth(); + } + + if(h > rt->m_texture.GetHeight()) + { + scale.y = (float)rt->m_texture.GetHeight() / th; + dst.w = (float)rt->m_texture.GetHeight() * scale.y / rt->m_texture.m_scale.y; + h = rt->m_texture.GetHeight(); + } + + GSVector4 src(0, 0, w, h); + + Texture* st; + Texture* dt; + Texture tmp; + + if(!m_texture) + { + st = &rt->m_texture; + dt = &m_texture; + } + else + { + st = &m_texture; + dt = &tmp; + } + + m_renderer->m_dev.CreateRenderTarget(*dt, w, h); + + if(src.x == dst.x && src.y == dst.y && src.z == dst.z && src.w == dst.w) + { + D3D10_BOX box = {0, 0, 0, w, h, 1}; + + m_renderer->m_dev->CopySubresourceRegion(*dt, 0, 0, 0, 0, *st, 0, &box); + } + else + { + src.z /= st->GetWidth(); + src.w /= st->GetHeight(); + + m_renderer->m_dev.StretchRect(*st, src, *dt, dst); + } + + if(tmp) + { + m_renderer->m_dev.Recycle(m_texture); + + m_texture = tmp; + } + + m_texture.m_scale = scale; + + switch(m_TEX0.PSM) + { + case PSM_PSMCT32: + m_bpp2 = 0; + break; + case PSM_PSMCT24: + m_bpp2 = 1; + break; + case PSM_PSMCT16: + case PSM_PSMCT16S: + m_bpp2 = 2; + break; + case PSM_PSMT8H: + m_bpp2 = 3; + m_renderer->m_dev.CreateTexture(m_palette, 256, 1, m_TEX0.CPSM == PSM_PSMCT32 ? DXGI_FORMAT_R8G8B8A8_UNORM : DXGI_FORMAT_R16_UNORM); // + m_initpalette = true; + break; + case PSM_PSMT4HL: + case PSM_PSMT4HH: + ASSERT(0); // TODO + break; + } + + return true; +} + +bool GSTextureCache10::GSTextureHW10::Create(GSDepthStencil* ds) +{ + m_rendered = true; + + // TODO + + return false; +} + +void GSTextureCache10::GSTextureHW10::Update() +{ + __super::Update(); + + if(m_rendered) + { + return; + } + + CRect r; + + if(!GetDirtyRect(r)) + { + return; + } + + m_valid |= r; + + //TRACE(_T("GSTexture::Update %d,%d - %d,%d (%08x)\n"), r.left, r.top, r.right, r.bottom, m_TEX0.TBP0); + + static BYTE* bits = (BYTE*)::_aligned_malloc(1024 * 1024 * 4, 16); + int pitch = 1024 * 4; + + if(m_renderer->m_psrr) + { + m_renderer->m_mem.ReadTextureNPNC(r, bits, pitch, m_renderer->m_context->TEX0, m_renderer->m_env.TEXA, m_renderer->m_context->CLAMP); + } + else + { + m_renderer->m_mem.ReadTextureNP(r, bits, pitch, m_renderer->m_context->TEX0, m_renderer->m_env.TEXA, m_renderer->m_context->CLAMP); + } + + m_texture.Update(r, bits, pitch); + + m_renderer->m_perfmon.Put(GSPerfMon::Unswizzle, r.Width() * r.Height() * m_bpp >> 3); +} diff --git a/plugins/GSdx/GSTextureCache10.h b/plugins/GSdx/GSTextureCache10.h index f236263516..48b304325a 100644 --- a/plugins/GSdx/GSTextureCache10.h +++ b/plugins/GSdx/GSTextureCache10.h @@ -1,66 +1,66 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSTextureCache.h" -#include "GSDevice10.h" - -class GSTextureCache10 : public GSTextureCache -{ - typedef GSDevice10::Texture Texture; - - class GSRenderTargetHW10 : public GSRenderTarget - { - public: - explicit GSRenderTargetHW10(GSRenderer* renderer) : GSRenderTarget(renderer) {} - - void Update(); - void Read(CRect r); - }; - - class GSDepthStencilHW10 : public GSDepthStencil - { - public: - explicit GSDepthStencilHW10(GSRenderer* renderer) : GSDepthStencil(renderer) {} - - void Update(); - }; - - class GSTextureHW10 : public GSTexture - { - public: - explicit GSTextureHW10(GSRenderer* renderer) : GSTexture(renderer) {} - - bool Create(); - bool Create(GSRenderTarget* rt); - bool Create(GSDepthStencil* ds); - void Update(); - }; - -protected: - GSRenderTarget* CreateRenderTarget() {return new GSRenderTargetHW10(m_renderer);} - GSDepthStencil* CreateDepthStencil() {return new GSDepthStencilHW10(m_renderer);} - GSTexture* CreateTexture() {return new GSTextureHW10(m_renderer);} - -public: - GSTextureCache10(GSRenderer* renderer); -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSTextureCache.h" +#include "GSDevice10.h" + +class GSTextureCache10 : public GSTextureCache +{ + typedef GSDevice10::Texture Texture; + + class GSRenderTargetHW10 : public GSRenderTarget + { + public: + explicit GSRenderTargetHW10(GSRenderer* renderer) : GSRenderTarget(renderer) {} + + void Update(); + void Read(CRect r); + }; + + class GSDepthStencilHW10 : public GSDepthStencil + { + public: + explicit GSDepthStencilHW10(GSRenderer* renderer) : GSDepthStencil(renderer) {} + + void Update(); + }; + + class GSTextureHW10 : public GSTexture + { + public: + explicit GSTextureHW10(GSRenderer* renderer) : GSTexture(renderer) {} + + bool Create(); + bool Create(GSRenderTarget* rt); + bool Create(GSDepthStencil* ds); + void Update(); + }; + +protected: + GSRenderTarget* CreateRenderTarget() {return new GSRenderTargetHW10(m_renderer);} + GSDepthStencil* CreateDepthStencil() {return new GSDepthStencilHW10(m_renderer);} + GSTexture* CreateTexture() {return new GSTextureHW10(m_renderer);} + +public: + GSTextureCache10(GSRenderer* renderer); +}; diff --git a/plugins/GSdx/GSTextureCache9.cpp b/plugins/GSdx/GSTextureCache9.cpp index 073462926e..31fe12f84a 100644 --- a/plugins/GSdx/GSTextureCache9.cpp +++ b/plugins/GSdx/GSTextureCache9.cpp @@ -1,453 +1,453 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSTextureCache9.h" - -// GSTextureCache9 - -GSTextureCache9::GSTextureCache9(GSRenderer* renderer) - : GSTextureCache(renderer) -{ -} - -// GSRenderTarget9 - -void GSTextureCache9::GSRenderTarget9::Update() -{ - __super::Update(); - - // FIXME: the union of the rects may also update wrong parts of the render target (but a lot faster :) - - CRect r = m_dirty.GetDirtyRect(m_TEX0, m_texture.GetSize()); - - m_dirty.RemoveAll(); - - if(r.IsRectEmpty()) return; - - int w = r.Width(); - int h = r.Height(); - - Texture texture; - - if(!m_renderer->m_dev.CreateTexture(texture, w, h)) - return; - - BYTE* bits; - int pitch; - - if(texture.Map(&bits, pitch)) - { - GIFRegTEXA TEXA; - - TEXA.AEM = 1; - TEXA.TA0 = 0; - TEXA.TA1 = 0x80; - - GIFRegCLAMP CLAMP; - - CLAMP.WMS = 0; - CLAMP.WMT = 0; - - m_renderer->m_mem.ReadTexture(r, bits, pitch, m_TEX0, TEXA, CLAMP); - - texture.Unmap(); - - // m_renderer->m_perfmon.Put(GSPerfMon::Unswizzle, r.Width() * r.Height() * 4); - - GSVector4 dr( - m_texture.m_scale.x * r.left, - m_texture.m_scale.y * r.top, - m_texture.m_scale.x * r.right, - m_texture.m_scale.y * r.bottom); - - m_renderer->m_dev.StretchRect(texture, m_texture, dr); - } - - m_renderer->m_dev.Recycle(texture); -} - -void GSTextureCache9::GSRenderTarget9::Read(CRect r) -{ - if(m_TEX0.PSM != PSM_PSMCT32 - && m_TEX0.PSM != PSM_PSMCT24 - && m_TEX0.PSM != PSM_PSMCT16 - && m_TEX0.PSM != PSM_PSMCT16S) - { - //ASSERT(0); - return; - } - - if(!m_dirty.IsEmpty()) - { - return; - } - - TRACE(_T("GSRenderTarget::Read %d,%d - %d,%d (%08x)\n"), r.left, r.top, r.right, r.bottom, m_TEX0.TBP0); - - // m_renderer->m_perfmon.Put(GSPerfMon::ReadRT, 1); - - int w = r.Width(); - int h = r.Height(); - - GSVector4 src; - - src.x = m_texture.m_scale.x * r.left / m_texture.GetWidth(); - src.y = m_texture.m_scale.y * r.top / m_texture.GetHeight(); - src.z = m_texture.m_scale.x * r.right / m_texture.GetWidth(); - src.w = m_texture.m_scale.y * r.bottom / m_texture.GetHeight(); - - Texture offscreen; - - if(!m_renderer->m_dev.CopyOffscreen(m_texture, src, offscreen, w, h)) - return; - - BYTE* bits; - int pitch; - - if(offscreen.Map(&bits, pitch)) - { - // TODO: block level write - - DWORD bp = m_TEX0.TBP0; - DWORD bw = m_TEX0.TBW; - - GSLocalMemory::pixelAddress pa = GSLocalMemory::m_psm[m_TEX0.PSM].pa; - - if(m_TEX0.PSM == PSM_PSMCT32) - { - for(int y = r.top; y < r.bottom; y++, bits += pitch) - { - DWORD addr = pa(0, y, bp, bw); - int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7]; - - for(int x = r.left, i = 0; x < r.right; x++, i++) - { - m_renderer->m_mem.WritePixel32(addr + offset[x], ((DWORD*)bits)[i]); - } - } - } - else if(m_TEX0.PSM == PSM_PSMCT24) - { - for(int y = r.top; y < r.bottom; y++, bits += pitch) - { - DWORD addr = pa(0, y, bp, bw); - int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7]; - - for(int x = r.left, i = 0; x < r.right; x++, i++) - { - m_renderer->m_mem.WritePixel24(addr + offset[x], ((DWORD*)bits)[i]); - } - } - } - else if(m_TEX0.PSM == PSM_PSMCT16 || m_TEX0.PSM == PSM_PSMCT16S) - { - for(int y = r.top; y < r.bottom; y++, bits += pitch) - { - DWORD addr = pa(0, y, bp, bw); - int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7]; - - for(int x = r.left, i = 0; x < r.right; x++, i++) - { - m_renderer->m_mem.WriteFrame16(addr + offset[x], ((DWORD*)bits)[i]); - } - } - } - else - { - ASSERT(0); - } - - offscreen.Unmap(); - } - - m_renderer->m_dev.Recycle(offscreen); -} - -// GSDepthStencil9 - -void GSTextureCache9::GSDepthStencil9::Update() -{ - __super::Update(); - - // TODO -} - -// GSTexture9 - -bool GSTextureCache9::GSTexture9::Create() -{ - // m_renderer->m_perfmon.Put(GSPerfMon::WriteTexture, 1); - - m_TEX0 = m_renderer->m_context->TEX0; - m_CLAMP = m_renderer->m_context->CLAMP; - - DWORD psm = m_TEX0.PSM; - - switch(psm) - { - case PSM_PSMT8: - case PSM_PSMT8H: - case PSM_PSMT4: - case PSM_PSMT4HL: - case PSM_PSMT4HH: - psm = m_TEX0.CPSM; - break; - } - - D3DFORMAT format; - - switch(psm) - { - default: - TRACE(_T("Invalid TEX0.PSM/CPSM (%I64d, %I64d)\n"), m_TEX0.PSM, m_TEX0.CPSM); - case PSM_PSMCT32: - m_bpp = 32; - m_bpp2 = 0; - format = D3DFMT_A8R8G8B8; - break; - case PSM_PSMCT24: - m_bpp = 32; - m_bpp2 = 1; - format = D3DFMT_A8R8G8B8; - break; - case PSM_PSMCT16: - case PSM_PSMCT16S: - m_bpp = 16; - m_bpp2 = 2; - format = D3DFMT_A1R5G5B5; - break; - } - - int w = 1 << m_TEX0.TW; - int h = 1 << m_TEX0.TH; - - return m_renderer->m_dev.CreateTexture(m_texture, w, h, format); -} - -bool GSTextureCache9::GSTexture9::Create(GSRenderTarget* rt) -{ - rt->Update(); - - // m_renderer->m_perfmon.Put(GSPerfMon::ConvertRT2T, 1); - - m_TEX0 = m_renderer->m_context->TEX0; - m_CLAMP = m_renderer->m_context->CLAMP; - m_rendered = true; - - int tw = 1 << m_TEX0.TW; - int th = 1 << m_TEX0.TH; - int tp = (int)m_TEX0.TW << 6; - - // do not round here!!! if edge becomes a black pixel and addressing mode is clamp => everything outside the clamped area turns into black (kh2 shadows) - - int w = (int)(rt->m_texture.m_scale.x * tw); - int h = (int)(rt->m_texture.m_scale.y * th); - - // pitch conversion - - if(rt->m_TEX0.TBW != m_TEX0.TBW) // && rt->m_TEX0.PSM == m_TEX0.PSM - { - // sfex3 uses this trick (bw: 10 -> 5, wraps the right side below the left) - - // ASSERT(rt->m_TEX0.TBW > m_TEX0.TBW); // otherwise scale.x need to be reduced to make the larger texture fit (TODO) - - m_renderer->m_dev.CreateRenderTarget(m_texture, rt->m_texture.GetWidth(), rt->m_texture.GetHeight()); - - int bw = 64; - int bh = m_TEX0.PSM == PSM_PSMCT32 || m_TEX0.PSM == PSM_PSMCT24 ? 32 : 64; - - int sw = (int)rt->m_TEX0.TBW << 6; - - int dw = (int)m_TEX0.TBW << 6; - int dh = 1 << m_TEX0.TH; - - for(int dy = 0; dy < dh; dy += bh) - { - for(int dx = 0; dx < dw; dx += bw) - { - int o = dy * dw / bh + dx; - - int sx = o % sw; - int sy = o / sw; - - GSVector4 src, dst; - - src.x = rt->m_texture.m_scale.x * sx / rt->m_texture.GetWidth(); - src.y = rt->m_texture.m_scale.y * sy / rt->m_texture.GetHeight(); - src.z = rt->m_texture.m_scale.x * (sx + bw) / rt->m_texture.GetWidth(); - src.w = rt->m_texture.m_scale.y * (sy + bh) / rt->m_texture.GetHeight(); - - dst.x = rt->m_texture.m_scale.x * dx; - dst.y = rt->m_texture.m_scale.y * dy; - dst.z = rt->m_texture.m_scale.x * (dx + bw); - dst.w = rt->m_texture.m_scale.y * (dy + bh); - - m_renderer->m_dev.StretchRect(rt->m_texture, src, m_texture, dst); - - // TODO: this is quite a lot of StretchRect, do it with one Draw - } - } - } - else if(tw < tp) - { - // FIXME: timesplitters blurs the render target by blending itself over a couple of times - - if(tw == 256 && th == 128 && tp == 512 && (m_TEX0.TBP0 == 0 || m_TEX0.TBP0 == 0x00e00)) - { - return false; - } - } - - // width/height conversion - - GSVector2 scale = rt->m_texture.m_scale; - - GSVector4 dst(0, 0, w, h); - - if(w > rt->m_texture.GetWidth()) - { - scale.x = (float)rt->m_texture.GetWidth() / tw; - dst.z = (float)rt->m_texture.GetWidth() * scale.x / rt->m_texture.m_scale.x; - w = rt->m_texture.GetWidth(); - } - - if(h > rt->m_texture.GetHeight()) - { - scale.y = (float)rt->m_texture.GetHeight() / th; - dst.w = (float)rt->m_texture.GetHeight() * scale.y / rt->m_texture.m_scale.y; - h = rt->m_texture.GetHeight(); - } - - GSVector4 src(0, 0, w, h); - - Texture* st; - Texture* dt; - Texture tmp; - - if(!m_texture) - { - st = &rt->m_texture; - dt = &m_texture; - } - else - { - st = &m_texture; - dt = &tmp; - } - - m_renderer->m_dev.CreateRenderTarget(*dt, w, h); - - if(src.x == dst.x && src.y == dst.y && src.z == dst.z && src.w == dst.w) - { - CRect r(0, 0, w, h); - - m_renderer->m_dev->StretchRect(*st, r, *dt, r, D3DTEXF_POINT); - } - else - { - src.z /= st->GetWidth(); - src.w /= st->GetHeight(); - - m_renderer->m_dev.StretchRect(*st, src, *dt, dst); - } - - if(tmp) - { - m_renderer->m_dev.Recycle(m_texture); - - m_texture = tmp; - } - - m_texture.m_scale = scale; - - switch(m_TEX0.PSM) - { - case PSM_PSMCT32: - m_bpp2 = 0; - break; - case PSM_PSMCT24: - m_bpp2 = 1; - break; - case PSM_PSMCT16: - case PSM_PSMCT16S: - m_bpp2 = 2; - break; - case PSM_PSMT8H: - m_bpp2 = 3; - m_renderer->m_dev.CreateTexture(m_palette, 256, 1, m_TEX0.CPSM == PSM_PSMCT32 ? D3DFMT_A8R8G8B8 : D3DFMT_A1R5G5B5); - m_initpalette = true; - break; - case PSM_PSMT4HL: - case PSM_PSMT4HH: - ASSERT(0); // TODO - break; - } - - return true; -} - -bool GSTextureCache9::GSTexture9::Create(GSDepthStencil* ds) -{ - m_rendered = true; - - // TODO - - return false; -} - -void GSTextureCache9::GSTexture9::Update() -{ - __super::Update(); - - if(m_rendered) - { - return; - } - - CRect r; - - if(!GetDirtyRect(r)) - { - return; - } - - m_valid |= r; - - BYTE* bits; - int pitch; - - if(m_texture.Map(&bits, pitch, &r)) - { - if(m_renderer->m_psrr) - { - m_renderer->m_mem.ReadTextureNPNC(r, bits, pitch, m_renderer->m_context->TEX0, m_renderer->m_env.TEXA, m_renderer->m_context->CLAMP); - } - else - { - m_renderer->m_mem.ReadTextureNP(r, bits, pitch, m_renderer->m_context->TEX0, m_renderer->m_env.TEXA, m_renderer->m_context->CLAMP); - } - - m_texture.Unmap(); - } - - m_renderer->m_perfmon.Put(GSPerfMon::Unswizzle, r.Width() * r.Height() * m_bpp >> 3); -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSTextureCache9.h" + +// GSTextureCache9 + +GSTextureCache9::GSTextureCache9(GSRenderer* renderer) + : GSTextureCache(renderer) +{ +} + +// GSRenderTarget9 + +void GSTextureCache9::GSRenderTarget9::Update() +{ + __super::Update(); + + // FIXME: the union of the rects may also update wrong parts of the render target (but a lot faster :) + + CRect r = m_dirty.GetDirtyRect(m_TEX0, m_texture.GetSize()); + + m_dirty.RemoveAll(); + + if(r.IsRectEmpty()) return; + + int w = r.Width(); + int h = r.Height(); + + Texture texture; + + if(!m_renderer->m_dev.CreateTexture(texture, w, h)) + return; + + BYTE* bits; + int pitch; + + if(texture.Map(&bits, pitch)) + { + GIFRegTEXA TEXA; + + TEXA.AEM = 1; + TEXA.TA0 = 0; + TEXA.TA1 = 0x80; + + GIFRegCLAMP CLAMP; + + CLAMP.WMS = 0; + CLAMP.WMT = 0; + + m_renderer->m_mem.ReadTexture(r, bits, pitch, m_TEX0, TEXA, CLAMP); + + texture.Unmap(); + + // m_renderer->m_perfmon.Put(GSPerfMon::Unswizzle, r.Width() * r.Height() * 4); + + GSVector4 dr( + m_texture.m_scale.x * r.left, + m_texture.m_scale.y * r.top, + m_texture.m_scale.x * r.right, + m_texture.m_scale.y * r.bottom); + + m_renderer->m_dev.StretchRect(texture, m_texture, dr); + } + + m_renderer->m_dev.Recycle(texture); +} + +void GSTextureCache9::GSRenderTarget9::Read(CRect r) +{ + if(m_TEX0.PSM != PSM_PSMCT32 + && m_TEX0.PSM != PSM_PSMCT24 + && m_TEX0.PSM != PSM_PSMCT16 + && m_TEX0.PSM != PSM_PSMCT16S) + { + //ASSERT(0); + return; + } + + if(!m_dirty.IsEmpty()) + { + return; + } + + TRACE(_T("GSRenderTarget::Read %d,%d - %d,%d (%08x)\n"), r.left, r.top, r.right, r.bottom, m_TEX0.TBP0); + + // m_renderer->m_perfmon.Put(GSPerfMon::ReadRT, 1); + + int w = r.Width(); + int h = r.Height(); + + GSVector4 src; + + src.x = m_texture.m_scale.x * r.left / m_texture.GetWidth(); + src.y = m_texture.m_scale.y * r.top / m_texture.GetHeight(); + src.z = m_texture.m_scale.x * r.right / m_texture.GetWidth(); + src.w = m_texture.m_scale.y * r.bottom / m_texture.GetHeight(); + + Texture offscreen; + + if(!m_renderer->m_dev.CopyOffscreen(m_texture, src, offscreen, w, h)) + return; + + BYTE* bits; + int pitch; + + if(offscreen.Map(&bits, pitch)) + { + // TODO: block level write + + DWORD bp = m_TEX0.TBP0; + DWORD bw = m_TEX0.TBW; + + GSLocalMemory::pixelAddress pa = GSLocalMemory::m_psm[m_TEX0.PSM].pa; + + if(m_TEX0.PSM == PSM_PSMCT32) + { + for(int y = r.top; y < r.bottom; y++, bits += pitch) + { + DWORD addr = pa(0, y, bp, bw); + int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7]; + + for(int x = r.left, i = 0; x < r.right; x++, i++) + { + m_renderer->m_mem.WritePixel32(addr + offset[x], ((DWORD*)bits)[i]); + } + } + } + else if(m_TEX0.PSM == PSM_PSMCT24) + { + for(int y = r.top; y < r.bottom; y++, bits += pitch) + { + DWORD addr = pa(0, y, bp, bw); + int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7]; + + for(int x = r.left, i = 0; x < r.right; x++, i++) + { + m_renderer->m_mem.WritePixel24(addr + offset[x], ((DWORD*)bits)[i]); + } + } + } + else if(m_TEX0.PSM == PSM_PSMCT16 || m_TEX0.PSM == PSM_PSMCT16S) + { + for(int y = r.top; y < r.bottom; y++, bits += pitch) + { + DWORD addr = pa(0, y, bp, bw); + int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7]; + + for(int x = r.left, i = 0; x < r.right; x++, i++) + { + m_renderer->m_mem.WriteFrame16(addr + offset[x], ((DWORD*)bits)[i]); + } + } + } + else + { + ASSERT(0); + } + + offscreen.Unmap(); + } + + m_renderer->m_dev.Recycle(offscreen); +} + +// GSDepthStencil9 + +void GSTextureCache9::GSDepthStencil9::Update() +{ + __super::Update(); + + // TODO +} + +// GSTexture9 + +bool GSTextureCache9::GSTexture9::Create() +{ + // m_renderer->m_perfmon.Put(GSPerfMon::WriteTexture, 1); + + m_TEX0 = m_renderer->m_context->TEX0; + m_CLAMP = m_renderer->m_context->CLAMP; + + DWORD psm = m_TEX0.PSM; + + switch(psm) + { + case PSM_PSMT8: + case PSM_PSMT8H: + case PSM_PSMT4: + case PSM_PSMT4HL: + case PSM_PSMT4HH: + psm = m_TEX0.CPSM; + break; + } + + D3DFORMAT format; + + switch(psm) + { + default: + TRACE(_T("Invalid TEX0.PSM/CPSM (%I64d, %I64d)\n"), m_TEX0.PSM, m_TEX0.CPSM); + case PSM_PSMCT32: + m_bpp = 32; + m_bpp2 = 0; + format = D3DFMT_A8R8G8B8; + break; + case PSM_PSMCT24: + m_bpp = 32; + m_bpp2 = 1; + format = D3DFMT_A8R8G8B8; + break; + case PSM_PSMCT16: + case PSM_PSMCT16S: + m_bpp = 16; + m_bpp2 = 2; + format = D3DFMT_A1R5G5B5; + break; + } + + int w = 1 << m_TEX0.TW; + int h = 1 << m_TEX0.TH; + + return m_renderer->m_dev.CreateTexture(m_texture, w, h, format); +} + +bool GSTextureCache9::GSTexture9::Create(GSRenderTarget* rt) +{ + rt->Update(); + + // m_renderer->m_perfmon.Put(GSPerfMon::ConvertRT2T, 1); + + m_TEX0 = m_renderer->m_context->TEX0; + m_CLAMP = m_renderer->m_context->CLAMP; + m_rendered = true; + + int tw = 1 << m_TEX0.TW; + int th = 1 << m_TEX0.TH; + int tp = (int)m_TEX0.TW << 6; + + // do not round here!!! if edge becomes a black pixel and addressing mode is clamp => everything outside the clamped area turns into black (kh2 shadows) + + int w = (int)(rt->m_texture.m_scale.x * tw); + int h = (int)(rt->m_texture.m_scale.y * th); + + // pitch conversion + + if(rt->m_TEX0.TBW != m_TEX0.TBW) // && rt->m_TEX0.PSM == m_TEX0.PSM + { + // sfex3 uses this trick (bw: 10 -> 5, wraps the right side below the left) + + // ASSERT(rt->m_TEX0.TBW > m_TEX0.TBW); // otherwise scale.x need to be reduced to make the larger texture fit (TODO) + + m_renderer->m_dev.CreateRenderTarget(m_texture, rt->m_texture.GetWidth(), rt->m_texture.GetHeight()); + + int bw = 64; + int bh = m_TEX0.PSM == PSM_PSMCT32 || m_TEX0.PSM == PSM_PSMCT24 ? 32 : 64; + + int sw = (int)rt->m_TEX0.TBW << 6; + + int dw = (int)m_TEX0.TBW << 6; + int dh = 1 << m_TEX0.TH; + + for(int dy = 0; dy < dh; dy += bh) + { + for(int dx = 0; dx < dw; dx += bw) + { + int o = dy * dw / bh + dx; + + int sx = o % sw; + int sy = o / sw; + + GSVector4 src, dst; + + src.x = rt->m_texture.m_scale.x * sx / rt->m_texture.GetWidth(); + src.y = rt->m_texture.m_scale.y * sy / rt->m_texture.GetHeight(); + src.z = rt->m_texture.m_scale.x * (sx + bw) / rt->m_texture.GetWidth(); + src.w = rt->m_texture.m_scale.y * (sy + bh) / rt->m_texture.GetHeight(); + + dst.x = rt->m_texture.m_scale.x * dx; + dst.y = rt->m_texture.m_scale.y * dy; + dst.z = rt->m_texture.m_scale.x * (dx + bw); + dst.w = rt->m_texture.m_scale.y * (dy + bh); + + m_renderer->m_dev.StretchRect(rt->m_texture, src, m_texture, dst); + + // TODO: this is quite a lot of StretchRect, do it with one Draw + } + } + } + else if(tw < tp) + { + // FIXME: timesplitters blurs the render target by blending itself over a couple of times + + if(tw == 256 && th == 128 && tp == 512 && (m_TEX0.TBP0 == 0 || m_TEX0.TBP0 == 0x00e00)) + { + return false; + } + } + + // width/height conversion + + GSVector2 scale = rt->m_texture.m_scale; + + GSVector4 dst(0, 0, w, h); + + if(w > rt->m_texture.GetWidth()) + { + scale.x = (float)rt->m_texture.GetWidth() / tw; + dst.z = (float)rt->m_texture.GetWidth() * scale.x / rt->m_texture.m_scale.x; + w = rt->m_texture.GetWidth(); + } + + if(h > rt->m_texture.GetHeight()) + { + scale.y = (float)rt->m_texture.GetHeight() / th; + dst.w = (float)rt->m_texture.GetHeight() * scale.y / rt->m_texture.m_scale.y; + h = rt->m_texture.GetHeight(); + } + + GSVector4 src(0, 0, w, h); + + Texture* st; + Texture* dt; + Texture tmp; + + if(!m_texture) + { + st = &rt->m_texture; + dt = &m_texture; + } + else + { + st = &m_texture; + dt = &tmp; + } + + m_renderer->m_dev.CreateRenderTarget(*dt, w, h); + + if(src.x == dst.x && src.y == dst.y && src.z == dst.z && src.w == dst.w) + { + CRect r(0, 0, w, h); + + m_renderer->m_dev->StretchRect(*st, r, *dt, r, D3DTEXF_POINT); + } + else + { + src.z /= st->GetWidth(); + src.w /= st->GetHeight(); + + m_renderer->m_dev.StretchRect(*st, src, *dt, dst); + } + + if(tmp) + { + m_renderer->m_dev.Recycle(m_texture); + + m_texture = tmp; + } + + m_texture.m_scale = scale; + + switch(m_TEX0.PSM) + { + case PSM_PSMCT32: + m_bpp2 = 0; + break; + case PSM_PSMCT24: + m_bpp2 = 1; + break; + case PSM_PSMCT16: + case PSM_PSMCT16S: + m_bpp2 = 2; + break; + case PSM_PSMT8H: + m_bpp2 = 3; + m_renderer->m_dev.CreateTexture(m_palette, 256, 1, m_TEX0.CPSM == PSM_PSMCT32 ? D3DFMT_A8R8G8B8 : D3DFMT_A1R5G5B5); + m_initpalette = true; + break; + case PSM_PSMT4HL: + case PSM_PSMT4HH: + ASSERT(0); // TODO + break; + } + + return true; +} + +bool GSTextureCache9::GSTexture9::Create(GSDepthStencil* ds) +{ + m_rendered = true; + + // TODO + + return false; +} + +void GSTextureCache9::GSTexture9::Update() +{ + __super::Update(); + + if(m_rendered) + { + return; + } + + CRect r; + + if(!GetDirtyRect(r)) + { + return; + } + + m_valid |= r; + + BYTE* bits; + int pitch; + + if(m_texture.Map(&bits, pitch, &r)) + { + if(m_renderer->m_psrr) + { + m_renderer->m_mem.ReadTextureNPNC(r, bits, pitch, m_renderer->m_context->TEX0, m_renderer->m_env.TEXA, m_renderer->m_context->CLAMP); + } + else + { + m_renderer->m_mem.ReadTextureNP(r, bits, pitch, m_renderer->m_context->TEX0, m_renderer->m_env.TEXA, m_renderer->m_context->CLAMP); + } + + m_texture.Unmap(); + } + + m_renderer->m_perfmon.Put(GSPerfMon::Unswizzle, r.Width() * r.Height() * m_bpp >> 3); +} diff --git a/plugins/GSdx/GSTextureCache9.h b/plugins/GSdx/GSTextureCache9.h index 5ac293fd55..e0f73ec01a 100644 --- a/plugins/GSdx/GSTextureCache9.h +++ b/plugins/GSdx/GSTextureCache9.h @@ -1,66 +1,66 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSTextureCache.h" -#include "GSDevice9.h" - -class GSTextureCache9 : public GSTextureCache -{ - typedef GSDevice9::Texture Texture; - - class GSRenderTarget9 : public GSRenderTarget - { - public: - explicit GSRenderTarget9(GSRenderer* renderer) : GSRenderTarget(renderer) {} - - void Update(); - void Read(CRect r); - }; - - class GSDepthStencil9 : public GSDepthStencil - { - public: - explicit GSDepthStencil9(GSRenderer* renderer) : GSDepthStencil(renderer) {} - - void Update(); - }; - - class GSTexture9 : public GSTexture - { - public: - explicit GSTexture9(GSRenderer* renderer) : GSTexture(renderer) {} - - bool Create(); - bool Create(GSRenderTarget* rt); - bool Create(GSDepthStencil* ds); - void Update(); - }; - -protected: - GSRenderTarget* CreateRenderTarget() {return new GSRenderTarget9(m_renderer);} - GSDepthStencil* CreateDepthStencil() {return new GSDepthStencil9(m_renderer);} - GSTexture* CreateTexture() {return new GSTexture9(m_renderer);} - -public: - GSTextureCache9(GSRenderer* renderer); +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSTextureCache.h" +#include "GSDevice9.h" + +class GSTextureCache9 : public GSTextureCache +{ + typedef GSDevice9::Texture Texture; + + class GSRenderTarget9 : public GSRenderTarget + { + public: + explicit GSRenderTarget9(GSRenderer* renderer) : GSRenderTarget(renderer) {} + + void Update(); + void Read(CRect r); + }; + + class GSDepthStencil9 : public GSDepthStencil + { + public: + explicit GSDepthStencil9(GSRenderer* renderer) : GSDepthStencil(renderer) {} + + void Update(); + }; + + class GSTexture9 : public GSTexture + { + public: + explicit GSTexture9(GSRenderer* renderer) : GSTexture(renderer) {} + + bool Create(); + bool Create(GSRenderTarget* rt); + bool Create(GSDepthStencil* ds); + void Update(); + }; + +protected: + GSRenderTarget* CreateRenderTarget() {return new GSRenderTarget9(m_renderer);} + GSDepthStencil* CreateDepthStencil() {return new GSDepthStencil9(m_renderer);} + GSTexture* CreateTexture() {return new GSTexture9(m_renderer);} + +public: + GSTextureCache9(GSRenderer* renderer); }; \ No newline at end of file diff --git a/plugins/GSdx/GSTextureCacheSW.cpp b/plugins/GSdx/GSTextureCacheSW.cpp index ab230937c7..e1b6e66aa2 100644 --- a/plugins/GSdx/GSTextureCacheSW.cpp +++ b/plugins/GSdx/GSTextureCacheSW.cpp @@ -1,376 +1,376 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSTextureCacheSW.h" - -// static FILE* m_log = NULL; - -GSTextureCacheSW::GSTextureCacheSW(GSState* state) - : m_state(state) -{ - // m_log = _tfopen(_T("c:\\log.txt"), _T("w")); -} - -GSTextureCacheSW::~GSTextureCacheSW() -{ - // fclose(m_log); - - RemoveAll(); -} - -const GSTextureCacheSW::GSTexture* GSTextureCacheSW::Lookup(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const CRect* r) -{ - GSLocalMemory& mem = m_state->m_mem; - - const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[TEX0.PSM]; - - const CAtlList& t2p = m_p2t[TEX0.TBP0 >> 5]; - - // fprintf(m_log, "lu %05x %d %d (%d) ", TEX0.TBP0, TEX0.TBW, TEX0.PSM, t2p.GetCount()); - - // if(r) fprintf(m_log, "(%d %d %d %d) ", r->left, r->top, r->right, r->bottom); - - GSTexture* t = NULL; - - POSITION pos = t2p.GetHeadPosition(); - - while(pos) - { - GSTexture* t2 = t2p.GetNext(pos)->t; - - // if(t2->m_TEX0.TBP0 != TEX0.TBP0 || t2->m_TEX0.TBW != TEX0.TBW || t2->m_TEX0.PSM != TEX0.PSM || t2->m_TEX0.TW != TEX0.TW || t2->m_TEX0.TH != TEX0.TH) - if(((t2->m_TEX0.ai32[0] ^ TEX0.ai32[0]) | ((t2->m_TEX0.ai32[1] ^ TEX0.ai32[1]) & 3)) != 0) - { - continue; - } - - if((psm.trbpp == 16 || psm.trbpp == 24) && (t2->m_TEX0.TCC != TEX0.TCC || TEX0.TCC == 1 && !(t2->m_TEXA == (GSVector4i)TEXA).alltrue())) - { - continue; - } - - // fprintf(m_log, "cache hit\n"); - - t = t2; - - t->m_age = 0; - - break; - } - - if(t == NULL) - { - // fprintf(m_log, "cache miss\n"); - - t = new GSTexture(m_state); - - t->m_pos = m_textures.AddTail(t); - - int tw = 1 << TEX0.TW; - int th = 1 << TEX0.TH; - - DWORD bp = TEX0.TBP0; - DWORD bw = TEX0.TBW; - - for(int j = 0, y = 0; y < th; j++, y += psm.pgs.cy) - { - DWORD page = psm.pgn(0, y, bp, bw); - - for(int i = 0, x = 0; x < tw && page < MAX_PAGES; i++, x += psm.pgs.cx, page++) - { - GSTexturePage* p = new GSTexturePage(); - - p->t = t; - p->row = j; - p->col = i; - - GSTexturePageEntry* p2te = new GSTexturePageEntry(); - - p2te->p2t = &m_p2t[page]; - p2te->pos = m_p2t[page].AddHead(p); - - t->m_p2te.AddTail(p2te); - - t->m_maxpages++; - } - } - } - - if(!t->Update(TEX0, TEXA, r)) - { - m_textures.RemoveAt(t->m_pos); - - delete t; - - printf("!@#$%\n"); // memory allocation may fail if the game is too hungry - - return NULL; - } - - return t; -} - -void GSTextureCacheSW::RemoveAll() -{ - POSITION pos = m_textures.GetHeadPosition(); - - while(pos) - { - delete m_textures.GetNext(pos); - } - - m_textures.RemoveAll(); - - for(int i = 0; i < MAX_PAGES; i++) - { - CAtlList& t2p = m_p2t[i]; - - ASSERT(t2p.IsEmpty()); - - POSITION pos = t2p.GetHeadPosition(); - - while(pos) - { - delete t2p.GetNext(pos); - } - - t2p.RemoveAll(); - } -} - -void GSTextureCacheSW::IncAge() -{ - POSITION pos = m_textures.GetHeadPosition(); - - while(pos) - { - POSITION cur = pos; - - GSTexture* t = m_textures.GetNext(pos); - - if(++t->m_age > 3) - { - m_textures.RemoveAt(cur); - - delete t; - } - } -} - -void GSTextureCacheSW::InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const CRect& r) -{ - const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[BITBLTBUF.DPSM]; - - CRect r2; - - r2.left = r.left & ~(psm.pgs.cx - 1); - r2.top = r.top & ~(psm.pgs.cy - 1); - r2.right = (r.right + (psm.pgs.cx - 1)) & ~(psm.pgs.cx - 1); - r2.bottom = (r.bottom + (psm.pgs.cy - 1)) & ~(psm.pgs.cy - 1); - - DWORD bp = BITBLTBUF.DBP; - DWORD bw = BITBLTBUF.DBW; - - // fprintf(m_log, "ivm %05x %d %d (%d %d %d %d)\n", bp, bw, BITBLTBUF.DPSM, r2.left, r2.top, r2.right, r2.bottom); - - for(int y = r2.top; y < r2.bottom; y += psm.pgs.cy) - { - DWORD page = psm.pgn(r2.left, y, bp, bw); - - for(int x = r2.left; x < r2.right && page < MAX_PAGES; x += psm.pgs.cx, page++) - { - const CAtlList& t2p = m_p2t[page]; - - POSITION pos = t2p.GetHeadPosition(); - - while(pos) - { - GSTexturePage* p = t2p.GetNext(pos); - - DWORD flag = 1 << p->col; - - if((p->t->m_valid[p->row] & flag) == 0) - { - continue; - } - - if(GSUtil::HasSharedBits(BITBLTBUF.DPSM, p->t->m_TEX0.PSM)) - { - p->t->m_valid[p->row] &= ~flag; - p->t->m_pages--; - - // fprintf(m_log, "ivm hit %05x %d %d (%d %d) (%d)", p->t->m_TEX0.TBP0, p->t->m_TEX0.TBW, p->t->m_TEX0.PSM, p->row, p->col, p->t->m_pages); - // if(p->t->m_pages == 0) fprintf(m_log, " *"); - // fprintf(m_log, "\n"); - } - } - } - } -} - -// - -GSTextureCacheSW::GSTexture::GSTexture(GSState* state) - : m_state(state) - , m_buff(NULL) - , m_tw(0) - , m_maxpages(0) - , m_pages(0) - , m_pos(NULL) - , m_age(0) -{ - memset(m_valid, 0, sizeof(m_valid)); -} - -GSTextureCacheSW::GSTexture::~GSTexture() -{ - if(m_buff) - { - _aligned_free(m_buff); - } - - POSITION pos = m_p2te.GetHeadPosition(); - - while(pos) - { - GSTexturePageEntry* p2te = m_p2te.GetNext(pos); - - GSTexturePage* p = p2te->p2t->GetAt(p2te->pos); - - ASSERT(p->t == this); - - delete p; - - p2te->p2t->RemoveAt(p2te->pos); - - delete p2te; - } - - m_p2te.RemoveAll(); -} - -bool GSTextureCacheSW::GSTexture::Update(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const CRect* r) -{ - if(m_pages == m_maxpages) - { - return true; - } - - m_TEX0 = TEX0; - m_TEXA = TEXA; - - GSLocalMemory& mem = m_state->m_mem; - - const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[TEX0.PSM]; - - int tw = 1 << TEX0.TW; - int th = 1 << TEX0.TH; - - if(tw < psm.bs.cx) tw = psm.bs.cx; - if(th < psm.bs.cy) th = psm.bs.cy; - - if(m_buff == NULL) - { - // fprintf(m_log, "up new (%d %d)\n", tw, th); - - m_buff = _aligned_malloc(tw * th * sizeof(DWORD), 16); - - if(m_buff == NULL) - { - return false; - } - - m_tw = max(psm.pal > 0 ? 5 : 3, TEX0.TW); // makes one row 32 bytes at least, matches the smallest block size that is allocated above for m_buff - } - - CRect r2; - - if(r) - { - r2.left = r->left & ~(psm.pgs.cx - 1); - r2.top = r->top & ~(psm.pgs.cy - 1); - r2.right = (r->right + (psm.pgs.cx - 1)) & ~(psm.pgs.cx - 1); - r2.bottom = (r->bottom + (psm.pgs.cy - 1)) & ~(psm.pgs.cy - 1); - } - - // TODO - - GSLocalMemory::readTexture rt = psm.pal > 0 ? psm.rtxP : psm.rtx; - int bytes = psm.pal > 0 ? 1 : 4; - - BYTE* dst = (BYTE*)m_buff; - - DWORD pitch = (1 << m_tw) * bytes; - DWORD mask = pitch - 1; - - for(int j = 0, y = 0; y < th; j++, y += psm.pgs.cy, dst += pitch * psm.pgs.cy) - { - if(m_valid[j] == mask) - { - continue; - } - - if(r) - { - if(y < r2.top) continue; - if(y >= r2.bottom) break; - } - - DWORD page = psm.pgn(0, y, TEX0.TBP0, TEX0.TBW); - - for(int i = 0, x = 0; x < tw && page < MAX_PAGES; i++, x += psm.pgs.cx, page++) - { - if(r) - { - if(x < r2.left) continue; - if(x >= r2.right) break; - } - - DWORD flag = 1 << i; - - if(m_valid[j] & flag) - { - continue; - } - - m_valid[j] |= flag; - m_pages++; - - ASSERT(m_pages <= m_maxpages); - - CRect r; - - r.left = x; - r.top = y; - r.right = min(x + psm.pgs.cx, tw); - r.bottom = min(y + psm.pgs.cy, th); - - // fprintf(m_log, "up fetch (%d %d) (%d %d %d %d)\n", j, i, r.left, r.top, r.right, r.bottom); - - (mem.*rt)(r, &dst[x * bytes], pitch, TEX0, TEXA); - - m_state->m_perfmon.Put(GSPerfMon::Unswizzle, r.Width() * r.Height() * bytes); - } - } - - return true; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSTextureCacheSW.h" + +// static FILE* m_log = NULL; + +GSTextureCacheSW::GSTextureCacheSW(GSState* state) + : m_state(state) +{ + // m_log = _tfopen(_T("c:\\log.txt"), _T("w")); +} + +GSTextureCacheSW::~GSTextureCacheSW() +{ + // fclose(m_log); + + RemoveAll(); +} + +const GSTextureCacheSW::GSTexture* GSTextureCacheSW::Lookup(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const CRect* r) +{ + GSLocalMemory& mem = m_state->m_mem; + + const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[TEX0.PSM]; + + const CAtlList& t2p = m_p2t[TEX0.TBP0 >> 5]; + + // fprintf(m_log, "lu %05x %d %d (%d) ", TEX0.TBP0, TEX0.TBW, TEX0.PSM, t2p.GetCount()); + + // if(r) fprintf(m_log, "(%d %d %d %d) ", r->left, r->top, r->right, r->bottom); + + GSTexture* t = NULL; + + POSITION pos = t2p.GetHeadPosition(); + + while(pos) + { + GSTexture* t2 = t2p.GetNext(pos)->t; + + // if(t2->m_TEX0.TBP0 != TEX0.TBP0 || t2->m_TEX0.TBW != TEX0.TBW || t2->m_TEX0.PSM != TEX0.PSM || t2->m_TEX0.TW != TEX0.TW || t2->m_TEX0.TH != TEX0.TH) + if(((t2->m_TEX0.ai32[0] ^ TEX0.ai32[0]) | ((t2->m_TEX0.ai32[1] ^ TEX0.ai32[1]) & 3)) != 0) + { + continue; + } + + if((psm.trbpp == 16 || psm.trbpp == 24) && (t2->m_TEX0.TCC != TEX0.TCC || TEX0.TCC == 1 && !(t2->m_TEXA == (GSVector4i)TEXA).alltrue())) + { + continue; + } + + // fprintf(m_log, "cache hit\n"); + + t = t2; + + t->m_age = 0; + + break; + } + + if(t == NULL) + { + // fprintf(m_log, "cache miss\n"); + + t = new GSTexture(m_state); + + t->m_pos = m_textures.AddTail(t); + + int tw = 1 << TEX0.TW; + int th = 1 << TEX0.TH; + + DWORD bp = TEX0.TBP0; + DWORD bw = TEX0.TBW; + + for(int j = 0, y = 0; y < th; j++, y += psm.pgs.cy) + { + DWORD page = psm.pgn(0, y, bp, bw); + + for(int i = 0, x = 0; x < tw && page < MAX_PAGES; i++, x += psm.pgs.cx, page++) + { + GSTexturePage* p = new GSTexturePage(); + + p->t = t; + p->row = j; + p->col = i; + + GSTexturePageEntry* p2te = new GSTexturePageEntry(); + + p2te->p2t = &m_p2t[page]; + p2te->pos = m_p2t[page].AddHead(p); + + t->m_p2te.AddTail(p2te); + + t->m_maxpages++; + } + } + } + + if(!t->Update(TEX0, TEXA, r)) + { + m_textures.RemoveAt(t->m_pos); + + delete t; + + printf("!@#$%\n"); // memory allocation may fail if the game is too hungry + + return NULL; + } + + return t; +} + +void GSTextureCacheSW::RemoveAll() +{ + POSITION pos = m_textures.GetHeadPosition(); + + while(pos) + { + delete m_textures.GetNext(pos); + } + + m_textures.RemoveAll(); + + for(int i = 0; i < MAX_PAGES; i++) + { + CAtlList& t2p = m_p2t[i]; + + ASSERT(t2p.IsEmpty()); + + POSITION pos = t2p.GetHeadPosition(); + + while(pos) + { + delete t2p.GetNext(pos); + } + + t2p.RemoveAll(); + } +} + +void GSTextureCacheSW::IncAge() +{ + POSITION pos = m_textures.GetHeadPosition(); + + while(pos) + { + POSITION cur = pos; + + GSTexture* t = m_textures.GetNext(pos); + + if(++t->m_age > 3) + { + m_textures.RemoveAt(cur); + + delete t; + } + } +} + +void GSTextureCacheSW::InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const CRect& r) +{ + const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[BITBLTBUF.DPSM]; + + CRect r2; + + r2.left = r.left & ~(psm.pgs.cx - 1); + r2.top = r.top & ~(psm.pgs.cy - 1); + r2.right = (r.right + (psm.pgs.cx - 1)) & ~(psm.pgs.cx - 1); + r2.bottom = (r.bottom + (psm.pgs.cy - 1)) & ~(psm.pgs.cy - 1); + + DWORD bp = BITBLTBUF.DBP; + DWORD bw = BITBLTBUF.DBW; + + // fprintf(m_log, "ivm %05x %d %d (%d %d %d %d)\n", bp, bw, BITBLTBUF.DPSM, r2.left, r2.top, r2.right, r2.bottom); + + for(int y = r2.top; y < r2.bottom; y += psm.pgs.cy) + { + DWORD page = psm.pgn(r2.left, y, bp, bw); + + for(int x = r2.left; x < r2.right && page < MAX_PAGES; x += psm.pgs.cx, page++) + { + const CAtlList& t2p = m_p2t[page]; + + POSITION pos = t2p.GetHeadPosition(); + + while(pos) + { + GSTexturePage* p = t2p.GetNext(pos); + + DWORD flag = 1 << p->col; + + if((p->t->m_valid[p->row] & flag) == 0) + { + continue; + } + + if(GSUtil::HasSharedBits(BITBLTBUF.DPSM, p->t->m_TEX0.PSM)) + { + p->t->m_valid[p->row] &= ~flag; + p->t->m_pages--; + + // fprintf(m_log, "ivm hit %05x %d %d (%d %d) (%d)", p->t->m_TEX0.TBP0, p->t->m_TEX0.TBW, p->t->m_TEX0.PSM, p->row, p->col, p->t->m_pages); + // if(p->t->m_pages == 0) fprintf(m_log, " *"); + // fprintf(m_log, "\n"); + } + } + } + } +} + +// + +GSTextureCacheSW::GSTexture::GSTexture(GSState* state) + : m_state(state) + , m_buff(NULL) + , m_tw(0) + , m_maxpages(0) + , m_pages(0) + , m_pos(NULL) + , m_age(0) +{ + memset(m_valid, 0, sizeof(m_valid)); +} + +GSTextureCacheSW::GSTexture::~GSTexture() +{ + if(m_buff) + { + _aligned_free(m_buff); + } + + POSITION pos = m_p2te.GetHeadPosition(); + + while(pos) + { + GSTexturePageEntry* p2te = m_p2te.GetNext(pos); + + GSTexturePage* p = p2te->p2t->GetAt(p2te->pos); + + ASSERT(p->t == this); + + delete p; + + p2te->p2t->RemoveAt(p2te->pos); + + delete p2te; + } + + m_p2te.RemoveAll(); +} + +bool GSTextureCacheSW::GSTexture::Update(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const CRect* r) +{ + if(m_pages == m_maxpages) + { + return true; + } + + m_TEX0 = TEX0; + m_TEXA = TEXA; + + GSLocalMemory& mem = m_state->m_mem; + + const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[TEX0.PSM]; + + int tw = 1 << TEX0.TW; + int th = 1 << TEX0.TH; + + if(tw < psm.bs.cx) tw = psm.bs.cx; + if(th < psm.bs.cy) th = psm.bs.cy; + + if(m_buff == NULL) + { + // fprintf(m_log, "up new (%d %d)\n", tw, th); + + m_buff = _aligned_malloc(tw * th * sizeof(DWORD), 16); + + if(m_buff == NULL) + { + return false; + } + + m_tw = max(psm.pal > 0 ? 5 : 3, TEX0.TW); // makes one row 32 bytes at least, matches the smallest block size that is allocated above for m_buff + } + + CRect r2; + + if(r) + { + r2.left = r->left & ~(psm.pgs.cx - 1); + r2.top = r->top & ~(psm.pgs.cy - 1); + r2.right = (r->right + (psm.pgs.cx - 1)) & ~(psm.pgs.cx - 1); + r2.bottom = (r->bottom + (psm.pgs.cy - 1)) & ~(psm.pgs.cy - 1); + } + + // TODO + + GSLocalMemory::readTexture rt = psm.pal > 0 ? psm.rtxP : psm.rtx; + int bytes = psm.pal > 0 ? 1 : 4; + + BYTE* dst = (BYTE*)m_buff; + + DWORD pitch = (1 << m_tw) * bytes; + DWORD mask = pitch - 1; + + for(int j = 0, y = 0; y < th; j++, y += psm.pgs.cy, dst += pitch * psm.pgs.cy) + { + if(m_valid[j] == mask) + { + continue; + } + + if(r) + { + if(y < r2.top) continue; + if(y >= r2.bottom) break; + } + + DWORD page = psm.pgn(0, y, TEX0.TBP0, TEX0.TBW); + + for(int i = 0, x = 0; x < tw && page < MAX_PAGES; i++, x += psm.pgs.cx, page++) + { + if(r) + { + if(x < r2.left) continue; + if(x >= r2.right) break; + } + + DWORD flag = 1 << i; + + if(m_valid[j] & flag) + { + continue; + } + + m_valid[j] |= flag; + m_pages++; + + ASSERT(m_pages <= m_maxpages); + + CRect r; + + r.left = x; + r.top = y; + r.right = min(x + psm.pgs.cx, tw); + r.bottom = min(y + psm.pgs.cy, th); + + // fprintf(m_log, "up fetch (%d %d) (%d %d %d %d)\n", j, i, r.left, r.top, r.right, r.bottom); + + (mem.*rt)(r, &dst[x * bytes], pitch, TEX0, TEXA); + + m_state->m_perfmon.Put(GSPerfMon::Unswizzle, r.Width() * r.Height() * bytes); + } + } + + return true; } \ No newline at end of file diff --git a/plugins/GSdx/GSTextureCacheSW.h b/plugins/GSdx/GSTextureCacheSW.h index 96dc5659f3..8f123300a6 100644 --- a/plugins/GSdx/GSTextureCacheSW.h +++ b/plugins/GSdx/GSTextureCacheSW.h @@ -1,83 +1,83 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSRenderer.h" - -#define MAX_PAGES 512 - -class GSTextureCacheSW -{ -public: - class GSTexture; - class GSTexturePage; - - class GSTexturePage - { - public: - GSTexture* t; - DWORD row, col; - }; - - class GSTexturePageEntry - { - public: - CAtlList* p2t; - POSITION pos; - }; - - class GSTexture - { - public: - GSState* m_state; - GIFRegTEX0 m_TEX0; - GIFRegTEXA m_TEXA; - void* m_buff; - DWORD m_tw; - DWORD m_valid[32]; - DWORD m_maxpages; - DWORD m_pages; - CAtlList m_p2te; - POSITION m_pos; - DWORD m_age; - - explicit GSTexture(GSState* state); - virtual ~GSTexture(); - - bool Update(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const CRect* r = NULL); - }; - -protected: - GSState* m_state; - CAtlList m_textures; - CAtlList m_p2t[MAX_PAGES]; - -public: - GSTextureCacheSW(GSState* state); - virtual ~GSTextureCacheSW(); - - const GSTexture* Lookup(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const CRect* r = NULL); - - void RemoveAll(); - void IncAge(); - void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const CRect& r); -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSRenderer.h" + +#define MAX_PAGES 512 + +class GSTextureCacheSW +{ +public: + class GSTexture; + class GSTexturePage; + + class GSTexturePage + { + public: + GSTexture* t; + DWORD row, col; + }; + + class GSTexturePageEntry + { + public: + CAtlList* p2t; + POSITION pos; + }; + + class GSTexture + { + public: + GSState* m_state; + GIFRegTEX0 m_TEX0; + GIFRegTEXA m_TEXA; + void* m_buff; + DWORD m_tw; + DWORD m_valid[32]; + DWORD m_maxpages; + DWORD m_pages; + CAtlList m_p2te; + POSITION m_pos; + DWORD m_age; + + explicit GSTexture(GSState* state); + virtual ~GSTexture(); + + bool Update(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const CRect* r = NULL); + }; + +protected: + GSState* m_state; + CAtlList m_textures; + CAtlList m_p2t[MAX_PAGES]; + +public: + GSTextureCacheSW(GSState* state); + virtual ~GSTextureCacheSW(); + + const GSTexture* Lookup(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const CRect* r = NULL); + + void RemoveAll(); + void IncAge(); + void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const CRect& r); +}; diff --git a/plugins/GSdx/GSTextureFX10.cpp b/plugins/GSdx/GSTextureFX10.cpp index c116082cad..0f3073d9cf 100644 --- a/plugins/GSdx/GSTextureFX10.cpp +++ b/plugins/GSdx/GSTextureFX10.cpp @@ -1,583 +1,583 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GSTextureFX10.h" -#include "resource.h" - -GSTextureFX10::GSTextureFX10() - : m_dev(NULL) - , m_vb_max(0) - , m_vb_start(0) - , m_vb_count(0) -{ - memset(&m_vs_cb_cache, 0, sizeof(m_vs_cb_cache)); - memset(&m_ps_cb_cache, 0, sizeof(m_ps_cb_cache)); -} - -bool GSTextureFX10::Create(GSDevice10* dev) -{ - m_dev = dev; - - // - - VSSelector sel; - - sel.bppz = 0; - sel.tme = 0; - sel.fst = 0; - - VSConstantBuffer cb; - - SetupVS(sel, &cb); // creates layout - - HRESULT hr; - - D3D10_BUFFER_DESC bd; - - memset(&bd, 0, sizeof(bd)); - - bd.ByteWidth = sizeof(VSConstantBuffer); - bd.Usage = D3D10_USAGE_DEFAULT; - bd.BindFlags = D3D10_BIND_CONSTANT_BUFFER; - - hr = (*m_dev)->CreateBuffer(&bd, NULL, &m_vs_cb); - - if(FAILED(hr)) return false; - - memset(&bd, 0, sizeof(bd)); - - bd.ByteWidth = sizeof(PSConstantBuffer); - bd.Usage = D3D10_USAGE_DEFAULT; - bd.BindFlags = D3D10_BIND_CONSTANT_BUFFER; - - hr = (*m_dev)->CreateBuffer(&bd, NULL, &m_ps_cb); - - if(FAILED(hr)) return false; - - D3D10_SAMPLER_DESC sd; - - memset(&sd, 0, sizeof(sd)); - - sd.Filter = D3D10_ENCODE_BASIC_FILTER(D3D10_FILTER_TYPE_POINT, D3D10_FILTER_TYPE_POINT, D3D10_FILTER_TYPE_POINT, false); - sd.AddressU = D3D10_TEXTURE_ADDRESS_CLAMP; - sd.AddressV = D3D10_TEXTURE_ADDRESS_CLAMP; - sd.AddressW = D3D10_TEXTURE_ADDRESS_CLAMP; - sd.MaxLOD = FLT_MAX; - sd.MaxAnisotropy = 16; - sd.ComparisonFunc = D3D10_COMPARISON_NEVER; - - hr = (*m_dev)->CreateSamplerState(&sd, &m_palette_ss); - - if(FAILED(hr)) return false; - - // - - return true; -} - -bool GSTextureFX10::SetupIA(const GSVertexHW10* vertices, int count, D3D10_PRIMITIVE_TOPOLOGY prim) -{ - HRESULT hr; - - if(max(count * 3 / 2, 10000) > m_vb_max) - { - m_vb_old = m_vb; - m_vb = NULL; - m_vb_max = max(count * 2, 10000); - m_vb_start = 0; - m_vb_count = 0; - } - - if(!m_vb) - { - D3D10_BUFFER_DESC bd; - - memset(&bd, 0, sizeof(bd)); - - bd.Usage = D3D10_USAGE_DYNAMIC; - bd.ByteWidth = m_vb_max * sizeof(vertices[0]); - bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; - bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; - - hr = (*m_dev)->CreateBuffer(&bd, NULL, &m_vb); - - if(FAILED(hr)) return false; - } - - GSVertexHW10* v = NULL; - - int next = m_vb_start + m_vb_count; - - if(next + count > m_vb_max) - { - if(SUCCEEDED(m_vb->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&v))) - { - memcpy(v, vertices, count * sizeof(vertices[0])); - - m_vb->Unmap(); - } - - m_vb_start = 0; - m_vb_count = count; - } - else - { - if(SUCCEEDED(m_vb->Map(D3D10_MAP_WRITE_NO_OVERWRITE, 0, (void**)&v))) - { - memcpy(&v[next], vertices, count * sizeof(vertices[0])); - - m_vb->Unmap(); - } - - m_vb_start = next; - m_vb_count = count; - } - - m_dev->IASetVertexBuffer(m_vb, sizeof(vertices[0])); - m_dev->IASetInputLayout(m_il); - m_dev->IASetPrimitiveTopology(prim); - - return true; -} - -bool GSTextureFX10::SetupVS(VSSelector sel, const VSConstantBuffer* cb) -{ - CComPtr vs; - - if(CRBMap >::CPair* pair = m_vs.Lookup(sel)) - { - vs = pair->m_value; - } - else - { - CStringA str[5]; - - str[0].Format("%d", sel.bpp); - str[1].Format("%d", sel.bppz); - str[2].Format("%d", sel.tme); - str[3].Format("%d", sel.fst); - str[4].Format("%d", sel.prim); - - D3D10_SHADER_MACRO macro[] = - { - {"VS_BPP", str[0]}, - {"VS_BPPZ", str[1]}, - {"VS_TME", str[2]}, - {"VS_FST", str[3]}, - {"VS_PRIM", str[4]}, - {NULL, NULL}, - }; - - D3D10_INPUT_ELEMENT_DESC layout[] = - { - {"POSITION", 0, DXGI_FORMAT_R16G16_UINT, 0, 8, D3D10_INPUT_PER_VERTEX_DATA, 0}, - {"POSITION", 1, DXGI_FORMAT_R32_UINT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0}, - {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0}, - {"TEXCOORD", 1, DXGI_FORMAT_R32_FLOAT, 0, 20, D3D10_INPUT_PER_VERTEX_DATA, 0}, - {"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 16, D3D10_INPUT_PER_VERTEX_DATA, 0}, - {"COLOR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 28, D3D10_INPUT_PER_VERTEX_DATA, 0}, - }; - - CComPtr il; - - m_dev->CompileShader(IDR_TFX10_FX, "vs_main", macro, &vs, layout, countof(layout), &il); - - if(m_il == NULL) - { - m_il = il; - } - - m_vs.SetAt(sel, vs); - } - - if(m_vs_cb_cache.Update(cb)) - { - (*m_dev)->UpdateSubresource(m_vs_cb, 0, NULL, cb, 0, 0); - } - - m_dev->VSSetShader(vs, m_vs_cb); - - return true; -} - -bool GSTextureFX10::SetupGS(GSSelector sel) -{ - HRESULT hr; - - CComPtr gs; - - if(sel.prim > 0 && (sel.iip == 0 || sel.prim == 3)) // geometry shader works in every case, but not needed - { - if(CRBMap >::CPair* pair = m_gs.Lookup(sel)) - { - gs = pair->m_value; - } - else - { - CStringA str[2]; - - str[0].Format("%d", sel.iip); - str[1].Format("%d", sel.prim); - - D3D10_SHADER_MACRO macro[] = - { - {"IIP", str[0]}, - {"PRIM", str[1]}, - {NULL, NULL}, - }; - - hr = m_dev->CompileShader(IDR_TFX10_FX, "gs_main", macro, &gs); - - m_gs.SetAt(sel, gs); - } - } - - m_dev->GSSetShader(gs); - - return true; -} - -bool GSTextureFX10::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, ID3D10ShaderResourceView* tex, ID3D10ShaderResourceView* pal) -{ - m_dev->PSSetShaderResources(tex, pal); - - UpdatePS(sel, cb, ssel); - - return true; -} - -void GSTextureFX10::UpdatePS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel) -{ - HRESULT hr; - - CComPtr ps; - - if(CRBMap >::CPair* pair = m_ps.Lookup(sel)) - { - ps = pair->m_value; - } - else - { - CStringA str[13]; - - str[0].Format("%d", sel.fst); - str[1].Format("%d", sel.wms); - str[2].Format("%d", sel.wmt); - str[3].Format("%d", sel.bpp); - str[4].Format("%d", sel.aem); - str[5].Format("%d", sel.tfx); - str[6].Format("%d", sel.tcc); - str[7].Format("%d", sel.ate); - str[8].Format("%d", sel.atst); - str[9].Format("%d", sel.fog); - str[10].Format("%d", sel.clr1); - str[11].Format("%d", sel.fba); - str[12].Format("%d", sel.aout); - - D3D10_SHADER_MACRO macro[] = - { - {"FST", str[0]}, - {"WMS", str[1]}, - {"WMT", str[2]}, - {"BPP", str[3]}, - {"AEM", str[4]}, - {"TFX", str[5]}, - {"TCC", str[6]}, - {"ATE", str[7]}, - {"ATST", str[8]}, - {"FOG", str[9]}, - {"CLR1", str[10]}, - {"FBA", str[11]}, - {"AOUT", str[12]}, - {NULL, NULL}, - }; - - hr = m_dev->CompileShader(IDR_TFX10_FX, "ps_main", macro, &ps); - - m_ps.SetAt(sel, ps); - } - - if(m_ps_cb_cache.Update(cb)) - { - (*m_dev)->UpdateSubresource(m_ps_cb, 0, NULL, cb, 0, 0); - } - - m_dev->PSSetShader(ps, m_ps_cb); - - CComPtr ss0, ss1; - - if(sel.tfx != 4) - { - if(sel.bpp >= 3 || sel.wms >= 3 || sel.wmt >= 3) - { - ssel.min = ssel.mag = 0; - } - - if(CRBMap >::CPair* pair = m_ps_ss.Lookup(ssel)) - { - ss0 = pair->m_value; - } - else - { - D3D10_SAMPLER_DESC sd; - - memset(&sd, 0, sizeof(sd)); - - sd.Filter = D3D10_ENCODE_BASIC_FILTER( - (ssel.min ? D3D10_FILTER_TYPE_LINEAR : D3D10_FILTER_TYPE_POINT), - (ssel.mag ? D3D10_FILTER_TYPE_LINEAR : D3D10_FILTER_TYPE_POINT), - D3D10_FILTER_TYPE_POINT, - false); - - sd.AddressU = ssel.tau ? D3D10_TEXTURE_ADDRESS_WRAP : D3D10_TEXTURE_ADDRESS_CLAMP; - sd.AddressV = ssel.tav ? D3D10_TEXTURE_ADDRESS_WRAP : D3D10_TEXTURE_ADDRESS_CLAMP; - sd.AddressW = D3D10_TEXTURE_ADDRESS_CLAMP; - - sd.MaxLOD = FLT_MAX; - sd.MaxAnisotropy = 16; - sd.ComparisonFunc = D3D10_COMPARISON_NEVER; - - hr = (*m_dev)->CreateSamplerState(&sd, &ss0); - - m_ps_ss.SetAt(ssel, ss0); - } - - if(sel.bpp == 3) - { - ss1 = m_palette_ss; - } - } - - m_dev->PSSetSamplerState(ss0, ss1); -} - -void GSTextureFX10::SetupRS(UINT w, UINT h, const RECT& scissor) -{ - m_dev->RSSet(w, h, &scissor); -} - -void GSTextureFX10::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf, ID3D10RenderTargetView* rtv, ID3D10DepthStencilView* dsv) -{ - UpdateOM(dssel, bsel, bf); - - m_dev->OMSetRenderTargets(rtv, dsv); -} - -void GSTextureFX10::UpdateOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf) -{ - HRESULT hr; - - CComPtr dss; - - if(CRBMap >::CPair* pair = m_om_dss.Lookup(dssel)) - { - dss = pair->m_value; - } - else - { - D3D10_DEPTH_STENCIL_DESC dsd; - - memset(&dsd, 0, sizeof(dsd)); - - if(dssel.date) - { - dsd.StencilEnable = true; - dsd.StencilReadMask = 1; - dsd.StencilWriteMask = 1; - dsd.FrontFace.StencilFunc = D3D10_COMPARISON_EQUAL; - dsd.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP; - dsd.FrontFace.StencilFailOp = D3D10_STENCIL_OP_KEEP; - dsd.FrontFace.StencilDepthFailOp = D3D10_STENCIL_OP_KEEP; - dsd.BackFace.StencilFunc = D3D10_COMPARISON_EQUAL; - dsd.BackFace.StencilPassOp = D3D10_STENCIL_OP_KEEP; - dsd.BackFace.StencilFailOp = D3D10_STENCIL_OP_KEEP; - dsd.BackFace.StencilDepthFailOp = D3D10_STENCIL_OP_KEEP; - } - - if(!(dssel.zte && dssel.ztst == 1 && !dssel.zwe)) - { - static const D3D10_COMPARISON_FUNC ztst[] = - { - D3D10_COMPARISON_NEVER, - D3D10_COMPARISON_ALWAYS, - D3D10_COMPARISON_GREATER_EQUAL, - D3D10_COMPARISON_GREATER - }; - - dsd.DepthEnable = dssel.zte; - dsd.DepthWriteMask = dssel.zwe ? D3D10_DEPTH_WRITE_MASK_ALL : D3D10_DEPTH_WRITE_MASK_ZERO; - dsd.DepthFunc = ztst[dssel.ztst]; - } - - hr = (*m_dev)->CreateDepthStencilState(&dsd, &dss); - - m_om_dss.SetAt(dssel, dss); - } - - m_dev->OMSetDepthStencilState(dss, 1); - - CComPtr bs; - - if(CRBMap >::CPair* pair = m_om_bs.Lookup(bsel)) - { - bs = pair->m_value; - } - else - { - D3D10_BLEND_DESC bd; - - memset(&bd, 0, sizeof(bd)); - - bd.BlendEnable[0] = bsel.abe; - - if(bsel.abe) - { - // (A:Cs/Cd/0 - B:Cs/Cd/0) * C:As/Ad/FIX + D:Cs/Cd/0 - - static const struct {int bogus; D3D10_BLEND_OP op; D3D10_BLEND src, dst;} map[3*3*3*3] = - { - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 0000: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 0001: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 0002: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 0010: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 0011: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 0012: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 0020: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 0021: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 0022: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 - {1, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_SRC1_ALPHA}, // * 0100: (Cs - Cd)*As + Cs ==> Cs*(As + 1) - Cd*As - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_INV_SRC1_ALPHA}, // 0101: (Cs - Cd)*As + Cd ==> Cs*As + Cd*(1 - As) - {0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_SRC1_ALPHA}, // 0102: (Cs - Cd)*As + 0 ==> Cs*As - Cd*As - {1, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_DEST_ALPHA}, // * 0110: (Cs - Cd)*Ad + Cs ==> Cs*(Ad + 1) - Cd*Ad - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_INV_DEST_ALPHA}, // 0111: (Cs - Cd)*Ad + Cd ==> Cs*Ad + Cd*(1 - Ad) - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_DEST_ALPHA}, // 0112: (Cs - Cd)*Ad + 0 ==> Cs*Ad - Cd*Ad - {1, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_BLEND_FACTOR}, // * 0120: (Cs - Cd)*F + Cs ==> Cs*(F + 1) - Cd*F - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_INV_BLEND_FACTOR}, // 0121: (Cs - Cd)*F + Cd ==> Cs*F + Cd*(1 - F) - {0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_BLEND_FACTOR}, // 0122: (Cs - Cd)*F + 0 ==> Cs*F - Cd*F - {1, D3D10_BLEND_OP_ADD, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_ZERO}, // * 0200: (Cs - 0)*As + Cs ==> Cs*(As + 1) - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_ONE}, // 0201: (Cs - 0)*As + Cd ==> Cs*As + Cd - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_ZERO}, // 0202: (Cs - 0)*As + 0 ==> Cs*As - {1, D3D10_BLEND_OP_ADD, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_ZERO}, // * 0210: (Cs - 0)*Ad + Cs ==> Cs*(Ad + 1) - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_ONE}, // 0211: (Cs - 0)*Ad + Cd ==> Cs*Ad + Cd - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_ZERO}, // 0212: (Cs - 0)*Ad + 0 ==> Cs*Ad - {1, D3D10_BLEND_OP_ADD, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_ZERO}, // * 0220: (Cs - 0)*F + Cs ==> Cs*(F + 1) - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_ONE}, // 0221: (Cs - 0)*F + Cd ==> Cs*F + Cd - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_ZERO}, // 0222: (Cs - 0)*F + 0 ==> Cs*F - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_INV_SRC1_ALPHA, D3D10_BLEND_SRC1_ALPHA}, // 1000: (Cd - Cs)*As + Cs ==> Cd*As + Cs*(1 - As) - {1, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_SRC1_ALPHA}, // * 1001: (Cd - Cs)*As + Cd ==> Cd*(As + 1) - Cs*As - {0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_SRC1_ALPHA}, // 1002: (Cd - Cs)*As + 0 ==> Cd*As - Cs*As - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_INV_DEST_ALPHA, D3D10_BLEND_DEST_ALPHA}, // 1010: (Cd - Cs)*Ad + Cs ==> Cd*Ad + Cs*(1 - Ad) - {1, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_DEST_ALPHA}, // * 1011: (Cd - Cs)*Ad + Cd ==> Cd*(Ad + 1) - Cs*Ad - {0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_DEST_ALPHA}, // 1012: (Cd - Cs)*Ad + 0 ==> Cd*Ad - Cs*Ad - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_INV_BLEND_FACTOR, D3D10_BLEND_BLEND_FACTOR}, // 1020: (Cd - Cs)*F + Cs ==> Cd*F + Cs*(1 - F) - {1, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_BLEND_FACTOR},// * 1021: (Cd - Cs)*F + Cd ==> Cd*(F + 1) - Cs*F - {0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_BLEND_FACTOR},// 1022: (Cd - Cs)*F + 0 ==> Cd*F - Cs*F - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 1100: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 1101: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 1102: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 1110: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 1111: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 1112: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 1120: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 1121: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 1122: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_SRC1_ALPHA}, // 1200: (Cd - 0)*As + Cs ==> Cs + Cd*As - {2, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_COLOR, D3D10_BLEND_SRC1_ALPHA}, // ** 1201: (Cd - 0)*As + Cd ==> Cd*(1 + As) // ffxii main menu background glow effect - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_SRC1_ALPHA}, // 1202: (Cd - 0)*As + 0 ==> Cd*As - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_DEST_ALPHA}, // 1210: (Cd - 0)*Ad + Cs ==> Cs + Cd*Ad - {2, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_COLOR, D3D10_BLEND_DEST_ALPHA}, // ** 1211: (Cd - 0)*Ad + Cd ==> Cd*(1 + Ad) - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_DEST_ALPHA}, // 1212: (Cd - 0)*Ad + 0 ==> Cd*Ad - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_BLEND_FACTOR}, // 1220: (Cd - 0)*F + Cs ==> Cs + Cd*F - {2, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_COLOR, D3D10_BLEND_BLEND_FACTOR}, // ** 1221: (Cd - 0)*F + Cd ==> Cd*(1 + F) - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_BLEND_FACTOR}, // 1222: (Cd - 0)*F + 0 ==> Cd*F - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_INV_SRC1_ALPHA, D3D10_BLEND_ZERO}, // 2000: (0 - Cs)*As + Cs ==> Cs*(1 - As) - {0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_ONE}, // 2001: (0 - Cs)*As + Cd ==> Cd - Cs*As - {0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_ZERO}, // 2002: (0 - Cs)*As + 0 ==> 0 - Cs*As - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_INV_DEST_ALPHA, D3D10_BLEND_ZERO}, // 2010: (0 - Cs)*Ad + Cs ==> Cs*(1 - Ad) - {0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_ONE}, // 2011: (0 - Cs)*Ad + Cd ==> Cd - Cs*Ad - {0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_ZERO}, // 2012: (0 - Cs)*Ad + 0 ==> 0 - Cs*Ad - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_INV_BLEND_FACTOR, D3D10_BLEND_ZERO}, // 2020: (0 - Cs)*F + Cs ==> Cs*(1 - F) - {0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_ONE}, // 2021: (0 - Cs)*F + Cd ==> Cd - Cs*F - {0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_ZERO}, // 2022: (0 - Cs)*F + 0 ==> 0 - Cs*F - {0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_ONE, D3D10_BLEND_SRC1_ALPHA}, // 2100: (0 - Cd)*As + Cs ==> Cs - Cd*As - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_INV_SRC1_ALPHA}, // 2101: (0 - Cd)*As + Cd ==> Cd*(1 - As) - {0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_ZERO, D3D10_BLEND_SRC1_ALPHA}, // 2102: (0 - Cd)*As + 0 ==> 0 - Cd*As - {0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_ONE, D3D10_BLEND_DEST_ALPHA}, // 2110: (0 - Cd)*Ad + Cs ==> Cs - Cd*Ad - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_INV_DEST_ALPHA}, // 2111: (0 - Cd)*Ad + Cd ==> Cd*(1 - Ad) - {0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_ONE, D3D10_BLEND_DEST_ALPHA}, // 2112: (0 - Cd)*Ad + 0 ==> 0 - Cd*Ad - {0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_ONE, D3D10_BLEND_BLEND_FACTOR}, // 2120: (0 - Cd)*F + Cs ==> Cs - Cd*F - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_INV_BLEND_FACTOR}, // 2121: (0 - Cd)*F + Cd ==> Cd*(1 - F) - {0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_ONE, D3D10_BLEND_BLEND_FACTOR}, // 2122: (0 - Cd)*F + 0 ==> 0 - Cd*F - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 2200: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 2201: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 2202: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 2210: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 2211: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 2212: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 2220: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 2221: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd - {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 2222: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 - }; - - // bogus: 0100, 0110, 0120, 0200, 0210, 0220, 1001, 1011, 1021 - - // tricky: 1201, 1211, 1221 - // - // Source.rgb = float3(1, 1, 1); - // 1201 Cd*(1 + As) => Source * Dest color + Dest * Source1 alpha - // 1211 Cd*(1 + Ad) => Source * Dest color + Dest * Dest alpha - // 1221 Cd*(1 + F) => Source * Dest color + Dest * Factor - - int i = ((bsel.a * 3 + bsel.b) * 3 + bsel.c) * 3 + bsel.d; - - bd.BlendOp = map[i].op; - bd.SrcBlend = map[i].src; - bd.DestBlend = map[i].dst; - bd.BlendOpAlpha = D3D10_BLEND_OP_ADD; - bd.SrcBlendAlpha = D3D10_BLEND_ONE; - bd.DestBlendAlpha = D3D10_BLEND_ZERO; - - if(map[i].bogus == 1) - { - ASSERT(0); - - (bsel.a == 0 ? bd.SrcBlend : bd.DestBlend) = D3D10_BLEND_ONE; - } - } - - if(bsel.wr) bd.RenderTargetWriteMask[0] |= D3D10_COLOR_WRITE_ENABLE_RED; - if(bsel.wg) bd.RenderTargetWriteMask[0] |= D3D10_COLOR_WRITE_ENABLE_GREEN; - if(bsel.wb) bd.RenderTargetWriteMask[0] |= D3D10_COLOR_WRITE_ENABLE_BLUE; - if(bsel.wa) bd.RenderTargetWriteMask[0] |= D3D10_COLOR_WRITE_ENABLE_ALPHA; - - hr = (*m_dev)->CreateBlendState(&bd, &bs); - - m_om_bs.SetAt(bsel, bs); - } - - m_dev->OMSetBlendState(bs, bf); -} - -void GSTextureFX10::Draw() -{ - m_dev->DrawPrimitive(m_vb_count, m_vb_start); -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSTextureFX10.h" +#include "resource.h" + +GSTextureFX10::GSTextureFX10() + : m_dev(NULL) + , m_vb_max(0) + , m_vb_start(0) + , m_vb_count(0) +{ + memset(&m_vs_cb_cache, 0, sizeof(m_vs_cb_cache)); + memset(&m_ps_cb_cache, 0, sizeof(m_ps_cb_cache)); +} + +bool GSTextureFX10::Create(GSDevice10* dev) +{ + m_dev = dev; + + // + + VSSelector sel; + + sel.bppz = 0; + sel.tme = 0; + sel.fst = 0; + + VSConstantBuffer cb; + + SetupVS(sel, &cb); // creates layout + + HRESULT hr; + + D3D10_BUFFER_DESC bd; + + memset(&bd, 0, sizeof(bd)); + + bd.ByteWidth = sizeof(VSConstantBuffer); + bd.Usage = D3D10_USAGE_DEFAULT; + bd.BindFlags = D3D10_BIND_CONSTANT_BUFFER; + + hr = (*m_dev)->CreateBuffer(&bd, NULL, &m_vs_cb); + + if(FAILED(hr)) return false; + + memset(&bd, 0, sizeof(bd)); + + bd.ByteWidth = sizeof(PSConstantBuffer); + bd.Usage = D3D10_USAGE_DEFAULT; + bd.BindFlags = D3D10_BIND_CONSTANT_BUFFER; + + hr = (*m_dev)->CreateBuffer(&bd, NULL, &m_ps_cb); + + if(FAILED(hr)) return false; + + D3D10_SAMPLER_DESC sd; + + memset(&sd, 0, sizeof(sd)); + + sd.Filter = D3D10_ENCODE_BASIC_FILTER(D3D10_FILTER_TYPE_POINT, D3D10_FILTER_TYPE_POINT, D3D10_FILTER_TYPE_POINT, false); + sd.AddressU = D3D10_TEXTURE_ADDRESS_CLAMP; + sd.AddressV = D3D10_TEXTURE_ADDRESS_CLAMP; + sd.AddressW = D3D10_TEXTURE_ADDRESS_CLAMP; + sd.MaxLOD = FLT_MAX; + sd.MaxAnisotropy = 16; + sd.ComparisonFunc = D3D10_COMPARISON_NEVER; + + hr = (*m_dev)->CreateSamplerState(&sd, &m_palette_ss); + + if(FAILED(hr)) return false; + + // + + return true; +} + +bool GSTextureFX10::SetupIA(const GSVertexHW10* vertices, int count, D3D10_PRIMITIVE_TOPOLOGY prim) +{ + HRESULT hr; + + if(max(count * 3 / 2, 10000) > m_vb_max) + { + m_vb_old = m_vb; + m_vb = NULL; + m_vb_max = max(count * 2, 10000); + m_vb_start = 0; + m_vb_count = 0; + } + + if(!m_vb) + { + D3D10_BUFFER_DESC bd; + + memset(&bd, 0, sizeof(bd)); + + bd.Usage = D3D10_USAGE_DYNAMIC; + bd.ByteWidth = m_vb_max * sizeof(vertices[0]); + bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; + bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; + + hr = (*m_dev)->CreateBuffer(&bd, NULL, &m_vb); + + if(FAILED(hr)) return false; + } + + GSVertexHW10* v = NULL; + + int next = m_vb_start + m_vb_count; + + if(next + count > m_vb_max) + { + if(SUCCEEDED(m_vb->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&v))) + { + memcpy(v, vertices, count * sizeof(vertices[0])); + + m_vb->Unmap(); + } + + m_vb_start = 0; + m_vb_count = count; + } + else + { + if(SUCCEEDED(m_vb->Map(D3D10_MAP_WRITE_NO_OVERWRITE, 0, (void**)&v))) + { + memcpy(&v[next], vertices, count * sizeof(vertices[0])); + + m_vb->Unmap(); + } + + m_vb_start = next; + m_vb_count = count; + } + + m_dev->IASetVertexBuffer(m_vb, sizeof(vertices[0])); + m_dev->IASetInputLayout(m_il); + m_dev->IASetPrimitiveTopology(prim); + + return true; +} + +bool GSTextureFX10::SetupVS(VSSelector sel, const VSConstantBuffer* cb) +{ + CComPtr vs; + + if(CRBMap >::CPair* pair = m_vs.Lookup(sel)) + { + vs = pair->m_value; + } + else + { + CStringA str[5]; + + str[0].Format("%d", sel.bpp); + str[1].Format("%d", sel.bppz); + str[2].Format("%d", sel.tme); + str[3].Format("%d", sel.fst); + str[4].Format("%d", sel.prim); + + D3D10_SHADER_MACRO macro[] = + { + {"VS_BPP", str[0]}, + {"VS_BPPZ", str[1]}, + {"VS_TME", str[2]}, + {"VS_FST", str[3]}, + {"VS_PRIM", str[4]}, + {NULL, NULL}, + }; + + D3D10_INPUT_ELEMENT_DESC layout[] = + { + {"POSITION", 0, DXGI_FORMAT_R16G16_UINT, 0, 8, D3D10_INPUT_PER_VERTEX_DATA, 0}, + {"POSITION", 1, DXGI_FORMAT_R32_UINT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0}, + {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0}, + {"TEXCOORD", 1, DXGI_FORMAT_R32_FLOAT, 0, 20, D3D10_INPUT_PER_VERTEX_DATA, 0}, + {"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 16, D3D10_INPUT_PER_VERTEX_DATA, 0}, + {"COLOR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 28, D3D10_INPUT_PER_VERTEX_DATA, 0}, + }; + + CComPtr il; + + m_dev->CompileShader(IDR_TFX10_FX, "vs_main", macro, &vs, layout, countof(layout), &il); + + if(m_il == NULL) + { + m_il = il; + } + + m_vs.SetAt(sel, vs); + } + + if(m_vs_cb_cache.Update(cb)) + { + (*m_dev)->UpdateSubresource(m_vs_cb, 0, NULL, cb, 0, 0); + } + + m_dev->VSSetShader(vs, m_vs_cb); + + return true; +} + +bool GSTextureFX10::SetupGS(GSSelector sel) +{ + HRESULT hr; + + CComPtr gs; + + if(sel.prim > 0 && (sel.iip == 0 || sel.prim == 3)) // geometry shader works in every case, but not needed + { + if(CRBMap >::CPair* pair = m_gs.Lookup(sel)) + { + gs = pair->m_value; + } + else + { + CStringA str[2]; + + str[0].Format("%d", sel.iip); + str[1].Format("%d", sel.prim); + + D3D10_SHADER_MACRO macro[] = + { + {"IIP", str[0]}, + {"PRIM", str[1]}, + {NULL, NULL}, + }; + + hr = m_dev->CompileShader(IDR_TFX10_FX, "gs_main", macro, &gs); + + m_gs.SetAt(sel, gs); + } + } + + m_dev->GSSetShader(gs); + + return true; +} + +bool GSTextureFX10::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, ID3D10ShaderResourceView* tex, ID3D10ShaderResourceView* pal) +{ + m_dev->PSSetShaderResources(tex, pal); + + UpdatePS(sel, cb, ssel); + + return true; +} + +void GSTextureFX10::UpdatePS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel) +{ + HRESULT hr; + + CComPtr ps; + + if(CRBMap >::CPair* pair = m_ps.Lookup(sel)) + { + ps = pair->m_value; + } + else + { + CStringA str[13]; + + str[0].Format("%d", sel.fst); + str[1].Format("%d", sel.wms); + str[2].Format("%d", sel.wmt); + str[3].Format("%d", sel.bpp); + str[4].Format("%d", sel.aem); + str[5].Format("%d", sel.tfx); + str[6].Format("%d", sel.tcc); + str[7].Format("%d", sel.ate); + str[8].Format("%d", sel.atst); + str[9].Format("%d", sel.fog); + str[10].Format("%d", sel.clr1); + str[11].Format("%d", sel.fba); + str[12].Format("%d", sel.aout); + + D3D10_SHADER_MACRO macro[] = + { + {"FST", str[0]}, + {"WMS", str[1]}, + {"WMT", str[2]}, + {"BPP", str[3]}, + {"AEM", str[4]}, + {"TFX", str[5]}, + {"TCC", str[6]}, + {"ATE", str[7]}, + {"ATST", str[8]}, + {"FOG", str[9]}, + {"CLR1", str[10]}, + {"FBA", str[11]}, + {"AOUT", str[12]}, + {NULL, NULL}, + }; + + hr = m_dev->CompileShader(IDR_TFX10_FX, "ps_main", macro, &ps); + + m_ps.SetAt(sel, ps); + } + + if(m_ps_cb_cache.Update(cb)) + { + (*m_dev)->UpdateSubresource(m_ps_cb, 0, NULL, cb, 0, 0); + } + + m_dev->PSSetShader(ps, m_ps_cb); + + CComPtr ss0, ss1; + + if(sel.tfx != 4) + { + if(sel.bpp >= 3 || sel.wms >= 3 || sel.wmt >= 3) + { + ssel.min = ssel.mag = 0; + } + + if(CRBMap >::CPair* pair = m_ps_ss.Lookup(ssel)) + { + ss0 = pair->m_value; + } + else + { + D3D10_SAMPLER_DESC sd; + + memset(&sd, 0, sizeof(sd)); + + sd.Filter = D3D10_ENCODE_BASIC_FILTER( + (ssel.min ? D3D10_FILTER_TYPE_LINEAR : D3D10_FILTER_TYPE_POINT), + (ssel.mag ? D3D10_FILTER_TYPE_LINEAR : D3D10_FILTER_TYPE_POINT), + D3D10_FILTER_TYPE_POINT, + false); + + sd.AddressU = ssel.tau ? D3D10_TEXTURE_ADDRESS_WRAP : D3D10_TEXTURE_ADDRESS_CLAMP; + sd.AddressV = ssel.tav ? D3D10_TEXTURE_ADDRESS_WRAP : D3D10_TEXTURE_ADDRESS_CLAMP; + sd.AddressW = D3D10_TEXTURE_ADDRESS_CLAMP; + + sd.MaxLOD = FLT_MAX; + sd.MaxAnisotropy = 16; + sd.ComparisonFunc = D3D10_COMPARISON_NEVER; + + hr = (*m_dev)->CreateSamplerState(&sd, &ss0); + + m_ps_ss.SetAt(ssel, ss0); + } + + if(sel.bpp == 3) + { + ss1 = m_palette_ss; + } + } + + m_dev->PSSetSamplerState(ss0, ss1); +} + +void GSTextureFX10::SetupRS(UINT w, UINT h, const RECT& scissor) +{ + m_dev->RSSet(w, h, &scissor); +} + +void GSTextureFX10::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf, ID3D10RenderTargetView* rtv, ID3D10DepthStencilView* dsv) +{ + UpdateOM(dssel, bsel, bf); + + m_dev->OMSetRenderTargets(rtv, dsv); +} + +void GSTextureFX10::UpdateOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf) +{ + HRESULT hr; + + CComPtr dss; + + if(CRBMap >::CPair* pair = m_om_dss.Lookup(dssel)) + { + dss = pair->m_value; + } + else + { + D3D10_DEPTH_STENCIL_DESC dsd; + + memset(&dsd, 0, sizeof(dsd)); + + if(dssel.date) + { + dsd.StencilEnable = true; + dsd.StencilReadMask = 1; + dsd.StencilWriteMask = 1; + dsd.FrontFace.StencilFunc = D3D10_COMPARISON_EQUAL; + dsd.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP; + dsd.FrontFace.StencilFailOp = D3D10_STENCIL_OP_KEEP; + dsd.FrontFace.StencilDepthFailOp = D3D10_STENCIL_OP_KEEP; + dsd.BackFace.StencilFunc = D3D10_COMPARISON_EQUAL; + dsd.BackFace.StencilPassOp = D3D10_STENCIL_OP_KEEP; + dsd.BackFace.StencilFailOp = D3D10_STENCIL_OP_KEEP; + dsd.BackFace.StencilDepthFailOp = D3D10_STENCIL_OP_KEEP; + } + + if(!(dssel.zte && dssel.ztst == 1 && !dssel.zwe)) + { + static const D3D10_COMPARISON_FUNC ztst[] = + { + D3D10_COMPARISON_NEVER, + D3D10_COMPARISON_ALWAYS, + D3D10_COMPARISON_GREATER_EQUAL, + D3D10_COMPARISON_GREATER + }; + + dsd.DepthEnable = dssel.zte; + dsd.DepthWriteMask = dssel.zwe ? D3D10_DEPTH_WRITE_MASK_ALL : D3D10_DEPTH_WRITE_MASK_ZERO; + dsd.DepthFunc = ztst[dssel.ztst]; + } + + hr = (*m_dev)->CreateDepthStencilState(&dsd, &dss); + + m_om_dss.SetAt(dssel, dss); + } + + m_dev->OMSetDepthStencilState(dss, 1); + + CComPtr bs; + + if(CRBMap >::CPair* pair = m_om_bs.Lookup(bsel)) + { + bs = pair->m_value; + } + else + { + D3D10_BLEND_DESC bd; + + memset(&bd, 0, sizeof(bd)); + + bd.BlendEnable[0] = bsel.abe; + + if(bsel.abe) + { + // (A:Cs/Cd/0 - B:Cs/Cd/0) * C:As/Ad/FIX + D:Cs/Cd/0 + + static const struct {int bogus; D3D10_BLEND_OP op; D3D10_BLEND src, dst;} map[3*3*3*3] = + { + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 0000: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 0001: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 0002: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 0010: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 0011: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 0012: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 0020: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 0021: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 0022: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {1, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_SRC1_ALPHA}, // * 0100: (Cs - Cd)*As + Cs ==> Cs*(As + 1) - Cd*As + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_INV_SRC1_ALPHA}, // 0101: (Cs - Cd)*As + Cd ==> Cs*As + Cd*(1 - As) + {0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_SRC1_ALPHA}, // 0102: (Cs - Cd)*As + 0 ==> Cs*As - Cd*As + {1, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_DEST_ALPHA}, // * 0110: (Cs - Cd)*Ad + Cs ==> Cs*(Ad + 1) - Cd*Ad + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_INV_DEST_ALPHA}, // 0111: (Cs - Cd)*Ad + Cd ==> Cs*Ad + Cd*(1 - Ad) + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_DEST_ALPHA}, // 0112: (Cs - Cd)*Ad + 0 ==> Cs*Ad - Cd*Ad + {1, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_BLEND_FACTOR}, // * 0120: (Cs - Cd)*F + Cs ==> Cs*(F + 1) - Cd*F + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_INV_BLEND_FACTOR}, // 0121: (Cs - Cd)*F + Cd ==> Cs*F + Cd*(1 - F) + {0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_BLEND_FACTOR}, // 0122: (Cs - Cd)*F + 0 ==> Cs*F - Cd*F + {1, D3D10_BLEND_OP_ADD, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_ZERO}, // * 0200: (Cs - 0)*As + Cs ==> Cs*(As + 1) + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_ONE}, // 0201: (Cs - 0)*As + Cd ==> Cs*As + Cd + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_ZERO}, // 0202: (Cs - 0)*As + 0 ==> Cs*As + {1, D3D10_BLEND_OP_ADD, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_ZERO}, // * 0210: (Cs - 0)*Ad + Cs ==> Cs*(Ad + 1) + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_ONE}, // 0211: (Cs - 0)*Ad + Cd ==> Cs*Ad + Cd + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_ZERO}, // 0212: (Cs - 0)*Ad + 0 ==> Cs*Ad + {1, D3D10_BLEND_OP_ADD, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_ZERO}, // * 0220: (Cs - 0)*F + Cs ==> Cs*(F + 1) + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_ONE}, // 0221: (Cs - 0)*F + Cd ==> Cs*F + Cd + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_ZERO}, // 0222: (Cs - 0)*F + 0 ==> Cs*F + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_INV_SRC1_ALPHA, D3D10_BLEND_SRC1_ALPHA}, // 1000: (Cd - Cs)*As + Cs ==> Cd*As + Cs*(1 - As) + {1, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_SRC1_ALPHA}, // * 1001: (Cd - Cs)*As + Cd ==> Cd*(As + 1) - Cs*As + {0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_SRC1_ALPHA}, // 1002: (Cd - Cs)*As + 0 ==> Cd*As - Cs*As + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_INV_DEST_ALPHA, D3D10_BLEND_DEST_ALPHA}, // 1010: (Cd - Cs)*Ad + Cs ==> Cd*Ad + Cs*(1 - Ad) + {1, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_DEST_ALPHA}, // * 1011: (Cd - Cs)*Ad + Cd ==> Cd*(Ad + 1) - Cs*Ad + {0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_DEST_ALPHA}, // 1012: (Cd - Cs)*Ad + 0 ==> Cd*Ad - Cs*Ad + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_INV_BLEND_FACTOR, D3D10_BLEND_BLEND_FACTOR}, // 1020: (Cd - Cs)*F + Cs ==> Cd*F + Cs*(1 - F) + {1, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_BLEND_FACTOR},// * 1021: (Cd - Cs)*F + Cd ==> Cd*(F + 1) - Cs*F + {0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_BLEND_FACTOR},// 1022: (Cd - Cs)*F + 0 ==> Cd*F - Cs*F + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 1100: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 1101: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 1102: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 1110: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 1111: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 1112: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 1120: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 1121: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 1122: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_SRC1_ALPHA}, // 1200: (Cd - 0)*As + Cs ==> Cs + Cd*As + {2, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_COLOR, D3D10_BLEND_SRC1_ALPHA}, // ** 1201: (Cd - 0)*As + Cd ==> Cd*(1 + As) // ffxii main menu background glow effect + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_SRC1_ALPHA}, // 1202: (Cd - 0)*As + 0 ==> Cd*As + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_DEST_ALPHA}, // 1210: (Cd - 0)*Ad + Cs ==> Cs + Cd*Ad + {2, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_COLOR, D3D10_BLEND_DEST_ALPHA}, // ** 1211: (Cd - 0)*Ad + Cd ==> Cd*(1 + Ad) + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_DEST_ALPHA}, // 1212: (Cd - 0)*Ad + 0 ==> Cd*Ad + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_BLEND_FACTOR}, // 1220: (Cd - 0)*F + Cs ==> Cs + Cd*F + {2, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_COLOR, D3D10_BLEND_BLEND_FACTOR}, // ** 1221: (Cd - 0)*F + Cd ==> Cd*(1 + F) + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_BLEND_FACTOR}, // 1222: (Cd - 0)*F + 0 ==> Cd*F + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_INV_SRC1_ALPHA, D3D10_BLEND_ZERO}, // 2000: (0 - Cs)*As + Cs ==> Cs*(1 - As) + {0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_ONE}, // 2001: (0 - Cs)*As + Cd ==> Cd - Cs*As + {0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_ZERO}, // 2002: (0 - Cs)*As + 0 ==> 0 - Cs*As + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_INV_DEST_ALPHA, D3D10_BLEND_ZERO}, // 2010: (0 - Cs)*Ad + Cs ==> Cs*(1 - Ad) + {0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_ONE}, // 2011: (0 - Cs)*Ad + Cd ==> Cd - Cs*Ad + {0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_ZERO}, // 2012: (0 - Cs)*Ad + 0 ==> 0 - Cs*Ad + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_INV_BLEND_FACTOR, D3D10_BLEND_ZERO}, // 2020: (0 - Cs)*F + Cs ==> Cs*(1 - F) + {0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_ONE}, // 2021: (0 - Cs)*F + Cd ==> Cd - Cs*F + {0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_ZERO}, // 2022: (0 - Cs)*F + 0 ==> 0 - Cs*F + {0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_ONE, D3D10_BLEND_SRC1_ALPHA}, // 2100: (0 - Cd)*As + Cs ==> Cs - Cd*As + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_INV_SRC1_ALPHA}, // 2101: (0 - Cd)*As + Cd ==> Cd*(1 - As) + {0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_ZERO, D3D10_BLEND_SRC1_ALPHA}, // 2102: (0 - Cd)*As + 0 ==> 0 - Cd*As + {0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_ONE, D3D10_BLEND_DEST_ALPHA}, // 2110: (0 - Cd)*Ad + Cs ==> Cs - Cd*Ad + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_INV_DEST_ALPHA}, // 2111: (0 - Cd)*Ad + Cd ==> Cd*(1 - Ad) + {0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_ONE, D3D10_BLEND_DEST_ALPHA}, // 2112: (0 - Cd)*Ad + 0 ==> 0 - Cd*Ad + {0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_ONE, D3D10_BLEND_BLEND_FACTOR}, // 2120: (0 - Cd)*F + Cs ==> Cs - Cd*F + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_INV_BLEND_FACTOR}, // 2121: (0 - Cd)*F + Cd ==> Cd*(1 - F) + {0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_ONE, D3D10_BLEND_BLEND_FACTOR}, // 2122: (0 - Cd)*F + 0 ==> 0 - Cd*F + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 2200: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 2201: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 2202: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 2210: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 2211: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 2212: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 2220: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 2221: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 2222: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + }; + + // bogus: 0100, 0110, 0120, 0200, 0210, 0220, 1001, 1011, 1021 + + // tricky: 1201, 1211, 1221 + // + // Source.rgb = float3(1, 1, 1); + // 1201 Cd*(1 + As) => Source * Dest color + Dest * Source1 alpha + // 1211 Cd*(1 + Ad) => Source * Dest color + Dest * Dest alpha + // 1221 Cd*(1 + F) => Source * Dest color + Dest * Factor + + int i = ((bsel.a * 3 + bsel.b) * 3 + bsel.c) * 3 + bsel.d; + + bd.BlendOp = map[i].op; + bd.SrcBlend = map[i].src; + bd.DestBlend = map[i].dst; + bd.BlendOpAlpha = D3D10_BLEND_OP_ADD; + bd.SrcBlendAlpha = D3D10_BLEND_ONE; + bd.DestBlendAlpha = D3D10_BLEND_ZERO; + + if(map[i].bogus == 1) + { + ASSERT(0); + + (bsel.a == 0 ? bd.SrcBlend : bd.DestBlend) = D3D10_BLEND_ONE; + } + } + + if(bsel.wr) bd.RenderTargetWriteMask[0] |= D3D10_COLOR_WRITE_ENABLE_RED; + if(bsel.wg) bd.RenderTargetWriteMask[0] |= D3D10_COLOR_WRITE_ENABLE_GREEN; + if(bsel.wb) bd.RenderTargetWriteMask[0] |= D3D10_COLOR_WRITE_ENABLE_BLUE; + if(bsel.wa) bd.RenderTargetWriteMask[0] |= D3D10_COLOR_WRITE_ENABLE_ALPHA; + + hr = (*m_dev)->CreateBlendState(&bd, &bs); + + m_om_bs.SetAt(bsel, bs); + } + + m_dev->OMSetBlendState(bs, bf); +} + +void GSTextureFX10::Draw() +{ + m_dev->DrawPrimitive(m_vb_count, m_vb_start); +} diff --git a/plugins/GSdx/GSTextureFX10.h b/plugins/GSdx/GSTextureFX10.h index 823176ee14..6dcaedc29e 100644 --- a/plugins/GSdx/GSTextureFX10.h +++ b/plugins/GSdx/GSTextureFX10.h @@ -1,248 +1,248 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSDevice10.h" - -class GSTextureFX10 -{ -public: - #pragma pack(push, 1) - - __declspec(align(16)) struct VSConstantBuffer - { - GSVector4 VertexScale; - GSVector4 VertexOffset; - GSVector2 TextureScale; - float _pad[2]; - - struct VSConstantBuffer() {memset(this, 0, sizeof(*this));} - - __forceinline bool Update(const VSConstantBuffer* cb) - { - GSVector4i* a = (GSVector4i*)this; - GSVector4i* b = (GSVector4i*)cb; - - GSVector4i b0 = b[0]; - GSVector4i b1 = b[1]; - GSVector4i b2 = b[2]; - - if(!((a[0] == b0) & (a[1] == b1) & (a[2] == b2)).alltrue()) - { - a[0] = b0; - a[1] = b1; - a[2] = b2; - - return true; - } - - return false; - } - }; - - union VSSelector - { - struct - { - DWORD bpp:3; - DWORD bppz:2; - DWORD tme:1; - DWORD fst:1; - DWORD prim:3; - }; - - DWORD dw; - - operator DWORD() {return dw & 0x3ff;} - }; - - __declspec(align(16)) struct PSConstantBuffer - { - GSVector4 FogColor; - float MINU; - float MAXU; - float MINV; - float MAXV; - DWORD UMSK; - DWORD UFIX; - DWORD VMSK; - DWORD VFIX; - float TA0; - float TA1; - float AREF; - float _pad[1]; - GSVector2 WH; - GSVector2 rWrH; - - struct PSConstantBuffer() {memset(this, 0, sizeof(*this));} - - __forceinline bool Update(const PSConstantBuffer* cb) - { - GSVector4i* a = (GSVector4i*)this; - GSVector4i* b = (GSVector4i*)cb; - - GSVector4i b0 = b[0]; - GSVector4i b1 = b[1]; - GSVector4i b2 = b[2]; - GSVector4i b3 = b[3]; - GSVector4i b4 = b[4]; - - if(!((a[0] == b0) & (a[1] == b1) & (a[2] == b2) & (a[3] == b3) & (a[4] == b4)).alltrue()) - { - a[0] = b0; - a[1] = b1; - a[2] = b2; - a[3] = b3; - a[4] = b4; - - return true; - } - - return false; - } - }; - - union PSSelector - { - struct - { - DWORD fst:1; - DWORD wms:2; - DWORD wmt:2; - DWORD bpp:3; - DWORD aem:1; - DWORD tfx:3; - DWORD tcc:1; - DWORD ate:1; - DWORD atst:3; - DWORD fog:1; - DWORD clr1:1; - DWORD fba:1; - DWORD aout:1; - }; - - DWORD dw; - - operator DWORD() {return dw & 0x1fffff;} - }; - - union GSSelector - { - struct - { - DWORD iip:1; - DWORD prim:2; - }; - - DWORD dw; - - operator DWORD() {return dw & 0x7;} - }; - - union PSSamplerSelector - { - struct - { - DWORD tau:1; - DWORD tav:1; - DWORD min:1; - DWORD mag:1; - }; - - DWORD dw; - - operator DWORD() {return dw & 0xf;} - }; - - union OMDepthStencilSelector - { - struct - { - DWORD zte:1; - DWORD ztst:2; - DWORD zwe:1; - DWORD date:1; - }; - - DWORD dw; - - operator DWORD() {return dw & 0x1f;} - }; - - union OMBlendSelector - { - struct - { - DWORD abe:1; - DWORD a:2; - DWORD b:2; - DWORD c:2; - DWORD d:2; - DWORD wr:1; - DWORD wg:1; - DWORD wb:1; - DWORD wa:1; - }; - - DWORD dw; - - operator DWORD() {return dw & 0x1fff;} - }; - - #pragma pack(pop) - -private: - GSDevice10* m_dev; - CComPtr m_il; - CRBMapC > m_vs; - CComPtr m_vs_cb; - CRBMapC > m_gs; - CRBMapC > m_ps; - CComPtr m_ps_cb; - CRBMapC > m_ps_ss; - CComPtr m_palette_ss; - CRBMapC > m_om_dss; - CRBMapC > m_om_bs; - - CComPtr m_vb, m_vb_old; - int m_vb_max; - int m_vb_start; - int m_vb_count; - - VSConstantBuffer m_vs_cb_cache; - PSConstantBuffer m_ps_cb_cache; - -public: - GSTextureFX10(); - - bool Create(GSDevice10* dev); - - bool SetupIA(const GSVertexHW10* vertices, int count, D3D10_PRIMITIVE_TOPOLOGY prim); - bool SetupVS(VSSelector sel, const VSConstantBuffer* cb); - bool SetupGS(GSSelector sel); - bool SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, ID3D10ShaderResourceView* tex, ID3D10ShaderResourceView* pal); - void UpdatePS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel); - void SetupRS(UINT w, UINT h, const RECT& scissor); - void SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf, ID3D10RenderTargetView* rtv, ID3D10DepthStencilView* dsv); - void UpdateOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf); - void Draw(); -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSDevice10.h" + +class GSTextureFX10 +{ +public: + #pragma pack(push, 1) + + __declspec(align(16)) struct VSConstantBuffer + { + GSVector4 VertexScale; + GSVector4 VertexOffset; + GSVector2 TextureScale; + float _pad[2]; + + struct VSConstantBuffer() {memset(this, 0, sizeof(*this));} + + __forceinline bool Update(const VSConstantBuffer* cb) + { + GSVector4i* a = (GSVector4i*)this; + GSVector4i* b = (GSVector4i*)cb; + + GSVector4i b0 = b[0]; + GSVector4i b1 = b[1]; + GSVector4i b2 = b[2]; + + if(!((a[0] == b0) & (a[1] == b1) & (a[2] == b2)).alltrue()) + { + a[0] = b0; + a[1] = b1; + a[2] = b2; + + return true; + } + + return false; + } + }; + + union VSSelector + { + struct + { + DWORD bpp:3; + DWORD bppz:2; + DWORD tme:1; + DWORD fst:1; + DWORD prim:3; + }; + + DWORD dw; + + operator DWORD() {return dw & 0x3ff;} + }; + + __declspec(align(16)) struct PSConstantBuffer + { + GSVector4 FogColor; + float MINU; + float MAXU; + float MINV; + float MAXV; + DWORD UMSK; + DWORD UFIX; + DWORD VMSK; + DWORD VFIX; + float TA0; + float TA1; + float AREF; + float _pad[1]; + GSVector2 WH; + GSVector2 rWrH; + + struct PSConstantBuffer() {memset(this, 0, sizeof(*this));} + + __forceinline bool Update(const PSConstantBuffer* cb) + { + GSVector4i* a = (GSVector4i*)this; + GSVector4i* b = (GSVector4i*)cb; + + GSVector4i b0 = b[0]; + GSVector4i b1 = b[1]; + GSVector4i b2 = b[2]; + GSVector4i b3 = b[3]; + GSVector4i b4 = b[4]; + + if(!((a[0] == b0) & (a[1] == b1) & (a[2] == b2) & (a[3] == b3) & (a[4] == b4)).alltrue()) + { + a[0] = b0; + a[1] = b1; + a[2] = b2; + a[3] = b3; + a[4] = b4; + + return true; + } + + return false; + } + }; + + union PSSelector + { + struct + { + DWORD fst:1; + DWORD wms:2; + DWORD wmt:2; + DWORD bpp:3; + DWORD aem:1; + DWORD tfx:3; + DWORD tcc:1; + DWORD ate:1; + DWORD atst:3; + DWORD fog:1; + DWORD clr1:1; + DWORD fba:1; + DWORD aout:1; + }; + + DWORD dw; + + operator DWORD() {return dw & 0x1fffff;} + }; + + union GSSelector + { + struct + { + DWORD iip:1; + DWORD prim:2; + }; + + DWORD dw; + + operator DWORD() {return dw & 0x7;} + }; + + union PSSamplerSelector + { + struct + { + DWORD tau:1; + DWORD tav:1; + DWORD min:1; + DWORD mag:1; + }; + + DWORD dw; + + operator DWORD() {return dw & 0xf;} + }; + + union OMDepthStencilSelector + { + struct + { + DWORD zte:1; + DWORD ztst:2; + DWORD zwe:1; + DWORD date:1; + }; + + DWORD dw; + + operator DWORD() {return dw & 0x1f;} + }; + + union OMBlendSelector + { + struct + { + DWORD abe:1; + DWORD a:2; + DWORD b:2; + DWORD c:2; + DWORD d:2; + DWORD wr:1; + DWORD wg:1; + DWORD wb:1; + DWORD wa:1; + }; + + DWORD dw; + + operator DWORD() {return dw & 0x1fff;} + }; + + #pragma pack(pop) + +private: + GSDevice10* m_dev; + CComPtr m_il; + CRBMapC > m_vs; + CComPtr m_vs_cb; + CRBMapC > m_gs; + CRBMapC > m_ps; + CComPtr m_ps_cb; + CRBMapC > m_ps_ss; + CComPtr m_palette_ss; + CRBMapC > m_om_dss; + CRBMapC > m_om_bs; + + CComPtr m_vb, m_vb_old; + int m_vb_max; + int m_vb_start; + int m_vb_count; + + VSConstantBuffer m_vs_cb_cache; + PSConstantBuffer m_ps_cb_cache; + +public: + GSTextureFX10(); + + bool Create(GSDevice10* dev); + + bool SetupIA(const GSVertexHW10* vertices, int count, D3D10_PRIMITIVE_TOPOLOGY prim); + bool SetupVS(VSSelector sel, const VSConstantBuffer* cb); + bool SetupGS(GSSelector sel); + bool SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, ID3D10ShaderResourceView* tex, ID3D10ShaderResourceView* pal); + void UpdatePS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel); + void SetupRS(UINT w, UINT h, const RECT& scissor); + void SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf, ID3D10RenderTargetView* rtv, ID3D10DepthStencilView* dsv); + void UpdateOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf); + void Draw(); +}; diff --git a/plugins/GSdx/GSTextureFX9.cpp b/plugins/GSdx/GSTextureFX9.cpp index de10336849..82c213d165 100644 --- a/plugins/GSdx/GSTextureFX9.cpp +++ b/plugins/GSdx/GSTextureFX9.cpp @@ -1,464 +1,464 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GSTextureFX9.h" -#include "resource.h" - -GSTextureFX9::GSTextureFX9() - : m_dev(NULL) -{ -} - -bool GSTextureFX9::Create(GSDevice9* dev) -{ - m_dev = dev; - - VSSelector sel; - - sel.bppz = 0; - sel.tme = 0; - sel.fst = 0; - sel.logz = 0; - - VSConstantBuffer cb; - - SetupVS(sel, &cb); // creates layout - - return true; -} - -bool GSTextureFX9::CreateMskFix(GSTexture9& t, DWORD size, DWORD msk, DWORD fix) -{ - DWORD hash = (size << 20) | (msk << 10) | fix; - - if(CRBMap::CPair* pair = m_mskfix.Lookup(hash)) - { - t = pair->m_value; - } - else - { - if(!m_dev->CreateTexture(t, size, 1, D3DFMT_R32F)) - { - return false; - } - - BYTE* bits; - int pitch; - - if(t.Map(&bits, pitch)) - { - for(DWORD i = 0; i < size; i++) - { - ((float*)bits)[i] = (float)((i & msk) | fix) / size; - } - - t.Unmap(); - } - - m_mskfix.SetAt(hash, t); - } - - return true; -} - -bool GSTextureFX9::SetupIA(const GSVertexHW9* vertices, UINT count, D3DPRIMITIVETYPE prim) -{ - m_dev->IASetVertexBuffer(count, vertices); - m_dev->IASetInputLayout(m_il); - m_dev->IASetPrimitiveTopology(prim); - - return true; -} - -bool GSTextureFX9::SetupVS(VSSelector sel, const VSConstantBuffer* cb) -{ - CComPtr vs; - - if(CRBMap >::CPair* pair = m_vs.Lookup(sel)) - { - vs = pair->m_value; - } - else - { - CStringA str[4]; - - str[0].Format("%d", sel.bppz); - str[1].Format("%d", sel.tme); - str[2].Format("%d", sel.fst); - str[3].Format("%d", sel.logz); - - D3DXMACRO macro[] = - { - {"VS_BPPZ", str[0]}, - {"VS_TME", str[1]}, - {"VS_FST", str[2]}, - {"VS_LOGZ", str[3]}, - {NULL, NULL}, - }; - - static const D3DVERTEXELEMENT9 layout[] = - { - {0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, - {0, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, - {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1}, - {0, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, - D3DDECL_END() - }; - - CComPtr il; - - m_dev->CompileShader(IDR_TFX9_FX, "vs_main", macro, &vs, layout, countof(layout), &il); - - if(m_il == NULL) - { - m_il = il; - } - - m_vs.SetAt(sel, vs); - } - - m_dev->VSSetShader(vs, (const float*)cb, sizeof(*cb) / sizeof(GSVector4)); - - return true; -} - -bool GSTextureFX9::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, IDirect3DTexture9* tex, IDirect3DTexture9* pal, bool psrr) -{ - m_dev->PSSetShaderResources(tex, pal); - - if(tex && psrr) - { - if(sel.wms == 3) - { - D3DSURFACE_DESC desc; - tex->GetLevelDesc(0, &desc); - - GSTexture9 t; - CreateMskFix(t, desc.Width, cb->UMSK, cb->UFIX); - - (*m_dev)->SetTexture(2, t); - } - - if(sel.wmt == 3) - { - D3DSURFACE_DESC desc; - tex->GetLevelDesc(0, &desc); - - GSTexture9 t; - CreateMskFix(t, desc.Height, cb->VMSK, cb->VFIX); - - (*m_dev)->SetTexture(3, t); - } - } - - UpdatePS(sel, cb, ssel, psrr); - - return true; -} - -void GSTextureFX9::UpdatePS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, bool psrr) -{ - HRESULT hr; - - if(!psrr) - { - if(sel.wms == 3) sel.wms = 0; - if(sel.wmt == 3) sel.wmt = 0; - } - - CComPtr ps; - - if(CRBMap >::CPair* pair = m_ps.Lookup(sel)) - { - ps = pair->m_value; - } - else - { - CStringA str[12]; - - str[0].Format("%d", sel.fst); - str[1].Format("%d", sel.wms); - str[2].Format("%d", sel.wmt); - str[3].Format("%d", sel.bpp); - str[4].Format("%d", sel.aem); - str[5].Format("%d", sel.tfx); - str[6].Format("%d", sel.tcc); - str[7].Format("%d", sel.ate); - str[8].Format("%d", sel.atst); - str[9].Format("%d", sel.fog); - str[10].Format("%d", sel.clr1); - str[11].Format("%d", sel.rt); - - D3DXMACRO macro[] = - { - {"FST", str[0]}, - {"WMS", str[1]}, - {"WMT", str[2]}, - {"BPP", str[3]}, - {"AEM", str[4]}, - {"TFX", str[5]}, - {"TCC", str[6]}, - {"ATE", str[7]}, - {"ATST", str[8]}, - {"FOG", str[9]}, - {"CLR1", str[10]}, - {"RT", str[11]}, - {NULL, NULL}, - }; - - hr = m_dev->CompileShader(IDR_TFX9_FX, "ps_main", macro, &ps); - - m_ps.SetAt(sel, ps); - } - - m_dev->PSSetShader(ps, (const float*)cb, sizeof(*cb) / sizeof(GSVector4)); - - Direct3DSamplerState9* ss = NULL; - - if(sel.tfx != 4) - { - if(sel.bpp >= 3 || sel.wms >= 3 || sel.wmt >= 3) - { - ssel.min = ssel.mag = 0; - } - - if(CRBMap::CPair* pair = m_ps_ss.Lookup(ssel)) - { - ss = pair->m_value; - } - else - { - ss = new Direct3DSamplerState9(); - - memset(ss, 0, sizeof(*ss)); - - ss->FilterMin[0] = ssel.min ? D3DTEXF_LINEAR : D3DTEXF_POINT; - ss->FilterMag[0] = ssel.mag ? D3DTEXF_LINEAR : D3DTEXF_POINT; - ss->FilterMin[1] = D3DTEXF_POINT; - ss->FilterMag[1] = D3DTEXF_POINT; - - ss->AddressU = ssel.tau ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP; - ss->AddressV = ssel.tav ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP; - - m_ps_ss.SetAt(ssel, ss); - } - } - - m_dev->PSSetSamplerState(ss); -} - -void GSTextureFX9::SetupRS(int w, int h, const RECT& scissor) -{ - m_dev->RSSet(w, h, &scissor); -} - -void GSTextureFX9::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, BYTE bf, IDirect3DSurface9* rt, IDirect3DSurface9* ds) -{ - UpdateOM(dssel, bsel, bf); - - m_dev->OMSetRenderTargets(rt, ds); -} - -void GSTextureFX9::UpdateOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, BYTE bf) -{ - Direct3DDepthStencilState9* dss = NULL; - - if(CRBMap::CPair* pair = m_om_dss.Lookup(dssel)) - { - dss = pair->m_value; - } - else - { - dss = new Direct3DDepthStencilState9(); - - memset(dss, 0, sizeof(*dss)); - - if(dssel.date || dssel.fba) - { - dss->StencilEnable = true; - dss->StencilReadMask = 1; - dss->StencilWriteMask = 2; - dss->StencilFunc = dssel.date ? D3DCMP_EQUAL : D3DCMP_ALWAYS; - dss->StencilPassOp = dssel.fba ? D3DSTENCILOP_REPLACE : D3DSTENCILOP_KEEP; - dss->StencilFailOp = dssel.fba ? D3DSTENCILOP_ZERO : D3DSTENCILOP_KEEP; - dss->StencilDepthFailOp = dssel.fba ? D3DSTENCILOP_ZERO : D3DSTENCILOP_KEEP; - } - - if(!(dssel.zte && dssel.ztst == 1 && !dssel.zwe)) - { - static const D3DCMPFUNC ztst[] = - { - D3DCMP_NEVER, - D3DCMP_ALWAYS, - D3DCMP_GREATEREQUAL, - D3DCMP_GREATER - }; - - dss->DepthEnable = dssel.zte; - dss->DepthWriteMask = dssel.zwe; - dss->DepthFunc = ztst[dssel.ztst]; - } - - m_om_dss.SetAt(dssel, dss); - } - - m_dev->OMSetDepthStencilState(dss, 3); - - Direct3DBlendState9* bs = NULL; - - if(CRBMap::CPair* pair = m_om_bs.Lookup(bsel)) - { - bs = pair->m_value; - } - else - { - bs = new Direct3DBlendState9(); - - memset(bs, 0, sizeof(*bs)); - - bs->BlendEnable = bsel.abe; - - if(bsel.abe) - { - // (A:Cs/Cd/0 - B:Cs/Cd/0) * C:As/Ad/FIX + D:Cs/Cd/0 - - static const struct {int bogus; D3DBLENDOP op; D3DBLEND src, dst;} map[3*3*3*3] = - { - {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 0000: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 0001: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 0002: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 - {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 0010: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 0011: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 0012: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 - {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 0020: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 0021: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 0022: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 - {1, D3DBLENDOP_SUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // * 0100: (Cs - Cd)*As + Cs ==> Cs*(As + 1) - Cd*As - {0, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA}, // 0101: (Cs - Cd)*As + Cd ==> Cs*As + Cd*(1 - As) - {0, D3DBLENDOP_SUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // 0102: (Cs - Cd)*As + 0 ==> Cs*As - Cd*As - {1, D3DBLENDOP_SUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // * 0110: (Cs - Cd)*Ad + Cs ==> Cs*(Ad + 1) - Cd*Ad - {0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_INVDESTALPHA}, // 0111: (Cs - Cd)*Ad + Cd ==> Cs*Ad + Cd*(1 - Ad) - {0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // 0112: (Cs - Cd)*Ad + 0 ==> Cs*Ad - Cd*Ad - {1, D3DBLENDOP_SUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR}, // * 0120: (Cs - Cd)*F + Cs ==> Cs*(F + 1) - Cd*F - {0, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_INVBLENDFACTOR}, // 0121: (Cs - Cd)*F + Cd ==> Cs*F + Cd*(1 - F) - {0, D3DBLENDOP_SUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR}, // 0122: (Cs - Cd)*F + 0 ==> Cs*F - Cd*F - {1, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // * 0200: (Cs - 0)*As + Cs ==> Cs*(As + 1) - {0, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ONE}, // 0201: (Cs - 0)*As + Cd ==> Cs*As + Cd - {0, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // 0202: (Cs - 0)*As + 0 ==> Cs*As - {1, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // * 0210: (Cs - 0)*Ad + Cs ==> Cs*(As + 1) - {0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_ONE}, // 0211: (Cs - 0)*Ad + Cd ==> Cs*Ad + Cd - {0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_ZERO}, // 0212: (Cs - 0)*Ad + 0 ==> Cs*Ad - {1, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_ZERO}, // * 0220: (Cs - 0)*F + Cs ==> Cs*(F + 1) - {0, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_ONE}, // 0221: (Cs - 0)*F + Cd ==> Cs*F + Cd - {0, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_ZERO}, // 0222: (Cs - 0)*F + 0 ==> Cs*F - {0, D3DBLENDOP_ADD, D3DBLEND_INVSRCALPHA, D3DBLEND_SRCALPHA}, // 1000: (Cd - Cs)*As + Cs ==> Cd*As + Cs*(1 - As) - {1, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // * 1001: (Cd - Cs)*As + Cd ==> Cd*(As + 1) - Cs*As - {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // 1002: (Cd - Cs)*As + 0 ==> Cd*As - Cs*As - {0, D3DBLENDOP_ADD, D3DBLEND_INVDESTALPHA, D3DBLEND_DESTALPHA}, // 1010: (Cd - Cs)*Ad + Cs ==> Cd*Ad + Cs*(1 - Ad) - {1, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // * 1011: (Cd - Cs)*Ad + Cd ==> Cd*(Ad + 1) - Cs*Ad - {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // 1012: (Cd - Cs)*Ad + 0 ==> Cd*Ad - Cs*Ad - {0, D3DBLENDOP_ADD, D3DBLEND_INVBLENDFACTOR, D3DBLEND_BLENDFACTOR}, // 1020: (Cd - Cs)*F + Cs ==> Cd*F + Cs*(1 - F) - {1, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR},// * 1021: (Cd - Cs)*F + Cd ==> Cd*(F + 1) - Cs*F - {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR},// 1022: (Cd - Cs)*F + 0 ==> Cd*F - Cs*F - {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 1100: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 1101: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 1102: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 - {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 1110: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 1111: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 1112: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 - {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 1120: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 1121: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 1122: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 - {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_SRCALPHA}, // 1200: (Cd - 0)*As + Cs ==> Cs + Cd*As - {2, D3DBLENDOP_ADD, D3DBLEND_DESTCOLOR, D3DBLEND_SRCALPHA}, // ** 1201: (Cd - 0)*As + Cd ==> Cd*(1 + As) // ffxii main menu background glow effect - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_SRCALPHA}, // 1202: (Cd - 0)*As + 0 ==> Cd*As - {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_DESTALPHA}, // 1210: (Cd - 0)*Ad + Cs ==> Cs + Cd*Ad - {2, D3DBLENDOP_ADD, D3DBLEND_DESTCOLOR, D3DBLEND_DESTALPHA}, // ** 1211: (Cd - 0)*Ad + Cd ==> Cd*(1 + Ad) - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_DESTALPHA}, // 1212: (Cd - 0)*Ad + 0 ==> Cd*Ad - {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_BLENDFACTOR}, // 1220: (Cd - 0)*F + Cs ==> Cs + Cd*F - {2, D3DBLENDOP_ADD, D3DBLEND_DESTCOLOR, D3DBLEND_BLENDFACTOR}, // ** 1221: (Cd - 0)*F + Cd ==> Cd*(1 + F) - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_BLENDFACTOR}, // 1222: (Cd - 0)*F + 0 ==> Cd*F - {0, D3DBLENDOP_ADD, D3DBLEND_INVSRCALPHA, D3DBLEND_ZERO}, // 2000: (0 - Cs)*As + Cs ==> Cs*(1 - As) - {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_ONE}, // 2001: (0 - Cs)*As + Cd ==> Cd - Cs*As - {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // 2002: (0 - Cs)*As + 0 ==> 0 - Cs*As - {0, D3DBLENDOP_ADD, D3DBLEND_INVDESTALPHA, D3DBLEND_ZERO}, // 2010: (0 - Cs)*Ad + Cs ==> Cs*(1 - Ad) - {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_ONE}, // 2011: (0 - Cs)*Ad + Cd ==> Cd - Cs*Ad - {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_ZERO}, // 2012: (0 - Cs)*Ad + 0 ==> 0 - Cs*Ad - {0, D3DBLENDOP_ADD, D3DBLEND_INVBLENDFACTOR, D3DBLEND_ZERO}, // 2020: (0 - Cs)*F + Cs ==> Cs*(1 - F) - {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_ONE}, // 2021: (0 - Cs)*F + Cd ==> Cd - Cs*F - {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_ZERO}, // 2022: (0 - Cs)*F + 0 ==> 0 - Cs*F - {0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_SRCALPHA}, // 2100: (0 - Cd)*As + Cs ==> Cs - Cd*As - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_INVSRCALPHA}, // 2101: (0 - Cd)*As + Cd ==> Cd*(1 - As) - {0, D3DBLENDOP_SUBTRACT, D3DBLEND_ZERO, D3DBLEND_SRCALPHA}, // 2102: (0 - Cd)*As + 0 ==> 0 - Cd*As - {0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_DESTALPHA}, // 2110: (0 - Cd)*Ad + Cs ==> Cs - Cd*Ad - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_INVDESTALPHA}, // 2111: (0 - Cd)*Ad + Cd ==> Cd*(1 - Ad) - {0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_DESTALPHA}, // 2112: (0 - Cd)*Ad + 0 ==> 0 - Cd*Ad - {0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_BLENDFACTOR}, // 2120: (0 - Cd)*F + Cs ==> Cs - Cd*F - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_INVBLENDFACTOR}, // 2121: (0 - Cd)*F + Cd ==> Cd*(1 - F) - {0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_BLENDFACTOR}, // 2122: (0 - Cd)*F + 0 ==> 0 - Cd*F - {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 2200: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 2201: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 2202: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 - {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 2210: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 2211: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 2212: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 - {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 2220: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 2221: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd - {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 2222: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 - }; - - // bogus: 0100, 0110, 0120, 0200, 0210, 0220, 1001, 1011, 1021 - - // tricky: 1201, 1211, 1221 - // - // Source.rgb = float3(1, 1, 1); - // 1201 Cd*(1 + As) => Source * Dest color + Dest * Source alpha - // 1211 Cd*(1 + Ad) => Source * Dest color + Dest * Dest alpha - // 1221 Cd*(1 + F) => Source * Dest color + Dest * Factor - - int i = ((bsel.a * 3 + bsel.b) * 3 + bsel.c) * 3 + bsel.d; - - bs->BlendOp = map[i].op; - bs->SrcBlend = map[i].src; - bs->DestBlend = map[i].dst; - bs->BlendOpAlpha = D3DBLENDOP_ADD; - bs->SrcBlendAlpha = D3DBLEND_ONE; - bs->DestBlendAlpha = D3DBLEND_ZERO; - - if(map[i].bogus == 1) - { - ASSERT(0); - - (bsel.a == 0 ? bs->SrcBlend : bs->DestBlend) = D3DBLEND_ONE; - } - } - - if(bsel.wr) bs->RenderTargetWriteMask |= D3DCOLORWRITEENABLE_RED; - if(bsel.wg) bs->RenderTargetWriteMask |= D3DCOLORWRITEENABLE_GREEN; - if(bsel.wb) bs->RenderTargetWriteMask |= D3DCOLORWRITEENABLE_BLUE; - if(bsel.wa) bs->RenderTargetWriteMask |= D3DCOLORWRITEENABLE_ALPHA; - - m_om_bs.SetAt(bsel, bs); - } - - m_dev->OMSetBlendState(bs, 0x010101 * bf); -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSTextureFX9.h" +#include "resource.h" + +GSTextureFX9::GSTextureFX9() + : m_dev(NULL) +{ +} + +bool GSTextureFX9::Create(GSDevice9* dev) +{ + m_dev = dev; + + VSSelector sel; + + sel.bppz = 0; + sel.tme = 0; + sel.fst = 0; + sel.logz = 0; + + VSConstantBuffer cb; + + SetupVS(sel, &cb); // creates layout + + return true; +} + +bool GSTextureFX9::CreateMskFix(GSTexture9& t, DWORD size, DWORD msk, DWORD fix) +{ + DWORD hash = (size << 20) | (msk << 10) | fix; + + if(CRBMap::CPair* pair = m_mskfix.Lookup(hash)) + { + t = pair->m_value; + } + else + { + if(!m_dev->CreateTexture(t, size, 1, D3DFMT_R32F)) + { + return false; + } + + BYTE* bits; + int pitch; + + if(t.Map(&bits, pitch)) + { + for(DWORD i = 0; i < size; i++) + { + ((float*)bits)[i] = (float)((i & msk) | fix) / size; + } + + t.Unmap(); + } + + m_mskfix.SetAt(hash, t); + } + + return true; +} + +bool GSTextureFX9::SetupIA(const GSVertexHW9* vertices, UINT count, D3DPRIMITIVETYPE prim) +{ + m_dev->IASetVertexBuffer(count, vertices); + m_dev->IASetInputLayout(m_il); + m_dev->IASetPrimitiveTopology(prim); + + return true; +} + +bool GSTextureFX9::SetupVS(VSSelector sel, const VSConstantBuffer* cb) +{ + CComPtr vs; + + if(CRBMap >::CPair* pair = m_vs.Lookup(sel)) + { + vs = pair->m_value; + } + else + { + CStringA str[4]; + + str[0].Format("%d", sel.bppz); + str[1].Format("%d", sel.tme); + str[2].Format("%d", sel.fst); + str[3].Format("%d", sel.logz); + + D3DXMACRO macro[] = + { + {"VS_BPPZ", str[0]}, + {"VS_TME", str[1]}, + {"VS_FST", str[2]}, + {"VS_LOGZ", str[3]}, + {NULL, NULL}, + }; + + static const D3DVERTEXELEMENT9 layout[] = + { + {0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, + {0, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, + {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1}, + {0, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, + D3DDECL_END() + }; + + CComPtr il; + + m_dev->CompileShader(IDR_TFX9_FX, "vs_main", macro, &vs, layout, countof(layout), &il); + + if(m_il == NULL) + { + m_il = il; + } + + m_vs.SetAt(sel, vs); + } + + m_dev->VSSetShader(vs, (const float*)cb, sizeof(*cb) / sizeof(GSVector4)); + + return true; +} + +bool GSTextureFX9::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, IDirect3DTexture9* tex, IDirect3DTexture9* pal, bool psrr) +{ + m_dev->PSSetShaderResources(tex, pal); + + if(tex && psrr) + { + if(sel.wms == 3) + { + D3DSURFACE_DESC desc; + tex->GetLevelDesc(0, &desc); + + GSTexture9 t; + CreateMskFix(t, desc.Width, cb->UMSK, cb->UFIX); + + (*m_dev)->SetTexture(2, t); + } + + if(sel.wmt == 3) + { + D3DSURFACE_DESC desc; + tex->GetLevelDesc(0, &desc); + + GSTexture9 t; + CreateMskFix(t, desc.Height, cb->VMSK, cb->VFIX); + + (*m_dev)->SetTexture(3, t); + } + } + + UpdatePS(sel, cb, ssel, psrr); + + return true; +} + +void GSTextureFX9::UpdatePS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, bool psrr) +{ + HRESULT hr; + + if(!psrr) + { + if(sel.wms == 3) sel.wms = 0; + if(sel.wmt == 3) sel.wmt = 0; + } + + CComPtr ps; + + if(CRBMap >::CPair* pair = m_ps.Lookup(sel)) + { + ps = pair->m_value; + } + else + { + CStringA str[12]; + + str[0].Format("%d", sel.fst); + str[1].Format("%d", sel.wms); + str[2].Format("%d", sel.wmt); + str[3].Format("%d", sel.bpp); + str[4].Format("%d", sel.aem); + str[5].Format("%d", sel.tfx); + str[6].Format("%d", sel.tcc); + str[7].Format("%d", sel.ate); + str[8].Format("%d", sel.atst); + str[9].Format("%d", sel.fog); + str[10].Format("%d", sel.clr1); + str[11].Format("%d", sel.rt); + + D3DXMACRO macro[] = + { + {"FST", str[0]}, + {"WMS", str[1]}, + {"WMT", str[2]}, + {"BPP", str[3]}, + {"AEM", str[4]}, + {"TFX", str[5]}, + {"TCC", str[6]}, + {"ATE", str[7]}, + {"ATST", str[8]}, + {"FOG", str[9]}, + {"CLR1", str[10]}, + {"RT", str[11]}, + {NULL, NULL}, + }; + + hr = m_dev->CompileShader(IDR_TFX9_FX, "ps_main", macro, &ps); + + m_ps.SetAt(sel, ps); + } + + m_dev->PSSetShader(ps, (const float*)cb, sizeof(*cb) / sizeof(GSVector4)); + + Direct3DSamplerState9* ss = NULL; + + if(sel.tfx != 4) + { + if(sel.bpp >= 3 || sel.wms >= 3 || sel.wmt >= 3) + { + ssel.min = ssel.mag = 0; + } + + if(CRBMap::CPair* pair = m_ps_ss.Lookup(ssel)) + { + ss = pair->m_value; + } + else + { + ss = new Direct3DSamplerState9(); + + memset(ss, 0, sizeof(*ss)); + + ss->FilterMin[0] = ssel.min ? D3DTEXF_LINEAR : D3DTEXF_POINT; + ss->FilterMag[0] = ssel.mag ? D3DTEXF_LINEAR : D3DTEXF_POINT; + ss->FilterMin[1] = D3DTEXF_POINT; + ss->FilterMag[1] = D3DTEXF_POINT; + + ss->AddressU = ssel.tau ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP; + ss->AddressV = ssel.tav ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP; + + m_ps_ss.SetAt(ssel, ss); + } + } + + m_dev->PSSetSamplerState(ss); +} + +void GSTextureFX9::SetupRS(int w, int h, const RECT& scissor) +{ + m_dev->RSSet(w, h, &scissor); +} + +void GSTextureFX9::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, BYTE bf, IDirect3DSurface9* rt, IDirect3DSurface9* ds) +{ + UpdateOM(dssel, bsel, bf); + + m_dev->OMSetRenderTargets(rt, ds); +} + +void GSTextureFX9::UpdateOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, BYTE bf) +{ + Direct3DDepthStencilState9* dss = NULL; + + if(CRBMap::CPair* pair = m_om_dss.Lookup(dssel)) + { + dss = pair->m_value; + } + else + { + dss = new Direct3DDepthStencilState9(); + + memset(dss, 0, sizeof(*dss)); + + if(dssel.date || dssel.fba) + { + dss->StencilEnable = true; + dss->StencilReadMask = 1; + dss->StencilWriteMask = 2; + dss->StencilFunc = dssel.date ? D3DCMP_EQUAL : D3DCMP_ALWAYS; + dss->StencilPassOp = dssel.fba ? D3DSTENCILOP_REPLACE : D3DSTENCILOP_KEEP; + dss->StencilFailOp = dssel.fba ? D3DSTENCILOP_ZERO : D3DSTENCILOP_KEEP; + dss->StencilDepthFailOp = dssel.fba ? D3DSTENCILOP_ZERO : D3DSTENCILOP_KEEP; + } + + if(!(dssel.zte && dssel.ztst == 1 && !dssel.zwe)) + { + static const D3DCMPFUNC ztst[] = + { + D3DCMP_NEVER, + D3DCMP_ALWAYS, + D3DCMP_GREATEREQUAL, + D3DCMP_GREATER + }; + + dss->DepthEnable = dssel.zte; + dss->DepthWriteMask = dssel.zwe; + dss->DepthFunc = ztst[dssel.ztst]; + } + + m_om_dss.SetAt(dssel, dss); + } + + m_dev->OMSetDepthStencilState(dss, 3); + + Direct3DBlendState9* bs = NULL; + + if(CRBMap::CPair* pair = m_om_bs.Lookup(bsel)) + { + bs = pair->m_value; + } + else + { + bs = new Direct3DBlendState9(); + + memset(bs, 0, sizeof(*bs)); + + bs->BlendEnable = bsel.abe; + + if(bsel.abe) + { + // (A:Cs/Cd/0 - B:Cs/Cd/0) * C:As/Ad/FIX + D:Cs/Cd/0 + + static const struct {int bogus; D3DBLENDOP op; D3DBLEND src, dst;} map[3*3*3*3] = + { + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 0000: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 0001: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 0002: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 0010: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 0011: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 0012: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 0020: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 0021: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 0022: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {1, D3DBLENDOP_SUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // * 0100: (Cs - Cd)*As + Cs ==> Cs*(As + 1) - Cd*As + {0, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA}, // 0101: (Cs - Cd)*As + Cd ==> Cs*As + Cd*(1 - As) + {0, D3DBLENDOP_SUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // 0102: (Cs - Cd)*As + 0 ==> Cs*As - Cd*As + {1, D3DBLENDOP_SUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // * 0110: (Cs - Cd)*Ad + Cs ==> Cs*(Ad + 1) - Cd*Ad + {0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_INVDESTALPHA}, // 0111: (Cs - Cd)*Ad + Cd ==> Cs*Ad + Cd*(1 - Ad) + {0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // 0112: (Cs - Cd)*Ad + 0 ==> Cs*Ad - Cd*Ad + {1, D3DBLENDOP_SUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR}, // * 0120: (Cs - Cd)*F + Cs ==> Cs*(F + 1) - Cd*F + {0, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_INVBLENDFACTOR}, // 0121: (Cs - Cd)*F + Cd ==> Cs*F + Cd*(1 - F) + {0, D3DBLENDOP_SUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR}, // 0122: (Cs - Cd)*F + 0 ==> Cs*F - Cd*F + {1, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // * 0200: (Cs - 0)*As + Cs ==> Cs*(As + 1) + {0, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ONE}, // 0201: (Cs - 0)*As + Cd ==> Cs*As + Cd + {0, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // 0202: (Cs - 0)*As + 0 ==> Cs*As + {1, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // * 0210: (Cs - 0)*Ad + Cs ==> Cs*(As + 1) + {0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_ONE}, // 0211: (Cs - 0)*Ad + Cd ==> Cs*Ad + Cd + {0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_ZERO}, // 0212: (Cs - 0)*Ad + 0 ==> Cs*Ad + {1, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_ZERO}, // * 0220: (Cs - 0)*F + Cs ==> Cs*(F + 1) + {0, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_ONE}, // 0221: (Cs - 0)*F + Cd ==> Cs*F + Cd + {0, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_ZERO}, // 0222: (Cs - 0)*F + 0 ==> Cs*F + {0, D3DBLENDOP_ADD, D3DBLEND_INVSRCALPHA, D3DBLEND_SRCALPHA}, // 1000: (Cd - Cs)*As + Cs ==> Cd*As + Cs*(1 - As) + {1, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // * 1001: (Cd - Cs)*As + Cd ==> Cd*(As + 1) - Cs*As + {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // 1002: (Cd - Cs)*As + 0 ==> Cd*As - Cs*As + {0, D3DBLENDOP_ADD, D3DBLEND_INVDESTALPHA, D3DBLEND_DESTALPHA}, // 1010: (Cd - Cs)*Ad + Cs ==> Cd*Ad + Cs*(1 - Ad) + {1, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // * 1011: (Cd - Cs)*Ad + Cd ==> Cd*(Ad + 1) - Cs*Ad + {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // 1012: (Cd - Cs)*Ad + 0 ==> Cd*Ad - Cs*Ad + {0, D3DBLENDOP_ADD, D3DBLEND_INVBLENDFACTOR, D3DBLEND_BLENDFACTOR}, // 1020: (Cd - Cs)*F + Cs ==> Cd*F + Cs*(1 - F) + {1, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR},// * 1021: (Cd - Cs)*F + Cd ==> Cd*(F + 1) - Cs*F + {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR},// 1022: (Cd - Cs)*F + 0 ==> Cd*F - Cs*F + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 1100: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 1101: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 1102: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 1110: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 1111: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 1112: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 1120: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 1121: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 1122: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_SRCALPHA}, // 1200: (Cd - 0)*As + Cs ==> Cs + Cd*As + {2, D3DBLENDOP_ADD, D3DBLEND_DESTCOLOR, D3DBLEND_SRCALPHA}, // ** 1201: (Cd - 0)*As + Cd ==> Cd*(1 + As) // ffxii main menu background glow effect + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_SRCALPHA}, // 1202: (Cd - 0)*As + 0 ==> Cd*As + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_DESTALPHA}, // 1210: (Cd - 0)*Ad + Cs ==> Cs + Cd*Ad + {2, D3DBLENDOP_ADD, D3DBLEND_DESTCOLOR, D3DBLEND_DESTALPHA}, // ** 1211: (Cd - 0)*Ad + Cd ==> Cd*(1 + Ad) + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_DESTALPHA}, // 1212: (Cd - 0)*Ad + 0 ==> Cd*Ad + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_BLENDFACTOR}, // 1220: (Cd - 0)*F + Cs ==> Cs + Cd*F + {2, D3DBLENDOP_ADD, D3DBLEND_DESTCOLOR, D3DBLEND_BLENDFACTOR}, // ** 1221: (Cd - 0)*F + Cd ==> Cd*(1 + F) + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_BLENDFACTOR}, // 1222: (Cd - 0)*F + 0 ==> Cd*F + {0, D3DBLENDOP_ADD, D3DBLEND_INVSRCALPHA, D3DBLEND_ZERO}, // 2000: (0 - Cs)*As + Cs ==> Cs*(1 - As) + {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_ONE}, // 2001: (0 - Cs)*As + Cd ==> Cd - Cs*As + {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // 2002: (0 - Cs)*As + 0 ==> 0 - Cs*As + {0, D3DBLENDOP_ADD, D3DBLEND_INVDESTALPHA, D3DBLEND_ZERO}, // 2010: (0 - Cs)*Ad + Cs ==> Cs*(1 - Ad) + {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_ONE}, // 2011: (0 - Cs)*Ad + Cd ==> Cd - Cs*Ad + {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_ZERO}, // 2012: (0 - Cs)*Ad + 0 ==> 0 - Cs*Ad + {0, D3DBLENDOP_ADD, D3DBLEND_INVBLENDFACTOR, D3DBLEND_ZERO}, // 2020: (0 - Cs)*F + Cs ==> Cs*(1 - F) + {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_ONE}, // 2021: (0 - Cs)*F + Cd ==> Cd - Cs*F + {0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_ZERO}, // 2022: (0 - Cs)*F + 0 ==> 0 - Cs*F + {0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_SRCALPHA}, // 2100: (0 - Cd)*As + Cs ==> Cs - Cd*As + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_INVSRCALPHA}, // 2101: (0 - Cd)*As + Cd ==> Cd*(1 - As) + {0, D3DBLENDOP_SUBTRACT, D3DBLEND_ZERO, D3DBLEND_SRCALPHA}, // 2102: (0 - Cd)*As + 0 ==> 0 - Cd*As + {0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_DESTALPHA}, // 2110: (0 - Cd)*Ad + Cs ==> Cs - Cd*Ad + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_INVDESTALPHA}, // 2111: (0 - Cd)*Ad + Cd ==> Cd*(1 - Ad) + {0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_DESTALPHA}, // 2112: (0 - Cd)*Ad + 0 ==> 0 - Cd*Ad + {0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_BLENDFACTOR}, // 2120: (0 - Cd)*F + Cs ==> Cs - Cd*F + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_INVBLENDFACTOR}, // 2121: (0 - Cd)*F + Cd ==> Cd*(1 - F) + {0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_BLENDFACTOR}, // 2122: (0 - Cd)*F + 0 ==> 0 - Cd*F + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 2200: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 2201: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 2202: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 2210: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 2211: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 2212: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 2220: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 2221: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 2222: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + }; + + // bogus: 0100, 0110, 0120, 0200, 0210, 0220, 1001, 1011, 1021 + + // tricky: 1201, 1211, 1221 + // + // Source.rgb = float3(1, 1, 1); + // 1201 Cd*(1 + As) => Source * Dest color + Dest * Source alpha + // 1211 Cd*(1 + Ad) => Source * Dest color + Dest * Dest alpha + // 1221 Cd*(1 + F) => Source * Dest color + Dest * Factor + + int i = ((bsel.a * 3 + bsel.b) * 3 + bsel.c) * 3 + bsel.d; + + bs->BlendOp = map[i].op; + bs->SrcBlend = map[i].src; + bs->DestBlend = map[i].dst; + bs->BlendOpAlpha = D3DBLENDOP_ADD; + bs->SrcBlendAlpha = D3DBLEND_ONE; + bs->DestBlendAlpha = D3DBLEND_ZERO; + + if(map[i].bogus == 1) + { + ASSERT(0); + + (bsel.a == 0 ? bs->SrcBlend : bs->DestBlend) = D3DBLEND_ONE; + } + } + + if(bsel.wr) bs->RenderTargetWriteMask |= D3DCOLORWRITEENABLE_RED; + if(bsel.wg) bs->RenderTargetWriteMask |= D3DCOLORWRITEENABLE_GREEN; + if(bsel.wb) bs->RenderTargetWriteMask |= D3DCOLORWRITEENABLE_BLUE; + if(bsel.wa) bs->RenderTargetWriteMask |= D3DCOLORWRITEENABLE_ALPHA; + + m_om_bs.SetAt(bsel, bs); + } + + m_dev->OMSetBlendState(bs, 0x010101 * bf); +} diff --git a/plugins/GSdx/GSTextureFX9.h b/plugins/GSdx/GSTextureFX9.h index 6b7fad206a..e2811059c9 100644 --- a/plugins/GSdx/GSTextureFX9.h +++ b/plugins/GSdx/GSTextureFX9.h @@ -1,173 +1,173 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSDevice9.h" - -class GSTextureFX9 -{ -public: - #pragma pack(push, 1) - - struct VSConstantBuffer - { - GSVector4 VertexScale; - GSVector4 VertexOffset; - GSVector2 TextureScale; - float _pad[2]; - }; - - union VSSelector - { - struct - { - DWORD bppz:2; - DWORD tme:1; - DWORD fst:1; - DWORD logz:1; - }; - - DWORD dw; - - operator DWORD() {return dw & 0x1f;} - }; - - struct PSConstantBuffer - { - GSVector4 FogColor; - float MINU; - float MAXU; - float MINV; - float MAXV; - DWORD UMSK; - DWORD UFIX; - DWORD VMSK; - DWORD VFIX; - float TA0; - float TA1; - float AREF; - float _pad[1]; - GSVector2 WH; - GSVector2 rWrH; - }; - - union PSSelector - { - struct - { - DWORD fst:1; - DWORD wms:2; - DWORD wmt:2; - DWORD bpp:3; - DWORD aem:1; - DWORD tfx:3; - DWORD tcc:1; - DWORD ate:1; - DWORD atst:3; - DWORD fog:1; - DWORD clr1:1; - DWORD rt:1; - }; - - DWORD dw; - - operator DWORD() {return dw & 0xfffff;} - }; - - union PSSamplerSelector - { - struct - { - DWORD tau:1; - DWORD tav:1; - DWORD min:1; - DWORD mag:1; - }; - - DWORD dw; - - operator DWORD() {return dw & 0xf;} - }; - - union OMDepthStencilSelector - { - struct - { - DWORD zte:1; - DWORD ztst:2; - DWORD zwe:1; - DWORD date:1; - DWORD fba:1; - }; - - DWORD dw; - - operator DWORD() {return dw & 0x3f;} - }; - - union OMBlendSelector - { - struct - { - DWORD abe:1; - DWORD a:2; - DWORD b:2; - DWORD c:2; - DWORD d:2; - DWORD wr:1; - DWORD wg:1; - DWORD wb:1; - DWORD wa:1; - }; - - DWORD dw; - - operator DWORD() {return dw & 0x1fff;} - }; - - #pragma pack(pop) - -private: - GSDevice9* m_dev; - CComPtr m_il; - CRBMapC > m_vs; - D3DXHANDLE m_vs_params; - CRBMapC > m_ps; - CRBMapC m_ps_ss; - CRBMapC m_om_dss; - CRBMapC m_om_bs; - CRBMapC m_mskfix; - -public: - GSTextureFX9(); - - bool Create(GSDevice9* dev); - bool CreateMskFix(GSTexture9& t, DWORD size, DWORD msk, DWORD fix); - - bool SetupIA(const GSVertexHW9* vertices, UINT count, D3DPRIMITIVETYPE prim); - bool SetupVS(VSSelector sel, const VSConstantBuffer* cb); - bool SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, IDirect3DTexture9* tex, IDirect3DTexture9* pal, bool psrr); - void UpdatePS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, bool psrr); - void SetupRS(int w, int h, const RECT& scissor); - void SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, BYTE bf, IDirect3DSurface9* rt, IDirect3DSurface9* ds); - void UpdateOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, BYTE bf); -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSDevice9.h" + +class GSTextureFX9 +{ +public: + #pragma pack(push, 1) + + struct VSConstantBuffer + { + GSVector4 VertexScale; + GSVector4 VertexOffset; + GSVector2 TextureScale; + float _pad[2]; + }; + + union VSSelector + { + struct + { + DWORD bppz:2; + DWORD tme:1; + DWORD fst:1; + DWORD logz:1; + }; + + DWORD dw; + + operator DWORD() {return dw & 0x1f;} + }; + + struct PSConstantBuffer + { + GSVector4 FogColor; + float MINU; + float MAXU; + float MINV; + float MAXV; + DWORD UMSK; + DWORD UFIX; + DWORD VMSK; + DWORD VFIX; + float TA0; + float TA1; + float AREF; + float _pad[1]; + GSVector2 WH; + GSVector2 rWrH; + }; + + union PSSelector + { + struct + { + DWORD fst:1; + DWORD wms:2; + DWORD wmt:2; + DWORD bpp:3; + DWORD aem:1; + DWORD tfx:3; + DWORD tcc:1; + DWORD ate:1; + DWORD atst:3; + DWORD fog:1; + DWORD clr1:1; + DWORD rt:1; + }; + + DWORD dw; + + operator DWORD() {return dw & 0xfffff;} + }; + + union PSSamplerSelector + { + struct + { + DWORD tau:1; + DWORD tav:1; + DWORD min:1; + DWORD mag:1; + }; + + DWORD dw; + + operator DWORD() {return dw & 0xf;} + }; + + union OMDepthStencilSelector + { + struct + { + DWORD zte:1; + DWORD ztst:2; + DWORD zwe:1; + DWORD date:1; + DWORD fba:1; + }; + + DWORD dw; + + operator DWORD() {return dw & 0x3f;} + }; + + union OMBlendSelector + { + struct + { + DWORD abe:1; + DWORD a:2; + DWORD b:2; + DWORD c:2; + DWORD d:2; + DWORD wr:1; + DWORD wg:1; + DWORD wb:1; + DWORD wa:1; + }; + + DWORD dw; + + operator DWORD() {return dw & 0x1fff;} + }; + + #pragma pack(pop) + +private: + GSDevice9* m_dev; + CComPtr m_il; + CRBMapC > m_vs; + D3DXHANDLE m_vs_params; + CRBMapC > m_ps; + CRBMapC m_ps_ss; + CRBMapC m_om_dss; + CRBMapC m_om_bs; + CRBMapC m_mskfix; + +public: + GSTextureFX9(); + + bool Create(GSDevice9* dev); + bool CreateMskFix(GSTexture9& t, DWORD size, DWORD msk, DWORD fix); + + bool SetupIA(const GSVertexHW9* vertices, UINT count, D3DPRIMITIVETYPE prim); + bool SetupVS(VSSelector sel, const VSConstantBuffer* cb); + bool SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, IDirect3DTexture9* tex, IDirect3DTexture9* pal, bool psrr); + void UpdatePS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, bool psrr); + void SetupRS(int w, int h, const RECT& scissor); + void SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, BYTE bf, IDirect3DSurface9* rt, IDirect3DSurface9* ds); + void UpdateOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, BYTE bf); +}; diff --git a/plugins/GSdx/GSTextureNull.cpp b/plugins/GSdx/GSTextureNull.cpp index b2141079e1..04c28e874f 100644 --- a/plugins/GSdx/GSTextureNull.cpp +++ b/plugins/GSdx/GSTextureNull.cpp @@ -1,36 +1,36 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GSTextureNull.h" - -GSTextureNull::GSTextureNull() -{ - memset(&m_desc, 0, sizeof(m_desc)); -} - -GSTextureNull::GSTextureNull(int type, int w, int h, int format) -{ - m_desc.type = type; - m_desc.w = w; - m_desc.h = h; - m_desc.format = format; -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSTextureNull.h" + +GSTextureNull::GSTextureNull() +{ + memset(&m_desc, 0, sizeof(m_desc)); +} + +GSTextureNull::GSTextureNull(int type, int w, int h, int format) +{ + m_desc.type = type; + m_desc.w = w; + m_desc.h = h; + m_desc.format = format; +} diff --git a/plugins/GSdx/GSTextureNull.h b/plugins/GSdx/GSTextureNull.h index 18898b9008..38f21990fe 100644 --- a/plugins/GSdx/GSTextureNull.h +++ b/plugins/GSdx/GSTextureNull.h @@ -1,44 +1,44 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSTexture.h" - -class GSTextureNull : public GSTexture -{ - struct {int type, w, h, format;} m_desc; - -public: - GSTextureNull(); - GSTextureNull(int type, int w, int h, int format); - - operator bool() {return m_desc.type != 0;} - - int GetType() const {return m_desc.type;} - int GetWidth() const {return m_desc.w;} - int GetHeight() const {return m_desc.h;} - int GetFormat() const {return m_desc.format;} - bool Update(const CRect& r, const void* data, int pitch) {return true;} - bool Map(BYTE** bits, int& pitch, const RECT* r = NULL) {return true;} - void Unmap() {} - bool Save(CString fn, bool dds = false) {return false;} -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSTexture.h" + +class GSTextureNull : public GSTexture +{ + struct {int type, w, h, format;} m_desc; + +public: + GSTextureNull(); + GSTextureNull(int type, int w, int h, int format); + + operator bool() {return m_desc.type != 0;} + + int GetType() const {return m_desc.type;} + int GetWidth() const {return m_desc.w;} + int GetHeight() const {return m_desc.h;} + int GetFormat() const {return m_desc.format;} + bool Update(const CRect& r, const void* data, int pitch) {return true;} + bool Map(BYTE** bits, int& pitch, const RECT* r = NULL) {return true;} + void Unmap() {} + bool Save(CString fn, bool dds = false) {return false;} +}; diff --git a/plugins/GSdx/GSUtil.cpp b/plugins/GSdx/GSUtil.cpp index bba238a38e..4f06fe7fe9 100644 --- a/plugins/GSdx/GSUtil.cpp +++ b/plugins/GSdx/GSUtil.cpp @@ -1,272 +1,272 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GS.h" -#include "GSUtil.h" -#include "svnrev.h" - -static struct GSUtilMaps -{ - BYTE PrimClassField[8]; - bool CompatibleBitsField[64][64]; - bool SharedBitsField[64][64]; - - struct GSUtilMaps() - { - PrimClassField[GS_POINTLIST] = GS_POINT_CLASS; - PrimClassField[GS_LINELIST] = GS_LINE_CLASS; - PrimClassField[GS_LINESTRIP] = GS_LINE_CLASS; - PrimClassField[GS_TRIANGLELIST] = GS_TRIANGLE_CLASS; - PrimClassField[GS_TRIANGLESTRIP] = GS_TRIANGLE_CLASS; - PrimClassField[GS_TRIANGLEFAN] = GS_TRIANGLE_CLASS; - PrimClassField[GS_SPRITE] = GS_SPRITE_CLASS; - PrimClassField[GS_INVALID] = GS_INVALID_CLASS; - - memset(CompatibleBitsField, 0, sizeof(CompatibleBitsField)); - - CompatibleBitsField[PSM_PSMCT32][PSM_PSMCT24] = true; - CompatibleBitsField[PSM_PSMCT24][PSM_PSMCT32] = true; - CompatibleBitsField[PSM_PSMCT16][PSM_PSMCT16S] = true; - CompatibleBitsField[PSM_PSMCT16S][PSM_PSMCT16] = true; - CompatibleBitsField[PSM_PSMZ32][PSM_PSMZ24] = true; - CompatibleBitsField[PSM_PSMZ24][PSM_PSMZ32] = true; - CompatibleBitsField[PSM_PSMZ16][PSM_PSMZ16S] = true; - CompatibleBitsField[PSM_PSMZ16S][PSM_PSMZ16] = true; - - memset(SharedBitsField, 1, sizeof(SharedBitsField)); - - SharedBitsField[PSM_PSMCT24][PSM_PSMT8H] = false; - SharedBitsField[PSM_PSMCT24][PSM_PSMT4HL] = false; - SharedBitsField[PSM_PSMCT24][PSM_PSMT4HH] = false; - SharedBitsField[PSM_PSMZ24][PSM_PSMT8H] = false; - SharedBitsField[PSM_PSMZ24][PSM_PSMT4HL] = false; - SharedBitsField[PSM_PSMZ24][PSM_PSMT4HH] = false; - SharedBitsField[PSM_PSMT8H][PSM_PSMCT24] = false; - SharedBitsField[PSM_PSMT8H][PSM_PSMZ24] = false; - SharedBitsField[PSM_PSMT4HL][PSM_PSMCT24] = false; - SharedBitsField[PSM_PSMT4HL][PSM_PSMZ24] = false; - SharedBitsField[PSM_PSMT4HL][PSM_PSMT4HH] = false; - SharedBitsField[PSM_PSMT4HH][PSM_PSMCT24] = false; - SharedBitsField[PSM_PSMT4HH][PSM_PSMZ24] = false; - SharedBitsField[PSM_PSMT4HH][PSM_PSMT4HL] = false; - } - -} s_maps; - -GS_PRIM_CLASS GSUtil::GetPrimClass(DWORD prim) -{ - return (GS_PRIM_CLASS)s_maps.PrimClassField[prim]; -} - -bool GSUtil::HasSharedBits(DWORD spsm, DWORD dpsm) -{ - return s_maps.SharedBitsField[spsm][dpsm]; -} - -bool GSUtil::HasSharedBits(DWORD sbp, DWORD spsm, DWORD dbp, DWORD dpsm) -{ - if(sbp != dbp) return false; - - return HasSharedBits(spsm, dpsm); -} - -bool GSUtil::HasCompatibleBits(DWORD spsm, DWORD dpsm) -{ - if(spsm == dpsm) return true; - - return s_maps.CompatibleBitsField[spsm][dpsm]; -} - -bool GSUtil::IsRectInRect(const CRect& inner, const CRect& outer) -{ - return outer.left <= inner.left && inner.right <= outer.right && outer.top <= inner.top && inner.bottom <= outer.bottom; -} - -bool GSUtil::IsRectInRectH(const CRect& inner, const CRect& outer) -{ - return outer.top <= inner.top && inner.bottom <= outer.bottom; -} - -bool GSUtil::IsRectInRectV(const CRect& inner, const CRect& outer) -{ - return outer.left <= inner.left && inner.right <= outer.right; -} - -void GSUtil::FitRect(CRect& r, int aspectratio) -{ - static const int ar[][2] = {{0, 0}, {4, 3}, {16, 9}}; - - if(aspectratio <= 0 || aspectratio >= countof(ar)) - { - return; - } - - int arx = ar[aspectratio][0]; - int ary = ar[aspectratio][1]; - - CRect r2 = r; - - if(arx > 0 && ary > 0) - { - if(r.Width() * ary > r.Height() * arx) - { - int w = r.Height() * arx / ary; - r.left = r.CenterPoint().x - w / 2; - if(r.left & 1) r.left++; - r.right = r.left + w; - } - else - { - int h = r.Width() * ary / arx; - r.top = r.CenterPoint().y - h / 2; - if(r.top & 1) r.top++; - r.bottom = r.top + h; - } - } - - r &= r2; -} - -bool GSUtil::CheckDirectX() -{ - CString str; - - str.Format(_T("d3dx9_%d.dll"), D3DX_SDK_VERSION); - - if(HINSTANCE hDll = LoadLibrary(str)) - { - FreeLibrary(hDll); - } - else - { - int res = AfxMessageBox(_T("Please update DirectX!\n\nWould you like to open the download page in your browser?"), MB_YESNO); - - if(res == IDYES) - { - ShellExecute(NULL, _T("open"), _T("http://www.microsoft.com/downloads/details.aspx?FamilyId=2DA43D38-DB71-4C1B-BC6A-9B6652CD92A3"), NULL, NULL, SW_SHOWNORMAL); - } - - return false; - } - - return true; -} - -static bool _CheckSSE() -{ - __try - { - static __m128i m; - - #if _M_SSE >= 0x402 - m.m128i_i32[0] = _mm_popcnt_u32(1234); - #elif _M_SSE >= 0x401 - m = _mm_packus_epi32(m, m); - #elif _M_SSE >= 0x301 - m = _mm_alignr_epi8(m, m, 1); - #elif _M_SSE >= 0x200 - m = _mm_packs_epi32(m, m); - #endif - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - return false; - } - - return true; -} - -bool GSUtil::CheckSSE() -{ - if(!_CheckSSE()) - { - CString str; - str.Format(_T("This CPU does not support SSE %d.%02d"), _M_SSE >> 8, _M_SSE & 0xff); - AfxMessageBox(str, MB_OK); - - return false; - } - - return true; -} - -bool GSUtil::IsDirect3D10Available() -{ - if(HMODULE hModule = LoadLibrary(_T("d3d10.dll"))) - { - FreeLibrary(hModule); - - return true; - } - - return false; -} - -char* GSUtil::GetLibName() -{ - CString str; - - str.Format(_T("GSdx %d"), SVN_REV); - - if(SVN_MODS) str += _T("m"); - -#if _M_AMD64 - str += _T(" 64-bit"); -#endif - - CAtlList sl; - -#ifdef __INTEL_COMPILER - CString s; - s.Format(_T("Intel C++ %d.%02d"), __INTEL_COMPILER/100, __INTEL_COMPILER%100); - sl.AddTail(s); -#elif _MSC_VER - CString s; - s.Format(_T("MSVC %d.%02d"), _MSC_VER/100, _MSC_VER%100); - sl.AddTail(s); -#endif - -#if _M_SSE >= 0x402 - sl.AddTail(_T("SSE42")); -#elif _M_SSE >= 0x401 - sl.AddTail(_T("SSE41")); -#elif _M_SSE >= 0x301 - sl.AddTail(_T("SSSE3")); -#elif _M_SSE >= 0x200 - sl.AddTail(_T("SSE2")); -#elif _M_SSE >= 0x100 - sl.AddTail(_T("SSE")); -#endif - - POSITION pos = sl.GetHeadPosition(); - - while(pos) - { - if(pos == sl.GetHeadPosition()) str += _T(" ("); - str += sl.GetNext(pos); - str += pos ? _T(", ") : _T(")"); - } - - static char buff[256]; - strncpy(buff, CStringA(str), min(countof(buff)-1, str.GetLength())); - return buff; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GS.h" +#include "GSUtil.h" +#include "svnrev.h" + +static struct GSUtilMaps +{ + BYTE PrimClassField[8]; + bool CompatibleBitsField[64][64]; + bool SharedBitsField[64][64]; + + struct GSUtilMaps() + { + PrimClassField[GS_POINTLIST] = GS_POINT_CLASS; + PrimClassField[GS_LINELIST] = GS_LINE_CLASS; + PrimClassField[GS_LINESTRIP] = GS_LINE_CLASS; + PrimClassField[GS_TRIANGLELIST] = GS_TRIANGLE_CLASS; + PrimClassField[GS_TRIANGLESTRIP] = GS_TRIANGLE_CLASS; + PrimClassField[GS_TRIANGLEFAN] = GS_TRIANGLE_CLASS; + PrimClassField[GS_SPRITE] = GS_SPRITE_CLASS; + PrimClassField[GS_INVALID] = GS_INVALID_CLASS; + + memset(CompatibleBitsField, 0, sizeof(CompatibleBitsField)); + + CompatibleBitsField[PSM_PSMCT32][PSM_PSMCT24] = true; + CompatibleBitsField[PSM_PSMCT24][PSM_PSMCT32] = true; + CompatibleBitsField[PSM_PSMCT16][PSM_PSMCT16S] = true; + CompatibleBitsField[PSM_PSMCT16S][PSM_PSMCT16] = true; + CompatibleBitsField[PSM_PSMZ32][PSM_PSMZ24] = true; + CompatibleBitsField[PSM_PSMZ24][PSM_PSMZ32] = true; + CompatibleBitsField[PSM_PSMZ16][PSM_PSMZ16S] = true; + CompatibleBitsField[PSM_PSMZ16S][PSM_PSMZ16] = true; + + memset(SharedBitsField, 1, sizeof(SharedBitsField)); + + SharedBitsField[PSM_PSMCT24][PSM_PSMT8H] = false; + SharedBitsField[PSM_PSMCT24][PSM_PSMT4HL] = false; + SharedBitsField[PSM_PSMCT24][PSM_PSMT4HH] = false; + SharedBitsField[PSM_PSMZ24][PSM_PSMT8H] = false; + SharedBitsField[PSM_PSMZ24][PSM_PSMT4HL] = false; + SharedBitsField[PSM_PSMZ24][PSM_PSMT4HH] = false; + SharedBitsField[PSM_PSMT8H][PSM_PSMCT24] = false; + SharedBitsField[PSM_PSMT8H][PSM_PSMZ24] = false; + SharedBitsField[PSM_PSMT4HL][PSM_PSMCT24] = false; + SharedBitsField[PSM_PSMT4HL][PSM_PSMZ24] = false; + SharedBitsField[PSM_PSMT4HL][PSM_PSMT4HH] = false; + SharedBitsField[PSM_PSMT4HH][PSM_PSMCT24] = false; + SharedBitsField[PSM_PSMT4HH][PSM_PSMZ24] = false; + SharedBitsField[PSM_PSMT4HH][PSM_PSMT4HL] = false; + } + +} s_maps; + +GS_PRIM_CLASS GSUtil::GetPrimClass(DWORD prim) +{ + return (GS_PRIM_CLASS)s_maps.PrimClassField[prim]; +} + +bool GSUtil::HasSharedBits(DWORD spsm, DWORD dpsm) +{ + return s_maps.SharedBitsField[spsm][dpsm]; +} + +bool GSUtil::HasSharedBits(DWORD sbp, DWORD spsm, DWORD dbp, DWORD dpsm) +{ + if(sbp != dbp) return false; + + return HasSharedBits(spsm, dpsm); +} + +bool GSUtil::HasCompatibleBits(DWORD spsm, DWORD dpsm) +{ + if(spsm == dpsm) return true; + + return s_maps.CompatibleBitsField[spsm][dpsm]; +} + +bool GSUtil::IsRectInRect(const CRect& inner, const CRect& outer) +{ + return outer.left <= inner.left && inner.right <= outer.right && outer.top <= inner.top && inner.bottom <= outer.bottom; +} + +bool GSUtil::IsRectInRectH(const CRect& inner, const CRect& outer) +{ + return outer.top <= inner.top && inner.bottom <= outer.bottom; +} + +bool GSUtil::IsRectInRectV(const CRect& inner, const CRect& outer) +{ + return outer.left <= inner.left && inner.right <= outer.right; +} + +void GSUtil::FitRect(CRect& r, int aspectratio) +{ + static const int ar[][2] = {{0, 0}, {4, 3}, {16, 9}}; + + if(aspectratio <= 0 || aspectratio >= countof(ar)) + { + return; + } + + int arx = ar[aspectratio][0]; + int ary = ar[aspectratio][1]; + + CRect r2 = r; + + if(arx > 0 && ary > 0) + { + if(r.Width() * ary > r.Height() * arx) + { + int w = r.Height() * arx / ary; + r.left = r.CenterPoint().x - w / 2; + if(r.left & 1) r.left++; + r.right = r.left + w; + } + else + { + int h = r.Width() * ary / arx; + r.top = r.CenterPoint().y - h / 2; + if(r.top & 1) r.top++; + r.bottom = r.top + h; + } + } + + r &= r2; +} + +bool GSUtil::CheckDirectX() +{ + CString str; + + str.Format(_T("d3dx9_%d.dll"), D3DX_SDK_VERSION); + + if(HINSTANCE hDll = LoadLibrary(str)) + { + FreeLibrary(hDll); + } + else + { + int res = AfxMessageBox(_T("Please update DirectX!\n\nWould you like to open the download page in your browser?"), MB_YESNO); + + if(res == IDYES) + { + ShellExecute(NULL, _T("open"), _T("http://www.microsoft.com/downloads/details.aspx?FamilyId=2DA43D38-DB71-4C1B-BC6A-9B6652CD92A3"), NULL, NULL, SW_SHOWNORMAL); + } + + return false; + } + + return true; +} + +static bool _CheckSSE() +{ + __try + { + static __m128i m; + + #if _M_SSE >= 0x402 + m.m128i_i32[0] = _mm_popcnt_u32(1234); + #elif _M_SSE >= 0x401 + m = _mm_packus_epi32(m, m); + #elif _M_SSE >= 0x301 + m = _mm_alignr_epi8(m, m, 1); + #elif _M_SSE >= 0x200 + m = _mm_packs_epi32(m, m); + #endif + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return false; + } + + return true; +} + +bool GSUtil::CheckSSE() +{ + if(!_CheckSSE()) + { + CString str; + str.Format(_T("This CPU does not support SSE %d.%02d"), _M_SSE >> 8, _M_SSE & 0xff); + AfxMessageBox(str, MB_OK); + + return false; + } + + return true; +} + +bool GSUtil::IsDirect3D10Available() +{ + if(HMODULE hModule = LoadLibrary(_T("d3d10.dll"))) + { + FreeLibrary(hModule); + + return true; + } + + return false; +} + +char* GSUtil::GetLibName() +{ + CString str; + + str.Format(_T("GSdx %d"), SVN_REV); + + if(SVN_MODS) str += _T("m"); + +#if _M_AMD64 + str += _T(" 64-bit"); +#endif + + CAtlList sl; + +#ifdef __INTEL_COMPILER + CString s; + s.Format(_T("Intel C++ %d.%02d"), __INTEL_COMPILER/100, __INTEL_COMPILER%100); + sl.AddTail(s); +#elif _MSC_VER + CString s; + s.Format(_T("MSVC %d.%02d"), _MSC_VER/100, _MSC_VER%100); + sl.AddTail(s); +#endif + +#if _M_SSE >= 0x402 + sl.AddTail(_T("SSE42")); +#elif _M_SSE >= 0x401 + sl.AddTail(_T("SSE41")); +#elif _M_SSE >= 0x301 + sl.AddTail(_T("SSSE3")); +#elif _M_SSE >= 0x200 + sl.AddTail(_T("SSE2")); +#elif _M_SSE >= 0x100 + sl.AddTail(_T("SSE")); +#endif + + POSITION pos = sl.GetHeadPosition(); + + while(pos) + { + if(pos == sl.GetHeadPosition()) str += _T(" ("); + str += sl.GetNext(pos); + str += pos ? _T(", ") : _T(")"); + } + + static char buff[256]; + strncpy(buff, CStringA(str), min(countof(buff)-1, str.GetLength())); + return buff; } \ No newline at end of file diff --git a/plugins/GSdx/GSUtil.h b/plugins/GSdx/GSUtil.h index 973111ff72..2d0eacb569 100644 --- a/plugins/GSdx/GSUtil.h +++ b/plugins/GSdx/GSUtil.h @@ -1,68 +1,68 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GS.h" - -class GSUtil -{ -public: - static GS_PRIM_CLASS GetPrimClass(DWORD prim); - - static bool HasSharedBits(DWORD spsm, DWORD dpsm); - static bool HasSharedBits(DWORD sbp, DWORD spsm, DWORD dbp, DWORD dpsm); - static bool HasCompatibleBits(DWORD spsm, DWORD dpsm); - - static bool IsRectInRect(const CRect& inner, const CRect& outer); - static bool IsRectInRectH(const CRect& inner, const CRect& outer); - static bool IsRectInRectV(const CRect& inner, const CRect& outer); - - static void FitRect(CRect& r, int aspectratio); - - static int EncodePSM(int psm) - { - switch(psm) - { - case PSM_PSMCT32: - case PSM_PSMZ32: - return 0; - case PSM_PSMCT24: - case PSM_PSMZ24: - return 1; - case PSM_PSMCT16: - case PSM_PSMCT16S: - case PSM_PSMZ16: - case PSM_PSMZ16S: - return 2; - default: - return 3; - } - } - - static bool CheckDirectX(); - static bool CheckSSE(); - - static bool IsDirect3D10Available(); - - static char* GetLibName(); -}; - +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GS.h" + +class GSUtil +{ +public: + static GS_PRIM_CLASS GetPrimClass(DWORD prim); + + static bool HasSharedBits(DWORD spsm, DWORD dpsm); + static bool HasSharedBits(DWORD sbp, DWORD spsm, DWORD dbp, DWORD dpsm); + static bool HasCompatibleBits(DWORD spsm, DWORD dpsm); + + static bool IsRectInRect(const CRect& inner, const CRect& outer); + static bool IsRectInRectH(const CRect& inner, const CRect& outer); + static bool IsRectInRectV(const CRect& inner, const CRect& outer); + + static void FitRect(CRect& r, int aspectratio); + + static int EncodePSM(int psm) + { + switch(psm) + { + case PSM_PSMCT32: + case PSM_PSMZ32: + return 0; + case PSM_PSMCT24: + case PSM_PSMZ24: + return 1; + case PSM_PSMCT16: + case PSM_PSMCT16S: + case PSM_PSMZ16: + case PSM_PSMZ16S: + return 2; + default: + return 3; + } + } + + static bool CheckDirectX(); + static bool CheckSSE(); + + static bool IsDirect3D10Available(); + + static char* GetLibName(); +}; + diff --git a/plugins/GSdx/GSVector.cpp b/plugins/GSdx/GSVector.cpp index ff11789881..a684fb9f31 100644 --- a/plugins/GSdx/GSVector.cpp +++ b/plugins/GSdx/GSVector.cpp @@ -1,46 +1,46 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSVector.h" - -const GSVector4 GSVector4::m_ps0123(0.0f, 1.0f, 2.0f, 3.0f); -const GSVector4 GSVector4::m_ps4567(4.0f, 5.0f, 6.0f, 7.0f); - -void GSVector4::operator = (const GSVector4i& v) -{ - m = _mm_cvtepi32_ps(v); -} - -void GSVector4i::operator = (const GSVector4& v) -{ - m = _mm_cvttps_epi32(v); -} - -GSVector4i GSVector4i::cast(const GSVector4& v) -{ - return GSVector4i(_mm_castps_si128(v.m)); -} - -GSVector4 GSVector4::cast(const GSVector4i& v) -{ - return GSVector4(_mm_castsi128_ps(v.m)); -} +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSVector.h" + +const GSVector4 GSVector4::m_ps0123(0.0f, 1.0f, 2.0f, 3.0f); +const GSVector4 GSVector4::m_ps4567(4.0f, 5.0f, 6.0f, 7.0f); + +void GSVector4::operator = (const GSVector4i& v) +{ + m = _mm_cvtepi32_ps(v); +} + +void GSVector4i::operator = (const GSVector4& v) +{ + m = _mm_cvttps_epi32(v); +} + +GSVector4i GSVector4i::cast(const GSVector4& v) +{ + return GSVector4i(_mm_castps_si128(v.m)); +} + +GSVector4 GSVector4::cast(const GSVector4i& v) +{ + return GSVector4(_mm_castsi128_ps(v.m)); +} diff --git a/plugins/GSdx/GSVector.h b/plugins/GSdx/GSVector.h index 4244bc0b29..a160a36d0a 100644 --- a/plugins/GSdx/GSVector.h +++ b/plugins/GSdx/GSVector.h @@ -1,2644 +1,2644 @@ -#pragma once - -// NOTE: x64 version of the _mm_set_* functions are terrible, first they store components into memory then reload in one piece (VS2008 SP1) - -#pragma pack(push, 1) - -template class GSVector2T -{ -public: - union - { - struct {T x, y;}; - struct {T r, g;}; - struct {T v[2];}; - }; - - GSVector2T() - { - } - - GSVector2T(T x, T y) - { - this->x = x; - this->y = y; - } - - GSVector2T(const GSVector2T& v) - { - *this = v; - } - - void operator = (const GSVector2T& v) - { - _mm_storel_epi64((__m128i*)this, _mm_loadl_epi64((__m128i*)&v)); - } -}; - -typedef __declspec(align(8)) GSVector2T GSVector2; -typedef __declspec(align(8)) GSVector2T GSVector2i; - -class GSVector4; - -__declspec(align(16)) class GSVector4i -{ -public: - union - { - struct {int x, y, z, w;}; - struct {int r, g, b, a;}; - int v[4]; - float f32[4]; - unsigned __int64 u64[2]; - __int8 i8[16]; - __int16 i16[8]; - __int32 i32[4]; - __int64 i64[2]; - unsigned __int8 u8[16]; - unsigned __int16 u16[8]; - unsigned __int32 u32[4]; - __m128i m; - }; - - GSVector4i() - { - } - - GSVector4i(int x, int y, int z, int w) - { - // 4 gprs - - // m = _mm_set_epi32(w, z, y, x); - - // 2 gprs - - GSVector4i xz = load(x).upl32(load(z)); - GSVector4i yw = load(y).upl32(load(w)); - - *this = xz.upl32(yw); - } - - GSVector4i(int x, int y) - { - *this = load(x).upl32(load(y)); - } - - GSVector4i(short s0, short s1, short s2, short s3, short s4, short s5, short s6, short s7) - { - m = _mm_set_epi16(s7, s6, s5, s4, s3, s2, s1, s0); - } - - GSVector4i(char b0, char b1, char b2, char b3, char b4, char b5, char b6, char b7, char b8, char b9, char b10, char b11, char b12, char b13, char b14, char b15) - { - m = _mm_set_epi8(b15, b14, b13, b12, b11, b10, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0); - } - - GSVector4i(const GSVector4i& v) - { - m = v.m; - } - - explicit GSVector4i(const GSVector2i& v) - { - m = _mm_loadl_epi64((__m128i*)&v); - } - - explicit GSVector4i(int i) - { - m = _mm_set1_epi32(i); - } - - explicit GSVector4i(__m128i m) - { - this->m = m; - } - - explicit GSVector4i(const CRect& r) - { - *this = GSVector4i(r.left, r.top, r.right, r.bottom); - } - - explicit GSVector4i(const GSVector4& v) - { - *this = v; - } - - void operator = (const GSVector4i& v) - { - m = v.m; - } - - void operator = (const GSVector4& v); - - void operator = (int i) - { - m = _mm_set1_epi32(i); - } - - void operator = (__m128i m) - { - this->m = m; - } - - void operator = (const CRect& r) - { - m = GSVector4i(r); - } - - operator __m128i() const - { - return m; - } - - operator CRect() const - { - return *(CRect*)&m; - } - - UINT32 rgba32() const - { - GSVector4i v = *this; - - v = v.ps32(v); - v = v.pu16(v); - - return (UINT32)store(v); - } - - static GSVector4i cast(const GSVector4& v); - - #if _M_SSE >= 0x401 - - GSVector4i sat_i8(const GSVector4i& a, const GSVector4i& b) const - { - return max_i8(a).min_i8(b); - } - - GSVector4i sat_i8(const GSVector4i& a) const - { - return max_i8(a.xyxy()).min_i8(a.zwzw()); - } - - #endif - - GSVector4i sat_i16(const GSVector4i& a, const GSVector4i& b) const - { - return max_i16(a).min_i16(b); - } - - GSVector4i sat_i16(const GSVector4i& a) const - { - return max_i16(a.xyxy()).min_i16(a.zwzw()); - } - - #if _M_SSE >= 0x401 - - GSVector4i sat_i32(const GSVector4i& a, const GSVector4i& b) const - { - return max_i32(a).min_i32(b); - } - - GSVector4i sat_i32(const GSVector4i& a) const - { - return max_i32(a.xyxy()).min_i32(a.zwzw()); - } - - #endif - - GSVector4i sat_u8(const GSVector4i& a, const GSVector4i& b) const - { - return max_u8(a).min_u8(b); - } - - GSVector4i sat_u8(const GSVector4i& a) const - { - return max_u8(a.xyxy()).min_u8(a.zwzw()); - } - - #if _M_SSE >= 0x401 - - GSVector4i sat_u16(const GSVector4i& a, const GSVector4i& b) const - { - return max_u16(a).min_u16(b); - } - - GSVector4i sat_u16(const GSVector4i& a) const - { - return max_u16(a.xyxy()).min_u16(a.zwzw()); - } - - #endif - - #if _M_SSE >= 0x401 - - GSVector4i sat_u32(const GSVector4i& a, const GSVector4i& b) const - { - return max_u32(a).min_u32(b); - } - - GSVector4i sat_u32(const GSVector4i& a) const - { - return max_u32(a.xyxy()).min_u32(a.zwzw()); - } - - #endif - - #if _M_SSE >= 0x401 - - GSVector4i min_i8(const GSVector4i& a) const - { - return GSVector4i(_mm_min_epi8(m, a)); - } - - GSVector4i max_i8(const GSVector4i& a) const - { - return GSVector4i(_mm_max_epi8(m, a)); - } - - #endif - - GSVector4i min_i16(const GSVector4i& a) const - { - return GSVector4i(_mm_min_epi16(m, a)); - } - - GSVector4i max_i16(const GSVector4i& a) const - { - return GSVector4i(_mm_max_epi16(m, a)); - } - - #if _M_SSE >= 0x401 - - GSVector4i min_i32(const GSVector4i& a) const - { - return GSVector4i(_mm_min_epi32(m, a)); - } - - GSVector4i max_i32(const GSVector4i& a) const - { - return GSVector4i(_mm_max_epi32(m, a)); - } - - #endif - - GSVector4i min_u8(const GSVector4i& a) const - { - return GSVector4i(_mm_min_epu8(m, a)); - } - - GSVector4i max_u8(const GSVector4i& a) const - { - return GSVector4i(_mm_max_epu8(m, a)); - } - - #if _M_SSE >= 0x401 - - GSVector4i min_u16(const GSVector4i& a) const - { - return GSVector4i(_mm_min_epu16(m, a)); - } - - GSVector4i max_u16(const GSVector4i& a) const - { - return GSVector4i(_mm_max_epu16(m, a)); - } - - GSVector4i min_u32(const GSVector4i& a) const - { - return GSVector4i(_mm_min_epu32(m, a)); - } - - GSVector4i max_u32(const GSVector4i& a) const - { - return GSVector4i(_mm_max_epu32(m, a)); - } - - #endif - - static int min_i16(int a, int b) - { - return store(load(a).min_i16(load(b))); - } - - GSVector4i clamp8() const - { - return pu16().upl8(); - } - - GSVector4i blend8(const GSVector4i& a, const GSVector4i& mask) const - { - return GSVector4i(_mm_blendv_epi8(m, a, mask)); - } - - #if _M_SSE >= 0x401 - - template GSVector4i blend16(const GSVector4i& a) const - { - return GSVector4i(_mm_blend_epi16(m, a, mask)); - } - - #endif - - GSVector4i blend(const GSVector4i& a, const GSVector4i& mask) const - { - return GSVector4i(_mm_or_si128(_mm_andnot_si128(mask, m), _mm_and_si128(mask, a))); - } - - GSVector4i mix16(const GSVector4i& a) const - { - #if _M_SSE >= 0x401 - - return blend16<0xaa>(a); - - #else - - return blend8(a, GSVector4i::xffff0000()); - - #endif - } - - #if _M_SSE >= 0x301 - - GSVector4i shuffle8(const GSVector4i& mask) const - { - return GSVector4i(_mm_shuffle_epi8(m, mask)); - } - - #endif - - GSVector4i ps16(const GSVector4i& a) const - { - return GSVector4i(_mm_packs_epi16(m, a)); - } - - GSVector4i ps16() const - { - return GSVector4i(_mm_packs_epi16(m, m)); - } - - GSVector4i pu16(const GSVector4i& a) const - { - return GSVector4i(_mm_packus_epi16(m, a)); - } - - GSVector4i pu16() const - { - return GSVector4i(_mm_packus_epi16(m, m)); - } - - GSVector4i ps32(const GSVector4i& a) const - { - return GSVector4i(_mm_packs_epi32(m, a)); - } - - GSVector4i ps32() const - { - return GSVector4i(_mm_packs_epi32(m, m)); - } - - #if _M_SSE >= 0x401 - - GSVector4i pu32(const GSVector4i& a) const - { - return GSVector4i(_mm_packus_epi32(m, a)); - } - - GSVector4i pu32() const - { - return GSVector4i(_mm_packus_epi32(m, m)); - } - - #endif - - GSVector4i upl8(const GSVector4i& a) const - { - return GSVector4i(_mm_unpacklo_epi8(m, a)); - } - - GSVector4i uph8(const GSVector4i& a) const - { - return GSVector4i(_mm_unpackhi_epi8(m, a)); - } - - GSVector4i upl16(const GSVector4i& a) const - { - return GSVector4i(_mm_unpacklo_epi16(m, a)); - } - - GSVector4i uph16(const GSVector4i& a) const - { - return GSVector4i(_mm_unpackhi_epi16(m, a)); - } - - GSVector4i upl32(const GSVector4i& a) const - { - return GSVector4i(_mm_unpacklo_epi32(m, a)); - } - - GSVector4i uph32(const GSVector4i& a) const - { - return GSVector4i(_mm_unpackhi_epi32(m, a)); - } - - GSVector4i upl64(const GSVector4i& a) const - { - return GSVector4i(_mm_unpacklo_epi64(m, a)); - } - - GSVector4i uph64(const GSVector4i& a) const - { - return GSVector4i(_mm_unpackhi_epi64(m, a)); - } - - GSVector4i upl8() const - { - #if 0 // _M_SSE >= 0x401 // TODO: compiler bug - - return GSVector4i(_mm_cvtepu8_epi16(m)); - - #else - - return GSVector4i(_mm_unpacklo_epi8(m, _mm_setzero_si128())); - - #endif - } - - GSVector4i uph8() const - { - return GSVector4i(_mm_unpackhi_epi8(m, _mm_setzero_si128())); - } - - GSVector4i upl16() const - { - #if 0 //_M_SSE >= 0x401 // TODO: compiler bug - - return GSVector4i(_mm_cvtepu16_epi32(m)); - - #else - - return GSVector4i(_mm_unpacklo_epi16(m, _mm_setzero_si128())); - - #endif - } - - GSVector4i uph16() const - { - return GSVector4i(_mm_unpackhi_epi16(m, _mm_setzero_si128())); - } - - GSVector4i upl32() const - { - #if 0 //_M_SSE >= 0x401 // TODO: compiler bug - - return GSVector4i(_mm_cvtepu32_epi64(m)); - - #else - - return GSVector4i(_mm_unpacklo_epi32(m, _mm_setzero_si128())); - - #endif - } - - GSVector4i uph32() const - { - return GSVector4i(_mm_unpackhi_epi32(m, _mm_setzero_si128())); - } - - GSVector4i upl64() const - { - return GSVector4i(_mm_unpacklo_epi64(m, _mm_setzero_si128())); - } - - GSVector4i uph64() const - { - return GSVector4i(_mm_unpackhi_epi64(m, _mm_setzero_si128())); - } - - #if _M_SSE >= 0x401 - - // WARNING!!! - // - // MSVC (2008, 2010 ctp) believes that there is a "mem, reg" form of the pmovz/sx* instructions, - // turning these intrinsics into a minefield, don't spill regs when using them... - - GSVector4i i8to16() const - { - return GSVector4i(_mm_cvtepi8_epi16(m)); - } - - GSVector4i u8to16() const - { - return GSVector4i(_mm_cvtepu8_epi16(m)); - } - - GSVector4i i8to32() const - { - return GSVector4i(_mm_cvtepi8_epi32(m)); - } - - GSVector4i u8to32() const - { - return GSVector4i(_mm_cvtepu8_epi32(m)); - } - - GSVector4i i8to64() const - { - return GSVector4i(_mm_cvtepi8_epi64(m)); - } - - GSVector4i u8to64() const - { - return GSVector4i(_mm_cvtepu16_epi64(m)); - } - - GSVector4i i16to32() const - { - return GSVector4i(_mm_cvtepi16_epi32(m)); - } - - GSVector4i u16to32() const - { - return GSVector4i(_mm_cvtepu16_epi32(m)); - } - - GSVector4i i16to64() const - { - return GSVector4i(_mm_cvtepi16_epi64(m)); - } - - GSVector4i u16to64() const - { - return GSVector4i(_mm_cvtepu16_epi64(m)); - } - - GSVector4i i32to64() const - { - return GSVector4i(_mm_cvtepi32_epi64(m)); - } - - GSVector4i u32to64() const - { - return GSVector4i(_mm_cvtepu32_epi64(m)); - } - - #else - - GSVector4i u8to16() const - { - return upl8(); - } - - GSVector4i u8to32() const - { - return upl8().upl16(); - } - - GSVector4i u8to64() const - { - return upl8().upl16().upl32(); - } - - GSVector4i u16to32() const - { - return upl16(); - } - - GSVector4i u16to64() const - { - return upl16().upl32(); - } - - GSVector4i u32to64() const - { - return upl32(); - } - - #endif - - template GSVector4i srl() const - { - #pragma warning(push) - #pragma warning(disable: 4556) - - return GSVector4i(_mm_srli_si128(m, i)); - - #pragma warning(pop) - } - - template GSVector4i srl(const GSVector4i& v) - { - #if _M_SSE >= 0x301 - - return GSVector4i(_mm_alignr_epi8(v.m, m, i)); - - #else - - if(i == 0) return *this; - else if(i < 16) return srl() | v.sll<16 - i>(); - else if(i == 16) return v; - else if(i < 32) return v.srl(); - else return zero(); - - #endif - } - - template GSVector4i sll() const - { - #pragma warning(push) - #pragma warning(disable: 4556) - - return GSVector4i(_mm_slli_si128(m, i)); - - #pragma warning(pop) - } - - GSVector4i sra16(int i) const - { - return GSVector4i(_mm_srai_epi16(m, i)); - } - - GSVector4i sra32(int i) const - { - return GSVector4i(_mm_srai_epi32(m, i)); - } - - GSVector4i sll16(int i) const - { - return GSVector4i(_mm_slli_epi16(m, i)); - } - - GSVector4i sll32(int i) const - { - return GSVector4i(_mm_slli_epi32(m, i)); - } - - GSVector4i sll64(int i) const - { - return GSVector4i(_mm_slli_epi64(m, i)); - } - - GSVector4i srl16(int i) const - { - return GSVector4i(_mm_srli_epi16(m, i)); - } - - GSVector4i srl32(int i) const - { - return GSVector4i(_mm_srli_epi32(m, i)); - } - - GSVector4i srl64(int i) const - { - return GSVector4i(_mm_srli_epi64(m, i)); - } - - GSVector4i add8(const GSVector4i& v) const - { - return GSVector4i(_mm_add_epi8(m, v.m)); - } - - GSVector4i add16(const GSVector4i& v) const - { - return GSVector4i(_mm_add_epi16(m, v.m)); - } - - GSVector4i add32(const GSVector4i& v) const - { - return GSVector4i(_mm_add_epi32(m, v.m)); - } - - GSVector4i adds8(const GSVector4i& v) const - { - return GSVector4i(_mm_adds_epi8(m, v.m)); - } - - GSVector4i adds16(const GSVector4i& v) const - { - return GSVector4i(_mm_adds_epi16(m, v.m)); - } - - GSVector4i addus8(const GSVector4i& v) const - { - return GSVector4i(_mm_adds_epu8(m, v.m)); - } - - GSVector4i addus16(const GSVector4i& v) const - { - return GSVector4i(_mm_adds_epu16(m, v.m)); - } - - GSVector4i sub8(const GSVector4i& v) const - { - return GSVector4i(_mm_sub_epi8(m, v.m)); - } - - GSVector4i sub16(const GSVector4i& v) const - { - return GSVector4i(_mm_sub_epi16(m, v.m)); - } - - GSVector4i sub32(const GSVector4i& v) const - { - return GSVector4i(_mm_sub_epi32(m, v.m)); - } - - GSVector4i subs8(const GSVector4i& v) const - { - return GSVector4i(_mm_subs_epi8(m, v.m)); - } - - GSVector4i subs16(const GSVector4i& v) const - { - return GSVector4i(_mm_subs_epi16(m, v.m)); - } - - GSVector4i subus8(const GSVector4i& v) const - { - return GSVector4i(_mm_subs_epu8(m, v.m)); - } - - GSVector4i subus16(const GSVector4i& v) const - { - return GSVector4i(_mm_subs_epu16(m, v.m)); - } - - GSVector4i avg8(const GSVector4i& v) const - { - return GSVector4i(_mm_avg_epu8(m, v.m)); - } - - GSVector4i avg16(const GSVector4i& v) const - { - return GSVector4i(_mm_avg_epu16(m, v.m)); - } - - GSVector4i mul16hs(const GSVector4i& v) const - { - return GSVector4i(_mm_mulhi_epi16(m, v.m)); - } - - GSVector4i mul16hu(const GSVector4i& v) const - { - return GSVector4i(_mm_mulhi_epu16(m, v.m)); - } - - GSVector4i mul16l(const GSVector4i& v) const - { - return GSVector4i(_mm_mullo_epi16(m, v.m)); - } - - #if _M_SSE >= 0x301 - - GSVector4i mul16hrs(const GSVector4i& v) const - { - return GSVector4i(_mm_mulhrs_epi16(m, v.m)); - } - - #endif - - template GSVector4i lerp16(const GSVector4i& a, const GSVector4i& f) const - { - // (a - this) * f << shift + this - - return add16(a.sub16(*this).modulate16(f)); - } - - template static GSVector4i lerp16(const GSVector4i& a, const GSVector4i& b, const GSVector4i& c) - { - // (a - b) * c << shift - - return a.sub16(b).modulate16(c); - } - - template static GSVector4i lerp16(const GSVector4i& a, const GSVector4i& b, const GSVector4i& c, const GSVector4i& d) - { - // (a - b) * c << shift + d - - return d.add16(a.sub16(b).modulate16(c)); - } - - template GSVector4i modulate16(const GSVector4i& f) const - { - // a * f << shift - - #if _M_SSE >= 0x301 - - if(shift == 0) - { - return mul16hrs(f); - } - - #endif - - return sll16(shift + 1).mul16hs(f); - } - - GSVector4i eq8(const GSVector4i& v) const - { - return GSVector4i(_mm_cmpeq_epi8(m, v.m)); - } - - GSVector4i eq16(const GSVector4i& v) const - { - return GSVector4i(_mm_cmpeq_epi16(m, v.m)); - } - - GSVector4i eq32(const GSVector4i& v) const - { - return GSVector4i(_mm_cmpeq_epi32(m, v.m)); - } - - GSVector4i neq8(const GSVector4i& v) const - { - return ~eq8(v); - } - - GSVector4i neq16(const GSVector4i& v) const - { - return ~eq16(v); - } - - GSVector4i neq32(const GSVector4i& v) const - { - return ~eq32(v); - } - - GSVector4i gt8(const GSVector4i& v) const - { - return GSVector4i(_mm_cmpgt_epi8(m, v.m)); - } - - GSVector4i gt16(const GSVector4i& v) const - { - return GSVector4i(_mm_cmpgt_epi16(m, v.m)); - } - - GSVector4i gt32(const GSVector4i& v) const - { - return GSVector4i(_mm_cmpgt_epi32(m, v.m)); - } - - GSVector4i lt8(const GSVector4i& v) const - { - return GSVector4i(_mm_cmplt_epi8(m, v.m)); - } - - GSVector4i lt16(const GSVector4i& v) const - { - return GSVector4i(_mm_cmplt_epi16(m, v.m)); - } - - GSVector4i lt32(const GSVector4i& v) const - { - return GSVector4i(_mm_cmplt_epi32(m, v.m)); - } - - GSVector4i andnot(const GSVector4i& v) const - { - return GSVector4i(_mm_andnot_si128(v.m, m)); - } - - int mask() const - { - return _mm_movemask_epi8(m); - } - - bool alltrue() const - { - return _mm_movemask_epi8(m) == 0xffff; - } - - bool anytrue() const - { - return _mm_movemask_epi8(m) != 0x0000; - } - - #if _M_SSE >= 0x401 - - template GSVector4i insert8(int a) const - { - return GSVector4i(_mm_insert_epi8(m, a, i)); - } - - #endif - - template int extract8() const - { - #if _M_SSE >= 0x401 - return _mm_extract_epi8(m, i); - #else - return (int)u8[i]; - #endif - } - - template GSVector4i insert16(int a) const - { - return GSVector4i(_mm_insert_epi16(m, a, i)); - } - - template int extract16() const - { - return _mm_extract_epi16(m, i); - } - - #if _M_SSE >= 0x401 - - template GSVector4i insert32(int a) const - { - return GSVector4i(_mm_insert_epi32(m, a, i)); - } - - #endif - - template int extract32() const - { - if(i == 0) return GSVector4i::store(*this); - #if _M_SSE >= 0x401 - return _mm_extract_epi32(m, i); - #else - return i32[i]; - #endif - } - - #ifdef _M_AMD64 - - #if _M_SSE >= 0x401 - - template GSVector4i insert64(__int64 a) const - { - return GSVector4i(_mm_insert_epi64(m, a, i)); - } - - #endif - - template __int64 extract64() const - { - if(i == 0) return GSVector4i::storeq(*this); - #if _M_SSE >= 0x401 - return _mm_extract_epi64(m, i); - #else - return i64[i]; - #endif - } - - #endif - - #if _M_SSE >= 0x401 - - template __forceinline GSVector4i gather8_4(const T* ptr) const - { - GSVector4i v; - - v = load((int)ptr[extract8() & 0xf]); - v = v.insert8<1>((int)ptr[extract8() >> 4]); - v = v.insert8<2>((int)ptr[extract8() & 0xf]); - v = v.insert8<3>((int)ptr[extract8() >> 4]); - v = v.insert8<4>((int)ptr[extract8() & 0xf]); - v = v.insert8<5>((int)ptr[extract8() >> 4]); - v = v.insert8<6>((int)ptr[extract8() & 0xf]); - v = v.insert8<7>((int)ptr[extract8() >> 4]); - v = v.insert8<8>((int)ptr[extract8() & 0xf]); - v = v.insert8<9>((int)ptr[extract8() >> 4]); - v = v.insert8<10>((int)ptr[extract8() & 0xf]); - v = v.insert8<11>((int)ptr[extract8() >> 4]); - v = v.insert8<12>((int)ptr[extract8() & 0xf]); - v = v.insert8<13>((int)ptr[extract8() >> 4]); - v = v.insert8<14>((int)ptr[extract8() & 0xf]); - v = v.insert8<15>((int)ptr[extract8() >> 4]); - - return v; - } - - template __forceinline GSVector4i gather8_8(const T* ptr) const - { - GSVector4i v; - - v = load((int)ptr[extract8<0>()]); - v = v.insert8<1>((int)ptr[extract8<1>()]); - v = v.insert8<2>((int)ptr[extract8<2>()]); - v = v.insert8<3>((int)ptr[extract8<3>()]); - v = v.insert8<4>((int)ptr[extract8<4>()]); - v = v.insert8<5>((int)ptr[extract8<5>()]); - v = v.insert8<6>((int)ptr[extract8<6>()]); - v = v.insert8<7>((int)ptr[extract8<7>()]); - v = v.insert8<8>((int)ptr[extract8<8>()]); - v = v.insert8<9>((int)ptr[extract8<9>()]); - v = v.insert8<10>((int)ptr[extract8<10>()]); - v = v.insert8<11>((int)ptr[extract8<11>()]); - v = v.insert8<12>((int)ptr[extract8<12>()]); - v = v.insert8<13>((int)ptr[extract8<13>()]); - v = v.insert8<14>((int)ptr[extract8<14>()]); - v = v.insert8<15>((int)ptr[extract8<15>()]); - - return v; - } - - template __forceinline GSVector4i gather8_16(const T* ptr, const GSVector4i& a) const - { - GSVector4i v = a; - - v = v.insert8((int)ptr[extract16<0>()]); - v = v.insert8((int)ptr[extract16<1>()]); - v = v.insert8((int)ptr[extract16<2>()]); - v = v.insert8((int)ptr[extract16<3>()]); - v = v.insert8((int)ptr[extract16<4>()]); - v = v.insert8((int)ptr[extract16<5>()]); - v = v.insert8((int)ptr[extract16<6>()]); - v = v.insert8((int)ptr[extract16<7>()]); - - return v; - } - - template __forceinline GSVector4i gather8_32(const T* ptr, const GSVector4i& a) const - { - GSVector4i v = a; - - v = v.insert8((int)ptr[extract32<0>()]); - v = v.insert8((int)ptr[extract32<1>()]); - v = v.insert8((int)ptr[extract32<2>()]); - v = v.insert8((int)ptr[extract32<3>()]); - - return v; - } - - #endif - - template __forceinline GSVector4i gather16_4(const T* ptr) const - { - GSVector4i v; - - v = load((int)ptr[extract8() & 0xf]); - v = v.insert16<1>((int)ptr[extract8() >> 4]); - v = v.insert16<2>((int)ptr[extract8() & 0xf]); - v = v.insert16<3>((int)ptr[extract8() >> 4]); - v = v.insert16<4>((int)ptr[extract8() & 0xf]); - v = v.insert16<5>((int)ptr[extract8() >> 4]); - v = v.insert16<6>((int)ptr[extract8() & 0xf]); - v = v.insert16<7>((int)ptr[extract8() >> 4]); - - return v; - } - - template __forceinline GSVector4i gather16_8(const T* ptr) const - { - GSVector4i v; - - v = load((int)ptr[extract8()]); - v = v.insert16<1>((int)ptr[extract8()]); - v = v.insert16<2>((int)ptr[extract8()]); - v = v.insert16<3>((int)ptr[extract8()]); - v = v.insert16<4>((int)ptr[extract8()]); - v = v.insert16<5>((int)ptr[extract8()]); - v = v.insert16<6>((int)ptr[extract8()]); - v = v.insert16<7>((int)ptr[extract8()]); - - return v; - } - - template__forceinline GSVector4i gather16_16(const T* ptr) const - { - GSVector4i v; - - v = load((int)ptr[extract16<0>()]); - v = v.insert16<1>((int)ptr[extract16<1>()]); - v = v.insert16<2>((int)ptr[extract16<2>()]); - v = v.insert16<3>((int)ptr[extract16<3>()]); - v = v.insert16<4>((int)ptr[extract16<4>()]); - v = v.insert16<5>((int)ptr[extract16<5>()]); - v = v.insert16<6>((int)ptr[extract16<6>()]); - v = v.insert16<7>((int)ptr[extract16<7>()]); - - return v; - } - - template__forceinline GSVector4i gather16_16(const T1* ptr1, const T2* ptr2) const - { - GSVector4i v; - - v = load((int)ptr2[ptr1[extract16<0>()]]); - v = v.insert16<1>((int)ptr2[ptr1[extract16<1>()]]); - v = v.insert16<2>((int)ptr2[ptr1[extract16<2>()]]); - v = v.insert16<3>((int)ptr2[ptr1[extract16<3>()]]); - v = v.insert16<4>((int)ptr2[ptr1[extract16<4>()]]); - v = v.insert16<5>((int)ptr2[ptr1[extract16<5>()]]); - v = v.insert16<6>((int)ptr2[ptr1[extract16<6>()]]); - v = v.insert16<7>((int)ptr2[ptr1[extract16<7>()]]); - - return v; - } - - template __forceinline GSVector4i gather16_32(const T* ptr, const GSVector4i& a) const - { - GSVector4i v = a; - - v = v.insert16((int)ptr[extract32<0>()]); - v = v.insert16((int)ptr[extract32<1>()]); - v = v.insert16((int)ptr[extract32<2>()]); - v = v.insert16((int)ptr[extract32<3>()]); - - return v; - } - - #if _M_SSE >= 0x401 - - template __forceinline GSVector4i gather32_4(const T* ptr) const - { - GSVector4i v; - - v = load((int)ptr[extract8() & 0xf]); - v = v.insert32<1>((int)ptr[extract8() >> 4]); - v = v.insert32<2>((int)ptr[extract8() & 0xf]); - v = v.insert32<3>((int)ptr[extract8() >> 4]); - return v; - } - - template __forceinline GSVector4i gather32_8(const T* ptr) const - { - GSVector4i v; - - v = load((int)ptr[extract8()]); - v = v.insert32<1>((int)ptr[extract8()]); - v = v.insert32<2>((int)ptr[extract8()]); - v = v.insert32<3>((int)ptr[extract8()]); - - return v; - } - - template __forceinline GSVector4i gather32_16(const T* ptr) const - { - GSVector4i v; - - v = load((int)ptr[extract16()]); - v = v.insert32<1>((int)ptr[extract16()]); - v = v.insert32<2>((int)ptr[extract16()]); - v = v.insert32<3>((int)ptr[extract16()]); - - return v; - } - - template __forceinline GSVector4i gather32_32(const T* ptr) const - { - GSVector4i v; - - v = load((int)ptr[extract32<0>()]); - v = v.insert32<1>((int)ptr[extract32<1>()]); - v = v.insert32<2>((int)ptr[extract32<2>()]); - v = v.insert32<3>((int)ptr[extract32<3>()]); - - return v; - } - - template __forceinline GSVector4i gather32_32(const T1* ptr1, const T2* ptr2) const - { - GSVector4i v; - - v = load((int)ptr2[ptr1[extract32<0>()]]); - v = v.insert32<1>((int)ptr2[ptr1[extract32<1>()]]); - v = v.insert32<2>((int)ptr2[ptr1[extract32<2>()]]); - v = v.insert32<3>((int)ptr2[ptr1[extract32<3>()]]); - - return v; - } - - #else - - template __forceinline GSVector4i gather32_4(const T* ptr) const - { - return GSVector4i( - (int)ptr[extract8() & 0xf], - (int)ptr[extract8() >> 4], - (int)ptr[extract8() & 0xf], - (int)ptr[extract8() >> 4]); - } - - template __forceinline GSVector4i gather32_8(const T* ptr) const - { - return GSVector4i( - (int)ptr[extract8()], - (int)ptr[extract8()], - (int)ptr[extract8()], - (int)ptr[extract8()]); - } - - template __forceinline GSVector4i gather32_16(const T* ptr) const - { - return GSVector4i( - (int)ptr[extract16()], - (int)ptr[extract16()], - (int)ptr[extract16()], - (int)ptr[extract16()]); - } - - template __forceinline GSVector4i gather32_32(const T* ptr) const - { - return GSVector4i( - (int)ptr[extract32<0>()], - (int)ptr[extract32<1>()], - (int)ptr[extract32<2>()], - (int)ptr[extract32<3>()]); - } - - template __forceinline GSVector4i gather32_32(const T1* ptr1, const T2* ptr2) const - { - return GSVector4i( - (int)ptr2[ptr1[extract32<0>()]], - (int)ptr2[ptr1[extract32<1>()]], - (int)ptr2[ptr1[extract32<2>()]], - (int)ptr2[ptr1[extract32<3>()]]); - } - - #endif - - #if defined(_M_AMD64) && _M_SSE >= 0x401 - - template __forceinline GSVector4i gather64_4(const T* ptr) const - { - GSVector4i v; - - v = loadq((__int64)ptr[extract8() & 0xf]); - v = v.insert64<1>((__int64)ptr[extract8() >> 4]); - - return v; - } - - template __forceinline GSVector4i gather64_8(const T* ptr) const - { - GSVector4i v; - - v = loadq((__int64)ptr[extract8()]); - v = v.insert64<1>((__int64)ptr[extract8()]); - - return v; - } - - template __forceinline GSVector4i gather64_16(const T* ptr) const - { - GSVector4i v; - - v = loadq((__int64)ptr[extract16()]); - v = v.insert64<1>((__int64)ptr[extract16()]); - - return v; - } - - template __forceinline GSVector4i gather64_32(const T* ptr) const - { - GSVector4i v; - - v = loadq((__int64)ptr[extract32()]); - v = v.insert64<1>((__int64)ptr[extract32()]); - - return v; - } - - template __forceinline GSVector4i gather64_64(const T* ptr) const - { - GSVector4i v; - - v = loadq((__int64)ptr[extract64<0>()]); - v = v.insert64<1>((__int64)ptr[extract64<1>()]); - - return v; - } - - #else - - template __forceinline GSVector4i gather64_4(const T* ptr) const - { - GSVector4i v; - - v = loadu(&ptr[extract8() & 0xf], &ptr[extract8() >> 4]); - - return v; - } - - template __forceinline GSVector4i gather64_8(const T* ptr) const - { - GSVector4i v; - - v = load(&ptr[extract8()], &ptr[extract8()]); - - return v; - } - - template __forceinline GSVector4i gather64_16(const T* ptr) const - { - GSVector4i v; - - v = load(&ptr[extract16()], &ptr[extract16()]); - - return v; - } - - template __forceinline GSVector4i gather64_32(const T* ptr) const - { - GSVector4i v; - - v = load(&ptr[extract32()], &ptr[extract32()]); - - return v; - } - - #endif - - #if _M_SSE >= 0x401 - - template __forceinline void gather8_4(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const - { - dst[0] = gather8_4<0>(ptr); - dst[1] = gather8_4<8>(ptr); - } - - __forceinline void gather8_8(const BYTE* RESTRICT ptr, GSVector4i* RESTRICT dst) const - { - dst[0] = gather8_8<>(ptr); - } - - #endif - - template __forceinline void gather16_4(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const - { - dst[0] = gather16_4<0>(ptr); - dst[1] = gather16_4<4>(ptr); - dst[2] = gather16_4<8>(ptr); - dst[3] = gather16_4<12>(ptr); - } - - template __forceinline void gather16_8(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const - { - dst[0] = gather16_8<0>(ptr); - dst[1] = gather16_8<8>(ptr); - } - - template __forceinline void gather16_16(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const - { - dst[0] = gather16_16<>(ptr); - } - - template __forceinline void gather32_4(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const - { - dst[0] = gather32_4<0>(ptr); - dst[1] = gather32_4<2>(ptr); - dst[2] = gather32_4<4>(ptr); - dst[3] = gather32_4<6>(ptr); - dst[4] = gather32_4<8>(ptr); - dst[5] = gather32_4<10>(ptr); - dst[6] = gather32_4<12>(ptr); - dst[7] = gather32_4<14>(ptr); - } - - template __forceinline void gather32_8(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const - { - dst[0] = gather32_8<0>(ptr); - dst[1] = gather32_8<4>(ptr); - dst[2] = gather32_8<8>(ptr); - dst[3] = gather32_8<12>(ptr); - } - - template __forceinline void gather32_16(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const - { - dst[0] = gather32_16<0>(ptr); - dst[1] = gather32_16<4>(ptr); - } - - template __forceinline void gather32_32(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const - { - dst[0] = gather32_32<>(ptr); - } - - template __forceinline void gather64_4(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const - { - dst[0] = gather64_4<0>(ptr); - dst[1] = gather64_4<1>(ptr); - dst[2] = gather64_4<2>(ptr); - dst[3] = gather64_4<3>(ptr); - dst[4] = gather64_4<4>(ptr); - dst[5] = gather64_4<5>(ptr); - dst[6] = gather64_4<6>(ptr); - dst[7] = gather64_4<7>(ptr); - dst[8] = gather64_4<8>(ptr); - dst[9] = gather64_4<9>(ptr); - dst[10] = gather64_4<10>(ptr); - dst[11] = gather64_4<11>(ptr); - dst[12] = gather64_4<12>(ptr); - dst[13] = gather64_4<13>(ptr); - dst[14] = gather64_4<14>(ptr); - dst[15] = gather64_4<15>(ptr); - } - - template __forceinline void gather64_8(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const - { - dst[0] = gather64_8<0>(ptr); - dst[1] = gather64_8<2>(ptr); - dst[2] = gather64_8<4>(ptr); - dst[3] = gather64_8<6>(ptr); - dst[4] = gather64_8<8>(ptr); - dst[5] = gather64_8<10>(ptr); - dst[6] = gather64_8<12>(ptr); - dst[7] = gather64_8<14>(ptr); - } - - template __forceinline void gather64_16(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const - { - dst[0] = gather64_16<0>(ptr); - dst[1] = gather64_16<2>(ptr); - dst[2] = gather64_16<4>(ptr); - dst[3] = gather64_16<8>(ptr); - } - - template __forceinline void gather64_32(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const - { - dst[0] = gather64_32<0>(ptr); - dst[1] = gather64_32<2>(ptr); - } - - #ifdef _M_AMD64 - - template __forceinline void gather64_64(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const - { - dst[0] = gather64_64<>(ptr); - } - - #endif - - #if _M_SSE >= 0x401 - - static GSVector4i loadnt(const void* p) - { - return GSVector4i(_mm_stream_load_si128((__m128i*)p)); - } - - #endif - - static GSVector4i loadl(const void* p) - { - return GSVector4i(_mm_loadl_epi64((__m128i*)p)); - } - - static GSVector4i loadh(const void* p) - { - return GSVector4i(_mm_castps_si128(_mm_loadh_pi(_mm_setzero_ps(), (__m64*)p))); - } - - static GSVector4i loadh(const void* p, const GSVector4i& v) - { - return GSVector4i(_mm_castps_si128(_mm_loadh_pi(_mm_castsi128_ps(v.m), (__m64*)p))); - } - - static GSVector4i load(const void* pl, const void* ph) - { - return loadh(ph, loadl(pl)); - } -/* - static GSVector4i load(const void* pl, const void* ph) - { - __m128i lo = _mm_loadl_epi64((__m128i*)pl); - __m128i hi = _mm_loadl_epi64((__m128i*)ph); - - return GSVector4i(_mm_unpacklo_epi64(lo, hi)); - } -*/ - template static GSVector4i load(const void* p) - { - return GSVector4i(aligned ? _mm_load_si128((__m128i*)p) : _mm_loadu_si128((__m128i*)p)); - } - - static GSVector4i load(int i) - { - return GSVector4i(_mm_cvtsi32_si128(i)); - } - - #ifdef _M_AMD64 - - static GSVector4i loadq(__int64 i) - { - return GSVector4i(_mm_cvtsi64_si128(i)); - } - - #endif - - static void storent(void* p, const GSVector4i& v) - { - _mm_stream_si128((__m128i*)p, v.m); - } - - static void storel(void* p, const GSVector4i& v) - { - _mm_storel_epi64((__m128i*)p, v.m); - } - - static void storeh(void* p, const GSVector4i& v) - { - _mm_storeh_pi((__m64*)p, _mm_castsi128_ps(v.m)); - } - - static void store(void* pl, void* ph, const GSVector4i& v) - { - GSVector4i::storel(pl, v); - GSVector4i::storeh(ph, v); - } - - template static void store(void* p, const GSVector4i& v) - { - if(aligned) _mm_store_si128((__m128i*)p, v.m); - else _mm_storeu_si128((__m128i*)p, v.m); - } - - static int store(const GSVector4i& v) - { - return _mm_cvtsi128_si32(v.m); - } - - #ifdef _M_AMD64 - - static __int64 storeq(const GSVector4i& v) - { - return _mm_cvtsi128_si64(v.m); - } - - #endif - - __forceinline static void transpose(GSVector4i& a, GSVector4i& b, GSVector4i& c, GSVector4i& d) - { - _MM_TRANSPOSE4_SI128(a.m, b.m, c.m, d.m); - } - - __forceinline static void sw4(GSVector4i& a, GSVector4i& b, GSVector4i& c, GSVector4i& d) - { - const __m128i epi32_0f0f0f0f = _mm_set1_epi32(0x0f0f0f0f); - - GSVector4i mask(epi32_0f0f0f0f); - - GSVector4i e = (b << 4).blend(a, mask); - GSVector4i f = b.blend(a >> 4, mask); - GSVector4i g = (d << 4).blend(c, mask); - GSVector4i h = d.blend(c >> 4, mask); - - a = e.upl8(f); - c = e.uph8(f); - b = g.upl8(h); - d = g.uph8(h); - } - - __forceinline static void sw8(GSVector4i& a, GSVector4i& b, GSVector4i& c, GSVector4i& d) - { - GSVector4i e = a; - GSVector4i f = c; - - a = e.upl8(b); - c = e.uph8(b); - b = f.upl8(d); - d = f.uph8(d); - } - - __forceinline static void sw16(GSVector4i& a, GSVector4i& b, GSVector4i& c, GSVector4i& d) - { - GSVector4i e = a; - GSVector4i f = c; - - a = e.upl16(b); - c = e.uph16(b); - b = f.upl16(d); - d = f.uph16(d); - } - - __forceinline static void sw16rl(GSVector4i& a, GSVector4i& b, GSVector4i& c, GSVector4i& d) - { - GSVector4i e = a; - GSVector4i f = c; - - a = b.upl16(e); - c = e.uph16(b); - b = d.upl16(f); - d = f.uph16(d); - } - - __forceinline static void sw16rh(GSVector4i& a, GSVector4i& b, GSVector4i& c, GSVector4i& d) - { - GSVector4i e = a; - GSVector4i f = c; - - a = e.upl16(b); - c = b.uph16(e); - b = f.upl16(d); - d = d.uph16(f); - } - - __forceinline static void sw32(GSVector4i& a, GSVector4i& b, GSVector4i& c, GSVector4i& d) - { - GSVector4i e = a; - GSVector4i f = c; - - a = e.upl32(b); - c = e.uph32(b); - b = f.upl32(d); - d = f.uph32(d); - } - - __forceinline static void sw64(GSVector4i& a, GSVector4i& b, GSVector4i& c, GSVector4i& d) - { - GSVector4i e = a; - GSVector4i f = c; - - a = e.upl64(b); - c = e.uph64(b); - b = f.upl64(d); - d = f.uph64(d); - } - - __forceinline static bool compare(const void* dst, const void* src, int size) - { - ASSERT((size & 15) == 0); - - size >>= 4; - - GSVector4i* s = (GSVector4i*)src; - GSVector4i* d = (GSVector4i*)dst; - - GSVector4i v = GSVector4i::xffffffff(); - - for(int i = 0; i < size; i++) - { - v &= d[i] == s[i]; - } - - return v.alltrue(); - } - - __forceinline static bool update(const void* dst, const void* src, int size) - { - ASSERT((size & 15) == 0); - - size >>= 4; - - GSVector4i* s = (GSVector4i*)src; - GSVector4i* d = (GSVector4i*)dst; - - GSVector4i v = GSVector4i::xffffffff(); - - for(int i = 0; i < size; i++) - { - v &= d[i] == s[i]; - - d[i] = s[i]; - } - - return v.alltrue(); - } - - void operator += (const GSVector4i& v) - { - m = _mm_add_epi32(m, v); - } - - void operator -= (const GSVector4i& v) - { - m = _mm_sub_epi32(m, v); - } - - void operator += (int i) - { - *this += GSVector4i(i); - } - - void operator -= (int i) - { - *this -= GSVector4i(i); - } - - void operator <<= (const int i) - { - m = _mm_slli_epi32(m, i); - } - - void operator >>= (const int i) - { - m = _mm_srli_epi32(m, i); - } - - void operator &= (const GSVector4i& v) - { - m = _mm_and_si128(m, v); - } - - void operator |= (const GSVector4i& v) - { - m = _mm_or_si128(m, v); - } - - void operator ^= (const GSVector4i& v) - { - m = _mm_xor_si128(m, v); - } - - friend GSVector4i operator + (const GSVector4i& v1, const GSVector4i& v2) - { - return GSVector4i(_mm_add_epi32(v1, v2)); - } - - friend GSVector4i operator - (const GSVector4i& v1, const GSVector4i& v2) - { - return GSVector4i(_mm_sub_epi32(v1, v2)); - } - - friend GSVector4i operator + (const GSVector4i& v, int i) - { - return v + GSVector4i(i); - } - - friend GSVector4i operator - (const GSVector4i& v, int i) - { - return v - GSVector4i(i); - } - - friend GSVector4i operator << (const GSVector4i& v, const int i) - { - return GSVector4i(_mm_slli_epi32(v, i)); - } - - friend GSVector4i operator >> (const GSVector4i& v, const int i) - { - return GSVector4i(_mm_srli_epi32(v, i)); - } - - friend GSVector4i operator & (const GSVector4i& v1, const GSVector4i& v2) - { - return GSVector4i(_mm_and_si128(v1, v2)); - } - - friend GSVector4i operator | (const GSVector4i& v1, const GSVector4i& v2) - { - return GSVector4i(_mm_or_si128(v1, v2)); - } - - friend GSVector4i operator ^ (const GSVector4i& v1, const GSVector4i& v2) - { - return GSVector4i(_mm_xor_si128(v1, v2)); - } - - friend GSVector4i operator & (const GSVector4i& v, int i) - { - return v & GSVector4i(i); - } - - friend GSVector4i operator | (const GSVector4i& v, int i) - { - return v | GSVector4i(i); - } - - friend GSVector4i operator ^ (const GSVector4i& v, int i) - { - return v ^ GSVector4i(i); - } - - friend GSVector4i operator ~ (const GSVector4i& v) - { - return v ^ (v == v); - } - - friend GSVector4i operator == (const GSVector4i& v1, const GSVector4i& v2) - { - return GSVector4i(_mm_cmpeq_epi32(v1, v2)); - } - - friend GSVector4i operator != (const GSVector4i& v1, const GSVector4i& v2) - { - return ~(v1 == v2); - } - - friend GSVector4i operator > (const GSVector4i& v1, const GSVector4i& v2) - { - return GSVector4i(_mm_cmpgt_epi32(v1, v2)); - } - - friend GSVector4i operator < (const GSVector4i& v1, const GSVector4i& v2) - { - return GSVector4i(_mm_cmplt_epi32(v1, v2)); - } - - friend GSVector4i operator >= (const GSVector4i& v1, const GSVector4i& v2) - { - return (v1 > v2) | (v1 == v2); - } - - friend GSVector4i operator <= (const GSVector4i& v1, const GSVector4i& v2) - { - return (v1 < v2) | (v1 == v2); - } - - template GSVector4i shuffle() const - { - return GSVector4i(_mm_shuffle_epi32(m, _MM_SHUFFLE(i, i, i, i))); - } - - #define VECTOR4i_SHUFFLE_4(xs, xn, ys, yn, zs, zn, ws, wn) \ - GSVector4i xs##ys##zs##ws() const {return GSVector4i(_mm_shuffle_epi32(m, _MM_SHUFFLE(wn, zn, yn, xn)));} \ - GSVector4i xs##ys##zs##ws##l() const {return GSVector4i(_mm_shufflelo_epi16(m, _MM_SHUFFLE(wn, zn, yn, xn)));} \ - GSVector4i xs##ys##zs##ws##h() const {return GSVector4i(_mm_shufflehi_epi16(m, _MM_SHUFFLE(wn, zn, yn, xn)));} \ - GSVector4i xs##ys##zs##ws##lh() const {return GSVector4i(_mm_shufflehi_epi16(_mm_shufflelo_epi16(m, _MM_SHUFFLE(wn, zn, yn, xn)), _MM_SHUFFLE(wn, zn, yn, xn)));} \ - - #define VECTOR4i_SHUFFLE_3(xs, xn, ys, yn, zs, zn) \ - VECTOR4i_SHUFFLE_4(xs, xn, ys, yn, zs, zn, x, 0) \ - VECTOR4i_SHUFFLE_4(xs, xn, ys, yn, zs, zn, y, 1) \ - VECTOR4i_SHUFFLE_4(xs, xn, ys, yn, zs, zn, z, 2) \ - VECTOR4i_SHUFFLE_4(xs, xn, ys, yn, zs, zn, w, 3) \ - - #define VECTOR4i_SHUFFLE_2(xs, xn, ys, yn) \ - VECTOR4i_SHUFFLE_3(xs, xn, ys, yn, x, 0) \ - VECTOR4i_SHUFFLE_3(xs, xn, ys, yn, y, 1) \ - VECTOR4i_SHUFFLE_3(xs, xn, ys, yn, z, 2) \ - VECTOR4i_SHUFFLE_3(xs, xn, ys, yn, w, 3) \ - - #define VECTOR4i_SHUFFLE_1(xs, xn) \ - GSVector4i xs##4##() const {return GSVector4i(_mm_shuffle_epi32(m, _MM_SHUFFLE(xn, xn, xn, xn)));} \ - GSVector4i xs##4##l() const {return GSVector4i(_mm_shufflelo_epi16(m, _MM_SHUFFLE(xn, xn, xn, xn)));} \ - GSVector4i xs##4##h() const {return GSVector4i(_mm_shufflehi_epi16(m, _MM_SHUFFLE(xn, xn, xn, xn)));} \ - VECTOR4i_SHUFFLE_2(xs, xn, x, 0) \ - VECTOR4i_SHUFFLE_2(xs, xn, y, 1) \ - VECTOR4i_SHUFFLE_2(xs, xn, z, 2) \ - VECTOR4i_SHUFFLE_2(xs, xn, w, 3) \ - - VECTOR4i_SHUFFLE_1(x, 0) - VECTOR4i_SHUFFLE_1(y, 1) - VECTOR4i_SHUFFLE_1(z, 2) - VECTOR4i_SHUFFLE_1(w, 3) - - static GSVector4i zero() {return GSVector4i(_mm_setzero_si128());} - - static GSVector4i xffffffff() {return zero() == zero();} - - static GSVector4i x00000001() {return xffffffff().srl32(31);} - static GSVector4i x00000003() {return xffffffff().srl32(30);} - static GSVector4i x00000007() {return xffffffff().srl32(29);} - static GSVector4i x0000000f() {return xffffffff().srl32(28);} - static GSVector4i x0000001f() {return xffffffff().srl32(27);} - static GSVector4i x0000003f() {return xffffffff().srl32(26);} - static GSVector4i x0000007f() {return xffffffff().srl32(25);} - static GSVector4i x000000ff() {return xffffffff().srl32(24);} - static GSVector4i x000001ff() {return xffffffff().srl32(23);} - static GSVector4i x000003ff() {return xffffffff().srl32(22);} - static GSVector4i x000007ff() {return xffffffff().srl32(21);} - static GSVector4i x00000fff() {return xffffffff().srl32(20);} - static GSVector4i x00001fff() {return xffffffff().srl32(19);} - static GSVector4i x00003fff() {return xffffffff().srl32(18);} - static GSVector4i x00007fff() {return xffffffff().srl32(17);} - static GSVector4i x0000ffff() {return xffffffff().srl32(16);} - static GSVector4i x0001ffff() {return xffffffff().srl32(15);} - static GSVector4i x0003ffff() {return xffffffff().srl32(14);} - static GSVector4i x0007ffff() {return xffffffff().srl32(13);} - static GSVector4i x000fffff() {return xffffffff().srl32(12);} - static GSVector4i x001fffff() {return xffffffff().srl32(11);} - static GSVector4i x003fffff() {return xffffffff().srl32(10);} - static GSVector4i x007fffff() {return xffffffff().srl32( 9);} - static GSVector4i x00ffffff() {return xffffffff().srl32( 8);} - static GSVector4i x01ffffff() {return xffffffff().srl32( 7);} - static GSVector4i x03ffffff() {return xffffffff().srl32( 6);} - static GSVector4i x07ffffff() {return xffffffff().srl32( 5);} - static GSVector4i x0fffffff() {return xffffffff().srl32( 4);} - static GSVector4i x1fffffff() {return xffffffff().srl32( 3);} - static GSVector4i x3fffffff() {return xffffffff().srl32( 2);} - static GSVector4i x7fffffff() {return xffffffff().srl32( 1);} - - static GSVector4i x80000000() {return xffffffff().sll32(31);} - static GSVector4i xc0000000() {return xffffffff().sll32(30);} - static GSVector4i xe0000000() {return xffffffff().sll32(29);} - static GSVector4i xf0000000() {return xffffffff().sll32(28);} - static GSVector4i xf8000000() {return xffffffff().sll32(27);} - static GSVector4i xfc000000() {return xffffffff().sll32(26);} - static GSVector4i xfe000000() {return xffffffff().sll32(25);} - static GSVector4i xff000000() {return xffffffff().sll32(24);} - static GSVector4i xff800000() {return xffffffff().sll32(23);} - static GSVector4i xffc00000() {return xffffffff().sll32(22);} - static GSVector4i xffe00000() {return xffffffff().sll32(21);} - static GSVector4i xfff00000() {return xffffffff().sll32(20);} - static GSVector4i xfff80000() {return xffffffff().sll32(19);} - static GSVector4i xfffc0000() {return xffffffff().sll32(18);} - static GSVector4i xfffe0000() {return xffffffff().sll32(17);} - static GSVector4i xffff0000() {return xffffffff().sll32(16);} - static GSVector4i xffff8000() {return xffffffff().sll32(15);} - static GSVector4i xffffc000() {return xffffffff().sll32(14);} - static GSVector4i xffffe000() {return xffffffff().sll32(13);} - static GSVector4i xfffff000() {return xffffffff().sll32(12);} - static GSVector4i xfffff800() {return xffffffff().sll32(11);} - static GSVector4i xfffffc00() {return xffffffff().sll32(10);} - static GSVector4i xfffffe00() {return xffffffff().sll32( 9);} - static GSVector4i xffffff00() {return xffffffff().sll32( 8);} - static GSVector4i xffffff80() {return xffffffff().sll32( 7);} - static GSVector4i xffffffc0() {return xffffffff().sll32( 6);} - static GSVector4i xffffffe0() {return xffffffff().sll32( 5);} - static GSVector4i xfffffff0() {return xffffffff().sll32( 4);} - static GSVector4i xfffffff8() {return xffffffff().sll32( 3);} - static GSVector4i xfffffffc() {return xffffffff().sll32( 2);} - static GSVector4i xfffffffe() {return xffffffff().sll32( 1);} - - static GSVector4i x0001() {return xffffffff().srl16(15);} - static GSVector4i x0003() {return xffffffff().srl16(14);} - static GSVector4i x0007() {return xffffffff().srl16(13);} - static GSVector4i x000f() {return xffffffff().srl16(12);} - static GSVector4i x001f() {return xffffffff().srl16(11);} - static GSVector4i x003f() {return xffffffff().srl16(10);} - static GSVector4i x007f() {return xffffffff().srl16( 9);} - static GSVector4i x00ff() {return xffffffff().srl16( 8);} - static GSVector4i x01ff() {return xffffffff().srl16( 7);} - static GSVector4i x03ff() {return xffffffff().srl16( 6);} - static GSVector4i x07ff() {return xffffffff().srl16( 5);} - static GSVector4i x0fff() {return xffffffff().srl16( 4);} - static GSVector4i x1fff() {return xffffffff().srl16( 3);} - static GSVector4i x3fff() {return xffffffff().srl16( 2);} - static GSVector4i x7fff() {return xffffffff().srl16( 1);} - - static GSVector4i x8000() {return xffffffff().sll16(15);} - static GSVector4i xc000() {return xffffffff().sll16(14);} - static GSVector4i xe000() {return xffffffff().sll16(13);} - static GSVector4i xf000() {return xffffffff().sll16(12);} - static GSVector4i xf800() {return xffffffff().sll16(11);} - static GSVector4i xfc00() {return xffffffff().sll16(10);} - static GSVector4i xfe00() {return xffffffff().sll16( 9);} - static GSVector4i xff00() {return xffffffff().sll16( 8);} - static GSVector4i xff80() {return xffffffff().sll16( 7);} - static GSVector4i xffc0() {return xffffffff().sll16( 6);} - static GSVector4i xffe0() {return xffffffff().sll16( 5);} - static GSVector4i xfff0() {return xffffffff().sll16( 4);} - static GSVector4i xfff8() {return xffffffff().sll16( 3);} - static GSVector4i xfffc() {return xffffffff().sll16( 2);} - static GSVector4i xfffe() {return xffffffff().sll16( 1);} - - static GSVector4i xffffffff(const GSVector4i& v) {return v == v;} - - static GSVector4i x00000001(const GSVector4i& v) {return xffffffff(v).srl32(31);} - static GSVector4i x00000003(const GSVector4i& v) {return xffffffff(v).srl32(30);} - static GSVector4i x00000007(const GSVector4i& v) {return xffffffff(v).srl32(29);} - static GSVector4i x0000000f(const GSVector4i& v) {return xffffffff(v).srl32(28);} - static GSVector4i x0000001f(const GSVector4i& v) {return xffffffff(v).srl32(27);} - static GSVector4i x0000003f(const GSVector4i& v) {return xffffffff(v).srl32(26);} - static GSVector4i x0000007f(const GSVector4i& v) {return xffffffff(v).srl32(25);} - static GSVector4i x000000ff(const GSVector4i& v) {return xffffffff(v).srl32(24);} - static GSVector4i x000001ff(const GSVector4i& v) {return xffffffff(v).srl32(23);} - static GSVector4i x000003ff(const GSVector4i& v) {return xffffffff(v).srl32(22);} - static GSVector4i x000007ff(const GSVector4i& v) {return xffffffff(v).srl32(21);} - static GSVector4i x00000fff(const GSVector4i& v) {return xffffffff(v).srl32(20);} - static GSVector4i x00001fff(const GSVector4i& v) {return xffffffff(v).srl32(19);} - static GSVector4i x00003fff(const GSVector4i& v) {return xffffffff(v).srl32(18);} - static GSVector4i x00007fff(const GSVector4i& v) {return xffffffff(v).srl32(17);} - static GSVector4i x0000ffff(const GSVector4i& v) {return xffffffff(v).srl32(16);} - static GSVector4i x0001ffff(const GSVector4i& v) {return xffffffff(v).srl32(15);} - static GSVector4i x0003ffff(const GSVector4i& v) {return xffffffff(v).srl32(14);} - static GSVector4i x0007ffff(const GSVector4i& v) {return xffffffff(v).srl32(13);} - static GSVector4i x000fffff(const GSVector4i& v) {return xffffffff(v).srl32(12);} - static GSVector4i x001fffff(const GSVector4i& v) {return xffffffff(v).srl32(11);} - static GSVector4i x003fffff(const GSVector4i& v) {return xffffffff(v).srl32(10);} - static GSVector4i x007fffff(const GSVector4i& v) {return xffffffff(v).srl32( 9);} - static GSVector4i x00ffffff(const GSVector4i& v) {return xffffffff(v).srl32( 8);} - static GSVector4i x01ffffff(const GSVector4i& v) {return xffffffff(v).srl32( 7);} - static GSVector4i x03ffffff(const GSVector4i& v) {return xffffffff(v).srl32( 6);} - static GSVector4i x07ffffff(const GSVector4i& v) {return xffffffff(v).srl32( 5);} - static GSVector4i x0fffffff(const GSVector4i& v) {return xffffffff(v).srl32( 4);} - static GSVector4i x1fffffff(const GSVector4i& v) {return xffffffff(v).srl32( 3);} - static GSVector4i x3fffffff(const GSVector4i& v) {return xffffffff(v).srl32( 2);} - static GSVector4i x7fffffff(const GSVector4i& v) {return xffffffff(v).srl32( 1);} - - static GSVector4i x80000000(const GSVector4i& v) {return xffffffff(v).sll32(31);} - static GSVector4i xc0000000(const GSVector4i& v) {return xffffffff(v).sll32(30);} - static GSVector4i xe0000000(const GSVector4i& v) {return xffffffff(v).sll32(29);} - static GSVector4i xf0000000(const GSVector4i& v) {return xffffffff(v).sll32(28);} - static GSVector4i xf8000000(const GSVector4i& v) {return xffffffff(v).sll32(27);} - static GSVector4i xfc000000(const GSVector4i& v) {return xffffffff(v).sll32(26);} - static GSVector4i xfe000000(const GSVector4i& v) {return xffffffff(v).sll32(25);} - static GSVector4i xff000000(const GSVector4i& v) {return xffffffff(v).sll32(24);} - static GSVector4i xff800000(const GSVector4i& v) {return xffffffff(v).sll32(23);} - static GSVector4i xffc00000(const GSVector4i& v) {return xffffffff(v).sll32(22);} - static GSVector4i xffe00000(const GSVector4i& v) {return xffffffff(v).sll32(21);} - static GSVector4i xfff00000(const GSVector4i& v) {return xffffffff(v).sll32(20);} - static GSVector4i xfff80000(const GSVector4i& v) {return xffffffff(v).sll32(19);} - static GSVector4i xfffc0000(const GSVector4i& v) {return xffffffff(v).sll32(18);} - static GSVector4i xfffe0000(const GSVector4i& v) {return xffffffff(v).sll32(17);} - static GSVector4i xffff0000(const GSVector4i& v) {return xffffffff(v).sll32(16);} - static GSVector4i xffff8000(const GSVector4i& v) {return xffffffff(v).sll32(15);} - static GSVector4i xffffc000(const GSVector4i& v) {return xffffffff(v).sll32(14);} - static GSVector4i xffffe000(const GSVector4i& v) {return xffffffff(v).sll32(13);} - static GSVector4i xfffff000(const GSVector4i& v) {return xffffffff(v).sll32(12);} - static GSVector4i xfffff800(const GSVector4i& v) {return xffffffff(v).sll32(11);} - static GSVector4i xfffffc00(const GSVector4i& v) {return xffffffff(v).sll32(10);} - static GSVector4i xfffffe00(const GSVector4i& v) {return xffffffff(v).sll32( 9);} - static GSVector4i xffffff00(const GSVector4i& v) {return xffffffff(v).sll32( 8);} - static GSVector4i xffffff80(const GSVector4i& v) {return xffffffff(v).sll32( 7);} - static GSVector4i xffffffc0(const GSVector4i& v) {return xffffffff(v).sll32( 6);} - static GSVector4i xffffffe0(const GSVector4i& v) {return xffffffff(v).sll32( 5);} - static GSVector4i xfffffff0(const GSVector4i& v) {return xffffffff(v).sll32( 4);} - static GSVector4i xfffffff8(const GSVector4i& v) {return xffffffff(v).sll32( 3);} - static GSVector4i xfffffffc(const GSVector4i& v) {return xffffffff(v).sll32( 2);} - static GSVector4i xfffffffe(const GSVector4i& v) {return xffffffff(v).sll32( 1);} - - static GSVector4i x0001(const GSVector4i& v) {return xffffffff(v).srl16(15);} - static GSVector4i x0003(const GSVector4i& v) {return xffffffff(v).srl16(14);} - static GSVector4i x0007(const GSVector4i& v) {return xffffffff(v).srl16(13);} - static GSVector4i x000f(const GSVector4i& v) {return xffffffff(v).srl16(12);} - static GSVector4i x001f(const GSVector4i& v) {return xffffffff(v).srl16(11);} - static GSVector4i x003f(const GSVector4i& v) {return xffffffff(v).srl16(10);} - static GSVector4i x007f(const GSVector4i& v) {return xffffffff(v).srl16( 9);} - static GSVector4i x00ff(const GSVector4i& v) {return xffffffff(v).srl16( 8);} - static GSVector4i x01ff(const GSVector4i& v) {return xffffffff(v).srl16( 7);} - static GSVector4i x03ff(const GSVector4i& v) {return xffffffff(v).srl16( 6);} - static GSVector4i x07ff(const GSVector4i& v) {return xffffffff(v).srl16( 5);} - static GSVector4i x0fff(const GSVector4i& v) {return xffffffff(v).srl16( 4);} - static GSVector4i x1fff(const GSVector4i& v) {return xffffffff(v).srl16( 3);} - static GSVector4i x3fff(const GSVector4i& v) {return xffffffff(v).srl16( 2);} - static GSVector4i x7fff(const GSVector4i& v) {return xffffffff(v).srl16( 1);} - - static GSVector4i x8000(const GSVector4i& v) {return xffffffff(v).sll16(15);} - static GSVector4i xc000(const GSVector4i& v) {return xffffffff(v).sll16(14);} - static GSVector4i xe000(const GSVector4i& v) {return xffffffff(v).sll16(13);} - static GSVector4i xf000(const GSVector4i& v) {return xffffffff(v).sll16(12);} - static GSVector4i xf800(const GSVector4i& v) {return xffffffff(v).sll16(11);} - static GSVector4i xfc00(const GSVector4i& v) {return xffffffff(v).sll16(10);} - static GSVector4i xfe00(const GSVector4i& v) {return xffffffff(v).sll16( 9);} - static GSVector4i xff00(const GSVector4i& v) {return xffffffff(v).sll16( 8);} - static GSVector4i xff80(const GSVector4i& v) {return xffffffff(v).sll16( 7);} - static GSVector4i xffc0(const GSVector4i& v) {return xffffffff(v).sll16( 6);} - static GSVector4i xffe0(const GSVector4i& v) {return xffffffff(v).sll16( 5);} - static GSVector4i xfff0(const GSVector4i& v) {return xffffffff(v).sll16( 4);} - static GSVector4i xfff8(const GSVector4i& v) {return xffffffff(v).sll16( 3);} - static GSVector4i xfffc(const GSVector4i& v) {return xffffffff(v).sll16( 2);} - static GSVector4i xfffe(const GSVector4i& v) {return xffffffff(v).sll16( 1);} -}; - -__declspec(align(16)) class GSVector4 -{ -public: - union - { - struct {float x, y, z, w;}; - struct {float r, g, b, a;}; - float v[4]; - float f32[4]; - unsigned __int64 u64[2]; - __int8 i8[16]; - __int16 i16[8]; - __int32 i32[4]; - __int64 i64[2]; - unsigned __int8 u8[16]; - unsigned __int16 u16[8]; - unsigned __int32 u32[4]; - __m128 m; - }; - - static const GSVector4 m_ps0123; - static const GSVector4 m_ps4567; - - GSVector4() - { - } - - GSVector4(float x, float y, float z, float w) - { - m = _mm_set_ps(w, z, y, x); - } - - GSVector4(float x, float y) - { - m = _mm_unpacklo_ps(_mm_load_ss(&x), _mm_load_ss(&y)); - } - - GSVector4(int x, int y, int z, int w) - { - m = _mm_cvtepi32_ps(_mm_set_epi32(w, z, y, x)); - } - - GSVector4(int x, int y) - { - m = _mm_cvtepi32_ps(_mm_unpacklo_epi32(_mm_cvtsi32_si128(x), _mm_cvtsi32_si128(y))); - } - - GSVector4(const GSVector4& v) - { - m = v.m; - } - - explicit GSVector4(const GSVector2& v) - { - m = _mm_castsi128_ps(_mm_loadl_epi64((__m128i*)&v)); - } - - explicit GSVector4(float f) - { - m = _mm_set1_ps(f); - } - - explicit GSVector4(__m128 m) - { - this->m = m; - } - - explicit GSVector4(CRect r) - { - m = _mm_set_ps((float)r.bottom, (float)r.right, (float)r.top, (float)r.left); - } - - explicit GSVector4(DWORD dw) - { - *this = GSVector4(GSVector4i::load((int)dw).u8to32()); - } - - explicit GSVector4(const GSVector4i& v) - { - *this = v; - } - - void operator = (const GSVector4& v) - { - m = v.m; - } - - void operator = (const GSVector4i& v); - - void operator = (float f) - { - m = _mm_set1_ps(f); - } - - void operator = (__m128 m) - { - this->m = m; - } - - void operator = (DWORD dw) - { - *this = GSVector4(GSVector4i::load((int)dw).u8to32()); - } - - void operator = (CRect r) - { - *this = GSVector4(GSVector4i(r.left, r.top, r.right, r.bottom)); - } - - operator __m128() const - { - return m; - } - - UINT32 rgba32() const - { - return GSVector4i(*this).rgba32(); - } - - static GSVector4 cast(const GSVector4i& v); - - GSVector4 abs() const - { - return GSVector4(_mm_abs_ps(m)); - } - - GSVector4 neg() const - { - return GSVector4(_mm_neg_ps(m)); - } - - GSVector4 rcp() const - { - return GSVector4(_mm_rcp_ps(m)); - } - - GSVector4 rcpnr() const - { - return GSVector4(_mm_rcpnr_ps(m)); - } - - GSVector4 floor() const - { - return GSVector4(_mm_floor_ps(m)); - } - - GSVector4 ceil() const - { - return GSVector4(_mm_ceil_ps(m)); - } - - GSVector4 mod2x(const GSVector4& f, const int scale = 256) const - { - return *this * (f * (2.0f / scale)); - } - - GSVector4 mod2x(float f, const int scale = 256) const - { - return mod2x(GSVector4(f), scale); - } - - GSVector4 madd(const GSVector4& a, const GSVector4& b) const - { - return *this * a + b; // TODO: _mm_fmadd_ps - } - - GSVector4 msub(const GSVector4& a, const GSVector4& b) const - { - return *this * a + b; // TODO: _mm_fmsub_ps - } - - GSVector4 nmadd(const GSVector4& a, const GSVector4& b) const - { - return b - *this * a; // TODO: _mm_fnmadd_ps - } - - GSVector4 nmsub(const GSVector4& a, const GSVector4& b) const - { - return -b - *this * a; // TODO: _mm_fmnsub_ps - } - - GSVector4 lerp(const GSVector4& v, const GSVector4& f) const - { - return *this + (v - *this) * f; - } - - GSVector4 lerp(const GSVector4& v, float f) const - { - return lerp(v, GSVector4(f)); - } - - GSVector4 hadd() const - { - #if _M_SSE >= 0x300 - return GSVector4(_mm_hadd_ps(m, m)); - #else - return xzxz() + ywyw(); - #endif - } - - GSVector4 hadd(const GSVector4& v) const - { - #if _M_SSE >= 0x300 - return GSVector4(_mm_hadd_ps(m, v.m)); - #else - return xzxz(v) + ywyw(v); - #endif - } - - #if _M_SSE >= 0x401 - template GSVector4 dp(const GSVector4& v) const - { - return GSVector4(_mm_dp_ps(m, v.m, i)); - } - #endif - - GSVector4 sat(const GSVector4& a, const GSVector4& b) const - { - return GSVector4(_mm_min_ps(_mm_max_ps(m, a), b)); - } - - GSVector4 sat(const GSVector4& a) const - { - return GSVector4(_mm_min_ps(_mm_max_ps(m, a.xyxy()), a.zwzw())); - } - - GSVector4 sat(const float scale = 255) const - { - return sat(zero(), GSVector4(scale)); - } - - GSVector4 clamp(const float scale = 255) const - { - return minv(GSVector4(scale)); - } - - GSVector4 minv(const GSVector4& a) const - { - return GSVector4(_mm_min_ps(m, a)); - } - - GSVector4 maxv(const GSVector4& a) const - { - return GSVector4(_mm_max_ps(m, a)); - } - - GSVector4 blend8(const GSVector4& a, const GSVector4& mask) const - { - return GSVector4(_mm_blendv_ps(m, a, mask)); - } - - GSVector4 upl(const GSVector4& a) const - { - return GSVector4(_mm_unpacklo_ps(m, a)); - } - - GSVector4 uph(const GSVector4& a) const - { - return GSVector4(_mm_unpackhi_ps(m, a)); - } - - GSVector4 l2h(const GSVector4& a) const - { - return GSVector4(_mm_movelh_ps(m, a)); - } - - GSVector4 h2l(const GSVector4& a) const - { - return GSVector4(_mm_movehl_ps(m, a)); - } - - GSVector4 andnot(const GSVector4& v) const - { - return GSVector4(_mm_andnot_ps(v.m, m)); - } - - int mask() const - { - return _mm_movemask_ps(m); - } - - bool alltrue() const - { - return _mm_movemask_ps(m) == 0xf; - } - - bool allfalse() const - { - return _mm_movemask_ps(m) == 0; - } - - // TODO: insert - - template int extract() const - { - #if _M_SSE >= 0x401 - return _mm_extract_ps(m, i); - #else - return i32[i]; - #endif - } - - static GSVector4 zero() - { - return GSVector4(_mm_setzero_ps()); - } - - static GSVector4 xffffffff() - { - return zero() == zero(); - } - - static GSVector4 ps0123() - { - return GSVector4(m_ps0123); - } - - static GSVector4 ps4567() - { - return GSVector4(m_ps4567); - } - - static GSVector4 loadl(const void* p) - { - return GSVector4(_mm_castpd_ps(_mm_load_sd((double*)p))); - } - - static GSVector4 load(float f) - { - return GSVector4(_mm_load_ss(&f)); - } - - template static GSVector4 load(const void* p) - { - return GSVector4i(aligned ? _mm_load_ps((__m128*)p) : _mm_loadu_ps((__m128*)p)); - } - - static void storel(void* p, const GSVector4& v) - { - _mm_store_sd((double*)p, _mm_castps_pd(v.m)); - } - - template static void store(void* p, const GSVector4& v) - { - if(aligned) _mm_store_ps((__m128*)p, v.m); - else _mm_storeu_ps((__m128*)p, v.m); - } - - __forceinline static void expand(const GSVector4i& v, GSVector4& a, GSVector4& b, GSVector4& c, GSVector4& d) - { - GSVector4i mask = GSVector4i::x000000ff(); - - a = v & mask; - b = (v >> 8) & mask; - c = (v >> 16) & mask; - d = (v >> 24); - } - - __forceinline static void transpose(GSVector4& a, GSVector4& b, GSVector4& c, GSVector4& d) - { - GSVector4 v0 = a.xyxy(b); - GSVector4 v1 = c.xyxy(d); - - GSVector4 e = v0.xzxz(v1); - GSVector4 f = v0.ywyw(v1); - - GSVector4 v2 = a.zwzw(b); - GSVector4 v3 = c.zwzw(d); - - GSVector4 g = v2.xzxz(v3); - GSVector4 h = v2.ywyw(v3); - - a = e; - b = f; - c = g; - d = h; -/* - GSVector4 v0 = a.xyxy(b); - GSVector4 v1 = c.xyxy(d); - GSVector4 v2 = a.zwzw(b); - GSVector4 v3 = c.zwzw(d); - - a = v0.xzxz(v1); - b = v0.ywyw(v1); - c = v2.xzxz(v3); - d = v2.ywyw(v3); -*/ -/* - GSVector4 v0 = a.upl(b); - GSVector4 v1 = a.uph(b); - GSVector4 v2 = c.upl(d); - GSVector4 v3 = c.uph(d); - - a = v0.l2h(v2); - b = v2.h2l(v0); - c = v1.l2h(v3); - d = v3.h2l(v1); -*/ } - - GSVector4 operator - () const - { - return neg(); - } - - void operator += (const GSVector4& v) - { - m = _mm_add_ps(m, v); - } - - void operator -= (const GSVector4& v) - { - m = _mm_sub_ps(m, v); - } - - void operator *= (const GSVector4& v) - { - m = _mm_mul_ps(m, v); - } - - void operator /= (const GSVector4& v) - { - m = _mm_div_ps(m, v); - } - - void operator += (float f) - { - *this += GSVector4(f); - } - - void operator -= (float f) - { - *this -= GSVector4(f); - } - - void operator *= (float f) - { - *this *= GSVector4(f); - } - - void operator /= (float f) - { - *this /= GSVector4(f); - } - - void operator &= (const GSVector4& v) - { - m = _mm_and_ps(m, v); - } - - void operator |= (const GSVector4& v) - { - m = _mm_or_ps(m, v); - } - - void operator ^= (const GSVector4& v) - { - m = _mm_xor_ps(m, v); - } - - friend GSVector4 operator + (const GSVector4& v1, const GSVector4& v2) - { - return GSVector4(_mm_add_ps(v1, v2)); - } - - friend GSVector4 operator - (const GSVector4& v1, const GSVector4& v2) - { - return GSVector4(_mm_sub_ps(v1, v2)); - } - - friend GSVector4 operator * (const GSVector4& v1, const GSVector4& v2) - { - return GSVector4(_mm_mul_ps(v1, v2)); - } - - friend GSVector4 operator / (const GSVector4& v1, const GSVector4& v2) - { - return GSVector4(_mm_div_ps(v1, v2)); - } - - friend GSVector4 operator + (const GSVector4& v, float f) - { - return v + GSVector4(f); - } - - friend GSVector4 operator - (const GSVector4& v, float f) - { - return v - GSVector4(f); - } - - friend GSVector4 operator * (const GSVector4& v, float f) - { - return v * GSVector4(f); - } - - friend GSVector4 operator / (const GSVector4& v, float f) - { - return v / GSVector4(f); - } - - friend GSVector4 operator & (const GSVector4& v1, const GSVector4& v2) - { - return GSVector4(_mm_and_ps(v1, v2)); - } - - friend GSVector4 operator | (const GSVector4& v1, const GSVector4& v2) - { - return GSVector4(_mm_or_ps(v1, v2)); - } - - friend GSVector4 operator ^ (const GSVector4& v1, const GSVector4& v2) - { - return GSVector4(_mm_xor_ps(v1, v2)); - } - - friend GSVector4 operator == (const GSVector4& v1, const GSVector4& v2) - { - return GSVector4(_mm_cmpeq_ps(v1, v2)); - } - - friend GSVector4 operator != (const GSVector4& v1, const GSVector4& v2) - { - return GSVector4(_mm_cmpneq_ps(v1, v2)); - } - - friend GSVector4 operator > (const GSVector4& v1, const GSVector4& v2) - { - return GSVector4(_mm_cmpgt_ps(v1, v2)); - } - - friend GSVector4 operator < (const GSVector4& v1, const GSVector4& v2) - { - return GSVector4(_mm_cmplt_ps(v1, v2)); - } - - friend GSVector4 operator >= (const GSVector4& v1, const GSVector4& v2) - { - return GSVector4(_mm_cmpge_ps(v1, v2)); - } - - friend GSVector4 operator <= (const GSVector4& v1, const GSVector4& v2) - { - return GSVector4(_mm_cmple_ps(v1, v2)); - } - - template GSVector4 shuffle() const - { - return GSVector4(_mm_shuffle_ps(m, m, _MM_SHUFFLE(i, i, i, i))); - } - - #define VECTOR4_SHUFFLE_4(xs, xn, ys, yn, zs, zn, ws, wn) \ - GSVector4 xs##ys##zs##ws() const {return GSVector4(_mm_shuffle_ps(m, m, _MM_SHUFFLE(wn, zn, yn, xn)));} \ - GSVector4 xs##ys##zs##ws(const GSVector4& v) const {return GSVector4(_mm_shuffle_ps(m, v.m, _MM_SHUFFLE(wn, zn, yn, xn)));} \ - - #define VECTOR4_SHUFFLE_3(xs, xn, ys, yn, zs, zn) \ - VECTOR4_SHUFFLE_4(xs, xn, ys, yn, zs, zn, x, 0) \ - VECTOR4_SHUFFLE_4(xs, xn, ys, yn, zs, zn, y, 1) \ - VECTOR4_SHUFFLE_4(xs, xn, ys, yn, zs, zn, z, 2) \ - VECTOR4_SHUFFLE_4(xs, xn, ys, yn, zs, zn, w, 3) \ - - #define VECTOR4_SHUFFLE_2(xs, xn, ys, yn) \ - VECTOR4_SHUFFLE_3(xs, xn, ys, yn, x, 0) \ - VECTOR4_SHUFFLE_3(xs, xn, ys, yn, y, 1) \ - VECTOR4_SHUFFLE_3(xs, xn, ys, yn, z, 2) \ - VECTOR4_SHUFFLE_3(xs, xn, ys, yn, w, 3) \ - - #define VECTOR4_SHUFFLE_1(xs, xn) \ - GSVector4 xs##4##() const {return GSVector4(_mm_shuffle_ps(m, m, _MM_SHUFFLE(xn, xn, xn, xn)));} \ - GSVector4 xs##4##(const GSVector4& v) const {return GSVector4(_mm_shuffle_ps(m, v.m, _MM_SHUFFLE(xn, xn, xn, xn)));} \ - VECTOR4_SHUFFLE_2(xs, xn, x, 0) \ - VECTOR4_SHUFFLE_2(xs, xn, y, 1) \ - VECTOR4_SHUFFLE_2(xs, xn, z, 2) \ - VECTOR4_SHUFFLE_2(xs, xn, w, 3) \ - - VECTOR4_SHUFFLE_1(x, 0) - VECTOR4_SHUFFLE_1(y, 1) - VECTOR4_SHUFFLE_1(z, 2) - VECTOR4_SHUFFLE_1(w, 3) -}; - -#pragma pack(pop) +#pragma once + +// NOTE: x64 version of the _mm_set_* functions are terrible, first they store components into memory then reload in one piece (VS2008 SP1) + +#pragma pack(push, 1) + +template class GSVector2T +{ +public: + union + { + struct {T x, y;}; + struct {T r, g;}; + struct {T v[2];}; + }; + + GSVector2T() + { + } + + GSVector2T(T x, T y) + { + this->x = x; + this->y = y; + } + + GSVector2T(const GSVector2T& v) + { + *this = v; + } + + void operator = (const GSVector2T& v) + { + _mm_storel_epi64((__m128i*)this, _mm_loadl_epi64((__m128i*)&v)); + } +}; + +typedef __declspec(align(8)) GSVector2T GSVector2; +typedef __declspec(align(8)) GSVector2T GSVector2i; + +class GSVector4; + +__declspec(align(16)) class GSVector4i +{ +public: + union + { + struct {int x, y, z, w;}; + struct {int r, g, b, a;}; + int v[4]; + float f32[4]; + unsigned __int64 u64[2]; + __int8 i8[16]; + __int16 i16[8]; + __int32 i32[4]; + __int64 i64[2]; + unsigned __int8 u8[16]; + unsigned __int16 u16[8]; + unsigned __int32 u32[4]; + __m128i m; + }; + + GSVector4i() + { + } + + GSVector4i(int x, int y, int z, int w) + { + // 4 gprs + + // m = _mm_set_epi32(w, z, y, x); + + // 2 gprs + + GSVector4i xz = load(x).upl32(load(z)); + GSVector4i yw = load(y).upl32(load(w)); + + *this = xz.upl32(yw); + } + + GSVector4i(int x, int y) + { + *this = load(x).upl32(load(y)); + } + + GSVector4i(short s0, short s1, short s2, short s3, short s4, short s5, short s6, short s7) + { + m = _mm_set_epi16(s7, s6, s5, s4, s3, s2, s1, s0); + } + + GSVector4i(char b0, char b1, char b2, char b3, char b4, char b5, char b6, char b7, char b8, char b9, char b10, char b11, char b12, char b13, char b14, char b15) + { + m = _mm_set_epi8(b15, b14, b13, b12, b11, b10, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0); + } + + GSVector4i(const GSVector4i& v) + { + m = v.m; + } + + explicit GSVector4i(const GSVector2i& v) + { + m = _mm_loadl_epi64((__m128i*)&v); + } + + explicit GSVector4i(int i) + { + m = _mm_set1_epi32(i); + } + + explicit GSVector4i(__m128i m) + { + this->m = m; + } + + explicit GSVector4i(const CRect& r) + { + *this = GSVector4i(r.left, r.top, r.right, r.bottom); + } + + explicit GSVector4i(const GSVector4& v) + { + *this = v; + } + + void operator = (const GSVector4i& v) + { + m = v.m; + } + + void operator = (const GSVector4& v); + + void operator = (int i) + { + m = _mm_set1_epi32(i); + } + + void operator = (__m128i m) + { + this->m = m; + } + + void operator = (const CRect& r) + { + m = GSVector4i(r); + } + + operator __m128i() const + { + return m; + } + + operator CRect() const + { + return *(CRect*)&m; + } + + UINT32 rgba32() const + { + GSVector4i v = *this; + + v = v.ps32(v); + v = v.pu16(v); + + return (UINT32)store(v); + } + + static GSVector4i cast(const GSVector4& v); + + #if _M_SSE >= 0x401 + + GSVector4i sat_i8(const GSVector4i& a, const GSVector4i& b) const + { + return max_i8(a).min_i8(b); + } + + GSVector4i sat_i8(const GSVector4i& a) const + { + return max_i8(a.xyxy()).min_i8(a.zwzw()); + } + + #endif + + GSVector4i sat_i16(const GSVector4i& a, const GSVector4i& b) const + { + return max_i16(a).min_i16(b); + } + + GSVector4i sat_i16(const GSVector4i& a) const + { + return max_i16(a.xyxy()).min_i16(a.zwzw()); + } + + #if _M_SSE >= 0x401 + + GSVector4i sat_i32(const GSVector4i& a, const GSVector4i& b) const + { + return max_i32(a).min_i32(b); + } + + GSVector4i sat_i32(const GSVector4i& a) const + { + return max_i32(a.xyxy()).min_i32(a.zwzw()); + } + + #endif + + GSVector4i sat_u8(const GSVector4i& a, const GSVector4i& b) const + { + return max_u8(a).min_u8(b); + } + + GSVector4i sat_u8(const GSVector4i& a) const + { + return max_u8(a.xyxy()).min_u8(a.zwzw()); + } + + #if _M_SSE >= 0x401 + + GSVector4i sat_u16(const GSVector4i& a, const GSVector4i& b) const + { + return max_u16(a).min_u16(b); + } + + GSVector4i sat_u16(const GSVector4i& a) const + { + return max_u16(a.xyxy()).min_u16(a.zwzw()); + } + + #endif + + #if _M_SSE >= 0x401 + + GSVector4i sat_u32(const GSVector4i& a, const GSVector4i& b) const + { + return max_u32(a).min_u32(b); + } + + GSVector4i sat_u32(const GSVector4i& a) const + { + return max_u32(a.xyxy()).min_u32(a.zwzw()); + } + + #endif + + #if _M_SSE >= 0x401 + + GSVector4i min_i8(const GSVector4i& a) const + { + return GSVector4i(_mm_min_epi8(m, a)); + } + + GSVector4i max_i8(const GSVector4i& a) const + { + return GSVector4i(_mm_max_epi8(m, a)); + } + + #endif + + GSVector4i min_i16(const GSVector4i& a) const + { + return GSVector4i(_mm_min_epi16(m, a)); + } + + GSVector4i max_i16(const GSVector4i& a) const + { + return GSVector4i(_mm_max_epi16(m, a)); + } + + #if _M_SSE >= 0x401 + + GSVector4i min_i32(const GSVector4i& a) const + { + return GSVector4i(_mm_min_epi32(m, a)); + } + + GSVector4i max_i32(const GSVector4i& a) const + { + return GSVector4i(_mm_max_epi32(m, a)); + } + + #endif + + GSVector4i min_u8(const GSVector4i& a) const + { + return GSVector4i(_mm_min_epu8(m, a)); + } + + GSVector4i max_u8(const GSVector4i& a) const + { + return GSVector4i(_mm_max_epu8(m, a)); + } + + #if _M_SSE >= 0x401 + + GSVector4i min_u16(const GSVector4i& a) const + { + return GSVector4i(_mm_min_epu16(m, a)); + } + + GSVector4i max_u16(const GSVector4i& a) const + { + return GSVector4i(_mm_max_epu16(m, a)); + } + + GSVector4i min_u32(const GSVector4i& a) const + { + return GSVector4i(_mm_min_epu32(m, a)); + } + + GSVector4i max_u32(const GSVector4i& a) const + { + return GSVector4i(_mm_max_epu32(m, a)); + } + + #endif + + static int min_i16(int a, int b) + { + return store(load(a).min_i16(load(b))); + } + + GSVector4i clamp8() const + { + return pu16().upl8(); + } + + GSVector4i blend8(const GSVector4i& a, const GSVector4i& mask) const + { + return GSVector4i(_mm_blendv_epi8(m, a, mask)); + } + + #if _M_SSE >= 0x401 + + template GSVector4i blend16(const GSVector4i& a) const + { + return GSVector4i(_mm_blend_epi16(m, a, mask)); + } + + #endif + + GSVector4i blend(const GSVector4i& a, const GSVector4i& mask) const + { + return GSVector4i(_mm_or_si128(_mm_andnot_si128(mask, m), _mm_and_si128(mask, a))); + } + + GSVector4i mix16(const GSVector4i& a) const + { + #if _M_SSE >= 0x401 + + return blend16<0xaa>(a); + + #else + + return blend8(a, GSVector4i::xffff0000()); + + #endif + } + + #if _M_SSE >= 0x301 + + GSVector4i shuffle8(const GSVector4i& mask) const + { + return GSVector4i(_mm_shuffle_epi8(m, mask)); + } + + #endif + + GSVector4i ps16(const GSVector4i& a) const + { + return GSVector4i(_mm_packs_epi16(m, a)); + } + + GSVector4i ps16() const + { + return GSVector4i(_mm_packs_epi16(m, m)); + } + + GSVector4i pu16(const GSVector4i& a) const + { + return GSVector4i(_mm_packus_epi16(m, a)); + } + + GSVector4i pu16() const + { + return GSVector4i(_mm_packus_epi16(m, m)); + } + + GSVector4i ps32(const GSVector4i& a) const + { + return GSVector4i(_mm_packs_epi32(m, a)); + } + + GSVector4i ps32() const + { + return GSVector4i(_mm_packs_epi32(m, m)); + } + + #if _M_SSE >= 0x401 + + GSVector4i pu32(const GSVector4i& a) const + { + return GSVector4i(_mm_packus_epi32(m, a)); + } + + GSVector4i pu32() const + { + return GSVector4i(_mm_packus_epi32(m, m)); + } + + #endif + + GSVector4i upl8(const GSVector4i& a) const + { + return GSVector4i(_mm_unpacklo_epi8(m, a)); + } + + GSVector4i uph8(const GSVector4i& a) const + { + return GSVector4i(_mm_unpackhi_epi8(m, a)); + } + + GSVector4i upl16(const GSVector4i& a) const + { + return GSVector4i(_mm_unpacklo_epi16(m, a)); + } + + GSVector4i uph16(const GSVector4i& a) const + { + return GSVector4i(_mm_unpackhi_epi16(m, a)); + } + + GSVector4i upl32(const GSVector4i& a) const + { + return GSVector4i(_mm_unpacklo_epi32(m, a)); + } + + GSVector4i uph32(const GSVector4i& a) const + { + return GSVector4i(_mm_unpackhi_epi32(m, a)); + } + + GSVector4i upl64(const GSVector4i& a) const + { + return GSVector4i(_mm_unpacklo_epi64(m, a)); + } + + GSVector4i uph64(const GSVector4i& a) const + { + return GSVector4i(_mm_unpackhi_epi64(m, a)); + } + + GSVector4i upl8() const + { + #if 0 // _M_SSE >= 0x401 // TODO: compiler bug + + return GSVector4i(_mm_cvtepu8_epi16(m)); + + #else + + return GSVector4i(_mm_unpacklo_epi8(m, _mm_setzero_si128())); + + #endif + } + + GSVector4i uph8() const + { + return GSVector4i(_mm_unpackhi_epi8(m, _mm_setzero_si128())); + } + + GSVector4i upl16() const + { + #if 0 //_M_SSE >= 0x401 // TODO: compiler bug + + return GSVector4i(_mm_cvtepu16_epi32(m)); + + #else + + return GSVector4i(_mm_unpacklo_epi16(m, _mm_setzero_si128())); + + #endif + } + + GSVector4i uph16() const + { + return GSVector4i(_mm_unpackhi_epi16(m, _mm_setzero_si128())); + } + + GSVector4i upl32() const + { + #if 0 //_M_SSE >= 0x401 // TODO: compiler bug + + return GSVector4i(_mm_cvtepu32_epi64(m)); + + #else + + return GSVector4i(_mm_unpacklo_epi32(m, _mm_setzero_si128())); + + #endif + } + + GSVector4i uph32() const + { + return GSVector4i(_mm_unpackhi_epi32(m, _mm_setzero_si128())); + } + + GSVector4i upl64() const + { + return GSVector4i(_mm_unpacklo_epi64(m, _mm_setzero_si128())); + } + + GSVector4i uph64() const + { + return GSVector4i(_mm_unpackhi_epi64(m, _mm_setzero_si128())); + } + + #if _M_SSE >= 0x401 + + // WARNING!!! + // + // MSVC (2008, 2010 ctp) believes that there is a "mem, reg" form of the pmovz/sx* instructions, + // turning these intrinsics into a minefield, don't spill regs when using them... + + GSVector4i i8to16() const + { + return GSVector4i(_mm_cvtepi8_epi16(m)); + } + + GSVector4i u8to16() const + { + return GSVector4i(_mm_cvtepu8_epi16(m)); + } + + GSVector4i i8to32() const + { + return GSVector4i(_mm_cvtepi8_epi32(m)); + } + + GSVector4i u8to32() const + { + return GSVector4i(_mm_cvtepu8_epi32(m)); + } + + GSVector4i i8to64() const + { + return GSVector4i(_mm_cvtepi8_epi64(m)); + } + + GSVector4i u8to64() const + { + return GSVector4i(_mm_cvtepu16_epi64(m)); + } + + GSVector4i i16to32() const + { + return GSVector4i(_mm_cvtepi16_epi32(m)); + } + + GSVector4i u16to32() const + { + return GSVector4i(_mm_cvtepu16_epi32(m)); + } + + GSVector4i i16to64() const + { + return GSVector4i(_mm_cvtepi16_epi64(m)); + } + + GSVector4i u16to64() const + { + return GSVector4i(_mm_cvtepu16_epi64(m)); + } + + GSVector4i i32to64() const + { + return GSVector4i(_mm_cvtepi32_epi64(m)); + } + + GSVector4i u32to64() const + { + return GSVector4i(_mm_cvtepu32_epi64(m)); + } + + #else + + GSVector4i u8to16() const + { + return upl8(); + } + + GSVector4i u8to32() const + { + return upl8().upl16(); + } + + GSVector4i u8to64() const + { + return upl8().upl16().upl32(); + } + + GSVector4i u16to32() const + { + return upl16(); + } + + GSVector4i u16to64() const + { + return upl16().upl32(); + } + + GSVector4i u32to64() const + { + return upl32(); + } + + #endif + + template GSVector4i srl() const + { + #pragma warning(push) + #pragma warning(disable: 4556) + + return GSVector4i(_mm_srli_si128(m, i)); + + #pragma warning(pop) + } + + template GSVector4i srl(const GSVector4i& v) + { + #if _M_SSE >= 0x301 + + return GSVector4i(_mm_alignr_epi8(v.m, m, i)); + + #else + + if(i == 0) return *this; + else if(i < 16) return srl() | v.sll<16 - i>(); + else if(i == 16) return v; + else if(i < 32) return v.srl(); + else return zero(); + + #endif + } + + template GSVector4i sll() const + { + #pragma warning(push) + #pragma warning(disable: 4556) + + return GSVector4i(_mm_slli_si128(m, i)); + + #pragma warning(pop) + } + + GSVector4i sra16(int i) const + { + return GSVector4i(_mm_srai_epi16(m, i)); + } + + GSVector4i sra32(int i) const + { + return GSVector4i(_mm_srai_epi32(m, i)); + } + + GSVector4i sll16(int i) const + { + return GSVector4i(_mm_slli_epi16(m, i)); + } + + GSVector4i sll32(int i) const + { + return GSVector4i(_mm_slli_epi32(m, i)); + } + + GSVector4i sll64(int i) const + { + return GSVector4i(_mm_slli_epi64(m, i)); + } + + GSVector4i srl16(int i) const + { + return GSVector4i(_mm_srli_epi16(m, i)); + } + + GSVector4i srl32(int i) const + { + return GSVector4i(_mm_srli_epi32(m, i)); + } + + GSVector4i srl64(int i) const + { + return GSVector4i(_mm_srli_epi64(m, i)); + } + + GSVector4i add8(const GSVector4i& v) const + { + return GSVector4i(_mm_add_epi8(m, v.m)); + } + + GSVector4i add16(const GSVector4i& v) const + { + return GSVector4i(_mm_add_epi16(m, v.m)); + } + + GSVector4i add32(const GSVector4i& v) const + { + return GSVector4i(_mm_add_epi32(m, v.m)); + } + + GSVector4i adds8(const GSVector4i& v) const + { + return GSVector4i(_mm_adds_epi8(m, v.m)); + } + + GSVector4i adds16(const GSVector4i& v) const + { + return GSVector4i(_mm_adds_epi16(m, v.m)); + } + + GSVector4i addus8(const GSVector4i& v) const + { + return GSVector4i(_mm_adds_epu8(m, v.m)); + } + + GSVector4i addus16(const GSVector4i& v) const + { + return GSVector4i(_mm_adds_epu16(m, v.m)); + } + + GSVector4i sub8(const GSVector4i& v) const + { + return GSVector4i(_mm_sub_epi8(m, v.m)); + } + + GSVector4i sub16(const GSVector4i& v) const + { + return GSVector4i(_mm_sub_epi16(m, v.m)); + } + + GSVector4i sub32(const GSVector4i& v) const + { + return GSVector4i(_mm_sub_epi32(m, v.m)); + } + + GSVector4i subs8(const GSVector4i& v) const + { + return GSVector4i(_mm_subs_epi8(m, v.m)); + } + + GSVector4i subs16(const GSVector4i& v) const + { + return GSVector4i(_mm_subs_epi16(m, v.m)); + } + + GSVector4i subus8(const GSVector4i& v) const + { + return GSVector4i(_mm_subs_epu8(m, v.m)); + } + + GSVector4i subus16(const GSVector4i& v) const + { + return GSVector4i(_mm_subs_epu16(m, v.m)); + } + + GSVector4i avg8(const GSVector4i& v) const + { + return GSVector4i(_mm_avg_epu8(m, v.m)); + } + + GSVector4i avg16(const GSVector4i& v) const + { + return GSVector4i(_mm_avg_epu16(m, v.m)); + } + + GSVector4i mul16hs(const GSVector4i& v) const + { + return GSVector4i(_mm_mulhi_epi16(m, v.m)); + } + + GSVector4i mul16hu(const GSVector4i& v) const + { + return GSVector4i(_mm_mulhi_epu16(m, v.m)); + } + + GSVector4i mul16l(const GSVector4i& v) const + { + return GSVector4i(_mm_mullo_epi16(m, v.m)); + } + + #if _M_SSE >= 0x301 + + GSVector4i mul16hrs(const GSVector4i& v) const + { + return GSVector4i(_mm_mulhrs_epi16(m, v.m)); + } + + #endif + + template GSVector4i lerp16(const GSVector4i& a, const GSVector4i& f) const + { + // (a - this) * f << shift + this + + return add16(a.sub16(*this).modulate16(f)); + } + + template static GSVector4i lerp16(const GSVector4i& a, const GSVector4i& b, const GSVector4i& c) + { + // (a - b) * c << shift + + return a.sub16(b).modulate16(c); + } + + template static GSVector4i lerp16(const GSVector4i& a, const GSVector4i& b, const GSVector4i& c, const GSVector4i& d) + { + // (a - b) * c << shift + d + + return d.add16(a.sub16(b).modulate16(c)); + } + + template GSVector4i modulate16(const GSVector4i& f) const + { + // a * f << shift + + #if _M_SSE >= 0x301 + + if(shift == 0) + { + return mul16hrs(f); + } + + #endif + + return sll16(shift + 1).mul16hs(f); + } + + GSVector4i eq8(const GSVector4i& v) const + { + return GSVector4i(_mm_cmpeq_epi8(m, v.m)); + } + + GSVector4i eq16(const GSVector4i& v) const + { + return GSVector4i(_mm_cmpeq_epi16(m, v.m)); + } + + GSVector4i eq32(const GSVector4i& v) const + { + return GSVector4i(_mm_cmpeq_epi32(m, v.m)); + } + + GSVector4i neq8(const GSVector4i& v) const + { + return ~eq8(v); + } + + GSVector4i neq16(const GSVector4i& v) const + { + return ~eq16(v); + } + + GSVector4i neq32(const GSVector4i& v) const + { + return ~eq32(v); + } + + GSVector4i gt8(const GSVector4i& v) const + { + return GSVector4i(_mm_cmpgt_epi8(m, v.m)); + } + + GSVector4i gt16(const GSVector4i& v) const + { + return GSVector4i(_mm_cmpgt_epi16(m, v.m)); + } + + GSVector4i gt32(const GSVector4i& v) const + { + return GSVector4i(_mm_cmpgt_epi32(m, v.m)); + } + + GSVector4i lt8(const GSVector4i& v) const + { + return GSVector4i(_mm_cmplt_epi8(m, v.m)); + } + + GSVector4i lt16(const GSVector4i& v) const + { + return GSVector4i(_mm_cmplt_epi16(m, v.m)); + } + + GSVector4i lt32(const GSVector4i& v) const + { + return GSVector4i(_mm_cmplt_epi32(m, v.m)); + } + + GSVector4i andnot(const GSVector4i& v) const + { + return GSVector4i(_mm_andnot_si128(v.m, m)); + } + + int mask() const + { + return _mm_movemask_epi8(m); + } + + bool alltrue() const + { + return _mm_movemask_epi8(m) == 0xffff; + } + + bool anytrue() const + { + return _mm_movemask_epi8(m) != 0x0000; + } + + #if _M_SSE >= 0x401 + + template GSVector4i insert8(int a) const + { + return GSVector4i(_mm_insert_epi8(m, a, i)); + } + + #endif + + template int extract8() const + { + #if _M_SSE >= 0x401 + return _mm_extract_epi8(m, i); + #else + return (int)u8[i]; + #endif + } + + template GSVector4i insert16(int a) const + { + return GSVector4i(_mm_insert_epi16(m, a, i)); + } + + template int extract16() const + { + return _mm_extract_epi16(m, i); + } + + #if _M_SSE >= 0x401 + + template GSVector4i insert32(int a) const + { + return GSVector4i(_mm_insert_epi32(m, a, i)); + } + + #endif + + template int extract32() const + { + if(i == 0) return GSVector4i::store(*this); + #if _M_SSE >= 0x401 + return _mm_extract_epi32(m, i); + #else + return i32[i]; + #endif + } + + #ifdef _M_AMD64 + + #if _M_SSE >= 0x401 + + template GSVector4i insert64(__int64 a) const + { + return GSVector4i(_mm_insert_epi64(m, a, i)); + } + + #endif + + template __int64 extract64() const + { + if(i == 0) return GSVector4i::storeq(*this); + #if _M_SSE >= 0x401 + return _mm_extract_epi64(m, i); + #else + return i64[i]; + #endif + } + + #endif + + #if _M_SSE >= 0x401 + + template __forceinline GSVector4i gather8_4(const T* ptr) const + { + GSVector4i v; + + v = load((int)ptr[extract8() & 0xf]); + v = v.insert8<1>((int)ptr[extract8() >> 4]); + v = v.insert8<2>((int)ptr[extract8() & 0xf]); + v = v.insert8<3>((int)ptr[extract8() >> 4]); + v = v.insert8<4>((int)ptr[extract8() & 0xf]); + v = v.insert8<5>((int)ptr[extract8() >> 4]); + v = v.insert8<6>((int)ptr[extract8() & 0xf]); + v = v.insert8<7>((int)ptr[extract8() >> 4]); + v = v.insert8<8>((int)ptr[extract8() & 0xf]); + v = v.insert8<9>((int)ptr[extract8() >> 4]); + v = v.insert8<10>((int)ptr[extract8() & 0xf]); + v = v.insert8<11>((int)ptr[extract8() >> 4]); + v = v.insert8<12>((int)ptr[extract8() & 0xf]); + v = v.insert8<13>((int)ptr[extract8() >> 4]); + v = v.insert8<14>((int)ptr[extract8() & 0xf]); + v = v.insert8<15>((int)ptr[extract8() >> 4]); + + return v; + } + + template __forceinline GSVector4i gather8_8(const T* ptr) const + { + GSVector4i v; + + v = load((int)ptr[extract8<0>()]); + v = v.insert8<1>((int)ptr[extract8<1>()]); + v = v.insert8<2>((int)ptr[extract8<2>()]); + v = v.insert8<3>((int)ptr[extract8<3>()]); + v = v.insert8<4>((int)ptr[extract8<4>()]); + v = v.insert8<5>((int)ptr[extract8<5>()]); + v = v.insert8<6>((int)ptr[extract8<6>()]); + v = v.insert8<7>((int)ptr[extract8<7>()]); + v = v.insert8<8>((int)ptr[extract8<8>()]); + v = v.insert8<9>((int)ptr[extract8<9>()]); + v = v.insert8<10>((int)ptr[extract8<10>()]); + v = v.insert8<11>((int)ptr[extract8<11>()]); + v = v.insert8<12>((int)ptr[extract8<12>()]); + v = v.insert8<13>((int)ptr[extract8<13>()]); + v = v.insert8<14>((int)ptr[extract8<14>()]); + v = v.insert8<15>((int)ptr[extract8<15>()]); + + return v; + } + + template __forceinline GSVector4i gather8_16(const T* ptr, const GSVector4i& a) const + { + GSVector4i v = a; + + v = v.insert8((int)ptr[extract16<0>()]); + v = v.insert8((int)ptr[extract16<1>()]); + v = v.insert8((int)ptr[extract16<2>()]); + v = v.insert8((int)ptr[extract16<3>()]); + v = v.insert8((int)ptr[extract16<4>()]); + v = v.insert8((int)ptr[extract16<5>()]); + v = v.insert8((int)ptr[extract16<6>()]); + v = v.insert8((int)ptr[extract16<7>()]); + + return v; + } + + template __forceinline GSVector4i gather8_32(const T* ptr, const GSVector4i& a) const + { + GSVector4i v = a; + + v = v.insert8((int)ptr[extract32<0>()]); + v = v.insert8((int)ptr[extract32<1>()]); + v = v.insert8((int)ptr[extract32<2>()]); + v = v.insert8((int)ptr[extract32<3>()]); + + return v; + } + + #endif + + template __forceinline GSVector4i gather16_4(const T* ptr) const + { + GSVector4i v; + + v = load((int)ptr[extract8() & 0xf]); + v = v.insert16<1>((int)ptr[extract8() >> 4]); + v = v.insert16<2>((int)ptr[extract8() & 0xf]); + v = v.insert16<3>((int)ptr[extract8() >> 4]); + v = v.insert16<4>((int)ptr[extract8() & 0xf]); + v = v.insert16<5>((int)ptr[extract8() >> 4]); + v = v.insert16<6>((int)ptr[extract8() & 0xf]); + v = v.insert16<7>((int)ptr[extract8() >> 4]); + + return v; + } + + template __forceinline GSVector4i gather16_8(const T* ptr) const + { + GSVector4i v; + + v = load((int)ptr[extract8()]); + v = v.insert16<1>((int)ptr[extract8()]); + v = v.insert16<2>((int)ptr[extract8()]); + v = v.insert16<3>((int)ptr[extract8()]); + v = v.insert16<4>((int)ptr[extract8()]); + v = v.insert16<5>((int)ptr[extract8()]); + v = v.insert16<6>((int)ptr[extract8()]); + v = v.insert16<7>((int)ptr[extract8()]); + + return v; + } + + template__forceinline GSVector4i gather16_16(const T* ptr) const + { + GSVector4i v; + + v = load((int)ptr[extract16<0>()]); + v = v.insert16<1>((int)ptr[extract16<1>()]); + v = v.insert16<2>((int)ptr[extract16<2>()]); + v = v.insert16<3>((int)ptr[extract16<3>()]); + v = v.insert16<4>((int)ptr[extract16<4>()]); + v = v.insert16<5>((int)ptr[extract16<5>()]); + v = v.insert16<6>((int)ptr[extract16<6>()]); + v = v.insert16<7>((int)ptr[extract16<7>()]); + + return v; + } + + template__forceinline GSVector4i gather16_16(const T1* ptr1, const T2* ptr2) const + { + GSVector4i v; + + v = load((int)ptr2[ptr1[extract16<0>()]]); + v = v.insert16<1>((int)ptr2[ptr1[extract16<1>()]]); + v = v.insert16<2>((int)ptr2[ptr1[extract16<2>()]]); + v = v.insert16<3>((int)ptr2[ptr1[extract16<3>()]]); + v = v.insert16<4>((int)ptr2[ptr1[extract16<4>()]]); + v = v.insert16<5>((int)ptr2[ptr1[extract16<5>()]]); + v = v.insert16<6>((int)ptr2[ptr1[extract16<6>()]]); + v = v.insert16<7>((int)ptr2[ptr1[extract16<7>()]]); + + return v; + } + + template __forceinline GSVector4i gather16_32(const T* ptr, const GSVector4i& a) const + { + GSVector4i v = a; + + v = v.insert16((int)ptr[extract32<0>()]); + v = v.insert16((int)ptr[extract32<1>()]); + v = v.insert16((int)ptr[extract32<2>()]); + v = v.insert16((int)ptr[extract32<3>()]); + + return v; + } + + #if _M_SSE >= 0x401 + + template __forceinline GSVector4i gather32_4(const T* ptr) const + { + GSVector4i v; + + v = load((int)ptr[extract8() & 0xf]); + v = v.insert32<1>((int)ptr[extract8() >> 4]); + v = v.insert32<2>((int)ptr[extract8() & 0xf]); + v = v.insert32<3>((int)ptr[extract8() >> 4]); + return v; + } + + template __forceinline GSVector4i gather32_8(const T* ptr) const + { + GSVector4i v; + + v = load((int)ptr[extract8()]); + v = v.insert32<1>((int)ptr[extract8()]); + v = v.insert32<2>((int)ptr[extract8()]); + v = v.insert32<3>((int)ptr[extract8()]); + + return v; + } + + template __forceinline GSVector4i gather32_16(const T* ptr) const + { + GSVector4i v; + + v = load((int)ptr[extract16()]); + v = v.insert32<1>((int)ptr[extract16()]); + v = v.insert32<2>((int)ptr[extract16()]); + v = v.insert32<3>((int)ptr[extract16()]); + + return v; + } + + template __forceinline GSVector4i gather32_32(const T* ptr) const + { + GSVector4i v; + + v = load((int)ptr[extract32<0>()]); + v = v.insert32<1>((int)ptr[extract32<1>()]); + v = v.insert32<2>((int)ptr[extract32<2>()]); + v = v.insert32<3>((int)ptr[extract32<3>()]); + + return v; + } + + template __forceinline GSVector4i gather32_32(const T1* ptr1, const T2* ptr2) const + { + GSVector4i v; + + v = load((int)ptr2[ptr1[extract32<0>()]]); + v = v.insert32<1>((int)ptr2[ptr1[extract32<1>()]]); + v = v.insert32<2>((int)ptr2[ptr1[extract32<2>()]]); + v = v.insert32<3>((int)ptr2[ptr1[extract32<3>()]]); + + return v; + } + + #else + + template __forceinline GSVector4i gather32_4(const T* ptr) const + { + return GSVector4i( + (int)ptr[extract8() & 0xf], + (int)ptr[extract8() >> 4], + (int)ptr[extract8() & 0xf], + (int)ptr[extract8() >> 4]); + } + + template __forceinline GSVector4i gather32_8(const T* ptr) const + { + return GSVector4i( + (int)ptr[extract8()], + (int)ptr[extract8()], + (int)ptr[extract8()], + (int)ptr[extract8()]); + } + + template __forceinline GSVector4i gather32_16(const T* ptr) const + { + return GSVector4i( + (int)ptr[extract16()], + (int)ptr[extract16()], + (int)ptr[extract16()], + (int)ptr[extract16()]); + } + + template __forceinline GSVector4i gather32_32(const T* ptr) const + { + return GSVector4i( + (int)ptr[extract32<0>()], + (int)ptr[extract32<1>()], + (int)ptr[extract32<2>()], + (int)ptr[extract32<3>()]); + } + + template __forceinline GSVector4i gather32_32(const T1* ptr1, const T2* ptr2) const + { + return GSVector4i( + (int)ptr2[ptr1[extract32<0>()]], + (int)ptr2[ptr1[extract32<1>()]], + (int)ptr2[ptr1[extract32<2>()]], + (int)ptr2[ptr1[extract32<3>()]]); + } + + #endif + + #if defined(_M_AMD64) && _M_SSE >= 0x401 + + template __forceinline GSVector4i gather64_4(const T* ptr) const + { + GSVector4i v; + + v = loadq((__int64)ptr[extract8() & 0xf]); + v = v.insert64<1>((__int64)ptr[extract8() >> 4]); + + return v; + } + + template __forceinline GSVector4i gather64_8(const T* ptr) const + { + GSVector4i v; + + v = loadq((__int64)ptr[extract8()]); + v = v.insert64<1>((__int64)ptr[extract8()]); + + return v; + } + + template __forceinline GSVector4i gather64_16(const T* ptr) const + { + GSVector4i v; + + v = loadq((__int64)ptr[extract16()]); + v = v.insert64<1>((__int64)ptr[extract16()]); + + return v; + } + + template __forceinline GSVector4i gather64_32(const T* ptr) const + { + GSVector4i v; + + v = loadq((__int64)ptr[extract32()]); + v = v.insert64<1>((__int64)ptr[extract32()]); + + return v; + } + + template __forceinline GSVector4i gather64_64(const T* ptr) const + { + GSVector4i v; + + v = loadq((__int64)ptr[extract64<0>()]); + v = v.insert64<1>((__int64)ptr[extract64<1>()]); + + return v; + } + + #else + + template __forceinline GSVector4i gather64_4(const T* ptr) const + { + GSVector4i v; + + v = loadu(&ptr[extract8() & 0xf], &ptr[extract8() >> 4]); + + return v; + } + + template __forceinline GSVector4i gather64_8(const T* ptr) const + { + GSVector4i v; + + v = load(&ptr[extract8()], &ptr[extract8()]); + + return v; + } + + template __forceinline GSVector4i gather64_16(const T* ptr) const + { + GSVector4i v; + + v = load(&ptr[extract16()], &ptr[extract16()]); + + return v; + } + + template __forceinline GSVector4i gather64_32(const T* ptr) const + { + GSVector4i v; + + v = load(&ptr[extract32()], &ptr[extract32()]); + + return v; + } + + #endif + + #if _M_SSE >= 0x401 + + template __forceinline void gather8_4(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const + { + dst[0] = gather8_4<0>(ptr); + dst[1] = gather8_4<8>(ptr); + } + + __forceinline void gather8_8(const BYTE* RESTRICT ptr, GSVector4i* RESTRICT dst) const + { + dst[0] = gather8_8<>(ptr); + } + + #endif + + template __forceinline void gather16_4(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const + { + dst[0] = gather16_4<0>(ptr); + dst[1] = gather16_4<4>(ptr); + dst[2] = gather16_4<8>(ptr); + dst[3] = gather16_4<12>(ptr); + } + + template __forceinline void gather16_8(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const + { + dst[0] = gather16_8<0>(ptr); + dst[1] = gather16_8<8>(ptr); + } + + template __forceinline void gather16_16(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const + { + dst[0] = gather16_16<>(ptr); + } + + template __forceinline void gather32_4(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const + { + dst[0] = gather32_4<0>(ptr); + dst[1] = gather32_4<2>(ptr); + dst[2] = gather32_4<4>(ptr); + dst[3] = gather32_4<6>(ptr); + dst[4] = gather32_4<8>(ptr); + dst[5] = gather32_4<10>(ptr); + dst[6] = gather32_4<12>(ptr); + dst[7] = gather32_4<14>(ptr); + } + + template __forceinline void gather32_8(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const + { + dst[0] = gather32_8<0>(ptr); + dst[1] = gather32_8<4>(ptr); + dst[2] = gather32_8<8>(ptr); + dst[3] = gather32_8<12>(ptr); + } + + template __forceinline void gather32_16(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const + { + dst[0] = gather32_16<0>(ptr); + dst[1] = gather32_16<4>(ptr); + } + + template __forceinline void gather32_32(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const + { + dst[0] = gather32_32<>(ptr); + } + + template __forceinline void gather64_4(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const + { + dst[0] = gather64_4<0>(ptr); + dst[1] = gather64_4<1>(ptr); + dst[2] = gather64_4<2>(ptr); + dst[3] = gather64_4<3>(ptr); + dst[4] = gather64_4<4>(ptr); + dst[5] = gather64_4<5>(ptr); + dst[6] = gather64_4<6>(ptr); + dst[7] = gather64_4<7>(ptr); + dst[8] = gather64_4<8>(ptr); + dst[9] = gather64_4<9>(ptr); + dst[10] = gather64_4<10>(ptr); + dst[11] = gather64_4<11>(ptr); + dst[12] = gather64_4<12>(ptr); + dst[13] = gather64_4<13>(ptr); + dst[14] = gather64_4<14>(ptr); + dst[15] = gather64_4<15>(ptr); + } + + template __forceinline void gather64_8(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const + { + dst[0] = gather64_8<0>(ptr); + dst[1] = gather64_8<2>(ptr); + dst[2] = gather64_8<4>(ptr); + dst[3] = gather64_8<6>(ptr); + dst[4] = gather64_8<8>(ptr); + dst[5] = gather64_8<10>(ptr); + dst[6] = gather64_8<12>(ptr); + dst[7] = gather64_8<14>(ptr); + } + + template __forceinline void gather64_16(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const + { + dst[0] = gather64_16<0>(ptr); + dst[1] = gather64_16<2>(ptr); + dst[2] = gather64_16<4>(ptr); + dst[3] = gather64_16<8>(ptr); + } + + template __forceinline void gather64_32(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const + { + dst[0] = gather64_32<0>(ptr); + dst[1] = gather64_32<2>(ptr); + } + + #ifdef _M_AMD64 + + template __forceinline void gather64_64(const T* RESTRICT ptr, GSVector4i* RESTRICT dst) const + { + dst[0] = gather64_64<>(ptr); + } + + #endif + + #if _M_SSE >= 0x401 + + static GSVector4i loadnt(const void* p) + { + return GSVector4i(_mm_stream_load_si128((__m128i*)p)); + } + + #endif + + static GSVector4i loadl(const void* p) + { + return GSVector4i(_mm_loadl_epi64((__m128i*)p)); + } + + static GSVector4i loadh(const void* p) + { + return GSVector4i(_mm_castps_si128(_mm_loadh_pi(_mm_setzero_ps(), (__m64*)p))); + } + + static GSVector4i loadh(const void* p, const GSVector4i& v) + { + return GSVector4i(_mm_castps_si128(_mm_loadh_pi(_mm_castsi128_ps(v.m), (__m64*)p))); + } + + static GSVector4i load(const void* pl, const void* ph) + { + return loadh(ph, loadl(pl)); + } +/* + static GSVector4i load(const void* pl, const void* ph) + { + __m128i lo = _mm_loadl_epi64((__m128i*)pl); + __m128i hi = _mm_loadl_epi64((__m128i*)ph); + + return GSVector4i(_mm_unpacklo_epi64(lo, hi)); + } +*/ + template static GSVector4i load(const void* p) + { + return GSVector4i(aligned ? _mm_load_si128((__m128i*)p) : _mm_loadu_si128((__m128i*)p)); + } + + static GSVector4i load(int i) + { + return GSVector4i(_mm_cvtsi32_si128(i)); + } + + #ifdef _M_AMD64 + + static GSVector4i loadq(__int64 i) + { + return GSVector4i(_mm_cvtsi64_si128(i)); + } + + #endif + + static void storent(void* p, const GSVector4i& v) + { + _mm_stream_si128((__m128i*)p, v.m); + } + + static void storel(void* p, const GSVector4i& v) + { + _mm_storel_epi64((__m128i*)p, v.m); + } + + static void storeh(void* p, const GSVector4i& v) + { + _mm_storeh_pi((__m64*)p, _mm_castsi128_ps(v.m)); + } + + static void store(void* pl, void* ph, const GSVector4i& v) + { + GSVector4i::storel(pl, v); + GSVector4i::storeh(ph, v); + } + + template static void store(void* p, const GSVector4i& v) + { + if(aligned) _mm_store_si128((__m128i*)p, v.m); + else _mm_storeu_si128((__m128i*)p, v.m); + } + + static int store(const GSVector4i& v) + { + return _mm_cvtsi128_si32(v.m); + } + + #ifdef _M_AMD64 + + static __int64 storeq(const GSVector4i& v) + { + return _mm_cvtsi128_si64(v.m); + } + + #endif + + __forceinline static void transpose(GSVector4i& a, GSVector4i& b, GSVector4i& c, GSVector4i& d) + { + _MM_TRANSPOSE4_SI128(a.m, b.m, c.m, d.m); + } + + __forceinline static void sw4(GSVector4i& a, GSVector4i& b, GSVector4i& c, GSVector4i& d) + { + const __m128i epi32_0f0f0f0f = _mm_set1_epi32(0x0f0f0f0f); + + GSVector4i mask(epi32_0f0f0f0f); + + GSVector4i e = (b << 4).blend(a, mask); + GSVector4i f = b.blend(a >> 4, mask); + GSVector4i g = (d << 4).blend(c, mask); + GSVector4i h = d.blend(c >> 4, mask); + + a = e.upl8(f); + c = e.uph8(f); + b = g.upl8(h); + d = g.uph8(h); + } + + __forceinline static void sw8(GSVector4i& a, GSVector4i& b, GSVector4i& c, GSVector4i& d) + { + GSVector4i e = a; + GSVector4i f = c; + + a = e.upl8(b); + c = e.uph8(b); + b = f.upl8(d); + d = f.uph8(d); + } + + __forceinline static void sw16(GSVector4i& a, GSVector4i& b, GSVector4i& c, GSVector4i& d) + { + GSVector4i e = a; + GSVector4i f = c; + + a = e.upl16(b); + c = e.uph16(b); + b = f.upl16(d); + d = f.uph16(d); + } + + __forceinline static void sw16rl(GSVector4i& a, GSVector4i& b, GSVector4i& c, GSVector4i& d) + { + GSVector4i e = a; + GSVector4i f = c; + + a = b.upl16(e); + c = e.uph16(b); + b = d.upl16(f); + d = f.uph16(d); + } + + __forceinline static void sw16rh(GSVector4i& a, GSVector4i& b, GSVector4i& c, GSVector4i& d) + { + GSVector4i e = a; + GSVector4i f = c; + + a = e.upl16(b); + c = b.uph16(e); + b = f.upl16(d); + d = d.uph16(f); + } + + __forceinline static void sw32(GSVector4i& a, GSVector4i& b, GSVector4i& c, GSVector4i& d) + { + GSVector4i e = a; + GSVector4i f = c; + + a = e.upl32(b); + c = e.uph32(b); + b = f.upl32(d); + d = f.uph32(d); + } + + __forceinline static void sw64(GSVector4i& a, GSVector4i& b, GSVector4i& c, GSVector4i& d) + { + GSVector4i e = a; + GSVector4i f = c; + + a = e.upl64(b); + c = e.uph64(b); + b = f.upl64(d); + d = f.uph64(d); + } + + __forceinline static bool compare(const void* dst, const void* src, int size) + { + ASSERT((size & 15) == 0); + + size >>= 4; + + GSVector4i* s = (GSVector4i*)src; + GSVector4i* d = (GSVector4i*)dst; + + GSVector4i v = GSVector4i::xffffffff(); + + for(int i = 0; i < size; i++) + { + v &= d[i] == s[i]; + } + + return v.alltrue(); + } + + __forceinline static bool update(const void* dst, const void* src, int size) + { + ASSERT((size & 15) == 0); + + size >>= 4; + + GSVector4i* s = (GSVector4i*)src; + GSVector4i* d = (GSVector4i*)dst; + + GSVector4i v = GSVector4i::xffffffff(); + + for(int i = 0; i < size; i++) + { + v &= d[i] == s[i]; + + d[i] = s[i]; + } + + return v.alltrue(); + } + + void operator += (const GSVector4i& v) + { + m = _mm_add_epi32(m, v); + } + + void operator -= (const GSVector4i& v) + { + m = _mm_sub_epi32(m, v); + } + + void operator += (int i) + { + *this += GSVector4i(i); + } + + void operator -= (int i) + { + *this -= GSVector4i(i); + } + + void operator <<= (const int i) + { + m = _mm_slli_epi32(m, i); + } + + void operator >>= (const int i) + { + m = _mm_srli_epi32(m, i); + } + + void operator &= (const GSVector4i& v) + { + m = _mm_and_si128(m, v); + } + + void operator |= (const GSVector4i& v) + { + m = _mm_or_si128(m, v); + } + + void operator ^= (const GSVector4i& v) + { + m = _mm_xor_si128(m, v); + } + + friend GSVector4i operator + (const GSVector4i& v1, const GSVector4i& v2) + { + return GSVector4i(_mm_add_epi32(v1, v2)); + } + + friend GSVector4i operator - (const GSVector4i& v1, const GSVector4i& v2) + { + return GSVector4i(_mm_sub_epi32(v1, v2)); + } + + friend GSVector4i operator + (const GSVector4i& v, int i) + { + return v + GSVector4i(i); + } + + friend GSVector4i operator - (const GSVector4i& v, int i) + { + return v - GSVector4i(i); + } + + friend GSVector4i operator << (const GSVector4i& v, const int i) + { + return GSVector4i(_mm_slli_epi32(v, i)); + } + + friend GSVector4i operator >> (const GSVector4i& v, const int i) + { + return GSVector4i(_mm_srli_epi32(v, i)); + } + + friend GSVector4i operator & (const GSVector4i& v1, const GSVector4i& v2) + { + return GSVector4i(_mm_and_si128(v1, v2)); + } + + friend GSVector4i operator | (const GSVector4i& v1, const GSVector4i& v2) + { + return GSVector4i(_mm_or_si128(v1, v2)); + } + + friend GSVector4i operator ^ (const GSVector4i& v1, const GSVector4i& v2) + { + return GSVector4i(_mm_xor_si128(v1, v2)); + } + + friend GSVector4i operator & (const GSVector4i& v, int i) + { + return v & GSVector4i(i); + } + + friend GSVector4i operator | (const GSVector4i& v, int i) + { + return v | GSVector4i(i); + } + + friend GSVector4i operator ^ (const GSVector4i& v, int i) + { + return v ^ GSVector4i(i); + } + + friend GSVector4i operator ~ (const GSVector4i& v) + { + return v ^ (v == v); + } + + friend GSVector4i operator == (const GSVector4i& v1, const GSVector4i& v2) + { + return GSVector4i(_mm_cmpeq_epi32(v1, v2)); + } + + friend GSVector4i operator != (const GSVector4i& v1, const GSVector4i& v2) + { + return ~(v1 == v2); + } + + friend GSVector4i operator > (const GSVector4i& v1, const GSVector4i& v2) + { + return GSVector4i(_mm_cmpgt_epi32(v1, v2)); + } + + friend GSVector4i operator < (const GSVector4i& v1, const GSVector4i& v2) + { + return GSVector4i(_mm_cmplt_epi32(v1, v2)); + } + + friend GSVector4i operator >= (const GSVector4i& v1, const GSVector4i& v2) + { + return (v1 > v2) | (v1 == v2); + } + + friend GSVector4i operator <= (const GSVector4i& v1, const GSVector4i& v2) + { + return (v1 < v2) | (v1 == v2); + } + + template GSVector4i shuffle() const + { + return GSVector4i(_mm_shuffle_epi32(m, _MM_SHUFFLE(i, i, i, i))); + } + + #define VECTOR4i_SHUFFLE_4(xs, xn, ys, yn, zs, zn, ws, wn) \ + GSVector4i xs##ys##zs##ws() const {return GSVector4i(_mm_shuffle_epi32(m, _MM_SHUFFLE(wn, zn, yn, xn)));} \ + GSVector4i xs##ys##zs##ws##l() const {return GSVector4i(_mm_shufflelo_epi16(m, _MM_SHUFFLE(wn, zn, yn, xn)));} \ + GSVector4i xs##ys##zs##ws##h() const {return GSVector4i(_mm_shufflehi_epi16(m, _MM_SHUFFLE(wn, zn, yn, xn)));} \ + GSVector4i xs##ys##zs##ws##lh() const {return GSVector4i(_mm_shufflehi_epi16(_mm_shufflelo_epi16(m, _MM_SHUFFLE(wn, zn, yn, xn)), _MM_SHUFFLE(wn, zn, yn, xn)));} \ + + #define VECTOR4i_SHUFFLE_3(xs, xn, ys, yn, zs, zn) \ + VECTOR4i_SHUFFLE_4(xs, xn, ys, yn, zs, zn, x, 0) \ + VECTOR4i_SHUFFLE_4(xs, xn, ys, yn, zs, zn, y, 1) \ + VECTOR4i_SHUFFLE_4(xs, xn, ys, yn, zs, zn, z, 2) \ + VECTOR4i_SHUFFLE_4(xs, xn, ys, yn, zs, zn, w, 3) \ + + #define VECTOR4i_SHUFFLE_2(xs, xn, ys, yn) \ + VECTOR4i_SHUFFLE_3(xs, xn, ys, yn, x, 0) \ + VECTOR4i_SHUFFLE_3(xs, xn, ys, yn, y, 1) \ + VECTOR4i_SHUFFLE_3(xs, xn, ys, yn, z, 2) \ + VECTOR4i_SHUFFLE_3(xs, xn, ys, yn, w, 3) \ + + #define VECTOR4i_SHUFFLE_1(xs, xn) \ + GSVector4i xs##4##() const {return GSVector4i(_mm_shuffle_epi32(m, _MM_SHUFFLE(xn, xn, xn, xn)));} \ + GSVector4i xs##4##l() const {return GSVector4i(_mm_shufflelo_epi16(m, _MM_SHUFFLE(xn, xn, xn, xn)));} \ + GSVector4i xs##4##h() const {return GSVector4i(_mm_shufflehi_epi16(m, _MM_SHUFFLE(xn, xn, xn, xn)));} \ + VECTOR4i_SHUFFLE_2(xs, xn, x, 0) \ + VECTOR4i_SHUFFLE_2(xs, xn, y, 1) \ + VECTOR4i_SHUFFLE_2(xs, xn, z, 2) \ + VECTOR4i_SHUFFLE_2(xs, xn, w, 3) \ + + VECTOR4i_SHUFFLE_1(x, 0) + VECTOR4i_SHUFFLE_1(y, 1) + VECTOR4i_SHUFFLE_1(z, 2) + VECTOR4i_SHUFFLE_1(w, 3) + + static GSVector4i zero() {return GSVector4i(_mm_setzero_si128());} + + static GSVector4i xffffffff() {return zero() == zero();} + + static GSVector4i x00000001() {return xffffffff().srl32(31);} + static GSVector4i x00000003() {return xffffffff().srl32(30);} + static GSVector4i x00000007() {return xffffffff().srl32(29);} + static GSVector4i x0000000f() {return xffffffff().srl32(28);} + static GSVector4i x0000001f() {return xffffffff().srl32(27);} + static GSVector4i x0000003f() {return xffffffff().srl32(26);} + static GSVector4i x0000007f() {return xffffffff().srl32(25);} + static GSVector4i x000000ff() {return xffffffff().srl32(24);} + static GSVector4i x000001ff() {return xffffffff().srl32(23);} + static GSVector4i x000003ff() {return xffffffff().srl32(22);} + static GSVector4i x000007ff() {return xffffffff().srl32(21);} + static GSVector4i x00000fff() {return xffffffff().srl32(20);} + static GSVector4i x00001fff() {return xffffffff().srl32(19);} + static GSVector4i x00003fff() {return xffffffff().srl32(18);} + static GSVector4i x00007fff() {return xffffffff().srl32(17);} + static GSVector4i x0000ffff() {return xffffffff().srl32(16);} + static GSVector4i x0001ffff() {return xffffffff().srl32(15);} + static GSVector4i x0003ffff() {return xffffffff().srl32(14);} + static GSVector4i x0007ffff() {return xffffffff().srl32(13);} + static GSVector4i x000fffff() {return xffffffff().srl32(12);} + static GSVector4i x001fffff() {return xffffffff().srl32(11);} + static GSVector4i x003fffff() {return xffffffff().srl32(10);} + static GSVector4i x007fffff() {return xffffffff().srl32( 9);} + static GSVector4i x00ffffff() {return xffffffff().srl32( 8);} + static GSVector4i x01ffffff() {return xffffffff().srl32( 7);} + static GSVector4i x03ffffff() {return xffffffff().srl32( 6);} + static GSVector4i x07ffffff() {return xffffffff().srl32( 5);} + static GSVector4i x0fffffff() {return xffffffff().srl32( 4);} + static GSVector4i x1fffffff() {return xffffffff().srl32( 3);} + static GSVector4i x3fffffff() {return xffffffff().srl32( 2);} + static GSVector4i x7fffffff() {return xffffffff().srl32( 1);} + + static GSVector4i x80000000() {return xffffffff().sll32(31);} + static GSVector4i xc0000000() {return xffffffff().sll32(30);} + static GSVector4i xe0000000() {return xffffffff().sll32(29);} + static GSVector4i xf0000000() {return xffffffff().sll32(28);} + static GSVector4i xf8000000() {return xffffffff().sll32(27);} + static GSVector4i xfc000000() {return xffffffff().sll32(26);} + static GSVector4i xfe000000() {return xffffffff().sll32(25);} + static GSVector4i xff000000() {return xffffffff().sll32(24);} + static GSVector4i xff800000() {return xffffffff().sll32(23);} + static GSVector4i xffc00000() {return xffffffff().sll32(22);} + static GSVector4i xffe00000() {return xffffffff().sll32(21);} + static GSVector4i xfff00000() {return xffffffff().sll32(20);} + static GSVector4i xfff80000() {return xffffffff().sll32(19);} + static GSVector4i xfffc0000() {return xffffffff().sll32(18);} + static GSVector4i xfffe0000() {return xffffffff().sll32(17);} + static GSVector4i xffff0000() {return xffffffff().sll32(16);} + static GSVector4i xffff8000() {return xffffffff().sll32(15);} + static GSVector4i xffffc000() {return xffffffff().sll32(14);} + static GSVector4i xffffe000() {return xffffffff().sll32(13);} + static GSVector4i xfffff000() {return xffffffff().sll32(12);} + static GSVector4i xfffff800() {return xffffffff().sll32(11);} + static GSVector4i xfffffc00() {return xffffffff().sll32(10);} + static GSVector4i xfffffe00() {return xffffffff().sll32( 9);} + static GSVector4i xffffff00() {return xffffffff().sll32( 8);} + static GSVector4i xffffff80() {return xffffffff().sll32( 7);} + static GSVector4i xffffffc0() {return xffffffff().sll32( 6);} + static GSVector4i xffffffe0() {return xffffffff().sll32( 5);} + static GSVector4i xfffffff0() {return xffffffff().sll32( 4);} + static GSVector4i xfffffff8() {return xffffffff().sll32( 3);} + static GSVector4i xfffffffc() {return xffffffff().sll32( 2);} + static GSVector4i xfffffffe() {return xffffffff().sll32( 1);} + + static GSVector4i x0001() {return xffffffff().srl16(15);} + static GSVector4i x0003() {return xffffffff().srl16(14);} + static GSVector4i x0007() {return xffffffff().srl16(13);} + static GSVector4i x000f() {return xffffffff().srl16(12);} + static GSVector4i x001f() {return xffffffff().srl16(11);} + static GSVector4i x003f() {return xffffffff().srl16(10);} + static GSVector4i x007f() {return xffffffff().srl16( 9);} + static GSVector4i x00ff() {return xffffffff().srl16( 8);} + static GSVector4i x01ff() {return xffffffff().srl16( 7);} + static GSVector4i x03ff() {return xffffffff().srl16( 6);} + static GSVector4i x07ff() {return xffffffff().srl16( 5);} + static GSVector4i x0fff() {return xffffffff().srl16( 4);} + static GSVector4i x1fff() {return xffffffff().srl16( 3);} + static GSVector4i x3fff() {return xffffffff().srl16( 2);} + static GSVector4i x7fff() {return xffffffff().srl16( 1);} + + static GSVector4i x8000() {return xffffffff().sll16(15);} + static GSVector4i xc000() {return xffffffff().sll16(14);} + static GSVector4i xe000() {return xffffffff().sll16(13);} + static GSVector4i xf000() {return xffffffff().sll16(12);} + static GSVector4i xf800() {return xffffffff().sll16(11);} + static GSVector4i xfc00() {return xffffffff().sll16(10);} + static GSVector4i xfe00() {return xffffffff().sll16( 9);} + static GSVector4i xff00() {return xffffffff().sll16( 8);} + static GSVector4i xff80() {return xffffffff().sll16( 7);} + static GSVector4i xffc0() {return xffffffff().sll16( 6);} + static GSVector4i xffe0() {return xffffffff().sll16( 5);} + static GSVector4i xfff0() {return xffffffff().sll16( 4);} + static GSVector4i xfff8() {return xffffffff().sll16( 3);} + static GSVector4i xfffc() {return xffffffff().sll16( 2);} + static GSVector4i xfffe() {return xffffffff().sll16( 1);} + + static GSVector4i xffffffff(const GSVector4i& v) {return v == v;} + + static GSVector4i x00000001(const GSVector4i& v) {return xffffffff(v).srl32(31);} + static GSVector4i x00000003(const GSVector4i& v) {return xffffffff(v).srl32(30);} + static GSVector4i x00000007(const GSVector4i& v) {return xffffffff(v).srl32(29);} + static GSVector4i x0000000f(const GSVector4i& v) {return xffffffff(v).srl32(28);} + static GSVector4i x0000001f(const GSVector4i& v) {return xffffffff(v).srl32(27);} + static GSVector4i x0000003f(const GSVector4i& v) {return xffffffff(v).srl32(26);} + static GSVector4i x0000007f(const GSVector4i& v) {return xffffffff(v).srl32(25);} + static GSVector4i x000000ff(const GSVector4i& v) {return xffffffff(v).srl32(24);} + static GSVector4i x000001ff(const GSVector4i& v) {return xffffffff(v).srl32(23);} + static GSVector4i x000003ff(const GSVector4i& v) {return xffffffff(v).srl32(22);} + static GSVector4i x000007ff(const GSVector4i& v) {return xffffffff(v).srl32(21);} + static GSVector4i x00000fff(const GSVector4i& v) {return xffffffff(v).srl32(20);} + static GSVector4i x00001fff(const GSVector4i& v) {return xffffffff(v).srl32(19);} + static GSVector4i x00003fff(const GSVector4i& v) {return xffffffff(v).srl32(18);} + static GSVector4i x00007fff(const GSVector4i& v) {return xffffffff(v).srl32(17);} + static GSVector4i x0000ffff(const GSVector4i& v) {return xffffffff(v).srl32(16);} + static GSVector4i x0001ffff(const GSVector4i& v) {return xffffffff(v).srl32(15);} + static GSVector4i x0003ffff(const GSVector4i& v) {return xffffffff(v).srl32(14);} + static GSVector4i x0007ffff(const GSVector4i& v) {return xffffffff(v).srl32(13);} + static GSVector4i x000fffff(const GSVector4i& v) {return xffffffff(v).srl32(12);} + static GSVector4i x001fffff(const GSVector4i& v) {return xffffffff(v).srl32(11);} + static GSVector4i x003fffff(const GSVector4i& v) {return xffffffff(v).srl32(10);} + static GSVector4i x007fffff(const GSVector4i& v) {return xffffffff(v).srl32( 9);} + static GSVector4i x00ffffff(const GSVector4i& v) {return xffffffff(v).srl32( 8);} + static GSVector4i x01ffffff(const GSVector4i& v) {return xffffffff(v).srl32( 7);} + static GSVector4i x03ffffff(const GSVector4i& v) {return xffffffff(v).srl32( 6);} + static GSVector4i x07ffffff(const GSVector4i& v) {return xffffffff(v).srl32( 5);} + static GSVector4i x0fffffff(const GSVector4i& v) {return xffffffff(v).srl32( 4);} + static GSVector4i x1fffffff(const GSVector4i& v) {return xffffffff(v).srl32( 3);} + static GSVector4i x3fffffff(const GSVector4i& v) {return xffffffff(v).srl32( 2);} + static GSVector4i x7fffffff(const GSVector4i& v) {return xffffffff(v).srl32( 1);} + + static GSVector4i x80000000(const GSVector4i& v) {return xffffffff(v).sll32(31);} + static GSVector4i xc0000000(const GSVector4i& v) {return xffffffff(v).sll32(30);} + static GSVector4i xe0000000(const GSVector4i& v) {return xffffffff(v).sll32(29);} + static GSVector4i xf0000000(const GSVector4i& v) {return xffffffff(v).sll32(28);} + static GSVector4i xf8000000(const GSVector4i& v) {return xffffffff(v).sll32(27);} + static GSVector4i xfc000000(const GSVector4i& v) {return xffffffff(v).sll32(26);} + static GSVector4i xfe000000(const GSVector4i& v) {return xffffffff(v).sll32(25);} + static GSVector4i xff000000(const GSVector4i& v) {return xffffffff(v).sll32(24);} + static GSVector4i xff800000(const GSVector4i& v) {return xffffffff(v).sll32(23);} + static GSVector4i xffc00000(const GSVector4i& v) {return xffffffff(v).sll32(22);} + static GSVector4i xffe00000(const GSVector4i& v) {return xffffffff(v).sll32(21);} + static GSVector4i xfff00000(const GSVector4i& v) {return xffffffff(v).sll32(20);} + static GSVector4i xfff80000(const GSVector4i& v) {return xffffffff(v).sll32(19);} + static GSVector4i xfffc0000(const GSVector4i& v) {return xffffffff(v).sll32(18);} + static GSVector4i xfffe0000(const GSVector4i& v) {return xffffffff(v).sll32(17);} + static GSVector4i xffff0000(const GSVector4i& v) {return xffffffff(v).sll32(16);} + static GSVector4i xffff8000(const GSVector4i& v) {return xffffffff(v).sll32(15);} + static GSVector4i xffffc000(const GSVector4i& v) {return xffffffff(v).sll32(14);} + static GSVector4i xffffe000(const GSVector4i& v) {return xffffffff(v).sll32(13);} + static GSVector4i xfffff000(const GSVector4i& v) {return xffffffff(v).sll32(12);} + static GSVector4i xfffff800(const GSVector4i& v) {return xffffffff(v).sll32(11);} + static GSVector4i xfffffc00(const GSVector4i& v) {return xffffffff(v).sll32(10);} + static GSVector4i xfffffe00(const GSVector4i& v) {return xffffffff(v).sll32( 9);} + static GSVector4i xffffff00(const GSVector4i& v) {return xffffffff(v).sll32( 8);} + static GSVector4i xffffff80(const GSVector4i& v) {return xffffffff(v).sll32( 7);} + static GSVector4i xffffffc0(const GSVector4i& v) {return xffffffff(v).sll32( 6);} + static GSVector4i xffffffe0(const GSVector4i& v) {return xffffffff(v).sll32( 5);} + static GSVector4i xfffffff0(const GSVector4i& v) {return xffffffff(v).sll32( 4);} + static GSVector4i xfffffff8(const GSVector4i& v) {return xffffffff(v).sll32( 3);} + static GSVector4i xfffffffc(const GSVector4i& v) {return xffffffff(v).sll32( 2);} + static GSVector4i xfffffffe(const GSVector4i& v) {return xffffffff(v).sll32( 1);} + + static GSVector4i x0001(const GSVector4i& v) {return xffffffff(v).srl16(15);} + static GSVector4i x0003(const GSVector4i& v) {return xffffffff(v).srl16(14);} + static GSVector4i x0007(const GSVector4i& v) {return xffffffff(v).srl16(13);} + static GSVector4i x000f(const GSVector4i& v) {return xffffffff(v).srl16(12);} + static GSVector4i x001f(const GSVector4i& v) {return xffffffff(v).srl16(11);} + static GSVector4i x003f(const GSVector4i& v) {return xffffffff(v).srl16(10);} + static GSVector4i x007f(const GSVector4i& v) {return xffffffff(v).srl16( 9);} + static GSVector4i x00ff(const GSVector4i& v) {return xffffffff(v).srl16( 8);} + static GSVector4i x01ff(const GSVector4i& v) {return xffffffff(v).srl16( 7);} + static GSVector4i x03ff(const GSVector4i& v) {return xffffffff(v).srl16( 6);} + static GSVector4i x07ff(const GSVector4i& v) {return xffffffff(v).srl16( 5);} + static GSVector4i x0fff(const GSVector4i& v) {return xffffffff(v).srl16( 4);} + static GSVector4i x1fff(const GSVector4i& v) {return xffffffff(v).srl16( 3);} + static GSVector4i x3fff(const GSVector4i& v) {return xffffffff(v).srl16( 2);} + static GSVector4i x7fff(const GSVector4i& v) {return xffffffff(v).srl16( 1);} + + static GSVector4i x8000(const GSVector4i& v) {return xffffffff(v).sll16(15);} + static GSVector4i xc000(const GSVector4i& v) {return xffffffff(v).sll16(14);} + static GSVector4i xe000(const GSVector4i& v) {return xffffffff(v).sll16(13);} + static GSVector4i xf000(const GSVector4i& v) {return xffffffff(v).sll16(12);} + static GSVector4i xf800(const GSVector4i& v) {return xffffffff(v).sll16(11);} + static GSVector4i xfc00(const GSVector4i& v) {return xffffffff(v).sll16(10);} + static GSVector4i xfe00(const GSVector4i& v) {return xffffffff(v).sll16( 9);} + static GSVector4i xff00(const GSVector4i& v) {return xffffffff(v).sll16( 8);} + static GSVector4i xff80(const GSVector4i& v) {return xffffffff(v).sll16( 7);} + static GSVector4i xffc0(const GSVector4i& v) {return xffffffff(v).sll16( 6);} + static GSVector4i xffe0(const GSVector4i& v) {return xffffffff(v).sll16( 5);} + static GSVector4i xfff0(const GSVector4i& v) {return xffffffff(v).sll16( 4);} + static GSVector4i xfff8(const GSVector4i& v) {return xffffffff(v).sll16( 3);} + static GSVector4i xfffc(const GSVector4i& v) {return xffffffff(v).sll16( 2);} + static GSVector4i xfffe(const GSVector4i& v) {return xffffffff(v).sll16( 1);} +}; + +__declspec(align(16)) class GSVector4 +{ +public: + union + { + struct {float x, y, z, w;}; + struct {float r, g, b, a;}; + float v[4]; + float f32[4]; + unsigned __int64 u64[2]; + __int8 i8[16]; + __int16 i16[8]; + __int32 i32[4]; + __int64 i64[2]; + unsigned __int8 u8[16]; + unsigned __int16 u16[8]; + unsigned __int32 u32[4]; + __m128 m; + }; + + static const GSVector4 m_ps0123; + static const GSVector4 m_ps4567; + + GSVector4() + { + } + + GSVector4(float x, float y, float z, float w) + { + m = _mm_set_ps(w, z, y, x); + } + + GSVector4(float x, float y) + { + m = _mm_unpacklo_ps(_mm_load_ss(&x), _mm_load_ss(&y)); + } + + GSVector4(int x, int y, int z, int w) + { + m = _mm_cvtepi32_ps(_mm_set_epi32(w, z, y, x)); + } + + GSVector4(int x, int y) + { + m = _mm_cvtepi32_ps(_mm_unpacklo_epi32(_mm_cvtsi32_si128(x), _mm_cvtsi32_si128(y))); + } + + GSVector4(const GSVector4& v) + { + m = v.m; + } + + explicit GSVector4(const GSVector2& v) + { + m = _mm_castsi128_ps(_mm_loadl_epi64((__m128i*)&v)); + } + + explicit GSVector4(float f) + { + m = _mm_set1_ps(f); + } + + explicit GSVector4(__m128 m) + { + this->m = m; + } + + explicit GSVector4(CRect r) + { + m = _mm_set_ps((float)r.bottom, (float)r.right, (float)r.top, (float)r.left); + } + + explicit GSVector4(DWORD dw) + { + *this = GSVector4(GSVector4i::load((int)dw).u8to32()); + } + + explicit GSVector4(const GSVector4i& v) + { + *this = v; + } + + void operator = (const GSVector4& v) + { + m = v.m; + } + + void operator = (const GSVector4i& v); + + void operator = (float f) + { + m = _mm_set1_ps(f); + } + + void operator = (__m128 m) + { + this->m = m; + } + + void operator = (DWORD dw) + { + *this = GSVector4(GSVector4i::load((int)dw).u8to32()); + } + + void operator = (CRect r) + { + *this = GSVector4(GSVector4i(r.left, r.top, r.right, r.bottom)); + } + + operator __m128() const + { + return m; + } + + UINT32 rgba32() const + { + return GSVector4i(*this).rgba32(); + } + + static GSVector4 cast(const GSVector4i& v); + + GSVector4 abs() const + { + return GSVector4(_mm_abs_ps(m)); + } + + GSVector4 neg() const + { + return GSVector4(_mm_neg_ps(m)); + } + + GSVector4 rcp() const + { + return GSVector4(_mm_rcp_ps(m)); + } + + GSVector4 rcpnr() const + { + return GSVector4(_mm_rcpnr_ps(m)); + } + + GSVector4 floor() const + { + return GSVector4(_mm_floor_ps(m)); + } + + GSVector4 ceil() const + { + return GSVector4(_mm_ceil_ps(m)); + } + + GSVector4 mod2x(const GSVector4& f, const int scale = 256) const + { + return *this * (f * (2.0f / scale)); + } + + GSVector4 mod2x(float f, const int scale = 256) const + { + return mod2x(GSVector4(f), scale); + } + + GSVector4 madd(const GSVector4& a, const GSVector4& b) const + { + return *this * a + b; // TODO: _mm_fmadd_ps + } + + GSVector4 msub(const GSVector4& a, const GSVector4& b) const + { + return *this * a + b; // TODO: _mm_fmsub_ps + } + + GSVector4 nmadd(const GSVector4& a, const GSVector4& b) const + { + return b - *this * a; // TODO: _mm_fnmadd_ps + } + + GSVector4 nmsub(const GSVector4& a, const GSVector4& b) const + { + return -b - *this * a; // TODO: _mm_fmnsub_ps + } + + GSVector4 lerp(const GSVector4& v, const GSVector4& f) const + { + return *this + (v - *this) * f; + } + + GSVector4 lerp(const GSVector4& v, float f) const + { + return lerp(v, GSVector4(f)); + } + + GSVector4 hadd() const + { + #if _M_SSE >= 0x300 + return GSVector4(_mm_hadd_ps(m, m)); + #else + return xzxz() + ywyw(); + #endif + } + + GSVector4 hadd(const GSVector4& v) const + { + #if _M_SSE >= 0x300 + return GSVector4(_mm_hadd_ps(m, v.m)); + #else + return xzxz(v) + ywyw(v); + #endif + } + + #if _M_SSE >= 0x401 + template GSVector4 dp(const GSVector4& v) const + { + return GSVector4(_mm_dp_ps(m, v.m, i)); + } + #endif + + GSVector4 sat(const GSVector4& a, const GSVector4& b) const + { + return GSVector4(_mm_min_ps(_mm_max_ps(m, a), b)); + } + + GSVector4 sat(const GSVector4& a) const + { + return GSVector4(_mm_min_ps(_mm_max_ps(m, a.xyxy()), a.zwzw())); + } + + GSVector4 sat(const float scale = 255) const + { + return sat(zero(), GSVector4(scale)); + } + + GSVector4 clamp(const float scale = 255) const + { + return minv(GSVector4(scale)); + } + + GSVector4 minv(const GSVector4& a) const + { + return GSVector4(_mm_min_ps(m, a)); + } + + GSVector4 maxv(const GSVector4& a) const + { + return GSVector4(_mm_max_ps(m, a)); + } + + GSVector4 blend8(const GSVector4& a, const GSVector4& mask) const + { + return GSVector4(_mm_blendv_ps(m, a, mask)); + } + + GSVector4 upl(const GSVector4& a) const + { + return GSVector4(_mm_unpacklo_ps(m, a)); + } + + GSVector4 uph(const GSVector4& a) const + { + return GSVector4(_mm_unpackhi_ps(m, a)); + } + + GSVector4 l2h(const GSVector4& a) const + { + return GSVector4(_mm_movelh_ps(m, a)); + } + + GSVector4 h2l(const GSVector4& a) const + { + return GSVector4(_mm_movehl_ps(m, a)); + } + + GSVector4 andnot(const GSVector4& v) const + { + return GSVector4(_mm_andnot_ps(v.m, m)); + } + + int mask() const + { + return _mm_movemask_ps(m); + } + + bool alltrue() const + { + return _mm_movemask_ps(m) == 0xf; + } + + bool allfalse() const + { + return _mm_movemask_ps(m) == 0; + } + + // TODO: insert + + template int extract() const + { + #if _M_SSE >= 0x401 + return _mm_extract_ps(m, i); + #else + return i32[i]; + #endif + } + + static GSVector4 zero() + { + return GSVector4(_mm_setzero_ps()); + } + + static GSVector4 xffffffff() + { + return zero() == zero(); + } + + static GSVector4 ps0123() + { + return GSVector4(m_ps0123); + } + + static GSVector4 ps4567() + { + return GSVector4(m_ps4567); + } + + static GSVector4 loadl(const void* p) + { + return GSVector4(_mm_castpd_ps(_mm_load_sd((double*)p))); + } + + static GSVector4 load(float f) + { + return GSVector4(_mm_load_ss(&f)); + } + + template static GSVector4 load(const void* p) + { + return GSVector4i(aligned ? _mm_load_ps((__m128*)p) : _mm_loadu_ps((__m128*)p)); + } + + static void storel(void* p, const GSVector4& v) + { + _mm_store_sd((double*)p, _mm_castps_pd(v.m)); + } + + template static void store(void* p, const GSVector4& v) + { + if(aligned) _mm_store_ps((__m128*)p, v.m); + else _mm_storeu_ps((__m128*)p, v.m); + } + + __forceinline static void expand(const GSVector4i& v, GSVector4& a, GSVector4& b, GSVector4& c, GSVector4& d) + { + GSVector4i mask = GSVector4i::x000000ff(); + + a = v & mask; + b = (v >> 8) & mask; + c = (v >> 16) & mask; + d = (v >> 24); + } + + __forceinline static void transpose(GSVector4& a, GSVector4& b, GSVector4& c, GSVector4& d) + { + GSVector4 v0 = a.xyxy(b); + GSVector4 v1 = c.xyxy(d); + + GSVector4 e = v0.xzxz(v1); + GSVector4 f = v0.ywyw(v1); + + GSVector4 v2 = a.zwzw(b); + GSVector4 v3 = c.zwzw(d); + + GSVector4 g = v2.xzxz(v3); + GSVector4 h = v2.ywyw(v3); + + a = e; + b = f; + c = g; + d = h; +/* + GSVector4 v0 = a.xyxy(b); + GSVector4 v1 = c.xyxy(d); + GSVector4 v2 = a.zwzw(b); + GSVector4 v3 = c.zwzw(d); + + a = v0.xzxz(v1); + b = v0.ywyw(v1); + c = v2.xzxz(v3); + d = v2.ywyw(v3); +*/ +/* + GSVector4 v0 = a.upl(b); + GSVector4 v1 = a.uph(b); + GSVector4 v2 = c.upl(d); + GSVector4 v3 = c.uph(d); + + a = v0.l2h(v2); + b = v2.h2l(v0); + c = v1.l2h(v3); + d = v3.h2l(v1); +*/ } + + GSVector4 operator - () const + { + return neg(); + } + + void operator += (const GSVector4& v) + { + m = _mm_add_ps(m, v); + } + + void operator -= (const GSVector4& v) + { + m = _mm_sub_ps(m, v); + } + + void operator *= (const GSVector4& v) + { + m = _mm_mul_ps(m, v); + } + + void operator /= (const GSVector4& v) + { + m = _mm_div_ps(m, v); + } + + void operator += (float f) + { + *this += GSVector4(f); + } + + void operator -= (float f) + { + *this -= GSVector4(f); + } + + void operator *= (float f) + { + *this *= GSVector4(f); + } + + void operator /= (float f) + { + *this /= GSVector4(f); + } + + void operator &= (const GSVector4& v) + { + m = _mm_and_ps(m, v); + } + + void operator |= (const GSVector4& v) + { + m = _mm_or_ps(m, v); + } + + void operator ^= (const GSVector4& v) + { + m = _mm_xor_ps(m, v); + } + + friend GSVector4 operator + (const GSVector4& v1, const GSVector4& v2) + { + return GSVector4(_mm_add_ps(v1, v2)); + } + + friend GSVector4 operator - (const GSVector4& v1, const GSVector4& v2) + { + return GSVector4(_mm_sub_ps(v1, v2)); + } + + friend GSVector4 operator * (const GSVector4& v1, const GSVector4& v2) + { + return GSVector4(_mm_mul_ps(v1, v2)); + } + + friend GSVector4 operator / (const GSVector4& v1, const GSVector4& v2) + { + return GSVector4(_mm_div_ps(v1, v2)); + } + + friend GSVector4 operator + (const GSVector4& v, float f) + { + return v + GSVector4(f); + } + + friend GSVector4 operator - (const GSVector4& v, float f) + { + return v - GSVector4(f); + } + + friend GSVector4 operator * (const GSVector4& v, float f) + { + return v * GSVector4(f); + } + + friend GSVector4 operator / (const GSVector4& v, float f) + { + return v / GSVector4(f); + } + + friend GSVector4 operator & (const GSVector4& v1, const GSVector4& v2) + { + return GSVector4(_mm_and_ps(v1, v2)); + } + + friend GSVector4 operator | (const GSVector4& v1, const GSVector4& v2) + { + return GSVector4(_mm_or_ps(v1, v2)); + } + + friend GSVector4 operator ^ (const GSVector4& v1, const GSVector4& v2) + { + return GSVector4(_mm_xor_ps(v1, v2)); + } + + friend GSVector4 operator == (const GSVector4& v1, const GSVector4& v2) + { + return GSVector4(_mm_cmpeq_ps(v1, v2)); + } + + friend GSVector4 operator != (const GSVector4& v1, const GSVector4& v2) + { + return GSVector4(_mm_cmpneq_ps(v1, v2)); + } + + friend GSVector4 operator > (const GSVector4& v1, const GSVector4& v2) + { + return GSVector4(_mm_cmpgt_ps(v1, v2)); + } + + friend GSVector4 operator < (const GSVector4& v1, const GSVector4& v2) + { + return GSVector4(_mm_cmplt_ps(v1, v2)); + } + + friend GSVector4 operator >= (const GSVector4& v1, const GSVector4& v2) + { + return GSVector4(_mm_cmpge_ps(v1, v2)); + } + + friend GSVector4 operator <= (const GSVector4& v1, const GSVector4& v2) + { + return GSVector4(_mm_cmple_ps(v1, v2)); + } + + template GSVector4 shuffle() const + { + return GSVector4(_mm_shuffle_ps(m, m, _MM_SHUFFLE(i, i, i, i))); + } + + #define VECTOR4_SHUFFLE_4(xs, xn, ys, yn, zs, zn, ws, wn) \ + GSVector4 xs##ys##zs##ws() const {return GSVector4(_mm_shuffle_ps(m, m, _MM_SHUFFLE(wn, zn, yn, xn)));} \ + GSVector4 xs##ys##zs##ws(const GSVector4& v) const {return GSVector4(_mm_shuffle_ps(m, v.m, _MM_SHUFFLE(wn, zn, yn, xn)));} \ + + #define VECTOR4_SHUFFLE_3(xs, xn, ys, yn, zs, zn) \ + VECTOR4_SHUFFLE_4(xs, xn, ys, yn, zs, zn, x, 0) \ + VECTOR4_SHUFFLE_4(xs, xn, ys, yn, zs, zn, y, 1) \ + VECTOR4_SHUFFLE_4(xs, xn, ys, yn, zs, zn, z, 2) \ + VECTOR4_SHUFFLE_4(xs, xn, ys, yn, zs, zn, w, 3) \ + + #define VECTOR4_SHUFFLE_2(xs, xn, ys, yn) \ + VECTOR4_SHUFFLE_3(xs, xn, ys, yn, x, 0) \ + VECTOR4_SHUFFLE_3(xs, xn, ys, yn, y, 1) \ + VECTOR4_SHUFFLE_3(xs, xn, ys, yn, z, 2) \ + VECTOR4_SHUFFLE_3(xs, xn, ys, yn, w, 3) \ + + #define VECTOR4_SHUFFLE_1(xs, xn) \ + GSVector4 xs##4##() const {return GSVector4(_mm_shuffle_ps(m, m, _MM_SHUFFLE(xn, xn, xn, xn)));} \ + GSVector4 xs##4##(const GSVector4& v) const {return GSVector4(_mm_shuffle_ps(m, v.m, _MM_SHUFFLE(xn, xn, xn, xn)));} \ + VECTOR4_SHUFFLE_2(xs, xn, x, 0) \ + VECTOR4_SHUFFLE_2(xs, xn, y, 1) \ + VECTOR4_SHUFFLE_2(xs, xn, z, 2) \ + VECTOR4_SHUFFLE_2(xs, xn, w, 3) \ + + VECTOR4_SHUFFLE_1(x, 0) + VECTOR4_SHUFFLE_1(y, 1) + VECTOR4_SHUFFLE_1(z, 2) + VECTOR4_SHUFFLE_1(w, 3) +}; + +#pragma pack(pop) diff --git a/plugins/GSdx/GSVertex.h b/plugins/GSdx/GSVertex.h index c1b52ac154..bfe77ee796 100644 --- a/plugins/GSdx/GSVertex.h +++ b/plugins/GSdx/GSVertex.h @@ -1,87 +1,87 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GS.h" -#include "GSVector.h" -#include "GSVertexHW.h" -#include "GSVertexSW.h" - -#pragma pack(push, 1) - -__declspec(align(16)) struct GSVertex -{ - union - { - struct - { - GIFRegST ST; - GIFRegXYZ XYZ; - GIFRegRGBAQ RGBAQ; - GIFRegFOG FOG; - }; - - struct {__m128i m128i[2];}; - struct {__m128 m128[2];}; - }; - - GIFRegUV UV; - - GSVertex() {memset(this, 0, sizeof(*this));} - - GSVector4 GetUV() const {return GSVector4(GSVector4i::load(UV.ai32[0]).upl16());} -}; - -struct GSVertexOld -{ - GIFRegRGBAQ RGBAQ; - GIFRegST ST; - GIFRegUV UV; - GIFRegXYZ XYZ; - GIFRegFOG FOG; - - GSVertexOld() {memset(this, 0, sizeof(*this));} -}; - -struct GSVertexP -{ - GSVector4 p; -}; - -struct GSVertexPT1 -{ - GSVector4 p; - GSVector2 t; -}; - -struct GSVertexPT2 -{ - GSVector4 p; - GSVector2 t[2]; -}; - -struct GSVertexNull -{ - GSVector4 p; -}; - -#pragma pack(pop) +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GS.h" +#include "GSVector.h" +#include "GSVertexHW.h" +#include "GSVertexSW.h" + +#pragma pack(push, 1) + +__declspec(align(16)) struct GSVertex +{ + union + { + struct + { + GIFRegST ST; + GIFRegXYZ XYZ; + GIFRegRGBAQ RGBAQ; + GIFRegFOG FOG; + }; + + struct {__m128i m128i[2];}; + struct {__m128 m128[2];}; + }; + + GIFRegUV UV; + + GSVertex() {memset(this, 0, sizeof(*this));} + + GSVector4 GetUV() const {return GSVector4(GSVector4i::load(UV.ai32[0]).upl16());} +}; + +struct GSVertexOld +{ + GIFRegRGBAQ RGBAQ; + GIFRegST ST; + GIFRegUV UV; + GIFRegXYZ XYZ; + GIFRegFOG FOG; + + GSVertexOld() {memset(this, 0, sizeof(*this));} +}; + +struct GSVertexP +{ + GSVector4 p; +}; + +struct GSVertexPT1 +{ + GSVector4 p; + GSVector2 t; +}; + +struct GSVertexPT2 +{ + GSVector4 p; + GSVector2 t[2]; +}; + +struct GSVertexNull +{ + GSVector4 p; +}; + +#pragma pack(pop) diff --git a/plugins/GSdx/GSVertexHW.h b/plugins/GSdx/GSVertexHW.h index eaa209f81b..add5e9eeeb 100644 --- a/plugins/GSdx/GSVertexHW.h +++ b/plugins/GSdx/GSVertexHW.h @@ -1,87 +1,87 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSVector.h" - -#pragma pack(push, 1) - -__declspec(align(16)) union GSVertexHW9 -{ - struct - { - GSVector2 t; - union {struct {BYTE r, g, b, a;}; DWORD c0;}; - union {struct {BYTE ta0, ta1, res, f;}; DWORD c1;}; - GSVector4 p; - }; - - struct {__m128i m128i[2];}; - struct {__m128 m128[2];}; - -#if _M_SSE >= 0x200 - GSVertexHW9& operator = (GSVertexHW9& v) {m128i[0] = v.m128i[0]; m128i[1] = v.m128i[1]; return *this;} -#endif - - float GetQ() {return p.w;} -}; - -__declspec(align(16)) union GSVertexHW10 -{ - struct - { - union - { - struct {float x, y;} t; - GIFRegST ST; - }; - - union - { - struct {union {struct {WORD x, y;}; DWORD xy;}; DWORD z;} p; - GIFRegXYZ XYZ; - }; - - union - { - union {struct {BYTE r, g, b, a; float q;}; DWORD c0;}; - GIFRegRGBAQ RGBAQ; - }; - - union - { - struct {DWORD _pad[1]; union {struct {BYTE ta0, ta1, res, f;}; DWORD c1;};}; - GIFRegFOG FOG; - }; - }; - - struct {__m128i m128i[2];}; - struct {__m128 m128[2];}; - -#if _M_SSE >= 0x200 - GSVertexHW10& operator = (GSVertexHW10& v) {m128i[0] = v.m128i[0]; m128i[1] = v.m128i[1]; return *this;} -#endif - - float GetQ() {return q;} -}; - -#pragma pack(pop) +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSVector.h" + +#pragma pack(push, 1) + +__declspec(align(16)) union GSVertexHW9 +{ + struct + { + GSVector2 t; + union {struct {BYTE r, g, b, a;}; DWORD c0;}; + union {struct {BYTE ta0, ta1, res, f;}; DWORD c1;}; + GSVector4 p; + }; + + struct {__m128i m128i[2];}; + struct {__m128 m128[2];}; + +#if _M_SSE >= 0x200 + GSVertexHW9& operator = (GSVertexHW9& v) {m128i[0] = v.m128i[0]; m128i[1] = v.m128i[1]; return *this;} +#endif + + float GetQ() {return p.w;} +}; + +__declspec(align(16)) union GSVertexHW10 +{ + struct + { + union + { + struct {float x, y;} t; + GIFRegST ST; + }; + + union + { + struct {union {struct {WORD x, y;}; DWORD xy;}; DWORD z;} p; + GIFRegXYZ XYZ; + }; + + union + { + union {struct {BYTE r, g, b, a; float q;}; DWORD c0;}; + GIFRegRGBAQ RGBAQ; + }; + + union + { + struct {DWORD _pad[1]; union {struct {BYTE ta0, ta1, res, f;}; DWORD c1;};}; + GIFRegFOG FOG; + }; + }; + + struct {__m128i m128i[2];}; + struct {__m128 m128[2];}; + +#if _M_SSE >= 0x200 + GSVertexHW10& operator = (GSVertexHW10& v) {m128i[0] = v.m128i[0]; m128i[1] = v.m128i[1]; return *this;} +#endif + + float GetQ() {return q;} +}; + +#pragma pack(pop) diff --git a/plugins/GSdx/GSVertexList.cpp b/plugins/GSdx/GSVertexList.cpp index 21377b3758..b51ecaba10 100644 --- a/plugins/GSdx/GSVertexList.cpp +++ b/plugins/GSdx/GSVertexList.cpp @@ -1,23 +1,23 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" #include "GSVertexList.h" \ No newline at end of file diff --git a/plugins/GSdx/GSVertexList.h b/plugins/GSdx/GSVertexList.h index 95111cd6de..c7152a8ff0 100644 --- a/plugins/GSdx/GSVertexList.h +++ b/plugins/GSdx/GSVertexList.h @@ -1,87 +1,87 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -template class GSVertexList -{ - void* m_base; - Vertex* m_v[3]; - DWORD m_count; - -public: - GSVertexList() - : m_count(0) - { - m_base = _aligned_malloc(sizeof(Vertex) * countof(m_v), 16); - - for(int i = 0; i < countof(m_v); i++) - { - m_v[i] = &((Vertex*)m_base)[i]; - } - } - - virtual ~GSVertexList() - { - _aligned_free(m_base); - } - - void RemoveAll() - { - m_count = 0; - } - - __forceinline Vertex& AddTail() - { - ASSERT(m_count < 3); - - return *m_v[m_count++]; - } - - __forceinline void RemoveAt(int pos, int keep) - { - if(keep == 1) - { - Vertex* tmp = m_v[pos + 0]; - m_v[pos + 0] = m_v[pos + 1]; - m_v[pos + 1] = tmp; - } - else if(keep == 2) - { - Vertex* tmp = m_v[pos + 0]; - m_v[pos + 0] = m_v[pos + 1]; - m_v[pos + 1] = m_v[pos + 2]; - m_v[pos + 2] = tmp; - } - - m_count = pos + keep; - } - - __forceinline void GetAt(int i, Vertex& v) - { - v = *m_v[i]; - } - - DWORD GetCount() - { - return m_count; - } -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +template class GSVertexList +{ + void* m_base; + Vertex* m_v[3]; + DWORD m_count; + +public: + GSVertexList() + : m_count(0) + { + m_base = _aligned_malloc(sizeof(Vertex) * countof(m_v), 16); + + for(int i = 0; i < countof(m_v); i++) + { + m_v[i] = &((Vertex*)m_base)[i]; + } + } + + virtual ~GSVertexList() + { + _aligned_free(m_base); + } + + void RemoveAll() + { + m_count = 0; + } + + __forceinline Vertex& AddTail() + { + ASSERT(m_count < 3); + + return *m_v[m_count++]; + } + + __forceinline void RemoveAt(int pos, int keep) + { + if(keep == 1) + { + Vertex* tmp = m_v[pos + 0]; + m_v[pos + 0] = m_v[pos + 1]; + m_v[pos + 1] = tmp; + } + else if(keep == 2) + { + Vertex* tmp = m_v[pos + 0]; + m_v[pos + 0] = m_v[pos + 1]; + m_v[pos + 1] = m_v[pos + 2]; + m_v[pos + 2] = tmp; + } + + m_count = pos + keep; + } + + __forceinline void GetAt(int i, Vertex& v) + { + v = *m_v[i]; + } + + DWORD GetCount() + { + return m_count; + } +}; diff --git a/plugins/GSdx/GSVertexSW.h b/plugins/GSdx/GSVertexSW.h index f29481b51c..cc4613b5df 100644 --- a/plugins/GSdx/GSVertexSW.h +++ b/plugins/GSdx/GSVertexSW.h @@ -1,254 +1,254 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#include "GSVector.h" - -__declspec(align(16)) union GSVertexSW -{ - struct {GSVector4 c, p, t;}; - struct {GSVector4 v[3];}; - struct {float f[12];}; - - GSVertexSW() {} - GSVertexSW(const GSVertexSW& v) {*this = v;} - - void operator = (const GSVertexSW& v) {c = v.c; p = v.p; t = v.t;} - void operator += (const GSVertexSW& v) {c += v.c; p += v.p; t += v.t;} - - friend GSVertexSW operator + (const GSVertexSW& v1, const GSVertexSW& v2); - friend GSVertexSW operator - (const GSVertexSW& v1, const GSVertexSW& v2); - friend GSVertexSW operator * (const GSVertexSW& v, const GSVector4& vv); - friend GSVertexSW operator / (const GSVertexSW& v, const GSVector4& vv); - friend GSVertexSW operator * (const GSVertexSW& v, float f); - friend GSVertexSW operator / (const GSVertexSW& v, float f); - - static bool IsQuad(const GSVertexSW* v, int& tl, int& br) - { - GSVector4 v0 = v[0].p.xyxy(v[0].t); - GSVector4 v1 = v[1].p.xyxy(v[1].t); - GSVector4 v2 = v[2].p.xyxy(v[2].t); - - GSVector4 v01 = v0 == v1; - GSVector4 v12 = v1 == v2; - GSVector4 v02 = v0 == v2; - - GSVector4 vtl, vbr; - - GSVector4 test; - - int i; - - if(v12.allfalse()) - { - test = (v01 ^ v02) & (v01 ^ v02.zwxy()); - vtl = v0; - vbr = v1 + (v2 - v0); - i = 0; - } - else if(v02.allfalse()) - { - test = (v01 ^ v12) & (v01 ^ v12.zwxy()); - vtl = v1; - vbr = v0 + (v2 - v1); - i = 1; - } - else if(v01.allfalse()) - { - test = (v02 ^ v12) & (v02 ^ v12.zwxy()); - vtl = v2; - vbr = v0 + (v1 - v2); - i = 2; - } - else - { - return false; - } - - if(!test.alltrue()) - { - return false; - } - - tl = i; - - GSVector4 v3 = v[3].p.xyxy(v[3].t); - GSVector4 v4 = v[4].p.xyxy(v[4].t); - GSVector4 v5 = v[5].p.xyxy(v[5].t); - - GSVector4 v34 = v3 == v4; - GSVector4 v45 = v4 == v5; - GSVector4 v35 = v3 == v5; - - if(v34.allfalse()) - { - test = (v35 ^ v45) & (v35 ^ v45.zwxy()) & (vtl == v3 + (v4 - v5)) & (vbr == v5); - i = 5; - } - else if(v35.allfalse()) - { - test = (v34 ^ v45) & (v34 ^ v45.zwxy()) & (vtl == v3 + (v5 - v4)) & (vbr == v4); - i = 4; - } - else if(v45.allfalse()) - { - test = (v34 ^ v35) & (v34 ^ v35.zwxy()) & (vtl == v5 + (v4 - v3)) & (vbr == v3); - i = 3; - } - else - { - return false; - } - - if(!test.alltrue()) - { - return false; - } - - br = i; - - v0 = v[0].p.zwzw(v[0].t); - v1 = v[1].p.zwzw(v[1].t); - v2 = v[2].p.zwzw(v[2].t); - v3 = v[3].p.zwzw(v[3].t); - v4 = v[4].p.zwzw(v[4].t); - v5 = v[5].p.zwzw(v[5].t); - - test = ((v0 == v1) & (v0 == v2)) & ((v0 == v3) & (v0 == v4)) & (v0 == v5); - - if(!test.alltrue()) - { - return false; - } - - v0 = v[0].c; - v1 = v[1].c; - v2 = v[2].c; - v3 = v[3].c; - v4 = v[4].c; - v5 = v[5].c; - - test = ((v0 == v1) & (v0 == v2)) & ((v0 == v3) & (v0 == v4)) & (v0 == v5); - - if(!test.alltrue()) - { - return false; - } - - return true; - } -}; - -__forceinline GSVertexSW operator + (const GSVertexSW& v1, const GSVertexSW& v2) -{ - GSVertexSW v0; - v0.c = v1.c + v2.c; - v0.p = v1.p + v2.p; - v0.t = v1.t + v2.t; - return v0; -} - -__forceinline GSVertexSW operator - (const GSVertexSW& v1, const GSVertexSW& v2) -{ - GSVertexSW v0; - v0.c = v1.c - v2.c; - v0.p = v1.p - v2.p; - v0.t = v1.t - v2.t; - return v0; -} - -__forceinline GSVertexSW operator * (const GSVertexSW& v, const GSVector4& vv) -{ - GSVertexSW v0; - v0.c = v.c * vv; - v0.p = v.p * vv; - v0.t = v.t * vv; - return v0; -} - -__forceinline GSVertexSW operator / (const GSVertexSW& v, const GSVector4& vv) -{ - GSVertexSW v0; - v0.c = v.c / vv; - v0.p = v.p / vv; - v0.t = v.t / vv; - return v0; -} - -__forceinline GSVertexSW operator * (const GSVertexSW& v, float f) -{ - GSVertexSW v0; - GSVector4 vf(f); - v0.c = v.c * vf; - v0.p = v.p * vf; - v0.t = v.t * vf; - return v0; -} - -__forceinline GSVertexSW operator / (const GSVertexSW& v, float f) -{ - GSVertexSW v0; - GSVector4 vf(f); - v0.c = v.c / vf; - v0.p = v.p / vf; - v0.t = v.t / vf; - return v0; -} - -__declspec(align(16)) struct GSVertexTrace -{ - GSVertexSW m_min, m_max; - - union - { - DWORD value; - struct {DWORD x:1, y:1, z:1, f:1, s:1, t:1, q:1, _pad:1, r:1, g:1, b:1, a:1;}; - struct {DWORD xyzf:4, stq:4, rgba:4;}; - } m_eq; - - void Update(const GSVertexSW* v, int count) - { - GSVertexSW min, max; - - min.p = v[0].p; - max.p = v[0].p; - min.t = v[0].t; - max.t = v[0].t; - min.c = v[0].c; - max.c = v[0].c; - - for(int i = 1; i < count; i++) - { - min.c = min.c.minv(v[i].c); - max.c = max.c.maxv(v[i].c); - min.p = min.p.minv(v[i].p); - max.p = max.p.maxv(v[i].p); - min.t = min.t.minv(v[i].t); - max.t = max.t.maxv(v[i].t); - } - - m_min = min; - m_max = max; - - m_eq.value = (min.p == max.p).mask() | ((min.t == max.t).mask() << 4) | ((min.c == max.c).mask() << 8); - } -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSVector.h" + +__declspec(align(16)) union GSVertexSW +{ + struct {GSVector4 c, p, t;}; + struct {GSVector4 v[3];}; + struct {float f[12];}; + + GSVertexSW() {} + GSVertexSW(const GSVertexSW& v) {*this = v;} + + void operator = (const GSVertexSW& v) {c = v.c; p = v.p; t = v.t;} + void operator += (const GSVertexSW& v) {c += v.c; p += v.p; t += v.t;} + + friend GSVertexSW operator + (const GSVertexSW& v1, const GSVertexSW& v2); + friend GSVertexSW operator - (const GSVertexSW& v1, const GSVertexSW& v2); + friend GSVertexSW operator * (const GSVertexSW& v, const GSVector4& vv); + friend GSVertexSW operator / (const GSVertexSW& v, const GSVector4& vv); + friend GSVertexSW operator * (const GSVertexSW& v, float f); + friend GSVertexSW operator / (const GSVertexSW& v, float f); + + static bool IsQuad(const GSVertexSW* v, int& tl, int& br) + { + GSVector4 v0 = v[0].p.xyxy(v[0].t); + GSVector4 v1 = v[1].p.xyxy(v[1].t); + GSVector4 v2 = v[2].p.xyxy(v[2].t); + + GSVector4 v01 = v0 == v1; + GSVector4 v12 = v1 == v2; + GSVector4 v02 = v0 == v2; + + GSVector4 vtl, vbr; + + GSVector4 test; + + int i; + + if(v12.allfalse()) + { + test = (v01 ^ v02) & (v01 ^ v02.zwxy()); + vtl = v0; + vbr = v1 + (v2 - v0); + i = 0; + } + else if(v02.allfalse()) + { + test = (v01 ^ v12) & (v01 ^ v12.zwxy()); + vtl = v1; + vbr = v0 + (v2 - v1); + i = 1; + } + else if(v01.allfalse()) + { + test = (v02 ^ v12) & (v02 ^ v12.zwxy()); + vtl = v2; + vbr = v0 + (v1 - v2); + i = 2; + } + else + { + return false; + } + + if(!test.alltrue()) + { + return false; + } + + tl = i; + + GSVector4 v3 = v[3].p.xyxy(v[3].t); + GSVector4 v4 = v[4].p.xyxy(v[4].t); + GSVector4 v5 = v[5].p.xyxy(v[5].t); + + GSVector4 v34 = v3 == v4; + GSVector4 v45 = v4 == v5; + GSVector4 v35 = v3 == v5; + + if(v34.allfalse()) + { + test = (v35 ^ v45) & (v35 ^ v45.zwxy()) & (vtl == v3 + (v4 - v5)) & (vbr == v5); + i = 5; + } + else if(v35.allfalse()) + { + test = (v34 ^ v45) & (v34 ^ v45.zwxy()) & (vtl == v3 + (v5 - v4)) & (vbr == v4); + i = 4; + } + else if(v45.allfalse()) + { + test = (v34 ^ v35) & (v34 ^ v35.zwxy()) & (vtl == v5 + (v4 - v3)) & (vbr == v3); + i = 3; + } + else + { + return false; + } + + if(!test.alltrue()) + { + return false; + } + + br = i; + + v0 = v[0].p.zwzw(v[0].t); + v1 = v[1].p.zwzw(v[1].t); + v2 = v[2].p.zwzw(v[2].t); + v3 = v[3].p.zwzw(v[3].t); + v4 = v[4].p.zwzw(v[4].t); + v5 = v[5].p.zwzw(v[5].t); + + test = ((v0 == v1) & (v0 == v2)) & ((v0 == v3) & (v0 == v4)) & (v0 == v5); + + if(!test.alltrue()) + { + return false; + } + + v0 = v[0].c; + v1 = v[1].c; + v2 = v[2].c; + v3 = v[3].c; + v4 = v[4].c; + v5 = v[5].c; + + test = ((v0 == v1) & (v0 == v2)) & ((v0 == v3) & (v0 == v4)) & (v0 == v5); + + if(!test.alltrue()) + { + return false; + } + + return true; + } +}; + +__forceinline GSVertexSW operator + (const GSVertexSW& v1, const GSVertexSW& v2) +{ + GSVertexSW v0; + v0.c = v1.c + v2.c; + v0.p = v1.p + v2.p; + v0.t = v1.t + v2.t; + return v0; +} + +__forceinline GSVertexSW operator - (const GSVertexSW& v1, const GSVertexSW& v2) +{ + GSVertexSW v0; + v0.c = v1.c - v2.c; + v0.p = v1.p - v2.p; + v0.t = v1.t - v2.t; + return v0; +} + +__forceinline GSVertexSW operator * (const GSVertexSW& v, const GSVector4& vv) +{ + GSVertexSW v0; + v0.c = v.c * vv; + v0.p = v.p * vv; + v0.t = v.t * vv; + return v0; +} + +__forceinline GSVertexSW operator / (const GSVertexSW& v, const GSVector4& vv) +{ + GSVertexSW v0; + v0.c = v.c / vv; + v0.p = v.p / vv; + v0.t = v.t / vv; + return v0; +} + +__forceinline GSVertexSW operator * (const GSVertexSW& v, float f) +{ + GSVertexSW v0; + GSVector4 vf(f); + v0.c = v.c * vf; + v0.p = v.p * vf; + v0.t = v.t * vf; + return v0; +} + +__forceinline GSVertexSW operator / (const GSVertexSW& v, float f) +{ + GSVertexSW v0; + GSVector4 vf(f); + v0.c = v.c / vf; + v0.p = v.p / vf; + v0.t = v.t / vf; + return v0; +} + +__declspec(align(16)) struct GSVertexTrace +{ + GSVertexSW m_min, m_max; + + union + { + DWORD value; + struct {DWORD x:1, y:1, z:1, f:1, s:1, t:1, q:1, _pad:1, r:1, g:1, b:1, a:1;}; + struct {DWORD xyzf:4, stq:4, rgba:4;}; + } m_eq; + + void Update(const GSVertexSW* v, int count) + { + GSVertexSW min, max; + + min.p = v[0].p; + max.p = v[0].p; + min.t = v[0].t; + max.t = v[0].t; + min.c = v[0].c; + max.c = v[0].c; + + for(int i = 1; i < count; i++) + { + min.c = min.c.minv(v[i].c); + max.c = max.c.maxv(v[i].c); + min.p = min.p.minv(v[i].p); + max.p = max.p.maxv(v[i].p); + min.t = min.t.minv(v[i].t); + max.t = max.t.maxv(v[i].t); + } + + m_min = min; + m_max = max; + + m_eq.value = (min.p == max.p).mask() | ((min.t == max.t).mask() << 4) | ((min.c == max.c).mask() << 8); + } +}; diff --git a/plugins/GSdx/GSWnd.cpp b/plugins/GSdx/GSWnd.cpp index 6c716fbd8f..f2d195a99c 100644 --- a/plugins/GSdx/GSWnd.cpp +++ b/plugins/GSdx/GSWnd.cpp @@ -1,76 +1,76 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "StdAfx.h" -#include "GSWnd.h" - -BEGIN_MESSAGE_MAP(GSWnd, CWnd) - ON_WM_CLOSE() -END_MESSAGE_MAP() - -GSWnd::GSWnd() -{ -} - -GSWnd::~GSWnd() -{ - DestroyWindow(); -} - -bool GSWnd::Create(LPCTSTR title) -{ - CRect r; - - GetDesktopWindow()->GetWindowRect(r); - - CSize s(r.Width() / 3, r.Width() / 4); - - if(!GetSystemMetrics(SM_REMOTESESSION)) - { - s.cx *= 2; - s.cy *= 2; - } - - r = CRect(r.CenterPoint() - CSize(s.cx / 2, s.cy / 2), s); - - LPCTSTR wc = AfxRegisterWndClass(CS_VREDRAW|CS_HREDRAW|CS_DBLCLKS, AfxGetApp()->LoadStandardCursor(IDC_ARROW), 0, 0); - - return !!CreateEx(0, wc, title, WS_OVERLAPPEDWINDOW, r, NULL, 0); -} - -void GSWnd::Show() -{ - SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); - SetForegroundWindow(); - ShowWindow(SW_SHOWNORMAL); -} - -void GSWnd::Hide() -{ - ShowWindow(SW_HIDE); -} - -void GSWnd::OnClose() -{ - Hide(); - - PostMessage(WM_QUIT); +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "StdAfx.h" +#include "GSWnd.h" + +BEGIN_MESSAGE_MAP(GSWnd, CWnd) + ON_WM_CLOSE() +END_MESSAGE_MAP() + +GSWnd::GSWnd() +{ +} + +GSWnd::~GSWnd() +{ + DestroyWindow(); +} + +bool GSWnd::Create(LPCTSTR title) +{ + CRect r; + + GetDesktopWindow()->GetWindowRect(r); + + CSize s(r.Width() / 3, r.Width() / 4); + + if(!GetSystemMetrics(SM_REMOTESESSION)) + { + s.cx *= 2; + s.cy *= 2; + } + + r = CRect(r.CenterPoint() - CSize(s.cx / 2, s.cy / 2), s); + + LPCTSTR wc = AfxRegisterWndClass(CS_VREDRAW|CS_HREDRAW|CS_DBLCLKS, AfxGetApp()->LoadStandardCursor(IDC_ARROW), 0, 0); + + return !!CreateEx(0, wc, title, WS_OVERLAPPEDWINDOW, r, NULL, 0); +} + +void GSWnd::Show() +{ + SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); + SetForegroundWindow(); + ShowWindow(SW_SHOWNORMAL); +} + +void GSWnd::Hide() +{ + ShowWindow(SW_HIDE); +} + +void GSWnd::OnClose() +{ + Hide(); + + PostMessage(WM_QUIT); } \ No newline at end of file diff --git a/plugins/GSdx/GSWnd.h b/plugins/GSdx/GSWnd.h index 27a9773521..aa76393b6f 100644 --- a/plugins/GSdx/GSWnd.h +++ b/plugins/GSdx/GSWnd.h @@ -1,37 +1,37 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -class GSWnd : public CWnd -{ - DECLARE_MESSAGE_MAP() - -public: - GSWnd(); - virtual ~GSWnd(); - - virtual bool Create(LPCTSTR title); - - void Show(); - void Hide(); - void OnClose(); -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +class GSWnd : public CWnd +{ + DECLARE_MESSAGE_MAP() + +public: + GSWnd(); + virtual ~GSWnd(); + + virtual bool Create(LPCTSTR title); + + void Show(); + void Hide(); + void OnClose(); +}; diff --git a/plugins/GSdx/GSdx.cpp b/plugins/GSdx/GSdx.cpp index e20ebb5548..799d55ea5c 100644 --- a/plugins/GSdx/GSdx.cpp +++ b/plugins/GSdx/GSdx.cpp @@ -1,97 +1,97 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "GSdx.h" - -// -// Note! -// -// If this DLL is dynamically linked against the MFC -// DLLs, any functions exported from this DLL which -// call into MFC must have the AFX_MANAGE_STATE macro -// added at the very beginning of the function. -// -// For example: -// -// extern "C" BOOL PASCAL EXPORT ExportedFunction() -// { -// AFX_MANAGE_STATE(AfxGetStaticModuleState()); -// // normal function body here -// } -// -// It is very important that this macro appear in each -// function, prior to any calls into MFC. This means that -// it must appear as the first statement within the -// function, even before any object variable declarations -// as their constructors may generate calls into the MFC -// DLL. -// -// Please see MFC Technical Notes 33 and 58 for additional -// details. -// - -BEGIN_MESSAGE_MAP(GSdxApp, CWinApp) -END_MESSAGE_MAP() - -GSdxApp::GSdxApp() -{ -} - -GSdxApp theApp; - -BOOL GSdxApp::InitInstance() -{ - __super::InitInstance(); - - SetRegistryKey(_T("Gabest")); - - CString str; - GetModuleFileName(AfxGetInstanceHandle(), str.GetBuffer(MAX_PATH), MAX_PATH); - str.ReleaseBuffer(); - - CPath path(str); - path.RenameExtension(_T(".ini")); - - CPath fn = path; - fn.StripPath(); - - path.RemoveFileSpec(); - path.Append(_T("..\\inis")); - CreateDirectory(path, NULL); - path.Append(fn); - - if(m_pszRegistryKey) - { - free((void*)m_pszRegistryKey); - } - - m_pszRegistryKey = NULL; - - if(m_pszProfileName) - { - free((void*)m_pszProfileName); - } - - m_pszProfileName = _tcsdup((LPCTSTR)path); - - return TRUE; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSdx.h" + +// +// Note! +// +// If this DLL is dynamically linked against the MFC +// DLLs, any functions exported from this DLL which +// call into MFC must have the AFX_MANAGE_STATE macro +// added at the very beginning of the function. +// +// For example: +// +// extern "C" BOOL PASCAL EXPORT ExportedFunction() +// { +// AFX_MANAGE_STATE(AfxGetStaticModuleState()); +// // normal function body here +// } +// +// It is very important that this macro appear in each +// function, prior to any calls into MFC. This means that +// it must appear as the first statement within the +// function, even before any object variable declarations +// as their constructors may generate calls into the MFC +// DLL. +// +// Please see MFC Technical Notes 33 and 58 for additional +// details. +// + +BEGIN_MESSAGE_MAP(GSdxApp, CWinApp) +END_MESSAGE_MAP() + +GSdxApp::GSdxApp() +{ +} + +GSdxApp theApp; + +BOOL GSdxApp::InitInstance() +{ + __super::InitInstance(); + + SetRegistryKey(_T("Gabest")); + + CString str; + GetModuleFileName(AfxGetInstanceHandle(), str.GetBuffer(MAX_PATH), MAX_PATH); + str.ReleaseBuffer(); + + CPath path(str); + path.RenameExtension(_T(".ini")); + + CPath fn = path; + fn.StripPath(); + + path.RemoveFileSpec(); + path.Append(_T("..\\inis")); + CreateDirectory(path, NULL); + path.Append(fn); + + if(m_pszRegistryKey) + { + free((void*)m_pszRegistryKey); + } + + m_pszRegistryKey = NULL; + + if(m_pszProfileName) + { + free((void*)m_pszProfileName); + } + + m_pszProfileName = _tcsdup((LPCTSTR)path); + + return TRUE; } \ No newline at end of file diff --git a/plugins/GSdx/GSdx.h b/plugins/GSdx/GSdx.h index c1ba09a618..5d3be89e27 100644 --- a/plugins/GSdx/GSdx.h +++ b/plugins/GSdx/GSdx.h @@ -1,37 +1,37 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#ifndef __AFXWIN_H__ - #error include 'stdafx.h' before including this file for PCH -#endif - -class GSdxApp : public CWinApp -{ -public: - GSdxApp(); - -public: - virtual BOOL InitInstance(); - - DECLARE_MESSAGE_MAP() -}; +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +class GSdxApp : public CWinApp +{ +public: + GSdxApp(); + +public: + virtual BOOL InitInstance(); + + DECLARE_MESSAGE_MAP() +}; diff --git a/plugins/GSdx/baseclasses/amextra.cpp b/plugins/GSdx/baseclasses/amextra.cpp index 3330bd74af..7722d60a2d 100644 --- a/plugins/GSdx/baseclasses/amextra.cpp +++ b/plugins/GSdx/baseclasses/amextra.cpp @@ -1,111 +1,111 @@ -//------------------------------------------------------------------------------ -// File: AMExtra.cpp -// -// Desc: DirectShow base classes - implements CRenderedInputPin class. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" // DirectShow base class definitions -#include // Needed for definition of timeGetTime -#include // Standard data type limit definitions -#include "measure.h" // Used for time critical log functions - -#include "amextra.h" - -#pragma warning(disable:4355) - -// Implements CRenderedInputPin class - -CRenderedInputPin::CRenderedInputPin(TCHAR *pObjectName, - CBaseFilter *pFilter, - CCritSec *pLock, - HRESULT *phr, - LPCWSTR pName) : - CBaseInputPin(pObjectName, pFilter, pLock, phr, pName), - m_bAtEndOfStream(FALSE), - m_bCompleteNotified(FALSE) -{ -} -#ifdef UNICODE -CRenderedInputPin::CRenderedInputPin(CHAR *pObjectName, - CBaseFilter *pFilter, - CCritSec *pLock, - HRESULT *phr, - LPCWSTR pName) : - CBaseInputPin(pObjectName, pFilter, pLock, phr, pName), - m_bAtEndOfStream(FALSE), - m_bCompleteNotified(FALSE) -{ -} -#endif - -// Flush end of stream condition - caller should do any -// necessary stream level locking before calling this - -STDMETHODIMP CRenderedInputPin::EndOfStream() -{ - HRESULT hr = CheckStreaming(); - - // Do EC_COMPLETE handling for rendered pins - if (S_OK == hr && !m_bAtEndOfStream) { - m_bAtEndOfStream = TRUE; - FILTER_STATE fs; - EXECUTE_ASSERT(SUCCEEDED(m_pFilter->GetState(0, &fs))); - if (fs == State_Running) { - DoCompleteHandling(); - } - } - return hr; -} - - -// Called to complete the flush - -STDMETHODIMP CRenderedInputPin::EndFlush() -{ - CAutoLock lck(m_pLock); - - // Clean up renderer state - m_bAtEndOfStream = FALSE; - m_bCompleteNotified = FALSE; - - return CBaseInputPin::EndFlush(); -} - - -// Notify of Run() from filter - -HRESULT CRenderedInputPin::Run(REFERENCE_TIME tStart) -{ - UNREFERENCED_PARAMETER(tStart); - m_bCompleteNotified = FALSE; - if (m_bAtEndOfStream) { - DoCompleteHandling(); - } - return S_OK; -} - - -// Clear status on going into paused state - -HRESULT CRenderedInputPin::Active() -{ - m_bAtEndOfStream = FALSE; - m_bCompleteNotified = FALSE; - return CBaseInputPin::Active(); -} - - -// Do stuff to deliver end of stream - -void CRenderedInputPin::DoCompleteHandling() -{ - ASSERT(m_bAtEndOfStream); - if (!m_bCompleteNotified) { - m_bCompleteNotified = TRUE; - m_pFilter->NotifyEvent(EC_COMPLETE, S_OK, (LONG_PTR)(IBaseFilter *)m_pFilter); - } -} - +//------------------------------------------------------------------------------ +// File: AMExtra.cpp +// +// Desc: DirectShow base classes - implements CRenderedInputPin class. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" // DirectShow base class definitions +#include // Needed for definition of timeGetTime +#include // Standard data type limit definitions +#include "measure.h" // Used for time critical log functions + +#include "amextra.h" + +#pragma warning(disable:4355) + +// Implements CRenderedInputPin class + +CRenderedInputPin::CRenderedInputPin(TCHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName) : + CBaseInputPin(pObjectName, pFilter, pLock, phr, pName), + m_bAtEndOfStream(FALSE), + m_bCompleteNotified(FALSE) +{ +} +#ifdef UNICODE +CRenderedInputPin::CRenderedInputPin(CHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName) : + CBaseInputPin(pObjectName, pFilter, pLock, phr, pName), + m_bAtEndOfStream(FALSE), + m_bCompleteNotified(FALSE) +{ +} +#endif + +// Flush end of stream condition - caller should do any +// necessary stream level locking before calling this + +STDMETHODIMP CRenderedInputPin::EndOfStream() +{ + HRESULT hr = CheckStreaming(); + + // Do EC_COMPLETE handling for rendered pins + if (S_OK == hr && !m_bAtEndOfStream) { + m_bAtEndOfStream = TRUE; + FILTER_STATE fs; + EXECUTE_ASSERT(SUCCEEDED(m_pFilter->GetState(0, &fs))); + if (fs == State_Running) { + DoCompleteHandling(); + } + } + return hr; +} + + +// Called to complete the flush + +STDMETHODIMP CRenderedInputPin::EndFlush() +{ + CAutoLock lck(m_pLock); + + // Clean up renderer state + m_bAtEndOfStream = FALSE; + m_bCompleteNotified = FALSE; + + return CBaseInputPin::EndFlush(); +} + + +// Notify of Run() from filter + +HRESULT CRenderedInputPin::Run(REFERENCE_TIME tStart) +{ + UNREFERENCED_PARAMETER(tStart); + m_bCompleteNotified = FALSE; + if (m_bAtEndOfStream) { + DoCompleteHandling(); + } + return S_OK; +} + + +// Clear status on going into paused state + +HRESULT CRenderedInputPin::Active() +{ + m_bAtEndOfStream = FALSE; + m_bCompleteNotified = FALSE; + return CBaseInputPin::Active(); +} + + +// Do stuff to deliver end of stream + +void CRenderedInputPin::DoCompleteHandling() +{ + ASSERT(m_bAtEndOfStream); + if (!m_bCompleteNotified) { + m_bCompleteNotified = TRUE; + m_pFilter->NotifyEvent(EC_COMPLETE, S_OK, (LONG_PTR)(IBaseFilter *)m_pFilter); + } +} + diff --git a/plugins/GSdx/baseclasses/amextra.h b/plugins/GSdx/baseclasses/amextra.h index ddb067ffcf..a0f021fa43 100644 --- a/plugins/GSdx/baseclasses/amextra.h +++ b/plugins/GSdx/baseclasses/amextra.h @@ -1,56 +1,56 @@ -//------------------------------------------------------------------------------ -// File: AMExtra.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __AMEXTRA__ -#define __AMEXTRA__ - -// Simple rendered input pin -// -// NOTE if your filter queues stuff before rendering then it may not be -// appropriate to use this class -// -// In that case queue the end of stream condition until the last sample -// is actually rendered and flush the condition appropriately - -class CRenderedInputPin : public CBaseInputPin -{ -public: - - CRenderedInputPin(TCHAR *pObjectName, - CBaseFilter *pFilter, - CCritSec *pLock, - HRESULT *phr, - LPCWSTR pName); -#ifdef UNICODE - CRenderedInputPin(CHAR *pObjectName, - CBaseFilter *pFilter, - CCritSec *pLock, - HRESULT *phr, - LPCWSTR pName); -#endif - - // Override methods to track end of stream state - STDMETHODIMP EndOfStream(); - STDMETHODIMP EndFlush(); - - HRESULT Active(); - HRESULT Run(REFERENCE_TIME tStart); - -protected: - - // Member variables to track state - BOOL m_bAtEndOfStream; // Set by EndOfStream - BOOL m_bCompleteNotified; // Set when we notify for EC_COMPLETE - -private: - void DoCompleteHandling(); -}; - -#endif // __AMEXTRA__ - +//------------------------------------------------------------------------------ +// File: AMExtra.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __AMEXTRA__ +#define __AMEXTRA__ + +// Simple rendered input pin +// +// NOTE if your filter queues stuff before rendering then it may not be +// appropriate to use this class +// +// In that case queue the end of stream condition until the last sample +// is actually rendered and flush the condition appropriately + +class CRenderedInputPin : public CBaseInputPin +{ +public: + + CRenderedInputPin(TCHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName); +#ifdef UNICODE + CRenderedInputPin(CHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName); +#endif + + // Override methods to track end of stream state + STDMETHODIMP EndOfStream(); + STDMETHODIMP EndFlush(); + + HRESULT Active(); + HRESULT Run(REFERENCE_TIME tStart); + +protected: + + // Member variables to track state + BOOL m_bAtEndOfStream; // Set by EndOfStream + BOOL m_bCompleteNotified; // Set when we notify for EC_COMPLETE + +private: + void DoCompleteHandling(); +}; + +#endif // __AMEXTRA__ + diff --git a/plugins/GSdx/baseclasses/amfilter.cpp b/plugins/GSdx/baseclasses/amfilter.cpp index 112dba97c1..0241a022e7 100644 --- a/plugins/GSdx/baseclasses/amfilter.cpp +++ b/plugins/GSdx/baseclasses/amfilter.cpp @@ -1,5203 +1,5203 @@ -//------------------------------------------------------------------------------ -// File: AMFilter.cpp -// -// Desc: DirectShow base classes - implements class hierarchy for streams -// architecture. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -//===================================================================== -//===================================================================== -// The following classes are declared in this header: -// -// -// CBaseMediaFilter Basic IMediaFilter support (abstract class) -// CBaseFilter Support for IBaseFilter (incl. IMediaFilter) -// CEnumPins Enumerate input and output pins -// CEnumMediaTypes Enumerate the preferred pin formats -// CBasePin Abstract base class for IPin interface -// CBaseOutputPin Adds data provider member functions -// CBaseInputPin Implements IMemInputPin interface -// CMediaSample Basic transport unit for IMemInputPin -// CBaseAllocator General list guff for most allocators -// CMemAllocator Implements memory buffer allocation -// -//===================================================================== -//===================================================================== - -#include "streams.h" - - - -//===================================================================== -// Helpers -//===================================================================== -STDAPI CreateMemoryAllocator(IMemAllocator **ppAllocator) -{ - return CoCreateInstance(CLSID_MemoryAllocator, - 0, - CLSCTX_INPROC_SERVER, - IID_IMemAllocator, - (void **)ppAllocator); -} - -// Put this one here rather than in ctlutil.cpp to avoid linking -// anything brought in by ctlutil.cpp -STDAPI CreatePosPassThru( - LPUNKNOWN pAgg, - BOOL bRenderer, - IPin *pPin, - IUnknown **ppPassThru -) -{ - *ppPassThru = NULL; - IUnknown *pUnkSeek; - HRESULT hr = CoCreateInstance(CLSID_SeekingPassThru, - pAgg, - CLSCTX_INPROC_SERVER, - IID_IUnknown, - (void **)&pUnkSeek - ); - if (FAILED(hr)) { - return hr; - } - - ISeekingPassThru *pPassThru; - hr = pUnkSeek->QueryInterface(IID_ISeekingPassThru, (void**)&pPassThru); - if (FAILED(hr)) { - pUnkSeek->Release(); - return hr; - } - hr = pPassThru->Init(bRenderer, pPin); - pPassThru->Release(); - if (FAILED(hr)) { - pUnkSeek->Release(); - return hr; - } - *ppPassThru = pUnkSeek; - return S_OK; -} - - - -#define CONNECT_TRACE_LEVEL 3 - -//===================================================================== -//===================================================================== -// Implements CBaseMediaFilter -//===================================================================== -//===================================================================== - - -/* Constructor */ - -CBaseMediaFilter::CBaseMediaFilter(const TCHAR *pName, - LPUNKNOWN pUnk, - CCritSec *pLock, - REFCLSID clsid) : - CUnknown(pName, pUnk), - m_pLock(pLock), - m_clsid(clsid), - m_State(State_Stopped), - m_pClock(NULL) -{ -} - - -/* Destructor */ - -CBaseMediaFilter::~CBaseMediaFilter() -{ - // must be stopped, but can't call Stop here since - // our critsec has been destroyed. - - /* Release any clock we were using */ - - if (m_pClock) { - m_pClock->Release(); - m_pClock = NULL; - } -} - - -/* Override this to say what interfaces we support and where */ - -STDMETHODIMP -CBaseMediaFilter::NonDelegatingQueryInterface( - REFIID riid, - void ** ppv) -{ - if (riid == IID_IMediaFilter) { - return GetInterface((IMediaFilter *) this, ppv); - } else if (riid == IID_IPersist) { - return GetInterface((IPersist *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - -/* Return the filter's clsid */ -STDMETHODIMP -CBaseMediaFilter::GetClassID(CLSID *pClsID) -{ - CheckPointer(pClsID,E_POINTER); - ValidateReadWritePtr(pClsID,sizeof(CLSID)); - *pClsID = m_clsid; - return NOERROR; -} - -/* Override this if your state changes are not done synchronously */ - -STDMETHODIMP -CBaseMediaFilter::GetState(DWORD dwMSecs, FILTER_STATE *State) -{ - UNREFERENCED_PARAMETER(dwMSecs); - CheckPointer(State,E_POINTER); - ValidateReadWritePtr(State,sizeof(FILTER_STATE)); - - *State = m_State; - return S_OK; -} - - -/* Set the clock we will use for synchronisation */ - -STDMETHODIMP -CBaseMediaFilter::SetSyncSource(IReferenceClock *pClock) -{ - CAutoLock cObjectLock(m_pLock); - - // Ensure the new one does not go away - even if the same as the old - if (pClock) { - pClock->AddRef(); - } - - // if we have a clock, release it - if (m_pClock) { - m_pClock->Release(); - } - - // Set the new reference clock (might be NULL) - // Should we query it to ensure it is a clock? Consider for a debug build. - m_pClock = pClock; - - return NOERROR; -} - -/* Return the clock we are using for synchronisation */ -STDMETHODIMP -CBaseMediaFilter::GetSyncSource(IReferenceClock **pClock) -{ - CheckPointer(pClock,E_POINTER); - ValidateReadWritePtr(pClock,sizeof(IReferenceClock *)); - CAutoLock cObjectLock(m_pLock); - - if (m_pClock) { - // returning an interface... addref it... - m_pClock->AddRef(); - } - *pClock = (IReferenceClock*)m_pClock; - return NOERROR; -} - - -/* Put the filter into a stopped state */ - -STDMETHODIMP -CBaseMediaFilter::Stop() -{ - CAutoLock cObjectLock(m_pLock); - - m_State = State_Stopped; - return S_OK; -} - - -/* Put the filter into a paused state */ - -STDMETHODIMP -CBaseMediaFilter::Pause() -{ - CAutoLock cObjectLock(m_pLock); - - m_State = State_Paused; - return S_OK; -} - - -// Put the filter into a running state. - -// The time parameter is the offset to be added to the samples' -// stream time to get the reference time at which they should be presented. -// -// you can either add these two and compare it against the reference clock, -// or you can call CBaseMediaFilter::StreamTime and compare that against -// the sample timestamp. - -STDMETHODIMP -CBaseMediaFilter::Run(REFERENCE_TIME tStart) -{ - CAutoLock cObjectLock(m_pLock); - - // remember the stream time offset - m_tStart = tStart; - - if (m_State == State_Stopped){ - HRESULT hr = Pause(); - - if (FAILED(hr)) { - return hr; - } - } - m_State = State_Running; - return S_OK; -} - - -// -// return the current stream time - samples with start timestamps of this -// time or before should be rendered by now -HRESULT -CBaseMediaFilter::StreamTime(CRefTime& rtStream) -{ - // Caller must lock for synchronization - // We can't grab the filter lock because we want to be able to call - // this from worker threads without deadlocking - - if (m_pClock == NULL) { - return VFW_E_NO_CLOCK; - } - - // get the current reference time - HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream); - if (FAILED(hr)) { - return hr; - } - - // subtract the stream offset to get stream time - rtStream -= m_tStart; - - return S_OK; -} - - -//===================================================================== -//===================================================================== -// Implements CBaseFilter -//===================================================================== -//===================================================================== - - -/* Override this to say what interfaces we support and where */ - -STDMETHODIMP CBaseFilter::NonDelegatingQueryInterface(REFIID riid, - void **ppv) -{ - /* Do we have this interface */ - - if (riid == IID_IBaseFilter) { - return GetInterface((IBaseFilter *) this, ppv); - } else if (riid == IID_IMediaFilter) { - return GetInterface((IMediaFilter *) this, ppv); - } else if (riid == IID_IPersist) { - return GetInterface((IPersist *) this, ppv); - } else if (riid == IID_IAMovieSetup) { - return GetInterface((IAMovieSetup *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - -#ifdef DEBUG -STDMETHODIMP_(ULONG) CBaseFilter::NonDelegatingRelease() -{ - if (m_cRef == 1) { - KASSERT(m_pGraph == NULL); - } - return CUnknown::NonDelegatingRelease(); -} -#endif - - -/* Constructor */ - -CBaseFilter::CBaseFilter(const TCHAR *pName, - LPUNKNOWN pUnk, - CCritSec *pLock, - REFCLSID clsid) : - CUnknown( pName, pUnk ), - m_pLock(pLock), - m_clsid(clsid), - m_State(State_Stopped), - m_pClock(NULL), - m_pGraph(NULL), - m_pSink(NULL), - m_pName(NULL), - m_PinVersion(1) -{ - - ASSERT(pLock != NULL); -} - -/* Passes in a redundant HRESULT argument */ - -CBaseFilter::CBaseFilter(TCHAR *pName, - LPUNKNOWN pUnk, - CCritSec *pLock, - REFCLSID clsid, - HRESULT *phr) : - CUnknown( pName, pUnk ), - m_pLock(pLock), - m_clsid(clsid), - m_State(State_Stopped), - m_pClock(NULL), - m_pGraph(NULL), - m_pSink(NULL), - m_pName(NULL), - m_PinVersion(1) -{ - - ASSERT(pLock != NULL); - UNREFERENCED_PARAMETER(phr); -} - -#ifdef UNICODE -CBaseFilter::CBaseFilter(const CHAR *pName, - LPUNKNOWN pUnk, - CCritSec *pLock, - REFCLSID clsid) : - CUnknown( pName, pUnk ), - m_pLock(pLock), - m_clsid(clsid), - m_State(State_Stopped), - m_pClock(NULL), - m_pGraph(NULL), - m_pSink(NULL), - m_pName(NULL), - m_PinVersion(1) -{ - - ASSERT(pLock != NULL); -} -CBaseFilter::CBaseFilter(CHAR *pName, - LPUNKNOWN pUnk, - CCritSec *pLock, - REFCLSID clsid, - HRESULT *phr) : - CUnknown( pName, pUnk ), - m_pLock(pLock), - m_clsid(clsid), - m_State(State_Stopped), - m_pClock(NULL), - m_pGraph(NULL), - m_pSink(NULL), - m_pName(NULL), - m_PinVersion(1) -{ - - ASSERT(pLock != NULL); - UNREFERENCED_PARAMETER(phr); -} -#endif - -/* Destructor */ - -CBaseFilter::~CBaseFilter() -{ - - // NOTE we do NOT hold references on the filtergraph for m_pGraph or m_pSink - // When we did we had the circular reference problem. Nothing would go away. - - delete[] m_pName; - - // must be stopped, but can't call Stop here since - // our critsec has been destroyed. - - /* Release any clock we were using */ - if (m_pClock) { - m_pClock->Release(); - m_pClock = NULL; - } -} - -/* Return the filter's clsid */ -STDMETHODIMP -CBaseFilter::GetClassID(CLSID *pClsID) -{ - CheckPointer(pClsID,E_POINTER); - ValidateReadWritePtr(pClsID,sizeof(CLSID)); - *pClsID = m_clsid; - return NOERROR; -} - -/* Override this if your state changes are not done synchronously */ -STDMETHODIMP -CBaseFilter::GetState(DWORD dwMSecs, FILTER_STATE *State) -{ - UNREFERENCED_PARAMETER(dwMSecs); - CheckPointer(State,E_POINTER); - ValidateReadWritePtr(State,sizeof(FILTER_STATE)); - - *State = m_State; - return S_OK; -} - - -/* Set the clock we will use for synchronisation */ - -STDMETHODIMP -CBaseFilter::SetSyncSource(IReferenceClock *pClock) -{ - CAutoLock cObjectLock(m_pLock); - - // Ensure the new one does not go away - even if the same as the old - if (pClock) { - pClock->AddRef(); - } - - // if we have a clock, release it - if (m_pClock) { - m_pClock->Release(); - } - - // Set the new reference clock (might be NULL) - // Should we query it to ensure it is a clock? Consider for a debug build. - m_pClock = pClock; - - return NOERROR; -} - -/* Return the clock we are using for synchronisation */ -STDMETHODIMP -CBaseFilter::GetSyncSource(IReferenceClock **pClock) -{ - CheckPointer(pClock,E_POINTER); - ValidateReadWritePtr(pClock,sizeof(IReferenceClock *)); - CAutoLock cObjectLock(m_pLock); - - if (m_pClock) { - // returning an interface... addref it... - m_pClock->AddRef(); - } - *pClock = (IReferenceClock*)m_pClock; - return NOERROR; -} - - - -// override CBaseMediaFilter Stop method, to deactivate any pins this -// filter has. -STDMETHODIMP -CBaseFilter::Stop() -{ - CAutoLock cObjectLock(m_pLock); - HRESULT hr = NOERROR; - - // notify all pins of the state change - if (m_State != State_Stopped) { - int cPins = GetPinCount(); - for (int c = 0; c < cPins; c++) { - - CBasePin *pPin = GetPin(c); - - // Disconnected pins are not activated - this saves pins worrying - // about this state themselves. We ignore the return code to make - // sure everyone is inactivated regardless. The base input pin - // class can return an error if it has no allocator but Stop can - // be used to resync the graph state after something has gone bad - - if (pPin->IsConnected()) { - HRESULT hrTmp = pPin->Inactive(); - if (FAILED(hrTmp) && SUCCEEDED(hr)) { - hr = hrTmp; - } - } - } - } - - - m_State = State_Stopped; - return hr; -} - - -// override CBaseMediaFilter Pause method to activate any pins -// this filter has (also called from Run) - -STDMETHODIMP -CBaseFilter::Pause() -{ - CAutoLock cObjectLock(m_pLock); - - // notify all pins of the change to active state - if (m_State == State_Stopped) { - int cPins = GetPinCount(); - for (int c = 0; c < cPins; c++) { - - CBasePin *pPin = GetPin(c); - - // Disconnected pins are not activated - this saves pins - // worrying about this state themselves - - if (pPin->IsConnected()) { - HRESULT hr = pPin->Active(); - if (FAILED(hr)) { - return hr; - } - } - } - } - - - - m_State = State_Paused; - return S_OK; -} - -// Put the filter into a running state. - -// The time parameter is the offset to be added to the samples' -// stream time to get the reference time at which they should be presented. -// -// you can either add these two and compare it against the reference clock, -// or you can call CBaseFilter::StreamTime and compare that against -// the sample timestamp. - -STDMETHODIMP -CBaseFilter::Run(REFERENCE_TIME tStart) -{ - CAutoLock cObjectLock(m_pLock); - - // remember the stream time offset - m_tStart = tStart; - - if (m_State == State_Stopped){ - HRESULT hr = Pause(); - - if (FAILED(hr)) { - return hr; - } - } - // notify all pins of the change to active state - if (m_State != State_Running) { - int cPins = GetPinCount(); - for (int c = 0; c < cPins; c++) { - - CBasePin *pPin = GetPin(c); - - // Disconnected pins are not activated - this saves pins - // worrying about this state themselves - - if (pPin->IsConnected()) { - HRESULT hr = pPin->Run(tStart); - if (FAILED(hr)) { - return hr; - } - } - } - } - - - m_State = State_Running; - return S_OK; -} - -// -// return the current stream time - samples with start timestamps of this -// time or before should be rendered by now -HRESULT -CBaseFilter::StreamTime(CRefTime& rtStream) -{ - // Caller must lock for synchronization - // We can't grab the filter lock because we want to be able to call - // this from worker threads without deadlocking - - if (m_pClock == NULL) { - return VFW_E_NO_CLOCK; - } - - // get the current reference time - HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream); - if (FAILED(hr)) { - return hr; - } - - // subtract the stream offset to get stream time - rtStream -= m_tStart; - - return S_OK; -} - - -/* Create an enumerator for the pins attached to this filter */ - -STDMETHODIMP -CBaseFilter::EnumPins(IEnumPins **ppEnum) -{ - CheckPointer(ppEnum,E_POINTER); - ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *)); - - /* Create a new ref counted enumerator */ - - *ppEnum = new CEnumPins(this, - NULL); - - return *ppEnum == NULL ? E_OUTOFMEMORY : NOERROR; -} - - -// default behaviour of FindPin is to assume pins are named -// by their pin names -STDMETHODIMP -CBaseFilter::FindPin( - LPCWSTR Id, - IPin ** ppPin -) -{ - CheckPointer(ppPin,E_POINTER); - ValidateReadWritePtr(ppPin,sizeof(IPin *)); - - // We're going to search the pin list so maintain integrity - CAutoLock lck(m_pLock); - int iCount = GetPinCount(); - for (int i = 0; i < iCount; i++) { - CBasePin *pPin = GetPin(i); - ASSERT(pPin != NULL); - - if (0 == lstrcmpW(pPin->Name(), Id)) { - // Found one that matches - // - // AddRef() and return it - *ppPin = pPin; - pPin->AddRef(); - return S_OK; - } - } - *ppPin = NULL; - return VFW_E_NOT_FOUND; -} - -/* Return information about this filter */ - -STDMETHODIMP -CBaseFilter::QueryFilterInfo(FILTER_INFO * pInfo) -{ - CheckPointer(pInfo,E_POINTER); - ValidateReadWritePtr(pInfo,sizeof(FILTER_INFO)); - - if (m_pName) { - lstrcpynW(pInfo->achName, m_pName, sizeof(pInfo->achName)/sizeof(WCHAR)); - } else { - pInfo->achName[0] = L'\0'; - } - pInfo->pGraph = m_pGraph; - if (m_pGraph) - m_pGraph->AddRef(); - return NOERROR; -} - - -/* Provide the filter with a filter graph */ - -STDMETHODIMP -CBaseFilter::JoinFilterGraph( - IFilterGraph * pGraph, - LPCWSTR pName) -{ - CAutoLock cObjectLock(m_pLock); - - // NOTE: we no longer hold references on the graph (m_pGraph, m_pSink) - - m_pGraph = pGraph; - if (m_pGraph) { - HRESULT hr = m_pGraph->QueryInterface(IID_IMediaEventSink, - (void**) &m_pSink); - if (FAILED(hr)) { - ASSERT(m_pSink == NULL); - } - else m_pSink->Release(); // we do NOT keep a reference on it. - } else { - // if graph pointer is null, then we should - // also release the IMediaEventSink on the same object - we don't - // refcount it, so just set it to null - m_pSink = NULL; - } - - - if (m_pName) { - delete[] m_pName; - m_pName = NULL; - } - - if (pName) { - DWORD nameLen = lstrlenW(pName)+1; - m_pName = new WCHAR[nameLen]; - if (m_pName) { - CopyMemory(m_pName, pName, nameLen*sizeof(WCHAR)); - } else { - // !!! error here? - ASSERT(FALSE); - } - } - - - return NOERROR; -} - - -// return a Vendor information string. Optional - may return E_NOTIMPL. -// memory returned should be freed using CoTaskMemFree -// default implementation returns E_NOTIMPL -STDMETHODIMP -CBaseFilter::QueryVendorInfo( - LPWSTR* pVendorInfo) -{ - UNREFERENCED_PARAMETER(pVendorInfo); - return E_NOTIMPL; -} - - -// send an event notification to the filter graph if we know about it. -// returns S_OK if delivered, S_FALSE if the filter graph does not sink -// events, or an error otherwise. -HRESULT -CBaseFilter::NotifyEvent( - long EventCode, - LONG_PTR EventParam1, - LONG_PTR EventParam2) -{ - // Snapshot so we don't have to lock up - IMediaEventSink *pSink = m_pSink; - if (pSink) { - if (EC_COMPLETE == EventCode) { - EventParam2 = (LONG_PTR)(IBaseFilter*)this; - } - - return pSink->Notify(EventCode, EventParam1, EventParam2); - } else { - return E_NOTIMPL; - } -} - -// Request reconnect -// pPin is the pin to reconnect -// pmt is the type to reconnect with - can be NULL -// Calls ReconnectEx on the filter graph -HRESULT -CBaseFilter::ReconnectPin( - IPin *pPin, - AM_MEDIA_TYPE const *pmt -) -{ - IFilterGraph2 *pGraph2; - if (m_pGraph != NULL) { - HRESULT hr = m_pGraph->QueryInterface(IID_IFilterGraph2, (void **)&pGraph2); - if (SUCCEEDED(hr)) { - hr = pGraph2->ReconnectEx(pPin, pmt); - pGraph2->Release(); - return hr; - } else { - return m_pGraph->Reconnect(pPin); - } - } else { - return E_NOINTERFACE; - } -} - - - -/* This is the same idea as the media type version does for type enumeration - on pins but for the list of pins available. So if the list of pins you - provide changes dynamically then either override this virtual function - to provide the version number, or more simply call IncrementPinVersion */ - -LONG CBaseFilter::GetPinVersion() -{ - return m_PinVersion; -} - - -/* Increment the current pin version cookie */ - -void CBaseFilter::IncrementPinVersion() -{ - InterlockedIncrement(&m_PinVersion); -} - -/* register filter */ - -STDMETHODIMP CBaseFilter::Register() -{ - // get setup data, if it exists - // - LPAMOVIESETUP_FILTER psetupdata = GetSetupData(); - - // check we've got data - // - if( NULL == psetupdata ) return S_FALSE; - - // init is ref counted so call just in case - // we're being called cold. - // - HRESULT hr = CoInitialize( (LPVOID)NULL ); - ASSERT( SUCCEEDED(hr) ); - - // get hold of IFilterMapper - // - IFilterMapper *pIFM; - hr = CoCreateInstance( CLSID_FilterMapper - , NULL - , CLSCTX_INPROC_SERVER - , IID_IFilterMapper - , (void **)&pIFM ); - if( SUCCEEDED(hr) ) - { - hr = AMovieSetupRegisterFilter( psetupdata, pIFM, TRUE ); - pIFM->Release(); - } - - // and clear up - // - CoFreeUnusedLibraries(); - CoUninitialize(); - - return NOERROR; -} - - -/* unregister filter */ - -STDMETHODIMP CBaseFilter::Unregister() -{ - // get setup data, if it exists - // - LPAMOVIESETUP_FILTER psetupdata = GetSetupData(); - - // check we've got data - // - if( NULL == psetupdata ) return S_FALSE; - - // OLE init is ref counted so call - // just in case we're being called cold. - // - HRESULT hr = CoInitialize( (LPVOID)NULL ); - ASSERT( SUCCEEDED(hr) ); - - // get hold of IFilterMapper - // - IFilterMapper *pIFM; - hr = CoCreateInstance( CLSID_FilterMapper - , NULL - , CLSCTX_INPROC_SERVER - , IID_IFilterMapper - , (void **)&pIFM ); - if( SUCCEEDED(hr) ) - { - hr = AMovieSetupRegisterFilter( psetupdata, pIFM, FALSE ); - - // release interface - // - pIFM->Release(); - } - - // clear up - // - CoFreeUnusedLibraries(); - CoUninitialize(); - - // handle one acceptable "error" - that - // of filter not being registered! - // (couldn't find a suitable #define'd - // name for the error!) - // - if( 0x80070002 == hr) - return NOERROR; - else - return hr; -} - - -//===================================================================== -//===================================================================== -// Implements CEnumPins -//===================================================================== -//===================================================================== - - -CEnumPins::CEnumPins(CBaseFilter *pFilter, - CEnumPins *pEnumPins) : - m_Position(0), - m_PinCount(0), - m_pFilter(pFilter), - m_cRef(1), // Already ref counted - m_PinCache(NAME("Pin Cache")) -{ - -#ifdef DEBUG - m_dwCookie = DbgRegisterObjectCreation("CEnumPins", 0); -#endif - - /* We must be owned by a filter derived from CBaseFilter */ - - ASSERT(pFilter != NULL); - - /* Hold a reference count on our filter */ - m_pFilter->AddRef(); - - /* Are we creating a new enumerator */ - - if (pEnumPins == NULL) { - m_Version = m_pFilter->GetPinVersion(); - m_PinCount = m_pFilter->GetPinCount(); - } else { - ASSERT(m_Position <= m_PinCount); - m_Position = pEnumPins->m_Position; - m_PinCount = pEnumPins->m_PinCount; - m_Version = pEnumPins->m_Version; - m_PinCache.AddTail(&(pEnumPins->m_PinCache)); - } -} - - -/* Destructor releases the reference count on our filter NOTE since we hold - a reference count on the filter who created us we know it is safe to - release it, no access can be made to it afterwards though as we have just - caused the last reference count to go and the object to be deleted */ - -CEnumPins::~CEnumPins() -{ - m_pFilter->Release(); - -#ifdef DEBUG - DbgRegisterObjectDestruction(m_dwCookie); -#endif -} - - -/* Override this to say what interfaces we support where */ - -STDMETHODIMP -CEnumPins::QueryInterface(REFIID riid,void **ppv) -{ - CheckPointer(ppv, E_POINTER); - - /* Do we have this interface */ - - if (riid == IID_IEnumPins || riid == IID_IUnknown) { - return GetInterface((IEnumPins *) this, ppv); - } else { - *ppv = NULL; - return E_NOINTERFACE; - } -} - -STDMETHODIMP_(ULONG) -CEnumPins::AddRef() -{ - return InterlockedIncrement(&m_cRef); -} - -STDMETHODIMP_(ULONG) -CEnumPins::Release() -{ - ULONG cRef = InterlockedDecrement(&m_cRef); - if (cRef == 0) { - delete this; - } - return cRef; -} - -/* One of an enumerator's basic member functions allows us to create a cloned - interface that initially has the same state. Since we are taking a snapshot - of an object (current position and all) we must lock access at the start */ - -STDMETHODIMP -CEnumPins::Clone(IEnumPins **ppEnum) -{ - CheckPointer(ppEnum,E_POINTER); - ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *)); - HRESULT hr = NOERROR; - - /* Check we are still in sync with the filter */ - if (AreWeOutOfSync() == TRUE) { - *ppEnum = NULL; - hr = VFW_E_ENUM_OUT_OF_SYNC; - } else { - - *ppEnum = new CEnumPins(m_pFilter, - this); - if (*ppEnum == NULL) { - hr = E_OUTOFMEMORY; - } - } - return hr; -} - - -/* Return the next pin after the current position */ - -STDMETHODIMP -CEnumPins::Next(ULONG cPins, // place this many pins... - IPin **ppPins, // ...in this array - ULONG *pcFetched) // actual count passed returned here -{ - CheckPointer(ppPins,E_POINTER); - ValidateReadWritePtr(ppPins,cPins * sizeof(IPin *)); - - ASSERT(ppPins); - - if (pcFetched!=NULL) { - ValidateWritePtr(pcFetched, sizeof(ULONG)); - *pcFetched = 0; // default unless we succeed - } - // now check that the parameter is valid - else if (cPins>1) { // pcFetched == NULL - return E_INVALIDARG; - } - ULONG cFetched = 0; // increment as we get each one. - - /* Check we are still in sync with the filter */ - if (AreWeOutOfSync() == TRUE) { - // If we are out of sync, we should refresh the enumerator. - // This will reset the position and update the other members, but - // will not clear cache of pins we have already returned. - Refresh(); - } - - /* Calculate the number of available pins */ - - int cRealPins = min(m_PinCount - m_Position, (int) cPins); - if (cRealPins == 0) { - return S_FALSE; - } - - /* Return each pin interface NOTE GetPin returns CBasePin * not addrefed - so we must QI for the IPin (which increments its reference count) - If while we are retrieving a pin from the filter an error occurs we - assume that our internal state is stale with respect to the filter - (for example someone has deleted a pin) so we - return VFW_E_ENUM_OUT_OF_SYNC */ - - while (cRealPins && (m_PinCount - m_Position)) { - - /* Get the next pin object from the filter */ - - CBasePin *pPin = m_pFilter->GetPin(m_Position++); - if (pPin == NULL) { - // If this happend, and it's not the first time through, then we've got a problem, - // since we should really go back and release the iPins, which we have previously - // AddRef'ed. - ASSERT( cFetched==0 ); - return VFW_E_ENUM_OUT_OF_SYNC; - } - - /* We only want to return this pin, if it is not in our cache */ - if (0 == m_PinCache.Find(pPin)) - { - /* From the object get an IPin interface */ - - *ppPins = pPin; - pPin->AddRef(); - - cFetched++; - ppPins++; - - m_PinCache.AddTail(pPin); - - cRealPins--; - - } - } - - if (pcFetched!=NULL) { - *pcFetched = cFetched; - } - - return (cPins==cFetched ? NOERROR : S_FALSE); -} - - -/* Skip over one or more entries in the enumerator */ - -STDMETHODIMP -CEnumPins::Skip(ULONG cPins) -{ - /* Check we are still in sync with the filter */ - if (AreWeOutOfSync() == TRUE) { - return VFW_E_ENUM_OUT_OF_SYNC; - } - - /* Work out how many pins are left to skip over */ - /* We could position at the end if we are asked to skip too many... */ - /* ..which would match the base implementation for CEnumMediaTypes::Skip */ - - ULONG PinsLeft = m_PinCount - m_Position; - if (cPins > PinsLeft) { - return S_FALSE; - } - m_Position += cPins; - return NOERROR; -} - - -/* Set the current position back to the start */ -/* Reset has 4 simple steps: - * - * Set position to head of list - * Sync enumerator with object being enumerated - * Clear the cache of pins already returned - * return S_OK - */ - -STDMETHODIMP -CEnumPins::Reset() -{ - m_Version = m_pFilter->GetPinVersion(); - m_PinCount = m_pFilter->GetPinCount(); - - m_Position = 0; - - // Clear the cache - m_PinCache.RemoveAll(); - - return S_OK; -} - - -/* Set the current position back to the start */ -/* Refresh has 3 simple steps: - * - * Set position to head of list - * Sync enumerator with object being enumerated - * return S_OK - */ - -STDMETHODIMP -CEnumPins::Refresh() -{ - m_Version = m_pFilter->GetPinVersion(); - m_PinCount = m_pFilter->GetPinCount(); - - m_Position = 0; - return S_OK; -} - - -//===================================================================== -//===================================================================== -// Implements CEnumMediaTypes -//===================================================================== -//===================================================================== - - -CEnumMediaTypes::CEnumMediaTypes(CBasePin *pPin, - CEnumMediaTypes *pEnumMediaTypes) : - m_Position(0), - m_pPin(pPin), - m_cRef(1) -{ - -#ifdef DEBUG - m_dwCookie = DbgRegisterObjectCreation("CEnumMediaTypes", 0); -#endif - - /* We must be owned by a pin derived from CBasePin */ - - ASSERT(pPin != NULL); - - /* Hold a reference count on our pin */ - m_pPin->AddRef(); - - /* Are we creating a new enumerator */ - - if (pEnumMediaTypes == NULL) { - m_Version = m_pPin->GetMediaTypeVersion(); - return; - } - - m_Position = pEnumMediaTypes->m_Position; - m_Version = pEnumMediaTypes->m_Version; -} - - -/* Destructor releases the reference count on our base pin. NOTE since we hold - a reference count on the pin who created us we know it is safe to release - it, no access can be made to it afterwards though as we might have just - caused the last reference count to go and the object to be deleted */ - -CEnumMediaTypes::~CEnumMediaTypes() -{ -#ifdef DEBUG - DbgRegisterObjectDestruction(m_dwCookie); -#endif - m_pPin->Release(); -} - - -/* Override this to say what interfaces we support where */ - -STDMETHODIMP -CEnumMediaTypes::QueryInterface(REFIID riid,void **ppv) -{ - CheckPointer(ppv, E_POINTER); - - /* Do we have this interface */ - - if (riid == IID_IEnumMediaTypes || riid == IID_IUnknown) { - return GetInterface((IEnumMediaTypes *) this, ppv); - } else { - *ppv = NULL; - return E_NOINTERFACE; - } -} - -STDMETHODIMP_(ULONG) -CEnumMediaTypes::AddRef() -{ - return InterlockedIncrement(&m_cRef); -} - -STDMETHODIMP_(ULONG) -CEnumMediaTypes::Release() -{ - ULONG cRef = InterlockedDecrement(&m_cRef); - if (cRef == 0) { - delete this; - } - return cRef; -} - -/* One of an enumerator's basic member functions allows us to create a cloned - interface that initially has the same state. Since we are taking a snapshot - of an object (current position and all) we must lock access at the start */ - -STDMETHODIMP -CEnumMediaTypes::Clone(IEnumMediaTypes **ppEnum) -{ - CheckPointer(ppEnum,E_POINTER); - ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *)); - HRESULT hr = NOERROR; - - /* Check we are still in sync with the pin */ - if (AreWeOutOfSync() == TRUE) { - *ppEnum = NULL; - hr = VFW_E_ENUM_OUT_OF_SYNC; - } else { - - *ppEnum = new CEnumMediaTypes(m_pPin, - this); - - if (*ppEnum == NULL) { - hr = E_OUTOFMEMORY; - } - } - return hr; -} - - -/* Enumerate the next pin(s) after the current position. The client using this - interface passes in a pointer to an array of pointers each of which will - be filled in with a pointer to a fully initialised media type format - Return NOERROR if it all works, - S_FALSE if fewer than cMediaTypes were enumerated. - VFW_E_ENUM_OUT_OF_SYNC if the enumerator has been broken by - state changes in the filter - The actual count always correctly reflects the number of types in the array. -*/ - -STDMETHODIMP -CEnumMediaTypes::Next(ULONG cMediaTypes, // place this many types... - AM_MEDIA_TYPE **ppMediaTypes, // ...in this array - ULONG *pcFetched) // actual count passed -{ - CheckPointer(ppMediaTypes,E_POINTER); - ValidateReadWritePtr(ppMediaTypes,cMediaTypes * sizeof(AM_MEDIA_TYPE *)); - /* Check we are still in sync with the pin */ - if (AreWeOutOfSync() == TRUE) { - return VFW_E_ENUM_OUT_OF_SYNC; - } - - if (pcFetched!=NULL) { - ValidateWritePtr(pcFetched, sizeof(ULONG)); - *pcFetched = 0; // default unless we succeed - } - // now check that the parameter is valid - else if (cMediaTypes>1) { // pcFetched == NULL - return E_INVALIDARG; - } - ULONG cFetched = 0; // increment as we get each one. - - /* Return each media type by asking the filter for them in turn - If we - have an error code retured to us while we are retrieving a media type - we assume that our internal state is stale with respect to the filter - (for example the window size changing) so we return - VFW_E_ENUM_OUT_OF_SYNC */ - - while (cMediaTypes) { - - CMediaType cmt; - - HRESULT hr = m_pPin->GetMediaType(m_Position++, &cmt); - if (S_OK != hr) { - break; - } - - /* We now have a CMediaType object that contains the next media type - but when we assign it to the array position we CANNOT just assign - the AM_MEDIA_TYPE structure because as soon as the object goes out of - scope it will delete the memory we have just copied. The function - we use is CreateMediaType which allocates a task memory block */ - - /* Transfer across the format block manually to save an allocate - and free on the format block and generally go faster */ - - *ppMediaTypes = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); - if (*ppMediaTypes == NULL) { - break; - } - - /* Do a regular copy */ - **ppMediaTypes = (AM_MEDIA_TYPE)cmt; - - /* Make sure the destructor doesn't free these */ - cmt.pbFormat = NULL; - cmt.cbFormat = NULL; - cmt.pUnk = NULL; - - - ppMediaTypes++; - cFetched++; - cMediaTypes--; - } - - if (pcFetched!=NULL) { - *pcFetched = cFetched; - } - - return ( cMediaTypes==0 ? NOERROR : S_FALSE ); -} - - -/* Skip over one or more entries in the enumerator */ - -STDMETHODIMP -CEnumMediaTypes::Skip(ULONG cMediaTypes) -{ - // If we're skipping 0 elements we're guaranteed to skip the - // correct number of elements - if (cMediaTypes == 0) { - return S_OK; - } - - /* Check we are still in sync with the pin */ - if (AreWeOutOfSync() == TRUE) { - return VFW_E_ENUM_OUT_OF_SYNC; - } - - m_Position += cMediaTypes; - - /* See if we're over the end */ - CMediaType cmt; - return S_OK == m_pPin->GetMediaType(m_Position - 1, &cmt) ? S_OK : S_FALSE; -} - - -/* Set the current position back to the start */ -/* Reset has 3 simple steps: - * - * set position to head of list - * sync enumerator with object being enumerated - * return S_OK - */ - -STDMETHODIMP -CEnumMediaTypes::Reset() - -{ - m_Position = 0; - - // Bring the enumerator back into step with the current state. This - // may be a noop but ensures that the enumerator will be valid on the - // next call. - m_Version = m_pPin->GetMediaTypeVersion(); - return NOERROR; -} - - -//===================================================================== -//===================================================================== -// Implements CBasePin -//===================================================================== -//===================================================================== - - -/* NOTE The implementation of this class calls the CUnknown constructor with - a NULL outer unknown pointer. This has the effect of making us a self - contained class, ie any QueryInterface, AddRef or Release calls will be - routed to the class's NonDelegatingUnknown methods. You will typically - find that the classes that do this then override one or more of these - virtual functions to provide more specialised behaviour. A good example - of this is where a class wants to keep the QueryInterface internal but - still wants its lifetime controlled by the external object */ - -/* Constructor */ - -CBasePin::CBasePin(TCHAR *pObjectName, - CBaseFilter *pFilter, - CCritSec *pLock, - HRESULT *phr, - LPCWSTR pName, - PIN_DIRECTION dir) : - CUnknown( pObjectName, NULL ), - m_pFilter(pFilter), - m_pLock(pLock), - m_pName(NULL), - m_Connected(NULL), - m_dir(dir), - m_bRunTimeError(FALSE), - m_pQSink(NULL), - m_TypeVersion(1), - m_tStart(), - m_tStop(MAX_TIME), - m_bCanReconnectWhenActive(false), - m_bTryMyTypesFirst(false), - m_dRate(1.0) -{ - /* WARNING - pFilter is often not a properly constituted object at - this state (in particular QueryInterface may not work) - this - is because its owner is often its containing object and we - have been called from the containing object's constructor so - the filter's owner has not yet had its CUnknown constructor - called - */ - - ASSERT(pFilter != NULL); - ASSERT(pLock != NULL); - - if (pName) { - DWORD nameLen = lstrlenW(pName)+1; - m_pName = new WCHAR[nameLen]; - if (m_pName) { - CopyMemory(m_pName, pName, nameLen*sizeof(WCHAR)); - } - } - -#ifdef DEBUG - m_cRef = 0; -#endif -} - -#ifdef UNICODE -CBasePin::CBasePin(CHAR *pObjectName, - CBaseFilter *pFilter, - CCritSec *pLock, - HRESULT *phr, - LPCWSTR pName, - PIN_DIRECTION dir) : - CUnknown( pObjectName, NULL ), - m_pFilter(pFilter), - m_pLock(pLock), - m_pName(NULL), - m_Connected(NULL), - m_dir(dir), - m_bRunTimeError(FALSE), - m_pQSink(NULL), - m_TypeVersion(1), - m_tStart(), - m_tStop(MAX_TIME), - m_bCanReconnectWhenActive(false), - m_bTryMyTypesFirst(false), - m_dRate(1.0) -{ - /* WARNING - pFilter is often not a properly constituted object at - this state (in particular QueryInterface may not work) - this - is because its owner is often its containing object and we - have been called from the containing object's constructor so - the filter's owner has not yet had its CUnknown constructor - called - */ - - ASSERT(pFilter != NULL); - ASSERT(pLock != NULL); - - if (pName) { - DWORD nameLen = lstrlenW(pName)+1; - m_pName = new WCHAR[nameLen]; - if (m_pName) { - CopyMemory(m_pName, pName, nameLen*sizeof(WCHAR)); - } - } - -#ifdef DEBUG - m_cRef = 0; -#endif -} -#endif - -/* Destructor since a connected pin holds a reference count on us there is - no way that we can be deleted unless we are not currently connected */ - -CBasePin::~CBasePin() -{ - - // We don't call disconnect because if the filter is going away - // all the pins must have a reference count of zero so they must - // have been disconnected anyway - (but check the assumption) - ASSERT(m_Connected == FALSE); - - delete[] m_pName; - - // check the internal reference count is consistent - ASSERT(m_cRef == 0); -} - - -/* Override this to say what interfaces we support and where */ - -STDMETHODIMP -CBasePin::NonDelegatingQueryInterface(REFIID riid, void ** ppv) -{ - /* Do we have this interface */ - - if (riid == IID_IPin) { - return GetInterface((IPin *) this, ppv); - } else if (riid == IID_IQualityControl) { - return GetInterface((IQualityControl *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -/* Override to increment the owning filter's reference count */ - -STDMETHODIMP_(ULONG) -CBasePin::NonDelegatingAddRef() -{ - ASSERT(InterlockedIncrement(&m_cRef) > 0); - return m_pFilter->AddRef(); -} - - -/* Override to decrement the owning filter's reference count */ - -STDMETHODIMP_(ULONG) -CBasePin::NonDelegatingRelease() -{ - ASSERT(InterlockedDecrement(&m_cRef) >= 0); - return m_pFilter->Release(); -} - - -/* Displays pin connection information */ - -#ifdef DEBUG -void -CBasePin::DisplayPinInfo(IPin *pReceivePin) -{ - - if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) { - PIN_INFO ConnectPinInfo; - PIN_INFO ReceivePinInfo; - - if (FAILED(QueryPinInfo(&ConnectPinInfo))) { - (void)StringCchCopyW(ConnectPinInfo.achName, NUMELMS(ConnectPinInfo.achName),L"Bad Pin"); - } else { - QueryPinInfoReleaseFilter(ConnectPinInfo); - } - - if (FAILED(pReceivePin->QueryPinInfo(&ReceivePinInfo))) { - (void)StringCchCopyW(ReceivePinInfo.achName, NUMELMS(ReceivePinInfo.achName),L"Bad Pin"); - } else { - QueryPinInfoReleaseFilter(ReceivePinInfo); - } - - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying to connect Pins :"))); - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" <%ls>"), ConnectPinInfo.achName)); - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" <%ls>"), ReceivePinInfo.achName)); - } -} -#endif - - -/* Displays general information on the pin media type */ - -#ifdef DEBUG -void CBasePin::DisplayTypeInfo(IPin *pPin, const CMediaType *pmt) -{ - UNREFERENCED_PARAMETER(pPin); - if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) { - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying media type:"))); - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" major type: %hs"), - GuidNames[*pmt->Type()])); - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" sub type : %hs"), - GuidNames[*pmt->Subtype()])); - } -} -#endif - -/* Asked to connect to a pin. A pin is always attached to an owning filter - object so we always delegate our locking to that object. We first of all - retrieve a media type enumerator for the input pin and see if we accept - any of the formats that it would ideally like, failing that we retrieve - our enumerator and see if it will accept any of our preferred types */ - -STDMETHODIMP -CBasePin::Connect( - IPin * pReceivePin, - const AM_MEDIA_TYPE *pmt // optional media type -) -{ - CheckPointer(pReceivePin,E_POINTER); - ValidateReadPtr(pReceivePin,sizeof(IPin)); - CAutoLock cObjectLock(m_pLock); - DisplayPinInfo(pReceivePin); - - /* See if we are already connected */ - - if (m_Connected) { - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Already connected"))); - return VFW_E_ALREADY_CONNECTED; - } - - /* See if the filter is active */ - if (!IsStopped() && !m_bCanReconnectWhenActive) { - return VFW_E_NOT_STOPPED; - } - - - // Find a mutually agreeable media type - - // Pass in the template media type. If this is partially specified, - // each of the enumerated media types will need to be checked against - // it. If it is non-null and fully specified, we will just try to connect - // with this. - - const CMediaType * ptype = (CMediaType*)pmt; - HRESULT hr = AgreeMediaType(pReceivePin, ptype); - if (FAILED(hr)) { - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to agree type"))); - - // Since the procedure is already returning an error code, there - // is nothing else this function can do to report the error. - EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); - - - return hr; - } - - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Connection succeeded"))); - - - return NOERROR; -} - -// given a specific media type, attempt a connection (includes -// checking that the type is acceptable to this pin) -HRESULT -CBasePin::AttemptConnection( - IPin* pReceivePin, // connect to this pin - const CMediaType* pmt // using this type -) -{ - // The caller should hold the filter lock becasue this function - // uses m_Connected. The caller should also hold the filter lock - // because this function calls SetMediaType(), IsStopped() and - // CompleteConnect(). - ASSERT(CritCheckIn(m_pLock)); - - // Check that the connection is valid -- need to do this for every - // connect attempt since BreakConnect will undo it. - HRESULT hr = CheckConnect(pReceivePin); - if (FAILED(hr)) { - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("CheckConnect failed"))); - - // Since the procedure is already returning an error code, there - // is nothing else this function can do to report the error. - EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); - - return hr; - } - - DisplayTypeInfo(pReceivePin, pmt); - - /* Check we will accept this media type */ - - hr = CheckMediaType(pmt); - if (hr == NOERROR) { - - /* Make ourselves look connected otherwise ReceiveConnection - may not be able to complete the connection - */ - m_Connected = pReceivePin; - m_Connected->AddRef(); - hr = SetMediaType(pmt); - if (SUCCEEDED(hr)) { - /* See if the other pin will accept this type */ - - hr = pReceivePin->ReceiveConnection((IPin *)this, pmt); - if (SUCCEEDED(hr)) { - /* Complete the connection */ - - hr = CompleteConnect(pReceivePin); - if (SUCCEEDED(hr)) { - return hr; - } else { - DbgLog((LOG_TRACE, - CONNECT_TRACE_LEVEL, - TEXT("Failed to complete connection"))); - pReceivePin->Disconnect(); - } - } - } - } else { - // we cannot use this media type - - // return a specific media type error if there is one - // or map a general failure code to something more helpful - // (in particular S_FALSE gets changed to an error code) - if (SUCCEEDED(hr) || - (hr == E_FAIL) || - (hr == E_INVALIDARG)) { - hr = VFW_E_TYPE_NOT_ACCEPTED; - } - } - - // BreakConnect and release any connection here in case CheckMediaType - // failed, or if we set anything up during a call back during - // ReceiveConnection. - - // Since the procedure is already returning an error code, there - // is nothing else this function can do to report the error. - EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); - - /* If failed then undo our state */ - if (m_Connected) { - m_Connected->Release(); - m_Connected = NULL; - } - - return hr; -} - -/* Given an enumerator we cycle through all the media types it proposes and - firstly suggest them to our derived pin class and if that succeeds try - them with the pin in a ReceiveConnection call. This means that if our pin - proposes a media type we still check in here that we can support it. This - is deliberate so that in simple cases the enumerator can hold all of the - media types even if some of them are not really currently available */ - -HRESULT CBasePin::TryMediaTypes( - IPin *pReceivePin, - const CMediaType *pmt, - IEnumMediaTypes *pEnum) -{ - /* Reset the current enumerator position */ - - HRESULT hr = pEnum->Reset(); - if (FAILED(hr)) { - return hr; - } - - CMediaType *pMediaType = NULL; - ULONG ulMediaCount = 0; - - // attempt to remember a specific error code if there is one - HRESULT hrFailure = S_OK; - - for (;;) { - - /* Retrieve the next media type NOTE each time round the loop the - enumerator interface will allocate another AM_MEDIA_TYPE structure - If we are successful then we copy it into our output object, if - not then we must delete the memory allocated before returning */ - - hr = pEnum->Next(1, (AM_MEDIA_TYPE**)&pMediaType,&ulMediaCount); - if (hr != S_OK) { - if (S_OK == hrFailure) { - hrFailure = VFW_E_NO_ACCEPTABLE_TYPES; - } - return hrFailure; - } - - - ASSERT(ulMediaCount == 1); - ASSERT(pMediaType); - - // check that this matches the partial type (if any) - - if ((pmt == NULL) || - pMediaType->MatchesPartial(pmt)) { - - hr = AttemptConnection(pReceivePin, pMediaType); - - // attempt to remember a specific error code - if (FAILED(hr) && - SUCCEEDED(hrFailure) && - (hr != E_FAIL) && - (hr != E_INVALIDARG) && - (hr != VFW_E_TYPE_NOT_ACCEPTED)) { - hrFailure = hr; - } - } else { - hr = VFW_E_NO_ACCEPTABLE_TYPES; - } - - DeleteMediaType(pMediaType); - - if (S_OK == hr) { - return hr; - } - } -} - - -/* This is called to make the connection, including the taask of finding - a media type for the pin connection. pmt is the proposed media type - from the Connect call: if this is fully specified, we will try that. - Otherwise we enumerate and try all the input pin's types first and - if that fails we then enumerate and try all our preferred media types. - For each media type we check it against pmt (if non-null and partially - specified) as well as checking that both pins will accept it. - */ - -HRESULT CBasePin::AgreeMediaType( - IPin *pReceivePin, - const CMediaType *pmt) -{ - ASSERT(pReceivePin); - IEnumMediaTypes *pEnumMediaTypes = NULL; - - // if the media type is fully specified then use that - if ( (pmt != NULL) && (!pmt->IsPartiallySpecified())) { - - // if this media type fails, then we must fail the connection - // since if pmt is nonnull we are only allowed to connect - // using a type that matches it. - - return AttemptConnection(pReceivePin, pmt); - } - - - /* Try the other pin's enumerator */ - - HRESULT hrFailure = VFW_E_NO_ACCEPTABLE_TYPES; - - for (int i = 0; i < 2; i++) { - HRESULT hr; - if (i == (int)m_bTryMyTypesFirst) { - hr = pReceivePin->EnumMediaTypes(&pEnumMediaTypes); - } else { - hr = EnumMediaTypes(&pEnumMediaTypes); - } - if (SUCCEEDED(hr)) { - ASSERT(pEnumMediaTypes); - hr = TryMediaTypes(pReceivePin,pmt,pEnumMediaTypes); - pEnumMediaTypes->Release(); - if (SUCCEEDED(hr)) { - return NOERROR; - } else { - // try to remember specific error codes if there are any - if ((hr != E_FAIL) && - (hr != E_INVALIDARG) && - (hr != VFW_E_TYPE_NOT_ACCEPTED)) { - hrFailure = hr; - } - } - } - } - - return hrFailure; -} - - -/* Called when we want to complete a connection to another filter. Failing - this will also fail the connection and disconnect the other pin as well */ - -HRESULT -CBasePin::CompleteConnect(IPin *pReceivePin) -{ - UNREFERENCED_PARAMETER(pReceivePin); - return NOERROR; -} - - -/* This is called to set the format for a pin connection - CheckMediaType - will have been called to check the connection format and if it didn't - return an error code then this (virtual) function will be invoked */ - -HRESULT -CBasePin::SetMediaType(const CMediaType *pmt) -{ - HRESULT hr = m_mt.Set(*pmt); - if (FAILED(hr)) { - return hr; - } - - return NOERROR; -} - - -/* This is called during Connect() to provide a virtual method that can do - any specific check needed for connection such as QueryInterface. This - base class method just checks that the pin directions don't match */ - -HRESULT -CBasePin::CheckConnect(IPin * pPin) -{ - /* Check that pin directions DONT match */ - - PIN_DIRECTION pd; - pPin->QueryDirection(&pd); - - ASSERT((pd == PINDIR_OUTPUT) || (pd == PINDIR_INPUT)); - ASSERT((m_dir == PINDIR_OUTPUT) || (m_dir == PINDIR_INPUT)); - - // we should allow for non-input and non-output connections? - if (pd == m_dir) { - return VFW_E_INVALID_DIRECTION; - } - return NOERROR; -} - - -/* This is called when we realise we can't make a connection to the pin and - must undo anything we did in CheckConnect - override to release QIs done */ - -HRESULT -CBasePin::BreakConnect() -{ - return NOERROR; -} - - -/* Called normally by an output pin on an input pin to try and establish a - connection. -*/ - -STDMETHODIMP -CBasePin::ReceiveConnection( - IPin * pConnector, // this is the pin who we will connect to - const AM_MEDIA_TYPE *pmt // this is the media type we will exchange -) -{ - CheckPointer(pConnector,E_POINTER); - CheckPointer(pmt,E_POINTER); - ValidateReadPtr(pConnector,sizeof(IPin)); - ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE)); - CAutoLock cObjectLock(m_pLock); - - /* Are we already connected */ - if (m_Connected) { - return VFW_E_ALREADY_CONNECTED; - } - - /* See if the filter is active */ - if (!IsStopped() && !m_bCanReconnectWhenActive) { - return VFW_E_NOT_STOPPED; - } - - HRESULT hr = CheckConnect(pConnector); - if (FAILED(hr)) { - // Since the procedure is already returning an error code, there - // is nothing else this function can do to report the error. - EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); - - - return hr; - } - - /* Ask derived class if this media type is ok */ - - CMediaType * pcmt = (CMediaType*) pmt; - hr = CheckMediaType(pcmt); - if (hr != NOERROR) { - // no -we don't support this media type - - // Since the procedure is already returning an error code, there - // is nothing else this function can do to report the error. - EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); - - // return a specific media type error if there is one - // or map a general failure code to something more helpful - // (in particular S_FALSE gets changed to an error code) - if (SUCCEEDED(hr) || - (hr == E_FAIL) || - (hr == E_INVALIDARG)) { - hr = VFW_E_TYPE_NOT_ACCEPTED; - } - - - return hr; - } - - /* Complete the connection */ - - m_Connected = pConnector; - m_Connected->AddRef(); - hr = SetMediaType(pcmt); - if (SUCCEEDED(hr)) { - hr = CompleteConnect(pConnector); - if (SUCCEEDED(hr)) { - - - return NOERROR; - } - } - - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to set the media type or failed to complete the connection."))); - m_Connected->Release(); - m_Connected = NULL; - - // Since the procedure is already returning an error code, there - // is nothing else this function can do to report the error. - EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); - - - return hr; -} - - -/* Called when we want to terminate a pin connection */ - -STDMETHODIMP -CBasePin::Disconnect() -{ - CAutoLock cObjectLock(m_pLock); - - /* See if the filter is active */ - if (!IsStopped()) { - return VFW_E_NOT_STOPPED; - } - - return DisconnectInternal(); -} - -STDMETHODIMP -CBasePin::DisconnectInternal() -{ - ASSERT(CritCheckIn(m_pLock)); - - if (m_Connected) { - HRESULT hr = BreakConnect(); - if( FAILED( hr ) ) { - - - // There is usually a bug in the program if BreakConnect() fails. - DbgBreak( "WARNING: BreakConnect() failed in CBasePin::Disconnect()." ); - return hr; - } - - m_Connected->Release(); - m_Connected = NULL; - - - return S_OK; - } else { - // no connection - not an error - - - return S_FALSE; - } -} - - -/* Return an AddRef()'d pointer to the connected pin if there is one */ -STDMETHODIMP -CBasePin::ConnectedTo( - IPin **ppPin -) -{ - CheckPointer(ppPin,E_POINTER); - ValidateReadWritePtr(ppPin,sizeof(IPin *)); - // - // It's pointless to lock here. - // The caller should ensure integrity. - // - - IPin *pPin = m_Connected; - *ppPin = pPin; - if (pPin != NULL) { - pPin->AddRef(); - return S_OK; - } else { - ASSERT(*ppPin == NULL); - return VFW_E_NOT_CONNECTED; - } -} - -/* Return the media type of the connection */ -STDMETHODIMP -CBasePin::ConnectionMediaType( - AM_MEDIA_TYPE *pmt -) -{ - CheckPointer(pmt,E_POINTER); - ValidateReadWritePtr(pmt,sizeof(AM_MEDIA_TYPE)); - CAutoLock cObjectLock(m_pLock); - - /* Copy constructor of m_mt allocates the memory */ - if (IsConnected()) { - CopyMediaType( pmt, &m_mt ); - return S_OK; - } else { - ((CMediaType *)pmt)->InitMediaType(); - return VFW_E_NOT_CONNECTED; - } -} - -/* Return information about the filter we are connect to */ - -STDMETHODIMP -CBasePin::QueryPinInfo( - PIN_INFO * pInfo -) -{ - CheckPointer(pInfo,E_POINTER); - ValidateReadWritePtr(pInfo,sizeof(PIN_INFO)); - - pInfo->pFilter = m_pFilter; - if (m_pFilter) { - m_pFilter->AddRef(); - } - - if (m_pName) { - lstrcpynW(pInfo->achName, m_pName, sizeof(pInfo->achName)/sizeof(WCHAR)); - } else { - pInfo->achName[0] = L'\0'; - } - - pInfo->dir = m_dir; - - return NOERROR; -} - -STDMETHODIMP -CBasePin::QueryDirection( - PIN_DIRECTION * pPinDir -) -{ - CheckPointer(pPinDir,E_POINTER); - ValidateReadWritePtr(pPinDir,sizeof(PIN_DIRECTION)); - - *pPinDir = m_dir; - return NOERROR; -} - -// Default QueryId to return the pin's name -STDMETHODIMP -CBasePin::QueryId( - LPWSTR * Id -) -{ - // We're not going away because someone's got a pointer to us - // so there's no need to lock - - return AMGetWideString(Name(), Id); -} - -/* Does this pin support this media type WARNING this interface function does - not lock the main object as it is meant to be asynchronous by nature - if - the media types you support depend on some internal state that is updated - dynamically then you will need to implement locking in a derived class */ - -STDMETHODIMP -CBasePin::QueryAccept( - const AM_MEDIA_TYPE *pmt -) -{ - CheckPointer(pmt,E_POINTER); - ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE)); - - /* The CheckMediaType method is valid to return error codes if the media - type is horrible, an example might be E_INVALIDARG. What we do here - is map all the error codes into either S_OK or S_FALSE regardless */ - - HRESULT hr = CheckMediaType((CMediaType*)pmt); - if (FAILED(hr)) { - return S_FALSE; - } - // note that the only defined success codes should be S_OK and S_FALSE... - return hr; -} - - -/* This can be called to return an enumerator for the pin's list of preferred - media types. An input pin is not obliged to have any preferred formats - although it can do. For example, the window renderer has a preferred type - which describes a video image that matches the current window size. All - output pins should expose at least one preferred format otherwise it is - possible that neither pin has any types and so no connection is possible */ - -STDMETHODIMP -CBasePin::EnumMediaTypes( - IEnumMediaTypes **ppEnum -) -{ - CheckPointer(ppEnum,E_POINTER); - ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *)); - - /* Create a new ref counted enumerator */ - - *ppEnum = new CEnumMediaTypes(this, - NULL); - - if (*ppEnum == NULL) { - return E_OUTOFMEMORY; - } - - return NOERROR; -} - - - -/* This is a virtual function that returns a media type corresponding with - place iPosition in the list. This base class simply returns an error as - we support no media types by default but derived classes should override */ - -HRESULT CBasePin::GetMediaType(int iPosition, CMediaType *pMediaType) -{ - UNREFERENCED_PARAMETER(iPosition); - UNREFERENCED_PARAMETER(pMediaType); - return E_UNEXPECTED; -} - - -/* This is a virtual function that returns the current media type version. - The base class initialises the media type enumerators with the value 1 - By default we always returns that same value. A Derived class may change - the list of media types available and after doing so it should increment - the version either in a method derived from this, or more simply by just - incrementing the m_TypeVersion base pin variable. The type enumerators - call this when they want to see if their enumerations are out of date */ - -LONG CBasePin::GetMediaTypeVersion() -{ - return m_TypeVersion; -} - - -/* Increment the cookie representing the current media type version */ - -void CBasePin::IncrementTypeVersion() -{ - InterlockedIncrement(&m_TypeVersion); -} - - -/* Called by IMediaFilter implementation when the state changes from Stopped - to either paused or running and in derived classes could do things like - commit memory and grab hardware resource (the default is to do nothing) */ - -HRESULT -CBasePin::Active(void) -{ - return NOERROR; -} - -/* Called by IMediaFilter implementation when the state changes from - to either paused to running and in derived classes could do things like - commit memory and grab hardware resource (the default is to do nothing) */ - -HRESULT -CBasePin::Run(REFERENCE_TIME tStart) -{ - UNREFERENCED_PARAMETER(tStart); - return NOERROR; -} - - -/* Also called by the IMediaFilter implementation when the state changes to - Stopped at which point you should decommit allocators and free hardware - resources you grabbed in the Active call (default is also to do nothing) */ - -HRESULT -CBasePin::Inactive(void) -{ - m_bRunTimeError = FALSE; - return NOERROR; -} - - -// Called when no more data will arrive -STDMETHODIMP -CBasePin::EndOfStream(void) -{ - return S_OK; -} - - -STDMETHODIMP -CBasePin::SetSink(IQualityControl * piqc) -{ - CAutoLock cObjectLock(m_pLock); - if (piqc) ValidateReadPtr(piqc,sizeof(IQualityControl)); - m_pQSink = piqc; - return NOERROR; -} // SetSink - - -STDMETHODIMP -CBasePin::Notify(IBaseFilter * pSender, Quality q) -{ - UNREFERENCED_PARAMETER(q); - UNREFERENCED_PARAMETER(pSender); - DbgBreak("IQualityControl::Notify not over-ridden from CBasePin. (IGNORE is OK)"); - return E_NOTIMPL; -} //Notify - - -// NewSegment notifies of the start/stop/rate applying to the data -// about to be received. Default implementation records data and -// returns S_OK. -// Override this to pass downstream. -STDMETHODIMP -CBasePin::NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate) -{ - m_tStart = tStart; - m_tStop = tStop; - m_dRate = dRate; - - return S_OK; -} - - -//===================================================================== -//===================================================================== -// Implements CBaseOutputPin -//===================================================================== -//===================================================================== - - -CBaseOutputPin::CBaseOutputPin(TCHAR *pObjectName, - CBaseFilter *pFilter, - CCritSec *pLock, - HRESULT *phr, - LPCWSTR pName) : - CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT), - m_pAllocator(NULL), - m_pInputPin(NULL) -{ - ASSERT(pFilter); -} - -#ifdef UNICODE -CBaseOutputPin::CBaseOutputPin(CHAR *pObjectName, - CBaseFilter *pFilter, - CCritSec *pLock, - HRESULT *phr, - LPCWSTR pName) : - CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT), - m_pAllocator(NULL), - m_pInputPin(NULL) -{ - ASSERT(pFilter); -} -#endif - -/* This is called after a media type has been proposed - - Try to complete the connection by agreeing the allocator -*/ -HRESULT -CBaseOutputPin::CompleteConnect(IPin *pReceivePin) -{ - UNREFERENCED_PARAMETER(pReceivePin); - return DecideAllocator(m_pInputPin, &m_pAllocator); -} - - -/* This method is called when the output pin is about to try and connect to - an input pin. It is at this point that you should try and grab any extra - interfaces that you need, in this case IMemInputPin. Because this is - only called if we are not currently connected we do NOT need to call - BreakConnect. This also makes it easier to derive classes from us as - BreakConnect is only called when we actually have to break a connection - (or a partly made connection) and not when we are checking a connection */ - -/* Overriden from CBasePin */ - -HRESULT -CBaseOutputPin::CheckConnect(IPin * pPin) -{ - HRESULT hr = CBasePin::CheckConnect(pPin); - if (FAILED(hr)) { - return hr; - } - - // get an input pin and an allocator interface - hr = pPin->QueryInterface(IID_IMemInputPin, (void **) &m_pInputPin); - if (FAILED(hr)) { - return hr; - } - return NOERROR; -} - - -/* Overriden from CBasePin */ - -HRESULT -CBaseOutputPin::BreakConnect() -{ - /* Release any allocator we hold */ - - if (m_pAllocator) { - // Always decommit the allocator because a downstream filter may or - // may not decommit the connection's allocator. A memory leak could - // occur if the allocator is not decommited when a connection is broken. - HRESULT hr = m_pAllocator->Decommit(); - if( FAILED( hr ) ) { - return hr; - } - - m_pAllocator->Release(); - m_pAllocator = NULL; - } - - /* Release any input pin interface we hold */ - - if (m_pInputPin) { - m_pInputPin->Release(); - m_pInputPin = NULL; - } - return NOERROR; -} - - -/* This is called when the input pin didn't give us a valid allocator */ - -HRESULT -CBaseOutputPin::InitAllocator(IMemAllocator **ppAlloc) -{ - return CreateMemoryAllocator(ppAlloc); -} - - -/* Decide on an allocator, override this if you want to use your own allocator - Override DecideBufferSize to call SetProperties. If the input pin fails - the GetAllocator call then this will construct a CMemAllocator and call - DecideBufferSize on that, and if that fails then we are completely hosed. - If the you succeed the DecideBufferSize call, we will notify the input - pin of the selected allocator. NOTE this is called during Connect() which - therefore looks after grabbing and locking the object's critical section */ - -// We query the input pin for its requested properties and pass this to -// DecideBufferSize to allow it to fulfill requests that it is happy -// with (eg most people don't care about alignment and are thus happy to -// use the downstream pin's alignment request). - -HRESULT -CBaseOutputPin::DecideAllocator(IMemInputPin *pPin, IMemAllocator **ppAlloc) -{ - HRESULT hr = NOERROR; - *ppAlloc = NULL; - - // get downstream prop request - // the derived class may modify this in DecideBufferSize, but - // we assume that he will consistently modify it the same way, - // so we only get it once - ALLOCATOR_PROPERTIES prop; - ZeroMemory(&prop, sizeof(prop)); - - // whatever he returns, we assume prop is either all zeros - // or he has filled it out. - pPin->GetAllocatorRequirements(&prop); - - // if he doesn't care about alignment, then set it to 1 - if (prop.cbAlign == 0) { - prop.cbAlign = 1; - } - - /* Try the allocator provided by the input pin */ - - hr = pPin->GetAllocator(ppAlloc); - if (SUCCEEDED(hr)) { - - hr = DecideBufferSize(*ppAlloc, &prop); - if (SUCCEEDED(hr)) { - hr = pPin->NotifyAllocator(*ppAlloc, FALSE); - if (SUCCEEDED(hr)) { - return NOERROR; - } - } - } - - /* If the GetAllocator failed we may not have an interface */ - - if (*ppAlloc) { - (*ppAlloc)->Release(); - *ppAlloc = NULL; - } - - /* Try the output pin's allocator by the same method */ - - hr = InitAllocator(ppAlloc); - if (SUCCEEDED(hr)) { - - // note - the properties passed here are in the same - // structure as above and may have been modified by - // the previous call to DecideBufferSize - hr = DecideBufferSize(*ppAlloc, &prop); - if (SUCCEEDED(hr)) { - hr = pPin->NotifyAllocator(*ppAlloc, FALSE); - if (SUCCEEDED(hr)) { - return NOERROR; - } - } - } - - /* Likewise we may not have an interface to release */ - - if (*ppAlloc) { - (*ppAlloc)->Release(); - *ppAlloc = NULL; - } - return hr; -} - - -/* This returns an empty sample buffer from the allocator WARNING the same - dangers and restrictions apply here as described below for Deliver() */ - -HRESULT -CBaseOutputPin::GetDeliveryBuffer(IMediaSample ** ppSample, - REFERENCE_TIME * pStartTime, - REFERENCE_TIME * pEndTime, - DWORD dwFlags) -{ - if (m_pAllocator != NULL) { - return m_pAllocator->GetBuffer(ppSample,pStartTime,pEndTime,dwFlags); - } else { - return E_NOINTERFACE; - } -} - - -/* Deliver a filled-in sample to the connected input pin. NOTE the object must - have locked itself before calling us otherwise we may get halfway through - executing this method only to find the filter graph has got in and - disconnected us from the input pin. If the filter has no worker threads - then the lock is best applied on Receive(), otherwise it should be done - when the worker thread is ready to deliver. There is a wee snag to worker - threads that this shows up. The worker thread must lock the object when - it is ready to deliver a sample, but it may have to wait until a state - change has completed, but that may never complete because the state change - is waiting for the worker thread to complete. The way to handle this is for - the state change code to grab the critical section, then set an abort event - for the worker thread, then release the critical section and wait for the - worker thread to see the event we set and then signal that it has finished - (with another event). At which point the state change code can complete */ - -// note (if you've still got any breath left after reading that) that you -// need to release the sample yourself after this call. if the connected -// input pin needs to hold onto the sample beyond the call, it will addref -// the sample itself. - -// of course you must release this one and call GetDeliveryBuffer for the -// next. You cannot reuse it directly. - -HRESULT -CBaseOutputPin::Deliver(IMediaSample * pSample) -{ - if (m_pInputPin == NULL) { - return VFW_E_NOT_CONNECTED; - } - - - return m_pInputPin->Receive(pSample); -} - - -// called from elsewhere in our filter to pass EOS downstream to -// our connected input pin -HRESULT -CBaseOutputPin::DeliverEndOfStream(void) -{ - // remember this is on IPin not IMemInputPin - if (m_Connected == NULL) { - return VFW_E_NOT_CONNECTED; - } - return m_Connected->EndOfStream(); -} - - -/* Commit the allocator's memory, this is called through IMediaFilter - which is responsible for locking the object before calling us */ - -HRESULT -CBaseOutputPin::Active(void) -{ - if (m_pAllocator == NULL) { - return VFW_E_NO_ALLOCATOR; - } - return m_pAllocator->Commit(); -} - - -/* Free up or unprepare allocator's memory, this is called through - IMediaFilter which is responsible for locking the object first */ - -HRESULT -CBaseOutputPin::Inactive(void) -{ - m_bRunTimeError = FALSE; - if (m_pAllocator == NULL) { - return VFW_E_NO_ALLOCATOR; - } - return m_pAllocator->Decommit(); -} - -// we have a default handling of EndOfStream which is to return -// an error, since this should be called on input pins only -STDMETHODIMP -CBaseOutputPin::EndOfStream(void) -{ - return E_UNEXPECTED; -} - - -// BeginFlush should be called on input pins only -STDMETHODIMP -CBaseOutputPin::BeginFlush(void) -{ - return E_UNEXPECTED; -} - -// EndFlush should be called on input pins only -STDMETHODIMP -CBaseOutputPin::EndFlush(void) -{ - return E_UNEXPECTED; -} - -// call BeginFlush on the connected input pin -HRESULT -CBaseOutputPin::DeliverBeginFlush(void) -{ - // remember this is on IPin not IMemInputPin - if (m_Connected == NULL) { - return VFW_E_NOT_CONNECTED; - } - return m_Connected->BeginFlush(); -} - -// call EndFlush on the connected input pin -HRESULT -CBaseOutputPin::DeliverEndFlush(void) -{ - // remember this is on IPin not IMemInputPin - if (m_Connected == NULL) { - return VFW_E_NOT_CONNECTED; - } - return m_Connected->EndFlush(); -} -// deliver NewSegment to connected pin -HRESULT -CBaseOutputPin::DeliverNewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate) -{ - if (m_Connected == NULL) { - return VFW_E_NOT_CONNECTED; - } - return m_Connected->NewSegment(tStart, tStop, dRate); -} - - -//===================================================================== -//===================================================================== -// Implements CBaseInputPin -//===================================================================== -//===================================================================== - - -/* Constructor creates a default allocator object */ - -CBaseInputPin::CBaseInputPin(TCHAR *pObjectName, - CBaseFilter *pFilter, - CCritSec *pLock, - HRESULT *phr, - LPCWSTR pPinName) : - CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT), - m_pAllocator(NULL), - m_bReadOnly(FALSE), - m_bFlushing(FALSE) -{ - ZeroMemory(&m_SampleProps, sizeof(m_SampleProps)); -} - -#ifdef UNICODE -CBaseInputPin::CBaseInputPin(CHAR *pObjectName, - CBaseFilter *pFilter, - CCritSec *pLock, - HRESULT *phr, - LPCWSTR pPinName) : - CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT), - m_pAllocator(NULL), - m_bReadOnly(FALSE), - m_bFlushing(FALSE) -{ - ZeroMemory(&m_SampleProps, sizeof(m_SampleProps)); -} -#endif - -/* Destructor releases it's reference count on the default allocator */ - -CBaseInputPin::~CBaseInputPin() -{ - if (m_pAllocator != NULL) { - m_pAllocator->Release(); - m_pAllocator = NULL; - } -} - - -// override this to publicise our interfaces -STDMETHODIMP -CBaseInputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv) -{ - /* Do we know about this interface */ - - if (riid == IID_IMemInputPin) { - return GetInterface((IMemInputPin *) this, ppv); - } else { - return CBasePin::NonDelegatingQueryInterface(riid, ppv); - } -} - - -/* Return the allocator interface that this input pin would like the output - pin to use. NOTE subsequent calls to GetAllocator should all return an - interface onto the SAME object so we create one object at the start - - Note: - The allocator is Release()'d on disconnect and replaced on - NotifyAllocator(). - - Override this to provide your own allocator. -*/ - -STDMETHODIMP -CBaseInputPin::GetAllocator( - IMemAllocator **ppAllocator) -{ - CheckPointer(ppAllocator,E_POINTER); - ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *)); - CAutoLock cObjectLock(m_pLock); - - if (m_pAllocator == NULL) { - HRESULT hr = CreateMemoryAllocator(&m_pAllocator); - if (FAILED(hr)) { - return hr; - } - } - ASSERT(m_pAllocator != NULL); - *ppAllocator = m_pAllocator; - m_pAllocator->AddRef(); - return NOERROR; -} - - -/* Tell the input pin which allocator the output pin is actually going to use - Override this if you care - NOTE the locking we do both here and also in - GetAllocator is unnecessary but derived classes that do something useful - will undoubtedly have to lock the object so this might help remind people */ - -STDMETHODIMP -CBaseInputPin::NotifyAllocator( - IMemAllocator * pAllocator, - BOOL bReadOnly) -{ - CheckPointer(pAllocator,E_POINTER); - ValidateReadPtr(pAllocator,sizeof(IMemAllocator)); - CAutoLock cObjectLock(m_pLock); - - IMemAllocator *pOldAllocator = m_pAllocator; - pAllocator->AddRef(); - m_pAllocator = pAllocator; - - if (pOldAllocator != NULL) { - pOldAllocator->Release(); - } - - // the readonly flag indicates whether samples from this allocator should - // be regarded as readonly - if true, then inplace transforms will not be - // allowed. - m_bReadOnly = (BYTE)bReadOnly; - return NOERROR; -} - - -HRESULT -CBaseInputPin::BreakConnect() -{ - /* We don't need our allocator any more */ - if (m_pAllocator) { - // Always decommit the allocator because a downstream filter may or - // may not decommit the connection's allocator. A memory leak could - // occur if the allocator is not decommited when a pin is disconnected. - HRESULT hr = m_pAllocator->Decommit(); - if( FAILED( hr ) ) { - return hr; - } - - m_pAllocator->Release(); - m_pAllocator = NULL; - } - - return S_OK; -} - - -/* Do something with this media sample - this base class checks to see if the - format has changed with this media sample and if so checks that the filter - will accept it, generating a run time error if not. Once we have raised a - run time error we set a flag so that no more samples will be accepted - - It is important that any filter should override this method and implement - synchronization so that samples are not processed when the pin is - disconnected etc -*/ - -STDMETHODIMP -CBaseInputPin::Receive(IMediaSample *pSample) -{ - CheckPointer(pSample,E_POINTER); - ValidateReadPtr(pSample,sizeof(IMediaSample)); - ASSERT(pSample); - - HRESULT hr = CheckStreaming(); - if (S_OK != hr) { - return hr; - } - - - - /* Check for IMediaSample2 */ - IMediaSample2 *pSample2; - if (SUCCEEDED(pSample->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) { - hr = pSample2->GetProperties(sizeof(m_SampleProps), (PBYTE)&m_SampleProps); - pSample2->Release(); - if (FAILED(hr)) { - return hr; - } - } else { - /* Get the properties the hard way */ - m_SampleProps.cbData = sizeof(m_SampleProps); - m_SampleProps.dwTypeSpecificFlags = 0; - m_SampleProps.dwStreamId = AM_STREAM_MEDIA; - m_SampleProps.dwSampleFlags = 0; - if (S_OK == pSample->IsDiscontinuity()) { - m_SampleProps.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY; - } - if (S_OK == pSample->IsPreroll()) { - m_SampleProps.dwSampleFlags |= AM_SAMPLE_PREROLL; - } - if (S_OK == pSample->IsSyncPoint()) { - m_SampleProps.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT; - } - if (SUCCEEDED(pSample->GetTime(&m_SampleProps.tStart, - &m_SampleProps.tStop))) { - m_SampleProps.dwSampleFlags |= AM_SAMPLE_TIMEVALID | - AM_SAMPLE_STOPVALID; - } - if (S_OK == pSample->GetMediaType(&m_SampleProps.pMediaType)) { - m_SampleProps.dwSampleFlags |= AM_SAMPLE_TYPECHANGED; - } - pSample->GetPointer(&m_SampleProps.pbBuffer); - m_SampleProps.lActual = pSample->GetActualDataLength(); - m_SampleProps.cbBuffer = pSample->GetSize(); - } - - /* Has the format changed in this sample */ - - if (!(m_SampleProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED)) { - return NOERROR; - } - - /* Check the derived class accepts this format */ - /* This shouldn't fail as the source must call QueryAccept first */ - - hr = CheckMediaType((CMediaType *)m_SampleProps.pMediaType); - - if (hr == NOERROR) { - return NOERROR; - } - - /* Raise a runtime error if we fail the media type */ - - m_bRunTimeError = TRUE; - EndOfStream(); - m_pFilter->NotifyEvent(EC_ERRORABORT,VFW_E_TYPE_NOT_ACCEPTED,0); - return VFW_E_INVALIDMEDIATYPE; -} - - -/* Receive multiple samples */ -STDMETHODIMP -CBaseInputPin::ReceiveMultiple ( - IMediaSample **pSamples, - long nSamples, - long *nSamplesProcessed) -{ - CheckPointer(pSamples,E_POINTER); - ValidateReadPtr(pSamples,nSamples * sizeof(IMediaSample *)); - - HRESULT hr = S_OK; - *nSamplesProcessed = 0; - while (nSamples-- > 0) { - hr = Receive(pSamples[*nSamplesProcessed]); - - /* S_FALSE means don't send any more */ - if (hr != S_OK) { - break; - } - (*nSamplesProcessed)++; - } - return hr; -} - -/* See if Receive() might block */ -STDMETHODIMP -CBaseInputPin::ReceiveCanBlock() -{ - /* Ask all the output pins if they block - If there are no output pin assume we do block - */ - int cPins = m_pFilter->GetPinCount(); - int cOutputPins = 0; - for (int c = 0; c < cPins; c++) { - CBasePin *pPin = m_pFilter->GetPin(c); - PIN_DIRECTION pd; - HRESULT hr = pPin->QueryDirection(&pd); - if (FAILED(hr)) { - return hr; - } - - if (pd == PINDIR_OUTPUT) { - - IPin *pConnected; - hr = pPin->ConnectedTo(&pConnected); - if (SUCCEEDED(hr)) { - ASSERT(pConnected != NULL); - cOutputPins++; - IMemInputPin *pInputPin; - hr = pConnected->QueryInterface( - IID_IMemInputPin, - (void **)&pInputPin); - pConnected->Release(); - if (SUCCEEDED(hr)) { - hr = pInputPin->ReceiveCanBlock(); - pInputPin->Release(); - if (hr != S_FALSE) { - return S_OK; - } - } else { - /* There's a transport we don't understand here */ - return S_OK; - } - } - } - } - return cOutputPins == 0 ? S_OK : S_FALSE; -} - -// Default handling for BeginFlush - call at the beginning -// of your implementation (makes sure that all Receive calls -// fail). After calling this, you need to free any queued data -// and then call downstream. -STDMETHODIMP -CBaseInputPin::BeginFlush(void) -{ - // BeginFlush is NOT synchronized with streaming but is part of - // a control action - hence we synchronize with the filter - CAutoLock lck(m_pLock); - - // if we are already in mid-flush, this is probably a mistake - // though not harmful - try to pick it up for now so I can think about it - ASSERT(!m_bFlushing); - - // first thing to do is ensure that no further Receive calls succeed - m_bFlushing = TRUE; - - // now discard any data and call downstream - must do that - // in derived classes - return S_OK; -} - -// default handling for EndFlush - call at end of your implementation -// - before calling this, ensure that there is no queued data and no thread -// pushing any more without a further receive, then call downstream, -// then call this method to clear the m_bFlushing flag and re-enable -// receives -STDMETHODIMP -CBaseInputPin::EndFlush(void) -{ - // Endlush is NOT synchronized with streaming but is part of - // a control action - hence we synchronize with the filter - CAutoLock lck(m_pLock); - - // almost certainly a mistake if we are not in mid-flush - ASSERT(m_bFlushing); - - // before calling, sync with pushing thread and ensure - // no more data is going downstream, then call EndFlush on - // downstream pins. - - // now re-enable Receives - m_bFlushing = FALSE; - - // No more errors - m_bRunTimeError = FALSE; - - return S_OK; -} - - -STDMETHODIMP -CBaseInputPin::Notify(IBaseFilter * pSender, Quality q) -{ - UNREFERENCED_PARAMETER(q); - CheckPointer(pSender,E_POINTER); - ValidateReadPtr(pSender,sizeof(IBaseFilter)); - DbgBreak("IQuality::Notify called on an input pin"); - return NOERROR; -} // Notify - -/* Free up or unprepare allocator's memory, this is called through - IMediaFilter which is responsible for locking the object first */ - -HRESULT -CBaseInputPin::Inactive(void) -{ - m_bRunTimeError = FALSE; - if (m_pAllocator == NULL) { - return VFW_E_NO_ALLOCATOR; - } - - m_bFlushing = FALSE; - - return m_pAllocator->Decommit(); -} - -// what requirements do we have of the allocator - override if you want -// to support other people's allocators but need a specific alignment -// or prefix. -STDMETHODIMP -CBaseInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES*pProps) -{ - UNREFERENCED_PARAMETER(pProps); - return E_NOTIMPL; -} - -// Check if it's OK to process data -// -HRESULT -CBaseInputPin::CheckStreaming() -{ - // Shouldn't be able to get any data if we're not connected! - ASSERT(IsConnected()); - - // Don't process stuff in Stopped state - if (IsStopped()) { - return VFW_E_WRONG_STATE; - } - if (m_bFlushing) { - return S_FALSE; - } - if (m_bRunTimeError) { - return VFW_E_RUNTIME_ERROR; - } - return S_OK; -} - -// Pass on the Quality notification q to -// a. Our QualityControl sink (if we have one) or else -// b. to our upstream filter -// and if that doesn't work, throw it away with a bad return code -HRESULT -CBaseInputPin::PassNotify(Quality& q) -{ - // We pass the message on, which means that we find the quality sink - // for our input pin and send it there - - DbgLog((LOG_TRACE,3,TEXT("Passing Quality notification through transform"))); - if (m_pQSink!=NULL) { - return m_pQSink->Notify(m_pFilter, q); - } else { - // no sink set, so pass it upstream - HRESULT hr; - IQualityControl * pIQC; - - hr = VFW_E_NOT_FOUND; // default - if (m_Connected) { - m_Connected->QueryInterface(IID_IQualityControl, (void**)&pIQC); - - if (pIQC!=NULL) { - hr = pIQC->Notify(m_pFilter, q); - pIQC->Release(); - } - } - return hr; - } - -} // PassNotify - -//===================================================================== -//===================================================================== -// Memory allocation class, implements CMediaSample -//===================================================================== -//===================================================================== - - -/* NOTE The implementation of this class calls the CUnknown constructor with - a NULL outer unknown pointer. This has the effect of making us a self - contained class, ie any QueryInterface, AddRef or Release calls will be - routed to the class's NonDelegatingUnknown methods. You will typically - find that the classes that do this then override one or more of these - virtual functions to provide more specialised behaviour. A good example - of this is where a class wants to keep the QueryInterface internal but - still wants it's lifetime controlled by the external object */ - -/* The last two parameters have default values of NULL and zero */ - -CMediaSample::CMediaSample(TCHAR *pName, - CBaseAllocator *pAllocator, - HRESULT *phr, - LPBYTE pBuffer, - LONG length) : - m_pBuffer(pBuffer), // Initialise the buffer - m_cbBuffer(length), // And it's length - m_lActual(length), // By default, actual = length - m_pMediaType(NULL), // No media type change - m_dwFlags(0), // Nothing set - m_cRef(0), // 0 ref count - m_dwTypeSpecificFlags(0), // Type specific flags - m_dwStreamId(AM_STREAM_MEDIA), // Stream id - m_pAllocator(pAllocator) // Allocator -{ - - /* We must have an owner and it must also be derived from class - CBaseAllocator BUT we do not hold a reference count on it */ - - ASSERT(pAllocator); -} - -#ifdef UNICODE -CMediaSample::CMediaSample(CHAR *pName, - CBaseAllocator *pAllocator, - HRESULT *phr, - LPBYTE pBuffer, - LONG length) : - m_pBuffer(pBuffer), // Initialise the buffer - m_cbBuffer(length), // And it's length - m_lActual(length), // By default, actual = length - m_pMediaType(NULL), // No media type change - m_dwFlags(0), // Nothing set - m_cRef(0), // 0 ref count - m_dwTypeSpecificFlags(0), // Type specific flags - m_dwStreamId(AM_STREAM_MEDIA), // Stream id - m_pAllocator(pAllocator) // Allocator -{ - - /* We must have an owner and it must also be derived from class - CBaseAllocator BUT we do not hold a reference count on it */ - - ASSERT(pAllocator); -} -#endif - -/* Destructor deletes the media type memory */ - -CMediaSample::~CMediaSample() -{ - - if (m_pMediaType) { - DeleteMediaType(m_pMediaType); - } -} - -/* Override this to publicise our interfaces */ - -STDMETHODIMP -CMediaSample::QueryInterface(REFIID riid, void **ppv) -{ - if (riid == IID_IMediaSample || - riid == IID_IMediaSample2 || - riid == IID_IUnknown) { - return GetInterface((IMediaSample *) this, ppv); - } else { - return E_NOINTERFACE; - } -} - -STDMETHODIMP_(ULONG) -CMediaSample::AddRef() -{ - return InterlockedIncrement(&m_cRef); -} - - -// -- CMediaSample lifetimes -- -// -// On final release of this sample buffer it is not deleted but -// returned to the freelist of the owning memory allocator -// -// The allocator may be waiting for the last buffer to be placed on the free -// list in order to decommit all the memory, so the ReleaseBuffer() call may -// result in this sample being deleted. We also need to hold a refcount on -// the allocator to stop that going away until we have finished with this. -// However, we cannot release the allocator before the ReleaseBuffer, as the -// release may cause us to be deleted. Similarly we can't do it afterwards. -// -// Thus we must leave it to the allocator to hold an addref on our behalf. -// When he issues us in GetBuffer, he addref's himself. When ReleaseBuffer -// is called, he releases himself, possibly causing us and him to be deleted. - - -STDMETHODIMP_(ULONG) -CMediaSample::Release() -{ - /* Decrement our own private reference count */ - LONG lRef; - if (m_cRef == 1) { - lRef = 0; - m_cRef = 0; - } else { - lRef = InterlockedDecrement(&m_cRef); - } - ASSERT(lRef >= 0); - - DbgLog((LOG_MEMORY,3,TEXT(" Unknown %X ref-- = %d"), - this, m_cRef)); - - /* Did we release our final reference count */ - if (lRef == 0) { - /* Free all resources */ - if (m_dwFlags & Sample_TypeChanged) { - SetMediaType(NULL); - } - ASSERT(m_pMediaType == NULL); - m_dwFlags = 0; - m_dwTypeSpecificFlags = 0; - m_dwStreamId = AM_STREAM_MEDIA; - - /* This may cause us to be deleted */ - // Our refcount is reliably 0 thus no-one will mess with us - m_pAllocator->ReleaseBuffer(this); - } - return (ULONG)lRef; -} - - -// set the buffer pointer and length. Used by allocators that -// want variable sized pointers or pointers into already-read data. -// This is only available through a CMediaSample* not an IMediaSample* -// and so cannot be changed by clients. -HRESULT -CMediaSample::SetPointer(BYTE * ptr, LONG cBytes) -{ - m_pBuffer = ptr; // new buffer area (could be null) - m_cbBuffer = cBytes; // length of buffer - m_lActual = cBytes; // length of data in buffer (assume full) - - return S_OK; -} - - -// get me a read/write pointer to this buffer's memory. I will actually -// want to use sizeUsed bytes. -STDMETHODIMP -CMediaSample::GetPointer(BYTE ** ppBuffer) -{ - ValidateReadWritePtr(ppBuffer,sizeof(BYTE *)); - - // creator must have set pointer either during - // constructor or by SetPointer - ASSERT(m_pBuffer); - - *ppBuffer = m_pBuffer; - return NOERROR; -} - - -// return the size in bytes of this buffer -STDMETHODIMP_(LONG) -CMediaSample::GetSize(void) -{ - return m_cbBuffer; -} - - -// get the stream time at which this sample should start and finish. -STDMETHODIMP -CMediaSample::GetTime( - REFERENCE_TIME * pTimeStart, // put time here - REFERENCE_TIME * pTimeEnd -) -{ - ValidateReadWritePtr(pTimeStart,sizeof(REFERENCE_TIME)); - ValidateReadWritePtr(pTimeEnd,sizeof(REFERENCE_TIME)); - - if (!(m_dwFlags & Sample_StopValid)) { - if (!(m_dwFlags & Sample_TimeValid)) { - return VFW_E_SAMPLE_TIME_NOT_SET; - } else { - *pTimeStart = m_Start; - - // Make sure old stuff works - *pTimeEnd = m_Start + 1; - return VFW_S_NO_STOP_TIME; - } - } - - *pTimeStart = m_Start; - *pTimeEnd = m_End; - return NOERROR; -} - - -// Set the stream time at which this sample should start and finish. -// NULL pointers means the time is reset -STDMETHODIMP -CMediaSample::SetTime( - REFERENCE_TIME * pTimeStart, - REFERENCE_TIME * pTimeEnd -) -{ - if (pTimeStart == NULL) { - ASSERT(pTimeEnd == NULL); - m_dwFlags &= ~(Sample_TimeValid | Sample_StopValid); - } else { - if (pTimeEnd == NULL) { - m_Start = *pTimeStart; - m_dwFlags |= Sample_TimeValid; - m_dwFlags &= ~Sample_StopValid; - } else { - ValidateReadPtr(pTimeStart,sizeof(REFERENCE_TIME)); - ValidateReadPtr(pTimeEnd,sizeof(REFERENCE_TIME)); - ASSERT(*pTimeEnd >= *pTimeStart); - - m_Start = *pTimeStart; - m_End = *pTimeEnd; - m_dwFlags |= Sample_TimeValid | Sample_StopValid; - } - } - return NOERROR; -} - - -// get the media times (eg bytes) for this sample -STDMETHODIMP -CMediaSample::GetMediaTime( - LONGLONG * pTimeStart, - LONGLONG * pTimeEnd -) -{ - ValidateReadWritePtr(pTimeStart,sizeof(LONGLONG)); - ValidateReadWritePtr(pTimeEnd,sizeof(LONGLONG)); - - if (!(m_dwFlags & Sample_MediaTimeValid)) { - return VFW_E_MEDIA_TIME_NOT_SET; - } - - *pTimeStart = m_MediaStart; - *pTimeEnd = (m_MediaStart + m_MediaEnd); - return NOERROR; -} - - -// Set the media times for this sample -STDMETHODIMP -CMediaSample::SetMediaTime( - LONGLONG * pTimeStart, - LONGLONG * pTimeEnd -) -{ - if (pTimeStart == NULL) { - ASSERT(pTimeEnd == NULL); - m_dwFlags &= ~Sample_MediaTimeValid; - } else { - ValidateReadPtr(pTimeStart,sizeof(LONGLONG)); - ValidateReadPtr(pTimeEnd,sizeof(LONGLONG)); - ASSERT(*pTimeEnd >= *pTimeStart); - - m_MediaStart = *pTimeStart; - m_MediaEnd = (LONG)(*pTimeEnd - *pTimeStart); - m_dwFlags |= Sample_MediaTimeValid; - } - return NOERROR; -} - - -STDMETHODIMP -CMediaSample::IsSyncPoint(void) -{ - if (m_dwFlags & Sample_SyncPoint) { - return S_OK; - } else { - return S_FALSE; - } -} - - -STDMETHODIMP -CMediaSample::SetSyncPoint(BOOL bIsSyncPoint) -{ - if (bIsSyncPoint) { - m_dwFlags |= Sample_SyncPoint; - } else { - m_dwFlags &= ~Sample_SyncPoint; - } - return NOERROR; -} - -// returns S_OK if there is a discontinuity in the data (this same is -// not a continuation of the previous stream of data -// - there has been a seek). -STDMETHODIMP -CMediaSample::IsDiscontinuity(void) -{ - if (m_dwFlags & Sample_Discontinuity) { - return S_OK; - } else { - return S_FALSE; - } -} - -// set the discontinuity property - TRUE if this sample is not a -// continuation, but a new sample after a seek. -STDMETHODIMP -CMediaSample::SetDiscontinuity(BOOL bDiscont) -{ - // should be TRUE or FALSE - if (bDiscont) { - m_dwFlags |= Sample_Discontinuity; - } else { - m_dwFlags &= ~Sample_Discontinuity; - } - return S_OK; -} - -STDMETHODIMP -CMediaSample::IsPreroll(void) -{ - if (m_dwFlags & Sample_Preroll) { - return S_OK; - } else { - return S_FALSE; - } -} - - -STDMETHODIMP -CMediaSample::SetPreroll(BOOL bIsPreroll) -{ - if (bIsPreroll) { - m_dwFlags |= Sample_Preroll; - } else { - m_dwFlags &= ~Sample_Preroll; - } - return NOERROR; -} - -STDMETHODIMP_(LONG) -CMediaSample::GetActualDataLength(void) -{ - return m_lActual; -} - - -STDMETHODIMP -CMediaSample::SetActualDataLength(LONG lActual) -{ - if (lActual > m_cbBuffer) { - ASSERT(lActual <= GetSize()); - return VFW_E_BUFFER_OVERFLOW; - } - m_lActual = lActual; - return NOERROR; -} - - -/* These allow for limited format changes in band */ - -STDMETHODIMP -CMediaSample::GetMediaType(AM_MEDIA_TYPE **ppMediaType) -{ - ValidateReadWritePtr(ppMediaType,sizeof(AM_MEDIA_TYPE *)); - ASSERT(ppMediaType); - - /* Do we have a new media type for them */ - - if (!(m_dwFlags & Sample_TypeChanged)) { - ASSERT(m_pMediaType == NULL); - *ppMediaType = NULL; - return S_FALSE; - } - - ASSERT(m_pMediaType); - - /* Create a copy of our media type */ - - *ppMediaType = CreateMediaType(m_pMediaType); - if (*ppMediaType == NULL) { - return E_OUTOFMEMORY; - } - return NOERROR; -} - - -/* Mark this sample as having a different format type */ - -STDMETHODIMP -CMediaSample::SetMediaType(AM_MEDIA_TYPE *pMediaType) -{ - /* Delete the current media type */ - - if (m_pMediaType) { - DeleteMediaType(m_pMediaType); - m_pMediaType = NULL; - } - - /* Mechanism for resetting the format type */ - - if (pMediaType == NULL) { - m_dwFlags &= ~Sample_TypeChanged; - return NOERROR; - } - - ASSERT(pMediaType); - ValidateReadPtr(pMediaType,sizeof(AM_MEDIA_TYPE)); - - /* Take a copy of the media type */ - - m_pMediaType = CreateMediaType(pMediaType); - if (m_pMediaType == NULL) { - m_dwFlags &= ~Sample_TypeChanged; - return E_OUTOFMEMORY; - } - - m_dwFlags |= Sample_TypeChanged; - return NOERROR; -} - -// Set and get properties (IMediaSample2) -STDMETHODIMP CMediaSample::GetProperties( - DWORD cbProperties, - BYTE * pbProperties -) -{ - if (0 != cbProperties) { - CheckPointer(pbProperties, E_POINTER); - // Return generic stuff up to the length - AM_SAMPLE2_PROPERTIES Props; - Props.cbData = (DWORD) (min(cbProperties, sizeof(Props))); - Props.dwSampleFlags = m_dwFlags & ~Sample_MediaTimeValid; - Props.dwTypeSpecificFlags = m_dwTypeSpecificFlags; - Props.pbBuffer = m_pBuffer; - Props.cbBuffer = m_cbBuffer; - Props.lActual = m_lActual; - Props.tStart = m_Start; - Props.tStop = m_End; - Props.dwStreamId = m_dwStreamId; - if (m_dwFlags & AM_SAMPLE_TYPECHANGED) { - Props.pMediaType = m_pMediaType; - } else { - Props.pMediaType = NULL; - } - CopyMemory(pbProperties, &Props, Props.cbData); - } - return S_OK; -} - -#define CONTAINS_FIELD(type, field, offset) \ - ((FIELD_OFFSET(type, field) + sizeof(((type *)0)->field)) <= offset) - -HRESULT CMediaSample::SetProperties( - DWORD cbProperties, - const BYTE * pbProperties -) -{ - - /* Generic properties */ - AM_MEDIA_TYPE *pMediaType = NULL; - - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbData, cbProperties)) { - CheckPointer(pbProperties, E_POINTER); - AM_SAMPLE2_PROPERTIES *pProps = - (AM_SAMPLE2_PROPERTIES *)pbProperties; - - /* Don't use more data than is actually there */ - if (pProps->cbData < cbProperties) { - cbProperties = pProps->cbData; - } - /* We only handle IMediaSample2 */ - if (cbProperties > sizeof(*pProps) || - pProps->cbData > sizeof(*pProps)) { - return E_INVALIDARG; - } - /* Do checks first, the assignments (for backout) */ - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) { - /* Check the flags */ - if (pProps->dwSampleFlags & - (~Sample_ValidFlags | Sample_MediaTimeValid)) { - return E_INVALIDARG; - } - /* Check a flag isn't being set for a property - not being provided - */ - if ((pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) && - !(m_dwFlags & AM_SAMPLE_TIMEVALID) && - !CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) { - return E_INVALIDARG; - } - } - /* NB - can't SET the pointer or size */ - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pbBuffer, cbProperties)) { - - /* Check pbBuffer */ - if (pProps->pbBuffer != 0 && pProps->pbBuffer != m_pBuffer) { - return E_INVALIDARG; - } - } - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties)) { - - /* Check cbBuffer */ - if (pProps->cbBuffer != 0 && pProps->cbBuffer != m_cbBuffer) { - return E_INVALIDARG; - } - } - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties) && - CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) { - - /* Check lActual */ - if (pProps->cbBuffer < pProps->lActual) { - return E_INVALIDARG; - } - } - - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) { - - /* Check pMediaType */ - if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) { - CheckPointer(pProps->pMediaType, E_POINTER); - pMediaType = CreateMediaType(pProps->pMediaType); - if (pMediaType == NULL) { - return E_OUTOFMEMORY; - } - } - } - - /* Now do the assignments */ - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwStreamId, cbProperties)) { - m_dwStreamId = pProps->dwStreamId; - } - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) { - /* Set the flags */ - m_dwFlags = pProps->dwSampleFlags | - (m_dwFlags & Sample_MediaTimeValid); - m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; - } else { - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwTypeSpecificFlags, cbProperties)) { - m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; - } - } - - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) { - /* Set lActual */ - m_lActual = pProps->lActual; - } - - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) { - - /* Set the times */ - m_End = pProps->tStop; - } - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStart, cbProperties)) { - - /* Set the times */ - m_Start = pProps->tStart; - } - - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) { - /* Set pMediaType */ - if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) { - if (m_pMediaType != NULL) { - DeleteMediaType(m_pMediaType); - } - m_pMediaType = pMediaType; - } - } - - /* Fix up the type changed flag to correctly reflect the current state - If, for instance the input contained no type change but the - output does then if we don't do this we'd lose the - output media type. - */ - if (m_pMediaType) { - m_dwFlags |= Sample_TypeChanged; - } else { - m_dwFlags &= ~Sample_TypeChanged; - } - } - - return S_OK; -} - - -// -// The streaming thread calls IPin::NewSegment(), IPin::EndOfStream(), -// IMemInputPin::Receive() and IMemInputPin::ReceiveMultiple() on the -// connected input pin. The application thread calls Block(). The -// following class members can only be called by the streaming thread. -// -// Deliver() -// DeliverNewSegment() -// StartUsingOutputPin() -// StopUsingOutputPin() -// ChangeOutputFormat() -// ChangeMediaType() -// DynamicReconnect() -// -// The following class members can only be called by the application thread. -// -// Block() -// SynchronousBlockOutputPin() -// AsynchronousBlockOutputPin() -// - -CDynamicOutputPin::CDynamicOutputPin( - TCHAR *pObjectName, - CBaseFilter *pFilter, - CCritSec *pLock, - HRESULT *phr, - LPCWSTR pName) : - CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName), - m_hStopEvent(NULL), - m_pGraphConfig(NULL), - m_bPinUsesReadOnlyAllocator(FALSE), - m_BlockState(NOT_BLOCKED), - m_hUnblockOutputPinEvent(NULL), - m_hNotifyCallerPinBlockedEvent(NULL), - m_dwBlockCallerThreadID(0), - m_dwNumOutstandingOutputPinUsers(0) -{ - HRESULT hr = Initialize(); - if( FAILED( hr ) ) { - *phr = hr; - return; - } -} - -#ifdef UNICODE -CDynamicOutputPin::CDynamicOutputPin( - CHAR *pObjectName, - CBaseFilter *pFilter, - CCritSec *pLock, - HRESULT *phr, - LPCWSTR pName) : - CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName), - m_hStopEvent(NULL), - m_pGraphConfig(NULL), - m_bPinUsesReadOnlyAllocator(FALSE), - m_BlockState(NOT_BLOCKED), - m_hUnblockOutputPinEvent(NULL), - m_hNotifyCallerPinBlockedEvent(NULL), - m_dwBlockCallerThreadID(0), - m_dwNumOutstandingOutputPinUsers(0) -{ - HRESULT hr = Initialize(); - if( FAILED( hr ) ) { - *phr = hr; - return; - } -} -#endif - -CDynamicOutputPin::~CDynamicOutputPin() -{ - if(NULL != m_hUnblockOutputPinEvent) { - // This call should not fail because we have access to m_hUnblockOutputPinEvent - // and m_hUnblockOutputPinEvent is a valid event. - EXECUTE_ASSERT(::CloseHandle(m_hUnblockOutputPinEvent)); - } - - if(NULL != m_hNotifyCallerPinBlockedEvent) { - // This call should not fail because we have access to m_hNotifyCallerPinBlockedEvent - // and m_hNotifyCallerPinBlockedEvent is a valid event. - EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); - } -} - -HRESULT CDynamicOutputPin::Initialize(void) -{ - m_hUnblockOutputPinEvent = ::CreateEvent( NULL, // The event will have the default security descriptor. - TRUE, // This is a manual reset event. - TRUE, // The event is initially signaled. - NULL ); // The event is not named. - - // CreateEvent() returns NULL if an error occurs. - if(NULL == m_hUnblockOutputPinEvent) { - return AmGetLastErrorToHResult(); - } - - // Set flag to say we can reconnect while streaming. - SetReconnectWhenActive(true); - - return S_OK; -} - -STDMETHODIMP CDynamicOutputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv) -{ - if(riid == IID_IPinFlowControl) { - return GetInterface(static_cast(this), ppv); - } else { - return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv); - } -} - -STDMETHODIMP CDynamicOutputPin::Disconnect(void) -{ - CAutoLock cObjectLock(m_pLock); - return DisconnectInternal(); -} - -STDMETHODIMP CDynamicOutputPin::Block(DWORD dwBlockFlags, HANDLE hEvent) -{ - const DWORD VALID_FLAGS = AM_PIN_FLOW_CONTROL_BLOCK; - - // Check for illegal flags. - if(dwBlockFlags & ~VALID_FLAGS) { - return E_INVALIDARG; - } - - // Make sure the event is unsignaled. - if((dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) && (NULL != hEvent)) { - if( !::ResetEvent( hEvent ) ) { - return AmGetLastErrorToHResult(); - } - } - - // No flags are set if we are unblocking the output pin. - if(0 == dwBlockFlags) { - - // This parameter should be NULL because unblock operations are always synchronous. - // There is no need to notify the caller when the event is done. - if(NULL != hEvent) { - return E_INVALIDARG; - } - } - - #ifdef DEBUG - AssertValid(); - #endif // DEBUG - - HRESULT hr; - - if(dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) { - // IPinFlowControl::Block()'s hEvent parameter is NULL if the block is synchronous. - // If hEvent is not NULL, the block is asynchronous. - if(NULL == hEvent) { - hr = SynchronousBlockOutputPin(); - } else { - hr = AsynchronousBlockOutputPin(hEvent); - } - } else { - hr = UnblockOutputPin(); - } - - #ifdef DEBUG - AssertValid(); - #endif // DEBUG - - if(FAILED(hr)) { - return hr; - } - - return S_OK; -} - -HRESULT CDynamicOutputPin::SynchronousBlockOutputPin(void) -{ - HANDLE hNotifyCallerPinBlockedEvent = :: CreateEvent( NULL, // The event will have the default security attributes. - FALSE, // This is an automatic reset event. - FALSE, // The event is initially unsignaled. - NULL ); // The event is not named. - - // CreateEvent() returns NULL if an error occurs. - if(NULL == hNotifyCallerPinBlockedEvent) { - return AmGetLastErrorToHResult(); - } - - HRESULT hr = AsynchronousBlockOutputPin(hNotifyCallerPinBlockedEvent); - if(FAILED(hr)) { - // This call should not fail because we have access to hNotifyCallerPinBlockedEvent - // and hNotifyCallerPinBlockedEvent is a valid event. - EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent)); - - return hr; - } - - hr = WaitEvent(hNotifyCallerPinBlockedEvent); - - // This call should not fail because we have access to hNotifyCallerPinBlockedEvent - // and hNotifyCallerPinBlockedEvent is a valid event. - EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent)); - - if(FAILED(hr)) { - return hr; - } - - return S_OK; -} - -HRESULT CDynamicOutputPin::AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent) -{ - // This function holds the m_BlockStateLock because it uses - // m_dwBlockCallerThreadID, m_BlockState and - // m_hNotifyCallerPinBlockedEvent. - CAutoLock alBlockStateLock(&m_BlockStateLock); - - if(NOT_BLOCKED != m_BlockState) { - if(m_dwBlockCallerThreadID == ::GetCurrentThreadId()) { - return VFW_E_PIN_ALREADY_BLOCKED_ON_THIS_THREAD; - } else { - return VFW_E_PIN_ALREADY_BLOCKED; - } - } - - BOOL fSuccess = ::DuplicateHandle( ::GetCurrentProcess(), - hNotifyCallerPinBlockedEvent, - ::GetCurrentProcess(), - &m_hNotifyCallerPinBlockedEvent, - EVENT_MODIFY_STATE, - FALSE, - 0 ); - if( !fSuccess ) { - return AmGetLastErrorToHResult(); - } - - m_BlockState = PENDING; - m_dwBlockCallerThreadID = ::GetCurrentThreadId(); - - // The output pin cannot be blocked if the streaming thread is - // calling IPin::NewSegment(), IPin::EndOfStream(), IMemInputPin::Receive() - // or IMemInputPin::ReceiveMultiple() on the connected input pin. Also, it - // cannot be blocked if the streaming thread is calling DynamicReconnect(), - // ChangeMediaType() or ChangeOutputFormat(). - if(!StreamingThreadUsingOutputPin()) { - - // The output pin can be immediately blocked. - BlockOutputPin(); - } - - return S_OK; -} - -void CDynamicOutputPin::BlockOutputPin(void) -{ - // The caller should always hold the m_BlockStateLock because this function - // uses m_BlockState and m_hNotifyCallerPinBlockedEvent. - ASSERT(CritCheckIn(&m_BlockStateLock)); - - // This function should not be called if the streaming thread is modifying - // the connection state or it's passing data downstream. - ASSERT(!StreamingThreadUsingOutputPin()); - - // This should not fail because we successfully created the event - // and we have the security permissions to change it's state. - EXECUTE_ASSERT(::ResetEvent(m_hUnblockOutputPinEvent)); - - // This event should not fail because AsynchronousBlockOutputPin() successfully - // duplicated this handle and we have the appropriate security permissions. - EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent)); - EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); - - m_BlockState = BLOCKED; - m_hNotifyCallerPinBlockedEvent = NULL; -} - -HRESULT CDynamicOutputPin::UnblockOutputPin(void) -{ - // UnblockOutputPin() holds the m_BlockStateLock because it - // uses m_BlockState, m_dwBlockCallerThreadID and - // m_hNotifyCallerPinBlockedEvent. - CAutoLock alBlockStateLock(&m_BlockStateLock); - - if(NOT_BLOCKED == m_BlockState) { - return S_FALSE; - } - - // This should not fail because we successfully created the event - // and we have the security permissions to change it's state. - EXECUTE_ASSERT(::SetEvent(m_hUnblockOutputPinEvent)); - - // Cancel the block operation if it's still pending. - if(NULL != m_hNotifyCallerPinBlockedEvent) { - // This event should not fail because AsynchronousBlockOutputPin() successfully - // duplicated this handle and we have the appropriate security permissions. - EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent)); - EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); - } - - m_BlockState = NOT_BLOCKED; - m_dwBlockCallerThreadID = 0; - m_hNotifyCallerPinBlockedEvent = NULL; - - return S_OK; -} - -HRESULT CDynamicOutputPin::StartUsingOutputPin(void) -{ - // The caller should not hold m_BlockStateLock. If the caller does, - // a deadlock could occur. - ASSERT(CritCheckOut(&m_BlockStateLock)); - - CAutoLock alBlockStateLock(&m_BlockStateLock); - - #ifdef DEBUG - AssertValid(); - #endif // DEBUG - - // Are we in the middle of a block operation? - while(BLOCKED == m_BlockState) { - m_BlockStateLock.Unlock(); - - // If this ASSERT fires, a deadlock could occur. The caller should make sure - // that this thread never acquires the Block State lock more than once. - ASSERT(CritCheckOut( &m_BlockStateLock )); - - // WaitForMultipleObjects() returns WAIT_OBJECT_0 if the unblock event - // is fired. It returns WAIT_OBJECT_0 + 1 if the stop event if fired. - // See the Windows SDK documentation for more information on - // WaitForMultipleObjects(). - const DWORD UNBLOCK = WAIT_OBJECT_0; - const DWORD STOP = WAIT_OBJECT_0 + 1; - - HANDLE ahWaitEvents[] = { m_hUnblockOutputPinEvent, m_hStopEvent }; - DWORD dwNumWaitEvents = sizeof(ahWaitEvents)/sizeof(HANDLE); - - DWORD dwReturnValue = ::WaitForMultipleObjects( dwNumWaitEvents, ahWaitEvents, FALSE, INFINITE ); - - m_BlockStateLock.Lock(); - - #ifdef DEBUG - AssertValid(); - #endif // DEBUG - - switch( dwReturnValue ) { - case UNBLOCK: - break; - - case STOP: - return VFW_E_STATE_CHANGED; - - case WAIT_FAILED: - return AmGetLastErrorToHResult(); - - default: - DbgBreak( "An Unexpected case occured in CDynamicOutputPin::StartUsingOutputPin()." ); - return E_UNEXPECTED; - } - } - - m_dwNumOutstandingOutputPinUsers++; - - #ifdef DEBUG - AssertValid(); - #endif // DEBUG - - return S_OK; -} - -void CDynamicOutputPin::StopUsingOutputPin(void) -{ - CAutoLock alBlockStateLock(&m_BlockStateLock); - - #ifdef DEBUG - AssertValid(); - #endif // DEBUG - - m_dwNumOutstandingOutputPinUsers--; - - if((m_dwNumOutstandingOutputPinUsers == 0) && (NOT_BLOCKED != m_BlockState)) { - BlockOutputPin(); - } - - #ifdef DEBUG - AssertValid(); - #endif // DEBUG -} - -bool CDynamicOutputPin::StreamingThreadUsingOutputPin(void) -{ - CAutoLock alBlockStateLock(&m_BlockStateLock); - - return (m_dwNumOutstandingOutputPinUsers > 0); -} - -void CDynamicOutputPin::SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent) -{ - // This pointer is not addrefed because filters are not allowed to - // hold references to the filter graph manager. See the documentation for - // IBaseFilter::JoinFilterGraph() in the Direct Show SDK for more information. - m_pGraphConfig = pGraphConfig; - - m_hStopEvent = hStopEvent; -} - -HRESULT CDynamicOutputPin::Active(void) -{ - // Make sure the user initialized the object by calling SetConfigInfo(). - if((NULL == m_hStopEvent) || (NULL == m_pGraphConfig)) { - DbgBreak( ERROR: CDynamicOutputPin::Active() failed because m_pGraphConfig and m_hStopEvent were not initialized. Call SetConfigInfo() to initialize them. ); - return E_FAIL; - } - - // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). - // The ASSERT can also fire if the event if destroyed and then Active() is called. An event - // handle is invalid if 1) the event does not exist or the user does not have the security - // permissions to use the event. - EXECUTE_ASSERT(ResetEvent(m_hStopEvent)); - - return CBaseOutputPin::Active(); -} - -HRESULT CDynamicOutputPin::Inactive(void) -{ - // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). - // The ASSERT can also fire if the event if destroyed and then Active() is called. An event - // handle is invalid if 1) the event does not exist or the user does not have the security - // permissions to use the event. - EXECUTE_ASSERT(SetEvent(m_hStopEvent)); - - return CBaseOutputPin::Inactive(); -} - -HRESULT CDynamicOutputPin::DeliverBeginFlush(void) -{ - // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). - // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called. - // An event handle is invalid if 1) the event does not exist or the user does not have the security - // permissions to use the event. - EXECUTE_ASSERT(SetEvent(m_hStopEvent)); - - return CBaseOutputPin::DeliverBeginFlush(); -} - -HRESULT CDynamicOutputPin::DeliverEndFlush(void) -{ - // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). - // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called. - // An event handle is invalid if 1) the event does not exist or the user does not have the security - // permissions to use the event. - EXECUTE_ASSERT(ResetEvent(m_hStopEvent)); - - return CBaseOutputPin::DeliverEndFlush(); -} - - -// ChangeOutputFormat() either dynamicly changes the connection's format type or it dynamicly -// reconnects the output pin. -HRESULT CDynamicOutputPin::ChangeOutputFormat - ( - const AM_MEDIA_TYPE *pmt, - REFERENCE_TIME tSegmentStart, - REFERENCE_TIME tSegmentStop, - double dSegmentRate - ) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT(StreamingThreadUsingOutputPin()); - - // Callers should always pass a valid media type to ChangeOutputFormat() . - ASSERT(NULL != pmt); - - CMediaType cmt(*pmt); - HRESULT hr = ChangeMediaType(&cmt); - if (FAILED(hr)) { - return hr; - } - - hr = DeliverNewSegment(tSegmentStart, tSegmentStop, dSegmentRate); - if( FAILED( hr ) ) { - return hr; - } - - return S_OK; -} - -HRESULT CDynamicOutputPin::ChangeMediaType(const CMediaType *pmt) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT(StreamingThreadUsingOutputPin()); - - // This function assumes the filter graph is running. - ASSERT(!IsStopped()); - - if(!IsConnected()) { - return VFW_E_NOT_CONNECTED; - } - - /* First check if the downstream pin will accept a dynamic - format change - */ - QzCComPtr pConnection; - - m_Connected->QueryInterface(IID_IPinConnection, (void **)&pConnection); - if(pConnection != NULL) { - - if(S_OK == pConnection->DynamicQueryAccept(pmt)) { - - HRESULT hr = ChangeMediaTypeHelper(pmt); - if(FAILED(hr)) { - return hr; - } - - return S_OK; - } - } - - /* Can't do the dynamic connection */ - return DynamicReconnect(pmt); -} - -HRESULT CDynamicOutputPin::ChangeMediaTypeHelper(const CMediaType *pmt) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT(StreamingThreadUsingOutputPin()); - - HRESULT hr = m_Connected->ReceiveConnection(this, pmt); - if(FAILED(hr)) { - return hr; - } - - hr = SetMediaType(pmt); - if(FAILED(hr)) { - return hr; - } - - // Does this pin use the local memory transport? - if(NULL != m_pInputPin) { - // This function assumes that m_pInputPin and m_Connected are - // two different interfaces to the same object. - ASSERT(::IsEqualObject(m_Connected, m_pInputPin)); - - ALLOCATOR_PROPERTIES apInputPinRequirements; - apInputPinRequirements.cbAlign = 0; - apInputPinRequirements.cbBuffer = 0; - apInputPinRequirements.cbPrefix = 0; - apInputPinRequirements.cBuffers = 0; - - m_pInputPin->GetAllocatorRequirements(&apInputPinRequirements); - - // A zero allignment does not make any sense. - if(0 == apInputPinRequirements.cbAlign) { - apInputPinRequirements.cbAlign = 1; - } - - hr = m_pAllocator->Decommit(); - if(FAILED(hr)) { - return hr; - } - - hr = DecideBufferSize(m_pAllocator, &apInputPinRequirements); - if(FAILED(hr)) { - return hr; - } - - hr = m_pAllocator->Commit(); - if(FAILED(hr)) { - return hr; - } - - hr = m_pInputPin->NotifyAllocator(m_pAllocator, m_bPinUsesReadOnlyAllocator); - if(FAILED(hr)) { - return hr; - } - } - - return S_OK; -} - -// this method has to be called from the thread that is pushing data, -// and it's the caller's responsibility to make sure that the thread -// has no outstand samples because they cannot be delivered after a -// reconnect -// -HRESULT CDynamicOutputPin::DynamicReconnect( const CMediaType* pmt ) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT(StreamingThreadUsingOutputPin()); - - if((m_pGraphConfig == NULL) || (NULL == m_hStopEvent)) { - return E_FAIL; - } - - HRESULT hr = m_pGraphConfig->Reconnect( - this, - NULL, - pmt, - NULL, - m_hStopEvent, - AM_GRAPH_CONFIG_RECONNECT_CACHE_REMOVED_FILTERS ); - - return hr; -} - -HRESULT CDynamicOutputPin::CompleteConnect(IPin *pReceivePin) -{ - HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin); - if(SUCCEEDED(hr)) { - if(!IsStopped() && m_pAllocator) { - hr = m_pAllocator->Commit(); - ASSERT(hr != VFW_E_ALREADY_COMMITTED); - } - } - - return hr; -} - -#ifdef DEBUG -void CDynamicOutputPin::AssertValid(void) -{ - // Make sure the object was correctly initialized. - - // This ASSERT only fires if the object failed to initialize - // and the user ignored the constructor's return code (phr). - ASSERT(NULL != m_hUnblockOutputPinEvent); - - // If either of these ASSERTs fire, the user did not correctly call - // SetConfigInfo(). - ASSERT(NULL != m_hStopEvent); - ASSERT(NULL != m_pGraphConfig); - - // Make sure the block state is consistent. - - CAutoLock alBlockStateLock(&m_BlockStateLock); - - // BLOCK_STATE variables only have three legal values: PENDING, BLOCKED and NOT_BLOCKED. - ASSERT((NOT_BLOCKED == m_BlockState) || (PENDING == m_BlockState) || (BLOCKED == m_BlockState)); - - // m_hNotifyCallerPinBlockedEvent is only needed when a block operation cannot complete - // immediately. - ASSERT(((NULL == m_hNotifyCallerPinBlockedEvent) && (PENDING != m_BlockState)) || - ((NULL != m_hNotifyCallerPinBlockedEvent) && (PENDING == m_BlockState)) ); - - // m_dwBlockCallerThreadID should always be 0 if the pin is not blocked and - // the user is not trying to block the pin. - ASSERT((0 == m_dwBlockCallerThreadID) || (NOT_BLOCKED != m_BlockState)); - - // If this ASSERT fires, the streaming thread is using the output pin and the - // output pin is blocked. - ASSERT(((0 != m_dwNumOutstandingOutputPinUsers) && (BLOCKED != m_BlockState)) || - ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED != m_BlockState)) || - ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED == m_BlockState)) ); -} -#endif // DEBUG - -HRESULT CDynamicOutputPin::WaitEvent(HANDLE hEvent) -{ - const DWORD EVENT_SIGNALED = WAIT_OBJECT_0; - - DWORD dwReturnValue = ::WaitForSingleObject(hEvent, INFINITE); - - switch( dwReturnValue ) { - case EVENT_SIGNALED: - return S_OK; - - case WAIT_FAILED: - return AmGetLastErrorToHResult(); - - default: - DbgBreak( "An Unexpected case occured in CDynamicOutputPin::WaitEvent()." ); - return E_UNEXPECTED; - } -} - -//===================================================================== -//===================================================================== -// Implements CBaseAllocator -//===================================================================== -//===================================================================== - - -/* Constructor overrides the default settings for the free list to request - that it be alertable (ie the list can be cast to a handle which can be - passed to WaitForSingleObject). Both of the allocator lists also ask for - object locking, the all list matches the object default settings but I - have included them here just so it is obvious what kind of list it is */ - -CBaseAllocator::CBaseAllocator(TCHAR *pName, - LPUNKNOWN pUnk, - HRESULT *phr, - BOOL bEvent, - BOOL fEnableReleaseCallback - ) : - CUnknown(pName, pUnk), - m_lAllocated(0), - m_bChanged(FALSE), - m_bCommitted(FALSE), - m_bDecommitInProgress(FALSE), - m_lSize(0), - m_lCount(0), - m_lAlignment(0), - m_lPrefix(0), - m_hSem(NULL), - m_lWaiting(0), - m_fEnableReleaseCallback(fEnableReleaseCallback), - m_pNotify(NULL) -{ - - if (bEvent) { - m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); - if (m_hSem == NULL) { - *phr = E_OUTOFMEMORY; - return; - } - } -} - -#ifdef UNICODE -CBaseAllocator::CBaseAllocator(CHAR *pName, - LPUNKNOWN pUnk, - HRESULT *phr, - BOOL bEvent, - BOOL fEnableReleaseCallback) : - CUnknown(pName, pUnk), - m_lAllocated(0), - m_bChanged(FALSE), - m_bCommitted(FALSE), - m_bDecommitInProgress(FALSE), - m_lSize(0), - m_lCount(0), - m_lAlignment(0), - m_lPrefix(0), - m_hSem(NULL), - m_lWaiting(0), - m_fEnableReleaseCallback(fEnableReleaseCallback), - m_pNotify(NULL) -{ - - if (bEvent) { - m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); - if (m_hSem == NULL) { - *phr = E_OUTOFMEMORY; - return; - } - } -} -#endif - -/* Destructor */ - -CBaseAllocator::~CBaseAllocator() -{ - // we can't call Decommit here since that would mean a call to a - // pure virtual in destructor. - // We must assume that the derived class has gone into decommit state in - // its destructor. - - ASSERT(!m_bCommitted); - if (m_hSem != NULL) { - EXECUTE_ASSERT(CloseHandle(m_hSem)); - } - if (m_pNotify) { - m_pNotify->Release(); - } -} - - -/* Override this to publicise our interfaces */ - -STDMETHODIMP -CBaseAllocator::NonDelegatingQueryInterface(REFIID riid, void **ppv) -{ - /* Do we know about this interface */ - - if (riid == IID_IMemAllocator || - riid == IID_IMemAllocatorCallbackTemp && m_fEnableReleaseCallback) { - return GetInterface((IMemAllocatorCallbackTemp *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -/* This sets the size and count of the required samples. The memory isn't - actually allocated until Commit() is called, if memory has already been - allocated then assuming no samples are outstanding the user may call us - to change the buffering, the memory will be released in Commit() */ - -STDMETHODIMP -CBaseAllocator::SetProperties( - ALLOCATOR_PROPERTIES* pRequest, - ALLOCATOR_PROPERTIES* pActual) -{ - CheckPointer(pRequest, E_POINTER); - CheckPointer(pActual, E_POINTER); - ValidateReadWritePtr(pActual, sizeof(ALLOCATOR_PROPERTIES)); - CAutoLock cObjectLock(this); - - ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES)); - - ASSERT(pRequest->cbBuffer > 0); - - /* Check the alignment requested */ - if (pRequest->cbAlign != 1) { - DbgLog((LOG_ERROR, 2, TEXT("Alignment requested was 0x%x, not 1"), - pRequest->cbAlign)); - return VFW_E_BADALIGN; - } - - /* Can't do this if already committed, there is an argument that says we - should not reject the SetProperties call if there are buffers still - active. However this is called by the source filter, which is the same - person who is holding the samples. Therefore it is not unreasonable - for them to free all their samples before changing the requirements */ - - if (m_bCommitted) { - return VFW_E_ALREADY_COMMITTED; - } - - /* Must be no outstanding buffers */ - - if (m_lAllocated != m_lFree.GetCount()) { - return VFW_E_BUFFERS_OUTSTANDING; - } - - /* There isn't any real need to check the parameters as they - will just be rejected when the user finally calls Commit */ - - pActual->cbBuffer = m_lSize = pRequest->cbBuffer; - pActual->cBuffers = m_lCount = pRequest->cBuffers; - pActual->cbAlign = m_lAlignment = pRequest->cbAlign; - pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix; - - m_bChanged = TRUE; - return NOERROR; -} - -STDMETHODIMP -CBaseAllocator::GetProperties( - ALLOCATOR_PROPERTIES * pActual) -{ - CheckPointer(pActual,E_POINTER); - ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES)); - - CAutoLock cObjectLock(this); - pActual->cbBuffer = m_lSize; - pActual->cBuffers = m_lCount; - pActual->cbAlign = m_lAlignment; - pActual->cbPrefix = m_lPrefix; - return NOERROR; -} - -// get container for a sample. Blocking, synchronous call to get the -// next free buffer (as represented by an IMediaSample interface). -// on return, the time etc properties will be invalid, but the buffer -// pointer and size will be correct. - -HRESULT CBaseAllocator::GetBuffer(IMediaSample **ppBuffer, - REFERENCE_TIME *pStartTime, - REFERENCE_TIME *pEndTime, - DWORD dwFlags - ) -{ - UNREFERENCED_PARAMETER(pStartTime); - UNREFERENCED_PARAMETER(pEndTime); - UNREFERENCED_PARAMETER(dwFlags); - CMediaSample *pSample; - - *ppBuffer = NULL; - for (;;) - { - { // scope for lock - CAutoLock cObjectLock(this); - - /* Check we are committed */ - if (!m_bCommitted) { - return VFW_E_NOT_COMMITTED; - } - pSample = (CMediaSample *) m_lFree.RemoveHead(); - if (pSample == NULL) { - SetWaiting(); - } - } - - /* If we didn't get a sample then wait for the list to signal */ - - if (pSample) { - break; - } - if (dwFlags & AM_GBF_NOWAIT) { - return VFW_E_TIMEOUT; - } - ASSERT(m_hSem != NULL); - WaitForSingleObject(m_hSem, INFINITE); - } - - /* Addref the buffer up to one. On release - back to zero instead of being deleted, it will requeue itself by - calling the ReleaseBuffer member function. NOTE the owner of a - media sample must always be derived from CBaseAllocator */ - - - ASSERT(pSample->m_cRef == 0); - pSample->m_cRef = 1; - *ppBuffer = pSample; - - - return NOERROR; -} - - -/* Final release of a CMediaSample will call this */ - -STDMETHODIMP -CBaseAllocator::ReleaseBuffer(IMediaSample * pSample) -{ - CheckPointer(pSample,E_POINTER); - ValidateReadPtr(pSample,sizeof(IMediaSample)); - - - - BOOL bRelease = FALSE; - { - CAutoLock cal(this); - - /* Put back on the free list */ - - m_lFree.Add((CMediaSample *)pSample); - if (m_lWaiting != 0) { - NotifySample(); - } - - // if there is a pending Decommit, then we need to complete it by - // calling Free() when the last buffer is placed on the free list - - LONG l1 = m_lFree.GetCount(); - if (m_bDecommitInProgress && (l1 == m_lAllocated)) { - Free(); - m_bDecommitInProgress = FALSE; - bRelease = TRUE; - } - } - - if (m_pNotify) { - - ASSERT(m_fEnableReleaseCallback); - - // - // Note that this is not synchronized with setting up a notification - // method. - // - m_pNotify->NotifyRelease(); - } - - /* For each buffer there is one AddRef, made in GetBuffer and released - here. This may cause the allocator and all samples to be deleted */ - - if (bRelease) { - Release(); - } - return NOERROR; -} - -STDMETHODIMP -CBaseAllocator::SetNotify( - IMemAllocatorNotifyCallbackTemp* pNotify - ) -{ - ASSERT(m_fEnableReleaseCallback); - CAutoLock lck(this); - if (pNotify) { - pNotify->AddRef(); - } - if (m_pNotify) { - m_pNotify->Release(); - } - m_pNotify = pNotify; - return S_OK; -} - -STDMETHODIMP -CBaseAllocator::GetFreeCount( - LONG* plBuffersFree - ) -{ - ASSERT(m_fEnableReleaseCallback); - CAutoLock cObjectLock(this); - *plBuffersFree = m_lCount - m_lAllocated + m_lFree.GetCount(); - return NOERROR; -} - -void -CBaseAllocator::NotifySample() -{ - if (m_lWaiting != 0) { - ASSERT(m_hSem != NULL); - ReleaseSemaphore(m_hSem, m_lWaiting, 0); - m_lWaiting = 0; - } -} - -STDMETHODIMP -CBaseAllocator::Commit() -{ - /* Check we are not decommitted */ - CAutoLock cObjectLock(this); - - // cannot need to alloc or re-alloc if we are committed - if (m_bCommitted) { - return NOERROR; - } - - /* Allow GetBuffer calls */ - - m_bCommitted = TRUE; - - // is there a pending decommit ? if so, just cancel it - if (m_bDecommitInProgress) { - m_bDecommitInProgress = FALSE; - - // don't call Alloc at this point. He cannot allow SetProperties - // between Decommit and the last free, so the buffer size cannot have - // changed. And because some of the buffers are not free yet, he - // cannot re-alloc anyway. - return NOERROR; - } - - DbgLog((LOG_MEMORY, 1, TEXT("Allocating: %ldx%ld"), m_lCount, m_lSize)); - - // actually need to allocate the samples - HRESULT hr = Alloc(); - if (FAILED(hr)) { - m_bCommitted = FALSE; - return hr; - } - AddRef(); - return NOERROR; -} - - -STDMETHODIMP -CBaseAllocator::Decommit() -{ - BOOL bRelease = FALSE; - { - /* Check we are not already decommitted */ - CAutoLock cObjectLock(this); - if (m_bCommitted == FALSE) { - if (m_bDecommitInProgress == FALSE) { - return NOERROR; - } - } - - /* No more GetBuffer calls will succeed */ - m_bCommitted = FALSE; - - // are any buffers outstanding? - if (m_lFree.GetCount() < m_lAllocated) { - // please complete the decommit when last buffer is freed - m_bDecommitInProgress = TRUE; - } else { - m_bDecommitInProgress = FALSE; - - // need to complete the decommit here as there are no - // outstanding buffers - - Free(); - bRelease = TRUE; - } - - // Tell anyone waiting that they can go now so we can - // reject their call - NotifySample(); - } - - if (bRelease) { - Release(); - } - return NOERROR; -} - - -/* Base definition of allocation which checks we are ok to go ahead and do - the full allocation. We return S_FALSE if the requirements are the same */ - -HRESULT -CBaseAllocator::Alloc(void) -{ - /* Error if he hasn't set the size yet */ - if (m_lCount <= 0 || m_lSize <= 0 || m_lAlignment <= 0) { - return VFW_E_SIZENOTSET; - } - - /* should never get here while buffers outstanding */ - ASSERT(m_lFree.GetCount() == m_lAllocated); - - /* If the requirements haven't changed then don't reallocate */ - if (m_bChanged == FALSE) { - return S_FALSE; - } - - return NOERROR; -} - -/* Implement CBaseAllocator::CSampleList::Remove(pSample) - Removes pSample from the list -*/ -void -CBaseAllocator::CSampleList::Remove(CMediaSample * pSample) -{ - CMediaSample **pSearch; - for (pSearch = &m_List; - *pSearch != NULL; - pSearch = &(CBaseAllocator::NextSample(*pSearch))) { - if (*pSearch == pSample) { - *pSearch = CBaseAllocator::NextSample(pSample); - CBaseAllocator::NextSample(pSample) = NULL; - m_nOnList--; - return; - } - } - DbgBreak("Couldn't find sample in list"); -} - -//===================================================================== -//===================================================================== -// Implements CMemAllocator -//===================================================================== -//===================================================================== - - -/* This goes in the factory template table to create new instances */ -CUnknown *CMemAllocator::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) -{ - CUnknown *pUnkRet = new CMemAllocator(NAME("CMemAllocator"), pUnk, phr); - return pUnkRet; -} - -CMemAllocator::CMemAllocator( - TCHAR *pName, - LPUNKNOWN pUnk, - HRESULT *phr) - : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE), - m_pBuffer(NULL) -{ -} - -#ifdef UNICODE -CMemAllocator::CMemAllocator( - CHAR *pName, - LPUNKNOWN pUnk, - HRESULT *phr) - : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE), - m_pBuffer(NULL) -{ -} -#endif - -/* This sets the size and count of the required samples. The memory isn't - actually allocated until Commit() is called, if memory has already been - allocated then assuming no samples are outstanding the user may call us - to change the buffering, the memory will be released in Commit() */ -STDMETHODIMP -CMemAllocator::SetProperties( - ALLOCATOR_PROPERTIES* pRequest, - ALLOCATOR_PROPERTIES* pActual) -{ - CheckPointer(pActual,E_POINTER); - ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES)); - CAutoLock cObjectLock(this); - - ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES)); - - ASSERT(pRequest->cbBuffer > 0); - - SYSTEM_INFO SysInfo; - GetSystemInfo(&SysInfo); - - /* Check the alignment request is a power of 2 */ - if ((-pRequest->cbAlign & pRequest->cbAlign) != pRequest->cbAlign) { - DbgLog((LOG_ERROR, 1, TEXT("Alignment requested 0x%x not a power of 2!"), - pRequest->cbAlign)); - } - /* Check the alignment requested */ - if (pRequest->cbAlign == 0 || - (SysInfo.dwAllocationGranularity & (pRequest->cbAlign - 1)) != 0) { - DbgLog((LOG_ERROR, 1, TEXT("Invalid alignment 0x%x requested - granularity = 0x%x"), - pRequest->cbAlign, SysInfo.dwAllocationGranularity)); - return VFW_E_BADALIGN; - } - - /* Can't do this if already committed, there is an argument that says we - should not reject the SetProperties call if there are buffers still - active. However this is called by the source filter, which is the same - person who is holding the samples. Therefore it is not unreasonable - for them to free all their samples before changing the requirements */ - - if (m_bCommitted == TRUE) { - return VFW_E_ALREADY_COMMITTED; - } - - /* Must be no outstanding buffers */ - - if (m_lFree.GetCount() < m_lAllocated) { - return VFW_E_BUFFERS_OUTSTANDING; - } - - /* There isn't any real need to check the parameters as they - will just be rejected when the user finally calls Commit */ - - // round length up to alignment - remember that prefix is included in - // the alignment - LONG lSize = pRequest->cbBuffer + pRequest->cbPrefix; - LONG lRemainder = lSize % pRequest->cbAlign; - if (lRemainder != 0) { - lSize = lSize - lRemainder + pRequest->cbAlign; - } - pActual->cbBuffer = m_lSize = (lSize - pRequest->cbPrefix); - - pActual->cBuffers = m_lCount = pRequest->cBuffers; - pActual->cbAlign = m_lAlignment = pRequest->cbAlign; - pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix; - - m_bChanged = TRUE; - return NOERROR; -} - -// override this to allocate our resources when Commit is called. -// -// note that our resources may be already allocated when this is called, -// since we don't free them on Decommit. We will only be called when in -// decommit state with all buffers free. -// -// object locked by caller -HRESULT -CMemAllocator::Alloc(void) -{ - CAutoLock lck(this); - - /* Check he has called SetProperties */ - HRESULT hr = CBaseAllocator::Alloc(); - if (FAILED(hr)) { - return hr; - } - - /* If the requirements haven't changed then don't reallocate */ - if (hr == S_FALSE) { - ASSERT(m_pBuffer); - return NOERROR; - } - ASSERT(hr == S_OK); // we use this fact in the loop below - - /* Free the old resources */ - if (m_pBuffer) { - ReallyFree(); - } - - /* Compute the aligned size */ - LONG lAlignedSize = m_lSize + m_lPrefix; - if (m_lAlignment > 1) { - LONG lRemainder = lAlignedSize % m_lAlignment; - if (lRemainder != 0) { - lAlignedSize += (m_lAlignment - lRemainder); - } - } - - /* Create the contiguous memory block for the samples - making sure it's properly aligned (64K should be enough!) - */ - ASSERT(lAlignedSize % m_lAlignment == 0); - - m_pBuffer = (PBYTE)VirtualAlloc(NULL, - m_lCount * lAlignedSize, - MEM_COMMIT, - PAGE_READWRITE); - - if (m_pBuffer == NULL) { - return E_OUTOFMEMORY; - } - - LPBYTE pNext = m_pBuffer; - CMediaSample *pSample; - - ASSERT(m_lAllocated == 0); - - // Create the new samples - we have allocated m_lSize bytes for each sample - // plus m_lPrefix bytes per sample as a prefix. We set the pointer to - // the memory after the prefix - so that GetPointer() will return a pointer - // to m_lSize bytes. - for (; m_lAllocated < m_lCount; m_lAllocated++, pNext += lAlignedSize) { - - - pSample = new CMediaSample( - NAME("Default memory media sample"), - this, - &hr, - pNext + m_lPrefix, // GetPointer() value - m_lSize); // not including prefix - - ASSERT(SUCCEEDED(hr)); - if (pSample == NULL) { - return E_OUTOFMEMORY; - } - - // This CANNOT fail - m_lFree.Add(pSample); - } - - m_bChanged = FALSE; - return NOERROR; -} - - -// override this to free up any resources we have allocated. -// called from the base class on Decommit when all buffers have been -// returned to the free list. -// -// caller has already locked the object. - -// in our case, we keep the memory until we are deleted, so -// we do nothing here. The memory is deleted in the destructor by -// calling ReallyFree() -void -CMemAllocator::Free(void) -{ - return; -} - - -// called from the destructor (and from Alloc if changing size/count) to -// actually free up the memory -void -CMemAllocator::ReallyFree(void) -{ - /* Should never be deleting this unless all buffers are freed */ - - ASSERT(m_lAllocated == m_lFree.GetCount()); - - /* Free up all the CMediaSamples */ - - CMediaSample *pSample; - for (;;) { - pSample = m_lFree.RemoveHead(); - if (pSample != NULL) { - delete pSample; - } else { - break; - } - } - - m_lAllocated = 0; - - // free the block of buffer memory - if (m_pBuffer) { - EXECUTE_ASSERT(VirtualFree(m_pBuffer, 0, MEM_RELEASE)); - m_pBuffer = NULL; - } -} - - -/* Destructor frees our memory resources */ - -CMemAllocator::~CMemAllocator() -{ - Decommit(); - ReallyFree(); -} - -// ------------------------------------------------------------------------ -// filter registration through IFilterMapper. used if IFilterMapper is -// not found (Quartz 1.0 install) - -STDAPI -AMovieSetupRegisterFilter( const AMOVIESETUP_FILTER * const psetupdata - , IFilterMapper * pIFM - , BOOL bRegister ) -{ - DbgLog((LOG_TRACE, 3, TEXT("= AMovieSetupRegisterFilter"))); - - // check we've got data - // - if( NULL == psetupdata ) return S_FALSE; - - - // unregister filter - // (as pins are subkeys of filter's CLSID key - // they do not need to be removed separately). - // - DbgLog((LOG_TRACE, 3, TEXT("= = unregister filter"))); - HRESULT hr = pIFM->UnregisterFilter( *(psetupdata->clsID) ); - - - if( bRegister ) - { - // register filter - // - DbgLog((LOG_TRACE, 3, TEXT("= = register filter"))); - hr = pIFM->RegisterFilter( *(psetupdata->clsID) - , psetupdata->strName - , psetupdata->dwMerit ); - if( SUCCEEDED(hr) ) - { - // all its pins - // - DbgLog((LOG_TRACE, 3, TEXT("= = register filter pins"))); - for( UINT m1=0; m1 < psetupdata->nPins; m1++ ) - { - hr = pIFM->RegisterPin( *(psetupdata->clsID) - , psetupdata->lpPin[m1].strName - , psetupdata->lpPin[m1].bRendered - , psetupdata->lpPin[m1].bOutput - , psetupdata->lpPin[m1].bZero - , psetupdata->lpPin[m1].bMany - , *(psetupdata->lpPin[m1].clsConnectsToFilter) - , psetupdata->lpPin[m1].strConnectsToPin ); - - if( SUCCEEDED(hr) ) - { - // and each pin's media types - // - DbgLog((LOG_TRACE, 3, TEXT("= = register filter pin types"))); - for( UINT m2=0; m2 < psetupdata->lpPin[m1].nMediaTypes; m2++ ) - { - hr = pIFM->RegisterPinType( *(psetupdata->clsID) - , psetupdata->lpPin[m1].strName - , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMajorType) - , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMinorType) ); - if( FAILED(hr) ) break; - } - if( FAILED(hr) ) break; - } - if( FAILED(hr) ) break; - } - } - } - - // handle one acceptable "error" - that - // of filter not being registered! - // (couldn't find a suitable #define'd - // name for the error!) - // - if( 0x80070002 == hr) - return NOERROR; - else - return hr; -} - -// Remove warnings about unreferenced inline functions -#pragma warning(disable:4514) - +//------------------------------------------------------------------------------ +// File: AMFilter.cpp +// +// Desc: DirectShow base classes - implements class hierarchy for streams +// architecture. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +//===================================================================== +//===================================================================== +// The following classes are declared in this header: +// +// +// CBaseMediaFilter Basic IMediaFilter support (abstract class) +// CBaseFilter Support for IBaseFilter (incl. IMediaFilter) +// CEnumPins Enumerate input and output pins +// CEnumMediaTypes Enumerate the preferred pin formats +// CBasePin Abstract base class for IPin interface +// CBaseOutputPin Adds data provider member functions +// CBaseInputPin Implements IMemInputPin interface +// CMediaSample Basic transport unit for IMemInputPin +// CBaseAllocator General list guff for most allocators +// CMemAllocator Implements memory buffer allocation +// +//===================================================================== +//===================================================================== + +#include "streams.h" + + + +//===================================================================== +// Helpers +//===================================================================== +STDAPI CreateMemoryAllocator(IMemAllocator **ppAllocator) +{ + return CoCreateInstance(CLSID_MemoryAllocator, + 0, + CLSCTX_INPROC_SERVER, + IID_IMemAllocator, + (void **)ppAllocator); +} + +// Put this one here rather than in ctlutil.cpp to avoid linking +// anything brought in by ctlutil.cpp +STDAPI CreatePosPassThru( + LPUNKNOWN pAgg, + BOOL bRenderer, + IPin *pPin, + IUnknown **ppPassThru +) +{ + *ppPassThru = NULL; + IUnknown *pUnkSeek; + HRESULT hr = CoCreateInstance(CLSID_SeekingPassThru, + pAgg, + CLSCTX_INPROC_SERVER, + IID_IUnknown, + (void **)&pUnkSeek + ); + if (FAILED(hr)) { + return hr; + } + + ISeekingPassThru *pPassThru; + hr = pUnkSeek->QueryInterface(IID_ISeekingPassThru, (void**)&pPassThru); + if (FAILED(hr)) { + pUnkSeek->Release(); + return hr; + } + hr = pPassThru->Init(bRenderer, pPin); + pPassThru->Release(); + if (FAILED(hr)) { + pUnkSeek->Release(); + return hr; + } + *ppPassThru = pUnkSeek; + return S_OK; +} + + + +#define CONNECT_TRACE_LEVEL 3 + +//===================================================================== +//===================================================================== +// Implements CBaseMediaFilter +//===================================================================== +//===================================================================== + + +/* Constructor */ + +CBaseMediaFilter::CBaseMediaFilter(const TCHAR *pName, + LPUNKNOWN pUnk, + CCritSec *pLock, + REFCLSID clsid) : + CUnknown(pName, pUnk), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL) +{ +} + + +/* Destructor */ + +CBaseMediaFilter::~CBaseMediaFilter() +{ + // must be stopped, but can't call Stop here since + // our critsec has been destroyed. + + /* Release any clock we were using */ + + if (m_pClock) { + m_pClock->Release(); + m_pClock = NULL; + } +} + + +/* Override this to say what interfaces we support and where */ + +STDMETHODIMP +CBaseMediaFilter::NonDelegatingQueryInterface( + REFIID riid, + void ** ppv) +{ + if (riid == IID_IMediaFilter) { + return GetInterface((IMediaFilter *) this, ppv); + } else if (riid == IID_IPersist) { + return GetInterface((IPersist *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + +/* Return the filter's clsid */ +STDMETHODIMP +CBaseMediaFilter::GetClassID(CLSID *pClsID) +{ + CheckPointer(pClsID,E_POINTER); + ValidateReadWritePtr(pClsID,sizeof(CLSID)); + *pClsID = m_clsid; + return NOERROR; +} + +/* Override this if your state changes are not done synchronously */ + +STDMETHODIMP +CBaseMediaFilter::GetState(DWORD dwMSecs, FILTER_STATE *State) +{ + UNREFERENCED_PARAMETER(dwMSecs); + CheckPointer(State,E_POINTER); + ValidateReadWritePtr(State,sizeof(FILTER_STATE)); + + *State = m_State; + return S_OK; +} + + +/* Set the clock we will use for synchronisation */ + +STDMETHODIMP +CBaseMediaFilter::SetSyncSource(IReferenceClock *pClock) +{ + CAutoLock cObjectLock(m_pLock); + + // Ensure the new one does not go away - even if the same as the old + if (pClock) { + pClock->AddRef(); + } + + // if we have a clock, release it + if (m_pClock) { + m_pClock->Release(); + } + + // Set the new reference clock (might be NULL) + // Should we query it to ensure it is a clock? Consider for a debug build. + m_pClock = pClock; + + return NOERROR; +} + +/* Return the clock we are using for synchronisation */ +STDMETHODIMP +CBaseMediaFilter::GetSyncSource(IReferenceClock **pClock) +{ + CheckPointer(pClock,E_POINTER); + ValidateReadWritePtr(pClock,sizeof(IReferenceClock *)); + CAutoLock cObjectLock(m_pLock); + + if (m_pClock) { + // returning an interface... addref it... + m_pClock->AddRef(); + } + *pClock = (IReferenceClock*)m_pClock; + return NOERROR; +} + + +/* Put the filter into a stopped state */ + +STDMETHODIMP +CBaseMediaFilter::Stop() +{ + CAutoLock cObjectLock(m_pLock); + + m_State = State_Stopped; + return S_OK; +} + + +/* Put the filter into a paused state */ + +STDMETHODIMP +CBaseMediaFilter::Pause() +{ + CAutoLock cObjectLock(m_pLock); + + m_State = State_Paused; + return S_OK; +} + + +// Put the filter into a running state. + +// The time parameter is the offset to be added to the samples' +// stream time to get the reference time at which they should be presented. +// +// you can either add these two and compare it against the reference clock, +// or you can call CBaseMediaFilter::StreamTime and compare that against +// the sample timestamp. + +STDMETHODIMP +CBaseMediaFilter::Run(REFERENCE_TIME tStart) +{ + CAutoLock cObjectLock(m_pLock); + + // remember the stream time offset + m_tStart = tStart; + + if (m_State == State_Stopped){ + HRESULT hr = Pause(); + + if (FAILED(hr)) { + return hr; + } + } + m_State = State_Running; + return S_OK; +} + + +// +// return the current stream time - samples with start timestamps of this +// time or before should be rendered by now +HRESULT +CBaseMediaFilter::StreamTime(CRefTime& rtStream) +{ + // Caller must lock for synchronization + // We can't grab the filter lock because we want to be able to call + // this from worker threads without deadlocking + + if (m_pClock == NULL) { + return VFW_E_NO_CLOCK; + } + + // get the current reference time + HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream); + if (FAILED(hr)) { + return hr; + } + + // subtract the stream offset to get stream time + rtStream -= m_tStart; + + return S_OK; +} + + +//===================================================================== +//===================================================================== +// Implements CBaseFilter +//===================================================================== +//===================================================================== + + +/* Override this to say what interfaces we support and where */ + +STDMETHODIMP CBaseFilter::NonDelegatingQueryInterface(REFIID riid, + void **ppv) +{ + /* Do we have this interface */ + + if (riid == IID_IBaseFilter) { + return GetInterface((IBaseFilter *) this, ppv); + } else if (riid == IID_IMediaFilter) { + return GetInterface((IMediaFilter *) this, ppv); + } else if (riid == IID_IPersist) { + return GetInterface((IPersist *) this, ppv); + } else if (riid == IID_IAMovieSetup) { + return GetInterface((IAMovieSetup *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + +#ifdef DEBUG +STDMETHODIMP_(ULONG) CBaseFilter::NonDelegatingRelease() +{ + if (m_cRef == 1) { + KASSERT(m_pGraph == NULL); + } + return CUnknown::NonDelegatingRelease(); +} +#endif + + +/* Constructor */ + +CBaseFilter::CBaseFilter(const TCHAR *pName, + LPUNKNOWN pUnk, + CCritSec *pLock, + REFCLSID clsid) : + CUnknown( pName, pUnk ), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL), + m_pGraph(NULL), + m_pSink(NULL), + m_pName(NULL), + m_PinVersion(1) +{ + + ASSERT(pLock != NULL); +} + +/* Passes in a redundant HRESULT argument */ + +CBaseFilter::CBaseFilter(TCHAR *pName, + LPUNKNOWN pUnk, + CCritSec *pLock, + REFCLSID clsid, + HRESULT *phr) : + CUnknown( pName, pUnk ), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL), + m_pGraph(NULL), + m_pSink(NULL), + m_pName(NULL), + m_PinVersion(1) +{ + + ASSERT(pLock != NULL); + UNREFERENCED_PARAMETER(phr); +} + +#ifdef UNICODE +CBaseFilter::CBaseFilter(const CHAR *pName, + LPUNKNOWN pUnk, + CCritSec *pLock, + REFCLSID clsid) : + CUnknown( pName, pUnk ), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL), + m_pGraph(NULL), + m_pSink(NULL), + m_pName(NULL), + m_PinVersion(1) +{ + + ASSERT(pLock != NULL); +} +CBaseFilter::CBaseFilter(CHAR *pName, + LPUNKNOWN pUnk, + CCritSec *pLock, + REFCLSID clsid, + HRESULT *phr) : + CUnknown( pName, pUnk ), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL), + m_pGraph(NULL), + m_pSink(NULL), + m_pName(NULL), + m_PinVersion(1) +{ + + ASSERT(pLock != NULL); + UNREFERENCED_PARAMETER(phr); +} +#endif + +/* Destructor */ + +CBaseFilter::~CBaseFilter() +{ + + // NOTE we do NOT hold references on the filtergraph for m_pGraph or m_pSink + // When we did we had the circular reference problem. Nothing would go away. + + delete[] m_pName; + + // must be stopped, but can't call Stop here since + // our critsec has been destroyed. + + /* Release any clock we were using */ + if (m_pClock) { + m_pClock->Release(); + m_pClock = NULL; + } +} + +/* Return the filter's clsid */ +STDMETHODIMP +CBaseFilter::GetClassID(CLSID *pClsID) +{ + CheckPointer(pClsID,E_POINTER); + ValidateReadWritePtr(pClsID,sizeof(CLSID)); + *pClsID = m_clsid; + return NOERROR; +} + +/* Override this if your state changes are not done synchronously */ +STDMETHODIMP +CBaseFilter::GetState(DWORD dwMSecs, FILTER_STATE *State) +{ + UNREFERENCED_PARAMETER(dwMSecs); + CheckPointer(State,E_POINTER); + ValidateReadWritePtr(State,sizeof(FILTER_STATE)); + + *State = m_State; + return S_OK; +} + + +/* Set the clock we will use for synchronisation */ + +STDMETHODIMP +CBaseFilter::SetSyncSource(IReferenceClock *pClock) +{ + CAutoLock cObjectLock(m_pLock); + + // Ensure the new one does not go away - even if the same as the old + if (pClock) { + pClock->AddRef(); + } + + // if we have a clock, release it + if (m_pClock) { + m_pClock->Release(); + } + + // Set the new reference clock (might be NULL) + // Should we query it to ensure it is a clock? Consider for a debug build. + m_pClock = pClock; + + return NOERROR; +} + +/* Return the clock we are using for synchronisation */ +STDMETHODIMP +CBaseFilter::GetSyncSource(IReferenceClock **pClock) +{ + CheckPointer(pClock,E_POINTER); + ValidateReadWritePtr(pClock,sizeof(IReferenceClock *)); + CAutoLock cObjectLock(m_pLock); + + if (m_pClock) { + // returning an interface... addref it... + m_pClock->AddRef(); + } + *pClock = (IReferenceClock*)m_pClock; + return NOERROR; +} + + + +// override CBaseMediaFilter Stop method, to deactivate any pins this +// filter has. +STDMETHODIMP +CBaseFilter::Stop() +{ + CAutoLock cObjectLock(m_pLock); + HRESULT hr = NOERROR; + + // notify all pins of the state change + if (m_State != State_Stopped) { + int cPins = GetPinCount(); + for (int c = 0; c < cPins; c++) { + + CBasePin *pPin = GetPin(c); + + // Disconnected pins are not activated - this saves pins worrying + // about this state themselves. We ignore the return code to make + // sure everyone is inactivated regardless. The base input pin + // class can return an error if it has no allocator but Stop can + // be used to resync the graph state after something has gone bad + + if (pPin->IsConnected()) { + HRESULT hrTmp = pPin->Inactive(); + if (FAILED(hrTmp) && SUCCEEDED(hr)) { + hr = hrTmp; + } + } + } + } + + + m_State = State_Stopped; + return hr; +} + + +// override CBaseMediaFilter Pause method to activate any pins +// this filter has (also called from Run) + +STDMETHODIMP +CBaseFilter::Pause() +{ + CAutoLock cObjectLock(m_pLock); + + // notify all pins of the change to active state + if (m_State == State_Stopped) { + int cPins = GetPinCount(); + for (int c = 0; c < cPins; c++) { + + CBasePin *pPin = GetPin(c); + + // Disconnected pins are not activated - this saves pins + // worrying about this state themselves + + if (pPin->IsConnected()) { + HRESULT hr = pPin->Active(); + if (FAILED(hr)) { + return hr; + } + } + } + } + + + + m_State = State_Paused; + return S_OK; +} + +// Put the filter into a running state. + +// The time parameter is the offset to be added to the samples' +// stream time to get the reference time at which they should be presented. +// +// you can either add these two and compare it against the reference clock, +// or you can call CBaseFilter::StreamTime and compare that against +// the sample timestamp. + +STDMETHODIMP +CBaseFilter::Run(REFERENCE_TIME tStart) +{ + CAutoLock cObjectLock(m_pLock); + + // remember the stream time offset + m_tStart = tStart; + + if (m_State == State_Stopped){ + HRESULT hr = Pause(); + + if (FAILED(hr)) { + return hr; + } + } + // notify all pins of the change to active state + if (m_State != State_Running) { + int cPins = GetPinCount(); + for (int c = 0; c < cPins; c++) { + + CBasePin *pPin = GetPin(c); + + // Disconnected pins are not activated - this saves pins + // worrying about this state themselves + + if (pPin->IsConnected()) { + HRESULT hr = pPin->Run(tStart); + if (FAILED(hr)) { + return hr; + } + } + } + } + + + m_State = State_Running; + return S_OK; +} + +// +// return the current stream time - samples with start timestamps of this +// time or before should be rendered by now +HRESULT +CBaseFilter::StreamTime(CRefTime& rtStream) +{ + // Caller must lock for synchronization + // We can't grab the filter lock because we want to be able to call + // this from worker threads without deadlocking + + if (m_pClock == NULL) { + return VFW_E_NO_CLOCK; + } + + // get the current reference time + HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream); + if (FAILED(hr)) { + return hr; + } + + // subtract the stream offset to get stream time + rtStream -= m_tStart; + + return S_OK; +} + + +/* Create an enumerator for the pins attached to this filter */ + +STDMETHODIMP +CBaseFilter::EnumPins(IEnumPins **ppEnum) +{ + CheckPointer(ppEnum,E_POINTER); + ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *)); + + /* Create a new ref counted enumerator */ + + *ppEnum = new CEnumPins(this, + NULL); + + return *ppEnum == NULL ? E_OUTOFMEMORY : NOERROR; +} + + +// default behaviour of FindPin is to assume pins are named +// by their pin names +STDMETHODIMP +CBaseFilter::FindPin( + LPCWSTR Id, + IPin ** ppPin +) +{ + CheckPointer(ppPin,E_POINTER); + ValidateReadWritePtr(ppPin,sizeof(IPin *)); + + // We're going to search the pin list so maintain integrity + CAutoLock lck(m_pLock); + int iCount = GetPinCount(); + for (int i = 0; i < iCount; i++) { + CBasePin *pPin = GetPin(i); + ASSERT(pPin != NULL); + + if (0 == lstrcmpW(pPin->Name(), Id)) { + // Found one that matches + // + // AddRef() and return it + *ppPin = pPin; + pPin->AddRef(); + return S_OK; + } + } + *ppPin = NULL; + return VFW_E_NOT_FOUND; +} + +/* Return information about this filter */ + +STDMETHODIMP +CBaseFilter::QueryFilterInfo(FILTER_INFO * pInfo) +{ + CheckPointer(pInfo,E_POINTER); + ValidateReadWritePtr(pInfo,sizeof(FILTER_INFO)); + + if (m_pName) { + lstrcpynW(pInfo->achName, m_pName, sizeof(pInfo->achName)/sizeof(WCHAR)); + } else { + pInfo->achName[0] = L'\0'; + } + pInfo->pGraph = m_pGraph; + if (m_pGraph) + m_pGraph->AddRef(); + return NOERROR; +} + + +/* Provide the filter with a filter graph */ + +STDMETHODIMP +CBaseFilter::JoinFilterGraph( + IFilterGraph * pGraph, + LPCWSTR pName) +{ + CAutoLock cObjectLock(m_pLock); + + // NOTE: we no longer hold references on the graph (m_pGraph, m_pSink) + + m_pGraph = pGraph; + if (m_pGraph) { + HRESULT hr = m_pGraph->QueryInterface(IID_IMediaEventSink, + (void**) &m_pSink); + if (FAILED(hr)) { + ASSERT(m_pSink == NULL); + } + else m_pSink->Release(); // we do NOT keep a reference on it. + } else { + // if graph pointer is null, then we should + // also release the IMediaEventSink on the same object - we don't + // refcount it, so just set it to null + m_pSink = NULL; + } + + + if (m_pName) { + delete[] m_pName; + m_pName = NULL; + } + + if (pName) { + DWORD nameLen = lstrlenW(pName)+1; + m_pName = new WCHAR[nameLen]; + if (m_pName) { + CopyMemory(m_pName, pName, nameLen*sizeof(WCHAR)); + } else { + // !!! error here? + ASSERT(FALSE); + } + } + + + return NOERROR; +} + + +// return a Vendor information string. Optional - may return E_NOTIMPL. +// memory returned should be freed using CoTaskMemFree +// default implementation returns E_NOTIMPL +STDMETHODIMP +CBaseFilter::QueryVendorInfo( + LPWSTR* pVendorInfo) +{ + UNREFERENCED_PARAMETER(pVendorInfo); + return E_NOTIMPL; +} + + +// send an event notification to the filter graph if we know about it. +// returns S_OK if delivered, S_FALSE if the filter graph does not sink +// events, or an error otherwise. +HRESULT +CBaseFilter::NotifyEvent( + long EventCode, + LONG_PTR EventParam1, + LONG_PTR EventParam2) +{ + // Snapshot so we don't have to lock up + IMediaEventSink *pSink = m_pSink; + if (pSink) { + if (EC_COMPLETE == EventCode) { + EventParam2 = (LONG_PTR)(IBaseFilter*)this; + } + + return pSink->Notify(EventCode, EventParam1, EventParam2); + } else { + return E_NOTIMPL; + } +} + +// Request reconnect +// pPin is the pin to reconnect +// pmt is the type to reconnect with - can be NULL +// Calls ReconnectEx on the filter graph +HRESULT +CBaseFilter::ReconnectPin( + IPin *pPin, + AM_MEDIA_TYPE const *pmt +) +{ + IFilterGraph2 *pGraph2; + if (m_pGraph != NULL) { + HRESULT hr = m_pGraph->QueryInterface(IID_IFilterGraph2, (void **)&pGraph2); + if (SUCCEEDED(hr)) { + hr = pGraph2->ReconnectEx(pPin, pmt); + pGraph2->Release(); + return hr; + } else { + return m_pGraph->Reconnect(pPin); + } + } else { + return E_NOINTERFACE; + } +} + + + +/* This is the same idea as the media type version does for type enumeration + on pins but for the list of pins available. So if the list of pins you + provide changes dynamically then either override this virtual function + to provide the version number, or more simply call IncrementPinVersion */ + +LONG CBaseFilter::GetPinVersion() +{ + return m_PinVersion; +} + + +/* Increment the current pin version cookie */ + +void CBaseFilter::IncrementPinVersion() +{ + InterlockedIncrement(&m_PinVersion); +} + +/* register filter */ + +STDMETHODIMP CBaseFilter::Register() +{ + // get setup data, if it exists + // + LPAMOVIESETUP_FILTER psetupdata = GetSetupData(); + + // check we've got data + // + if( NULL == psetupdata ) return S_FALSE; + + // init is ref counted so call just in case + // we're being called cold. + // + HRESULT hr = CoInitialize( (LPVOID)NULL ); + ASSERT( SUCCEEDED(hr) ); + + // get hold of IFilterMapper + // + IFilterMapper *pIFM; + hr = CoCreateInstance( CLSID_FilterMapper + , NULL + , CLSCTX_INPROC_SERVER + , IID_IFilterMapper + , (void **)&pIFM ); + if( SUCCEEDED(hr) ) + { + hr = AMovieSetupRegisterFilter( psetupdata, pIFM, TRUE ); + pIFM->Release(); + } + + // and clear up + // + CoFreeUnusedLibraries(); + CoUninitialize(); + + return NOERROR; +} + + +/* unregister filter */ + +STDMETHODIMP CBaseFilter::Unregister() +{ + // get setup data, if it exists + // + LPAMOVIESETUP_FILTER psetupdata = GetSetupData(); + + // check we've got data + // + if( NULL == psetupdata ) return S_FALSE; + + // OLE init is ref counted so call + // just in case we're being called cold. + // + HRESULT hr = CoInitialize( (LPVOID)NULL ); + ASSERT( SUCCEEDED(hr) ); + + // get hold of IFilterMapper + // + IFilterMapper *pIFM; + hr = CoCreateInstance( CLSID_FilterMapper + , NULL + , CLSCTX_INPROC_SERVER + , IID_IFilterMapper + , (void **)&pIFM ); + if( SUCCEEDED(hr) ) + { + hr = AMovieSetupRegisterFilter( psetupdata, pIFM, FALSE ); + + // release interface + // + pIFM->Release(); + } + + // clear up + // + CoFreeUnusedLibraries(); + CoUninitialize(); + + // handle one acceptable "error" - that + // of filter not being registered! + // (couldn't find a suitable #define'd + // name for the error!) + // + if( 0x80070002 == hr) + return NOERROR; + else + return hr; +} + + +//===================================================================== +//===================================================================== +// Implements CEnumPins +//===================================================================== +//===================================================================== + + +CEnumPins::CEnumPins(CBaseFilter *pFilter, + CEnumPins *pEnumPins) : + m_Position(0), + m_PinCount(0), + m_pFilter(pFilter), + m_cRef(1), // Already ref counted + m_PinCache(NAME("Pin Cache")) +{ + +#ifdef DEBUG + m_dwCookie = DbgRegisterObjectCreation("CEnumPins", 0); +#endif + + /* We must be owned by a filter derived from CBaseFilter */ + + ASSERT(pFilter != NULL); + + /* Hold a reference count on our filter */ + m_pFilter->AddRef(); + + /* Are we creating a new enumerator */ + + if (pEnumPins == NULL) { + m_Version = m_pFilter->GetPinVersion(); + m_PinCount = m_pFilter->GetPinCount(); + } else { + ASSERT(m_Position <= m_PinCount); + m_Position = pEnumPins->m_Position; + m_PinCount = pEnumPins->m_PinCount; + m_Version = pEnumPins->m_Version; + m_PinCache.AddTail(&(pEnumPins->m_PinCache)); + } +} + + +/* Destructor releases the reference count on our filter NOTE since we hold + a reference count on the filter who created us we know it is safe to + release it, no access can be made to it afterwards though as we have just + caused the last reference count to go and the object to be deleted */ + +CEnumPins::~CEnumPins() +{ + m_pFilter->Release(); + +#ifdef DEBUG + DbgRegisterObjectDestruction(m_dwCookie); +#endif +} + + +/* Override this to say what interfaces we support where */ + +STDMETHODIMP +CEnumPins::QueryInterface(REFIID riid,void **ppv) +{ + CheckPointer(ppv, E_POINTER); + + /* Do we have this interface */ + + if (riid == IID_IEnumPins || riid == IID_IUnknown) { + return GetInterface((IEnumPins *) this, ppv); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } +} + +STDMETHODIMP_(ULONG) +CEnumPins::AddRef() +{ + return InterlockedIncrement(&m_cRef); +} + +STDMETHODIMP_(ULONG) +CEnumPins::Release() +{ + ULONG cRef = InterlockedDecrement(&m_cRef); + if (cRef == 0) { + delete this; + } + return cRef; +} + +/* One of an enumerator's basic member functions allows us to create a cloned + interface that initially has the same state. Since we are taking a snapshot + of an object (current position and all) we must lock access at the start */ + +STDMETHODIMP +CEnumPins::Clone(IEnumPins **ppEnum) +{ + CheckPointer(ppEnum,E_POINTER); + ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *)); + HRESULT hr = NOERROR; + + /* Check we are still in sync with the filter */ + if (AreWeOutOfSync() == TRUE) { + *ppEnum = NULL; + hr = VFW_E_ENUM_OUT_OF_SYNC; + } else { + + *ppEnum = new CEnumPins(m_pFilter, + this); + if (*ppEnum == NULL) { + hr = E_OUTOFMEMORY; + } + } + return hr; +} + + +/* Return the next pin after the current position */ + +STDMETHODIMP +CEnumPins::Next(ULONG cPins, // place this many pins... + IPin **ppPins, // ...in this array + ULONG *pcFetched) // actual count passed returned here +{ + CheckPointer(ppPins,E_POINTER); + ValidateReadWritePtr(ppPins,cPins * sizeof(IPin *)); + + ASSERT(ppPins); + + if (pcFetched!=NULL) { + ValidateWritePtr(pcFetched, sizeof(ULONG)); + *pcFetched = 0; // default unless we succeed + } + // now check that the parameter is valid + else if (cPins>1) { // pcFetched == NULL + return E_INVALIDARG; + } + ULONG cFetched = 0; // increment as we get each one. + + /* Check we are still in sync with the filter */ + if (AreWeOutOfSync() == TRUE) { + // If we are out of sync, we should refresh the enumerator. + // This will reset the position and update the other members, but + // will not clear cache of pins we have already returned. + Refresh(); + } + + /* Calculate the number of available pins */ + + int cRealPins = min(m_PinCount - m_Position, (int) cPins); + if (cRealPins == 0) { + return S_FALSE; + } + + /* Return each pin interface NOTE GetPin returns CBasePin * not addrefed + so we must QI for the IPin (which increments its reference count) + If while we are retrieving a pin from the filter an error occurs we + assume that our internal state is stale with respect to the filter + (for example someone has deleted a pin) so we + return VFW_E_ENUM_OUT_OF_SYNC */ + + while (cRealPins && (m_PinCount - m_Position)) { + + /* Get the next pin object from the filter */ + + CBasePin *pPin = m_pFilter->GetPin(m_Position++); + if (pPin == NULL) { + // If this happend, and it's not the first time through, then we've got a problem, + // since we should really go back and release the iPins, which we have previously + // AddRef'ed. + ASSERT( cFetched==0 ); + return VFW_E_ENUM_OUT_OF_SYNC; + } + + /* We only want to return this pin, if it is not in our cache */ + if (0 == m_PinCache.Find(pPin)) + { + /* From the object get an IPin interface */ + + *ppPins = pPin; + pPin->AddRef(); + + cFetched++; + ppPins++; + + m_PinCache.AddTail(pPin); + + cRealPins--; + + } + } + + if (pcFetched!=NULL) { + *pcFetched = cFetched; + } + + return (cPins==cFetched ? NOERROR : S_FALSE); +} + + +/* Skip over one or more entries in the enumerator */ + +STDMETHODIMP +CEnumPins::Skip(ULONG cPins) +{ + /* Check we are still in sync with the filter */ + if (AreWeOutOfSync() == TRUE) { + return VFW_E_ENUM_OUT_OF_SYNC; + } + + /* Work out how many pins are left to skip over */ + /* We could position at the end if we are asked to skip too many... */ + /* ..which would match the base implementation for CEnumMediaTypes::Skip */ + + ULONG PinsLeft = m_PinCount - m_Position; + if (cPins > PinsLeft) { + return S_FALSE; + } + m_Position += cPins; + return NOERROR; +} + + +/* Set the current position back to the start */ +/* Reset has 4 simple steps: + * + * Set position to head of list + * Sync enumerator with object being enumerated + * Clear the cache of pins already returned + * return S_OK + */ + +STDMETHODIMP +CEnumPins::Reset() +{ + m_Version = m_pFilter->GetPinVersion(); + m_PinCount = m_pFilter->GetPinCount(); + + m_Position = 0; + + // Clear the cache + m_PinCache.RemoveAll(); + + return S_OK; +} + + +/* Set the current position back to the start */ +/* Refresh has 3 simple steps: + * + * Set position to head of list + * Sync enumerator with object being enumerated + * return S_OK + */ + +STDMETHODIMP +CEnumPins::Refresh() +{ + m_Version = m_pFilter->GetPinVersion(); + m_PinCount = m_pFilter->GetPinCount(); + + m_Position = 0; + return S_OK; +} + + +//===================================================================== +//===================================================================== +// Implements CEnumMediaTypes +//===================================================================== +//===================================================================== + + +CEnumMediaTypes::CEnumMediaTypes(CBasePin *pPin, + CEnumMediaTypes *pEnumMediaTypes) : + m_Position(0), + m_pPin(pPin), + m_cRef(1) +{ + +#ifdef DEBUG + m_dwCookie = DbgRegisterObjectCreation("CEnumMediaTypes", 0); +#endif + + /* We must be owned by a pin derived from CBasePin */ + + ASSERT(pPin != NULL); + + /* Hold a reference count on our pin */ + m_pPin->AddRef(); + + /* Are we creating a new enumerator */ + + if (pEnumMediaTypes == NULL) { + m_Version = m_pPin->GetMediaTypeVersion(); + return; + } + + m_Position = pEnumMediaTypes->m_Position; + m_Version = pEnumMediaTypes->m_Version; +} + + +/* Destructor releases the reference count on our base pin. NOTE since we hold + a reference count on the pin who created us we know it is safe to release + it, no access can be made to it afterwards though as we might have just + caused the last reference count to go and the object to be deleted */ + +CEnumMediaTypes::~CEnumMediaTypes() +{ +#ifdef DEBUG + DbgRegisterObjectDestruction(m_dwCookie); +#endif + m_pPin->Release(); +} + + +/* Override this to say what interfaces we support where */ + +STDMETHODIMP +CEnumMediaTypes::QueryInterface(REFIID riid,void **ppv) +{ + CheckPointer(ppv, E_POINTER); + + /* Do we have this interface */ + + if (riid == IID_IEnumMediaTypes || riid == IID_IUnknown) { + return GetInterface((IEnumMediaTypes *) this, ppv); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } +} + +STDMETHODIMP_(ULONG) +CEnumMediaTypes::AddRef() +{ + return InterlockedIncrement(&m_cRef); +} + +STDMETHODIMP_(ULONG) +CEnumMediaTypes::Release() +{ + ULONG cRef = InterlockedDecrement(&m_cRef); + if (cRef == 0) { + delete this; + } + return cRef; +} + +/* One of an enumerator's basic member functions allows us to create a cloned + interface that initially has the same state. Since we are taking a snapshot + of an object (current position and all) we must lock access at the start */ + +STDMETHODIMP +CEnumMediaTypes::Clone(IEnumMediaTypes **ppEnum) +{ + CheckPointer(ppEnum,E_POINTER); + ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *)); + HRESULT hr = NOERROR; + + /* Check we are still in sync with the pin */ + if (AreWeOutOfSync() == TRUE) { + *ppEnum = NULL; + hr = VFW_E_ENUM_OUT_OF_SYNC; + } else { + + *ppEnum = new CEnumMediaTypes(m_pPin, + this); + + if (*ppEnum == NULL) { + hr = E_OUTOFMEMORY; + } + } + return hr; +} + + +/* Enumerate the next pin(s) after the current position. The client using this + interface passes in a pointer to an array of pointers each of which will + be filled in with a pointer to a fully initialised media type format + Return NOERROR if it all works, + S_FALSE if fewer than cMediaTypes were enumerated. + VFW_E_ENUM_OUT_OF_SYNC if the enumerator has been broken by + state changes in the filter + The actual count always correctly reflects the number of types in the array. +*/ + +STDMETHODIMP +CEnumMediaTypes::Next(ULONG cMediaTypes, // place this many types... + AM_MEDIA_TYPE **ppMediaTypes, // ...in this array + ULONG *pcFetched) // actual count passed +{ + CheckPointer(ppMediaTypes,E_POINTER); + ValidateReadWritePtr(ppMediaTypes,cMediaTypes * sizeof(AM_MEDIA_TYPE *)); + /* Check we are still in sync with the pin */ + if (AreWeOutOfSync() == TRUE) { + return VFW_E_ENUM_OUT_OF_SYNC; + } + + if (pcFetched!=NULL) { + ValidateWritePtr(pcFetched, sizeof(ULONG)); + *pcFetched = 0; // default unless we succeed + } + // now check that the parameter is valid + else if (cMediaTypes>1) { // pcFetched == NULL + return E_INVALIDARG; + } + ULONG cFetched = 0; // increment as we get each one. + + /* Return each media type by asking the filter for them in turn - If we + have an error code retured to us while we are retrieving a media type + we assume that our internal state is stale with respect to the filter + (for example the window size changing) so we return + VFW_E_ENUM_OUT_OF_SYNC */ + + while (cMediaTypes) { + + CMediaType cmt; + + HRESULT hr = m_pPin->GetMediaType(m_Position++, &cmt); + if (S_OK != hr) { + break; + } + + /* We now have a CMediaType object that contains the next media type + but when we assign it to the array position we CANNOT just assign + the AM_MEDIA_TYPE structure because as soon as the object goes out of + scope it will delete the memory we have just copied. The function + we use is CreateMediaType which allocates a task memory block */ + + /* Transfer across the format block manually to save an allocate + and free on the format block and generally go faster */ + + *ppMediaTypes = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); + if (*ppMediaTypes == NULL) { + break; + } + + /* Do a regular copy */ + **ppMediaTypes = (AM_MEDIA_TYPE)cmt; + + /* Make sure the destructor doesn't free these */ + cmt.pbFormat = NULL; + cmt.cbFormat = NULL; + cmt.pUnk = NULL; + + + ppMediaTypes++; + cFetched++; + cMediaTypes--; + } + + if (pcFetched!=NULL) { + *pcFetched = cFetched; + } + + return ( cMediaTypes==0 ? NOERROR : S_FALSE ); +} + + +/* Skip over one or more entries in the enumerator */ + +STDMETHODIMP +CEnumMediaTypes::Skip(ULONG cMediaTypes) +{ + // If we're skipping 0 elements we're guaranteed to skip the + // correct number of elements + if (cMediaTypes == 0) { + return S_OK; + } + + /* Check we are still in sync with the pin */ + if (AreWeOutOfSync() == TRUE) { + return VFW_E_ENUM_OUT_OF_SYNC; + } + + m_Position += cMediaTypes; + + /* See if we're over the end */ + CMediaType cmt; + return S_OK == m_pPin->GetMediaType(m_Position - 1, &cmt) ? S_OK : S_FALSE; +} + + +/* Set the current position back to the start */ +/* Reset has 3 simple steps: + * + * set position to head of list + * sync enumerator with object being enumerated + * return S_OK + */ + +STDMETHODIMP +CEnumMediaTypes::Reset() + +{ + m_Position = 0; + + // Bring the enumerator back into step with the current state. This + // may be a noop but ensures that the enumerator will be valid on the + // next call. + m_Version = m_pPin->GetMediaTypeVersion(); + return NOERROR; +} + + +//===================================================================== +//===================================================================== +// Implements CBasePin +//===================================================================== +//===================================================================== + + +/* NOTE The implementation of this class calls the CUnknown constructor with + a NULL outer unknown pointer. This has the effect of making us a self + contained class, ie any QueryInterface, AddRef or Release calls will be + routed to the class's NonDelegatingUnknown methods. You will typically + find that the classes that do this then override one or more of these + virtual functions to provide more specialised behaviour. A good example + of this is where a class wants to keep the QueryInterface internal but + still wants its lifetime controlled by the external object */ + +/* Constructor */ + +CBasePin::CBasePin(TCHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName, + PIN_DIRECTION dir) : + CUnknown( pObjectName, NULL ), + m_pFilter(pFilter), + m_pLock(pLock), + m_pName(NULL), + m_Connected(NULL), + m_dir(dir), + m_bRunTimeError(FALSE), + m_pQSink(NULL), + m_TypeVersion(1), + m_tStart(), + m_tStop(MAX_TIME), + m_bCanReconnectWhenActive(false), + m_bTryMyTypesFirst(false), + m_dRate(1.0) +{ + /* WARNING - pFilter is often not a properly constituted object at + this state (in particular QueryInterface may not work) - this + is because its owner is often its containing object and we + have been called from the containing object's constructor so + the filter's owner has not yet had its CUnknown constructor + called + */ + + ASSERT(pFilter != NULL); + ASSERT(pLock != NULL); + + if (pName) { + DWORD nameLen = lstrlenW(pName)+1; + m_pName = new WCHAR[nameLen]; + if (m_pName) { + CopyMemory(m_pName, pName, nameLen*sizeof(WCHAR)); + } + } + +#ifdef DEBUG + m_cRef = 0; +#endif +} + +#ifdef UNICODE +CBasePin::CBasePin(CHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName, + PIN_DIRECTION dir) : + CUnknown( pObjectName, NULL ), + m_pFilter(pFilter), + m_pLock(pLock), + m_pName(NULL), + m_Connected(NULL), + m_dir(dir), + m_bRunTimeError(FALSE), + m_pQSink(NULL), + m_TypeVersion(1), + m_tStart(), + m_tStop(MAX_TIME), + m_bCanReconnectWhenActive(false), + m_bTryMyTypesFirst(false), + m_dRate(1.0) +{ + /* WARNING - pFilter is often not a properly constituted object at + this state (in particular QueryInterface may not work) - this + is because its owner is often its containing object and we + have been called from the containing object's constructor so + the filter's owner has not yet had its CUnknown constructor + called + */ + + ASSERT(pFilter != NULL); + ASSERT(pLock != NULL); + + if (pName) { + DWORD nameLen = lstrlenW(pName)+1; + m_pName = new WCHAR[nameLen]; + if (m_pName) { + CopyMemory(m_pName, pName, nameLen*sizeof(WCHAR)); + } + } + +#ifdef DEBUG + m_cRef = 0; +#endif +} +#endif + +/* Destructor since a connected pin holds a reference count on us there is + no way that we can be deleted unless we are not currently connected */ + +CBasePin::~CBasePin() +{ + + // We don't call disconnect because if the filter is going away + // all the pins must have a reference count of zero so they must + // have been disconnected anyway - (but check the assumption) + ASSERT(m_Connected == FALSE); + + delete[] m_pName; + + // check the internal reference count is consistent + ASSERT(m_cRef == 0); +} + + +/* Override this to say what interfaces we support and where */ + +STDMETHODIMP +CBasePin::NonDelegatingQueryInterface(REFIID riid, void ** ppv) +{ + /* Do we have this interface */ + + if (riid == IID_IPin) { + return GetInterface((IPin *) this, ppv); + } else if (riid == IID_IQualityControl) { + return GetInterface((IQualityControl *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +/* Override to increment the owning filter's reference count */ + +STDMETHODIMP_(ULONG) +CBasePin::NonDelegatingAddRef() +{ + ASSERT(InterlockedIncrement(&m_cRef) > 0); + return m_pFilter->AddRef(); +} + + +/* Override to decrement the owning filter's reference count */ + +STDMETHODIMP_(ULONG) +CBasePin::NonDelegatingRelease() +{ + ASSERT(InterlockedDecrement(&m_cRef) >= 0); + return m_pFilter->Release(); +} + + +/* Displays pin connection information */ + +#ifdef DEBUG +void +CBasePin::DisplayPinInfo(IPin *pReceivePin) +{ + + if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) { + PIN_INFO ConnectPinInfo; + PIN_INFO ReceivePinInfo; + + if (FAILED(QueryPinInfo(&ConnectPinInfo))) { + (void)StringCchCopyW(ConnectPinInfo.achName, NUMELMS(ConnectPinInfo.achName),L"Bad Pin"); + } else { + QueryPinInfoReleaseFilter(ConnectPinInfo); + } + + if (FAILED(pReceivePin->QueryPinInfo(&ReceivePinInfo))) { + (void)StringCchCopyW(ReceivePinInfo.achName, NUMELMS(ReceivePinInfo.achName),L"Bad Pin"); + } else { + QueryPinInfoReleaseFilter(ReceivePinInfo); + } + + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying to connect Pins :"))); + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" <%ls>"), ConnectPinInfo.achName)); + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" <%ls>"), ReceivePinInfo.achName)); + } +} +#endif + + +/* Displays general information on the pin media type */ + +#ifdef DEBUG +void CBasePin::DisplayTypeInfo(IPin *pPin, const CMediaType *pmt) +{ + UNREFERENCED_PARAMETER(pPin); + if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) { + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying media type:"))); + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" major type: %hs"), + GuidNames[*pmt->Type()])); + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" sub type : %hs"), + GuidNames[*pmt->Subtype()])); + } +} +#endif + +/* Asked to connect to a pin. A pin is always attached to an owning filter + object so we always delegate our locking to that object. We first of all + retrieve a media type enumerator for the input pin and see if we accept + any of the formats that it would ideally like, failing that we retrieve + our enumerator and see if it will accept any of our preferred types */ + +STDMETHODIMP +CBasePin::Connect( + IPin * pReceivePin, + const AM_MEDIA_TYPE *pmt // optional media type +) +{ + CheckPointer(pReceivePin,E_POINTER); + ValidateReadPtr(pReceivePin,sizeof(IPin)); + CAutoLock cObjectLock(m_pLock); + DisplayPinInfo(pReceivePin); + + /* See if we are already connected */ + + if (m_Connected) { + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Already connected"))); + return VFW_E_ALREADY_CONNECTED; + } + + /* See if the filter is active */ + if (!IsStopped() && !m_bCanReconnectWhenActive) { + return VFW_E_NOT_STOPPED; + } + + + // Find a mutually agreeable media type - + // Pass in the template media type. If this is partially specified, + // each of the enumerated media types will need to be checked against + // it. If it is non-null and fully specified, we will just try to connect + // with this. + + const CMediaType * ptype = (CMediaType*)pmt; + HRESULT hr = AgreeMediaType(pReceivePin, ptype); + if (FAILED(hr)) { + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to agree type"))); + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + + + return hr; + } + + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Connection succeeded"))); + + + return NOERROR; +} + +// given a specific media type, attempt a connection (includes +// checking that the type is acceptable to this pin) +HRESULT +CBasePin::AttemptConnection( + IPin* pReceivePin, // connect to this pin + const CMediaType* pmt // using this type +) +{ + // The caller should hold the filter lock becasue this function + // uses m_Connected. The caller should also hold the filter lock + // because this function calls SetMediaType(), IsStopped() and + // CompleteConnect(). + ASSERT(CritCheckIn(m_pLock)); + + // Check that the connection is valid -- need to do this for every + // connect attempt since BreakConnect will undo it. + HRESULT hr = CheckConnect(pReceivePin); + if (FAILED(hr)) { + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("CheckConnect failed"))); + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + + return hr; + } + + DisplayTypeInfo(pReceivePin, pmt); + + /* Check we will accept this media type */ + + hr = CheckMediaType(pmt); + if (hr == NOERROR) { + + /* Make ourselves look connected otherwise ReceiveConnection + may not be able to complete the connection + */ + m_Connected = pReceivePin; + m_Connected->AddRef(); + hr = SetMediaType(pmt); + if (SUCCEEDED(hr)) { + /* See if the other pin will accept this type */ + + hr = pReceivePin->ReceiveConnection((IPin *)this, pmt); + if (SUCCEEDED(hr)) { + /* Complete the connection */ + + hr = CompleteConnect(pReceivePin); + if (SUCCEEDED(hr)) { + return hr; + } else { + DbgLog((LOG_TRACE, + CONNECT_TRACE_LEVEL, + TEXT("Failed to complete connection"))); + pReceivePin->Disconnect(); + } + } + } + } else { + // we cannot use this media type + + // return a specific media type error if there is one + // or map a general failure code to something more helpful + // (in particular S_FALSE gets changed to an error code) + if (SUCCEEDED(hr) || + (hr == E_FAIL) || + (hr == E_INVALIDARG)) { + hr = VFW_E_TYPE_NOT_ACCEPTED; + } + } + + // BreakConnect and release any connection here in case CheckMediaType + // failed, or if we set anything up during a call back during + // ReceiveConnection. + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + + /* If failed then undo our state */ + if (m_Connected) { + m_Connected->Release(); + m_Connected = NULL; + } + + return hr; +} + +/* Given an enumerator we cycle through all the media types it proposes and + firstly suggest them to our derived pin class and if that succeeds try + them with the pin in a ReceiveConnection call. This means that if our pin + proposes a media type we still check in here that we can support it. This + is deliberate so that in simple cases the enumerator can hold all of the + media types even if some of them are not really currently available */ + +HRESULT CBasePin::TryMediaTypes( + IPin *pReceivePin, + const CMediaType *pmt, + IEnumMediaTypes *pEnum) +{ + /* Reset the current enumerator position */ + + HRESULT hr = pEnum->Reset(); + if (FAILED(hr)) { + return hr; + } + + CMediaType *pMediaType = NULL; + ULONG ulMediaCount = 0; + + // attempt to remember a specific error code if there is one + HRESULT hrFailure = S_OK; + + for (;;) { + + /* Retrieve the next media type NOTE each time round the loop the + enumerator interface will allocate another AM_MEDIA_TYPE structure + If we are successful then we copy it into our output object, if + not then we must delete the memory allocated before returning */ + + hr = pEnum->Next(1, (AM_MEDIA_TYPE**)&pMediaType,&ulMediaCount); + if (hr != S_OK) { + if (S_OK == hrFailure) { + hrFailure = VFW_E_NO_ACCEPTABLE_TYPES; + } + return hrFailure; + } + + + ASSERT(ulMediaCount == 1); + ASSERT(pMediaType); + + // check that this matches the partial type (if any) + + if ((pmt == NULL) || + pMediaType->MatchesPartial(pmt)) { + + hr = AttemptConnection(pReceivePin, pMediaType); + + // attempt to remember a specific error code + if (FAILED(hr) && + SUCCEEDED(hrFailure) && + (hr != E_FAIL) && + (hr != E_INVALIDARG) && + (hr != VFW_E_TYPE_NOT_ACCEPTED)) { + hrFailure = hr; + } + } else { + hr = VFW_E_NO_ACCEPTABLE_TYPES; + } + + DeleteMediaType(pMediaType); + + if (S_OK == hr) { + return hr; + } + } +} + + +/* This is called to make the connection, including the taask of finding + a media type for the pin connection. pmt is the proposed media type + from the Connect call: if this is fully specified, we will try that. + Otherwise we enumerate and try all the input pin's types first and + if that fails we then enumerate and try all our preferred media types. + For each media type we check it against pmt (if non-null and partially + specified) as well as checking that both pins will accept it. + */ + +HRESULT CBasePin::AgreeMediaType( + IPin *pReceivePin, + const CMediaType *pmt) +{ + ASSERT(pReceivePin); + IEnumMediaTypes *pEnumMediaTypes = NULL; + + // if the media type is fully specified then use that + if ( (pmt != NULL) && (!pmt->IsPartiallySpecified())) { + + // if this media type fails, then we must fail the connection + // since if pmt is nonnull we are only allowed to connect + // using a type that matches it. + + return AttemptConnection(pReceivePin, pmt); + } + + + /* Try the other pin's enumerator */ + + HRESULT hrFailure = VFW_E_NO_ACCEPTABLE_TYPES; + + for (int i = 0; i < 2; i++) { + HRESULT hr; + if (i == (int)m_bTryMyTypesFirst) { + hr = pReceivePin->EnumMediaTypes(&pEnumMediaTypes); + } else { + hr = EnumMediaTypes(&pEnumMediaTypes); + } + if (SUCCEEDED(hr)) { + ASSERT(pEnumMediaTypes); + hr = TryMediaTypes(pReceivePin,pmt,pEnumMediaTypes); + pEnumMediaTypes->Release(); + if (SUCCEEDED(hr)) { + return NOERROR; + } else { + // try to remember specific error codes if there are any + if ((hr != E_FAIL) && + (hr != E_INVALIDARG) && + (hr != VFW_E_TYPE_NOT_ACCEPTED)) { + hrFailure = hr; + } + } + } + } + + return hrFailure; +} + + +/* Called when we want to complete a connection to another filter. Failing + this will also fail the connection and disconnect the other pin as well */ + +HRESULT +CBasePin::CompleteConnect(IPin *pReceivePin) +{ + UNREFERENCED_PARAMETER(pReceivePin); + return NOERROR; +} + + +/* This is called to set the format for a pin connection - CheckMediaType + will have been called to check the connection format and if it didn't + return an error code then this (virtual) function will be invoked */ + +HRESULT +CBasePin::SetMediaType(const CMediaType *pmt) +{ + HRESULT hr = m_mt.Set(*pmt); + if (FAILED(hr)) { + return hr; + } + + return NOERROR; +} + + +/* This is called during Connect() to provide a virtual method that can do + any specific check needed for connection such as QueryInterface. This + base class method just checks that the pin directions don't match */ + +HRESULT +CBasePin::CheckConnect(IPin * pPin) +{ + /* Check that pin directions DONT match */ + + PIN_DIRECTION pd; + pPin->QueryDirection(&pd); + + ASSERT((pd == PINDIR_OUTPUT) || (pd == PINDIR_INPUT)); + ASSERT((m_dir == PINDIR_OUTPUT) || (m_dir == PINDIR_INPUT)); + + // we should allow for non-input and non-output connections? + if (pd == m_dir) { + return VFW_E_INVALID_DIRECTION; + } + return NOERROR; +} + + +/* This is called when we realise we can't make a connection to the pin and + must undo anything we did in CheckConnect - override to release QIs done */ + +HRESULT +CBasePin::BreakConnect() +{ + return NOERROR; +} + + +/* Called normally by an output pin on an input pin to try and establish a + connection. +*/ + +STDMETHODIMP +CBasePin::ReceiveConnection( + IPin * pConnector, // this is the pin who we will connect to + const AM_MEDIA_TYPE *pmt // this is the media type we will exchange +) +{ + CheckPointer(pConnector,E_POINTER); + CheckPointer(pmt,E_POINTER); + ValidateReadPtr(pConnector,sizeof(IPin)); + ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE)); + CAutoLock cObjectLock(m_pLock); + + /* Are we already connected */ + if (m_Connected) { + return VFW_E_ALREADY_CONNECTED; + } + + /* See if the filter is active */ + if (!IsStopped() && !m_bCanReconnectWhenActive) { + return VFW_E_NOT_STOPPED; + } + + HRESULT hr = CheckConnect(pConnector); + if (FAILED(hr)) { + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + + + return hr; + } + + /* Ask derived class if this media type is ok */ + + CMediaType * pcmt = (CMediaType*) pmt; + hr = CheckMediaType(pcmt); + if (hr != NOERROR) { + // no -we don't support this media type + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + + // return a specific media type error if there is one + // or map a general failure code to something more helpful + // (in particular S_FALSE gets changed to an error code) + if (SUCCEEDED(hr) || + (hr == E_FAIL) || + (hr == E_INVALIDARG)) { + hr = VFW_E_TYPE_NOT_ACCEPTED; + } + + + return hr; + } + + /* Complete the connection */ + + m_Connected = pConnector; + m_Connected->AddRef(); + hr = SetMediaType(pcmt); + if (SUCCEEDED(hr)) { + hr = CompleteConnect(pConnector); + if (SUCCEEDED(hr)) { + + + return NOERROR; + } + } + + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to set the media type or failed to complete the connection."))); + m_Connected->Release(); + m_Connected = NULL; + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + + + return hr; +} + + +/* Called when we want to terminate a pin connection */ + +STDMETHODIMP +CBasePin::Disconnect() +{ + CAutoLock cObjectLock(m_pLock); + + /* See if the filter is active */ + if (!IsStopped()) { + return VFW_E_NOT_STOPPED; + } + + return DisconnectInternal(); +} + +STDMETHODIMP +CBasePin::DisconnectInternal() +{ + ASSERT(CritCheckIn(m_pLock)); + + if (m_Connected) { + HRESULT hr = BreakConnect(); + if( FAILED( hr ) ) { + + + // There is usually a bug in the program if BreakConnect() fails. + DbgBreak( "WARNING: BreakConnect() failed in CBasePin::Disconnect()." ); + return hr; + } + + m_Connected->Release(); + m_Connected = NULL; + + + return S_OK; + } else { + // no connection - not an error + + + return S_FALSE; + } +} + + +/* Return an AddRef()'d pointer to the connected pin if there is one */ +STDMETHODIMP +CBasePin::ConnectedTo( + IPin **ppPin +) +{ + CheckPointer(ppPin,E_POINTER); + ValidateReadWritePtr(ppPin,sizeof(IPin *)); + // + // It's pointless to lock here. + // The caller should ensure integrity. + // + + IPin *pPin = m_Connected; + *ppPin = pPin; + if (pPin != NULL) { + pPin->AddRef(); + return S_OK; + } else { + ASSERT(*ppPin == NULL); + return VFW_E_NOT_CONNECTED; + } +} + +/* Return the media type of the connection */ +STDMETHODIMP +CBasePin::ConnectionMediaType( + AM_MEDIA_TYPE *pmt +) +{ + CheckPointer(pmt,E_POINTER); + ValidateReadWritePtr(pmt,sizeof(AM_MEDIA_TYPE)); + CAutoLock cObjectLock(m_pLock); + + /* Copy constructor of m_mt allocates the memory */ + if (IsConnected()) { + CopyMediaType( pmt, &m_mt ); + return S_OK; + } else { + ((CMediaType *)pmt)->InitMediaType(); + return VFW_E_NOT_CONNECTED; + } +} + +/* Return information about the filter we are connect to */ + +STDMETHODIMP +CBasePin::QueryPinInfo( + PIN_INFO * pInfo +) +{ + CheckPointer(pInfo,E_POINTER); + ValidateReadWritePtr(pInfo,sizeof(PIN_INFO)); + + pInfo->pFilter = m_pFilter; + if (m_pFilter) { + m_pFilter->AddRef(); + } + + if (m_pName) { + lstrcpynW(pInfo->achName, m_pName, sizeof(pInfo->achName)/sizeof(WCHAR)); + } else { + pInfo->achName[0] = L'\0'; + } + + pInfo->dir = m_dir; + + return NOERROR; +} + +STDMETHODIMP +CBasePin::QueryDirection( + PIN_DIRECTION * pPinDir +) +{ + CheckPointer(pPinDir,E_POINTER); + ValidateReadWritePtr(pPinDir,sizeof(PIN_DIRECTION)); + + *pPinDir = m_dir; + return NOERROR; +} + +// Default QueryId to return the pin's name +STDMETHODIMP +CBasePin::QueryId( + LPWSTR * Id +) +{ + // We're not going away because someone's got a pointer to us + // so there's no need to lock + + return AMGetWideString(Name(), Id); +} + +/* Does this pin support this media type WARNING this interface function does + not lock the main object as it is meant to be asynchronous by nature - if + the media types you support depend on some internal state that is updated + dynamically then you will need to implement locking in a derived class */ + +STDMETHODIMP +CBasePin::QueryAccept( + const AM_MEDIA_TYPE *pmt +) +{ + CheckPointer(pmt,E_POINTER); + ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE)); + + /* The CheckMediaType method is valid to return error codes if the media + type is horrible, an example might be E_INVALIDARG. What we do here + is map all the error codes into either S_OK or S_FALSE regardless */ + + HRESULT hr = CheckMediaType((CMediaType*)pmt); + if (FAILED(hr)) { + return S_FALSE; + } + // note that the only defined success codes should be S_OK and S_FALSE... + return hr; +} + + +/* This can be called to return an enumerator for the pin's list of preferred + media types. An input pin is not obliged to have any preferred formats + although it can do. For example, the window renderer has a preferred type + which describes a video image that matches the current window size. All + output pins should expose at least one preferred format otherwise it is + possible that neither pin has any types and so no connection is possible */ + +STDMETHODIMP +CBasePin::EnumMediaTypes( + IEnumMediaTypes **ppEnum +) +{ + CheckPointer(ppEnum,E_POINTER); + ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *)); + + /* Create a new ref counted enumerator */ + + *ppEnum = new CEnumMediaTypes(this, + NULL); + + if (*ppEnum == NULL) { + return E_OUTOFMEMORY; + } + + return NOERROR; +} + + + +/* This is a virtual function that returns a media type corresponding with + place iPosition in the list. This base class simply returns an error as + we support no media types by default but derived classes should override */ + +HRESULT CBasePin::GetMediaType(int iPosition, CMediaType *pMediaType) +{ + UNREFERENCED_PARAMETER(iPosition); + UNREFERENCED_PARAMETER(pMediaType); + return E_UNEXPECTED; +} + + +/* This is a virtual function that returns the current media type version. + The base class initialises the media type enumerators with the value 1 + By default we always returns that same value. A Derived class may change + the list of media types available and after doing so it should increment + the version either in a method derived from this, or more simply by just + incrementing the m_TypeVersion base pin variable. The type enumerators + call this when they want to see if their enumerations are out of date */ + +LONG CBasePin::GetMediaTypeVersion() +{ + return m_TypeVersion; +} + + +/* Increment the cookie representing the current media type version */ + +void CBasePin::IncrementTypeVersion() +{ + InterlockedIncrement(&m_TypeVersion); +} + + +/* Called by IMediaFilter implementation when the state changes from Stopped + to either paused or running and in derived classes could do things like + commit memory and grab hardware resource (the default is to do nothing) */ + +HRESULT +CBasePin::Active(void) +{ + return NOERROR; +} + +/* Called by IMediaFilter implementation when the state changes from + to either paused to running and in derived classes could do things like + commit memory and grab hardware resource (the default is to do nothing) */ + +HRESULT +CBasePin::Run(REFERENCE_TIME tStart) +{ + UNREFERENCED_PARAMETER(tStart); + return NOERROR; +} + + +/* Also called by the IMediaFilter implementation when the state changes to + Stopped at which point you should decommit allocators and free hardware + resources you grabbed in the Active call (default is also to do nothing) */ + +HRESULT +CBasePin::Inactive(void) +{ + m_bRunTimeError = FALSE; + return NOERROR; +} + + +// Called when no more data will arrive +STDMETHODIMP +CBasePin::EndOfStream(void) +{ + return S_OK; +} + + +STDMETHODIMP +CBasePin::SetSink(IQualityControl * piqc) +{ + CAutoLock cObjectLock(m_pLock); + if (piqc) ValidateReadPtr(piqc,sizeof(IQualityControl)); + m_pQSink = piqc; + return NOERROR; +} // SetSink + + +STDMETHODIMP +CBasePin::Notify(IBaseFilter * pSender, Quality q) +{ + UNREFERENCED_PARAMETER(q); + UNREFERENCED_PARAMETER(pSender); + DbgBreak("IQualityControl::Notify not over-ridden from CBasePin. (IGNORE is OK)"); + return E_NOTIMPL; +} //Notify + + +// NewSegment notifies of the start/stop/rate applying to the data +// about to be received. Default implementation records data and +// returns S_OK. +// Override this to pass downstream. +STDMETHODIMP +CBasePin::NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + m_tStart = tStart; + m_tStop = tStop; + m_dRate = dRate; + + return S_OK; +} + + +//===================================================================== +//===================================================================== +// Implements CBaseOutputPin +//===================================================================== +//===================================================================== + + +CBaseOutputPin::CBaseOutputPin(TCHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName) : + CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT), + m_pAllocator(NULL), + m_pInputPin(NULL) +{ + ASSERT(pFilter); +} + +#ifdef UNICODE +CBaseOutputPin::CBaseOutputPin(CHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName) : + CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT), + m_pAllocator(NULL), + m_pInputPin(NULL) +{ + ASSERT(pFilter); +} +#endif + +/* This is called after a media type has been proposed + + Try to complete the connection by agreeing the allocator +*/ +HRESULT +CBaseOutputPin::CompleteConnect(IPin *pReceivePin) +{ + UNREFERENCED_PARAMETER(pReceivePin); + return DecideAllocator(m_pInputPin, &m_pAllocator); +} + + +/* This method is called when the output pin is about to try and connect to + an input pin. It is at this point that you should try and grab any extra + interfaces that you need, in this case IMemInputPin. Because this is + only called if we are not currently connected we do NOT need to call + BreakConnect. This also makes it easier to derive classes from us as + BreakConnect is only called when we actually have to break a connection + (or a partly made connection) and not when we are checking a connection */ + +/* Overriden from CBasePin */ + +HRESULT +CBaseOutputPin::CheckConnect(IPin * pPin) +{ + HRESULT hr = CBasePin::CheckConnect(pPin); + if (FAILED(hr)) { + return hr; + } + + // get an input pin and an allocator interface + hr = pPin->QueryInterface(IID_IMemInputPin, (void **) &m_pInputPin); + if (FAILED(hr)) { + return hr; + } + return NOERROR; +} + + +/* Overriden from CBasePin */ + +HRESULT +CBaseOutputPin::BreakConnect() +{ + /* Release any allocator we hold */ + + if (m_pAllocator) { + // Always decommit the allocator because a downstream filter may or + // may not decommit the connection's allocator. A memory leak could + // occur if the allocator is not decommited when a connection is broken. + HRESULT hr = m_pAllocator->Decommit(); + if( FAILED( hr ) ) { + return hr; + } + + m_pAllocator->Release(); + m_pAllocator = NULL; + } + + /* Release any input pin interface we hold */ + + if (m_pInputPin) { + m_pInputPin->Release(); + m_pInputPin = NULL; + } + return NOERROR; +} + + +/* This is called when the input pin didn't give us a valid allocator */ + +HRESULT +CBaseOutputPin::InitAllocator(IMemAllocator **ppAlloc) +{ + return CreateMemoryAllocator(ppAlloc); +} + + +/* Decide on an allocator, override this if you want to use your own allocator + Override DecideBufferSize to call SetProperties. If the input pin fails + the GetAllocator call then this will construct a CMemAllocator and call + DecideBufferSize on that, and if that fails then we are completely hosed. + If the you succeed the DecideBufferSize call, we will notify the input + pin of the selected allocator. NOTE this is called during Connect() which + therefore looks after grabbing and locking the object's critical section */ + +// We query the input pin for its requested properties and pass this to +// DecideBufferSize to allow it to fulfill requests that it is happy +// with (eg most people don't care about alignment and are thus happy to +// use the downstream pin's alignment request). + +HRESULT +CBaseOutputPin::DecideAllocator(IMemInputPin *pPin, IMemAllocator **ppAlloc) +{ + HRESULT hr = NOERROR; + *ppAlloc = NULL; + + // get downstream prop request + // the derived class may modify this in DecideBufferSize, but + // we assume that he will consistently modify it the same way, + // so we only get it once + ALLOCATOR_PROPERTIES prop; + ZeroMemory(&prop, sizeof(prop)); + + // whatever he returns, we assume prop is either all zeros + // or he has filled it out. + pPin->GetAllocatorRequirements(&prop); + + // if he doesn't care about alignment, then set it to 1 + if (prop.cbAlign == 0) { + prop.cbAlign = 1; + } + + /* Try the allocator provided by the input pin */ + + hr = pPin->GetAllocator(ppAlloc); + if (SUCCEEDED(hr)) { + + hr = DecideBufferSize(*ppAlloc, &prop); + if (SUCCEEDED(hr)) { + hr = pPin->NotifyAllocator(*ppAlloc, FALSE); + if (SUCCEEDED(hr)) { + return NOERROR; + } + } + } + + /* If the GetAllocator failed we may not have an interface */ + + if (*ppAlloc) { + (*ppAlloc)->Release(); + *ppAlloc = NULL; + } + + /* Try the output pin's allocator by the same method */ + + hr = InitAllocator(ppAlloc); + if (SUCCEEDED(hr)) { + + // note - the properties passed here are in the same + // structure as above and may have been modified by + // the previous call to DecideBufferSize + hr = DecideBufferSize(*ppAlloc, &prop); + if (SUCCEEDED(hr)) { + hr = pPin->NotifyAllocator(*ppAlloc, FALSE); + if (SUCCEEDED(hr)) { + return NOERROR; + } + } + } + + /* Likewise we may not have an interface to release */ + + if (*ppAlloc) { + (*ppAlloc)->Release(); + *ppAlloc = NULL; + } + return hr; +} + + +/* This returns an empty sample buffer from the allocator WARNING the same + dangers and restrictions apply here as described below for Deliver() */ + +HRESULT +CBaseOutputPin::GetDeliveryBuffer(IMediaSample ** ppSample, + REFERENCE_TIME * pStartTime, + REFERENCE_TIME * pEndTime, + DWORD dwFlags) +{ + if (m_pAllocator != NULL) { + return m_pAllocator->GetBuffer(ppSample,pStartTime,pEndTime,dwFlags); + } else { + return E_NOINTERFACE; + } +} + + +/* Deliver a filled-in sample to the connected input pin. NOTE the object must + have locked itself before calling us otherwise we may get halfway through + executing this method only to find the filter graph has got in and + disconnected us from the input pin. If the filter has no worker threads + then the lock is best applied on Receive(), otherwise it should be done + when the worker thread is ready to deliver. There is a wee snag to worker + threads that this shows up. The worker thread must lock the object when + it is ready to deliver a sample, but it may have to wait until a state + change has completed, but that may never complete because the state change + is waiting for the worker thread to complete. The way to handle this is for + the state change code to grab the critical section, then set an abort event + for the worker thread, then release the critical section and wait for the + worker thread to see the event we set and then signal that it has finished + (with another event). At which point the state change code can complete */ + +// note (if you've still got any breath left after reading that) that you +// need to release the sample yourself after this call. if the connected +// input pin needs to hold onto the sample beyond the call, it will addref +// the sample itself. + +// of course you must release this one and call GetDeliveryBuffer for the +// next. You cannot reuse it directly. + +HRESULT +CBaseOutputPin::Deliver(IMediaSample * pSample) +{ + if (m_pInputPin == NULL) { + return VFW_E_NOT_CONNECTED; + } + + + return m_pInputPin->Receive(pSample); +} + + +// called from elsewhere in our filter to pass EOS downstream to +// our connected input pin +HRESULT +CBaseOutputPin::DeliverEndOfStream(void) +{ + // remember this is on IPin not IMemInputPin + if (m_Connected == NULL) { + return VFW_E_NOT_CONNECTED; + } + return m_Connected->EndOfStream(); +} + + +/* Commit the allocator's memory, this is called through IMediaFilter + which is responsible for locking the object before calling us */ + +HRESULT +CBaseOutputPin::Active(void) +{ + if (m_pAllocator == NULL) { + return VFW_E_NO_ALLOCATOR; + } + return m_pAllocator->Commit(); +} + + +/* Free up or unprepare allocator's memory, this is called through + IMediaFilter which is responsible for locking the object first */ + +HRESULT +CBaseOutputPin::Inactive(void) +{ + m_bRunTimeError = FALSE; + if (m_pAllocator == NULL) { + return VFW_E_NO_ALLOCATOR; + } + return m_pAllocator->Decommit(); +} + +// we have a default handling of EndOfStream which is to return +// an error, since this should be called on input pins only +STDMETHODIMP +CBaseOutputPin::EndOfStream(void) +{ + return E_UNEXPECTED; +} + + +// BeginFlush should be called on input pins only +STDMETHODIMP +CBaseOutputPin::BeginFlush(void) +{ + return E_UNEXPECTED; +} + +// EndFlush should be called on input pins only +STDMETHODIMP +CBaseOutputPin::EndFlush(void) +{ + return E_UNEXPECTED; +} + +// call BeginFlush on the connected input pin +HRESULT +CBaseOutputPin::DeliverBeginFlush(void) +{ + // remember this is on IPin not IMemInputPin + if (m_Connected == NULL) { + return VFW_E_NOT_CONNECTED; + } + return m_Connected->BeginFlush(); +} + +// call EndFlush on the connected input pin +HRESULT +CBaseOutputPin::DeliverEndFlush(void) +{ + // remember this is on IPin not IMemInputPin + if (m_Connected == NULL) { + return VFW_E_NOT_CONNECTED; + } + return m_Connected->EndFlush(); +} +// deliver NewSegment to connected pin +HRESULT +CBaseOutputPin::DeliverNewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + if (m_Connected == NULL) { + return VFW_E_NOT_CONNECTED; + } + return m_Connected->NewSegment(tStart, tStop, dRate); +} + + +//===================================================================== +//===================================================================== +// Implements CBaseInputPin +//===================================================================== +//===================================================================== + + +/* Constructor creates a default allocator object */ + +CBaseInputPin::CBaseInputPin(TCHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pPinName) : + CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT), + m_pAllocator(NULL), + m_bReadOnly(FALSE), + m_bFlushing(FALSE) +{ + ZeroMemory(&m_SampleProps, sizeof(m_SampleProps)); +} + +#ifdef UNICODE +CBaseInputPin::CBaseInputPin(CHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pPinName) : + CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT), + m_pAllocator(NULL), + m_bReadOnly(FALSE), + m_bFlushing(FALSE) +{ + ZeroMemory(&m_SampleProps, sizeof(m_SampleProps)); +} +#endif + +/* Destructor releases it's reference count on the default allocator */ + +CBaseInputPin::~CBaseInputPin() +{ + if (m_pAllocator != NULL) { + m_pAllocator->Release(); + m_pAllocator = NULL; + } +} + + +// override this to publicise our interfaces +STDMETHODIMP +CBaseInputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + /* Do we know about this interface */ + + if (riid == IID_IMemInputPin) { + return GetInterface((IMemInputPin *) this, ppv); + } else { + return CBasePin::NonDelegatingQueryInterface(riid, ppv); + } +} + + +/* Return the allocator interface that this input pin would like the output + pin to use. NOTE subsequent calls to GetAllocator should all return an + interface onto the SAME object so we create one object at the start + + Note: + The allocator is Release()'d on disconnect and replaced on + NotifyAllocator(). + + Override this to provide your own allocator. +*/ + +STDMETHODIMP +CBaseInputPin::GetAllocator( + IMemAllocator **ppAllocator) +{ + CheckPointer(ppAllocator,E_POINTER); + ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *)); + CAutoLock cObjectLock(m_pLock); + + if (m_pAllocator == NULL) { + HRESULT hr = CreateMemoryAllocator(&m_pAllocator); + if (FAILED(hr)) { + return hr; + } + } + ASSERT(m_pAllocator != NULL); + *ppAllocator = m_pAllocator; + m_pAllocator->AddRef(); + return NOERROR; +} + + +/* Tell the input pin which allocator the output pin is actually going to use + Override this if you care - NOTE the locking we do both here and also in + GetAllocator is unnecessary but derived classes that do something useful + will undoubtedly have to lock the object so this might help remind people */ + +STDMETHODIMP +CBaseInputPin::NotifyAllocator( + IMemAllocator * pAllocator, + BOOL bReadOnly) +{ + CheckPointer(pAllocator,E_POINTER); + ValidateReadPtr(pAllocator,sizeof(IMemAllocator)); + CAutoLock cObjectLock(m_pLock); + + IMemAllocator *pOldAllocator = m_pAllocator; + pAllocator->AddRef(); + m_pAllocator = pAllocator; + + if (pOldAllocator != NULL) { + pOldAllocator->Release(); + } + + // the readonly flag indicates whether samples from this allocator should + // be regarded as readonly - if true, then inplace transforms will not be + // allowed. + m_bReadOnly = (BYTE)bReadOnly; + return NOERROR; +} + + +HRESULT +CBaseInputPin::BreakConnect() +{ + /* We don't need our allocator any more */ + if (m_pAllocator) { + // Always decommit the allocator because a downstream filter may or + // may not decommit the connection's allocator. A memory leak could + // occur if the allocator is not decommited when a pin is disconnected. + HRESULT hr = m_pAllocator->Decommit(); + if( FAILED( hr ) ) { + return hr; + } + + m_pAllocator->Release(); + m_pAllocator = NULL; + } + + return S_OK; +} + + +/* Do something with this media sample - this base class checks to see if the + format has changed with this media sample and if so checks that the filter + will accept it, generating a run time error if not. Once we have raised a + run time error we set a flag so that no more samples will be accepted + + It is important that any filter should override this method and implement + synchronization so that samples are not processed when the pin is + disconnected etc +*/ + +STDMETHODIMP +CBaseInputPin::Receive(IMediaSample *pSample) +{ + CheckPointer(pSample,E_POINTER); + ValidateReadPtr(pSample,sizeof(IMediaSample)); + ASSERT(pSample); + + HRESULT hr = CheckStreaming(); + if (S_OK != hr) { + return hr; + } + + + + /* Check for IMediaSample2 */ + IMediaSample2 *pSample2; + if (SUCCEEDED(pSample->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) { + hr = pSample2->GetProperties(sizeof(m_SampleProps), (PBYTE)&m_SampleProps); + pSample2->Release(); + if (FAILED(hr)) { + return hr; + } + } else { + /* Get the properties the hard way */ + m_SampleProps.cbData = sizeof(m_SampleProps); + m_SampleProps.dwTypeSpecificFlags = 0; + m_SampleProps.dwStreamId = AM_STREAM_MEDIA; + m_SampleProps.dwSampleFlags = 0; + if (S_OK == pSample->IsDiscontinuity()) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY; + } + if (S_OK == pSample->IsPreroll()) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_PREROLL; + } + if (S_OK == pSample->IsSyncPoint()) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT; + } + if (SUCCEEDED(pSample->GetTime(&m_SampleProps.tStart, + &m_SampleProps.tStop))) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_TIMEVALID | + AM_SAMPLE_STOPVALID; + } + if (S_OK == pSample->GetMediaType(&m_SampleProps.pMediaType)) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_TYPECHANGED; + } + pSample->GetPointer(&m_SampleProps.pbBuffer); + m_SampleProps.lActual = pSample->GetActualDataLength(); + m_SampleProps.cbBuffer = pSample->GetSize(); + } + + /* Has the format changed in this sample */ + + if (!(m_SampleProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED)) { + return NOERROR; + } + + /* Check the derived class accepts this format */ + /* This shouldn't fail as the source must call QueryAccept first */ + + hr = CheckMediaType((CMediaType *)m_SampleProps.pMediaType); + + if (hr == NOERROR) { + return NOERROR; + } + + /* Raise a runtime error if we fail the media type */ + + m_bRunTimeError = TRUE; + EndOfStream(); + m_pFilter->NotifyEvent(EC_ERRORABORT,VFW_E_TYPE_NOT_ACCEPTED,0); + return VFW_E_INVALIDMEDIATYPE; +} + + +/* Receive multiple samples */ +STDMETHODIMP +CBaseInputPin::ReceiveMultiple ( + IMediaSample **pSamples, + long nSamples, + long *nSamplesProcessed) +{ + CheckPointer(pSamples,E_POINTER); + ValidateReadPtr(pSamples,nSamples * sizeof(IMediaSample *)); + + HRESULT hr = S_OK; + *nSamplesProcessed = 0; + while (nSamples-- > 0) { + hr = Receive(pSamples[*nSamplesProcessed]); + + /* S_FALSE means don't send any more */ + if (hr != S_OK) { + break; + } + (*nSamplesProcessed)++; + } + return hr; +} + +/* See if Receive() might block */ +STDMETHODIMP +CBaseInputPin::ReceiveCanBlock() +{ + /* Ask all the output pins if they block + If there are no output pin assume we do block + */ + int cPins = m_pFilter->GetPinCount(); + int cOutputPins = 0; + for (int c = 0; c < cPins; c++) { + CBasePin *pPin = m_pFilter->GetPin(c); + PIN_DIRECTION pd; + HRESULT hr = pPin->QueryDirection(&pd); + if (FAILED(hr)) { + return hr; + } + + if (pd == PINDIR_OUTPUT) { + + IPin *pConnected; + hr = pPin->ConnectedTo(&pConnected); + if (SUCCEEDED(hr)) { + ASSERT(pConnected != NULL); + cOutputPins++; + IMemInputPin *pInputPin; + hr = pConnected->QueryInterface( + IID_IMemInputPin, + (void **)&pInputPin); + pConnected->Release(); + if (SUCCEEDED(hr)) { + hr = pInputPin->ReceiveCanBlock(); + pInputPin->Release(); + if (hr != S_FALSE) { + return S_OK; + } + } else { + /* There's a transport we don't understand here */ + return S_OK; + } + } + } + } + return cOutputPins == 0 ? S_OK : S_FALSE; +} + +// Default handling for BeginFlush - call at the beginning +// of your implementation (makes sure that all Receive calls +// fail). After calling this, you need to free any queued data +// and then call downstream. +STDMETHODIMP +CBaseInputPin::BeginFlush(void) +{ + // BeginFlush is NOT synchronized with streaming but is part of + // a control action - hence we synchronize with the filter + CAutoLock lck(m_pLock); + + // if we are already in mid-flush, this is probably a mistake + // though not harmful - try to pick it up for now so I can think about it + ASSERT(!m_bFlushing); + + // first thing to do is ensure that no further Receive calls succeed + m_bFlushing = TRUE; + + // now discard any data and call downstream - must do that + // in derived classes + return S_OK; +} + +// default handling for EndFlush - call at end of your implementation +// - before calling this, ensure that there is no queued data and no thread +// pushing any more without a further receive, then call downstream, +// then call this method to clear the m_bFlushing flag and re-enable +// receives +STDMETHODIMP +CBaseInputPin::EndFlush(void) +{ + // Endlush is NOT synchronized with streaming but is part of + // a control action - hence we synchronize with the filter + CAutoLock lck(m_pLock); + + // almost certainly a mistake if we are not in mid-flush + ASSERT(m_bFlushing); + + // before calling, sync with pushing thread and ensure + // no more data is going downstream, then call EndFlush on + // downstream pins. + + // now re-enable Receives + m_bFlushing = FALSE; + + // No more errors + m_bRunTimeError = FALSE; + + return S_OK; +} + + +STDMETHODIMP +CBaseInputPin::Notify(IBaseFilter * pSender, Quality q) +{ + UNREFERENCED_PARAMETER(q); + CheckPointer(pSender,E_POINTER); + ValidateReadPtr(pSender,sizeof(IBaseFilter)); + DbgBreak("IQuality::Notify called on an input pin"); + return NOERROR; +} // Notify + +/* Free up or unprepare allocator's memory, this is called through + IMediaFilter which is responsible for locking the object first */ + +HRESULT +CBaseInputPin::Inactive(void) +{ + m_bRunTimeError = FALSE; + if (m_pAllocator == NULL) { + return VFW_E_NO_ALLOCATOR; + } + + m_bFlushing = FALSE; + + return m_pAllocator->Decommit(); +} + +// what requirements do we have of the allocator - override if you want +// to support other people's allocators but need a specific alignment +// or prefix. +STDMETHODIMP +CBaseInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES*pProps) +{ + UNREFERENCED_PARAMETER(pProps); + return E_NOTIMPL; +} + +// Check if it's OK to process data +// +HRESULT +CBaseInputPin::CheckStreaming() +{ + // Shouldn't be able to get any data if we're not connected! + ASSERT(IsConnected()); + + // Don't process stuff in Stopped state + if (IsStopped()) { + return VFW_E_WRONG_STATE; + } + if (m_bFlushing) { + return S_FALSE; + } + if (m_bRunTimeError) { + return VFW_E_RUNTIME_ERROR; + } + return S_OK; +} + +// Pass on the Quality notification q to +// a. Our QualityControl sink (if we have one) or else +// b. to our upstream filter +// and if that doesn't work, throw it away with a bad return code +HRESULT +CBaseInputPin::PassNotify(Quality& q) +{ + // We pass the message on, which means that we find the quality sink + // for our input pin and send it there + + DbgLog((LOG_TRACE,3,TEXT("Passing Quality notification through transform"))); + if (m_pQSink!=NULL) { + return m_pQSink->Notify(m_pFilter, q); + } else { + // no sink set, so pass it upstream + HRESULT hr; + IQualityControl * pIQC; + + hr = VFW_E_NOT_FOUND; // default + if (m_Connected) { + m_Connected->QueryInterface(IID_IQualityControl, (void**)&pIQC); + + if (pIQC!=NULL) { + hr = pIQC->Notify(m_pFilter, q); + pIQC->Release(); + } + } + return hr; + } + +} // PassNotify + +//===================================================================== +//===================================================================== +// Memory allocation class, implements CMediaSample +//===================================================================== +//===================================================================== + + +/* NOTE The implementation of this class calls the CUnknown constructor with + a NULL outer unknown pointer. This has the effect of making us a self + contained class, ie any QueryInterface, AddRef or Release calls will be + routed to the class's NonDelegatingUnknown methods. You will typically + find that the classes that do this then override one or more of these + virtual functions to provide more specialised behaviour. A good example + of this is where a class wants to keep the QueryInterface internal but + still wants it's lifetime controlled by the external object */ + +/* The last two parameters have default values of NULL and zero */ + +CMediaSample::CMediaSample(TCHAR *pName, + CBaseAllocator *pAllocator, + HRESULT *phr, + LPBYTE pBuffer, + LONG length) : + m_pBuffer(pBuffer), // Initialise the buffer + m_cbBuffer(length), // And it's length + m_lActual(length), // By default, actual = length + m_pMediaType(NULL), // No media type change + m_dwFlags(0), // Nothing set + m_cRef(0), // 0 ref count + m_dwTypeSpecificFlags(0), // Type specific flags + m_dwStreamId(AM_STREAM_MEDIA), // Stream id + m_pAllocator(pAllocator) // Allocator +{ + + /* We must have an owner and it must also be derived from class + CBaseAllocator BUT we do not hold a reference count on it */ + + ASSERT(pAllocator); +} + +#ifdef UNICODE +CMediaSample::CMediaSample(CHAR *pName, + CBaseAllocator *pAllocator, + HRESULT *phr, + LPBYTE pBuffer, + LONG length) : + m_pBuffer(pBuffer), // Initialise the buffer + m_cbBuffer(length), // And it's length + m_lActual(length), // By default, actual = length + m_pMediaType(NULL), // No media type change + m_dwFlags(0), // Nothing set + m_cRef(0), // 0 ref count + m_dwTypeSpecificFlags(0), // Type specific flags + m_dwStreamId(AM_STREAM_MEDIA), // Stream id + m_pAllocator(pAllocator) // Allocator +{ + + /* We must have an owner and it must also be derived from class + CBaseAllocator BUT we do not hold a reference count on it */ + + ASSERT(pAllocator); +} +#endif + +/* Destructor deletes the media type memory */ + +CMediaSample::~CMediaSample() +{ + + if (m_pMediaType) { + DeleteMediaType(m_pMediaType); + } +} + +/* Override this to publicise our interfaces */ + +STDMETHODIMP +CMediaSample::QueryInterface(REFIID riid, void **ppv) +{ + if (riid == IID_IMediaSample || + riid == IID_IMediaSample2 || + riid == IID_IUnknown) { + return GetInterface((IMediaSample *) this, ppv); + } else { + return E_NOINTERFACE; + } +} + +STDMETHODIMP_(ULONG) +CMediaSample::AddRef() +{ + return InterlockedIncrement(&m_cRef); +} + + +// -- CMediaSample lifetimes -- +// +// On final release of this sample buffer it is not deleted but +// returned to the freelist of the owning memory allocator +// +// The allocator may be waiting for the last buffer to be placed on the free +// list in order to decommit all the memory, so the ReleaseBuffer() call may +// result in this sample being deleted. We also need to hold a refcount on +// the allocator to stop that going away until we have finished with this. +// However, we cannot release the allocator before the ReleaseBuffer, as the +// release may cause us to be deleted. Similarly we can't do it afterwards. +// +// Thus we must leave it to the allocator to hold an addref on our behalf. +// When he issues us in GetBuffer, he addref's himself. When ReleaseBuffer +// is called, he releases himself, possibly causing us and him to be deleted. + + +STDMETHODIMP_(ULONG) +CMediaSample::Release() +{ + /* Decrement our own private reference count */ + LONG lRef; + if (m_cRef == 1) { + lRef = 0; + m_cRef = 0; + } else { + lRef = InterlockedDecrement(&m_cRef); + } + ASSERT(lRef >= 0); + + DbgLog((LOG_MEMORY,3,TEXT(" Unknown %X ref-- = %d"), + this, m_cRef)); + + /* Did we release our final reference count */ + if (lRef == 0) { + /* Free all resources */ + if (m_dwFlags & Sample_TypeChanged) { + SetMediaType(NULL); + } + ASSERT(m_pMediaType == NULL); + m_dwFlags = 0; + m_dwTypeSpecificFlags = 0; + m_dwStreamId = AM_STREAM_MEDIA; + + /* This may cause us to be deleted */ + // Our refcount is reliably 0 thus no-one will mess with us + m_pAllocator->ReleaseBuffer(this); + } + return (ULONG)lRef; +} + + +// set the buffer pointer and length. Used by allocators that +// want variable sized pointers or pointers into already-read data. +// This is only available through a CMediaSample* not an IMediaSample* +// and so cannot be changed by clients. +HRESULT +CMediaSample::SetPointer(BYTE * ptr, LONG cBytes) +{ + m_pBuffer = ptr; // new buffer area (could be null) + m_cbBuffer = cBytes; // length of buffer + m_lActual = cBytes; // length of data in buffer (assume full) + + return S_OK; +} + + +// get me a read/write pointer to this buffer's memory. I will actually +// want to use sizeUsed bytes. +STDMETHODIMP +CMediaSample::GetPointer(BYTE ** ppBuffer) +{ + ValidateReadWritePtr(ppBuffer,sizeof(BYTE *)); + + // creator must have set pointer either during + // constructor or by SetPointer + ASSERT(m_pBuffer); + + *ppBuffer = m_pBuffer; + return NOERROR; +} + + +// return the size in bytes of this buffer +STDMETHODIMP_(LONG) +CMediaSample::GetSize(void) +{ + return m_cbBuffer; +} + + +// get the stream time at which this sample should start and finish. +STDMETHODIMP +CMediaSample::GetTime( + REFERENCE_TIME * pTimeStart, // put time here + REFERENCE_TIME * pTimeEnd +) +{ + ValidateReadWritePtr(pTimeStart,sizeof(REFERENCE_TIME)); + ValidateReadWritePtr(pTimeEnd,sizeof(REFERENCE_TIME)); + + if (!(m_dwFlags & Sample_StopValid)) { + if (!(m_dwFlags & Sample_TimeValid)) { + return VFW_E_SAMPLE_TIME_NOT_SET; + } else { + *pTimeStart = m_Start; + + // Make sure old stuff works + *pTimeEnd = m_Start + 1; + return VFW_S_NO_STOP_TIME; + } + } + + *pTimeStart = m_Start; + *pTimeEnd = m_End; + return NOERROR; +} + + +// Set the stream time at which this sample should start and finish. +// NULL pointers means the time is reset +STDMETHODIMP +CMediaSample::SetTime( + REFERENCE_TIME * pTimeStart, + REFERENCE_TIME * pTimeEnd +) +{ + if (pTimeStart == NULL) { + ASSERT(pTimeEnd == NULL); + m_dwFlags &= ~(Sample_TimeValid | Sample_StopValid); + } else { + if (pTimeEnd == NULL) { + m_Start = *pTimeStart; + m_dwFlags |= Sample_TimeValid; + m_dwFlags &= ~Sample_StopValid; + } else { + ValidateReadPtr(pTimeStart,sizeof(REFERENCE_TIME)); + ValidateReadPtr(pTimeEnd,sizeof(REFERENCE_TIME)); + ASSERT(*pTimeEnd >= *pTimeStart); + + m_Start = *pTimeStart; + m_End = *pTimeEnd; + m_dwFlags |= Sample_TimeValid | Sample_StopValid; + } + } + return NOERROR; +} + + +// get the media times (eg bytes) for this sample +STDMETHODIMP +CMediaSample::GetMediaTime( + LONGLONG * pTimeStart, + LONGLONG * pTimeEnd +) +{ + ValidateReadWritePtr(pTimeStart,sizeof(LONGLONG)); + ValidateReadWritePtr(pTimeEnd,sizeof(LONGLONG)); + + if (!(m_dwFlags & Sample_MediaTimeValid)) { + return VFW_E_MEDIA_TIME_NOT_SET; + } + + *pTimeStart = m_MediaStart; + *pTimeEnd = (m_MediaStart + m_MediaEnd); + return NOERROR; +} + + +// Set the media times for this sample +STDMETHODIMP +CMediaSample::SetMediaTime( + LONGLONG * pTimeStart, + LONGLONG * pTimeEnd +) +{ + if (pTimeStart == NULL) { + ASSERT(pTimeEnd == NULL); + m_dwFlags &= ~Sample_MediaTimeValid; + } else { + ValidateReadPtr(pTimeStart,sizeof(LONGLONG)); + ValidateReadPtr(pTimeEnd,sizeof(LONGLONG)); + ASSERT(*pTimeEnd >= *pTimeStart); + + m_MediaStart = *pTimeStart; + m_MediaEnd = (LONG)(*pTimeEnd - *pTimeStart); + m_dwFlags |= Sample_MediaTimeValid; + } + return NOERROR; +} + + +STDMETHODIMP +CMediaSample::IsSyncPoint(void) +{ + if (m_dwFlags & Sample_SyncPoint) { + return S_OK; + } else { + return S_FALSE; + } +} + + +STDMETHODIMP +CMediaSample::SetSyncPoint(BOOL bIsSyncPoint) +{ + if (bIsSyncPoint) { + m_dwFlags |= Sample_SyncPoint; + } else { + m_dwFlags &= ~Sample_SyncPoint; + } + return NOERROR; +} + +// returns S_OK if there is a discontinuity in the data (this same is +// not a continuation of the previous stream of data +// - there has been a seek). +STDMETHODIMP +CMediaSample::IsDiscontinuity(void) +{ + if (m_dwFlags & Sample_Discontinuity) { + return S_OK; + } else { + return S_FALSE; + } +} + +// set the discontinuity property - TRUE if this sample is not a +// continuation, but a new sample after a seek. +STDMETHODIMP +CMediaSample::SetDiscontinuity(BOOL bDiscont) +{ + // should be TRUE or FALSE + if (bDiscont) { + m_dwFlags |= Sample_Discontinuity; + } else { + m_dwFlags &= ~Sample_Discontinuity; + } + return S_OK; +} + +STDMETHODIMP +CMediaSample::IsPreroll(void) +{ + if (m_dwFlags & Sample_Preroll) { + return S_OK; + } else { + return S_FALSE; + } +} + + +STDMETHODIMP +CMediaSample::SetPreroll(BOOL bIsPreroll) +{ + if (bIsPreroll) { + m_dwFlags |= Sample_Preroll; + } else { + m_dwFlags &= ~Sample_Preroll; + } + return NOERROR; +} + +STDMETHODIMP_(LONG) +CMediaSample::GetActualDataLength(void) +{ + return m_lActual; +} + + +STDMETHODIMP +CMediaSample::SetActualDataLength(LONG lActual) +{ + if (lActual > m_cbBuffer) { + ASSERT(lActual <= GetSize()); + return VFW_E_BUFFER_OVERFLOW; + } + m_lActual = lActual; + return NOERROR; +} + + +/* These allow for limited format changes in band */ + +STDMETHODIMP +CMediaSample::GetMediaType(AM_MEDIA_TYPE **ppMediaType) +{ + ValidateReadWritePtr(ppMediaType,sizeof(AM_MEDIA_TYPE *)); + ASSERT(ppMediaType); + + /* Do we have a new media type for them */ + + if (!(m_dwFlags & Sample_TypeChanged)) { + ASSERT(m_pMediaType == NULL); + *ppMediaType = NULL; + return S_FALSE; + } + + ASSERT(m_pMediaType); + + /* Create a copy of our media type */ + + *ppMediaType = CreateMediaType(m_pMediaType); + if (*ppMediaType == NULL) { + return E_OUTOFMEMORY; + } + return NOERROR; +} + + +/* Mark this sample as having a different format type */ + +STDMETHODIMP +CMediaSample::SetMediaType(AM_MEDIA_TYPE *pMediaType) +{ + /* Delete the current media type */ + + if (m_pMediaType) { + DeleteMediaType(m_pMediaType); + m_pMediaType = NULL; + } + + /* Mechanism for resetting the format type */ + + if (pMediaType == NULL) { + m_dwFlags &= ~Sample_TypeChanged; + return NOERROR; + } + + ASSERT(pMediaType); + ValidateReadPtr(pMediaType,sizeof(AM_MEDIA_TYPE)); + + /* Take a copy of the media type */ + + m_pMediaType = CreateMediaType(pMediaType); + if (m_pMediaType == NULL) { + m_dwFlags &= ~Sample_TypeChanged; + return E_OUTOFMEMORY; + } + + m_dwFlags |= Sample_TypeChanged; + return NOERROR; +} + +// Set and get properties (IMediaSample2) +STDMETHODIMP CMediaSample::GetProperties( + DWORD cbProperties, + BYTE * pbProperties +) +{ + if (0 != cbProperties) { + CheckPointer(pbProperties, E_POINTER); + // Return generic stuff up to the length + AM_SAMPLE2_PROPERTIES Props; + Props.cbData = (DWORD) (min(cbProperties, sizeof(Props))); + Props.dwSampleFlags = m_dwFlags & ~Sample_MediaTimeValid; + Props.dwTypeSpecificFlags = m_dwTypeSpecificFlags; + Props.pbBuffer = m_pBuffer; + Props.cbBuffer = m_cbBuffer; + Props.lActual = m_lActual; + Props.tStart = m_Start; + Props.tStop = m_End; + Props.dwStreamId = m_dwStreamId; + if (m_dwFlags & AM_SAMPLE_TYPECHANGED) { + Props.pMediaType = m_pMediaType; + } else { + Props.pMediaType = NULL; + } + CopyMemory(pbProperties, &Props, Props.cbData); + } + return S_OK; +} + +#define CONTAINS_FIELD(type, field, offset) \ + ((FIELD_OFFSET(type, field) + sizeof(((type *)0)->field)) <= offset) + +HRESULT CMediaSample::SetProperties( + DWORD cbProperties, + const BYTE * pbProperties +) +{ + + /* Generic properties */ + AM_MEDIA_TYPE *pMediaType = NULL; + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbData, cbProperties)) { + CheckPointer(pbProperties, E_POINTER); + AM_SAMPLE2_PROPERTIES *pProps = + (AM_SAMPLE2_PROPERTIES *)pbProperties; + + /* Don't use more data than is actually there */ + if (pProps->cbData < cbProperties) { + cbProperties = pProps->cbData; + } + /* We only handle IMediaSample2 */ + if (cbProperties > sizeof(*pProps) || + pProps->cbData > sizeof(*pProps)) { + return E_INVALIDARG; + } + /* Do checks first, the assignments (for backout) */ + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) { + /* Check the flags */ + if (pProps->dwSampleFlags & + (~Sample_ValidFlags | Sample_MediaTimeValid)) { + return E_INVALIDARG; + } + /* Check a flag isn't being set for a property + not being provided + */ + if ((pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) && + !(m_dwFlags & AM_SAMPLE_TIMEVALID) && + !CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) { + return E_INVALIDARG; + } + } + /* NB - can't SET the pointer or size */ + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pbBuffer, cbProperties)) { + + /* Check pbBuffer */ + if (pProps->pbBuffer != 0 && pProps->pbBuffer != m_pBuffer) { + return E_INVALIDARG; + } + } + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties)) { + + /* Check cbBuffer */ + if (pProps->cbBuffer != 0 && pProps->cbBuffer != m_cbBuffer) { + return E_INVALIDARG; + } + } + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties) && + CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) { + + /* Check lActual */ + if (pProps->cbBuffer < pProps->lActual) { + return E_INVALIDARG; + } + } + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) { + + /* Check pMediaType */ + if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) { + CheckPointer(pProps->pMediaType, E_POINTER); + pMediaType = CreateMediaType(pProps->pMediaType); + if (pMediaType == NULL) { + return E_OUTOFMEMORY; + } + } + } + + /* Now do the assignments */ + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwStreamId, cbProperties)) { + m_dwStreamId = pProps->dwStreamId; + } + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) { + /* Set the flags */ + m_dwFlags = pProps->dwSampleFlags | + (m_dwFlags & Sample_MediaTimeValid); + m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; + } else { + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwTypeSpecificFlags, cbProperties)) { + m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; + } + } + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) { + /* Set lActual */ + m_lActual = pProps->lActual; + } + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) { + + /* Set the times */ + m_End = pProps->tStop; + } + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStart, cbProperties)) { + + /* Set the times */ + m_Start = pProps->tStart; + } + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) { + /* Set pMediaType */ + if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) { + if (m_pMediaType != NULL) { + DeleteMediaType(m_pMediaType); + } + m_pMediaType = pMediaType; + } + } + + /* Fix up the type changed flag to correctly reflect the current state + If, for instance the input contained no type change but the + output does then if we don't do this we'd lose the + output media type. + */ + if (m_pMediaType) { + m_dwFlags |= Sample_TypeChanged; + } else { + m_dwFlags &= ~Sample_TypeChanged; + } + } + + return S_OK; +} + + +// +// The streaming thread calls IPin::NewSegment(), IPin::EndOfStream(), +// IMemInputPin::Receive() and IMemInputPin::ReceiveMultiple() on the +// connected input pin. The application thread calls Block(). The +// following class members can only be called by the streaming thread. +// +// Deliver() +// DeliverNewSegment() +// StartUsingOutputPin() +// StopUsingOutputPin() +// ChangeOutputFormat() +// ChangeMediaType() +// DynamicReconnect() +// +// The following class members can only be called by the application thread. +// +// Block() +// SynchronousBlockOutputPin() +// AsynchronousBlockOutputPin() +// + +CDynamicOutputPin::CDynamicOutputPin( + TCHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName) : + CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName), + m_hStopEvent(NULL), + m_pGraphConfig(NULL), + m_bPinUsesReadOnlyAllocator(FALSE), + m_BlockState(NOT_BLOCKED), + m_hUnblockOutputPinEvent(NULL), + m_hNotifyCallerPinBlockedEvent(NULL), + m_dwBlockCallerThreadID(0), + m_dwNumOutstandingOutputPinUsers(0) +{ + HRESULT hr = Initialize(); + if( FAILED( hr ) ) { + *phr = hr; + return; + } +} + +#ifdef UNICODE +CDynamicOutputPin::CDynamicOutputPin( + CHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName) : + CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName), + m_hStopEvent(NULL), + m_pGraphConfig(NULL), + m_bPinUsesReadOnlyAllocator(FALSE), + m_BlockState(NOT_BLOCKED), + m_hUnblockOutputPinEvent(NULL), + m_hNotifyCallerPinBlockedEvent(NULL), + m_dwBlockCallerThreadID(0), + m_dwNumOutstandingOutputPinUsers(0) +{ + HRESULT hr = Initialize(); + if( FAILED( hr ) ) { + *phr = hr; + return; + } +} +#endif + +CDynamicOutputPin::~CDynamicOutputPin() +{ + if(NULL != m_hUnblockOutputPinEvent) { + // This call should not fail because we have access to m_hUnblockOutputPinEvent + // and m_hUnblockOutputPinEvent is a valid event. + EXECUTE_ASSERT(::CloseHandle(m_hUnblockOutputPinEvent)); + } + + if(NULL != m_hNotifyCallerPinBlockedEvent) { + // This call should not fail because we have access to m_hNotifyCallerPinBlockedEvent + // and m_hNotifyCallerPinBlockedEvent is a valid event. + EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); + } +} + +HRESULT CDynamicOutputPin::Initialize(void) +{ + m_hUnblockOutputPinEvent = ::CreateEvent( NULL, // The event will have the default security descriptor. + TRUE, // This is a manual reset event. + TRUE, // The event is initially signaled. + NULL ); // The event is not named. + + // CreateEvent() returns NULL if an error occurs. + if(NULL == m_hUnblockOutputPinEvent) { + return AmGetLastErrorToHResult(); + } + + // Set flag to say we can reconnect while streaming. + SetReconnectWhenActive(true); + + return S_OK; +} + +STDMETHODIMP CDynamicOutputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + if(riid == IID_IPinFlowControl) { + return GetInterface(static_cast(this), ppv); + } else { + return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv); + } +} + +STDMETHODIMP CDynamicOutputPin::Disconnect(void) +{ + CAutoLock cObjectLock(m_pLock); + return DisconnectInternal(); +} + +STDMETHODIMP CDynamicOutputPin::Block(DWORD dwBlockFlags, HANDLE hEvent) +{ + const DWORD VALID_FLAGS = AM_PIN_FLOW_CONTROL_BLOCK; + + // Check for illegal flags. + if(dwBlockFlags & ~VALID_FLAGS) { + return E_INVALIDARG; + } + + // Make sure the event is unsignaled. + if((dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) && (NULL != hEvent)) { + if( !::ResetEvent( hEvent ) ) { + return AmGetLastErrorToHResult(); + } + } + + // No flags are set if we are unblocking the output pin. + if(0 == dwBlockFlags) { + + // This parameter should be NULL because unblock operations are always synchronous. + // There is no need to notify the caller when the event is done. + if(NULL != hEvent) { + return E_INVALIDARG; + } + } + + #ifdef DEBUG + AssertValid(); + #endif // DEBUG + + HRESULT hr; + + if(dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) { + // IPinFlowControl::Block()'s hEvent parameter is NULL if the block is synchronous. + // If hEvent is not NULL, the block is asynchronous. + if(NULL == hEvent) { + hr = SynchronousBlockOutputPin(); + } else { + hr = AsynchronousBlockOutputPin(hEvent); + } + } else { + hr = UnblockOutputPin(); + } + + #ifdef DEBUG + AssertValid(); + #endif // DEBUG + + if(FAILED(hr)) { + return hr; + } + + return S_OK; +} + +HRESULT CDynamicOutputPin::SynchronousBlockOutputPin(void) +{ + HANDLE hNotifyCallerPinBlockedEvent = :: CreateEvent( NULL, // The event will have the default security attributes. + FALSE, // This is an automatic reset event. + FALSE, // The event is initially unsignaled. + NULL ); // The event is not named. + + // CreateEvent() returns NULL if an error occurs. + if(NULL == hNotifyCallerPinBlockedEvent) { + return AmGetLastErrorToHResult(); + } + + HRESULT hr = AsynchronousBlockOutputPin(hNotifyCallerPinBlockedEvent); + if(FAILED(hr)) { + // This call should not fail because we have access to hNotifyCallerPinBlockedEvent + // and hNotifyCallerPinBlockedEvent is a valid event. + EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent)); + + return hr; + } + + hr = WaitEvent(hNotifyCallerPinBlockedEvent); + + // This call should not fail because we have access to hNotifyCallerPinBlockedEvent + // and hNotifyCallerPinBlockedEvent is a valid event. + EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent)); + + if(FAILED(hr)) { + return hr; + } + + return S_OK; +} + +HRESULT CDynamicOutputPin::AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent) +{ + // This function holds the m_BlockStateLock because it uses + // m_dwBlockCallerThreadID, m_BlockState and + // m_hNotifyCallerPinBlockedEvent. + CAutoLock alBlockStateLock(&m_BlockStateLock); + + if(NOT_BLOCKED != m_BlockState) { + if(m_dwBlockCallerThreadID == ::GetCurrentThreadId()) { + return VFW_E_PIN_ALREADY_BLOCKED_ON_THIS_THREAD; + } else { + return VFW_E_PIN_ALREADY_BLOCKED; + } + } + + BOOL fSuccess = ::DuplicateHandle( ::GetCurrentProcess(), + hNotifyCallerPinBlockedEvent, + ::GetCurrentProcess(), + &m_hNotifyCallerPinBlockedEvent, + EVENT_MODIFY_STATE, + FALSE, + 0 ); + if( !fSuccess ) { + return AmGetLastErrorToHResult(); + } + + m_BlockState = PENDING; + m_dwBlockCallerThreadID = ::GetCurrentThreadId(); + + // The output pin cannot be blocked if the streaming thread is + // calling IPin::NewSegment(), IPin::EndOfStream(), IMemInputPin::Receive() + // or IMemInputPin::ReceiveMultiple() on the connected input pin. Also, it + // cannot be blocked if the streaming thread is calling DynamicReconnect(), + // ChangeMediaType() or ChangeOutputFormat(). + if(!StreamingThreadUsingOutputPin()) { + + // The output pin can be immediately blocked. + BlockOutputPin(); + } + + return S_OK; +} + +void CDynamicOutputPin::BlockOutputPin(void) +{ + // The caller should always hold the m_BlockStateLock because this function + // uses m_BlockState and m_hNotifyCallerPinBlockedEvent. + ASSERT(CritCheckIn(&m_BlockStateLock)); + + // This function should not be called if the streaming thread is modifying + // the connection state or it's passing data downstream. + ASSERT(!StreamingThreadUsingOutputPin()); + + // This should not fail because we successfully created the event + // and we have the security permissions to change it's state. + EXECUTE_ASSERT(::ResetEvent(m_hUnblockOutputPinEvent)); + + // This event should not fail because AsynchronousBlockOutputPin() successfully + // duplicated this handle and we have the appropriate security permissions. + EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent)); + EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); + + m_BlockState = BLOCKED; + m_hNotifyCallerPinBlockedEvent = NULL; +} + +HRESULT CDynamicOutputPin::UnblockOutputPin(void) +{ + // UnblockOutputPin() holds the m_BlockStateLock because it + // uses m_BlockState, m_dwBlockCallerThreadID and + // m_hNotifyCallerPinBlockedEvent. + CAutoLock alBlockStateLock(&m_BlockStateLock); + + if(NOT_BLOCKED == m_BlockState) { + return S_FALSE; + } + + // This should not fail because we successfully created the event + // and we have the security permissions to change it's state. + EXECUTE_ASSERT(::SetEvent(m_hUnblockOutputPinEvent)); + + // Cancel the block operation if it's still pending. + if(NULL != m_hNotifyCallerPinBlockedEvent) { + // This event should not fail because AsynchronousBlockOutputPin() successfully + // duplicated this handle and we have the appropriate security permissions. + EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent)); + EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); + } + + m_BlockState = NOT_BLOCKED; + m_dwBlockCallerThreadID = 0; + m_hNotifyCallerPinBlockedEvent = NULL; + + return S_OK; +} + +HRESULT CDynamicOutputPin::StartUsingOutputPin(void) +{ + // The caller should not hold m_BlockStateLock. If the caller does, + // a deadlock could occur. + ASSERT(CritCheckOut(&m_BlockStateLock)); + + CAutoLock alBlockStateLock(&m_BlockStateLock); + + #ifdef DEBUG + AssertValid(); + #endif // DEBUG + + // Are we in the middle of a block operation? + while(BLOCKED == m_BlockState) { + m_BlockStateLock.Unlock(); + + // If this ASSERT fires, a deadlock could occur. The caller should make sure + // that this thread never acquires the Block State lock more than once. + ASSERT(CritCheckOut( &m_BlockStateLock )); + + // WaitForMultipleObjects() returns WAIT_OBJECT_0 if the unblock event + // is fired. It returns WAIT_OBJECT_0 + 1 if the stop event if fired. + // See the Windows SDK documentation for more information on + // WaitForMultipleObjects(). + const DWORD UNBLOCK = WAIT_OBJECT_0; + const DWORD STOP = WAIT_OBJECT_0 + 1; + + HANDLE ahWaitEvents[] = { m_hUnblockOutputPinEvent, m_hStopEvent }; + DWORD dwNumWaitEvents = sizeof(ahWaitEvents)/sizeof(HANDLE); + + DWORD dwReturnValue = ::WaitForMultipleObjects( dwNumWaitEvents, ahWaitEvents, FALSE, INFINITE ); + + m_BlockStateLock.Lock(); + + #ifdef DEBUG + AssertValid(); + #endif // DEBUG + + switch( dwReturnValue ) { + case UNBLOCK: + break; + + case STOP: + return VFW_E_STATE_CHANGED; + + case WAIT_FAILED: + return AmGetLastErrorToHResult(); + + default: + DbgBreak( "An Unexpected case occured in CDynamicOutputPin::StartUsingOutputPin()." ); + return E_UNEXPECTED; + } + } + + m_dwNumOutstandingOutputPinUsers++; + + #ifdef DEBUG + AssertValid(); + #endif // DEBUG + + return S_OK; +} + +void CDynamicOutputPin::StopUsingOutputPin(void) +{ + CAutoLock alBlockStateLock(&m_BlockStateLock); + + #ifdef DEBUG + AssertValid(); + #endif // DEBUG + + m_dwNumOutstandingOutputPinUsers--; + + if((m_dwNumOutstandingOutputPinUsers == 0) && (NOT_BLOCKED != m_BlockState)) { + BlockOutputPin(); + } + + #ifdef DEBUG + AssertValid(); + #endif // DEBUG +} + +bool CDynamicOutputPin::StreamingThreadUsingOutputPin(void) +{ + CAutoLock alBlockStateLock(&m_BlockStateLock); + + return (m_dwNumOutstandingOutputPinUsers > 0); +} + +void CDynamicOutputPin::SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent) +{ + // This pointer is not addrefed because filters are not allowed to + // hold references to the filter graph manager. See the documentation for + // IBaseFilter::JoinFilterGraph() in the Direct Show SDK for more information. + m_pGraphConfig = pGraphConfig; + + m_hStopEvent = hStopEvent; +} + +HRESULT CDynamicOutputPin::Active(void) +{ + // Make sure the user initialized the object by calling SetConfigInfo(). + if((NULL == m_hStopEvent) || (NULL == m_pGraphConfig)) { + DbgBreak( ERROR: CDynamicOutputPin::Active() failed because m_pGraphConfig and m_hStopEvent were not initialized. Call SetConfigInfo() to initialize them. ); + return E_FAIL; + } + + // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). + // The ASSERT can also fire if the event if destroyed and then Active() is called. An event + // handle is invalid if 1) the event does not exist or the user does not have the security + // permissions to use the event. + EXECUTE_ASSERT(ResetEvent(m_hStopEvent)); + + return CBaseOutputPin::Active(); +} + +HRESULT CDynamicOutputPin::Inactive(void) +{ + // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). + // The ASSERT can also fire if the event if destroyed and then Active() is called. An event + // handle is invalid if 1) the event does not exist or the user does not have the security + // permissions to use the event. + EXECUTE_ASSERT(SetEvent(m_hStopEvent)); + + return CBaseOutputPin::Inactive(); +} + +HRESULT CDynamicOutputPin::DeliverBeginFlush(void) +{ + // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). + // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called. + // An event handle is invalid if 1) the event does not exist or the user does not have the security + // permissions to use the event. + EXECUTE_ASSERT(SetEvent(m_hStopEvent)); + + return CBaseOutputPin::DeliverBeginFlush(); +} + +HRESULT CDynamicOutputPin::DeliverEndFlush(void) +{ + // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). + // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called. + // An event handle is invalid if 1) the event does not exist or the user does not have the security + // permissions to use the event. + EXECUTE_ASSERT(ResetEvent(m_hStopEvent)); + + return CBaseOutputPin::DeliverEndFlush(); +} + + +// ChangeOutputFormat() either dynamicly changes the connection's format type or it dynamicly +// reconnects the output pin. +HRESULT CDynamicOutputPin::ChangeOutputFormat + ( + const AM_MEDIA_TYPE *pmt, + REFERENCE_TIME tSegmentStart, + REFERENCE_TIME tSegmentStop, + double dSegmentRate + ) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + // Callers should always pass a valid media type to ChangeOutputFormat() . + ASSERT(NULL != pmt); + + CMediaType cmt(*pmt); + HRESULT hr = ChangeMediaType(&cmt); + if (FAILED(hr)) { + return hr; + } + + hr = DeliverNewSegment(tSegmentStart, tSegmentStop, dSegmentRate); + if( FAILED( hr ) ) { + return hr; + } + + return S_OK; +} + +HRESULT CDynamicOutputPin::ChangeMediaType(const CMediaType *pmt) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + // This function assumes the filter graph is running. + ASSERT(!IsStopped()); + + if(!IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + + /* First check if the downstream pin will accept a dynamic + format change + */ + QzCComPtr pConnection; + + m_Connected->QueryInterface(IID_IPinConnection, (void **)&pConnection); + if(pConnection != NULL) { + + if(S_OK == pConnection->DynamicQueryAccept(pmt)) { + + HRESULT hr = ChangeMediaTypeHelper(pmt); + if(FAILED(hr)) { + return hr; + } + + return S_OK; + } + } + + /* Can't do the dynamic connection */ + return DynamicReconnect(pmt); +} + +HRESULT CDynamicOutputPin::ChangeMediaTypeHelper(const CMediaType *pmt) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + HRESULT hr = m_Connected->ReceiveConnection(this, pmt); + if(FAILED(hr)) { + return hr; + } + + hr = SetMediaType(pmt); + if(FAILED(hr)) { + return hr; + } + + // Does this pin use the local memory transport? + if(NULL != m_pInputPin) { + // This function assumes that m_pInputPin and m_Connected are + // two different interfaces to the same object. + ASSERT(::IsEqualObject(m_Connected, m_pInputPin)); + + ALLOCATOR_PROPERTIES apInputPinRequirements; + apInputPinRequirements.cbAlign = 0; + apInputPinRequirements.cbBuffer = 0; + apInputPinRequirements.cbPrefix = 0; + apInputPinRequirements.cBuffers = 0; + + m_pInputPin->GetAllocatorRequirements(&apInputPinRequirements); + + // A zero allignment does not make any sense. + if(0 == apInputPinRequirements.cbAlign) { + apInputPinRequirements.cbAlign = 1; + } + + hr = m_pAllocator->Decommit(); + if(FAILED(hr)) { + return hr; + } + + hr = DecideBufferSize(m_pAllocator, &apInputPinRequirements); + if(FAILED(hr)) { + return hr; + } + + hr = m_pAllocator->Commit(); + if(FAILED(hr)) { + return hr; + } + + hr = m_pInputPin->NotifyAllocator(m_pAllocator, m_bPinUsesReadOnlyAllocator); + if(FAILED(hr)) { + return hr; + } + } + + return S_OK; +} + +// this method has to be called from the thread that is pushing data, +// and it's the caller's responsibility to make sure that the thread +// has no outstand samples because they cannot be delivered after a +// reconnect +// +HRESULT CDynamicOutputPin::DynamicReconnect( const CMediaType* pmt ) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + if((m_pGraphConfig == NULL) || (NULL == m_hStopEvent)) { + return E_FAIL; + } + + HRESULT hr = m_pGraphConfig->Reconnect( + this, + NULL, + pmt, + NULL, + m_hStopEvent, + AM_GRAPH_CONFIG_RECONNECT_CACHE_REMOVED_FILTERS ); + + return hr; +} + +HRESULT CDynamicOutputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin); + if(SUCCEEDED(hr)) { + if(!IsStopped() && m_pAllocator) { + hr = m_pAllocator->Commit(); + ASSERT(hr != VFW_E_ALREADY_COMMITTED); + } + } + + return hr; +} + +#ifdef DEBUG +void CDynamicOutputPin::AssertValid(void) +{ + // Make sure the object was correctly initialized. + + // This ASSERT only fires if the object failed to initialize + // and the user ignored the constructor's return code (phr). + ASSERT(NULL != m_hUnblockOutputPinEvent); + + // If either of these ASSERTs fire, the user did not correctly call + // SetConfigInfo(). + ASSERT(NULL != m_hStopEvent); + ASSERT(NULL != m_pGraphConfig); + + // Make sure the block state is consistent. + + CAutoLock alBlockStateLock(&m_BlockStateLock); + + // BLOCK_STATE variables only have three legal values: PENDING, BLOCKED and NOT_BLOCKED. + ASSERT((NOT_BLOCKED == m_BlockState) || (PENDING == m_BlockState) || (BLOCKED == m_BlockState)); + + // m_hNotifyCallerPinBlockedEvent is only needed when a block operation cannot complete + // immediately. + ASSERT(((NULL == m_hNotifyCallerPinBlockedEvent) && (PENDING != m_BlockState)) || + ((NULL != m_hNotifyCallerPinBlockedEvent) && (PENDING == m_BlockState)) ); + + // m_dwBlockCallerThreadID should always be 0 if the pin is not blocked and + // the user is not trying to block the pin. + ASSERT((0 == m_dwBlockCallerThreadID) || (NOT_BLOCKED != m_BlockState)); + + // If this ASSERT fires, the streaming thread is using the output pin and the + // output pin is blocked. + ASSERT(((0 != m_dwNumOutstandingOutputPinUsers) && (BLOCKED != m_BlockState)) || + ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED != m_BlockState)) || + ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED == m_BlockState)) ); +} +#endif // DEBUG + +HRESULT CDynamicOutputPin::WaitEvent(HANDLE hEvent) +{ + const DWORD EVENT_SIGNALED = WAIT_OBJECT_0; + + DWORD dwReturnValue = ::WaitForSingleObject(hEvent, INFINITE); + + switch( dwReturnValue ) { + case EVENT_SIGNALED: + return S_OK; + + case WAIT_FAILED: + return AmGetLastErrorToHResult(); + + default: + DbgBreak( "An Unexpected case occured in CDynamicOutputPin::WaitEvent()." ); + return E_UNEXPECTED; + } +} + +//===================================================================== +//===================================================================== +// Implements CBaseAllocator +//===================================================================== +//===================================================================== + + +/* Constructor overrides the default settings for the free list to request + that it be alertable (ie the list can be cast to a handle which can be + passed to WaitForSingleObject). Both of the allocator lists also ask for + object locking, the all list matches the object default settings but I + have included them here just so it is obvious what kind of list it is */ + +CBaseAllocator::CBaseAllocator(TCHAR *pName, + LPUNKNOWN pUnk, + HRESULT *phr, + BOOL bEvent, + BOOL fEnableReleaseCallback + ) : + CUnknown(pName, pUnk), + m_lAllocated(0), + m_bChanged(FALSE), + m_bCommitted(FALSE), + m_bDecommitInProgress(FALSE), + m_lSize(0), + m_lCount(0), + m_lAlignment(0), + m_lPrefix(0), + m_hSem(NULL), + m_lWaiting(0), + m_fEnableReleaseCallback(fEnableReleaseCallback), + m_pNotify(NULL) +{ + + if (bEvent) { + m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); + if (m_hSem == NULL) { + *phr = E_OUTOFMEMORY; + return; + } + } +} + +#ifdef UNICODE +CBaseAllocator::CBaseAllocator(CHAR *pName, + LPUNKNOWN pUnk, + HRESULT *phr, + BOOL bEvent, + BOOL fEnableReleaseCallback) : + CUnknown(pName, pUnk), + m_lAllocated(0), + m_bChanged(FALSE), + m_bCommitted(FALSE), + m_bDecommitInProgress(FALSE), + m_lSize(0), + m_lCount(0), + m_lAlignment(0), + m_lPrefix(0), + m_hSem(NULL), + m_lWaiting(0), + m_fEnableReleaseCallback(fEnableReleaseCallback), + m_pNotify(NULL) +{ + + if (bEvent) { + m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); + if (m_hSem == NULL) { + *phr = E_OUTOFMEMORY; + return; + } + } +} +#endif + +/* Destructor */ + +CBaseAllocator::~CBaseAllocator() +{ + // we can't call Decommit here since that would mean a call to a + // pure virtual in destructor. + // We must assume that the derived class has gone into decommit state in + // its destructor. + + ASSERT(!m_bCommitted); + if (m_hSem != NULL) { + EXECUTE_ASSERT(CloseHandle(m_hSem)); + } + if (m_pNotify) { + m_pNotify->Release(); + } +} + + +/* Override this to publicise our interfaces */ + +STDMETHODIMP +CBaseAllocator::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + /* Do we know about this interface */ + + if (riid == IID_IMemAllocator || + riid == IID_IMemAllocatorCallbackTemp && m_fEnableReleaseCallback) { + return GetInterface((IMemAllocatorCallbackTemp *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +/* This sets the size and count of the required samples. The memory isn't + actually allocated until Commit() is called, if memory has already been + allocated then assuming no samples are outstanding the user may call us + to change the buffering, the memory will be released in Commit() */ + +STDMETHODIMP +CBaseAllocator::SetProperties( + ALLOCATOR_PROPERTIES* pRequest, + ALLOCATOR_PROPERTIES* pActual) +{ + CheckPointer(pRequest, E_POINTER); + CheckPointer(pActual, E_POINTER); + ValidateReadWritePtr(pActual, sizeof(ALLOCATOR_PROPERTIES)); + CAutoLock cObjectLock(this); + + ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES)); + + ASSERT(pRequest->cbBuffer > 0); + + /* Check the alignment requested */ + if (pRequest->cbAlign != 1) { + DbgLog((LOG_ERROR, 2, TEXT("Alignment requested was 0x%x, not 1"), + pRequest->cbAlign)); + return VFW_E_BADALIGN; + } + + /* Can't do this if already committed, there is an argument that says we + should not reject the SetProperties call if there are buffers still + active. However this is called by the source filter, which is the same + person who is holding the samples. Therefore it is not unreasonable + for them to free all their samples before changing the requirements */ + + if (m_bCommitted) { + return VFW_E_ALREADY_COMMITTED; + } + + /* Must be no outstanding buffers */ + + if (m_lAllocated != m_lFree.GetCount()) { + return VFW_E_BUFFERS_OUTSTANDING; + } + + /* There isn't any real need to check the parameters as they + will just be rejected when the user finally calls Commit */ + + pActual->cbBuffer = m_lSize = pRequest->cbBuffer; + pActual->cBuffers = m_lCount = pRequest->cBuffers; + pActual->cbAlign = m_lAlignment = pRequest->cbAlign; + pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix; + + m_bChanged = TRUE; + return NOERROR; +} + +STDMETHODIMP +CBaseAllocator::GetProperties( + ALLOCATOR_PROPERTIES * pActual) +{ + CheckPointer(pActual,E_POINTER); + ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES)); + + CAutoLock cObjectLock(this); + pActual->cbBuffer = m_lSize; + pActual->cBuffers = m_lCount; + pActual->cbAlign = m_lAlignment; + pActual->cbPrefix = m_lPrefix; + return NOERROR; +} + +// get container for a sample. Blocking, synchronous call to get the +// next free buffer (as represented by an IMediaSample interface). +// on return, the time etc properties will be invalid, but the buffer +// pointer and size will be correct. + +HRESULT CBaseAllocator::GetBuffer(IMediaSample **ppBuffer, + REFERENCE_TIME *pStartTime, + REFERENCE_TIME *pEndTime, + DWORD dwFlags + ) +{ + UNREFERENCED_PARAMETER(pStartTime); + UNREFERENCED_PARAMETER(pEndTime); + UNREFERENCED_PARAMETER(dwFlags); + CMediaSample *pSample; + + *ppBuffer = NULL; + for (;;) + { + { // scope for lock + CAutoLock cObjectLock(this); + + /* Check we are committed */ + if (!m_bCommitted) { + return VFW_E_NOT_COMMITTED; + } + pSample = (CMediaSample *) m_lFree.RemoveHead(); + if (pSample == NULL) { + SetWaiting(); + } + } + + /* If we didn't get a sample then wait for the list to signal */ + + if (pSample) { + break; + } + if (dwFlags & AM_GBF_NOWAIT) { + return VFW_E_TIMEOUT; + } + ASSERT(m_hSem != NULL); + WaitForSingleObject(m_hSem, INFINITE); + } + + /* Addref the buffer up to one. On release + back to zero instead of being deleted, it will requeue itself by + calling the ReleaseBuffer member function. NOTE the owner of a + media sample must always be derived from CBaseAllocator */ + + + ASSERT(pSample->m_cRef == 0); + pSample->m_cRef = 1; + *ppBuffer = pSample; + + + return NOERROR; +} + + +/* Final release of a CMediaSample will call this */ + +STDMETHODIMP +CBaseAllocator::ReleaseBuffer(IMediaSample * pSample) +{ + CheckPointer(pSample,E_POINTER); + ValidateReadPtr(pSample,sizeof(IMediaSample)); + + + + BOOL bRelease = FALSE; + { + CAutoLock cal(this); + + /* Put back on the free list */ + + m_lFree.Add((CMediaSample *)pSample); + if (m_lWaiting != 0) { + NotifySample(); + } + + // if there is a pending Decommit, then we need to complete it by + // calling Free() when the last buffer is placed on the free list + + LONG l1 = m_lFree.GetCount(); + if (m_bDecommitInProgress && (l1 == m_lAllocated)) { + Free(); + m_bDecommitInProgress = FALSE; + bRelease = TRUE; + } + } + + if (m_pNotify) { + + ASSERT(m_fEnableReleaseCallback); + + // + // Note that this is not synchronized with setting up a notification + // method. + // + m_pNotify->NotifyRelease(); + } + + /* For each buffer there is one AddRef, made in GetBuffer and released + here. This may cause the allocator and all samples to be deleted */ + + if (bRelease) { + Release(); + } + return NOERROR; +} + +STDMETHODIMP +CBaseAllocator::SetNotify( + IMemAllocatorNotifyCallbackTemp* pNotify + ) +{ + ASSERT(m_fEnableReleaseCallback); + CAutoLock lck(this); + if (pNotify) { + pNotify->AddRef(); + } + if (m_pNotify) { + m_pNotify->Release(); + } + m_pNotify = pNotify; + return S_OK; +} + +STDMETHODIMP +CBaseAllocator::GetFreeCount( + LONG* plBuffersFree + ) +{ + ASSERT(m_fEnableReleaseCallback); + CAutoLock cObjectLock(this); + *plBuffersFree = m_lCount - m_lAllocated + m_lFree.GetCount(); + return NOERROR; +} + +void +CBaseAllocator::NotifySample() +{ + if (m_lWaiting != 0) { + ASSERT(m_hSem != NULL); + ReleaseSemaphore(m_hSem, m_lWaiting, 0); + m_lWaiting = 0; + } +} + +STDMETHODIMP +CBaseAllocator::Commit() +{ + /* Check we are not decommitted */ + CAutoLock cObjectLock(this); + + // cannot need to alloc or re-alloc if we are committed + if (m_bCommitted) { + return NOERROR; + } + + /* Allow GetBuffer calls */ + + m_bCommitted = TRUE; + + // is there a pending decommit ? if so, just cancel it + if (m_bDecommitInProgress) { + m_bDecommitInProgress = FALSE; + + // don't call Alloc at this point. He cannot allow SetProperties + // between Decommit and the last free, so the buffer size cannot have + // changed. And because some of the buffers are not free yet, he + // cannot re-alloc anyway. + return NOERROR; + } + + DbgLog((LOG_MEMORY, 1, TEXT("Allocating: %ldx%ld"), m_lCount, m_lSize)); + + // actually need to allocate the samples + HRESULT hr = Alloc(); + if (FAILED(hr)) { + m_bCommitted = FALSE; + return hr; + } + AddRef(); + return NOERROR; +} + + +STDMETHODIMP +CBaseAllocator::Decommit() +{ + BOOL bRelease = FALSE; + { + /* Check we are not already decommitted */ + CAutoLock cObjectLock(this); + if (m_bCommitted == FALSE) { + if (m_bDecommitInProgress == FALSE) { + return NOERROR; + } + } + + /* No more GetBuffer calls will succeed */ + m_bCommitted = FALSE; + + // are any buffers outstanding? + if (m_lFree.GetCount() < m_lAllocated) { + // please complete the decommit when last buffer is freed + m_bDecommitInProgress = TRUE; + } else { + m_bDecommitInProgress = FALSE; + + // need to complete the decommit here as there are no + // outstanding buffers + + Free(); + bRelease = TRUE; + } + + // Tell anyone waiting that they can go now so we can + // reject their call + NotifySample(); + } + + if (bRelease) { + Release(); + } + return NOERROR; +} + + +/* Base definition of allocation which checks we are ok to go ahead and do + the full allocation. We return S_FALSE if the requirements are the same */ + +HRESULT +CBaseAllocator::Alloc(void) +{ + /* Error if he hasn't set the size yet */ + if (m_lCount <= 0 || m_lSize <= 0 || m_lAlignment <= 0) { + return VFW_E_SIZENOTSET; + } + + /* should never get here while buffers outstanding */ + ASSERT(m_lFree.GetCount() == m_lAllocated); + + /* If the requirements haven't changed then don't reallocate */ + if (m_bChanged == FALSE) { + return S_FALSE; + } + + return NOERROR; +} + +/* Implement CBaseAllocator::CSampleList::Remove(pSample) + Removes pSample from the list +*/ +void +CBaseAllocator::CSampleList::Remove(CMediaSample * pSample) +{ + CMediaSample **pSearch; + for (pSearch = &m_List; + *pSearch != NULL; + pSearch = &(CBaseAllocator::NextSample(*pSearch))) { + if (*pSearch == pSample) { + *pSearch = CBaseAllocator::NextSample(pSample); + CBaseAllocator::NextSample(pSample) = NULL; + m_nOnList--; + return; + } + } + DbgBreak("Couldn't find sample in list"); +} + +//===================================================================== +//===================================================================== +// Implements CMemAllocator +//===================================================================== +//===================================================================== + + +/* This goes in the factory template table to create new instances */ +CUnknown *CMemAllocator::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) +{ + CUnknown *pUnkRet = new CMemAllocator(NAME("CMemAllocator"), pUnk, phr); + return pUnkRet; +} + +CMemAllocator::CMemAllocator( + TCHAR *pName, + LPUNKNOWN pUnk, + HRESULT *phr) + : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE), + m_pBuffer(NULL) +{ +} + +#ifdef UNICODE +CMemAllocator::CMemAllocator( + CHAR *pName, + LPUNKNOWN pUnk, + HRESULT *phr) + : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE), + m_pBuffer(NULL) +{ +} +#endif + +/* This sets the size and count of the required samples. The memory isn't + actually allocated until Commit() is called, if memory has already been + allocated then assuming no samples are outstanding the user may call us + to change the buffering, the memory will be released in Commit() */ +STDMETHODIMP +CMemAllocator::SetProperties( + ALLOCATOR_PROPERTIES* pRequest, + ALLOCATOR_PROPERTIES* pActual) +{ + CheckPointer(pActual,E_POINTER); + ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES)); + CAutoLock cObjectLock(this); + + ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES)); + + ASSERT(pRequest->cbBuffer > 0); + + SYSTEM_INFO SysInfo; + GetSystemInfo(&SysInfo); + + /* Check the alignment request is a power of 2 */ + if ((-pRequest->cbAlign & pRequest->cbAlign) != pRequest->cbAlign) { + DbgLog((LOG_ERROR, 1, TEXT("Alignment requested 0x%x not a power of 2!"), + pRequest->cbAlign)); + } + /* Check the alignment requested */ + if (pRequest->cbAlign == 0 || + (SysInfo.dwAllocationGranularity & (pRequest->cbAlign - 1)) != 0) { + DbgLog((LOG_ERROR, 1, TEXT("Invalid alignment 0x%x requested - granularity = 0x%x"), + pRequest->cbAlign, SysInfo.dwAllocationGranularity)); + return VFW_E_BADALIGN; + } + + /* Can't do this if already committed, there is an argument that says we + should not reject the SetProperties call if there are buffers still + active. However this is called by the source filter, which is the same + person who is holding the samples. Therefore it is not unreasonable + for them to free all their samples before changing the requirements */ + + if (m_bCommitted == TRUE) { + return VFW_E_ALREADY_COMMITTED; + } + + /* Must be no outstanding buffers */ + + if (m_lFree.GetCount() < m_lAllocated) { + return VFW_E_BUFFERS_OUTSTANDING; + } + + /* There isn't any real need to check the parameters as they + will just be rejected when the user finally calls Commit */ + + // round length up to alignment - remember that prefix is included in + // the alignment + LONG lSize = pRequest->cbBuffer + pRequest->cbPrefix; + LONG lRemainder = lSize % pRequest->cbAlign; + if (lRemainder != 0) { + lSize = lSize - lRemainder + pRequest->cbAlign; + } + pActual->cbBuffer = m_lSize = (lSize - pRequest->cbPrefix); + + pActual->cBuffers = m_lCount = pRequest->cBuffers; + pActual->cbAlign = m_lAlignment = pRequest->cbAlign; + pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix; + + m_bChanged = TRUE; + return NOERROR; +} + +// override this to allocate our resources when Commit is called. +// +// note that our resources may be already allocated when this is called, +// since we don't free them on Decommit. We will only be called when in +// decommit state with all buffers free. +// +// object locked by caller +HRESULT +CMemAllocator::Alloc(void) +{ + CAutoLock lck(this); + + /* Check he has called SetProperties */ + HRESULT hr = CBaseAllocator::Alloc(); + if (FAILED(hr)) { + return hr; + } + + /* If the requirements haven't changed then don't reallocate */ + if (hr == S_FALSE) { + ASSERT(m_pBuffer); + return NOERROR; + } + ASSERT(hr == S_OK); // we use this fact in the loop below + + /* Free the old resources */ + if (m_pBuffer) { + ReallyFree(); + } + + /* Compute the aligned size */ + LONG lAlignedSize = m_lSize + m_lPrefix; + if (m_lAlignment > 1) { + LONG lRemainder = lAlignedSize % m_lAlignment; + if (lRemainder != 0) { + lAlignedSize += (m_lAlignment - lRemainder); + } + } + + /* Create the contiguous memory block for the samples + making sure it's properly aligned (64K should be enough!) + */ + ASSERT(lAlignedSize % m_lAlignment == 0); + + m_pBuffer = (PBYTE)VirtualAlloc(NULL, + m_lCount * lAlignedSize, + MEM_COMMIT, + PAGE_READWRITE); + + if (m_pBuffer == NULL) { + return E_OUTOFMEMORY; + } + + LPBYTE pNext = m_pBuffer; + CMediaSample *pSample; + + ASSERT(m_lAllocated == 0); + + // Create the new samples - we have allocated m_lSize bytes for each sample + // plus m_lPrefix bytes per sample as a prefix. We set the pointer to + // the memory after the prefix - so that GetPointer() will return a pointer + // to m_lSize bytes. + for (; m_lAllocated < m_lCount; m_lAllocated++, pNext += lAlignedSize) { + + + pSample = new CMediaSample( + NAME("Default memory media sample"), + this, + &hr, + pNext + m_lPrefix, // GetPointer() value + m_lSize); // not including prefix + + ASSERT(SUCCEEDED(hr)); + if (pSample == NULL) { + return E_OUTOFMEMORY; + } + + // This CANNOT fail + m_lFree.Add(pSample); + } + + m_bChanged = FALSE; + return NOERROR; +} + + +// override this to free up any resources we have allocated. +// called from the base class on Decommit when all buffers have been +// returned to the free list. +// +// caller has already locked the object. + +// in our case, we keep the memory until we are deleted, so +// we do nothing here. The memory is deleted in the destructor by +// calling ReallyFree() +void +CMemAllocator::Free(void) +{ + return; +} + + +// called from the destructor (and from Alloc if changing size/count) to +// actually free up the memory +void +CMemAllocator::ReallyFree(void) +{ + /* Should never be deleting this unless all buffers are freed */ + + ASSERT(m_lAllocated == m_lFree.GetCount()); + + /* Free up all the CMediaSamples */ + + CMediaSample *pSample; + for (;;) { + pSample = m_lFree.RemoveHead(); + if (pSample != NULL) { + delete pSample; + } else { + break; + } + } + + m_lAllocated = 0; + + // free the block of buffer memory + if (m_pBuffer) { + EXECUTE_ASSERT(VirtualFree(m_pBuffer, 0, MEM_RELEASE)); + m_pBuffer = NULL; + } +} + + +/* Destructor frees our memory resources */ + +CMemAllocator::~CMemAllocator() +{ + Decommit(); + ReallyFree(); +} + +// ------------------------------------------------------------------------ +// filter registration through IFilterMapper. used if IFilterMapper is +// not found (Quartz 1.0 install) + +STDAPI +AMovieSetupRegisterFilter( const AMOVIESETUP_FILTER * const psetupdata + , IFilterMapper * pIFM + , BOOL bRegister ) +{ + DbgLog((LOG_TRACE, 3, TEXT("= AMovieSetupRegisterFilter"))); + + // check we've got data + // + if( NULL == psetupdata ) return S_FALSE; + + + // unregister filter + // (as pins are subkeys of filter's CLSID key + // they do not need to be removed separately). + // + DbgLog((LOG_TRACE, 3, TEXT("= = unregister filter"))); + HRESULT hr = pIFM->UnregisterFilter( *(psetupdata->clsID) ); + + + if( bRegister ) + { + // register filter + // + DbgLog((LOG_TRACE, 3, TEXT("= = register filter"))); + hr = pIFM->RegisterFilter( *(psetupdata->clsID) + , psetupdata->strName + , psetupdata->dwMerit ); + if( SUCCEEDED(hr) ) + { + // all its pins + // + DbgLog((LOG_TRACE, 3, TEXT("= = register filter pins"))); + for( UINT m1=0; m1 < psetupdata->nPins; m1++ ) + { + hr = pIFM->RegisterPin( *(psetupdata->clsID) + , psetupdata->lpPin[m1].strName + , psetupdata->lpPin[m1].bRendered + , psetupdata->lpPin[m1].bOutput + , psetupdata->lpPin[m1].bZero + , psetupdata->lpPin[m1].bMany + , *(psetupdata->lpPin[m1].clsConnectsToFilter) + , psetupdata->lpPin[m1].strConnectsToPin ); + + if( SUCCEEDED(hr) ) + { + // and each pin's media types + // + DbgLog((LOG_TRACE, 3, TEXT("= = register filter pin types"))); + for( UINT m2=0; m2 < psetupdata->lpPin[m1].nMediaTypes; m2++ ) + { + hr = pIFM->RegisterPinType( *(psetupdata->clsID) + , psetupdata->lpPin[m1].strName + , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMajorType) + , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMinorType) ); + if( FAILED(hr) ) break; + } + if( FAILED(hr) ) break; + } + if( FAILED(hr) ) break; + } + } + } + + // handle one acceptable "error" - that + // of filter not being registered! + // (couldn't find a suitable #define'd + // name for the error!) + // + if( 0x80070002 == hr) + return NOERROR; + else + return hr; +} + +// Remove warnings about unreferenced inline functions +#pragma warning(disable:4514) + diff --git a/plugins/GSdx/baseclasses/amfilter.h b/plugins/GSdx/baseclasses/amfilter.h index 47ffc0a5f0..70dbb44547 100644 --- a/plugins/GSdx/baseclasses/amfilter.h +++ b/plugins/GSdx/baseclasses/amfilter.h @@ -1,1587 +1,1587 @@ -//------------------------------------------------------------------------------ -// File: AMFilter.h -// -// Desc: DirectShow base classes - efines class hierarchy for streams -// architecture. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __FILTER__ -#define __FILTER__ - -/* The following classes are declared in this header: */ - -class CBaseMediaFilter; // IMediaFilter support -class CBaseFilter; // IBaseFilter,IMediaFilter support -class CBasePin; // Abstract base class for IPin interface -class CEnumPins; // Enumerate input and output pins -class CEnumMediaTypes; // Enumerate the pin's preferred formats -class CBaseOutputPin; // Adds data provider member functions -class CBaseInputPin; // Implements IMemInputPin interface -class CMediaSample; // Basic transport unit for IMemInputPin -class CBaseAllocator; // General list guff for most allocators -class CMemAllocator; // Implements memory buffer allocation - - -//===================================================================== -//===================================================================== -// -// QueryFilterInfo and QueryPinInfo AddRef the interface pointers -// they return. You can use the macro below to release the interface. -// -//===================================================================== -//===================================================================== - -#define QueryFilterInfoReleaseGraph(fi) if ((fi).pGraph) (fi).pGraph->Release(); - -#define QueryPinInfoReleaseFilter(pi) if ((pi).pFilter) (pi).pFilter->Release(); - -//===================================================================== -//===================================================================== -// Defines CBaseMediaFilter -// -// Abstract base class implementing IMediaFilter. -// -// Typically you will derive your filter from CBaseFilter rather than -// this, unless you are implementing an object such as a plug-in -// distributor that needs to support IMediaFilter but not IBaseFilter. -// -// Note that IMediaFilter is derived from IPersist to allow query of -// class id. -//===================================================================== -//===================================================================== - -class AM_NOVTABLE CBaseMediaFilter : public CUnknown, - public IMediaFilter -{ - -protected: - - FILTER_STATE m_State; // current state: running, paused - IReferenceClock *m_pClock; // this filter's reference clock - // note: all filters in a filter graph use the same clock - - // offset from stream time to reference time - CRefTime m_tStart; - - CLSID m_clsid; // This filters clsid - // used for serialization - CCritSec *m_pLock; // Object we use for locking - -public: - - CBaseMediaFilter( - const TCHAR *pName, - LPUNKNOWN pUnk, - CCritSec *pLock, - REFCLSID clsid); - - virtual ~CBaseMediaFilter(); - - DECLARE_IUNKNOWN - - // override this to say what interfaces we support where - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv); - - // - // --- IPersist method --- - // - - STDMETHODIMP GetClassID(CLSID *pClsID); - - // --- IMediaFilter methods --- - - STDMETHODIMP GetState(DWORD dwMSecs, FILTER_STATE *State); - - STDMETHODIMP SetSyncSource(IReferenceClock *pClock); - - STDMETHODIMP GetSyncSource(IReferenceClock **pClock); - - // default implementation of Stop and Pause just record the - // state. Override to activate or de-activate your filter. - // Note that Run when called from Stopped state will call Pause - // to ensure activation, so if you are a source or transform - // you will probably not need to override Run. - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - - - // the start parameter is the difference to be added to the - // sample's stream time to get the reference time for - // its presentation - STDMETHODIMP Run(REFERENCE_TIME tStart); - - // --- helper methods --- - - // return the current stream time - ie find out what - // stream time should be appearing now - virtual HRESULT StreamTime(CRefTime& rtStream); - - // Is the filter currently active? (running or paused) - BOOL IsActive() { - CAutoLock cObjectLock(m_pLock); - return ((m_State == State_Paused) || (m_State == State_Running)); - }; -}; - -//===================================================================== -//===================================================================== -// Defines CBaseFilter -// -// An abstract class providing basic IBaseFilter support for pin -// enumeration and filter information reading. -// -// We cannot derive from CBaseMediaFilter since methods in IMediaFilter -// are also in IBaseFilter and would be ambiguous. Since much of the code -// assumes that they derive from a class that has m_State and other state -// directly available, we duplicate code from CBaseMediaFilter rather than -// having a member variable. -// -// Derive your filter from this, or from a derived object such as -// CTransformFilter. -//===================================================================== -//===================================================================== - - -class AM_NOVTABLE CBaseFilter : public CUnknown, // Handles an IUnknown - public IBaseFilter, // The Filter Interface - public IAMovieSetup // For un/registration -{ - -friend class CBasePin; - -protected: - FILTER_STATE m_State; // current state: running, paused - IReferenceClock *m_pClock; // this graph's ref clock - CRefTime m_tStart; // offset from stream time to reference time - CLSID m_clsid; // This filters clsid - // used for serialization - CCritSec *m_pLock; // Object we use for locking - - WCHAR *m_pName; // Full filter name - IFilterGraph *m_pGraph; // Graph we belong to - IMediaEventSink *m_pSink; // Called with notify events - LONG m_PinVersion; // Current pin version - -public: - - CBaseFilter( - const TCHAR *pName, // Object description - LPUNKNOWN pUnk, // IUnknown of delegating object - CCritSec *pLock, // Object who maintains lock - REFCLSID clsid); // The clsid to be used to serialize this filter - - CBaseFilter( - TCHAR *pName, // Object description - LPUNKNOWN pUnk, // IUnknown of delegating object - CCritSec *pLock, // Object who maintains lock - REFCLSID clsid, // The clsid to be used to serialize this filter - HRESULT *phr); // General OLE return code -#ifdef UNICODE - CBaseFilter( - const CHAR *pName, // Object description - LPUNKNOWN pUnk, // IUnknown of delegating object - CCritSec *pLock, // Object who maintains lock - REFCLSID clsid); // The clsid to be used to serialize this filter - - CBaseFilter( - CHAR *pName, // Object description - LPUNKNOWN pUnk, // IUnknown of delegating object - CCritSec *pLock, // Object who maintains lock - REFCLSID clsid, // The clsid to be used to serialize this filter - HRESULT *phr); // General OLE return code -#endif - ~CBaseFilter(); - - DECLARE_IUNKNOWN - - // override this to say what interfaces we support where - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv); -#ifdef DEBUG - STDMETHODIMP_(ULONG) NonDelegatingRelease(); -#endif - - // - // --- IPersist method --- - // - - STDMETHODIMP GetClassID(CLSID *pClsID); - - // --- IMediaFilter methods --- - - STDMETHODIMP GetState(DWORD dwMSecs, FILTER_STATE *State); - - STDMETHODIMP SetSyncSource(IReferenceClock *pClock); - - STDMETHODIMP GetSyncSource(IReferenceClock **pClock); - - - // override Stop and Pause so we can activate the pins. - // Note that Run will call Pause first if activation needed. - // Override these if you want to activate your filter rather than - // your pins. - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - - // the start parameter is the difference to be added to the - // sample's stream time to get the reference time for - // its presentation - STDMETHODIMP Run(REFERENCE_TIME tStart); - - // --- helper methods --- - - // return the current stream time - ie find out what - // stream time should be appearing now - virtual HRESULT StreamTime(CRefTime& rtStream); - - // Is the filter currently active? - BOOL IsActive() { - CAutoLock cObjectLock(m_pLock); - return ((m_State == State_Paused) || (m_State == State_Running)); - }; - - // Is this filter stopped (without locking) - BOOL IsStopped() { - return (m_State == State_Stopped); - }; - - // - // --- IBaseFilter methods --- - // - - // pin enumerator - STDMETHODIMP EnumPins( - IEnumPins ** ppEnum); - - - // default behaviour of FindPin assumes pin ids are their names - STDMETHODIMP FindPin( - LPCWSTR Id, - IPin ** ppPin - ); - - STDMETHODIMP QueryFilterInfo( - FILTER_INFO * pInfo); - - STDMETHODIMP JoinFilterGraph( - IFilterGraph * pGraph, - LPCWSTR pName); - - // return a Vendor information string. Optional - may return E_NOTIMPL. - // memory returned should be freed using CoTaskMemFree - // default implementation returns E_NOTIMPL - STDMETHODIMP QueryVendorInfo( - LPWSTR* pVendorInfo - ); - - // --- helper methods --- - - // send an event notification to the filter graph if we know about it. - // returns S_OK if delivered, S_FALSE if the filter graph does not sink - // events, or an error otherwise. - HRESULT NotifyEvent( - long EventCode, - LONG_PTR EventParam1, - LONG_PTR EventParam2); - - // return the filter graph we belong to - IFilterGraph *GetFilterGraph() { - return m_pGraph; - } - - // Request reconnect - // pPin is the pin to reconnect - // pmt is the type to reconnect with - can be NULL - // Calls ReconnectEx on the filter graph - HRESULT ReconnectPin(IPin *pPin, AM_MEDIA_TYPE const *pmt); - - // find out the current pin version (used by enumerators) - virtual LONG GetPinVersion(); - void IncrementPinVersion(); - - // you need to supply these to access the pins from the enumerator - // and for default Stop and Pause/Run activation. - virtual int GetPinCount() PURE; - virtual CBasePin *GetPin(int n) PURE; - - // --- IAMovieSetup methods --- - - STDMETHODIMP Register(); // ask filter to register itself - STDMETHODIMP Unregister(); // and unregister itself - - // --- setup helper methods --- - // (override to return filters setup data) - - virtual LPAMOVIESETUP_FILTER GetSetupData(){ return NULL; } - -}; - - -//===================================================================== -//===================================================================== -// Defines CBasePin -// -// Abstract class that supports the basics of IPin -//===================================================================== -//===================================================================== - -class AM_NOVTABLE CBasePin : public CUnknown, public IPin, public IQualityControl -{ - -protected: - - WCHAR * m_pName; // This pin's name - IPin *m_Connected; // Pin we have connected to - PIN_DIRECTION m_dir; // Direction of this pin - CCritSec *m_pLock; // Object we use for locking - bool m_bRunTimeError; // Run time error generated - bool m_bCanReconnectWhenActive; // OK to reconnect when active - bool m_bTryMyTypesFirst; // When connecting enumerate - // this pin's types first - CBaseFilter *m_pFilter; // Filter we were created by - IQualityControl *m_pQSink; // Target for Quality messages - LONG m_TypeVersion; // Holds current type version - CMediaType m_mt; // Media type of connection - - CRefTime m_tStart; // time from NewSegment call - CRefTime m_tStop; // time from NewSegment - double m_dRate; // rate from NewSegment - -#ifdef DEBUG - LONG m_cRef; // Ref count tracing -#endif - - // displays pin connection information - -#ifdef DEBUG - void DisplayPinInfo(IPin *pReceivePin); - void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt); -#else - void DisplayPinInfo(IPin *pReceivePin) {}; - void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt) {}; -#endif - - // used to agree a media type for a pin connection - - // given a specific media type, attempt a connection (includes - // checking that the type is acceptable to this pin) - HRESULT - AttemptConnection( - IPin* pReceivePin, // connect to this pin - const CMediaType* pmt // using this type - ); - - // try all the media types in this enumerator - for each that - // we accept, try to connect using ReceiveConnection. - HRESULT TryMediaTypes( - IPin *pReceivePin, // connect to this pin - const CMediaType *pmt, // proposed type from Connect - IEnumMediaTypes *pEnum); // try this enumerator - - // establish a connection with a suitable mediatype. Needs to - // propose a media type if the pmt pointer is null or partially - // specified - use TryMediaTypes on both our and then the other pin's - // enumerator until we find one that works. - HRESULT AgreeMediaType( - IPin *pReceivePin, // connect to this pin - const CMediaType *pmt); // proposed type from Connect - -public: - - CBasePin( - TCHAR *pObjectName, // Object description - CBaseFilter *pFilter, // Owning filter who knows about pins - CCritSec *pLock, // Object who implements the lock - HRESULT *phr, // General OLE return code - LPCWSTR pName, // Pin name for us - PIN_DIRECTION dir); // Either PINDIR_INPUT or PINDIR_OUTPUT -#ifdef UNICODE - CBasePin( - CHAR *pObjectName, // Object description - CBaseFilter *pFilter, // Owning filter who knows about pins - CCritSec *pLock, // Object who implements the lock - HRESULT *phr, // General OLE return code - LPCWSTR pName, // Pin name for us - PIN_DIRECTION dir); // Either PINDIR_INPUT or PINDIR_OUTPUT -#endif - virtual ~CBasePin(); - - DECLARE_IUNKNOWN - - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv); - STDMETHODIMP_(ULONG) NonDelegatingRelease(); - STDMETHODIMP_(ULONG) NonDelegatingAddRef(); - - // --- IPin methods --- - - // take lead role in establishing a connection. Media type pointer - // may be null, or may point to partially-specified mediatype - // (subtype or format type may be GUID_NULL). - STDMETHODIMP Connect( - IPin * pReceivePin, - const AM_MEDIA_TYPE *pmt // optional media type - ); - - // (passive) accept a connection from another pin - STDMETHODIMP ReceiveConnection( - IPin * pConnector, // this is the initiating connecting pin - const AM_MEDIA_TYPE *pmt // this is the media type we will exchange - ); - - STDMETHODIMP Disconnect(); - - STDMETHODIMP ConnectedTo(IPin **pPin); - - STDMETHODIMP ConnectionMediaType(AM_MEDIA_TYPE *pmt); - - STDMETHODIMP QueryPinInfo( - PIN_INFO * pInfo - ); - - STDMETHODIMP QueryDirection( - PIN_DIRECTION * pPinDir - ); - - STDMETHODIMP QueryId( - LPWSTR * Id - ); - - // does the pin support this media type - STDMETHODIMP QueryAccept( - const AM_MEDIA_TYPE *pmt - ); - - // return an enumerator for this pins preferred media types - STDMETHODIMP EnumMediaTypes( - IEnumMediaTypes **ppEnum - ); - - // return an array of IPin* - the pins that this pin internally connects to - // All pins put in the array must be AddReffed (but no others) - // Errors: "Can't say" - FAIL, not enough slots - return S_FALSE - // Default: return E_NOTIMPL - // The filter graph will interpret NOT_IMPL as any input pin connects to - // all visible output pins and vice versa. - // apPin can be NULL if nPin==0 (not otherwise). - STDMETHODIMP QueryInternalConnections( - IPin* *apPin, // array of IPin* - ULONG *nPin // on input, the number of slots - // on output the number of pins - ) { return E_NOTIMPL; } - - // Called when no more data will be sent - STDMETHODIMP EndOfStream(void); - - // Begin/EndFlush still PURE - - // NewSegment notifies of the start/stop/rate applying to the data - // about to be received. Default implementation records data and - // returns S_OK. - // Override this to pass downstream. - STDMETHODIMP NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate); - - //================================================================================ - // IQualityControl methods - //================================================================================ - - STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); - - STDMETHODIMP SetSink(IQualityControl * piqc); - - // --- helper methods --- - - // Returns true if the pin is connected. false otherwise. - BOOL IsConnected(void) {return (m_Connected != NULL); }; - // Return the pin this is connected to (if any) - IPin * GetConnected() { return m_Connected; }; - - // Check if our filter is currently stopped - BOOL IsStopped() { - return (m_pFilter->m_State == State_Stopped); - }; - - // find out the current type version (used by enumerators) - virtual LONG GetMediaTypeVersion(); - void IncrementTypeVersion(); - - // switch the pin to active (paused or running) mode - // not an error to call this if already active - virtual HRESULT Active(void); - - // switch the pin to inactive state - may already be inactive - virtual HRESULT Inactive(void); - - // Notify of Run() from filter - virtual HRESULT Run(REFERENCE_TIME tStart); - - // check if the pin can support this specific proposed type and format - virtual HRESULT CheckMediaType(const CMediaType *) PURE; - - // set the connection to use this format (previously agreed) - virtual HRESULT SetMediaType(const CMediaType *); - - // check that the connection is ok before verifying it - // can be overridden eg to check what interfaces will be supported. - virtual HRESULT CheckConnect(IPin *); - - // Set and release resources required for a connection - virtual HRESULT BreakConnect(); - virtual HRESULT CompleteConnect(IPin *pReceivePin); - - // returns the preferred formats for a pin - virtual HRESULT GetMediaType(int iPosition,CMediaType *pMediaType); - - // access to NewSegment values - REFERENCE_TIME CurrentStopTime() { - return m_tStop; - } - REFERENCE_TIME CurrentStartTime() { - return m_tStart; - } - double CurrentRate() { - return m_dRate; - } - - // Access name - LPWSTR Name() { return m_pName; }; - - // Can reconnectwhen active? - void SetReconnectWhenActive(bool bCanReconnect) - { - m_bCanReconnectWhenActive = bCanReconnect; - } - - bool CanReconnectWhenActive() - { - return m_bCanReconnectWhenActive; - } - -protected: - STDMETHODIMP DisconnectInternal(); -}; - - -//===================================================================== -//===================================================================== -// Defines CEnumPins -// -// Pin enumerator class that works by calling CBaseFilter. This interface -// is provided by CBaseFilter::EnumPins and calls GetPinCount() and -// GetPin() to enumerate existing pins. Needs to be a separate object so -// that it can be cloned (creating an existing object at the same -// position in the enumeration) -// -//===================================================================== -//===================================================================== - -class CEnumPins : public IEnumPins // The interface we support -{ - int m_Position; // Current ordinal position - int m_PinCount; // Number of pins available - CBaseFilter *m_pFilter; // The filter who owns us - LONG m_Version; // Pin version information - LONG m_cRef; - - typedef CGenericList CPinList; - - CPinList m_PinCache; // These pointers have not been AddRef'ed and - // so they should not be dereferenced. They are - // merely kept to ID which pins have been enumerated. - -#ifdef DEBUG - DWORD m_dwCookie; -#endif - - /* If while we are retrieving a pin for example from the filter an error - occurs we assume that our internal state is stale with respect to the - filter (someone may have deleted all the pins). We can check before - starting whether or not the operation is likely to fail by asking the - filter what it's current version number is. If the filter has not - overriden the GetPinVersion method then this will always match */ - - BOOL AreWeOutOfSync() { - return (m_pFilter->GetPinVersion() == m_Version ? FALSE : TRUE); - }; - - /* This method performs the same operations as Reset, except is does not clear - the cache of pins already enumerated. */ - - STDMETHODIMP Refresh(); - -public: - - CEnumPins( - CBaseFilter *pFilter, - CEnumPins *pEnumPins); - - virtual ~CEnumPins(); - - // IUnknown - STDMETHODIMP QueryInterface(REFIID riid, void **ppv); - STDMETHODIMP_(ULONG) AddRef(); - STDMETHODIMP_(ULONG) Release(); - - // IEnumPins - STDMETHODIMP Next( - ULONG cPins, // place this many pins... - IPin ** ppPins, // ...in this array of IPin* - ULONG * pcFetched // actual count passed returned here - ); - - STDMETHODIMP Skip(ULONG cPins); - STDMETHODIMP Reset(); - STDMETHODIMP Clone(IEnumPins **ppEnum); - - -}; - - -//===================================================================== -//===================================================================== -// Defines CEnumMediaTypes -// -// Enumerates the preferred formats for input and output pins -//===================================================================== -//===================================================================== - -class CEnumMediaTypes : public IEnumMediaTypes // The interface we support -{ - int m_Position; // Current ordinal position - CBasePin *m_pPin; // The pin who owns us - LONG m_Version; // Media type version value - LONG m_cRef; -#ifdef DEBUG - DWORD m_dwCookie; -#endif - - /* The media types a filter supports can be quite dynamic so we add to - the general IEnumXXXX interface the ability to be signaled when they - change via an event handle the connected filter supplies. Until the - Reset method is called after the state changes all further calls to - the enumerator (except Reset) will return E_UNEXPECTED error code */ - - BOOL AreWeOutOfSync() { - return (m_pPin->GetMediaTypeVersion() == m_Version ? FALSE : TRUE); - }; - -public: - - CEnumMediaTypes( - CBasePin *pPin, - CEnumMediaTypes *pEnumMediaTypes); - - virtual ~CEnumMediaTypes(); - - // IUnknown - STDMETHODIMP QueryInterface(REFIID riid, void **ppv); - STDMETHODIMP_(ULONG) AddRef(); - STDMETHODIMP_(ULONG) Release(); - - // IEnumMediaTypes - STDMETHODIMP Next( - ULONG cMediaTypes, // place this many pins... - AM_MEDIA_TYPE ** ppMediaTypes, // ...in this array - ULONG * pcFetched // actual count passed - ); - - STDMETHODIMP Skip(ULONG cMediaTypes); - STDMETHODIMP Reset(); - STDMETHODIMP Clone(IEnumMediaTypes **ppEnum); -}; - - - - -//===================================================================== -//===================================================================== -// Defines CBaseOutputPin -// -// class derived from CBasePin that can pass buffers to a connected pin -// that supports IMemInputPin. Supports IPin. -// -// Derive your output pin from this. -// -//===================================================================== -//===================================================================== - -class AM_NOVTABLE CBaseOutputPin : public CBasePin -{ - -protected: - - IMemAllocator *m_pAllocator; - IMemInputPin *m_pInputPin; // interface on the downstreaminput pin - // set up in CheckConnect when we connect. - -public: - - CBaseOutputPin( - TCHAR *pObjectName, - CBaseFilter *pFilter, - CCritSec *pLock, - HRESULT *phr, - LPCWSTR pName); -#ifdef UNICODE - CBaseOutputPin( - CHAR *pObjectName, - CBaseFilter *pFilter, - CCritSec *pLock, - HRESULT *phr, - LPCWSTR pName); -#endif - // override CompleteConnect() so we can negotiate an allocator - virtual HRESULT CompleteConnect(IPin *pReceivePin); - - // negotiate the allocator and its buffer size/count and other properties - // Calls DecideBufferSize to set properties - virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc); - - // override this to set the buffer size and count. Return an error - // if the size/count is not to your liking. - // The allocator properties passed in are those requested by the - // input pin - use eg the alignment and prefix members if you have - // no preference on these. - virtual HRESULT DecideBufferSize( - IMemAllocator * pAlloc, - ALLOCATOR_PROPERTIES * ppropInputRequest - ) PURE; - - // returns an empty sample buffer from the allocator - virtual HRESULT GetDeliveryBuffer(IMediaSample ** ppSample, - REFERENCE_TIME * pStartTime, - REFERENCE_TIME * pEndTime, - DWORD dwFlags); - - // deliver a filled-in sample to the connected input pin - // note - you need to release it after calling this. The receiving - // pin will addref the sample if it needs to hold it beyond the - // call. - virtual HRESULT Deliver(IMediaSample *); - - // override this to control the connection - virtual HRESULT InitAllocator(IMemAllocator **ppAlloc); - HRESULT CheckConnect(IPin *pPin); - HRESULT BreakConnect(); - - // override to call Commit and Decommit - HRESULT Active(void); - HRESULT Inactive(void); - - // we have a default handling of EndOfStream which is to return - // an error, since this should be called on input pins only - STDMETHODIMP EndOfStream(void); - - // called from elsewhere in our filter to pass EOS downstream to - // our connected input pin - virtual HRESULT DeliverEndOfStream(void); - - // same for Begin/EndFlush - we handle Begin/EndFlush since it - // is an error on an output pin, and we have Deliver methods to - // call the methods on the connected pin - STDMETHODIMP BeginFlush(void); - STDMETHODIMP EndFlush(void); - virtual HRESULT DeliverBeginFlush(void); - virtual HRESULT DeliverEndFlush(void); - - // deliver NewSegment to connected pin - you will need to - // override this if you queue any data in your output pin. - virtual HRESULT DeliverNewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate); - - //================================================================================ - // IQualityControl methods - //================================================================================ - - // All inherited from CBasePin and not overridden here. - // STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); - // STDMETHODIMP SetSink(IQualityControl * piqc); -}; - - -//===================================================================== -//===================================================================== -// Defines CBaseInputPin -// -// derive your standard input pin from this. -// you need to supply GetMediaType and CheckConnect etc (see CBasePin), -// and you need to supply Receive to do something more useful. -// -//===================================================================== -//===================================================================== - -class AM_NOVTABLE CBaseInputPin : public CBasePin, - public IMemInputPin -{ - -protected: - - IMemAllocator *m_pAllocator; // Default memory allocator - - // allocator is read-only, so received samples - // cannot be modified (probably only relevant to in-place - // transforms - BYTE m_bReadOnly; - - // in flushing state (between BeginFlush and EndFlush) - // if TRUE, all Receives are returned with S_FALSE - BYTE m_bFlushing; - - // Sample properties - initalized in Receive - AM_SAMPLE2_PROPERTIES m_SampleProps; - -public: - - CBaseInputPin( - TCHAR *pObjectName, - CBaseFilter *pFilter, - CCritSec *pLock, - HRESULT *phr, - LPCWSTR pName); -#ifdef UNICODE - CBaseInputPin( - CHAR *pObjectName, - CBaseFilter *pFilter, - CCritSec *pLock, - HRESULT *phr, - LPCWSTR pName); -#endif - virtual ~CBaseInputPin(); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); - - // return the allocator interface that this input pin - // would like the output pin to use - STDMETHODIMP GetAllocator(IMemAllocator ** ppAllocator); - - // tell the input pin which allocator the output pin is actually - // going to use. - STDMETHODIMP NotifyAllocator( - IMemAllocator * pAllocator, - BOOL bReadOnly); - - // do something with this media sample - STDMETHODIMP Receive(IMediaSample *pSample); - - // do something with these media samples - STDMETHODIMP ReceiveMultiple ( - IMediaSample **pSamples, - long nSamples, - long *nSamplesProcessed); - - // See if Receive() blocks - STDMETHODIMP ReceiveCanBlock(); - - // Default handling for BeginFlush - call at the beginning - // of your implementation (makes sure that all Receive calls - // fail). After calling this, you need to free any queued data - // and then call downstream. - STDMETHODIMP BeginFlush(void); - - // default handling for EndFlush - call at end of your implementation - // - before calling this, ensure that there is no queued data and no thread - // pushing any more without a further receive, then call downstream, - // then call this method to clear the m_bFlushing flag and re-enable - // receives - STDMETHODIMP EndFlush(void); - - // this method is optional (can return E_NOTIMPL). - // default implementation returns E_NOTIMPL. Override if you have - // specific alignment or prefix needs, but could use an upstream - // allocator - STDMETHODIMP GetAllocatorRequirements(ALLOCATOR_PROPERTIES*pProps); - - // Release the pin's allocator. - HRESULT BreakConnect(); - - // helper method to check the read-only flag - BOOL IsReadOnly() { - return m_bReadOnly; - }; - - // helper method to see if we are flushing - BOOL IsFlushing() { - return m_bFlushing; - }; - - // Override this for checking whether it's OK to process samples - // Also call this from EndOfStream. - virtual HRESULT CheckStreaming(); - - // Pass a Quality notification on to the appropriate sink - HRESULT PassNotify(Quality& q); - - - //================================================================================ - // IQualityControl methods (from CBasePin) - //================================================================================ - - STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); - - // no need to override: - // STDMETHODIMP SetSink(IQualityControl * piqc); - - - // switch the pin to inactive state - may already be inactive - virtual HRESULT Inactive(void); - - // Return sample properties pointer - AM_SAMPLE2_PROPERTIES * SampleProps() { - ASSERT(m_SampleProps.cbData != 0); - return &m_SampleProps; - } - -}; - -/////////////////////////////////////////////////////////////////////////// -// CDynamicOutputPin -// - -class CDynamicOutputPin : public CBaseOutputPin, - public IPinFlowControl -{ -public: -#ifdef UNICODE - CDynamicOutputPin( - CHAR *pObjectName, - CBaseFilter *pFilter, - CCritSec *pLock, - HRESULT *phr, - LPCWSTR pName); -#endif - - CDynamicOutputPin( - TCHAR *pObjectName, - CBaseFilter *pFilter, - CCritSec *pLock, - HRESULT *phr, - LPCWSTR pName); - - ~CDynamicOutputPin(); - - // IUnknown Methods - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); - - // IPin Methods - STDMETHODIMP Disconnect(void); - - // IPinFlowControl Methods - STDMETHODIMP Block(DWORD dwBlockFlags, HANDLE hEvent); - - // Set graph config info - void SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent); - - #ifdef DEBUG - virtual HRESULT Deliver(IMediaSample *pSample); - virtual HRESULT DeliverEndOfStream(void); - virtual HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - #endif // DEBUG - - HRESULT DeliverBeginFlush(void); - HRESULT DeliverEndFlush(void); - - HRESULT Inactive(void); - HRESULT Active(void); - virtual HRESULT CompleteConnect(IPin *pReceivePin); - - virtual HRESULT StartUsingOutputPin(void); - virtual void StopUsingOutputPin(void); - virtual bool StreamingThreadUsingOutputPin(void); - - HRESULT ChangeOutputFormat - ( - const AM_MEDIA_TYPE *pmt, - REFERENCE_TIME tSegmentStart, - REFERENCE_TIME tSegmentStop, - double dSegmentRate - ); - HRESULT ChangeMediaType(const CMediaType *pmt); - HRESULT DynamicReconnect(const CMediaType *pmt); - -protected: - HRESULT SynchronousBlockOutputPin(void); - HRESULT AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent); - HRESULT UnblockOutputPin(void); - - void BlockOutputPin(void); - void ResetBlockState(void); - - static HRESULT WaitEvent(HANDLE hEvent); - - enum BLOCK_STATE - { - NOT_BLOCKED, - PENDING, - BLOCKED - }; - - // This lock should be held when the following class members are - // being used: m_hNotifyCallerPinBlockedEvent, m_BlockState, - // m_dwBlockCallerThreadID and m_dwNumOutstandingOutputPinUsers. - CCritSec m_BlockStateLock; - - // This event should be signaled when the output pin is - // not blocked. This is a manual reset event. For more - // information on events, see the documentation for - // CreateEvent() in the Windows SDK. - HANDLE m_hUnblockOutputPinEvent; - - // This event will be signaled when block operation succeedes or - // when the user cancels the block operation. The block operation - // can be canceled by calling IPinFlowControl2::Block( 0, NULL ) - // while the block operation is pending. - HANDLE m_hNotifyCallerPinBlockedEvent; - - // The state of the current block operation. - BLOCK_STATE m_BlockState; - - // The ID of the thread which last called IPinFlowControl::Block(). - // For more information on thread IDs, see the documentation for - // GetCurrentThreadID() in the Windows SDK. - DWORD m_dwBlockCallerThreadID; - - // The number of times StartUsingOutputPin() has been sucessfully - // called and a corresponding call to StopUsingOutputPin() has not - // been made. When this variable is greater than 0, the streaming - // thread is calling IPin::NewSegment(), IPin::EndOfStream(), - // IMemInputPin::Receive() or IMemInputPin::ReceiveMultiple(). The - // streaming thread could also be calling: DynamicReconnect(), - // ChangeMediaType() or ChangeOutputFormat(). The output pin cannot - // be blocked while the output pin is being used. - DWORD m_dwNumOutstandingOutputPinUsers; - - // This event should be set when the IMediaFilter::Stop() is called. - // This is a manual reset event. It is also set when the output pin - // delivers a flush to the connected input pin. - HANDLE m_hStopEvent; - IGraphConfig* m_pGraphConfig; - - // TRUE if the output pin's allocator's samples are read only. - // Otherwise FALSE. For more information, see the documentation - // for IMemInputPin::NotifyAllocator(). - BOOL m_bPinUsesReadOnlyAllocator; - -private: - HRESULT Initialize(void); - HRESULT ChangeMediaTypeHelper(const CMediaType *pmt); - - #ifdef DEBUG - void AssertValid(void); - #endif // DEBUG -}; - -class CAutoUsingOutputPin -{ -public: - CAutoUsingOutputPin( CDynamicOutputPin* pOutputPin, HRESULT* phr ); - ~CAutoUsingOutputPin(); - -private: - CDynamicOutputPin* m_pOutputPin; -}; - -inline CAutoUsingOutputPin::CAutoUsingOutputPin( CDynamicOutputPin* pOutputPin, HRESULT* phr ) : - m_pOutputPin(NULL) -{ - // The caller should always pass in valid pointers. - ASSERT( NULL != pOutputPin ); - ASSERT( NULL != phr ); - - // Make sure the user initialized phr. - ASSERT( S_OK == *phr ); - - HRESULT hr = pOutputPin->StartUsingOutputPin(); - if( FAILED( hr ) ) - { - *phr = hr; - return; - } - - m_pOutputPin = pOutputPin; -} - -inline CAutoUsingOutputPin::~CAutoUsingOutputPin() -{ - if( NULL != m_pOutputPin ) - { - m_pOutputPin->StopUsingOutputPin(); - } -} - -#ifdef DEBUG - -inline HRESULT CDynamicOutputPin::Deliver(IMediaSample *pSample) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT(StreamingThreadUsingOutputPin()); - - return CBaseOutputPin::Deliver(pSample); -} - -inline HRESULT CDynamicOutputPin::DeliverEndOfStream(void) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT( StreamingThreadUsingOutputPin() ); - - return CBaseOutputPin::DeliverEndOfStream(); -} - -inline HRESULT CDynamicOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT(StreamingThreadUsingOutputPin()); - - return CBaseOutputPin::DeliverNewSegment(tStart, tStop, dRate); -} - -#endif // DEBUG - -//===================================================================== -//===================================================================== -// Memory allocators -// -// the shared memory transport between pins requires the input pin -// to provide a memory allocator that can provide sample objects. A -// sample object supports the IMediaSample interface. -// -// CBaseAllocator handles the management of free and busy samples. It -// allocates CMediaSample objects. CBaseAllocator is an abstract class: -// in particular it has no method of initializing the list of free -// samples. CMemAllocator is derived from CBaseAllocator and initializes -// the list of samples using memory from the standard IMalloc interface. -// -// If you want your buffers to live in some special area of memory, -// derive your allocator object from CBaseAllocator. If you derive your -// IMemInputPin interface object from CBaseMemInputPin, you will get -// CMemAllocator-based allocation etc for free and will just need to -// supply the Receive handling, and media type / format negotiation. -//===================================================================== -//===================================================================== - - -//===================================================================== -//===================================================================== -// Defines CMediaSample -// -// an object of this class supports IMediaSample and represents a buffer -// for media data with some associated properties. Releasing it returns -// it to a freelist managed by a CBaseAllocator derived object. -//===================================================================== -//===================================================================== - -class CMediaSample : public IMediaSample2 // The interface we support -{ - -protected: - - friend class CBaseAllocator; - - /* Values for dwFlags - these are used for backward compatiblity - only now - use AM_SAMPLE_xxx - */ - enum { Sample_SyncPoint = 0x01, /* Is this a sync point */ - Sample_Preroll = 0x02, /* Is this a preroll sample */ - Sample_Discontinuity = 0x04, /* Set if start of new segment */ - Sample_TypeChanged = 0x08, /* Has the type changed */ - Sample_TimeValid = 0x10, /* Set if time is valid */ - Sample_MediaTimeValid = 0x20, /* Is the media time valid */ - Sample_TimeDiscontinuity = 0x40, /* Time discontinuity */ - Sample_StopValid = 0x100, /* Stop time valid */ - Sample_ValidFlags = 0x1FF - }; - - /* Properties, the media sample class can be a container for a format - change in which case we take a copy of a type through the SetMediaType - interface function and then return it when GetMediaType is called. As - we do no internal processing on it we leave it as a pointer */ - - DWORD m_dwFlags; /* Flags for this sample */ - /* Type specific flags are packed - into the top word - */ - DWORD m_dwTypeSpecificFlags; /* Media type specific flags */ - LPBYTE m_pBuffer; /* Pointer to the complete buffer */ - LONG m_lActual; /* Length of data in this sample */ - LONG m_cbBuffer; /* Size of the buffer */ - CBaseAllocator *m_pAllocator; /* The allocator who owns us */ - CMediaSample *m_pNext; /* Chaining in free list */ - REFERENCE_TIME m_Start; /* Start sample time */ - REFERENCE_TIME m_End; /* End sample time */ - LONGLONG m_MediaStart; /* Real media start position */ - LONG m_MediaEnd; /* A difference to get the end */ - AM_MEDIA_TYPE *m_pMediaType; /* Media type change data */ - DWORD m_dwStreamId; /* Stream id */ -public: - LONG m_cRef; /* Reference count */ - - -public: - - CMediaSample( - TCHAR *pName, - CBaseAllocator *pAllocator, - HRESULT *phr, - LPBYTE pBuffer = NULL, - LONG length = 0); -#ifdef UNICODE - CMediaSample( - CHAR *pName, - CBaseAllocator *pAllocator, - HRESULT *phr, - LPBYTE pBuffer = NULL, - LONG length = 0); -#endif - - virtual ~CMediaSample(); - - /* Note the media sample does not delegate to its owner */ - - STDMETHODIMP QueryInterface(REFIID riid, void **ppv); - STDMETHODIMP_(ULONG) AddRef(); - STDMETHODIMP_(ULONG) Release(); - - // set the buffer pointer and length. Used by allocators that - // want variable sized pointers or pointers into already-read data. - // This is only available through a CMediaSample* not an IMediaSample* - // and so cannot be changed by clients. - HRESULT SetPointer(BYTE * ptr, LONG cBytes); - - // Get me a read/write pointer to this buffer's memory. - STDMETHODIMP GetPointer(BYTE ** ppBuffer); - - STDMETHODIMP_(LONG) GetSize(void); - - // get the stream time at which this sample should start and finish. - STDMETHODIMP GetTime( - REFERENCE_TIME * pTimeStart, // put time here - REFERENCE_TIME * pTimeEnd - ); - - // Set the stream time at which this sample should start and finish. - STDMETHODIMP SetTime( - REFERENCE_TIME * pTimeStart, // put time here - REFERENCE_TIME * pTimeEnd - ); - STDMETHODIMP IsSyncPoint(void); - STDMETHODIMP SetSyncPoint(BOOL bIsSyncPoint); - STDMETHODIMP IsPreroll(void); - STDMETHODIMP SetPreroll(BOOL bIsPreroll); - - STDMETHODIMP_(LONG) GetActualDataLength(void); - STDMETHODIMP SetActualDataLength(LONG lActual); - - // these allow for limited format changes in band - - STDMETHODIMP GetMediaType(AM_MEDIA_TYPE **ppMediaType); - STDMETHODIMP SetMediaType(AM_MEDIA_TYPE *pMediaType); - - // returns S_OK if there is a discontinuity in the data (this same is - // not a continuation of the previous stream of data - // - there has been a seek). - STDMETHODIMP IsDiscontinuity(void); - // set the discontinuity property - TRUE if this sample is not a - // continuation, but a new sample after a seek. - STDMETHODIMP SetDiscontinuity(BOOL bDiscontinuity); - - // get the media times for this sample - STDMETHODIMP GetMediaTime( - LONGLONG * pTimeStart, - LONGLONG * pTimeEnd - ); - - // Set the media times for this sample - STDMETHODIMP SetMediaTime( - LONGLONG * pTimeStart, - LONGLONG * pTimeEnd - ); - - // Set and get properties (IMediaSample2) - STDMETHODIMP GetProperties( - DWORD cbProperties, - BYTE * pbProperties - ); - - STDMETHODIMP SetProperties( - DWORD cbProperties, - const BYTE * pbProperties - ); -}; - - -//===================================================================== -//===================================================================== -// Defines CBaseAllocator -// -// Abstract base class that manages a list of media samples -// -// This class provides support for getting buffers from the free list, -// including handling of commit and (asynchronous) decommit. -// -// Derive from this class and override the Alloc and Free functions to -// allocate your CMediaSample (or derived) objects and add them to the -// free list, preparing them as necessary. -//===================================================================== -//===================================================================== - -class AM_NOVTABLE CBaseAllocator : public CUnknown,// A non delegating IUnknown - public IMemAllocatorCallbackTemp, // The interface we support - public CCritSec // Provides object locking -{ - class CSampleList; - friend class CSampleList; - - /* Trick to get at protected member in CMediaSample */ - static CMediaSample * &NextSample(CMediaSample *pSample) - { - return pSample->m_pNext; - }; - - /* Mini list class for the free list */ - class CSampleList - { - public: - CSampleList() : m_List(NULL), m_nOnList(0) {}; -#ifdef DEBUG - ~CSampleList() - { - ASSERT(m_nOnList == 0); - }; -#endif - CMediaSample *Head() const { return m_List; }; - CMediaSample *Next(CMediaSample *pSample) const { return CBaseAllocator::NextSample(pSample); }; - int GetCount() const { return m_nOnList; }; - void Add(CMediaSample *pSample) - { - ASSERT(pSample != NULL); - CBaseAllocator::NextSample(pSample) = m_List; - m_List = pSample; - m_nOnList++; - }; - CMediaSample *RemoveHead() - { - CMediaSample *pSample = m_List; - if (pSample != NULL) { - m_List = CBaseAllocator::NextSample(m_List); - m_nOnList--; - } - return pSample; - }; - void Remove(CMediaSample *pSample); - - public: - CMediaSample *m_List; - int m_nOnList; - }; -protected: - - CSampleList m_lFree; // Free list - - /* Note to overriders of CBaseAllocator. - - We use a lazy signalling mechanism for waiting for samples. - This means we don't call the OS if no waits occur. - - In order to implement this: - - 1. When a new sample is added to m_lFree call NotifySample() which - calls ReleaseSemaphore on m_hSem with a count of m_lWaiting and - sets m_lWaiting to 0. - This must all be done holding the allocator's critical section. - - 2. When waiting for a sample call SetWaiting() which increments - m_lWaiting BEFORE leaving the allocator's critical section. - - 3. Actually wait by calling WaitForSingleObject(m_hSem, INFINITE) - having left the allocator's critical section. The effect of - this is to remove 1 from the semaphore's count. You MUST call - this once having incremented m_lWaiting. - - The following are then true when the critical section is not held : - (let nWaiting = number about to wait or waiting) - - (1) if (m_lFree.GetCount() != 0) then (m_lWaiting == 0) - (2) m_lWaiting + Semaphore count == nWaiting - - We would deadlock if - nWaiting != 0 && - m_lFree.GetCount() != 0 && - Semaphore count == 0 - - But from (1) if m_lFree.GetCount() != 0 then m_lWaiting == 0 so - from (2) Semaphore count == nWaiting (which is non-0) so the - deadlock can't happen. - */ - - HANDLE m_hSem; // For signalling - long m_lWaiting; // Waiting for a free element - long m_lCount; // how many buffers we have agreed to provide - long m_lAllocated; // how many buffers are currently allocated - long m_lSize; // agreed size of each buffer - long m_lAlignment; // agreed alignment - long m_lPrefix; // agreed prefix (preceeds GetPointer() value) - BOOL m_bChanged; // Have the buffer requirements changed - - // if true, we are decommitted and can't allocate memory - BOOL m_bCommitted; - // if true, the decommit has happened, but we haven't called Free yet - // as there are still outstanding buffers - BOOL m_bDecommitInProgress; - - // Notification interface - IMemAllocatorNotifyCallbackTemp *m_pNotify; - - BOOL m_fEnableReleaseCallback; - - // called to decommit the memory when the last buffer is freed - // pure virtual - need to override this - virtual void Free(void) PURE; - - // override to allocate the memory when commit called - virtual HRESULT Alloc(void); - -public: - - CBaseAllocator( - TCHAR *, LPUNKNOWN, HRESULT *, - BOOL bEvent = TRUE, BOOL fEnableReleaseCallback = FALSE); -#ifdef UNICODE - CBaseAllocator( - CHAR *, LPUNKNOWN, HRESULT *, - BOOL bEvent = TRUE, BOOL fEnableReleaseCallback = FALSE); -#endif - virtual ~CBaseAllocator(); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); - - STDMETHODIMP SetProperties( - ALLOCATOR_PROPERTIES* pRequest, - ALLOCATOR_PROPERTIES* pActual); - - // return the properties actually being used on this allocator - STDMETHODIMP GetProperties( - ALLOCATOR_PROPERTIES* pProps); - - // override Commit to allocate memory. We handle the GetBuffer - //state changes - STDMETHODIMP Commit(); - - // override this to handle the memory freeing. We handle any outstanding - // GetBuffer calls - STDMETHODIMP Decommit(); - - // get container for a sample. Blocking, synchronous call to get the - // next free buffer (as represented by an IMediaSample interface). - // on return, the time etc properties will be invalid, but the buffer - // pointer and size will be correct. The two time parameters are - // optional and either may be NULL, they may alternatively be set to - // the start and end times the sample will have attached to it - // bPrevFramesSkipped is not used (used only by the video renderer's - // allocator where it affects quality management in direct draw). - - STDMETHODIMP GetBuffer(IMediaSample **ppBuffer, - REFERENCE_TIME * pStartTime, - REFERENCE_TIME * pEndTime, - DWORD dwFlags); - - // final release of a CMediaSample will call this - STDMETHODIMP ReleaseBuffer(IMediaSample *pBuffer); - // obsolete:: virtual void PutOnFreeList(CMediaSample * pSample); - - STDMETHODIMP SetNotify(IMemAllocatorNotifyCallbackTemp *pNotify); - - STDMETHODIMP GetFreeCount(LONG *plBuffersFree); - - // Notify that a sample is available - void NotifySample(); - - // Notify that we're waiting for a sample - void SetWaiting() { m_lWaiting++; }; -}; - - -//===================================================================== -//===================================================================== -// Defines CMemAllocator -// -// this is an allocator based on CBaseAllocator that allocates sample -// buffers in main memory (from 'new'). You must call SetProperties -// before calling Commit. -// -// we don't free the memory when going into Decommit state. The simplest -// way to implement this without complicating CBaseAllocator is to -// have a Free() function, called to go into decommit state, that does -// nothing and a ReallyFree function called from our destructor that -// actually frees the memory. -//===================================================================== -//===================================================================== - -// Make me one from quartz.dll -STDAPI CreateMemoryAllocator(IMemAllocator **ppAllocator); - -class CMemAllocator : public CBaseAllocator -{ - -protected: - - LPBYTE m_pBuffer; // combined memory for all buffers - - // override to free the memory when decommit completes - // - we actually do nothing, and save the memory until deletion. - void Free(void); - - // called from the destructor (and from Alloc if changing size/count) to - // actually free up the memory - void ReallyFree(void); - - // overriden to allocate the memory when commit called - HRESULT Alloc(void); - -public: - /* This goes in the factory template table to create new instances */ - static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *); - - STDMETHODIMP SetProperties( - ALLOCATOR_PROPERTIES* pRequest, - ALLOCATOR_PROPERTIES* pActual); - - CMemAllocator(TCHAR *, LPUNKNOWN, HRESULT *); -#ifdef UNICODE - CMemAllocator(CHAR *, LPUNKNOWN, HRESULT *); -#endif - ~CMemAllocator(); -}; - -// helper used by IAMovieSetup implementation -STDAPI -AMovieSetupRegisterFilter( const AMOVIESETUP_FILTER * const psetupdata - , IFilterMapper * pIFM - , BOOL bRegister ); - - -/////////////////////////////////////////////////////////////////////////// -// ------------------------------------------------------------------------ -// ------------------------------------------------------------------------ -// ------------------------------------------------------------------------ -// ------------------------------------------------------------------------ -/////////////////////////////////////////////////////////////////////////// - -#endif /* __FILTER__ */ - - - +//------------------------------------------------------------------------------ +// File: AMFilter.h +// +// Desc: DirectShow base classes - efines class hierarchy for streams +// architecture. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __FILTER__ +#define __FILTER__ + +/* The following classes are declared in this header: */ + +class CBaseMediaFilter; // IMediaFilter support +class CBaseFilter; // IBaseFilter,IMediaFilter support +class CBasePin; // Abstract base class for IPin interface +class CEnumPins; // Enumerate input and output pins +class CEnumMediaTypes; // Enumerate the pin's preferred formats +class CBaseOutputPin; // Adds data provider member functions +class CBaseInputPin; // Implements IMemInputPin interface +class CMediaSample; // Basic transport unit for IMemInputPin +class CBaseAllocator; // General list guff for most allocators +class CMemAllocator; // Implements memory buffer allocation + + +//===================================================================== +//===================================================================== +// +// QueryFilterInfo and QueryPinInfo AddRef the interface pointers +// they return. You can use the macro below to release the interface. +// +//===================================================================== +//===================================================================== + +#define QueryFilterInfoReleaseGraph(fi) if ((fi).pGraph) (fi).pGraph->Release(); + +#define QueryPinInfoReleaseFilter(pi) if ((pi).pFilter) (pi).pFilter->Release(); + +//===================================================================== +//===================================================================== +// Defines CBaseMediaFilter +// +// Abstract base class implementing IMediaFilter. +// +// Typically you will derive your filter from CBaseFilter rather than +// this, unless you are implementing an object such as a plug-in +// distributor that needs to support IMediaFilter but not IBaseFilter. +// +// Note that IMediaFilter is derived from IPersist to allow query of +// class id. +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBaseMediaFilter : public CUnknown, + public IMediaFilter +{ + +protected: + + FILTER_STATE m_State; // current state: running, paused + IReferenceClock *m_pClock; // this filter's reference clock + // note: all filters in a filter graph use the same clock + + // offset from stream time to reference time + CRefTime m_tStart; + + CLSID m_clsid; // This filters clsid + // used for serialization + CCritSec *m_pLock; // Object we use for locking + +public: + + CBaseMediaFilter( + const TCHAR *pName, + LPUNKNOWN pUnk, + CCritSec *pLock, + REFCLSID clsid); + + virtual ~CBaseMediaFilter(); + + DECLARE_IUNKNOWN + + // override this to say what interfaces we support where + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv); + + // + // --- IPersist method --- + // + + STDMETHODIMP GetClassID(CLSID *pClsID); + + // --- IMediaFilter methods --- + + STDMETHODIMP GetState(DWORD dwMSecs, FILTER_STATE *State); + + STDMETHODIMP SetSyncSource(IReferenceClock *pClock); + + STDMETHODIMP GetSyncSource(IReferenceClock **pClock); + + // default implementation of Stop and Pause just record the + // state. Override to activate or de-activate your filter. + // Note that Run when called from Stopped state will call Pause + // to ensure activation, so if you are a source or transform + // you will probably not need to override Run. + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + + + // the start parameter is the difference to be added to the + // sample's stream time to get the reference time for + // its presentation + STDMETHODIMP Run(REFERENCE_TIME tStart); + + // --- helper methods --- + + // return the current stream time - ie find out what + // stream time should be appearing now + virtual HRESULT StreamTime(CRefTime& rtStream); + + // Is the filter currently active? (running or paused) + BOOL IsActive() { + CAutoLock cObjectLock(m_pLock); + return ((m_State == State_Paused) || (m_State == State_Running)); + }; +}; + +//===================================================================== +//===================================================================== +// Defines CBaseFilter +// +// An abstract class providing basic IBaseFilter support for pin +// enumeration and filter information reading. +// +// We cannot derive from CBaseMediaFilter since methods in IMediaFilter +// are also in IBaseFilter and would be ambiguous. Since much of the code +// assumes that they derive from a class that has m_State and other state +// directly available, we duplicate code from CBaseMediaFilter rather than +// having a member variable. +// +// Derive your filter from this, or from a derived object such as +// CTransformFilter. +//===================================================================== +//===================================================================== + + +class AM_NOVTABLE CBaseFilter : public CUnknown, // Handles an IUnknown + public IBaseFilter, // The Filter Interface + public IAMovieSetup // For un/registration +{ + +friend class CBasePin; + +protected: + FILTER_STATE m_State; // current state: running, paused + IReferenceClock *m_pClock; // this graph's ref clock + CRefTime m_tStart; // offset from stream time to reference time + CLSID m_clsid; // This filters clsid + // used for serialization + CCritSec *m_pLock; // Object we use for locking + + WCHAR *m_pName; // Full filter name + IFilterGraph *m_pGraph; // Graph we belong to + IMediaEventSink *m_pSink; // Called with notify events + LONG m_PinVersion; // Current pin version + +public: + + CBaseFilter( + const TCHAR *pName, // Object description + LPUNKNOWN pUnk, // IUnknown of delegating object + CCritSec *pLock, // Object who maintains lock + REFCLSID clsid); // The clsid to be used to serialize this filter + + CBaseFilter( + TCHAR *pName, // Object description + LPUNKNOWN pUnk, // IUnknown of delegating object + CCritSec *pLock, // Object who maintains lock + REFCLSID clsid, // The clsid to be used to serialize this filter + HRESULT *phr); // General OLE return code +#ifdef UNICODE + CBaseFilter( + const CHAR *pName, // Object description + LPUNKNOWN pUnk, // IUnknown of delegating object + CCritSec *pLock, // Object who maintains lock + REFCLSID clsid); // The clsid to be used to serialize this filter + + CBaseFilter( + CHAR *pName, // Object description + LPUNKNOWN pUnk, // IUnknown of delegating object + CCritSec *pLock, // Object who maintains lock + REFCLSID clsid, // The clsid to be used to serialize this filter + HRESULT *phr); // General OLE return code +#endif + ~CBaseFilter(); + + DECLARE_IUNKNOWN + + // override this to say what interfaces we support where + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv); +#ifdef DEBUG + STDMETHODIMP_(ULONG) NonDelegatingRelease(); +#endif + + // + // --- IPersist method --- + // + + STDMETHODIMP GetClassID(CLSID *pClsID); + + // --- IMediaFilter methods --- + + STDMETHODIMP GetState(DWORD dwMSecs, FILTER_STATE *State); + + STDMETHODIMP SetSyncSource(IReferenceClock *pClock); + + STDMETHODIMP GetSyncSource(IReferenceClock **pClock); + + + // override Stop and Pause so we can activate the pins. + // Note that Run will call Pause first if activation needed. + // Override these if you want to activate your filter rather than + // your pins. + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + + // the start parameter is the difference to be added to the + // sample's stream time to get the reference time for + // its presentation + STDMETHODIMP Run(REFERENCE_TIME tStart); + + // --- helper methods --- + + // return the current stream time - ie find out what + // stream time should be appearing now + virtual HRESULT StreamTime(CRefTime& rtStream); + + // Is the filter currently active? + BOOL IsActive() { + CAutoLock cObjectLock(m_pLock); + return ((m_State == State_Paused) || (m_State == State_Running)); + }; + + // Is this filter stopped (without locking) + BOOL IsStopped() { + return (m_State == State_Stopped); + }; + + // + // --- IBaseFilter methods --- + // + + // pin enumerator + STDMETHODIMP EnumPins( + IEnumPins ** ppEnum); + + + // default behaviour of FindPin assumes pin ids are their names + STDMETHODIMP FindPin( + LPCWSTR Id, + IPin ** ppPin + ); + + STDMETHODIMP QueryFilterInfo( + FILTER_INFO * pInfo); + + STDMETHODIMP JoinFilterGraph( + IFilterGraph * pGraph, + LPCWSTR pName); + + // return a Vendor information string. Optional - may return E_NOTIMPL. + // memory returned should be freed using CoTaskMemFree + // default implementation returns E_NOTIMPL + STDMETHODIMP QueryVendorInfo( + LPWSTR* pVendorInfo + ); + + // --- helper methods --- + + // send an event notification to the filter graph if we know about it. + // returns S_OK if delivered, S_FALSE if the filter graph does not sink + // events, or an error otherwise. + HRESULT NotifyEvent( + long EventCode, + LONG_PTR EventParam1, + LONG_PTR EventParam2); + + // return the filter graph we belong to + IFilterGraph *GetFilterGraph() { + return m_pGraph; + } + + // Request reconnect + // pPin is the pin to reconnect + // pmt is the type to reconnect with - can be NULL + // Calls ReconnectEx on the filter graph + HRESULT ReconnectPin(IPin *pPin, AM_MEDIA_TYPE const *pmt); + + // find out the current pin version (used by enumerators) + virtual LONG GetPinVersion(); + void IncrementPinVersion(); + + // you need to supply these to access the pins from the enumerator + // and for default Stop and Pause/Run activation. + virtual int GetPinCount() PURE; + virtual CBasePin *GetPin(int n) PURE; + + // --- IAMovieSetup methods --- + + STDMETHODIMP Register(); // ask filter to register itself + STDMETHODIMP Unregister(); // and unregister itself + + // --- setup helper methods --- + // (override to return filters setup data) + + virtual LPAMOVIESETUP_FILTER GetSetupData(){ return NULL; } + +}; + + +//===================================================================== +//===================================================================== +// Defines CBasePin +// +// Abstract class that supports the basics of IPin +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBasePin : public CUnknown, public IPin, public IQualityControl +{ + +protected: + + WCHAR * m_pName; // This pin's name + IPin *m_Connected; // Pin we have connected to + PIN_DIRECTION m_dir; // Direction of this pin + CCritSec *m_pLock; // Object we use for locking + bool m_bRunTimeError; // Run time error generated + bool m_bCanReconnectWhenActive; // OK to reconnect when active + bool m_bTryMyTypesFirst; // When connecting enumerate + // this pin's types first + CBaseFilter *m_pFilter; // Filter we were created by + IQualityControl *m_pQSink; // Target for Quality messages + LONG m_TypeVersion; // Holds current type version + CMediaType m_mt; // Media type of connection + + CRefTime m_tStart; // time from NewSegment call + CRefTime m_tStop; // time from NewSegment + double m_dRate; // rate from NewSegment + +#ifdef DEBUG + LONG m_cRef; // Ref count tracing +#endif + + // displays pin connection information + +#ifdef DEBUG + void DisplayPinInfo(IPin *pReceivePin); + void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt); +#else + void DisplayPinInfo(IPin *pReceivePin) {}; + void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt) {}; +#endif + + // used to agree a media type for a pin connection + + // given a specific media type, attempt a connection (includes + // checking that the type is acceptable to this pin) + HRESULT + AttemptConnection( + IPin* pReceivePin, // connect to this pin + const CMediaType* pmt // using this type + ); + + // try all the media types in this enumerator - for each that + // we accept, try to connect using ReceiveConnection. + HRESULT TryMediaTypes( + IPin *pReceivePin, // connect to this pin + const CMediaType *pmt, // proposed type from Connect + IEnumMediaTypes *pEnum); // try this enumerator + + // establish a connection with a suitable mediatype. Needs to + // propose a media type if the pmt pointer is null or partially + // specified - use TryMediaTypes on both our and then the other pin's + // enumerator until we find one that works. + HRESULT AgreeMediaType( + IPin *pReceivePin, // connect to this pin + const CMediaType *pmt); // proposed type from Connect + +public: + + CBasePin( + TCHAR *pObjectName, // Object description + CBaseFilter *pFilter, // Owning filter who knows about pins + CCritSec *pLock, // Object who implements the lock + HRESULT *phr, // General OLE return code + LPCWSTR pName, // Pin name for us + PIN_DIRECTION dir); // Either PINDIR_INPUT or PINDIR_OUTPUT +#ifdef UNICODE + CBasePin( + CHAR *pObjectName, // Object description + CBaseFilter *pFilter, // Owning filter who knows about pins + CCritSec *pLock, // Object who implements the lock + HRESULT *phr, // General OLE return code + LPCWSTR pName, // Pin name for us + PIN_DIRECTION dir); // Either PINDIR_INPUT or PINDIR_OUTPUT +#endif + virtual ~CBasePin(); + + DECLARE_IUNKNOWN + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv); + STDMETHODIMP_(ULONG) NonDelegatingRelease(); + STDMETHODIMP_(ULONG) NonDelegatingAddRef(); + + // --- IPin methods --- + + // take lead role in establishing a connection. Media type pointer + // may be null, or may point to partially-specified mediatype + // (subtype or format type may be GUID_NULL). + STDMETHODIMP Connect( + IPin * pReceivePin, + const AM_MEDIA_TYPE *pmt // optional media type + ); + + // (passive) accept a connection from another pin + STDMETHODIMP ReceiveConnection( + IPin * pConnector, // this is the initiating connecting pin + const AM_MEDIA_TYPE *pmt // this is the media type we will exchange + ); + + STDMETHODIMP Disconnect(); + + STDMETHODIMP ConnectedTo(IPin **pPin); + + STDMETHODIMP ConnectionMediaType(AM_MEDIA_TYPE *pmt); + + STDMETHODIMP QueryPinInfo( + PIN_INFO * pInfo + ); + + STDMETHODIMP QueryDirection( + PIN_DIRECTION * pPinDir + ); + + STDMETHODIMP QueryId( + LPWSTR * Id + ); + + // does the pin support this media type + STDMETHODIMP QueryAccept( + const AM_MEDIA_TYPE *pmt + ); + + // return an enumerator for this pins preferred media types + STDMETHODIMP EnumMediaTypes( + IEnumMediaTypes **ppEnum + ); + + // return an array of IPin* - the pins that this pin internally connects to + // All pins put in the array must be AddReffed (but no others) + // Errors: "Can't say" - FAIL, not enough slots - return S_FALSE + // Default: return E_NOTIMPL + // The filter graph will interpret NOT_IMPL as any input pin connects to + // all visible output pins and vice versa. + // apPin can be NULL if nPin==0 (not otherwise). + STDMETHODIMP QueryInternalConnections( + IPin* *apPin, // array of IPin* + ULONG *nPin // on input, the number of slots + // on output the number of pins + ) { return E_NOTIMPL; } + + // Called when no more data will be sent + STDMETHODIMP EndOfStream(void); + + // Begin/EndFlush still PURE + + // NewSegment notifies of the start/stop/rate applying to the data + // about to be received. Default implementation records data and + // returns S_OK. + // Override this to pass downstream. + STDMETHODIMP NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + + //================================================================================ + // IQualityControl methods + //================================================================================ + + STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); + + STDMETHODIMP SetSink(IQualityControl * piqc); + + // --- helper methods --- + + // Returns true if the pin is connected. false otherwise. + BOOL IsConnected(void) {return (m_Connected != NULL); }; + // Return the pin this is connected to (if any) + IPin * GetConnected() { return m_Connected; }; + + // Check if our filter is currently stopped + BOOL IsStopped() { + return (m_pFilter->m_State == State_Stopped); + }; + + // find out the current type version (used by enumerators) + virtual LONG GetMediaTypeVersion(); + void IncrementTypeVersion(); + + // switch the pin to active (paused or running) mode + // not an error to call this if already active + virtual HRESULT Active(void); + + // switch the pin to inactive state - may already be inactive + virtual HRESULT Inactive(void); + + // Notify of Run() from filter + virtual HRESULT Run(REFERENCE_TIME tStart); + + // check if the pin can support this specific proposed type and format + virtual HRESULT CheckMediaType(const CMediaType *) PURE; + + // set the connection to use this format (previously agreed) + virtual HRESULT SetMediaType(const CMediaType *); + + // check that the connection is ok before verifying it + // can be overridden eg to check what interfaces will be supported. + virtual HRESULT CheckConnect(IPin *); + + // Set and release resources required for a connection + virtual HRESULT BreakConnect(); + virtual HRESULT CompleteConnect(IPin *pReceivePin); + + // returns the preferred formats for a pin + virtual HRESULT GetMediaType(int iPosition,CMediaType *pMediaType); + + // access to NewSegment values + REFERENCE_TIME CurrentStopTime() { + return m_tStop; + } + REFERENCE_TIME CurrentStartTime() { + return m_tStart; + } + double CurrentRate() { + return m_dRate; + } + + // Access name + LPWSTR Name() { return m_pName; }; + + // Can reconnectwhen active? + void SetReconnectWhenActive(bool bCanReconnect) + { + m_bCanReconnectWhenActive = bCanReconnect; + } + + bool CanReconnectWhenActive() + { + return m_bCanReconnectWhenActive; + } + +protected: + STDMETHODIMP DisconnectInternal(); +}; + + +//===================================================================== +//===================================================================== +// Defines CEnumPins +// +// Pin enumerator class that works by calling CBaseFilter. This interface +// is provided by CBaseFilter::EnumPins and calls GetPinCount() and +// GetPin() to enumerate existing pins. Needs to be a separate object so +// that it can be cloned (creating an existing object at the same +// position in the enumeration) +// +//===================================================================== +//===================================================================== + +class CEnumPins : public IEnumPins // The interface we support +{ + int m_Position; // Current ordinal position + int m_PinCount; // Number of pins available + CBaseFilter *m_pFilter; // The filter who owns us + LONG m_Version; // Pin version information + LONG m_cRef; + + typedef CGenericList CPinList; + + CPinList m_PinCache; // These pointers have not been AddRef'ed and + // so they should not be dereferenced. They are + // merely kept to ID which pins have been enumerated. + +#ifdef DEBUG + DWORD m_dwCookie; +#endif + + /* If while we are retrieving a pin for example from the filter an error + occurs we assume that our internal state is stale with respect to the + filter (someone may have deleted all the pins). We can check before + starting whether or not the operation is likely to fail by asking the + filter what it's current version number is. If the filter has not + overriden the GetPinVersion method then this will always match */ + + BOOL AreWeOutOfSync() { + return (m_pFilter->GetPinVersion() == m_Version ? FALSE : TRUE); + }; + + /* This method performs the same operations as Reset, except is does not clear + the cache of pins already enumerated. */ + + STDMETHODIMP Refresh(); + +public: + + CEnumPins( + CBaseFilter *pFilter, + CEnumPins *pEnumPins); + + virtual ~CEnumPins(); + + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, void **ppv); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IEnumPins + STDMETHODIMP Next( + ULONG cPins, // place this many pins... + IPin ** ppPins, // ...in this array of IPin* + ULONG * pcFetched // actual count passed returned here + ); + + STDMETHODIMP Skip(ULONG cPins); + STDMETHODIMP Reset(); + STDMETHODIMP Clone(IEnumPins **ppEnum); + + +}; + + +//===================================================================== +//===================================================================== +// Defines CEnumMediaTypes +// +// Enumerates the preferred formats for input and output pins +//===================================================================== +//===================================================================== + +class CEnumMediaTypes : public IEnumMediaTypes // The interface we support +{ + int m_Position; // Current ordinal position + CBasePin *m_pPin; // The pin who owns us + LONG m_Version; // Media type version value + LONG m_cRef; +#ifdef DEBUG + DWORD m_dwCookie; +#endif + + /* The media types a filter supports can be quite dynamic so we add to + the general IEnumXXXX interface the ability to be signaled when they + change via an event handle the connected filter supplies. Until the + Reset method is called after the state changes all further calls to + the enumerator (except Reset) will return E_UNEXPECTED error code */ + + BOOL AreWeOutOfSync() { + return (m_pPin->GetMediaTypeVersion() == m_Version ? FALSE : TRUE); + }; + +public: + + CEnumMediaTypes( + CBasePin *pPin, + CEnumMediaTypes *pEnumMediaTypes); + + virtual ~CEnumMediaTypes(); + + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, void **ppv); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IEnumMediaTypes + STDMETHODIMP Next( + ULONG cMediaTypes, // place this many pins... + AM_MEDIA_TYPE ** ppMediaTypes, // ...in this array + ULONG * pcFetched // actual count passed + ); + + STDMETHODIMP Skip(ULONG cMediaTypes); + STDMETHODIMP Reset(); + STDMETHODIMP Clone(IEnumMediaTypes **ppEnum); +}; + + + + +//===================================================================== +//===================================================================== +// Defines CBaseOutputPin +// +// class derived from CBasePin that can pass buffers to a connected pin +// that supports IMemInputPin. Supports IPin. +// +// Derive your output pin from this. +// +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBaseOutputPin : public CBasePin +{ + +protected: + + IMemAllocator *m_pAllocator; + IMemInputPin *m_pInputPin; // interface on the downstreaminput pin + // set up in CheckConnect when we connect. + +public: + + CBaseOutputPin( + TCHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName); +#ifdef UNICODE + CBaseOutputPin( + CHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName); +#endif + // override CompleteConnect() so we can negotiate an allocator + virtual HRESULT CompleteConnect(IPin *pReceivePin); + + // negotiate the allocator and its buffer size/count and other properties + // Calls DecideBufferSize to set properties + virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc); + + // override this to set the buffer size and count. Return an error + // if the size/count is not to your liking. + // The allocator properties passed in are those requested by the + // input pin - use eg the alignment and prefix members if you have + // no preference on these. + virtual HRESULT DecideBufferSize( + IMemAllocator * pAlloc, + ALLOCATOR_PROPERTIES * ppropInputRequest + ) PURE; + + // returns an empty sample buffer from the allocator + virtual HRESULT GetDeliveryBuffer(IMediaSample ** ppSample, + REFERENCE_TIME * pStartTime, + REFERENCE_TIME * pEndTime, + DWORD dwFlags); + + // deliver a filled-in sample to the connected input pin + // note - you need to release it after calling this. The receiving + // pin will addref the sample if it needs to hold it beyond the + // call. + virtual HRESULT Deliver(IMediaSample *); + + // override this to control the connection + virtual HRESULT InitAllocator(IMemAllocator **ppAlloc); + HRESULT CheckConnect(IPin *pPin); + HRESULT BreakConnect(); + + // override to call Commit and Decommit + HRESULT Active(void); + HRESULT Inactive(void); + + // we have a default handling of EndOfStream which is to return + // an error, since this should be called on input pins only + STDMETHODIMP EndOfStream(void); + + // called from elsewhere in our filter to pass EOS downstream to + // our connected input pin + virtual HRESULT DeliverEndOfStream(void); + + // same for Begin/EndFlush - we handle Begin/EndFlush since it + // is an error on an output pin, and we have Deliver methods to + // call the methods on the connected pin + STDMETHODIMP BeginFlush(void); + STDMETHODIMP EndFlush(void); + virtual HRESULT DeliverBeginFlush(void); + virtual HRESULT DeliverEndFlush(void); + + // deliver NewSegment to connected pin - you will need to + // override this if you queue any data in your output pin. + virtual HRESULT DeliverNewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + + //================================================================================ + // IQualityControl methods + //================================================================================ + + // All inherited from CBasePin and not overridden here. + // STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); + // STDMETHODIMP SetSink(IQualityControl * piqc); +}; + + +//===================================================================== +//===================================================================== +// Defines CBaseInputPin +// +// derive your standard input pin from this. +// you need to supply GetMediaType and CheckConnect etc (see CBasePin), +// and you need to supply Receive to do something more useful. +// +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBaseInputPin : public CBasePin, + public IMemInputPin +{ + +protected: + + IMemAllocator *m_pAllocator; // Default memory allocator + + // allocator is read-only, so received samples + // cannot be modified (probably only relevant to in-place + // transforms + BYTE m_bReadOnly; + + // in flushing state (between BeginFlush and EndFlush) + // if TRUE, all Receives are returned with S_FALSE + BYTE m_bFlushing; + + // Sample properties - initalized in Receive + AM_SAMPLE2_PROPERTIES m_SampleProps; + +public: + + CBaseInputPin( + TCHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName); +#ifdef UNICODE + CBaseInputPin( + CHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName); +#endif + virtual ~CBaseInputPin(); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + // return the allocator interface that this input pin + // would like the output pin to use + STDMETHODIMP GetAllocator(IMemAllocator ** ppAllocator); + + // tell the input pin which allocator the output pin is actually + // going to use. + STDMETHODIMP NotifyAllocator( + IMemAllocator * pAllocator, + BOOL bReadOnly); + + // do something with this media sample + STDMETHODIMP Receive(IMediaSample *pSample); + + // do something with these media samples + STDMETHODIMP ReceiveMultiple ( + IMediaSample **pSamples, + long nSamples, + long *nSamplesProcessed); + + // See if Receive() blocks + STDMETHODIMP ReceiveCanBlock(); + + // Default handling for BeginFlush - call at the beginning + // of your implementation (makes sure that all Receive calls + // fail). After calling this, you need to free any queued data + // and then call downstream. + STDMETHODIMP BeginFlush(void); + + // default handling for EndFlush - call at end of your implementation + // - before calling this, ensure that there is no queued data and no thread + // pushing any more without a further receive, then call downstream, + // then call this method to clear the m_bFlushing flag and re-enable + // receives + STDMETHODIMP EndFlush(void); + + // this method is optional (can return E_NOTIMPL). + // default implementation returns E_NOTIMPL. Override if you have + // specific alignment or prefix needs, but could use an upstream + // allocator + STDMETHODIMP GetAllocatorRequirements(ALLOCATOR_PROPERTIES*pProps); + + // Release the pin's allocator. + HRESULT BreakConnect(); + + // helper method to check the read-only flag + BOOL IsReadOnly() { + return m_bReadOnly; + }; + + // helper method to see if we are flushing + BOOL IsFlushing() { + return m_bFlushing; + }; + + // Override this for checking whether it's OK to process samples + // Also call this from EndOfStream. + virtual HRESULT CheckStreaming(); + + // Pass a Quality notification on to the appropriate sink + HRESULT PassNotify(Quality& q); + + + //================================================================================ + // IQualityControl methods (from CBasePin) + //================================================================================ + + STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); + + // no need to override: + // STDMETHODIMP SetSink(IQualityControl * piqc); + + + // switch the pin to inactive state - may already be inactive + virtual HRESULT Inactive(void); + + // Return sample properties pointer + AM_SAMPLE2_PROPERTIES * SampleProps() { + ASSERT(m_SampleProps.cbData != 0); + return &m_SampleProps; + } + +}; + +/////////////////////////////////////////////////////////////////////////// +// CDynamicOutputPin +// + +class CDynamicOutputPin : public CBaseOutputPin, + public IPinFlowControl +{ +public: +#ifdef UNICODE + CDynamicOutputPin( + CHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName); +#endif + + CDynamicOutputPin( + TCHAR *pObjectName, + CBaseFilter *pFilter, + CCritSec *pLock, + HRESULT *phr, + LPCWSTR pName); + + ~CDynamicOutputPin(); + + // IUnknown Methods + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + // IPin Methods + STDMETHODIMP Disconnect(void); + + // IPinFlowControl Methods + STDMETHODIMP Block(DWORD dwBlockFlags, HANDLE hEvent); + + // Set graph config info + void SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent); + + #ifdef DEBUG + virtual HRESULT Deliver(IMediaSample *pSample); + virtual HRESULT DeliverEndOfStream(void); + virtual HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + #endif // DEBUG + + HRESULT DeliverBeginFlush(void); + HRESULT DeliverEndFlush(void); + + HRESULT Inactive(void); + HRESULT Active(void); + virtual HRESULT CompleteConnect(IPin *pReceivePin); + + virtual HRESULT StartUsingOutputPin(void); + virtual void StopUsingOutputPin(void); + virtual bool StreamingThreadUsingOutputPin(void); + + HRESULT ChangeOutputFormat + ( + const AM_MEDIA_TYPE *pmt, + REFERENCE_TIME tSegmentStart, + REFERENCE_TIME tSegmentStop, + double dSegmentRate + ); + HRESULT ChangeMediaType(const CMediaType *pmt); + HRESULT DynamicReconnect(const CMediaType *pmt); + +protected: + HRESULT SynchronousBlockOutputPin(void); + HRESULT AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent); + HRESULT UnblockOutputPin(void); + + void BlockOutputPin(void); + void ResetBlockState(void); + + static HRESULT WaitEvent(HANDLE hEvent); + + enum BLOCK_STATE + { + NOT_BLOCKED, + PENDING, + BLOCKED + }; + + // This lock should be held when the following class members are + // being used: m_hNotifyCallerPinBlockedEvent, m_BlockState, + // m_dwBlockCallerThreadID and m_dwNumOutstandingOutputPinUsers. + CCritSec m_BlockStateLock; + + // This event should be signaled when the output pin is + // not blocked. This is a manual reset event. For more + // information on events, see the documentation for + // CreateEvent() in the Windows SDK. + HANDLE m_hUnblockOutputPinEvent; + + // This event will be signaled when block operation succeedes or + // when the user cancels the block operation. The block operation + // can be canceled by calling IPinFlowControl2::Block( 0, NULL ) + // while the block operation is pending. + HANDLE m_hNotifyCallerPinBlockedEvent; + + // The state of the current block operation. + BLOCK_STATE m_BlockState; + + // The ID of the thread which last called IPinFlowControl::Block(). + // For more information on thread IDs, see the documentation for + // GetCurrentThreadID() in the Windows SDK. + DWORD m_dwBlockCallerThreadID; + + // The number of times StartUsingOutputPin() has been sucessfully + // called and a corresponding call to StopUsingOutputPin() has not + // been made. When this variable is greater than 0, the streaming + // thread is calling IPin::NewSegment(), IPin::EndOfStream(), + // IMemInputPin::Receive() or IMemInputPin::ReceiveMultiple(). The + // streaming thread could also be calling: DynamicReconnect(), + // ChangeMediaType() or ChangeOutputFormat(). The output pin cannot + // be blocked while the output pin is being used. + DWORD m_dwNumOutstandingOutputPinUsers; + + // This event should be set when the IMediaFilter::Stop() is called. + // This is a manual reset event. It is also set when the output pin + // delivers a flush to the connected input pin. + HANDLE m_hStopEvent; + IGraphConfig* m_pGraphConfig; + + // TRUE if the output pin's allocator's samples are read only. + // Otherwise FALSE. For more information, see the documentation + // for IMemInputPin::NotifyAllocator(). + BOOL m_bPinUsesReadOnlyAllocator; + +private: + HRESULT Initialize(void); + HRESULT ChangeMediaTypeHelper(const CMediaType *pmt); + + #ifdef DEBUG + void AssertValid(void); + #endif // DEBUG +}; + +class CAutoUsingOutputPin +{ +public: + CAutoUsingOutputPin( CDynamicOutputPin* pOutputPin, HRESULT* phr ); + ~CAutoUsingOutputPin(); + +private: + CDynamicOutputPin* m_pOutputPin; +}; + +inline CAutoUsingOutputPin::CAutoUsingOutputPin( CDynamicOutputPin* pOutputPin, HRESULT* phr ) : + m_pOutputPin(NULL) +{ + // The caller should always pass in valid pointers. + ASSERT( NULL != pOutputPin ); + ASSERT( NULL != phr ); + + // Make sure the user initialized phr. + ASSERT( S_OK == *phr ); + + HRESULT hr = pOutputPin->StartUsingOutputPin(); + if( FAILED( hr ) ) + { + *phr = hr; + return; + } + + m_pOutputPin = pOutputPin; +} + +inline CAutoUsingOutputPin::~CAutoUsingOutputPin() +{ + if( NULL != m_pOutputPin ) + { + m_pOutputPin->StopUsingOutputPin(); + } +} + +#ifdef DEBUG + +inline HRESULT CDynamicOutputPin::Deliver(IMediaSample *pSample) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + return CBaseOutputPin::Deliver(pSample); +} + +inline HRESULT CDynamicOutputPin::DeliverEndOfStream(void) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT( StreamingThreadUsingOutputPin() ); + + return CBaseOutputPin::DeliverEndOfStream(); +} + +inline HRESULT CDynamicOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + return CBaseOutputPin::DeliverNewSegment(tStart, tStop, dRate); +} + +#endif // DEBUG + +//===================================================================== +//===================================================================== +// Memory allocators +// +// the shared memory transport between pins requires the input pin +// to provide a memory allocator that can provide sample objects. A +// sample object supports the IMediaSample interface. +// +// CBaseAllocator handles the management of free and busy samples. It +// allocates CMediaSample objects. CBaseAllocator is an abstract class: +// in particular it has no method of initializing the list of free +// samples. CMemAllocator is derived from CBaseAllocator and initializes +// the list of samples using memory from the standard IMalloc interface. +// +// If you want your buffers to live in some special area of memory, +// derive your allocator object from CBaseAllocator. If you derive your +// IMemInputPin interface object from CBaseMemInputPin, you will get +// CMemAllocator-based allocation etc for free and will just need to +// supply the Receive handling, and media type / format negotiation. +//===================================================================== +//===================================================================== + + +//===================================================================== +//===================================================================== +// Defines CMediaSample +// +// an object of this class supports IMediaSample and represents a buffer +// for media data with some associated properties. Releasing it returns +// it to a freelist managed by a CBaseAllocator derived object. +//===================================================================== +//===================================================================== + +class CMediaSample : public IMediaSample2 // The interface we support +{ + +protected: + + friend class CBaseAllocator; + + /* Values for dwFlags - these are used for backward compatiblity + only now - use AM_SAMPLE_xxx + */ + enum { Sample_SyncPoint = 0x01, /* Is this a sync point */ + Sample_Preroll = 0x02, /* Is this a preroll sample */ + Sample_Discontinuity = 0x04, /* Set if start of new segment */ + Sample_TypeChanged = 0x08, /* Has the type changed */ + Sample_TimeValid = 0x10, /* Set if time is valid */ + Sample_MediaTimeValid = 0x20, /* Is the media time valid */ + Sample_TimeDiscontinuity = 0x40, /* Time discontinuity */ + Sample_StopValid = 0x100, /* Stop time valid */ + Sample_ValidFlags = 0x1FF + }; + + /* Properties, the media sample class can be a container for a format + change in which case we take a copy of a type through the SetMediaType + interface function and then return it when GetMediaType is called. As + we do no internal processing on it we leave it as a pointer */ + + DWORD m_dwFlags; /* Flags for this sample */ + /* Type specific flags are packed + into the top word + */ + DWORD m_dwTypeSpecificFlags; /* Media type specific flags */ + LPBYTE m_pBuffer; /* Pointer to the complete buffer */ + LONG m_lActual; /* Length of data in this sample */ + LONG m_cbBuffer; /* Size of the buffer */ + CBaseAllocator *m_pAllocator; /* The allocator who owns us */ + CMediaSample *m_pNext; /* Chaining in free list */ + REFERENCE_TIME m_Start; /* Start sample time */ + REFERENCE_TIME m_End; /* End sample time */ + LONGLONG m_MediaStart; /* Real media start position */ + LONG m_MediaEnd; /* A difference to get the end */ + AM_MEDIA_TYPE *m_pMediaType; /* Media type change data */ + DWORD m_dwStreamId; /* Stream id */ +public: + LONG m_cRef; /* Reference count */ + + +public: + + CMediaSample( + TCHAR *pName, + CBaseAllocator *pAllocator, + HRESULT *phr, + LPBYTE pBuffer = NULL, + LONG length = 0); +#ifdef UNICODE + CMediaSample( + CHAR *pName, + CBaseAllocator *pAllocator, + HRESULT *phr, + LPBYTE pBuffer = NULL, + LONG length = 0); +#endif + + virtual ~CMediaSample(); + + /* Note the media sample does not delegate to its owner */ + + STDMETHODIMP QueryInterface(REFIID riid, void **ppv); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // set the buffer pointer and length. Used by allocators that + // want variable sized pointers or pointers into already-read data. + // This is only available through a CMediaSample* not an IMediaSample* + // and so cannot be changed by clients. + HRESULT SetPointer(BYTE * ptr, LONG cBytes); + + // Get me a read/write pointer to this buffer's memory. + STDMETHODIMP GetPointer(BYTE ** ppBuffer); + + STDMETHODIMP_(LONG) GetSize(void); + + // get the stream time at which this sample should start and finish. + STDMETHODIMP GetTime( + REFERENCE_TIME * pTimeStart, // put time here + REFERENCE_TIME * pTimeEnd + ); + + // Set the stream time at which this sample should start and finish. + STDMETHODIMP SetTime( + REFERENCE_TIME * pTimeStart, // put time here + REFERENCE_TIME * pTimeEnd + ); + STDMETHODIMP IsSyncPoint(void); + STDMETHODIMP SetSyncPoint(BOOL bIsSyncPoint); + STDMETHODIMP IsPreroll(void); + STDMETHODIMP SetPreroll(BOOL bIsPreroll); + + STDMETHODIMP_(LONG) GetActualDataLength(void); + STDMETHODIMP SetActualDataLength(LONG lActual); + + // these allow for limited format changes in band + + STDMETHODIMP GetMediaType(AM_MEDIA_TYPE **ppMediaType); + STDMETHODIMP SetMediaType(AM_MEDIA_TYPE *pMediaType); + + // returns S_OK if there is a discontinuity in the data (this same is + // not a continuation of the previous stream of data + // - there has been a seek). + STDMETHODIMP IsDiscontinuity(void); + // set the discontinuity property - TRUE if this sample is not a + // continuation, but a new sample after a seek. + STDMETHODIMP SetDiscontinuity(BOOL bDiscontinuity); + + // get the media times for this sample + STDMETHODIMP GetMediaTime( + LONGLONG * pTimeStart, + LONGLONG * pTimeEnd + ); + + // Set the media times for this sample + STDMETHODIMP SetMediaTime( + LONGLONG * pTimeStart, + LONGLONG * pTimeEnd + ); + + // Set and get properties (IMediaSample2) + STDMETHODIMP GetProperties( + DWORD cbProperties, + BYTE * pbProperties + ); + + STDMETHODIMP SetProperties( + DWORD cbProperties, + const BYTE * pbProperties + ); +}; + + +//===================================================================== +//===================================================================== +// Defines CBaseAllocator +// +// Abstract base class that manages a list of media samples +// +// This class provides support for getting buffers from the free list, +// including handling of commit and (asynchronous) decommit. +// +// Derive from this class and override the Alloc and Free functions to +// allocate your CMediaSample (or derived) objects and add them to the +// free list, preparing them as necessary. +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBaseAllocator : public CUnknown,// A non delegating IUnknown + public IMemAllocatorCallbackTemp, // The interface we support + public CCritSec // Provides object locking +{ + class CSampleList; + friend class CSampleList; + + /* Trick to get at protected member in CMediaSample */ + static CMediaSample * &NextSample(CMediaSample *pSample) + { + return pSample->m_pNext; + }; + + /* Mini list class for the free list */ + class CSampleList + { + public: + CSampleList() : m_List(NULL), m_nOnList(0) {}; +#ifdef DEBUG + ~CSampleList() + { + ASSERT(m_nOnList == 0); + }; +#endif + CMediaSample *Head() const { return m_List; }; + CMediaSample *Next(CMediaSample *pSample) const { return CBaseAllocator::NextSample(pSample); }; + int GetCount() const { return m_nOnList; }; + void Add(CMediaSample *pSample) + { + ASSERT(pSample != NULL); + CBaseAllocator::NextSample(pSample) = m_List; + m_List = pSample; + m_nOnList++; + }; + CMediaSample *RemoveHead() + { + CMediaSample *pSample = m_List; + if (pSample != NULL) { + m_List = CBaseAllocator::NextSample(m_List); + m_nOnList--; + } + return pSample; + }; + void Remove(CMediaSample *pSample); + + public: + CMediaSample *m_List; + int m_nOnList; + }; +protected: + + CSampleList m_lFree; // Free list + + /* Note to overriders of CBaseAllocator. + + We use a lazy signalling mechanism for waiting for samples. + This means we don't call the OS if no waits occur. + + In order to implement this: + + 1. When a new sample is added to m_lFree call NotifySample() which + calls ReleaseSemaphore on m_hSem with a count of m_lWaiting and + sets m_lWaiting to 0. + This must all be done holding the allocator's critical section. + + 2. When waiting for a sample call SetWaiting() which increments + m_lWaiting BEFORE leaving the allocator's critical section. + + 3. Actually wait by calling WaitForSingleObject(m_hSem, INFINITE) + having left the allocator's critical section. The effect of + this is to remove 1 from the semaphore's count. You MUST call + this once having incremented m_lWaiting. + + The following are then true when the critical section is not held : + (let nWaiting = number about to wait or waiting) + + (1) if (m_lFree.GetCount() != 0) then (m_lWaiting == 0) + (2) m_lWaiting + Semaphore count == nWaiting + + We would deadlock if + nWaiting != 0 && + m_lFree.GetCount() != 0 && + Semaphore count == 0 + + But from (1) if m_lFree.GetCount() != 0 then m_lWaiting == 0 so + from (2) Semaphore count == nWaiting (which is non-0) so the + deadlock can't happen. + */ + + HANDLE m_hSem; // For signalling + long m_lWaiting; // Waiting for a free element + long m_lCount; // how many buffers we have agreed to provide + long m_lAllocated; // how many buffers are currently allocated + long m_lSize; // agreed size of each buffer + long m_lAlignment; // agreed alignment + long m_lPrefix; // agreed prefix (preceeds GetPointer() value) + BOOL m_bChanged; // Have the buffer requirements changed + + // if true, we are decommitted and can't allocate memory + BOOL m_bCommitted; + // if true, the decommit has happened, but we haven't called Free yet + // as there are still outstanding buffers + BOOL m_bDecommitInProgress; + + // Notification interface + IMemAllocatorNotifyCallbackTemp *m_pNotify; + + BOOL m_fEnableReleaseCallback; + + // called to decommit the memory when the last buffer is freed + // pure virtual - need to override this + virtual void Free(void) PURE; + + // override to allocate the memory when commit called + virtual HRESULT Alloc(void); + +public: + + CBaseAllocator( + TCHAR *, LPUNKNOWN, HRESULT *, + BOOL bEvent = TRUE, BOOL fEnableReleaseCallback = FALSE); +#ifdef UNICODE + CBaseAllocator( + CHAR *, LPUNKNOWN, HRESULT *, + BOOL bEvent = TRUE, BOOL fEnableReleaseCallback = FALSE); +#endif + virtual ~CBaseAllocator(); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + STDMETHODIMP SetProperties( + ALLOCATOR_PROPERTIES* pRequest, + ALLOCATOR_PROPERTIES* pActual); + + // return the properties actually being used on this allocator + STDMETHODIMP GetProperties( + ALLOCATOR_PROPERTIES* pProps); + + // override Commit to allocate memory. We handle the GetBuffer + //state changes + STDMETHODIMP Commit(); + + // override this to handle the memory freeing. We handle any outstanding + // GetBuffer calls + STDMETHODIMP Decommit(); + + // get container for a sample. Blocking, synchronous call to get the + // next free buffer (as represented by an IMediaSample interface). + // on return, the time etc properties will be invalid, but the buffer + // pointer and size will be correct. The two time parameters are + // optional and either may be NULL, they may alternatively be set to + // the start and end times the sample will have attached to it + // bPrevFramesSkipped is not used (used only by the video renderer's + // allocator where it affects quality management in direct draw). + + STDMETHODIMP GetBuffer(IMediaSample **ppBuffer, + REFERENCE_TIME * pStartTime, + REFERENCE_TIME * pEndTime, + DWORD dwFlags); + + // final release of a CMediaSample will call this + STDMETHODIMP ReleaseBuffer(IMediaSample *pBuffer); + // obsolete:: virtual void PutOnFreeList(CMediaSample * pSample); + + STDMETHODIMP SetNotify(IMemAllocatorNotifyCallbackTemp *pNotify); + + STDMETHODIMP GetFreeCount(LONG *plBuffersFree); + + // Notify that a sample is available + void NotifySample(); + + // Notify that we're waiting for a sample + void SetWaiting() { m_lWaiting++; }; +}; + + +//===================================================================== +//===================================================================== +// Defines CMemAllocator +// +// this is an allocator based on CBaseAllocator that allocates sample +// buffers in main memory (from 'new'). You must call SetProperties +// before calling Commit. +// +// we don't free the memory when going into Decommit state. The simplest +// way to implement this without complicating CBaseAllocator is to +// have a Free() function, called to go into decommit state, that does +// nothing and a ReallyFree function called from our destructor that +// actually frees the memory. +//===================================================================== +//===================================================================== + +// Make me one from quartz.dll +STDAPI CreateMemoryAllocator(IMemAllocator **ppAllocator); + +class CMemAllocator : public CBaseAllocator +{ + +protected: + + LPBYTE m_pBuffer; // combined memory for all buffers + + // override to free the memory when decommit completes + // - we actually do nothing, and save the memory until deletion. + void Free(void); + + // called from the destructor (and from Alloc if changing size/count) to + // actually free up the memory + void ReallyFree(void); + + // overriden to allocate the memory when commit called + HRESULT Alloc(void); + +public: + /* This goes in the factory template table to create new instances */ + static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *); + + STDMETHODIMP SetProperties( + ALLOCATOR_PROPERTIES* pRequest, + ALLOCATOR_PROPERTIES* pActual); + + CMemAllocator(TCHAR *, LPUNKNOWN, HRESULT *); +#ifdef UNICODE + CMemAllocator(CHAR *, LPUNKNOWN, HRESULT *); +#endif + ~CMemAllocator(); +}; + +// helper used by IAMovieSetup implementation +STDAPI +AMovieSetupRegisterFilter( const AMOVIESETUP_FILTER * const psetupdata + , IFilterMapper * pIFM + , BOOL bRegister ); + + +/////////////////////////////////////////////////////////////////////////// +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ +/////////////////////////////////////////////////////////////////////////// + +#endif /* __FILTER__ */ + + + diff --git a/plugins/GSdx/baseclasses/amvideo.cpp b/plugins/GSdx/baseclasses/amvideo.cpp index 088a2e19e6..3a371f0338 100644 --- a/plugins/GSdx/baseclasses/amvideo.cpp +++ b/plugins/GSdx/baseclasses/amvideo.cpp @@ -1,275 +1,275 @@ -//------------------------------------------------------------------------------ -// File: AMVideo.cpp -// -// Desc: DirectShow base classes - implements helper functions for -// bitmap formats. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include - -// These are bit field masks for true colour devices - -const DWORD bits555[] = {0x007C00,0x0003E0,0x00001F}; -const DWORD bits565[] = {0x00F800,0x0007E0,0x00001F}; -const DWORD bits888[] = {0xFF0000,0x00FF00,0x0000FF}; - -// This maps bitmap subtypes into a bits per pixel value and also a -// name. unicode and ansi versions are stored because we have to -// return a pointer to a static string. -const struct { - const GUID *pSubtype; - WORD BitCount; - CHAR *pName; - WCHAR *wszName; -} BitCountMap[] = { &MEDIASUBTYPE_RGB1, 1, "RGB Monochrome", L"RGB Monochrome", - &MEDIASUBTYPE_RGB4, 4, "RGB VGA", L"RGB VGA", - &MEDIASUBTYPE_RGB8, 8, "RGB 8", L"RGB 8", - &MEDIASUBTYPE_RGB565, 16, "RGB 565 (16 bit)", L"RGB 565 (16 bit)", - &MEDIASUBTYPE_RGB555, 16, "RGB 555 (16 bit)", L"RGB 555 (16 bit)", - &MEDIASUBTYPE_RGB24, 24, "RGB 24", L"RGB 24", - &MEDIASUBTYPE_RGB32, 32, "RGB 32", L"RGB 32", - &MEDIASUBTYPE_ARGB32, 32, "ARGB 32", L"ARGB 32", - &MEDIASUBTYPE_Overlay, 0, "Overlay", L"Overlay", - &GUID_NULL, 0, "UNKNOWN", L"UNKNOWN" -}; - -// Return the size of the bitmap as defined by this header - -STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader) -{ - return DIBSIZE(*pHeader); -} - - -// This is called if the header has a 16 bit colour depth and needs to work -// out the detailed type from the bit fields (either RGB 565 or RGB 555) - -STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader) -{ - BITMAPINFO *pbmInfo = (BITMAPINFO *) pbmiHeader; - ASSERT(pbmiHeader->biBitCount == 16); - - // If its BI_RGB then it's RGB 555 by default - - if (pbmiHeader->biCompression == BI_RGB) { - return MEDIASUBTYPE_RGB555; - } - - // Compare the bit fields with RGB 555 - - DWORD *pMask = (DWORD *) pbmInfo->bmiColors; - if (pMask[0] == bits555[0]) { - if (pMask[1] == bits555[1]) { - if (pMask[2] == bits555[2]) { - return MEDIASUBTYPE_RGB555; - } - } - } - - // Compare the bit fields with RGB 565 - - pMask = (DWORD *) pbmInfo->bmiColors; - if (pMask[0] == bits565[0]) { - if (pMask[1] == bits565[1]) { - if (pMask[2] == bits565[2]) { - return MEDIASUBTYPE_RGB565; - } - } - } - return GUID_NULL; -} - - -// Given a BITMAPINFOHEADER structure this returns the GUID sub type that is -// used to describe it in format negotiations. For example a video codec fills -// in the format block with a VIDEOINFO structure, it also fills in the major -// type with MEDIATYPE_VIDEO and the subtype with a GUID that matches the bit -// count, for example if it is an eight bit image then MEDIASUBTYPE_RGB8 - -STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader) -{ - ASSERT(pbmiHeader); - - // If it's not RGB then create a GUID from the compression type - - if (pbmiHeader->biCompression != BI_RGB) { - if (pbmiHeader->biCompression != BI_BITFIELDS) { - FOURCCMap FourCCMap(pbmiHeader->biCompression); - return (const GUID) FourCCMap; - } - } - - // Map the RGB DIB bit depth to a image GUID - - switch(pbmiHeader->biBitCount) { - case 1 : return MEDIASUBTYPE_RGB1; - case 4 : return MEDIASUBTYPE_RGB4; - case 8 : return MEDIASUBTYPE_RGB8; - case 16 : return GetTrueColorType(pbmiHeader); - case 24 : return MEDIASUBTYPE_RGB24; - case 32 : return MEDIASUBTYPE_RGB32; - } - return GUID_NULL; -} - - -// Given a video bitmap subtype we return the number of bits per pixel it uses -// We return a WORD bit count as thats what the BITMAPINFOHEADER uses. If the -// GUID subtype is not found in the table we return an invalid USHRT_MAX - -STDAPI_(WORD) GetBitCount(const GUID *pSubtype) -{ - ASSERT(pSubtype); - const GUID *pMediaSubtype; - INT iPosition = 0; - - // Scan the mapping list seeing if the source GUID matches any known - // bitmap subtypes, the list is terminated by a GUID_NULL entry - - while (TRUE) { - pMediaSubtype = BitCountMap[iPosition].pSubtype; - if (IsEqualGUID(*pMediaSubtype,GUID_NULL)) { - return USHRT_MAX; - } - if (IsEqualGUID(*pMediaSubtype,*pSubtype)) { - return BitCountMap[iPosition].BitCount; - } - iPosition++; - } -} - - -// Given a bitmap subtype we return a description name that can be used for -// debug purposes. In a retail build this function still returns the names -// If the subtype isn't found in the lookup table we return string UNKNOWN - -int LocateSubtype(const GUID *pSubtype) -{ - ASSERT(pSubtype); - const GUID *pMediaSubtype; - INT iPosition = 0; - - // Scan the mapping list seeing if the source GUID matches any known - // bitmap subtypes, the list is terminated by a GUID_NULL entry - - while (TRUE) { - pMediaSubtype = BitCountMap[iPosition].pSubtype; - if (IsEqualGUID(*pMediaSubtype,*pSubtype) || - IsEqualGUID(*pMediaSubtype,GUID_NULL) - ) - { - break; - } - - iPosition++; - } - - return iPosition; -} - - - -STDAPI_(WCHAR *) GetSubtypeNameW(const GUID *pSubtype) -{ - return BitCountMap[LocateSubtype(pSubtype)].wszName; -} - -STDAPI_(CHAR *) GetSubtypeNameA(const GUID *pSubtype) -{ - return BitCountMap[LocateSubtype(pSubtype)].pName; -} - -#ifndef GetSubtypeName -#error wxutil.h should have defined GetSubtypeName -#endif -#undef GetSubtypeName - -// this is here for people that linked to it directly; most people -// would use the header file that picks the A or W version. -STDAPI_(CHAR *) GetSubtypeName(const GUID *pSubtype) -{ - return GetSubtypeNameA(pSubtype); -} - - -// The mechanism for describing a bitmap format is with the BITMAPINFOHEADER -// This is really messy to deal with because it invariably has fields that -// follow it holding bit fields, palettes and the rest. This function gives -// the number of bytes required to hold a VIDEOINFO that represents it. This -// count includes the prefix information (like the rcSource rectangle) the -// BITMAPINFOHEADER field, and any other colour information on the end. -// -// WARNING If you want to copy a BITMAPINFOHEADER into a VIDEOINFO always make -// sure that you use the HEADER macro because the BITMAPINFOHEADER field isn't -// right at the start of the VIDEOINFO (there are a number of other fields), -// -// CopyMemory(HEADER(pVideoInfo),pbmi,sizeof(BITMAPINFOHEADER)); -// - -STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader) -{ - // Everyone has this to start with this - LONG Size = SIZE_PREHEADER + pHeader->biSize; - - ASSERT(pHeader->biSize >= sizeof(BITMAPINFOHEADER)); - - // Does this format use a palette, if the number of colours actually used - // is zero then it is set to the maximum that are allowed for that colour - // depth (an example is 256 for eight bits). Truecolour formats may also - // pass a palette with them in which case the used count is non zero - - // This would scare me. - ASSERT(pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed == 0); - - if (pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed) { - LONG Entries = (DWORD) 1 << pHeader->biBitCount; - if (pHeader->biClrUsed) { - Entries = pHeader->biClrUsed; - } - Size += Entries * sizeof(RGBQUAD); - } - - // Truecolour formats may have a BI_BITFIELDS specifier for compression - // type which means that room for three DWORDs should be allocated that - // specify where in each pixel the RGB colour components may be found - - if (pHeader->biCompression == BI_BITFIELDS) { - Size += SIZE_MASKS; - } - - // A BITMAPINFO for a palettised image may also contain a palette map that - // provides the information to map from a source palette to a destination - // palette during a BitBlt for example, because this information is only - // ever processed during drawing you don't normally store the palette map - // nor have any way of knowing if it is present in the data structure - - return Size; -} - - -// Returns TRUE if the VIDEOINFO contains a palette - -STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo) -{ - if (PALETTISED(pVideoInfo) == FALSE) { - if (pVideoInfo->bmiHeader.biClrUsed == 0) { - return FALSE; - } - } - return TRUE; -} - - -// Return a pointer to the first entry in a palette - -STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo) -{ - if (pVideoInfo->bmiHeader.biCompression == BI_BITFIELDS) { - return TRUECOLOR(pVideoInfo)->bmiColors; - } - return COLORS(pVideoInfo); -} +//------------------------------------------------------------------------------ +// File: AMVideo.cpp +// +// Desc: DirectShow base classes - implements helper functions for +// bitmap formats. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include + +// These are bit field masks for true colour devices + +const DWORD bits555[] = {0x007C00,0x0003E0,0x00001F}; +const DWORD bits565[] = {0x00F800,0x0007E0,0x00001F}; +const DWORD bits888[] = {0xFF0000,0x00FF00,0x0000FF}; + +// This maps bitmap subtypes into a bits per pixel value and also a +// name. unicode and ansi versions are stored because we have to +// return a pointer to a static string. +const struct { + const GUID *pSubtype; + WORD BitCount; + CHAR *pName; + WCHAR *wszName; +} BitCountMap[] = { &MEDIASUBTYPE_RGB1, 1, "RGB Monochrome", L"RGB Monochrome", + &MEDIASUBTYPE_RGB4, 4, "RGB VGA", L"RGB VGA", + &MEDIASUBTYPE_RGB8, 8, "RGB 8", L"RGB 8", + &MEDIASUBTYPE_RGB565, 16, "RGB 565 (16 bit)", L"RGB 565 (16 bit)", + &MEDIASUBTYPE_RGB555, 16, "RGB 555 (16 bit)", L"RGB 555 (16 bit)", + &MEDIASUBTYPE_RGB24, 24, "RGB 24", L"RGB 24", + &MEDIASUBTYPE_RGB32, 32, "RGB 32", L"RGB 32", + &MEDIASUBTYPE_ARGB32, 32, "ARGB 32", L"ARGB 32", + &MEDIASUBTYPE_Overlay, 0, "Overlay", L"Overlay", + &GUID_NULL, 0, "UNKNOWN", L"UNKNOWN" +}; + +// Return the size of the bitmap as defined by this header + +STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader) +{ + return DIBSIZE(*pHeader); +} + + +// This is called if the header has a 16 bit colour depth and needs to work +// out the detailed type from the bit fields (either RGB 565 or RGB 555) + +STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader) +{ + BITMAPINFO *pbmInfo = (BITMAPINFO *) pbmiHeader; + ASSERT(pbmiHeader->biBitCount == 16); + + // If its BI_RGB then it's RGB 555 by default + + if (pbmiHeader->biCompression == BI_RGB) { + return MEDIASUBTYPE_RGB555; + } + + // Compare the bit fields with RGB 555 + + DWORD *pMask = (DWORD *) pbmInfo->bmiColors; + if (pMask[0] == bits555[0]) { + if (pMask[1] == bits555[1]) { + if (pMask[2] == bits555[2]) { + return MEDIASUBTYPE_RGB555; + } + } + } + + // Compare the bit fields with RGB 565 + + pMask = (DWORD *) pbmInfo->bmiColors; + if (pMask[0] == bits565[0]) { + if (pMask[1] == bits565[1]) { + if (pMask[2] == bits565[2]) { + return MEDIASUBTYPE_RGB565; + } + } + } + return GUID_NULL; +} + + +// Given a BITMAPINFOHEADER structure this returns the GUID sub type that is +// used to describe it in format negotiations. For example a video codec fills +// in the format block with a VIDEOINFO structure, it also fills in the major +// type with MEDIATYPE_VIDEO and the subtype with a GUID that matches the bit +// count, for example if it is an eight bit image then MEDIASUBTYPE_RGB8 + +STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader) +{ + ASSERT(pbmiHeader); + + // If it's not RGB then create a GUID from the compression type + + if (pbmiHeader->biCompression != BI_RGB) { + if (pbmiHeader->biCompression != BI_BITFIELDS) { + FOURCCMap FourCCMap(pbmiHeader->biCompression); + return (const GUID) FourCCMap; + } + } + + // Map the RGB DIB bit depth to a image GUID + + switch(pbmiHeader->biBitCount) { + case 1 : return MEDIASUBTYPE_RGB1; + case 4 : return MEDIASUBTYPE_RGB4; + case 8 : return MEDIASUBTYPE_RGB8; + case 16 : return GetTrueColorType(pbmiHeader); + case 24 : return MEDIASUBTYPE_RGB24; + case 32 : return MEDIASUBTYPE_RGB32; + } + return GUID_NULL; +} + + +// Given a video bitmap subtype we return the number of bits per pixel it uses +// We return a WORD bit count as thats what the BITMAPINFOHEADER uses. If the +// GUID subtype is not found in the table we return an invalid USHRT_MAX + +STDAPI_(WORD) GetBitCount(const GUID *pSubtype) +{ + ASSERT(pSubtype); + const GUID *pMediaSubtype; + INT iPosition = 0; + + // Scan the mapping list seeing if the source GUID matches any known + // bitmap subtypes, the list is terminated by a GUID_NULL entry + + while (TRUE) { + pMediaSubtype = BitCountMap[iPosition].pSubtype; + if (IsEqualGUID(*pMediaSubtype,GUID_NULL)) { + return USHRT_MAX; + } + if (IsEqualGUID(*pMediaSubtype,*pSubtype)) { + return BitCountMap[iPosition].BitCount; + } + iPosition++; + } +} + + +// Given a bitmap subtype we return a description name that can be used for +// debug purposes. In a retail build this function still returns the names +// If the subtype isn't found in the lookup table we return string UNKNOWN + +int LocateSubtype(const GUID *pSubtype) +{ + ASSERT(pSubtype); + const GUID *pMediaSubtype; + INT iPosition = 0; + + // Scan the mapping list seeing if the source GUID matches any known + // bitmap subtypes, the list is terminated by a GUID_NULL entry + + while (TRUE) { + pMediaSubtype = BitCountMap[iPosition].pSubtype; + if (IsEqualGUID(*pMediaSubtype,*pSubtype) || + IsEqualGUID(*pMediaSubtype,GUID_NULL) + ) + { + break; + } + + iPosition++; + } + + return iPosition; +} + + + +STDAPI_(WCHAR *) GetSubtypeNameW(const GUID *pSubtype) +{ + return BitCountMap[LocateSubtype(pSubtype)].wszName; +} + +STDAPI_(CHAR *) GetSubtypeNameA(const GUID *pSubtype) +{ + return BitCountMap[LocateSubtype(pSubtype)].pName; +} + +#ifndef GetSubtypeName +#error wxutil.h should have defined GetSubtypeName +#endif +#undef GetSubtypeName + +// this is here for people that linked to it directly; most people +// would use the header file that picks the A or W version. +STDAPI_(CHAR *) GetSubtypeName(const GUID *pSubtype) +{ + return GetSubtypeNameA(pSubtype); +} + + +// The mechanism for describing a bitmap format is with the BITMAPINFOHEADER +// This is really messy to deal with because it invariably has fields that +// follow it holding bit fields, palettes and the rest. This function gives +// the number of bytes required to hold a VIDEOINFO that represents it. This +// count includes the prefix information (like the rcSource rectangle) the +// BITMAPINFOHEADER field, and any other colour information on the end. +// +// WARNING If you want to copy a BITMAPINFOHEADER into a VIDEOINFO always make +// sure that you use the HEADER macro because the BITMAPINFOHEADER field isn't +// right at the start of the VIDEOINFO (there are a number of other fields), +// +// CopyMemory(HEADER(pVideoInfo),pbmi,sizeof(BITMAPINFOHEADER)); +// + +STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader) +{ + // Everyone has this to start with this + LONG Size = SIZE_PREHEADER + pHeader->biSize; + + ASSERT(pHeader->biSize >= sizeof(BITMAPINFOHEADER)); + + // Does this format use a palette, if the number of colours actually used + // is zero then it is set to the maximum that are allowed for that colour + // depth (an example is 256 for eight bits). Truecolour formats may also + // pass a palette with them in which case the used count is non zero + + // This would scare me. + ASSERT(pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed == 0); + + if (pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed) { + LONG Entries = (DWORD) 1 << pHeader->biBitCount; + if (pHeader->biClrUsed) { + Entries = pHeader->biClrUsed; + } + Size += Entries * sizeof(RGBQUAD); + } + + // Truecolour formats may have a BI_BITFIELDS specifier for compression + // type which means that room for three DWORDs should be allocated that + // specify where in each pixel the RGB colour components may be found + + if (pHeader->biCompression == BI_BITFIELDS) { + Size += SIZE_MASKS; + } + + // A BITMAPINFO for a palettised image may also contain a palette map that + // provides the information to map from a source palette to a destination + // palette during a BitBlt for example, because this information is only + // ever processed during drawing you don't normally store the palette map + // nor have any way of knowing if it is present in the data structure + + return Size; +} + + +// Returns TRUE if the VIDEOINFO contains a palette + +STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo) +{ + if (PALETTISED(pVideoInfo) == FALSE) { + if (pVideoInfo->bmiHeader.biClrUsed == 0) { + return FALSE; + } + } + return TRUE; +} + + +// Return a pointer to the first entry in a palette + +STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo) +{ + if (pVideoInfo->bmiHeader.biCompression == BI_BITFIELDS) { + return TRUECOLOR(pVideoInfo)->bmiColors; + } + return COLORS(pVideoInfo); +} diff --git a/plugins/GSdx/baseclasses/cache.h b/plugins/GSdx/baseclasses/cache.h index d98f262f9c..2ef996f4bc 100644 --- a/plugins/GSdx/baseclasses/cache.h +++ b/plugins/GSdx/baseclasses/cache.h @@ -1,74 +1,74 @@ -//------------------------------------------------------------------------------ -// File: Cache.h -// -// Desc: DirectShow base classes - efines a non-MFC generic cache class. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -/* This class implements a simple cache. A cache object is instantiated - with the number of items it is to hold. An item is a pointer to an - object derived from CBaseObject (helps reduce memory leaks). The cache - can then have objects added to it and removed from it. The cache size - is fixed at construction time and may therefore run out or be flooded. - If it runs out it returns a NULL pointer, if it fills up it also returns - a NULL pointer instead of a pointer to the object just inserted */ - -/* Making these classes inherit from CBaseObject does nothing for their - functionality but it allows us to check there are no memory leaks */ - -/* WARNING Be very careful when using this class, what it lets you do is - store and retrieve objects so that you can minimise object creation - which in turns improves efficiency. However the object you store is - exactly the same as the object you get back which means that it short - circuits the constructor initialisation phase. This means any class - variables the object has (eg pointers) are highly likely to be invalid. - Therefore ensure you reinitialise the object before using it again */ - - -#ifndef __CACHE__ -#define __CACHE__ - - -class CCache : CBaseObject { - - /* Make copy constructor and assignment operator inaccessible */ - - CCache(const CCache &refCache); - CCache &operator=(const CCache &refCache); - -private: - - /* These are initialised in the constructor. The first variable points to - an array of pointers, each of which points to a CBaseObject derived - object. The m_iCacheSize is the static fixed size for the cache and the - m_iUsed defines the number of places filled with objects at any time. - We fill the array of pointers from the start (ie m_ppObjects[0] first) - and then only add and remove objects from the end position, so in this - respect the array of object pointers should be treated as a stack */ - - CBaseObject **m_ppObjects; - const INT m_iCacheSize; - INT m_iUsed; - -public: - - CCache(TCHAR *pName,INT iItems); - virtual ~CCache(); - - /* Add an item to the cache */ - CBaseObject *AddToCache(CBaseObject *pObject); - - /* Remove an item from the cache */ - CBaseObject *RemoveFromCache(); - - /* Delete all the objects held in the cache */ - void RemoveAll(void); - - /* Return the cache size which is set during construction */ - INT GetCacheSize(void) const {return m_iCacheSize;}; -}; - -#endif /* __CACHE__ */ - +//------------------------------------------------------------------------------ +// File: Cache.h +// +// Desc: DirectShow base classes - efines a non-MFC generic cache class. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* This class implements a simple cache. A cache object is instantiated + with the number of items it is to hold. An item is a pointer to an + object derived from CBaseObject (helps reduce memory leaks). The cache + can then have objects added to it and removed from it. The cache size + is fixed at construction time and may therefore run out or be flooded. + If it runs out it returns a NULL pointer, if it fills up it also returns + a NULL pointer instead of a pointer to the object just inserted */ + +/* Making these classes inherit from CBaseObject does nothing for their + functionality but it allows us to check there are no memory leaks */ + +/* WARNING Be very careful when using this class, what it lets you do is + store and retrieve objects so that you can minimise object creation + which in turns improves efficiency. However the object you store is + exactly the same as the object you get back which means that it short + circuits the constructor initialisation phase. This means any class + variables the object has (eg pointers) are highly likely to be invalid. + Therefore ensure you reinitialise the object before using it again */ + + +#ifndef __CACHE__ +#define __CACHE__ + + +class CCache : CBaseObject { + + /* Make copy constructor and assignment operator inaccessible */ + + CCache(const CCache &refCache); + CCache &operator=(const CCache &refCache); + +private: + + /* These are initialised in the constructor. The first variable points to + an array of pointers, each of which points to a CBaseObject derived + object. The m_iCacheSize is the static fixed size for the cache and the + m_iUsed defines the number of places filled with objects at any time. + We fill the array of pointers from the start (ie m_ppObjects[0] first) + and then only add and remove objects from the end position, so in this + respect the array of object pointers should be treated as a stack */ + + CBaseObject **m_ppObjects; + const INT m_iCacheSize; + INT m_iUsed; + +public: + + CCache(TCHAR *pName,INT iItems); + virtual ~CCache(); + + /* Add an item to the cache */ + CBaseObject *AddToCache(CBaseObject *pObject); + + /* Remove an item from the cache */ + CBaseObject *RemoveFromCache(); + + /* Delete all the objects held in the cache */ + void RemoveAll(void); + + /* Return the cache size which is set during construction */ + INT GetCacheSize(void) const {return m_iCacheSize;}; +}; + +#endif /* __CACHE__ */ + diff --git a/plugins/GSdx/baseclasses/combase.cpp b/plugins/GSdx/baseclasses/combase.cpp index 70a33ecae0..d8c193a9dc 100644 --- a/plugins/GSdx/baseclasses/combase.cpp +++ b/plugins/GSdx/baseclasses/combase.cpp @@ -1,256 +1,256 @@ -//------------------------------------------------------------------------------ -// File: ComBase.cpp -// -// Desc: DirectShow base classes - implements class hierarchy for creating -// COM objects. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#pragma warning( disable : 4514 ) // Disable warnings re unused inline functions - - -/* Define the static member variable */ - -LONG CBaseObject::m_cObjects = 0; - - -/* Constructor */ - -CBaseObject::CBaseObject(const TCHAR *pName) -{ - /* Increment the number of active objects */ - InterlockedIncrement(&m_cObjects); - -#ifdef DEBUG - -#ifdef UNICODE - m_dwCookie = DbgRegisterObjectCreation(0, pName); -#else - m_dwCookie = DbgRegisterObjectCreation(pName, 0); -#endif - -#endif -} - -#ifdef UNICODE -CBaseObject::CBaseObject(const char *pName) -{ - /* Increment the number of active objects */ - InterlockedIncrement(&m_cObjects); - -#ifdef DEBUG - m_dwCookie = DbgRegisterObjectCreation(pName, 0); -#endif -} -#endif - -HINSTANCE hlibOLEAut32; - -/* Destructor */ - -CBaseObject::~CBaseObject() -{ - /* Decrement the number of objects active */ - if (InterlockedDecrement(&m_cObjects) == 0) { - if (hlibOLEAut32) { - FreeLibrary(hlibOLEAut32); - - hlibOLEAut32 = 0; - } - }; - - -#ifdef DEBUG - DbgRegisterObjectDestruction(m_dwCookie); -#endif -} - -static const TCHAR szOle32Aut[] = TEXT("OleAut32.dll"); - -HINSTANCE LoadOLEAut32() -{ - if (hlibOLEAut32 == 0) { - - hlibOLEAut32 = LoadLibrary(szOle32Aut); - } - - return hlibOLEAut32; -} - - -/* Constructor */ - -// We know we use "this" in the initialization list, we also know we don't modify *phr. -#pragma warning( disable : 4355 4100 ) -CUnknown::CUnknown(const TCHAR *pName, LPUNKNOWN pUnk) -: CBaseObject(pName) -/* Start the object with a reference count of zero - when the */ -/* object is queried for it's first interface this may be */ -/* incremented depending on whether or not this object is */ -/* currently being aggregated upon */ -, m_cRef(0) -/* Set our pointer to our IUnknown interface. */ -/* If we have an outer, use its, otherwise use ours. */ -/* This pointer effectivly points to the owner of */ -/* this object and can be accessed by the GetOwner() method. */ -, m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) - /* Why the double cast? Well, the inner cast is a type-safe cast */ - /* to pointer to a type from which we inherit. The second is */ - /* type-unsafe but works because INonDelegatingUnknown "behaves */ - /* like" IUnknown. (Only the names on the methods change.) */ -{ - // Everything we need to do has been done in the initializer list -} - -// This does the same as above except it has a useless HRESULT argument -// use the previous constructor, this is just left for compatibility... -CUnknown::CUnknown(TCHAR *pName, LPUNKNOWN pUnk,HRESULT *phr) : - CBaseObject(pName), - m_cRef(0), - m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) -{ -} - -#ifdef UNICODE -CUnknown::CUnknown(const CHAR *pName, LPUNKNOWN pUnk) -: CBaseObject(pName), m_cRef(0), - m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) -{ } - -CUnknown::CUnknown(CHAR *pName, LPUNKNOWN pUnk,HRESULT *phr) : - CBaseObject(pName), m_cRef(0), - m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) -{ } - -#endif - -#pragma warning( default : 4355 4100 ) - - -/* QueryInterface */ - -STDMETHODIMP CUnknown::NonDelegatingQueryInterface(REFIID riid, void ** ppv) -{ - CheckPointer(ppv,E_POINTER); - ValidateReadWritePtr(ppv,sizeof(PVOID)); - - /* We know only about IUnknown */ - - if (riid == IID_IUnknown) { - GetInterface((LPUNKNOWN) (PNDUNKNOWN) this, ppv); - return NOERROR; - } else { - *ppv = NULL; - return E_NOINTERFACE; - } -} - -/* We have to ensure that we DON'T use a max macro, since these will typically */ -/* lead to one of the parameters being evaluated twice. Since we are worried */ -/* about concurrency, we can't afford to access the m_cRef twice since we can't */ -/* afford to run the risk that its value having changed between accesses. */ - -template inline static T ourmax( const T & a, const T & b ) -{ - return a > b ? a : b; -} - -/* AddRef */ - -STDMETHODIMP_(ULONG) CUnknown::NonDelegatingAddRef() -{ - LONG lRef = InterlockedIncrement( &m_cRef ); - ASSERT(lRef > 0); - DbgLog((LOG_MEMORY,3,TEXT(" Obj %d ref++ = %d"), - m_dwCookie, m_cRef)); - return ourmax(ULONG(m_cRef), 1ul); -} - - -/* Release */ - -STDMETHODIMP_(ULONG) CUnknown::NonDelegatingRelease() -{ - /* If the reference count drops to zero delete ourselves */ - - LONG lRef = InterlockedDecrement( &m_cRef ); - ASSERT(lRef >= 0); - - DbgLog((LOG_MEMORY,3,TEXT(" Object %d ref-- = %d"), - m_dwCookie, m_cRef)); - if (lRef == 0) { - - // COM rules say we must protect against re-entrancy. - // If we are an aggregator and we hold our own interfaces - // on the aggregatee, the QI for these interfaces will - // addref ourselves. So after doing the QI we must release - // a ref count on ourselves. Then, before releasing the - // private interface, we must addref ourselves. When we do - // this from the destructor here it will result in the ref - // count going to 1 and then back to 0 causing us to - // re-enter the destructor. Hence we add an extra refcount here - // once we know we will delete the object. - // for an example aggregator see filgraph\distrib.cpp. - - m_cRef++; - - delete this; - return ULONG(0); - } else { - return ourmax(ULONG(m_cRef), 1ul); - } -} - - -/* Return an interface pointer to a requesting client - performing a thread safe AddRef as necessary */ - -STDAPI GetInterface(LPUNKNOWN pUnk, void **ppv) -{ - CheckPointer(ppv, E_POINTER); - *ppv = pUnk; - pUnk->AddRef(); - return NOERROR; -} - - -/* Compares two interfaces and returns TRUE if they are on the same object */ - -BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond) -{ - /* Different objects can't have the same interface pointer for - any interface - */ - if (pFirst == pSecond) { - return TRUE; - } - /* OK - do it the hard way - check if they have the same - IUnknown pointers - a single object can only have one of these - */ - LPUNKNOWN pUnknown1; // Retrieve the IUnknown interface - LPUNKNOWN pUnknown2; // Retrieve the other IUnknown interface - HRESULT hr; // General OLE return code - - ASSERT(pFirst); - ASSERT(pSecond); - - /* See if the IUnknown pointers match */ - - hr = pFirst->QueryInterface(IID_IUnknown,(void **) &pUnknown1); - ASSERT(SUCCEEDED(hr)); - ASSERT(pUnknown1); - - hr = pSecond->QueryInterface(IID_IUnknown,(void **) &pUnknown2); - ASSERT(SUCCEEDED(hr)); - ASSERT(pUnknown2); - - /* Release the extra interfaces we hold */ - - pUnknown1->Release(); - pUnknown2->Release(); - return (pUnknown1 == pUnknown2); -} - +//------------------------------------------------------------------------------ +// File: ComBase.cpp +// +// Desc: DirectShow base classes - implements class hierarchy for creating +// COM objects. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#pragma warning( disable : 4514 ) // Disable warnings re unused inline functions + + +/* Define the static member variable */ + +LONG CBaseObject::m_cObjects = 0; + + +/* Constructor */ + +CBaseObject::CBaseObject(const TCHAR *pName) +{ + /* Increment the number of active objects */ + InterlockedIncrement(&m_cObjects); + +#ifdef DEBUG + +#ifdef UNICODE + m_dwCookie = DbgRegisterObjectCreation(0, pName); +#else + m_dwCookie = DbgRegisterObjectCreation(pName, 0); +#endif + +#endif +} + +#ifdef UNICODE +CBaseObject::CBaseObject(const char *pName) +{ + /* Increment the number of active objects */ + InterlockedIncrement(&m_cObjects); + +#ifdef DEBUG + m_dwCookie = DbgRegisterObjectCreation(pName, 0); +#endif +} +#endif + +HINSTANCE hlibOLEAut32; + +/* Destructor */ + +CBaseObject::~CBaseObject() +{ + /* Decrement the number of objects active */ + if (InterlockedDecrement(&m_cObjects) == 0) { + if (hlibOLEAut32) { + FreeLibrary(hlibOLEAut32); + + hlibOLEAut32 = 0; + } + }; + + +#ifdef DEBUG + DbgRegisterObjectDestruction(m_dwCookie); +#endif +} + +static const TCHAR szOle32Aut[] = TEXT("OleAut32.dll"); + +HINSTANCE LoadOLEAut32() +{ + if (hlibOLEAut32 == 0) { + + hlibOLEAut32 = LoadLibrary(szOle32Aut); + } + + return hlibOLEAut32; +} + + +/* Constructor */ + +// We know we use "this" in the initialization list, we also know we don't modify *phr. +#pragma warning( disable : 4355 4100 ) +CUnknown::CUnknown(const TCHAR *pName, LPUNKNOWN pUnk) +: CBaseObject(pName) +/* Start the object with a reference count of zero - when the */ +/* object is queried for it's first interface this may be */ +/* incremented depending on whether or not this object is */ +/* currently being aggregated upon */ +, m_cRef(0) +/* Set our pointer to our IUnknown interface. */ +/* If we have an outer, use its, otherwise use ours. */ +/* This pointer effectivly points to the owner of */ +/* this object and can be accessed by the GetOwner() method. */ +, m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) + /* Why the double cast? Well, the inner cast is a type-safe cast */ + /* to pointer to a type from which we inherit. The second is */ + /* type-unsafe but works because INonDelegatingUnknown "behaves */ + /* like" IUnknown. (Only the names on the methods change.) */ +{ + // Everything we need to do has been done in the initializer list +} + +// This does the same as above except it has a useless HRESULT argument +// use the previous constructor, this is just left for compatibility... +CUnknown::CUnknown(TCHAR *pName, LPUNKNOWN pUnk,HRESULT *phr) : + CBaseObject(pName), + m_cRef(0), + m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) +{ +} + +#ifdef UNICODE +CUnknown::CUnknown(const CHAR *pName, LPUNKNOWN pUnk) +: CBaseObject(pName), m_cRef(0), + m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) +{ } + +CUnknown::CUnknown(CHAR *pName, LPUNKNOWN pUnk,HRESULT *phr) : + CBaseObject(pName), m_cRef(0), + m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) +{ } + +#endif + +#pragma warning( default : 4355 4100 ) + + +/* QueryInterface */ + +STDMETHODIMP CUnknown::NonDelegatingQueryInterface(REFIID riid, void ** ppv) +{ + CheckPointer(ppv,E_POINTER); + ValidateReadWritePtr(ppv,sizeof(PVOID)); + + /* We know only about IUnknown */ + + if (riid == IID_IUnknown) { + GetInterface((LPUNKNOWN) (PNDUNKNOWN) this, ppv); + return NOERROR; + } else { + *ppv = NULL; + return E_NOINTERFACE; + } +} + +/* We have to ensure that we DON'T use a max macro, since these will typically */ +/* lead to one of the parameters being evaluated twice. Since we are worried */ +/* about concurrency, we can't afford to access the m_cRef twice since we can't */ +/* afford to run the risk that its value having changed between accesses. */ + +template inline static T ourmax( const T & a, const T & b ) +{ + return a > b ? a : b; +} + +/* AddRef */ + +STDMETHODIMP_(ULONG) CUnknown::NonDelegatingAddRef() +{ + LONG lRef = InterlockedIncrement( &m_cRef ); + ASSERT(lRef > 0); + DbgLog((LOG_MEMORY,3,TEXT(" Obj %d ref++ = %d"), + m_dwCookie, m_cRef)); + return ourmax(ULONG(m_cRef), 1ul); +} + + +/* Release */ + +STDMETHODIMP_(ULONG) CUnknown::NonDelegatingRelease() +{ + /* If the reference count drops to zero delete ourselves */ + + LONG lRef = InterlockedDecrement( &m_cRef ); + ASSERT(lRef >= 0); + + DbgLog((LOG_MEMORY,3,TEXT(" Object %d ref-- = %d"), + m_dwCookie, m_cRef)); + if (lRef == 0) { + + // COM rules say we must protect against re-entrancy. + // If we are an aggregator and we hold our own interfaces + // on the aggregatee, the QI for these interfaces will + // addref ourselves. So after doing the QI we must release + // a ref count on ourselves. Then, before releasing the + // private interface, we must addref ourselves. When we do + // this from the destructor here it will result in the ref + // count going to 1 and then back to 0 causing us to + // re-enter the destructor. Hence we add an extra refcount here + // once we know we will delete the object. + // for an example aggregator see filgraph\distrib.cpp. + + m_cRef++; + + delete this; + return ULONG(0); + } else { + return ourmax(ULONG(m_cRef), 1ul); + } +} + + +/* Return an interface pointer to a requesting client + performing a thread safe AddRef as necessary */ + +STDAPI GetInterface(LPUNKNOWN pUnk, void **ppv) +{ + CheckPointer(ppv, E_POINTER); + *ppv = pUnk; + pUnk->AddRef(); + return NOERROR; +} + + +/* Compares two interfaces and returns TRUE if they are on the same object */ + +BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond) +{ + /* Different objects can't have the same interface pointer for + any interface + */ + if (pFirst == pSecond) { + return TRUE; + } + /* OK - do it the hard way - check if they have the same + IUnknown pointers - a single object can only have one of these + */ + LPUNKNOWN pUnknown1; // Retrieve the IUnknown interface + LPUNKNOWN pUnknown2; // Retrieve the other IUnknown interface + HRESULT hr; // General OLE return code + + ASSERT(pFirst); + ASSERT(pSecond); + + /* See if the IUnknown pointers match */ + + hr = pFirst->QueryInterface(IID_IUnknown,(void **) &pUnknown1); + ASSERT(SUCCEEDED(hr)); + ASSERT(pUnknown1); + + hr = pSecond->QueryInterface(IID_IUnknown,(void **) &pUnknown2); + ASSERT(SUCCEEDED(hr)); + ASSERT(pUnknown2); + + /* Release the extra interfaces we hold */ + + pUnknown1->Release(); + pUnknown2->Release(); + return (pUnknown1 == pUnknown2); +} + diff --git a/plugins/GSdx/baseclasses/combase.h b/plugins/GSdx/baseclasses/combase.h index 34d5ca65cd..901056b77e 100644 --- a/plugins/GSdx/baseclasses/combase.h +++ b/plugins/GSdx/baseclasses/combase.h @@ -1,319 +1,319 @@ -//------------------------------------------------------------------------------ -// File: ComBase.h -// -// Desc: DirectShow base classes - defines a class hierarchy for creating -// COM objects. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -/* - -a. Derive your COM object from CUnknown - -b. Make a static CreateInstance function that takes an LPUNKNOWN, an HRESULT * - and a TCHAR *. The LPUNKNOWN defines the object to delegate IUnknown calls - to. The HRESULT * allows error codes to be passed around constructors and - the TCHAR * is a descriptive name that can be printed on the debugger. - - It is important that constructors only change the HRESULT * if they have - to set an ERROR code, if it was successful then leave it alone or you may - overwrite an error code from an object previously created. - - When you call a constructor the descriptive name should be in static store - as we do not copy the string. To stop large amounts of memory being used - in retail builds by all these static strings use the NAME macro, - - CMyFilter = new CImplFilter(NAME("My filter"),pUnknown,phr); - if (FAILED(hr)) { - return hr; - } - - In retail builds NAME(_x_) compiles to NULL, the base CBaseObject class - knows not to do anything with objects that don't have a name. - -c. Have a constructor for your object that passes the LPUNKNOWN, HRESULT * and - TCHAR * to the CUnknown constructor. You can set the HRESULT if you have an - error, or just simply pass it through to the constructor. - - The object creation will fail in the class factory if the HRESULT indicates - an error (ie FAILED(HRESULT) == TRUE) - -d. Create a FactoryTemplate with your object's class id and CreateInstance - function. - -Then (for each interface) either - -Multiple inheritance - -1. Also derive it from ISomeInterface -2. Include DECLARE_IUNKNOWN in your class definition to declare - implementations of QueryInterface, AddRef and Release that - call the outer unknown -3. Override NonDelegatingQueryInterface to expose ISomeInterface by - code something like - - if (riid == IID_ISomeInterface) { - return GetInterface((ISomeInterface *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } - -4. Declare and implement the member functions of ISomeInterface. - -or: Nested interfaces - -1. Declare a class derived from CUnknown -2. Include DECLARE_IUNKNOWN in your class definition -3. Override NonDelegatingQueryInterface to expose ISomeInterface by - code something like - - if (riid == IID_ISomeInterface) { - return GetInterface((ISomeInterface *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } - -4. Implement the member functions of ISomeInterface. Use GetOwner() to - access the COM object class. - -And in your COM object class: - -5. Make the nested class a friend of the COM object class, and declare - an instance of the nested class as a member of the COM object class. - - NOTE that because you must always pass the outer unknown and an hResult - to the CUnknown constructor you cannot use a default constructor, in - other words you will have to make the member variable a pointer to the - class and make a NEW call in your constructor to actually create it. - -6. override the NonDelegatingQueryInterface with code like this: - - if (riid == IID_ISomeInterface) { - return m_pImplFilter-> - NonDelegatingQueryInterface(IID_ISomeInterface, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } - -You can have mixed classes which support some interfaces via multiple -inheritance and some via nested classes - -*/ - -#ifndef __COMBASE__ -#define __COMBASE__ - -// Filter Setup data structures no defined in axextend.idl - -typedef REGPINTYPES -AMOVIESETUP_MEDIATYPE, * PAMOVIESETUP_MEDIATYPE, * FAR LPAMOVIESETUP_MEDIATYPE; - -typedef REGFILTERPINS -AMOVIESETUP_PIN, * PAMOVIESETUP_PIN, * FAR LPAMOVIESETUP_PIN; - -typedef struct _AMOVIESETUP_FILTER -{ - const CLSID * clsID; - const WCHAR * strName; - DWORD dwMerit; - UINT nPins; - const AMOVIESETUP_PIN * lpPin; -} -AMOVIESETUP_FILTER, * PAMOVIESETUP_FILTER, * FAR LPAMOVIESETUP_FILTER; - -/* The DLLENTRY module initialises the module handle on loading */ - -extern HINSTANCE g_hInst; - -/* On DLL load remember which platform we are running on */ - -extern DWORD g_amPlatform; -extern OSVERSIONINFO g_osInfo; // Filled in by GetVersionEx - -/* Version of IUnknown that is renamed to allow a class to support both - non delegating and delegating IUnknowns in the same COM object */ - -#ifndef INONDELEGATINGUNKNOWN_DEFINED -DECLARE_INTERFACE(INonDelegatingUnknown) -{ - STDMETHOD(NonDelegatingQueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG, NonDelegatingAddRef)(THIS) PURE; - STDMETHOD_(ULONG, NonDelegatingRelease)(THIS) PURE; -}; -#define INONDELEGATINGUNKNOWN_DEFINED -#endif - -typedef INonDelegatingUnknown *PNDUNKNOWN; - - -/* This is the base object class that supports active object counting. As - part of the debug facilities we trace every time a C++ object is created - or destroyed. The name of the object has to be passed up through the class - derivation list during construction as you cannot call virtual functions - in the constructor. The downside of all this is that every single object - constructor has to take an object name parameter that describes it */ - -class CBaseObject -{ - -private: - - // Disable the copy constructor and assignment by default so you will get - // compiler errors instead of unexpected behaviour if you pass objects - // by value or assign objects. - CBaseObject(const CBaseObject& objectSrc); // no implementation - void operator=(const CBaseObject& objectSrc); // no implementation - -private: - static LONG m_cObjects; /* Total number of objects active */ - -protected: -#ifdef DEBUG - DWORD m_dwCookie; /* Cookie identifying this object */ -#endif - - -public: - - /* These increment and decrement the number of active objects */ - - CBaseObject(const TCHAR *pName); -#ifdef UNICODE - CBaseObject(const char *pName); -#endif - ~CBaseObject(); - - /* Call this to find if there are any CUnknown derived objects active */ - - static LONG ObjectsActive() { - return m_cObjects; - }; -}; - - -/* An object that supports one or more COM interfaces will be based on - this class. It supports counting of total objects for DLLCanUnloadNow - support, and an implementation of the core non delegating IUnknown */ - -class AM_NOVTABLE CUnknown : public INonDelegatingUnknown, - public CBaseObject -{ -private: - const LPUNKNOWN m_pUnknown; /* Owner of this object */ - -protected: /* So we can override NonDelegatingRelease() */ - volatile LONG m_cRef; /* Number of reference counts */ - -public: - - CUnknown(const TCHAR *pName, LPUNKNOWN pUnk); - virtual ~CUnknown() {}; - - // This is redundant, just use the other constructor - // as we never touch the HRESULT in this anyway - CUnknown(TCHAR *pName, LPUNKNOWN pUnk,HRESULT *phr); -#ifdef UNICODE - CUnknown(const char *pName, LPUNKNOWN pUnk); - CUnknown(char *pName, LPUNKNOWN pUnk,HRESULT *phr); -#endif - - /* Return the owner of this object */ - - LPUNKNOWN GetOwner() const { - return m_pUnknown; - }; - - /* Called from the class factory to create a new instance, it is - pure virtual so it must be overriden in your derived class */ - - /* static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *) */ - - /* Non delegating unknown implementation */ - - STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **); - STDMETHODIMP_(ULONG) NonDelegatingAddRef(); - STDMETHODIMP_(ULONG) NonDelegatingRelease(); -}; - -#if (_MSC_VER <= 1200) -#pragma warning(disable:4211) - -/* The standard InterlockedXXX functions won't take volatiles */ -static inline LONG WINAPI InterlockedIncrement( volatile LONG * plong ) -{ return InterlockedIncrement( const_cast( plong ) ); } - -static inline LONG WINAPI InterlockedDecrement( volatile LONG * plong ) -{ return InterlockedDecrement( const_cast( plong ) ); } - -#pragma warning(default:4211) -#endif - - -/* Return an interface pointer to a requesting client - performing a thread safe AddRef as necessary */ - -STDAPI GetInterface(LPUNKNOWN pUnk, void **ppv); - -/* A function that can create a new COM object */ - -typedef CUnknown *(CALLBACK *LPFNNewCOMObject)(LPUNKNOWN pUnkOuter, HRESULT *phr); - -/* A function (can be NULL) which is called from the DLL entrypoint - routine for each factory template: - - bLoading - TRUE on DLL load, FALSE on DLL unload - rclsid - the m_ClsID of the entry -*/ -typedef void (CALLBACK *LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid); - -/* Create one of these per object class in an array so that - the default class factory code can create new instances */ - -class CFactoryTemplate { - -public: - - const WCHAR * m_Name; - const CLSID * m_ClsID; - LPFNNewCOMObject m_lpfnNew; - LPFNInitRoutine m_lpfnInit; - const AMOVIESETUP_FILTER * m_pAMovieSetup_Filter; - - BOOL IsClassID(REFCLSID rclsid) const { - return (IsEqualCLSID(*m_ClsID,rclsid)); - }; - - CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) const { - CheckPointer(phr,NULL); - return m_lpfnNew(pUnk, phr); - }; -}; - - -/* You must override the (pure virtual) NonDelegatingQueryInterface to return - interface pointers (using GetInterface) to the interfaces your derived - class supports (the default implementation only supports IUnknown) */ - -#define DECLARE_IUNKNOWN \ - STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { \ - return GetOwner()->QueryInterface(riid,ppv); \ - }; \ - STDMETHODIMP_(ULONG) AddRef() { \ - return GetOwner()->AddRef(); \ - }; \ - STDMETHODIMP_(ULONG) Release() { \ - return GetOwner()->Release(); \ - }; - - - -HINSTANCE LoadOLEAut32(); - - -#endif /* __COMBASE__ */ - - - - +//------------------------------------------------------------------------------ +// File: ComBase.h +// +// Desc: DirectShow base classes - defines a class hierarchy for creating +// COM objects. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* + +a. Derive your COM object from CUnknown + +b. Make a static CreateInstance function that takes an LPUNKNOWN, an HRESULT * + and a TCHAR *. The LPUNKNOWN defines the object to delegate IUnknown calls + to. The HRESULT * allows error codes to be passed around constructors and + the TCHAR * is a descriptive name that can be printed on the debugger. + + It is important that constructors only change the HRESULT * if they have + to set an ERROR code, if it was successful then leave it alone or you may + overwrite an error code from an object previously created. + + When you call a constructor the descriptive name should be in static store + as we do not copy the string. To stop large amounts of memory being used + in retail builds by all these static strings use the NAME macro, + + CMyFilter = new CImplFilter(NAME("My filter"),pUnknown,phr); + if (FAILED(hr)) { + return hr; + } + + In retail builds NAME(_x_) compiles to NULL, the base CBaseObject class + knows not to do anything with objects that don't have a name. + +c. Have a constructor for your object that passes the LPUNKNOWN, HRESULT * and + TCHAR * to the CUnknown constructor. You can set the HRESULT if you have an + error, or just simply pass it through to the constructor. + + The object creation will fail in the class factory if the HRESULT indicates + an error (ie FAILED(HRESULT) == TRUE) + +d. Create a FactoryTemplate with your object's class id and CreateInstance + function. + +Then (for each interface) either + +Multiple inheritance + +1. Also derive it from ISomeInterface +2. Include DECLARE_IUNKNOWN in your class definition to declare + implementations of QueryInterface, AddRef and Release that + call the outer unknown +3. Override NonDelegatingQueryInterface to expose ISomeInterface by + code something like + + if (riid == IID_ISomeInterface) { + return GetInterface((ISomeInterface *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + +4. Declare and implement the member functions of ISomeInterface. + +or: Nested interfaces + +1. Declare a class derived from CUnknown +2. Include DECLARE_IUNKNOWN in your class definition +3. Override NonDelegatingQueryInterface to expose ISomeInterface by + code something like + + if (riid == IID_ISomeInterface) { + return GetInterface((ISomeInterface *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + +4. Implement the member functions of ISomeInterface. Use GetOwner() to + access the COM object class. + +And in your COM object class: + +5. Make the nested class a friend of the COM object class, and declare + an instance of the nested class as a member of the COM object class. + + NOTE that because you must always pass the outer unknown and an hResult + to the CUnknown constructor you cannot use a default constructor, in + other words you will have to make the member variable a pointer to the + class and make a NEW call in your constructor to actually create it. + +6. override the NonDelegatingQueryInterface with code like this: + + if (riid == IID_ISomeInterface) { + return m_pImplFilter-> + NonDelegatingQueryInterface(IID_ISomeInterface, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + +You can have mixed classes which support some interfaces via multiple +inheritance and some via nested classes + +*/ + +#ifndef __COMBASE__ +#define __COMBASE__ + +// Filter Setup data structures no defined in axextend.idl + +typedef REGPINTYPES +AMOVIESETUP_MEDIATYPE, * PAMOVIESETUP_MEDIATYPE, * FAR LPAMOVIESETUP_MEDIATYPE; + +typedef REGFILTERPINS +AMOVIESETUP_PIN, * PAMOVIESETUP_PIN, * FAR LPAMOVIESETUP_PIN; + +typedef struct _AMOVIESETUP_FILTER +{ + const CLSID * clsID; + const WCHAR * strName; + DWORD dwMerit; + UINT nPins; + const AMOVIESETUP_PIN * lpPin; +} +AMOVIESETUP_FILTER, * PAMOVIESETUP_FILTER, * FAR LPAMOVIESETUP_FILTER; + +/* The DLLENTRY module initialises the module handle on loading */ + +extern HINSTANCE g_hInst; + +/* On DLL load remember which platform we are running on */ + +extern DWORD g_amPlatform; +extern OSVERSIONINFO g_osInfo; // Filled in by GetVersionEx + +/* Version of IUnknown that is renamed to allow a class to support both + non delegating and delegating IUnknowns in the same COM object */ + +#ifndef INONDELEGATINGUNKNOWN_DEFINED +DECLARE_INTERFACE(INonDelegatingUnknown) +{ + STDMETHOD(NonDelegatingQueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG, NonDelegatingAddRef)(THIS) PURE; + STDMETHOD_(ULONG, NonDelegatingRelease)(THIS) PURE; +}; +#define INONDELEGATINGUNKNOWN_DEFINED +#endif + +typedef INonDelegatingUnknown *PNDUNKNOWN; + + +/* This is the base object class that supports active object counting. As + part of the debug facilities we trace every time a C++ object is created + or destroyed. The name of the object has to be passed up through the class + derivation list during construction as you cannot call virtual functions + in the constructor. The downside of all this is that every single object + constructor has to take an object name parameter that describes it */ + +class CBaseObject +{ + +private: + + // Disable the copy constructor and assignment by default so you will get + // compiler errors instead of unexpected behaviour if you pass objects + // by value or assign objects. + CBaseObject(const CBaseObject& objectSrc); // no implementation + void operator=(const CBaseObject& objectSrc); // no implementation + +private: + static LONG m_cObjects; /* Total number of objects active */ + +protected: +#ifdef DEBUG + DWORD m_dwCookie; /* Cookie identifying this object */ +#endif + + +public: + + /* These increment and decrement the number of active objects */ + + CBaseObject(const TCHAR *pName); +#ifdef UNICODE + CBaseObject(const char *pName); +#endif + ~CBaseObject(); + + /* Call this to find if there are any CUnknown derived objects active */ + + static LONG ObjectsActive() { + return m_cObjects; + }; +}; + + +/* An object that supports one or more COM interfaces will be based on + this class. It supports counting of total objects for DLLCanUnloadNow + support, and an implementation of the core non delegating IUnknown */ + +class AM_NOVTABLE CUnknown : public INonDelegatingUnknown, + public CBaseObject +{ +private: + const LPUNKNOWN m_pUnknown; /* Owner of this object */ + +protected: /* So we can override NonDelegatingRelease() */ + volatile LONG m_cRef; /* Number of reference counts */ + +public: + + CUnknown(const TCHAR *pName, LPUNKNOWN pUnk); + virtual ~CUnknown() {}; + + // This is redundant, just use the other constructor + // as we never touch the HRESULT in this anyway + CUnknown(TCHAR *pName, LPUNKNOWN pUnk,HRESULT *phr); +#ifdef UNICODE + CUnknown(const char *pName, LPUNKNOWN pUnk); + CUnknown(char *pName, LPUNKNOWN pUnk,HRESULT *phr); +#endif + + /* Return the owner of this object */ + + LPUNKNOWN GetOwner() const { + return m_pUnknown; + }; + + /* Called from the class factory to create a new instance, it is + pure virtual so it must be overriden in your derived class */ + + /* static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *) */ + + /* Non delegating unknown implementation */ + + STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **); + STDMETHODIMP_(ULONG) NonDelegatingAddRef(); + STDMETHODIMP_(ULONG) NonDelegatingRelease(); +}; + +#if (_MSC_VER <= 1200) +#pragma warning(disable:4211) + +/* The standard InterlockedXXX functions won't take volatiles */ +static inline LONG WINAPI InterlockedIncrement( volatile LONG * plong ) +{ return InterlockedIncrement( const_cast( plong ) ); } + +static inline LONG WINAPI InterlockedDecrement( volatile LONG * plong ) +{ return InterlockedDecrement( const_cast( plong ) ); } + +#pragma warning(default:4211) +#endif + + +/* Return an interface pointer to a requesting client + performing a thread safe AddRef as necessary */ + +STDAPI GetInterface(LPUNKNOWN pUnk, void **ppv); + +/* A function that can create a new COM object */ + +typedef CUnknown *(CALLBACK *LPFNNewCOMObject)(LPUNKNOWN pUnkOuter, HRESULT *phr); + +/* A function (can be NULL) which is called from the DLL entrypoint + routine for each factory template: + + bLoading - TRUE on DLL load, FALSE on DLL unload + rclsid - the m_ClsID of the entry +*/ +typedef void (CALLBACK *LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid); + +/* Create one of these per object class in an array so that + the default class factory code can create new instances */ + +class CFactoryTemplate { + +public: + + const WCHAR * m_Name; + const CLSID * m_ClsID; + LPFNNewCOMObject m_lpfnNew; + LPFNInitRoutine m_lpfnInit; + const AMOVIESETUP_FILTER * m_pAMovieSetup_Filter; + + BOOL IsClassID(REFCLSID rclsid) const { + return (IsEqualCLSID(*m_ClsID,rclsid)); + }; + + CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) const { + CheckPointer(phr,NULL); + return m_lpfnNew(pUnk, phr); + }; +}; + + +/* You must override the (pure virtual) NonDelegatingQueryInterface to return + interface pointers (using GetInterface) to the interfaces your derived + class supports (the default implementation only supports IUnknown) */ + +#define DECLARE_IUNKNOWN \ + STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { \ + return GetOwner()->QueryInterface(riid,ppv); \ + }; \ + STDMETHODIMP_(ULONG) AddRef() { \ + return GetOwner()->AddRef(); \ + }; \ + STDMETHODIMP_(ULONG) Release() { \ + return GetOwner()->Release(); \ + }; + + + +HINSTANCE LoadOLEAut32(); + + +#endif /* __COMBASE__ */ + + + + diff --git a/plugins/GSdx/baseclasses/ctlutil.cpp b/plugins/GSdx/baseclasses/ctlutil.cpp index 1a623cf943..a234f838a1 100644 --- a/plugins/GSdx/baseclasses/ctlutil.cpp +++ b/plugins/GSdx/baseclasses/ctlutil.cpp @@ -1,2531 +1,2531 @@ -//------------------------------------------------------------------------------ -// File: CtlUtil.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// Base classes implementing IDispatch parsing for the basic control dual -// interfaces. Derive from these and implement just the custom method and -// property methods. We also implement CPosPassThru that can be used by -// renderers and transforms to pass by IMediaPosition and IMediaSeeking - - -#include "streams.h" -#include -#include "seekpt.h" - -// 'bool' non standard reserved word -#pragma warning(disable:4237) - - -// --- CBaseDispatch implementation ---------- -CBaseDispatch::~CBaseDispatch() -{ - if (m_pti) { - m_pti->Release(); - } -} - - -// return 1 if we support GetTypeInfo - -STDMETHODIMP -CBaseDispatch::GetTypeInfoCount(UINT * pctinfo) -{ - CheckPointer(pctinfo,E_POINTER); - ValidateReadWritePtr(pctinfo,sizeof(UINT *)); - *pctinfo = 1; - return S_OK; -} - - -typedef HRESULT (STDAPICALLTYPE *LPLOADTYPELIB)( - const OLECHAR FAR *szFile, - ITypeLib FAR* FAR* pptlib); - -typedef HRESULT (STDAPICALLTYPE *LPLOADREGTYPELIB)(REFGUID rguid, - WORD wVerMajor, - WORD wVerMinor, - LCID lcid, - ITypeLib FAR* FAR* pptlib); - -// attempt to find our type library - -STDMETHODIMP -CBaseDispatch::GetTypeInfo( - REFIID riid, - UINT itinfo, - LCID lcid, - ITypeInfo ** pptinfo) -{ - CheckPointer(pptinfo,E_POINTER); - ValidateReadWritePtr(pptinfo,sizeof(ITypeInfo *)); - HRESULT hr; - - *pptinfo = NULL; - - // we only support one type element - if (0 != itinfo) { - return TYPE_E_ELEMENTNOTFOUND; - } - - if (NULL == pptinfo) { - return E_POINTER; - } - - // always look for neutral - if (NULL == m_pti) { - - LPLOADTYPELIB lpfnLoadTypeLib; - LPLOADREGTYPELIB lpfnLoadRegTypeLib; - ITypeLib *ptlib; - HINSTANCE hInst; - - static const char szTypeLib[] = "LoadTypeLib"; - static const char szRegTypeLib[] = "LoadRegTypeLib"; - static const WCHAR szControl[] = L"control.tlb"; - - // - // Try to get the Ole32Aut.dll module handle. - // - - hInst = LoadOLEAut32(); - if (hInst == NULL) { - DWORD dwError = GetLastError(); - return AmHresultFromWin32(dwError); - } - lpfnLoadRegTypeLib = (LPLOADREGTYPELIB)GetProcAddress(hInst, - szRegTypeLib); - if (lpfnLoadRegTypeLib == NULL) { - DWORD dwError = GetLastError(); - return AmHresultFromWin32(dwError); - } - - hr = (*lpfnLoadRegTypeLib)(LIBID_QuartzTypeLib, 1, 0, // version 1.0 - lcid, &ptlib); - - if (FAILED(hr)) { - - // attempt to load directly - this will fill the - // registry in if it finds it - - lpfnLoadTypeLib = (LPLOADTYPELIB)GetProcAddress(hInst, szTypeLib); - if (lpfnLoadTypeLib == NULL) { - DWORD dwError = GetLastError(); - return AmHresultFromWin32(dwError); - } - - hr = (*lpfnLoadTypeLib)(szControl, &ptlib); - if (FAILED(hr)) { - return hr; - } - } - - hr = ptlib->GetTypeInfoOfGuid( - riid, - &m_pti); - - ptlib->Release(); - - if (FAILED(hr)) { - return hr; - } - } - - *pptinfo = m_pti; - m_pti->AddRef(); - return S_OK; -} - - -STDMETHODIMP -CBaseDispatch::GetIDsOfNames( - REFIID riid, - OLECHAR ** rgszNames, - UINT cNames, - LCID lcid, - DISPID * rgdispid) -{ - // although the IDispatch riid is dead, we use this to pass from - // the interface implementation class to us the iid we are talking about. - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(riid, 0, lcid, &pti); - - if (SUCCEEDED(hr)) { - hr = pti->GetIDsOfNames(rgszNames, cNames, rgdispid); - - pti->Release(); - } - return hr; -} - - -// --- CMediaControl implementation --------- - -CMediaControl::CMediaControl(const TCHAR * name,LPUNKNOWN pUnk) : - CUnknown(name, pUnk) -{ -} - -// expose our interfaces IMediaControl and IUnknown - -STDMETHODIMP -CMediaControl::NonDelegatingQueryInterface(REFIID riid, void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IMediaControl) { - return GetInterface( (IMediaControl *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -// return 1 if we support GetTypeInfo - -STDMETHODIMP -CMediaControl::GetTypeInfoCount(UINT * pctinfo) -{ - return m_basedisp.GetTypeInfoCount(pctinfo); -} - - -// attempt to find our type library - -STDMETHODIMP -CMediaControl::GetTypeInfo( - UINT itinfo, - LCID lcid, - ITypeInfo ** pptinfo) -{ - return m_basedisp.GetTypeInfo( - IID_IMediaControl, - itinfo, - lcid, - pptinfo); -} - - -STDMETHODIMP -CMediaControl::GetIDsOfNames( - REFIID riid, - OLECHAR ** rgszNames, - UINT cNames, - LCID lcid, - DISPID * rgdispid) -{ - return m_basedisp.GetIDsOfNames( - IID_IMediaControl, - rgszNames, - cNames, - lcid, - rgdispid); -} - - -STDMETHODIMP -CMediaControl::Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - DISPPARAMS * pdispparams, - VARIANT * pvarResult, - EXCEPINFO * pexcepinfo, - UINT * puArgErr) -{ - // this parameter is a dead leftover from an earlier interface - if (IID_NULL != riid) { - return DISP_E_UNKNOWNINTERFACE; - } - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(0, lcid, &pti); - - if (FAILED(hr)) { - return hr; - } - - hr = pti->Invoke( - (IMediaControl *)this, - dispidMember, - wFlags, - pdispparams, - pvarResult, - pexcepinfo, - puArgErr); - - pti->Release(); - return hr; -} - - -// --- CMediaEvent implementation ---------- - - -CMediaEvent::CMediaEvent(const TCHAR * name,LPUNKNOWN pUnk) : - CUnknown(name, pUnk) -{ -} - - -// expose our interfaces IMediaEvent and IUnknown - -STDMETHODIMP -CMediaEvent::NonDelegatingQueryInterface(REFIID riid, void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IMediaEvent || riid == IID_IMediaEventEx) { - return GetInterface( (IMediaEventEx *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -// return 1 if we support GetTypeInfo - -STDMETHODIMP -CMediaEvent::GetTypeInfoCount(UINT * pctinfo) -{ - return m_basedisp.GetTypeInfoCount(pctinfo); -} - - -// attempt to find our type library - -STDMETHODIMP -CMediaEvent::GetTypeInfo( - UINT itinfo, - LCID lcid, - ITypeInfo ** pptinfo) -{ - return m_basedisp.GetTypeInfo( - IID_IMediaEvent, - itinfo, - lcid, - pptinfo); -} - - -STDMETHODIMP -CMediaEvent::GetIDsOfNames( - REFIID riid, - OLECHAR ** rgszNames, - UINT cNames, - LCID lcid, - DISPID * rgdispid) -{ - return m_basedisp.GetIDsOfNames( - IID_IMediaEvent, - rgszNames, - cNames, - lcid, - rgdispid); -} - - -STDMETHODIMP -CMediaEvent::Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - DISPPARAMS * pdispparams, - VARIANT * pvarResult, - EXCEPINFO * pexcepinfo, - UINT * puArgErr) -{ - // this parameter is a dead leftover from an earlier interface - if (IID_NULL != riid) { - return DISP_E_UNKNOWNINTERFACE; - } - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(0, lcid, &pti); - - if (FAILED(hr)) { - return hr; - } - - hr = pti->Invoke( - (IMediaEvent *)this, - dispidMember, - wFlags, - pdispparams, - pvarResult, - pexcepinfo, - puArgErr); - - pti->Release(); - return hr; -} - - -// --- CMediaPosition implementation ---------- - - -CMediaPosition::CMediaPosition(const TCHAR * name,LPUNKNOWN pUnk) : - CUnknown(name, pUnk) -{ -} - -CMediaPosition::CMediaPosition(const TCHAR * name, - LPUNKNOWN pUnk, - HRESULT * phr) : - CUnknown(name, pUnk) -{ - UNREFERENCED_PARAMETER(phr); -} - - -// expose our interfaces IMediaPosition and IUnknown - -STDMETHODIMP -CMediaPosition::NonDelegatingQueryInterface(REFIID riid, void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IMediaPosition) { - return GetInterface( (IMediaPosition *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -// return 1 if we support GetTypeInfo - -STDMETHODIMP -CMediaPosition::GetTypeInfoCount(UINT * pctinfo) -{ - return m_basedisp.GetTypeInfoCount(pctinfo); -} - - -// attempt to find our type library - -STDMETHODIMP -CMediaPosition::GetTypeInfo( - UINT itinfo, - LCID lcid, - ITypeInfo ** pptinfo) -{ - return m_basedisp.GetTypeInfo( - IID_IMediaPosition, - itinfo, - lcid, - pptinfo); -} - - -STDMETHODIMP -CMediaPosition::GetIDsOfNames( - REFIID riid, - OLECHAR ** rgszNames, - UINT cNames, - LCID lcid, - DISPID * rgdispid) -{ - return m_basedisp.GetIDsOfNames( - IID_IMediaPosition, - rgszNames, - cNames, - lcid, - rgdispid); -} - - -STDMETHODIMP -CMediaPosition::Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - DISPPARAMS * pdispparams, - VARIANT * pvarResult, - EXCEPINFO * pexcepinfo, - UINT * puArgErr) -{ - // this parameter is a dead leftover from an earlier interface - if (IID_NULL != riid) { - return DISP_E_UNKNOWNINTERFACE; - } - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(0, lcid, &pti); - - if (FAILED(hr)) { - return hr; - } - - hr = pti->Invoke( - (IMediaPosition *)this, - dispidMember, - wFlags, - pdispparams, - pvarResult, - pexcepinfo, - puArgErr); - - pti->Release(); - return hr; -} - - -// --- IMediaPosition and IMediaSeeking pass through class ---------- - - -CPosPassThru::CPosPassThru(const TCHAR *pName, - LPUNKNOWN pUnk, - HRESULT *phr, - IPin *pPin) : - CMediaPosition(pName,pUnk), - m_pPin(pPin) -{ - if (pPin == NULL) { - *phr = E_POINTER; - return; - } -} - - -// Expose our IMediaSeeking and IMediaPosition interfaces - -STDMETHODIMP -CPosPassThru::NonDelegatingQueryInterface(REFIID riid,void **ppv) -{ - CheckPointer(ppv,E_POINTER); - *ppv = NULL; - - if (riid == IID_IMediaSeeking) { - return GetInterface( static_cast(this), ppv); - } - return CMediaPosition::NonDelegatingQueryInterface(riid,ppv); -} - - -// Return the IMediaPosition interface from our peer - -HRESULT -CPosPassThru::GetPeer(IMediaPosition ** ppMP) -{ - *ppMP = NULL; - - IPin *pConnected; - HRESULT hr = m_pPin->ConnectedTo(&pConnected); - if (FAILED(hr)) { - return E_NOTIMPL; - } - IMediaPosition * pMP; - hr = pConnected->QueryInterface(IID_IMediaPosition, (void **) &pMP); - pConnected->Release(); - if (FAILED(hr)) { - return E_NOTIMPL; - } - - *ppMP = pMP; - return S_OK; -} - - -// Return the IMediaSeeking interface from our peer - -HRESULT -CPosPassThru::GetPeerSeeking(IMediaSeeking ** ppMS) -{ - *ppMS = NULL; - - IPin *pConnected; - HRESULT hr = m_pPin->ConnectedTo(&pConnected); - if (FAILED(hr)) { - return E_NOTIMPL; - } - IMediaSeeking * pMS; - hr = pConnected->QueryInterface(IID_IMediaSeeking, (void **) &pMS); - pConnected->Release(); - if (FAILED(hr)) { - return E_NOTIMPL; - } - - *ppMS = pMS; - return S_OK; -} - - -// --- IMediaSeeking methods ---------- - - -STDMETHODIMP -CPosPassThru::GetCapabilities(DWORD * pCaps) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->GetCapabilities(pCaps); - pMS->Release(); - return hr; -} - -STDMETHODIMP -CPosPassThru::CheckCapabilities(DWORD * pCaps) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->CheckCapabilities(pCaps); - pMS->Release(); - return hr; -} - -STDMETHODIMP -CPosPassThru::IsFormatSupported(const GUID * pFormat) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->IsFormatSupported(pFormat); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::QueryPreferredFormat(GUID *pFormat) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->QueryPreferredFormat(pFormat); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::SetTimeFormat(const GUID * pFormat) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->SetTimeFormat(pFormat); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::GetTimeFormat(GUID *pFormat) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->GetTimeFormat(pFormat); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::IsUsingTimeFormat(const GUID * pFormat) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->IsUsingTimeFormat(pFormat); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::ConvertTimeFormat(LONGLONG * pTarget, const GUID * pTargetFormat, - LONGLONG Source, const GUID * pSourceFormat ) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat ); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::SetPositions( LONGLONG * pCurrent, DWORD CurrentFlags - , LONGLONG * pStop, DWORD StopFlags ) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->SetPositions(pCurrent, CurrentFlags, pStop, StopFlags ); - pMS->Release(); - return hr; -} - -STDMETHODIMP -CPosPassThru::GetPositions(LONGLONG *pCurrent, LONGLONG * pStop) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->GetPositions(pCurrent,pStop); - pMS->Release(); - return hr; -} - -HRESULT -CPosPassThru::GetSeekingLongLong -( HRESULT (__stdcall IMediaSeeking::*pMethod)( LONGLONG * ) -, LONGLONG * pll -) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (SUCCEEDED(hr)) - { - hr = (pMS->*pMethod)(pll); - pMS->Release(); - } - return hr; -} - -// If we don't have a current position then ask upstream - -STDMETHODIMP -CPosPassThru::GetCurrentPosition(LONGLONG *pCurrent) -{ - // Can we report the current position - HRESULT hr = GetMediaTime(pCurrent,NULL); - if (SUCCEEDED(hr)) hr = NOERROR; - else hr = GetSeekingLongLong( &IMediaSeeking::GetCurrentPosition, pCurrent ); - return hr; -} - - -STDMETHODIMP -CPosPassThru::GetStopPosition(LONGLONG *pStop) -{ - return GetSeekingLongLong( &IMediaSeeking::GetStopPosition, pStop );; -} - -STDMETHODIMP -CPosPassThru::GetDuration(LONGLONG *pDuration) -{ - return GetSeekingLongLong( &IMediaSeeking::GetDuration, pDuration );; -} - - -STDMETHODIMP -CPosPassThru::GetPreroll(LONGLONG *pllPreroll) -{ - return GetSeekingLongLong( &IMediaSeeking::GetPreroll, pllPreroll );; -} - - -STDMETHODIMP -CPosPassThru::GetAvailable( LONGLONG *pEarliest, LONGLONG *pLatest ) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->GetAvailable( pEarliest, pLatest ); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::GetRate(double * pdRate) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - hr = pMS->GetRate(pdRate); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::SetRate(double dRate) -{ - if (0.0 == dRate) { - return E_INVALIDARG; - } - - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - hr = pMS->SetRate(dRate); - pMS->Release(); - return hr; -} - - - - -// --- IMediaPosition methods ---------- - - -STDMETHODIMP -CPosPassThru::get_Duration(REFTIME * plength) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - - hr = pMP->get_Duration(plength); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::get_CurrentPosition(REFTIME * pllTime) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->get_CurrentPosition(pllTime); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::put_CurrentPosition(REFTIME llTime) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->put_CurrentPosition(llTime); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::get_StopTime(REFTIME * pllTime) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->get_StopTime(pllTime); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::put_StopTime(REFTIME llTime) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->put_StopTime(llTime); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::get_PrerollTime(REFTIME * pllTime) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->get_PrerollTime(pllTime); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::put_PrerollTime(REFTIME llTime) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->put_PrerollTime(llTime); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::get_Rate(double * pdRate) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->get_Rate(pdRate); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::put_Rate(double dRate) -{ - if (0.0 == dRate) { - return E_INVALIDARG; - } - - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->put_Rate(dRate); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::CanSeekForward(LONG *pCanSeekForward) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->CanSeekForward(pCanSeekForward); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::CanSeekBackward(LONG *pCanSeekBackward) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->CanSeekBackward(pCanSeekBackward); - pMP->Release(); - return hr; -} - - -// --- Implements the CRendererPosPassThru class ---------- - - -// Media times (eg current frame, field, sample etc) are passed through the -// filtergraph in media samples. When a renderer gets a sample with media -// times in it, it will call one of the RegisterMediaTime methods we expose -// (one takes an IMediaSample, the other takes the media times direct). We -// store the media times internally and return them in GetCurrentPosition. - -CRendererPosPassThru::CRendererPosPassThru(const TCHAR *pName, - LPUNKNOWN pUnk, - HRESULT *phr, - IPin *pPin) : - CPosPassThru(pName,pUnk,phr,pPin), - m_StartMedia(0), - m_EndMedia(0), - m_bReset(TRUE) -{ -} - - -// Sets the media times the object should report - -HRESULT -CRendererPosPassThru::RegisterMediaTime(IMediaSample *pMediaSample) -{ - ASSERT(pMediaSample); - LONGLONG StartMedia; - LONGLONG EndMedia; - - CAutoLock cAutoLock(&m_PositionLock); - - // Get the media times from the sample - - HRESULT hr = pMediaSample->GetTime(&StartMedia,&EndMedia); - if (FAILED(hr)) - { - ASSERT(hr == VFW_E_SAMPLE_TIME_NOT_SET); - return hr; - } - - m_StartMedia = StartMedia; - m_EndMedia = EndMedia; - m_bReset = FALSE; - return NOERROR; -} - - -// Sets the media times the object should report - -HRESULT -CRendererPosPassThru::RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime) -{ - CAutoLock cAutoLock(&m_PositionLock); - m_StartMedia = StartTime; - m_EndMedia = EndTime; - m_bReset = FALSE; - return NOERROR; -} - - -// Return the current media times registered in the object - -HRESULT -CRendererPosPassThru::GetMediaTime(LONGLONG *pStartTime,LONGLONG *pEndTime) -{ - ASSERT(pStartTime); - - CAutoLock cAutoLock(&m_PositionLock); - if (m_bReset == TRUE) { - return E_FAIL; - } - - // We don't have to return the end time - - HRESULT hr = ConvertTimeFormat( pStartTime, 0, m_StartMedia, &TIME_FORMAT_MEDIA_TIME ); - if (pEndTime && SUCCEEDED(hr)) { - hr = ConvertTimeFormat( pEndTime, 0, m_EndMedia, &TIME_FORMAT_MEDIA_TIME ); - } - return hr; -} - - -// Resets the media times we hold - -HRESULT -CRendererPosPassThru::ResetMediaTime() -{ - CAutoLock cAutoLock(&m_PositionLock); - m_StartMedia = 0; - m_EndMedia = 0; - m_bReset = TRUE; - return NOERROR; -} - -// Intended to be called by the owing filter during EOS processing so -// that the media times can be adjusted to the stop time. This ensures -// that the GetCurrentPosition will actully get to the stop position. -HRESULT -CRendererPosPassThru::EOS() -{ - HRESULT hr; - - if ( m_bReset == TRUE ) hr = E_FAIL; - else - { - LONGLONG llStop; - if SUCCEEDED(hr=GetStopPosition(&llStop)) - { - CAutoLock cAutoLock(&m_PositionLock); - m_StartMedia = - m_EndMedia = llStop; - } - } - return hr; -} - -// -- CSourceSeeking implementation ------------ - -CSourceSeeking::CSourceSeeking( - const TCHAR * pName, - LPUNKNOWN pUnk, - HRESULT* phr, - CCritSec * pLock) : - CUnknown(pName, pUnk), - m_pLock(pLock), - m_rtStart((long)0) -{ - m_rtStop = _I64_MAX / 2; - m_rtDuration = m_rtStop; - m_dRateSeeking = 1.0; - - m_dwSeekingCaps = AM_SEEKING_CanSeekForwards - | AM_SEEKING_CanSeekBackwards - | AM_SEEKING_CanSeekAbsolute - | AM_SEEKING_CanGetStopPos - | AM_SEEKING_CanGetDuration; -} - -HRESULT CSourceSeeking::NonDelegatingQueryInterface(REFIID riid, void **ppv) -{ - if(riid == IID_IMediaSeeking) { - CheckPointer(ppv, E_POINTER); - return GetInterface(static_cast(this), ppv); - } - else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -HRESULT CSourceSeeking::IsFormatSupported(const GUID * pFormat) -{ - CheckPointer(pFormat, E_POINTER); - // only seeking in time (REFERENCE_TIME units) is supported - return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; -} - -HRESULT CSourceSeeking::QueryPreferredFormat(GUID *pFormat) -{ - CheckPointer(pFormat, E_POINTER); - *pFormat = TIME_FORMAT_MEDIA_TIME; - return S_OK; -} - -HRESULT CSourceSeeking::SetTimeFormat(const GUID * pFormat) -{ - CheckPointer(pFormat, E_POINTER); - - // nothing to set; just check that it's TIME_FORMAT_TIME - return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : E_INVALIDARG; -} - -HRESULT CSourceSeeking::IsUsingTimeFormat(const GUID * pFormat) -{ - CheckPointer(pFormat, E_POINTER); - return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; -} - -HRESULT CSourceSeeking::GetTimeFormat(GUID *pFormat) -{ - CheckPointer(pFormat, E_POINTER); - *pFormat = TIME_FORMAT_MEDIA_TIME; - return S_OK; -} - -HRESULT CSourceSeeking::GetDuration(LONGLONG *pDuration) -{ - CheckPointer(pDuration, E_POINTER); - CAutoLock lock(m_pLock); - *pDuration = m_rtDuration; - return S_OK; -} - -HRESULT CSourceSeeking::GetStopPosition(LONGLONG *pStop) -{ - CheckPointer(pStop, E_POINTER); - CAutoLock lock(m_pLock); - *pStop = m_rtStop; - return S_OK; -} - -HRESULT CSourceSeeking::GetCurrentPosition(LONGLONG *pCurrent) -{ - // GetCurrentPosition is typically supported only in renderers and - // not in source filters. - return E_NOTIMPL; -} - -HRESULT CSourceSeeking::GetCapabilities( DWORD * pCapabilities ) -{ - CheckPointer(pCapabilities, E_POINTER); - *pCapabilities = m_dwSeekingCaps; - return S_OK; -} - -HRESULT CSourceSeeking::CheckCapabilities( DWORD * pCapabilities ) -{ - CheckPointer(pCapabilities, E_POINTER); - - // make sure all requested capabilities are in our mask - return (~m_dwSeekingCaps & *pCapabilities) ? S_FALSE : S_OK; -} - -HRESULT CSourceSeeking::ConvertTimeFormat( LONGLONG * pTarget, const GUID * pTargetFormat, - LONGLONG Source, const GUID * pSourceFormat ) -{ - CheckPointer(pTarget, E_POINTER); - // format guids can be null to indicate current format - - // since we only support TIME_FORMAT_MEDIA_TIME, we don't really - // offer any conversions. - if(pTargetFormat == 0 || *pTargetFormat == TIME_FORMAT_MEDIA_TIME) - { - if(pSourceFormat == 0 || *pSourceFormat == TIME_FORMAT_MEDIA_TIME) - { - *pTarget = Source; - return S_OK; - } - } - - return E_INVALIDARG; -} - - -HRESULT CSourceSeeking::SetPositions( LONGLONG * pCurrent, DWORD CurrentFlags - , LONGLONG * pStop, DWORD StopFlags ) -{ - DWORD StopPosBits = StopFlags & AM_SEEKING_PositioningBitsMask; - DWORD StartPosBits = CurrentFlags & AM_SEEKING_PositioningBitsMask; - - if(StopFlags) { - CheckPointer(pStop, E_POINTER); - - // accept only relative, incremental, or absolute positioning - if(StopPosBits != StopFlags) { - return E_INVALIDARG; - } - } - - if(CurrentFlags) { - CheckPointer(pCurrent, E_POINTER); - if(StartPosBits != AM_SEEKING_AbsolutePositioning && - StartPosBits != AM_SEEKING_RelativePositioning) { - return E_INVALIDARG; - } - } - - - // scope for autolock - { - CAutoLock lock(m_pLock); - - // set start position - if(StartPosBits == AM_SEEKING_AbsolutePositioning) - { - m_rtStart = *pCurrent; - } - else if(StartPosBits == AM_SEEKING_RelativePositioning) - { - m_rtStart += *pCurrent; - } - - // set stop position - if(StopPosBits == AM_SEEKING_AbsolutePositioning) - { - m_rtStop = *pStop; - } - else if(StopPosBits == AM_SEEKING_IncrementalPositioning) - { - m_rtStop = m_rtStart + *pStop; - } - else if(StopPosBits == AM_SEEKING_RelativePositioning) - { - m_rtStop = m_rtStop + *pStop; - } - } - - - HRESULT hr = S_OK; - if(SUCCEEDED(hr) && StopPosBits) { - hr = ChangeStop(); - } - if(StartPosBits) { - hr = ChangeStart(); - } - - return hr; -} - - -HRESULT CSourceSeeking::GetPositions( LONGLONG * pCurrent, LONGLONG * pStop ) -{ - if(pCurrent) { - *pCurrent = m_rtStart; - } - if(pStop) { - *pStop = m_rtStop; - } - - return S_OK;; -} - - -HRESULT CSourceSeeking::GetAvailable( LONGLONG * pEarliest, LONGLONG * pLatest ) -{ - if(pEarliest) { - *pEarliest = 0; - } - if(pLatest) { - CAutoLock lock(m_pLock); - *pLatest = m_rtDuration; - } - return S_OK; -} - -HRESULT CSourceSeeking::SetRate( double dRate) -{ - { - CAutoLock lock(m_pLock); - m_dRateSeeking = dRate; - } - return ChangeRate(); -} - -HRESULT CSourceSeeking::GetRate( double * pdRate) -{ - CheckPointer(pdRate, E_POINTER); - CAutoLock lock(m_pLock); - *pdRate = m_dRateSeeking; - return S_OK; -} - -HRESULT CSourceSeeking::GetPreroll(LONGLONG *pPreroll) -{ - CheckPointer(pPreroll, E_POINTER); - *pPreroll = 0; - return S_OK; -} - - - - - -// --- CSourcePosition implementation ---------- - - -CSourcePosition::CSourcePosition(const TCHAR * pName, - LPUNKNOWN pUnk, - HRESULT* phr, - CCritSec * pLock) : - CMediaPosition(pName, pUnk), - m_pLock(pLock), - m_Start(CRefTime((LONGLONG)0)) -{ - m_Stop = _I64_MAX; - m_Rate = 1.0; -} - - -STDMETHODIMP -CSourcePosition::get_Duration(REFTIME * plength) -{ - CheckPointer(plength,E_POINTER); - ValidateReadWritePtr(plength,sizeof(REFTIME)); - CAutoLock lock(m_pLock); - - *plength = m_Duration; - return S_OK; -} - - -STDMETHODIMP -CSourcePosition::put_CurrentPosition(REFTIME llTime) -{ - m_pLock->Lock(); - m_Start = llTime; - m_pLock->Unlock(); - - return ChangeStart(); -} - - -STDMETHODIMP -CSourcePosition::get_StopTime(REFTIME * pllTime) -{ - CheckPointer(pllTime,E_POINTER); - ValidateReadWritePtr(pllTime,sizeof(REFTIME)); - CAutoLock lock(m_pLock); - - *pllTime = m_Stop; - return S_OK; -} - - -STDMETHODIMP -CSourcePosition::put_StopTime(REFTIME llTime) -{ - m_pLock->Lock(); - m_Stop = llTime; - m_pLock->Unlock(); - - return ChangeStop(); -} - - -STDMETHODIMP -CSourcePosition::get_PrerollTime(REFTIME * pllTime) -{ - CheckPointer(pllTime,E_POINTER); - ValidateReadWritePtr(pllTime,sizeof(REFTIME)); - return E_NOTIMPL; -} - - -STDMETHODIMP -CSourcePosition::put_PrerollTime(REFTIME llTime) -{ - return E_NOTIMPL; -} - - -STDMETHODIMP -CSourcePosition::get_Rate(double * pdRate) -{ - CheckPointer(pdRate,E_POINTER); - ValidateReadWritePtr(pdRate,sizeof(double)); - CAutoLock lock(m_pLock); - - *pdRate = m_Rate; - return S_OK; -} - - -STDMETHODIMP -CSourcePosition::put_Rate(double dRate) -{ - m_pLock->Lock(); - m_Rate = dRate; - m_pLock->Unlock(); - - return ChangeRate(); -} - - -// By default we can seek forwards - -STDMETHODIMP -CSourcePosition::CanSeekForward(LONG *pCanSeekForward) -{ - CheckPointer(pCanSeekForward,E_POINTER); - *pCanSeekForward = OATRUE; - return S_OK; -} - - -// By default we can seek backwards - -STDMETHODIMP -CSourcePosition::CanSeekBackward(LONG *pCanSeekBackward) -{ - CheckPointer(pCanSeekBackward,E_POINTER); - *pCanSeekBackward = OATRUE; - return S_OK; -} - - -// --- Implementation of CBasicAudio class ---------- - - -CBasicAudio::CBasicAudio(const TCHAR * pName,LPUNKNOWN punk) : - CUnknown(pName, punk) -{ -} - -// overriden to publicise our interfaces - -STDMETHODIMP -CBasicAudio::NonDelegatingQueryInterface(REFIID riid, void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IBasicAudio) { - return GetInterface( (IBasicAudio *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -STDMETHODIMP -CBasicAudio::GetTypeInfoCount(UINT * pctinfo) -{ - return m_basedisp.GetTypeInfoCount(pctinfo); -} - - -STDMETHODIMP -CBasicAudio::GetTypeInfo( - UINT itinfo, - LCID lcid, - ITypeInfo ** pptinfo) -{ - return m_basedisp.GetTypeInfo( - IID_IBasicAudio, - itinfo, - lcid, - pptinfo); -} - - -STDMETHODIMP -CBasicAudio::GetIDsOfNames( - REFIID riid, - OLECHAR ** rgszNames, - UINT cNames, - LCID lcid, - DISPID * rgdispid) -{ - return m_basedisp.GetIDsOfNames( - IID_IBasicAudio, - rgszNames, - cNames, - lcid, - rgdispid); -} - - -STDMETHODIMP -CBasicAudio::Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - DISPPARAMS * pdispparams, - VARIANT * pvarResult, - EXCEPINFO * pexcepinfo, - UINT * puArgErr) -{ - // this parameter is a dead leftover from an earlier interface - if (IID_NULL != riid) { - return DISP_E_UNKNOWNINTERFACE; - } - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(0, lcid, &pti); - - if (FAILED(hr)) { - return hr; - } - - hr = pti->Invoke( - (IBasicAudio *)this, - dispidMember, - wFlags, - pdispparams, - pvarResult, - pexcepinfo, - puArgErr); - - pti->Release(); - return hr; -} - - -// --- IVideoWindow implementation ---------- - -CBaseVideoWindow::CBaseVideoWindow(const TCHAR * pName,LPUNKNOWN punk) : - CUnknown(pName, punk) -{ -} - - -// overriden to publicise our interfaces - -STDMETHODIMP -CBaseVideoWindow::NonDelegatingQueryInterface(REFIID riid, void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IVideoWindow) { - return GetInterface( (IVideoWindow *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -STDMETHODIMP -CBaseVideoWindow::GetTypeInfoCount(UINT * pctinfo) -{ - return m_basedisp.GetTypeInfoCount(pctinfo); -} - - -STDMETHODIMP -CBaseVideoWindow::GetTypeInfo( - UINT itinfo, - LCID lcid, - ITypeInfo ** pptinfo) -{ - return m_basedisp.GetTypeInfo( - IID_IVideoWindow, - itinfo, - lcid, - pptinfo); -} - - -STDMETHODIMP -CBaseVideoWindow::GetIDsOfNames( - REFIID riid, - OLECHAR ** rgszNames, - UINT cNames, - LCID lcid, - DISPID * rgdispid) -{ - return m_basedisp.GetIDsOfNames( - IID_IVideoWindow, - rgszNames, - cNames, - lcid, - rgdispid); -} - - -STDMETHODIMP -CBaseVideoWindow::Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - DISPPARAMS * pdispparams, - VARIANT * pvarResult, - EXCEPINFO * pexcepinfo, - UINT * puArgErr) -{ - // this parameter is a dead leftover from an earlier interface - if (IID_NULL != riid) { - return DISP_E_UNKNOWNINTERFACE; - } - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(0, lcid, &pti); - - if (FAILED(hr)) { - return hr; - } - - hr = pti->Invoke( - (IVideoWindow *)this, - dispidMember, - wFlags, - pdispparams, - pvarResult, - pexcepinfo, - puArgErr); - - pti->Release(); - return hr; -} - - -// --- IBasicVideo implementation ---------- - - -CBaseBasicVideo::CBaseBasicVideo(const TCHAR * pName,LPUNKNOWN punk) : - CUnknown(pName, punk) -{ -} - - -// overriden to publicise our interfaces - -STDMETHODIMP -CBaseBasicVideo::NonDelegatingQueryInterface(REFIID riid, void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IBasicVideo || riid == IID_IBasicVideo2) { - return GetInterface( static_cast(this), ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -STDMETHODIMP -CBaseBasicVideo::GetTypeInfoCount(UINT * pctinfo) -{ - return m_basedisp.GetTypeInfoCount(pctinfo); -} - - -STDMETHODIMP -CBaseBasicVideo::GetTypeInfo( - UINT itinfo, - LCID lcid, - ITypeInfo ** pptinfo) -{ - return m_basedisp.GetTypeInfo( - IID_IBasicVideo, - itinfo, - lcid, - pptinfo); -} - - -STDMETHODIMP -CBaseBasicVideo::GetIDsOfNames( - REFIID riid, - OLECHAR ** rgszNames, - UINT cNames, - LCID lcid, - DISPID * rgdispid) -{ - return m_basedisp.GetIDsOfNames( - IID_IBasicVideo, - rgszNames, - cNames, - lcid, - rgdispid); -} - - -STDMETHODIMP -CBaseBasicVideo::Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - DISPPARAMS * pdispparams, - VARIANT * pvarResult, - EXCEPINFO * pexcepinfo, - UINT * puArgErr) -{ - // this parameter is a dead leftover from an earlier interface - if (IID_NULL != riid) { - return DISP_E_UNKNOWNINTERFACE; - } - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(0, lcid, &pti); - - if (FAILED(hr)) { - return hr; - } - - hr = pti->Invoke( - (IBasicVideo *)this, - dispidMember, - wFlags, - pdispparams, - pvarResult, - pexcepinfo, - puArgErr); - - pti->Release(); - return hr; -} - - -// --- Implementation of Deferred Commands ---------- - - -CDispParams::CDispParams(UINT nArgs, VARIANT* pArgs, HRESULT *phr) -{ - cNamedArgs = 0; - rgdispidNamedArgs = NULL; - cArgs = nArgs; - - if (cArgs) { - rgvarg = new VARIANT[cArgs]; - if (NULL == rgvarg) { - cArgs = 0; - if (phr) { - *phr = E_OUTOFMEMORY; - } - return; - } - - for (UINT i = 0; i < cArgs; i++) { - - VARIANT * pDest = &rgvarg[i]; - VARIANT * pSrc = &pArgs[i]; - - pDest->vt = pSrc->vt; - switch(pDest->vt) { - - case VT_I4: - pDest->lVal = pSrc->lVal; - break; - - case VT_UI1: - pDest->bVal = pSrc->bVal; - break; - - case VT_I2: - pDest->iVal = pSrc->iVal; - break; - - case VT_R4: - pDest->fltVal = pSrc->fltVal; - break; - - case VT_R8: - pDest->dblVal = pSrc->dblVal; - break; - - case VT_BOOL: - pDest->boolVal = pSrc->boolVal; - break; - - case VT_ERROR: - pDest->scode = pSrc->scode; - break; - - case VT_CY: - pDest->cyVal = pSrc->cyVal; - break; - - case VT_DATE: - pDest->date = pSrc->date; - break; - - case VT_BSTR: - if (pSrc->bstrVal == NULL) { - pDest->bstrVal = NULL; - } else { - - // a BSTR is a WORD followed by a UNICODE string. - // the pointer points just after the WORD - - WORD len = * (WORD*) (pSrc->bstrVal - (sizeof(WORD) / sizeof(OLECHAR))); - OLECHAR* pch = new OLECHAR[len + (sizeof(WORD)/sizeof(OLECHAR))]; - if (pch) { - WORD *pui = (WORD*)pch; - *pui = len; - pDest->bstrVal = pch + (sizeof(WORD)/sizeof(OLECHAR)); - CopyMemory(pDest->bstrVal, pSrc->bstrVal, len*sizeof(OLECHAR)); - } else { - cArgs = i; - if (phr) { - *phr = E_OUTOFMEMORY; - } - } - } - pDest->bstrVal = pSrc->bstrVal; - break; - - case VT_UNKNOWN: - pDest->punkVal = pSrc->punkVal; - pDest->punkVal->AddRef(); - break; - - case VT_DISPATCH: - pDest->pdispVal = pSrc->pdispVal; - pDest->pdispVal->AddRef(); - break; - - default: - // a type we haven't got round to adding yet! - ASSERT(0); - break; - } - } - - } else { - rgvarg = NULL; - } - -} - - -CDispParams::~CDispParams() -{ - for (UINT i = 0; i < cArgs; i++) { - switch(rgvarg[i].vt) { - case VT_BSTR: - if (rgvarg[i].bstrVal != NULL) { - OLECHAR * pch = rgvarg[i].bstrVal - (sizeof(WORD)/sizeof(OLECHAR)); - delete pch; - } - break; - - case VT_UNKNOWN: - rgvarg[i].punkVal->Release(); - break; - - case VT_DISPATCH: - rgvarg[i].pdispVal->Release(); - break; - } - } - delete[] rgvarg; -} - - -// lifetime is controlled by refcounts (see defer.h) - -CDeferredCommand::CDeferredCommand( - CCmdQueue * pQ, - LPUNKNOWN pUnk, - HRESULT * phr, - LPUNKNOWN pUnkExecutor, - REFTIME time, - GUID* iid, - long dispidMethod, - short wFlags, - long nArgs, - VARIANT* pDispParams, - VARIANT* pvarResult, - short* puArgErr, - BOOL bStream - ) : - CUnknown(NAME("DeferredCommand"), pUnk), - m_pQueue(pQ), - m_pUnk(pUnkExecutor), - m_iid(iid), - m_dispidMethod(dispidMethod), - m_wFlags(wFlags), - m_DispParams(nArgs, pDispParams, phr), - m_pvarResult(pvarResult), - m_bStream(bStream), - m_hrResult(E_ABORT) - -{ - // convert REFTIME to REFERENCE_TIME - COARefTime convertor(time); - m_time = convertor; - - // no check of time validity - it's ok to queue a command that's - // already late - - // check iid is supportable on pUnk by QueryInterface for it - IUnknown * pInterface; - HRESULT hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface); - if (FAILED(hr)) { - *phr = hr; - return; - } - pInterface->Release(); - - - // !!! check dispidMethod and param/return types using typelib - ITypeInfo *pti; - hr = m_Dispatch.GetTypeInfo(*iid, 0, 0, &pti); - if (FAILED(hr)) { - *phr = hr; - return; - } - // !!! some sort of ITypeInfo validity check here - pti->Release(); - - - // Fix up the dispid for put and get - if (wFlags == DISPATCH_PROPERTYPUT) { - m_DispParams.cNamedArgs = 1; - m_DispId = DISPID_PROPERTYPUT; - m_DispParams.rgdispidNamedArgs = &m_DispId; - } - - // all checks ok - add to queue - hr = pQ->Insert(this); - if (FAILED(hr)) { - *phr = hr; - } -} - - -// refcounts are held by caller of InvokeAt... and by list. So if -// we get here, we can't be on the list - -#if 0 -CDeferredCommand::~CDeferredCommand() -{ - // this assert is invalid since if the queue is deleted while we are - // still on the queue, we will have been removed by the queue and this - // m_pQueue will not have been modified. - // ASSERT(m_pQueue == NULL); - - // we don't hold a ref count on pUnk, which is the object that should - // execute the command. - // This is because there would otherwise be a circular refcount problem - // since pUnk probably owns the CmdQueue object that has a refcount - // on us. - // The lifetime of pUnk is guaranteed by it being part of, or lifetime - // controlled by, our parent object. As long as we are on the list, pUnk - // must be valid. Once we are off the list, we do not use pUnk. - -} -#endif - - -// overriden to publicise our interfaces - -STDMETHODIMP -CDeferredCommand::NonDelegatingQueryInterface(REFIID riid, void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IDeferredCommand) { - return GetInterface( (IDeferredCommand *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -// remove from q. this will reduce the refcount by one (since the q -// holds a count) but can't make us go away since he must have a -// refcount in order to call this method. - -STDMETHODIMP -CDeferredCommand::Cancel() -{ - if (m_pQueue == NULL) { - return VFW_E_ALREADY_CANCELLED; - } - - HRESULT hr = m_pQueue->Remove(this); - if (FAILED(hr)) { - return hr; - } - - m_pQueue = NULL; - return S_OK; -} - - -STDMETHODIMP -CDeferredCommand::Confidence(LONG* pConfidence) -{ - return E_NOTIMPL; -} - - -STDMETHODIMP -CDeferredCommand::GetHResult(HRESULT * phrResult) -{ - CheckPointer(phrResult,E_POINTER); - ValidateReadWritePtr(phrResult,sizeof(HRESULT)); - - if (m_pQueue != NULL) { - return E_ABORT; - } - *phrResult = m_hrResult; - return S_OK; -} - - -// set the time to be a new time (checking that it is valid) and -// then requeue - -STDMETHODIMP -CDeferredCommand::Postpone(REFTIME newtime) -{ - - // check that this time is not past - // convert REFTIME to REFERENCE_TIME - COARefTime convertor(newtime); - - // check that the time has not passed - if (m_pQueue->CheckTime(convertor, IsStreamTime())) { - return VFW_E_TIME_ALREADY_PASSED; - } - - // extract from list - HRESULT hr = m_pQueue->Remove(this); - if (FAILED(hr)) { - return hr; - } - - // change time - m_time = convertor; - - // requeue - hr = m_pQueue->Insert(this); - - return hr; -} - - -HRESULT -CDeferredCommand::Invoke() -{ - // check that we are still outstanding - if (m_pQueue == NULL) { - return VFW_E_ALREADY_CANCELLED; - } - - // get the type info - ITypeInfo* pti; - HRESULT hr = m_Dispatch.GetTypeInfo(GetIID(), 0, 0, &pti); - if (FAILED(hr)) { - return hr; - } - - // qi for the expected interface and then invoke it. Note that we have to - // treat the returned interface as IUnknown since we don't know its type. - IUnknown* pInterface; - - hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface); - if (FAILED(hr)) { - pti->Release(); - return hr; - } - - EXCEPINFO expinfo; - UINT uArgErr; - m_hrResult = pti->Invoke( - pInterface, - GetMethod(), - GetFlags(), - GetParams(), - GetResult(), - &expinfo, - &uArgErr); - - // release the interface we QI'd for - pInterface->Release(); - pti->Release(); - - - // remove from list whether or not successful - // or we loop indefinitely - hr = m_pQueue->Remove(this); - m_pQueue = NULL; - return hr; -} - - - -// --- CCmdQueue methods ---------- - - -CCmdQueue::CCmdQueue() : - m_listPresentation(NAME("Presentation time command list")), - m_listStream(NAME("Stream time command list")), - m_evDue(TRUE), // manual reset - m_dwAdvise(0), - m_pClock(NULL), - m_bRunning(FALSE) -{ -} - - -CCmdQueue::~CCmdQueue() -{ - // empty all our lists - - // we hold a refcount on each, so traverse and Release each - // entry then RemoveAll to empty the list - WXLIST_POSITION pos = m_listPresentation.GetHeadPosition(); - - while(pos) { - CDeferredCommand* pCmd = m_listPresentation.GetNext(pos); - pCmd->Release(); - } - m_listPresentation.RemoveAll(); - - pos = m_listStream.GetHeadPosition(); - - while(pos) { - CDeferredCommand* pCmd = m_listStream.GetNext(pos); - pCmd->Release(); - } - m_listStream.RemoveAll(); - - if (m_pClock) { - if (m_dwAdvise) { - m_pClock->Unadvise(m_dwAdvise); - m_dwAdvise = 0; - } - m_pClock->Release(); - } -} - - -// returns a new CDeferredCommand object that will be initialised with -// the parameters and will be added to the queue during construction. -// returns S_OK if successfully created otherwise an error and -// no object has been queued. - -HRESULT -CCmdQueue::New( - CDeferredCommand **ppCmd, - LPUNKNOWN pUnk, // this object will execute command - REFTIME time, - GUID* iid, - long dispidMethod, - short wFlags, - long cArgs, - VARIANT* pDispParams, - VARIANT* pvarResult, - short* puArgErr, - BOOL bStream -) -{ - CAutoLock lock(&m_Lock); - - HRESULT hr = S_OK; - *ppCmd = NULL; - - CDeferredCommand* pCmd; - pCmd = new CDeferredCommand( - this, - NULL, // not aggregated - &hr, - pUnk, // this guy will execute - time, - iid, - dispidMethod, - wFlags, - cArgs, - pDispParams, - pvarResult, - puArgErr, - bStream); - - if (pCmd == NULL) { - hr = E_OUTOFMEMORY; - } else { - *ppCmd = pCmd; - } - return hr; -} - - -HRESULT -CCmdQueue::Insert(CDeferredCommand* pCmd) -{ - CAutoLock lock(&m_Lock); - - // addref the item - pCmd->AddRef(); - - CGenericList * pList; - if (pCmd->IsStreamTime()) { - pList = &m_listStream; - } else { - pList = &m_listPresentation; - } - WXLIST_POSITION pos = pList->GetHeadPosition(); - - // seek past all items that are before us - while (pos && - (pList->Get(pos)->GetTime() <= pCmd->GetTime())) { - - pList->GetNext(pos); - } - - // now at end of list or in front of items that come later - if (!pos) { - pList->AddTail(pCmd); - } else { - pList->AddBefore(pos, pCmd); - } - - SetTimeAdvise(); - return S_OK; -} - - -HRESULT -CCmdQueue::Remove(CDeferredCommand* pCmd) -{ - CAutoLock lock(&m_Lock); - HRESULT hr = S_OK; - - CGenericList * pList; - if (pCmd->IsStreamTime()) { - pList = &m_listStream; - } else { - pList = &m_listPresentation; - } - WXLIST_POSITION pos = pList->GetHeadPosition(); - - // traverse the list - while (pos && (pList->Get(pos) != pCmd)) { - pList->GetNext(pos); - } - - // did we drop off the end? - if (!pos) { - hr = VFW_E_NOT_FOUND; - } else { - - // found it - now take off list - pList->Remove(pos); - - // Insert did an AddRef, so release it - pCmd->Release(); - - // check that timer request is still for earliest time - SetTimeAdvise(); - } - return hr; -} - - -// set the clock used for timing - -HRESULT -CCmdQueue::SetSyncSource(IReferenceClock* pClock) -{ - CAutoLock lock(&m_Lock); - - // addref the new clock first in case they are the same - if (pClock) { - pClock->AddRef(); - } - - // kill any advise on the old clock - if (m_pClock) { - if (m_dwAdvise) { - m_pClock->Unadvise(m_dwAdvise); - m_dwAdvise = 0; - } - m_pClock->Release(); - } - m_pClock = pClock; - - // set up a new advise - SetTimeAdvise(); - return S_OK; -} - - -// set up a timer event with the reference clock - -void -CCmdQueue::SetTimeAdvise(void) -{ - // make sure we have a clock to use - if (!m_pClock) { - return; - } - - // reset the event whenever we are requesting a new signal - m_evDue.Reset(); - - // time 0 is earliest - CRefTime current; - - // find the earliest presentation time - if (m_listPresentation.GetCount() > 0) { - - WXLIST_POSITION pos = m_listPresentation.GetHeadPosition(); - current = m_listPresentation.Get(pos)->GetTime(); - } - - // if we're running, check the stream times too - if (m_bRunning) { - - CRefTime t; - - if (m_listStream.GetCount() > 0) { - - WXLIST_POSITION pos = m_listStream.GetHeadPosition(); - t = m_listStream.Get(pos)->GetTime(); - - // add on stream time offset to get presentation time - t += m_StreamTimeOffset; - - // is this earlier? - if ((current == TimeZero) || (t < current)) { - current = t; - } - } - } - - // need to change? - if ((current > TimeZero) && (current != m_tCurrentAdvise)) { - if (m_dwAdvise) { - m_pClock->Unadvise(m_dwAdvise); - // reset the event whenever we are requesting a new signal - m_evDue.Reset(); - } - - // ask for time advice - the first two params are either - // stream time offset and stream time or - // presentation time and 0. we always use the latter - HRESULT hr = m_pClock->AdviseTime( - (REFERENCE_TIME)current, - TimeZero, - (HEVENT) HANDLE(m_evDue), - &m_dwAdvise); - - ASSERT(SUCCEEDED(hr)); - m_tCurrentAdvise = current; - } -} - - -// switch to run mode. Streamtime to Presentation time mapping known. - -HRESULT -CCmdQueue::Run(REFERENCE_TIME tStreamTimeOffset) -{ - CAutoLock lock(&m_Lock); - - m_StreamTimeOffset = tStreamTimeOffset; - m_bRunning = TRUE; - - // ensure advise is accurate - SetTimeAdvise(); - return S_OK; -} - - -// switch to Stopped or Paused mode. Time mapping not known. - -HRESULT -CCmdQueue::EndRun() -{ - CAutoLock lock(&m_Lock); - - m_bRunning = FALSE; - - // check timer setting - stream times - SetTimeAdvise(); - return S_OK; -} - - -// return a pointer to the next due command. Blocks for msTimeout -// milliseconds until there is a due command. -// Stream-time commands will only become due between Run and Endrun calls. -// The command remains queued until invoked or cancelled. -// Returns E_ABORT if timeout occurs, otherwise S_OK (or other error). -// -// returns an AddRef'd object - -HRESULT -CCmdQueue::GetDueCommand(CDeferredCommand ** ppCmd, long msTimeout) -{ - // loop until we timeout or find a due command - for (;;) { - - { - CAutoLock lock(&m_Lock); - - - // find the earliest command - CDeferredCommand * pCmd = NULL; - - // check the presentation time and the - // stream time list to find the earliest - - if (m_listPresentation.GetCount() > 0) { - WXLIST_POSITION pos = m_listPresentation.GetHeadPosition(); - pCmd = m_listPresentation.Get(pos); - } - - if (m_bRunning && (m_listStream.GetCount() > 0)) { - WXLIST_POSITION pos = m_listStream.GetHeadPosition(); - CDeferredCommand* pStrm = m_listStream.Get(pos); - - CRefTime t = pStrm->GetTime() + m_StreamTimeOffset; - if (!pCmd || (t < pCmd->GetTime())) { - pCmd = pStrm; - } - } - - // if we have found one, is it due? - if (pCmd) { - if (CheckTime(pCmd->GetTime(), pCmd->IsStreamTime())) { - - // yes it's due - addref it - pCmd->AddRef(); - *ppCmd = pCmd; - return S_OK; - } - } - } - - // block until the advise is signalled - if (WaitForSingleObject(m_evDue, msTimeout) != WAIT_OBJECT_0) { - return E_ABORT; - } - } -} - - -// return a pointer to a command that will be due for a given time. -// Pass in a stream time here. The stream time offset will be passed -// in via the Run method. -// Commands remain queued until invoked or cancelled. -// This method will not block. It will report E_ABORT if there are no -// commands due yet. -// -// returns an AddRef'd object - -HRESULT -CCmdQueue::GetCommandDueFor(REFERENCE_TIME rtStream, CDeferredCommand**ppCmd) -{ - CAutoLock lock(&m_Lock); - - CRefTime tStream(rtStream); - - // find the earliest stream and presentation time commands - CDeferredCommand* pStream = NULL; - if (m_listStream.GetCount() > 0) { - WXLIST_POSITION pos = m_listStream.GetHeadPosition(); - pStream = m_listStream.Get(pos); - } - CDeferredCommand* pPresent = NULL; - if (m_listPresentation.GetCount() > 0) { - WXLIST_POSITION pos = m_listPresentation.GetHeadPosition(); - pPresent = m_listPresentation.Get(pos); - } - - // is there a presentation time that has passed already - if (pPresent && CheckTime(pPresent->GetTime(), FALSE)) { - pPresent->AddRef(); - *ppCmd = pPresent; - return S_OK; - } - - // is there a stream time command due before this stream time - if (pStream && (pStream->GetTime() <= tStream)) { - pPresent->AddRef(); - *ppCmd = pStream; - return S_OK; - } - - // if we are running, we can map presentation times to - // stream time. In this case, is there a presentation time command - // that will be due before this stream time is presented? - if (m_bRunning && pPresent) { - - // this stream time will appear at... - tStream += m_StreamTimeOffset; - - // due before that? - if (pPresent->GetTime() <= tStream) { - *ppCmd = pPresent; - return S_OK; - } - } - - // no commands due yet - return VFW_E_NOT_FOUND; -} - +//------------------------------------------------------------------------------ +// File: CtlUtil.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Base classes implementing IDispatch parsing for the basic control dual +// interfaces. Derive from these and implement just the custom method and +// property methods. We also implement CPosPassThru that can be used by +// renderers and transforms to pass by IMediaPosition and IMediaSeeking + + +#include "streams.h" +#include +#include "seekpt.h" + +// 'bool' non standard reserved word +#pragma warning(disable:4237) + + +// --- CBaseDispatch implementation ---------- +CBaseDispatch::~CBaseDispatch() +{ + if (m_pti) { + m_pti->Release(); + } +} + + +// return 1 if we support GetTypeInfo + +STDMETHODIMP +CBaseDispatch::GetTypeInfoCount(UINT * pctinfo) +{ + CheckPointer(pctinfo,E_POINTER); + ValidateReadWritePtr(pctinfo,sizeof(UINT *)); + *pctinfo = 1; + return S_OK; +} + + +typedef HRESULT (STDAPICALLTYPE *LPLOADTYPELIB)( + const OLECHAR FAR *szFile, + ITypeLib FAR* FAR* pptlib); + +typedef HRESULT (STDAPICALLTYPE *LPLOADREGTYPELIB)(REFGUID rguid, + WORD wVerMajor, + WORD wVerMinor, + LCID lcid, + ITypeLib FAR* FAR* pptlib); + +// attempt to find our type library + +STDMETHODIMP +CBaseDispatch::GetTypeInfo( + REFIID riid, + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo) +{ + CheckPointer(pptinfo,E_POINTER); + ValidateReadWritePtr(pptinfo,sizeof(ITypeInfo *)); + HRESULT hr; + + *pptinfo = NULL; + + // we only support one type element + if (0 != itinfo) { + return TYPE_E_ELEMENTNOTFOUND; + } + + if (NULL == pptinfo) { + return E_POINTER; + } + + // always look for neutral + if (NULL == m_pti) { + + LPLOADTYPELIB lpfnLoadTypeLib; + LPLOADREGTYPELIB lpfnLoadRegTypeLib; + ITypeLib *ptlib; + HINSTANCE hInst; + + static const char szTypeLib[] = "LoadTypeLib"; + static const char szRegTypeLib[] = "LoadRegTypeLib"; + static const WCHAR szControl[] = L"control.tlb"; + + // + // Try to get the Ole32Aut.dll module handle. + // + + hInst = LoadOLEAut32(); + if (hInst == NULL) { + DWORD dwError = GetLastError(); + return AmHresultFromWin32(dwError); + } + lpfnLoadRegTypeLib = (LPLOADREGTYPELIB)GetProcAddress(hInst, + szRegTypeLib); + if (lpfnLoadRegTypeLib == NULL) { + DWORD dwError = GetLastError(); + return AmHresultFromWin32(dwError); + } + + hr = (*lpfnLoadRegTypeLib)(LIBID_QuartzTypeLib, 1, 0, // version 1.0 + lcid, &ptlib); + + if (FAILED(hr)) { + + // attempt to load directly - this will fill the + // registry in if it finds it + + lpfnLoadTypeLib = (LPLOADTYPELIB)GetProcAddress(hInst, szTypeLib); + if (lpfnLoadTypeLib == NULL) { + DWORD dwError = GetLastError(); + return AmHresultFromWin32(dwError); + } + + hr = (*lpfnLoadTypeLib)(szControl, &ptlib); + if (FAILED(hr)) { + return hr; + } + } + + hr = ptlib->GetTypeInfoOfGuid( + riid, + &m_pti); + + ptlib->Release(); + + if (FAILED(hr)) { + return hr; + } + } + + *pptinfo = m_pti; + m_pti->AddRef(); + return S_OK; +} + + +STDMETHODIMP +CBaseDispatch::GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid) +{ + // although the IDispatch riid is dead, we use this to pass from + // the interface implementation class to us the iid we are talking about. + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(riid, 0, lcid, &pti); + + if (SUCCEEDED(hr)) { + hr = pti->GetIDsOfNames(rgszNames, cNames, rgdispid); + + pti->Release(); + } + return hr; +} + + +// --- CMediaControl implementation --------- + +CMediaControl::CMediaControl(const TCHAR * name,LPUNKNOWN pUnk) : + CUnknown(name, pUnk) +{ +} + +// expose our interfaces IMediaControl and IUnknown + +STDMETHODIMP +CMediaControl::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IMediaControl) { + return GetInterface( (IMediaControl *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// return 1 if we support GetTypeInfo + +STDMETHODIMP +CMediaControl::GetTypeInfoCount(UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +// attempt to find our type library + +STDMETHODIMP +CMediaControl::GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IMediaControl, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CMediaControl::GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IMediaControl, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CMediaControl::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IMediaControl *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- CMediaEvent implementation ---------- + + +CMediaEvent::CMediaEvent(const TCHAR * name,LPUNKNOWN pUnk) : + CUnknown(name, pUnk) +{ +} + + +// expose our interfaces IMediaEvent and IUnknown + +STDMETHODIMP +CMediaEvent::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IMediaEvent || riid == IID_IMediaEventEx) { + return GetInterface( (IMediaEventEx *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// return 1 if we support GetTypeInfo + +STDMETHODIMP +CMediaEvent::GetTypeInfoCount(UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +// attempt to find our type library + +STDMETHODIMP +CMediaEvent::GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IMediaEvent, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CMediaEvent::GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IMediaEvent, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CMediaEvent::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IMediaEvent *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- CMediaPosition implementation ---------- + + +CMediaPosition::CMediaPosition(const TCHAR * name,LPUNKNOWN pUnk) : + CUnknown(name, pUnk) +{ +} + +CMediaPosition::CMediaPosition(const TCHAR * name, + LPUNKNOWN pUnk, + HRESULT * phr) : + CUnknown(name, pUnk) +{ + UNREFERENCED_PARAMETER(phr); +} + + +// expose our interfaces IMediaPosition and IUnknown + +STDMETHODIMP +CMediaPosition::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IMediaPosition) { + return GetInterface( (IMediaPosition *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// return 1 if we support GetTypeInfo + +STDMETHODIMP +CMediaPosition::GetTypeInfoCount(UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +// attempt to find our type library + +STDMETHODIMP +CMediaPosition::GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IMediaPosition, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CMediaPosition::GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IMediaPosition, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CMediaPosition::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IMediaPosition *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- IMediaPosition and IMediaSeeking pass through class ---------- + + +CPosPassThru::CPosPassThru(const TCHAR *pName, + LPUNKNOWN pUnk, + HRESULT *phr, + IPin *pPin) : + CMediaPosition(pName,pUnk), + m_pPin(pPin) +{ + if (pPin == NULL) { + *phr = E_POINTER; + return; + } +} + + +// Expose our IMediaSeeking and IMediaPosition interfaces + +STDMETHODIMP +CPosPassThru::NonDelegatingQueryInterface(REFIID riid,void **ppv) +{ + CheckPointer(ppv,E_POINTER); + *ppv = NULL; + + if (riid == IID_IMediaSeeking) { + return GetInterface( static_cast(this), ppv); + } + return CMediaPosition::NonDelegatingQueryInterface(riid,ppv); +} + + +// Return the IMediaPosition interface from our peer + +HRESULT +CPosPassThru::GetPeer(IMediaPosition ** ppMP) +{ + *ppMP = NULL; + + IPin *pConnected; + HRESULT hr = m_pPin->ConnectedTo(&pConnected); + if (FAILED(hr)) { + return E_NOTIMPL; + } + IMediaPosition * pMP; + hr = pConnected->QueryInterface(IID_IMediaPosition, (void **) &pMP); + pConnected->Release(); + if (FAILED(hr)) { + return E_NOTIMPL; + } + + *ppMP = pMP; + return S_OK; +} + + +// Return the IMediaSeeking interface from our peer + +HRESULT +CPosPassThru::GetPeerSeeking(IMediaSeeking ** ppMS) +{ + *ppMS = NULL; + + IPin *pConnected; + HRESULT hr = m_pPin->ConnectedTo(&pConnected); + if (FAILED(hr)) { + return E_NOTIMPL; + } + IMediaSeeking * pMS; + hr = pConnected->QueryInterface(IID_IMediaSeeking, (void **) &pMS); + pConnected->Release(); + if (FAILED(hr)) { + return E_NOTIMPL; + } + + *ppMS = pMS; + return S_OK; +} + + +// --- IMediaSeeking methods ---------- + + +STDMETHODIMP +CPosPassThru::GetCapabilities(DWORD * pCaps) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->GetCapabilities(pCaps); + pMS->Release(); + return hr; +} + +STDMETHODIMP +CPosPassThru::CheckCapabilities(DWORD * pCaps) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->CheckCapabilities(pCaps); + pMS->Release(); + return hr; +} + +STDMETHODIMP +CPosPassThru::IsFormatSupported(const GUID * pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->IsFormatSupported(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::QueryPreferredFormat(GUID *pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->QueryPreferredFormat(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::SetTimeFormat(const GUID * pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->SetTimeFormat(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::GetTimeFormat(GUID *pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->GetTimeFormat(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::IsUsingTimeFormat(const GUID * pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->IsUsingTimeFormat(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::ConvertTimeFormat(LONGLONG * pTarget, const GUID * pTargetFormat, + LONGLONG Source, const GUID * pSourceFormat ) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat ); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::SetPositions( LONGLONG * pCurrent, DWORD CurrentFlags + , LONGLONG * pStop, DWORD StopFlags ) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->SetPositions(pCurrent, CurrentFlags, pStop, StopFlags ); + pMS->Release(); + return hr; +} + +STDMETHODIMP +CPosPassThru::GetPositions(LONGLONG *pCurrent, LONGLONG * pStop) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->GetPositions(pCurrent,pStop); + pMS->Release(); + return hr; +} + +HRESULT +CPosPassThru::GetSeekingLongLong +( HRESULT (__stdcall IMediaSeeking::*pMethod)( LONGLONG * ) +, LONGLONG * pll +) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (SUCCEEDED(hr)) + { + hr = (pMS->*pMethod)(pll); + pMS->Release(); + } + return hr; +} + +// If we don't have a current position then ask upstream + +STDMETHODIMP +CPosPassThru::GetCurrentPosition(LONGLONG *pCurrent) +{ + // Can we report the current position + HRESULT hr = GetMediaTime(pCurrent,NULL); + if (SUCCEEDED(hr)) hr = NOERROR; + else hr = GetSeekingLongLong( &IMediaSeeking::GetCurrentPosition, pCurrent ); + return hr; +} + + +STDMETHODIMP +CPosPassThru::GetStopPosition(LONGLONG *pStop) +{ + return GetSeekingLongLong( &IMediaSeeking::GetStopPosition, pStop );; +} + +STDMETHODIMP +CPosPassThru::GetDuration(LONGLONG *pDuration) +{ + return GetSeekingLongLong( &IMediaSeeking::GetDuration, pDuration );; +} + + +STDMETHODIMP +CPosPassThru::GetPreroll(LONGLONG *pllPreroll) +{ + return GetSeekingLongLong( &IMediaSeeking::GetPreroll, pllPreroll );; +} + + +STDMETHODIMP +CPosPassThru::GetAvailable( LONGLONG *pEarliest, LONGLONG *pLatest ) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->GetAvailable( pEarliest, pLatest ); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::GetRate(double * pdRate) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + hr = pMS->GetRate(pdRate); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::SetRate(double dRate) +{ + if (0.0 == dRate) { + return E_INVALIDARG; + } + + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + hr = pMS->SetRate(dRate); + pMS->Release(); + return hr; +} + + + + +// --- IMediaPosition methods ---------- + + +STDMETHODIMP +CPosPassThru::get_Duration(REFTIME * plength) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + + hr = pMP->get_Duration(plength); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::get_CurrentPosition(REFTIME * pllTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->get_CurrentPosition(pllTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::put_CurrentPosition(REFTIME llTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->put_CurrentPosition(llTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::get_StopTime(REFTIME * pllTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->get_StopTime(pllTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::put_StopTime(REFTIME llTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->put_StopTime(llTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::get_PrerollTime(REFTIME * pllTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->get_PrerollTime(pllTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::put_PrerollTime(REFTIME llTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->put_PrerollTime(llTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::get_Rate(double * pdRate) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->get_Rate(pdRate); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::put_Rate(double dRate) +{ + if (0.0 == dRate) { + return E_INVALIDARG; + } + + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->put_Rate(dRate); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::CanSeekForward(LONG *pCanSeekForward) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->CanSeekForward(pCanSeekForward); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::CanSeekBackward(LONG *pCanSeekBackward) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->CanSeekBackward(pCanSeekBackward); + pMP->Release(); + return hr; +} + + +// --- Implements the CRendererPosPassThru class ---------- + + +// Media times (eg current frame, field, sample etc) are passed through the +// filtergraph in media samples. When a renderer gets a sample with media +// times in it, it will call one of the RegisterMediaTime methods we expose +// (one takes an IMediaSample, the other takes the media times direct). We +// store the media times internally and return them in GetCurrentPosition. + +CRendererPosPassThru::CRendererPosPassThru(const TCHAR *pName, + LPUNKNOWN pUnk, + HRESULT *phr, + IPin *pPin) : + CPosPassThru(pName,pUnk,phr,pPin), + m_StartMedia(0), + m_EndMedia(0), + m_bReset(TRUE) +{ +} + + +// Sets the media times the object should report + +HRESULT +CRendererPosPassThru::RegisterMediaTime(IMediaSample *pMediaSample) +{ + ASSERT(pMediaSample); + LONGLONG StartMedia; + LONGLONG EndMedia; + + CAutoLock cAutoLock(&m_PositionLock); + + // Get the media times from the sample + + HRESULT hr = pMediaSample->GetTime(&StartMedia,&EndMedia); + if (FAILED(hr)) + { + ASSERT(hr == VFW_E_SAMPLE_TIME_NOT_SET); + return hr; + } + + m_StartMedia = StartMedia; + m_EndMedia = EndMedia; + m_bReset = FALSE; + return NOERROR; +} + + +// Sets the media times the object should report + +HRESULT +CRendererPosPassThru::RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime) +{ + CAutoLock cAutoLock(&m_PositionLock); + m_StartMedia = StartTime; + m_EndMedia = EndTime; + m_bReset = FALSE; + return NOERROR; +} + + +// Return the current media times registered in the object + +HRESULT +CRendererPosPassThru::GetMediaTime(LONGLONG *pStartTime,LONGLONG *pEndTime) +{ + ASSERT(pStartTime); + + CAutoLock cAutoLock(&m_PositionLock); + if (m_bReset == TRUE) { + return E_FAIL; + } + + // We don't have to return the end time + + HRESULT hr = ConvertTimeFormat( pStartTime, 0, m_StartMedia, &TIME_FORMAT_MEDIA_TIME ); + if (pEndTime && SUCCEEDED(hr)) { + hr = ConvertTimeFormat( pEndTime, 0, m_EndMedia, &TIME_FORMAT_MEDIA_TIME ); + } + return hr; +} + + +// Resets the media times we hold + +HRESULT +CRendererPosPassThru::ResetMediaTime() +{ + CAutoLock cAutoLock(&m_PositionLock); + m_StartMedia = 0; + m_EndMedia = 0; + m_bReset = TRUE; + return NOERROR; +} + +// Intended to be called by the owing filter during EOS processing so +// that the media times can be adjusted to the stop time. This ensures +// that the GetCurrentPosition will actully get to the stop position. +HRESULT +CRendererPosPassThru::EOS() +{ + HRESULT hr; + + if ( m_bReset == TRUE ) hr = E_FAIL; + else + { + LONGLONG llStop; + if SUCCEEDED(hr=GetStopPosition(&llStop)) + { + CAutoLock cAutoLock(&m_PositionLock); + m_StartMedia = + m_EndMedia = llStop; + } + } + return hr; +} + +// -- CSourceSeeking implementation ------------ + +CSourceSeeking::CSourceSeeking( + const TCHAR * pName, + LPUNKNOWN pUnk, + HRESULT* phr, + CCritSec * pLock) : + CUnknown(pName, pUnk), + m_pLock(pLock), + m_rtStart((long)0) +{ + m_rtStop = _I64_MAX / 2; + m_rtDuration = m_rtStop; + m_dRateSeeking = 1.0; + + m_dwSeekingCaps = AM_SEEKING_CanSeekForwards + | AM_SEEKING_CanSeekBackwards + | AM_SEEKING_CanSeekAbsolute + | AM_SEEKING_CanGetStopPos + | AM_SEEKING_CanGetDuration; +} + +HRESULT CSourceSeeking::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + if(riid == IID_IMediaSeeking) { + CheckPointer(ppv, E_POINTER); + return GetInterface(static_cast(this), ppv); + } + else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +HRESULT CSourceSeeking::IsFormatSupported(const GUID * pFormat) +{ + CheckPointer(pFormat, E_POINTER); + // only seeking in time (REFERENCE_TIME units) is supported + return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; +} + +HRESULT CSourceSeeking::QueryPreferredFormat(GUID *pFormat) +{ + CheckPointer(pFormat, E_POINTER); + *pFormat = TIME_FORMAT_MEDIA_TIME; + return S_OK; +} + +HRESULT CSourceSeeking::SetTimeFormat(const GUID * pFormat) +{ + CheckPointer(pFormat, E_POINTER); + + // nothing to set; just check that it's TIME_FORMAT_TIME + return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : E_INVALIDARG; +} + +HRESULT CSourceSeeking::IsUsingTimeFormat(const GUID * pFormat) +{ + CheckPointer(pFormat, E_POINTER); + return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; +} + +HRESULT CSourceSeeking::GetTimeFormat(GUID *pFormat) +{ + CheckPointer(pFormat, E_POINTER); + *pFormat = TIME_FORMAT_MEDIA_TIME; + return S_OK; +} + +HRESULT CSourceSeeking::GetDuration(LONGLONG *pDuration) +{ + CheckPointer(pDuration, E_POINTER); + CAutoLock lock(m_pLock); + *pDuration = m_rtDuration; + return S_OK; +} + +HRESULT CSourceSeeking::GetStopPosition(LONGLONG *pStop) +{ + CheckPointer(pStop, E_POINTER); + CAutoLock lock(m_pLock); + *pStop = m_rtStop; + return S_OK; +} + +HRESULT CSourceSeeking::GetCurrentPosition(LONGLONG *pCurrent) +{ + // GetCurrentPosition is typically supported only in renderers and + // not in source filters. + return E_NOTIMPL; +} + +HRESULT CSourceSeeking::GetCapabilities( DWORD * pCapabilities ) +{ + CheckPointer(pCapabilities, E_POINTER); + *pCapabilities = m_dwSeekingCaps; + return S_OK; +} + +HRESULT CSourceSeeking::CheckCapabilities( DWORD * pCapabilities ) +{ + CheckPointer(pCapabilities, E_POINTER); + + // make sure all requested capabilities are in our mask + return (~m_dwSeekingCaps & *pCapabilities) ? S_FALSE : S_OK; +} + +HRESULT CSourceSeeking::ConvertTimeFormat( LONGLONG * pTarget, const GUID * pTargetFormat, + LONGLONG Source, const GUID * pSourceFormat ) +{ + CheckPointer(pTarget, E_POINTER); + // format guids can be null to indicate current format + + // since we only support TIME_FORMAT_MEDIA_TIME, we don't really + // offer any conversions. + if(pTargetFormat == 0 || *pTargetFormat == TIME_FORMAT_MEDIA_TIME) + { + if(pSourceFormat == 0 || *pSourceFormat == TIME_FORMAT_MEDIA_TIME) + { + *pTarget = Source; + return S_OK; + } + } + + return E_INVALIDARG; +} + + +HRESULT CSourceSeeking::SetPositions( LONGLONG * pCurrent, DWORD CurrentFlags + , LONGLONG * pStop, DWORD StopFlags ) +{ + DWORD StopPosBits = StopFlags & AM_SEEKING_PositioningBitsMask; + DWORD StartPosBits = CurrentFlags & AM_SEEKING_PositioningBitsMask; + + if(StopFlags) { + CheckPointer(pStop, E_POINTER); + + // accept only relative, incremental, or absolute positioning + if(StopPosBits != StopFlags) { + return E_INVALIDARG; + } + } + + if(CurrentFlags) { + CheckPointer(pCurrent, E_POINTER); + if(StartPosBits != AM_SEEKING_AbsolutePositioning && + StartPosBits != AM_SEEKING_RelativePositioning) { + return E_INVALIDARG; + } + } + + + // scope for autolock + { + CAutoLock lock(m_pLock); + + // set start position + if(StartPosBits == AM_SEEKING_AbsolutePositioning) + { + m_rtStart = *pCurrent; + } + else if(StartPosBits == AM_SEEKING_RelativePositioning) + { + m_rtStart += *pCurrent; + } + + // set stop position + if(StopPosBits == AM_SEEKING_AbsolutePositioning) + { + m_rtStop = *pStop; + } + else if(StopPosBits == AM_SEEKING_IncrementalPositioning) + { + m_rtStop = m_rtStart + *pStop; + } + else if(StopPosBits == AM_SEEKING_RelativePositioning) + { + m_rtStop = m_rtStop + *pStop; + } + } + + + HRESULT hr = S_OK; + if(SUCCEEDED(hr) && StopPosBits) { + hr = ChangeStop(); + } + if(StartPosBits) { + hr = ChangeStart(); + } + + return hr; +} + + +HRESULT CSourceSeeking::GetPositions( LONGLONG * pCurrent, LONGLONG * pStop ) +{ + if(pCurrent) { + *pCurrent = m_rtStart; + } + if(pStop) { + *pStop = m_rtStop; + } + + return S_OK;; +} + + +HRESULT CSourceSeeking::GetAvailable( LONGLONG * pEarliest, LONGLONG * pLatest ) +{ + if(pEarliest) { + *pEarliest = 0; + } + if(pLatest) { + CAutoLock lock(m_pLock); + *pLatest = m_rtDuration; + } + return S_OK; +} + +HRESULT CSourceSeeking::SetRate( double dRate) +{ + { + CAutoLock lock(m_pLock); + m_dRateSeeking = dRate; + } + return ChangeRate(); +} + +HRESULT CSourceSeeking::GetRate( double * pdRate) +{ + CheckPointer(pdRate, E_POINTER); + CAutoLock lock(m_pLock); + *pdRate = m_dRateSeeking; + return S_OK; +} + +HRESULT CSourceSeeking::GetPreroll(LONGLONG *pPreroll) +{ + CheckPointer(pPreroll, E_POINTER); + *pPreroll = 0; + return S_OK; +} + + + + + +// --- CSourcePosition implementation ---------- + + +CSourcePosition::CSourcePosition(const TCHAR * pName, + LPUNKNOWN pUnk, + HRESULT* phr, + CCritSec * pLock) : + CMediaPosition(pName, pUnk), + m_pLock(pLock), + m_Start(CRefTime((LONGLONG)0)) +{ + m_Stop = _I64_MAX; + m_Rate = 1.0; +} + + +STDMETHODIMP +CSourcePosition::get_Duration(REFTIME * plength) +{ + CheckPointer(plength,E_POINTER); + ValidateReadWritePtr(plength,sizeof(REFTIME)); + CAutoLock lock(m_pLock); + + *plength = m_Duration; + return S_OK; +} + + +STDMETHODIMP +CSourcePosition::put_CurrentPosition(REFTIME llTime) +{ + m_pLock->Lock(); + m_Start = llTime; + m_pLock->Unlock(); + + return ChangeStart(); +} + + +STDMETHODIMP +CSourcePosition::get_StopTime(REFTIME * pllTime) +{ + CheckPointer(pllTime,E_POINTER); + ValidateReadWritePtr(pllTime,sizeof(REFTIME)); + CAutoLock lock(m_pLock); + + *pllTime = m_Stop; + return S_OK; +} + + +STDMETHODIMP +CSourcePosition::put_StopTime(REFTIME llTime) +{ + m_pLock->Lock(); + m_Stop = llTime; + m_pLock->Unlock(); + + return ChangeStop(); +} + + +STDMETHODIMP +CSourcePosition::get_PrerollTime(REFTIME * pllTime) +{ + CheckPointer(pllTime,E_POINTER); + ValidateReadWritePtr(pllTime,sizeof(REFTIME)); + return E_NOTIMPL; +} + + +STDMETHODIMP +CSourcePosition::put_PrerollTime(REFTIME llTime) +{ + return E_NOTIMPL; +} + + +STDMETHODIMP +CSourcePosition::get_Rate(double * pdRate) +{ + CheckPointer(pdRate,E_POINTER); + ValidateReadWritePtr(pdRate,sizeof(double)); + CAutoLock lock(m_pLock); + + *pdRate = m_Rate; + return S_OK; +} + + +STDMETHODIMP +CSourcePosition::put_Rate(double dRate) +{ + m_pLock->Lock(); + m_Rate = dRate; + m_pLock->Unlock(); + + return ChangeRate(); +} + + +// By default we can seek forwards + +STDMETHODIMP +CSourcePosition::CanSeekForward(LONG *pCanSeekForward) +{ + CheckPointer(pCanSeekForward,E_POINTER); + *pCanSeekForward = OATRUE; + return S_OK; +} + + +// By default we can seek backwards + +STDMETHODIMP +CSourcePosition::CanSeekBackward(LONG *pCanSeekBackward) +{ + CheckPointer(pCanSeekBackward,E_POINTER); + *pCanSeekBackward = OATRUE; + return S_OK; +} + + +// --- Implementation of CBasicAudio class ---------- + + +CBasicAudio::CBasicAudio(const TCHAR * pName,LPUNKNOWN punk) : + CUnknown(pName, punk) +{ +} + +// overriden to publicise our interfaces + +STDMETHODIMP +CBasicAudio::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IBasicAudio) { + return GetInterface( (IBasicAudio *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +STDMETHODIMP +CBasicAudio::GetTypeInfoCount(UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +STDMETHODIMP +CBasicAudio::GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IBasicAudio, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CBasicAudio::GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IBasicAudio, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CBasicAudio::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IBasicAudio *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- IVideoWindow implementation ---------- + +CBaseVideoWindow::CBaseVideoWindow(const TCHAR * pName,LPUNKNOWN punk) : + CUnknown(pName, punk) +{ +} + + +// overriden to publicise our interfaces + +STDMETHODIMP +CBaseVideoWindow::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IVideoWindow) { + return GetInterface( (IVideoWindow *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +STDMETHODIMP +CBaseVideoWindow::GetTypeInfoCount(UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +STDMETHODIMP +CBaseVideoWindow::GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IVideoWindow, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CBaseVideoWindow::GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IVideoWindow, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CBaseVideoWindow::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IVideoWindow *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- IBasicVideo implementation ---------- + + +CBaseBasicVideo::CBaseBasicVideo(const TCHAR * pName,LPUNKNOWN punk) : + CUnknown(pName, punk) +{ +} + + +// overriden to publicise our interfaces + +STDMETHODIMP +CBaseBasicVideo::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IBasicVideo || riid == IID_IBasicVideo2) { + return GetInterface( static_cast(this), ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +STDMETHODIMP +CBaseBasicVideo::GetTypeInfoCount(UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +STDMETHODIMP +CBaseBasicVideo::GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IBasicVideo, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CBaseBasicVideo::GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IBasicVideo, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CBaseBasicVideo::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IBasicVideo *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- Implementation of Deferred Commands ---------- + + +CDispParams::CDispParams(UINT nArgs, VARIANT* pArgs, HRESULT *phr) +{ + cNamedArgs = 0; + rgdispidNamedArgs = NULL; + cArgs = nArgs; + + if (cArgs) { + rgvarg = new VARIANT[cArgs]; + if (NULL == rgvarg) { + cArgs = 0; + if (phr) { + *phr = E_OUTOFMEMORY; + } + return; + } + + for (UINT i = 0; i < cArgs; i++) { + + VARIANT * pDest = &rgvarg[i]; + VARIANT * pSrc = &pArgs[i]; + + pDest->vt = pSrc->vt; + switch(pDest->vt) { + + case VT_I4: + pDest->lVal = pSrc->lVal; + break; + + case VT_UI1: + pDest->bVal = pSrc->bVal; + break; + + case VT_I2: + pDest->iVal = pSrc->iVal; + break; + + case VT_R4: + pDest->fltVal = pSrc->fltVal; + break; + + case VT_R8: + pDest->dblVal = pSrc->dblVal; + break; + + case VT_BOOL: + pDest->boolVal = pSrc->boolVal; + break; + + case VT_ERROR: + pDest->scode = pSrc->scode; + break; + + case VT_CY: + pDest->cyVal = pSrc->cyVal; + break; + + case VT_DATE: + pDest->date = pSrc->date; + break; + + case VT_BSTR: + if (pSrc->bstrVal == NULL) { + pDest->bstrVal = NULL; + } else { + + // a BSTR is a WORD followed by a UNICODE string. + // the pointer points just after the WORD + + WORD len = * (WORD*) (pSrc->bstrVal - (sizeof(WORD) / sizeof(OLECHAR))); + OLECHAR* pch = new OLECHAR[len + (sizeof(WORD)/sizeof(OLECHAR))]; + if (pch) { + WORD *pui = (WORD*)pch; + *pui = len; + pDest->bstrVal = pch + (sizeof(WORD)/sizeof(OLECHAR)); + CopyMemory(pDest->bstrVal, pSrc->bstrVal, len*sizeof(OLECHAR)); + } else { + cArgs = i; + if (phr) { + *phr = E_OUTOFMEMORY; + } + } + } + pDest->bstrVal = pSrc->bstrVal; + break; + + case VT_UNKNOWN: + pDest->punkVal = pSrc->punkVal; + pDest->punkVal->AddRef(); + break; + + case VT_DISPATCH: + pDest->pdispVal = pSrc->pdispVal; + pDest->pdispVal->AddRef(); + break; + + default: + // a type we haven't got round to adding yet! + ASSERT(0); + break; + } + } + + } else { + rgvarg = NULL; + } + +} + + +CDispParams::~CDispParams() +{ + for (UINT i = 0; i < cArgs; i++) { + switch(rgvarg[i].vt) { + case VT_BSTR: + if (rgvarg[i].bstrVal != NULL) { + OLECHAR * pch = rgvarg[i].bstrVal - (sizeof(WORD)/sizeof(OLECHAR)); + delete pch; + } + break; + + case VT_UNKNOWN: + rgvarg[i].punkVal->Release(); + break; + + case VT_DISPATCH: + rgvarg[i].pdispVal->Release(); + break; + } + } + delete[] rgvarg; +} + + +// lifetime is controlled by refcounts (see defer.h) + +CDeferredCommand::CDeferredCommand( + CCmdQueue * pQ, + LPUNKNOWN pUnk, + HRESULT * phr, + LPUNKNOWN pUnkExecutor, + REFTIME time, + GUID* iid, + long dispidMethod, + short wFlags, + long nArgs, + VARIANT* pDispParams, + VARIANT* pvarResult, + short* puArgErr, + BOOL bStream + ) : + CUnknown(NAME("DeferredCommand"), pUnk), + m_pQueue(pQ), + m_pUnk(pUnkExecutor), + m_iid(iid), + m_dispidMethod(dispidMethod), + m_wFlags(wFlags), + m_DispParams(nArgs, pDispParams, phr), + m_pvarResult(pvarResult), + m_bStream(bStream), + m_hrResult(E_ABORT) + +{ + // convert REFTIME to REFERENCE_TIME + COARefTime convertor(time); + m_time = convertor; + + // no check of time validity - it's ok to queue a command that's + // already late + + // check iid is supportable on pUnk by QueryInterface for it + IUnknown * pInterface; + HRESULT hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface); + if (FAILED(hr)) { + *phr = hr; + return; + } + pInterface->Release(); + + + // !!! check dispidMethod and param/return types using typelib + ITypeInfo *pti; + hr = m_Dispatch.GetTypeInfo(*iid, 0, 0, &pti); + if (FAILED(hr)) { + *phr = hr; + return; + } + // !!! some sort of ITypeInfo validity check here + pti->Release(); + + + // Fix up the dispid for put and get + if (wFlags == DISPATCH_PROPERTYPUT) { + m_DispParams.cNamedArgs = 1; + m_DispId = DISPID_PROPERTYPUT; + m_DispParams.rgdispidNamedArgs = &m_DispId; + } + + // all checks ok - add to queue + hr = pQ->Insert(this); + if (FAILED(hr)) { + *phr = hr; + } +} + + +// refcounts are held by caller of InvokeAt... and by list. So if +// we get here, we can't be on the list + +#if 0 +CDeferredCommand::~CDeferredCommand() +{ + // this assert is invalid since if the queue is deleted while we are + // still on the queue, we will have been removed by the queue and this + // m_pQueue will not have been modified. + // ASSERT(m_pQueue == NULL); + + // we don't hold a ref count on pUnk, which is the object that should + // execute the command. + // This is because there would otherwise be a circular refcount problem + // since pUnk probably owns the CmdQueue object that has a refcount + // on us. + // The lifetime of pUnk is guaranteed by it being part of, or lifetime + // controlled by, our parent object. As long as we are on the list, pUnk + // must be valid. Once we are off the list, we do not use pUnk. + +} +#endif + + +// overriden to publicise our interfaces + +STDMETHODIMP +CDeferredCommand::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IDeferredCommand) { + return GetInterface( (IDeferredCommand *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// remove from q. this will reduce the refcount by one (since the q +// holds a count) but can't make us go away since he must have a +// refcount in order to call this method. + +STDMETHODIMP +CDeferredCommand::Cancel() +{ + if (m_pQueue == NULL) { + return VFW_E_ALREADY_CANCELLED; + } + + HRESULT hr = m_pQueue->Remove(this); + if (FAILED(hr)) { + return hr; + } + + m_pQueue = NULL; + return S_OK; +} + + +STDMETHODIMP +CDeferredCommand::Confidence(LONG* pConfidence) +{ + return E_NOTIMPL; +} + + +STDMETHODIMP +CDeferredCommand::GetHResult(HRESULT * phrResult) +{ + CheckPointer(phrResult,E_POINTER); + ValidateReadWritePtr(phrResult,sizeof(HRESULT)); + + if (m_pQueue != NULL) { + return E_ABORT; + } + *phrResult = m_hrResult; + return S_OK; +} + + +// set the time to be a new time (checking that it is valid) and +// then requeue + +STDMETHODIMP +CDeferredCommand::Postpone(REFTIME newtime) +{ + + // check that this time is not past + // convert REFTIME to REFERENCE_TIME + COARefTime convertor(newtime); + + // check that the time has not passed + if (m_pQueue->CheckTime(convertor, IsStreamTime())) { + return VFW_E_TIME_ALREADY_PASSED; + } + + // extract from list + HRESULT hr = m_pQueue->Remove(this); + if (FAILED(hr)) { + return hr; + } + + // change time + m_time = convertor; + + // requeue + hr = m_pQueue->Insert(this); + + return hr; +} + + +HRESULT +CDeferredCommand::Invoke() +{ + // check that we are still outstanding + if (m_pQueue == NULL) { + return VFW_E_ALREADY_CANCELLED; + } + + // get the type info + ITypeInfo* pti; + HRESULT hr = m_Dispatch.GetTypeInfo(GetIID(), 0, 0, &pti); + if (FAILED(hr)) { + return hr; + } + + // qi for the expected interface and then invoke it. Note that we have to + // treat the returned interface as IUnknown since we don't know its type. + IUnknown* pInterface; + + hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface); + if (FAILED(hr)) { + pti->Release(); + return hr; + } + + EXCEPINFO expinfo; + UINT uArgErr; + m_hrResult = pti->Invoke( + pInterface, + GetMethod(), + GetFlags(), + GetParams(), + GetResult(), + &expinfo, + &uArgErr); + + // release the interface we QI'd for + pInterface->Release(); + pti->Release(); + + + // remove from list whether or not successful + // or we loop indefinitely + hr = m_pQueue->Remove(this); + m_pQueue = NULL; + return hr; +} + + + +// --- CCmdQueue methods ---------- + + +CCmdQueue::CCmdQueue() : + m_listPresentation(NAME("Presentation time command list")), + m_listStream(NAME("Stream time command list")), + m_evDue(TRUE), // manual reset + m_dwAdvise(0), + m_pClock(NULL), + m_bRunning(FALSE) +{ +} + + +CCmdQueue::~CCmdQueue() +{ + // empty all our lists + + // we hold a refcount on each, so traverse and Release each + // entry then RemoveAll to empty the list + WXLIST_POSITION pos = m_listPresentation.GetHeadPosition(); + + while(pos) { + CDeferredCommand* pCmd = m_listPresentation.GetNext(pos); + pCmd->Release(); + } + m_listPresentation.RemoveAll(); + + pos = m_listStream.GetHeadPosition(); + + while(pos) { + CDeferredCommand* pCmd = m_listStream.GetNext(pos); + pCmd->Release(); + } + m_listStream.RemoveAll(); + + if (m_pClock) { + if (m_dwAdvise) { + m_pClock->Unadvise(m_dwAdvise); + m_dwAdvise = 0; + } + m_pClock->Release(); + } +} + + +// returns a new CDeferredCommand object that will be initialised with +// the parameters and will be added to the queue during construction. +// returns S_OK if successfully created otherwise an error and +// no object has been queued. + +HRESULT +CCmdQueue::New( + CDeferredCommand **ppCmd, + LPUNKNOWN pUnk, // this object will execute command + REFTIME time, + GUID* iid, + long dispidMethod, + short wFlags, + long cArgs, + VARIANT* pDispParams, + VARIANT* pvarResult, + short* puArgErr, + BOOL bStream +) +{ + CAutoLock lock(&m_Lock); + + HRESULT hr = S_OK; + *ppCmd = NULL; + + CDeferredCommand* pCmd; + pCmd = new CDeferredCommand( + this, + NULL, // not aggregated + &hr, + pUnk, // this guy will execute + time, + iid, + dispidMethod, + wFlags, + cArgs, + pDispParams, + pvarResult, + puArgErr, + bStream); + + if (pCmd == NULL) { + hr = E_OUTOFMEMORY; + } else { + *ppCmd = pCmd; + } + return hr; +} + + +HRESULT +CCmdQueue::Insert(CDeferredCommand* pCmd) +{ + CAutoLock lock(&m_Lock); + + // addref the item + pCmd->AddRef(); + + CGenericList * pList; + if (pCmd->IsStreamTime()) { + pList = &m_listStream; + } else { + pList = &m_listPresentation; + } + WXLIST_POSITION pos = pList->GetHeadPosition(); + + // seek past all items that are before us + while (pos && + (pList->Get(pos)->GetTime() <= pCmd->GetTime())) { + + pList->GetNext(pos); + } + + // now at end of list or in front of items that come later + if (!pos) { + pList->AddTail(pCmd); + } else { + pList->AddBefore(pos, pCmd); + } + + SetTimeAdvise(); + return S_OK; +} + + +HRESULT +CCmdQueue::Remove(CDeferredCommand* pCmd) +{ + CAutoLock lock(&m_Lock); + HRESULT hr = S_OK; + + CGenericList * pList; + if (pCmd->IsStreamTime()) { + pList = &m_listStream; + } else { + pList = &m_listPresentation; + } + WXLIST_POSITION pos = pList->GetHeadPosition(); + + // traverse the list + while (pos && (pList->Get(pos) != pCmd)) { + pList->GetNext(pos); + } + + // did we drop off the end? + if (!pos) { + hr = VFW_E_NOT_FOUND; + } else { + + // found it - now take off list + pList->Remove(pos); + + // Insert did an AddRef, so release it + pCmd->Release(); + + // check that timer request is still for earliest time + SetTimeAdvise(); + } + return hr; +} + + +// set the clock used for timing + +HRESULT +CCmdQueue::SetSyncSource(IReferenceClock* pClock) +{ + CAutoLock lock(&m_Lock); + + // addref the new clock first in case they are the same + if (pClock) { + pClock->AddRef(); + } + + // kill any advise on the old clock + if (m_pClock) { + if (m_dwAdvise) { + m_pClock->Unadvise(m_dwAdvise); + m_dwAdvise = 0; + } + m_pClock->Release(); + } + m_pClock = pClock; + + // set up a new advise + SetTimeAdvise(); + return S_OK; +} + + +// set up a timer event with the reference clock + +void +CCmdQueue::SetTimeAdvise(void) +{ + // make sure we have a clock to use + if (!m_pClock) { + return; + } + + // reset the event whenever we are requesting a new signal + m_evDue.Reset(); + + // time 0 is earliest + CRefTime current; + + // find the earliest presentation time + if (m_listPresentation.GetCount() > 0) { + + WXLIST_POSITION pos = m_listPresentation.GetHeadPosition(); + current = m_listPresentation.Get(pos)->GetTime(); + } + + // if we're running, check the stream times too + if (m_bRunning) { + + CRefTime t; + + if (m_listStream.GetCount() > 0) { + + WXLIST_POSITION pos = m_listStream.GetHeadPosition(); + t = m_listStream.Get(pos)->GetTime(); + + // add on stream time offset to get presentation time + t += m_StreamTimeOffset; + + // is this earlier? + if ((current == TimeZero) || (t < current)) { + current = t; + } + } + } + + // need to change? + if ((current > TimeZero) && (current != m_tCurrentAdvise)) { + if (m_dwAdvise) { + m_pClock->Unadvise(m_dwAdvise); + // reset the event whenever we are requesting a new signal + m_evDue.Reset(); + } + + // ask for time advice - the first two params are either + // stream time offset and stream time or + // presentation time and 0. we always use the latter + HRESULT hr = m_pClock->AdviseTime( + (REFERENCE_TIME)current, + TimeZero, + (HEVENT) HANDLE(m_evDue), + &m_dwAdvise); + + ASSERT(SUCCEEDED(hr)); + m_tCurrentAdvise = current; + } +} + + +// switch to run mode. Streamtime to Presentation time mapping known. + +HRESULT +CCmdQueue::Run(REFERENCE_TIME tStreamTimeOffset) +{ + CAutoLock lock(&m_Lock); + + m_StreamTimeOffset = tStreamTimeOffset; + m_bRunning = TRUE; + + // ensure advise is accurate + SetTimeAdvise(); + return S_OK; +} + + +// switch to Stopped or Paused mode. Time mapping not known. + +HRESULT +CCmdQueue::EndRun() +{ + CAutoLock lock(&m_Lock); + + m_bRunning = FALSE; + + // check timer setting - stream times + SetTimeAdvise(); + return S_OK; +} + + +// return a pointer to the next due command. Blocks for msTimeout +// milliseconds until there is a due command. +// Stream-time commands will only become due between Run and Endrun calls. +// The command remains queued until invoked or cancelled. +// Returns E_ABORT if timeout occurs, otherwise S_OK (or other error). +// +// returns an AddRef'd object + +HRESULT +CCmdQueue::GetDueCommand(CDeferredCommand ** ppCmd, long msTimeout) +{ + // loop until we timeout or find a due command + for (;;) { + + { + CAutoLock lock(&m_Lock); + + + // find the earliest command + CDeferredCommand * pCmd = NULL; + + // check the presentation time and the + // stream time list to find the earliest + + if (m_listPresentation.GetCount() > 0) { + WXLIST_POSITION pos = m_listPresentation.GetHeadPosition(); + pCmd = m_listPresentation.Get(pos); + } + + if (m_bRunning && (m_listStream.GetCount() > 0)) { + WXLIST_POSITION pos = m_listStream.GetHeadPosition(); + CDeferredCommand* pStrm = m_listStream.Get(pos); + + CRefTime t = pStrm->GetTime() + m_StreamTimeOffset; + if (!pCmd || (t < pCmd->GetTime())) { + pCmd = pStrm; + } + } + + // if we have found one, is it due? + if (pCmd) { + if (CheckTime(pCmd->GetTime(), pCmd->IsStreamTime())) { + + // yes it's due - addref it + pCmd->AddRef(); + *ppCmd = pCmd; + return S_OK; + } + } + } + + // block until the advise is signalled + if (WaitForSingleObject(m_evDue, msTimeout) != WAIT_OBJECT_0) { + return E_ABORT; + } + } +} + + +// return a pointer to a command that will be due for a given time. +// Pass in a stream time here. The stream time offset will be passed +// in via the Run method. +// Commands remain queued until invoked or cancelled. +// This method will not block. It will report E_ABORT if there are no +// commands due yet. +// +// returns an AddRef'd object + +HRESULT +CCmdQueue::GetCommandDueFor(REFERENCE_TIME rtStream, CDeferredCommand**ppCmd) +{ + CAutoLock lock(&m_Lock); + + CRefTime tStream(rtStream); + + // find the earliest stream and presentation time commands + CDeferredCommand* pStream = NULL; + if (m_listStream.GetCount() > 0) { + WXLIST_POSITION pos = m_listStream.GetHeadPosition(); + pStream = m_listStream.Get(pos); + } + CDeferredCommand* pPresent = NULL; + if (m_listPresentation.GetCount() > 0) { + WXLIST_POSITION pos = m_listPresentation.GetHeadPosition(); + pPresent = m_listPresentation.Get(pos); + } + + // is there a presentation time that has passed already + if (pPresent && CheckTime(pPresent->GetTime(), FALSE)) { + pPresent->AddRef(); + *ppCmd = pPresent; + return S_OK; + } + + // is there a stream time command due before this stream time + if (pStream && (pStream->GetTime() <= tStream)) { + pPresent->AddRef(); + *ppCmd = pStream; + return S_OK; + } + + // if we are running, we can map presentation times to + // stream time. In this case, is there a presentation time command + // that will be due before this stream time is presented? + if (m_bRunning && pPresent) { + + // this stream time will appear at... + tStream += m_StreamTimeOffset; + + // due before that? + if (pPresent->GetTime() <= tStream) { + *ppCmd = pPresent; + return S_OK; + } + } + + // no commands due yet + return VFW_E_NOT_FOUND; +} + diff --git a/plugins/GSdx/baseclasses/ctlutil.h b/plugins/GSdx/baseclasses/ctlutil.h index 5df80c0d00..ce4490cdef 100644 --- a/plugins/GSdx/baseclasses/ctlutil.h +++ b/plugins/GSdx/baseclasses/ctlutil.h @@ -1,919 +1,919 @@ -//------------------------------------------------------------------------------ -// File: CtlUtil.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// Base classes implementing IDispatch parsing for the basic control dual -// interfaces. Derive from these and implement just the custom method and -// property methods. We also implement CPosPassThru that can be used by -// renderers and transforms to pass by IMediaPosition and IMediaSeeking - -#ifndef __CTLUTIL__ -#define __CTLUTIL__ - -// OLE Automation has different ideas of TRUE and FALSE - -#define OATRUE (-1) -#define OAFALSE (0) - - -// It's possible that we could replace this class with CreateStdDispatch - -class CBaseDispatch -{ - ITypeInfo * m_pti; - -public: - - CBaseDispatch() : m_pti(NULL) {} - ~CBaseDispatch(); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - REFIID riid, - UINT itinfo, - LCID lcid, - ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - OLECHAR ** rgszNames, - UINT cNames, - LCID lcid, - DISPID * rgdispid); -}; - - -class AM_NOVTABLE CMediaControl : - public IMediaControl, - public CUnknown -{ - CBaseDispatch m_basedisp; - -public: - - CMediaControl(const TCHAR *, LPUNKNOWN); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - UINT itinfo, - LCID lcid, - ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - OLECHAR ** rgszNames, - UINT cNames, - LCID lcid, - DISPID * rgdispid); - - STDMETHODIMP Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - DISPPARAMS * pdispparams, - VARIANT * pvarResult, - EXCEPINFO * pexcepinfo, - UINT * puArgErr); -}; - - -class AM_NOVTABLE CMediaEvent : - public IMediaEventEx, - public CUnknown -{ - CBaseDispatch m_basedisp; - -public: - - CMediaEvent(const TCHAR *, LPUNKNOWN); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - UINT itinfo, - LCID lcid, - ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - OLECHAR ** rgszNames, - UINT cNames, - LCID lcid, - DISPID * rgdispid); - - STDMETHODIMP Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - DISPPARAMS * pdispparams, - VARIANT * pvarResult, - EXCEPINFO * pexcepinfo, - UINT * puArgErr); -}; - - -class AM_NOVTABLE CMediaPosition : - public IMediaPosition, - public CUnknown -{ - CBaseDispatch m_basedisp; - - -public: - - CMediaPosition(const TCHAR *, LPUNKNOWN); - CMediaPosition(const TCHAR *, LPUNKNOWN, HRESULT *phr); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - UINT itinfo, - LCID lcid, - ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - OLECHAR ** rgszNames, - UINT cNames, - LCID lcid, - DISPID * rgdispid); - - STDMETHODIMP Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - DISPPARAMS * pdispparams, - VARIANT * pvarResult, - EXCEPINFO * pexcepinfo, - UINT * puArgErr); - -}; - - -// OA-compatibility means that we must use double as the RefTime value, -// and REFERENCE_TIME (essentially a LONGLONG) within filters. -// this class converts between the two - -class COARefTime : public CRefTime { -public: - - COARefTime() { - }; - - COARefTime(CRefTime t) - : CRefTime(t) - { - }; - - COARefTime(REFERENCE_TIME t) - : CRefTime(t) - { - }; - - COARefTime(double d) { - m_time = (LONGLONG) (d * 10000000); - }; - - operator double() { - return double(m_time) / 10000000; - }; - - operator REFERENCE_TIME() { - return m_time; - }; - - COARefTime& operator=(const double& rd) { - m_time = (LONGLONG) (rd * 10000000); - return *this; - } - - COARefTime& operator=(const REFERENCE_TIME& rt) { - m_time = rt; - return *this; - } - - inline BOOL operator==(const COARefTime& rt) - { - return m_time == rt.m_time; - }; - - inline BOOL operator!=(const COARefTime& rt) - { - return m_time != rt.m_time; - }; - - inline BOOL operator < (const COARefTime& rt) - { - return m_time < rt.m_time; - }; - - inline BOOL operator > (const COARefTime& rt) - { - return m_time > rt.m_time; - }; - - inline BOOL operator >= (const COARefTime& rt) - { - return m_time >= rt.m_time; - }; - - inline BOOL operator <= (const COARefTime& rt) - { - return m_time <= rt.m_time; - }; - - inline COARefTime operator+(const COARefTime& rt) - { - return COARefTime(m_time + rt.m_time); - }; - - inline COARefTime operator-(const COARefTime& rt) - { - return COARefTime(m_time - rt.m_time); - }; - - inline COARefTime operator*(LONG l) - { - return COARefTime(m_time * l); - }; - - inline COARefTime operator/(LONG l) - { - return COARefTime(m_time / l); - }; - -private: - // Prevent bugs from constructing from LONG (which gets - // converted to double and then multiplied by 10000000 - COARefTime(LONG); - int operator=(LONG); -}; - - -// A utility class that handles IMediaPosition and IMediaSeeking on behalf -// of single-input pin renderers, or transform filters. -// -// Renderers will expose this from the filter; transform filters will -// expose it from the output pin and not the renderer. -// -// Create one of these, giving it your IPin* for your input pin, and delegate -// all IMediaPosition methods to it. It will query the input pin for -// IMediaPosition and respond appropriately. -// -// Call ForceRefresh if the pin connection changes. -// -// This class no longer caches the upstream IMediaPosition or IMediaSeeking -// it acquires it on each method call. This means ForceRefresh is not needed. -// The method is kept for source compatibility and to minimise the changes -// if we need to put it back later for performance reasons. - -class CPosPassThru : public IMediaSeeking, public CMediaPosition -{ - IPin *m_pPin; - - HRESULT GetPeer(IMediaPosition **ppMP); - HRESULT GetPeerSeeking(IMediaSeeking **ppMS); - -public: - - CPosPassThru(const TCHAR *, LPUNKNOWN, HRESULT*, IPin *); - DECLARE_IUNKNOWN - - HRESULT ForceRefresh() { - return S_OK; - }; - - // override to return an accurate current position - virtual HRESULT GetMediaTime(LONGLONG *pStartTime,LONGLONG *pEndTime) { - return E_FAIL; - } - - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv); - - // IMediaSeeking methods - STDMETHODIMP GetCapabilities( DWORD * pCapabilities ); - STDMETHODIMP CheckCapabilities( DWORD * pCapabilities ); - STDMETHODIMP SetTimeFormat(const GUID * pFormat); - STDMETHODIMP GetTimeFormat(GUID *pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID * pFormat); - STDMETHODIMP IsFormatSupported( const GUID * pFormat); - STDMETHODIMP QueryPreferredFormat( GUID *pFormat); - STDMETHODIMP ConvertTimeFormat(LONGLONG * pTarget, const GUID * pTargetFormat, - LONGLONG Source, const GUID * pSourceFormat ); - STDMETHODIMP SetPositions( LONGLONG * pCurrent, DWORD CurrentFlags - , LONGLONG * pStop, DWORD StopFlags ); - - STDMETHODIMP GetPositions( LONGLONG * pCurrent, LONGLONG * pStop ); - STDMETHODIMP GetCurrentPosition( LONGLONG * pCurrent ); - STDMETHODIMP GetStopPosition( LONGLONG * pStop ); - STDMETHODIMP SetRate( double dRate); - STDMETHODIMP GetRate( double * pdRate); - STDMETHODIMP GetDuration( LONGLONG *pDuration); - STDMETHODIMP GetAvailable( LONGLONG *pEarliest, LONGLONG *pLatest ); - STDMETHODIMP GetPreroll( LONGLONG *pllPreroll ); - - // IMediaPosition properties - STDMETHODIMP get_Duration(REFTIME * plength); - STDMETHODIMP put_CurrentPosition(REFTIME llTime); - STDMETHODIMP get_StopTime(REFTIME * pllTime); - STDMETHODIMP put_StopTime(REFTIME llTime); - STDMETHODIMP get_PrerollTime(REFTIME * pllTime); - STDMETHODIMP put_PrerollTime(REFTIME llTime); - STDMETHODIMP get_Rate(double * pdRate); - STDMETHODIMP put_Rate(double dRate); - STDMETHODIMP get_CurrentPosition(REFTIME * pllTime); - STDMETHODIMP CanSeekForward(LONG *pCanSeekForward); - STDMETHODIMP CanSeekBackward(LONG *pCanSeekBackward); - -private: - HRESULT GetSeekingLongLong( HRESULT (__stdcall IMediaSeeking::*pMethod)( LONGLONG * ), - LONGLONG * pll ); -}; - - -// Adds the ability to return a current position - -class CRendererPosPassThru : public CPosPassThru -{ - CCritSec m_PositionLock; // Locks access to our position - LONGLONG m_StartMedia; // Start media time last seen - LONGLONG m_EndMedia; // And likewise the end media - BOOL m_bReset; // Have media times been set - -public: - - // Used to help with passing media times through graph - - CRendererPosPassThru(const TCHAR *, LPUNKNOWN, HRESULT*, IPin *); - HRESULT RegisterMediaTime(IMediaSample *pMediaSample); - HRESULT RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime); - HRESULT GetMediaTime(LONGLONG *pStartTime,LONGLONG *pEndTime); - HRESULT ResetMediaTime(); - HRESULT EOS(); -}; - -STDAPI CreatePosPassThru( - LPUNKNOWN pAgg, - BOOL bRenderer, - IPin *pPin, - IUnknown **ppPassThru -); - -// A class that handles the IDispatch part of IBasicAudio and leaves the -// properties and methods themselves pure virtual. - -class AM_NOVTABLE CBasicAudio : public IBasicAudio, public CUnknown -{ - CBaseDispatch m_basedisp; - -public: - - CBasicAudio(const TCHAR *, LPUNKNOWN); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - UINT itinfo, - LCID lcid, - ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - OLECHAR ** rgszNames, - UINT cNames, - LCID lcid, - DISPID * rgdispid); - - STDMETHODIMP Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - DISPPARAMS * pdispparams, - VARIANT * pvarResult, - EXCEPINFO * pexcepinfo, - UINT * puArgErr); -}; - - -// A class that handles the IDispatch part of IBasicVideo and leaves the -// properties and methods themselves pure virtual. - -class AM_NOVTABLE CBaseBasicVideo : public IBasicVideo2, public CUnknown -{ - CBaseDispatch m_basedisp; - -public: - - CBaseBasicVideo(const TCHAR *, LPUNKNOWN); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - UINT itinfo, - LCID lcid, - ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - OLECHAR ** rgszNames, - UINT cNames, - LCID lcid, - DISPID * rgdispid); - - STDMETHODIMP Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - DISPPARAMS * pdispparams, - VARIANT * pvarResult, - EXCEPINFO * pexcepinfo, - UINT * puArgErr); - - STDMETHODIMP GetPreferredAspectRatio( - long *plAspectX, - long *plAspectY) - { - return E_NOTIMPL; - } -}; - - -// A class that handles the IDispatch part of IVideoWindow and leaves the -// properties and methods themselves pure virtual. - -class AM_NOVTABLE CBaseVideoWindow : public IVideoWindow, public CUnknown -{ - CBaseDispatch m_basedisp; - -public: - - CBaseVideoWindow(const TCHAR *, LPUNKNOWN); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - UINT itinfo, - LCID lcid, - ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - OLECHAR ** rgszNames, - UINT cNames, - LCID lcid, - DISPID * rgdispid); - - STDMETHODIMP Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - DISPPARAMS * pdispparams, - VARIANT * pvarResult, - EXCEPINFO * pexcepinfo, - UINT * puArgErr); -}; - - -// abstract class to help source filters with their implementation -// of IMediaPosition. Derive from this and set the duration (and stop -// position). Also override NotifyChange to do something when the properties -// change. - -class AM_NOVTABLE CSourcePosition : public CMediaPosition -{ - -public: - CSourcePosition(const TCHAR *, LPUNKNOWN, HRESULT*, CCritSec *); - - // IMediaPosition methods - STDMETHODIMP get_Duration(REFTIME * plength); - STDMETHODIMP put_CurrentPosition(REFTIME llTime); - STDMETHODIMP get_StopTime(REFTIME * pllTime); - STDMETHODIMP put_StopTime(REFTIME llTime); - STDMETHODIMP get_PrerollTime(REFTIME * pllTime); - STDMETHODIMP put_PrerollTime(REFTIME llTime); - STDMETHODIMP get_Rate(double * pdRate); - STDMETHODIMP put_Rate(double dRate); - STDMETHODIMP CanSeekForward(LONG *pCanSeekForward); - STDMETHODIMP CanSeekBackward(LONG *pCanSeekBackward); - - // override if you can return the data you are actually working on - STDMETHODIMP get_CurrentPosition(REFTIME * pllTime) { - return E_NOTIMPL; - }; - -protected: - - // we call this to notify changes. Override to handle them - virtual HRESULT ChangeStart() PURE; - virtual HRESULT ChangeStop() PURE; - virtual HRESULT ChangeRate() PURE; - - COARefTime m_Duration; - COARefTime m_Start; - COARefTime m_Stop; - double m_Rate; - - CCritSec * m_pLock; -}; - -class AM_NOVTABLE CSourceSeeking : - public IMediaSeeking, - public CUnknown -{ - -public: - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); - - // IMediaSeeking methods - - STDMETHODIMP IsFormatSupported(const GUID * pFormat); - STDMETHODIMP QueryPreferredFormat(GUID *pFormat); - STDMETHODIMP SetTimeFormat(const GUID * pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID * pFormat); - STDMETHODIMP GetTimeFormat(GUID *pFormat); - STDMETHODIMP GetDuration(LONGLONG *pDuration); - STDMETHODIMP GetStopPosition(LONGLONG *pStop); - STDMETHODIMP GetCurrentPosition(LONGLONG *pCurrent); - STDMETHODIMP GetCapabilities( DWORD * pCapabilities ); - STDMETHODIMP CheckCapabilities( DWORD * pCapabilities ); - STDMETHODIMP ConvertTimeFormat( LONGLONG * pTarget, const GUID * pTargetFormat, - LONGLONG Source, const GUID * pSourceFormat ); - - STDMETHODIMP SetPositions( LONGLONG * pCurrent, DWORD CurrentFlags - , LONGLONG * pStop, DWORD StopFlags ); - - STDMETHODIMP GetPositions( LONGLONG * pCurrent, LONGLONG * pStop ); - - STDMETHODIMP GetAvailable( LONGLONG * pEarliest, LONGLONG * pLatest ); - STDMETHODIMP SetRate( double dRate); - STDMETHODIMP GetRate( double * pdRate); - STDMETHODIMP GetPreroll(LONGLONG *pPreroll); - - -protected: - - // ctor - CSourceSeeking(const TCHAR *, LPUNKNOWN, HRESULT*, CCritSec *); - - // we call this to notify changes. Override to handle them - virtual HRESULT ChangeStart() PURE; - virtual HRESULT ChangeStop() PURE; - virtual HRESULT ChangeRate() PURE; - - CRefTime m_rtDuration; // length of stream - CRefTime m_rtStart; // source will start here - CRefTime m_rtStop; // source will stop here - double m_dRateSeeking; - - // seeking capabilities - DWORD m_dwSeekingCaps; - - CCritSec * m_pLock; -}; - - -// Base classes supporting Deferred commands. - -// Deferred commands are queued by calls to methods on the IQueueCommand -// interface, exposed by the filtergraph and by some filters. A successful -// call to one of these methods will return an IDeferredCommand interface -// representing the queued command. -// -// A CDeferredCommand object represents a single deferred command, and exposes -// the IDeferredCommand interface as well as other methods permitting time -// checks and actual execution. It contains a reference to the CCommandQueue -// object on which it is queued. -// -// CCommandQueue is a base class providing a queue of CDeferredCommand -// objects, and methods to add, remove, check status and invoke the queued -// commands. A CCommandQueue object would be part of an object that -// implemented IQueueCommand. - -class CCmdQueue; - -// take a copy of the params and store them. Release any allocated -// memory in destructor - -class CDispParams : public DISPPARAMS -{ -public: - CDispParams(UINT nArgs, VARIANT* pArgs, HRESULT *phr = NULL); - ~CDispParams(); -}; - - -// CDeferredCommand lifetime is controlled by refcounts. Caller of -// InvokeAt.. gets a refcounted interface pointer, and the CCmdQueue -// object also holds a refcount on us. Calling Cancel or Invoke takes -// us off the CCmdQueue and thus reduces the refcount by 1. Once taken -// off the queue we cannot be put back on the queue. - -class CDeferredCommand - : public CUnknown, - public IDeferredCommand -{ -public: - - CDeferredCommand( - CCmdQueue * pQ, - LPUNKNOWN pUnk, // aggregation outer unk - HRESULT * phr, - LPUNKNOWN pUnkExecutor, // object that will execute this cmd - REFTIME time, - GUID* iid, - long dispidMethod, - short wFlags, - long cArgs, - VARIANT* pDispParams, - VARIANT* pvarResult, - short* puArgErr, - BOOL bStream - ); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); - - // IDeferredCommand methods - STDMETHODIMP Cancel(); - STDMETHODIMP Confidence( - LONG* pConfidence); - STDMETHODIMP Postpone( - REFTIME newtime); - STDMETHODIMP GetHResult( - HRESULT* phrResult); - - // other public methods - - HRESULT Invoke(); - - // access methods - - // returns TRUE if streamtime, FALSE if presentation time - BOOL IsStreamTime() { - return m_bStream; - }; - - CRefTime GetTime() { - return m_time; - }; - - REFIID GetIID() { - return *m_iid; - }; - - long GetMethod() { - return m_dispidMethod; - }; - - short GetFlags() { - return m_wFlags; - }; - - DISPPARAMS* GetParams() { - return &m_DispParams; - }; - - VARIANT* GetResult() { - return m_pvarResult; - }; - -protected: - - CCmdQueue* m_pQueue; - - // pUnk for the interface that we will execute the command on - LPUNKNOWN m_pUnk; - - // stored command data - REFERENCE_TIME m_time; - GUID* m_iid; - long m_dispidMethod; - short m_wFlags; - VARIANT* m_pvarResult; - BOOL m_bStream; - CDispParams m_DispParams; - DISPID m_DispId; // For get and put - - // we use this for ITypeInfo access - CBaseDispatch m_Dispatch; - - // save retval here - HRESULT m_hrResult; -}; - - -// a list of CDeferredCommand objects. this is a base class providing -// the basics of access to the list. If you want to use CDeferredCommand -// objects then your queue needs to be derived from this class. - -class AM_NOVTABLE CCmdQueue -{ -public: - CCmdQueue(); - virtual ~CCmdQueue(); - - // returns a new CDeferredCommand object that will be initialised with - // the parameters and will be added to the queue during construction. - // returns S_OK if successfully created otherwise an error and - // no object has been queued. - virtual HRESULT New( - CDeferredCommand **ppCmd, - LPUNKNOWN pUnk, - REFTIME time, - GUID* iid, - long dispidMethod, - short wFlags, - long cArgs, - VARIANT* pDispParams, - VARIANT* pvarResult, - short* puArgErr, - BOOL bStream - ); - - // called by the CDeferredCommand object to add and remove itself - // from the queue - virtual HRESULT Insert(CDeferredCommand* pCmd); - virtual HRESULT Remove(CDeferredCommand* pCmd); - - // Command-Due Checking - // - // There are two schemes of synchronisation: coarse and accurate. In - // coarse mode, you wait till the time arrives and then execute the cmd. - // In accurate mode, you wait until you are processing the sample that - // will appear at the time, and then execute the command. It's up to the - // filter which one it will implement. The filtergraph will always - // implement coarse mode for commands queued at the filtergraph. - // - // If you want coarse sync, you probably want to wait until there is a - // command due, and then execute it. You can do this by calling - // GetDueCommand. If you have several things to wait for, get the - // event handle from GetDueHandle() and when this is signalled then call - // GetDueCommand. Stream time will only advance between calls to Run and - // EndRun. Note that to avoid an extra thread there is no guarantee that - // if the handle is set there will be a command ready. Each time the - // event is signalled, call GetDueCommand (probably with a 0 timeout); - // This may return E_ABORT. - // - // If you want accurate sync, you must call GetCommandDueFor, passing - // as a parameter the stream time of the samples you are about to process. - // This will return: - // -- a stream-time command due at or before that stream time - // -- a presentation-time command due at or before the - // time that stream time will be presented (only between Run - // and EndRun calls, since outside of this, the mapping from - // stream time to presentation time is not known. - // -- any presentation-time command due now. - // This means that if you want accurate synchronisation on samples that - // might be processed during Paused mode, you need to use - // stream-time commands. - // - // In all cases, commands remain queued until Invoked or Cancelled. The - // setting and resetting of the event handle is managed entirely by this - // queue object. - - // set the clock used for timing - virtual HRESULT SetSyncSource(IReferenceClock*); - - // switch to run mode. Streamtime to Presentation time mapping known. - virtual HRESULT Run(REFERENCE_TIME tStreamTimeOffset); - - // switch to Stopped or Paused mode. Time mapping not known. - virtual HRESULT EndRun(); - - // return a pointer to the next due command. Blocks for msTimeout - // milliseconds until there is a due command. - // Stream-time commands will only become due between Run and Endrun calls. - // The command remains queued until invoked or cancelled. - // Returns E_ABORT if timeout occurs, otherwise S_OK (or other error). - // Returns an AddRef-ed object - virtual HRESULT GetDueCommand(CDeferredCommand ** ppCmd, long msTimeout); - - // return the event handle that will be signalled whenever - // there are deferred commands due for execution (when GetDueCommand - // will not block). - HANDLE GetDueHandle() { - return HANDLE(m_evDue); - }; - - // return a pointer to a command that will be due for a given time. - // Pass in a stream time here. The stream time offset will be passed - // in via the Run method. - // Commands remain queued until invoked or cancelled. - // This method will not block. It will report VFW_E_NOT_FOUND if there - // are no commands due yet. - // Returns an AddRef-ed object - virtual HRESULT GetCommandDueFor(REFERENCE_TIME tStream, CDeferredCommand**ppCmd); - - // check if a given time is due (TRUE if it is due yet) - BOOL CheckTime(CRefTime time, BOOL bStream) { - - // if no clock, nothing is due! - if (!m_pClock) { - return FALSE; - } - - // stream time - if (bStream) { - - // not valid if not running - if (!m_bRunning) { - return FALSE; - } - // add on known stream time offset to get presentation time - time += m_StreamTimeOffset; - } - - CRefTime Now; - m_pClock->GetTime((REFERENCE_TIME*)&Now); - return (time <= Now); - }; - -protected: - - // protect access to lists etc - CCritSec m_Lock; - - // commands queued in presentation time are stored here - CGenericList m_listPresentation; - - // commands queued in stream time are stored here - CGenericList m_listStream; - - // set when any commands are due - CAMEvent m_evDue; - - // creates an advise for the earliest time required, if any - void SetTimeAdvise(void); - - // advise id from reference clock (0 if no outstanding advise) - DWORD_PTR m_dwAdvise; - - // advise time is for this presentation time - CRefTime m_tCurrentAdvise; - - // the reference clock we are using (addrefed) - IReferenceClock* m_pClock; - - // true when running - BOOL m_bRunning; - - // contains stream time offset when m_bRunning is true - CRefTime m_StreamTimeOffset; -}; - -#endif // __CTLUTIL__ +//------------------------------------------------------------------------------ +// File: CtlUtil.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Base classes implementing IDispatch parsing for the basic control dual +// interfaces. Derive from these and implement just the custom method and +// property methods. We also implement CPosPassThru that can be used by +// renderers and transforms to pass by IMediaPosition and IMediaSeeking + +#ifndef __CTLUTIL__ +#define __CTLUTIL__ + +// OLE Automation has different ideas of TRUE and FALSE + +#define OATRUE (-1) +#define OAFALSE (0) + + +// It's possible that we could replace this class with CreateStdDispatch + +class CBaseDispatch +{ + ITypeInfo * m_pti; + +public: + + CBaseDispatch() : m_pti(NULL) {} + ~CBaseDispatch(); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + REFIID riid, + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid); +}; + + +class AM_NOVTABLE CMediaControl : + public IMediaControl, + public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CMediaControl(const TCHAR *, LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr); +}; + + +class AM_NOVTABLE CMediaEvent : + public IMediaEventEx, + public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CMediaEvent(const TCHAR *, LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr); +}; + + +class AM_NOVTABLE CMediaPosition : + public IMediaPosition, + public CUnknown +{ + CBaseDispatch m_basedisp; + + +public: + + CMediaPosition(const TCHAR *, LPUNKNOWN); + CMediaPosition(const TCHAR *, LPUNKNOWN, HRESULT *phr); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr); + +}; + + +// OA-compatibility means that we must use double as the RefTime value, +// and REFERENCE_TIME (essentially a LONGLONG) within filters. +// this class converts between the two + +class COARefTime : public CRefTime { +public: + + COARefTime() { + }; + + COARefTime(CRefTime t) + : CRefTime(t) + { + }; + + COARefTime(REFERENCE_TIME t) + : CRefTime(t) + { + }; + + COARefTime(double d) { + m_time = (LONGLONG) (d * 10000000); + }; + + operator double() { + return double(m_time) / 10000000; + }; + + operator REFERENCE_TIME() { + return m_time; + }; + + COARefTime& operator=(const double& rd) { + m_time = (LONGLONG) (rd * 10000000); + return *this; + } + + COARefTime& operator=(const REFERENCE_TIME& rt) { + m_time = rt; + return *this; + } + + inline BOOL operator==(const COARefTime& rt) + { + return m_time == rt.m_time; + }; + + inline BOOL operator!=(const COARefTime& rt) + { + return m_time != rt.m_time; + }; + + inline BOOL operator < (const COARefTime& rt) + { + return m_time < rt.m_time; + }; + + inline BOOL operator > (const COARefTime& rt) + { + return m_time > rt.m_time; + }; + + inline BOOL operator >= (const COARefTime& rt) + { + return m_time >= rt.m_time; + }; + + inline BOOL operator <= (const COARefTime& rt) + { + return m_time <= rt.m_time; + }; + + inline COARefTime operator+(const COARefTime& rt) + { + return COARefTime(m_time + rt.m_time); + }; + + inline COARefTime operator-(const COARefTime& rt) + { + return COARefTime(m_time - rt.m_time); + }; + + inline COARefTime operator*(LONG l) + { + return COARefTime(m_time * l); + }; + + inline COARefTime operator/(LONG l) + { + return COARefTime(m_time / l); + }; + +private: + // Prevent bugs from constructing from LONG (which gets + // converted to double and then multiplied by 10000000 + COARefTime(LONG); + int operator=(LONG); +}; + + +// A utility class that handles IMediaPosition and IMediaSeeking on behalf +// of single-input pin renderers, or transform filters. +// +// Renderers will expose this from the filter; transform filters will +// expose it from the output pin and not the renderer. +// +// Create one of these, giving it your IPin* for your input pin, and delegate +// all IMediaPosition methods to it. It will query the input pin for +// IMediaPosition and respond appropriately. +// +// Call ForceRefresh if the pin connection changes. +// +// This class no longer caches the upstream IMediaPosition or IMediaSeeking +// it acquires it on each method call. This means ForceRefresh is not needed. +// The method is kept for source compatibility and to minimise the changes +// if we need to put it back later for performance reasons. + +class CPosPassThru : public IMediaSeeking, public CMediaPosition +{ + IPin *m_pPin; + + HRESULT GetPeer(IMediaPosition **ppMP); + HRESULT GetPeerSeeking(IMediaSeeking **ppMS); + +public: + + CPosPassThru(const TCHAR *, LPUNKNOWN, HRESULT*, IPin *); + DECLARE_IUNKNOWN + + HRESULT ForceRefresh() { + return S_OK; + }; + + // override to return an accurate current position + virtual HRESULT GetMediaTime(LONGLONG *pStartTime,LONGLONG *pEndTime) { + return E_FAIL; + } + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv); + + // IMediaSeeking methods + STDMETHODIMP GetCapabilities( DWORD * pCapabilities ); + STDMETHODIMP CheckCapabilities( DWORD * pCapabilities ); + STDMETHODIMP SetTimeFormat(const GUID * pFormat); + STDMETHODIMP GetTimeFormat(GUID *pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID * pFormat); + STDMETHODIMP IsFormatSupported( const GUID * pFormat); + STDMETHODIMP QueryPreferredFormat( GUID *pFormat); + STDMETHODIMP ConvertTimeFormat(LONGLONG * pTarget, const GUID * pTargetFormat, + LONGLONG Source, const GUID * pSourceFormat ); + STDMETHODIMP SetPositions( LONGLONG * pCurrent, DWORD CurrentFlags + , LONGLONG * pStop, DWORD StopFlags ); + + STDMETHODIMP GetPositions( LONGLONG * pCurrent, LONGLONG * pStop ); + STDMETHODIMP GetCurrentPosition( LONGLONG * pCurrent ); + STDMETHODIMP GetStopPosition( LONGLONG * pStop ); + STDMETHODIMP SetRate( double dRate); + STDMETHODIMP GetRate( double * pdRate); + STDMETHODIMP GetDuration( LONGLONG *pDuration); + STDMETHODIMP GetAvailable( LONGLONG *pEarliest, LONGLONG *pLatest ); + STDMETHODIMP GetPreroll( LONGLONG *pllPreroll ); + + // IMediaPosition properties + STDMETHODIMP get_Duration(REFTIME * plength); + STDMETHODIMP put_CurrentPosition(REFTIME llTime); + STDMETHODIMP get_StopTime(REFTIME * pllTime); + STDMETHODIMP put_StopTime(REFTIME llTime); + STDMETHODIMP get_PrerollTime(REFTIME * pllTime); + STDMETHODIMP put_PrerollTime(REFTIME llTime); + STDMETHODIMP get_Rate(double * pdRate); + STDMETHODIMP put_Rate(double dRate); + STDMETHODIMP get_CurrentPosition(REFTIME * pllTime); + STDMETHODIMP CanSeekForward(LONG *pCanSeekForward); + STDMETHODIMP CanSeekBackward(LONG *pCanSeekBackward); + +private: + HRESULT GetSeekingLongLong( HRESULT (__stdcall IMediaSeeking::*pMethod)( LONGLONG * ), + LONGLONG * pll ); +}; + + +// Adds the ability to return a current position + +class CRendererPosPassThru : public CPosPassThru +{ + CCritSec m_PositionLock; // Locks access to our position + LONGLONG m_StartMedia; // Start media time last seen + LONGLONG m_EndMedia; // And likewise the end media + BOOL m_bReset; // Have media times been set + +public: + + // Used to help with passing media times through graph + + CRendererPosPassThru(const TCHAR *, LPUNKNOWN, HRESULT*, IPin *); + HRESULT RegisterMediaTime(IMediaSample *pMediaSample); + HRESULT RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime); + HRESULT GetMediaTime(LONGLONG *pStartTime,LONGLONG *pEndTime); + HRESULT ResetMediaTime(); + HRESULT EOS(); +}; + +STDAPI CreatePosPassThru( + LPUNKNOWN pAgg, + BOOL bRenderer, + IPin *pPin, + IUnknown **ppPassThru +); + +// A class that handles the IDispatch part of IBasicAudio and leaves the +// properties and methods themselves pure virtual. + +class AM_NOVTABLE CBasicAudio : public IBasicAudio, public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CBasicAudio(const TCHAR *, LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr); +}; + + +// A class that handles the IDispatch part of IBasicVideo and leaves the +// properties and methods themselves pure virtual. + +class AM_NOVTABLE CBaseBasicVideo : public IBasicVideo2, public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CBaseBasicVideo(const TCHAR *, LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr); + + STDMETHODIMP GetPreferredAspectRatio( + long *plAspectX, + long *plAspectY) + { + return E_NOTIMPL; + } +}; + + +// A class that handles the IDispatch part of IVideoWindow and leaves the +// properties and methods themselves pure virtual. + +class AM_NOVTABLE CBaseVideoWindow : public IVideoWindow, public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CBaseVideoWindow(const TCHAR *, LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + OLECHAR ** rgszNames, + UINT cNames, + LCID lcid, + DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr); +}; + + +// abstract class to help source filters with their implementation +// of IMediaPosition. Derive from this and set the duration (and stop +// position). Also override NotifyChange to do something when the properties +// change. + +class AM_NOVTABLE CSourcePosition : public CMediaPosition +{ + +public: + CSourcePosition(const TCHAR *, LPUNKNOWN, HRESULT*, CCritSec *); + + // IMediaPosition methods + STDMETHODIMP get_Duration(REFTIME * plength); + STDMETHODIMP put_CurrentPosition(REFTIME llTime); + STDMETHODIMP get_StopTime(REFTIME * pllTime); + STDMETHODIMP put_StopTime(REFTIME llTime); + STDMETHODIMP get_PrerollTime(REFTIME * pllTime); + STDMETHODIMP put_PrerollTime(REFTIME llTime); + STDMETHODIMP get_Rate(double * pdRate); + STDMETHODIMP put_Rate(double dRate); + STDMETHODIMP CanSeekForward(LONG *pCanSeekForward); + STDMETHODIMP CanSeekBackward(LONG *pCanSeekBackward); + + // override if you can return the data you are actually working on + STDMETHODIMP get_CurrentPosition(REFTIME * pllTime) { + return E_NOTIMPL; + }; + +protected: + + // we call this to notify changes. Override to handle them + virtual HRESULT ChangeStart() PURE; + virtual HRESULT ChangeStop() PURE; + virtual HRESULT ChangeRate() PURE; + + COARefTime m_Duration; + COARefTime m_Start; + COARefTime m_Stop; + double m_Rate; + + CCritSec * m_pLock; +}; + +class AM_NOVTABLE CSourceSeeking : + public IMediaSeeking, + public CUnknown +{ + +public: + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + // IMediaSeeking methods + + STDMETHODIMP IsFormatSupported(const GUID * pFormat); + STDMETHODIMP QueryPreferredFormat(GUID *pFormat); + STDMETHODIMP SetTimeFormat(const GUID * pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID * pFormat); + STDMETHODIMP GetTimeFormat(GUID *pFormat); + STDMETHODIMP GetDuration(LONGLONG *pDuration); + STDMETHODIMP GetStopPosition(LONGLONG *pStop); + STDMETHODIMP GetCurrentPosition(LONGLONG *pCurrent); + STDMETHODIMP GetCapabilities( DWORD * pCapabilities ); + STDMETHODIMP CheckCapabilities( DWORD * pCapabilities ); + STDMETHODIMP ConvertTimeFormat( LONGLONG * pTarget, const GUID * pTargetFormat, + LONGLONG Source, const GUID * pSourceFormat ); + + STDMETHODIMP SetPositions( LONGLONG * pCurrent, DWORD CurrentFlags + , LONGLONG * pStop, DWORD StopFlags ); + + STDMETHODIMP GetPositions( LONGLONG * pCurrent, LONGLONG * pStop ); + + STDMETHODIMP GetAvailable( LONGLONG * pEarliest, LONGLONG * pLatest ); + STDMETHODIMP SetRate( double dRate); + STDMETHODIMP GetRate( double * pdRate); + STDMETHODIMP GetPreroll(LONGLONG *pPreroll); + + +protected: + + // ctor + CSourceSeeking(const TCHAR *, LPUNKNOWN, HRESULT*, CCritSec *); + + // we call this to notify changes. Override to handle them + virtual HRESULT ChangeStart() PURE; + virtual HRESULT ChangeStop() PURE; + virtual HRESULT ChangeRate() PURE; + + CRefTime m_rtDuration; // length of stream + CRefTime m_rtStart; // source will start here + CRefTime m_rtStop; // source will stop here + double m_dRateSeeking; + + // seeking capabilities + DWORD m_dwSeekingCaps; + + CCritSec * m_pLock; +}; + + +// Base classes supporting Deferred commands. + +// Deferred commands are queued by calls to methods on the IQueueCommand +// interface, exposed by the filtergraph and by some filters. A successful +// call to one of these methods will return an IDeferredCommand interface +// representing the queued command. +// +// A CDeferredCommand object represents a single deferred command, and exposes +// the IDeferredCommand interface as well as other methods permitting time +// checks and actual execution. It contains a reference to the CCommandQueue +// object on which it is queued. +// +// CCommandQueue is a base class providing a queue of CDeferredCommand +// objects, and methods to add, remove, check status and invoke the queued +// commands. A CCommandQueue object would be part of an object that +// implemented IQueueCommand. + +class CCmdQueue; + +// take a copy of the params and store them. Release any allocated +// memory in destructor + +class CDispParams : public DISPPARAMS +{ +public: + CDispParams(UINT nArgs, VARIANT* pArgs, HRESULT *phr = NULL); + ~CDispParams(); +}; + + +// CDeferredCommand lifetime is controlled by refcounts. Caller of +// InvokeAt.. gets a refcounted interface pointer, and the CCmdQueue +// object also holds a refcount on us. Calling Cancel or Invoke takes +// us off the CCmdQueue and thus reduces the refcount by 1. Once taken +// off the queue we cannot be put back on the queue. + +class CDeferredCommand + : public CUnknown, + public IDeferredCommand +{ +public: + + CDeferredCommand( + CCmdQueue * pQ, + LPUNKNOWN pUnk, // aggregation outer unk + HRESULT * phr, + LPUNKNOWN pUnkExecutor, // object that will execute this cmd + REFTIME time, + GUID* iid, + long dispidMethod, + short wFlags, + long cArgs, + VARIANT* pDispParams, + VARIANT* pvarResult, + short* puArgErr, + BOOL bStream + ); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + // IDeferredCommand methods + STDMETHODIMP Cancel(); + STDMETHODIMP Confidence( + LONG* pConfidence); + STDMETHODIMP Postpone( + REFTIME newtime); + STDMETHODIMP GetHResult( + HRESULT* phrResult); + + // other public methods + + HRESULT Invoke(); + + // access methods + + // returns TRUE if streamtime, FALSE if presentation time + BOOL IsStreamTime() { + return m_bStream; + }; + + CRefTime GetTime() { + return m_time; + }; + + REFIID GetIID() { + return *m_iid; + }; + + long GetMethod() { + return m_dispidMethod; + }; + + short GetFlags() { + return m_wFlags; + }; + + DISPPARAMS* GetParams() { + return &m_DispParams; + }; + + VARIANT* GetResult() { + return m_pvarResult; + }; + +protected: + + CCmdQueue* m_pQueue; + + // pUnk for the interface that we will execute the command on + LPUNKNOWN m_pUnk; + + // stored command data + REFERENCE_TIME m_time; + GUID* m_iid; + long m_dispidMethod; + short m_wFlags; + VARIANT* m_pvarResult; + BOOL m_bStream; + CDispParams m_DispParams; + DISPID m_DispId; // For get and put + + // we use this for ITypeInfo access + CBaseDispatch m_Dispatch; + + // save retval here + HRESULT m_hrResult; +}; + + +// a list of CDeferredCommand objects. this is a base class providing +// the basics of access to the list. If you want to use CDeferredCommand +// objects then your queue needs to be derived from this class. + +class AM_NOVTABLE CCmdQueue +{ +public: + CCmdQueue(); + virtual ~CCmdQueue(); + + // returns a new CDeferredCommand object that will be initialised with + // the parameters and will be added to the queue during construction. + // returns S_OK if successfully created otherwise an error and + // no object has been queued. + virtual HRESULT New( + CDeferredCommand **ppCmd, + LPUNKNOWN pUnk, + REFTIME time, + GUID* iid, + long dispidMethod, + short wFlags, + long cArgs, + VARIANT* pDispParams, + VARIANT* pvarResult, + short* puArgErr, + BOOL bStream + ); + + // called by the CDeferredCommand object to add and remove itself + // from the queue + virtual HRESULT Insert(CDeferredCommand* pCmd); + virtual HRESULT Remove(CDeferredCommand* pCmd); + + // Command-Due Checking + // + // There are two schemes of synchronisation: coarse and accurate. In + // coarse mode, you wait till the time arrives and then execute the cmd. + // In accurate mode, you wait until you are processing the sample that + // will appear at the time, and then execute the command. It's up to the + // filter which one it will implement. The filtergraph will always + // implement coarse mode for commands queued at the filtergraph. + // + // If you want coarse sync, you probably want to wait until there is a + // command due, and then execute it. You can do this by calling + // GetDueCommand. If you have several things to wait for, get the + // event handle from GetDueHandle() and when this is signalled then call + // GetDueCommand. Stream time will only advance between calls to Run and + // EndRun. Note that to avoid an extra thread there is no guarantee that + // if the handle is set there will be a command ready. Each time the + // event is signalled, call GetDueCommand (probably with a 0 timeout); + // This may return E_ABORT. + // + // If you want accurate sync, you must call GetCommandDueFor, passing + // as a parameter the stream time of the samples you are about to process. + // This will return: + // -- a stream-time command due at or before that stream time + // -- a presentation-time command due at or before the + // time that stream time will be presented (only between Run + // and EndRun calls, since outside of this, the mapping from + // stream time to presentation time is not known. + // -- any presentation-time command due now. + // This means that if you want accurate synchronisation on samples that + // might be processed during Paused mode, you need to use + // stream-time commands. + // + // In all cases, commands remain queued until Invoked or Cancelled. The + // setting and resetting of the event handle is managed entirely by this + // queue object. + + // set the clock used for timing + virtual HRESULT SetSyncSource(IReferenceClock*); + + // switch to run mode. Streamtime to Presentation time mapping known. + virtual HRESULT Run(REFERENCE_TIME tStreamTimeOffset); + + // switch to Stopped or Paused mode. Time mapping not known. + virtual HRESULT EndRun(); + + // return a pointer to the next due command. Blocks for msTimeout + // milliseconds until there is a due command. + // Stream-time commands will only become due between Run and Endrun calls. + // The command remains queued until invoked or cancelled. + // Returns E_ABORT if timeout occurs, otherwise S_OK (or other error). + // Returns an AddRef-ed object + virtual HRESULT GetDueCommand(CDeferredCommand ** ppCmd, long msTimeout); + + // return the event handle that will be signalled whenever + // there are deferred commands due for execution (when GetDueCommand + // will not block). + HANDLE GetDueHandle() { + return HANDLE(m_evDue); + }; + + // return a pointer to a command that will be due for a given time. + // Pass in a stream time here. The stream time offset will be passed + // in via the Run method. + // Commands remain queued until invoked or cancelled. + // This method will not block. It will report VFW_E_NOT_FOUND if there + // are no commands due yet. + // Returns an AddRef-ed object + virtual HRESULT GetCommandDueFor(REFERENCE_TIME tStream, CDeferredCommand**ppCmd); + + // check if a given time is due (TRUE if it is due yet) + BOOL CheckTime(CRefTime time, BOOL bStream) { + + // if no clock, nothing is due! + if (!m_pClock) { + return FALSE; + } + + // stream time + if (bStream) { + + // not valid if not running + if (!m_bRunning) { + return FALSE; + } + // add on known stream time offset to get presentation time + time += m_StreamTimeOffset; + } + + CRefTime Now; + m_pClock->GetTime((REFERENCE_TIME*)&Now); + return (time <= Now); + }; + +protected: + + // protect access to lists etc + CCritSec m_Lock; + + // commands queued in presentation time are stored here + CGenericList m_listPresentation; + + // commands queued in stream time are stored here + CGenericList m_listStream; + + // set when any commands are due + CAMEvent m_evDue; + + // creates an advise for the earliest time required, if any + void SetTimeAdvise(void); + + // advise id from reference clock (0 if no outstanding advise) + DWORD_PTR m_dwAdvise; + + // advise time is for this presentation time + CRefTime m_tCurrentAdvise; + + // the reference clock we are using (addrefed) + IReferenceClock* m_pClock; + + // true when running + BOOL m_bRunning; + + // contains stream time offset when m_bRunning is true + CRefTime m_StreamTimeOffset; +}; + +#endif // __CTLUTIL__ diff --git a/plugins/GSdx/baseclasses/ddmm.cpp b/plugins/GSdx/baseclasses/ddmm.cpp index 079a35e474..85ccc65012 100644 --- a/plugins/GSdx/baseclasses/ddmm.cpp +++ b/plugins/GSdx/baseclasses/ddmm.cpp @@ -1,129 +1,129 @@ -//------------------------------------------------------------------------------ -// File: DDMM.cpp -// -// Desc: DirectShow base classes - implements routines for using DirectDraw -// on a multimonitor system. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include -#include "ddmm.h" - -/* - * FindDeviceCallback - */ -typedef struct { - LPSTR szDevice; - GUID* lpGUID; - GUID GUID; - BOOL fFound; -} FindDeviceData; - -BOOL CALLBACK FindDeviceCallback(GUID* lpGUID, LPSTR szName, LPSTR szDevice, LPVOID lParam) -{ - FindDeviceData *p = (FindDeviceData*)lParam; - - if (lstrcmpiA(p->szDevice, szDevice) == 0) { - if (lpGUID) { - p->GUID = *lpGUID; - p->lpGUID = &p->GUID; - } else { - p->lpGUID = NULL; - } - p->fFound = TRUE; - return FALSE; - } - return TRUE; -} - - -BOOL CALLBACK FindDeviceCallbackEx(GUID* lpGUID, LPSTR szName, LPSTR szDevice, LPVOID lParam, HMONITOR hMonitor) -{ - FindDeviceData *p = (FindDeviceData*)lParam; - - if (lstrcmpiA(p->szDevice, szDevice) == 0) { - if (lpGUID) { - p->GUID = *lpGUID; - p->lpGUID = &p->GUID; - } else { - p->lpGUID = NULL; - } - p->fFound = TRUE; - return FALSE; - } - return TRUE; -} - - -/* - * DirectDrawCreateFromDevice - * - * create a DirectDraw object for a particular device - */ -IDirectDraw * DirectDrawCreateFromDevice(LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, PDRAWENUM DirectDrawEnumerateP) -{ - IDirectDraw* pdd = NULL; - FindDeviceData find; - - if (szDevice == NULL) { - DirectDrawCreateP(NULL, &pdd, NULL); - return pdd; - } - - find.szDevice = szDevice; - find.fFound = FALSE; - DirectDrawEnumerateP(FindDeviceCallback, (LPVOID)&find); - - if (find.fFound) - { - // - // In 4bpp mode the following DDraw call causes a message box to be popped - // up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we - // make sure it doesn't happen. - // - UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); - DirectDrawCreateP(find.lpGUID, &pdd, NULL); - SetErrorMode(ErrorMode); - } - - return pdd; -} - - -/* - * DirectDrawCreateFromDeviceEx - * - * create a DirectDraw object for a particular device - */ -IDirectDraw * DirectDrawCreateFromDeviceEx(LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, LPDIRECTDRAWENUMERATEEXA DirectDrawEnumerateExP) -{ - IDirectDraw* pdd = NULL; - FindDeviceData find; - - if (szDevice == NULL) { - DirectDrawCreateP(NULL, &pdd, NULL); - return pdd; - } - - find.szDevice = szDevice; - find.fFound = FALSE; - DirectDrawEnumerateExP(FindDeviceCallbackEx, (LPVOID)&find, - DDENUM_ATTACHEDSECONDARYDEVICES); - - if (find.fFound) - { - // - // In 4bpp mode the following DDraw call causes a message box to be popped - // up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we - // make sure it doesn't happen. - // - UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); - DirectDrawCreateP(find.lpGUID, &pdd, NULL); - SetErrorMode(ErrorMode); - } - - return pdd; -} +//------------------------------------------------------------------------------ +// File: DDMM.cpp +// +// Desc: DirectShow base classes - implements routines for using DirectDraw +// on a multimonitor system. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include +#include "ddmm.h" + +/* + * FindDeviceCallback + */ +typedef struct { + LPSTR szDevice; + GUID* lpGUID; + GUID GUID; + BOOL fFound; +} FindDeviceData; + +BOOL CALLBACK FindDeviceCallback(GUID* lpGUID, LPSTR szName, LPSTR szDevice, LPVOID lParam) +{ + FindDeviceData *p = (FindDeviceData*)lParam; + + if (lstrcmpiA(p->szDevice, szDevice) == 0) { + if (lpGUID) { + p->GUID = *lpGUID; + p->lpGUID = &p->GUID; + } else { + p->lpGUID = NULL; + } + p->fFound = TRUE; + return FALSE; + } + return TRUE; +} + + +BOOL CALLBACK FindDeviceCallbackEx(GUID* lpGUID, LPSTR szName, LPSTR szDevice, LPVOID lParam, HMONITOR hMonitor) +{ + FindDeviceData *p = (FindDeviceData*)lParam; + + if (lstrcmpiA(p->szDevice, szDevice) == 0) { + if (lpGUID) { + p->GUID = *lpGUID; + p->lpGUID = &p->GUID; + } else { + p->lpGUID = NULL; + } + p->fFound = TRUE; + return FALSE; + } + return TRUE; +} + + +/* + * DirectDrawCreateFromDevice + * + * create a DirectDraw object for a particular device + */ +IDirectDraw * DirectDrawCreateFromDevice(LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, PDRAWENUM DirectDrawEnumerateP) +{ + IDirectDraw* pdd = NULL; + FindDeviceData find; + + if (szDevice == NULL) { + DirectDrawCreateP(NULL, &pdd, NULL); + return pdd; + } + + find.szDevice = szDevice; + find.fFound = FALSE; + DirectDrawEnumerateP(FindDeviceCallback, (LPVOID)&find); + + if (find.fFound) + { + // + // In 4bpp mode the following DDraw call causes a message box to be popped + // up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we + // make sure it doesn't happen. + // + UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); + DirectDrawCreateP(find.lpGUID, &pdd, NULL); + SetErrorMode(ErrorMode); + } + + return pdd; +} + + +/* + * DirectDrawCreateFromDeviceEx + * + * create a DirectDraw object for a particular device + */ +IDirectDraw * DirectDrawCreateFromDeviceEx(LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, LPDIRECTDRAWENUMERATEEXA DirectDrawEnumerateExP) +{ + IDirectDraw* pdd = NULL; + FindDeviceData find; + + if (szDevice == NULL) { + DirectDrawCreateP(NULL, &pdd, NULL); + return pdd; + } + + find.szDevice = szDevice; + find.fFound = FALSE; + DirectDrawEnumerateExP(FindDeviceCallbackEx, (LPVOID)&find, + DDENUM_ATTACHEDSECONDARYDEVICES); + + if (find.fFound) + { + // + // In 4bpp mode the following DDraw call causes a message box to be popped + // up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we + // make sure it doesn't happen. + // + UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); + DirectDrawCreateP(find.lpGUID, &pdd, NULL); + SetErrorMode(ErrorMode); + } + + return pdd; +} diff --git a/plugins/GSdx/baseclasses/ddmm.h b/plugins/GSdx/baseclasses/ddmm.h index 678bec3f66..c790754882 100644 --- a/plugins/GSdx/baseclasses/ddmm.h +++ b/plugins/GSdx/baseclasses/ddmm.h @@ -1,28 +1,28 @@ -//------------------------------------------------------------------------------ -// File: DDMM.h -// -// Desc: DirectShow base classes - efines routines for using DirectDraw -// on a multimonitor system. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifdef __cplusplus -extern "C" { /* Assume C declarations for C++ */ -#endif /* __cplusplus */ - -// DDRAW.H might not include these -#ifndef DDENUM_ATTACHEDSECONDARYDEVICES -#define DDENUM_ATTACHEDSECONDARYDEVICES 0x00000001L -#endif - -typedef HRESULT (*PDRAWCREATE)(IID *,LPDIRECTDRAW *,LPUNKNOWN); -typedef HRESULT (*PDRAWENUM)(LPDDENUMCALLBACKA, LPVOID); - -IDirectDraw * DirectDrawCreateFromDevice(LPSTR, PDRAWCREATE, PDRAWENUM); -IDirectDraw * DirectDrawCreateFromDeviceEx(LPSTR, PDRAWCREATE, LPDIRECTDRAWENUMERATEEXA); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ +//------------------------------------------------------------------------------ +// File: DDMM.h +// +// Desc: DirectShow base classes - efines routines for using DirectDraw +// on a multimonitor system. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +// DDRAW.H might not include these +#ifndef DDENUM_ATTACHEDSECONDARYDEVICES +#define DDENUM_ATTACHEDSECONDARYDEVICES 0x00000001L +#endif + +typedef HRESULT (*PDRAWCREATE)(IID *,LPDIRECTDRAW *,LPUNKNOWN); +typedef HRESULT (*PDRAWENUM)(LPDDENUMCALLBACKA, LPVOID); + +IDirectDraw * DirectDrawCreateFromDevice(LPSTR, PDRAWCREATE, PDRAWENUM); +IDirectDraw * DirectDrawCreateFromDeviceEx(LPSTR, PDRAWCREATE, LPDIRECTDRAWENUMERATEEXA); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ diff --git a/plugins/GSdx/baseclasses/dsschedule.h b/plugins/GSdx/baseclasses/dsschedule.h index cc21b1c3ce..a81c5760a4 100644 --- a/plugins/GSdx/baseclasses/dsschedule.h +++ b/plugins/GSdx/baseclasses/dsschedule.h @@ -1,128 +1,128 @@ -//------------------------------------------------------------------------------ -// File: DSSchedule.h (replaces DirectX 8's schedule.h) -// -// Desc: DirectShow base classes. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __CAMSchedule__ -#define __CAMSchedule__ - -class CAMSchedule : private CBaseObject -{ -public: - virtual ~CAMSchedule(); - // ev is the event we should fire if the advise time needs re-evaluating - CAMSchedule( HANDLE ev ); - - DWORD GetAdviseCount(); - REFERENCE_TIME GetNextAdviseTime(); - - // We need a method for derived classes to add advise packets, we return the cookie - DWORD_PTR AddAdvisePacket( const REFERENCE_TIME & time1, const REFERENCE_TIME & time2, HANDLE h, BOOL periodic ); - // And a way to cancel - HRESULT Unadvise(DWORD_PTR dwAdviseCookie); - - // Tell us the time please, and we'll dispatch the expired events. We return the time of the next event. - // NB: The time returned will be "useless" if you start adding extra Advises. But that's the problem of - // whoever is using this helper class (typically a clock). - REFERENCE_TIME Advise( const REFERENCE_TIME & rtTime ); - - // Get the event handle which will be set if advise time requires re-evaluation. - HANDLE GetEvent() const { return m_ev; } - -private: - // We define the nodes that will be used in our singly linked list - // of advise packets. The list is ordered by time, with the - // elements that will expire first at the front. - class CAdvisePacket - { - public: - CAdvisePacket() - {} - - CAdvisePacket * m_next; - DWORD_PTR m_dwAdviseCookie; - REFERENCE_TIME m_rtEventTime; // Time at which event should be set - REFERENCE_TIME m_rtPeriod; // Periodic time - HANDLE m_hNotify; // Handle to event or semephore - BOOL m_bPeriodic; // TRUE => Periodic event - - CAdvisePacket( CAdvisePacket * next, LONGLONG time ) : m_next(next), m_rtEventTime(time) - {} - - void InsertAfter( CAdvisePacket * p ) - { - p->m_next = m_next; - m_next = p; - } - - int IsZ() const // That is, is it the node that represents the end of the list - { return m_next == 0; } - - CAdvisePacket * RemoveNext() - { - CAdvisePacket *const next = m_next; - CAdvisePacket *const new_next = next->m_next; - m_next = new_next; - return next; - } - - void DeleteNext() - { - delete RemoveNext(); - } - - CAdvisePacket * Next() const - { - CAdvisePacket * result = m_next; - if (result->IsZ()) result = 0; - return result; - } - - DWORD_PTR Cookie() const - { return m_dwAdviseCookie; } - }; - - // Structure is: - // head -> elmt1 -> elmt2 -> z -> null - // So an empty list is: head -> z -> null - // Having head & z as links makes insertaion, - // deletion and shunting much easier. - CAdvisePacket head, z; // z is both a tail and a sentry - - volatile DWORD_PTR m_dwNextCookie; // Strictly increasing - volatile DWORD m_dwAdviseCount; // Number of elements on list - - CCritSec m_Serialize; - - // AddAdvisePacket: adds the packet, returns the cookie (0 if failed) - DWORD_PTR AddAdvisePacket( CAdvisePacket * pPacket ); - // Event that we should set if the packed added above will be the next to fire. - const HANDLE m_ev; - - // A Shunt is where we have changed the first element in the - // list and want it re-evaluating (i.e. repositioned) in - // the list. - void ShuntHead(); - - // Rather than delete advise packets, we cache them for future use - CAdvisePacket * m_pAdviseCache; - DWORD m_dwCacheCount; - enum { dwCacheMax = 5 }; // Don't bother caching more than five - - void Delete( CAdvisePacket * pLink );// This "Delete" will cache the Link - -// Attributes and methods for debugging -public: -#ifdef DEBUG - void DumpLinkedList(); -#else - void DumpLinkedList() {} -#endif - -}; - -#endif // __CAMSchedule__ +//------------------------------------------------------------------------------ +// File: DSSchedule.h (replaces DirectX 8's schedule.h) +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __CAMSchedule__ +#define __CAMSchedule__ + +class CAMSchedule : private CBaseObject +{ +public: + virtual ~CAMSchedule(); + // ev is the event we should fire if the advise time needs re-evaluating + CAMSchedule( HANDLE ev ); + + DWORD GetAdviseCount(); + REFERENCE_TIME GetNextAdviseTime(); + + // We need a method for derived classes to add advise packets, we return the cookie + DWORD_PTR AddAdvisePacket( const REFERENCE_TIME & time1, const REFERENCE_TIME & time2, HANDLE h, BOOL periodic ); + // And a way to cancel + HRESULT Unadvise(DWORD_PTR dwAdviseCookie); + + // Tell us the time please, and we'll dispatch the expired events. We return the time of the next event. + // NB: The time returned will be "useless" if you start adding extra Advises. But that's the problem of + // whoever is using this helper class (typically a clock). + REFERENCE_TIME Advise( const REFERENCE_TIME & rtTime ); + + // Get the event handle which will be set if advise time requires re-evaluation. + HANDLE GetEvent() const { return m_ev; } + +private: + // We define the nodes that will be used in our singly linked list + // of advise packets. The list is ordered by time, with the + // elements that will expire first at the front. + class CAdvisePacket + { + public: + CAdvisePacket() + {} + + CAdvisePacket * m_next; + DWORD_PTR m_dwAdviseCookie; + REFERENCE_TIME m_rtEventTime; // Time at which event should be set + REFERENCE_TIME m_rtPeriod; // Periodic time + HANDLE m_hNotify; // Handle to event or semephore + BOOL m_bPeriodic; // TRUE => Periodic event + + CAdvisePacket( CAdvisePacket * next, LONGLONG time ) : m_next(next), m_rtEventTime(time) + {} + + void InsertAfter( CAdvisePacket * p ) + { + p->m_next = m_next; + m_next = p; + } + + int IsZ() const // That is, is it the node that represents the end of the list + { return m_next == 0; } + + CAdvisePacket * RemoveNext() + { + CAdvisePacket *const next = m_next; + CAdvisePacket *const new_next = next->m_next; + m_next = new_next; + return next; + } + + void DeleteNext() + { + delete RemoveNext(); + } + + CAdvisePacket * Next() const + { + CAdvisePacket * result = m_next; + if (result->IsZ()) result = 0; + return result; + } + + DWORD_PTR Cookie() const + { return m_dwAdviseCookie; } + }; + + // Structure is: + // head -> elmt1 -> elmt2 -> z -> null + // So an empty list is: head -> z -> null + // Having head & z as links makes insertaion, + // deletion and shunting much easier. + CAdvisePacket head, z; // z is both a tail and a sentry + + volatile DWORD_PTR m_dwNextCookie; // Strictly increasing + volatile DWORD m_dwAdviseCount; // Number of elements on list + + CCritSec m_Serialize; + + // AddAdvisePacket: adds the packet, returns the cookie (0 if failed) + DWORD_PTR AddAdvisePacket( CAdvisePacket * pPacket ); + // Event that we should set if the packed added above will be the next to fire. + const HANDLE m_ev; + + // A Shunt is where we have changed the first element in the + // list and want it re-evaluating (i.e. repositioned) in + // the list. + void ShuntHead(); + + // Rather than delete advise packets, we cache them for future use + CAdvisePacket * m_pAdviseCache; + DWORD m_dwCacheCount; + enum { dwCacheMax = 5 }; // Don't bother caching more than five + + void Delete( CAdvisePacket * pLink );// This "Delete" will cache the Link + +// Attributes and methods for debugging +public: +#ifdef DEBUG + void DumpLinkedList(); +#else + void DumpLinkedList() {} +#endif + +}; + +#endif // __CAMSchedule__ diff --git a/plugins/GSdx/baseclasses/fourcc.h b/plugins/GSdx/baseclasses/fourcc.h index dea8171a6b..ae20ab3425 100644 --- a/plugins/GSdx/baseclasses/fourcc.h +++ b/plugins/GSdx/baseclasses/fourcc.h @@ -1,101 +1,101 @@ -//------------------------------------------------------------------------------ -// File: FourCC.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// FOURCCMap -// -// provides a mapping between old-style multimedia format DWORDs -// and new-style GUIDs. -// -// A range of 4 billion GUIDs has been allocated to ensure that this -// mapping can be done straightforwardly one-to-one in both directions. -// -// January 95 - - -#ifndef __FOURCC__ -#define __FOURCC__ - - -// Multimedia format types are marked with DWORDs built from four 8-bit -// chars and known as FOURCCs. New multimedia AM_MEDIA_TYPE definitions include -// a subtype GUID. In order to simplify the mapping, GUIDs in the range: -// XXXXXXXX-0000-0010-8000-00AA00389B71 -// are reserved for FOURCCs. - -class FOURCCMap : public GUID -{ - -public: - FOURCCMap(); - FOURCCMap(DWORD Fourcc); - FOURCCMap(const GUID *); - - - DWORD GetFOURCC(void); - void SetFOURCC(DWORD fourcc); - void SetFOURCC(const GUID *); - -private: - void InitGUID(); -}; - -#define GUID_Data2 0 -#define GUID_Data3 0x10 -#define GUID_Data4_1 0xaa000080 -#define GUID_Data4_2 0x719b3800 - -inline void -FOURCCMap::InitGUID() { - Data2 = GUID_Data2; - Data3 = GUID_Data3; - ((DWORD *)Data4)[0] = GUID_Data4_1; - ((DWORD *)Data4)[1] = GUID_Data4_2; -} - -inline -FOURCCMap::FOURCCMap() { - InitGUID(); - SetFOURCC( DWORD(0)); -} - -inline -FOURCCMap::FOURCCMap(DWORD fourcc) -{ - InitGUID(); - SetFOURCC(fourcc); -} - -inline -FOURCCMap::FOURCCMap(const GUID * pGuid) -{ - InitGUID(); - SetFOURCC(pGuid); -} - -inline void -FOURCCMap::SetFOURCC(const GUID * pGuid) -{ - FOURCCMap * p = (FOURCCMap*) pGuid; - SetFOURCC(p->GetFOURCC()); -} - -inline void -FOURCCMap::SetFOURCC(DWORD fourcc) -{ - Data1 = fourcc; -} - -inline DWORD -FOURCCMap::GetFOURCC(void) -{ - return Data1; -} - -#endif /* __FOURCC__ */ - +//------------------------------------------------------------------------------ +// File: FourCC.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// FOURCCMap +// +// provides a mapping between old-style multimedia format DWORDs +// and new-style GUIDs. +// +// A range of 4 billion GUIDs has been allocated to ensure that this +// mapping can be done straightforwardly one-to-one in both directions. +// +// January 95 + + +#ifndef __FOURCC__ +#define __FOURCC__ + + +// Multimedia format types are marked with DWORDs built from four 8-bit +// chars and known as FOURCCs. New multimedia AM_MEDIA_TYPE definitions include +// a subtype GUID. In order to simplify the mapping, GUIDs in the range: +// XXXXXXXX-0000-0010-8000-00AA00389B71 +// are reserved for FOURCCs. + +class FOURCCMap : public GUID +{ + +public: + FOURCCMap(); + FOURCCMap(DWORD Fourcc); + FOURCCMap(const GUID *); + + + DWORD GetFOURCC(void); + void SetFOURCC(DWORD fourcc); + void SetFOURCC(const GUID *); + +private: + void InitGUID(); +}; + +#define GUID_Data2 0 +#define GUID_Data3 0x10 +#define GUID_Data4_1 0xaa000080 +#define GUID_Data4_2 0x719b3800 + +inline void +FOURCCMap::InitGUID() { + Data2 = GUID_Data2; + Data3 = GUID_Data3; + ((DWORD *)Data4)[0] = GUID_Data4_1; + ((DWORD *)Data4)[1] = GUID_Data4_2; +} + +inline +FOURCCMap::FOURCCMap() { + InitGUID(); + SetFOURCC( DWORD(0)); +} + +inline +FOURCCMap::FOURCCMap(DWORD fourcc) +{ + InitGUID(); + SetFOURCC(fourcc); +} + +inline +FOURCCMap::FOURCCMap(const GUID * pGuid) +{ + InitGUID(); + SetFOURCC(pGuid); +} + +inline void +FOURCCMap::SetFOURCC(const GUID * pGuid) +{ + FOURCCMap * p = (FOURCCMap*) pGuid; + SetFOURCC(p->GetFOURCC()); +} + +inline void +FOURCCMap::SetFOURCC(DWORD fourcc) +{ + Data1 = fourcc; +} + +inline DWORD +FOURCCMap::GetFOURCC(void) +{ + return Data1; +} + +#endif /* __FOURCC__ */ + diff --git a/plugins/GSdx/baseclasses/measure.h b/plugins/GSdx/baseclasses/measure.h index 75365e3a66..f90eb15897 100644 --- a/plugins/GSdx/baseclasses/measure.h +++ b/plugins/GSdx/baseclasses/measure.h @@ -1,222 +1,222 @@ -//------------------------------------------------------------------------------ -// File: Measure.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -/* - The idea is to pepper the source code with interesting measurements and - have the last few thousand of these recorded in a circular buffer that - can be post-processed to give interesting numbers. - - WHAT THE LOG LOOKS LIKE: - - Time (sec) Type Delta Incident_Name - 0.055,41 NOTE -. Incident Nine - Another note - 0.055,42 NOTE 0.000,01 Incident Nine - Another note - 0.055,44 NOTE 0.000,02 Incident Nine - Another note - 0.055,45 STOP -. Incident Eight - Also random - 0.055,47 START -. Incident Seven - Random - 0.055,49 NOTE 0.000,05 Incident Nine - Another note - ------- ---------------- - 0.125,60 STOP 0.000,03 Msr_Stop - 0.125,62 START -. Msr_Start - 0.125,63 START -. Incident Two - Start/Stop - 0.125,65 STOP 0.000,03 Msr_Start - 0.125,66 START -. Msr_Stop - 0.125,68 STOP 0.000,05 Incident Two - Start/Stop - 0.125,70 STOP 0.000,04 Msr_Stop - 0.125,72 START -. Msr_Start - 0.125,73 START -. Incident Two - Start/Stop - 0.125,75 STOP 0.000,03 Msr_Start - 0.125,77 START -. Msr_Stop - 0.125,78 STOP 0.000,05 Incident Two - Start/Stop - 0.125,80 STOP 0.000,03 Msr_Stop - 0.125,81 NOTE -. Incident Three - single Note - 0.125,83 START -. Incident Four - Start, no stop - 0.125,85 START -. Incident Five - Single Start/Stop - 0.125,87 STOP 0.000,02 Incident Five - Single Start/Stop - -Number Average StdDev Smallest Largest Incident_Name - 10 0.000,58 0.000,10 0.000,55 0.000,85 Incident One - Note - 50 0.000,05 0.000,00 0.000,05 0.000,05 Incident Two - Start/Stop - 1 -. -. -. -. Incident Three - single Note - 0 -. -. -. -. Incident Four - Start, no stop - 1 0.000,02 -. 0.000,02 0.000,02 Incident Five - Single Start/Stop - 0 -. -. -. -. Incident Six - zero occurrences - 100 0.000,25 0.000,12 0.000,02 0.000,62 Incident Seven - Random - 100 0.000,79 0.000,48 0.000,02 0.001,92 Incident Eight - Also random - 5895 0.000,01 0.000,01 0.000,01 0.000,56 Incident Nine - Another note - 10 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Note - 50 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Start - 50 0.000,04 0.000,03 0.000,03 0.000,31 Msr_Stop - - WHAT IT MEANS: - The log shows what happened and when. Each line shows the time at which - something happened (see WHAT YOU CODE below) what it was that happened - and (if approporate) the time since the corresponding previous event - (that's the delta column). - - The statistics show how many times each event occurred, what the average - delta time was, also the standard deviation, largest and smalles delta. - - WHAT YOU CODE: - - Before anything else executes: - register your ids - - int id1 = Msr_Register("Incident One - Note"); - int id2 = Msr_Register("Incident Two - Start/Stop"); - int id3 = Msr_Register("Incident Three - single Note"); - etc. - - At interesting moments: - - // To measure a repetitive event - e.g. end of bitblt to screen - Msr_Note(Id9); // e.g. "video frame hiting the screen NOW!" - - or - - // To measure an elapsed time e.g. time taken to decode an MPEG B-frame - Msr_Start(Id2); // e.g. "Starting to decode MPEG B-frame" - . . . - MsrStop(Id2); // "Finished MPEG decode" - - At the end: - - HANDLE hFile; - hFile = CreateFile("Perf.log", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); - Msr_Dump(hFile); // This writes the log out to the file - CloseHandle(hFile); - - or - - Msr_Dump(NULL); // This writes it to DbgLog((LOG_TRACE,0, ... )); - // but if you are writing it out to the debugger - // then the times are probably all garbage because - // the debugger can make things run awfully slow. - - A given id should be used either for start / stop or Note calls. If Notes - are mixed in with Starts and Stops their statistics will be gibberish. - - If you code the calls in upper case i.e. MSR_START(idMunge); then you get - macros which will turn into nothing unless PERF is defined. - - You can reset the statistical counts for a given id by calling Reset(Id). - They are reset by default at the start. - It logs Reset as a special incident, so you can see it in the log. - - The log is a circular buffer in storage (to try to minimise disk I/O). - It overwrites the oldest entries once full. The statistics include ALL - incidents since the last Reset, whether still visible in the log or not. -*/ - -#ifndef __MEASURE__ -#define __MEASURE__ - -#ifdef PERF -#define MSR_INIT() Msr_Init() -#define MSR_TERMINATE() Msr_Terminate() -#define MSR_REGISTER(a) Msr_Register(a) -#define MSR_RESET(a) Msr_Reset(a) -#define MSR_CONTROL(a) Msr_Control(a) -#define MSR_START(a) Msr_Start(a) -#define MSR_STOP(a) Msr_Stop(a) -#define MSR_NOTE(a) Msr_Note(a) -#define MSR_INTEGER(a,b) Msr_Integer(a,b) -#define MSR_DUMP(a) Msr_Dump(a) -#define MSR_DUMPSTATS(a) Msr_DumpStats(a) -#else -#define MSR_INIT() ((void)0) -#define MSR_TERMINATE() ((void)0) -#define MSR_REGISTER(a) 0 -#define MSR_RESET(a) ((void)0) -#define MSR_CONTROL(a) ((void)0) -#define MSR_START(a) ((void)0) -#define MSR_STOP(a) ((void)0) -#define MSR_NOTE(a) ((void)0) -#define MSR_INTEGER(a,b) ((void)0) -#define MSR_DUMP(a) ((void)0) -#define MSR_DUMPSTATS(a) ((void)0) -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// This must be called first - (called by the DllEntry) - -void WINAPI Msr_Init(void); - - -// Call this last to clean up (or just let it fall off the end - who cares?) - -void WINAPI Msr_Terminate(void); - - -// Call this to get an Id for an "incident" that you can pass to Start, Stop or Note -// everything that's logged is called an "incident". - -int WINAPI Msr_Register(LPTSTR Incident); - - -// Reset the statistical counts for an incident - -void WINAPI Msr_Reset(int Id); - - -// Reset all the counts for all incidents -#define MSR_RESET_ALL 0 -#define MSR_PAUSE 1 -#define MSR_RUN 2 - -void WINAPI Msr_Control(int iAction); - - -// log the start of an operation - -void WINAPI Msr_Start(int Id); - - -// log the end of an operation - -void WINAPI Msr_Stop(int Id); - - -// log a one-off or repetitive operation - -void WINAPI Msr_Note(int Id); - - -// log an integer (on which we can see statistics later) -void WINAPI Msr_Integer(int Id, int n); - - -// print out all the vaialable log (it may have wrapped) and then the statistics. -// When the log wraps you lose log but the statistics are still complete. -// hFIle==NULL => use DbgLog -// otherwise hFile must have come from CreateFile or OpenFile. - -void WINAPI Msr_Dump(HANDLE hFile); - - -// just dump the statistics - never mind the log - -void WINAPI Msr_DumpStats(HANDLE hFile); - -// Type definitions in case you want to declare a pointer to the dump functions -// (makes it a trifle easier to do dynamic linking -// i.e. LoadModule, GetProcAddress and call that) - -// Typedefs so can declare MSR_DUMPPROC *MsrDumpStats; or whatever -typedef void WINAPI MSR_DUMPPROC(HANDLE hFile); -typedef void WINAPI MSR_CONTROLPROC(int iAction); - - -#ifdef __cplusplus -} -#endif - -#endif // __MEASURE__ +//------------------------------------------------------------------------------ +// File: Measure.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* + The idea is to pepper the source code with interesting measurements and + have the last few thousand of these recorded in a circular buffer that + can be post-processed to give interesting numbers. + + WHAT THE LOG LOOKS LIKE: + + Time (sec) Type Delta Incident_Name + 0.055,41 NOTE -. Incident Nine - Another note + 0.055,42 NOTE 0.000,01 Incident Nine - Another note + 0.055,44 NOTE 0.000,02 Incident Nine - Another note + 0.055,45 STOP -. Incident Eight - Also random + 0.055,47 START -. Incident Seven - Random + 0.055,49 NOTE 0.000,05 Incident Nine - Another note + ------- ---------------- + 0.125,60 STOP 0.000,03 Msr_Stop + 0.125,62 START -. Msr_Start + 0.125,63 START -. Incident Two - Start/Stop + 0.125,65 STOP 0.000,03 Msr_Start + 0.125,66 START -. Msr_Stop + 0.125,68 STOP 0.000,05 Incident Two - Start/Stop + 0.125,70 STOP 0.000,04 Msr_Stop + 0.125,72 START -. Msr_Start + 0.125,73 START -. Incident Two - Start/Stop + 0.125,75 STOP 0.000,03 Msr_Start + 0.125,77 START -. Msr_Stop + 0.125,78 STOP 0.000,05 Incident Two - Start/Stop + 0.125,80 STOP 0.000,03 Msr_Stop + 0.125,81 NOTE -. Incident Three - single Note + 0.125,83 START -. Incident Four - Start, no stop + 0.125,85 START -. Incident Five - Single Start/Stop + 0.125,87 STOP 0.000,02 Incident Five - Single Start/Stop + +Number Average StdDev Smallest Largest Incident_Name + 10 0.000,58 0.000,10 0.000,55 0.000,85 Incident One - Note + 50 0.000,05 0.000,00 0.000,05 0.000,05 Incident Two - Start/Stop + 1 -. -. -. -. Incident Three - single Note + 0 -. -. -. -. Incident Four - Start, no stop + 1 0.000,02 -. 0.000,02 0.000,02 Incident Five - Single Start/Stop + 0 -. -. -. -. Incident Six - zero occurrences + 100 0.000,25 0.000,12 0.000,02 0.000,62 Incident Seven - Random + 100 0.000,79 0.000,48 0.000,02 0.001,92 Incident Eight - Also random + 5895 0.000,01 0.000,01 0.000,01 0.000,56 Incident Nine - Another note + 10 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Note + 50 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Start + 50 0.000,04 0.000,03 0.000,03 0.000,31 Msr_Stop + + WHAT IT MEANS: + The log shows what happened and when. Each line shows the time at which + something happened (see WHAT YOU CODE below) what it was that happened + and (if approporate) the time since the corresponding previous event + (that's the delta column). + + The statistics show how many times each event occurred, what the average + delta time was, also the standard deviation, largest and smalles delta. + + WHAT YOU CODE: + + Before anything else executes: - register your ids + + int id1 = Msr_Register("Incident One - Note"); + int id2 = Msr_Register("Incident Two - Start/Stop"); + int id3 = Msr_Register("Incident Three - single Note"); + etc. + + At interesting moments: + + // To measure a repetitive event - e.g. end of bitblt to screen + Msr_Note(Id9); // e.g. "video frame hiting the screen NOW!" + + or + + // To measure an elapsed time e.g. time taken to decode an MPEG B-frame + Msr_Start(Id2); // e.g. "Starting to decode MPEG B-frame" + . . . + MsrStop(Id2); // "Finished MPEG decode" + + At the end: + + HANDLE hFile; + hFile = CreateFile("Perf.log", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + Msr_Dump(hFile); // This writes the log out to the file + CloseHandle(hFile); + + or + + Msr_Dump(NULL); // This writes it to DbgLog((LOG_TRACE,0, ... )); + // but if you are writing it out to the debugger + // then the times are probably all garbage because + // the debugger can make things run awfully slow. + + A given id should be used either for start / stop or Note calls. If Notes + are mixed in with Starts and Stops their statistics will be gibberish. + + If you code the calls in upper case i.e. MSR_START(idMunge); then you get + macros which will turn into nothing unless PERF is defined. + + You can reset the statistical counts for a given id by calling Reset(Id). + They are reset by default at the start. + It logs Reset as a special incident, so you can see it in the log. + + The log is a circular buffer in storage (to try to minimise disk I/O). + It overwrites the oldest entries once full. The statistics include ALL + incidents since the last Reset, whether still visible in the log or not. +*/ + +#ifndef __MEASURE__ +#define __MEASURE__ + +#ifdef PERF +#define MSR_INIT() Msr_Init() +#define MSR_TERMINATE() Msr_Terminate() +#define MSR_REGISTER(a) Msr_Register(a) +#define MSR_RESET(a) Msr_Reset(a) +#define MSR_CONTROL(a) Msr_Control(a) +#define MSR_START(a) Msr_Start(a) +#define MSR_STOP(a) Msr_Stop(a) +#define MSR_NOTE(a) Msr_Note(a) +#define MSR_INTEGER(a,b) Msr_Integer(a,b) +#define MSR_DUMP(a) Msr_Dump(a) +#define MSR_DUMPSTATS(a) Msr_DumpStats(a) +#else +#define MSR_INIT() ((void)0) +#define MSR_TERMINATE() ((void)0) +#define MSR_REGISTER(a) 0 +#define MSR_RESET(a) ((void)0) +#define MSR_CONTROL(a) ((void)0) +#define MSR_START(a) ((void)0) +#define MSR_STOP(a) ((void)0) +#define MSR_NOTE(a) ((void)0) +#define MSR_INTEGER(a,b) ((void)0) +#define MSR_DUMP(a) ((void)0) +#define MSR_DUMPSTATS(a) ((void)0) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// This must be called first - (called by the DllEntry) + +void WINAPI Msr_Init(void); + + +// Call this last to clean up (or just let it fall off the end - who cares?) + +void WINAPI Msr_Terminate(void); + + +// Call this to get an Id for an "incident" that you can pass to Start, Stop or Note +// everything that's logged is called an "incident". + +int WINAPI Msr_Register(LPTSTR Incident); + + +// Reset the statistical counts for an incident + +void WINAPI Msr_Reset(int Id); + + +// Reset all the counts for all incidents +#define MSR_RESET_ALL 0 +#define MSR_PAUSE 1 +#define MSR_RUN 2 + +void WINAPI Msr_Control(int iAction); + + +// log the start of an operation + +void WINAPI Msr_Start(int Id); + + +// log the end of an operation + +void WINAPI Msr_Stop(int Id); + + +// log a one-off or repetitive operation + +void WINAPI Msr_Note(int Id); + + +// log an integer (on which we can see statistics later) +void WINAPI Msr_Integer(int Id, int n); + + +// print out all the vaialable log (it may have wrapped) and then the statistics. +// When the log wraps you lose log but the statistics are still complete. +// hFIle==NULL => use DbgLog +// otherwise hFile must have come from CreateFile or OpenFile. + +void WINAPI Msr_Dump(HANDLE hFile); + + +// just dump the statistics - never mind the log + +void WINAPI Msr_DumpStats(HANDLE hFile); + +// Type definitions in case you want to declare a pointer to the dump functions +// (makes it a trifle easier to do dynamic linking +// i.e. LoadModule, GetProcAddress and call that) + +// Typedefs so can declare MSR_DUMPPROC *MsrDumpStats; or whatever +typedef void WINAPI MSR_DUMPPROC(HANDLE hFile); +typedef void WINAPI MSR_CONTROLPROC(int iAction); + + +#ifdef __cplusplus +} +#endif + +#endif // __MEASURE__ diff --git a/plugins/GSdx/baseclasses/msgthrd.h b/plugins/GSdx/baseclasses/msgthrd.h index f07d5162ad..eb09be2430 100644 --- a/plugins/GSdx/baseclasses/msgthrd.h +++ b/plugins/GSdx/baseclasses/msgthrd.h @@ -1,120 +1,120 @@ -//------------------------------------------------------------------------------ -// File: MsgThrd.h -// -// Desc: DirectShow base classes - provides support for a worker thread -// class to which one can asynchronously post messages. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// Message class - really just a structure. -// -class CMsg { -public: - UINT uMsg; - DWORD dwFlags; - LPVOID lpParam; - CAMEvent *pEvent; - - CMsg(UINT u, DWORD dw, LPVOID lp, CAMEvent *pEvnt) - : uMsg(u), dwFlags(dw), lpParam(lp), pEvent(pEvnt) {} - - CMsg() - : uMsg(0), dwFlags(0L), lpParam(NULL), pEvent(NULL) {} -}; - -// This is the actual thread class. It exports all the usual thread control -// functions. The created thread is different from a normal WIN32 thread in -// that it is prompted to perform particaular tasks by responding to messages -// posted to its message queue. -// -class AM_NOVTABLE CMsgThread { -private: - static DWORD WINAPI DefaultThreadProc(LPVOID lpParam); - DWORD m_ThreadId; - HANDLE m_hThread; - -protected: - - // if you want to override GetThreadMsg to block on other things - // as well as this queue, you need access to this - CGenericList m_ThreadQueue; - CCritSec m_Lock; - HANDLE m_hSem; - LONG m_lWaiting; - -public: - CMsgThread() - : m_ThreadId(0), - m_hThread(NULL), - m_lWaiting(0), - m_hSem(NULL), - // make a list with a cache of 5 items - m_ThreadQueue(NAME("MsgThread list"), 5) - { - } - - ~CMsgThread(); - // override this if you want to block on other things as well - // as the message loop - void virtual GetThreadMsg(CMsg *msg); - - // override this if you want to do something on thread startup - virtual void OnThreadInit() { - }; - - BOOL CreateThread(); - - BOOL WaitForThreadExit(LPDWORD lpdwExitCode) { - if (m_hThread != NULL) { - WaitForSingleObject(m_hThread, INFINITE); - return GetExitCodeThread(m_hThread, lpdwExitCode); - } - return FALSE; - } - - DWORD ResumeThread() { - return ::ResumeThread(m_hThread); - } - - DWORD SuspendThread() { - return ::SuspendThread(m_hThread); - } - - int GetThreadPriority() { - return ::GetThreadPriority(m_hThread); - } - - BOOL SetThreadPriority(int nPriority) { - return ::SetThreadPriority(m_hThread, nPriority); - } - - HANDLE GetThreadHandle() { - return m_hThread; - } - - DWORD GetThreadId() { - return m_ThreadId; - } - - - void PutThreadMsg(UINT uMsg, DWORD dwMsgFlags, - LPVOID lpMsgParam, CAMEvent *pEvent = NULL) { - CAutoLock lck(&m_Lock); - CMsg* pMsg = new CMsg(uMsg, dwMsgFlags, lpMsgParam, pEvent); - m_ThreadQueue.AddTail(pMsg); - if (m_lWaiting != 0) { - ReleaseSemaphore(m_hSem, m_lWaiting, 0); - m_lWaiting = 0; - } - } - - // This is the function prototype of the function that the client - // supplies. It is always called on the created thread, never on - // the creator thread. - // - virtual LRESULT ThreadMessageProc( - UINT uMsg, DWORD dwFlags, LPVOID lpParam, CAMEvent *pEvent) = 0; -}; - +//------------------------------------------------------------------------------ +// File: MsgThrd.h +// +// Desc: DirectShow base classes - provides support for a worker thread +// class to which one can asynchronously post messages. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Message class - really just a structure. +// +class CMsg { +public: + UINT uMsg; + DWORD dwFlags; + LPVOID lpParam; + CAMEvent *pEvent; + + CMsg(UINT u, DWORD dw, LPVOID lp, CAMEvent *pEvnt) + : uMsg(u), dwFlags(dw), lpParam(lp), pEvent(pEvnt) {} + + CMsg() + : uMsg(0), dwFlags(0L), lpParam(NULL), pEvent(NULL) {} +}; + +// This is the actual thread class. It exports all the usual thread control +// functions. The created thread is different from a normal WIN32 thread in +// that it is prompted to perform particaular tasks by responding to messages +// posted to its message queue. +// +class AM_NOVTABLE CMsgThread { +private: + static DWORD WINAPI DefaultThreadProc(LPVOID lpParam); + DWORD m_ThreadId; + HANDLE m_hThread; + +protected: + + // if you want to override GetThreadMsg to block on other things + // as well as this queue, you need access to this + CGenericList m_ThreadQueue; + CCritSec m_Lock; + HANDLE m_hSem; + LONG m_lWaiting; + +public: + CMsgThread() + : m_ThreadId(0), + m_hThread(NULL), + m_lWaiting(0), + m_hSem(NULL), + // make a list with a cache of 5 items + m_ThreadQueue(NAME("MsgThread list"), 5) + { + } + + ~CMsgThread(); + // override this if you want to block on other things as well + // as the message loop + void virtual GetThreadMsg(CMsg *msg); + + // override this if you want to do something on thread startup + virtual void OnThreadInit() { + }; + + BOOL CreateThread(); + + BOOL WaitForThreadExit(LPDWORD lpdwExitCode) { + if (m_hThread != NULL) { + WaitForSingleObject(m_hThread, INFINITE); + return GetExitCodeThread(m_hThread, lpdwExitCode); + } + return FALSE; + } + + DWORD ResumeThread() { + return ::ResumeThread(m_hThread); + } + + DWORD SuspendThread() { + return ::SuspendThread(m_hThread); + } + + int GetThreadPriority() { + return ::GetThreadPriority(m_hThread); + } + + BOOL SetThreadPriority(int nPriority) { + return ::SetThreadPriority(m_hThread, nPriority); + } + + HANDLE GetThreadHandle() { + return m_hThread; + } + + DWORD GetThreadId() { + return m_ThreadId; + } + + + void PutThreadMsg(UINT uMsg, DWORD dwMsgFlags, + LPVOID lpMsgParam, CAMEvent *pEvent = NULL) { + CAutoLock lck(&m_Lock); + CMsg* pMsg = new CMsg(uMsg, dwMsgFlags, lpMsgParam, pEvent); + m_ThreadQueue.AddTail(pMsg); + if (m_lWaiting != 0) { + ReleaseSemaphore(m_hSem, m_lWaiting, 0); + m_lWaiting = 0; + } + } + + // This is the function prototype of the function that the client + // supplies. It is always called on the created thread, never on + // the creator thread. + // + virtual LRESULT ThreadMessageProc( + UINT uMsg, DWORD dwFlags, LPVOID lpParam, CAMEvent *pEvent) = 0; +}; + diff --git a/plugins/GSdx/baseclasses/mtype.cpp b/plugins/GSdx/baseclasses/mtype.cpp index d56c15a5da..5d49a6dd84 100644 --- a/plugins/GSdx/baseclasses/mtype.cpp +++ b/plugins/GSdx/baseclasses/mtype.cpp @@ -1,477 +1,477 @@ -//------------------------------------------------------------------------------ -// File: MType.cpp -// -// Desc: DirectShow base classes - implements a class that holds and -// manages media type information. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// helper class that derived pin objects can use to compare media -// types etc. Has same data members as the struct AM_MEDIA_TYPE defined -// in the streams IDL file, but also has (non-virtual) functions - -#include "streams.h" -#include - -CMediaType::~CMediaType(){ - FreeMediaType(*this); -} - - -CMediaType::CMediaType() -{ - InitMediaType(); -} - - -CMediaType::CMediaType(const GUID * type) -{ - InitMediaType(); - majortype = *type; -} - - -// copy constructor does a deep copy of the format block - -CMediaType::CMediaType(const AM_MEDIA_TYPE& rt, HRESULT* phr) -{ - HRESULT hr = CopyMediaType(this, &rt); - if (FAILED(hr) && (NULL != phr)) { - *phr = hr; - } -} - - -CMediaType::CMediaType(const CMediaType& rt, HRESULT* phr) -{ - HRESULT hr = CopyMediaType(this, &rt); - if (FAILED(hr) && (NULL != phr)) { - *phr = hr; - } -} - - -// this class inherits publicly from AM_MEDIA_TYPE so the compiler could generate -// the following assignment operator itself, however it could introduce some -// memory conflicts and leaks in the process because the structure contains -// a dynamically allocated block (pbFormat) which it will not copy correctly - -CMediaType& -CMediaType::operator=(const AM_MEDIA_TYPE& rt) -{ - Set(rt); - return *this; -} - -CMediaType& -CMediaType::operator=(const CMediaType& rt) -{ - *this = (AM_MEDIA_TYPE &) rt; - return *this; -} - -BOOL -CMediaType::operator == (const CMediaType& rt) const -{ - // I don't believe we need to check sample size or - // temporal compression flags, since I think these must - // be represented in the type, subtype and format somehow. They - // are pulled out as separate flags so that people who don't understand - // the particular format representation can still see them, but - // they should duplicate information in the format block. - - return ((IsEqualGUID(majortype,rt.majortype) == TRUE) && - (IsEqualGUID(subtype,rt.subtype) == TRUE) && - (IsEqualGUID(formattype,rt.formattype) == TRUE) && - (cbFormat == rt.cbFormat) && - ( (cbFormat == 0) || - (memcmp(pbFormat, rt.pbFormat, cbFormat) == 0))); -} - - -BOOL -CMediaType::operator != (const CMediaType& rt) const -{ - /* Check to see if they are equal */ - - if (*this == rt) { - return FALSE; - } - return TRUE; -} - - -HRESULT -CMediaType::Set(const CMediaType& rt) -{ - return Set((AM_MEDIA_TYPE &) rt); -} - - -HRESULT -CMediaType::Set(const AM_MEDIA_TYPE& rt) -{ - if (&rt != this) { - FreeMediaType(*this); - HRESULT hr = CopyMediaType(this, &rt); - if (FAILED(hr)) { - return E_OUTOFMEMORY; - } - } - - return S_OK; -} - - -BOOL -CMediaType::IsValid() const -{ - return (!IsEqualGUID(majortype,GUID_NULL)); -} - - -void -CMediaType::SetType(const GUID* ptype) -{ - majortype = *ptype; -} - - -void -CMediaType::SetSubtype(const GUID* ptype) -{ - subtype = *ptype; -} - - -ULONG -CMediaType::GetSampleSize() const { - if (IsFixedSize()) { - return lSampleSize; - } else { - return 0; - } -} - - -void -CMediaType::SetSampleSize(ULONG sz) { - if (sz == 0) { - SetVariableSize(); - } else { - bFixedSizeSamples = TRUE; - lSampleSize = sz; - } -} - - -void -CMediaType::SetVariableSize() { - bFixedSizeSamples = FALSE; -} - - -void -CMediaType::SetTemporalCompression(BOOL bCompressed) { - bTemporalCompression = bCompressed; -} - -BOOL -CMediaType::SetFormat(BYTE * pformat, ULONG cb) -{ - if (NULL == AllocFormatBuffer(cb)) - return(FALSE); - - ASSERT(pbFormat); - memcpy(pbFormat, pformat, cb); - return(TRUE); -} - - -// set the type of the media type format block, this type defines what you -// will actually find in the format pointer. For example FORMAT_VideoInfo or -// FORMAT_WaveFormatEx. In the future this may be an interface pointer to a -// property set. Before sending out media types this should be filled in. - -void -CMediaType::SetFormatType(const GUID *pformattype) -{ - formattype = *pformattype; -} - - -// reset the format buffer - -void CMediaType::ResetFormatBuffer() -{ - if (cbFormat) { - CoTaskMemFree((PVOID)pbFormat); - } - cbFormat = 0; - pbFormat = NULL; -} - - -// allocate length bytes for the format and return a read/write pointer -// If we cannot allocate the new block of memory we return NULL leaving -// the original block of memory untouched (as does ReallocFormatBuffer) - -BYTE* -CMediaType::AllocFormatBuffer(ULONG length) -{ - ASSERT(length); - - // do the types have the same buffer size - - if (cbFormat == length) { - return pbFormat; - } - - // allocate the new format buffer - - BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length); - if (pNewFormat == NULL) { - if (length <= cbFormat) return pbFormat; //reuse the old block anyway. - return NULL; - } - - // delete the old format - - if (cbFormat != 0) { - ASSERT(pbFormat); - CoTaskMemFree((PVOID)pbFormat); - } - - cbFormat = length; - pbFormat = pNewFormat; - return pbFormat; -} - - -// reallocate length bytes for the format and return a read/write pointer -// to it. We keep as much information as we can given the new buffer size -// if this fails the original format buffer is left untouched. The caller -// is responsible for ensuring the size of memory required is non zero - -BYTE* -CMediaType::ReallocFormatBuffer(ULONG length) -{ - ASSERT(length); - - // do the types have the same buffer size - - if (cbFormat == length) { - return pbFormat; - } - - // allocate the new format buffer - - BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length); - if (pNewFormat == NULL) { - if (length <= cbFormat) return pbFormat; //reuse the old block anyway. - return NULL; - } - - // copy any previous format (or part of if new is smaller) - // delete the old format and replace with the new one - - if (cbFormat != 0) { - ASSERT(pbFormat); - memcpy(pNewFormat,pbFormat,min(length,cbFormat)); - CoTaskMemFree((PVOID)pbFormat); - } - - cbFormat = length; - pbFormat = pNewFormat; - return pNewFormat; -} - -// initialise a media type structure - -void CMediaType::InitMediaType() -{ - ZeroMemory((PVOID)this, sizeof(*this)); - lSampleSize = 1; - bFixedSizeSamples = TRUE; -} - - -// a partially specified media type can be passed to IPin::Connect -// as a constraint on the media type used in the connection. -// the type, subtype or format type can be null. -BOOL -CMediaType::IsPartiallySpecified(void) const -{ - if ((majortype == GUID_NULL) || - (formattype == GUID_NULL)) { - return TRUE; - } else { - return FALSE; - } -} - -BOOL -CMediaType::MatchesPartial(const CMediaType* ppartial) const -{ - if ((ppartial->majortype != GUID_NULL) && - (majortype != ppartial->majortype)) { - return FALSE; - } - if ((ppartial->subtype != GUID_NULL) && - (subtype != ppartial->subtype)) { - return FALSE; - } - - if (ppartial->formattype != GUID_NULL) { - // if the format block is specified then it must match exactly - if (formattype != ppartial->formattype) { - return FALSE; - } - if (cbFormat != ppartial->cbFormat) { - return FALSE; - } - if ((cbFormat != 0) && - (memcmp(pbFormat, ppartial->pbFormat, cbFormat) != 0)) { - return FALSE; - } - } - - return TRUE; - -} - - - -// general purpose function to delete a heap allocated AM_MEDIA_TYPE structure -// which is useful when calling IEnumMediaTypes::Next as the interface -// implementation allocates the structures which you must later delete -// the format block may also be a pointer to an interface to release - -void WINAPI DeleteMediaType(AM_MEDIA_TYPE *pmt) -{ - // allow NULL pointers for coding simplicity - - if (pmt == NULL) { - return; - } - - FreeMediaType(*pmt); - CoTaskMemFree((PVOID)pmt); -} - - -// this also comes in useful when using the IEnumMediaTypes interface so -// that you can copy a media type, you can do nearly the same by creating -// a CMediaType object but as soon as it goes out of scope the destructor -// will delete the memory it allocated (this takes a copy of the memory) - -AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc) -{ - ASSERT(pSrc); - - // Allocate a block of memory for the media type - - AM_MEDIA_TYPE *pMediaType = - (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); - - if (pMediaType == NULL) { - return NULL; - } - // Copy the variable length format block - - HRESULT hr = CopyMediaType(pMediaType,pSrc); - if (FAILED(hr)) { - CoTaskMemFree((PVOID)pMediaType); - return NULL; - } - - return pMediaType; -} - - -// Copy 1 media type to another - -HRESULT WINAPI CopyMediaType(AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource) -{ - // We'll leak if we copy onto one that already exists - there's one - // case we can check like that - copying to itself. - ASSERT(pmtSource != pmtTarget); - *pmtTarget = *pmtSource; - if (pmtSource->cbFormat != 0) { - ASSERT(pmtSource->pbFormat != NULL); - pmtTarget->pbFormat = (PBYTE)CoTaskMemAlloc(pmtSource->cbFormat); - if (pmtTarget->pbFormat == NULL) { - pmtTarget->cbFormat = 0; - return E_OUTOFMEMORY; - } else { - CopyMemory((PVOID)pmtTarget->pbFormat, (PVOID)pmtSource->pbFormat, - pmtTarget->cbFormat); - } - } - if (pmtTarget->pUnk != NULL) { - pmtTarget->pUnk->AddRef(); - } - - return S_OK; -} - -// Free an existing media type (ie free resources it holds) - -void WINAPI FreeMediaType(AM_MEDIA_TYPE& mt) -{ - if (mt.cbFormat != 0) { - CoTaskMemFree((PVOID)mt.pbFormat); - - // Strictly unnecessary but tidier - mt.cbFormat = 0; - mt.pbFormat = NULL; - } - if (mt.pUnk != NULL) { - mt.pUnk->Release(); - mt.pUnk = NULL; - } -} - -// Initialize a media type from a WAVEFORMATEX - -STDAPI CreateAudioMediaType( - const WAVEFORMATEX *pwfx, - AM_MEDIA_TYPE *pmt, - BOOL bSetFormat -) -{ - pmt->majortype = MEDIATYPE_Audio; - if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { - pmt->subtype = ((PWAVEFORMATEXTENSIBLE)pwfx)->SubFormat; - } else { - pmt->subtype = FOURCCMap(pwfx->wFormatTag); - } - pmt->formattype = FORMAT_WaveFormatEx; - pmt->bFixedSizeSamples = TRUE; - pmt->bTemporalCompression = FALSE; - pmt->lSampleSize = pwfx->nBlockAlign; - pmt->pUnk = NULL; - if (bSetFormat) { - if (pwfx->wFormatTag == WAVE_FORMAT_PCM) { - pmt->cbFormat = sizeof(WAVEFORMATEX); - } else { - pmt->cbFormat = sizeof(WAVEFORMATEX) + pwfx->cbSize; - } - pmt->pbFormat = (PBYTE)CoTaskMemAlloc(pmt->cbFormat); - if (pmt->pbFormat == NULL) { - return E_OUTOFMEMORY; - } - if (pwfx->wFormatTag == WAVE_FORMAT_PCM) { - CopyMemory(pmt->pbFormat, pwfx, sizeof(PCMWAVEFORMAT)); - ((WAVEFORMATEX *)pmt->pbFormat)->cbSize = 0; - } else { - CopyMemory(pmt->pbFormat, pwfx, pmt->cbFormat); - } - } - return S_OK; -} - -// eliminate very many spurious warnings from MS compiler -#pragma warning(disable:4514) +//------------------------------------------------------------------------------ +// File: MType.cpp +// +// Desc: DirectShow base classes - implements a class that holds and +// manages media type information. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// helper class that derived pin objects can use to compare media +// types etc. Has same data members as the struct AM_MEDIA_TYPE defined +// in the streams IDL file, but also has (non-virtual) functions + +#include "streams.h" +#include + +CMediaType::~CMediaType(){ + FreeMediaType(*this); +} + + +CMediaType::CMediaType() +{ + InitMediaType(); +} + + +CMediaType::CMediaType(const GUID * type) +{ + InitMediaType(); + majortype = *type; +} + + +// copy constructor does a deep copy of the format block + +CMediaType::CMediaType(const AM_MEDIA_TYPE& rt, HRESULT* phr) +{ + HRESULT hr = CopyMediaType(this, &rt); + if (FAILED(hr) && (NULL != phr)) { + *phr = hr; + } +} + + +CMediaType::CMediaType(const CMediaType& rt, HRESULT* phr) +{ + HRESULT hr = CopyMediaType(this, &rt); + if (FAILED(hr) && (NULL != phr)) { + *phr = hr; + } +} + + +// this class inherits publicly from AM_MEDIA_TYPE so the compiler could generate +// the following assignment operator itself, however it could introduce some +// memory conflicts and leaks in the process because the structure contains +// a dynamically allocated block (pbFormat) which it will not copy correctly + +CMediaType& +CMediaType::operator=(const AM_MEDIA_TYPE& rt) +{ + Set(rt); + return *this; +} + +CMediaType& +CMediaType::operator=(const CMediaType& rt) +{ + *this = (AM_MEDIA_TYPE &) rt; + return *this; +} + +BOOL +CMediaType::operator == (const CMediaType& rt) const +{ + // I don't believe we need to check sample size or + // temporal compression flags, since I think these must + // be represented in the type, subtype and format somehow. They + // are pulled out as separate flags so that people who don't understand + // the particular format representation can still see them, but + // they should duplicate information in the format block. + + return ((IsEqualGUID(majortype,rt.majortype) == TRUE) && + (IsEqualGUID(subtype,rt.subtype) == TRUE) && + (IsEqualGUID(formattype,rt.formattype) == TRUE) && + (cbFormat == rt.cbFormat) && + ( (cbFormat == 0) || + (memcmp(pbFormat, rt.pbFormat, cbFormat) == 0))); +} + + +BOOL +CMediaType::operator != (const CMediaType& rt) const +{ + /* Check to see if they are equal */ + + if (*this == rt) { + return FALSE; + } + return TRUE; +} + + +HRESULT +CMediaType::Set(const CMediaType& rt) +{ + return Set((AM_MEDIA_TYPE &) rt); +} + + +HRESULT +CMediaType::Set(const AM_MEDIA_TYPE& rt) +{ + if (&rt != this) { + FreeMediaType(*this); + HRESULT hr = CopyMediaType(this, &rt); + if (FAILED(hr)) { + return E_OUTOFMEMORY; + } + } + + return S_OK; +} + + +BOOL +CMediaType::IsValid() const +{ + return (!IsEqualGUID(majortype,GUID_NULL)); +} + + +void +CMediaType::SetType(const GUID* ptype) +{ + majortype = *ptype; +} + + +void +CMediaType::SetSubtype(const GUID* ptype) +{ + subtype = *ptype; +} + + +ULONG +CMediaType::GetSampleSize() const { + if (IsFixedSize()) { + return lSampleSize; + } else { + return 0; + } +} + + +void +CMediaType::SetSampleSize(ULONG sz) { + if (sz == 0) { + SetVariableSize(); + } else { + bFixedSizeSamples = TRUE; + lSampleSize = sz; + } +} + + +void +CMediaType::SetVariableSize() { + bFixedSizeSamples = FALSE; +} + + +void +CMediaType::SetTemporalCompression(BOOL bCompressed) { + bTemporalCompression = bCompressed; +} + +BOOL +CMediaType::SetFormat(BYTE * pformat, ULONG cb) +{ + if (NULL == AllocFormatBuffer(cb)) + return(FALSE); + + ASSERT(pbFormat); + memcpy(pbFormat, pformat, cb); + return(TRUE); +} + + +// set the type of the media type format block, this type defines what you +// will actually find in the format pointer. For example FORMAT_VideoInfo or +// FORMAT_WaveFormatEx. In the future this may be an interface pointer to a +// property set. Before sending out media types this should be filled in. + +void +CMediaType::SetFormatType(const GUID *pformattype) +{ + formattype = *pformattype; +} + + +// reset the format buffer + +void CMediaType::ResetFormatBuffer() +{ + if (cbFormat) { + CoTaskMemFree((PVOID)pbFormat); + } + cbFormat = 0; + pbFormat = NULL; +} + + +// allocate length bytes for the format and return a read/write pointer +// If we cannot allocate the new block of memory we return NULL leaving +// the original block of memory untouched (as does ReallocFormatBuffer) + +BYTE* +CMediaType::AllocFormatBuffer(ULONG length) +{ + ASSERT(length); + + // do the types have the same buffer size + + if (cbFormat == length) { + return pbFormat; + } + + // allocate the new format buffer + + BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length); + if (pNewFormat == NULL) { + if (length <= cbFormat) return pbFormat; //reuse the old block anyway. + return NULL; + } + + // delete the old format + + if (cbFormat != 0) { + ASSERT(pbFormat); + CoTaskMemFree((PVOID)pbFormat); + } + + cbFormat = length; + pbFormat = pNewFormat; + return pbFormat; +} + + +// reallocate length bytes for the format and return a read/write pointer +// to it. We keep as much information as we can given the new buffer size +// if this fails the original format buffer is left untouched. The caller +// is responsible for ensuring the size of memory required is non zero + +BYTE* +CMediaType::ReallocFormatBuffer(ULONG length) +{ + ASSERT(length); + + // do the types have the same buffer size + + if (cbFormat == length) { + return pbFormat; + } + + // allocate the new format buffer + + BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length); + if (pNewFormat == NULL) { + if (length <= cbFormat) return pbFormat; //reuse the old block anyway. + return NULL; + } + + // copy any previous format (or part of if new is smaller) + // delete the old format and replace with the new one + + if (cbFormat != 0) { + ASSERT(pbFormat); + memcpy(pNewFormat,pbFormat,min(length,cbFormat)); + CoTaskMemFree((PVOID)pbFormat); + } + + cbFormat = length; + pbFormat = pNewFormat; + return pNewFormat; +} + +// initialise a media type structure + +void CMediaType::InitMediaType() +{ + ZeroMemory((PVOID)this, sizeof(*this)); + lSampleSize = 1; + bFixedSizeSamples = TRUE; +} + + +// a partially specified media type can be passed to IPin::Connect +// as a constraint on the media type used in the connection. +// the type, subtype or format type can be null. +BOOL +CMediaType::IsPartiallySpecified(void) const +{ + if ((majortype == GUID_NULL) || + (formattype == GUID_NULL)) { + return TRUE; + } else { + return FALSE; + } +} + +BOOL +CMediaType::MatchesPartial(const CMediaType* ppartial) const +{ + if ((ppartial->majortype != GUID_NULL) && + (majortype != ppartial->majortype)) { + return FALSE; + } + if ((ppartial->subtype != GUID_NULL) && + (subtype != ppartial->subtype)) { + return FALSE; + } + + if (ppartial->formattype != GUID_NULL) { + // if the format block is specified then it must match exactly + if (formattype != ppartial->formattype) { + return FALSE; + } + if (cbFormat != ppartial->cbFormat) { + return FALSE; + } + if ((cbFormat != 0) && + (memcmp(pbFormat, ppartial->pbFormat, cbFormat) != 0)) { + return FALSE; + } + } + + return TRUE; + +} + + + +// general purpose function to delete a heap allocated AM_MEDIA_TYPE structure +// which is useful when calling IEnumMediaTypes::Next as the interface +// implementation allocates the structures which you must later delete +// the format block may also be a pointer to an interface to release + +void WINAPI DeleteMediaType(AM_MEDIA_TYPE *pmt) +{ + // allow NULL pointers for coding simplicity + + if (pmt == NULL) { + return; + } + + FreeMediaType(*pmt); + CoTaskMemFree((PVOID)pmt); +} + + +// this also comes in useful when using the IEnumMediaTypes interface so +// that you can copy a media type, you can do nearly the same by creating +// a CMediaType object but as soon as it goes out of scope the destructor +// will delete the memory it allocated (this takes a copy of the memory) + +AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc) +{ + ASSERT(pSrc); + + // Allocate a block of memory for the media type + + AM_MEDIA_TYPE *pMediaType = + (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); + + if (pMediaType == NULL) { + return NULL; + } + // Copy the variable length format block + + HRESULT hr = CopyMediaType(pMediaType,pSrc); + if (FAILED(hr)) { + CoTaskMemFree((PVOID)pMediaType); + return NULL; + } + + return pMediaType; +} + + +// Copy 1 media type to another + +HRESULT WINAPI CopyMediaType(AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource) +{ + // We'll leak if we copy onto one that already exists - there's one + // case we can check like that - copying to itself. + ASSERT(pmtSource != pmtTarget); + *pmtTarget = *pmtSource; + if (pmtSource->cbFormat != 0) { + ASSERT(pmtSource->pbFormat != NULL); + pmtTarget->pbFormat = (PBYTE)CoTaskMemAlloc(pmtSource->cbFormat); + if (pmtTarget->pbFormat == NULL) { + pmtTarget->cbFormat = 0; + return E_OUTOFMEMORY; + } else { + CopyMemory((PVOID)pmtTarget->pbFormat, (PVOID)pmtSource->pbFormat, + pmtTarget->cbFormat); + } + } + if (pmtTarget->pUnk != NULL) { + pmtTarget->pUnk->AddRef(); + } + + return S_OK; +} + +// Free an existing media type (ie free resources it holds) + +void WINAPI FreeMediaType(AM_MEDIA_TYPE& mt) +{ + if (mt.cbFormat != 0) { + CoTaskMemFree((PVOID)mt.pbFormat); + + // Strictly unnecessary but tidier + mt.cbFormat = 0; + mt.pbFormat = NULL; + } + if (mt.pUnk != NULL) { + mt.pUnk->Release(); + mt.pUnk = NULL; + } +} + +// Initialize a media type from a WAVEFORMATEX + +STDAPI CreateAudioMediaType( + const WAVEFORMATEX *pwfx, + AM_MEDIA_TYPE *pmt, + BOOL bSetFormat +) +{ + pmt->majortype = MEDIATYPE_Audio; + if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { + pmt->subtype = ((PWAVEFORMATEXTENSIBLE)pwfx)->SubFormat; + } else { + pmt->subtype = FOURCCMap(pwfx->wFormatTag); + } + pmt->formattype = FORMAT_WaveFormatEx; + pmt->bFixedSizeSamples = TRUE; + pmt->bTemporalCompression = FALSE; + pmt->lSampleSize = pwfx->nBlockAlign; + pmt->pUnk = NULL; + if (bSetFormat) { + if (pwfx->wFormatTag == WAVE_FORMAT_PCM) { + pmt->cbFormat = sizeof(WAVEFORMATEX); + } else { + pmt->cbFormat = sizeof(WAVEFORMATEX) + pwfx->cbSize; + } + pmt->pbFormat = (PBYTE)CoTaskMemAlloc(pmt->cbFormat); + if (pmt->pbFormat == NULL) { + return E_OUTOFMEMORY; + } + if (pwfx->wFormatTag == WAVE_FORMAT_PCM) { + CopyMemory(pmt->pbFormat, pwfx, sizeof(PCMWAVEFORMAT)); + ((WAVEFORMATEX *)pmt->pbFormat)->cbSize = 0; + } else { + CopyMemory(pmt->pbFormat, pwfx, pmt->cbFormat); + } + } + return S_OK; +} + +// eliminate very many spurious warnings from MS compiler +#pragma warning(disable:4514) diff --git a/plugins/GSdx/baseclasses/mtype.h b/plugins/GSdx/baseclasses/mtype.h index 7a8a2395b3..41d5829829 100644 --- a/plugins/GSdx/baseclasses/mtype.h +++ b/plugins/GSdx/baseclasses/mtype.h @@ -1,89 +1,89 @@ -//------------------------------------------------------------------------------ -// File: MtType.h -// -// Desc: DirectShow base classes - defines a class that holds and manages -// media type information. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __MTYPE__ -#define __MTYPE__ - -/* Helper class that derived pin objects can use to compare media - types etc. Has same data members as the struct AM_MEDIA_TYPE defined - in the streams IDL file, but also has (non-virtual) functions */ - -class CMediaType : public _AMMediaType { - -public: - - ~CMediaType(); - CMediaType(); - CMediaType(const GUID * majortype); - CMediaType(const AM_MEDIA_TYPE&, HRESULT* phr = NULL); - CMediaType(const CMediaType&, HRESULT* phr = NULL); - - CMediaType& operator=(const CMediaType&); - CMediaType& operator=(const AM_MEDIA_TYPE&); - - BOOL operator == (const CMediaType&) const; - BOOL operator != (const CMediaType&) const; - - HRESULT Set(const CMediaType& rt); - HRESULT Set(const AM_MEDIA_TYPE& rt); - - BOOL IsValid() const; - - const GUID *Type() const { return &majortype;} ; - void SetType(const GUID *); - const GUID *Subtype() const { return &subtype;} ; - void SetSubtype(const GUID *); - - BOOL IsFixedSize() const {return bFixedSizeSamples; }; - BOOL IsTemporalCompressed() const {return bTemporalCompression; }; - ULONG GetSampleSize() const; - - void SetSampleSize(ULONG sz); - void SetVariableSize(); - void SetTemporalCompression(BOOL bCompressed); - - // read/write pointer to format - can't change length without - // calling SetFormat, AllocFormatBuffer or ReallocFormatBuffer - - BYTE* Format() const {return pbFormat; }; - ULONG FormatLength() const { return cbFormat; }; - - void SetFormatType(const GUID *); - const GUID *FormatType() const {return &formattype; }; - BOOL SetFormat(BYTE *pFormat, ULONG length); - void ResetFormatBuffer(); - BYTE* AllocFormatBuffer(ULONG length); - BYTE* ReallocFormatBuffer(ULONG length); - - void InitMediaType(); - - BOOL MatchesPartial(const CMediaType* ppartial) const; - BOOL IsPartiallySpecified(void) const; -}; - - -/* General purpose functions to copy and delete a task allocated AM_MEDIA_TYPE - structure which is useful when using the IEnumMediaFormats interface as - the implementation allocates the structures which you must later delete */ - -void WINAPI DeleteMediaType(AM_MEDIA_TYPE *pmt); -AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc); -HRESULT WINAPI CopyMediaType(AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource); -void WINAPI FreeMediaType(AM_MEDIA_TYPE& mt); - -// Initialize a media type from a WAVEFORMATEX - -STDAPI CreateAudioMediaType( - const WAVEFORMATEX *pwfx, - AM_MEDIA_TYPE *pmt, - BOOL bSetFormat); - -#endif /* __MTYPE__ */ - +//------------------------------------------------------------------------------ +// File: MtType.h +// +// Desc: DirectShow base classes - defines a class that holds and manages +// media type information. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __MTYPE__ +#define __MTYPE__ + +/* Helper class that derived pin objects can use to compare media + types etc. Has same data members as the struct AM_MEDIA_TYPE defined + in the streams IDL file, but also has (non-virtual) functions */ + +class CMediaType : public _AMMediaType { + +public: + + ~CMediaType(); + CMediaType(); + CMediaType(const GUID * majortype); + CMediaType(const AM_MEDIA_TYPE&, HRESULT* phr = NULL); + CMediaType(const CMediaType&, HRESULT* phr = NULL); + + CMediaType& operator=(const CMediaType&); + CMediaType& operator=(const AM_MEDIA_TYPE&); + + BOOL operator == (const CMediaType&) const; + BOOL operator != (const CMediaType&) const; + + HRESULT Set(const CMediaType& rt); + HRESULT Set(const AM_MEDIA_TYPE& rt); + + BOOL IsValid() const; + + const GUID *Type() const { return &majortype;} ; + void SetType(const GUID *); + const GUID *Subtype() const { return &subtype;} ; + void SetSubtype(const GUID *); + + BOOL IsFixedSize() const {return bFixedSizeSamples; }; + BOOL IsTemporalCompressed() const {return bTemporalCompression; }; + ULONG GetSampleSize() const; + + void SetSampleSize(ULONG sz); + void SetVariableSize(); + void SetTemporalCompression(BOOL bCompressed); + + // read/write pointer to format - can't change length without + // calling SetFormat, AllocFormatBuffer or ReallocFormatBuffer + + BYTE* Format() const {return pbFormat; }; + ULONG FormatLength() const { return cbFormat; }; + + void SetFormatType(const GUID *); + const GUID *FormatType() const {return &formattype; }; + BOOL SetFormat(BYTE *pFormat, ULONG length); + void ResetFormatBuffer(); + BYTE* AllocFormatBuffer(ULONG length); + BYTE* ReallocFormatBuffer(ULONG length); + + void InitMediaType(); + + BOOL MatchesPartial(const CMediaType* ppartial) const; + BOOL IsPartiallySpecified(void) const; +}; + + +/* General purpose functions to copy and delete a task allocated AM_MEDIA_TYPE + structure which is useful when using the IEnumMediaFormats interface as + the implementation allocates the structures which you must later delete */ + +void WINAPI DeleteMediaType(AM_MEDIA_TYPE *pmt); +AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc); +HRESULT WINAPI CopyMediaType(AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource); +void WINAPI FreeMediaType(AM_MEDIA_TYPE& mt); + +// Initialize a media type from a WAVEFORMATEX + +STDAPI CreateAudioMediaType( + const WAVEFORMATEX *pwfx, + AM_MEDIA_TYPE *pmt, + BOOL bSetFormat); + +#endif /* __MTYPE__ */ + diff --git a/plugins/GSdx/baseclasses/outputq.cpp b/plugins/GSdx/baseclasses/outputq.cpp index da96a10765..a034cdb40f 100644 --- a/plugins/GSdx/baseclasses/outputq.cpp +++ b/plugins/GSdx/baseclasses/outputq.cpp @@ -1,794 +1,794 @@ -//------------------------------------------------------------------------------ -// File: OutputQ.cpp -// -// Desc: DirectShow base classes - implements COutputQueue class used by an -// output pin which may sometimes want to queue output samples on a -// separate thread and sometimes call Receive() directly on the input -// pin. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" - - -// -// COutputQueue Constructor : -// -// Determines if a thread is to be created and creates resources -// -// pInputPin - the downstream input pin we're queueing samples to -// -// phr - changed to a failure code if this function fails -// (otherwise unchanges) -// -// bAuto - Ask pInputPin if it can block in Receive by calling -// its ReceiveCanBlock method and create a thread if -// it can block, otherwise not. -// -// bQueue - if bAuto == FALSE then we create a thread if and only -// if bQueue == TRUE -// -// lBatchSize - work in batches of lBatchSize -// -// bBatchEact - Use exact batch sizes so don't send until the -// batch is full or SendAnyway() is called -// -// lListSize - If we create a thread make the list of samples queued -// to the thread have this size cache -// -// dwPriority - If we create a thread set its priority to this -// -COutputQueue::COutputQueue( - IPin *pInputPin, // Pin to send stuff to - HRESULT *phr, // 'Return code' - BOOL bAuto, // Ask pin if queue or not - BOOL bQueue, // Send through queue - LONG lBatchSize, // Batch - BOOL bBatchExact, // Batch exactly to BatchSize - LONG lListSize, - DWORD dwPriority, - bool bFlushingOpt // flushing optimization - ) : m_lBatchSize(lBatchSize), - m_bBatchExact(bBatchExact && (lBatchSize > 1)), - m_hThread(NULL), - m_hSem(NULL), - m_List(NULL), - m_pPin(pInputPin), - m_ppSamples(NULL), - m_lWaiting(0), - m_pInputPin(NULL), - m_bSendAnyway(FALSE), - m_nBatched(0), - m_bFlushing(FALSE), - m_bFlushed(TRUE), - m_bFlushingOpt(bFlushingOpt), - m_bTerminate(FALSE), - m_hEventPop(NULL), - m_hr(S_OK) -{ - ASSERT(m_lBatchSize > 0); - - - if (FAILED(*phr)) { - return; - } - - // Check the input pin is OK and cache its IMemInputPin interface - - *phr = pInputPin->QueryInterface(IID_IMemInputPin, (void **)&m_pInputPin); - if (FAILED(*phr)) { - return; - } - - // See if we should ask the downstream pin - - if (bAuto) { - HRESULT hr = m_pInputPin->ReceiveCanBlock(); - if (SUCCEEDED(hr)) { - bQueue = hr == S_OK; - } - } - - // Create our sample batch - - m_ppSamples = new PMEDIASAMPLE[m_lBatchSize]; - if (m_ppSamples == NULL) { - *phr = E_OUTOFMEMORY; - return; - } - - // If we're queueing allocate resources - - if (bQueue) { - DbgLog((LOG_TRACE, 2, TEXT("Creating thread for output pin"))); - m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); - if (m_hSem == NULL) { - DWORD dwError = GetLastError(); - *phr = AmHresultFromWin32(dwError); - return; - } - m_List = new CSampleList(NAME("Sample Queue List"), - lListSize, - FALSE // No lock - ); - if (m_List == NULL) { - *phr = E_OUTOFMEMORY; - return; - } - - - DWORD dwThreadId; - m_hThread = CreateThread(NULL, - 0, - InitialThreadProc, - (LPVOID)this, - 0, - &dwThreadId); - if (m_hThread == NULL) { - DWORD dwError = GetLastError(); - *phr = AmHresultFromWin32(dwError); - return; - } - SetThreadPriority(m_hThread, dwPriority); - } else { - DbgLog((LOG_TRACE, 2, TEXT("Calling input pin directly - no thread"))); - } -} - -// -// COutputQueuee Destructor : -// -// Free all resources - -// -// Thread, -// Batched samples -// -COutputQueue::~COutputQueue() -{ - DbgLog((LOG_TRACE, 3, TEXT("COutputQueue::~COutputQueue"))); - /* Free our pointer */ - if (m_pInputPin != NULL) { - m_pInputPin->Release(); - } - if (m_hThread != NULL) { - { - CAutoLock lck(this); - m_bTerminate = TRUE; - m_hr = S_FALSE; - NotifyThread(); - } - DbgWaitForSingleObject(m_hThread); - EXECUTE_ASSERT(CloseHandle(m_hThread)); - - // The thread frees the samples when asked to terminate - - ASSERT(m_List->GetCount() == 0); - delete m_List; - } else { - FreeSamples(); - } - if (m_hSem != NULL) { - EXECUTE_ASSERT(CloseHandle(m_hSem)); - } - delete [] m_ppSamples; -} - -// -// Call the real thread proc as a member function -// -DWORD WINAPI COutputQueue::InitialThreadProc(LPVOID pv) -{ - HRESULT hrCoInit = CAMThread::CoInitializeHelper(); - - COutputQueue *pSampleQueue = (COutputQueue *)pv; - DWORD dwReturn = pSampleQueue->ThreadProc(); - - if(hrCoInit == S_OK) { - CoUninitialize(); - } - - return dwReturn; -} - -// -// Thread sending the samples downstream : -// -// When there is nothing to do the thread sets m_lWaiting (while -// holding the critical section) and then waits for m_hSem to be -// set (not holding the critical section) -// -DWORD COutputQueue::ThreadProc() -{ - while (TRUE) { - BOOL bWait = FALSE; - IMediaSample *pSample; - LONG lNumberToSend; // Local copy - NewSegmentPacket* ppacket; - - // - // Get a batch of samples and send it if possible - // In any case exit the loop if there is a control action - // requested - // - { - CAutoLock lck(this); - while (TRUE) { - - if (m_bTerminate) { - FreeSamples(); - return 0; - } - if (m_bFlushing) { - FreeSamples(); - SetEvent(m_evFlushComplete); - } - - // Get a sample off the list - - pSample = m_List->RemoveHead(); - // inform derived class we took something off the queue - if (m_hEventPop) { - //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); - SetEvent(m_hEventPop); - } - - if (pSample != NULL && - !IsSpecialSample(pSample)) { - - // If its just a regular sample just add it to the batch - // and exit the loop if the batch is full - - m_ppSamples[m_nBatched++] = pSample; - if (m_nBatched == m_lBatchSize) { - break; - } - } else { - - // If there was nothing in the queue and there's nothing - // to send (either because there's nothing or the batch - // isn't full) then prepare to wait - - if (pSample == NULL && - (m_bBatchExact || m_nBatched == 0)) { - - // Tell other thread to set the event when there's - // something do to - - ASSERT(m_lWaiting == 0); - m_lWaiting++; - bWait = TRUE; - } else { - - // We break out of the loop on SEND_PACKET unless - // there's nothing to send - - if (pSample == SEND_PACKET && m_nBatched == 0) { - continue; - } - - if (pSample == NEW_SEGMENT) { - // now we need the parameters - we are - // guaranteed that the next packet contains them - ppacket = (NewSegmentPacket *) m_List->RemoveHead(); - // we took something off the queue - if (m_hEventPop) { - //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); - SetEvent(m_hEventPop); - } - - ASSERT(ppacket); - } - // EOS_PACKET falls through here and we exit the loop - // In this way it acts like SEND_PACKET - } - break; - } - } - if (!bWait) { - // We look at m_nBatched from the client side so keep - // it up to date inside the critical section - lNumberToSend = m_nBatched; // Local copy - m_nBatched = 0; - } - } - - // Wait for some more data - - if (bWait) { - DbgWaitForSingleObject(m_hSem); - continue; - } - - - - // OK - send it if there's anything to send - // We DON'T check m_bBatchExact here because either we've got - // a full batch or we dropped through because we got - // SEND_PACKET or EOS_PACKET - both of which imply we should - // flush our batch - - if (lNumberToSend != 0) { - long nProcessed; - if (m_hr == S_OK) { - ASSERT(!m_bFlushed); - HRESULT hr = m_pInputPin->ReceiveMultiple(m_ppSamples, - lNumberToSend, - &nProcessed); - /* Don't overwrite a flushing state HRESULT */ - CAutoLock lck(this); - if (m_hr == S_OK) { - m_hr = hr; - } - ASSERT(!m_bFlushed); - } - while (lNumberToSend != 0) { - m_ppSamples[--lNumberToSend]->Release(); - } - if (m_hr != S_OK) { - - // In any case wait for more data - S_OK just - // means there wasn't an error - - DbgLog((LOG_ERROR, 2, TEXT("ReceiveMultiple returned %8.8X"), - m_hr)); - } - } - - // Check for end of stream - - if (pSample == EOS_PACKET) { - - // We don't send even end of stream on if we've previously - // returned something other than S_OK - // This is because in that case the pin which returned - // something other than S_OK should have either sent - // EndOfStream() or notified the filter graph - - if (m_hr == S_OK) { - DbgLog((LOG_TRACE, 2, TEXT("COutputQueue sending EndOfStream()"))); - HRESULT hr = m_pPin->EndOfStream(); - if (FAILED(hr)) { - DbgLog((LOG_ERROR, 2, TEXT("COutputQueue got code 0x%8.8X from EndOfStream()"))); - } - } - } - - // Data from a new source - - if (pSample == RESET_PACKET) { - m_hr = S_OK; - SetEvent(m_evFlushComplete); - } - - if (pSample == NEW_SEGMENT) { - m_pPin->NewSegment(ppacket->tStart, ppacket->tStop, ppacket->dRate); - delete ppacket; - } - } -} - -// Send batched stuff anyway -void COutputQueue::SendAnyway() -{ - if (!IsQueued()) { - - // m_bSendAnyway is a private parameter checked in ReceiveMultiple - - m_bSendAnyway = TRUE; - LONG nProcessed; - ReceiveMultiple(NULL, 0, &nProcessed); - m_bSendAnyway = FALSE; - - } else { - CAutoLock lck(this); - QueueSample(SEND_PACKET); - NotifyThread(); - } -} - -void -COutputQueue::NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate) -{ - if (!IsQueued()) { - if (S_OK == m_hr) { - if (m_bBatchExact) { - SendAnyway(); - } - m_pPin->NewSegment(tStart, tStop, dRate); - } - } else { - if (m_hr == S_OK) { - // - // we need to queue the new segment to appear in order in the - // data, but we need to pass parameters to it. Rather than - // take the hit of wrapping every single sample so we can tell - // special ones apart, we queue special pointers to indicate - // special packets, and we guarantee (by holding the - // critical section) that the packet immediately following a - // NEW_SEGMENT value is a NewSegmentPacket containing the - // parameters. - NewSegmentPacket * ppack = new NewSegmentPacket; - if (ppack == NULL) { - return; - } - ppack->tStart = tStart; - ppack->tStop = tStop; - ppack->dRate = dRate; - - CAutoLock lck(this); - QueueSample(NEW_SEGMENT); - QueueSample( (IMediaSample*) ppack); - NotifyThread(); - } - } -} - - -// -// End of Stream is queued to output device -// -void COutputQueue::EOS() -{ - CAutoLock lck(this); - if (!IsQueued()) { - if (m_bBatchExact) { - SendAnyway(); - } - if (m_hr == S_OK) { - DbgLog((LOG_TRACE, 2, TEXT("COutputQueue sending EndOfStream()"))); - m_bFlushed = FALSE; - HRESULT hr = m_pPin->EndOfStream(); - if (FAILED(hr)) { - DbgLog((LOG_ERROR, 2, TEXT("COutputQueue got code 0x%8.8X from EndOfStream()"))); - } - } - } else { - if (m_hr == S_OK) { - m_bFlushed = FALSE; - QueueSample(EOS_PACKET); - NotifyThread(); - } - } -} - -// -// Flush all the samples in the queue -// -void COutputQueue::BeginFlush() -{ - if (IsQueued()) { - { - CAutoLock lck(this); - - // block receives -- we assume this is done by the - // filter in which we are a component - - // discard all queued data - - m_bFlushing = TRUE; - - // Make sure we discard all samples from now on - - if (m_hr == S_OK) { - m_hr = S_FALSE; - } - - // Optimize so we don't keep calling downstream all the time - - if (m_bFlushed && m_bFlushingOpt) { - return; - } - - // Make sure we really wait for the flush to complete - m_evFlushComplete.Reset(); - - NotifyThread(); - } - - // pass this downstream - - m_pPin->BeginFlush(); - } else { - // pass downstream first to avoid deadlocks - m_pPin->BeginFlush(); - CAutoLock lck(this); - // discard all queued data - - m_bFlushing = TRUE; - - // Make sure we discard all samples from now on - - if (m_hr == S_OK) { - m_hr = S_FALSE; - } - } - -} - -// -// leave flush mode - pass this downstream -void COutputQueue::EndFlush() -{ - { - CAutoLock lck(this); - ASSERT(m_bFlushing); - if (m_bFlushingOpt && m_bFlushed && IsQueued()) { - m_bFlushing = FALSE; - m_hr = S_OK; - return; - } - } - - // sync with pushing thread -- done in BeginFlush - // ensure no more data to go downstream -- done in BeginFlush - // - // Because we are synching here there is no need to hold the critical - // section (in fact we'd deadlock if we did!) - - if (IsQueued()) { - m_evFlushComplete.Wait(); - } else { - FreeSamples(); - } - - // Be daring - the caller has guaranteed no samples will arrive - // before EndFlush() returns - - m_bFlushing = FALSE; - m_bFlushed = TRUE; - - // call EndFlush on downstream pins - - m_pPin->EndFlush(); - - m_hr = S_OK; -} - -// COutputQueue::QueueSample -// -// private method to Send a sample to the output queue -// The critical section MUST be held when this is called - -void COutputQueue::QueueSample(IMediaSample *pSample) -{ - if (NULL == m_List->AddTail(pSample)) { - if (!IsSpecialSample(pSample)) { - pSample->Release(); - } - } -} - -// -// COutputQueue::Receive() -// -// Send a single sample by the multiple sample route -// (NOTE - this could be optimized if necessary) -// -// On return the sample will have been Release()'d -// - -HRESULT COutputQueue::Receive(IMediaSample *pSample) -{ - LONG nProcessed; - return ReceiveMultiple(&pSample, 1, &nProcessed); -} - -// -// COutputQueue::ReceiveMultiple() -// -// Send a set of samples to the downstream pin -// -// ppSamples - array of samples -// nSamples - how many -// nSamplesProcessed - How many were processed -// -// On return all samples will have been Release()'d -// - -HRESULT COutputQueue::ReceiveMultiple ( - IMediaSample **ppSamples, - long nSamples, - long *nSamplesProcessed) -{ - CAutoLock lck(this); - // Either call directly or queue up the samples - - if (!IsQueued()) { - - // If we already had a bad return code then just return - - if (S_OK != m_hr) { - - // If we've never received anything since the last Flush() - // and the sticky return code is not S_OK we must be - // flushing - // ((!A || B) is equivalent to A implies B) - ASSERT(!m_bFlushed || m_bFlushing); - - // We're supposed to Release() them anyway! - *nSamplesProcessed = 0; - for (int i = 0; i < nSamples; i++) { - DbgLog((LOG_TRACE, 3, TEXT("COutputQueue (direct) : Discarding %d samples code 0x%8.8X"), - nSamples, m_hr)); - ppSamples[i]->Release(); - } - - return m_hr; - } - // - // If we're flushing the sticky return code should be S_FALSE - // - ASSERT(!m_bFlushing); - m_bFlushed = FALSE; - - ASSERT(m_nBatched < m_lBatchSize); - ASSERT(m_nBatched == 0 || m_bBatchExact); - - // Loop processing the samples in batches - - LONG iLost = 0; - long iDone; - for (iDone = 0; - iDone < nSamples || (m_nBatched != 0 && m_bSendAnyway); - ) { - -//pragma message (REMIND("Implement threshold scheme")) - ASSERT(m_nBatched < m_lBatchSize); - if (iDone < nSamples) { - m_ppSamples[m_nBatched++] = ppSamples[iDone++]; - } - if (m_nBatched == m_lBatchSize || - nSamples == 0 && (m_bSendAnyway || !m_bBatchExact)) { - LONG nDone; - DbgLog((LOG_TRACE, 4, TEXT("Batching %d samples"), - m_nBatched)); - - if (m_hr == S_OK) { - m_hr = m_pInputPin->ReceiveMultiple(m_ppSamples, - m_nBatched, - &nDone); - } else { - nDone = 0; - } - iLost += m_nBatched - nDone; - for (LONG i = 0; i < m_nBatched; i++) { - m_ppSamples[i]->Release(); - } - m_nBatched = 0; - } - } - *nSamplesProcessed = iDone - iLost; - if (*nSamplesProcessed < 0) { - *nSamplesProcessed = 0; - } - return m_hr; - } else { - /* We're sending to our thread */ - - if (m_hr != S_OK) { - *nSamplesProcessed = 0; - DbgLog((LOG_TRACE, 3, TEXT("COutputQueue (queued) : Discarding %d samples code 0x%8.8X"), - nSamples, m_hr)); - for (int i = 0; i < nSamples; i++) { - ppSamples[i]->Release(); - } - return m_hr; - } - m_bFlushed = FALSE; - for (long i = 0; i < nSamples; i++) { - QueueSample(ppSamples[i]); - } - *nSamplesProcessed = nSamples; - if (!m_bBatchExact || - m_nBatched + m_List->GetCount() >= m_lBatchSize) { - NotifyThread(); - } - return S_OK; - } -} - -// Get ready for new data - cancels sticky m_hr -void COutputQueue::Reset() -{ - if (!IsQueued()) { - m_hr = S_OK; - } else { - CAutoLock lck(this); - QueueSample(RESET_PACKET); - NotifyThread(); - m_evFlushComplete.Wait(); - } -} - -// Remove and Release() all queued and Batched samples -void COutputQueue::FreeSamples() -{ - CAutoLock lck(this); - if (IsQueued()) { - while (TRUE) { - IMediaSample *pSample = m_List->RemoveHead(); - // inform derived class we took something off the queue - if (m_hEventPop) { - //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); - SetEvent(m_hEventPop); - } - - if (pSample == NULL) { - break; - } - if (!IsSpecialSample(pSample)) { - pSample->Release(); - } else { - if (pSample == NEW_SEGMENT) { - // Free NEW_SEGMENT packet - NewSegmentPacket *ppacket = - (NewSegmentPacket *) m_List->RemoveHead(); - // inform derived class we took something off the queue - if (m_hEventPop) { - //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); - SetEvent(m_hEventPop); - } - - ASSERT(ppacket != NULL); - delete ppacket; - } - } - } - } - for (int i = 0; i < m_nBatched; i++) { - m_ppSamples[i]->Release(); - } - m_nBatched = 0; -} - -// Notify the thread if there is something to do -// -// The critical section MUST be held when this is called -void COutputQueue::NotifyThread() -{ - // Optimize - no need to signal if it's not waiting - ASSERT(IsQueued()); - if (m_lWaiting) { - ReleaseSemaphore(m_hSem, m_lWaiting, NULL); - m_lWaiting = 0; - } -} - -// See if there's any work to do -// Returns -// TRUE if there is nothing on the queue and nothing in the batch -// and all data has been sent -// FALSE otherwise -// -BOOL COutputQueue::IsIdle() -{ - CAutoLock lck(this); - - // We're idle if - // there is no thread (!IsQueued()) OR - // the thread is waiting for more work (m_lWaiting != 0) - // AND - // there's nothing in the current batch (m_nBatched == 0) - - if (IsQueued() && m_lWaiting == 0 || m_nBatched != 0) { - return FALSE; - } else { - - // If we're idle it shouldn't be possible for there - // to be anything on the work queue - - ASSERT(!IsQueued() || m_List->GetCount() == 0); - return TRUE; - } -} - - -void COutputQueue::SetPopEvent(HANDLE hEvent) -{ - m_hEventPop = hEvent; -} +//------------------------------------------------------------------------------ +// File: OutputQ.cpp +// +// Desc: DirectShow base classes - implements COutputQueue class used by an +// output pin which may sometimes want to queue output samples on a +// separate thread and sometimes call Receive() directly on the input +// pin. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" + + +// +// COutputQueue Constructor : +// +// Determines if a thread is to be created and creates resources +// +// pInputPin - the downstream input pin we're queueing samples to +// +// phr - changed to a failure code if this function fails +// (otherwise unchanges) +// +// bAuto - Ask pInputPin if it can block in Receive by calling +// its ReceiveCanBlock method and create a thread if +// it can block, otherwise not. +// +// bQueue - if bAuto == FALSE then we create a thread if and only +// if bQueue == TRUE +// +// lBatchSize - work in batches of lBatchSize +// +// bBatchEact - Use exact batch sizes so don't send until the +// batch is full or SendAnyway() is called +// +// lListSize - If we create a thread make the list of samples queued +// to the thread have this size cache +// +// dwPriority - If we create a thread set its priority to this +// +COutputQueue::COutputQueue( + IPin *pInputPin, // Pin to send stuff to + HRESULT *phr, // 'Return code' + BOOL bAuto, // Ask pin if queue or not + BOOL bQueue, // Send through queue + LONG lBatchSize, // Batch + BOOL bBatchExact, // Batch exactly to BatchSize + LONG lListSize, + DWORD dwPriority, + bool bFlushingOpt // flushing optimization + ) : m_lBatchSize(lBatchSize), + m_bBatchExact(bBatchExact && (lBatchSize > 1)), + m_hThread(NULL), + m_hSem(NULL), + m_List(NULL), + m_pPin(pInputPin), + m_ppSamples(NULL), + m_lWaiting(0), + m_pInputPin(NULL), + m_bSendAnyway(FALSE), + m_nBatched(0), + m_bFlushing(FALSE), + m_bFlushed(TRUE), + m_bFlushingOpt(bFlushingOpt), + m_bTerminate(FALSE), + m_hEventPop(NULL), + m_hr(S_OK) +{ + ASSERT(m_lBatchSize > 0); + + + if (FAILED(*phr)) { + return; + } + + // Check the input pin is OK and cache its IMemInputPin interface + + *phr = pInputPin->QueryInterface(IID_IMemInputPin, (void **)&m_pInputPin); + if (FAILED(*phr)) { + return; + } + + // See if we should ask the downstream pin + + if (bAuto) { + HRESULT hr = m_pInputPin->ReceiveCanBlock(); + if (SUCCEEDED(hr)) { + bQueue = hr == S_OK; + } + } + + // Create our sample batch + + m_ppSamples = new PMEDIASAMPLE[m_lBatchSize]; + if (m_ppSamples == NULL) { + *phr = E_OUTOFMEMORY; + return; + } + + // If we're queueing allocate resources + + if (bQueue) { + DbgLog((LOG_TRACE, 2, TEXT("Creating thread for output pin"))); + m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); + if (m_hSem == NULL) { + DWORD dwError = GetLastError(); + *phr = AmHresultFromWin32(dwError); + return; + } + m_List = new CSampleList(NAME("Sample Queue List"), + lListSize, + FALSE // No lock + ); + if (m_List == NULL) { + *phr = E_OUTOFMEMORY; + return; + } + + + DWORD dwThreadId; + m_hThread = CreateThread(NULL, + 0, + InitialThreadProc, + (LPVOID)this, + 0, + &dwThreadId); + if (m_hThread == NULL) { + DWORD dwError = GetLastError(); + *phr = AmHresultFromWin32(dwError); + return; + } + SetThreadPriority(m_hThread, dwPriority); + } else { + DbgLog((LOG_TRACE, 2, TEXT("Calling input pin directly - no thread"))); + } +} + +// +// COutputQueuee Destructor : +// +// Free all resources - +// +// Thread, +// Batched samples +// +COutputQueue::~COutputQueue() +{ + DbgLog((LOG_TRACE, 3, TEXT("COutputQueue::~COutputQueue"))); + /* Free our pointer */ + if (m_pInputPin != NULL) { + m_pInputPin->Release(); + } + if (m_hThread != NULL) { + { + CAutoLock lck(this); + m_bTerminate = TRUE; + m_hr = S_FALSE; + NotifyThread(); + } + DbgWaitForSingleObject(m_hThread); + EXECUTE_ASSERT(CloseHandle(m_hThread)); + + // The thread frees the samples when asked to terminate + + ASSERT(m_List->GetCount() == 0); + delete m_List; + } else { + FreeSamples(); + } + if (m_hSem != NULL) { + EXECUTE_ASSERT(CloseHandle(m_hSem)); + } + delete [] m_ppSamples; +} + +// +// Call the real thread proc as a member function +// +DWORD WINAPI COutputQueue::InitialThreadProc(LPVOID pv) +{ + HRESULT hrCoInit = CAMThread::CoInitializeHelper(); + + COutputQueue *pSampleQueue = (COutputQueue *)pv; + DWORD dwReturn = pSampleQueue->ThreadProc(); + + if(hrCoInit == S_OK) { + CoUninitialize(); + } + + return dwReturn; +} + +// +// Thread sending the samples downstream : +// +// When there is nothing to do the thread sets m_lWaiting (while +// holding the critical section) and then waits for m_hSem to be +// set (not holding the critical section) +// +DWORD COutputQueue::ThreadProc() +{ + while (TRUE) { + BOOL bWait = FALSE; + IMediaSample *pSample; + LONG lNumberToSend; // Local copy + NewSegmentPacket* ppacket; + + // + // Get a batch of samples and send it if possible + // In any case exit the loop if there is a control action + // requested + // + { + CAutoLock lck(this); + while (TRUE) { + + if (m_bTerminate) { + FreeSamples(); + return 0; + } + if (m_bFlushing) { + FreeSamples(); + SetEvent(m_evFlushComplete); + } + + // Get a sample off the list + + pSample = m_List->RemoveHead(); + // inform derived class we took something off the queue + if (m_hEventPop) { + //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); + SetEvent(m_hEventPop); + } + + if (pSample != NULL && + !IsSpecialSample(pSample)) { + + // If its just a regular sample just add it to the batch + // and exit the loop if the batch is full + + m_ppSamples[m_nBatched++] = pSample; + if (m_nBatched == m_lBatchSize) { + break; + } + } else { + + // If there was nothing in the queue and there's nothing + // to send (either because there's nothing or the batch + // isn't full) then prepare to wait + + if (pSample == NULL && + (m_bBatchExact || m_nBatched == 0)) { + + // Tell other thread to set the event when there's + // something do to + + ASSERT(m_lWaiting == 0); + m_lWaiting++; + bWait = TRUE; + } else { + + // We break out of the loop on SEND_PACKET unless + // there's nothing to send + + if (pSample == SEND_PACKET && m_nBatched == 0) { + continue; + } + + if (pSample == NEW_SEGMENT) { + // now we need the parameters - we are + // guaranteed that the next packet contains them + ppacket = (NewSegmentPacket *) m_List->RemoveHead(); + // we took something off the queue + if (m_hEventPop) { + //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); + SetEvent(m_hEventPop); + } + + ASSERT(ppacket); + } + // EOS_PACKET falls through here and we exit the loop + // In this way it acts like SEND_PACKET + } + break; + } + } + if (!bWait) { + // We look at m_nBatched from the client side so keep + // it up to date inside the critical section + lNumberToSend = m_nBatched; // Local copy + m_nBatched = 0; + } + } + + // Wait for some more data + + if (bWait) { + DbgWaitForSingleObject(m_hSem); + continue; + } + + + + // OK - send it if there's anything to send + // We DON'T check m_bBatchExact here because either we've got + // a full batch or we dropped through because we got + // SEND_PACKET or EOS_PACKET - both of which imply we should + // flush our batch + + if (lNumberToSend != 0) { + long nProcessed; + if (m_hr == S_OK) { + ASSERT(!m_bFlushed); + HRESULT hr = m_pInputPin->ReceiveMultiple(m_ppSamples, + lNumberToSend, + &nProcessed); + /* Don't overwrite a flushing state HRESULT */ + CAutoLock lck(this); + if (m_hr == S_OK) { + m_hr = hr; + } + ASSERT(!m_bFlushed); + } + while (lNumberToSend != 0) { + m_ppSamples[--lNumberToSend]->Release(); + } + if (m_hr != S_OK) { + + // In any case wait for more data - S_OK just + // means there wasn't an error + + DbgLog((LOG_ERROR, 2, TEXT("ReceiveMultiple returned %8.8X"), + m_hr)); + } + } + + // Check for end of stream + + if (pSample == EOS_PACKET) { + + // We don't send even end of stream on if we've previously + // returned something other than S_OK + // This is because in that case the pin which returned + // something other than S_OK should have either sent + // EndOfStream() or notified the filter graph + + if (m_hr == S_OK) { + DbgLog((LOG_TRACE, 2, TEXT("COutputQueue sending EndOfStream()"))); + HRESULT hr = m_pPin->EndOfStream(); + if (FAILED(hr)) { + DbgLog((LOG_ERROR, 2, TEXT("COutputQueue got code 0x%8.8X from EndOfStream()"))); + } + } + } + + // Data from a new source + + if (pSample == RESET_PACKET) { + m_hr = S_OK; + SetEvent(m_evFlushComplete); + } + + if (pSample == NEW_SEGMENT) { + m_pPin->NewSegment(ppacket->tStart, ppacket->tStop, ppacket->dRate); + delete ppacket; + } + } +} + +// Send batched stuff anyway +void COutputQueue::SendAnyway() +{ + if (!IsQueued()) { + + // m_bSendAnyway is a private parameter checked in ReceiveMultiple + + m_bSendAnyway = TRUE; + LONG nProcessed; + ReceiveMultiple(NULL, 0, &nProcessed); + m_bSendAnyway = FALSE; + + } else { + CAutoLock lck(this); + QueueSample(SEND_PACKET); + NotifyThread(); + } +} + +void +COutputQueue::NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + if (!IsQueued()) { + if (S_OK == m_hr) { + if (m_bBatchExact) { + SendAnyway(); + } + m_pPin->NewSegment(tStart, tStop, dRate); + } + } else { + if (m_hr == S_OK) { + // + // we need to queue the new segment to appear in order in the + // data, but we need to pass parameters to it. Rather than + // take the hit of wrapping every single sample so we can tell + // special ones apart, we queue special pointers to indicate + // special packets, and we guarantee (by holding the + // critical section) that the packet immediately following a + // NEW_SEGMENT value is a NewSegmentPacket containing the + // parameters. + NewSegmentPacket * ppack = new NewSegmentPacket; + if (ppack == NULL) { + return; + } + ppack->tStart = tStart; + ppack->tStop = tStop; + ppack->dRate = dRate; + + CAutoLock lck(this); + QueueSample(NEW_SEGMENT); + QueueSample( (IMediaSample*) ppack); + NotifyThread(); + } + } +} + + +// +// End of Stream is queued to output device +// +void COutputQueue::EOS() +{ + CAutoLock lck(this); + if (!IsQueued()) { + if (m_bBatchExact) { + SendAnyway(); + } + if (m_hr == S_OK) { + DbgLog((LOG_TRACE, 2, TEXT("COutputQueue sending EndOfStream()"))); + m_bFlushed = FALSE; + HRESULT hr = m_pPin->EndOfStream(); + if (FAILED(hr)) { + DbgLog((LOG_ERROR, 2, TEXT("COutputQueue got code 0x%8.8X from EndOfStream()"))); + } + } + } else { + if (m_hr == S_OK) { + m_bFlushed = FALSE; + QueueSample(EOS_PACKET); + NotifyThread(); + } + } +} + +// +// Flush all the samples in the queue +// +void COutputQueue::BeginFlush() +{ + if (IsQueued()) { + { + CAutoLock lck(this); + + // block receives -- we assume this is done by the + // filter in which we are a component + + // discard all queued data + + m_bFlushing = TRUE; + + // Make sure we discard all samples from now on + + if (m_hr == S_OK) { + m_hr = S_FALSE; + } + + // Optimize so we don't keep calling downstream all the time + + if (m_bFlushed && m_bFlushingOpt) { + return; + } + + // Make sure we really wait for the flush to complete + m_evFlushComplete.Reset(); + + NotifyThread(); + } + + // pass this downstream + + m_pPin->BeginFlush(); + } else { + // pass downstream first to avoid deadlocks + m_pPin->BeginFlush(); + CAutoLock lck(this); + // discard all queued data + + m_bFlushing = TRUE; + + // Make sure we discard all samples from now on + + if (m_hr == S_OK) { + m_hr = S_FALSE; + } + } + +} + +// +// leave flush mode - pass this downstream +void COutputQueue::EndFlush() +{ + { + CAutoLock lck(this); + ASSERT(m_bFlushing); + if (m_bFlushingOpt && m_bFlushed && IsQueued()) { + m_bFlushing = FALSE; + m_hr = S_OK; + return; + } + } + + // sync with pushing thread -- done in BeginFlush + // ensure no more data to go downstream -- done in BeginFlush + // + // Because we are synching here there is no need to hold the critical + // section (in fact we'd deadlock if we did!) + + if (IsQueued()) { + m_evFlushComplete.Wait(); + } else { + FreeSamples(); + } + + // Be daring - the caller has guaranteed no samples will arrive + // before EndFlush() returns + + m_bFlushing = FALSE; + m_bFlushed = TRUE; + + // call EndFlush on downstream pins + + m_pPin->EndFlush(); + + m_hr = S_OK; +} + +// COutputQueue::QueueSample +// +// private method to Send a sample to the output queue +// The critical section MUST be held when this is called + +void COutputQueue::QueueSample(IMediaSample *pSample) +{ + if (NULL == m_List->AddTail(pSample)) { + if (!IsSpecialSample(pSample)) { + pSample->Release(); + } + } +} + +// +// COutputQueue::Receive() +// +// Send a single sample by the multiple sample route +// (NOTE - this could be optimized if necessary) +// +// On return the sample will have been Release()'d +// + +HRESULT COutputQueue::Receive(IMediaSample *pSample) +{ + LONG nProcessed; + return ReceiveMultiple(&pSample, 1, &nProcessed); +} + +// +// COutputQueue::ReceiveMultiple() +// +// Send a set of samples to the downstream pin +// +// ppSamples - array of samples +// nSamples - how many +// nSamplesProcessed - How many were processed +// +// On return all samples will have been Release()'d +// + +HRESULT COutputQueue::ReceiveMultiple ( + IMediaSample **ppSamples, + long nSamples, + long *nSamplesProcessed) +{ + CAutoLock lck(this); + // Either call directly or queue up the samples + + if (!IsQueued()) { + + // If we already had a bad return code then just return + + if (S_OK != m_hr) { + + // If we've never received anything since the last Flush() + // and the sticky return code is not S_OK we must be + // flushing + // ((!A || B) is equivalent to A implies B) + ASSERT(!m_bFlushed || m_bFlushing); + + // We're supposed to Release() them anyway! + *nSamplesProcessed = 0; + for (int i = 0; i < nSamples; i++) { + DbgLog((LOG_TRACE, 3, TEXT("COutputQueue (direct) : Discarding %d samples code 0x%8.8X"), + nSamples, m_hr)); + ppSamples[i]->Release(); + } + + return m_hr; + } + // + // If we're flushing the sticky return code should be S_FALSE + // + ASSERT(!m_bFlushing); + m_bFlushed = FALSE; + + ASSERT(m_nBatched < m_lBatchSize); + ASSERT(m_nBatched == 0 || m_bBatchExact); + + // Loop processing the samples in batches + + LONG iLost = 0; + long iDone; + for (iDone = 0; + iDone < nSamples || (m_nBatched != 0 && m_bSendAnyway); + ) { + +//pragma message (REMIND("Implement threshold scheme")) + ASSERT(m_nBatched < m_lBatchSize); + if (iDone < nSamples) { + m_ppSamples[m_nBatched++] = ppSamples[iDone++]; + } + if (m_nBatched == m_lBatchSize || + nSamples == 0 && (m_bSendAnyway || !m_bBatchExact)) { + LONG nDone; + DbgLog((LOG_TRACE, 4, TEXT("Batching %d samples"), + m_nBatched)); + + if (m_hr == S_OK) { + m_hr = m_pInputPin->ReceiveMultiple(m_ppSamples, + m_nBatched, + &nDone); + } else { + nDone = 0; + } + iLost += m_nBatched - nDone; + for (LONG i = 0; i < m_nBatched; i++) { + m_ppSamples[i]->Release(); + } + m_nBatched = 0; + } + } + *nSamplesProcessed = iDone - iLost; + if (*nSamplesProcessed < 0) { + *nSamplesProcessed = 0; + } + return m_hr; + } else { + /* We're sending to our thread */ + + if (m_hr != S_OK) { + *nSamplesProcessed = 0; + DbgLog((LOG_TRACE, 3, TEXT("COutputQueue (queued) : Discarding %d samples code 0x%8.8X"), + nSamples, m_hr)); + for (int i = 0; i < nSamples; i++) { + ppSamples[i]->Release(); + } + return m_hr; + } + m_bFlushed = FALSE; + for (long i = 0; i < nSamples; i++) { + QueueSample(ppSamples[i]); + } + *nSamplesProcessed = nSamples; + if (!m_bBatchExact || + m_nBatched + m_List->GetCount() >= m_lBatchSize) { + NotifyThread(); + } + return S_OK; + } +} + +// Get ready for new data - cancels sticky m_hr +void COutputQueue::Reset() +{ + if (!IsQueued()) { + m_hr = S_OK; + } else { + CAutoLock lck(this); + QueueSample(RESET_PACKET); + NotifyThread(); + m_evFlushComplete.Wait(); + } +} + +// Remove and Release() all queued and Batched samples +void COutputQueue::FreeSamples() +{ + CAutoLock lck(this); + if (IsQueued()) { + while (TRUE) { + IMediaSample *pSample = m_List->RemoveHead(); + // inform derived class we took something off the queue + if (m_hEventPop) { + //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); + SetEvent(m_hEventPop); + } + + if (pSample == NULL) { + break; + } + if (!IsSpecialSample(pSample)) { + pSample->Release(); + } else { + if (pSample == NEW_SEGMENT) { + // Free NEW_SEGMENT packet + NewSegmentPacket *ppacket = + (NewSegmentPacket *) m_List->RemoveHead(); + // inform derived class we took something off the queue + if (m_hEventPop) { + //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); + SetEvent(m_hEventPop); + } + + ASSERT(ppacket != NULL); + delete ppacket; + } + } + } + } + for (int i = 0; i < m_nBatched; i++) { + m_ppSamples[i]->Release(); + } + m_nBatched = 0; +} + +// Notify the thread if there is something to do +// +// The critical section MUST be held when this is called +void COutputQueue::NotifyThread() +{ + // Optimize - no need to signal if it's not waiting + ASSERT(IsQueued()); + if (m_lWaiting) { + ReleaseSemaphore(m_hSem, m_lWaiting, NULL); + m_lWaiting = 0; + } +} + +// See if there's any work to do +// Returns +// TRUE if there is nothing on the queue and nothing in the batch +// and all data has been sent +// FALSE otherwise +// +BOOL COutputQueue::IsIdle() +{ + CAutoLock lck(this); + + // We're idle if + // there is no thread (!IsQueued()) OR + // the thread is waiting for more work (m_lWaiting != 0) + // AND + // there's nothing in the current batch (m_nBatched == 0) + + if (IsQueued() && m_lWaiting == 0 || m_nBatched != 0) { + return FALSE; + } else { + + // If we're idle it shouldn't be possible for there + // to be anything on the work queue + + ASSERT(!IsQueued() || m_List->GetCount() == 0); + return TRUE; + } +} + + +void COutputQueue::SetPopEvent(HANDLE hEvent) +{ + m_hEventPop = hEvent; +} diff --git a/plugins/GSdx/baseclasses/outputq.h b/plugins/GSdx/baseclasses/outputq.h index d021922a53..3869fa74b0 100644 --- a/plugins/GSdx/baseclasses/outputq.h +++ b/plugins/GSdx/baseclasses/outputq.h @@ -1,137 +1,137 @@ -//------------------------------------------------------------------------------ -// File: OutputQ.h -// -// Desc: DirectShow base classes - defines the COutputQueue class, which -// makes a queue of samples and sends them to an output pin. The -// class will optionally send the samples to the pin directly. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -typedef CGenericList CSampleList; - -class COutputQueue : public CCritSec -{ -public: - // Constructor - COutputQueue(IPin *pInputPin, // Pin to send stuff to - HRESULT *phr, // 'Return code' - BOOL bAuto = TRUE, // Ask pin if blocks - BOOL bQueue = TRUE, // Send through queue (ignored if - // bAuto set) - LONG lBatchSize = 1, // Batch - BOOL bBatchExact = FALSE,// Batch exactly to BatchSize - LONG lListSize = // Likely number in the list - DEFAULTCACHE, - DWORD dwPriority = // Priority of thread to create - THREAD_PRIORITY_NORMAL, - bool bFlushingOpt = false // flushing optimization - ); - ~COutputQueue(); - - // enter flush state - discard all data - void BeginFlush(); // Begin flushing samples - - // re-enable receives (pass this downstream) - void EndFlush(); // Complete flush of samples - downstream - // pin guaranteed not to block at this stage - - void EOS(); // Call this on End of stream - - void SendAnyway(); // Send batched samples anyway (if bBatchExact set) - - void NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate); - - HRESULT Receive(IMediaSample *pSample); - - // do something with these media samples - HRESULT ReceiveMultiple ( - IMediaSample **pSamples, - long nSamples, - long *nSamplesProcessed); - - void Reset(); // Reset m_hr ready for more data - - // See if its idle or not - BOOL IsIdle(); - - // give the class an event to fire after everything removed from the queue - void SetPopEvent(HANDLE hEvent); - -protected: - static DWORD WINAPI InitialThreadProc(LPVOID pv); - DWORD ThreadProc(); - BOOL IsQueued() - { - return m_List != NULL; - } - - // The critical section MUST be held when this is called - void QueueSample(IMediaSample *pSample); - - BOOL IsSpecialSample(IMediaSample *pSample) - { - return (DWORD_PTR)pSample > (DWORD_PTR)(LONG_PTR)(-16); - } - - // Remove and Release() batched and queued samples - void FreeSamples(); - - // Notify the thread there is something to do - void NotifyThread(); - - -protected: - // Queue 'messages' - #define SEND_PACKET ((IMediaSample *)(LONG_PTR)(-2)) // Send batch - #define EOS_PACKET ((IMediaSample *)(LONG_PTR)(-3)) // End of stream - #define RESET_PACKET ((IMediaSample *)(LONG_PTR)(-4)) // Reset m_hr - #define NEW_SEGMENT ((IMediaSample *)(LONG_PTR)(-5)) // send NewSegment - - // new segment packet is always followed by one of these - struct NewSegmentPacket { - REFERENCE_TIME tStart; - REFERENCE_TIME tStop; - double dRate; - }; - - // Remember input stuff - IPin * const m_pPin; - IMemInputPin * m_pInputPin; - BOOL const m_bBatchExact; - LONG const m_lBatchSize; - - CSampleList * m_List; - HANDLE m_hSem; - CAMEvent m_evFlushComplete; - HANDLE m_hThread; - IMediaSample ** m_ppSamples; - LONG m_nBatched; - - // Wait optimization - LONG m_lWaiting; - // Flush synchronization - BOOL m_bFlushing; - - // flushing optimization. some downstream filters have trouble - // with the queue's flushing optimization. other rely on it - BOOL m_bFlushed; - bool m_bFlushingOpt; - - // Terminate now - BOOL m_bTerminate; - - // Send anyway flag for batching - BOOL m_bSendAnyway; - - // Deferred 'return code' - BOOL volatile m_hr; - - // an event that can be fired after every deliver - HANDLE m_hEventPop; -}; - +//------------------------------------------------------------------------------ +// File: OutputQ.h +// +// Desc: DirectShow base classes - defines the COutputQueue class, which +// makes a queue of samples and sends them to an output pin. The +// class will optionally send the samples to the pin directly. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +typedef CGenericList CSampleList; + +class COutputQueue : public CCritSec +{ +public: + // Constructor + COutputQueue(IPin *pInputPin, // Pin to send stuff to + HRESULT *phr, // 'Return code' + BOOL bAuto = TRUE, // Ask pin if blocks + BOOL bQueue = TRUE, // Send through queue (ignored if + // bAuto set) + LONG lBatchSize = 1, // Batch + BOOL bBatchExact = FALSE,// Batch exactly to BatchSize + LONG lListSize = // Likely number in the list + DEFAULTCACHE, + DWORD dwPriority = // Priority of thread to create + THREAD_PRIORITY_NORMAL, + bool bFlushingOpt = false // flushing optimization + ); + ~COutputQueue(); + + // enter flush state - discard all data + void BeginFlush(); // Begin flushing samples + + // re-enable receives (pass this downstream) + void EndFlush(); // Complete flush of samples - downstream + // pin guaranteed not to block at this stage + + void EOS(); // Call this on End of stream + + void SendAnyway(); // Send batched samples anyway (if bBatchExact set) + + void NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + + HRESULT Receive(IMediaSample *pSample); + + // do something with these media samples + HRESULT ReceiveMultiple ( + IMediaSample **pSamples, + long nSamples, + long *nSamplesProcessed); + + void Reset(); // Reset m_hr ready for more data + + // See if its idle or not + BOOL IsIdle(); + + // give the class an event to fire after everything removed from the queue + void SetPopEvent(HANDLE hEvent); + +protected: + static DWORD WINAPI InitialThreadProc(LPVOID pv); + DWORD ThreadProc(); + BOOL IsQueued() + { + return m_List != NULL; + } + + // The critical section MUST be held when this is called + void QueueSample(IMediaSample *pSample); + + BOOL IsSpecialSample(IMediaSample *pSample) + { + return (DWORD_PTR)pSample > (DWORD_PTR)(LONG_PTR)(-16); + } + + // Remove and Release() batched and queued samples + void FreeSamples(); + + // Notify the thread there is something to do + void NotifyThread(); + + +protected: + // Queue 'messages' + #define SEND_PACKET ((IMediaSample *)(LONG_PTR)(-2)) // Send batch + #define EOS_PACKET ((IMediaSample *)(LONG_PTR)(-3)) // End of stream + #define RESET_PACKET ((IMediaSample *)(LONG_PTR)(-4)) // Reset m_hr + #define NEW_SEGMENT ((IMediaSample *)(LONG_PTR)(-5)) // send NewSegment + + // new segment packet is always followed by one of these + struct NewSegmentPacket { + REFERENCE_TIME tStart; + REFERENCE_TIME tStop; + double dRate; + }; + + // Remember input stuff + IPin * const m_pPin; + IMemInputPin * m_pInputPin; + BOOL const m_bBatchExact; + LONG const m_lBatchSize; + + CSampleList * m_List; + HANDLE m_hSem; + CAMEvent m_evFlushComplete; + HANDLE m_hThread; + IMediaSample ** m_ppSamples; + LONG m_nBatched; + + // Wait optimization + LONG m_lWaiting; + // Flush synchronization + BOOL m_bFlushing; + + // flushing optimization. some downstream filters have trouble + // with the queue's flushing optimization. other rely on it + BOOL m_bFlushed; + bool m_bFlushingOpt; + + // Terminate now + BOOL m_bTerminate; + + // Send anyway flag for batching + BOOL m_bSendAnyway; + + // Deferred 'return code' + BOOL volatile m_hr; + + // an event that can be fired after every deliver + HANDLE m_hEventPop; +}; + diff --git a/plugins/GSdx/baseclasses/pstream.cpp b/plugins/GSdx/baseclasses/pstream.cpp index af85fee9da..3a15b39e91 100644 --- a/plugins/GSdx/baseclasses/pstream.cpp +++ b/plugins/GSdx/baseclasses/pstream.cpp @@ -1,196 +1,196 @@ -//------------------------------------------------------------------------------ -// File: PStream.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" - -#ifdef PERF -#include -#endif - - -// -// Constructor -// -CPersistStream::CPersistStream(IUnknown *punk, HRESULT *phr) - : mPS_fDirty(FALSE) -{ - mPS_dwFileVersion = GetSoftwareVersion(); -} - - -// -// Destructor -// -CPersistStream::~CPersistStream() { - // Nothing to do -} - -#if 0 -SAMPLE CODE TO COPY - not active at the moment - -// -// NonDelegatingQueryInterface -// -// This object supports IPersist & IPersistStream -STDMETHODIMP CPersistStream::NonDelegatingQueryInterface(REFIID riid, void **ppv) -{ - if (riid == IID_IPersist) { - return GetInterface((IPersist *) this, ppv); - } - else if (riid == IID_IPersistStream) { - return GetInterface((IPersistStream *) this, ppv); - } - else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} -#endif - - -// -// WriteToStream -// -// Writes to the stream (default action is to write nothing) -HRESULT CPersistStream::WriteToStream(IStream *pStream) -{ - // You can override this to do things like - // hr = pStream->Write(MyStructure, sizeof(MyStructure), NULL); - - return NOERROR; -} - - - -HRESULT CPersistStream::ReadFromStream(IStream * pStream) -{ - // You can override this to do things like - // hr = pStream->Read(MyStructure, sizeof(MyStructure), NULL); - - return NOERROR; -} - - -// -// Load -// -// Load all the data from the given stream -STDMETHODIMP CPersistStream::Load(LPSTREAM pStm) -{ - HRESULT hr; - // Load the version number then the data - mPS_dwFileVersion = ReadInt(pStm, hr); - if (FAILED(hr)) { - return hr; - } - - return ReadFromStream(pStm); -} // Load - - - -// -// Save -// -// Save the contents of this Stream. -STDMETHODIMP CPersistStream::Save(LPSTREAM pStm, BOOL fClearDirty) -{ - - HRESULT hr = WriteInt(pStm, GetSoftwareVersion()); - if (FAILED(hr)) { - return hr; - } - - hr = WriteToStream(pStm); - if (FAILED(hr)) { - return hr; - } - - mPS_fDirty = !fClearDirty; - - return hr; -} // Save - - -// WriteInt -// -// Writes an integer to an IStream as 11 UNICODE characters followed by one space. -// You could use this for shorts or unsigneds or anything (up to 32 bits) -// where the value isn't actually truncated by squeezing it into 32 bits. -// Values such as (unsigned) 0x80000000 would come out as -2147483648 -// but would then load as 0x80000000 through ReadInt. Cast as you please. - -STDAPI WriteInt(IStream *pIStream, int n) -{ - WCHAR Buff[13]; // Allows for trailing null that we don't write - (void)StringCchPrintfW(Buff, NUMELMS(Buff), L"%011d ",n); - return pIStream->Write(&(Buff[0]), 12*sizeof(WCHAR), NULL); -} // WriteInt - - -// ReadInt -// -// Reads an integer from an IStream. -// Read as 4 bytes. You could use this for shorts or unsigneds or anything -// where the value isn't actually truncated by squeezing it into 32 bits -// Striped down subset of what sscanf can do (without dragging in the C runtime) - -STDAPI_(int) ReadInt(IStream *pIStream, HRESULT &hr) -{ - - int Sign = 1; - unsigned int n = 0; // result wil be n*Sign - WCHAR wch; - - hr = pIStream->Read( &wch, sizeof(wch), NULL); - if (FAILED(hr)) { - return 0; - } - - if (wch==L'-'){ - Sign = -1; - hr = pIStream->Read( &wch, sizeof(wch), NULL); - if (FAILED(hr)) { - return 0; - } - } - - for( ; ; ) { - if (wch>=L'0' && wch<=L'9') { - n = 10*n+(int)(wch-L'0'); - } else if ( wch == L' ' - || wch == L'\t' - || wch == L'\r' - || wch == L'\n' - || wch == L'\0' - ) { - break; - } else { - hr = VFW_E_INVALID_FILE_FORMAT; - return 0; - } - - hr = pIStream->Read( &wch, sizeof(wch), NULL); - if (FAILED(hr)) { - return 0; - } - } - - if (n==0x80000000 && Sign==-1) { - // This is the negative number that has no positive version! - return (int)n; - } - else return (int)n * Sign; -} // ReadInt - - -// The microsoft C/C++ compile generates level 4 warnings to the effect that -// a particular inline function (from some base class) was not needed. -// This line gets rid of hundreds of such unwanted messages and makes -// -W4 compilation feasible: -#pragma warning(disable: 4514) +//------------------------------------------------------------------------------ +// File: PStream.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" + +#ifdef PERF +#include +#endif + + +// +// Constructor +// +CPersistStream::CPersistStream(IUnknown *punk, HRESULT *phr) + : mPS_fDirty(FALSE) +{ + mPS_dwFileVersion = GetSoftwareVersion(); +} + + +// +// Destructor +// +CPersistStream::~CPersistStream() { + // Nothing to do +} + +#if 0 +SAMPLE CODE TO COPY - not active at the moment + +// +// NonDelegatingQueryInterface +// +// This object supports IPersist & IPersistStream +STDMETHODIMP CPersistStream::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + if (riid == IID_IPersist) { + return GetInterface((IPersist *) this, ppv); + } + else if (riid == IID_IPersistStream) { + return GetInterface((IPersistStream *) this, ppv); + } + else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} +#endif + + +// +// WriteToStream +// +// Writes to the stream (default action is to write nothing) +HRESULT CPersistStream::WriteToStream(IStream *pStream) +{ + // You can override this to do things like + // hr = pStream->Write(MyStructure, sizeof(MyStructure), NULL); + + return NOERROR; +} + + + +HRESULT CPersistStream::ReadFromStream(IStream * pStream) +{ + // You can override this to do things like + // hr = pStream->Read(MyStructure, sizeof(MyStructure), NULL); + + return NOERROR; +} + + +// +// Load +// +// Load all the data from the given stream +STDMETHODIMP CPersistStream::Load(LPSTREAM pStm) +{ + HRESULT hr; + // Load the version number then the data + mPS_dwFileVersion = ReadInt(pStm, hr); + if (FAILED(hr)) { + return hr; + } + + return ReadFromStream(pStm); +} // Load + + + +// +// Save +// +// Save the contents of this Stream. +STDMETHODIMP CPersistStream::Save(LPSTREAM pStm, BOOL fClearDirty) +{ + + HRESULT hr = WriteInt(pStm, GetSoftwareVersion()); + if (FAILED(hr)) { + return hr; + } + + hr = WriteToStream(pStm); + if (FAILED(hr)) { + return hr; + } + + mPS_fDirty = !fClearDirty; + + return hr; +} // Save + + +// WriteInt +// +// Writes an integer to an IStream as 11 UNICODE characters followed by one space. +// You could use this for shorts or unsigneds or anything (up to 32 bits) +// where the value isn't actually truncated by squeezing it into 32 bits. +// Values such as (unsigned) 0x80000000 would come out as -2147483648 +// but would then load as 0x80000000 through ReadInt. Cast as you please. + +STDAPI WriteInt(IStream *pIStream, int n) +{ + WCHAR Buff[13]; // Allows for trailing null that we don't write + (void)StringCchPrintfW(Buff, NUMELMS(Buff), L"%011d ",n); + return pIStream->Write(&(Buff[0]), 12*sizeof(WCHAR), NULL); +} // WriteInt + + +// ReadInt +// +// Reads an integer from an IStream. +// Read as 4 bytes. You could use this for shorts or unsigneds or anything +// where the value isn't actually truncated by squeezing it into 32 bits +// Striped down subset of what sscanf can do (without dragging in the C runtime) + +STDAPI_(int) ReadInt(IStream *pIStream, HRESULT &hr) +{ + + int Sign = 1; + unsigned int n = 0; // result wil be n*Sign + WCHAR wch; + + hr = pIStream->Read( &wch, sizeof(wch), NULL); + if (FAILED(hr)) { + return 0; + } + + if (wch==L'-'){ + Sign = -1; + hr = pIStream->Read( &wch, sizeof(wch), NULL); + if (FAILED(hr)) { + return 0; + } + } + + for( ; ; ) { + if (wch>=L'0' && wch<=L'9') { + n = 10*n+(int)(wch-L'0'); + } else if ( wch == L' ' + || wch == L'\t' + || wch == L'\r' + || wch == L'\n' + || wch == L'\0' + ) { + break; + } else { + hr = VFW_E_INVALID_FILE_FORMAT; + return 0; + } + + hr = pIStream->Read( &wch, sizeof(wch), NULL); + if (FAILED(hr)) { + return 0; + } + } + + if (n==0x80000000 && Sign==-1) { + // This is the negative number that has no positive version! + return (int)n; + } + else return (int)n * Sign; +} // ReadInt + + +// The microsoft C/C++ compile generates level 4 warnings to the effect that +// a particular inline function (from some base class) was not needed. +// This line gets rid of hundreds of such unwanted messages and makes +// -W4 compilation feasible: +#pragma warning(disable: 4514) diff --git a/plugins/GSdx/baseclasses/pstream.h b/plugins/GSdx/baseclasses/pstream.h index 95ec88cdd5..0611a4e311 100644 --- a/plugins/GSdx/baseclasses/pstream.h +++ b/plugins/GSdx/baseclasses/pstream.h @@ -1,114 +1,114 @@ -//------------------------------------------------------------------------------ -// File: PStream.h -// -// Desc: DirectShow base classes - defines a class for persistent properties -// of filters. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __PSTREAM__ -#define __PSTREAM__ - -// Base class for persistent properties of filters -// (i.e. filter properties in saved graphs) - -// The simplest way to use this is: -// 1. Arrange for your filter to inherit this class -// 2. Implement in your class WriteToStream and ReadFromStream -// These will override the "do nothing" functions here. -// 3. Change your NonDelegatingQueryInterface to handle IPersistStream -// 4. Implement SizeMax to return the number of bytes of data you save. -// If you save UNICODE data, don't forget a char is 2 bytes. -// 5. Whenever your data changes, call SetDirty() -// -// At some point you may decide to alter, or extend the format of your data. -// At that point you will wish that you had a version number in all the old -// saved graphs, so that you can tell, when you read them, whether they -// represent the old or new form. To assist you in this, this class -// writes and reads a version number. -// When it writes, it calls GetSoftwareVersion() to enquire what version -// of the software we have at the moment. (In effect this is a version number -// of the data layout in the file). It writes this as the first thing in the data. -// If you want to change the version, implement (override) GetSoftwareVersion(). -// It reads this from the file into mPS_dwFileVersion before calling ReadFromStream, -// so in ReadFromStream you can check mPS_dwFileVersion to see if you are reading -// an old version file. -// Normally you should accept files whose version is no newer than the software -// version that's reading them. - - -// CPersistStream -// -// Implements IPersistStream. -// See 'OLE Programmers Reference (Vol 1):Structured Storage Overview' for -// more implementation information. -class CPersistStream : public IPersistStream { - private: - - // Internal state: - - protected: - DWORD mPS_dwFileVersion; // version number of file (being read) - BOOL mPS_fDirty; - - public: - - // IPersistStream methods - - STDMETHODIMP IsDirty() - {return (mPS_fDirty ? S_OK : S_FALSE);} // note FALSE means clean - STDMETHODIMP Load(LPSTREAM pStm); - STDMETHODIMP Save(LPSTREAM pStm, BOOL fClearDirty); - STDMETHODIMP GetSizeMax(ULARGE_INTEGER * pcbSize) - // Allow 24 bytes for version. - { pcbSize->QuadPart = 12*sizeof(WCHAR)+SizeMax(); return NOERROR; } - - // implementation - - CPersistStream(IUnknown *punk, HRESULT *phr); - ~CPersistStream(); - - HRESULT SetDirty(BOOL fDirty) - { mPS_fDirty = fDirty; return NOERROR;} - - - // override to reveal IPersist & IPersistStream - // STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); - - // --- IPersist --- - - // You must override this to provide your own class id - STDMETHODIMP GetClassID(CLSID *pClsid) PURE; - - // overrideable if you want - // file version number. Override it if you ever change format - virtual DWORD GetSoftwareVersion(void) { return 0; } - - - //========================================================================= - // OVERRIDE THESE to read and write your data - // OVERRIDE THESE to read and write your data - // OVERRIDE THESE to read and write your data - - virtual int SizeMax() {return 0;} - virtual HRESULT WriteToStream(IStream *pStream); - virtual HRESULT ReadFromStream(IStream *pStream); - //========================================================================= - - private: - -}; - - -// --- Useful helpers --- - - -// Writes an int to an IStream as UNICODE. -STDAPI WriteInt(IStream *pIStream, int n); - -// inverse of WriteInt -STDAPI_(int) ReadInt(IStream *pIStream, HRESULT &hr); - -#endif // __PSTREAM__ +//------------------------------------------------------------------------------ +// File: PStream.h +// +// Desc: DirectShow base classes - defines a class for persistent properties +// of filters. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __PSTREAM__ +#define __PSTREAM__ + +// Base class for persistent properties of filters +// (i.e. filter properties in saved graphs) + +// The simplest way to use this is: +// 1. Arrange for your filter to inherit this class +// 2. Implement in your class WriteToStream and ReadFromStream +// These will override the "do nothing" functions here. +// 3. Change your NonDelegatingQueryInterface to handle IPersistStream +// 4. Implement SizeMax to return the number of bytes of data you save. +// If you save UNICODE data, don't forget a char is 2 bytes. +// 5. Whenever your data changes, call SetDirty() +// +// At some point you may decide to alter, or extend the format of your data. +// At that point you will wish that you had a version number in all the old +// saved graphs, so that you can tell, when you read them, whether they +// represent the old or new form. To assist you in this, this class +// writes and reads a version number. +// When it writes, it calls GetSoftwareVersion() to enquire what version +// of the software we have at the moment. (In effect this is a version number +// of the data layout in the file). It writes this as the first thing in the data. +// If you want to change the version, implement (override) GetSoftwareVersion(). +// It reads this from the file into mPS_dwFileVersion before calling ReadFromStream, +// so in ReadFromStream you can check mPS_dwFileVersion to see if you are reading +// an old version file. +// Normally you should accept files whose version is no newer than the software +// version that's reading them. + + +// CPersistStream +// +// Implements IPersistStream. +// See 'OLE Programmers Reference (Vol 1):Structured Storage Overview' for +// more implementation information. +class CPersistStream : public IPersistStream { + private: + + // Internal state: + + protected: + DWORD mPS_dwFileVersion; // version number of file (being read) + BOOL mPS_fDirty; + + public: + + // IPersistStream methods + + STDMETHODIMP IsDirty() + {return (mPS_fDirty ? S_OK : S_FALSE);} // note FALSE means clean + STDMETHODIMP Load(LPSTREAM pStm); + STDMETHODIMP Save(LPSTREAM pStm, BOOL fClearDirty); + STDMETHODIMP GetSizeMax(ULARGE_INTEGER * pcbSize) + // Allow 24 bytes for version. + { pcbSize->QuadPart = 12*sizeof(WCHAR)+SizeMax(); return NOERROR; } + + // implementation + + CPersistStream(IUnknown *punk, HRESULT *phr); + ~CPersistStream(); + + HRESULT SetDirty(BOOL fDirty) + { mPS_fDirty = fDirty; return NOERROR;} + + + // override to reveal IPersist & IPersistStream + // STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + // --- IPersist --- + + // You must override this to provide your own class id + STDMETHODIMP GetClassID(CLSID *pClsid) PURE; + + // overrideable if you want + // file version number. Override it if you ever change format + virtual DWORD GetSoftwareVersion(void) { return 0; } + + + //========================================================================= + // OVERRIDE THESE to read and write your data + // OVERRIDE THESE to read and write your data + // OVERRIDE THESE to read and write your data + + virtual int SizeMax() {return 0;} + virtual HRESULT WriteToStream(IStream *pStream); + virtual HRESULT ReadFromStream(IStream *pStream); + //========================================================================= + + private: + +}; + + +// --- Useful helpers --- + + +// Writes an int to an IStream as UNICODE. +STDAPI WriteInt(IStream *pIStream, int n); + +// inverse of WriteInt +STDAPI_(int) ReadInt(IStream *pIStream, HRESULT &hr); + +#endif // __PSTREAM__ diff --git a/plugins/GSdx/baseclasses/pullpin.cpp b/plugins/GSdx/baseclasses/pullpin.cpp index da347f570a..81d0199351 100644 --- a/plugins/GSdx/baseclasses/pullpin.cpp +++ b/plugins/GSdx/baseclasses/pullpin.cpp @@ -1,527 +1,527 @@ -//------------------------------------------------------------------------------ -// File: PullPin.cpp -// -// Desc: DirectShow base classes - implements CPullPin class that pulls data -// from IAsyncReader. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include "pullpin.h" - - - -CPullPin::CPullPin() - : m_pReader(NULL), - m_pAlloc(NULL), - m_State(TM_Exit) -{ -} - -CPullPin::~CPullPin() -{ - Disconnect(); -} - -// returns S_OK if successfully connected to an IAsyncReader interface -// from this object -// Optional allocator should be proposed as a preferred allocator if -// necessary -HRESULT -CPullPin::Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync) -{ - CAutoLock lock(&m_AccessLock); - - if (m_pReader) { - return VFW_E_ALREADY_CONNECTED; - } - - HRESULT hr = pUnk->QueryInterface(IID_IAsyncReader, (void**)&m_pReader); - if (FAILED(hr)) { - return(hr); - } - - hr = DecideAllocator(pAlloc, NULL); - if (FAILED(hr)) { - Disconnect(); - return hr; - } - - LONGLONG llTotal, llAvail; - hr = m_pReader->Length(&llTotal, &llAvail); - if (FAILED(hr)) { - Disconnect(); - return hr; - } - - // convert from file position to reference time - m_tDuration = llTotal * UNITS; - m_tStop = m_tDuration; - m_tStart = 0; - - m_bSync = bSync; - - return S_OK; -} - -// disconnect any connection made in Connect -HRESULT -CPullPin::Disconnect() -{ - CAutoLock lock(&m_AccessLock); - - StopThread(); - - if (m_pReader) { - m_pReader->Release(); - m_pReader = NULL; - } - - if (m_pAlloc) { - m_pAlloc->Release(); - m_pAlloc = NULL; - } - - return S_OK; -} - -// agree an allocator using RequestAllocator - optional -// props param specifies your requirements (non-zero fields). -// returns an error code if fail to match requirements. -// optional IMemAllocator interface is offered as a preferred allocator -// but no error occurs if it can't be met. -HRESULT -CPullPin::DecideAllocator( - IMemAllocator * pAlloc, - ALLOCATOR_PROPERTIES * pProps) -{ - ALLOCATOR_PROPERTIES *pRequest; - ALLOCATOR_PROPERTIES Request; - if (pProps == NULL) { - Request.cBuffers = 3; - Request.cbBuffer = 64*1024; - Request.cbAlign = 0; - Request.cbPrefix = 0; - pRequest = &Request; - } else { - pRequest = pProps; - } - HRESULT hr = m_pReader->RequestAllocator( - pAlloc, - pRequest, - &m_pAlloc); - return hr; -} - -// start pulling data -HRESULT -CPullPin::Active(void) -{ - ASSERT(!ThreadExists()); - return StartThread(); -} - -// stop pulling data -HRESULT -CPullPin::Inactive(void) -{ - StopThread(); - - return S_OK; -} - -HRESULT -CPullPin::Seek(REFERENCE_TIME tStart, REFERENCE_TIME tStop) -{ - CAutoLock lock(&m_AccessLock); - - ThreadMsg AtStart = m_State; - - if (AtStart == TM_Start) { - BeginFlush(); - PauseThread(); - EndFlush(); - } - - m_tStart = tStart; - m_tStop = tStop; - - HRESULT hr = S_OK; - if (AtStart == TM_Start) { - hr = StartThread(); - } - - return hr; -} - -HRESULT -CPullPin::Duration(REFERENCE_TIME* ptDuration) -{ - *ptDuration = m_tDuration; - return S_OK; -} - - -HRESULT -CPullPin::StartThread() -{ - CAutoLock lock(&m_AccessLock); - - if (!m_pAlloc || !m_pReader) { - return E_UNEXPECTED; - } - - HRESULT hr; - if (!ThreadExists()) { - - // commit allocator - hr = m_pAlloc->Commit(); - if (FAILED(hr)) { - return hr; - } - - // start thread - if (!Create()) { - return E_FAIL; - } - } - - m_State = TM_Start; - hr = (HRESULT) CallWorker(m_State); - return hr; -} - -HRESULT -CPullPin::PauseThread() -{ - CAutoLock lock(&m_AccessLock); - - if (!ThreadExists()) { - return E_UNEXPECTED; - } - - // need to flush to ensure the thread is not blocked - // in WaitForNext - HRESULT hr = m_pReader->BeginFlush(); - if (FAILED(hr)) { - return hr; - } - - m_State = TM_Pause; - hr = CallWorker(TM_Pause); - - m_pReader->EndFlush(); - return hr; -} - -HRESULT -CPullPin::StopThread() -{ - CAutoLock lock(&m_AccessLock); - - if (!ThreadExists()) { - return S_FALSE; - } - - // need to flush to ensure the thread is not blocked - // in WaitForNext - HRESULT hr = m_pReader->BeginFlush(); - if (FAILED(hr)) { - return hr; - } - - m_State = TM_Exit; - hr = CallWorker(TM_Exit); - - m_pReader->EndFlush(); - - // wait for thread to completely exit - Close(); - - // decommit allocator - if (m_pAlloc) { - m_pAlloc->Decommit(); - } - - return S_OK; -} - - -DWORD -CPullPin::ThreadProc(void) -{ - while(1) { - DWORD cmd = GetRequest(); - switch(cmd) { - case TM_Exit: - Reply(S_OK); - return 0; - - case TM_Pause: - // we are paused already - Reply(S_OK); - break; - - case TM_Start: - Reply(S_OK); - Process(); - break; - } - - // at this point, there should be no outstanding requests on the - // upstream filter. - // We should force begin/endflush to ensure that this is true. - // !!!Note that we may currently be inside a BeginFlush/EndFlush pair - // on another thread, but the premature EndFlush will do no harm now - // that we are idle. - m_pReader->BeginFlush(); - CleanupCancelled(); - m_pReader->EndFlush(); - } -} - -HRESULT -CPullPin::QueueSample( - REFERENCE_TIME& tCurrent, - REFERENCE_TIME tAlignStop, - BOOL bDiscontinuity - ) -{ - IMediaSample* pSample; - - HRESULT hr = m_pAlloc->GetBuffer(&pSample, NULL, NULL, 0); - if (FAILED(hr)) { - return hr; - } - - LONGLONG tStopThis = tCurrent + (pSample->GetSize() * UNITS); - if (tStopThis > tAlignStop) { - tStopThis = tAlignStop; - } - pSample->SetTime(&tCurrent, &tStopThis); - tCurrent = tStopThis; - - pSample->SetDiscontinuity(bDiscontinuity); - - hr = m_pReader->Request( - pSample, - 0); - if (FAILED(hr)) { - pSample->Release(); - - CleanupCancelled(); - OnError(hr); - } - return hr; -} - -HRESULT -CPullPin::CollectAndDeliver( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop) -{ - IMediaSample* pSample = NULL; // better be sure pSample is set - DWORD_PTR dwUnused; - HRESULT hr = m_pReader->WaitForNext( - INFINITE, - &pSample, - &dwUnused); - if (FAILED(hr)) { - if (pSample) { - pSample->Release(); - } - } else { - hr = DeliverSample(pSample, tStart, tStop); - } - if (FAILED(hr)) { - CleanupCancelled(); - OnError(hr); - } - return hr; - -} - -HRESULT -CPullPin::DeliverSample( - IMediaSample* pSample, - REFERENCE_TIME tStart, - REFERENCE_TIME tStop - ) -{ - // fix up sample if past actual stop (for sector alignment) - REFERENCE_TIME t1, t2; - pSample->GetTime(&t1, &t2); - if (t2 > tStop) { - t2 = tStop; - } - - // adjust times to be relative to (aligned) start time - t1 -= tStart; - t2 -= tStart; - pSample->SetTime(&t1, &t2); - - - HRESULT hr = Receive(pSample); - pSample->Release(); - return hr; -} - -void -CPullPin::Process(void) -{ - // is there anything to do? - if (m_tStop <= m_tStart) { - EndOfStream(); - return; - } - - BOOL bDiscontinuity = TRUE; - - // if there is more than one sample at the allocator, - // then try to queue 2 at once in order to overlap. - // -- get buffer count and required alignment - ALLOCATOR_PROPERTIES Actual; - HRESULT hr = m_pAlloc->GetProperties(&Actual); - - // align the start position downwards - REFERENCE_TIME tStart = AlignDown(m_tStart / UNITS, Actual.cbAlign) * UNITS; - REFERENCE_TIME tCurrent = tStart; - - REFERENCE_TIME tStop = m_tStop; - if (tStop > m_tDuration) { - tStop = m_tDuration; - } - - // align the stop position - may be past stop, but that - // doesn't matter - REFERENCE_TIME tAlignStop = AlignUp(tStop / UNITS, Actual.cbAlign) * UNITS; - - - DWORD dwRequest; - - if (!m_bSync) { - - // Break out of the loop either if we get to the end or we're asked - // to do something else - while (tCurrent < tAlignStop) { - - // Break out without calling EndOfStream if we're asked to - // do something different - if (CheckRequest(&dwRequest)) { - return; - } - - // queue a first sample - if (Actual.cBuffers > 1) { - - hr = QueueSample(tCurrent, tAlignStop, TRUE); - bDiscontinuity = FALSE; - - if (FAILED(hr)) { - return; - } - } - - - - // loop queueing second and waiting for first.. - while (tCurrent < tAlignStop) { - - hr = QueueSample(tCurrent, tAlignStop, bDiscontinuity); - bDiscontinuity = FALSE; - - if (FAILED(hr)) { - return; - } - - hr = CollectAndDeliver(tStart, tStop); - if (S_OK != hr) { - - // stop if error, or if downstream filter said - // to stop. - return; - } - } - - if (Actual.cBuffers > 1) { - hr = CollectAndDeliver(tStart, tStop); - if (FAILED(hr)) { - return; - } - } - } - } else { - - // sync version of above loop - while (tCurrent < tAlignStop) { - - // Break out without calling EndOfStream if we're asked to - // do something different - if (CheckRequest(&dwRequest)) { - return; - } - - IMediaSample* pSample; - - hr = m_pAlloc->GetBuffer(&pSample, NULL, NULL, 0); - if (FAILED(hr)) { - OnError(hr); - return; - } - - LONGLONG tStopThis = tCurrent + (pSample->GetSize() * UNITS); - if (tStopThis > tAlignStop) { - tStopThis = tAlignStop; - } - pSample->SetTime(&tCurrent, &tStopThis); - tCurrent = tStopThis; - - if (bDiscontinuity) { - pSample->SetDiscontinuity(TRUE); - bDiscontinuity = FALSE; - } - - hr = m_pReader->SyncReadAligned(pSample); - - if (FAILED(hr)) { - pSample->Release(); - OnError(hr); - return; - } - - hr = DeliverSample(pSample, tStart, tStop); - if (hr != S_OK) { - if (FAILED(hr)) { - OnError(hr); - } - return; - } - } - } - - EndOfStream(); -} - -// after a flush, cancelled i/o will be waiting for collection -// and release -void -CPullPin::CleanupCancelled(void) -{ - while (1) { - IMediaSample * pSample; - DWORD_PTR dwUnused; - - HRESULT hr = m_pReader->WaitForNext( - 0, // no wait - &pSample, - &dwUnused); - if(pSample) { - pSample->Release(); - } else { - // no more samples - return; - } - } -} +//------------------------------------------------------------------------------ +// File: PullPin.cpp +// +// Desc: DirectShow base classes - implements CPullPin class that pulls data +// from IAsyncReader. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include "pullpin.h" + + + +CPullPin::CPullPin() + : m_pReader(NULL), + m_pAlloc(NULL), + m_State(TM_Exit) +{ +} + +CPullPin::~CPullPin() +{ + Disconnect(); +} + +// returns S_OK if successfully connected to an IAsyncReader interface +// from this object +// Optional allocator should be proposed as a preferred allocator if +// necessary +HRESULT +CPullPin::Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync) +{ + CAutoLock lock(&m_AccessLock); + + if (m_pReader) { + return VFW_E_ALREADY_CONNECTED; + } + + HRESULT hr = pUnk->QueryInterface(IID_IAsyncReader, (void**)&m_pReader); + if (FAILED(hr)) { + return(hr); + } + + hr = DecideAllocator(pAlloc, NULL); + if (FAILED(hr)) { + Disconnect(); + return hr; + } + + LONGLONG llTotal, llAvail; + hr = m_pReader->Length(&llTotal, &llAvail); + if (FAILED(hr)) { + Disconnect(); + return hr; + } + + // convert from file position to reference time + m_tDuration = llTotal * UNITS; + m_tStop = m_tDuration; + m_tStart = 0; + + m_bSync = bSync; + + return S_OK; +} + +// disconnect any connection made in Connect +HRESULT +CPullPin::Disconnect() +{ + CAutoLock lock(&m_AccessLock); + + StopThread(); + + if (m_pReader) { + m_pReader->Release(); + m_pReader = NULL; + } + + if (m_pAlloc) { + m_pAlloc->Release(); + m_pAlloc = NULL; + } + + return S_OK; +} + +// agree an allocator using RequestAllocator - optional +// props param specifies your requirements (non-zero fields). +// returns an error code if fail to match requirements. +// optional IMemAllocator interface is offered as a preferred allocator +// but no error occurs if it can't be met. +HRESULT +CPullPin::DecideAllocator( + IMemAllocator * pAlloc, + ALLOCATOR_PROPERTIES * pProps) +{ + ALLOCATOR_PROPERTIES *pRequest; + ALLOCATOR_PROPERTIES Request; + if (pProps == NULL) { + Request.cBuffers = 3; + Request.cbBuffer = 64*1024; + Request.cbAlign = 0; + Request.cbPrefix = 0; + pRequest = &Request; + } else { + pRequest = pProps; + } + HRESULT hr = m_pReader->RequestAllocator( + pAlloc, + pRequest, + &m_pAlloc); + return hr; +} + +// start pulling data +HRESULT +CPullPin::Active(void) +{ + ASSERT(!ThreadExists()); + return StartThread(); +} + +// stop pulling data +HRESULT +CPullPin::Inactive(void) +{ + StopThread(); + + return S_OK; +} + +HRESULT +CPullPin::Seek(REFERENCE_TIME tStart, REFERENCE_TIME tStop) +{ + CAutoLock lock(&m_AccessLock); + + ThreadMsg AtStart = m_State; + + if (AtStart == TM_Start) { + BeginFlush(); + PauseThread(); + EndFlush(); + } + + m_tStart = tStart; + m_tStop = tStop; + + HRESULT hr = S_OK; + if (AtStart == TM_Start) { + hr = StartThread(); + } + + return hr; +} + +HRESULT +CPullPin::Duration(REFERENCE_TIME* ptDuration) +{ + *ptDuration = m_tDuration; + return S_OK; +} + + +HRESULT +CPullPin::StartThread() +{ + CAutoLock lock(&m_AccessLock); + + if (!m_pAlloc || !m_pReader) { + return E_UNEXPECTED; + } + + HRESULT hr; + if (!ThreadExists()) { + + // commit allocator + hr = m_pAlloc->Commit(); + if (FAILED(hr)) { + return hr; + } + + // start thread + if (!Create()) { + return E_FAIL; + } + } + + m_State = TM_Start; + hr = (HRESULT) CallWorker(m_State); + return hr; +} + +HRESULT +CPullPin::PauseThread() +{ + CAutoLock lock(&m_AccessLock); + + if (!ThreadExists()) { + return E_UNEXPECTED; + } + + // need to flush to ensure the thread is not blocked + // in WaitForNext + HRESULT hr = m_pReader->BeginFlush(); + if (FAILED(hr)) { + return hr; + } + + m_State = TM_Pause; + hr = CallWorker(TM_Pause); + + m_pReader->EndFlush(); + return hr; +} + +HRESULT +CPullPin::StopThread() +{ + CAutoLock lock(&m_AccessLock); + + if (!ThreadExists()) { + return S_FALSE; + } + + // need to flush to ensure the thread is not blocked + // in WaitForNext + HRESULT hr = m_pReader->BeginFlush(); + if (FAILED(hr)) { + return hr; + } + + m_State = TM_Exit; + hr = CallWorker(TM_Exit); + + m_pReader->EndFlush(); + + // wait for thread to completely exit + Close(); + + // decommit allocator + if (m_pAlloc) { + m_pAlloc->Decommit(); + } + + return S_OK; +} + + +DWORD +CPullPin::ThreadProc(void) +{ + while(1) { + DWORD cmd = GetRequest(); + switch(cmd) { + case TM_Exit: + Reply(S_OK); + return 0; + + case TM_Pause: + // we are paused already + Reply(S_OK); + break; + + case TM_Start: + Reply(S_OK); + Process(); + break; + } + + // at this point, there should be no outstanding requests on the + // upstream filter. + // We should force begin/endflush to ensure that this is true. + // !!!Note that we may currently be inside a BeginFlush/EndFlush pair + // on another thread, but the premature EndFlush will do no harm now + // that we are idle. + m_pReader->BeginFlush(); + CleanupCancelled(); + m_pReader->EndFlush(); + } +} + +HRESULT +CPullPin::QueueSample( + REFERENCE_TIME& tCurrent, + REFERENCE_TIME tAlignStop, + BOOL bDiscontinuity + ) +{ + IMediaSample* pSample; + + HRESULT hr = m_pAlloc->GetBuffer(&pSample, NULL, NULL, 0); + if (FAILED(hr)) { + return hr; + } + + LONGLONG tStopThis = tCurrent + (pSample->GetSize() * UNITS); + if (tStopThis > tAlignStop) { + tStopThis = tAlignStop; + } + pSample->SetTime(&tCurrent, &tStopThis); + tCurrent = tStopThis; + + pSample->SetDiscontinuity(bDiscontinuity); + + hr = m_pReader->Request( + pSample, + 0); + if (FAILED(hr)) { + pSample->Release(); + + CleanupCancelled(); + OnError(hr); + } + return hr; +} + +HRESULT +CPullPin::CollectAndDeliver( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop) +{ + IMediaSample* pSample = NULL; // better be sure pSample is set + DWORD_PTR dwUnused; + HRESULT hr = m_pReader->WaitForNext( + INFINITE, + &pSample, + &dwUnused); + if (FAILED(hr)) { + if (pSample) { + pSample->Release(); + } + } else { + hr = DeliverSample(pSample, tStart, tStop); + } + if (FAILED(hr)) { + CleanupCancelled(); + OnError(hr); + } + return hr; + +} + +HRESULT +CPullPin::DeliverSample( + IMediaSample* pSample, + REFERENCE_TIME tStart, + REFERENCE_TIME tStop + ) +{ + // fix up sample if past actual stop (for sector alignment) + REFERENCE_TIME t1, t2; + pSample->GetTime(&t1, &t2); + if (t2 > tStop) { + t2 = tStop; + } + + // adjust times to be relative to (aligned) start time + t1 -= tStart; + t2 -= tStart; + pSample->SetTime(&t1, &t2); + + + HRESULT hr = Receive(pSample); + pSample->Release(); + return hr; +} + +void +CPullPin::Process(void) +{ + // is there anything to do? + if (m_tStop <= m_tStart) { + EndOfStream(); + return; + } + + BOOL bDiscontinuity = TRUE; + + // if there is more than one sample at the allocator, + // then try to queue 2 at once in order to overlap. + // -- get buffer count and required alignment + ALLOCATOR_PROPERTIES Actual; + HRESULT hr = m_pAlloc->GetProperties(&Actual); + + // align the start position downwards + REFERENCE_TIME tStart = AlignDown(m_tStart / UNITS, Actual.cbAlign) * UNITS; + REFERENCE_TIME tCurrent = tStart; + + REFERENCE_TIME tStop = m_tStop; + if (tStop > m_tDuration) { + tStop = m_tDuration; + } + + // align the stop position - may be past stop, but that + // doesn't matter + REFERENCE_TIME tAlignStop = AlignUp(tStop / UNITS, Actual.cbAlign) * UNITS; + + + DWORD dwRequest; + + if (!m_bSync) { + + // Break out of the loop either if we get to the end or we're asked + // to do something else + while (tCurrent < tAlignStop) { + + // Break out without calling EndOfStream if we're asked to + // do something different + if (CheckRequest(&dwRequest)) { + return; + } + + // queue a first sample + if (Actual.cBuffers > 1) { + + hr = QueueSample(tCurrent, tAlignStop, TRUE); + bDiscontinuity = FALSE; + + if (FAILED(hr)) { + return; + } + } + + + + // loop queueing second and waiting for first.. + while (tCurrent < tAlignStop) { + + hr = QueueSample(tCurrent, tAlignStop, bDiscontinuity); + bDiscontinuity = FALSE; + + if (FAILED(hr)) { + return; + } + + hr = CollectAndDeliver(tStart, tStop); + if (S_OK != hr) { + + // stop if error, or if downstream filter said + // to stop. + return; + } + } + + if (Actual.cBuffers > 1) { + hr = CollectAndDeliver(tStart, tStop); + if (FAILED(hr)) { + return; + } + } + } + } else { + + // sync version of above loop + while (tCurrent < tAlignStop) { + + // Break out without calling EndOfStream if we're asked to + // do something different + if (CheckRequest(&dwRequest)) { + return; + } + + IMediaSample* pSample; + + hr = m_pAlloc->GetBuffer(&pSample, NULL, NULL, 0); + if (FAILED(hr)) { + OnError(hr); + return; + } + + LONGLONG tStopThis = tCurrent + (pSample->GetSize() * UNITS); + if (tStopThis > tAlignStop) { + tStopThis = tAlignStop; + } + pSample->SetTime(&tCurrent, &tStopThis); + tCurrent = tStopThis; + + if (bDiscontinuity) { + pSample->SetDiscontinuity(TRUE); + bDiscontinuity = FALSE; + } + + hr = m_pReader->SyncReadAligned(pSample); + + if (FAILED(hr)) { + pSample->Release(); + OnError(hr); + return; + } + + hr = DeliverSample(pSample, tStart, tStop); + if (hr != S_OK) { + if (FAILED(hr)) { + OnError(hr); + } + return; + } + } + } + + EndOfStream(); +} + +// after a flush, cancelled i/o will be waiting for collection +// and release +void +CPullPin::CleanupCancelled(void) +{ + while (1) { + IMediaSample * pSample; + DWORD_PTR dwUnused; + + HRESULT hr = m_pReader->WaitForNext( + 0, // no wait + &pSample, + &dwUnused); + if(pSample) { + pSample->Release(); + } else { + // no more samples + return; + } + } +} diff --git a/plugins/GSdx/baseclasses/pullpin.h b/plugins/GSdx/baseclasses/pullpin.h index 254ffe248a..654670138c 100644 --- a/plugins/GSdx/baseclasses/pullpin.h +++ b/plugins/GSdx/baseclasses/pullpin.h @@ -1,152 +1,152 @@ -//------------------------------------------------------------------------------ -// File: PullPin.h -// -// Desc: DirectShow base classes - defines CPullPin class. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __PULLPIN_H__ -#define __PULLPIN_H__ - -// -// CPullPin -// -// object supporting pulling data from an IAsyncReader interface. -// Given a start/stop position, calls a pure Receive method with each -// IMediaSample received. -// -// This is essentially for use in a MemInputPin when it finds itself -// connected to an IAsyncReader pin instead of a pushing pin. -// - -class CPullPin : public CAMThread -{ - IAsyncReader* m_pReader; - REFERENCE_TIME m_tStart; - REFERENCE_TIME m_tStop; - REFERENCE_TIME m_tDuration; - BOOL m_bSync; - - enum ThreadMsg { - TM_Pause, // stop pulling and wait for next message - TM_Start, // start pulling - TM_Exit, // stop and exit - }; - - ThreadMsg m_State; - - // override pure thread proc from CAMThread - DWORD ThreadProc(void); - - // running pull method (check m_bSync) - void Process(void); - - // clean up any cancelled i/o after a flush - void CleanupCancelled(void); - - // suspend thread from pulling, eg during seek - HRESULT PauseThread(); - - // start thread pulling - create thread if necy - HRESULT StartThread(); - - // stop and close thread - HRESULT StopThread(); - - // called from ProcessAsync to queue and collect requests - HRESULT QueueSample( - REFERENCE_TIME& tCurrent, - REFERENCE_TIME tAlignStop, - BOOL bDiscontinuity); - - HRESULT CollectAndDeliver( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop); - - HRESULT DeliverSample( - IMediaSample* pSample, - REFERENCE_TIME tStart, - REFERENCE_TIME tStop); - -protected: - IMemAllocator * m_pAlloc; - -public: - CPullPin(); - virtual ~CPullPin(); - - // returns S_OK if successfully connected to an IAsyncReader interface - // from this object - // Optional allocator should be proposed as a preferred allocator if - // necessary - // bSync is TRUE if we are to use sync reads instead of the - // async methods. - HRESULT Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync); - - // disconnect any connection made in Connect - HRESULT Disconnect(); - - // agree an allocator using RequestAllocator - optional - // props param specifies your requirements (non-zero fields). - // returns an error code if fail to match requirements. - // optional IMemAllocator interface is offered as a preferred allocator - // but no error occurs if it can't be met. - virtual HRESULT DecideAllocator( - IMemAllocator* pAlloc, - ALLOCATOR_PROPERTIES * pProps); - - // set start and stop position. if active, will start immediately at - // the new position. Default is 0 to duration - HRESULT Seek(REFERENCE_TIME tStart, REFERENCE_TIME tStop); - - // return the total duration - HRESULT Duration(REFERENCE_TIME* ptDuration); - - // start pulling data - HRESULT Active(void); - - // stop pulling data - HRESULT Inactive(void); - - // helper functions - LONGLONG AlignDown(LONGLONG ll, LONG lAlign) { - // aligning downwards is just truncation - return ll & ~(lAlign-1); - }; - - LONGLONG AlignUp(LONGLONG ll, LONG lAlign) { - // align up: round up to next boundary - return (ll + (lAlign -1)) & ~(lAlign -1); - }; - - // GetReader returns the (addrefed) IAsyncReader interface - // for SyncRead etc - IAsyncReader* GetReader() { - m_pReader->AddRef(); - return m_pReader; - }; - - // -- pure -- - - // override this to handle data arrival - // return value other than S_OK will stop data - virtual HRESULT Receive(IMediaSample*) PURE; - - // override this to handle end-of-stream - virtual HRESULT EndOfStream(void) PURE; - - // called on runtime errors that will have caused pulling - // to stop - // these errors are all returned from the upstream filter, who - // will have already reported any errors to the filtergraph. - virtual void OnError(HRESULT hr) PURE; - - // flush this pin and all downstream - virtual HRESULT BeginFlush() PURE; - virtual HRESULT EndFlush() PURE; - -}; - -#endif //__PULLPIN_H__ +//------------------------------------------------------------------------------ +// File: PullPin.h +// +// Desc: DirectShow base classes - defines CPullPin class. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __PULLPIN_H__ +#define __PULLPIN_H__ + +// +// CPullPin +// +// object supporting pulling data from an IAsyncReader interface. +// Given a start/stop position, calls a pure Receive method with each +// IMediaSample received. +// +// This is essentially for use in a MemInputPin when it finds itself +// connected to an IAsyncReader pin instead of a pushing pin. +// + +class CPullPin : public CAMThread +{ + IAsyncReader* m_pReader; + REFERENCE_TIME m_tStart; + REFERENCE_TIME m_tStop; + REFERENCE_TIME m_tDuration; + BOOL m_bSync; + + enum ThreadMsg { + TM_Pause, // stop pulling and wait for next message + TM_Start, // start pulling + TM_Exit, // stop and exit + }; + + ThreadMsg m_State; + + // override pure thread proc from CAMThread + DWORD ThreadProc(void); + + // running pull method (check m_bSync) + void Process(void); + + // clean up any cancelled i/o after a flush + void CleanupCancelled(void); + + // suspend thread from pulling, eg during seek + HRESULT PauseThread(); + + // start thread pulling - create thread if necy + HRESULT StartThread(); + + // stop and close thread + HRESULT StopThread(); + + // called from ProcessAsync to queue and collect requests + HRESULT QueueSample( + REFERENCE_TIME& tCurrent, + REFERENCE_TIME tAlignStop, + BOOL bDiscontinuity); + + HRESULT CollectAndDeliver( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop); + + HRESULT DeliverSample( + IMediaSample* pSample, + REFERENCE_TIME tStart, + REFERENCE_TIME tStop); + +protected: + IMemAllocator * m_pAlloc; + +public: + CPullPin(); + virtual ~CPullPin(); + + // returns S_OK if successfully connected to an IAsyncReader interface + // from this object + // Optional allocator should be proposed as a preferred allocator if + // necessary + // bSync is TRUE if we are to use sync reads instead of the + // async methods. + HRESULT Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync); + + // disconnect any connection made in Connect + HRESULT Disconnect(); + + // agree an allocator using RequestAllocator - optional + // props param specifies your requirements (non-zero fields). + // returns an error code if fail to match requirements. + // optional IMemAllocator interface is offered as a preferred allocator + // but no error occurs if it can't be met. + virtual HRESULT DecideAllocator( + IMemAllocator* pAlloc, + ALLOCATOR_PROPERTIES * pProps); + + // set start and stop position. if active, will start immediately at + // the new position. Default is 0 to duration + HRESULT Seek(REFERENCE_TIME tStart, REFERENCE_TIME tStop); + + // return the total duration + HRESULT Duration(REFERENCE_TIME* ptDuration); + + // start pulling data + HRESULT Active(void); + + // stop pulling data + HRESULT Inactive(void); + + // helper functions + LONGLONG AlignDown(LONGLONG ll, LONG lAlign) { + // aligning downwards is just truncation + return ll & ~(lAlign-1); + }; + + LONGLONG AlignUp(LONGLONG ll, LONG lAlign) { + // align up: round up to next boundary + return (ll + (lAlign -1)) & ~(lAlign -1); + }; + + // GetReader returns the (addrefed) IAsyncReader interface + // for SyncRead etc + IAsyncReader* GetReader() { + m_pReader->AddRef(); + return m_pReader; + }; + + // -- pure -- + + // override this to handle data arrival + // return value other than S_OK will stop data + virtual HRESULT Receive(IMediaSample*) PURE; + + // override this to handle end-of-stream + virtual HRESULT EndOfStream(void) PURE; + + // called on runtime errors that will have caused pulling + // to stop + // these errors are all returned from the upstream filter, who + // will have already reported any errors to the filtergraph. + virtual void OnError(HRESULT hr) PURE; + + // flush this pin and all downstream + virtual HRESULT BeginFlush() PURE; + virtual HRESULT EndFlush() PURE; + +}; + +#endif //__PULLPIN_H__ diff --git a/plugins/GSdx/baseclasses/refclock.cpp b/plugins/GSdx/baseclasses/refclock.cpp index bd8cc13577..636351a806 100644 --- a/plugins/GSdx/baseclasses/refclock.cpp +++ b/plugins/GSdx/baseclasses/refclock.cpp @@ -1,340 +1,340 @@ -//------------------------------------------------------------------------------ -// File: RefClock.cpp -// -// Desc: DirectShow base classes - implements the IReferenceClock interface. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include - - - -// 'this' used in constructor list -#pragma warning(disable:4355) - - -STDMETHODIMP CBaseReferenceClock::NonDelegatingQueryInterface( - REFIID riid, - void ** ppv) -{ - HRESULT hr; - - if (riid == IID_IReferenceClock) - { - hr = GetInterface((IReferenceClock *) this, ppv); - } - else - { - hr = CUnknown::NonDelegatingQueryInterface(riid, ppv); - } - return hr; -} - -CBaseReferenceClock::~CBaseReferenceClock() -{ - - if (m_TimerResolution) timeEndPeriod(m_TimerResolution); - - m_pSchedule->DumpLinkedList(); - - if (m_hThread) - { - m_bAbort = TRUE; - TriggerThread(); - WaitForSingleObject( m_hThread, INFINITE ); - EXECUTE_ASSERT( CloseHandle(m_hThread) ); - m_hThread = 0; - EXECUTE_ASSERT( CloseHandle(m_pSchedule->GetEvent()) ); - delete m_pSchedule; - } -} - -// A derived class may supply a hThreadEvent if it has its own thread that will take care -// of calling the schedulers Advise method. (Refere to CBaseReferenceClock::AdviseThread() -// to see what such a thread has to do.) -CBaseReferenceClock::CBaseReferenceClock( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr, CAMSchedule * pShed ) -: CUnknown( pName, pUnk ) -, m_rtLastGotTime(0) -, m_TimerResolution(0) -, m_bAbort( FALSE ) -, m_pSchedule( pShed ? pShed : new CAMSchedule(CreateEvent(NULL, FALSE, FALSE, NULL)) ) -, m_hThread(0) -{ - - - ASSERT(m_pSchedule); - if (!m_pSchedule) - { - *phr = E_OUTOFMEMORY; - } - else - { - // Set up the highest resolution timer we can manage - TIMECAPS tc; - m_TimerResolution = (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(tc))) - ? tc.wPeriodMin - : 1; - - timeBeginPeriod(m_TimerResolution); - - /* Initialise our system times - the derived clock should set the right values */ - m_dwPrevSystemTime = timeGetTime(); - m_rtPrivateTime = (UNITS / MILLISECONDS) * m_dwPrevSystemTime; - - #ifdef PERF - m_idGetSystemTime = MSR_REGISTER(TEXT("CBaseReferenceClock::GetTime")); - #endif - - if ( !pShed ) - { - DWORD ThreadID; - m_hThread = ::CreateThread(NULL, // Security attributes - (DWORD) 0, // Initial stack size - AdviseThreadFunction, // Thread start address - (LPVOID) this, // Thread parameter - (DWORD) 0, // Creation flags - &ThreadID); // Thread identifier - - if (m_hThread) - { - SetThreadPriority( m_hThread, THREAD_PRIORITY_TIME_CRITICAL ); - } - else - { - *phr = E_FAIL; - EXECUTE_ASSERT( CloseHandle(m_pSchedule->GetEvent()) ); - delete m_pSchedule; - } - } - } -} - -void CBaseReferenceClock::Restart (IN REFERENCE_TIME rtMinTime) -{ - Lock(); - m_rtLastGotTime = rtMinTime ; - Unlock(); -} - -STDMETHODIMP CBaseReferenceClock::GetTime(REFERENCE_TIME *pTime) -{ - HRESULT hr; - if (pTime) - { - REFERENCE_TIME rtNow; - Lock(); - rtNow = GetPrivateTime(); - if (rtNow > m_rtLastGotTime) - { - m_rtLastGotTime = rtNow; - hr = S_OK; - } - else - { - hr = S_FALSE; - } - *pTime = m_rtLastGotTime; - Unlock(); - MSR_INTEGER(m_idGetSystemTime, LONG((*pTime) / (UNITS/MILLISECONDS)) ); - } - else hr = E_POINTER; - - return hr; -} - -/* Ask for an async notification that a time has elapsed */ - -STDMETHODIMP CBaseReferenceClock::AdviseTime( - REFERENCE_TIME baseTime, // base reference time - REFERENCE_TIME streamTime, // stream offset time - HEVENT hEvent, // advise via this event - DWORD_PTR *pdwAdviseCookie) // where your cookie goes -{ - CheckPointer(pdwAdviseCookie, E_POINTER); - *pdwAdviseCookie = 0; - - // Check that the event is not already set - ASSERT(WAIT_TIMEOUT == WaitForSingleObject(HANDLE(hEvent),0)); - - HRESULT hr; - - const REFERENCE_TIME lRefTime = baseTime + streamTime; - if ( lRefTime <= 0 || lRefTime == MAX_TIME ) - { - hr = E_INVALIDARG; - } - else - { - *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( lRefTime, 0, HANDLE(hEvent), FALSE ); - hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY; - } - return hr; -} - - -/* Ask for an asynchronous periodic notification that a time has elapsed */ - -STDMETHODIMP CBaseReferenceClock::AdvisePeriodic( - REFERENCE_TIME StartTime, // starting at this time - REFERENCE_TIME PeriodTime, // time between notifications - HSEMAPHORE hSemaphore, // advise via a semaphore - DWORD_PTR *pdwAdviseCookie) // where your cookie goes -{ - CheckPointer(pdwAdviseCookie, E_POINTER); - *pdwAdviseCookie = 0; - - HRESULT hr; - if (StartTime > 0 && PeriodTime > 0 && StartTime != MAX_TIME ) - { - *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( StartTime, PeriodTime, HANDLE(hSemaphore), TRUE ); - hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY; - } - else hr = E_INVALIDARG; - - return hr; -} - - -STDMETHODIMP CBaseReferenceClock::Unadvise(DWORD_PTR dwAdviseCookie) -{ - return m_pSchedule->Unadvise(dwAdviseCookie); -} - - -REFERENCE_TIME CBaseReferenceClock::GetPrivateTime() -{ - CAutoLock cObjectLock(this); - - - /* If the clock has wrapped then the current time will be less than - * the last time we were notified so add on the extra milliseconds - * - * The time period is long enough so that the likelihood of - * successive calls spanning the clock cycle is not considered. - */ - - DWORD dwTime = timeGetTime(); - { - m_rtPrivateTime += Int32x32To64(UNITS / MILLISECONDS, (DWORD)(dwTime - m_dwPrevSystemTime)); - m_dwPrevSystemTime = dwTime; - } - - return m_rtPrivateTime; -} - - -/* Adjust the current time by the input value. This allows an - external time source to work out some of the latency of the clock - system and adjust the "current" time accordingly. The intent is - that the time returned to the user is synchronised to a clock - source and allows drift to be catered for. - - For example: if the clock source detects a drift it can pass a delta - to the current time rather than having to set an explicit time. -*/ - -STDMETHODIMP CBaseReferenceClock::SetTimeDelta(const REFERENCE_TIME & TimeDelta) -{ -#ifdef DEBUG - - // Just break if passed an improper time delta value - LONGLONG llDelta = TimeDelta > 0 ? TimeDelta : -TimeDelta; - if (llDelta > UNITS * 1000) { - DbgLog((LOG_TRACE, 0, TEXT("Bad Time Delta"))); - //DebugBreak(); - } - - // We're going to calculate a "severity" for the time change. Max -1 - // min 8. We'll then use this as the debug logging level for a - // debug log message. - const LONG usDelta = LONG(TimeDelta/10); // Delta in micro-secs - - DWORD delta = abs(usDelta); // varying delta - // Severity == 8 - ceil(log(abs( micro-secs delta))) - int Severity = 8; - while ( delta > 0 ) - { - delta >>= 3; // div 8 - Severity--; - } - - // Sev == 0 => > 2 second delta! - DbgLog((LOG_TIMING, Severity < 0 ? 0 : Severity, - TEXT("Sev %2i: CSystemClock::SetTimeDelta(%8ld us) %lu -> %lu ms."), - Severity, usDelta, DWORD(ConvertToMilliseconds(m_rtPrivateTime)), - DWORD(ConvertToMilliseconds(TimeDelta+m_rtPrivateTime)) )); - - // Don't want the DbgBreak to fire when running stress on debug-builds. - #ifdef BREAK_ON_SEVERE_TIME_DELTA - if (Severity < 0) - DbgBreakPoint(TEXT("SetTimeDelta > 16 seconds!"), - TEXT(__FILE__),__LINE__); - #endif - -#endif - - CAutoLock cObjectLock(this); - m_rtPrivateTime += TimeDelta; - // If time goes forwards, and we have advises, then we need to - // trigger the thread so that it can re-evaluate its wait time. - // Since we don't want the cost of the thread switches if the change - // is really small, only do it if clock goes forward by more than - // 0.5 millisecond. If the time goes backwards, the thread will - // wake up "early" (relativly speaking) and will re-evaluate at - // that time. - if ( TimeDelta > 5000 && m_pSchedule->GetAdviseCount() > 0 ) TriggerThread(); - return NOERROR; -} - -// Thread stuff - -DWORD __stdcall CBaseReferenceClock::AdviseThreadFunction(LPVOID p) -{ - return DWORD(reinterpret_cast(p)->AdviseThread()); -} - -HRESULT CBaseReferenceClock::AdviseThread() -{ - DWORD dwWait = INFINITE; - - // The first thing we do is wait until something interesting happens - // (meaning a first advise or shutdown). This prevents us calling - // GetPrivateTime immediately which is goodness as that is a virtual - // routine and the derived class may not yet be constructed. (This - // thread is created in the base class constructor.) - - while ( !m_bAbort ) - { - // Wait for an interesting event to happen - DbgLog((LOG_TIMING, 3, TEXT("CBaseRefClock::AdviseThread() Delay: %lu ms"), dwWait )); - WaitForSingleObject(m_pSchedule->GetEvent(), dwWait); - if (m_bAbort) break; - - // There are several reasons why we need to work from the internal - // time, mainly to do with what happens when time goes backwards. - // Mainly, it stop us looping madly if an event is just about to - // expire when the clock goes backward (i.e. GetTime stop for a - // while). - const REFERENCE_TIME rtNow = GetPrivateTime(); - - DbgLog((LOG_TIMING, 3, - TEXT("CBaseRefClock::AdviseThread() Woke at = %lu ms"), - ConvertToMilliseconds(rtNow) )); - - // We must add in a millisecond, since this is the resolution of our - // WaitForSingleObject timer. Failure to do so will cause us to loop - // franticly for (approx) 1 a millisecond. - m_rtNextAdvise = m_pSchedule->Advise( 10000 + rtNow ); - LONGLONG llWait = m_rtNextAdvise - rtNow; - - ASSERT( llWait > 0 ); - - llWait = ConvertToMilliseconds(llWait); - // DON'T replace this with a max!! (The type's of these things is VERY important) - dwWait = (llWait > REFERENCE_TIME(UINT_MAX)) ? UINT_MAX : DWORD(llWait); - }; - return NOERROR; -} +//------------------------------------------------------------------------------ +// File: RefClock.cpp +// +// Desc: DirectShow base classes - implements the IReferenceClock interface. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include + + + +// 'this' used in constructor list +#pragma warning(disable:4355) + + +STDMETHODIMP CBaseReferenceClock::NonDelegatingQueryInterface( + REFIID riid, + void ** ppv) +{ + HRESULT hr; + + if (riid == IID_IReferenceClock) + { + hr = GetInterface((IReferenceClock *) this, ppv); + } + else + { + hr = CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + return hr; +} + +CBaseReferenceClock::~CBaseReferenceClock() +{ + + if (m_TimerResolution) timeEndPeriod(m_TimerResolution); + + m_pSchedule->DumpLinkedList(); + + if (m_hThread) + { + m_bAbort = TRUE; + TriggerThread(); + WaitForSingleObject( m_hThread, INFINITE ); + EXECUTE_ASSERT( CloseHandle(m_hThread) ); + m_hThread = 0; + EXECUTE_ASSERT( CloseHandle(m_pSchedule->GetEvent()) ); + delete m_pSchedule; + } +} + +// A derived class may supply a hThreadEvent if it has its own thread that will take care +// of calling the schedulers Advise method. (Refere to CBaseReferenceClock::AdviseThread() +// to see what such a thread has to do.) +CBaseReferenceClock::CBaseReferenceClock( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr, CAMSchedule * pShed ) +: CUnknown( pName, pUnk ) +, m_rtLastGotTime(0) +, m_TimerResolution(0) +, m_bAbort( FALSE ) +, m_pSchedule( pShed ? pShed : new CAMSchedule(CreateEvent(NULL, FALSE, FALSE, NULL)) ) +, m_hThread(0) +{ + + + ASSERT(m_pSchedule); + if (!m_pSchedule) + { + *phr = E_OUTOFMEMORY; + } + else + { + // Set up the highest resolution timer we can manage + TIMECAPS tc; + m_TimerResolution = (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(tc))) + ? tc.wPeriodMin + : 1; + + timeBeginPeriod(m_TimerResolution); + + /* Initialise our system times - the derived clock should set the right values */ + m_dwPrevSystemTime = timeGetTime(); + m_rtPrivateTime = (UNITS / MILLISECONDS) * m_dwPrevSystemTime; + + #ifdef PERF + m_idGetSystemTime = MSR_REGISTER(TEXT("CBaseReferenceClock::GetTime")); + #endif + + if ( !pShed ) + { + DWORD ThreadID; + m_hThread = ::CreateThread(NULL, // Security attributes + (DWORD) 0, // Initial stack size + AdviseThreadFunction, // Thread start address + (LPVOID) this, // Thread parameter + (DWORD) 0, // Creation flags + &ThreadID); // Thread identifier + + if (m_hThread) + { + SetThreadPriority( m_hThread, THREAD_PRIORITY_TIME_CRITICAL ); + } + else + { + *phr = E_FAIL; + EXECUTE_ASSERT( CloseHandle(m_pSchedule->GetEvent()) ); + delete m_pSchedule; + } + } + } +} + +void CBaseReferenceClock::Restart (IN REFERENCE_TIME rtMinTime) +{ + Lock(); + m_rtLastGotTime = rtMinTime ; + Unlock(); +} + +STDMETHODIMP CBaseReferenceClock::GetTime(REFERENCE_TIME *pTime) +{ + HRESULT hr; + if (pTime) + { + REFERENCE_TIME rtNow; + Lock(); + rtNow = GetPrivateTime(); + if (rtNow > m_rtLastGotTime) + { + m_rtLastGotTime = rtNow; + hr = S_OK; + } + else + { + hr = S_FALSE; + } + *pTime = m_rtLastGotTime; + Unlock(); + MSR_INTEGER(m_idGetSystemTime, LONG((*pTime) / (UNITS/MILLISECONDS)) ); + } + else hr = E_POINTER; + + return hr; +} + +/* Ask for an async notification that a time has elapsed */ + +STDMETHODIMP CBaseReferenceClock::AdviseTime( + REFERENCE_TIME baseTime, // base reference time + REFERENCE_TIME streamTime, // stream offset time + HEVENT hEvent, // advise via this event + DWORD_PTR *pdwAdviseCookie) // where your cookie goes +{ + CheckPointer(pdwAdviseCookie, E_POINTER); + *pdwAdviseCookie = 0; + + // Check that the event is not already set + ASSERT(WAIT_TIMEOUT == WaitForSingleObject(HANDLE(hEvent),0)); + + HRESULT hr; + + const REFERENCE_TIME lRefTime = baseTime + streamTime; + if ( lRefTime <= 0 || lRefTime == MAX_TIME ) + { + hr = E_INVALIDARG; + } + else + { + *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( lRefTime, 0, HANDLE(hEvent), FALSE ); + hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY; + } + return hr; +} + + +/* Ask for an asynchronous periodic notification that a time has elapsed */ + +STDMETHODIMP CBaseReferenceClock::AdvisePeriodic( + REFERENCE_TIME StartTime, // starting at this time + REFERENCE_TIME PeriodTime, // time between notifications + HSEMAPHORE hSemaphore, // advise via a semaphore + DWORD_PTR *pdwAdviseCookie) // where your cookie goes +{ + CheckPointer(pdwAdviseCookie, E_POINTER); + *pdwAdviseCookie = 0; + + HRESULT hr; + if (StartTime > 0 && PeriodTime > 0 && StartTime != MAX_TIME ) + { + *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( StartTime, PeriodTime, HANDLE(hSemaphore), TRUE ); + hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY; + } + else hr = E_INVALIDARG; + + return hr; +} + + +STDMETHODIMP CBaseReferenceClock::Unadvise(DWORD_PTR dwAdviseCookie) +{ + return m_pSchedule->Unadvise(dwAdviseCookie); +} + + +REFERENCE_TIME CBaseReferenceClock::GetPrivateTime() +{ + CAutoLock cObjectLock(this); + + + /* If the clock has wrapped then the current time will be less than + * the last time we were notified so add on the extra milliseconds + * + * The time period is long enough so that the likelihood of + * successive calls spanning the clock cycle is not considered. + */ + + DWORD dwTime = timeGetTime(); + { + m_rtPrivateTime += Int32x32To64(UNITS / MILLISECONDS, (DWORD)(dwTime - m_dwPrevSystemTime)); + m_dwPrevSystemTime = dwTime; + } + + return m_rtPrivateTime; +} + + +/* Adjust the current time by the input value. This allows an + external time source to work out some of the latency of the clock + system and adjust the "current" time accordingly. The intent is + that the time returned to the user is synchronised to a clock + source and allows drift to be catered for. + + For example: if the clock source detects a drift it can pass a delta + to the current time rather than having to set an explicit time. +*/ + +STDMETHODIMP CBaseReferenceClock::SetTimeDelta(const REFERENCE_TIME & TimeDelta) +{ +#ifdef DEBUG + + // Just break if passed an improper time delta value + LONGLONG llDelta = TimeDelta > 0 ? TimeDelta : -TimeDelta; + if (llDelta > UNITS * 1000) { + DbgLog((LOG_TRACE, 0, TEXT("Bad Time Delta"))); + //DebugBreak(); + } + + // We're going to calculate a "severity" for the time change. Max -1 + // min 8. We'll then use this as the debug logging level for a + // debug log message. + const LONG usDelta = LONG(TimeDelta/10); // Delta in micro-secs + + DWORD delta = abs(usDelta); // varying delta + // Severity == 8 - ceil(log(abs( micro-secs delta))) + int Severity = 8; + while ( delta > 0 ) + { + delta >>= 3; // div 8 + Severity--; + } + + // Sev == 0 => > 2 second delta! + DbgLog((LOG_TIMING, Severity < 0 ? 0 : Severity, + TEXT("Sev %2i: CSystemClock::SetTimeDelta(%8ld us) %lu -> %lu ms."), + Severity, usDelta, DWORD(ConvertToMilliseconds(m_rtPrivateTime)), + DWORD(ConvertToMilliseconds(TimeDelta+m_rtPrivateTime)) )); + + // Don't want the DbgBreak to fire when running stress on debug-builds. + #ifdef BREAK_ON_SEVERE_TIME_DELTA + if (Severity < 0) + DbgBreakPoint(TEXT("SetTimeDelta > 16 seconds!"), + TEXT(__FILE__),__LINE__); + #endif + +#endif + + CAutoLock cObjectLock(this); + m_rtPrivateTime += TimeDelta; + // If time goes forwards, and we have advises, then we need to + // trigger the thread so that it can re-evaluate its wait time. + // Since we don't want the cost of the thread switches if the change + // is really small, only do it if clock goes forward by more than + // 0.5 millisecond. If the time goes backwards, the thread will + // wake up "early" (relativly speaking) and will re-evaluate at + // that time. + if ( TimeDelta > 5000 && m_pSchedule->GetAdviseCount() > 0 ) TriggerThread(); + return NOERROR; +} + +// Thread stuff + +DWORD __stdcall CBaseReferenceClock::AdviseThreadFunction(LPVOID p) +{ + return DWORD(reinterpret_cast(p)->AdviseThread()); +} + +HRESULT CBaseReferenceClock::AdviseThread() +{ + DWORD dwWait = INFINITE; + + // The first thing we do is wait until something interesting happens + // (meaning a first advise or shutdown). This prevents us calling + // GetPrivateTime immediately which is goodness as that is a virtual + // routine and the derived class may not yet be constructed. (This + // thread is created in the base class constructor.) + + while ( !m_bAbort ) + { + // Wait for an interesting event to happen + DbgLog((LOG_TIMING, 3, TEXT("CBaseRefClock::AdviseThread() Delay: %lu ms"), dwWait )); + WaitForSingleObject(m_pSchedule->GetEvent(), dwWait); + if (m_bAbort) break; + + // There are several reasons why we need to work from the internal + // time, mainly to do with what happens when time goes backwards. + // Mainly, it stop us looping madly if an event is just about to + // expire when the clock goes backward (i.e. GetTime stop for a + // while). + const REFERENCE_TIME rtNow = GetPrivateTime(); + + DbgLog((LOG_TIMING, 3, + TEXT("CBaseRefClock::AdviseThread() Woke at = %lu ms"), + ConvertToMilliseconds(rtNow) )); + + // We must add in a millisecond, since this is the resolution of our + // WaitForSingleObject timer. Failure to do so will cause us to loop + // franticly for (approx) 1 a millisecond. + m_rtNextAdvise = m_pSchedule->Advise( 10000 + rtNow ); + LONGLONG llWait = m_rtNextAdvise - rtNow; + + ASSERT( llWait > 0 ); + + llWait = ConvertToMilliseconds(llWait); + // DON'T replace this with a max!! (The type's of these things is VERY important) + dwWait = (llWait > REFERENCE_TIME(UINT_MAX)) ? UINT_MAX : DWORD(llWait); + }; + return NOERROR; +} diff --git a/plugins/GSdx/baseclasses/refclock.h b/plugins/GSdx/baseclasses/refclock.h index a864f72b14..a47ae7b033 100644 --- a/plugins/GSdx/baseclasses/refclock.h +++ b/plugins/GSdx/baseclasses/refclock.h @@ -1,171 +1,171 @@ -//------------------------------------------------------------------------------ -// File: RefClock.h -// -// Desc: DirectShow base classes - defines the IReferenceClock interface. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __BASEREFCLOCK__ -#define __BASEREFCLOCK__ - -#include "dsschedule.h" - -const UINT RESOLUTION = 1; /* High resolution timer */ -const INT ADVISE_CACHE = 4; /* Default cache size */ -const LONGLONG MAX_TIME = 0x7FFFFFFFFFFFFFFF; /* Maximum LONGLONG value */ - -inline LONGLONG WINAPI ConvertToMilliseconds(const REFERENCE_TIME& RT) -{ - /* This converts an arbitrary value representing a reference time - into a MILLISECONDS value for use in subsequent system calls */ - - return (RT / (UNITS / MILLISECONDS)); -} - -/* This class hierarchy will support an IReferenceClock interface so - that an audio card (or other externally driven clock) can update the - system wide clock that everyone uses. - - The interface will be pretty thin with probably just one update method - This interface has not yet been defined. - */ - -/* This abstract base class implements the IReferenceClock - * interface. Classes that actually provide clock signals (from - * whatever source) have to be derived from this class. - * - * The abstract class provides implementations for: - * CUnknown support - * locking support (CCritSec) - * client advise code (creates a thread) - * - * Question: what can we do about quality? Change the timer - * resolution to lower the system load? Up the priority of the - * timer thread to force more responsive signals? - * - * During class construction we create a worker thread that is destroyed during - * destuction. This thread executes a series of WaitForSingleObject calls, - * waking up when a command is given to the thread or the next wake up point - * is reached. The wakeup points are determined by clients making Advise - * calls. - * - * Each advise call defines a point in time when they wish to be notified. A - * periodic advise is a series of these such events. We maintain a list of - * advise links and calculate when the nearest event notification is due for. - * We then call WaitForSingleObject with a timeout equal to this time. The - * handle we wait on is used by the class to signal that something has changed - * and that we must reschedule the next event. This typically happens when - * someone comes in and asks for an advise link while we are waiting for an - * event to timeout. - * - * While we are modifying the list of advise requests we - * are protected from interference through a critical section. Clients are NOT - * advised through callbacks. One shot clients have an event set, while - * periodic clients have a semaphore released for each event notification. A - * semaphore allows a client to be kept up to date with the number of events - * actually triggered and be assured that they can't miss multiple events being - * set. - * - * Keeping track of advises is taken care of by the CAMSchedule class. - */ - -class CBaseReferenceClock -: public CUnknown, public IReferenceClock, public CCritSec -{ -protected: - virtual ~CBaseReferenceClock(); // Don't let me be created on the stack! -public: - CBaseReferenceClock(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr, CAMSchedule * pSched = 0 ); - - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void ** ppv); - - DECLARE_IUNKNOWN - - /* IReferenceClock methods */ - // Derived classes must implement GetPrivateTime(). All our GetTime - // does is call GetPrivateTime and then check so that time does not - // go backwards. A return code of S_FALSE implies that the internal - // clock has gone backwards and GetTime time has halted until internal - // time has caught up. (Don't know if this will be much use to folk, - // but it seems odd not to use the return code for something useful.) - STDMETHODIMP GetTime(REFERENCE_TIME *pTime); - // When this is called, it sets m_rtLastGotTime to the time it returns. - - /* Provide standard mechanisms for scheduling events */ - - /* Ask for an async notification that a time has elapsed */ - STDMETHODIMP AdviseTime( - REFERENCE_TIME baseTime, // base reference time - REFERENCE_TIME streamTime, // stream offset time - HEVENT hEvent, // advise via this event - DWORD_PTR *pdwAdviseCookie // where your cookie goes - ); - - /* Ask for an asynchronous periodic notification that a time has elapsed */ - STDMETHODIMP AdvisePeriodic( - REFERENCE_TIME StartTime, // starting at this time - REFERENCE_TIME PeriodTime, // time between notifications - HSEMAPHORE hSemaphore, // advise via a semaphore - DWORD_PTR *pdwAdviseCookie // where your cookie goes - ); - - /* Cancel a request for notification(s) - if the notification was - * a one shot timer then this function doesn't need to be called - * as the advise is automatically cancelled, however it does no - * harm to explicitly cancel a one-shot advise. It is REQUIRED that - * clients call Unadvise to clear a Periodic advise setting. - */ - - STDMETHODIMP Unadvise(DWORD_PTR dwAdviseCookie); - - /* Methods for the benefit of derived classes or outer objects */ - - // GetPrivateTime() is the REAL clock. GetTime is just a cover for - // it. Derived classes will probably override this method but not - // GetTime() itself. - // The important point about GetPrivateTime() is it's allowed to go - // backwards. Our GetTime() will keep returning the LastGotTime - // until GetPrivateTime() catches up. - virtual REFERENCE_TIME GetPrivateTime(); - - /* Provide a method for correcting drift */ - STDMETHODIMP SetTimeDelta( const REFERENCE_TIME& TimeDelta ); - - CAMSchedule * GetSchedule() const { return m_pSchedule; } - -private: - REFERENCE_TIME m_rtPrivateTime; // Current best estimate of time - DWORD m_dwPrevSystemTime; // Last vaule we got from timeGetTime - REFERENCE_TIME m_rtLastGotTime; // Last time returned by GetTime - REFERENCE_TIME m_rtNextAdvise; // Time of next advise - UINT m_TimerResolution; - -#ifdef PERF - int m_idGetSystemTime; -#endif - -// Thread stuff -public: - void TriggerThread() // Wakes thread up. Need to do this if - { // time to next advise needs reevaluating. - EXECUTE_ASSERT(SetEvent(m_pSchedule->GetEvent())); - } - - -private: - BOOL m_bAbort; // Flag used for thread shutdown - HANDLE m_hThread; // Thread handle - - HRESULT AdviseThread(); // Method in which the advise thread runs - static DWORD __stdcall AdviseThreadFunction(LPVOID); // Function used to get there - -protected: - CAMSchedule * const m_pSchedule; - - void Restart (IN REFERENCE_TIME rtMinTime = 0I64) ; -}; - -#endif - +//------------------------------------------------------------------------------ +// File: RefClock.h +// +// Desc: DirectShow base classes - defines the IReferenceClock interface. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __BASEREFCLOCK__ +#define __BASEREFCLOCK__ + +#include "dsschedule.h" + +const UINT RESOLUTION = 1; /* High resolution timer */ +const INT ADVISE_CACHE = 4; /* Default cache size */ +const LONGLONG MAX_TIME = 0x7FFFFFFFFFFFFFFF; /* Maximum LONGLONG value */ + +inline LONGLONG WINAPI ConvertToMilliseconds(const REFERENCE_TIME& RT) +{ + /* This converts an arbitrary value representing a reference time + into a MILLISECONDS value for use in subsequent system calls */ + + return (RT / (UNITS / MILLISECONDS)); +} + +/* This class hierarchy will support an IReferenceClock interface so + that an audio card (or other externally driven clock) can update the + system wide clock that everyone uses. + + The interface will be pretty thin with probably just one update method + This interface has not yet been defined. + */ + +/* This abstract base class implements the IReferenceClock + * interface. Classes that actually provide clock signals (from + * whatever source) have to be derived from this class. + * + * The abstract class provides implementations for: + * CUnknown support + * locking support (CCritSec) + * client advise code (creates a thread) + * + * Question: what can we do about quality? Change the timer + * resolution to lower the system load? Up the priority of the + * timer thread to force more responsive signals? + * + * During class construction we create a worker thread that is destroyed during + * destuction. This thread executes a series of WaitForSingleObject calls, + * waking up when a command is given to the thread or the next wake up point + * is reached. The wakeup points are determined by clients making Advise + * calls. + * + * Each advise call defines a point in time when they wish to be notified. A + * periodic advise is a series of these such events. We maintain a list of + * advise links and calculate when the nearest event notification is due for. + * We then call WaitForSingleObject with a timeout equal to this time. The + * handle we wait on is used by the class to signal that something has changed + * and that we must reschedule the next event. This typically happens when + * someone comes in and asks for an advise link while we are waiting for an + * event to timeout. + * + * While we are modifying the list of advise requests we + * are protected from interference through a critical section. Clients are NOT + * advised through callbacks. One shot clients have an event set, while + * periodic clients have a semaphore released for each event notification. A + * semaphore allows a client to be kept up to date with the number of events + * actually triggered and be assured that they can't miss multiple events being + * set. + * + * Keeping track of advises is taken care of by the CAMSchedule class. + */ + +class CBaseReferenceClock +: public CUnknown, public IReferenceClock, public CCritSec +{ +protected: + virtual ~CBaseReferenceClock(); // Don't let me be created on the stack! +public: + CBaseReferenceClock(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr, CAMSchedule * pSched = 0 ); + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void ** ppv); + + DECLARE_IUNKNOWN + + /* IReferenceClock methods */ + // Derived classes must implement GetPrivateTime(). All our GetTime + // does is call GetPrivateTime and then check so that time does not + // go backwards. A return code of S_FALSE implies that the internal + // clock has gone backwards and GetTime time has halted until internal + // time has caught up. (Don't know if this will be much use to folk, + // but it seems odd not to use the return code for something useful.) + STDMETHODIMP GetTime(REFERENCE_TIME *pTime); + // When this is called, it sets m_rtLastGotTime to the time it returns. + + /* Provide standard mechanisms for scheduling events */ + + /* Ask for an async notification that a time has elapsed */ + STDMETHODIMP AdviseTime( + REFERENCE_TIME baseTime, // base reference time + REFERENCE_TIME streamTime, // stream offset time + HEVENT hEvent, // advise via this event + DWORD_PTR *pdwAdviseCookie // where your cookie goes + ); + + /* Ask for an asynchronous periodic notification that a time has elapsed */ + STDMETHODIMP AdvisePeriodic( + REFERENCE_TIME StartTime, // starting at this time + REFERENCE_TIME PeriodTime, // time between notifications + HSEMAPHORE hSemaphore, // advise via a semaphore + DWORD_PTR *pdwAdviseCookie // where your cookie goes + ); + + /* Cancel a request for notification(s) - if the notification was + * a one shot timer then this function doesn't need to be called + * as the advise is automatically cancelled, however it does no + * harm to explicitly cancel a one-shot advise. It is REQUIRED that + * clients call Unadvise to clear a Periodic advise setting. + */ + + STDMETHODIMP Unadvise(DWORD_PTR dwAdviseCookie); + + /* Methods for the benefit of derived classes or outer objects */ + + // GetPrivateTime() is the REAL clock. GetTime is just a cover for + // it. Derived classes will probably override this method but not + // GetTime() itself. + // The important point about GetPrivateTime() is it's allowed to go + // backwards. Our GetTime() will keep returning the LastGotTime + // until GetPrivateTime() catches up. + virtual REFERENCE_TIME GetPrivateTime(); + + /* Provide a method for correcting drift */ + STDMETHODIMP SetTimeDelta( const REFERENCE_TIME& TimeDelta ); + + CAMSchedule * GetSchedule() const { return m_pSchedule; } + +private: + REFERENCE_TIME m_rtPrivateTime; // Current best estimate of time + DWORD m_dwPrevSystemTime; // Last vaule we got from timeGetTime + REFERENCE_TIME m_rtLastGotTime; // Last time returned by GetTime + REFERENCE_TIME m_rtNextAdvise; // Time of next advise + UINT m_TimerResolution; + +#ifdef PERF + int m_idGetSystemTime; +#endif + +// Thread stuff +public: + void TriggerThread() // Wakes thread up. Need to do this if + { // time to next advise needs reevaluating. + EXECUTE_ASSERT(SetEvent(m_pSchedule->GetEvent())); + } + + +private: + BOOL m_bAbort; // Flag used for thread shutdown + HANDLE m_hThread; // Thread handle + + HRESULT AdviseThread(); // Method in which the advise thread runs + static DWORD __stdcall AdviseThreadFunction(LPVOID); // Function used to get there + +protected: + CAMSchedule * const m_pSchedule; + + void Restart (IN REFERENCE_TIME rtMinTime = 0I64) ; +}; + +#endif + diff --git a/plugins/GSdx/baseclasses/reftime.h b/plugins/GSdx/baseclasses/reftime.h index 87c43b9fef..2cf70df998 100644 --- a/plugins/GSdx/baseclasses/reftime.h +++ b/plugins/GSdx/baseclasses/reftime.h @@ -1,116 +1,116 @@ -//------------------------------------------------------------------------------ -// File: RefTime.h -// -// Desc: DirectShow base classes - defines CRefTime, a class that manages -// reference times. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// -// CRefTime -// -// Manage reference times. -// Shares same data layout as REFERENCE_TIME, but adds some (nonvirtual) -// functions providing simple comparison, conversion and arithmetic. -// -// A reference time (at the moment) is a unit of seconds represented in -// 100ns units as is used in the Win32 FILETIME structure. BUT the time -// a REFERENCE_TIME represents is NOT the time elapsed since 1/1/1601 it -// will either be stream time or reference time depending upon context -// -// This class provides simple arithmetic operations on reference times -// -// keep non-virtual otherwise the data layout will not be the same as -// REFERENCE_TIME - - -// ----- -// note that you are safe to cast a CRefTime* to a REFERENCE_TIME*, but -// you will need to do so explicitly -// ----- - - -#ifndef __REFTIME__ -#define __REFTIME__ - - -const LONGLONG MILLISECONDS = (1000); // 10 ^ 3 -const LONGLONG NANOSECONDS = (1000000000); // 10 ^ 9 -const LONGLONG UNITS = (NANOSECONDS / 100); // 10 ^ 7 - -/* Unfortunately an inline function here generates a call to __allmul - - even for constants! -*/ -#define MILLISECONDS_TO_100NS_UNITS(lMs) \ - Int32x32To64((lMs), (UNITS / MILLISECONDS)) - -class CRefTime -{ -public: - - // *MUST* be the only data member so that this class is exactly - // equivalent to a REFERENCE_TIME. - // Also, must be *no virtual functions* - - REFERENCE_TIME m_time; - - inline CRefTime() - { - // default to 0 time - m_time = 0; - }; - - inline CRefTime(LONG msecs) - { - m_time = MILLISECONDS_TO_100NS_UNITS(msecs); - }; - - inline CRefTime(REFERENCE_TIME rt) - { - m_time = rt; - }; - - inline operator REFERENCE_TIME() const - { - return m_time; - }; - - inline CRefTime& operator=(const CRefTime& rt) - { - m_time = rt.m_time; - return *this; - }; - - inline CRefTime& operator=(const LONGLONG ll) - { - m_time = ll; - return *this; - }; - - inline CRefTime& operator+=(const CRefTime& rt) - { - return (*this = *this + rt); - }; - - inline CRefTime& operator-=(const CRefTime& rt) - { - return (*this = *this - rt); - }; - - inline LONG Millisecs(void) - { - return (LONG)(m_time / (UNITS / MILLISECONDS)); - }; - - inline LONGLONG GetUnits(void) - { - return m_time; - }; -}; - -const LONGLONG TimeZero = 0; - -#endif /* __REFTIME__ */ - +//------------------------------------------------------------------------------ +// File: RefTime.h +// +// Desc: DirectShow base classes - defines CRefTime, a class that manages +// reference times. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// +// CRefTime +// +// Manage reference times. +// Shares same data layout as REFERENCE_TIME, but adds some (nonvirtual) +// functions providing simple comparison, conversion and arithmetic. +// +// A reference time (at the moment) is a unit of seconds represented in +// 100ns units as is used in the Win32 FILETIME structure. BUT the time +// a REFERENCE_TIME represents is NOT the time elapsed since 1/1/1601 it +// will either be stream time or reference time depending upon context +// +// This class provides simple arithmetic operations on reference times +// +// keep non-virtual otherwise the data layout will not be the same as +// REFERENCE_TIME + + +// ----- +// note that you are safe to cast a CRefTime* to a REFERENCE_TIME*, but +// you will need to do so explicitly +// ----- + + +#ifndef __REFTIME__ +#define __REFTIME__ + + +const LONGLONG MILLISECONDS = (1000); // 10 ^ 3 +const LONGLONG NANOSECONDS = (1000000000); // 10 ^ 9 +const LONGLONG UNITS = (NANOSECONDS / 100); // 10 ^ 7 + +/* Unfortunately an inline function here generates a call to __allmul + - even for constants! +*/ +#define MILLISECONDS_TO_100NS_UNITS(lMs) \ + Int32x32To64((lMs), (UNITS / MILLISECONDS)) + +class CRefTime +{ +public: + + // *MUST* be the only data member so that this class is exactly + // equivalent to a REFERENCE_TIME. + // Also, must be *no virtual functions* + + REFERENCE_TIME m_time; + + inline CRefTime() + { + // default to 0 time + m_time = 0; + }; + + inline CRefTime(LONG msecs) + { + m_time = MILLISECONDS_TO_100NS_UNITS(msecs); + }; + + inline CRefTime(REFERENCE_TIME rt) + { + m_time = rt; + }; + + inline operator REFERENCE_TIME() const + { + return m_time; + }; + + inline CRefTime& operator=(const CRefTime& rt) + { + m_time = rt.m_time; + return *this; + }; + + inline CRefTime& operator=(const LONGLONG ll) + { + m_time = ll; + return *this; + }; + + inline CRefTime& operator+=(const CRefTime& rt) + { + return (*this = *this + rt); + }; + + inline CRefTime& operator-=(const CRefTime& rt) + { + return (*this = *this - rt); + }; + + inline LONG Millisecs(void) + { + return (LONG)(m_time / (UNITS / MILLISECONDS)); + }; + + inline LONGLONG GetUnits(void) + { + return m_time; + }; +}; + +const LONGLONG TimeZero = 0; + +#endif /* __REFTIME__ */ + diff --git a/plugins/GSdx/baseclasses/renbase.cpp b/plugins/GSdx/baseclasses/renbase.cpp index 633f26aadb..c725629dfe 100644 --- a/plugins/GSdx/baseclasses/renbase.cpp +++ b/plugins/GSdx/baseclasses/renbase.cpp @@ -1,2844 +1,2844 @@ -//------------------------------------------------------------------------------ -// File: RenBase.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" // DirectShow base class definitions -#include // Needed for definition of timeGetTime -#include // Standard data type limit definitions -#include "measure.h" // Used for time critical log functions - -#pragma warning(disable:4355) - -// Helper function for clamping time differences -int inline TimeDiff(REFERENCE_TIME rt) -{ - if (rt < - (50 * UNITS)) { - return -(50 * UNITS); - } else - if (rt > 50 * UNITS) { - return 50 * UNITS; - } else return (int)rt; -} - -// Implements the CBaseRenderer class - -CBaseRenderer::CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer - TCHAR *pName, // Debug ONLY description - LPUNKNOWN pUnk, // Aggregated owner object - HRESULT *phr) : // General OLE return code - - CBaseFilter(pName,pUnk,&m_InterfaceLock,RenderClass), - m_evComplete(TRUE), - m_bAbort(FALSE), - m_pPosition(NULL), - m_ThreadSignal(TRUE), - m_bStreaming(FALSE), - m_bEOS(FALSE), - m_bEOSDelivered(FALSE), - m_pMediaSample(NULL), - m_dwAdvise(0), - m_pQSink(NULL), - m_pInputPin(NULL), - m_bRepaintStatus(TRUE), - m_SignalTime(0), - m_bInReceive(FALSE), - m_EndOfStreamTimer(0) -{ - Ready(); -#ifdef PERF - m_idBaseStamp = MSR_REGISTER(TEXT("BaseRenderer: sample time stamp")); - m_idBaseRenderTime = MSR_REGISTER(TEXT("BaseRenderer: draw time (msec)")); - m_idBaseAccuracy = MSR_REGISTER(TEXT("BaseRenderer: Accuracy (msec)")); -#endif -} - - -// Delete the dynamically allocated IMediaPosition and IMediaSeeking helper -// object. The object is created when somebody queries us. These are standard -// control interfaces for seeking and setting start/stop positions and rates. -// We will probably also have made an input pin based on CRendererInputPin -// that has to be deleted, it's created when an enumerator calls our GetPin - -CBaseRenderer::~CBaseRenderer() -{ - ASSERT(m_bStreaming == FALSE); - ASSERT(m_EndOfStreamTimer == 0); - StopStreaming(); - ClearPendingSample(); - - // Delete any IMediaPosition implementation - - if (m_pPosition) { - delete m_pPosition; - m_pPosition = NULL; - } - - // Delete any input pin created - - if (m_pInputPin) { - delete m_pInputPin; - m_pInputPin = NULL; - } - - // Release any Quality sink - - ASSERT(m_pQSink == NULL); -} - - -// This returns the IMediaPosition and IMediaSeeking interfaces - -HRESULT CBaseRenderer::GetMediaPositionInterface(REFIID riid,void **ppv) -{ - CAutoLock cObjectCreationLock(&m_ObjectCreationLock); - if (m_pPosition) { - return m_pPosition->NonDelegatingQueryInterface(riid,ppv); - } - - HRESULT hr = NOERROR; - - // Create implementation of this dynamically since sometimes we may - // never try and do a seek. The helper object implements a position - // control interface (IMediaPosition) which in fact simply takes the - // calls normally from the filter graph and passes them upstream - - m_pPosition = new CRendererPosPassThru(NAME("Renderer CPosPassThru"), - CBaseFilter::GetOwner(), - (HRESULT *) &hr, - GetPin(0)); - if (m_pPosition == NULL) { - return E_OUTOFMEMORY; - } - - if (FAILED(hr)) { - delete m_pPosition; - m_pPosition = NULL; - return E_NOINTERFACE; - } - return GetMediaPositionInterface(riid,ppv); -} - - -// Overriden to say what interfaces we support and where - -STDMETHODIMP CBaseRenderer::NonDelegatingQueryInterface(REFIID riid,void **ppv) -{ - // Do we have this interface - - if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { - return GetMediaPositionInterface(riid,ppv); - } else { - return CBaseFilter::NonDelegatingQueryInterface(riid,ppv); - } -} - - -// This is called whenever we change states, we have a manual reset event that -// is signalled whenever we don't won't the source filter thread to wait in us -// (such as in a stopped state) and likewise is not signalled whenever it can -// wait (during paused and running) this function sets or resets the thread -// event. The event is used to stop source filter threads waiting in Receive - -HRESULT CBaseRenderer::SourceThreadCanWait(BOOL bCanWait) -{ - if (bCanWait == TRUE) { - m_ThreadSignal.Reset(); - } else { - m_ThreadSignal.Set(); - } - return NOERROR; -} - - -#ifdef DEBUG -// Dump the current renderer state to the debug terminal. The hardest part of -// the renderer is the window where we unlock everything to wait for a clock -// to signal it is time to draw or for the application to cancel everything -// by stopping the filter. If we get things wrong we can leave the thread in -// WaitForRenderTime with no way for it to ever get out and we will deadlock - -void CBaseRenderer::DisplayRendererState() -{ - DbgLog((LOG_TIMING, 1, TEXT("\nTimed out in WaitForRenderTime"))); - - // No way should this be signalled at this point - - BOOL bSignalled = m_ThreadSignal.Check(); - DbgLog((LOG_TIMING, 1, TEXT("Signal sanity check %d"),bSignalled)); - - // Now output the current renderer state variables - - DbgLog((LOG_TIMING, 1, TEXT("Filter state %d"),m_State)); - - DbgLog((LOG_TIMING, 1, TEXT("Abort flag %d"),m_bAbort)); - - DbgLog((LOG_TIMING, 1, TEXT("Streaming flag %d"),m_bStreaming)); - - DbgLog((LOG_TIMING, 1, TEXT("Clock advise link %d"),m_dwAdvise)); - - DbgLog((LOG_TIMING, 1, TEXT("Current media sample %x"),m_pMediaSample)); - - DbgLog((LOG_TIMING, 1, TEXT("EOS signalled %d"),m_bEOS)); - - DbgLog((LOG_TIMING, 1, TEXT("EOS delivered %d"),m_bEOSDelivered)); - - DbgLog((LOG_TIMING, 1, TEXT("Repaint status %d"),m_bRepaintStatus)); - - - // Output the delayed end of stream timer information - - DbgLog((LOG_TIMING, 1, TEXT("End of stream timer %x"),m_EndOfStreamTimer)); - - DbgLog((LOG_TIMING, 1, TEXT("Deliver time %s"),CDisp((LONGLONG)m_SignalTime))); - - - // Should never timeout during a flushing state - - BOOL bFlushing = m_pInputPin->IsFlushing(); - DbgLog((LOG_TIMING, 1, TEXT("Flushing sanity check %d"),bFlushing)); - - // Display the time we were told to start at - DbgLog((LOG_TIMING, 1, TEXT("Last run time %s"),CDisp((LONGLONG)m_tStart.m_time))); - - // Have we got a reference clock - if (m_pClock == NULL) return; - - // Get the current time from the wall clock - - CRefTime CurrentTime,StartTime,EndTime; - m_pClock->GetTime((REFERENCE_TIME*) &CurrentTime); - CRefTime Offset = CurrentTime - m_tStart; - - // Display the current time from the clock - - DbgLog((LOG_TIMING, 1, TEXT("Clock time %s"),CDisp((LONGLONG)CurrentTime.m_time))); - - DbgLog((LOG_TIMING, 1, TEXT("Time difference %dms"),Offset.Millisecs())); - - - // Do we have a sample ready to render - if (m_pMediaSample == NULL) return; - - m_pMediaSample->GetTime((REFERENCE_TIME*)&StartTime, (REFERENCE_TIME*)&EndTime); - DbgLog((LOG_TIMING, 1, TEXT("Next sample stream times (Start %d End %d ms)"), - StartTime.Millisecs(),EndTime.Millisecs())); - - // Calculate how long it is until it is due for rendering - CRefTime Wait = (m_tStart + StartTime) - CurrentTime; - DbgLog((LOG_TIMING, 1, TEXT("Wait required %d ms"),Wait.Millisecs())); -} -#endif - - -// Wait until the clock sets the timer event or we're otherwise signalled. We -// set an arbitrary timeout for this wait and if it fires then we display the -// current renderer state on the debugger. It will often fire if the filter's -// left paused in an application however it may also fire during stress tests -// if the synchronisation with application seeks and state changes is faulty - -#define RENDER_TIMEOUT 10000 - -HRESULT CBaseRenderer::WaitForRenderTime() -{ - HANDLE WaitObjects[] = { m_ThreadSignal, m_RenderEvent }; - DWORD Result = WAIT_TIMEOUT; - - // Wait for either the time to arrive or for us to be stopped - - OnWaitStart(); - while (Result == WAIT_TIMEOUT) { - Result = WaitForMultipleObjects(2,WaitObjects,FALSE,RENDER_TIMEOUT); - -#ifdef DEBUG - if (Result == WAIT_TIMEOUT) DisplayRendererState(); -#endif - - } - OnWaitEnd(); - - // We may have been awoken without the timer firing - - if (Result == WAIT_OBJECT_0) { - return VFW_E_STATE_CHANGED; - } - - SignalTimerFired(); - return NOERROR; -} - - -// Poll waiting for Receive to complete. This really matters when -// Receive may set the palette and cause window messages -// The problem is that if we don't really wait for a renderer to -// stop processing we can deadlock waiting for a transform which -// is calling the renderer's Receive() method because the transform's -// Stop method doesn't know to process window messages to unblock -// the renderer's Receive processing -void CBaseRenderer::WaitForReceiveToComplete() -{ - for (;;) { - if (!m_bInReceive) { - break; - } - - MSG msg; - // Receive all interthread sendmessages - PeekMessage(&msg, NULL, WM_NULL, WM_NULL, PM_NOREMOVE); - - Sleep(1); - } - - // If the wakebit for QS_POSTMESSAGE is set, the PeekMessage call - // above just cleared the changebit which will cause some messaging - // calls to block (waitMessage, MsgWaitFor...) now. - // Post a dummy message to set the QS_POSTMESSAGE bit again - if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) { - // Send dummy message - PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0); - } -} - -// A filter can have four discrete states, namely Stopped, Running, Paused, -// Intermediate. We are in an intermediate state if we are currently trying -// to pause but haven't yet got the first sample (or if we have been flushed -// in paused state and therefore still have to wait for a sample to arrive) - -// This class contains an event called m_evComplete which is signalled when -// the current state is completed and is not signalled when we are waiting to -// complete the last state transition. As mentioned above the only time we -// use this at the moment is when we wait for a media sample in paused state -// If while we are waiting we receive an end of stream notification from the -// source filter then we know no data is imminent so we can reset the event -// This means that when we transition to paused the source filter must call -// end of stream on us or send us an image otherwise we'll hang indefinately - - -// Simple internal way of getting the real state - -FILTER_STATE CBaseRenderer::GetRealState() { - return m_State; -} - - -// The renderer doesn't complete the full transition to paused states until -// it has got one media sample to render. If you ask it for its state while -// it's waiting it will return the state along with VFW_S_STATE_INTERMEDIATE - -STDMETHODIMP CBaseRenderer::GetState(DWORD dwMSecs,FILTER_STATE *State) -{ - CheckPointer(State,E_POINTER); - - if (WaitDispatchingMessages(m_evComplete, dwMSecs) == WAIT_TIMEOUT) { - *State = m_State; - return VFW_S_STATE_INTERMEDIATE; - } - *State = m_State; - return NOERROR; -} - - -// If we're pausing and we have no samples we don't complete the transition -// to State_Paused and we return S_FALSE. However if the m_bAbort flag has -// been set then all samples are rejected so there is no point waiting for -// one. If we do have a sample then return NOERROR. We will only ever return -// VFW_S_STATE_INTERMEDIATE from GetState after being paused with no sample -// (calling GetState after either being stopped or Run will NOT return this) - -HRESULT CBaseRenderer::CompleteStateChange(FILTER_STATE OldState) -{ - // Allow us to be paused when disconnected - - if (m_pInputPin->IsConnected() == FALSE) { - Ready(); - return S_OK; - } - - // Have we run off the end of stream - - if (IsEndOfStream() == TRUE) { - Ready(); - return S_OK; - } - - // Make sure we get fresh data after being stopped - - if (HaveCurrentSample() == TRUE) { - if (OldState != State_Stopped) { - Ready(); - return S_OK; - } - } - NotReady(); - return S_FALSE; -} - - -// When we stop the filter the things we do are:- - -// Decommit the allocator being used in the connection -// Release the source filter if it's waiting in Receive -// Cancel any advise link we set up with the clock -// Any end of stream signalled is now obsolete so reset -// Allow us to be stopped when we are not connected - -STDMETHODIMP CBaseRenderer::Stop() -{ - CAutoLock cRendererLock(&m_InterfaceLock); - - // Make sure there really is a state change - - if (m_State == State_Stopped) { - return NOERROR; - } - - // Is our input pin connected - - if (m_pInputPin->IsConnected() == FALSE) { - NOTE("Input pin is not connected"); - m_State = State_Stopped; - return NOERROR; - } - - CBaseFilter::Stop(); - - // If we are going into a stopped state then we must decommit whatever - // allocator we are using it so that any source filter waiting in the - // GetBuffer can be released and unlock themselves for a state change - - if (m_pInputPin->Allocator()) { - m_pInputPin->Allocator()->Decommit(); - } - - // Cancel any scheduled rendering - - SetRepaintStatus(TRUE); - StopStreaming(); - SourceThreadCanWait(FALSE); - ResetEndOfStream(); - CancelNotification(); - - // There should be no outstanding clock advise - ASSERT(CancelNotification() == S_FALSE); - ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); - ASSERT(m_EndOfStreamTimer == 0); - - Ready(); - WaitForReceiveToComplete(); - m_bAbort = FALSE; - - return NOERROR; -} - - -// When we pause the filter the things we do are:- - -// Commit the allocator being used in the connection -// Allow a source filter thread to wait in Receive -// Cancel any clock advise link (we may be running) -// Possibly complete the state change if we have data -// Allow us to be paused when we are not connected - -STDMETHODIMP CBaseRenderer::Pause() -{ - CAutoLock cRendererLock(&m_InterfaceLock); - FILTER_STATE OldState = m_State; - ASSERT(m_pInputPin->IsFlushing() == FALSE); - - // Make sure there really is a state change - - if (m_State == State_Paused) { - return CompleteStateChange(State_Paused); - } - - // Has our input pin been connected - - if (m_pInputPin->IsConnected() == FALSE) { - NOTE("Input pin is not connected"); - m_State = State_Paused; - return CompleteStateChange(State_Paused); - } - - // Pause the base filter class - - HRESULT hr = CBaseFilter::Pause(); - if (FAILED(hr)) { - NOTE("Pause failed"); - return hr; - } - - // Enable EC_REPAINT events again - - SetRepaintStatus(TRUE); - StopStreaming(); - SourceThreadCanWait(TRUE); - CancelNotification(); - ResetEndOfStreamTimer(); - - // If we are going into a paused state then we must commit whatever - // allocator we are using it so that any source filter can call the - // GetBuffer and expect to get a buffer without returning an error - - if (m_pInputPin->Allocator()) { - m_pInputPin->Allocator()->Commit(); - } - - // There should be no outstanding advise - ASSERT(CancelNotification() == S_FALSE); - ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); - ASSERT(m_EndOfStreamTimer == 0); - ASSERT(m_pInputPin->IsFlushing() == FALSE); - - // When we come out of a stopped state we must clear any image we were - // holding onto for frame refreshing. Since renderers see state changes - // first we can reset ourselves ready to accept the source thread data - // Paused or running after being stopped causes the current position to - // be reset so we're not interested in passing end of stream signals - - if (OldState == State_Stopped) { - m_bAbort = FALSE; - ClearPendingSample(); - } - return CompleteStateChange(OldState); -} - - -// When we run the filter the things we do are:- - -// Commit the allocator being used in the connection -// Allow a source filter thread to wait in Receive -// Signal the render event just to get us going -// Start the base class by calling StartStreaming -// Allow us to be run when we are not connected -// Signal EC_COMPLETE if we are not connected - -STDMETHODIMP CBaseRenderer::Run(REFERENCE_TIME StartTime) -{ - CAutoLock cRendererLock(&m_InterfaceLock); - FILTER_STATE OldState = m_State; - - // Make sure there really is a state change - - if (m_State == State_Running) { - return NOERROR; - } - - // Send EC_COMPLETE if we're not connected - - if (m_pInputPin->IsConnected() == FALSE) { - NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this); - m_State = State_Running; - return NOERROR; - } - - Ready(); - - // Pause the base filter class - - HRESULT hr = CBaseFilter::Run(StartTime); - if (FAILED(hr)) { - NOTE("Run failed"); - return hr; - } - - // Allow the source thread to wait - ASSERT(m_pInputPin->IsFlushing() == FALSE); - SourceThreadCanWait(TRUE); - SetRepaintStatus(FALSE); - - // There should be no outstanding advise - ASSERT(CancelNotification() == S_FALSE); - ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); - ASSERT(m_EndOfStreamTimer == 0); - ASSERT(m_pInputPin->IsFlushing() == FALSE); - - // If we are going into a running state then we must commit whatever - // allocator we are using it so that any source filter can call the - // GetBuffer and expect to get a buffer without returning an error - - if (m_pInputPin->Allocator()) { - m_pInputPin->Allocator()->Commit(); - } - - // When we come out of a stopped state we must clear any image we were - // holding onto for frame refreshing. Since renderers see state changes - // first we can reset ourselves ready to accept the source thread data - // Paused or running after being stopped causes the current position to - // be reset so we're not interested in passing end of stream signals - - if (OldState == State_Stopped) { - m_bAbort = FALSE; - ClearPendingSample(); - } - return StartStreaming(); -} - - -// Return the number of input pins we support - -int CBaseRenderer::GetPinCount() -{ - return 1; -} - - -// We only support one input pin and it is numbered zero - -CBasePin *CBaseRenderer::GetPin(int n) -{ - CAutoLock cObjectCreationLock(&m_ObjectCreationLock); - - // Should only ever be called with zero - ASSERT(n == 0); - - if (n != 0) { - return NULL; - } - - // Create the input pin if not already done so - - if (m_pInputPin == NULL) { - - // hr must be initialized to NOERROR because - // CRendererInputPin's constructor only changes - // hr's value if an error occurs. - HRESULT hr = NOERROR; - - m_pInputPin = new CRendererInputPin(this,&hr,L"In"); - if (NULL == m_pInputPin) { - return NULL; - } - - if (FAILED(hr)) { - delete m_pInputPin; - m_pInputPin = NULL; - return NULL; - } - } - return m_pInputPin; -} - - -// If "In" then return the IPin for our input pin, otherwise NULL and error - -STDMETHODIMP CBaseRenderer::FindPin(LPCWSTR Id, IPin **ppPin) -{ - CheckPointer(ppPin,E_POINTER); - - if (0==lstrcmpW(Id,L"In")) { - *ppPin = GetPin(0); - ASSERT(*ppPin); - (*ppPin)->AddRef(); - } else { - *ppPin = NULL; - return VFW_E_NOT_FOUND; - } - return NOERROR; -} - - -// Called when the input pin receives an EndOfStream notification. If we have -// not got a sample, then notify EC_COMPLETE now. If we have samples, then set -// m_bEOS and check for this on completing samples. If we're waiting to pause -// then complete the transition to paused state by setting the state event - -HRESULT CBaseRenderer::EndOfStream() -{ - // Ignore these calls if we are stopped - - if (m_State == State_Stopped) { - return NOERROR; - } - - // If we have a sample then wait for it to be rendered - - m_bEOS = TRUE; - if (m_pMediaSample) { - return NOERROR; - } - - // If we are waiting for pause then we are now ready since we cannot now - // carry on waiting for a sample to arrive since we are being told there - // won't be any. This sets an event that the GetState function picks up - - Ready(); - - // Only signal completion now if we are running otherwise queue it until - // we do run in StartStreaming. This is used when we seek because a seek - // causes a pause where early notification of completion is misleading - - if (m_bStreaming) { - SendEndOfStream(); - } - return NOERROR; -} - - -// When we are told to flush we should release the source thread - -HRESULT CBaseRenderer::BeginFlush() -{ - // If paused then report state intermediate until we get some data - - if (m_State == State_Paused) { - NotReady(); - } - - SourceThreadCanWait(FALSE); - CancelNotification(); - ClearPendingSample(); - // Wait for Receive to complete - WaitForReceiveToComplete(); - - return NOERROR; -} - - -// After flushing the source thread can wait in Receive again - -HRESULT CBaseRenderer::EndFlush() -{ - // Reset the current sample media time - if (m_pPosition) m_pPosition->ResetMediaTime(); - - // There should be no outstanding advise - - ASSERT(CancelNotification() == S_FALSE); - SourceThreadCanWait(TRUE); - return NOERROR; -} - - -// We can now send EC_REPAINTs if so required - -HRESULT CBaseRenderer::CompleteConnect(IPin *pReceivePin) -{ - // The caller should always hold the interface lock because - // the function uses CBaseFilter::m_State. - ASSERT(CritCheckIn(&m_InterfaceLock)); - - m_bAbort = FALSE; - - if (State_Running == GetRealState()) { - HRESULT hr = StartStreaming(); - if (FAILED(hr)) { - return hr; - } - - SetRepaintStatus(FALSE); - } else { - SetRepaintStatus(TRUE); - } - - return NOERROR; -} - - -// Called when we go paused or running - -HRESULT CBaseRenderer::Active() -{ - return NOERROR; -} - - -// Called when we go into a stopped state - -HRESULT CBaseRenderer::Inactive() -{ - if (m_pPosition) { - m_pPosition->ResetMediaTime(); - } - // People who derive from this may want to override this behaviour - // to keep hold of the sample in some circumstances - ClearPendingSample(); - - return NOERROR; -} - - -// Tell derived classes about the media type agreed - -HRESULT CBaseRenderer::SetMediaType(const CMediaType *pmt) -{ - return NOERROR; -} - - -// When we break the input pin connection we should reset the EOS flags. When -// we are asked for either IMediaPosition or IMediaSeeking we will create a -// CPosPassThru object to handles media time pass through. When we're handed -// samples we store (by calling CPosPassThru::RegisterMediaTime) their media -// times so we can then return a real current position of data being rendered - -HRESULT CBaseRenderer::BreakConnect() -{ - // Do we have a quality management sink - - if (m_pQSink) { - m_pQSink->Release(); - m_pQSink = NULL; - } - - // Check we have a valid connection - - if (m_pInputPin->IsConnected() == FALSE) { - return S_FALSE; - } - - // Check we are stopped before disconnecting - if (m_State != State_Stopped && !m_pInputPin->CanReconnectWhenActive()) { - return VFW_E_NOT_STOPPED; - } - - SetRepaintStatus(FALSE); - ResetEndOfStream(); - ClearPendingSample(); - m_bAbort = FALSE; - - if (State_Running == m_State) { - StopStreaming(); - } - - return NOERROR; -} - - -// Retrieves the sample times for this samples (note the sample times are -// passed in by reference not value). We return S_FALSE to say schedule this -// sample according to the times on the sample. We also return S_OK in -// which case the object should simply render the sample data immediately - -HRESULT CBaseRenderer::GetSampleTimes(IMediaSample *pMediaSample, - REFERENCE_TIME *pStartTime, - REFERENCE_TIME *pEndTime) -{ - ASSERT(m_dwAdvise == 0); - ASSERT(pMediaSample); - - // If the stop time for this sample is before or the same as start time, - // then just ignore it (release it) and schedule the next one in line - // Source filters should always fill in the start and end times properly! - - if (SUCCEEDED(pMediaSample->GetTime(pStartTime, pEndTime))) { - if (*pEndTime < *pStartTime) { - return VFW_E_START_TIME_AFTER_END; - } - } else { - // no time set in the sample... draw it now? - return S_OK; - } - - // Can't synchronise without a clock so we return S_OK which tells the - // caller that the sample should be rendered immediately without going - // through the overhead of setting a timer advise link with the clock - - if (m_pClock == NULL) { - return S_OK; - } - return ShouldDrawSampleNow(pMediaSample,pStartTime,pEndTime); -} - - -// By default all samples are drawn according to their time stamps so we -// return S_FALSE. Returning S_OK means draw immediately, this is used -// by the derived video renderer class in its quality management. - -HRESULT CBaseRenderer::ShouldDrawSampleNow(IMediaSample *pMediaSample, - REFERENCE_TIME *ptrStart, - REFERENCE_TIME *ptrEnd) -{ - return S_FALSE; -} - - -// We must always reset the current advise time to zero after a timer fires -// because there are several possible ways which lead us not to do any more -// scheduling such as the pending image being cleared after state changes - -void CBaseRenderer::SignalTimerFired() -{ - m_dwAdvise = 0; -} - - -// Cancel any notification currently scheduled. This is called by the owning -// window object when it is told to stop streaming. If there is no timer link -// outstanding then calling this is benign otherwise we go ahead and cancel -// We must always reset the render event as the quality management code can -// signal immediate rendering by setting the event without setting an advise -// link. If we're subsequently stopped and run the first attempt to setup an -// advise link with the reference clock will find the event still signalled - -HRESULT CBaseRenderer::CancelNotification() -{ - ASSERT(m_dwAdvise == 0 || m_pClock); - DWORD_PTR dwAdvise = m_dwAdvise; - - // Have we a live advise link - - if (m_dwAdvise) { - m_pClock->Unadvise(m_dwAdvise); - SignalTimerFired(); - ASSERT(m_dwAdvise == 0); - } - - // Clear the event and return our status - - m_RenderEvent.Reset(); - return (dwAdvise ? S_OK : S_FALSE); -} - - -// Responsible for setting up one shot advise links with the clock -// Return FALSE if the sample is to be dropped (not drawn at all) -// Return TRUE if the sample is to be drawn and in this case also -// arrange for m_RenderEvent to be set at the appropriate time - -BOOL CBaseRenderer::ScheduleSample(IMediaSample *pMediaSample) -{ - REFERENCE_TIME StartSample, EndSample; - - // Is someone pulling our leg - - if (pMediaSample == NULL) { - return FALSE; - } - - // Get the next sample due up for rendering. If there aren't any ready - // then GetNextSampleTimes returns an error. If there is one to be done - // then it succeeds and yields the sample times. If it is due now then - // it returns S_OK other if it's to be done when due it returns S_FALSE - - HRESULT hr = GetSampleTimes(pMediaSample, &StartSample, &EndSample); - if (FAILED(hr)) { - return FALSE; - } - - // If we don't have a reference clock then we cannot set up the advise - // time so we simply set the event indicating an image to render. This - // will cause us to run flat out without any timing or synchronisation - - if (hr == S_OK) { - EXECUTE_ASSERT(SetEvent((HANDLE) m_RenderEvent)); - return TRUE; - } - - ASSERT(m_dwAdvise == 0); - ASSERT(m_pClock); - ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); - - // We do have a valid reference clock interface so we can ask it to - // set an event when the image comes due for rendering. We pass in - // the reference time we were told to start at and also the current - // stream time which is the offset from the start reference time - - hr = m_pClock->AdviseTime( - (REFERENCE_TIME) m_tStart, // Start run time - StartSample, // Stream time - (HEVENT)(HANDLE) m_RenderEvent, // Render notification - &m_dwAdvise); // Advise cookie - - if (SUCCEEDED(hr)) { - return TRUE; - } - - // We could not schedule the next sample for rendering despite the fact - // we have a valid sample here. This is a fair indication that either - // the system clock is wrong or the time stamp for the sample is duff - - ASSERT(m_dwAdvise == 0); - return FALSE; -} - - -// This is called when a sample comes due for rendering. We pass the sample -// on to the derived class. After rendering we will initialise the timer for -// the next sample, NOTE signal that the last one fired first, if we don't -// do this it thinks there is still one outstanding that hasn't completed - -HRESULT CBaseRenderer::Render(IMediaSample *pMediaSample) -{ - // If the media sample is NULL then we will have been notified by the - // clock that another sample is ready but in the mean time someone has - // stopped us streaming which causes the next sample to be released - - if (pMediaSample == NULL) { - return S_FALSE; - } - - // If we have stopped streaming then don't render any more samples, the - // thread that got in and locked us and then reset this flag does not - // clear the pending sample as we can use it to refresh any output device - - if (m_bStreaming == FALSE) { - return S_FALSE; - } - - // Time how long the rendering takes - - OnRenderStart(pMediaSample); - DoRenderSample(pMediaSample); - OnRenderEnd(pMediaSample); - - return NOERROR; -} - - -// Checks if there is a sample waiting at the renderer - -BOOL CBaseRenderer::HaveCurrentSample() -{ - CAutoLock cRendererLock(&m_RendererLock); - return (m_pMediaSample == NULL ? FALSE : TRUE); -} - - -// Returns the current sample waiting at the video renderer. We AddRef the -// sample before returning so that should it come due for rendering the -// person who called this method will hold the remaining reference count -// that will stop the sample being added back onto the allocator free list - -IMediaSample *CBaseRenderer::GetCurrentSample() -{ - CAutoLock cRendererLock(&m_RendererLock); - if (m_pMediaSample) { - m_pMediaSample->AddRef(); - } - return m_pMediaSample; -} - - -// Called when the source delivers us a sample. We go through a few checks to -// make sure the sample can be rendered. If we are running (streaming) then we -// have the sample scheduled with the reference clock, if we are not streaming -// then we have received an sample in paused mode so we can complete any state -// transition. On leaving this function everything will be unlocked so an app -// thread may get in and change our state to stopped (for example) in which -// case it will also signal the thread event so that our wait call is stopped - -HRESULT CBaseRenderer::PrepareReceive(IMediaSample *pMediaSample) -{ - CAutoLock cInterfaceLock(&m_InterfaceLock); - m_bInReceive = TRUE; - - // Check our flushing and filter state - - // This function must hold the interface lock because it calls - // CBaseInputPin::Receive() and CBaseInputPin::Receive() uses - // CBasePin::m_bRunTimeError. - HRESULT hr = m_pInputPin->CBaseInputPin::Receive(pMediaSample); - - if (hr != NOERROR) { - m_bInReceive = FALSE; - return E_FAIL; - } - - // Has the type changed on a media sample. We do all rendering - // synchronously on the source thread, which has a side effect - // that only one buffer is ever outstanding. Therefore when we - // have Receive called we can go ahead and change the format - // Since the format change can cause a SendMessage we just don't - // lock - if (m_pInputPin->SampleProps()->pMediaType) { - hr = m_pInputPin->SetMediaType( - (CMediaType *)m_pInputPin->SampleProps()->pMediaType); - if (FAILED(hr)) { - m_bInReceive = FALSE; - return hr; - } - } - - - CAutoLock cSampleLock(&m_RendererLock); - - ASSERT(IsActive() == TRUE); - ASSERT(m_pInputPin->IsFlushing() == FALSE); - ASSERT(m_pInputPin->IsConnected() == TRUE); - ASSERT(m_pMediaSample == NULL); - - // Return an error if we already have a sample waiting for rendering - // source pins must serialise the Receive calls - we also check that - // no data is being sent after the source signalled an end of stream - - if (m_pMediaSample || m_bEOS || m_bAbort) { - Ready(); - m_bInReceive = FALSE; - return E_UNEXPECTED; - } - - // Store the media times from this sample - if (m_pPosition) m_pPosition->RegisterMediaTime(pMediaSample); - - // Schedule the next sample if we are streaming - - if ((m_bStreaming == TRUE) && (ScheduleSample(pMediaSample) == FALSE)) { - ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); - ASSERT(CancelNotification() == S_FALSE); - m_bInReceive = FALSE; - return VFW_E_SAMPLE_REJECTED; - } - - // Store the sample end time for EC_COMPLETE handling - m_SignalTime = m_pInputPin->SampleProps()->tStop; - - // BEWARE we sometimes keep the sample even after returning the thread to - // the source filter such as when we go into a stopped state (we keep it - // to refresh the device with) so we must AddRef it to keep it safely. If - // we start flushing the source thread is released and any sample waiting - // will be released otherwise GetBuffer may never return (see BeginFlush) - - m_pMediaSample = pMediaSample; - m_pMediaSample->AddRef(); - - if (m_bStreaming == FALSE) { - SetRepaintStatus(TRUE); - } - return NOERROR; -} - - -// Called by the source filter when we have a sample to render. Under normal -// circumstances we set an advise link with the clock, wait for the time to -// arrive and then render the data using the PURE virtual DoRenderSample that -// the derived class will have overriden. After rendering the sample we may -// also signal EOS if it was the last one sent before EndOfStream was called - -HRESULT CBaseRenderer::Receive(IMediaSample *pSample) -{ - ASSERT(pSample); - - // It may return VFW_E_SAMPLE_REJECTED code to say don't bother - - HRESULT hr = PrepareReceive(pSample); - ASSERT(m_bInReceive == SUCCEEDED(hr)); - if (FAILED(hr)) { - if (hr == VFW_E_SAMPLE_REJECTED) { - return NOERROR; - } - return hr; - } - - // We realize the palette in "PrepareRender()" so we have to give away the - // filter lock here. - if (m_State == State_Paused) { - PrepareRender(); - // no need to use InterlockedExchange - m_bInReceive = FALSE; - { - // We must hold both these locks - CAutoLock cRendererLock(&m_InterfaceLock); - if (m_State == State_Stopped) - return NOERROR; - - m_bInReceive = TRUE; - CAutoLock cSampleLock(&m_RendererLock); - OnReceiveFirstSample(pSample); - } - Ready(); - } - // Having set an advise link with the clock we sit and wait. We may be - // awoken by the clock firing or by a state change. The rendering call - // will lock the critical section and check we can still render the data - - hr = WaitForRenderTime(); - if (FAILED(hr)) { - m_bInReceive = FALSE; - return NOERROR; - } - - PrepareRender(); - - // Set this here and poll it until we work out the locking correctly - // It can't be right that the streaming stuff grabs the interface - // lock - after all we want to be able to wait for this stuff - // to complete - m_bInReceive = FALSE; - - // We must hold both these locks - CAutoLock cRendererLock(&m_InterfaceLock); - - // since we gave away the filter wide lock, the sate of the filter could - // have chnaged to Stopped - if (m_State == State_Stopped) - return NOERROR; - - CAutoLock cSampleLock(&m_RendererLock); - - // Deal with this sample - - Render(m_pMediaSample); - ClearPendingSample(); - SendEndOfStream(); - CancelNotification(); - return NOERROR; -} - - -// This is called when we stop or are inactivated to clear the pending sample -// We release the media sample interface so that they can be allocated to the -// source filter again, unless of course we are changing state to inactive in -// which case GetBuffer will return an error. We must also reset the current -// media sample to NULL so that we know we do not currently have an image - -HRESULT CBaseRenderer::ClearPendingSample() -{ - CAutoLock cRendererLock(&m_RendererLock); - if (m_pMediaSample) { - m_pMediaSample->Release(); - m_pMediaSample = NULL; - } - return NOERROR; -} - - -// Used to signal end of stream according to the sample end time - -void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier - UINT uMsg, // Not currently used - DWORD_PTR dwUser,// User information - DWORD_PTR dw1, // Windows reserved - DWORD_PTR dw2) // is also reserved -{ - CBaseRenderer *pRenderer = (CBaseRenderer *) dwUser; - NOTE1("EndOfStreamTimer called (%d)",uID); - pRenderer->TimerCallback(); -} - -// Do the timer callback work -void CBaseRenderer::TimerCallback() -{ - // Lock for synchronization (but don't hold this lock when calling - // timeKillEvent) - CAutoLock cRendererLock(&m_RendererLock); - - // See if we should signal end of stream now - - if (m_EndOfStreamTimer) { - m_EndOfStreamTimer = 0; - SendEndOfStream(); - } -} - - -// If we are at the end of the stream signal the filter graph but do not set -// the state flag back to FALSE. Once we drop off the end of the stream we -// leave the flag set (until a subsequent ResetEndOfStream). Each sample we -// get delivered will update m_SignalTime to be the last sample's end time. -// We must wait this long before signalling end of stream to the filtergraph - -#define TIMEOUT_DELIVERYWAIT 50 -#define TIMEOUT_RESOLUTION 10 - -HRESULT CBaseRenderer::SendEndOfStream() -{ - ASSERT(CritCheckIn(&m_RendererLock)); - if (m_bEOS == FALSE || m_bEOSDelivered || m_EndOfStreamTimer) { - return NOERROR; - } - - // If there is no clock then signal immediately - if (m_pClock == NULL) { - return NotifyEndOfStream(); - } - - // How long into the future is the delivery time - - REFERENCE_TIME Signal = m_tStart + m_SignalTime; - REFERENCE_TIME CurrentTime; - m_pClock->GetTime(&CurrentTime); - LONG Delay = LONG((Signal - CurrentTime) / 10000); - - // Dump the timing information to the debugger - - NOTE1("Delay until end of stream delivery %d",Delay); - NOTE1("Current %s",(LPCTSTR)CDisp((LONGLONG)CurrentTime)); - NOTE1("Signal %s",(LPCTSTR)CDisp((LONGLONG)Signal)); - - // Wait for the delivery time to arrive - - if (Delay < TIMEOUT_DELIVERYWAIT) { - return NotifyEndOfStream(); - } - - // Signal a timer callback on another worker thread - - m_EndOfStreamTimer = CompatibleTimeSetEvent((UINT) Delay, // Period of timer - TIMEOUT_RESOLUTION, // Timer resolution - EndOfStreamTimer, // Callback function - DWORD_PTR(this), // Used information - TIME_ONESHOT); // Type of callback - if (m_EndOfStreamTimer == 0) { - return NotifyEndOfStream(); - } - return NOERROR; -} - - -// Signals EC_COMPLETE to the filtergraph manager - -HRESULT CBaseRenderer::NotifyEndOfStream() -{ - CAutoLock cRendererLock(&m_RendererLock); - ASSERT(m_bEOSDelivered == FALSE); - ASSERT(m_EndOfStreamTimer == 0); - - // Has the filter changed state - - if (m_bStreaming == FALSE) { - ASSERT(m_EndOfStreamTimer == 0); - return NOERROR; - } - - // Reset the end of stream timer - m_EndOfStreamTimer = 0; - - // If we've been using the IMediaPosition interface, set it's start - // and end media "times" to the stop position by hand. This ensures - // that we actually get to the end, even if the MPEG guestimate has - // been bad or if the quality management dropped the last few frames - - if (m_pPosition) m_pPosition->EOS(); - m_bEOSDelivered = TRUE; - NOTE("Sending EC_COMPLETE..."); - return NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this); -} - - -// Reset the end of stream flag, this is typically called when we transfer to -// stopped states since that resets the current position back to the start so -// we will receive more samples or another EndOfStream if there aren't any. We -// keep two separate flags one to say we have run off the end of the stream -// (this is the m_bEOS flag) and another to say we have delivered EC_COMPLETE -// to the filter graph. We need the latter otherwise we can end up sending an -// EC_COMPLETE every time the source changes state and calls our EndOfStream - -HRESULT CBaseRenderer::ResetEndOfStream() -{ - ResetEndOfStreamTimer(); - CAutoLock cRendererLock(&m_RendererLock); - - m_bEOS = FALSE; - m_bEOSDelivered = FALSE; - m_SignalTime = 0; - - return NOERROR; -} - - -// Kills any outstanding end of stream timer - -void CBaseRenderer::ResetEndOfStreamTimer() -{ - ASSERT(CritCheckOut(&m_RendererLock)); - if (m_EndOfStreamTimer) { - timeKillEvent(m_EndOfStreamTimer); - m_EndOfStreamTimer = 0; - } -} - - -// This is called when we start running so that we can schedule any pending -// image we have with the clock and display any timing information. If we -// don't have any sample but we have queued an EOS flag then we send it. If -// we do have a sample then we wait until that has been rendered before we -// signal the filter graph otherwise we may change state before it's done - -HRESULT CBaseRenderer::StartStreaming() -{ - CAutoLock cRendererLock(&m_RendererLock); - if (m_bStreaming == TRUE) { - return NOERROR; - } - - // Reset the streaming times ready for running - - m_bStreaming = TRUE; - - timeBeginPeriod(1); - OnStartStreaming(); - - // There should be no outstanding advise - ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); - ASSERT(CancelNotification() == S_FALSE); - - // If we have an EOS and no data then deliver it now - - if (m_pMediaSample == NULL) { - return SendEndOfStream(); - } - - // Have the data rendered - - ASSERT(m_pMediaSample); - if (!ScheduleSample(m_pMediaSample)) - m_RenderEvent.Set(); - - return NOERROR; -} - - -// This is called when we stop streaming so that we can set our internal flag -// indicating we are not now to schedule any more samples arriving. The state -// change methods in the filter implementation take care of cancelling any -// clock advise link we have set up and clearing any pending sample we have - -HRESULT CBaseRenderer::StopStreaming() -{ - CAutoLock cRendererLock(&m_RendererLock); - m_bEOSDelivered = FALSE; - - if (m_bStreaming == TRUE) { - m_bStreaming = FALSE; - OnStopStreaming(); - timeEndPeriod(1); - } - return NOERROR; -} - - -// We have a boolean flag that is reset when we have signalled EC_REPAINT to -// the filter graph. We set this when we receive an image so that should any -// conditions arise again we can send another one. By having a flag we ensure -// we don't flood the filter graph with redundant calls. We do not set the -// event when we receive an EndOfStream call since there is no point in us -// sending further EC_REPAINTs. In particular the AutoShowWindow method and -// the DirectDraw object use this method to control the window repainting - -void CBaseRenderer::SetRepaintStatus(BOOL bRepaint) -{ - CAutoLock cSampleLock(&m_RendererLock); - m_bRepaintStatus = bRepaint; -} - - -// Pass the window handle to the upstream filter - -void CBaseRenderer::SendNotifyWindow(IPin *pPin,HWND hwnd) -{ - IMediaEventSink *pSink; - - // Does the pin support IMediaEventSink - HRESULT hr = pPin->QueryInterface(IID_IMediaEventSink,(void **)&pSink); - if (SUCCEEDED(hr)) { - pSink->Notify(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0); - pSink->Release(); - } - NotifyEvent(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0); -} - - -// Signal an EC_REPAINT to the filter graph. This can be used to have data -// sent to us. For example when a video window is first displayed it may -// not have an image to display, at which point it signals EC_REPAINT. The -// filtergraph will either pause the graph if stopped or if already paused -// it will call put_CurrentPosition of the current position. Setting the -// current position to itself has the stream flushed and the image resent - -#define RLOG(_x_) DbgLog((LOG_TRACE,1,TEXT(_x_))); - -void CBaseRenderer::SendRepaint() -{ - CAutoLock cSampleLock(&m_RendererLock); - ASSERT(m_pInputPin); - - // We should not send repaint notifications when... - // - An end of stream has been notified - // - Our input pin is being flushed - // - The input pin is not connected - // - We have aborted a video playback - // - There is a repaint already sent - - if (m_bAbort == FALSE) { - if (m_pInputPin->IsConnected() == TRUE) { - if (m_pInputPin->IsFlushing() == FALSE) { - if (IsEndOfStream() == FALSE) { - if (m_bRepaintStatus == TRUE) { - IPin *pPin = (IPin *) m_pInputPin; - NotifyEvent(EC_REPAINT,(LONG_PTR) pPin,0); - SetRepaintStatus(FALSE); - RLOG("Sending repaint"); - } - } - } - } - } -} - - -// When a video window detects a display change (WM_DISPLAYCHANGE message) it -// can send an EC_DISPLAY_CHANGED event code along with the renderer pin. The -// filtergraph will stop everyone and reconnect our input pin. As we're then -// reconnected we can accept the media type that matches the new display mode -// since we may no longer be able to draw the current image type efficiently - -BOOL CBaseRenderer::OnDisplayChange() -{ - // Ignore if we are not connected yet - - CAutoLock cSampleLock(&m_RendererLock); - if (m_pInputPin->IsConnected() == FALSE) { - return FALSE; - } - - RLOG("Notification of EC_DISPLAY_CHANGE"); - - // Pass our input pin as parameter on the event - - IPin *pPin = (IPin *) m_pInputPin; - m_pInputPin->AddRef(); - NotifyEvent(EC_DISPLAY_CHANGED,(LONG_PTR) pPin,0); - SetAbortSignal(TRUE); - ClearPendingSample(); - m_pInputPin->Release(); - - return TRUE; -} - - -// Called just before we start drawing. -// Store the current time in m_trRenderStart to allow the rendering time to be -// logged. Log the time stamp of the sample and how late it is (neg is early) - -void CBaseRenderer::OnRenderStart(IMediaSample *pMediaSample) -{ -#ifdef PERF - REFERENCE_TIME trStart, trEnd; - pMediaSample->GetTime(&trStart, &trEnd); - - MSR_INTEGER(m_idBaseStamp, (int)trStart); // dump low order 32 bits - - m_pClock->GetTime(&m_trRenderStart); - MSR_INTEGER(0, (int)m_trRenderStart); - REFERENCE_TIME trStream; - trStream = m_trRenderStart-m_tStart; // convert reftime to stream time - MSR_INTEGER(0,(int)trStream); - - const int trLate = (int)(trStream - trStart); - MSR_INTEGER(m_idBaseAccuracy, trLate/10000); // dump in mSec -#endif - -} // OnRenderStart - - -// Called directly after drawing an image. -// calculate the time spent drawing and log it. - -void CBaseRenderer::OnRenderEnd(IMediaSample *pMediaSample) -{ -#ifdef PERF - REFERENCE_TIME trNow; - m_pClock->GetTime(&trNow); - MSR_INTEGER(0,(int)trNow); - int t = (int)((trNow - m_trRenderStart)/10000); // convert UNITS->msec - MSR_INTEGER(m_idBaseRenderTime, t); -#endif -} // OnRenderEnd - - - - -// Constructor must be passed the base renderer object - -CRendererInputPin::CRendererInputPin(CBaseRenderer *pRenderer, - HRESULT *phr, - LPCWSTR pPinName) : - CBaseInputPin(NAME("Renderer pin"), - pRenderer, - &pRenderer->m_InterfaceLock, - (HRESULT *) phr, - pPinName) -{ - m_pRenderer = pRenderer; - ASSERT(m_pRenderer); -} - - -// Signals end of data stream on the input pin - -STDMETHODIMP CRendererInputPin::EndOfStream() -{ - CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); - CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); - - // Make sure we're streaming ok - - HRESULT hr = CheckStreaming(); - if (hr != NOERROR) { - return hr; - } - - // Pass it onto the renderer - - hr = m_pRenderer->EndOfStream(); - if (SUCCEEDED(hr)) { - hr = CBaseInputPin::EndOfStream(); - } - return hr; -} - - -// Signals start of flushing on the input pin - we do the final reset end of -// stream with the renderer lock unlocked but with the interface lock locked -// We must do this because we call timeKillEvent, our timer callback method -// has to take the renderer lock to serialise our state. Therefore holding a -// renderer lock when calling timeKillEvent could cause a deadlock condition - -STDMETHODIMP CRendererInputPin::BeginFlush() -{ - CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); - { - CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); - CBaseInputPin::BeginFlush(); - m_pRenderer->BeginFlush(); - } - return m_pRenderer->ResetEndOfStream(); -} - - -// Signals end of flushing on the input pin - -STDMETHODIMP CRendererInputPin::EndFlush() -{ - CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); - CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); - - HRESULT hr = m_pRenderer->EndFlush(); - if (SUCCEEDED(hr)) { - hr = CBaseInputPin::EndFlush(); - } - return hr; -} - - -// Pass the sample straight through to the renderer object - -STDMETHODIMP CRendererInputPin::Receive(IMediaSample *pSample) -{ - HRESULT hr = m_pRenderer->Receive(pSample); - if (FAILED(hr)) { - - // A deadlock could occur if the caller holds the renderer lock and - // attempts to acquire the interface lock. - ASSERT(CritCheckOut(&m_pRenderer->m_RendererLock)); - - { - // The interface lock must be held when the filter is calling - // IsStopped() or IsFlushing(). The interface lock must also - // be held because the function uses m_bRunTimeError. - CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); - - // We do not report errors which occur while the filter is stopping, - // flushing or if the m_bAbort flag is set . Errors are expected to - // occur during these operations and the streaming thread correctly - // handles the errors. - if (!IsStopped() && !IsFlushing() && !m_pRenderer->m_bAbort && !m_bRunTimeError) { - - // EC_ERRORABORT's first parameter is the error which caused - // the event and its' last parameter is 0. See the Direct - // Show SDK documentation for more information. - m_pRenderer->NotifyEvent(EC_ERRORABORT,hr,0); - - { - CAutoLock alRendererLock(&m_pRenderer->m_RendererLock); - if (m_pRenderer->IsStreaming() && !m_pRenderer->IsEndOfStreamDelivered()) { - m_pRenderer->NotifyEndOfStream(); - } - } - - m_bRunTimeError = TRUE; - } - } - } - - return hr; -} - - -// Called when the input pin is disconnected - -HRESULT CRendererInputPin::BreakConnect() -{ - HRESULT hr = m_pRenderer->BreakConnect(); - if (FAILED(hr)) { - return hr; - } - return CBaseInputPin::BreakConnect(); -} - - -// Called when the input pin is connected - -HRESULT CRendererInputPin::CompleteConnect(IPin *pReceivePin) -{ - HRESULT hr = m_pRenderer->CompleteConnect(pReceivePin); - if (FAILED(hr)) { - return hr; - } - return CBaseInputPin::CompleteConnect(pReceivePin); -} - - -// Give the pin id of our one and only pin - -STDMETHODIMP CRendererInputPin::QueryId(LPWSTR *Id) -{ - CheckPointer(Id,E_POINTER); - - const size_t len = 4; - *Id = (LPWSTR)CoTaskMemAlloc(len * sizeof(WCHAR)); - if (*Id == NULL) { - return E_OUTOFMEMORY; - } - (void)StringCchCopyW(*Id, len, L"In"); - return NOERROR; -} - - -// Will the filter accept this media type - -HRESULT CRendererInputPin::CheckMediaType(const CMediaType *pmt) -{ - return m_pRenderer->CheckMediaType(pmt); -} - - -// Called when we go paused or running - -HRESULT CRendererInputPin::Active() -{ - return m_pRenderer->Active(); -} - - -// Called when we go into a stopped state - -HRESULT CRendererInputPin::Inactive() -{ - // The caller must hold the interface lock because - // this function uses m_bRunTimeError. - ASSERT(CritCheckIn(&m_pRenderer->m_InterfaceLock)); - - m_bRunTimeError = FALSE; - - return m_pRenderer->Inactive(); -} - - -// Tell derived classes about the media type agreed - -HRESULT CRendererInputPin::SetMediaType(const CMediaType *pmt) -{ - HRESULT hr = CBaseInputPin::SetMediaType(pmt); - if (FAILED(hr)) { - return hr; - } - return m_pRenderer->SetMediaType(pmt); -} - - -// We do not keep an event object to use when setting up a timer link with -// the clock but are given a pointer to one by the owning object through the -// SetNotificationObject method - this must be initialised before starting -// We can override the default quality management process to have it always -// draw late frames, this is currently done by having the following registry -// key (actually an INI key) called DrawLateFrames set to 1 (default is 0) - -const TCHAR AMQUALITY[] = TEXT("ActiveMovie"); -const TCHAR DRAWLATEFRAMES[] = TEXT("DrawLateFrames"); - -CBaseVideoRenderer::CBaseVideoRenderer( - REFCLSID RenderClass, // CLSID for this renderer - TCHAR *pName, // Debug ONLY description - LPUNKNOWN pUnk, // Aggregated owner object - HRESULT *phr) : // General OLE return code - - CBaseRenderer(RenderClass,pName,pUnk,phr), - m_cFramesDropped(0), - m_cFramesDrawn(0), - m_bSupplierHandlingQuality(FALSE) -{ - ResetStreamingTimes(); - -#ifdef PERF - m_idTimeStamp = MSR_REGISTER(TEXT("Frame time stamp")); - m_idEarliness = MSR_REGISTER(TEXT("Earliness fudge")); - m_idTarget = MSR_REGISTER(TEXT("Target (mSec)")); - m_idSchLateTime = MSR_REGISTER(TEXT("mSec late when scheduled")); - m_idDecision = MSR_REGISTER(TEXT("Scheduler decision code")); - m_idQualityRate = MSR_REGISTER(TEXT("Quality rate sent")); - m_idQualityTime = MSR_REGISTER(TEXT("Quality time sent")); - m_idWaitReal = MSR_REGISTER(TEXT("Render wait")); - // m_idWait = MSR_REGISTER(TEXT("wait time recorded (msec)")); - m_idFrameAccuracy = MSR_REGISTER(TEXT("Frame accuracy (msecs)")); - m_bDrawLateFrames = GetProfileInt(AMQUALITY, DRAWLATEFRAMES, FALSE); - //m_idSendQuality = MSR_REGISTER(TEXT("Processing Quality message")); - - m_idRenderAvg = MSR_REGISTER(TEXT("Render draw time Avg")); - m_idFrameAvg = MSR_REGISTER(TEXT("FrameAvg")); - m_idWaitAvg = MSR_REGISTER(TEXT("WaitAvg")); - m_idDuration = MSR_REGISTER(TEXT("Duration")); - m_idThrottle = MSR_REGISTER(TEXT("Audio-video throttle wait")); - // m_idDebug = MSR_REGISTER(TEXT("Debug stuff")); -#endif // PERF -} // Constructor - - -// Destructor is just a placeholder - -CBaseVideoRenderer::~CBaseVideoRenderer() -{ - ASSERT(m_dwAdvise == 0); -} - - -// The timing functions in this class are called by the window object and by -// the renderer's allocator. -// The windows object calls timing functions as it receives media sample -// images for drawing using GDI. -// The allocator calls timing functions when it starts passing DCI/DirectDraw -// surfaces which are not rendered in the same way; The decompressor writes -// directly to the surface with no separate rendering, so those code paths -// call direct into us. Since we only ever hand out DCI/DirectDraw surfaces -// when we have allocated one and only one image we know there cannot be any -// conflict between the two. -// -// We use timeGetTime to return the timing counts we use (since it's relative -// performance we are interested in rather than absolute compared to a clock) -// The window object sets the accuracy of the system clock (normally 1ms) by -// calling timeBeginPeriod/timeEndPeriod when it changes streaming states - - -// Reset all times controlling streaming. -// Set them so that -// 1. Frames will not initially be dropped -// 2. The first frame will definitely be drawn (achieved by saying that there -// has not ben a frame drawn for a long time). - -HRESULT CBaseVideoRenderer::ResetStreamingTimes() -{ - m_trLastDraw = -1000; // set up as first frame since ages (1 sec) ago - m_tStreamingStart = timeGetTime(); - m_trRenderAvg = 0; - m_trFrameAvg = -1; // -1000 fps == "unset" - m_trDuration = 0; // 0 - strange value - m_trRenderLast = 0; - m_trWaitAvg = 0; - m_tRenderStart = 0; - m_cFramesDrawn = 0; - m_cFramesDropped = 0; - m_iTotAcc = 0; - m_iSumSqAcc = 0; - m_iSumSqFrameTime = 0; - m_trFrame = 0; // hygiene - not really needed - m_trLate = 0; // hygiene - not really needed - m_iSumFrameTime = 0; - m_nNormal = 0; - m_trEarliness = 0; - m_trTarget = -300000; // 30mSec early - m_trThrottle = 0; - m_trRememberStampForPerf = 0; - -#ifdef PERF - m_trRememberFrameForPerf = 0; -#endif - - return NOERROR; -} // ResetStreamingTimes - - -// Reset all times controlling streaming. Note that we're now streaming. We -// don't need to set the rendering event to have the source filter released -// as it is done during the Run processing. When we are run we immediately -// release the source filter thread and draw any image waiting (that image -// may already have been drawn once as a poster frame while we were paused) - -HRESULT CBaseVideoRenderer::OnStartStreaming() -{ - ResetStreamingTimes(); - return NOERROR; -} // OnStartStreaming - - -// Called at end of streaming. Fixes times for property page report - -HRESULT CBaseVideoRenderer::OnStopStreaming() -{ - m_tStreamingStart = timeGetTime()-m_tStreamingStart; - return NOERROR; -} // OnStopStreaming - - -// Called when we start waiting for a rendering event. -// Used to update times spent waiting and not waiting. - -void CBaseVideoRenderer::OnWaitStart() -{ - MSR_START(m_idWaitReal); -} // OnWaitStart - - -// Called when we are awoken from the wait in the window OR by our allocator -// when it is hanging around until the next sample is due for rendering on a -// DCI/DirectDraw surface. We add the wait time into our rolling average. -// We grab the interface lock so that we're serialised with the application -// thread going through the run code - which in due course ends up calling -// ResetStreaming times - possibly as we run through this section of code - -void CBaseVideoRenderer::OnWaitEnd() -{ -#ifdef PERF - MSR_STOP(m_idWaitReal); - // for a perf build we want to know just exactly how late we REALLY are. - // even if this means that we have to look at the clock again. - - REFERENCE_TIME trRealStream; // the real time now expressed as stream time. -#if 0 - m_pClock->GetTime(&trRealStream); // Calling clock here causes W95 deadlock! -#else - // We will be discarding overflows like mad here! - // This is wrong really because timeGetTime() can wrap but it's - // only for PERF - REFERENCE_TIME tr = timeGetTime()*10000; - trRealStream = tr + m_llTimeOffset; -#endif - trRealStream -= m_tStart; // convert to stream time (this is a reftime) - - if (m_trRememberStampForPerf==0) { - // This is probably the poster frame at the start, and it is not scheduled - // in the usual way at all. Just count it. The rememberstamp gets set - // in ShouldDrawSampleNow, so this does invalid frame recording until we - // actually start playing. - PreparePerformanceData(0, 0); - } else { - int trLate = (int)(trRealStream - m_trRememberStampForPerf); - int trFrame = (int)(tr - m_trRememberFrameForPerf); - PreparePerformanceData(trLate, trFrame); - } - m_trRememberFrameForPerf = tr; -#endif //PERF -} // OnWaitEnd - - -// Put data on one side that describes the lateness of the current frame. -// We don't yet know whether it will actually be drawn. In direct draw mode, -// this decision is up to the filter upstream, and it could change its mind. -// The rules say that if it did draw it must call Receive(). One way or -// another we eventually get into either OnRenderStart or OnDirectRender and -// these both call RecordFrameLateness to update the statistics. - -void CBaseVideoRenderer::PreparePerformanceData(int trLate, int trFrame) -{ - m_trLate = trLate; - m_trFrame = trFrame; -} // PreparePerformanceData - - -// update the statistics: -// m_iTotAcc, m_iSumSqAcc, m_iSumSqFrameTime, m_iSumFrameTime, m_cFramesDrawn -// Note that because the properties page reports using these variables, -// 1. We need to be inside a critical section -// 2. They must all be updated together. Updating the sums here and the count -// elsewhere can result in imaginary jitter (i.e. attempts to find square roots -// of negative numbers) in the property page code. - -void CBaseVideoRenderer::RecordFrameLateness(int trLate, int trFrame) -{ - // Record how timely we are. - int tLate = trLate/10000; - - // Best estimate of moment of appearing on the screen is average of - // start and end draw times. Here we have only the end time. This may - // tend to show us as spuriously late by up to 1/2 frame rate achieved. - // Decoder probably monitors draw time. We don't bother. - MSR_INTEGER( m_idFrameAccuracy, tLate ); - - // This is a kludge - we can get frames that are very late - // especially (at start-up) and they invalidate the statistics. - // So ignore things that are more than 1 sec off. - if (tLate>1000 || tLate<-1000) { - if (m_cFramesDrawn<=1) { - tLate = 0; - } else if (tLate>0) { - tLate = 1000; - } else { - tLate = -1000; - } - } - // The very first frame often has a invalid time, so don't - // count it into the statistics. (???) - if (m_cFramesDrawn>1) { - m_iTotAcc += tLate; - m_iSumSqAcc += (tLate*tLate); - } - - // calculate inter-frame time. Doesn't make sense for first frame - // second frame suffers from invalid first frame stamp. - if (m_cFramesDrawn>2) { - int tFrame = trFrame/10000; // convert to mSec else it overflows - - // This is a kludge. It can overflow anyway (a pause can cause - // a very long inter-frame time) and it overflows at 2**31/10**7 - // or about 215 seconds i.e. 3min 35sec - if (tFrame>1000||tFrame<0) tFrame = 1000; - m_iSumSqFrameTime += tFrame*tFrame; - ASSERT(m_iSumSqFrameTime>=0); - m_iSumFrameTime += tFrame; - } - ++m_cFramesDrawn; - -} // RecordFrameLateness - - -void CBaseVideoRenderer::ThrottleWait() -{ - if (m_trThrottle>0) { - int iThrottle = m_trThrottle/10000; // convert to mSec - MSR_INTEGER( m_idThrottle, iThrottle); - DbgLog((LOG_TRACE, 0, TEXT("Throttle %d ms"), iThrottle)); - Sleep(iThrottle); - } else { - Sleep(0); - } -} // ThrottleWait - - -// Whenever a frame is rendered it goes though either OnRenderStart -// or OnDirectRender. Data that are generated during ShouldDrawSample -// are added to the statistics by calling RecordFrameLateness from both -// these two places. - -// Called in place of OnRenderStart..OnRenderEnd -// When a DirectDraw image is drawn -void CBaseVideoRenderer::OnDirectRender(IMediaSample *pMediaSample) -{ - m_trRenderAvg = 0; - m_trRenderLast = 5000000; // If we mode switch, we do NOT want this - // to inhibit the new average getting going! - // so we set it to half a second - // MSR_INTEGER(m_idRenderAvg, m_trRenderAvg/10000); - RecordFrameLateness(m_trLate, m_trFrame); - ThrottleWait(); -} // OnDirectRender - - -// Called just before we start drawing. All we do is to get the current clock -// time (from the system) and return. We have to store the start render time -// in a member variable because it isn't used until we complete the drawing -// The rest is just performance logging. - -void CBaseVideoRenderer::OnRenderStart(IMediaSample *pMediaSample) -{ - RecordFrameLateness(m_trLate, m_trFrame); - m_tRenderStart = timeGetTime(); -} // OnRenderStart - - -// Called directly after drawing an image. We calculate the time spent in the -// drawing code and if this doesn't appear to have any odd looking spikes in -// it then we add it to the current average draw time. Measurement spikes may -// occur if the drawing thread is interrupted and switched to somewhere else. - -void CBaseVideoRenderer::OnRenderEnd(IMediaSample *pMediaSample) -{ - // The renderer time can vary erratically if we are interrupted so we do - // some smoothing to help get more sensible figures out but even that is - // not enough as figures can go 9,10,9,9,83,9 and we must disregard 83 - - int tr = (timeGetTime() - m_tRenderStart)*10000; // convert mSec->UNITS - if (tr < m_trRenderAvg*2 || tr < 2 * m_trRenderLast) { - // DO_MOVING_AVG(m_trRenderAvg, tr); - m_trRenderAvg = (tr + (AVGPERIOD-1)*m_trRenderAvg)/AVGPERIOD; - } - m_trRenderLast = tr; - ThrottleWait(); -} // OnRenderEnd - - -STDMETHODIMP CBaseVideoRenderer::SetSink( IQualityControl * piqc) -{ - - m_pQSink = piqc; - - return NOERROR; -} // SetSink - - -STDMETHODIMP CBaseVideoRenderer::Notify( IBaseFilter * pSelf, Quality q) -{ - // NOTE: We are NOT getting any locks here. We could be called - // asynchronously and possibly even on a time critical thread of - // someone else's - so we do the minumum. We only set one state - // variable (an integer) and if that happens to be in the middle - // of another thread reading it they will just get either the new - // or the old value. Locking would achieve no more than this. - - // It might be nice to check that we are being called from m_pGraph, but - // it turns out to be a millisecond or so per throw! - - // This is heuristics, these numbers are aimed at being "what works" - // rather than anything based on some theory. - // We use a hyperbola because it's easy to calculate and it includes - // a panic button asymptote (which we push off just to the left) - // The throttling fits the following table (roughly) - // Proportion Throttle (msec) - // >=1000 0 - // 900 3 - // 800 7 - // 700 11 - // 600 17 - // 500 25 - // 400 35 - // 300 50 - // 200 72 - // 125 100 - // 100 112 - // 50 146 - // 0 200 - - // (some evidence that we could go for a sharper kink - e.g. no throttling - // until below the 750 mark - might give fractionally more frames on a - // P60-ish machine). The easy way to get these coefficients is to use - // Renbase.xls follow the instructions therein using excel solver. - - if (q.Proportion>=1000) { m_trThrottle = 0; } - else { - // The DWORD is to make quite sure I get unsigned arithmetic - // as the constant is between 2**31 and 2**32 - m_trThrottle = -330000 + (388880000/(q.Proportion+167)); - } - return NOERROR; -} // Notify - - -// Send a message to indicate what our supplier should do about quality. -// Theory: -// What a supplier wants to know is "is the frame I'm working on NOW -// going to be late?". -// F1 is the frame at the supplier (as above) -// Tf1 is the due time for F1 -// T1 is the time at that point (NOW!) -// Tr1 is the time that f1 WILL actually be rendered -// L1 is the latency of the graph for frame F1 = Tr1-T1 -// D1 (for delay) is how late F1 will be beyond its due time i.e. -// D1 = (Tr1-Tf1) which is what the supplier really wants to know. -// Unfortunately Tr1 is in the future and is unknown, so is L1 -// -// We could estimate L1 by its value for a previous frame, -// L0 = Tr0-T0 and work off -// D1' = ((T1+L0)-Tf1) = (T1 + (Tr0-T0) -Tf1) -// Rearranging terms: -// D1' = (T1-T0) + (Tr0-Tf1) -// adding (Tf0-Tf0) and rearranging again: -// = (T1-T0) + (Tr0-Tf0) + (Tf0-Tf1) -// = (T1-T0) - (Tf1-Tf0) + (Tr0-Tf0) -// But (Tr0-Tf0) is just D0 - how late frame zero was, and this is the -// Late field in the quality message that we send. -// The other two terms just state what correction should be applied before -// using the lateness of F0 to predict the lateness of F1. -// (T1-T0) says how much time has actually passed (we have lost this much) -// (Tf1-Tf0) says how much time should have passed if we were keeping pace -// (we have gained this much). -// -// Suppliers should therefore work off: -// Quality.Late + (T1-T0) - (Tf1-Tf0) -// and see if this is "acceptably late" or even early (i.e. negative). -// They get T1 and T0 by polling the clock, they get Tf1 and Tf0 from -// the time stamps in the frames. They get Quality.Late from us. -// - -HRESULT CBaseVideoRenderer::SendQuality(REFERENCE_TIME trLate, - REFERENCE_TIME trRealStream) -{ - Quality q; - HRESULT hr; - - // If we are the main user of time, then report this as Flood/Dry. - // If our suppliers are, then report it as Famine/Glut. - // - // We need to take action, but avoid hunting. Hunting is caused by - // 1. Taking too much action too soon and overshooting - // 2. Taking too long to react (so averaging can CAUSE hunting). - // - // The reason why we use trLate as well as Wait is to reduce hunting; - // if the wait time is coming down and about to go into the red, we do - // NOT want to rely on some average which is only telling is that it used - // to be OK once. - - q.TimeStamp = (REFERENCE_TIME)trRealStream; - - if (m_trFrameAvg<0) { - q.Type = Famine; // guess - } - // Is the greater part of the time taken bltting or something else - else if (m_trFrameAvg > 2*m_trRenderAvg) { - q.Type = Famine; // mainly other - } else { - q.Type = Flood; // mainly bltting - } - - q.Proportion = 1000; // default - - if (m_trFrameAvg<0) { - // leave it alone - we don't know enough - } - else if ( trLate> 0 ) { - // try to catch up over the next second - // We could be Really, REALLY late, but rendering all the frames - // anyway, just because it's so cheap. - - q.Proportion = 1000 - (int)((trLate)/(UNITS/1000)); - if (q.Proportion<500) { - q.Proportion = 500; // don't go daft. (could've been negative!) - } else { - } - - } else if ( m_trWaitAvg>20000 - && trLate<-20000 - ){ - // Go cautiously faster - aim at 2mSec wait. - if (m_trWaitAvg>=m_trFrameAvg) { - // This can happen because of some fudges. - // The waitAvg is how long we originally planned to wait - // The frameAvg is more honest. - // It means that we are spending a LOT of time waiting - q.Proportion = 2000; // double. - } else { - if (m_trFrameAvg+20000 > m_trWaitAvg) { - q.Proportion - = 1000 * (m_trFrameAvg / (m_trFrameAvg + 20000 - m_trWaitAvg)); - } else { - // We're apparently spending more than the whole frame time waiting. - // Assume that the averages are slightly out of kilter, but that we - // are indeed doing a lot of waiting. (This leg probably never - // happens, but the code avoids any potential divide by zero). - q.Proportion = 2000; - } - } - - if (q.Proportion>2000) { - q.Proportion = 2000; // don't go crazy. - } - } - - // Tell the supplier how late frames are when they get rendered - // That's how late we are now. - // If we are in directdraw mode then the guy upstream can see the drawing - // times and we'll just report on the start time. He can figure out any - // offset to apply. If we are in DIB Section mode then we will apply an - // extra offset which is half of our drawing time. This is usually small - // but can sometimes be the dominant effect. For this we will use the - // average drawing time rather than the last frame. If the last frame took - // a long time to draw and made us late, that's already in the lateness - // figure. We should not add it in again unless we expect the next frame - // to be the same. We don't, we expect the average to be a better shot. - // In direct draw mode the RenderAvg will be zero. - - q.Late = trLate + m_trRenderAvg/2; - - // log what we're doing - MSR_INTEGER(m_idQualityRate, q.Proportion); - MSR_INTEGER( m_idQualityTime, (int)q.Late / 10000 ); - - // A specific sink interface may be set through IPin - - if (m_pQSink==NULL) { - // Get our input pin's peer. We send quality management messages - // to any nominated receiver of these things (set in the IPin - // interface), or else to our source filter. - - IQualityControl *pQC = NULL; - IPin *pOutputPin = m_pInputPin->GetConnected(); - ASSERT(pOutputPin != NULL); - - // And get an AddRef'd quality control interface - - hr = pOutputPin->QueryInterface(IID_IQualityControl,(void**) &pQC); - if (SUCCEEDED(hr)) { - m_pQSink = pQC; - } - } - if (m_pQSink) { - return m_pQSink->Notify(this,q); - } - - return S_FALSE; - -} // SendQuality - - -// We are called with a valid IMediaSample image to decide whether this is to -// be drawn or not. There must be a reference clock in operation. -// Return S_OK if it is to be drawn Now (as soon as possible) -// Return S_FALSE if it is to be drawn when it's due -// Return an error if we want to drop it -// m_nNormal=-1 indicates that we dropped the previous frame and so this -// one should be drawn early. Respect it and update it. -// Use current stream time plus a number of heuristics (detailed below) -// to make the decision - -HRESULT CBaseVideoRenderer::ShouldDrawSampleNow(IMediaSample *pMediaSample, - REFERENCE_TIME *ptrStart, - REFERENCE_TIME *ptrEnd) -{ - - // Don't call us unless there's a clock interface to synchronise with - ASSERT(m_pClock); - - MSR_INTEGER(m_idTimeStamp, (int)((*ptrStart)>>32)); // high order 32 bits - MSR_INTEGER(m_idTimeStamp, (int)(*ptrStart)); // low order 32 bits - - // We lose a bit of time depending on the monitor type waiting for the next - // screen refresh. On average this might be about 8mSec - so it will be - // later than we think when the picture appears. To compensate a bit - // we bias the media samples by -8mSec i.e. 80000 UNITs. - // We don't ever make a stream time negative (call it paranoia) - if (*ptrStart>=80000) { - *ptrStart -= 80000; - *ptrEnd -= 80000; // bias stop to to retain valid frame duration - } - - // Cache the time stamp now. We will want to compare what we did with what - // we started with (after making the monitor allowance). - m_trRememberStampForPerf = *ptrStart; - - // Get reference times (current and late) - REFERENCE_TIME trRealStream; // the real time now expressed as stream time. - m_pClock->GetTime(&trRealStream); -#ifdef PERF - // While the reference clock is expensive: - // Remember the offset from timeGetTime and use that. - // This overflows all over the place, but when we subtract to get - // differences the overflows all cancel out. - m_llTimeOffset = trRealStream-timeGetTime()*10000; -#endif - trRealStream -= m_tStart; // convert to stream time (this is a reftime) - - // We have to wory about two versions of "lateness". The truth, which we - // try to work out here and the one measured against m_trTarget which - // includes long term feedback. We report statistics against the truth - // but for operational decisions we work to the target. - // We use TimeDiff to make sure we get an integer because we - // may actually be late (or more likely early if there is a big time - // gap) by a very long time. - const int trTrueLate = TimeDiff(trRealStream - *ptrStart); - const int trLate = trTrueLate; - - MSR_INTEGER(m_idSchLateTime, trTrueLate/10000); - - // Send quality control messages upstream, measured against target - HRESULT hr = SendQuality(trLate, trRealStream); - // Note: the filter upstream is allowed to this FAIL meaning "you do it". - m_bSupplierHandlingQuality = (hr==S_OK); - - // Decision time! Do we drop, draw when ready or draw immediately? - - const int trDuration = (int)(*ptrEnd - *ptrStart); - { - // We need to see if the frame rate of the file has just changed. - // This would make comparing our previous frame rate with the current - // frame rate inefficent. Hang on a moment though. I've seen files - // where the frames vary between 33 and 34 mSec so as to average - // 30fps. A minor variation like that won't hurt us. - int t = m_trDuration/32; - if ( trDuration > m_trDuration+t - || trDuration < m_trDuration-t - ) { - // There's a major variation. Reset the average frame rate to - // exactly the current rate to disable decision 9002 for this frame, - // and remember the new rate. - m_trFrameAvg = trDuration; - m_trDuration = trDuration; - } - } - - MSR_INTEGER(m_idEarliness, m_trEarliness/10000); - MSR_INTEGER(m_idRenderAvg, m_trRenderAvg/10000); - MSR_INTEGER(m_idFrameAvg, m_trFrameAvg/10000); - MSR_INTEGER(m_idWaitAvg, m_trWaitAvg/10000); - MSR_INTEGER(m_idDuration, trDuration/10000); - -#ifdef PERF - if (S_OK==pMediaSample->IsDiscontinuity()) { - MSR_INTEGER(m_idDecision, 9000); - } -#endif - - // Control the graceful slide back from slow to fast machine mode. - // After a frame drop accept an early frame and set the earliness to here - // If this frame is already later than the earliness then slide it to here - // otherwise do the standard slide (reduce by about 12% per frame). - // Note: earliness is normally NEGATIVE - BOOL bJustDroppedFrame - = ( m_bSupplierHandlingQuality - // Can't use the pin sample properties because we might - // not be in Receive when we call this - && (S_OK == pMediaSample->IsDiscontinuity()) // he just dropped one - ) - || (m_nNormal==-1); // we just dropped one - - - // Set m_trEarliness (slide back from slow to fast machine mode) - if (trLate>0) { - m_trEarliness = 0; // we are no longer in fast machine mode at all! - } else if ( (trLate>=m_trEarliness) || bJustDroppedFrame) { - m_trEarliness = trLate; // Things have slipped of their own accord - } else { - m_trEarliness = m_trEarliness - m_trEarliness/8; // graceful slide - } - - // prepare the new wait average - but don't pollute the old one until - // we have finished with it. - int trWaitAvg; - { - // We never mix in a negative wait. This causes us to believe in fast machines - // slightly more. - int trL = trLate<0 ? -trLate : 0; - trWaitAvg = (trL + m_trWaitAvg*(AVGPERIOD-1))/AVGPERIOD; - } - - - int trFrame; - { - REFERENCE_TIME tr = trRealStream - m_trLastDraw; // Cd be large - 4 min pause! - if (tr>10000000) { - tr = 10000000; // 1 second - arbitrarily. - } - trFrame = int(tr); - } - - // We will DRAW this frame IF... - if ( - // ...the time we are spending drawing is a small fraction of the total - // observed inter-frame time so that dropping it won't help much. - (3*m_trRenderAvg <= m_trFrameAvg) - - // ...or our supplier is NOT handling things and the next frame would - // be less timely than this one or our supplier CLAIMS to be handling - // things, and is now less than a full FOUR frames late. - || ( m_bSupplierHandlingQuality - ? (trLate <= trDuration*4) - : (trLate+trLate < trDuration) - ) - - // ...or we are on average waiting for over eight milliseconds then - // this may be just a glitch. Draw it and we'll hope to catch up. - || (m_trWaitAvg > 80000) - - // ...or we haven't drawn an image for over a second. We will update - // the display, which stops the video looking hung. - // Do this regardless of how late this media sample is. - || ((trRealStream - m_trLastDraw) > UNITS) - - ) { - HRESULT Result; - - // We are going to play this frame. We may want to play it early. - // We will play it early if we think we are in slow machine mode. - // If we think we are NOT in slow machine mode, we will still play - // it early by m_trEarliness as this controls the graceful slide back. - // and in addition we aim at being m_trTarget late rather than "on time". - - BOOL bPlayASAP = FALSE; - - // we will play it AT ONCE (slow machine mode) if... - - // ...we are playing catch-up - if ( bJustDroppedFrame) { - bPlayASAP = TRUE; - MSR_INTEGER(m_idDecision, 9001); - } - - // ...or if we are running below the true frame rate - // exact comparisons are glitchy, for these measurements, - // so add an extra 5% or so - else if ( (m_trFrameAvg > trDuration + trDuration/16) - - // It's possible to get into a state where we are losing ground, but - // are a very long way ahead. To avoid this or recover from it - // we refuse to play early by more than 10 frames. - && (trLate > - trDuration*10) - ){ - bPlayASAP = TRUE; - MSR_INTEGER(m_idDecision, 9002); - } -#if 0 - // ...or if we have been late and are less than one frame early - else if ( (trLate + trDuration > 0) - && (m_trWaitAvg<=20000) - ) { - bPlayASAP = TRUE; - MSR_INTEGER(m_idDecision, 9003); - } -#endif - // We will NOT play it at once if we are grossly early. On very slow frame - // rate movies - e.g. clock.avi - it is not a good idea to leap ahead just - // because we got starved (for instance by the net) and dropped one frame - // some time or other. If we are more than 900mSec early, then wait. - if (trLate<-9000000) { - bPlayASAP = FALSE; - } - - if (bPlayASAP) { - - m_nNormal = 0; - MSR_INTEGER(m_idDecision, 0); - // When we are here, we are in slow-machine mode. trLate may well - // oscillate between negative and positive when the supplier is - // dropping frames to keep sync. We should not let that mislead - // us into thinking that we have as much as zero spare time! - // We just update with a zero wait. - m_trWaitAvg = (m_trWaitAvg*(AVGPERIOD-1))/AVGPERIOD; - - // Assume that we draw it immediately. Update inter-frame stats - m_trFrameAvg = (trFrame + m_trFrameAvg*(AVGPERIOD-1))/AVGPERIOD; -#ifndef PERF - // If this is NOT a perf build, then report what we know so far - // without looking at the clock any more. This assumes that we - // actually wait for exactly the time we hope to. It also reports - // how close we get to the manipulated time stamps that we now have - // rather than the ones we originally started with. It will - // therefore be a little optimistic. However it's fast. - PreparePerformanceData(trTrueLate, trFrame); -#endif - m_trLastDraw = trRealStream; - if (m_trEarliness > trLate) { - m_trEarliness = trLate; // if we are actually early, this is neg - } - Result = S_OK; // Draw it now - - } else { - ++m_nNormal; - // Set the average frame rate to EXACTLY the ideal rate. - // If we are exiting slow-machine mode then we will have caught up - // and be running ahead, so as we slide back to exact timing we will - // have a longer than usual gap at this point. If we record this - // real gap then we'll think that we're running slow and go back - // into slow-machine mode and vever get it straight. - m_trFrameAvg = trDuration; - MSR_INTEGER(m_idDecision, 1); - - // Play it early by m_trEarliness and by m_trTarget - - { - int trE = m_trEarliness; - if (trE < -m_trFrameAvg) { - trE = -m_trFrameAvg; - } - *ptrStart += trE; // N.B. earliness is negative - } - - int Delay = -trTrueLate; - Result = Delay<=0 ? S_OK : S_FALSE; // OK = draw now, FALSE = wait - - m_trWaitAvg = trWaitAvg; - - // Predict when it will actually be drawn and update frame stats - - if (Result==S_FALSE) { // We are going to wait - trFrame = TimeDiff(*ptrStart-m_trLastDraw); - m_trLastDraw = *ptrStart; - } else { - // trFrame is already = trRealStream-m_trLastDraw; - m_trLastDraw = trRealStream; - } -#ifndef PERF - int iAccuracy; - if (Delay>0) { - // Report lateness based on when we intend to play it - iAccuracy = TimeDiff(*ptrStart-m_trRememberStampForPerf); - } else { - // Report lateness based on playing it *now*. - iAccuracy = trTrueLate; // trRealStream-RememberStampForPerf; - } - PreparePerformanceData(iAccuracy, trFrame); -#endif - } - return Result; - } - - // We are going to drop this frame! - // Of course in DirectDraw mode the guy upstream may draw it anyway. - - // This will probably give a large negative wack to the wait avg. - m_trWaitAvg = trWaitAvg; - -#ifdef PERF - // Respect registry setting - debug only! - if (m_bDrawLateFrames) { - return S_OK; // draw it when it's ready - } // even though it's late. -#endif - - // We are going to drop this frame so draw the next one early - // n.b. if the supplier is doing direct draw then he may draw it anyway - // but he's doing something funny to arrive here in that case. - - MSR_INTEGER(m_idDecision, 2); - m_nNormal = -1; - return E_FAIL; // drop it - -} // ShouldDrawSampleNow - - -// NOTE we're called by both the window thread and the source filter thread -// so we have to be protected by a critical section (locked before called) -// Also, when the window thread gets signalled to render an image, it always -// does so regardless of how late it is. All the degradation is done when we -// are scheduling the next sample to be drawn. Hence when we start an advise -// link to draw a sample, that sample's time will always become the last one -// drawn - unless of course we stop streaming in which case we cancel links - -BOOL CBaseVideoRenderer::ScheduleSample(IMediaSample *pMediaSample) -{ - // We override ShouldDrawSampleNow to add quality management - - BOOL bDrawImage = CBaseRenderer::ScheduleSample(pMediaSample); - if (bDrawImage == FALSE) { - ++m_cFramesDropped; - return FALSE; - } - - // m_cFramesDrawn must NOT be updated here. It has to be updated - // in RecordFrameLateness at the same time as the other statistics. - return TRUE; -} - - -// Implementation of IQualProp interface needed to support the property page -// This is how the property page gets the data out of the scheduler. We are -// passed into the constructor the owning object in the COM sense, this will -// either be the video renderer or an external IUnknown if we're aggregated. -// We initialise our CUnknown base class with this interface pointer. Then -// all we have to do is to override NonDelegatingQueryInterface to expose -// our IQualProp interface. The AddRef and Release are handled automatically -// by the base class and will be passed on to the appropriate outer object - -STDMETHODIMP CBaseVideoRenderer::get_FramesDroppedInRenderer(int *pcFramesDropped) -{ - CheckPointer(pcFramesDropped,E_POINTER); - CAutoLock cVideoLock(&m_InterfaceLock); - *pcFramesDropped = m_cFramesDropped; - return NOERROR; -} // get_FramesDroppedInRenderer - - -// Set *pcFramesDrawn to the number of frames drawn since -// streaming started. - -STDMETHODIMP CBaseVideoRenderer::get_FramesDrawn( int *pcFramesDrawn) -{ - CheckPointer(pcFramesDrawn,E_POINTER); - CAutoLock cVideoLock(&m_InterfaceLock); - *pcFramesDrawn = m_cFramesDrawn; - return NOERROR; -} // get_FramesDrawn - - -// Set iAvgFrameRate to the frames per hundred secs since -// streaming started. 0 otherwise. - -STDMETHODIMP CBaseVideoRenderer::get_AvgFrameRate( int *piAvgFrameRate) -{ - CheckPointer(piAvgFrameRate,E_POINTER); - CAutoLock cVideoLock(&m_InterfaceLock); - - int t; - if (m_bStreaming) { - t = timeGetTime()-m_tStreamingStart; - } else { - t = m_tStreamingStart; - } - - if (t<=0) { - *piAvgFrameRate = 0; - ASSERT(m_cFramesDrawn == 0); - } else { - // i is frames per hundred seconds - *piAvgFrameRate = MulDiv(100000, m_cFramesDrawn, t); - } - return NOERROR; -} // get_AvgFrameRate - - -// Set *piAvg to the average sync offset since streaming started -// in mSec. The sync offset is the time in mSec between when the frame -// should have been drawn and when the frame was actually drawn. - -STDMETHODIMP CBaseVideoRenderer::get_AvgSyncOffset( int *piAvg) -{ - CheckPointer(piAvg,E_POINTER); - CAutoLock cVideoLock(&m_InterfaceLock); - - if (NULL==m_pClock) { - *piAvg = 0; - return NOERROR; - } - - // Note that we didn't gather the stats on the first frame - // so we use m_cFramesDrawn-1 here - if (m_cFramesDrawn<=1) { - *piAvg = 0; - } else { - *piAvg = (int)(m_iTotAcc / (m_cFramesDrawn-1)); - } - return NOERROR; -} // get_AvgSyncOffset - - -// To avoid dragging in the maths library - a cheap -// approximate integer square root. -// We do this by getting a starting guess which is between 1 -// and 2 times too large, followed by THREE iterations of -// Newton Raphson. (That will give accuracy to the nearest mSec -// for the range in question - roughly 0..1000) -// -// It would be faster to use a linear interpolation and ONE NR, but -// who cares. If anyone does - the best linear interpolation is -// to approximates sqrt(x) by -// y = x * (sqrt(2)-1) + 1 - 1/sqrt(2) + 1/(8*(sqrt(2)-1)) -// 0r y = x*0.41421 + 0.59467 -// This minimises the maximal error in the range in question. -// (error is about +0.008883 and then one NR will give error .0000something -// (Of course these are integers, so you can't just multiply by 0.41421 -// you'd have to do some sort of MulDiv). -// Anyone wanna check my maths? (This is only for a property display!) - -int isqrt(int x) -{ - int s = 1; - // Make s an initial guess for sqrt(x) - if (x > 0x40000000) { - s = 0x8000; // prevent any conceivable closed loop - } else { - while (s*s=0) s = (s*s+x)/(2*s); - if (s>=0) s = (s*s+x)/(2*s); - } - } - return s; -} - -// -// Do estimates for standard deviations for per-frame -// statistics -// -HRESULT CBaseVideoRenderer::GetStdDev( - int nSamples, - int *piResult, - LONGLONG llSumSq, - LONGLONG iTot -) -{ - CheckPointer(piResult,E_POINTER); - CAutoLock cVideoLock(&m_InterfaceLock); - - if (NULL==m_pClock) { - *piResult = 0; - return NOERROR; - } - - // If S is the Sum of the Squares of observations and - // T the Total (i.e. sum) of the observations and there were - // N observations, then an estimate of the standard deviation is - // sqrt( (S - T**2/N) / (N-1) ) - - if (nSamples<=1) { - *piResult = 0; - } else { - LONGLONG x; - // First frames have invalid stamps, so we get no stats for them - // So we need 2 frames to get 1 datum, so N is cFramesDrawn-1 - - // so we use m_cFramesDrawn-1 here - x = llSumSq - llMulDiv(iTot, iTot, nSamples, 0); - x = x / (nSamples-1); - ASSERT(x>=0); - *piResult = isqrt((LONG)x); - } - return NOERROR; -} - -// Set *piDev to the standard deviation in mSec of the sync offset -// of each frame since streaming started. - -STDMETHODIMP CBaseVideoRenderer::get_DevSyncOffset( int *piDev) -{ - // First frames have invalid stamps, so we get no stats for them - // So we need 2 frames to get 1 datum, so N is cFramesDrawn-1 - return GetStdDev(m_cFramesDrawn - 1, - piDev, - m_iSumSqAcc, - m_iTotAcc); -} // get_DevSyncOffset - - -// Set *piJitter to the standard deviation in mSec of the inter-frame time -// of frames since streaming started. - -STDMETHODIMP CBaseVideoRenderer::get_Jitter( int *piJitter) -{ - // First frames have invalid stamps, so we get no stats for them - // So second frame gives invalid inter-frame time - // So we need 3 frames to get 1 datum, so N is cFramesDrawn-2 - return GetStdDev(m_cFramesDrawn - 2, - piJitter, - m_iSumSqFrameTime, - m_iSumFrameTime); -} // get_Jitter - - -// Overidden to return our IQualProp interface - -STDMETHODIMP -CBaseVideoRenderer::NonDelegatingQueryInterface(REFIID riid,VOID **ppv) -{ - // We return IQualProp and delegate everything else - - if (riid == IID_IQualProp) { - return GetInterface( (IQualProp *)this, ppv); - } else if (riid == IID_IQualityControl) { - return GetInterface( (IQualityControl *)this, ppv); - } - return CBaseRenderer::NonDelegatingQueryInterface(riid,ppv); -} - - -// Override JoinFilterGraph so that, just before leaving -// the graph we can send an EC_WINDOW_DESTROYED event - -STDMETHODIMP -CBaseVideoRenderer::JoinFilterGraph(IFilterGraph *pGraph,LPCWSTR pName) -{ - // Since we send EC_ACTIVATE, we also need to ensure - // we send EC_WINDOW_DESTROYED or the resource manager may be - // holding us as a focus object - if (!pGraph && m_pGraph) { - - // We were in a graph and now we're not - // Do this properly in case we are aggregated - IBaseFilter* pFilter; - QueryInterface(IID_IBaseFilter,(void **) &pFilter); - NotifyEvent(EC_WINDOW_DESTROYED, (LPARAM) pFilter, 0); - pFilter->Release(); - } - return CBaseFilter::JoinFilterGraph(pGraph, pName); -} - - -// This removes a large number of level 4 warnings from the -// Microsoft compiler which in this case are not very useful -#pragma warning(disable: 4514) - +//------------------------------------------------------------------------------ +// File: RenBase.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" // DirectShow base class definitions +#include // Needed for definition of timeGetTime +#include // Standard data type limit definitions +#include "measure.h" // Used for time critical log functions + +#pragma warning(disable:4355) + +// Helper function for clamping time differences +int inline TimeDiff(REFERENCE_TIME rt) +{ + if (rt < - (50 * UNITS)) { + return -(50 * UNITS); + } else + if (rt > 50 * UNITS) { + return 50 * UNITS; + } else return (int)rt; +} + +// Implements the CBaseRenderer class + +CBaseRenderer::CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer + TCHAR *pName, // Debug ONLY description + LPUNKNOWN pUnk, // Aggregated owner object + HRESULT *phr) : // General OLE return code + + CBaseFilter(pName,pUnk,&m_InterfaceLock,RenderClass), + m_evComplete(TRUE), + m_bAbort(FALSE), + m_pPosition(NULL), + m_ThreadSignal(TRUE), + m_bStreaming(FALSE), + m_bEOS(FALSE), + m_bEOSDelivered(FALSE), + m_pMediaSample(NULL), + m_dwAdvise(0), + m_pQSink(NULL), + m_pInputPin(NULL), + m_bRepaintStatus(TRUE), + m_SignalTime(0), + m_bInReceive(FALSE), + m_EndOfStreamTimer(0) +{ + Ready(); +#ifdef PERF + m_idBaseStamp = MSR_REGISTER(TEXT("BaseRenderer: sample time stamp")); + m_idBaseRenderTime = MSR_REGISTER(TEXT("BaseRenderer: draw time (msec)")); + m_idBaseAccuracy = MSR_REGISTER(TEXT("BaseRenderer: Accuracy (msec)")); +#endif +} + + +// Delete the dynamically allocated IMediaPosition and IMediaSeeking helper +// object. The object is created when somebody queries us. These are standard +// control interfaces for seeking and setting start/stop positions and rates. +// We will probably also have made an input pin based on CRendererInputPin +// that has to be deleted, it's created when an enumerator calls our GetPin + +CBaseRenderer::~CBaseRenderer() +{ + ASSERT(m_bStreaming == FALSE); + ASSERT(m_EndOfStreamTimer == 0); + StopStreaming(); + ClearPendingSample(); + + // Delete any IMediaPosition implementation + + if (m_pPosition) { + delete m_pPosition; + m_pPosition = NULL; + } + + // Delete any input pin created + + if (m_pInputPin) { + delete m_pInputPin; + m_pInputPin = NULL; + } + + // Release any Quality sink + + ASSERT(m_pQSink == NULL); +} + + +// This returns the IMediaPosition and IMediaSeeking interfaces + +HRESULT CBaseRenderer::GetMediaPositionInterface(REFIID riid,void **ppv) +{ + CAutoLock cObjectCreationLock(&m_ObjectCreationLock); + if (m_pPosition) { + return m_pPosition->NonDelegatingQueryInterface(riid,ppv); + } + + HRESULT hr = NOERROR; + + // Create implementation of this dynamically since sometimes we may + // never try and do a seek. The helper object implements a position + // control interface (IMediaPosition) which in fact simply takes the + // calls normally from the filter graph and passes them upstream + + m_pPosition = new CRendererPosPassThru(NAME("Renderer CPosPassThru"), + CBaseFilter::GetOwner(), + (HRESULT *) &hr, + GetPin(0)); + if (m_pPosition == NULL) { + return E_OUTOFMEMORY; + } + + if (FAILED(hr)) { + delete m_pPosition; + m_pPosition = NULL; + return E_NOINTERFACE; + } + return GetMediaPositionInterface(riid,ppv); +} + + +// Overriden to say what interfaces we support and where + +STDMETHODIMP CBaseRenderer::NonDelegatingQueryInterface(REFIID riid,void **ppv) +{ + // Do we have this interface + + if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { + return GetMediaPositionInterface(riid,ppv); + } else { + return CBaseFilter::NonDelegatingQueryInterface(riid,ppv); + } +} + + +// This is called whenever we change states, we have a manual reset event that +// is signalled whenever we don't won't the source filter thread to wait in us +// (such as in a stopped state) and likewise is not signalled whenever it can +// wait (during paused and running) this function sets or resets the thread +// event. The event is used to stop source filter threads waiting in Receive + +HRESULT CBaseRenderer::SourceThreadCanWait(BOOL bCanWait) +{ + if (bCanWait == TRUE) { + m_ThreadSignal.Reset(); + } else { + m_ThreadSignal.Set(); + } + return NOERROR; +} + + +#ifdef DEBUG +// Dump the current renderer state to the debug terminal. The hardest part of +// the renderer is the window where we unlock everything to wait for a clock +// to signal it is time to draw or for the application to cancel everything +// by stopping the filter. If we get things wrong we can leave the thread in +// WaitForRenderTime with no way for it to ever get out and we will deadlock + +void CBaseRenderer::DisplayRendererState() +{ + DbgLog((LOG_TIMING, 1, TEXT("\nTimed out in WaitForRenderTime"))); + + // No way should this be signalled at this point + + BOOL bSignalled = m_ThreadSignal.Check(); + DbgLog((LOG_TIMING, 1, TEXT("Signal sanity check %d"),bSignalled)); + + // Now output the current renderer state variables + + DbgLog((LOG_TIMING, 1, TEXT("Filter state %d"),m_State)); + + DbgLog((LOG_TIMING, 1, TEXT("Abort flag %d"),m_bAbort)); + + DbgLog((LOG_TIMING, 1, TEXT("Streaming flag %d"),m_bStreaming)); + + DbgLog((LOG_TIMING, 1, TEXT("Clock advise link %d"),m_dwAdvise)); + + DbgLog((LOG_TIMING, 1, TEXT("Current media sample %x"),m_pMediaSample)); + + DbgLog((LOG_TIMING, 1, TEXT("EOS signalled %d"),m_bEOS)); + + DbgLog((LOG_TIMING, 1, TEXT("EOS delivered %d"),m_bEOSDelivered)); + + DbgLog((LOG_TIMING, 1, TEXT("Repaint status %d"),m_bRepaintStatus)); + + + // Output the delayed end of stream timer information + + DbgLog((LOG_TIMING, 1, TEXT("End of stream timer %x"),m_EndOfStreamTimer)); + + DbgLog((LOG_TIMING, 1, TEXT("Deliver time %s"),CDisp((LONGLONG)m_SignalTime))); + + + // Should never timeout during a flushing state + + BOOL bFlushing = m_pInputPin->IsFlushing(); + DbgLog((LOG_TIMING, 1, TEXT("Flushing sanity check %d"),bFlushing)); + + // Display the time we were told to start at + DbgLog((LOG_TIMING, 1, TEXT("Last run time %s"),CDisp((LONGLONG)m_tStart.m_time))); + + // Have we got a reference clock + if (m_pClock == NULL) return; + + // Get the current time from the wall clock + + CRefTime CurrentTime,StartTime,EndTime; + m_pClock->GetTime((REFERENCE_TIME*) &CurrentTime); + CRefTime Offset = CurrentTime - m_tStart; + + // Display the current time from the clock + + DbgLog((LOG_TIMING, 1, TEXT("Clock time %s"),CDisp((LONGLONG)CurrentTime.m_time))); + + DbgLog((LOG_TIMING, 1, TEXT("Time difference %dms"),Offset.Millisecs())); + + + // Do we have a sample ready to render + if (m_pMediaSample == NULL) return; + + m_pMediaSample->GetTime((REFERENCE_TIME*)&StartTime, (REFERENCE_TIME*)&EndTime); + DbgLog((LOG_TIMING, 1, TEXT("Next sample stream times (Start %d End %d ms)"), + StartTime.Millisecs(),EndTime.Millisecs())); + + // Calculate how long it is until it is due for rendering + CRefTime Wait = (m_tStart + StartTime) - CurrentTime; + DbgLog((LOG_TIMING, 1, TEXT("Wait required %d ms"),Wait.Millisecs())); +} +#endif + + +// Wait until the clock sets the timer event or we're otherwise signalled. We +// set an arbitrary timeout for this wait and if it fires then we display the +// current renderer state on the debugger. It will often fire if the filter's +// left paused in an application however it may also fire during stress tests +// if the synchronisation with application seeks and state changes is faulty + +#define RENDER_TIMEOUT 10000 + +HRESULT CBaseRenderer::WaitForRenderTime() +{ + HANDLE WaitObjects[] = { m_ThreadSignal, m_RenderEvent }; + DWORD Result = WAIT_TIMEOUT; + + // Wait for either the time to arrive or for us to be stopped + + OnWaitStart(); + while (Result == WAIT_TIMEOUT) { + Result = WaitForMultipleObjects(2,WaitObjects,FALSE,RENDER_TIMEOUT); + +#ifdef DEBUG + if (Result == WAIT_TIMEOUT) DisplayRendererState(); +#endif + + } + OnWaitEnd(); + + // We may have been awoken without the timer firing + + if (Result == WAIT_OBJECT_0) { + return VFW_E_STATE_CHANGED; + } + + SignalTimerFired(); + return NOERROR; +} + + +// Poll waiting for Receive to complete. This really matters when +// Receive may set the palette and cause window messages +// The problem is that if we don't really wait for a renderer to +// stop processing we can deadlock waiting for a transform which +// is calling the renderer's Receive() method because the transform's +// Stop method doesn't know to process window messages to unblock +// the renderer's Receive processing +void CBaseRenderer::WaitForReceiveToComplete() +{ + for (;;) { + if (!m_bInReceive) { + break; + } + + MSG msg; + // Receive all interthread sendmessages + PeekMessage(&msg, NULL, WM_NULL, WM_NULL, PM_NOREMOVE); + + Sleep(1); + } + + // If the wakebit for QS_POSTMESSAGE is set, the PeekMessage call + // above just cleared the changebit which will cause some messaging + // calls to block (waitMessage, MsgWaitFor...) now. + // Post a dummy message to set the QS_POSTMESSAGE bit again + if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) { + // Send dummy message + PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0); + } +} + +// A filter can have four discrete states, namely Stopped, Running, Paused, +// Intermediate. We are in an intermediate state if we are currently trying +// to pause but haven't yet got the first sample (or if we have been flushed +// in paused state and therefore still have to wait for a sample to arrive) + +// This class contains an event called m_evComplete which is signalled when +// the current state is completed and is not signalled when we are waiting to +// complete the last state transition. As mentioned above the only time we +// use this at the moment is when we wait for a media sample in paused state +// If while we are waiting we receive an end of stream notification from the +// source filter then we know no data is imminent so we can reset the event +// This means that when we transition to paused the source filter must call +// end of stream on us or send us an image otherwise we'll hang indefinately + + +// Simple internal way of getting the real state + +FILTER_STATE CBaseRenderer::GetRealState() { + return m_State; +} + + +// The renderer doesn't complete the full transition to paused states until +// it has got one media sample to render. If you ask it for its state while +// it's waiting it will return the state along with VFW_S_STATE_INTERMEDIATE + +STDMETHODIMP CBaseRenderer::GetState(DWORD dwMSecs,FILTER_STATE *State) +{ + CheckPointer(State,E_POINTER); + + if (WaitDispatchingMessages(m_evComplete, dwMSecs) == WAIT_TIMEOUT) { + *State = m_State; + return VFW_S_STATE_INTERMEDIATE; + } + *State = m_State; + return NOERROR; +} + + +// If we're pausing and we have no samples we don't complete the transition +// to State_Paused and we return S_FALSE. However if the m_bAbort flag has +// been set then all samples are rejected so there is no point waiting for +// one. If we do have a sample then return NOERROR. We will only ever return +// VFW_S_STATE_INTERMEDIATE from GetState after being paused with no sample +// (calling GetState after either being stopped or Run will NOT return this) + +HRESULT CBaseRenderer::CompleteStateChange(FILTER_STATE OldState) +{ + // Allow us to be paused when disconnected + + if (m_pInputPin->IsConnected() == FALSE) { + Ready(); + return S_OK; + } + + // Have we run off the end of stream + + if (IsEndOfStream() == TRUE) { + Ready(); + return S_OK; + } + + // Make sure we get fresh data after being stopped + + if (HaveCurrentSample() == TRUE) { + if (OldState != State_Stopped) { + Ready(); + return S_OK; + } + } + NotReady(); + return S_FALSE; +} + + +// When we stop the filter the things we do are:- + +// Decommit the allocator being used in the connection +// Release the source filter if it's waiting in Receive +// Cancel any advise link we set up with the clock +// Any end of stream signalled is now obsolete so reset +// Allow us to be stopped when we are not connected + +STDMETHODIMP CBaseRenderer::Stop() +{ + CAutoLock cRendererLock(&m_InterfaceLock); + + // Make sure there really is a state change + + if (m_State == State_Stopped) { + return NOERROR; + } + + // Is our input pin connected + + if (m_pInputPin->IsConnected() == FALSE) { + NOTE("Input pin is not connected"); + m_State = State_Stopped; + return NOERROR; + } + + CBaseFilter::Stop(); + + // If we are going into a stopped state then we must decommit whatever + // allocator we are using it so that any source filter waiting in the + // GetBuffer can be released and unlock themselves for a state change + + if (m_pInputPin->Allocator()) { + m_pInputPin->Allocator()->Decommit(); + } + + // Cancel any scheduled rendering + + SetRepaintStatus(TRUE); + StopStreaming(); + SourceThreadCanWait(FALSE); + ResetEndOfStream(); + CancelNotification(); + + // There should be no outstanding clock advise + ASSERT(CancelNotification() == S_FALSE); + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(m_EndOfStreamTimer == 0); + + Ready(); + WaitForReceiveToComplete(); + m_bAbort = FALSE; + + return NOERROR; +} + + +// When we pause the filter the things we do are:- + +// Commit the allocator being used in the connection +// Allow a source filter thread to wait in Receive +// Cancel any clock advise link (we may be running) +// Possibly complete the state change if we have data +// Allow us to be paused when we are not connected + +STDMETHODIMP CBaseRenderer::Pause() +{ + CAutoLock cRendererLock(&m_InterfaceLock); + FILTER_STATE OldState = m_State; + ASSERT(m_pInputPin->IsFlushing() == FALSE); + + // Make sure there really is a state change + + if (m_State == State_Paused) { + return CompleteStateChange(State_Paused); + } + + // Has our input pin been connected + + if (m_pInputPin->IsConnected() == FALSE) { + NOTE("Input pin is not connected"); + m_State = State_Paused; + return CompleteStateChange(State_Paused); + } + + // Pause the base filter class + + HRESULT hr = CBaseFilter::Pause(); + if (FAILED(hr)) { + NOTE("Pause failed"); + return hr; + } + + // Enable EC_REPAINT events again + + SetRepaintStatus(TRUE); + StopStreaming(); + SourceThreadCanWait(TRUE); + CancelNotification(); + ResetEndOfStreamTimer(); + + // If we are going into a paused state then we must commit whatever + // allocator we are using it so that any source filter can call the + // GetBuffer and expect to get a buffer without returning an error + + if (m_pInputPin->Allocator()) { + m_pInputPin->Allocator()->Commit(); + } + + // There should be no outstanding advise + ASSERT(CancelNotification() == S_FALSE); + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(m_EndOfStreamTimer == 0); + ASSERT(m_pInputPin->IsFlushing() == FALSE); + + // When we come out of a stopped state we must clear any image we were + // holding onto for frame refreshing. Since renderers see state changes + // first we can reset ourselves ready to accept the source thread data + // Paused or running after being stopped causes the current position to + // be reset so we're not interested in passing end of stream signals + + if (OldState == State_Stopped) { + m_bAbort = FALSE; + ClearPendingSample(); + } + return CompleteStateChange(OldState); +} + + +// When we run the filter the things we do are:- + +// Commit the allocator being used in the connection +// Allow a source filter thread to wait in Receive +// Signal the render event just to get us going +// Start the base class by calling StartStreaming +// Allow us to be run when we are not connected +// Signal EC_COMPLETE if we are not connected + +STDMETHODIMP CBaseRenderer::Run(REFERENCE_TIME StartTime) +{ + CAutoLock cRendererLock(&m_InterfaceLock); + FILTER_STATE OldState = m_State; + + // Make sure there really is a state change + + if (m_State == State_Running) { + return NOERROR; + } + + // Send EC_COMPLETE if we're not connected + + if (m_pInputPin->IsConnected() == FALSE) { + NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this); + m_State = State_Running; + return NOERROR; + } + + Ready(); + + // Pause the base filter class + + HRESULT hr = CBaseFilter::Run(StartTime); + if (FAILED(hr)) { + NOTE("Run failed"); + return hr; + } + + // Allow the source thread to wait + ASSERT(m_pInputPin->IsFlushing() == FALSE); + SourceThreadCanWait(TRUE); + SetRepaintStatus(FALSE); + + // There should be no outstanding advise + ASSERT(CancelNotification() == S_FALSE); + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(m_EndOfStreamTimer == 0); + ASSERT(m_pInputPin->IsFlushing() == FALSE); + + // If we are going into a running state then we must commit whatever + // allocator we are using it so that any source filter can call the + // GetBuffer and expect to get a buffer without returning an error + + if (m_pInputPin->Allocator()) { + m_pInputPin->Allocator()->Commit(); + } + + // When we come out of a stopped state we must clear any image we were + // holding onto for frame refreshing. Since renderers see state changes + // first we can reset ourselves ready to accept the source thread data + // Paused or running after being stopped causes the current position to + // be reset so we're not interested in passing end of stream signals + + if (OldState == State_Stopped) { + m_bAbort = FALSE; + ClearPendingSample(); + } + return StartStreaming(); +} + + +// Return the number of input pins we support + +int CBaseRenderer::GetPinCount() +{ + return 1; +} + + +// We only support one input pin and it is numbered zero + +CBasePin *CBaseRenderer::GetPin(int n) +{ + CAutoLock cObjectCreationLock(&m_ObjectCreationLock); + + // Should only ever be called with zero + ASSERT(n == 0); + + if (n != 0) { + return NULL; + } + + // Create the input pin if not already done so + + if (m_pInputPin == NULL) { + + // hr must be initialized to NOERROR because + // CRendererInputPin's constructor only changes + // hr's value if an error occurs. + HRESULT hr = NOERROR; + + m_pInputPin = new CRendererInputPin(this,&hr,L"In"); + if (NULL == m_pInputPin) { + return NULL; + } + + if (FAILED(hr)) { + delete m_pInputPin; + m_pInputPin = NULL; + return NULL; + } + } + return m_pInputPin; +} + + +// If "In" then return the IPin for our input pin, otherwise NULL and error + +STDMETHODIMP CBaseRenderer::FindPin(LPCWSTR Id, IPin **ppPin) +{ + CheckPointer(ppPin,E_POINTER); + + if (0==lstrcmpW(Id,L"In")) { + *ppPin = GetPin(0); + ASSERT(*ppPin); + (*ppPin)->AddRef(); + } else { + *ppPin = NULL; + return VFW_E_NOT_FOUND; + } + return NOERROR; +} + + +// Called when the input pin receives an EndOfStream notification. If we have +// not got a sample, then notify EC_COMPLETE now. If we have samples, then set +// m_bEOS and check for this on completing samples. If we're waiting to pause +// then complete the transition to paused state by setting the state event + +HRESULT CBaseRenderer::EndOfStream() +{ + // Ignore these calls if we are stopped + + if (m_State == State_Stopped) { + return NOERROR; + } + + // If we have a sample then wait for it to be rendered + + m_bEOS = TRUE; + if (m_pMediaSample) { + return NOERROR; + } + + // If we are waiting for pause then we are now ready since we cannot now + // carry on waiting for a sample to arrive since we are being told there + // won't be any. This sets an event that the GetState function picks up + + Ready(); + + // Only signal completion now if we are running otherwise queue it until + // we do run in StartStreaming. This is used when we seek because a seek + // causes a pause where early notification of completion is misleading + + if (m_bStreaming) { + SendEndOfStream(); + } + return NOERROR; +} + + +// When we are told to flush we should release the source thread + +HRESULT CBaseRenderer::BeginFlush() +{ + // If paused then report state intermediate until we get some data + + if (m_State == State_Paused) { + NotReady(); + } + + SourceThreadCanWait(FALSE); + CancelNotification(); + ClearPendingSample(); + // Wait for Receive to complete + WaitForReceiveToComplete(); + + return NOERROR; +} + + +// After flushing the source thread can wait in Receive again + +HRESULT CBaseRenderer::EndFlush() +{ + // Reset the current sample media time + if (m_pPosition) m_pPosition->ResetMediaTime(); + + // There should be no outstanding advise + + ASSERT(CancelNotification() == S_FALSE); + SourceThreadCanWait(TRUE); + return NOERROR; +} + + +// We can now send EC_REPAINTs if so required + +HRESULT CBaseRenderer::CompleteConnect(IPin *pReceivePin) +{ + // The caller should always hold the interface lock because + // the function uses CBaseFilter::m_State. + ASSERT(CritCheckIn(&m_InterfaceLock)); + + m_bAbort = FALSE; + + if (State_Running == GetRealState()) { + HRESULT hr = StartStreaming(); + if (FAILED(hr)) { + return hr; + } + + SetRepaintStatus(FALSE); + } else { + SetRepaintStatus(TRUE); + } + + return NOERROR; +} + + +// Called when we go paused or running + +HRESULT CBaseRenderer::Active() +{ + return NOERROR; +} + + +// Called when we go into a stopped state + +HRESULT CBaseRenderer::Inactive() +{ + if (m_pPosition) { + m_pPosition->ResetMediaTime(); + } + // People who derive from this may want to override this behaviour + // to keep hold of the sample in some circumstances + ClearPendingSample(); + + return NOERROR; +} + + +// Tell derived classes about the media type agreed + +HRESULT CBaseRenderer::SetMediaType(const CMediaType *pmt) +{ + return NOERROR; +} + + +// When we break the input pin connection we should reset the EOS flags. When +// we are asked for either IMediaPosition or IMediaSeeking we will create a +// CPosPassThru object to handles media time pass through. When we're handed +// samples we store (by calling CPosPassThru::RegisterMediaTime) their media +// times so we can then return a real current position of data being rendered + +HRESULT CBaseRenderer::BreakConnect() +{ + // Do we have a quality management sink + + if (m_pQSink) { + m_pQSink->Release(); + m_pQSink = NULL; + } + + // Check we have a valid connection + + if (m_pInputPin->IsConnected() == FALSE) { + return S_FALSE; + } + + // Check we are stopped before disconnecting + if (m_State != State_Stopped && !m_pInputPin->CanReconnectWhenActive()) { + return VFW_E_NOT_STOPPED; + } + + SetRepaintStatus(FALSE); + ResetEndOfStream(); + ClearPendingSample(); + m_bAbort = FALSE; + + if (State_Running == m_State) { + StopStreaming(); + } + + return NOERROR; +} + + +// Retrieves the sample times for this samples (note the sample times are +// passed in by reference not value). We return S_FALSE to say schedule this +// sample according to the times on the sample. We also return S_OK in +// which case the object should simply render the sample data immediately + +HRESULT CBaseRenderer::GetSampleTimes(IMediaSample *pMediaSample, + REFERENCE_TIME *pStartTime, + REFERENCE_TIME *pEndTime) +{ + ASSERT(m_dwAdvise == 0); + ASSERT(pMediaSample); + + // If the stop time for this sample is before or the same as start time, + // then just ignore it (release it) and schedule the next one in line + // Source filters should always fill in the start and end times properly! + + if (SUCCEEDED(pMediaSample->GetTime(pStartTime, pEndTime))) { + if (*pEndTime < *pStartTime) { + return VFW_E_START_TIME_AFTER_END; + } + } else { + // no time set in the sample... draw it now? + return S_OK; + } + + // Can't synchronise without a clock so we return S_OK which tells the + // caller that the sample should be rendered immediately without going + // through the overhead of setting a timer advise link with the clock + + if (m_pClock == NULL) { + return S_OK; + } + return ShouldDrawSampleNow(pMediaSample,pStartTime,pEndTime); +} + + +// By default all samples are drawn according to their time stamps so we +// return S_FALSE. Returning S_OK means draw immediately, this is used +// by the derived video renderer class in its quality management. + +HRESULT CBaseRenderer::ShouldDrawSampleNow(IMediaSample *pMediaSample, + REFERENCE_TIME *ptrStart, + REFERENCE_TIME *ptrEnd) +{ + return S_FALSE; +} + + +// We must always reset the current advise time to zero after a timer fires +// because there are several possible ways which lead us not to do any more +// scheduling such as the pending image being cleared after state changes + +void CBaseRenderer::SignalTimerFired() +{ + m_dwAdvise = 0; +} + + +// Cancel any notification currently scheduled. This is called by the owning +// window object when it is told to stop streaming. If there is no timer link +// outstanding then calling this is benign otherwise we go ahead and cancel +// We must always reset the render event as the quality management code can +// signal immediate rendering by setting the event without setting an advise +// link. If we're subsequently stopped and run the first attempt to setup an +// advise link with the reference clock will find the event still signalled + +HRESULT CBaseRenderer::CancelNotification() +{ + ASSERT(m_dwAdvise == 0 || m_pClock); + DWORD_PTR dwAdvise = m_dwAdvise; + + // Have we a live advise link + + if (m_dwAdvise) { + m_pClock->Unadvise(m_dwAdvise); + SignalTimerFired(); + ASSERT(m_dwAdvise == 0); + } + + // Clear the event and return our status + + m_RenderEvent.Reset(); + return (dwAdvise ? S_OK : S_FALSE); +} + + +// Responsible for setting up one shot advise links with the clock +// Return FALSE if the sample is to be dropped (not drawn at all) +// Return TRUE if the sample is to be drawn and in this case also +// arrange for m_RenderEvent to be set at the appropriate time + +BOOL CBaseRenderer::ScheduleSample(IMediaSample *pMediaSample) +{ + REFERENCE_TIME StartSample, EndSample; + + // Is someone pulling our leg + + if (pMediaSample == NULL) { + return FALSE; + } + + // Get the next sample due up for rendering. If there aren't any ready + // then GetNextSampleTimes returns an error. If there is one to be done + // then it succeeds and yields the sample times. If it is due now then + // it returns S_OK other if it's to be done when due it returns S_FALSE + + HRESULT hr = GetSampleTimes(pMediaSample, &StartSample, &EndSample); + if (FAILED(hr)) { + return FALSE; + } + + // If we don't have a reference clock then we cannot set up the advise + // time so we simply set the event indicating an image to render. This + // will cause us to run flat out without any timing or synchronisation + + if (hr == S_OK) { + EXECUTE_ASSERT(SetEvent((HANDLE) m_RenderEvent)); + return TRUE; + } + + ASSERT(m_dwAdvise == 0); + ASSERT(m_pClock); + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + + // We do have a valid reference clock interface so we can ask it to + // set an event when the image comes due for rendering. We pass in + // the reference time we were told to start at and also the current + // stream time which is the offset from the start reference time + + hr = m_pClock->AdviseTime( + (REFERENCE_TIME) m_tStart, // Start run time + StartSample, // Stream time + (HEVENT)(HANDLE) m_RenderEvent, // Render notification + &m_dwAdvise); // Advise cookie + + if (SUCCEEDED(hr)) { + return TRUE; + } + + // We could not schedule the next sample for rendering despite the fact + // we have a valid sample here. This is a fair indication that either + // the system clock is wrong or the time stamp for the sample is duff + + ASSERT(m_dwAdvise == 0); + return FALSE; +} + + +// This is called when a sample comes due for rendering. We pass the sample +// on to the derived class. After rendering we will initialise the timer for +// the next sample, NOTE signal that the last one fired first, if we don't +// do this it thinks there is still one outstanding that hasn't completed + +HRESULT CBaseRenderer::Render(IMediaSample *pMediaSample) +{ + // If the media sample is NULL then we will have been notified by the + // clock that another sample is ready but in the mean time someone has + // stopped us streaming which causes the next sample to be released + + if (pMediaSample == NULL) { + return S_FALSE; + } + + // If we have stopped streaming then don't render any more samples, the + // thread that got in and locked us and then reset this flag does not + // clear the pending sample as we can use it to refresh any output device + + if (m_bStreaming == FALSE) { + return S_FALSE; + } + + // Time how long the rendering takes + + OnRenderStart(pMediaSample); + DoRenderSample(pMediaSample); + OnRenderEnd(pMediaSample); + + return NOERROR; +} + + +// Checks if there is a sample waiting at the renderer + +BOOL CBaseRenderer::HaveCurrentSample() +{ + CAutoLock cRendererLock(&m_RendererLock); + return (m_pMediaSample == NULL ? FALSE : TRUE); +} + + +// Returns the current sample waiting at the video renderer. We AddRef the +// sample before returning so that should it come due for rendering the +// person who called this method will hold the remaining reference count +// that will stop the sample being added back onto the allocator free list + +IMediaSample *CBaseRenderer::GetCurrentSample() +{ + CAutoLock cRendererLock(&m_RendererLock); + if (m_pMediaSample) { + m_pMediaSample->AddRef(); + } + return m_pMediaSample; +} + + +// Called when the source delivers us a sample. We go through a few checks to +// make sure the sample can be rendered. If we are running (streaming) then we +// have the sample scheduled with the reference clock, if we are not streaming +// then we have received an sample in paused mode so we can complete any state +// transition. On leaving this function everything will be unlocked so an app +// thread may get in and change our state to stopped (for example) in which +// case it will also signal the thread event so that our wait call is stopped + +HRESULT CBaseRenderer::PrepareReceive(IMediaSample *pMediaSample) +{ + CAutoLock cInterfaceLock(&m_InterfaceLock); + m_bInReceive = TRUE; + + // Check our flushing and filter state + + // This function must hold the interface lock because it calls + // CBaseInputPin::Receive() and CBaseInputPin::Receive() uses + // CBasePin::m_bRunTimeError. + HRESULT hr = m_pInputPin->CBaseInputPin::Receive(pMediaSample); + + if (hr != NOERROR) { + m_bInReceive = FALSE; + return E_FAIL; + } + + // Has the type changed on a media sample. We do all rendering + // synchronously on the source thread, which has a side effect + // that only one buffer is ever outstanding. Therefore when we + // have Receive called we can go ahead and change the format + // Since the format change can cause a SendMessage we just don't + // lock + if (m_pInputPin->SampleProps()->pMediaType) { + hr = m_pInputPin->SetMediaType( + (CMediaType *)m_pInputPin->SampleProps()->pMediaType); + if (FAILED(hr)) { + m_bInReceive = FALSE; + return hr; + } + } + + + CAutoLock cSampleLock(&m_RendererLock); + + ASSERT(IsActive() == TRUE); + ASSERT(m_pInputPin->IsFlushing() == FALSE); + ASSERT(m_pInputPin->IsConnected() == TRUE); + ASSERT(m_pMediaSample == NULL); + + // Return an error if we already have a sample waiting for rendering + // source pins must serialise the Receive calls - we also check that + // no data is being sent after the source signalled an end of stream + + if (m_pMediaSample || m_bEOS || m_bAbort) { + Ready(); + m_bInReceive = FALSE; + return E_UNEXPECTED; + } + + // Store the media times from this sample + if (m_pPosition) m_pPosition->RegisterMediaTime(pMediaSample); + + // Schedule the next sample if we are streaming + + if ((m_bStreaming == TRUE) && (ScheduleSample(pMediaSample) == FALSE)) { + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(CancelNotification() == S_FALSE); + m_bInReceive = FALSE; + return VFW_E_SAMPLE_REJECTED; + } + + // Store the sample end time for EC_COMPLETE handling + m_SignalTime = m_pInputPin->SampleProps()->tStop; + + // BEWARE we sometimes keep the sample even after returning the thread to + // the source filter such as when we go into a stopped state (we keep it + // to refresh the device with) so we must AddRef it to keep it safely. If + // we start flushing the source thread is released and any sample waiting + // will be released otherwise GetBuffer may never return (see BeginFlush) + + m_pMediaSample = pMediaSample; + m_pMediaSample->AddRef(); + + if (m_bStreaming == FALSE) { + SetRepaintStatus(TRUE); + } + return NOERROR; +} + + +// Called by the source filter when we have a sample to render. Under normal +// circumstances we set an advise link with the clock, wait for the time to +// arrive and then render the data using the PURE virtual DoRenderSample that +// the derived class will have overriden. After rendering the sample we may +// also signal EOS if it was the last one sent before EndOfStream was called + +HRESULT CBaseRenderer::Receive(IMediaSample *pSample) +{ + ASSERT(pSample); + + // It may return VFW_E_SAMPLE_REJECTED code to say don't bother + + HRESULT hr = PrepareReceive(pSample); + ASSERT(m_bInReceive == SUCCEEDED(hr)); + if (FAILED(hr)) { + if (hr == VFW_E_SAMPLE_REJECTED) { + return NOERROR; + } + return hr; + } + + // We realize the palette in "PrepareRender()" so we have to give away the + // filter lock here. + if (m_State == State_Paused) { + PrepareRender(); + // no need to use InterlockedExchange + m_bInReceive = FALSE; + { + // We must hold both these locks + CAutoLock cRendererLock(&m_InterfaceLock); + if (m_State == State_Stopped) + return NOERROR; + + m_bInReceive = TRUE; + CAutoLock cSampleLock(&m_RendererLock); + OnReceiveFirstSample(pSample); + } + Ready(); + } + // Having set an advise link with the clock we sit and wait. We may be + // awoken by the clock firing or by a state change. The rendering call + // will lock the critical section and check we can still render the data + + hr = WaitForRenderTime(); + if (FAILED(hr)) { + m_bInReceive = FALSE; + return NOERROR; + } + + PrepareRender(); + + // Set this here and poll it until we work out the locking correctly + // It can't be right that the streaming stuff grabs the interface + // lock - after all we want to be able to wait for this stuff + // to complete + m_bInReceive = FALSE; + + // We must hold both these locks + CAutoLock cRendererLock(&m_InterfaceLock); + + // since we gave away the filter wide lock, the sate of the filter could + // have chnaged to Stopped + if (m_State == State_Stopped) + return NOERROR; + + CAutoLock cSampleLock(&m_RendererLock); + + // Deal with this sample + + Render(m_pMediaSample); + ClearPendingSample(); + SendEndOfStream(); + CancelNotification(); + return NOERROR; +} + + +// This is called when we stop or are inactivated to clear the pending sample +// We release the media sample interface so that they can be allocated to the +// source filter again, unless of course we are changing state to inactive in +// which case GetBuffer will return an error. We must also reset the current +// media sample to NULL so that we know we do not currently have an image + +HRESULT CBaseRenderer::ClearPendingSample() +{ + CAutoLock cRendererLock(&m_RendererLock); + if (m_pMediaSample) { + m_pMediaSample->Release(); + m_pMediaSample = NULL; + } + return NOERROR; +} + + +// Used to signal end of stream according to the sample end time + +void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier + UINT uMsg, // Not currently used + DWORD_PTR dwUser,// User information + DWORD_PTR dw1, // Windows reserved + DWORD_PTR dw2) // is also reserved +{ + CBaseRenderer *pRenderer = (CBaseRenderer *) dwUser; + NOTE1("EndOfStreamTimer called (%d)",uID); + pRenderer->TimerCallback(); +} + +// Do the timer callback work +void CBaseRenderer::TimerCallback() +{ + // Lock for synchronization (but don't hold this lock when calling + // timeKillEvent) + CAutoLock cRendererLock(&m_RendererLock); + + // See if we should signal end of stream now + + if (m_EndOfStreamTimer) { + m_EndOfStreamTimer = 0; + SendEndOfStream(); + } +} + + +// If we are at the end of the stream signal the filter graph but do not set +// the state flag back to FALSE. Once we drop off the end of the stream we +// leave the flag set (until a subsequent ResetEndOfStream). Each sample we +// get delivered will update m_SignalTime to be the last sample's end time. +// We must wait this long before signalling end of stream to the filtergraph + +#define TIMEOUT_DELIVERYWAIT 50 +#define TIMEOUT_RESOLUTION 10 + +HRESULT CBaseRenderer::SendEndOfStream() +{ + ASSERT(CritCheckIn(&m_RendererLock)); + if (m_bEOS == FALSE || m_bEOSDelivered || m_EndOfStreamTimer) { + return NOERROR; + } + + // If there is no clock then signal immediately + if (m_pClock == NULL) { + return NotifyEndOfStream(); + } + + // How long into the future is the delivery time + + REFERENCE_TIME Signal = m_tStart + m_SignalTime; + REFERENCE_TIME CurrentTime; + m_pClock->GetTime(&CurrentTime); + LONG Delay = LONG((Signal - CurrentTime) / 10000); + + // Dump the timing information to the debugger + + NOTE1("Delay until end of stream delivery %d",Delay); + NOTE1("Current %s",(LPCTSTR)CDisp((LONGLONG)CurrentTime)); + NOTE1("Signal %s",(LPCTSTR)CDisp((LONGLONG)Signal)); + + // Wait for the delivery time to arrive + + if (Delay < TIMEOUT_DELIVERYWAIT) { + return NotifyEndOfStream(); + } + + // Signal a timer callback on another worker thread + + m_EndOfStreamTimer = CompatibleTimeSetEvent((UINT) Delay, // Period of timer + TIMEOUT_RESOLUTION, // Timer resolution + EndOfStreamTimer, // Callback function + DWORD_PTR(this), // Used information + TIME_ONESHOT); // Type of callback + if (m_EndOfStreamTimer == 0) { + return NotifyEndOfStream(); + } + return NOERROR; +} + + +// Signals EC_COMPLETE to the filtergraph manager + +HRESULT CBaseRenderer::NotifyEndOfStream() +{ + CAutoLock cRendererLock(&m_RendererLock); + ASSERT(m_bEOSDelivered == FALSE); + ASSERT(m_EndOfStreamTimer == 0); + + // Has the filter changed state + + if (m_bStreaming == FALSE) { + ASSERT(m_EndOfStreamTimer == 0); + return NOERROR; + } + + // Reset the end of stream timer + m_EndOfStreamTimer = 0; + + // If we've been using the IMediaPosition interface, set it's start + // and end media "times" to the stop position by hand. This ensures + // that we actually get to the end, even if the MPEG guestimate has + // been bad or if the quality management dropped the last few frames + + if (m_pPosition) m_pPosition->EOS(); + m_bEOSDelivered = TRUE; + NOTE("Sending EC_COMPLETE..."); + return NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this); +} + + +// Reset the end of stream flag, this is typically called when we transfer to +// stopped states since that resets the current position back to the start so +// we will receive more samples or another EndOfStream if there aren't any. We +// keep two separate flags one to say we have run off the end of the stream +// (this is the m_bEOS flag) and another to say we have delivered EC_COMPLETE +// to the filter graph. We need the latter otherwise we can end up sending an +// EC_COMPLETE every time the source changes state and calls our EndOfStream + +HRESULT CBaseRenderer::ResetEndOfStream() +{ + ResetEndOfStreamTimer(); + CAutoLock cRendererLock(&m_RendererLock); + + m_bEOS = FALSE; + m_bEOSDelivered = FALSE; + m_SignalTime = 0; + + return NOERROR; +} + + +// Kills any outstanding end of stream timer + +void CBaseRenderer::ResetEndOfStreamTimer() +{ + ASSERT(CritCheckOut(&m_RendererLock)); + if (m_EndOfStreamTimer) { + timeKillEvent(m_EndOfStreamTimer); + m_EndOfStreamTimer = 0; + } +} + + +// This is called when we start running so that we can schedule any pending +// image we have with the clock and display any timing information. If we +// don't have any sample but we have queued an EOS flag then we send it. If +// we do have a sample then we wait until that has been rendered before we +// signal the filter graph otherwise we may change state before it's done + +HRESULT CBaseRenderer::StartStreaming() +{ + CAutoLock cRendererLock(&m_RendererLock); + if (m_bStreaming == TRUE) { + return NOERROR; + } + + // Reset the streaming times ready for running + + m_bStreaming = TRUE; + + timeBeginPeriod(1); + OnStartStreaming(); + + // There should be no outstanding advise + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(CancelNotification() == S_FALSE); + + // If we have an EOS and no data then deliver it now + + if (m_pMediaSample == NULL) { + return SendEndOfStream(); + } + + // Have the data rendered + + ASSERT(m_pMediaSample); + if (!ScheduleSample(m_pMediaSample)) + m_RenderEvent.Set(); + + return NOERROR; +} + + +// This is called when we stop streaming so that we can set our internal flag +// indicating we are not now to schedule any more samples arriving. The state +// change methods in the filter implementation take care of cancelling any +// clock advise link we have set up and clearing any pending sample we have + +HRESULT CBaseRenderer::StopStreaming() +{ + CAutoLock cRendererLock(&m_RendererLock); + m_bEOSDelivered = FALSE; + + if (m_bStreaming == TRUE) { + m_bStreaming = FALSE; + OnStopStreaming(); + timeEndPeriod(1); + } + return NOERROR; +} + + +// We have a boolean flag that is reset when we have signalled EC_REPAINT to +// the filter graph. We set this when we receive an image so that should any +// conditions arise again we can send another one. By having a flag we ensure +// we don't flood the filter graph with redundant calls. We do not set the +// event when we receive an EndOfStream call since there is no point in us +// sending further EC_REPAINTs. In particular the AutoShowWindow method and +// the DirectDraw object use this method to control the window repainting + +void CBaseRenderer::SetRepaintStatus(BOOL bRepaint) +{ + CAutoLock cSampleLock(&m_RendererLock); + m_bRepaintStatus = bRepaint; +} + + +// Pass the window handle to the upstream filter + +void CBaseRenderer::SendNotifyWindow(IPin *pPin,HWND hwnd) +{ + IMediaEventSink *pSink; + + // Does the pin support IMediaEventSink + HRESULT hr = pPin->QueryInterface(IID_IMediaEventSink,(void **)&pSink); + if (SUCCEEDED(hr)) { + pSink->Notify(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0); + pSink->Release(); + } + NotifyEvent(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0); +} + + +// Signal an EC_REPAINT to the filter graph. This can be used to have data +// sent to us. For example when a video window is first displayed it may +// not have an image to display, at which point it signals EC_REPAINT. The +// filtergraph will either pause the graph if stopped or if already paused +// it will call put_CurrentPosition of the current position. Setting the +// current position to itself has the stream flushed and the image resent + +#define RLOG(_x_) DbgLog((LOG_TRACE,1,TEXT(_x_))); + +void CBaseRenderer::SendRepaint() +{ + CAutoLock cSampleLock(&m_RendererLock); + ASSERT(m_pInputPin); + + // We should not send repaint notifications when... + // - An end of stream has been notified + // - Our input pin is being flushed + // - The input pin is not connected + // - We have aborted a video playback + // - There is a repaint already sent + + if (m_bAbort == FALSE) { + if (m_pInputPin->IsConnected() == TRUE) { + if (m_pInputPin->IsFlushing() == FALSE) { + if (IsEndOfStream() == FALSE) { + if (m_bRepaintStatus == TRUE) { + IPin *pPin = (IPin *) m_pInputPin; + NotifyEvent(EC_REPAINT,(LONG_PTR) pPin,0); + SetRepaintStatus(FALSE); + RLOG("Sending repaint"); + } + } + } + } + } +} + + +// When a video window detects a display change (WM_DISPLAYCHANGE message) it +// can send an EC_DISPLAY_CHANGED event code along with the renderer pin. The +// filtergraph will stop everyone and reconnect our input pin. As we're then +// reconnected we can accept the media type that matches the new display mode +// since we may no longer be able to draw the current image type efficiently + +BOOL CBaseRenderer::OnDisplayChange() +{ + // Ignore if we are not connected yet + + CAutoLock cSampleLock(&m_RendererLock); + if (m_pInputPin->IsConnected() == FALSE) { + return FALSE; + } + + RLOG("Notification of EC_DISPLAY_CHANGE"); + + // Pass our input pin as parameter on the event + + IPin *pPin = (IPin *) m_pInputPin; + m_pInputPin->AddRef(); + NotifyEvent(EC_DISPLAY_CHANGED,(LONG_PTR) pPin,0); + SetAbortSignal(TRUE); + ClearPendingSample(); + m_pInputPin->Release(); + + return TRUE; +} + + +// Called just before we start drawing. +// Store the current time in m_trRenderStart to allow the rendering time to be +// logged. Log the time stamp of the sample and how late it is (neg is early) + +void CBaseRenderer::OnRenderStart(IMediaSample *pMediaSample) +{ +#ifdef PERF + REFERENCE_TIME trStart, trEnd; + pMediaSample->GetTime(&trStart, &trEnd); + + MSR_INTEGER(m_idBaseStamp, (int)trStart); // dump low order 32 bits + + m_pClock->GetTime(&m_trRenderStart); + MSR_INTEGER(0, (int)m_trRenderStart); + REFERENCE_TIME trStream; + trStream = m_trRenderStart-m_tStart; // convert reftime to stream time + MSR_INTEGER(0,(int)trStream); + + const int trLate = (int)(trStream - trStart); + MSR_INTEGER(m_idBaseAccuracy, trLate/10000); // dump in mSec +#endif + +} // OnRenderStart + + +// Called directly after drawing an image. +// calculate the time spent drawing and log it. + +void CBaseRenderer::OnRenderEnd(IMediaSample *pMediaSample) +{ +#ifdef PERF + REFERENCE_TIME trNow; + m_pClock->GetTime(&trNow); + MSR_INTEGER(0,(int)trNow); + int t = (int)((trNow - m_trRenderStart)/10000); // convert UNITS->msec + MSR_INTEGER(m_idBaseRenderTime, t); +#endif +} // OnRenderEnd + + + + +// Constructor must be passed the base renderer object + +CRendererInputPin::CRendererInputPin(CBaseRenderer *pRenderer, + HRESULT *phr, + LPCWSTR pPinName) : + CBaseInputPin(NAME("Renderer pin"), + pRenderer, + &pRenderer->m_InterfaceLock, + (HRESULT *) phr, + pPinName) +{ + m_pRenderer = pRenderer; + ASSERT(m_pRenderer); +} + + +// Signals end of data stream on the input pin + +STDMETHODIMP CRendererInputPin::EndOfStream() +{ + CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); + CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); + + // Make sure we're streaming ok + + HRESULT hr = CheckStreaming(); + if (hr != NOERROR) { + return hr; + } + + // Pass it onto the renderer + + hr = m_pRenderer->EndOfStream(); + if (SUCCEEDED(hr)) { + hr = CBaseInputPin::EndOfStream(); + } + return hr; +} + + +// Signals start of flushing on the input pin - we do the final reset end of +// stream with the renderer lock unlocked but with the interface lock locked +// We must do this because we call timeKillEvent, our timer callback method +// has to take the renderer lock to serialise our state. Therefore holding a +// renderer lock when calling timeKillEvent could cause a deadlock condition + +STDMETHODIMP CRendererInputPin::BeginFlush() +{ + CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); + { + CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); + CBaseInputPin::BeginFlush(); + m_pRenderer->BeginFlush(); + } + return m_pRenderer->ResetEndOfStream(); +} + + +// Signals end of flushing on the input pin + +STDMETHODIMP CRendererInputPin::EndFlush() +{ + CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); + CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); + + HRESULT hr = m_pRenderer->EndFlush(); + if (SUCCEEDED(hr)) { + hr = CBaseInputPin::EndFlush(); + } + return hr; +} + + +// Pass the sample straight through to the renderer object + +STDMETHODIMP CRendererInputPin::Receive(IMediaSample *pSample) +{ + HRESULT hr = m_pRenderer->Receive(pSample); + if (FAILED(hr)) { + + // A deadlock could occur if the caller holds the renderer lock and + // attempts to acquire the interface lock. + ASSERT(CritCheckOut(&m_pRenderer->m_RendererLock)); + + { + // The interface lock must be held when the filter is calling + // IsStopped() or IsFlushing(). The interface lock must also + // be held because the function uses m_bRunTimeError. + CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); + + // We do not report errors which occur while the filter is stopping, + // flushing or if the m_bAbort flag is set . Errors are expected to + // occur during these operations and the streaming thread correctly + // handles the errors. + if (!IsStopped() && !IsFlushing() && !m_pRenderer->m_bAbort && !m_bRunTimeError) { + + // EC_ERRORABORT's first parameter is the error which caused + // the event and its' last parameter is 0. See the Direct + // Show SDK documentation for more information. + m_pRenderer->NotifyEvent(EC_ERRORABORT,hr,0); + + { + CAutoLock alRendererLock(&m_pRenderer->m_RendererLock); + if (m_pRenderer->IsStreaming() && !m_pRenderer->IsEndOfStreamDelivered()) { + m_pRenderer->NotifyEndOfStream(); + } + } + + m_bRunTimeError = TRUE; + } + } + } + + return hr; +} + + +// Called when the input pin is disconnected + +HRESULT CRendererInputPin::BreakConnect() +{ + HRESULT hr = m_pRenderer->BreakConnect(); + if (FAILED(hr)) { + return hr; + } + return CBaseInputPin::BreakConnect(); +} + + +// Called when the input pin is connected + +HRESULT CRendererInputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = m_pRenderer->CompleteConnect(pReceivePin); + if (FAILED(hr)) { + return hr; + } + return CBaseInputPin::CompleteConnect(pReceivePin); +} + + +// Give the pin id of our one and only pin + +STDMETHODIMP CRendererInputPin::QueryId(LPWSTR *Id) +{ + CheckPointer(Id,E_POINTER); + + const size_t len = 4; + *Id = (LPWSTR)CoTaskMemAlloc(len * sizeof(WCHAR)); + if (*Id == NULL) { + return E_OUTOFMEMORY; + } + (void)StringCchCopyW(*Id, len, L"In"); + return NOERROR; +} + + +// Will the filter accept this media type + +HRESULT CRendererInputPin::CheckMediaType(const CMediaType *pmt) +{ + return m_pRenderer->CheckMediaType(pmt); +} + + +// Called when we go paused or running + +HRESULT CRendererInputPin::Active() +{ + return m_pRenderer->Active(); +} + + +// Called when we go into a stopped state + +HRESULT CRendererInputPin::Inactive() +{ + // The caller must hold the interface lock because + // this function uses m_bRunTimeError. + ASSERT(CritCheckIn(&m_pRenderer->m_InterfaceLock)); + + m_bRunTimeError = FALSE; + + return m_pRenderer->Inactive(); +} + + +// Tell derived classes about the media type agreed + +HRESULT CRendererInputPin::SetMediaType(const CMediaType *pmt) +{ + HRESULT hr = CBaseInputPin::SetMediaType(pmt); + if (FAILED(hr)) { + return hr; + } + return m_pRenderer->SetMediaType(pmt); +} + + +// We do not keep an event object to use when setting up a timer link with +// the clock but are given a pointer to one by the owning object through the +// SetNotificationObject method - this must be initialised before starting +// We can override the default quality management process to have it always +// draw late frames, this is currently done by having the following registry +// key (actually an INI key) called DrawLateFrames set to 1 (default is 0) + +const TCHAR AMQUALITY[] = TEXT("ActiveMovie"); +const TCHAR DRAWLATEFRAMES[] = TEXT("DrawLateFrames"); + +CBaseVideoRenderer::CBaseVideoRenderer( + REFCLSID RenderClass, // CLSID for this renderer + TCHAR *pName, // Debug ONLY description + LPUNKNOWN pUnk, // Aggregated owner object + HRESULT *phr) : // General OLE return code + + CBaseRenderer(RenderClass,pName,pUnk,phr), + m_cFramesDropped(0), + m_cFramesDrawn(0), + m_bSupplierHandlingQuality(FALSE) +{ + ResetStreamingTimes(); + +#ifdef PERF + m_idTimeStamp = MSR_REGISTER(TEXT("Frame time stamp")); + m_idEarliness = MSR_REGISTER(TEXT("Earliness fudge")); + m_idTarget = MSR_REGISTER(TEXT("Target (mSec)")); + m_idSchLateTime = MSR_REGISTER(TEXT("mSec late when scheduled")); + m_idDecision = MSR_REGISTER(TEXT("Scheduler decision code")); + m_idQualityRate = MSR_REGISTER(TEXT("Quality rate sent")); + m_idQualityTime = MSR_REGISTER(TEXT("Quality time sent")); + m_idWaitReal = MSR_REGISTER(TEXT("Render wait")); + // m_idWait = MSR_REGISTER(TEXT("wait time recorded (msec)")); + m_idFrameAccuracy = MSR_REGISTER(TEXT("Frame accuracy (msecs)")); + m_bDrawLateFrames = GetProfileInt(AMQUALITY, DRAWLATEFRAMES, FALSE); + //m_idSendQuality = MSR_REGISTER(TEXT("Processing Quality message")); + + m_idRenderAvg = MSR_REGISTER(TEXT("Render draw time Avg")); + m_idFrameAvg = MSR_REGISTER(TEXT("FrameAvg")); + m_idWaitAvg = MSR_REGISTER(TEXT("WaitAvg")); + m_idDuration = MSR_REGISTER(TEXT("Duration")); + m_idThrottle = MSR_REGISTER(TEXT("Audio-video throttle wait")); + // m_idDebug = MSR_REGISTER(TEXT("Debug stuff")); +#endif // PERF +} // Constructor + + +// Destructor is just a placeholder + +CBaseVideoRenderer::~CBaseVideoRenderer() +{ + ASSERT(m_dwAdvise == 0); +} + + +// The timing functions in this class are called by the window object and by +// the renderer's allocator. +// The windows object calls timing functions as it receives media sample +// images for drawing using GDI. +// The allocator calls timing functions when it starts passing DCI/DirectDraw +// surfaces which are not rendered in the same way; The decompressor writes +// directly to the surface with no separate rendering, so those code paths +// call direct into us. Since we only ever hand out DCI/DirectDraw surfaces +// when we have allocated one and only one image we know there cannot be any +// conflict between the two. +// +// We use timeGetTime to return the timing counts we use (since it's relative +// performance we are interested in rather than absolute compared to a clock) +// The window object sets the accuracy of the system clock (normally 1ms) by +// calling timeBeginPeriod/timeEndPeriod when it changes streaming states + + +// Reset all times controlling streaming. +// Set them so that +// 1. Frames will not initially be dropped +// 2. The first frame will definitely be drawn (achieved by saying that there +// has not ben a frame drawn for a long time). + +HRESULT CBaseVideoRenderer::ResetStreamingTimes() +{ + m_trLastDraw = -1000; // set up as first frame since ages (1 sec) ago + m_tStreamingStart = timeGetTime(); + m_trRenderAvg = 0; + m_trFrameAvg = -1; // -1000 fps == "unset" + m_trDuration = 0; // 0 - strange value + m_trRenderLast = 0; + m_trWaitAvg = 0; + m_tRenderStart = 0; + m_cFramesDrawn = 0; + m_cFramesDropped = 0; + m_iTotAcc = 0; + m_iSumSqAcc = 0; + m_iSumSqFrameTime = 0; + m_trFrame = 0; // hygiene - not really needed + m_trLate = 0; // hygiene - not really needed + m_iSumFrameTime = 0; + m_nNormal = 0; + m_trEarliness = 0; + m_trTarget = -300000; // 30mSec early + m_trThrottle = 0; + m_trRememberStampForPerf = 0; + +#ifdef PERF + m_trRememberFrameForPerf = 0; +#endif + + return NOERROR; +} // ResetStreamingTimes + + +// Reset all times controlling streaming. Note that we're now streaming. We +// don't need to set the rendering event to have the source filter released +// as it is done during the Run processing. When we are run we immediately +// release the source filter thread and draw any image waiting (that image +// may already have been drawn once as a poster frame while we were paused) + +HRESULT CBaseVideoRenderer::OnStartStreaming() +{ + ResetStreamingTimes(); + return NOERROR; +} // OnStartStreaming + + +// Called at end of streaming. Fixes times for property page report + +HRESULT CBaseVideoRenderer::OnStopStreaming() +{ + m_tStreamingStart = timeGetTime()-m_tStreamingStart; + return NOERROR; +} // OnStopStreaming + + +// Called when we start waiting for a rendering event. +// Used to update times spent waiting and not waiting. + +void CBaseVideoRenderer::OnWaitStart() +{ + MSR_START(m_idWaitReal); +} // OnWaitStart + + +// Called when we are awoken from the wait in the window OR by our allocator +// when it is hanging around until the next sample is due for rendering on a +// DCI/DirectDraw surface. We add the wait time into our rolling average. +// We grab the interface lock so that we're serialised with the application +// thread going through the run code - which in due course ends up calling +// ResetStreaming times - possibly as we run through this section of code + +void CBaseVideoRenderer::OnWaitEnd() +{ +#ifdef PERF + MSR_STOP(m_idWaitReal); + // for a perf build we want to know just exactly how late we REALLY are. + // even if this means that we have to look at the clock again. + + REFERENCE_TIME trRealStream; // the real time now expressed as stream time. +#if 0 + m_pClock->GetTime(&trRealStream); // Calling clock here causes W95 deadlock! +#else + // We will be discarding overflows like mad here! + // This is wrong really because timeGetTime() can wrap but it's + // only for PERF + REFERENCE_TIME tr = timeGetTime()*10000; + trRealStream = tr + m_llTimeOffset; +#endif + trRealStream -= m_tStart; // convert to stream time (this is a reftime) + + if (m_trRememberStampForPerf==0) { + // This is probably the poster frame at the start, and it is not scheduled + // in the usual way at all. Just count it. The rememberstamp gets set + // in ShouldDrawSampleNow, so this does invalid frame recording until we + // actually start playing. + PreparePerformanceData(0, 0); + } else { + int trLate = (int)(trRealStream - m_trRememberStampForPerf); + int trFrame = (int)(tr - m_trRememberFrameForPerf); + PreparePerformanceData(trLate, trFrame); + } + m_trRememberFrameForPerf = tr; +#endif //PERF +} // OnWaitEnd + + +// Put data on one side that describes the lateness of the current frame. +// We don't yet know whether it will actually be drawn. In direct draw mode, +// this decision is up to the filter upstream, and it could change its mind. +// The rules say that if it did draw it must call Receive(). One way or +// another we eventually get into either OnRenderStart or OnDirectRender and +// these both call RecordFrameLateness to update the statistics. + +void CBaseVideoRenderer::PreparePerformanceData(int trLate, int trFrame) +{ + m_trLate = trLate; + m_trFrame = trFrame; +} // PreparePerformanceData + + +// update the statistics: +// m_iTotAcc, m_iSumSqAcc, m_iSumSqFrameTime, m_iSumFrameTime, m_cFramesDrawn +// Note that because the properties page reports using these variables, +// 1. We need to be inside a critical section +// 2. They must all be updated together. Updating the sums here and the count +// elsewhere can result in imaginary jitter (i.e. attempts to find square roots +// of negative numbers) in the property page code. + +void CBaseVideoRenderer::RecordFrameLateness(int trLate, int trFrame) +{ + // Record how timely we are. + int tLate = trLate/10000; + + // Best estimate of moment of appearing on the screen is average of + // start and end draw times. Here we have only the end time. This may + // tend to show us as spuriously late by up to 1/2 frame rate achieved. + // Decoder probably monitors draw time. We don't bother. + MSR_INTEGER( m_idFrameAccuracy, tLate ); + + // This is a kludge - we can get frames that are very late + // especially (at start-up) and they invalidate the statistics. + // So ignore things that are more than 1 sec off. + if (tLate>1000 || tLate<-1000) { + if (m_cFramesDrawn<=1) { + tLate = 0; + } else if (tLate>0) { + tLate = 1000; + } else { + tLate = -1000; + } + } + // The very first frame often has a invalid time, so don't + // count it into the statistics. (???) + if (m_cFramesDrawn>1) { + m_iTotAcc += tLate; + m_iSumSqAcc += (tLate*tLate); + } + + // calculate inter-frame time. Doesn't make sense for first frame + // second frame suffers from invalid first frame stamp. + if (m_cFramesDrawn>2) { + int tFrame = trFrame/10000; // convert to mSec else it overflows + + // This is a kludge. It can overflow anyway (a pause can cause + // a very long inter-frame time) and it overflows at 2**31/10**7 + // or about 215 seconds i.e. 3min 35sec + if (tFrame>1000||tFrame<0) tFrame = 1000; + m_iSumSqFrameTime += tFrame*tFrame; + ASSERT(m_iSumSqFrameTime>=0); + m_iSumFrameTime += tFrame; + } + ++m_cFramesDrawn; + +} // RecordFrameLateness + + +void CBaseVideoRenderer::ThrottleWait() +{ + if (m_trThrottle>0) { + int iThrottle = m_trThrottle/10000; // convert to mSec + MSR_INTEGER( m_idThrottle, iThrottle); + DbgLog((LOG_TRACE, 0, TEXT("Throttle %d ms"), iThrottle)); + Sleep(iThrottle); + } else { + Sleep(0); + } +} // ThrottleWait + + +// Whenever a frame is rendered it goes though either OnRenderStart +// or OnDirectRender. Data that are generated during ShouldDrawSample +// are added to the statistics by calling RecordFrameLateness from both +// these two places. + +// Called in place of OnRenderStart..OnRenderEnd +// When a DirectDraw image is drawn +void CBaseVideoRenderer::OnDirectRender(IMediaSample *pMediaSample) +{ + m_trRenderAvg = 0; + m_trRenderLast = 5000000; // If we mode switch, we do NOT want this + // to inhibit the new average getting going! + // so we set it to half a second + // MSR_INTEGER(m_idRenderAvg, m_trRenderAvg/10000); + RecordFrameLateness(m_trLate, m_trFrame); + ThrottleWait(); +} // OnDirectRender + + +// Called just before we start drawing. All we do is to get the current clock +// time (from the system) and return. We have to store the start render time +// in a member variable because it isn't used until we complete the drawing +// The rest is just performance logging. + +void CBaseVideoRenderer::OnRenderStart(IMediaSample *pMediaSample) +{ + RecordFrameLateness(m_trLate, m_trFrame); + m_tRenderStart = timeGetTime(); +} // OnRenderStart + + +// Called directly after drawing an image. We calculate the time spent in the +// drawing code and if this doesn't appear to have any odd looking spikes in +// it then we add it to the current average draw time. Measurement spikes may +// occur if the drawing thread is interrupted and switched to somewhere else. + +void CBaseVideoRenderer::OnRenderEnd(IMediaSample *pMediaSample) +{ + // The renderer time can vary erratically if we are interrupted so we do + // some smoothing to help get more sensible figures out but even that is + // not enough as figures can go 9,10,9,9,83,9 and we must disregard 83 + + int tr = (timeGetTime() - m_tRenderStart)*10000; // convert mSec->UNITS + if (tr < m_trRenderAvg*2 || tr < 2 * m_trRenderLast) { + // DO_MOVING_AVG(m_trRenderAvg, tr); + m_trRenderAvg = (tr + (AVGPERIOD-1)*m_trRenderAvg)/AVGPERIOD; + } + m_trRenderLast = tr; + ThrottleWait(); +} // OnRenderEnd + + +STDMETHODIMP CBaseVideoRenderer::SetSink( IQualityControl * piqc) +{ + + m_pQSink = piqc; + + return NOERROR; +} // SetSink + + +STDMETHODIMP CBaseVideoRenderer::Notify( IBaseFilter * pSelf, Quality q) +{ + // NOTE: We are NOT getting any locks here. We could be called + // asynchronously and possibly even on a time critical thread of + // someone else's - so we do the minumum. We only set one state + // variable (an integer) and if that happens to be in the middle + // of another thread reading it they will just get either the new + // or the old value. Locking would achieve no more than this. + + // It might be nice to check that we are being called from m_pGraph, but + // it turns out to be a millisecond or so per throw! + + // This is heuristics, these numbers are aimed at being "what works" + // rather than anything based on some theory. + // We use a hyperbola because it's easy to calculate and it includes + // a panic button asymptote (which we push off just to the left) + // The throttling fits the following table (roughly) + // Proportion Throttle (msec) + // >=1000 0 + // 900 3 + // 800 7 + // 700 11 + // 600 17 + // 500 25 + // 400 35 + // 300 50 + // 200 72 + // 125 100 + // 100 112 + // 50 146 + // 0 200 + + // (some evidence that we could go for a sharper kink - e.g. no throttling + // until below the 750 mark - might give fractionally more frames on a + // P60-ish machine). The easy way to get these coefficients is to use + // Renbase.xls follow the instructions therein using excel solver. + + if (q.Proportion>=1000) { m_trThrottle = 0; } + else { + // The DWORD is to make quite sure I get unsigned arithmetic + // as the constant is between 2**31 and 2**32 + m_trThrottle = -330000 + (388880000/(q.Proportion+167)); + } + return NOERROR; +} // Notify + + +// Send a message to indicate what our supplier should do about quality. +// Theory: +// What a supplier wants to know is "is the frame I'm working on NOW +// going to be late?". +// F1 is the frame at the supplier (as above) +// Tf1 is the due time for F1 +// T1 is the time at that point (NOW!) +// Tr1 is the time that f1 WILL actually be rendered +// L1 is the latency of the graph for frame F1 = Tr1-T1 +// D1 (for delay) is how late F1 will be beyond its due time i.e. +// D1 = (Tr1-Tf1) which is what the supplier really wants to know. +// Unfortunately Tr1 is in the future and is unknown, so is L1 +// +// We could estimate L1 by its value for a previous frame, +// L0 = Tr0-T0 and work off +// D1' = ((T1+L0)-Tf1) = (T1 + (Tr0-T0) -Tf1) +// Rearranging terms: +// D1' = (T1-T0) + (Tr0-Tf1) +// adding (Tf0-Tf0) and rearranging again: +// = (T1-T0) + (Tr0-Tf0) + (Tf0-Tf1) +// = (T1-T0) - (Tf1-Tf0) + (Tr0-Tf0) +// But (Tr0-Tf0) is just D0 - how late frame zero was, and this is the +// Late field in the quality message that we send. +// The other two terms just state what correction should be applied before +// using the lateness of F0 to predict the lateness of F1. +// (T1-T0) says how much time has actually passed (we have lost this much) +// (Tf1-Tf0) says how much time should have passed if we were keeping pace +// (we have gained this much). +// +// Suppliers should therefore work off: +// Quality.Late + (T1-T0) - (Tf1-Tf0) +// and see if this is "acceptably late" or even early (i.e. negative). +// They get T1 and T0 by polling the clock, they get Tf1 and Tf0 from +// the time stamps in the frames. They get Quality.Late from us. +// + +HRESULT CBaseVideoRenderer::SendQuality(REFERENCE_TIME trLate, + REFERENCE_TIME trRealStream) +{ + Quality q; + HRESULT hr; + + // If we are the main user of time, then report this as Flood/Dry. + // If our suppliers are, then report it as Famine/Glut. + // + // We need to take action, but avoid hunting. Hunting is caused by + // 1. Taking too much action too soon and overshooting + // 2. Taking too long to react (so averaging can CAUSE hunting). + // + // The reason why we use trLate as well as Wait is to reduce hunting; + // if the wait time is coming down and about to go into the red, we do + // NOT want to rely on some average which is only telling is that it used + // to be OK once. + + q.TimeStamp = (REFERENCE_TIME)trRealStream; + + if (m_trFrameAvg<0) { + q.Type = Famine; // guess + } + // Is the greater part of the time taken bltting or something else + else if (m_trFrameAvg > 2*m_trRenderAvg) { + q.Type = Famine; // mainly other + } else { + q.Type = Flood; // mainly bltting + } + + q.Proportion = 1000; // default + + if (m_trFrameAvg<0) { + // leave it alone - we don't know enough + } + else if ( trLate> 0 ) { + // try to catch up over the next second + // We could be Really, REALLY late, but rendering all the frames + // anyway, just because it's so cheap. + + q.Proportion = 1000 - (int)((trLate)/(UNITS/1000)); + if (q.Proportion<500) { + q.Proportion = 500; // don't go daft. (could've been negative!) + } else { + } + + } else if ( m_trWaitAvg>20000 + && trLate<-20000 + ){ + // Go cautiously faster - aim at 2mSec wait. + if (m_trWaitAvg>=m_trFrameAvg) { + // This can happen because of some fudges. + // The waitAvg is how long we originally planned to wait + // The frameAvg is more honest. + // It means that we are spending a LOT of time waiting + q.Proportion = 2000; // double. + } else { + if (m_trFrameAvg+20000 > m_trWaitAvg) { + q.Proportion + = 1000 * (m_trFrameAvg / (m_trFrameAvg + 20000 - m_trWaitAvg)); + } else { + // We're apparently spending more than the whole frame time waiting. + // Assume that the averages are slightly out of kilter, but that we + // are indeed doing a lot of waiting. (This leg probably never + // happens, but the code avoids any potential divide by zero). + q.Proportion = 2000; + } + } + + if (q.Proportion>2000) { + q.Proportion = 2000; // don't go crazy. + } + } + + // Tell the supplier how late frames are when they get rendered + // That's how late we are now. + // If we are in directdraw mode then the guy upstream can see the drawing + // times and we'll just report on the start time. He can figure out any + // offset to apply. If we are in DIB Section mode then we will apply an + // extra offset which is half of our drawing time. This is usually small + // but can sometimes be the dominant effect. For this we will use the + // average drawing time rather than the last frame. If the last frame took + // a long time to draw and made us late, that's already in the lateness + // figure. We should not add it in again unless we expect the next frame + // to be the same. We don't, we expect the average to be a better shot. + // In direct draw mode the RenderAvg will be zero. + + q.Late = trLate + m_trRenderAvg/2; + + // log what we're doing + MSR_INTEGER(m_idQualityRate, q.Proportion); + MSR_INTEGER( m_idQualityTime, (int)q.Late / 10000 ); + + // A specific sink interface may be set through IPin + + if (m_pQSink==NULL) { + // Get our input pin's peer. We send quality management messages + // to any nominated receiver of these things (set in the IPin + // interface), or else to our source filter. + + IQualityControl *pQC = NULL; + IPin *pOutputPin = m_pInputPin->GetConnected(); + ASSERT(pOutputPin != NULL); + + // And get an AddRef'd quality control interface + + hr = pOutputPin->QueryInterface(IID_IQualityControl,(void**) &pQC); + if (SUCCEEDED(hr)) { + m_pQSink = pQC; + } + } + if (m_pQSink) { + return m_pQSink->Notify(this,q); + } + + return S_FALSE; + +} // SendQuality + + +// We are called with a valid IMediaSample image to decide whether this is to +// be drawn or not. There must be a reference clock in operation. +// Return S_OK if it is to be drawn Now (as soon as possible) +// Return S_FALSE if it is to be drawn when it's due +// Return an error if we want to drop it +// m_nNormal=-1 indicates that we dropped the previous frame and so this +// one should be drawn early. Respect it and update it. +// Use current stream time plus a number of heuristics (detailed below) +// to make the decision + +HRESULT CBaseVideoRenderer::ShouldDrawSampleNow(IMediaSample *pMediaSample, + REFERENCE_TIME *ptrStart, + REFERENCE_TIME *ptrEnd) +{ + + // Don't call us unless there's a clock interface to synchronise with + ASSERT(m_pClock); + + MSR_INTEGER(m_idTimeStamp, (int)((*ptrStart)>>32)); // high order 32 bits + MSR_INTEGER(m_idTimeStamp, (int)(*ptrStart)); // low order 32 bits + + // We lose a bit of time depending on the monitor type waiting for the next + // screen refresh. On average this might be about 8mSec - so it will be + // later than we think when the picture appears. To compensate a bit + // we bias the media samples by -8mSec i.e. 80000 UNITs. + // We don't ever make a stream time negative (call it paranoia) + if (*ptrStart>=80000) { + *ptrStart -= 80000; + *ptrEnd -= 80000; // bias stop to to retain valid frame duration + } + + // Cache the time stamp now. We will want to compare what we did with what + // we started with (after making the monitor allowance). + m_trRememberStampForPerf = *ptrStart; + + // Get reference times (current and late) + REFERENCE_TIME trRealStream; // the real time now expressed as stream time. + m_pClock->GetTime(&trRealStream); +#ifdef PERF + // While the reference clock is expensive: + // Remember the offset from timeGetTime and use that. + // This overflows all over the place, but when we subtract to get + // differences the overflows all cancel out. + m_llTimeOffset = trRealStream-timeGetTime()*10000; +#endif + trRealStream -= m_tStart; // convert to stream time (this is a reftime) + + // We have to wory about two versions of "lateness". The truth, which we + // try to work out here and the one measured against m_trTarget which + // includes long term feedback. We report statistics against the truth + // but for operational decisions we work to the target. + // We use TimeDiff to make sure we get an integer because we + // may actually be late (or more likely early if there is a big time + // gap) by a very long time. + const int trTrueLate = TimeDiff(trRealStream - *ptrStart); + const int trLate = trTrueLate; + + MSR_INTEGER(m_idSchLateTime, trTrueLate/10000); + + // Send quality control messages upstream, measured against target + HRESULT hr = SendQuality(trLate, trRealStream); + // Note: the filter upstream is allowed to this FAIL meaning "you do it". + m_bSupplierHandlingQuality = (hr==S_OK); + + // Decision time! Do we drop, draw when ready or draw immediately? + + const int trDuration = (int)(*ptrEnd - *ptrStart); + { + // We need to see if the frame rate of the file has just changed. + // This would make comparing our previous frame rate with the current + // frame rate inefficent. Hang on a moment though. I've seen files + // where the frames vary between 33 and 34 mSec so as to average + // 30fps. A minor variation like that won't hurt us. + int t = m_trDuration/32; + if ( trDuration > m_trDuration+t + || trDuration < m_trDuration-t + ) { + // There's a major variation. Reset the average frame rate to + // exactly the current rate to disable decision 9002 for this frame, + // and remember the new rate. + m_trFrameAvg = trDuration; + m_trDuration = trDuration; + } + } + + MSR_INTEGER(m_idEarliness, m_trEarliness/10000); + MSR_INTEGER(m_idRenderAvg, m_trRenderAvg/10000); + MSR_INTEGER(m_idFrameAvg, m_trFrameAvg/10000); + MSR_INTEGER(m_idWaitAvg, m_trWaitAvg/10000); + MSR_INTEGER(m_idDuration, trDuration/10000); + +#ifdef PERF + if (S_OK==pMediaSample->IsDiscontinuity()) { + MSR_INTEGER(m_idDecision, 9000); + } +#endif + + // Control the graceful slide back from slow to fast machine mode. + // After a frame drop accept an early frame and set the earliness to here + // If this frame is already later than the earliness then slide it to here + // otherwise do the standard slide (reduce by about 12% per frame). + // Note: earliness is normally NEGATIVE + BOOL bJustDroppedFrame + = ( m_bSupplierHandlingQuality + // Can't use the pin sample properties because we might + // not be in Receive when we call this + && (S_OK == pMediaSample->IsDiscontinuity()) // he just dropped one + ) + || (m_nNormal==-1); // we just dropped one + + + // Set m_trEarliness (slide back from slow to fast machine mode) + if (trLate>0) { + m_trEarliness = 0; // we are no longer in fast machine mode at all! + } else if ( (trLate>=m_trEarliness) || bJustDroppedFrame) { + m_trEarliness = trLate; // Things have slipped of their own accord + } else { + m_trEarliness = m_trEarliness - m_trEarliness/8; // graceful slide + } + + // prepare the new wait average - but don't pollute the old one until + // we have finished with it. + int trWaitAvg; + { + // We never mix in a negative wait. This causes us to believe in fast machines + // slightly more. + int trL = trLate<0 ? -trLate : 0; + trWaitAvg = (trL + m_trWaitAvg*(AVGPERIOD-1))/AVGPERIOD; + } + + + int trFrame; + { + REFERENCE_TIME tr = trRealStream - m_trLastDraw; // Cd be large - 4 min pause! + if (tr>10000000) { + tr = 10000000; // 1 second - arbitrarily. + } + trFrame = int(tr); + } + + // We will DRAW this frame IF... + if ( + // ...the time we are spending drawing is a small fraction of the total + // observed inter-frame time so that dropping it won't help much. + (3*m_trRenderAvg <= m_trFrameAvg) + + // ...or our supplier is NOT handling things and the next frame would + // be less timely than this one or our supplier CLAIMS to be handling + // things, and is now less than a full FOUR frames late. + || ( m_bSupplierHandlingQuality + ? (trLate <= trDuration*4) + : (trLate+trLate < trDuration) + ) + + // ...or we are on average waiting for over eight milliseconds then + // this may be just a glitch. Draw it and we'll hope to catch up. + || (m_trWaitAvg > 80000) + + // ...or we haven't drawn an image for over a second. We will update + // the display, which stops the video looking hung. + // Do this regardless of how late this media sample is. + || ((trRealStream - m_trLastDraw) > UNITS) + + ) { + HRESULT Result; + + // We are going to play this frame. We may want to play it early. + // We will play it early if we think we are in slow machine mode. + // If we think we are NOT in slow machine mode, we will still play + // it early by m_trEarliness as this controls the graceful slide back. + // and in addition we aim at being m_trTarget late rather than "on time". + + BOOL bPlayASAP = FALSE; + + // we will play it AT ONCE (slow machine mode) if... + + // ...we are playing catch-up + if ( bJustDroppedFrame) { + bPlayASAP = TRUE; + MSR_INTEGER(m_idDecision, 9001); + } + + // ...or if we are running below the true frame rate + // exact comparisons are glitchy, for these measurements, + // so add an extra 5% or so + else if ( (m_trFrameAvg > trDuration + trDuration/16) + + // It's possible to get into a state where we are losing ground, but + // are a very long way ahead. To avoid this or recover from it + // we refuse to play early by more than 10 frames. + && (trLate > - trDuration*10) + ){ + bPlayASAP = TRUE; + MSR_INTEGER(m_idDecision, 9002); + } +#if 0 + // ...or if we have been late and are less than one frame early + else if ( (trLate + trDuration > 0) + && (m_trWaitAvg<=20000) + ) { + bPlayASAP = TRUE; + MSR_INTEGER(m_idDecision, 9003); + } +#endif + // We will NOT play it at once if we are grossly early. On very slow frame + // rate movies - e.g. clock.avi - it is not a good idea to leap ahead just + // because we got starved (for instance by the net) and dropped one frame + // some time or other. If we are more than 900mSec early, then wait. + if (trLate<-9000000) { + bPlayASAP = FALSE; + } + + if (bPlayASAP) { + + m_nNormal = 0; + MSR_INTEGER(m_idDecision, 0); + // When we are here, we are in slow-machine mode. trLate may well + // oscillate between negative and positive when the supplier is + // dropping frames to keep sync. We should not let that mislead + // us into thinking that we have as much as zero spare time! + // We just update with a zero wait. + m_trWaitAvg = (m_trWaitAvg*(AVGPERIOD-1))/AVGPERIOD; + + // Assume that we draw it immediately. Update inter-frame stats + m_trFrameAvg = (trFrame + m_trFrameAvg*(AVGPERIOD-1))/AVGPERIOD; +#ifndef PERF + // If this is NOT a perf build, then report what we know so far + // without looking at the clock any more. This assumes that we + // actually wait for exactly the time we hope to. It also reports + // how close we get to the manipulated time stamps that we now have + // rather than the ones we originally started with. It will + // therefore be a little optimistic. However it's fast. + PreparePerformanceData(trTrueLate, trFrame); +#endif + m_trLastDraw = trRealStream; + if (m_trEarliness > trLate) { + m_trEarliness = trLate; // if we are actually early, this is neg + } + Result = S_OK; // Draw it now + + } else { + ++m_nNormal; + // Set the average frame rate to EXACTLY the ideal rate. + // If we are exiting slow-machine mode then we will have caught up + // and be running ahead, so as we slide back to exact timing we will + // have a longer than usual gap at this point. If we record this + // real gap then we'll think that we're running slow and go back + // into slow-machine mode and vever get it straight. + m_trFrameAvg = trDuration; + MSR_INTEGER(m_idDecision, 1); + + // Play it early by m_trEarliness and by m_trTarget + + { + int trE = m_trEarliness; + if (trE < -m_trFrameAvg) { + trE = -m_trFrameAvg; + } + *ptrStart += trE; // N.B. earliness is negative + } + + int Delay = -trTrueLate; + Result = Delay<=0 ? S_OK : S_FALSE; // OK = draw now, FALSE = wait + + m_trWaitAvg = trWaitAvg; + + // Predict when it will actually be drawn and update frame stats + + if (Result==S_FALSE) { // We are going to wait + trFrame = TimeDiff(*ptrStart-m_trLastDraw); + m_trLastDraw = *ptrStart; + } else { + // trFrame is already = trRealStream-m_trLastDraw; + m_trLastDraw = trRealStream; + } +#ifndef PERF + int iAccuracy; + if (Delay>0) { + // Report lateness based on when we intend to play it + iAccuracy = TimeDiff(*ptrStart-m_trRememberStampForPerf); + } else { + // Report lateness based on playing it *now*. + iAccuracy = trTrueLate; // trRealStream-RememberStampForPerf; + } + PreparePerformanceData(iAccuracy, trFrame); +#endif + } + return Result; + } + + // We are going to drop this frame! + // Of course in DirectDraw mode the guy upstream may draw it anyway. + + // This will probably give a large negative wack to the wait avg. + m_trWaitAvg = trWaitAvg; + +#ifdef PERF + // Respect registry setting - debug only! + if (m_bDrawLateFrames) { + return S_OK; // draw it when it's ready + } // even though it's late. +#endif + + // We are going to drop this frame so draw the next one early + // n.b. if the supplier is doing direct draw then he may draw it anyway + // but he's doing something funny to arrive here in that case. + + MSR_INTEGER(m_idDecision, 2); + m_nNormal = -1; + return E_FAIL; // drop it + +} // ShouldDrawSampleNow + + +// NOTE we're called by both the window thread and the source filter thread +// so we have to be protected by a critical section (locked before called) +// Also, when the window thread gets signalled to render an image, it always +// does so regardless of how late it is. All the degradation is done when we +// are scheduling the next sample to be drawn. Hence when we start an advise +// link to draw a sample, that sample's time will always become the last one +// drawn - unless of course we stop streaming in which case we cancel links + +BOOL CBaseVideoRenderer::ScheduleSample(IMediaSample *pMediaSample) +{ + // We override ShouldDrawSampleNow to add quality management + + BOOL bDrawImage = CBaseRenderer::ScheduleSample(pMediaSample); + if (bDrawImage == FALSE) { + ++m_cFramesDropped; + return FALSE; + } + + // m_cFramesDrawn must NOT be updated here. It has to be updated + // in RecordFrameLateness at the same time as the other statistics. + return TRUE; +} + + +// Implementation of IQualProp interface needed to support the property page +// This is how the property page gets the data out of the scheduler. We are +// passed into the constructor the owning object in the COM sense, this will +// either be the video renderer or an external IUnknown if we're aggregated. +// We initialise our CUnknown base class with this interface pointer. Then +// all we have to do is to override NonDelegatingQueryInterface to expose +// our IQualProp interface. The AddRef and Release are handled automatically +// by the base class and will be passed on to the appropriate outer object + +STDMETHODIMP CBaseVideoRenderer::get_FramesDroppedInRenderer(int *pcFramesDropped) +{ + CheckPointer(pcFramesDropped,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + *pcFramesDropped = m_cFramesDropped; + return NOERROR; +} // get_FramesDroppedInRenderer + + +// Set *pcFramesDrawn to the number of frames drawn since +// streaming started. + +STDMETHODIMP CBaseVideoRenderer::get_FramesDrawn( int *pcFramesDrawn) +{ + CheckPointer(pcFramesDrawn,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + *pcFramesDrawn = m_cFramesDrawn; + return NOERROR; +} // get_FramesDrawn + + +// Set iAvgFrameRate to the frames per hundred secs since +// streaming started. 0 otherwise. + +STDMETHODIMP CBaseVideoRenderer::get_AvgFrameRate( int *piAvgFrameRate) +{ + CheckPointer(piAvgFrameRate,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + + int t; + if (m_bStreaming) { + t = timeGetTime()-m_tStreamingStart; + } else { + t = m_tStreamingStart; + } + + if (t<=0) { + *piAvgFrameRate = 0; + ASSERT(m_cFramesDrawn == 0); + } else { + // i is frames per hundred seconds + *piAvgFrameRate = MulDiv(100000, m_cFramesDrawn, t); + } + return NOERROR; +} // get_AvgFrameRate + + +// Set *piAvg to the average sync offset since streaming started +// in mSec. The sync offset is the time in mSec between when the frame +// should have been drawn and when the frame was actually drawn. + +STDMETHODIMP CBaseVideoRenderer::get_AvgSyncOffset( int *piAvg) +{ + CheckPointer(piAvg,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + + if (NULL==m_pClock) { + *piAvg = 0; + return NOERROR; + } + + // Note that we didn't gather the stats on the first frame + // so we use m_cFramesDrawn-1 here + if (m_cFramesDrawn<=1) { + *piAvg = 0; + } else { + *piAvg = (int)(m_iTotAcc / (m_cFramesDrawn-1)); + } + return NOERROR; +} // get_AvgSyncOffset + + +// To avoid dragging in the maths library - a cheap +// approximate integer square root. +// We do this by getting a starting guess which is between 1 +// and 2 times too large, followed by THREE iterations of +// Newton Raphson. (That will give accuracy to the nearest mSec +// for the range in question - roughly 0..1000) +// +// It would be faster to use a linear interpolation and ONE NR, but +// who cares. If anyone does - the best linear interpolation is +// to approximates sqrt(x) by +// y = x * (sqrt(2)-1) + 1 - 1/sqrt(2) + 1/(8*(sqrt(2)-1)) +// 0r y = x*0.41421 + 0.59467 +// This minimises the maximal error in the range in question. +// (error is about +0.008883 and then one NR will give error .0000something +// (Of course these are integers, so you can't just multiply by 0.41421 +// you'd have to do some sort of MulDiv). +// Anyone wanna check my maths? (This is only for a property display!) + +int isqrt(int x) +{ + int s = 1; + // Make s an initial guess for sqrt(x) + if (x > 0x40000000) { + s = 0x8000; // prevent any conceivable closed loop + } else { + while (s*s=0) s = (s*s+x)/(2*s); + if (s>=0) s = (s*s+x)/(2*s); + } + } + return s; +} + +// +// Do estimates for standard deviations for per-frame +// statistics +// +HRESULT CBaseVideoRenderer::GetStdDev( + int nSamples, + int *piResult, + LONGLONG llSumSq, + LONGLONG iTot +) +{ + CheckPointer(piResult,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + + if (NULL==m_pClock) { + *piResult = 0; + return NOERROR; + } + + // If S is the Sum of the Squares of observations and + // T the Total (i.e. sum) of the observations and there were + // N observations, then an estimate of the standard deviation is + // sqrt( (S - T**2/N) / (N-1) ) + + if (nSamples<=1) { + *piResult = 0; + } else { + LONGLONG x; + // First frames have invalid stamps, so we get no stats for them + // So we need 2 frames to get 1 datum, so N is cFramesDrawn-1 + + // so we use m_cFramesDrawn-1 here + x = llSumSq - llMulDiv(iTot, iTot, nSamples, 0); + x = x / (nSamples-1); + ASSERT(x>=0); + *piResult = isqrt((LONG)x); + } + return NOERROR; +} + +// Set *piDev to the standard deviation in mSec of the sync offset +// of each frame since streaming started. + +STDMETHODIMP CBaseVideoRenderer::get_DevSyncOffset( int *piDev) +{ + // First frames have invalid stamps, so we get no stats for them + // So we need 2 frames to get 1 datum, so N is cFramesDrawn-1 + return GetStdDev(m_cFramesDrawn - 1, + piDev, + m_iSumSqAcc, + m_iTotAcc); +} // get_DevSyncOffset + + +// Set *piJitter to the standard deviation in mSec of the inter-frame time +// of frames since streaming started. + +STDMETHODIMP CBaseVideoRenderer::get_Jitter( int *piJitter) +{ + // First frames have invalid stamps, so we get no stats for them + // So second frame gives invalid inter-frame time + // So we need 3 frames to get 1 datum, so N is cFramesDrawn-2 + return GetStdDev(m_cFramesDrawn - 2, + piJitter, + m_iSumSqFrameTime, + m_iSumFrameTime); +} // get_Jitter + + +// Overidden to return our IQualProp interface + +STDMETHODIMP +CBaseVideoRenderer::NonDelegatingQueryInterface(REFIID riid,VOID **ppv) +{ + // We return IQualProp and delegate everything else + + if (riid == IID_IQualProp) { + return GetInterface( (IQualProp *)this, ppv); + } else if (riid == IID_IQualityControl) { + return GetInterface( (IQualityControl *)this, ppv); + } + return CBaseRenderer::NonDelegatingQueryInterface(riid,ppv); +} + + +// Override JoinFilterGraph so that, just before leaving +// the graph we can send an EC_WINDOW_DESTROYED event + +STDMETHODIMP +CBaseVideoRenderer::JoinFilterGraph(IFilterGraph *pGraph,LPCWSTR pName) +{ + // Since we send EC_ACTIVATE, we also need to ensure + // we send EC_WINDOW_DESTROYED or the resource manager may be + // holding us as a focus object + if (!pGraph && m_pGraph) { + + // We were in a graph and now we're not + // Do this properly in case we are aggregated + IBaseFilter* pFilter; + QueryInterface(IID_IBaseFilter,(void **) &pFilter); + NotifyEvent(EC_WINDOW_DESTROYED, (LPARAM) pFilter, 0); + pFilter->Release(); + } + return CBaseFilter::JoinFilterGraph(pGraph, pName); +} + + +// This removes a large number of level 4 warnings from the +// Microsoft compiler which in this case are not very useful +#pragma warning(disable: 4514) + diff --git a/plugins/GSdx/baseclasses/renbase.h b/plugins/GSdx/baseclasses/renbase.h index f30a3fad19..5352e873b4 100644 --- a/plugins/GSdx/baseclasses/renbase.h +++ b/plugins/GSdx/baseclasses/renbase.h @@ -1,478 +1,478 @@ -//------------------------------------------------------------------------------ -// File: RenBase.h -// -// Desc: DirectShow base classes - defines a generic ActiveX base renderer -// class. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __RENBASE__ -#define __RENBASE__ - -// Forward class declarations - -class CBaseRenderer; -class CBaseVideoRenderer; -class CRendererInputPin; - -// This is our input pin class that channels calls to the renderer - -class CRendererInputPin : public CBaseInputPin -{ -protected: - - CBaseRenderer *m_pRenderer; - -public: - - CRendererInputPin(CBaseRenderer *pRenderer, - HRESULT *phr, - LPCWSTR Name); - - // Overriden from the base pin classes - - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin *pReceivePin); - HRESULT SetMediaType(const CMediaType *pmt); - HRESULT CheckMediaType(const CMediaType *pmt); - HRESULT Active(); - HRESULT Inactive(); - - // Add rendering behaviour to interface functions - - STDMETHODIMP QueryId(LPWSTR *Id); - STDMETHODIMP EndOfStream(); - STDMETHODIMP BeginFlush(); - STDMETHODIMP EndFlush(); - STDMETHODIMP Receive(IMediaSample *pMediaSample); - - // Helper - IMemAllocator inline *Allocator() const - { - return m_pAllocator; - } -}; - -// Main renderer class that handles synchronisation and state changes - -class CBaseRenderer : public CBaseFilter -{ -protected: - - friend class CRendererInputPin; - - friend void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier - UINT uMsg, // Not currently used - DWORD_PTR dwUser, // User information - DWORD_PTR dw1, // Windows reserved - DWORD_PTR dw2); // Is also reserved - - CRendererPosPassThru *m_pPosition; // Media seeking pass by object - CAMEvent m_RenderEvent; // Used to signal timer events - CAMEvent m_ThreadSignal; // Signalled to release worker thread - CAMEvent m_evComplete; // Signalled when state complete - BOOL m_bAbort; // Stop us from rendering more data - BOOL m_bStreaming; // Are we currently streaming - DWORD_PTR m_dwAdvise; // Timer advise cookie - IMediaSample *m_pMediaSample; // Current image media sample - BOOL m_bEOS; // Any more samples in the stream - BOOL m_bEOSDelivered; // Have we delivered an EC_COMPLETE - CRendererInputPin *m_pInputPin; // Our renderer input pin object - CCritSec m_InterfaceLock; // Critical section for interfaces - CCritSec m_RendererLock; // Controls access to internals - IQualityControl * m_pQSink; // QualityControl sink - BOOL m_bRepaintStatus; // Can we signal an EC_REPAINT - // Avoid some deadlocks by tracking filter during stop - volatile BOOL m_bInReceive; // Inside Receive between PrepareReceive - // And actually processing the sample - REFERENCE_TIME m_SignalTime; // Time when we signal EC_COMPLETE - UINT m_EndOfStreamTimer; // Used to signal end of stream - CCritSec m_ObjectCreationLock; // This lock protects the creation and - // of m_pPosition and m_pInputPin. It - // ensures that two threads cannot create - // either object simultaneously. - -public: - - CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer - TCHAR *pName, // Debug ONLY description - LPUNKNOWN pUnk, // Aggregated owner object - HRESULT *phr); // General OLE return code - - ~CBaseRenderer(); - - // Overriden to say what interfaces we support and where - - virtual HRESULT GetMediaPositionInterface(REFIID riid,void **ppv); - STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **); - - virtual HRESULT SourceThreadCanWait(BOOL bCanWait); - -#ifdef DEBUG - // Debug only dump of the renderer state - void DisplayRendererState(); -#endif - virtual HRESULT WaitForRenderTime(); - virtual HRESULT CompleteStateChange(FILTER_STATE OldState); - - // Return internal information about this filter - - BOOL IsEndOfStream() { return m_bEOS; }; - BOOL IsEndOfStreamDelivered() { return m_bEOSDelivered; }; - BOOL IsStreaming() { return m_bStreaming; }; - void SetAbortSignal(BOOL bAbort) { m_bAbort = bAbort; }; - virtual void OnReceiveFirstSample(IMediaSample *pMediaSample) { }; - CAMEvent *GetRenderEvent() { return &m_RenderEvent; }; - - // Permit access to the transition state - - void Ready() { m_evComplete.Set(); }; - void NotReady() { m_evComplete.Reset(); }; - BOOL CheckReady() { return m_evComplete.Check(); }; - - virtual int GetPinCount(); - virtual CBasePin *GetPin(int n); - FILTER_STATE GetRealState(); - void SendRepaint(); - void SendNotifyWindow(IPin *pPin,HWND hwnd); - BOOL OnDisplayChange(); - void SetRepaintStatus(BOOL bRepaint); - - // Override the filter and pin interface functions - - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - STDMETHODIMP Run(REFERENCE_TIME StartTime); - STDMETHODIMP GetState(DWORD dwMSecs,FILTER_STATE *State); - STDMETHODIMP FindPin(LPCWSTR Id, IPin **ppPin); - - // These are available for a quality management implementation - - virtual void OnRenderStart(IMediaSample *pMediaSample); - virtual void OnRenderEnd(IMediaSample *pMediaSample); - virtual HRESULT OnStartStreaming() { return NOERROR; }; - virtual HRESULT OnStopStreaming() { return NOERROR; }; - virtual void OnWaitStart() { }; - virtual void OnWaitEnd() { }; - virtual void PrepareRender() { }; - -#ifdef PERF - REFERENCE_TIME m_trRenderStart; // Just before we started drawing - // Set in OnRenderStart, Used in OnRenderEnd - int m_idBaseStamp; // MSR_id for frame time stamp - int m_idBaseRenderTime; // MSR_id for true wait time - int m_idBaseAccuracy; // MSR_id for time frame is late (int) -#endif - - // Quality management implementation for scheduling rendering - - virtual BOOL ScheduleSample(IMediaSample *pMediaSample); - virtual HRESULT GetSampleTimes(IMediaSample *pMediaSample, - REFERENCE_TIME *pStartTime, - REFERENCE_TIME *pEndTime); - - virtual HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample, - REFERENCE_TIME *ptrStart, - REFERENCE_TIME *ptrEnd); - - // Lots of end of stream complexities - - void TimerCallback(); - void ResetEndOfStreamTimer(); - HRESULT NotifyEndOfStream(); - virtual HRESULT SendEndOfStream(); - virtual HRESULT ResetEndOfStream(); - virtual HRESULT EndOfStream(); - - // Rendering is based around the clock - - void SignalTimerFired(); - virtual HRESULT CancelNotification(); - virtual HRESULT ClearPendingSample(); - - // Called when the filter changes state - - virtual HRESULT Active(); - virtual HRESULT Inactive(); - virtual HRESULT StartStreaming(); - virtual HRESULT StopStreaming(); - virtual HRESULT BeginFlush(); - virtual HRESULT EndFlush(); - - // Deal with connections and type changes - - virtual HRESULT BreakConnect(); - virtual HRESULT SetMediaType(const CMediaType *pmt); - virtual HRESULT CompleteConnect(IPin *pReceivePin); - - // These look after the handling of data samples - - virtual HRESULT PrepareReceive(IMediaSample *pMediaSample); - virtual HRESULT Receive(IMediaSample *pMediaSample); - virtual BOOL HaveCurrentSample(); - virtual IMediaSample *GetCurrentSample(); - virtual HRESULT Render(IMediaSample *pMediaSample); - - // Derived classes MUST override these - virtual HRESULT DoRenderSample(IMediaSample *pMediaSample) PURE; - virtual HRESULT CheckMediaType(const CMediaType *) PURE; - - // Helper - void WaitForReceiveToComplete(); -}; - - -// CBaseVideoRenderer is a renderer class (see its ancestor class) and -// it handles scheduling of media samples so that they are drawn at the -// correct time by the reference clock. It implements a degradation -// strategy. Possible degradation modes are: -// Drop frames here (only useful if the drawing takes significant time) -// Signal supplier (upstream) to drop some frame(s) - i.e. one-off skip. -// Signal supplier to change the frame rate - i.e. ongoing skipping. -// Or any combination of the above. -// In order to determine what's useful to try we need to know what's going -// on. This is done by timing various operations (including the supplier). -// This timing is done by using timeGetTime as it is accurate enough and -// usually cheaper than calling the reference clock. It also tells the -// truth if there is an audio break and the reference clock stops. -// We provide a number of public entry points (named OnXxxStart, OnXxxEnd) -// which the rest of the renderer calls at significant moments. These do -// the timing. - -// the number of frames that the sliding averages are averaged over. -// the rule is (1024*NewObservation + (AVGPERIOD-1) * PreviousAverage)/AVGPERIOD -#define AVGPERIOD 4 -#define DO_MOVING_AVG(avg,obs) (avg = (1024*obs + (AVGPERIOD-1)*avg)/AVGPERIOD) -// Spot the bug in this macro - I can't. but it doesn't work! - -class CBaseVideoRenderer : public CBaseRenderer, // Base renderer class - public IQualProp, // Property page guff - public IQualityControl // Allow throttling -{ -protected: - - // Hungarian: - // tFoo is the time Foo in mSec (beware m_tStart from filter.h) - // trBar is the time Bar by the reference clock - - //****************************************************************** - // State variables to control synchronisation - //****************************************************************** - - // Control of sending Quality messages. We need to know whether - // we are in trouble (e.g. frames being dropped) and where the time - // is being spent. - - // When we drop a frame we play the next one early. - // The frame after that is likely to wait before drawing and counting this - // wait as spare time is unfair, so we count it as a zero wait. - // We therefore need to know whether we are playing frames early or not. - - int m_nNormal; // The number of consecutive frames - // drawn at their normal time (not early) - // -1 means we just dropped a frame. - -#ifdef PERF - BOOL m_bDrawLateFrames; // Don't drop any frames (debug and I'm - // not keen on people using it!) -#endif - - BOOL m_bSupplierHandlingQuality;// The response to Quality messages says - // our supplier is handling things. - // We will allow things to go extra late - // before dropping frames. We will play - // very early after he has dropped one. - - // Control of scheduling, frame dropping etc. - // We need to know where the time is being spent so as to tell whether - // we should be taking action here, signalling supplier or what. - // The variables are initialised to a mode of NOT dropping frames. - // They will tell the truth after a few frames. - // We typically record a start time for an event, later we get the time - // again and subtract to get the elapsed time, and we average this over - // a few frames. The average is used to tell what mode we are in. - - // Although these are reference times (64 bit) they are all DIFFERENCES - // between times which are small. An int will go up to 214 secs before - // overflow. Avoiding 64 bit multiplications and divisions seems - // worth while. - - - - // Audio-video throttling. If the user has turned up audio quality - // very high (in principle it could be any other stream, not just audio) - // then we can receive cries for help via the graph manager. In this case - // we put in a wait for some time after rendering each frame. - int m_trThrottle; - - // The time taken to render (i.e. BitBlt) frames controls which component - // needs to degrade. If the blt is expensive, the renderer degrades. - // If the blt is cheap it's done anyway and the supplier degrades. - int m_trRenderAvg; // Time frames are taking to blt - int m_trRenderLast; // Time for last frame blt - int m_tRenderStart; // Just before we started drawing (mSec) - // derived from timeGetTime. - - // When frames are dropped we will play the next frame as early as we can. - // If it was a false alarm and the machine is fast we slide gently back to - // normal timing. To do this, we record the offset showing just how early - // we really are. This will normally be negative meaning early or zero. - int m_trEarliness; - - // Target provides slow long-term feedback to try to reduce the - // average sync offset to zero. Whenever a frame is actually rendered - // early we add a msec or two, whenever late we take off a few. - // We add or take off 1/32 of the error time. - // Eventually we should be hovering around zero. For a really bad case - // where we were (say) 300mSec off, it might take 100 odd frames to - // settle down. The rate of change of this is intended to be slower - // than any other mechanism in Quartz, thereby avoiding hunting. - int m_trTarget; - - // The proportion of time spent waiting for the right moment to blt - // controls whether we bother to drop a frame or whether we reckon that - // we're doing well enough that we can stand a one-frame glitch. - int m_trWaitAvg; // Average of last few wait times - // (actually we just average how early - // we were). Negative here means LATE. - - // The average inter-frame time. - // This is used to calculate the proportion of the time used by the - // three operations (supplying us, waiting, rendering) - int m_trFrameAvg; // Average inter-frame time - int m_trDuration; // duration of last frame. - -#ifdef PERF - // Performance logging identifiers - int m_idTimeStamp; // MSR_id for frame time stamp - int m_idEarliness; // MSR_id for earliness fudge - int m_idTarget; // MSR_id for Target fudge - int m_idWaitReal; // MSR_id for true wait time - int m_idWait; // MSR_id for wait time recorded - int m_idFrameAccuracy; // MSR_id for time frame is late (int) - int m_idRenderAvg; // MSR_id for Render time recorded (int) - int m_idSchLateTime; // MSR_id for lateness at scheduler - int m_idQualityRate; // MSR_id for Quality rate requested - int m_idQualityTime; // MSR_id for Quality time requested - int m_idDecision; // MSR_id for decision code - int m_idDuration; // MSR_id for duration of a frame - int m_idThrottle; // MSR_id for audio-video throttling - //int m_idDebug; // MSR_id for trace style debugging - //int m_idSendQuality; // MSR_id for timing the notifications per se -#endif // PERF - REFERENCE_TIME m_trRememberStampForPerf; // original time stamp of frame - // with no earliness fudges etc. -#ifdef PERF - REFERENCE_TIME m_trRememberFrameForPerf; // time when previous frame rendered - - // debug... - int m_idFrameAvg; - int m_idWaitAvg; -#endif - - // PROPERTY PAGE - // This has edit fields that show the user what's happening - // These member variables hold these counts. - - int m_cFramesDropped; // cumulative frames dropped IN THE RENDERER - int m_cFramesDrawn; // Frames since streaming started seen BY THE - // RENDERER (some may be dropped upstream) - - // Next two support average sync offset and standard deviation of sync offset. - LONGLONG m_iTotAcc; // Sum of accuracies in mSec - LONGLONG m_iSumSqAcc; // Sum of squares of (accuracies in mSec) - - // Next two allow jitter calculation. Jitter is std deviation of frame time. - REFERENCE_TIME m_trLastDraw; // Time of prev frame (for inter-frame times) - LONGLONG m_iSumSqFrameTime; // Sum of squares of (inter-frame time in mSec) - LONGLONG m_iSumFrameTime; // Sum of inter-frame times in mSec - - // To get performance statistics on frame rate, jitter etc, we need - // to record the lateness and inter-frame time. What we actually need are the - // data above (sum, sum of squares and number of entries for each) but the data - // is generated just ahead of time and only later do we discover whether the - // frame was actually drawn or not. So we have to hang on to the data - int m_trLate; // hold onto frame lateness - int m_trFrame; // hold onto inter-frame time - - int m_tStreamingStart; // if streaming then time streaming started - // else time of last streaming session - // used for property page statistics -#ifdef PERF - LONGLONG m_llTimeOffset; // timeGetTime()*10000+m_llTimeOffset==ref time -#endif - -public: - - - CBaseVideoRenderer(REFCLSID RenderClass, // CLSID for this renderer - TCHAR *pName, // Debug ONLY description - LPUNKNOWN pUnk, // Aggregated owner object - HRESULT *phr); // General OLE return code - - ~CBaseVideoRenderer(); - - // IQualityControl methods - Notify allows audio-video throttling - - STDMETHODIMP SetSink( IQualityControl * piqc); - STDMETHODIMP Notify( IBaseFilter * pSelf, Quality q); - - // These provide a full video quality management implementation - - void OnRenderStart(IMediaSample *pMediaSample); - void OnRenderEnd(IMediaSample *pMediaSample); - void OnWaitStart(); - void OnWaitEnd(); - HRESULT OnStartStreaming(); - HRESULT OnStopStreaming(); - void ThrottleWait(); - - // Handle the statistics gathering for our quality management - - void PreparePerformanceData(int trLate, int trFrame); - virtual void RecordFrameLateness(int trLate, int trFrame); - virtual void OnDirectRender(IMediaSample *pMediaSample); - virtual HRESULT ResetStreamingTimes(); - BOOL ScheduleSample(IMediaSample *pMediaSample); - HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample, - REFERENCE_TIME *ptrStart, - REFERENCE_TIME *ptrEnd); - - virtual HRESULT SendQuality(REFERENCE_TIME trLate, REFERENCE_TIME trRealStream); - STDMETHODIMP JoinFilterGraph(IFilterGraph * pGraph, LPCWSTR pName); - - // - // Do estimates for standard deviations for per-frame - // statistics - // - // *piResult = (llSumSq - iTot * iTot / m_cFramesDrawn - 1) / - // (m_cFramesDrawn - 2) - // or 0 if m_cFramesDrawn <= 3 - // - HRESULT GetStdDev( - int nSamples, - int *piResult, - LONGLONG llSumSq, - LONGLONG iTot - ); -public: - - // IQualProp property page support - - STDMETHODIMP get_FramesDroppedInRenderer(int *cFramesDropped); - STDMETHODIMP get_FramesDrawn(int *pcFramesDrawn); - STDMETHODIMP get_AvgFrameRate(int *piAvgFrameRate); - STDMETHODIMP get_Jitter(int *piJitter); - STDMETHODIMP get_AvgSyncOffset(int *piAvg); - STDMETHODIMP get_DevSyncOffset(int *piDev); - - // Implement an IUnknown interface and expose IQualProp - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,VOID **ppv); -}; - -#endif // __RENBASE__ - +//------------------------------------------------------------------------------ +// File: RenBase.h +// +// Desc: DirectShow base classes - defines a generic ActiveX base renderer +// class. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __RENBASE__ +#define __RENBASE__ + +// Forward class declarations + +class CBaseRenderer; +class CBaseVideoRenderer; +class CRendererInputPin; + +// This is our input pin class that channels calls to the renderer + +class CRendererInputPin : public CBaseInputPin +{ +protected: + + CBaseRenderer *m_pRenderer; + +public: + + CRendererInputPin(CBaseRenderer *pRenderer, + HRESULT *phr, + LPCWSTR Name); + + // Overriden from the base pin classes + + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin *pReceivePin); + HRESULT SetMediaType(const CMediaType *pmt); + HRESULT CheckMediaType(const CMediaType *pmt); + HRESULT Active(); + HRESULT Inactive(); + + // Add rendering behaviour to interface functions + + STDMETHODIMP QueryId(LPWSTR *Id); + STDMETHODIMP EndOfStream(); + STDMETHODIMP BeginFlush(); + STDMETHODIMP EndFlush(); + STDMETHODIMP Receive(IMediaSample *pMediaSample); + + // Helper + IMemAllocator inline *Allocator() const + { + return m_pAllocator; + } +}; + +// Main renderer class that handles synchronisation and state changes + +class CBaseRenderer : public CBaseFilter +{ +protected: + + friend class CRendererInputPin; + + friend void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier + UINT uMsg, // Not currently used + DWORD_PTR dwUser, // User information + DWORD_PTR dw1, // Windows reserved + DWORD_PTR dw2); // Is also reserved + + CRendererPosPassThru *m_pPosition; // Media seeking pass by object + CAMEvent m_RenderEvent; // Used to signal timer events + CAMEvent m_ThreadSignal; // Signalled to release worker thread + CAMEvent m_evComplete; // Signalled when state complete + BOOL m_bAbort; // Stop us from rendering more data + BOOL m_bStreaming; // Are we currently streaming + DWORD_PTR m_dwAdvise; // Timer advise cookie + IMediaSample *m_pMediaSample; // Current image media sample + BOOL m_bEOS; // Any more samples in the stream + BOOL m_bEOSDelivered; // Have we delivered an EC_COMPLETE + CRendererInputPin *m_pInputPin; // Our renderer input pin object + CCritSec m_InterfaceLock; // Critical section for interfaces + CCritSec m_RendererLock; // Controls access to internals + IQualityControl * m_pQSink; // QualityControl sink + BOOL m_bRepaintStatus; // Can we signal an EC_REPAINT + // Avoid some deadlocks by tracking filter during stop + volatile BOOL m_bInReceive; // Inside Receive between PrepareReceive + // And actually processing the sample + REFERENCE_TIME m_SignalTime; // Time when we signal EC_COMPLETE + UINT m_EndOfStreamTimer; // Used to signal end of stream + CCritSec m_ObjectCreationLock; // This lock protects the creation and + // of m_pPosition and m_pInputPin. It + // ensures that two threads cannot create + // either object simultaneously. + +public: + + CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer + TCHAR *pName, // Debug ONLY description + LPUNKNOWN pUnk, // Aggregated owner object + HRESULT *phr); // General OLE return code + + ~CBaseRenderer(); + + // Overriden to say what interfaces we support and where + + virtual HRESULT GetMediaPositionInterface(REFIID riid,void **ppv); + STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **); + + virtual HRESULT SourceThreadCanWait(BOOL bCanWait); + +#ifdef DEBUG + // Debug only dump of the renderer state + void DisplayRendererState(); +#endif + virtual HRESULT WaitForRenderTime(); + virtual HRESULT CompleteStateChange(FILTER_STATE OldState); + + // Return internal information about this filter + + BOOL IsEndOfStream() { return m_bEOS; }; + BOOL IsEndOfStreamDelivered() { return m_bEOSDelivered; }; + BOOL IsStreaming() { return m_bStreaming; }; + void SetAbortSignal(BOOL bAbort) { m_bAbort = bAbort; }; + virtual void OnReceiveFirstSample(IMediaSample *pMediaSample) { }; + CAMEvent *GetRenderEvent() { return &m_RenderEvent; }; + + // Permit access to the transition state + + void Ready() { m_evComplete.Set(); }; + void NotReady() { m_evComplete.Reset(); }; + BOOL CheckReady() { return m_evComplete.Check(); }; + + virtual int GetPinCount(); + virtual CBasePin *GetPin(int n); + FILTER_STATE GetRealState(); + void SendRepaint(); + void SendNotifyWindow(IPin *pPin,HWND hwnd); + BOOL OnDisplayChange(); + void SetRepaintStatus(BOOL bRepaint); + + // Override the filter and pin interface functions + + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + STDMETHODIMP Run(REFERENCE_TIME StartTime); + STDMETHODIMP GetState(DWORD dwMSecs,FILTER_STATE *State); + STDMETHODIMP FindPin(LPCWSTR Id, IPin **ppPin); + + // These are available for a quality management implementation + + virtual void OnRenderStart(IMediaSample *pMediaSample); + virtual void OnRenderEnd(IMediaSample *pMediaSample); + virtual HRESULT OnStartStreaming() { return NOERROR; }; + virtual HRESULT OnStopStreaming() { return NOERROR; }; + virtual void OnWaitStart() { }; + virtual void OnWaitEnd() { }; + virtual void PrepareRender() { }; + +#ifdef PERF + REFERENCE_TIME m_trRenderStart; // Just before we started drawing + // Set in OnRenderStart, Used in OnRenderEnd + int m_idBaseStamp; // MSR_id for frame time stamp + int m_idBaseRenderTime; // MSR_id for true wait time + int m_idBaseAccuracy; // MSR_id for time frame is late (int) +#endif + + // Quality management implementation for scheduling rendering + + virtual BOOL ScheduleSample(IMediaSample *pMediaSample); + virtual HRESULT GetSampleTimes(IMediaSample *pMediaSample, + REFERENCE_TIME *pStartTime, + REFERENCE_TIME *pEndTime); + + virtual HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample, + REFERENCE_TIME *ptrStart, + REFERENCE_TIME *ptrEnd); + + // Lots of end of stream complexities + + void TimerCallback(); + void ResetEndOfStreamTimer(); + HRESULT NotifyEndOfStream(); + virtual HRESULT SendEndOfStream(); + virtual HRESULT ResetEndOfStream(); + virtual HRESULT EndOfStream(); + + // Rendering is based around the clock + + void SignalTimerFired(); + virtual HRESULT CancelNotification(); + virtual HRESULT ClearPendingSample(); + + // Called when the filter changes state + + virtual HRESULT Active(); + virtual HRESULT Inactive(); + virtual HRESULT StartStreaming(); + virtual HRESULT StopStreaming(); + virtual HRESULT BeginFlush(); + virtual HRESULT EndFlush(); + + // Deal with connections and type changes + + virtual HRESULT BreakConnect(); + virtual HRESULT SetMediaType(const CMediaType *pmt); + virtual HRESULT CompleteConnect(IPin *pReceivePin); + + // These look after the handling of data samples + + virtual HRESULT PrepareReceive(IMediaSample *pMediaSample); + virtual HRESULT Receive(IMediaSample *pMediaSample); + virtual BOOL HaveCurrentSample(); + virtual IMediaSample *GetCurrentSample(); + virtual HRESULT Render(IMediaSample *pMediaSample); + + // Derived classes MUST override these + virtual HRESULT DoRenderSample(IMediaSample *pMediaSample) PURE; + virtual HRESULT CheckMediaType(const CMediaType *) PURE; + + // Helper + void WaitForReceiveToComplete(); +}; + + +// CBaseVideoRenderer is a renderer class (see its ancestor class) and +// it handles scheduling of media samples so that they are drawn at the +// correct time by the reference clock. It implements a degradation +// strategy. Possible degradation modes are: +// Drop frames here (only useful if the drawing takes significant time) +// Signal supplier (upstream) to drop some frame(s) - i.e. one-off skip. +// Signal supplier to change the frame rate - i.e. ongoing skipping. +// Or any combination of the above. +// In order to determine what's useful to try we need to know what's going +// on. This is done by timing various operations (including the supplier). +// This timing is done by using timeGetTime as it is accurate enough and +// usually cheaper than calling the reference clock. It also tells the +// truth if there is an audio break and the reference clock stops. +// We provide a number of public entry points (named OnXxxStart, OnXxxEnd) +// which the rest of the renderer calls at significant moments. These do +// the timing. + +// the number of frames that the sliding averages are averaged over. +// the rule is (1024*NewObservation + (AVGPERIOD-1) * PreviousAverage)/AVGPERIOD +#define AVGPERIOD 4 +#define DO_MOVING_AVG(avg,obs) (avg = (1024*obs + (AVGPERIOD-1)*avg)/AVGPERIOD) +// Spot the bug in this macro - I can't. but it doesn't work! + +class CBaseVideoRenderer : public CBaseRenderer, // Base renderer class + public IQualProp, // Property page guff + public IQualityControl // Allow throttling +{ +protected: + + // Hungarian: + // tFoo is the time Foo in mSec (beware m_tStart from filter.h) + // trBar is the time Bar by the reference clock + + //****************************************************************** + // State variables to control synchronisation + //****************************************************************** + + // Control of sending Quality messages. We need to know whether + // we are in trouble (e.g. frames being dropped) and where the time + // is being spent. + + // When we drop a frame we play the next one early. + // The frame after that is likely to wait before drawing and counting this + // wait as spare time is unfair, so we count it as a zero wait. + // We therefore need to know whether we are playing frames early or not. + + int m_nNormal; // The number of consecutive frames + // drawn at their normal time (not early) + // -1 means we just dropped a frame. + +#ifdef PERF + BOOL m_bDrawLateFrames; // Don't drop any frames (debug and I'm + // not keen on people using it!) +#endif + + BOOL m_bSupplierHandlingQuality;// The response to Quality messages says + // our supplier is handling things. + // We will allow things to go extra late + // before dropping frames. We will play + // very early after he has dropped one. + + // Control of scheduling, frame dropping etc. + // We need to know where the time is being spent so as to tell whether + // we should be taking action here, signalling supplier or what. + // The variables are initialised to a mode of NOT dropping frames. + // They will tell the truth after a few frames. + // We typically record a start time for an event, later we get the time + // again and subtract to get the elapsed time, and we average this over + // a few frames. The average is used to tell what mode we are in. + + // Although these are reference times (64 bit) they are all DIFFERENCES + // between times which are small. An int will go up to 214 secs before + // overflow. Avoiding 64 bit multiplications and divisions seems + // worth while. + + + + // Audio-video throttling. If the user has turned up audio quality + // very high (in principle it could be any other stream, not just audio) + // then we can receive cries for help via the graph manager. In this case + // we put in a wait for some time after rendering each frame. + int m_trThrottle; + + // The time taken to render (i.e. BitBlt) frames controls which component + // needs to degrade. If the blt is expensive, the renderer degrades. + // If the blt is cheap it's done anyway and the supplier degrades. + int m_trRenderAvg; // Time frames are taking to blt + int m_trRenderLast; // Time for last frame blt + int m_tRenderStart; // Just before we started drawing (mSec) + // derived from timeGetTime. + + // When frames are dropped we will play the next frame as early as we can. + // If it was a false alarm and the machine is fast we slide gently back to + // normal timing. To do this, we record the offset showing just how early + // we really are. This will normally be negative meaning early or zero. + int m_trEarliness; + + // Target provides slow long-term feedback to try to reduce the + // average sync offset to zero. Whenever a frame is actually rendered + // early we add a msec or two, whenever late we take off a few. + // We add or take off 1/32 of the error time. + // Eventually we should be hovering around zero. For a really bad case + // where we were (say) 300mSec off, it might take 100 odd frames to + // settle down. The rate of change of this is intended to be slower + // than any other mechanism in Quartz, thereby avoiding hunting. + int m_trTarget; + + // The proportion of time spent waiting for the right moment to blt + // controls whether we bother to drop a frame or whether we reckon that + // we're doing well enough that we can stand a one-frame glitch. + int m_trWaitAvg; // Average of last few wait times + // (actually we just average how early + // we were). Negative here means LATE. + + // The average inter-frame time. + // This is used to calculate the proportion of the time used by the + // three operations (supplying us, waiting, rendering) + int m_trFrameAvg; // Average inter-frame time + int m_trDuration; // duration of last frame. + +#ifdef PERF + // Performance logging identifiers + int m_idTimeStamp; // MSR_id for frame time stamp + int m_idEarliness; // MSR_id for earliness fudge + int m_idTarget; // MSR_id for Target fudge + int m_idWaitReal; // MSR_id for true wait time + int m_idWait; // MSR_id for wait time recorded + int m_idFrameAccuracy; // MSR_id for time frame is late (int) + int m_idRenderAvg; // MSR_id for Render time recorded (int) + int m_idSchLateTime; // MSR_id for lateness at scheduler + int m_idQualityRate; // MSR_id for Quality rate requested + int m_idQualityTime; // MSR_id for Quality time requested + int m_idDecision; // MSR_id for decision code + int m_idDuration; // MSR_id for duration of a frame + int m_idThrottle; // MSR_id for audio-video throttling + //int m_idDebug; // MSR_id for trace style debugging + //int m_idSendQuality; // MSR_id for timing the notifications per se +#endif // PERF + REFERENCE_TIME m_trRememberStampForPerf; // original time stamp of frame + // with no earliness fudges etc. +#ifdef PERF + REFERENCE_TIME m_trRememberFrameForPerf; // time when previous frame rendered + + // debug... + int m_idFrameAvg; + int m_idWaitAvg; +#endif + + // PROPERTY PAGE + // This has edit fields that show the user what's happening + // These member variables hold these counts. + + int m_cFramesDropped; // cumulative frames dropped IN THE RENDERER + int m_cFramesDrawn; // Frames since streaming started seen BY THE + // RENDERER (some may be dropped upstream) + + // Next two support average sync offset and standard deviation of sync offset. + LONGLONG m_iTotAcc; // Sum of accuracies in mSec + LONGLONG m_iSumSqAcc; // Sum of squares of (accuracies in mSec) + + // Next two allow jitter calculation. Jitter is std deviation of frame time. + REFERENCE_TIME m_trLastDraw; // Time of prev frame (for inter-frame times) + LONGLONG m_iSumSqFrameTime; // Sum of squares of (inter-frame time in mSec) + LONGLONG m_iSumFrameTime; // Sum of inter-frame times in mSec + + // To get performance statistics on frame rate, jitter etc, we need + // to record the lateness and inter-frame time. What we actually need are the + // data above (sum, sum of squares and number of entries for each) but the data + // is generated just ahead of time and only later do we discover whether the + // frame was actually drawn or not. So we have to hang on to the data + int m_trLate; // hold onto frame lateness + int m_trFrame; // hold onto inter-frame time + + int m_tStreamingStart; // if streaming then time streaming started + // else time of last streaming session + // used for property page statistics +#ifdef PERF + LONGLONG m_llTimeOffset; // timeGetTime()*10000+m_llTimeOffset==ref time +#endif + +public: + + + CBaseVideoRenderer(REFCLSID RenderClass, // CLSID for this renderer + TCHAR *pName, // Debug ONLY description + LPUNKNOWN pUnk, // Aggregated owner object + HRESULT *phr); // General OLE return code + + ~CBaseVideoRenderer(); + + // IQualityControl methods - Notify allows audio-video throttling + + STDMETHODIMP SetSink( IQualityControl * piqc); + STDMETHODIMP Notify( IBaseFilter * pSelf, Quality q); + + // These provide a full video quality management implementation + + void OnRenderStart(IMediaSample *pMediaSample); + void OnRenderEnd(IMediaSample *pMediaSample); + void OnWaitStart(); + void OnWaitEnd(); + HRESULT OnStartStreaming(); + HRESULT OnStopStreaming(); + void ThrottleWait(); + + // Handle the statistics gathering for our quality management + + void PreparePerformanceData(int trLate, int trFrame); + virtual void RecordFrameLateness(int trLate, int trFrame); + virtual void OnDirectRender(IMediaSample *pMediaSample); + virtual HRESULT ResetStreamingTimes(); + BOOL ScheduleSample(IMediaSample *pMediaSample); + HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample, + REFERENCE_TIME *ptrStart, + REFERENCE_TIME *ptrEnd); + + virtual HRESULT SendQuality(REFERENCE_TIME trLate, REFERENCE_TIME trRealStream); + STDMETHODIMP JoinFilterGraph(IFilterGraph * pGraph, LPCWSTR pName); + + // + // Do estimates for standard deviations for per-frame + // statistics + // + // *piResult = (llSumSq - iTot * iTot / m_cFramesDrawn - 1) / + // (m_cFramesDrawn - 2) + // or 0 if m_cFramesDrawn <= 3 + // + HRESULT GetStdDev( + int nSamples, + int *piResult, + LONGLONG llSumSq, + LONGLONG iTot + ); +public: + + // IQualProp property page support + + STDMETHODIMP get_FramesDroppedInRenderer(int *cFramesDropped); + STDMETHODIMP get_FramesDrawn(int *pcFramesDrawn); + STDMETHODIMP get_AvgFrameRate(int *piAvgFrameRate); + STDMETHODIMP get_Jitter(int *piJitter); + STDMETHODIMP get_AvgSyncOffset(int *piAvg); + STDMETHODIMP get_DevSyncOffset(int *piDev); + + // Implement an IUnknown interface and expose IQualProp + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,VOID **ppv); +}; + +#endif // __RENBASE__ + diff --git a/plugins/GSdx/baseclasses/schedule.cpp b/plugins/GSdx/baseclasses/schedule.cpp index 170f1427b7..f377a9ee2b 100644 --- a/plugins/GSdx/baseclasses/schedule.cpp +++ b/plugins/GSdx/baseclasses/schedule.cpp @@ -1,284 +1,284 @@ -//------------------------------------------------------------------------------ -// File: Schedule.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" - -// DbgLog values (all on LOG_TIMING): -// -// 2 for schedulting, firing and shunting of events -// 3 for wait delays and wake-up times of event thread -// 4 for details of whats on the list when the thread awakes - -/* Construct & destructors */ - -CAMSchedule::CAMSchedule( HANDLE ev ) -: CBaseObject(TEXT("CAMSchedule")) -, head(&z, 0), z(0, MAX_TIME) -, m_dwNextCookie(0), m_dwAdviseCount(0) -, m_pAdviseCache(0), m_dwCacheCount(0) -, m_ev( ev ) -{ - head.m_dwAdviseCookie = z.m_dwAdviseCookie = 0; -} - -CAMSchedule::~CAMSchedule() -{ - m_Serialize.Lock(); - - // Delete cache - CAdvisePacket * p = m_pAdviseCache; - while (p) - { - CAdvisePacket *const p_next = p->m_next; - delete p; - p = p_next; - } - - ASSERT( m_dwAdviseCount == 0 ); - // Better to be safe than sorry - if ( m_dwAdviseCount > 0 ) - { - DumpLinkedList(); - while ( !head.m_next->IsZ() ) - { - head.DeleteNext(); - --m_dwAdviseCount; - } - } - - // If, in the debug version, we assert twice, it means, not only - // did we have left over advises, but we have also let m_dwAdviseCount - // get out of sync. with the number of advises actually on the list. - ASSERT( m_dwAdviseCount == 0 ); - - m_Serialize.Unlock(); -} - -/* Public methods */ - -DWORD CAMSchedule::GetAdviseCount() -{ - // No need to lock, m_dwAdviseCount is 32bits & declared volatile - return m_dwAdviseCount; -} - -REFERENCE_TIME CAMSchedule::GetNextAdviseTime() -{ - CAutoLock lck(&m_Serialize); // Need to stop the linked list from changing - return head.m_next->m_rtEventTime; -} - -DWORD_PTR CAMSchedule::AddAdvisePacket -( const REFERENCE_TIME & time1 -, const REFERENCE_TIME & time2 -, HANDLE h, BOOL periodic -) -{ - // Since we use MAX_TIME as a sentry, we can't afford to - // schedule a notification at MAX_TIME - ASSERT( time1 < MAX_TIME ); - DWORD_PTR Result; - CAdvisePacket * p; - - m_Serialize.Lock(); - - if (m_pAdviseCache) - { - p = m_pAdviseCache; - m_pAdviseCache = p->m_next; - --m_dwCacheCount; - } - else - { - p = new CAdvisePacket(); - } - if (p) - { - p->m_rtEventTime = time1; p->m_rtPeriod = time2; - p->m_hNotify = h; p->m_bPeriodic = periodic; - Result = AddAdvisePacket( p ); - } - else Result = 0; - - m_Serialize.Unlock(); - - return Result; -} - -HRESULT CAMSchedule::Unadvise(DWORD_PTR dwAdviseCookie) -{ - HRESULT hr = S_FALSE; - CAdvisePacket * p_prev = &head; - CAdvisePacket * p_n; - m_Serialize.Lock(); - while ( p_n = p_prev->Next() ) // The Next() method returns NULL when it hits z - { - if ( p_n->m_dwAdviseCookie == dwAdviseCookie ) - { - Delete( p_prev->RemoveNext() ); - --m_dwAdviseCount; - hr = S_OK; - // Having found one cookie that matches, there should be no more - #ifdef DEBUG - while (p_n = p_prev->Next()) - { - ASSERT(p_n->m_dwAdviseCookie != dwAdviseCookie); - p_prev = p_n; - } - #endif - break; - } - p_prev = p_n; - }; - m_Serialize.Unlock(); - return hr; -} - -REFERENCE_TIME CAMSchedule::Advise( const REFERENCE_TIME & rtTime ) -{ - REFERENCE_TIME rtNextTime; - CAdvisePacket * pAdvise; - - DbgLog((LOG_TIMING, 2, - TEXT("CAMSchedule::Advise( %lu ms )"), ULONG(rtTime / (UNITS / MILLISECONDS)))); - - CAutoLock lck(&m_Serialize); - - #ifdef DEBUG - if (DbgCheckModuleLevel(LOG_TIMING, 4)) DumpLinkedList(); - #endif - - // Note - DON'T cache the difference, it might overflow - while ( rtTime >= (rtNextTime = (pAdvise=head.m_next)->m_rtEventTime) && - !pAdvise->IsZ() ) - { - ASSERT(pAdvise->m_dwAdviseCookie); // If this is zero, its the head or the tail!! - - ASSERT(pAdvise->m_hNotify != INVALID_HANDLE_VALUE); - - if (pAdvise->m_bPeriodic == TRUE) - { - ReleaseSemaphore(pAdvise->m_hNotify,1,NULL); - pAdvise->m_rtEventTime += pAdvise->m_rtPeriod; - ShuntHead(); - } - else - { - ASSERT( pAdvise->m_bPeriodic == FALSE ); - EXECUTE_ASSERT(SetEvent(pAdvise->m_hNotify)); - --m_dwAdviseCount; - Delete( head.RemoveNext() ); - } - - } - - DbgLog((LOG_TIMING, 3, - TEXT("CAMSchedule::Advise() Next time stamp: %lu ms, for advise %lu."), - DWORD(rtNextTime / (UNITS / MILLISECONDS)), pAdvise->m_dwAdviseCookie )); - - return rtNextTime; -} - -/* Private methods */ - -DWORD_PTR CAMSchedule::AddAdvisePacket( CAdvisePacket * pPacket ) -{ - ASSERT(pPacket->m_rtEventTime >= 0 && pPacket->m_rtEventTime < MAX_TIME); - ASSERT(CritCheckIn(&m_Serialize)); - - CAdvisePacket * p_prev = &head; - CAdvisePacket * p_n; - - const DWORD_PTR Result = pPacket->m_dwAdviseCookie = ++m_dwNextCookie; - // This relies on the fact that z is a sentry with a maximal m_rtEventTime - for(;;p_prev = p_n) - { - p_n = p_prev->m_next; - if ( p_n->m_rtEventTime >= pPacket->m_rtEventTime ) break; - } - p_prev->InsertAfter( pPacket ); - ++m_dwAdviseCount; - - DbgLog((LOG_TIMING, 2, TEXT("Added advise %lu, for thread 0x%02X, scheduled at %lu"), - pPacket->m_dwAdviseCookie, GetCurrentThreadId(), (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) )); - - // If packet added at the head, then clock needs to re-evaluate wait time. - if ( p_prev == &head ) SetEvent( m_ev ); - - return Result; -} - -void CAMSchedule::Delete( CAdvisePacket * pPacket ) -{ - if ( m_dwCacheCount >= dwCacheMax ) delete pPacket; - else - { - m_Serialize.Lock(); - pPacket->m_next = m_pAdviseCache; - m_pAdviseCache = pPacket; - ++m_dwCacheCount; - m_Serialize.Unlock(); - } -} - - -// Takes the head of the list & repositions it -void CAMSchedule::ShuntHead() -{ - CAdvisePacket * p_prev = &head; - CAdvisePacket * p_n; - - m_Serialize.Lock(); - CAdvisePacket *const pPacket = head.m_next; - - // This will catch both an empty list, - // and if somehow a MAX_TIME time gets into the list - // (which would also break this method). - ASSERT( pPacket->m_rtEventTime < MAX_TIME ); - - // This relies on the fact that z is a sentry with a maximal m_rtEventTime - for(;;p_prev = p_n) - { - p_n = p_prev->m_next; - if ( p_n->m_rtEventTime > pPacket->m_rtEventTime ) break; - } - // If p_prev == pPacket then we're already in the right place - if (p_prev != pPacket) - { - head.m_next = pPacket->m_next; - (p_prev->m_next = pPacket)->m_next = p_n; - } - #ifdef DEBUG - DbgLog((LOG_TIMING, 2, TEXT("Periodic advise %lu, shunted to %lu"), - pPacket->m_dwAdviseCookie, (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) )); - #endif - m_Serialize.Unlock(); -} - - -#ifdef DEBUG -void CAMSchedule::DumpLinkedList() -{ - m_Serialize.Lock(); - int i=0; - DbgLog((LOG_TIMING, 1, TEXT("CAMSchedule::DumpLinkedList() this = 0x%p"), this)); - for ( CAdvisePacket * p = &head - ; p - ; p = p->m_next , i++ - ) - { - DbgLog((LOG_TIMING, 1, TEXT("Advise List # %lu, Cookie %d, RefTime %lu"), - i, - p->m_dwAdviseCookie, - p->m_rtEventTime / (UNITS / MILLISECONDS) - )); - } - m_Serialize.Unlock(); -} -#endif +//------------------------------------------------------------------------------ +// File: Schedule.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" + +// DbgLog values (all on LOG_TIMING): +// +// 2 for schedulting, firing and shunting of events +// 3 for wait delays and wake-up times of event thread +// 4 for details of whats on the list when the thread awakes + +/* Construct & destructors */ + +CAMSchedule::CAMSchedule( HANDLE ev ) +: CBaseObject(TEXT("CAMSchedule")) +, head(&z, 0), z(0, MAX_TIME) +, m_dwNextCookie(0), m_dwAdviseCount(0) +, m_pAdviseCache(0), m_dwCacheCount(0) +, m_ev( ev ) +{ + head.m_dwAdviseCookie = z.m_dwAdviseCookie = 0; +} + +CAMSchedule::~CAMSchedule() +{ + m_Serialize.Lock(); + + // Delete cache + CAdvisePacket * p = m_pAdviseCache; + while (p) + { + CAdvisePacket *const p_next = p->m_next; + delete p; + p = p_next; + } + + ASSERT( m_dwAdviseCount == 0 ); + // Better to be safe than sorry + if ( m_dwAdviseCount > 0 ) + { + DumpLinkedList(); + while ( !head.m_next->IsZ() ) + { + head.DeleteNext(); + --m_dwAdviseCount; + } + } + + // If, in the debug version, we assert twice, it means, not only + // did we have left over advises, but we have also let m_dwAdviseCount + // get out of sync. with the number of advises actually on the list. + ASSERT( m_dwAdviseCount == 0 ); + + m_Serialize.Unlock(); +} + +/* Public methods */ + +DWORD CAMSchedule::GetAdviseCount() +{ + // No need to lock, m_dwAdviseCount is 32bits & declared volatile + return m_dwAdviseCount; +} + +REFERENCE_TIME CAMSchedule::GetNextAdviseTime() +{ + CAutoLock lck(&m_Serialize); // Need to stop the linked list from changing + return head.m_next->m_rtEventTime; +} + +DWORD_PTR CAMSchedule::AddAdvisePacket +( const REFERENCE_TIME & time1 +, const REFERENCE_TIME & time2 +, HANDLE h, BOOL periodic +) +{ + // Since we use MAX_TIME as a sentry, we can't afford to + // schedule a notification at MAX_TIME + ASSERT( time1 < MAX_TIME ); + DWORD_PTR Result; + CAdvisePacket * p; + + m_Serialize.Lock(); + + if (m_pAdviseCache) + { + p = m_pAdviseCache; + m_pAdviseCache = p->m_next; + --m_dwCacheCount; + } + else + { + p = new CAdvisePacket(); + } + if (p) + { + p->m_rtEventTime = time1; p->m_rtPeriod = time2; + p->m_hNotify = h; p->m_bPeriodic = periodic; + Result = AddAdvisePacket( p ); + } + else Result = 0; + + m_Serialize.Unlock(); + + return Result; +} + +HRESULT CAMSchedule::Unadvise(DWORD_PTR dwAdviseCookie) +{ + HRESULT hr = S_FALSE; + CAdvisePacket * p_prev = &head; + CAdvisePacket * p_n; + m_Serialize.Lock(); + while ( p_n = p_prev->Next() ) // The Next() method returns NULL when it hits z + { + if ( p_n->m_dwAdviseCookie == dwAdviseCookie ) + { + Delete( p_prev->RemoveNext() ); + --m_dwAdviseCount; + hr = S_OK; + // Having found one cookie that matches, there should be no more + #ifdef DEBUG + while (p_n = p_prev->Next()) + { + ASSERT(p_n->m_dwAdviseCookie != dwAdviseCookie); + p_prev = p_n; + } + #endif + break; + } + p_prev = p_n; + }; + m_Serialize.Unlock(); + return hr; +} + +REFERENCE_TIME CAMSchedule::Advise( const REFERENCE_TIME & rtTime ) +{ + REFERENCE_TIME rtNextTime; + CAdvisePacket * pAdvise; + + DbgLog((LOG_TIMING, 2, + TEXT("CAMSchedule::Advise( %lu ms )"), ULONG(rtTime / (UNITS / MILLISECONDS)))); + + CAutoLock lck(&m_Serialize); + + #ifdef DEBUG + if (DbgCheckModuleLevel(LOG_TIMING, 4)) DumpLinkedList(); + #endif + + // Note - DON'T cache the difference, it might overflow + while ( rtTime >= (rtNextTime = (pAdvise=head.m_next)->m_rtEventTime) && + !pAdvise->IsZ() ) + { + ASSERT(pAdvise->m_dwAdviseCookie); // If this is zero, its the head or the tail!! + + ASSERT(pAdvise->m_hNotify != INVALID_HANDLE_VALUE); + + if (pAdvise->m_bPeriodic == TRUE) + { + ReleaseSemaphore(pAdvise->m_hNotify,1,NULL); + pAdvise->m_rtEventTime += pAdvise->m_rtPeriod; + ShuntHead(); + } + else + { + ASSERT( pAdvise->m_bPeriodic == FALSE ); + EXECUTE_ASSERT(SetEvent(pAdvise->m_hNotify)); + --m_dwAdviseCount; + Delete( head.RemoveNext() ); + } + + } + + DbgLog((LOG_TIMING, 3, + TEXT("CAMSchedule::Advise() Next time stamp: %lu ms, for advise %lu."), + DWORD(rtNextTime / (UNITS / MILLISECONDS)), pAdvise->m_dwAdviseCookie )); + + return rtNextTime; +} + +/* Private methods */ + +DWORD_PTR CAMSchedule::AddAdvisePacket( CAdvisePacket * pPacket ) +{ + ASSERT(pPacket->m_rtEventTime >= 0 && pPacket->m_rtEventTime < MAX_TIME); + ASSERT(CritCheckIn(&m_Serialize)); + + CAdvisePacket * p_prev = &head; + CAdvisePacket * p_n; + + const DWORD_PTR Result = pPacket->m_dwAdviseCookie = ++m_dwNextCookie; + // This relies on the fact that z is a sentry with a maximal m_rtEventTime + for(;;p_prev = p_n) + { + p_n = p_prev->m_next; + if ( p_n->m_rtEventTime >= pPacket->m_rtEventTime ) break; + } + p_prev->InsertAfter( pPacket ); + ++m_dwAdviseCount; + + DbgLog((LOG_TIMING, 2, TEXT("Added advise %lu, for thread 0x%02X, scheduled at %lu"), + pPacket->m_dwAdviseCookie, GetCurrentThreadId(), (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) )); + + // If packet added at the head, then clock needs to re-evaluate wait time. + if ( p_prev == &head ) SetEvent( m_ev ); + + return Result; +} + +void CAMSchedule::Delete( CAdvisePacket * pPacket ) +{ + if ( m_dwCacheCount >= dwCacheMax ) delete pPacket; + else + { + m_Serialize.Lock(); + pPacket->m_next = m_pAdviseCache; + m_pAdviseCache = pPacket; + ++m_dwCacheCount; + m_Serialize.Unlock(); + } +} + + +// Takes the head of the list & repositions it +void CAMSchedule::ShuntHead() +{ + CAdvisePacket * p_prev = &head; + CAdvisePacket * p_n; + + m_Serialize.Lock(); + CAdvisePacket *const pPacket = head.m_next; + + // This will catch both an empty list, + // and if somehow a MAX_TIME time gets into the list + // (which would also break this method). + ASSERT( pPacket->m_rtEventTime < MAX_TIME ); + + // This relies on the fact that z is a sentry with a maximal m_rtEventTime + for(;;p_prev = p_n) + { + p_n = p_prev->m_next; + if ( p_n->m_rtEventTime > pPacket->m_rtEventTime ) break; + } + // If p_prev == pPacket then we're already in the right place + if (p_prev != pPacket) + { + head.m_next = pPacket->m_next; + (p_prev->m_next = pPacket)->m_next = p_n; + } + #ifdef DEBUG + DbgLog((LOG_TIMING, 2, TEXT("Periodic advise %lu, shunted to %lu"), + pPacket->m_dwAdviseCookie, (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) )); + #endif + m_Serialize.Unlock(); +} + + +#ifdef DEBUG +void CAMSchedule::DumpLinkedList() +{ + m_Serialize.Lock(); + int i=0; + DbgLog((LOG_TIMING, 1, TEXT("CAMSchedule::DumpLinkedList() this = 0x%p"), this)); + for ( CAdvisePacket * p = &head + ; p + ; p = p->m_next , i++ + ) + { + DbgLog((LOG_TIMING, 1, TEXT("Advise List # %lu, Cookie %d, RefTime %lu"), + i, + p->m_dwAdviseCookie, + p->m_rtEventTime / (UNITS / MILLISECONDS) + )); + } + m_Serialize.Unlock(); +} +#endif diff --git a/plugins/GSdx/baseclasses/schedule.h b/plugins/GSdx/baseclasses/schedule.h index 2d01911b31..e7873072c0 100644 --- a/plugins/GSdx/baseclasses/schedule.h +++ b/plugins/GSdx/baseclasses/schedule.h @@ -1,128 +1,128 @@ -//------------------------------------------------------------------------------ -// File: Schedule.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __CAMSchedule__ -#define __CAMSchedule__ - -class CAMSchedule : private CBaseObject -{ -public: - virtual ~CAMSchedule(); - // ev is the event we should fire if the advise time needs re-evaluating - CAMSchedule( HANDLE ev ); - - DWORD GetAdviseCount(); - REFERENCE_TIME GetNextAdviseTime(); - - // We need a method for derived classes to add advise packets, we return the cookie - DWORD_PTR AddAdvisePacket( const REFERENCE_TIME & time1, const REFERENCE_TIME & time2, HANDLE h, BOOL periodic ); - // And a way to cancel - HRESULT Unadvise(DWORD_PTR dwAdviseCookie); - - // Tell us the time please, and we'll dispatch the expired events. We return the time of the next event. - // NB: The time returned will be "useless" if you start adding extra Advises. But that's the problem of - // whoever is using this helper class (typically a clock). - REFERENCE_TIME Advise( const REFERENCE_TIME & rtTime ); - - // Get the event handle which will be set if advise time requires re-evaluation. - HANDLE GetEvent() const { return m_ev; } - -private: - // We define the nodes that will be used in our singly linked list - // of advise packets. The list is ordered by time, with the - // elements that will expire first at the front. - class CAdvisePacket - { - public: - CAdvisePacket() - {} - - CAdvisePacket * m_next; - DWORD_PTR m_dwAdviseCookie; - REFERENCE_TIME m_rtEventTime; // Time at which event should be set - REFERENCE_TIME m_rtPeriod; // Periodic time - HANDLE m_hNotify; // Handle to event or semephore - BOOL m_bPeriodic; // TRUE => Periodic event - - CAdvisePacket( CAdvisePacket * next, LONGLONG time ) : m_next(next), m_rtEventTime(time) - {} - - void InsertAfter( CAdvisePacket * p ) - { - p->m_next = m_next; - m_next = p; - } - - int IsZ() const // That is, is it the node that represents the end of the list - { return m_next == 0; } - - CAdvisePacket * RemoveNext() - { - CAdvisePacket *const next = m_next; - CAdvisePacket *const new_next = next->m_next; - m_next = new_next; - return next; - } - - void DeleteNext() - { - delete RemoveNext(); - } - - CAdvisePacket * Next() const - { - CAdvisePacket * result = m_next; - if (result->IsZ()) result = 0; - return result; - } - - DWORD_PTR Cookie() const - { return m_dwAdviseCookie; } - }; - - // Structure is: - // head -> elmt1 -> elmt2 -> z -> null - // So an empty list is: head -> z -> null - // Having head & z as links makes insertaion, - // deletion and shunting much easier. - CAdvisePacket head, z; // z is both a tail and a sentry - - volatile DWORD_PTR m_dwNextCookie; // Strictly increasing - volatile DWORD m_dwAdviseCount; // Number of elements on list - - CCritSec m_Serialize; - - // AddAdvisePacket: adds the packet, returns the cookie (0 if failed) - DWORD_PTR AddAdvisePacket( CAdvisePacket * pPacket ); - // Event that we should set if the packed added above will be the next to fire. - const HANDLE m_ev; - - // A Shunt is where we have changed the first element in the - // list and want it re-evaluating (i.e. repositioned) in - // the list. - void ShuntHead(); - - // Rather than delete advise packets, we cache them for future use - CAdvisePacket * m_pAdviseCache; - DWORD m_dwCacheCount; - enum { dwCacheMax = 5 }; // Don't bother caching more than five - - void Delete( CAdvisePacket * pLink );// This "Delete" will cache the Link - -// Attributes and methods for debugging -public: -#ifdef DEBUG - void DumpLinkedList(); -#else - void DumpLinkedList() {} -#endif - -}; - -#endif // __CAMSchedule__ +//------------------------------------------------------------------------------ +// File: Schedule.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __CAMSchedule__ +#define __CAMSchedule__ + +class CAMSchedule : private CBaseObject +{ +public: + virtual ~CAMSchedule(); + // ev is the event we should fire if the advise time needs re-evaluating + CAMSchedule( HANDLE ev ); + + DWORD GetAdviseCount(); + REFERENCE_TIME GetNextAdviseTime(); + + // We need a method for derived classes to add advise packets, we return the cookie + DWORD_PTR AddAdvisePacket( const REFERENCE_TIME & time1, const REFERENCE_TIME & time2, HANDLE h, BOOL periodic ); + // And a way to cancel + HRESULT Unadvise(DWORD_PTR dwAdviseCookie); + + // Tell us the time please, and we'll dispatch the expired events. We return the time of the next event. + // NB: The time returned will be "useless" if you start adding extra Advises. But that's the problem of + // whoever is using this helper class (typically a clock). + REFERENCE_TIME Advise( const REFERENCE_TIME & rtTime ); + + // Get the event handle which will be set if advise time requires re-evaluation. + HANDLE GetEvent() const { return m_ev; } + +private: + // We define the nodes that will be used in our singly linked list + // of advise packets. The list is ordered by time, with the + // elements that will expire first at the front. + class CAdvisePacket + { + public: + CAdvisePacket() + {} + + CAdvisePacket * m_next; + DWORD_PTR m_dwAdviseCookie; + REFERENCE_TIME m_rtEventTime; // Time at which event should be set + REFERENCE_TIME m_rtPeriod; // Periodic time + HANDLE m_hNotify; // Handle to event or semephore + BOOL m_bPeriodic; // TRUE => Periodic event + + CAdvisePacket( CAdvisePacket * next, LONGLONG time ) : m_next(next), m_rtEventTime(time) + {} + + void InsertAfter( CAdvisePacket * p ) + { + p->m_next = m_next; + m_next = p; + } + + int IsZ() const // That is, is it the node that represents the end of the list + { return m_next == 0; } + + CAdvisePacket * RemoveNext() + { + CAdvisePacket *const next = m_next; + CAdvisePacket *const new_next = next->m_next; + m_next = new_next; + return next; + } + + void DeleteNext() + { + delete RemoveNext(); + } + + CAdvisePacket * Next() const + { + CAdvisePacket * result = m_next; + if (result->IsZ()) result = 0; + return result; + } + + DWORD_PTR Cookie() const + { return m_dwAdviseCookie; } + }; + + // Structure is: + // head -> elmt1 -> elmt2 -> z -> null + // So an empty list is: head -> z -> null + // Having head & z as links makes insertaion, + // deletion and shunting much easier. + CAdvisePacket head, z; // z is both a tail and a sentry + + volatile DWORD_PTR m_dwNextCookie; // Strictly increasing + volatile DWORD m_dwAdviseCount; // Number of elements on list + + CCritSec m_Serialize; + + // AddAdvisePacket: adds the packet, returns the cookie (0 if failed) + DWORD_PTR AddAdvisePacket( CAdvisePacket * pPacket ); + // Event that we should set if the packed added above will be the next to fire. + const HANDLE m_ev; + + // A Shunt is where we have changed the first element in the + // list and want it re-evaluating (i.e. repositioned) in + // the list. + void ShuntHead(); + + // Rather than delete advise packets, we cache them for future use + CAdvisePacket * m_pAdviseCache; + DWORD m_dwCacheCount; + enum { dwCacheMax = 5 }; // Don't bother caching more than five + + void Delete( CAdvisePacket * pLink );// This "Delete" will cache the Link + +// Attributes and methods for debugging +public: +#ifdef DEBUG + void DumpLinkedList(); +#else + void DumpLinkedList() {} +#endif + +}; + +#endif // __CAMSchedule__ diff --git a/plugins/GSdx/baseclasses/seekpt.cpp b/plugins/GSdx/baseclasses/seekpt.cpp index 5b90c09505..d01eea326e 100644 --- a/plugins/GSdx/baseclasses/seekpt.cpp +++ b/plugins/GSdx/baseclasses/seekpt.cpp @@ -1,83 +1,83 @@ -//------------------------------------------------------------------------------ -// File: SeekPT.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include "seekpt.h" - -//================================================================== -// CreateInstance -// This goes in the factory template table to create new instances -// If there is already a mapper instance - return that, else make one -// and save it in a static variable so that forever after we can return that. -//================================================================== - -CUnknown * CSeekingPassThru::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) -{ - return new CSeekingPassThru(NAME("Seeking PassThru"),pUnk, phr); -} - - -STDMETHODIMP CSeekingPassThru::NonDelegatingQueryInterface(REFIID riid, void ** ppv) -{ - if (riid == IID_ISeekingPassThru) { - return GetInterface((ISeekingPassThru *) this, ppv); - } else { - if (m_pPosPassThru && - (riid == IID_IMediaSeeking || - riid == IID_IMediaPosition)) { - return m_pPosPassThru->NonDelegatingQueryInterface(riid,ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } - } -} - - -CSeekingPassThru::CSeekingPassThru( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr ) - : CUnknown(pName, pUnk, phr), - m_pPosPassThru(NULL) -{ -} - - -CSeekingPassThru::~CSeekingPassThru() -{ - delete m_pPosPassThru; -} - -STDMETHODIMP CSeekingPassThru::Init(BOOL bRendererSeeking, IPin *pPin) -{ - HRESULT hr = NOERROR; - if (m_pPosPassThru) { - hr = E_FAIL; - } else { - m_pPosPassThru = - bRendererSeeking ? - new CRendererPosPassThru( - NAME("Render Seeking COM object"), - (IUnknown *)this, - &hr, - pPin) : - new CPosPassThru( - NAME("Render Seeking COM object"), - (IUnknown *)this, - &hr, - pPin); - if (!m_pPosPassThru) { - hr = E_OUTOFMEMORY; - } else { - if (FAILED(hr)) { - delete m_pPosPassThru; - m_pPosPassThru = NULL; - } - } - } - return hr; -} - +//------------------------------------------------------------------------------ +// File: SeekPT.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include "seekpt.h" + +//================================================================== +// CreateInstance +// This goes in the factory template table to create new instances +// If there is already a mapper instance - return that, else make one +// and save it in a static variable so that forever after we can return that. +//================================================================== + +CUnknown * CSeekingPassThru::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) +{ + return new CSeekingPassThru(NAME("Seeking PassThru"),pUnk, phr); +} + + +STDMETHODIMP CSeekingPassThru::NonDelegatingQueryInterface(REFIID riid, void ** ppv) +{ + if (riid == IID_ISeekingPassThru) { + return GetInterface((ISeekingPassThru *) this, ppv); + } else { + if (m_pPosPassThru && + (riid == IID_IMediaSeeking || + riid == IID_IMediaPosition)) { + return m_pPosPassThru->NonDelegatingQueryInterface(riid,ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + } +} + + +CSeekingPassThru::CSeekingPassThru( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr ) + : CUnknown(pName, pUnk, phr), + m_pPosPassThru(NULL) +{ +} + + +CSeekingPassThru::~CSeekingPassThru() +{ + delete m_pPosPassThru; +} + +STDMETHODIMP CSeekingPassThru::Init(BOOL bRendererSeeking, IPin *pPin) +{ + HRESULT hr = NOERROR; + if (m_pPosPassThru) { + hr = E_FAIL; + } else { + m_pPosPassThru = + bRendererSeeking ? + new CRendererPosPassThru( + NAME("Render Seeking COM object"), + (IUnknown *)this, + &hr, + pPin) : + new CPosPassThru( + NAME("Render Seeking COM object"), + (IUnknown *)this, + &hr, + pPin); + if (!m_pPosPassThru) { + hr = E_OUTOFMEMORY; + } else { + if (FAILED(hr)) { + delete m_pPosPassThru; + m_pPosPassThru = NULL; + } + } + } + return hr; +} + diff --git a/plugins/GSdx/baseclasses/seekpt.h b/plugins/GSdx/baseclasses/seekpt.h index 93b7061398..1d26dfee0a 100644 --- a/plugins/GSdx/baseclasses/seekpt.h +++ b/plugins/GSdx/baseclasses/seekpt.h @@ -1,30 +1,30 @@ -//------------------------------------------------------------------------------ -// File: SeekPT.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __seekpt_h__ -#define __seekpt_h__ - - -class CSeekingPassThru : public ISeekingPassThru, public CUnknown -{ -public: - static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr); - CSeekingPassThru(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr); - ~CSeekingPassThru(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv); - - STDMETHODIMP Init(BOOL bSupportRendering, IPin *pPin); - -private: - CPosPassThru *m_pPosPassThru; -}; - -#endif +//------------------------------------------------------------------------------ +// File: SeekPT.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __seekpt_h__ +#define __seekpt_h__ + + +class CSeekingPassThru : public ISeekingPassThru, public CUnknown +{ +public: + static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr); + CSeekingPassThru(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr); + ~CSeekingPassThru(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv); + + STDMETHODIMP Init(BOOL bSupportRendering, IPin *pPin); + +private: + CPosPassThru *m_pPosPassThru; +}; + +#endif diff --git a/plugins/GSdx/baseclasses/source.cpp b/plugins/GSdx/baseclasses/source.cpp index 9d58373617..8d71f3d65f 100644 --- a/plugins/GSdx/baseclasses/source.cpp +++ b/plugins/GSdx/baseclasses/source.cpp @@ -1,522 +1,522 @@ -//------------------------------------------------------------------------------ -// File: Source.cpp -// -// Desc: DirectShow base classes - implements CSource, which is a Quartz -// source filter 'template.' -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// Locking Strategy. -// -// Hold the filter critical section (m_pFilter->pStateLock()) to serialise -// access to functions. Note that, in general, this lock may be held -// by a function when the worker thread may want to hold it. Therefore -// if you wish to access shared state from the worker thread you will -// need to add another critical section object. The execption is during -// the threads processing loop, when it is safe to get the filter critical -// section from within FillBuffer(). - -#include "streams.h" - - -// -// CSource::Constructor -// -// Initialise the pin count for the filter. The user will create the pins in -// the derived class. -CSource::CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid) - : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), - m_iPins(0), - m_paStreams(NULL) -{ -} - -CSource::CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr) - : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), - m_iPins(0), - m_paStreams(NULL) -{ - UNREFERENCED_PARAMETER(phr); -} - -#ifdef UNICODE -CSource::CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid) - : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), - m_iPins(0), - m_paStreams(NULL) -{ -} - -CSource::CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr) - : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), - m_iPins(0), - m_paStreams(NULL) -{ - UNREFERENCED_PARAMETER(phr); -} -#endif - -// -// CSource::Destructor -// -CSource::~CSource() -{ - /* Free our pins and pin array */ - while (m_iPins != 0) { - // deleting the pins causes them to be removed from the array... - delete m_paStreams[m_iPins - 1]; - } - - ASSERT(m_paStreams == NULL); -} - - -// -// Add a new pin -// -HRESULT CSource::AddPin(CSourceStream *pStream) -{ - CAutoLock lock(&m_cStateLock); - - /* Allocate space for this pin and the old ones */ - CSourceStream **paStreams = new CSourceStream *[m_iPins + 1]; - if (paStreams == NULL) { - return E_OUTOFMEMORY; - } - if (m_paStreams != NULL) { - CopyMemory((PVOID)paStreams, (PVOID)m_paStreams, - m_iPins * sizeof(m_paStreams[0])); - paStreams[m_iPins] = pStream; - delete [] m_paStreams; - } - m_paStreams = paStreams; - m_paStreams[m_iPins] = pStream; - m_iPins++; - return S_OK; -} - -// -// Remove a pin - pStream is NOT deleted -// -HRESULT CSource::RemovePin(CSourceStream *pStream) -{ - int i; - for (i = 0; i < m_iPins; i++) { - if (m_paStreams[i] == pStream) { - if (m_iPins == 1) { - delete [] m_paStreams; - m_paStreams = NULL; - } else { - /* no need to reallocate */ - while (++i < m_iPins) - m_paStreams[i - 1] = m_paStreams[i]; - } - m_iPins--; - return S_OK; - } - } - return S_FALSE; -} - -// -// FindPin -// -// Set *ppPin to the IPin* that has the id Id. -// or to NULL if the Id cannot be matched. -STDMETHODIMP CSource::FindPin(LPCWSTR Id, IPin **ppPin) -{ - CheckPointer(ppPin,E_POINTER); - ValidateReadWritePtr(ppPin,sizeof(IPin *)); - // The -1 undoes the +1 in QueryId and ensures that totally invalid - // strings (for which WstrToInt delivers 0) give a deliver a NULL pin. - int i = WstrToInt(Id) -1; - *ppPin = GetPin(i); - if (*ppPin!=NULL){ - (*ppPin)->AddRef(); - return NOERROR; - } else { - return VFW_E_NOT_FOUND; - } -} - -// -// FindPinNumber -// -// return the number of the pin with this IPin* or -1 if none -int CSource::FindPinNumber(IPin *iPin) { - int i; - for (i=0; in && n>=0 it follows that m_iPins>0 - // which is what used to be checked (i.e. checking that we have a pin) - if ((n >= 0) && (n < m_iPins)) { - - ASSERT(m_paStreams[n]); - return m_paStreams[n]; - } - return NULL; -} - - -// - - -// * -// * --- CSourceStream ---- -// * - -// -// Set Id to point to a CoTaskMemAlloc'd -STDMETHODIMP CSourceStream::QueryId(LPWSTR *Id) { - CheckPointer(Id,E_POINTER); - ValidateReadWritePtr(Id,sizeof(LPWSTR)); - - // We give the pins id's which are 1,2,... - // FindPinNumber returns -1 for an invalid pin - int i = 1+ m_pFilter->FindPinNumber(this); - if (i<1) return VFW_E_NOT_FOUND; - *Id = (LPWSTR)CoTaskMemAlloc(4*sizeof(WCHAR)); - if (*Id==NULL) { - return E_OUTOFMEMORY; - } - IntToWstr(i, *Id, 4); - return NOERROR; -} - - - -// -// CSourceStream::Constructor -// -// increments the number of pins present on the filter -CSourceStream::CSourceStream( - TCHAR *pObjectName, - HRESULT *phr, - CSource *ps, - LPCWSTR pPinName) - : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName), - m_pFilter(ps) { - - *phr = m_pFilter->AddPin(this); -} - -#ifdef UNICODE -CSourceStream::CSourceStream( - char *pObjectName, - HRESULT *phr, - CSource *ps, - LPCWSTR pPinName) - : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName), - m_pFilter(ps) { - - *phr = m_pFilter->AddPin(this); -} -#endif -// -// CSourceStream::Destructor -// -// Decrements the number of pins on this filter -CSourceStream::~CSourceStream(void) { - - m_pFilter->RemovePin(this); -} - - -// -// CheckMediaType -// -// Do we support this type? Provides the default support for 1 type. -HRESULT CSourceStream::CheckMediaType(const CMediaType *pMediaType) { - - CAutoLock lock(m_pFilter->pStateLock()); - - CMediaType mt; - GetMediaType(&mt); - - if (mt == *pMediaType) { - return NOERROR; - } - - return E_FAIL; -} - - -// -// GetMediaType/3 -// -// By default we support only one type -// iPosition indexes are 0-n -HRESULT CSourceStream::GetMediaType(int iPosition, CMediaType *pMediaType) { - - CAutoLock lock(m_pFilter->pStateLock()); - - if (iPosition<0) { - return E_INVALIDARG; - } - if (iPosition>0) { - return VFW_S_NO_MORE_ITEMS; - } - return GetMediaType(pMediaType); -} - - -// -// Active -// -// The pin is active - start up the worker thread -HRESULT CSourceStream::Active(void) { - - CAutoLock lock(m_pFilter->pStateLock()); - - HRESULT hr; - - if (m_pFilter->IsActive()) { - return S_FALSE; // succeeded, but did not allocate resources (they already exist...) - } - - // do nothing if not connected - its ok not to connect to - // all pins of a source filter - if (!IsConnected()) { - return NOERROR; - } - - hr = CBaseOutputPin::Active(); - if (FAILED(hr)) { - return hr; - } - - ASSERT(!ThreadExists()); - - // start the thread - if (!Create()) { - return E_FAIL; - } - - // Tell thread to initialize. If OnThreadCreate Fails, so does this. - hr = Init(); - if (FAILED(hr)) - return hr; - - return Pause(); -} - - -// -// Inactive -// -// Pin is inactive - shut down the worker thread -// Waits for the worker to exit before returning. -HRESULT CSourceStream::Inactive(void) { - - CAutoLock lock(m_pFilter->pStateLock()); - - HRESULT hr; - - // do nothing if not connected - its ok not to connect to - // all pins of a source filter - if (!IsConnected()) { - return NOERROR; - } - - // !!! need to do this before trying to stop the thread, because - // we may be stuck waiting for our own allocator!!! - - hr = CBaseOutputPin::Inactive(); // call this first to Decommit the allocator - if (FAILED(hr)) { - return hr; - } - - if (ThreadExists()) { - hr = Stop(); - - if (FAILED(hr)) { - return hr; - } - - hr = Exit(); - if (FAILED(hr)) { - return hr; - } - - Close(); // Wait for the thread to exit, then tidy up. - } - - // hr = CBaseOutputPin::Inactive(); // call this first to Decommit the allocator - //if (FAILED(hr)) { - // return hr; - //} - - return NOERROR; -} - - -// -// ThreadProc -// -// When this returns the thread exits -// Return codes > 0 indicate an error occured -DWORD CSourceStream::ThreadProc(void) { - - HRESULT hr; // the return code from calls - Command com; - - do { - com = GetRequest(); - if (com != CMD_INIT) { - DbgLog((LOG_ERROR, 1, TEXT("Thread expected init command"))); - Reply((DWORD) E_UNEXPECTED); - } - } while (com != CMD_INIT); - - DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread initializing"))); - - hr = OnThreadCreate(); // perform set up tasks - if (FAILED(hr)) { - DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadCreate failed. Aborting thread."))); - OnThreadDestroy(); - Reply(hr); // send failed return code from OnThreadCreate - return 1; - } - - // Initialisation suceeded - Reply(NOERROR); - - Command cmd; - do { - cmd = GetRequest(); - - switch (cmd) { - - case CMD_EXIT: - Reply(NOERROR); - break; - - case CMD_RUN: - DbgLog((LOG_ERROR, 1, TEXT("CMD_RUN received before a CMD_PAUSE???"))); - // !!! fall through??? - - case CMD_PAUSE: - Reply(NOERROR); - DoBufferProcessingLoop(); - break; - - case CMD_STOP: - Reply(NOERROR); - break; - - default: - DbgLog((LOG_ERROR, 1, TEXT("Unknown command %d received!"), cmd)); - Reply((DWORD) E_NOTIMPL); - break; - } - } while (cmd != CMD_EXIT); - - hr = OnThreadDestroy(); // tidy up. - if (FAILED(hr)) { - DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadDestroy failed. Exiting thread."))); - return 1; - } - - DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread exiting"))); - return 0; -} - - -// -// DoBufferProcessingLoop -// -// Grabs a buffer and calls the users processing function. -// Overridable, so that different delivery styles can be catered for. -HRESULT CSourceStream::DoBufferProcessingLoop(void) { - - Command com; - - OnThreadStartPlay(); - - do { - while (!CheckRequest(&com)) { - - IMediaSample *pSample; - - HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); - if (FAILED(hr)) { - Sleep(1); - continue; // go round again. Perhaps the error will go away - // or the allocator is decommited & we will be asked to - // exit soon. - } - - // Virtual function user will override. - hr = FillBuffer(pSample); - - if (hr == S_OK) { - hr = Deliver(pSample); - pSample->Release(); - - // downstream filter returns S_FALSE if it wants us to - // stop or an error if it's reporting an error. - if(hr != S_OK) - { - DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr)); - return S_OK; - } - - } else if (hr == S_FALSE) { - // derived class wants us to stop pushing data - pSample->Release(); - DeliverEndOfStream(); - return S_OK; - } else { - // derived class encountered an error - pSample->Release(); - DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr)); - DeliverEndOfStream(); - m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0); - return hr; - } - - // all paths release the sample - } - - // For all commands sent to us there must be a Reply call! - - if (com == CMD_RUN || com == CMD_PAUSE) { - Reply(NOERROR); - } else if (com != CMD_STOP) { - Reply((DWORD) E_UNEXPECTED); - DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!"))); - } - } while (com != CMD_STOP); - - return S_FALSE; -} - +//------------------------------------------------------------------------------ +// File: Source.cpp +// +// Desc: DirectShow base classes - implements CSource, which is a Quartz +// source filter 'template.' +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Locking Strategy. +// +// Hold the filter critical section (m_pFilter->pStateLock()) to serialise +// access to functions. Note that, in general, this lock may be held +// by a function when the worker thread may want to hold it. Therefore +// if you wish to access shared state from the worker thread you will +// need to add another critical section object. The execption is during +// the threads processing loop, when it is safe to get the filter critical +// section from within FillBuffer(). + +#include "streams.h" + + +// +// CSource::Constructor +// +// Initialise the pin count for the filter. The user will create the pins in +// the derived class. +CSource::CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid) + : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), + m_iPins(0), + m_paStreams(NULL) +{ +} + +CSource::CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr) + : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), + m_iPins(0), + m_paStreams(NULL) +{ + UNREFERENCED_PARAMETER(phr); +} + +#ifdef UNICODE +CSource::CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid) + : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), + m_iPins(0), + m_paStreams(NULL) +{ +} + +CSource::CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr) + : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), + m_iPins(0), + m_paStreams(NULL) +{ + UNREFERENCED_PARAMETER(phr); +} +#endif + +// +// CSource::Destructor +// +CSource::~CSource() +{ + /* Free our pins and pin array */ + while (m_iPins != 0) { + // deleting the pins causes them to be removed from the array... + delete m_paStreams[m_iPins - 1]; + } + + ASSERT(m_paStreams == NULL); +} + + +// +// Add a new pin +// +HRESULT CSource::AddPin(CSourceStream *pStream) +{ + CAutoLock lock(&m_cStateLock); + + /* Allocate space for this pin and the old ones */ + CSourceStream **paStreams = new CSourceStream *[m_iPins + 1]; + if (paStreams == NULL) { + return E_OUTOFMEMORY; + } + if (m_paStreams != NULL) { + CopyMemory((PVOID)paStreams, (PVOID)m_paStreams, + m_iPins * sizeof(m_paStreams[0])); + paStreams[m_iPins] = pStream; + delete [] m_paStreams; + } + m_paStreams = paStreams; + m_paStreams[m_iPins] = pStream; + m_iPins++; + return S_OK; +} + +// +// Remove a pin - pStream is NOT deleted +// +HRESULT CSource::RemovePin(CSourceStream *pStream) +{ + int i; + for (i = 0; i < m_iPins; i++) { + if (m_paStreams[i] == pStream) { + if (m_iPins == 1) { + delete [] m_paStreams; + m_paStreams = NULL; + } else { + /* no need to reallocate */ + while (++i < m_iPins) + m_paStreams[i - 1] = m_paStreams[i]; + } + m_iPins--; + return S_OK; + } + } + return S_FALSE; +} + +// +// FindPin +// +// Set *ppPin to the IPin* that has the id Id. +// or to NULL if the Id cannot be matched. +STDMETHODIMP CSource::FindPin(LPCWSTR Id, IPin **ppPin) +{ + CheckPointer(ppPin,E_POINTER); + ValidateReadWritePtr(ppPin,sizeof(IPin *)); + // The -1 undoes the +1 in QueryId and ensures that totally invalid + // strings (for which WstrToInt delivers 0) give a deliver a NULL pin. + int i = WstrToInt(Id) -1; + *ppPin = GetPin(i); + if (*ppPin!=NULL){ + (*ppPin)->AddRef(); + return NOERROR; + } else { + return VFW_E_NOT_FOUND; + } +} + +// +// FindPinNumber +// +// return the number of the pin with this IPin* or -1 if none +int CSource::FindPinNumber(IPin *iPin) { + int i; + for (i=0; in && n>=0 it follows that m_iPins>0 + // which is what used to be checked (i.e. checking that we have a pin) + if ((n >= 0) && (n < m_iPins)) { + + ASSERT(m_paStreams[n]); + return m_paStreams[n]; + } + return NULL; +} + + +// + + +// * +// * --- CSourceStream ---- +// * + +// +// Set Id to point to a CoTaskMemAlloc'd +STDMETHODIMP CSourceStream::QueryId(LPWSTR *Id) { + CheckPointer(Id,E_POINTER); + ValidateReadWritePtr(Id,sizeof(LPWSTR)); + + // We give the pins id's which are 1,2,... + // FindPinNumber returns -1 for an invalid pin + int i = 1+ m_pFilter->FindPinNumber(this); + if (i<1) return VFW_E_NOT_FOUND; + *Id = (LPWSTR)CoTaskMemAlloc(4*sizeof(WCHAR)); + if (*Id==NULL) { + return E_OUTOFMEMORY; + } + IntToWstr(i, *Id, 4); + return NOERROR; +} + + + +// +// CSourceStream::Constructor +// +// increments the number of pins present on the filter +CSourceStream::CSourceStream( + TCHAR *pObjectName, + HRESULT *phr, + CSource *ps, + LPCWSTR pPinName) + : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName), + m_pFilter(ps) { + + *phr = m_pFilter->AddPin(this); +} + +#ifdef UNICODE +CSourceStream::CSourceStream( + char *pObjectName, + HRESULT *phr, + CSource *ps, + LPCWSTR pPinName) + : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName), + m_pFilter(ps) { + + *phr = m_pFilter->AddPin(this); +} +#endif +// +// CSourceStream::Destructor +// +// Decrements the number of pins on this filter +CSourceStream::~CSourceStream(void) { + + m_pFilter->RemovePin(this); +} + + +// +// CheckMediaType +// +// Do we support this type? Provides the default support for 1 type. +HRESULT CSourceStream::CheckMediaType(const CMediaType *pMediaType) { + + CAutoLock lock(m_pFilter->pStateLock()); + + CMediaType mt; + GetMediaType(&mt); + + if (mt == *pMediaType) { + return NOERROR; + } + + return E_FAIL; +} + + +// +// GetMediaType/3 +// +// By default we support only one type +// iPosition indexes are 0-n +HRESULT CSourceStream::GetMediaType(int iPosition, CMediaType *pMediaType) { + + CAutoLock lock(m_pFilter->pStateLock()); + + if (iPosition<0) { + return E_INVALIDARG; + } + if (iPosition>0) { + return VFW_S_NO_MORE_ITEMS; + } + return GetMediaType(pMediaType); +} + + +// +// Active +// +// The pin is active - start up the worker thread +HRESULT CSourceStream::Active(void) { + + CAutoLock lock(m_pFilter->pStateLock()); + + HRESULT hr; + + if (m_pFilter->IsActive()) { + return S_FALSE; // succeeded, but did not allocate resources (they already exist...) + } + + // do nothing if not connected - its ok not to connect to + // all pins of a source filter + if (!IsConnected()) { + return NOERROR; + } + + hr = CBaseOutputPin::Active(); + if (FAILED(hr)) { + return hr; + } + + ASSERT(!ThreadExists()); + + // start the thread + if (!Create()) { + return E_FAIL; + } + + // Tell thread to initialize. If OnThreadCreate Fails, so does this. + hr = Init(); + if (FAILED(hr)) + return hr; + + return Pause(); +} + + +// +// Inactive +// +// Pin is inactive - shut down the worker thread +// Waits for the worker to exit before returning. +HRESULT CSourceStream::Inactive(void) { + + CAutoLock lock(m_pFilter->pStateLock()); + + HRESULT hr; + + // do nothing if not connected - its ok not to connect to + // all pins of a source filter + if (!IsConnected()) { + return NOERROR; + } + + // !!! need to do this before trying to stop the thread, because + // we may be stuck waiting for our own allocator!!! + + hr = CBaseOutputPin::Inactive(); // call this first to Decommit the allocator + if (FAILED(hr)) { + return hr; + } + + if (ThreadExists()) { + hr = Stop(); + + if (FAILED(hr)) { + return hr; + } + + hr = Exit(); + if (FAILED(hr)) { + return hr; + } + + Close(); // Wait for the thread to exit, then tidy up. + } + + // hr = CBaseOutputPin::Inactive(); // call this first to Decommit the allocator + //if (FAILED(hr)) { + // return hr; + //} + + return NOERROR; +} + + +// +// ThreadProc +// +// When this returns the thread exits +// Return codes > 0 indicate an error occured +DWORD CSourceStream::ThreadProc(void) { + + HRESULT hr; // the return code from calls + Command com; + + do { + com = GetRequest(); + if (com != CMD_INIT) { + DbgLog((LOG_ERROR, 1, TEXT("Thread expected init command"))); + Reply((DWORD) E_UNEXPECTED); + } + } while (com != CMD_INIT); + + DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread initializing"))); + + hr = OnThreadCreate(); // perform set up tasks + if (FAILED(hr)) { + DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadCreate failed. Aborting thread."))); + OnThreadDestroy(); + Reply(hr); // send failed return code from OnThreadCreate + return 1; + } + + // Initialisation suceeded + Reply(NOERROR); + + Command cmd; + do { + cmd = GetRequest(); + + switch (cmd) { + + case CMD_EXIT: + Reply(NOERROR); + break; + + case CMD_RUN: + DbgLog((LOG_ERROR, 1, TEXT("CMD_RUN received before a CMD_PAUSE???"))); + // !!! fall through??? + + case CMD_PAUSE: + Reply(NOERROR); + DoBufferProcessingLoop(); + break; + + case CMD_STOP: + Reply(NOERROR); + break; + + default: + DbgLog((LOG_ERROR, 1, TEXT("Unknown command %d received!"), cmd)); + Reply((DWORD) E_NOTIMPL); + break; + } + } while (cmd != CMD_EXIT); + + hr = OnThreadDestroy(); // tidy up. + if (FAILED(hr)) { + DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadDestroy failed. Exiting thread."))); + return 1; + } + + DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread exiting"))); + return 0; +} + + +// +// DoBufferProcessingLoop +// +// Grabs a buffer and calls the users processing function. +// Overridable, so that different delivery styles can be catered for. +HRESULT CSourceStream::DoBufferProcessingLoop(void) { + + Command com; + + OnThreadStartPlay(); + + do { + while (!CheckRequest(&com)) { + + IMediaSample *pSample; + + HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); + if (FAILED(hr)) { + Sleep(1); + continue; // go round again. Perhaps the error will go away + // or the allocator is decommited & we will be asked to + // exit soon. + } + + // Virtual function user will override. + hr = FillBuffer(pSample); + + if (hr == S_OK) { + hr = Deliver(pSample); + pSample->Release(); + + // downstream filter returns S_FALSE if it wants us to + // stop or an error if it's reporting an error. + if(hr != S_OK) + { + DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr)); + return S_OK; + } + + } else if (hr == S_FALSE) { + // derived class wants us to stop pushing data + pSample->Release(); + DeliverEndOfStream(); + return S_OK; + } else { + // derived class encountered an error + pSample->Release(); + DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr)); + DeliverEndOfStream(); + m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0); + return hr; + } + + // all paths release the sample + } + + // For all commands sent to us there must be a Reply call! + + if (com == CMD_RUN || com == CMD_PAUSE) { + Reply(NOERROR); + } else if (com != CMD_STOP) { + Reply((DWORD) E_UNEXPECTED); + DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!"))); + } + } while (com != CMD_STOP); + + return S_FALSE; +} + diff --git a/plugins/GSdx/baseclasses/source.h b/plugins/GSdx/baseclasses/source.h index 6dff3e7569..a5f0aeb26d 100644 --- a/plugins/GSdx/baseclasses/source.h +++ b/plugins/GSdx/baseclasses/source.h @@ -1,172 +1,172 @@ -//------------------------------------------------------------------------------ -// File: Source.h -// -// Desc: DirectShow base classes - defines classes to simplify creation of -// ActiveX source filters that support continuous generation of data. -// No support is provided for IMediaControl or IMediaPosition. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// -// Derive your source filter from CSource. -// During construction either: -// Create some CSourceStream objects to manage your pins -// Provide the user with a means of doing so eg, an IPersistFile interface. -// -// CSource provides: -// IBaseFilter interface management -// IMediaFilter interface management, via CBaseFilter -// Pin counting for CBaseFilter -// -// Derive a class from CSourceStream to manage your output pin types -// Implement GetMediaType/1 to return the type you support. If you support multiple -// types then overide GetMediaType/3, CheckMediaType and GetMediaTypeCount. -// Implement Fillbuffer() to put data into one buffer. -// -// CSourceStream provides: -// IPin management via CBaseOutputPin -// Worker thread management - -#ifndef __CSOURCE__ -#define __CSOURCE__ - -class CSourceStream; // The class that will handle each pin - - -// -// CSource -// -// Override construction to provide a means of creating -// CSourceStream derived objects - ie a way of creating pins. -class CSource : public CBaseFilter { -public: - - CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr); - CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid); -#ifdef UNICODE - CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr); - CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid); -#endif - ~CSource(); - - int GetPinCount(void); - CBasePin *GetPin(int n); - - // -- Utilities -- - - CCritSec* pStateLock(void) { return &m_cStateLock; } // provide our critical section - - HRESULT AddPin(CSourceStream *); - HRESULT RemovePin(CSourceStream *); - - STDMETHODIMP FindPin( - LPCWSTR Id, - IPin ** ppPin - ); - - int FindPinNumber(IPin *iPin); - -protected: - - int m_iPins; // The number of pins on this filter. Updated by CSourceStream - // constructors & destructors. - CSourceStream **m_paStreams; // the pins on this filter. - - CCritSec m_cStateLock; // Lock this to serialize function accesses to the filter state - -}; - - -// -// CSourceStream -// -// Use this class to manage a stream of data that comes from a -// pin. -// Uses a worker thread to put data on the pin. -class CSourceStream : public CAMThread, public CBaseOutputPin { -public: - - CSourceStream(TCHAR *pObjectName, - HRESULT *phr, - CSource *pms, - LPCWSTR pName); -#ifdef UNICODE - CSourceStream(CHAR *pObjectName, - HRESULT *phr, - CSource *pms, - LPCWSTR pName); -#endif - virtual ~CSourceStream(void); // virtual destructor ensures derived class destructors are called too. - -protected: - - CSource *m_pFilter; // The parent of this stream - - // * - // * Data Source - // * - // * The following three functions: FillBuffer, OnThreadCreate/Destroy, are - // * called from within the ThreadProc. They are used in the creation of - // * the media samples this pin will provide - // * - - // Override this to provide the worker thread a means - // of processing a buffer - virtual HRESULT FillBuffer(IMediaSample *pSamp) PURE; - - // Called as the thread is created/destroyed - use to perform - // jobs such as start/stop streaming mode - // If OnThreadCreate returns an error the thread will exit. - virtual HRESULT OnThreadCreate(void) {return NOERROR;}; - virtual HRESULT OnThreadDestroy(void) {return NOERROR;}; - virtual HRESULT OnThreadStartPlay(void) {return NOERROR;}; - - // * - // * Worker Thread - // * - - HRESULT Active(void); // Starts up the worker thread - HRESULT Inactive(void); // Exits the worker thread. - -public: - // thread commands - enum Command {CMD_INIT, CMD_PAUSE, CMD_RUN, CMD_STOP, CMD_EXIT}; - HRESULT Init(void) { return CallWorker(CMD_INIT); } - HRESULT Exit(void) { return CallWorker(CMD_EXIT); } - HRESULT Run(void) { return CallWorker(CMD_RUN); } - HRESULT Pause(void) { return CallWorker(CMD_PAUSE); } - HRESULT Stop(void) { return CallWorker(CMD_STOP); } - -protected: - Command GetRequest(void) { return (Command) CAMThread::GetRequest(); } - BOOL CheckRequest(Command *pCom) { return CAMThread::CheckRequest( (DWORD *) pCom); } - - // override these if you want to add thread commands - virtual DWORD ThreadProc(void); // the thread function - - virtual HRESULT DoBufferProcessingLoop(void); // the loop executed whilst running - - - // * - // * AM_MEDIA_TYPE support - // * - - // If you support more than one media type then override these 2 functions - virtual HRESULT CheckMediaType(const CMediaType *pMediaType); - virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType); // List pos. 0-n - - // If you support only one type then override this fn. - // This will only be called by the default implementations - // of CheckMediaType and GetMediaType(int, CMediaType*) - // You must override this fn. or the above 2! - virtual HRESULT GetMediaType(CMediaType *pMediaType) {return E_UNEXPECTED;} - - STDMETHODIMP QueryId( - LPWSTR * Id - ); -}; - -#endif // __CSOURCE__ - +//------------------------------------------------------------------------------ +// File: Source.h +// +// Desc: DirectShow base classes - defines classes to simplify creation of +// ActiveX source filters that support continuous generation of data. +// No support is provided for IMediaControl or IMediaPosition. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// +// Derive your source filter from CSource. +// During construction either: +// Create some CSourceStream objects to manage your pins +// Provide the user with a means of doing so eg, an IPersistFile interface. +// +// CSource provides: +// IBaseFilter interface management +// IMediaFilter interface management, via CBaseFilter +// Pin counting for CBaseFilter +// +// Derive a class from CSourceStream to manage your output pin types +// Implement GetMediaType/1 to return the type you support. If you support multiple +// types then overide GetMediaType/3, CheckMediaType and GetMediaTypeCount. +// Implement Fillbuffer() to put data into one buffer. +// +// CSourceStream provides: +// IPin management via CBaseOutputPin +// Worker thread management + +#ifndef __CSOURCE__ +#define __CSOURCE__ + +class CSourceStream; // The class that will handle each pin + + +// +// CSource +// +// Override construction to provide a means of creating +// CSourceStream derived objects - ie a way of creating pins. +class CSource : public CBaseFilter { +public: + + CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr); + CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid); +#ifdef UNICODE + CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr); + CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid); +#endif + ~CSource(); + + int GetPinCount(void); + CBasePin *GetPin(int n); + + // -- Utilities -- + + CCritSec* pStateLock(void) { return &m_cStateLock; } // provide our critical section + + HRESULT AddPin(CSourceStream *); + HRESULT RemovePin(CSourceStream *); + + STDMETHODIMP FindPin( + LPCWSTR Id, + IPin ** ppPin + ); + + int FindPinNumber(IPin *iPin); + +protected: + + int m_iPins; // The number of pins on this filter. Updated by CSourceStream + // constructors & destructors. + CSourceStream **m_paStreams; // the pins on this filter. + + CCritSec m_cStateLock; // Lock this to serialize function accesses to the filter state + +}; + + +// +// CSourceStream +// +// Use this class to manage a stream of data that comes from a +// pin. +// Uses a worker thread to put data on the pin. +class CSourceStream : public CAMThread, public CBaseOutputPin { +public: + + CSourceStream(TCHAR *pObjectName, + HRESULT *phr, + CSource *pms, + LPCWSTR pName); +#ifdef UNICODE + CSourceStream(CHAR *pObjectName, + HRESULT *phr, + CSource *pms, + LPCWSTR pName); +#endif + virtual ~CSourceStream(void); // virtual destructor ensures derived class destructors are called too. + +protected: + + CSource *m_pFilter; // The parent of this stream + + // * + // * Data Source + // * + // * The following three functions: FillBuffer, OnThreadCreate/Destroy, are + // * called from within the ThreadProc. They are used in the creation of + // * the media samples this pin will provide + // * + + // Override this to provide the worker thread a means + // of processing a buffer + virtual HRESULT FillBuffer(IMediaSample *pSamp) PURE; + + // Called as the thread is created/destroyed - use to perform + // jobs such as start/stop streaming mode + // If OnThreadCreate returns an error the thread will exit. + virtual HRESULT OnThreadCreate(void) {return NOERROR;}; + virtual HRESULT OnThreadDestroy(void) {return NOERROR;}; + virtual HRESULT OnThreadStartPlay(void) {return NOERROR;}; + + // * + // * Worker Thread + // * + + HRESULT Active(void); // Starts up the worker thread + HRESULT Inactive(void); // Exits the worker thread. + +public: + // thread commands + enum Command {CMD_INIT, CMD_PAUSE, CMD_RUN, CMD_STOP, CMD_EXIT}; + HRESULT Init(void) { return CallWorker(CMD_INIT); } + HRESULT Exit(void) { return CallWorker(CMD_EXIT); } + HRESULT Run(void) { return CallWorker(CMD_RUN); } + HRESULT Pause(void) { return CallWorker(CMD_PAUSE); } + HRESULT Stop(void) { return CallWorker(CMD_STOP); } + +protected: + Command GetRequest(void) { return (Command) CAMThread::GetRequest(); } + BOOL CheckRequest(Command *pCom) { return CAMThread::CheckRequest( (DWORD *) pCom); } + + // override these if you want to add thread commands + virtual DWORD ThreadProc(void); // the thread function + + virtual HRESULT DoBufferProcessingLoop(void); // the loop executed whilst running + + + // * + // * AM_MEDIA_TYPE support + // * + + // If you support more than one media type then override these 2 functions + virtual HRESULT CheckMediaType(const CMediaType *pMediaType); + virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType); // List pos. 0-n + + // If you support only one type then override this fn. + // This will only be called by the default implementations + // of CheckMediaType and GetMediaType(int, CMediaType*) + // You must override this fn. or the above 2! + virtual HRESULT GetMediaType(CMediaType *pMediaType) {return E_UNEXPECTED;} + + STDMETHODIMP QueryId( + LPWSTR * Id + ); +}; + +#endif // __CSOURCE__ + diff --git a/plugins/GSdx/baseclasses/streams.h b/plugins/GSdx/baseclasses/streams.h index f5c9f60764..f0d830444d 100644 --- a/plugins/GSdx/baseclasses/streams.h +++ b/plugins/GSdx/baseclasses/streams.h @@ -1,254 +1,254 @@ -//------------------------------------------------------------------------------ -// File: Streams.h -// -// Desc: DirectShow base classes - defines overall streams architecture. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __STREAMS__ -#define __STREAMS__ - -#ifdef _MSC_VER -// disable some level-4 warnings, use #pragma warning(enable:###) to re-enable -#pragma warning(disable:4100) // warning C4100: unreferenced formal parameter -#pragma warning(disable:4127) // warning C4127: conditional expression is constant -#pragma warning(disable:4189) // warning C4189: local variable is initialized but not referenced -#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union -#pragma warning(disable:4511) // warning C4511: copy constructor could not be generated -#pragma warning(disable:4512) // warning C4512: assignment operator could not be generated -#pragma warning(disable:4514) // warning C4514: unreferenced inline function has been removed -#pragma warning(disable:4710) // warning C4710: 'function' not inlined - -#if _MSC_VER>=1100 -#define AM_NOVTABLE __declspec(novtable) -#else -#define AM_NOVTABLE -#endif -#endif // MSC_VER - -// Because of differences between Visual C++ and older Microsoft SDKs, -// you may have defined _DEBUG without defining DEBUG. This logic -// ensures that both will be set if Visual C++ sets _DEBUG. -#ifdef _DEBUG -#ifndef DEBUG -#define DEBUG -#endif -#endif - -#include -#include -#include -#include - -// Disable warning message for C4201 - use of nameless struct/union -// Otherwise, strmif.h will generate warnings for Win32 debug builds -#pragma warning( disable : 4201 ) - -#include - -#ifndef NUMELMS - #define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0])) -#endif - -/////////////////////////////////////////////////////////////////////////// -// The following definitions come from the Platform SDK and are required if -// the applicaiton is being compiled with the headers from Visual C++ 6.0. -/////////////////////////////////////////////////////////////////////////// -#ifndef InterlockedExchangePointer - #define InterlockedExchangePointer(Target, Value) \ - (PVOID)InterlockedExchange((PLONG)(Target), (LONG)(Value)) -#endif - -#ifndef _WAVEFORMATEXTENSIBLE_ -#define _WAVEFORMATEXTENSIBLE_ -typedef struct { - WAVEFORMATEX Format; - union { - WORD wValidBitsPerSample; /* bits of precision */ - WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */ - WORD wReserved; /* If neither applies, set to zero. */ - } Samples; - DWORD dwChannelMask; /* which channels are */ - /* present in stream */ - GUID SubFormat; -} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; -#endif // !_WAVEFORMATEXTENSIBLE_ - -#if !defined(WAVE_FORMAT_EXTENSIBLE) -#define WAVE_FORMAT_EXTENSIBLE 0xFFFE -#endif // !defined(WAVE_FORMAT_EXTENSIBLE) - -#ifndef GetWindowLongPtr - #define GetWindowLongPtrA GetWindowLongA - #define GetWindowLongPtrW GetWindowLongW - #ifdef UNICODE - #define GetWindowLongPtr GetWindowLongPtrW - #else - #define GetWindowLongPtr GetWindowLongPtrA - #endif // !UNICODE -#endif // !GetWindowLongPtr - -#ifndef SetWindowLongPtr - #define SetWindowLongPtrA SetWindowLongA - #define SetWindowLongPtrW SetWindowLongW - #ifdef UNICODE - #define SetWindowLongPtr SetWindowLongPtrW - #else - #define SetWindowLongPtr SetWindowLongPtrA - #endif // !UNICODE -#endif // !SetWindowLongPtr - -#ifndef GWLP_WNDPROC - #define GWLP_WNDPROC (-4) -#endif -#ifndef GWLP_HINSTANCE - #define GWLP_HINSTANCE (-6) -#endif -#ifndef GWLP_HWNDPARENT - #define GWLP_HWNDPARENT (-8) -#endif -#ifndef GWLP_USERDATA - #define GWLP_USERDATA (-21) -#endif -#ifndef GWLP_ID - #define GWLP_ID (-12) -#endif -#ifndef DWLP_MSGRESULT - #define DWLP_MSGRESULT 0 -#endif -#ifndef DWLP_DLGPROC - #define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT) -#endif -#ifndef DWLP_USER - #define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC) -#endif -/////////////////////////////////////////////////////////////////////////// -// End Platform SDK definitions -/////////////////////////////////////////////////////////////////////////// - -#include - -#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union -#include // Generated IDL header file for streams interfaces - -#include "reftime.h" // Helper class for REFERENCE_TIME management -#include "wxdebug.h" // Debug support for logging and ASSERTs -#include "amvideo.h" // ActiveMovie video interfaces and definitions -//include amaudio.h explicitly if you need it. it requires the DirectX SDK. -//#include "amaudio.h" // ActiveMovie audio interfaces and definitions -#include "wxutil.h" // General helper classes for threads etc -#include "combase.h" // Base COM classes to support IUnknown -//#include "dllsetup.h" // Filter registration support functions -#include "measure.h" // Performance measurement -#include "comlite.h" // Light weight com function prototypes - -#include "cache.h" // Simple cache container class -#include "wxlist.h" // Non MFC generic list class -#include "msgthrd.h" // CMsgThread -#include "mtype.h" // Helper class for managing media types -#include "fourcc.h" // conversions between FOURCCs and GUIDs -#include "control.h" // generated from control.odl -#include "ctlutil.h" // control interface utility classes -#include "evcode.h" // event code definitions -#include "amfilter.h" // Main streams architecture class hierachy -#include "transfrm.h" // Generic transform filter -#include "transip.h" // Generic transform-in-place filter -#include "uuids.h" // declaration of type GUIDs and well-known clsids -#include "source.h" // Generic source filter -#include "outputq.h" // Output pin queueing -#include "errors.h" // HRESULT status and error definitions -#include "renbase.h" // Base class for writing ActiveX renderers -//#include "winutil.h" // Helps with filters that manage windows -//#include "winctrl.h" // Implements the IVideoWindow interface -//#include "videoctl.h" // Specifically video related classes -#include "refclock.h" // Base clock class -#include "sysclock.h" // System clock -#include "pstream.h" // IPersistStream helper class -#include "vtrans.h" // Video Transform Filter base class -#include "amextra.h" -//#include "cprop.h" // Base property page class -#include "strmctl.h" // IAMStreamControl support -#include "edevdefs.h" // External device control interface defines -#include "audevcod.h" // audio filter device error event codes - -#include - -#define NO_SHLWAPI_STRFCNS -#include -#include - -#ifndef NUMELMS - #define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0])) -#endif - -class CPinInfo : public PIN_INFO -{ -public: - CPinInfo() {pFilter = NULL;} - ~CPinInfo() {if(pFilter) pFilter->Release();} -}; - -class CFilterInfo : public FILTER_INFO -{ -public: - CFilterInfo() {pGraph = NULL;} - ~CFilterInfo() {if(pGraph) pGraph->Release();} -}; - -#define BeginEnumFilters(pFilterGraph, pEnumFilters, pBaseFilter) \ - {CComPtr pEnumFilters; \ - if(pFilterGraph && SUCCEEDED(pFilterGraph->EnumFilters(&pEnumFilters))) \ - { \ - for(CComPtr pBaseFilter; S_OK == pEnumFilters->Next(1, &pBaseFilter, 0); pBaseFilter = NULL) \ - { \ - -#define EndEnumFilters }}} - -#define BeginEnumCachedFilters(pGraphConfig, pEnumFilters, pBaseFilter) \ - {CComPtr pEnumFilters; \ - if(pGraphConfig && SUCCEEDED(pGraphConfig->EnumCacheFilter(&pEnumFilters))) \ - { \ - for(CComPtr pBaseFilter; S_OK == pEnumFilters->Next(1, &pBaseFilter, 0); pBaseFilter = NULL) \ - { \ - -#define EndEnumCachedFilters }}} - -#define BeginEnumPins(pBaseFilter, pEnumPins, pPin) \ - {CComPtr pEnumPins; \ - if(pBaseFilter && SUCCEEDED(pBaseFilter->EnumPins(&pEnumPins))) \ - { \ - for(CComPtr pPin; S_OK == pEnumPins->Next(1, &pPin, 0); pPin = NULL) \ - { \ - -#define EndEnumPins }}} - -#define BeginEnumMediaTypes(pPin, pEnumMediaTypes, pMediaType) \ - {CComPtr pEnumMediaTypes; \ - if(pPin && SUCCEEDED(pPin->EnumMediaTypes(&pEnumMediaTypes))) \ - { \ - AM_MEDIA_TYPE* pMediaType = NULL; \ - for(; S_OK == pEnumMediaTypes->Next(1, &pMediaType, NULL); DeleteMediaType(pMediaType), pMediaType = NULL) \ - { \ - -#define EndEnumMediaTypes(pMediaType) } if(pMediaType) DeleteMediaType(pMediaType); }} - -#define BeginEnumSysDev(clsid, pMoniker) \ - {CComPtr pDevEnum4$##clsid; \ - pDevEnum4$##clsid.CoCreateInstance(CLSID_SystemDeviceEnum); \ - CComPtr pClassEnum4$##clsid; \ - if(SUCCEEDED(pDevEnum4$##clsid->CreateClassEnumerator(clsid, &pClassEnum4$##clsid, 0)) \ - && pClassEnum4$##clsid) \ - { \ - for(CComPtr pMoniker; pClassEnum4$##clsid->Next(1, &pMoniker, 0) == S_OK; pMoniker = NULL) \ - { \ - -#define EndEnumSysDev }}} - -#else - #ifdef DEBUG - #pragma message("STREAMS.H included TWICE") - #endif -#endif // __STREAMS__ - +//------------------------------------------------------------------------------ +// File: Streams.h +// +// Desc: DirectShow base classes - defines overall streams architecture. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __STREAMS__ +#define __STREAMS__ + +#ifdef _MSC_VER +// disable some level-4 warnings, use #pragma warning(enable:###) to re-enable +#pragma warning(disable:4100) // warning C4100: unreferenced formal parameter +#pragma warning(disable:4127) // warning C4127: conditional expression is constant +#pragma warning(disable:4189) // warning C4189: local variable is initialized but not referenced +#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union +#pragma warning(disable:4511) // warning C4511: copy constructor could not be generated +#pragma warning(disable:4512) // warning C4512: assignment operator could not be generated +#pragma warning(disable:4514) // warning C4514: unreferenced inline function has been removed +#pragma warning(disable:4710) // warning C4710: 'function' not inlined + +#if _MSC_VER>=1100 +#define AM_NOVTABLE __declspec(novtable) +#else +#define AM_NOVTABLE +#endif +#endif // MSC_VER + +// Because of differences between Visual C++ and older Microsoft SDKs, +// you may have defined _DEBUG without defining DEBUG. This logic +// ensures that both will be set if Visual C++ sets _DEBUG. +#ifdef _DEBUG +#ifndef DEBUG +#define DEBUG +#endif +#endif + +#include +#include +#include +#include + +// Disable warning message for C4201 - use of nameless struct/union +// Otherwise, strmif.h will generate warnings for Win32 debug builds +#pragma warning( disable : 4201 ) + +#include + +#ifndef NUMELMS + #define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0])) +#endif + +/////////////////////////////////////////////////////////////////////////// +// The following definitions come from the Platform SDK and are required if +// the applicaiton is being compiled with the headers from Visual C++ 6.0. +/////////////////////////////////////////////////////////////////////////// +#ifndef InterlockedExchangePointer + #define InterlockedExchangePointer(Target, Value) \ + (PVOID)InterlockedExchange((PLONG)(Target), (LONG)(Value)) +#endif + +#ifndef _WAVEFORMATEXTENSIBLE_ +#define _WAVEFORMATEXTENSIBLE_ +typedef struct { + WAVEFORMATEX Format; + union { + WORD wValidBitsPerSample; /* bits of precision */ + WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */ + WORD wReserved; /* If neither applies, set to zero. */ + } Samples; + DWORD dwChannelMask; /* which channels are */ + /* present in stream */ + GUID SubFormat; +} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; +#endif // !_WAVEFORMATEXTENSIBLE_ + +#if !defined(WAVE_FORMAT_EXTENSIBLE) +#define WAVE_FORMAT_EXTENSIBLE 0xFFFE +#endif // !defined(WAVE_FORMAT_EXTENSIBLE) + +#ifndef GetWindowLongPtr + #define GetWindowLongPtrA GetWindowLongA + #define GetWindowLongPtrW GetWindowLongW + #ifdef UNICODE + #define GetWindowLongPtr GetWindowLongPtrW + #else + #define GetWindowLongPtr GetWindowLongPtrA + #endif // !UNICODE +#endif // !GetWindowLongPtr + +#ifndef SetWindowLongPtr + #define SetWindowLongPtrA SetWindowLongA + #define SetWindowLongPtrW SetWindowLongW + #ifdef UNICODE + #define SetWindowLongPtr SetWindowLongPtrW + #else + #define SetWindowLongPtr SetWindowLongPtrA + #endif // !UNICODE +#endif // !SetWindowLongPtr + +#ifndef GWLP_WNDPROC + #define GWLP_WNDPROC (-4) +#endif +#ifndef GWLP_HINSTANCE + #define GWLP_HINSTANCE (-6) +#endif +#ifndef GWLP_HWNDPARENT + #define GWLP_HWNDPARENT (-8) +#endif +#ifndef GWLP_USERDATA + #define GWLP_USERDATA (-21) +#endif +#ifndef GWLP_ID + #define GWLP_ID (-12) +#endif +#ifndef DWLP_MSGRESULT + #define DWLP_MSGRESULT 0 +#endif +#ifndef DWLP_DLGPROC + #define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT) +#endif +#ifndef DWLP_USER + #define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC) +#endif +/////////////////////////////////////////////////////////////////////////// +// End Platform SDK definitions +/////////////////////////////////////////////////////////////////////////// + +#include + +#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union +#include // Generated IDL header file for streams interfaces + +#include "reftime.h" // Helper class for REFERENCE_TIME management +#include "wxdebug.h" // Debug support for logging and ASSERTs +#include "amvideo.h" // ActiveMovie video interfaces and definitions +//include amaudio.h explicitly if you need it. it requires the DirectX SDK. +//#include "amaudio.h" // ActiveMovie audio interfaces and definitions +#include "wxutil.h" // General helper classes for threads etc +#include "combase.h" // Base COM classes to support IUnknown +//#include "dllsetup.h" // Filter registration support functions +#include "measure.h" // Performance measurement +#include "comlite.h" // Light weight com function prototypes + +#include "cache.h" // Simple cache container class +#include "wxlist.h" // Non MFC generic list class +#include "msgthrd.h" // CMsgThread +#include "mtype.h" // Helper class for managing media types +#include "fourcc.h" // conversions between FOURCCs and GUIDs +#include "control.h" // generated from control.odl +#include "ctlutil.h" // control interface utility classes +#include "evcode.h" // event code definitions +#include "amfilter.h" // Main streams architecture class hierachy +#include "transfrm.h" // Generic transform filter +#include "transip.h" // Generic transform-in-place filter +#include "uuids.h" // declaration of type GUIDs and well-known clsids +#include "source.h" // Generic source filter +#include "outputq.h" // Output pin queueing +#include "errors.h" // HRESULT status and error definitions +#include "renbase.h" // Base class for writing ActiveX renderers +//#include "winutil.h" // Helps with filters that manage windows +//#include "winctrl.h" // Implements the IVideoWindow interface +//#include "videoctl.h" // Specifically video related classes +#include "refclock.h" // Base clock class +#include "sysclock.h" // System clock +#include "pstream.h" // IPersistStream helper class +#include "vtrans.h" // Video Transform Filter base class +#include "amextra.h" +//#include "cprop.h" // Base property page class +#include "strmctl.h" // IAMStreamControl support +#include "edevdefs.h" // External device control interface defines +#include "audevcod.h" // audio filter device error event codes + +#include + +#define NO_SHLWAPI_STRFCNS +#include +#include + +#ifndef NUMELMS + #define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0])) +#endif + +class CPinInfo : public PIN_INFO +{ +public: + CPinInfo() {pFilter = NULL;} + ~CPinInfo() {if(pFilter) pFilter->Release();} +}; + +class CFilterInfo : public FILTER_INFO +{ +public: + CFilterInfo() {pGraph = NULL;} + ~CFilterInfo() {if(pGraph) pGraph->Release();} +}; + +#define BeginEnumFilters(pFilterGraph, pEnumFilters, pBaseFilter) \ + {CComPtr pEnumFilters; \ + if(pFilterGraph && SUCCEEDED(pFilterGraph->EnumFilters(&pEnumFilters))) \ + { \ + for(CComPtr pBaseFilter; S_OK == pEnumFilters->Next(1, &pBaseFilter, 0); pBaseFilter = NULL) \ + { \ + +#define EndEnumFilters }}} + +#define BeginEnumCachedFilters(pGraphConfig, pEnumFilters, pBaseFilter) \ + {CComPtr pEnumFilters; \ + if(pGraphConfig && SUCCEEDED(pGraphConfig->EnumCacheFilter(&pEnumFilters))) \ + { \ + for(CComPtr pBaseFilter; S_OK == pEnumFilters->Next(1, &pBaseFilter, 0); pBaseFilter = NULL) \ + { \ + +#define EndEnumCachedFilters }}} + +#define BeginEnumPins(pBaseFilter, pEnumPins, pPin) \ + {CComPtr pEnumPins; \ + if(pBaseFilter && SUCCEEDED(pBaseFilter->EnumPins(&pEnumPins))) \ + { \ + for(CComPtr pPin; S_OK == pEnumPins->Next(1, &pPin, 0); pPin = NULL) \ + { \ + +#define EndEnumPins }}} + +#define BeginEnumMediaTypes(pPin, pEnumMediaTypes, pMediaType) \ + {CComPtr pEnumMediaTypes; \ + if(pPin && SUCCEEDED(pPin->EnumMediaTypes(&pEnumMediaTypes))) \ + { \ + AM_MEDIA_TYPE* pMediaType = NULL; \ + for(; S_OK == pEnumMediaTypes->Next(1, &pMediaType, NULL); DeleteMediaType(pMediaType), pMediaType = NULL) \ + { \ + +#define EndEnumMediaTypes(pMediaType) } if(pMediaType) DeleteMediaType(pMediaType); }} + +#define BeginEnumSysDev(clsid, pMoniker) \ + {CComPtr pDevEnum4$##clsid; \ + pDevEnum4$##clsid.CoCreateInstance(CLSID_SystemDeviceEnum); \ + CComPtr pClassEnum4$##clsid; \ + if(SUCCEEDED(pDevEnum4$##clsid->CreateClassEnumerator(clsid, &pClassEnum4$##clsid, 0)) \ + && pClassEnum4$##clsid) \ + { \ + for(CComPtr pMoniker; pClassEnum4$##clsid->Next(1, &pMoniker, 0) == S_OK; pMoniker = NULL) \ + { \ + +#define EndEnumSysDev }}} + +#else + #ifdef DEBUG + #pragma message("STREAMS.H included TWICE") + #endif +#endif // __STREAMS__ + diff --git a/plugins/GSdx/baseclasses/strmctl.cpp b/plugins/GSdx/baseclasses/strmctl.cpp index f0373d4869..cba7e9b6ec 100644 --- a/plugins/GSdx/baseclasses/strmctl.cpp +++ b/plugins/GSdx/baseclasses/strmctl.cpp @@ -1,401 +1,401 @@ -//------------------------------------------------------------------------------ -// File: StrmCtl.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include "strmctl.h" - -CBaseStreamControl::CBaseStreamControl() -: m_StreamState(STREAM_FLOWING) -, m_StreamStateOnStop(STREAM_FLOWING) // means no pending stop -, m_tStartTime(MAX_TIME) -, m_tStopTime(MAX_TIME) -, m_dwStartCookie(0) -, m_dwStopCookie(0) -, m_pRefClock(NULL) -, m_FilterState(State_Stopped) -, m_bIsFlushing(FALSE) -, m_bStopSendExtra(FALSE) -{} - -CBaseStreamControl::~CBaseStreamControl() -{ - // Make sure we release the clock. - SetSyncSource(NULL); - return; -} - - -STDMETHODIMP CBaseStreamControl::StopAt(const REFERENCE_TIME * ptStop, BOOL bSendExtra, DWORD dwCookie) -{ - CAutoLock lck(&m_CritSec); - m_bStopSendExtra = FALSE; // reset - m_bStopExtraSent = FALSE; - if (ptStop) - { - if (*ptStop == MAX_TIME) - { - DbgLog((LOG_TRACE,2,TEXT("StopAt: Cancel stop"))); - CancelStop(); - // If there's now a command to start in the future, we assume - // they want to be stopped when the graph is first run - if (m_FilterState == State_Stopped && m_tStartTime < MAX_TIME) { - m_StreamState = STREAM_DISCARDING; - DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING"))); - } - return NOERROR; - } - DbgLog((LOG_TRACE,2,TEXT("StopAt: %dms extra=%d"), - (int)(*ptStop/10000), bSendExtra)); - // if the first command is to stop in the future, then we assume they - // want to be started when the graph is first run - if (m_FilterState == State_Stopped && m_tStartTime > *ptStop) { - m_StreamState = STREAM_FLOWING; - DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING"))); - } - m_bStopSendExtra = bSendExtra; - m_tStopTime = *ptStop; - m_dwStopCookie = dwCookie; - m_StreamStateOnStop = STREAM_DISCARDING; - } - else - { - DbgLog((LOG_TRACE,2,TEXT("StopAt: now"))); - // sending an extra frame when told to stop now would mess people up - m_bStopSendExtra = FALSE; - m_tStopTime = MAX_TIME; - m_dwStopCookie = 0; - m_StreamState = STREAM_DISCARDING; - m_StreamStateOnStop = STREAM_FLOWING; // no pending stop - } - // we might change our mind what to do with a sample we're blocking - m_StreamEvent.Set(); - return NOERROR; -} - -STDMETHODIMP CBaseStreamControl::StartAt -( const REFERENCE_TIME *ptStart, DWORD dwCookie ) -{ - CAutoLock lck(&m_CritSec); - if (ptStart) - { - if (*ptStart == MAX_TIME) - { - DbgLog((LOG_TRACE,2,TEXT("StartAt: Cancel start"))); - CancelStart(); - // If there's now a command to stop in the future, we assume - // they want to be started when the graph is first run - if (m_FilterState == State_Stopped && m_tStopTime < MAX_TIME) { - DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING"))); - m_StreamState = STREAM_FLOWING; - } - return NOERROR; - } - DbgLog((LOG_TRACE,2,TEXT("StartAt: %dms"), (int)(*ptStart/10000))); - // if the first command is to start in the future, then we assume they - // want to be stopped when the graph is first run - if (m_FilterState == State_Stopped && m_tStopTime >= *ptStart) { - DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING"))); - m_StreamState = STREAM_DISCARDING; - } - m_tStartTime = *ptStart; - m_dwStartCookie = dwCookie; - // if (m_tStopTime == m_tStartTime) CancelStop(); - } - else - { - DbgLog((LOG_TRACE,2,TEXT("StartAt: now"))); - m_tStartTime = MAX_TIME; - m_dwStartCookie = 0; - m_StreamState = STREAM_FLOWING; - } - // we might change our mind what to do with a sample we're blocking - m_StreamEvent.Set(); - return NOERROR; -} - -// Retrieve information about current settings -STDMETHODIMP CBaseStreamControl::GetInfo(AM_STREAM_INFO *pInfo) -{ - if (pInfo == NULL) - return E_POINTER; - - pInfo->tStart = m_tStartTime; - pInfo->tStop = m_tStopTime; - pInfo->dwStartCookie = m_dwStartCookie; - pInfo->dwStopCookie = m_dwStopCookie; - pInfo->dwFlags = m_bStopSendExtra ? AM_STREAM_INFO_STOP_SEND_EXTRA : 0; - pInfo->dwFlags |= m_tStartTime == MAX_TIME ? 0 : AM_STREAM_INFO_START_DEFINED; - pInfo->dwFlags |= m_tStopTime == MAX_TIME ? 0 : AM_STREAM_INFO_STOP_DEFINED; - switch (m_StreamState) { - default: - DbgBreak("Invalid stream state"); - case STREAM_FLOWING: - break; - case STREAM_DISCARDING: - pInfo->dwFlags |= AM_STREAM_INFO_DISCARDING; - break; - } - return S_OK; -} - - -void CBaseStreamControl::ExecuteStop() -{ - ASSERT(CritCheckIn(&m_CritSec)); - m_StreamState = m_StreamStateOnStop; - if (m_dwStopCookie && m_pSink) { - DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STOPPED (%d)"), - m_dwStopCookie)); - m_pSink->Notify(EC_STREAM_CONTROL_STOPPED, (LONG_PTR)this, m_dwStopCookie); - } - CancelStop(); // This will do the tidy up -} - -void CBaseStreamControl::ExecuteStart() -{ - ASSERT(CritCheckIn(&m_CritSec)); - m_StreamState = STREAM_FLOWING; - if (m_dwStartCookie) { - DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STARTED (%d)"), - m_dwStartCookie)); - m_pSink->Notify(EC_STREAM_CONTROL_STARTED, (LONG_PTR)this, m_dwStartCookie); - } - CancelStart(); // This will do the tidy up -} - -void CBaseStreamControl::CancelStop() -{ - ASSERT(CritCheckIn(&m_CritSec)); - m_tStopTime = MAX_TIME; - m_dwStopCookie = 0; - m_StreamStateOnStop = STREAM_FLOWING; -} - -void CBaseStreamControl::CancelStart() -{ - ASSERT(CritCheckIn(&m_CritSec)); - m_tStartTime = MAX_TIME; - m_dwStartCookie = 0; -} - - -// This guy will return one of the three StreamControlState's. Here's what the caller -// should do for each one: -// -// STREAM_FLOWING: Proceed as usual (render or pass the sample on) -// STREAM_DISCARDING: Calculate the time 'til *pSampleStart and wait that long -// for the event handle (GetStreamEventHandle()). If the -// wait expires, throw the sample away. If the event -// fires, call me back, I've changed my mind. -// I use pSampleStart (not Stop) so that live sources don't -// block for the duration of their samples, since the clock -// will always read approximately pSampleStart when called - - -// All through this code, you'll notice the following rules: -// - When start and stop time are the same, it's as if start was first -// - An event is considered inside the sample when it's >= sample start time -// but < sample stop time -// - if any part of the sample is supposed to be sent, we'll send the whole -// thing since we don't break it into smaller pieces -// - If we skip over a start or stop without doing it, we still signal the event -// and reset ourselves in case somebody's waiting for the event, and to make -// sure we notice that the event is past and should be forgotten -// Here are the 19 cases that have to be handled (x=start o=stop <-->=sample): -// -// 1. xo<--> start then stop -// 2. ox<--> stop then start -// 3. x start -// 4. o stop then start -// 5. x<-->o start -// 6. o<-->x stop -// 7. o start -// 8. x no change -// 9. start -// 10. stop then start -// 11. <-->xo no change -// 12. <-->ox no change -// 13. x<--> start -// 14. start -// 15. <-->x no change -// 16. o<--> stop -// 17. no change -// 18. <-->o no change -// 19. <--> no change - - -enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckSampleTimes -( const REFERENCE_TIME * pSampleStart, const REFERENCE_TIME * pSampleStop ) -{ - CAutoLock lck(&m_CritSec); - - ASSERT(!m_bIsFlushing); - ASSERT(pSampleStart && pSampleStop); - - // Don't ask me how I came up with the code below to handle all 19 cases - // - DannyMi - - if (m_tStopTime >= *pSampleStart) - { - if (m_tStartTime >= *pSampleStop) - return m_StreamState; // cases 8 11 12 15 17 18 19 - if (m_tStopTime < m_tStartTime) - ExecuteStop(); // case 10 - ExecuteStart(); // cases 3 5 7 9 13 14 - return m_StreamState; - } - - if (m_tStartTime >= *pSampleStop) - { - ExecuteStop(); // cases 6 16 - return m_StreamState; - } - - if (m_tStartTime <= m_tStopTime) - { - ExecuteStart(); - ExecuteStop(); - return m_StreamState; // case 1 - } - else - { - ExecuteStop(); - ExecuteStart(); - return m_StreamState; // cases 2 4 - } -} - - -enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckStreamState( IMediaSample * pSample ) -{ - - REFERENCE_TIME rtBufferStart, rtBufferStop; - const BOOL bNoBufferTimes = - pSample == NULL || - FAILED(pSample->GetTime(&rtBufferStart, &rtBufferStop)); - - StreamControlState state; - LONG lWait; - - do - { - // something has to break out of the blocking - if (m_bIsFlushing || m_FilterState == State_Stopped) - return STREAM_DISCARDING; - - if (bNoBufferTimes) { - // Can't do anything until we get a time stamp - state = m_StreamState; - break; - } else { - state = CheckSampleTimes( &rtBufferStart, &rtBufferStop ); - if (state == STREAM_FLOWING) - break; - - // we aren't supposed to send this, but we've been - // told to send one more than we were supposed to - // (and the stop isn't still pending and we're streaming) - if (m_bStopSendExtra && !m_bStopExtraSent && - m_tStopTime == MAX_TIME && - m_FilterState != State_Stopped) { - m_bStopExtraSent = TRUE; - DbgLog((LOG_TRACE,2,TEXT("%d sending an EXTRA frame"), - m_dwStopCookie)); - state = STREAM_FLOWING; - break; - } - } - - // We're in discarding mode - - // If we've no clock, discard as fast as we can - if (!m_pRefClock) { - break; - - // If we're paused, we can't discard in a timely manner because - // there's no such thing as stream times. We must block until - // we run or stop, or we'll end up throwing the whole stream away - // as quickly as possible - } else if (m_FilterState == State_Paused) { - lWait = INFINITE; - - } else { - // wait until it's time for the sample until we say "discard" - // ("discard in a timely fashion") - REFERENCE_TIME rtNow; - EXECUTE_ASSERT(SUCCEEDED(m_pRefClock->GetTime(&rtNow))); - rtNow -= m_tRunStart; // Into relative ref-time - lWait = LONG((rtBufferStart - rtNow)/10000); // 100ns -> ms - if (lWait < 10) break; // Not worth waiting - discard early - } - - } while(WaitForSingleObject(GetStreamEventHandle(), lWait) != WAIT_TIMEOUT); - - return state; -} - - -void CBaseStreamControl::NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart ) -{ - CAutoLock lck(&m_CritSec); - - // or we will get confused - if (m_FilterState == new_state) - return; - - switch (new_state) - { - case State_Stopped: - - DbgLog((LOG_TRACE,2,TEXT("Filter is STOPPED"))); - - // execute any pending starts and stops in the right order, - // to make sure all notifications get sent, and we end up - // in the right state to begin next time (??? why not?) - - if (m_tStartTime != MAX_TIME && m_tStopTime == MAX_TIME) { - ExecuteStart(); - } else if (m_tStopTime != MAX_TIME && m_tStartTime == MAX_TIME) { - ExecuteStop(); - } else if (m_tStopTime != MAX_TIME && m_tStartTime != MAX_TIME) { - if (m_tStartTime <= m_tStopTime) { - ExecuteStart(); - ExecuteStop(); - } else { - ExecuteStop(); - ExecuteStart(); - } - } - // always start off flowing when the graph starts streaming - // unless told otherwise - m_StreamState = STREAM_FLOWING; - m_FilterState = new_state; - break; - - case State_Running: - - DbgLog((LOG_TRACE,2,TEXT("Filter is RUNNING"))); - - m_tRunStart = tStart; - // fall-through - - default: // case State_Paused: - m_FilterState = new_state; - } - // unblock! - m_StreamEvent.Set(); -} - - -void CBaseStreamControl::Flushing(BOOL bInProgress) -{ - CAutoLock lck(&m_CritSec); - m_bIsFlushing = bInProgress; - m_StreamEvent.Set(); -} +//------------------------------------------------------------------------------ +// File: StrmCtl.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include "strmctl.h" + +CBaseStreamControl::CBaseStreamControl() +: m_StreamState(STREAM_FLOWING) +, m_StreamStateOnStop(STREAM_FLOWING) // means no pending stop +, m_tStartTime(MAX_TIME) +, m_tStopTime(MAX_TIME) +, m_dwStartCookie(0) +, m_dwStopCookie(0) +, m_pRefClock(NULL) +, m_FilterState(State_Stopped) +, m_bIsFlushing(FALSE) +, m_bStopSendExtra(FALSE) +{} + +CBaseStreamControl::~CBaseStreamControl() +{ + // Make sure we release the clock. + SetSyncSource(NULL); + return; +} + + +STDMETHODIMP CBaseStreamControl::StopAt(const REFERENCE_TIME * ptStop, BOOL bSendExtra, DWORD dwCookie) +{ + CAutoLock lck(&m_CritSec); + m_bStopSendExtra = FALSE; // reset + m_bStopExtraSent = FALSE; + if (ptStop) + { + if (*ptStop == MAX_TIME) + { + DbgLog((LOG_TRACE,2,TEXT("StopAt: Cancel stop"))); + CancelStop(); + // If there's now a command to start in the future, we assume + // they want to be stopped when the graph is first run + if (m_FilterState == State_Stopped && m_tStartTime < MAX_TIME) { + m_StreamState = STREAM_DISCARDING; + DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING"))); + } + return NOERROR; + } + DbgLog((LOG_TRACE,2,TEXT("StopAt: %dms extra=%d"), + (int)(*ptStop/10000), bSendExtra)); + // if the first command is to stop in the future, then we assume they + // want to be started when the graph is first run + if (m_FilterState == State_Stopped && m_tStartTime > *ptStop) { + m_StreamState = STREAM_FLOWING; + DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING"))); + } + m_bStopSendExtra = bSendExtra; + m_tStopTime = *ptStop; + m_dwStopCookie = dwCookie; + m_StreamStateOnStop = STREAM_DISCARDING; + } + else + { + DbgLog((LOG_TRACE,2,TEXT("StopAt: now"))); + // sending an extra frame when told to stop now would mess people up + m_bStopSendExtra = FALSE; + m_tStopTime = MAX_TIME; + m_dwStopCookie = 0; + m_StreamState = STREAM_DISCARDING; + m_StreamStateOnStop = STREAM_FLOWING; // no pending stop + } + // we might change our mind what to do with a sample we're blocking + m_StreamEvent.Set(); + return NOERROR; +} + +STDMETHODIMP CBaseStreamControl::StartAt +( const REFERENCE_TIME *ptStart, DWORD dwCookie ) +{ + CAutoLock lck(&m_CritSec); + if (ptStart) + { + if (*ptStart == MAX_TIME) + { + DbgLog((LOG_TRACE,2,TEXT("StartAt: Cancel start"))); + CancelStart(); + // If there's now a command to stop in the future, we assume + // they want to be started when the graph is first run + if (m_FilterState == State_Stopped && m_tStopTime < MAX_TIME) { + DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING"))); + m_StreamState = STREAM_FLOWING; + } + return NOERROR; + } + DbgLog((LOG_TRACE,2,TEXT("StartAt: %dms"), (int)(*ptStart/10000))); + // if the first command is to start in the future, then we assume they + // want to be stopped when the graph is first run + if (m_FilterState == State_Stopped && m_tStopTime >= *ptStart) { + DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING"))); + m_StreamState = STREAM_DISCARDING; + } + m_tStartTime = *ptStart; + m_dwStartCookie = dwCookie; + // if (m_tStopTime == m_tStartTime) CancelStop(); + } + else + { + DbgLog((LOG_TRACE,2,TEXT("StartAt: now"))); + m_tStartTime = MAX_TIME; + m_dwStartCookie = 0; + m_StreamState = STREAM_FLOWING; + } + // we might change our mind what to do with a sample we're blocking + m_StreamEvent.Set(); + return NOERROR; +} + +// Retrieve information about current settings +STDMETHODIMP CBaseStreamControl::GetInfo(AM_STREAM_INFO *pInfo) +{ + if (pInfo == NULL) + return E_POINTER; + + pInfo->tStart = m_tStartTime; + pInfo->tStop = m_tStopTime; + pInfo->dwStartCookie = m_dwStartCookie; + pInfo->dwStopCookie = m_dwStopCookie; + pInfo->dwFlags = m_bStopSendExtra ? AM_STREAM_INFO_STOP_SEND_EXTRA : 0; + pInfo->dwFlags |= m_tStartTime == MAX_TIME ? 0 : AM_STREAM_INFO_START_DEFINED; + pInfo->dwFlags |= m_tStopTime == MAX_TIME ? 0 : AM_STREAM_INFO_STOP_DEFINED; + switch (m_StreamState) { + default: + DbgBreak("Invalid stream state"); + case STREAM_FLOWING: + break; + case STREAM_DISCARDING: + pInfo->dwFlags |= AM_STREAM_INFO_DISCARDING; + break; + } + return S_OK; +} + + +void CBaseStreamControl::ExecuteStop() +{ + ASSERT(CritCheckIn(&m_CritSec)); + m_StreamState = m_StreamStateOnStop; + if (m_dwStopCookie && m_pSink) { + DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STOPPED (%d)"), + m_dwStopCookie)); + m_pSink->Notify(EC_STREAM_CONTROL_STOPPED, (LONG_PTR)this, m_dwStopCookie); + } + CancelStop(); // This will do the tidy up +} + +void CBaseStreamControl::ExecuteStart() +{ + ASSERT(CritCheckIn(&m_CritSec)); + m_StreamState = STREAM_FLOWING; + if (m_dwStartCookie) { + DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STARTED (%d)"), + m_dwStartCookie)); + m_pSink->Notify(EC_STREAM_CONTROL_STARTED, (LONG_PTR)this, m_dwStartCookie); + } + CancelStart(); // This will do the tidy up +} + +void CBaseStreamControl::CancelStop() +{ + ASSERT(CritCheckIn(&m_CritSec)); + m_tStopTime = MAX_TIME; + m_dwStopCookie = 0; + m_StreamStateOnStop = STREAM_FLOWING; +} + +void CBaseStreamControl::CancelStart() +{ + ASSERT(CritCheckIn(&m_CritSec)); + m_tStartTime = MAX_TIME; + m_dwStartCookie = 0; +} + + +// This guy will return one of the three StreamControlState's. Here's what the caller +// should do for each one: +// +// STREAM_FLOWING: Proceed as usual (render or pass the sample on) +// STREAM_DISCARDING: Calculate the time 'til *pSampleStart and wait that long +// for the event handle (GetStreamEventHandle()). If the +// wait expires, throw the sample away. If the event +// fires, call me back, I've changed my mind. +// I use pSampleStart (not Stop) so that live sources don't +// block for the duration of their samples, since the clock +// will always read approximately pSampleStart when called + + +// All through this code, you'll notice the following rules: +// - When start and stop time are the same, it's as if start was first +// - An event is considered inside the sample when it's >= sample start time +// but < sample stop time +// - if any part of the sample is supposed to be sent, we'll send the whole +// thing since we don't break it into smaller pieces +// - If we skip over a start or stop without doing it, we still signal the event +// and reset ourselves in case somebody's waiting for the event, and to make +// sure we notice that the event is past and should be forgotten +// Here are the 19 cases that have to be handled (x=start o=stop <-->=sample): +// +// 1. xo<--> start then stop +// 2. ox<--> stop then start +// 3. x start +// 4. o stop then start +// 5. x<-->o start +// 6. o<-->x stop +// 7. o start +// 8. x no change +// 9. start +// 10. stop then start +// 11. <-->xo no change +// 12. <-->ox no change +// 13. x<--> start +// 14. start +// 15. <-->x no change +// 16. o<--> stop +// 17. no change +// 18. <-->o no change +// 19. <--> no change + + +enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckSampleTimes +( const REFERENCE_TIME * pSampleStart, const REFERENCE_TIME * pSampleStop ) +{ + CAutoLock lck(&m_CritSec); + + ASSERT(!m_bIsFlushing); + ASSERT(pSampleStart && pSampleStop); + + // Don't ask me how I came up with the code below to handle all 19 cases + // - DannyMi + + if (m_tStopTime >= *pSampleStart) + { + if (m_tStartTime >= *pSampleStop) + return m_StreamState; // cases 8 11 12 15 17 18 19 + if (m_tStopTime < m_tStartTime) + ExecuteStop(); // case 10 + ExecuteStart(); // cases 3 5 7 9 13 14 + return m_StreamState; + } + + if (m_tStartTime >= *pSampleStop) + { + ExecuteStop(); // cases 6 16 + return m_StreamState; + } + + if (m_tStartTime <= m_tStopTime) + { + ExecuteStart(); + ExecuteStop(); + return m_StreamState; // case 1 + } + else + { + ExecuteStop(); + ExecuteStart(); + return m_StreamState; // cases 2 4 + } +} + + +enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckStreamState( IMediaSample * pSample ) +{ + + REFERENCE_TIME rtBufferStart, rtBufferStop; + const BOOL bNoBufferTimes = + pSample == NULL || + FAILED(pSample->GetTime(&rtBufferStart, &rtBufferStop)); + + StreamControlState state; + LONG lWait; + + do + { + // something has to break out of the blocking + if (m_bIsFlushing || m_FilterState == State_Stopped) + return STREAM_DISCARDING; + + if (bNoBufferTimes) { + // Can't do anything until we get a time stamp + state = m_StreamState; + break; + } else { + state = CheckSampleTimes( &rtBufferStart, &rtBufferStop ); + if (state == STREAM_FLOWING) + break; + + // we aren't supposed to send this, but we've been + // told to send one more than we were supposed to + // (and the stop isn't still pending and we're streaming) + if (m_bStopSendExtra && !m_bStopExtraSent && + m_tStopTime == MAX_TIME && + m_FilterState != State_Stopped) { + m_bStopExtraSent = TRUE; + DbgLog((LOG_TRACE,2,TEXT("%d sending an EXTRA frame"), + m_dwStopCookie)); + state = STREAM_FLOWING; + break; + } + } + + // We're in discarding mode + + // If we've no clock, discard as fast as we can + if (!m_pRefClock) { + break; + + // If we're paused, we can't discard in a timely manner because + // there's no such thing as stream times. We must block until + // we run or stop, or we'll end up throwing the whole stream away + // as quickly as possible + } else if (m_FilterState == State_Paused) { + lWait = INFINITE; + + } else { + // wait until it's time for the sample until we say "discard" + // ("discard in a timely fashion") + REFERENCE_TIME rtNow; + EXECUTE_ASSERT(SUCCEEDED(m_pRefClock->GetTime(&rtNow))); + rtNow -= m_tRunStart; // Into relative ref-time + lWait = LONG((rtBufferStart - rtNow)/10000); // 100ns -> ms + if (lWait < 10) break; // Not worth waiting - discard early + } + + } while(WaitForSingleObject(GetStreamEventHandle(), lWait) != WAIT_TIMEOUT); + + return state; +} + + +void CBaseStreamControl::NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart ) +{ + CAutoLock lck(&m_CritSec); + + // or we will get confused + if (m_FilterState == new_state) + return; + + switch (new_state) + { + case State_Stopped: + + DbgLog((LOG_TRACE,2,TEXT("Filter is STOPPED"))); + + // execute any pending starts and stops in the right order, + // to make sure all notifications get sent, and we end up + // in the right state to begin next time (??? why not?) + + if (m_tStartTime != MAX_TIME && m_tStopTime == MAX_TIME) { + ExecuteStart(); + } else if (m_tStopTime != MAX_TIME && m_tStartTime == MAX_TIME) { + ExecuteStop(); + } else if (m_tStopTime != MAX_TIME && m_tStartTime != MAX_TIME) { + if (m_tStartTime <= m_tStopTime) { + ExecuteStart(); + ExecuteStop(); + } else { + ExecuteStop(); + ExecuteStart(); + } + } + // always start off flowing when the graph starts streaming + // unless told otherwise + m_StreamState = STREAM_FLOWING; + m_FilterState = new_state; + break; + + case State_Running: + + DbgLog((LOG_TRACE,2,TEXT("Filter is RUNNING"))); + + m_tRunStart = tStart; + // fall-through + + default: // case State_Paused: + m_FilterState = new_state; + } + // unblock! + m_StreamEvent.Set(); +} + + +void CBaseStreamControl::Flushing(BOOL bInProgress) +{ + CAutoLock lck(&m_CritSec); + m_bIsFlushing = bInProgress; + m_StreamEvent.Set(); +} diff --git a/plugins/GSdx/baseclasses/strmctl.h b/plugins/GSdx/baseclasses/strmctl.h index 2a1475fe3a..d054777c75 100644 --- a/plugins/GSdx/baseclasses/strmctl.h +++ b/plugins/GSdx/baseclasses/strmctl.h @@ -1,157 +1,157 @@ -//------------------------------------------------------------------------------ -// File: StrmCtl.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __strmctl_h__ -#define __strmctl_h__ - -class CBaseStreamControl : public IAMStreamControl -{ -public: - // Used by the implementation - enum StreamControlState - { STREAM_FLOWING = 0x1000, - STREAM_DISCARDING - }; - -private: - enum StreamControlState m_StreamState; // Current stream state - enum StreamControlState m_StreamStateOnStop; // State after next stop - // (i.e.Blocking or Discarding) - - REFERENCE_TIME m_tStartTime; // MAX_TIME implies none - REFERENCE_TIME m_tStopTime; // MAX_TIME implies none - DWORD m_dwStartCookie; // Cookie for notification to app - DWORD m_dwStopCookie; // Cookie for notification to app - volatile BOOL m_bIsFlushing; // No optimization pls! - volatile BOOL m_bStopSendExtra; // bSendExtra was set - volatile BOOL m_bStopExtraSent; // the extra one was sent - - CCritSec m_CritSec; // CritSec to guard above attributes - - // Event to fire when we can come - // out of blocking, or to come out of waiting - // to discard if we change our minds. - // - CAMEvent m_StreamEvent; - - // All of these methods execute immediately. Helpers for others. - // - void ExecuteStop(); - void ExecuteStart(); - void CancelStop(); - void CancelStart(); - - // Some things we need to be told by our owning filter - // Your pin must also expose IAMStreamControl when QI'd for it! - // - IReferenceClock * m_pRefClock; // Need it to set advises - // Filter must tell us via - // SetSyncSource - IMediaEventSink * m_pSink; // Event sink - // Filter must tell us after it - // creates it in JoinFilterGraph() - FILTER_STATE m_FilterState; // Just need it! - // Filter must tell us via - // NotifyFilterState - REFERENCE_TIME m_tRunStart; // Per the Run call to the filter - - // This guy will return one of the three StreamControlState's. Here's what - // the caller should do for each one: - // - // STREAM_FLOWING: Proceed as usual (render or pass the sample on) - // STREAM_DISCARDING: Calculate the time 'til *pSampleStop and wait - // that long for the event handle - // (GetStreamEventHandle()). If the wait - // expires, throw the sample away. If the event - // fires, call me back - I've changed my mind. - // - enum StreamControlState CheckSampleTimes( const REFERENCE_TIME * pSampleStart, - const REFERENCE_TIME * pSampleStop ); - -public: - // You don't have to tell us much when we're created, but there are other - // obligations that must be met. See SetSyncSource & NotifyFilterState - // below. - // - CBaseStreamControl(); - ~CBaseStreamControl(); - - // If you want this class to work properly, there are thing you need to - // (keep) telling it. Filters with pins that use this class - // should ensure that they pass through to this method any calls they - // receive on their SetSyncSource. - - // We need a clock to see what time it is. This is for the - // "discard in a timely fashion" logic. If we discard everything as - // quick as possible, a whole 60 minute file could get discarded in the - // first 10 seconds, and if somebody wants to turn streaming on at 30 - // minutes into the file, and they make the call more than a few seconds - // after the graph is run, it may be too late! - // So we hold every sample until it's time has gone, then we discard it. - // The filter should call this when it gets a SetSyncSource - // - void SetSyncSource( IReferenceClock * pRefClock ) - { - CAutoLock lck(&m_CritSec); - if (m_pRefClock) m_pRefClock->Release(); - m_pRefClock = pRefClock; - if (m_pRefClock) m_pRefClock->AddRef(); - } - - // Set event sink for notifications - // The filter should call this in its JoinFilterGraph after it creates the - // IMediaEventSink - // - void SetFilterGraph( IMediaEventSink *pSink ) { - m_pSink = pSink; - } - - // Since we schedule in stream time, we need the tStart and must track the - // state of our owning filter. - // The app should call this ever state change - // - void NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart = 0 ); - - // Filter should call Flushing(TRUE) in BeginFlush, - // and Flushing(FALSE) in EndFlush. - // - void Flushing( BOOL bInProgress ); - - - // The two main methods of IAMStreamControl - - // Class adds default values suitable for immediate - // muting and unmuting of the stream. - - STDMETHODIMP StopAt( const REFERENCE_TIME * ptStop = NULL, - BOOL bSendExtra = FALSE, - DWORD dwCookie = 0 ); - STDMETHODIMP StartAt( const REFERENCE_TIME * ptStart = NULL, - DWORD dwCookie = 0 ); - STDMETHODIMP GetInfo( AM_STREAM_INFO *pInfo); - - // Helper function for pin's receive method. Call this with - // the sample and we'll tell you what to do with it. We'll do a - // WaitForSingleObject within this call if one is required. This is - // a "What should I do with this sample?" kind of call. We'll tell the - // caller to either flow it or discard it. - // If pSample is NULL we evaluate based on the current state - // settings - enum StreamControlState CheckStreamState( IMediaSample * pSample ); - -private: - // These don't require locking, but we are relying on the fact that - // m_StreamState can be retrieved with integrity, and is a snap shot that - // may have just been, or may be just about to be, changed. - HANDLE GetStreamEventHandle() const { return m_StreamEvent; } - enum StreamControlState GetStreamState() const { return m_StreamState; } - BOOL IsStreaming() const { return m_StreamState == STREAM_FLOWING; } -}; - -#endif +//------------------------------------------------------------------------------ +// File: StrmCtl.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __strmctl_h__ +#define __strmctl_h__ + +class CBaseStreamControl : public IAMStreamControl +{ +public: + // Used by the implementation + enum StreamControlState + { STREAM_FLOWING = 0x1000, + STREAM_DISCARDING + }; + +private: + enum StreamControlState m_StreamState; // Current stream state + enum StreamControlState m_StreamStateOnStop; // State after next stop + // (i.e.Blocking or Discarding) + + REFERENCE_TIME m_tStartTime; // MAX_TIME implies none + REFERENCE_TIME m_tStopTime; // MAX_TIME implies none + DWORD m_dwStartCookie; // Cookie for notification to app + DWORD m_dwStopCookie; // Cookie for notification to app + volatile BOOL m_bIsFlushing; // No optimization pls! + volatile BOOL m_bStopSendExtra; // bSendExtra was set + volatile BOOL m_bStopExtraSent; // the extra one was sent + + CCritSec m_CritSec; // CritSec to guard above attributes + + // Event to fire when we can come + // out of blocking, or to come out of waiting + // to discard if we change our minds. + // + CAMEvent m_StreamEvent; + + // All of these methods execute immediately. Helpers for others. + // + void ExecuteStop(); + void ExecuteStart(); + void CancelStop(); + void CancelStart(); + + // Some things we need to be told by our owning filter + // Your pin must also expose IAMStreamControl when QI'd for it! + // + IReferenceClock * m_pRefClock; // Need it to set advises + // Filter must tell us via + // SetSyncSource + IMediaEventSink * m_pSink; // Event sink + // Filter must tell us after it + // creates it in JoinFilterGraph() + FILTER_STATE m_FilterState; // Just need it! + // Filter must tell us via + // NotifyFilterState + REFERENCE_TIME m_tRunStart; // Per the Run call to the filter + + // This guy will return one of the three StreamControlState's. Here's what + // the caller should do for each one: + // + // STREAM_FLOWING: Proceed as usual (render or pass the sample on) + // STREAM_DISCARDING: Calculate the time 'til *pSampleStop and wait + // that long for the event handle + // (GetStreamEventHandle()). If the wait + // expires, throw the sample away. If the event + // fires, call me back - I've changed my mind. + // + enum StreamControlState CheckSampleTimes( const REFERENCE_TIME * pSampleStart, + const REFERENCE_TIME * pSampleStop ); + +public: + // You don't have to tell us much when we're created, but there are other + // obligations that must be met. See SetSyncSource & NotifyFilterState + // below. + // + CBaseStreamControl(); + ~CBaseStreamControl(); + + // If you want this class to work properly, there are thing you need to + // (keep) telling it. Filters with pins that use this class + // should ensure that they pass through to this method any calls they + // receive on their SetSyncSource. + + // We need a clock to see what time it is. This is for the + // "discard in a timely fashion" logic. If we discard everything as + // quick as possible, a whole 60 minute file could get discarded in the + // first 10 seconds, and if somebody wants to turn streaming on at 30 + // minutes into the file, and they make the call more than a few seconds + // after the graph is run, it may be too late! + // So we hold every sample until it's time has gone, then we discard it. + // The filter should call this when it gets a SetSyncSource + // + void SetSyncSource( IReferenceClock * pRefClock ) + { + CAutoLock lck(&m_CritSec); + if (m_pRefClock) m_pRefClock->Release(); + m_pRefClock = pRefClock; + if (m_pRefClock) m_pRefClock->AddRef(); + } + + // Set event sink for notifications + // The filter should call this in its JoinFilterGraph after it creates the + // IMediaEventSink + // + void SetFilterGraph( IMediaEventSink *pSink ) { + m_pSink = pSink; + } + + // Since we schedule in stream time, we need the tStart and must track the + // state of our owning filter. + // The app should call this ever state change + // + void NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart = 0 ); + + // Filter should call Flushing(TRUE) in BeginFlush, + // and Flushing(FALSE) in EndFlush. + // + void Flushing( BOOL bInProgress ); + + + // The two main methods of IAMStreamControl + + // Class adds default values suitable for immediate + // muting and unmuting of the stream. + + STDMETHODIMP StopAt( const REFERENCE_TIME * ptStop = NULL, + BOOL bSendExtra = FALSE, + DWORD dwCookie = 0 ); + STDMETHODIMP StartAt( const REFERENCE_TIME * ptStart = NULL, + DWORD dwCookie = 0 ); + STDMETHODIMP GetInfo( AM_STREAM_INFO *pInfo); + + // Helper function for pin's receive method. Call this with + // the sample and we'll tell you what to do with it. We'll do a + // WaitForSingleObject within this call if one is required. This is + // a "What should I do with this sample?" kind of call. We'll tell the + // caller to either flow it or discard it. + // If pSample is NULL we evaluate based on the current state + // settings + enum StreamControlState CheckStreamState( IMediaSample * pSample ); + +private: + // These don't require locking, but we are relying on the fact that + // m_StreamState can be retrieved with integrity, and is a snap shot that + // may have just been, or may be just about to be, changed. + HANDLE GetStreamEventHandle() const { return m_StreamEvent; } + enum StreamControlState GetStreamState() const { return m_StreamState; } + BOOL IsStreaming() const { return m_StreamState == STREAM_FLOWING; } +}; + +#endif diff --git a/plugins/GSdx/baseclasses/sysclock.cpp b/plugins/GSdx/baseclasses/sysclock.cpp index a3cb59e40b..733e6f8bbb 100644 --- a/plugins/GSdx/baseclasses/sysclock.cpp +++ b/plugins/GSdx/baseclasses/sysclock.cpp @@ -1,74 +1,74 @@ -//------------------------------------------------------------------------------ -// File: SysClock.cpp -// -// Desc: DirectShow base classes - implements a system clock based on -// IReferenceClock. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include - - -#ifdef FILTER_DLL - -/* List of class IDs and creator functions for the class factory. This - provides the link between the OLE entry point in the DLL and an object - being created. The class factory will call the static CreateInstance - function when it is asked to create a CLSID_SystemClock object */ - -CFactoryTemplate g_Templates[1] = { - {&CLSID_SystemClock, CSystemClock::CreateInstance} -}; - -int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]); -#endif - -/* This goes in the factory template table to create new instances */ -CUnknown * WINAPI CSystemClock::CreateInstance(LPUNKNOWN pUnk,HRESULT *phr) -{ - return new CSystemClock(NAME("System reference clock"),pUnk, phr); -} - - -CSystemClock::CSystemClock(TCHAR *pName,LPUNKNOWN pUnk,HRESULT *phr) : - CBaseReferenceClock(pName, pUnk, phr) -{ -} - -STDMETHODIMP CSystemClock::NonDelegatingQueryInterface( - REFIID riid, - void ** ppv) -{ - if (riid == IID_IPersist) - { - return GetInterface(static_cast(this), ppv); - } - else if (riid == IID_IAMClockAdjust) - { - return GetInterface(static_cast(this), ppv); - } - else - { - return CBaseReferenceClock::NonDelegatingQueryInterface(riid, ppv); - } -} - -/* Return the clock's clsid */ -STDMETHODIMP -CSystemClock::GetClassID(CLSID *pClsID) -{ - CheckPointer(pClsID,E_POINTER); - ValidateReadWritePtr(pClsID,sizeof(CLSID)); - *pClsID = CLSID_SystemClock; - return NOERROR; -} - - -STDMETHODIMP -CSystemClock::SetClockDelta(REFERENCE_TIME rtDelta) -{ - return SetTimeDelta(rtDelta); -} +//------------------------------------------------------------------------------ +// File: SysClock.cpp +// +// Desc: DirectShow base classes - implements a system clock based on +// IReferenceClock. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include + + +#ifdef FILTER_DLL + +/* List of class IDs and creator functions for the class factory. This + provides the link between the OLE entry point in the DLL and an object + being created. The class factory will call the static CreateInstance + function when it is asked to create a CLSID_SystemClock object */ + +CFactoryTemplate g_Templates[1] = { + {&CLSID_SystemClock, CSystemClock::CreateInstance} +}; + +int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]); +#endif + +/* This goes in the factory template table to create new instances */ +CUnknown * WINAPI CSystemClock::CreateInstance(LPUNKNOWN pUnk,HRESULT *phr) +{ + return new CSystemClock(NAME("System reference clock"),pUnk, phr); +} + + +CSystemClock::CSystemClock(TCHAR *pName,LPUNKNOWN pUnk,HRESULT *phr) : + CBaseReferenceClock(pName, pUnk, phr) +{ +} + +STDMETHODIMP CSystemClock::NonDelegatingQueryInterface( + REFIID riid, + void ** ppv) +{ + if (riid == IID_IPersist) + { + return GetInterface(static_cast(this), ppv); + } + else if (riid == IID_IAMClockAdjust) + { + return GetInterface(static_cast(this), ppv); + } + else + { + return CBaseReferenceClock::NonDelegatingQueryInterface(riid, ppv); + } +} + +/* Return the clock's clsid */ +STDMETHODIMP +CSystemClock::GetClassID(CLSID *pClsID) +{ + CheckPointer(pClsID,E_POINTER); + ValidateReadWritePtr(pClsID,sizeof(CLSID)); + *pClsID = CLSID_SystemClock; + return NOERROR; +} + + +STDMETHODIMP +CSystemClock::SetClockDelta(REFERENCE_TIME rtDelta) +{ + return SetTimeDelta(rtDelta); +} diff --git a/plugins/GSdx/baseclasses/sysclock.h b/plugins/GSdx/baseclasses/sysclock.h index 53c8e4cefe..d55015f2f5 100644 --- a/plugins/GSdx/baseclasses/sysclock.h +++ b/plugins/GSdx/baseclasses/sysclock.h @@ -1,39 +1,39 @@ -//------------------------------------------------------------------------------ -// File: SysClock.h -// -// Desc: DirectShow base classes - defines a system clock implementation of -// IReferenceClock. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __SYSTEMCLOCK__ -#define __SYSTEMCLOCK__ - -// -// Base clock. Uses timeGetTime ONLY -// Uses most of the code in the base reference clock. -// Provides GetTime -// - -class CSystemClock : public CBaseReferenceClock, public IAMClockAdjust, public IPersist -{ -public: - // We must be able to create an instance of ourselves - static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *phr); - CSystemClock(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr); - - DECLARE_IUNKNOWN - - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void ** ppv); - - // Yield up our class id so that we can be persisted - // Implement required Ipersist method - STDMETHODIMP GetClassID(CLSID *pClsID); - - // IAMClockAdjust methods - STDMETHODIMP SetClockDelta(REFERENCE_TIME rtDelta); -}; //CSystemClock - -#endif /* __SYSTEMCLOCK__ */ +//------------------------------------------------------------------------------ +// File: SysClock.h +// +// Desc: DirectShow base classes - defines a system clock implementation of +// IReferenceClock. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __SYSTEMCLOCK__ +#define __SYSTEMCLOCK__ + +// +// Base clock. Uses timeGetTime ONLY +// Uses most of the code in the base reference clock. +// Provides GetTime +// + +class CSystemClock : public CBaseReferenceClock, public IAMClockAdjust, public IPersist +{ +public: + // We must be able to create an instance of ourselves + static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *phr); + CSystemClock(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr); + + DECLARE_IUNKNOWN + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void ** ppv); + + // Yield up our class id so that we can be persisted + // Implement required Ipersist method + STDMETHODIMP GetClassID(CLSID *pClsID); + + // IAMClockAdjust methods + STDMETHODIMP SetClockDelta(REFERENCE_TIME rtDelta); +}; //CSystemClock + +#endif /* __SYSTEMCLOCK__ */ diff --git a/plugins/GSdx/baseclasses/transfrm.cpp b/plugins/GSdx/baseclasses/transfrm.cpp index 2fc6e141aa..6ba8af266a 100644 --- a/plugins/GSdx/baseclasses/transfrm.cpp +++ b/plugins/GSdx/baseclasses/transfrm.cpp @@ -1,1016 +1,1016 @@ -//------------------------------------------------------------------------------ -// File: Transfrm.cpp -// -// Desc: DirectShow base classes - implements class for simple transform -// filters such as video decompressors. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include "measure.h" - - -// ================================================================= -// Implements the CTransformFilter class -// ================================================================= - -CTransformFilter::CTransformFilter(TCHAR *pName, - LPUNKNOWN pUnk, - REFCLSID clsid) : - CBaseFilter(pName,pUnk,&m_csFilter, clsid), - m_pInput(NULL), - m_pOutput(NULL), - m_bEOSDelivered(FALSE), - m_bQualityChanged(FALSE), - m_bSampleSkipped(FALSE) -{ -#ifdef PERF - RegisterPerfId(); -#endif // PERF -} - -#ifdef UNICODE -CTransformFilter::CTransformFilter(char *pName, - LPUNKNOWN pUnk, - REFCLSID clsid) : - CBaseFilter(pName,pUnk,&m_csFilter, clsid), - m_pInput(NULL), - m_pOutput(NULL), - m_bEOSDelivered(FALSE), - m_bQualityChanged(FALSE), - m_bSampleSkipped(FALSE) -{ -#ifdef PERF - RegisterPerfId(); -#endif // PERF -} -#endif - -// destructor - -CTransformFilter::~CTransformFilter() -{ - // Delete the pins - - delete m_pInput; - delete m_pOutput; -} - - -// Transform place holder - should never be called -HRESULT CTransformFilter::Transform(IMediaSample * pIn, IMediaSample *pOut) -{ - UNREFERENCED_PARAMETER(pIn); - UNREFERENCED_PARAMETER(pOut); - DbgBreak("CTransformFilter::Transform() should never be called"); - return E_UNEXPECTED; -} - - -// return the number of pins we provide - -int CTransformFilter::GetPinCount() -{ - return 2; -} - - -// return a non-addrefed CBasePin * for the user to addref if he holds onto it -// for longer than his pointer to us. We create the pins dynamically when they -// are asked for rather than in the constructor. This is because we want to -// give the derived class an oppportunity to return different pin objects - -// We return the objects as and when they are needed. If either of these fails -// then we return NULL, the assumption being that the caller will realise the -// whole deal is off and destroy us - which in turn will delete everything. - -CBasePin * -CTransformFilter::GetPin(int n) -{ - HRESULT hr = S_OK; - - // Create an input pin if necessary - - if (m_pInput == NULL) { - - m_pInput = new CTransformInputPin(NAME("Transform input pin"), - this, // Owner filter - &hr, // Result code - L"XForm In"); // Pin name - - - // Can't fail - ASSERT(SUCCEEDED(hr)); - if (m_pInput == NULL) { - return NULL; - } - m_pOutput = (CTransformOutputPin *) - new CTransformOutputPin(NAME("Transform output pin"), - this, // Owner filter - &hr, // Result code - L"XForm Out"); // Pin name - - - // Can't fail - ASSERT(SUCCEEDED(hr)); - if (m_pOutput == NULL) { - delete m_pInput; - m_pInput = NULL; - } - } - - // Return the appropriate pin - - if (n == 0) { - return m_pInput; - } else - if (n == 1) { - return m_pOutput; - } else { - return NULL; - } -} - - -// -// FindPin -// -// If Id is In or Out then return the IPin* for that pin -// creating the pin if need be. Otherwise return NULL with an error. - -STDMETHODIMP CTransformFilter::FindPin(LPCWSTR Id, IPin **ppPin) -{ - CheckPointer(ppPin,E_POINTER); - ValidateReadWritePtr(ppPin,sizeof(IPin *)); - - if (0==lstrcmpW(Id,L"In")) { - *ppPin = GetPin(0); - } else if (0==lstrcmpW(Id,L"Out")) { - *ppPin = GetPin(1); - } else { - *ppPin = NULL; - return VFW_E_NOT_FOUND; - } - - HRESULT hr = NOERROR; - // AddRef() returned pointer - but GetPin could fail if memory is low. - if (*ppPin) { - (*ppPin)->AddRef(); - } else { - hr = E_OUTOFMEMORY; // probably. There's no pin anyway. - } - return hr; -} - - -// override these two functions if you want to inform something -// about entry to or exit from streaming state. - -HRESULT -CTransformFilter::StartStreaming() -{ - return NOERROR; -} - - -HRESULT -CTransformFilter::StopStreaming() -{ - return NOERROR; -} - - -// override this to grab extra interfaces on connection - -HRESULT -CTransformFilter::CheckConnect(PIN_DIRECTION dir,IPin *pPin) -{ - UNREFERENCED_PARAMETER(dir); - UNREFERENCED_PARAMETER(pPin); - return NOERROR; -} - - -// place holder to allow derived classes to release any extra interfaces - -HRESULT -CTransformFilter::BreakConnect(PIN_DIRECTION dir) -{ - UNREFERENCED_PARAMETER(dir); - return NOERROR; -} - - -// Let derived classes know about connection completion - -HRESULT -CTransformFilter::CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin) -{ - UNREFERENCED_PARAMETER(direction); - UNREFERENCED_PARAMETER(pReceivePin); - return NOERROR; -} - - -// override this to know when the media type is really set - -HRESULT -CTransformFilter::SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt) -{ - UNREFERENCED_PARAMETER(direction); - UNREFERENCED_PARAMETER(pmt); - return NOERROR; -} - - -// Set up our output sample -HRESULT -CTransformFilter::InitializeOutputSample(IMediaSample *pSample, IMediaSample **ppOutSample) -{ - IMediaSample *pOutSample; - - // default - times are the same - - AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); - DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0; - - // This will prevent the image renderer from switching us to DirectDraw - // when we can't do it without skipping frames because we're not on a - // keyframe. If it really has to switch us, it still will, but then we - // will have to wait for the next keyframe - if (!(pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT)) { - dwFlags |= AM_GBF_NOTASYNCPOINT; - } - - ASSERT(m_pOutput->m_pAllocator != NULL); - HRESULT hr = m_pOutput->m_pAllocator->GetBuffer( - &pOutSample - , pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID ? - &pProps->tStart : NULL - , pProps->dwSampleFlags & AM_SAMPLE_STOPVALID ? - &pProps->tStop : NULL - , dwFlags - ); - *ppOutSample = pOutSample; - if (FAILED(hr)) { - return hr; - } - - ASSERT(pOutSample); - IMediaSample2 *pOutSample2; - if (SUCCEEDED(pOutSample->QueryInterface(IID_IMediaSample2, - (void **)&pOutSample2))) { - /* Modify it */ - AM_SAMPLE2_PROPERTIES OutProps; - EXECUTE_ASSERT(SUCCEEDED(pOutSample2->GetProperties( - FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&OutProps) - )); - OutProps.dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; - OutProps.dwSampleFlags = - (OutProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED) | - (pProps->dwSampleFlags & ~AM_SAMPLE_TYPECHANGED); - OutProps.tStart = pProps->tStart; - OutProps.tStop = pProps->tStop; - OutProps.cbData = FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId); - hr = pOutSample2->SetProperties( - FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId), - (PBYTE)&OutProps - ); - if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { - m_bSampleSkipped = FALSE; - } - pOutSample2->Release(); - } else { - if (pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) { - pOutSample->SetTime(&pProps->tStart, - &pProps->tStop); - } - if (pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT) { - pOutSample->SetSyncPoint(TRUE); - } - if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { - pOutSample->SetDiscontinuity(TRUE); - m_bSampleSkipped = FALSE; - } - // Copy the media times - - LONGLONG MediaStart, MediaEnd; - if (pSample->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) { - pOutSample->SetMediaTime(&MediaStart,&MediaEnd); - } - } - return S_OK; -} - -// override this to customize the transform process - -HRESULT -CTransformFilter::Receive(IMediaSample *pSample) -{ - /* Check for other streams and pass them on */ - AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); - if (pProps->dwStreamId != AM_STREAM_MEDIA) { - return m_pOutput->m_pInputPin->Receive(pSample); - } - HRESULT hr; - ASSERT(pSample); - IMediaSample * pOutSample; - - // If no output to deliver to then no point sending us data - - ASSERT (m_pOutput != NULL) ; - - // Set up the output sample - hr = InitializeOutputSample(pSample, &pOutSample); - - if (FAILED(hr)) { - return hr; - } - - // Start timing the transform (if PERF is defined) - MSR_START(m_idTransform); - - // have the derived class transform the data - - hr = Transform(pSample, pOutSample); - - // Stop the clock and log it (if PERF is defined) - MSR_STOP(m_idTransform); - - if (FAILED(hr)) { - DbgLog((LOG_TRACE,1,TEXT("Error from transform"))); - } else { - // the Transform() function can return S_FALSE to indicate that the - // sample should not be delivered; we only deliver the sample if it's - // really S_OK (same as NOERROR, of course.) - if (hr == NOERROR) { - hr = m_pOutput->m_pInputPin->Receive(pOutSample); - m_bSampleSkipped = FALSE; // last thing no longer dropped - } else { - // S_FALSE returned from Transform is a PRIVATE agreement - // We should return NOERROR from Receive() in this cause because returning S_FALSE - // from Receive() means that this is the end of the stream and no more data should - // be sent. - if (S_FALSE == hr) { - - // Release the sample before calling notify to avoid - // deadlocks if the sample holds a lock on the system - // such as DirectDraw buffers do - pOutSample->Release(); - m_bSampleSkipped = TRUE; - if (!m_bQualityChanged) { - NotifyEvent(EC_QUALITY_CHANGE,0,0); - m_bQualityChanged = TRUE; - } - return NOERROR; - } - } - } - - // release the output buffer. If the connected pin still needs it, - // it will have addrefed it itself. - pOutSample->Release(); - - return hr; -} - - -// Return S_FALSE to mean "pass the note on upstream" -// Return NOERROR (Same as S_OK) -// to mean "I've done something about it, don't pass it on" -HRESULT CTransformFilter::AlterQuality(Quality q) -{ - UNREFERENCED_PARAMETER(q); - return S_FALSE; -} - - -// EndOfStream received. Default behaviour is to deliver straight -// downstream, since we have no queued data. If you overrode Receive -// and have queue data, then you need to handle this and deliver EOS after -// all queued data is sent -HRESULT -CTransformFilter::EndOfStream(void) -{ - HRESULT hr = NOERROR; - if (m_pOutput != NULL) { - hr = m_pOutput->DeliverEndOfStream(); - } - - return hr; -} - - -// enter flush state. Receives already blocked -// must override this if you have queued data or a worker thread -HRESULT -CTransformFilter::BeginFlush(void) -{ - HRESULT hr = NOERROR; - if (m_pOutput != NULL) { - // block receives -- done by caller (CBaseInputPin::BeginFlush) - - // discard queued data -- we have no queued data - - // free anyone blocked on receive - not possible in this filter - - // call downstream - hr = m_pOutput->DeliverBeginFlush(); - } - return hr; -} - - -// leave flush state. must override this if you have queued data -// or a worker thread -HRESULT -CTransformFilter::EndFlush(void) -{ - // sync with pushing thread -- we have no worker thread - - // ensure no more data to go downstream -- we have no queued data - - // call EndFlush on downstream pins - ASSERT (m_pOutput != NULL); - return m_pOutput->DeliverEndFlush(); - - // caller (the input pin's method) will unblock Receives -} - - -// override these so that the derived filter can catch them - -STDMETHODIMP -CTransformFilter::Stop() -{ - CAutoLock lck1(&m_csFilter); - if (m_State == State_Stopped) { - return NOERROR; - } - - // Succeed the Stop if we are not completely connected - - ASSERT(m_pInput == NULL || m_pOutput != NULL); - if (m_pInput == NULL || m_pInput->IsConnected() == FALSE || - m_pOutput->IsConnected() == FALSE) { - m_State = State_Stopped; - m_bEOSDelivered = FALSE; - return NOERROR; - } - - ASSERT(m_pInput); - ASSERT(m_pOutput); - - // decommit the input pin before locking or we can deadlock - m_pInput->Inactive(); - - // synchronize with Receive calls - - CAutoLock lck2(&m_csReceive); - m_pOutput->Inactive(); - - // allow a class derived from CTransformFilter - // to know about starting and stopping streaming - - HRESULT hr = StopStreaming(); - if (SUCCEEDED(hr)) { - // complete the state transition - m_State = State_Stopped; - m_bEOSDelivered = FALSE; - } - return hr; -} - - -STDMETHODIMP -CTransformFilter::Pause() -{ - CAutoLock lck(&m_csFilter); - HRESULT hr = NOERROR; - - if (m_State == State_Paused) { - // (This space left deliberately blank) - } - - // If we have no input pin or it isn't yet connected then when we are - // asked to pause we deliver an end of stream to the downstream filter. - // This makes sure that it doesn't sit there forever waiting for - // samples which we cannot ever deliver without an input connection. - - else if (m_pInput == NULL || m_pInput->IsConnected() == FALSE) { - if (m_pOutput && m_bEOSDelivered == FALSE) { - m_pOutput->DeliverEndOfStream(); - m_bEOSDelivered = TRUE; - } - m_State = State_Paused; - } - - // We may have an input connection but no output connection - // However, if we have an input pin we do have an output pin - - else if (m_pOutput->IsConnected() == FALSE) { - m_State = State_Paused; - } - - else { - if (m_State == State_Stopped) { - // allow a class derived from CTransformFilter - // to know about starting and stopping streaming - CAutoLock lck2(&m_csReceive); - hr = StartStreaming(); - } - if (SUCCEEDED(hr)) { - hr = CBaseFilter::Pause(); - } - } - - m_bSampleSkipped = FALSE; - m_bQualityChanged = FALSE; - return hr; -} - -HRESULT -CTransformFilter::NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate) -{ - if (m_pOutput != NULL) { - return m_pOutput->DeliverNewSegment(tStart, tStop, dRate); - } - return S_OK; -} - -// Check streaming status -HRESULT -CTransformInputPin::CheckStreaming() -{ - ASSERT(m_pTransformFilter->m_pOutput != NULL); - if (!m_pTransformFilter->m_pOutput->IsConnected()) { - return VFW_E_NOT_CONNECTED; - } else { - // Shouldn't be able to get any data if we're not connected! - ASSERT(IsConnected()); - - // we're flushing - if (m_bFlushing) { - return S_FALSE; - } - // Don't process stuff in Stopped state - if (IsStopped()) { - return VFW_E_WRONG_STATE; - } - if (m_bRunTimeError) { - return VFW_E_RUNTIME_ERROR; - } - return S_OK; - } -} - - -// ================================================================= -// Implements the CTransformInputPin class -// ================================================================= - - -// constructor - -CTransformInputPin::CTransformInputPin( - TCHAR *pObjectName, - CTransformFilter *pTransformFilter, - HRESULT * phr, - LPCWSTR pName) - : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName) -{ - DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin"))); - m_pTransformFilter = pTransformFilter; -} - -#ifdef UNICODE -CTransformInputPin::CTransformInputPin( - CHAR *pObjectName, - CTransformFilter *pTransformFilter, - HRESULT * phr, - LPCWSTR pName) - : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName) -{ - DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin"))); - m_pTransformFilter = pTransformFilter; -} -#endif - -// provides derived filter a chance to grab extra interfaces - -HRESULT -CTransformInputPin::CheckConnect(IPin *pPin) -{ - HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_INPUT,pPin); - if (FAILED(hr)) { - return hr; - } - return CBaseInputPin::CheckConnect(pPin); -} - - -// provides derived filter a chance to release it's extra interfaces - -HRESULT -CTransformInputPin::BreakConnect() -{ - // Can't disconnect unless stopped - ASSERT(IsStopped()); - m_pTransformFilter->BreakConnect(PINDIR_INPUT); - return CBaseInputPin::BreakConnect(); -} - - -// Let derived class know when the input pin is connected - -HRESULT -CTransformInputPin::CompleteConnect(IPin *pReceivePin) -{ - HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin); - if (FAILED(hr)) { - return hr; - } - return CBaseInputPin::CompleteConnect(pReceivePin); -} - - -// check that we can support a given media type - -HRESULT -CTransformInputPin::CheckMediaType(const CMediaType* pmt) -{ - // Check the input type - - HRESULT hr = m_pTransformFilter->CheckInputType(pmt); - if (S_OK != hr) { - return hr; - } - - // if the output pin is still connected, then we have - // to check the transform not just the input format - - if ((m_pTransformFilter->m_pOutput != NULL) && - (m_pTransformFilter->m_pOutput->IsConnected())) { - return m_pTransformFilter->CheckTransform( - pmt, - &m_pTransformFilter->m_pOutput->CurrentMediaType()); - } else { - return hr; - } -} - - -// set the media type for this connection - -HRESULT -CTransformInputPin::SetMediaType(const CMediaType* mtIn) -{ - // Set the base class media type (should always succeed) - HRESULT hr = CBasePin::SetMediaType(mtIn); - if (FAILED(hr)) { - return hr; - } - - // check the transform can be done (should always succeed) - ASSERT(SUCCEEDED(m_pTransformFilter->CheckInputType(mtIn))); - - return m_pTransformFilter->SetMediaType(PINDIR_INPUT,mtIn); -} - - -// ================================================================= -// Implements IMemInputPin interface -// ================================================================= - - -// provide EndOfStream that passes straight downstream -// (there is no queued data) -STDMETHODIMP -CTransformInputPin::EndOfStream(void) -{ - CAutoLock lck(&m_pTransformFilter->m_csReceive); - HRESULT hr = CheckStreaming(); - if (S_OK == hr) { - hr = m_pTransformFilter->EndOfStream(); - } - return hr; -} - - -// enter flushing state. Call default handler to block Receives, then -// pass to overridable method in filter -STDMETHODIMP -CTransformInputPin::BeginFlush(void) -{ - CAutoLock lck(&m_pTransformFilter->m_csFilter); - // Are we actually doing anything? - ASSERT(m_pTransformFilter->m_pOutput != NULL); - if (!IsConnected() || - !m_pTransformFilter->m_pOutput->IsConnected()) { - return VFW_E_NOT_CONNECTED; - } - HRESULT hr = CBaseInputPin::BeginFlush(); - if (FAILED(hr)) { - return hr; - } - - return m_pTransformFilter->BeginFlush(); -} - - -// leave flushing state. -// Pass to overridable method in filter, then call base class -// to unblock receives (finally) -STDMETHODIMP -CTransformInputPin::EndFlush(void) -{ - CAutoLock lck(&m_pTransformFilter->m_csFilter); - // Are we actually doing anything? - ASSERT(m_pTransformFilter->m_pOutput != NULL); - if (!IsConnected() || - !m_pTransformFilter->m_pOutput->IsConnected()) { - return VFW_E_NOT_CONNECTED; - } - - HRESULT hr = m_pTransformFilter->EndFlush(); - if (FAILED(hr)) { - return hr; - } - - return CBaseInputPin::EndFlush(); -} - - -// here's the next block of data from the stream. -// AddRef it yourself if you need to hold it beyond the end -// of this call. - -HRESULT -CTransformInputPin::Receive(IMediaSample * pSample) -{ - HRESULT hr; - CAutoLock lck(&m_pTransformFilter->m_csReceive); - ASSERT(pSample); - - // check all is well with the base class - hr = CBaseInputPin::Receive(pSample); - if (S_OK == hr) { - hr = m_pTransformFilter->Receive(pSample); - } - return hr; -} - - - - -// override to pass downstream -STDMETHODIMP -CTransformInputPin::NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate) -{ - // Save the values in the pin - CBasePin::NewSegment(tStart, tStop, dRate); - return m_pTransformFilter->NewSegment(tStart, tStop, dRate); -} - - - - -// ================================================================= -// Implements the CTransformOutputPin class -// ================================================================= - - -// constructor - -CTransformOutputPin::CTransformOutputPin( - TCHAR *pObjectName, - CTransformFilter *pTransformFilter, - HRESULT * phr, - LPCWSTR pPinName) - : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName), - m_pPosition(NULL) -{ - DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin"))); - m_pTransformFilter = pTransformFilter; - -} - -#ifdef UNICODE -CTransformOutputPin::CTransformOutputPin( - CHAR *pObjectName, - CTransformFilter *pTransformFilter, - HRESULT * phr, - LPCWSTR pPinName) - : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName), - m_pPosition(NULL) -{ - DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin"))); - m_pTransformFilter = pTransformFilter; - -} -#endif - -// destructor - -CTransformOutputPin::~CTransformOutputPin() -{ - DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::~CTransformOutputPin"))); - - if (m_pPosition) m_pPosition->Release(); -} - - -// overriden to expose IMediaPosition and IMediaSeeking control interfaces - -STDMETHODIMP -CTransformOutputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv) -{ - CheckPointer(ppv,E_POINTER); - ValidateReadWritePtr(ppv,sizeof(PVOID)); - *ppv = NULL; - - if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { - - // we should have an input pin by now - - ASSERT(m_pTransformFilter->m_pInput != NULL); - - if (m_pPosition == NULL) { - - HRESULT hr = CreatePosPassThru( - GetOwner(), - FALSE, - (IPin *)m_pTransformFilter->m_pInput, - &m_pPosition); - if (FAILED(hr)) { - return hr; - } - } - return m_pPosition->QueryInterface(riid, ppv); - } else { - return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv); - } -} - - -// provides derived filter a chance to grab extra interfaces - -HRESULT -CTransformOutputPin::CheckConnect(IPin *pPin) -{ - // we should have an input connection first - - ASSERT(m_pTransformFilter->m_pInput != NULL); - if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) { - return E_UNEXPECTED; - } - - HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_OUTPUT,pPin); - if (FAILED(hr)) { - return hr; - } - return CBaseOutputPin::CheckConnect(pPin); -} - - -// provides derived filter a chance to release it's extra interfaces - -HRESULT -CTransformOutputPin::BreakConnect() -{ - // Can't disconnect unless stopped - ASSERT(IsStopped()); - m_pTransformFilter->BreakConnect(PINDIR_OUTPUT); - return CBaseOutputPin::BreakConnect(); -} - - -// Let derived class know when the output pin is connected - -HRESULT -CTransformOutputPin::CompleteConnect(IPin *pReceivePin) -{ - HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin); - if (FAILED(hr)) { - return hr; - } - return CBaseOutputPin::CompleteConnect(pReceivePin); -} - - -// check a given transform - must have selected input type first - -HRESULT -CTransformOutputPin::CheckMediaType(const CMediaType* pmtOut) -{ - // must have selected input first - ASSERT(m_pTransformFilter->m_pInput != NULL); - if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) { - return E_INVALIDARG; - } - - return m_pTransformFilter->CheckTransform( - &m_pTransformFilter->m_pInput->CurrentMediaType(), - pmtOut); -} - - -// called after we have agreed a media type to actually set it in which case -// we run the CheckTransform function to get the output format type again - -HRESULT -CTransformOutputPin::SetMediaType(const CMediaType* pmtOut) -{ - HRESULT hr = NOERROR; - ASSERT(m_pTransformFilter->m_pInput != NULL); - - ASSERT(m_pTransformFilter->m_pInput->CurrentMediaType().IsValid()); - - // Set the base class media type (should always succeed) - hr = CBasePin::SetMediaType(pmtOut); - if (FAILED(hr)) { - return hr; - } - -#ifdef DEBUG - if (FAILED(m_pTransformFilter->CheckTransform(&m_pTransformFilter-> - m_pInput->CurrentMediaType(),pmtOut))) { - DbgLog((LOG_ERROR,0,TEXT("*** This filter is accepting an output media type"))); - DbgLog((LOG_ERROR,0,TEXT(" that it can't currently transform to. I hope"))); - DbgLog((LOG_ERROR,0,TEXT(" it's smart enough to reconnect its input."))); - } -#endif - - return m_pTransformFilter->SetMediaType(PINDIR_OUTPUT,pmtOut); -} - - -// pass the buffer size decision through to the main transform class - -HRESULT -CTransformOutputPin::DecideBufferSize( - IMemAllocator * pAllocator, - ALLOCATOR_PROPERTIES* pProp) -{ - return m_pTransformFilter->DecideBufferSize(pAllocator, pProp); -} - - - -// return a specific media type indexed by iPosition - -HRESULT -CTransformOutputPin::GetMediaType( - int iPosition, - CMediaType *pMediaType) -{ - ASSERT(m_pTransformFilter->m_pInput != NULL); - - // We don't have any media types if our input is not connected - - if (m_pTransformFilter->m_pInput->IsConnected()) { - return m_pTransformFilter->GetMediaType(iPosition,pMediaType); - } else { - return VFW_S_NO_MORE_ITEMS; - } -} - - -// Override this if you can do something constructive to act on the -// quality message. Consider passing it upstream as well - -// Pass the quality mesage on upstream. - -STDMETHODIMP -CTransformOutputPin::Notify(IBaseFilter * pSender, Quality q) -{ - UNREFERENCED_PARAMETER(pSender); - ValidateReadPtr(pSender,sizeof(IBaseFilter)); - - // First see if we want to handle this ourselves - HRESULT hr = m_pTransformFilter->AlterQuality(q); - if (hr!=S_FALSE) { - return hr; // either S_OK or a failure - } - - // S_FALSE means we pass the message on. - // Find the quality sink for our input pin and send it there - - ASSERT(m_pTransformFilter->m_pInput != NULL); - - return m_pTransformFilter->m_pInput->PassNotify(q); - -} // Notify - - -// the following removes a very large number of level 4 warnings from the microsoft -// compiler output, which are not useful at all in this case. -#pragma warning(disable:4514) +//------------------------------------------------------------------------------ +// File: Transfrm.cpp +// +// Desc: DirectShow base classes - implements class for simple transform +// filters such as video decompressors. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include "measure.h" + + +// ================================================================= +// Implements the CTransformFilter class +// ================================================================= + +CTransformFilter::CTransformFilter(TCHAR *pName, + LPUNKNOWN pUnk, + REFCLSID clsid) : + CBaseFilter(pName,pUnk,&m_csFilter, clsid), + m_pInput(NULL), + m_pOutput(NULL), + m_bEOSDelivered(FALSE), + m_bQualityChanged(FALSE), + m_bSampleSkipped(FALSE) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF +} + +#ifdef UNICODE +CTransformFilter::CTransformFilter(char *pName, + LPUNKNOWN pUnk, + REFCLSID clsid) : + CBaseFilter(pName,pUnk,&m_csFilter, clsid), + m_pInput(NULL), + m_pOutput(NULL), + m_bEOSDelivered(FALSE), + m_bQualityChanged(FALSE), + m_bSampleSkipped(FALSE) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF +} +#endif + +// destructor + +CTransformFilter::~CTransformFilter() +{ + // Delete the pins + + delete m_pInput; + delete m_pOutput; +} + + +// Transform place holder - should never be called +HRESULT CTransformFilter::Transform(IMediaSample * pIn, IMediaSample *pOut) +{ + UNREFERENCED_PARAMETER(pIn); + UNREFERENCED_PARAMETER(pOut); + DbgBreak("CTransformFilter::Transform() should never be called"); + return E_UNEXPECTED; +} + + +// return the number of pins we provide + +int CTransformFilter::GetPinCount() +{ + return 2; +} + + +// return a non-addrefed CBasePin * for the user to addref if he holds onto it +// for longer than his pointer to us. We create the pins dynamically when they +// are asked for rather than in the constructor. This is because we want to +// give the derived class an oppportunity to return different pin objects + +// We return the objects as and when they are needed. If either of these fails +// then we return NULL, the assumption being that the caller will realise the +// whole deal is off and destroy us - which in turn will delete everything. + +CBasePin * +CTransformFilter::GetPin(int n) +{ + HRESULT hr = S_OK; + + // Create an input pin if necessary + + if (m_pInput == NULL) { + + m_pInput = new CTransformInputPin(NAME("Transform input pin"), + this, // Owner filter + &hr, // Result code + L"XForm In"); // Pin name + + + // Can't fail + ASSERT(SUCCEEDED(hr)); + if (m_pInput == NULL) { + return NULL; + } + m_pOutput = (CTransformOutputPin *) + new CTransformOutputPin(NAME("Transform output pin"), + this, // Owner filter + &hr, // Result code + L"XForm Out"); // Pin name + + + // Can't fail + ASSERT(SUCCEEDED(hr)); + if (m_pOutput == NULL) { + delete m_pInput; + m_pInput = NULL; + } + } + + // Return the appropriate pin + + if (n == 0) { + return m_pInput; + } else + if (n == 1) { + return m_pOutput; + } else { + return NULL; + } +} + + +// +// FindPin +// +// If Id is In or Out then return the IPin* for that pin +// creating the pin if need be. Otherwise return NULL with an error. + +STDMETHODIMP CTransformFilter::FindPin(LPCWSTR Id, IPin **ppPin) +{ + CheckPointer(ppPin,E_POINTER); + ValidateReadWritePtr(ppPin,sizeof(IPin *)); + + if (0==lstrcmpW(Id,L"In")) { + *ppPin = GetPin(0); + } else if (0==lstrcmpW(Id,L"Out")) { + *ppPin = GetPin(1); + } else { + *ppPin = NULL; + return VFW_E_NOT_FOUND; + } + + HRESULT hr = NOERROR; + // AddRef() returned pointer - but GetPin could fail if memory is low. + if (*ppPin) { + (*ppPin)->AddRef(); + } else { + hr = E_OUTOFMEMORY; // probably. There's no pin anyway. + } + return hr; +} + + +// override these two functions if you want to inform something +// about entry to or exit from streaming state. + +HRESULT +CTransformFilter::StartStreaming() +{ + return NOERROR; +} + + +HRESULT +CTransformFilter::StopStreaming() +{ + return NOERROR; +} + + +// override this to grab extra interfaces on connection + +HRESULT +CTransformFilter::CheckConnect(PIN_DIRECTION dir,IPin *pPin) +{ + UNREFERENCED_PARAMETER(dir); + UNREFERENCED_PARAMETER(pPin); + return NOERROR; +} + + +// place holder to allow derived classes to release any extra interfaces + +HRESULT +CTransformFilter::BreakConnect(PIN_DIRECTION dir) +{ + UNREFERENCED_PARAMETER(dir); + return NOERROR; +} + + +// Let derived classes know about connection completion + +HRESULT +CTransformFilter::CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin) +{ + UNREFERENCED_PARAMETER(direction); + UNREFERENCED_PARAMETER(pReceivePin); + return NOERROR; +} + + +// override this to know when the media type is really set + +HRESULT +CTransformFilter::SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt) +{ + UNREFERENCED_PARAMETER(direction); + UNREFERENCED_PARAMETER(pmt); + return NOERROR; +} + + +// Set up our output sample +HRESULT +CTransformFilter::InitializeOutputSample(IMediaSample *pSample, IMediaSample **ppOutSample) +{ + IMediaSample *pOutSample; + + // default - times are the same + + AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); + DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0; + + // This will prevent the image renderer from switching us to DirectDraw + // when we can't do it without skipping frames because we're not on a + // keyframe. If it really has to switch us, it still will, but then we + // will have to wait for the next keyframe + if (!(pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT)) { + dwFlags |= AM_GBF_NOTASYNCPOINT; + } + + ASSERT(m_pOutput->m_pAllocator != NULL); + HRESULT hr = m_pOutput->m_pAllocator->GetBuffer( + &pOutSample + , pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID ? + &pProps->tStart : NULL + , pProps->dwSampleFlags & AM_SAMPLE_STOPVALID ? + &pProps->tStop : NULL + , dwFlags + ); + *ppOutSample = pOutSample; + if (FAILED(hr)) { + return hr; + } + + ASSERT(pOutSample); + IMediaSample2 *pOutSample2; + if (SUCCEEDED(pOutSample->QueryInterface(IID_IMediaSample2, + (void **)&pOutSample2))) { + /* Modify it */ + AM_SAMPLE2_PROPERTIES OutProps; + EXECUTE_ASSERT(SUCCEEDED(pOutSample2->GetProperties( + FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&OutProps) + )); + OutProps.dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; + OutProps.dwSampleFlags = + (OutProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED) | + (pProps->dwSampleFlags & ~AM_SAMPLE_TYPECHANGED); + OutProps.tStart = pProps->tStart; + OutProps.tStop = pProps->tStop; + OutProps.cbData = FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId); + hr = pOutSample2->SetProperties( + FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId), + (PBYTE)&OutProps + ); + if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { + m_bSampleSkipped = FALSE; + } + pOutSample2->Release(); + } else { + if (pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) { + pOutSample->SetTime(&pProps->tStart, + &pProps->tStop); + } + if (pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT) { + pOutSample->SetSyncPoint(TRUE); + } + if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { + pOutSample->SetDiscontinuity(TRUE); + m_bSampleSkipped = FALSE; + } + // Copy the media times + + LONGLONG MediaStart, MediaEnd; + if (pSample->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) { + pOutSample->SetMediaTime(&MediaStart,&MediaEnd); + } + } + return S_OK; +} + +// override this to customize the transform process + +HRESULT +CTransformFilter::Receive(IMediaSample *pSample) +{ + /* Check for other streams and pass them on */ + AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); + if (pProps->dwStreamId != AM_STREAM_MEDIA) { + return m_pOutput->m_pInputPin->Receive(pSample); + } + HRESULT hr; + ASSERT(pSample); + IMediaSample * pOutSample; + + // If no output to deliver to then no point sending us data + + ASSERT (m_pOutput != NULL) ; + + // Set up the output sample + hr = InitializeOutputSample(pSample, &pOutSample); + + if (FAILED(hr)) { + return hr; + } + + // Start timing the transform (if PERF is defined) + MSR_START(m_idTransform); + + // have the derived class transform the data + + hr = Transform(pSample, pOutSample); + + // Stop the clock and log it (if PERF is defined) + MSR_STOP(m_idTransform); + + if (FAILED(hr)) { + DbgLog((LOG_TRACE,1,TEXT("Error from transform"))); + } else { + // the Transform() function can return S_FALSE to indicate that the + // sample should not be delivered; we only deliver the sample if it's + // really S_OK (same as NOERROR, of course.) + if (hr == NOERROR) { + hr = m_pOutput->m_pInputPin->Receive(pOutSample); + m_bSampleSkipped = FALSE; // last thing no longer dropped + } else { + // S_FALSE returned from Transform is a PRIVATE agreement + // We should return NOERROR from Receive() in this cause because returning S_FALSE + // from Receive() means that this is the end of the stream and no more data should + // be sent. + if (S_FALSE == hr) { + + // Release the sample before calling notify to avoid + // deadlocks if the sample holds a lock on the system + // such as DirectDraw buffers do + pOutSample->Release(); + m_bSampleSkipped = TRUE; + if (!m_bQualityChanged) { + NotifyEvent(EC_QUALITY_CHANGE,0,0); + m_bQualityChanged = TRUE; + } + return NOERROR; + } + } + } + + // release the output buffer. If the connected pin still needs it, + // it will have addrefed it itself. + pOutSample->Release(); + + return hr; +} + + +// Return S_FALSE to mean "pass the note on upstream" +// Return NOERROR (Same as S_OK) +// to mean "I've done something about it, don't pass it on" +HRESULT CTransformFilter::AlterQuality(Quality q) +{ + UNREFERENCED_PARAMETER(q); + return S_FALSE; +} + + +// EndOfStream received. Default behaviour is to deliver straight +// downstream, since we have no queued data. If you overrode Receive +// and have queue data, then you need to handle this and deliver EOS after +// all queued data is sent +HRESULT +CTransformFilter::EndOfStream(void) +{ + HRESULT hr = NOERROR; + if (m_pOutput != NULL) { + hr = m_pOutput->DeliverEndOfStream(); + } + + return hr; +} + + +// enter flush state. Receives already blocked +// must override this if you have queued data or a worker thread +HRESULT +CTransformFilter::BeginFlush(void) +{ + HRESULT hr = NOERROR; + if (m_pOutput != NULL) { + // block receives -- done by caller (CBaseInputPin::BeginFlush) + + // discard queued data -- we have no queued data + + // free anyone blocked on receive - not possible in this filter + + // call downstream + hr = m_pOutput->DeliverBeginFlush(); + } + return hr; +} + + +// leave flush state. must override this if you have queued data +// or a worker thread +HRESULT +CTransformFilter::EndFlush(void) +{ + // sync with pushing thread -- we have no worker thread + + // ensure no more data to go downstream -- we have no queued data + + // call EndFlush on downstream pins + ASSERT (m_pOutput != NULL); + return m_pOutput->DeliverEndFlush(); + + // caller (the input pin's method) will unblock Receives +} + + +// override these so that the derived filter can catch them + +STDMETHODIMP +CTransformFilter::Stop() +{ + CAutoLock lck1(&m_csFilter); + if (m_State == State_Stopped) { + return NOERROR; + } + + // Succeed the Stop if we are not completely connected + + ASSERT(m_pInput == NULL || m_pOutput != NULL); + if (m_pInput == NULL || m_pInput->IsConnected() == FALSE || + m_pOutput->IsConnected() == FALSE) { + m_State = State_Stopped; + m_bEOSDelivered = FALSE; + return NOERROR; + } + + ASSERT(m_pInput); + ASSERT(m_pOutput); + + // decommit the input pin before locking or we can deadlock + m_pInput->Inactive(); + + // synchronize with Receive calls + + CAutoLock lck2(&m_csReceive); + m_pOutput->Inactive(); + + // allow a class derived from CTransformFilter + // to know about starting and stopping streaming + + HRESULT hr = StopStreaming(); + if (SUCCEEDED(hr)) { + // complete the state transition + m_State = State_Stopped; + m_bEOSDelivered = FALSE; + } + return hr; +} + + +STDMETHODIMP +CTransformFilter::Pause() +{ + CAutoLock lck(&m_csFilter); + HRESULT hr = NOERROR; + + if (m_State == State_Paused) { + // (This space left deliberately blank) + } + + // If we have no input pin or it isn't yet connected then when we are + // asked to pause we deliver an end of stream to the downstream filter. + // This makes sure that it doesn't sit there forever waiting for + // samples which we cannot ever deliver without an input connection. + + else if (m_pInput == NULL || m_pInput->IsConnected() == FALSE) { + if (m_pOutput && m_bEOSDelivered == FALSE) { + m_pOutput->DeliverEndOfStream(); + m_bEOSDelivered = TRUE; + } + m_State = State_Paused; + } + + // We may have an input connection but no output connection + // However, if we have an input pin we do have an output pin + + else if (m_pOutput->IsConnected() == FALSE) { + m_State = State_Paused; + } + + else { + if (m_State == State_Stopped) { + // allow a class derived from CTransformFilter + // to know about starting and stopping streaming + CAutoLock lck2(&m_csReceive); + hr = StartStreaming(); + } + if (SUCCEEDED(hr)) { + hr = CBaseFilter::Pause(); + } + } + + m_bSampleSkipped = FALSE; + m_bQualityChanged = FALSE; + return hr; +} + +HRESULT +CTransformFilter::NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + if (m_pOutput != NULL) { + return m_pOutput->DeliverNewSegment(tStart, tStop, dRate); + } + return S_OK; +} + +// Check streaming status +HRESULT +CTransformInputPin::CheckStreaming() +{ + ASSERT(m_pTransformFilter->m_pOutput != NULL); + if (!m_pTransformFilter->m_pOutput->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } else { + // Shouldn't be able to get any data if we're not connected! + ASSERT(IsConnected()); + + // we're flushing + if (m_bFlushing) { + return S_FALSE; + } + // Don't process stuff in Stopped state + if (IsStopped()) { + return VFW_E_WRONG_STATE; + } + if (m_bRunTimeError) { + return VFW_E_RUNTIME_ERROR; + } + return S_OK; + } +} + + +// ================================================================= +// Implements the CTransformInputPin class +// ================================================================= + + +// constructor + +CTransformInputPin::CTransformInputPin( + TCHAR *pObjectName, + CTransformFilter *pTransformFilter, + HRESULT * phr, + LPCWSTR pName) + : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName) +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin"))); + m_pTransformFilter = pTransformFilter; +} + +#ifdef UNICODE +CTransformInputPin::CTransformInputPin( + CHAR *pObjectName, + CTransformFilter *pTransformFilter, + HRESULT * phr, + LPCWSTR pName) + : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName) +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin"))); + m_pTransformFilter = pTransformFilter; +} +#endif + +// provides derived filter a chance to grab extra interfaces + +HRESULT +CTransformInputPin::CheckConnect(IPin *pPin) +{ + HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_INPUT,pPin); + if (FAILED(hr)) { + return hr; + } + return CBaseInputPin::CheckConnect(pPin); +} + + +// provides derived filter a chance to release it's extra interfaces + +HRESULT +CTransformInputPin::BreakConnect() +{ + // Can't disconnect unless stopped + ASSERT(IsStopped()); + m_pTransformFilter->BreakConnect(PINDIR_INPUT); + return CBaseInputPin::BreakConnect(); +} + + +// Let derived class know when the input pin is connected + +HRESULT +CTransformInputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin); + if (FAILED(hr)) { + return hr; + } + return CBaseInputPin::CompleteConnect(pReceivePin); +} + + +// check that we can support a given media type + +HRESULT +CTransformInputPin::CheckMediaType(const CMediaType* pmt) +{ + // Check the input type + + HRESULT hr = m_pTransformFilter->CheckInputType(pmt); + if (S_OK != hr) { + return hr; + } + + // if the output pin is still connected, then we have + // to check the transform not just the input format + + if ((m_pTransformFilter->m_pOutput != NULL) && + (m_pTransformFilter->m_pOutput->IsConnected())) { + return m_pTransformFilter->CheckTransform( + pmt, + &m_pTransformFilter->m_pOutput->CurrentMediaType()); + } else { + return hr; + } +} + + +// set the media type for this connection + +HRESULT +CTransformInputPin::SetMediaType(const CMediaType* mtIn) +{ + // Set the base class media type (should always succeed) + HRESULT hr = CBasePin::SetMediaType(mtIn); + if (FAILED(hr)) { + return hr; + } + + // check the transform can be done (should always succeed) + ASSERT(SUCCEEDED(m_pTransformFilter->CheckInputType(mtIn))); + + return m_pTransformFilter->SetMediaType(PINDIR_INPUT,mtIn); +} + + +// ================================================================= +// Implements IMemInputPin interface +// ================================================================= + + +// provide EndOfStream that passes straight downstream +// (there is no queued data) +STDMETHODIMP +CTransformInputPin::EndOfStream(void) +{ + CAutoLock lck(&m_pTransformFilter->m_csReceive); + HRESULT hr = CheckStreaming(); + if (S_OK == hr) { + hr = m_pTransformFilter->EndOfStream(); + } + return hr; +} + + +// enter flushing state. Call default handler to block Receives, then +// pass to overridable method in filter +STDMETHODIMP +CTransformInputPin::BeginFlush(void) +{ + CAutoLock lck(&m_pTransformFilter->m_csFilter); + // Are we actually doing anything? + ASSERT(m_pTransformFilter->m_pOutput != NULL); + if (!IsConnected() || + !m_pTransformFilter->m_pOutput->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + HRESULT hr = CBaseInputPin::BeginFlush(); + if (FAILED(hr)) { + return hr; + } + + return m_pTransformFilter->BeginFlush(); +} + + +// leave flushing state. +// Pass to overridable method in filter, then call base class +// to unblock receives (finally) +STDMETHODIMP +CTransformInputPin::EndFlush(void) +{ + CAutoLock lck(&m_pTransformFilter->m_csFilter); + // Are we actually doing anything? + ASSERT(m_pTransformFilter->m_pOutput != NULL); + if (!IsConnected() || + !m_pTransformFilter->m_pOutput->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + + HRESULT hr = m_pTransformFilter->EndFlush(); + if (FAILED(hr)) { + return hr; + } + + return CBaseInputPin::EndFlush(); +} + + +// here's the next block of data from the stream. +// AddRef it yourself if you need to hold it beyond the end +// of this call. + +HRESULT +CTransformInputPin::Receive(IMediaSample * pSample) +{ + HRESULT hr; + CAutoLock lck(&m_pTransformFilter->m_csReceive); + ASSERT(pSample); + + // check all is well with the base class + hr = CBaseInputPin::Receive(pSample); + if (S_OK == hr) { + hr = m_pTransformFilter->Receive(pSample); + } + return hr; +} + + + + +// override to pass downstream +STDMETHODIMP +CTransformInputPin::NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + // Save the values in the pin + CBasePin::NewSegment(tStart, tStop, dRate); + return m_pTransformFilter->NewSegment(tStart, tStop, dRate); +} + + + + +// ================================================================= +// Implements the CTransformOutputPin class +// ================================================================= + + +// constructor + +CTransformOutputPin::CTransformOutputPin( + TCHAR *pObjectName, + CTransformFilter *pTransformFilter, + HRESULT * phr, + LPCWSTR pPinName) + : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName), + m_pPosition(NULL) +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin"))); + m_pTransformFilter = pTransformFilter; + +} + +#ifdef UNICODE +CTransformOutputPin::CTransformOutputPin( + CHAR *pObjectName, + CTransformFilter *pTransformFilter, + HRESULT * phr, + LPCWSTR pPinName) + : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName), + m_pPosition(NULL) +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin"))); + m_pTransformFilter = pTransformFilter; + +} +#endif + +// destructor + +CTransformOutputPin::~CTransformOutputPin() +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::~CTransformOutputPin"))); + + if (m_pPosition) m_pPosition->Release(); +} + + +// overriden to expose IMediaPosition and IMediaSeeking control interfaces + +STDMETHODIMP +CTransformOutputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv) +{ + CheckPointer(ppv,E_POINTER); + ValidateReadWritePtr(ppv,sizeof(PVOID)); + *ppv = NULL; + + if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { + + // we should have an input pin by now + + ASSERT(m_pTransformFilter->m_pInput != NULL); + + if (m_pPosition == NULL) { + + HRESULT hr = CreatePosPassThru( + GetOwner(), + FALSE, + (IPin *)m_pTransformFilter->m_pInput, + &m_pPosition); + if (FAILED(hr)) { + return hr; + } + } + return m_pPosition->QueryInterface(riid, ppv); + } else { + return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// provides derived filter a chance to grab extra interfaces + +HRESULT +CTransformOutputPin::CheckConnect(IPin *pPin) +{ + // we should have an input connection first + + ASSERT(m_pTransformFilter->m_pInput != NULL); + if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) { + return E_UNEXPECTED; + } + + HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_OUTPUT,pPin); + if (FAILED(hr)) { + return hr; + } + return CBaseOutputPin::CheckConnect(pPin); +} + + +// provides derived filter a chance to release it's extra interfaces + +HRESULT +CTransformOutputPin::BreakConnect() +{ + // Can't disconnect unless stopped + ASSERT(IsStopped()); + m_pTransformFilter->BreakConnect(PINDIR_OUTPUT); + return CBaseOutputPin::BreakConnect(); +} + + +// Let derived class know when the output pin is connected + +HRESULT +CTransformOutputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin); + if (FAILED(hr)) { + return hr; + } + return CBaseOutputPin::CompleteConnect(pReceivePin); +} + + +// check a given transform - must have selected input type first + +HRESULT +CTransformOutputPin::CheckMediaType(const CMediaType* pmtOut) +{ + // must have selected input first + ASSERT(m_pTransformFilter->m_pInput != NULL); + if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) { + return E_INVALIDARG; + } + + return m_pTransformFilter->CheckTransform( + &m_pTransformFilter->m_pInput->CurrentMediaType(), + pmtOut); +} + + +// called after we have agreed a media type to actually set it in which case +// we run the CheckTransform function to get the output format type again + +HRESULT +CTransformOutputPin::SetMediaType(const CMediaType* pmtOut) +{ + HRESULT hr = NOERROR; + ASSERT(m_pTransformFilter->m_pInput != NULL); + + ASSERT(m_pTransformFilter->m_pInput->CurrentMediaType().IsValid()); + + // Set the base class media type (should always succeed) + hr = CBasePin::SetMediaType(pmtOut); + if (FAILED(hr)) { + return hr; + } + +#ifdef DEBUG + if (FAILED(m_pTransformFilter->CheckTransform(&m_pTransformFilter-> + m_pInput->CurrentMediaType(),pmtOut))) { + DbgLog((LOG_ERROR,0,TEXT("*** This filter is accepting an output media type"))); + DbgLog((LOG_ERROR,0,TEXT(" that it can't currently transform to. I hope"))); + DbgLog((LOG_ERROR,0,TEXT(" it's smart enough to reconnect its input."))); + } +#endif + + return m_pTransformFilter->SetMediaType(PINDIR_OUTPUT,pmtOut); +} + + +// pass the buffer size decision through to the main transform class + +HRESULT +CTransformOutputPin::DecideBufferSize( + IMemAllocator * pAllocator, + ALLOCATOR_PROPERTIES* pProp) +{ + return m_pTransformFilter->DecideBufferSize(pAllocator, pProp); +} + + + +// return a specific media type indexed by iPosition + +HRESULT +CTransformOutputPin::GetMediaType( + int iPosition, + CMediaType *pMediaType) +{ + ASSERT(m_pTransformFilter->m_pInput != NULL); + + // We don't have any media types if our input is not connected + + if (m_pTransformFilter->m_pInput->IsConnected()) { + return m_pTransformFilter->GetMediaType(iPosition,pMediaType); + } else { + return VFW_S_NO_MORE_ITEMS; + } +} + + +// Override this if you can do something constructive to act on the +// quality message. Consider passing it upstream as well + +// Pass the quality mesage on upstream. + +STDMETHODIMP +CTransformOutputPin::Notify(IBaseFilter * pSender, Quality q) +{ + UNREFERENCED_PARAMETER(pSender); + ValidateReadPtr(pSender,sizeof(IBaseFilter)); + + // First see if we want to handle this ourselves + HRESULT hr = m_pTransformFilter->AlterQuality(q); + if (hr!=S_FALSE) { + return hr; // either S_OK or a failure + } + + // S_FALSE means we pass the message on. + // Find the quality sink for our input pin and send it there + + ASSERT(m_pTransformFilter->m_pInput != NULL); + + return m_pTransformFilter->m_pInput->PassNotify(q); + +} // Notify + + +// the following removes a very large number of level 4 warnings from the microsoft +// compiler output, which are not useful at all in this case. +#pragma warning(disable:4514) diff --git a/plugins/GSdx/baseclasses/transfrm.h b/plugins/GSdx/baseclasses/transfrm.h index 55a07dcab5..d4873fa533 100644 --- a/plugins/GSdx/baseclasses/transfrm.h +++ b/plugins/GSdx/baseclasses/transfrm.h @@ -1,304 +1,304 @@ -//------------------------------------------------------------------------------ -// File: Transfrm.h -// -// Desc: DirectShow base classes - defines classes from which simple -// transform codecs may be derived. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// It assumes the codec has one input and one output stream, and has no -// interest in memory management, interface negotiation or anything else. -// -// derive your class from this, and supply Transform and the media type/format -// negotiation functions. Implement that class, compile and link and -// you're done. - - -#ifndef __TRANSFRM__ -#define __TRANSFRM__ - -// ====================================================================== -// This is the com object that represents a simple transform filter. It -// supports IBaseFilter, IMediaFilter and two pins through nested interfaces -// ====================================================================== - -class CTransformFilter; - -// ================================================== -// Implements the input pin -// ================================================== - -class CTransformInputPin : public CBaseInputPin -{ - friend class CTransformFilter; - -protected: - CTransformFilter *m_pTransformFilter; - - -public: - - CTransformInputPin( - TCHAR *pObjectName, - CTransformFilter *pTransformFilter, - HRESULT * phr, - LPCWSTR pName); -#ifdef UNICODE - CTransformInputPin( - char *pObjectName, - CTransformFilter *pTransformFilter, - HRESULT * phr, - LPCWSTR pName); -#endif - - STDMETHODIMP QueryId(LPWSTR * Id) - { - return AMGetWideString(L"In", Id); - } - - // Grab and release extra interfaces if required - - HRESULT CheckConnect(IPin *pPin); - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin *pReceivePin); - - // check that we can support this output type - HRESULT CheckMediaType(const CMediaType* mtIn); - - // set the connection media type - HRESULT SetMediaType(const CMediaType* mt); - - // --- IMemInputPin ----- - - // here's the next block of data from the stream. - // AddRef it yourself if you need to hold it beyond the end - // of this call. - STDMETHODIMP Receive(IMediaSample * pSample); - - // provide EndOfStream that passes straight downstream - // (there is no queued data) - STDMETHODIMP EndOfStream(void); - - // passes it to CTransformFilter::BeginFlush - STDMETHODIMP BeginFlush(void); - - // passes it to CTransformFilter::EndFlush - STDMETHODIMP EndFlush(void); - - STDMETHODIMP NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate); - - // Check if it's OK to process samples - virtual HRESULT CheckStreaming(); - - // Media type -public: - CMediaType& CurrentMediaType() { return m_mt; }; - -}; - -// ================================================== -// Implements the output pin -// ================================================== - -class CTransformOutputPin : public CBaseOutputPin -{ - friend class CTransformFilter; - -protected: - CTransformFilter *m_pTransformFilter; - -public: - - // implement IMediaPosition by passing upstream - IUnknown * m_pPosition; - - CTransformOutputPin( - TCHAR *pObjectName, - CTransformFilter *pTransformFilter, - HRESULT * phr, - LPCWSTR pName); -#ifdef UNICODE - CTransformOutputPin( - CHAR *pObjectName, - CTransformFilter *pTransformFilter, - HRESULT * phr, - LPCWSTR pName); -#endif - ~CTransformOutputPin(); - - // override to expose IMediaPosition - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); - - // --- CBaseOutputPin ------------ - - STDMETHODIMP QueryId(LPWSTR * Id) - { - return AMGetWideString(L"Out", Id); - } - - // Grab and release extra interfaces if required - - HRESULT CheckConnect(IPin *pPin); - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin *pReceivePin); - - // check that we can support this output type - HRESULT CheckMediaType(const CMediaType* mtOut); - - // set the connection media type - HRESULT SetMediaType(const CMediaType *pmt); - - // called from CBaseOutputPin during connection to ask for - // the count and size of buffers we need. - HRESULT DecideBufferSize( - IMemAllocator * pAlloc, - ALLOCATOR_PROPERTIES *pProp); - - // returns the preferred formats for a pin - HRESULT GetMediaType(int iPosition,CMediaType *pMediaType); - - // inherited from IQualityControl via CBasePin - STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); - - // Media type -public: - CMediaType& CurrentMediaType() { return m_mt; }; -}; - - -class AM_NOVTABLE CTransformFilter : public CBaseFilter -{ - -public: - - // map getpin/getpincount for base enum of pins to owner - // override this to return more specialised pin objects - - virtual int GetPinCount(); - virtual CBasePin * GetPin(int n); - STDMETHODIMP FindPin(LPCWSTR Id, IPin **ppPin); - - // override state changes to allow derived transform filter - // to control streaming start/stop - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - -public: - - CTransformFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid); -#ifdef UNICODE - CTransformFilter(CHAR *, LPUNKNOWN, REFCLSID clsid); -#endif - ~CTransformFilter(); - - // ================================================================= - // ----- override these bits --------------------------------------- - // ================================================================= - - // These must be supplied in a derived class - - virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut); - - // check if you can support mtIn - virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE; - - // check if you can support the transform from this input to this output - virtual HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) PURE; - - // this goes in the factory template table to create new instances - // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *); - - // call the SetProperties function with appropriate arguments - virtual HRESULT DecideBufferSize( - IMemAllocator * pAllocator, - ALLOCATOR_PROPERTIES *pprop) PURE; - - // override to suggest OUTPUT pin media types - virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE; - - - - // ================================================================= - // ----- Optional Override Methods ----------------------- - // ================================================================= - - // you can also override these if you want to know about streaming - virtual HRESULT StartStreaming(); - virtual HRESULT StopStreaming(); - - // override if you can do anything constructive with quality notifications - virtual HRESULT AlterQuality(Quality q); - - // override this to know when the media type is actually set - virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt); - - // chance to grab extra interfaces on connection - virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin); - virtual HRESULT BreakConnect(PIN_DIRECTION dir); - virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin); - - // chance to customize the transform process - virtual HRESULT Receive(IMediaSample *pSample); - - // Standard setup for output sample - HRESULT InitializeOutputSample(IMediaSample *pSample, IMediaSample **ppOutSample); - - // if you override Receive, you may need to override these three too - virtual HRESULT EndOfStream(void); - virtual HRESULT BeginFlush(void); - virtual HRESULT EndFlush(void); - virtual HRESULT NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate); - -#ifdef PERF - // Override to register performance measurement with a less generic string - // You should do this to avoid confusion with other filters - virtual void RegisterPerfId() - {m_idTransform = MSR_REGISTER(TEXT("Transform"));} -#endif // PERF - - -// implementation details - -protected: - -#ifdef PERF - int m_idTransform; // performance measuring id -#endif - BOOL m_bEOSDelivered; // have we sent EndOfStream - BOOL m_bSampleSkipped; // Did we just skip a frame - BOOL m_bQualityChanged; // Have we degraded? - - // critical section protecting filter state. - - CCritSec m_csFilter; - - // critical section stopping state changes (ie Stop) while we're - // processing a sample. - // - // This critical section is held when processing - // events that occur on the receive thread - Receive() and EndOfStream(). - // - // If you want to hold both m_csReceive and m_csFilter then grab - // m_csFilter FIRST - like CTransformFilter::Stop() does. - - CCritSec m_csReceive; - - // these hold our input and output pins - - friend class CTransformInputPin; - friend class CTransformOutputPin; - CTransformInputPin *m_pInput; - CTransformOutputPin *m_pOutput; -}; - -#endif /* __TRANSFRM__ */ - - +//------------------------------------------------------------------------------ +// File: Transfrm.h +// +// Desc: DirectShow base classes - defines classes from which simple +// transform codecs may be derived. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// It assumes the codec has one input and one output stream, and has no +// interest in memory management, interface negotiation or anything else. +// +// derive your class from this, and supply Transform and the media type/format +// negotiation functions. Implement that class, compile and link and +// you're done. + + +#ifndef __TRANSFRM__ +#define __TRANSFRM__ + +// ====================================================================== +// This is the com object that represents a simple transform filter. It +// supports IBaseFilter, IMediaFilter and two pins through nested interfaces +// ====================================================================== + +class CTransformFilter; + +// ================================================== +// Implements the input pin +// ================================================== + +class CTransformInputPin : public CBaseInputPin +{ + friend class CTransformFilter; + +protected: + CTransformFilter *m_pTransformFilter; + + +public: + + CTransformInputPin( + TCHAR *pObjectName, + CTransformFilter *pTransformFilter, + HRESULT * phr, + LPCWSTR pName); +#ifdef UNICODE + CTransformInputPin( + char *pObjectName, + CTransformFilter *pTransformFilter, + HRESULT * phr, + LPCWSTR pName); +#endif + + STDMETHODIMP QueryId(LPWSTR * Id) + { + return AMGetWideString(L"In", Id); + } + + // Grab and release extra interfaces if required + + HRESULT CheckConnect(IPin *pPin); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin *pReceivePin); + + // check that we can support this output type + HRESULT CheckMediaType(const CMediaType* mtIn); + + // set the connection media type + HRESULT SetMediaType(const CMediaType* mt); + + // --- IMemInputPin ----- + + // here's the next block of data from the stream. + // AddRef it yourself if you need to hold it beyond the end + // of this call. + STDMETHODIMP Receive(IMediaSample * pSample); + + // provide EndOfStream that passes straight downstream + // (there is no queued data) + STDMETHODIMP EndOfStream(void); + + // passes it to CTransformFilter::BeginFlush + STDMETHODIMP BeginFlush(void); + + // passes it to CTransformFilter::EndFlush + STDMETHODIMP EndFlush(void); + + STDMETHODIMP NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + + // Check if it's OK to process samples + virtual HRESULT CheckStreaming(); + + // Media type +public: + CMediaType& CurrentMediaType() { return m_mt; }; + +}; + +// ================================================== +// Implements the output pin +// ================================================== + +class CTransformOutputPin : public CBaseOutputPin +{ + friend class CTransformFilter; + +protected: + CTransformFilter *m_pTransformFilter; + +public: + + // implement IMediaPosition by passing upstream + IUnknown * m_pPosition; + + CTransformOutputPin( + TCHAR *pObjectName, + CTransformFilter *pTransformFilter, + HRESULT * phr, + LPCWSTR pName); +#ifdef UNICODE + CTransformOutputPin( + CHAR *pObjectName, + CTransformFilter *pTransformFilter, + HRESULT * phr, + LPCWSTR pName); +#endif + ~CTransformOutputPin(); + + // override to expose IMediaPosition + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + // --- CBaseOutputPin ------------ + + STDMETHODIMP QueryId(LPWSTR * Id) + { + return AMGetWideString(L"Out", Id); + } + + // Grab and release extra interfaces if required + + HRESULT CheckConnect(IPin *pPin); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin *pReceivePin); + + // check that we can support this output type + HRESULT CheckMediaType(const CMediaType* mtOut); + + // set the connection media type + HRESULT SetMediaType(const CMediaType *pmt); + + // called from CBaseOutputPin during connection to ask for + // the count and size of buffers we need. + HRESULT DecideBufferSize( + IMemAllocator * pAlloc, + ALLOCATOR_PROPERTIES *pProp); + + // returns the preferred formats for a pin + HRESULT GetMediaType(int iPosition,CMediaType *pMediaType); + + // inherited from IQualityControl via CBasePin + STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); + + // Media type +public: + CMediaType& CurrentMediaType() { return m_mt; }; +}; + + +class AM_NOVTABLE CTransformFilter : public CBaseFilter +{ + +public: + + // map getpin/getpincount for base enum of pins to owner + // override this to return more specialised pin objects + + virtual int GetPinCount(); + virtual CBasePin * GetPin(int n); + STDMETHODIMP FindPin(LPCWSTR Id, IPin **ppPin); + + // override state changes to allow derived transform filter + // to control streaming start/stop + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + +public: + + CTransformFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid); +#ifdef UNICODE + CTransformFilter(CHAR *, LPUNKNOWN, REFCLSID clsid); +#endif + ~CTransformFilter(); + + // ================================================================= + // ----- override these bits --------------------------------------- + // ================================================================= + + // These must be supplied in a derived class + + virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut); + + // check if you can support mtIn + virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE; + + // check if you can support the transform from this input to this output + virtual HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) PURE; + + // this goes in the factory template table to create new instances + // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *); + + // call the SetProperties function with appropriate arguments + virtual HRESULT DecideBufferSize( + IMemAllocator * pAllocator, + ALLOCATOR_PROPERTIES *pprop) PURE; + + // override to suggest OUTPUT pin media types + virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE; + + + + // ================================================================= + // ----- Optional Override Methods ----------------------- + // ================================================================= + + // you can also override these if you want to know about streaming + virtual HRESULT StartStreaming(); + virtual HRESULT StopStreaming(); + + // override if you can do anything constructive with quality notifications + virtual HRESULT AlterQuality(Quality q); + + // override this to know when the media type is actually set + virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt); + + // chance to grab extra interfaces on connection + virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin); + virtual HRESULT BreakConnect(PIN_DIRECTION dir); + virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin); + + // chance to customize the transform process + virtual HRESULT Receive(IMediaSample *pSample); + + // Standard setup for output sample + HRESULT InitializeOutputSample(IMediaSample *pSample, IMediaSample **ppOutSample); + + // if you override Receive, you may need to override these three too + virtual HRESULT EndOfStream(void); + virtual HRESULT BeginFlush(void); + virtual HRESULT EndFlush(void); + virtual HRESULT NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + +#ifdef PERF + // Override to register performance measurement with a less generic string + // You should do this to avoid confusion with other filters + virtual void RegisterPerfId() + {m_idTransform = MSR_REGISTER(TEXT("Transform"));} +#endif // PERF + + +// implementation details + +protected: + +#ifdef PERF + int m_idTransform; // performance measuring id +#endif + BOOL m_bEOSDelivered; // have we sent EndOfStream + BOOL m_bSampleSkipped; // Did we just skip a frame + BOOL m_bQualityChanged; // Have we degraded? + + // critical section protecting filter state. + + CCritSec m_csFilter; + + // critical section stopping state changes (ie Stop) while we're + // processing a sample. + // + // This critical section is held when processing + // events that occur on the receive thread - Receive() and EndOfStream(). + // + // If you want to hold both m_csReceive and m_csFilter then grab + // m_csFilter FIRST - like CTransformFilter::Stop() does. + + CCritSec m_csReceive; + + // these hold our input and output pins + + friend class CTransformInputPin; + friend class CTransformOutputPin; + CTransformInputPin *m_pInput; + CTransformOutputPin *m_pOutput; +}; + +#endif /* __TRANSFRM__ */ + + diff --git a/plugins/GSdx/baseclasses/transip.cpp b/plugins/GSdx/baseclasses/transip.cpp index 43c72f20a8..ff851fca54 100644 --- a/plugins/GSdx/baseclasses/transip.cpp +++ b/plugins/GSdx/baseclasses/transip.cpp @@ -1,966 +1,966 @@ -//------------------------------------------------------------------------------ -// File: TransIP.cpp -// -// Desc: DirectShow base classes - implements class for simple Transform- -// In-Place filters such as audio. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// How allocators are decided. -// -// An in-place transform tries to do its work in someone else's buffers. -// It tries to persuade the filters on either side to use the same allocator -// (and for that matter the same media type). In desperation, if the downstream -// filter refuses to supply an allocator and the upstream filter offers only -// a read-only one then it will provide an allocator. -// if the upstream filter insists on a read-only allocator then the transform -// filter will (reluctantly) copy the data before transforming it. -// -// In order to pass an allocator through it needs to remember the one it got -// from the first connection to pass it on to the second one. -// -// It is good if we can avoid insisting on a particular order of connection -// (There is a precedent for insisting on the input -// being connected first. Insisting on the output being connected first is -// not allowed. That would break RenderFile.) -// -// The base pin classes (CBaseOutputPin and CBaseInputPin) both have a -// m_pAllocator member which is used in places like -// CBaseOutputPin::GetDeliveryBuffer and CBaseInputPin::Inactive. -// To avoid lots of extra overriding, we should keep these happy -// by using these pointers. -// -// When each pin is connected, it will set the corresponding m_pAllocator -// and will have a single ref-count on that allocator. -// -// Refcounts are acquired by GetAllocator calls which return AddReffed -// allocators and are released in one of: -// CBaseInputPin::Disconnect -// CBaseOutputPin::BreakConect -// In each case m_pAllocator is set to NULL after the release, so this -// is the last chance to ever release it. If there should ever be -// multiple refcounts associated with the same pointer, this had better -// be cleared up before that happens. To avoid such problems, we'll -// stick with one per pointer. - - - -// RECONNECTING and STATE CHANGES -// -// Each pin could be disconnected, connected with a read-only allocator, -// connected with an upstream read/write allocator, connected with an -// allocator from downstream or connected with its own allocator. -// Five states for each pin gives a data space of 25 states. -// -// Notation: -// -// R/W == read/write -// R-O == read-only -// -// -// -// 00 means an unconnected pin. -// <- means using a R/W allocator from the upstream filter -// <= means using a R-O allocator from an upstream filter -// || means using our own (R/W) allocator. -// -> means using a R/W allocator from a downstream filter -// (a R-O allocator from downstream is nonsense, it can't ever work). -// -// -// That makes 25 possible states. Some states are nonsense (two different -// allocators from the same place). These are just an artifact of the notation. -// <= <- Nonsense. -// <- <= Nonsense -// Some states are illegal (the output pin never accepts a R-O allocator): -// 00 <= !! Error !! -// <= <= !! Error !! -// || <= !! Error !! -// -> <= !! Error !! -// Three states appears to be inaccessible: -// -> || Inaccessible -// || -> Inaccessible -// || <- Inaccessible -// Some states only ever occur as intermediates with a pending reconnect which -// is guaranteed to finish in another state. -// -> 00 ?? unstable goes to || 00 -// 00 <- ?? unstable goes to 00 || -// -> <- ?? unstable goes to -> -> -// <- || ?? unstable goes to <- <- -// <- -> ?? unstable goes to <- <- -// And that leaves 11 possible resting states: -// 1 00 00 Nothing connected. -// 2 <- 00 Input pin connected. -// 3 <= 00 Input pin connected using R-O allocator. -// 4 || 00 Needs several state changes to get here. -// 5 00 || Output pin connected using our allocator -// 6 00 -> Downstream only connected -// 7 || || Undesirable but can be forced upon us. -// 8 <= || Copy forced. <= -> is preferable -// 9 <= -> OK - forced to copy. -// 10 <- <- Transform in place (ideal) -// 11 -> -> Transform in place (ideal) -// -// The object of the exercise is to ensure that we finish up in states -// 10 or 11 whenever possible. State 10 is only possible if the upstream -// filter has a R/W allocator (the AVI splitter notoriously -// doesn't) and state 11 is only possible if the downstream filter does -// offer an allocator. -// -// The transition table (entries marked * go via a reconnect) -// -// There are 8 possible transitions: -// A: Connect upstream to filter with R-O allocator that insists on using it. -// B: Connect upstream to filter with R-O allocator but chooses not to use it. -// C: Connect upstream to filter with R/W allocator and insists on using it. -// D: Connect upstream to filter with R/W allocator but chooses not to use it. -// E: Connect downstream to a filter that offers an allocator -// F: Connect downstream to a filter that does not offer an allocator -// G: disconnect upstream -// H: Disconnect downstream -// -// A B C D E F G H -// --------------------------------------------------------- -// 00 00 1 | 3 3 2 2 6 5 . . |1 00 00 -// <- 00 2 | . . . . *10/11 10 1 . |2 <- 00 -// <= 00 3 | . . . . *9/11 *7/8 1 . |3 <= 00 -// || 00 4 | . . . . *8 *7 1 . |4 || 00 -// 00 || 5 | 8 7 *10 7 . . . 1 |5 00 || -// 00 -> 6 | 9 11 *10 11 . . . 1 |6 00 -> -// || || 7 | . . . . . . 5 4 |7 || || -// <= || 8 | . . . . . . 5 3 |8 <= || -// <= -> 9 | . . . . . . 6 3 |9 <= -> -// <- <- 10| . . . . . . *5/6 2 |10 <- <- -// -> -> 11| . . . . . . 6 *2/3 |11 -> -> -// --------------------------------------------------------- -// A B C D E F G H -// -// All these states are accessible without requiring any filter to -// change its behaviour but not all transitions are accessible, for -// instance a transition from state 4 to anywhere other than -// state 8 requires that the upstream filter first offer a R-O allocator -// and then changes its mind and offer R/W. This is NOT allowable - it -// leads to things like the output pin getting a R/W allocator from -// upstream and then the input pin being told it can only have a R-O one. -// Note that you CAN change (say) the upstream filter for a different one, but -// only as a disconnect / connect, not as a Reconnect. (Exercise for -// the reader is to see how you get into state 4). -// -// The reconnection stuff goes as follows (some of the cases shown here as -// "no reconnect" may get one to finalise media type - an old story). -// If there is a reconnect where it says "no reconnect" here then the -// reconnection must not change the allocator choice. -// -// state 2: <- 00 transition E <- <- case C <- <- (no change) -// case D -> <- and then to -> -> -// -// state 2: <- 00 transition F <- <- (no reconnect) -// -// state 3: <= 00 transition E <= -> case A <= -> (no change) -// case B -> -> -// transition F <= || case A <= || (no change) -// case B || || -// -// state 4: || 00 transition E || || case B -> || and then all cases to -> -> -// F || || case B || || (no change) -// -// state 5: 00 || transition A <= || (no reconnect) -// B || || (no reconnect) -// C <- || all cases <- <- -// D || || (unfortunate, but upstream's choice) -// -// state 6: 00 -> transition A <= -> (no reconnect) -// B -> -> (no reconnect) -// C <- -> all cases <- <- -// D -> -> (no reconnect) -// -// state 10:<- <- transition G 00 <- case E 00 -> -// case F 00 || -// -// state 11:-> -> transition H -> 00 case A <= 00 (schizo) -// case B <= 00 -// case C <- 00 (schizo) -// case D <- 00 -// -// The Rules: -// To sort out media types: -// The input is reconnected -// if the input pin is connected and the output pin connects -// The output is reconnected -// If the output pin is connected -// and the input pin connects to a different media type -// -// To sort out allocators: -// The input is reconnected -// if the output disconnects and the input was using a downstream allocator -// The output pin calls SetAllocator to pass on a new allocator -// if the output is connected and -// if the input disconnects and the output was using an upstream allocator -// if the input acquires an allocator different from the output one -// and that new allocator is not R-O -// -// Data is copied (i.e. call getbuffer and copy the data before transforming it) -// if the two allocators are different. - - - -// CHAINS of filters: -// -// We sit between two filters (call them A and Z). We should finish up -// with the same allocator on both of our pins and that should be the -// same one that A and Z would have agreed on if we hadn't been in the -// way. Furthermore, it should not matter how many in-place transforms -// are in the way. Let B, C, D... be in-place transforms ("us"). -// Here's how it goes: -// -// 1. -// A connects to B. They agree on A's allocator. -// A-a->B -// -// 2. -// B connects to C. Same story. There is no point in a reconnect, but -// B will request an input reconnect anyway. -// A-a->B-a->C -// -// 3. -// C connects to Z. -// C insists on using A's allocator, but compromises by requesting a reconnect. -// of C's input. -// A-a->B-?->C-a->Z -// -// We now have pending reconnects on both A--->B and B--->C -// -// 4. -// The A--->B link is reconnected. -// A asks B for an allocator. B sees that it has a downstream connection so -// asks its downstream input pin i.e. C's input pin for an allocator. C sees -// that it too has a downstream connection so asks Z for an allocator. -// -// Even though Z's input pin is connected, it is being asked for an allocator. -// It could refuse, in which case the chain is done and will use A's allocator -// Alternatively, Z may supply one. A chooses either Z's or A's own one. -// B's input pin gets NotifyAllocator called to tell it the decision and it -// propagates this downstream by calling ReceiveAllocator on its output pin -// which calls NotifyAllocator on the next input pin downstream etc. -// If the choice is Z then it goes: -// A-z->B-a->C-a->Z -// A-z->B-z->C-a->Z -// A-z->B-z->C-z->Z -// -// And that's IT!! Any further (essentially spurious) reconnects peter out -// with no change in the chain. - -#include "streams.h" -#include "measure.h" -#include "transip.h" - - -// ================================================================= -// Implements the CTransInPlaceFilter class -// ================================================================= - -CTransInPlaceFilter::CTransInPlaceFilter - ( TCHAR *pName, - LPUNKNOWN pUnk, - REFCLSID clsid, - HRESULT *phr, - bool bModifiesData - ) - : CTransformFilter(pName, pUnk, clsid), - m_bModifiesData(bModifiesData) -{ -#ifdef PERF - RegisterPerfId(); -#endif // PERF - -} // constructor - -#ifdef UNICODE -CTransInPlaceFilter::CTransInPlaceFilter - ( CHAR *pName, - LPUNKNOWN pUnk, - REFCLSID clsid, - HRESULT *phr, - bool bModifiesData - ) - : CTransformFilter(pName, pUnk, clsid), - m_bModifiesData(bModifiesData) -{ -#ifdef PERF - RegisterPerfId(); -#endif // PERF - -} // constructor -#endif - -// return a non-addrefed CBasePin * for the user to addref if he holds onto it -// for longer than his pointer to us. We create the pins dynamically when they -// are asked for rather than in the constructor. This is because we want to -// give the derived class an oppportunity to return different pin objects - -// As soon as any pin is needed we create both (this is different from the -// usual transform filter) because enumerators, allocators etc are passed -// through from one pin to another and it becomes very painful if the other -// pin isn't there. If we fail to create either pin we ensure we fail both. - -CBasePin * -CTransInPlaceFilter::GetPin(int n) -{ - HRESULT hr = S_OK; - - // Create an input pin if not already done - - if (m_pInput == NULL) { - - m_pInput = new CTransInPlaceInputPin( NAME("TransInPlace input pin") - , this // Owner filter - , &hr // Result code - , L"Input" // Pin name - ); - - // Constructor for CTransInPlaceInputPin can't fail - ASSERT(SUCCEEDED(hr)); - } - - // Create an output pin if not already done - - if (m_pInput!=NULL && m_pOutput == NULL) { - - m_pOutput = new CTransInPlaceOutputPin( NAME("TransInPlace output pin") - , this // Owner filter - , &hr // Result code - , L"Output" // Pin name - ); - - // a failed return code should delete the object - - ASSERT(SUCCEEDED(hr)); - if (m_pOutput == NULL) { - delete m_pInput; - m_pInput = NULL; - } - } - - // Return the appropriate pin - - ASSERT (n>=0 && n<=1); - if (n == 0) { - return m_pInput; - } else if (n==1) { - return m_pOutput; - } else { - return NULL; - } - -} // GetPin - - - -// dir is the direction of our pin. -// pReceivePin is the pin we are connecting to. -HRESULT CTransInPlaceFilter::CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin) -{ - UNREFERENCED_PARAMETER(pReceivePin); - ASSERT(m_pInput); - ASSERT(m_pOutput); - - // if we are not part of a graph, then don't indirect the pointer - // this probably prevents use of the filter without a filtergraph - if (!m_pGraph) { - return VFW_E_NOT_IN_GRAPH; - } - - // Always reconnect the input to account for buffering changes - // - // Because we don't get to suggest a type on ReceiveConnection - // we need another way of making sure the right type gets used. - // - // One way would be to have our EnumMediaTypes return our output - // connection type first but more deterministic and simple is to - // call ReconnectEx passing the type we want to reconnect with - // via the base class ReconeectPin method. - - if (dir == PINDIR_OUTPUT) { - if( m_pInput->IsConnected() ) { - return ReconnectPin( m_pInput, &m_pOutput->CurrentMediaType() ); - } - return NOERROR; - } - - ASSERT(dir == PINDIR_INPUT); - - // Reconnect output if necessary - - if( m_pOutput->IsConnected() ) { - - if ( m_pInput->CurrentMediaType() - != m_pOutput->CurrentMediaType() - ) { - return ReconnectPin( m_pOutput, &m_pInput->CurrentMediaType() ); - } - } - return NOERROR; - -} // ComnpleteConnect - - -// -// DecideBufferSize -// -// Tell the output pin's allocator what size buffers we require. -// *pAlloc will be the allocator our output pin is using. -// - -HRESULT CTransInPlaceFilter::DecideBufferSize - ( IMemAllocator *pAlloc - , ALLOCATOR_PROPERTIES *pProperties - ) -{ - ALLOCATOR_PROPERTIES Request, Actual; - HRESULT hr; - - // If we are connected upstream, get his views - if (m_pInput->IsConnected()) { - // Get the input pin allocator, and get its size and count. - // we don't care about his alignment and prefix. - - hr = InputPin()->PeekAllocator()->GetProperties(&Request); - if (FAILED(hr)) { - // Input connected but with a secretive allocator - enough! - return hr; - } - } else { - // We're reduced to blind guessing. Let's guess one byte and if - // this isn't enough then when the other pin does get connected - // we can revise it. - ZeroMemory(&Request, sizeof(Request)); - Request.cBuffers = 1; - Request.cbBuffer = 1; - } - - - DbgLog((LOG_MEMORY,1,TEXT("Setting Allocator Requirements"))); - DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d"), - Request.cBuffers, Request.cbBuffer)); - - // Pass the allocator requirements to our output side - // but do a little sanity checking first or we'll just hit - // asserts in the allocator. - - pProperties->cBuffers = Request.cBuffers; - pProperties->cbBuffer = Request.cbBuffer; - pProperties->cbAlign = Request.cbAlign; - if (pProperties->cBuffers<=0) {pProperties->cBuffers = 1; } - if (pProperties->cbBuffer<=0) {pProperties->cbBuffer = 1; } - hr = pAlloc->SetProperties(pProperties, &Actual); - - if (FAILED(hr)) { - return hr; - } - - DbgLog((LOG_MEMORY,1,TEXT("Obtained Allocator Requirements"))); - DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d, Alignment %d"), - Actual.cBuffers, Actual.cbBuffer, Actual.cbAlign)); - - // Make sure we got the right alignment and at least the minimum required - - if ( (Request.cBuffers > Actual.cBuffers) - || (Request.cbBuffer > Actual.cbBuffer) - || (Request.cbAlign > Actual.cbAlign) - ) { - return E_FAIL; - } - return NOERROR; - -} // DecideBufferSize - -// -// Copy -// -// return a pointer to an identical copy of pSample -IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource) -{ - IMediaSample * pDest; - - HRESULT hr; - REFERENCE_TIME tStart, tStop; - const BOOL bTime = S_OK == pSource->GetTime( &tStart, &tStop); - - // this may block for an indeterminate amount of time - hr = OutputPin()->PeekAllocator()->GetBuffer( - &pDest - , bTime ? &tStart : NULL - , bTime ? &tStop : NULL - , m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0 - ); - - if (FAILED(hr)) { - return NULL; - } - - ASSERT(pDest); - IMediaSample2 *pSample2; - if (SUCCEEDED(pDest->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) { - HRESULT hr = pSample2->SetProperties( - FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, pbBuffer), - (PBYTE)m_pInput->SampleProps()); - pSample2->Release(); - if (FAILED(hr)) { - pDest->Release(); - return NULL; - } - } else { - if (bTime) { - pDest->SetTime(&tStart, &tStop); - } - - if (S_OK == pSource->IsSyncPoint()) { - pDest->SetSyncPoint(TRUE); - } - if (S_OK == pSource->IsDiscontinuity() || m_bSampleSkipped) { - pDest->SetDiscontinuity(TRUE); - } - if (S_OK == pSource->IsPreroll()) { - pDest->SetPreroll(TRUE); - } - - // Copy the media type - AM_MEDIA_TYPE *pMediaType; - if (S_OK == pSource->GetMediaType(&pMediaType)) { - pDest->SetMediaType(pMediaType); - DeleteMediaType( pMediaType ); - } - - } - - m_bSampleSkipped = FALSE; - - // Copy the sample media times - REFERENCE_TIME TimeStart, TimeEnd; - if (pSource->GetMediaTime(&TimeStart,&TimeEnd) == NOERROR) { - pDest->SetMediaTime(&TimeStart,&TimeEnd); - } - - // Copy the actual data length and the actual data. - { - const long lDataLength = pSource->GetActualDataLength(); - pDest->SetActualDataLength(lDataLength); - - // Copy the sample data - { - BYTE *pSourceBuffer, *pDestBuffer; - long lSourceSize = pSource->GetSize(); - long lDestSize = pDest->GetSize(); - - ASSERT(lDestSize >= lSourceSize && lDestSize >= lDataLength); - - pSource->GetPointer(&pSourceBuffer); - pDest->GetPointer(&pDestBuffer); - ASSERT(lDestSize == 0 || pSourceBuffer != NULL && pDestBuffer != NULL); - - CopyMemory( (PVOID) pDestBuffer, (PVOID) pSourceBuffer, lDataLength ); - } - } - - return pDest; - -} // Copy - - -// override this to customize the transform process - -HRESULT -CTransInPlaceFilter::Receive(IMediaSample *pSample) -{ - /* Check for other streams and pass them on */ - AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); - if (pProps->dwStreamId != AM_STREAM_MEDIA) { - return m_pOutput->Deliver(pSample); - } - HRESULT hr; - - // Start timing the TransInPlace (if PERF is defined) - MSR_START(m_idTransInPlace); - - if (UsingDifferentAllocators()) { - - // We have to copy the data. - - pSample = Copy(pSample); - - if (pSample==NULL) { - MSR_STOP(m_idTransInPlace); - return E_UNEXPECTED; - } - } - - // have the derived class transform the data - hr = Transform(pSample); - - // Stop the clock and log it (if PERF is defined) - MSR_STOP(m_idTransInPlace); - - if (FAILED(hr)) { - DbgLog((LOG_TRACE, 1, TEXT("Error from TransInPlace"))); - if (UsingDifferentAllocators()) { - pSample->Release(); - } - return hr; - } - - // the Transform() function can return S_FALSE to indicate that the - // sample should not be delivered; we only deliver the sample if it's - // really S_OK (same as NOERROR, of course.) - if (hr == NOERROR) { - hr = m_pOutput->Deliver(pSample); - } else { - // But it would be an error to return this private workaround - // to the caller ... - if (S_FALSE == hr) { - // S_FALSE returned from Transform is a PRIVATE agreement - // We should return NOERROR from Receive() in this cause because - // returning S_FALSE from Receive() means that this is the end - // of the stream and no more data should be sent. - m_bSampleSkipped = TRUE; - if (!m_bQualityChanged) { - NotifyEvent(EC_QUALITY_CHANGE,0,0); - m_bQualityChanged = TRUE; - } - hr = NOERROR; - } - } - - // release the output buffer. If the connected pin still needs it, - // it will have addrefed it itself. - if (UsingDifferentAllocators()) { - pSample->Release(); - } - - return hr; - -} // Receive - - - -// ================================================================= -// Implements the CTransInPlaceInputPin class -// ================================================================= - - -// constructor - -CTransInPlaceInputPin::CTransInPlaceInputPin - ( TCHAR *pObjectName - , CTransInPlaceFilter *pFilter - , HRESULT *phr - , LPCWSTR pName - ) - : CTransformInputPin(pObjectName, - pFilter, - phr, - pName) - , m_bReadOnly(FALSE) - , m_pTIPFilter(pFilter) -{ - DbgLog((LOG_TRACE, 2 - , TEXT("CTransInPlaceInputPin::CTransInPlaceInputPin"))); - -} // constructor - - -// ================================================================= -// Implements IMemInputPin interface -// ================================================================= - - -// If the downstream filter has one then offer that (even if our own output -// pin is not using it yet. If the upstream filter chooses it then we will -// tell our output pin to ReceiveAllocator). -// Else if our output pin is using an allocator then offer that. -// ( This could mean offering the upstream filter his own allocator, -// it could mean offerring our own -// ) or it could mean offering the one from downstream -// Else fail to offer any allocator at all. - -STDMETHODIMP CTransInPlaceInputPin::GetAllocator(IMemAllocator ** ppAllocator) -{ - CheckPointer(ppAllocator,E_POINTER); - ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *)); - CAutoLock cObjectLock(m_pLock); - - HRESULT hr; - - if ( m_pTIPFilter->m_pOutput->IsConnected() ) { - // Store the allocator we got - hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() - ->GetAllocator( ppAllocator ); - if (SUCCEEDED(hr)) { - m_pTIPFilter->OutputPin()->SetAllocator( *ppAllocator ); - } - } - else { - // Help upstream filter (eg TIP filter which is having to do a copy) - // by providing a temp allocator here - we'll never use - // this allocator because when our output is connected we'll - // reconnect this pin - hr = CTransformInputPin::GetAllocator( ppAllocator ); - } - return hr; - -} // GetAllocator - - - -/* Get told which allocator the upstream output pin is actually going to use */ - - -STDMETHODIMP -CTransInPlaceInputPin::NotifyAllocator( - IMemAllocator * pAllocator, - BOOL bReadOnly) -{ - HRESULT hr = S_OK; - CheckPointer(pAllocator,E_POINTER); - ValidateReadPtr(pAllocator,sizeof(IMemAllocator)); - - CAutoLock cObjectLock(m_pLock); - - m_bReadOnly = bReadOnly; - // If we modify data then don't accept the allocator if it's - // the same as the output pin's allocator - - // If our output is not connected just accept the allocator - // We're never going to use this allocator because when our - // output pin is connected we'll reconnect this pin - if (!m_pTIPFilter->OutputPin()->IsConnected()) { - return CTransformInputPin::NotifyAllocator(pAllocator, bReadOnly); - } - - // If the allocator is read-only and we're modifying data - // and the allocator is the same as the output pin's - // then reject - if (bReadOnly && m_pTIPFilter->m_bModifiesData) { - IMemAllocator *pOutputAllocator = - m_pTIPFilter->OutputPin()->PeekAllocator(); - - // Make sure we have an output allocator - if (pOutputAllocator == NULL) { - hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()-> - GetAllocator(&pOutputAllocator); - if(FAILED(hr)) { - hr = CreateMemoryAllocator(&pOutputAllocator); - } - if (SUCCEEDED(hr)) { - m_pTIPFilter->OutputPin()->SetAllocator(pOutputAllocator); - pOutputAllocator->Release(); - } - } - if (pAllocator == pOutputAllocator) { - hr = E_FAIL; - } else if(SUCCEEDED(hr)) { - // Must copy so set the allocator properties on the output - ALLOCATOR_PROPERTIES Props, Actual; - hr = pAllocator->GetProperties(&Props); - if (SUCCEEDED(hr)) { - hr = pOutputAllocator->SetProperties(&Props, &Actual); - } - if (SUCCEEDED(hr)) { - if ( (Props.cBuffers > Actual.cBuffers) - || (Props.cbBuffer > Actual.cbBuffer) - || (Props.cbAlign > Actual.cbAlign) - ) { - hr = E_FAIL; - } - } - - // Set the allocator on the output pin - if (SUCCEEDED(hr)) { - hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() - ->NotifyAllocator( pOutputAllocator, FALSE ); - } - } - } else { - hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() - ->NotifyAllocator( pAllocator, bReadOnly ); - if (SUCCEEDED(hr)) { - m_pTIPFilter->OutputPin()->SetAllocator( pAllocator ); - } - } - - if (SUCCEEDED(hr)) { - - // It's possible that the old and the new are the same thing. - // AddRef before release ensures that we don't unload it. - pAllocator->AddRef(); - - if( m_pAllocator != NULL ) - m_pAllocator->Release(); - - m_pAllocator = pAllocator; // We have an allocator for the input pin - } - - return hr; - -} // NotifyAllocator - - -// EnumMediaTypes -// - pass through to our downstream filter -STDMETHODIMP CTransInPlaceInputPin::EnumMediaTypes( IEnumMediaTypes **ppEnum ) -{ - // Can only pass through if connected - if( !m_pTIPFilter->m_pOutput->IsConnected() ) - return VFW_E_NOT_CONNECTED; - - return m_pTIPFilter->m_pOutput->GetConnected()->EnumMediaTypes( ppEnum ); - -} // EnumMediaTypes - - -// CheckMediaType -// - agree to anything if not connected, -// otherwise pass through to the downstream filter. -// This assumes that the filter does not change the media type. - -HRESULT CTransInPlaceInputPin::CheckMediaType(const CMediaType *pmt ) -{ - HRESULT hr = m_pTIPFilter->CheckInputType(pmt); - if (hr!=S_OK) return hr; - - if( m_pTIPFilter->m_pOutput->IsConnected() ) - return m_pTIPFilter->m_pOutput->GetConnected()->QueryAccept( pmt ); - else - return S_OK; - -} // CheckMediaType - - -// If upstream asks us what our requirements are, we will try to ask downstream -// if that doesn't work, we'll just take the defaults. -STDMETHODIMP -CTransInPlaceInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps) -{ - - if( m_pTIPFilter->m_pOutput->IsConnected() ) - return m_pTIPFilter->OutputPin() - ->ConnectedIMemInputPin()->GetAllocatorRequirements( pProps ); - else - return E_NOTIMPL; - -} // GetAllocatorRequirements - - -// CTransInPlaceInputPin::CompleteConnect() calls CBaseInputPin::CompleteConnect() -// and then calls CTransInPlaceFilter::CompleteConnect(). It does this because -// CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not -// want to reconnect a pin if CBaseInputPin::CompleteConnect() fails. -HRESULT -CTransInPlaceInputPin::CompleteConnect(IPin *pReceivePin) -{ - HRESULT hr = CBaseInputPin::CompleteConnect(pReceivePin); - if (FAILED(hr)) { - return hr; - } - - return m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin); -} // CompleteConnect - - -// ================================================================= -// Implements the CTransInPlaceOutputPin class -// ================================================================= - - -// constructor - -CTransInPlaceOutputPin::CTransInPlaceOutputPin( - TCHAR *pObjectName, - CTransInPlaceFilter *pFilter, - HRESULT * phr, - LPCWSTR pPinName) - : CTransformOutputPin( pObjectName - , pFilter - , phr - , pPinName), - m_pTIPFilter(pFilter) -{ - DbgLog(( LOG_TRACE, 2 - , TEXT("CTransInPlaceOutputPin::CTransInPlaceOutputPin"))); - -} // constructor - - -// EnumMediaTypes -// - pass through to our upstream filter -STDMETHODIMP CTransInPlaceOutputPin::EnumMediaTypes( IEnumMediaTypes **ppEnum ) -{ - // Can only pass through if connected. - if( ! m_pTIPFilter->m_pInput->IsConnected() ) - return VFW_E_NOT_CONNECTED; - - return m_pTIPFilter->m_pInput->GetConnected()->EnumMediaTypes( ppEnum ); - -} // EnumMediaTypes - - - -// CheckMediaType -// - agree to anything if not connected, -// otherwise pass through to the upstream filter. - -HRESULT CTransInPlaceOutputPin::CheckMediaType(const CMediaType *pmt ) -{ - // Don't accept any output pin type changes if we're copying - // between allocators - it's too late to change the input - // allocator size. - if (m_pTIPFilter->UsingDifferentAllocators() && !m_pFilter->IsStopped()) { - if (*pmt == m_mt) { - return S_OK; - } else { - return VFW_E_TYPE_NOT_ACCEPTED; - } - } - - // Assumes the type does not change. That's why we're calling - // CheckINPUTType here on the OUTPUT pin. - HRESULT hr = m_pTIPFilter->CheckInputType(pmt); - if (hr!=S_OK) return hr; - - if( m_pTIPFilter->m_pInput->IsConnected() ) - return m_pTIPFilter->m_pInput->GetConnected()->QueryAccept( pmt ); - else - return S_OK; - -} // CheckMediaType - - -/* Save the allocator pointer in the output pin -*/ -void -CTransInPlaceOutputPin::SetAllocator(IMemAllocator * pAllocator) -{ - pAllocator->AddRef(); - if (m_pAllocator) { - m_pAllocator->Release(); - } - m_pAllocator = pAllocator; -} // SetAllocator - - -// CTransInPlaceOutputPin::CompleteConnect() calls CBaseOutputPin::CompleteConnect() -// and then calls CTransInPlaceFilter::CompleteConnect(). It does this because -// CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not want to -// reconnect a pin if CBaseOutputPin::CompleteConnect() fails. -// CBaseOutputPin::CompleteConnect() often fails when our output pin is being connected -// to the Video Mixing Renderer. -HRESULT -CTransInPlaceOutputPin::CompleteConnect(IPin *pReceivePin) -{ - HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin); - if (FAILED(hr)) { - return hr; - } - - return m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin); -} // CompleteConnect +//------------------------------------------------------------------------------ +// File: TransIP.cpp +// +// Desc: DirectShow base classes - implements class for simple Transform- +// In-Place filters such as audio. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// How allocators are decided. +// +// An in-place transform tries to do its work in someone else's buffers. +// It tries to persuade the filters on either side to use the same allocator +// (and for that matter the same media type). In desperation, if the downstream +// filter refuses to supply an allocator and the upstream filter offers only +// a read-only one then it will provide an allocator. +// if the upstream filter insists on a read-only allocator then the transform +// filter will (reluctantly) copy the data before transforming it. +// +// In order to pass an allocator through it needs to remember the one it got +// from the first connection to pass it on to the second one. +// +// It is good if we can avoid insisting on a particular order of connection +// (There is a precedent for insisting on the input +// being connected first. Insisting on the output being connected first is +// not allowed. That would break RenderFile.) +// +// The base pin classes (CBaseOutputPin and CBaseInputPin) both have a +// m_pAllocator member which is used in places like +// CBaseOutputPin::GetDeliveryBuffer and CBaseInputPin::Inactive. +// To avoid lots of extra overriding, we should keep these happy +// by using these pointers. +// +// When each pin is connected, it will set the corresponding m_pAllocator +// and will have a single ref-count on that allocator. +// +// Refcounts are acquired by GetAllocator calls which return AddReffed +// allocators and are released in one of: +// CBaseInputPin::Disconnect +// CBaseOutputPin::BreakConect +// In each case m_pAllocator is set to NULL after the release, so this +// is the last chance to ever release it. If there should ever be +// multiple refcounts associated with the same pointer, this had better +// be cleared up before that happens. To avoid such problems, we'll +// stick with one per pointer. + + + +// RECONNECTING and STATE CHANGES +// +// Each pin could be disconnected, connected with a read-only allocator, +// connected with an upstream read/write allocator, connected with an +// allocator from downstream or connected with its own allocator. +// Five states for each pin gives a data space of 25 states. +// +// Notation: +// +// R/W == read/write +// R-O == read-only +// +// +// +// 00 means an unconnected pin. +// <- means using a R/W allocator from the upstream filter +// <= means using a R-O allocator from an upstream filter +// || means using our own (R/W) allocator. +// -> means using a R/W allocator from a downstream filter +// (a R-O allocator from downstream is nonsense, it can't ever work). +// +// +// That makes 25 possible states. Some states are nonsense (two different +// allocators from the same place). These are just an artifact of the notation. +// <= <- Nonsense. +// <- <= Nonsense +// Some states are illegal (the output pin never accepts a R-O allocator): +// 00 <= !! Error !! +// <= <= !! Error !! +// || <= !! Error !! +// -> <= !! Error !! +// Three states appears to be inaccessible: +// -> || Inaccessible +// || -> Inaccessible +// || <- Inaccessible +// Some states only ever occur as intermediates with a pending reconnect which +// is guaranteed to finish in another state. +// -> 00 ?? unstable goes to || 00 +// 00 <- ?? unstable goes to 00 || +// -> <- ?? unstable goes to -> -> +// <- || ?? unstable goes to <- <- +// <- -> ?? unstable goes to <- <- +// And that leaves 11 possible resting states: +// 1 00 00 Nothing connected. +// 2 <- 00 Input pin connected. +// 3 <= 00 Input pin connected using R-O allocator. +// 4 || 00 Needs several state changes to get here. +// 5 00 || Output pin connected using our allocator +// 6 00 -> Downstream only connected +// 7 || || Undesirable but can be forced upon us. +// 8 <= || Copy forced. <= -> is preferable +// 9 <= -> OK - forced to copy. +// 10 <- <- Transform in place (ideal) +// 11 -> -> Transform in place (ideal) +// +// The object of the exercise is to ensure that we finish up in states +// 10 or 11 whenever possible. State 10 is only possible if the upstream +// filter has a R/W allocator (the AVI splitter notoriously +// doesn't) and state 11 is only possible if the downstream filter does +// offer an allocator. +// +// The transition table (entries marked * go via a reconnect) +// +// There are 8 possible transitions: +// A: Connect upstream to filter with R-O allocator that insists on using it. +// B: Connect upstream to filter with R-O allocator but chooses not to use it. +// C: Connect upstream to filter with R/W allocator and insists on using it. +// D: Connect upstream to filter with R/W allocator but chooses not to use it. +// E: Connect downstream to a filter that offers an allocator +// F: Connect downstream to a filter that does not offer an allocator +// G: disconnect upstream +// H: Disconnect downstream +// +// A B C D E F G H +// --------------------------------------------------------- +// 00 00 1 | 3 3 2 2 6 5 . . |1 00 00 +// <- 00 2 | . . . . *10/11 10 1 . |2 <- 00 +// <= 00 3 | . . . . *9/11 *7/8 1 . |3 <= 00 +// || 00 4 | . . . . *8 *7 1 . |4 || 00 +// 00 || 5 | 8 7 *10 7 . . . 1 |5 00 || +// 00 -> 6 | 9 11 *10 11 . . . 1 |6 00 -> +// || || 7 | . . . . . . 5 4 |7 || || +// <= || 8 | . . . . . . 5 3 |8 <= || +// <= -> 9 | . . . . . . 6 3 |9 <= -> +// <- <- 10| . . . . . . *5/6 2 |10 <- <- +// -> -> 11| . . . . . . 6 *2/3 |11 -> -> +// --------------------------------------------------------- +// A B C D E F G H +// +// All these states are accessible without requiring any filter to +// change its behaviour but not all transitions are accessible, for +// instance a transition from state 4 to anywhere other than +// state 8 requires that the upstream filter first offer a R-O allocator +// and then changes its mind and offer R/W. This is NOT allowable - it +// leads to things like the output pin getting a R/W allocator from +// upstream and then the input pin being told it can only have a R-O one. +// Note that you CAN change (say) the upstream filter for a different one, but +// only as a disconnect / connect, not as a Reconnect. (Exercise for +// the reader is to see how you get into state 4). +// +// The reconnection stuff goes as follows (some of the cases shown here as +// "no reconnect" may get one to finalise media type - an old story). +// If there is a reconnect where it says "no reconnect" here then the +// reconnection must not change the allocator choice. +// +// state 2: <- 00 transition E <- <- case C <- <- (no change) +// case D -> <- and then to -> -> +// +// state 2: <- 00 transition F <- <- (no reconnect) +// +// state 3: <= 00 transition E <= -> case A <= -> (no change) +// case B -> -> +// transition F <= || case A <= || (no change) +// case B || || +// +// state 4: || 00 transition E || || case B -> || and then all cases to -> -> +// F || || case B || || (no change) +// +// state 5: 00 || transition A <= || (no reconnect) +// B || || (no reconnect) +// C <- || all cases <- <- +// D || || (unfortunate, but upstream's choice) +// +// state 6: 00 -> transition A <= -> (no reconnect) +// B -> -> (no reconnect) +// C <- -> all cases <- <- +// D -> -> (no reconnect) +// +// state 10:<- <- transition G 00 <- case E 00 -> +// case F 00 || +// +// state 11:-> -> transition H -> 00 case A <= 00 (schizo) +// case B <= 00 +// case C <- 00 (schizo) +// case D <- 00 +// +// The Rules: +// To sort out media types: +// The input is reconnected +// if the input pin is connected and the output pin connects +// The output is reconnected +// If the output pin is connected +// and the input pin connects to a different media type +// +// To sort out allocators: +// The input is reconnected +// if the output disconnects and the input was using a downstream allocator +// The output pin calls SetAllocator to pass on a new allocator +// if the output is connected and +// if the input disconnects and the output was using an upstream allocator +// if the input acquires an allocator different from the output one +// and that new allocator is not R-O +// +// Data is copied (i.e. call getbuffer and copy the data before transforming it) +// if the two allocators are different. + + + +// CHAINS of filters: +// +// We sit between two filters (call them A and Z). We should finish up +// with the same allocator on both of our pins and that should be the +// same one that A and Z would have agreed on if we hadn't been in the +// way. Furthermore, it should not matter how many in-place transforms +// are in the way. Let B, C, D... be in-place transforms ("us"). +// Here's how it goes: +// +// 1. +// A connects to B. They agree on A's allocator. +// A-a->B +// +// 2. +// B connects to C. Same story. There is no point in a reconnect, but +// B will request an input reconnect anyway. +// A-a->B-a->C +// +// 3. +// C connects to Z. +// C insists on using A's allocator, but compromises by requesting a reconnect. +// of C's input. +// A-a->B-?->C-a->Z +// +// We now have pending reconnects on both A--->B and B--->C +// +// 4. +// The A--->B link is reconnected. +// A asks B for an allocator. B sees that it has a downstream connection so +// asks its downstream input pin i.e. C's input pin for an allocator. C sees +// that it too has a downstream connection so asks Z for an allocator. +// +// Even though Z's input pin is connected, it is being asked for an allocator. +// It could refuse, in which case the chain is done and will use A's allocator +// Alternatively, Z may supply one. A chooses either Z's or A's own one. +// B's input pin gets NotifyAllocator called to tell it the decision and it +// propagates this downstream by calling ReceiveAllocator on its output pin +// which calls NotifyAllocator on the next input pin downstream etc. +// If the choice is Z then it goes: +// A-z->B-a->C-a->Z +// A-z->B-z->C-a->Z +// A-z->B-z->C-z->Z +// +// And that's IT!! Any further (essentially spurious) reconnects peter out +// with no change in the chain. + +#include "streams.h" +#include "measure.h" +#include "transip.h" + + +// ================================================================= +// Implements the CTransInPlaceFilter class +// ================================================================= + +CTransInPlaceFilter::CTransInPlaceFilter + ( TCHAR *pName, + LPUNKNOWN pUnk, + REFCLSID clsid, + HRESULT *phr, + bool bModifiesData + ) + : CTransformFilter(pName, pUnk, clsid), + m_bModifiesData(bModifiesData) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF + +} // constructor + +#ifdef UNICODE +CTransInPlaceFilter::CTransInPlaceFilter + ( CHAR *pName, + LPUNKNOWN pUnk, + REFCLSID clsid, + HRESULT *phr, + bool bModifiesData + ) + : CTransformFilter(pName, pUnk, clsid), + m_bModifiesData(bModifiesData) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF + +} // constructor +#endif + +// return a non-addrefed CBasePin * for the user to addref if he holds onto it +// for longer than his pointer to us. We create the pins dynamically when they +// are asked for rather than in the constructor. This is because we want to +// give the derived class an oppportunity to return different pin objects + +// As soon as any pin is needed we create both (this is different from the +// usual transform filter) because enumerators, allocators etc are passed +// through from one pin to another and it becomes very painful if the other +// pin isn't there. If we fail to create either pin we ensure we fail both. + +CBasePin * +CTransInPlaceFilter::GetPin(int n) +{ + HRESULT hr = S_OK; + + // Create an input pin if not already done + + if (m_pInput == NULL) { + + m_pInput = new CTransInPlaceInputPin( NAME("TransInPlace input pin") + , this // Owner filter + , &hr // Result code + , L"Input" // Pin name + ); + + // Constructor for CTransInPlaceInputPin can't fail + ASSERT(SUCCEEDED(hr)); + } + + // Create an output pin if not already done + + if (m_pInput!=NULL && m_pOutput == NULL) { + + m_pOutput = new CTransInPlaceOutputPin( NAME("TransInPlace output pin") + , this // Owner filter + , &hr // Result code + , L"Output" // Pin name + ); + + // a failed return code should delete the object + + ASSERT(SUCCEEDED(hr)); + if (m_pOutput == NULL) { + delete m_pInput; + m_pInput = NULL; + } + } + + // Return the appropriate pin + + ASSERT (n>=0 && n<=1); + if (n == 0) { + return m_pInput; + } else if (n==1) { + return m_pOutput; + } else { + return NULL; + } + +} // GetPin + + + +// dir is the direction of our pin. +// pReceivePin is the pin we are connecting to. +HRESULT CTransInPlaceFilter::CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin) +{ + UNREFERENCED_PARAMETER(pReceivePin); + ASSERT(m_pInput); + ASSERT(m_pOutput); + + // if we are not part of a graph, then don't indirect the pointer + // this probably prevents use of the filter without a filtergraph + if (!m_pGraph) { + return VFW_E_NOT_IN_GRAPH; + } + + // Always reconnect the input to account for buffering changes + // + // Because we don't get to suggest a type on ReceiveConnection + // we need another way of making sure the right type gets used. + // + // One way would be to have our EnumMediaTypes return our output + // connection type first but more deterministic and simple is to + // call ReconnectEx passing the type we want to reconnect with + // via the base class ReconeectPin method. + + if (dir == PINDIR_OUTPUT) { + if( m_pInput->IsConnected() ) { + return ReconnectPin( m_pInput, &m_pOutput->CurrentMediaType() ); + } + return NOERROR; + } + + ASSERT(dir == PINDIR_INPUT); + + // Reconnect output if necessary + + if( m_pOutput->IsConnected() ) { + + if ( m_pInput->CurrentMediaType() + != m_pOutput->CurrentMediaType() + ) { + return ReconnectPin( m_pOutput, &m_pInput->CurrentMediaType() ); + } + } + return NOERROR; + +} // ComnpleteConnect + + +// +// DecideBufferSize +// +// Tell the output pin's allocator what size buffers we require. +// *pAlloc will be the allocator our output pin is using. +// + +HRESULT CTransInPlaceFilter::DecideBufferSize + ( IMemAllocator *pAlloc + , ALLOCATOR_PROPERTIES *pProperties + ) +{ + ALLOCATOR_PROPERTIES Request, Actual; + HRESULT hr; + + // If we are connected upstream, get his views + if (m_pInput->IsConnected()) { + // Get the input pin allocator, and get its size and count. + // we don't care about his alignment and prefix. + + hr = InputPin()->PeekAllocator()->GetProperties(&Request); + if (FAILED(hr)) { + // Input connected but with a secretive allocator - enough! + return hr; + } + } else { + // We're reduced to blind guessing. Let's guess one byte and if + // this isn't enough then when the other pin does get connected + // we can revise it. + ZeroMemory(&Request, sizeof(Request)); + Request.cBuffers = 1; + Request.cbBuffer = 1; + } + + + DbgLog((LOG_MEMORY,1,TEXT("Setting Allocator Requirements"))); + DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d"), + Request.cBuffers, Request.cbBuffer)); + + // Pass the allocator requirements to our output side + // but do a little sanity checking first or we'll just hit + // asserts in the allocator. + + pProperties->cBuffers = Request.cBuffers; + pProperties->cbBuffer = Request.cbBuffer; + pProperties->cbAlign = Request.cbAlign; + if (pProperties->cBuffers<=0) {pProperties->cBuffers = 1; } + if (pProperties->cbBuffer<=0) {pProperties->cbBuffer = 1; } + hr = pAlloc->SetProperties(pProperties, &Actual); + + if (FAILED(hr)) { + return hr; + } + + DbgLog((LOG_MEMORY,1,TEXT("Obtained Allocator Requirements"))); + DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d, Alignment %d"), + Actual.cBuffers, Actual.cbBuffer, Actual.cbAlign)); + + // Make sure we got the right alignment and at least the minimum required + + if ( (Request.cBuffers > Actual.cBuffers) + || (Request.cbBuffer > Actual.cbBuffer) + || (Request.cbAlign > Actual.cbAlign) + ) { + return E_FAIL; + } + return NOERROR; + +} // DecideBufferSize + +// +// Copy +// +// return a pointer to an identical copy of pSample +IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource) +{ + IMediaSample * pDest; + + HRESULT hr; + REFERENCE_TIME tStart, tStop; + const BOOL bTime = S_OK == pSource->GetTime( &tStart, &tStop); + + // this may block for an indeterminate amount of time + hr = OutputPin()->PeekAllocator()->GetBuffer( + &pDest + , bTime ? &tStart : NULL + , bTime ? &tStop : NULL + , m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0 + ); + + if (FAILED(hr)) { + return NULL; + } + + ASSERT(pDest); + IMediaSample2 *pSample2; + if (SUCCEEDED(pDest->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) { + HRESULT hr = pSample2->SetProperties( + FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, pbBuffer), + (PBYTE)m_pInput->SampleProps()); + pSample2->Release(); + if (FAILED(hr)) { + pDest->Release(); + return NULL; + } + } else { + if (bTime) { + pDest->SetTime(&tStart, &tStop); + } + + if (S_OK == pSource->IsSyncPoint()) { + pDest->SetSyncPoint(TRUE); + } + if (S_OK == pSource->IsDiscontinuity() || m_bSampleSkipped) { + pDest->SetDiscontinuity(TRUE); + } + if (S_OK == pSource->IsPreroll()) { + pDest->SetPreroll(TRUE); + } + + // Copy the media type + AM_MEDIA_TYPE *pMediaType; + if (S_OK == pSource->GetMediaType(&pMediaType)) { + pDest->SetMediaType(pMediaType); + DeleteMediaType( pMediaType ); + } + + } + + m_bSampleSkipped = FALSE; + + // Copy the sample media times + REFERENCE_TIME TimeStart, TimeEnd; + if (pSource->GetMediaTime(&TimeStart,&TimeEnd) == NOERROR) { + pDest->SetMediaTime(&TimeStart,&TimeEnd); + } + + // Copy the actual data length and the actual data. + { + const long lDataLength = pSource->GetActualDataLength(); + pDest->SetActualDataLength(lDataLength); + + // Copy the sample data + { + BYTE *pSourceBuffer, *pDestBuffer; + long lSourceSize = pSource->GetSize(); + long lDestSize = pDest->GetSize(); + + ASSERT(lDestSize >= lSourceSize && lDestSize >= lDataLength); + + pSource->GetPointer(&pSourceBuffer); + pDest->GetPointer(&pDestBuffer); + ASSERT(lDestSize == 0 || pSourceBuffer != NULL && pDestBuffer != NULL); + + CopyMemory( (PVOID) pDestBuffer, (PVOID) pSourceBuffer, lDataLength ); + } + } + + return pDest; + +} // Copy + + +// override this to customize the transform process + +HRESULT +CTransInPlaceFilter::Receive(IMediaSample *pSample) +{ + /* Check for other streams and pass them on */ + AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); + if (pProps->dwStreamId != AM_STREAM_MEDIA) { + return m_pOutput->Deliver(pSample); + } + HRESULT hr; + + // Start timing the TransInPlace (if PERF is defined) + MSR_START(m_idTransInPlace); + + if (UsingDifferentAllocators()) { + + // We have to copy the data. + + pSample = Copy(pSample); + + if (pSample==NULL) { + MSR_STOP(m_idTransInPlace); + return E_UNEXPECTED; + } + } + + // have the derived class transform the data + hr = Transform(pSample); + + // Stop the clock and log it (if PERF is defined) + MSR_STOP(m_idTransInPlace); + + if (FAILED(hr)) { + DbgLog((LOG_TRACE, 1, TEXT("Error from TransInPlace"))); + if (UsingDifferentAllocators()) { + pSample->Release(); + } + return hr; + } + + // the Transform() function can return S_FALSE to indicate that the + // sample should not be delivered; we only deliver the sample if it's + // really S_OK (same as NOERROR, of course.) + if (hr == NOERROR) { + hr = m_pOutput->Deliver(pSample); + } else { + // But it would be an error to return this private workaround + // to the caller ... + if (S_FALSE == hr) { + // S_FALSE returned from Transform is a PRIVATE agreement + // We should return NOERROR from Receive() in this cause because + // returning S_FALSE from Receive() means that this is the end + // of the stream and no more data should be sent. + m_bSampleSkipped = TRUE; + if (!m_bQualityChanged) { + NotifyEvent(EC_QUALITY_CHANGE,0,0); + m_bQualityChanged = TRUE; + } + hr = NOERROR; + } + } + + // release the output buffer. If the connected pin still needs it, + // it will have addrefed it itself. + if (UsingDifferentAllocators()) { + pSample->Release(); + } + + return hr; + +} // Receive + + + +// ================================================================= +// Implements the CTransInPlaceInputPin class +// ================================================================= + + +// constructor + +CTransInPlaceInputPin::CTransInPlaceInputPin + ( TCHAR *pObjectName + , CTransInPlaceFilter *pFilter + , HRESULT *phr + , LPCWSTR pName + ) + : CTransformInputPin(pObjectName, + pFilter, + phr, + pName) + , m_bReadOnly(FALSE) + , m_pTIPFilter(pFilter) +{ + DbgLog((LOG_TRACE, 2 + , TEXT("CTransInPlaceInputPin::CTransInPlaceInputPin"))); + +} // constructor + + +// ================================================================= +// Implements IMemInputPin interface +// ================================================================= + + +// If the downstream filter has one then offer that (even if our own output +// pin is not using it yet. If the upstream filter chooses it then we will +// tell our output pin to ReceiveAllocator). +// Else if our output pin is using an allocator then offer that. +// ( This could mean offering the upstream filter his own allocator, +// it could mean offerring our own +// ) or it could mean offering the one from downstream +// Else fail to offer any allocator at all. + +STDMETHODIMP CTransInPlaceInputPin::GetAllocator(IMemAllocator ** ppAllocator) +{ + CheckPointer(ppAllocator,E_POINTER); + ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *)); + CAutoLock cObjectLock(m_pLock); + + HRESULT hr; + + if ( m_pTIPFilter->m_pOutput->IsConnected() ) { + // Store the allocator we got + hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() + ->GetAllocator( ppAllocator ); + if (SUCCEEDED(hr)) { + m_pTIPFilter->OutputPin()->SetAllocator( *ppAllocator ); + } + } + else { + // Help upstream filter (eg TIP filter which is having to do a copy) + // by providing a temp allocator here - we'll never use + // this allocator because when our output is connected we'll + // reconnect this pin + hr = CTransformInputPin::GetAllocator( ppAllocator ); + } + return hr; + +} // GetAllocator + + + +/* Get told which allocator the upstream output pin is actually going to use */ + + +STDMETHODIMP +CTransInPlaceInputPin::NotifyAllocator( + IMemAllocator * pAllocator, + BOOL bReadOnly) +{ + HRESULT hr = S_OK; + CheckPointer(pAllocator,E_POINTER); + ValidateReadPtr(pAllocator,sizeof(IMemAllocator)); + + CAutoLock cObjectLock(m_pLock); + + m_bReadOnly = bReadOnly; + // If we modify data then don't accept the allocator if it's + // the same as the output pin's allocator + + // If our output is not connected just accept the allocator + // We're never going to use this allocator because when our + // output pin is connected we'll reconnect this pin + if (!m_pTIPFilter->OutputPin()->IsConnected()) { + return CTransformInputPin::NotifyAllocator(pAllocator, bReadOnly); + } + + // If the allocator is read-only and we're modifying data + // and the allocator is the same as the output pin's + // then reject + if (bReadOnly && m_pTIPFilter->m_bModifiesData) { + IMemAllocator *pOutputAllocator = + m_pTIPFilter->OutputPin()->PeekAllocator(); + + // Make sure we have an output allocator + if (pOutputAllocator == NULL) { + hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()-> + GetAllocator(&pOutputAllocator); + if(FAILED(hr)) { + hr = CreateMemoryAllocator(&pOutputAllocator); + } + if (SUCCEEDED(hr)) { + m_pTIPFilter->OutputPin()->SetAllocator(pOutputAllocator); + pOutputAllocator->Release(); + } + } + if (pAllocator == pOutputAllocator) { + hr = E_FAIL; + } else if(SUCCEEDED(hr)) { + // Must copy so set the allocator properties on the output + ALLOCATOR_PROPERTIES Props, Actual; + hr = pAllocator->GetProperties(&Props); + if (SUCCEEDED(hr)) { + hr = pOutputAllocator->SetProperties(&Props, &Actual); + } + if (SUCCEEDED(hr)) { + if ( (Props.cBuffers > Actual.cBuffers) + || (Props.cbBuffer > Actual.cbBuffer) + || (Props.cbAlign > Actual.cbAlign) + ) { + hr = E_FAIL; + } + } + + // Set the allocator on the output pin + if (SUCCEEDED(hr)) { + hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() + ->NotifyAllocator( pOutputAllocator, FALSE ); + } + } + } else { + hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() + ->NotifyAllocator( pAllocator, bReadOnly ); + if (SUCCEEDED(hr)) { + m_pTIPFilter->OutputPin()->SetAllocator( pAllocator ); + } + } + + if (SUCCEEDED(hr)) { + + // It's possible that the old and the new are the same thing. + // AddRef before release ensures that we don't unload it. + pAllocator->AddRef(); + + if( m_pAllocator != NULL ) + m_pAllocator->Release(); + + m_pAllocator = pAllocator; // We have an allocator for the input pin + } + + return hr; + +} // NotifyAllocator + + +// EnumMediaTypes +// - pass through to our downstream filter +STDMETHODIMP CTransInPlaceInputPin::EnumMediaTypes( IEnumMediaTypes **ppEnum ) +{ + // Can only pass through if connected + if( !m_pTIPFilter->m_pOutput->IsConnected() ) + return VFW_E_NOT_CONNECTED; + + return m_pTIPFilter->m_pOutput->GetConnected()->EnumMediaTypes( ppEnum ); + +} // EnumMediaTypes + + +// CheckMediaType +// - agree to anything if not connected, +// otherwise pass through to the downstream filter. +// This assumes that the filter does not change the media type. + +HRESULT CTransInPlaceInputPin::CheckMediaType(const CMediaType *pmt ) +{ + HRESULT hr = m_pTIPFilter->CheckInputType(pmt); + if (hr!=S_OK) return hr; + + if( m_pTIPFilter->m_pOutput->IsConnected() ) + return m_pTIPFilter->m_pOutput->GetConnected()->QueryAccept( pmt ); + else + return S_OK; + +} // CheckMediaType + + +// If upstream asks us what our requirements are, we will try to ask downstream +// if that doesn't work, we'll just take the defaults. +STDMETHODIMP +CTransInPlaceInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps) +{ + + if( m_pTIPFilter->m_pOutput->IsConnected() ) + return m_pTIPFilter->OutputPin() + ->ConnectedIMemInputPin()->GetAllocatorRequirements( pProps ); + else + return E_NOTIMPL; + +} // GetAllocatorRequirements + + +// CTransInPlaceInputPin::CompleteConnect() calls CBaseInputPin::CompleteConnect() +// and then calls CTransInPlaceFilter::CompleteConnect(). It does this because +// CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not +// want to reconnect a pin if CBaseInputPin::CompleteConnect() fails. +HRESULT +CTransInPlaceInputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = CBaseInputPin::CompleteConnect(pReceivePin); + if (FAILED(hr)) { + return hr; + } + + return m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin); +} // CompleteConnect + + +// ================================================================= +// Implements the CTransInPlaceOutputPin class +// ================================================================= + + +// constructor + +CTransInPlaceOutputPin::CTransInPlaceOutputPin( + TCHAR *pObjectName, + CTransInPlaceFilter *pFilter, + HRESULT * phr, + LPCWSTR pPinName) + : CTransformOutputPin( pObjectName + , pFilter + , phr + , pPinName), + m_pTIPFilter(pFilter) +{ + DbgLog(( LOG_TRACE, 2 + , TEXT("CTransInPlaceOutputPin::CTransInPlaceOutputPin"))); + +} // constructor + + +// EnumMediaTypes +// - pass through to our upstream filter +STDMETHODIMP CTransInPlaceOutputPin::EnumMediaTypes( IEnumMediaTypes **ppEnum ) +{ + // Can only pass through if connected. + if( ! m_pTIPFilter->m_pInput->IsConnected() ) + return VFW_E_NOT_CONNECTED; + + return m_pTIPFilter->m_pInput->GetConnected()->EnumMediaTypes( ppEnum ); + +} // EnumMediaTypes + + + +// CheckMediaType +// - agree to anything if not connected, +// otherwise pass through to the upstream filter. + +HRESULT CTransInPlaceOutputPin::CheckMediaType(const CMediaType *pmt ) +{ + // Don't accept any output pin type changes if we're copying + // between allocators - it's too late to change the input + // allocator size. + if (m_pTIPFilter->UsingDifferentAllocators() && !m_pFilter->IsStopped()) { + if (*pmt == m_mt) { + return S_OK; + } else { + return VFW_E_TYPE_NOT_ACCEPTED; + } + } + + // Assumes the type does not change. That's why we're calling + // CheckINPUTType here on the OUTPUT pin. + HRESULT hr = m_pTIPFilter->CheckInputType(pmt); + if (hr!=S_OK) return hr; + + if( m_pTIPFilter->m_pInput->IsConnected() ) + return m_pTIPFilter->m_pInput->GetConnected()->QueryAccept( pmt ); + else + return S_OK; + +} // CheckMediaType + + +/* Save the allocator pointer in the output pin +*/ +void +CTransInPlaceOutputPin::SetAllocator(IMemAllocator * pAllocator) +{ + pAllocator->AddRef(); + if (m_pAllocator) { + m_pAllocator->Release(); + } + m_pAllocator = pAllocator; +} // SetAllocator + + +// CTransInPlaceOutputPin::CompleteConnect() calls CBaseOutputPin::CompleteConnect() +// and then calls CTransInPlaceFilter::CompleteConnect(). It does this because +// CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not want to +// reconnect a pin if CBaseOutputPin::CompleteConnect() fails. +// CBaseOutputPin::CompleteConnect() often fails when our output pin is being connected +// to the Video Mixing Renderer. +HRESULT +CTransInPlaceOutputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin); + if (FAILED(hr)) { + return hr; + } + + return m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin); +} // CompleteConnect diff --git a/plugins/GSdx/baseclasses/transip.h b/plugins/GSdx/baseclasses/transip.h index 2c1e5114ac..4945f62143 100644 --- a/plugins/GSdx/baseclasses/transip.h +++ b/plugins/GSdx/baseclasses/transip.h @@ -1,250 +1,250 @@ -//------------------------------------------------------------------------------ -// File: TransIP.h -// -// Desc: DirectShow base classes - defines classes from which simple -// Transform-In-Place filters may be derived. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// -// The difference between this and Transfrm.h is that Transfrm copies the data. -// -// It assumes the filter has one input and one output stream, and has no -// interest in memory management, interface negotiation or anything else. -// -// Derive your class from this, and supply Transform and the media type/format -// negotiation functions. Implement that class, compile and link and -// you're done. - - -#ifndef __TRANSIP__ -#define __TRANSIP__ - -// ====================================================================== -// This is the com object that represents a simple transform filter. It -// supports IBaseFilter, IMediaFilter and two pins through nested interfaces -// ====================================================================== - -class CTransInPlaceFilter; - -// Several of the pin functions call filter functions to do the work, -// so you can often use the pin classes unaltered, just overriding the -// functions in CTransInPlaceFilter. If that's not enough and you want -// to derive your own pin class, override GetPin in the filter to supply -// your own pin classes to the filter. - -// ================================================== -// Implements the input pin -// ================================================== - -class CTransInPlaceInputPin : public CTransformInputPin -{ - -protected: - CTransInPlaceFilter * const m_pTIPFilter; // our filter - BOOL m_bReadOnly; // incoming stream is read only - -public: - - CTransInPlaceInputPin( - TCHAR *pObjectName, - CTransInPlaceFilter *pFilter, - HRESULT *phr, - LPCWSTR pName); - - // --- IMemInputPin ----- - - // Provide an enumerator for media types by getting one from downstream - STDMETHODIMP EnumMediaTypes( IEnumMediaTypes **ppEnum ); - - // Say whether media type is acceptable. - HRESULT CheckMediaType(const CMediaType* pmt); - - // Return our upstream allocator - STDMETHODIMP GetAllocator(IMemAllocator ** ppAllocator); - - // get told which allocator the upstream output pin is actually - // going to use. - STDMETHODIMP NotifyAllocator(IMemAllocator * pAllocator, - BOOL bReadOnly); - - // Allow the filter to see what allocator we have - // N.B. This does NOT AddRef - IMemAllocator * PeekAllocator() const - { return m_pAllocator; } - - // Pass this on downstream if it ever gets called. - STDMETHODIMP GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps); - - HRESULT CompleteConnect(IPin *pReceivePin); - - inline const BOOL ReadOnly() { return m_bReadOnly ; } - -}; // CTransInPlaceInputPin - -// ================================================== -// Implements the output pin -// ================================================== - -class CTransInPlaceOutputPin : public CTransformOutputPin -{ - -protected: - // m_pFilter points to our CBaseFilter - CTransInPlaceFilter * const m_pTIPFilter; - -public: - - CTransInPlaceOutputPin( - TCHAR *pObjectName, - CTransInPlaceFilter *pFilter, - HRESULT *phr, - LPCWSTR pName); - - - // --- CBaseOutputPin ------------ - - // negotiate the allocator and its buffer size/count - // Insists on using our own allocator. (Actually the one upstream of us). - // We don't override this - instead we just agree the default - // then let the upstream filter decide for itself on reconnect - // virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc); - - // Provide a media type enumerator. Get it from upstream. - STDMETHODIMP EnumMediaTypes( IEnumMediaTypes **ppEnum ); - - // Say whether media type is acceptable. - HRESULT CheckMediaType(const CMediaType* pmt); - - // This just saves the allocator being used on the output pin - // Also called by input pin's GetAllocator() - void SetAllocator(IMemAllocator * pAllocator); - - IMemInputPin * ConnectedIMemInputPin() - { return m_pInputPin; } - - // Allow the filter to see what allocator we have - // N.B. This does NOT AddRef - IMemAllocator * PeekAllocator() const - { return m_pAllocator; } - - HRESULT CompleteConnect(IPin *pReceivePin); - -}; // CTransInPlaceOutputPin - - -class AM_NOVTABLE CTransInPlaceFilter : public CTransformFilter -{ - -public: - - // map getpin/getpincount for base enum of pins to owner - // override this to return more specialised pin objects - - virtual CBasePin *GetPin(int n); - -public: - - // Set bModifiesData == false if your derived filter does - // not modify the data samples (for instance it's just copying - // them somewhere else or looking at the timestamps). - - CTransInPlaceFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid, HRESULT *, - bool bModifiesData = true); -#ifdef UNICODE - CTransInPlaceFilter(CHAR *, LPUNKNOWN, REFCLSID clsid, HRESULT *, - bool bModifiesData = true); -#endif - // The following are defined to avoid undefined pure virtuals. - // Even if they are never called, they will give linkage warnings/errors - - // We override EnumMediaTypes to bypass the transform class enumerator - // which would otherwise call this. - HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) - { DbgBreak("CTransInPlaceFilter::GetMediaType should never be called"); - return E_UNEXPECTED; - } - - // This is called when we actually have to provide out own allocator. - HRESULT DecideBufferSize(IMemAllocator*, ALLOCATOR_PROPERTIES *); - - // The functions which call this in CTransform are overridden in this - // class to call CheckInputType with the assumption that the type - // does not change. In Debug builds some calls will be made and - // we just ensure that they do not assert. - HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut) - { - return S_OK; - }; - - - // ================================================================= - // ----- You may want to override this ----------------------------- - // ================================================================= - - HRESULT CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin); - - // chance to customize the transform process - virtual HRESULT Receive(IMediaSample *pSample); - - // ================================================================= - // ----- You MUST override these ----------------------------------- - // ================================================================= - - virtual HRESULT Transform(IMediaSample *pSample) PURE; - - // this goes in the factory template table to create new instances - // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *); - - -#ifdef PERF - // Override to register performance measurement with a less generic string - // You should do this to avoid confusion with other filters - virtual void RegisterPerfId() - {m_idTransInPlace = MSR_REGISTER(TEXT("TransInPlace"));} -#endif // PERF - - -// implementation details - -protected: - - IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource); - -#ifdef PERF - int m_idTransInPlace; // performance measuring id -#endif // PERF - bool m_bModifiesData; // Does this filter change the data? - - // these hold our input and output pins - - friend class CTransInPlaceInputPin; - friend class CTransInPlaceOutputPin; - - CTransInPlaceInputPin *InputPin() const - { - return (CTransInPlaceInputPin *)m_pInput; - }; - CTransInPlaceOutputPin *OutputPin() const - { - return (CTransInPlaceOutputPin *)m_pOutput; - }; - - // Helper to see if the input and output types match - BOOL TypesMatch() - { - return InputPin()->CurrentMediaType() == - OutputPin()->CurrentMediaType(); - } - - // Are the input and output allocators different? - BOOL UsingDifferentAllocators() const - { - return InputPin()->PeekAllocator() != OutputPin()->PeekAllocator(); - } -}; // CTransInPlaceFilter - -#endif /* __TRANSIP__ */ - +//------------------------------------------------------------------------------ +// File: TransIP.h +// +// Desc: DirectShow base classes - defines classes from which simple +// Transform-In-Place filters may be derived. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// +// The difference between this and Transfrm.h is that Transfrm copies the data. +// +// It assumes the filter has one input and one output stream, and has no +// interest in memory management, interface negotiation or anything else. +// +// Derive your class from this, and supply Transform and the media type/format +// negotiation functions. Implement that class, compile and link and +// you're done. + + +#ifndef __TRANSIP__ +#define __TRANSIP__ + +// ====================================================================== +// This is the com object that represents a simple transform filter. It +// supports IBaseFilter, IMediaFilter and two pins through nested interfaces +// ====================================================================== + +class CTransInPlaceFilter; + +// Several of the pin functions call filter functions to do the work, +// so you can often use the pin classes unaltered, just overriding the +// functions in CTransInPlaceFilter. If that's not enough and you want +// to derive your own pin class, override GetPin in the filter to supply +// your own pin classes to the filter. + +// ================================================== +// Implements the input pin +// ================================================== + +class CTransInPlaceInputPin : public CTransformInputPin +{ + +protected: + CTransInPlaceFilter * const m_pTIPFilter; // our filter + BOOL m_bReadOnly; // incoming stream is read only + +public: + + CTransInPlaceInputPin( + TCHAR *pObjectName, + CTransInPlaceFilter *pFilter, + HRESULT *phr, + LPCWSTR pName); + + // --- IMemInputPin ----- + + // Provide an enumerator for media types by getting one from downstream + STDMETHODIMP EnumMediaTypes( IEnumMediaTypes **ppEnum ); + + // Say whether media type is acceptable. + HRESULT CheckMediaType(const CMediaType* pmt); + + // Return our upstream allocator + STDMETHODIMP GetAllocator(IMemAllocator ** ppAllocator); + + // get told which allocator the upstream output pin is actually + // going to use. + STDMETHODIMP NotifyAllocator(IMemAllocator * pAllocator, + BOOL bReadOnly); + + // Allow the filter to see what allocator we have + // N.B. This does NOT AddRef + IMemAllocator * PeekAllocator() const + { return m_pAllocator; } + + // Pass this on downstream if it ever gets called. + STDMETHODIMP GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps); + + HRESULT CompleteConnect(IPin *pReceivePin); + + inline const BOOL ReadOnly() { return m_bReadOnly ; } + +}; // CTransInPlaceInputPin + +// ================================================== +// Implements the output pin +// ================================================== + +class CTransInPlaceOutputPin : public CTransformOutputPin +{ + +protected: + // m_pFilter points to our CBaseFilter + CTransInPlaceFilter * const m_pTIPFilter; + +public: + + CTransInPlaceOutputPin( + TCHAR *pObjectName, + CTransInPlaceFilter *pFilter, + HRESULT *phr, + LPCWSTR pName); + + + // --- CBaseOutputPin ------------ + + // negotiate the allocator and its buffer size/count + // Insists on using our own allocator. (Actually the one upstream of us). + // We don't override this - instead we just agree the default + // then let the upstream filter decide for itself on reconnect + // virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc); + + // Provide a media type enumerator. Get it from upstream. + STDMETHODIMP EnumMediaTypes( IEnumMediaTypes **ppEnum ); + + // Say whether media type is acceptable. + HRESULT CheckMediaType(const CMediaType* pmt); + + // This just saves the allocator being used on the output pin + // Also called by input pin's GetAllocator() + void SetAllocator(IMemAllocator * pAllocator); + + IMemInputPin * ConnectedIMemInputPin() + { return m_pInputPin; } + + // Allow the filter to see what allocator we have + // N.B. This does NOT AddRef + IMemAllocator * PeekAllocator() const + { return m_pAllocator; } + + HRESULT CompleteConnect(IPin *pReceivePin); + +}; // CTransInPlaceOutputPin + + +class AM_NOVTABLE CTransInPlaceFilter : public CTransformFilter +{ + +public: + + // map getpin/getpincount for base enum of pins to owner + // override this to return more specialised pin objects + + virtual CBasePin *GetPin(int n); + +public: + + // Set bModifiesData == false if your derived filter does + // not modify the data samples (for instance it's just copying + // them somewhere else or looking at the timestamps). + + CTransInPlaceFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid, HRESULT *, + bool bModifiesData = true); +#ifdef UNICODE + CTransInPlaceFilter(CHAR *, LPUNKNOWN, REFCLSID clsid, HRESULT *, + bool bModifiesData = true); +#endif + // The following are defined to avoid undefined pure virtuals. + // Even if they are never called, they will give linkage warnings/errors + + // We override EnumMediaTypes to bypass the transform class enumerator + // which would otherwise call this. + HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) + { DbgBreak("CTransInPlaceFilter::GetMediaType should never be called"); + return E_UNEXPECTED; + } + + // This is called when we actually have to provide out own allocator. + HRESULT DecideBufferSize(IMemAllocator*, ALLOCATOR_PROPERTIES *); + + // The functions which call this in CTransform are overridden in this + // class to call CheckInputType with the assumption that the type + // does not change. In Debug builds some calls will be made and + // we just ensure that they do not assert. + HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut) + { + return S_OK; + }; + + + // ================================================================= + // ----- You may want to override this ----------------------------- + // ================================================================= + + HRESULT CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin); + + // chance to customize the transform process + virtual HRESULT Receive(IMediaSample *pSample); + + // ================================================================= + // ----- You MUST override these ----------------------------------- + // ================================================================= + + virtual HRESULT Transform(IMediaSample *pSample) PURE; + + // this goes in the factory template table to create new instances + // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *); + + +#ifdef PERF + // Override to register performance measurement with a less generic string + // You should do this to avoid confusion with other filters + virtual void RegisterPerfId() + {m_idTransInPlace = MSR_REGISTER(TEXT("TransInPlace"));} +#endif // PERF + + +// implementation details + +protected: + + IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource); + +#ifdef PERF + int m_idTransInPlace; // performance measuring id +#endif // PERF + bool m_bModifiesData; // Does this filter change the data? + + // these hold our input and output pins + + friend class CTransInPlaceInputPin; + friend class CTransInPlaceOutputPin; + + CTransInPlaceInputPin *InputPin() const + { + return (CTransInPlaceInputPin *)m_pInput; + }; + CTransInPlaceOutputPin *OutputPin() const + { + return (CTransInPlaceOutputPin *)m_pOutput; + }; + + // Helper to see if the input and output types match + BOOL TypesMatch() + { + return InputPin()->CurrentMediaType() == + OutputPin()->CurrentMediaType(); + } + + // Are the input and output allocators different? + BOOL UsingDifferentAllocators() const + { + return InputPin()->PeekAllocator() != OutputPin()->PeekAllocator(); + } +}; // CTransInPlaceFilter + +#endif /* __TRANSIP__ */ + diff --git a/plugins/GSdx/baseclasses/vtrans.cpp b/plugins/GSdx/baseclasses/vtrans.cpp index f93c200dcb..2fb587508b 100644 --- a/plugins/GSdx/baseclasses/vtrans.cpp +++ b/plugins/GSdx/baseclasses/vtrans.cpp @@ -1,468 +1,468 @@ -//------------------------------------------------------------------------------ -// File: Vtrans.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include "measure.h" -// #include // now in precomp file streams.h - -CVideoTransformFilter::CVideoTransformFilter - ( TCHAR *pName, LPUNKNOWN pUnk, REFCLSID clsid) - : CTransformFilter(pName, pUnk, clsid) - , m_itrLate(0) - , m_nKeyFramePeriod(0) // No QM until we see at least 2 key frames - , m_nFramesSinceKeyFrame(0) - , m_bSkipping(FALSE) - , m_tDecodeStart(0) - , m_itrAvgDecode(300000) // 30mSec - probably allows skipping - , m_bQualityChanged(FALSE) -{ -#ifdef PERF - RegisterPerfId(); -#endif // PERF -} - - -CVideoTransformFilter::~CVideoTransformFilter() -{ - // nothing to do -} - - -// Reset our quality management state - -HRESULT CVideoTransformFilter::StartStreaming() -{ - m_itrLate = 0; - m_nKeyFramePeriod = 0; // No QM until we see at least 2 key frames - m_nFramesSinceKeyFrame = 0; - m_bSkipping = FALSE; - m_tDecodeStart = 0; - m_itrAvgDecode = 300000; // 30mSec - probably allows skipping - m_bQualityChanged = FALSE; - m_bSampleSkipped = FALSE; - return NOERROR; -} - - -// Overriden to reset quality management information - -HRESULT CVideoTransformFilter::EndFlush() -{ - { - // Synchronize - CAutoLock lck(&m_csReceive); - - // Reset our stats - // - // Note - we don't want to call derived classes here, - // we only want to reset our internal variables and this - // is a convenient way to do it - CVideoTransformFilter::StartStreaming(); - } - return CTransformFilter::EndFlush(); -} - - -HRESULT CVideoTransformFilter::AbortPlayback(HRESULT hr) -{ - NotifyEvent(EC_ERRORABORT, hr, 0); - m_pOutput->DeliverEndOfStream(); - return hr; -} - - -// Receive() -// -// Accept a sample from upstream, decide whether to process it -// or drop it. If we process it then get a buffer from the -// allocator of the downstream connection, transform it into the -// new buffer and deliver it to the downstream filter. -// If we decide not to process it then we do not get a buffer. - -// Remember that although this code will notice format changes coming into -// the input pin, it will NOT change its output format if that results -// in the filter needing to make a corresponding output format change. Your -// derived filter will have to take care of that. (eg. a palette change if -// the input and output is an 8 bit format). If the input sample is discarded -// and nothing is sent out for this Receive, please remember to put the format -// change on the first output sample that you actually do send. -// If your filter will produce the same output type even when the input type -// changes, then this base class code will do everything you need. - -HRESULT CVideoTransformFilter::Receive(IMediaSample *pSample) -{ - // If the next filter downstream is the video renderer, then it may - // be able to operate in DirectDraw mode which saves copying the data - // and gives higher performance. In that case the buffer which we - // get from GetDeliveryBuffer will be a DirectDraw buffer, and - // drawing into this buffer draws directly onto the display surface. - // This means that any waiting for the correct time to draw occurs - // during GetDeliveryBuffer, and that once the buffer is given to us - // the video renderer will count it in its statistics as a frame drawn. - // This means that any decision to drop the frame must be taken before - // calling GetDeliveryBuffer. - - ASSERT(CritCheckIn(&m_csReceive)); - AM_MEDIA_TYPE *pmtOut, *pmt; -#ifdef DEBUG - FOURCCMap fccOut; -#endif - HRESULT hr; - ASSERT(pSample); - IMediaSample * pOutSample; - - // If no output pin to deliver to then no point sending us data - ASSERT (m_pOutput != NULL) ; - - // The source filter may dynamically ask us to start transforming from a - // different media type than the one we're using now. If we don't, we'll - // draw garbage. (typically, this is a palette change in the movie, - // but could be something more sinister like the compression type changing, - // or even the video size changing) - -#define rcS1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcSource -#define rcT1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcTarget - - pSample->GetMediaType(&pmt); - if (pmt != NULL && pmt->pbFormat != NULL) { - - // spew some debug output - ASSERT(!IsEqualGUID(pmt->majortype, GUID_NULL)); -#ifdef DEBUG - fccOut.SetFOURCC(&pmt->subtype); - LONG lCompression = HEADER(pmt->pbFormat)->biCompression; - LONG lBitCount = HEADER(pmt->pbFormat)->biBitCount; - LONG lStride = (HEADER(pmt->pbFormat)->biWidth * lBitCount + 7) / 8; - lStride = (lStride + 3) & ~3; - DbgLog((LOG_TRACE,3,TEXT("*Changing input type on the fly to"))); - DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"), - fccOut.GetFOURCC(), lCompression, lBitCount)); - DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"), - HEADER(pmt->pbFormat)->biHeight, - rcT1.left, rcT1.top, rcT1.right, rcT1.bottom)); - DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"), - rcS1.left, rcS1.top, rcS1.right, rcS1.bottom, - lStride)); -#endif - - // now switch to using the new format. I am assuming that the - // derived filter will do the right thing when its media type is - // switched and streaming is restarted. - - StopStreaming(); - m_pInput->CurrentMediaType() = *pmt; - DeleteMediaType(pmt); - // if this fails, playback will stop, so signal an error - hr = StartStreaming(); - if (FAILED(hr)) { - return AbortPlayback(hr); - } - } - - // Now that we have noticed any format changes on the input sample, it's - // OK to discard it. - - if (ShouldSkipFrame(pSample)) { - MSR_NOTE(m_idSkip); - m_bSampleSkipped = TRUE; - return NOERROR; - } - - // Set up the output sample - hr = InitializeOutputSample(pSample, &pOutSample); - - if (FAILED(hr)) { - return hr; - } - - m_bSampleSkipped = FALSE; - - // The renderer may ask us to on-the-fly to start transforming to a - // different format. If we don't obey it, we'll draw garbage - -#define rcS ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcSource -#define rcT ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcTarget - - pOutSample->GetMediaType(&pmtOut); - if (pmtOut != NULL && pmtOut->pbFormat != NULL) { - - // spew some debug output - ASSERT(!IsEqualGUID(pmtOut->majortype, GUID_NULL)); -#ifdef DEBUG - fccOut.SetFOURCC(&pmtOut->subtype); - LONG lCompression = HEADER(pmtOut->pbFormat)->biCompression; - LONG lBitCount = HEADER(pmtOut->pbFormat)->biBitCount; - LONG lStride = (HEADER(pmtOut->pbFormat)->biWidth * lBitCount + 7) / 8; - lStride = (lStride + 3) & ~3; - DbgLog((LOG_TRACE,3,TEXT("*Changing output type on the fly to"))); - DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"), - fccOut.GetFOURCC(), lCompression, lBitCount)); - DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"), - HEADER(pmtOut->pbFormat)->biHeight, - rcT.left, rcT.top, rcT.right, rcT.bottom)); - DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"), - rcS.left, rcS.top, rcS.right, rcS.bottom, - lStride)); -#endif - - // now switch to using the new format. I am assuming that the - // derived filter will do the right thing when its media type is - // switched and streaming is restarted. - - StopStreaming(); - m_pOutput->CurrentMediaType() = *pmtOut; - DeleteMediaType(pmtOut); - hr = StartStreaming(); - - if (SUCCEEDED(hr)) { - // a new format, means a new empty buffer, so wait for a keyframe - // before passing anything on to the renderer. - // !!! a keyframe may never come, so give up after 30 frames - DbgLog((LOG_TRACE,3,TEXT("Output format change means we must wait for a keyframe"))); - m_nWaitForKey = 30; - - // if this fails, playback will stop, so signal an error - } else { - - // Must release the sample before calling AbortPlayback - // because we might be holding the win16 lock or - // ddraw lock - pOutSample->Release(); - AbortPlayback(hr); - return hr; - } - } - - // After a discontinuity, we need to wait for the next key frame - if (pSample->IsDiscontinuity() == S_OK) { - DbgLog((LOG_TRACE,3,TEXT("Non-key discontinuity - wait for keyframe"))); - m_nWaitForKey = 30; - } - - // Start timing the transform (and log it if PERF is defined) - - if (SUCCEEDED(hr)) { - m_tDecodeStart = timeGetTime(); - MSR_START(m_idTransform); - - // have the derived class transform the data - hr = Transform(pSample, pOutSample); - - // Stop the clock (and log it if PERF is defined) - MSR_STOP(m_idTransform); - m_tDecodeStart = timeGetTime()-m_tDecodeStart; - m_itrAvgDecode = m_tDecodeStart*(10000/16) + 15*(m_itrAvgDecode/16); - - // Maybe we're waiting for a keyframe still? - if (m_nWaitForKey) - m_nWaitForKey--; - if (m_nWaitForKey && pSample->IsSyncPoint() == S_OK) - m_nWaitForKey = FALSE; - - // if so, then we don't want to pass this on to the renderer - if (m_nWaitForKey && hr == NOERROR) { - DbgLog((LOG_TRACE,3,TEXT("still waiting for a keyframe"))); - hr = S_FALSE; - } - } - - if (FAILED(hr)) { - DbgLog((LOG_TRACE,1,TEXT("Error from video transform"))); - } else { - // the Transform() function can return S_FALSE to indicate that the - // sample should not be delivered; we only deliver the sample if it's - // really S_OK (same as NOERROR, of course.) - // Try not to return S_FALSE to a direct draw buffer (it's wasteful) - // Try to take the decision earlier - before you get it. - - if (hr == NOERROR) { - hr = m_pOutput->Deliver(pOutSample); - } else { - // S_FALSE returned from Transform is a PRIVATE agreement - // We should return NOERROR from Receive() in this case because returning S_FALSE - // from Receive() means that this is the end of the stream and no more data should - // be sent. - if (S_FALSE == hr) { - - // We must Release() the sample before doing anything - // like calling the filter graph because having the - // sample means we may have the DirectDraw lock - // (== win16 lock on some versions) - pOutSample->Release(); - m_bSampleSkipped = TRUE; - if (!m_bQualityChanged) { - m_bQualityChanged = TRUE; - NotifyEvent(EC_QUALITY_CHANGE,0,0); - } - return NOERROR; - } - } - } - - // release the output buffer. If the connected pin still needs it, - // it will have addrefed it itself. - pOutSample->Release(); - ASSERT(CritCheckIn(&m_csReceive)); - - return hr; -} - - - -BOOL CVideoTransformFilter::ShouldSkipFrame( IMediaSample * pIn) -{ - REFERENCE_TIME trStart, trStopAt; - HRESULT hr = pIn->GetTime(&trStart, &trStopAt); - - // Don't skip frames with no timestamps - if (hr != S_OK) - return FALSE; - - int itrFrame = (int)(trStopAt - trStart); // frame duration - - if(S_OK==pIn->IsSyncPoint()) { - MSR_INTEGER(m_idFrameType, 1); - if ( m_nKeyFramePeriod < m_nFramesSinceKeyFrame ) { - // record the max - m_nKeyFramePeriod = m_nFramesSinceKeyFrame; - } - m_nFramesSinceKeyFrame = 0; - m_bSkipping = FALSE; - } else { - MSR_INTEGER(m_idFrameType, 2); - if ( m_nFramesSinceKeyFrame>m_nKeyFramePeriod - && m_nKeyFramePeriod>0 - ) { - // We haven't seen the key frame yet, but we were clearly being - // overoptimistic about how frequent they are. - m_nKeyFramePeriod = m_nFramesSinceKeyFrame; - } - } - - - // Whatever we might otherwise decide, - // if we are taking only a small fraction of the required frame time to decode - // then any quality problems are actually coming from somewhere else. - // Could be a net problem at the source for instance. In this case there's - // no point in us skipping frames here. - if (m_itrAvgDecode*4>itrFrame) { - - // Don't skip unless we are at least a whole frame late. - // (We would skip B frames if more than 1/2 frame late, but they're safe). - if ( m_itrLate > itrFrame ) { - - // Don't skip unless the anticipated key frame would be no more than - // 1 frame early. If the renderer has not been waiting (we *guess* - // it hasn't because we're late) then it will allow frames to be - // played early by up to a frame. - - // Let T = Stream time from now to anticipated next key frame - // = (frame duration) * (KeyFramePeriod - FramesSinceKeyFrame) - // So we skip if T - Late < one frame i.e. - // (duration) * (freq - FramesSince) - Late < duration - // or (duration) * (freq - FramesSince - 1) < Late - - // We don't dare skip until we have seen some key frames and have - // some idea how often they occur and they are reasonably frequent. - if (m_nKeyFramePeriod>0) { - // It would be crazy - but we could have a stream with key frames - // a very long way apart - and if they are further than about - // 3.5 minutes apart then we could get arithmetic overflow in - // reference time units. Therefore we switch to mSec at this point - int it = (itrFrame/10000) - * (m_nKeyFramePeriod-m_nFramesSinceKeyFrame - 1); - MSR_INTEGER(m_idTimeTillKey, it); - - // For debug - might want to see the details - dump them as scratch pad -#ifdef VTRANSPERF - MSR_INTEGER(0, itrFrame); - MSR_INTEGER(0, m_nFramesSinceKeyFrame); - MSR_INTEGER(0, m_nKeyFramePeriod); -#endif - if (m_itrLate/10000 > it) { - m_bSkipping = TRUE; - // Now we are committed. Once we start skipping, we - // cannot stop until we hit a key frame. - } else { -#ifdef VTRANSPERF - MSR_INTEGER(0, 777770); // not near enough to next key -#endif - } - } else { -#ifdef VTRANSPERF - MSR_INTEGER(0, 777771); // Next key not predictable -#endif - } - } else { -#ifdef VTRANSPERF - MSR_INTEGER(0, 777772); // Less than one frame late - MSR_INTEGER(0, m_itrLate); - MSR_INTEGER(0, itrFrame); -#endif - } - } else { -#ifdef VTRANSPERF - MSR_INTEGER(0, 777773); // Decode time short - not not worth skipping - MSR_INTEGER(0, m_itrAvgDecode); - MSR_INTEGER(0, itrFrame); -#endif - } - - ++m_nFramesSinceKeyFrame; - - if (m_bSkipping) { - // We will count down the lateness as we skip each frame. - // We re-assess each frame. The key frame might not arrive when expected. - // We reset m_itrLate if we get a new Quality message, but actually that's - // not likely because we're not sending frames on to the Renderer. In - // fact if we DID get another one it would mean that there's a long - // pipe between us and the renderer and we might need an altogether - // better strategy to avoid hunting! - m_itrLate = m_itrLate - itrFrame; - } - - MSR_INTEGER(m_idLate, (int)m_itrLate/10000 ); // Note how late we think we are - if (m_bSkipping) { - if (!m_bQualityChanged) { - m_bQualityChanged = TRUE; - NotifyEvent(EC_QUALITY_CHANGE,0,0); - } - } - return m_bSkipping; -} - - -HRESULT CVideoTransformFilter::AlterQuality(Quality q) -{ - // to reduce the amount of 64 bit arithmetic, m_itrLate is an int. - // +, -, >, == etc are not too bad, but * and / are painful. - if (m_itrLate>300000000) { - // Avoid overflow and silliness - more than 30 secs late is already silly - m_itrLate = 300000000; - } else { - m_itrLate = (int)q.Late; - } - // We ignore the other fields - - // We're actually not very good at handling this. In non-direct draw mode - // most of the time can be spent in the renderer which can skip any frame. - // In that case we'd rather the renderer handled things. - // Nevertheless we will keep an eye on it and if we really start getting - // a very long way behind then we will actually skip - but we'll still tell - // the renderer (or whoever is downstream) that they should handle quality. - - return E_FAIL; // Tell the renderer to do his thing. - -} - - - -// This will avoid several hundred useless warnings if compiled -W4 by MS VC++ v4 -#pragma warning(disable:4514) - +//------------------------------------------------------------------------------ +// File: Vtrans.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include "measure.h" +// #include // now in precomp file streams.h + +CVideoTransformFilter::CVideoTransformFilter + ( TCHAR *pName, LPUNKNOWN pUnk, REFCLSID clsid) + : CTransformFilter(pName, pUnk, clsid) + , m_itrLate(0) + , m_nKeyFramePeriod(0) // No QM until we see at least 2 key frames + , m_nFramesSinceKeyFrame(0) + , m_bSkipping(FALSE) + , m_tDecodeStart(0) + , m_itrAvgDecode(300000) // 30mSec - probably allows skipping + , m_bQualityChanged(FALSE) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF +} + + +CVideoTransformFilter::~CVideoTransformFilter() +{ + // nothing to do +} + + +// Reset our quality management state + +HRESULT CVideoTransformFilter::StartStreaming() +{ + m_itrLate = 0; + m_nKeyFramePeriod = 0; // No QM until we see at least 2 key frames + m_nFramesSinceKeyFrame = 0; + m_bSkipping = FALSE; + m_tDecodeStart = 0; + m_itrAvgDecode = 300000; // 30mSec - probably allows skipping + m_bQualityChanged = FALSE; + m_bSampleSkipped = FALSE; + return NOERROR; +} + + +// Overriden to reset quality management information + +HRESULT CVideoTransformFilter::EndFlush() +{ + { + // Synchronize + CAutoLock lck(&m_csReceive); + + // Reset our stats + // + // Note - we don't want to call derived classes here, + // we only want to reset our internal variables and this + // is a convenient way to do it + CVideoTransformFilter::StartStreaming(); + } + return CTransformFilter::EndFlush(); +} + + +HRESULT CVideoTransformFilter::AbortPlayback(HRESULT hr) +{ + NotifyEvent(EC_ERRORABORT, hr, 0); + m_pOutput->DeliverEndOfStream(); + return hr; +} + + +// Receive() +// +// Accept a sample from upstream, decide whether to process it +// or drop it. If we process it then get a buffer from the +// allocator of the downstream connection, transform it into the +// new buffer and deliver it to the downstream filter. +// If we decide not to process it then we do not get a buffer. + +// Remember that although this code will notice format changes coming into +// the input pin, it will NOT change its output format if that results +// in the filter needing to make a corresponding output format change. Your +// derived filter will have to take care of that. (eg. a palette change if +// the input and output is an 8 bit format). If the input sample is discarded +// and nothing is sent out for this Receive, please remember to put the format +// change on the first output sample that you actually do send. +// If your filter will produce the same output type even when the input type +// changes, then this base class code will do everything you need. + +HRESULT CVideoTransformFilter::Receive(IMediaSample *pSample) +{ + // If the next filter downstream is the video renderer, then it may + // be able to operate in DirectDraw mode which saves copying the data + // and gives higher performance. In that case the buffer which we + // get from GetDeliveryBuffer will be a DirectDraw buffer, and + // drawing into this buffer draws directly onto the display surface. + // This means that any waiting for the correct time to draw occurs + // during GetDeliveryBuffer, and that once the buffer is given to us + // the video renderer will count it in its statistics as a frame drawn. + // This means that any decision to drop the frame must be taken before + // calling GetDeliveryBuffer. + + ASSERT(CritCheckIn(&m_csReceive)); + AM_MEDIA_TYPE *pmtOut, *pmt; +#ifdef DEBUG + FOURCCMap fccOut; +#endif + HRESULT hr; + ASSERT(pSample); + IMediaSample * pOutSample; + + // If no output pin to deliver to then no point sending us data + ASSERT (m_pOutput != NULL) ; + + // The source filter may dynamically ask us to start transforming from a + // different media type than the one we're using now. If we don't, we'll + // draw garbage. (typically, this is a palette change in the movie, + // but could be something more sinister like the compression type changing, + // or even the video size changing) + +#define rcS1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcSource +#define rcT1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcTarget + + pSample->GetMediaType(&pmt); + if (pmt != NULL && pmt->pbFormat != NULL) { + + // spew some debug output + ASSERT(!IsEqualGUID(pmt->majortype, GUID_NULL)); +#ifdef DEBUG + fccOut.SetFOURCC(&pmt->subtype); + LONG lCompression = HEADER(pmt->pbFormat)->biCompression; + LONG lBitCount = HEADER(pmt->pbFormat)->biBitCount; + LONG lStride = (HEADER(pmt->pbFormat)->biWidth * lBitCount + 7) / 8; + lStride = (lStride + 3) & ~3; + DbgLog((LOG_TRACE,3,TEXT("*Changing input type on the fly to"))); + DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"), + fccOut.GetFOURCC(), lCompression, lBitCount)); + DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"), + HEADER(pmt->pbFormat)->biHeight, + rcT1.left, rcT1.top, rcT1.right, rcT1.bottom)); + DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"), + rcS1.left, rcS1.top, rcS1.right, rcS1.bottom, + lStride)); +#endif + + // now switch to using the new format. I am assuming that the + // derived filter will do the right thing when its media type is + // switched and streaming is restarted. + + StopStreaming(); + m_pInput->CurrentMediaType() = *pmt; + DeleteMediaType(pmt); + // if this fails, playback will stop, so signal an error + hr = StartStreaming(); + if (FAILED(hr)) { + return AbortPlayback(hr); + } + } + + // Now that we have noticed any format changes on the input sample, it's + // OK to discard it. + + if (ShouldSkipFrame(pSample)) { + MSR_NOTE(m_idSkip); + m_bSampleSkipped = TRUE; + return NOERROR; + } + + // Set up the output sample + hr = InitializeOutputSample(pSample, &pOutSample); + + if (FAILED(hr)) { + return hr; + } + + m_bSampleSkipped = FALSE; + + // The renderer may ask us to on-the-fly to start transforming to a + // different format. If we don't obey it, we'll draw garbage + +#define rcS ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcSource +#define rcT ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcTarget + + pOutSample->GetMediaType(&pmtOut); + if (pmtOut != NULL && pmtOut->pbFormat != NULL) { + + // spew some debug output + ASSERT(!IsEqualGUID(pmtOut->majortype, GUID_NULL)); +#ifdef DEBUG + fccOut.SetFOURCC(&pmtOut->subtype); + LONG lCompression = HEADER(pmtOut->pbFormat)->biCompression; + LONG lBitCount = HEADER(pmtOut->pbFormat)->biBitCount; + LONG lStride = (HEADER(pmtOut->pbFormat)->biWidth * lBitCount + 7) / 8; + lStride = (lStride + 3) & ~3; + DbgLog((LOG_TRACE,3,TEXT("*Changing output type on the fly to"))); + DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"), + fccOut.GetFOURCC(), lCompression, lBitCount)); + DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"), + HEADER(pmtOut->pbFormat)->biHeight, + rcT.left, rcT.top, rcT.right, rcT.bottom)); + DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"), + rcS.left, rcS.top, rcS.right, rcS.bottom, + lStride)); +#endif + + // now switch to using the new format. I am assuming that the + // derived filter will do the right thing when its media type is + // switched and streaming is restarted. + + StopStreaming(); + m_pOutput->CurrentMediaType() = *pmtOut; + DeleteMediaType(pmtOut); + hr = StartStreaming(); + + if (SUCCEEDED(hr)) { + // a new format, means a new empty buffer, so wait for a keyframe + // before passing anything on to the renderer. + // !!! a keyframe may never come, so give up after 30 frames + DbgLog((LOG_TRACE,3,TEXT("Output format change means we must wait for a keyframe"))); + m_nWaitForKey = 30; + + // if this fails, playback will stop, so signal an error + } else { + + // Must release the sample before calling AbortPlayback + // because we might be holding the win16 lock or + // ddraw lock + pOutSample->Release(); + AbortPlayback(hr); + return hr; + } + } + + // After a discontinuity, we need to wait for the next key frame + if (pSample->IsDiscontinuity() == S_OK) { + DbgLog((LOG_TRACE,3,TEXT("Non-key discontinuity - wait for keyframe"))); + m_nWaitForKey = 30; + } + + // Start timing the transform (and log it if PERF is defined) + + if (SUCCEEDED(hr)) { + m_tDecodeStart = timeGetTime(); + MSR_START(m_idTransform); + + // have the derived class transform the data + hr = Transform(pSample, pOutSample); + + // Stop the clock (and log it if PERF is defined) + MSR_STOP(m_idTransform); + m_tDecodeStart = timeGetTime()-m_tDecodeStart; + m_itrAvgDecode = m_tDecodeStart*(10000/16) + 15*(m_itrAvgDecode/16); + + // Maybe we're waiting for a keyframe still? + if (m_nWaitForKey) + m_nWaitForKey--; + if (m_nWaitForKey && pSample->IsSyncPoint() == S_OK) + m_nWaitForKey = FALSE; + + // if so, then we don't want to pass this on to the renderer + if (m_nWaitForKey && hr == NOERROR) { + DbgLog((LOG_TRACE,3,TEXT("still waiting for a keyframe"))); + hr = S_FALSE; + } + } + + if (FAILED(hr)) { + DbgLog((LOG_TRACE,1,TEXT("Error from video transform"))); + } else { + // the Transform() function can return S_FALSE to indicate that the + // sample should not be delivered; we only deliver the sample if it's + // really S_OK (same as NOERROR, of course.) + // Try not to return S_FALSE to a direct draw buffer (it's wasteful) + // Try to take the decision earlier - before you get it. + + if (hr == NOERROR) { + hr = m_pOutput->Deliver(pOutSample); + } else { + // S_FALSE returned from Transform is a PRIVATE agreement + // We should return NOERROR from Receive() in this case because returning S_FALSE + // from Receive() means that this is the end of the stream and no more data should + // be sent. + if (S_FALSE == hr) { + + // We must Release() the sample before doing anything + // like calling the filter graph because having the + // sample means we may have the DirectDraw lock + // (== win16 lock on some versions) + pOutSample->Release(); + m_bSampleSkipped = TRUE; + if (!m_bQualityChanged) { + m_bQualityChanged = TRUE; + NotifyEvent(EC_QUALITY_CHANGE,0,0); + } + return NOERROR; + } + } + } + + // release the output buffer. If the connected pin still needs it, + // it will have addrefed it itself. + pOutSample->Release(); + ASSERT(CritCheckIn(&m_csReceive)); + + return hr; +} + + + +BOOL CVideoTransformFilter::ShouldSkipFrame( IMediaSample * pIn) +{ + REFERENCE_TIME trStart, trStopAt; + HRESULT hr = pIn->GetTime(&trStart, &trStopAt); + + // Don't skip frames with no timestamps + if (hr != S_OK) + return FALSE; + + int itrFrame = (int)(trStopAt - trStart); // frame duration + + if(S_OK==pIn->IsSyncPoint()) { + MSR_INTEGER(m_idFrameType, 1); + if ( m_nKeyFramePeriod < m_nFramesSinceKeyFrame ) { + // record the max + m_nKeyFramePeriod = m_nFramesSinceKeyFrame; + } + m_nFramesSinceKeyFrame = 0; + m_bSkipping = FALSE; + } else { + MSR_INTEGER(m_idFrameType, 2); + if ( m_nFramesSinceKeyFrame>m_nKeyFramePeriod + && m_nKeyFramePeriod>0 + ) { + // We haven't seen the key frame yet, but we were clearly being + // overoptimistic about how frequent they are. + m_nKeyFramePeriod = m_nFramesSinceKeyFrame; + } + } + + + // Whatever we might otherwise decide, + // if we are taking only a small fraction of the required frame time to decode + // then any quality problems are actually coming from somewhere else. + // Could be a net problem at the source for instance. In this case there's + // no point in us skipping frames here. + if (m_itrAvgDecode*4>itrFrame) { + + // Don't skip unless we are at least a whole frame late. + // (We would skip B frames if more than 1/2 frame late, but they're safe). + if ( m_itrLate > itrFrame ) { + + // Don't skip unless the anticipated key frame would be no more than + // 1 frame early. If the renderer has not been waiting (we *guess* + // it hasn't because we're late) then it will allow frames to be + // played early by up to a frame. + + // Let T = Stream time from now to anticipated next key frame + // = (frame duration) * (KeyFramePeriod - FramesSinceKeyFrame) + // So we skip if T - Late < one frame i.e. + // (duration) * (freq - FramesSince) - Late < duration + // or (duration) * (freq - FramesSince - 1) < Late + + // We don't dare skip until we have seen some key frames and have + // some idea how often they occur and they are reasonably frequent. + if (m_nKeyFramePeriod>0) { + // It would be crazy - but we could have a stream with key frames + // a very long way apart - and if they are further than about + // 3.5 minutes apart then we could get arithmetic overflow in + // reference time units. Therefore we switch to mSec at this point + int it = (itrFrame/10000) + * (m_nKeyFramePeriod-m_nFramesSinceKeyFrame - 1); + MSR_INTEGER(m_idTimeTillKey, it); + + // For debug - might want to see the details - dump them as scratch pad +#ifdef VTRANSPERF + MSR_INTEGER(0, itrFrame); + MSR_INTEGER(0, m_nFramesSinceKeyFrame); + MSR_INTEGER(0, m_nKeyFramePeriod); +#endif + if (m_itrLate/10000 > it) { + m_bSkipping = TRUE; + // Now we are committed. Once we start skipping, we + // cannot stop until we hit a key frame. + } else { +#ifdef VTRANSPERF + MSR_INTEGER(0, 777770); // not near enough to next key +#endif + } + } else { +#ifdef VTRANSPERF + MSR_INTEGER(0, 777771); // Next key not predictable +#endif + } + } else { +#ifdef VTRANSPERF + MSR_INTEGER(0, 777772); // Less than one frame late + MSR_INTEGER(0, m_itrLate); + MSR_INTEGER(0, itrFrame); +#endif + } + } else { +#ifdef VTRANSPERF + MSR_INTEGER(0, 777773); // Decode time short - not not worth skipping + MSR_INTEGER(0, m_itrAvgDecode); + MSR_INTEGER(0, itrFrame); +#endif + } + + ++m_nFramesSinceKeyFrame; + + if (m_bSkipping) { + // We will count down the lateness as we skip each frame. + // We re-assess each frame. The key frame might not arrive when expected. + // We reset m_itrLate if we get a new Quality message, but actually that's + // not likely because we're not sending frames on to the Renderer. In + // fact if we DID get another one it would mean that there's a long + // pipe between us and the renderer and we might need an altogether + // better strategy to avoid hunting! + m_itrLate = m_itrLate - itrFrame; + } + + MSR_INTEGER(m_idLate, (int)m_itrLate/10000 ); // Note how late we think we are + if (m_bSkipping) { + if (!m_bQualityChanged) { + m_bQualityChanged = TRUE; + NotifyEvent(EC_QUALITY_CHANGE,0,0); + } + } + return m_bSkipping; +} + + +HRESULT CVideoTransformFilter::AlterQuality(Quality q) +{ + // to reduce the amount of 64 bit arithmetic, m_itrLate is an int. + // +, -, >, == etc are not too bad, but * and / are painful. + if (m_itrLate>300000000) { + // Avoid overflow and silliness - more than 30 secs late is already silly + m_itrLate = 300000000; + } else { + m_itrLate = (int)q.Late; + } + // We ignore the other fields + + // We're actually not very good at handling this. In non-direct draw mode + // most of the time can be spent in the renderer which can skip any frame. + // In that case we'd rather the renderer handled things. + // Nevertheless we will keep an eye on it and if we really start getting + // a very long way behind then we will actually skip - but we'll still tell + // the renderer (or whoever is downstream) that they should handle quality. + + return E_FAIL; // Tell the renderer to do his thing. + +} + + + +// This will avoid several hundred useless warnings if compiled -W4 by MS VC++ v4 +#pragma warning(disable:4514) + diff --git a/plugins/GSdx/baseclasses/vtrans.h b/plugins/GSdx/baseclasses/vtrans.h index a9c1d6bde1..05a8aefc1c 100644 --- a/plugins/GSdx/baseclasses/vtrans.h +++ b/plugins/GSdx/baseclasses/vtrans.h @@ -1,143 +1,143 @@ -//------------------------------------------------------------------------------ -// File: VTrans.h -// -// Desc: DirectShow base classes - defines a video transform class. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// This class is derived from CTransformFilter, but is specialised to handle -// the requirements of video quality control by frame dropping. -// This is a non-in-place transform, (i.e. it copies the data) such as a decoder. - -class CVideoTransformFilter : public CTransformFilter -{ - public: - - CVideoTransformFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid); - ~CVideoTransformFilter(); - HRESULT EndFlush(); - - // ================================================================= - // ----- override these bits --------------------------------------- - // ================================================================= - // The following methods are in CTransformFilter which is inherited. - // They are mentioned here for completeness - // - // These MUST be supplied in a derived class - // - // NOTE: - // virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut); - // virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE; - // virtual HRESULT CheckTransform - // (const CMediaType* mtIn, const CMediaType* mtOut) PURE; - // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *); - // virtual HRESULT DecideBufferSize - // (IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop) PURE; - // virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE; - // - // These MAY also be overridden - // - // virtual HRESULT StopStreaming(); - // virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt); - // virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin); - // virtual HRESULT BreakConnect(PIN_DIRECTION dir); - // virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin); - // virtual HRESULT EndOfStream(void); - // virtual HRESULT BeginFlush(void); - // virtual HRESULT EndFlush(void); - // virtual HRESULT NewSegment - // (REFERENCE_TIME tStart,REFERENCE_TIME tStop,double dRate); -#ifdef PERF - - // If you override this - ensure that you register all these ids - // as well as any of your own, - virtual void RegisterPerfId() { - m_idSkip = MSR_REGISTER(TEXT("Video Transform Skip frame")); - m_idFrameType = MSR_REGISTER(TEXT("Video transform frame type")); - m_idLate = MSR_REGISTER(TEXT("Video Transform Lateness")); - m_idTimeTillKey = MSR_REGISTER(TEXT("Video Transform Estd. time to next key")); - CTransformFilter::RegisterPerfId(); - } -#endif - - protected: - - // =========== QUALITY MANAGEMENT IMPLEMENTATION ======================== - // Frames are assumed to come in three types: - // Type 1: an AVI key frame or an MPEG I frame. - // This frame can be decoded with no history. - // Dropping this frame means that no further frame can be decoded - // until the next type 1 frame. - // Type 1 frames are sync points. - // Type 2: an AVI non-key frame or an MPEG P frame. - // This frame cannot be decoded unless the previous type 1 frame was - // decoded and all type 2 frames since have been decoded. - // Dropping this frame means that no further frame can be decoded - // until the next type 1 frame. - // Type 3: An MPEG B frame. - // This frame cannot be decoded unless the previous type 1 or 2 frame - // has been decoded AND the subsequent type 1 or 2 frame has also - // been decoded. (This requires decoding the frames out of sequence). - // Dropping this frame affects no other frames. This implementation - // does not allow for these. All non-sync-point frames are treated - // as being type 2. - // - // The spacing of frames of type 1 in a file is not guaranteed. There MUST - // be a type 1 frame at (well, near) the start of the file in order to start - // decoding at all. After that there could be one every half second or so, - // there could be one at the start of each scene (aka "cut", "shot") or - // there could be no more at all. - // If there is only a single type 1 frame then NO FRAMES CAN BE DROPPED - // without losing all the rest of the movie. There is no way to tell whether - // this is the case, so we find that we are in the gambling business. - // To try to improve the odds, we record the greatest interval between type 1s - // that we have seen and we bet on things being no worse than this in the - // future. - - // You can tell if it's a type 1 frame by calling IsSyncPoint(). - // there is no architected way to test for a type 3, so you should override - // the quality management here if you have B-frames. - - int m_nKeyFramePeriod; // the largest observed interval between type 1 frames - // 1 means every frame is type 1, 2 means every other. - - int m_nFramesSinceKeyFrame; // Used to count frames since the last type 1. - // becomes the new m_nKeyFramePeriod if greater. - - BOOL m_bSkipping; // we are skipping to the next type 1 frame - -#ifdef PERF - int m_idFrameType; // MSR id Frame type. 1=Key, 2="non-key" - int m_idSkip; // MSR id skipping - int m_idLate; // MSR id lateness - int m_idTimeTillKey; // MSR id for guessed time till next key frame. -#endif - - virtual HRESULT StartStreaming(); - - HRESULT AbortPlayback(HRESULT hr); // if something bad happens - - HRESULT Receive(IMediaSample *pSample); - - HRESULT AlterQuality(Quality q); - - BOOL ShouldSkipFrame(IMediaSample * pIn); - - int m_itrLate; // lateness from last Quality message - // (this overflows at 214 secs late). - int m_tDecodeStart; // timeGetTime when decode started. - int m_itrAvgDecode; // Average decode time in reference units. - - BOOL m_bNoSkip; // debug - no skipping. - - // We send an EC_QUALITY_CHANGE notification to the app if we have to degrade. - // We send one when we start degrading, not one for every frame, this means - // we track whether we've sent one yet. - BOOL m_bQualityChanged; - - // When non-zero, don't pass anything to renderer until next keyframe - // If there are few keys, give up and eventually draw something - int m_nWaitForKey; -}; +//------------------------------------------------------------------------------ +// File: VTrans.h +// +// Desc: DirectShow base classes - defines a video transform class. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// This class is derived from CTransformFilter, but is specialised to handle +// the requirements of video quality control by frame dropping. +// This is a non-in-place transform, (i.e. it copies the data) such as a decoder. + +class CVideoTransformFilter : public CTransformFilter +{ + public: + + CVideoTransformFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid); + ~CVideoTransformFilter(); + HRESULT EndFlush(); + + // ================================================================= + // ----- override these bits --------------------------------------- + // ================================================================= + // The following methods are in CTransformFilter which is inherited. + // They are mentioned here for completeness + // + // These MUST be supplied in a derived class + // + // NOTE: + // virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut); + // virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE; + // virtual HRESULT CheckTransform + // (const CMediaType* mtIn, const CMediaType* mtOut) PURE; + // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *); + // virtual HRESULT DecideBufferSize + // (IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop) PURE; + // virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE; + // + // These MAY also be overridden + // + // virtual HRESULT StopStreaming(); + // virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt); + // virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin); + // virtual HRESULT BreakConnect(PIN_DIRECTION dir); + // virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin); + // virtual HRESULT EndOfStream(void); + // virtual HRESULT BeginFlush(void); + // virtual HRESULT EndFlush(void); + // virtual HRESULT NewSegment + // (REFERENCE_TIME tStart,REFERENCE_TIME tStop,double dRate); +#ifdef PERF + + // If you override this - ensure that you register all these ids + // as well as any of your own, + virtual void RegisterPerfId() { + m_idSkip = MSR_REGISTER(TEXT("Video Transform Skip frame")); + m_idFrameType = MSR_REGISTER(TEXT("Video transform frame type")); + m_idLate = MSR_REGISTER(TEXT("Video Transform Lateness")); + m_idTimeTillKey = MSR_REGISTER(TEXT("Video Transform Estd. time to next key")); + CTransformFilter::RegisterPerfId(); + } +#endif + + protected: + + // =========== QUALITY MANAGEMENT IMPLEMENTATION ======================== + // Frames are assumed to come in three types: + // Type 1: an AVI key frame or an MPEG I frame. + // This frame can be decoded with no history. + // Dropping this frame means that no further frame can be decoded + // until the next type 1 frame. + // Type 1 frames are sync points. + // Type 2: an AVI non-key frame or an MPEG P frame. + // This frame cannot be decoded unless the previous type 1 frame was + // decoded and all type 2 frames since have been decoded. + // Dropping this frame means that no further frame can be decoded + // until the next type 1 frame. + // Type 3: An MPEG B frame. + // This frame cannot be decoded unless the previous type 1 or 2 frame + // has been decoded AND the subsequent type 1 or 2 frame has also + // been decoded. (This requires decoding the frames out of sequence). + // Dropping this frame affects no other frames. This implementation + // does not allow for these. All non-sync-point frames are treated + // as being type 2. + // + // The spacing of frames of type 1 in a file is not guaranteed. There MUST + // be a type 1 frame at (well, near) the start of the file in order to start + // decoding at all. After that there could be one every half second or so, + // there could be one at the start of each scene (aka "cut", "shot") or + // there could be no more at all. + // If there is only a single type 1 frame then NO FRAMES CAN BE DROPPED + // without losing all the rest of the movie. There is no way to tell whether + // this is the case, so we find that we are in the gambling business. + // To try to improve the odds, we record the greatest interval between type 1s + // that we have seen and we bet on things being no worse than this in the + // future. + + // You can tell if it's a type 1 frame by calling IsSyncPoint(). + // there is no architected way to test for a type 3, so you should override + // the quality management here if you have B-frames. + + int m_nKeyFramePeriod; // the largest observed interval between type 1 frames + // 1 means every frame is type 1, 2 means every other. + + int m_nFramesSinceKeyFrame; // Used to count frames since the last type 1. + // becomes the new m_nKeyFramePeriod if greater. + + BOOL m_bSkipping; // we are skipping to the next type 1 frame + +#ifdef PERF + int m_idFrameType; // MSR id Frame type. 1=Key, 2="non-key" + int m_idSkip; // MSR id skipping + int m_idLate; // MSR id lateness + int m_idTimeTillKey; // MSR id for guessed time till next key frame. +#endif + + virtual HRESULT StartStreaming(); + + HRESULT AbortPlayback(HRESULT hr); // if something bad happens + + HRESULT Receive(IMediaSample *pSample); + + HRESULT AlterQuality(Quality q); + + BOOL ShouldSkipFrame(IMediaSample * pIn); + + int m_itrLate; // lateness from last Quality message + // (this overflows at 214 secs late). + int m_tDecodeStart; // timeGetTime when decode started. + int m_itrAvgDecode; // Average decode time in reference units. + + BOOL m_bNoSkip; // debug - no skipping. + + // We send an EC_QUALITY_CHANGE notification to the app if we have to degrade. + // We send one when we start degrading, not one for every frame, this means + // we track whether we've sent one yet. + BOOL m_bQualityChanged; + + // When non-zero, don't pass anything to renderer until next keyframe + // If there are few keys, give up and eventually draw something + int m_nWaitForKey; +}; diff --git a/plugins/GSdx/baseclasses/wxdebug.cpp b/plugins/GSdx/baseclasses/wxdebug.cpp index 3cb0b42ce7..00ab7bb2d9 100644 --- a/plugins/GSdx/baseclasses/wxdebug.cpp +++ b/plugins/GSdx/baseclasses/wxdebug.cpp @@ -1,1418 +1,1418 @@ -//------------------------------------------------------------------------------ -// File: WXDebug.cpp -// -// Desc: DirectShow base classes - implements ActiveX system debugging -// facilities. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include -#include - -#ifdef DEBUG -#ifdef UNICODE -#ifndef _UNICODE -#define _UNICODE -#endif // _UNICODE -#endif // UNICODE -#endif // DEBUG - -#ifdef DEBUG - -// The Win32 wsprintf() function writes a maximum of 1024 characters to it's output buffer. -// See the documentation for wsprintf()'s lpOut parameter for more information. -const INT iDEBUGINFO = 1024; // Used to format strings - -/* For every module and executable we store a debugging level for each of - the five categories (eg LOG_ERROR and LOG_TIMING). This makes it easy - to isolate and debug individual modules without seeing everybody elses - spurious debug output. The keys are stored in the registry under the - HKEY_LOCAL_MACHINE\SOFTWARE\Debug\\ key values - NOTE these must be in the same order as their enumeration definition */ - -TCHAR *pKeyNames[] = { - TEXT("TIMING"), // Timing and performance measurements - TEXT("TRACE"), // General step point call tracing - TEXT("MEMORY"), // Memory and object allocation/destruction - TEXT("LOCKING"), // Locking/unlocking of critical sections - TEXT("ERROR"), // Debug error notification - TEXT("CUSTOM1"), - TEXT("CUSTOM2"), - TEXT("CUSTOM3"), - TEXT("CUSTOM4"), - TEXT("CUSTOM5") - }; - -const TCHAR CAutoTrace::_szEntering[] = TEXT("->: %s"); -const TCHAR CAutoTrace::_szLeaving[] = TEXT("<-: %s"); - -const INT iMAXLEVELS = NUMELMS(pKeyNames); // Maximum debug categories - -HINSTANCE m_hInst; // Module instance handle -TCHAR m_ModuleName[iDEBUGINFO]; // Cut down module name -DWORD m_Levels[iMAXLEVELS]; // Debug level per category -CRITICAL_SECTION m_CSDebug; // Controls access to list -DWORD m_dwNextCookie; // Next active object ID -ObjectDesc *pListHead = NULL; // First active object -DWORD m_dwObjectCount; // Active object count -BOOL m_bInit = FALSE; // Have we been initialised -HANDLE m_hOutput = INVALID_HANDLE_VALUE; // Optional output written here -DWORD dwWaitTimeout = INFINITE; // Default timeout value -DWORD dwTimeOffset; // Time of first DbgLog call -bool g_fUseKASSERT = false; // don't create messagebox -bool g_fDbgInDllEntryPoint = false; -bool g_fAutoRefreshLevels = false; - -const TCHAR *pBaseKey = TEXT("SOFTWARE\\Debug"); -const TCHAR *pGlobalKey = TEXT("GLOBAL"); -static CHAR *pUnknownName = "UNKNOWN"; - -TCHAR *TimeoutName = TEXT("TIMEOUT"); - -/* This sets the instance handle that the debug library uses to find - the module's file name from the Win32 GetModuleFileName function */ - -void WINAPI DbgInitialise(HINSTANCE hInst) -{ - InitializeCriticalSection(&m_CSDebug); - m_bInit = TRUE; - - m_hInst = hInst; - DbgInitModuleName(); - if (GetProfileInt(m_ModuleName, TEXT("BreakOnLoad"), 0)) - DebugBreak(); - DbgInitModuleSettings(false); - DbgInitGlobalSettings(true); - dwTimeOffset = timeGetTime(); -} - - -/* This is called to clear up any resources the debug library uses - at the - moment we delete our critical section and the object list. The values we - retrieve from the registry are all done during initialisation but we don't - go looking for update notifications while we are running, if the values - are changed then the application has to be restarted to pick them up */ - -void WINAPI DbgTerminate() -{ - if (m_hOutput != INVALID_HANDLE_VALUE) { - EXECUTE_ASSERT(CloseHandle(m_hOutput)); - m_hOutput = INVALID_HANDLE_VALUE; - } - DeleteCriticalSection(&m_CSDebug); - m_bInit = FALSE; -} - - -/* This is called by DbgInitLogLevels to read the debug settings - for each logging category for this module from the registry */ - -void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax) -{ - LONG lReturn; // Create key return value - LONG lKeyPos; // Current key category - DWORD dwKeySize; // Size of the key value - DWORD dwKeyType; // Receives it's type - DWORD dwKeyValue; // This fields value - - /* Try and read a value for each key position in turn */ - for (lKeyPos = 0;lKeyPos < iMAXLEVELS;lKeyPos++) { - - dwKeySize = sizeof(DWORD); - lReturn = RegQueryValueEx( - hKey, // Handle to an open key - pKeyNames[lKeyPos], // Subkey name derivation - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE) &dwKeyValue, // Returns the field's value - &dwKeySize ); // Number of bytes transferred - - /* If either the key was not available or it was not a DWORD value - then we ensure only the high priority debug logging is output - but we try and update the field to a zero filled DWORD value */ - - if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) { - - dwKeyValue = 0; - lReturn = RegSetValueEx( - hKey, // Handle of an open key - pKeyNames[lKeyPos], // Address of subkey name - (DWORD) 0, // Reserved field - REG_DWORD, // Type of the key field - (PBYTE) &dwKeyValue, // Value for the field - sizeof(DWORD)); // Size of the field buffer - - if (lReturn != ERROR_SUCCESS) { - DbgLog((LOG_ERROR,0,TEXT("Could not create subkey %s"),pKeyNames[lKeyPos])); - dwKeyValue = 0; - } - } - if(fTakeMax) - { - m_Levels[lKeyPos] = max(dwKeyValue,m_Levels[lKeyPos]); - } - else - { - if((m_Levels[lKeyPos] & LOG_FORCIBLY_SET) == 0) { - m_Levels[lKeyPos] = dwKeyValue; - } - } - } - - /* Read the timeout value for catching hangs */ - dwKeySize = sizeof(DWORD); - lReturn = RegQueryValueEx( - hKey, // Handle to an open key - TimeoutName, // Subkey name derivation - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE) &dwWaitTimeout, // Returns the field's value - &dwKeySize ); // Number of bytes transferred - - /* If either the key was not available or it was not a DWORD value - then we ensure only the high priority debug logging is output - but we try and update the field to a zero filled DWORD value */ - - if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) { - - dwWaitTimeout = INFINITE; - lReturn = RegSetValueEx( - hKey, // Handle of an open key - TimeoutName, // Address of subkey name - (DWORD) 0, // Reserved field - REG_DWORD, // Type of the key field - (PBYTE) &dwWaitTimeout, // Value for the field - sizeof(DWORD)); // Size of the field buffer - - if (lReturn != ERROR_SUCCESS) { - DbgLog((LOG_ERROR,0,TEXT("Could not create subkey %s"),TimeoutName)); - dwWaitTimeout = INFINITE; - } - } -} - -void WINAPI DbgOutString(LPCTSTR psz) -{ - if (m_hOutput != INVALID_HANDLE_VALUE) { - UINT cb = lstrlen(psz); - DWORD dw; -#ifdef UNICODE - CHAR szDest[2048]; - WideCharToMultiByte(CP_ACP, 0, psz, -1, szDest, NUMELMS(szDest), 0, 0); - WriteFile (m_hOutput, szDest, cb, &dw, NULL); -#else - WriteFile (m_hOutput, psz, cb, &dw, NULL); -#endif - } else { - OutputDebugString (psz); - } -} - -/* Called by DbgInitGlobalSettings to setup alternate logging destinations - */ - -void WINAPI DbgInitLogTo ( - HKEY hKey) -{ - LONG lReturn; - DWORD dwKeyType; - DWORD dwKeySize; - TCHAR szFile[MAX_PATH] = {0}; - static const TCHAR cszKey[] = TEXT("LogToFile"); - - dwKeySize = MAX_PATH; - lReturn = RegQueryValueEx( - hKey, // Handle to an open key - cszKey, // Subkey name derivation - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE) szFile, // Returns the field's value - &dwKeySize); // Number of bytes transferred - - // create an empty key if it does not already exist - // - if (lReturn != ERROR_SUCCESS || dwKeyType != REG_SZ) - { - dwKeySize = sizeof(TCHAR); - lReturn = RegSetValueEx( - hKey, // Handle of an open key - cszKey, // Address of subkey name - (DWORD) 0, // Reserved field - REG_SZ, // Type of the key field - (PBYTE)szFile, // Value for the field - dwKeySize); // Size of the field buffer - } - - // if an output-to was specified. try to open it. - // - if (m_hOutput != INVALID_HANDLE_VALUE) { - EXECUTE_ASSERT(CloseHandle (m_hOutput)); - m_hOutput = INVALID_HANDLE_VALUE; - } - if (szFile[0] != 0) - { - if (!lstrcmpi(szFile, TEXT("Console"))) { - m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE); - if (m_hOutput == INVALID_HANDLE_VALUE) { - AllocConsole (); - m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE); - } - SetConsoleTitle (TEXT("ActiveX Debug Output")); - } else if (szFile[0] && - lstrcmpi(szFile, TEXT("Debug")) && - lstrcmpi(szFile, TEXT("Debugger")) && - lstrcmpi(szFile, TEXT("Deb"))) - { - m_hOutput = CreateFile(szFile, GENERIC_WRITE, - FILE_SHARE_READ, - NULL, OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); - if (INVALID_HANDLE_VALUE != m_hOutput) - { - static const TCHAR cszBar[] = TEXT("\r\n\r\n=====DbgInitialize()=====\r\n\r\n"); - SetFilePointer (m_hOutput, 0, NULL, FILE_END); - DbgOutString (cszBar); - } - } - } -} - - - -/* This is called by DbgInitLogLevels to read the global debug settings for - each logging category for this module from the registry. Normally each - module has it's own values set for it's different debug categories but - setting the global SOFTWARE\Debug\Global applies them to ALL modules */ - -void WINAPI DbgInitGlobalSettings(bool fTakeMax) -{ - LONG lReturn; // Create key return value - TCHAR szInfo[iDEBUGINFO]; // Constructs key names - HKEY hGlobalKey; // Global override key - - /* Construct the global base key name */ - (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%s\\%s"),pBaseKey,pGlobalKey); - - /* Create or open the key for this module */ - lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key - szInfo, // Address of subkey name - (DWORD) 0, // Reserved value - NULL, // Address of class name - (DWORD) 0, // Special options flags - KEY_ALL_ACCESS, // Desired security access - NULL, // Key security descriptor - &hGlobalKey, // Opened handle buffer - NULL); // What really happened - - if (lReturn != ERROR_SUCCESS) { - DbgLog((LOG_ERROR,0,TEXT("Could not access GLOBAL module key"))); - return; - } - - DbgInitKeyLevels(hGlobalKey, fTakeMax); - RegCloseKey(hGlobalKey); -} - - -/* This sets the debugging log levels for the different categories. We start - by opening (or creating if not already available) the SOFTWARE\Debug key - that all these settings live under. We then look at the global values - set under SOFTWARE\Debug\Global which apply on top of the individual - module settings. We then load the individual module registry settings */ - -void WINAPI DbgInitModuleSettings(bool fTakeMax) -{ - LONG lReturn; // Create key return value - TCHAR szInfo[iDEBUGINFO]; // Constructs key names - HKEY hModuleKey; // Module key handle - - /* Construct the base key name */ - (void)StringCchPrintf(szInfo,NUMELMS(szInfo), TEXT("%s\\%s"),pBaseKey,m_ModuleName); - - /* Create or open the key for this module */ - lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key - szInfo, // Address of subkey name - (DWORD) 0, // Reserved value - NULL, // Address of class name - (DWORD) 0, // Special options flags - KEY_ALL_ACCESS, // Desired security access - NULL, // Key security descriptor - &hModuleKey, // Opened handle buffer - NULL); // What really happened - - if (lReturn != ERROR_SUCCESS) { - DbgLog((LOG_ERROR,0,TEXT("Could not access module key"))); - return; - } - - DbgInitLogTo(hModuleKey); - DbgInitKeyLevels(hModuleKey, fTakeMax); - RegCloseKey(hModuleKey); -} - - -/* Initialise the module file name */ - -void WINAPI DbgInitModuleName() -{ - TCHAR FullName[iDEBUGINFO]; // Load the full path and module name - TCHAR *pName; // Searches from the end for a backslash - - GetModuleFileName(m_hInst,FullName,iDEBUGINFO); - pName = _tcsrchr(FullName,'\\'); - if (pName == NULL) { - pName = FullName; - } else { - pName++; - } - (void)StringCchCopy(m_ModuleName,NUMELMS(m_ModuleName), pName); -} - -struct MsgBoxMsg -{ - HWND hwnd; - TCHAR *szTitle; - TCHAR *szMessage; - DWORD dwFlags; - INT iResult; -}; - -// -// create a thread to call MessageBox(). calling MessageBox() on -// random threads at bad times can confuse the host (eg IE). -// -DWORD WINAPI MsgBoxThread( - LPVOID lpParameter // thread data - ) -{ - MsgBoxMsg *pmsg = (MsgBoxMsg *)lpParameter; - pmsg->iResult = MessageBox( - pmsg->hwnd, - pmsg->szTitle, - pmsg->szMessage, - pmsg->dwFlags); - - return 0; -} - -INT MessageBoxOtherThread( - HWND hwnd, - TCHAR *szTitle, - TCHAR *szMessage, - DWORD dwFlags) -{ - if(g_fDbgInDllEntryPoint) - { - // can't wait on another thread because we have the loader - // lock held in the dll entry point. - return MessageBox(hwnd, szTitle, szMessage, dwFlags); - } - else - { - MsgBoxMsg msg = {hwnd, szTitle, szMessage, dwFlags, 0}; - DWORD dwid; - HANDLE hThread = CreateThread( - 0, // security - 0, // stack size - MsgBoxThread, - (void *)&msg, // arg - 0, // flags - &dwid); - if(hThread) - { - WaitForSingleObject(hThread, INFINITE); - CloseHandle(hThread); - return msg.iResult; - } - - // break into debugger on failure. - return IDCANCEL; - } -} - -/* Displays a message box if the condition evaluated to FALSE */ - -void WINAPI DbgAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine) -{ - if(g_fUseKASSERT) - { - DbgKernelAssert(pCondition, pFileName, iLine); - } - else - { - - TCHAR szInfo[iDEBUGINFO]; - - (void)StringCchPrintf(szInfo, NUMELMS(szInfo), TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"), - pCondition, iLine, pFileName); - - INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("ASSERT Failed"), - MB_SYSTEMMODAL | - MB_ICONHAND | - MB_YESNOCANCEL | - MB_SETFOREGROUND); - switch (MsgId) - { - case IDNO: /* Kill the application */ - - FatalAppExit(FALSE, TEXT("Application terminated")); - break; - - case IDCANCEL: /* Break into the debugger */ - - DebugBreak(); - break; - - case IDYES: /* Ignore assertion continue execution */ - break; - } - } -} - -/* Displays a message box at a break point */ - -void WINAPI DbgBreakPoint(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine) -{ - if(g_fUseKASSERT) - { - DbgKernelAssert(pCondition, pFileName, iLine); - } - else - { - TCHAR szInfo[iDEBUGINFO]; - - (void)StringCchPrintf(szInfo, NUMELMS(szInfo), TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"), - pCondition, iLine, pFileName); - - INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("Hard coded break point"), - MB_SYSTEMMODAL | - MB_ICONHAND | - MB_YESNOCANCEL | - MB_SETFOREGROUND); - switch (MsgId) - { - case IDNO: /* Kill the application */ - - FatalAppExit(FALSE, TEXT("Application terminated")); - break; - - case IDCANCEL: /* Break into the debugger */ - - DebugBreak(); - break; - - case IDYES: /* Ignore break point continue execution */ - break; - } - } -} - -void WINAPI DbgBreakPoint(const TCHAR *pFileName,INT iLine,const TCHAR* szFormatString,...) -{ - // A debug break point message can have at most 2000 characters if - // ANSI or UNICODE characters are being used. A debug break point message - // can have between 1000 and 2000 double byte characters in it. If a - // particular message needs more characters, then the value of this constant - // should be increased. - const DWORD MAX_BREAK_POINT_MESSAGE_SIZE = 2000; - - TCHAR szBreakPointMessage[MAX_BREAK_POINT_MESSAGE_SIZE]; - - const DWORD MAX_CHARS_IN_BREAK_POINT_MESSAGE = sizeof(szBreakPointMessage) / sizeof(TCHAR); - - va_list va; - va_start( va, szFormatString ); - - HRESULT hr = StringCchVPrintf( szBreakPointMessage, MAX_CHARS_IN_BREAK_POINT_MESSAGE, szFormatString, va ); - - va_end(va); - - if( S_OK != hr ) { - DbgBreak( "ERROR in DbgBreakPoint(). The variable length debug message could not be displayed because _vsnprintf() failed." ); - return; - } - - ::DbgBreakPoint( szBreakPointMessage, pFileName, iLine ); -} - - -/* When we initialised the library we stored in the m_Levels array the current - debug output level for this module for each of the five categories. When - some debug logging is sent to us it can be sent with a combination of the - categories (if it is applicable to many for example) in which case we map - the type's categories into their current debug levels and see if any of - them can be accepted. The function looks at each bit position in turn from - the input type field and then compares it's debug level with the modules. - - A level of 0 means that output is always sent to the debugger. This is - due to producing output if the input level is <= m_Levels. -*/ - - -BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level) -{ - if(g_fAutoRefreshLevels) - { - // re-read the registry every second. We cannot use RegNotify() to - // notice registry changes because it's not available on win9x. - static DWORD g_dwLastRefresh = 0; - DWORD dwTime = timeGetTime(); - if(dwTime - g_dwLastRefresh > 1000) { - g_dwLastRefresh = dwTime; - - // there's a race condition: multiple threads could update the - // values. plus read and write not synchronized. no harm - // though. - DbgInitModuleSettings(false); - } - } - - - DWORD Mask = 0x01; - - // If no valid bits are set return FALSE - if ((Type & ((1<m_szName = szObjectName; - pObject->m_wszName = wszObjectName; - pObject->m_dwCookie = ++m_dwNextCookie; - pObject->m_pNext = pListHead; - - pListHead = pObject; - m_dwObjectCount++; - - DWORD ObjectCookie = pObject->m_dwCookie; - ASSERT(ObjectCookie); - - if(wszObjectName) { - DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%ls) %d Active"), - pObject->m_dwCookie, wszObjectName, m_dwObjectCount)); - } else { - DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%hs) %d Active"), - pObject->m_dwCookie, szObjectName, m_dwObjectCount)); - } - - LeaveCriticalSection(&m_CSDebug); - return ObjectCookie; -} - - -/* This is called by the CBaseObject destructor when an object is about to be - destroyed, we are passed the cookie we returned during construction that - identifies this object. We scan the object list for a matching cookie and - remove the object if successful. We also update the active object count */ - -BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie) -{ - /* Grab the list critical section */ - EnterCriticalSection(&m_CSDebug); - - ObjectDesc *pObject = pListHead; - ObjectDesc *pPrevious = NULL; - - /* Scan the object list looking for a cookie match */ - - while (pObject) { - if (pObject->m_dwCookie == dwCookie) { - break; - } - pPrevious = pObject; - pObject = pObject->m_pNext; - } - - if (pObject == NULL) { - DbgBreak("Apparently destroying a bogus object"); - LeaveCriticalSection(&m_CSDebug); - return FALSE; - } - - /* Is the object at the head of the list */ - - if (pPrevious == NULL) { - pListHead = pObject->m_pNext; - } else { - pPrevious->m_pNext = pObject->m_pNext; - } - - /* Delete the object and update the housekeeping information */ - - m_dwObjectCount--; - - if(pObject->m_wszName) { - DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%ls) %d Active"), - pObject->m_dwCookie, pObject->m_wszName, m_dwObjectCount)); - } else { - DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%hs) %d Active"), - pObject->m_dwCookie, pObject->m_szName, m_dwObjectCount)); - } - - delete pObject; - LeaveCriticalSection(&m_CSDebug); - return TRUE; -} - - -/* This runs through the active object list displaying their details */ - -void WINAPI DbgDumpObjectRegister() -{ - TCHAR szInfo[iDEBUGINFO]; - - /* Grab the list critical section */ - - EnterCriticalSection(&m_CSDebug); - ObjectDesc *pObject = pListHead; - - /* Scan the object list displaying the name and cookie */ - - DbgLog((LOG_MEMORY,2,TEXT(""))); - DbgLog((LOG_MEMORY,2,TEXT(" ID Object Description"))); - DbgLog((LOG_MEMORY,2,TEXT(""))); - - while (pObject) { - if(pObject->m_wszName) { - #ifdef UNICODE - LPCTSTR FORMAT_STRING = TEXT("%5d (%8x) %30s"); - #else - LPCTSTR FORMAT_STRING = TEXT("%5d (%8x) %30S"); - #endif - - (void)StringCchPrintf(szInfo,NUMELMS(szInfo), FORMAT_STRING, pObject->m_dwCookie, &pObject, pObject->m_wszName); - - } else { - #ifdef UNICODE - LPCTSTR FORMAT_STRING = TEXT("%5d (%8x) %30S"); - #else - LPCTSTR FORMAT_STRING = TEXT("%5d (%8x) %30s"); - #endif - - (void)StringCchPrintf(szInfo,NUMELMS(szInfo),FORMAT_STRING,pObject->m_dwCookie, &pObject, pObject->m_szName); - } - DbgLog((LOG_MEMORY,2,szInfo)); - pObject = pObject->m_pNext; - } - - (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("Total object count %5d"),m_dwObjectCount); - DbgLog((LOG_MEMORY,2,TEXT(""))); - DbgLog((LOG_MEMORY,1,szInfo)); - LeaveCriticalSection(&m_CSDebug); -} - -/* Debug infinite wait stuff */ -DWORD WINAPI DbgWaitForSingleObject(HANDLE h) -{ - DWORD dwWaitResult; - do { - dwWaitResult = WaitForSingleObject(h, dwWaitTimeout); - ASSERT(dwWaitResult == WAIT_OBJECT_0); - } while (dwWaitResult == WAIT_TIMEOUT); - return dwWaitResult; -} -DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount, - CONST HANDLE *lpHandles, - BOOL bWaitAll) -{ - DWORD dwWaitResult; - do { - dwWaitResult = WaitForMultipleObjects(nCount, - lpHandles, - bWaitAll, - dwWaitTimeout); - ASSERT((DWORD)(dwWaitResult - WAIT_OBJECT_0) < MAXIMUM_WAIT_OBJECTS); - } while (dwWaitResult == WAIT_TIMEOUT); - return dwWaitResult; -} - -void WINAPI DbgSetWaitTimeout(DWORD dwTimeout) -{ - dwWaitTimeout = dwTimeout; -} - -#endif /* DEBUG */ - -#ifdef _OBJBASE_H_ - - /* Stuff for printing out our GUID names */ - - GUID_STRING_ENTRY g_GuidNames[] = { - #define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - { #name, { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } }, - #include - }; - - CGuidNameList GuidNames; - int g_cGuidNames = sizeof(g_GuidNames) / sizeof(g_GuidNames[0]); - - char *CGuidNameList::operator [] (const GUID &guid) - { - for (int i = 0; i < g_cGuidNames; i++) { - if (g_GuidNames[i].guid == guid) { - return g_GuidNames[i].szName; - } - } - if (guid == GUID_NULL) { - return "GUID_NULL"; - } - - // !!! add something to print FOURCC guids? - - // shouldn't this print the hex CLSID? - return "Unknown GUID Name"; - } - -#endif /* _OBJBASE_H_ */ - -/* CDisp class - display our data types */ - -// clashes with REFERENCE_TIME -CDisp::CDisp(LONGLONG ll, int Format) -{ - // note: this could be combined with CDisp(LONGLONG) by - // introducing a default format of CDISP_REFTIME - LARGE_INTEGER li; - li.QuadPart = ll; - switch (Format) { - case CDISP_DEC: - { - TCHAR temp[20]; - int pos=20; - temp[--pos] = 0; - int digit; - // always output at least one digit - do { - // Get the rightmost digit - we only need the low word - digit = li.LowPart % 10; - li.QuadPart /= 10; - temp[--pos] = (TCHAR) digit+L'0'; - } while (li.QuadPart); - (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%s"), temp+pos); - break; - } - case CDISP_HEX: - default: - (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("0x%X%8.8X"), li.HighPart, li.LowPart); - } -}; - -CDisp::CDisp(REFCLSID clsid) -{ - WCHAR strClass[CHARS_IN_GUID+1]; - StringFromGUID2(clsid, strClass, sizeof(strClass) / sizeof(strClass[0])); - ASSERT(sizeof(m_String)/sizeof(m_String[0]) >= CHARS_IN_GUID+1); - #ifdef UNICODE - (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%s"), strClass); - #else - (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%S"), strClass); - #endif -}; - -#ifdef __STREAMS__ -/* Display stuff */ -CDisp::CDisp(CRefTime llTime) -{ - LPTSTR lpsz = m_String; - size_t len = NUMELMS(m_String); - LONGLONG llDiv; - if (llTime < 0) { - llTime = -llTime; - (void)StringCchPrintf(lpsz, len, TEXT("-")); - size_t t = lstrlen(lpsz); - lpsz += t; - len -= t; - } - llDiv = (LONGLONG)24 * 3600 * 10000000; - if (llTime >= llDiv) { - (void)StringCchPrintf(lpsz, len, TEXT("%d days "), (LONG)(llTime / llDiv)); - size_t t = lstrlen(lpsz); - lpsz += t; - len -= t; - llTime = llTime % llDiv; - } - llDiv = (LONGLONG)3600 * 10000000; - if (llTime >= llDiv) { - (void)StringCchPrintf(lpsz, len, TEXT("%d hrs "), (LONG)(llTime / llDiv)); - size_t t = lstrlen(lpsz); - lpsz += t; - len -= t; - llTime = llTime % llDiv; - } - llDiv = (LONGLONG)60 * 10000000; - if (llTime >= llDiv) { - (void)StringCchPrintf(lpsz, len, TEXT("%d mins "), (LONG)(llTime / llDiv)); - size_t t = lstrlen(lpsz); - lpsz += t; - len -= t; - llTime = llTime % llDiv; - } - (void)StringCchPrintf(lpsz, len, TEXT("%d.%3.3d sec"), - (LONG)llTime / 10000000, - (LONG)((llTime % 10000000) / 10000)); -}; - -#endif // __STREAMS__ - - -/* Display pin */ -CDisp::CDisp(IPin *pPin) -{ - PIN_INFO pi; - TCHAR str[MAX_PIN_NAME]; - CLSID clsid; - - if (pPin) { - pPin->QueryPinInfo(&pi); - pi.pFilter->GetClassID(&clsid); - QueryPinInfoReleaseFilter(pi); - #ifndef UNICODE - WideCharToMultiByte(GetACP(), 0, pi.achName, lstrlenW(pi.achName) + 1, - str, MAX_PIN_NAME, NULL, NULL); - #else - (void)StringCchCopy(str, NUMELMS(str), pi.achName); - #endif - } else { - (void)StringCchCopy(str, NUMELMS(str), TEXT("NULL IPin")); - } - - size_t len = lstrlen(str)+64; - m_pString = (TCHAR*) new TCHAR[len]; - if (!m_pString) { - return; - } - - #ifdef UNICODE - LPCTSTR FORMAT_STRING = TEXT("%S(%s)"); - #else - LPCTSTR FORMAT_STRING = TEXT("%s(%s)"); - #endif - - (void)StringCchPrintf(m_pString, len, FORMAT_STRING, GuidNames[clsid], str); -} - -/* Display filter or pin */ -CDisp::CDisp(IUnknown *pUnk) -{ - IBaseFilter *pf; - HRESULT hr = pUnk->QueryInterface(IID_IBaseFilter, (void **)&pf); - if(SUCCEEDED(hr)) - { - FILTER_INFO fi; - hr = pf->QueryFilterInfo(&fi); - if(SUCCEEDED(hr)) - { - QueryFilterInfoReleaseGraph(fi); - - size_t len = lstrlenW(fi.achName) + 1; - m_pString = new TCHAR[len]; - if(m_pString) - { - #ifdef UNICODE - LPCTSTR FORMAT_STRING = TEXT("%s"); - #else - LPCTSTR FORMAT_STRING = TEXT("%S"); - #endif - - (void)StringCchPrintf(m_pString, len, FORMAT_STRING, fi.achName); - } - } - - pf->Release(); - - return; - } - - IPin *pp; - hr = pUnk->QueryInterface(IID_IPin, (void **)&pp); - if(SUCCEEDED(hr)) - { - CDisp::CDisp(pp); - pp->Release(); - return; - } -} - - -CDisp::~CDisp() -{ -} - -CDispBasic::~CDispBasic() -{ - if (m_pString != m_String) { - delete [] m_pString; - } -} - -CDisp::CDisp(double d) -{ -#ifdef DEBUG - (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%.16g"), d); -#else - (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%d.%03d"), (int) d, (int) ((d - (int) d) * 1000)); -#endif -} - - -/* If built for debug this will display the media type details. We convert the - major and subtypes into strings and also ask the base classes for a string - description of the subtype, so MEDIASUBTYPE_RGB565 becomes RGB 565 16 bit - We also display the fields in the BITMAPINFOHEADER structure, this should - succeed as we do not accept input types unless the format is big enough */ - -#ifdef DEBUG -void WINAPI DisplayType(LPTSTR label, const AM_MEDIA_TYPE *pmtIn, DWORD dwLevel) -{ - - /* Dump the GUID types and a short description */ - - DbgLog((LOG_TRACE,dwLevel,TEXT(""))); - DbgLog((LOG_TRACE,dwLevel,TEXT("%s M type %hs S type %hs"), label, - GuidNames[pmtIn->majortype], - GuidNames[pmtIn->subtype])); - DbgLog((LOG_TRACE,dwLevel,TEXT("Subtype description %s"),GetSubtypeName(&pmtIn->subtype))); - - /* Dump the generic media types */ - - if (pmtIn->bTemporalCompression) { - DbgLog((LOG_TRACE,dwLevel,TEXT("Temporally compressed"))); - } else { - DbgLog((LOG_TRACE,dwLevel,TEXT("Not temporally compressed"))); - } - - if (pmtIn->bFixedSizeSamples) { - DbgLog((LOG_TRACE,dwLevel,TEXT("Sample size %d"),pmtIn->lSampleSize)); - } else { - DbgLog((LOG_TRACE,dwLevel,TEXT("Variable size samples"))); - } - - if (pmtIn->formattype == FORMAT_VideoInfo) { - /* Dump the contents of the BITMAPINFOHEADER structure */ - BITMAPINFOHEADER *pbmi = HEADER(pmtIn->pbFormat); - VIDEOINFOHEADER *pVideoInfo = (VIDEOINFOHEADER *)pmtIn->pbFormat; - - DbgLog((LOG_TRACE,dwLevel,TEXT("Source rectangle (Left %d Top %d Right %d Bottom %d)"), - pVideoInfo->rcSource.left, - pVideoInfo->rcSource.top, - pVideoInfo->rcSource.right, - pVideoInfo->rcSource.bottom)); - - DbgLog((LOG_TRACE,dwLevel,TEXT("Target rectangle (Left %d Top %d Right %d Bottom %d)"), - pVideoInfo->rcTarget.left, - pVideoInfo->rcTarget.top, - pVideoInfo->rcTarget.right, - pVideoInfo->rcTarget.bottom)); - - DbgLog((LOG_TRACE,dwLevel,TEXT("Size of BITMAPINFO structure %d"),pbmi->biSize)); - if (pbmi->biCompression < 256) { - DbgLog((LOG_TRACE,dwLevel,TEXT("%dx%dx%d bit (%d)"), - pbmi->biWidth, pbmi->biHeight, - pbmi->biBitCount, pbmi->biCompression)); - } else { - DbgLog((LOG_TRACE,dwLevel,TEXT("%dx%dx%d bit '%4.4hs'"), - pbmi->biWidth, pbmi->biHeight, - pbmi->biBitCount, &pbmi->biCompression)); - } - - DbgLog((LOG_TRACE,dwLevel,TEXT("Image size %d"),pbmi->biSizeImage)); - DbgLog((LOG_TRACE,dwLevel,TEXT("Planes %d"),pbmi->biPlanes)); - DbgLog((LOG_TRACE,dwLevel,TEXT("X Pels per metre %d"),pbmi->biXPelsPerMeter)); - DbgLog((LOG_TRACE,dwLevel,TEXT("Y Pels per metre %d"),pbmi->biYPelsPerMeter)); - DbgLog((LOG_TRACE,dwLevel,TEXT("Colours used %d"),pbmi->biClrUsed)); - - } else if (pmtIn->majortype == MEDIATYPE_Audio) { - DbgLog((LOG_TRACE,dwLevel,TEXT(" Format type %hs"), - GuidNames[pmtIn->formattype])); - DbgLog((LOG_TRACE,dwLevel,TEXT(" Subtype %hs"), - GuidNames[pmtIn->subtype])); - - if ((pmtIn->subtype != MEDIASUBTYPE_MPEG1Packet) - && (pmtIn->cbFormat >= sizeof(PCMWAVEFORMAT))) - { - /* Dump the contents of the WAVEFORMATEX type-specific format structure */ - - WAVEFORMATEX *pwfx = (WAVEFORMATEX *) pmtIn->pbFormat; - DbgLog((LOG_TRACE,dwLevel,TEXT("wFormatTag %u"), pwfx->wFormatTag)); - DbgLog((LOG_TRACE,dwLevel,TEXT("nChannels %u"), pwfx->nChannels)); - DbgLog((LOG_TRACE,dwLevel,TEXT("nSamplesPerSec %lu"), pwfx->nSamplesPerSec)); - DbgLog((LOG_TRACE,dwLevel,TEXT("nAvgBytesPerSec %lu"), pwfx->nAvgBytesPerSec)); - DbgLog((LOG_TRACE,dwLevel,TEXT("nBlockAlign %u"), pwfx->nBlockAlign)); - DbgLog((LOG_TRACE,dwLevel,TEXT("wBitsPerSample %u"), pwfx->wBitsPerSample)); - - /* PCM uses a WAVEFORMAT and does not have the extra size field */ - - if (pmtIn->cbFormat >= sizeof(WAVEFORMATEX)) { - DbgLog((LOG_TRACE,dwLevel,TEXT("cbSize %u"), pwfx->cbSize)); - } - } else { - } - - } else { - DbgLog((LOG_TRACE,dwLevel,TEXT(" Format type %hs"), - GuidNames[pmtIn->formattype])); - // !!!! should add code to dump wave format, others - } -} - - -void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel) -{ - if( !pGraph ) - { - return; - } - - IEnumFilters *pFilters; - - DbgLog((LOG_TRACE,dwLevel,TEXT("DumpGraph [%x]"), pGraph)); - - if (FAILED(pGraph->EnumFilters(&pFilters))) { - DbgLog((LOG_TRACE,dwLevel,TEXT("EnumFilters failed!"))); - } - - IBaseFilter *pFilter; - ULONG n; - while (pFilters->Next(1, &pFilter, &n) == S_OK) { - FILTER_INFO info; - - if (FAILED(pFilter->QueryFilterInfo(&info))) { - DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%x] -- failed QueryFilterInfo"), pFilter)); - } else { - QueryFilterInfoReleaseGraph(info); - - // !!! should QueryVendorInfo here! - - DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%x] '%ls'"), pFilter, info.achName)); - - IEnumPins *pins; - - if (FAILED(pFilter->EnumPins(&pins))) { - DbgLog((LOG_TRACE,dwLevel,TEXT("EnumPins failed!"))); - } else { - - IPin *pPin; - while (pins->Next(1, &pPin, &n) == S_OK) { - PIN_INFO info; - - if (FAILED(pPin->QueryPinInfo(&info))) { - DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%x] -- failed QueryPinInfo"), pPin)); - } else { - QueryPinInfoReleaseFilter(info); - - IPin *pPinConnected = NULL; - - HRESULT hr = pPin->ConnectedTo(&pPinConnected); - - if (pPinConnected) { - DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%x] '%ls' [%sput]") - TEXT(" Connected to pin [%x]"), - pPin, info.achName, - info.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"), - pPinConnected)); - - pPinConnected->Release(); - - // perhaps we should really dump the type both ways as a sanity - // check? - if (info.dir == PINDIR_OUTPUT) { - AM_MEDIA_TYPE mt; - - hr = pPin->ConnectionMediaType(&mt); - - if (SUCCEEDED(hr)) { - DisplayType(TEXT("Connection type"), &mt); - - FreeMediaType(mt); - } - } - } else { - DbgLog((LOG_TRACE,dwLevel, - TEXT(" Pin [%x] '%ls' [%sput]"), - pPin, info.achName, - info.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"))); - - } - } - - pPin->Release(); - - } - - pins->Release(); - } - - } - - pFilter->Release(); - } - - pFilters->Release(); - -} - -#endif - +//------------------------------------------------------------------------------ +// File: WXDebug.cpp +// +// Desc: DirectShow base classes - implements ActiveX system debugging +// facilities. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include +#include + +#ifdef DEBUG +#ifdef UNICODE +#ifndef _UNICODE +#define _UNICODE +#endif // _UNICODE +#endif // UNICODE +#endif // DEBUG + +#ifdef DEBUG + +// The Win32 wsprintf() function writes a maximum of 1024 characters to it's output buffer. +// See the documentation for wsprintf()'s lpOut parameter for more information. +const INT iDEBUGINFO = 1024; // Used to format strings + +/* For every module and executable we store a debugging level for each of + the five categories (eg LOG_ERROR and LOG_TIMING). This makes it easy + to isolate and debug individual modules without seeing everybody elses + spurious debug output. The keys are stored in the registry under the + HKEY_LOCAL_MACHINE\SOFTWARE\Debug\\ key values + NOTE these must be in the same order as their enumeration definition */ + +TCHAR *pKeyNames[] = { + TEXT("TIMING"), // Timing and performance measurements + TEXT("TRACE"), // General step point call tracing + TEXT("MEMORY"), // Memory and object allocation/destruction + TEXT("LOCKING"), // Locking/unlocking of critical sections + TEXT("ERROR"), // Debug error notification + TEXT("CUSTOM1"), + TEXT("CUSTOM2"), + TEXT("CUSTOM3"), + TEXT("CUSTOM4"), + TEXT("CUSTOM5") + }; + +const TCHAR CAutoTrace::_szEntering[] = TEXT("->: %s"); +const TCHAR CAutoTrace::_szLeaving[] = TEXT("<-: %s"); + +const INT iMAXLEVELS = NUMELMS(pKeyNames); // Maximum debug categories + +HINSTANCE m_hInst; // Module instance handle +TCHAR m_ModuleName[iDEBUGINFO]; // Cut down module name +DWORD m_Levels[iMAXLEVELS]; // Debug level per category +CRITICAL_SECTION m_CSDebug; // Controls access to list +DWORD m_dwNextCookie; // Next active object ID +ObjectDesc *pListHead = NULL; // First active object +DWORD m_dwObjectCount; // Active object count +BOOL m_bInit = FALSE; // Have we been initialised +HANDLE m_hOutput = INVALID_HANDLE_VALUE; // Optional output written here +DWORD dwWaitTimeout = INFINITE; // Default timeout value +DWORD dwTimeOffset; // Time of first DbgLog call +bool g_fUseKASSERT = false; // don't create messagebox +bool g_fDbgInDllEntryPoint = false; +bool g_fAutoRefreshLevels = false; + +const TCHAR *pBaseKey = TEXT("SOFTWARE\\Debug"); +const TCHAR *pGlobalKey = TEXT("GLOBAL"); +static CHAR *pUnknownName = "UNKNOWN"; + +TCHAR *TimeoutName = TEXT("TIMEOUT"); + +/* This sets the instance handle that the debug library uses to find + the module's file name from the Win32 GetModuleFileName function */ + +void WINAPI DbgInitialise(HINSTANCE hInst) +{ + InitializeCriticalSection(&m_CSDebug); + m_bInit = TRUE; + + m_hInst = hInst; + DbgInitModuleName(); + if (GetProfileInt(m_ModuleName, TEXT("BreakOnLoad"), 0)) + DebugBreak(); + DbgInitModuleSettings(false); + DbgInitGlobalSettings(true); + dwTimeOffset = timeGetTime(); +} + + +/* This is called to clear up any resources the debug library uses - at the + moment we delete our critical section and the object list. The values we + retrieve from the registry are all done during initialisation but we don't + go looking for update notifications while we are running, if the values + are changed then the application has to be restarted to pick them up */ + +void WINAPI DbgTerminate() +{ + if (m_hOutput != INVALID_HANDLE_VALUE) { + EXECUTE_ASSERT(CloseHandle(m_hOutput)); + m_hOutput = INVALID_HANDLE_VALUE; + } + DeleteCriticalSection(&m_CSDebug); + m_bInit = FALSE; +} + + +/* This is called by DbgInitLogLevels to read the debug settings + for each logging category for this module from the registry */ + +void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax) +{ + LONG lReturn; // Create key return value + LONG lKeyPos; // Current key category + DWORD dwKeySize; // Size of the key value + DWORD dwKeyType; // Receives it's type + DWORD dwKeyValue; // This fields value + + /* Try and read a value for each key position in turn */ + for (lKeyPos = 0;lKeyPos < iMAXLEVELS;lKeyPos++) { + + dwKeySize = sizeof(DWORD); + lReturn = RegQueryValueEx( + hKey, // Handle to an open key + pKeyNames[lKeyPos], // Subkey name derivation + NULL, // Reserved field + &dwKeyType, // Returns the field type + (LPBYTE) &dwKeyValue, // Returns the field's value + &dwKeySize ); // Number of bytes transferred + + /* If either the key was not available or it was not a DWORD value + then we ensure only the high priority debug logging is output + but we try and update the field to a zero filled DWORD value */ + + if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) { + + dwKeyValue = 0; + lReturn = RegSetValueEx( + hKey, // Handle of an open key + pKeyNames[lKeyPos], // Address of subkey name + (DWORD) 0, // Reserved field + REG_DWORD, // Type of the key field + (PBYTE) &dwKeyValue, // Value for the field + sizeof(DWORD)); // Size of the field buffer + + if (lReturn != ERROR_SUCCESS) { + DbgLog((LOG_ERROR,0,TEXT("Could not create subkey %s"),pKeyNames[lKeyPos])); + dwKeyValue = 0; + } + } + if(fTakeMax) + { + m_Levels[lKeyPos] = max(dwKeyValue,m_Levels[lKeyPos]); + } + else + { + if((m_Levels[lKeyPos] & LOG_FORCIBLY_SET) == 0) { + m_Levels[lKeyPos] = dwKeyValue; + } + } + } + + /* Read the timeout value for catching hangs */ + dwKeySize = sizeof(DWORD); + lReturn = RegQueryValueEx( + hKey, // Handle to an open key + TimeoutName, // Subkey name derivation + NULL, // Reserved field + &dwKeyType, // Returns the field type + (LPBYTE) &dwWaitTimeout, // Returns the field's value + &dwKeySize ); // Number of bytes transferred + + /* If either the key was not available or it was not a DWORD value + then we ensure only the high priority debug logging is output + but we try and update the field to a zero filled DWORD value */ + + if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) { + + dwWaitTimeout = INFINITE; + lReturn = RegSetValueEx( + hKey, // Handle of an open key + TimeoutName, // Address of subkey name + (DWORD) 0, // Reserved field + REG_DWORD, // Type of the key field + (PBYTE) &dwWaitTimeout, // Value for the field + sizeof(DWORD)); // Size of the field buffer + + if (lReturn != ERROR_SUCCESS) { + DbgLog((LOG_ERROR,0,TEXT("Could not create subkey %s"),TimeoutName)); + dwWaitTimeout = INFINITE; + } + } +} + +void WINAPI DbgOutString(LPCTSTR psz) +{ + if (m_hOutput != INVALID_HANDLE_VALUE) { + UINT cb = lstrlen(psz); + DWORD dw; +#ifdef UNICODE + CHAR szDest[2048]; + WideCharToMultiByte(CP_ACP, 0, psz, -1, szDest, NUMELMS(szDest), 0, 0); + WriteFile (m_hOutput, szDest, cb, &dw, NULL); +#else + WriteFile (m_hOutput, psz, cb, &dw, NULL); +#endif + } else { + OutputDebugString (psz); + } +} + +/* Called by DbgInitGlobalSettings to setup alternate logging destinations + */ + +void WINAPI DbgInitLogTo ( + HKEY hKey) +{ + LONG lReturn; + DWORD dwKeyType; + DWORD dwKeySize; + TCHAR szFile[MAX_PATH] = {0}; + static const TCHAR cszKey[] = TEXT("LogToFile"); + + dwKeySize = MAX_PATH; + lReturn = RegQueryValueEx( + hKey, // Handle to an open key + cszKey, // Subkey name derivation + NULL, // Reserved field + &dwKeyType, // Returns the field type + (LPBYTE) szFile, // Returns the field's value + &dwKeySize); // Number of bytes transferred + + // create an empty key if it does not already exist + // + if (lReturn != ERROR_SUCCESS || dwKeyType != REG_SZ) + { + dwKeySize = sizeof(TCHAR); + lReturn = RegSetValueEx( + hKey, // Handle of an open key + cszKey, // Address of subkey name + (DWORD) 0, // Reserved field + REG_SZ, // Type of the key field + (PBYTE)szFile, // Value for the field + dwKeySize); // Size of the field buffer + } + + // if an output-to was specified. try to open it. + // + if (m_hOutput != INVALID_HANDLE_VALUE) { + EXECUTE_ASSERT(CloseHandle (m_hOutput)); + m_hOutput = INVALID_HANDLE_VALUE; + } + if (szFile[0] != 0) + { + if (!lstrcmpi(szFile, TEXT("Console"))) { + m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE); + if (m_hOutput == INVALID_HANDLE_VALUE) { + AllocConsole (); + m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE); + } + SetConsoleTitle (TEXT("ActiveX Debug Output")); + } else if (szFile[0] && + lstrcmpi(szFile, TEXT("Debug")) && + lstrcmpi(szFile, TEXT("Debugger")) && + lstrcmpi(szFile, TEXT("Deb"))) + { + m_hOutput = CreateFile(szFile, GENERIC_WRITE, + FILE_SHARE_READ, + NULL, OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (INVALID_HANDLE_VALUE != m_hOutput) + { + static const TCHAR cszBar[] = TEXT("\r\n\r\n=====DbgInitialize()=====\r\n\r\n"); + SetFilePointer (m_hOutput, 0, NULL, FILE_END); + DbgOutString (cszBar); + } + } + } +} + + + +/* This is called by DbgInitLogLevels to read the global debug settings for + each logging category for this module from the registry. Normally each + module has it's own values set for it's different debug categories but + setting the global SOFTWARE\Debug\Global applies them to ALL modules */ + +void WINAPI DbgInitGlobalSettings(bool fTakeMax) +{ + LONG lReturn; // Create key return value + TCHAR szInfo[iDEBUGINFO]; // Constructs key names + HKEY hGlobalKey; // Global override key + + /* Construct the global base key name */ + (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%s\\%s"),pBaseKey,pGlobalKey); + + /* Create or open the key for this module */ + lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key + szInfo, // Address of subkey name + (DWORD) 0, // Reserved value + NULL, // Address of class name + (DWORD) 0, // Special options flags + KEY_ALL_ACCESS, // Desired security access + NULL, // Key security descriptor + &hGlobalKey, // Opened handle buffer + NULL); // What really happened + + if (lReturn != ERROR_SUCCESS) { + DbgLog((LOG_ERROR,0,TEXT("Could not access GLOBAL module key"))); + return; + } + + DbgInitKeyLevels(hGlobalKey, fTakeMax); + RegCloseKey(hGlobalKey); +} + + +/* This sets the debugging log levels for the different categories. We start + by opening (or creating if not already available) the SOFTWARE\Debug key + that all these settings live under. We then look at the global values + set under SOFTWARE\Debug\Global which apply on top of the individual + module settings. We then load the individual module registry settings */ + +void WINAPI DbgInitModuleSettings(bool fTakeMax) +{ + LONG lReturn; // Create key return value + TCHAR szInfo[iDEBUGINFO]; // Constructs key names + HKEY hModuleKey; // Module key handle + + /* Construct the base key name */ + (void)StringCchPrintf(szInfo,NUMELMS(szInfo), TEXT("%s\\%s"),pBaseKey,m_ModuleName); + + /* Create or open the key for this module */ + lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key + szInfo, // Address of subkey name + (DWORD) 0, // Reserved value + NULL, // Address of class name + (DWORD) 0, // Special options flags + KEY_ALL_ACCESS, // Desired security access + NULL, // Key security descriptor + &hModuleKey, // Opened handle buffer + NULL); // What really happened + + if (lReturn != ERROR_SUCCESS) { + DbgLog((LOG_ERROR,0,TEXT("Could not access module key"))); + return; + } + + DbgInitLogTo(hModuleKey); + DbgInitKeyLevels(hModuleKey, fTakeMax); + RegCloseKey(hModuleKey); +} + + +/* Initialise the module file name */ + +void WINAPI DbgInitModuleName() +{ + TCHAR FullName[iDEBUGINFO]; // Load the full path and module name + TCHAR *pName; // Searches from the end for a backslash + + GetModuleFileName(m_hInst,FullName,iDEBUGINFO); + pName = _tcsrchr(FullName,'\\'); + if (pName == NULL) { + pName = FullName; + } else { + pName++; + } + (void)StringCchCopy(m_ModuleName,NUMELMS(m_ModuleName), pName); +} + +struct MsgBoxMsg +{ + HWND hwnd; + TCHAR *szTitle; + TCHAR *szMessage; + DWORD dwFlags; + INT iResult; +}; + +// +// create a thread to call MessageBox(). calling MessageBox() on +// random threads at bad times can confuse the host (eg IE). +// +DWORD WINAPI MsgBoxThread( + LPVOID lpParameter // thread data + ) +{ + MsgBoxMsg *pmsg = (MsgBoxMsg *)lpParameter; + pmsg->iResult = MessageBox( + pmsg->hwnd, + pmsg->szTitle, + pmsg->szMessage, + pmsg->dwFlags); + + return 0; +} + +INT MessageBoxOtherThread( + HWND hwnd, + TCHAR *szTitle, + TCHAR *szMessage, + DWORD dwFlags) +{ + if(g_fDbgInDllEntryPoint) + { + // can't wait on another thread because we have the loader + // lock held in the dll entry point. + return MessageBox(hwnd, szTitle, szMessage, dwFlags); + } + else + { + MsgBoxMsg msg = {hwnd, szTitle, szMessage, dwFlags, 0}; + DWORD dwid; + HANDLE hThread = CreateThread( + 0, // security + 0, // stack size + MsgBoxThread, + (void *)&msg, // arg + 0, // flags + &dwid); + if(hThread) + { + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + return msg.iResult; + } + + // break into debugger on failure. + return IDCANCEL; + } +} + +/* Displays a message box if the condition evaluated to FALSE */ + +void WINAPI DbgAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine) +{ + if(g_fUseKASSERT) + { + DbgKernelAssert(pCondition, pFileName, iLine); + } + else + { + + TCHAR szInfo[iDEBUGINFO]; + + (void)StringCchPrintf(szInfo, NUMELMS(szInfo), TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"), + pCondition, iLine, pFileName); + + INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("ASSERT Failed"), + MB_SYSTEMMODAL | + MB_ICONHAND | + MB_YESNOCANCEL | + MB_SETFOREGROUND); + switch (MsgId) + { + case IDNO: /* Kill the application */ + + FatalAppExit(FALSE, TEXT("Application terminated")); + break; + + case IDCANCEL: /* Break into the debugger */ + + DebugBreak(); + break; + + case IDYES: /* Ignore assertion continue execution */ + break; + } + } +} + +/* Displays a message box at a break point */ + +void WINAPI DbgBreakPoint(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine) +{ + if(g_fUseKASSERT) + { + DbgKernelAssert(pCondition, pFileName, iLine); + } + else + { + TCHAR szInfo[iDEBUGINFO]; + + (void)StringCchPrintf(szInfo, NUMELMS(szInfo), TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"), + pCondition, iLine, pFileName); + + INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("Hard coded break point"), + MB_SYSTEMMODAL | + MB_ICONHAND | + MB_YESNOCANCEL | + MB_SETFOREGROUND); + switch (MsgId) + { + case IDNO: /* Kill the application */ + + FatalAppExit(FALSE, TEXT("Application terminated")); + break; + + case IDCANCEL: /* Break into the debugger */ + + DebugBreak(); + break; + + case IDYES: /* Ignore break point continue execution */ + break; + } + } +} + +void WINAPI DbgBreakPoint(const TCHAR *pFileName,INT iLine,const TCHAR* szFormatString,...) +{ + // A debug break point message can have at most 2000 characters if + // ANSI or UNICODE characters are being used. A debug break point message + // can have between 1000 and 2000 double byte characters in it. If a + // particular message needs more characters, then the value of this constant + // should be increased. + const DWORD MAX_BREAK_POINT_MESSAGE_SIZE = 2000; + + TCHAR szBreakPointMessage[MAX_BREAK_POINT_MESSAGE_SIZE]; + + const DWORD MAX_CHARS_IN_BREAK_POINT_MESSAGE = sizeof(szBreakPointMessage) / sizeof(TCHAR); + + va_list va; + va_start( va, szFormatString ); + + HRESULT hr = StringCchVPrintf( szBreakPointMessage, MAX_CHARS_IN_BREAK_POINT_MESSAGE, szFormatString, va ); + + va_end(va); + + if( S_OK != hr ) { + DbgBreak( "ERROR in DbgBreakPoint(). The variable length debug message could not be displayed because _vsnprintf() failed." ); + return; + } + + ::DbgBreakPoint( szBreakPointMessage, pFileName, iLine ); +} + + +/* When we initialised the library we stored in the m_Levels array the current + debug output level for this module for each of the five categories. When + some debug logging is sent to us it can be sent with a combination of the + categories (if it is applicable to many for example) in which case we map + the type's categories into their current debug levels and see if any of + them can be accepted. The function looks at each bit position in turn from + the input type field and then compares it's debug level with the modules. + + A level of 0 means that output is always sent to the debugger. This is + due to producing output if the input level is <= m_Levels. +*/ + + +BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level) +{ + if(g_fAutoRefreshLevels) + { + // re-read the registry every second. We cannot use RegNotify() to + // notice registry changes because it's not available on win9x. + static DWORD g_dwLastRefresh = 0; + DWORD dwTime = timeGetTime(); + if(dwTime - g_dwLastRefresh > 1000) { + g_dwLastRefresh = dwTime; + + // there's a race condition: multiple threads could update the + // values. plus read and write not synchronized. no harm + // though. + DbgInitModuleSettings(false); + } + } + + + DWORD Mask = 0x01; + + // If no valid bits are set return FALSE + if ((Type & ((1<m_szName = szObjectName; + pObject->m_wszName = wszObjectName; + pObject->m_dwCookie = ++m_dwNextCookie; + pObject->m_pNext = pListHead; + + pListHead = pObject; + m_dwObjectCount++; + + DWORD ObjectCookie = pObject->m_dwCookie; + ASSERT(ObjectCookie); + + if(wszObjectName) { + DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%ls) %d Active"), + pObject->m_dwCookie, wszObjectName, m_dwObjectCount)); + } else { + DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%hs) %d Active"), + pObject->m_dwCookie, szObjectName, m_dwObjectCount)); + } + + LeaveCriticalSection(&m_CSDebug); + return ObjectCookie; +} + + +/* This is called by the CBaseObject destructor when an object is about to be + destroyed, we are passed the cookie we returned during construction that + identifies this object. We scan the object list for a matching cookie and + remove the object if successful. We also update the active object count */ + +BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie) +{ + /* Grab the list critical section */ + EnterCriticalSection(&m_CSDebug); + + ObjectDesc *pObject = pListHead; + ObjectDesc *pPrevious = NULL; + + /* Scan the object list looking for a cookie match */ + + while (pObject) { + if (pObject->m_dwCookie == dwCookie) { + break; + } + pPrevious = pObject; + pObject = pObject->m_pNext; + } + + if (pObject == NULL) { + DbgBreak("Apparently destroying a bogus object"); + LeaveCriticalSection(&m_CSDebug); + return FALSE; + } + + /* Is the object at the head of the list */ + + if (pPrevious == NULL) { + pListHead = pObject->m_pNext; + } else { + pPrevious->m_pNext = pObject->m_pNext; + } + + /* Delete the object and update the housekeeping information */ + + m_dwObjectCount--; + + if(pObject->m_wszName) { + DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%ls) %d Active"), + pObject->m_dwCookie, pObject->m_wszName, m_dwObjectCount)); + } else { + DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%hs) %d Active"), + pObject->m_dwCookie, pObject->m_szName, m_dwObjectCount)); + } + + delete pObject; + LeaveCriticalSection(&m_CSDebug); + return TRUE; +} + + +/* This runs through the active object list displaying their details */ + +void WINAPI DbgDumpObjectRegister() +{ + TCHAR szInfo[iDEBUGINFO]; + + /* Grab the list critical section */ + + EnterCriticalSection(&m_CSDebug); + ObjectDesc *pObject = pListHead; + + /* Scan the object list displaying the name and cookie */ + + DbgLog((LOG_MEMORY,2,TEXT(""))); + DbgLog((LOG_MEMORY,2,TEXT(" ID Object Description"))); + DbgLog((LOG_MEMORY,2,TEXT(""))); + + while (pObject) { + if(pObject->m_wszName) { + #ifdef UNICODE + LPCTSTR FORMAT_STRING = TEXT("%5d (%8x) %30s"); + #else + LPCTSTR FORMAT_STRING = TEXT("%5d (%8x) %30S"); + #endif + + (void)StringCchPrintf(szInfo,NUMELMS(szInfo), FORMAT_STRING, pObject->m_dwCookie, &pObject, pObject->m_wszName); + + } else { + #ifdef UNICODE + LPCTSTR FORMAT_STRING = TEXT("%5d (%8x) %30S"); + #else + LPCTSTR FORMAT_STRING = TEXT("%5d (%8x) %30s"); + #endif + + (void)StringCchPrintf(szInfo,NUMELMS(szInfo),FORMAT_STRING,pObject->m_dwCookie, &pObject, pObject->m_szName); + } + DbgLog((LOG_MEMORY,2,szInfo)); + pObject = pObject->m_pNext; + } + + (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("Total object count %5d"),m_dwObjectCount); + DbgLog((LOG_MEMORY,2,TEXT(""))); + DbgLog((LOG_MEMORY,1,szInfo)); + LeaveCriticalSection(&m_CSDebug); +} + +/* Debug infinite wait stuff */ +DWORD WINAPI DbgWaitForSingleObject(HANDLE h) +{ + DWORD dwWaitResult; + do { + dwWaitResult = WaitForSingleObject(h, dwWaitTimeout); + ASSERT(dwWaitResult == WAIT_OBJECT_0); + } while (dwWaitResult == WAIT_TIMEOUT); + return dwWaitResult; +} +DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount, + CONST HANDLE *lpHandles, + BOOL bWaitAll) +{ + DWORD dwWaitResult; + do { + dwWaitResult = WaitForMultipleObjects(nCount, + lpHandles, + bWaitAll, + dwWaitTimeout); + ASSERT((DWORD)(dwWaitResult - WAIT_OBJECT_0) < MAXIMUM_WAIT_OBJECTS); + } while (dwWaitResult == WAIT_TIMEOUT); + return dwWaitResult; +} + +void WINAPI DbgSetWaitTimeout(DWORD dwTimeout) +{ + dwWaitTimeout = dwTimeout; +} + +#endif /* DEBUG */ + +#ifdef _OBJBASE_H_ + + /* Stuff for printing out our GUID names */ + + GUID_STRING_ENTRY g_GuidNames[] = { + #define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + { #name, { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } }, + #include + }; + + CGuidNameList GuidNames; + int g_cGuidNames = sizeof(g_GuidNames) / sizeof(g_GuidNames[0]); + + char *CGuidNameList::operator [] (const GUID &guid) + { + for (int i = 0; i < g_cGuidNames; i++) { + if (g_GuidNames[i].guid == guid) { + return g_GuidNames[i].szName; + } + } + if (guid == GUID_NULL) { + return "GUID_NULL"; + } + + // !!! add something to print FOURCC guids? + + // shouldn't this print the hex CLSID? + return "Unknown GUID Name"; + } + +#endif /* _OBJBASE_H_ */ + +/* CDisp class - display our data types */ + +// clashes with REFERENCE_TIME +CDisp::CDisp(LONGLONG ll, int Format) +{ + // note: this could be combined with CDisp(LONGLONG) by + // introducing a default format of CDISP_REFTIME + LARGE_INTEGER li; + li.QuadPart = ll; + switch (Format) { + case CDISP_DEC: + { + TCHAR temp[20]; + int pos=20; + temp[--pos] = 0; + int digit; + // always output at least one digit + do { + // Get the rightmost digit - we only need the low word + digit = li.LowPart % 10; + li.QuadPart /= 10; + temp[--pos] = (TCHAR) digit+L'0'; + } while (li.QuadPart); + (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%s"), temp+pos); + break; + } + case CDISP_HEX: + default: + (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("0x%X%8.8X"), li.HighPart, li.LowPart); + } +}; + +CDisp::CDisp(REFCLSID clsid) +{ + WCHAR strClass[CHARS_IN_GUID+1]; + StringFromGUID2(clsid, strClass, sizeof(strClass) / sizeof(strClass[0])); + ASSERT(sizeof(m_String)/sizeof(m_String[0]) >= CHARS_IN_GUID+1); + #ifdef UNICODE + (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%s"), strClass); + #else + (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%S"), strClass); + #endif +}; + +#ifdef __STREAMS__ +/* Display stuff */ +CDisp::CDisp(CRefTime llTime) +{ + LPTSTR lpsz = m_String; + size_t len = NUMELMS(m_String); + LONGLONG llDiv; + if (llTime < 0) { + llTime = -llTime; + (void)StringCchPrintf(lpsz, len, TEXT("-")); + size_t t = lstrlen(lpsz); + lpsz += t; + len -= t; + } + llDiv = (LONGLONG)24 * 3600 * 10000000; + if (llTime >= llDiv) { + (void)StringCchPrintf(lpsz, len, TEXT("%d days "), (LONG)(llTime / llDiv)); + size_t t = lstrlen(lpsz); + lpsz += t; + len -= t; + llTime = llTime % llDiv; + } + llDiv = (LONGLONG)3600 * 10000000; + if (llTime >= llDiv) { + (void)StringCchPrintf(lpsz, len, TEXT("%d hrs "), (LONG)(llTime / llDiv)); + size_t t = lstrlen(lpsz); + lpsz += t; + len -= t; + llTime = llTime % llDiv; + } + llDiv = (LONGLONG)60 * 10000000; + if (llTime >= llDiv) { + (void)StringCchPrintf(lpsz, len, TEXT("%d mins "), (LONG)(llTime / llDiv)); + size_t t = lstrlen(lpsz); + lpsz += t; + len -= t; + llTime = llTime % llDiv; + } + (void)StringCchPrintf(lpsz, len, TEXT("%d.%3.3d sec"), + (LONG)llTime / 10000000, + (LONG)((llTime % 10000000) / 10000)); +}; + +#endif // __STREAMS__ + + +/* Display pin */ +CDisp::CDisp(IPin *pPin) +{ + PIN_INFO pi; + TCHAR str[MAX_PIN_NAME]; + CLSID clsid; + + if (pPin) { + pPin->QueryPinInfo(&pi); + pi.pFilter->GetClassID(&clsid); + QueryPinInfoReleaseFilter(pi); + #ifndef UNICODE + WideCharToMultiByte(GetACP(), 0, pi.achName, lstrlenW(pi.achName) + 1, + str, MAX_PIN_NAME, NULL, NULL); + #else + (void)StringCchCopy(str, NUMELMS(str), pi.achName); + #endif + } else { + (void)StringCchCopy(str, NUMELMS(str), TEXT("NULL IPin")); + } + + size_t len = lstrlen(str)+64; + m_pString = (TCHAR*) new TCHAR[len]; + if (!m_pString) { + return; + } + + #ifdef UNICODE + LPCTSTR FORMAT_STRING = TEXT("%S(%s)"); + #else + LPCTSTR FORMAT_STRING = TEXT("%s(%s)"); + #endif + + (void)StringCchPrintf(m_pString, len, FORMAT_STRING, GuidNames[clsid], str); +} + +/* Display filter or pin */ +CDisp::CDisp(IUnknown *pUnk) +{ + IBaseFilter *pf; + HRESULT hr = pUnk->QueryInterface(IID_IBaseFilter, (void **)&pf); + if(SUCCEEDED(hr)) + { + FILTER_INFO fi; + hr = pf->QueryFilterInfo(&fi); + if(SUCCEEDED(hr)) + { + QueryFilterInfoReleaseGraph(fi); + + size_t len = lstrlenW(fi.achName) + 1; + m_pString = new TCHAR[len]; + if(m_pString) + { + #ifdef UNICODE + LPCTSTR FORMAT_STRING = TEXT("%s"); + #else + LPCTSTR FORMAT_STRING = TEXT("%S"); + #endif + + (void)StringCchPrintf(m_pString, len, FORMAT_STRING, fi.achName); + } + } + + pf->Release(); + + return; + } + + IPin *pp; + hr = pUnk->QueryInterface(IID_IPin, (void **)&pp); + if(SUCCEEDED(hr)) + { + CDisp::CDisp(pp); + pp->Release(); + return; + } +} + + +CDisp::~CDisp() +{ +} + +CDispBasic::~CDispBasic() +{ + if (m_pString != m_String) { + delete [] m_pString; + } +} + +CDisp::CDisp(double d) +{ +#ifdef DEBUG + (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%.16g"), d); +#else + (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%d.%03d"), (int) d, (int) ((d - (int) d) * 1000)); +#endif +} + + +/* If built for debug this will display the media type details. We convert the + major and subtypes into strings and also ask the base classes for a string + description of the subtype, so MEDIASUBTYPE_RGB565 becomes RGB 565 16 bit + We also display the fields in the BITMAPINFOHEADER structure, this should + succeed as we do not accept input types unless the format is big enough */ + +#ifdef DEBUG +void WINAPI DisplayType(LPTSTR label, const AM_MEDIA_TYPE *pmtIn, DWORD dwLevel) +{ + + /* Dump the GUID types and a short description */ + + DbgLog((LOG_TRACE,dwLevel,TEXT(""))); + DbgLog((LOG_TRACE,dwLevel,TEXT("%s M type %hs S type %hs"), label, + GuidNames[pmtIn->majortype], + GuidNames[pmtIn->subtype])); + DbgLog((LOG_TRACE,dwLevel,TEXT("Subtype description %s"),GetSubtypeName(&pmtIn->subtype))); + + /* Dump the generic media types */ + + if (pmtIn->bTemporalCompression) { + DbgLog((LOG_TRACE,dwLevel,TEXT("Temporally compressed"))); + } else { + DbgLog((LOG_TRACE,dwLevel,TEXT("Not temporally compressed"))); + } + + if (pmtIn->bFixedSizeSamples) { + DbgLog((LOG_TRACE,dwLevel,TEXT("Sample size %d"),pmtIn->lSampleSize)); + } else { + DbgLog((LOG_TRACE,dwLevel,TEXT("Variable size samples"))); + } + + if (pmtIn->formattype == FORMAT_VideoInfo) { + /* Dump the contents of the BITMAPINFOHEADER structure */ + BITMAPINFOHEADER *pbmi = HEADER(pmtIn->pbFormat); + VIDEOINFOHEADER *pVideoInfo = (VIDEOINFOHEADER *)pmtIn->pbFormat; + + DbgLog((LOG_TRACE,dwLevel,TEXT("Source rectangle (Left %d Top %d Right %d Bottom %d)"), + pVideoInfo->rcSource.left, + pVideoInfo->rcSource.top, + pVideoInfo->rcSource.right, + pVideoInfo->rcSource.bottom)); + + DbgLog((LOG_TRACE,dwLevel,TEXT("Target rectangle (Left %d Top %d Right %d Bottom %d)"), + pVideoInfo->rcTarget.left, + pVideoInfo->rcTarget.top, + pVideoInfo->rcTarget.right, + pVideoInfo->rcTarget.bottom)); + + DbgLog((LOG_TRACE,dwLevel,TEXT("Size of BITMAPINFO structure %d"),pbmi->biSize)); + if (pbmi->biCompression < 256) { + DbgLog((LOG_TRACE,dwLevel,TEXT("%dx%dx%d bit (%d)"), + pbmi->biWidth, pbmi->biHeight, + pbmi->biBitCount, pbmi->biCompression)); + } else { + DbgLog((LOG_TRACE,dwLevel,TEXT("%dx%dx%d bit '%4.4hs'"), + pbmi->biWidth, pbmi->biHeight, + pbmi->biBitCount, &pbmi->biCompression)); + } + + DbgLog((LOG_TRACE,dwLevel,TEXT("Image size %d"),pbmi->biSizeImage)); + DbgLog((LOG_TRACE,dwLevel,TEXT("Planes %d"),pbmi->biPlanes)); + DbgLog((LOG_TRACE,dwLevel,TEXT("X Pels per metre %d"),pbmi->biXPelsPerMeter)); + DbgLog((LOG_TRACE,dwLevel,TEXT("Y Pels per metre %d"),pbmi->biYPelsPerMeter)); + DbgLog((LOG_TRACE,dwLevel,TEXT("Colours used %d"),pbmi->biClrUsed)); + + } else if (pmtIn->majortype == MEDIATYPE_Audio) { + DbgLog((LOG_TRACE,dwLevel,TEXT(" Format type %hs"), + GuidNames[pmtIn->formattype])); + DbgLog((LOG_TRACE,dwLevel,TEXT(" Subtype %hs"), + GuidNames[pmtIn->subtype])); + + if ((pmtIn->subtype != MEDIASUBTYPE_MPEG1Packet) + && (pmtIn->cbFormat >= sizeof(PCMWAVEFORMAT))) + { + /* Dump the contents of the WAVEFORMATEX type-specific format structure */ + + WAVEFORMATEX *pwfx = (WAVEFORMATEX *) pmtIn->pbFormat; + DbgLog((LOG_TRACE,dwLevel,TEXT("wFormatTag %u"), pwfx->wFormatTag)); + DbgLog((LOG_TRACE,dwLevel,TEXT("nChannels %u"), pwfx->nChannels)); + DbgLog((LOG_TRACE,dwLevel,TEXT("nSamplesPerSec %lu"), pwfx->nSamplesPerSec)); + DbgLog((LOG_TRACE,dwLevel,TEXT("nAvgBytesPerSec %lu"), pwfx->nAvgBytesPerSec)); + DbgLog((LOG_TRACE,dwLevel,TEXT("nBlockAlign %u"), pwfx->nBlockAlign)); + DbgLog((LOG_TRACE,dwLevel,TEXT("wBitsPerSample %u"), pwfx->wBitsPerSample)); + + /* PCM uses a WAVEFORMAT and does not have the extra size field */ + + if (pmtIn->cbFormat >= sizeof(WAVEFORMATEX)) { + DbgLog((LOG_TRACE,dwLevel,TEXT("cbSize %u"), pwfx->cbSize)); + } + } else { + } + + } else { + DbgLog((LOG_TRACE,dwLevel,TEXT(" Format type %hs"), + GuidNames[pmtIn->formattype])); + // !!!! should add code to dump wave format, others + } +} + + +void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel) +{ + if( !pGraph ) + { + return; + } + + IEnumFilters *pFilters; + + DbgLog((LOG_TRACE,dwLevel,TEXT("DumpGraph [%x]"), pGraph)); + + if (FAILED(pGraph->EnumFilters(&pFilters))) { + DbgLog((LOG_TRACE,dwLevel,TEXT("EnumFilters failed!"))); + } + + IBaseFilter *pFilter; + ULONG n; + while (pFilters->Next(1, &pFilter, &n) == S_OK) { + FILTER_INFO info; + + if (FAILED(pFilter->QueryFilterInfo(&info))) { + DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%x] -- failed QueryFilterInfo"), pFilter)); + } else { + QueryFilterInfoReleaseGraph(info); + + // !!! should QueryVendorInfo here! + + DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%x] '%ls'"), pFilter, info.achName)); + + IEnumPins *pins; + + if (FAILED(pFilter->EnumPins(&pins))) { + DbgLog((LOG_TRACE,dwLevel,TEXT("EnumPins failed!"))); + } else { + + IPin *pPin; + while (pins->Next(1, &pPin, &n) == S_OK) { + PIN_INFO info; + + if (FAILED(pPin->QueryPinInfo(&info))) { + DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%x] -- failed QueryPinInfo"), pPin)); + } else { + QueryPinInfoReleaseFilter(info); + + IPin *pPinConnected = NULL; + + HRESULT hr = pPin->ConnectedTo(&pPinConnected); + + if (pPinConnected) { + DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%x] '%ls' [%sput]") + TEXT(" Connected to pin [%x]"), + pPin, info.achName, + info.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"), + pPinConnected)); + + pPinConnected->Release(); + + // perhaps we should really dump the type both ways as a sanity + // check? + if (info.dir == PINDIR_OUTPUT) { + AM_MEDIA_TYPE mt; + + hr = pPin->ConnectionMediaType(&mt); + + if (SUCCEEDED(hr)) { + DisplayType(TEXT("Connection type"), &mt); + + FreeMediaType(mt); + } + } + } else { + DbgLog((LOG_TRACE,dwLevel, + TEXT(" Pin [%x] '%ls' [%sput]"), + pPin, info.achName, + info.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"))); + + } + } + + pPin->Release(); + + } + + pins->Release(); + } + + } + + pFilter->Release(); + } + + pFilters->Release(); + +} + +#endif + diff --git a/plugins/GSdx/baseclasses/wxdebug.h b/plugins/GSdx/baseclasses/wxdebug.h index 6a8b1ff0a4..d87a1a0c60 100644 --- a/plugins/GSdx/baseclasses/wxdebug.h +++ b/plugins/GSdx/baseclasses/wxdebug.h @@ -1,393 +1,393 @@ -//------------------------------------------------------------------------------ -// File: WXDebug.h -// -// Desc: DirectShow base classes - provides debugging facilities. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __WXDEBUG__ -#define __WXDEBUG__ - -// This library provides fairly straight forward debugging functionality, this -// is split into two main sections. The first is assertion handling, there are -// three types of assertions provided here. The most commonly used one is the -// ASSERT(condition) macro which will pop up a message box including the file -// and line number if the condition evaluates to FALSE. Then there is the -// EXECUTE_ASSERT macro which is the same as ASSERT except the condition will -// still be executed in NON debug builds. The final type of assertion is the -// KASSERT macro which is more suitable for pure (perhaps kernel) filters as -// the condition is printed onto the debugger rather than in a message box. -// -// The other part of the debug module facilties is general purpose logging. -// This is accessed by calling DbgLog(). The function takes a type and level -// field which define the type of informational string you are presenting and -// it's relative importance. The type field can be a combination (one or more) -// of LOG_TIMING, LOG_TRACE, LOG_MEMORY, LOG_LOCKING and LOG_ERROR. The level -// is a DWORD value where zero defines highest important. Use of zero as the -// debug logging level is to be encouraged ONLY for major errors or events as -// they will ALWAYS be displayed on the debugger. Other debug output has it's -// level matched against the current debug output level stored in the registry -// for this module and if less than the current setting it will be displayed. -// -// Each module or executable has it's own debug output level for each of the -// five types. These are read in when the DbgInitialise function is called -// for DLLs linking to STRMBASE.LIB this is done automatically when the DLL -// is loaded, executables must call it explicitely with the module instance -// handle given to them through the WINMAIN entry point. An executable must -// also call DbgTerminate when they have finished to clean up the resources -// the debug library uses, once again this is done automatically for DLLs - -// These are the five different categories of logging information - -enum { LOG_TIMING = 0x01, // Timing and performance measurements - LOG_TRACE = 0x02, // General step point call tracing - LOG_MEMORY = 0x04, // Memory and object allocation/destruction - LOG_LOCKING = 0x08, // Locking/unlocking of critical sections - LOG_ERROR = 0x10, // Debug error notification - LOG_CUSTOM1 = 0x20, - LOG_CUSTOM2 = 0x40, - LOG_CUSTOM3 = 0x80, - LOG_CUSTOM4 = 0x100, - LOG_CUSTOM5 = 0x200, -}; - -#define LOG_FORCIBLY_SET 0x80000000 - -enum { CDISP_HEX = 0x01, - CDISP_DEC = 0x02}; - -// For each object created derived from CBaseObject (in debug builds) we -// create a descriptor that holds it's name (statically allocated memory) -// and a cookie we assign it. We keep a list of all the active objects -// we have registered so that we can dump a list of remaining objects - -typedef struct tag_ObjectDesc { - const CHAR *m_szName; - const WCHAR *m_wszName; - DWORD m_dwCookie; - tag_ObjectDesc *m_pNext; -} ObjectDesc; - -#define DLLIMPORT __declspec(dllimport) -#define DLLEXPORT __declspec(dllexport) - -#ifdef DEBUG - - #define NAME(x) TEXT(x) - - // These are used internally by the debug library (PRIVATE) - - void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax); - void WINAPI DbgInitGlobalSettings(bool fTakeMax); - void WINAPI DbgInitModuleSettings(bool fTakeMax); - void WINAPI DbgInitModuleName(); - DWORD WINAPI DbgRegisterObjectCreation( - const CHAR *szObjectName, const WCHAR *wszObjectName); - - BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie); - - // These are the PUBLIC entry points - - BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level); - void WINAPI DbgSetModuleLevel(DWORD Type,DWORD Level); - void WINAPI DbgSetAutoRefreshLevels(bool fAuto); - - // Initialise the library with the module handle - - void WINAPI DbgInitialise(HINSTANCE hInst); - void WINAPI DbgTerminate(); - - void WINAPI DbgDumpObjectRegister(); - - // Display error and logging to the user - - void WINAPI DbgAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine); - void WINAPI DbgBreakPoint(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine); - void WINAPI DbgBreakPoint(const TCHAR *pFileName,INT iLine,const TCHAR* szFormatString,...); - - void WINAPI DbgKernelAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine); - void WINAPI DbgLogInfo(DWORD Type,DWORD Level,const TCHAR *pFormat,...); -#ifdef UNICODE - void WINAPI DbgLogInfo(DWORD Type,DWORD Level,const CHAR *pFormat,...); - void WINAPI DbgAssert(const CHAR *pCondition,const CHAR *pFileName,INT iLine); - void WINAPI DbgBreakPoint(const CHAR *pCondition,const CHAR *pFileName,INT iLine); - void WINAPI DbgKernelAssert(const CHAR *pCondition,const CHAR *pFileName,INT iLine); -#endif - void WINAPI DbgOutString(LPCTSTR psz); - - // Debug infinite wait stuff - DWORD WINAPI DbgWaitForSingleObject(HANDLE h); - DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount, - CONST HANDLE *lpHandles, - BOOL bWaitAll); - void WINAPI DbgSetWaitTimeout(DWORD dwTimeout); - -#ifdef __strmif_h__ - // Display a media type: Terse at level 2, verbose at level 5 - void WINAPI DisplayType(LPTSTR label, const AM_MEDIA_TYPE *pmtIn, DWORD dwLevel = 5); - - // Dump lots of information about a filter graph - void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel); -#endif - - #define KASSERT(_x_) if (!(_x_)) \ - DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) - - // Break on the debugger without putting up a message box - // message goes to debugger instead - - #define KDbgBreak(_x_) \ - DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) - - // We chose a common name for our ASSERT macro, MFC also uses this name - // So long as the implementation evaluates the condition and handles it - // then we will be ok. Rather than override the behaviour expected we - // will leave whatever first defines ASSERT as the handler (i.e. MFC) - #ifndef ASSERT - #define ASSERT(_x_) if (!(_x_)) \ - DbgAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) - #endif - - #define DbgAssertAligned( _ptr_, _alignment_ ) ASSERT( ((DWORD_PTR) (_ptr_)) % (_alignment_) == 0) - - // Put up a message box informing the user of a halt - // condition in the program - - #define DbgBreak(_x_) \ - DbgBreakPoint(TEXT(#_x_),TEXT(__FILE__),__LINE__) - - #define EXECUTE_ASSERT(_x_) ASSERT(_x_) - #define DbgLog(_x_) DbgLogInfo _x_ - // MFC style trace macros - - #define NOTE(_x_) DbgLog((LOG_TRACE,5,TEXT(_x_))) - #define NOTE1(_x_,a) DbgLog((LOG_TRACE,5,TEXT(_x_),a)) - #define NOTE2(_x_,a,b) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b)) - #define NOTE3(_x_,a,b,c) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c)) - #define NOTE4(_x_,a,b,c,d) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d)) - #define NOTE5(_x_,a,b,c,d,e) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d,e)) - -#else - - // Retail builds make public debug functions inert - WARNING the source - // files do not define or build any of the entry points in debug builds - // (public entry points compile to nothing) so if you go trying to call - // any of the private entry points in your source they won't compile - - #define NAME(_x_) ((TCHAR *) NULL) - - #define DbgInitialise(hInst) - #define DbgTerminate() - #define DbgLog(_x_) 0 - #define DbgOutString(psz) - #define DbgAssertAligned( _ptr_, _alignment_ ) 0 - - #define DbgRegisterObjectCreation(pObjectName) - #define DbgRegisterObjectDestruction(dwCookie) - #define DbgDumpObjectRegister() - - #define DbgCheckModuleLevel(Type,Level) - #define DbgSetModuleLevel(Type,Level) - #define DbgSetAutoRefreshLevels(fAuto) - - #define DbgWaitForSingleObject(h) WaitForSingleObject(h, INFINITE) - #define DbgWaitForMultipleObjects(nCount, lpHandles, bWaitAll) \ - WaitForMultipleObjects(nCount, lpHandles, bWaitAll, INFINITE) - #define DbgSetWaitTimeout(dwTimeout) - - #define KDbgBreak(_x_) - #define DbgBreak(_x_) - - #define KASSERT(_x_) ((void)0) - #ifndef ASSERT - #define ASSERT(_x_) ((void)0) - #endif - #define EXECUTE_ASSERT(_x_) ((void)(_x_)) - - // MFC style trace macros - - #define NOTE(_x_) ((void)0) - #define NOTE1(_x_,a) ((void)0) - #define NOTE2(_x_,a,b) ((void)0) - #define NOTE3(_x_,a,b,c) ((void)0) - #define NOTE4(_x_,a,b,c,d) ((void)0) - #define NOTE5(_x_,a,b,c,d,e) ((void)0) - - #define DisplayType(label, pmtIn) ((void)0) - #define DumpGraph(pGraph, label) ((void)0) -#endif - - -// Checks a pointer which should be non NULL - can be used as follows. - -#define CheckPointer(p,ret) {if((p)==NULL) return (ret);} - -// HRESULT Foo(VOID *pBar) -// { -// CheckPointer(pBar,E_INVALIDARG) -// } -// -// Or if the function returns a boolean -// -// BOOL Foo(VOID *pBar) -// { -// CheckPointer(pBar,FALSE) -// } - -// These validate pointers when symbol VFWROBUST is defined -// This will normally be defined in debug not retail builds - -#ifdef DEBUG - #define VFWROBUST -#endif - -#ifdef VFWROBUST - - #define ValidateReadPtr(p,cb) \ - {if(IsBadReadPtr((PVOID)p,cb) == TRUE) \ - DbgBreak("Invalid read pointer");} - - #define ValidateWritePtr(p,cb) \ - {if(IsBadWritePtr((PVOID)p,cb) == TRUE) \ - DbgBreak("Invalid write pointer");} - - #define ValidateReadWritePtr(p,cb) \ - {ValidateReadPtr(p,cb) ValidateWritePtr(p,cb)} - - #define ValidateStringPtr(p) \ - {if(IsBadStringPtr((LPCTSTR)p,INFINITE) == TRUE) \ - DbgBreak("Invalid string pointer");} - - #define ValidateStringPtrA(p) \ - {if(IsBadStringPtrA((LPCSTR)p,INFINITE) == TRUE) \ - DbgBreak("Invalid ANSI string pointer");} - - #define ValidateStringPtrW(p) \ - {if(IsBadStringPtrW((LPCWSTR)p,INFINITE) == TRUE) \ - DbgBreak("Invalid UNICODE string pointer");} - -#else - #define ValidateReadPtr(p,cb) 0 - #define ValidateWritePtr(p,cb) 0 - #define ValidateReadWritePtr(p,cb) 0 - #define ValidateStringPtr(p) 0 - #define ValidateStringPtrA(p) 0 - #define ValidateStringPtrW(p) 0 -#endif - - -#ifdef _OBJBASE_H_ - - // Outputting GUID names. If you want to include the name - // associated with a GUID (eg CLSID_...) then - // - // GuidNames[yourGUID] - // - // Returns the name defined in uuids.h as a string - - typedef struct { - CHAR *szName; - GUID guid; - } GUID_STRING_ENTRY; - - class CGuidNameList { - public: - CHAR *operator [] (const GUID& guid); - }; - - extern CGuidNameList GuidNames; - -#endif - -#ifndef REMIND - // REMIND macro - generates warning as reminder to complete coding - // (eg) usage: - // - // #pragma message (REMIND("Add automation support")) - - - #define QUOTE(x) #x - #define QQUOTE(y) QUOTE(y) - #define REMIND(str) __FILE__ "(" QQUOTE(__LINE__) ") : " str -#endif - -// Method to display objects in a useful format -// -// eg If you want to display a LONGLONG ll in a debug string do (eg) -// -// DbgLog((LOG_TRACE, n, TEXT("Value is %s"), (LPCTSTR)CDisp(ll, CDISP_HEX))); - - -class CDispBasic -{ -public: - CDispBasic() { m_pString = m_String; }; - ~CDispBasic(); -protected: - TCHAR* m_pString; // normally points to m_String... unless too much data - TCHAR m_String[50]; -}; -class CDisp : public CDispBasic -{ -public: - CDisp(LONGLONG ll, int Format = CDISP_HEX); // Display a LONGLONG in CDISP_HEX or CDISP_DEC form - CDisp(REFCLSID clsid); // Display a GUID - CDisp(double d); // Display a floating point number -#ifdef __strmif_h__ -#ifdef __STREAMS__ - CDisp(CRefTime t); // Display a Reference Time -#endif - CDisp(IPin *pPin); // Display a pin as {filter clsid}(pin name) - CDisp(IUnknown *pUnk); // Display a filter or pin -#endif // __strmif_h__ - ~CDisp(); - - // Implement cast to (LPCTSTR) as parameter to logger - operator LPCTSTR() - { - return (LPCTSTR)m_pString; - }; -}; - - -#if defined(DEBUG) -class CAutoTrace -{ -private: - const TCHAR* _szBlkName; - const int _level; - static const TCHAR _szEntering[]; - static const TCHAR _szLeaving[]; -public: - CAutoTrace(const TCHAR* szBlkName, const int level = 15) - : _szBlkName(szBlkName), _level(level) - {DbgLog((LOG_TRACE, _level, _szEntering, _szBlkName));} - - ~CAutoTrace() - {DbgLog((LOG_TRACE, _level, _szLeaving, _szBlkName));} -}; - -#if defined (__FUNCTION__) - -#define AMTRACEFN() CAutoTrace __trace(TEXT(__FUNCTION__)) -#define AMTRACE(_x_) CAutoTrace __trace(TEXT(__FUNCTION__)) - -#else - -#define AMTRACE(_x_) CAutoTrace __trace _x_ -#define AMTRACEFN() - -#endif - -#else - -#define AMTRACE(_x_) -#define AMTRACEFN() - -#endif - -#endif // __WXDEBUG__ - - +//------------------------------------------------------------------------------ +// File: WXDebug.h +// +// Desc: DirectShow base classes - provides debugging facilities. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __WXDEBUG__ +#define __WXDEBUG__ + +// This library provides fairly straight forward debugging functionality, this +// is split into two main sections. The first is assertion handling, there are +// three types of assertions provided here. The most commonly used one is the +// ASSERT(condition) macro which will pop up a message box including the file +// and line number if the condition evaluates to FALSE. Then there is the +// EXECUTE_ASSERT macro which is the same as ASSERT except the condition will +// still be executed in NON debug builds. The final type of assertion is the +// KASSERT macro which is more suitable for pure (perhaps kernel) filters as +// the condition is printed onto the debugger rather than in a message box. +// +// The other part of the debug module facilties is general purpose logging. +// This is accessed by calling DbgLog(). The function takes a type and level +// field which define the type of informational string you are presenting and +// it's relative importance. The type field can be a combination (one or more) +// of LOG_TIMING, LOG_TRACE, LOG_MEMORY, LOG_LOCKING and LOG_ERROR. The level +// is a DWORD value where zero defines highest important. Use of zero as the +// debug logging level is to be encouraged ONLY for major errors or events as +// they will ALWAYS be displayed on the debugger. Other debug output has it's +// level matched against the current debug output level stored in the registry +// for this module and if less than the current setting it will be displayed. +// +// Each module or executable has it's own debug output level for each of the +// five types. These are read in when the DbgInitialise function is called +// for DLLs linking to STRMBASE.LIB this is done automatically when the DLL +// is loaded, executables must call it explicitely with the module instance +// handle given to them through the WINMAIN entry point. An executable must +// also call DbgTerminate when they have finished to clean up the resources +// the debug library uses, once again this is done automatically for DLLs + +// These are the five different categories of logging information + +enum { LOG_TIMING = 0x01, // Timing and performance measurements + LOG_TRACE = 0x02, // General step point call tracing + LOG_MEMORY = 0x04, // Memory and object allocation/destruction + LOG_LOCKING = 0x08, // Locking/unlocking of critical sections + LOG_ERROR = 0x10, // Debug error notification + LOG_CUSTOM1 = 0x20, + LOG_CUSTOM2 = 0x40, + LOG_CUSTOM3 = 0x80, + LOG_CUSTOM4 = 0x100, + LOG_CUSTOM5 = 0x200, +}; + +#define LOG_FORCIBLY_SET 0x80000000 + +enum { CDISP_HEX = 0x01, + CDISP_DEC = 0x02}; + +// For each object created derived from CBaseObject (in debug builds) we +// create a descriptor that holds it's name (statically allocated memory) +// and a cookie we assign it. We keep a list of all the active objects +// we have registered so that we can dump a list of remaining objects + +typedef struct tag_ObjectDesc { + const CHAR *m_szName; + const WCHAR *m_wszName; + DWORD m_dwCookie; + tag_ObjectDesc *m_pNext; +} ObjectDesc; + +#define DLLIMPORT __declspec(dllimport) +#define DLLEXPORT __declspec(dllexport) + +#ifdef DEBUG + + #define NAME(x) TEXT(x) + + // These are used internally by the debug library (PRIVATE) + + void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax); + void WINAPI DbgInitGlobalSettings(bool fTakeMax); + void WINAPI DbgInitModuleSettings(bool fTakeMax); + void WINAPI DbgInitModuleName(); + DWORD WINAPI DbgRegisterObjectCreation( + const CHAR *szObjectName, const WCHAR *wszObjectName); + + BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie); + + // These are the PUBLIC entry points + + BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level); + void WINAPI DbgSetModuleLevel(DWORD Type,DWORD Level); + void WINAPI DbgSetAutoRefreshLevels(bool fAuto); + + // Initialise the library with the module handle + + void WINAPI DbgInitialise(HINSTANCE hInst); + void WINAPI DbgTerminate(); + + void WINAPI DbgDumpObjectRegister(); + + // Display error and logging to the user + + void WINAPI DbgAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine); + void WINAPI DbgBreakPoint(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine); + void WINAPI DbgBreakPoint(const TCHAR *pFileName,INT iLine,const TCHAR* szFormatString,...); + + void WINAPI DbgKernelAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine); + void WINAPI DbgLogInfo(DWORD Type,DWORD Level,const TCHAR *pFormat,...); +#ifdef UNICODE + void WINAPI DbgLogInfo(DWORD Type,DWORD Level,const CHAR *pFormat,...); + void WINAPI DbgAssert(const CHAR *pCondition,const CHAR *pFileName,INT iLine); + void WINAPI DbgBreakPoint(const CHAR *pCondition,const CHAR *pFileName,INT iLine); + void WINAPI DbgKernelAssert(const CHAR *pCondition,const CHAR *pFileName,INT iLine); +#endif + void WINAPI DbgOutString(LPCTSTR psz); + + // Debug infinite wait stuff + DWORD WINAPI DbgWaitForSingleObject(HANDLE h); + DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount, + CONST HANDLE *lpHandles, + BOOL bWaitAll); + void WINAPI DbgSetWaitTimeout(DWORD dwTimeout); + +#ifdef __strmif_h__ + // Display a media type: Terse at level 2, verbose at level 5 + void WINAPI DisplayType(LPTSTR label, const AM_MEDIA_TYPE *pmtIn, DWORD dwLevel = 5); + + // Dump lots of information about a filter graph + void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel); +#endif + + #define KASSERT(_x_) if (!(_x_)) \ + DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) + + // Break on the debugger without putting up a message box + // message goes to debugger instead + + #define KDbgBreak(_x_) \ + DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) + + // We chose a common name for our ASSERT macro, MFC also uses this name + // So long as the implementation evaluates the condition and handles it + // then we will be ok. Rather than override the behaviour expected we + // will leave whatever first defines ASSERT as the handler (i.e. MFC) + #ifndef ASSERT + #define ASSERT(_x_) if (!(_x_)) \ + DbgAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) + #endif + + #define DbgAssertAligned( _ptr_, _alignment_ ) ASSERT( ((DWORD_PTR) (_ptr_)) % (_alignment_) == 0) + + // Put up a message box informing the user of a halt + // condition in the program + + #define DbgBreak(_x_) \ + DbgBreakPoint(TEXT(#_x_),TEXT(__FILE__),__LINE__) + + #define EXECUTE_ASSERT(_x_) ASSERT(_x_) + #define DbgLog(_x_) DbgLogInfo _x_ + // MFC style trace macros + + #define NOTE(_x_) DbgLog((LOG_TRACE,5,TEXT(_x_))) + #define NOTE1(_x_,a) DbgLog((LOG_TRACE,5,TEXT(_x_),a)) + #define NOTE2(_x_,a,b) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b)) + #define NOTE3(_x_,a,b,c) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c)) + #define NOTE4(_x_,a,b,c,d) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d)) + #define NOTE5(_x_,a,b,c,d,e) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d,e)) + +#else + + // Retail builds make public debug functions inert - WARNING the source + // files do not define or build any of the entry points in debug builds + // (public entry points compile to nothing) so if you go trying to call + // any of the private entry points in your source they won't compile + + #define NAME(_x_) ((TCHAR *) NULL) + + #define DbgInitialise(hInst) + #define DbgTerminate() + #define DbgLog(_x_) 0 + #define DbgOutString(psz) + #define DbgAssertAligned( _ptr_, _alignment_ ) 0 + + #define DbgRegisterObjectCreation(pObjectName) + #define DbgRegisterObjectDestruction(dwCookie) + #define DbgDumpObjectRegister() + + #define DbgCheckModuleLevel(Type,Level) + #define DbgSetModuleLevel(Type,Level) + #define DbgSetAutoRefreshLevels(fAuto) + + #define DbgWaitForSingleObject(h) WaitForSingleObject(h, INFINITE) + #define DbgWaitForMultipleObjects(nCount, lpHandles, bWaitAll) \ + WaitForMultipleObjects(nCount, lpHandles, bWaitAll, INFINITE) + #define DbgSetWaitTimeout(dwTimeout) + + #define KDbgBreak(_x_) + #define DbgBreak(_x_) + + #define KASSERT(_x_) ((void)0) + #ifndef ASSERT + #define ASSERT(_x_) ((void)0) + #endif + #define EXECUTE_ASSERT(_x_) ((void)(_x_)) + + // MFC style trace macros + + #define NOTE(_x_) ((void)0) + #define NOTE1(_x_,a) ((void)0) + #define NOTE2(_x_,a,b) ((void)0) + #define NOTE3(_x_,a,b,c) ((void)0) + #define NOTE4(_x_,a,b,c,d) ((void)0) + #define NOTE5(_x_,a,b,c,d,e) ((void)0) + + #define DisplayType(label, pmtIn) ((void)0) + #define DumpGraph(pGraph, label) ((void)0) +#endif + + +// Checks a pointer which should be non NULL - can be used as follows. + +#define CheckPointer(p,ret) {if((p)==NULL) return (ret);} + +// HRESULT Foo(VOID *pBar) +// { +// CheckPointer(pBar,E_INVALIDARG) +// } +// +// Or if the function returns a boolean +// +// BOOL Foo(VOID *pBar) +// { +// CheckPointer(pBar,FALSE) +// } + +// These validate pointers when symbol VFWROBUST is defined +// This will normally be defined in debug not retail builds + +#ifdef DEBUG + #define VFWROBUST +#endif + +#ifdef VFWROBUST + + #define ValidateReadPtr(p,cb) \ + {if(IsBadReadPtr((PVOID)p,cb) == TRUE) \ + DbgBreak("Invalid read pointer");} + + #define ValidateWritePtr(p,cb) \ + {if(IsBadWritePtr((PVOID)p,cb) == TRUE) \ + DbgBreak("Invalid write pointer");} + + #define ValidateReadWritePtr(p,cb) \ + {ValidateReadPtr(p,cb) ValidateWritePtr(p,cb)} + + #define ValidateStringPtr(p) \ + {if(IsBadStringPtr((LPCTSTR)p,INFINITE) == TRUE) \ + DbgBreak("Invalid string pointer");} + + #define ValidateStringPtrA(p) \ + {if(IsBadStringPtrA((LPCSTR)p,INFINITE) == TRUE) \ + DbgBreak("Invalid ANSI string pointer");} + + #define ValidateStringPtrW(p) \ + {if(IsBadStringPtrW((LPCWSTR)p,INFINITE) == TRUE) \ + DbgBreak("Invalid UNICODE string pointer");} + +#else + #define ValidateReadPtr(p,cb) 0 + #define ValidateWritePtr(p,cb) 0 + #define ValidateReadWritePtr(p,cb) 0 + #define ValidateStringPtr(p) 0 + #define ValidateStringPtrA(p) 0 + #define ValidateStringPtrW(p) 0 +#endif + + +#ifdef _OBJBASE_H_ + + // Outputting GUID names. If you want to include the name + // associated with a GUID (eg CLSID_...) then + // + // GuidNames[yourGUID] + // + // Returns the name defined in uuids.h as a string + + typedef struct { + CHAR *szName; + GUID guid; + } GUID_STRING_ENTRY; + + class CGuidNameList { + public: + CHAR *operator [] (const GUID& guid); + }; + + extern CGuidNameList GuidNames; + +#endif + +#ifndef REMIND + // REMIND macro - generates warning as reminder to complete coding + // (eg) usage: + // + // #pragma message (REMIND("Add automation support")) + + + #define QUOTE(x) #x + #define QQUOTE(y) QUOTE(y) + #define REMIND(str) __FILE__ "(" QQUOTE(__LINE__) ") : " str +#endif + +// Method to display objects in a useful format +// +// eg If you want to display a LONGLONG ll in a debug string do (eg) +// +// DbgLog((LOG_TRACE, n, TEXT("Value is %s"), (LPCTSTR)CDisp(ll, CDISP_HEX))); + + +class CDispBasic +{ +public: + CDispBasic() { m_pString = m_String; }; + ~CDispBasic(); +protected: + TCHAR* m_pString; // normally points to m_String... unless too much data + TCHAR m_String[50]; +}; +class CDisp : public CDispBasic +{ +public: + CDisp(LONGLONG ll, int Format = CDISP_HEX); // Display a LONGLONG in CDISP_HEX or CDISP_DEC form + CDisp(REFCLSID clsid); // Display a GUID + CDisp(double d); // Display a floating point number +#ifdef __strmif_h__ +#ifdef __STREAMS__ + CDisp(CRefTime t); // Display a Reference Time +#endif + CDisp(IPin *pPin); // Display a pin as {filter clsid}(pin name) + CDisp(IUnknown *pUnk); // Display a filter or pin +#endif // __strmif_h__ + ~CDisp(); + + // Implement cast to (LPCTSTR) as parameter to logger + operator LPCTSTR() + { + return (LPCTSTR)m_pString; + }; +}; + + +#if defined(DEBUG) +class CAutoTrace +{ +private: + const TCHAR* _szBlkName; + const int _level; + static const TCHAR _szEntering[]; + static const TCHAR _szLeaving[]; +public: + CAutoTrace(const TCHAR* szBlkName, const int level = 15) + : _szBlkName(szBlkName), _level(level) + {DbgLog((LOG_TRACE, _level, _szEntering, _szBlkName));} + + ~CAutoTrace() + {DbgLog((LOG_TRACE, _level, _szLeaving, _szBlkName));} +}; + +#if defined (__FUNCTION__) + +#define AMTRACEFN() CAutoTrace __trace(TEXT(__FUNCTION__)) +#define AMTRACE(_x_) CAutoTrace __trace(TEXT(__FUNCTION__)) + +#else + +#define AMTRACE(_x_) CAutoTrace __trace _x_ +#define AMTRACEFN() + +#endif + +#else + +#define AMTRACE(_x_) +#define AMTRACEFN() + +#endif + +#endif // __WXDEBUG__ + + diff --git a/plugins/GSdx/baseclasses/wxlist.cpp b/plugins/GSdx/baseclasses/wxlist.cpp index 27c3a5b8c5..1270e8d3d4 100644 --- a/plugins/GSdx/baseclasses/wxlist.cpp +++ b/plugins/GSdx/baseclasses/wxlist.cpp @@ -1,885 +1,885 @@ -//------------------------------------------------------------------------------ -// File: WXList.cpp -// -// Desc: DirectShow base classes - implements a non-MFC based generic list -// template class. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -/* A generic list of pointers to objects. - Objectives: avoid using MFC libraries in ndm kernel mode and - provide a really useful list type. - - The class is thread safe in that separate threads may add and - delete items in the list concurrently although the application - must ensure that constructor and destructor access is suitably - synchronised. - - The list name must not conflict with MFC classes as an - application may use both - - The nodes form a doubly linked, NULL terminated chain with an anchor - block (the list object per se) holding pointers to the first and last - nodes and a count of the nodes. - There is a node cache to reduce the allocation and freeing overhead. - It optionally (determined at construction time) has an Event which is - set whenever the list becomes non-empty and reset whenever it becomes - empty. - It optionally (determined at construction time) has a Critical Section - which is entered during the important part of each operation. (About - all you can do outside it is some parameter checking). - - The node cache is a repository of nodes that are NOT in the list to speed - up storage allocation. Each list has its own cache to reduce locking and - serialising. The list accesses are serialised anyway for a given list - a - common cache would mean that we would have to separately serialise access - of all lists within the cache. Because the cache only stores nodes that are - not in the list, releasing the cache does not release any list nodes. This - means that list nodes can be copied or rechained from one list to another - without danger of creating a dangling reference if the original cache goes - away. - - Questionable design decisions: - 1. Retaining the warts for compatibility - 2. Keeping an element count -i.e. counting whenever we do anything - instead of only when we want the count. - 3. Making the chain pointers NULL terminated. If the list object - itself looks just like a node and the list is kept as a ring then - it reduces the number of special cases. All inserts look the same. -*/ - - -#include "streams.h" - -/* set cursor to the position of each element of list in turn */ -#define INTERNALTRAVERSELIST(list, cursor) \ -for ( cursor = (list).GetHeadPositionI() \ - ; cursor!=NULL \ - ; cursor = (list).Next(cursor) \ - ) - - -/* set cursor to the position of each element of list in turn - in reverse order -*/ -#define INTERNALREVERSETRAVERSELIST(list, cursor) \ -for ( cursor = (list).GetTailPositionI() \ - ; cursor!=NULL \ - ; cursor = (list).Prev(cursor) \ - ) - -/* Constructor calls a separate initialisation function that - creates a node cache, optionally creates a lock object - and optionally creates a signaling object. - - By default we create a locking object, a DEFAULTCACHE sized - cache but no event object so the list cannot be used in calls - to WaitForSingleObject -*/ -CBaseList::CBaseList(TCHAR *pName, // Descriptive list name - INT iItems) : // Node cache size -#ifdef DEBUG - CBaseObject(pName), -#endif - m_pFirst(NULL), - m_pLast(NULL), - m_Count(0), - m_Cache(iItems) -{ -} // constructor - -CBaseList::CBaseList(TCHAR *pName) : // Descriptive list name -#ifdef DEBUG - CBaseObject(pName), -#endif - m_pFirst(NULL), - m_pLast(NULL), - m_Count(0), - m_Cache(DEFAULTCACHE) -{ -} // constructor - -#ifdef UNICODE -CBaseList::CBaseList(CHAR *pName, // Descriptive list name - INT iItems) : // Node cache size -#ifdef DEBUG - CBaseObject(pName), -#endif - m_pFirst(NULL), - m_pLast(NULL), - m_Count(0), - m_Cache(iItems) -{ -} // constructor - -CBaseList::CBaseList(CHAR *pName) : // Descriptive list name -#ifdef DEBUG - CBaseObject(pName), -#endif - m_pFirst(NULL), - m_pLast(NULL), - m_Count(0), - m_Cache(DEFAULTCACHE) -{ -} // constructor - -#endif - -/* The destructor enumerates all the node objects in the list and - in the cache deleting each in turn. We do not do any processing - on the objects that the list holds (i.e. points to) so if they - represent interfaces for example the creator of the list should - ensure that each of them is released before deleting us -*/ -CBaseList::~CBaseList() -{ - /* Delete all our list nodes */ - - RemoveAll(); - -} // destructor - -/* Remove all the nodes from the list but don't do anything - with the objects that each node looks after (this is the - responsibility of the creator). - Aa a last act we reset the signalling event - (if available) to indicate to clients that the list - does not have any entries in it. -*/ -void CBaseList::RemoveAll() -{ - /* Free up all the CNode objects NOTE we don't bother putting the - deleted nodes into the cache as this method is only really called - in serious times of change such as when we are being deleted at - which point the cache will be deleted anway */ - - CNode *pn = m_pFirst; - while (pn) { - CNode *op = pn; - pn = pn->Next(); - delete op; - } - - /* Reset the object count and the list pointers */ - - m_Count = 0; - m_pFirst = m_pLast = NULL; - -} // RemoveAll - - - -/* Return a position enumerator for the entire list. - A position enumerator is a pointer to a node object cast to a - transparent type so all we do is return the head/tail node - pointer in the list. - WARNING because the position is a pointer to a node there is - an implicit assumption for users a the list class that after - deleting an object from the list that any other position - enumerators that you have may be invalid (since the node - may be gone). -*/ -WXLIST_POSITION CBaseList::GetHeadPositionI() const -{ - return (WXLIST_POSITION) m_pFirst; -} // GetHeadPosition - - - -WXLIST_POSITION CBaseList::GetTailPositionI() const -{ - return (WXLIST_POSITION) m_pLast; -} // GetTailPosition - - - -/* Get the number of objects in the list, - Get the lock before accessing the count. - Locking may not be entirely necessary but it has the side effect - of making sure that all operations are complete before we get it. - So for example if a list is being added to this list then that - will have completed in full before we continue rather than seeing - an intermediate albeit valid state -*/ -int CBaseList::GetCountI() const -{ - return m_Count; -} // GetCount - - - -/* Return the object at rp, update rp to the next object from - the list or NULL if you have moved over the last object. - You may still call this function once we return NULL but - we will continue to return a NULL position value -*/ -void *CBaseList::GetNextI(WXLIST_POSITION& rp) const -{ - /* have we reached the end of the list */ - - if (rp == NULL) { - return NULL; - } - - /* Lock the object before continuing */ - - void *pObject; - - /* Copy the original position then step on */ - - CNode *pn = (CNode *) rp; - ASSERT(pn != NULL); - rp = (WXLIST_POSITION) pn->Next(); - - /* Get the object at the original position from the list */ - - pObject = pn->GetData(); - // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. - return pObject; -} //GetNext - - - -/* Return the object at p. - Asking for the object at NULL ASSERTs then returns NULL - The object is NOT locked. The list is not being changed - in any way. If another thread is busy deleting the object - then locking would only result in a change from one bad - behaviour to another. -*/ -void *CBaseList::GetI(WXLIST_POSITION p) const -{ - if (p == NULL) { - return NULL; - } - - CNode * pn = (CNode *) p; - void *pObject = pn->GetData(); - // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. - return pObject; -} //Get - - - -/* Return the first position in the list which holds the given pointer. - Return NULL if it's not found. -*/ -WXLIST_POSITION CBaseList::FindI( void * pObj) const -{ - WXLIST_POSITION pn; - INTERNALTRAVERSELIST(*this, pn){ - if (GetI(pn)==pObj) { - return pn; - } - } - return NULL; -} // Find - - - -/* Remove the first node in the list (deletes the pointer to its object - from the list, does not free the object itself). - Return the pointer to its object or NULL if empty -*/ -void *CBaseList::RemoveHeadI() -{ - /* All we do is get the head position and ask for that to be deleted. - We could special case this since some of the code path checking - in Remove() is redundant as we know there is no previous - node for example but it seems to gain little over the - added complexity - */ - - return RemoveI((WXLIST_POSITION)m_pFirst); -} // RemoveHead - - - -/* Remove the last node in the list (deletes the pointer to its object - from the list, does not free the object itself). - Return the pointer to its object or NULL if empty -*/ -void *CBaseList::RemoveTailI() -{ - /* All we do is get the tail position and ask for that to be deleted. - We could special case this since some of the code path checking - in Remove() is redundant as we know there is no previous - node for example but it seems to gain little over the - added complexity - */ - - return RemoveI((WXLIST_POSITION)m_pLast); -} // RemoveTail - - - -/* Remove the pointer to the object in this position from the list. - Deal with all the chain pointers - Return a pointer to the object removed from the list. - The node object that is freed as a result - of this operation is added to the node cache where - it can be used again. - Remove(NULL) is a harmless no-op - but probably is a wart. -*/ -void *CBaseList::RemoveI(WXLIST_POSITION pos) -{ - /* Lock the critical section before continuing */ - - // ASSERT (pos!=NULL); // Removing NULL is to be harmless! - if (pos==NULL) return NULL; - - - CNode *pCurrent = (CNode *) pos; - ASSERT(pCurrent != NULL); - - /* Update the previous node */ - - CNode *pNode = pCurrent->Prev(); - if (pNode == NULL) { - m_pFirst = pCurrent->Next(); - } else { - pNode->SetNext(pCurrent->Next()); - } - - /* Update the following node */ - - pNode = pCurrent->Next(); - if (pNode == NULL) { - m_pLast = pCurrent->Prev(); - } else { - pNode->SetPrev(pCurrent->Prev()); - } - - /* Get the object this node was looking after */ - - void *pObject = pCurrent->GetData(); - - // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. - - /* Try and add the node object to the cache - - a NULL return code from the cache means we ran out of room. - The cache size is fixed by a constructor argument when the - list is created and defaults to DEFAULTCACHE. - This means that the cache will have room for this many - node objects. So if you have a list of media samples - and you know there will never be more than five active at - any given time of them for example then override the default - constructor - */ - - m_Cache.AddToCache(pCurrent); - - /* If the list is empty then reset the list event */ - - --m_Count; - ASSERT(m_Count >= 0); - return pObject; -} // Remove - - - -/* Add this object to the tail end of our list - Return the new tail position. -*/ - -WXLIST_POSITION CBaseList::AddTailI(void *pObject) -{ - /* Lock the critical section before continuing */ - - CNode *pNode; - // ASSERT(pObject); // NULL pointers in the list are allowed. - - /* If there is a node objects in the cache then use - that otherwise we will have to create a new one */ - - pNode = (CNode *) m_Cache.RemoveFromCache(); - if (pNode == NULL) { - pNode = new CNode; - } - - /* Check we have a valid object */ - - if (pNode == NULL) { - return NULL; - } - - /* Initialise all the CNode object - just in case it came from the cache - */ - - pNode->SetData(pObject); - pNode->SetNext(NULL); - pNode->SetPrev(m_pLast); - - if (m_pLast == NULL) { - m_pFirst = pNode; - } else { - m_pLast->SetNext(pNode); - } - - /* Set the new last node pointer and also increment the number - of list entries, the critical section is unlocked when we - exit the function - */ - - m_pLast = pNode; - ++m_Count; - - return (WXLIST_POSITION) pNode; -} // AddTail(object) - - - -/* Add this object to the head end of our list - Return the new head position. -*/ -WXLIST_POSITION CBaseList::AddHeadI(void *pObject) -{ - CNode *pNode; - // ASSERT(pObject); // NULL pointers in the list are allowed. - - /* If there is a node objects in the cache then use - that otherwise we will have to create a new one */ - - pNode = (CNode *) m_Cache.RemoveFromCache(); - if (pNode == NULL) { - pNode = new CNode; - } - - /* Check we have a valid object */ - - if (pNode == NULL) { - return NULL; - } - - /* Initialise all the CNode object - just in case it came from the cache - */ - - pNode->SetData(pObject); - - /* chain it in (set four pointers) */ - pNode->SetPrev(NULL); - pNode->SetNext(m_pFirst); - - if (m_pFirst == NULL) { - m_pLast = pNode; - } else { - m_pFirst->SetPrev(pNode); - } - m_pFirst = pNode; - - ++m_Count; - - return (WXLIST_POSITION) pNode; -} // AddHead(object) - - - -/* Add all the elements in *pList to the tail of this list. - Return TRUE if it all worked, FALSE if it didn't. - If it fails some elements may have been added. -*/ -BOOL CBaseList::AddTail(CBaseList *pList) -{ - /* lock the object before starting then enumerate - each entry in the source list and add them one by one to - our list (while still holding the object lock) - Lock the other list too. - */ - WXLIST_POSITION pos = pList->GetHeadPositionI(); - - while (pos) { - if (NULL == AddTailI(pList->GetNextI(pos))) { - return FALSE; - } - } - return TRUE; -} // AddTail(list) - - - -/* Add all the elements in *pList to the head of this list. - Return TRUE if it all worked, FALSE if it didn't. - If it fails some elements may have been added. -*/ -BOOL CBaseList::AddHead(CBaseList *pList) -{ - /* lock the object before starting then enumerate - each entry in the source list and add them one by one to - our list (while still holding the object lock) - Lock the other list too. - - To avoid reversing the list, traverse it backwards. - */ - - WXLIST_POSITION pos; - - INTERNALREVERSETRAVERSELIST(*pList, pos) { - if (NULL== AddHeadI(pList->GetI(pos))){ - return FALSE; - } - } - return TRUE; -} // AddHead(list) - - - -/* Add the object after position p - p is still valid after the operation. - AddAfter(NULL,x) adds x to the start - same as AddHead - Return the position of the new object, NULL if it failed -*/ -WXLIST_POSITION CBaseList::AddAfterI(WXLIST_POSITION pos, void * pObj) -{ - if (pos==NULL) - return AddHeadI(pObj); - - /* As someone else might be furkling with the list - - Lock the critical section before continuing - */ - CNode *pAfter = (CNode *) pos; - ASSERT(pAfter != NULL); - if (pAfter==m_pLast) - return AddTailI(pObj); - - /* set pnode to point to a new node, preferably from the cache */ - - CNode *pNode = (CNode *) m_Cache.RemoveFromCache(); - if (pNode == NULL) { - pNode = new CNode; - } - - /* Check we have a valid object */ - - if (pNode == NULL) { - return NULL; - } - - /* Initialise all the CNode object - just in case it came from the cache - */ - - pNode->SetData(pObj); - - /* It is to be added to the middle of the list - there is a before - and after node. Chain it after pAfter, before pBefore. - */ - CNode * pBefore = pAfter->Next(); - ASSERT(pBefore != NULL); - - /* chain it in (set four pointers) */ - pNode->SetPrev(pAfter); - pNode->SetNext(pBefore); - pBefore->SetPrev(pNode); - pAfter->SetNext(pNode); - - ++m_Count; - - return (WXLIST_POSITION) pNode; - -} // AddAfter(object) - - - -BOOL CBaseList::AddAfter(WXLIST_POSITION p, CBaseList *pList) -{ - WXLIST_POSITION pos; - INTERNALTRAVERSELIST(*pList, pos) { - /* p follows along the elements being added */ - p = AddAfterI(p, pList->GetI(pos)); - if (p==NULL) return FALSE; - } - return TRUE; -} // AddAfter(list) - - - -/* Mirror images: - Add the element or list after position p. - p is still valid after the operation. - AddBefore(NULL,x) adds x to the end - same as AddTail -*/ -WXLIST_POSITION CBaseList::AddBeforeI(WXLIST_POSITION pos, void * pObj) -{ - if (pos==NULL) - return AddTailI(pObj); - - /* set pnode to point to a new node, preferably from the cache */ - - CNode *pBefore = (CNode *) pos; - ASSERT(pBefore != NULL); - if (pBefore==m_pFirst) - return AddHeadI(pObj); - - CNode * pNode = (CNode *) m_Cache.RemoveFromCache(); - if (pNode == NULL) { - pNode = new CNode; - } - - /* Check we have a valid object */ - - if (pNode == NULL) { - return NULL; - } - - /* Initialise all the CNode object - just in case it came from the cache - */ - - pNode->SetData(pObj); - - /* It is to be added to the middle of the list - there is a before - and after node. Chain it after pAfter, before pBefore. - */ - - CNode * pAfter = pBefore->Prev(); - ASSERT(pAfter != NULL); - - /* chain it in (set four pointers) */ - pNode->SetPrev(pAfter); - pNode->SetNext(pBefore); - pBefore->SetPrev(pNode); - pAfter->SetNext(pNode); - - ++m_Count; - - return (WXLIST_POSITION) pNode; - -} // Addbefore(object) - - - -BOOL CBaseList::AddBefore(WXLIST_POSITION p, CBaseList *pList) -{ - WXLIST_POSITION pos; - INTERNALREVERSETRAVERSELIST(*pList, pos) { - /* p follows along the elements being added */ - p = AddBeforeI(p, pList->GetI(pos)); - if (p==NULL) return FALSE; - } - return TRUE; -} // AddBefore(list) - - - -/* Split *this after position p in *this - Retain as *this the tail portion of the original *this - Add the head portion to the tail end of *pList - Return TRUE if it all worked, FALSE if it didn't. - - e.g. - foo->MoveToTail(foo->GetHeadPosition(), bar); - moves one element from the head of foo to the tail of bar - foo->MoveToTail(NULL, bar); - is a no-op - foo->MoveToTail(foo->GetTailPosition, bar); - concatenates foo onto the end of bar and empties foo. - - A better, except excessively long name might be - MoveElementsFromHeadThroughPositionToOtherTail -*/ -BOOL CBaseList::MoveToTail - (WXLIST_POSITION pos, CBaseList *pList) -{ - /* Algorithm: - Note that the elements (including their order) in the concatenation - of *pList to the head of *this is invariant. - 1. Count elements to be moved - 2. Join *pList onto the head of this to make one long chain - 3. Set first/Last pointers in *this and *pList - 4. Break the chain at the new place - 5. Adjust counts - 6. Set/Reset any events - */ - - if (pos==NULL) return TRUE; // no-op. Eliminates special cases later. - - - /* Make cMove the number of nodes to move */ - CNode * p = (CNode *)pos; - int cMove = 0; // number of nodes to move - while(p!=NULL) { - p = p->Prev(); - ++cMove; - } - - - /* Join the two chains together */ - if (pList->m_pLast!=NULL) - pList->m_pLast->SetNext(m_pFirst); - if (m_pFirst!=NULL) - m_pFirst->SetPrev(pList->m_pLast); - - - /* set first and last pointers */ - p = (CNode *)pos; - - if (pList->m_pFirst==NULL) - pList->m_pFirst = m_pFirst; - m_pFirst = p->Next(); - if (m_pFirst==NULL) - m_pLast = NULL; - pList->m_pLast = p; - - - /* Break the chain after p to create the new pieces */ - if (m_pFirst!=NULL) - m_pFirst->SetPrev(NULL); - p->SetNext(NULL); - - - /* Adjust the counts */ - m_Count -= cMove; - pList->m_Count += cMove; - - return TRUE; - -} // MoveToTail - - - -/* Mirror image of MoveToTail: - Split *this before position p in *this. - Retain in *this the head portion of the original *this - Add the tail portion to the start (i.e. head) of *pList - Return TRUE if it all worked, FALSE if it didn't. - - e.g. - foo->MoveToHead(foo->GetTailPosition(), bar); - moves one element from the tail of foo to the head of bar - foo->MoveToHead(NULL, bar); - is a no-op - foo->MoveToHead(foo->GetHeadPosition, bar); - concatenates foo onto the start of bar and empties foo. -*/ -BOOL CBaseList::MoveToHead - (WXLIST_POSITION pos, CBaseList *pList) -{ - - /* See the comments on the algorithm in MoveToTail */ - - if (pos==NULL) return TRUE; // no-op. Eliminates special cases later. - - /* Make cMove the number of nodes to move */ - CNode * p = (CNode *)pos; - int cMove = 0; // number of nodes to move - while(p!=NULL) { - p = p->Next(); - ++cMove; - } - - - /* Join the two chains together */ - if (pList->m_pFirst!=NULL) - pList->m_pFirst->SetPrev(m_pLast); - if (m_pLast!=NULL) - m_pLast->SetNext(pList->m_pFirst); - - - /* set first and last pointers */ - p = (CNode *)pos; - - - if (pList->m_pLast==NULL) - pList->m_pLast = m_pLast; - - m_pLast = p->Prev(); - if (m_pLast==NULL) - m_pFirst = NULL; - pList->m_pFirst = p; - - - /* Break the chain after p to create the new pieces */ - if (m_pLast!=NULL) - m_pLast->SetNext(NULL); - p->SetPrev(NULL); - - - /* Adjust the counts */ - m_Count -= cMove; - pList->m_Count += cMove; - - return TRUE; - -} // MoveToHead - - - -/* Reverse the order of the [pointers to] objects in *this -*/ -void CBaseList::Reverse() -{ - /* algorithm: - The obvious booby trap is that you flip pointers around and lose - addressability to the node that you are going to process next. - The easy way to avoid this is do do one chain at a time. - - Run along the forward chain, - For each node, set the reverse pointer to the one ahead of us. - The reverse chain is now a copy of the old forward chain, including - the NULL termination. - - Run along the reverse chain (i.e. old forward chain again) - For each node set the forward pointer of the node ahead to point back - to the one we're standing on. - The first node needs special treatment, - it's new forward pointer is NULL. - Finally set the First/Last pointers - - */ - CNode * p; - - // Yes we COULD use a traverse, but it would look funny! - p = m_pFirst; - while (p!=NULL) { - CNode * q; - q = p->Next(); - p->SetNext(p->Prev()); - p->SetPrev(q); - p = q; - } - - p = m_pFirst; - m_pFirst = m_pLast; - m_pLast = p; - - -#if 0 // old version - - if (m_pFirst==NULL) return; // empty list - if (m_pFirst->Next()==NULL) return; // single node list - - - /* run along forward chain */ - for ( p = m_pFirst - ; p!=NULL - ; p = p->Next() - ){ - p->SetPrev(p->Next()); - } - - - /* special case first element */ - m_pFirst->SetNext(NULL); // fix the old first element - - - /* run along new reverse chain i.e. old forward chain again */ - for ( p = m_pFirst // start at the old first element - ; p->Prev()!=NULL // while there's a node still to be set - ; p = p->Prev() // work in the same direction as before - ){ - p->Prev()->SetNext(p); - } - - - /* fix forward and reverse pointers - - the triple XOR swap would work but all the casts look hideous */ - p = m_pFirst; - m_pFirst = m_pLast; - m_pLast = p; -#endif - -} // Reverse +//------------------------------------------------------------------------------ +// File: WXList.cpp +// +// Desc: DirectShow base classes - implements a non-MFC based generic list +// template class. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* A generic list of pointers to objects. + Objectives: avoid using MFC libraries in ndm kernel mode and + provide a really useful list type. + + The class is thread safe in that separate threads may add and + delete items in the list concurrently although the application + must ensure that constructor and destructor access is suitably + synchronised. + + The list name must not conflict with MFC classes as an + application may use both + + The nodes form a doubly linked, NULL terminated chain with an anchor + block (the list object per se) holding pointers to the first and last + nodes and a count of the nodes. + There is a node cache to reduce the allocation and freeing overhead. + It optionally (determined at construction time) has an Event which is + set whenever the list becomes non-empty and reset whenever it becomes + empty. + It optionally (determined at construction time) has a Critical Section + which is entered during the important part of each operation. (About + all you can do outside it is some parameter checking). + + The node cache is a repository of nodes that are NOT in the list to speed + up storage allocation. Each list has its own cache to reduce locking and + serialising. The list accesses are serialised anyway for a given list - a + common cache would mean that we would have to separately serialise access + of all lists within the cache. Because the cache only stores nodes that are + not in the list, releasing the cache does not release any list nodes. This + means that list nodes can be copied or rechained from one list to another + without danger of creating a dangling reference if the original cache goes + away. + + Questionable design decisions: + 1. Retaining the warts for compatibility + 2. Keeping an element count -i.e. counting whenever we do anything + instead of only when we want the count. + 3. Making the chain pointers NULL terminated. If the list object + itself looks just like a node and the list is kept as a ring then + it reduces the number of special cases. All inserts look the same. +*/ + + +#include "streams.h" + +/* set cursor to the position of each element of list in turn */ +#define INTERNALTRAVERSELIST(list, cursor) \ +for ( cursor = (list).GetHeadPositionI() \ + ; cursor!=NULL \ + ; cursor = (list).Next(cursor) \ + ) + + +/* set cursor to the position of each element of list in turn + in reverse order +*/ +#define INTERNALREVERSETRAVERSELIST(list, cursor) \ +for ( cursor = (list).GetTailPositionI() \ + ; cursor!=NULL \ + ; cursor = (list).Prev(cursor) \ + ) + +/* Constructor calls a separate initialisation function that + creates a node cache, optionally creates a lock object + and optionally creates a signaling object. + + By default we create a locking object, a DEFAULTCACHE sized + cache but no event object so the list cannot be used in calls + to WaitForSingleObject +*/ +CBaseList::CBaseList(TCHAR *pName, // Descriptive list name + INT iItems) : // Node cache size +#ifdef DEBUG + CBaseObject(pName), +#endif + m_pFirst(NULL), + m_pLast(NULL), + m_Count(0), + m_Cache(iItems) +{ +} // constructor + +CBaseList::CBaseList(TCHAR *pName) : // Descriptive list name +#ifdef DEBUG + CBaseObject(pName), +#endif + m_pFirst(NULL), + m_pLast(NULL), + m_Count(0), + m_Cache(DEFAULTCACHE) +{ +} // constructor + +#ifdef UNICODE +CBaseList::CBaseList(CHAR *pName, // Descriptive list name + INT iItems) : // Node cache size +#ifdef DEBUG + CBaseObject(pName), +#endif + m_pFirst(NULL), + m_pLast(NULL), + m_Count(0), + m_Cache(iItems) +{ +} // constructor + +CBaseList::CBaseList(CHAR *pName) : // Descriptive list name +#ifdef DEBUG + CBaseObject(pName), +#endif + m_pFirst(NULL), + m_pLast(NULL), + m_Count(0), + m_Cache(DEFAULTCACHE) +{ +} // constructor + +#endif + +/* The destructor enumerates all the node objects in the list and + in the cache deleting each in turn. We do not do any processing + on the objects that the list holds (i.e. points to) so if they + represent interfaces for example the creator of the list should + ensure that each of them is released before deleting us +*/ +CBaseList::~CBaseList() +{ + /* Delete all our list nodes */ + + RemoveAll(); + +} // destructor + +/* Remove all the nodes from the list but don't do anything + with the objects that each node looks after (this is the + responsibility of the creator). + Aa a last act we reset the signalling event + (if available) to indicate to clients that the list + does not have any entries in it. +*/ +void CBaseList::RemoveAll() +{ + /* Free up all the CNode objects NOTE we don't bother putting the + deleted nodes into the cache as this method is only really called + in serious times of change such as when we are being deleted at + which point the cache will be deleted anway */ + + CNode *pn = m_pFirst; + while (pn) { + CNode *op = pn; + pn = pn->Next(); + delete op; + } + + /* Reset the object count and the list pointers */ + + m_Count = 0; + m_pFirst = m_pLast = NULL; + +} // RemoveAll + + + +/* Return a position enumerator for the entire list. + A position enumerator is a pointer to a node object cast to a + transparent type so all we do is return the head/tail node + pointer in the list. + WARNING because the position is a pointer to a node there is + an implicit assumption for users a the list class that after + deleting an object from the list that any other position + enumerators that you have may be invalid (since the node + may be gone). +*/ +WXLIST_POSITION CBaseList::GetHeadPositionI() const +{ + return (WXLIST_POSITION) m_pFirst; +} // GetHeadPosition + + + +WXLIST_POSITION CBaseList::GetTailPositionI() const +{ + return (WXLIST_POSITION) m_pLast; +} // GetTailPosition + + + +/* Get the number of objects in the list, + Get the lock before accessing the count. + Locking may not be entirely necessary but it has the side effect + of making sure that all operations are complete before we get it. + So for example if a list is being added to this list then that + will have completed in full before we continue rather than seeing + an intermediate albeit valid state +*/ +int CBaseList::GetCountI() const +{ + return m_Count; +} // GetCount + + + +/* Return the object at rp, update rp to the next object from + the list or NULL if you have moved over the last object. + You may still call this function once we return NULL but + we will continue to return a NULL position value +*/ +void *CBaseList::GetNextI(WXLIST_POSITION& rp) const +{ + /* have we reached the end of the list */ + + if (rp == NULL) { + return NULL; + } + + /* Lock the object before continuing */ + + void *pObject; + + /* Copy the original position then step on */ + + CNode *pn = (CNode *) rp; + ASSERT(pn != NULL); + rp = (WXLIST_POSITION) pn->Next(); + + /* Get the object at the original position from the list */ + + pObject = pn->GetData(); + // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. + return pObject; +} //GetNext + + + +/* Return the object at p. + Asking for the object at NULL ASSERTs then returns NULL + The object is NOT locked. The list is not being changed + in any way. If another thread is busy deleting the object + then locking would only result in a change from one bad + behaviour to another. +*/ +void *CBaseList::GetI(WXLIST_POSITION p) const +{ + if (p == NULL) { + return NULL; + } + + CNode * pn = (CNode *) p; + void *pObject = pn->GetData(); + // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. + return pObject; +} //Get + + + +/* Return the first position in the list which holds the given pointer. + Return NULL if it's not found. +*/ +WXLIST_POSITION CBaseList::FindI( void * pObj) const +{ + WXLIST_POSITION pn; + INTERNALTRAVERSELIST(*this, pn){ + if (GetI(pn)==pObj) { + return pn; + } + } + return NULL; +} // Find + + + +/* Remove the first node in the list (deletes the pointer to its object + from the list, does not free the object itself). + Return the pointer to its object or NULL if empty +*/ +void *CBaseList::RemoveHeadI() +{ + /* All we do is get the head position and ask for that to be deleted. + We could special case this since some of the code path checking + in Remove() is redundant as we know there is no previous + node for example but it seems to gain little over the + added complexity + */ + + return RemoveI((WXLIST_POSITION)m_pFirst); +} // RemoveHead + + + +/* Remove the last node in the list (deletes the pointer to its object + from the list, does not free the object itself). + Return the pointer to its object or NULL if empty +*/ +void *CBaseList::RemoveTailI() +{ + /* All we do is get the tail position and ask for that to be deleted. + We could special case this since some of the code path checking + in Remove() is redundant as we know there is no previous + node for example but it seems to gain little over the + added complexity + */ + + return RemoveI((WXLIST_POSITION)m_pLast); +} // RemoveTail + + + +/* Remove the pointer to the object in this position from the list. + Deal with all the chain pointers + Return a pointer to the object removed from the list. + The node object that is freed as a result + of this operation is added to the node cache where + it can be used again. + Remove(NULL) is a harmless no-op - but probably is a wart. +*/ +void *CBaseList::RemoveI(WXLIST_POSITION pos) +{ + /* Lock the critical section before continuing */ + + // ASSERT (pos!=NULL); // Removing NULL is to be harmless! + if (pos==NULL) return NULL; + + + CNode *pCurrent = (CNode *) pos; + ASSERT(pCurrent != NULL); + + /* Update the previous node */ + + CNode *pNode = pCurrent->Prev(); + if (pNode == NULL) { + m_pFirst = pCurrent->Next(); + } else { + pNode->SetNext(pCurrent->Next()); + } + + /* Update the following node */ + + pNode = pCurrent->Next(); + if (pNode == NULL) { + m_pLast = pCurrent->Prev(); + } else { + pNode->SetPrev(pCurrent->Prev()); + } + + /* Get the object this node was looking after */ + + void *pObject = pCurrent->GetData(); + + // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. + + /* Try and add the node object to the cache - + a NULL return code from the cache means we ran out of room. + The cache size is fixed by a constructor argument when the + list is created and defaults to DEFAULTCACHE. + This means that the cache will have room for this many + node objects. So if you have a list of media samples + and you know there will never be more than five active at + any given time of them for example then override the default + constructor + */ + + m_Cache.AddToCache(pCurrent); + + /* If the list is empty then reset the list event */ + + --m_Count; + ASSERT(m_Count >= 0); + return pObject; +} // Remove + + + +/* Add this object to the tail end of our list + Return the new tail position. +*/ + +WXLIST_POSITION CBaseList::AddTailI(void *pObject) +{ + /* Lock the critical section before continuing */ + + CNode *pNode; + // ASSERT(pObject); // NULL pointers in the list are allowed. + + /* If there is a node objects in the cache then use + that otherwise we will have to create a new one */ + + pNode = (CNode *) m_Cache.RemoveFromCache(); + if (pNode == NULL) { + pNode = new CNode; + } + + /* Check we have a valid object */ + + if (pNode == NULL) { + return NULL; + } + + /* Initialise all the CNode object + just in case it came from the cache + */ + + pNode->SetData(pObject); + pNode->SetNext(NULL); + pNode->SetPrev(m_pLast); + + if (m_pLast == NULL) { + m_pFirst = pNode; + } else { + m_pLast->SetNext(pNode); + } + + /* Set the new last node pointer and also increment the number + of list entries, the critical section is unlocked when we + exit the function + */ + + m_pLast = pNode; + ++m_Count; + + return (WXLIST_POSITION) pNode; +} // AddTail(object) + + + +/* Add this object to the head end of our list + Return the new head position. +*/ +WXLIST_POSITION CBaseList::AddHeadI(void *pObject) +{ + CNode *pNode; + // ASSERT(pObject); // NULL pointers in the list are allowed. + + /* If there is a node objects in the cache then use + that otherwise we will have to create a new one */ + + pNode = (CNode *) m_Cache.RemoveFromCache(); + if (pNode == NULL) { + pNode = new CNode; + } + + /* Check we have a valid object */ + + if (pNode == NULL) { + return NULL; + } + + /* Initialise all the CNode object + just in case it came from the cache + */ + + pNode->SetData(pObject); + + /* chain it in (set four pointers) */ + pNode->SetPrev(NULL); + pNode->SetNext(m_pFirst); + + if (m_pFirst == NULL) { + m_pLast = pNode; + } else { + m_pFirst->SetPrev(pNode); + } + m_pFirst = pNode; + + ++m_Count; + + return (WXLIST_POSITION) pNode; +} // AddHead(object) + + + +/* Add all the elements in *pList to the tail of this list. + Return TRUE if it all worked, FALSE if it didn't. + If it fails some elements may have been added. +*/ +BOOL CBaseList::AddTail(CBaseList *pList) +{ + /* lock the object before starting then enumerate + each entry in the source list and add them one by one to + our list (while still holding the object lock) + Lock the other list too. + */ + WXLIST_POSITION pos = pList->GetHeadPositionI(); + + while (pos) { + if (NULL == AddTailI(pList->GetNextI(pos))) { + return FALSE; + } + } + return TRUE; +} // AddTail(list) + + + +/* Add all the elements in *pList to the head of this list. + Return TRUE if it all worked, FALSE if it didn't. + If it fails some elements may have been added. +*/ +BOOL CBaseList::AddHead(CBaseList *pList) +{ + /* lock the object before starting then enumerate + each entry in the source list and add them one by one to + our list (while still holding the object lock) + Lock the other list too. + + To avoid reversing the list, traverse it backwards. + */ + + WXLIST_POSITION pos; + + INTERNALREVERSETRAVERSELIST(*pList, pos) { + if (NULL== AddHeadI(pList->GetI(pos))){ + return FALSE; + } + } + return TRUE; +} // AddHead(list) + + + +/* Add the object after position p + p is still valid after the operation. + AddAfter(NULL,x) adds x to the start - same as AddHead + Return the position of the new object, NULL if it failed +*/ +WXLIST_POSITION CBaseList::AddAfterI(WXLIST_POSITION pos, void * pObj) +{ + if (pos==NULL) + return AddHeadI(pObj); + + /* As someone else might be furkling with the list - + Lock the critical section before continuing + */ + CNode *pAfter = (CNode *) pos; + ASSERT(pAfter != NULL); + if (pAfter==m_pLast) + return AddTailI(pObj); + + /* set pnode to point to a new node, preferably from the cache */ + + CNode *pNode = (CNode *) m_Cache.RemoveFromCache(); + if (pNode == NULL) { + pNode = new CNode; + } + + /* Check we have a valid object */ + + if (pNode == NULL) { + return NULL; + } + + /* Initialise all the CNode object + just in case it came from the cache + */ + + pNode->SetData(pObj); + + /* It is to be added to the middle of the list - there is a before + and after node. Chain it after pAfter, before pBefore. + */ + CNode * pBefore = pAfter->Next(); + ASSERT(pBefore != NULL); + + /* chain it in (set four pointers) */ + pNode->SetPrev(pAfter); + pNode->SetNext(pBefore); + pBefore->SetPrev(pNode); + pAfter->SetNext(pNode); + + ++m_Count; + + return (WXLIST_POSITION) pNode; + +} // AddAfter(object) + + + +BOOL CBaseList::AddAfter(WXLIST_POSITION p, CBaseList *pList) +{ + WXLIST_POSITION pos; + INTERNALTRAVERSELIST(*pList, pos) { + /* p follows along the elements being added */ + p = AddAfterI(p, pList->GetI(pos)); + if (p==NULL) return FALSE; + } + return TRUE; +} // AddAfter(list) + + + +/* Mirror images: + Add the element or list after position p. + p is still valid after the operation. + AddBefore(NULL,x) adds x to the end - same as AddTail +*/ +WXLIST_POSITION CBaseList::AddBeforeI(WXLIST_POSITION pos, void * pObj) +{ + if (pos==NULL) + return AddTailI(pObj); + + /* set pnode to point to a new node, preferably from the cache */ + + CNode *pBefore = (CNode *) pos; + ASSERT(pBefore != NULL); + if (pBefore==m_pFirst) + return AddHeadI(pObj); + + CNode * pNode = (CNode *) m_Cache.RemoveFromCache(); + if (pNode == NULL) { + pNode = new CNode; + } + + /* Check we have a valid object */ + + if (pNode == NULL) { + return NULL; + } + + /* Initialise all the CNode object + just in case it came from the cache + */ + + pNode->SetData(pObj); + + /* It is to be added to the middle of the list - there is a before + and after node. Chain it after pAfter, before pBefore. + */ + + CNode * pAfter = pBefore->Prev(); + ASSERT(pAfter != NULL); + + /* chain it in (set four pointers) */ + pNode->SetPrev(pAfter); + pNode->SetNext(pBefore); + pBefore->SetPrev(pNode); + pAfter->SetNext(pNode); + + ++m_Count; + + return (WXLIST_POSITION) pNode; + +} // Addbefore(object) + + + +BOOL CBaseList::AddBefore(WXLIST_POSITION p, CBaseList *pList) +{ + WXLIST_POSITION pos; + INTERNALREVERSETRAVERSELIST(*pList, pos) { + /* p follows along the elements being added */ + p = AddBeforeI(p, pList->GetI(pos)); + if (p==NULL) return FALSE; + } + return TRUE; +} // AddBefore(list) + + + +/* Split *this after position p in *this + Retain as *this the tail portion of the original *this + Add the head portion to the tail end of *pList + Return TRUE if it all worked, FALSE if it didn't. + + e.g. + foo->MoveToTail(foo->GetHeadPosition(), bar); + moves one element from the head of foo to the tail of bar + foo->MoveToTail(NULL, bar); + is a no-op + foo->MoveToTail(foo->GetTailPosition, bar); + concatenates foo onto the end of bar and empties foo. + + A better, except excessively long name might be + MoveElementsFromHeadThroughPositionToOtherTail +*/ +BOOL CBaseList::MoveToTail + (WXLIST_POSITION pos, CBaseList *pList) +{ + /* Algorithm: + Note that the elements (including their order) in the concatenation + of *pList to the head of *this is invariant. + 1. Count elements to be moved + 2. Join *pList onto the head of this to make one long chain + 3. Set first/Last pointers in *this and *pList + 4. Break the chain at the new place + 5. Adjust counts + 6. Set/Reset any events + */ + + if (pos==NULL) return TRUE; // no-op. Eliminates special cases later. + + + /* Make cMove the number of nodes to move */ + CNode * p = (CNode *)pos; + int cMove = 0; // number of nodes to move + while(p!=NULL) { + p = p->Prev(); + ++cMove; + } + + + /* Join the two chains together */ + if (pList->m_pLast!=NULL) + pList->m_pLast->SetNext(m_pFirst); + if (m_pFirst!=NULL) + m_pFirst->SetPrev(pList->m_pLast); + + + /* set first and last pointers */ + p = (CNode *)pos; + + if (pList->m_pFirst==NULL) + pList->m_pFirst = m_pFirst; + m_pFirst = p->Next(); + if (m_pFirst==NULL) + m_pLast = NULL; + pList->m_pLast = p; + + + /* Break the chain after p to create the new pieces */ + if (m_pFirst!=NULL) + m_pFirst->SetPrev(NULL); + p->SetNext(NULL); + + + /* Adjust the counts */ + m_Count -= cMove; + pList->m_Count += cMove; + + return TRUE; + +} // MoveToTail + + + +/* Mirror image of MoveToTail: + Split *this before position p in *this. + Retain in *this the head portion of the original *this + Add the tail portion to the start (i.e. head) of *pList + Return TRUE if it all worked, FALSE if it didn't. + + e.g. + foo->MoveToHead(foo->GetTailPosition(), bar); + moves one element from the tail of foo to the head of bar + foo->MoveToHead(NULL, bar); + is a no-op + foo->MoveToHead(foo->GetHeadPosition, bar); + concatenates foo onto the start of bar and empties foo. +*/ +BOOL CBaseList::MoveToHead + (WXLIST_POSITION pos, CBaseList *pList) +{ + + /* See the comments on the algorithm in MoveToTail */ + + if (pos==NULL) return TRUE; // no-op. Eliminates special cases later. + + /* Make cMove the number of nodes to move */ + CNode * p = (CNode *)pos; + int cMove = 0; // number of nodes to move + while(p!=NULL) { + p = p->Next(); + ++cMove; + } + + + /* Join the two chains together */ + if (pList->m_pFirst!=NULL) + pList->m_pFirst->SetPrev(m_pLast); + if (m_pLast!=NULL) + m_pLast->SetNext(pList->m_pFirst); + + + /* set first and last pointers */ + p = (CNode *)pos; + + + if (pList->m_pLast==NULL) + pList->m_pLast = m_pLast; + + m_pLast = p->Prev(); + if (m_pLast==NULL) + m_pFirst = NULL; + pList->m_pFirst = p; + + + /* Break the chain after p to create the new pieces */ + if (m_pLast!=NULL) + m_pLast->SetNext(NULL); + p->SetPrev(NULL); + + + /* Adjust the counts */ + m_Count -= cMove; + pList->m_Count += cMove; + + return TRUE; + +} // MoveToHead + + + +/* Reverse the order of the [pointers to] objects in *this +*/ +void CBaseList::Reverse() +{ + /* algorithm: + The obvious booby trap is that you flip pointers around and lose + addressability to the node that you are going to process next. + The easy way to avoid this is do do one chain at a time. + + Run along the forward chain, + For each node, set the reverse pointer to the one ahead of us. + The reverse chain is now a copy of the old forward chain, including + the NULL termination. + + Run along the reverse chain (i.e. old forward chain again) + For each node set the forward pointer of the node ahead to point back + to the one we're standing on. + The first node needs special treatment, + it's new forward pointer is NULL. + Finally set the First/Last pointers + + */ + CNode * p; + + // Yes we COULD use a traverse, but it would look funny! + p = m_pFirst; + while (p!=NULL) { + CNode * q; + q = p->Next(); + p->SetNext(p->Prev()); + p->SetPrev(q); + p = q; + } + + p = m_pFirst; + m_pFirst = m_pLast; + m_pLast = p; + + +#if 0 // old version + + if (m_pFirst==NULL) return; // empty list + if (m_pFirst->Next()==NULL) return; // single node list + + + /* run along forward chain */ + for ( p = m_pFirst + ; p!=NULL + ; p = p->Next() + ){ + p->SetPrev(p->Next()); + } + + + /* special case first element */ + m_pFirst->SetNext(NULL); // fix the old first element + + + /* run along new reverse chain i.e. old forward chain again */ + for ( p = m_pFirst // start at the old first element + ; p->Prev()!=NULL // while there's a node still to be set + ; p = p->Prev() // work in the same direction as before + ){ + p->Prev()->SetNext(p); + } + + + /* fix forward and reverse pointers + - the triple XOR swap would work but all the casts look hideous */ + p = m_pFirst; + m_pFirst = m_pLast; + m_pLast = p; +#endif + +} // Reverse diff --git a/plugins/GSdx/baseclasses/wxlist.h b/plugins/GSdx/baseclasses/wxlist.h index 3c268c3258..d7660e0297 100644 --- a/plugins/GSdx/baseclasses/wxlist.h +++ b/plugins/GSdx/baseclasses/wxlist.h @@ -1,543 +1,543 @@ -//------------------------------------------------------------------------------ -// File: WXList.h -// -// Desc: DirectShow base classes - defines a non-MFC generic template list -// class. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -/* A generic list of pointers to objects. - No storage management or copying is done on the objects pointed to. - Objectives: avoid using MFC libraries in ndm kernel mode and - provide a really useful list type. - - The class is thread safe in that separate threads may add and - delete items in the list concurrently although the application - must ensure that constructor and destructor access is suitably - synchronised. An application can cause deadlock with operations - which use two lists by simultaneously calling - list1->Operation(list2) and list2->Operation(list1). So don't! - - The names must not conflict with MFC classes as an application - may use both. - */ - -#ifndef __WXLIST__ -#define __WXLIST__ - - /* A POSITION represents (in some fashion that's opaque) a cursor - on the list that can be set to identify any element. NULL is - a valid value and several operations regard NULL as the position - "one step off the end of the list". (In an n element list there - are n+1 places to insert and NULL is that "n+1-th" value). - The POSITION of an element in the list is only invalidated if - that element is deleted. Move operations may mean that what - was a valid POSITION in one list is now a valid POSITION in - a different list. - - Some operations which at first sight are illegal are allowed as - harmless no-ops. For instance RemoveHead is legal on an empty - list and it returns NULL. This allows an atomic way to test if - there is an element there, and if so, get it. The two operations - AddTail and RemoveHead thus implement a MONITOR (See Hoare's paper). - - Single element operations return POSITIONs, non-NULL means it worked. - whole list operations return a BOOL. TRUE means it all worked. - - This definition is the same as the POSITION type for MFCs, so we must - avoid defining it twice. - */ -struct __WXLIST_POSITION { int unused; }; -typedef __WXLIST_POSITION* WXLIST_POSITION; - -const int DEFAULTCACHE = 10; /* Default node object cache size */ - -/* A class representing one node in a list. - Each node knows a pointer to it's adjacent nodes and also a pointer - to the object that it looks after. - All of these pointers can be retrieved or set through member functions. -*/ -class CBaseList -#ifdef DEBUG - : public CBaseObject -#endif -{ - /* Making these classes inherit from CBaseObject does nothing - functionally but it allows us to check there are no memory - leaks in debug builds. - */ - -public: - -#ifdef DEBUG - class CNode : public CBaseObject { -#else - class CNode { -#endif - - CNode *m_pPrev; /* Previous node in the list */ - CNode *m_pNext; /* Next node in the list */ - void *m_pObject; /* Pointer to the object */ - - public: - - /* Constructor - initialise the object's pointers */ - CNode() -#ifdef DEBUG - : CBaseObject(NAME("List node")) -#endif - { - }; - - - /* Return the previous node before this one */ - CNode *Prev() const { return m_pPrev; }; - - - /* Return the next node after this one */ - CNode *Next() const { return m_pNext; }; - - - /* Set the previous node before this one */ - void SetPrev(CNode *p) { m_pPrev = p; }; - - - /* Set the next node after this one */ - void SetNext(CNode *p) { m_pNext = p; }; - - - /* Get the pointer to the object for this node */ - void *GetData() const { return m_pObject; }; - - - /* Set the pointer to the object for this node */ - void SetData(void *p) { m_pObject = p; }; - }; - - class CNodeCache - { - public: - CNodeCache(INT iCacheSize) : m_iCacheSize(iCacheSize), - m_pHead(NULL), - m_iUsed(0) - {}; - ~CNodeCache() { - CNode *pNode = m_pHead; - while (pNode) { - CNode *pCurrent = pNode; - pNode = pNode->Next(); - delete pCurrent; - } - }; - void AddToCache(CNode *pNode) - { - if (m_iUsed < m_iCacheSize) { - pNode->SetNext(m_pHead); - m_pHead = pNode; - m_iUsed++; - } else { - delete pNode; - } - }; - CNode *RemoveFromCache() - { - CNode *pNode = m_pHead; - if (pNode != NULL) { - m_pHead = pNode->Next(); - m_iUsed--; - ASSERT(m_iUsed >= 0); - } else { - ASSERT(m_iUsed == 0); - } - return pNode; - }; - private: - INT m_iCacheSize; - INT m_iUsed; - CNode *m_pHead; - }; - -protected: - - CNode* m_pFirst; /* Pointer to first node in the list */ - CNode* m_pLast; /* Pointer to the last node in the list */ - LONG m_Count; /* Number of nodes currently in the list */ - -private: - - CNodeCache m_Cache; /* Cache of unused node pointers */ - -private: - - /* These override the default copy constructor and assignment - operator for all list classes. They are in the private class - declaration section so that anybody trying to pass a list - object by value will generate a compile time error of - "cannot access the private member function". If these were - not here then the compiler will create default constructors - and assignment operators which when executed first take a - copy of all member variables and then during destruction - delete them all. This must not be done for any heap - allocated data. - */ - CBaseList(const CBaseList &refList); - CBaseList &operator=(const CBaseList &refList); - -public: - - CBaseList(TCHAR *pName, - INT iItems); - - CBaseList(TCHAR *pName); -#ifdef UNICODE - CBaseList(CHAR *pName, - INT iItems); - - CBaseList(CHAR *pName); -#endif - ~CBaseList(); - - /* Remove all the nodes from *this i.e. make the list empty */ - void RemoveAll(); - - - /* Return a cursor which identifies the first element of *this */ - WXLIST_POSITION GetHeadPositionI() const; - - - /* Return a cursor which identifies the last element of *this */ - WXLIST_POSITION GetTailPositionI() const; - - - /* Return the number of objects in *this */ - int GetCountI() const; - -protected: - /* Return the pointer to the object at rp, - Update rp to the next node in *this - but make it NULL if it was at the end of *this. - This is a wart retained for backwards compatibility. - GetPrev is not implemented. - Use Next, Prev and Get separately. - */ - void *GetNextI(WXLIST_POSITION& rp) const; - - - /* Return a pointer to the object at p - Asking for the object at NULL will return NULL harmlessly. - */ - void *GetI(WXLIST_POSITION p) const; - -public: - /* return the next / prev position in *this - return NULL when going past the end/start. - Next(NULL) is same as GetHeadPosition() - Prev(NULL) is same as GetTailPosition() - An n element list therefore behaves like a n+1 element - cycle with NULL at the start/end. - - !!WARNING!! - This handling of NULL is DIFFERENT from GetNext. - - Some reasons are: - 1. For a list of n items there are n+1 positions to insert - These are conveniently encoded as the n POSITIONs and NULL. - 2. If you are keeping a list sorted (fairly common) and you - search forward for an element to insert before and don't - find it you finish up with NULL as the element before which - to insert. You then want that NULL to be a valid WXLIST_POSITION - so that you can insert before it and you want that insertion - point to mean the (n+1)-th one that doesn't have a WXLIST_POSITION. - (symmetrically if you are working backwards through the list). - 3. It simplifies the algebra which the methods generate. - e.g. AddBefore(p,x) is identical to AddAfter(Prev(p),x) - in ALL cases. All the other arguments probably are reflections - of the algebraic point. - */ - WXLIST_POSITION Next(WXLIST_POSITION pos) const - { - if (pos == NULL) { - return (WXLIST_POSITION) m_pFirst; - } - CNode *pn = (CNode *) pos; - return (WXLIST_POSITION) pn->Next(); - } //Next - - // See Next - WXLIST_POSITION Prev(WXLIST_POSITION pos) const - { - if (pos == NULL) { - return (WXLIST_POSITION) m_pLast; - } - CNode *pn = (CNode *) pos; - return (WXLIST_POSITION) pn->Prev(); - } //Prev - - - /* Return the first position in *this which holds the given - pointer. Return NULL if the pointer was not not found. - */ -protected: - WXLIST_POSITION FindI( void * pObj) const; - - /* Remove the first node in *this (deletes the pointer to its - object from the list, does not free the object itself). - Return the pointer to its object. - If *this was already empty it will harmlessly return NULL. - */ - void *RemoveHeadI(); - - - /* Remove the last node in *this (deletes the pointer to its - object from the list, does not free the object itself). - Return the pointer to its object. - If *this was already empty it will harmlessly return NULL. - */ - void *RemoveTailI(); - - - /* Remove the node identified by p from the list (deletes the pointer - to its object from the list, does not free the object itself). - Asking to Remove the object at NULL will harmlessly return NULL. - Return the pointer to the object removed. - */ - void *RemoveI(WXLIST_POSITION p); - - /* Add single object *pObj to become a new last element of the list. - Return the new tail position, NULL if it fails. - If you are adding a COM objects, you might want AddRef it first. - Other existing POSITIONs in *this are still valid - */ - WXLIST_POSITION AddTailI(void * pObj); -public: - - - /* Add all the elements in *pList to the tail of *this. - This duplicates all the nodes in *pList (i.e. duplicates - all its pointers to objects). It does not duplicate the objects. - If you are adding a list of pointers to a COM object into the list - it's a good idea to AddRef them all it when you AddTail it. - Return TRUE if it all worked, FALSE if it didn't. - If it fails some elements may have been added. - Existing POSITIONs in *this are still valid - - If you actually want to MOVE the elements, use MoveToTail instead. - */ - BOOL AddTail(CBaseList *pList); - - - /* Mirror images of AddHead: */ - - /* Add single object to become a new first element of the list. - Return the new head position, NULL if it fails. - Existing POSITIONs in *this are still valid - */ -protected: - WXLIST_POSITION AddHeadI(void * pObj); -public: - - /* Add all the elements in *pList to the head of *this. - Same warnings apply as for AddTail. - Return TRUE if it all worked, FALSE if it didn't. - If it fails some of the objects may have been added. - - If you actually want to MOVE the elements, use MoveToHead instead. - */ - BOOL AddHead(CBaseList *pList); - - - /* Add the object *pObj to *this after position p in *this. - AddAfter(NULL,x) adds x to the start - equivalent to AddHead - Return the position of the object added, NULL if it failed. - Existing POSITIONs in *this are undisturbed, including p. - */ -protected: - WXLIST_POSITION AddAfterI(WXLIST_POSITION p, void * pObj); -public: - - /* Add the list *pList to *this after position p in *this - AddAfter(NULL,x) adds x to the start - equivalent to AddHead - Return TRUE if it all worked, FALSE if it didn't. - If it fails, some of the objects may be added - Existing POSITIONs in *this are undisturbed, including p. - */ - BOOL AddAfter(WXLIST_POSITION p, CBaseList *pList); - - - /* Mirror images: - Add the object *pObj to this-List after position p in *this. - AddBefore(NULL,x) adds x to the end - equivalent to AddTail - Return the position of the new object, NULL if it fails - Existing POSITIONs in *this are undisturbed, including p. - */ - protected: - WXLIST_POSITION AddBeforeI(WXLIST_POSITION p, void * pObj); - public: - - /* Add the list *pList to *this before position p in *this - AddAfter(NULL,x) adds x to the start - equivalent to AddHead - Return TRUE if it all worked, FALSE if it didn't. - If it fails, some of the objects may be added - Existing POSITIONs in *this are undisturbed, including p. - */ - BOOL AddBefore(WXLIST_POSITION p, CBaseList *pList); - - - /* Note that AddAfter(p,x) is equivalent to AddBefore(Next(p),x) - even in cases where p is NULL or Next(p) is NULL. - Similarly for mirror images etc. - This may make it easier to argue about programs. - */ - - - - /* The following operations do not copy any elements. - They move existing blocks of elements around by switching pointers. - They are fairly efficient for long lists as for short lists. - (Alas, the Count slows things down). - - They split the list into two parts. - One part remains as the original list, the other part - is appended to the second list. There are eight possible - variations: - Split the list {after/before} a given element - keep the {head/tail} portion in the original list - append the rest to the {head/tail} of the new list. - - Since After is strictly equivalent to Before Next - we are not in serious need of the Before/After variants. - That leaves only four. - - If you are processing a list left to right and dumping - the bits that you have processed into another list as - you go, the Tail/Tail variant gives the most natural result. - If you are processing in reverse order, Head/Head is best. - - By using NULL positions and empty lists judiciously either - of the other two can be built up in two operations. - - The definition of NULL (see Next/Prev etc) means that - degenerate cases include - "move all elements to new list" - "Split a list into two lists" - "Concatenate two lists" - (and quite a few no-ops) - - !!WARNING!! The type checking won't buy you much if you get list - positions muddled up - e.g. use a WXLIST_POSITION that's in a different - list and see what a mess you get! - */ - - /* Split *this after position p in *this - Retain as *this the tail portion of the original *this - Add the head portion to the tail end of *pList - Return TRUE if it all worked, FALSE if it didn't. - - e.g. - foo->MoveToTail(foo->GetHeadPosition(), bar); - moves one element from the head of foo to the tail of bar - foo->MoveToTail(NULL, bar); - is a no-op, returns NULL - foo->MoveToTail(foo->GetTailPosition, bar); - concatenates foo onto the end of bar and empties foo. - - A better, except excessively long name might be - MoveElementsFromHeadThroughPositionToOtherTail - */ - BOOL MoveToTail(WXLIST_POSITION pos, CBaseList *pList); - - - /* Mirror image: - Split *this before position p in *this. - Retain in *this the head portion of the original *this - Add the tail portion to the start (i.e. head) of *pList - - e.g. - foo->MoveToHead(foo->GetTailPosition(), bar); - moves one element from the tail of foo to the head of bar - foo->MoveToHead(NULL, bar); - is a no-op, returns NULL - foo->MoveToHead(foo->GetHeadPosition, bar); - concatenates foo onto the start of bar and empties foo. - */ - BOOL MoveToHead(WXLIST_POSITION pos, CBaseList *pList); - - - /* Reverse the order of the [pointers to] objects in *this - */ - void Reverse(); - - - /* set cursor to the position of each element of list in turn */ - #define TRAVERSELIST(list, cursor) \ - for ( cursor = (list).GetHeadPosition() \ - ; cursor!=NULL \ - ; cursor = (list).Next(cursor) \ - ) - - - /* set cursor to the position of each element of list in turn - in reverse order - */ - #define REVERSETRAVERSELIST(list, cursor) \ - for ( cursor = (list).GetTailPosition() \ - ; cursor!=NULL \ - ; cursor = (list).Prev(cursor) \ - ) - -}; // end of class declaration - -template class CGenericList : public CBaseList -{ -public: - CGenericList(TCHAR *pName, - INT iItems, - BOOL bLock = TRUE, - BOOL bAlert = FALSE) : - CBaseList(pName, iItems) { - UNREFERENCED_PARAMETER(bAlert); - UNREFERENCED_PARAMETER(bLock); - }; - CGenericList(TCHAR *pName) : - CBaseList(pName) { - }; - - WXLIST_POSITION GetHeadPosition() const { return (WXLIST_POSITION)m_pFirst; } - WXLIST_POSITION GetTailPosition() const { return (WXLIST_POSITION)m_pLast; } - int GetCount() const { return m_Count; } - - OBJECT *GetNext(WXLIST_POSITION& rp) const { return (OBJECT *) GetNextI(rp); } - - OBJECT *Get(WXLIST_POSITION p) const { return (OBJECT *) GetI(p); } - OBJECT *GetHead() const { return Get(GetHeadPosition()); } - - OBJECT *RemoveHead() { return (OBJECT *) RemoveHeadI(); } - - OBJECT *RemoveTail() { return (OBJECT *) RemoveTailI(); } - - OBJECT *Remove(WXLIST_POSITION p) { return (OBJECT *) RemoveI(p); } - WXLIST_POSITION AddBefore(WXLIST_POSITION p, OBJECT * pObj) { return AddBeforeI(p, pObj); } - WXLIST_POSITION AddAfter(WXLIST_POSITION p, OBJECT * pObj) { return AddAfterI(p, pObj); } - WXLIST_POSITION AddHead(OBJECT * pObj) { return AddHeadI(pObj); } - WXLIST_POSITION AddTail(OBJECT * pObj) { return AddTailI(pObj); } - BOOL AddTail(CGenericList *pList) - { return CBaseList::AddTail((CBaseList *) pList); } - BOOL AddHead(CGenericList *pList) - { return CBaseList::AddHead((CBaseList *) pList); } - BOOL AddAfter(WXLIST_POSITION p, CGenericList *pList) - { return CBaseList::AddAfter(p, (CBaseList *) pList); }; - BOOL AddBefore(WXLIST_POSITION p, CGenericList *pList) - { return CBaseList::AddBefore(p, (CBaseList *) pList); }; - WXLIST_POSITION Find( OBJECT * pObj) const { return FindI(pObj); } -}; // end of class declaration - - - -/* These define the standard list types */ - -typedef CGenericList CBaseObjectList; -typedef CGenericList CBaseInterfaceList; - -#endif /* __WXLIST__ */ - +//------------------------------------------------------------------------------ +// File: WXList.h +// +// Desc: DirectShow base classes - defines a non-MFC generic template list +// class. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* A generic list of pointers to objects. + No storage management or copying is done on the objects pointed to. + Objectives: avoid using MFC libraries in ndm kernel mode and + provide a really useful list type. + + The class is thread safe in that separate threads may add and + delete items in the list concurrently although the application + must ensure that constructor and destructor access is suitably + synchronised. An application can cause deadlock with operations + which use two lists by simultaneously calling + list1->Operation(list2) and list2->Operation(list1). So don't! + + The names must not conflict with MFC classes as an application + may use both. + */ + +#ifndef __WXLIST__ +#define __WXLIST__ + + /* A POSITION represents (in some fashion that's opaque) a cursor + on the list that can be set to identify any element. NULL is + a valid value and several operations regard NULL as the position + "one step off the end of the list". (In an n element list there + are n+1 places to insert and NULL is that "n+1-th" value). + The POSITION of an element in the list is only invalidated if + that element is deleted. Move operations may mean that what + was a valid POSITION in one list is now a valid POSITION in + a different list. + + Some operations which at first sight are illegal are allowed as + harmless no-ops. For instance RemoveHead is legal on an empty + list and it returns NULL. This allows an atomic way to test if + there is an element there, and if so, get it. The two operations + AddTail and RemoveHead thus implement a MONITOR (See Hoare's paper). + + Single element operations return POSITIONs, non-NULL means it worked. + whole list operations return a BOOL. TRUE means it all worked. + + This definition is the same as the POSITION type for MFCs, so we must + avoid defining it twice. + */ +struct __WXLIST_POSITION { int unused; }; +typedef __WXLIST_POSITION* WXLIST_POSITION; + +const int DEFAULTCACHE = 10; /* Default node object cache size */ + +/* A class representing one node in a list. + Each node knows a pointer to it's adjacent nodes and also a pointer + to the object that it looks after. + All of these pointers can be retrieved or set through member functions. +*/ +class CBaseList +#ifdef DEBUG + : public CBaseObject +#endif +{ + /* Making these classes inherit from CBaseObject does nothing + functionally but it allows us to check there are no memory + leaks in debug builds. + */ + +public: + +#ifdef DEBUG + class CNode : public CBaseObject { +#else + class CNode { +#endif + + CNode *m_pPrev; /* Previous node in the list */ + CNode *m_pNext; /* Next node in the list */ + void *m_pObject; /* Pointer to the object */ + + public: + + /* Constructor - initialise the object's pointers */ + CNode() +#ifdef DEBUG + : CBaseObject(NAME("List node")) +#endif + { + }; + + + /* Return the previous node before this one */ + CNode *Prev() const { return m_pPrev; }; + + + /* Return the next node after this one */ + CNode *Next() const { return m_pNext; }; + + + /* Set the previous node before this one */ + void SetPrev(CNode *p) { m_pPrev = p; }; + + + /* Set the next node after this one */ + void SetNext(CNode *p) { m_pNext = p; }; + + + /* Get the pointer to the object for this node */ + void *GetData() const { return m_pObject; }; + + + /* Set the pointer to the object for this node */ + void SetData(void *p) { m_pObject = p; }; + }; + + class CNodeCache + { + public: + CNodeCache(INT iCacheSize) : m_iCacheSize(iCacheSize), + m_pHead(NULL), + m_iUsed(0) + {}; + ~CNodeCache() { + CNode *pNode = m_pHead; + while (pNode) { + CNode *pCurrent = pNode; + pNode = pNode->Next(); + delete pCurrent; + } + }; + void AddToCache(CNode *pNode) + { + if (m_iUsed < m_iCacheSize) { + pNode->SetNext(m_pHead); + m_pHead = pNode; + m_iUsed++; + } else { + delete pNode; + } + }; + CNode *RemoveFromCache() + { + CNode *pNode = m_pHead; + if (pNode != NULL) { + m_pHead = pNode->Next(); + m_iUsed--; + ASSERT(m_iUsed >= 0); + } else { + ASSERT(m_iUsed == 0); + } + return pNode; + }; + private: + INT m_iCacheSize; + INT m_iUsed; + CNode *m_pHead; + }; + +protected: + + CNode* m_pFirst; /* Pointer to first node in the list */ + CNode* m_pLast; /* Pointer to the last node in the list */ + LONG m_Count; /* Number of nodes currently in the list */ + +private: + + CNodeCache m_Cache; /* Cache of unused node pointers */ + +private: + + /* These override the default copy constructor and assignment + operator for all list classes. They are in the private class + declaration section so that anybody trying to pass a list + object by value will generate a compile time error of + "cannot access the private member function". If these were + not here then the compiler will create default constructors + and assignment operators which when executed first take a + copy of all member variables and then during destruction + delete them all. This must not be done for any heap + allocated data. + */ + CBaseList(const CBaseList &refList); + CBaseList &operator=(const CBaseList &refList); + +public: + + CBaseList(TCHAR *pName, + INT iItems); + + CBaseList(TCHAR *pName); +#ifdef UNICODE + CBaseList(CHAR *pName, + INT iItems); + + CBaseList(CHAR *pName); +#endif + ~CBaseList(); + + /* Remove all the nodes from *this i.e. make the list empty */ + void RemoveAll(); + + + /* Return a cursor which identifies the first element of *this */ + WXLIST_POSITION GetHeadPositionI() const; + + + /* Return a cursor which identifies the last element of *this */ + WXLIST_POSITION GetTailPositionI() const; + + + /* Return the number of objects in *this */ + int GetCountI() const; + +protected: + /* Return the pointer to the object at rp, + Update rp to the next node in *this + but make it NULL if it was at the end of *this. + This is a wart retained for backwards compatibility. + GetPrev is not implemented. + Use Next, Prev and Get separately. + */ + void *GetNextI(WXLIST_POSITION& rp) const; + + + /* Return a pointer to the object at p + Asking for the object at NULL will return NULL harmlessly. + */ + void *GetI(WXLIST_POSITION p) const; + +public: + /* return the next / prev position in *this + return NULL when going past the end/start. + Next(NULL) is same as GetHeadPosition() + Prev(NULL) is same as GetTailPosition() + An n element list therefore behaves like a n+1 element + cycle with NULL at the start/end. + + !!WARNING!! - This handling of NULL is DIFFERENT from GetNext. + + Some reasons are: + 1. For a list of n items there are n+1 positions to insert + These are conveniently encoded as the n POSITIONs and NULL. + 2. If you are keeping a list sorted (fairly common) and you + search forward for an element to insert before and don't + find it you finish up with NULL as the element before which + to insert. You then want that NULL to be a valid WXLIST_POSITION + so that you can insert before it and you want that insertion + point to mean the (n+1)-th one that doesn't have a WXLIST_POSITION. + (symmetrically if you are working backwards through the list). + 3. It simplifies the algebra which the methods generate. + e.g. AddBefore(p,x) is identical to AddAfter(Prev(p),x) + in ALL cases. All the other arguments probably are reflections + of the algebraic point. + */ + WXLIST_POSITION Next(WXLIST_POSITION pos) const + { + if (pos == NULL) { + return (WXLIST_POSITION) m_pFirst; + } + CNode *pn = (CNode *) pos; + return (WXLIST_POSITION) pn->Next(); + } //Next + + // See Next + WXLIST_POSITION Prev(WXLIST_POSITION pos) const + { + if (pos == NULL) { + return (WXLIST_POSITION) m_pLast; + } + CNode *pn = (CNode *) pos; + return (WXLIST_POSITION) pn->Prev(); + } //Prev + + + /* Return the first position in *this which holds the given + pointer. Return NULL if the pointer was not not found. + */ +protected: + WXLIST_POSITION FindI( void * pObj) const; + + /* Remove the first node in *this (deletes the pointer to its + object from the list, does not free the object itself). + Return the pointer to its object. + If *this was already empty it will harmlessly return NULL. + */ + void *RemoveHeadI(); + + + /* Remove the last node in *this (deletes the pointer to its + object from the list, does not free the object itself). + Return the pointer to its object. + If *this was already empty it will harmlessly return NULL. + */ + void *RemoveTailI(); + + + /* Remove the node identified by p from the list (deletes the pointer + to its object from the list, does not free the object itself). + Asking to Remove the object at NULL will harmlessly return NULL. + Return the pointer to the object removed. + */ + void *RemoveI(WXLIST_POSITION p); + + /* Add single object *pObj to become a new last element of the list. + Return the new tail position, NULL if it fails. + If you are adding a COM objects, you might want AddRef it first. + Other existing POSITIONs in *this are still valid + */ + WXLIST_POSITION AddTailI(void * pObj); +public: + + + /* Add all the elements in *pList to the tail of *this. + This duplicates all the nodes in *pList (i.e. duplicates + all its pointers to objects). It does not duplicate the objects. + If you are adding a list of pointers to a COM object into the list + it's a good idea to AddRef them all it when you AddTail it. + Return TRUE if it all worked, FALSE if it didn't. + If it fails some elements may have been added. + Existing POSITIONs in *this are still valid + + If you actually want to MOVE the elements, use MoveToTail instead. + */ + BOOL AddTail(CBaseList *pList); + + + /* Mirror images of AddHead: */ + + /* Add single object to become a new first element of the list. + Return the new head position, NULL if it fails. + Existing POSITIONs in *this are still valid + */ +protected: + WXLIST_POSITION AddHeadI(void * pObj); +public: + + /* Add all the elements in *pList to the head of *this. + Same warnings apply as for AddTail. + Return TRUE if it all worked, FALSE if it didn't. + If it fails some of the objects may have been added. + + If you actually want to MOVE the elements, use MoveToHead instead. + */ + BOOL AddHead(CBaseList *pList); + + + /* Add the object *pObj to *this after position p in *this. + AddAfter(NULL,x) adds x to the start - equivalent to AddHead + Return the position of the object added, NULL if it failed. + Existing POSITIONs in *this are undisturbed, including p. + */ +protected: + WXLIST_POSITION AddAfterI(WXLIST_POSITION p, void * pObj); +public: + + /* Add the list *pList to *this after position p in *this + AddAfter(NULL,x) adds x to the start - equivalent to AddHead + Return TRUE if it all worked, FALSE if it didn't. + If it fails, some of the objects may be added + Existing POSITIONs in *this are undisturbed, including p. + */ + BOOL AddAfter(WXLIST_POSITION p, CBaseList *pList); + + + /* Mirror images: + Add the object *pObj to this-List after position p in *this. + AddBefore(NULL,x) adds x to the end - equivalent to AddTail + Return the position of the new object, NULL if it fails + Existing POSITIONs in *this are undisturbed, including p. + */ + protected: + WXLIST_POSITION AddBeforeI(WXLIST_POSITION p, void * pObj); + public: + + /* Add the list *pList to *this before position p in *this + AddAfter(NULL,x) adds x to the start - equivalent to AddHead + Return TRUE if it all worked, FALSE if it didn't. + If it fails, some of the objects may be added + Existing POSITIONs in *this are undisturbed, including p. + */ + BOOL AddBefore(WXLIST_POSITION p, CBaseList *pList); + + + /* Note that AddAfter(p,x) is equivalent to AddBefore(Next(p),x) + even in cases where p is NULL or Next(p) is NULL. + Similarly for mirror images etc. + This may make it easier to argue about programs. + */ + + + + /* The following operations do not copy any elements. + They move existing blocks of elements around by switching pointers. + They are fairly efficient for long lists as for short lists. + (Alas, the Count slows things down). + + They split the list into two parts. + One part remains as the original list, the other part + is appended to the second list. There are eight possible + variations: + Split the list {after/before} a given element + keep the {head/tail} portion in the original list + append the rest to the {head/tail} of the new list. + + Since After is strictly equivalent to Before Next + we are not in serious need of the Before/After variants. + That leaves only four. + + If you are processing a list left to right and dumping + the bits that you have processed into another list as + you go, the Tail/Tail variant gives the most natural result. + If you are processing in reverse order, Head/Head is best. + + By using NULL positions and empty lists judiciously either + of the other two can be built up in two operations. + + The definition of NULL (see Next/Prev etc) means that + degenerate cases include + "move all elements to new list" + "Split a list into two lists" + "Concatenate two lists" + (and quite a few no-ops) + + !!WARNING!! The type checking won't buy you much if you get list + positions muddled up - e.g. use a WXLIST_POSITION that's in a different + list and see what a mess you get! + */ + + /* Split *this after position p in *this + Retain as *this the tail portion of the original *this + Add the head portion to the tail end of *pList + Return TRUE if it all worked, FALSE if it didn't. + + e.g. + foo->MoveToTail(foo->GetHeadPosition(), bar); + moves one element from the head of foo to the tail of bar + foo->MoveToTail(NULL, bar); + is a no-op, returns NULL + foo->MoveToTail(foo->GetTailPosition, bar); + concatenates foo onto the end of bar and empties foo. + + A better, except excessively long name might be + MoveElementsFromHeadThroughPositionToOtherTail + */ + BOOL MoveToTail(WXLIST_POSITION pos, CBaseList *pList); + + + /* Mirror image: + Split *this before position p in *this. + Retain in *this the head portion of the original *this + Add the tail portion to the start (i.e. head) of *pList + + e.g. + foo->MoveToHead(foo->GetTailPosition(), bar); + moves one element from the tail of foo to the head of bar + foo->MoveToHead(NULL, bar); + is a no-op, returns NULL + foo->MoveToHead(foo->GetHeadPosition, bar); + concatenates foo onto the start of bar and empties foo. + */ + BOOL MoveToHead(WXLIST_POSITION pos, CBaseList *pList); + + + /* Reverse the order of the [pointers to] objects in *this + */ + void Reverse(); + + + /* set cursor to the position of each element of list in turn */ + #define TRAVERSELIST(list, cursor) \ + for ( cursor = (list).GetHeadPosition() \ + ; cursor!=NULL \ + ; cursor = (list).Next(cursor) \ + ) + + + /* set cursor to the position of each element of list in turn + in reverse order + */ + #define REVERSETRAVERSELIST(list, cursor) \ + for ( cursor = (list).GetTailPosition() \ + ; cursor!=NULL \ + ; cursor = (list).Prev(cursor) \ + ) + +}; // end of class declaration + +template class CGenericList : public CBaseList +{ +public: + CGenericList(TCHAR *pName, + INT iItems, + BOOL bLock = TRUE, + BOOL bAlert = FALSE) : + CBaseList(pName, iItems) { + UNREFERENCED_PARAMETER(bAlert); + UNREFERENCED_PARAMETER(bLock); + }; + CGenericList(TCHAR *pName) : + CBaseList(pName) { + }; + + WXLIST_POSITION GetHeadPosition() const { return (WXLIST_POSITION)m_pFirst; } + WXLIST_POSITION GetTailPosition() const { return (WXLIST_POSITION)m_pLast; } + int GetCount() const { return m_Count; } + + OBJECT *GetNext(WXLIST_POSITION& rp) const { return (OBJECT *) GetNextI(rp); } + + OBJECT *Get(WXLIST_POSITION p) const { return (OBJECT *) GetI(p); } + OBJECT *GetHead() const { return Get(GetHeadPosition()); } + + OBJECT *RemoveHead() { return (OBJECT *) RemoveHeadI(); } + + OBJECT *RemoveTail() { return (OBJECT *) RemoveTailI(); } + + OBJECT *Remove(WXLIST_POSITION p) { return (OBJECT *) RemoveI(p); } + WXLIST_POSITION AddBefore(WXLIST_POSITION p, OBJECT * pObj) { return AddBeforeI(p, pObj); } + WXLIST_POSITION AddAfter(WXLIST_POSITION p, OBJECT * pObj) { return AddAfterI(p, pObj); } + WXLIST_POSITION AddHead(OBJECT * pObj) { return AddHeadI(pObj); } + WXLIST_POSITION AddTail(OBJECT * pObj) { return AddTailI(pObj); } + BOOL AddTail(CGenericList *pList) + { return CBaseList::AddTail((CBaseList *) pList); } + BOOL AddHead(CGenericList *pList) + { return CBaseList::AddHead((CBaseList *) pList); } + BOOL AddAfter(WXLIST_POSITION p, CGenericList *pList) + { return CBaseList::AddAfter(p, (CBaseList *) pList); }; + BOOL AddBefore(WXLIST_POSITION p, CGenericList *pList) + { return CBaseList::AddBefore(p, (CBaseList *) pList); }; + WXLIST_POSITION Find( OBJECT * pObj) const { return FindI(pObj); } +}; // end of class declaration + + + +/* These define the standard list types */ + +typedef CGenericList CBaseObjectList; +typedef CGenericList CBaseInterfaceList; + +#endif /* __WXLIST__ */ + diff --git a/plugins/GSdx/baseclasses/wxutil.cpp b/plugins/GSdx/baseclasses/wxutil.cpp index 8947f6dcec..ae08ef67ff 100644 --- a/plugins/GSdx/baseclasses/wxutil.cpp +++ b/plugins/GSdx/baseclasses/wxutil.cpp @@ -1,1243 +1,1243 @@ -//------------------------------------------------------------------------------ -// File: WXUtil.cpp -// -// Desc: DirectShow base classes - implements helper classes for building -// multimedia filters. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" - -// -// Declare function from largeint.h we need so that PPC can build -// - -// -// Enlarged integer divide - 64-bits / 32-bits > 32-bits -// - -#ifndef _X86_ - -#define LLtoU64(x) (*(unsigned __int64*)(void*)(&(x))) - -__inline -ULONG -WINAPI -EnlargedUnsignedDivide ( - IN ULARGE_INTEGER Dividend, - IN ULONG Divisor, - IN PULONG Remainder - ) -{ - // return remainder if necessary - if (Remainder != NULL) - *Remainder = (ULONG)(LLtoU64(Dividend) % Divisor); - return (ULONG)(LLtoU64(Dividend) / Divisor); -} - -#else -__inline -ULONG -WINAPI -EnlargedUnsignedDivide ( - IN ULARGE_INTEGER Dividend, - IN ULONG Divisor, - IN PULONG Remainder - ) -{ - ULONG ulResult; - _asm { - mov eax,Dividend.LowPart - mov edx,Dividend.HighPart - mov ecx,Remainder - div Divisor - or ecx,ecx - jz short label - mov [ecx],edx -label: - mov ulResult,eax - } - return ulResult; -} -#endif - -// --- CAMEvent ----------------------- -CAMEvent::CAMEvent(BOOL fManualReset) -{ - m_hEvent = CreateEvent(NULL, fManualReset, FALSE, NULL); -} - -CAMEvent::~CAMEvent() -{ - if (m_hEvent) { - EXECUTE_ASSERT(CloseHandle(m_hEvent)); - } -} - - -// --- CAMMsgEvent ----------------------- -// One routine. The rest is handled in CAMEvent - -BOOL CAMMsgEvent::WaitMsg(DWORD dwTimeout) -{ - // wait for the event to be signalled, or for the - // timeout (in MS) to expire. allow SENT messages - // to be processed while we wait - DWORD dwWait; - DWORD dwStartTime; - - // set the waiting period. - DWORD dwWaitTime = dwTimeout; - - // the timeout will eventually run down as we iterate - // processing messages. grab the start time so that - // we can calculate elapsed times. - if (dwWaitTime != INFINITE) { - dwStartTime = timeGetTime(); - } - - do { - dwWait = MsgWaitForMultipleObjects(1,&m_hEvent,FALSE, dwWaitTime, QS_SENDMESSAGE); - if (dwWait == WAIT_OBJECT_0 + 1) { - MSG Message; - PeekMessage(&Message,NULL,0,0,PM_NOREMOVE); - - // If we have an explicit length of time to wait calculate - // the next wake up point - which might be now. - // If dwTimeout is INFINITE, it stays INFINITE - if (dwWaitTime != INFINITE) { - - DWORD dwElapsed = timeGetTime()-dwStartTime; - - dwWaitTime = - (dwElapsed >= dwTimeout) - ? 0 // wake up with WAIT_TIMEOUT - : dwTimeout-dwElapsed; - } - } - } while (dwWait == WAIT_OBJECT_0 + 1); - - // return TRUE if we woke on the event handle, - // FALSE if we timed out. - return (dwWait == WAIT_OBJECT_0); -} - -// --- CAMThread ---------------------- - - -CAMThread::CAMThread() - : m_EventSend(TRUE) // must be manual-reset for CheckRequest() -{ - m_hThread = NULL; -} - -CAMThread::~CAMThread() { - Close(); -} - - -// when the thread starts, it calls this function. We unwrap the 'this' -//pointer and call ThreadProc. -DWORD WINAPI -CAMThread::InitialThreadProc(LPVOID pv) -{ - HRESULT hrCoInit = CAMThread::CoInitializeHelper(); - if(FAILED(hrCoInit)) { - DbgLog((LOG_ERROR, 1, TEXT("CoInitializeEx failed."))); - } - - CAMThread * pThread = (CAMThread *) pv; - - HRESULT hr = pThread->ThreadProc(); - - if(SUCCEEDED(hrCoInit)) { - CoUninitialize(); - } - - return hr; -} - -BOOL -CAMThread::Create() -{ - DWORD threadid; - - CAutoLock lock(&m_AccessLock); - - if (ThreadExists()) { - return FALSE; - } - - m_hThread = CreateThread( - NULL, - 0, - CAMThread::InitialThreadProc, - this, - 0, - &threadid); - - if (!m_hThread) { - return FALSE; - } - - return TRUE; -} - -DWORD -CAMThread::CallWorker(DWORD dwParam) -{ - // lock access to the worker thread for scope of this object - CAutoLock lock(&m_AccessLock); - - if (!ThreadExists()) { - return (DWORD) E_FAIL; - } - - // set the parameter - m_dwParam = dwParam; - - // signal the worker thread - m_EventSend.Set(); - - // wait for the completion to be signalled - m_EventComplete.Wait(); - - // done - this is the thread's return value - return m_dwReturnVal; -} - -// Wait for a request from the client -DWORD -CAMThread::GetRequest() -{ - m_EventSend.Wait(); - return m_dwParam; -} - -// is there a request? -BOOL -CAMThread::CheckRequest(DWORD * pParam) -{ - if (!m_EventSend.Check()) { - return FALSE; - } else { - if (pParam) { - *pParam = m_dwParam; - } - return TRUE; - } -} - -// reply to the request -void -CAMThread::Reply(DWORD dw) -{ - m_dwReturnVal = dw; - - // The request is now complete so CheckRequest should fail from - // now on - // - // This event should be reset BEFORE we signal the client or - // the client may Set it before we reset it and we'll then - // reset it (!) - - m_EventSend.Reset(); - - // Tell the client we're finished - - m_EventComplete.Set(); -} - -HRESULT CAMThread::CoInitializeHelper() -{ - // call CoInitializeEx and tell OLE not to create a window (this - // thread probably won't dispatch messages and will hang on - // broadcast msgs o/w). - // - // If CoInitEx is not available, threads that don't call CoCreate - // aren't affected. Threads that do will have to handle the - // failure. Perhaps we should fall back to CoInitialize and risk - // hanging? - // - - // older versions of ole32.dll don't have CoInitializeEx - - HRESULT hr = E_FAIL; - HINSTANCE hOle = GetModuleHandle(TEXT("ole32.dll")); - if(hOle) - { - typedef HRESULT (STDAPICALLTYPE *PCoInitializeEx)( - LPVOID pvReserved, DWORD dwCoInit); - PCoInitializeEx pCoInitializeEx = - (PCoInitializeEx)(GetProcAddress(hOle, "CoInitializeEx")); - if(pCoInitializeEx) - { - hr = (*pCoInitializeEx)(0, COINIT_DISABLE_OLE1DDE ); - } - } - else - { - // caller must load ole32.dll - DbgBreak("couldn't locate ole32.dll"); - } - - return hr; -} - - -// destructor for CMsgThread - cleans up any messages left in the -// queue when the thread exited -CMsgThread::~CMsgThread() -{ - if (m_hThread != NULL) { - WaitForSingleObject(m_hThread, INFINITE); - EXECUTE_ASSERT(CloseHandle(m_hThread)); - } - - WXLIST_POSITION pos = m_ThreadQueue.GetHeadPosition(); - while (pos) { - CMsg * pMsg = m_ThreadQueue.GetNext(pos); - delete pMsg; - } - m_ThreadQueue.RemoveAll(); - - if (m_hSem != NULL) { - EXECUTE_ASSERT(CloseHandle(m_hSem)); - } -} - -BOOL -CMsgThread::CreateThread( - ) -{ - m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); - if (m_hSem == NULL) { - return FALSE; - } - - m_hThread = ::CreateThread(NULL, 0, DefaultThreadProc, - (LPVOID)this, 0, &m_ThreadId); - return m_hThread != NULL; -} - - -// This is the threads message pump. Here we get and dispatch messages to -// clients thread proc until the client refuses to process a message. -// The client returns a non-zero value to stop the message pump, this -// value becomes the threads exit code. - -DWORD WINAPI -CMsgThread::DefaultThreadProc( - LPVOID lpParam - ) -{ - CMsgThread *lpThis = (CMsgThread *)lpParam; - CMsg msg; - LRESULT lResult; - - // !!! - CoInitialize(NULL); - - // allow a derived class to handle thread startup - lpThis->OnThreadInit(); - - do { - lpThis->GetThreadMsg(&msg); - lResult = lpThis->ThreadMessageProc(msg.uMsg,msg.dwFlags, - msg.lpParam, msg.pEvent); - } while (lResult == 0L); - - // !!! - CoUninitialize(); - - return (DWORD)lResult; -} - - -// Block until the next message is placed on the list m_ThreadQueue. -// copies the message to the message pointed to by *pmsg -void -CMsgThread::GetThreadMsg(CMsg *msg) -{ - CMsg * pmsg = NULL; - - // keep trying until a message appears - while (TRUE) { - { - CAutoLock lck(&m_Lock); - pmsg = m_ThreadQueue.RemoveHead(); - if (pmsg == NULL) { - m_lWaiting++; - } else { - break; - } - } - // the semaphore will be signalled when it is non-empty - WaitForSingleObject(m_hSem, INFINITE); - } - // copy fields to caller's CMsg - *msg = *pmsg; - - // this CMsg was allocated by the 'new' in PutThreadMsg - delete pmsg; - -} - - -// NOTE: as we need to use the same binaries on Win95 as on NT this code should -// be compiled WITHOUT unicode being defined. Otherwise we will not pick up -// these internal routines and the binary will not run on Win95. - -#ifndef UNICODE -// Windows 95 doesn't implement this, so we provide an implementation. -// LPWSTR -// WINAPI -// lstrcpyWInternal( -// LPWSTR lpString1, -// LPCWSTR lpString2 -// ) -// { -// LPWSTR lpReturn = lpString1; -// while (*lpString1++ = *lpString2++); -// -// return lpReturn; -// } - -// Windows 95 doesn't implement this, so we provide an implementation. -LPWSTR -WINAPI -lstrcpynWInternal( - LPWSTR lpString1, - LPCWSTR lpString2, - int iMaxLength - ) -{ - ASSERT(iMaxLength); - LPWSTR lpReturn = lpString1; - if (iMaxLength) { - while (--iMaxLength && (*lpString1++ = *lpString2++)); - - // If we ran out of room (which will be the case if - // iMaxLength is now 0) we still need to terminate the - // string. - if (!iMaxLength) *lpString1 = L'\0'; - } - return lpReturn; -} - -int -WINAPI -lstrcmpWInternal( - LPCWSTR lpString1, - LPCWSTR lpString2 - ) -{ - do { - WCHAR c1 = *lpString1; - WCHAR c2 = *lpString2; - if (c1 != c2) - return (int) c1 - (int) c2; - } while (*lpString1++ && *lpString2++); - return 0; -} - - -int -WINAPI -lstrcmpiWInternal( - LPCWSTR lpString1, - LPCWSTR lpString2 - ) -{ - do { - WCHAR c1 = *lpString1; - WCHAR c2 = *lpString2; - if (c1 >= L'A' && c1 <= L'Z') - c1 -= (WCHAR) (L'A' - L'a'); - if (c2 >= L'A' && c2 <= L'Z') - c2 -= (WCHAR) (L'A' - L'a'); - - if (c1 != c2) - return (int) c1 - (int) c2; - } while (*lpString1++ && *lpString2++); - - return 0; -} - - -int -WINAPI -lstrlenWInternal( - LPCWSTR lpString - ) -{ - int i = -1; - while (*(lpString+(++i))) - ; - return i; -} - - -// int WINAPIV wsprintfWInternal(LPWSTR wszOut, LPCWSTR pszFmt, ...) -// { -// char fmt[256]; // !!! -// char ach[256]; // !!! -// int i; -// -// va_list va; -// va_start(va, pszFmt); -// WideCharToMultiByte(GetACP(), 0, pszFmt, -1, fmt, 256, NULL, NULL); -// (void)StringCchVPrintf(ach, NUMELMS(ach), fmt, va); -// i = lstrlenA(ach); -// va_end(va); -// -// MultiByteToWideChar(CP_ACP, 0, ach, -1, wszOut, i+1); -// -// return i; -// } -#else - -// need to provide the implementations in unicode for non-unicode -// builds linking with the unicode strmbase.lib -//LPWSTR WINAPI lstrcpyWInternal( -// LPWSTR lpString1, -// LPCWSTR lpString2 -// ) -//{ -// return lstrcpyW(lpString1, lpString2); -//} - -LPWSTR WINAPI lstrcpynWInternal( - LPWSTR lpString1, - LPCWSTR lpString2, - int iMaxLength - ) -{ - return lstrcpynW(lpString1, lpString2, iMaxLength); -} - -int WINAPI lstrcmpWInternal( - LPCWSTR lpString1, - LPCWSTR lpString2 - ) -{ - return lstrcmpW(lpString1, lpString2); -} - - -int WINAPI lstrcmpiWInternal( - LPCWSTR lpString1, - LPCWSTR lpString2 - ) -{ - return lstrcmpiW(lpString1, lpString2); -} - - -int WINAPI lstrlenWInternal( - LPCWSTR lpString - ) -{ - return lstrlenW(lpString); -} - - -//int WINAPIV wsprintfWInternal( -// LPWSTR wszOut, LPCWSTR pszFmt, ...) -//{ -// va_list va; -// va_start(va, pszFmt); -// int i = wvsprintfW(wszOut, pszFmt, va); -// va_end(va); -// return i; -//} -#endif - - -// Helper function - convert int to WSTR -void WINAPI IntToWstr(int i, LPWSTR wstr, size_t len) -{ -#ifdef UNICODE - (void)StringCchPrintf(wstr, len, L"%d", i); -#else - TCHAR temp[32]; - (void)StringCchPrintf(temp, NUMELMS(temp), "%d", i); - MultiByteToWideChar(CP_ACP, 0, temp, -1, wstr, int(len) ); -#endif -} // IntToWstr - - -#if 0 -void * memchrInternal(const void *pv, int c, size_t sz) -{ - BYTE *pb = (BYTE *) pv; - while (sz--) { - if (*pb == c) - return (void *) pb; - pb++; - } - return NULL; -} -#endif - - -#define MEMORY_ALIGNMENT 4 -#define MEMORY_ALIGNMENT_LOG2 2 -#define MEMORY_ALIGNMENT_MASK MEMORY_ALIGNMENT - 1 - -void * __stdcall memmoveInternal(void * dst, const void * src, size_t count) -{ - void * ret = dst; - -#ifdef _X86_ - if (dst <= src || (char *)dst >= ((char *)src + count)) { - - /* - * Non-Overlapping Buffers - * copy from lower addresses to higher addresses - */ - _asm { - mov esi,src - mov edi,dst - mov ecx,count - cld - mov edx,ecx - and edx,MEMORY_ALIGNMENT_MASK - shr ecx,MEMORY_ALIGNMENT_LOG2 - rep movsd - or ecx,edx - jz memmove_done - rep movsb -memmove_done: - } - } - else { - - /* - * Overlapping Buffers - * copy from higher addresses to lower addresses - */ - _asm { - mov esi,src - mov edi,dst - mov ecx,count - std - add esi,ecx - add edi,ecx - dec esi - dec edi - rep movsb - cld - } - } -#else - MoveMemory(dst, src, count); -#endif - - return ret; -} - -/* Arithmetic functions to help with time format conversions -*/ - -#ifdef _M_ALPHA -// work around bug in version 12.00.8385 of the alpha compiler where -// UInt32x32To64 sign-extends its arguments (?) -#undef UInt32x32To64 -#define UInt32x32To64(a, b) (((ULONGLONG)((ULONG)(a)) & 0xffffffff) * ((ULONGLONG)((ULONG)(b)) & 0xffffffff)) -#endif - -/* Compute (a * b + d) / c */ -LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG d) -{ - /* Compute the absolute values to avoid signed arithmetic problems */ - ULARGE_INTEGER ua, ub; - DWORDLONG uc; - - ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a); - ub.QuadPart = (DWORDLONG)(b >= 0 ? b : -b); - uc = (DWORDLONG)(c >= 0 ? c : -c); - BOOL bSign = (a < 0) ^ (b < 0); - - /* Do long multiplication */ - ULARGE_INTEGER p[2]; - p[0].QuadPart = UInt32x32To64(ua.LowPart, ub.LowPart); - - /* This next computation cannot overflow into p[1].HighPart because - the max number we can compute here is: - - (2 ** 32 - 1) * (2 ** 32 - 1) + // ua.LowPart * ub.LowPart - (2 ** 32) * (2 ** 31) * (2 ** 32 - 1) * 2 // x.LowPart * y.HighPart * 2 - - == 2 ** 96 - 2 ** 64 + (2 ** 64 - 2 ** 33 + 1) - == 2 ** 96 - 2 ** 33 + 1 - < 2 ** 96 - */ - - ULARGE_INTEGER x; - x.QuadPart = UInt32x32To64(ua.LowPart, ub.HighPart) + - UInt32x32To64(ua.HighPart, ub.LowPart) + - p[0].HighPart; - p[0].HighPart = x.LowPart; - p[1].QuadPart = UInt32x32To64(ua.HighPart, ub.HighPart) + x.HighPart; - - if (d != 0) { - ULARGE_INTEGER ud[2]; - if (bSign) { - ud[0].QuadPart = (DWORDLONG)(-d); - if (d > 0) { - /* -d < 0 */ - ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1; - } else { - ud[1].QuadPart = (DWORDLONG)0; - } - } else { - ud[0].QuadPart = (DWORDLONG)d; - if (d < 0) { - ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1; - } else { - ud[1].QuadPart = (DWORDLONG)0; - } - } - /* Now do extended addition */ - ULARGE_INTEGER uliTotal; - - /* Add ls DWORDs */ - uliTotal.QuadPart = (DWORDLONG)ud[0].LowPart + p[0].LowPart; - p[0].LowPart = uliTotal.LowPart; - - /* Propagate carry */ - uliTotal.LowPart = uliTotal.HighPart; - uliTotal.HighPart = 0; - - /* Add 2nd most ls DWORDs */ - uliTotal.QuadPart += (DWORDLONG)ud[0].HighPart + p[0].HighPart; - p[0].HighPart = uliTotal.LowPart; - - /* Propagate carry */ - uliTotal.LowPart = uliTotal.HighPart; - uliTotal.HighPart = 0; - - /* Add MS DWORDLONGs - no carry expected */ - p[1].QuadPart += ud[1].QuadPart + uliTotal.QuadPart; - - /* Now see if we got a sign change from the addition */ - if ((LONG)p[1].HighPart < 0) { - bSign = !bSign; - - /* Negate the current value (ugh!) */ - p[0].QuadPart = ~p[0].QuadPart; - p[1].QuadPart = ~p[1].QuadPart; - p[0].QuadPart += 1; - p[1].QuadPart += (p[0].QuadPart == 0); - } - } - - /* Now for the division */ - if (c < 0) { - bSign = !bSign; - } - - - /* This will catch c == 0 and overflow */ - if (uc <= p[1].QuadPart) { - return bSign ? (LONGLONG)0x8000000000000000 : - (LONGLONG)0x7FFFFFFFFFFFFFFF; - } - - DWORDLONG ullResult; - - /* Do the division */ - /* If the dividend is a DWORD_LONG use the compiler */ - if (p[1].QuadPart == 0) { - ullResult = p[0].QuadPart / uc; - return bSign ? -(LONGLONG)ullResult : (LONGLONG)ullResult; - } - - /* If the divisor is a DWORD then its simpler */ - ULARGE_INTEGER ulic; - ulic.QuadPart = uc; - if (ulic.HighPart == 0) { - ULARGE_INTEGER uliDividend; - ULARGE_INTEGER uliResult; - DWORD dwDivisor = (DWORD)uc; - // ASSERT(p[1].HighPart == 0 && p[1].LowPart < dwDivisor); - uliDividend.HighPart = p[1].LowPart; - uliDividend.LowPart = p[0].HighPart; -#ifndef USE_LARGEINT - uliResult.HighPart = (DWORD)(uliDividend.QuadPart / dwDivisor); - p[0].HighPart = (DWORD)(uliDividend.QuadPart % dwDivisor); - uliResult.LowPart = 0; - uliResult.QuadPart = p[0].QuadPart / dwDivisor + uliResult.QuadPart; -#else - /* NOTE - this routine will take exceptions if - the result does not fit in a DWORD - */ - if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) { - uliResult.HighPart = EnlargedUnsignedDivide( - uliDividend, - dwDivisor, - &p[0].HighPart); - } else { - uliResult.HighPart = 0; - } - uliResult.LowPart = EnlargedUnsignedDivide( - p[0], - dwDivisor, - NULL); -#endif - return bSign ? -(LONGLONG)uliResult.QuadPart : - (LONGLONG)uliResult.QuadPart; - } - - - ullResult = 0; - - /* OK - do long division */ - for (int i = 0; i < 64; i++) { - ullResult <<= 1; - - /* Shift 128 bit p left 1 */ - p[1].QuadPart <<= 1; - if ((p[0].HighPart & 0x80000000) != 0) { - p[1].LowPart++; - } - p[0].QuadPart <<= 1; - - /* Compare */ - if (uc <= p[1].QuadPart) { - p[1].QuadPart -= uc; - ullResult += 1; - } - } - - return bSign ? - (LONGLONG)ullResult : (LONGLONG)ullResult; -} - -LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG d) -{ - ULARGE_INTEGER ua; - DWORD ub; - DWORD uc; - - /* Compute the absolute values to avoid signed arithmetic problems */ - ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a); - ub = (DWORD)(b >= 0 ? b : -b); - uc = (DWORD)(c >= 0 ? c : -c); - BOOL bSign = (a < 0) ^ (b < 0); - - /* Do long multiplication */ - ULARGE_INTEGER p0; - DWORD p1; - p0.QuadPart = UInt32x32To64(ua.LowPart, ub); - - if (ua.HighPart != 0) { - ULARGE_INTEGER x; - x.QuadPart = UInt32x32To64(ua.HighPart, ub) + p0.HighPart; - p0.HighPart = x.LowPart; - p1 = x.HighPart; - } else { - p1 = 0; - } - - if (d != 0) { - ULARGE_INTEGER ud0; - DWORD ud1; - - if (bSign) { - // - // Cast d to LONGLONG first otherwise -0x80000000 sign extends - // incorrectly - // - ud0.QuadPart = (DWORDLONG)(-(LONGLONG)d); - if (d > 0) { - /* -d < 0 */ - ud1 = (DWORD)-1; - } else { - ud1 = (DWORD)0; - } - } else { - ud0.QuadPart = (DWORDLONG)d; - if (d < 0) { - ud1 = (DWORD)-1; - } else { - ud1 = (DWORD)0; - } - } - /* Now do extended addition */ - ULARGE_INTEGER uliTotal; - - /* Add ls DWORDs */ - uliTotal.QuadPart = (DWORDLONG)ud0.LowPart + p0.LowPart; - p0.LowPart = uliTotal.LowPart; - - /* Propagate carry */ - uliTotal.LowPart = uliTotal.HighPart; - uliTotal.HighPart = 0; - - /* Add 2nd most ls DWORDs */ - uliTotal.QuadPart += (DWORDLONG)ud0.HighPart + p0.HighPart; - p0.HighPart = uliTotal.LowPart; - - /* Add MS DWORDLONGs - no carry expected */ - p1 += ud1 + uliTotal.HighPart; - - /* Now see if we got a sign change from the addition */ - if ((LONG)p1 < 0) { - bSign = !bSign; - - /* Negate the current value (ugh!) */ - p0.QuadPart = ~p0.QuadPart; - p1 = ~p1; - p0.QuadPart += 1; - p1 += (p0.QuadPart == 0); - } - } - - /* Now for the division */ - if (c < 0) { - bSign = !bSign; - } - - - /* This will catch c == 0 and overflow */ - if (uc <= p1) { - return bSign ? (LONGLONG)0x8000000000000000 : - (LONGLONG)0x7FFFFFFFFFFFFFFF; - } - - /* Do the division */ - - /* If the divisor is a DWORD then its simpler */ - ULARGE_INTEGER uliDividend; - ULARGE_INTEGER uliResult; - DWORD dwDivisor = uc; - uliDividend.HighPart = p1; - uliDividend.LowPart = p0.HighPart; - /* NOTE - this routine will take exceptions if - the result does not fit in a DWORD - */ - if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) { - uliResult.HighPart = EnlargedUnsignedDivide( - uliDividend, - dwDivisor, - &p0.HighPart); - } else { - uliResult.HighPart = 0; - } - uliResult.LowPart = EnlargedUnsignedDivide( - p0, - dwDivisor, - NULL); - return bSign ? -(LONGLONG)uliResult.QuadPart : - (LONGLONG)uliResult.QuadPart; -} - -#ifdef DEBUG -/******************************Public*Routine******************************\ -* Debug CCritSec helpers -* -* We provide debug versions of the Constructor, destructor, Lock and Unlock -* routines. The debug code tracks who owns each critical section by -* maintaining a depth count. -* -* History: -* -\**************************************************************************/ - -CCritSec::CCritSec(DWORD id) -{ - InitializeCriticalSection(&m_CritSec); - m_id = id; - m_currentOwner = m_lockCount = 0; - m_fTrace = FALSE; -} - -CCritSec::~CCritSec() -{ - DeleteCriticalSection(&m_CritSec); -} - -void CCritSec::Lock() -{ - UINT tracelevel=3; - DWORD us = GetCurrentThreadId(); - DWORD currentOwner = m_currentOwner; - if (currentOwner && (currentOwner != us)) { - // already owned, but not by us - if (m_fTrace) { - DbgLog((LOG_LOCKING, 2, TEXT("Thread %d about to wait for lock %x owned by %d"), - GetCurrentThreadId(), &m_CritSec, currentOwner)); - tracelevel=2; - // if we saw the message about waiting for the critical - // section we ensure we see the message when we get the - // critical section - } - } - - EnterCriticalSection(&m_CritSec); - - if (0 == m_lockCount++) { - // we now own it for the first time. Set owner information - m_currentOwner = us; - - if (m_fTrace) { - DbgLog((LOG_LOCKING, tracelevel, TEXT("Thread %d now owns lock %x"), m_currentOwner, &m_CritSec)); - } - } -} - -void CCritSec::Unlock() { - if (0 == --m_lockCount) { - // about to be unowned - if (m_fTrace) { - DbgLog((LOG_LOCKING, 3, TEXT("Thread %d releasing lock %x"), m_currentOwner, &m_CritSec)); - } - - m_currentOwner = 0; - } - LeaveCriticalSection(&m_CritSec); -} - -void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace) -{ - pcCrit->m_fTrace = fTrace; -} - -BOOL WINAPI CritCheckIn(CCritSec * pcCrit) -{ - return (GetCurrentThreadId() == pcCrit->m_currentOwner); -} - -BOOL WINAPI CritCheckIn(const CCritSec * pcCrit) -{ - return (GetCurrentThreadId() == pcCrit->m_currentOwner); -} - -BOOL WINAPI CritCheckOut(CCritSec * pcCrit) -{ - return (GetCurrentThreadId() != pcCrit->m_currentOwner); -} - -BOOL WINAPI CritCheckOut(const CCritSec * pcCrit) -{ - return (GetCurrentThreadId() != pcCrit->m_currentOwner); -} -#endif - - -STDAPI WriteBSTR(BSTR *pstrDest, LPCWSTR szSrc) -{ - *pstrDest = SysAllocString( szSrc ); - if( !(*pstrDest) ) return E_OUTOFMEMORY; - return NOERROR; -} - - -STDAPI FreeBSTR(BSTR* pstr) -{ - if( *pstr == NULL ) return S_FALSE; - SysFreeString( *pstr ); - return NOERROR; -} - - -// Return a wide string - allocating memory for it -// Returns: -// S_OK - no error -// E_POINTER - ppszReturn == NULL -// E_OUTOFMEMORY - can't allocate memory for returned string -STDAPI AMGetWideString(LPCWSTR psz, LPWSTR *ppszReturn) -{ - CheckPointer(ppszReturn, E_POINTER); - ValidateReadWritePtr(ppszReturn, sizeof(LPWSTR)); - DWORD nameLen = sizeof(WCHAR) * (lstrlenW(psz)+1); - *ppszReturn = (LPWSTR)CoTaskMemAlloc(nameLen); - if (*ppszReturn == NULL) { - return E_OUTOFMEMORY; - } - CopyMemory(*ppszReturn, psz, nameLen); - return NOERROR; -} - -// Waits for the HANDLE hObject. While waiting messages sent -// to windows on our thread by SendMessage will be processed. -// Using this function to do waits and mutual exclusion -// avoids some deadlocks in objects with windows. -// Return codes are the same as for WaitForSingleObject -DWORD WINAPI WaitDispatchingMessages( - HANDLE hObject, - DWORD dwWait, - HWND hwnd, - UINT uMsg, - HANDLE hEvent) -{ - BOOL bPeeked = FALSE; - DWORD dwResult; - DWORD dwStart = 0; - DWORD dwThreadPriority = 0; - - static UINT uMsgId = 0; - - HANDLE hObjects[2] = { hObject, hEvent }; - if (dwWait != INFINITE && dwWait != 0) { - dwStart = GetTickCount(); - } - for (; ; ) { - DWORD nCount = NULL != hEvent ? 2 : 1; - - // Minimize the chance of actually dispatching any messages - // by seeing if we can lock immediately. - dwResult = WaitForMultipleObjects(nCount, hObjects, FALSE, 0); - if (dwResult < WAIT_OBJECT_0 + nCount) { - break; - } - - DWORD dwTimeOut = dwWait; - if (dwTimeOut > 10) { - dwTimeOut = 10; - } - dwResult = MsgWaitForMultipleObjects( - nCount, - hObjects, - FALSE, - dwTimeOut, - hwnd == NULL ? QS_SENDMESSAGE : - QS_SENDMESSAGE + QS_POSTMESSAGE); - if (dwResult == WAIT_OBJECT_0 + nCount || - dwResult == WAIT_TIMEOUT && dwTimeOut != dwWait) { - MSG msg; - if (hwnd != NULL) { - while (PeekMessage(&msg, hwnd, uMsg, uMsg, PM_REMOVE)) { - DispatchMessage(&msg); - } - } - // Do this anyway - the previous peek doesn't flush out the - // messages - PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); - - if (dwWait != INFINITE && dwWait != 0) { - DWORD dwNow = GetTickCount(); - - // Working with differences handles wrap-around - DWORD dwDiff = dwNow - dwStart; - if (dwDiff > dwWait) { - dwWait = 0; - } else { - dwWait -= dwDiff; - } - dwStart = dwNow; - } - if (!bPeeked) { - // Raise our priority to prevent our message queue - // building up - dwThreadPriority = GetThreadPriority(GetCurrentThread()); - if (dwThreadPriority < THREAD_PRIORITY_HIGHEST) { - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); - } - bPeeked = TRUE; - } - } else { - break; - } - } - if (bPeeked) { - SetThreadPriority(GetCurrentThread(), dwThreadPriority); - if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) { - if (uMsgId == 0) { - uMsgId = RegisterWindowMessage(TEXT("AMUnblock")); - } - if (uMsgId != 0) { - MSG msg; - // Remove old ones - while (PeekMessage(&msg, (HWND)-1, uMsgId, uMsgId, PM_REMOVE)) { - } - } - PostThreadMessage(GetCurrentThreadId(), uMsgId, 0, 0); - } - } - return dwResult; -} - -HRESULT AmGetLastErrorToHResult() -{ - DWORD dwLastError = GetLastError(); - if(dwLastError != 0) - { - return HRESULT_FROM_WIN32(dwLastError); - } - else - { - return E_FAIL; - } -} - -IUnknown* QzAtlComPtrAssign(IUnknown** pp, IUnknown* lp) -{ - if (lp != NULL) - lp->AddRef(); - if (*pp) - (*pp)->Release(); - *pp = lp; - return lp; -} - -/****************************************************************************** - -CompatibleTimeSetEvent - - CompatibleTimeSetEvent() sets the TIME_KILL_SYNCHRONOUS flag before calling -timeSetEvent() if the current operating system supports it. TIME_KILL_SYNCHRONOUS -is supported on Windows XP and later operating systems. - -Parameters: -- The same parameters as timeSetEvent(). See timeSetEvent()'s documentation in -the Platform SDK for more information. - -Return Value: -- The same return value as timeSetEvent(). See timeSetEvent()'s documentation in -the Platform SDK for more information. - -******************************************************************************/ -MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent ) -{ - #if WINVER >= 0x0501 - { - static bool fCheckedVersion = false; - static bool fTimeKillSynchronousFlagAvailable = false; - - if( !fCheckedVersion ) { - fTimeKillSynchronousFlagAvailable = TimeKillSynchronousFlagAvailable(); - fCheckedVersion = true; - } - - if( fTimeKillSynchronousFlagAvailable ) { - fuEvent = fuEvent | TIME_KILL_SYNCHRONOUS; - } - } - #endif // WINVER >= 0x0501 - - return timeSetEvent( uDelay, uResolution, lpTimeProc, dwUser, fuEvent ); -} - -bool TimeKillSynchronousFlagAvailable( void ) -{ - OSVERSIONINFO osverinfo; - - osverinfo.dwOSVersionInfoSize = sizeof(osverinfo); - - if( GetVersionEx( &osverinfo ) ) { - - // Windows XP's major version is 5 and its' minor version is 1. - // timeSetEvent() started supporting the TIME_KILL_SYNCHRONOUS flag - // in Windows XP. - if( (osverinfo.dwMajorVersion > 5) || - ( (osverinfo.dwMajorVersion == 5) && (osverinfo.dwMinorVersion >= 1) ) ) { - return true; - } - } - - return false; -} +//------------------------------------------------------------------------------ +// File: WXUtil.cpp +// +// Desc: DirectShow base classes - implements helper classes for building +// multimedia filters. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" + +// +// Declare function from largeint.h we need so that PPC can build +// + +// +// Enlarged integer divide - 64-bits / 32-bits > 32-bits +// + +#ifndef _X86_ + +#define LLtoU64(x) (*(unsigned __int64*)(void*)(&(x))) + +__inline +ULONG +WINAPI +EnlargedUnsignedDivide ( + IN ULARGE_INTEGER Dividend, + IN ULONG Divisor, + IN PULONG Remainder + ) +{ + // return remainder if necessary + if (Remainder != NULL) + *Remainder = (ULONG)(LLtoU64(Dividend) % Divisor); + return (ULONG)(LLtoU64(Dividend) / Divisor); +} + +#else +__inline +ULONG +WINAPI +EnlargedUnsignedDivide ( + IN ULARGE_INTEGER Dividend, + IN ULONG Divisor, + IN PULONG Remainder + ) +{ + ULONG ulResult; + _asm { + mov eax,Dividend.LowPart + mov edx,Dividend.HighPart + mov ecx,Remainder + div Divisor + or ecx,ecx + jz short label + mov [ecx],edx +label: + mov ulResult,eax + } + return ulResult; +} +#endif + +// --- CAMEvent ----------------------- +CAMEvent::CAMEvent(BOOL fManualReset) +{ + m_hEvent = CreateEvent(NULL, fManualReset, FALSE, NULL); +} + +CAMEvent::~CAMEvent() +{ + if (m_hEvent) { + EXECUTE_ASSERT(CloseHandle(m_hEvent)); + } +} + + +// --- CAMMsgEvent ----------------------- +// One routine. The rest is handled in CAMEvent + +BOOL CAMMsgEvent::WaitMsg(DWORD dwTimeout) +{ + // wait for the event to be signalled, or for the + // timeout (in MS) to expire. allow SENT messages + // to be processed while we wait + DWORD dwWait; + DWORD dwStartTime; + + // set the waiting period. + DWORD dwWaitTime = dwTimeout; + + // the timeout will eventually run down as we iterate + // processing messages. grab the start time so that + // we can calculate elapsed times. + if (dwWaitTime != INFINITE) { + dwStartTime = timeGetTime(); + } + + do { + dwWait = MsgWaitForMultipleObjects(1,&m_hEvent,FALSE, dwWaitTime, QS_SENDMESSAGE); + if (dwWait == WAIT_OBJECT_0 + 1) { + MSG Message; + PeekMessage(&Message,NULL,0,0,PM_NOREMOVE); + + // If we have an explicit length of time to wait calculate + // the next wake up point - which might be now. + // If dwTimeout is INFINITE, it stays INFINITE + if (dwWaitTime != INFINITE) { + + DWORD dwElapsed = timeGetTime()-dwStartTime; + + dwWaitTime = + (dwElapsed >= dwTimeout) + ? 0 // wake up with WAIT_TIMEOUT + : dwTimeout-dwElapsed; + } + } + } while (dwWait == WAIT_OBJECT_0 + 1); + + // return TRUE if we woke on the event handle, + // FALSE if we timed out. + return (dwWait == WAIT_OBJECT_0); +} + +// --- CAMThread ---------------------- + + +CAMThread::CAMThread() + : m_EventSend(TRUE) // must be manual-reset for CheckRequest() +{ + m_hThread = NULL; +} + +CAMThread::~CAMThread() { + Close(); +} + + +// when the thread starts, it calls this function. We unwrap the 'this' +//pointer and call ThreadProc. +DWORD WINAPI +CAMThread::InitialThreadProc(LPVOID pv) +{ + HRESULT hrCoInit = CAMThread::CoInitializeHelper(); + if(FAILED(hrCoInit)) { + DbgLog((LOG_ERROR, 1, TEXT("CoInitializeEx failed."))); + } + + CAMThread * pThread = (CAMThread *) pv; + + HRESULT hr = pThread->ThreadProc(); + + if(SUCCEEDED(hrCoInit)) { + CoUninitialize(); + } + + return hr; +} + +BOOL +CAMThread::Create() +{ + DWORD threadid; + + CAutoLock lock(&m_AccessLock); + + if (ThreadExists()) { + return FALSE; + } + + m_hThread = CreateThread( + NULL, + 0, + CAMThread::InitialThreadProc, + this, + 0, + &threadid); + + if (!m_hThread) { + return FALSE; + } + + return TRUE; +} + +DWORD +CAMThread::CallWorker(DWORD dwParam) +{ + // lock access to the worker thread for scope of this object + CAutoLock lock(&m_AccessLock); + + if (!ThreadExists()) { + return (DWORD) E_FAIL; + } + + // set the parameter + m_dwParam = dwParam; + + // signal the worker thread + m_EventSend.Set(); + + // wait for the completion to be signalled + m_EventComplete.Wait(); + + // done - this is the thread's return value + return m_dwReturnVal; +} + +// Wait for a request from the client +DWORD +CAMThread::GetRequest() +{ + m_EventSend.Wait(); + return m_dwParam; +} + +// is there a request? +BOOL +CAMThread::CheckRequest(DWORD * pParam) +{ + if (!m_EventSend.Check()) { + return FALSE; + } else { + if (pParam) { + *pParam = m_dwParam; + } + return TRUE; + } +} + +// reply to the request +void +CAMThread::Reply(DWORD dw) +{ + m_dwReturnVal = dw; + + // The request is now complete so CheckRequest should fail from + // now on + // + // This event should be reset BEFORE we signal the client or + // the client may Set it before we reset it and we'll then + // reset it (!) + + m_EventSend.Reset(); + + // Tell the client we're finished + + m_EventComplete.Set(); +} + +HRESULT CAMThread::CoInitializeHelper() +{ + // call CoInitializeEx and tell OLE not to create a window (this + // thread probably won't dispatch messages and will hang on + // broadcast msgs o/w). + // + // If CoInitEx is not available, threads that don't call CoCreate + // aren't affected. Threads that do will have to handle the + // failure. Perhaps we should fall back to CoInitialize and risk + // hanging? + // + + // older versions of ole32.dll don't have CoInitializeEx + + HRESULT hr = E_FAIL; + HINSTANCE hOle = GetModuleHandle(TEXT("ole32.dll")); + if(hOle) + { + typedef HRESULT (STDAPICALLTYPE *PCoInitializeEx)( + LPVOID pvReserved, DWORD dwCoInit); + PCoInitializeEx pCoInitializeEx = + (PCoInitializeEx)(GetProcAddress(hOle, "CoInitializeEx")); + if(pCoInitializeEx) + { + hr = (*pCoInitializeEx)(0, COINIT_DISABLE_OLE1DDE ); + } + } + else + { + // caller must load ole32.dll + DbgBreak("couldn't locate ole32.dll"); + } + + return hr; +} + + +// destructor for CMsgThread - cleans up any messages left in the +// queue when the thread exited +CMsgThread::~CMsgThread() +{ + if (m_hThread != NULL) { + WaitForSingleObject(m_hThread, INFINITE); + EXECUTE_ASSERT(CloseHandle(m_hThread)); + } + + WXLIST_POSITION pos = m_ThreadQueue.GetHeadPosition(); + while (pos) { + CMsg * pMsg = m_ThreadQueue.GetNext(pos); + delete pMsg; + } + m_ThreadQueue.RemoveAll(); + + if (m_hSem != NULL) { + EXECUTE_ASSERT(CloseHandle(m_hSem)); + } +} + +BOOL +CMsgThread::CreateThread( + ) +{ + m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); + if (m_hSem == NULL) { + return FALSE; + } + + m_hThread = ::CreateThread(NULL, 0, DefaultThreadProc, + (LPVOID)this, 0, &m_ThreadId); + return m_hThread != NULL; +} + + +// This is the threads message pump. Here we get and dispatch messages to +// clients thread proc until the client refuses to process a message. +// The client returns a non-zero value to stop the message pump, this +// value becomes the threads exit code. + +DWORD WINAPI +CMsgThread::DefaultThreadProc( + LPVOID lpParam + ) +{ + CMsgThread *lpThis = (CMsgThread *)lpParam; + CMsg msg; + LRESULT lResult; + + // !!! + CoInitialize(NULL); + + // allow a derived class to handle thread startup + lpThis->OnThreadInit(); + + do { + lpThis->GetThreadMsg(&msg); + lResult = lpThis->ThreadMessageProc(msg.uMsg,msg.dwFlags, + msg.lpParam, msg.pEvent); + } while (lResult == 0L); + + // !!! + CoUninitialize(); + + return (DWORD)lResult; +} + + +// Block until the next message is placed on the list m_ThreadQueue. +// copies the message to the message pointed to by *pmsg +void +CMsgThread::GetThreadMsg(CMsg *msg) +{ + CMsg * pmsg = NULL; + + // keep trying until a message appears + while (TRUE) { + { + CAutoLock lck(&m_Lock); + pmsg = m_ThreadQueue.RemoveHead(); + if (pmsg == NULL) { + m_lWaiting++; + } else { + break; + } + } + // the semaphore will be signalled when it is non-empty + WaitForSingleObject(m_hSem, INFINITE); + } + // copy fields to caller's CMsg + *msg = *pmsg; + + // this CMsg was allocated by the 'new' in PutThreadMsg + delete pmsg; + +} + + +// NOTE: as we need to use the same binaries on Win95 as on NT this code should +// be compiled WITHOUT unicode being defined. Otherwise we will not pick up +// these internal routines and the binary will not run on Win95. + +#ifndef UNICODE +// Windows 95 doesn't implement this, so we provide an implementation. +// LPWSTR +// WINAPI +// lstrcpyWInternal( +// LPWSTR lpString1, +// LPCWSTR lpString2 +// ) +// { +// LPWSTR lpReturn = lpString1; +// while (*lpString1++ = *lpString2++); +// +// return lpReturn; +// } + +// Windows 95 doesn't implement this, so we provide an implementation. +LPWSTR +WINAPI +lstrcpynWInternal( + LPWSTR lpString1, + LPCWSTR lpString2, + int iMaxLength + ) +{ + ASSERT(iMaxLength); + LPWSTR lpReturn = lpString1; + if (iMaxLength) { + while (--iMaxLength && (*lpString1++ = *lpString2++)); + + // If we ran out of room (which will be the case if + // iMaxLength is now 0) we still need to terminate the + // string. + if (!iMaxLength) *lpString1 = L'\0'; + } + return lpReturn; +} + +int +WINAPI +lstrcmpWInternal( + LPCWSTR lpString1, + LPCWSTR lpString2 + ) +{ + do { + WCHAR c1 = *lpString1; + WCHAR c2 = *lpString2; + if (c1 != c2) + return (int) c1 - (int) c2; + } while (*lpString1++ && *lpString2++); + return 0; +} + + +int +WINAPI +lstrcmpiWInternal( + LPCWSTR lpString1, + LPCWSTR lpString2 + ) +{ + do { + WCHAR c1 = *lpString1; + WCHAR c2 = *lpString2; + if (c1 >= L'A' && c1 <= L'Z') + c1 -= (WCHAR) (L'A' - L'a'); + if (c2 >= L'A' && c2 <= L'Z') + c2 -= (WCHAR) (L'A' - L'a'); + + if (c1 != c2) + return (int) c1 - (int) c2; + } while (*lpString1++ && *lpString2++); + + return 0; +} + + +int +WINAPI +lstrlenWInternal( + LPCWSTR lpString + ) +{ + int i = -1; + while (*(lpString+(++i))) + ; + return i; +} + + +// int WINAPIV wsprintfWInternal(LPWSTR wszOut, LPCWSTR pszFmt, ...) +// { +// char fmt[256]; // !!! +// char ach[256]; // !!! +// int i; +// +// va_list va; +// va_start(va, pszFmt); +// WideCharToMultiByte(GetACP(), 0, pszFmt, -1, fmt, 256, NULL, NULL); +// (void)StringCchVPrintf(ach, NUMELMS(ach), fmt, va); +// i = lstrlenA(ach); +// va_end(va); +// +// MultiByteToWideChar(CP_ACP, 0, ach, -1, wszOut, i+1); +// +// return i; +// } +#else + +// need to provide the implementations in unicode for non-unicode +// builds linking with the unicode strmbase.lib +//LPWSTR WINAPI lstrcpyWInternal( +// LPWSTR lpString1, +// LPCWSTR lpString2 +// ) +//{ +// return lstrcpyW(lpString1, lpString2); +//} + +LPWSTR WINAPI lstrcpynWInternal( + LPWSTR lpString1, + LPCWSTR lpString2, + int iMaxLength + ) +{ + return lstrcpynW(lpString1, lpString2, iMaxLength); +} + +int WINAPI lstrcmpWInternal( + LPCWSTR lpString1, + LPCWSTR lpString2 + ) +{ + return lstrcmpW(lpString1, lpString2); +} + + +int WINAPI lstrcmpiWInternal( + LPCWSTR lpString1, + LPCWSTR lpString2 + ) +{ + return lstrcmpiW(lpString1, lpString2); +} + + +int WINAPI lstrlenWInternal( + LPCWSTR lpString + ) +{ + return lstrlenW(lpString); +} + + +//int WINAPIV wsprintfWInternal( +// LPWSTR wszOut, LPCWSTR pszFmt, ...) +//{ +// va_list va; +// va_start(va, pszFmt); +// int i = wvsprintfW(wszOut, pszFmt, va); +// va_end(va); +// return i; +//} +#endif + + +// Helper function - convert int to WSTR +void WINAPI IntToWstr(int i, LPWSTR wstr, size_t len) +{ +#ifdef UNICODE + (void)StringCchPrintf(wstr, len, L"%d", i); +#else + TCHAR temp[32]; + (void)StringCchPrintf(temp, NUMELMS(temp), "%d", i); + MultiByteToWideChar(CP_ACP, 0, temp, -1, wstr, int(len) ); +#endif +} // IntToWstr + + +#if 0 +void * memchrInternal(const void *pv, int c, size_t sz) +{ + BYTE *pb = (BYTE *) pv; + while (sz--) { + if (*pb == c) + return (void *) pb; + pb++; + } + return NULL; +} +#endif + + +#define MEMORY_ALIGNMENT 4 +#define MEMORY_ALIGNMENT_LOG2 2 +#define MEMORY_ALIGNMENT_MASK MEMORY_ALIGNMENT - 1 + +void * __stdcall memmoveInternal(void * dst, const void * src, size_t count) +{ + void * ret = dst; + +#ifdef _X86_ + if (dst <= src || (char *)dst >= ((char *)src + count)) { + + /* + * Non-Overlapping Buffers + * copy from lower addresses to higher addresses + */ + _asm { + mov esi,src + mov edi,dst + mov ecx,count + cld + mov edx,ecx + and edx,MEMORY_ALIGNMENT_MASK + shr ecx,MEMORY_ALIGNMENT_LOG2 + rep movsd + or ecx,edx + jz memmove_done + rep movsb +memmove_done: + } + } + else { + + /* + * Overlapping Buffers + * copy from higher addresses to lower addresses + */ + _asm { + mov esi,src + mov edi,dst + mov ecx,count + std + add esi,ecx + add edi,ecx + dec esi + dec edi + rep movsb + cld + } + } +#else + MoveMemory(dst, src, count); +#endif + + return ret; +} + +/* Arithmetic functions to help with time format conversions +*/ + +#ifdef _M_ALPHA +// work around bug in version 12.00.8385 of the alpha compiler where +// UInt32x32To64 sign-extends its arguments (?) +#undef UInt32x32To64 +#define UInt32x32To64(a, b) (((ULONGLONG)((ULONG)(a)) & 0xffffffff) * ((ULONGLONG)((ULONG)(b)) & 0xffffffff)) +#endif + +/* Compute (a * b + d) / c */ +LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG d) +{ + /* Compute the absolute values to avoid signed arithmetic problems */ + ULARGE_INTEGER ua, ub; + DWORDLONG uc; + + ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a); + ub.QuadPart = (DWORDLONG)(b >= 0 ? b : -b); + uc = (DWORDLONG)(c >= 0 ? c : -c); + BOOL bSign = (a < 0) ^ (b < 0); + + /* Do long multiplication */ + ULARGE_INTEGER p[2]; + p[0].QuadPart = UInt32x32To64(ua.LowPart, ub.LowPart); + + /* This next computation cannot overflow into p[1].HighPart because + the max number we can compute here is: + + (2 ** 32 - 1) * (2 ** 32 - 1) + // ua.LowPart * ub.LowPart + (2 ** 32) * (2 ** 31) * (2 ** 32 - 1) * 2 // x.LowPart * y.HighPart * 2 + + == 2 ** 96 - 2 ** 64 + (2 ** 64 - 2 ** 33 + 1) + == 2 ** 96 - 2 ** 33 + 1 + < 2 ** 96 + */ + + ULARGE_INTEGER x; + x.QuadPart = UInt32x32To64(ua.LowPart, ub.HighPart) + + UInt32x32To64(ua.HighPart, ub.LowPart) + + p[0].HighPart; + p[0].HighPart = x.LowPart; + p[1].QuadPart = UInt32x32To64(ua.HighPart, ub.HighPart) + x.HighPart; + + if (d != 0) { + ULARGE_INTEGER ud[2]; + if (bSign) { + ud[0].QuadPart = (DWORDLONG)(-d); + if (d > 0) { + /* -d < 0 */ + ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1; + } else { + ud[1].QuadPart = (DWORDLONG)0; + } + } else { + ud[0].QuadPart = (DWORDLONG)d; + if (d < 0) { + ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1; + } else { + ud[1].QuadPart = (DWORDLONG)0; + } + } + /* Now do extended addition */ + ULARGE_INTEGER uliTotal; + + /* Add ls DWORDs */ + uliTotal.QuadPart = (DWORDLONG)ud[0].LowPart + p[0].LowPart; + p[0].LowPart = uliTotal.LowPart; + + /* Propagate carry */ + uliTotal.LowPart = uliTotal.HighPart; + uliTotal.HighPart = 0; + + /* Add 2nd most ls DWORDs */ + uliTotal.QuadPart += (DWORDLONG)ud[0].HighPart + p[0].HighPart; + p[0].HighPart = uliTotal.LowPart; + + /* Propagate carry */ + uliTotal.LowPart = uliTotal.HighPart; + uliTotal.HighPart = 0; + + /* Add MS DWORDLONGs - no carry expected */ + p[1].QuadPart += ud[1].QuadPart + uliTotal.QuadPart; + + /* Now see if we got a sign change from the addition */ + if ((LONG)p[1].HighPart < 0) { + bSign = !bSign; + + /* Negate the current value (ugh!) */ + p[0].QuadPart = ~p[0].QuadPart; + p[1].QuadPart = ~p[1].QuadPart; + p[0].QuadPart += 1; + p[1].QuadPart += (p[0].QuadPart == 0); + } + } + + /* Now for the division */ + if (c < 0) { + bSign = !bSign; + } + + + /* This will catch c == 0 and overflow */ + if (uc <= p[1].QuadPart) { + return bSign ? (LONGLONG)0x8000000000000000 : + (LONGLONG)0x7FFFFFFFFFFFFFFF; + } + + DWORDLONG ullResult; + + /* Do the division */ + /* If the dividend is a DWORD_LONG use the compiler */ + if (p[1].QuadPart == 0) { + ullResult = p[0].QuadPart / uc; + return bSign ? -(LONGLONG)ullResult : (LONGLONG)ullResult; + } + + /* If the divisor is a DWORD then its simpler */ + ULARGE_INTEGER ulic; + ulic.QuadPart = uc; + if (ulic.HighPart == 0) { + ULARGE_INTEGER uliDividend; + ULARGE_INTEGER uliResult; + DWORD dwDivisor = (DWORD)uc; + // ASSERT(p[1].HighPart == 0 && p[1].LowPart < dwDivisor); + uliDividend.HighPart = p[1].LowPart; + uliDividend.LowPart = p[0].HighPart; +#ifndef USE_LARGEINT + uliResult.HighPart = (DWORD)(uliDividend.QuadPart / dwDivisor); + p[0].HighPart = (DWORD)(uliDividend.QuadPart % dwDivisor); + uliResult.LowPart = 0; + uliResult.QuadPart = p[0].QuadPart / dwDivisor + uliResult.QuadPart; +#else + /* NOTE - this routine will take exceptions if + the result does not fit in a DWORD + */ + if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) { + uliResult.HighPart = EnlargedUnsignedDivide( + uliDividend, + dwDivisor, + &p[0].HighPart); + } else { + uliResult.HighPart = 0; + } + uliResult.LowPart = EnlargedUnsignedDivide( + p[0], + dwDivisor, + NULL); +#endif + return bSign ? -(LONGLONG)uliResult.QuadPart : + (LONGLONG)uliResult.QuadPart; + } + + + ullResult = 0; + + /* OK - do long division */ + for (int i = 0; i < 64; i++) { + ullResult <<= 1; + + /* Shift 128 bit p left 1 */ + p[1].QuadPart <<= 1; + if ((p[0].HighPart & 0x80000000) != 0) { + p[1].LowPart++; + } + p[0].QuadPart <<= 1; + + /* Compare */ + if (uc <= p[1].QuadPart) { + p[1].QuadPart -= uc; + ullResult += 1; + } + } + + return bSign ? - (LONGLONG)ullResult : (LONGLONG)ullResult; +} + +LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG d) +{ + ULARGE_INTEGER ua; + DWORD ub; + DWORD uc; + + /* Compute the absolute values to avoid signed arithmetic problems */ + ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a); + ub = (DWORD)(b >= 0 ? b : -b); + uc = (DWORD)(c >= 0 ? c : -c); + BOOL bSign = (a < 0) ^ (b < 0); + + /* Do long multiplication */ + ULARGE_INTEGER p0; + DWORD p1; + p0.QuadPart = UInt32x32To64(ua.LowPart, ub); + + if (ua.HighPart != 0) { + ULARGE_INTEGER x; + x.QuadPart = UInt32x32To64(ua.HighPart, ub) + p0.HighPart; + p0.HighPart = x.LowPart; + p1 = x.HighPart; + } else { + p1 = 0; + } + + if (d != 0) { + ULARGE_INTEGER ud0; + DWORD ud1; + + if (bSign) { + // + // Cast d to LONGLONG first otherwise -0x80000000 sign extends + // incorrectly + // + ud0.QuadPart = (DWORDLONG)(-(LONGLONG)d); + if (d > 0) { + /* -d < 0 */ + ud1 = (DWORD)-1; + } else { + ud1 = (DWORD)0; + } + } else { + ud0.QuadPart = (DWORDLONG)d; + if (d < 0) { + ud1 = (DWORD)-1; + } else { + ud1 = (DWORD)0; + } + } + /* Now do extended addition */ + ULARGE_INTEGER uliTotal; + + /* Add ls DWORDs */ + uliTotal.QuadPart = (DWORDLONG)ud0.LowPart + p0.LowPart; + p0.LowPart = uliTotal.LowPart; + + /* Propagate carry */ + uliTotal.LowPart = uliTotal.HighPart; + uliTotal.HighPart = 0; + + /* Add 2nd most ls DWORDs */ + uliTotal.QuadPart += (DWORDLONG)ud0.HighPart + p0.HighPart; + p0.HighPart = uliTotal.LowPart; + + /* Add MS DWORDLONGs - no carry expected */ + p1 += ud1 + uliTotal.HighPart; + + /* Now see if we got a sign change from the addition */ + if ((LONG)p1 < 0) { + bSign = !bSign; + + /* Negate the current value (ugh!) */ + p0.QuadPart = ~p0.QuadPart; + p1 = ~p1; + p0.QuadPart += 1; + p1 += (p0.QuadPart == 0); + } + } + + /* Now for the division */ + if (c < 0) { + bSign = !bSign; + } + + + /* This will catch c == 0 and overflow */ + if (uc <= p1) { + return bSign ? (LONGLONG)0x8000000000000000 : + (LONGLONG)0x7FFFFFFFFFFFFFFF; + } + + /* Do the division */ + + /* If the divisor is a DWORD then its simpler */ + ULARGE_INTEGER uliDividend; + ULARGE_INTEGER uliResult; + DWORD dwDivisor = uc; + uliDividend.HighPart = p1; + uliDividend.LowPart = p0.HighPart; + /* NOTE - this routine will take exceptions if + the result does not fit in a DWORD + */ + if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) { + uliResult.HighPart = EnlargedUnsignedDivide( + uliDividend, + dwDivisor, + &p0.HighPart); + } else { + uliResult.HighPart = 0; + } + uliResult.LowPart = EnlargedUnsignedDivide( + p0, + dwDivisor, + NULL); + return bSign ? -(LONGLONG)uliResult.QuadPart : + (LONGLONG)uliResult.QuadPart; +} + +#ifdef DEBUG +/******************************Public*Routine******************************\ +* Debug CCritSec helpers +* +* We provide debug versions of the Constructor, destructor, Lock and Unlock +* routines. The debug code tracks who owns each critical section by +* maintaining a depth count. +* +* History: +* +\**************************************************************************/ + +CCritSec::CCritSec(DWORD id) +{ + InitializeCriticalSection(&m_CritSec); + m_id = id; + m_currentOwner = m_lockCount = 0; + m_fTrace = FALSE; +} + +CCritSec::~CCritSec() +{ + DeleteCriticalSection(&m_CritSec); +} + +void CCritSec::Lock() +{ + UINT tracelevel=3; + DWORD us = GetCurrentThreadId(); + DWORD currentOwner = m_currentOwner; + if (currentOwner && (currentOwner != us)) { + // already owned, but not by us + if (m_fTrace) { + DbgLog((LOG_LOCKING, 2, TEXT("Thread %d about to wait for lock %x owned by %d"), + GetCurrentThreadId(), &m_CritSec, currentOwner)); + tracelevel=2; + // if we saw the message about waiting for the critical + // section we ensure we see the message when we get the + // critical section + } + } + + EnterCriticalSection(&m_CritSec); + + if (0 == m_lockCount++) { + // we now own it for the first time. Set owner information + m_currentOwner = us; + + if (m_fTrace) { + DbgLog((LOG_LOCKING, tracelevel, TEXT("Thread %d now owns lock %x"), m_currentOwner, &m_CritSec)); + } + } +} + +void CCritSec::Unlock() { + if (0 == --m_lockCount) { + // about to be unowned + if (m_fTrace) { + DbgLog((LOG_LOCKING, 3, TEXT("Thread %d releasing lock %x"), m_currentOwner, &m_CritSec)); + } + + m_currentOwner = 0; + } + LeaveCriticalSection(&m_CritSec); +} + +void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace) +{ + pcCrit->m_fTrace = fTrace; +} + +BOOL WINAPI CritCheckIn(CCritSec * pcCrit) +{ + return (GetCurrentThreadId() == pcCrit->m_currentOwner); +} + +BOOL WINAPI CritCheckIn(const CCritSec * pcCrit) +{ + return (GetCurrentThreadId() == pcCrit->m_currentOwner); +} + +BOOL WINAPI CritCheckOut(CCritSec * pcCrit) +{ + return (GetCurrentThreadId() != pcCrit->m_currentOwner); +} + +BOOL WINAPI CritCheckOut(const CCritSec * pcCrit) +{ + return (GetCurrentThreadId() != pcCrit->m_currentOwner); +} +#endif + + +STDAPI WriteBSTR(BSTR *pstrDest, LPCWSTR szSrc) +{ + *pstrDest = SysAllocString( szSrc ); + if( !(*pstrDest) ) return E_OUTOFMEMORY; + return NOERROR; +} + + +STDAPI FreeBSTR(BSTR* pstr) +{ + if( *pstr == NULL ) return S_FALSE; + SysFreeString( *pstr ); + return NOERROR; +} + + +// Return a wide string - allocating memory for it +// Returns: +// S_OK - no error +// E_POINTER - ppszReturn == NULL +// E_OUTOFMEMORY - can't allocate memory for returned string +STDAPI AMGetWideString(LPCWSTR psz, LPWSTR *ppszReturn) +{ + CheckPointer(ppszReturn, E_POINTER); + ValidateReadWritePtr(ppszReturn, sizeof(LPWSTR)); + DWORD nameLen = sizeof(WCHAR) * (lstrlenW(psz)+1); + *ppszReturn = (LPWSTR)CoTaskMemAlloc(nameLen); + if (*ppszReturn == NULL) { + return E_OUTOFMEMORY; + } + CopyMemory(*ppszReturn, psz, nameLen); + return NOERROR; +} + +// Waits for the HANDLE hObject. While waiting messages sent +// to windows on our thread by SendMessage will be processed. +// Using this function to do waits and mutual exclusion +// avoids some deadlocks in objects with windows. +// Return codes are the same as for WaitForSingleObject +DWORD WINAPI WaitDispatchingMessages( + HANDLE hObject, + DWORD dwWait, + HWND hwnd, + UINT uMsg, + HANDLE hEvent) +{ + BOOL bPeeked = FALSE; + DWORD dwResult; + DWORD dwStart = 0; + DWORD dwThreadPriority = 0; + + static UINT uMsgId = 0; + + HANDLE hObjects[2] = { hObject, hEvent }; + if (dwWait != INFINITE && dwWait != 0) { + dwStart = GetTickCount(); + } + for (; ; ) { + DWORD nCount = NULL != hEvent ? 2 : 1; + + // Minimize the chance of actually dispatching any messages + // by seeing if we can lock immediately. + dwResult = WaitForMultipleObjects(nCount, hObjects, FALSE, 0); + if (dwResult < WAIT_OBJECT_0 + nCount) { + break; + } + + DWORD dwTimeOut = dwWait; + if (dwTimeOut > 10) { + dwTimeOut = 10; + } + dwResult = MsgWaitForMultipleObjects( + nCount, + hObjects, + FALSE, + dwTimeOut, + hwnd == NULL ? QS_SENDMESSAGE : + QS_SENDMESSAGE + QS_POSTMESSAGE); + if (dwResult == WAIT_OBJECT_0 + nCount || + dwResult == WAIT_TIMEOUT && dwTimeOut != dwWait) { + MSG msg; + if (hwnd != NULL) { + while (PeekMessage(&msg, hwnd, uMsg, uMsg, PM_REMOVE)) { + DispatchMessage(&msg); + } + } + // Do this anyway - the previous peek doesn't flush out the + // messages + PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); + + if (dwWait != INFINITE && dwWait != 0) { + DWORD dwNow = GetTickCount(); + + // Working with differences handles wrap-around + DWORD dwDiff = dwNow - dwStart; + if (dwDiff > dwWait) { + dwWait = 0; + } else { + dwWait -= dwDiff; + } + dwStart = dwNow; + } + if (!bPeeked) { + // Raise our priority to prevent our message queue + // building up + dwThreadPriority = GetThreadPriority(GetCurrentThread()); + if (dwThreadPriority < THREAD_PRIORITY_HIGHEST) { + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); + } + bPeeked = TRUE; + } + } else { + break; + } + } + if (bPeeked) { + SetThreadPriority(GetCurrentThread(), dwThreadPriority); + if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) { + if (uMsgId == 0) { + uMsgId = RegisterWindowMessage(TEXT("AMUnblock")); + } + if (uMsgId != 0) { + MSG msg; + // Remove old ones + while (PeekMessage(&msg, (HWND)-1, uMsgId, uMsgId, PM_REMOVE)) { + } + } + PostThreadMessage(GetCurrentThreadId(), uMsgId, 0, 0); + } + } + return dwResult; +} + +HRESULT AmGetLastErrorToHResult() +{ + DWORD dwLastError = GetLastError(); + if(dwLastError != 0) + { + return HRESULT_FROM_WIN32(dwLastError); + } + else + { + return E_FAIL; + } +} + +IUnknown* QzAtlComPtrAssign(IUnknown** pp, IUnknown* lp) +{ + if (lp != NULL) + lp->AddRef(); + if (*pp) + (*pp)->Release(); + *pp = lp; + return lp; +} + +/****************************************************************************** + +CompatibleTimeSetEvent + + CompatibleTimeSetEvent() sets the TIME_KILL_SYNCHRONOUS flag before calling +timeSetEvent() if the current operating system supports it. TIME_KILL_SYNCHRONOUS +is supported on Windows XP and later operating systems. + +Parameters: +- The same parameters as timeSetEvent(). See timeSetEvent()'s documentation in +the Platform SDK for more information. + +Return Value: +- The same return value as timeSetEvent(). See timeSetEvent()'s documentation in +the Platform SDK for more information. + +******************************************************************************/ +MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent ) +{ + #if WINVER >= 0x0501 + { + static bool fCheckedVersion = false; + static bool fTimeKillSynchronousFlagAvailable = false; + + if( !fCheckedVersion ) { + fTimeKillSynchronousFlagAvailable = TimeKillSynchronousFlagAvailable(); + fCheckedVersion = true; + } + + if( fTimeKillSynchronousFlagAvailable ) { + fuEvent = fuEvent | TIME_KILL_SYNCHRONOUS; + } + } + #endif // WINVER >= 0x0501 + + return timeSetEvent( uDelay, uResolution, lpTimeProc, dwUser, fuEvent ); +} + +bool TimeKillSynchronousFlagAvailable( void ) +{ + OSVERSIONINFO osverinfo; + + osverinfo.dwOSVersionInfoSize = sizeof(osverinfo); + + if( GetVersionEx( &osverinfo ) ) { + + // Windows XP's major version is 5 and its' minor version is 1. + // timeSetEvent() started supporting the TIME_KILL_SYNCHRONOUS flag + // in Windows XP. + if( (osverinfo.dwMajorVersion > 5) || + ( (osverinfo.dwMajorVersion == 5) && (osverinfo.dwMinorVersion >= 1) ) ) { + return true; + } + } + + return false; +} diff --git a/plugins/GSdx/baseclasses/wxutil.h b/plugins/GSdx/baseclasses/wxutil.h index 1d7d9f82c2..f0d598d23f 100644 --- a/plugins/GSdx/baseclasses/wxutil.h +++ b/plugins/GSdx/baseclasses/wxutil.h @@ -1,541 +1,541 @@ -//------------------------------------------------------------------------------ -// File: WXUtil.h -// -// Desc: DirectShow base classes - defines helper classes and functions for -// building multimedia filters. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __WXUTIL__ -#define __WXUTIL__ - -// eliminate spurious "statement has no effect" warnings. -#pragma warning(disable: 4705) - -// wrapper for whatever critical section we have -class CCritSec { - - // make copy constructor and assignment operator inaccessible - - CCritSec(const CCritSec &refCritSec); - CCritSec &operator=(const CCritSec &refCritSec); - - CRITICAL_SECTION m_CritSec; - -#ifdef DEBUG -public: - DWORD m_id; - DWORD m_currentOwner; - DWORD m_lockCount; - BOOL m_fTrace; // Trace this one -public: - CCritSec(DWORD id = 0); - ~CCritSec(); - void Lock(); - void Unlock(); -#else - -public: - CCritSec() { - InitializeCriticalSection(&m_CritSec); - }; - - ~CCritSec() { - DeleteCriticalSection(&m_CritSec); - }; - - void Lock() { - EnterCriticalSection(&m_CritSec); - }; - - void Unlock() { - LeaveCriticalSection(&m_CritSec); - }; -#endif -}; - -// -// To make deadlocks easier to track it is useful to insert in the -// code an assertion that says whether we own a critical section or -// not. We make the routines that do the checking globals to avoid -// having different numbers of member functions in the debug and -// retail class implementations of CCritSec. In addition we provide -// a routine that allows usage of specific critical sections to be -// traced. This is NOT on by default - there are far too many. -// - -#ifdef DEBUG - BOOL WINAPI CritCheckIn(CCritSec * pcCrit); - BOOL WINAPI CritCheckIn(const CCritSec * pcCrit); - BOOL WINAPI CritCheckOut(CCritSec * pcCrit); - BOOL WINAPI CritCheckOut(const CCritSec * pcCrit); - void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace); -#else - #define CritCheckIn(x) TRUE - #define CritCheckOut(x) TRUE - #define DbgLockTrace(pc, fT) -#endif - - -// locks a critical section, and unlocks it automatically -// when the lock goes out of scope -class CAutoLock { - - // make copy constructor and assignment operator inaccessible - - CAutoLock(const CAutoLock &refAutoLock); - CAutoLock &operator=(const CAutoLock &refAutoLock); - -protected: - CCritSec * m_pLock; - -public: - CAutoLock(CCritSec * plock) - { - m_pLock = plock; - m_pLock->Lock(); - }; - - ~CAutoLock() { - m_pLock->Unlock(); - }; -}; - - - -// wrapper for event objects -class CAMEvent -{ - - // make copy constructor and assignment operator inaccessible - - CAMEvent(const CAMEvent &refEvent); - CAMEvent &operator=(const CAMEvent &refEvent); - -protected: - HANDLE m_hEvent; -public: - CAMEvent(BOOL fManualReset = FALSE); - ~CAMEvent(); - - // Cast to HANDLE - we don't support this as an lvalue - operator HANDLE () const { return m_hEvent; }; - - void Set() {EXECUTE_ASSERT(SetEvent(m_hEvent));}; - BOOL Wait(DWORD dwTimeout = INFINITE) { - return (WaitForSingleObject(m_hEvent, dwTimeout) == WAIT_OBJECT_0); - }; - void Reset() { ResetEvent(m_hEvent); }; - BOOL Check() { return Wait(0); }; -}; - - -// wrapper for event objects that do message processing -// This adds ONE method to the CAMEvent object to allow sent -// messages to be processed while waiting - -class CAMMsgEvent : public CAMEvent -{ - -public: - - // Allow SEND messages to be processed while waiting - BOOL WaitMsg(DWORD dwTimeout = INFINITE); -}; - -// old name supported for the time being -#define CTimeoutEvent CAMEvent - -// support for a worker thread - -// simple thread class supports creation of worker thread, synchronization -// and communication. Can be derived to simplify parameter passing -class AM_NOVTABLE CAMThread { - - // make copy constructor and assignment operator inaccessible - - CAMThread(const CAMThread &refThread); - CAMThread &operator=(const CAMThread &refThread); - - CAMEvent m_EventSend; - CAMEvent m_EventComplete; - - DWORD m_dwParam; - DWORD m_dwReturnVal; - -protected: - HANDLE m_hThread; - - // thread will run this function on startup - // must be supplied by derived class - virtual DWORD ThreadProc() = 0; - -public: - CAMThread(); - virtual ~CAMThread(); - - CCritSec m_AccessLock; // locks access by client threads - CCritSec m_WorkerLock; // locks access to shared objects - - // thread initially runs this. param is actually 'this'. function - // just gets this and calls ThreadProc - static DWORD WINAPI InitialThreadProc(LPVOID pv); - - // start thread running - error if already running - BOOL Create(); - - // signal the thread, and block for a response - // - DWORD CallWorker(DWORD); - - // accessor thread calls this when done with thread (having told thread - // to exit) - void Close() { - #pragma warning( push ) - // C4312: 'type cast' : conversion from 'LONG' to 'PVOID' of greater size - // - // This code works correctly on 32-bit and 64-bit systems. - #pragma warning( disable : 4312 ) - HANDLE hThread = (HANDLE)InterlockedExchangePointer(&m_hThread, 0); - #pragma warning( pop ) - - if (hThread) { - WaitForSingleObject(hThread, INFINITE); - CloseHandle(hThread); - } - }; - - // ThreadExists - // Return TRUE if the thread exists. FALSE otherwise - BOOL ThreadExists(void) const - { - if (m_hThread == 0) { - return FALSE; - } else { - return TRUE; - } - } - - // wait for the next request - DWORD GetRequest(); - - // is there a request? - BOOL CheckRequest(DWORD * pParam); - - // reply to the request - void Reply(DWORD); - - // If you want to do WaitForMultipleObjects you'll need to include - // this handle in your wait list or you won't be responsive - HANDLE GetRequestHandle() const { return m_EventSend; }; - - // Find out what the request was - DWORD GetRequestParam() const { return m_dwParam; }; - - // call CoInitializeEx (COINIT_DISABLE_OLE1DDE) if - // available. S_FALSE means it's not available. - static HRESULT CoInitializeHelper(); -}; - - -// CQueue -// -// Implements a simple Queue ADT. The queue contains a finite number of -// objects, access to which is controlled by a semaphore. The semaphore -// is created with an initial count (N). Each time an object is added -// a call to WaitForSingleObject is made on the semaphore's handle. When -// this function returns a slot has been reserved in the queue for the new -// object. If no slots are available the function blocks until one becomes -// available. Each time an object is removed from the queue ReleaseSemaphore -// is called on the semaphore's handle, thus freeing a slot in the queue. -// If no objects are present in the queue the function blocks until an -// object has been added. - -#define DEFAULT_QUEUESIZE 2 - -template class CQueue { -private: - HANDLE hSemPut; // Semaphore controlling queue "putting" - HANDLE hSemGet; // Semaphore controlling queue "getting" - CRITICAL_SECTION CritSect; // Thread seriallization - int nMax; // Max objects allowed in queue - int iNextPut; // Array index of next "PutMsg" - int iNextGet; // Array index of next "GetMsg" - T *QueueObjects; // Array of objects (ptr's to void) - - void Initialize(int n) { - iNextPut = iNextGet = 0; - nMax = n; - InitializeCriticalSection(&CritSect); - hSemPut = CreateSemaphore(NULL, n, n, NULL); - hSemGet = CreateSemaphore(NULL, 0, n, NULL); - QueueObjects = new T[n]; - } - - -public: - CQueue(int n) { - Initialize(n); - } - - CQueue() { - Initialize(DEFAULT_QUEUESIZE); - } - - ~CQueue() { - delete [] QueueObjects; - DeleteCriticalSection(&CritSect); - CloseHandle(hSemPut); - CloseHandle(hSemGet); - } - - T GetQueueObject() { - int iSlot; - T Object; - LONG lPrevious; - - // Wait for someone to put something on our queue, returns straight - // away is there is already an object on the queue. - // - WaitForSingleObject(hSemGet, INFINITE); - - EnterCriticalSection(&CritSect); - iSlot = iNextGet++ % nMax; - Object = QueueObjects[iSlot]; - LeaveCriticalSection(&CritSect); - - // Release anyone waiting to put an object onto our queue as there - // is now space available in the queue. - // - ReleaseSemaphore(hSemPut, 1L, &lPrevious); - return Object; - } - - void PutQueueObject(T Object) { - int iSlot; - LONG lPrevious; - - // Wait for someone to get something from our queue, returns straight - // away is there is already an empty slot on the queue. - // - WaitForSingleObject(hSemPut, INFINITE); - - EnterCriticalSection(&CritSect); - iSlot = iNextPut++ % nMax; - QueueObjects[iSlot] = Object; - LeaveCriticalSection(&CritSect); - - // Release anyone waiting to remove an object from our queue as there - // is now an object available to be removed. - // - ReleaseSemaphore(hSemGet, 1L, &lPrevious); - } -}; - -// miscellaneous string conversion functions -// NOTE: as we need to use the same binaries on Win95 as on NT this code should -// be compiled WITHOUT unicode being defined. Otherwise we will not pick up -// these internal routines and the binary will not run on Win95. - -// int WINAPIV wsprintfWInternal(LPWSTR, LPCWSTR, ...); - -//LPWSTR -//WINAPI -//lstrcpyWInternal( -// LPWSTR lpString1, -// LPCWSTR lpString2 -// ); -LPWSTR -WINAPI -lstrcpynWInternal( - LPWSTR lpString1, - LPCWSTR lpString2, - int iMaxLength - ); -int -WINAPI -lstrcmpWInternal( - LPCWSTR lpString1, - LPCWSTR lpString2 - ); -int -WINAPI -lstrcmpiWInternal( - LPCWSTR lpString1, - LPCWSTR lpString2 - ); -int -WINAPI -lstrlenWInternal( - LPCWSTR lpString - ); - -#ifndef UNICODE -#define wsprintfW wsprintfWInternal -#define lstrcpyW lstrcpyWInternal -#define lstrcpynW lstrcpynWInternal -#define lstrcmpW lstrcmpWInternal -#define lstrcmpiW lstrcmpiWInternal -#define lstrlenW lstrlenWInternal -#endif - -extern "C" -void * __stdcall memmoveInternal(void *, const void *, size_t); - -inline void * __cdecl memchrInternal(const void *buf, int chr, size_t cnt) -{ -#ifdef _X86_ - void *pRet = NULL; - - _asm { - cld // make sure we get the direction right - mov ecx, cnt // num of bytes to scan - mov edi, buf // pointer byte stream - mov eax, chr // byte to scan for - repne scasb // look for the byte in the byte stream - jnz exit_memchr // Z flag set if byte found - dec edi // scasb always increments edi even when it - // finds the required byte - mov pRet, edi -exit_memchr: - } - return pRet; - -#else - while ( cnt && (*(unsigned char *)buf != (unsigned char)chr) ) { - buf = (unsigned char *)buf + 1; - cnt--; - } - - return(cnt ? (void *)buf : NULL); -#endif -} - -void WINAPI IntToWstr(int i, LPWSTR wstr, size_t len); - -#define WstrToInt(sz) _wtoi(sz) -#define atoiW(sz) _wtoi(sz) -#define atoiA(sz) atoi(sz) - -// These are available to help managing bitmap VIDEOINFOHEADER media structures - -extern const DWORD bits555[3]; -extern const DWORD bits565[3]; -extern const DWORD bits888[3]; - -// These help convert between VIDEOINFOHEADER and BITMAPINFO structures - -STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader); -STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader); -STDAPI_(WORD) GetBitCount(const GUID *pSubtype); - -// strmbase.lib implements this for compatibility with people who -// managed to link to this directly. we don't want to advertise it. -// -// STDAPI_(/* T */ CHAR *) GetSubtypeName(const GUID *pSubtype); - -STDAPI_(CHAR *) GetSubtypeNameA(const GUID *pSubtype); -STDAPI_(WCHAR *) GetSubtypeNameW(const GUID *pSubtype); - -#ifdef UNICODE -#define GetSubtypeName GetSubtypeNameW -#else -#define GetSubtypeName GetSubtypeNameA -#endif - -STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader); -STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader); -STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo); -STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo); - - -// Compares two interfaces and returns TRUE if they are on the same object -BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond); - -// This is for comparing pins -#define EqualPins(pPin1, pPin2) IsEqualObject(pPin1, pPin2) - - -// Arithmetic helper functions - -// Compute (a * b + rnd) / c -LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG rnd); -LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG rnd); - - -// Avoids us dyna-linking to SysAllocString to copy BSTR strings -STDAPI WriteBSTR(BSTR * pstrDest, LPCWSTR szSrc); -STDAPI FreeBSTR(BSTR* pstr); - -// Return a wide string - allocating memory for it -// Returns: -// S_OK - no error -// E_POINTER - ppszReturn == NULL -// E_OUTOFMEMORY - can't allocate memory for returned string -STDAPI AMGetWideString(LPCWSTR pszString, LPWSTR *ppszReturn); - -// Special wait for objects owning windows -DWORD WINAPI WaitDispatchingMessages( - HANDLE hObject, - DWORD dwWait, - HWND hwnd = NULL, - UINT uMsg = 0, - HANDLE hEvent = NULL); - -// HRESULT_FROM_WIN32 converts ERROR_SUCCESS to a success code, but in -// our use of HRESULT_FROM_WIN32, it typically means a function failed -// to call SetLastError(), and we still want a failure code. -// -#define AmHresultFromWin32(x) (MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, x)) - -// call GetLastError and return an HRESULT value that will fail the -// SUCCEEDED() macro. -HRESULT AmGetLastErrorToHResult(void); - -// duplicate of ATL's CComPtr to avoid linker conflicts. - -IUnknown* QzAtlComPtrAssign(IUnknown** pp, IUnknown* lp); - -template -class QzCComPtr -{ -public: - typedef T _PtrClass; - QzCComPtr() {p=NULL;} - QzCComPtr(T* lp) - { - if ((p = lp) != NULL) - p->AddRef(); - } - QzCComPtr(const QzCComPtr& lp) - { - if ((p = lp.p) != NULL) - p->AddRef(); - } - ~QzCComPtr() {if (p) p->Release();} - void Release() {if (p) p->Release(); p=NULL;} - operator T*() {return (T*)p;} - T& operator*() {ASSERT(p!=NULL); return *p; } - //The assert on operator& usually indicates a bug. If this is really - //what is needed, however, take the address of the p member explicitly. - T** operator&() { ASSERT(p==NULL); return &p; } - T* operator->() { ASSERT(p!=NULL); return p; } - T* operator=(T* lp){return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp);} - T* operator=(const QzCComPtr& lp) - { - return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp.p); - } -#if _MSC_VER>1020 - bool operator!(){return (p == NULL);} -#else - BOOL operator!(){return (p == NULL) ? TRUE : FALSE;} -#endif - T* p; -}; - -MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent ); -bool TimeKillSynchronousFlagAvailable( void ); - -#endif /* __WXUTIL__ */ +//------------------------------------------------------------------------------ +// File: WXUtil.h +// +// Desc: DirectShow base classes - defines helper classes and functions for +// building multimedia filters. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __WXUTIL__ +#define __WXUTIL__ + +// eliminate spurious "statement has no effect" warnings. +#pragma warning(disable: 4705) + +// wrapper for whatever critical section we have +class CCritSec { + + // make copy constructor and assignment operator inaccessible + + CCritSec(const CCritSec &refCritSec); + CCritSec &operator=(const CCritSec &refCritSec); + + CRITICAL_SECTION m_CritSec; + +#ifdef DEBUG +public: + DWORD m_id; + DWORD m_currentOwner; + DWORD m_lockCount; + BOOL m_fTrace; // Trace this one +public: + CCritSec(DWORD id = 0); + ~CCritSec(); + void Lock(); + void Unlock(); +#else + +public: + CCritSec() { + InitializeCriticalSection(&m_CritSec); + }; + + ~CCritSec() { + DeleteCriticalSection(&m_CritSec); + }; + + void Lock() { + EnterCriticalSection(&m_CritSec); + }; + + void Unlock() { + LeaveCriticalSection(&m_CritSec); + }; +#endif +}; + +// +// To make deadlocks easier to track it is useful to insert in the +// code an assertion that says whether we own a critical section or +// not. We make the routines that do the checking globals to avoid +// having different numbers of member functions in the debug and +// retail class implementations of CCritSec. In addition we provide +// a routine that allows usage of specific critical sections to be +// traced. This is NOT on by default - there are far too many. +// + +#ifdef DEBUG + BOOL WINAPI CritCheckIn(CCritSec * pcCrit); + BOOL WINAPI CritCheckIn(const CCritSec * pcCrit); + BOOL WINAPI CritCheckOut(CCritSec * pcCrit); + BOOL WINAPI CritCheckOut(const CCritSec * pcCrit); + void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace); +#else + #define CritCheckIn(x) TRUE + #define CritCheckOut(x) TRUE + #define DbgLockTrace(pc, fT) +#endif + + +// locks a critical section, and unlocks it automatically +// when the lock goes out of scope +class CAutoLock { + + // make copy constructor and assignment operator inaccessible + + CAutoLock(const CAutoLock &refAutoLock); + CAutoLock &operator=(const CAutoLock &refAutoLock); + +protected: + CCritSec * m_pLock; + +public: + CAutoLock(CCritSec * plock) + { + m_pLock = plock; + m_pLock->Lock(); + }; + + ~CAutoLock() { + m_pLock->Unlock(); + }; +}; + + + +// wrapper for event objects +class CAMEvent +{ + + // make copy constructor and assignment operator inaccessible + + CAMEvent(const CAMEvent &refEvent); + CAMEvent &operator=(const CAMEvent &refEvent); + +protected: + HANDLE m_hEvent; +public: + CAMEvent(BOOL fManualReset = FALSE); + ~CAMEvent(); + + // Cast to HANDLE - we don't support this as an lvalue + operator HANDLE () const { return m_hEvent; }; + + void Set() {EXECUTE_ASSERT(SetEvent(m_hEvent));}; + BOOL Wait(DWORD dwTimeout = INFINITE) { + return (WaitForSingleObject(m_hEvent, dwTimeout) == WAIT_OBJECT_0); + }; + void Reset() { ResetEvent(m_hEvent); }; + BOOL Check() { return Wait(0); }; +}; + + +// wrapper for event objects that do message processing +// This adds ONE method to the CAMEvent object to allow sent +// messages to be processed while waiting + +class CAMMsgEvent : public CAMEvent +{ + +public: + + // Allow SEND messages to be processed while waiting + BOOL WaitMsg(DWORD dwTimeout = INFINITE); +}; + +// old name supported for the time being +#define CTimeoutEvent CAMEvent + +// support for a worker thread + +// simple thread class supports creation of worker thread, synchronization +// and communication. Can be derived to simplify parameter passing +class AM_NOVTABLE CAMThread { + + // make copy constructor and assignment operator inaccessible + + CAMThread(const CAMThread &refThread); + CAMThread &operator=(const CAMThread &refThread); + + CAMEvent m_EventSend; + CAMEvent m_EventComplete; + + DWORD m_dwParam; + DWORD m_dwReturnVal; + +protected: + HANDLE m_hThread; + + // thread will run this function on startup + // must be supplied by derived class + virtual DWORD ThreadProc() = 0; + +public: + CAMThread(); + virtual ~CAMThread(); + + CCritSec m_AccessLock; // locks access by client threads + CCritSec m_WorkerLock; // locks access to shared objects + + // thread initially runs this. param is actually 'this'. function + // just gets this and calls ThreadProc + static DWORD WINAPI InitialThreadProc(LPVOID pv); + + // start thread running - error if already running + BOOL Create(); + + // signal the thread, and block for a response + // + DWORD CallWorker(DWORD); + + // accessor thread calls this when done with thread (having told thread + // to exit) + void Close() { + #pragma warning( push ) + // C4312: 'type cast' : conversion from 'LONG' to 'PVOID' of greater size + // + // This code works correctly on 32-bit and 64-bit systems. + #pragma warning( disable : 4312 ) + HANDLE hThread = (HANDLE)InterlockedExchangePointer(&m_hThread, 0); + #pragma warning( pop ) + + if (hThread) { + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + } + }; + + // ThreadExists + // Return TRUE if the thread exists. FALSE otherwise + BOOL ThreadExists(void) const + { + if (m_hThread == 0) { + return FALSE; + } else { + return TRUE; + } + } + + // wait for the next request + DWORD GetRequest(); + + // is there a request? + BOOL CheckRequest(DWORD * pParam); + + // reply to the request + void Reply(DWORD); + + // If you want to do WaitForMultipleObjects you'll need to include + // this handle in your wait list or you won't be responsive + HANDLE GetRequestHandle() const { return m_EventSend; }; + + // Find out what the request was + DWORD GetRequestParam() const { return m_dwParam; }; + + // call CoInitializeEx (COINIT_DISABLE_OLE1DDE) if + // available. S_FALSE means it's not available. + static HRESULT CoInitializeHelper(); +}; + + +// CQueue +// +// Implements a simple Queue ADT. The queue contains a finite number of +// objects, access to which is controlled by a semaphore. The semaphore +// is created with an initial count (N). Each time an object is added +// a call to WaitForSingleObject is made on the semaphore's handle. When +// this function returns a slot has been reserved in the queue for the new +// object. If no slots are available the function blocks until one becomes +// available. Each time an object is removed from the queue ReleaseSemaphore +// is called on the semaphore's handle, thus freeing a slot in the queue. +// If no objects are present in the queue the function blocks until an +// object has been added. + +#define DEFAULT_QUEUESIZE 2 + +template class CQueue { +private: + HANDLE hSemPut; // Semaphore controlling queue "putting" + HANDLE hSemGet; // Semaphore controlling queue "getting" + CRITICAL_SECTION CritSect; // Thread seriallization + int nMax; // Max objects allowed in queue + int iNextPut; // Array index of next "PutMsg" + int iNextGet; // Array index of next "GetMsg" + T *QueueObjects; // Array of objects (ptr's to void) + + void Initialize(int n) { + iNextPut = iNextGet = 0; + nMax = n; + InitializeCriticalSection(&CritSect); + hSemPut = CreateSemaphore(NULL, n, n, NULL); + hSemGet = CreateSemaphore(NULL, 0, n, NULL); + QueueObjects = new T[n]; + } + + +public: + CQueue(int n) { + Initialize(n); + } + + CQueue() { + Initialize(DEFAULT_QUEUESIZE); + } + + ~CQueue() { + delete [] QueueObjects; + DeleteCriticalSection(&CritSect); + CloseHandle(hSemPut); + CloseHandle(hSemGet); + } + + T GetQueueObject() { + int iSlot; + T Object; + LONG lPrevious; + + // Wait for someone to put something on our queue, returns straight + // away is there is already an object on the queue. + // + WaitForSingleObject(hSemGet, INFINITE); + + EnterCriticalSection(&CritSect); + iSlot = iNextGet++ % nMax; + Object = QueueObjects[iSlot]; + LeaveCriticalSection(&CritSect); + + // Release anyone waiting to put an object onto our queue as there + // is now space available in the queue. + // + ReleaseSemaphore(hSemPut, 1L, &lPrevious); + return Object; + } + + void PutQueueObject(T Object) { + int iSlot; + LONG lPrevious; + + // Wait for someone to get something from our queue, returns straight + // away is there is already an empty slot on the queue. + // + WaitForSingleObject(hSemPut, INFINITE); + + EnterCriticalSection(&CritSect); + iSlot = iNextPut++ % nMax; + QueueObjects[iSlot] = Object; + LeaveCriticalSection(&CritSect); + + // Release anyone waiting to remove an object from our queue as there + // is now an object available to be removed. + // + ReleaseSemaphore(hSemGet, 1L, &lPrevious); + } +}; + +// miscellaneous string conversion functions +// NOTE: as we need to use the same binaries on Win95 as on NT this code should +// be compiled WITHOUT unicode being defined. Otherwise we will not pick up +// these internal routines and the binary will not run on Win95. + +// int WINAPIV wsprintfWInternal(LPWSTR, LPCWSTR, ...); + +//LPWSTR +//WINAPI +//lstrcpyWInternal( +// LPWSTR lpString1, +// LPCWSTR lpString2 +// ); +LPWSTR +WINAPI +lstrcpynWInternal( + LPWSTR lpString1, + LPCWSTR lpString2, + int iMaxLength + ); +int +WINAPI +lstrcmpWInternal( + LPCWSTR lpString1, + LPCWSTR lpString2 + ); +int +WINAPI +lstrcmpiWInternal( + LPCWSTR lpString1, + LPCWSTR lpString2 + ); +int +WINAPI +lstrlenWInternal( + LPCWSTR lpString + ); + +#ifndef UNICODE +#define wsprintfW wsprintfWInternal +#define lstrcpyW lstrcpyWInternal +#define lstrcpynW lstrcpynWInternal +#define lstrcmpW lstrcmpWInternal +#define lstrcmpiW lstrcmpiWInternal +#define lstrlenW lstrlenWInternal +#endif + +extern "C" +void * __stdcall memmoveInternal(void *, const void *, size_t); + +inline void * __cdecl memchrInternal(const void *buf, int chr, size_t cnt) +{ +#ifdef _X86_ + void *pRet = NULL; + + _asm { + cld // make sure we get the direction right + mov ecx, cnt // num of bytes to scan + mov edi, buf // pointer byte stream + mov eax, chr // byte to scan for + repne scasb // look for the byte in the byte stream + jnz exit_memchr // Z flag set if byte found + dec edi // scasb always increments edi even when it + // finds the required byte + mov pRet, edi +exit_memchr: + } + return pRet; + +#else + while ( cnt && (*(unsigned char *)buf != (unsigned char)chr) ) { + buf = (unsigned char *)buf + 1; + cnt--; + } + + return(cnt ? (void *)buf : NULL); +#endif +} + +void WINAPI IntToWstr(int i, LPWSTR wstr, size_t len); + +#define WstrToInt(sz) _wtoi(sz) +#define atoiW(sz) _wtoi(sz) +#define atoiA(sz) atoi(sz) + +// These are available to help managing bitmap VIDEOINFOHEADER media structures + +extern const DWORD bits555[3]; +extern const DWORD bits565[3]; +extern const DWORD bits888[3]; + +// These help convert between VIDEOINFOHEADER and BITMAPINFO structures + +STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader); +STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader); +STDAPI_(WORD) GetBitCount(const GUID *pSubtype); + +// strmbase.lib implements this for compatibility with people who +// managed to link to this directly. we don't want to advertise it. +// +// STDAPI_(/* T */ CHAR *) GetSubtypeName(const GUID *pSubtype); + +STDAPI_(CHAR *) GetSubtypeNameA(const GUID *pSubtype); +STDAPI_(WCHAR *) GetSubtypeNameW(const GUID *pSubtype); + +#ifdef UNICODE +#define GetSubtypeName GetSubtypeNameW +#else +#define GetSubtypeName GetSubtypeNameA +#endif + +STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader); +STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader); +STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo); +STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo); + + +// Compares two interfaces and returns TRUE if they are on the same object +BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond); + +// This is for comparing pins +#define EqualPins(pPin1, pPin2) IsEqualObject(pPin1, pPin2) + + +// Arithmetic helper functions + +// Compute (a * b + rnd) / c +LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG rnd); +LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG rnd); + + +// Avoids us dyna-linking to SysAllocString to copy BSTR strings +STDAPI WriteBSTR(BSTR * pstrDest, LPCWSTR szSrc); +STDAPI FreeBSTR(BSTR* pstr); + +// Return a wide string - allocating memory for it +// Returns: +// S_OK - no error +// E_POINTER - ppszReturn == NULL +// E_OUTOFMEMORY - can't allocate memory for returned string +STDAPI AMGetWideString(LPCWSTR pszString, LPWSTR *ppszReturn); + +// Special wait for objects owning windows +DWORD WINAPI WaitDispatchingMessages( + HANDLE hObject, + DWORD dwWait, + HWND hwnd = NULL, + UINT uMsg = 0, + HANDLE hEvent = NULL); + +// HRESULT_FROM_WIN32 converts ERROR_SUCCESS to a success code, but in +// our use of HRESULT_FROM_WIN32, it typically means a function failed +// to call SetLastError(), and we still want a failure code. +// +#define AmHresultFromWin32(x) (MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, x)) + +// call GetLastError and return an HRESULT value that will fail the +// SUCCEEDED() macro. +HRESULT AmGetLastErrorToHResult(void); + +// duplicate of ATL's CComPtr to avoid linker conflicts. + +IUnknown* QzAtlComPtrAssign(IUnknown** pp, IUnknown* lp); + +template +class QzCComPtr +{ +public: + typedef T _PtrClass; + QzCComPtr() {p=NULL;} + QzCComPtr(T* lp) + { + if ((p = lp) != NULL) + p->AddRef(); + } + QzCComPtr(const QzCComPtr& lp) + { + if ((p = lp.p) != NULL) + p->AddRef(); + } + ~QzCComPtr() {if (p) p->Release();} + void Release() {if (p) p->Release(); p=NULL;} + operator T*() {return (T*)p;} + T& operator*() {ASSERT(p!=NULL); return *p; } + //The assert on operator& usually indicates a bug. If this is really + //what is needed, however, take the address of the p member explicitly. + T** operator&() { ASSERT(p==NULL); return &p; } + T* operator->() { ASSERT(p!=NULL); return p; } + T* operator=(T* lp){return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp);} + T* operator=(const QzCComPtr& lp) + { + return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp.p); + } +#if _MSC_VER>1020 + bool operator!(){return (p == NULL);} +#else + BOOL operator!(){return (p == NULL) ? TRUE : FALSE;} +#endif + T* p; +}; + +MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent ); +bool TimeKillSynchronousFlagAvailable( void ); + +#endif /* __WXUTIL__ */ diff --git a/plugins/GSdx/resource.h b/plugins/GSdx/resource.h index c2c41e76a1..a10f5e1c5f 100644 --- a/plugins/GSdx/resource.h +++ b/plugins/GSdx/resource.h @@ -1,55 +1,55 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by GSdx.rc -// -#define IDC_CHECK1 2001 -#define IDC_CHECK2 2002 -#define IDC_CHECK3 2003 -#define IDC_CHECK5 2004 -#define IDC_CHECK6 2005 -#define IDC_COMBO1 2006 -#define IDC_COMBO3 2007 -#define IDC_COMBO4 2008 -#define IDC_EDIT1 2009 -#define IDC_EDIT2 2010 -#define IDC_BUTTON1 2011 -#define IDC_BUTTON2 2012 -#define IDC_EDIT3 2012 -#define IDC_CUSTOM1 2013 -#define IDC_CHECK4 2014 -#define IDC_COMBO2 2015 -#define IDC_COMBO5 2016 -#define IDC_RADIO1 2017 -#define IDC_COMBO6 2017 -#define IDC_SPIN1 2018 -#define IDC_COMBO7 2018 -#define IDC_SPIN2 2019 -#define IDD_CONFIG 2020 -#define IDC_SPIN3 2020 -#define IDB_LOGO9 2021 -#define IDB_LOGO10 2022 -#define IDC_CHECK7 2023 -#define IDC_LOGO9 2024 -#define IDC_LOGO10 2025 -#define IDD_CAPTURE 2026 -#define IDC_EDIT4 2027 -#define IDD_GPUCONFIG 2027 -#define IDR_CONVERT9_FX 10000 -#define IDR_TFX9_FX 10001 -#define IDR_MERGE9_FX 10002 -#define IDR_INTERLACE9_FX 10003 -#define IDR_CONVERT10_FX 10004 -#define IDR_TFX10_FX 10005 -#define IDR_MERGE10_FX 10006 -#define IDR_INTERLACE10_FX 10007 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 10009 -#define _APS_NEXT_COMMAND_VALUE 32771 -#define _APS_NEXT_CONTROL_VALUE 2028 -#define _APS_NEXT_SYMED_VALUE 5000 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by GSdx.rc +// +#define IDC_CHECK1 2001 +#define IDC_CHECK2 2002 +#define IDC_CHECK3 2003 +#define IDC_CHECK5 2004 +#define IDC_CHECK6 2005 +#define IDC_COMBO1 2006 +#define IDC_COMBO3 2007 +#define IDC_COMBO4 2008 +#define IDC_EDIT1 2009 +#define IDC_EDIT2 2010 +#define IDC_BUTTON1 2011 +#define IDC_BUTTON2 2012 +#define IDC_EDIT3 2012 +#define IDC_CUSTOM1 2013 +#define IDC_CHECK4 2014 +#define IDC_COMBO2 2015 +#define IDC_COMBO5 2016 +#define IDC_RADIO1 2017 +#define IDC_COMBO6 2017 +#define IDC_SPIN1 2018 +#define IDC_COMBO7 2018 +#define IDC_SPIN2 2019 +#define IDD_CONFIG 2020 +#define IDC_SPIN3 2020 +#define IDB_LOGO9 2021 +#define IDB_LOGO10 2022 +#define IDC_CHECK7 2023 +#define IDC_LOGO9 2024 +#define IDC_LOGO10 2025 +#define IDD_CAPTURE 2026 +#define IDC_EDIT4 2027 +#define IDD_GPUCONFIG 2027 +#define IDR_CONVERT9_FX 10000 +#define IDR_TFX9_FX 10001 +#define IDR_MERGE9_FX 10002 +#define IDR_INTERLACE9_FX 10003 +#define IDR_CONVERT10_FX 10004 +#define IDR_TFX10_FX 10005 +#define IDR_MERGE10_FX 10006 +#define IDR_INTERLACE10_FX 10007 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 10009 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 2028 +#define _APS_NEXT_SYMED_VALUE 5000 +#endif +#endif diff --git a/plugins/GSdx/sse.h b/plugins/GSdx/sse.h index 4efc8a96e0..b8af513a10 100644 --- a/plugins/GSdx/sse.h +++ b/plugins/GSdx/sse.h @@ -1,132 +1,132 @@ -/* - * Copyright (C) 2007-2009 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -// sse2 - -#if _M_SSE >= 0x200 - - #include - #include - - #ifndef _MM_DENORMALS_ARE_ZERO - #define _MM_DENORMALS_ARE_ZERO 0x0040 - #endif - - #define MXCSR (_MM_DENORMALS_ARE_ZERO | _MM_MASK_MASK | _MM_ROUND_NEAREST | _MM_FLUSH_ZERO_ON) - - #if _MSC_VER < 1500 - - __forceinline __m128i _mm_castps_si128(__m128 a) {return *(__m128i*)&a;} - __forceinline __m128 _mm_castsi128_ps(__m128i a) {return *(__m128*)&a;} - __forceinline __m128i _mm_castpd_si128(__m128d a) {return *(__m128i*)&a;} - __forceinline __m128d _mm_castsi128_pd(__m128i a) {return *(__m128d*)&a;} - __forceinline __m128d _mm_castps_pd(__m128 a) {return *(__m128d*)&a;} - __forceinline __m128 _mm_castpd_ps(__m128d a) {return *(__m128*)&a;} - - #endif - - const __m128 ps_3f800000 = _mm_castsi128_ps(_mm_set1_epi32(0x3f800000)); - const __m128 ps_4b000000 = _mm_castsi128_ps(_mm_set1_epi32(0x4b000000)); - const __m128 ps_7fffffff = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)); - const __m128 ps_80000000 = _mm_castsi128_ps(_mm_set1_epi32(0x80000000)); - const __m128 ps_ffffffff = _mm_castsi128_ps(_mm_set1_epi32(0xffffffff)); - - __forceinline __m128 _mm_neg_ps(__m128 r) - { - return _mm_xor_ps(ps_80000000, r); - } - - __forceinline __m128 _mm_abs_ps(__m128 r) - { - return _mm_and_ps(ps_7fffffff, r); - } - - #define _MM_TRANSPOSE4_SI128(row0, row1, row2, row3) \ - { \ - __m128 tmp0 = _mm_shuffle_ps(_mm_castsi128_ps(row0), _mm_castsi128_ps(row1), 0x44); \ - __m128 tmp2 = _mm_shuffle_ps(_mm_castsi128_ps(row0), _mm_castsi128_ps(row1), 0xEE); \ - __m128 tmp1 = _mm_shuffle_ps(_mm_castsi128_ps(row2), _mm_castsi128_ps(row3), 0x44); \ - __m128 tmp3 = _mm_shuffle_ps(_mm_castsi128_ps(row2), _mm_castsi128_ps(row3), 0xEE); \ - (row0) = _mm_castps_si128(_mm_shuffle_ps(tmp0, tmp1, 0x88)); \ - (row1) = _mm_castps_si128(_mm_shuffle_ps(tmp0, tmp1, 0xDD)); \ - (row2) = _mm_castps_si128(_mm_shuffle_ps(tmp2, tmp3, 0x88)); \ - (row3) = _mm_castps_si128(_mm_shuffle_ps(tmp2, tmp3, 0xDD)); \ - } - - __forceinline __m128 _mm_rcpnr_ps(__m128 r) - { - __m128 t = _mm_rcp_ps(r); - - return _mm_sub_ps(_mm_add_ps(t, t), _mm_mul_ps(_mm_mul_ps(t, t), r)); - } - - -#else - -#error TODO: GSVector4 and GSRasterizer needs SSE2 - -#endif - -// sse3 - -#if _M_SSE >= 0x301 - - #include - -#endif - -// sse4 - -#if _M_SSE >= 0x401 - - #include - -#else - - // not an equal replacement for sse4's blend but for our needs it is ok - - #define _mm_blendv_ps(a, b, mask) _mm_or_ps(_mm_andnot_ps(mask, a), _mm_and_ps(mask, b)) - #define _mm_blendv_epi8(a, b, mask) _mm_or_si128(_mm_andnot_si128(mask, a), _mm_and_si128(mask, b)) - - __forceinline __m128 _mm_round_ps(__m128 x) - { - __m128 t = _mm_or_ps(_mm_and_ps(ps_80000000, x), ps_4b000000); - - return _mm_sub_ps(_mm_add_ps(x, t), t); - } - - __forceinline __m128 _mm_floor_ps(__m128 x) - { - __m128 t = _mm_round_ps(x); - - return _mm_sub_ps(t, _mm_and_ps(_mm_cmplt_ps(x, t), ps_3f800000)); - } - - __forceinline __m128 _mm_ceil_ps(__m128 x) - { - __m128 t = _mm_round_ps(x); - - return _mm_add_ps(t, _mm_and_ps(_mm_cmpgt_ps(x, t), ps_3f800000)); - } - -#endif +/* + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +// sse2 + +#if _M_SSE >= 0x200 + + #include + #include + + #ifndef _MM_DENORMALS_ARE_ZERO + #define _MM_DENORMALS_ARE_ZERO 0x0040 + #endif + + #define MXCSR (_MM_DENORMALS_ARE_ZERO | _MM_MASK_MASK | _MM_ROUND_NEAREST | _MM_FLUSH_ZERO_ON) + + #if _MSC_VER < 1500 + + __forceinline __m128i _mm_castps_si128(__m128 a) {return *(__m128i*)&a;} + __forceinline __m128 _mm_castsi128_ps(__m128i a) {return *(__m128*)&a;} + __forceinline __m128i _mm_castpd_si128(__m128d a) {return *(__m128i*)&a;} + __forceinline __m128d _mm_castsi128_pd(__m128i a) {return *(__m128d*)&a;} + __forceinline __m128d _mm_castps_pd(__m128 a) {return *(__m128d*)&a;} + __forceinline __m128 _mm_castpd_ps(__m128d a) {return *(__m128*)&a;} + + #endif + + const __m128 ps_3f800000 = _mm_castsi128_ps(_mm_set1_epi32(0x3f800000)); + const __m128 ps_4b000000 = _mm_castsi128_ps(_mm_set1_epi32(0x4b000000)); + const __m128 ps_7fffffff = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)); + const __m128 ps_80000000 = _mm_castsi128_ps(_mm_set1_epi32(0x80000000)); + const __m128 ps_ffffffff = _mm_castsi128_ps(_mm_set1_epi32(0xffffffff)); + + __forceinline __m128 _mm_neg_ps(__m128 r) + { + return _mm_xor_ps(ps_80000000, r); + } + + __forceinline __m128 _mm_abs_ps(__m128 r) + { + return _mm_and_ps(ps_7fffffff, r); + } + + #define _MM_TRANSPOSE4_SI128(row0, row1, row2, row3) \ + { \ + __m128 tmp0 = _mm_shuffle_ps(_mm_castsi128_ps(row0), _mm_castsi128_ps(row1), 0x44); \ + __m128 tmp2 = _mm_shuffle_ps(_mm_castsi128_ps(row0), _mm_castsi128_ps(row1), 0xEE); \ + __m128 tmp1 = _mm_shuffle_ps(_mm_castsi128_ps(row2), _mm_castsi128_ps(row3), 0x44); \ + __m128 tmp3 = _mm_shuffle_ps(_mm_castsi128_ps(row2), _mm_castsi128_ps(row3), 0xEE); \ + (row0) = _mm_castps_si128(_mm_shuffle_ps(tmp0, tmp1, 0x88)); \ + (row1) = _mm_castps_si128(_mm_shuffle_ps(tmp0, tmp1, 0xDD)); \ + (row2) = _mm_castps_si128(_mm_shuffle_ps(tmp2, tmp3, 0x88)); \ + (row3) = _mm_castps_si128(_mm_shuffle_ps(tmp2, tmp3, 0xDD)); \ + } + + __forceinline __m128 _mm_rcpnr_ps(__m128 r) + { + __m128 t = _mm_rcp_ps(r); + + return _mm_sub_ps(_mm_add_ps(t, t), _mm_mul_ps(_mm_mul_ps(t, t), r)); + } + + +#else + +#error TODO: GSVector4 and GSRasterizer needs SSE2 + +#endif + +// sse3 + +#if _M_SSE >= 0x301 + + #include + +#endif + +// sse4 + +#if _M_SSE >= 0x401 + + #include + +#else + + // not an equal replacement for sse4's blend but for our needs it is ok + + #define _mm_blendv_ps(a, b, mask) _mm_or_ps(_mm_andnot_ps(mask, a), _mm_and_ps(mask, b)) + #define _mm_blendv_epi8(a, b, mask) _mm_or_si128(_mm_andnot_si128(mask, a), _mm_and_si128(mask, b)) + + __forceinline __m128 _mm_round_ps(__m128 x) + { + __m128 t = _mm_or_ps(_mm_and_ps(ps_80000000, x), ps_4b000000); + + return _mm_sub_ps(_mm_add_ps(x, t), t); + } + + __forceinline __m128 _mm_floor_ps(__m128 x) + { + __m128 t = _mm_round_ps(x); + + return _mm_sub_ps(t, _mm_and_ps(_mm_cmplt_ps(x, t), ps_3f800000)); + } + + __forceinline __m128 _mm_ceil_ps(__m128 x) + { + __m128 t = _mm_round_ps(x); + + return _mm_add_ps(t, _mm_and_ps(_mm_cmpgt_ps(x, t), ps_3f800000)); + } + +#endif diff --git a/plugins/GSdx/stdafx.cpp b/plugins/GSdx/stdafx.cpp index 3832007ce8..bda8426831 100644 --- a/plugins/GSdx/stdafx.cpp +++ b/plugins/GSdx/stdafx.cpp @@ -1,8 +1,8 @@ -// stdafx.cpp : source file that includes just the standard includes -// GSdx.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" - -// TODO: reference any additional headers you need in STDAFX.H -// and not in this file +// stdafx.cpp : source file that includes just the standard includes +// GSdx.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/plugins/GSdx/stdafx.h b/plugins/GSdx/stdafx.h index 7a3b2d9fd4..826f5a6029 100644 --- a/plugins/GSdx/stdafx.h +++ b/plugins/GSdx/stdafx.h @@ -1,107 +1,107 @@ -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, but -// are changed infrequently - -#pragma once - -#pragma warning(disable: 4996) - -#ifndef VC_EXTRALEAN -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers -#endif - -// Modify the following defines if you have to target a platform prior to the ones specified below. -// Refer to MSDN for the latest info on corresponding values for different platforms. -#ifndef WINVER // Allow use of features specific to Windows 95 and Windows NT 4 or later. -#define WINVER 0x0510 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later. -#endif - -#ifndef _WIN32_WINNT // Allow use of features specific to Windows NT 4 or later. -#define _WIN32_WINNT 0x0400 // Change this to the appropriate value to target Windows 2000 or later. -#endif - -#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later. -#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. -#endif - -#ifndef _WIN32_IE // Allow use of features specific to IE 4.0 or later. -#define _WIN32_IE 0x0400 // Change this to the appropriate value to target IE 5.0 or later. -#endif - -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit - -#include // MFC core and standard components -//#include // MFC extensions -#ifndef _AFX_NO_AFXCMN_SUPPORT -#include // MFC support for Windows Common Controls -#endif // _AFX_NO_AFXCMN_SUPPORT -//#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if !defined(_M_SSE) && (defined(_M_AMD64) || defined(_M_IX86_FP) && _M_IX86_FP >= 2) -#define _M_SSE 0x200 -#endif - -#include "sse.h" - -#define countof(a) (sizeof(a)/sizeof(a[0])) - -#define EXPORT_C extern "C" __declspec(dllexport) void __stdcall -#define EXPORT_C_(type) extern "C" __declspec(dllexport) type __stdcall - -#ifndef RESTRICT - #ifdef __INTEL_COMPILER - #define RESTRICT restrict - #elif _MSC_VER >= 1400 - #define RESTRICT __restrict - #else - #define RESTRICT - #endif -#endif - -#pragma warning(disable : 4995 4324 4100) - -#define D3DCOLORWRITEENABLE_RGB (D3DCOLORWRITEENABLE_RED|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_BLUE) -#define D3DCOLORWRITEENABLE_RGBA (D3DCOLORWRITEENABLE_RGB|D3DCOLORWRITEENABLE_ALPHA) - -#define QI(i) (riid == __uuidof(i)) ? GetInterface((i*)this, ppv) : - -template class CRBMapC : public CRBMap -{ - // CRBMap + a cache for the last value (simple, but already a lot better) - - CPair* m_pair; - -public: - CRBMapC() : m_pair(NULL) {} - - CPair* Lookup(KINARGTYPE key) - { - if(m_pair && key == m_pair->m_key) - { - return m_pair; - } - - m_pair = __super::Lookup(key); - - return m_pair; - } - - POSITION SetAt(KINARGTYPE key, VINARGTYPE value) - { - POSITION pos = __super::SetAt(key, value); - - m_pair = __super::GetAt(pos); - - return pos; - } -}; - +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently + +#pragma once + +#pragma warning(disable: 4996) + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers +#endif + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef WINVER // Allow use of features specific to Windows 95 and Windows NT 4 or later. +#define WINVER 0x0510 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later. +#endif + +#ifndef _WIN32_WINNT // Allow use of features specific to Windows NT 4 or later. +#define _WIN32_WINNT 0x0400 // Change this to the appropriate value to target Windows 2000 or later. +#endif + +#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later. +#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. +#endif + +#ifndef _WIN32_IE // Allow use of features specific to IE 4.0 or later. +#define _WIN32_IE 0x0400 // Change this to the appropriate value to target IE 5.0 or later. +#endif + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit + +#include // MFC core and standard components +//#include // MFC extensions +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(_M_SSE) && (defined(_M_AMD64) || defined(_M_IX86_FP) && _M_IX86_FP >= 2) +#define _M_SSE 0x200 +#endif + +#include "sse.h" + +#define countof(a) (sizeof(a)/sizeof(a[0])) + +#define EXPORT_C extern "C" __declspec(dllexport) void __stdcall +#define EXPORT_C_(type) extern "C" __declspec(dllexport) type __stdcall + +#ifndef RESTRICT + #ifdef __INTEL_COMPILER + #define RESTRICT restrict + #elif _MSC_VER >= 1400 + #define RESTRICT __restrict + #else + #define RESTRICT + #endif +#endif + +#pragma warning(disable : 4995 4324 4100) + +#define D3DCOLORWRITEENABLE_RGB (D3DCOLORWRITEENABLE_RED|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_BLUE) +#define D3DCOLORWRITEENABLE_RGBA (D3DCOLORWRITEENABLE_RGB|D3DCOLORWRITEENABLE_ALPHA) + +#define QI(i) (riid == __uuidof(i)) ? GetInterface((i*)this, ppv) : + +template class CRBMapC : public CRBMap +{ + // CRBMap + a cache for the last value (simple, but already a lot better) + + CPair* m_pair; + +public: + CRBMapC() : m_pair(NULL) {} + + CPair* Lookup(KINARGTYPE key) + { + if(m_pair && key == m_pair->m_key) + { + return m_pair; + } + + m_pair = __super::Lookup(key); + + return m_pair; + } + + POSITION SetAt(KINARGTYPE key, VINARGTYPE value) + { + POSITION pos = __super::SetAt(key, value); + + m_pair = __super::GetAt(pos); + + return pos; + } +}; + diff --git a/plugins/GSdx/svnrev_template.h b/plugins/GSdx/svnrev_template.h index 678f7916d3..c8806d96ae 100644 --- a/plugins/GSdx/svnrev_template.h +++ b/plugins/GSdx/svnrev_template.h @@ -1,2 +1,2 @@ -#define SVN_REV $WCREV$ +#define SVN_REV $WCREV$ #define SVN_MODS $WCMODS?1:0$ \ No newline at end of file diff --git a/plugins/PeopsSPU2/Makefile b/plugins/PeopsSPU2/Makefile index 0b5a12f97e..685c267710 100644 --- a/plugins/PeopsSPU2/Makefile +++ b/plugins/PeopsSPU2/Makefile @@ -1,75 +1,75 @@ -############################################################################## -# MAKEFILE FOR THE PEOPS OSS SPU2... just run "make" -############################################################################## - -############################################################################## -# 1. SETS (CCFLAGS3 is used) -############################################################################## -all: spu2PeopsOSS -install: all - -# Set to TRUE to build the ALSA support -USEALSA = FALSE -# Set to TRUE to disable the thread library support - helpful for some Linux distros -NOTHREADLIB = FALSE - -############################################################################## - -CC = gcc -CCFLAGS1 = -fPIC -c -Wall -O3 -CCFLAGS2 = -fPIC -c -Wall -O2 -ffast-math -CCFLAGS3 = -fPIC -c -Wall -O3 -ffast-math -fomit-frame-pointer - -INCLUDE = -LINK = gcc -OBJ = spu.o dma.o freeze.o registers.o -LIB = -lc -lm - -ifeq ($(USEALSA), TRUE) - OBJ+= alsa.o - LIB+= -lasound - LINKFLAGS = -shared -Wl,-soname,libspu2PeopsALSA.so -o libspu2PeopsALSA.so.1.0.3 - CCFLAGS3+= -DUSEALSA -else - OBJ+= oss.o - LINKFLAGS = -shared -Wl,-soname,libspu2PeopsOSS.so.1.6 -fPIC -fomit-frame-pointer -o libspu2PeopsOSS.so.1.6 -endif - -ifeq ($(NOTHREADLIB), TRUE) - CCFLAGS3+= -DNOTHREADLIB -else - LIB+= -lpthread -endif - - - -############################################################################## -# 2. MAIN RULE -############################################################################## - -spu2PeopsOSS : $(OBJ) - $(LINK) $(LINKFLAGS) $(OBJ) $(LIB) - -############################################################################## -# 3. GENERAL RULES -############################################################################## - -%.o : %.c - $(CC) $(CCFLAGS3) $(INCLUDE) $< - -############################################################################## -# 4. SPECIFIC RULES -############################################################################## - -spu.o : spu.c stdafx.h externals.h cfg.h dsoundoss.h regs.h debug.h xa.c reverb.c adsr.c -cfg.o : stdafx.h externals.h -dma.o : dma.c stdafx.h externals.h -freeze.o : freeze.c stdafx.h externals.h registers.h spu.h regs.h -oss.o : oss.c stdafx.h externals.h -alsa.o : alsa.h stdafx.h externals.h -registers.o : registers.c stdafx.h externals.h registers.h regs.h reverb.h - -.PHONY: clean spu2PeopsOSS - -clean: - rm -f *.o *.so.* +############################################################################## +# MAKEFILE FOR THE PEOPS OSS SPU2... just run "make" +############################################################################## + +############################################################################## +# 1. SETS (CCFLAGS3 is used) +############################################################################## +all: spu2PeopsOSS +install: all + +# Set to TRUE to build the ALSA support +USEALSA = FALSE +# Set to TRUE to disable the thread library support - helpful for some Linux distros +NOTHREADLIB = FALSE + +############################################################################## + +CC = gcc +CCFLAGS1 = -fPIC -c -Wall -O3 +CCFLAGS2 = -fPIC -c -Wall -O2 -ffast-math +CCFLAGS3 = -fPIC -c -Wall -O3 -ffast-math -fomit-frame-pointer + +INCLUDE = +LINK = gcc +OBJ = spu.o dma.o freeze.o registers.o +LIB = -lc -lm + +ifeq ($(USEALSA), TRUE) + OBJ+= alsa.o + LIB+= -lasound + LINKFLAGS = -shared -Wl,-soname,libspu2PeopsALSA.so -o libspu2PeopsALSA.so.1.0.3 + CCFLAGS3+= -DUSEALSA +else + OBJ+= oss.o + LINKFLAGS = -shared -Wl,-soname,libspu2PeopsOSS.so.1.6 -fPIC -fomit-frame-pointer -o libspu2PeopsOSS.so.1.6 +endif + +ifeq ($(NOTHREADLIB), TRUE) + CCFLAGS3+= -DNOTHREADLIB +else + LIB+= -lpthread +endif + + + +############################################################################## +# 2. MAIN RULE +############################################################################## + +spu2PeopsOSS : $(OBJ) + $(LINK) $(LINKFLAGS) $(OBJ) $(LIB) + +############################################################################## +# 3. GENERAL RULES +############################################################################## + +%.o : %.c + $(CC) $(CCFLAGS3) $(INCLUDE) $< + +############################################################################## +# 4. SPECIFIC RULES +############################################################################## + +spu.o : spu.c stdafx.h externals.h cfg.h dsoundoss.h regs.h debug.h xa.c reverb.c adsr.c +cfg.o : stdafx.h externals.h +dma.o : dma.c stdafx.h externals.h +freeze.o : freeze.c stdafx.h externals.h registers.h spu.h regs.h +oss.o : oss.c stdafx.h externals.h +alsa.o : alsa.h stdafx.h externals.h +registers.o : registers.c stdafx.h externals.h registers.h regs.h reverb.h + +.PHONY: clean spu2PeopsOSS + +clean: + rm -f *.o *.so.* diff --git a/plugins/PeopsSPU2/adsr.c b/plugins/PeopsSPU2/adsr.c index dabeb4296e..88dc30245a 100644 --- a/plugins/PeopsSPU2/adsr.c +++ b/plugins/PeopsSPU2/adsr.c @@ -1,668 +1,668 @@ -/*************************************************************************** - adsr.c - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2003/05/14 - xodnizel -// - removed stopping of reverb on sample end -// -// 2003/01/06 - Pete -// - added Neill's ADSR timings -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -#include "stdafx.h" - -#define _IN_ADSR - -// will be included from spu.c -#ifdef _IN_SPU - -//////////////////////////////////////////////////////////////////////// -// ADSR func -//////////////////////////////////////////////////////////////////////// - -unsigned long RateTable[160]; - -void InitADSR(void) // INIT ADSR -{ - unsigned long r,rs,rd;int i; - - memset(RateTable,0,sizeof(unsigned long)*160); // build the rate table according to Neill's rules (see at bottom of file) - - r=3;rs=1;rd=0; - - for(i=32;i<160;i++) // we start at pos 32 with the real values... everything before is 0 - { - if(r<0x3FFFFFFF) - { - r+=rs; - rd++;if(rd==5) {rd=1;rs*=2;} - } - if(r>0x3FFFFFFF) r=0x3FFFFFFF; - - RateTable[i]=r; - } -} - -//////////////////////////////////////////////////////////////////////// - -INLINE void StartADSR(int ch) // MIX ADSR -{ - s_chan[ch].ADSRX.lVolume=1; // and init some adsr vars - s_chan[ch].ADSRX.State=0; - s_chan[ch].ADSRX.EnvelopeVol=0; -} - -//////////////////////////////////////////////////////////////////////// - -INLINE int MixADSR(int ch) // MIX ADSR -{ - if(s_chan[ch].bStop) // should be stopped: - { - if(s_chan[ch].bIgnoreLoop==0){ - s_chan[ch].ADSRX.EnvelopeVol=0; - s_chan[ch].bOn=0; - s_chan[ch].pStart= NULL; //FFX U and E need this else the speech never ends - s_chan[ch].pLoop= s_chan[ch].pCurr; //FFX J needs this else speech never plays :P - s_chan[ch].bStop=1; - s_chan[ch].bIgnoreLoop=0; - return 0; - } - if(s_chan[ch].ADSRX.ReleaseModeExp)// do release - { - switch((s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7) - { - case 0: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +0 + 32]; break; - case 1: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +4 + 32]; break; - case 2: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +6 + 32]; break; - case 3: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +8 + 32]; break; - case 4: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +9 + 32]; break; - case 5: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +10+ 32]; break; - case 6: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +11+ 32]; break; - case 7: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +12+ 32]; break; - } - } - else - { - s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x0C + 32]; - } - - if(s_chan[ch].ADSRX.EnvelopeVol<0) - { - s_chan[ch].ADSRX.EnvelopeVol=0; - s_chan[ch].bOn=0; - s_chan[ch].bStop=1; - s_chan[ch].bIgnoreLoop=0; - //s_chan[ch].bReverb=0; - //s_chan[ch].bNoise=0; - } - - s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; - s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; - return s_chan[ch].ADSRX.lVolume; - } - else // not stopped yet? - { - if(s_chan[ch].ADSRX.State==0) // -> attack - { - if(s_chan[ch].ADSRX.AttackModeExp) - { - if(s_chan[ch].ADSRX.EnvelopeVol<0x60000000) - s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x10 + 32]; - else - s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x18 + 32]; - } - else - { - s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x10 + 32]; - } - - if(s_chan[ch].ADSRX.EnvelopeVol<0) - { - s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF; - s_chan[ch].ADSRX.State=1; - } - - s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; - return s_chan[ch].ADSRX.lVolume; - } - //--------------------------------------------------// - if(s_chan[ch].ADSRX.State==1) // -> decay - { - switch((s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7) - { - case 0: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+0 + 32]; break; - case 1: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+4 + 32]; break; - case 2: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+6 + 32]; break; - case 3: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+8 + 32]; break; - case 4: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+9 + 32]; break; - case 5: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+10+ 32]; break; - case 6: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+11+ 32]; break; - case 7: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+12+ 32]; break; - } - - if(s_chan[ch].ADSRX.EnvelopeVol<0) s_chan[ch].ADSRX.EnvelopeVol=0; - if(((s_chan[ch].ADSRX.EnvelopeVol>>27)&0xF) <= s_chan[ch].ADSRX.SustainLevel) - { - s_chan[ch].ADSRX.State=2; - } - - s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; - return s_chan[ch].ADSRX.lVolume; - } - //--------------------------------------------------// - if(s_chan[ch].ADSRX.State==2) // -> sustain - { - if(s_chan[ch].ADSRX.SustainIncrease) - { - if(s_chan[ch].ADSRX.SustainModeExp) - { - if(s_chan[ch].ADSRX.EnvelopeVol<0x60000000) - s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x10 + 32]; - else - s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x18 + 32]; - } - else - { - s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x10 + 32]; - } - - if(s_chan[ch].ADSRX.EnvelopeVol<0) - { - s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF; - } - } - else - { - if(s_chan[ch].ADSRX.SustainModeExp) - { - switch((s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7) - { - case 0: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +0 + 32];break; - case 1: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +4 + 32];break; - case 2: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +6 + 32];break; - case 3: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +8 + 32];break; - case 4: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +9 + 32];break; - case 5: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +10+ 32];break; - case 6: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +11+ 32];break; - case 7: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +12+ 32];break; - } - } - else - { - s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x0F + 32]; - } - - if(s_chan[ch].ADSRX.EnvelopeVol<0) - { - s_chan[ch].ADSRX.EnvelopeVol=0; - } - } - s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; - return s_chan[ch].ADSRX.lVolume; - } - } - return 0; -} - -#endif - -/* -James Higgs ADSR investigations: - -PSX SPU Envelope Timings -~~~~~~~~~~~~~~~~~~~~~~~~ - -First, here is an extract from doomed's SPU doc, which explains the basics -of the SPU "volume envelope": - -*** doomed doc extract start *** - --------------------------------------------------------------------------- -Voices. --------------------------------------------------------------------------- -The SPU has 24 hardware voices. These voices can be used to reproduce sample -data, noise or can be used as frequency modulator on the next voice. -Each voice has it's own programmable ADSR envelope filter. The main volume -can be programmed independently for left and right output. - -The ADSR envelope filter works as follows: -Ar = Attack rate, which specifies the speed at which the volume increases - from zero to it's maximum value, as soon as the note on is given. The - slope can be set to lineair or exponential. -Dr = Decay rate specifies the speed at which the volume decreases to the - sustain level. Decay is always decreasing exponentially. -Sl = Sustain level, base level from which sustain starts. -Sr = Sustain rate is the rate at which the volume of the sustained note - increases or decreases. This can be either lineair or exponential. -Rr = Release rate is the rate at which the volume of the note decreases - as soon as the note off is given. - - lvl | - ^ | /\Dr __ - Sl _| _ / _ \__--- \ - | / ---__ \ Rr - | /Ar Sr \ \ - | / \\ - |/___________________\________ - ->time - -The overal volume can also be set to sweep up or down lineairly or -exponentially from it's current value. This can be done seperately -for left and right. - -Relevant SPU registers: -------------------------------------------------------------- -$1f801xx8 Attack/Decay/Sustain level -bit |0f|0e 0d 0c 0b 0a 09 08|07 06 05 04|03 02 01 00| -desc.|Am| Ar |Dr |Sl | - -Am 0 Attack mode Linear - 1 Exponential - -Ar 0-7f attack rate -Dr 0-f decay rate -Sl 0-f sustain level -------------------------------------------------------------- -$1f801xxa Sustain rate, Release Rate. -bit |0f|0e|0d|0c 0b 0a 09 08 07 06|05|04 03 02 01 00| -desc.|Sm|Sd| 0| Sr |Rm|Rr | - -Sm 0 sustain rate mode linear - 1 exponential -Sd 0 sustain rate mode increase - 1 decrease -Sr 0-7f Sustain Rate -Rm 0 Linear decrease - 1 Exponential decrease -Rr 0-1f Release Rate - -Note: decay mode is always Expontial decrease, and thus cannot -be set. -------------------------------------------------------------- -$1f801xxc Current ADSR volume -bit |0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00| -desc.|ADSRvol | - -ADSRvol Returns the current envelope volume when - read. --- James' Note: return range: 0 -> 32767 - -*** doomed doc extract end *** - -By using a small PSX proggie to visualise the envelope as it was played, -the following results for envelope timing were obtained: - -1. Attack rate value (linear mode) - - Attack value range: 0 -> 127 - - Value | 48 | 52 | 56 | 60 | 64 | 68 | 72 | | 80 | - ----------------------------------------------------------------- - Frames | 11 | 21 | 42 | 84 | 169| 338| 676| |2890| - - Note: frames is no. of PAL frames to reach full volume (100% - amplitude) - - Hmm, noticing that the time taken to reach full volume doubles - every time we add 4 to our attack value, we know the equation is - of form: - frames = k * 2 ^ (value / 4) - - (You may ponder about envelope generator hardware at this point, - or maybe not... :) - - By substituting some stuff and running some checks, we get: - - k = 0.00257 (close enuf) - - therefore, - frames = 0.00257 * 2 ^ (value / 4) - If you just happen to be writing an emulator, then you can probably - use an equation like: - - %volume_increase_per_tick = 1 / frames - - - ------------------------------------ - Pete: - ms=((1<<(value>>2))*514)/10000 - ------------------------------------ - -2. Decay rate value (only has log mode) - - Decay value range: 0 -> 15 - - Value | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | - ------------------------------------------------ - frames | | | | | 6 | 12 | 24 | 47 | - - Note: frames here is no. of PAL frames to decay to 50% volume. - - formula: frames = k * 2 ^ (value) - - Substituting, we get: k = 0.00146 - - Further info on logarithmic nature: - frames to decay to sustain level 3 = 3 * frames to decay to - sustain level 9 - - Also no. of frames to 25% volume = roughly 1.85 * no. of frames to - 50% volume. - - Frag it - just use linear approx. - - ------------------------------------ - Pete: - ms=((1< 127 - - Value | 48 | 52 | 56 | 60 | 64 | 68 | 72 | - ------------------------------------------- - frames | 9 | 19 | 37 | 74 | 147| 293| 587| - - Here, frames = no. of PAL frames for volume amplitude to go from 100% - to 0% (or vice-versa). - - Same formula as for attack value, just a different value for k: - - k = 0.00225 - - ie: frames = 0.00225 * 2 ^ (value / 4) - - For emulation purposes: - - %volume_increase_or_decrease_per_tick = 1 / frames - - ------------------------------------ - Pete: - ms=((1<<(value>>2))*450)/10000 - ------------------------------------ - - -4. Release rate (linear mode) - - Release rate range: 0 -> 31 - - Value | 13 | 14 | 15 | 16 | 17 | - --------------------------------------------------------------- - frames | 18 | 36 | 73 | 146| 292| - - Here, frames = no. of PAL frames to decay from 100% vol to 0% vol - after "note-off" is triggered. - - Formula: frames = k * 2 ^ (value) - - And so: k = 0.00223 - - ------------------------------------ - Pete: - ms=((1< release phase - { - if(s_chan[ch].ADSR.ReleaseVal!=0) // -> release not 0: do release (if 0: stop right now) - { - if(!s_chan[ch].ADSR.ReleaseVol) // --> release just started? set up the release stuff - { - s_chan[ch].ADSR.ReleaseStartTime=s_chan[ch].ADSR.lTime; - s_chan[ch].ADSR.ReleaseVol=s_chan[ch].ADSR.lVolume; - s_chan[ch].ADSR.ReleaseTime = // --> calc how long does it take to reach the wanted sus level - (s_chan[ch].ADSR.ReleaseTime* - s_chan[ch].ADSR.ReleaseVol)/1024; - } - // -> NO release exp mode used (yet) - v=s_chan[ch].ADSR.ReleaseVol; // -> get last volume - lT=s_chan[ch].ADSR.lTime- // -> how much time is past? - s_chan[ch].ADSR.ReleaseStartTime; - l1=s_chan[ch].ADSR.ReleaseTime; - - if(lT we still have to release - { - v=v-((v*lT)/l1); // --> calc new volume - } - else // -> release is over: now really stop that sample - {v=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;} - } - else // -> release IS 0: release at once - { - v=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0; - } - } - else - {//--------------------------------------------------// not in release phase: - v=1024; - lT=s_chan[ch].ADSR.lTime; - l1=s_chan[ch].ADSR.AttackTime; - - if(lT0) - { - if(l3!=0) v2+=((v-v2)*lT)/l3; - else v2=v; - } - else - { - if(l3!=0) v2-=(v2*lT)/l3; - else v2=v; - } - - if(v2>v) v2=v; - if(v2<=0) {v2=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;} - - v=v2; - } - } - } - - //----------------------------------------------------// - // ok, done for this channel, so increase time - - s_chan[ch].ADSR.lTime+=1; // 1 = 1.020408f ms; - - if(v>1024) v=1024; // adjust volume - if(v<0) v=0; - s_chan[ch].ADSR.lVolume=v; // store act volume - - return v; // return the volume factor -*/ - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - - -/* ------------------------------------------------------------------------------ -Neill Corlett -Playstation SPU envelope timing notes ------------------------------------------------------------------------------ - -This is preliminary. This may be wrong. But the model described herein fits -all of my experimental data, and it's just simple enough to sound right. - -ADSR envelope level ranges from 0x00000000 to 0x7FFFFFFF internally. -The value returned by channel reg 0xC is (envelope_level>>16). - -Each sample, an increment or decrement value will be added to or -subtracted from this envelope level. - -Create the rate log table. The values double every 4 entries. - entry #0 = 4 - - 4, 5, 6, 7, - 8,10,12,14, - 16,20,24,28, ... - - entry #40 = 4096... - entry #44 = 8192... - entry #48 = 16384... - entry #52 = 32768... - entry #56 = 65536... - -increments and decrements are in terms of ratelogtable[n] -n may exceed the table bounds (plan on n being between -32 and 127). -table values are all clipped between 0x00000000 and 0x3FFFFFFF - -when you "voice on", the envelope is always fully reset. -(yes, it may click. the real thing does this too.) - -envelope level begins at zero. - -each state happens for at least 1 cycle -(transitions are not instantaneous) -this may result in some oddness: if the decay rate is uberfast, it will cut -the envelope from full down to half in one sample, potentially skipping over -the sustain level - -ATTACK ------- -- if the envelope level has overflowed past the max, clip to 0x7FFFFFFF and - proceed to DECAY. - -Linear attack mode: -- line extends upward to 0x7FFFFFFF -- increment per sample is ratelogtable[(Ar^0x7F)-0x10] - -Logarithmic attack mode: -if envelope_level < 0x60000000: - - line extends upward to 0x60000000 - - increment per sample is ratelogtable[(Ar^0x7F)-0x10] -else: - - line extends upward to 0x7FFFFFFF - - increment per sample is ratelogtable[(Ar^0x7F)-0x18] - -DECAY ------ -- if ((envelope_level>>27)&0xF) <= Sl, proceed to SUSTAIN. - Do not clip to the sustain level. -- current line ends at (envelope_level & 0x07FFFFFF) -- decrement per sample depends on (envelope_level>>28)&0x7 - 0: ratelogtable[(4*(Dr^0x1F))-0x18+0] - 1: ratelogtable[(4*(Dr^0x1F))-0x18+4] - 2: ratelogtable[(4*(Dr^0x1F))-0x18+6] - 3: ratelogtable[(4*(Dr^0x1F))-0x18+8] - 4: ratelogtable[(4*(Dr^0x1F))-0x18+9] - 5: ratelogtable[(4*(Dr^0x1F))-0x18+10] - 6: ratelogtable[(4*(Dr^0x1F))-0x18+11] - 7: ratelogtable[(4*(Dr^0x1F))-0x18+12] - (note that this is the same as the release rate formula, except that - decay rates 10-1F aren't possible... those would be slower in theory) - -SUSTAIN -------- -- no terminating condition except for voice off -- Sd=0 (increase) behavior is identical to ATTACK for both log and linear. -- Sd=1 (decrease) behavior: -Linear sustain decrease: -- line extends to 0x00000000 -- decrement per sample is ratelogtable[(Sr^0x7F)-0x0F] -Logarithmic sustain decrease: -- current line ends at (envelope_level & 0x07FFFFFF) -- decrement per sample depends on (envelope_level>>28)&0x7 - 0: ratelogtable[(Sr^0x7F)-0x1B+0] - 1: ratelogtable[(Sr^0x7F)-0x1B+4] - 2: ratelogtable[(Sr^0x7F)-0x1B+6] - 3: ratelogtable[(Sr^0x7F)-0x1B+8] - 4: ratelogtable[(Sr^0x7F)-0x1B+9] - 5: ratelogtable[(Sr^0x7F)-0x1B+10] - 6: ratelogtable[(Sr^0x7F)-0x1B+11] - 7: ratelogtable[(Sr^0x7F)-0x1B+12] - -RELEASE -------- -- if the envelope level has overflowed to negative, clip to 0 and QUIT. - -Linear release mode: -- line extends to 0x00000000 -- decrement per sample is ratelogtable[(4*(Rr^0x1F))-0x0C] - -Logarithmic release mode: -- line extends to (envelope_level & 0x0FFFFFFF) -- decrement per sample depends on (envelope_level>>28)&0x7 - 0: ratelogtable[(4*(Rr^0x1F))-0x18+0] - 1: ratelogtable[(4*(Rr^0x1F))-0x18+4] - 2: ratelogtable[(4*(Rr^0x1F))-0x18+6] - 3: ratelogtable[(4*(Rr^0x1F))-0x18+8] - 4: ratelogtable[(4*(Rr^0x1F))-0x18+9] - 5: ratelogtable[(4*(Rr^0x1F))-0x18+10] - 6: ratelogtable[(4*(Rr^0x1F))-0x18+11] - 7: ratelogtable[(4*(Rr^0x1F))-0x18+12] - ------------------------------------------------------------------------------ -*/ - +/*************************************************************************** + adsr.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/05/14 - xodnizel +// - removed stopping of reverb on sample end +// +// 2003/01/06 - Pete +// - added Neill's ADSR timings +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_ADSR + +// will be included from spu.c +#ifdef _IN_SPU + +//////////////////////////////////////////////////////////////////////// +// ADSR func +//////////////////////////////////////////////////////////////////////// + +unsigned long RateTable[160]; + +void InitADSR(void) // INIT ADSR +{ + unsigned long r,rs,rd;int i; + + memset(RateTable,0,sizeof(unsigned long)*160); // build the rate table according to Neill's rules (see at bottom of file) + + r=3;rs=1;rd=0; + + for(i=32;i<160;i++) // we start at pos 32 with the real values... everything before is 0 + { + if(r<0x3FFFFFFF) + { + r+=rs; + rd++;if(rd==5) {rd=1;rs*=2;} + } + if(r>0x3FFFFFFF) r=0x3FFFFFFF; + + RateTable[i]=r; + } +} + +//////////////////////////////////////////////////////////////////////// + +INLINE void StartADSR(int ch) // MIX ADSR +{ + s_chan[ch].ADSRX.lVolume=1; // and init some adsr vars + s_chan[ch].ADSRX.State=0; + s_chan[ch].ADSRX.EnvelopeVol=0; +} + +//////////////////////////////////////////////////////////////////////// + +INLINE int MixADSR(int ch) // MIX ADSR +{ + if(s_chan[ch].bStop) // should be stopped: + { + if(s_chan[ch].bIgnoreLoop==0){ + s_chan[ch].ADSRX.EnvelopeVol=0; + s_chan[ch].bOn=0; + s_chan[ch].pStart= NULL; //FFX U and E need this else the speech never ends + s_chan[ch].pLoop= s_chan[ch].pCurr; //FFX J needs this else speech never plays :P + s_chan[ch].bStop=1; + s_chan[ch].bIgnoreLoop=0; + return 0; + } + if(s_chan[ch].ADSRX.ReleaseModeExp)// do release + { + switch((s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7) + { + case 0: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +0 + 32]; break; + case 1: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +4 + 32]; break; + case 2: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +6 + 32]; break; + case 3: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +8 + 32]; break; + case 4: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +9 + 32]; break; + case 5: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +10+ 32]; break; + case 6: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +11+ 32]; break; + case 7: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +12+ 32]; break; + } + } + else + { + s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x0C + 32]; + } + + if(s_chan[ch].ADSRX.EnvelopeVol<0) + { + s_chan[ch].ADSRX.EnvelopeVol=0; + s_chan[ch].bOn=0; + s_chan[ch].bStop=1; + s_chan[ch].bIgnoreLoop=0; + //s_chan[ch].bReverb=0; + //s_chan[ch].bNoise=0; + } + + s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; + s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; + return s_chan[ch].ADSRX.lVolume; + } + else // not stopped yet? + { + if(s_chan[ch].ADSRX.State==0) // -> attack + { + if(s_chan[ch].ADSRX.AttackModeExp) + { + if(s_chan[ch].ADSRX.EnvelopeVol<0x60000000) + s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x10 + 32]; + else + s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x18 + 32]; + } + else + { + s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x10 + 32]; + } + + if(s_chan[ch].ADSRX.EnvelopeVol<0) + { + s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF; + s_chan[ch].ADSRX.State=1; + } + + s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; + return s_chan[ch].ADSRX.lVolume; + } + //--------------------------------------------------// + if(s_chan[ch].ADSRX.State==1) // -> decay + { + switch((s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7) + { + case 0: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+0 + 32]; break; + case 1: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+4 + 32]; break; + case 2: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+6 + 32]; break; + case 3: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+8 + 32]; break; + case 4: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+9 + 32]; break; + case 5: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+10+ 32]; break; + case 6: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+11+ 32]; break; + case 7: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+12+ 32]; break; + } + + if(s_chan[ch].ADSRX.EnvelopeVol<0) s_chan[ch].ADSRX.EnvelopeVol=0; + if(((s_chan[ch].ADSRX.EnvelopeVol>>27)&0xF) <= s_chan[ch].ADSRX.SustainLevel) + { + s_chan[ch].ADSRX.State=2; + } + + s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; + return s_chan[ch].ADSRX.lVolume; + } + //--------------------------------------------------// + if(s_chan[ch].ADSRX.State==2) // -> sustain + { + if(s_chan[ch].ADSRX.SustainIncrease) + { + if(s_chan[ch].ADSRX.SustainModeExp) + { + if(s_chan[ch].ADSRX.EnvelopeVol<0x60000000) + s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x10 + 32]; + else + s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x18 + 32]; + } + else + { + s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x10 + 32]; + } + + if(s_chan[ch].ADSRX.EnvelopeVol<0) + { + s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF; + } + } + else + { + if(s_chan[ch].ADSRX.SustainModeExp) + { + switch((s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7) + { + case 0: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +0 + 32];break; + case 1: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +4 + 32];break; + case 2: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +6 + 32];break; + case 3: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +8 + 32];break; + case 4: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +9 + 32];break; + case 5: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +10+ 32];break; + case 6: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +11+ 32];break; + case 7: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +12+ 32];break; + } + } + else + { + s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x0F + 32]; + } + + if(s_chan[ch].ADSRX.EnvelopeVol<0) + { + s_chan[ch].ADSRX.EnvelopeVol=0; + } + } + s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; + return s_chan[ch].ADSRX.lVolume; + } + } + return 0; +} + +#endif + +/* +James Higgs ADSR investigations: + +PSX SPU Envelope Timings +~~~~~~~~~~~~~~~~~~~~~~~~ + +First, here is an extract from doomed's SPU doc, which explains the basics +of the SPU "volume envelope": + +*** doomed doc extract start *** + +-------------------------------------------------------------------------- +Voices. +-------------------------------------------------------------------------- +The SPU has 24 hardware voices. These voices can be used to reproduce sample +data, noise or can be used as frequency modulator on the next voice. +Each voice has it's own programmable ADSR envelope filter. The main volume +can be programmed independently for left and right output. + +The ADSR envelope filter works as follows: +Ar = Attack rate, which specifies the speed at which the volume increases + from zero to it's maximum value, as soon as the note on is given. The + slope can be set to lineair or exponential. +Dr = Decay rate specifies the speed at which the volume decreases to the + sustain level. Decay is always decreasing exponentially. +Sl = Sustain level, base level from which sustain starts. +Sr = Sustain rate is the rate at which the volume of the sustained note + increases or decreases. This can be either lineair or exponential. +Rr = Release rate is the rate at which the volume of the note decreases + as soon as the note off is given. + + lvl | + ^ | /\Dr __ + Sl _| _ / _ \__--- \ + | / ---__ \ Rr + | /Ar Sr \ \ + | / \\ + |/___________________\________ + ->time + +The overal volume can also be set to sweep up or down lineairly or +exponentially from it's current value. This can be done seperately +for left and right. + +Relevant SPU registers: +------------------------------------------------------------- +$1f801xx8 Attack/Decay/Sustain level +bit |0f|0e 0d 0c 0b 0a 09 08|07 06 05 04|03 02 01 00| +desc.|Am| Ar |Dr |Sl | + +Am 0 Attack mode Linear + 1 Exponential + +Ar 0-7f attack rate +Dr 0-f decay rate +Sl 0-f sustain level +------------------------------------------------------------- +$1f801xxa Sustain rate, Release Rate. +bit |0f|0e|0d|0c 0b 0a 09 08 07 06|05|04 03 02 01 00| +desc.|Sm|Sd| 0| Sr |Rm|Rr | + +Sm 0 sustain rate mode linear + 1 exponential +Sd 0 sustain rate mode increase + 1 decrease +Sr 0-7f Sustain Rate +Rm 0 Linear decrease + 1 Exponential decrease +Rr 0-1f Release Rate + +Note: decay mode is always Expontial decrease, and thus cannot +be set. +------------------------------------------------------------- +$1f801xxc Current ADSR volume +bit |0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00| +desc.|ADSRvol | + +ADSRvol Returns the current envelope volume when + read. +-- James' Note: return range: 0 -> 32767 + +*** doomed doc extract end *** + +By using a small PSX proggie to visualise the envelope as it was played, +the following results for envelope timing were obtained: + +1. Attack rate value (linear mode) + + Attack value range: 0 -> 127 + + Value | 48 | 52 | 56 | 60 | 64 | 68 | 72 | | 80 | + ----------------------------------------------------------------- + Frames | 11 | 21 | 42 | 84 | 169| 338| 676| |2890| + + Note: frames is no. of PAL frames to reach full volume (100% + amplitude) + + Hmm, noticing that the time taken to reach full volume doubles + every time we add 4 to our attack value, we know the equation is + of form: + frames = k * 2 ^ (value / 4) + + (You may ponder about envelope generator hardware at this point, + or maybe not... :) + + By substituting some stuff and running some checks, we get: + + k = 0.00257 (close enuf) + + therefore, + frames = 0.00257 * 2 ^ (value / 4) + If you just happen to be writing an emulator, then you can probably + use an equation like: + + %volume_increase_per_tick = 1 / frames + + + ------------------------------------ + Pete: + ms=((1<<(value>>2))*514)/10000 + ------------------------------------ + +2. Decay rate value (only has log mode) + + Decay value range: 0 -> 15 + + Value | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | + ------------------------------------------------ + frames | | | | | 6 | 12 | 24 | 47 | + + Note: frames here is no. of PAL frames to decay to 50% volume. + + formula: frames = k * 2 ^ (value) + + Substituting, we get: k = 0.00146 + + Further info on logarithmic nature: + frames to decay to sustain level 3 = 3 * frames to decay to + sustain level 9 + + Also no. of frames to 25% volume = roughly 1.85 * no. of frames to + 50% volume. + + Frag it - just use linear approx. + + ------------------------------------ + Pete: + ms=((1< 127 + + Value | 48 | 52 | 56 | 60 | 64 | 68 | 72 | + ------------------------------------------- + frames | 9 | 19 | 37 | 74 | 147| 293| 587| + + Here, frames = no. of PAL frames for volume amplitude to go from 100% + to 0% (or vice-versa). + + Same formula as for attack value, just a different value for k: + + k = 0.00225 + + ie: frames = 0.00225 * 2 ^ (value / 4) + + For emulation purposes: + + %volume_increase_or_decrease_per_tick = 1 / frames + + ------------------------------------ + Pete: + ms=((1<<(value>>2))*450)/10000 + ------------------------------------ + + +4. Release rate (linear mode) + + Release rate range: 0 -> 31 + + Value | 13 | 14 | 15 | 16 | 17 | + --------------------------------------------------------------- + frames | 18 | 36 | 73 | 146| 292| + + Here, frames = no. of PAL frames to decay from 100% vol to 0% vol + after "note-off" is triggered. + + Formula: frames = k * 2 ^ (value) + + And so: k = 0.00223 + + ------------------------------------ + Pete: + ms=((1< release phase + { + if(s_chan[ch].ADSR.ReleaseVal!=0) // -> release not 0: do release (if 0: stop right now) + { + if(!s_chan[ch].ADSR.ReleaseVol) // --> release just started? set up the release stuff + { + s_chan[ch].ADSR.ReleaseStartTime=s_chan[ch].ADSR.lTime; + s_chan[ch].ADSR.ReleaseVol=s_chan[ch].ADSR.lVolume; + s_chan[ch].ADSR.ReleaseTime = // --> calc how long does it take to reach the wanted sus level + (s_chan[ch].ADSR.ReleaseTime* + s_chan[ch].ADSR.ReleaseVol)/1024; + } + // -> NO release exp mode used (yet) + v=s_chan[ch].ADSR.ReleaseVol; // -> get last volume + lT=s_chan[ch].ADSR.lTime- // -> how much time is past? + s_chan[ch].ADSR.ReleaseStartTime; + l1=s_chan[ch].ADSR.ReleaseTime; + + if(lT we still have to release + { + v=v-((v*lT)/l1); // --> calc new volume + } + else // -> release is over: now really stop that sample + {v=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;} + } + else // -> release IS 0: release at once + { + v=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0; + } + } + else + {//--------------------------------------------------// not in release phase: + v=1024; + lT=s_chan[ch].ADSR.lTime; + l1=s_chan[ch].ADSR.AttackTime; + + if(lT0) + { + if(l3!=0) v2+=((v-v2)*lT)/l3; + else v2=v; + } + else + { + if(l3!=0) v2-=(v2*lT)/l3; + else v2=v; + } + + if(v2>v) v2=v; + if(v2<=0) {v2=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;} + + v=v2; + } + } + } + + //----------------------------------------------------// + // ok, done for this channel, so increase time + + s_chan[ch].ADSR.lTime+=1; // 1 = 1.020408f ms; + + if(v>1024) v=1024; // adjust volume + if(v<0) v=0; + s_chan[ch].ADSR.lVolume=v; // store act volume + + return v; // return the volume factor +*/ + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + + +/* +----------------------------------------------------------------------------- +Neill Corlett +Playstation SPU envelope timing notes +----------------------------------------------------------------------------- + +This is preliminary. This may be wrong. But the model described herein fits +all of my experimental data, and it's just simple enough to sound right. + +ADSR envelope level ranges from 0x00000000 to 0x7FFFFFFF internally. +The value returned by channel reg 0xC is (envelope_level>>16). + +Each sample, an increment or decrement value will be added to or +subtracted from this envelope level. + +Create the rate log table. The values double every 4 entries. + entry #0 = 4 + + 4, 5, 6, 7, + 8,10,12,14, + 16,20,24,28, ... + + entry #40 = 4096... + entry #44 = 8192... + entry #48 = 16384... + entry #52 = 32768... + entry #56 = 65536... + +increments and decrements are in terms of ratelogtable[n] +n may exceed the table bounds (plan on n being between -32 and 127). +table values are all clipped between 0x00000000 and 0x3FFFFFFF + +when you "voice on", the envelope is always fully reset. +(yes, it may click. the real thing does this too.) + +envelope level begins at zero. + +each state happens for at least 1 cycle +(transitions are not instantaneous) +this may result in some oddness: if the decay rate is uberfast, it will cut +the envelope from full down to half in one sample, potentially skipping over +the sustain level + +ATTACK +------ +- if the envelope level has overflowed past the max, clip to 0x7FFFFFFF and + proceed to DECAY. + +Linear attack mode: +- line extends upward to 0x7FFFFFFF +- increment per sample is ratelogtable[(Ar^0x7F)-0x10] + +Logarithmic attack mode: +if envelope_level < 0x60000000: + - line extends upward to 0x60000000 + - increment per sample is ratelogtable[(Ar^0x7F)-0x10] +else: + - line extends upward to 0x7FFFFFFF + - increment per sample is ratelogtable[(Ar^0x7F)-0x18] + +DECAY +----- +- if ((envelope_level>>27)&0xF) <= Sl, proceed to SUSTAIN. + Do not clip to the sustain level. +- current line ends at (envelope_level & 0x07FFFFFF) +- decrement per sample depends on (envelope_level>>28)&0x7 + 0: ratelogtable[(4*(Dr^0x1F))-0x18+0] + 1: ratelogtable[(4*(Dr^0x1F))-0x18+4] + 2: ratelogtable[(4*(Dr^0x1F))-0x18+6] + 3: ratelogtable[(4*(Dr^0x1F))-0x18+8] + 4: ratelogtable[(4*(Dr^0x1F))-0x18+9] + 5: ratelogtable[(4*(Dr^0x1F))-0x18+10] + 6: ratelogtable[(4*(Dr^0x1F))-0x18+11] + 7: ratelogtable[(4*(Dr^0x1F))-0x18+12] + (note that this is the same as the release rate formula, except that + decay rates 10-1F aren't possible... those would be slower in theory) + +SUSTAIN +------- +- no terminating condition except for voice off +- Sd=0 (increase) behavior is identical to ATTACK for both log and linear. +- Sd=1 (decrease) behavior: +Linear sustain decrease: +- line extends to 0x00000000 +- decrement per sample is ratelogtable[(Sr^0x7F)-0x0F] +Logarithmic sustain decrease: +- current line ends at (envelope_level & 0x07FFFFFF) +- decrement per sample depends on (envelope_level>>28)&0x7 + 0: ratelogtable[(Sr^0x7F)-0x1B+0] + 1: ratelogtable[(Sr^0x7F)-0x1B+4] + 2: ratelogtable[(Sr^0x7F)-0x1B+6] + 3: ratelogtable[(Sr^0x7F)-0x1B+8] + 4: ratelogtable[(Sr^0x7F)-0x1B+9] + 5: ratelogtable[(Sr^0x7F)-0x1B+10] + 6: ratelogtable[(Sr^0x7F)-0x1B+11] + 7: ratelogtable[(Sr^0x7F)-0x1B+12] + +RELEASE +------- +- if the envelope level has overflowed to negative, clip to 0 and QUIT. + +Linear release mode: +- line extends to 0x00000000 +- decrement per sample is ratelogtable[(4*(Rr^0x1F))-0x0C] + +Logarithmic release mode: +- line extends to (envelope_level & 0x0FFFFFFF) +- decrement per sample depends on (envelope_level>>28)&0x7 + 0: ratelogtable[(4*(Rr^0x1F))-0x18+0] + 1: ratelogtable[(4*(Rr^0x1F))-0x18+4] + 2: ratelogtable[(4*(Rr^0x1F))-0x18+6] + 3: ratelogtable[(4*(Rr^0x1F))-0x18+8] + 4: ratelogtable[(4*(Rr^0x1F))-0x18+9] + 5: ratelogtable[(4*(Rr^0x1F))-0x18+10] + 6: ratelogtable[(4*(Rr^0x1F))-0x18+11] + 7: ratelogtable[(4*(Rr^0x1F))-0x18+12] + +----------------------------------------------------------------------------- +*/ + diff --git a/plugins/PeopsSPU2/adsr.h b/plugins/PeopsSPU2/adsr.h index 777a0d84c0..8f3ea505fd 100644 --- a/plugins/PeopsSPU2/adsr.h +++ b/plugins/PeopsSPU2/adsr.h @@ -1,28 +1,28 @@ -/*************************************************************************** - adsr.h - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -INLINE void StartADSR(int ch); -INLINE int MixADSR(int ch); +/*************************************************************************** + adsr.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +INLINE void StartADSR(int ch); +INLINE int MixADSR(int ch); diff --git a/plugins/PeopsSPU2/alsa.h b/plugins/PeopsSPU2/alsa.h index 4ea9e2140b..d003e447cd 100644 --- a/plugins/PeopsSPU2/alsa.h +++ b/plugins/PeopsSPU2/alsa.h @@ -1,30 +1,30 @@ -/*************************************************************************** - alsa.h - description - ------------------- - begin : Sat Mar 01 2003 +/*************************************************************************** + alsa.h - description + ------------------- + begin : Sat Mar 01 2003 copyright : (C) 2002 by Pete Bernert email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. * - * * - ***************************************************************************/ - - -#ifndef _ALSA_SOUND_H -#define _ALSA_SOUND_H - -#ifdef ALSA_MEM_DEF -#define ALSA_MEM_EXTERN -#else -#define ALSA_MEM_EXTERN extern -#endif - -ALSA_MEM_EXTERN int sound_buffer_size; - -#endif // _ALSA_SOUND_H + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + + +#ifndef _ALSA_SOUND_H +#define _ALSA_SOUND_H + +#ifdef ALSA_MEM_DEF +#define ALSA_MEM_EXTERN +#else +#define ALSA_MEM_EXTERN extern +#endif + +ALSA_MEM_EXTERN int sound_buffer_size; + +#endif // _ALSA_SOUND_H diff --git a/plugins/PeopsSPU2/cfg.c b/plugins/PeopsSPU2/cfg.c index 2ccefbede4..c4a08fa8d4 100644 --- a/plugins/PeopsSPU2/cfg.c +++ b/plugins/PeopsSPU2/cfg.c @@ -1,256 +1,256 @@ -/*************************************************************************** - cfg.c - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2004/04/04 - Pete -// - changed plugin to emulate PS2 spu -// -// 2003/06/07 - Pete -// - added Linux NOTHREADLIB define -// -// 2003/02/28 - Pete -// - added option for kode54's interpolation and linuzappz's mono mode -// -// 2003/01/19 - Pete -// - added Neill's reverb -// -// 2002/08/04 - Pete -// - small linux bug fix: now the cfg file can be in the main emu directory as well -// -// 2002/06/08 - linuzappz -// - Added combo str for SPUasync, and MAXMODE is now defined as 2 -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -#include "stdafx.h" - -#define _IN_CFG - -#include "externals.h" - -//////////////////////////////////////////////////////////////////////// -// WINDOWS CONFIG/ABOUT HANDLING -//////////////////////////////////////////////////////////////////////// - -#include "resource.h" - -//////////////////////////////////////////////////////////////////////// -// simple about dlg handler -//////////////////////////////////////////////////////////////////////// - -BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch(uMsg) - { - case WM_COMMAND: - { - switch(LOWORD(wParam)) - {case IDOK: EndDialog(hW,TRUE);return TRUE;} - } - } - return FALSE; -} - -//////////////////////////////////////////////////////////////////////// -// READ CONFIG: from win registry -//////////////////////////////////////////////////////////////////////// - -// timer mode 2 (spuupdate sync mode) can be enabled for windows -// by setting MAXMODE to 2. -// Attention: that mode is not much tested, maybe the dsound buffers -// need to get adjusted to use that mode safely. Also please note: -// sync sound updates will _always_ cause glitches, if the system is -// busy by, for example, long lasting cdrom accesses. OK, you have -// be warned :) - -#define MAXMODE 2 -//#define MAXMODE 1 - -void ReadConfig(void) -{ - HKEY myKey; - DWORD temp; - DWORD type; - DWORD size; - // init vars - iVolume=3; - iDebugMode=0; - iRecordMode=0; - iUseReverb=0; - iUseInterpolation=2; - iUseTimer = 2; - - if(RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\PS2Eplugin\\SPU2\\PeopsSound",0,KEY_ALL_ACCESS,&myKey)==ERROR_SUCCESS) - { - size = 4; - if(RegQueryValueEx(myKey,"Volume",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iVolume=(int)temp; - size = 4; - if(RegQueryValueEx(myKey,"DebugMode",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iDebugMode=(int)temp; - size = 4; - if(RegQueryValueEx(myKey,"RecordMode",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iRecordMode=(int)temp; - size = 4; - if(RegQueryValueEx(myKey,"UseReverb",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iUseReverb=(int)temp; - size = 4; - if(RegQueryValueEx(myKey,"UseInterpolation",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iUseInterpolation=(int)temp; - size = 4; - if(RegQueryValueEx(myKey,"UseTimer",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) - iUseTimer=(int)temp; - - - RegCloseKey(myKey); - } - - if(iVolume<1) iVolume=1; - if(iVolume>5) iVolume=5; -} - -//////////////////////////////////////////////////////////////////////// -// WRITE CONFIG: in win registry -//////////////////////////////////////////////////////////////////////// - -void WriteConfig(void) -{ - HKEY myKey; - DWORD myDisp; - DWORD temp; - - RegCreateKeyEx(HKEY_CURRENT_USER,"Software\\PS2Eplugin\\SPU2\\PeopsSound",0,NULL,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&myKey,&myDisp); - temp=iVolume; - RegSetValueEx(myKey,"Volume",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - temp=iDebugMode; - RegSetValueEx(myKey,"DebugMode",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - temp=iRecordMode; - RegSetValueEx(myKey,"RecordMode",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - temp=iUseReverb; - RegSetValueEx(myKey,"UseReverb",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - temp=iUseInterpolation; - RegSetValueEx(myKey,"UseInterpolation",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - temp=iUseTimer; - RegSetValueEx(myKey,"UseTimer",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); - RegCloseKey(myKey); -} - -//////////////////////////////////////////////////////////////////////// -// INIT WIN CFG DIALOG -//////////////////////////////////////////////////////////////////////// - -BOOL OnInitDSoundDialog(HWND hW) -{ - HWND hWC; - - ReadConfig(); - - hWC=GetDlgItem(hW,IDC_VOLUME); - ComboBox_AddString(hWC, "0: Mute"); - ComboBox_AddString(hWC, "1: low"); - ComboBox_AddString(hWC, "2: medium"); - ComboBox_AddString(hWC, "3: loud"); - ComboBox_AddString(hWC, "4: loudest"); - ComboBox_SetCurSel(hWC,5-iVolume); - if(iDebugMode) CheckDlgButton(hW,IDC_DEBUGMODE,TRUE); - if(iRecordMode) CheckDlgButton(hW,IDC_RECORDMODE,TRUE); - if(iUseTimer==0) CheckDlgButton(hW,IDC_TIMER,TRUE); - - hWC=GetDlgItem(hW,IDC_USEREVERB); - ComboBox_AddString(hWC, "0: No reverb (fastest)"); - ComboBox_AddString(hWC, "1: SPU2 reverb (may be buggy, not tested yet)"); - ComboBox_SetCurSel(hWC,iUseReverb); - - hWC=GetDlgItem(hW,IDC_INTERPOL); - ComboBox_AddString(hWC, "0: None (fastest)"); - ComboBox_AddString(hWC, "1: Simple interpolation"); - ComboBox_AddString(hWC, "2: Gaussian interpolation (good quality)"); - ComboBox_AddString(hWC, "3: Cubic interpolation (better treble)"); - ComboBox_SetCurSel(hWC,iUseInterpolation); - - return TRUE; -} - -//////////////////////////////////////////////////////////////////////// -// WIN CFG DLG OK -//////////////////////////////////////////////////////////////////////// - -void OnDSoundOK(HWND hW) -{ - HWND hWC; - - if(IsDlgButtonChecked(hW,IDC_TIMER)) - iUseTimer=0; else iUseTimer=2; - - hWC=GetDlgItem(hW,IDC_VOLUME); - iVolume=5-ComboBox_GetCurSel(hWC); - - hWC=GetDlgItem(hW,IDC_USEREVERB); - iUseReverb=ComboBox_GetCurSel(hWC); - - hWC=GetDlgItem(hW,IDC_INTERPOL); - iUseInterpolation=ComboBox_GetCurSel(hWC); - - if(IsDlgButtonChecked(hW,IDC_DEBUGMODE)) - iDebugMode=1; else iDebugMode=0; - - if(IsDlgButtonChecked(hW,IDC_RECORDMODE)) - iRecordMode=1; else iRecordMode=0; - - WriteConfig(); // write registry - - EndDialog(hW,TRUE); -} - -//////////////////////////////////////////////////////////////////////// -// WIN CFG DLG CANCEL -//////////////////////////////////////////////////////////////////////// - -void OnDSoundCancel(HWND hW) -{ - EndDialog(hW,FALSE); -} - -//////////////////////////////////////////////////////////////////////// -// WIN CFG PROC -//////////////////////////////////////////////////////////////////////// - -BOOL CALLBACK DSoundDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch(uMsg) - { - case WM_INITDIALOG: - return OnInitDSoundDialog(hW); - - case WM_COMMAND: - { - switch(LOWORD(wParam)) - { - case IDCANCEL: OnDSoundCancel(hW);return TRUE; - case IDOK: OnDSoundOK(hW); return TRUE; - } - } - } - return FALSE; -} - +/*************************************************************************** + cfg.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/04/04 - Pete +// - changed plugin to emulate PS2 spu +// +// 2003/06/07 - Pete +// - added Linux NOTHREADLIB define +// +// 2003/02/28 - Pete +// - added option for kode54's interpolation and linuzappz's mono mode +// +// 2003/01/19 - Pete +// - added Neill's reverb +// +// 2002/08/04 - Pete +// - small linux bug fix: now the cfg file can be in the main emu directory as well +// +// 2002/06/08 - linuzappz +// - Added combo str for SPUasync, and MAXMODE is now defined as 2 +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_CFG + +#include "externals.h" + +//////////////////////////////////////////////////////////////////////// +// WINDOWS CONFIG/ABOUT HANDLING +//////////////////////////////////////////////////////////////////////// + +#include "resource.h" + +//////////////////////////////////////////////////////////////////////// +// simple about dlg handler +//////////////////////////////////////////////////////////////////////// + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_COMMAND: + { + switch(LOWORD(wParam)) + {case IDOK: EndDialog(hW,TRUE);return TRUE;} + } + } + return FALSE; +} + +//////////////////////////////////////////////////////////////////////// +// READ CONFIG: from win registry +//////////////////////////////////////////////////////////////////////// + +// timer mode 2 (spuupdate sync mode) can be enabled for windows +// by setting MAXMODE to 2. +// Attention: that mode is not much tested, maybe the dsound buffers +// need to get adjusted to use that mode safely. Also please note: +// sync sound updates will _always_ cause glitches, if the system is +// busy by, for example, long lasting cdrom accesses. OK, you have +// be warned :) + +#define MAXMODE 2 +//#define MAXMODE 1 + +void ReadConfig(void) +{ + HKEY myKey; + DWORD temp; + DWORD type; + DWORD size; + // init vars + iVolume=3; + iDebugMode=0; + iRecordMode=0; + iUseReverb=0; + iUseInterpolation=2; + iUseTimer = 2; + + if(RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\PS2Eplugin\\SPU2\\PeopsSound",0,KEY_ALL_ACCESS,&myKey)==ERROR_SUCCESS) + { + size = 4; + if(RegQueryValueEx(myKey,"Volume",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iVolume=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"DebugMode",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iDebugMode=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"RecordMode",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iRecordMode=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"UseReverb",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iUseReverb=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"UseInterpolation",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iUseInterpolation=(int)temp; + size = 4; + if(RegQueryValueEx(myKey,"UseTimer",0,&type,(LPBYTE)&temp,&size)==ERROR_SUCCESS) + iUseTimer=(int)temp; + + + RegCloseKey(myKey); + } + + if(iVolume<1) iVolume=1; + if(iVolume>5) iVolume=5; +} + +//////////////////////////////////////////////////////////////////////// +// WRITE CONFIG: in win registry +//////////////////////////////////////////////////////////////////////// + +void WriteConfig(void) +{ + HKEY myKey; + DWORD myDisp; + DWORD temp; + + RegCreateKeyEx(HKEY_CURRENT_USER,"Software\\PS2Eplugin\\SPU2\\PeopsSound",0,NULL,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&myKey,&myDisp); + temp=iVolume; + RegSetValueEx(myKey,"Volume",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iDebugMode; + RegSetValueEx(myKey,"DebugMode",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iRecordMode; + RegSetValueEx(myKey,"RecordMode",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iUseReverb; + RegSetValueEx(myKey,"UseReverb",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iUseInterpolation; + RegSetValueEx(myKey,"UseInterpolation",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + temp=iUseTimer; + RegSetValueEx(myKey,"UseTimer",0,REG_DWORD,(LPBYTE) &temp,sizeof(temp)); + RegCloseKey(myKey); +} + +//////////////////////////////////////////////////////////////////////// +// INIT WIN CFG DIALOG +//////////////////////////////////////////////////////////////////////// + +BOOL OnInitDSoundDialog(HWND hW) +{ + HWND hWC; + + ReadConfig(); + + hWC=GetDlgItem(hW,IDC_VOLUME); + ComboBox_AddString(hWC, "0: Mute"); + ComboBox_AddString(hWC, "1: low"); + ComboBox_AddString(hWC, "2: medium"); + ComboBox_AddString(hWC, "3: loud"); + ComboBox_AddString(hWC, "4: loudest"); + ComboBox_SetCurSel(hWC,5-iVolume); + if(iDebugMode) CheckDlgButton(hW,IDC_DEBUGMODE,TRUE); + if(iRecordMode) CheckDlgButton(hW,IDC_RECORDMODE,TRUE); + if(iUseTimer==0) CheckDlgButton(hW,IDC_TIMER,TRUE); + + hWC=GetDlgItem(hW,IDC_USEREVERB); + ComboBox_AddString(hWC, "0: No reverb (fastest)"); + ComboBox_AddString(hWC, "1: SPU2 reverb (may be buggy, not tested yet)"); + ComboBox_SetCurSel(hWC,iUseReverb); + + hWC=GetDlgItem(hW,IDC_INTERPOL); + ComboBox_AddString(hWC, "0: None (fastest)"); + ComboBox_AddString(hWC, "1: Simple interpolation"); + ComboBox_AddString(hWC, "2: Gaussian interpolation (good quality)"); + ComboBox_AddString(hWC, "3: Cubic interpolation (better treble)"); + ComboBox_SetCurSel(hWC,iUseInterpolation); + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// WIN CFG DLG OK +//////////////////////////////////////////////////////////////////////// + +void OnDSoundOK(HWND hW) +{ + HWND hWC; + + if(IsDlgButtonChecked(hW,IDC_TIMER)) + iUseTimer=0; else iUseTimer=2; + + hWC=GetDlgItem(hW,IDC_VOLUME); + iVolume=5-ComboBox_GetCurSel(hWC); + + hWC=GetDlgItem(hW,IDC_USEREVERB); + iUseReverb=ComboBox_GetCurSel(hWC); + + hWC=GetDlgItem(hW,IDC_INTERPOL); + iUseInterpolation=ComboBox_GetCurSel(hWC); + + if(IsDlgButtonChecked(hW,IDC_DEBUGMODE)) + iDebugMode=1; else iDebugMode=0; + + if(IsDlgButtonChecked(hW,IDC_RECORDMODE)) + iRecordMode=1; else iRecordMode=0; + + WriteConfig(); // write registry + + EndDialog(hW,TRUE); +} + +//////////////////////////////////////////////////////////////////////// +// WIN CFG DLG CANCEL +//////////////////////////////////////////////////////////////////////// + +void OnDSoundCancel(HWND hW) +{ + EndDialog(hW,FALSE); +} + +//////////////////////////////////////////////////////////////////////// +// WIN CFG PROC +//////////////////////////////////////////////////////////////////////// + +BOOL CALLBACK DSoundDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: + return OnInitDSoundDialog(hW); + + case WM_COMMAND: + { + switch(LOWORD(wParam)) + { + case IDCANCEL: OnDSoundCancel(hW);return TRUE; + case IDOK: OnDSoundOK(hW); return TRUE; + } + } + } + return FALSE; +} + diff --git a/plugins/PeopsSPU2/debug.c b/plugins/PeopsSPU2/debug.c index 1aa65b3958..bd1d98ea3e 100644 --- a/plugins/PeopsSPU2/debug.c +++ b/plugins/PeopsSPU2/debug.c @@ -1,442 +1,442 @@ -/*************************************************************************** - debug.c - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2004/12/25 - Pete -// - update mute checkboxes if core selection changes -// -// 2004/04/04 - Pete -// - changed plugin to emulate PS2 spu -// -// 2003/01/06 - Pete -// - added Neil's ADSR timings -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -#include "stdafx.h" - -#define _IN_DEBUG - -#include "externals.h" - -//////////////////////////////////////////////////////////////////////// -// WINDOWS DEBUG DIALOG HANDLING -//////////////////////////////////////////////////////////////////////// - -#ifdef _WINDOWS - -#include "resource.h" - -//#define SMALLDEBUG -//#include - -//////////////////////////////////////////////////////////////////////// -// display debug infos - -const COLORREF crStreamCol[]={ - RGB( 0, 0, 0), - RGB(255,255,255), - RGB(128, 0,128), - RGB( 0,128, 0), - RGB( 0, 0,255), - RGB(255, 0, 0) - }; - -const COLORREF crAdsrCol[] ={ - RGB( 0, 0, 0), - RGB(255, 0, 0), - RGB( 0,255, 0), - RGB(255, 0,255), - RGB( 0, 0,255), - RGB( 0, 0, 0), - }; - -HBRUSH hBStream[6]; // brushes for stream lines -HPEN hPAdsr[6]; // pens for adsr lines -int iSelChannel=0; // user selected channel -int iCoreOffset=0; - -//////////////////////////////////////////////////////////////////////// -// display the sound data waves: no subclassing used, so the -// area will not be redrawn... but faster that way, and good enuff -// for debugging purposes - -void DisplayStreamInfos(HWND hW) -{ - HWND hWS=GetDlgItem(hW,IDC_SAREA); - HDC hdc;RECT r;HBRUSH hBO;int ch,dy,i,j,id; - - //----------------------------------------------------// - - GetClientRect(hWS,&r); // get size of stream display - hdc=GetDC(hWS); // device context - r.right--; // leave the right border intact - ScrollDC(hdc,-1,0,&r,&r,NULL,NULL); // scroll one pixel to the left - - //----------------------------------------------------// - - hBO=SelectObject(hdc,hBStream[0]); // clean the right border - PatBlt(hdc,r.right-1,0,1,r.bottom,PATCOPY); - - //----------------------------------------------------// - - dy=r.bottom/HLFCHAN; // size of one channel area - - for(ch=0;ch get one channel data (-32k ... 32k) - j=(dy*j)/33768; if(j==0) j=1; // -> adjust to display coords - i=(dy/2)+(ch*r.bottom/HLFCHAN)-j/2; // -> position where to paint it - - - - if (s_chan[ch+iCoreOffset].iMute) id=1; // -> get color id - else if(s_chan[ch+iCoreOffset].bNoise) id=2; - else if(s_chan[ch+iCoreOffset].bFMod==2) id=3; - else if(s_chan[ch+iCoreOffset].bFMod==1) id=4; - else id=5; - - SelectObject(hdc,hBStream[id]); // -> select the brush - PatBlt(hdc,r.right-1,i,1,j,PATCOPY); // -> paint the value line - } - - if(ch) SetPixel(hdc,r.right-1, // -> not first line? - ch*r.bottom/HLFCHAN,RGB(0,0,0)); // --> draw the line (one dot scrolled to the left) - } - - //----------------------------------------------------// - - SelectObject(hdc,hBO); // repair brush - - ReleaseDC(hWS,hdc); // release context -} - -//////////////////////////////////////////////////////////////////////// -// display adsr lines: also no subclassing for repainting used - -void DisplayADSRInfos(HWND hW) -{ - HWND hWS=GetDlgItem(hW,IDC_ADSR); - HDC hdc;RECT r;HBRUSH hBO;char szB[16]; - int ch=iSelChannel+iCoreOffset,dx,dy,dm,dn,ia,id,is,ir; - - //----------------------------------------------------// get display size - - GetClientRect(hWS,&r); - hdc=GetDC(hWS); - - //----------------------------------------------------// clean the area - - hBO=SelectObject(hdc,hBStream[0]); - PatBlt(hdc,0,0,r.right,r.bottom,PATCOPY); - r.left++;r.right-=2;r.top++;r.bottom-=2; // shrink the display rect for better optics - - //----------------------------------------------------// - - ia=min(s_chan[ch].ADSR.AttackTime,10000); // get adsr, but limit it for drawing - id=min(s_chan[ch].ADSR.DecayTime,10000); - is=min(s_chan[ch].ADSR.SustainTime,10000); - ir=min(s_chan[ch].ADSR.ReleaseTime,10000); - - dx=ia+id+is+ir; // get the dx in (limited) adsr units - - // set the real values to the info statics - SetDlgItemInt(hW,IDC_SADSR1,s_chan[ch].ADSRX.AttackRate,FALSE); - SetDlgItemInt(hW,IDC_SADSR2,s_chan[ch].ADSRX.DecayRate,FALSE); - SetDlgItemInt(hW,IDC_SADSR3,s_chan[ch].ADSRX.SustainRate,FALSE); - SetDlgItemInt(hW,IDC_SADSR4,s_chan[ch].ADSRX.ReleaseRate,FALSE); - SetDlgItemInt(hW,IDC_SADSR5,s_chan[ch].ADSRX.SustainLevel,FALSE); - SetDlgItemInt(hW,IDC_SADSR6,s_chan[ch].ADSRX.SustainIncrease,TRUE); - SetDlgItemInt(hW,IDC_SADSR7,s_chan[ch].ADSRX.lVolume,TRUE); - wsprintf(szB,"%08lX",s_chan[ch].ADSRX.EnvelopeVol); - SetDlgItemText(hW,IDC_SADSR8,szB); - - if(dx) // something to draw? - { - HPEN hPO=SelectObject(hdc,hPAdsr[1]); // sel A pen - dn=r.left; - MoveToEx(hdc,dn,r.bottom,NULL); // move to bottom left corner - - dn+=(ia*r.right)/dx; // calc A x line pos - LineTo(hdc,dn,r.top); // line to AxPos,top - - SelectObject(hdc,hPAdsr[2]); // sel D pen - dn+=(id*r.right)/dx; // calc D x line pos - dy=r.top+((1024-s_chan[ch].ADSR.SustainLevel)* // calc the D y pos - r.bottom)/1024; // (our S level is ranged from 0 to 1024) - LineTo(hdc,dn,dy); // line to DxPos,SLevel - - SelectObject(hdc,hPAdsr[3]); // sel S pen - if(s_chan[ch].ADSR.SustainTime>10000) - dm=1; // we have to fake the S values... S will - else // inc/decrease until channel stop... - if(s_chan[ch].ADSR.SustainTime==0) - dm=0; // we dunno here when this will happen, - else - dm=21-(((s_chan[ch].ADSR.SustainTime/500))); // so we do some more or less angled line, - dy=dy-(s_chan[ch].ADSR.SustainModeDec*dm); // roughly depending on the S time - if(dy>r.bottom) dy=r.bottom; - if(dy>1); - SetDlgItemText(hW,IDC_CI10,szB); - if(s_chan[ch].pCurr==(unsigned char *)-1) - SetDlgItemText(hW,IDC_CI11,"FFFFFFFF"); - else - { - wsprintf(szB,"%08lX",((unsigned long)s_chan[ch].pCurr-(unsigned long)spuMemC)>>1); - SetDlgItemText(hW,IDC_CI11,szB); - } - - wsprintf(szB,"%08lX",((unsigned long)s_chan[ch].pLoop-(unsigned long)spuMemC)>>1); - SetDlgItemText(hW,IDC_CI12,szB); - SetDlgItemInt(hW,IDC_CI13,s_chan[ch].iRightVolume,TRUE); - SetDlgItemInt(hW,IDC_CI14,s_chan[ch].iLeftVolume,TRUE); - SetDlgItemInt(hW,IDC_CI15,s_chan[ch].iActFreq,TRUE); - SetDlgItemInt(hW,IDC_CI16,s_chan[ch].iUsedFreq,TRUE); - -// wsprintf(szB,"%04x",s_chan[ch].iRightVolRaw); - wsprintf(szB,"R%d",s_chan[ch].bVolumeR); - SetDlgItemText(hW,IDC_CI17,szB); -// wsprintf(szB,"%04x",s_chan[ch].iLeftVolRaw); - wsprintf(szB,"L%d",s_chan[ch].bVolumeL); - SetDlgItemText(hW,IDC_CI18,szB); - - wsprintf(szB,"%08lX",s_chan[ch].iNextAdr); - SetDlgItemText(hW,IDC_CI19,szB); - - // generic infos - /*if(pSpuIrq[ch]==0) - SetDlgItemText(hW,IDC_STA1,"FFFFFFFF"); - else - {*/ - wsprintf(szB,"%08lX",((unsigned long)pSpuIrq[ch/24]-(unsigned long)spuMemC)>>1); - SetDlgItemText(hW,IDC_STA1,szB); - /*}*/ - - wsprintf(szB,"%04X",spuCtrl2[ch/24]); - SetDlgItemText(hW,IDC_STA2,szB); - wsprintf(szB,"%04X",spuStat2[ch/24]); - SetDlgItemText(hW,IDC_STA3,szB); - - wsprintf(szB,"%08lX",spuAddr2[ch/24]); - SetDlgItemText(hW,IDC_STA4,szB); - } - -//////////////////////////////////////////////////////////////////////// -// display everything (called in dialog timer for value refreshing) - -void DisplayDebugInfos(HWND hW) -{ - DisplayStreamInfos(hW); - DisplayADSRInfos(hW); - DisplayChannelInfos(hW); -} - -EXPORT_GCC void CALLBACK SPU2write(unsigned long reg, unsigned short val); -EXPORT_GCC unsigned short CALLBACK SPU2read(unsigned long reg); - -//////////////////////////////////////////////////////////////////////// -// main debug dlg handler - -char old_buffer[128]; -int iBuffRepeats=0; - -BOOL CALLBACK DebugDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch(uMsg) - { - //--------------------------------------------------// init - case WM_INITDIALOG: - { - int i; - ShowCursor(TRUE); // mmm... who is hiding it? main emu? tsts - iSelChannel=0; // sel first channel - iCoreOffset=0; - CheckRadioButton(hW,IDC_CHAN1,IDC_CHAN24,IDC_CHAN1); - CheckRadioButton(hW,IDC_CORE1,IDC_CORE2,IDC_CORE1); - - memset(old_buffer,0,128); - // create brushes/pens - hBStream[0]=CreateSolidBrush(GetSysColor(COLOR_3DFACE)); - hPAdsr[0]=CreatePen(PS_SOLID,0,GetSysColor(COLOR_3DFACE)); - for(i=1;i<6;i++) - { - hBStream[i]=CreateSolidBrush(crStreamCol[i]); - hPAdsr[i]=CreatePen(PS_SOLID,0,crAdsrCol[i]); - } - SetTimer(hW,999,50,NULL); // now create update timer - return TRUE; - } - //--------------------------------------------------// destroy - case WM_DESTROY: - { - int i; - KillTimer(hW,999); // first kill timer - for(i=0;i<6;i++) // then kill brushes/pens - { - DeleteObject(hBStream[i]); - DeleteObject(hPAdsr[i]); - } - }break; - //--------------------------------------------------// timer - case WM_TIMER: - { - if(wParam==999) DisplayDebugInfos(hW); // update all values - }break; - //--------------------------------------------------// command - case WM_COMMAND: - { - if(wParam==IDCANCEL) iDebugMode=2; // cancel? raise flag for destroying the dialog - - if(wParam>=IDC_CORE1 && wParam<=IDC_CORE2) // core clicked? - { - int i; - - if(IsDlgButtonChecked(hW,IDC_CORE1)) // -> sel correct half of channels - iCoreOffset=0; - else iCoreOffset=24; - - for(i=IDC_MUTE1;i<=IDC_MUTE24;i++) - { - if(s_chan[i-IDC_MUTE1+iCoreOffset].iMute) - CheckDlgButton(hW,i,TRUE); - else CheckDlgButton(hW,i,FALSE); - } - - InvalidateRect(hW,NULL,TRUE); - UpdateWindow(hW); - } - - if(wParam>=IDC_MUTE1 && wParam<=IDC_MUTE24) // mute clicked? - { - if(IsDlgButtonChecked(hW,wParam)) // -> mute/unmute it - s_chan[wParam-IDC_MUTE1+iCoreOffset].iMute=1; - else - s_chan[wParam-IDC_MUTE1+iCoreOffset].iMute=0; - } - // all mute/unmute - if(wParam==IDC_MUTEOFF) SendMessage(hW,WM_MUTE,0,0); - if(wParam==IDC_MUTEON) SendMessage(hW,WM_MUTE,1,0); - - if(wParam>=IDC_CHAN1 && wParam<=IDC_CHAN24) // sel channel - { - if(IsDlgButtonChecked(hW,wParam)) - { - iSelChannel=wParam-IDC_CHAN1; - SetDlgItemInt(hW,IDC_CHANNUM,iSelChannel+1,FALSE); - } - } - }break; - //--------------------------------------------------// mute - case WM_MUTE: - { // will be called by the mute/unmute all button and on savestate load - int i; - for(i=IDC_MUTE1;i<=IDC_MUTE24;i++) - { - CheckDlgButton(hW,i,wParam); - if(wParam) - s_chan[i-IDC_MUTE1+iCoreOffset].iMute=1; - else - s_chan[i-IDC_MUTE1+iCoreOffset].iMute=0; - } - }break; - //--------------------------------------------------// size - case WM_SIZE: - if(wParam==SIZE_MINIMIZED) SetFocus(hWMain); // if we get minimized, set the foxus to the main window - break; - //--------------------------------------------------// setcursor - case WM_SETCURSOR: - { - SetCursor(LoadCursor(NULL,IDC_ARROW)); // force the arrow - return TRUE; - } - //--------------------------------------------------// - } - return FALSE; -} - -//////////////////////////////////////////////////////////////////////// -#include -extern FILE * LogFile; -void logprintf(LPCTSTR pFormat, ...) -{ - if(iDebugMode!=1) return; - if(!IsWindow(hWDebug)) return; - else - { - va_list list; - - va_start(list,pFormat); - vfprintf(LogFile, pFormat, list); - va_end(list); - } - -} - -#endif - +/*************************************************************************** + debug.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/12/25 - Pete +// - update mute checkboxes if core selection changes +// +// 2004/04/04 - Pete +// - changed plugin to emulate PS2 spu +// +// 2003/01/06 - Pete +// - added Neil's ADSR timings +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_DEBUG + +#include "externals.h" + +//////////////////////////////////////////////////////////////////////// +// WINDOWS DEBUG DIALOG HANDLING +//////////////////////////////////////////////////////////////////////// + +#ifdef _WINDOWS + +#include "resource.h" + +//#define SMALLDEBUG +//#include + +//////////////////////////////////////////////////////////////////////// +// display debug infos + +const COLORREF crStreamCol[]={ + RGB( 0, 0, 0), + RGB(255,255,255), + RGB(128, 0,128), + RGB( 0,128, 0), + RGB( 0, 0,255), + RGB(255, 0, 0) + }; + +const COLORREF crAdsrCol[] ={ + RGB( 0, 0, 0), + RGB(255, 0, 0), + RGB( 0,255, 0), + RGB(255, 0,255), + RGB( 0, 0,255), + RGB( 0, 0, 0), + }; + +HBRUSH hBStream[6]; // brushes for stream lines +HPEN hPAdsr[6]; // pens for adsr lines +int iSelChannel=0; // user selected channel +int iCoreOffset=0; + +//////////////////////////////////////////////////////////////////////// +// display the sound data waves: no subclassing used, so the +// area will not be redrawn... but faster that way, and good enuff +// for debugging purposes + +void DisplayStreamInfos(HWND hW) +{ + HWND hWS=GetDlgItem(hW,IDC_SAREA); + HDC hdc;RECT r;HBRUSH hBO;int ch,dy,i,j,id; + + //----------------------------------------------------// + + GetClientRect(hWS,&r); // get size of stream display + hdc=GetDC(hWS); // device context + r.right--; // leave the right border intact + ScrollDC(hdc,-1,0,&r,&r,NULL,NULL); // scroll one pixel to the left + + //----------------------------------------------------// + + hBO=SelectObject(hdc,hBStream[0]); // clean the right border + PatBlt(hdc,r.right-1,0,1,r.bottom,PATCOPY); + + //----------------------------------------------------// + + dy=r.bottom/HLFCHAN; // size of one channel area + + for(ch=0;ch get one channel data (-32k ... 32k) + j=(dy*j)/33768; if(j==0) j=1; // -> adjust to display coords + i=(dy/2)+(ch*r.bottom/HLFCHAN)-j/2; // -> position where to paint it + + + + if (s_chan[ch+iCoreOffset].iMute) id=1; // -> get color id + else if(s_chan[ch+iCoreOffset].bNoise) id=2; + else if(s_chan[ch+iCoreOffset].bFMod==2) id=3; + else if(s_chan[ch+iCoreOffset].bFMod==1) id=4; + else id=5; + + SelectObject(hdc,hBStream[id]); // -> select the brush + PatBlt(hdc,r.right-1,i,1,j,PATCOPY); // -> paint the value line + } + + if(ch) SetPixel(hdc,r.right-1, // -> not first line? + ch*r.bottom/HLFCHAN,RGB(0,0,0)); // --> draw the line (one dot scrolled to the left) + } + + //----------------------------------------------------// + + SelectObject(hdc,hBO); // repair brush + + ReleaseDC(hWS,hdc); // release context +} + +//////////////////////////////////////////////////////////////////////// +// display adsr lines: also no subclassing for repainting used + +void DisplayADSRInfos(HWND hW) +{ + HWND hWS=GetDlgItem(hW,IDC_ADSR); + HDC hdc;RECT r;HBRUSH hBO;char szB[16]; + int ch=iSelChannel+iCoreOffset,dx,dy,dm,dn,ia,id,is,ir; + + //----------------------------------------------------// get display size + + GetClientRect(hWS,&r); + hdc=GetDC(hWS); + + //----------------------------------------------------// clean the area + + hBO=SelectObject(hdc,hBStream[0]); + PatBlt(hdc,0,0,r.right,r.bottom,PATCOPY); + r.left++;r.right-=2;r.top++;r.bottom-=2; // shrink the display rect for better optics + + //----------------------------------------------------// + + ia=min(s_chan[ch].ADSR.AttackTime,10000); // get adsr, but limit it for drawing + id=min(s_chan[ch].ADSR.DecayTime,10000); + is=min(s_chan[ch].ADSR.SustainTime,10000); + ir=min(s_chan[ch].ADSR.ReleaseTime,10000); + + dx=ia+id+is+ir; // get the dx in (limited) adsr units + + // set the real values to the info statics + SetDlgItemInt(hW,IDC_SADSR1,s_chan[ch].ADSRX.AttackRate,FALSE); + SetDlgItemInt(hW,IDC_SADSR2,s_chan[ch].ADSRX.DecayRate,FALSE); + SetDlgItemInt(hW,IDC_SADSR3,s_chan[ch].ADSRX.SustainRate,FALSE); + SetDlgItemInt(hW,IDC_SADSR4,s_chan[ch].ADSRX.ReleaseRate,FALSE); + SetDlgItemInt(hW,IDC_SADSR5,s_chan[ch].ADSRX.SustainLevel,FALSE); + SetDlgItemInt(hW,IDC_SADSR6,s_chan[ch].ADSRX.SustainIncrease,TRUE); + SetDlgItemInt(hW,IDC_SADSR7,s_chan[ch].ADSRX.lVolume,TRUE); + wsprintf(szB,"%08lX",s_chan[ch].ADSRX.EnvelopeVol); + SetDlgItemText(hW,IDC_SADSR8,szB); + + if(dx) // something to draw? + { + HPEN hPO=SelectObject(hdc,hPAdsr[1]); // sel A pen + dn=r.left; + MoveToEx(hdc,dn,r.bottom,NULL); // move to bottom left corner + + dn+=(ia*r.right)/dx; // calc A x line pos + LineTo(hdc,dn,r.top); // line to AxPos,top + + SelectObject(hdc,hPAdsr[2]); // sel D pen + dn+=(id*r.right)/dx; // calc D x line pos + dy=r.top+((1024-s_chan[ch].ADSR.SustainLevel)* // calc the D y pos + r.bottom)/1024; // (our S level is ranged from 0 to 1024) + LineTo(hdc,dn,dy); // line to DxPos,SLevel + + SelectObject(hdc,hPAdsr[3]); // sel S pen + if(s_chan[ch].ADSR.SustainTime>10000) + dm=1; // we have to fake the S values... S will + else // inc/decrease until channel stop... + if(s_chan[ch].ADSR.SustainTime==0) + dm=0; // we dunno here when this will happen, + else + dm=21-(((s_chan[ch].ADSR.SustainTime/500))); // so we do some more or less angled line, + dy=dy-(s_chan[ch].ADSR.SustainModeDec*dm); // roughly depending on the S time + if(dy>r.bottom) dy=r.bottom; + if(dy>1); + SetDlgItemText(hW,IDC_CI10,szB); + if(s_chan[ch].pCurr==(unsigned char *)-1) + SetDlgItemText(hW,IDC_CI11,"FFFFFFFF"); + else + { + wsprintf(szB,"%08lX",((unsigned long)s_chan[ch].pCurr-(unsigned long)spuMemC)>>1); + SetDlgItemText(hW,IDC_CI11,szB); + } + + wsprintf(szB,"%08lX",((unsigned long)s_chan[ch].pLoop-(unsigned long)spuMemC)>>1); + SetDlgItemText(hW,IDC_CI12,szB); + SetDlgItemInt(hW,IDC_CI13,s_chan[ch].iRightVolume,TRUE); + SetDlgItemInt(hW,IDC_CI14,s_chan[ch].iLeftVolume,TRUE); + SetDlgItemInt(hW,IDC_CI15,s_chan[ch].iActFreq,TRUE); + SetDlgItemInt(hW,IDC_CI16,s_chan[ch].iUsedFreq,TRUE); + +// wsprintf(szB,"%04x",s_chan[ch].iRightVolRaw); + wsprintf(szB,"R%d",s_chan[ch].bVolumeR); + SetDlgItemText(hW,IDC_CI17,szB); +// wsprintf(szB,"%04x",s_chan[ch].iLeftVolRaw); + wsprintf(szB,"L%d",s_chan[ch].bVolumeL); + SetDlgItemText(hW,IDC_CI18,szB); + + wsprintf(szB,"%08lX",s_chan[ch].iNextAdr); + SetDlgItemText(hW,IDC_CI19,szB); + + // generic infos + /*if(pSpuIrq[ch]==0) + SetDlgItemText(hW,IDC_STA1,"FFFFFFFF"); + else + {*/ + wsprintf(szB,"%08lX",((unsigned long)pSpuIrq[ch/24]-(unsigned long)spuMemC)>>1); + SetDlgItemText(hW,IDC_STA1,szB); + /*}*/ + + wsprintf(szB,"%04X",spuCtrl2[ch/24]); + SetDlgItemText(hW,IDC_STA2,szB); + wsprintf(szB,"%04X",spuStat2[ch/24]); + SetDlgItemText(hW,IDC_STA3,szB); + + wsprintf(szB,"%08lX",spuAddr2[ch/24]); + SetDlgItemText(hW,IDC_STA4,szB); + } + +//////////////////////////////////////////////////////////////////////// +// display everything (called in dialog timer for value refreshing) + +void DisplayDebugInfos(HWND hW) +{ + DisplayStreamInfos(hW); + DisplayADSRInfos(hW); + DisplayChannelInfos(hW); +} + +EXPORT_GCC void CALLBACK SPU2write(unsigned long reg, unsigned short val); +EXPORT_GCC unsigned short CALLBACK SPU2read(unsigned long reg); + +//////////////////////////////////////////////////////////////////////// +// main debug dlg handler + +char old_buffer[128]; +int iBuffRepeats=0; + +BOOL CALLBACK DebugDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + //--------------------------------------------------// init + case WM_INITDIALOG: + { + int i; + ShowCursor(TRUE); // mmm... who is hiding it? main emu? tsts + iSelChannel=0; // sel first channel + iCoreOffset=0; + CheckRadioButton(hW,IDC_CHAN1,IDC_CHAN24,IDC_CHAN1); + CheckRadioButton(hW,IDC_CORE1,IDC_CORE2,IDC_CORE1); + + memset(old_buffer,0,128); + // create brushes/pens + hBStream[0]=CreateSolidBrush(GetSysColor(COLOR_3DFACE)); + hPAdsr[0]=CreatePen(PS_SOLID,0,GetSysColor(COLOR_3DFACE)); + for(i=1;i<6;i++) + { + hBStream[i]=CreateSolidBrush(crStreamCol[i]); + hPAdsr[i]=CreatePen(PS_SOLID,0,crAdsrCol[i]); + } + SetTimer(hW,999,50,NULL); // now create update timer + return TRUE; + } + //--------------------------------------------------// destroy + case WM_DESTROY: + { + int i; + KillTimer(hW,999); // first kill timer + for(i=0;i<6;i++) // then kill brushes/pens + { + DeleteObject(hBStream[i]); + DeleteObject(hPAdsr[i]); + } + }break; + //--------------------------------------------------// timer + case WM_TIMER: + { + if(wParam==999) DisplayDebugInfos(hW); // update all values + }break; + //--------------------------------------------------// command + case WM_COMMAND: + { + if(wParam==IDCANCEL) iDebugMode=2; // cancel? raise flag for destroying the dialog + + if(wParam>=IDC_CORE1 && wParam<=IDC_CORE2) // core clicked? + { + int i; + + if(IsDlgButtonChecked(hW,IDC_CORE1)) // -> sel correct half of channels + iCoreOffset=0; + else iCoreOffset=24; + + for(i=IDC_MUTE1;i<=IDC_MUTE24;i++) + { + if(s_chan[i-IDC_MUTE1+iCoreOffset].iMute) + CheckDlgButton(hW,i,TRUE); + else CheckDlgButton(hW,i,FALSE); + } + + InvalidateRect(hW,NULL,TRUE); + UpdateWindow(hW); + } + + if(wParam>=IDC_MUTE1 && wParam<=IDC_MUTE24) // mute clicked? + { + if(IsDlgButtonChecked(hW,wParam)) // -> mute/unmute it + s_chan[wParam-IDC_MUTE1+iCoreOffset].iMute=1; + else + s_chan[wParam-IDC_MUTE1+iCoreOffset].iMute=0; + } + // all mute/unmute + if(wParam==IDC_MUTEOFF) SendMessage(hW,WM_MUTE,0,0); + if(wParam==IDC_MUTEON) SendMessage(hW,WM_MUTE,1,0); + + if(wParam>=IDC_CHAN1 && wParam<=IDC_CHAN24) // sel channel + { + if(IsDlgButtonChecked(hW,wParam)) + { + iSelChannel=wParam-IDC_CHAN1; + SetDlgItemInt(hW,IDC_CHANNUM,iSelChannel+1,FALSE); + } + } + }break; + //--------------------------------------------------// mute + case WM_MUTE: + { // will be called by the mute/unmute all button and on savestate load + int i; + for(i=IDC_MUTE1;i<=IDC_MUTE24;i++) + { + CheckDlgButton(hW,i,wParam); + if(wParam) + s_chan[i-IDC_MUTE1+iCoreOffset].iMute=1; + else + s_chan[i-IDC_MUTE1+iCoreOffset].iMute=0; + } + }break; + //--------------------------------------------------// size + case WM_SIZE: + if(wParam==SIZE_MINIMIZED) SetFocus(hWMain); // if we get minimized, set the foxus to the main window + break; + //--------------------------------------------------// setcursor + case WM_SETCURSOR: + { + SetCursor(LoadCursor(NULL,IDC_ARROW)); // force the arrow + return TRUE; + } + //--------------------------------------------------// + } + return FALSE; +} + +//////////////////////////////////////////////////////////////////////// +#include +extern FILE * LogFile; +void logprintf(LPCTSTR pFormat, ...) +{ + if(iDebugMode!=1) return; + if(!IsWindow(hWDebug)) return; + else + { + va_list list; + + va_start(list,pFormat); + vfprintf(LogFile, pFormat, list); + va_end(list); + } + +} + +#endif + diff --git a/plugins/PeopsSPU2/debug.h b/plugins/PeopsSPU2/debug.h index 4999b42d2b..5f352e18bf 100644 --- a/plugins/PeopsSPU2/debug.h +++ b/plugins/PeopsSPU2/debug.h @@ -1,34 +1,34 @@ -/*************************************************************************** - debug.h - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -#ifdef _WIN32 -BOOL CALLBACK DebugDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); -void logprintf(LPCTSTR pFormat, ...); -#else - -#define logprintf 0&& - -#endif +/*************************************************************************** + debug.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#ifdef _WIN32 +BOOL CALLBACK DebugDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); +void logprintf(LPCTSTR pFormat, ...); +#else + +#define logprintf 0&& + +#endif diff --git a/plugins/PeopsSPU2/dma.c b/plugins/PeopsSPU2/dma.c index 0bebed05e1..1378f6c18a 100644 --- a/plugins/PeopsSPU2/dma.c +++ b/plugins/PeopsSPU2/dma.c @@ -181,8 +181,8 @@ int ADMAS4Write() if(Adma4.AmountLeft == 0) { - if(Adma4.IRQ == 0){ - Adma4.IRQ = 1; + if(Adma4.IRQ == 0){ + Adma4.IRQ = 1; irqCallbackDMA4(); } } @@ -225,8 +225,8 @@ int ADMAS7Write() if(Adma7.AmountLeft == 0) { - if(Adma7.IRQ == 0){ - Adma7.IRQ = 1; + if(Adma7.IRQ == 0){ + Adma7.IRQ = 1; irqCallbackDMA7(); } } @@ -242,7 +242,7 @@ EXPORT_GCC void CALLBACK SPU2writeDMA4Mem(short * pMem,unsigned int iSize) { //fwrite(pMem,iSize<<1,1,LogFile); // memset(&Adma4,0,sizeof(ADMA)); - //if( !Adma4.Enabled ) + //if( !Adma4.Enabled ) // Adma4.Index = 0; //Adma4.ADMAPos = 0; if((Adma4.ADMAPos == 512 && Adma4.Index <= 256) || (Adma4.ADMAPos == 256 && Adma4.Index >= 256) || Adma4.AmountLeft >= 512) { @@ -250,7 +250,7 @@ EXPORT_GCC void CALLBACK SPU2writeDMA4Mem(short * pMem,unsigned int iSize) Adma4.TempAmount = iSize; } else { Adma4.MemAddr = pMem; - Adma4.AmountLeft += iSize; + Adma4.AmountLeft += iSize; ADMAS4Write(); } return; @@ -280,34 +280,34 @@ EXPORT_GCC void CALLBACK SPU2writeDMA4Mem(short * pMem,unsigned int iSize) interrupt |= (1<<1); } -void LogRawSound(void* pleft, int leftstride, void* pright, int rightstride, int numsamples) -{ -#ifdef _DEBUG - static FILE* g_fLogSound = NULL; - - char* left = (char*)pleft; - char* right = (char*)pright; - unsigned short* tempbuf; - int i; - - if( g_fLogSound == NULL ) { - g_fLogSound = fopen("rawsndbuf.pcm", "wb"); - if( g_fLogSound == NULL ) - return; - } - - tempbuf = (unsigned short*)malloc(4*numsamples); - - for(i = 0; i < numsamples; ++i) { - tempbuf[2*i+0] = *(unsigned short*)left; - tempbuf[2*i+1] = *(unsigned short*)right; - left += leftstride; - right += rightstride; - } - - fwrite(&tempbuf[0], 4*numsamples, 1, g_fLogSound); - free(tempbuf); -#endif +void LogRawSound(void* pleft, int leftstride, void* pright, int rightstride, int numsamples) +{ +#ifdef _DEBUG + static FILE* g_fLogSound = NULL; + + char* left = (char*)pleft; + char* right = (char*)pright; + unsigned short* tempbuf; + int i; + + if( g_fLogSound == NULL ) { + g_fLogSound = fopen("rawsndbuf.pcm", "wb"); + if( g_fLogSound == NULL ) + return; + } + + tempbuf = (unsigned short*)malloc(4*numsamples); + + for(i = 0; i < numsamples; ++i) { + tempbuf[2*i+0] = *(unsigned short*)left; + tempbuf[2*i+1] = *(unsigned short*)right; + left += leftstride; + right += rightstride; + } + + fwrite(&tempbuf[0], 4*numsamples, 1, g_fLogSound); + free(tempbuf); +#endif } EXPORT_GCC void CALLBACK SPU2writeDMA7Mem(unsigned short * pMem,int iSize) @@ -321,7 +321,7 @@ EXPORT_GCC void CALLBACK SPU2writeDMA7Mem(unsigned short * pMem,int iSize) { //fwrite(pMem,iSize<<1,1,LogFile); // memset(&Adma7,0,sizeof(ADMA)); - //if( !Adma7.Enabled ) + //if( !Adma7.Enabled ) // Adma7.Index = 0; //Adma7.ADMAPos = 0; if((Adma7.ADMAPos == 512 && Adma7.Index <= 256) || (Adma7.ADMAPos == 256 && Adma7.Index >= 256) || Adma7.AmountLeft >= 512) { @@ -329,7 +329,7 @@ EXPORT_GCC void CALLBACK SPU2writeDMA7Mem(unsigned short * pMem,int iSize) Adma7.TempAmount = iSize; } else { Adma7.MemAddr = pMem; - Adma7.AmountLeft += iSize; + Adma7.AmountLeft += iSize; ADMAS7Write(); } return; diff --git a/plugins/PeopsSPU2/dma.h b/plugins/PeopsSPU2/dma.h index 4314b60a35..f56d10166b 100644 --- a/plugins/PeopsSPU2/dma.h +++ b/plugins/PeopsSPU2/dma.h @@ -1,28 +1,28 @@ -/*************************************************************************** - dma.h - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -void InterruptDMA4(void); -void InterruptDMA7(void); +/*************************************************************************** + dma.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +void InterruptDMA4(void); +void InterruptDMA7(void); diff --git a/plugins/PeopsSPU2/dsound.c b/plugins/PeopsSPU2/dsound.c index a35b2d8b43..7c9aad6d82 100644 --- a/plugins/PeopsSPU2/dsound.c +++ b/plugins/PeopsSPU2/dsound.c @@ -1,268 +1,268 @@ -/*************************************************************************** - dsound.c - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2005/08/29 - Pete -// - changed to 48Khz output -// -// 2003/01/12 - Pete -// - added recording funcs -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -#include "stdafx.h" - -#define _IN_DSOUND - -#include "externals.h" - -#ifdef _WINDOWS -#define _LPCWAVEFORMATEX_DEFINED -#include "dsound.h" - -#include "record.h" - -//////////////////////////////////////////////////////////////////////// -// dsound globals -//////////////////////////////////////////////////////////////////////// - -LPDIRECTSOUND lpDS; -LPDIRECTSOUNDBUFFER lpDSBPRIMARY = NULL; -LPDIRECTSOUNDBUFFER lpDSBSECONDARY1 = NULL; -LPDIRECTSOUNDBUFFER lpDSBSECONDARY2 = NULL; -DSBUFFERDESC dsbd; -DSBUFFERDESC dsbdesc; -DSCAPS dscaps; -DSBCAPS dsbcaps; - -unsigned long LastWrite=0xffffffff; -unsigned long LastWriteS=0xffffffff; -unsigned long LastPlay=0; - -//////////////////////////////////////////////////////////////////////// -// SETUP SOUND -//////////////////////////////////////////////////////////////////////// - -void SetupSound(void) -{ - HRESULT dsval;WAVEFORMATEX pcmwf; - - dsval = DirectSoundCreate(NULL,&lpDS,NULL); - if(dsval!=DS_OK) - { - MessageBox(hWMain,"DirectSoundCreate!","Error",MB_OK); - return; - } - - if(DS_OK!=IDirectSound_SetCooperativeLevel(lpDS,hWMain, DSSCL_PRIORITY)) - { - if(DS_OK!=IDirectSound_SetCooperativeLevel(lpDS,hWMain, DSSCL_NORMAL)) - { - MessageBox(hWMain,"SetCooperativeLevel!","Error",MB_OK); - return; - } - } - - memset(&dsbd,0,sizeof(DSBUFFERDESC)); - dsbd.dwSize = sizeof(DSBUFFERDESC); // NT4 hack! sizeof(dsbd); - dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; - dsbd.dwBufferBytes = 0; - dsbd.lpwfxFormat = NULL; - - dsval=IDirectSound_CreateSoundBuffer(lpDS,&dsbd,&lpDSBPRIMARY,NULL); - if(dsval!=DS_OK) - { - MessageBox(hWMain, "CreateSoundBuffer (Primary)", "Error",MB_OK); - return; - } - - memset(&pcmwf, 0, sizeof(WAVEFORMATEX)); - pcmwf.wFormatTag = WAVE_FORMAT_PCM; - - pcmwf.nChannels = 2; - pcmwf.nBlockAlign = 4; - - pcmwf.nSamplesPerSec = 48000; - - pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign; - pcmwf.wBitsPerSample = 16; - - dsval=IDirectSoundBuffer_SetFormat(lpDSBPRIMARY,&pcmwf); - if(dsval!=DS_OK) - { - MessageBox(hWMain, "SetFormat!", "Error",MB_OK); - return; - } - - dscaps.dwSize = sizeof(DSCAPS); - dsbcaps.dwSize = sizeof(DSBCAPS); - IDirectSound_GetCaps(lpDS,&dscaps); - IDirectSoundBuffer_GetCaps(lpDSBPRIMARY,&dsbcaps); - - memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); - dsbdesc.dwSize = sizeof(DSBUFFERDESC); // NT4 hack! sizeof(DSBUFFERDESC); - dsbdesc.dwFlags = DSBCAPS_LOCHARDWARE | DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; - dsbdesc.dwBufferBytes = SOUNDSIZE; - dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf; - - dsval=IDirectSound_CreateSoundBuffer(lpDS,&dsbdesc,&lpDSBSECONDARY1,NULL); - if(dsval!=DS_OK) - { - dsbdesc.dwFlags = DSBCAPS_LOCSOFTWARE | DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; - dsval=IDirectSound_CreateSoundBuffer(lpDS,&dsbdesc,&lpDSBSECONDARY1,NULL); - if(dsval!=DS_OK) - { - MessageBox(hWMain,"CreateSoundBuffer (Secondary1)", "Error",MB_OK); - return; - } - } - - - - dsval=IDirectSoundBuffer_Play(lpDSBPRIMARY,0,0,DSBPLAY_LOOPING); - if(dsval!=DS_OK) - { - MessageBox(hWMain,"Play (Primary)","Error",MB_OK); - return; - } - - dsval=IDirectSoundBuffer_Play(lpDSBSECONDARY1,0,0,DSBPLAY_LOOPING); - if(dsval!=DS_OK) - { - MessageBox(hWMain,"Play (Secondary1)","Error",MB_OK); - return; - } - -} - -//////////////////////////////////////////////////////////////////////// -// REMOVE SOUND -//////////////////////////////////////////////////////////////////////// - -void RemoveSound(void) -{ - int iRes; - - if(iDoRecord) RecordStop(); - - if(lpDSBSECONDARY1!=NULL) - { - IDirectSoundBuffer_Stop(lpDSBSECONDARY1); - iRes=IDirectSoundBuffer_Release(lpDSBSECONDARY1); - // FF says such a loop is bad... Demo says it's good... Pete doesn't care - while(iRes!=0) iRes=IDirectSoundBuffer_Release(lpDSBSECONDARY1); - lpDSBSECONDARY1=NULL; - } - - if(lpDSBPRIMARY!=NULL) - { - IDirectSoundBuffer_Stop(lpDSBPRIMARY); - iRes=IDirectSoundBuffer_Release(lpDSBPRIMARY); - // FF says such a loop is bad... Demo says it's good... Pete doesn't care - while(iRes!=0) iRes=IDirectSoundBuffer_Release(lpDSBPRIMARY); - lpDSBPRIMARY=NULL; - } - - if(lpDS!=NULL) - { - iRes=IDirectSound_Release(lpDS); - // FF says such a loop is bad... Demo says it's good... Pete doesn't care - while(iRes!=0) iRes=IDirectSound_Release(lpDS); - lpDS=NULL; - } - -} - -//////////////////////////////////////////////////////////////////////// -// GET BYTES BUFFERED -//////////////////////////////////////////////////////////////////////// - -unsigned long SoundGetBytesBuffered(void) -{ - unsigned long cplay,cwrite; - - if(LastWrite==0xffffffff) return 0; - - IDirectSoundBuffer_GetCurrentPosition(lpDSBSECONDARY1,&cplay,&cwrite); - - if(cplay>SOUNDSIZE) return SOUNDSIZE; - - if(cplay>2; - - lpSS=(unsigned long *)pSound; - while(dw) {*lpSD++=*lpSS++;dw--;} - - if(lpvPtr2) - { - lpSD=(unsigned long *)lpvPtr2; - dw=dwBytes2>>2; - while(dw) {*lpSD++=*lpSS++;dw--;} - } - - IDirectSoundBuffer_Unlock(lpDSBSECONDARY1,lpvPtr1,dwBytes1,lpvPtr2,dwBytes2); - LastWrite+=lBytes; - if(LastWrite>=SOUNDSIZE) LastWrite-=SOUNDSIZE; - LastPlay=cplay; -} -#endif - - - +/*************************************************************************** + dsound.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2005/08/29 - Pete +// - changed to 48Khz output +// +// 2003/01/12 - Pete +// - added recording funcs +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_DSOUND + +#include "externals.h" + +#ifdef _WINDOWS +#define _LPCWAVEFORMATEX_DEFINED +#include "dsound.h" + +#include "record.h" + +//////////////////////////////////////////////////////////////////////// +// dsound globals +//////////////////////////////////////////////////////////////////////// + +LPDIRECTSOUND lpDS; +LPDIRECTSOUNDBUFFER lpDSBPRIMARY = NULL; +LPDIRECTSOUNDBUFFER lpDSBSECONDARY1 = NULL; +LPDIRECTSOUNDBUFFER lpDSBSECONDARY2 = NULL; +DSBUFFERDESC dsbd; +DSBUFFERDESC dsbdesc; +DSCAPS dscaps; +DSBCAPS dsbcaps; + +unsigned long LastWrite=0xffffffff; +unsigned long LastWriteS=0xffffffff; +unsigned long LastPlay=0; + +//////////////////////////////////////////////////////////////////////// +// SETUP SOUND +//////////////////////////////////////////////////////////////////////// + +void SetupSound(void) +{ + HRESULT dsval;WAVEFORMATEX pcmwf; + + dsval = DirectSoundCreate(NULL,&lpDS,NULL); + if(dsval!=DS_OK) + { + MessageBox(hWMain,"DirectSoundCreate!","Error",MB_OK); + return; + } + + if(DS_OK!=IDirectSound_SetCooperativeLevel(lpDS,hWMain, DSSCL_PRIORITY)) + { + if(DS_OK!=IDirectSound_SetCooperativeLevel(lpDS,hWMain, DSSCL_NORMAL)) + { + MessageBox(hWMain,"SetCooperativeLevel!","Error",MB_OK); + return; + } + } + + memset(&dsbd,0,sizeof(DSBUFFERDESC)); + dsbd.dwSize = sizeof(DSBUFFERDESC); // NT4 hack! sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; + dsbd.dwBufferBytes = 0; + dsbd.lpwfxFormat = NULL; + + dsval=IDirectSound_CreateSoundBuffer(lpDS,&dsbd,&lpDSBPRIMARY,NULL); + if(dsval!=DS_OK) + { + MessageBox(hWMain, "CreateSoundBuffer (Primary)", "Error",MB_OK); + return; + } + + memset(&pcmwf, 0, sizeof(WAVEFORMATEX)); + pcmwf.wFormatTag = WAVE_FORMAT_PCM; + + pcmwf.nChannels = 2; + pcmwf.nBlockAlign = 4; + + pcmwf.nSamplesPerSec = 48000; + + pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign; + pcmwf.wBitsPerSample = 16; + + dsval=IDirectSoundBuffer_SetFormat(lpDSBPRIMARY,&pcmwf); + if(dsval!=DS_OK) + { + MessageBox(hWMain, "SetFormat!", "Error",MB_OK); + return; + } + + dscaps.dwSize = sizeof(DSCAPS); + dsbcaps.dwSize = sizeof(DSBCAPS); + IDirectSound_GetCaps(lpDS,&dscaps); + IDirectSoundBuffer_GetCaps(lpDSBPRIMARY,&dsbcaps); + + memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); + dsbdesc.dwSize = sizeof(DSBUFFERDESC); // NT4 hack! sizeof(DSBUFFERDESC); + dsbdesc.dwFlags = DSBCAPS_LOCHARDWARE | DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; + dsbdesc.dwBufferBytes = SOUNDSIZE; + dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf; + + dsval=IDirectSound_CreateSoundBuffer(lpDS,&dsbdesc,&lpDSBSECONDARY1,NULL); + if(dsval!=DS_OK) + { + dsbdesc.dwFlags = DSBCAPS_LOCSOFTWARE | DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; + dsval=IDirectSound_CreateSoundBuffer(lpDS,&dsbdesc,&lpDSBSECONDARY1,NULL); + if(dsval!=DS_OK) + { + MessageBox(hWMain,"CreateSoundBuffer (Secondary1)", "Error",MB_OK); + return; + } + } + + + + dsval=IDirectSoundBuffer_Play(lpDSBPRIMARY,0,0,DSBPLAY_LOOPING); + if(dsval!=DS_OK) + { + MessageBox(hWMain,"Play (Primary)","Error",MB_OK); + return; + } + + dsval=IDirectSoundBuffer_Play(lpDSBSECONDARY1,0,0,DSBPLAY_LOOPING); + if(dsval!=DS_OK) + { + MessageBox(hWMain,"Play (Secondary1)","Error",MB_OK); + return; + } + +} + +//////////////////////////////////////////////////////////////////////// +// REMOVE SOUND +//////////////////////////////////////////////////////////////////////// + +void RemoveSound(void) +{ + int iRes; + + if(iDoRecord) RecordStop(); + + if(lpDSBSECONDARY1!=NULL) + { + IDirectSoundBuffer_Stop(lpDSBSECONDARY1); + iRes=IDirectSoundBuffer_Release(lpDSBSECONDARY1); + // FF says such a loop is bad... Demo says it's good... Pete doesn't care + while(iRes!=0) iRes=IDirectSoundBuffer_Release(lpDSBSECONDARY1); + lpDSBSECONDARY1=NULL; + } + + if(lpDSBPRIMARY!=NULL) + { + IDirectSoundBuffer_Stop(lpDSBPRIMARY); + iRes=IDirectSoundBuffer_Release(lpDSBPRIMARY); + // FF says such a loop is bad... Demo says it's good... Pete doesn't care + while(iRes!=0) iRes=IDirectSoundBuffer_Release(lpDSBPRIMARY); + lpDSBPRIMARY=NULL; + } + + if(lpDS!=NULL) + { + iRes=IDirectSound_Release(lpDS); + // FF says such a loop is bad... Demo says it's good... Pete doesn't care + while(iRes!=0) iRes=IDirectSound_Release(lpDS); + lpDS=NULL; + } + +} + +//////////////////////////////////////////////////////////////////////// +// GET BYTES BUFFERED +//////////////////////////////////////////////////////////////////////// + +unsigned long SoundGetBytesBuffered(void) +{ + unsigned long cplay,cwrite; + + if(LastWrite==0xffffffff) return 0; + + IDirectSoundBuffer_GetCurrentPosition(lpDSBSECONDARY1,&cplay,&cwrite); + + if(cplay>SOUNDSIZE) return SOUNDSIZE; + + if(cplay>2; + + lpSS=(unsigned long *)pSound; + while(dw) {*lpSD++=*lpSS++;dw--;} + + if(lpvPtr2) + { + lpSD=(unsigned long *)lpvPtr2; + dw=dwBytes2>>2; + while(dw) {*lpSD++=*lpSS++;dw--;} + } + + IDirectSoundBuffer_Unlock(lpDSBSECONDARY1,lpvPtr1,dwBytes1,lpvPtr2,dwBytes2); + LastWrite+=lBytes; + if(LastWrite>=SOUNDSIZE) LastWrite-=SOUNDSIZE; + LastPlay=cplay; +} +#endif + + + diff --git a/plugins/PeopsSPU2/dsound.h b/plugins/PeopsSPU2/dsound.h index f03fff1da9..92cf31365d 100644 --- a/plugins/PeopsSPU2/dsound.h +++ b/plugins/PeopsSPU2/dsound.h @@ -1,2357 +1,2357 @@ -/*==========================================================================; - * - * Copyright (c) Microsoft Corporation. All rights reserved. - * - * File: dsound.h - * Content: DirectSound include file - * - **************************************************************************/ - -#define COM_NO_WINDOWS_H -#include -#include - -#ifndef DIRECTSOUND_VERSION -#define DIRECTSOUND_VERSION 0x0900 /* Version 9.0 */ -#endif - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -#ifndef __DSOUND_INCLUDED__ -#define __DSOUND_INCLUDED__ - -/* Type definitions shared with Direct3D */ - -#ifndef DX_SHARED_DEFINES - -typedef float D3DVALUE, *LPD3DVALUE; - -#ifndef D3DCOLOR_DEFINED -typedef DWORD D3DCOLOR; -#define D3DCOLOR_DEFINED -#endif - -#ifndef LPD3DCOLOR_DEFINED -typedef DWORD *LPD3DCOLOR; -#define LPD3DCOLOR_DEFINED -#endif - -#ifndef D3DVECTOR_DEFINED -typedef struct _D3DVECTOR { - float x; - float y; - float z; -} D3DVECTOR; -#define D3DVECTOR_DEFINED -#endif - -#ifndef LPD3DVECTOR_DEFINED -typedef D3DVECTOR *LPD3DVECTOR; -#define LPD3DVECTOR_DEFINED -#endif - -#define DX_SHARED_DEFINES -#endif // DX_SHARED_DEFINES - -#define _FACDS 0x878 /* DirectSound's facility code */ -#define MAKE_DSHRESULT(code) MAKE_HRESULT(1, _FACDS, code) - -// DirectSound Component GUID {47D4D946-62E8-11CF-93BC-444553540000} -DEFINE_GUID(CLSID_DirectSound, 0x47d4d946, 0x62e8, 0x11cf, 0x93, 0xbc, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0); - -// DirectSound 8.0 Component GUID {3901CC3F-84B5-4FA4-BA35-AA8172B8A09B} -DEFINE_GUID(CLSID_DirectSound8, 0x3901cc3f, 0x84b5, 0x4fa4, 0xba, 0x35, 0xaa, 0x81, 0x72, 0xb8, 0xa0, 0x9b); - -// DirectSound Capture Component GUID {B0210780-89CD-11D0-AF08-00A0C925CD16} -DEFINE_GUID(CLSID_DirectSoundCapture, 0xb0210780, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); - -// DirectSound 8.0 Capture Component GUID {E4BCAC13-7F99-4908-9A8E-74E3BF24B6E1} -DEFINE_GUID(CLSID_DirectSoundCapture8, 0xe4bcac13, 0x7f99, 0x4908, 0x9a, 0x8e, 0x74, 0xe3, 0xbf, 0x24, 0xb6, 0xe1); - -// DirectSound Full Duplex Component GUID {FEA4300C-7959-4147-B26A-2377B9E7A91D} -DEFINE_GUID(CLSID_DirectSoundFullDuplex, 0xfea4300c, 0x7959, 0x4147, 0xb2, 0x6a, 0x23, 0x77, 0xb9, 0xe7, 0xa9, 0x1d); - - -// DirectSound default playback device GUID {DEF00000-9C6D-47ED-AAF1-4DDA8F2B5C03} -DEFINE_GUID(DSDEVID_DefaultPlayback, 0xdef00000, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03); - -// DirectSound default capture device GUID {DEF00001-9C6D-47ED-AAF1-4DDA8F2B5C03} -DEFINE_GUID(DSDEVID_DefaultCapture, 0xdef00001, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03); - -// DirectSound default device for voice playback {DEF00002-9C6D-47ED-AAF1-4DDA8F2B5C03} -DEFINE_GUID(DSDEVID_DefaultVoicePlayback, 0xdef00002, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03); - -// DirectSound default device for voice capture {DEF00003-9C6D-47ED-AAF1-4DDA8F2B5C03} -DEFINE_GUID(DSDEVID_DefaultVoiceCapture, 0xdef00003, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03); - - -// -// Forward declarations for interfaces. -// 'struct' not 'class' per the way DECLARE_INTERFACE_ is defined -// - -#ifdef __cplusplus -struct IDirectSound; -struct IDirectSoundBuffer; -struct IDirectSound3DListener; -struct IDirectSound3DBuffer; -struct IDirectSoundCapture; -struct IDirectSoundCaptureBuffer; -struct IDirectSoundNotify; -#endif // __cplusplus - - -// -// DirectSound 8.0 interfaces. -// - -#if DIRECTSOUND_VERSION >= 0x0800 - -#ifdef __cplusplus -struct IDirectSound8; -struct IDirectSoundBuffer8; -struct IDirectSoundCaptureBuffer8; -struct IDirectSoundFXGargle; -struct IDirectSoundFXChorus; -struct IDirectSoundFXFlanger; -struct IDirectSoundFXEcho; -struct IDirectSoundFXDistortion; -struct IDirectSoundFXCompressor; -struct IDirectSoundFXParamEq; -struct IDirectSoundFXWavesReverb; -struct IDirectSoundFXI3DL2Reverb; -struct IDirectSoundCaptureFXAec; -struct IDirectSoundCaptureFXNoiseSuppress; -struct IDirectSoundFullDuplex; -#endif // __cplusplus - -// IDirectSound8, IDirectSoundBuffer8 and IDirectSoundCaptureBuffer8 are the -// only DirectSound 7.0 interfaces with changed functionality in version 8.0. -// The other level 8 interfaces as equivalent to their level 7 counterparts: - -#define IDirectSoundCapture8 IDirectSoundCapture -#define IDirectSound3DListener8 IDirectSound3DListener -#define IDirectSound3DBuffer8 IDirectSound3DBuffer -#define IDirectSoundNotify8 IDirectSoundNotify -#define IDirectSoundFXGargle8 IDirectSoundFXGargle -#define IDirectSoundFXChorus8 IDirectSoundFXChorus -#define IDirectSoundFXFlanger8 IDirectSoundFXFlanger -#define IDirectSoundFXEcho8 IDirectSoundFXEcho -#define IDirectSoundFXDistortion8 IDirectSoundFXDistortion -#define IDirectSoundFXCompressor8 IDirectSoundFXCompressor -#define IDirectSoundFXParamEq8 IDirectSoundFXParamEq -#define IDirectSoundFXWavesReverb8 IDirectSoundFXWavesReverb -#define IDirectSoundFXI3DL2Reverb8 IDirectSoundFXI3DL2Reverb -#define IDirectSoundCaptureFXAec8 IDirectSoundCaptureFXAec -#define IDirectSoundCaptureFXNoiseSuppress8 IDirectSoundCaptureFXNoiseSuppress -#define IDirectSoundFullDuplex8 IDirectSoundFullDuplex - -#endif // DIRECTSOUND_VERSION >= 0x0800 - -typedef struct IDirectSound *LPDIRECTSOUND; -typedef struct IDirectSoundBuffer *LPDIRECTSOUNDBUFFER; -typedef struct IDirectSound3DListener *LPDIRECTSOUND3DLISTENER; -typedef struct IDirectSound3DBuffer *LPDIRECTSOUND3DBUFFER; -typedef struct IDirectSoundCapture *LPDIRECTSOUNDCAPTURE; -typedef struct IDirectSoundCaptureBuffer *LPDIRECTSOUNDCAPTUREBUFFER; -typedef struct IDirectSoundNotify *LPDIRECTSOUNDNOTIFY; - - -#if DIRECTSOUND_VERSION >= 0x0800 - -typedef struct IDirectSoundFXGargle *LPDIRECTSOUNDFXGARGLE; -typedef struct IDirectSoundFXChorus *LPDIRECTSOUNDFXCHORUS; -typedef struct IDirectSoundFXFlanger *LPDIRECTSOUNDFXFLANGER; -typedef struct IDirectSoundFXEcho *LPDIRECTSOUNDFXECHO; -typedef struct IDirectSoundFXDistortion *LPDIRECTSOUNDFXDISTORTION; -typedef struct IDirectSoundFXCompressor *LPDIRECTSOUNDFXCOMPRESSOR; -typedef struct IDirectSoundFXParamEq *LPDIRECTSOUNDFXPARAMEQ; -typedef struct IDirectSoundFXWavesReverb *LPDIRECTSOUNDFXWAVESREVERB; -typedef struct IDirectSoundFXI3DL2Reverb *LPDIRECTSOUNDFXI3DL2REVERB; -typedef struct IDirectSoundCaptureFXAec *LPDIRECTSOUNDCAPTUREFXAEC; -typedef struct IDirectSoundCaptureFXNoiseSuppress *LPDIRECTSOUNDCAPTUREFXNOISESUPPRESS; -typedef struct IDirectSoundFullDuplex *LPDIRECTSOUNDFULLDUPLEX; - -typedef struct IDirectSound8 *LPDIRECTSOUND8; -typedef struct IDirectSoundBuffer8 *LPDIRECTSOUNDBUFFER8; -typedef struct IDirectSound3DListener8 *LPDIRECTSOUND3DLISTENER8; -typedef struct IDirectSound3DBuffer8 *LPDIRECTSOUND3DBUFFER8; -typedef struct IDirectSoundCapture8 *LPDIRECTSOUNDCAPTURE8; -typedef struct IDirectSoundCaptureBuffer8 *LPDIRECTSOUNDCAPTUREBUFFER8; -typedef struct IDirectSoundNotify8 *LPDIRECTSOUNDNOTIFY8; -typedef struct IDirectSoundFXGargle8 *LPDIRECTSOUNDFXGARGLE8; -typedef struct IDirectSoundFXChorus8 *LPDIRECTSOUNDFXCHORUS8; -typedef struct IDirectSoundFXFlanger8 *LPDIRECTSOUNDFXFLANGER8; -typedef struct IDirectSoundFXEcho8 *LPDIRECTSOUNDFXECHO8; -typedef struct IDirectSoundFXDistortion8 *LPDIRECTSOUNDFXDISTORTION8; -typedef struct IDirectSoundFXCompressor8 *LPDIRECTSOUNDFXCOMPRESSOR8; -typedef struct IDirectSoundFXParamEq8 *LPDIRECTSOUNDFXPARAMEQ8; -typedef struct IDirectSoundFXWavesReverb8 *LPDIRECTSOUNDFXWAVESREVERB8; -typedef struct IDirectSoundFXI3DL2Reverb8 *LPDIRECTSOUNDFXI3DL2REVERB8; -typedef struct IDirectSoundCaptureFXAec8 *LPDIRECTSOUNDCAPTUREFXAEC8; -typedef struct IDirectSoundCaptureFXNoiseSuppress8 *LPDIRECTSOUNDCAPTUREFXNOISESUPPRESS8; -typedef struct IDirectSoundFullDuplex8 *LPDIRECTSOUNDFULLDUPLEX8; - -#endif // DIRECTSOUND_VERSION >= 0x0800 - -// -// IID definitions for the unchanged DirectSound 8.0 interfaces -// - -#if DIRECTSOUND_VERSION >= 0x0800 - -#define IID_IDirectSoundCapture8 IID_IDirectSoundCapture -#define IID_IDirectSound3DListener8 IID_IDirectSound3DListener -#define IID_IDirectSound3DBuffer8 IID_IDirectSound3DBuffer -#define IID_IDirectSoundNotify8 IID_IDirectSoundNotify -#define IID_IDirectSoundFXGargle8 IID_IDirectSoundFXGargle -#define IID_IDirectSoundFXChorus8 IID_IDirectSoundFXChorus -#define IID_IDirectSoundFXFlanger8 IID_IDirectSoundFXFlanger -#define IID_IDirectSoundFXEcho8 IID_IDirectSoundFXEcho -#define IID_IDirectSoundFXDistortion8 IID_IDirectSoundFXDistortion -#define IID_IDirectSoundFXCompressor8 IID_IDirectSoundFXCompressor -#define IID_IDirectSoundFXParamEq8 IID_IDirectSoundFXParamEq -#define IID_IDirectSoundFXWavesReverb8 IID_IDirectSoundFXWavesReverb -#define IID_IDirectSoundFXI3DL2Reverb8 IID_IDirectSoundFXI3DL2Reverb -#define IID_IDirectSoundCaptureFXAec8 IID_IDirectSoundCaptureFXAec -#define IID_IDirectSoundCaptureFXNoiseSuppress8 IID_IDirectSoundCaptureFXNoiseSuppress -#define IID_IDirectSoundFullDuplex8 IID_IDirectSoundFullDuplex - -#endif // DIRECTSOUND_VERSION >= 0x0800 - -// -// Compatibility typedefs -// - -#ifndef _LPCWAVEFORMATEX_DEFINED -#define _LPCWAVEFORMATEX_DEFINED -typedef const WAVEFORMATEX *LPCWAVEFORMATEX; -#endif // _LPCWAVEFORMATEX_DEFINED - -#ifndef __LPCGUID_DEFINED__ -#define __LPCGUID_DEFINED__ -typedef const GUID *LPCGUID; -#endif // __LPCGUID_DEFINED__ - -typedef LPDIRECTSOUND *LPLPDIRECTSOUND; -typedef LPDIRECTSOUNDBUFFER *LPLPDIRECTSOUNDBUFFER; -typedef LPDIRECTSOUND3DLISTENER *LPLPDIRECTSOUND3DLISTENER; -typedef LPDIRECTSOUND3DBUFFER *LPLPDIRECTSOUND3DBUFFER; -typedef LPDIRECTSOUNDCAPTURE *LPLPDIRECTSOUNDCAPTURE; -typedef LPDIRECTSOUNDCAPTUREBUFFER *LPLPDIRECTSOUNDCAPTUREBUFFER; -typedef LPDIRECTSOUNDNOTIFY *LPLPDIRECTSOUNDNOTIFY; - -#if DIRECTSOUND_VERSION >= 0x0800 -typedef LPDIRECTSOUND8 *LPLPDIRECTSOUND8; -typedef LPDIRECTSOUNDBUFFER8 *LPLPDIRECTSOUNDBUFFER8; -typedef LPDIRECTSOUNDCAPTURE8 *LPLPDIRECTSOUNDCAPTURE8; -typedef LPDIRECTSOUNDCAPTUREBUFFER8 *LPLPDIRECTSOUNDCAPTUREBUFFER8; -#endif // DIRECTSOUND_VERSION >= 0x0800 - -// -// Structures -// - -typedef struct _DSCAPS -{ - DWORD dwSize; - DWORD dwFlags; - DWORD dwMinSecondarySampleRate; - DWORD dwMaxSecondarySampleRate; - DWORD dwPrimaryBuffers; - DWORD dwMaxHwMixingAllBuffers; - DWORD dwMaxHwMixingStaticBuffers; - DWORD dwMaxHwMixingStreamingBuffers; - DWORD dwFreeHwMixingAllBuffers; - DWORD dwFreeHwMixingStaticBuffers; - DWORD dwFreeHwMixingStreamingBuffers; - DWORD dwMaxHw3DAllBuffers; - DWORD dwMaxHw3DStaticBuffers; - DWORD dwMaxHw3DStreamingBuffers; - DWORD dwFreeHw3DAllBuffers; - DWORD dwFreeHw3DStaticBuffers; - DWORD dwFreeHw3DStreamingBuffers; - DWORD dwTotalHwMemBytes; - DWORD dwFreeHwMemBytes; - DWORD dwMaxContigFreeHwMemBytes; - DWORD dwUnlockTransferRateHwBuffers; - DWORD dwPlayCpuOverheadSwBuffers; - DWORD dwReserved1; - DWORD dwReserved2; -} DSCAPS, *LPDSCAPS; - -typedef const DSCAPS *LPCDSCAPS; - -typedef struct _DSBCAPS -{ - DWORD dwSize; - DWORD dwFlags; - DWORD dwBufferBytes; - DWORD dwUnlockTransferRate; - DWORD dwPlayCpuOverhead; -} DSBCAPS, *LPDSBCAPS; - -typedef const DSBCAPS *LPCDSBCAPS; - -#if DIRECTSOUND_VERSION >= 0x0800 - - typedef struct _DSEFFECTDESC - { - DWORD dwSize; - DWORD dwFlags; - GUID guidDSFXClass; - DWORD_PTR dwReserved1; - DWORD_PTR dwReserved2; - } DSEFFECTDESC, *LPDSEFFECTDESC; - typedef const DSEFFECTDESC *LPCDSEFFECTDESC; - - #define DSFX_LOCHARDWARE 0x00000001 - #define DSFX_LOCSOFTWARE 0x00000002 - - enum - { - DSFXR_PRESENT, // 0 - DSFXR_LOCHARDWARE, // 1 - DSFXR_LOCSOFTWARE, // 2 - DSFXR_UNALLOCATED, // 3 - DSFXR_FAILED, // 4 - DSFXR_UNKNOWN, // 5 - DSFXR_SENDLOOP // 6 - }; - - typedef struct _DSCEFFECTDESC - { - DWORD dwSize; - DWORD dwFlags; - GUID guidDSCFXClass; - GUID guidDSCFXInstance; - DWORD dwReserved1; - DWORD dwReserved2; - } DSCEFFECTDESC, *LPDSCEFFECTDESC; - typedef const DSCEFFECTDESC *LPCDSCEFFECTDESC; - - #define DSCFX_LOCHARDWARE 0x00000001 - #define DSCFX_LOCSOFTWARE 0x00000002 - - #define DSCFXR_LOCHARDWARE 0x00000010 - #define DSCFXR_LOCSOFTWARE 0x00000020 - -#endif // DIRECTSOUND_VERSION >= 0x0800 - -typedef struct _DSBUFFERDESC -{ - DWORD dwSize; - DWORD dwFlags; - DWORD dwBufferBytes; - DWORD dwReserved; - LPWAVEFORMATEX lpwfxFormat; -#if DIRECTSOUND_VERSION >= 0x0700 - GUID guid3DAlgorithm; -#endif -} DSBUFFERDESC, *LPDSBUFFERDESC; - -typedef const DSBUFFERDESC *LPCDSBUFFERDESC; - -// Older version of this structure: - -typedef struct _DSBUFFERDESC1 -{ - DWORD dwSize; - DWORD dwFlags; - DWORD dwBufferBytes; - DWORD dwReserved; - LPWAVEFORMATEX lpwfxFormat; -} DSBUFFERDESC1, *LPDSBUFFERDESC1; - -typedef const DSBUFFERDESC1 *LPCDSBUFFERDESC1; - -typedef struct _DS3DBUFFER -{ - DWORD dwSize; - D3DVECTOR vPosition; - D3DVECTOR vVelocity; - DWORD dwInsideConeAngle; - DWORD dwOutsideConeAngle; - D3DVECTOR vConeOrientation; - LONG lConeOutsideVolume; - D3DVALUE flMinDistance; - D3DVALUE flMaxDistance; - DWORD dwMode; -} DS3DBUFFER, *LPDS3DBUFFER; - -typedef const DS3DBUFFER *LPCDS3DBUFFER; - -typedef struct _DS3DLISTENER -{ - DWORD dwSize; - D3DVECTOR vPosition; - D3DVECTOR vVelocity; - D3DVECTOR vOrientFront; - D3DVECTOR vOrientTop; - D3DVALUE flDistanceFactor; - D3DVALUE flRolloffFactor; - D3DVALUE flDopplerFactor; -} DS3DLISTENER, *LPDS3DLISTENER; - -typedef const DS3DLISTENER *LPCDS3DLISTENER; - -typedef struct _DSCCAPS -{ - DWORD dwSize; - DWORD dwFlags; - DWORD dwFormats; - DWORD dwChannels; -} DSCCAPS, *LPDSCCAPS; - -typedef const DSCCAPS *LPCDSCCAPS; - -typedef struct _DSCBUFFERDESC1 -{ - DWORD dwSize; - DWORD dwFlags; - DWORD dwBufferBytes; - DWORD dwReserved; - LPWAVEFORMATEX lpwfxFormat; -} DSCBUFFERDESC1, *LPDSCBUFFERDESC1; - -typedef struct _DSCBUFFERDESC -{ - DWORD dwSize; - DWORD dwFlags; - DWORD dwBufferBytes; - DWORD dwReserved; - LPWAVEFORMATEX lpwfxFormat; -#if DIRECTSOUND_VERSION >= 0x0800 - DWORD dwFXCount; - LPDSCEFFECTDESC lpDSCFXDesc; -#endif -} DSCBUFFERDESC, *LPDSCBUFFERDESC; - -typedef const DSCBUFFERDESC *LPCDSCBUFFERDESC; - -typedef struct _DSCBCAPS -{ - DWORD dwSize; - DWORD dwFlags; - DWORD dwBufferBytes; - DWORD dwReserved; -} DSCBCAPS, *LPDSCBCAPS; - -typedef const DSCBCAPS *LPCDSCBCAPS; - -typedef struct _DSBPOSITIONNOTIFY -{ - DWORD dwOffset; - HANDLE hEventNotify; -} DSBPOSITIONNOTIFY, *LPDSBPOSITIONNOTIFY; - -typedef const DSBPOSITIONNOTIFY *LPCDSBPOSITIONNOTIFY; - -// -// DirectSound API -// - -typedef BOOL (CALLBACK *LPDSENUMCALLBACKA)(LPGUID, LPCSTR, LPCSTR, LPVOID); -typedef BOOL (CALLBACK *LPDSENUMCALLBACKW)(LPGUID, LPCWSTR, LPCWSTR, LPVOID); - -extern HRESULT WINAPI DirectSoundCreate(LPCGUID pcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter); -extern HRESULT WINAPI DirectSoundEnumerateA(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext); -extern HRESULT WINAPI DirectSoundEnumerateW(LPDSENUMCALLBACKW pDSEnumCallback, LPVOID pContext); - -extern HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID pcGuidDevice, LPDIRECTSOUNDCAPTURE *ppDSC, LPUNKNOWN pUnkOuter); -extern HRESULT WINAPI DirectSoundCaptureEnumerateA(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext); -extern HRESULT WINAPI DirectSoundCaptureEnumerateW(LPDSENUMCALLBACKW pDSEnumCallback, LPVOID pContext); - -#if DIRECTSOUND_VERSION >= 0x0800 -extern HRESULT WINAPI DirectSoundCreate8(LPCGUID pcGuidDevice, LPDIRECTSOUND8 *ppDS8, LPUNKNOWN pUnkOuter); -extern HRESULT WINAPI DirectSoundCaptureCreate8(LPCGUID pcGuidDevice, LPDIRECTSOUNDCAPTURE8 *ppDSC8, LPUNKNOWN pUnkOuter); -extern HRESULT WINAPI DirectSoundFullDuplexCreate(LPCGUID pcGuidCaptureDevice, LPCGUID pcGuidRenderDevice, - LPCDSCBUFFERDESC pcDSCBufferDesc, LPCDSBUFFERDESC pcDSBufferDesc, HWND hWnd, - DWORD dwLevel, LPDIRECTSOUNDFULLDUPLEX* ppDSFD, LPDIRECTSOUNDCAPTUREBUFFER8 *ppDSCBuffer8, - LPDIRECTSOUNDBUFFER8 *ppDSBuffer8, LPUNKNOWN pUnkOuter); -#define DirectSoundFullDuplexCreate8 DirectSoundFullDuplexCreate - -extern HRESULT WINAPI GetDeviceID(LPCGUID pGuidSrc, LPGUID pGuidDest); -#endif // DIRECTSOUND_VERSION >= 0x0800 - -#ifdef UNICODE -#define LPDSENUMCALLBACK LPDSENUMCALLBACKW -#define DirectSoundEnumerate DirectSoundEnumerateW -#define DirectSoundCaptureEnumerate DirectSoundCaptureEnumerateW -#else // UNICODE -#define LPDSENUMCALLBACK LPDSENUMCALLBACKA -#define DirectSoundEnumerate DirectSoundEnumerateA -#define DirectSoundCaptureEnumerate DirectSoundCaptureEnumerateA -#endif // UNICODE - -// -// IUnknown -// - -#if !defined(__cplusplus) || defined(CINTERFACE) -#ifndef IUnknown_QueryInterface -#define IUnknown_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) -#endif // IUnknown_QueryInterface -#ifndef IUnknown_AddRef -#define IUnknown_AddRef(p) (p)->lpVtbl->AddRef(p) -#endif // IUnknown_AddRef -#ifndef IUnknown_Release -#define IUnknown_Release(p) (p)->lpVtbl->Release(p) -#endif // IUnknown_Release -#else // !defined(__cplusplus) || defined(CINTERFACE) -#ifndef IUnknown_QueryInterface -#define IUnknown_QueryInterface(p,a,b) (p)->QueryInterface(a,b) -#endif // IUnknown_QueryInterface -#ifndef IUnknown_AddRef -#define IUnknown_AddRef(p) (p)->AddRef() -#endif // IUnknown_AddRef -#ifndef IUnknown_Release -#define IUnknown_Release(p) (p)->Release() -#endif // IUnknown_Release -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -#ifndef __IReferenceClock_INTERFACE_DEFINED__ -#define __IReferenceClock_INTERFACE_DEFINED__ - -typedef LONGLONG REFERENCE_TIME; -typedef REFERENCE_TIME *LPREFERENCE_TIME; - -DEFINE_GUID(IID_IReferenceClock, 0x56a86897, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); - -#undef INTERFACE -#define INTERFACE IReferenceClock - -DECLARE_INTERFACE_(IReferenceClock, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IReferenceClock methods - STDMETHOD(GetTime) (THIS_ REFERENCE_TIME *pTime) PURE; - STDMETHOD(AdviseTime) (THIS_ REFERENCE_TIME rtBaseTime, REFERENCE_TIME rtStreamTime, - HANDLE hEvent, LPDWORD pdwAdviseCookie) PURE; - STDMETHOD(AdvisePeriodic) (THIS_ REFERENCE_TIME rtStartTime, REFERENCE_TIME rtPeriodTime, - HANDLE hSemaphore, LPDWORD pdwAdviseCookie) PURE; - STDMETHOD(Unadvise) (THIS_ DWORD dwAdviseCookie) PURE; -}; - -#endif // __IReferenceClock_INTERFACE_DEFINED__ - -#ifndef IReferenceClock_QueryInterface - -#define IReferenceClock_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IReferenceClock_AddRef(p) IUnknown_AddRef(p) -#define IReferenceClock_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IReferenceClock_GetTime(p,a) (p)->lpVtbl->GetTime(p,a) -#define IReferenceClock_AdviseTime(p,a,b,c,d) (p)->lpVtbl->AdviseTime(p,a,b,c,d) -#define IReferenceClock_AdvisePeriodic(p,a,b,c,d) (p)->lpVtbl->AdvisePeriodic(p,a,b,c,d) -#define IReferenceClock_Unadvise(p,a) (p)->lpVtbl->Unadvise(p,a) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IReferenceClock_GetTime(p,a) (p)->GetTime(a) -#define IReferenceClock_AdviseTime(p,a,b,c,d) (p)->AdviseTime(a,b,c,d) -#define IReferenceClock_AdvisePeriodic(p,a,b,c,d) (p)->AdvisePeriodic(a,b,c,d) -#define IReferenceClock_Unadvise(p,a) (p)->Unadvise(a) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -#endif // IReferenceClock_QueryInterface - -// -// IDirectSound -// - -DEFINE_GUID(IID_IDirectSound, 0x279AFA83, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); - -#undef INTERFACE -#define INTERFACE IDirectSound - -DECLARE_INTERFACE_(IDirectSound, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSound methods - STDMETHOD(CreateSoundBuffer) (THIS_ LPCDSBUFFERDESC pcDSBufferDesc, LPDIRECTSOUNDBUFFER *ppDSBuffer, LPUNKNOWN pUnkOuter) PURE; - STDMETHOD(GetCaps) (THIS_ LPDSCAPS pDSCaps) PURE; - STDMETHOD(DuplicateSoundBuffer) (THIS_ LPDIRECTSOUNDBUFFER pDSBufferOriginal, LPDIRECTSOUNDBUFFER *ppDSBufferDuplicate) PURE; - STDMETHOD(SetCooperativeLevel) (THIS_ HWND hwnd, DWORD dwLevel) PURE; - STDMETHOD(Compact) (THIS) PURE; - STDMETHOD(GetSpeakerConfig) (THIS_ LPDWORD pdwSpeakerConfig) PURE; - STDMETHOD(SetSpeakerConfig) (THIS_ DWORD dwSpeakerConfig) PURE; - STDMETHOD(Initialize) (THIS_ LPCGUID pcGuidDevice) PURE; -}; - -#define IDirectSound_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSound_AddRef(p) IUnknown_AddRef(p) -#define IDirectSound_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSound_CreateSoundBuffer(p,a,b,c) (p)->lpVtbl->CreateSoundBuffer(p,a,b,c) -#define IDirectSound_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) -#define IDirectSound_DuplicateSoundBuffer(p,a,b) (p)->lpVtbl->DuplicateSoundBuffer(p,a,b) -#define IDirectSound_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) -#define IDirectSound_Compact(p) (p)->lpVtbl->Compact(p) -#define IDirectSound_GetSpeakerConfig(p,a) (p)->lpVtbl->GetSpeakerConfig(p,a) -#define IDirectSound_SetSpeakerConfig(p,b) (p)->lpVtbl->SetSpeakerConfig(p,b) -#define IDirectSound_Initialize(p,a) (p)->lpVtbl->Initialize(p,a) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSound_CreateSoundBuffer(p,a,b,c) (p)->CreateSoundBuffer(a,b,c) -#define IDirectSound_GetCaps(p,a) (p)->GetCaps(a) -#define IDirectSound_DuplicateSoundBuffer(p,a,b) (p)->DuplicateSoundBuffer(a,b) -#define IDirectSound_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) -#define IDirectSound_Compact(p) (p)->Compact() -#define IDirectSound_GetSpeakerConfig(p,a) (p)->GetSpeakerConfig(a) -#define IDirectSound_SetSpeakerConfig(p,b) (p)->SetSpeakerConfig(b) -#define IDirectSound_Initialize(p,a) (p)->Initialize(a) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -#if DIRECTSOUND_VERSION >= 0x0800 - -// -// IDirectSound8 -// - -DEFINE_GUID(IID_IDirectSound8, 0xC50A7E93, 0xF395, 0x4834, 0x9E, 0xF6, 0x7F, 0xA9, 0x9D, 0xE5, 0x09, 0x66); - -#undef INTERFACE -#define INTERFACE IDirectSound8 - -DECLARE_INTERFACE_(IDirectSound8, IDirectSound) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSound methods - STDMETHOD(CreateSoundBuffer) (THIS_ LPCDSBUFFERDESC pcDSBufferDesc, LPDIRECTSOUNDBUFFER *ppDSBuffer, LPUNKNOWN pUnkOuter) PURE; - STDMETHOD(GetCaps) (THIS_ LPDSCAPS pDSCaps) PURE; - STDMETHOD(DuplicateSoundBuffer) (THIS_ LPDIRECTSOUNDBUFFER pDSBufferOriginal, LPDIRECTSOUNDBUFFER *ppDSBufferDuplicate) PURE; - STDMETHOD(SetCooperativeLevel) (THIS_ HWND hwnd, DWORD dwLevel) PURE; - STDMETHOD(Compact) (THIS) PURE; - STDMETHOD(GetSpeakerConfig) (THIS_ LPDWORD pdwSpeakerConfig) PURE; - STDMETHOD(SetSpeakerConfig) (THIS_ DWORD dwSpeakerConfig) PURE; - STDMETHOD(Initialize) (THIS_ LPCGUID pcGuidDevice) PURE; - - // IDirectSound8 methods - STDMETHOD(VerifyCertification) (THIS_ LPDWORD pdwCertified) PURE; -}; - -#define IDirectSound8_QueryInterface(p,a,b) IDirectSound_QueryInterface(p,a,b) -#define IDirectSound8_AddRef(p) IDirectSound_AddRef(p) -#define IDirectSound8_Release(p) IDirectSound_Release(p) -#define IDirectSound8_CreateSoundBuffer(p,a,b,c) IDirectSound_CreateSoundBuffer(p,a,b,c) -#define IDirectSound8_GetCaps(p,a) IDirectSound_GetCaps(p,a) -#define IDirectSound8_DuplicateSoundBuffer(p,a,b) IDirectSound_DuplicateSoundBuffer(p,a,b) -#define IDirectSound8_SetCooperativeLevel(p,a,b) IDirectSound_SetCooperativeLevel(p,a,b) -#define IDirectSound8_Compact(p) IDirectSound_Compact(p) -#define IDirectSound8_GetSpeakerConfig(p,a) IDirectSound_GetSpeakerConfig(p,a) -#define IDirectSound8_SetSpeakerConfig(p,a) IDirectSound_SetSpeakerConfig(p,a) -#define IDirectSound8_Initialize(p,a) IDirectSound_Initialize(p,a) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSound8_VerifyCertification(p,a) (p)->lpVtbl->VerifyCertification(p,a) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSound8_VerifyCertification(p,a) (p)->VerifyCertification(a) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -#endif // DIRECTSOUND_VERSION >= 0x0800 - -// -// IDirectSoundBuffer -// - -DEFINE_GUID(IID_IDirectSoundBuffer, 0x279AFA85, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); - -#undef INTERFACE -#define INTERFACE IDirectSoundBuffer - -DECLARE_INTERFACE_(IDirectSoundBuffer, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSoundBuffer methods - STDMETHOD(GetCaps) (THIS_ LPDSBCAPS pDSBufferCaps) PURE; - STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD pdwCurrentPlayCursor, LPDWORD pdwCurrentWriteCursor) PURE; - STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE; - STDMETHOD(GetVolume) (THIS_ LPLONG plVolume) PURE; - STDMETHOD(GetPan) (THIS_ LPLONG plPan) PURE; - STDMETHOD(GetFrequency) (THIS_ LPDWORD pdwFrequency) PURE; - STDMETHOD(GetStatus) (THIS_ LPDWORD pdwStatus) PURE; - STDMETHOD(Initialize) (THIS_ LPDIRECTSOUND pDirectSound, LPCDSBUFFERDESC pcDSBufferDesc) PURE; - STDMETHOD(Lock) (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1, - LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE; - STDMETHOD(Play) (THIS_ DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags) PURE; - STDMETHOD(SetCurrentPosition) (THIS_ DWORD dwNewPosition) PURE; - STDMETHOD(SetFormat) (THIS_ LPCWAVEFORMATEX pcfxFormat) PURE; - STDMETHOD(SetVolume) (THIS_ LONG lVolume) PURE; - STDMETHOD(SetPan) (THIS_ LONG lPan) PURE; - STDMETHOD(SetFrequency) (THIS_ DWORD dwFrequency) PURE; - STDMETHOD(Stop) (THIS) PURE; - STDMETHOD(Unlock) (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE; - STDMETHOD(Restore) (THIS) PURE; -}; - -#define IDirectSoundBuffer_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSoundBuffer_AddRef(p) IUnknown_AddRef(p) -#define IDirectSoundBuffer_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundBuffer_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) -#define IDirectSoundBuffer_GetCurrentPosition(p,a,b) (p)->lpVtbl->GetCurrentPosition(p,a,b) -#define IDirectSoundBuffer_GetFormat(p,a,b,c) (p)->lpVtbl->GetFormat(p,a,b,c) -#define IDirectSoundBuffer_GetVolume(p,a) (p)->lpVtbl->GetVolume(p,a) -#define IDirectSoundBuffer_GetPan(p,a) (p)->lpVtbl->GetPan(p,a) -#define IDirectSoundBuffer_GetFrequency(p,a) (p)->lpVtbl->GetFrequency(p,a) -#define IDirectSoundBuffer_GetStatus(p,a) (p)->lpVtbl->GetStatus(p,a) -#define IDirectSoundBuffer_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) -#define IDirectSoundBuffer_Lock(p,a,b,c,d,e,f,g) (p)->lpVtbl->Lock(p,a,b,c,d,e,f,g) -#define IDirectSoundBuffer_Play(p,a,b,c) (p)->lpVtbl->Play(p,a,b,c) -#define IDirectSoundBuffer_SetCurrentPosition(p,a) (p)->lpVtbl->SetCurrentPosition(p,a) -#define IDirectSoundBuffer_SetFormat(p,a) (p)->lpVtbl->SetFormat(p,a) -#define IDirectSoundBuffer_SetVolume(p,a) (p)->lpVtbl->SetVolume(p,a) -#define IDirectSoundBuffer_SetPan(p,a) (p)->lpVtbl->SetPan(p,a) -#define IDirectSoundBuffer_SetFrequency(p,a) (p)->lpVtbl->SetFrequency(p,a) -#define IDirectSoundBuffer_Stop(p) (p)->lpVtbl->Stop(p) -#define IDirectSoundBuffer_Unlock(p,a,b,c,d) (p)->lpVtbl->Unlock(p,a,b,c,d) -#define IDirectSoundBuffer_Restore(p) (p)->lpVtbl->Restore(p) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundBuffer_GetCaps(p,a) (p)->GetCaps(a) -#define IDirectSoundBuffer_GetCurrentPosition(p,a,b) (p)->GetCurrentPosition(a,b) -#define IDirectSoundBuffer_GetFormat(p,a,b,c) (p)->GetFormat(a,b,c) -#define IDirectSoundBuffer_GetVolume(p,a) (p)->GetVolume(a) -#define IDirectSoundBuffer_GetPan(p,a) (p)->GetPan(a) -#define IDirectSoundBuffer_GetFrequency(p,a) (p)->GetFrequency(a) -#define IDirectSoundBuffer_GetStatus(p,a) (p)->GetStatus(a) -#define IDirectSoundBuffer_Initialize(p,a,b) (p)->Initialize(a,b) -#define IDirectSoundBuffer_Lock(p,a,b,c,d,e,f,g) (p)->Lock(a,b,c,d,e,f,g) -#define IDirectSoundBuffer_Play(p,a,b,c) (p)->Play(a,b,c) -#define IDirectSoundBuffer_SetCurrentPosition(p,a) (p)->SetCurrentPosition(a) -#define IDirectSoundBuffer_SetFormat(p,a) (p)->SetFormat(a) -#define IDirectSoundBuffer_SetVolume(p,a) (p)->SetVolume(a) -#define IDirectSoundBuffer_SetPan(p,a) (p)->SetPan(a) -#define IDirectSoundBuffer_SetFrequency(p,a) (p)->SetFrequency(a) -#define IDirectSoundBuffer_Stop(p) (p)->Stop() -#define IDirectSoundBuffer_Unlock(p,a,b,c,d) (p)->Unlock(a,b,c,d) -#define IDirectSoundBuffer_Restore(p) (p)->Restore() -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -#if DIRECTSOUND_VERSION >= 0x0800 - -// -// IDirectSoundBuffer8 -// - -DEFINE_GUID(IID_IDirectSoundBuffer8, 0x6825a449, 0x7524, 0x4d82, 0x92, 0x0f, 0x50, 0xe3, 0x6a, 0xb3, 0xab, 0x1e); - -#undef INTERFACE -#define INTERFACE IDirectSoundBuffer8 - -DECLARE_INTERFACE_(IDirectSoundBuffer8, IDirectSoundBuffer) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSoundBuffer methods - STDMETHOD(GetCaps) (THIS_ LPDSBCAPS pDSBufferCaps) PURE; - STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD pdwCurrentPlayCursor, LPDWORD pdwCurrentWriteCursor) PURE; - STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE; - STDMETHOD(GetVolume) (THIS_ LPLONG plVolume) PURE; - STDMETHOD(GetPan) (THIS_ LPLONG plPan) PURE; - STDMETHOD(GetFrequency) (THIS_ LPDWORD pdwFrequency) PURE; - STDMETHOD(GetStatus) (THIS_ LPDWORD pdwStatus) PURE; - STDMETHOD(Initialize) (THIS_ LPDIRECTSOUND pDirectSound, LPCDSBUFFERDESC pcDSBufferDesc) PURE; - STDMETHOD(Lock) (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1, - LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE; - STDMETHOD(Play) (THIS_ DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags) PURE; - STDMETHOD(SetCurrentPosition) (THIS_ DWORD dwNewPosition) PURE; - STDMETHOD(SetFormat) (THIS_ LPCWAVEFORMATEX pcfxFormat) PURE; - STDMETHOD(SetVolume) (THIS_ LONG lVolume) PURE; - STDMETHOD(SetPan) (THIS_ LONG lPan) PURE; - STDMETHOD(SetFrequency) (THIS_ DWORD dwFrequency) PURE; - STDMETHOD(Stop) (THIS) PURE; - STDMETHOD(Unlock) (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE; - STDMETHOD(Restore) (THIS) PURE; - - // IDirectSoundBuffer8 methods - STDMETHOD(SetFX) (THIS_ DWORD dwEffectsCount, LPDSEFFECTDESC pDSFXDesc, LPDWORD pdwResultCodes) PURE; - STDMETHOD(AcquireResources) (THIS_ DWORD dwFlags, DWORD dwEffectsCount, LPDWORD pdwResultCodes) PURE; - STDMETHOD(GetObjectInPath) (THIS_ REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, LPVOID *ppObject) PURE; -}; - -// Special GUID meaning "select all objects" for use in GetObjectInPath() -DEFINE_GUID(GUID_All_Objects, 0xaa114de5, 0xc262, 0x4169, 0xa1, 0xc8, 0x23, 0xd6, 0x98, 0xcc, 0x73, 0xb5); - -#define IDirectSoundBuffer8_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSoundBuffer8_AddRef(p) IUnknown_AddRef(p) -#define IDirectSoundBuffer8_Release(p) IUnknown_Release(p) - -#define IDirectSoundBuffer8_GetCaps(p,a) IDirectSoundBuffer_GetCaps(p,a) -#define IDirectSoundBuffer8_GetCurrentPosition(p,a,b) IDirectSoundBuffer_GetCurrentPosition(p,a,b) -#define IDirectSoundBuffer8_GetFormat(p,a,b,c) IDirectSoundBuffer_GetFormat(p,a,b,c) -#define IDirectSoundBuffer8_GetVolume(p,a) IDirectSoundBuffer_GetVolume(p,a) -#define IDirectSoundBuffer8_GetPan(p,a) IDirectSoundBuffer_GetPan(p,a) -#define IDirectSoundBuffer8_GetFrequency(p,a) IDirectSoundBuffer_GetFrequency(p,a) -#define IDirectSoundBuffer8_GetStatus(p,a) IDirectSoundBuffer_GetStatus(p,a) -#define IDirectSoundBuffer8_Initialize(p,a,b) IDirectSoundBuffer_Initialize(p,a,b) -#define IDirectSoundBuffer8_Lock(p,a,b,c,d,e,f,g) IDirectSoundBuffer_Lock(p,a,b,c,d,e,f,g) -#define IDirectSoundBuffer8_Play(p,a,b,c) IDirectSoundBuffer_Play(p,a,b,c) -#define IDirectSoundBuffer8_SetCurrentPosition(p,a) IDirectSoundBuffer_SetCurrentPosition(p,a) -#define IDirectSoundBuffer8_SetFormat(p,a) IDirectSoundBuffer_SetFormat(p,a) -#define IDirectSoundBuffer8_SetVolume(p,a) IDirectSoundBuffer_SetVolume(p,a) -#define IDirectSoundBuffer8_SetPan(p,a) IDirectSoundBuffer_SetPan(p,a) -#define IDirectSoundBuffer8_SetFrequency(p,a) IDirectSoundBuffer_SetFrequency(p,a) -#define IDirectSoundBuffer8_Stop(p) IDirectSoundBuffer_Stop(p) -#define IDirectSoundBuffer8_Unlock(p,a,b,c,d) IDirectSoundBuffer_Unlock(p,a,b,c,d) -#define IDirectSoundBuffer8_Restore(p) IDirectSoundBuffer_Restore(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundBuffer8_SetFX(p,a,b,c) (p)->lpVtbl->SetFX(p,a,b,c) -#define IDirectSoundBuffer8_AcquireResources(p,a,b,c) (p)->lpVtbl->AcquireResources(p,a,b,c) -#define IDirectSoundBuffer8_GetObjectInPath(p,a,b,c,d) (p)->lpVtbl->GetObjectInPath(p,a,b,c,d) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundBuffer8_SetFX(p,a,b,c) (p)->SetFX(a,b,c) -#define IDirectSoundBuffer8_AcquireResources(p,a,b,c) (p)->AcquireResources(a,b,c) -#define IDirectSoundBuffer8_GetObjectInPath(p,a,b,c,d) (p)->GetObjectInPath(a,b,c,d) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -#endif // DIRECTSOUND_VERSION >= 0x0800 - -// -// IDirectSound3DListener -// - -DEFINE_GUID(IID_IDirectSound3DListener, 0x279AFA84, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); - -#undef INTERFACE -#define INTERFACE IDirectSound3DListener - -DECLARE_INTERFACE_(IDirectSound3DListener, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSound3DListener methods - STDMETHOD(GetAllParameters) (THIS_ LPDS3DLISTENER pListener) PURE; - STDMETHOD(GetDistanceFactor) (THIS_ D3DVALUE* pflDistanceFactor) PURE; - STDMETHOD(GetDopplerFactor) (THIS_ D3DVALUE* pflDopplerFactor) PURE; - STDMETHOD(GetOrientation) (THIS_ D3DVECTOR* pvOrientFront, D3DVECTOR* pvOrientTop) PURE; - STDMETHOD(GetPosition) (THIS_ D3DVECTOR* pvPosition) PURE; - STDMETHOD(GetRolloffFactor) (THIS_ D3DVALUE* pflRolloffFactor) PURE; - STDMETHOD(GetVelocity) (THIS_ D3DVECTOR* pvVelocity) PURE; - STDMETHOD(SetAllParameters) (THIS_ LPCDS3DLISTENER pcListener, DWORD dwApply) PURE; - STDMETHOD(SetDistanceFactor) (THIS_ D3DVALUE flDistanceFactor, DWORD dwApply) PURE; - STDMETHOD(SetDopplerFactor) (THIS_ D3DVALUE flDopplerFactor, DWORD dwApply) PURE; - STDMETHOD(SetOrientation) (THIS_ D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, - D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD dwApply) PURE; - STDMETHOD(SetPosition) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; - STDMETHOD(SetRolloffFactor) (THIS_ D3DVALUE flRolloffFactor, DWORD dwApply) PURE; - STDMETHOD(SetVelocity) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; - STDMETHOD(CommitDeferredSettings) (THIS) PURE; -}; - -#define IDirectSound3DListener_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSound3DListener_AddRef(p) IUnknown_AddRef(p) -#define IDirectSound3DListener_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSound3DListener_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) -#define IDirectSound3DListener_GetDistanceFactor(p,a) (p)->lpVtbl->GetDistanceFactor(p,a) -#define IDirectSound3DListener_GetDopplerFactor(p,a) (p)->lpVtbl->GetDopplerFactor(p,a) -#define IDirectSound3DListener_GetOrientation(p,a,b) (p)->lpVtbl->GetOrientation(p,a,b) -#define IDirectSound3DListener_GetPosition(p,a) (p)->lpVtbl->GetPosition(p,a) -#define IDirectSound3DListener_GetRolloffFactor(p,a) (p)->lpVtbl->GetRolloffFactor(p,a) -#define IDirectSound3DListener_GetVelocity(p,a) (p)->lpVtbl->GetVelocity(p,a) -#define IDirectSound3DListener_SetAllParameters(p,a,b) (p)->lpVtbl->SetAllParameters(p,a,b) -#define IDirectSound3DListener_SetDistanceFactor(p,a,b) (p)->lpVtbl->SetDistanceFactor(p,a,b) -#define IDirectSound3DListener_SetDopplerFactor(p,a,b) (p)->lpVtbl->SetDopplerFactor(p,a,b) -#define IDirectSound3DListener_SetOrientation(p,a,b,c,d,e,f,g) (p)->lpVtbl->SetOrientation(p,a,b,c,d,e,f,g) -#define IDirectSound3DListener_SetPosition(p,a,b,c,d) (p)->lpVtbl->SetPosition(p,a,b,c,d) -#define IDirectSound3DListener_SetRolloffFactor(p,a,b) (p)->lpVtbl->SetRolloffFactor(p,a,b) -#define IDirectSound3DListener_SetVelocity(p,a,b,c,d) (p)->lpVtbl->SetVelocity(p,a,b,c,d) -#define IDirectSound3DListener_CommitDeferredSettings(p) (p)->lpVtbl->CommitDeferredSettings(p) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSound3DListener_GetAllParameters(p,a) (p)->GetAllParameters(a) -#define IDirectSound3DListener_GetDistanceFactor(p,a) (p)->GetDistanceFactor(a) -#define IDirectSound3DListener_GetDopplerFactor(p,a) (p)->GetDopplerFactor(a) -#define IDirectSound3DListener_GetOrientation(p,a,b) (p)->GetOrientation(a,b) -#define IDirectSound3DListener_GetPosition(p,a) (p)->GetPosition(a) -#define IDirectSound3DListener_GetRolloffFactor(p,a) (p)->GetRolloffFactor(a) -#define IDirectSound3DListener_GetVelocity(p,a) (p)->GetVelocity(a) -#define IDirectSound3DListener_SetAllParameters(p,a,b) (p)->SetAllParameters(a,b) -#define IDirectSound3DListener_SetDistanceFactor(p,a,b) (p)->SetDistanceFactor(a,b) -#define IDirectSound3DListener_SetDopplerFactor(p,a,b) (p)->SetDopplerFactor(a,b) -#define IDirectSound3DListener_SetOrientation(p,a,b,c,d,e,f,g) (p)->SetOrientation(a,b,c,d,e,f,g) -#define IDirectSound3DListener_SetPosition(p,a,b,c,d) (p)->SetPosition(a,b,c,d) -#define IDirectSound3DListener_SetRolloffFactor(p,a,b) (p)->SetRolloffFactor(a,b) -#define IDirectSound3DListener_SetVelocity(p,a,b,c,d) (p)->SetVelocity(a,b,c,d) -#define IDirectSound3DListener_CommitDeferredSettings(p) (p)->CommitDeferredSettings() -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -// -// IDirectSound3DBuffer -// - -DEFINE_GUID(IID_IDirectSound3DBuffer, 0x279AFA86, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); - -#undef INTERFACE -#define INTERFACE IDirectSound3DBuffer - -DECLARE_INTERFACE_(IDirectSound3DBuffer, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSound3DBuffer methods - STDMETHOD(GetAllParameters) (THIS_ LPDS3DBUFFER pDs3dBuffer) PURE; - STDMETHOD(GetConeAngles) (THIS_ LPDWORD pdwInsideConeAngle, LPDWORD pdwOutsideConeAngle) PURE; - STDMETHOD(GetConeOrientation) (THIS_ D3DVECTOR* pvOrientation) PURE; - STDMETHOD(GetConeOutsideVolume) (THIS_ LPLONG plConeOutsideVolume) PURE; - STDMETHOD(GetMaxDistance) (THIS_ D3DVALUE* pflMaxDistance) PURE; - STDMETHOD(GetMinDistance) (THIS_ D3DVALUE* pflMinDistance) PURE; - STDMETHOD(GetMode) (THIS_ LPDWORD pdwMode) PURE; - STDMETHOD(GetPosition) (THIS_ D3DVECTOR* pvPosition) PURE; - STDMETHOD(GetVelocity) (THIS_ D3DVECTOR* pvVelocity) PURE; - STDMETHOD(SetAllParameters) (THIS_ LPCDS3DBUFFER pcDs3dBuffer, DWORD dwApply) PURE; - STDMETHOD(SetConeAngles) (THIS_ DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD dwApply) PURE; - STDMETHOD(SetConeOrientation) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; - STDMETHOD(SetConeOutsideVolume) (THIS_ LONG lConeOutsideVolume, DWORD dwApply) PURE; - STDMETHOD(SetMaxDistance) (THIS_ D3DVALUE flMaxDistance, DWORD dwApply) PURE; - STDMETHOD(SetMinDistance) (THIS_ D3DVALUE flMinDistance, DWORD dwApply) PURE; - STDMETHOD(SetMode) (THIS_ DWORD dwMode, DWORD dwApply) PURE; - STDMETHOD(SetPosition) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; - STDMETHOD(SetVelocity) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; -}; - -#define IDirectSound3DBuffer_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSound3DBuffer_AddRef(p) IUnknown_AddRef(p) -#define IDirectSound3DBuffer_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSound3DBuffer_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) -#define IDirectSound3DBuffer_GetConeAngles(p,a,b) (p)->lpVtbl->GetConeAngles(p,a,b) -#define IDirectSound3DBuffer_GetConeOrientation(p,a) (p)->lpVtbl->GetConeOrientation(p,a) -#define IDirectSound3DBuffer_GetConeOutsideVolume(p,a) (p)->lpVtbl->GetConeOutsideVolume(p,a) -#define IDirectSound3DBuffer_GetPosition(p,a) (p)->lpVtbl->GetPosition(p,a) -#define IDirectSound3DBuffer_GetMinDistance(p,a) (p)->lpVtbl->GetMinDistance(p,a) -#define IDirectSound3DBuffer_GetMaxDistance(p,a) (p)->lpVtbl->GetMaxDistance(p,a) -#define IDirectSound3DBuffer_GetMode(p,a) (p)->lpVtbl->GetMode(p,a) -#define IDirectSound3DBuffer_GetVelocity(p,a) (p)->lpVtbl->GetVelocity(p,a) -#define IDirectSound3DBuffer_SetAllParameters(p,a,b) (p)->lpVtbl->SetAllParameters(p,a,b) -#define IDirectSound3DBuffer_SetConeAngles(p,a,b,c) (p)->lpVtbl->SetConeAngles(p,a,b,c) -#define IDirectSound3DBuffer_SetConeOrientation(p,a,b,c,d) (p)->lpVtbl->SetConeOrientation(p,a,b,c,d) -#define IDirectSound3DBuffer_SetConeOutsideVolume(p,a,b) (p)->lpVtbl->SetConeOutsideVolume(p,a,b) -#define IDirectSound3DBuffer_SetPosition(p,a,b,c,d) (p)->lpVtbl->SetPosition(p,a,b,c,d) -#define IDirectSound3DBuffer_SetMinDistance(p,a,b) (p)->lpVtbl->SetMinDistance(p,a,b) -#define IDirectSound3DBuffer_SetMaxDistance(p,a,b) (p)->lpVtbl->SetMaxDistance(p,a,b) -#define IDirectSound3DBuffer_SetMode(p,a,b) (p)->lpVtbl->SetMode(p,a,b) -#define IDirectSound3DBuffer_SetVelocity(p,a,b,c,d) (p)->lpVtbl->SetVelocity(p,a,b,c,d) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSound3DBuffer_GetAllParameters(p,a) (p)->GetAllParameters(a) -#define IDirectSound3DBuffer_GetConeAngles(p,a,b) (p)->GetConeAngles(a,b) -#define IDirectSound3DBuffer_GetConeOrientation(p,a) (p)->GetConeOrientation(a) -#define IDirectSound3DBuffer_GetConeOutsideVolume(p,a) (p)->GetConeOutsideVolume(a) -#define IDirectSound3DBuffer_GetPosition(p,a) (p)->GetPosition(a) -#define IDirectSound3DBuffer_GetMinDistance(p,a) (p)->GetMinDistance(a) -#define IDirectSound3DBuffer_GetMaxDistance(p,a) (p)->GetMaxDistance(a) -#define IDirectSound3DBuffer_GetMode(p,a) (p)->GetMode(a) -#define IDirectSound3DBuffer_GetVelocity(p,a) (p)->GetVelocity(a) -#define IDirectSound3DBuffer_SetAllParameters(p,a,b) (p)->SetAllParameters(a,b) -#define IDirectSound3DBuffer_SetConeAngles(p,a,b,c) (p)->SetConeAngles(a,b,c) -#define IDirectSound3DBuffer_SetConeOrientation(p,a,b,c,d) (p)->SetConeOrientation(a,b,c,d) -#define IDirectSound3DBuffer_SetConeOutsideVolume(p,a,b) (p)->SetConeOutsideVolume(a,b) -#define IDirectSound3DBuffer_SetPosition(p,a,b,c,d) (p)->SetPosition(a,b,c,d) -#define IDirectSound3DBuffer_SetMinDistance(p,a,b) (p)->SetMinDistance(a,b) -#define IDirectSound3DBuffer_SetMaxDistance(p,a,b) (p)->SetMaxDistance(a,b) -#define IDirectSound3DBuffer_SetMode(p,a,b) (p)->SetMode(a,b) -#define IDirectSound3DBuffer_SetVelocity(p,a,b,c,d) (p)->SetVelocity(a,b,c,d) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -// -// IDirectSoundCapture -// - -DEFINE_GUID(IID_IDirectSoundCapture, 0xb0210781, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); - -#undef INTERFACE -#define INTERFACE IDirectSoundCapture - -DECLARE_INTERFACE_(IDirectSoundCapture, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSoundCapture methods - STDMETHOD(CreateCaptureBuffer) (THIS_ LPCDSCBUFFERDESC pcDSCBufferDesc, LPDIRECTSOUNDCAPTUREBUFFER *ppDSCBuffer, LPUNKNOWN pUnkOuter) PURE; - STDMETHOD(GetCaps) (THIS_ LPDSCCAPS pDSCCaps) PURE; - STDMETHOD(Initialize) (THIS_ LPCGUID pcGuidDevice) PURE; -}; - -#define IDirectSoundCapture_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSoundCapture_AddRef(p) IUnknown_AddRef(p) -#define IDirectSoundCapture_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundCapture_CreateCaptureBuffer(p,a,b,c) (p)->lpVtbl->CreateCaptureBuffer(p,a,b,c) -#define IDirectSoundCapture_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) -#define IDirectSoundCapture_Initialize(p,a) (p)->lpVtbl->Initialize(p,a) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundCapture_CreateCaptureBuffer(p,a,b,c) (p)->CreateCaptureBuffer(a,b,c) -#define IDirectSoundCapture_GetCaps(p,a) (p)->GetCaps(a) -#define IDirectSoundCapture_Initialize(p,a) (p)->Initialize(a) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -// -// IDirectSoundCaptureBuffer -// - -DEFINE_GUID(IID_IDirectSoundCaptureBuffer, 0xb0210782, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); - -#undef INTERFACE -#define INTERFACE IDirectSoundCaptureBuffer - -DECLARE_INTERFACE_(IDirectSoundCaptureBuffer, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSoundCaptureBuffer methods - STDMETHOD(GetCaps) (THIS_ LPDSCBCAPS pDSCBCaps) PURE; - STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD pdwCapturePosition, LPDWORD pdwReadPosition) PURE; - STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE; - STDMETHOD(GetStatus) (THIS_ LPDWORD pdwStatus) PURE; - STDMETHOD(Initialize) (THIS_ LPDIRECTSOUNDCAPTURE pDirectSoundCapture, LPCDSCBUFFERDESC pcDSCBufferDesc) PURE; - STDMETHOD(Lock) (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1, - LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE; - STDMETHOD(Start) (THIS_ DWORD dwFlags) PURE; - STDMETHOD(Stop) (THIS) PURE; - STDMETHOD(Unlock) (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE; -}; - -#define IDirectSoundCaptureBuffer_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSoundCaptureBuffer_AddRef(p) IUnknown_AddRef(p) -#define IDirectSoundCaptureBuffer_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundCaptureBuffer_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) -#define IDirectSoundCaptureBuffer_GetCurrentPosition(p,a,b) (p)->lpVtbl->GetCurrentPosition(p,a,b) -#define IDirectSoundCaptureBuffer_GetFormat(p,a,b,c) (p)->lpVtbl->GetFormat(p,a,b,c) -#define IDirectSoundCaptureBuffer_GetStatus(p,a) (p)->lpVtbl->GetStatus(p,a) -#define IDirectSoundCaptureBuffer_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) -#define IDirectSoundCaptureBuffer_Lock(p,a,b,c,d,e,f,g) (p)->lpVtbl->Lock(p,a,b,c,d,e,f,g) -#define IDirectSoundCaptureBuffer_Start(p,a) (p)->lpVtbl->Start(p,a) -#define IDirectSoundCaptureBuffer_Stop(p) (p)->lpVtbl->Stop(p) -#define IDirectSoundCaptureBuffer_Unlock(p,a,b,c,d) (p)->lpVtbl->Unlock(p,a,b,c,d) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundCaptureBuffer_GetCaps(p,a) (p)->GetCaps(a) -#define IDirectSoundCaptureBuffer_GetCurrentPosition(p,a,b) (p)->GetCurrentPosition(a,b) -#define IDirectSoundCaptureBuffer_GetFormat(p,a,b,c) (p)->GetFormat(a,b,c) -#define IDirectSoundCaptureBuffer_GetStatus(p,a) (p)->GetStatus(a) -#define IDirectSoundCaptureBuffer_Initialize(p,a,b) (p)->Initialize(a,b) -#define IDirectSoundCaptureBuffer_Lock(p,a,b,c,d,e,f,g) (p)->Lock(a,b,c,d,e,f,g) -#define IDirectSoundCaptureBuffer_Start(p,a) (p)->Start(a) -#define IDirectSoundCaptureBuffer_Stop(p) (p)->Stop() -#define IDirectSoundCaptureBuffer_Unlock(p,a,b,c,d) (p)->Unlock(a,b,c,d) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - - -#if DIRECTSOUND_VERSION >= 0x0800 - -// -// IDirectSoundCaptureBuffer8 -// - -DEFINE_GUID(IID_IDirectSoundCaptureBuffer8, 0x990df4, 0xdbb, 0x4872, 0x83, 0x3e, 0x6d, 0x30, 0x3e, 0x80, 0xae, 0xb6); - -#undef INTERFACE -#define INTERFACE IDirectSoundCaptureBuffer8 - -DECLARE_INTERFACE_(IDirectSoundCaptureBuffer8, IDirectSoundCaptureBuffer) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSoundCaptureBuffer methods - STDMETHOD(GetCaps) (THIS_ LPDSCBCAPS pDSCBCaps) PURE; - STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD pdwCapturePosition, LPDWORD pdwReadPosition) PURE; - STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE; - STDMETHOD(GetStatus) (THIS_ LPDWORD pdwStatus) PURE; - STDMETHOD(Initialize) (THIS_ LPDIRECTSOUNDCAPTURE pDirectSoundCapture, LPCDSCBUFFERDESC pcDSCBufferDesc) PURE; - STDMETHOD(Lock) (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1, - LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE; - STDMETHOD(Start) (THIS_ DWORD dwFlags) PURE; - STDMETHOD(Stop) (THIS) PURE; - STDMETHOD(Unlock) (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE; - - // IDirectSoundCaptureBuffer8 methods - STDMETHOD(GetObjectInPath) (THIS_ REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, LPVOID *ppObject) PURE; - STDMETHOD(GetFXStatus) (DWORD dwFXCount, LPDWORD pdwFXStatus) PURE; -}; - -#define IDirectSoundCaptureBuffer8_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSoundCaptureBuffer8_AddRef(p) IUnknown_AddRef(p) -#define IDirectSoundCaptureBuffer8_Release(p) IUnknown_Release(p) - -#define IDirectSoundCaptureBuffer8_GetCaps(p,a) IDirectSoundCaptureBuffer_GetCaps(p,a) -#define IDirectSoundCaptureBuffer8_GetCurrentPosition(p,a,b) IDirectSoundCaptureBuffer_GetCurrentPosition(p,a,b) -#define IDirectSoundCaptureBuffer8_GetFormat(p,a,b,c) IDirectSoundCaptureBuffer_GetFormat(p,a,b,c) -#define IDirectSoundCaptureBuffer8_GetStatus(p,a) IDirectSoundCaptureBuffer_GetStatus(p,a) -#define IDirectSoundCaptureBuffer8_Initialize(p,a,b) IDirectSoundCaptureBuffer_Initialize(p,a,b) -#define IDirectSoundCaptureBuffer8_Lock(p,a,b,c,d,e,f,g) IDirectSoundCaptureBuffer_Lock(p,a,b,c,d,e,f,g) -#define IDirectSoundCaptureBuffer8_Start(p,a) IDirectSoundCaptureBuffer_Start(p,a) -#define IDirectSoundCaptureBuffer8_Stop(p) IDirectSoundCaptureBuffer_Stop(p)) -#define IDirectSoundCaptureBuffer8_Unlock(p,a,b,c,d) IDirectSoundCaptureBuffer_Unlock(p,a,b,c,d) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundCaptureBuffer8_GetObjectInPath(p,a,b,c,d) (p)->lpVtbl->GetObjectInPath(p,a,b,c,d) -#define IDirectSoundCaptureBuffer8_GetFXStatus(p,a,b) (p)->lpVtbl->GetFXStatus(p,a,b) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundCaptureBuffer8_GetObjectInPath(p,a,b,c,d) (p)->GetObjectInPath(a,b,c,d) -#define IDirectSoundCaptureBuffer8_GetFXStatus(p,a,b) (p)->GetFXStatus(a,b) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -#endif // DIRECTSOUND_VERSION >= 0x0800 - -// -// IDirectSoundNotify -// - -DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); - -#undef INTERFACE -#define INTERFACE IDirectSoundNotify - -DECLARE_INTERFACE_(IDirectSoundNotify, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSoundNotify methods - STDMETHOD(SetNotificationPositions) (THIS_ DWORD dwPositionNotifies, LPCDSBPOSITIONNOTIFY pcPositionNotifies) PURE; -}; - -#define IDirectSoundNotify_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSoundNotify_AddRef(p) IUnknown_AddRef(p) -#define IDirectSoundNotify_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundNotify_SetNotificationPositions(p,a,b) (p)->lpVtbl->SetNotificationPositions(p,a,b) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundNotify_SetNotificationPositions(p,a,b) (p)->SetNotificationPositions(a,b) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -// -// IKsPropertySet -// - -#ifndef _IKsPropertySet_ -#define _IKsPropertySet_ - -#ifdef __cplusplus -// 'struct' not 'class' per the way DECLARE_INTERFACE_ is defined -struct IKsPropertySet; -#endif // __cplusplus - -typedef struct IKsPropertySet *LPKSPROPERTYSET; - -#define KSPROPERTY_SUPPORT_GET 0x00000001 -#define KSPROPERTY_SUPPORT_SET 0x00000002 - -DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa, 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93); - -#undef INTERFACE -#define INTERFACE IKsPropertySet - -DECLARE_INTERFACE_(IKsPropertySet, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IKsPropertySet methods - STDMETHOD(Get) (THIS_ REFGUID rguidPropSet, ULONG ulId, LPVOID pInstanceData, ULONG ulInstanceLength, - LPVOID pPropertyData, ULONG ulDataLength, PULONG pulBytesReturned) PURE; - STDMETHOD(Set) (THIS_ REFGUID rguidPropSet, ULONG ulId, LPVOID pInstanceData, ULONG ulInstanceLength, - LPVOID pPropertyData, ULONG ulDataLength) PURE; - STDMETHOD(QuerySupport) (THIS_ REFGUID rguidPropSet, ULONG ulId, PULONG pulTypeSupport) PURE; -}; - -#define IKsPropertySet_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IKsPropertySet_AddRef(p) IUnknown_AddRef(p) -#define IKsPropertySet_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IKsPropertySet_Get(p,a,b,c,d,e,f,g) (p)->lpVtbl->Get(p,a,b,c,d,e,f,g) -#define IKsPropertySet_Set(p,a,b,c,d,e,f) (p)->lpVtbl->Set(p,a,b,c,d,e,f) -#define IKsPropertySet_QuerySupport(p,a,b,c) (p)->lpVtbl->QuerySupport(p,a,b,c) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IKsPropertySet_Get(p,a,b,c,d,e,f,g) (p)->Get(a,b,c,d,e,f,g) -#define IKsPropertySet_Set(p,a,b,c,d,e,f) (p)->Set(a,b,c,d,e,f) -#define IKsPropertySet_QuerySupport(p,a,b,c) (p)->QuerySupport(a,b,c) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -#endif // _IKsPropertySet_ - -#if DIRECTSOUND_VERSION >= 0x0800 - -// -// IDirectSoundFXGargle -// - -DEFINE_GUID(IID_IDirectSoundFXGargle, 0xd616f352, 0xd622, 0x11ce, 0xaa, 0xc5, 0x00, 0x20, 0xaf, 0x0b, 0x99, 0xa3); - -typedef struct _DSFXGargle -{ - DWORD dwRateHz; // Rate of modulation in hz - DWORD dwWaveShape; // DSFXGARGLE_WAVE_xxx -} DSFXGargle, *LPDSFXGargle; - -#define DSFXGARGLE_WAVE_TRIANGLE 0 -#define DSFXGARGLE_WAVE_SQUARE 1 - -typedef const DSFXGargle *LPCDSFXGargle; - -#define DSFXGARGLE_RATEHZ_MIN 1 -#define DSFXGARGLE_RATEHZ_MAX 1000 - -#undef INTERFACE -#define INTERFACE IDirectSoundFXGargle - -DECLARE_INTERFACE_(IDirectSoundFXGargle, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSoundFXGargle methods - STDMETHOD(SetAllParameters) (THIS_ LPCDSFXGargle pcDsFxGargle) PURE; - STDMETHOD(GetAllParameters) (THIS_ LPDSFXGargle pDsFxGargle) PURE; -}; - -#define IDirectSoundFXGargle_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSoundFXGargle_AddRef(p) IUnknown_AddRef(p) -#define IDirectSoundFXGargle_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFXGargle_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) -#define IDirectSoundFXGargle_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFXGargle_SetAllParameters(p,a) (p)->SetAllParameters(a) -#define IDirectSoundFXGargle_GetAllParameters(p,a) (p)->GetAllParameters(a) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -// -// IDirectSoundFXChorus -// - -DEFINE_GUID(IID_IDirectSoundFXChorus, 0x880842e3, 0x145f, 0x43e6, 0xa9, 0x34, 0xa7, 0x18, 0x06, 0xe5, 0x05, 0x47); - -typedef struct _DSFXChorus -{ - FLOAT fWetDryMix; - FLOAT fDepth; - FLOAT fFeedback; - FLOAT fFrequency; - LONG lWaveform; // LFO shape; DSFXCHORUS_WAVE_xxx - FLOAT fDelay; - LONG lPhase; -} DSFXChorus, *LPDSFXChorus; - -typedef const DSFXChorus *LPCDSFXChorus; - -#define DSFXCHORUS_WAVE_TRIANGLE 0 -#define DSFXCHORUS_WAVE_SIN 1 - -#define DSFXCHORUS_WETDRYMIX_MIN 0.0f -#define DSFXCHORUS_WETDRYMIX_MAX 100.0f -#define DSFXCHORUS_DEPTH_MIN 0.0f -#define DSFXCHORUS_DEPTH_MAX 100.0f -#define DSFXCHORUS_FEEDBACK_MIN -99.0f -#define DSFXCHORUS_FEEDBACK_MAX 99.0f -#define DSFXCHORUS_FREQUENCY_MIN 0.0f -#define DSFXCHORUS_FREQUENCY_MAX 10.0f -#define DSFXCHORUS_DELAY_MIN 0.0f -#define DSFXCHORUS_DELAY_MAX 20.0f -#define DSFXCHORUS_PHASE_MIN 0 -#define DSFXCHORUS_PHASE_MAX 4 - -#define DSFXCHORUS_PHASE_NEG_180 0 -#define DSFXCHORUS_PHASE_NEG_90 1 -#define DSFXCHORUS_PHASE_ZERO 2 -#define DSFXCHORUS_PHASE_90 3 -#define DSFXCHORUS_PHASE_180 4 - -#undef INTERFACE -#define INTERFACE IDirectSoundFXChorus - -DECLARE_INTERFACE_(IDirectSoundFXChorus, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSoundFXChorus methods - STDMETHOD(SetAllParameters) (THIS_ LPCDSFXChorus pcDsFxChorus) PURE; - STDMETHOD(GetAllParameters) (THIS_ LPDSFXChorus pDsFxChorus) PURE; -}; - -#define IDirectSoundFXChorus_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSoundFXChorus_AddRef(p) IUnknown_AddRef(p) -#define IDirectSoundFXChorus_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFXChorus_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) -#define IDirectSoundFXChorus_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFXChorus_SetAllParameters(p,a) (p)->SetAllParameters(a) -#define IDirectSoundFXChorus_GetAllParameters(p,a) (p)->GetAllParameters(a) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -// -// IDirectSoundFXFlanger -// - -DEFINE_GUID(IID_IDirectSoundFXFlanger, 0x903e9878, 0x2c92, 0x4072, 0x9b, 0x2c, 0xea, 0x68, 0xf5, 0x39, 0x67, 0x83); - -typedef struct _DSFXFlanger -{ - FLOAT fWetDryMix; - FLOAT fDepth; - FLOAT fFeedback; - FLOAT fFrequency; - LONG lWaveform; - FLOAT fDelay; - LONG lPhase; -} DSFXFlanger, *LPDSFXFlanger; - -typedef const DSFXFlanger *LPCDSFXFlanger; - -#define DSFXFLANGER_WAVE_TRIANGLE 0 -#define DSFXFLANGER_WAVE_SIN 1 - -#define DSFXFLANGER_WETDRYMIX_MIN 0.0f -#define DSFXFLANGER_WETDRYMIX_MAX 100.0f -#define DSFXFLANGER_FREQUENCY_MIN 0.0f -#define DSFXFLANGER_FREQUENCY_MAX 10.0f -#define DSFXFLANGER_DEPTH_MIN 0.0f -#define DSFXFLANGER_DEPTH_MAX 100.0f -#define DSFXFLANGER_PHASE_MIN 0 -#define DSFXFLANGER_PHASE_MAX 4 -#define DSFXFLANGER_FEEDBACK_MIN -99.0f -#define DSFXFLANGER_FEEDBACK_MAX 99.0f -#define DSFXFLANGER_DELAY_MIN 0.0f -#define DSFXFLANGER_DELAY_MAX 4.0f - -#define DSFXFLANGER_PHASE_NEG_180 0 -#define DSFXFLANGER_PHASE_NEG_90 1 -#define DSFXFLANGER_PHASE_ZERO 2 -#define DSFXFLANGER_PHASE_90 3 -#define DSFXFLANGER_PHASE_180 4 - -#undef INTERFACE -#define INTERFACE IDirectSoundFXFlanger - -DECLARE_INTERFACE_(IDirectSoundFXFlanger, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSoundFXFlanger methods - STDMETHOD(SetAllParameters) (THIS_ LPCDSFXFlanger pcDsFxFlanger) PURE; - STDMETHOD(GetAllParameters) (THIS_ LPDSFXFlanger pDsFxFlanger) PURE; -}; - -#define IDirectSoundFXFlanger_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSoundFXFlanger_AddRef(p) IUnknown_AddRef(p) -#define IDirectSoundFXFlanger_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFXFlanger_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) -#define IDirectSoundFXFlanger_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFXFlanger_SetAllParameters(p,a) (p)->SetAllParameters(a) -#define IDirectSoundFXFlanger_GetAllParameters(p,a) (p)->GetAllParameters(a) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -// -// IDirectSoundFXEcho -// - -DEFINE_GUID(IID_IDirectSoundFXEcho, 0x8bd28edf, 0x50db, 0x4e92, 0xa2, 0xbd, 0x44, 0x54, 0x88, 0xd1, 0xed, 0x42); - -typedef struct _DSFXEcho -{ - FLOAT fWetDryMix; - FLOAT fFeedback; - FLOAT fLeftDelay; - FLOAT fRightDelay; - LONG lPanDelay; -} DSFXEcho, *LPDSFXEcho; - -typedef const DSFXEcho *LPCDSFXEcho; - -#define DSFXECHO_WETDRYMIX_MIN 0.0f -#define DSFXECHO_WETDRYMIX_MAX 100.0f -#define DSFXECHO_FEEDBACK_MIN 0.0f -#define DSFXECHO_FEEDBACK_MAX 100.0f -#define DSFXECHO_LEFTDELAY_MIN 1.0f -#define DSFXECHO_LEFTDELAY_MAX 2000.0f -#define DSFXECHO_RIGHTDELAY_MIN 1.0f -#define DSFXECHO_RIGHTDELAY_MAX 2000.0f -#define DSFXECHO_PANDELAY_MIN 0 -#define DSFXECHO_PANDELAY_MAX 1 - -#undef INTERFACE -#define INTERFACE IDirectSoundFXEcho - -DECLARE_INTERFACE_(IDirectSoundFXEcho, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSoundFXEcho methods - STDMETHOD(SetAllParameters) (THIS_ LPCDSFXEcho pcDsFxEcho) PURE; - STDMETHOD(GetAllParameters) (THIS_ LPDSFXEcho pDsFxEcho) PURE; -}; - -#define IDirectSoundFXEcho_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSoundFXEcho_AddRef(p) IUnknown_AddRef(p) -#define IDirectSoundFXEcho_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFXEcho_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) -#define IDirectSoundFXEcho_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFXEcho_SetAllParameters(p,a) (p)->SetAllParameters(a) -#define IDirectSoundFXEcho_GetAllParameters(p,a) (p)->GetAllParameters(a) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -// -// IDirectSoundFXDistortion -// - -DEFINE_GUID(IID_IDirectSoundFXDistortion, 0x8ecf4326, 0x455f, 0x4d8b, 0xbd, 0xa9, 0x8d, 0x5d, 0x3e, 0x9e, 0x3e, 0x0b); - -typedef struct _DSFXDistortion -{ - FLOAT fGain; - FLOAT fEdge; - FLOAT fPostEQCenterFrequency; - FLOAT fPostEQBandwidth; - FLOAT fPreLowpassCutoff; -} DSFXDistortion, *LPDSFXDistortion; - -typedef const DSFXDistortion *LPCDSFXDistortion; - -#define DSFXDISTORTION_GAIN_MIN -60.0f -#define DSFXDISTORTION_GAIN_MAX 0.0f -#define DSFXDISTORTION_EDGE_MIN 0.0f -#define DSFXDISTORTION_EDGE_MAX 100.0f -#define DSFXDISTORTION_POSTEQCENTERFREQUENCY_MIN 100.0f -#define DSFXDISTORTION_POSTEQCENTERFREQUENCY_MAX 8000.0f -#define DSFXDISTORTION_POSTEQBANDWIDTH_MIN 100.0f -#define DSFXDISTORTION_POSTEQBANDWIDTH_MAX 8000.0f -#define DSFXDISTORTION_PRELOWPASSCUTOFF_MIN 100.0f -#define DSFXDISTORTION_PRELOWPASSCUTOFF_MAX 8000.0f - -#undef INTERFACE -#define INTERFACE IDirectSoundFXDistortion - -DECLARE_INTERFACE_(IDirectSoundFXDistortion, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSoundFXDistortion methods - STDMETHOD(SetAllParameters) (THIS_ LPCDSFXDistortion pcDsFxDistortion) PURE; - STDMETHOD(GetAllParameters) (THIS_ LPDSFXDistortion pDsFxDistortion) PURE; -}; - -#define IDirectSoundFXDistortion_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSoundFXDistortion_AddRef(p) IUnknown_AddRef(p) -#define IDirectSoundFXDistortion_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFXDistortion_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) -#define IDirectSoundFXDistortion_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFXDistortion_SetAllParameters(p,a) (p)->SetAllParameters(a) -#define IDirectSoundFXDistortion_GetAllParameters(p,a) (p)->GetAllParameters(a) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -// -// IDirectSoundFXCompressor -// - -DEFINE_GUID(IID_IDirectSoundFXCompressor, 0x4bbd1154, 0x62f6, 0x4e2c, 0xa1, 0x5c, 0xd3, 0xb6, 0xc4, 0x17, 0xf7, 0xa0); - -typedef struct _DSFXCompressor -{ - FLOAT fGain; - FLOAT fAttack; - FLOAT fRelease; - FLOAT fThreshold; - FLOAT fRatio; - FLOAT fPredelay; -} DSFXCompressor, *LPDSFXCompressor; - -typedef const DSFXCompressor *LPCDSFXCompressor; - -#define DSFXCOMPRESSOR_GAIN_MIN -60.0f -#define DSFXCOMPRESSOR_GAIN_MAX 60.0f -#define DSFXCOMPRESSOR_ATTACK_MIN 0.01f -#define DSFXCOMPRESSOR_ATTACK_MAX 500.0f -#define DSFXCOMPRESSOR_RELEASE_MIN 50.0f -#define DSFXCOMPRESSOR_RELEASE_MAX 3000.0f -#define DSFXCOMPRESSOR_THRESHOLD_MIN -60.0f -#define DSFXCOMPRESSOR_THRESHOLD_MAX 0.0f -#define DSFXCOMPRESSOR_RATIO_MIN 1.0f -#define DSFXCOMPRESSOR_RATIO_MAX 100.0f -#define DSFXCOMPRESSOR_PREDELAY_MIN 0.0f -#define DSFXCOMPRESSOR_PREDELAY_MAX 4.0f - -#undef INTERFACE -#define INTERFACE IDirectSoundFXCompressor - -DECLARE_INTERFACE_(IDirectSoundFXCompressor, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSoundFXCompressor methods - STDMETHOD(SetAllParameters) (THIS_ LPCDSFXCompressor pcDsFxCompressor) PURE; - STDMETHOD(GetAllParameters) (THIS_ LPDSFXCompressor pDsFxCompressor) PURE; -}; - -#define IDirectSoundFXCompressor_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSoundFXCompressor_AddRef(p) IUnknown_AddRef(p) -#define IDirectSoundFXCompressor_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFXCompressor_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) -#define IDirectSoundFXCompressor_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFXCompressor_SetAllParameters(p,a) (p)->SetAllParameters(a) -#define IDirectSoundFXCompressor_GetAllParameters(p,a) (p)->GetAllParameters(a) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -// -// IDirectSoundFXParamEq -// - -DEFINE_GUID(IID_IDirectSoundFXParamEq, 0xc03ca9fe, 0xfe90, 0x4204, 0x80, 0x78, 0x82, 0x33, 0x4c, 0xd1, 0x77, 0xda); - -typedef struct _DSFXParamEq -{ - FLOAT fCenter; - FLOAT fBandwidth; - FLOAT fGain; -} DSFXParamEq, *LPDSFXParamEq; - -typedef const DSFXParamEq *LPCDSFXParamEq; - -#define DSFXPARAMEQ_CENTER_MIN 80.0f -#define DSFXPARAMEQ_CENTER_MAX 16000.0f -#define DSFXPARAMEQ_BANDWIDTH_MIN 1.0f -#define DSFXPARAMEQ_BANDWIDTH_MAX 36.0f -#define DSFXPARAMEQ_GAIN_MIN -15.0f -#define DSFXPARAMEQ_GAIN_MAX 15.0f - -#undef INTERFACE -#define INTERFACE IDirectSoundFXParamEq - -DECLARE_INTERFACE_(IDirectSoundFXParamEq, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSoundFXParamEq methods - STDMETHOD(SetAllParameters) (THIS_ LPCDSFXParamEq pcDsFxParamEq) PURE; - STDMETHOD(GetAllParameters) (THIS_ LPDSFXParamEq pDsFxParamEq) PURE; -}; - -#define IDirectSoundFXParamEq_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSoundFXParamEq_AddRef(p) IUnknown_AddRef(p) -#define IDirectSoundFXParamEq_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFXParamEq_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) -#define IDirectSoundFXParamEq_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFXParamEq_SetAllParameters(p,a) (p)->SetAllParameters(a) -#define IDirectSoundFXParamEq_GetAllParameters(p,a) (p)->GetAllParameters(a) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -// -// IDirectSoundFXI3DL2Reverb -// - -DEFINE_GUID(IID_IDirectSoundFXI3DL2Reverb, 0x4b166a6a, 0x0d66, 0x43f3, 0x80, 0xe3, 0xee, 0x62, 0x80, 0xde, 0xe1, 0xa4); - -typedef struct _DSFXI3DL2Reverb -{ - LONG lRoom; // [-10000, 0] default: -1000 mB - LONG lRoomHF; // [-10000, 0] default: 0 mB - FLOAT flRoomRolloffFactor; // [0.0, 10.0] default: 0.0 - FLOAT flDecayTime; // [0.1, 20.0] default: 1.49s - FLOAT flDecayHFRatio; // [0.1, 2.0] default: 0.83 - LONG lReflections; // [-10000, 1000] default: -2602 mB - FLOAT flReflectionsDelay; // [0.0, 0.3] default: 0.007 s - LONG lReverb; // [-10000, 2000] default: 200 mB - FLOAT flReverbDelay; // [0.0, 0.1] default: 0.011 s - FLOAT flDiffusion; // [0.0, 100.0] default: 100.0 % - FLOAT flDensity; // [0.0, 100.0] default: 100.0 % - FLOAT flHFReference; // [20.0, 20000.0] default: 5000.0 Hz -} DSFXI3DL2Reverb, *LPDSFXI3DL2Reverb; - -typedef const DSFXI3DL2Reverb *LPCDSFXI3DL2Reverb; - -#define DSFX_I3DL2REVERB_ROOM_MIN (-10000) -#define DSFX_I3DL2REVERB_ROOM_MAX 0 -#define DSFX_I3DL2REVERB_ROOM_DEFAULT (-1000) - -#define DSFX_I3DL2REVERB_ROOMHF_MIN (-10000) -#define DSFX_I3DL2REVERB_ROOMHF_MAX 0 -#define DSFX_I3DL2REVERB_ROOMHF_DEFAULT (-100) - -#define DSFX_I3DL2REVERB_ROOMROLLOFFFACTOR_MIN 0.0f -#define DSFX_I3DL2REVERB_ROOMROLLOFFFACTOR_MAX 10.0f -#define DSFX_I3DL2REVERB_ROOMROLLOFFFACTOR_DEFAULT 0.0f - -#define DSFX_I3DL2REVERB_DECAYTIME_MIN 0.1f -#define DSFX_I3DL2REVERB_DECAYTIME_MAX 20.0f -#define DSFX_I3DL2REVERB_DECAYTIME_DEFAULT 1.49f - -#define DSFX_I3DL2REVERB_DECAYHFRATIO_MIN 0.1f -#define DSFX_I3DL2REVERB_DECAYHFRATIO_MAX 2.0f -#define DSFX_I3DL2REVERB_DECAYHFRATIO_DEFAULT 0.83f - -#define DSFX_I3DL2REVERB_REFLECTIONS_MIN (-10000) -#define DSFX_I3DL2REVERB_REFLECTIONS_MAX 1000 -#define DSFX_I3DL2REVERB_REFLECTIONS_DEFAULT (-2602) - -#define DSFX_I3DL2REVERB_REFLECTIONSDELAY_MIN 0.0f -#define DSFX_I3DL2REVERB_REFLECTIONSDELAY_MAX 0.3f -#define DSFX_I3DL2REVERB_REFLECTIONSDELAY_DEFAULT 0.007f - -#define DSFX_I3DL2REVERB_REVERB_MIN (-10000) -#define DSFX_I3DL2REVERB_REVERB_MAX 2000 -#define DSFX_I3DL2REVERB_REVERB_DEFAULT (200) - -#define DSFX_I3DL2REVERB_REVERBDELAY_MIN 0.0f -#define DSFX_I3DL2REVERB_REVERBDELAY_MAX 0.1f -#define DSFX_I3DL2REVERB_REVERBDELAY_DEFAULT 0.011f - -#define DSFX_I3DL2REVERB_DIFFUSION_MIN 0.0f -#define DSFX_I3DL2REVERB_DIFFUSION_MAX 100.0f -#define DSFX_I3DL2REVERB_DIFFUSION_DEFAULT 100.0f - -#define DSFX_I3DL2REVERB_DENSITY_MIN 0.0f -#define DSFX_I3DL2REVERB_DENSITY_MAX 100.0f -#define DSFX_I3DL2REVERB_DENSITY_DEFAULT 100.0f - -#define DSFX_I3DL2REVERB_HFREFERENCE_MIN 20.0f -#define DSFX_I3DL2REVERB_HFREFERENCE_MAX 20000.0f -#define DSFX_I3DL2REVERB_HFREFERENCE_DEFAULT 5000.0f - -#define DSFX_I3DL2REVERB_QUALITY_MIN 0 -#define DSFX_I3DL2REVERB_QUALITY_MAX 3 -#define DSFX_I3DL2REVERB_QUALITY_DEFAULT 2 - -#undef INTERFACE -#define INTERFACE IDirectSoundFXI3DL2Reverb - -DECLARE_INTERFACE_(IDirectSoundFXI3DL2Reverb, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSoundFXI3DL2Reverb methods - STDMETHOD(SetAllParameters) (THIS_ LPCDSFXI3DL2Reverb pcDsFxI3DL2Reverb) PURE; - STDMETHOD(GetAllParameters) (THIS_ LPDSFXI3DL2Reverb pDsFxI3DL2Reverb) PURE; - STDMETHOD(SetPreset) (THIS_ DWORD dwPreset) PURE; - STDMETHOD(GetPreset) (THIS_ LPDWORD pdwPreset) PURE; - STDMETHOD(SetQuality) (THIS_ LONG lQuality) PURE; - STDMETHOD(GetQuality) (THIS_ LONG *plQuality) PURE; -}; - -#define IDirectSoundFXI3DL2Reverb_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSoundFXI3DL2Reverb_AddRef(p) IUnknown_AddRef(p) -#define IDirectSoundFXI3DL2Reverb_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFXI3DL2Reverb_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) -#define IDirectSoundFXI3DL2Reverb_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) -#define IDirectSoundFXI3DL2Reverb_SetPreset(p,a) (p)->lpVtbl->SetPreset(p,a) -#define IDirectSoundFXI3DL2Reverb_GetPreset(p,a) (p)->lpVtbl->GetPreset(p,a) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFXI3DL2Reverb_SetAllParameters(p,a) (p)->SetAllParameters(a) -#define IDirectSoundFXI3DL2Reverb_GetAllParameters(p,a) (p)->GetAllParameters(a) -#define IDirectSoundFXI3DL2Reverb_SetPreset(p,a) (p)->SetPreset(a) -#define IDirectSoundFXI3DL2Reverb_GetPreset(p,a) (p)->GetPreset(a) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -// -// IDirectSoundFXWavesReverb -// - -DEFINE_GUID(IID_IDirectSoundFXWavesReverb,0x46858c3a,0x0dc6,0x45e3,0xb7,0x60,0xd4,0xee,0xf1,0x6c,0xb3,0x25); - -typedef struct _DSFXWavesReverb -{ - FLOAT fInGain; // [-96.0,0.0] default: 0.0 dB - FLOAT fReverbMix; // [-96.0,0.0] default: 0.0 db - FLOAT fReverbTime; // [0.001,3000.0] default: 1000.0 ms - FLOAT fHighFreqRTRatio; // [0.001,0.999] default: 0.001 -} DSFXWavesReverb, *LPDSFXWavesReverb; - -typedef const DSFXWavesReverb *LPCDSFXWavesReverb; - -#define DSFX_WAVESREVERB_INGAIN_MIN -96.0f -#define DSFX_WAVESREVERB_INGAIN_MAX 0.0f -#define DSFX_WAVESREVERB_INGAIN_DEFAULT 0.0f -#define DSFX_WAVESREVERB_REVERBMIX_MIN -96.0f -#define DSFX_WAVESREVERB_REVERBMIX_MAX 0.0f -#define DSFX_WAVESREVERB_REVERBMIX_DEFAULT 0.0f -#define DSFX_WAVESREVERB_REVERBTIME_MIN 0.001f -#define DSFX_WAVESREVERB_REVERBTIME_MAX 3000.0f -#define DSFX_WAVESREVERB_REVERBTIME_DEFAULT 1000.0f -#define DSFX_WAVESREVERB_HIGHFREQRTRATIO_MIN 0.001f -#define DSFX_WAVESREVERB_HIGHFREQRTRATIO_MAX 0.999f -#define DSFX_WAVESREVERB_HIGHFREQRTRATIO_DEFAULT 0.001f - -#undef INTERFACE -#define INTERFACE IDirectSoundFXWavesReverb - -DECLARE_INTERFACE_(IDirectSoundFXWavesReverb, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSoundFXWavesReverb methods - STDMETHOD(SetAllParameters) (THIS_ LPCDSFXWavesReverb pcDsFxWavesReverb) PURE; - STDMETHOD(GetAllParameters) (THIS_ LPDSFXWavesReverb pDsFxWavesReverb) PURE; -}; - -#define IDirectSoundFXWavesReverb_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSoundFXWavesReverb_AddRef(p) IUnknown_AddRef(p) -#define IDirectSoundFXWavesReverb_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFXWavesReverb_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) -#define IDirectSoundFXWavesReverb_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFXWavesReverb_SetAllParameters(p,a) (p)->SetAllParameters(a) -#define IDirectSoundFXWavesReverb_GetAllParameters(p,a) (p)->GetAllParameters(a) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -// -// IDirectSoundCaptureFXAec -// - -DEFINE_GUID(IID_IDirectSoundCaptureFXAec, 0xad74143d, 0x903d, 0x4ab7, 0x80, 0x66, 0x28, 0xd3, 0x63, 0x03, 0x6d, 0x65); - -typedef struct _DSCFXAec -{ - BOOL fEnable; - BOOL fNoiseFill; - DWORD dwMode; -} DSCFXAec, *LPDSCFXAec; - -typedef const DSCFXAec *LPCDSCFXAec; - -// These match the AEC_MODE_* constants in the DDK's ksmedia.h file -#define DSCFX_AEC_MODE_PASS_THROUGH 0x0 -#define DSCFX_AEC_MODE_HALF_DUPLEX 0x1 -#define DSCFX_AEC_MODE_FULL_DUPLEX 0x2 - -// These match the AEC_STATUS_* constants in ksmedia.h -#define DSCFX_AEC_STATUS_HISTORY_UNINITIALIZED 0x0 -#define DSCFX_AEC_STATUS_HISTORY_CONTINUOUSLY_CONVERGED 0x1 -#define DSCFX_AEC_STATUS_HISTORY_PREVIOUSLY_DIVERGED 0x2 -#define DSCFX_AEC_STATUS_CURRENTLY_CONVERGED 0x8 - -#undef INTERFACE -#define INTERFACE IDirectSoundCaptureFXAec - -DECLARE_INTERFACE_(IDirectSoundCaptureFXAec, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSoundCaptureFXAec methods - STDMETHOD(SetAllParameters) (THIS_ LPCDSCFXAec pDscFxAec) PURE; - STDMETHOD(GetAllParameters) (THIS_ LPDSCFXAec pDscFxAec) PURE; - STDMETHOD(GetStatus) (THIS_ PDWORD pdwStatus) PURE; - STDMETHOD(Reset) (THIS) PURE; -}; - -#define IDirectSoundCaptureFXAec_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSoundCaptureFXAec_AddRef(p) IUnknown_AddRef(p) -#define IDirectSoundCaptureFXAec_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundCaptureFXAec_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) -#define IDirectSoundCaptureFXAec_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundCaptureFXAec_SetAllParameters(p,a) (p)->SetAllParameters(a) -#define IDirectSoundCaptureFXAec_GetAllParameters(p,a) (p)->GetAllParameters(a) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - - -// -// IDirectSoundCaptureFXNoiseSuppress -// - -DEFINE_GUID(IID_IDirectSoundCaptureFXNoiseSuppress, 0xed311e41, 0xfbae, 0x4175, 0x96, 0x25, 0xcd, 0x8, 0x54, 0xf6, 0x93, 0xca); - -typedef struct _DSCFXNoiseSuppress -{ - BOOL fEnable; -} DSCFXNoiseSuppress, *LPDSCFXNoiseSuppress; - -typedef const DSCFXNoiseSuppress *LPCDSCFXNoiseSuppress; - -#undef INTERFACE -#define INTERFACE IDirectSoundCaptureFXNoiseSuppress - -DECLARE_INTERFACE_(IDirectSoundCaptureFXNoiseSuppress, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSoundCaptureFXNoiseSuppress methods - STDMETHOD(SetAllParameters) (THIS_ LPCDSCFXNoiseSuppress pcDscFxNoiseSuppress) PURE; - STDMETHOD(GetAllParameters) (THIS_ LPDSCFXNoiseSuppress pDscFxNoiseSuppress) PURE; - STDMETHOD(Reset) (THIS) PURE; -}; - -#define IDirectSoundCaptureFXNoiseSuppress_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSoundCaptureFXNoiseSuppress_AddRef(p) IUnknown_AddRef(p) -#define IDirectSoundCaptureFXNoiseSuppress_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundCaptureFXNoiseSuppress_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) -#define IDirectSoundCaptureFXNoiseSuppress_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundCaptureFXNoiseSuppress_SetAllParameters(p,a) (p)->SetAllParameters(a) -#define IDirectSoundCaptureFXNoiseSuppress_GetAllParameters(p,a) (p)->GetAllParameters(a) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - - -// -// IDirectSoundFullDuplex -// - -#ifndef _IDirectSoundFullDuplex_ -#define _IDirectSoundFullDuplex_ - -#ifdef __cplusplus -// 'struct' not 'class' per the way DECLARE_INTERFACE_ is defined -struct IDirectSoundFullDuplex; -#endif // __cplusplus - - -DEFINE_GUID(IID_IDirectSoundFullDuplex, 0xedcb4c7a, 0xdaab, 0x4216, 0xa4, 0x2e, 0x6c, 0x50, 0x59, 0x6d, 0xdc, 0x1d); - -#undef INTERFACE -#define INTERFACE IDirectSoundFullDuplex - -DECLARE_INTERFACE_(IDirectSoundFullDuplex, IUnknown) -{ - // IUnknown methods - STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; - - // IDirectSoundFullDuplex methods - STDMETHOD(Initialize) (THIS_ LPCGUID pCaptureGuid, LPCGUID pRenderGuid, LPCDSCBUFFERDESC lpDscBufferDesc, LPCDSBUFFERDESC lpDsBufferDesc, HWND hWnd, DWORD dwLevel, LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8, LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8) PURE; -}; - -#define IDirectSoundFullDuplex_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) -#define IDirectSoundFullDuplex_AddRef(p) IUnknown_AddRef(p) -#define IDirectSoundFullDuplex_Release(p) IUnknown_Release(p) - -#if !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFullDuplex_Initialize(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->Initialize(p,a,b,c,d,e,f,g,h) -#else // !defined(__cplusplus) || defined(CINTERFACE) -#define IDirectSoundFullDuplex_Initialize(p,a,b,c,d,e,f,g,h) (p)->Initialize(a,b,c,d,e,f,g,h) -#endif // !defined(__cplusplus) || defined(CINTERFACE) - -#endif // _IDirectSoundFullDuplex_ - -#endif // DIRECTSOUND_VERSION >= 0x0800 - -// -// Return Codes -// - -// The function completed successfully -#define DS_OK S_OK - -// The call succeeded, but we had to substitute the 3D algorithm -#define DS_NO_VIRTUALIZATION MAKE_HRESULT(0, _FACDS, 10) - -// The call failed because resources (such as a priority level) -// were already being used by another caller -#define DSERR_ALLOCATED MAKE_DSHRESULT(10) - -// The control (vol, pan, etc.) requested by the caller is not available -#define DSERR_CONTROLUNAVAIL MAKE_DSHRESULT(30) - -// An invalid parameter was passed to the returning function -#define DSERR_INVALIDPARAM E_INVALIDARG - -// This call is not valid for the current state of this object -#define DSERR_INVALIDCALL MAKE_DSHRESULT(50) - -// An undetermined error occurred inside the DirectSound subsystem -#define DSERR_GENERIC E_FAIL - -// The caller does not have the priority level required for the function to -// succeed -#define DSERR_PRIOLEVELNEEDED MAKE_DSHRESULT(70) - -// Not enough free memory is available to complete the operation -#define DSERR_OUTOFMEMORY E_OUTOFMEMORY - -// The specified WAVE format is not supported -#define DSERR_BADFORMAT MAKE_DSHRESULT(100) - -// The function called is not supported at this time -#define DSERR_UNSUPPORTED E_NOTIMPL - -// No sound driver is available for use -#define DSERR_NODRIVER MAKE_DSHRESULT(120) - -// This object is already initialized -#define DSERR_ALREADYINITIALIZED MAKE_DSHRESULT(130) - -// This object does not support aggregation -#define DSERR_NOAGGREGATION CLASS_E_NOAGGREGATION - -// The buffer memory has been lost, and must be restored -#define DSERR_BUFFERLOST MAKE_DSHRESULT(150) - -// Another app has a higher priority level, preventing this call from -// succeeding -#define DSERR_OTHERAPPHASPRIO MAKE_DSHRESULT(160) - -// This object has not been initialized -#define DSERR_UNINITIALIZED MAKE_DSHRESULT(170) - -// The requested COM interface is not available -#define DSERR_NOINTERFACE E_NOINTERFACE - -// Access is denied -#define DSERR_ACCESSDENIED E_ACCESSDENIED - -// Tried to create a DSBCAPS_CTRLFX buffer shorter than DSBSIZE_FX_MIN milliseconds -#define DSERR_BUFFERTOOSMALL MAKE_DSHRESULT(180) - -// Attempt to use DirectSound 8 functionality on an older DirectSound object -#define DSERR_DS8_REQUIRED MAKE_DSHRESULT(190) - -// A circular loop of send effects was detected -#define DSERR_SENDLOOP MAKE_DSHRESULT(200) - -// The GUID specified in an audiopath file does not match a valid MIXIN buffer -#define DSERR_BADSENDBUFFERGUID MAKE_DSHRESULT(210) - -// The object requested was not found (numerically equal to DMUS_E_NOT_FOUND) -#define DSERR_OBJECTNOTFOUND MAKE_DSHRESULT(4449) - -// The effects requested could not be found on the system, or they were found -// but in the wrong order, or in the wrong hardware/software locations. -#define DSERR_FXUNAVAILABLE MAKE_DSHRESULT(220) - -// -// Flags -// - -#define DSCAPS_PRIMARYMONO 0x00000001 -#define DSCAPS_PRIMARYSTEREO 0x00000002 -#define DSCAPS_PRIMARY8BIT 0x00000004 -#define DSCAPS_PRIMARY16BIT 0x00000008 -#define DSCAPS_CONTINUOUSRATE 0x00000010 -#define DSCAPS_EMULDRIVER 0x00000020 -#define DSCAPS_CERTIFIED 0x00000040 -#define DSCAPS_SECONDARYMONO 0x00000100 -#define DSCAPS_SECONDARYSTEREO 0x00000200 -#define DSCAPS_SECONDARY8BIT 0x00000400 -#define DSCAPS_SECONDARY16BIT 0x00000800 - -#define DSSCL_NORMAL 0x00000001 -#define DSSCL_PRIORITY 0x00000002 -#define DSSCL_EXCLUSIVE 0x00000003 -#define DSSCL_WRITEPRIMARY 0x00000004 - -#define DSSPEAKER_DIRECTOUT 0x00000000 -#define DSSPEAKER_HEADPHONE 0x00000001 -#define DSSPEAKER_MONO 0x00000002 -#define DSSPEAKER_QUAD 0x00000003 -#define DSSPEAKER_STEREO 0x00000004 -#define DSSPEAKER_SURROUND 0x00000005 -#define DSSPEAKER_5POINT1 0x00000006 -#define DSSPEAKER_7POINT1 0x00000007 - -#define DSSPEAKER_GEOMETRY_MIN 0x00000005 // 5 degrees -#define DSSPEAKER_GEOMETRY_NARROW 0x0000000A // 10 degrees -#define DSSPEAKER_GEOMETRY_WIDE 0x00000014 // 20 degrees -#define DSSPEAKER_GEOMETRY_MAX 0x000000B4 // 180 degrees - -#define DSSPEAKER_COMBINED(c, g) ((DWORD)(((BYTE)(c)) | ((DWORD)((BYTE)(g))) << 16)) -#define DSSPEAKER_CONFIG(a) ((BYTE)(a)) -#define DSSPEAKER_GEOMETRY(a) ((BYTE)(((DWORD)(a) >> 16) & 0x00FF)) - -#define DSBCAPS_PRIMARYBUFFER 0x00000001 -#define DSBCAPS_STATIC 0x00000002 -#define DSBCAPS_LOCHARDWARE 0x00000004 -#define DSBCAPS_LOCSOFTWARE 0x00000008 -#define DSBCAPS_CTRL3D 0x00000010 -#define DSBCAPS_CTRLFREQUENCY 0x00000020 -#define DSBCAPS_CTRLPAN 0x00000040 -#define DSBCAPS_CTRLVOLUME 0x00000080 -#define DSBCAPS_CTRLPOSITIONNOTIFY 0x00000100 -#define DSBCAPS_CTRLFX 0x00000200 -#define DSBCAPS_STICKYFOCUS 0x00004000 -#define DSBCAPS_GLOBALFOCUS 0x00008000 -#define DSBCAPS_GETCURRENTPOSITION2 0x00010000 -#define DSBCAPS_MUTE3DATMAXDISTANCE 0x00020000 -#define DSBCAPS_LOCDEFER 0x00040000 - -#define DSBPLAY_LOOPING 0x00000001 -#define DSBPLAY_LOCHARDWARE 0x00000002 -#define DSBPLAY_LOCSOFTWARE 0x00000004 -#define DSBPLAY_TERMINATEBY_TIME 0x00000008 -#define DSBPLAY_TERMINATEBY_DISTANCE 0x000000010 -#define DSBPLAY_TERMINATEBY_PRIORITY 0x000000020 - -#define DSBSTATUS_PLAYING 0x00000001 -#define DSBSTATUS_BUFFERLOST 0x00000002 -#define DSBSTATUS_LOOPING 0x00000004 -#define DSBSTATUS_LOCHARDWARE 0x00000008 -#define DSBSTATUS_LOCSOFTWARE 0x00000010 -#define DSBSTATUS_TERMINATED 0x00000020 - -#define DSBLOCK_FROMWRITECURSOR 0x00000001 -#define DSBLOCK_ENTIREBUFFER 0x00000002 - -#define DSBFREQUENCY_ORIGINAL 0 -#define DSBFREQUENCY_MIN 100 -#if DIRECTSOUND_VERSION >= 0x0900 -#define DSBFREQUENCY_MAX 200000 -#else -#define DSBFREQUENCY_MAX 100000 -#endif - -#define DSBPAN_LEFT -10000 -#define DSBPAN_CENTER 0 -#define DSBPAN_RIGHT 10000 - -#define DSBVOLUME_MIN -10000 -#define DSBVOLUME_MAX 0 - -#define DSBSIZE_MIN 4 -#define DSBSIZE_MAX 0x0FFFFFFF -#define DSBSIZE_FX_MIN 150 // NOTE: Milliseconds, not bytes - -#define DS3DMODE_NORMAL 0x00000000 -#define DS3DMODE_HEADRELATIVE 0x00000001 -#define DS3DMODE_DISABLE 0x00000002 - -#define DS3D_IMMEDIATE 0x00000000 -#define DS3D_DEFERRED 0x00000001 - -#define DS3D_MINDISTANCEFACTOR FLT_MIN -#define DS3D_MAXDISTANCEFACTOR FLT_MAX -#define DS3D_DEFAULTDISTANCEFACTOR 1.0f - -#define DS3D_MINROLLOFFFACTOR 0.0f -#define DS3D_MAXROLLOFFFACTOR 10.0f -#define DS3D_DEFAULTROLLOFFFACTOR 1.0f - -#define DS3D_MINDOPPLERFACTOR 0.0f -#define DS3D_MAXDOPPLERFACTOR 10.0f -#define DS3D_DEFAULTDOPPLERFACTOR 1.0f - -#define DS3D_DEFAULTMINDISTANCE 1.0f -#define DS3D_DEFAULTMAXDISTANCE 1000000000.0f - -#define DS3D_MINCONEANGLE 0 -#define DS3D_MAXCONEANGLE 360 -#define DS3D_DEFAULTCONEANGLE 360 - -#define DS3D_DEFAULTCONEOUTSIDEVOLUME DSBVOLUME_MAX - -// IDirectSoundCapture attributes - -#define DSCCAPS_EMULDRIVER DSCAPS_EMULDRIVER -#define DSCCAPS_CERTIFIED DSCAPS_CERTIFIED -#define DSCCAPS_MULTIPLECAPTURE 0x00000001 - -// IDirectSoundCaptureBuffer attributes - -#define DSCBCAPS_WAVEMAPPED 0x80000000 - -#if DIRECTSOUND_VERSION >= 0x0800 -#define DSCBCAPS_CTRLFX 0x00000200 -#endif - - -#define DSCBLOCK_ENTIREBUFFER 0x00000001 - -#define DSCBSTATUS_CAPTURING 0x00000001 -#define DSCBSTATUS_LOOPING 0x00000002 - -#define DSCBSTART_LOOPING 0x00000001 - -#define DSBPN_OFFSETSTOP 0xFFFFFFFF - -#define DS_CERTIFIED 0x00000000 -#define DS_UNCERTIFIED 0x00000001 - - -// -// Flags for the I3DL2 effects -// - -// -// I3DL2 Material Presets -// - -enum -{ - DSFX_I3DL2_MATERIAL_PRESET_SINGLEWINDOW, - DSFX_I3DL2_MATERIAL_PRESET_DOUBLEWINDOW, - DSFX_I3DL2_MATERIAL_PRESET_THINDOOR, - DSFX_I3DL2_MATERIAL_PRESET_THICKDOOR, - DSFX_I3DL2_MATERIAL_PRESET_WOODWALL, - DSFX_I3DL2_MATERIAL_PRESET_BRICKWALL, - DSFX_I3DL2_MATERIAL_PRESET_STONEWALL, - DSFX_I3DL2_MATERIAL_PRESET_CURTAIN -}; - -#define I3DL2_MATERIAL_PRESET_SINGLEWINDOW -2800,0.71f -#define I3DL2_MATERIAL_PRESET_DOUBLEWINDOW -5000,0.40f -#define I3DL2_MATERIAL_PRESET_THINDOOR -1800,0.66f -#define I3DL2_MATERIAL_PRESET_THICKDOOR -4400,0.64f -#define I3DL2_MATERIAL_PRESET_WOODWALL -4000,0.50f -#define I3DL2_MATERIAL_PRESET_BRICKWALL -5000,0.60f -#define I3DL2_MATERIAL_PRESET_STONEWALL -6000,0.68f -#define I3DL2_MATERIAL_PRESET_CURTAIN -1200,0.15f - -enum -{ - DSFX_I3DL2_ENVIRONMENT_PRESET_DEFAULT, - DSFX_I3DL2_ENVIRONMENT_PRESET_GENERIC, - DSFX_I3DL2_ENVIRONMENT_PRESET_PADDEDCELL, - DSFX_I3DL2_ENVIRONMENT_PRESET_ROOM, - DSFX_I3DL2_ENVIRONMENT_PRESET_BATHROOM, - DSFX_I3DL2_ENVIRONMENT_PRESET_LIVINGROOM, - DSFX_I3DL2_ENVIRONMENT_PRESET_STONEROOM, - DSFX_I3DL2_ENVIRONMENT_PRESET_AUDITORIUM, - DSFX_I3DL2_ENVIRONMENT_PRESET_CONCERTHALL, - DSFX_I3DL2_ENVIRONMENT_PRESET_CAVE, - DSFX_I3DL2_ENVIRONMENT_PRESET_ARENA, - DSFX_I3DL2_ENVIRONMENT_PRESET_HANGAR, - DSFX_I3DL2_ENVIRONMENT_PRESET_CARPETEDHALLWAY, - DSFX_I3DL2_ENVIRONMENT_PRESET_HALLWAY, - DSFX_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR, - DSFX_I3DL2_ENVIRONMENT_PRESET_ALLEY, - DSFX_I3DL2_ENVIRONMENT_PRESET_FOREST, - DSFX_I3DL2_ENVIRONMENT_PRESET_CITY, - DSFX_I3DL2_ENVIRONMENT_PRESET_MOUNTAINS, - DSFX_I3DL2_ENVIRONMENT_PRESET_QUARRY, - DSFX_I3DL2_ENVIRONMENT_PRESET_PLAIN, - DSFX_I3DL2_ENVIRONMENT_PRESET_PARKINGLOT, - DSFX_I3DL2_ENVIRONMENT_PRESET_SEWERPIPE, - DSFX_I3DL2_ENVIRONMENT_PRESET_UNDERWATER, - DSFX_I3DL2_ENVIRONMENT_PRESET_SMALLROOM, - DSFX_I3DL2_ENVIRONMENT_PRESET_MEDIUMROOM, - DSFX_I3DL2_ENVIRONMENT_PRESET_LARGEROOM, - DSFX_I3DL2_ENVIRONMENT_PRESET_MEDIUMHALL, - DSFX_I3DL2_ENVIRONMENT_PRESET_LARGEHALL, - DSFX_I3DL2_ENVIRONMENT_PRESET_PLATE -}; - -// -// I3DL2 Reverberation Presets Values -// - -#define I3DL2_ENVIRONMENT_PRESET_DEFAULT -1000, -100, 0.0f, 1.49f, 0.83f, -2602, 0.007f, 200, 0.011f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_GENERIC -1000, -100, 0.0f, 1.49f, 0.83f, -2602, 0.007f, 200, 0.011f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_PADDEDCELL -1000,-6000, 0.0f, 0.17f, 0.10f, -1204, 0.001f, 207, 0.002f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_ROOM -1000, -454, 0.0f, 0.40f, 0.83f, -1646, 0.002f, 53, 0.003f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_BATHROOM -1000,-1200, 0.0f, 1.49f, 0.54f, -370, 0.007f, 1030, 0.011f, 100.0f, 60.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_LIVINGROOM -1000,-6000, 0.0f, 0.50f, 0.10f, -1376, 0.003f, -1104, 0.004f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_STONEROOM -1000, -300, 0.0f, 2.31f, 0.64f, -711, 0.012f, 83, 0.017f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_AUDITORIUM -1000, -476, 0.0f, 4.32f, 0.59f, -789, 0.020f, -289, 0.030f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_CONCERTHALL -1000, -500, 0.0f, 3.92f, 0.70f, -1230, 0.020f, -2, 0.029f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_CAVE -1000, 0, 0.0f, 2.91f, 1.30f, -602, 0.015f, -302, 0.022f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_ARENA -1000, -698, 0.0f, 7.24f, 0.33f, -1166, 0.020f, 16, 0.030f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_HANGAR -1000,-1000, 0.0f,10.05f, 0.23f, -602, 0.020f, 198, 0.030f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_CARPETEDHALLWAY -1000,-4000, 0.0f, 0.30f, 0.10f, -1831, 0.002f, -1630, 0.030f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_HALLWAY -1000, -300, 0.0f, 1.49f, 0.59f, -1219, 0.007f, 441, 0.011f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR -1000, -237, 0.0f, 2.70f, 0.79f, -1214, 0.013f, 395, 0.020f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_ALLEY -1000, -270, 0.0f, 1.49f, 0.86f, -1204, 0.007f, -4, 0.011f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_FOREST -1000,-3300, 0.0f, 1.49f, 0.54f, -2560, 0.162f, -613, 0.088f, 79.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_CITY -1000, -800, 0.0f, 1.49f, 0.67f, -2273, 0.007f, -2217, 0.011f, 50.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_MOUNTAINS -1000,-2500, 0.0f, 1.49f, 0.21f, -2780, 0.300f, -2014, 0.100f, 27.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_QUARRY -1000,-1000, 0.0f, 1.49f, 0.83f,-10000, 0.061f, 500, 0.025f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_PLAIN -1000,-2000, 0.0f, 1.49f, 0.50f, -2466, 0.179f, -2514, 0.100f, 21.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_PARKINGLOT -1000, 0, 0.0f, 1.65f, 1.50f, -1363, 0.008f, -1153, 0.012f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_SEWERPIPE -1000,-1000, 0.0f, 2.81f, 0.14f, 429, 0.014f, 648, 0.021f, 80.0f, 60.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_UNDERWATER -1000,-4000, 0.0f, 1.49f, 0.10f, -449, 0.007f, 1700, 0.011f, 100.0f, 100.0f, 5000.0f - -// -// Examples simulating 'musical' reverb presets -// -// Name Decay time Description -// Small Room 1.1s A small size room with a length of 5m or so. -// Medium Room 1.3s A medium size room with a length of 10m or so. -// Large Room 1.5s A large size room suitable for live performances. -// Medium Hall 1.8s A medium size concert hall. -// Large Hall 1.8s A large size concert hall suitable for a full orchestra. -// Plate 1.3s A plate reverb simulation. -// - -#define I3DL2_ENVIRONMENT_PRESET_SMALLROOM -1000, -600, 0.0f, 1.10f, 0.83f, -400, 0.005f, 500, 0.010f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_MEDIUMROOM -1000, -600, 0.0f, 1.30f, 0.83f, -1000, 0.010f, -200, 0.020f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_LARGEROOM -1000, -600, 0.0f, 1.50f, 0.83f, -1600, 0.020f, -1000, 0.040f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_MEDIUMHALL -1000, -600, 0.0f, 1.80f, 0.70f, -1300, 0.015f, -800, 0.030f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_LARGEHALL -1000, -600, 0.0f, 1.80f, 0.70f, -2000, 0.030f, -1400, 0.060f, 100.0f, 100.0f, 5000.0f -#define I3DL2_ENVIRONMENT_PRESET_PLATE -1000, -200, 0.0f, 1.30f, 0.90f, 0, 0.002f, 0, 0.010f, 100.0f, 75.0f, 5000.0f - -// -// DirectSound3D Algorithms -// - -// Default DirectSound3D algorithm {00000000-0000-0000-0000-000000000000} -#define DS3DALG_DEFAULT GUID_NULL - -// No virtualization (Pan3D) {C241333F-1C1B-11d2-94F5-00C04FC28ACA} -DEFINE_GUID(DS3DALG_NO_VIRTUALIZATION, 0xc241333f, 0x1c1b, 0x11d2, 0x94, 0xf5, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca); - -// High-quality HRTF algorithm {C2413340-1C1B-11d2-94F5-00C04FC28ACA} -DEFINE_GUID(DS3DALG_HRTF_FULL, 0xc2413340, 0x1c1b, 0x11d2, 0x94, 0xf5, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca); - -// Lower-quality HRTF algorithm {C2413342-1C1B-11d2-94F5-00C04FC28ACA} -DEFINE_GUID(DS3DALG_HRTF_LIGHT, 0xc2413342, 0x1c1b, 0x11d2, 0x94, 0xf5, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca); - - -#if DIRECTSOUND_VERSION >= 0x0800 - -// -// DirectSound Internal Effect Algorithms -// - - -// Gargle {DAFD8210-5711-4B91-9FE3-F75B7AE279BF} -DEFINE_GUID(GUID_DSFX_STANDARD_GARGLE, 0xdafd8210, 0x5711, 0x4b91, 0x9f, 0xe3, 0xf7, 0x5b, 0x7a, 0xe2, 0x79, 0xbf); - -// Chorus {EFE6629C-81F7-4281-BD91-C9D604A95AF6} -DEFINE_GUID(GUID_DSFX_STANDARD_CHORUS, 0xefe6629c, 0x81f7, 0x4281, 0xbd, 0x91, 0xc9, 0xd6, 0x04, 0xa9, 0x5a, 0xf6); - -// Flanger {EFCA3D92-DFD8-4672-A603-7420894BAD98} -DEFINE_GUID(GUID_DSFX_STANDARD_FLANGER, 0xefca3d92, 0xdfd8, 0x4672, 0xa6, 0x03, 0x74, 0x20, 0x89, 0x4b, 0xad, 0x98); - -// Echo/Delay {EF3E932C-D40B-4F51-8CCF-3F98F1B29D5D} -DEFINE_GUID(GUID_DSFX_STANDARD_ECHO, 0xef3e932c, 0xd40b, 0x4f51, 0x8c, 0xcf, 0x3f, 0x98, 0xf1, 0xb2, 0x9d, 0x5d); - -// Distortion {EF114C90-CD1D-484E-96E5-09CFAF912A21} -DEFINE_GUID(GUID_DSFX_STANDARD_DISTORTION, 0xef114c90, 0xcd1d, 0x484e, 0x96, 0xe5, 0x09, 0xcf, 0xaf, 0x91, 0x2a, 0x21); - -// Compressor/Limiter {EF011F79-4000-406D-87AF-BFFB3FC39D57} -DEFINE_GUID(GUID_DSFX_STANDARD_COMPRESSOR, 0xef011f79, 0x4000, 0x406d, 0x87, 0xaf, 0xbf, 0xfb, 0x3f, 0xc3, 0x9d, 0x57); - -// Parametric Equalization {120CED89-3BF4-4173-A132-3CB406CF3231} -DEFINE_GUID(GUID_DSFX_STANDARD_PARAMEQ, 0x120ced89, 0x3bf4, 0x4173, 0xa1, 0x32, 0x3c, 0xb4, 0x06, 0xcf, 0x32, 0x31); - -// I3DL2 Environmental Reverberation: Reverb (Listener) Effect {EF985E71-D5C7-42D4-BA4D-2D073E2E96F4} -DEFINE_GUID(GUID_DSFX_STANDARD_I3DL2REVERB, 0xef985e71, 0xd5c7, 0x42d4, 0xba, 0x4d, 0x2d, 0x07, 0x3e, 0x2e, 0x96, 0xf4); - -// Waves Reverberation {87FC0268-9A55-4360-95AA-004A1D9DE26C} -DEFINE_GUID(GUID_DSFX_WAVES_REVERB, 0x87fc0268, 0x9a55, 0x4360, 0x95, 0xaa, 0x00, 0x4a, 0x1d, 0x9d, 0xe2, 0x6c); - -// -// DirectSound Capture Effect Algorithms -// - - -// Acoustic Echo Canceller {BF963D80-C559-11D0-8A2B-00A0C9255AC1} -// Matches KSNODETYPE_ACOUSTIC_ECHO_CANCEL in ksmedia.h -DEFINE_GUID(GUID_DSCFX_CLASS_AEC, 0xBF963D80L, 0xC559, 0x11D0, 0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1); - -// Microsoft AEC {CDEBB919-379A-488a-8765-F53CFD36DE40} -DEFINE_GUID(GUID_DSCFX_MS_AEC, 0xcdebb919, 0x379a, 0x488a, 0x87, 0x65, 0xf5, 0x3c, 0xfd, 0x36, 0xde, 0x40); - -// System AEC {1C22C56D-9879-4f5b-A389-27996DDC2810} -DEFINE_GUID(GUID_DSCFX_SYSTEM_AEC, 0x1c22c56d, 0x9879, 0x4f5b, 0xa3, 0x89, 0x27, 0x99, 0x6d, 0xdc, 0x28, 0x10); - -// Noise Supression {E07F903F-62FD-4e60-8CDD-DEA7236665B5} -// Matches KSNODETYPE_NOISE_SUPPRESS in post Windows ME DDK's ksmedia.h -DEFINE_GUID(GUID_DSCFX_CLASS_NS, 0xe07f903f, 0x62fd, 0x4e60, 0x8c, 0xdd, 0xde, 0xa7, 0x23, 0x66, 0x65, 0xb5); - -// Microsoft Noise Suppresion {11C5C73B-66E9-4ba1-A0BA-E814C6EED92D} -DEFINE_GUID(GUID_DSCFX_MS_NS, 0x11c5c73b, 0x66e9, 0x4ba1, 0xa0, 0xba, 0xe8, 0x14, 0xc6, 0xee, 0xd9, 0x2d); - -// System Noise Suppresion {5AB0882E-7274-4516-877D-4EEE99BA4FD0} -DEFINE_GUID(GUID_DSCFX_SYSTEM_NS, 0x5ab0882e, 0x7274, 0x4516, 0x87, 0x7d, 0x4e, 0xee, 0x99, 0xba, 0x4f, 0xd0); - -#endif // DIRECTSOUND_VERSION >= 0x0800 - -#endif // __DSOUND_INCLUDED__ - - - -#ifdef __cplusplus -}; -#endif // __cplusplus - - +/*==========================================================================; + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * File: dsound.h + * Content: DirectSound include file + * + **************************************************************************/ + +#define COM_NO_WINDOWS_H +#include +#include + +#ifndef DIRECTSOUND_VERSION +#define DIRECTSOUND_VERSION 0x0900 /* Version 9.0 */ +#endif + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#ifndef __DSOUND_INCLUDED__ +#define __DSOUND_INCLUDED__ + +/* Type definitions shared with Direct3D */ + +#ifndef DX_SHARED_DEFINES + +typedef float D3DVALUE, *LPD3DVALUE; + +#ifndef D3DCOLOR_DEFINED +typedef DWORD D3DCOLOR; +#define D3DCOLOR_DEFINED +#endif + +#ifndef LPD3DCOLOR_DEFINED +typedef DWORD *LPD3DCOLOR; +#define LPD3DCOLOR_DEFINED +#endif + +#ifndef D3DVECTOR_DEFINED +typedef struct _D3DVECTOR { + float x; + float y; + float z; +} D3DVECTOR; +#define D3DVECTOR_DEFINED +#endif + +#ifndef LPD3DVECTOR_DEFINED +typedef D3DVECTOR *LPD3DVECTOR; +#define LPD3DVECTOR_DEFINED +#endif + +#define DX_SHARED_DEFINES +#endif // DX_SHARED_DEFINES + +#define _FACDS 0x878 /* DirectSound's facility code */ +#define MAKE_DSHRESULT(code) MAKE_HRESULT(1, _FACDS, code) + +// DirectSound Component GUID {47D4D946-62E8-11CF-93BC-444553540000} +DEFINE_GUID(CLSID_DirectSound, 0x47d4d946, 0x62e8, 0x11cf, 0x93, 0xbc, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0); + +// DirectSound 8.0 Component GUID {3901CC3F-84B5-4FA4-BA35-AA8172B8A09B} +DEFINE_GUID(CLSID_DirectSound8, 0x3901cc3f, 0x84b5, 0x4fa4, 0xba, 0x35, 0xaa, 0x81, 0x72, 0xb8, 0xa0, 0x9b); + +// DirectSound Capture Component GUID {B0210780-89CD-11D0-AF08-00A0C925CD16} +DEFINE_GUID(CLSID_DirectSoundCapture, 0xb0210780, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); + +// DirectSound 8.0 Capture Component GUID {E4BCAC13-7F99-4908-9A8E-74E3BF24B6E1} +DEFINE_GUID(CLSID_DirectSoundCapture8, 0xe4bcac13, 0x7f99, 0x4908, 0x9a, 0x8e, 0x74, 0xe3, 0xbf, 0x24, 0xb6, 0xe1); + +// DirectSound Full Duplex Component GUID {FEA4300C-7959-4147-B26A-2377B9E7A91D} +DEFINE_GUID(CLSID_DirectSoundFullDuplex, 0xfea4300c, 0x7959, 0x4147, 0xb2, 0x6a, 0x23, 0x77, 0xb9, 0xe7, 0xa9, 0x1d); + + +// DirectSound default playback device GUID {DEF00000-9C6D-47ED-AAF1-4DDA8F2B5C03} +DEFINE_GUID(DSDEVID_DefaultPlayback, 0xdef00000, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03); + +// DirectSound default capture device GUID {DEF00001-9C6D-47ED-AAF1-4DDA8F2B5C03} +DEFINE_GUID(DSDEVID_DefaultCapture, 0xdef00001, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03); + +// DirectSound default device for voice playback {DEF00002-9C6D-47ED-AAF1-4DDA8F2B5C03} +DEFINE_GUID(DSDEVID_DefaultVoicePlayback, 0xdef00002, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03); + +// DirectSound default device for voice capture {DEF00003-9C6D-47ED-AAF1-4DDA8F2B5C03} +DEFINE_GUID(DSDEVID_DefaultVoiceCapture, 0xdef00003, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03); + + +// +// Forward declarations for interfaces. +// 'struct' not 'class' per the way DECLARE_INTERFACE_ is defined +// + +#ifdef __cplusplus +struct IDirectSound; +struct IDirectSoundBuffer; +struct IDirectSound3DListener; +struct IDirectSound3DBuffer; +struct IDirectSoundCapture; +struct IDirectSoundCaptureBuffer; +struct IDirectSoundNotify; +#endif // __cplusplus + + +// +// DirectSound 8.0 interfaces. +// + +#if DIRECTSOUND_VERSION >= 0x0800 + +#ifdef __cplusplus +struct IDirectSound8; +struct IDirectSoundBuffer8; +struct IDirectSoundCaptureBuffer8; +struct IDirectSoundFXGargle; +struct IDirectSoundFXChorus; +struct IDirectSoundFXFlanger; +struct IDirectSoundFXEcho; +struct IDirectSoundFXDistortion; +struct IDirectSoundFXCompressor; +struct IDirectSoundFXParamEq; +struct IDirectSoundFXWavesReverb; +struct IDirectSoundFXI3DL2Reverb; +struct IDirectSoundCaptureFXAec; +struct IDirectSoundCaptureFXNoiseSuppress; +struct IDirectSoundFullDuplex; +#endif // __cplusplus + +// IDirectSound8, IDirectSoundBuffer8 and IDirectSoundCaptureBuffer8 are the +// only DirectSound 7.0 interfaces with changed functionality in version 8.0. +// The other level 8 interfaces as equivalent to their level 7 counterparts: + +#define IDirectSoundCapture8 IDirectSoundCapture +#define IDirectSound3DListener8 IDirectSound3DListener +#define IDirectSound3DBuffer8 IDirectSound3DBuffer +#define IDirectSoundNotify8 IDirectSoundNotify +#define IDirectSoundFXGargle8 IDirectSoundFXGargle +#define IDirectSoundFXChorus8 IDirectSoundFXChorus +#define IDirectSoundFXFlanger8 IDirectSoundFXFlanger +#define IDirectSoundFXEcho8 IDirectSoundFXEcho +#define IDirectSoundFXDistortion8 IDirectSoundFXDistortion +#define IDirectSoundFXCompressor8 IDirectSoundFXCompressor +#define IDirectSoundFXParamEq8 IDirectSoundFXParamEq +#define IDirectSoundFXWavesReverb8 IDirectSoundFXWavesReverb +#define IDirectSoundFXI3DL2Reverb8 IDirectSoundFXI3DL2Reverb +#define IDirectSoundCaptureFXAec8 IDirectSoundCaptureFXAec +#define IDirectSoundCaptureFXNoiseSuppress8 IDirectSoundCaptureFXNoiseSuppress +#define IDirectSoundFullDuplex8 IDirectSoundFullDuplex + +#endif // DIRECTSOUND_VERSION >= 0x0800 + +typedef struct IDirectSound *LPDIRECTSOUND; +typedef struct IDirectSoundBuffer *LPDIRECTSOUNDBUFFER; +typedef struct IDirectSound3DListener *LPDIRECTSOUND3DLISTENER; +typedef struct IDirectSound3DBuffer *LPDIRECTSOUND3DBUFFER; +typedef struct IDirectSoundCapture *LPDIRECTSOUNDCAPTURE; +typedef struct IDirectSoundCaptureBuffer *LPDIRECTSOUNDCAPTUREBUFFER; +typedef struct IDirectSoundNotify *LPDIRECTSOUNDNOTIFY; + + +#if DIRECTSOUND_VERSION >= 0x0800 + +typedef struct IDirectSoundFXGargle *LPDIRECTSOUNDFXGARGLE; +typedef struct IDirectSoundFXChorus *LPDIRECTSOUNDFXCHORUS; +typedef struct IDirectSoundFXFlanger *LPDIRECTSOUNDFXFLANGER; +typedef struct IDirectSoundFXEcho *LPDIRECTSOUNDFXECHO; +typedef struct IDirectSoundFXDistortion *LPDIRECTSOUNDFXDISTORTION; +typedef struct IDirectSoundFXCompressor *LPDIRECTSOUNDFXCOMPRESSOR; +typedef struct IDirectSoundFXParamEq *LPDIRECTSOUNDFXPARAMEQ; +typedef struct IDirectSoundFXWavesReverb *LPDIRECTSOUNDFXWAVESREVERB; +typedef struct IDirectSoundFXI3DL2Reverb *LPDIRECTSOUNDFXI3DL2REVERB; +typedef struct IDirectSoundCaptureFXAec *LPDIRECTSOUNDCAPTUREFXAEC; +typedef struct IDirectSoundCaptureFXNoiseSuppress *LPDIRECTSOUNDCAPTUREFXNOISESUPPRESS; +typedef struct IDirectSoundFullDuplex *LPDIRECTSOUNDFULLDUPLEX; + +typedef struct IDirectSound8 *LPDIRECTSOUND8; +typedef struct IDirectSoundBuffer8 *LPDIRECTSOUNDBUFFER8; +typedef struct IDirectSound3DListener8 *LPDIRECTSOUND3DLISTENER8; +typedef struct IDirectSound3DBuffer8 *LPDIRECTSOUND3DBUFFER8; +typedef struct IDirectSoundCapture8 *LPDIRECTSOUNDCAPTURE8; +typedef struct IDirectSoundCaptureBuffer8 *LPDIRECTSOUNDCAPTUREBUFFER8; +typedef struct IDirectSoundNotify8 *LPDIRECTSOUNDNOTIFY8; +typedef struct IDirectSoundFXGargle8 *LPDIRECTSOUNDFXGARGLE8; +typedef struct IDirectSoundFXChorus8 *LPDIRECTSOUNDFXCHORUS8; +typedef struct IDirectSoundFXFlanger8 *LPDIRECTSOUNDFXFLANGER8; +typedef struct IDirectSoundFXEcho8 *LPDIRECTSOUNDFXECHO8; +typedef struct IDirectSoundFXDistortion8 *LPDIRECTSOUNDFXDISTORTION8; +typedef struct IDirectSoundFXCompressor8 *LPDIRECTSOUNDFXCOMPRESSOR8; +typedef struct IDirectSoundFXParamEq8 *LPDIRECTSOUNDFXPARAMEQ8; +typedef struct IDirectSoundFXWavesReverb8 *LPDIRECTSOUNDFXWAVESREVERB8; +typedef struct IDirectSoundFXI3DL2Reverb8 *LPDIRECTSOUNDFXI3DL2REVERB8; +typedef struct IDirectSoundCaptureFXAec8 *LPDIRECTSOUNDCAPTUREFXAEC8; +typedef struct IDirectSoundCaptureFXNoiseSuppress8 *LPDIRECTSOUNDCAPTUREFXNOISESUPPRESS8; +typedef struct IDirectSoundFullDuplex8 *LPDIRECTSOUNDFULLDUPLEX8; + +#endif // DIRECTSOUND_VERSION >= 0x0800 + +// +// IID definitions for the unchanged DirectSound 8.0 interfaces +// + +#if DIRECTSOUND_VERSION >= 0x0800 + +#define IID_IDirectSoundCapture8 IID_IDirectSoundCapture +#define IID_IDirectSound3DListener8 IID_IDirectSound3DListener +#define IID_IDirectSound3DBuffer8 IID_IDirectSound3DBuffer +#define IID_IDirectSoundNotify8 IID_IDirectSoundNotify +#define IID_IDirectSoundFXGargle8 IID_IDirectSoundFXGargle +#define IID_IDirectSoundFXChorus8 IID_IDirectSoundFXChorus +#define IID_IDirectSoundFXFlanger8 IID_IDirectSoundFXFlanger +#define IID_IDirectSoundFXEcho8 IID_IDirectSoundFXEcho +#define IID_IDirectSoundFXDistortion8 IID_IDirectSoundFXDistortion +#define IID_IDirectSoundFXCompressor8 IID_IDirectSoundFXCompressor +#define IID_IDirectSoundFXParamEq8 IID_IDirectSoundFXParamEq +#define IID_IDirectSoundFXWavesReverb8 IID_IDirectSoundFXWavesReverb +#define IID_IDirectSoundFXI3DL2Reverb8 IID_IDirectSoundFXI3DL2Reverb +#define IID_IDirectSoundCaptureFXAec8 IID_IDirectSoundCaptureFXAec +#define IID_IDirectSoundCaptureFXNoiseSuppress8 IID_IDirectSoundCaptureFXNoiseSuppress +#define IID_IDirectSoundFullDuplex8 IID_IDirectSoundFullDuplex + +#endif // DIRECTSOUND_VERSION >= 0x0800 + +// +// Compatibility typedefs +// + +#ifndef _LPCWAVEFORMATEX_DEFINED +#define _LPCWAVEFORMATEX_DEFINED +typedef const WAVEFORMATEX *LPCWAVEFORMATEX; +#endif // _LPCWAVEFORMATEX_DEFINED + +#ifndef __LPCGUID_DEFINED__ +#define __LPCGUID_DEFINED__ +typedef const GUID *LPCGUID; +#endif // __LPCGUID_DEFINED__ + +typedef LPDIRECTSOUND *LPLPDIRECTSOUND; +typedef LPDIRECTSOUNDBUFFER *LPLPDIRECTSOUNDBUFFER; +typedef LPDIRECTSOUND3DLISTENER *LPLPDIRECTSOUND3DLISTENER; +typedef LPDIRECTSOUND3DBUFFER *LPLPDIRECTSOUND3DBUFFER; +typedef LPDIRECTSOUNDCAPTURE *LPLPDIRECTSOUNDCAPTURE; +typedef LPDIRECTSOUNDCAPTUREBUFFER *LPLPDIRECTSOUNDCAPTUREBUFFER; +typedef LPDIRECTSOUNDNOTIFY *LPLPDIRECTSOUNDNOTIFY; + +#if DIRECTSOUND_VERSION >= 0x0800 +typedef LPDIRECTSOUND8 *LPLPDIRECTSOUND8; +typedef LPDIRECTSOUNDBUFFER8 *LPLPDIRECTSOUNDBUFFER8; +typedef LPDIRECTSOUNDCAPTURE8 *LPLPDIRECTSOUNDCAPTURE8; +typedef LPDIRECTSOUNDCAPTUREBUFFER8 *LPLPDIRECTSOUNDCAPTUREBUFFER8; +#endif // DIRECTSOUND_VERSION >= 0x0800 + +// +// Structures +// + +typedef struct _DSCAPS +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwMinSecondarySampleRate; + DWORD dwMaxSecondarySampleRate; + DWORD dwPrimaryBuffers; + DWORD dwMaxHwMixingAllBuffers; + DWORD dwMaxHwMixingStaticBuffers; + DWORD dwMaxHwMixingStreamingBuffers; + DWORD dwFreeHwMixingAllBuffers; + DWORD dwFreeHwMixingStaticBuffers; + DWORD dwFreeHwMixingStreamingBuffers; + DWORD dwMaxHw3DAllBuffers; + DWORD dwMaxHw3DStaticBuffers; + DWORD dwMaxHw3DStreamingBuffers; + DWORD dwFreeHw3DAllBuffers; + DWORD dwFreeHw3DStaticBuffers; + DWORD dwFreeHw3DStreamingBuffers; + DWORD dwTotalHwMemBytes; + DWORD dwFreeHwMemBytes; + DWORD dwMaxContigFreeHwMemBytes; + DWORD dwUnlockTransferRateHwBuffers; + DWORD dwPlayCpuOverheadSwBuffers; + DWORD dwReserved1; + DWORD dwReserved2; +} DSCAPS, *LPDSCAPS; + +typedef const DSCAPS *LPCDSCAPS; + +typedef struct _DSBCAPS +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwUnlockTransferRate; + DWORD dwPlayCpuOverhead; +} DSBCAPS, *LPDSBCAPS; + +typedef const DSBCAPS *LPCDSBCAPS; + +#if DIRECTSOUND_VERSION >= 0x0800 + + typedef struct _DSEFFECTDESC + { + DWORD dwSize; + DWORD dwFlags; + GUID guidDSFXClass; + DWORD_PTR dwReserved1; + DWORD_PTR dwReserved2; + } DSEFFECTDESC, *LPDSEFFECTDESC; + typedef const DSEFFECTDESC *LPCDSEFFECTDESC; + + #define DSFX_LOCHARDWARE 0x00000001 + #define DSFX_LOCSOFTWARE 0x00000002 + + enum + { + DSFXR_PRESENT, // 0 + DSFXR_LOCHARDWARE, // 1 + DSFXR_LOCSOFTWARE, // 2 + DSFXR_UNALLOCATED, // 3 + DSFXR_FAILED, // 4 + DSFXR_UNKNOWN, // 5 + DSFXR_SENDLOOP // 6 + }; + + typedef struct _DSCEFFECTDESC + { + DWORD dwSize; + DWORD dwFlags; + GUID guidDSCFXClass; + GUID guidDSCFXInstance; + DWORD dwReserved1; + DWORD dwReserved2; + } DSCEFFECTDESC, *LPDSCEFFECTDESC; + typedef const DSCEFFECTDESC *LPCDSCEFFECTDESC; + + #define DSCFX_LOCHARDWARE 0x00000001 + #define DSCFX_LOCSOFTWARE 0x00000002 + + #define DSCFXR_LOCHARDWARE 0x00000010 + #define DSCFXR_LOCSOFTWARE 0x00000020 + +#endif // DIRECTSOUND_VERSION >= 0x0800 + +typedef struct _DSBUFFERDESC +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwReserved; + LPWAVEFORMATEX lpwfxFormat; +#if DIRECTSOUND_VERSION >= 0x0700 + GUID guid3DAlgorithm; +#endif +} DSBUFFERDESC, *LPDSBUFFERDESC; + +typedef const DSBUFFERDESC *LPCDSBUFFERDESC; + +// Older version of this structure: + +typedef struct _DSBUFFERDESC1 +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwReserved; + LPWAVEFORMATEX lpwfxFormat; +} DSBUFFERDESC1, *LPDSBUFFERDESC1; + +typedef const DSBUFFERDESC1 *LPCDSBUFFERDESC1; + +typedef struct _DS3DBUFFER +{ + DWORD dwSize; + D3DVECTOR vPosition; + D3DVECTOR vVelocity; + DWORD dwInsideConeAngle; + DWORD dwOutsideConeAngle; + D3DVECTOR vConeOrientation; + LONG lConeOutsideVolume; + D3DVALUE flMinDistance; + D3DVALUE flMaxDistance; + DWORD dwMode; +} DS3DBUFFER, *LPDS3DBUFFER; + +typedef const DS3DBUFFER *LPCDS3DBUFFER; + +typedef struct _DS3DLISTENER +{ + DWORD dwSize; + D3DVECTOR vPosition; + D3DVECTOR vVelocity; + D3DVECTOR vOrientFront; + D3DVECTOR vOrientTop; + D3DVALUE flDistanceFactor; + D3DVALUE flRolloffFactor; + D3DVALUE flDopplerFactor; +} DS3DLISTENER, *LPDS3DLISTENER; + +typedef const DS3DLISTENER *LPCDS3DLISTENER; + +typedef struct _DSCCAPS +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwFormats; + DWORD dwChannels; +} DSCCAPS, *LPDSCCAPS; + +typedef const DSCCAPS *LPCDSCCAPS; + +typedef struct _DSCBUFFERDESC1 +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwReserved; + LPWAVEFORMATEX lpwfxFormat; +} DSCBUFFERDESC1, *LPDSCBUFFERDESC1; + +typedef struct _DSCBUFFERDESC +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwReserved; + LPWAVEFORMATEX lpwfxFormat; +#if DIRECTSOUND_VERSION >= 0x0800 + DWORD dwFXCount; + LPDSCEFFECTDESC lpDSCFXDesc; +#endif +} DSCBUFFERDESC, *LPDSCBUFFERDESC; + +typedef const DSCBUFFERDESC *LPCDSCBUFFERDESC; + +typedef struct _DSCBCAPS +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwReserved; +} DSCBCAPS, *LPDSCBCAPS; + +typedef const DSCBCAPS *LPCDSCBCAPS; + +typedef struct _DSBPOSITIONNOTIFY +{ + DWORD dwOffset; + HANDLE hEventNotify; +} DSBPOSITIONNOTIFY, *LPDSBPOSITIONNOTIFY; + +typedef const DSBPOSITIONNOTIFY *LPCDSBPOSITIONNOTIFY; + +// +// DirectSound API +// + +typedef BOOL (CALLBACK *LPDSENUMCALLBACKA)(LPGUID, LPCSTR, LPCSTR, LPVOID); +typedef BOOL (CALLBACK *LPDSENUMCALLBACKW)(LPGUID, LPCWSTR, LPCWSTR, LPVOID); + +extern HRESULT WINAPI DirectSoundCreate(LPCGUID pcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter); +extern HRESULT WINAPI DirectSoundEnumerateA(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext); +extern HRESULT WINAPI DirectSoundEnumerateW(LPDSENUMCALLBACKW pDSEnumCallback, LPVOID pContext); + +extern HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID pcGuidDevice, LPDIRECTSOUNDCAPTURE *ppDSC, LPUNKNOWN pUnkOuter); +extern HRESULT WINAPI DirectSoundCaptureEnumerateA(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext); +extern HRESULT WINAPI DirectSoundCaptureEnumerateW(LPDSENUMCALLBACKW pDSEnumCallback, LPVOID pContext); + +#if DIRECTSOUND_VERSION >= 0x0800 +extern HRESULT WINAPI DirectSoundCreate8(LPCGUID pcGuidDevice, LPDIRECTSOUND8 *ppDS8, LPUNKNOWN pUnkOuter); +extern HRESULT WINAPI DirectSoundCaptureCreate8(LPCGUID pcGuidDevice, LPDIRECTSOUNDCAPTURE8 *ppDSC8, LPUNKNOWN pUnkOuter); +extern HRESULT WINAPI DirectSoundFullDuplexCreate(LPCGUID pcGuidCaptureDevice, LPCGUID pcGuidRenderDevice, + LPCDSCBUFFERDESC pcDSCBufferDesc, LPCDSBUFFERDESC pcDSBufferDesc, HWND hWnd, + DWORD dwLevel, LPDIRECTSOUNDFULLDUPLEX* ppDSFD, LPDIRECTSOUNDCAPTUREBUFFER8 *ppDSCBuffer8, + LPDIRECTSOUNDBUFFER8 *ppDSBuffer8, LPUNKNOWN pUnkOuter); +#define DirectSoundFullDuplexCreate8 DirectSoundFullDuplexCreate + +extern HRESULT WINAPI GetDeviceID(LPCGUID pGuidSrc, LPGUID pGuidDest); +#endif // DIRECTSOUND_VERSION >= 0x0800 + +#ifdef UNICODE +#define LPDSENUMCALLBACK LPDSENUMCALLBACKW +#define DirectSoundEnumerate DirectSoundEnumerateW +#define DirectSoundCaptureEnumerate DirectSoundCaptureEnumerateW +#else // UNICODE +#define LPDSENUMCALLBACK LPDSENUMCALLBACKA +#define DirectSoundEnumerate DirectSoundEnumerateA +#define DirectSoundCaptureEnumerate DirectSoundCaptureEnumerateA +#endif // UNICODE + +// +// IUnknown +// + +#if !defined(__cplusplus) || defined(CINTERFACE) +#ifndef IUnknown_QueryInterface +#define IUnknown_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#endif // IUnknown_QueryInterface +#ifndef IUnknown_AddRef +#define IUnknown_AddRef(p) (p)->lpVtbl->AddRef(p) +#endif // IUnknown_AddRef +#ifndef IUnknown_Release +#define IUnknown_Release(p) (p)->lpVtbl->Release(p) +#endif // IUnknown_Release +#else // !defined(__cplusplus) || defined(CINTERFACE) +#ifndef IUnknown_QueryInterface +#define IUnknown_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#endif // IUnknown_QueryInterface +#ifndef IUnknown_AddRef +#define IUnknown_AddRef(p) (p)->AddRef() +#endif // IUnknown_AddRef +#ifndef IUnknown_Release +#define IUnknown_Release(p) (p)->Release() +#endif // IUnknown_Release +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +#ifndef __IReferenceClock_INTERFACE_DEFINED__ +#define __IReferenceClock_INTERFACE_DEFINED__ + +typedef LONGLONG REFERENCE_TIME; +typedef REFERENCE_TIME *LPREFERENCE_TIME; + +DEFINE_GUID(IID_IReferenceClock, 0x56a86897, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); + +#undef INTERFACE +#define INTERFACE IReferenceClock + +DECLARE_INTERFACE_(IReferenceClock, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IReferenceClock methods + STDMETHOD(GetTime) (THIS_ REFERENCE_TIME *pTime) PURE; + STDMETHOD(AdviseTime) (THIS_ REFERENCE_TIME rtBaseTime, REFERENCE_TIME rtStreamTime, + HANDLE hEvent, LPDWORD pdwAdviseCookie) PURE; + STDMETHOD(AdvisePeriodic) (THIS_ REFERENCE_TIME rtStartTime, REFERENCE_TIME rtPeriodTime, + HANDLE hSemaphore, LPDWORD pdwAdviseCookie) PURE; + STDMETHOD(Unadvise) (THIS_ DWORD dwAdviseCookie) PURE; +}; + +#endif // __IReferenceClock_INTERFACE_DEFINED__ + +#ifndef IReferenceClock_QueryInterface + +#define IReferenceClock_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IReferenceClock_AddRef(p) IUnknown_AddRef(p) +#define IReferenceClock_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IReferenceClock_GetTime(p,a) (p)->lpVtbl->GetTime(p,a) +#define IReferenceClock_AdviseTime(p,a,b,c,d) (p)->lpVtbl->AdviseTime(p,a,b,c,d) +#define IReferenceClock_AdvisePeriodic(p,a,b,c,d) (p)->lpVtbl->AdvisePeriodic(p,a,b,c,d) +#define IReferenceClock_Unadvise(p,a) (p)->lpVtbl->Unadvise(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IReferenceClock_GetTime(p,a) (p)->GetTime(a) +#define IReferenceClock_AdviseTime(p,a,b,c,d) (p)->AdviseTime(a,b,c,d) +#define IReferenceClock_AdvisePeriodic(p,a,b,c,d) (p)->AdvisePeriodic(a,b,c,d) +#define IReferenceClock_Unadvise(p,a) (p)->Unadvise(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +#endif // IReferenceClock_QueryInterface + +// +// IDirectSound +// + +DEFINE_GUID(IID_IDirectSound, 0x279AFA83, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); + +#undef INTERFACE +#define INTERFACE IDirectSound + +DECLARE_INTERFACE_(IDirectSound, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSound methods + STDMETHOD(CreateSoundBuffer) (THIS_ LPCDSBUFFERDESC pcDSBufferDesc, LPDIRECTSOUNDBUFFER *ppDSBuffer, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(GetCaps) (THIS_ LPDSCAPS pDSCaps) PURE; + STDMETHOD(DuplicateSoundBuffer) (THIS_ LPDIRECTSOUNDBUFFER pDSBufferOriginal, LPDIRECTSOUNDBUFFER *ppDSBufferDuplicate) PURE; + STDMETHOD(SetCooperativeLevel) (THIS_ HWND hwnd, DWORD dwLevel) PURE; + STDMETHOD(Compact) (THIS) PURE; + STDMETHOD(GetSpeakerConfig) (THIS_ LPDWORD pdwSpeakerConfig) PURE; + STDMETHOD(SetSpeakerConfig) (THIS_ DWORD dwSpeakerConfig) PURE; + STDMETHOD(Initialize) (THIS_ LPCGUID pcGuidDevice) PURE; +}; + +#define IDirectSound_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSound_AddRef(p) IUnknown_AddRef(p) +#define IDirectSound_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound_CreateSoundBuffer(p,a,b,c) (p)->lpVtbl->CreateSoundBuffer(p,a,b,c) +#define IDirectSound_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) +#define IDirectSound_DuplicateSoundBuffer(p,a,b) (p)->lpVtbl->DuplicateSoundBuffer(p,a,b) +#define IDirectSound_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) +#define IDirectSound_Compact(p) (p)->lpVtbl->Compact(p) +#define IDirectSound_GetSpeakerConfig(p,a) (p)->lpVtbl->GetSpeakerConfig(p,a) +#define IDirectSound_SetSpeakerConfig(p,b) (p)->lpVtbl->SetSpeakerConfig(p,b) +#define IDirectSound_Initialize(p,a) (p)->lpVtbl->Initialize(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound_CreateSoundBuffer(p,a,b,c) (p)->CreateSoundBuffer(a,b,c) +#define IDirectSound_GetCaps(p,a) (p)->GetCaps(a) +#define IDirectSound_DuplicateSoundBuffer(p,a,b) (p)->DuplicateSoundBuffer(a,b) +#define IDirectSound_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) +#define IDirectSound_Compact(p) (p)->Compact() +#define IDirectSound_GetSpeakerConfig(p,a) (p)->GetSpeakerConfig(a) +#define IDirectSound_SetSpeakerConfig(p,b) (p)->SetSpeakerConfig(b) +#define IDirectSound_Initialize(p,a) (p)->Initialize(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +#if DIRECTSOUND_VERSION >= 0x0800 + +// +// IDirectSound8 +// + +DEFINE_GUID(IID_IDirectSound8, 0xC50A7E93, 0xF395, 0x4834, 0x9E, 0xF6, 0x7F, 0xA9, 0x9D, 0xE5, 0x09, 0x66); + +#undef INTERFACE +#define INTERFACE IDirectSound8 + +DECLARE_INTERFACE_(IDirectSound8, IDirectSound) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSound methods + STDMETHOD(CreateSoundBuffer) (THIS_ LPCDSBUFFERDESC pcDSBufferDesc, LPDIRECTSOUNDBUFFER *ppDSBuffer, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(GetCaps) (THIS_ LPDSCAPS pDSCaps) PURE; + STDMETHOD(DuplicateSoundBuffer) (THIS_ LPDIRECTSOUNDBUFFER pDSBufferOriginal, LPDIRECTSOUNDBUFFER *ppDSBufferDuplicate) PURE; + STDMETHOD(SetCooperativeLevel) (THIS_ HWND hwnd, DWORD dwLevel) PURE; + STDMETHOD(Compact) (THIS) PURE; + STDMETHOD(GetSpeakerConfig) (THIS_ LPDWORD pdwSpeakerConfig) PURE; + STDMETHOD(SetSpeakerConfig) (THIS_ DWORD dwSpeakerConfig) PURE; + STDMETHOD(Initialize) (THIS_ LPCGUID pcGuidDevice) PURE; + + // IDirectSound8 methods + STDMETHOD(VerifyCertification) (THIS_ LPDWORD pdwCertified) PURE; +}; + +#define IDirectSound8_QueryInterface(p,a,b) IDirectSound_QueryInterface(p,a,b) +#define IDirectSound8_AddRef(p) IDirectSound_AddRef(p) +#define IDirectSound8_Release(p) IDirectSound_Release(p) +#define IDirectSound8_CreateSoundBuffer(p,a,b,c) IDirectSound_CreateSoundBuffer(p,a,b,c) +#define IDirectSound8_GetCaps(p,a) IDirectSound_GetCaps(p,a) +#define IDirectSound8_DuplicateSoundBuffer(p,a,b) IDirectSound_DuplicateSoundBuffer(p,a,b) +#define IDirectSound8_SetCooperativeLevel(p,a,b) IDirectSound_SetCooperativeLevel(p,a,b) +#define IDirectSound8_Compact(p) IDirectSound_Compact(p) +#define IDirectSound8_GetSpeakerConfig(p,a) IDirectSound_GetSpeakerConfig(p,a) +#define IDirectSound8_SetSpeakerConfig(p,a) IDirectSound_SetSpeakerConfig(p,a) +#define IDirectSound8_Initialize(p,a) IDirectSound_Initialize(p,a) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound8_VerifyCertification(p,a) (p)->lpVtbl->VerifyCertification(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound8_VerifyCertification(p,a) (p)->VerifyCertification(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +#endif // DIRECTSOUND_VERSION >= 0x0800 + +// +// IDirectSoundBuffer +// + +DEFINE_GUID(IID_IDirectSoundBuffer, 0x279AFA85, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); + +#undef INTERFACE +#define INTERFACE IDirectSoundBuffer + +DECLARE_INTERFACE_(IDirectSoundBuffer, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundBuffer methods + STDMETHOD(GetCaps) (THIS_ LPDSBCAPS pDSBufferCaps) PURE; + STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD pdwCurrentPlayCursor, LPDWORD pdwCurrentWriteCursor) PURE; + STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE; + STDMETHOD(GetVolume) (THIS_ LPLONG plVolume) PURE; + STDMETHOD(GetPan) (THIS_ LPLONG plPan) PURE; + STDMETHOD(GetFrequency) (THIS_ LPDWORD pdwFrequency) PURE; + STDMETHOD(GetStatus) (THIS_ LPDWORD pdwStatus) PURE; + STDMETHOD(Initialize) (THIS_ LPDIRECTSOUND pDirectSound, LPCDSBUFFERDESC pcDSBufferDesc) PURE; + STDMETHOD(Lock) (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1, + LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE; + STDMETHOD(Play) (THIS_ DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags) PURE; + STDMETHOD(SetCurrentPosition) (THIS_ DWORD dwNewPosition) PURE; + STDMETHOD(SetFormat) (THIS_ LPCWAVEFORMATEX pcfxFormat) PURE; + STDMETHOD(SetVolume) (THIS_ LONG lVolume) PURE; + STDMETHOD(SetPan) (THIS_ LONG lPan) PURE; + STDMETHOD(SetFrequency) (THIS_ DWORD dwFrequency) PURE; + STDMETHOD(Stop) (THIS) PURE; + STDMETHOD(Unlock) (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE; + STDMETHOD(Restore) (THIS) PURE; +}; + +#define IDirectSoundBuffer_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundBuffer_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundBuffer_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundBuffer_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) +#define IDirectSoundBuffer_GetCurrentPosition(p,a,b) (p)->lpVtbl->GetCurrentPosition(p,a,b) +#define IDirectSoundBuffer_GetFormat(p,a,b,c) (p)->lpVtbl->GetFormat(p,a,b,c) +#define IDirectSoundBuffer_GetVolume(p,a) (p)->lpVtbl->GetVolume(p,a) +#define IDirectSoundBuffer_GetPan(p,a) (p)->lpVtbl->GetPan(p,a) +#define IDirectSoundBuffer_GetFrequency(p,a) (p)->lpVtbl->GetFrequency(p,a) +#define IDirectSoundBuffer_GetStatus(p,a) (p)->lpVtbl->GetStatus(p,a) +#define IDirectSoundBuffer_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +#define IDirectSoundBuffer_Lock(p,a,b,c,d,e,f,g) (p)->lpVtbl->Lock(p,a,b,c,d,e,f,g) +#define IDirectSoundBuffer_Play(p,a,b,c) (p)->lpVtbl->Play(p,a,b,c) +#define IDirectSoundBuffer_SetCurrentPosition(p,a) (p)->lpVtbl->SetCurrentPosition(p,a) +#define IDirectSoundBuffer_SetFormat(p,a) (p)->lpVtbl->SetFormat(p,a) +#define IDirectSoundBuffer_SetVolume(p,a) (p)->lpVtbl->SetVolume(p,a) +#define IDirectSoundBuffer_SetPan(p,a) (p)->lpVtbl->SetPan(p,a) +#define IDirectSoundBuffer_SetFrequency(p,a) (p)->lpVtbl->SetFrequency(p,a) +#define IDirectSoundBuffer_Stop(p) (p)->lpVtbl->Stop(p) +#define IDirectSoundBuffer_Unlock(p,a,b,c,d) (p)->lpVtbl->Unlock(p,a,b,c,d) +#define IDirectSoundBuffer_Restore(p) (p)->lpVtbl->Restore(p) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundBuffer_GetCaps(p,a) (p)->GetCaps(a) +#define IDirectSoundBuffer_GetCurrentPosition(p,a,b) (p)->GetCurrentPosition(a,b) +#define IDirectSoundBuffer_GetFormat(p,a,b,c) (p)->GetFormat(a,b,c) +#define IDirectSoundBuffer_GetVolume(p,a) (p)->GetVolume(a) +#define IDirectSoundBuffer_GetPan(p,a) (p)->GetPan(a) +#define IDirectSoundBuffer_GetFrequency(p,a) (p)->GetFrequency(a) +#define IDirectSoundBuffer_GetStatus(p,a) (p)->GetStatus(a) +#define IDirectSoundBuffer_Initialize(p,a,b) (p)->Initialize(a,b) +#define IDirectSoundBuffer_Lock(p,a,b,c,d,e,f,g) (p)->Lock(a,b,c,d,e,f,g) +#define IDirectSoundBuffer_Play(p,a,b,c) (p)->Play(a,b,c) +#define IDirectSoundBuffer_SetCurrentPosition(p,a) (p)->SetCurrentPosition(a) +#define IDirectSoundBuffer_SetFormat(p,a) (p)->SetFormat(a) +#define IDirectSoundBuffer_SetVolume(p,a) (p)->SetVolume(a) +#define IDirectSoundBuffer_SetPan(p,a) (p)->SetPan(a) +#define IDirectSoundBuffer_SetFrequency(p,a) (p)->SetFrequency(a) +#define IDirectSoundBuffer_Stop(p) (p)->Stop() +#define IDirectSoundBuffer_Unlock(p,a,b,c,d) (p)->Unlock(a,b,c,d) +#define IDirectSoundBuffer_Restore(p) (p)->Restore() +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +#if DIRECTSOUND_VERSION >= 0x0800 + +// +// IDirectSoundBuffer8 +// + +DEFINE_GUID(IID_IDirectSoundBuffer8, 0x6825a449, 0x7524, 0x4d82, 0x92, 0x0f, 0x50, 0xe3, 0x6a, 0xb3, 0xab, 0x1e); + +#undef INTERFACE +#define INTERFACE IDirectSoundBuffer8 + +DECLARE_INTERFACE_(IDirectSoundBuffer8, IDirectSoundBuffer) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundBuffer methods + STDMETHOD(GetCaps) (THIS_ LPDSBCAPS pDSBufferCaps) PURE; + STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD pdwCurrentPlayCursor, LPDWORD pdwCurrentWriteCursor) PURE; + STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE; + STDMETHOD(GetVolume) (THIS_ LPLONG plVolume) PURE; + STDMETHOD(GetPan) (THIS_ LPLONG plPan) PURE; + STDMETHOD(GetFrequency) (THIS_ LPDWORD pdwFrequency) PURE; + STDMETHOD(GetStatus) (THIS_ LPDWORD pdwStatus) PURE; + STDMETHOD(Initialize) (THIS_ LPDIRECTSOUND pDirectSound, LPCDSBUFFERDESC pcDSBufferDesc) PURE; + STDMETHOD(Lock) (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1, + LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE; + STDMETHOD(Play) (THIS_ DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags) PURE; + STDMETHOD(SetCurrentPosition) (THIS_ DWORD dwNewPosition) PURE; + STDMETHOD(SetFormat) (THIS_ LPCWAVEFORMATEX pcfxFormat) PURE; + STDMETHOD(SetVolume) (THIS_ LONG lVolume) PURE; + STDMETHOD(SetPan) (THIS_ LONG lPan) PURE; + STDMETHOD(SetFrequency) (THIS_ DWORD dwFrequency) PURE; + STDMETHOD(Stop) (THIS) PURE; + STDMETHOD(Unlock) (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE; + STDMETHOD(Restore) (THIS) PURE; + + // IDirectSoundBuffer8 methods + STDMETHOD(SetFX) (THIS_ DWORD dwEffectsCount, LPDSEFFECTDESC pDSFXDesc, LPDWORD pdwResultCodes) PURE; + STDMETHOD(AcquireResources) (THIS_ DWORD dwFlags, DWORD dwEffectsCount, LPDWORD pdwResultCodes) PURE; + STDMETHOD(GetObjectInPath) (THIS_ REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, LPVOID *ppObject) PURE; +}; + +// Special GUID meaning "select all objects" for use in GetObjectInPath() +DEFINE_GUID(GUID_All_Objects, 0xaa114de5, 0xc262, 0x4169, 0xa1, 0xc8, 0x23, 0xd6, 0x98, 0xcc, 0x73, 0xb5); + +#define IDirectSoundBuffer8_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundBuffer8_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundBuffer8_Release(p) IUnknown_Release(p) + +#define IDirectSoundBuffer8_GetCaps(p,a) IDirectSoundBuffer_GetCaps(p,a) +#define IDirectSoundBuffer8_GetCurrentPosition(p,a,b) IDirectSoundBuffer_GetCurrentPosition(p,a,b) +#define IDirectSoundBuffer8_GetFormat(p,a,b,c) IDirectSoundBuffer_GetFormat(p,a,b,c) +#define IDirectSoundBuffer8_GetVolume(p,a) IDirectSoundBuffer_GetVolume(p,a) +#define IDirectSoundBuffer8_GetPan(p,a) IDirectSoundBuffer_GetPan(p,a) +#define IDirectSoundBuffer8_GetFrequency(p,a) IDirectSoundBuffer_GetFrequency(p,a) +#define IDirectSoundBuffer8_GetStatus(p,a) IDirectSoundBuffer_GetStatus(p,a) +#define IDirectSoundBuffer8_Initialize(p,a,b) IDirectSoundBuffer_Initialize(p,a,b) +#define IDirectSoundBuffer8_Lock(p,a,b,c,d,e,f,g) IDirectSoundBuffer_Lock(p,a,b,c,d,e,f,g) +#define IDirectSoundBuffer8_Play(p,a,b,c) IDirectSoundBuffer_Play(p,a,b,c) +#define IDirectSoundBuffer8_SetCurrentPosition(p,a) IDirectSoundBuffer_SetCurrentPosition(p,a) +#define IDirectSoundBuffer8_SetFormat(p,a) IDirectSoundBuffer_SetFormat(p,a) +#define IDirectSoundBuffer8_SetVolume(p,a) IDirectSoundBuffer_SetVolume(p,a) +#define IDirectSoundBuffer8_SetPan(p,a) IDirectSoundBuffer_SetPan(p,a) +#define IDirectSoundBuffer8_SetFrequency(p,a) IDirectSoundBuffer_SetFrequency(p,a) +#define IDirectSoundBuffer8_Stop(p) IDirectSoundBuffer_Stop(p) +#define IDirectSoundBuffer8_Unlock(p,a,b,c,d) IDirectSoundBuffer_Unlock(p,a,b,c,d) +#define IDirectSoundBuffer8_Restore(p) IDirectSoundBuffer_Restore(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundBuffer8_SetFX(p,a,b,c) (p)->lpVtbl->SetFX(p,a,b,c) +#define IDirectSoundBuffer8_AcquireResources(p,a,b,c) (p)->lpVtbl->AcquireResources(p,a,b,c) +#define IDirectSoundBuffer8_GetObjectInPath(p,a,b,c,d) (p)->lpVtbl->GetObjectInPath(p,a,b,c,d) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundBuffer8_SetFX(p,a,b,c) (p)->SetFX(a,b,c) +#define IDirectSoundBuffer8_AcquireResources(p,a,b,c) (p)->AcquireResources(a,b,c) +#define IDirectSoundBuffer8_GetObjectInPath(p,a,b,c,d) (p)->GetObjectInPath(a,b,c,d) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +#endif // DIRECTSOUND_VERSION >= 0x0800 + +// +// IDirectSound3DListener +// + +DEFINE_GUID(IID_IDirectSound3DListener, 0x279AFA84, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); + +#undef INTERFACE +#define INTERFACE IDirectSound3DListener + +DECLARE_INTERFACE_(IDirectSound3DListener, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSound3DListener methods + STDMETHOD(GetAllParameters) (THIS_ LPDS3DLISTENER pListener) PURE; + STDMETHOD(GetDistanceFactor) (THIS_ D3DVALUE* pflDistanceFactor) PURE; + STDMETHOD(GetDopplerFactor) (THIS_ D3DVALUE* pflDopplerFactor) PURE; + STDMETHOD(GetOrientation) (THIS_ D3DVECTOR* pvOrientFront, D3DVECTOR* pvOrientTop) PURE; + STDMETHOD(GetPosition) (THIS_ D3DVECTOR* pvPosition) PURE; + STDMETHOD(GetRolloffFactor) (THIS_ D3DVALUE* pflRolloffFactor) PURE; + STDMETHOD(GetVelocity) (THIS_ D3DVECTOR* pvVelocity) PURE; + STDMETHOD(SetAllParameters) (THIS_ LPCDS3DLISTENER pcListener, DWORD dwApply) PURE; + STDMETHOD(SetDistanceFactor) (THIS_ D3DVALUE flDistanceFactor, DWORD dwApply) PURE; + STDMETHOD(SetDopplerFactor) (THIS_ D3DVALUE flDopplerFactor, DWORD dwApply) PURE; + STDMETHOD(SetOrientation) (THIS_ D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, + D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD dwApply) PURE; + STDMETHOD(SetPosition) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; + STDMETHOD(SetRolloffFactor) (THIS_ D3DVALUE flRolloffFactor, DWORD dwApply) PURE; + STDMETHOD(SetVelocity) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; + STDMETHOD(CommitDeferredSettings) (THIS) PURE; +}; + +#define IDirectSound3DListener_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSound3DListener_AddRef(p) IUnknown_AddRef(p) +#define IDirectSound3DListener_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound3DListener_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#define IDirectSound3DListener_GetDistanceFactor(p,a) (p)->lpVtbl->GetDistanceFactor(p,a) +#define IDirectSound3DListener_GetDopplerFactor(p,a) (p)->lpVtbl->GetDopplerFactor(p,a) +#define IDirectSound3DListener_GetOrientation(p,a,b) (p)->lpVtbl->GetOrientation(p,a,b) +#define IDirectSound3DListener_GetPosition(p,a) (p)->lpVtbl->GetPosition(p,a) +#define IDirectSound3DListener_GetRolloffFactor(p,a) (p)->lpVtbl->GetRolloffFactor(p,a) +#define IDirectSound3DListener_GetVelocity(p,a) (p)->lpVtbl->GetVelocity(p,a) +#define IDirectSound3DListener_SetAllParameters(p,a,b) (p)->lpVtbl->SetAllParameters(p,a,b) +#define IDirectSound3DListener_SetDistanceFactor(p,a,b) (p)->lpVtbl->SetDistanceFactor(p,a,b) +#define IDirectSound3DListener_SetDopplerFactor(p,a,b) (p)->lpVtbl->SetDopplerFactor(p,a,b) +#define IDirectSound3DListener_SetOrientation(p,a,b,c,d,e,f,g) (p)->lpVtbl->SetOrientation(p,a,b,c,d,e,f,g) +#define IDirectSound3DListener_SetPosition(p,a,b,c,d) (p)->lpVtbl->SetPosition(p,a,b,c,d) +#define IDirectSound3DListener_SetRolloffFactor(p,a,b) (p)->lpVtbl->SetRolloffFactor(p,a,b) +#define IDirectSound3DListener_SetVelocity(p,a,b,c,d) (p)->lpVtbl->SetVelocity(p,a,b,c,d) +#define IDirectSound3DListener_CommitDeferredSettings(p) (p)->lpVtbl->CommitDeferredSettings(p) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound3DListener_GetAllParameters(p,a) (p)->GetAllParameters(a) +#define IDirectSound3DListener_GetDistanceFactor(p,a) (p)->GetDistanceFactor(a) +#define IDirectSound3DListener_GetDopplerFactor(p,a) (p)->GetDopplerFactor(a) +#define IDirectSound3DListener_GetOrientation(p,a,b) (p)->GetOrientation(a,b) +#define IDirectSound3DListener_GetPosition(p,a) (p)->GetPosition(a) +#define IDirectSound3DListener_GetRolloffFactor(p,a) (p)->GetRolloffFactor(a) +#define IDirectSound3DListener_GetVelocity(p,a) (p)->GetVelocity(a) +#define IDirectSound3DListener_SetAllParameters(p,a,b) (p)->SetAllParameters(a,b) +#define IDirectSound3DListener_SetDistanceFactor(p,a,b) (p)->SetDistanceFactor(a,b) +#define IDirectSound3DListener_SetDopplerFactor(p,a,b) (p)->SetDopplerFactor(a,b) +#define IDirectSound3DListener_SetOrientation(p,a,b,c,d,e,f,g) (p)->SetOrientation(a,b,c,d,e,f,g) +#define IDirectSound3DListener_SetPosition(p,a,b,c,d) (p)->SetPosition(a,b,c,d) +#define IDirectSound3DListener_SetRolloffFactor(p,a,b) (p)->SetRolloffFactor(a,b) +#define IDirectSound3DListener_SetVelocity(p,a,b,c,d) (p)->SetVelocity(a,b,c,d) +#define IDirectSound3DListener_CommitDeferredSettings(p) (p)->CommitDeferredSettings() +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSound3DBuffer +// + +DEFINE_GUID(IID_IDirectSound3DBuffer, 0x279AFA86, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); + +#undef INTERFACE +#define INTERFACE IDirectSound3DBuffer + +DECLARE_INTERFACE_(IDirectSound3DBuffer, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSound3DBuffer methods + STDMETHOD(GetAllParameters) (THIS_ LPDS3DBUFFER pDs3dBuffer) PURE; + STDMETHOD(GetConeAngles) (THIS_ LPDWORD pdwInsideConeAngle, LPDWORD pdwOutsideConeAngle) PURE; + STDMETHOD(GetConeOrientation) (THIS_ D3DVECTOR* pvOrientation) PURE; + STDMETHOD(GetConeOutsideVolume) (THIS_ LPLONG plConeOutsideVolume) PURE; + STDMETHOD(GetMaxDistance) (THIS_ D3DVALUE* pflMaxDistance) PURE; + STDMETHOD(GetMinDistance) (THIS_ D3DVALUE* pflMinDistance) PURE; + STDMETHOD(GetMode) (THIS_ LPDWORD pdwMode) PURE; + STDMETHOD(GetPosition) (THIS_ D3DVECTOR* pvPosition) PURE; + STDMETHOD(GetVelocity) (THIS_ D3DVECTOR* pvVelocity) PURE; + STDMETHOD(SetAllParameters) (THIS_ LPCDS3DBUFFER pcDs3dBuffer, DWORD dwApply) PURE; + STDMETHOD(SetConeAngles) (THIS_ DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD dwApply) PURE; + STDMETHOD(SetConeOrientation) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; + STDMETHOD(SetConeOutsideVolume) (THIS_ LONG lConeOutsideVolume, DWORD dwApply) PURE; + STDMETHOD(SetMaxDistance) (THIS_ D3DVALUE flMaxDistance, DWORD dwApply) PURE; + STDMETHOD(SetMinDistance) (THIS_ D3DVALUE flMinDistance, DWORD dwApply) PURE; + STDMETHOD(SetMode) (THIS_ DWORD dwMode, DWORD dwApply) PURE; + STDMETHOD(SetPosition) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; + STDMETHOD(SetVelocity) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; +}; + +#define IDirectSound3DBuffer_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSound3DBuffer_AddRef(p) IUnknown_AddRef(p) +#define IDirectSound3DBuffer_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound3DBuffer_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#define IDirectSound3DBuffer_GetConeAngles(p,a,b) (p)->lpVtbl->GetConeAngles(p,a,b) +#define IDirectSound3DBuffer_GetConeOrientation(p,a) (p)->lpVtbl->GetConeOrientation(p,a) +#define IDirectSound3DBuffer_GetConeOutsideVolume(p,a) (p)->lpVtbl->GetConeOutsideVolume(p,a) +#define IDirectSound3DBuffer_GetPosition(p,a) (p)->lpVtbl->GetPosition(p,a) +#define IDirectSound3DBuffer_GetMinDistance(p,a) (p)->lpVtbl->GetMinDistance(p,a) +#define IDirectSound3DBuffer_GetMaxDistance(p,a) (p)->lpVtbl->GetMaxDistance(p,a) +#define IDirectSound3DBuffer_GetMode(p,a) (p)->lpVtbl->GetMode(p,a) +#define IDirectSound3DBuffer_GetVelocity(p,a) (p)->lpVtbl->GetVelocity(p,a) +#define IDirectSound3DBuffer_SetAllParameters(p,a,b) (p)->lpVtbl->SetAllParameters(p,a,b) +#define IDirectSound3DBuffer_SetConeAngles(p,a,b,c) (p)->lpVtbl->SetConeAngles(p,a,b,c) +#define IDirectSound3DBuffer_SetConeOrientation(p,a,b,c,d) (p)->lpVtbl->SetConeOrientation(p,a,b,c,d) +#define IDirectSound3DBuffer_SetConeOutsideVolume(p,a,b) (p)->lpVtbl->SetConeOutsideVolume(p,a,b) +#define IDirectSound3DBuffer_SetPosition(p,a,b,c,d) (p)->lpVtbl->SetPosition(p,a,b,c,d) +#define IDirectSound3DBuffer_SetMinDistance(p,a,b) (p)->lpVtbl->SetMinDistance(p,a,b) +#define IDirectSound3DBuffer_SetMaxDistance(p,a,b) (p)->lpVtbl->SetMaxDistance(p,a,b) +#define IDirectSound3DBuffer_SetMode(p,a,b) (p)->lpVtbl->SetMode(p,a,b) +#define IDirectSound3DBuffer_SetVelocity(p,a,b,c,d) (p)->lpVtbl->SetVelocity(p,a,b,c,d) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound3DBuffer_GetAllParameters(p,a) (p)->GetAllParameters(a) +#define IDirectSound3DBuffer_GetConeAngles(p,a,b) (p)->GetConeAngles(a,b) +#define IDirectSound3DBuffer_GetConeOrientation(p,a) (p)->GetConeOrientation(a) +#define IDirectSound3DBuffer_GetConeOutsideVolume(p,a) (p)->GetConeOutsideVolume(a) +#define IDirectSound3DBuffer_GetPosition(p,a) (p)->GetPosition(a) +#define IDirectSound3DBuffer_GetMinDistance(p,a) (p)->GetMinDistance(a) +#define IDirectSound3DBuffer_GetMaxDistance(p,a) (p)->GetMaxDistance(a) +#define IDirectSound3DBuffer_GetMode(p,a) (p)->GetMode(a) +#define IDirectSound3DBuffer_GetVelocity(p,a) (p)->GetVelocity(a) +#define IDirectSound3DBuffer_SetAllParameters(p,a,b) (p)->SetAllParameters(a,b) +#define IDirectSound3DBuffer_SetConeAngles(p,a,b,c) (p)->SetConeAngles(a,b,c) +#define IDirectSound3DBuffer_SetConeOrientation(p,a,b,c,d) (p)->SetConeOrientation(a,b,c,d) +#define IDirectSound3DBuffer_SetConeOutsideVolume(p,a,b) (p)->SetConeOutsideVolume(a,b) +#define IDirectSound3DBuffer_SetPosition(p,a,b,c,d) (p)->SetPosition(a,b,c,d) +#define IDirectSound3DBuffer_SetMinDistance(p,a,b) (p)->SetMinDistance(a,b) +#define IDirectSound3DBuffer_SetMaxDistance(p,a,b) (p)->SetMaxDistance(a,b) +#define IDirectSound3DBuffer_SetMode(p,a,b) (p)->SetMode(a,b) +#define IDirectSound3DBuffer_SetVelocity(p,a,b,c,d) (p)->SetVelocity(a,b,c,d) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundCapture +// + +DEFINE_GUID(IID_IDirectSoundCapture, 0xb0210781, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); + +#undef INTERFACE +#define INTERFACE IDirectSoundCapture + +DECLARE_INTERFACE_(IDirectSoundCapture, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundCapture methods + STDMETHOD(CreateCaptureBuffer) (THIS_ LPCDSCBUFFERDESC pcDSCBufferDesc, LPDIRECTSOUNDCAPTUREBUFFER *ppDSCBuffer, LPUNKNOWN pUnkOuter) PURE; + STDMETHOD(GetCaps) (THIS_ LPDSCCAPS pDSCCaps) PURE; + STDMETHOD(Initialize) (THIS_ LPCGUID pcGuidDevice) PURE; +}; + +#define IDirectSoundCapture_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundCapture_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundCapture_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCapture_CreateCaptureBuffer(p,a,b,c) (p)->lpVtbl->CreateCaptureBuffer(p,a,b,c) +#define IDirectSoundCapture_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) +#define IDirectSoundCapture_Initialize(p,a) (p)->lpVtbl->Initialize(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCapture_CreateCaptureBuffer(p,a,b,c) (p)->CreateCaptureBuffer(a,b,c) +#define IDirectSoundCapture_GetCaps(p,a) (p)->GetCaps(a) +#define IDirectSoundCapture_Initialize(p,a) (p)->Initialize(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundCaptureBuffer +// + +DEFINE_GUID(IID_IDirectSoundCaptureBuffer, 0xb0210782, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); + +#undef INTERFACE +#define INTERFACE IDirectSoundCaptureBuffer + +DECLARE_INTERFACE_(IDirectSoundCaptureBuffer, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundCaptureBuffer methods + STDMETHOD(GetCaps) (THIS_ LPDSCBCAPS pDSCBCaps) PURE; + STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD pdwCapturePosition, LPDWORD pdwReadPosition) PURE; + STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE; + STDMETHOD(GetStatus) (THIS_ LPDWORD pdwStatus) PURE; + STDMETHOD(Initialize) (THIS_ LPDIRECTSOUNDCAPTURE pDirectSoundCapture, LPCDSCBUFFERDESC pcDSCBufferDesc) PURE; + STDMETHOD(Lock) (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1, + LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE; + STDMETHOD(Start) (THIS_ DWORD dwFlags) PURE; + STDMETHOD(Stop) (THIS) PURE; + STDMETHOD(Unlock) (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE; +}; + +#define IDirectSoundCaptureBuffer_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundCaptureBuffer_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundCaptureBuffer_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCaptureBuffer_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) +#define IDirectSoundCaptureBuffer_GetCurrentPosition(p,a,b) (p)->lpVtbl->GetCurrentPosition(p,a,b) +#define IDirectSoundCaptureBuffer_GetFormat(p,a,b,c) (p)->lpVtbl->GetFormat(p,a,b,c) +#define IDirectSoundCaptureBuffer_GetStatus(p,a) (p)->lpVtbl->GetStatus(p,a) +#define IDirectSoundCaptureBuffer_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +#define IDirectSoundCaptureBuffer_Lock(p,a,b,c,d,e,f,g) (p)->lpVtbl->Lock(p,a,b,c,d,e,f,g) +#define IDirectSoundCaptureBuffer_Start(p,a) (p)->lpVtbl->Start(p,a) +#define IDirectSoundCaptureBuffer_Stop(p) (p)->lpVtbl->Stop(p) +#define IDirectSoundCaptureBuffer_Unlock(p,a,b,c,d) (p)->lpVtbl->Unlock(p,a,b,c,d) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCaptureBuffer_GetCaps(p,a) (p)->GetCaps(a) +#define IDirectSoundCaptureBuffer_GetCurrentPosition(p,a,b) (p)->GetCurrentPosition(a,b) +#define IDirectSoundCaptureBuffer_GetFormat(p,a,b,c) (p)->GetFormat(a,b,c) +#define IDirectSoundCaptureBuffer_GetStatus(p,a) (p)->GetStatus(a) +#define IDirectSoundCaptureBuffer_Initialize(p,a,b) (p)->Initialize(a,b) +#define IDirectSoundCaptureBuffer_Lock(p,a,b,c,d,e,f,g) (p)->Lock(a,b,c,d,e,f,g) +#define IDirectSoundCaptureBuffer_Start(p,a) (p)->Start(a) +#define IDirectSoundCaptureBuffer_Stop(p) (p)->Stop() +#define IDirectSoundCaptureBuffer_Unlock(p,a,b,c,d) (p)->Unlock(a,b,c,d) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + + +#if DIRECTSOUND_VERSION >= 0x0800 + +// +// IDirectSoundCaptureBuffer8 +// + +DEFINE_GUID(IID_IDirectSoundCaptureBuffer8, 0x990df4, 0xdbb, 0x4872, 0x83, 0x3e, 0x6d, 0x30, 0x3e, 0x80, 0xae, 0xb6); + +#undef INTERFACE +#define INTERFACE IDirectSoundCaptureBuffer8 + +DECLARE_INTERFACE_(IDirectSoundCaptureBuffer8, IDirectSoundCaptureBuffer) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundCaptureBuffer methods + STDMETHOD(GetCaps) (THIS_ LPDSCBCAPS pDSCBCaps) PURE; + STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD pdwCapturePosition, LPDWORD pdwReadPosition) PURE; + STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE; + STDMETHOD(GetStatus) (THIS_ LPDWORD pdwStatus) PURE; + STDMETHOD(Initialize) (THIS_ LPDIRECTSOUNDCAPTURE pDirectSoundCapture, LPCDSCBUFFERDESC pcDSCBufferDesc) PURE; + STDMETHOD(Lock) (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1, + LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE; + STDMETHOD(Start) (THIS_ DWORD dwFlags) PURE; + STDMETHOD(Stop) (THIS) PURE; + STDMETHOD(Unlock) (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE; + + // IDirectSoundCaptureBuffer8 methods + STDMETHOD(GetObjectInPath) (THIS_ REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, LPVOID *ppObject) PURE; + STDMETHOD(GetFXStatus) (DWORD dwFXCount, LPDWORD pdwFXStatus) PURE; +}; + +#define IDirectSoundCaptureBuffer8_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundCaptureBuffer8_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundCaptureBuffer8_Release(p) IUnknown_Release(p) + +#define IDirectSoundCaptureBuffer8_GetCaps(p,a) IDirectSoundCaptureBuffer_GetCaps(p,a) +#define IDirectSoundCaptureBuffer8_GetCurrentPosition(p,a,b) IDirectSoundCaptureBuffer_GetCurrentPosition(p,a,b) +#define IDirectSoundCaptureBuffer8_GetFormat(p,a,b,c) IDirectSoundCaptureBuffer_GetFormat(p,a,b,c) +#define IDirectSoundCaptureBuffer8_GetStatus(p,a) IDirectSoundCaptureBuffer_GetStatus(p,a) +#define IDirectSoundCaptureBuffer8_Initialize(p,a,b) IDirectSoundCaptureBuffer_Initialize(p,a,b) +#define IDirectSoundCaptureBuffer8_Lock(p,a,b,c,d,e,f,g) IDirectSoundCaptureBuffer_Lock(p,a,b,c,d,e,f,g) +#define IDirectSoundCaptureBuffer8_Start(p,a) IDirectSoundCaptureBuffer_Start(p,a) +#define IDirectSoundCaptureBuffer8_Stop(p) IDirectSoundCaptureBuffer_Stop(p)) +#define IDirectSoundCaptureBuffer8_Unlock(p,a,b,c,d) IDirectSoundCaptureBuffer_Unlock(p,a,b,c,d) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCaptureBuffer8_GetObjectInPath(p,a,b,c,d) (p)->lpVtbl->GetObjectInPath(p,a,b,c,d) +#define IDirectSoundCaptureBuffer8_GetFXStatus(p,a,b) (p)->lpVtbl->GetFXStatus(p,a,b) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCaptureBuffer8_GetObjectInPath(p,a,b,c,d) (p)->GetObjectInPath(a,b,c,d) +#define IDirectSoundCaptureBuffer8_GetFXStatus(p,a,b) (p)->GetFXStatus(a,b) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +#endif // DIRECTSOUND_VERSION >= 0x0800 + +// +// IDirectSoundNotify +// + +DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); + +#undef INTERFACE +#define INTERFACE IDirectSoundNotify + +DECLARE_INTERFACE_(IDirectSoundNotify, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundNotify methods + STDMETHOD(SetNotificationPositions) (THIS_ DWORD dwPositionNotifies, LPCDSBPOSITIONNOTIFY pcPositionNotifies) PURE; +}; + +#define IDirectSoundNotify_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundNotify_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundNotify_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundNotify_SetNotificationPositions(p,a,b) (p)->lpVtbl->SetNotificationPositions(p,a,b) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundNotify_SetNotificationPositions(p,a,b) (p)->SetNotificationPositions(a,b) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IKsPropertySet +// + +#ifndef _IKsPropertySet_ +#define _IKsPropertySet_ + +#ifdef __cplusplus +// 'struct' not 'class' per the way DECLARE_INTERFACE_ is defined +struct IKsPropertySet; +#endif // __cplusplus + +typedef struct IKsPropertySet *LPKSPROPERTYSET; + +#define KSPROPERTY_SUPPORT_GET 0x00000001 +#define KSPROPERTY_SUPPORT_SET 0x00000002 + +DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa, 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93); + +#undef INTERFACE +#define INTERFACE IKsPropertySet + +DECLARE_INTERFACE_(IKsPropertySet, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IKsPropertySet methods + STDMETHOD(Get) (THIS_ REFGUID rguidPropSet, ULONG ulId, LPVOID pInstanceData, ULONG ulInstanceLength, + LPVOID pPropertyData, ULONG ulDataLength, PULONG pulBytesReturned) PURE; + STDMETHOD(Set) (THIS_ REFGUID rguidPropSet, ULONG ulId, LPVOID pInstanceData, ULONG ulInstanceLength, + LPVOID pPropertyData, ULONG ulDataLength) PURE; + STDMETHOD(QuerySupport) (THIS_ REFGUID rguidPropSet, ULONG ulId, PULONG pulTypeSupport) PURE; +}; + +#define IKsPropertySet_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IKsPropertySet_AddRef(p) IUnknown_AddRef(p) +#define IKsPropertySet_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IKsPropertySet_Get(p,a,b,c,d,e,f,g) (p)->lpVtbl->Get(p,a,b,c,d,e,f,g) +#define IKsPropertySet_Set(p,a,b,c,d,e,f) (p)->lpVtbl->Set(p,a,b,c,d,e,f) +#define IKsPropertySet_QuerySupport(p,a,b,c) (p)->lpVtbl->QuerySupport(p,a,b,c) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IKsPropertySet_Get(p,a,b,c,d,e,f,g) (p)->Get(a,b,c,d,e,f,g) +#define IKsPropertySet_Set(p,a,b,c,d,e,f) (p)->Set(a,b,c,d,e,f) +#define IKsPropertySet_QuerySupport(p,a,b,c) (p)->QuerySupport(a,b,c) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +#endif // _IKsPropertySet_ + +#if DIRECTSOUND_VERSION >= 0x0800 + +// +// IDirectSoundFXGargle +// + +DEFINE_GUID(IID_IDirectSoundFXGargle, 0xd616f352, 0xd622, 0x11ce, 0xaa, 0xc5, 0x00, 0x20, 0xaf, 0x0b, 0x99, 0xa3); + +typedef struct _DSFXGargle +{ + DWORD dwRateHz; // Rate of modulation in hz + DWORD dwWaveShape; // DSFXGARGLE_WAVE_xxx +} DSFXGargle, *LPDSFXGargle; + +#define DSFXGARGLE_WAVE_TRIANGLE 0 +#define DSFXGARGLE_WAVE_SQUARE 1 + +typedef const DSFXGargle *LPCDSFXGargle; + +#define DSFXGARGLE_RATEHZ_MIN 1 +#define DSFXGARGLE_RATEHZ_MAX 1000 + +#undef INTERFACE +#define INTERFACE IDirectSoundFXGargle + +DECLARE_INTERFACE_(IDirectSoundFXGargle, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFXGargle methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSFXGargle pcDsFxGargle) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSFXGargle pDsFxGargle) PURE; +}; + +#define IDirectSoundFXGargle_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFXGargle_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFXGargle_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXGargle_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundFXGargle_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXGargle_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundFXGargle_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundFXChorus +// + +DEFINE_GUID(IID_IDirectSoundFXChorus, 0x880842e3, 0x145f, 0x43e6, 0xa9, 0x34, 0xa7, 0x18, 0x06, 0xe5, 0x05, 0x47); + +typedef struct _DSFXChorus +{ + FLOAT fWetDryMix; + FLOAT fDepth; + FLOAT fFeedback; + FLOAT fFrequency; + LONG lWaveform; // LFO shape; DSFXCHORUS_WAVE_xxx + FLOAT fDelay; + LONG lPhase; +} DSFXChorus, *LPDSFXChorus; + +typedef const DSFXChorus *LPCDSFXChorus; + +#define DSFXCHORUS_WAVE_TRIANGLE 0 +#define DSFXCHORUS_WAVE_SIN 1 + +#define DSFXCHORUS_WETDRYMIX_MIN 0.0f +#define DSFXCHORUS_WETDRYMIX_MAX 100.0f +#define DSFXCHORUS_DEPTH_MIN 0.0f +#define DSFXCHORUS_DEPTH_MAX 100.0f +#define DSFXCHORUS_FEEDBACK_MIN -99.0f +#define DSFXCHORUS_FEEDBACK_MAX 99.0f +#define DSFXCHORUS_FREQUENCY_MIN 0.0f +#define DSFXCHORUS_FREQUENCY_MAX 10.0f +#define DSFXCHORUS_DELAY_MIN 0.0f +#define DSFXCHORUS_DELAY_MAX 20.0f +#define DSFXCHORUS_PHASE_MIN 0 +#define DSFXCHORUS_PHASE_MAX 4 + +#define DSFXCHORUS_PHASE_NEG_180 0 +#define DSFXCHORUS_PHASE_NEG_90 1 +#define DSFXCHORUS_PHASE_ZERO 2 +#define DSFXCHORUS_PHASE_90 3 +#define DSFXCHORUS_PHASE_180 4 + +#undef INTERFACE +#define INTERFACE IDirectSoundFXChorus + +DECLARE_INTERFACE_(IDirectSoundFXChorus, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFXChorus methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSFXChorus pcDsFxChorus) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSFXChorus pDsFxChorus) PURE; +}; + +#define IDirectSoundFXChorus_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFXChorus_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFXChorus_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXChorus_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundFXChorus_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXChorus_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundFXChorus_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundFXFlanger +// + +DEFINE_GUID(IID_IDirectSoundFXFlanger, 0x903e9878, 0x2c92, 0x4072, 0x9b, 0x2c, 0xea, 0x68, 0xf5, 0x39, 0x67, 0x83); + +typedef struct _DSFXFlanger +{ + FLOAT fWetDryMix; + FLOAT fDepth; + FLOAT fFeedback; + FLOAT fFrequency; + LONG lWaveform; + FLOAT fDelay; + LONG lPhase; +} DSFXFlanger, *LPDSFXFlanger; + +typedef const DSFXFlanger *LPCDSFXFlanger; + +#define DSFXFLANGER_WAVE_TRIANGLE 0 +#define DSFXFLANGER_WAVE_SIN 1 + +#define DSFXFLANGER_WETDRYMIX_MIN 0.0f +#define DSFXFLANGER_WETDRYMIX_MAX 100.0f +#define DSFXFLANGER_FREQUENCY_MIN 0.0f +#define DSFXFLANGER_FREQUENCY_MAX 10.0f +#define DSFXFLANGER_DEPTH_MIN 0.0f +#define DSFXFLANGER_DEPTH_MAX 100.0f +#define DSFXFLANGER_PHASE_MIN 0 +#define DSFXFLANGER_PHASE_MAX 4 +#define DSFXFLANGER_FEEDBACK_MIN -99.0f +#define DSFXFLANGER_FEEDBACK_MAX 99.0f +#define DSFXFLANGER_DELAY_MIN 0.0f +#define DSFXFLANGER_DELAY_MAX 4.0f + +#define DSFXFLANGER_PHASE_NEG_180 0 +#define DSFXFLANGER_PHASE_NEG_90 1 +#define DSFXFLANGER_PHASE_ZERO 2 +#define DSFXFLANGER_PHASE_90 3 +#define DSFXFLANGER_PHASE_180 4 + +#undef INTERFACE +#define INTERFACE IDirectSoundFXFlanger + +DECLARE_INTERFACE_(IDirectSoundFXFlanger, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFXFlanger methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSFXFlanger pcDsFxFlanger) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSFXFlanger pDsFxFlanger) PURE; +}; + +#define IDirectSoundFXFlanger_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFXFlanger_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFXFlanger_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXFlanger_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundFXFlanger_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXFlanger_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundFXFlanger_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundFXEcho +// + +DEFINE_GUID(IID_IDirectSoundFXEcho, 0x8bd28edf, 0x50db, 0x4e92, 0xa2, 0xbd, 0x44, 0x54, 0x88, 0xd1, 0xed, 0x42); + +typedef struct _DSFXEcho +{ + FLOAT fWetDryMix; + FLOAT fFeedback; + FLOAT fLeftDelay; + FLOAT fRightDelay; + LONG lPanDelay; +} DSFXEcho, *LPDSFXEcho; + +typedef const DSFXEcho *LPCDSFXEcho; + +#define DSFXECHO_WETDRYMIX_MIN 0.0f +#define DSFXECHO_WETDRYMIX_MAX 100.0f +#define DSFXECHO_FEEDBACK_MIN 0.0f +#define DSFXECHO_FEEDBACK_MAX 100.0f +#define DSFXECHO_LEFTDELAY_MIN 1.0f +#define DSFXECHO_LEFTDELAY_MAX 2000.0f +#define DSFXECHO_RIGHTDELAY_MIN 1.0f +#define DSFXECHO_RIGHTDELAY_MAX 2000.0f +#define DSFXECHO_PANDELAY_MIN 0 +#define DSFXECHO_PANDELAY_MAX 1 + +#undef INTERFACE +#define INTERFACE IDirectSoundFXEcho + +DECLARE_INTERFACE_(IDirectSoundFXEcho, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFXEcho methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSFXEcho pcDsFxEcho) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSFXEcho pDsFxEcho) PURE; +}; + +#define IDirectSoundFXEcho_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFXEcho_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFXEcho_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXEcho_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundFXEcho_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXEcho_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundFXEcho_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundFXDistortion +// + +DEFINE_GUID(IID_IDirectSoundFXDistortion, 0x8ecf4326, 0x455f, 0x4d8b, 0xbd, 0xa9, 0x8d, 0x5d, 0x3e, 0x9e, 0x3e, 0x0b); + +typedef struct _DSFXDistortion +{ + FLOAT fGain; + FLOAT fEdge; + FLOAT fPostEQCenterFrequency; + FLOAT fPostEQBandwidth; + FLOAT fPreLowpassCutoff; +} DSFXDistortion, *LPDSFXDistortion; + +typedef const DSFXDistortion *LPCDSFXDistortion; + +#define DSFXDISTORTION_GAIN_MIN -60.0f +#define DSFXDISTORTION_GAIN_MAX 0.0f +#define DSFXDISTORTION_EDGE_MIN 0.0f +#define DSFXDISTORTION_EDGE_MAX 100.0f +#define DSFXDISTORTION_POSTEQCENTERFREQUENCY_MIN 100.0f +#define DSFXDISTORTION_POSTEQCENTERFREQUENCY_MAX 8000.0f +#define DSFXDISTORTION_POSTEQBANDWIDTH_MIN 100.0f +#define DSFXDISTORTION_POSTEQBANDWIDTH_MAX 8000.0f +#define DSFXDISTORTION_PRELOWPASSCUTOFF_MIN 100.0f +#define DSFXDISTORTION_PRELOWPASSCUTOFF_MAX 8000.0f + +#undef INTERFACE +#define INTERFACE IDirectSoundFXDistortion + +DECLARE_INTERFACE_(IDirectSoundFXDistortion, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFXDistortion methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSFXDistortion pcDsFxDistortion) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSFXDistortion pDsFxDistortion) PURE; +}; + +#define IDirectSoundFXDistortion_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFXDistortion_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFXDistortion_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXDistortion_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundFXDistortion_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXDistortion_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundFXDistortion_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundFXCompressor +// + +DEFINE_GUID(IID_IDirectSoundFXCompressor, 0x4bbd1154, 0x62f6, 0x4e2c, 0xa1, 0x5c, 0xd3, 0xb6, 0xc4, 0x17, 0xf7, 0xa0); + +typedef struct _DSFXCompressor +{ + FLOAT fGain; + FLOAT fAttack; + FLOAT fRelease; + FLOAT fThreshold; + FLOAT fRatio; + FLOAT fPredelay; +} DSFXCompressor, *LPDSFXCompressor; + +typedef const DSFXCompressor *LPCDSFXCompressor; + +#define DSFXCOMPRESSOR_GAIN_MIN -60.0f +#define DSFXCOMPRESSOR_GAIN_MAX 60.0f +#define DSFXCOMPRESSOR_ATTACK_MIN 0.01f +#define DSFXCOMPRESSOR_ATTACK_MAX 500.0f +#define DSFXCOMPRESSOR_RELEASE_MIN 50.0f +#define DSFXCOMPRESSOR_RELEASE_MAX 3000.0f +#define DSFXCOMPRESSOR_THRESHOLD_MIN -60.0f +#define DSFXCOMPRESSOR_THRESHOLD_MAX 0.0f +#define DSFXCOMPRESSOR_RATIO_MIN 1.0f +#define DSFXCOMPRESSOR_RATIO_MAX 100.0f +#define DSFXCOMPRESSOR_PREDELAY_MIN 0.0f +#define DSFXCOMPRESSOR_PREDELAY_MAX 4.0f + +#undef INTERFACE +#define INTERFACE IDirectSoundFXCompressor + +DECLARE_INTERFACE_(IDirectSoundFXCompressor, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFXCompressor methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSFXCompressor pcDsFxCompressor) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSFXCompressor pDsFxCompressor) PURE; +}; + +#define IDirectSoundFXCompressor_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFXCompressor_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFXCompressor_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXCompressor_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundFXCompressor_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXCompressor_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundFXCompressor_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundFXParamEq +// + +DEFINE_GUID(IID_IDirectSoundFXParamEq, 0xc03ca9fe, 0xfe90, 0x4204, 0x80, 0x78, 0x82, 0x33, 0x4c, 0xd1, 0x77, 0xda); + +typedef struct _DSFXParamEq +{ + FLOAT fCenter; + FLOAT fBandwidth; + FLOAT fGain; +} DSFXParamEq, *LPDSFXParamEq; + +typedef const DSFXParamEq *LPCDSFXParamEq; + +#define DSFXPARAMEQ_CENTER_MIN 80.0f +#define DSFXPARAMEQ_CENTER_MAX 16000.0f +#define DSFXPARAMEQ_BANDWIDTH_MIN 1.0f +#define DSFXPARAMEQ_BANDWIDTH_MAX 36.0f +#define DSFXPARAMEQ_GAIN_MIN -15.0f +#define DSFXPARAMEQ_GAIN_MAX 15.0f + +#undef INTERFACE +#define INTERFACE IDirectSoundFXParamEq + +DECLARE_INTERFACE_(IDirectSoundFXParamEq, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFXParamEq methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSFXParamEq pcDsFxParamEq) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSFXParamEq pDsFxParamEq) PURE; +}; + +#define IDirectSoundFXParamEq_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFXParamEq_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFXParamEq_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXParamEq_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundFXParamEq_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXParamEq_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundFXParamEq_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundFXI3DL2Reverb +// + +DEFINE_GUID(IID_IDirectSoundFXI3DL2Reverb, 0x4b166a6a, 0x0d66, 0x43f3, 0x80, 0xe3, 0xee, 0x62, 0x80, 0xde, 0xe1, 0xa4); + +typedef struct _DSFXI3DL2Reverb +{ + LONG lRoom; // [-10000, 0] default: -1000 mB + LONG lRoomHF; // [-10000, 0] default: 0 mB + FLOAT flRoomRolloffFactor; // [0.0, 10.0] default: 0.0 + FLOAT flDecayTime; // [0.1, 20.0] default: 1.49s + FLOAT flDecayHFRatio; // [0.1, 2.0] default: 0.83 + LONG lReflections; // [-10000, 1000] default: -2602 mB + FLOAT flReflectionsDelay; // [0.0, 0.3] default: 0.007 s + LONG lReverb; // [-10000, 2000] default: 200 mB + FLOAT flReverbDelay; // [0.0, 0.1] default: 0.011 s + FLOAT flDiffusion; // [0.0, 100.0] default: 100.0 % + FLOAT flDensity; // [0.0, 100.0] default: 100.0 % + FLOAT flHFReference; // [20.0, 20000.0] default: 5000.0 Hz +} DSFXI3DL2Reverb, *LPDSFXI3DL2Reverb; + +typedef const DSFXI3DL2Reverb *LPCDSFXI3DL2Reverb; + +#define DSFX_I3DL2REVERB_ROOM_MIN (-10000) +#define DSFX_I3DL2REVERB_ROOM_MAX 0 +#define DSFX_I3DL2REVERB_ROOM_DEFAULT (-1000) + +#define DSFX_I3DL2REVERB_ROOMHF_MIN (-10000) +#define DSFX_I3DL2REVERB_ROOMHF_MAX 0 +#define DSFX_I3DL2REVERB_ROOMHF_DEFAULT (-100) + +#define DSFX_I3DL2REVERB_ROOMROLLOFFFACTOR_MIN 0.0f +#define DSFX_I3DL2REVERB_ROOMROLLOFFFACTOR_MAX 10.0f +#define DSFX_I3DL2REVERB_ROOMROLLOFFFACTOR_DEFAULT 0.0f + +#define DSFX_I3DL2REVERB_DECAYTIME_MIN 0.1f +#define DSFX_I3DL2REVERB_DECAYTIME_MAX 20.0f +#define DSFX_I3DL2REVERB_DECAYTIME_DEFAULT 1.49f + +#define DSFX_I3DL2REVERB_DECAYHFRATIO_MIN 0.1f +#define DSFX_I3DL2REVERB_DECAYHFRATIO_MAX 2.0f +#define DSFX_I3DL2REVERB_DECAYHFRATIO_DEFAULT 0.83f + +#define DSFX_I3DL2REVERB_REFLECTIONS_MIN (-10000) +#define DSFX_I3DL2REVERB_REFLECTIONS_MAX 1000 +#define DSFX_I3DL2REVERB_REFLECTIONS_DEFAULT (-2602) + +#define DSFX_I3DL2REVERB_REFLECTIONSDELAY_MIN 0.0f +#define DSFX_I3DL2REVERB_REFLECTIONSDELAY_MAX 0.3f +#define DSFX_I3DL2REVERB_REFLECTIONSDELAY_DEFAULT 0.007f + +#define DSFX_I3DL2REVERB_REVERB_MIN (-10000) +#define DSFX_I3DL2REVERB_REVERB_MAX 2000 +#define DSFX_I3DL2REVERB_REVERB_DEFAULT (200) + +#define DSFX_I3DL2REVERB_REVERBDELAY_MIN 0.0f +#define DSFX_I3DL2REVERB_REVERBDELAY_MAX 0.1f +#define DSFX_I3DL2REVERB_REVERBDELAY_DEFAULT 0.011f + +#define DSFX_I3DL2REVERB_DIFFUSION_MIN 0.0f +#define DSFX_I3DL2REVERB_DIFFUSION_MAX 100.0f +#define DSFX_I3DL2REVERB_DIFFUSION_DEFAULT 100.0f + +#define DSFX_I3DL2REVERB_DENSITY_MIN 0.0f +#define DSFX_I3DL2REVERB_DENSITY_MAX 100.0f +#define DSFX_I3DL2REVERB_DENSITY_DEFAULT 100.0f + +#define DSFX_I3DL2REVERB_HFREFERENCE_MIN 20.0f +#define DSFX_I3DL2REVERB_HFREFERENCE_MAX 20000.0f +#define DSFX_I3DL2REVERB_HFREFERENCE_DEFAULT 5000.0f + +#define DSFX_I3DL2REVERB_QUALITY_MIN 0 +#define DSFX_I3DL2REVERB_QUALITY_MAX 3 +#define DSFX_I3DL2REVERB_QUALITY_DEFAULT 2 + +#undef INTERFACE +#define INTERFACE IDirectSoundFXI3DL2Reverb + +DECLARE_INTERFACE_(IDirectSoundFXI3DL2Reverb, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFXI3DL2Reverb methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSFXI3DL2Reverb pcDsFxI3DL2Reverb) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSFXI3DL2Reverb pDsFxI3DL2Reverb) PURE; + STDMETHOD(SetPreset) (THIS_ DWORD dwPreset) PURE; + STDMETHOD(GetPreset) (THIS_ LPDWORD pdwPreset) PURE; + STDMETHOD(SetQuality) (THIS_ LONG lQuality) PURE; + STDMETHOD(GetQuality) (THIS_ LONG *plQuality) PURE; +}; + +#define IDirectSoundFXI3DL2Reverb_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFXI3DL2Reverb_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFXI3DL2Reverb_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXI3DL2Reverb_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundFXI3DL2Reverb_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#define IDirectSoundFXI3DL2Reverb_SetPreset(p,a) (p)->lpVtbl->SetPreset(p,a) +#define IDirectSoundFXI3DL2Reverb_GetPreset(p,a) (p)->lpVtbl->GetPreset(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXI3DL2Reverb_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundFXI3DL2Reverb_GetAllParameters(p,a) (p)->GetAllParameters(a) +#define IDirectSoundFXI3DL2Reverb_SetPreset(p,a) (p)->SetPreset(a) +#define IDirectSoundFXI3DL2Reverb_GetPreset(p,a) (p)->GetPreset(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundFXWavesReverb +// + +DEFINE_GUID(IID_IDirectSoundFXWavesReverb,0x46858c3a,0x0dc6,0x45e3,0xb7,0x60,0xd4,0xee,0xf1,0x6c,0xb3,0x25); + +typedef struct _DSFXWavesReverb +{ + FLOAT fInGain; // [-96.0,0.0] default: 0.0 dB + FLOAT fReverbMix; // [-96.0,0.0] default: 0.0 db + FLOAT fReverbTime; // [0.001,3000.0] default: 1000.0 ms + FLOAT fHighFreqRTRatio; // [0.001,0.999] default: 0.001 +} DSFXWavesReverb, *LPDSFXWavesReverb; + +typedef const DSFXWavesReverb *LPCDSFXWavesReverb; + +#define DSFX_WAVESREVERB_INGAIN_MIN -96.0f +#define DSFX_WAVESREVERB_INGAIN_MAX 0.0f +#define DSFX_WAVESREVERB_INGAIN_DEFAULT 0.0f +#define DSFX_WAVESREVERB_REVERBMIX_MIN -96.0f +#define DSFX_WAVESREVERB_REVERBMIX_MAX 0.0f +#define DSFX_WAVESREVERB_REVERBMIX_DEFAULT 0.0f +#define DSFX_WAVESREVERB_REVERBTIME_MIN 0.001f +#define DSFX_WAVESREVERB_REVERBTIME_MAX 3000.0f +#define DSFX_WAVESREVERB_REVERBTIME_DEFAULT 1000.0f +#define DSFX_WAVESREVERB_HIGHFREQRTRATIO_MIN 0.001f +#define DSFX_WAVESREVERB_HIGHFREQRTRATIO_MAX 0.999f +#define DSFX_WAVESREVERB_HIGHFREQRTRATIO_DEFAULT 0.001f + +#undef INTERFACE +#define INTERFACE IDirectSoundFXWavesReverb + +DECLARE_INTERFACE_(IDirectSoundFXWavesReverb, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFXWavesReverb methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSFXWavesReverb pcDsFxWavesReverb) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSFXWavesReverb pDsFxWavesReverb) PURE; +}; + +#define IDirectSoundFXWavesReverb_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFXWavesReverb_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFXWavesReverb_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXWavesReverb_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundFXWavesReverb_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFXWavesReverb_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundFXWavesReverb_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundCaptureFXAec +// + +DEFINE_GUID(IID_IDirectSoundCaptureFXAec, 0xad74143d, 0x903d, 0x4ab7, 0x80, 0x66, 0x28, 0xd3, 0x63, 0x03, 0x6d, 0x65); + +typedef struct _DSCFXAec +{ + BOOL fEnable; + BOOL fNoiseFill; + DWORD dwMode; +} DSCFXAec, *LPDSCFXAec; + +typedef const DSCFXAec *LPCDSCFXAec; + +// These match the AEC_MODE_* constants in the DDK's ksmedia.h file +#define DSCFX_AEC_MODE_PASS_THROUGH 0x0 +#define DSCFX_AEC_MODE_HALF_DUPLEX 0x1 +#define DSCFX_AEC_MODE_FULL_DUPLEX 0x2 + +// These match the AEC_STATUS_* constants in ksmedia.h +#define DSCFX_AEC_STATUS_HISTORY_UNINITIALIZED 0x0 +#define DSCFX_AEC_STATUS_HISTORY_CONTINUOUSLY_CONVERGED 0x1 +#define DSCFX_AEC_STATUS_HISTORY_PREVIOUSLY_DIVERGED 0x2 +#define DSCFX_AEC_STATUS_CURRENTLY_CONVERGED 0x8 + +#undef INTERFACE +#define INTERFACE IDirectSoundCaptureFXAec + +DECLARE_INTERFACE_(IDirectSoundCaptureFXAec, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundCaptureFXAec methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSCFXAec pDscFxAec) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSCFXAec pDscFxAec) PURE; + STDMETHOD(GetStatus) (THIS_ PDWORD pdwStatus) PURE; + STDMETHOD(Reset) (THIS) PURE; +}; + +#define IDirectSoundCaptureFXAec_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundCaptureFXAec_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundCaptureFXAec_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCaptureFXAec_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundCaptureFXAec_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCaptureFXAec_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundCaptureFXAec_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + + +// +// IDirectSoundCaptureFXNoiseSuppress +// + +DEFINE_GUID(IID_IDirectSoundCaptureFXNoiseSuppress, 0xed311e41, 0xfbae, 0x4175, 0x96, 0x25, 0xcd, 0x8, 0x54, 0xf6, 0x93, 0xca); + +typedef struct _DSCFXNoiseSuppress +{ + BOOL fEnable; +} DSCFXNoiseSuppress, *LPDSCFXNoiseSuppress; + +typedef const DSCFXNoiseSuppress *LPCDSCFXNoiseSuppress; + +#undef INTERFACE +#define INTERFACE IDirectSoundCaptureFXNoiseSuppress + +DECLARE_INTERFACE_(IDirectSoundCaptureFXNoiseSuppress, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundCaptureFXNoiseSuppress methods + STDMETHOD(SetAllParameters) (THIS_ LPCDSCFXNoiseSuppress pcDscFxNoiseSuppress) PURE; + STDMETHOD(GetAllParameters) (THIS_ LPDSCFXNoiseSuppress pDscFxNoiseSuppress) PURE; + STDMETHOD(Reset) (THIS) PURE; +}; + +#define IDirectSoundCaptureFXNoiseSuppress_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundCaptureFXNoiseSuppress_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundCaptureFXNoiseSuppress_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCaptureFXNoiseSuppress_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) +#define IDirectSoundCaptureFXNoiseSuppress_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCaptureFXNoiseSuppress_SetAllParameters(p,a) (p)->SetAllParameters(a) +#define IDirectSoundCaptureFXNoiseSuppress_GetAllParameters(p,a) (p)->GetAllParameters(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + + +// +// IDirectSoundFullDuplex +// + +#ifndef _IDirectSoundFullDuplex_ +#define _IDirectSoundFullDuplex_ + +#ifdef __cplusplus +// 'struct' not 'class' per the way DECLARE_INTERFACE_ is defined +struct IDirectSoundFullDuplex; +#endif // __cplusplus + + +DEFINE_GUID(IID_IDirectSoundFullDuplex, 0xedcb4c7a, 0xdaab, 0x4216, 0xa4, 0x2e, 0x6c, 0x50, 0x59, 0x6d, 0xdc, 0x1d); + +#undef INTERFACE +#define INTERFACE IDirectSoundFullDuplex + +DECLARE_INTERFACE_(IDirectSoundFullDuplex, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundFullDuplex methods + STDMETHOD(Initialize) (THIS_ LPCGUID pCaptureGuid, LPCGUID pRenderGuid, LPCDSCBUFFERDESC lpDscBufferDesc, LPCDSBUFFERDESC lpDsBufferDesc, HWND hWnd, DWORD dwLevel, LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8, LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8) PURE; +}; + +#define IDirectSoundFullDuplex_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) +#define IDirectSoundFullDuplex_AddRef(p) IUnknown_AddRef(p) +#define IDirectSoundFullDuplex_Release(p) IUnknown_Release(p) + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFullDuplex_Initialize(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->Initialize(p,a,b,c,d,e,f,g,h) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundFullDuplex_Initialize(p,a,b,c,d,e,f,g,h) (p)->Initialize(a,b,c,d,e,f,g,h) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +#endif // _IDirectSoundFullDuplex_ + +#endif // DIRECTSOUND_VERSION >= 0x0800 + +// +// Return Codes +// + +// The function completed successfully +#define DS_OK S_OK + +// The call succeeded, but we had to substitute the 3D algorithm +#define DS_NO_VIRTUALIZATION MAKE_HRESULT(0, _FACDS, 10) + +// The call failed because resources (such as a priority level) +// were already being used by another caller +#define DSERR_ALLOCATED MAKE_DSHRESULT(10) + +// The control (vol, pan, etc.) requested by the caller is not available +#define DSERR_CONTROLUNAVAIL MAKE_DSHRESULT(30) + +// An invalid parameter was passed to the returning function +#define DSERR_INVALIDPARAM E_INVALIDARG + +// This call is not valid for the current state of this object +#define DSERR_INVALIDCALL MAKE_DSHRESULT(50) + +// An undetermined error occurred inside the DirectSound subsystem +#define DSERR_GENERIC E_FAIL + +// The caller does not have the priority level required for the function to +// succeed +#define DSERR_PRIOLEVELNEEDED MAKE_DSHRESULT(70) + +// Not enough free memory is available to complete the operation +#define DSERR_OUTOFMEMORY E_OUTOFMEMORY + +// The specified WAVE format is not supported +#define DSERR_BADFORMAT MAKE_DSHRESULT(100) + +// The function called is not supported at this time +#define DSERR_UNSUPPORTED E_NOTIMPL + +// No sound driver is available for use +#define DSERR_NODRIVER MAKE_DSHRESULT(120) + +// This object is already initialized +#define DSERR_ALREADYINITIALIZED MAKE_DSHRESULT(130) + +// This object does not support aggregation +#define DSERR_NOAGGREGATION CLASS_E_NOAGGREGATION + +// The buffer memory has been lost, and must be restored +#define DSERR_BUFFERLOST MAKE_DSHRESULT(150) + +// Another app has a higher priority level, preventing this call from +// succeeding +#define DSERR_OTHERAPPHASPRIO MAKE_DSHRESULT(160) + +// This object has not been initialized +#define DSERR_UNINITIALIZED MAKE_DSHRESULT(170) + +// The requested COM interface is not available +#define DSERR_NOINTERFACE E_NOINTERFACE + +// Access is denied +#define DSERR_ACCESSDENIED E_ACCESSDENIED + +// Tried to create a DSBCAPS_CTRLFX buffer shorter than DSBSIZE_FX_MIN milliseconds +#define DSERR_BUFFERTOOSMALL MAKE_DSHRESULT(180) + +// Attempt to use DirectSound 8 functionality on an older DirectSound object +#define DSERR_DS8_REQUIRED MAKE_DSHRESULT(190) + +// A circular loop of send effects was detected +#define DSERR_SENDLOOP MAKE_DSHRESULT(200) + +// The GUID specified in an audiopath file does not match a valid MIXIN buffer +#define DSERR_BADSENDBUFFERGUID MAKE_DSHRESULT(210) + +// The object requested was not found (numerically equal to DMUS_E_NOT_FOUND) +#define DSERR_OBJECTNOTFOUND MAKE_DSHRESULT(4449) + +// The effects requested could not be found on the system, or they were found +// but in the wrong order, or in the wrong hardware/software locations. +#define DSERR_FXUNAVAILABLE MAKE_DSHRESULT(220) + +// +// Flags +// + +#define DSCAPS_PRIMARYMONO 0x00000001 +#define DSCAPS_PRIMARYSTEREO 0x00000002 +#define DSCAPS_PRIMARY8BIT 0x00000004 +#define DSCAPS_PRIMARY16BIT 0x00000008 +#define DSCAPS_CONTINUOUSRATE 0x00000010 +#define DSCAPS_EMULDRIVER 0x00000020 +#define DSCAPS_CERTIFIED 0x00000040 +#define DSCAPS_SECONDARYMONO 0x00000100 +#define DSCAPS_SECONDARYSTEREO 0x00000200 +#define DSCAPS_SECONDARY8BIT 0x00000400 +#define DSCAPS_SECONDARY16BIT 0x00000800 + +#define DSSCL_NORMAL 0x00000001 +#define DSSCL_PRIORITY 0x00000002 +#define DSSCL_EXCLUSIVE 0x00000003 +#define DSSCL_WRITEPRIMARY 0x00000004 + +#define DSSPEAKER_DIRECTOUT 0x00000000 +#define DSSPEAKER_HEADPHONE 0x00000001 +#define DSSPEAKER_MONO 0x00000002 +#define DSSPEAKER_QUAD 0x00000003 +#define DSSPEAKER_STEREO 0x00000004 +#define DSSPEAKER_SURROUND 0x00000005 +#define DSSPEAKER_5POINT1 0x00000006 +#define DSSPEAKER_7POINT1 0x00000007 + +#define DSSPEAKER_GEOMETRY_MIN 0x00000005 // 5 degrees +#define DSSPEAKER_GEOMETRY_NARROW 0x0000000A // 10 degrees +#define DSSPEAKER_GEOMETRY_WIDE 0x00000014 // 20 degrees +#define DSSPEAKER_GEOMETRY_MAX 0x000000B4 // 180 degrees + +#define DSSPEAKER_COMBINED(c, g) ((DWORD)(((BYTE)(c)) | ((DWORD)((BYTE)(g))) << 16)) +#define DSSPEAKER_CONFIG(a) ((BYTE)(a)) +#define DSSPEAKER_GEOMETRY(a) ((BYTE)(((DWORD)(a) >> 16) & 0x00FF)) + +#define DSBCAPS_PRIMARYBUFFER 0x00000001 +#define DSBCAPS_STATIC 0x00000002 +#define DSBCAPS_LOCHARDWARE 0x00000004 +#define DSBCAPS_LOCSOFTWARE 0x00000008 +#define DSBCAPS_CTRL3D 0x00000010 +#define DSBCAPS_CTRLFREQUENCY 0x00000020 +#define DSBCAPS_CTRLPAN 0x00000040 +#define DSBCAPS_CTRLVOLUME 0x00000080 +#define DSBCAPS_CTRLPOSITIONNOTIFY 0x00000100 +#define DSBCAPS_CTRLFX 0x00000200 +#define DSBCAPS_STICKYFOCUS 0x00004000 +#define DSBCAPS_GLOBALFOCUS 0x00008000 +#define DSBCAPS_GETCURRENTPOSITION2 0x00010000 +#define DSBCAPS_MUTE3DATMAXDISTANCE 0x00020000 +#define DSBCAPS_LOCDEFER 0x00040000 + +#define DSBPLAY_LOOPING 0x00000001 +#define DSBPLAY_LOCHARDWARE 0x00000002 +#define DSBPLAY_LOCSOFTWARE 0x00000004 +#define DSBPLAY_TERMINATEBY_TIME 0x00000008 +#define DSBPLAY_TERMINATEBY_DISTANCE 0x000000010 +#define DSBPLAY_TERMINATEBY_PRIORITY 0x000000020 + +#define DSBSTATUS_PLAYING 0x00000001 +#define DSBSTATUS_BUFFERLOST 0x00000002 +#define DSBSTATUS_LOOPING 0x00000004 +#define DSBSTATUS_LOCHARDWARE 0x00000008 +#define DSBSTATUS_LOCSOFTWARE 0x00000010 +#define DSBSTATUS_TERMINATED 0x00000020 + +#define DSBLOCK_FROMWRITECURSOR 0x00000001 +#define DSBLOCK_ENTIREBUFFER 0x00000002 + +#define DSBFREQUENCY_ORIGINAL 0 +#define DSBFREQUENCY_MIN 100 +#if DIRECTSOUND_VERSION >= 0x0900 +#define DSBFREQUENCY_MAX 200000 +#else +#define DSBFREQUENCY_MAX 100000 +#endif + +#define DSBPAN_LEFT -10000 +#define DSBPAN_CENTER 0 +#define DSBPAN_RIGHT 10000 + +#define DSBVOLUME_MIN -10000 +#define DSBVOLUME_MAX 0 + +#define DSBSIZE_MIN 4 +#define DSBSIZE_MAX 0x0FFFFFFF +#define DSBSIZE_FX_MIN 150 // NOTE: Milliseconds, not bytes + +#define DS3DMODE_NORMAL 0x00000000 +#define DS3DMODE_HEADRELATIVE 0x00000001 +#define DS3DMODE_DISABLE 0x00000002 + +#define DS3D_IMMEDIATE 0x00000000 +#define DS3D_DEFERRED 0x00000001 + +#define DS3D_MINDISTANCEFACTOR FLT_MIN +#define DS3D_MAXDISTANCEFACTOR FLT_MAX +#define DS3D_DEFAULTDISTANCEFACTOR 1.0f + +#define DS3D_MINROLLOFFFACTOR 0.0f +#define DS3D_MAXROLLOFFFACTOR 10.0f +#define DS3D_DEFAULTROLLOFFFACTOR 1.0f + +#define DS3D_MINDOPPLERFACTOR 0.0f +#define DS3D_MAXDOPPLERFACTOR 10.0f +#define DS3D_DEFAULTDOPPLERFACTOR 1.0f + +#define DS3D_DEFAULTMINDISTANCE 1.0f +#define DS3D_DEFAULTMAXDISTANCE 1000000000.0f + +#define DS3D_MINCONEANGLE 0 +#define DS3D_MAXCONEANGLE 360 +#define DS3D_DEFAULTCONEANGLE 360 + +#define DS3D_DEFAULTCONEOUTSIDEVOLUME DSBVOLUME_MAX + +// IDirectSoundCapture attributes + +#define DSCCAPS_EMULDRIVER DSCAPS_EMULDRIVER +#define DSCCAPS_CERTIFIED DSCAPS_CERTIFIED +#define DSCCAPS_MULTIPLECAPTURE 0x00000001 + +// IDirectSoundCaptureBuffer attributes + +#define DSCBCAPS_WAVEMAPPED 0x80000000 + +#if DIRECTSOUND_VERSION >= 0x0800 +#define DSCBCAPS_CTRLFX 0x00000200 +#endif + + +#define DSCBLOCK_ENTIREBUFFER 0x00000001 + +#define DSCBSTATUS_CAPTURING 0x00000001 +#define DSCBSTATUS_LOOPING 0x00000002 + +#define DSCBSTART_LOOPING 0x00000001 + +#define DSBPN_OFFSETSTOP 0xFFFFFFFF + +#define DS_CERTIFIED 0x00000000 +#define DS_UNCERTIFIED 0x00000001 + + +// +// Flags for the I3DL2 effects +// + +// +// I3DL2 Material Presets +// + +enum +{ + DSFX_I3DL2_MATERIAL_PRESET_SINGLEWINDOW, + DSFX_I3DL2_MATERIAL_PRESET_DOUBLEWINDOW, + DSFX_I3DL2_MATERIAL_PRESET_THINDOOR, + DSFX_I3DL2_MATERIAL_PRESET_THICKDOOR, + DSFX_I3DL2_MATERIAL_PRESET_WOODWALL, + DSFX_I3DL2_MATERIAL_PRESET_BRICKWALL, + DSFX_I3DL2_MATERIAL_PRESET_STONEWALL, + DSFX_I3DL2_MATERIAL_PRESET_CURTAIN +}; + +#define I3DL2_MATERIAL_PRESET_SINGLEWINDOW -2800,0.71f +#define I3DL2_MATERIAL_PRESET_DOUBLEWINDOW -5000,0.40f +#define I3DL2_MATERIAL_PRESET_THINDOOR -1800,0.66f +#define I3DL2_MATERIAL_PRESET_THICKDOOR -4400,0.64f +#define I3DL2_MATERIAL_PRESET_WOODWALL -4000,0.50f +#define I3DL2_MATERIAL_PRESET_BRICKWALL -5000,0.60f +#define I3DL2_MATERIAL_PRESET_STONEWALL -6000,0.68f +#define I3DL2_MATERIAL_PRESET_CURTAIN -1200,0.15f + +enum +{ + DSFX_I3DL2_ENVIRONMENT_PRESET_DEFAULT, + DSFX_I3DL2_ENVIRONMENT_PRESET_GENERIC, + DSFX_I3DL2_ENVIRONMENT_PRESET_PADDEDCELL, + DSFX_I3DL2_ENVIRONMENT_PRESET_ROOM, + DSFX_I3DL2_ENVIRONMENT_PRESET_BATHROOM, + DSFX_I3DL2_ENVIRONMENT_PRESET_LIVINGROOM, + DSFX_I3DL2_ENVIRONMENT_PRESET_STONEROOM, + DSFX_I3DL2_ENVIRONMENT_PRESET_AUDITORIUM, + DSFX_I3DL2_ENVIRONMENT_PRESET_CONCERTHALL, + DSFX_I3DL2_ENVIRONMENT_PRESET_CAVE, + DSFX_I3DL2_ENVIRONMENT_PRESET_ARENA, + DSFX_I3DL2_ENVIRONMENT_PRESET_HANGAR, + DSFX_I3DL2_ENVIRONMENT_PRESET_CARPETEDHALLWAY, + DSFX_I3DL2_ENVIRONMENT_PRESET_HALLWAY, + DSFX_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR, + DSFX_I3DL2_ENVIRONMENT_PRESET_ALLEY, + DSFX_I3DL2_ENVIRONMENT_PRESET_FOREST, + DSFX_I3DL2_ENVIRONMENT_PRESET_CITY, + DSFX_I3DL2_ENVIRONMENT_PRESET_MOUNTAINS, + DSFX_I3DL2_ENVIRONMENT_PRESET_QUARRY, + DSFX_I3DL2_ENVIRONMENT_PRESET_PLAIN, + DSFX_I3DL2_ENVIRONMENT_PRESET_PARKINGLOT, + DSFX_I3DL2_ENVIRONMENT_PRESET_SEWERPIPE, + DSFX_I3DL2_ENVIRONMENT_PRESET_UNDERWATER, + DSFX_I3DL2_ENVIRONMENT_PRESET_SMALLROOM, + DSFX_I3DL2_ENVIRONMENT_PRESET_MEDIUMROOM, + DSFX_I3DL2_ENVIRONMENT_PRESET_LARGEROOM, + DSFX_I3DL2_ENVIRONMENT_PRESET_MEDIUMHALL, + DSFX_I3DL2_ENVIRONMENT_PRESET_LARGEHALL, + DSFX_I3DL2_ENVIRONMENT_PRESET_PLATE +}; + +// +// I3DL2 Reverberation Presets Values +// + +#define I3DL2_ENVIRONMENT_PRESET_DEFAULT -1000, -100, 0.0f, 1.49f, 0.83f, -2602, 0.007f, 200, 0.011f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_GENERIC -1000, -100, 0.0f, 1.49f, 0.83f, -2602, 0.007f, 200, 0.011f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_PADDEDCELL -1000,-6000, 0.0f, 0.17f, 0.10f, -1204, 0.001f, 207, 0.002f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_ROOM -1000, -454, 0.0f, 0.40f, 0.83f, -1646, 0.002f, 53, 0.003f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_BATHROOM -1000,-1200, 0.0f, 1.49f, 0.54f, -370, 0.007f, 1030, 0.011f, 100.0f, 60.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_LIVINGROOM -1000,-6000, 0.0f, 0.50f, 0.10f, -1376, 0.003f, -1104, 0.004f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_STONEROOM -1000, -300, 0.0f, 2.31f, 0.64f, -711, 0.012f, 83, 0.017f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_AUDITORIUM -1000, -476, 0.0f, 4.32f, 0.59f, -789, 0.020f, -289, 0.030f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_CONCERTHALL -1000, -500, 0.0f, 3.92f, 0.70f, -1230, 0.020f, -2, 0.029f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_CAVE -1000, 0, 0.0f, 2.91f, 1.30f, -602, 0.015f, -302, 0.022f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_ARENA -1000, -698, 0.0f, 7.24f, 0.33f, -1166, 0.020f, 16, 0.030f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_HANGAR -1000,-1000, 0.0f,10.05f, 0.23f, -602, 0.020f, 198, 0.030f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_CARPETEDHALLWAY -1000,-4000, 0.0f, 0.30f, 0.10f, -1831, 0.002f, -1630, 0.030f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_HALLWAY -1000, -300, 0.0f, 1.49f, 0.59f, -1219, 0.007f, 441, 0.011f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR -1000, -237, 0.0f, 2.70f, 0.79f, -1214, 0.013f, 395, 0.020f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_ALLEY -1000, -270, 0.0f, 1.49f, 0.86f, -1204, 0.007f, -4, 0.011f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_FOREST -1000,-3300, 0.0f, 1.49f, 0.54f, -2560, 0.162f, -613, 0.088f, 79.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_CITY -1000, -800, 0.0f, 1.49f, 0.67f, -2273, 0.007f, -2217, 0.011f, 50.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_MOUNTAINS -1000,-2500, 0.0f, 1.49f, 0.21f, -2780, 0.300f, -2014, 0.100f, 27.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_QUARRY -1000,-1000, 0.0f, 1.49f, 0.83f,-10000, 0.061f, 500, 0.025f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_PLAIN -1000,-2000, 0.0f, 1.49f, 0.50f, -2466, 0.179f, -2514, 0.100f, 21.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_PARKINGLOT -1000, 0, 0.0f, 1.65f, 1.50f, -1363, 0.008f, -1153, 0.012f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_SEWERPIPE -1000,-1000, 0.0f, 2.81f, 0.14f, 429, 0.014f, 648, 0.021f, 80.0f, 60.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_UNDERWATER -1000,-4000, 0.0f, 1.49f, 0.10f, -449, 0.007f, 1700, 0.011f, 100.0f, 100.0f, 5000.0f + +// +// Examples simulating 'musical' reverb presets +// +// Name Decay time Description +// Small Room 1.1s A small size room with a length of 5m or so. +// Medium Room 1.3s A medium size room with a length of 10m or so. +// Large Room 1.5s A large size room suitable for live performances. +// Medium Hall 1.8s A medium size concert hall. +// Large Hall 1.8s A large size concert hall suitable for a full orchestra. +// Plate 1.3s A plate reverb simulation. +// + +#define I3DL2_ENVIRONMENT_PRESET_SMALLROOM -1000, -600, 0.0f, 1.10f, 0.83f, -400, 0.005f, 500, 0.010f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_MEDIUMROOM -1000, -600, 0.0f, 1.30f, 0.83f, -1000, 0.010f, -200, 0.020f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_LARGEROOM -1000, -600, 0.0f, 1.50f, 0.83f, -1600, 0.020f, -1000, 0.040f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_MEDIUMHALL -1000, -600, 0.0f, 1.80f, 0.70f, -1300, 0.015f, -800, 0.030f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_LARGEHALL -1000, -600, 0.0f, 1.80f, 0.70f, -2000, 0.030f, -1400, 0.060f, 100.0f, 100.0f, 5000.0f +#define I3DL2_ENVIRONMENT_PRESET_PLATE -1000, -200, 0.0f, 1.30f, 0.90f, 0, 0.002f, 0, 0.010f, 100.0f, 75.0f, 5000.0f + +// +// DirectSound3D Algorithms +// + +// Default DirectSound3D algorithm {00000000-0000-0000-0000-000000000000} +#define DS3DALG_DEFAULT GUID_NULL + +// No virtualization (Pan3D) {C241333F-1C1B-11d2-94F5-00C04FC28ACA} +DEFINE_GUID(DS3DALG_NO_VIRTUALIZATION, 0xc241333f, 0x1c1b, 0x11d2, 0x94, 0xf5, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca); + +// High-quality HRTF algorithm {C2413340-1C1B-11d2-94F5-00C04FC28ACA} +DEFINE_GUID(DS3DALG_HRTF_FULL, 0xc2413340, 0x1c1b, 0x11d2, 0x94, 0xf5, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca); + +// Lower-quality HRTF algorithm {C2413342-1C1B-11d2-94F5-00C04FC28ACA} +DEFINE_GUID(DS3DALG_HRTF_LIGHT, 0xc2413342, 0x1c1b, 0x11d2, 0x94, 0xf5, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca); + + +#if DIRECTSOUND_VERSION >= 0x0800 + +// +// DirectSound Internal Effect Algorithms +// + + +// Gargle {DAFD8210-5711-4B91-9FE3-F75B7AE279BF} +DEFINE_GUID(GUID_DSFX_STANDARD_GARGLE, 0xdafd8210, 0x5711, 0x4b91, 0x9f, 0xe3, 0xf7, 0x5b, 0x7a, 0xe2, 0x79, 0xbf); + +// Chorus {EFE6629C-81F7-4281-BD91-C9D604A95AF6} +DEFINE_GUID(GUID_DSFX_STANDARD_CHORUS, 0xefe6629c, 0x81f7, 0x4281, 0xbd, 0x91, 0xc9, 0xd6, 0x04, 0xa9, 0x5a, 0xf6); + +// Flanger {EFCA3D92-DFD8-4672-A603-7420894BAD98} +DEFINE_GUID(GUID_DSFX_STANDARD_FLANGER, 0xefca3d92, 0xdfd8, 0x4672, 0xa6, 0x03, 0x74, 0x20, 0x89, 0x4b, 0xad, 0x98); + +// Echo/Delay {EF3E932C-D40B-4F51-8CCF-3F98F1B29D5D} +DEFINE_GUID(GUID_DSFX_STANDARD_ECHO, 0xef3e932c, 0xd40b, 0x4f51, 0x8c, 0xcf, 0x3f, 0x98, 0xf1, 0xb2, 0x9d, 0x5d); + +// Distortion {EF114C90-CD1D-484E-96E5-09CFAF912A21} +DEFINE_GUID(GUID_DSFX_STANDARD_DISTORTION, 0xef114c90, 0xcd1d, 0x484e, 0x96, 0xe5, 0x09, 0xcf, 0xaf, 0x91, 0x2a, 0x21); + +// Compressor/Limiter {EF011F79-4000-406D-87AF-BFFB3FC39D57} +DEFINE_GUID(GUID_DSFX_STANDARD_COMPRESSOR, 0xef011f79, 0x4000, 0x406d, 0x87, 0xaf, 0xbf, 0xfb, 0x3f, 0xc3, 0x9d, 0x57); + +// Parametric Equalization {120CED89-3BF4-4173-A132-3CB406CF3231} +DEFINE_GUID(GUID_DSFX_STANDARD_PARAMEQ, 0x120ced89, 0x3bf4, 0x4173, 0xa1, 0x32, 0x3c, 0xb4, 0x06, 0xcf, 0x32, 0x31); + +// I3DL2 Environmental Reverberation: Reverb (Listener) Effect {EF985E71-D5C7-42D4-BA4D-2D073E2E96F4} +DEFINE_GUID(GUID_DSFX_STANDARD_I3DL2REVERB, 0xef985e71, 0xd5c7, 0x42d4, 0xba, 0x4d, 0x2d, 0x07, 0x3e, 0x2e, 0x96, 0xf4); + +// Waves Reverberation {87FC0268-9A55-4360-95AA-004A1D9DE26C} +DEFINE_GUID(GUID_DSFX_WAVES_REVERB, 0x87fc0268, 0x9a55, 0x4360, 0x95, 0xaa, 0x00, 0x4a, 0x1d, 0x9d, 0xe2, 0x6c); + +// +// DirectSound Capture Effect Algorithms +// + + +// Acoustic Echo Canceller {BF963D80-C559-11D0-8A2B-00A0C9255AC1} +// Matches KSNODETYPE_ACOUSTIC_ECHO_CANCEL in ksmedia.h +DEFINE_GUID(GUID_DSCFX_CLASS_AEC, 0xBF963D80L, 0xC559, 0x11D0, 0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1); + +// Microsoft AEC {CDEBB919-379A-488a-8765-F53CFD36DE40} +DEFINE_GUID(GUID_DSCFX_MS_AEC, 0xcdebb919, 0x379a, 0x488a, 0x87, 0x65, 0xf5, 0x3c, 0xfd, 0x36, 0xde, 0x40); + +// System AEC {1C22C56D-9879-4f5b-A389-27996DDC2810} +DEFINE_GUID(GUID_DSCFX_SYSTEM_AEC, 0x1c22c56d, 0x9879, 0x4f5b, 0xa3, 0x89, 0x27, 0x99, 0x6d, 0xdc, 0x28, 0x10); + +// Noise Supression {E07F903F-62FD-4e60-8CDD-DEA7236665B5} +// Matches KSNODETYPE_NOISE_SUPPRESS in post Windows ME DDK's ksmedia.h +DEFINE_GUID(GUID_DSCFX_CLASS_NS, 0xe07f903f, 0x62fd, 0x4e60, 0x8c, 0xdd, 0xde, 0xa7, 0x23, 0x66, 0x65, 0xb5); + +// Microsoft Noise Suppresion {11C5C73B-66E9-4ba1-A0BA-E814C6EED92D} +DEFINE_GUID(GUID_DSCFX_MS_NS, 0x11c5c73b, 0x66e9, 0x4ba1, 0xa0, 0xba, 0xe8, 0x14, 0xc6, 0xee, 0xd9, 0x2d); + +// System Noise Suppresion {5AB0882E-7274-4516-877D-4EEE99BA4FD0} +DEFINE_GUID(GUID_DSCFX_SYSTEM_NS, 0x5ab0882e, 0x7274, 0x4516, 0x87, 0x7d, 0x4e, 0xee, 0x99, 0xba, 0x4f, 0xd0); + +#endif // DIRECTSOUND_VERSION >= 0x0800 + +#endif // __DSOUND_INCLUDED__ + + + +#ifdef __cplusplus +}; +#endif // __cplusplus + + diff --git a/plugins/PeopsSPU2/dsoundoss.h b/plugins/PeopsSPU2/dsoundoss.h index 65c22eeaa5..86d788a7ae 100644 --- a/plugins/PeopsSPU2/dsoundoss.h +++ b/plugins/PeopsSPU2/dsoundoss.h @@ -1,36 +1,36 @@ -/*************************************************************************** - dsoundoss.h - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - - -void SetupSound(void); -void RemoveSound(void); -unsigned long SoundGetBytesBuffered(void); -void SoundFeedStreamData(unsigned char* pSound,long lBytes); - -#ifndef _WINDOWS -unsigned long timeGetTime(); -#endif - +/*************************************************************************** + dsoundoss.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + + +void SetupSound(void); +void RemoveSound(void); +unsigned long SoundGetBytesBuffered(void); +void SoundFeedStreamData(unsigned char* pSound,long lBytes); + +#ifndef _WINDOWS +unsigned long timeGetTime(); +#endif + diff --git a/plugins/PeopsSPU2/externals.h b/plugins/PeopsSPU2/externals.h index af68ea6791..9b74b85d8d 100644 --- a/plugins/PeopsSPU2/externals.h +++ b/plugins/PeopsSPU2/externals.h @@ -1,364 +1,364 @@ -/*************************************************************************** - externals.h - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2004/04/04 - Pete -// - changed plugin to emulate PS2 spu -// -// 2002/04/04 - Pete -// - increased channel struct for interpolation -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - - -///////////////////////////////////////////////////////// -// generic defines -///////////////////////////////////////////////////////// - -//#define PSE_LT_SPU 4 -//#define PSE_SPU_ERR_SUCCESS 0 -//#define PSE_SPU_ERR -60 -//#define PSE_SPU_ERR_NOTCONFIGURED PSE_SPU_ERR - 1 -//#define PSE_SPU_ERR_INIT PSE_SPU_ERR - 2 - -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif - -//////////////////////////////////////////////////////////////////////// -// spu defines -//////////////////////////////////////////////////////////////////////// - -// sound buffer sizes -// 500 ms complete sound buffer -#define SOUNDSIZE 76800 - -// 200 ms test buffer... if less than that is buffered, a new upload will happen -#define TESTSIZE 26304//13152 - -// num of channels -#define MAXCHAN 48 -#define HLFCHAN 24 - -// ~ 1 ms of data -#define NSSIZE 48 - -/////////////////////////////////////////////////////////// -// struct defines -/////////////////////////////////////////////////////////// -// ADMA Channels -extern EXPORT_GCC void CALLBACK SPU2async(unsigned long cycle); -typedef struct -{ - unsigned short * MemAddr; - unsigned short * TempMem; - unsigned int Index; - unsigned int AmountLeft; - unsigned int ADMAPos; - unsigned int TransferAmount; - int IRQ; - int TempAmount; -} ADMA; - -typedef struct -{ - int Left; - int Right; -} DINPUT; - -// ADSR INFOS PER CHANNEL -typedef struct -{ - int AttackModeExp; - long AttackTime; - long DecayTime; - long SustainLevel; - int SustainModeExp; - long SustainModeDec; - long SustainTime; - int ReleaseModeExp; - unsigned long ReleaseVal; - long ReleaseTime; - long ReleaseStartTime; - long ReleaseVol; - long lTime; - long lVolume; -} ADSRInfo; - -typedef struct -{ - int State; - int AttackModeExp; - int AttackRate; - int DecayRate; - int SustainLevel; - int SustainModeExp; - int SustainIncrease; - int SustainRate; - int ReleaseModeExp; - int ReleaseRate; - int EnvelopeVol; - long lVolume; - long lDummy1; - long lDummy2; -} ADSRInfoEx; - -/////////////////////////////////////////////////////////// - -// Tmp Flags - -// used for debug channel muting -#define FLAG_MUTE 1 - -// used for simple interpolation -#define FLAG_IPOL0 2 -#define FLAG_IPOL1 4 - -/////////////////////////////////////////////////////////// - -// MAIN CHANNEL STRUCT -typedef struct -{ - // no mutexes used anymore... don't need them to sync access - //HANDLE hMutex; - - int bNew; // start flag - - int iSBPos; // mixing stuff - int spos; - int sinc; - int SB[32+32]; // Pete added another 32 dwords in 1.6 ... prevents overflow issues with gaussian/cubic interpolation (thanx xodnizel!), and can be used for even better interpolations, eh? :) - int sval; - - unsigned char * pStart; // start ptr into sound mem - unsigned char * pCurr; // current pos in sound mem - unsigned char * pLoop; // loop ptr in sound mem - - int iStartAdr; - int iLoopAdr; - int iNextAdr; - - int bOn; // is channel active (sample playing?) - int bStop; // is channel stopped (sample _can_ still be playing, ADSR Release phase) - int bEndPoint; // end point reached - int bReverbL; // can we do reverb on this channel? must have ctrl register bit, to get active - int bReverbR; - - int bVolumeL; // Volume on/off - int bVolumeR; - - int iActFreq; // current psx pitch - int iUsedFreq; // current pc pitch - int iLeftVolume; // left volume - int iLeftVolRaw; // left psx volume value - int bIgnoreLoop; // ignore loop bit, if an external loop address is used - int iMute; // mute mode - int iRightVolume; // right volume - int iRightVolRaw; // right psx volume value - int iRawPitch; // raw pitch (0...3fff) - int iIrqDone; // debug irq done flag - int s_1; // last decoding infos - int s_2; - int bRVBActive; // reverb active flag - int bNoise; // noise active flag - int bFMod; // freq mod (0=off, 1=sound channel, 2=freq channel) - int iOldNoise; // old noise val for this channel - ADSRInfo ADSR; // active ADSR settings - ADSRInfoEx ADSRX; // next ADSR settings (will be moved to active on sample start) - -} SPUCHAN; - -/////////////////////////////////////////////////////////// - -typedef struct -{ - int StartAddr; // reverb area start addr in samples - int EndAddr; // reverb area end addr in samples - int CurrAddr; // reverb area curr addr in samples - - int VolLeft; - int VolRight; - int iLastRVBLeft; - int iLastRVBRight; - int iRVBLeft; - int iRVBRight; - int iCnt; - - int FB_SRC_A; // (offset) - int FB_SRC_B; // (offset) - int IIR_ALPHA; // (coef.) - int ACC_COEF_A; // (coef.) - int ACC_COEF_B; // (coef.) - int ACC_COEF_C; // (coef.) - int ACC_COEF_D; // (coef.) - int IIR_COEF; // (coef.) - int FB_ALPHA; // (coef.) - int FB_X; // (coef.) - int IIR_DEST_A0; // (offset) - int IIR_DEST_A1; // (offset) - int ACC_SRC_A0; // (offset) - int ACC_SRC_A1; // (offset) - int ACC_SRC_B0; // (offset) - int ACC_SRC_B1; // (offset) - int IIR_SRC_A0; // (offset) - int IIR_SRC_A1; // (offset) - int IIR_DEST_B0; // (offset) - int IIR_DEST_B1; // (offset) - int ACC_SRC_C0; // (offset) - int ACC_SRC_C1; // (offset) - int ACC_SRC_D0; // (offset) - int ACC_SRC_D1; // (offset) - int IIR_SRC_B1; // (offset) - int IIR_SRC_B0; // (offset) - int MIX_DEST_A0; // (offset) - int MIX_DEST_A1; // (offset) - int MIX_DEST_B0; // (offset) - int MIX_DEST_B1; // (offset) - int IN_COEF_L; // (coef.) - int IN_COEF_R; // (coef.) -} REVERBInfo; - -#ifdef _WINDOWS -extern HINSTANCE hInst; -#define WM_MUTE (WM_USER+543) -#endif - -/////////////////////////////////////////////////////////// -// SPU.C globals -/////////////////////////////////////////////////////////// - -#ifndef _IN_SPU - -// psx buffers / addresses - -extern unsigned short regArea[]; -extern unsigned short spuMem[]; -extern unsigned char * spuMemC; -extern unsigned char * pSpuIrq[]; -extern unsigned char * pSpuBuffer; - -// user settings - -extern int iUseXA; -extern int iVolume; -extern int iXAPitch; -extern int iUseTimer; -extern int iDebugMode; -extern int iRecordMode; -extern int iUseReverb; -extern int iUseInterpolation; -extern int iDisStereo; -extern int aSync; -// MISC - -extern SPUCHAN s_chan[]; -extern REVERBInfo rvb[]; - -extern unsigned long dwNoiseVal; -extern unsigned short spuCtrl2[]; -extern unsigned short spuStat2[]; -extern unsigned long spuIrq2[]; -extern unsigned long spuAddr2[]; -extern unsigned long spuRvbAddr2[]; -extern unsigned long spuRvbAEnd2[]; - -extern int bEndThread; -extern int bThreadEnded; -extern int bSpuInit; - -extern int SSumR[]; -extern int SSumL[]; -extern int iCycle; -extern short * pS; -extern unsigned long dwNewChannel2[]; -extern unsigned long dwEndChannel2[]; - -extern int iSpuAsyncWait; - -#ifdef _WINDOWS -extern HWND hWMain; // window handle -extern HWND hWDebug; -#endif - -extern void (CALLBACK *cddavCallback)(unsigned short,unsigned short); - -#endif - -/////////////////////////////////////////////////////////// -// DSOUND.C globals -/////////////////////////////////////////////////////////// - -#ifndef _IN_DSOUND - -#ifdef _WINDOWS -extern unsigned long LastWrite; -extern unsigned long LastPlay; -#endif - -#endif - -/////////////////////////////////////////////////////////// -// RECORD.C globals -/////////////////////////////////////////////////////////// - -#ifndef _IN_RECORD - -#ifdef _WINDOWS -extern int iDoRecord; -#endif - -#endif - -/////////////////////////////////////////////////////////// -// XA.C globals -/////////////////////////////////////////////////////////// - -#ifndef _IN_XA - -extern xa_decode_t * xapGlobal; - -extern unsigned long * XAFeed; -extern unsigned long * XAPlay; -extern unsigned long * XAStart; -extern unsigned long * XAEnd; - -extern unsigned long XARepeat; -extern unsigned long XALastVal; - -extern int iLeftXAVol; -extern int iRightXAVol; - -#endif - -/////////////////////////////////////////////////////////// -// REVERB.C globals -/////////////////////////////////////////////////////////// - -#ifndef _IN_REVERB - -extern int * sRVBPlay[]; -extern int * sRVBEnd[]; -extern int * sRVBStart[]; - -#endif +/*************************************************************************** + externals.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/04/04 - Pete +// - changed plugin to emulate PS2 spu +// +// 2002/04/04 - Pete +// - increased channel struct for interpolation +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + + +///////////////////////////////////////////////////////// +// generic defines +///////////////////////////////////////////////////////// + +//#define PSE_LT_SPU 4 +//#define PSE_SPU_ERR_SUCCESS 0 +//#define PSE_SPU_ERR -60 +//#define PSE_SPU_ERR_NOTCONFIGURED PSE_SPU_ERR - 1 +//#define PSE_SPU_ERR_INIT PSE_SPU_ERR - 2 + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +//////////////////////////////////////////////////////////////////////// +// spu defines +//////////////////////////////////////////////////////////////////////// + +// sound buffer sizes +// 500 ms complete sound buffer +#define SOUNDSIZE 76800 + +// 200 ms test buffer... if less than that is buffered, a new upload will happen +#define TESTSIZE 26304//13152 + +// num of channels +#define MAXCHAN 48 +#define HLFCHAN 24 + +// ~ 1 ms of data +#define NSSIZE 48 + +/////////////////////////////////////////////////////////// +// struct defines +/////////////////////////////////////////////////////////// +// ADMA Channels +extern EXPORT_GCC void CALLBACK SPU2async(unsigned long cycle); +typedef struct +{ + unsigned short * MemAddr; + unsigned short * TempMem; + unsigned int Index; + unsigned int AmountLeft; + unsigned int ADMAPos; + unsigned int TransferAmount; + int IRQ; + int TempAmount; +} ADMA; + +typedef struct +{ + int Left; + int Right; +} DINPUT; + +// ADSR INFOS PER CHANNEL +typedef struct +{ + int AttackModeExp; + long AttackTime; + long DecayTime; + long SustainLevel; + int SustainModeExp; + long SustainModeDec; + long SustainTime; + int ReleaseModeExp; + unsigned long ReleaseVal; + long ReleaseTime; + long ReleaseStartTime; + long ReleaseVol; + long lTime; + long lVolume; +} ADSRInfo; + +typedef struct +{ + int State; + int AttackModeExp; + int AttackRate; + int DecayRate; + int SustainLevel; + int SustainModeExp; + int SustainIncrease; + int SustainRate; + int ReleaseModeExp; + int ReleaseRate; + int EnvelopeVol; + long lVolume; + long lDummy1; + long lDummy2; +} ADSRInfoEx; + +/////////////////////////////////////////////////////////// + +// Tmp Flags + +// used for debug channel muting +#define FLAG_MUTE 1 + +// used for simple interpolation +#define FLAG_IPOL0 2 +#define FLAG_IPOL1 4 + +/////////////////////////////////////////////////////////// + +// MAIN CHANNEL STRUCT +typedef struct +{ + // no mutexes used anymore... don't need them to sync access + //HANDLE hMutex; + + int bNew; // start flag + + int iSBPos; // mixing stuff + int spos; + int sinc; + int SB[32+32]; // Pete added another 32 dwords in 1.6 ... prevents overflow issues with gaussian/cubic interpolation (thanx xodnizel!), and can be used for even better interpolations, eh? :) + int sval; + + unsigned char * pStart; // start ptr into sound mem + unsigned char * pCurr; // current pos in sound mem + unsigned char * pLoop; // loop ptr in sound mem + + int iStartAdr; + int iLoopAdr; + int iNextAdr; + + int bOn; // is channel active (sample playing?) + int bStop; // is channel stopped (sample _can_ still be playing, ADSR Release phase) + int bEndPoint; // end point reached + int bReverbL; // can we do reverb on this channel? must have ctrl register bit, to get active + int bReverbR; + + int bVolumeL; // Volume on/off + int bVolumeR; + + int iActFreq; // current psx pitch + int iUsedFreq; // current pc pitch + int iLeftVolume; // left volume + int iLeftVolRaw; // left psx volume value + int bIgnoreLoop; // ignore loop bit, if an external loop address is used + int iMute; // mute mode + int iRightVolume; // right volume + int iRightVolRaw; // right psx volume value + int iRawPitch; // raw pitch (0...3fff) + int iIrqDone; // debug irq done flag + int s_1; // last decoding infos + int s_2; + int bRVBActive; // reverb active flag + int bNoise; // noise active flag + int bFMod; // freq mod (0=off, 1=sound channel, 2=freq channel) + int iOldNoise; // old noise val for this channel + ADSRInfo ADSR; // active ADSR settings + ADSRInfoEx ADSRX; // next ADSR settings (will be moved to active on sample start) + +} SPUCHAN; + +/////////////////////////////////////////////////////////// + +typedef struct +{ + int StartAddr; // reverb area start addr in samples + int EndAddr; // reverb area end addr in samples + int CurrAddr; // reverb area curr addr in samples + + int VolLeft; + int VolRight; + int iLastRVBLeft; + int iLastRVBRight; + int iRVBLeft; + int iRVBRight; + int iCnt; + + int FB_SRC_A; // (offset) + int FB_SRC_B; // (offset) + int IIR_ALPHA; // (coef.) + int ACC_COEF_A; // (coef.) + int ACC_COEF_B; // (coef.) + int ACC_COEF_C; // (coef.) + int ACC_COEF_D; // (coef.) + int IIR_COEF; // (coef.) + int FB_ALPHA; // (coef.) + int FB_X; // (coef.) + int IIR_DEST_A0; // (offset) + int IIR_DEST_A1; // (offset) + int ACC_SRC_A0; // (offset) + int ACC_SRC_A1; // (offset) + int ACC_SRC_B0; // (offset) + int ACC_SRC_B1; // (offset) + int IIR_SRC_A0; // (offset) + int IIR_SRC_A1; // (offset) + int IIR_DEST_B0; // (offset) + int IIR_DEST_B1; // (offset) + int ACC_SRC_C0; // (offset) + int ACC_SRC_C1; // (offset) + int ACC_SRC_D0; // (offset) + int ACC_SRC_D1; // (offset) + int IIR_SRC_B1; // (offset) + int IIR_SRC_B0; // (offset) + int MIX_DEST_A0; // (offset) + int MIX_DEST_A1; // (offset) + int MIX_DEST_B0; // (offset) + int MIX_DEST_B1; // (offset) + int IN_COEF_L; // (coef.) + int IN_COEF_R; // (coef.) +} REVERBInfo; + +#ifdef _WINDOWS +extern HINSTANCE hInst; +#define WM_MUTE (WM_USER+543) +#endif + +/////////////////////////////////////////////////////////// +// SPU.C globals +/////////////////////////////////////////////////////////// + +#ifndef _IN_SPU + +// psx buffers / addresses + +extern unsigned short regArea[]; +extern unsigned short spuMem[]; +extern unsigned char * spuMemC; +extern unsigned char * pSpuIrq[]; +extern unsigned char * pSpuBuffer; + +// user settings + +extern int iUseXA; +extern int iVolume; +extern int iXAPitch; +extern int iUseTimer; +extern int iDebugMode; +extern int iRecordMode; +extern int iUseReverb; +extern int iUseInterpolation; +extern int iDisStereo; +extern int aSync; +// MISC + +extern SPUCHAN s_chan[]; +extern REVERBInfo rvb[]; + +extern unsigned long dwNoiseVal; +extern unsigned short spuCtrl2[]; +extern unsigned short spuStat2[]; +extern unsigned long spuIrq2[]; +extern unsigned long spuAddr2[]; +extern unsigned long spuRvbAddr2[]; +extern unsigned long spuRvbAEnd2[]; + +extern int bEndThread; +extern int bThreadEnded; +extern int bSpuInit; + +extern int SSumR[]; +extern int SSumL[]; +extern int iCycle; +extern short * pS; +extern unsigned long dwNewChannel2[]; +extern unsigned long dwEndChannel2[]; + +extern int iSpuAsyncWait; + +#ifdef _WINDOWS +extern HWND hWMain; // window handle +extern HWND hWDebug; +#endif + +extern void (CALLBACK *cddavCallback)(unsigned short,unsigned short); + +#endif + +/////////////////////////////////////////////////////////// +// DSOUND.C globals +/////////////////////////////////////////////////////////// + +#ifndef _IN_DSOUND + +#ifdef _WINDOWS +extern unsigned long LastWrite; +extern unsigned long LastPlay; +#endif + +#endif + +/////////////////////////////////////////////////////////// +// RECORD.C globals +/////////////////////////////////////////////////////////// + +#ifndef _IN_RECORD + +#ifdef _WINDOWS +extern int iDoRecord; +#endif + +#endif + +/////////////////////////////////////////////////////////// +// XA.C globals +/////////////////////////////////////////////////////////// + +#ifndef _IN_XA + +extern xa_decode_t * xapGlobal; + +extern unsigned long * XAFeed; +extern unsigned long * XAPlay; +extern unsigned long * XAStart; +extern unsigned long * XAEnd; + +extern unsigned long XARepeat; +extern unsigned long XALastVal; + +extern int iLeftXAVol; +extern int iRightXAVol; + +#endif + +/////////////////////////////////////////////////////////// +// REVERB.C globals +/////////////////////////////////////////////////////////// + +#ifndef _IN_REVERB + +extern int * sRVBPlay[]; +extern int * sRVBEnd[]; +extern int * sRVBStart[]; + +#endif diff --git a/plugins/PeopsSPU2/freeze.c b/plugins/PeopsSPU2/freeze.c index d7459449d6..5496a96d05 100644 --- a/plugins/PeopsSPU2/freeze.c +++ b/plugins/PeopsSPU2/freeze.c @@ -1,246 +1,246 @@ -/*************************************************************************** - freeze.c - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2004/12/24 - Pete -// - freeze functions adapted to pcsx2-0.7 -// -// 2004/04/04 - Pete -// - changed plugin to emulate PS2 spu -// -// 2003/03/20 - Pete -// - fix to prevent the new interpolations from crashing when loading a save state -// -// 2003/01/06 - Pete -// - small changes for version 1.3 adsr save state loading -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -#include "stdafx.h" - -#define _IN_FREEZE - -#include "externals.h" -#include "registers.h" -#include "spu.h" -#include "regs.h" -#include "debug.h" -#include "resource.h" - -//////////////////////////////////////////////////////////////////////// -// freeze structs -//////////////////////////////////////////////////////////////////////// - -typedef struct { - int size; - char *data; -} SPUFreeze_t; - -typedef struct -{ - char szSPUName[8]; - unsigned long ulFreezeVersion; - unsigned long ulFreezeSize; - unsigned char cSPUPort[64*1024]; - unsigned char cSPURam[2*1024*1024]; -} SPUFreeze_Ex_t; - -typedef struct -{ - unsigned long spuIrq0; - unsigned long spuIrq1; - unsigned long pSpuIrq0; - unsigned long pSpuIrq1; - unsigned long dummy0; - unsigned long dummy1; - unsigned long dummy2; - unsigned long dummy3; - - SPUCHAN s_chan[MAXCHAN]; - -} SPUOSSFreeze_t; - -//////////////////////////////////////////////////////////////////////// - -void LoadStateV1(SPUFreeze_Ex_t * pF); // newest version -void LoadStateUnknown(SPUFreeze_Ex_t * pF); // unknown format - -//////////////////////////////////////////////////////////////////////// -// SPUFREEZE: called by main emu on savestate load/save -//////////////////////////////////////////////////////////////////////// - -EXPORT_GCC long CALLBACK SPU2freeze(unsigned long ulFreezeMode,SPUFreeze_t * pFt) -{ - int i;SPUOSSFreeze_t * pFO;SPUFreeze_Ex_t * pF; - - if(!pFt) return 0; // first check - - if(ulFreezeMode) // save? - {//--------------------------------------------------// - pFt->size=sizeof(SPUFreeze_Ex_t)+sizeof(SPUOSSFreeze_t); - - if(ulFreezeMode==2) return 0; // emu just asking for size? bye - - if(!pFt->data) return 0; - - pF=(SPUFreeze_Ex_t *)pFt->data; - - memset(pF,0,pFt->size); - - strcpy(pF->szSPUName,"PBOSS2"); - pF->ulFreezeVersion=1; - pF->ulFreezeSize=pFt->size; - // save mode: - RemoveTimer(); // stop timer - - memcpy(pF->cSPURam,spuMem,2*1024*1024); // copy common infos - memcpy(pF->cSPUPort,regArea,64*1024); - - pFO=(SPUOSSFreeze_t *)(pF+1); // store special stuff - - pFO->spuIrq0=spuIrq2[0]; - if(pSpuIrq[0]) pFO->pSpuIrq0 = (unsigned long)pSpuIrq[0]-(unsigned long)spuMemC; - pFO->spuIrq1=spuIrq2[1]; - if(pSpuIrq[1]) pFO->pSpuIrq1 = (unsigned long)pSpuIrq[1]-(unsigned long)spuMemC; - - for(i=0;is_chan[i],(void *)&s_chan[i],sizeof(SPUCHAN)); - if(pFO->s_chan[i].pStart) - pFO->s_chan[i].pStart-=(unsigned long)spuMemC; - if(pFO->s_chan[i].pCurr) - pFO->s_chan[i].pCurr-=(unsigned long)spuMemC; - if(pFO->s_chan[i].pLoop) - pFO->s_chan[i].pLoop-=(unsigned long)spuMemC; - } - - SetupTimer(); // sound processing on again - - return 1; - //--------------------------------------------------// - } - - // load state: -#ifdef _WINDOWS - if(iDebugMode==1 && IsWindow(hWDebug)) // we have to disbale the debug window, if active - DestroyWindow(hWDebug); - hWDebug=0; - - if(IsBadReadPtr(pFt,sizeof(SPUFreeze_t))) // check bad emu stuff - return 0; -#endif - - if(pFt->size!=sizeof(SPUFreeze_Ex_t)+ // not our stuff? bye - sizeof(SPUOSSFreeze_t)) return 0; - if(!pFt->data) return 0; - - pF=(SPUFreeze_Ex_t *)pFt->data; - - RemoveTimer(); // we stop processing while doing the save! - - memcpy(spuMem,pF->cSPURam,2*1024*1024); // get ram - memcpy(regArea,pF->cSPUPort,64*1024); - - if(!strcmp(pF->szSPUName,"PBOSS2") && - pF->ulFreezeVersion==1) - LoadStateV1(pF); - else LoadStateUnknown(pF); - - // repair some globals - for(i=0x7FFE;i>=0x0000;i-=2) - { - SPU2write(i,regArea[i]); - } - - // fix to prevent new interpolations from crashing - for(i=0;ispuIrq0; - if(pFO->pSpuIrq0) pSpuIrq[0] = pFO->pSpuIrq0+spuMemC; else pSpuIrq[0]=0; - spuIrq2[1] = pFO->spuIrq1; - if(pFO->pSpuIrq1) pSpuIrq[1] = pFO->pSpuIrq1+spuMemC; else pSpuIrq[1]=0; - - for(i=0;is_chan[i],sizeof(SPUCHAN)); - - s_chan[i].pStart+=(unsigned long)spuMemC; - s_chan[i].pCurr+=(unsigned long)spuMemC; - s_chan[i].pLoop+=(unsigned long)spuMemC; - s_chan[i].iMute=0; - s_chan[i].iIrqDone=0; - } -} - -//////////////////////////////////////////////////////////////////////// - -void LoadStateUnknown(SPUFreeze_Ex_t * pF) -{ - int i; - - for(i=0;isize=sizeof(SPUFreeze_Ex_t)+sizeof(SPUOSSFreeze_t); + + if(ulFreezeMode==2) return 0; // emu just asking for size? bye + + if(!pFt->data) return 0; + + pF=(SPUFreeze_Ex_t *)pFt->data; + + memset(pF,0,pFt->size); + + strcpy(pF->szSPUName,"PBOSS2"); + pF->ulFreezeVersion=1; + pF->ulFreezeSize=pFt->size; + // save mode: + RemoveTimer(); // stop timer + + memcpy(pF->cSPURam,spuMem,2*1024*1024); // copy common infos + memcpy(pF->cSPUPort,regArea,64*1024); + + pFO=(SPUOSSFreeze_t *)(pF+1); // store special stuff + + pFO->spuIrq0=spuIrq2[0]; + if(pSpuIrq[0]) pFO->pSpuIrq0 = (unsigned long)pSpuIrq[0]-(unsigned long)spuMemC; + pFO->spuIrq1=spuIrq2[1]; + if(pSpuIrq[1]) pFO->pSpuIrq1 = (unsigned long)pSpuIrq[1]-(unsigned long)spuMemC; + + for(i=0;is_chan[i],(void *)&s_chan[i],sizeof(SPUCHAN)); + if(pFO->s_chan[i].pStart) + pFO->s_chan[i].pStart-=(unsigned long)spuMemC; + if(pFO->s_chan[i].pCurr) + pFO->s_chan[i].pCurr-=(unsigned long)spuMemC; + if(pFO->s_chan[i].pLoop) + pFO->s_chan[i].pLoop-=(unsigned long)spuMemC; + } + + SetupTimer(); // sound processing on again + + return 1; + //--------------------------------------------------// + } + + // load state: +#ifdef _WINDOWS + if(iDebugMode==1 && IsWindow(hWDebug)) // we have to disbale the debug window, if active + DestroyWindow(hWDebug); + hWDebug=0; + + if(IsBadReadPtr(pFt,sizeof(SPUFreeze_t))) // check bad emu stuff + return 0; +#endif + + if(pFt->size!=sizeof(SPUFreeze_Ex_t)+ // not our stuff? bye + sizeof(SPUOSSFreeze_t)) return 0; + if(!pFt->data) return 0; + + pF=(SPUFreeze_Ex_t *)pFt->data; + + RemoveTimer(); // we stop processing while doing the save! + + memcpy(spuMem,pF->cSPURam,2*1024*1024); // get ram + memcpy(regArea,pF->cSPUPort,64*1024); + + if(!strcmp(pF->szSPUName,"PBOSS2") && + pF->ulFreezeVersion==1) + LoadStateV1(pF); + else LoadStateUnknown(pF); + + // repair some globals + for(i=0x7FFE;i>=0x0000;i-=2) + { + SPU2write(i,regArea[i]); + } + + // fix to prevent new interpolations from crashing + for(i=0;ispuIrq0; + if(pFO->pSpuIrq0) pSpuIrq[0] = pFO->pSpuIrq0+spuMemC; else pSpuIrq[0]=0; + spuIrq2[1] = pFO->spuIrq1; + if(pFO->pSpuIrq1) pSpuIrq[1] = pFO->pSpuIrq1+spuMemC; else pSpuIrq[1]=0; + + for(i=0;is_chan[i],sizeof(SPUCHAN)); + + s_chan[i].pStart+=(unsigned long)spuMemC; + s_chan[i].pCurr+=(unsigned long)spuMemC; + s_chan[i].pLoop+=(unsigned long)spuMemC; + s_chan[i].iMute=0; + s_chan[i].iIrqDone=0; + } +} + +//////////////////////////////////////////////////////////////////////// + +void LoadStateUnknown(SPUFreeze_Ex_t * pF) +{ + int i; + + for(i=0;i -#define IDC_STATIC -1 +#include +#define IDC_STATIC -1 diff --git a/plugins/PeopsSPU2/oss.c b/plugins/PeopsSPU2/oss.c index e8360ac17e..8f83363e29 100644 --- a/plugins/PeopsSPU2/oss.c +++ b/plugins/PeopsSPU2/oss.c @@ -1,190 +1,190 @@ -/*************************************************************************** - oss.c - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2005/08/29 - Pete -// - changed to 48Khz output -// -// 2003/03/01 - linuzappz -// - added checkings for oss_audio_fd == -1 -// -// 2003/02/08 - linuzappz -// - added iDisStereo stuff -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -#include "stdafx.h" - -#define _IN_OSS - -#include "externals.h" - -#ifndef _WIN32 - -//////////////////////////////////////////////////////////////////////// -// small linux time helper... only used for watchdog -//////////////////////////////////////////////////////////////////////// -#include - -extern unsigned int timeGetTime() -{ - struct timeb t; - ftime(&t); - return (unsigned int)(t.time*1000+t.millitm); -} - -//////////////////////////////////////////////////////////////////////// -// oss globals -//////////////////////////////////////////////////////////////////////// - -#define OSS_MEM_DEF -#include "oss.h" -static int oss_audio_fd = -1; -extern int errno; - -//////////////////////////////////////////////////////////////////////// -// SETUP SOUND -//////////////////////////////////////////////////////////////////////// - -void SetupSound(void) -{ - int pspeed=48000; - int pstereo; - int format; - int fragsize = 0; - int myfrag; - int oss_speed, oss_stereo; - - if(iDisStereo) pstereo=OSS_MODE_MONO; - else pstereo=OSS_MODE_STEREO; - - oss_speed = pspeed; - oss_stereo = pstereo; - - if((oss_audio_fd=open("/dev/dsp",O_WRONLY,0))==-1) - { - printf("Sound device not available!\n"); - return; - } - - if(ioctl(oss_audio_fd,SNDCTL_DSP_RESET,0)==-1) - { - printf("Sound reset failed\n"); - return; - } - - // we use 64 fragments with 1024 bytes each - - fragsize=10; - myfrag=(63<<16)|fragsize; - - if(ioctl(oss_audio_fd,SNDCTL_DSP_SETFRAGMENT,&myfrag)==-1) - { - printf("Sound set fragment failed!\n"); - return; - } - - format = AFMT_S16_LE; - - if(ioctl(oss_audio_fd,SNDCTL_DSP_SETFMT,&format) == -1) - { - printf("Sound format not supported!\n"); - return; - } - - if(format!=AFMT_S16_LE) - { - printf("Sound format not supported!\n"); - return; - } - - if(ioctl(oss_audio_fd,SNDCTL_DSP_STEREO,&oss_stereo)==-1) - { - printf("Stereo mode not supported!\n"); - return; - } - - if(oss_stereo!=1) - { - iDisStereo=1; - } - - if(ioctl(oss_audio_fd,SNDCTL_DSP_SPEED,&oss_speed)==-1) - { - printf("Sound frequency not supported\n"); - return; - } - - if(oss_speed!=pspeed) - { - printf("Sound frequency not supported\n"); - return; - } -} - -//////////////////////////////////////////////////////////////////////// -// REMOVE SOUND -//////////////////////////////////////////////////////////////////////// - -void RemoveSound(void) -{ - if(oss_audio_fd != -1 ) - { - close(oss_audio_fd); - oss_audio_fd = -1; - } -} - -//////////////////////////////////////////////////////////////////////// -// GET BYTES BUFFERED -//////////////////////////////////////////////////////////////////////// - -unsigned long SoundGetBytesBuffered(void) -{ - audio_buf_info info; - unsigned long l; - - if(oss_audio_fd == -1) return SOUNDSIZE; - if(ioctl(oss_audio_fd,SNDCTL_DSP_GETOSPACE,&info)==-1) - l=0; - else - { - if(info.fragments<(info.fragstotal>>1)) // can we write in at least the half of fragments? - l=SOUNDSIZE; // -> no? wait - else l=0; // -> else go on - } - - return l; -} - -//////////////////////////////////////////////////////////////////////// -// FEED SOUND DATA -//////////////////////////////////////////////////////////////////////// - -void SoundFeedVoiceData(unsigned char* pSound,long lBytes) -{ - if(oss_audio_fd == -1) return; - write(oss_audio_fd,pSound,lBytes); -} - -#endif +/*************************************************************************** + oss.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2005/08/29 - Pete +// - changed to 48Khz output +// +// 2003/03/01 - linuzappz +// - added checkings for oss_audio_fd == -1 +// +// 2003/02/08 - linuzappz +// - added iDisStereo stuff +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_OSS + +#include "externals.h" + +#ifndef _WIN32 + +//////////////////////////////////////////////////////////////////////// +// small linux time helper... only used for watchdog +//////////////////////////////////////////////////////////////////////// +#include + +extern unsigned int timeGetTime() +{ + struct timeb t; + ftime(&t); + return (unsigned int)(t.time*1000+t.millitm); +} + +//////////////////////////////////////////////////////////////////////// +// oss globals +//////////////////////////////////////////////////////////////////////// + +#define OSS_MEM_DEF +#include "oss.h" +static int oss_audio_fd = -1; +extern int errno; + +//////////////////////////////////////////////////////////////////////// +// SETUP SOUND +//////////////////////////////////////////////////////////////////////// + +void SetupSound(void) +{ + int pspeed=48000; + int pstereo; + int format; + int fragsize = 0; + int myfrag; + int oss_speed, oss_stereo; + + if(iDisStereo) pstereo=OSS_MODE_MONO; + else pstereo=OSS_MODE_STEREO; + + oss_speed = pspeed; + oss_stereo = pstereo; + + if((oss_audio_fd=open("/dev/dsp",O_WRONLY,0))==-1) + { + printf("Sound device not available!\n"); + return; + } + + if(ioctl(oss_audio_fd,SNDCTL_DSP_RESET,0)==-1) + { + printf("Sound reset failed\n"); + return; + } + + // we use 64 fragments with 1024 bytes each + + fragsize=10; + myfrag=(63<<16)|fragsize; + + if(ioctl(oss_audio_fd,SNDCTL_DSP_SETFRAGMENT,&myfrag)==-1) + { + printf("Sound set fragment failed!\n"); + return; + } + + format = AFMT_S16_LE; + + if(ioctl(oss_audio_fd,SNDCTL_DSP_SETFMT,&format) == -1) + { + printf("Sound format not supported!\n"); + return; + } + + if(format!=AFMT_S16_LE) + { + printf("Sound format not supported!\n"); + return; + } + + if(ioctl(oss_audio_fd,SNDCTL_DSP_STEREO,&oss_stereo)==-1) + { + printf("Stereo mode not supported!\n"); + return; + } + + if(oss_stereo!=1) + { + iDisStereo=1; + } + + if(ioctl(oss_audio_fd,SNDCTL_DSP_SPEED,&oss_speed)==-1) + { + printf("Sound frequency not supported\n"); + return; + } + + if(oss_speed!=pspeed) + { + printf("Sound frequency not supported\n"); + return; + } +} + +//////////////////////////////////////////////////////////////////////// +// REMOVE SOUND +//////////////////////////////////////////////////////////////////////// + +void RemoveSound(void) +{ + if(oss_audio_fd != -1 ) + { + close(oss_audio_fd); + oss_audio_fd = -1; + } +} + +//////////////////////////////////////////////////////////////////////// +// GET BYTES BUFFERED +//////////////////////////////////////////////////////////////////////// + +unsigned long SoundGetBytesBuffered(void) +{ + audio_buf_info info; + unsigned long l; + + if(oss_audio_fd == -1) return SOUNDSIZE; + if(ioctl(oss_audio_fd,SNDCTL_DSP_GETOSPACE,&info)==-1) + l=0; + else + { + if(info.fragments<(info.fragstotal>>1)) // can we write in at least the half of fragments? + l=SOUNDSIZE; // -> no? wait + else l=0; // -> else go on + } + + return l; +} + +//////////////////////////////////////////////////////////////////////// +// FEED SOUND DATA +//////////////////////////////////////////////////////////////////////// + +void SoundFeedVoiceData(unsigned char* pSound,long lBytes) +{ + if(oss_audio_fd == -1) return; + write(oss_audio_fd,pSound,lBytes); +} + +#endif diff --git a/plugins/PeopsSPU2/psemuxa.h b/plugins/PeopsSPU2/psemuxa.h index 84c626043f..11482750e1 100644 --- a/plugins/PeopsSPU2/psemuxa.h +++ b/plugins/PeopsSPU2/psemuxa.h @@ -1,28 +1,28 @@ -//============================================ -//=== Audio XA decoding -//=== Kazzuya -//============================================ - -#ifndef DECODEXA_H -#define DECODEXA_H - -typedef struct -{ - long y0, y1; -} ADPCM_Decode_t; - -typedef struct -{ - int freq; - int nbits; - int stereo; - int nsamples; - ADPCM_Decode_t left, right; - short pcm[16384]; -} xa_decode_t; - -long xa_decode_sector( xa_decode_t *xdp, - unsigned char *sectorp, - int is_first_sector ); - -#endif +//============================================ +//=== Audio XA decoding +//=== Kazzuya +//============================================ + +#ifndef DECODEXA_H +#define DECODEXA_H + +typedef struct +{ + long y0, y1; +} ADPCM_Decode_t; + +typedef struct +{ + int freq; + int nbits; + int stereo; + int nsamples; + ADPCM_Decode_t left, right; + short pcm[16384]; +} xa_decode_t; + +long xa_decode_sector( xa_decode_t *xdp, + unsigned char *sectorp, + int is_first_sector ); + +#endif diff --git a/plugins/PeopsSPU2/record.c b/plugins/PeopsSPU2/record.c index 2206d388c1..b256224cb7 100644 --- a/plugins/PeopsSPU2/record.c +++ b/plugins/PeopsSPU2/record.c @@ -1,184 +1,184 @@ -/*************************************************************************** - spu.c - description - ------------------- - begin : Sun Jan 12 2003 - copyright : (C) 2003 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2005/08/29 - Pete -// - changed to 48Khz output -// -// 2003/03/01 - Pete -// - added mono mode -// -// 2003/01/12 - Pete -// - added recording funcs (win version only) -// -//*************************************************************************// - -#include "stdafx.h" - -#ifdef _WINDOWS - -#include -#include "resource.h" -#include "externals.h" - -#define _IN_RECORD - -#include "record.h" - -//////////////////////////////////////////////////////////////////////// - -int iDoRecord=0; -HMMIO hWaveFile=NULL; -MMCKINFO mmckMain; -MMCKINFO mmckData; -char szFileName[256]={"C:\\PEOPS.WAV"}; - -//////////////////////////////////////////////////////////////////////// - -void RecordStart() -{ - WAVEFORMATEX pcmwf; - - // setup header in the same format as our directsound stream - memset(&pcmwf,0,sizeof(WAVEFORMATEX)); - pcmwf.wFormatTag = WAVE_FORMAT_PCM; - - pcmwf.nChannels = 2; - pcmwf.nBlockAlign = 4; - - pcmwf.nSamplesPerSec = 48000; - pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign; - pcmwf.wBitsPerSample = 16; - - // create file - hWaveFile=mmioOpen(szFileName,NULL,MMIO_CREATE|MMIO_WRITE|MMIO_EXCLUSIVE | MMIO_ALLOCBUF); - if(!hWaveFile) return; - - // setup WAVE, fmt and data chunks - memset(&mmckMain,0,sizeof(MMCKINFO)); - mmckMain.fccType = mmioFOURCC('W','A','V','E'); - - mmioCreateChunk(hWaveFile,&mmckMain,MMIO_CREATERIFF); - - memset(&mmckData,0,sizeof(MMCKINFO)); - mmckData.ckid = mmioFOURCC('f','m','t',' '); - mmckData.cksize = sizeof(WAVEFORMATEX); - - mmioCreateChunk(hWaveFile,&mmckData,0); - mmioWrite(hWaveFile,(char*)&pcmwf,sizeof(WAVEFORMATEX)); - mmioAscend(hWaveFile,&mmckData,0); - - mmckData.ckid = mmioFOURCC('d','a','t','a'); - mmioCreateChunk(hWaveFile,&mmckData,0); -} - -//////////////////////////////////////////////////////////////////////// - -void RecordStop() -{ - // first some check, if recording is running - iDoRecord=0; - if(!hWaveFile) return; - - // now finish writing & close the wave file - mmioAscend(hWaveFile,&mmckData,0); - mmioAscend(hWaveFile,&mmckMain,0); - mmioClose(hWaveFile,0); - - // init var - hWaveFile=NULL; -} - -//////////////////////////////////////////////////////////////////////// - -void RecordBuffer(unsigned char* pSound,long lBytes) -{ - // write the samples - if(hWaveFile) mmioWrite(hWaveFile,pSound,lBytes); -} - -//////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////// - -BOOL CALLBACK RecordDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch(uMsg) - { - //--------------------------------------------------// init - case WM_INITDIALOG: - { - SetDlgItemText(hW,IDC_WAVFILE,szFileName); // init filename edit - ShowCursor(TRUE); // mmm... who is hiding it? main emu? tsts - return TRUE; - } - //--------------------------------------------------// destroy - case WM_DESTROY: - { - RecordStop(); - }break; - //--------------------------------------------------// command - case WM_COMMAND: - { - if(wParam==IDCANCEL) iRecordMode=2; // cancel? raise flag for destroying the dialog - - if(wParam==IDC_RECORD) // record start/stop? - { - if(IsWindowEnabled(GetDlgItem(hW,IDC_WAVFILE))) // not started yet (edit is not disabled): - { - GetDlgItemText(hW,IDC_WAVFILE,szFileName,255);// get filename - - RecordStart(); // start recording - - if(hWaveFile) // start was ok? - { // -> disable filename edit, change text, raise flag - EnableWindow(GetDlgItem(hW,IDC_WAVFILE),FALSE); - SetDlgItemText(hW,IDC_RECORD,"Stop recording"); - iDoRecord=1; - } - else MessageBeep(0xFFFFFFFF); // error starting recording? BEEP - } - else // stop recording? - { - RecordStop(); // -> just do it - EnableWindow(GetDlgItem(hW,IDC_WAVFILE),TRUE);// -> enable filename edit again - SetDlgItemText(hW,IDC_RECORD,"Start recording"); - } - SetFocus(hWMain); - } - - }break; - //--------------------------------------------------// size - case WM_SIZE: - if(wParam==SIZE_MINIMIZED) SetFocus(hWMain); // if we get minimized, set the foxus to the main window - break; - //--------------------------------------------------// setcursor - case WM_SETCURSOR: - { - SetCursor(LoadCursor(NULL,IDC_ARROW)); // force the arrow - return TRUE; - } - //--------------------------------------------------// - } - return FALSE; -} - -//////////////////////////////////////////////////////////////////////// -#endif +/*************************************************************************** + spu.c - description + ------------------- + begin : Sun Jan 12 2003 + copyright : (C) 2003 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2005/08/29 - Pete +// - changed to 48Khz output +// +// 2003/03/01 - Pete +// - added mono mode +// +// 2003/01/12 - Pete +// - added recording funcs (win version only) +// +//*************************************************************************// + +#include "stdafx.h" + +#ifdef _WINDOWS + +#include +#include "resource.h" +#include "externals.h" + +#define _IN_RECORD + +#include "record.h" + +//////////////////////////////////////////////////////////////////////// + +int iDoRecord=0; +HMMIO hWaveFile=NULL; +MMCKINFO mmckMain; +MMCKINFO mmckData; +char szFileName[256]={"C:\\PEOPS.WAV"}; + +//////////////////////////////////////////////////////////////////////// + +void RecordStart() +{ + WAVEFORMATEX pcmwf; + + // setup header in the same format as our directsound stream + memset(&pcmwf,0,sizeof(WAVEFORMATEX)); + pcmwf.wFormatTag = WAVE_FORMAT_PCM; + + pcmwf.nChannels = 2; + pcmwf.nBlockAlign = 4; + + pcmwf.nSamplesPerSec = 48000; + pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign; + pcmwf.wBitsPerSample = 16; + + // create file + hWaveFile=mmioOpen(szFileName,NULL,MMIO_CREATE|MMIO_WRITE|MMIO_EXCLUSIVE | MMIO_ALLOCBUF); + if(!hWaveFile) return; + + // setup WAVE, fmt and data chunks + memset(&mmckMain,0,sizeof(MMCKINFO)); + mmckMain.fccType = mmioFOURCC('W','A','V','E'); + + mmioCreateChunk(hWaveFile,&mmckMain,MMIO_CREATERIFF); + + memset(&mmckData,0,sizeof(MMCKINFO)); + mmckData.ckid = mmioFOURCC('f','m','t',' '); + mmckData.cksize = sizeof(WAVEFORMATEX); + + mmioCreateChunk(hWaveFile,&mmckData,0); + mmioWrite(hWaveFile,(char*)&pcmwf,sizeof(WAVEFORMATEX)); + mmioAscend(hWaveFile,&mmckData,0); + + mmckData.ckid = mmioFOURCC('d','a','t','a'); + mmioCreateChunk(hWaveFile,&mmckData,0); +} + +//////////////////////////////////////////////////////////////////////// + +void RecordStop() +{ + // first some check, if recording is running + iDoRecord=0; + if(!hWaveFile) return; + + // now finish writing & close the wave file + mmioAscend(hWaveFile,&mmckData,0); + mmioAscend(hWaveFile,&mmckMain,0); + mmioClose(hWaveFile,0); + + // init var + hWaveFile=NULL; +} + +//////////////////////////////////////////////////////////////////////// + +void RecordBuffer(unsigned char* pSound,long lBytes) +{ + // write the samples + if(hWaveFile) mmioWrite(hWaveFile,pSound,lBytes); +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +BOOL CALLBACK RecordDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + //--------------------------------------------------// init + case WM_INITDIALOG: + { + SetDlgItemText(hW,IDC_WAVFILE,szFileName); // init filename edit + ShowCursor(TRUE); // mmm... who is hiding it? main emu? tsts + return TRUE; + } + //--------------------------------------------------// destroy + case WM_DESTROY: + { + RecordStop(); + }break; + //--------------------------------------------------// command + case WM_COMMAND: + { + if(wParam==IDCANCEL) iRecordMode=2; // cancel? raise flag for destroying the dialog + + if(wParam==IDC_RECORD) // record start/stop? + { + if(IsWindowEnabled(GetDlgItem(hW,IDC_WAVFILE))) // not started yet (edit is not disabled): + { + GetDlgItemText(hW,IDC_WAVFILE,szFileName,255);// get filename + + RecordStart(); // start recording + + if(hWaveFile) // start was ok? + { // -> disable filename edit, change text, raise flag + EnableWindow(GetDlgItem(hW,IDC_WAVFILE),FALSE); + SetDlgItemText(hW,IDC_RECORD,"Stop recording"); + iDoRecord=1; + } + else MessageBeep(0xFFFFFFFF); // error starting recording? BEEP + } + else // stop recording? + { + RecordStop(); // -> just do it + EnableWindow(GetDlgItem(hW,IDC_WAVFILE),TRUE);// -> enable filename edit again + SetDlgItemText(hW,IDC_RECORD,"Start recording"); + } + SetFocus(hWMain); + } + + }break; + //--------------------------------------------------// size + case WM_SIZE: + if(wParam==SIZE_MINIMIZED) SetFocus(hWMain); // if we get minimized, set the foxus to the main window + break; + //--------------------------------------------------// setcursor + case WM_SETCURSOR: + { + SetCursor(LoadCursor(NULL,IDC_ARROW)); // force the arrow + return TRUE; + } + //--------------------------------------------------// + } + return FALSE; +} + +//////////////////////////////////////////////////////////////////////// +#endif diff --git a/plugins/PeopsSPU2/record.h b/plugins/PeopsSPU2/record.h index 24fd34cd4f..e0350f15bd 100644 --- a/plugins/PeopsSPU2/record.h +++ b/plugins/PeopsSPU2/record.h @@ -1,12 +1,12 @@ -#ifndef _RECORD_H_ -#define _RECORD_H_ - -#ifdef _WINDOWS -void RecordStart(); -void RecordBuffer(unsigned char* pSound,long lBytes); -void RecordStop(); -BOOL CALLBACK RecordDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); -#endif - -#endif - +#ifndef _RECORD_H_ +#define _RECORD_H_ + +#ifdef _WINDOWS +void RecordStart(); +void RecordBuffer(unsigned char* pSound,long lBytes); +void RecordStop(); +BOOL CALLBACK RecordDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); +#endif + +#endif + diff --git a/plugins/PeopsSPU2/registers.c b/plugins/PeopsSPU2/registers.c index cf4cae09f3..5f86a73475 100644 --- a/plugins/PeopsSPU2/registers.c +++ b/plugins/PeopsSPU2/registers.c @@ -1,2095 +1,2095 @@ -/*************************************************************************** - registers.c - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2004/04/04 - Pete -// - changed plugin to emulate PS2 spu -// -// 2003/02/09 - kode54 -// - removed &0x3fff from reverb volume registers, fixes a few games, -// hopefully won't be breaking anything -// -// 2003/01/19 - Pete -// - added Neill's reverb -// -// 2003/01/06 - Pete -// - added Neill's ADSR timings -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -#include "stdafx.h" - -#define _IN_REGISTERS - -#include "externals.h" -#include "registers.h" -#include "regs.h" -#include "reverb.h" -#include "debug.h" - -int MMIXC0 = 0, MMIXC1 = 0; -/* -// adsr time values (in ms) by James Higgs ... see the end of -// the adsr.c source for details - -#define ATTACK_MS 514L -#define DECAYHALF_MS 292L -#define DECAY_MS 584L -#define SUSTAIN_MS 450L -#define RELEASE_MS 446L -*/ - -// we have a timebase of 1.020408f ms, not 1 ms... so adjust adsr defines -#define ATTACK_MS 494L -#define DECAYHALF_MS 286L -#define DECAY_MS 572L -#define SUSTAIN_MS 441L -#define RELEASE_MS 437L - -extern void (CALLBACK *irqCallbackSPU2)(); // func of main emu, called on spu irq - - -//////////////////////////////////////////////////////////////////////// -// WRITE REGISTERS: called by main emu -//////////////////////////////////////////////////////////////////////// - -EXPORT_GCC void CALLBACK SPU2write(unsigned long reg, unsigned short val) -{ - long r=reg&0xffff; - - - - regArea[r] = val; - - if(spuCtrl2[0]&0x40 && spuIrq2[0] == r){ - //regArea[0x7C0] |= 0x4; - regArea[PS2_IRQINFO] |= 4; - irqCallbackSPU2(); - } - if(spuCtrl2[1]&0x40 && spuIrq2[1] == r){ - //regArea[0x7C0] |= 0x8; - regArea[PS2_IRQINFO] |= 8; - irqCallbackSPU2(); - } - if((r>=0x0000 && r<0x0180)||(r>=0x0400 && r<0x0580)) // some channel info? - { - int rx=0; - int ch=0; - if(r>=0x400) { - rx= r - 0x400; - ch=(rx>>4)+24; - } else { - rx= r; - ch=(rx>>4); - } - - switch(rx&0x0f) - { - //------------------------------------------------// r volume - case 0: - SetVolumeL((unsigned char)ch,val); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG Volume Left - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); -#endif - break; - //------------------------------------------------// l volume - case 2: - SetVolumeR((unsigned char)ch,val); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG Volume Right - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); -#endif - break; - //------------------------------------------------// pitch - case 4: - SetPitch(ch,val); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG Pitch - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); -#endif - break; - //------------------------------------------------// level with pre-calcs - case 6: - { - const unsigned long lval=val;unsigned long lx; - //---------------------------------------------// - s_chan[ch].ADSRX.AttackModeExp=(lval&0x8000)?1:0; - s_chan[ch].ADSRX.AttackRate=(lval>>8) & 0x007f; - s_chan[ch].ADSRX.DecayRate=(lval>>4) & 0x000f; - s_chan[ch].ADSRX.SustainLevel=lval & 0x000f; - //---------------------------------------------// - if(!iDebugMode) break; - //---------------------------------------------// stuff below is only for debug mode - - s_chan[ch].ADSR.AttackModeExp=(lval&0x8000)?1:0; //0x007f - - lx=(((lval>>8) & 0x007f)>>2); // attack time to run from 0 to 100% volume - lx=min(31,lx); // no overflow on shift! - if(lx) - { - lx = (1<>4) & 0x000f; // decay: - if(lx) // our const decay value is time it takes from 100% to 0% of volume - { - lx = ((1<<(lx))*DECAY_MS)/10000L; - if(!lx) lx=1; - } - s_chan[ch].ADSR.DecayTime = // so calc how long does it take to run from 100% to the wanted sus level - (lx*(1024-s_chan[ch].ADSR.SustainLevel))/1024; - } -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG ADSR1 - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); -#endif - break; - //------------------------------------------------// adsr times with pre-calcs - case 8: - { - const unsigned long lval=val;unsigned long lx; - - //----------------------------------------------// - s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0; - s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1; - s_chan[ch].ADSRX.SustainRate = (lval>>6) & 0x007f; - s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0; - s_chan[ch].ADSRX.ReleaseRate = lval & 0x001f; - //----------------------------------------------// - if(!iDebugMode) break; - //----------------------------------------------// stuff below is only for debug mode - - s_chan[ch].ADSR.SustainModeExp = (lval&0x8000)?1:0; - s_chan[ch].ADSR.ReleaseModeExp = (lval&0x0020)?1:0; - - lx=((((lval>>6) & 0x007f)>>2)); // sustain time... often very high - lx=min(31,lx); // values are used to hold the volume - if(lx) // until a sound stop occurs - { // the highest value we reach (due to - lx = (1< 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); -#endif - break; - default: -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG Unknown Mixing reg - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); -#endif - break; - //------------------------------------------------// - } - - return; - } - - if((r>=0x01c0 && r<0x02E0)||(r>=0x05c0 && r<0x06E0)) // some channel info? - { - int ch=0;unsigned long rx=r; - - ch=((rx & 0x3ff)-0x1c0) / 0xC; - - rx-=ch*0xC; - if(rx>=0x400) {ch+=24;rx-=0x400;} - - switch(rx) - { - //------------------------------------------------// - case 0x1C0: - s_chan[ch].iStartAdr=(((unsigned long)val&0x3f)<<16)|(s_chan[ch].iStartAdr&0xFFFF); - s_chan[ch].pStart=spuMemC+(s_chan[ch].iStartAdr<<1); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG Start Addr Hi - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); -#endif - break; - case 0x1C2: - s_chan[ch].iStartAdr=(s_chan[ch].iStartAdr & 0x3f0000) | (val & 0xFFFF); - s_chan[ch].pStart=spuMemC+(s_chan[ch].iStartAdr<<1); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG Start Addr Lo - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); -#endif - break; - //------------------------------------------------// - case 0x1C4: - s_chan[ch].iLoopAdr=(((unsigned long)val&0x3f)<<16)|(s_chan[ch].iLoopAdr&0xFFFF); - s_chan[ch].pLoop=spuMemC+(s_chan[ch].iLoopAdr<<1); - if(s_chan[ch].iLoopAdr)s_chan[ch].bIgnoreLoop=1; - else s_chan[ch].bIgnoreLoop=0; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG Loop Addr Hi - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); -#endif - break; - case 0x1C6: - s_chan[ch].iLoopAdr=(s_chan[ch].iLoopAdr & 0x3f0000) | (val & 0xFFFF); - s_chan[ch].pLoop=spuMemC+(s_chan[ch].iLoopAdr<<1); - if(s_chan[ch].iLoopAdr)s_chan[ch].bIgnoreLoop=1; - else s_chan[ch].bIgnoreLoop=0; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG Loop Addr Lo - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); -#endif - break; - //------------------------------------------------// - case 0x1C8: - // unused... check if it gets written as well - s_chan[ch].iNextAdr=(((unsigned long)val&0x3f)<<16)|(s_chan[ch].iNextAdr&0xFFFF); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG Next Addr Hi - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); -#endif - break; - case 0x1CA: - // unused... check if it gets written as well - s_chan[ch].iNextAdr=(s_chan[ch].iNextAdr & 0x3f0000) | (val & 0xFFFF); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG Next Addr Lo - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); -#endif - break; - //------------------------------------------------// - } - - return; - } - - switch(r) - { - //-------------------------------------------------// - case PS2_C0_SPUaddr_Hi: - spuAddr2[0] = (((unsigned long)val&0x3f)<<16)|(spuAddr2[0]&0xFFFF); // 6bits -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG TSAH - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_SPUaddr_Lo: - spuAddr2[0] = (spuAddr2[0] & 0x3F0000) | (val & 0xFFFF); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG TSAL - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_SPUaddr_Hi: - spuAddr2[1] = (((unsigned long)val&0x3f)<<16)|(spuAddr2[1]&0xFFFF); // 6bits -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG TSAH - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_SPUaddr_Lo: - spuAddr2[1] = (spuAddr2[1] & 0x3F0000) | (val & 0xFFFF); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG TSAL - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_SPUdata: - spuMem[spuAddr2[0]] = val; - if(spuCtrl2[0]&0x40 && spuIrq2[0] == spuAddr2[0]){ - regArea[0x7C0] |= 0x4; - regArea[PS2_IRQINFO] |= 4; - irqCallbackSPU2(); - } - spuAddr2[0]++; - if(spuAddr2[0]>0xFFFFF) spuAddr2[0] = 0; - spuStat2[0]|=0x80; - spuCtrl2[0]&=~0x30; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG SPU Data - Core 0 Addr %X Val %X\r\n", spuAddr2[0]-1, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_SPUdata: - spuMem[spuAddr2[1]] = val; - - if(spuCtrl2[1]&0x40 && spuIrq2[1] == spuAddr2[1]){ - regArea[0x7C0] |= 0x8; - regArea[PS2_IRQINFO] |= 8; - irqCallbackSPU2(); - } - spuAddr2[1]++; - if(spuAddr2[1]>0xFFFFF) spuAddr2[1] = 0; - spuStat2[1]|=0x80; - spuCtrl2[1]&=~0x30; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG SPU Data - Core 1 Addr %X Val %X\r\n", spuAddr2[1]-1, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_ATTR: - spuCtrl2[0]=val; - if(!(val & 0x40))regArea[PS2_IRQINFO] &= ~0x4; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG ATTR - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_ADMAS: - regArea[(PS2_C0_ADMAS)]=val; - ///regArea[(0x344)>>1]&= ~0x80; - //regArea[(0x744)>>1]&= ~0x80; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG ADMA STAT - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - case PS2_C1_ADMAS: - regArea[(PS2_C1_ADMAS)]=val; - //regArea[(0x344)>>1]&= ~0x80; - //regArea[(0x744)>>1]&= ~0x80; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG ADMA STAT - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - case PS2_C1_ATTR: - spuCtrl2[1]=val; - if(!(val & 0x40))regArea[PS2_IRQINFO] &= ~0x8; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG ATTR - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_SPUstat: - spuStat2[0]=val; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG SPU STAT - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_SPUstat: - spuStat2[1]=val; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG SPU STAT - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_ReverbAddr_Hi: - spuRvbAddr2[0] = (((unsigned long)val&0x3f)<<16)|(spuRvbAddr2[0]&0xFFFF); - SetReverbAddr(0); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG ESAH - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_ReverbAddr_Lo: - spuRvbAddr2[0] = (spuRvbAddr2[0] & 0x3f0000) | (val & 0xFFFF); - SetReverbAddr(0); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG ESAL - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_ReverbAEnd_Hi: - spuRvbAEnd2[0] = (((unsigned long)val&0x3f)<<16)/*|(spuRvbAEnd2[0]&0xFFFF)*/; - rvb[0].EndAddr=spuRvbAEnd2[0]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG EEAH - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_ReverbAEnd_Hi: - spuRvbAEnd2[1] = (((unsigned long)val&0x3f)<<16)/*|(spuRvbAEnd2[1]&0xFFFF)*/; - rvb[1].EndAddr=spuRvbAEnd2[1]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG EEAH - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_ReverbAddr_Hi: - spuRvbAddr2[1] = (((unsigned long)val&0x3f)<<16)|(spuRvbAddr2[1]&0xFFFF); - SetReverbAddr(1); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG ESAH - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_ReverbAddr_Lo: - spuRvbAddr2[1] = (spuRvbAddr2[1] & 0x3f0000) | (val & 0xFFFF); - SetReverbAddr(1); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG ESAL - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_SPUirqAddr_Hi: - spuIrq2[0] = (((unsigned long)val&0x3f)<<16)|(spuIrq2[0]&0xFFFF); // 6bits - pSpuIrq[0]=spuMemC+(spuIrq2[0]<<1); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG IRQAH - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_SPUirqAddr_Lo: - spuIrq2[0] = (spuIrq2[0] & 0x3F0000) | (val & 0xFFFF); - pSpuIrq[0]=spuMemC+(spuIrq2[0]<<1); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG IRQAL - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_SPUirqAddr_Hi: - spuIrq2[1] = (((unsigned long)val&0x3f)<<16)|(spuIrq2[1]&0xFFFF); // 6bits - pSpuIrq[1]=spuMemC+(spuIrq2[1]<<1); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG IRQAH - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_SPUirqAddr_Lo: - spuIrq2[1] = (spuIrq2[1] & 0x3F0000) | (val & 0xFFFF); - pSpuIrq[1]=spuMemC+(spuIrq2[1]<<1); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG IRQAL - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_IRQINFO: - // regArea[PS2_IRQINFO] = 0; // clear -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG IRQINFO - Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, val); -#endif - break; - case PS2_C0_AVOLL: -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG AVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - case PS2_C0_AVOLR: -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG AVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - case PS2_C1_AVOLL: -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG AVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - case PS2_C1_AVOLR: -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG AVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - case PS2_C0_SPUrvolL: - rvb[0].VolLeft=val; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG EVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_SPUrvolR: - rvb[0].VolRight=val; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG EVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_SPUrvolL: - rvb[1].VolLeft=val; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG EVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_SPUrvolR: - rvb[1].VolRight=val; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG EVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_SPUon1: - SoundOn(0,16,val); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG KON0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_SPUon2: - SoundOn(16,24,val); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG KON1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_SPUon1: - SoundOn(24,40,val); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG KON0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_SPUon2: - SoundOn(40,48,val); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG KON1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_SPUoff1: - SoundOff(0,16,val); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG KOF0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_SPUoff2: - SoundOff(16,24,val); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG KOF1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_SPUoff1: - SoundOff(24,40,val); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG KOF0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_SPUoff2: - SoundOff(40,48,val); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG KOF1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_SPUend1: - dwEndChannel2[0] &= 0xff0000; // According to manual all bits are cleared by writing an arbitary value -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG ENDX0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - case PS2_C0_SPUend2: - dwEndChannel2[0] &= 0xffff; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG ENDX1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_SPUend1: - dwEndChannel2[1] &= 0xff0000; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG ENDX0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - case PS2_C1_SPUend2: - dwEndChannel2[1] &= 0xffff; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG ENDX1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_FMod1: - FModOn(0,16,val); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG PMON0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_FMod2: - FModOn(16,24,val); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG PMON1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_FMod1: - FModOn(24,40,val); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG PMON0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_FMod2: - FModOn(40,48,val); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG PMON1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_Noise1: - NoiseOn(0,16,val); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG NON0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_Noise2: - NoiseOn(16,24,val); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG NON1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_Noise1: - NoiseOn(24,40,val); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG NON0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_Noise2: - NoiseOn(40,48,val); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG NON1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_MVOLL: - regArea[PS2_C0_MVOLL] = val; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG MVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - case PS2_C0_MVOLR: - regArea[PS2_C0_MVOLR] = val; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG MVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - case PS2_C1_MVOLL: - regArea[PS2_C0_MVOLL] = val; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG MVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - case PS2_C1_MVOLR: - regArea[PS2_C0_MVOLR] = val; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG MVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - - case PS2_C0_BVOLL: - regArea[PS2_C0_BVOLL] = val; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG BVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - case PS2_C0_BVOLR: - regArea[PS2_C0_BVOLR] = val; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG BVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - case PS2_C1_BVOLL: - regArea[PS2_C1_BVOLL] = val; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG BVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - case PS2_C1_BVOLR: - regArea[PS2_C1_BVOLR] = val; - #ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG BVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - case PS2_C0_MMIX: - regArea[PS2_C0_MMIX] = val; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG MMIX - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - case PS2_C1_MMIX: - regArea[PS2_C1_MMIX] = val; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG MMIX - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - case PS2_C0_DryL1: - VolumeOn(0,16,val,0); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG VMIXL0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_DryL2: - VolumeOn(16,24,val,0); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG VMIXL1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_DryL1: - VolumeOn(24,40,val,0); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG VMIXL0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_DryL2: - VolumeOn(40,48,val,0); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG VMIXL1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_DryR1: - VolumeOn(0,16,val,1); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG VMIXR0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_DryR2: - VolumeOn(16,24,val,1); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG VMIXR1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_DryR1: - VolumeOn(24,40,val,1); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG VMIXR0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_DryR2: - VolumeOn(40,48,val,1); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG VMIXR1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_RVBon1_L: - ReverbOn(0,16,val,0); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG VMIXEL0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_RVBon2_L: - ReverbOn(16,24,val,0); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG VMIXEL1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_RVBon1_L: - ReverbOn(24,40,val,0); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG VMIXEL0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_RVBon2_L: - ReverbOn(40,48,val,0); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG VMIXEL1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_RVBon1_R: - ReverbOn(0,16,val,1); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG VMIXER0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_RVBon2_R: - ReverbOn(16,24,val,1); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG VMIXER1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_RVBon1_R: - ReverbOn(24,40,val,1); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG VMIXER0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C1_RVBon2_R: - ReverbOn(40,48,val,1); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG VMIXER1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); -#endif - break; - //-------------------------------------------------// - case PS2_C0_Reverb+0: - rvb[0].FB_SRC_A=(((unsigned long)val&0x3f)<<16)|(rvb[0].FB_SRC_A&0xFFFF); - break; - case PS2_C0_Reverb+2: - rvb[0].FB_SRC_A=(rvb[0].FB_SRC_A & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+4: - rvb[0].FB_SRC_B=(((unsigned long)val&0x3f)<<16)|(rvb[0].FB_SRC_B&0xFFFF); - break; - case PS2_C0_Reverb+6: - rvb[0].FB_SRC_B=(rvb[0].FB_SRC_B & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+8: - rvb[0].IIR_DEST_A0=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_DEST_A0&0xFFFF); - break; - case PS2_C0_Reverb+10: - rvb[0].IIR_DEST_A0=(rvb[0].IIR_DEST_A0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+12: - rvb[0].IIR_DEST_A1=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_DEST_A1&0xFFFF); - break; - case PS2_C0_Reverb+14: - rvb[0].IIR_DEST_A1=(rvb[0].IIR_DEST_A1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+16: - rvb[0].ACC_SRC_A0=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_A0&0xFFFF); - break; - case PS2_C0_Reverb+18: - rvb[0].ACC_SRC_A0=(rvb[0].ACC_SRC_A0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+20: - rvb[0].ACC_SRC_A1=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_A1&0xFFFF); - break; - case PS2_C0_Reverb+22: - rvb[0].ACC_SRC_A1=(rvb[0].ACC_SRC_A1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+24: - rvb[0].ACC_SRC_B0=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_B0&0xFFFF); - break; - case PS2_C0_Reverb+26: - rvb[0].ACC_SRC_B0=(rvb[0].ACC_SRC_B0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+28: - rvb[0].ACC_SRC_B1=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_B1&0xFFFF); - break; - case PS2_C0_Reverb+30: - rvb[0].ACC_SRC_B1=(rvb[0].ACC_SRC_B1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+32: - rvb[0].IIR_SRC_A0=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_SRC_A0&0xFFFF); - break; - case PS2_C0_Reverb+34: - rvb[0].IIR_SRC_A0=(rvb[0].IIR_SRC_A0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+36: - rvb[0].IIR_SRC_A1=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_SRC_A1&0xFFFF); - break; - case PS2_C0_Reverb+38: - rvb[0].IIR_SRC_A1=(rvb[0].IIR_SRC_A1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+40: - rvb[0].IIR_DEST_B0=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_DEST_B0&0xFFFF); - break; - case PS2_C0_Reverb+42: - rvb[0].IIR_DEST_B0=(rvb[0].IIR_DEST_B0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+44: - rvb[0].IIR_DEST_B1=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_DEST_B1&0xFFFF); - break; - case PS2_C0_Reverb+46: - rvb[0].IIR_DEST_B1=(rvb[0].IIR_DEST_B1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+48: - rvb[0].ACC_SRC_C0=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_C0&0xFFFF); - break; - case PS2_C0_Reverb+50: - rvb[0].ACC_SRC_C0=(rvb[0].ACC_SRC_C0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+52: - rvb[0].ACC_SRC_C1=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_C1&0xFFFF); - break; - case PS2_C0_Reverb+54: - rvb[0].ACC_SRC_C1=(rvb[0].ACC_SRC_C1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+56: - rvb[0].ACC_SRC_D0=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_D0&0xFFFF); - break; - case PS2_C0_Reverb+58: - rvb[0].ACC_SRC_D0=(rvb[0].ACC_SRC_D0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+60: - rvb[0].ACC_SRC_D1=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_D1&0xFFFF); - break; - case PS2_C0_Reverb+62: - rvb[0].ACC_SRC_D1=(rvb[0].ACC_SRC_D1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+64: - rvb[0].IIR_SRC_B1=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_SRC_B1&0xFFFF); - break; - case PS2_C0_Reverb+66: - rvb[0].IIR_SRC_B1=(rvb[0].IIR_SRC_B1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+68: - rvb[0].IIR_SRC_B0=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_SRC_B0&0xFFFF); - break; - case PS2_C0_Reverb+70: - rvb[0].IIR_SRC_B0=(rvb[0].IIR_SRC_B0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+72: - rvb[0].MIX_DEST_A0=(((unsigned long)val&0x3f)<<16)|(rvb[0].MIX_DEST_A0&0xFFFF); - break; - case PS2_C0_Reverb+74: - rvb[0].MIX_DEST_A0=(rvb[0].MIX_DEST_A0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+76: - rvb[0].MIX_DEST_A1=(((unsigned long)val&0x3f)<<16)|(rvb[0].MIX_DEST_A1&0xFFFF); - break; - case PS2_C0_Reverb+78: - rvb[0].MIX_DEST_A1=(rvb[0].MIX_DEST_A1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+80: - rvb[0].MIX_DEST_B0=(((unsigned long)val&0x3f)<<16)|(rvb[0].MIX_DEST_B0&0xFFFF); - break; - case PS2_C0_Reverb+82: - rvb[0].MIX_DEST_B0=(rvb[0].MIX_DEST_B0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_Reverb+84: - rvb[0].MIX_DEST_B1=(((unsigned long)val&0x3f)<<16)|(rvb[0].MIX_DEST_B1&0xFFFF); - break; - case PS2_C0_Reverb+86: - rvb[0].MIX_DEST_B1=(rvb[0].MIX_DEST_B1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C0_ReverbX+0: rvb[0].IIR_ALPHA=(short)val; break; - case PS2_C0_ReverbX+2: rvb[0].ACC_COEF_A=(short)val; break; - case PS2_C0_ReverbX+4: rvb[0].ACC_COEF_B=(short)val; break; - case PS2_C0_ReverbX+6: rvb[0].ACC_COEF_C=(short)val; break; - case PS2_C0_ReverbX+8: rvb[0].ACC_COEF_D=(short)val; break; - case PS2_C0_ReverbX+10: rvb[0].IIR_COEF=(short)val; break; - case PS2_C0_ReverbX+12: rvb[0].FB_ALPHA=(short)val; break; - case PS2_C0_ReverbX+14: rvb[0].FB_X=(short)val; break; - case PS2_C0_ReverbX+16: rvb[0].IN_COEF_L=(short)val; break; - case PS2_C0_ReverbX+18: rvb[0].IN_COEF_R=(short)val; break; - //-------------------------------------------------// - case PS2_C1_Reverb+0: - rvb[1].FB_SRC_A=(((unsigned long)val&0x3f)<<16)|(rvb[1].FB_SRC_A&0xFFFF); - break; - case PS2_C1_Reverb+2: - rvb[1].FB_SRC_A=(rvb[1].FB_SRC_A & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+4: - rvb[1].FB_SRC_B=(((unsigned long)val&0x3f)<<16)|(rvb[1].FB_SRC_B&0xFFFF); - break; - case PS2_C1_Reverb+6: - rvb[1].FB_SRC_B=(rvb[1].FB_SRC_B & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+8: - rvb[1].IIR_DEST_A0=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_DEST_A0&0xFFFF); - break; - case PS2_C1_Reverb+10: - rvb[1].IIR_DEST_A0=(rvb[1].IIR_DEST_A0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+12: - rvb[1].IIR_DEST_A1=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_DEST_A1&0xFFFF); - break; - case PS2_C1_Reverb+14: - rvb[1].IIR_DEST_A1=(rvb[1].IIR_DEST_A1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+16: - rvb[1].ACC_SRC_A0=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_A0&0xFFFF); - break; - case PS2_C1_Reverb+18: - rvb[1].ACC_SRC_A0=(rvb[1].ACC_SRC_A0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+20: - rvb[1].ACC_SRC_A1=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_A1&0xFFFF); - break; - case PS2_C1_Reverb+22: - rvb[1].ACC_SRC_A1=(rvb[1].ACC_SRC_A1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+24: - rvb[1].ACC_SRC_B0=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_B0&0xFFFF); - break; - case PS2_C1_Reverb+26: - rvb[1].ACC_SRC_B0=(rvb[1].ACC_SRC_B0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+28: - rvb[1].ACC_SRC_B1=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_B1&0xFFFF); - break; - case PS2_C1_Reverb+30: - rvb[1].ACC_SRC_B1=(rvb[1].ACC_SRC_B1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+32: - rvb[1].IIR_SRC_A0=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_SRC_A0&0xFFFF); - break; - case PS2_C1_Reverb+34: - rvb[1].IIR_SRC_A0=(rvb[1].IIR_SRC_A0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+36: - rvb[1].IIR_SRC_A1=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_SRC_A1&0xFFFF); - break; - case PS2_C1_Reverb+38: - rvb[1].IIR_SRC_A1=(rvb[1].IIR_SRC_A1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+40: - rvb[1].IIR_DEST_B0=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_DEST_B0&0xFFFF); - break; - case PS2_C1_Reverb+42: - rvb[1].IIR_DEST_B0=(rvb[1].IIR_DEST_B0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+44: - rvb[1].IIR_DEST_B1=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_DEST_B1&0xFFFF); - break; - case PS2_C1_Reverb+46: - rvb[1].IIR_DEST_B1=(rvb[1].IIR_DEST_B1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+48: - rvb[1].ACC_SRC_C0=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_C0&0xFFFF); - break; - case PS2_C1_Reverb+50: - rvb[1].ACC_SRC_C0=(rvb[1].ACC_SRC_C0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+52: - rvb[1].ACC_SRC_C1=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_C1&0xFFFF); - break; - case PS2_C1_Reverb+54: - rvb[1].ACC_SRC_C1=(rvb[1].ACC_SRC_C1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+56: - rvb[1].ACC_SRC_D0=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_D0&0xFFFF); - break; - case PS2_C1_Reverb+58: - rvb[1].ACC_SRC_D0=(rvb[1].ACC_SRC_D0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+60: - rvb[1].ACC_SRC_D1=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_D1&0xFFFF); - break; - case PS2_C1_Reverb+62: - rvb[1].ACC_SRC_D1=(rvb[1].ACC_SRC_D1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+64: - rvb[1].IIR_SRC_B1=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_SRC_B1&0xFFFF); - break; - case PS2_C1_Reverb+66: - rvb[1].IIR_SRC_B1=(rvb[1].IIR_SRC_B1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+68: - rvb[1].IIR_SRC_B0=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_SRC_B0&0xFFFF); - break; - case PS2_C1_Reverb+70: - rvb[1].IIR_SRC_B0=(rvb[1].IIR_SRC_B0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+72: - rvb[1].MIX_DEST_A0=(((unsigned long)val&0x3f)<<16)|(rvb[1].MIX_DEST_A0&0xFFFF); - break; - case PS2_C1_Reverb+74: - rvb[1].MIX_DEST_A0=(rvb[1].MIX_DEST_A0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+76: - rvb[1].MIX_DEST_A1=(((unsigned long)val&0x3f)<<16)|(rvb[1].MIX_DEST_A1&0xFFFF); - break; - case PS2_C1_Reverb+78: - rvb[1].MIX_DEST_A1=(rvb[1].MIX_DEST_A1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+80: - rvb[1].MIX_DEST_B0=(((unsigned long)val&0x3f)<<16)|(rvb[1].MIX_DEST_B0&0xFFFF); - break; - case PS2_C1_Reverb+82: - rvb[1].MIX_DEST_B0=(rvb[1].MIX_DEST_B0 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_Reverb+84: - rvb[1].MIX_DEST_B1=(((unsigned long)val&0x3f)<<16)|(rvb[1].MIX_DEST_B1&0xFFFF); - break; - case PS2_C1_Reverb+86: - rvb[1].MIX_DEST_B1=(rvb[1].MIX_DEST_B1 & 0x3f0000) | ((val) & 0xFFFF); - break; - case PS2_C1_ReverbX+0: rvb[1].IIR_ALPHA=(short)val; break; - case PS2_C1_ReverbX+2: rvb[1].ACC_COEF_A=(short)val; break; - case PS2_C1_ReverbX+4: rvb[1].ACC_COEF_B=(short)val; break; - case PS2_C1_ReverbX+6: rvb[1].ACC_COEF_C=(short)val; break; - case PS2_C1_ReverbX+8: rvb[1].ACC_COEF_D=(short)val; break; - case PS2_C1_ReverbX+10: rvb[1].IIR_COEF=(short)val; break; - case PS2_C1_ReverbX+12: rvb[1].FB_ALPHA=(short)val; break; - case PS2_C1_ReverbX+14: rvb[1].FB_X=(short)val; break; - case PS2_C1_ReverbX+16: rvb[1].IN_COEF_L=(short)val; break; - case PS2_C1_ReverbX+18: rvb[1].IN_COEF_R=(short)val; break; - case PS2_SPDIF_OUT: -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG SPDIF_OUT Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,val); -#endif - break; - case PS2_SPDIF_MODE: -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG SPDIF_MODE Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,val); -#endif - break; - case PS2_SPDIF_MEDIA: -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG SPDIF_OUT Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,val); -#endif - break; - case PS2_SPDIF_COPY: -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG SPDIF_COPY Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,val); -#endif - break; - default: //All other writes -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("W_REG Unknown Register Addr %X Value %X\r\n",reg&0xFFFF,val); -#endif - break; - } - - iSpuAsyncWait=0; - -} - -//////////////////////////////////////////////////////////////////////// -// READ REGISTER: called by main emu -//////////////////////////////////////////////////////////////////////// -EXPORT_GCC unsigned short CALLBACK SPU2read(unsigned long reg) -{ - long r=reg&0xffff; - unsigned int ret = 0; - -if(spuCtrl2[0]&0x40 && spuIrq2[0] == r){ - //regArea[0x7C0] |= 0x4; - regArea[PS2_IRQINFO] |= 4; - irqCallbackSPU2(); - } -if(spuCtrl2[1]&0x40 && spuIrq2[1] == r){ - //regArea[0x7C0] |= 0x8; - regArea[PS2_IRQINFO] |= 8; - irqCallbackSPU2(); - } - if((r>=0x0000 && r<0x0180)||(r>=0x0400 && r<0x0580)) // some channel info? - { - int addr=0; - int ch=((r & 0x3ff)>>4); - if(r>=0x400) ch+=24; - - switch(r&0x0f) - { - case 0: //Left Volume - ret = s_chan[ch].iLeftVolRaw; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG Volume Left - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); -#endif - break; - case 2: //Right Volume - ret = s_chan[ch].iRightVolRaw; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG Volume Right - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); -#endif - break; - case 4: //Pitch - ret = regArea[r]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG Pitch - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); -#endif - break; - case 6: //ASDR1 - ret = regArea[r]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG ASDR1 - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); -#endif - break; - case 8: //ASDR2 - ret = regArea[r]; - #ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG ASDR2 - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); -#endif - break; - case 10: //Envelope (current) - ret = (unsigned short)(s_chan[ch].ADSRX.EnvelopeVol>>16); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG Envelope - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); -#endif - break; - - } - - }else - if((r>=0x01c0 && r<0x02E0)||(r>=0x05c0 && r<0x06E0)) // some channel info? - { - int ch=0;unsigned long rx=r; - - ch=((rx & 0x3ff)-0x1c0) / 0xC; - - rx-=ch*0xC; - if(rx>=0x400) {ch+=24;rx-=0x400;} - - switch(rx) - { - case 0x1C0: - ret = (((s_chan[ch].pStart-spuMemC)>>17)&0x3F); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG Start Addr Hi - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); -#endif - break; - case 0x1C2: - ret = (((s_chan[ch].pStart-spuMemC)>>1)&0xFFFF); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG Start Addr Lo - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); -#endif - break; - //------------------------------------------------// - case 0x1C4: - ret = (((s_chan[ch].pLoop-spuMemC)>>17)&0x3F); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG Loop Addr Hi - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); -#endif - break; - case 0x1C6: - ret = (((s_chan[ch].pLoop-spuMemC)>>1)&0xFFFF); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG Loop Addr Lo - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); -#endif - break; - //------------------------------------------------// - case 0x1C8: - ret = ((((s_chan[ch].pCurr)-spuMemC)>>17)&0x3F); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG Next Addr Hi - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); -#endif - break; - case 0x1CA: - ret = ((((s_chan[ch].pCurr)-spuMemC)>>1)&0xFFFF); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG Next Addr Lo - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); -#endif - break; - default: - ret = regArea[rx]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG Channel Addr Unknown - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); -#endif - break; - - //------------------------------------------------// - } - }else{ - switch(r) - { - //--------------------------------------------------// - case PS2_C0_SPUend1: - ret = (unsigned short)((dwEndChannel2[0]&0xFFFF)); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG ENDX 0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C0_SPUend2: - ret = (unsigned short)((dwEndChannel2[0]>>16)); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG ENDX 1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //--------------------------------------------------// - case PS2_C1_SPUend1: - ret = (unsigned short)((dwEndChannel2[1]&0xFFFF)); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG ENDX 0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C1_SPUend2: - ret = (unsigned short)((dwEndChannel2[1]>>16)); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG ENDX 1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //--------------------------------------------------// - case PS2_C0_ATTR: - ret = spuCtrl2[0]; - #ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG Core Attr - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //--------------------------------------------------// - case PS2_C1_ATTR: - ret = spuCtrl2[1]; - #ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG Core Attr - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //--------------------------------------------------// - case PS2_C0_SPUstat: - ret = spuStat2[0]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG SPU Status - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //--------------------------------------------------// - case PS2_C1_SPUstat: - ret = spuStat2[1]; - #ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG SPU Status - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //--------------------------------------------------// - case PS2_C0_SPUdata: - { - unsigned short s=spuMem[spuAddr2[0]]; - - if(spuCtrl2[0]&0x40 && spuIrq2[0] == spuAddr2[0]){ - regArea[0x7C0] |= 0x4; - regArea[PS2_IRQINFO] |= 4; - irqCallbackSPU2(); - } - spuAddr2[0]++; - if(spuAddr2[0]>0xFFFFF) spuAddr2[0] = 0; - spuStat2[0]|=0x80; - spuCtrl2[0]&=~0x30; - ret = s; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG SPU Data - Core 0 Addr %X SSA %x Val %X\r\n", reg&0xFFFF, spuAddr2[0]-1, ret); -#endif - } - break; - //--------------------------------------------------// - case PS2_C1_SPUdata: - { - unsigned short s=spuMem[spuAddr2[1]]; - - if(spuCtrl2[1]&0x40 && spuIrq2[1] == spuAddr2[1]){ - regArea[0x7C0] |= 0x8; - regArea[PS2_IRQINFO] |= 8; - irqCallbackSPU2(); - } - spuAddr2[1]++; - if(spuAddr2[1]>0xFFFFF) spuAddr2[1] = 0; - spuStat2[1]|=0x80; - spuCtrl2[1]&=~0x30; - ret = s; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG SPU Data - Core 1 Addr %X SSA %x Val %X\r\n", reg&0xFFFF, spuAddr2[1]-1, ret); -#endif - } - break; - //--------------------------------------------------// - case PS2_C0_SPUaddr_Hi: - ret = (unsigned short)((spuAddr2[0]>>16)&0x3F); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG TSAH - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C0_SPUaddr_Lo: - ret = (unsigned short)((spuAddr2[0]&0xFFFF)); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG TSAL - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //--------------------------------------------------// - case PS2_C1_SPUaddr_Hi: - ret = (unsigned short)((spuAddr2[1]>>16)&0x3F); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG TSAH - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C1_SPUaddr_Lo: - ret = (unsigned short)((spuAddr2[1]&0xFFFF)); -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG TSAL - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C0_ReverbAEnd_Hi: - ret = regArea[PS2_C0_ReverbAEnd_Hi]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG EEAH - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C1_ReverbAEnd_Hi: - ret = regArea[PS2_C1_ReverbAEnd_Hi]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG EEAH - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C0_ReverbAddr_Lo: - ret = regArea[PS2_C0_ReverbAddr_Lo]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG ESAL - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - - case PS2_C1_ReverbAddr_Lo: - ret = regArea[PS2_C1_ReverbAddr_Lo]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG ESAL - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_IRQINFO: - ret = regArea[PS2_IRQINFO]; - // regArea[PS2_IRQINFO] = 0; // clear -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG IRQINFO - Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C0_ADMAS: - ret = regArea[(PS2_C0_ADMAS)]; - ///regArea[(0x344)>>1]&= ~0x80; - //regArea[(0x744)>>1]&= ~0x80; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG ADMA STAT - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C1_ADMAS: - ret = regArea[(PS2_C1_ADMAS)]; - //regArea[(0x344)>>1]&= ~0x80; - //regArea[(0x744)>>1]&= ~0x80; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG ADMA STAT - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //--------------------------------------------------// - case PS2_C0_SPUrvolL: - ret = rvb[0].VolLeft; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG EVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C0_SPUrvolR: - ret = rvb[0].VolRight; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG EVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C1_SPUrvolL: - ret = rvb[1].VolLeft; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG EVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C1_SPUrvolR: - ret = rvb[1].VolRight; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG EVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C0_SPUon1: - ret = regArea[PS2_C0_SPUon1]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG KON0 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C0_SPUon2: - ret = regArea[PS2_C0_SPUon2]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG KON1 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C1_SPUon1: - ret = regArea[PS2_C1_SPUon1]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG KON0 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C1_SPUon2: - ret = regArea[PS2_C1_SPUon2]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG KON1 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C0_SPUoff1: - ret = regArea[PS2_C0_SPUoff1]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG KOF0 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C0_SPUoff2: - ret = regArea[PS2_C0_SPUoff2]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG KOF1 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C1_SPUoff1: - ret = regArea[PS2_C1_SPUoff1]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG KOF0 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C1_SPUoff2: - ret = regArea[PS2_C1_SPUoff2]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG KOF1 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C0_FMod1: - ret = regArea[PS2_C0_FMod1]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG PMON0 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C0_FMod2: - ret = regArea[PS2_C0_FMod2]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG PMON1 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C1_FMod1: - ret = regArea[PS2_C1_FMod1]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG PMON0 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C1_FMod2: - ret = regArea[PS2_C1_FMod2]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG PMON1 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C0_Noise1: - ret = regArea[PS2_C0_Noise1]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG NON0 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C0_Noise2: - ret = regArea[PS2_C0_Noise2]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG NON1 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C1_Noise1: - ret = regArea[PS2_C1_Noise1]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG NON0 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C1_Noise2: - ret = regArea[PS2_C1_Noise2]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG NON1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C0_AVOLL: - ret = regArea[PS2_C0_AVOLL]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG AVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C0_AVOLR: - ret = regArea[PS2_C0_AVOLR]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG AVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C1_AVOLL: - ret = regArea[PS2_C1_AVOLL]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG AVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C1_AVOLR: - ret = regArea[PS2_C1_AVOLR]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG AVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C0_MVOLL: - ret = regArea[PS2_C0_MVOLL]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG MVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C0_MVOLR: - ret = regArea[PS2_C0_MVOLR]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG MVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C1_MVOLL: - regArea[PS2_C0_MVOLL]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG MVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C1_MVOLR: - ret = regArea[PS2_C0_MVOLR]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG MVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - - case PS2_C0_BVOLL: - ret = regArea[PS2_C0_BVOLL]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG BVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C0_BVOLR: - ret = regArea[PS2_C0_BVOLR]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG BVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C1_BVOLL: - ret = regArea[PS2_C1_BVOLL]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG BVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C1_BVOLR: - ret = regArea[PS2_C1_BVOLR]; - #ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG BVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C0_MMIX: - ret = regArea[PS2_C0_MMIX]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG MMIX - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C1_MMIX: - ret = regArea[PS2_C1_MMIX]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG MMIX - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_C0_DryL1: - ret = regArea[PS2_C0_DryL1]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG VMIXL0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C0_DryL2: - ret = regArea[PS2_C0_DryL2]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG VMIXL1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C1_DryL1: - ret = regArea[PS2_C1_DryL1]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG VMIXL0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C1_DryL2: - ret = regArea[PS2_C1_DryL2]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG VMIXL1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C0_DryR1: - ret = regArea[PS2_C0_DryR1]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG VMIXR0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C0_DryR2: - ret = regArea[PS2_C0_DryR2]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG VMIXR1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C1_DryR1: - ret = regArea[PS2_C1_DryR1]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG VMIXR0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C1_DryR2: - ret = regArea[PS2_C1_DryR2]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG VMIXR1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C0_RVBon1_L: - ret = regArea[PS2_C0_RVBon1_L]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG VMIXEL0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C0_RVBon2_L: - ret = regArea[PS2_C0_RVBon2_L]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG VMIXEL1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C1_RVBon1_L: - ret = regArea[PS2_C1_RVBon1_L]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG VMIXEL0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C1_RVBon2_L: - ret = regArea[PS2_C1_RVBon2_L]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG VMIXEL1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C0_RVBon1_R: - ret = regArea[PS2_C0_RVBon1_R]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG VMIXER0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C0_RVBon2_R: - ret = regArea[PS2_C0_RVBon2_R]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG VMIXER1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C1_RVBon1_R: - ret = regArea[PS2_C1_RVBon1_R]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG VMIXER0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - //-------------------------------------------------// - case PS2_C1_RVBon2_R: - ret = regArea[PS2_C1_RVBon2_R]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG VMIXER1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - case PS2_SPDIF_OUT: - ret = regArea[PS2_SPDIF_OUT]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG SPDIF_OUT Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,ret); -#endif - break; - case PS2_SPDIF_MODE: - ret = regArea[PS2_SPDIF_MODE]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG SPDIF_MODE Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,ret); -#endif - break; - case PS2_SPDIF_MEDIA: - ret = regArea[PS2_SPDIF_MEDIA]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG SPDIF_OUT Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,ret); -#endif - break; - case PS2_SPDIF_COPY: - ret = regArea[PS2_SPDIF_COPY]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG SPDIF_COPY Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,ret); -#endif - break; - default: - ret = regArea[r]; -#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG Unknown Register - Addr %X Val %X\r\n", reg&0xFFFF, ret); -#endif - break; - } - /*#ifdef _WINDOWS - if(iDebugMode==1) logprintf("R_REG %X Val %X\r\n",reg&0xFFFF, ret); -#endif*/ - } - - - return ret; -} - -//////////////////////////////////////////////////////////////////////// -// SOUND ON register write -//////////////////////////////////////////////////////////////////////// - -void SoundOn(int start,int end,unsigned short val) // SOUND ON PSX COMAND -{ - int ch; - - for(ch=start;ch>=1) // loop channels - { - if((val&1) && s_chan[ch].pStart) // mmm... start has to be set before key on !?! - { - //s_chan[ch].bStop = 0; - if(ch > 24){ - int tempchan = ch-24; - if(tempchan > 15) { - regArea[PS2_C1_SPUoff2] &= ~(1<<(tempchan-16)); - }else{ - regArea[PS2_C1_SPUoff1] &= ~(1< 15) { - regArea[PS2_C0_SPUoff2] &= ~(1<<(tempchan-16)); - }else{ - regArea[PS2_C0_SPUoff1] &= ~(1<>=1) // loop channels - { - if(val&1) // && s_chan[i].bOn) mmm... - { - if(ch > 24){ - int tempchan = ch-24; - if(tempchan > 15) { - regArea[PS2_C1_SPUon2] &= ~(1<<(tempchan-16)); - }else{ - regArea[PS2_C1_SPUon1] &= ~(1< 15) { - regArea[PS2_C0_SPUon2] &= ~(1<<(tempchan-16)); - }else{ - regArea[PS2_C0_SPUon1] &= ~(1<>=1) // loop channels - { - if(val&1) // -> fmod on/off - { - if(ch>0) - { - s_chan[ch].bFMod=1; // --> sound channel - s_chan[ch-1].bFMod=2; // --> freq channel - } - } - else - { - s_chan[ch].bFMod=0; // --> turn off fmod - } - } -} - -//////////////////////////////////////////////////////////////////////// -// NOISE register write -//////////////////////////////////////////////////////////////////////// - -void NoiseOn(int start,int end,unsigned short val) // NOISE ON PSX COMMAND -{ - int ch; - - for(ch=start;ch>=1) // loop channels - { - if(val&1) // -> noise on/off - { - s_chan[ch].bNoise=1; - } - else - { - s_chan[ch].bNoise=0; - } - } -} - -//////////////////////////////////////////////////////////////////////// -// LEFT VOLUME register write -//////////////////////////////////////////////////////////////////////// - -// please note: sweep and phase invert are wrong... but I've never seen -// them used - -void SetVolumeL(unsigned char ch,short vol) // LEFT VOLUME -{ - s_chan[ch].iLeftVolRaw=vol; - - if(vol&0x8000) // sweep? - { - short sInc=1; // -> sweep up? - if(vol&0x2000) sInc=-1; // -> or down? - if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this - vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64 - vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half! - vol*=128; - } - else // no sweep: - { - if(vol&0x4000) // -> mmm... phase inverted? have to investigate this - //vol^=0xffff; - vol=0x3fff-(vol&0x3fff); - } - - vol&=0x3fff; - s_chan[ch].iLeftVolume=vol; // store volume -} - -//////////////////////////////////////////////////////////////////////// -// RIGHT VOLUME register write -//////////////////////////////////////////////////////////////////////// - -void SetVolumeR(unsigned char ch,short vol) // RIGHT VOLUME -{ - s_chan[ch].iRightVolRaw=vol; - - if(vol&0x8000) // comments... see above :) - { - short sInc=1; - if(vol&0x2000) sInc=-1; - if(vol&0x1000) vol^=0xffff; - vol=((vol&0x7f)+1)/2; - vol+=vol/(2*sInc); - vol*=128; - } - else - { - if(vol&0x4000) //vol=vol^=0xffff; - vol=0x3fff-(vol&0x3fff); - } - - vol&=0x3fff; - - s_chan[ch].iRightVolume=vol; -} - -//////////////////////////////////////////////////////////////////////// -// PITCH register write -//////////////////////////////////////////////////////////////////////// - -void SetPitch(int ch,unsigned short val) // SET PITCH -{ - int NP; - if(val>0x3fff) NP=0x3fff; // get pitch val - else NP=val; - - s_chan[ch].iRawPitch=NP; - - NP=(48000L*NP)/4096L; // calc frequency(48000Hz) - if(NP<1) NP=1; // some security - s_chan[ch].iActFreq=NP; // store frequency -} - -//////////////////////////////////////////////////////////////////////// -// REVERB register write -//////////////////////////////////////////////////////////////////////// - -void ReverbOn(int start,int end,unsigned short val,int iRight) // REVERB ON PSX COMMAND -{ - int ch; - - for(ch=start;ch>=1) // loop channels - { - if(val&1) // -> reverb on/off - { - if(iRight) s_chan[ch].bReverbR=1; - else s_chan[ch].bReverbL=1; - } - else - { - if(iRight) s_chan[ch].bReverbR=0; - else s_chan[ch].bReverbL=0; - } - } -} - -//////////////////////////////////////////////////////////////////////// -// REVERB START register write -//////////////////////////////////////////////////////////////////////// - -void SetReverbAddr(int core) -{ - long val=spuRvbAddr2[core]; - - if(rvb[core].StartAddr!=val) - { - if(val<=0x27ff) - { - rvb[core].StartAddr=rvb[core].CurrAddr=0; - } - else - { - rvb[core].StartAddr=val; - rvb[core].CurrAddr=rvb[core].StartAddr; - } - } -} - -//////////////////////////////////////////////////////////////////////// -// DRY LEFT/RIGHT per voice switches -//////////////////////////////////////////////////////////////////////// - -void VolumeOn(int start,int end,unsigned short val,int iRight) // VOLUME ON PSX COMMAND -{ - int ch; - - for(ch=start;ch>=1) // loop channels - { - if(val&1) // -> reverb on/off - { - if(iRight) s_chan[ch].bVolumeR=1; - else s_chan[ch].bVolumeL=1; - } - else - { - if(iRight) s_chan[ch].bVolumeR=0; - else s_chan[ch].bVolumeL=0; - } - } -} - - +/*************************************************************************** + registers.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/04/04 - Pete +// - changed plugin to emulate PS2 spu +// +// 2003/02/09 - kode54 +// - removed &0x3fff from reverb volume registers, fixes a few games, +// hopefully won't be breaking anything +// +// 2003/01/19 - Pete +// - added Neill's reverb +// +// 2003/01/06 - Pete +// - added Neill's ADSR timings +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_REGISTERS + +#include "externals.h" +#include "registers.h" +#include "regs.h" +#include "reverb.h" +#include "debug.h" + +int MMIXC0 = 0, MMIXC1 = 0; +/* +// adsr time values (in ms) by James Higgs ... see the end of +// the adsr.c source for details + +#define ATTACK_MS 514L +#define DECAYHALF_MS 292L +#define DECAY_MS 584L +#define SUSTAIN_MS 450L +#define RELEASE_MS 446L +*/ + +// we have a timebase of 1.020408f ms, not 1 ms... so adjust adsr defines +#define ATTACK_MS 494L +#define DECAYHALF_MS 286L +#define DECAY_MS 572L +#define SUSTAIN_MS 441L +#define RELEASE_MS 437L + +extern void (CALLBACK *irqCallbackSPU2)(); // func of main emu, called on spu irq + + +//////////////////////////////////////////////////////////////////////// +// WRITE REGISTERS: called by main emu +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC void CALLBACK SPU2write(unsigned long reg, unsigned short val) +{ + long r=reg&0xffff; + + + + regArea[r] = val; + + if(spuCtrl2[0]&0x40 && spuIrq2[0] == r){ + //regArea[0x7C0] |= 0x4; + regArea[PS2_IRQINFO] |= 4; + irqCallbackSPU2(); + } + if(spuCtrl2[1]&0x40 && spuIrq2[1] == r){ + //regArea[0x7C0] |= 0x8; + regArea[PS2_IRQINFO] |= 8; + irqCallbackSPU2(); + } + if((r>=0x0000 && r<0x0180)||(r>=0x0400 && r<0x0580)) // some channel info? + { + int rx=0; + int ch=0; + if(r>=0x400) { + rx= r - 0x400; + ch=(rx>>4)+24; + } else { + rx= r; + ch=(rx>>4); + } + + switch(rx&0x0f) + { + //------------------------------------------------// r volume + case 0: + SetVolumeL((unsigned char)ch,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Volume Left - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + //------------------------------------------------// l volume + case 2: + SetVolumeR((unsigned char)ch,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Volume Right - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + //------------------------------------------------// pitch + case 4: + SetPitch(ch,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Pitch - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + //------------------------------------------------// level with pre-calcs + case 6: + { + const unsigned long lval=val;unsigned long lx; + //---------------------------------------------// + s_chan[ch].ADSRX.AttackModeExp=(lval&0x8000)?1:0; + s_chan[ch].ADSRX.AttackRate=(lval>>8) & 0x007f; + s_chan[ch].ADSRX.DecayRate=(lval>>4) & 0x000f; + s_chan[ch].ADSRX.SustainLevel=lval & 0x000f; + //---------------------------------------------// + if(!iDebugMode) break; + //---------------------------------------------// stuff below is only for debug mode + + s_chan[ch].ADSR.AttackModeExp=(lval&0x8000)?1:0; //0x007f + + lx=(((lval>>8) & 0x007f)>>2); // attack time to run from 0 to 100% volume + lx=min(31,lx); // no overflow on shift! + if(lx) + { + lx = (1<>4) & 0x000f; // decay: + if(lx) // our const decay value is time it takes from 100% to 0% of volume + { + lx = ((1<<(lx))*DECAY_MS)/10000L; + if(!lx) lx=1; + } + s_chan[ch].ADSR.DecayTime = // so calc how long does it take to run from 100% to the wanted sus level + (lx*(1024-s_chan[ch].ADSR.SustainLevel))/1024; + } +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ADSR1 - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + //------------------------------------------------// adsr times with pre-calcs + case 8: + { + const unsigned long lval=val;unsigned long lx; + + //----------------------------------------------// + s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0; + s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1; + s_chan[ch].ADSRX.SustainRate = (lval>>6) & 0x007f; + s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0; + s_chan[ch].ADSRX.ReleaseRate = lval & 0x001f; + //----------------------------------------------// + if(!iDebugMode) break; + //----------------------------------------------// stuff below is only for debug mode + + s_chan[ch].ADSR.SustainModeExp = (lval&0x8000)?1:0; + s_chan[ch].ADSR.ReleaseModeExp = (lval&0x0020)?1:0; + + lx=((((lval>>6) & 0x007f)>>2)); // sustain time... often very high + lx=min(31,lx); // values are used to hold the volume + if(lx) // until a sound stop occurs + { // the highest value we reach (due to + lx = (1< 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + default: +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Unknown Mixing reg - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + //------------------------------------------------// + } + + return; + } + + if((r>=0x01c0 && r<0x02E0)||(r>=0x05c0 && r<0x06E0)) // some channel info? + { + int ch=0;unsigned long rx=r; + + ch=((rx & 0x3ff)-0x1c0) / 0xC; + + rx-=ch*0xC; + if(rx>=0x400) {ch+=24;rx-=0x400;} + + switch(rx) + { + //------------------------------------------------// + case 0x1C0: + s_chan[ch].iStartAdr=(((unsigned long)val&0x3f)<<16)|(s_chan[ch].iStartAdr&0xFFFF); + s_chan[ch].pStart=spuMemC+(s_chan[ch].iStartAdr<<1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Start Addr Hi - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + case 0x1C2: + s_chan[ch].iStartAdr=(s_chan[ch].iStartAdr & 0x3f0000) | (val & 0xFFFF); + s_chan[ch].pStart=spuMemC+(s_chan[ch].iStartAdr<<1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Start Addr Lo - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + //------------------------------------------------// + case 0x1C4: + s_chan[ch].iLoopAdr=(((unsigned long)val&0x3f)<<16)|(s_chan[ch].iLoopAdr&0xFFFF); + s_chan[ch].pLoop=spuMemC+(s_chan[ch].iLoopAdr<<1); + if(s_chan[ch].iLoopAdr)s_chan[ch].bIgnoreLoop=1; + else s_chan[ch].bIgnoreLoop=0; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Loop Addr Hi - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + case 0x1C6: + s_chan[ch].iLoopAdr=(s_chan[ch].iLoopAdr & 0x3f0000) | (val & 0xFFFF); + s_chan[ch].pLoop=spuMemC+(s_chan[ch].iLoopAdr<<1); + if(s_chan[ch].iLoopAdr)s_chan[ch].bIgnoreLoop=1; + else s_chan[ch].bIgnoreLoop=0; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Loop Addr Lo - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + //------------------------------------------------// + case 0x1C8: + // unused... check if it gets written as well + s_chan[ch].iNextAdr=(((unsigned long)val&0x3f)<<16)|(s_chan[ch].iNextAdr&0xFFFF); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Next Addr Hi - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + case 0x1CA: + // unused... check if it gets written as well + s_chan[ch].iNextAdr=(s_chan[ch].iNextAdr & 0x3f0000) | (val & 0xFFFF); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Next Addr Lo - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, val); +#endif + break; + //------------------------------------------------// + } + + return; + } + + switch(r) + { + //-------------------------------------------------// + case PS2_C0_SPUaddr_Hi: + spuAddr2[0] = (((unsigned long)val&0x3f)<<16)|(spuAddr2[0]&0xFFFF); // 6bits +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG TSAH - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUaddr_Lo: + spuAddr2[0] = (spuAddr2[0] & 0x3F0000) | (val & 0xFFFF); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG TSAL - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUaddr_Hi: + spuAddr2[1] = (((unsigned long)val&0x3f)<<16)|(spuAddr2[1]&0xFFFF); // 6bits +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG TSAH - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUaddr_Lo: + spuAddr2[1] = (spuAddr2[1] & 0x3F0000) | (val & 0xFFFF); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG TSAL - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUdata: + spuMem[spuAddr2[0]] = val; + if(spuCtrl2[0]&0x40 && spuIrq2[0] == spuAddr2[0]){ + regArea[0x7C0] |= 0x4; + regArea[PS2_IRQINFO] |= 4; + irqCallbackSPU2(); + } + spuAddr2[0]++; + if(spuAddr2[0]>0xFFFFF) spuAddr2[0] = 0; + spuStat2[0]|=0x80; + spuCtrl2[0]&=~0x30; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG SPU Data - Core 0 Addr %X Val %X\r\n", spuAddr2[0]-1, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUdata: + spuMem[spuAddr2[1]] = val; + + if(spuCtrl2[1]&0x40 && spuIrq2[1] == spuAddr2[1]){ + regArea[0x7C0] |= 0x8; + regArea[PS2_IRQINFO] |= 8; + irqCallbackSPU2(); + } + spuAddr2[1]++; + if(spuAddr2[1]>0xFFFFF) spuAddr2[1] = 0; + spuStat2[1]|=0x80; + spuCtrl2[1]&=~0x30; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG SPU Data - Core 1 Addr %X Val %X\r\n", spuAddr2[1]-1, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_ATTR: + spuCtrl2[0]=val; + if(!(val & 0x40))regArea[PS2_IRQINFO] &= ~0x4; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ATTR - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_ADMAS: + regArea[(PS2_C0_ADMAS)]=val; + ///regArea[(0x344)>>1]&= ~0x80; + //regArea[(0x744)>>1]&= ~0x80; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ADMA STAT - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_ADMAS: + regArea[(PS2_C1_ADMAS)]=val; + //regArea[(0x344)>>1]&= ~0x80; + //regArea[(0x744)>>1]&= ~0x80; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ADMA STAT - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_ATTR: + spuCtrl2[1]=val; + if(!(val & 0x40))regArea[PS2_IRQINFO] &= ~0x8; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ATTR - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUstat: + spuStat2[0]=val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG SPU STAT - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUstat: + spuStat2[1]=val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG SPU STAT - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_ReverbAddr_Hi: + spuRvbAddr2[0] = (((unsigned long)val&0x3f)<<16)|(spuRvbAddr2[0]&0xFFFF); + SetReverbAddr(0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ESAH - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_ReverbAddr_Lo: + spuRvbAddr2[0] = (spuRvbAddr2[0] & 0x3f0000) | (val & 0xFFFF); + SetReverbAddr(0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ESAL - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_ReverbAEnd_Hi: + spuRvbAEnd2[0] = (((unsigned long)val&0x3f)<<16)/*|(spuRvbAEnd2[0]&0xFFFF)*/; + rvb[0].EndAddr=spuRvbAEnd2[0]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG EEAH - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_ReverbAEnd_Hi: + spuRvbAEnd2[1] = (((unsigned long)val&0x3f)<<16)/*|(spuRvbAEnd2[1]&0xFFFF)*/; + rvb[1].EndAddr=spuRvbAEnd2[1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG EEAH - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_ReverbAddr_Hi: + spuRvbAddr2[1] = (((unsigned long)val&0x3f)<<16)|(spuRvbAddr2[1]&0xFFFF); + SetReverbAddr(1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ESAH - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_ReverbAddr_Lo: + spuRvbAddr2[1] = (spuRvbAddr2[1] & 0x3f0000) | (val & 0xFFFF); + SetReverbAddr(1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ESAL - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUirqAddr_Hi: + spuIrq2[0] = (((unsigned long)val&0x3f)<<16)|(spuIrq2[0]&0xFFFF); // 6bits + pSpuIrq[0]=spuMemC+(spuIrq2[0]<<1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG IRQAH - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUirqAddr_Lo: + spuIrq2[0] = (spuIrq2[0] & 0x3F0000) | (val & 0xFFFF); + pSpuIrq[0]=spuMemC+(spuIrq2[0]<<1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG IRQAL - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUirqAddr_Hi: + spuIrq2[1] = (((unsigned long)val&0x3f)<<16)|(spuIrq2[1]&0xFFFF); // 6bits + pSpuIrq[1]=spuMemC+(spuIrq2[1]<<1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG IRQAH - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUirqAddr_Lo: + spuIrq2[1] = (spuIrq2[1] & 0x3F0000) | (val & 0xFFFF); + pSpuIrq[1]=spuMemC+(spuIrq2[1]<<1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG IRQAL - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_IRQINFO: + // regArea[PS2_IRQINFO] = 0; // clear +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG IRQINFO - Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C0_AVOLL: +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG AVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C0_AVOLR: +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG AVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_AVOLL: +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG AVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_AVOLR: +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG AVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C0_SPUrvolL: + rvb[0].VolLeft=val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG EVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUrvolR: + rvb[0].VolRight=val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG EVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUrvolL: + rvb[1].VolLeft=val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG EVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUrvolR: + rvb[1].VolRight=val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG EVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUon1: + SoundOn(0,16,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG KON0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUon2: + SoundOn(16,24,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG KON1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUon1: + SoundOn(24,40,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG KON0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUon2: + SoundOn(40,48,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG KON1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUoff1: + SoundOff(0,16,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG KOF0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUoff2: + SoundOff(16,24,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG KOF1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUoff1: + SoundOff(24,40,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG KOF0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUoff2: + SoundOff(40,48,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG KOF1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUend1: + dwEndChannel2[0] &= 0xff0000; // According to manual all bits are cleared by writing an arbitary value +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ENDX0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C0_SPUend2: + dwEndChannel2[0] &= 0xffff; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ENDX1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUend1: + dwEndChannel2[1] &= 0xff0000; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ENDX0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_SPUend2: + dwEndChannel2[1] &= 0xffff; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG ENDX1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_FMod1: + FModOn(0,16,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG PMON0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_FMod2: + FModOn(16,24,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG PMON1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_FMod1: + FModOn(24,40,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG PMON0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_FMod2: + FModOn(40,48,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG PMON1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_Noise1: + NoiseOn(0,16,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG NON0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_Noise2: + NoiseOn(16,24,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG NON1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_Noise1: + NoiseOn(24,40,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG NON0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_Noise2: + NoiseOn(40,48,val); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG NON1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_MVOLL: + regArea[PS2_C0_MVOLL] = val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG MVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C0_MVOLR: + regArea[PS2_C0_MVOLR] = val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG MVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_MVOLL: + regArea[PS2_C0_MVOLL] = val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG MVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_MVOLR: + regArea[PS2_C0_MVOLR] = val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG MVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + + case PS2_C0_BVOLL: + regArea[PS2_C0_BVOLL] = val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG BVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C0_BVOLR: + regArea[PS2_C0_BVOLR] = val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG BVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_BVOLL: + regArea[PS2_C1_BVOLL] = val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG BVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_BVOLR: + regArea[PS2_C1_BVOLR] = val; + #ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG BVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C0_MMIX: + regArea[PS2_C0_MMIX] = val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG MMIX - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C1_MMIX: + regArea[PS2_C1_MMIX] = val; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG MMIX - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + case PS2_C0_DryL1: + VolumeOn(0,16,val,0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXL0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_DryL2: + VolumeOn(16,24,val,0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXL1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_DryL1: + VolumeOn(24,40,val,0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXL0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_DryL2: + VolumeOn(40,48,val,0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXL1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_DryR1: + VolumeOn(0,16,val,1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXR0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_DryR2: + VolumeOn(16,24,val,1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXR1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_DryR1: + VolumeOn(24,40,val,1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXR0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_DryR2: + VolumeOn(40,48,val,1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXR1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_RVBon1_L: + ReverbOn(0,16,val,0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXEL0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_RVBon2_L: + ReverbOn(16,24,val,0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXEL1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_RVBon1_L: + ReverbOn(24,40,val,0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXEL0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_RVBon2_L: + ReverbOn(40,48,val,0); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXEL1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_RVBon1_R: + ReverbOn(0,16,val,1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXER0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_RVBon2_R: + ReverbOn(16,24,val,1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXER1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_RVBon1_R: + ReverbOn(24,40,val,1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXER0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C1_RVBon2_R: + ReverbOn(40,48,val,1); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG VMIXER1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, val); +#endif + break; + //-------------------------------------------------// + case PS2_C0_Reverb+0: + rvb[0].FB_SRC_A=(((unsigned long)val&0x3f)<<16)|(rvb[0].FB_SRC_A&0xFFFF); + break; + case PS2_C0_Reverb+2: + rvb[0].FB_SRC_A=(rvb[0].FB_SRC_A & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+4: + rvb[0].FB_SRC_B=(((unsigned long)val&0x3f)<<16)|(rvb[0].FB_SRC_B&0xFFFF); + break; + case PS2_C0_Reverb+6: + rvb[0].FB_SRC_B=(rvb[0].FB_SRC_B & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+8: + rvb[0].IIR_DEST_A0=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_DEST_A0&0xFFFF); + break; + case PS2_C0_Reverb+10: + rvb[0].IIR_DEST_A0=(rvb[0].IIR_DEST_A0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+12: + rvb[0].IIR_DEST_A1=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_DEST_A1&0xFFFF); + break; + case PS2_C0_Reverb+14: + rvb[0].IIR_DEST_A1=(rvb[0].IIR_DEST_A1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+16: + rvb[0].ACC_SRC_A0=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_A0&0xFFFF); + break; + case PS2_C0_Reverb+18: + rvb[0].ACC_SRC_A0=(rvb[0].ACC_SRC_A0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+20: + rvb[0].ACC_SRC_A1=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_A1&0xFFFF); + break; + case PS2_C0_Reverb+22: + rvb[0].ACC_SRC_A1=(rvb[0].ACC_SRC_A1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+24: + rvb[0].ACC_SRC_B0=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_B0&0xFFFF); + break; + case PS2_C0_Reverb+26: + rvb[0].ACC_SRC_B0=(rvb[0].ACC_SRC_B0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+28: + rvb[0].ACC_SRC_B1=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_B1&0xFFFF); + break; + case PS2_C0_Reverb+30: + rvb[0].ACC_SRC_B1=(rvb[0].ACC_SRC_B1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+32: + rvb[0].IIR_SRC_A0=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_SRC_A0&0xFFFF); + break; + case PS2_C0_Reverb+34: + rvb[0].IIR_SRC_A0=(rvb[0].IIR_SRC_A0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+36: + rvb[0].IIR_SRC_A1=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_SRC_A1&0xFFFF); + break; + case PS2_C0_Reverb+38: + rvb[0].IIR_SRC_A1=(rvb[0].IIR_SRC_A1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+40: + rvb[0].IIR_DEST_B0=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_DEST_B0&0xFFFF); + break; + case PS2_C0_Reverb+42: + rvb[0].IIR_DEST_B0=(rvb[0].IIR_DEST_B0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+44: + rvb[0].IIR_DEST_B1=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_DEST_B1&0xFFFF); + break; + case PS2_C0_Reverb+46: + rvb[0].IIR_DEST_B1=(rvb[0].IIR_DEST_B1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+48: + rvb[0].ACC_SRC_C0=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_C0&0xFFFF); + break; + case PS2_C0_Reverb+50: + rvb[0].ACC_SRC_C0=(rvb[0].ACC_SRC_C0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+52: + rvb[0].ACC_SRC_C1=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_C1&0xFFFF); + break; + case PS2_C0_Reverb+54: + rvb[0].ACC_SRC_C1=(rvb[0].ACC_SRC_C1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+56: + rvb[0].ACC_SRC_D0=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_D0&0xFFFF); + break; + case PS2_C0_Reverb+58: + rvb[0].ACC_SRC_D0=(rvb[0].ACC_SRC_D0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+60: + rvb[0].ACC_SRC_D1=(((unsigned long)val&0x3f)<<16)|(rvb[0].ACC_SRC_D1&0xFFFF); + break; + case PS2_C0_Reverb+62: + rvb[0].ACC_SRC_D1=(rvb[0].ACC_SRC_D1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+64: + rvb[0].IIR_SRC_B1=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_SRC_B1&0xFFFF); + break; + case PS2_C0_Reverb+66: + rvb[0].IIR_SRC_B1=(rvb[0].IIR_SRC_B1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+68: + rvb[0].IIR_SRC_B0=(((unsigned long)val&0x3f)<<16)|(rvb[0].IIR_SRC_B0&0xFFFF); + break; + case PS2_C0_Reverb+70: + rvb[0].IIR_SRC_B0=(rvb[0].IIR_SRC_B0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+72: + rvb[0].MIX_DEST_A0=(((unsigned long)val&0x3f)<<16)|(rvb[0].MIX_DEST_A0&0xFFFF); + break; + case PS2_C0_Reverb+74: + rvb[0].MIX_DEST_A0=(rvb[0].MIX_DEST_A0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+76: + rvb[0].MIX_DEST_A1=(((unsigned long)val&0x3f)<<16)|(rvb[0].MIX_DEST_A1&0xFFFF); + break; + case PS2_C0_Reverb+78: + rvb[0].MIX_DEST_A1=(rvb[0].MIX_DEST_A1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+80: + rvb[0].MIX_DEST_B0=(((unsigned long)val&0x3f)<<16)|(rvb[0].MIX_DEST_B0&0xFFFF); + break; + case PS2_C0_Reverb+82: + rvb[0].MIX_DEST_B0=(rvb[0].MIX_DEST_B0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_Reverb+84: + rvb[0].MIX_DEST_B1=(((unsigned long)val&0x3f)<<16)|(rvb[0].MIX_DEST_B1&0xFFFF); + break; + case PS2_C0_Reverb+86: + rvb[0].MIX_DEST_B1=(rvb[0].MIX_DEST_B1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C0_ReverbX+0: rvb[0].IIR_ALPHA=(short)val; break; + case PS2_C0_ReverbX+2: rvb[0].ACC_COEF_A=(short)val; break; + case PS2_C0_ReverbX+4: rvb[0].ACC_COEF_B=(short)val; break; + case PS2_C0_ReverbX+6: rvb[0].ACC_COEF_C=(short)val; break; + case PS2_C0_ReverbX+8: rvb[0].ACC_COEF_D=(short)val; break; + case PS2_C0_ReverbX+10: rvb[0].IIR_COEF=(short)val; break; + case PS2_C0_ReverbX+12: rvb[0].FB_ALPHA=(short)val; break; + case PS2_C0_ReverbX+14: rvb[0].FB_X=(short)val; break; + case PS2_C0_ReverbX+16: rvb[0].IN_COEF_L=(short)val; break; + case PS2_C0_ReverbX+18: rvb[0].IN_COEF_R=(short)val; break; + //-------------------------------------------------// + case PS2_C1_Reverb+0: + rvb[1].FB_SRC_A=(((unsigned long)val&0x3f)<<16)|(rvb[1].FB_SRC_A&0xFFFF); + break; + case PS2_C1_Reverb+2: + rvb[1].FB_SRC_A=(rvb[1].FB_SRC_A & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+4: + rvb[1].FB_SRC_B=(((unsigned long)val&0x3f)<<16)|(rvb[1].FB_SRC_B&0xFFFF); + break; + case PS2_C1_Reverb+6: + rvb[1].FB_SRC_B=(rvb[1].FB_SRC_B & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+8: + rvb[1].IIR_DEST_A0=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_DEST_A0&0xFFFF); + break; + case PS2_C1_Reverb+10: + rvb[1].IIR_DEST_A0=(rvb[1].IIR_DEST_A0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+12: + rvb[1].IIR_DEST_A1=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_DEST_A1&0xFFFF); + break; + case PS2_C1_Reverb+14: + rvb[1].IIR_DEST_A1=(rvb[1].IIR_DEST_A1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+16: + rvb[1].ACC_SRC_A0=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_A0&0xFFFF); + break; + case PS2_C1_Reverb+18: + rvb[1].ACC_SRC_A0=(rvb[1].ACC_SRC_A0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+20: + rvb[1].ACC_SRC_A1=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_A1&0xFFFF); + break; + case PS2_C1_Reverb+22: + rvb[1].ACC_SRC_A1=(rvb[1].ACC_SRC_A1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+24: + rvb[1].ACC_SRC_B0=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_B0&0xFFFF); + break; + case PS2_C1_Reverb+26: + rvb[1].ACC_SRC_B0=(rvb[1].ACC_SRC_B0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+28: + rvb[1].ACC_SRC_B1=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_B1&0xFFFF); + break; + case PS2_C1_Reverb+30: + rvb[1].ACC_SRC_B1=(rvb[1].ACC_SRC_B1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+32: + rvb[1].IIR_SRC_A0=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_SRC_A0&0xFFFF); + break; + case PS2_C1_Reverb+34: + rvb[1].IIR_SRC_A0=(rvb[1].IIR_SRC_A0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+36: + rvb[1].IIR_SRC_A1=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_SRC_A1&0xFFFF); + break; + case PS2_C1_Reverb+38: + rvb[1].IIR_SRC_A1=(rvb[1].IIR_SRC_A1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+40: + rvb[1].IIR_DEST_B0=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_DEST_B0&0xFFFF); + break; + case PS2_C1_Reverb+42: + rvb[1].IIR_DEST_B0=(rvb[1].IIR_DEST_B0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+44: + rvb[1].IIR_DEST_B1=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_DEST_B1&0xFFFF); + break; + case PS2_C1_Reverb+46: + rvb[1].IIR_DEST_B1=(rvb[1].IIR_DEST_B1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+48: + rvb[1].ACC_SRC_C0=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_C0&0xFFFF); + break; + case PS2_C1_Reverb+50: + rvb[1].ACC_SRC_C0=(rvb[1].ACC_SRC_C0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+52: + rvb[1].ACC_SRC_C1=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_C1&0xFFFF); + break; + case PS2_C1_Reverb+54: + rvb[1].ACC_SRC_C1=(rvb[1].ACC_SRC_C1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+56: + rvb[1].ACC_SRC_D0=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_D0&0xFFFF); + break; + case PS2_C1_Reverb+58: + rvb[1].ACC_SRC_D0=(rvb[1].ACC_SRC_D0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+60: + rvb[1].ACC_SRC_D1=(((unsigned long)val&0x3f)<<16)|(rvb[1].ACC_SRC_D1&0xFFFF); + break; + case PS2_C1_Reverb+62: + rvb[1].ACC_SRC_D1=(rvb[1].ACC_SRC_D1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+64: + rvb[1].IIR_SRC_B1=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_SRC_B1&0xFFFF); + break; + case PS2_C1_Reverb+66: + rvb[1].IIR_SRC_B1=(rvb[1].IIR_SRC_B1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+68: + rvb[1].IIR_SRC_B0=(((unsigned long)val&0x3f)<<16)|(rvb[1].IIR_SRC_B0&0xFFFF); + break; + case PS2_C1_Reverb+70: + rvb[1].IIR_SRC_B0=(rvb[1].IIR_SRC_B0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+72: + rvb[1].MIX_DEST_A0=(((unsigned long)val&0x3f)<<16)|(rvb[1].MIX_DEST_A0&0xFFFF); + break; + case PS2_C1_Reverb+74: + rvb[1].MIX_DEST_A0=(rvb[1].MIX_DEST_A0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+76: + rvb[1].MIX_DEST_A1=(((unsigned long)val&0x3f)<<16)|(rvb[1].MIX_DEST_A1&0xFFFF); + break; + case PS2_C1_Reverb+78: + rvb[1].MIX_DEST_A1=(rvb[1].MIX_DEST_A1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+80: + rvb[1].MIX_DEST_B0=(((unsigned long)val&0x3f)<<16)|(rvb[1].MIX_DEST_B0&0xFFFF); + break; + case PS2_C1_Reverb+82: + rvb[1].MIX_DEST_B0=(rvb[1].MIX_DEST_B0 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_Reverb+84: + rvb[1].MIX_DEST_B1=(((unsigned long)val&0x3f)<<16)|(rvb[1].MIX_DEST_B1&0xFFFF); + break; + case PS2_C1_Reverb+86: + rvb[1].MIX_DEST_B1=(rvb[1].MIX_DEST_B1 & 0x3f0000) | ((val) & 0xFFFF); + break; + case PS2_C1_ReverbX+0: rvb[1].IIR_ALPHA=(short)val; break; + case PS2_C1_ReverbX+2: rvb[1].ACC_COEF_A=(short)val; break; + case PS2_C1_ReverbX+4: rvb[1].ACC_COEF_B=(short)val; break; + case PS2_C1_ReverbX+6: rvb[1].ACC_COEF_C=(short)val; break; + case PS2_C1_ReverbX+8: rvb[1].ACC_COEF_D=(short)val; break; + case PS2_C1_ReverbX+10: rvb[1].IIR_COEF=(short)val; break; + case PS2_C1_ReverbX+12: rvb[1].FB_ALPHA=(short)val; break; + case PS2_C1_ReverbX+14: rvb[1].FB_X=(short)val; break; + case PS2_C1_ReverbX+16: rvb[1].IN_COEF_L=(short)val; break; + case PS2_C1_ReverbX+18: rvb[1].IN_COEF_R=(short)val; break; + case PS2_SPDIF_OUT: +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG SPDIF_OUT Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,val); +#endif + break; + case PS2_SPDIF_MODE: +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG SPDIF_MODE Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,val); +#endif + break; + case PS2_SPDIF_MEDIA: +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG SPDIF_OUT Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,val); +#endif + break; + case PS2_SPDIF_COPY: +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG SPDIF_COPY Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,val); +#endif + break; + default: //All other writes +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("W_REG Unknown Register Addr %X Value %X\r\n",reg&0xFFFF,val); +#endif + break; + } + + iSpuAsyncWait=0; + +} + +//////////////////////////////////////////////////////////////////////// +// READ REGISTER: called by main emu +//////////////////////////////////////////////////////////////////////// +EXPORT_GCC unsigned short CALLBACK SPU2read(unsigned long reg) +{ + long r=reg&0xffff; + unsigned int ret = 0; + +if(spuCtrl2[0]&0x40 && spuIrq2[0] == r){ + //regArea[0x7C0] |= 0x4; + regArea[PS2_IRQINFO] |= 4; + irqCallbackSPU2(); + } +if(spuCtrl2[1]&0x40 && spuIrq2[1] == r){ + //regArea[0x7C0] |= 0x8; + regArea[PS2_IRQINFO] |= 8; + irqCallbackSPU2(); + } + if((r>=0x0000 && r<0x0180)||(r>=0x0400 && r<0x0580)) // some channel info? + { + int addr=0; + int ch=((r & 0x3ff)>>4); + if(r>=0x400) ch+=24; + + switch(r&0x0f) + { + case 0: //Left Volume + ret = s_chan[ch].iLeftVolRaw; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Volume Left - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + case 2: //Right Volume + ret = s_chan[ch].iRightVolRaw; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Volume Right - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + case 4: //Pitch + ret = regArea[r]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Pitch - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + case 6: //ASDR1 + ret = regArea[r]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ASDR1 - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + case 8: //ASDR2 + ret = regArea[r]; + #ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ASDR2 - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + case 10: //Envelope (current) + ret = (unsigned short)(s_chan[ch].ADSRX.EnvelopeVol>>16); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Envelope - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + + } + + }else + if((r>=0x01c0 && r<0x02E0)||(r>=0x05c0 && r<0x06E0)) // some channel info? + { + int ch=0;unsigned long rx=r; + + ch=((rx & 0x3ff)-0x1c0) / 0xC; + + rx-=ch*0xC; + if(rx>=0x400) {ch+=24;rx-=0x400;} + + switch(rx) + { + case 0x1C0: + ret = (((s_chan[ch].pStart-spuMemC)>>17)&0x3F); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Start Addr Hi - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + case 0x1C2: + ret = (((s_chan[ch].pStart-spuMemC)>>1)&0xFFFF); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Start Addr Lo - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + //------------------------------------------------// + case 0x1C4: + ret = (((s_chan[ch].pLoop-spuMemC)>>17)&0x3F); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Loop Addr Hi - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + case 0x1C6: + ret = (((s_chan[ch].pLoop-spuMemC)>>1)&0xFFFF); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Loop Addr Lo - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + //------------------------------------------------// + case 0x1C8: + ret = ((((s_chan[ch].pCurr)-spuMemC)>>17)&0x3F); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Next Addr Hi - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + case 0x1CA: + ret = ((((s_chan[ch].pCurr)-spuMemC)>>1)&0xFFFF); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Next Addr Lo - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + default: + ret = regArea[rx]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Channel Addr Unknown - Channel %d Core %d Addr %X Val %X\r\n", (ch > 23? (ch - 24) : ch), ch/24, reg&0xFFFF, ret); +#endif + break; + + //------------------------------------------------// + } + }else{ + switch(r) + { + //--------------------------------------------------// + case PS2_C0_SPUend1: + ret = (unsigned short)((dwEndChannel2[0]&0xFFFF)); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ENDX 0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_SPUend2: + ret = (unsigned short)((dwEndChannel2[0]>>16)); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ENDX 1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //--------------------------------------------------// + case PS2_C1_SPUend1: + ret = (unsigned short)((dwEndChannel2[1]&0xFFFF)); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ENDX 0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_SPUend2: + ret = (unsigned short)((dwEndChannel2[1]>>16)); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ENDX 1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //--------------------------------------------------// + case PS2_C0_ATTR: + ret = spuCtrl2[0]; + #ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Core Attr - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //--------------------------------------------------// + case PS2_C1_ATTR: + ret = spuCtrl2[1]; + #ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Core Attr - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //--------------------------------------------------// + case PS2_C0_SPUstat: + ret = spuStat2[0]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG SPU Status - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //--------------------------------------------------// + case PS2_C1_SPUstat: + ret = spuStat2[1]; + #ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG SPU Status - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //--------------------------------------------------// + case PS2_C0_SPUdata: + { + unsigned short s=spuMem[spuAddr2[0]]; + + if(spuCtrl2[0]&0x40 && spuIrq2[0] == spuAddr2[0]){ + regArea[0x7C0] |= 0x4; + regArea[PS2_IRQINFO] |= 4; + irqCallbackSPU2(); + } + spuAddr2[0]++; + if(spuAddr2[0]>0xFFFFF) spuAddr2[0] = 0; + spuStat2[0]|=0x80; + spuCtrl2[0]&=~0x30; + ret = s; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG SPU Data - Core 0 Addr %X SSA %x Val %X\r\n", reg&0xFFFF, spuAddr2[0]-1, ret); +#endif + } + break; + //--------------------------------------------------// + case PS2_C1_SPUdata: + { + unsigned short s=spuMem[spuAddr2[1]]; + + if(spuCtrl2[1]&0x40 && spuIrq2[1] == spuAddr2[1]){ + regArea[0x7C0] |= 0x8; + regArea[PS2_IRQINFO] |= 8; + irqCallbackSPU2(); + } + spuAddr2[1]++; + if(spuAddr2[1]>0xFFFFF) spuAddr2[1] = 0; + spuStat2[1]|=0x80; + spuCtrl2[1]&=~0x30; + ret = s; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG SPU Data - Core 1 Addr %X SSA %x Val %X\r\n", reg&0xFFFF, spuAddr2[1]-1, ret); +#endif + } + break; + //--------------------------------------------------// + case PS2_C0_SPUaddr_Hi: + ret = (unsigned short)((spuAddr2[0]>>16)&0x3F); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG TSAH - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_SPUaddr_Lo: + ret = (unsigned short)((spuAddr2[0]&0xFFFF)); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG TSAL - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //--------------------------------------------------// + case PS2_C1_SPUaddr_Hi: + ret = (unsigned short)((spuAddr2[1]>>16)&0x3F); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG TSAH - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_SPUaddr_Lo: + ret = (unsigned short)((spuAddr2[1]&0xFFFF)); +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG TSAL - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_ReverbAEnd_Hi: + ret = regArea[PS2_C0_ReverbAEnd_Hi]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG EEAH - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_ReverbAEnd_Hi: + ret = regArea[PS2_C1_ReverbAEnd_Hi]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG EEAH - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_ReverbAddr_Lo: + ret = regArea[PS2_C0_ReverbAddr_Lo]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ESAL - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + + case PS2_C1_ReverbAddr_Lo: + ret = regArea[PS2_C1_ReverbAddr_Lo]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ESAL - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_IRQINFO: + ret = regArea[PS2_IRQINFO]; + // regArea[PS2_IRQINFO] = 0; // clear +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG IRQINFO - Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_ADMAS: + ret = regArea[(PS2_C0_ADMAS)]; + ///regArea[(0x344)>>1]&= ~0x80; + //regArea[(0x744)>>1]&= ~0x80; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ADMA STAT - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_ADMAS: + ret = regArea[(PS2_C1_ADMAS)]; + //regArea[(0x344)>>1]&= ~0x80; + //regArea[(0x744)>>1]&= ~0x80; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG ADMA STAT - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //--------------------------------------------------// + case PS2_C0_SPUrvolL: + ret = rvb[0].VolLeft; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG EVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUrvolR: + ret = rvb[0].VolRight; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG EVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUrvolL: + ret = rvb[1].VolLeft; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG EVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUrvolR: + ret = rvb[1].VolRight; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG EVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUon1: + ret = regArea[PS2_C0_SPUon1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG KON0 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUon2: + ret = regArea[PS2_C0_SPUon2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG KON1 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUon1: + ret = regArea[PS2_C1_SPUon1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG KON0 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUon2: + ret = regArea[PS2_C1_SPUon2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG KON1 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUoff1: + ret = regArea[PS2_C0_SPUoff1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG KOF0 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_SPUoff2: + ret = regArea[PS2_C0_SPUoff2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG KOF1 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUoff1: + ret = regArea[PS2_C1_SPUoff1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG KOF0 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_SPUoff2: + ret = regArea[PS2_C1_SPUoff2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG KOF1 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_FMod1: + ret = regArea[PS2_C0_FMod1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG PMON0 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_FMod2: + ret = regArea[PS2_C0_FMod2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG PMON1 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_FMod1: + ret = regArea[PS2_C1_FMod1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG PMON0 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_FMod2: + ret = regArea[PS2_C1_FMod2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG PMON1 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_Noise1: + ret = regArea[PS2_C0_Noise1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG NON0 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_Noise2: + ret = regArea[PS2_C0_Noise2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG NON1 - Core 0 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_Noise1: + ret = regArea[PS2_C1_Noise1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG NON0 - Core 1 Addr %X Val %X - Not Implemented!\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_Noise2: + ret = regArea[PS2_C1_Noise2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG NON1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_AVOLL: + ret = regArea[PS2_C0_AVOLL]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG AVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_AVOLR: + ret = regArea[PS2_C0_AVOLR]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG AVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_AVOLL: + ret = regArea[PS2_C1_AVOLL]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG AVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_AVOLR: + ret = regArea[PS2_C1_AVOLR]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG AVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_MVOLL: + ret = regArea[PS2_C0_MVOLL]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG MVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_MVOLR: + ret = regArea[PS2_C0_MVOLR]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG MVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_MVOLL: + regArea[PS2_C0_MVOLL]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG MVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_MVOLR: + ret = regArea[PS2_C0_MVOLR]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG MVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + + case PS2_C0_BVOLL: + ret = regArea[PS2_C0_BVOLL]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG BVOL Left - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_BVOLR: + ret = regArea[PS2_C0_BVOLR]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG BVOL Right - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_BVOLL: + ret = regArea[PS2_C1_BVOLL]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG BVOL Left - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_BVOLR: + ret = regArea[PS2_C1_BVOLR]; + #ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG BVOL Right - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_MMIX: + ret = regArea[PS2_C0_MMIX]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG MMIX - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C1_MMIX: + ret = regArea[PS2_C1_MMIX]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG MMIX - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_C0_DryL1: + ret = regArea[PS2_C0_DryL1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXL0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_DryL2: + ret = regArea[PS2_C0_DryL2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXL1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_DryL1: + ret = regArea[PS2_C1_DryL1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXL0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_DryL2: + ret = regArea[PS2_C1_DryL2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXL1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_DryR1: + ret = regArea[PS2_C0_DryR1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXR0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_DryR2: + ret = regArea[PS2_C0_DryR2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXR1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_DryR1: + ret = regArea[PS2_C1_DryR1]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXR0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_DryR2: + ret = regArea[PS2_C1_DryR2]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXR1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_RVBon1_L: + ret = regArea[PS2_C0_RVBon1_L]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXEL0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_RVBon2_L: + ret = regArea[PS2_C0_RVBon2_L]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXEL1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_RVBon1_L: + ret = regArea[PS2_C1_RVBon1_L]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXEL0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_RVBon2_L: + ret = regArea[PS2_C1_RVBon2_L]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXEL1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_RVBon1_R: + ret = regArea[PS2_C0_RVBon1_R]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXER0 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C0_RVBon2_R: + ret = regArea[PS2_C0_RVBon2_R]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXER1 - Core 0 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_RVBon1_R: + ret = regArea[PS2_C1_RVBon1_R]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXER0 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + //-------------------------------------------------// + case PS2_C1_RVBon2_R: + ret = regArea[PS2_C1_RVBon2_R]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG VMIXER1 - Core 1 Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + case PS2_SPDIF_OUT: + ret = regArea[PS2_SPDIF_OUT]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG SPDIF_OUT Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,ret); +#endif + break; + case PS2_SPDIF_MODE: + ret = regArea[PS2_SPDIF_MODE]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG SPDIF_MODE Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,ret); +#endif + break; + case PS2_SPDIF_MEDIA: + ret = regArea[PS2_SPDIF_MEDIA]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG SPDIF_OUT Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,ret); +#endif + break; + case PS2_SPDIF_COPY: + ret = regArea[PS2_SPDIF_COPY]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG SPDIF_COPY Addr %X Value %X - Not Implemented!\r\n",reg&0xFFFF,ret); +#endif + break; + default: + ret = regArea[r]; +#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG Unknown Register - Addr %X Val %X\r\n", reg&0xFFFF, ret); +#endif + break; + } + /*#ifdef _WINDOWS + if(iDebugMode==1) logprintf("R_REG %X Val %X\r\n",reg&0xFFFF, ret); +#endif*/ + } + + + return ret; +} + +//////////////////////////////////////////////////////////////////////// +// SOUND ON register write +//////////////////////////////////////////////////////////////////////// + +void SoundOn(int start,int end,unsigned short val) // SOUND ON PSX COMAND +{ + int ch; + + for(ch=start;ch>=1) // loop channels + { + if((val&1) && s_chan[ch].pStart) // mmm... start has to be set before key on !?! + { + //s_chan[ch].bStop = 0; + if(ch > 24){ + int tempchan = ch-24; + if(tempchan > 15) { + regArea[PS2_C1_SPUoff2] &= ~(1<<(tempchan-16)); + }else{ + regArea[PS2_C1_SPUoff1] &= ~(1< 15) { + regArea[PS2_C0_SPUoff2] &= ~(1<<(tempchan-16)); + }else{ + regArea[PS2_C0_SPUoff1] &= ~(1<>=1) // loop channels + { + if(val&1) // && s_chan[i].bOn) mmm... + { + if(ch > 24){ + int tempchan = ch-24; + if(tempchan > 15) { + regArea[PS2_C1_SPUon2] &= ~(1<<(tempchan-16)); + }else{ + regArea[PS2_C1_SPUon1] &= ~(1< 15) { + regArea[PS2_C0_SPUon2] &= ~(1<<(tempchan-16)); + }else{ + regArea[PS2_C0_SPUon1] &= ~(1<>=1) // loop channels + { + if(val&1) // -> fmod on/off + { + if(ch>0) + { + s_chan[ch].bFMod=1; // --> sound channel + s_chan[ch-1].bFMod=2; // --> freq channel + } + } + else + { + s_chan[ch].bFMod=0; // --> turn off fmod + } + } +} + +//////////////////////////////////////////////////////////////////////// +// NOISE register write +//////////////////////////////////////////////////////////////////////// + +void NoiseOn(int start,int end,unsigned short val) // NOISE ON PSX COMMAND +{ + int ch; + + for(ch=start;ch>=1) // loop channels + { + if(val&1) // -> noise on/off + { + s_chan[ch].bNoise=1; + } + else + { + s_chan[ch].bNoise=0; + } + } +} + +//////////////////////////////////////////////////////////////////////// +// LEFT VOLUME register write +//////////////////////////////////////////////////////////////////////// + +// please note: sweep and phase invert are wrong... but I've never seen +// them used + +void SetVolumeL(unsigned char ch,short vol) // LEFT VOLUME +{ + s_chan[ch].iLeftVolRaw=vol; + + if(vol&0x8000) // sweep? + { + short sInc=1; // -> sweep up? + if(vol&0x2000) sInc=-1; // -> or down? + if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this + vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64 + vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half! + vol*=128; + } + else // no sweep: + { + if(vol&0x4000) // -> mmm... phase inverted? have to investigate this + //vol^=0xffff; + vol=0x3fff-(vol&0x3fff); + } + + vol&=0x3fff; + s_chan[ch].iLeftVolume=vol; // store volume +} + +//////////////////////////////////////////////////////////////////////// +// RIGHT VOLUME register write +//////////////////////////////////////////////////////////////////////// + +void SetVolumeR(unsigned char ch,short vol) // RIGHT VOLUME +{ + s_chan[ch].iRightVolRaw=vol; + + if(vol&0x8000) // comments... see above :) + { + short sInc=1; + if(vol&0x2000) sInc=-1; + if(vol&0x1000) vol^=0xffff; + vol=((vol&0x7f)+1)/2; + vol+=vol/(2*sInc); + vol*=128; + } + else + { + if(vol&0x4000) //vol=vol^=0xffff; + vol=0x3fff-(vol&0x3fff); + } + + vol&=0x3fff; + + s_chan[ch].iRightVolume=vol; +} + +//////////////////////////////////////////////////////////////////////// +// PITCH register write +//////////////////////////////////////////////////////////////////////// + +void SetPitch(int ch,unsigned short val) // SET PITCH +{ + int NP; + if(val>0x3fff) NP=0x3fff; // get pitch val + else NP=val; + + s_chan[ch].iRawPitch=NP; + + NP=(48000L*NP)/4096L; // calc frequency(48000Hz) + if(NP<1) NP=1; // some security + s_chan[ch].iActFreq=NP; // store frequency +} + +//////////////////////////////////////////////////////////////////////// +// REVERB register write +//////////////////////////////////////////////////////////////////////// + +void ReverbOn(int start,int end,unsigned short val,int iRight) // REVERB ON PSX COMMAND +{ + int ch; + + for(ch=start;ch>=1) // loop channels + { + if(val&1) // -> reverb on/off + { + if(iRight) s_chan[ch].bReverbR=1; + else s_chan[ch].bReverbL=1; + } + else + { + if(iRight) s_chan[ch].bReverbR=0; + else s_chan[ch].bReverbL=0; + } + } +} + +//////////////////////////////////////////////////////////////////////// +// REVERB START register write +//////////////////////////////////////////////////////////////////////// + +void SetReverbAddr(int core) +{ + long val=spuRvbAddr2[core]; + + if(rvb[core].StartAddr!=val) + { + if(val<=0x27ff) + { + rvb[core].StartAddr=rvb[core].CurrAddr=0; + } + else + { + rvb[core].StartAddr=val; + rvb[core].CurrAddr=rvb[core].StartAddr; + } + } +} + +//////////////////////////////////////////////////////////////////////// +// DRY LEFT/RIGHT per voice switches +//////////////////////////////////////////////////////////////////////// + +void VolumeOn(int start,int end,unsigned short val,int iRight) // VOLUME ON PSX COMMAND +{ + int ch; + + for(ch=start;ch>=1) // loop channels + { + if(val&1) // -> reverb on/off + { + if(iRight) s_chan[ch].bVolumeR=1; + else s_chan[ch].bVolumeL=1; + } + else + { + if(iRight) s_chan[ch].bVolumeR=0; + else s_chan[ch].bVolumeL=0; + } + } +} + + diff --git a/plugins/PeopsSPU2/registers.h b/plugins/PeopsSPU2/registers.h index 6a83201784..9eaaaf2731 100644 --- a/plugins/PeopsSPU2/registers.h +++ b/plugins/PeopsSPU2/registers.h @@ -1,820 +1,820 @@ -/*************************************************************************** - registers.h - description - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2004/04/04 - Pete -// - generic cleanup for the Peops release... register values by Kanodin & -// his team -// -//*************************************************************************// - -//########################################################################### - -#define PS2_C0_SPUaddr_Hi (0x1A8) -#define PS2_C0_SPUaddr_Lo (0x1AA) -#define PS2_C1_SPUaddr_Hi (0x5A8) -#define PS2_C1_SPUaddr_Lo (0x5AA) -#define PS2_C0_SPUdata (0x1AC) -#define PS2_C1_SPUdata (0x5AC) - -#define PS2_C0_SPUDMActrl (0x1AE) -#define PS2_C1_SPUDMActrl (0x5AE) - -#define PS2_C0_SPUstat (0x344) -#define PS2_C1_SPUstat (0x744) -#define PS2_IRQINFO (0x7C2) -#define PS2_C0_ReverbAddr_Hi (0x2E0) -#define PS2_C0_ReverbAddr_Lo (0x2E2) -#define PS2_C1_ReverbAddr_Hi (0x6E0) -#define PS2_C1_ReverbAddr_Lo (0x6E2) - -#define PS2_C0_ReverbAEnd_Hi (0x33C) -#define PS2_C0_ReverbAEnd_Lo (0x33E) -#define PS2_C1_ReverbAEnd_Hi (0x73C) -#define PS2_C1_ReverbAEnd_Lo (0x73E) - -#define PS2_C0_DryL1 (0x188) -#define PS2_C1_DryL1 (0x588) -#define PS2_C0_DryL2 (0x18A) -#define PS2_C1_DryL2 (0x58A) - -#define PS2_C0_DryR1 (0x190) -#define PS2_C1_DryR1 (0x590) -#define PS2_C0_DryR2 (0x192) -#define PS2_C1_DryR2 (0x592) - -#define PS2_C0_ATTR (0x19A) -#define PS2_C1_ATTR (0x59A) -#define PS2_C0_ADMAS (0x1B0) -#define PS2_C1_ADMAS (0x5B0) - -#define PS2_C0_SPUirqAddr_Hi (0x19C) -#define PS2_C0_SPUirqAddr_Lo (0x19E) -#define PS2_C1_SPUirqAddr_Hi (0x59C) -#define PS2_C1_SPUirqAddr_Lo (0x59E) -#define PS2_C0_SPUrvolL (0x764) -#define PS2_C0_SPUrvolR (0x766) -#define PS2_C1_SPUrvolL (0x028 + 0x764) -#define PS2_C1_SPUrvolR (0x028 + 0x766) -#define PS2_C0_SPUon1 (0x1A0) -#define PS2_C0_SPUon2 (0x1A2) -#define PS2_C1_SPUon1 (0x5A0) -#define PS2_C1_SPUon2 (0x5A2) -#define PS2_C0_SPUoff1 (0x1A4) -#define PS2_C0_SPUoff2 (0x1A6) -#define PS2_C1_SPUoff1 (0x5A4) -#define PS2_C1_SPUoff2 (0x5A6) -#define PS2_C0_FMod1 (0x180) -#define PS2_C0_FMod2 (0x182) -#define PS2_C1_FMod1 (0x580) -#define PS2_C1_FMod2 (0x582) -#define PS2_C0_Noise1 (0x184) -#define PS2_C0_Noise2 (0x186) -#define PS2_C1_Noise1 (0x584) -#define PS2_C1_Noise2 (0x586) - -#define PS2_C0_RVBon1_L (0x18C) -#define PS2_C0_RVBon2_L (0x18E) -#define PS2_C0_RVBon1_R (0x194) -#define PS2_C0_RVBon2_R (0x196) - -#define PS2_C1_RVBon1_L (0x58C) -#define PS2_C1_RVBon2_L (0x58E) -#define PS2_C1_RVBon1_R (0x594) -#define PS2_C1_RVBon2_R (0x596) -#define PS2_C0_Reverb (0x2E4) -#define PS2_C1_Reverb (0x6E4) -#define PS2_C0_ReverbX (0x774) -#define PS2_C1_ReverbX (0x028 + 0x774) -#define PS2_C0_SPUend1 (0x340) -#define PS2_C0_SPUend2 (0x342) -#define PS2_C1_SPUend1 (0x740) -#define PS2_C1_SPUend2 (0x742) -#define PS2_C0_AVOLL (0x768) // Disabled really, but games read it -#define PS2_C0_AVOLR (0x76A) // In for logging purposes -#define PS2_C1_AVOLL (0x790) // core external input volume (left) core 1 -#define PS2_C1_AVOLR (0x792) // core external input volume (right) core 1 -#define PS2_C0_BVOLL (0x76C) -#define PS2_C0_BVOLR (0x76E) -#define PS2_C1_BVOLL (0x794) -#define PS2_C1_BVOLR (0x796) -#define PS2_C0_MMIX (0x198) -#define PS2_C1_MMIX (0x598) - -#define PS2_C0_MVOLL (0x760) -#define PS2_C0_MVOLR (0x762) -#define PS2_C1_MVOLL (0x788) -#define PS2_C1_MVOLR (0x78A) - -// CORE 1 only - -#define PS2_SPDIF_OUT 0x7C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass -#define PS2_SPDIF_MODE 0x7C6 -#define PS2_SPDIF_MEDIA 0x7C8 // SPDIF Media: 'CD'/DVD -#define PS2_SPDIF_COPY 0x7CA // SPDIF Copy Protection - -//########################################################################### - -/* - Included the info received in Regs.txt list by Neill Corlett - Kanodin - - Voice parameters: - SD_VP_VOLL, SD_VP_VOLR - Volume left/right per voice. Assuming identical to PS1. - SD_VP_PITCH - Pitch scaler 0000-3FFF. Assuming identical to PS1. - SD_VP_ADSR1, SD_VP_ADSR1 - Envelope data. Bitfields are documented as identical to PS1. - SD_VP_ENVX - Current envelope value. Assuming identical to PS1. - SD_VP_VOLXL, SD_VP_VOLXR - Current voice volume left/right. Does not exist on the PS1. - Guessing that this is handy for the increase/decrease modes. - - Voice addresses: - - SD_VA_SSA - Sample start address; assuming identical to PS1 - SD_VA_LSAX - Loop start address; assuming identical to PS1 - SD_VA_NAX - Seems to be documented as the current playing address. - Does not exist on PS1. - - Switches: - - SD_S_PMON - Pitch mod; assuming identical to PS1 - SD_S_NON - Noise; assuming identical to PS1 - SD_S_VMIXL, SD_S_VMIXR - Voice mix L/R. Guessing this is just a separate L/R version - of the "voice enable" bits on the PS1. - SD_S_VMIXEL, SD_S_VMIXER - Voice effect mix L/R. Guessing this is just a separate L/R - version of the "voice reverb enable" bits on the PS1. - SD_S_KON, SD_S_KOFF - Key on/off; assuming identical to PS1 - - - Addresses: - - SD_A_TSA - Transfer start address; assuming identical to PS1 - SD_A_ESA - Effect start address - this is probably analogous to the - PS1's reverb work area start address - SD_A_EEA - Effect end address - this would've been fixed to 0x7FFFF on - the PS1; settable in 128K increments on the PS2. - SD_A_IRQA - IRQ address; assuming identical to PS1 - - Volume parameters: - - SD_P_MVOLL, SD_P_MVOLR - Master volume L/R; assuming identical to PS1 - SD_P_EVOLL, SD_P_EVOLR - Effect volume L/R; assuming analogous to RVOL on the PS1 - SD_P_AVOLL, SD_P_AVOLR - External input volume L/R - This is probably where CORE0 connects to CORE1 - SD_P_BVOLL, SD_P_BVOLR - Sound data input volume - perhaps this is the volume of - the raw PCM auto-DMA input? analogous to CD input volume? - SD_P_MVOLXL, SD_P_MVOLXR - Current master volume L/R; seems self-explanatory - - SD_P_MMIX - Mixer / effect enable bits. - bit 11 = MSNDL = voice output dry L - 10 = MSNDR = voice output dry R - 9 = MSNDEL = voice output wet L - 8 = MSNDER = voice output wet R - 7 = MINL = sound data input dry L - 6 = MINR = sound data input dry R - 5 = MINEL = sound data input wet L - 4 = MINER = sound data input wet R - 3 = SINL = core external input dry L - 2 = SINR = core external input dry R - 1 = SINEL = core external input wet L - 0 = SINER = core external input wet R - -Core attributes (SD_C) - - bit 4..5 - DMA related - bit 6 - IRQ enable - bit 7 - effect enable (reverb enable) - bit 13..8 - noise clock - bit 14 - mute - - - if you READ the two DMA related bits, if either are set, the channel is - considered "busy" by sceSdVoiceTrans - - - -Reverb parameters: - - Same as PS1 reverb (I used the names from my reverb doc). - - -Other PS2 IOP notes - - There's two DMA controllers: - The original one at 1F801080-1F8010FF (channels 0-6) - A new one at 1F801500-1F80157F (channels 7-13) - - They appear to function the same way - 7 channels each. - - SPU CORE0's DMA channel is 4 as per usual - SPU CORE1's DMA channel is 7 - -DMA channel 10 is SIF - - Original INTR controller at 1F801000-1F80107F - - All interrupt handling seems to be done using the old INTR, but - with some new bits defined: - - - - Reading from 1F801078 masks interrupts and returns 1 if they weren't - masked before. Writing 1 to 1F801078 re-enables interrupts. - Writing 0 doesn't. Maybe it was like that on the original PS1 too. - -Six root counters: - - RTC# address sources size prescale interrupt# -0 0x1F801100 sysclock,pixel 16 bit 1 only 4 -1 0x1F801110 sysclock,hline 16 bit 1 only 5 -2 0x1F801120 sysclock 16 bit 1,8 6 -3 0x1F801480 sysclock,hline 32 bit 1 only 14 -4 0x1F801490 sysclock 32 bit 1,8,16,256 15 -5 0x1F8014A0 sysclock 32 bit 1,8,16,256 16 - -Count (0x0) and Compare (0x8) registers work as before, only with more bits -in the new counters. - -Mode (0x4) works like this when written: - - bits 0..2 gate - bit 3 reset on target - bit 4 target interrupt enable - bit 5 overflow interrupt enable - bit 6 master enable (?) - bit 7 ? - bit 8 clock select - bit 9 prescale (OLD) - bit 10..12 ? - bit 13..14 prescale (NEW) - bit 15 ? always set to 1 - -Gate: - TM_NO_GATE 000 - TM_GATE_ON_Count 001 - TM_GATE_ON_ClearStart 011 - TM_GATE_ON_Clear_OFF_Start 101 - TM_GATE_ON_Start 111 - - V-blank ----+ +----------------------------+ +------ - | | | | - | | | | - +----+ +----+ - TM_NO_GATE: - - 0================================>============ - - TM_GATE_ON_Count: - - <---->0==========================><---->0===== - - TM_GATE_ON_ClearStart: - - 0====>0================================>0===== - - TM_GATE_ON_Clear_OFF_Start: - - 0====><-------------------------->0====><----- - - TM_GATE_ON_Start: - - <---->0==========================>============ - - reset on target: if set, counter resets to 0 when Compare value is reached - - target interrupt enable: if set, interrupt when Compare value is reached - overflow interrupt enable: if set, interrupt when counter overflows - - master enable: if this bit is clear, the timer should do nothing. - - clock select: for counters 0, 1, and 3, setting this will select the alternate - counter (pixel or hline) - - prescale (OLD): for counter 2 only. set this to prescale (divide) by 8. - - prescale (NEW): for counters 4 and 5 only: - - 00 = prescale by 1 - 01 = prescale by 8 - 10 = prescale by 16 - 11 = prescale by 256 - -Writing 0x4 also clears the counter. (I think.) - -When 0x4 is read, it becomes Status: - - bit 0..10 ? - bit 11 compare value was reached - bit 12 count overflowed - bit 13..15 ? - -Reading probably clears these bits. - - - - 1F8014B0 (word) - timer-related but otherwise unknown - 1F8014C0 (word) - timer-related but otherwise unknown - - - don't currently know how the interrupts work for DMA ch7 yet - - 1F801060 (word) - address of some kind. - - 1F801450 (word) - - if bit 3 is SET, we're in PS1 mode. - if bit 3 is CLEAR, we're in PS2 IOP mode. - - 1F802070 (byte) - unknown. status byte of some kind? visible to EE? - - 1D000000-1D00007F (?) - SIF related - - 1D000020 (word) - read counter of some sort? - sceSifInit waits for bit 0x10000 of this to be set. - 1D000030 (word) - read counter of some sort? - 1D000040 (word) - read bits 0x20, 0x40 mean something - 1D000060 (word) - used to detect whether the SIF interface exists - read must be 0x1D000060, or the top 20 bits must be zero -*/ - -/* - -// DirectX Audio SPU2 Driver for PCSX2 -// audio.c by J.F. and Kanodin (hooper1@cox.net) -// -// Copyright 2003 J.F. and Kanodin, and distributed under the -// terms of the GNU General Public License, v2 or later. -// http://www.gnu.org/copyleft/gpl.html. - -Included these just in case you need them J.F. - Kanodin - -// Core Start Addresses -#define CORE0 0x1f900000 -#define CORE1 0x1f900400 - - - #define IOP_INT_VBLANK (1<<0) - #define IOP_INT_GM (1<<1) - #define IOP_INT_CDROM (1<<2) - #define IOP_INT_DMA (1<<3) - #define IOP_INT_RTC0 (1<<4) - #define IOP_INT_RTC1 (1<<5) - #define IOP_INT_RTC2 (1<<6) - #define IOP_INT_SIO0 (1<<7) - #define IOP_INT_SIO1 (1<<8) - #define IOP_INT_SPU (1<<9) - #define IOP_INT_PIO (1<<10) - #define IOP_INT_EVBLANK (1<<11) - #define IOP_INT_DVD (1<<12) - #define IOP_INT_PCMCIA (1<<13) - #define IOP_INT_RTC3 (1<<14) - #define IOP_INT_RTC4 (1<<15) - #define IOP_INT_RTC5 (1<<16) - #define IOP_INT_SIO2 (1<<17) - #define IOP_INT_HTR0 (1<<18) - #define IOP_INT_HTR1 (1<<19) - #define IOP_INT_HTR2 (1<<20) - #define IOP_INT_HTR3 (1<<21) - #define IOP_INT_USB (1<<22) - #define IOP_INT_EXTR (1<<23) - #define IOP_INT_FWRE (1<<24) - #define IOP_INT_FDMA (1<<25) - -// CORE0 => +0x000, CORE1 => +0x400 - -// individual voice parameter regs - -#define VP_VOLL(cr, vc) (0x400 * cr + (vc << 4)) // voice volume (left) -#define VP_VOLR(cr, vc) (0x400 * cr + 0x002 + (vc << 4)) // voice volume (right) -#define VP_PITCH(cr, vc) (0x400 * cr + 0x004 + (vc << 4)) // voice pitch -#define VP_ADSR1(cr, vc) (0x400 * cr + 0x006 + (vc << 4)) // voice envelope (AR, DR, SL) -#define VP_ADSR2(cr, vc) (0x400 * cr + 0x008 + (vc << 4)) // voice envelope (SR, RR) -#define VP_ENVX(cr, vc) (0x400 * cr + 0x00A + (vc << 4)) // voice envelope (current value) -#define VP_VOLXL(cr, vc) (0x400 * cr + 0x00C + (vc << 4)) // voice volume (current value left) -#define VP_VOLXR(cr, vc) (0x400 * cr + 0x00E + (vc << 4)) // voice volume (current value right) - -#define VA_SSA(cr, vc) (0x400 * cr + 0x1C0 + (vc * 12)) // voice waveform data start address -#define VA_LSAX(cr, vc) (0x400 * cr + 0x1C4 + (vc * 12)) // voice waveform data loop address -#define VA_NAX(cr, vc) (0x400 * cr + 0x1C8 + (vc * 12)) // voice waveform data next address - -// common settings - -#define S_PMON(cr) (0x400 * cr + 0x180) // pitch modulation on -#define S_NON(cr) (0x400 * cr + 0x184) // noise generator on -#define S_VMIXL(cr) (0x400 * cr + 0x188) // voice output mixing (dry left) -#define S_VMIXEL(cr) (0x400 * cr + 0x18C) // voice output mixing (wet left) -#define S_VMIXR(cr) (0x400 * cr + 0x190) // voice output mixing (dry right) -#define S_VMIXER(cr) (0x400 * cr + 0x194) // voice output mixing (wet right) -#define P_MMIX(cr) (0x400 * cr + 0x198) // output type after voice mixing (See paragraph below) -#define P_ATTR(cr) (0x400 * cr + 0x19A) // core attributes (See paragraph below) -#define A_IRQA(cr) (0x400 * cr + 0x19C) // IRQ address -#define S_KON(cr) (0x400 * cr + 0x1A0) // key on (start voice sound generation) -#define S_KOFF(cr) (0x400 * cr + 0x1A4) // key off (end voice sound generation) -#define A_TSA(cr) (0x400 * cr + 0x1A8) // DMA transfer start address -#define P_DATA(cr) (0x400 * cr + 0x1AC) // DMA data register -#define P_CTRL(cr) (0x400 * cr + 0x1AE) // DMA control register -#define P_ADMAS(cr) (0x400 * cr + 0x1B0) // AutoDMA status - -#define A_ESA(cr) (0x400 * cr + 0x2E0) // effects work area start address - -#define FB_SRC_A(cr) (0x400 * cr + 0x2E4) -#define FB_SRC_B(cr) (0x400 * cr + 0x2E8) -#define IIR_DEST_A0(cr) (0x400 * cr + 0x2EC) -#define IIR_DEST_A1(cr) (0x400 * cr + 0x2F0) -#define ACC_SRC_A0(cr) (0x400 * cr + 0x2F4) -#define ACC_SRC_A1(cr) (0x400 * cr + 0x2F8) -#define ACC_SRC_B0(cr) (0x400 * cr + 0x2FC) - -#define ACC_SRC_B1(cr) (0x400 * cr + 0x300) -#define IIR_SRC_A0(cr) (0x400 * cr + 0x304) -#define IIR_SRC_A1(cr) (0x400 * cr + 0x308) -#define IIR_DEST_B0(cr) (0x400 * cr + 0x30C) -#define IIR_DEST_B1(cr) (0x400 * cr + 0x310) -#define ACC_SRC_C0(cr) (0x400 * cr + 0x314) -#define ACC_SRC_C1(cr) (0x400 * cr + 0x318) - -#define ACC_SRC_D0(cr) (0x400 * cr + 0x31C) -#define ACC_SRC_D1(cr) (0x400 * cr + 0x320) -#define IIR_SRC_B1(cr) (0x400 * cr + 0x324) -#define IIR_SRC_B0(cr) (0x400 * cr + 0x328) -#define MIX_DEST_A0(cr) (0x400 * cr + 0x32C) -#define MIX_DEST_A1(cr) (0x400 * cr + 0x330) -#define MIX_DEST_B0(cr) (0x400 * cr + 0x334) -#define MIX_DEST_B1(cr) (0x400 * cr + 0x338) - -#define A_EEA(cr) (0x400 * cr + 0x33C) // effects work area end address - -#define P_ENDX(cr) (0x400 * cr + 0x340) // voice loop end status -#define P_STAT(cr) (0x400 * cr + 0x344) // DMA status register -#define P_ENDS(cr) (0x400 * cr + 0x346) // ? - -// CORE0 => +0x400, CORE1 => +0x428 - -#define P_MVOLL(cr) (0x28 * cr + 0x760) // master volume (left) -#define P_MVOLR(cr) (0x28 * cr + 0x762) // master volume (right) -#define P_EVOLL(cr) (0x28 * cr + 0x764) // effect return volume (left) -#define P_EVOLR(cr) (0x28 * cr + 0x766) // effect return volume (right) -#define P_AVOLL(cr) (0x28 * cr + 0x768) // core external input volume (left) -#define P_AVOLR(cr) (0x28 * cr + 0x76A) // core external input volume (right) -#define P_BVOLL(cr) (0x28 * cr + 0x76C) // sound data input volume (left) -#define P_BVOLR(cr) (0x28 * cr + 0x76E) // sound data input volume (right) -#define P_MVOLXL(cr) (0x28 * cr + 0x770) // current master volume (left) -#define P_MVOLXR(cr) (0x28 * cr + 0x772) // current master volume (right) - -#define IIR_ALPHA(cr) (0x28 * cr + 0x774) -#define ACC_COEF_A(cr) (0x28 * cr + 0x776) -#define ACC_COEF_B(cr) (0x28 * cr + 0x778) -#define ACC_COEF_C(cr) (0x28 * cr + 0x77A) -#define ACC_COEF_D(cr) (0x28 * cr + 0x77C) -#define IIR_COEF(cr) (0x28 * cr + 0x77E) -#define FB_ALPHA(cr) (0x28 * cr + 0x780) -#define FB_X(cr) (0x28 * cr + 0x782) -#define IN_COEF_L(cr) (0x28 * cr + 0x784) -#define IN_COEF_R(cr) (0x28 * cr + 0x786) - -// CORE1 only => +0x400 - -#define SPDIF_OUT 0x7C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass -#define SPDIF_MODE 0x7C6 -#define SPDIF_MEDIA 0x7C8 // SPDIF Media: 'CD'/DVD -#define SPDIF_COPY 0x7CA // SPDIF Copy Protection - -// PS1 SPU CORE - -// individual voice settings - -#define SPU_VP_PITCH(vc) (0xC04 + (vc << 4)) // voice pitch -#define SPU_VA_SSA(vc) (0xC06 + (vc << 4)) // voice waveform data start address -#define SPU_VP_ADSR(vc) (0xC08 + (vc << 4)) // voice envelope -#define SPU_VA_SSA(vc) (0xC0E + (vc << 4)) // voice waveform data loop address - -// common settings - -#define SPU_P_MVOLL 0xD80 // master volume (left) -#define SPU_P_MVOLR 0xD82 // master volume (right) -#define SPU_P_RVOLL 0xD84 // effect return volume (left) -#define SPU_P_RVOLR 0xD86 // effect return volume (right) -#define SPU_S_KON1 0xD88 // key on -#define SPU_S_KON2 0xD8A // -#define SPU_S_KOFF1 0xD8C // key off -#define SPU_S_KOFF2 0xD8E // -#define SPU_S_PMON1 0xD90 // pitch modulation on -#define SPU_S_PMON2 0xD92 // -#define SPU_S_NON1 0xD94 // noise generator on -#define SPU_S_NON2 0xD96 // -#define SPU_S_RVBON1 0xD98 // effects on -#define SPU_S_RVBON2 0xD9A // -#define SPU_S_MUTE1 0xD9C // voice mute -#define SPU_S_MUTE2 0xD9E // - -#define SPU_A_ESA 0xDA2 // effects work area start -#define SPU_A_IRQA 0xDA4 // IRQ address -#define SPU_A_TSA 0xDA6 // DMA transfer start address -#define SPU_P_DATA 0xDA8 // DMA data register -#define SPU_P_CTRL 0xDAA // DMA control register -#define SPU_P_STAT 0xDAE // DMA status register - -#define SPU_P_CDL 0xDB0 // sound data input volume (left) -#define SPU_P_CDR 0xDB2 // sound data input volume (right) -#define SPU_P_EXTL 0xDB4 // external input volume (left) -#define SPU_P_EXTR 0xDB6 // external input volume (right) - -#define SPU_P_REVERB 0xDC0 // effects control - - -// Individual voice parameter regs CORE 0 -// Only - - -#define VP_VOLL(cr, vc) (0x400 * cr + (vc << 4)) // voice volume (left) -#define VP_VOLR(cr, vc) (0x400 * cr + 0x002 + (vc << 4)) // voice volume (right) -#define VP_PITCH(cr, vc) (0x400 * cr + 0x004 + (vc << 4)) // voice pitch -#define VP_ADSR1(cr, vc) (0x400 * cr + 0x006 + (vc << 4)) // voice envelope (AR, DR, SL) -#define VP_ADSR2(cr, vc) (0x400 * cr + 0x008 + (vc << 4)) // voice envelope (SR, RR) -#define VP_ENVX(cr, vc) (0x400 * cr + 0x00A + (vc << 4)) // voice envelope (current value) -#define VP_VOLXL(cr, vc) (0x400 * cr + 0x00C + (vc << 4)) // voice volume (current value left) -#define VP_VOLXR(cr, vc) (0x400 * cr + 0x00E + (vc << 4)) // voice volume (current value right) - -#define VA_SSA(cr, vc) (0x400 * cr + 0x1C0 + (vc * 12)) // voice waveform data start address -#define VA_LSAX(cr, vc) (0x400 * cr + 0x1C4 + (vc * 12)) // voice waveform data loop address -#define VA_NAX(cr, vc) (0x400 * cr + 0x1C8 + (vc * 12)) // voice waveform data next address - - -// CORE 0 Common Settings - - -#define S_PMON(cr) (0x400 * cr + 0x180) // pitch modulation on -#define S_NON(cr) (0x400 * cr + 0x184) // noise generator on -#define S_VMIXL(cr) (0x400 * cr + 0x188) // voice output mixing (dry left) -#define S_VMIXEL(cr) (0x400 * cr + 0x18C) // voice output mixing (wet left) -#define S_VMIXR(cr) (0x400 * cr + 0x190) // voice output mixing (dry right) -#define S_VMIXER(cr) (0x400 * cr + 0x194) // voice output mixing (wet right) -#define P_MMIX(cr) (0x400 * cr + 0x198) // output type after voice mixing (See paragraph below) -#define P_ATTR(cr) (0x400 * cr + 0x19A) // core attributes (See paragraph below) -#define A_IRQA(cr) (0x400 * cr + 0x19C) // IRQ address -#define S_KON(cr) (0x400 * cr + 0x1A0) // key on (start voice sound generation) -#define S_KOFF(cr) (0x400 * cr + 0x1A4) // key off (end voice sound generation) -#define A_TSA(cr) (0x400 * cr + 0x1A8) // DMA transfer start address -#define P_DATA(cr) (0x400 * cr + 0x1AC) // DMA data register -#define P_CTRL(cr) (0x400 * cr + 0x1AE) // DMA control register -#define P_ADMAS(cr) (0x400 * cr + 0x1B0) // AutoDMA status - -#define A_ESA(cr) (0x400 * cr + 0x2E0) // effects work area start address - - -// Core 0 Reverb Addresses - - -#define FB_SRC_A(cr) (0x400 * cr + 0x2E4) -#define FB_SRC_B(cr) (0x400 * cr + 0x2E8) -#define IIR_DEST_A0(cr) (0x400 * cr + 0x2EC) -#define IIR_DEST_A1(cr) (0x400 * cr + 0x2F0) -#define ACC_SRC_A0(cr) (0x400 * cr + 0x2F4) -#define ACC_SRC_A1(cr) (0x400 * cr + 0x2F8) -#define ACC_SRC_B0(cr) (0x400 * cr + 0x2FC) - -#define ACC_SRC_B1(cr) (0x400 * cr + 0x300) -#define IIR_SRC_A0(cr) (0x400 * cr + 0x304) -#define IIR_SRC_A1(cr) (0x400 * cr + 0x308) -#define IIR_DEST_B0(cr) (0x400 * cr + 0x30C) -#define IIR_DEST_B1(cr) (0x400 * cr + 0x310) -#define ACC_SRC_C0(cr) (0x400 * cr + 0x314) -#define ACC_SRC_C1(cr) (0x400 * cr + 0x318) - -#define ACC_SRC_D0(cr) (0x400 * cr + 0x31C) -#define ACC_SRC_D1(cr) (0x400 * cr + 0x320) -#define IIR_SRC_B1(cr) (0x400 * cr + 0x324) -#define IIR_SRC_B0(cr) (0x400 * cr + 0x328) -#define MIX_DEST_A0(cr) (0x400 * cr + 0x32C) -#define MIX_DEST_A1(cr) (0x400 * cr + 0x330) -#define MIX_DEST_B0(cr) (0x400 * cr + 0x334) -#define MIX_DEST_B1(cr) (0x400 * cr + 0x338) - -#define A_EEA(cr) (0x400 * cr + 0x33C) // effects work area end address - -#define P_ENDX(cr) (0x400 * cr + 0x340) // voice loop end status -#define P_STAT(cr) (0x400 * cr + 0x344) // DMA status register -#define P_ENDS(cr) (0x400 * cr + 0x346) // ? - - -// CORE 0 Specific - - -#define P_MVOLL(cr) (0x28 * cr + 0x760) // master volume (left) -#define P_MVOLR(cr) (0x28 * cr + 0x762) // master volume (right) -#define P_EVOLL(cr) (0x28 * cr + 0x764) // effect return volume (left) -#define P_EVOLR(cr) (0x28 * cr + 0x766) // effect return volume (right) -#define P_AVOLL(cr) (0x28 * cr + 0x768) // core external input volume (left) -#define P_AVOLR(cr) (0x28 * cr + 0x76A) // core external input volume (right) -#define P_BVOLL(cr) (0x28 * cr + 0x76C) // sound data input volume (left) -#define P_BVOLR(cr) (0x28 * cr + 0x76E) // sound data input volume (right) -#define P_MVOLXL(cr) (0x28 * cr + 0x770) // current master volume (left) -#define P_MVOLXR(cr) (0x28 * cr + 0x772) // current master volume (right) - - -// More CORE 0 Reverb - - -#define IIR_ALPHA(cr) (0x28 * cr + 0x774) -#define ACC_COEF_A(cr) (0x28 * cr + 0x776) -#define ACC_COEF_B(cr) (0x28 * cr + 0x778) -#define ACC_COEF_C(cr) (0x28 * cr + 0x77A) -#define ACC_COEF_D(cr) (0x28 * cr + 0x77C) -#define IIR_COEF(cr) (0x28 * cr + 0x77E) -#define FB_ALPHA(cr) (0x28 * cr + 0x780) -#define FB_X(cr) (0x28 * cr + 0x782) -#define IN_COEF_L(cr) (0x28 * cr + 0x784) -#define IN_COEF_R(cr) (0x28 * cr + 0x786) - - -// CORE 1 only - -#define SPDIF_OUT 0x7C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass -#define SPDIF_MODE 0x7C6 -#define SPDIF_MEDIA 0x7C8 // SPDIF Media: 'CD'/DVD -#define SPDIF_COPY 0x7CA // SPDIF Copy Protection -*/ - -/* PS1 SPU CORE - -*** The below really isn't needed, only if you *** -*** want to add SPU support to the plugin *** -*** which I see no need to add at this time. *** -*** individual voice settings *** - -#define SPU_VP_PITCH(vc) (0xC04 + (vc << 4)) // voice pitch -#define SPU_VA_SSA(vc) (0xC06 + (vc << 4)) // voice waveform data start address -#define SPU_VP_ADSR(vc) (0xC08 + (vc << 4)) // voice envelope -#define SPU_VA_SSA(vc) (0xC0E + (vc << 4)) // voice waveform data loop address - -// common settings - -#define SPU_P_MVOLL 0xD80 // master volume (left) -#define SPU_P_MVOLR 0xD82 // master volume (right) -#define SPU_P_RVOLL 0xD84 // effect return volume (left) -#define SPU_P_RVOLR 0xD86 // effect return volume (right) -#define SPU_S_KON1 0xD88 // key on -#define SPU_S_KON2 0xD8A // -#define SPU_S_KOFF1 0xD8C // key off -#define SPU_S_KOFF2 0xD8E // -#define SPU_S_PMON1 0xD90 // pitch modulation on -#define SPU_S_PMON2 0xD92 // -#define SPU_S_NON1 0xD94 // noise generator on -#define SPU_S_NON2 0xD96 // -#define SPU_S_RVBON1 0xD98 // effects on -#define SPU_S_RVBON2 0xD9A // -#define SPU_S_MUTE1 0xD9C // voice mute -#define SPU_S_MUTE2 0xD9E // - -#define SPU_A_ESA 0xDA2 // effects work area start -#define SPU_A_IRQA 0xDA4 // IRQ address -#define SPU_A_TSA 0xDA6 // DMA transfer start address -#define SPU_P_DATA 0xDA8 // DMA data register -#define SPU_P_CTRL 0xDAA // DMA control register -#define SPU_P_STAT 0xDAE // DMA status register - -#define SPU_P_CDL 0xDB0 // sound data input volume (left) -#define SPU_P_CDR 0xDB2 // sound data input volume (right) -#define SPU_P_EXTL 0xDB4 // external input volume (left) -#define SPU_P_EXTR 0xDB6 // external input volume (right) - -#define SPU_P_REVERB 0xDC0 // effects control -*/ - -/* -#define H_SPUReverbAddr 0x0da2 -#define H_SPUirqAddr 0x0da4 -#define H_SPUaddr 0x0da6 -#define H_SPUdata 0x0da8 -#define H_SPUctrl 0x0daa -#define H_SPUstat 0x0dae -#define H_SPUmvolL 0x0d80 -#define H_SPUmvolR 0x0d82 -#define H_SPUrvolL 0x0d84 -#define H_SPUrvolR 0x0d86 -#define H_SPUon1 0x0d88 -#define H_SPUon2 0x0d8a -#define H_SPUoff1 0x0d8c -#define H_SPUoff2 0x0d8e -#define H_FMod1 0x0d90 -#define H_FMod2 0x0d92 -#define H_Noise1 0x0d94 -#define H_Noise2 0x0d96 -#define H_RVBon1 0x0d98 -#define H_RVBon2 0x0d9a -#define H_SPUMute1 0x0d9c -#define H_SPUMute2 0x0d9e -#define H_CDLeft 0x0db0 -#define H_CDRight 0x0db2 -#define H_ExtLeft 0x0db4 -#define H_ExtRight 0x0db6 -#define H_Reverb 0x0dc0 -#define H_SPUPitch0 0x0c04 -#define H_SPUPitch1 0x0c14 -#define H_SPUPitch2 0x0c24 -#define H_SPUPitch3 0x0c34 -#define H_SPUPitch4 0x0c44 -#define H_SPUPitch5 0x0c54 -#define H_SPUPitch6 0x0c64 -#define H_SPUPitch7 0x0c74 -#define H_SPUPitch8 0x0c84 -#define H_SPUPitch9 0x0c94 -#define H_SPUPitch10 0x0ca4 -#define H_SPUPitch11 0x0cb4 -#define H_SPUPitch12 0x0cc4 -#define H_SPUPitch13 0x0cd4 -#define H_SPUPitch14 0x0ce4 -#define H_SPUPitch15 0x0cf4 -#define H_SPUPitch16 0x0d04 -#define H_SPUPitch17 0x0d14 -#define H_SPUPitch18 0x0d24 -#define H_SPUPitch19 0x0d34 -#define H_SPUPitch20 0x0d44 -#define H_SPUPitch21 0x0d54 -#define H_SPUPitch22 0x0d64 -#define H_SPUPitch23 0x0d74 - -#define H_SPUStartAdr0 0x0c06 -#define H_SPUStartAdr1 0x0c16 -#define H_SPUStartAdr2 0x0c26 -#define H_SPUStartAdr3 0x0c36 -#define H_SPUStartAdr4 0x0c46 -#define H_SPUStartAdr5 0x0c56 -#define H_SPUStartAdr6 0x0c66 -#define H_SPUStartAdr7 0x0c76 -#define H_SPUStartAdr8 0x0c86 -#define H_SPUStartAdr9 0x0c96 -#define H_SPUStartAdr10 0x0ca6 -#define H_SPUStartAdr11 0x0cb6 -#define H_SPUStartAdr12 0x0cc6 -#define H_SPUStartAdr13 0x0cd6 -#define H_SPUStartAdr14 0x0ce6 -#define H_SPUStartAdr15 0x0cf6 -#define H_SPUStartAdr16 0x0d06 -#define H_SPUStartAdr17 0x0d16 -#define H_SPUStartAdr18 0x0d26 -#define H_SPUStartAdr19 0x0d36 -#define H_SPUStartAdr20 0x0d46 -#define H_SPUStartAdr21 0x0d56 -#define H_SPUStartAdr22 0x0d66 -#define H_SPUStartAdr23 0x0d76 - -#define H_SPULoopAdr0 0x0c0e -#define H_SPULoopAdr1 0x0c1e -#define H_SPULoopAdr2 0x0c2e -#define H_SPULoopAdr3 0x0c3e -#define H_SPULoopAdr4 0x0c4e -#define H_SPULoopAdr5 0x0c5e -#define H_SPULoopAdr6 0x0c6e -#define H_SPULoopAdr7 0x0c7e -#define H_SPULoopAdr8 0x0c8e -#define H_SPULoopAdr9 0x0c9e -#define H_SPULoopAdr10 0x0cae -#define H_SPULoopAdr11 0x0cbe -#define H_SPULoopAdr12 0x0cce -#define H_SPULoopAdr13 0x0cde -#define H_SPULoopAdr14 0x0cee -#define H_SPULoopAdr15 0x0cfe -#define H_SPULoopAdr16 0x0d0e -#define H_SPULoopAdr17 0x0d1e -#define H_SPULoopAdr18 0x0d2e -#define H_SPULoopAdr19 0x0d3e -#define H_SPULoopAdr20 0x0d4e -#define H_SPULoopAdr21 0x0d5e -#define H_SPULoopAdr22 0x0d6e -#define H_SPULoopAdr23 0x0d7e - -#define H_SPU_ADSRLevel0 0x0c08 -#define H_SPU_ADSRLevel1 0x0c18 -#define H_SPU_ADSRLevel2 0x0c28 -#define H_SPU_ADSRLevel3 0x0c38 -#define H_SPU_ADSRLevel4 0x0c48 -#define H_SPU_ADSRLevel5 0x0c58 -#define H_SPU_ADSRLevel6 0x0c68 -#define H_SPU_ADSRLevel7 0x0c78 -#define H_SPU_ADSRLevel8 0x0c88 -#define H_SPU_ADSRLevel9 0x0c98 -#define H_SPU_ADSRLevel10 0x0ca8 -#define H_SPU_ADSRLevel11 0x0cb8 -#define H_SPU_ADSRLevel12 0x0cc8 -#define H_SPU_ADSRLevel13 0x0cd8 -#define H_SPU_ADSRLevel14 0x0ce8 -#define H_SPU_ADSRLevel15 0x0cf8 -#define H_SPU_ADSRLevel16 0x0d08 -#define H_SPU_ADSRLevel17 0x0d18 -#define H_SPU_ADSRLevel18 0x0d28 -#define H_SPU_ADSRLevel19 0x0d38 -#define H_SPU_ADSRLevel20 0x0d48 -#define H_SPU_ADSRLevel21 0x0d58 -#define H_SPU_ADSRLevel22 0x0d68 -#define H_SPU_ADSRLevel23 0x0d78 -*/ +/*************************************************************************** + registers.h - description + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/04/04 - Pete +// - generic cleanup for the Peops release... register values by Kanodin & +// his team +// +//*************************************************************************// + +//########################################################################### + +#define PS2_C0_SPUaddr_Hi (0x1A8) +#define PS2_C0_SPUaddr_Lo (0x1AA) +#define PS2_C1_SPUaddr_Hi (0x5A8) +#define PS2_C1_SPUaddr_Lo (0x5AA) +#define PS2_C0_SPUdata (0x1AC) +#define PS2_C1_SPUdata (0x5AC) + +#define PS2_C0_SPUDMActrl (0x1AE) +#define PS2_C1_SPUDMActrl (0x5AE) + +#define PS2_C0_SPUstat (0x344) +#define PS2_C1_SPUstat (0x744) +#define PS2_IRQINFO (0x7C2) +#define PS2_C0_ReverbAddr_Hi (0x2E0) +#define PS2_C0_ReverbAddr_Lo (0x2E2) +#define PS2_C1_ReverbAddr_Hi (0x6E0) +#define PS2_C1_ReverbAddr_Lo (0x6E2) + +#define PS2_C0_ReverbAEnd_Hi (0x33C) +#define PS2_C0_ReverbAEnd_Lo (0x33E) +#define PS2_C1_ReverbAEnd_Hi (0x73C) +#define PS2_C1_ReverbAEnd_Lo (0x73E) + +#define PS2_C0_DryL1 (0x188) +#define PS2_C1_DryL1 (0x588) +#define PS2_C0_DryL2 (0x18A) +#define PS2_C1_DryL2 (0x58A) + +#define PS2_C0_DryR1 (0x190) +#define PS2_C1_DryR1 (0x590) +#define PS2_C0_DryR2 (0x192) +#define PS2_C1_DryR2 (0x592) + +#define PS2_C0_ATTR (0x19A) +#define PS2_C1_ATTR (0x59A) +#define PS2_C0_ADMAS (0x1B0) +#define PS2_C1_ADMAS (0x5B0) + +#define PS2_C0_SPUirqAddr_Hi (0x19C) +#define PS2_C0_SPUirqAddr_Lo (0x19E) +#define PS2_C1_SPUirqAddr_Hi (0x59C) +#define PS2_C1_SPUirqAddr_Lo (0x59E) +#define PS2_C0_SPUrvolL (0x764) +#define PS2_C0_SPUrvolR (0x766) +#define PS2_C1_SPUrvolL (0x028 + 0x764) +#define PS2_C1_SPUrvolR (0x028 + 0x766) +#define PS2_C0_SPUon1 (0x1A0) +#define PS2_C0_SPUon2 (0x1A2) +#define PS2_C1_SPUon1 (0x5A0) +#define PS2_C1_SPUon2 (0x5A2) +#define PS2_C0_SPUoff1 (0x1A4) +#define PS2_C0_SPUoff2 (0x1A6) +#define PS2_C1_SPUoff1 (0x5A4) +#define PS2_C1_SPUoff2 (0x5A6) +#define PS2_C0_FMod1 (0x180) +#define PS2_C0_FMod2 (0x182) +#define PS2_C1_FMod1 (0x580) +#define PS2_C1_FMod2 (0x582) +#define PS2_C0_Noise1 (0x184) +#define PS2_C0_Noise2 (0x186) +#define PS2_C1_Noise1 (0x584) +#define PS2_C1_Noise2 (0x586) + +#define PS2_C0_RVBon1_L (0x18C) +#define PS2_C0_RVBon2_L (0x18E) +#define PS2_C0_RVBon1_R (0x194) +#define PS2_C0_RVBon2_R (0x196) + +#define PS2_C1_RVBon1_L (0x58C) +#define PS2_C1_RVBon2_L (0x58E) +#define PS2_C1_RVBon1_R (0x594) +#define PS2_C1_RVBon2_R (0x596) +#define PS2_C0_Reverb (0x2E4) +#define PS2_C1_Reverb (0x6E4) +#define PS2_C0_ReverbX (0x774) +#define PS2_C1_ReverbX (0x028 + 0x774) +#define PS2_C0_SPUend1 (0x340) +#define PS2_C0_SPUend2 (0x342) +#define PS2_C1_SPUend1 (0x740) +#define PS2_C1_SPUend2 (0x742) +#define PS2_C0_AVOLL (0x768) // Disabled really, but games read it +#define PS2_C0_AVOLR (0x76A) // In for logging purposes +#define PS2_C1_AVOLL (0x790) // core external input volume (left) core 1 +#define PS2_C1_AVOLR (0x792) // core external input volume (right) core 1 +#define PS2_C0_BVOLL (0x76C) +#define PS2_C0_BVOLR (0x76E) +#define PS2_C1_BVOLL (0x794) +#define PS2_C1_BVOLR (0x796) +#define PS2_C0_MMIX (0x198) +#define PS2_C1_MMIX (0x598) + +#define PS2_C0_MVOLL (0x760) +#define PS2_C0_MVOLR (0x762) +#define PS2_C1_MVOLL (0x788) +#define PS2_C1_MVOLR (0x78A) + +// CORE 1 only + +#define PS2_SPDIF_OUT 0x7C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass +#define PS2_SPDIF_MODE 0x7C6 +#define PS2_SPDIF_MEDIA 0x7C8 // SPDIF Media: 'CD'/DVD +#define PS2_SPDIF_COPY 0x7CA // SPDIF Copy Protection + +//########################################################################### + +/* + Included the info received in Regs.txt list by Neill Corlett - Kanodin + + Voice parameters: + SD_VP_VOLL, SD_VP_VOLR - Volume left/right per voice. Assuming identical to PS1. + SD_VP_PITCH - Pitch scaler 0000-3FFF. Assuming identical to PS1. + SD_VP_ADSR1, SD_VP_ADSR1 - Envelope data. Bitfields are documented as identical to PS1. + SD_VP_ENVX - Current envelope value. Assuming identical to PS1. + SD_VP_VOLXL, SD_VP_VOLXR - Current voice volume left/right. Does not exist on the PS1. + Guessing that this is handy for the increase/decrease modes. + + Voice addresses: + + SD_VA_SSA - Sample start address; assuming identical to PS1 + SD_VA_LSAX - Loop start address; assuming identical to PS1 + SD_VA_NAX - Seems to be documented as the current playing address. + Does not exist on PS1. + + Switches: + + SD_S_PMON - Pitch mod; assuming identical to PS1 + SD_S_NON - Noise; assuming identical to PS1 + SD_S_VMIXL, SD_S_VMIXR - Voice mix L/R. Guessing this is just a separate L/R version + of the "voice enable" bits on the PS1. + SD_S_VMIXEL, SD_S_VMIXER - Voice effect mix L/R. Guessing this is just a separate L/R + version of the "voice reverb enable" bits on the PS1. + SD_S_KON, SD_S_KOFF - Key on/off; assuming identical to PS1 + + + Addresses: + + SD_A_TSA - Transfer start address; assuming identical to PS1 + SD_A_ESA - Effect start address - this is probably analogous to the + PS1's reverb work area start address + SD_A_EEA - Effect end address - this would've been fixed to 0x7FFFF on + the PS1; settable in 128K increments on the PS2. + SD_A_IRQA - IRQ address; assuming identical to PS1 + + Volume parameters: + + SD_P_MVOLL, SD_P_MVOLR - Master volume L/R; assuming identical to PS1 + SD_P_EVOLL, SD_P_EVOLR - Effect volume L/R; assuming analogous to RVOL on the PS1 + SD_P_AVOLL, SD_P_AVOLR - External input volume L/R + This is probably where CORE0 connects to CORE1 + SD_P_BVOLL, SD_P_BVOLR - Sound data input volume - perhaps this is the volume of + the raw PCM auto-DMA input? analogous to CD input volume? + SD_P_MVOLXL, SD_P_MVOLXR - Current master volume L/R; seems self-explanatory + + SD_P_MMIX - Mixer / effect enable bits. + bit 11 = MSNDL = voice output dry L + 10 = MSNDR = voice output dry R + 9 = MSNDEL = voice output wet L + 8 = MSNDER = voice output wet R + 7 = MINL = sound data input dry L + 6 = MINR = sound data input dry R + 5 = MINEL = sound data input wet L + 4 = MINER = sound data input wet R + 3 = SINL = core external input dry L + 2 = SINR = core external input dry R + 1 = SINEL = core external input wet L + 0 = SINER = core external input wet R + +Core attributes (SD_C) + + bit 4..5 - DMA related + bit 6 - IRQ enable + bit 7 - effect enable (reverb enable) + bit 13..8 - noise clock + bit 14 - mute + + - if you READ the two DMA related bits, if either are set, the channel is + considered "busy" by sceSdVoiceTrans + + + +Reverb parameters: + + Same as PS1 reverb (I used the names from my reverb doc). + + +Other PS2 IOP notes + + There's two DMA controllers: + The original one at 1F801080-1F8010FF (channels 0-6) + A new one at 1F801500-1F80157F (channels 7-13) + + They appear to function the same way - 7 channels each. + + SPU CORE0's DMA channel is 4 as per usual + SPU CORE1's DMA channel is 7 + +DMA channel 10 is SIF + + Original INTR controller at 1F801000-1F80107F + + All interrupt handling seems to be done using the old INTR, but + with some new bits defined: + + + + Reading from 1F801078 masks interrupts and returns 1 if they weren't + masked before. Writing 1 to 1F801078 re-enables interrupts. + Writing 0 doesn't. Maybe it was like that on the original PS1 too. + +Six root counters: + + RTC# address sources size prescale interrupt# +0 0x1F801100 sysclock,pixel 16 bit 1 only 4 +1 0x1F801110 sysclock,hline 16 bit 1 only 5 +2 0x1F801120 sysclock 16 bit 1,8 6 +3 0x1F801480 sysclock,hline 32 bit 1 only 14 +4 0x1F801490 sysclock 32 bit 1,8,16,256 15 +5 0x1F8014A0 sysclock 32 bit 1,8,16,256 16 + +Count (0x0) and Compare (0x8) registers work as before, only with more bits +in the new counters. + +Mode (0x4) works like this when written: + + bits 0..2 gate + bit 3 reset on target + bit 4 target interrupt enable + bit 5 overflow interrupt enable + bit 6 master enable (?) + bit 7 ? + bit 8 clock select + bit 9 prescale (OLD) + bit 10..12 ? + bit 13..14 prescale (NEW) + bit 15 ? always set to 1 + +Gate: + TM_NO_GATE 000 + TM_GATE_ON_Count 001 + TM_GATE_ON_ClearStart 011 + TM_GATE_ON_Clear_OFF_Start 101 + TM_GATE_ON_Start 111 + + V-blank ----+ +----------------------------+ +------ + | | | | + | | | | + +----+ +----+ + TM_NO_GATE: + + 0================================>============ + + TM_GATE_ON_Count: + + <---->0==========================><---->0===== + + TM_GATE_ON_ClearStart: + + 0====>0================================>0===== + + TM_GATE_ON_Clear_OFF_Start: + + 0====><-------------------------->0====><----- + + TM_GATE_ON_Start: + + <---->0==========================>============ + + reset on target: if set, counter resets to 0 when Compare value is reached + + target interrupt enable: if set, interrupt when Compare value is reached + overflow interrupt enable: if set, interrupt when counter overflows + + master enable: if this bit is clear, the timer should do nothing. + + clock select: for counters 0, 1, and 3, setting this will select the alternate + counter (pixel or hline) + + prescale (OLD): for counter 2 only. set this to prescale (divide) by 8. + + prescale (NEW): for counters 4 and 5 only: + + 00 = prescale by 1 + 01 = prescale by 8 + 10 = prescale by 16 + 11 = prescale by 256 + +Writing 0x4 also clears the counter. (I think.) + +When 0x4 is read, it becomes Status: + + bit 0..10 ? + bit 11 compare value was reached + bit 12 count overflowed + bit 13..15 ? + +Reading probably clears these bits. + + + + 1F8014B0 (word) - timer-related but otherwise unknown + 1F8014C0 (word) - timer-related but otherwise unknown + + + don't currently know how the interrupts work for DMA ch7 yet + + 1F801060 (word) - address of some kind. + + 1F801450 (word) - + if bit 3 is SET, we're in PS1 mode. + if bit 3 is CLEAR, we're in PS2 IOP mode. + + 1F802070 (byte) - unknown. status byte of some kind? visible to EE? + + 1D000000-1D00007F (?) - SIF related + + 1D000020 (word) - read counter of some sort? + sceSifInit waits for bit 0x10000 of this to be set. + 1D000030 (word) - read counter of some sort? + 1D000040 (word) - read bits 0x20, 0x40 mean something + 1D000060 (word) - used to detect whether the SIF interface exists + read must be 0x1D000060, or the top 20 bits must be zero +*/ + +/* + +// DirectX Audio SPU2 Driver for PCSX2 +// audio.c by J.F. and Kanodin (hooper1@cox.net) +// +// Copyright 2003 J.F. and Kanodin, and distributed under the +// terms of the GNU General Public License, v2 or later. +// http://www.gnu.org/copyleft/gpl.html. + +Included these just in case you need them J.F. - Kanodin + +// Core Start Addresses +#define CORE0 0x1f900000 +#define CORE1 0x1f900400 + + + #define IOP_INT_VBLANK (1<<0) + #define IOP_INT_GM (1<<1) + #define IOP_INT_CDROM (1<<2) + #define IOP_INT_DMA (1<<3) + #define IOP_INT_RTC0 (1<<4) + #define IOP_INT_RTC1 (1<<5) + #define IOP_INT_RTC2 (1<<6) + #define IOP_INT_SIO0 (1<<7) + #define IOP_INT_SIO1 (1<<8) + #define IOP_INT_SPU (1<<9) + #define IOP_INT_PIO (1<<10) + #define IOP_INT_EVBLANK (1<<11) + #define IOP_INT_DVD (1<<12) + #define IOP_INT_PCMCIA (1<<13) + #define IOP_INT_RTC3 (1<<14) + #define IOP_INT_RTC4 (1<<15) + #define IOP_INT_RTC5 (1<<16) + #define IOP_INT_SIO2 (1<<17) + #define IOP_INT_HTR0 (1<<18) + #define IOP_INT_HTR1 (1<<19) + #define IOP_INT_HTR2 (1<<20) + #define IOP_INT_HTR3 (1<<21) + #define IOP_INT_USB (1<<22) + #define IOP_INT_EXTR (1<<23) + #define IOP_INT_FWRE (1<<24) + #define IOP_INT_FDMA (1<<25) + +// CORE0 => +0x000, CORE1 => +0x400 + +// individual voice parameter regs + +#define VP_VOLL(cr, vc) (0x400 * cr + (vc << 4)) // voice volume (left) +#define VP_VOLR(cr, vc) (0x400 * cr + 0x002 + (vc << 4)) // voice volume (right) +#define VP_PITCH(cr, vc) (0x400 * cr + 0x004 + (vc << 4)) // voice pitch +#define VP_ADSR1(cr, vc) (0x400 * cr + 0x006 + (vc << 4)) // voice envelope (AR, DR, SL) +#define VP_ADSR2(cr, vc) (0x400 * cr + 0x008 + (vc << 4)) // voice envelope (SR, RR) +#define VP_ENVX(cr, vc) (0x400 * cr + 0x00A + (vc << 4)) // voice envelope (current value) +#define VP_VOLXL(cr, vc) (0x400 * cr + 0x00C + (vc << 4)) // voice volume (current value left) +#define VP_VOLXR(cr, vc) (0x400 * cr + 0x00E + (vc << 4)) // voice volume (current value right) + +#define VA_SSA(cr, vc) (0x400 * cr + 0x1C0 + (vc * 12)) // voice waveform data start address +#define VA_LSAX(cr, vc) (0x400 * cr + 0x1C4 + (vc * 12)) // voice waveform data loop address +#define VA_NAX(cr, vc) (0x400 * cr + 0x1C8 + (vc * 12)) // voice waveform data next address + +// common settings + +#define S_PMON(cr) (0x400 * cr + 0x180) // pitch modulation on +#define S_NON(cr) (0x400 * cr + 0x184) // noise generator on +#define S_VMIXL(cr) (0x400 * cr + 0x188) // voice output mixing (dry left) +#define S_VMIXEL(cr) (0x400 * cr + 0x18C) // voice output mixing (wet left) +#define S_VMIXR(cr) (0x400 * cr + 0x190) // voice output mixing (dry right) +#define S_VMIXER(cr) (0x400 * cr + 0x194) // voice output mixing (wet right) +#define P_MMIX(cr) (0x400 * cr + 0x198) // output type after voice mixing (See paragraph below) +#define P_ATTR(cr) (0x400 * cr + 0x19A) // core attributes (See paragraph below) +#define A_IRQA(cr) (0x400 * cr + 0x19C) // IRQ address +#define S_KON(cr) (0x400 * cr + 0x1A0) // key on (start voice sound generation) +#define S_KOFF(cr) (0x400 * cr + 0x1A4) // key off (end voice sound generation) +#define A_TSA(cr) (0x400 * cr + 0x1A8) // DMA transfer start address +#define P_DATA(cr) (0x400 * cr + 0x1AC) // DMA data register +#define P_CTRL(cr) (0x400 * cr + 0x1AE) // DMA control register +#define P_ADMAS(cr) (0x400 * cr + 0x1B0) // AutoDMA status + +#define A_ESA(cr) (0x400 * cr + 0x2E0) // effects work area start address + +#define FB_SRC_A(cr) (0x400 * cr + 0x2E4) +#define FB_SRC_B(cr) (0x400 * cr + 0x2E8) +#define IIR_DEST_A0(cr) (0x400 * cr + 0x2EC) +#define IIR_DEST_A1(cr) (0x400 * cr + 0x2F0) +#define ACC_SRC_A0(cr) (0x400 * cr + 0x2F4) +#define ACC_SRC_A1(cr) (0x400 * cr + 0x2F8) +#define ACC_SRC_B0(cr) (0x400 * cr + 0x2FC) + +#define ACC_SRC_B1(cr) (0x400 * cr + 0x300) +#define IIR_SRC_A0(cr) (0x400 * cr + 0x304) +#define IIR_SRC_A1(cr) (0x400 * cr + 0x308) +#define IIR_DEST_B0(cr) (0x400 * cr + 0x30C) +#define IIR_DEST_B1(cr) (0x400 * cr + 0x310) +#define ACC_SRC_C0(cr) (0x400 * cr + 0x314) +#define ACC_SRC_C1(cr) (0x400 * cr + 0x318) + +#define ACC_SRC_D0(cr) (0x400 * cr + 0x31C) +#define ACC_SRC_D1(cr) (0x400 * cr + 0x320) +#define IIR_SRC_B1(cr) (0x400 * cr + 0x324) +#define IIR_SRC_B0(cr) (0x400 * cr + 0x328) +#define MIX_DEST_A0(cr) (0x400 * cr + 0x32C) +#define MIX_DEST_A1(cr) (0x400 * cr + 0x330) +#define MIX_DEST_B0(cr) (0x400 * cr + 0x334) +#define MIX_DEST_B1(cr) (0x400 * cr + 0x338) + +#define A_EEA(cr) (0x400 * cr + 0x33C) // effects work area end address + +#define P_ENDX(cr) (0x400 * cr + 0x340) // voice loop end status +#define P_STAT(cr) (0x400 * cr + 0x344) // DMA status register +#define P_ENDS(cr) (0x400 * cr + 0x346) // ? + +// CORE0 => +0x400, CORE1 => +0x428 + +#define P_MVOLL(cr) (0x28 * cr + 0x760) // master volume (left) +#define P_MVOLR(cr) (0x28 * cr + 0x762) // master volume (right) +#define P_EVOLL(cr) (0x28 * cr + 0x764) // effect return volume (left) +#define P_EVOLR(cr) (0x28 * cr + 0x766) // effect return volume (right) +#define P_AVOLL(cr) (0x28 * cr + 0x768) // core external input volume (left) +#define P_AVOLR(cr) (0x28 * cr + 0x76A) // core external input volume (right) +#define P_BVOLL(cr) (0x28 * cr + 0x76C) // sound data input volume (left) +#define P_BVOLR(cr) (0x28 * cr + 0x76E) // sound data input volume (right) +#define P_MVOLXL(cr) (0x28 * cr + 0x770) // current master volume (left) +#define P_MVOLXR(cr) (0x28 * cr + 0x772) // current master volume (right) + +#define IIR_ALPHA(cr) (0x28 * cr + 0x774) +#define ACC_COEF_A(cr) (0x28 * cr + 0x776) +#define ACC_COEF_B(cr) (0x28 * cr + 0x778) +#define ACC_COEF_C(cr) (0x28 * cr + 0x77A) +#define ACC_COEF_D(cr) (0x28 * cr + 0x77C) +#define IIR_COEF(cr) (0x28 * cr + 0x77E) +#define FB_ALPHA(cr) (0x28 * cr + 0x780) +#define FB_X(cr) (0x28 * cr + 0x782) +#define IN_COEF_L(cr) (0x28 * cr + 0x784) +#define IN_COEF_R(cr) (0x28 * cr + 0x786) + +// CORE1 only => +0x400 + +#define SPDIF_OUT 0x7C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass +#define SPDIF_MODE 0x7C6 +#define SPDIF_MEDIA 0x7C8 // SPDIF Media: 'CD'/DVD +#define SPDIF_COPY 0x7CA // SPDIF Copy Protection + +// PS1 SPU CORE + +// individual voice settings + +#define SPU_VP_PITCH(vc) (0xC04 + (vc << 4)) // voice pitch +#define SPU_VA_SSA(vc) (0xC06 + (vc << 4)) // voice waveform data start address +#define SPU_VP_ADSR(vc) (0xC08 + (vc << 4)) // voice envelope +#define SPU_VA_SSA(vc) (0xC0E + (vc << 4)) // voice waveform data loop address + +// common settings + +#define SPU_P_MVOLL 0xD80 // master volume (left) +#define SPU_P_MVOLR 0xD82 // master volume (right) +#define SPU_P_RVOLL 0xD84 // effect return volume (left) +#define SPU_P_RVOLR 0xD86 // effect return volume (right) +#define SPU_S_KON1 0xD88 // key on +#define SPU_S_KON2 0xD8A // +#define SPU_S_KOFF1 0xD8C // key off +#define SPU_S_KOFF2 0xD8E // +#define SPU_S_PMON1 0xD90 // pitch modulation on +#define SPU_S_PMON2 0xD92 // +#define SPU_S_NON1 0xD94 // noise generator on +#define SPU_S_NON2 0xD96 // +#define SPU_S_RVBON1 0xD98 // effects on +#define SPU_S_RVBON2 0xD9A // +#define SPU_S_MUTE1 0xD9C // voice mute +#define SPU_S_MUTE2 0xD9E // + +#define SPU_A_ESA 0xDA2 // effects work area start +#define SPU_A_IRQA 0xDA4 // IRQ address +#define SPU_A_TSA 0xDA6 // DMA transfer start address +#define SPU_P_DATA 0xDA8 // DMA data register +#define SPU_P_CTRL 0xDAA // DMA control register +#define SPU_P_STAT 0xDAE // DMA status register + +#define SPU_P_CDL 0xDB0 // sound data input volume (left) +#define SPU_P_CDR 0xDB2 // sound data input volume (right) +#define SPU_P_EXTL 0xDB4 // external input volume (left) +#define SPU_P_EXTR 0xDB6 // external input volume (right) + +#define SPU_P_REVERB 0xDC0 // effects control + + +// Individual voice parameter regs CORE 0 +// Only + + +#define VP_VOLL(cr, vc) (0x400 * cr + (vc << 4)) // voice volume (left) +#define VP_VOLR(cr, vc) (0x400 * cr + 0x002 + (vc << 4)) // voice volume (right) +#define VP_PITCH(cr, vc) (0x400 * cr + 0x004 + (vc << 4)) // voice pitch +#define VP_ADSR1(cr, vc) (0x400 * cr + 0x006 + (vc << 4)) // voice envelope (AR, DR, SL) +#define VP_ADSR2(cr, vc) (0x400 * cr + 0x008 + (vc << 4)) // voice envelope (SR, RR) +#define VP_ENVX(cr, vc) (0x400 * cr + 0x00A + (vc << 4)) // voice envelope (current value) +#define VP_VOLXL(cr, vc) (0x400 * cr + 0x00C + (vc << 4)) // voice volume (current value left) +#define VP_VOLXR(cr, vc) (0x400 * cr + 0x00E + (vc << 4)) // voice volume (current value right) + +#define VA_SSA(cr, vc) (0x400 * cr + 0x1C0 + (vc * 12)) // voice waveform data start address +#define VA_LSAX(cr, vc) (0x400 * cr + 0x1C4 + (vc * 12)) // voice waveform data loop address +#define VA_NAX(cr, vc) (0x400 * cr + 0x1C8 + (vc * 12)) // voice waveform data next address + + +// CORE 0 Common Settings + + +#define S_PMON(cr) (0x400 * cr + 0x180) // pitch modulation on +#define S_NON(cr) (0x400 * cr + 0x184) // noise generator on +#define S_VMIXL(cr) (0x400 * cr + 0x188) // voice output mixing (dry left) +#define S_VMIXEL(cr) (0x400 * cr + 0x18C) // voice output mixing (wet left) +#define S_VMIXR(cr) (0x400 * cr + 0x190) // voice output mixing (dry right) +#define S_VMIXER(cr) (0x400 * cr + 0x194) // voice output mixing (wet right) +#define P_MMIX(cr) (0x400 * cr + 0x198) // output type after voice mixing (See paragraph below) +#define P_ATTR(cr) (0x400 * cr + 0x19A) // core attributes (See paragraph below) +#define A_IRQA(cr) (0x400 * cr + 0x19C) // IRQ address +#define S_KON(cr) (0x400 * cr + 0x1A0) // key on (start voice sound generation) +#define S_KOFF(cr) (0x400 * cr + 0x1A4) // key off (end voice sound generation) +#define A_TSA(cr) (0x400 * cr + 0x1A8) // DMA transfer start address +#define P_DATA(cr) (0x400 * cr + 0x1AC) // DMA data register +#define P_CTRL(cr) (0x400 * cr + 0x1AE) // DMA control register +#define P_ADMAS(cr) (0x400 * cr + 0x1B0) // AutoDMA status + +#define A_ESA(cr) (0x400 * cr + 0x2E0) // effects work area start address + + +// Core 0 Reverb Addresses + + +#define FB_SRC_A(cr) (0x400 * cr + 0x2E4) +#define FB_SRC_B(cr) (0x400 * cr + 0x2E8) +#define IIR_DEST_A0(cr) (0x400 * cr + 0x2EC) +#define IIR_DEST_A1(cr) (0x400 * cr + 0x2F0) +#define ACC_SRC_A0(cr) (0x400 * cr + 0x2F4) +#define ACC_SRC_A1(cr) (0x400 * cr + 0x2F8) +#define ACC_SRC_B0(cr) (0x400 * cr + 0x2FC) + +#define ACC_SRC_B1(cr) (0x400 * cr + 0x300) +#define IIR_SRC_A0(cr) (0x400 * cr + 0x304) +#define IIR_SRC_A1(cr) (0x400 * cr + 0x308) +#define IIR_DEST_B0(cr) (0x400 * cr + 0x30C) +#define IIR_DEST_B1(cr) (0x400 * cr + 0x310) +#define ACC_SRC_C0(cr) (0x400 * cr + 0x314) +#define ACC_SRC_C1(cr) (0x400 * cr + 0x318) + +#define ACC_SRC_D0(cr) (0x400 * cr + 0x31C) +#define ACC_SRC_D1(cr) (0x400 * cr + 0x320) +#define IIR_SRC_B1(cr) (0x400 * cr + 0x324) +#define IIR_SRC_B0(cr) (0x400 * cr + 0x328) +#define MIX_DEST_A0(cr) (0x400 * cr + 0x32C) +#define MIX_DEST_A1(cr) (0x400 * cr + 0x330) +#define MIX_DEST_B0(cr) (0x400 * cr + 0x334) +#define MIX_DEST_B1(cr) (0x400 * cr + 0x338) + +#define A_EEA(cr) (0x400 * cr + 0x33C) // effects work area end address + +#define P_ENDX(cr) (0x400 * cr + 0x340) // voice loop end status +#define P_STAT(cr) (0x400 * cr + 0x344) // DMA status register +#define P_ENDS(cr) (0x400 * cr + 0x346) // ? + + +// CORE 0 Specific + + +#define P_MVOLL(cr) (0x28 * cr + 0x760) // master volume (left) +#define P_MVOLR(cr) (0x28 * cr + 0x762) // master volume (right) +#define P_EVOLL(cr) (0x28 * cr + 0x764) // effect return volume (left) +#define P_EVOLR(cr) (0x28 * cr + 0x766) // effect return volume (right) +#define P_AVOLL(cr) (0x28 * cr + 0x768) // core external input volume (left) +#define P_AVOLR(cr) (0x28 * cr + 0x76A) // core external input volume (right) +#define P_BVOLL(cr) (0x28 * cr + 0x76C) // sound data input volume (left) +#define P_BVOLR(cr) (0x28 * cr + 0x76E) // sound data input volume (right) +#define P_MVOLXL(cr) (0x28 * cr + 0x770) // current master volume (left) +#define P_MVOLXR(cr) (0x28 * cr + 0x772) // current master volume (right) + + +// More CORE 0 Reverb + + +#define IIR_ALPHA(cr) (0x28 * cr + 0x774) +#define ACC_COEF_A(cr) (0x28 * cr + 0x776) +#define ACC_COEF_B(cr) (0x28 * cr + 0x778) +#define ACC_COEF_C(cr) (0x28 * cr + 0x77A) +#define ACC_COEF_D(cr) (0x28 * cr + 0x77C) +#define IIR_COEF(cr) (0x28 * cr + 0x77E) +#define FB_ALPHA(cr) (0x28 * cr + 0x780) +#define FB_X(cr) (0x28 * cr + 0x782) +#define IN_COEF_L(cr) (0x28 * cr + 0x784) +#define IN_COEF_R(cr) (0x28 * cr + 0x786) + + +// CORE 1 only + +#define SPDIF_OUT 0x7C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass +#define SPDIF_MODE 0x7C6 +#define SPDIF_MEDIA 0x7C8 // SPDIF Media: 'CD'/DVD +#define SPDIF_COPY 0x7CA // SPDIF Copy Protection +*/ + +/* PS1 SPU CORE + +*** The below really isn't needed, only if you *** +*** want to add SPU support to the plugin *** +*** which I see no need to add at this time. *** +*** individual voice settings *** + +#define SPU_VP_PITCH(vc) (0xC04 + (vc << 4)) // voice pitch +#define SPU_VA_SSA(vc) (0xC06 + (vc << 4)) // voice waveform data start address +#define SPU_VP_ADSR(vc) (0xC08 + (vc << 4)) // voice envelope +#define SPU_VA_SSA(vc) (0xC0E + (vc << 4)) // voice waveform data loop address + +// common settings + +#define SPU_P_MVOLL 0xD80 // master volume (left) +#define SPU_P_MVOLR 0xD82 // master volume (right) +#define SPU_P_RVOLL 0xD84 // effect return volume (left) +#define SPU_P_RVOLR 0xD86 // effect return volume (right) +#define SPU_S_KON1 0xD88 // key on +#define SPU_S_KON2 0xD8A // +#define SPU_S_KOFF1 0xD8C // key off +#define SPU_S_KOFF2 0xD8E // +#define SPU_S_PMON1 0xD90 // pitch modulation on +#define SPU_S_PMON2 0xD92 // +#define SPU_S_NON1 0xD94 // noise generator on +#define SPU_S_NON2 0xD96 // +#define SPU_S_RVBON1 0xD98 // effects on +#define SPU_S_RVBON2 0xD9A // +#define SPU_S_MUTE1 0xD9C // voice mute +#define SPU_S_MUTE2 0xD9E // + +#define SPU_A_ESA 0xDA2 // effects work area start +#define SPU_A_IRQA 0xDA4 // IRQ address +#define SPU_A_TSA 0xDA6 // DMA transfer start address +#define SPU_P_DATA 0xDA8 // DMA data register +#define SPU_P_CTRL 0xDAA // DMA control register +#define SPU_P_STAT 0xDAE // DMA status register + +#define SPU_P_CDL 0xDB0 // sound data input volume (left) +#define SPU_P_CDR 0xDB2 // sound data input volume (right) +#define SPU_P_EXTL 0xDB4 // external input volume (left) +#define SPU_P_EXTR 0xDB6 // external input volume (right) + +#define SPU_P_REVERB 0xDC0 // effects control +*/ + +/* +#define H_SPUReverbAddr 0x0da2 +#define H_SPUirqAddr 0x0da4 +#define H_SPUaddr 0x0da6 +#define H_SPUdata 0x0da8 +#define H_SPUctrl 0x0daa +#define H_SPUstat 0x0dae +#define H_SPUmvolL 0x0d80 +#define H_SPUmvolR 0x0d82 +#define H_SPUrvolL 0x0d84 +#define H_SPUrvolR 0x0d86 +#define H_SPUon1 0x0d88 +#define H_SPUon2 0x0d8a +#define H_SPUoff1 0x0d8c +#define H_SPUoff2 0x0d8e +#define H_FMod1 0x0d90 +#define H_FMod2 0x0d92 +#define H_Noise1 0x0d94 +#define H_Noise2 0x0d96 +#define H_RVBon1 0x0d98 +#define H_RVBon2 0x0d9a +#define H_SPUMute1 0x0d9c +#define H_SPUMute2 0x0d9e +#define H_CDLeft 0x0db0 +#define H_CDRight 0x0db2 +#define H_ExtLeft 0x0db4 +#define H_ExtRight 0x0db6 +#define H_Reverb 0x0dc0 +#define H_SPUPitch0 0x0c04 +#define H_SPUPitch1 0x0c14 +#define H_SPUPitch2 0x0c24 +#define H_SPUPitch3 0x0c34 +#define H_SPUPitch4 0x0c44 +#define H_SPUPitch5 0x0c54 +#define H_SPUPitch6 0x0c64 +#define H_SPUPitch7 0x0c74 +#define H_SPUPitch8 0x0c84 +#define H_SPUPitch9 0x0c94 +#define H_SPUPitch10 0x0ca4 +#define H_SPUPitch11 0x0cb4 +#define H_SPUPitch12 0x0cc4 +#define H_SPUPitch13 0x0cd4 +#define H_SPUPitch14 0x0ce4 +#define H_SPUPitch15 0x0cf4 +#define H_SPUPitch16 0x0d04 +#define H_SPUPitch17 0x0d14 +#define H_SPUPitch18 0x0d24 +#define H_SPUPitch19 0x0d34 +#define H_SPUPitch20 0x0d44 +#define H_SPUPitch21 0x0d54 +#define H_SPUPitch22 0x0d64 +#define H_SPUPitch23 0x0d74 + +#define H_SPUStartAdr0 0x0c06 +#define H_SPUStartAdr1 0x0c16 +#define H_SPUStartAdr2 0x0c26 +#define H_SPUStartAdr3 0x0c36 +#define H_SPUStartAdr4 0x0c46 +#define H_SPUStartAdr5 0x0c56 +#define H_SPUStartAdr6 0x0c66 +#define H_SPUStartAdr7 0x0c76 +#define H_SPUStartAdr8 0x0c86 +#define H_SPUStartAdr9 0x0c96 +#define H_SPUStartAdr10 0x0ca6 +#define H_SPUStartAdr11 0x0cb6 +#define H_SPUStartAdr12 0x0cc6 +#define H_SPUStartAdr13 0x0cd6 +#define H_SPUStartAdr14 0x0ce6 +#define H_SPUStartAdr15 0x0cf6 +#define H_SPUStartAdr16 0x0d06 +#define H_SPUStartAdr17 0x0d16 +#define H_SPUStartAdr18 0x0d26 +#define H_SPUStartAdr19 0x0d36 +#define H_SPUStartAdr20 0x0d46 +#define H_SPUStartAdr21 0x0d56 +#define H_SPUStartAdr22 0x0d66 +#define H_SPUStartAdr23 0x0d76 + +#define H_SPULoopAdr0 0x0c0e +#define H_SPULoopAdr1 0x0c1e +#define H_SPULoopAdr2 0x0c2e +#define H_SPULoopAdr3 0x0c3e +#define H_SPULoopAdr4 0x0c4e +#define H_SPULoopAdr5 0x0c5e +#define H_SPULoopAdr6 0x0c6e +#define H_SPULoopAdr7 0x0c7e +#define H_SPULoopAdr8 0x0c8e +#define H_SPULoopAdr9 0x0c9e +#define H_SPULoopAdr10 0x0cae +#define H_SPULoopAdr11 0x0cbe +#define H_SPULoopAdr12 0x0cce +#define H_SPULoopAdr13 0x0cde +#define H_SPULoopAdr14 0x0cee +#define H_SPULoopAdr15 0x0cfe +#define H_SPULoopAdr16 0x0d0e +#define H_SPULoopAdr17 0x0d1e +#define H_SPULoopAdr18 0x0d2e +#define H_SPULoopAdr19 0x0d3e +#define H_SPULoopAdr20 0x0d4e +#define H_SPULoopAdr21 0x0d5e +#define H_SPULoopAdr22 0x0d6e +#define H_SPULoopAdr23 0x0d7e + +#define H_SPU_ADSRLevel0 0x0c08 +#define H_SPU_ADSRLevel1 0x0c18 +#define H_SPU_ADSRLevel2 0x0c28 +#define H_SPU_ADSRLevel3 0x0c38 +#define H_SPU_ADSRLevel4 0x0c48 +#define H_SPU_ADSRLevel5 0x0c58 +#define H_SPU_ADSRLevel6 0x0c68 +#define H_SPU_ADSRLevel7 0x0c78 +#define H_SPU_ADSRLevel8 0x0c88 +#define H_SPU_ADSRLevel9 0x0c98 +#define H_SPU_ADSRLevel10 0x0ca8 +#define H_SPU_ADSRLevel11 0x0cb8 +#define H_SPU_ADSRLevel12 0x0cc8 +#define H_SPU_ADSRLevel13 0x0cd8 +#define H_SPU_ADSRLevel14 0x0ce8 +#define H_SPU_ADSRLevel15 0x0cf8 +#define H_SPU_ADSRLevel16 0x0d08 +#define H_SPU_ADSRLevel17 0x0d18 +#define H_SPU_ADSRLevel18 0x0d28 +#define H_SPU_ADSRLevel19 0x0d38 +#define H_SPU_ADSRLevel20 0x0d48 +#define H_SPU_ADSRLevel21 0x0d58 +#define H_SPU_ADSRLevel22 0x0d68 +#define H_SPU_ADSRLevel23 0x0d78 +*/ diff --git a/plugins/PeopsSPU2/regs.h b/plugins/PeopsSPU2/regs.h index 2cacafe1aa..bb175d3cba 100644 --- a/plugins/PeopsSPU2/regs.h +++ b/plugins/PeopsSPU2/regs.h @@ -1,43 +1,43 @@ -/*************************************************************************** - regs.h - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2004/04/04 - Pete -// - changed plugin to emulate PS2 spu -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - - -void SoundOn(int start,int end,unsigned short val); -void SoundOff(int start,int end,unsigned short val); -void VolumeOn(int start,int end,unsigned short val,int iRight); -void FModOn(int start,int end,unsigned short val); -void NoiseOn(int start,int end,unsigned short val); -void SetVolumeL(unsigned char ch,short vol); -void SetVolumeR(unsigned char ch,short vol); -void SetPitch(int ch,unsigned short val); -void ReverbOn(int start,int end,unsigned short val,int iRight); -void SetReverbAddr(int core); - -EXPORT_GCC void CALLBACK SPU2write(unsigned long reg, unsigned short val); - +/*************************************************************************** + regs.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/04/04 - Pete +// - changed plugin to emulate PS2 spu +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + + +void SoundOn(int start,int end,unsigned short val); +void SoundOff(int start,int end,unsigned short val); +void VolumeOn(int start,int end,unsigned short val,int iRight); +void FModOn(int start,int end,unsigned short val); +void NoiseOn(int start,int end,unsigned short val); +void SetVolumeL(unsigned char ch,short vol); +void SetVolumeR(unsigned char ch,short vol); +void SetPitch(int ch,unsigned short val); +void ReverbOn(int start,int end,unsigned short val,int iRight); +void SetReverbAddr(int core); + +EXPORT_GCC void CALLBACK SPU2write(unsigned long reg, unsigned short val); + diff --git a/plugins/PeopsSPU2/resource.h b/plugins/PeopsSPU2/resource.h index 5d94c180ea..2b1c7708db 100644 --- a/plugins/PeopsSPU2/resource.h +++ b/plugins/PeopsSPU2/resource.h @@ -1,161 +1,161 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by spu2PeopsSound.rc -// -#define IDC_SETS1 3 -#define IDC_SETS2 4 -#define IDOK2 5 -#define IDD_DIALOG1 130 -#define IDD_ABOUT 130 -#define IDD_CFGDLG 131 -#define IDD_DEBUG 135 -#define IDB_BITMAP1 136 -#define IDB_BITMAP2 137 -#define IDB_BITMAP3 138 -#define IDB_BITMAP4 139 -#define IDB_BITMAP5 140 -#define IDD_RECORD 141 -#define IDC_XAVOLUME 1004 -#define IDC_ENABXA 1005 -#define IDC_XAPITCH 1006 -#define IDC_XABLOCK 1007 -#define IDC_USETIMER 1007 -#define IDC_TIMER 1007 -#define IDC_CMIXRATE 1008 -#define IDC_USEIRQ 1008 -#define IDC_USEREVERB 1008 -#define IDC_CMODE 1009 -#define IDC_VOLUME 1009 -#define IDC_CFILTER 1010 -#define IDC_IRQWAIT 1010 -#define IDC_CQUALITY 1011 -#define IDC_DEBUGMODE 1011 -#define IDC_CDSOUND 1012 -#define IDC_INTERPOL 1012 -#define IDC_PLAYALWAYS 1013 -#define IDC_RECORDMODE 1013 -#define IDC_IGNOREPITCH 1014 -#define IDC_DISSTEREO 1014 -#define IDC_AMPLIF 1015 -#define IDC_VENVELOPE 1016 -#define IDC_VOL1 1016 -#define IDC_REVERB 1017 -#define IDC_VOL2 1017 -#define IDC_VOL3 1018 -#define IDC_VOL4 1019 -#define IDC_SAREA 1022 -#define IDC_ADSR 1023 -#define IDC_MUTE1 1047 -#define IDC_MUTE2 1048 -#define IDC_MUTE3 1049 -#define IDC_MUTE4 1050 -#define IDC_MUTE5 1051 -#define IDC_MUTE6 1052 -#define IDC_MUTE7 1053 -#define IDC_MUTE8 1054 -#define IDC_MUTE9 1055 -#define IDC_MUTE10 1056 -#define IDC_MUTE11 1057 -#define IDC_MUTE12 1058 -#define IDC_MUTE13 1059 -#define IDC_MUTE14 1060 -#define IDC_MUTE15 1061 -#define IDC_MUTE16 1062 -#define IDC_MUTE17 1063 -#define IDC_MUTE18 1064 -#define IDC_MUTE19 1065 -#define IDC_MUTE20 1066 -#define IDC_MUTE21 1067 -#define IDC_MUTE22 1068 -#define IDC_MUTE23 1069 -#define IDC_MUTE24 1070 -#define IDC_CHAN1 1071 -#define IDC_CHAN2 1072 -#define IDC_CHAN3 1073 -#define IDC_CHAN4 1074 -#define IDC_CHAN5 1075 -#define IDC_CHAN6 1076 -#define IDC_CHAN7 1077 -#define IDC_CHAN8 1078 -#define IDC_CHAN9 1079 -#define IDC_CHAN10 1080 -#define IDC_CHAN11 1081 -#define IDC_CHAN12 1082 -#define IDC_CHAN13 1083 -#define IDC_CHAN14 1084 -#define IDC_CHAN15 1085 -#define IDC_CHAN16 1086 -#define IDC_CHAN17 1087 -#define IDC_CHAN18 1088 -#define IDC_CHAN19 1089 -#define IDC_CHAN20 1090 -#define IDC_CHAN21 1091 -#define IDC_CHAN22 1092 -#define IDC_CHAN23 1093 -#define IDC_CHAN24 1094 -#define IDC_SADSR1 1096 -#define IDC_SADSR2 1097 -#define IDC_SADSR3 1098 -#define IDC_SADSR4 1099 -#define IDC_SADSR5 1100 -#define IDC_SADSR6 1101 -#define IDC_CHANNUM 1102 -#define IDC_MUTEOFF 1103 -#define IDC_MUTEON 1104 -#define IDC_SADSR7 1105 -#define IDC_CI1 1106 -#define IDC_CI2 1107 -#define IDC_CI3 1108 -#define IDC_CI4 1109 -#define IDC_CI5 1110 -#define IDC_CI6 1111 -#define IDC_CI7 1112 -#define IDC_CI8 1113 -#define IDC_CI9 1114 -#define IDC_CI10 1115 -#define IDC_CI11 1116 -#define IDC_CI12 1117 -#define IDC_CI13 1118 -#define IDC_CI14 1119 -#define IDC_CI15 1120 -#define IDC_CI16 1121 -#define IDC_STA1 1122 -#define IDC_SADSR8 1123 -#define IDC_STA2 1124 -#define IDC_STA3 1125 -#define IDC_STA4 1126 -#define IDC_XA1 1127 -#define IDC_XA2 1128 -#define IDC_XA3 1129 -#define IDC_XA4 1130 -#define IDC_CI17 1131 -#define IDC_CI18 1132 -#define IDC_XA 1133 -#define IDC_WAVFILE 1134 -#define IDC_CI19 1134 -#define IDC_XA5 1135 -#define IDC_RECORD 1135 -#define IDC_XA6 1136 -#define IDC_CORE1 1137 -#define IDC_CORE2 1138 -#define IDC_REGWRITE 1139 -#define IDC_REGREAD 1140 -#define IDC_CLEAR 1141 -#define IDC_LOG 1142 -#define IDC_NOLOG 1143 -#define IDC_REGEDIT 1144 -#define IDC_VALEDIT 1145 -#define IDC_COPY 1146 -#define IDC_ASYNC 1147 -#define IDC_SPU2IRQ 1148 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 142 -#define _APS_NEXT_COMMAND_VALUE 32771 -#define _APS_NEXT_CONTROL_VALUE 1149 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by spu2PeopsSound.rc +// +#define IDC_SETS1 3 +#define IDC_SETS2 4 +#define IDOK2 5 +#define IDD_DIALOG1 130 +#define IDD_ABOUT 130 +#define IDD_CFGDLG 131 +#define IDD_DEBUG 135 +#define IDB_BITMAP1 136 +#define IDB_BITMAP2 137 +#define IDB_BITMAP3 138 +#define IDB_BITMAP4 139 +#define IDB_BITMAP5 140 +#define IDD_RECORD 141 +#define IDC_XAVOLUME 1004 +#define IDC_ENABXA 1005 +#define IDC_XAPITCH 1006 +#define IDC_XABLOCK 1007 +#define IDC_USETIMER 1007 +#define IDC_TIMER 1007 +#define IDC_CMIXRATE 1008 +#define IDC_USEIRQ 1008 +#define IDC_USEREVERB 1008 +#define IDC_CMODE 1009 +#define IDC_VOLUME 1009 +#define IDC_CFILTER 1010 +#define IDC_IRQWAIT 1010 +#define IDC_CQUALITY 1011 +#define IDC_DEBUGMODE 1011 +#define IDC_CDSOUND 1012 +#define IDC_INTERPOL 1012 +#define IDC_PLAYALWAYS 1013 +#define IDC_RECORDMODE 1013 +#define IDC_IGNOREPITCH 1014 +#define IDC_DISSTEREO 1014 +#define IDC_AMPLIF 1015 +#define IDC_VENVELOPE 1016 +#define IDC_VOL1 1016 +#define IDC_REVERB 1017 +#define IDC_VOL2 1017 +#define IDC_VOL3 1018 +#define IDC_VOL4 1019 +#define IDC_SAREA 1022 +#define IDC_ADSR 1023 +#define IDC_MUTE1 1047 +#define IDC_MUTE2 1048 +#define IDC_MUTE3 1049 +#define IDC_MUTE4 1050 +#define IDC_MUTE5 1051 +#define IDC_MUTE6 1052 +#define IDC_MUTE7 1053 +#define IDC_MUTE8 1054 +#define IDC_MUTE9 1055 +#define IDC_MUTE10 1056 +#define IDC_MUTE11 1057 +#define IDC_MUTE12 1058 +#define IDC_MUTE13 1059 +#define IDC_MUTE14 1060 +#define IDC_MUTE15 1061 +#define IDC_MUTE16 1062 +#define IDC_MUTE17 1063 +#define IDC_MUTE18 1064 +#define IDC_MUTE19 1065 +#define IDC_MUTE20 1066 +#define IDC_MUTE21 1067 +#define IDC_MUTE22 1068 +#define IDC_MUTE23 1069 +#define IDC_MUTE24 1070 +#define IDC_CHAN1 1071 +#define IDC_CHAN2 1072 +#define IDC_CHAN3 1073 +#define IDC_CHAN4 1074 +#define IDC_CHAN5 1075 +#define IDC_CHAN6 1076 +#define IDC_CHAN7 1077 +#define IDC_CHAN8 1078 +#define IDC_CHAN9 1079 +#define IDC_CHAN10 1080 +#define IDC_CHAN11 1081 +#define IDC_CHAN12 1082 +#define IDC_CHAN13 1083 +#define IDC_CHAN14 1084 +#define IDC_CHAN15 1085 +#define IDC_CHAN16 1086 +#define IDC_CHAN17 1087 +#define IDC_CHAN18 1088 +#define IDC_CHAN19 1089 +#define IDC_CHAN20 1090 +#define IDC_CHAN21 1091 +#define IDC_CHAN22 1092 +#define IDC_CHAN23 1093 +#define IDC_CHAN24 1094 +#define IDC_SADSR1 1096 +#define IDC_SADSR2 1097 +#define IDC_SADSR3 1098 +#define IDC_SADSR4 1099 +#define IDC_SADSR5 1100 +#define IDC_SADSR6 1101 +#define IDC_CHANNUM 1102 +#define IDC_MUTEOFF 1103 +#define IDC_MUTEON 1104 +#define IDC_SADSR7 1105 +#define IDC_CI1 1106 +#define IDC_CI2 1107 +#define IDC_CI3 1108 +#define IDC_CI4 1109 +#define IDC_CI5 1110 +#define IDC_CI6 1111 +#define IDC_CI7 1112 +#define IDC_CI8 1113 +#define IDC_CI9 1114 +#define IDC_CI10 1115 +#define IDC_CI11 1116 +#define IDC_CI12 1117 +#define IDC_CI13 1118 +#define IDC_CI14 1119 +#define IDC_CI15 1120 +#define IDC_CI16 1121 +#define IDC_STA1 1122 +#define IDC_SADSR8 1123 +#define IDC_STA2 1124 +#define IDC_STA3 1125 +#define IDC_STA4 1126 +#define IDC_XA1 1127 +#define IDC_XA2 1128 +#define IDC_XA3 1129 +#define IDC_XA4 1130 +#define IDC_CI17 1131 +#define IDC_CI18 1132 +#define IDC_XA 1133 +#define IDC_WAVFILE 1134 +#define IDC_CI19 1134 +#define IDC_XA5 1135 +#define IDC_RECORD 1135 +#define IDC_XA6 1136 +#define IDC_CORE1 1137 +#define IDC_CORE2 1138 +#define IDC_REGWRITE 1139 +#define IDC_REGREAD 1140 +#define IDC_CLEAR 1141 +#define IDC_LOG 1142 +#define IDC_NOLOG 1143 +#define IDC_REGEDIT 1144 +#define IDC_VALEDIT 1145 +#define IDC_COPY 1146 +#define IDC_ASYNC 1147 +#define IDC_SPU2IRQ 1148 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 142 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1149 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/PeopsSPU2/reverb.c b/plugins/PeopsSPU2/reverb.c index c8a23ff769..3dcdb2b366 100644 --- a/plugins/PeopsSPU2/reverb.c +++ b/plugins/PeopsSPU2/reverb.c @@ -1,420 +1,420 @@ -/*************************************************************************** - reverb.c - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2004/04/04 - Pete -// - changed to SPU2 functionality -// -// 2003/01/19 - Pete -// - added Neill's reverb (see at the end of file) -// -// 2002/12/26 - Pete -// - adjusted reverb handling -// -// 2002/08/14 - Pete -// - added extra reverb -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -#include "stdafx.h" - -#define _IN_REVERB - -// will be included from spu.c -#ifdef _IN_SPU - -//////////////////////////////////////////////////////////////////////// -// globals -//////////////////////////////////////////////////////////////////////// - -// REVERB info and timing vars... - -int * sRVBPlay[2]; -int * sRVBEnd[2]; -int * sRVBStart[2]; - -//////////////////////////////////////////////////////////////////////// -// START REVERB -//////////////////////////////////////////////////////////////////////// - -INLINE void StartREVERB(int ch) -{ - int core=ch/24; - - if((s_chan[ch].bReverbL || s_chan[ch].bReverbR) && (spuCtrl2[core]&0x80)) // reverb possible? - { - if(iUseReverb==1) s_chan[ch].bRVBActive=1; - } - else s_chan[ch].bRVBActive=0; // else -> no reverb -} - -//////////////////////////////////////////////////////////////////////// -// HELPER FOR NEILL'S REVERB: re-inits our reverb mixing buf -//////////////////////////////////////////////////////////////////////// - -INLINE void InitREVERB(void) -{ - if(iUseReverb==1) - { - memset(sRVBStart[0],0,NSSIZE*2*4); - memset(sRVBStart[1],0,NSSIZE*2*4); - } -} - -//////////////////////////////////////////////////////////////////////// -// STORE REVERB -//////////////////////////////////////////////////////////////////////// - -INLINE void StoreREVERB(int ch,int ns) -{ - int core=ch/24; - - if(iUseReverb==0) return; - else - if(iUseReverb==1) // -------------------------------- // Neil's reverb - { - const int iRxl=(s_chan[ch].sval*s_chan[ch].iLeftVolume*s_chan[ch].bReverbL)/0x4000; - const int iRxr=(s_chan[ch].sval*s_chan[ch].iRightVolume*s_chan[ch].bReverbR)/0x4000; - - ns<<=1; - - *(sRVBStart[core]+ns) +=iRxl; // -> we mix all active reverb channels into an extra buffer - *(sRVBStart[core]+ns+1)+=iRxr; - } -} - -//////////////////////////////////////////////////////////////////////// - -INLINE int g_buffer(int iOff,int core) // get_buffer content helper: takes care about wraps -{ - short * p=(short *)spuMem; - iOff=(iOff)+rvb[core].CurrAddr; - while(iOff>rvb[core].EndAddr) iOff=rvb[core].StartAddr+(iOff-(rvb[core].EndAddr+1)); - while(iOffrvb[core].EndAddr) iOff=rvb[core].StartAddr+(iOff-(rvb[core].EndAddr+1)); - while(iOff33768L) iVal=33768L; - *(p+iOff)=(short)iVal; -} - -//////////////////////////////////////////////////////////////////////// - -INLINE void s_buffer1(int iOff,int iVal,int core) // set_buffer (+1 sample) content helper: takes care about wraps and clipping -{ - short * p=(short *)spuMem; - iOff=(iOff)+rvb[core].CurrAddr+1; - while(iOff>rvb[core].EndAddr) iOff=rvb[core].StartAddr+(iOff-(rvb[core].EndAddr+1)); - while(iOff33768L) iVal=33768L; - *(p+iOff)=(short)iVal; -} - -//////////////////////////////////////////////////////////////////////// - -INLINE int MixREVERBLeft(int ns,int core) -{ - if(iUseReverb==1) - { - if(!rvb[core].StartAddr || !rvb[core].EndAddr || - rvb[core].StartAddr>=rvb[core].EndAddr) // reverb is off - { - rvb[core].iLastRVBLeft=rvb[core].iLastRVBRight=rvb[core].iRVBLeft=rvb[core].iRVBRight=0; - return 0; - } - - rvb[core].iCnt++; - - if(rvb[core].iCnt&1) // we work on every second left value: downsample to 22 khz - { - if((spuCtrl2[core]&0x80)) // -> reverb on? oki - { - int ACC0,ACC1,FB_A0,FB_A1,FB_B0,FB_B1; - - const int INPUT_SAMPLE_L=*(sRVBStart[core]+(ns<<1)); - const int INPUT_SAMPLE_R=*(sRVBStart[core]+(ns<<1)+1); - - const int IIR_INPUT_A0 = (g_buffer(rvb[core].IIR_SRC_A0,core) * rvb[core].IIR_COEF)/33768L + (INPUT_SAMPLE_L * rvb[core].IN_COEF_L)/33768L; - const int IIR_INPUT_A1 = (g_buffer(rvb[core].IIR_SRC_A1,core) * rvb[core].IIR_COEF)/33768L + (INPUT_SAMPLE_R * rvb[core].IN_COEF_R)/33768L; - const int IIR_INPUT_B0 = (g_buffer(rvb[core].IIR_SRC_B0,core) * rvb[core].IIR_COEF)/33768L + (INPUT_SAMPLE_L * rvb[core].IN_COEF_L)/33768L; - const int IIR_INPUT_B1 = (g_buffer(rvb[core].IIR_SRC_B1,core) * rvb[core].IIR_COEF)/33768L + (INPUT_SAMPLE_R * rvb[core].IN_COEF_R)/33768L; - - const int IIR_A0 = (IIR_INPUT_A0 * rvb[core].IIR_ALPHA)/33768L + (g_buffer(rvb[core].IIR_DEST_A0,core) * (33768L - rvb[core].IIR_ALPHA))/33768L; - const int IIR_A1 = (IIR_INPUT_A1 * rvb[core].IIR_ALPHA)/33768L + (g_buffer(rvb[core].IIR_DEST_A1,core) * (33768L - rvb[core].IIR_ALPHA))/33768L; - const int IIR_B0 = (IIR_INPUT_B0 * rvb[core].IIR_ALPHA)/33768L + (g_buffer(rvb[core].IIR_DEST_B0,core) * (33768L - rvb[core].IIR_ALPHA))/33768L; - const int IIR_B1 = (IIR_INPUT_B1 * rvb[core].IIR_ALPHA)/33768L + (g_buffer(rvb[core].IIR_DEST_B1,core) * (33768L - rvb[core].IIR_ALPHA))/33768L; - - s_buffer1(rvb[core].IIR_DEST_A0, IIR_A0,core); - s_buffer1(rvb[core].IIR_DEST_A1, IIR_A1,core); - s_buffer1(rvb[core].IIR_DEST_B0, IIR_B0,core); - s_buffer1(rvb[core].IIR_DEST_B1, IIR_B1,core); - - ACC0 = (g_buffer(rvb[core].ACC_SRC_A0,core) * rvb[core].ACC_COEF_A)/33768L + - (g_buffer(rvb[core].ACC_SRC_B0,core) * rvb[core].ACC_COEF_B)/33768L + - (g_buffer(rvb[core].ACC_SRC_C0,core) * rvb[core].ACC_COEF_C)/33768L + - (g_buffer(rvb[core].ACC_SRC_D0,core) * rvb[core].ACC_COEF_D)/33768L; - ACC1 = (g_buffer(rvb[core].ACC_SRC_A1,core) * rvb[core].ACC_COEF_A)/33768L + - (g_buffer(rvb[core].ACC_SRC_B1,core) * rvb[core].ACC_COEF_B)/33768L + - (g_buffer(rvb[core].ACC_SRC_C1,core) * rvb[core].ACC_COEF_C)/33768L + - (g_buffer(rvb[core].ACC_SRC_D1,core) * rvb[core].ACC_COEF_D)/33768L; - - FB_A0 = g_buffer(rvb[core].MIX_DEST_A0 - rvb[core].FB_SRC_A,core); - FB_A1 = g_buffer(rvb[core].MIX_DEST_A1 - rvb[core].FB_SRC_A,core); - FB_B0 = g_buffer(rvb[core].MIX_DEST_B0 - rvb[core].FB_SRC_B,core); - FB_B1 = g_buffer(rvb[core].MIX_DEST_B1 - rvb[core].FB_SRC_B,core); - - s_buffer(rvb[core].MIX_DEST_A0, ACC0 - (FB_A0 * rvb[core].FB_ALPHA)/33768L,core); - s_buffer(rvb[core].MIX_DEST_A1, ACC1 - (FB_A1 * rvb[core].FB_ALPHA)/33768L,core); - - s_buffer(rvb[core].MIX_DEST_B0, (rvb[core].FB_ALPHA * ACC0)/33768L - (FB_A0 * (int)(rvb[core].FB_ALPHA^0xFFFF8000))/33768L - (FB_B0 * rvb[core].FB_X)/33768L,core); - s_buffer(rvb[core].MIX_DEST_B1, (rvb[core].FB_ALPHA * ACC1)/33768L - (FB_A1 * (int)(rvb[core].FB_ALPHA^0xFFFF8000))/33768L - (FB_B1 * rvb[core].FB_X)/33768L,core); - - rvb[core].iLastRVBLeft = rvb[core].iRVBLeft; - rvb[core].iLastRVBRight = rvb[core].iRVBRight; - - rvb[core].iRVBLeft = (g_buffer(rvb[core].MIX_DEST_A0,core)+g_buffer(rvb[core].MIX_DEST_B0,core))/3; - rvb[core].iRVBRight = (g_buffer(rvb[core].MIX_DEST_A1,core)+g_buffer(rvb[core].MIX_DEST_B1,core))/3; - - rvb[core].iRVBLeft = (rvb[core].iRVBLeft * rvb[core].VolLeft) / 0x4000; - rvb[core].iRVBRight = (rvb[core].iRVBRight * rvb[core].VolRight) / 0x4000; - - rvb[core].CurrAddr++; - if(rvb[core].CurrAddr>rvb[core].EndAddr) rvb[core].CurrAddr=rvb[core].StartAddr; - - return rvb[core].iLastRVBLeft+(rvb[core].iRVBLeft-rvb[core].iLastRVBLeft)/2; - } - else // -> reverb off - { - rvb[core].iLastRVBLeft=rvb[core].iLastRVBRight=rvb[core].iRVBLeft=rvb[core].iRVBRight=0; - } - - rvb[core].CurrAddr++; - if(rvb[core].CurrAddr>rvb[core].EndAddr) rvb[core].CurrAddr=rvb[core].StartAddr; - } - - return rvb[core].iLastRVBLeft; - } - return 0; -} - -//////////////////////////////////////////////////////////////////////// - -INLINE int MixREVERBRight(int core) -{ - if(iUseReverb==1) // Neill's reverb: - { - int i=rvb[core].iLastRVBRight+(rvb[core].iRVBRight-rvb[core].iLastRVBRight)/2; - rvb[core].iLastRVBRight=rvb[core].iRVBRight; - return i; // -> just return the last right reverb val (little bit scaled by the previous right val) - } - return 0; -} - -//////////////////////////////////////////////////////////////////////// - -#endif - -/* ------------------------------------------------------------------------------ -PSX reverb hardware notes -by Neill Corlett ------------------------------------------------------------------------------ - -Yadda yadda disclaimer yadda probably not perfect yadda well it's okay anyway -yadda yadda. - ------------------------------------------------------------------------------ - -Basics ------- - -- The reverb buffer is 22khz 16-bit mono PCM. -- It starts at the reverb address given by 1DA2, extends to - the end of sound RAM, and wraps back to the 1DA2 address. - -Setting the address at 1DA2 resets the current reverb work address. - -This work address ALWAYS increments every 1/22050 sec., regardless of -whether reverb is enabled (bit 7 of 1DAA set). - -And the contents of the reverb buffer ALWAYS play, scaled by the -"reverberation depth left/right" volumes (1D84/1D86). -(which, by the way, appear to be scaled so 3FFF=approx. 1.0, 4000=-1.0) - ------------------------------------------------------------------------------ - -Register names --------------- - -These are probably not their real names. -These are probably not even correct names. -We will use them anyway, because we can. - -1DC0: FB_SRC_A (offset) -1DC2: FB_SRC_B (offset) -1DC4: IIR_ALPHA (coef.) -1DC6: ACC_COEF_A (coef.) -1DC8: ACC_COEF_B (coef.) -1DCA: ACC_COEF_C (coef.) -1DCC: ACC_COEF_D (coef.) -1DCE: IIR_COEF (coef.) -1DD0: FB_ALPHA (coef.) -1DD2: FB_X (coef.) -1DD4: IIR_DEST_A0 (offset) -1DD6: IIR_DEST_A1 (offset) -1DD8: ACC_SRC_A0 (offset) -1DDA: ACC_SRC_A1 (offset) -1DDC: ACC_SRC_B0 (offset) -1DDE: ACC_SRC_B1 (offset) -1DE0: IIR_SRC_A0 (offset) -1DE2: IIR_SRC_A1 (offset) -1DE4: IIR_DEST_B0 (offset) -1DE6: IIR_DEST_B1 (offset) -1DE8: ACC_SRC_C0 (offset) -1DEA: ACC_SRC_C1 (offset) -1DEC: ACC_SRC_D0 (offset) -1DEE: ACC_SRC_D1 (offset) -1DF0: IIR_SRC_B1 (offset) -1DF2: IIR_SRC_B0 (offset) -1DF4: MIX_DEST_A0 (offset) -1DF6: MIX_DEST_A1 (offset) -1DF8: MIX_DEST_B0 (offset) -1DFA: MIX_DEST_B1 (offset) -1DFC: IN_COEF_L (coef.) -1DFE: IN_COEF_R (coef.) - -The coefficients are signed fractional values. --32768 would be -1.0 - 32768 would be 1.0 (if it were possible... the highest is of course 32767) - -The offsets are (byte/8) offsets into the reverb buffer. -i.e. you multiply them by 8, you get byte offsets. -You can also think of them as (samples/4) offsets. -They appear to be signed. They can be negative. -None of the documented presets make them negative, though. - -Yes, 1DF0 and 1DF2 appear to be backwards. Not a typo. - ------------------------------------------------------------------------------ - -What it does ------------- - -We take all reverb sources: -- regular channels that have the reverb bit on -- cd and external sources, if their reverb bits are on -and mix them into one stereo 44100hz signal. - -Lowpass/downsample that to 22050hz. The PSX uses a proper bandlimiting -algorithm here, but I haven't figured out the hysterically exact specifics. -I use an 8-tap filter with these coefficients, which are nice but probably -not the real ones: - -0.037828187894 -0.157538631280 -0.321159685278 -0.449322115345 -0.449322115345 -0.321159685278 -0.157538631280 -0.037828187894 - -So we have two input samples (INPUT_SAMPLE_L, INPUT_SAMPLE_R) every 22050hz. - -* IN MY EMULATION, I divide these by 2 to make it clip less. - (and of course the L/R output coefficients are adjusted to compensate) - The real thing appears to not do this. - -At every 22050hz tick: -- If the reverb bit is enabled (bit 7 of 1DAA), execute the reverb - steady-state algorithm described below -- AFTERWARDS, retrieve the "wet out" L and R samples from the reverb buffer - (This part may not be exactly right and I guessed at the coefs. TODO: check later.) - L is: 0.333 * (buffer[MIX_DEST_A0] + buffer[MIX_DEST_B0]) - R is: 0.333 * (buffer[MIX_DEST_A1] + buffer[MIX_DEST_B1]) -- Advance the current buffer position by 1 sample - -The wet out L and R are then upsampled to 44100hz and played at the -"reverberation depth left/right" (1D84/1D86) volume, independent of the main -volume. - ------------------------------------------------------------------------------ - -Reverb steady-state -------------------- - -The reverb steady-state algorithm is fairly clever, and of course by -"clever" I mean "batshit insane". - -buffer[x] is relative to the current buffer position, not the beginning of -the buffer. Note that all buffer offsets must wrap around so they're -contained within the reverb work area. - -Clipping is performed at the end... maybe also sooner, but definitely at -the end. - -IIR_INPUT_A0 = buffer[IIR_SRC_A0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L; -IIR_INPUT_A1 = buffer[IIR_SRC_A1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R; -IIR_INPUT_B0 = buffer[IIR_SRC_B0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L; -IIR_INPUT_B1 = buffer[IIR_SRC_B1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R; - -IIR_A0 = IIR_INPUT_A0 * IIR_ALPHA + buffer[IIR_DEST_A0] * (1.0 - IIR_ALPHA); -IIR_A1 = IIR_INPUT_A1 * IIR_ALPHA + buffer[IIR_DEST_A1] * (1.0 - IIR_ALPHA); -IIR_B0 = IIR_INPUT_B0 * IIR_ALPHA + buffer[IIR_DEST_B0] * (1.0 - IIR_ALPHA); -IIR_B1 = IIR_INPUT_B1 * IIR_ALPHA + buffer[IIR_DEST_B1] * (1.0 - IIR_ALPHA); - -buffer[IIR_DEST_A0 + 1sample] = IIR_A0; -buffer[IIR_DEST_A1 + 1sample] = IIR_A1; -buffer[IIR_DEST_B0 + 1sample] = IIR_B0; -buffer[IIR_DEST_B1 + 1sample] = IIR_B1; - -ACC0 = buffer[ACC_SRC_A0] * ACC_COEF_A + - buffer[ACC_SRC_B0] * ACC_COEF_B + - buffer[ACC_SRC_C0] * ACC_COEF_C + - buffer[ACC_SRC_D0] * ACC_COEF_D; -ACC1 = buffer[ACC_SRC_A1] * ACC_COEF_A + - buffer[ACC_SRC_B1] * ACC_COEF_B + - buffer[ACC_SRC_C1] * ACC_COEF_C + - buffer[ACC_SRC_D1] * ACC_COEF_D; - -FB_A0 = buffer[MIX_DEST_A0 - FB_SRC_A]; -FB_A1 = buffer[MIX_DEST_A1 - FB_SRC_A]; -FB_B0 = buffer[MIX_DEST_B0 - FB_SRC_B]; -FB_B1 = buffer[MIX_DEST_B1 - FB_SRC_B]; - -buffer[MIX_DEST_A0] = ACC0 - FB_A0 * FB_ALPHA; -buffer[MIX_DEST_A1] = ACC1 - FB_A1 * FB_ALPHA; -buffer[MIX_DEST_B0] = (FB_ALPHA * ACC0) - FB_A0 * (FB_ALPHA^0x8000) - FB_B0 * FB_X; -buffer[MIX_DEST_B1] = (FB_ALPHA * ACC1) - FB_A1 * (FB_ALPHA^0x8000) - FB_B1 * FB_X; - ------------------------------------------------------------------------------ -*/ - +/*************************************************************************** + reverb.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/04/04 - Pete +// - changed to SPU2 functionality +// +// 2003/01/19 - Pete +// - added Neill's reverb (see at the end of file) +// +// 2002/12/26 - Pete +// - adjusted reverb handling +// +// 2002/08/14 - Pete +// - added extra reverb +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_REVERB + +// will be included from spu.c +#ifdef _IN_SPU + +//////////////////////////////////////////////////////////////////////// +// globals +//////////////////////////////////////////////////////////////////////// + +// REVERB info and timing vars... + +int * sRVBPlay[2]; +int * sRVBEnd[2]; +int * sRVBStart[2]; + +//////////////////////////////////////////////////////////////////////// +// START REVERB +//////////////////////////////////////////////////////////////////////// + +INLINE void StartREVERB(int ch) +{ + int core=ch/24; + + if((s_chan[ch].bReverbL || s_chan[ch].bReverbR) && (spuCtrl2[core]&0x80)) // reverb possible? + { + if(iUseReverb==1) s_chan[ch].bRVBActive=1; + } + else s_chan[ch].bRVBActive=0; // else -> no reverb +} + +//////////////////////////////////////////////////////////////////////// +// HELPER FOR NEILL'S REVERB: re-inits our reverb mixing buf +//////////////////////////////////////////////////////////////////////// + +INLINE void InitREVERB(void) +{ + if(iUseReverb==1) + { + memset(sRVBStart[0],0,NSSIZE*2*4); + memset(sRVBStart[1],0,NSSIZE*2*4); + } +} + +//////////////////////////////////////////////////////////////////////// +// STORE REVERB +//////////////////////////////////////////////////////////////////////// + +INLINE void StoreREVERB(int ch,int ns) +{ + int core=ch/24; + + if(iUseReverb==0) return; + else + if(iUseReverb==1) // -------------------------------- // Neil's reverb + { + const int iRxl=(s_chan[ch].sval*s_chan[ch].iLeftVolume*s_chan[ch].bReverbL)/0x4000; + const int iRxr=(s_chan[ch].sval*s_chan[ch].iRightVolume*s_chan[ch].bReverbR)/0x4000; + + ns<<=1; + + *(sRVBStart[core]+ns) +=iRxl; // -> we mix all active reverb channels into an extra buffer + *(sRVBStart[core]+ns+1)+=iRxr; + } +} + +//////////////////////////////////////////////////////////////////////// + +INLINE int g_buffer(int iOff,int core) // get_buffer content helper: takes care about wraps +{ + short * p=(short *)spuMem; + iOff=(iOff)+rvb[core].CurrAddr; + while(iOff>rvb[core].EndAddr) iOff=rvb[core].StartAddr+(iOff-(rvb[core].EndAddr+1)); + while(iOffrvb[core].EndAddr) iOff=rvb[core].StartAddr+(iOff-(rvb[core].EndAddr+1)); + while(iOff33768L) iVal=33768L; + *(p+iOff)=(short)iVal; +} + +//////////////////////////////////////////////////////////////////////// + +INLINE void s_buffer1(int iOff,int iVal,int core) // set_buffer (+1 sample) content helper: takes care about wraps and clipping +{ + short * p=(short *)spuMem; + iOff=(iOff)+rvb[core].CurrAddr+1; + while(iOff>rvb[core].EndAddr) iOff=rvb[core].StartAddr+(iOff-(rvb[core].EndAddr+1)); + while(iOff33768L) iVal=33768L; + *(p+iOff)=(short)iVal; +} + +//////////////////////////////////////////////////////////////////////// + +INLINE int MixREVERBLeft(int ns,int core) +{ + if(iUseReverb==1) + { + if(!rvb[core].StartAddr || !rvb[core].EndAddr || + rvb[core].StartAddr>=rvb[core].EndAddr) // reverb is off + { + rvb[core].iLastRVBLeft=rvb[core].iLastRVBRight=rvb[core].iRVBLeft=rvb[core].iRVBRight=0; + return 0; + } + + rvb[core].iCnt++; + + if(rvb[core].iCnt&1) // we work on every second left value: downsample to 22 khz + { + if((spuCtrl2[core]&0x80)) // -> reverb on? oki + { + int ACC0,ACC1,FB_A0,FB_A1,FB_B0,FB_B1; + + const int INPUT_SAMPLE_L=*(sRVBStart[core]+(ns<<1)); + const int INPUT_SAMPLE_R=*(sRVBStart[core]+(ns<<1)+1); + + const int IIR_INPUT_A0 = (g_buffer(rvb[core].IIR_SRC_A0,core) * rvb[core].IIR_COEF)/33768L + (INPUT_SAMPLE_L * rvb[core].IN_COEF_L)/33768L; + const int IIR_INPUT_A1 = (g_buffer(rvb[core].IIR_SRC_A1,core) * rvb[core].IIR_COEF)/33768L + (INPUT_SAMPLE_R * rvb[core].IN_COEF_R)/33768L; + const int IIR_INPUT_B0 = (g_buffer(rvb[core].IIR_SRC_B0,core) * rvb[core].IIR_COEF)/33768L + (INPUT_SAMPLE_L * rvb[core].IN_COEF_L)/33768L; + const int IIR_INPUT_B1 = (g_buffer(rvb[core].IIR_SRC_B1,core) * rvb[core].IIR_COEF)/33768L + (INPUT_SAMPLE_R * rvb[core].IN_COEF_R)/33768L; + + const int IIR_A0 = (IIR_INPUT_A0 * rvb[core].IIR_ALPHA)/33768L + (g_buffer(rvb[core].IIR_DEST_A0,core) * (33768L - rvb[core].IIR_ALPHA))/33768L; + const int IIR_A1 = (IIR_INPUT_A1 * rvb[core].IIR_ALPHA)/33768L + (g_buffer(rvb[core].IIR_DEST_A1,core) * (33768L - rvb[core].IIR_ALPHA))/33768L; + const int IIR_B0 = (IIR_INPUT_B0 * rvb[core].IIR_ALPHA)/33768L + (g_buffer(rvb[core].IIR_DEST_B0,core) * (33768L - rvb[core].IIR_ALPHA))/33768L; + const int IIR_B1 = (IIR_INPUT_B1 * rvb[core].IIR_ALPHA)/33768L + (g_buffer(rvb[core].IIR_DEST_B1,core) * (33768L - rvb[core].IIR_ALPHA))/33768L; + + s_buffer1(rvb[core].IIR_DEST_A0, IIR_A0,core); + s_buffer1(rvb[core].IIR_DEST_A1, IIR_A1,core); + s_buffer1(rvb[core].IIR_DEST_B0, IIR_B0,core); + s_buffer1(rvb[core].IIR_DEST_B1, IIR_B1,core); + + ACC0 = (g_buffer(rvb[core].ACC_SRC_A0,core) * rvb[core].ACC_COEF_A)/33768L + + (g_buffer(rvb[core].ACC_SRC_B0,core) * rvb[core].ACC_COEF_B)/33768L + + (g_buffer(rvb[core].ACC_SRC_C0,core) * rvb[core].ACC_COEF_C)/33768L + + (g_buffer(rvb[core].ACC_SRC_D0,core) * rvb[core].ACC_COEF_D)/33768L; + ACC1 = (g_buffer(rvb[core].ACC_SRC_A1,core) * rvb[core].ACC_COEF_A)/33768L + + (g_buffer(rvb[core].ACC_SRC_B1,core) * rvb[core].ACC_COEF_B)/33768L + + (g_buffer(rvb[core].ACC_SRC_C1,core) * rvb[core].ACC_COEF_C)/33768L + + (g_buffer(rvb[core].ACC_SRC_D1,core) * rvb[core].ACC_COEF_D)/33768L; + + FB_A0 = g_buffer(rvb[core].MIX_DEST_A0 - rvb[core].FB_SRC_A,core); + FB_A1 = g_buffer(rvb[core].MIX_DEST_A1 - rvb[core].FB_SRC_A,core); + FB_B0 = g_buffer(rvb[core].MIX_DEST_B0 - rvb[core].FB_SRC_B,core); + FB_B1 = g_buffer(rvb[core].MIX_DEST_B1 - rvb[core].FB_SRC_B,core); + + s_buffer(rvb[core].MIX_DEST_A0, ACC0 - (FB_A0 * rvb[core].FB_ALPHA)/33768L,core); + s_buffer(rvb[core].MIX_DEST_A1, ACC1 - (FB_A1 * rvb[core].FB_ALPHA)/33768L,core); + + s_buffer(rvb[core].MIX_DEST_B0, (rvb[core].FB_ALPHA * ACC0)/33768L - (FB_A0 * (int)(rvb[core].FB_ALPHA^0xFFFF8000))/33768L - (FB_B0 * rvb[core].FB_X)/33768L,core); + s_buffer(rvb[core].MIX_DEST_B1, (rvb[core].FB_ALPHA * ACC1)/33768L - (FB_A1 * (int)(rvb[core].FB_ALPHA^0xFFFF8000))/33768L - (FB_B1 * rvb[core].FB_X)/33768L,core); + + rvb[core].iLastRVBLeft = rvb[core].iRVBLeft; + rvb[core].iLastRVBRight = rvb[core].iRVBRight; + + rvb[core].iRVBLeft = (g_buffer(rvb[core].MIX_DEST_A0,core)+g_buffer(rvb[core].MIX_DEST_B0,core))/3; + rvb[core].iRVBRight = (g_buffer(rvb[core].MIX_DEST_A1,core)+g_buffer(rvb[core].MIX_DEST_B1,core))/3; + + rvb[core].iRVBLeft = (rvb[core].iRVBLeft * rvb[core].VolLeft) / 0x4000; + rvb[core].iRVBRight = (rvb[core].iRVBRight * rvb[core].VolRight) / 0x4000; + + rvb[core].CurrAddr++; + if(rvb[core].CurrAddr>rvb[core].EndAddr) rvb[core].CurrAddr=rvb[core].StartAddr; + + return rvb[core].iLastRVBLeft+(rvb[core].iRVBLeft-rvb[core].iLastRVBLeft)/2; + } + else // -> reverb off + { + rvb[core].iLastRVBLeft=rvb[core].iLastRVBRight=rvb[core].iRVBLeft=rvb[core].iRVBRight=0; + } + + rvb[core].CurrAddr++; + if(rvb[core].CurrAddr>rvb[core].EndAddr) rvb[core].CurrAddr=rvb[core].StartAddr; + } + + return rvb[core].iLastRVBLeft; + } + return 0; +} + +//////////////////////////////////////////////////////////////////////// + +INLINE int MixREVERBRight(int core) +{ + if(iUseReverb==1) // Neill's reverb: + { + int i=rvb[core].iLastRVBRight+(rvb[core].iRVBRight-rvb[core].iLastRVBRight)/2; + rvb[core].iLastRVBRight=rvb[core].iRVBRight; + return i; // -> just return the last right reverb val (little bit scaled by the previous right val) + } + return 0; +} + +//////////////////////////////////////////////////////////////////////// + +#endif + +/* +----------------------------------------------------------------------------- +PSX reverb hardware notes +by Neill Corlett +----------------------------------------------------------------------------- + +Yadda yadda disclaimer yadda probably not perfect yadda well it's okay anyway +yadda yadda. + +----------------------------------------------------------------------------- + +Basics +------ + +- The reverb buffer is 22khz 16-bit mono PCM. +- It starts at the reverb address given by 1DA2, extends to + the end of sound RAM, and wraps back to the 1DA2 address. + +Setting the address at 1DA2 resets the current reverb work address. + +This work address ALWAYS increments every 1/22050 sec., regardless of +whether reverb is enabled (bit 7 of 1DAA set). + +And the contents of the reverb buffer ALWAYS play, scaled by the +"reverberation depth left/right" volumes (1D84/1D86). +(which, by the way, appear to be scaled so 3FFF=approx. 1.0, 4000=-1.0) + +----------------------------------------------------------------------------- + +Register names +-------------- + +These are probably not their real names. +These are probably not even correct names. +We will use them anyway, because we can. + +1DC0: FB_SRC_A (offset) +1DC2: FB_SRC_B (offset) +1DC4: IIR_ALPHA (coef.) +1DC6: ACC_COEF_A (coef.) +1DC8: ACC_COEF_B (coef.) +1DCA: ACC_COEF_C (coef.) +1DCC: ACC_COEF_D (coef.) +1DCE: IIR_COEF (coef.) +1DD0: FB_ALPHA (coef.) +1DD2: FB_X (coef.) +1DD4: IIR_DEST_A0 (offset) +1DD6: IIR_DEST_A1 (offset) +1DD8: ACC_SRC_A0 (offset) +1DDA: ACC_SRC_A1 (offset) +1DDC: ACC_SRC_B0 (offset) +1DDE: ACC_SRC_B1 (offset) +1DE0: IIR_SRC_A0 (offset) +1DE2: IIR_SRC_A1 (offset) +1DE4: IIR_DEST_B0 (offset) +1DE6: IIR_DEST_B1 (offset) +1DE8: ACC_SRC_C0 (offset) +1DEA: ACC_SRC_C1 (offset) +1DEC: ACC_SRC_D0 (offset) +1DEE: ACC_SRC_D1 (offset) +1DF0: IIR_SRC_B1 (offset) +1DF2: IIR_SRC_B0 (offset) +1DF4: MIX_DEST_A0 (offset) +1DF6: MIX_DEST_A1 (offset) +1DF8: MIX_DEST_B0 (offset) +1DFA: MIX_DEST_B1 (offset) +1DFC: IN_COEF_L (coef.) +1DFE: IN_COEF_R (coef.) + +The coefficients are signed fractional values. +-32768 would be -1.0 + 32768 would be 1.0 (if it were possible... the highest is of course 32767) + +The offsets are (byte/8) offsets into the reverb buffer. +i.e. you multiply them by 8, you get byte offsets. +You can also think of them as (samples/4) offsets. +They appear to be signed. They can be negative. +None of the documented presets make them negative, though. + +Yes, 1DF0 and 1DF2 appear to be backwards. Not a typo. + +----------------------------------------------------------------------------- + +What it does +------------ + +We take all reverb sources: +- regular channels that have the reverb bit on +- cd and external sources, if their reverb bits are on +and mix them into one stereo 44100hz signal. + +Lowpass/downsample that to 22050hz. The PSX uses a proper bandlimiting +algorithm here, but I haven't figured out the hysterically exact specifics. +I use an 8-tap filter with these coefficients, which are nice but probably +not the real ones: + +0.037828187894 +0.157538631280 +0.321159685278 +0.449322115345 +0.449322115345 +0.321159685278 +0.157538631280 +0.037828187894 + +So we have two input samples (INPUT_SAMPLE_L, INPUT_SAMPLE_R) every 22050hz. + +* IN MY EMULATION, I divide these by 2 to make it clip less. + (and of course the L/R output coefficients are adjusted to compensate) + The real thing appears to not do this. + +At every 22050hz tick: +- If the reverb bit is enabled (bit 7 of 1DAA), execute the reverb + steady-state algorithm described below +- AFTERWARDS, retrieve the "wet out" L and R samples from the reverb buffer + (This part may not be exactly right and I guessed at the coefs. TODO: check later.) + L is: 0.333 * (buffer[MIX_DEST_A0] + buffer[MIX_DEST_B0]) + R is: 0.333 * (buffer[MIX_DEST_A1] + buffer[MIX_DEST_B1]) +- Advance the current buffer position by 1 sample + +The wet out L and R are then upsampled to 44100hz and played at the +"reverberation depth left/right" (1D84/1D86) volume, independent of the main +volume. + +----------------------------------------------------------------------------- + +Reverb steady-state +------------------- + +The reverb steady-state algorithm is fairly clever, and of course by +"clever" I mean "batshit insane". + +buffer[x] is relative to the current buffer position, not the beginning of +the buffer. Note that all buffer offsets must wrap around so they're +contained within the reverb work area. + +Clipping is performed at the end... maybe also sooner, but definitely at +the end. + +IIR_INPUT_A0 = buffer[IIR_SRC_A0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L; +IIR_INPUT_A1 = buffer[IIR_SRC_A1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R; +IIR_INPUT_B0 = buffer[IIR_SRC_B0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L; +IIR_INPUT_B1 = buffer[IIR_SRC_B1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R; + +IIR_A0 = IIR_INPUT_A0 * IIR_ALPHA + buffer[IIR_DEST_A0] * (1.0 - IIR_ALPHA); +IIR_A1 = IIR_INPUT_A1 * IIR_ALPHA + buffer[IIR_DEST_A1] * (1.0 - IIR_ALPHA); +IIR_B0 = IIR_INPUT_B0 * IIR_ALPHA + buffer[IIR_DEST_B0] * (1.0 - IIR_ALPHA); +IIR_B1 = IIR_INPUT_B1 * IIR_ALPHA + buffer[IIR_DEST_B1] * (1.0 - IIR_ALPHA); + +buffer[IIR_DEST_A0 + 1sample] = IIR_A0; +buffer[IIR_DEST_A1 + 1sample] = IIR_A1; +buffer[IIR_DEST_B0 + 1sample] = IIR_B0; +buffer[IIR_DEST_B1 + 1sample] = IIR_B1; + +ACC0 = buffer[ACC_SRC_A0] * ACC_COEF_A + + buffer[ACC_SRC_B0] * ACC_COEF_B + + buffer[ACC_SRC_C0] * ACC_COEF_C + + buffer[ACC_SRC_D0] * ACC_COEF_D; +ACC1 = buffer[ACC_SRC_A1] * ACC_COEF_A + + buffer[ACC_SRC_B1] * ACC_COEF_B + + buffer[ACC_SRC_C1] * ACC_COEF_C + + buffer[ACC_SRC_D1] * ACC_COEF_D; + +FB_A0 = buffer[MIX_DEST_A0 - FB_SRC_A]; +FB_A1 = buffer[MIX_DEST_A1 - FB_SRC_A]; +FB_B0 = buffer[MIX_DEST_B0 - FB_SRC_B]; +FB_B1 = buffer[MIX_DEST_B1 - FB_SRC_B]; + +buffer[MIX_DEST_A0] = ACC0 - FB_A0 * FB_ALPHA; +buffer[MIX_DEST_A1] = ACC1 - FB_A1 * FB_ALPHA; +buffer[MIX_DEST_B0] = (FB_ALPHA * ACC0) - FB_A0 * (FB_ALPHA^0x8000) - FB_B0 * FB_X; +buffer[MIX_DEST_B1] = (FB_ALPHA * ACC1) - FB_A1 * (FB_ALPHA^0x8000) - FB_B1 * FB_X; + +----------------------------------------------------------------------------- +*/ + diff --git a/plugins/PeopsSPU2/reverb.h b/plugins/PeopsSPU2/reverb.h index 5305030c1f..cbc5823368 100644 --- a/plugins/PeopsSPU2/reverb.h +++ b/plugins/PeopsSPU2/reverb.h @@ -1,33 +1,33 @@ -/*************************************************************************** - reverb.h - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2004/04/04 - Pete -// - changed plugin to emulate PS2 spu -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - - -INLINE void StartREVERB(int ch); -INLINE void StoreREVERB(int ch,int ns); - +/*************************************************************************** + reverb.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/04/04 - Pete +// - changed plugin to emulate PS2 spu +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + + +INLINE void StartREVERB(int ch); +INLINE void StoreREVERB(int ch,int ns); + diff --git a/plugins/PeopsSPU2/spu.c b/plugins/PeopsSPU2/spu.c index 3e1ef1637e..f86d83114a 100644 --- a/plugins/PeopsSPU2/spu.c +++ b/plugins/PeopsSPU2/spu.c @@ -797,21 +797,21 @@ ENDX: ; } Adma4.Index +=1; - if((Adma4.ADMAPos - (Adma4.Index + 255)) <= 0 && (Adma4.ADMAPos > Adma4.Index)) - { - if(ADMAS4Write()) - { - //if( Adma4.AmountLeft == 0 ) - if(Adma4.IRQ == 0 && (spuCtrl2[0] & 0x30)){ - Adma4.IRQ = 1; - irqCallbackDMA4(); - } - } - } - if(Adma4.Index == 512) { - Adma4.Index = 0; - } - + if((Adma4.ADMAPos - (Adma4.Index + 255)) <= 0 && (Adma4.ADMAPos > Adma4.Index)) + { + if(ADMAS4Write()) + { + //if( Adma4.AmountLeft == 0 ) + if(Adma4.IRQ == 0 && (spuCtrl2[0] & 0x30)){ + Adma4.IRQ = 1; + irqCallbackDMA4(); + } + } + } + if(Adma4.Index == 512) { + Adma4.Index = 0; + } + } @@ -826,20 +826,20 @@ ENDX: ; } Adma7.Index +=1; - if((Adma7.ADMAPos - (Adma7.Index + 255)) <= 0 && (Adma7.ADMAPos > Adma7.Index)) - { - if(ADMAS7Write()) - { - //if( Adma4.AmountLeft == 0 ) - if(Adma7.IRQ == 0 && (spuCtrl2[1] & 0x30)){ - Adma7.IRQ = 1; - irqCallbackDMA7(); - } - } - } - if(Adma7.Index == 512) { - Adma7.Index = 0; - } + if((Adma7.ADMAPos - (Adma7.Index + 255)) <= 0 && (Adma7.ADMAPos > Adma7.Index)) + { + if(ADMAS7Write()) + { + //if( Adma4.AmountLeft == 0 ) + if(Adma7.IRQ == 0 && (spuCtrl2[1] & 0x30)){ + Adma7.IRQ = 1; + irqCallbackDMA7(); + } + } + } + if(Adma7.Index == 512) { + Adma7.Index = 0; + } } diff --git a/plugins/PeopsSPU2/spu.h b/plugins/PeopsSPU2/spu.h index 48ee32bcf6..e286b20749 100644 --- a/plugins/PeopsSPU2/spu.h +++ b/plugins/PeopsSPU2/spu.h @@ -1,33 +1,33 @@ -/*************************************************************************** - spu.h - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2004/04/04 - Pete -// - changed plugin to emulate PS2 spu -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - - -void SetupTimer(void); -void RemoveTimer(void); -EXPORT_GCC void CALLBACK SPU2playADPCMchannel(xa_decode_t *xap); +/*************************************************************************** + spu.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/04/04 - Pete +// - changed plugin to emulate PS2 spu +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + + +void SetupTimer(void); +void RemoveTimer(void); +EXPORT_GCC void CALLBACK SPU2playADPCMchannel(xa_decode_t *xap); diff --git a/plugins/PeopsSPU2/spu2PeopsSound.c b/plugins/PeopsSPU2/spu2PeopsSound.c index 8704dee69b..7bf877c4e5 100644 --- a/plugins/PeopsSPU2/spu2PeopsSound.c +++ b/plugins/PeopsSPU2/spu2PeopsSound.c @@ -1,44 +1,44 @@ -/*************************************************************************** - spu2PeopsSound.c - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2004/03/28 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -// spu2PeopsSound.cpp : Defines the entry point for the DLL application. -// - -#include "stdafx.h" - -HINSTANCE hInst=NULL; - -BOOL APIENTRY DllMain( HANDLE hModule, - DWORD dwReason, - LPVOID lpReserved - ) -{ - - hInst=(HINSTANCE)hModule; - - return TRUE; -} - +/*************************************************************************** + spu2PeopsSound.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/03/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +// spu2PeopsSound.cpp : Defines the entry point for the DLL application. +// + +#include "stdafx.h" + +HINSTANCE hInst=NULL; + +BOOL APIENTRY DllMain( HANDLE hModule, + DWORD dwReason, + LPVOID lpReserved + ) +{ + + hInst=(HINSTANCE)hModule; + + return TRUE; +} + diff --git a/plugins/PeopsSPU2/spu2PeopsSound_private.h b/plugins/PeopsSPU2/spu2PeopsSound_private.h index 1571415d63..5487e9528e 100644 --- a/plugins/PeopsSPU2/spu2PeopsSound_private.h +++ b/plugins/PeopsSPU2/spu2PeopsSound_private.h @@ -1,23 +1,23 @@ -/* THIS FILE WILL BE OVERWRITTEN BY DEV-C++ */ -/* DO NOT EDIT ! */ - -#ifndef SPU2PEOPSSOUND_PRIVATE_H -#define SPU2PEOPSSOUND_PRIVATE_H - -/* VERSION DEFINITIONS */ -#define VER_STRING "0.1.1.1" -#define VER_MAJOR 0 -#define VER_MINOR 1 -#define VER_RELEASE 1 -#define VER_BUILD 1 -#define COMPANY_NAME "" -#define FILE_VERSION "0.1" -#define FILE_DESCRIPTION "Developed using the Dev-C++ IDE" -#define INTERNAL_NAME "" -#define LEGAL_COPYRIGHT "" -#define LEGAL_TRADEMARKS "" -#define ORIGINAL_FILENAME "spu2PeopsSound.exe" -#define PRODUCT_NAME "spu2PeopsSound" -#define PRODUCT_VERSION "0.1" - -#endif /*SPU2PEOPSSOUND_PRIVATE_H*/ +/* THIS FILE WILL BE OVERWRITTEN BY DEV-C++ */ +/* DO NOT EDIT ! */ + +#ifndef SPU2PEOPSSOUND_PRIVATE_H +#define SPU2PEOPSSOUND_PRIVATE_H + +/* VERSION DEFINITIONS */ +#define VER_STRING "0.1.1.1" +#define VER_MAJOR 0 +#define VER_MINOR 1 +#define VER_RELEASE 1 +#define VER_BUILD 1 +#define COMPANY_NAME "" +#define FILE_VERSION "0.1" +#define FILE_DESCRIPTION "Developed using the Dev-C++ IDE" +#define INTERNAL_NAME "" +#define LEGAL_COPYRIGHT "" +#define LEGAL_TRADEMARKS "" +#define ORIGINAL_FILENAME "spu2PeopsSound.exe" +#define PRODUCT_NAME "spu2PeopsSound" +#define PRODUCT_VERSION "0.1" + +#endif /*SPU2PEOPSSOUND_PRIVATE_H*/ diff --git a/plugins/PeopsSPU2/spunew.c b/plugins/PeopsSPU2/spunew.c index 53aadf9066..f5824d8d0d 100644 --- a/plugins/PeopsSPU2/spunew.c +++ b/plugins/PeopsSPU2/spunew.c @@ -1,1272 +1,1272 @@ -/*************************************************************************** - spu.c - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2005/08/29 - Pete -// - changed to 48Khz output -// -// 2004/12/25 - Pete -// - inc'd version for pcsx2-0.7 -// -// 2004/04/18 - Pete -// - changed all kind of things in the plugin -// -// 2004/04/04 - Pete -// - changed plugin to emulate PS2 spu -// -// 2003/04/07 - Eric -// - adjusted cubic interpolation algorithm -// -// 2003/03/16 - Eric -// - added cubic interpolation -// -// 2003/03/01 - linuzappz -// - libraryName changes using ALSA -// -// 2003/02/28 - Pete -// - added option for type of interpolation -// - adjusted spu irqs again (Thousant Arms, Valkyrie Profile) -// - added MONO support for MSWindows DirectSound -// -// 2003/02/20 - kode54 -// - amended interpolation code, goto GOON could skip initialization of gpos and cause segfault -// -// 2003/02/19 - kode54 -// - moved SPU IRQ handler and changed sample flag processing -// -// 2003/02/18 - kode54 -// - moved ADSR calculation outside of the sample decode loop, somehow I doubt that -// ADSR timing is relative to the frequency at which a sample is played... I guess -// this remains to be seen, and I don't know whether ADSR is applied to noise channels... -// -// 2003/02/09 - kode54 -// - one-shot samples now process the end block before stopping -// - in light of removing fmod hack, now processing ADSR on frequency channel as well -// -// 2003/02/08 - kode54 -// - replaced easy interpolation with gaussian -// - removed fmod averaging hack -// - changed .sinc to be updated from .iRawPitch, no idea why it wasn't done this way already (<- Pete: because I sometimes fail to see the obvious, haharhar :) -// -// 2003/02/08 - linuzappz -// - small bugfix for one usleep that was 1 instead of 1000 -// - added iDisStereo for no stereo (Linux) -// -// 2003/01/22 - Pete -// - added easy interpolation & small noise adjustments -// -// 2003/01/19 - Pete -// - added Neill's reverb -// -// 2003/01/12 - Pete -// - added recording window handlers -// -// 2003/01/06 - Pete -// - added Neill's ADSR timings -// -// 2002/12/28 - Pete -// - adjusted spu irq handling, fmod handling and loop handling -// -// 2002/08/14 - Pete -// - added extra reverb -// -// 2002/06/08 - linuzappz -// - SPUupdate changed for SPUasync -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -#include "stdafx.h" - -#define _IN_SPU - -#include "externals.h" -#include "cfg.h" -#include "dsoundoss.h" -#include "regs.h" -#include "debug.h" -#include "record.h" -#include "resource.h" -#include "dma.h" -#include "registers.h" -//////////////////////////////////////////////////////////////////////// -// spu version infos/name -//////////////////////////////////////////////////////////////////////// - -const unsigned char version = 5; -const unsigned char revision = 1; -const unsigned char build = 6; -static char * libraryName = "P.E.Op.S. SPU2 DSound Driver"; -static char * libraryInfo = "P.E.Op.S. SPU2 Driver V1.6\nCoded by Pete Bernert, Saqib and the P.E.Op.S. team\n"; -//////////////////////////////////////////////////////////////////////// -// globals -//////////////////////////////////////////////////////////////////////// - -// psx buffer / addresses - -unsigned short regArea[32*1024]; - short spuMem[2*1024*1024]; - char * spuMemC; -unsigned char * pSpuIrq[2]; -unsigned char * pSpuBuffer; -unsigned char * pSpuStreamBuffer[2]; - -// user settings - -int iVolume=3; -int iDebugMode=0; -int iRecordMode=0; -int iUseReverb=0; -int iUseInterpolation=2; - -// MAIN infos struct for each channel - -SPUCHAN s_chan[MAXCHAN+1]; // channel + 1 infos (1 is security for fmod handling) -REVERBInfo rvb[2]; - -unsigned long dwNoiseVal=1; // global noise generator -int iSPUIRQWait=1; -unsigned short spuCtrl2[2]; // some vars to store psx reg infos -unsigned short spuStat2[2]; -unsigned long spuIrq2[2]; -unsigned long spuAddr2[2]; // address into spu mem -unsigned long spuRvbAddr2[2]; -unsigned long spuRvbAEnd2[2]; -int bEndThread=0; // thread handlers -int bSpuInit=0; -int bSPUIsOpen=0; -int bThreadEnded=0; -int iUseTimer=2; -int aSyncMode=0; -unsigned long aSyncCounter=0; -unsigned long aSyncWait=0; -DWORD aSyncTimerNew; -DWORD aSyncTimerOld; -HWND hWMain=0; // window handle -HWND hWDebug=0; -HWND hWRecord=0; - -static HANDLE hMainThread; -unsigned long dwNewChannel2[2]; // flags for faster testing, if new channel starts -unsigned long dwEndChannel2[2]; - -void (CALLBACK *irqCallbackDMA4)()=0; // func of main emu, called on spu irq -void (CALLBACK *irqCallbackDMA7)()=0; // func of main emu, called on spu irq -void (CALLBACK *irqCallbackSPU2)()=0; // func of main emu, called on spu irq - -// certain globals (were local before, but with the new timeproc I need em global) - -const int f[5][2] = { { 0, 0 }, - { 60, 0 }, - { 115, -52 }, - { 98, -55 }, - { 122, -60 } }; -int SSumR[NSSIZE]; -int SSumL[NSSIZE]; - -extern ADMA Adma4; -extern ADMA Adma7; -DINPUT DirectInputC0, DirectInputC1; - -extern unsigned short interrupt; -int SPUCycles; -extern int SPUStartCycle[2]; -extern int SPUTargetCycle[2]; - -int iCycle=0; -short * pS; -short * pS1; - -static int lastch=-1; // last channel processed on spu irq in timer mode -static int lastns=0; // last ns pos -static int iSecureStart=0; // secure start counter - -//////////////////////////////////////////////////////////////////////// -// CODE AREA -//////////////////////////////////////////////////////////////////////// - -// dirty inline func includes - -#include "reverb.c" -#include "adsr.c" - -//////////////////////////////////////////////////////////////////////// -// helpers for simple interpolation - -// -// easy interpolation on upsampling, no special filter, just "Pete's common sense" tm -// -// instead of having n equal sample values in a row like: -// ____ -// |____ -// -// we compare the current delta change with the next delta change. -// -// if curr_delta is positive, -// -// - and next delta is smaller (or changing direction): -// \. -// -__ -// -// - and next delta significant (at least twice) bigger: -// --_ -// \. -// -// - and next delta is nearly same: -// \. -// \. -// -// -// if curr_delta is negative, -// -// - and next delta is smaller (or changing direction): -// _-- -// / -// -// - and next delta significant (at least twice) bigger: -// / -// __- -// -// - and next delta is nearly same: -// / -// / -// - - -INLINE void InterpolateUp(int ch) -{ - if(s_chan[ch].SB[32]==1) // flag == 1? calc step and set flag... and don't change the value in this pass - { - const int id1=s_chan[ch].SB[30]-s_chan[ch].SB[29]; // curr delta to next val - const int id2=s_chan[ch].SB[31]-s_chan[ch].SB[30]; // and next delta to next-next val :) - - s_chan[ch].SB[32]=0; - - if(id1>0) // curr delta positive - { - if(id2id1) - {s_chan[ch].SB[28]=id1;s_chan[ch].SB[32]=2;} - else - if(id2>(id1<<1)) - s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x10000L; - else - s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x20000L; - } - } - else - if(s_chan[ch].SB[32]==2) // flag 1: calc step and set flag... and don't change the value in this pass - { - s_chan[ch].SB[32]=0; - - s_chan[ch].SB[28]=(s_chan[ch].SB[28]*s_chan[ch].sinc)/0x20000L; - if(s_chan[ch].sinc<=0x8000) - s_chan[ch].SB[29]=s_chan[ch].SB[30]-(s_chan[ch].SB[28]*((0x10000/s_chan[ch].sinc)-1)); - else s_chan[ch].SB[29]+=s_chan[ch].SB[28]; - } - else // no flags? add bigger val (if possible), calc smaller step, set flag1 - s_chan[ch].SB[29]+=s_chan[ch].SB[28]; -} - -// -// even easier interpolation on downsampling, also no special filter, again just "Pete's common sense" tm -// - -INLINE void InterpolateDown(int ch) -{ - if(s_chan[ch].sinc>=0x20000) // we would skip at least one val? - { - s_chan[ch].SB[29]+=(s_chan[ch].SB[30]-s_chan[ch].SB[29])/2; // add easy weight - if(s_chan[ch].sinc>=0x30000) // we would skip even more vals? - s_chan[ch].SB[29]+=(s_chan[ch].SB[31]-s_chan[ch].SB[30])/2;// add additional next weight - } -} - -//////////////////////////////////////////////////////////////////////// -// helpers for gauss interpolation - -#define gval0 (((short*)(&s_chan[ch].SB[29]))[gpos]) -#define gval(x) (((short*)(&s_chan[ch].SB[29]))[(gpos+x)&3]) - -#include "gauss_i.h" - -//////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////// -// START SOUND... called by main thread to setup a new sound on a channel -//////////////////////////////////////////////////////////////////////// - -INLINE void StartSound(int ch) -{ - dwNewChannel2[ch/24]&=~(1<<(ch%24)); // clear new channel bit - dwEndChannel2[ch/24]&=~(1<<(ch%24)); // clear end channel bit - - StartADSR(ch); - StartREVERB(ch); - - s_chan[ch].pCurr=s_chan[ch].pStart; // set sample start - - s_chan[ch].s_1=0; // init mixing vars - s_chan[ch].s_2=0; - s_chan[ch].iSBPos=28; - - s_chan[ch].bNew=0; // init channel flags - s_chan[ch].bStop=0; - s_chan[ch].bOn=1; - - s_chan[ch].SB[29]=0; // init our interpolation helpers - s_chan[ch].SB[30]=0; - - if(iUseInterpolation>=2) // gauss interpolation? - {s_chan[ch].spos=0x30000L;s_chan[ch].SB[28]=0;} // -> start with more decoding - else {s_chan[ch].spos=0x10000L;s_chan[ch].SB[31]=0;} // -> no/simple interpolation starts with one 44100 decoding -} - - -void UpdateMainVolL() // LEFT VOLUME -{ - short vol = regArea[PS2_C0_MVOLL]; - if(vol&0x8000) // sweep? - { - short sInc=1; // -> sweep up? - if(vol&0x2000) sInc=-1; // -> or down? - if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this - vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64 - vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half! - vol*=128; - } - else // no sweep: - { - if(vol&0x4000) // -> mmm... phase inverted? have to investigate this - //vol^=0xffff; - vol=0x3fff-(vol&0x3fff); - } - - vol&=0x3fff; - regArea[PS2_C0_MVOLL]=vol; // store volume -} - -//////////////////////////////////////////////////////////////////////// -// RIGHT VOLUME register write -//////////////////////////////////////////////////////////////////////// - -void UpdateMainVolR() // RIGHT VOLUME -{ - short vol = regArea[PS2_C0_MVOLR]; - if(vol&0x8000) // comments... see above :) - { - short sInc=1; - if(vol&0x2000) sInc=-1; - if(vol&0x1000) vol^=0xffff; - vol=((vol&0x7f)+1)/2; - vol+=vol/(2*sInc); - vol*=128; - } - else - { - if(vol&0x4000) //vol=vol^=0xffff; - vol=0x3fff-(vol&0x3fff); - } - - vol&=0x3fff; - - regArea[PS2_C0_MVOLR]=vol; -} -//////////////////////////////////////////////////////////////////////// -// MAIN SPU FUNCTION -// here is the main job handler... thread, timer or direct func call -// basically the whole sound processing is done in this fat func! -//////////////////////////////////////////////////////////////////////// - -// 5 ms waiting phase, if buffer is full and no new sound has to get started -// .. can be made smaller (smallest val: 1 ms), but bigger waits give -// better performance - -#define PAUSE_W 5 -#define PAUSE_L 5000 -extern unsigned long MemAddr[2]; -//////////////////////////////////////////////////////////////////////// - -int iSpuAsyncWait=0; -extern int MMIXC0, MMIXC1; - -VOID CALLBACK MAINProc(UINT nTimerId,UINT msg,DWORD dwUser,DWORD dwParam1, DWORD dwParam2) -{ - int s_1,s_2,fa,ns; - int core = 0; - unsigned char * start; - unsigned int nSample; - int d; - int ch,predict_nr,shift_factor,flags,s; - int gpos,bIRQReturn=0; - - while(!bEndThread) // until we are shutting down - { - //--------------------------------------------------// - // ok, at the beginning we are looking if there is - // enuff free place in the dsound/oss buffer to - // fill in new data, or if there is a new channel to start. - // if not, we wait (thread) or return (timer/spuasync) - // until enuff free place is available/a new channel gets - // started - if (aSyncMode==1) // Async supported? and enabled? - { - if (aSyncCounter<=737280) // If we have 10ms in the buffer, don't wait - { - if (aSyncWait<1000) Sleep(aSyncWait); // Wait a little to be more Synced (No more than 1 sec) - else Sleep (1000); - } - - while (aSyncCounter<=368640 && !bEndThread && aSyncMode==1) - Sleep (1); // bEndThread/aSyncMode are needed, to avoid close problems - - aSyncCounter -= 36864; // 1ms more done (48Hz*768cycles/Hz) - } - else - if(dwNewChannel2[0] || dwNewChannel2[1]) // new channel should start immedately? - { // (at least one bit 0 ... MAXCHANNEL is set?) - iSecureStart++; // -> set iSecure - if(iSecureStart>5) iSecureStart=0; // (if it is set 5 times - that means on 5 tries a new samples has been started - in a row, we will reset it, to give the sound update a chance) - } - else iSecureStart=0; // 0: no new channel should start - - while(!iSecureStart && !bEndThread && // no new start? no thread end? - (SoundGetBytesBuffered()>TESTSIZE)) // and still enuff data in sound buffer? - { - iSecureStart=0; // reset secure - - if(iUseTimer) // no-thread mode? - { - return; // -> and done this time (timer mode 1 or 2) - } - // win thread mode: - Sleep(PAUSE_W); // sleep for x ms (win) - - if(dwNewChannel2[0] || dwNewChannel2[1]) - iSecureStart=1; // if a new channel kicks in (or, of course, sound buffer runs low), we will leave the loop - } - //--------------------------------------------------// continue from irq handling in timer mode? - - if(lastch>=0) // will be -1 if no continue is pending - { - ch=lastch; ns=lastns; lastch=-1; // -> setup all kind of vars to continue - if( s_chan[ch].iSBPos < 28 ) { - goto GOON; // -> directly jump to the continue point - } - } - - //--------------------------------------------------// - //- main channel loop -// - //--------------------------------------------------// - { - for(ch=0;ch take it and calc steps - s_chan[ch].sinc = s_chan[ch].iRawPitch<<4; - if(!s_chan[ch].sinc) s_chan[ch].sinc=1; - if(iUseInterpolation==1) s_chan[ch].SB[32]=1; // -> freq change in simle imterpolation mode: set flag - } - - ns=0; - while(ns=0x10000L) - { - if(s_chan[ch].iSBPos==28) // 28 reached? - { - start=s_chan[ch].pCurr; // set up the current pos - - if (s_chan[ch].bOn==0) goto ENDX; // special "stop" sign - - s_chan[ch].iSBPos=0; - - s_1=s_chan[ch].s_1; - s_2=s_chan[ch].s_2; - - predict_nr = (int)*start; - start++; - flags = (int)*start; - start++; - - shift_factor = predict_nr&0xf; - predict_nr >>= 4; - // -------------------------------------- // - - for (nSample=0;nSample<28;nSample+=2,start++) - { - d=(int)*start; - s=((d&0xf)<<12); - if(s&0x8000) s|=0xffff0000; - - fa=(s >> shift_factor); - fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); - s_2=s_1; - s_1=fa; - s=((d & 0xf0) << 8); - - s_chan[ch].SB[nSample]=fa; - - if(s&0x8000) s|=0xffff0000; - fa=(s>>shift_factor); - fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); - s_2=s_1; - s_1=fa; - - s_chan[ch].SB[nSample+1]=fa; - } - - //////////////////////////////////////////// irq check - - if(spuCtrl2[core]&0x40) // some irq active? - { - if(iDebugMode==1) logprintf("IRQ Active ch %x, C%x\r\n", ch, ch/24); - - if((pSpuIrq[core] >= start-16 && // irq address reached? - pSpuIrq[core] <= start) || - ((flags&1) && // special: irq on looping addr, when stop/loop flag is set - (pSpuIrq[core] >= s_chan[ch].pLoop-16 && - pSpuIrq[core] <= s_chan[ch].pLoop))) - { - s_chan[ch].iIrqDone=1; // -> debug flag - - if(iDebugMode==1) logprintf("Sample End ch %x, C%x\r\n", ch, ch/24); - - regArea[0x7C0] |= 0x4< let's see what is happening if we call our irqs instead ;) - - if(iSPUIRQWait) // -> option: wait after irq for main emu - { - iSpuAsyncWait=1; - bIRQReturn=1; - } - } - } - - //////////////////////////////////////////// flag handler - if(flags & 0x2) s_chan[ch].bIgnoreLoop=1; // LOOP bit - - if(flags&0x4) s_chan[ch].pLoop=start-16; // LOOP/START bit - - if(flags&0x1) // 1: LOOP/END bit - { - dwEndChannel2[core]|=(1<<(ch%24)); - - if((flags&0xF) != 0x3) // Check if no loop is present - { - s_chan[ch].bIgnoreLoop=0; - s_chan[ch].bStop = 1; - logprintf("Stopping\r\n"); - } - else start = s_chan[ch].pLoop; - } - - s_chan[ch].pCurr=start; // store values for next cycle - s_chan[ch].s_1=s_1; - s_chan[ch].s_2=s_2; - - - //////////////////////////////////////////// - - if(bIRQReturn) // special return for "spu irq - wait for cpu action" - { - bIRQReturn=0; - if(iUseTimer!=2) - { - DWORD dwWatchTime=timeGetTime()+2500; - - while(iSpuAsyncWait && !bEndThread && - timeGetTime()32767L) fa=32767L; - if(fa<-32767L) fa=-32767L; - } - - if(iUseInterpolation>=2) // gauss/cubic interpolation - { - gpos = s_chan[ch].SB[28]; - gval0 = fa; - gpos = (gpos+1) & 3; - s_chan[ch].SB[28] = gpos; - } - else - if(iUseInterpolation==1) // simple interpolation - { - s_chan[ch].SB[28] = 0; - s_chan[ch].SB[29] = s_chan[ch].SB[30]; // -> helpers for simple linear interpolation: delay real val for two slots, and calc the two deltas, for a 'look at the future behaviour' - s_chan[ch].SB[30] = s_chan[ch].SB[31]; - s_chan[ch].SB[31] = fa; - s_chan[ch].SB[32] = 1; // -> flag: calc new interolation - } - else s_chan[ch].SB[29]=fa; // no interpolation - - s_chan[ch].spos -= 0x10000L; - } - - //////////////////////////////////////////////// - // noise handler... just produces some noise data - // surely wrong... and no noise frequency (spuCtrl&0x3f00) will be used... - // and sometimes the noise will be used as fmod modulation... pfff - - if(s_chan[ch].bNoise) - { - if((dwNoiseVal<<=1)&0x80000000L) - { - dwNoiseVal^=0x0040001L; - fa=((dwNoiseVal>>2)&0x7fff); - fa=-fa; - } - else fa=(dwNoiseVal>>2)&0x7fff; - - // mmm... depending on the noise freq we allow bigger/smaller changes to the previous val - fa=s_chan[ch].iOldNoise+((fa-s_chan[ch].iOldNoise)/((0x001f-((spuCtrl2[core]&0x3f00)>>9))+1)); - if(fa>32767L) fa=32767L; - if(fa<-32767L) fa=-32767L; - s_chan[ch].iOldNoise=fa; - - if(iUseInterpolation<2) // no gauss/cubic interpolation? - s_chan[ch].SB[29] = fa; // -> store noise val in "current sample" slot - } //---------------------------------------- - else // NO NOISE (NORMAL SAMPLE DATA) HERE - {//------------------------------------------// - if(iUseInterpolation==3) // cubic interpolation - { - long xd; - xd = ((s_chan[ch].spos) >> 1)+1; - gpos = s_chan[ch].SB[28]; - - fa = gval(3) - 3*gval(2) + 3*gval(1) - gval0; - fa *= (xd - (2<<15)) / 6; - fa >>= 15; - fa += gval(2) - gval(1) - gval(1) + gval0; - fa *= (xd - (1<<15)) >> 1; - fa >>= 15; - fa += gval(1) - gval0; - fa *= xd; - fa >>= 15; - fa = fa + gval0; - } - //------------------------------------------// - else - if(iUseInterpolation==2) // gauss interpolation - { - int vl, vr; - vl = (s_chan[ch].spos >> 6) & ~3; - gpos = s_chan[ch].SB[28]; - vr=(gauss[vl]*gval0)&~2047; - vr+=(gauss[vl+1]*gval(1))&~2047; - vr+=(gauss[vl+2]*gval(2))&~2047; - vr+=(gauss[vl+3]*gval(3))&~2047; - fa = vr>>11; - } - //------------------------------------------// - else - if(iUseInterpolation==1) // simple interpolation - { - if(s_chan[ch].sinc<0x10000L) // -> upsampling? - InterpolateUp(ch); // --> interpolate up - else InterpolateDown(ch); // --> else down - fa=s_chan[ch].SB[29]; - } - //------------------------------------------// - else fa=s_chan[ch].SB[29]; // no interpolation - } - - s_chan[ch].sval = (MixADSR(ch) * fa) / 1023; // add adsr - - if(s_chan[ch].bFMod==2) // fmod freq channel - { - int NP=((32768L+s_chan[ch].sval)*s_chan[ch+1].iRawPitch)>>14; - - if(NP>0x3fff) NP=0x3fff; - else if(NP<0x1) NP=0x1; - - NP=(48000L*NP)>>12; // calc frequency ( 48hz ) - - s_chan[ch+1].iActFreq=NP; - s_chan[ch+1].iUsedFreq=NP; - s_chan[ch+1].sinc=(((NP/10)<<16)/48000); // check , was 4800 - if(!s_chan[ch+1].sinc) s_chan[ch+1].sinc=1; - if(iUseInterpolation==1) // freq change in sipmle interpolation mode - s_chan[ch+1].SB[32]=1; - - } - else - { - ////////////////////////////////////////////// - // ok, left/right sound volume (ps2 volume goes from 0 ... 0x3fff) - - if(s_chan[ch].iMute) s_chan[ch].sval=0; // debug mute - else - { - if(s_chan[ch].bVolumeL) - SSumL[ns]+=(s_chan[ch].sval*s_chan[ch].iLeftVolume)>>14; - - if(s_chan[ch].bVolumeR) - SSumR[ns]+=(s_chan[ch].sval*s_chan[ch].iRightVolume)>>14; - } - - ////////////////////////////////////////////// - // now let us store sound data for reverb - - if(s_chan[ch].bRVBActive) StoreREVERB(ch,ns); - } - - //////////////////////////////////////////////// - // ok, go on until 1 ms data of this channel is collected - - ns++; - s_chan[ch].spos += s_chan[ch].sinc; - } -ENDX: ; - } - } - - //---------------------------------------------------// - //- here we have another 1 ms of sound data - //---------------------------------------------------// - /////////////////////////////////////////////////////// - // mix all channels (including reverb) into one buffer - for(ns=0;ns>16; - if((regArea[PS2_C1_MMIX] & 0x80)) SSumL[ns] += (DirectInputC1.Left*(int)regArea[PS2_C1_BVOLL])>>16; - - UpdateMainVolL(); - - d=SSumL[ns]/iVolume; - SSumL[ns]=0; - *pS++=(d<-32767) ? -32767 : ((d>32767) ? 32767 : d); - - SSumR[ns]+=MixREVERBRight(0); - SSumR[ns]+=MixREVERBRight(1); - - if((regArea[PS2_C0_MMIX] & 0x40)) SSumR[ns] += (DirectInputC0.Right*(int)regArea[PS2_C0_BVOLR])>>16; - if((regArea[PS2_C1_MMIX] & 0x40)) SSumR[ns] += (DirectInputC1.Right*(int)regArea[PS2_C1_BVOLR])>>16; - - UpdateMainVolR(); - d=SSumR[ns]/iVolume; - SSumR[ns]=0; - *pS++=(d<-32767) ? -32767 : ((d>32767) ? 32767 : d); - } - InitREVERB(); - - ////////////////////////////////////////////////////// - // feed the sound - // wanna have around 1/60 sec (16.666 ms) updates - - if(iCycle++>16) - { - SoundFeedVoiceData((unsigned char*)pSpuBuffer, - ((unsigned char *)pS)- - ((unsigned char *)pSpuBuffer)); - pS=(short *)pSpuBuffer; - iCycle=0; - } -} - // end of big main loop... - bThreadEnded=1; - return; -} - -//////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////// -DWORD WINAPI MAINThreadEx(LPVOID lpParameter) -{ - MAINProc(0,0,0,0,0); - return 0; -} - -//////////////////////////////////////////////////////////////////////// -// SPU ASYNC... even newer epsxe func -// 1 time every 'cycle' cycles... harhar -//////////////////////////////////////////////////////////////////////// -EXPORT_GCC void CALLBACK SPU2async(unsigned long cycle) -{ - SPUCycles += cycle; - if(interrupt & (1<<2)){ - if(SPUCycles - SPUStartCycle[1] >= SPUTargetCycle[1]){ - interrupt &= ~(1<<2); - irqCallbackDMA7(); - } - - } - - if(interrupt & (1<<1)){ - if(SPUCycles - SPUStartCycle[0] >= SPUTargetCycle[0]){ - interrupt &= ~(1<<1); - irqCallbackDMA4(); - } - } - - if(iSpuAsyncWait) - { - iSpuAsyncWait++; - if(iSpuAsyncWait<=64) return; - iSpuAsyncWait=0; - } - - if(iDebugMode==2) - { - if(IsWindow(hWDebug)) DestroyWindow(hWDebug); - hWDebug=0;iDebugMode=0; - } - if(iRecordMode==2) - { - if(IsWindow(hWRecord)) DestroyWindow(hWRecord); - hWRecord=0;iRecordMode=0; - } - - if(iUseTimer==0) // does the emu support SPUAsync, is it in thread mode, and in Thread Sync ON? - { - aSyncMode=1; // Ten, activate main function Sync system flag - - aSyncTimerOld = aSyncTimerNew; // Recalculate, AsyncWait (ms) - aSyncTimerNew = timeGetTime(); - - aSyncWait =(unsigned int)((aSyncTimerNew - aSyncTimerOld)/2); - - aSyncCounter += cycle ; - - return; - } - if(iUseTimer==2) // special mode, only used in Linux by this spu (or if you enable the experimental Windows mode) - { - aSyncMode = 0; - if(!bSpuInit) return; // -> no init, no call - MAINProc(0,0,0,0,0); // -> experimental win mode... not really tested... don't like the drawbacks - } -} - - -//////////////////////////////////////////////////////////////////////// -// INIT/EXIT STUFF -//////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////// -// SPUINIT: this func will be called first by the main emu -//////////////////////////////////////////////////////////////////////// - -#ifdef _WINDOWS -static HINSTANCE hIRE = NULL; -#endif - -EXPORT_GCC long CALLBACK SPU2init(void) -{ - spuMemC=(unsigned char *)spuMem; // just small setup - memset((void *)s_chan,0,MAXCHAN*sizeof(SPUCHAN)); - memset(rvb,0,2*sizeof(REVERBInfo)); - - InitADSR(); - - if(hIRE==NULL) hIRE=LoadLibrary("Riched32.dll "); // needed for debug output - - return 0; -} - -//////////////////////////////////////////////////////////////////////// -// SETUPTIMER: init of certain buffers and threads/timers -//////////////////////////////////////////////////////////////////////// - -void SetupTimer(void) -{ - memset(SSumR,0,NSSIZE*sizeof(int)); // init some mixing buffers - memset(SSumL,0,NSSIZE*sizeof(int)); - pS=(short *)pSpuBuffer; // setup soundbuffer pointer - pS1=(short *)pSpuStreamBuffer[0]; // setup soundbuffer pointer - - bEndThread=0; // init thread vars - bSpuInit=1; // flag: we are inited - - bSpuInit=1; // flag: we are inited - -#ifdef _WINDOWS - - if(iUseTimer==0) // windows: use thread - { - //_beginthread(MAINThread,0,NULL); - DWORD dw; - hMainThread=CreateThread(NULL,0,MAINThreadEx,0,0,&dw); - SetThreadPriority(hMainThread, - //THREAD_PRIORITY_TIME_CRITICAL); - THREAD_PRIORITY_HIGHEST); - } -#endif -} - -//////////////////////////////////////////////////////////////////////// -// REMOVETIMER: kill threads/timers -//////////////////////////////////////////////////////////////////////// - -void RemoveTimer(void) -{ - bEndThread=1; // raise flag to end thread - - if(iUseTimer!=2) // windows thread? - { - while(!bThreadEnded) {Sleep(5L);} // -> wait till thread has ended - Sleep(5L); - } - - bSpuInit=0; - - bThreadEnded=0; // no more spu is running -} - -//////////////////////////////////////////////////////////////////////// -// SETUPSTREAMS: init most of the spu buffers -//////////////////////////////////////////////////////////////////////// - -void SetupStreams(void) -{ - int i; - - pSpuBuffer=(unsigned char *)malloc(38400); // alloc mixing buffer - i=NSSIZE*2; - - sRVBStart[0] = (int *)malloc(i*4); // alloc reverb buffer - memset(sRVBStart[0],0,i*4); - sRVBEnd[0] = sRVBStart[0] + i; - sRVBPlay[0] = sRVBStart[0]; - sRVBStart[1] = (int *)malloc(i*4); // alloc reverb buffer - memset(sRVBStart[1],0,i*4); - sRVBEnd[1] = sRVBStart[1] + i; - sRVBPlay[1] = sRVBStart[1]; - - for(i=0;i init sustain - s_chan[i].iMute=0; - s_chan[i].iIrqDone=0; - s_chan[i].pLoop=spuMemC+(s_chan[i].iStartAdr<<1); - s_chan[i].pStart=spuMemC+(s_chan[i].iStartAdr<<1); - s_chan[i].pCurr=spuMemC+(s_chan[i].iStartAdr<<1); - } -} - -//////////////////////////////////////////////////////////////////////// -// REMOVESTREAMS: free most buffer -//////////////////////////////////////////////////////////////////////// - -void RemoveStreams(void) -{ - free(pSpuBuffer); // free mixing buffer - pSpuBuffer=NULL; - free(sRVBStart[0]); // free reverb buffer - sRVBStart[0]=0; - free(sRVBStart[1]); // free reverb buffer - sRVBStart[1]=0; -} - - -//////////////////////////////////////////////////////////////////////// -// SPUOPEN: called by main emu after init -//////////////////////////////////////////////////////////////////////// -#include -FILE * LogFile; -EXPORT_GCC long CALLBACK SPU2open(void* pWindow) -{ -#ifdef _WINDOWS - HWND hW= pWindow == NULL ? NULL : *(HWND*)pWindow; -#endif - - if(bSPUIsOpen) return 0; // security for some stupid main emus - LogFile = fopen("Logs/spu2.txt","wb"); - iVolume=3; - bEndThread=0; - bThreadEnded=0; - spuMemC=(unsigned char *)spuMem; - memset((void *)s_chan,0,(MAXCHAN+1)*sizeof(SPUCHAN)); - pSpuIrq[0]=spuMemC; - pSpuIrq[1]=spuMemC; - dwNewChannel2[0]=0; - dwNewChannel2[1]=0; - dwEndChannel2[0]=0; - dwEndChannel2[1]=0; - spuCtrl2[0]=0; - spuCtrl2[1]=0; - spuStat2[0]=0; - spuStat2[1]=0; - spuIrq2[0]=0; - spuIrq2[1]=0; - spuAddr2[0]=0x0; - spuAddr2[1]=0x0; - spuRvbAddr2[0]=0; - spuRvbAddr2[1]=0; - spuRvbAEnd2[0]=0; - spuRvbAEnd2[1]=0; - - memset(&Adma4,0,sizeof(ADMA)); - memset(&Adma7,0,sizeof(ADMA)); - - memset(&DirectInputC0,0,sizeof(DINPUT)); - memset(&DirectInputC1,0,sizeof(DINPUT)); - - LastWrite=0x00000000;LastPlay=0; // init some play vars - if(!IsWindow(hW)) hW=GetActiveWindow(); - hWMain = hW; // store hwnd - - ReadConfig(); // read user stuff - - SetupSound(); // setup midas (before init!) - - SetupStreams(); // prepare streaming - - SetupTimer(); // timer for feeding data - - bSPUIsOpen=1; - - if(iDebugMode) // windows debug dialog - { - hWDebug=CreateDialog(hInst,MAKEINTRESOURCE(IDD_DEBUG), - NULL,(DLGPROC)DebugDlgProc); - SetWindowPos(hWDebug,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOACTIVATE); - UpdateWindow(hWDebug); - SetFocus(hWMain); - } - - if(iRecordMode) // windows recording dialog - { - hWRecord=CreateDialog(hInst,MAKEINTRESOURCE(IDD_RECORD), - NULL,(DLGPROC)RecordDlgProc); - SetWindowPos(hWRecord,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOACTIVATE); - UpdateWindow(hWRecord); - SetFocus(hWMain); - } - - return 0; -} - -//////////////////////////////////////////////////////////////////////// - -// not used yet -#ifndef _WINDOWS -void SPU2setConfigFile(char * pCfg) -{ - pConfigFile=pCfg; -} -#endif - -//////////////////////////////////////////////////////////////////////// -// SPUCLOSE: called before shutdown -//////////////////////////////////////////////////////////////////////// - -EXPORT_GCC void CALLBACK SPU2close(void) -{ - if(!bSPUIsOpen) return; // some security - - bSPUIsOpen=0; // no more open - //fclose(LogFile); -#ifdef _WINDOWS - if(IsWindow(hWDebug)) DestroyWindow(hWDebug); - hWDebug=0; - if(IsWindow(hWRecord)) DestroyWindow(hWRecord); - hWRecord=0; -#endif - - RemoveTimer(); // no more feeding - - RemoveSound(); // no more sound handling - - RemoveStreams(); // no more streaming -} - -//////////////////////////////////////////////////////////////////////// -// SPUSHUTDOWN: called by main emu on final exit -//////////////////////////////////////////////////////////////////////// - -EXPORT_GCC void CALLBACK SPU2shutdown(void) -{ -#ifdef _WINDOWS - if(hIRE!=NULL) {FreeLibrary(hIRE);hIRE=NULL;} -#endif - - return; -} - -//////////////////////////////////////////////////////////////////////// -// SPUTEST: we don't test, we are always fine ;) -//////////////////////////////////////////////////////////////////////// - -EXPORT_GCC long CALLBACK SPU2test(void) -{ - return 0; -} - -//////////////////////////////////////////////////////////////////////// -// SPUCONFIGURE: call config dialog -//////////////////////////////////////////////////////////////////////// - -EXPORT_GCC void CALLBACK SPU2configure(void) -{ -#ifdef _WINDOWS - DialogBox(hInst,MAKEINTRESOURCE(IDD_CFGDLG), - GetActiveWindow(),(DLGPROC)DSoundDlgProc); -#else - StartCfgTool("CFG"); -#endif -} - -//////////////////////////////////////////////////////////////////////// -// SPUABOUT: show about window -//////////////////////////////////////////////////////////////////////// - -EXPORT_GCC void CALLBACK SPU2about(void) -{ -#ifdef _WINDOWS - DialogBox(hInst,MAKEINTRESOURCE(IDD_ABOUT), - GetActiveWindow(),(DLGPROC)AboutDlgProc); -#else - StartCfgTool("ABOUT"); -#endif -} - -//////////////////////////////////////////////////////////////////////// -// SETUP CALLBACKS -// this functions will be called once, -// passes a callback that should be called on SPU-IRQ/cdda volume change -//////////////////////////////////////////////////////////////////////// - -EXPORT_GCC void CALLBACK SPU2irqCallback(void (CALLBACK *SPU2callback)(int), - void (CALLBACK *DMA4callback)(int), - void (CALLBACK *DMA7callback)(int)) -{ - irqCallbackSPU2 = SPU2callback; - irqCallbackDMA4 = DMA4callback; - irqCallbackDMA7 = DMA7callback; -} - -//////////////////////////////////////////////////////////////////////// -// COMMON PLUGIN INFO FUNCS -//////////////////////////////////////////////////////////////////////// - -EXPORT_GCC char * CALLBACK PS2EgetLibName(void) -{ - return libraryName; -} - -#define PS2E_LT_SPU2 0x4 - -EXPORT_GCC unsigned long CALLBACK PS2EgetLibType(void) -{ - return PS2E_LT_SPU2; -} - -EXPORT_GCC unsigned long CALLBACK PS2EgetLibVersion2(unsigned long type) -{ - unsigned char v=version; - - // key hack to fake a lower version: - //if(GetAsyncKeyState(VK_SHIFT)&0x8000) v--; - - // compile hack to set lib version to PCSX2 0.6 standards - //v=2; - - return v<<16|revision<<8|build; -} - -//////////////////////////////////////////////////////////////////////// - +/*************************************************************************** + spu.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2005/08/29 - Pete +// - changed to 48Khz output +// +// 2004/12/25 - Pete +// - inc'd version for pcsx2-0.7 +// +// 2004/04/18 - Pete +// - changed all kind of things in the plugin +// +// 2004/04/04 - Pete +// - changed plugin to emulate PS2 spu +// +// 2003/04/07 - Eric +// - adjusted cubic interpolation algorithm +// +// 2003/03/16 - Eric +// - added cubic interpolation +// +// 2003/03/01 - linuzappz +// - libraryName changes using ALSA +// +// 2003/02/28 - Pete +// - added option for type of interpolation +// - adjusted spu irqs again (Thousant Arms, Valkyrie Profile) +// - added MONO support for MSWindows DirectSound +// +// 2003/02/20 - kode54 +// - amended interpolation code, goto GOON could skip initialization of gpos and cause segfault +// +// 2003/02/19 - kode54 +// - moved SPU IRQ handler and changed sample flag processing +// +// 2003/02/18 - kode54 +// - moved ADSR calculation outside of the sample decode loop, somehow I doubt that +// ADSR timing is relative to the frequency at which a sample is played... I guess +// this remains to be seen, and I don't know whether ADSR is applied to noise channels... +// +// 2003/02/09 - kode54 +// - one-shot samples now process the end block before stopping +// - in light of removing fmod hack, now processing ADSR on frequency channel as well +// +// 2003/02/08 - kode54 +// - replaced easy interpolation with gaussian +// - removed fmod averaging hack +// - changed .sinc to be updated from .iRawPitch, no idea why it wasn't done this way already (<- Pete: because I sometimes fail to see the obvious, haharhar :) +// +// 2003/02/08 - linuzappz +// - small bugfix for one usleep that was 1 instead of 1000 +// - added iDisStereo for no stereo (Linux) +// +// 2003/01/22 - Pete +// - added easy interpolation & small noise adjustments +// +// 2003/01/19 - Pete +// - added Neill's reverb +// +// 2003/01/12 - Pete +// - added recording window handlers +// +// 2003/01/06 - Pete +// - added Neill's ADSR timings +// +// 2002/12/28 - Pete +// - adjusted spu irq handling, fmod handling and loop handling +// +// 2002/08/14 - Pete +// - added extra reverb +// +// 2002/06/08 - linuzappz +// - SPUupdate changed for SPUasync +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_SPU + +#include "externals.h" +#include "cfg.h" +#include "dsoundoss.h" +#include "regs.h" +#include "debug.h" +#include "record.h" +#include "resource.h" +#include "dma.h" +#include "registers.h" +//////////////////////////////////////////////////////////////////////// +// spu version infos/name +//////////////////////////////////////////////////////////////////////// + +const unsigned char version = 5; +const unsigned char revision = 1; +const unsigned char build = 6; +static char * libraryName = "P.E.Op.S. SPU2 DSound Driver"; +static char * libraryInfo = "P.E.Op.S. SPU2 Driver V1.6\nCoded by Pete Bernert, Saqib and the P.E.Op.S. team\n"; +//////////////////////////////////////////////////////////////////////// +// globals +//////////////////////////////////////////////////////////////////////// + +// psx buffer / addresses + +unsigned short regArea[32*1024]; + short spuMem[2*1024*1024]; + char * spuMemC; +unsigned char * pSpuIrq[2]; +unsigned char * pSpuBuffer; +unsigned char * pSpuStreamBuffer[2]; + +// user settings + +int iVolume=3; +int iDebugMode=0; +int iRecordMode=0; +int iUseReverb=0; +int iUseInterpolation=2; + +// MAIN infos struct for each channel + +SPUCHAN s_chan[MAXCHAN+1]; // channel + 1 infos (1 is security for fmod handling) +REVERBInfo rvb[2]; + +unsigned long dwNoiseVal=1; // global noise generator +int iSPUIRQWait=1; +unsigned short spuCtrl2[2]; // some vars to store psx reg infos +unsigned short spuStat2[2]; +unsigned long spuIrq2[2]; +unsigned long spuAddr2[2]; // address into spu mem +unsigned long spuRvbAddr2[2]; +unsigned long spuRvbAEnd2[2]; +int bEndThread=0; // thread handlers +int bSpuInit=0; +int bSPUIsOpen=0; +int bThreadEnded=0; +int iUseTimer=2; +int aSyncMode=0; +unsigned long aSyncCounter=0; +unsigned long aSyncWait=0; +DWORD aSyncTimerNew; +DWORD aSyncTimerOld; +HWND hWMain=0; // window handle +HWND hWDebug=0; +HWND hWRecord=0; + +static HANDLE hMainThread; +unsigned long dwNewChannel2[2]; // flags for faster testing, if new channel starts +unsigned long dwEndChannel2[2]; + +void (CALLBACK *irqCallbackDMA4)()=0; // func of main emu, called on spu irq +void (CALLBACK *irqCallbackDMA7)()=0; // func of main emu, called on spu irq +void (CALLBACK *irqCallbackSPU2)()=0; // func of main emu, called on spu irq + +// certain globals (were local before, but with the new timeproc I need em global) + +const int f[5][2] = { { 0, 0 }, + { 60, 0 }, + { 115, -52 }, + { 98, -55 }, + { 122, -60 } }; +int SSumR[NSSIZE]; +int SSumL[NSSIZE]; + +extern ADMA Adma4; +extern ADMA Adma7; +DINPUT DirectInputC0, DirectInputC1; + +extern unsigned short interrupt; +int SPUCycles; +extern int SPUStartCycle[2]; +extern int SPUTargetCycle[2]; + +int iCycle=0; +short * pS; +short * pS1; + +static int lastch=-1; // last channel processed on spu irq in timer mode +static int lastns=0; // last ns pos +static int iSecureStart=0; // secure start counter + +//////////////////////////////////////////////////////////////////////// +// CODE AREA +//////////////////////////////////////////////////////////////////////// + +// dirty inline func includes + +#include "reverb.c" +#include "adsr.c" + +//////////////////////////////////////////////////////////////////////// +// helpers for simple interpolation + +// +// easy interpolation on upsampling, no special filter, just "Pete's common sense" tm +// +// instead of having n equal sample values in a row like: +// ____ +// |____ +// +// we compare the current delta change with the next delta change. +// +// if curr_delta is positive, +// +// - and next delta is smaller (or changing direction): +// \. +// -__ +// +// - and next delta significant (at least twice) bigger: +// --_ +// \. +// +// - and next delta is nearly same: +// \. +// \. +// +// +// if curr_delta is negative, +// +// - and next delta is smaller (or changing direction): +// _-- +// / +// +// - and next delta significant (at least twice) bigger: +// / +// __- +// +// - and next delta is nearly same: +// / +// / +// + + +INLINE void InterpolateUp(int ch) +{ + if(s_chan[ch].SB[32]==1) // flag == 1? calc step and set flag... and don't change the value in this pass + { + const int id1=s_chan[ch].SB[30]-s_chan[ch].SB[29]; // curr delta to next val + const int id2=s_chan[ch].SB[31]-s_chan[ch].SB[30]; // and next delta to next-next val :) + + s_chan[ch].SB[32]=0; + + if(id1>0) // curr delta positive + { + if(id2id1) + {s_chan[ch].SB[28]=id1;s_chan[ch].SB[32]=2;} + else + if(id2>(id1<<1)) + s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x10000L; + else + s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x20000L; + } + } + else + if(s_chan[ch].SB[32]==2) // flag 1: calc step and set flag... and don't change the value in this pass + { + s_chan[ch].SB[32]=0; + + s_chan[ch].SB[28]=(s_chan[ch].SB[28]*s_chan[ch].sinc)/0x20000L; + if(s_chan[ch].sinc<=0x8000) + s_chan[ch].SB[29]=s_chan[ch].SB[30]-(s_chan[ch].SB[28]*((0x10000/s_chan[ch].sinc)-1)); + else s_chan[ch].SB[29]+=s_chan[ch].SB[28]; + } + else // no flags? add bigger val (if possible), calc smaller step, set flag1 + s_chan[ch].SB[29]+=s_chan[ch].SB[28]; +} + +// +// even easier interpolation on downsampling, also no special filter, again just "Pete's common sense" tm +// + +INLINE void InterpolateDown(int ch) +{ + if(s_chan[ch].sinc>=0x20000) // we would skip at least one val? + { + s_chan[ch].SB[29]+=(s_chan[ch].SB[30]-s_chan[ch].SB[29])/2; // add easy weight + if(s_chan[ch].sinc>=0x30000) // we would skip even more vals? + s_chan[ch].SB[29]+=(s_chan[ch].SB[31]-s_chan[ch].SB[30])/2;// add additional next weight + } +} + +//////////////////////////////////////////////////////////////////////// +// helpers for gauss interpolation + +#define gval0 (((short*)(&s_chan[ch].SB[29]))[gpos]) +#define gval(x) (((short*)(&s_chan[ch].SB[29]))[(gpos+x)&3]) + +#include "gauss_i.h" + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +// START SOUND... called by main thread to setup a new sound on a channel +//////////////////////////////////////////////////////////////////////// + +INLINE void StartSound(int ch) +{ + dwNewChannel2[ch/24]&=~(1<<(ch%24)); // clear new channel bit + dwEndChannel2[ch/24]&=~(1<<(ch%24)); // clear end channel bit + + StartADSR(ch); + StartREVERB(ch); + + s_chan[ch].pCurr=s_chan[ch].pStart; // set sample start + + s_chan[ch].s_1=0; // init mixing vars + s_chan[ch].s_2=0; + s_chan[ch].iSBPos=28; + + s_chan[ch].bNew=0; // init channel flags + s_chan[ch].bStop=0; + s_chan[ch].bOn=1; + + s_chan[ch].SB[29]=0; // init our interpolation helpers + s_chan[ch].SB[30]=0; + + if(iUseInterpolation>=2) // gauss interpolation? + {s_chan[ch].spos=0x30000L;s_chan[ch].SB[28]=0;} // -> start with more decoding + else {s_chan[ch].spos=0x10000L;s_chan[ch].SB[31]=0;} // -> no/simple interpolation starts with one 44100 decoding +} + + +void UpdateMainVolL() // LEFT VOLUME +{ + short vol = regArea[PS2_C0_MVOLL]; + if(vol&0x8000) // sweep? + { + short sInc=1; // -> sweep up? + if(vol&0x2000) sInc=-1; // -> or down? + if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this + vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64 + vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half! + vol*=128; + } + else // no sweep: + { + if(vol&0x4000) // -> mmm... phase inverted? have to investigate this + //vol^=0xffff; + vol=0x3fff-(vol&0x3fff); + } + + vol&=0x3fff; + regArea[PS2_C0_MVOLL]=vol; // store volume +} + +//////////////////////////////////////////////////////////////////////// +// RIGHT VOLUME register write +//////////////////////////////////////////////////////////////////////// + +void UpdateMainVolR() // RIGHT VOLUME +{ + short vol = regArea[PS2_C0_MVOLR]; + if(vol&0x8000) // comments... see above :) + { + short sInc=1; + if(vol&0x2000) sInc=-1; + if(vol&0x1000) vol^=0xffff; + vol=((vol&0x7f)+1)/2; + vol+=vol/(2*sInc); + vol*=128; + } + else + { + if(vol&0x4000) //vol=vol^=0xffff; + vol=0x3fff-(vol&0x3fff); + } + + vol&=0x3fff; + + regArea[PS2_C0_MVOLR]=vol; +} +//////////////////////////////////////////////////////////////////////// +// MAIN SPU FUNCTION +// here is the main job handler... thread, timer or direct func call +// basically the whole sound processing is done in this fat func! +//////////////////////////////////////////////////////////////////////// + +// 5 ms waiting phase, if buffer is full and no new sound has to get started +// .. can be made smaller (smallest val: 1 ms), but bigger waits give +// better performance + +#define PAUSE_W 5 +#define PAUSE_L 5000 +extern unsigned long MemAddr[2]; +//////////////////////////////////////////////////////////////////////// + +int iSpuAsyncWait=0; +extern int MMIXC0, MMIXC1; + +VOID CALLBACK MAINProc(UINT nTimerId,UINT msg,DWORD dwUser,DWORD dwParam1, DWORD dwParam2) +{ + int s_1,s_2,fa,ns; + int core = 0; + unsigned char * start; + unsigned int nSample; + int d; + int ch,predict_nr,shift_factor,flags,s; + int gpos,bIRQReturn=0; + + while(!bEndThread) // until we are shutting down + { + //--------------------------------------------------// + // ok, at the beginning we are looking if there is + // enuff free place in the dsound/oss buffer to + // fill in new data, or if there is a new channel to start. + // if not, we wait (thread) or return (timer/spuasync) + // until enuff free place is available/a new channel gets + // started + if (aSyncMode==1) // Async supported? and enabled? + { + if (aSyncCounter<=737280) // If we have 10ms in the buffer, don't wait + { + if (aSyncWait<1000) Sleep(aSyncWait); // Wait a little to be more Synced (No more than 1 sec) + else Sleep (1000); + } + + while (aSyncCounter<=368640 && !bEndThread && aSyncMode==1) + Sleep (1); // bEndThread/aSyncMode are needed, to avoid close problems + + aSyncCounter -= 36864; // 1ms more done (48Hz*768cycles/Hz) + } + else + if(dwNewChannel2[0] || dwNewChannel2[1]) // new channel should start immedately? + { // (at least one bit 0 ... MAXCHANNEL is set?) + iSecureStart++; // -> set iSecure + if(iSecureStart>5) iSecureStart=0; // (if it is set 5 times - that means on 5 tries a new samples has been started - in a row, we will reset it, to give the sound update a chance) + } + else iSecureStart=0; // 0: no new channel should start + + while(!iSecureStart && !bEndThread && // no new start? no thread end? + (SoundGetBytesBuffered()>TESTSIZE)) // and still enuff data in sound buffer? + { + iSecureStart=0; // reset secure + + if(iUseTimer) // no-thread mode? + { + return; // -> and done this time (timer mode 1 or 2) + } + // win thread mode: + Sleep(PAUSE_W); // sleep for x ms (win) + + if(dwNewChannel2[0] || dwNewChannel2[1]) + iSecureStart=1; // if a new channel kicks in (or, of course, sound buffer runs low), we will leave the loop + } + //--------------------------------------------------// continue from irq handling in timer mode? + + if(lastch>=0) // will be -1 if no continue is pending + { + ch=lastch; ns=lastns; lastch=-1; // -> setup all kind of vars to continue + if( s_chan[ch].iSBPos < 28 ) { + goto GOON; // -> directly jump to the continue point + } + } + + //--------------------------------------------------// + //- main channel loop -// + //--------------------------------------------------// + { + for(ch=0;ch take it and calc steps + s_chan[ch].sinc = s_chan[ch].iRawPitch<<4; + if(!s_chan[ch].sinc) s_chan[ch].sinc=1; + if(iUseInterpolation==1) s_chan[ch].SB[32]=1; // -> freq change in simle imterpolation mode: set flag + } + + ns=0; + while(ns=0x10000L) + { + if(s_chan[ch].iSBPos==28) // 28 reached? + { + start=s_chan[ch].pCurr; // set up the current pos + + if (s_chan[ch].bOn==0) goto ENDX; // special "stop" sign + + s_chan[ch].iSBPos=0; + + s_1=s_chan[ch].s_1; + s_2=s_chan[ch].s_2; + + predict_nr = (int)*start; + start++; + flags = (int)*start; + start++; + + shift_factor = predict_nr&0xf; + predict_nr >>= 4; + // -------------------------------------- // + + for (nSample=0;nSample<28;nSample+=2,start++) + { + d=(int)*start; + s=((d&0xf)<<12); + if(s&0x8000) s|=0xffff0000; + + fa=(s >> shift_factor); + fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1; + s_1=fa; + s=((d & 0xf0) << 8); + + s_chan[ch].SB[nSample]=fa; + + if(s&0x8000) s|=0xffff0000; + fa=(s>>shift_factor); + fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1; + s_1=fa; + + s_chan[ch].SB[nSample+1]=fa; + } + + //////////////////////////////////////////// irq check + + if(spuCtrl2[core]&0x40) // some irq active? + { + if(iDebugMode==1) logprintf("IRQ Active ch %x, C%x\r\n", ch, ch/24); + + if((pSpuIrq[core] >= start-16 && // irq address reached? + pSpuIrq[core] <= start) || + ((flags&1) && // special: irq on looping addr, when stop/loop flag is set + (pSpuIrq[core] >= s_chan[ch].pLoop-16 && + pSpuIrq[core] <= s_chan[ch].pLoop))) + { + s_chan[ch].iIrqDone=1; // -> debug flag + + if(iDebugMode==1) logprintf("Sample End ch %x, C%x\r\n", ch, ch/24); + + regArea[0x7C0] |= 0x4< let's see what is happening if we call our irqs instead ;) + + if(iSPUIRQWait) // -> option: wait after irq for main emu + { + iSpuAsyncWait=1; + bIRQReturn=1; + } + } + } + + //////////////////////////////////////////// flag handler + if(flags & 0x2) s_chan[ch].bIgnoreLoop=1; // LOOP bit + + if(flags&0x4) s_chan[ch].pLoop=start-16; // LOOP/START bit + + if(flags&0x1) // 1: LOOP/END bit + { + dwEndChannel2[core]|=(1<<(ch%24)); + + if((flags&0xF) != 0x3) // Check if no loop is present + { + s_chan[ch].bIgnoreLoop=0; + s_chan[ch].bStop = 1; + logprintf("Stopping\r\n"); + } + else start = s_chan[ch].pLoop; + } + + s_chan[ch].pCurr=start; // store values for next cycle + s_chan[ch].s_1=s_1; + s_chan[ch].s_2=s_2; + + + //////////////////////////////////////////// + + if(bIRQReturn) // special return for "spu irq - wait for cpu action" + { + bIRQReturn=0; + if(iUseTimer!=2) + { + DWORD dwWatchTime=timeGetTime()+2500; + + while(iSpuAsyncWait && !bEndThread && + timeGetTime()32767L) fa=32767L; + if(fa<-32767L) fa=-32767L; + } + + if(iUseInterpolation>=2) // gauss/cubic interpolation + { + gpos = s_chan[ch].SB[28]; + gval0 = fa; + gpos = (gpos+1) & 3; + s_chan[ch].SB[28] = gpos; + } + else + if(iUseInterpolation==1) // simple interpolation + { + s_chan[ch].SB[28] = 0; + s_chan[ch].SB[29] = s_chan[ch].SB[30]; // -> helpers for simple linear interpolation: delay real val for two slots, and calc the two deltas, for a 'look at the future behaviour' + s_chan[ch].SB[30] = s_chan[ch].SB[31]; + s_chan[ch].SB[31] = fa; + s_chan[ch].SB[32] = 1; // -> flag: calc new interolation + } + else s_chan[ch].SB[29]=fa; // no interpolation + + s_chan[ch].spos -= 0x10000L; + } + + //////////////////////////////////////////////// + // noise handler... just produces some noise data + // surely wrong... and no noise frequency (spuCtrl&0x3f00) will be used... + // and sometimes the noise will be used as fmod modulation... pfff + + if(s_chan[ch].bNoise) + { + if((dwNoiseVal<<=1)&0x80000000L) + { + dwNoiseVal^=0x0040001L; + fa=((dwNoiseVal>>2)&0x7fff); + fa=-fa; + } + else fa=(dwNoiseVal>>2)&0x7fff; + + // mmm... depending on the noise freq we allow bigger/smaller changes to the previous val + fa=s_chan[ch].iOldNoise+((fa-s_chan[ch].iOldNoise)/((0x001f-((spuCtrl2[core]&0x3f00)>>9))+1)); + if(fa>32767L) fa=32767L; + if(fa<-32767L) fa=-32767L; + s_chan[ch].iOldNoise=fa; + + if(iUseInterpolation<2) // no gauss/cubic interpolation? + s_chan[ch].SB[29] = fa; // -> store noise val in "current sample" slot + } //---------------------------------------- + else // NO NOISE (NORMAL SAMPLE DATA) HERE + {//------------------------------------------// + if(iUseInterpolation==3) // cubic interpolation + { + long xd; + xd = ((s_chan[ch].spos) >> 1)+1; + gpos = s_chan[ch].SB[28]; + + fa = gval(3) - 3*gval(2) + 3*gval(1) - gval0; + fa *= (xd - (2<<15)) / 6; + fa >>= 15; + fa += gval(2) - gval(1) - gval(1) + gval0; + fa *= (xd - (1<<15)) >> 1; + fa >>= 15; + fa += gval(1) - gval0; + fa *= xd; + fa >>= 15; + fa = fa + gval0; + } + //------------------------------------------// + else + if(iUseInterpolation==2) // gauss interpolation + { + int vl, vr; + vl = (s_chan[ch].spos >> 6) & ~3; + gpos = s_chan[ch].SB[28]; + vr=(gauss[vl]*gval0)&~2047; + vr+=(gauss[vl+1]*gval(1))&~2047; + vr+=(gauss[vl+2]*gval(2))&~2047; + vr+=(gauss[vl+3]*gval(3))&~2047; + fa = vr>>11; + } + //------------------------------------------// + else + if(iUseInterpolation==1) // simple interpolation + { + if(s_chan[ch].sinc<0x10000L) // -> upsampling? + InterpolateUp(ch); // --> interpolate up + else InterpolateDown(ch); // --> else down + fa=s_chan[ch].SB[29]; + } + //------------------------------------------// + else fa=s_chan[ch].SB[29]; // no interpolation + } + + s_chan[ch].sval = (MixADSR(ch) * fa) / 1023; // add adsr + + if(s_chan[ch].bFMod==2) // fmod freq channel + { + int NP=((32768L+s_chan[ch].sval)*s_chan[ch+1].iRawPitch)>>14; + + if(NP>0x3fff) NP=0x3fff; + else if(NP<0x1) NP=0x1; + + NP=(48000L*NP)>>12; // calc frequency ( 48hz ) + + s_chan[ch+1].iActFreq=NP; + s_chan[ch+1].iUsedFreq=NP; + s_chan[ch+1].sinc=(((NP/10)<<16)/48000); // check , was 4800 + if(!s_chan[ch+1].sinc) s_chan[ch+1].sinc=1; + if(iUseInterpolation==1) // freq change in sipmle interpolation mode + s_chan[ch+1].SB[32]=1; + + } + else + { + ////////////////////////////////////////////// + // ok, left/right sound volume (ps2 volume goes from 0 ... 0x3fff) + + if(s_chan[ch].iMute) s_chan[ch].sval=0; // debug mute + else + { + if(s_chan[ch].bVolumeL) + SSumL[ns]+=(s_chan[ch].sval*s_chan[ch].iLeftVolume)>>14; + + if(s_chan[ch].bVolumeR) + SSumR[ns]+=(s_chan[ch].sval*s_chan[ch].iRightVolume)>>14; + } + + ////////////////////////////////////////////// + // now let us store sound data for reverb + + if(s_chan[ch].bRVBActive) StoreREVERB(ch,ns); + } + + //////////////////////////////////////////////// + // ok, go on until 1 ms data of this channel is collected + + ns++; + s_chan[ch].spos += s_chan[ch].sinc; + } +ENDX: ; + } + } + + //---------------------------------------------------// + //- here we have another 1 ms of sound data + //---------------------------------------------------// + /////////////////////////////////////////////////////// + // mix all channels (including reverb) into one buffer + for(ns=0;ns>16; + if((regArea[PS2_C1_MMIX] & 0x80)) SSumL[ns] += (DirectInputC1.Left*(int)regArea[PS2_C1_BVOLL])>>16; + + UpdateMainVolL(); + + d=SSumL[ns]/iVolume; + SSumL[ns]=0; + *pS++=(d<-32767) ? -32767 : ((d>32767) ? 32767 : d); + + SSumR[ns]+=MixREVERBRight(0); + SSumR[ns]+=MixREVERBRight(1); + + if((regArea[PS2_C0_MMIX] & 0x40)) SSumR[ns] += (DirectInputC0.Right*(int)regArea[PS2_C0_BVOLR])>>16; + if((regArea[PS2_C1_MMIX] & 0x40)) SSumR[ns] += (DirectInputC1.Right*(int)regArea[PS2_C1_BVOLR])>>16; + + UpdateMainVolR(); + d=SSumR[ns]/iVolume; + SSumR[ns]=0; + *pS++=(d<-32767) ? -32767 : ((d>32767) ? 32767 : d); + } + InitREVERB(); + + ////////////////////////////////////////////////////// + // feed the sound + // wanna have around 1/60 sec (16.666 ms) updates + + if(iCycle++>16) + { + SoundFeedVoiceData((unsigned char*)pSpuBuffer, + ((unsigned char *)pS)- + ((unsigned char *)pSpuBuffer)); + pS=(short *)pSpuBuffer; + iCycle=0; + } +} + // end of big main loop... + bThreadEnded=1; + return; +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +DWORD WINAPI MAINThreadEx(LPVOID lpParameter) +{ + MAINProc(0,0,0,0,0); + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// SPU ASYNC... even newer epsxe func +// 1 time every 'cycle' cycles... harhar +//////////////////////////////////////////////////////////////////////// +EXPORT_GCC void CALLBACK SPU2async(unsigned long cycle) +{ + SPUCycles += cycle; + if(interrupt & (1<<2)){ + if(SPUCycles - SPUStartCycle[1] >= SPUTargetCycle[1]){ + interrupt &= ~(1<<2); + irqCallbackDMA7(); + } + + } + + if(interrupt & (1<<1)){ + if(SPUCycles - SPUStartCycle[0] >= SPUTargetCycle[0]){ + interrupt &= ~(1<<1); + irqCallbackDMA4(); + } + } + + if(iSpuAsyncWait) + { + iSpuAsyncWait++; + if(iSpuAsyncWait<=64) return; + iSpuAsyncWait=0; + } + + if(iDebugMode==2) + { + if(IsWindow(hWDebug)) DestroyWindow(hWDebug); + hWDebug=0;iDebugMode=0; + } + if(iRecordMode==2) + { + if(IsWindow(hWRecord)) DestroyWindow(hWRecord); + hWRecord=0;iRecordMode=0; + } + + if(iUseTimer==0) // does the emu support SPUAsync, is it in thread mode, and in Thread Sync ON? + { + aSyncMode=1; // Ten, activate main function Sync system flag + + aSyncTimerOld = aSyncTimerNew; // Recalculate, AsyncWait (ms) + aSyncTimerNew = timeGetTime(); + + aSyncWait =(unsigned int)((aSyncTimerNew - aSyncTimerOld)/2); + + aSyncCounter += cycle ; + + return; + } + if(iUseTimer==2) // special mode, only used in Linux by this spu (or if you enable the experimental Windows mode) + { + aSyncMode = 0; + if(!bSpuInit) return; // -> no init, no call + MAINProc(0,0,0,0,0); // -> experimental win mode... not really tested... don't like the drawbacks + } +} + + +//////////////////////////////////////////////////////////////////////// +// INIT/EXIT STUFF +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +// SPUINIT: this func will be called first by the main emu +//////////////////////////////////////////////////////////////////////// + +#ifdef _WINDOWS +static HINSTANCE hIRE = NULL; +#endif + +EXPORT_GCC long CALLBACK SPU2init(void) +{ + spuMemC=(unsigned char *)spuMem; // just small setup + memset((void *)s_chan,0,MAXCHAN*sizeof(SPUCHAN)); + memset(rvb,0,2*sizeof(REVERBInfo)); + + InitADSR(); + + if(hIRE==NULL) hIRE=LoadLibrary("Riched32.dll "); // needed for debug output + + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// SETUPTIMER: init of certain buffers and threads/timers +//////////////////////////////////////////////////////////////////////// + +void SetupTimer(void) +{ + memset(SSumR,0,NSSIZE*sizeof(int)); // init some mixing buffers + memset(SSumL,0,NSSIZE*sizeof(int)); + pS=(short *)pSpuBuffer; // setup soundbuffer pointer + pS1=(short *)pSpuStreamBuffer[0]; // setup soundbuffer pointer + + bEndThread=0; // init thread vars + bSpuInit=1; // flag: we are inited + + bSpuInit=1; // flag: we are inited + +#ifdef _WINDOWS + + if(iUseTimer==0) // windows: use thread + { + //_beginthread(MAINThread,0,NULL); + DWORD dw; + hMainThread=CreateThread(NULL,0,MAINThreadEx,0,0,&dw); + SetThreadPriority(hMainThread, + //THREAD_PRIORITY_TIME_CRITICAL); + THREAD_PRIORITY_HIGHEST); + } +#endif +} + +//////////////////////////////////////////////////////////////////////// +// REMOVETIMER: kill threads/timers +//////////////////////////////////////////////////////////////////////// + +void RemoveTimer(void) +{ + bEndThread=1; // raise flag to end thread + + if(iUseTimer!=2) // windows thread? + { + while(!bThreadEnded) {Sleep(5L);} // -> wait till thread has ended + Sleep(5L); + } + + bSpuInit=0; + + bThreadEnded=0; // no more spu is running +} + +//////////////////////////////////////////////////////////////////////// +// SETUPSTREAMS: init most of the spu buffers +//////////////////////////////////////////////////////////////////////// + +void SetupStreams(void) +{ + int i; + + pSpuBuffer=(unsigned char *)malloc(38400); // alloc mixing buffer + i=NSSIZE*2; + + sRVBStart[0] = (int *)malloc(i*4); // alloc reverb buffer + memset(sRVBStart[0],0,i*4); + sRVBEnd[0] = sRVBStart[0] + i; + sRVBPlay[0] = sRVBStart[0]; + sRVBStart[1] = (int *)malloc(i*4); // alloc reverb buffer + memset(sRVBStart[1],0,i*4); + sRVBEnd[1] = sRVBStart[1] + i; + sRVBPlay[1] = sRVBStart[1]; + + for(i=0;i init sustain + s_chan[i].iMute=0; + s_chan[i].iIrqDone=0; + s_chan[i].pLoop=spuMemC+(s_chan[i].iStartAdr<<1); + s_chan[i].pStart=spuMemC+(s_chan[i].iStartAdr<<1); + s_chan[i].pCurr=spuMemC+(s_chan[i].iStartAdr<<1); + } +} + +//////////////////////////////////////////////////////////////////////// +// REMOVESTREAMS: free most buffer +//////////////////////////////////////////////////////////////////////// + +void RemoveStreams(void) +{ + free(pSpuBuffer); // free mixing buffer + pSpuBuffer=NULL; + free(sRVBStart[0]); // free reverb buffer + sRVBStart[0]=0; + free(sRVBStart[1]); // free reverb buffer + sRVBStart[1]=0; +} + + +//////////////////////////////////////////////////////////////////////// +// SPUOPEN: called by main emu after init +//////////////////////////////////////////////////////////////////////// +#include +FILE * LogFile; +EXPORT_GCC long CALLBACK SPU2open(void* pWindow) +{ +#ifdef _WINDOWS + HWND hW= pWindow == NULL ? NULL : *(HWND*)pWindow; +#endif + + if(bSPUIsOpen) return 0; // security for some stupid main emus + LogFile = fopen("Logs/spu2.txt","wb"); + iVolume=3; + bEndThread=0; + bThreadEnded=0; + spuMemC=(unsigned char *)spuMem; + memset((void *)s_chan,0,(MAXCHAN+1)*sizeof(SPUCHAN)); + pSpuIrq[0]=spuMemC; + pSpuIrq[1]=spuMemC; + dwNewChannel2[0]=0; + dwNewChannel2[1]=0; + dwEndChannel2[0]=0; + dwEndChannel2[1]=0; + spuCtrl2[0]=0; + spuCtrl2[1]=0; + spuStat2[0]=0; + spuStat2[1]=0; + spuIrq2[0]=0; + spuIrq2[1]=0; + spuAddr2[0]=0x0; + spuAddr2[1]=0x0; + spuRvbAddr2[0]=0; + spuRvbAddr2[1]=0; + spuRvbAEnd2[0]=0; + spuRvbAEnd2[1]=0; + + memset(&Adma4,0,sizeof(ADMA)); + memset(&Adma7,0,sizeof(ADMA)); + + memset(&DirectInputC0,0,sizeof(DINPUT)); + memset(&DirectInputC1,0,sizeof(DINPUT)); + + LastWrite=0x00000000;LastPlay=0; // init some play vars + if(!IsWindow(hW)) hW=GetActiveWindow(); + hWMain = hW; // store hwnd + + ReadConfig(); // read user stuff + + SetupSound(); // setup midas (before init!) + + SetupStreams(); // prepare streaming + + SetupTimer(); // timer for feeding data + + bSPUIsOpen=1; + + if(iDebugMode) // windows debug dialog + { + hWDebug=CreateDialog(hInst,MAKEINTRESOURCE(IDD_DEBUG), + NULL,(DLGPROC)DebugDlgProc); + SetWindowPos(hWDebug,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOACTIVATE); + UpdateWindow(hWDebug); + SetFocus(hWMain); + } + + if(iRecordMode) // windows recording dialog + { + hWRecord=CreateDialog(hInst,MAKEINTRESOURCE(IDD_RECORD), + NULL,(DLGPROC)RecordDlgProc); + SetWindowPos(hWRecord,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOACTIVATE); + UpdateWindow(hWRecord); + SetFocus(hWMain); + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////// + +// not used yet +#ifndef _WINDOWS +void SPU2setConfigFile(char * pCfg) +{ + pConfigFile=pCfg; +} +#endif + +//////////////////////////////////////////////////////////////////////// +// SPUCLOSE: called before shutdown +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC void CALLBACK SPU2close(void) +{ + if(!bSPUIsOpen) return; // some security + + bSPUIsOpen=0; // no more open + //fclose(LogFile); +#ifdef _WINDOWS + if(IsWindow(hWDebug)) DestroyWindow(hWDebug); + hWDebug=0; + if(IsWindow(hWRecord)) DestroyWindow(hWRecord); + hWRecord=0; +#endif + + RemoveTimer(); // no more feeding + + RemoveSound(); // no more sound handling + + RemoveStreams(); // no more streaming +} + +//////////////////////////////////////////////////////////////////////// +// SPUSHUTDOWN: called by main emu on final exit +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC void CALLBACK SPU2shutdown(void) +{ +#ifdef _WINDOWS + if(hIRE!=NULL) {FreeLibrary(hIRE);hIRE=NULL;} +#endif + + return; +} + +//////////////////////////////////////////////////////////////////////// +// SPUTEST: we don't test, we are always fine ;) +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC long CALLBACK SPU2test(void) +{ + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// SPUCONFIGURE: call config dialog +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC void CALLBACK SPU2configure(void) +{ +#ifdef _WINDOWS + DialogBox(hInst,MAKEINTRESOURCE(IDD_CFGDLG), + GetActiveWindow(),(DLGPROC)DSoundDlgProc); +#else + StartCfgTool("CFG"); +#endif +} + +//////////////////////////////////////////////////////////////////////// +// SPUABOUT: show about window +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC void CALLBACK SPU2about(void) +{ +#ifdef _WINDOWS + DialogBox(hInst,MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(),(DLGPROC)AboutDlgProc); +#else + StartCfgTool("ABOUT"); +#endif +} + +//////////////////////////////////////////////////////////////////////// +// SETUP CALLBACKS +// this functions will be called once, +// passes a callback that should be called on SPU-IRQ/cdda volume change +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC void CALLBACK SPU2irqCallback(void (CALLBACK *SPU2callback)(int), + void (CALLBACK *DMA4callback)(int), + void (CALLBACK *DMA7callback)(int)) +{ + irqCallbackSPU2 = SPU2callback; + irqCallbackDMA4 = DMA4callback; + irqCallbackDMA7 = DMA7callback; +} + +//////////////////////////////////////////////////////////////////////// +// COMMON PLUGIN INFO FUNCS +//////////////////////////////////////////////////////////////////////// + +EXPORT_GCC char * CALLBACK PS2EgetLibName(void) +{ + return libraryName; +} + +#define PS2E_LT_SPU2 0x4 + +EXPORT_GCC unsigned long CALLBACK PS2EgetLibType(void) +{ + return PS2E_LT_SPU2; +} + +EXPORT_GCC unsigned long CALLBACK PS2EgetLibVersion2(unsigned long type) +{ + unsigned char v=version; + + // key hack to fake a lower version: + //if(GetAsyncKeyState(VK_SHIFT)&0x8000) v--; + + // compile hack to set lib version to PCSX2 0.6 standards + //v=2; + + return v<<16|revision<<8|build; +} + +//////////////////////////////////////////////////////////////////////// + diff --git a/plugins/PeopsSPU2/stdafx.c b/plugins/PeopsSPU2/stdafx.c index 58a16807c0..eaf9c8ae14 100644 --- a/plugins/PeopsSPU2/stdafx.c +++ b/plugins/PeopsSPU2/stdafx.c @@ -1,8 +1,8 @@ -// stdafx.cpp : source file that includes just the standard includes -// spuPeopsSound.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" - -// TODO: reference any additional headers you need in STDAFX.H -// and not in this file +// stdafx.cpp : source file that includes just the standard includes +// spuPeopsSound.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/plugins/PeopsSPU2/xa.c b/plugins/PeopsSPU2/xa.c index fb63ad407f..93422db269 100644 --- a/plugins/PeopsSPU2/xa.c +++ b/plugins/PeopsSPU2/xa.c @@ -1,363 +1,363 @@ -/*************************************************************************** - xa.c - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2003/02/18 - kode54 -// - added gaussian interpolation -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - -#include "stdafx.h" - -#define _IN_XA - -// will be included from spu.c -#ifdef _IN_SPU - -//////////////////////////////////////////////////////////////////////// -// XA GLOBALS -//////////////////////////////////////////////////////////////////////// - -xa_decode_t * xapGlobal=0; - -unsigned long * XAFeed = NULL; -unsigned long * XAPlay = NULL; -unsigned long * XAStart = NULL; -unsigned long * XAEnd = NULL; - -unsigned long XARepeat = 0; -unsigned long XALastVal = 0; - -int iLeftXAVol = 32767; -int iRightXAVol = 32767; - -static int gauss_ptr = 0; -static int gauss_window[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - -#define gvall0 gauss_window[gauss_ptr] -#define gvall(x) gauss_window[(gauss_ptr+x)&3] -#define gvalr0 gauss_window[4+gauss_ptr] -#define gvalr(x) gauss_window[4+((gauss_ptr+x)&3)] - -//////////////////////////////////////////////////////////////////////// -// MIX XA -//////////////////////////////////////////////////////////////////////// - -INLINE void MixXA(void) -{ - int ns; - - for(ns=0;ns>16)&0xffff)) * iRightXAVol)/32767; - } - - if(XAPlay==XAFeed && XARepeat) - { - XARepeat--; - for(;ns>16)&0xffff)) * iRightXAVol)/32767; - } - } -} - -//////////////////////////////////////////////////////////////////////// -// FEED XA -//////////////////////////////////////////////////////////////////////// - -INLINE void FeedXA(xa_decode_t *xap) -{ - int sinc,spos,i,iSize,iPlace,vl,vr; - - if(!bSPUIsOpen) return; - - xapGlobal = xap; // store info for save states - XARepeat = 100; // set up repeat - - iSize=((44100*xap->nsamples)/xap->freq); // get size - if(!iSize) return; // none? bye - - if(XAFeed=10) - { - if(!dwFPS) dwFPS=1; - dw1=1000000/dwFPS; - if(dw1>=(dwL1-100) && dw1<=(dwL1+100)) dw1=dwL1; - else dwL1=dw1; - dw2=(xap->freq*100/xap->nsamples); - if((!dw1)||((dw2+100)>=dw1)) iLastSize=0; - else - { - iLastSize=iSize*dw2/dw1; - if(iLastSize>iPlace) iLastSize=iPlace; - iSize=iLastSize; - } - iFPSCnt=0;dwFPS=0; - } - else - { - if(iLastSize) iSize=iLastSize; - } - } - //----------------------------------------------------// - - spos=0x10000L; - sinc = (xap->nsamples << 16) / iSize; // calc freq by num / size - - if(xap->stereo) - { - unsigned long * pS=(unsigned long *)xap->pcm; - unsigned long l=0; - - if(iXAPitch) - { - long l1,l2;short s; - for(i=0;i=0x10000L) - { - l = *pS++; - gauss_window[gauss_ptr] = (short)LOWORD(l); - gauss_window[4+gauss_ptr] = (short)HIWORD(l); - gauss_ptr = (gauss_ptr+1) & 3; - spos -= 0x10000L; - } - vl = (spos >> 6) & ~3; - vr=(gauss[vl]*gvall0)&~2047; - vr+=(gauss[vl+1]*gvall(1))&~2047; - vr+=(gauss[vl+2]*gvall(2))&~2047; - vr+=(gauss[vl+3]*gvall(3))&~2047; - l= (vr >> 11) & 0xffff; - vr=(gauss[vl]*gvalr0)&~2047; - vr+=(gauss[vl+1]*gvalr(1))&~2047; - vr+=(gauss[vl+2]*gvalr(2))&~2047; - vr+=(gauss[vl+3]*gvalr(3))&~2047; - l |= vr << 5; - } - else - { - while(spos>=0x10000L) - { - l = *pS++; - spos -= 0x10000L; - } - } - - s=(short)LOWORD(l); - l1=s; - l1=(l1*iPlace)/iSize; - if(l1<-32767) l1=-32767; - if(l1> 32767) l1=32767; - s=(short)HIWORD(l); - l2=s; - l2=(l2*iPlace)/iSize; - if(l2<-32767) l2=-32767; - if(l2> 32767) l2=32767; - l=(l1&0xffff)|(l2<<16); - - *XAFeed++=l; - - if(XAFeed==XAEnd) XAFeed=XAStart; - if(XAFeed==XAPlay) - { - if(XAPlay!=XAStart) XAFeed=XAPlay-1; - break; - } - - spos += sinc; - } - } - else - { - for(i=0;i=0x10000L) - { - l = *pS++; - gauss_window[gauss_ptr] = (short)LOWORD(l); - gauss_window[4+gauss_ptr] = (short)HIWORD(l); - gauss_ptr = (gauss_ptr+1) & 3; - spos -= 0x10000L; - } - vl = (spos >> 6) & ~3; - vr=(gauss[vl]*gvall0)&~2047; - vr+=(gauss[vl+1]*gvall(1))&~2047; - vr+=(gauss[vl+2]*gvall(2))&~2047; - vr+=(gauss[vl+3]*gvall(3))&~2047; - l= (vr >> 11) & 0xffff; - vr=(gauss[vl]*gvalr0)&~2047; - vr+=(gauss[vl+1]*gvalr(1))&~2047; - vr+=(gauss[vl+2]*gvalr(2))&~2047; - vr+=(gauss[vl+3]*gvalr(3))&~2047; - l |= vr << 5; - } - else - { - while(spos>=0x10000L) - { - l = *pS++; - spos -= 0x10000L; - } - } - - *XAFeed++=l; - - if(XAFeed==XAEnd) XAFeed=XAStart; - if(XAFeed==XAPlay) - { - if(XAPlay!=XAStart) XAFeed=XAPlay-1; - break; - } - - spos += sinc; - } - } - } - else - { - unsigned short * pS=(unsigned short *)xap->pcm; - unsigned long l;short s=0; - - if(iXAPitch) - { - long l1; - for(i=0;i=0x10000L) - { - gauss_window[gauss_ptr] = (short)*pS++; - gauss_ptr = (gauss_ptr+1) & 3; - spos -= 0x10000L; - } - vl = (spos >> 6) & ~3; - vr=(gauss[vl]*gvall0)&~2047; - vr+=(gauss[vl+1]*gvall(1))&~2047; - vr+=(gauss[vl+2]*gvall(2))&~2047; - vr+=(gauss[vl+3]*gvall(3))&~2047; - l1=s= vr >> 11; - l1 &= 0xffff; - } - else - { - while(spos>=0x10000L) - { - s = *pS++; - spos -= 0x10000L; - } - l1=s; - } - - l1=(l1*iPlace)/iSize; - if(l1<-32767) l1=-32767; - if(l1> 32767) l1=32767; - l=(l1&0xffff)|(l1<<16); - *XAFeed++=l; - - if(XAFeed==XAEnd) XAFeed=XAStart; - if(XAFeed==XAPlay) - { - if(XAPlay!=XAStart) XAFeed=XAPlay-1; - break; - } - - spos += sinc; - } - } - else - { - for(i=0;i=0x10000L) - { - gauss_window[gauss_ptr] = (short)*pS++; - gauss_ptr = (gauss_ptr+1) & 3; - spos -= 0x10000L; - } - vl = (spos >> 6) & ~3; - vr=(gauss[vl]*gvall0)&~2047; - vr+=(gauss[vl+1]*gvall(1))&~2047; - vr+=(gauss[vl+2]*gvall(2))&~2047; - vr+=(gauss[vl+3]*gvall(3))&~2047; - l=s= vr >> 11; - l &= 0xffff; - } - else - { - while(spos>=0x10000L) - { - s = *pS++; - spos -= 0x10000L; - } - l=s; - } - - *XAFeed++=(l|(l<<16)); - - if(XAFeed==XAEnd) XAFeed=XAStart; - if(XAFeed==XAPlay) - { - if(XAPlay!=XAStart) XAFeed=XAPlay-1; - break; - } - - spos += sinc; - } - } - } -} - -#endif - +/*************************************************************************** + xa.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/02/18 - kode54 +// - added gaussian interpolation +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_XA + +// will be included from spu.c +#ifdef _IN_SPU + +//////////////////////////////////////////////////////////////////////// +// XA GLOBALS +//////////////////////////////////////////////////////////////////////// + +xa_decode_t * xapGlobal=0; + +unsigned long * XAFeed = NULL; +unsigned long * XAPlay = NULL; +unsigned long * XAStart = NULL; +unsigned long * XAEnd = NULL; + +unsigned long XARepeat = 0; +unsigned long XALastVal = 0; + +int iLeftXAVol = 32767; +int iRightXAVol = 32767; + +static int gauss_ptr = 0; +static int gauss_window[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + +#define gvall0 gauss_window[gauss_ptr] +#define gvall(x) gauss_window[(gauss_ptr+x)&3] +#define gvalr0 gauss_window[4+gauss_ptr] +#define gvalr(x) gauss_window[4+((gauss_ptr+x)&3)] + +//////////////////////////////////////////////////////////////////////// +// MIX XA +//////////////////////////////////////////////////////////////////////// + +INLINE void MixXA(void) +{ + int ns; + + for(ns=0;ns>16)&0xffff)) * iRightXAVol)/32767; + } + + if(XAPlay==XAFeed && XARepeat) + { + XARepeat--; + for(;ns>16)&0xffff)) * iRightXAVol)/32767; + } + } +} + +//////////////////////////////////////////////////////////////////////// +// FEED XA +//////////////////////////////////////////////////////////////////////// + +INLINE void FeedXA(xa_decode_t *xap) +{ + int sinc,spos,i,iSize,iPlace,vl,vr; + + if(!bSPUIsOpen) return; + + xapGlobal = xap; // store info for save states + XARepeat = 100; // set up repeat + + iSize=((44100*xap->nsamples)/xap->freq); // get size + if(!iSize) return; // none? bye + + if(XAFeed=10) + { + if(!dwFPS) dwFPS=1; + dw1=1000000/dwFPS; + if(dw1>=(dwL1-100) && dw1<=(dwL1+100)) dw1=dwL1; + else dwL1=dw1; + dw2=(xap->freq*100/xap->nsamples); + if((!dw1)||((dw2+100)>=dw1)) iLastSize=0; + else + { + iLastSize=iSize*dw2/dw1; + if(iLastSize>iPlace) iLastSize=iPlace; + iSize=iLastSize; + } + iFPSCnt=0;dwFPS=0; + } + else + { + if(iLastSize) iSize=iLastSize; + } + } + //----------------------------------------------------// + + spos=0x10000L; + sinc = (xap->nsamples << 16) / iSize; // calc freq by num / size + + if(xap->stereo) + { + unsigned long * pS=(unsigned long *)xap->pcm; + unsigned long l=0; + + if(iXAPitch) + { + long l1,l2;short s; + for(i=0;i=0x10000L) + { + l = *pS++; + gauss_window[gauss_ptr] = (short)LOWORD(l); + gauss_window[4+gauss_ptr] = (short)HIWORD(l); + gauss_ptr = (gauss_ptr+1) & 3; + spos -= 0x10000L; + } + vl = (spos >> 6) & ~3; + vr=(gauss[vl]*gvall0)&~2047; + vr+=(gauss[vl+1]*gvall(1))&~2047; + vr+=(gauss[vl+2]*gvall(2))&~2047; + vr+=(gauss[vl+3]*gvall(3))&~2047; + l= (vr >> 11) & 0xffff; + vr=(gauss[vl]*gvalr0)&~2047; + vr+=(gauss[vl+1]*gvalr(1))&~2047; + vr+=(gauss[vl+2]*gvalr(2))&~2047; + vr+=(gauss[vl+3]*gvalr(3))&~2047; + l |= vr << 5; + } + else + { + while(spos>=0x10000L) + { + l = *pS++; + spos -= 0x10000L; + } + } + + s=(short)LOWORD(l); + l1=s; + l1=(l1*iPlace)/iSize; + if(l1<-32767) l1=-32767; + if(l1> 32767) l1=32767; + s=(short)HIWORD(l); + l2=s; + l2=(l2*iPlace)/iSize; + if(l2<-32767) l2=-32767; + if(l2> 32767) l2=32767; + l=(l1&0xffff)|(l2<<16); + + *XAFeed++=l; + + if(XAFeed==XAEnd) XAFeed=XAStart; + if(XAFeed==XAPlay) + { + if(XAPlay!=XAStart) XAFeed=XAPlay-1; + break; + } + + spos += sinc; + } + } + else + { + for(i=0;i=0x10000L) + { + l = *pS++; + gauss_window[gauss_ptr] = (short)LOWORD(l); + gauss_window[4+gauss_ptr] = (short)HIWORD(l); + gauss_ptr = (gauss_ptr+1) & 3; + spos -= 0x10000L; + } + vl = (spos >> 6) & ~3; + vr=(gauss[vl]*gvall0)&~2047; + vr+=(gauss[vl+1]*gvall(1))&~2047; + vr+=(gauss[vl+2]*gvall(2))&~2047; + vr+=(gauss[vl+3]*gvall(3))&~2047; + l= (vr >> 11) & 0xffff; + vr=(gauss[vl]*gvalr0)&~2047; + vr+=(gauss[vl+1]*gvalr(1))&~2047; + vr+=(gauss[vl+2]*gvalr(2))&~2047; + vr+=(gauss[vl+3]*gvalr(3))&~2047; + l |= vr << 5; + } + else + { + while(spos>=0x10000L) + { + l = *pS++; + spos -= 0x10000L; + } + } + + *XAFeed++=l; + + if(XAFeed==XAEnd) XAFeed=XAStart; + if(XAFeed==XAPlay) + { + if(XAPlay!=XAStart) XAFeed=XAPlay-1; + break; + } + + spos += sinc; + } + } + } + else + { + unsigned short * pS=(unsigned short *)xap->pcm; + unsigned long l;short s=0; + + if(iXAPitch) + { + long l1; + for(i=0;i=0x10000L) + { + gauss_window[gauss_ptr] = (short)*pS++; + gauss_ptr = (gauss_ptr+1) & 3; + spos -= 0x10000L; + } + vl = (spos >> 6) & ~3; + vr=(gauss[vl]*gvall0)&~2047; + vr+=(gauss[vl+1]*gvall(1))&~2047; + vr+=(gauss[vl+2]*gvall(2))&~2047; + vr+=(gauss[vl+3]*gvall(3))&~2047; + l1=s= vr >> 11; + l1 &= 0xffff; + } + else + { + while(spos>=0x10000L) + { + s = *pS++; + spos -= 0x10000L; + } + l1=s; + } + + l1=(l1*iPlace)/iSize; + if(l1<-32767) l1=-32767; + if(l1> 32767) l1=32767; + l=(l1&0xffff)|(l1<<16); + *XAFeed++=l; + + if(XAFeed==XAEnd) XAFeed=XAStart; + if(XAFeed==XAPlay) + { + if(XAPlay!=XAStart) XAFeed=XAPlay-1; + break; + } + + spos += sinc; + } + } + else + { + for(i=0;i=0x10000L) + { + gauss_window[gauss_ptr] = (short)*pS++; + gauss_ptr = (gauss_ptr+1) & 3; + spos -= 0x10000L; + } + vl = (spos >> 6) & ~3; + vr=(gauss[vl]*gvall0)&~2047; + vr+=(gauss[vl+1]*gvall(1))&~2047; + vr+=(gauss[vl+2]*gvall(2))&~2047; + vr+=(gauss[vl+3]*gvall(3))&~2047; + l=s= vr >> 11; + l &= 0xffff; + } + else + { + while(spos>=0x10000L) + { + s = *pS++; + spos -= 0x10000L; + } + l=s; + } + + *XAFeed++=(l|(l<<16)); + + if(XAFeed==XAEnd) XAFeed=XAStart; + if(XAFeed==XAPlay) + { + if(XAPlay!=XAStart) XAFeed=XAPlay-1; + break; + } + + spos += sinc; + } + } + } +} + +#endif + diff --git a/plugins/PeopsSPU2/xa.h b/plugins/PeopsSPU2/xa.h index 0430552aad..6180c3891b 100644 --- a/plugins/PeopsSPU2/xa.h +++ b/plugins/PeopsSPU2/xa.h @@ -1,29 +1,29 @@ -/*************************************************************************** - xa.h - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ - -/*************************************************************************** - * * - * 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. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -//*************************************************************************// -// History of changes: -// -// 2002/05/15 - Pete -// - generic cleanup for the Peops release -// -//*************************************************************************// - - -INLINE void MixXA(void); -INLINE void FeedXA(xa_decode_t *xap); +/*************************************************************************** + xa.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + + +INLINE void MixXA(void); +INLINE void FeedXA(xa_decode_t *xap); diff --git a/plugins/SPU2null/Src/Config.cpp b/plugins/SPU2null/Src/Config.cpp index 46a55c303a..8d9a2aa717 100644 --- a/plugins/SPU2null/Src/Config.cpp +++ b/plugins/SPU2null/Src/Config.cpp @@ -1,51 +1,51 @@ -#include - -#include "SPU2.h" - -extern HINSTANCE hInst; -void SaveConfig() -{ - - Config *Conf1 = &conf; - char *szTemp; - char szIniFile[256], szValue[256]; - - GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); - szTemp = strrchr(szIniFile, '\\'); - - if(!szTemp) return; - strcpy(szTemp, "\\inis\\spu2null.ini"); - sprintf(szValue,"%u",Conf1->Log); - WritePrivateProfileString("Interface", "Logging",szValue,szIniFile); - -} - -void LoadConfig() { - FILE *fp; - - - Config *Conf1 = &conf; - char *szTemp; - char szIniFile[256], szValue[256]; - - GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); - szTemp = strrchr(szIniFile, '\\'); - - if(!szTemp) return ; - strcpy(szTemp, "\\inis\\spu2null.ini"); - fp=fopen("inis\\usbnull.ini","rt");//check if usbnull.ini really exists - if (!fp) - { - CreateDirectory("inis",NULL); - memset(&conf, 0, sizeof(conf)); - conf.Log = 0;//default value - SaveConfig();//save and return - return ; - } - fclose(fp); - GetPrivateProfileString("Interface", "Logging", NULL, szValue, 20, szIniFile); - Conf1->Log = strtoul(szValue, NULL, 10); - return ; - -} - +#include + +#include "SPU2.h" + +extern HINSTANCE hInst; +void SaveConfig() +{ + + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\spu2null.ini"); + sprintf(szValue,"%u",Conf1->Log); + WritePrivateProfileString("Interface", "Logging",szValue,szIniFile); + +} + +void LoadConfig() { + FILE *fp; + + + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return ; + strcpy(szTemp, "\\inis\\spu2null.ini"); + fp=fopen("inis\\usbnull.ini","rt");//check if usbnull.ini really exists + if (!fp) + { + CreateDirectory("inis",NULL); + memset(&conf, 0, sizeof(conf)); + conf.Log = 0;//default value + SaveConfig();//save and return + return ; + } + fclose(fp); + GetPrivateProfileString("Interface", "Logging", NULL, szValue, 20, szIniFile); + Conf1->Log = strtoul(szValue, NULL, 10); + return ; + +} + diff --git a/plugins/SPU2null/Src/PS2Edefs.h b/plugins/SPU2null/Src/PS2Edefs.h index 9b5bcfcbeb..06276f168e 100644 --- a/plugins/SPU2null/Src/PS2Edefs.h +++ b/plugins/SPU2null/Src/PS2Edefs.h @@ -1,812 +1,812 @@ -#ifndef __PS2EDEFS_H__ -#define __PS2EDEFS_H__ - -/* - * PS2E Definitions v0.6.2 (beta) - * - * Author: linuzappz@hotmail.com - * shadowpcsx2@yahoo.gr - * florinsasu@hotmail.com - */ - -/* - Notes: - * Since this is still beta things may change. - - * OSflags: - __LINUX__ (linux OS) - _WIN32 (win32 OS) - - * common return values (for ie. GSinit): - 0 - success - -1 - error - - * reserved keys: - F1 to F10 are reserved for the emulator - - * plugins should NOT change the current - working directory. - (on win32, add flag OFN_NOCHANGEDIR for - GetOpenFileName) - -*/ - -#include "PS2Etypes.h" - -#ifdef __LINUX__ -#define CALLBACK -#else -#include -#endif - - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ - defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ - defined(USBdefs) || defined(FWdefs) -#define COMMONdefs -#endif - -// PS2EgetLibType returns (may be OR'd) -#define PS2E_LT_GS 0x01 -#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- -#define PS2E_LT_SPU2 0x04 -#define PS2E_LT_CDVD 0x08 -#define PS2E_LT_DEV9 0x10 -#define PS2E_LT_USB 0x20 -#define PS2E_LT_FW 0x40 -#define PS2E_LT_SIO 0x80 - -// PS2EgetLibVersion2 (high 16 bits) -#define PS2E_GS_VERSION 0x0006 -#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- -#define PS2E_SPU2_VERSION 0x0005 -#define PS2E_CDVD_VERSION 0x0005 -#define PS2E_DEV9_VERSION 0x0003 -#define PS2E_USB_VERSION 0x0003 -#define PS2E_FW_VERSION 0x0002 -#define PS2E_SIO_VERSION 0x0001 -#ifdef COMMONdefs - -u32 CALLBACK PS2EgetLibType(void); -u32 CALLBACK PS2EgetLibVersion2(u32 type); -char* CALLBACK PS2EgetLibName(void); - -#endif - -// key values: -/* key values must be OS dependant: - win32: the VK_XXX will be used (WinUser) - linux: the XK_XXX will be used (XFree86) -*/ - -// event values: -#define KEYPRESS 1 -#define KEYRELEASE 2 - -typedef struct { - u32 key; - u32 event; -} keyEvent; - -// for 64bit compilers -typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; - -// plugin types -#define SIO_TYPE_PAD 0x00000001 -#define SIO_TYPE_MTAP 0x00000004 -#define SIO_TYPE_RM 0x00000040 -#define SIO_TYPE_MC 0x00000100 - -typedef int (CALLBACK * SIOchangeSlotCB)(int slot); - -typedef struct { - u8 ctrl:4; // control and mode bits - u8 mode:4; // control and mode bits - u8 trackNum; // current track number (1 to 99) - u8 trackIndex; // current index within track (0 to 99) - u8 trackM; // current minute location on the disc (BCD encoded) - u8 trackS; // current sector location on the disc (BCD encoded) - u8 trackF; // current frame location on the disc (BCD encoded) - u8 pad; // unused - u8 discM; // current minute offset from first track (BCD encoded) - u8 discS; // current sector offset from first track (BCD encoded) - u8 discF; // current frame offset from first track (BCD encoded) -} cdvdSubQ; - -typedef struct { // NOT bcd coded - u32 lsn; - u8 type; -} cdvdTD; - -typedef struct { - u8 strack; //number of the first track (usually 1) - u8 etrack; //number of the last track -} cdvdTN; - -// CDVDreadTrack mode values: -#define CDVD_MODE_2352 0 // full 2352 bytes -#define CDVD_MODE_2340 1 // skip sync (12) bytes -#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq - -// CDVDgetDiskType returns: -#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc -#define CDVD_TYPE_DVDV 0xfe // DVD Video -#define CDVD_TYPE_CDDA 0xfd // Audio CD -#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD -#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) -#define CDVD_TYPE_PS2CD 0x12 // PS2 CD -#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) -#define CDVD_TYPE_PSCD 0x10 // PS CD -#define CDVD_TYPE_UNKNOWN 0x05 // Unknown -#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided -#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided -#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd -#define CDVD_TYPE_DETCT 0x01 // Detecting -#define CDVD_TYPE_NODISC 0x00 // No Disc - -// CDVDgetTrayStatus returns: -#define CDVD_TRAY_CLOSE 0x00 -#define CDVD_TRAY_OPEN 0x01 - -// cdvdTD.type (track types for cds) -#define CDVD_AUDIO_TRACK 0x01 -#define CDVD_MODE1_TRACK 0x41 -#define CDVD_MODE2_TRACK 0x61 - -#define CDVD_AUDIO_MASK 0x00 -#define CDVD_DATA_MASK 0x40 -// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) - -typedef void (*DEV9callback)(int cycles); -typedef int (*DEV9handler)(void); - -typedef void (*USBcallback)(int cycles); -typedef int (*USBhandler)(void); - -// freeze modes: -#define FREEZE_LOAD 0 -#define FREEZE_SAVE 1 -#define FREEZE_SIZE 2 - -typedef struct { - char name[8]; - void *common; -} GSdriverInfo; - -#ifdef _WIN32 -typedef struct { // unsupported values must be set to zero - HWND hWnd; - HMENU hMenu; - HWND hStatusWnd; -} winInfo; -#endif - -/* GS plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef GSdefs - -// basic funcs - -s32 CALLBACK GSinit(); -s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); -void CALLBACK GSclose(); -void CALLBACK GSshutdown(); -void CALLBACK GSvsync(int field); -void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); -void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); -void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); -void CALLBACK GSgifSoftReset(u32 mask); -void CALLBACK GSreadFIFO(u64 *mem); -void CALLBACK GSreadFIFO2(u64 *mem, int qwc); - -// extended funcs - -// GSkeyEvent gets called when there is a keyEvent from the PAD plugin -void CALLBACK GSkeyEvent(keyEvent *ev); -void CALLBACK GSchangeSaveState(int, const char* filename); -void CALLBACK GSmakeSnapshot(char *path); -void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); -void CALLBACK GSirqCallback(void (*callback)()); -void CALLBACK GSprintf(int timeout, char *fmt, ...); -void CALLBACK GSsetBaseMem(void*); -void CALLBACK GSsetGameCRC(int crc, int gameoptions); - -// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done -void CALLBACK GSsetFrameSkip(int frameskip); - -void CALLBACK GSreset(); -void CALLBACK GSwriteCSR(u32 value); -void CALLBACK GSgetDriverInfo(GSdriverInfo *info); -#ifdef _WIN32 -s32 CALLBACK GSsetWindowInfo(winInfo *info); -#endif -s32 CALLBACK GSfreeze(int mode, freezeData *data); -void CALLBACK GSconfigure(); -void CALLBACK GSabout(); -s32 CALLBACK GStest(); - -#endif - -/* PAD plugin API -=[ OBSOLETE ]=- */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef PADdefs - -// basic funcs - -s32 CALLBACK PADinit(u32 flags); -s32 CALLBACK PADopen(void *pDsp); -void CALLBACK PADclose(); -void CALLBACK PADshutdown(); -// PADkeyEvent is called every vsync (return NULL if no event) -keyEvent* CALLBACK PADkeyEvent(); -u8 CALLBACK PADstartPoll(int pad); -u8 CALLBACK PADpoll(u8 value); -// returns: 1 if supported pad1 -// 2 if supported pad2 -// 3 if both are supported -u32 CALLBACK PADquery(); - -// extended funcs - -void CALLBACK PADgsDriverInfo(GSdriverInfo *info); -void CALLBACK PADconfigure(); -void CALLBACK PADabout(); -s32 CALLBACK PADtest(); - -#endif - -/* SIO plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SIOdefs - -// basic funcs - -s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); -s32 CALLBACK SIOopen(void *pDsp); -void CALLBACK SIOclose(); -void CALLBACK SIOshutdown(); -u8 CALLBACK SIOstartPoll(u8 value); -u8 CALLBACK SIOpoll(u8 value); -// returns: SIO_TYPE_{PAD,MTAP,RM,MC} -u32 CALLBACK SIOquery(); - -// extended funcs - -void CALLBACK SIOconfigure(); -void CALLBACK SIOabout(); -s32 CALLBACK SIOtest(); - -#endif - -/* SPU2 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SPU2defs - -// basic funcs - -s32 CALLBACK SPU2init(); -s32 CALLBACK SPU2open(void *pDsp); -void CALLBACK SPU2close(); -void CALLBACK SPU2shutdown(); -void CALLBACK SPU2write(u32 mem, u16 value); -u16 CALLBACK SPU2read(u32 mem); -void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA4(); -void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); -void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA7(); -u32 CALLBACK SPU2ReadMemAddr(int core); -void CALLBACK SPU2WriteMemAddr(int core,u32 value); -void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); -// extended funcs - -void CALLBACK SPU2async(u32 cycles); -s32 CALLBACK SPU2freeze(int mode, freezeData *data); -void CALLBACK SPU2configure(); -void CALLBACK SPU2about(); -s32 CALLBACK SPU2test(); - -#endif - -/* CDVD plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef CDVDdefs - -// basic funcs - -s32 CALLBACK CDVDinit(); -s32 CALLBACK CDVDopen(const char* pTitleFilename); -void CALLBACK CDVDclose(); -void CALLBACK CDVDshutdown(); -s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); - -// return can be NULL (for async modes) -u8* CALLBACK CDVDgetBuffer(); - -s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) -s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information -s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type -s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc -s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx -s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx -s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray -s32 CALLBACK CDVDctrlTrayClose(); //close disc tray - -// extended funcs - -void CALLBACK CDVDconfigure(); -void CALLBACK CDVDabout(); -s32 CALLBACK CDVDtest(); -void CALLBACK CDVDnewDiskCB(void (*callback)()); - -#endif - -/* DEV9 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef DEV9defs - -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK DEV9init(); -s32 CALLBACK DEV9open(void *pDsp); -void CALLBACK DEV9close(); -void CALLBACK DEV9shutdown(); -u8 CALLBACK DEV9read8(u32 addr); -u16 CALLBACK DEV9read16(u32 addr); -u32 CALLBACK DEV9read32(u32 addr); -void CALLBACK DEV9write8(u32 addr, u8 value); -void CALLBACK DEV9write16(u32 addr, u16 value); -void CALLBACK DEV9write32(u32 addr, u32 value); -void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); -void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK DEV9irqCallback(DEV9callback callback); -DEV9handler CALLBACK DEV9irqHandler(void); - -// extended funcs - -s32 CALLBACK DEV9freeze(int mode, freezeData *data); -void CALLBACK DEV9configure(); -void CALLBACK DEV9about(); -s32 CALLBACK DEV9test(); - -#endif - -/* USB plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef USBdefs - -// basic funcs - -s32 CALLBACK USBinit(); -s32 CALLBACK USBopen(void *pDsp); -void CALLBACK USBclose(); -void CALLBACK USBshutdown(); -u8 CALLBACK USBread8(u32 addr); -u16 CALLBACK USBread16(u32 addr); -u32 CALLBACK USBread32(u32 addr); -void CALLBACK USBwrite8(u32 addr, u8 value); -void CALLBACK USBwrite16(u32 addr, u16 value); -void CALLBACK USBwrite32(u32 addr, u32 value); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK USBirqCallback(USBcallback callback); -USBhandler CALLBACK USBirqHandler(void); -void CALLBACK USBsetRAM(void *mem); - -// extended funcs - -s32 CALLBACK USBfreeze(int mode, freezeData *data); -void CALLBACK USBconfigure(); -void CALLBACK USBabout(); -s32 CALLBACK USBtest(); - -#endif - -/* FW plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef FWdefs -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK FWinit(); -s32 CALLBACK FWopen(void *pDsp); -void CALLBACK FWclose(); -void CALLBACK FWshutdown(); -u32 CALLBACK FWread32(u32 addr); -void CALLBACK FWwrite32(u32 addr, u32 value); -void CALLBACK FWirqCallback(void (*callback)()); - -// extended funcs - -s32 CALLBACK FWfreeze(int mode, freezeData *data); -void CALLBACK FWconfigure(); -void CALLBACK FWabout(); -s32 CALLBACK FWtest(); -#endif - -// might be useful for emulators -#ifdef PLUGINtypedefs - -typedef u32 (CALLBACK* _PS2EgetLibType)(void); -typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); -typedef char*(CALLBACK* _PS2EgetLibName)(void); - -// GS -// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _GSinit)(); -typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); -typedef void (CALLBACK* _GSclose)(); -typedef void (CALLBACK* _GSshutdown)(); -typedef void (CALLBACK* _GSvsync)(int field); -typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); -typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); -typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); -typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); - -typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); -typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); -typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); -typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); -typedef void (CALLBACK* _GSsetBaseMem)(void*); -typedef void (CALLBACK* _GSsetGameCRC)(int, int); -typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); -typedef void (CALLBACK* _GSreset)(); -typedef void (CALLBACK* _GSwriteCSR)(u32 value); -typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); -#ifdef _WIN32 -typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); -#endif -typedef void (CALLBACK* _GSmakeSnapshot)(char *path); -typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); -typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _GSconfigure)(); -typedef s32 (CALLBACK* _GStest)(); -typedef void (CALLBACK* _GSabout)(); - -// PAD -typedef s32 (CALLBACK* _PADinit)(u32 flags); -typedef s32 (CALLBACK* _PADopen)(void *pDsp); -typedef void (CALLBACK* _PADclose)(); -typedef void (CALLBACK* _PADshutdown)(); -typedef keyEvent* (CALLBACK* _PADkeyEvent)(); -typedef u8 (CALLBACK* _PADstartPoll)(int pad); -typedef u8 (CALLBACK* _PADpoll)(u8 value); -typedef u32 (CALLBACK* _PADquery)(); - -typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); -typedef void (CALLBACK* _PADconfigure)(); -typedef s32 (CALLBACK* _PADtest)(); -typedef void (CALLBACK* _PADabout)(); - -// SIO -typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); -typedef s32 (CALLBACK* _SIOopen)(void *pDsp); -typedef void (CALLBACK* _SIOclose)(); -typedef void (CALLBACK* _SIOshutdown)(); -typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); -typedef u8 (CALLBACK* _SIOpoll)(u8 value); -typedef u32 (CALLBACK* _SIOquery)(); - -typedef void (CALLBACK* _SIOconfigure)(); -typedef s32 (CALLBACK* _SIOtest)(); -typedef void (CALLBACK* _SIOabout)(); - -// SPU2 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _SPU2init)(); -typedef s32 (CALLBACK* _SPU2open)(void *pDsp); -typedef void (CALLBACK* _SPU2close)(); -typedef void (CALLBACK* _SPU2shutdown)(); -typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); -typedef u16 (CALLBACK* _SPU2read)(u32 mem); -typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA4)(); -typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA7)(); -typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); -typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); -typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); -typedef void (CALLBACK* _SPU2async)(u32 cycles); -typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _SPU2configure)(); -typedef s32 (CALLBACK* _SPU2test)(); -typedef void (CALLBACK* _SPU2about)(); - -// CDVD -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _CDVDinit)(); -typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); -typedef void (CALLBACK* _CDVDclose)(); -typedef void (CALLBACK* _CDVDshutdown)(); -typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); -typedef u8* (CALLBACK* _CDVDgetBuffer)(); -typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); -typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); -typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); -typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); -typedef s32 (CALLBACK* _CDVDgetDiskType)(); -typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); -typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); -typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); - -typedef void (CALLBACK* _CDVDconfigure)(); -typedef s32 (CALLBACK* _CDVDtest)(); -typedef void (CALLBACK* _CDVDabout)(); -typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); - -// DEV9 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _DEV9init)(); -typedef s32 (CALLBACK* _DEV9open)(void *pDsp); -typedef void (CALLBACK* _DEV9close)(); -typedef void (CALLBACK* _DEV9shutdown)(); -typedef u8 (CALLBACK* _DEV9read8)(u32 mem); -typedef u16 (CALLBACK* _DEV9read16)(u32 mem); -typedef u32 (CALLBACK* _DEV9read32)(u32 mem); -typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); -typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); -typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); -typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); -typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); - -typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _DEV9configure)(); -typedef s32 (CALLBACK* _DEV9test)(); -typedef void (CALLBACK* _DEV9about)(); - -// USB -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _USBinit)(); -typedef s32 (CALLBACK* _USBopen)(void *pDsp); -typedef void (CALLBACK* _USBclose)(); -typedef void (CALLBACK* _USBshutdown)(); -typedef u8 (CALLBACK* _USBread8)(u32 mem); -typedef u16 (CALLBACK* _USBread16)(u32 mem); -typedef u32 (CALLBACK* _USBread32)(u32 mem); -typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); -typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); -typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); -typedef USBhandler (CALLBACK* _USBirqHandler)(void); -typedef void (CALLBACK* _USBsetRAM)(void *mem); - -typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _USBconfigure)(); -typedef s32 (CALLBACK* _USBtest)(); -typedef void (CALLBACK* _USBabout)(); - -//FW -typedef s32 (CALLBACK* _FWinit)(); -typedef s32 (CALLBACK* _FWopen)(void *pDsp); -typedef void (CALLBACK* _FWclose)(); -typedef void (CALLBACK* _FWshutdown)(); -typedef u32 (CALLBACK* _FWread32)(u32 mem); -typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); - -typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _FWconfigure)(); -typedef s32 (CALLBACK* _FWtest)(); -typedef void (CALLBACK* _FWabout)(); - -#endif - -#ifdef PLUGINfuncs - -// GS -_GSinit GSinit; -_GSopen GSopen; -_GSclose GSclose; -_GSshutdown GSshutdown; -_GSvsync GSvsync; -_GSgifTransfer1 GSgifTransfer1; -_GSgifTransfer2 GSgifTransfer2; -_GSgifTransfer3 GSgifTransfer3; -_GSgifSoftReset GSgifSoftReset; -_GSreadFIFO GSreadFIFO; -_GSreadFIFO2 GSreadFIFO2; - -_GSkeyEvent GSkeyEvent; -_GSchangeSaveState GSchangeSaveState; -_GSmakeSnapshot GSmakeSnapshot; -_GSmakeSnapshot2 GSmakeSnapshot2; -_GSirqCallback GSirqCallback; -_GSprintf GSprintf; -_GSsetBaseMem GSsetBaseMem; -_GSsetGameCRC GSsetGameCRC; -_GSsetFrameSkip GSsetFrameSkip; -_GSreset GSreset; -_GSwriteCSR GSwriteCSR; -_GSgetDriverInfo GSgetDriverInfo; -#ifdef _WIN32 -_GSsetWindowInfo GSsetWindowInfo; -#endif -_GSfreeze GSfreeze; -_GSconfigure GSconfigure; -_GStest GStest; -_GSabout GSabout; - -// PAD1 -_PADinit PAD1init; -_PADopen PAD1open; -_PADclose PAD1close; -_PADshutdown PAD1shutdown; -_PADkeyEvent PAD1keyEvent; -_PADstartPoll PAD1startPoll; -_PADpoll PAD1poll; -_PADquery PAD1query; - -_PADgsDriverInfo PAD1gsDriverInfo; -_PADconfigure PAD1configure; -_PADtest PAD1test; -_PADabout PAD1about; - -// PAD2 -_PADinit PAD2init; -_PADopen PAD2open; -_PADclose PAD2close; -_PADshutdown PAD2shutdown; -_PADkeyEvent PAD2keyEvent; -_PADstartPoll PAD2startPoll; -_PADpoll PAD2poll; -_PADquery PAD2query; - -_PADgsDriverInfo PAD2gsDriverInfo; -_PADconfigure PAD2configure; -_PADtest PAD2test; -_PADabout PAD2about; - -// SIO[2] -_SIOinit SIOinit[2][9]; -_SIOopen SIOopen[2][9]; -_SIOclose SIOclose[2][9]; -_SIOshutdown SIOshutdown[2][9]; -_SIOstartPoll SIOstartPoll[2][9]; -_SIOpoll SIOpoll[2][9]; -_SIOquery SIOquery[2][9]; - -_SIOconfigure SIOconfigure[2][9]; -_SIOtest SIOtest[2][9]; -_SIOabout SIOabout[2][9]; - -// SPU2 -_SPU2init SPU2init; -_SPU2open SPU2open; -_SPU2close SPU2close; -_SPU2shutdown SPU2shutdown; -_SPU2write SPU2write; -_SPU2read SPU2read; -_SPU2readDMA4Mem SPU2readDMA4Mem; -_SPU2writeDMA4Mem SPU2writeDMA4Mem; -_SPU2interruptDMA4 SPU2interruptDMA4; -_SPU2readDMA7Mem SPU2readDMA7Mem; -_SPU2writeDMA7Mem SPU2writeDMA7Mem; -_SPU2interruptDMA7 SPU2interruptDMA7; -_SPU2ReadMemAddr SPU2ReadMemAddr; -_SPU2WriteMemAddr SPU2WriteMemAddr; -_SPU2irqCallback SPU2irqCallback; - -_SPU2async SPU2async; -_SPU2freeze SPU2freeze; -_SPU2configure SPU2configure; -_SPU2test SPU2test; -_SPU2about SPU2about; - -// CDVD -_CDVDinit CDVDinit; -_CDVDopen CDVDopen; -_CDVDclose CDVDclose; -_CDVDshutdown CDVDshutdown; -_CDVDreadTrack CDVDreadTrack; -_CDVDgetBuffer CDVDgetBuffer; -_CDVDreadSubQ CDVDreadSubQ; -_CDVDgetTN CDVDgetTN; -_CDVDgetTD CDVDgetTD; -_CDVDgetTOC CDVDgetTOC; -_CDVDgetDiskType CDVDgetDiskType; -_CDVDgetTrayStatus CDVDgetTrayStatus; -_CDVDctrlTrayOpen CDVDctrlTrayOpen; -_CDVDctrlTrayClose CDVDctrlTrayClose; - -_CDVDconfigure CDVDconfigure; -_CDVDtest CDVDtest; -_CDVDabout CDVDabout; -_CDVDnewDiskCB CDVDnewDiskCB; - -// DEV9 -_DEV9init DEV9init; -_DEV9open DEV9open; -_DEV9close DEV9close; -_DEV9shutdown DEV9shutdown; -_DEV9read8 DEV9read8; -_DEV9read16 DEV9read16; -_DEV9read32 DEV9read32; -_DEV9write8 DEV9write8; -_DEV9write16 DEV9write16; -_DEV9write32 DEV9write32; -_DEV9readDMA8Mem DEV9readDMA8Mem; -_DEV9writeDMA8Mem DEV9writeDMA8Mem; -_DEV9irqCallback DEV9irqCallback; -_DEV9irqHandler DEV9irqHandler; - -_DEV9configure DEV9configure; -_DEV9freeze DEV9freeze; -_DEV9test DEV9test; -_DEV9about DEV9about; - -// USB -_USBinit USBinit; -_USBopen USBopen; -_USBclose USBclose; -_USBshutdown USBshutdown; -_USBread8 USBread8; -_USBread16 USBread16; -_USBread32 USBread32; -_USBwrite8 USBwrite8; -_USBwrite16 USBwrite16; -_USBwrite32 USBwrite32; -_USBirqCallback USBirqCallback; -_USBirqHandler USBirqHandler; -_USBsetRAM USBsetRAM; - -_USBconfigure USBconfigure; -_USBfreeze USBfreeze; -_USBtest USBtest; -_USBabout USBabout; - -// FW -_FWinit FWinit; -_FWopen FWopen; -_FWclose FWclose; -_FWshutdown FWshutdown; -_FWread32 FWread32; -_FWwrite32 FWwrite32; -_FWirqCallback FWirqCallback; - -_FWconfigure FWconfigure; -_FWfreeze FWfreeze; -_FWtest FWtest; -_FWabout FWabout; -#endif - -#endif /* __PS2EDEFS_H__ */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +// extended funcs + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/SPU2null/Src/Win32.cpp b/plugins/SPU2null/Src/Win32.cpp index 95f36c4ad0..5695dacb75 100644 --- a/plugins/SPU2null/Src/Win32.cpp +++ b/plugins/SPU2null/Src/Win32.cpp @@ -61,7 +61,8 @@ void CALLBACK SPU2configure() { DialogBox(hInst, MAKEINTRESOURCE(IDD_CONFIG), GetActiveWindow(), - (DLGPROC)ConfigureDlgProc); + (DLGPROC)ConfigureDlgProc); + } void CALLBACK SPU2about() { diff --git a/plugins/SPU2null/Src/mingw/Makefile.win b/plugins/SPU2null/Src/mingw/Makefile.win index 0b88810012..e789c19793 100644 --- a/plugins/SPU2null/Src/mingw/Makefile.win +++ b/plugins/SPU2null/Src/mingw/Makefile.win @@ -1,43 +1,43 @@ -# Project: SPU2null -# Makefile created by Dev-C++ 4.9.9.2 - -CPP = mingw32-g++.exe -CC = mingw32-gcc.exe -WINDRES = windres.exe -RES = Obj//SPU2null_private.res -OBJ = Obj//Win32.o Obj//Config.o Obj//SPU2.o $(RES) -LINKOBJ = Obj//Win32.o Obj//Config.o Obj//SPU2.o $(RES) -LIBS = -L"C:/Develop/Dev-Cpp/lib" --def plugin.def -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 -INCS = -I"C:/Develop/Dev-Cpp/include" -CXXINCS = -I"C:/Develop/Dev-Cpp/include" -BIN = SPU2null.dll -CXXFLAGS = $(CXXINCS) -CFLAGS = $(INCS) -Wall -O2 -fomit-frame-pointer -D__WIN32__ -D__MINGW32___ -RM = rm -f - -.PHONY: all all-before all-after clean clean-custom - -all: all-before SPU2null.dll all-after - - -clean: clean-custom - ${RM} $(OBJ) $(BIN) - -DLLWRAP=dllwrap.exe -DEFFILE=libSPU2null.def -STATICLIB=libSPU2null.a - -$(BIN): $(LINKOBJ) - $(DLLWRAP) --output-def $(DEFFILE) --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN) - -Obj//Win32.o: ../Win32.c - $(CC) -c ../Win32.c -o Obj//Win32.o $(CFLAGS) - -Obj//Config.o: ../Config.c - $(CC) -c ../Config.c -o Obj//Config.o $(CFLAGS) - -Obj//SPU2.o: ../SPU2.c - $(CC) -c ../SPU2.c -o Obj//SPU2.o $(CFLAGS) - -Obj//SPU2null_private.res: SPU2null_private.rc ../SPU2null.rc - $(WINDRES) -i SPU2null_private.rc --input-format=rc -o Obj//SPU2null_private.res -O coff --include-dir ../mingw --include-dir ../ +# Project: SPU2null +# Makefile created by Dev-C++ 4.9.9.2 + +CPP = mingw32-g++.exe +CC = mingw32-gcc.exe +WINDRES = windres.exe +RES = Obj//SPU2null_private.res +OBJ = Obj//Win32.o Obj//Config.o Obj//SPU2.o $(RES) +LINKOBJ = Obj//Win32.o Obj//Config.o Obj//SPU2.o $(RES) +LIBS = -L"C:/Develop/Dev-Cpp/lib" --def plugin.def -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 +INCS = -I"C:/Develop/Dev-Cpp/include" +CXXINCS = -I"C:/Develop/Dev-Cpp/include" +BIN = SPU2null.dll +CXXFLAGS = $(CXXINCS) +CFLAGS = $(INCS) -Wall -O2 -fomit-frame-pointer -D__WIN32__ -D__MINGW32___ +RM = rm -f + +.PHONY: all all-before all-after clean clean-custom + +all: all-before SPU2null.dll all-after + + +clean: clean-custom + ${RM} $(OBJ) $(BIN) + +DLLWRAP=dllwrap.exe +DEFFILE=libSPU2null.def +STATICLIB=libSPU2null.a + +$(BIN): $(LINKOBJ) + $(DLLWRAP) --output-def $(DEFFILE) --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN) + +Obj//Win32.o: ../Win32.c + $(CC) -c ../Win32.c -o Obj//Win32.o $(CFLAGS) + +Obj//Config.o: ../Config.c + $(CC) -c ../Config.c -o Obj//Config.o $(CFLAGS) + +Obj//SPU2.o: ../SPU2.c + $(CC) -c ../SPU2.c -o Obj//SPU2.o $(CFLAGS) + +Obj//SPU2null_private.res: SPU2null_private.rc ../SPU2null.rc + $(WINDRES) -i SPU2null_private.rc --input-format=rc -o Obj//SPU2null_private.res -O coff --include-dir ../mingw --include-dir ../ diff --git a/plugins/SPU2null/Src/mingw/afxres.h b/plugins/SPU2null/Src/mingw/afxres.h index 8a4b9df35b..99eace37c4 100644 --- a/plugins/SPU2null/Src/mingw/afxres.h +++ b/plugins/SPU2null/Src/mingw/afxres.h @@ -1,5 +1,5 @@ - -#include -#include - -#define IDC_STATIC (-1) + +#include +#include + +#define IDC_STATIC (-1) diff --git a/plugins/SPU2null/Src/resource.h b/plugins/SPU2null/Src/resource.h index 150ca1f844..701862bdef 100644 --- a/plugins/SPU2null/Src/resource.h +++ b/plugins/SPU2null/Src/resource.h @@ -1,21 +1,21 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by SPU2null.rc -// -#define IDD_CONFDLG 101 -#define IDD_CONFIG 101 -#define IDD_ABOUT 103 -#define IDC_NAME 1000 -#define IDC_CHECK1 1007 -#define IDC_LOGGING 1007 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by SPU2null.rc +// +#define IDD_CONFDLG 101 +#define IDD_CONFIG 101 +#define IDD_ABOUT 103 +#define IDC_NAME 1000 +#define IDC_CHECK1 1007 +#define IDC_LOGGING 1007 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/SSSPSXPAD/PadSSSPSX.cpp b/plugins/SSSPSXPAD/PadSSSPSX.cpp index 9a26c3d398..1af632c045 100644 --- a/plugins/SSSPSXPAD/PadSSSPSX.cpp +++ b/plugins/SSSPSXPAD/PadSSSPSX.cpp @@ -1,1041 +1,1041 @@ -#define WINVER 0x0500 -#define _WIN32_WINNT WINVER -#define DIRECTINPUT_VERSION 0x0800 - -#include -#include -#include -#include - -#include "PadSSSPSX.h" - -static const char* LibraryName = "SSSPSX PAD Plugin Pressure Mod"; -static const unsigned char version = 0x0002; -static const unsigned char revision = 1; -static const unsigned char build = 6; - -HMODULE hInstance; -HWND hTargetWnd; - -static struct -{ - Config config; - int devcnt; - LPDIRECTINPUT8 pDInput; - LPDIRECTINPUTDEVICE8 pDKeyboard; - LPDIRECTINPUTDEVICE8 pDDevice[4]; - LPDIRECTINPUTEFFECT pDEffect[4][2]; /* for Small & Big Motor */ - DIJOYSTATE JoyState[4]; - u16 padStat[2]; - int padID[2]; - int padMode1[2]; - int padMode2[2]; - int padModeE[2]; - int padModeC[2]; - int padModeF[2]; - int padVib0[2]; - int padVib1[2]; - int padVibF[2][4]; - int padVibC[2]; - DWORD padPress[2][16]; - int curPad; - int curByte; - int curCmd; - int cmdLen; -} global; - -static BOOL CALLBACK EnumAxesCallback (LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef) -{ - LPDIRECTINPUTDEVICE8 pDDevice = (LPDIRECTINPUTDEVICE8)pvRef; - DIPROPRANGE diprg; - diprg.diph.dwSize = sizeof (diprg); - diprg.diph.dwHeaderSize = sizeof (diprg.diph); - diprg.diph.dwObj = lpddoi->dwType; - diprg.diph.dwHow = DIPH_BYID; - diprg.lMin = -128; - diprg.lMax = 127; - pDDevice->SetProperty (DIPROP_RANGE, &diprg.diph); - return DIENUM_CONTINUE; -} - -static BOOL CALLBACK EnumJoysticksCallback (const DIDEVICEINSTANCE* instance, VOID* pContext) -{ - const int devno = global.devcnt; - if (devno >= 4) - return DIENUM_STOP; - HRESULT result = global.pDInput->CreateDevice (instance->guidInstance, &global.pDDevice[devno], NULL); - if (FAILED (result)) - return DIENUM_CONTINUE; - global.devcnt++; - return DIENUM_CONTINUE; -} - -static bool ReleaseDirectInput (void) -{ - int index = 4; - while (index--) - { - if (global.pDEffect[index][0]) - { - global.pDEffect[index][0]->Unload(); - global.pDEffect[index][0]->Release(); - global.pDEffect[index][0] = NULL; - } - if (global.pDEffect[index][1]) - { - global.pDEffect[index][1]->Unload(); - global.pDEffect[index][1]->Release(); - global.pDEffect[index][1] = NULL; - } - if (global.pDDevice[index]) - { - global.pDDevice[index]->Unacquire(); - global.pDDevice[index]->Release(); - global.pDDevice[index] = NULL; - } - } - if (global.pDKeyboard) - { - global.pDKeyboard->Unacquire(); - global.pDKeyboard->Release(); - global.pDKeyboard = NULL; - } - if (global.pDInput) - { - global.pDInput->Release(); - global.pDInput = NULL; - } - global.devcnt = 0; - return FALSE; -} - -static bool InitDirectInput (void) -{ - if (global.pDInput) - return TRUE; - HRESULT result = DirectInput8Create (hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&global.pDInput, NULL); - if (FAILED (result)) - return ReleaseDirectInput(); - result = global.pDInput->CreateDevice (GUID_SysKeyboard, &global.pDKeyboard, NULL); - if (FAILED (result)) - return ReleaseDirectInput(); - result = global.pDInput->EnumDevices (DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, NULL, DIEDFL_ATTACHEDONLY); - if (FAILED (result)) - return ReleaseDirectInput(); - result = global.pDKeyboard->SetDataFormat (&c_dfDIKeyboard); - if (FAILED (result)) - return ReleaseDirectInput(); - if (hTargetWnd) - { - global.pDKeyboard->Unacquire(); - result = global.pDKeyboard->SetCooperativeLevel (hTargetWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); - if (FAILED (result)) - return ReleaseDirectInput(); - } - int index = global.devcnt; - while (index--) - { - const LPDIRECTINPUTDEVICE8 pDDevice = global.pDDevice[index]; - result = pDDevice->SetDataFormat (&c_dfDIJoystick); - if (FAILED (result)) - return ReleaseDirectInput(); - if (hTargetWnd) - { - pDDevice->Unacquire(); - result = pDDevice->SetCooperativeLevel (hTargetWnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE); - if (FAILED (result)) - return ReleaseDirectInput(); - } - struct - { - DIPROPDWORD dipdw; - DWORD rgdwAxes[2]; - LONG rglDirection[2]; - DIPERIODIC per; - DICONSTANTFORCE cf; - DIEFFECT eff; - } local; - memset (&local, 0, sizeof (local)); - local.dipdw.diph.dwSize = sizeof (DIPROPDWORD); - local.dipdw.diph.dwHeaderSize = sizeof (DIPROPHEADER); - local.dipdw.diph.dwHow = DIPH_DEVICE; - local.dipdw.dwData = DIPROPAUTOCENTER_OFF; - pDDevice->SetProperty (DIPROP_AUTOCENTER, &local.dipdw.diph); - result = pDDevice->EnumObjects (EnumAxesCallback, pDDevice, DIDFT_AXIS); - if (FAILED (result)) - return ReleaseDirectInput(); - - local.rgdwAxes[0] = DIJOFS_X; - local.rgdwAxes[1] = DIJOFS_Y; - local.eff.dwSize = sizeof (DIEFFECT); - local.eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; - local.eff.dwDuration = INFINITE; - local.eff.dwGain = DI_FFNOMINALMAX; - local.eff.dwTriggerButton = DIEB_NOTRIGGER; - local.eff.cAxes = 2; - local.eff.rgdwAxes = local.rgdwAxes; - local.eff.rglDirection = local.rglDirection; - - /* Small Motor */ - local.eff.cbTypeSpecificParams = sizeof (DIPERIODIC); - local.eff.lpvTypeSpecificParams = &local.per; - result = pDDevice->CreateEffect (GUID_Square , &local.eff, &global.pDEffect[index][0], NULL); - if (FAILED (result)) - global.pDEffect[index][0] = NULL; - - /* Big Motor */ - local.eff.cbTypeSpecificParams = sizeof (DICONSTANTFORCE); - local.eff.lpvTypeSpecificParams = &local.cf; - result = pDDevice->CreateEffect (GUID_ConstantForce , &local.eff, &global.pDEffect[index][1], NULL); - if (FAILED (result)) - global.pDEffect[index][1] = NULL; - } - return TRUE; -} - -static bool AcquireDevice (LPDIRECTINPUTDEVICE8 lpDirectInputDevice) -{ - if (FAILED (lpDirectInputDevice->Acquire())) - { - HRESULT result = lpDirectInputDevice->Acquire(); - if (result == DIERR_OTHERAPPHASPRIO) - return FALSE; - if (FAILED (result)) - return ReleaseDirectInput(); - } - return TRUE; -} - -/* Small Motor */ -static bool SetDeviceForceS (int pad, DWORD force) -{ - InitDirectInput(); - if (global.pDEffect[pad][0]) - { - if ( force == 0) { - if (FAILED (global.pDEffect[pad][0]->Stop())) { - AcquireDevice (global.pDDevice[pad]); - if (FAILED (global.pDEffect[pad][0]->Stop())) - return ReleaseDirectInput(); - } - return TRUE; - } - LONG rglDirection[2] = { 0, 0 }; - DIPERIODIC per; - rglDirection[0] = force; - rglDirection[1] = force; - per.dwMagnitude = force; - per.dwPeriod = (DWORD) (0.01 * DI_SECONDS); - per.lOffset = 0; - per.dwPhase = 0; - DIEFFECT eff; - eff.dwSize = sizeof (DIEFFECT); - eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; - eff.cAxes = 2; - eff.rglDirection = rglDirection; - eff.lpEnvelope = 0; - eff.cbTypeSpecificParams = sizeof (DIPERIODIC); - eff.lpvTypeSpecificParams = &per; - if (FAILED (global.pDEffect[pad][0]->SetParameters (&eff, DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_START))) - return ReleaseDirectInput(); - if (FAILED (global.pDEffect[pad][0]->Start (1, 0))) - { - AcquireDevice (global.pDDevice[pad]); - if (FAILED (global.pDEffect[pad][0]->Start (1, 0))) - return ReleaseDirectInput(); - } - } - return TRUE; -} - -/* Big Motor */ -static bool SetDeviceForceB (int pad, DWORD force) -{ - InitDirectInput(); - if (global.pDEffect[pad][1]) - { - if ( force == 0) { - if (FAILED (global.pDEffect[pad][1]->Stop())) { - AcquireDevice (global.pDDevice[pad]); - if (FAILED (global.pDEffect[pad][1]->Stop())) - return ReleaseDirectInput(); - } - return TRUE; - } - LONG rglDirection[2] = { 0, 0 }; - DICONSTANTFORCE cf; - rglDirection[0] = force; - rglDirection[1] = force; - cf.lMagnitude = force; - DIEFFECT eff; - eff.dwSize = sizeof (DIEFFECT); - eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; - eff.cAxes = 2; - eff.rglDirection = rglDirection; - eff.lpEnvelope = 0; - eff.cbTypeSpecificParams = sizeof (DICONSTANTFORCE); - eff.lpvTypeSpecificParams = &cf; - if (FAILED (global.pDEffect[pad][1]->SetParameters (&eff, DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_START))) - return ReleaseDirectInput(); - if (FAILED (global.pDEffect[pad][1]->Start (1, 0))) - { - AcquireDevice (global.pDDevice[pad]); - if (FAILED (global.pDEffect[pad][1]->Start (1, 0))) - return ReleaseDirectInput(); - } - } - return TRUE; -} - -static bool GetJoyState (const int devno) -{ - InitDirectInput(); - if (global.pDDevice[devno] == NULL) - return FALSE; - global.pDDevice[devno]->Poll(); - if (FAILED (global.pDDevice[devno]->GetDeviceState (sizeof (DIJOYSTATE), &global.JoyState[devno]))) - { - AcquireDevice (global.pDDevice[devno]); - return FALSE; - } - return TRUE; -} - -static bool GetKeyState (u8* keyboard) -{ - InitDirectInput(); - if (global.pDKeyboard == NULL) - return FALSE; - global.pDKeyboard->Poll(); - if (FAILED (global.pDKeyboard->GetDeviceState (256, keyboard))) - { - AcquireDevice (global.pDKeyboard); - return FALSE; - } - return TRUE; -} - -static void MakeConfigFileName (char* fname) -{ - GetModuleFileName (hInstance, fname, 256); - strcpy (fname + strlen (fname) - 3, "cfg"); -} - -static void SaveConfig (void) -{ - char fname[256]; - MakeConfigFileName (fname); - HANDLE hFile = CreateFile (fname, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (hFile != INVALID_HANDLE_VALUE) - { - DWORD number_of_bytes; - WriteFile (hFile, &global.config, sizeof (global.config), &number_of_bytes, NULL); - CloseHandle (hFile); - } -} - -static void LoadConfig (void) -{ - char fname[256]; - MakeConfigFileName (fname); - HANDLE hFile = CreateFile (fname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (hFile != INVALID_HANDLE_VALUE) - { - DWORD number_of_bytes; - ReadFile (hFile, &global.config, sizeof (global.config), &number_of_bytes, NULL); - CloseHandle (hFile); - } - global.padVibC[0] = global.padVibC[1] = -1; - for (int cnt = 21; cnt--; ) - { - const int key0 = global.config.keys[0][cnt]; - if (key0 >= 0x1000) - global.padVibC[0] = (key0 & 0xfff) / 0x100; - const int key1 = global.config.keys[1][cnt]; - if (key1 >= 0x1000) - global.padVibC[1] = (key1 & 0xfff) / 0x100; - } -} - -static void PADsetMode (const int pad, const int mode) -{ - static const u8 padID[] = { 0x41, 0x73, 0x41, 0x79 }; - global.padMode1[pad] = mode; - global.padVib0[pad] = 0; - global.padVib1[pad] = 0; - global.padVibF[pad][0] = 0; - global.padVibF[pad][1] = 0; - global.padID[pad] = padID[global.padMode2[pad] * 2 + mode]; -} - -static void KeyPress (const int pad, const int index, const bool press) -{ - if (index < 16) - { - if (press) - { - global.padStat[pad] &= ~(1 << index); - if (global.padPress[pad][index] == 0) - global.padPress[pad][index] = GetTickCount(); - } - else - { - global.padStat[pad] |= 1 << index; - global.padPress[pad][index] = 0; - } - } - else - { - static bool prev[2] = { FALSE, FALSE }; - if ((prev[pad] != press) && (global.padModeF[pad] == 0)) - { - prev[pad] = press; - if (press) PADsetMode (pad, !global.padMode1[pad]); - } - } -} - -static void UpdateState (const int pad) -{ - static int flag_keyboard; - static int flag_joypad[4]; - if (pad == 0) - { - flag_keyboard = 0; - flag_joypad[0] = 0; - flag_joypad[1] = 0; - flag_joypad[2] = 0; - flag_joypad[3] = 0; - } - static u8 keystate[256]; - for (int index = 17; index--; ) - { - const int key = global.config.keys[pad][index]; - if (key == 0) - continue; - else if (key < 0x100) - { - if (flag_keyboard == FALSE) - { - flag_keyboard = TRUE; - if (GetKeyState (keystate) == FALSE) - return; - } - KeyPress (pad, index, keystate[key] & 0x80); - } - else - { - const int joypad = ((key & 0xfff) / 100); - if (flag_joypad[joypad] == FALSE) - { - flag_joypad[joypad] = TRUE; - if (GetJoyState (joypad) == FALSE) - return; - } - if (key < 0x2000) - { - KeyPress (pad, index, global.JoyState[joypad].rgbButtons[key & 0xff]); - } - else if (key < 0x3000) - { - const int state = ((int*)&global.JoyState[joypad].lX)[(key & 0xff) /2]; - switch (key & 1) - { - case 0: KeyPress (pad, index, state < -64); break; - case 1: KeyPress (pad, index, state >= 64); break; - } - } - else - { - const u32 state = global.JoyState[joypad].rgdwPOV[(key & 0xff) /4]; - switch (key & 3) - { - case 0: KeyPress (pad, index, (state >= 0 && state <= 4500) || (state >= 31500 && state <= 36000)); break; - case 1: KeyPress (pad, index, state >= 4500 && state <= 13500); break; - case 2: KeyPress (pad, index, state >= 13500 && state <= 22500); break; - case 3: KeyPress (pad, index, state >= 22500 && state <= 31500); break; - } - } - } - } - - /* Small Motor */ - const int vib0 = global.padVibF[pad][0] ? 10000 : 0; - if ((global.padVibF[pad][2] != vib0) && (global.padVibC[pad] >= 0)) - { - global.padVibF[pad][2] = vib0; - SetDeviceForceS (global.padVibC[pad], vib0); - } - /* Big Motor */ - const int vib1 = global.padVibF[pad][1] ? 500 + 37*global.padVibF[pad][1] : 0; - if ((global.padVibF[pad][3] != vib1) && (global.padVibC[pad] >= 0)) - { - global.padVibF[pad][3] = vib1; - SetDeviceForceB (global.padVibC[pad], vib1); - } -} - -static void set_label (const HWND hWnd, const int pad, const int index) -{ - const int key = global.config.keys[pad][index]; - char buff[64]; - if (key < 0x100) - { - if (key == 0) - strcpy (buff, "NONE"); - else if (GetKeyNameText (key << 16, buff, sizeof (buff)) == 0) - wsprintf (buff, "Keyboard 0x%02X", key); - } - else if (key >= 0x1000 && key < 0x2000) - { - wsprintf (buff, "J%d_%d", (key & 0xfff) / 0x100, (key & 0xff) + 1); - } - else if (key >= 0x2000 && key < 0x3000) - { - static const char name[][4] = { "MIN", "MAX" }; - const int axis = (key & 0xff); - wsprintf (buff, "J%d_AXIS%d_%s", (key & 0xfff) / 0x100, axis / 2, name[axis % 2]); - if (index >= 17 && index <= 20) - buff[strlen (buff) -4] = '\0'; - } - else if (key >= 0x3000 && key < 0x4000) - { - static const char name[][7] = { "FOWARD", "RIGHT", "BACK", "LEFT" }; - const int pov = (key & 0xff); - wsprintf (buff, "J%d_POV%d_%s", (key & 0xfff) / 0x100, pov /4, name[pov % 4]); - } - Button_SetText (GetDlgItem (hWnd, IDC_ESELECT + index), buff); -} - -static BOOL CALLBACK ConfigureDlgProc (const HWND hWnd, const UINT msg, const WPARAM wParam, const LPARAM lParam) -{ - static BYTE keymaps[2][256]; - static DWORD countdown; - static int disabled; - static HWND hTabWnd; - static int pad; - int cnt1; - int cnt2; - int key; - switch (msg) - { - case WM_INITDIALOG: - hTargetWnd = hWnd; - pad = disabled = 0; - LoadConfig(); - for (cnt1 = 21; cnt1--; ) - set_label (hWnd, pad, cnt1); - hTabWnd = GetDlgItem (hWnd, IDC_TABC); - TCITEM tcI; - tcI.mask = TCIF_TEXT; - tcI.pszText = "PAD1"; - TabCtrl_InsertItem (hTabWnd, 0, &tcI); - tcI.mask = TCIF_TEXT; - tcI.pszText = "PAD2"; - TabCtrl_InsertItem (hTabWnd, 1, &tcI); - SetTimer (hWnd, 0x80, 50, NULL); - return TRUE; - case WM_DESTROY: - break; - case WM_NOTIFY: - if (wParam == IDC_TABC) - { - if (disabled) - EnableWindow (GetDlgItem (hWnd, disabled), TRUE); - disabled = 0; - pad = TabCtrl_GetCurSel (hTabWnd); - for (cnt1 = 21; cnt1--; ) - set_label (hWnd, pad, cnt1); - } - break; - case WM_COMMAND: - for (cnt1 = 21; cnt1--; ) - { - if (LOWORD (wParam) == IDC_BSELECT + cnt1) - { - if (disabled) - EnableWindow (GetDlgItem (hWnd, disabled), TRUE); - EnableWindow (GetDlgItem (hWnd, disabled = wParam), FALSE); - countdown = GetTickCount(); - GetKeyState (keymaps[0]); - return TRUE; - } - } - if (LOWORD (wParam) == IDOK) - EndDialog (hWnd, IDOK); - else if (LOWORD (wParam) == IDCANCEL) - EndDialog (hWnd, IDCANCEL); - break; - case WM_TIMER: - if (disabled) - { - const int index = disabled - IDC_BSELECT; - int analog = FALSE; - if ((GetTickCount() - countdown) / 1000 != 10) - { - char buff[64]; - wsprintf (buff, "Timeout: %d", 10 - (GetTickCount() - countdown) / 1000); - SetWindowText (GetDlgItem (hWnd, IDC_ESELECT + index), buff); - } - else - { - global.config.keys[pad][index] = 0; - set_label (hWnd, pad, index); - EnableWindow (GetDlgItem (hWnd, disabled), TRUE); - disabled = 0; - break; - } - if (GetKeyState (keymaps[1]) == FALSE) - break; - for (key = 0x100; key--; ) - { - if (~keymaps[0][key] & keymaps[1][key] & 0x80) - break; - } - for (cnt1 = global.devcnt; cnt1--;) - { - if (GetJoyState (cnt1) == FALSE) - break; - - for (cnt2 = 32; cnt2--; ) - { - if (global.JoyState[cnt1].rgbButtons[cnt2]) - key = 0x1000 + 0x100 * cnt1 + cnt2; - } - for (cnt2 = 8; cnt2--; ) - { - const int now = ((u32*)&global.JoyState[cnt1].lX)[cnt2]; - if (now < -64) - { - key = 0x2000 + 0x100 * cnt1 + cnt2 * 2 +0; - analog = TRUE; - } - else if (now >= 64) - { - key = 0x2000 + 0x100 * cnt1 + cnt2 * 2 +1; - analog = TRUE; - } - } - for (cnt2 = 4; cnt2--; ) - { - const u32 now = global.JoyState[cnt1].rgdwPOV[cnt2]; - if ((now >= 0 && now < 4500) || (now >= 31500 && now < 36000)) - key = 0x3000 + 0x100 * cnt1 + cnt2 * 4 +0; - if (now >= 4500 && now < 13500) - key = 0x3000 + 0x100 * cnt1 + cnt2 * 4 +1; - if (now >= 13500 && now < 22500) - key = 0x3000 + 0x100 * cnt1 + cnt2 * 4 +2; - if (now >= 22500 && now < 31500) - key = 0x3000 + 0x100 * cnt1 + cnt2 * 4 +3; - } - } - if (index >= 17 && index <= 20 && analog == 0) - key = 0; - else if (key > 0) - { - if (key != 1) - global.config.keys[pad][index] = key; - set_label (hWnd, pad, index); - EnableWindow (GetDlgItem (hWnd, disabled), TRUE); - disabled = 0; - } - } - } - return FALSE; -} - -u32 CALLBACK PS2EgetLibType (void) -{ - return 0x02; -} - -const char* CALLBACK PS2EgetLibName (void) -{ - return LibraryName; -} - -u32 CALLBACK PS2EgetLibVersion2 (u32 type) -{ - return (version << 16) | (revision << 8) | build; -} - -u32 CALLBACK PSEgetLibType (void) -{ - return 8; -} - -const char* CALLBACK PSEgetLibName (void) -{ - return LibraryName; -} - -u32 CALLBACK PSEgetLibVersion (void) -{ - return (version << 16) | (revision << 8) | build; -} - -s32 CALLBACK PADinit (u32 flags) -{ - return 0; -} - -void CALLBACK PADshutdown (void) -{ -} - -static int n_open = 0; -s32 CALLBACK PADopen (HWND hWnd) -{ - if (!IsWindow (hWnd) && !IsBadReadPtr ((u32*)hWnd, 4)) - hWnd = *(HWND*)hWnd; - if (!IsWindow (hWnd)) - hWnd = NULL; - else - { - while (GetWindowLong (hWnd, GWL_STYLE) & WS_CHILD) - hWnd = GetParent (hWnd); - } - hTargetWnd = hWnd; - if (n_open++ == FALSE) - { - memset (&global, 0, sizeof (global)); - global.padStat[0] = 0xffff; - global.padStat[1] = 0xffff; - LoadConfig(); - PADsetMode (0, 0); - PADsetMode (1, 0); - } - return 0; -} - -void CALLBACK PADclose (void) -{ - if (--n_open == 0) - ReleaseDirectInput(); -} - -u32 CALLBACK PADquery (void) -{ - return 3; -} - -u8 CALLBACK PADstartPoll (int pad) -{ - global.curPad = pad -1; - global.curByte = 0; - return 0xff; -} - -static const u8 cmd40[8] = -{ - 0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5a -}; -static const u8 cmd41[8] = -{ - 0xff, 0x5a, 0xff, 0xff, 0x03, 0x00, 0x00, 0x5a, -}; -static const u8 cmd44[8] = -{ - 0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; -static const u8 cmd45[8] = -{ - 0xff, 0x5a, 0x03, 0x02, 0x01, 0x02, 0x01, 0x00, -}; -static const u8 cmd46[8] = -{ - 0xff, 0x5a, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0a, -}; -static const u8 cmd47[8] = -{ - 0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, -}; -static const u8 cmd4c[8] = -{ - 0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; -static const u8 cmd4d[8] = -{ - 0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -}; -static const u8 cmd4f[8] = -{ - 0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, -}; - -static u8 get_analog (const int key) -{ - const int pad = ((key & 0xf00) / 0x100); - const int pos = ((key & 0x0ff) /2); - return (u8)(((int*)&global.JoyState[pad].lX)[pos] + 128); -} - -static u8 get_pressure (const DWORD now, const DWORD press) -{ - /*if (press == 0) - return 0; - return (u8)((now - press > 2550) ? 255 : (now - press) / 10);*/ - return 255; -} - -u8 CALLBACK PADpoll (const u8 value) -{ - const int pad = global.curPad; - const int cur = global.curByte; - static u8 buf[20]; - if (cur == 0) - { - global.curByte++; - global.curCmd = value; - switch (value) - { - case 0x40: - global.cmdLen = sizeof (cmd40); - memcpy (buf, cmd40, sizeof (cmd40)); - return 0xf3; - case 0x41: - global.cmdLen = sizeof (cmd41); - memcpy (buf, cmd41, sizeof (cmd41)); - return 0xf3; - case 0x42: - case 0x43: - if (value == 0x42) UpdateState (pad); - global.cmdLen = 2 + 2 * (global.padID[pad] & 0x0f); - buf[1] = global.padModeC[pad] ? 0x00 : 0x5a; - *(u16*)&buf[2] = global.padStat[pad]; - if (value == 0x43 && global.padModeE[pad]) - { - buf[4] = 0; - buf[5] = 0; - buf[6] = 0; - buf[7] = 0; - return 0xf3; - } - else - { - buf[ 4] = get_analog (global.config.keys[pad][19]); - buf[ 5] = get_analog (global.config.keys[pad][20]); - buf[ 6] = get_analog (global.config.keys[pad][17]); - buf[ 7] = get_analog (global.config.keys[pad][18]); - if (global.padID[pad] == 0x79) - { - const DWORD now = GetTickCount(); - buf[ 8] = get_pressure (now, global.padPress[pad][2]); - buf[ 9] = get_pressure (now, global.padPress[pad][0]); - buf[10] = get_pressure (now, global.padPress[pad][3]); - buf[11] = get_pressure (now, global.padPress[pad][1]); - buf[12] = get_pressure (now, global.padPress[pad][11]); - buf[13] = get_pressure (now, global.padPress[pad][10]); - buf[14] = get_pressure (now, global.padPress[pad][9]); - buf[15] = get_pressure (now, global.padPress[pad][8]); - buf[16] = get_pressure (now, global.padPress[pad][13]); - buf[17] = get_pressure (now, global.padPress[pad][12]); - buf[18] = get_pressure (now, global.padPress[pad][15]); - buf[19] = get_pressure (now, global.padPress[pad][14]); - } - return (u8)global.padID[pad]; - } - break; - case 0x44: - global.cmdLen = sizeof (cmd44); - memcpy (buf, cmd44, sizeof (cmd44)); - return 0xf3; - case 0x45: - global.cmdLen = sizeof (cmd45); - memcpy (buf, cmd45, sizeof (cmd45)); - buf[4] = (u8)global.padMode1[pad]; - return 0xf3; - case 0x46: - global.cmdLen = sizeof (cmd46); - memcpy (buf, cmd46, sizeof (cmd46)); - return 0xf3; - case 0x47: - global.cmdLen = sizeof (cmd47); - memcpy (buf, cmd47, sizeof (cmd47)); - return 0xf3; - case 0x4c: - global.cmdLen = sizeof (cmd4c); - memcpy (buf, cmd4c, sizeof (cmd4c)); - return 0xf3; - case 0x4d: - global.cmdLen = sizeof (cmd4d); - memcpy (buf, cmd4d, sizeof (cmd4d)); - return 0xf3; - case 0x4f: - global.padID[pad] = 0x79; - global.padMode2[pad] = 1; - global.cmdLen = sizeof (cmd4f); - memcpy (buf, cmd4f, sizeof (cmd4f)); - return 0xf3; - } - } - switch (global.curCmd) - { - case 0x42: - if (cur == global.padVib0[pad]) - global.padVibF[pad][0] = value; - if (cur == global.padVib1[pad]) - global.padVibF[pad][1] = value; - break; - case 0x43: - if (cur == 2) - { - global.padModeE[pad] = value; - global.padModeC[pad] = 0; - } - break; - case 0x44: - if (cur == 2) - PADsetMode (pad, value); - if (cur == 3) - global.padModeF[pad] = (value == 3); - break; - case 0x46: - if (cur == 2) - { - switch(value) - { - case 0: - buf[5] = 0x02; - buf[6] = 0x00; - buf[7] = 0x0A; - break; - case 1: - buf[5] = 0x01; - buf[6] = 0x01; - buf[7] = 0x14; - break; - } - } - break; - case 0x4c: - if (cur == 2) - { - static const u8 buf5[] = { 0x04, 0x07, 0x02, 0x05 }; - buf[5] = buf5[value & 3]; - } - break; - case 0x4d: - if (cur >= 2) - { - if (cur == global.padVib0[pad]) - buf[cur] = 0x00; - if (cur == global.padVib1[pad]) - buf[cur] = 0x01; - if (value == 0x00) - { - global.padVib0[pad] = cur; - if ((global.padID[pad] & 0x0f) < (cur - 1) / 2) - global.padID[pad] = (global.padID[pad] & 0xf0) + (cur - 1) / 2; - } - else if (value == 0x01) - { - global.padVib1[pad] = cur; - if ((global.padID[pad] & 0x0f) < (cur - 1) / 2) - global.padID[pad] = (global.padID[pad] & 0xf0) + (cur - 1) / 2; - } - } - break; - } - if (cur >= global.cmdLen) - return 0; - return buf[global.curByte++]; -} - -typedef struct -{ - unsigned char controllerType; - unsigned short buttonStatus; - unsigned char rightJoyX, rightJoyY, leftJoyX, leftJoyY; - unsigned char moveX, moveY; - unsigned char reserved[91]; -} PadDataS; - -long PADreadPort1 (PadDataS* pads) -{ - memset (pads, 0, sizeof (PadDataS)); - if ((global.padID[0] & 0xf0) == 0x40) - pads->controllerType = 4; - else - pads->controllerType = 7; - pads->buttonStatus = global.padStat[0]; - pads->leftJoyX = get_analog (global.config.keys[0][17]); - pads->leftJoyY = get_analog (global.config.keys[0][18]); - pads->rightJoyX = get_analog (global.config.keys[0][19]); - pads->rightJoyY = get_analog (global.config.keys[0][20]); - pads->moveX = 0; - pads->moveY = 0; - return 0; -} - -long PADreadPort2 (PadDataS* pads) -{ - memset (pads, 0, sizeof (PadDataS)); - if ((global.padID[1] & 0xf0) == 0x40) - pads->controllerType = 4; - else - pads->controllerType = 7; - pads->buttonStatus = global.padStat[1]; - pads->leftJoyX = get_analog (global.config.keys[1][17]); - pads->leftJoyY = get_analog (global.config.keys[1][18]); - pads->rightJoyX = get_analog (global.config.keys[1][19]); - pads->rightJoyY = get_analog (global.config.keys[1][20]); - pads->moveX = 0; - pads->moveY = 0; - return 0; -} - -keyEvent* CALLBACK PADkeyEvent (void) -{ - static keyEvent ev; - static u8 state[2][256]; - if (n_open) - { - memcpy (state[0], state[1], sizeof (state[0])); - GetKeyState (state[1]); - for (int cnt = 0; cnt < 256; cnt++) - { - if (~state[0][cnt] & state[1][cnt] & 0x80) - { - ev.event = (state[1][cnt] & 0x80) ? 1 : 2; - ev.key = MapVirtualKey (cnt, 1); - return &ev; - } - } - } - return NULL; -} - -void CALLBACK PADconfigure (void) -{ - if (n_open == 0) - { - memset (&global, 0, sizeof (global)); - if (DialogBox (hInstance, MAKEINTRESOURCE (IDD_DIALOG1), GetActiveWindow(), (DLGPROC)ConfigureDlgProc) == IDOK) - SaveConfig(); - ReleaseDirectInput(); - } -} - -void CALLBACK PADabout (void) -{ - MessageBox (0, "Copyright (C) 2004-2005 Nagisa", "SSSPSX PAD plugin", 0); -} - -s32 CALLBACK PADtest (void) -{ - return 0; -} -//#ifdef _WIN64 -BOOL APIENTRY DllMain(HMODULE hInst, DWORD dwReason, LPVOID lpReserved) -{ - hInstance = hInst; - return TRUE; -} -//#else -BOOL APIENTRY EntryPoint (HMODULE hInst, DWORD dwReason, LPVOID lpReserved) -{ - hInstance = hInst; - return TRUE; -} -//#endif +#define WINVER 0x0500 +#define _WIN32_WINNT WINVER +#define DIRECTINPUT_VERSION 0x0800 + +#include +#include +#include +#include + +#include "PadSSSPSX.h" + +static const char* LibraryName = "SSSPSX PAD Plugin Pressure Mod"; +static const unsigned char version = 0x0002; +static const unsigned char revision = 1; +static const unsigned char build = 6; + +HMODULE hInstance; +HWND hTargetWnd; + +static struct +{ + Config config; + int devcnt; + LPDIRECTINPUT8 pDInput; + LPDIRECTINPUTDEVICE8 pDKeyboard; + LPDIRECTINPUTDEVICE8 pDDevice[4]; + LPDIRECTINPUTEFFECT pDEffect[4][2]; /* for Small & Big Motor */ + DIJOYSTATE JoyState[4]; + u16 padStat[2]; + int padID[2]; + int padMode1[2]; + int padMode2[2]; + int padModeE[2]; + int padModeC[2]; + int padModeF[2]; + int padVib0[2]; + int padVib1[2]; + int padVibF[2][4]; + int padVibC[2]; + DWORD padPress[2][16]; + int curPad; + int curByte; + int curCmd; + int cmdLen; +} global; + +static BOOL CALLBACK EnumAxesCallback (LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef) +{ + LPDIRECTINPUTDEVICE8 pDDevice = (LPDIRECTINPUTDEVICE8)pvRef; + DIPROPRANGE diprg; + diprg.diph.dwSize = sizeof (diprg); + diprg.diph.dwHeaderSize = sizeof (diprg.diph); + diprg.diph.dwObj = lpddoi->dwType; + diprg.diph.dwHow = DIPH_BYID; + diprg.lMin = -128; + diprg.lMax = 127; + pDDevice->SetProperty (DIPROP_RANGE, &diprg.diph); + return DIENUM_CONTINUE; +} + +static BOOL CALLBACK EnumJoysticksCallback (const DIDEVICEINSTANCE* instance, VOID* pContext) +{ + const int devno = global.devcnt; + if (devno >= 4) + return DIENUM_STOP; + HRESULT result = global.pDInput->CreateDevice (instance->guidInstance, &global.pDDevice[devno], NULL); + if (FAILED (result)) + return DIENUM_CONTINUE; + global.devcnt++; + return DIENUM_CONTINUE; +} + +static bool ReleaseDirectInput (void) +{ + int index = 4; + while (index--) + { + if (global.pDEffect[index][0]) + { + global.pDEffect[index][0]->Unload(); + global.pDEffect[index][0]->Release(); + global.pDEffect[index][0] = NULL; + } + if (global.pDEffect[index][1]) + { + global.pDEffect[index][1]->Unload(); + global.pDEffect[index][1]->Release(); + global.pDEffect[index][1] = NULL; + } + if (global.pDDevice[index]) + { + global.pDDevice[index]->Unacquire(); + global.pDDevice[index]->Release(); + global.pDDevice[index] = NULL; + } + } + if (global.pDKeyboard) + { + global.pDKeyboard->Unacquire(); + global.pDKeyboard->Release(); + global.pDKeyboard = NULL; + } + if (global.pDInput) + { + global.pDInput->Release(); + global.pDInput = NULL; + } + global.devcnt = 0; + return FALSE; +} + +static bool InitDirectInput (void) +{ + if (global.pDInput) + return TRUE; + HRESULT result = DirectInput8Create (hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&global.pDInput, NULL); + if (FAILED (result)) + return ReleaseDirectInput(); + result = global.pDInput->CreateDevice (GUID_SysKeyboard, &global.pDKeyboard, NULL); + if (FAILED (result)) + return ReleaseDirectInput(); + result = global.pDInput->EnumDevices (DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, NULL, DIEDFL_ATTACHEDONLY); + if (FAILED (result)) + return ReleaseDirectInput(); + result = global.pDKeyboard->SetDataFormat (&c_dfDIKeyboard); + if (FAILED (result)) + return ReleaseDirectInput(); + if (hTargetWnd) + { + global.pDKeyboard->Unacquire(); + result = global.pDKeyboard->SetCooperativeLevel (hTargetWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); + if (FAILED (result)) + return ReleaseDirectInput(); + } + int index = global.devcnt; + while (index--) + { + const LPDIRECTINPUTDEVICE8 pDDevice = global.pDDevice[index]; + result = pDDevice->SetDataFormat (&c_dfDIJoystick); + if (FAILED (result)) + return ReleaseDirectInput(); + if (hTargetWnd) + { + pDDevice->Unacquire(); + result = pDDevice->SetCooperativeLevel (hTargetWnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE); + if (FAILED (result)) + return ReleaseDirectInput(); + } + struct + { + DIPROPDWORD dipdw; + DWORD rgdwAxes[2]; + LONG rglDirection[2]; + DIPERIODIC per; + DICONSTANTFORCE cf; + DIEFFECT eff; + } local; + memset (&local, 0, sizeof (local)); + local.dipdw.diph.dwSize = sizeof (DIPROPDWORD); + local.dipdw.diph.dwHeaderSize = sizeof (DIPROPHEADER); + local.dipdw.diph.dwHow = DIPH_DEVICE; + local.dipdw.dwData = DIPROPAUTOCENTER_OFF; + pDDevice->SetProperty (DIPROP_AUTOCENTER, &local.dipdw.diph); + result = pDDevice->EnumObjects (EnumAxesCallback, pDDevice, DIDFT_AXIS); + if (FAILED (result)) + return ReleaseDirectInput(); + + local.rgdwAxes[0] = DIJOFS_X; + local.rgdwAxes[1] = DIJOFS_Y; + local.eff.dwSize = sizeof (DIEFFECT); + local.eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + local.eff.dwDuration = INFINITE; + local.eff.dwGain = DI_FFNOMINALMAX; + local.eff.dwTriggerButton = DIEB_NOTRIGGER; + local.eff.cAxes = 2; + local.eff.rgdwAxes = local.rgdwAxes; + local.eff.rglDirection = local.rglDirection; + + /* Small Motor */ + local.eff.cbTypeSpecificParams = sizeof (DIPERIODIC); + local.eff.lpvTypeSpecificParams = &local.per; + result = pDDevice->CreateEffect (GUID_Square , &local.eff, &global.pDEffect[index][0], NULL); + if (FAILED (result)) + global.pDEffect[index][0] = NULL; + + /* Big Motor */ + local.eff.cbTypeSpecificParams = sizeof (DICONSTANTFORCE); + local.eff.lpvTypeSpecificParams = &local.cf; + result = pDDevice->CreateEffect (GUID_ConstantForce , &local.eff, &global.pDEffect[index][1], NULL); + if (FAILED (result)) + global.pDEffect[index][1] = NULL; + } + return TRUE; +} + +static bool AcquireDevice (LPDIRECTINPUTDEVICE8 lpDirectInputDevice) +{ + if (FAILED (lpDirectInputDevice->Acquire())) + { + HRESULT result = lpDirectInputDevice->Acquire(); + if (result == DIERR_OTHERAPPHASPRIO) + return FALSE; + if (FAILED (result)) + return ReleaseDirectInput(); + } + return TRUE; +} + +/* Small Motor */ +static bool SetDeviceForceS (int pad, DWORD force) +{ + InitDirectInput(); + if (global.pDEffect[pad][0]) + { + if ( force == 0) { + if (FAILED (global.pDEffect[pad][0]->Stop())) { + AcquireDevice (global.pDDevice[pad]); + if (FAILED (global.pDEffect[pad][0]->Stop())) + return ReleaseDirectInput(); + } + return TRUE; + } + LONG rglDirection[2] = { 0, 0 }; + DIPERIODIC per; + rglDirection[0] = force; + rglDirection[1] = force; + per.dwMagnitude = force; + per.dwPeriod = (DWORD) (0.01 * DI_SECONDS); + per.lOffset = 0; + per.dwPhase = 0; + DIEFFECT eff; + eff.dwSize = sizeof (DIEFFECT); + eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + eff.cAxes = 2; + eff.rglDirection = rglDirection; + eff.lpEnvelope = 0; + eff.cbTypeSpecificParams = sizeof (DIPERIODIC); + eff.lpvTypeSpecificParams = &per; + if (FAILED (global.pDEffect[pad][0]->SetParameters (&eff, DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_START))) + return ReleaseDirectInput(); + if (FAILED (global.pDEffect[pad][0]->Start (1, 0))) + { + AcquireDevice (global.pDDevice[pad]); + if (FAILED (global.pDEffect[pad][0]->Start (1, 0))) + return ReleaseDirectInput(); + } + } + return TRUE; +} + +/* Big Motor */ +static bool SetDeviceForceB (int pad, DWORD force) +{ + InitDirectInput(); + if (global.pDEffect[pad][1]) + { + if ( force == 0) { + if (FAILED (global.pDEffect[pad][1]->Stop())) { + AcquireDevice (global.pDDevice[pad]); + if (FAILED (global.pDEffect[pad][1]->Stop())) + return ReleaseDirectInput(); + } + return TRUE; + } + LONG rglDirection[2] = { 0, 0 }; + DICONSTANTFORCE cf; + rglDirection[0] = force; + rglDirection[1] = force; + cf.lMagnitude = force; + DIEFFECT eff; + eff.dwSize = sizeof (DIEFFECT); + eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + eff.cAxes = 2; + eff.rglDirection = rglDirection; + eff.lpEnvelope = 0; + eff.cbTypeSpecificParams = sizeof (DICONSTANTFORCE); + eff.lpvTypeSpecificParams = &cf; + if (FAILED (global.pDEffect[pad][1]->SetParameters (&eff, DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_START))) + return ReleaseDirectInput(); + if (FAILED (global.pDEffect[pad][1]->Start (1, 0))) + { + AcquireDevice (global.pDDevice[pad]); + if (FAILED (global.pDEffect[pad][1]->Start (1, 0))) + return ReleaseDirectInput(); + } + } + return TRUE; +} + +static bool GetJoyState (const int devno) +{ + InitDirectInput(); + if (global.pDDevice[devno] == NULL) + return FALSE; + global.pDDevice[devno]->Poll(); + if (FAILED (global.pDDevice[devno]->GetDeviceState (sizeof (DIJOYSTATE), &global.JoyState[devno]))) + { + AcquireDevice (global.pDDevice[devno]); + return FALSE; + } + return TRUE; +} + +static bool GetKeyState (u8* keyboard) +{ + InitDirectInput(); + if (global.pDKeyboard == NULL) + return FALSE; + global.pDKeyboard->Poll(); + if (FAILED (global.pDKeyboard->GetDeviceState (256, keyboard))) + { + AcquireDevice (global.pDKeyboard); + return FALSE; + } + return TRUE; +} + +static void MakeConfigFileName (char* fname) +{ + GetModuleFileName (hInstance, fname, 256); + strcpy (fname + strlen (fname) - 3, "cfg"); +} + +static void SaveConfig (void) +{ + char fname[256]; + MakeConfigFileName (fname); + HANDLE hFile = CreateFile (fname, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + DWORD number_of_bytes; + WriteFile (hFile, &global.config, sizeof (global.config), &number_of_bytes, NULL); + CloseHandle (hFile); + } +} + +static void LoadConfig (void) +{ + char fname[256]; + MakeConfigFileName (fname); + HANDLE hFile = CreateFile (fname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + DWORD number_of_bytes; + ReadFile (hFile, &global.config, sizeof (global.config), &number_of_bytes, NULL); + CloseHandle (hFile); + } + global.padVibC[0] = global.padVibC[1] = -1; + for (int cnt = 21; cnt--; ) + { + const int key0 = global.config.keys[0][cnt]; + if (key0 >= 0x1000) + global.padVibC[0] = (key0 & 0xfff) / 0x100; + const int key1 = global.config.keys[1][cnt]; + if (key1 >= 0x1000) + global.padVibC[1] = (key1 & 0xfff) / 0x100; + } +} + +static void PADsetMode (const int pad, const int mode) +{ + static const u8 padID[] = { 0x41, 0x73, 0x41, 0x79 }; + global.padMode1[pad] = mode; + global.padVib0[pad] = 0; + global.padVib1[pad] = 0; + global.padVibF[pad][0] = 0; + global.padVibF[pad][1] = 0; + global.padID[pad] = padID[global.padMode2[pad] * 2 + mode]; +} + +static void KeyPress (const int pad, const int index, const bool press) +{ + if (index < 16) + { + if (press) + { + global.padStat[pad] &= ~(1 << index); + if (global.padPress[pad][index] == 0) + global.padPress[pad][index] = GetTickCount(); + } + else + { + global.padStat[pad] |= 1 << index; + global.padPress[pad][index] = 0; + } + } + else + { + static bool prev[2] = { FALSE, FALSE }; + if ((prev[pad] != press) && (global.padModeF[pad] == 0)) + { + prev[pad] = press; + if (press) PADsetMode (pad, !global.padMode1[pad]); + } + } +} + +static void UpdateState (const int pad) +{ + static int flag_keyboard; + static int flag_joypad[4]; + if (pad == 0) + { + flag_keyboard = 0; + flag_joypad[0] = 0; + flag_joypad[1] = 0; + flag_joypad[2] = 0; + flag_joypad[3] = 0; + } + static u8 keystate[256]; + for (int index = 17; index--; ) + { + const int key = global.config.keys[pad][index]; + if (key == 0) + continue; + else if (key < 0x100) + { + if (flag_keyboard == FALSE) + { + flag_keyboard = TRUE; + if (GetKeyState (keystate) == FALSE) + return; + } + KeyPress (pad, index, keystate[key] & 0x80); + } + else + { + const int joypad = ((key & 0xfff) / 100); + if (flag_joypad[joypad] == FALSE) + { + flag_joypad[joypad] = TRUE; + if (GetJoyState (joypad) == FALSE) + return; + } + if (key < 0x2000) + { + KeyPress (pad, index, global.JoyState[joypad].rgbButtons[key & 0xff]); + } + else if (key < 0x3000) + { + const int state = ((int*)&global.JoyState[joypad].lX)[(key & 0xff) /2]; + switch (key & 1) + { + case 0: KeyPress (pad, index, state < -64); break; + case 1: KeyPress (pad, index, state >= 64); break; + } + } + else + { + const u32 state = global.JoyState[joypad].rgdwPOV[(key & 0xff) /4]; + switch (key & 3) + { + case 0: KeyPress (pad, index, (state >= 0 && state <= 4500) || (state >= 31500 && state <= 36000)); break; + case 1: KeyPress (pad, index, state >= 4500 && state <= 13500); break; + case 2: KeyPress (pad, index, state >= 13500 && state <= 22500); break; + case 3: KeyPress (pad, index, state >= 22500 && state <= 31500); break; + } + } + } + } + + /* Small Motor */ + const int vib0 = global.padVibF[pad][0] ? 10000 : 0; + if ((global.padVibF[pad][2] != vib0) && (global.padVibC[pad] >= 0)) + { + global.padVibF[pad][2] = vib0; + SetDeviceForceS (global.padVibC[pad], vib0); + } + /* Big Motor */ + const int vib1 = global.padVibF[pad][1] ? 500 + 37*global.padVibF[pad][1] : 0; + if ((global.padVibF[pad][3] != vib1) && (global.padVibC[pad] >= 0)) + { + global.padVibF[pad][3] = vib1; + SetDeviceForceB (global.padVibC[pad], vib1); + } +} + +static void set_label (const HWND hWnd, const int pad, const int index) +{ + const int key = global.config.keys[pad][index]; + char buff[64]; + if (key < 0x100) + { + if (key == 0) + strcpy (buff, "NONE"); + else if (GetKeyNameText (key << 16, buff, sizeof (buff)) == 0) + wsprintf (buff, "Keyboard 0x%02X", key); + } + else if (key >= 0x1000 && key < 0x2000) + { + wsprintf (buff, "J%d_%d", (key & 0xfff) / 0x100, (key & 0xff) + 1); + } + else if (key >= 0x2000 && key < 0x3000) + { + static const char name[][4] = { "MIN", "MAX" }; + const int axis = (key & 0xff); + wsprintf (buff, "J%d_AXIS%d_%s", (key & 0xfff) / 0x100, axis / 2, name[axis % 2]); + if (index >= 17 && index <= 20) + buff[strlen (buff) -4] = '\0'; + } + else if (key >= 0x3000 && key < 0x4000) + { + static const char name[][7] = { "FOWARD", "RIGHT", "BACK", "LEFT" }; + const int pov = (key & 0xff); + wsprintf (buff, "J%d_POV%d_%s", (key & 0xfff) / 0x100, pov /4, name[pov % 4]); + } + Button_SetText (GetDlgItem (hWnd, IDC_ESELECT + index), buff); +} + +static BOOL CALLBACK ConfigureDlgProc (const HWND hWnd, const UINT msg, const WPARAM wParam, const LPARAM lParam) +{ + static BYTE keymaps[2][256]; + static DWORD countdown; + static int disabled; + static HWND hTabWnd; + static int pad; + int cnt1; + int cnt2; + int key; + switch (msg) + { + case WM_INITDIALOG: + hTargetWnd = hWnd; + pad = disabled = 0; + LoadConfig(); + for (cnt1 = 21; cnt1--; ) + set_label (hWnd, pad, cnt1); + hTabWnd = GetDlgItem (hWnd, IDC_TABC); + TCITEM tcI; + tcI.mask = TCIF_TEXT; + tcI.pszText = "PAD1"; + TabCtrl_InsertItem (hTabWnd, 0, &tcI); + tcI.mask = TCIF_TEXT; + tcI.pszText = "PAD2"; + TabCtrl_InsertItem (hTabWnd, 1, &tcI); + SetTimer (hWnd, 0x80, 50, NULL); + return TRUE; + case WM_DESTROY: + break; + case WM_NOTIFY: + if (wParam == IDC_TABC) + { + if (disabled) + EnableWindow (GetDlgItem (hWnd, disabled), TRUE); + disabled = 0; + pad = TabCtrl_GetCurSel (hTabWnd); + for (cnt1 = 21; cnt1--; ) + set_label (hWnd, pad, cnt1); + } + break; + case WM_COMMAND: + for (cnt1 = 21; cnt1--; ) + { + if (LOWORD (wParam) == IDC_BSELECT + cnt1) + { + if (disabled) + EnableWindow (GetDlgItem (hWnd, disabled), TRUE); + EnableWindow (GetDlgItem (hWnd, disabled = wParam), FALSE); + countdown = GetTickCount(); + GetKeyState (keymaps[0]); + return TRUE; + } + } + if (LOWORD (wParam) == IDOK) + EndDialog (hWnd, IDOK); + else if (LOWORD (wParam) == IDCANCEL) + EndDialog (hWnd, IDCANCEL); + break; + case WM_TIMER: + if (disabled) + { + const int index = disabled - IDC_BSELECT; + int analog = FALSE; + if ((GetTickCount() - countdown) / 1000 != 10) + { + char buff[64]; + wsprintf (buff, "Timeout: %d", 10 - (GetTickCount() - countdown) / 1000); + SetWindowText (GetDlgItem (hWnd, IDC_ESELECT + index), buff); + } + else + { + global.config.keys[pad][index] = 0; + set_label (hWnd, pad, index); + EnableWindow (GetDlgItem (hWnd, disabled), TRUE); + disabled = 0; + break; + } + if (GetKeyState (keymaps[1]) == FALSE) + break; + for (key = 0x100; key--; ) + { + if (~keymaps[0][key] & keymaps[1][key] & 0x80) + break; + } + for (cnt1 = global.devcnt; cnt1--;) + { + if (GetJoyState (cnt1) == FALSE) + break; + + for (cnt2 = 32; cnt2--; ) + { + if (global.JoyState[cnt1].rgbButtons[cnt2]) + key = 0x1000 + 0x100 * cnt1 + cnt2; + } + for (cnt2 = 8; cnt2--; ) + { + const int now = ((u32*)&global.JoyState[cnt1].lX)[cnt2]; + if (now < -64) + { + key = 0x2000 + 0x100 * cnt1 + cnt2 * 2 +0; + analog = TRUE; + } + else if (now >= 64) + { + key = 0x2000 + 0x100 * cnt1 + cnt2 * 2 +1; + analog = TRUE; + } + } + for (cnt2 = 4; cnt2--; ) + { + const u32 now = global.JoyState[cnt1].rgdwPOV[cnt2]; + if ((now >= 0 && now < 4500) || (now >= 31500 && now < 36000)) + key = 0x3000 + 0x100 * cnt1 + cnt2 * 4 +0; + if (now >= 4500 && now < 13500) + key = 0x3000 + 0x100 * cnt1 + cnt2 * 4 +1; + if (now >= 13500 && now < 22500) + key = 0x3000 + 0x100 * cnt1 + cnt2 * 4 +2; + if (now >= 22500 && now < 31500) + key = 0x3000 + 0x100 * cnt1 + cnt2 * 4 +3; + } + } + if (index >= 17 && index <= 20 && analog == 0) + key = 0; + else if (key > 0) + { + if (key != 1) + global.config.keys[pad][index] = key; + set_label (hWnd, pad, index); + EnableWindow (GetDlgItem (hWnd, disabled), TRUE); + disabled = 0; + } + } + } + return FALSE; +} + +u32 CALLBACK PS2EgetLibType (void) +{ + return 0x02; +} + +const char* CALLBACK PS2EgetLibName (void) +{ + return LibraryName; +} + +u32 CALLBACK PS2EgetLibVersion2 (u32 type) +{ + return (version << 16) | (revision << 8) | build; +} + +u32 CALLBACK PSEgetLibType (void) +{ + return 8; +} + +const char* CALLBACK PSEgetLibName (void) +{ + return LibraryName; +} + +u32 CALLBACK PSEgetLibVersion (void) +{ + return (version << 16) | (revision << 8) | build; +} + +s32 CALLBACK PADinit (u32 flags) +{ + return 0; +} + +void CALLBACK PADshutdown (void) +{ +} + +static int n_open = 0; +s32 CALLBACK PADopen (HWND hWnd) +{ + if (!IsWindow (hWnd) && !IsBadReadPtr ((u32*)hWnd, 4)) + hWnd = *(HWND*)hWnd; + if (!IsWindow (hWnd)) + hWnd = NULL; + else + { + while (GetWindowLong (hWnd, GWL_STYLE) & WS_CHILD) + hWnd = GetParent (hWnd); + } + hTargetWnd = hWnd; + if (n_open++ == FALSE) + { + memset (&global, 0, sizeof (global)); + global.padStat[0] = 0xffff; + global.padStat[1] = 0xffff; + LoadConfig(); + PADsetMode (0, 0); + PADsetMode (1, 0); + } + return 0; +} + +void CALLBACK PADclose (void) +{ + if (--n_open == 0) + ReleaseDirectInput(); +} + +u32 CALLBACK PADquery (void) +{ + return 3; +} + +u8 CALLBACK PADstartPoll (int pad) +{ + global.curPad = pad -1; + global.curByte = 0; + return 0xff; +} + +static const u8 cmd40[8] = +{ + 0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5a +}; +static const u8 cmd41[8] = +{ + 0xff, 0x5a, 0xff, 0xff, 0x03, 0x00, 0x00, 0x5a, +}; +static const u8 cmd44[8] = +{ + 0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static const u8 cmd45[8] = +{ + 0xff, 0x5a, 0x03, 0x02, 0x01, 0x02, 0x01, 0x00, +}; +static const u8 cmd46[8] = +{ + 0xff, 0x5a, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0a, +}; +static const u8 cmd47[8] = +{ + 0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, +}; +static const u8 cmd4c[8] = +{ + 0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static const u8 cmd4d[8] = +{ + 0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; +static const u8 cmd4f[8] = +{ + 0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, +}; + +static u8 get_analog (const int key) +{ + const int pad = ((key & 0xf00) / 0x100); + const int pos = ((key & 0x0ff) /2); + return (u8)(((int*)&global.JoyState[pad].lX)[pos] + 128); +} + +static u8 get_pressure (const DWORD now, const DWORD press) +{ + /*if (press == 0) + return 0; + return (u8)((now - press > 2550) ? 255 : (now - press) / 10);*/ + return 255; +} + +u8 CALLBACK PADpoll (const u8 value) +{ + const int pad = global.curPad; + const int cur = global.curByte; + static u8 buf[20]; + if (cur == 0) + { + global.curByte++; + global.curCmd = value; + switch (value) + { + case 0x40: + global.cmdLen = sizeof (cmd40); + memcpy (buf, cmd40, sizeof (cmd40)); + return 0xf3; + case 0x41: + global.cmdLen = sizeof (cmd41); + memcpy (buf, cmd41, sizeof (cmd41)); + return 0xf3; + case 0x42: + case 0x43: + if (value == 0x42) UpdateState (pad); + global.cmdLen = 2 + 2 * (global.padID[pad] & 0x0f); + buf[1] = global.padModeC[pad] ? 0x00 : 0x5a; + *(u16*)&buf[2] = global.padStat[pad]; + if (value == 0x43 && global.padModeE[pad]) + { + buf[4] = 0; + buf[5] = 0; + buf[6] = 0; + buf[7] = 0; + return 0xf3; + } + else + { + buf[ 4] = get_analog (global.config.keys[pad][19]); + buf[ 5] = get_analog (global.config.keys[pad][20]); + buf[ 6] = get_analog (global.config.keys[pad][17]); + buf[ 7] = get_analog (global.config.keys[pad][18]); + if (global.padID[pad] == 0x79) + { + const DWORD now = GetTickCount(); + buf[ 8] = get_pressure (now, global.padPress[pad][2]); + buf[ 9] = get_pressure (now, global.padPress[pad][0]); + buf[10] = get_pressure (now, global.padPress[pad][3]); + buf[11] = get_pressure (now, global.padPress[pad][1]); + buf[12] = get_pressure (now, global.padPress[pad][11]); + buf[13] = get_pressure (now, global.padPress[pad][10]); + buf[14] = get_pressure (now, global.padPress[pad][9]); + buf[15] = get_pressure (now, global.padPress[pad][8]); + buf[16] = get_pressure (now, global.padPress[pad][13]); + buf[17] = get_pressure (now, global.padPress[pad][12]); + buf[18] = get_pressure (now, global.padPress[pad][15]); + buf[19] = get_pressure (now, global.padPress[pad][14]); + } + return (u8)global.padID[pad]; + } + break; + case 0x44: + global.cmdLen = sizeof (cmd44); + memcpy (buf, cmd44, sizeof (cmd44)); + return 0xf3; + case 0x45: + global.cmdLen = sizeof (cmd45); + memcpy (buf, cmd45, sizeof (cmd45)); + buf[4] = (u8)global.padMode1[pad]; + return 0xf3; + case 0x46: + global.cmdLen = sizeof (cmd46); + memcpy (buf, cmd46, sizeof (cmd46)); + return 0xf3; + case 0x47: + global.cmdLen = sizeof (cmd47); + memcpy (buf, cmd47, sizeof (cmd47)); + return 0xf3; + case 0x4c: + global.cmdLen = sizeof (cmd4c); + memcpy (buf, cmd4c, sizeof (cmd4c)); + return 0xf3; + case 0x4d: + global.cmdLen = sizeof (cmd4d); + memcpy (buf, cmd4d, sizeof (cmd4d)); + return 0xf3; + case 0x4f: + global.padID[pad] = 0x79; + global.padMode2[pad] = 1; + global.cmdLen = sizeof (cmd4f); + memcpy (buf, cmd4f, sizeof (cmd4f)); + return 0xf3; + } + } + switch (global.curCmd) + { + case 0x42: + if (cur == global.padVib0[pad]) + global.padVibF[pad][0] = value; + if (cur == global.padVib1[pad]) + global.padVibF[pad][1] = value; + break; + case 0x43: + if (cur == 2) + { + global.padModeE[pad] = value; + global.padModeC[pad] = 0; + } + break; + case 0x44: + if (cur == 2) + PADsetMode (pad, value); + if (cur == 3) + global.padModeF[pad] = (value == 3); + break; + case 0x46: + if (cur == 2) + { + switch(value) + { + case 0: + buf[5] = 0x02; + buf[6] = 0x00; + buf[7] = 0x0A; + break; + case 1: + buf[5] = 0x01; + buf[6] = 0x01; + buf[7] = 0x14; + break; + } + } + break; + case 0x4c: + if (cur == 2) + { + static const u8 buf5[] = { 0x04, 0x07, 0x02, 0x05 }; + buf[5] = buf5[value & 3]; + } + break; + case 0x4d: + if (cur >= 2) + { + if (cur == global.padVib0[pad]) + buf[cur] = 0x00; + if (cur == global.padVib1[pad]) + buf[cur] = 0x01; + if (value == 0x00) + { + global.padVib0[pad] = cur; + if ((global.padID[pad] & 0x0f) < (cur - 1) / 2) + global.padID[pad] = (global.padID[pad] & 0xf0) + (cur - 1) / 2; + } + else if (value == 0x01) + { + global.padVib1[pad] = cur; + if ((global.padID[pad] & 0x0f) < (cur - 1) / 2) + global.padID[pad] = (global.padID[pad] & 0xf0) + (cur - 1) / 2; + } + } + break; + } + if (cur >= global.cmdLen) + return 0; + return buf[global.curByte++]; +} + +typedef struct +{ + unsigned char controllerType; + unsigned short buttonStatus; + unsigned char rightJoyX, rightJoyY, leftJoyX, leftJoyY; + unsigned char moveX, moveY; + unsigned char reserved[91]; +} PadDataS; + +long PADreadPort1 (PadDataS* pads) +{ + memset (pads, 0, sizeof (PadDataS)); + if ((global.padID[0] & 0xf0) == 0x40) + pads->controllerType = 4; + else + pads->controllerType = 7; + pads->buttonStatus = global.padStat[0]; + pads->leftJoyX = get_analog (global.config.keys[0][17]); + pads->leftJoyY = get_analog (global.config.keys[0][18]); + pads->rightJoyX = get_analog (global.config.keys[0][19]); + pads->rightJoyY = get_analog (global.config.keys[0][20]); + pads->moveX = 0; + pads->moveY = 0; + return 0; +} + +long PADreadPort2 (PadDataS* pads) +{ + memset (pads, 0, sizeof (PadDataS)); + if ((global.padID[1] & 0xf0) == 0x40) + pads->controllerType = 4; + else + pads->controllerType = 7; + pads->buttonStatus = global.padStat[1]; + pads->leftJoyX = get_analog (global.config.keys[1][17]); + pads->leftJoyY = get_analog (global.config.keys[1][18]); + pads->rightJoyX = get_analog (global.config.keys[1][19]); + pads->rightJoyY = get_analog (global.config.keys[1][20]); + pads->moveX = 0; + pads->moveY = 0; + return 0; +} + +keyEvent* CALLBACK PADkeyEvent (void) +{ + static keyEvent ev; + static u8 state[2][256]; + if (n_open) + { + memcpy (state[0], state[1], sizeof (state[0])); + GetKeyState (state[1]); + for (int cnt = 0; cnt < 256; cnt++) + { + if (~state[0][cnt] & state[1][cnt] & 0x80) + { + ev.event = (state[1][cnt] & 0x80) ? 1 : 2; + ev.key = MapVirtualKey (cnt, 1); + return &ev; + } + } + } + return NULL; +} + +void CALLBACK PADconfigure (void) +{ + if (n_open == 0) + { + memset (&global, 0, sizeof (global)); + if (DialogBox (hInstance, MAKEINTRESOURCE (IDD_DIALOG1), GetActiveWindow(), (DLGPROC)ConfigureDlgProc) == IDOK) + SaveConfig(); + ReleaseDirectInput(); + } +} + +void CALLBACK PADabout (void) +{ + MessageBox (0, "Copyright (C) 2004-2005 Nagisa", "SSSPSX PAD plugin", 0); +} + +s32 CALLBACK PADtest (void) +{ + return 0; +} +//#ifdef _WIN64 +BOOL APIENTRY DllMain(HMODULE hInst, DWORD dwReason, LPVOID lpReserved) +{ + hInstance = hInst; + return TRUE; +} +//#else +BOOL APIENTRY EntryPoint (HMODULE hInst, DWORD dwReason, LPVOID lpReserved) +{ + hInstance = hInst; + return TRUE; +} +//#endif diff --git a/plugins/SSSPSXPAD/PadSSSPSX.h b/plugins/SSSPSXPAD/PadSSSPSX.h index facd78303a..22bac3ac64 100644 --- a/plugins/SSSPSXPAD/PadSSSPSX.h +++ b/plugins/SSSPSXPAD/PadSSSPSX.h @@ -1,45 +1,45 @@ -/* PADwin - * Copyright (C) 2002-2004 PADwin 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PAD_H__ -#define __PAD_H__ - -#include "PadSSSPSXres.h" - -typedef __int8 s8; -typedef __int16 s16; -typedef __int32 s32; -typedef __int64 s64; - -typedef unsigned __int8 u8; -typedef unsigned __int16 u16; -typedef unsigned __int32 u32; -typedef unsigned __int64 u64; - -typedef struct -{ - u32 key; - u32 event; -} keyEvent; - -typedef struct -{ - u32 keys[2][21]; -} Config; - -#endif +/* PADwin + * Copyright (C) 2002-2004 PADwin 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PAD_H__ +#define __PAD_H__ + +#include "PadSSSPSXres.h" + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +typedef struct +{ + u32 key; + u32 event; +} keyEvent; + +typedef struct +{ + u32 keys[2][21]; +} Config; + +#endif diff --git a/plugins/SSSPSXPAD/PadSSSPSXres.h b/plugins/SSSPSXPAD/PadSSSPSXres.h index bcfbc8f0b2..e45dc6a1a9 100644 --- a/plugins/SSSPSXPAD/PadSSSPSXres.h +++ b/plugins/SSSPSXPAD/PadSSSPSXres.h @@ -1,59 +1,59 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by PadSSSPSX.rc -// -#define IDD_DIALOG1 100 -#define IDC_BSELECT 1000 -#define IDC_BL3 1001 -#define IDC_BR3 1002 -#define IDC_BSTART 1003 -#define IDC_BUP 1004 -#define IDC_BRIGHT 1005 -#define IDC_BDOWN 1006 -#define IDC_BLEFT 1007 -#define IDC_BL2 1008 -#define IDC_BR2 1009 -#define IDC_BL1 1010 -#define IDC_BR1 1011 -#define IDC_BTRIANGLE 1012 -#define IDC_BCIRCLE 1013 -#define IDC_BCROSS 1014 -#define IDC_BSQUARE 1015 -#define IDC_BMODE 1016 -#define IDC_BLAX 1017 -#define IDC_BLAY 1018 -#define IDC_BRAX 1019 -#define IDC_BRAY 1020 -#define IDC_ESELECT 1030 -#define IDC_EL3 1031 -#define IDC_ER3 1032 -#define IDC_ESTART 1033 -#define IDC_EUP 1034 -#define IDC_ERIGHT 1035 -#define IDC_EDOWN 1036 -#define IDC_ELEFT 1037 -#define IDC_EL2 1038 -#define IDC_ER2 1039 -#define IDC_EL1 1040 -#define IDC_ER1 1041 -#define IDC_ETRIANGLE 1042 -#define IDC_ECIRCLE 1043 -#define IDC_ECROSS 1044 -#define IDC_ESQUARE 1045 -#define IDC_EMODE 1046 -#define IDC_ELAX 1047 -#define IDC_ELAY 1048 -#define IDC_ERAX 1049 -#define IDC_ERAY 1050 -#define IDC_TABC 1060 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1061 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by PadSSSPSX.rc +// +#define IDD_DIALOG1 100 +#define IDC_BSELECT 1000 +#define IDC_BL3 1001 +#define IDC_BR3 1002 +#define IDC_BSTART 1003 +#define IDC_BUP 1004 +#define IDC_BRIGHT 1005 +#define IDC_BDOWN 1006 +#define IDC_BLEFT 1007 +#define IDC_BL2 1008 +#define IDC_BR2 1009 +#define IDC_BL1 1010 +#define IDC_BR1 1011 +#define IDC_BTRIANGLE 1012 +#define IDC_BCIRCLE 1013 +#define IDC_BCROSS 1014 +#define IDC_BSQUARE 1015 +#define IDC_BMODE 1016 +#define IDC_BLAX 1017 +#define IDC_BLAY 1018 +#define IDC_BRAX 1019 +#define IDC_BRAY 1020 +#define IDC_ESELECT 1030 +#define IDC_EL3 1031 +#define IDC_ER3 1032 +#define IDC_ESTART 1033 +#define IDC_EUP 1034 +#define IDC_ERIGHT 1035 +#define IDC_EDOWN 1036 +#define IDC_ELEFT 1037 +#define IDC_EL2 1038 +#define IDC_ER2 1039 +#define IDC_EL1 1040 +#define IDC_ER1 1041 +#define IDC_ETRIANGLE 1042 +#define IDC_ECIRCLE 1043 +#define IDC_ECROSS 1044 +#define IDC_ESQUARE 1045 +#define IDC_EMODE 1046 +#define IDC_ELAX 1047 +#define IDC_ELAY 1048 +#define IDC_ERAX 1049 +#define IDC_ERAY 1050 +#define IDC_TABC 1060 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1061 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/USBnull/Linux/Config.c b/plugins/USBnull/Linux/Config.c index c4abd824fc..7c6833f54b 100644 --- a/plugins/USBnull/Linux/Config.c +++ b/plugins/USBnull/Linux/Config.c @@ -1,59 +1,59 @@ -/* USBnull - * Copyright (C) 2002-2004 USBnull 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include - -#include "USB.h" - -void LoadConfig() { -/* FILE *f; - char cfg[256]; - - sprintf(cfg, "%s/.PS2E/CDVDiso.cfg", getenv("HOME")); - f = fopen(cfg, "r"); - if (f == NULL) { - strcpy(IsoFile, DEV_DEF); - strcpy(CdDev, CDDEV_DEF); - return; - } - fscanf(f, "IsoFile = %[^\n]\n", IsoFile); - fscanf(f, "CdDev = %[^\n]\n", CdDev); - if (!strncmp(IsoFile, "CdDev =", 9)) *IsoFile = 0; // quick fix - if (*CdDev == 0) strcpy(CdDev, CDDEV_DEF); - fclose(f);*/ -} - -void SaveConfig() { -/* FILE *f; - char cfg[256]; - - sprintf(cfg, "%s/.PS2E", getenv("HOME")); - mkdir(cfg, 0755); - sprintf(cfg, "%s/.PS2E/CDVDiso.cfg", getenv("HOME")); - f = fopen(cfg, "w"); - if (f == NULL) - return; - fprintf(f, "IsoFile = %s\n", IsoFile); - fprintf(f, "CdDev = %s\n", CdDev); - fclose(f);*/ -} - +/* USBnull + * Copyright (C) 2002-2004 USBnull 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include "USB.h" + +void LoadConfig() { +/* FILE *f; + char cfg[256]; + + sprintf(cfg, "%s/.PS2E/CDVDiso.cfg", getenv("HOME")); + f = fopen(cfg, "r"); + if (f == NULL) { + strcpy(IsoFile, DEV_DEF); + strcpy(CdDev, CDDEV_DEF); + return; + } + fscanf(f, "IsoFile = %[^\n]\n", IsoFile); + fscanf(f, "CdDev = %[^\n]\n", CdDev); + if (!strncmp(IsoFile, "CdDev =", 9)) *IsoFile = 0; // quick fix + if (*CdDev == 0) strcpy(CdDev, CDDEV_DEF); + fclose(f);*/ +} + +void SaveConfig() { +/* FILE *f; + char cfg[256]; + + sprintf(cfg, "%s/.PS2E", getenv("HOME")); + mkdir(cfg, 0755); + sprintf(cfg, "%s/.PS2E/CDVDiso.cfg", getenv("HOME")); + f = fopen(cfg, "w"); + if (f == NULL) + return; + fprintf(f, "IsoFile = %s\n", IsoFile); + fprintf(f, "CdDev = %s\n", CdDev); + fclose(f);*/ +} + diff --git a/plugins/USBnull/Linux/Config.h b/plugins/USBnull/Linux/Config.h index 8382b720c5..1dcda4ffc6 100644 --- a/plugins/USBnull/Linux/Config.h +++ b/plugins/USBnull/Linux/Config.h @@ -1,20 +1,20 @@ -/* USBnull - * Copyright (C) 2002-2004 USBnull 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -void SaveConfig(); -void LoadConfig(); +/* USBnull + * Copyright (C) 2002-2004 USBnull 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +void SaveConfig(); +void LoadConfig(); diff --git a/plugins/USBnull/Linux/Linux.c b/plugins/USBnull/Linux/Linux.c index 1a07ba1500..d1587aa413 100644 --- a/plugins/USBnull/Linux/Linux.c +++ b/plugins/USBnull/Linux/Linux.c @@ -1,74 +1,74 @@ -/* USBnull - * Copyright (C) 2002-2004 USBnull 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include - - -int ExecCfg(char *arg) { - char cfg[256]; - struct stat buf; - - strcpy(cfg, "./cfgUSBnull"); - if (stat(cfg, &buf) != -1) { - sprintf(cfg, "%s %s", cfg, arg); - return system(cfg); - } - - strcpy(cfg, "./cfg/cfgUSBnull"); - if (stat(cfg, &buf) != -1) { - sprintf(cfg, "%s %s", cfg, arg); - return system(cfg); - } - - sprintf(cfg, "%s/cfgUSBnull", getenv("HOME")); - if (stat(cfg, &buf) != -1) { - sprintf(cfg, "%s %s", cfg, arg); - return system(cfg); - } - - printf("cfgUSBnull file not found!\n"); - return -1; -} - -void SysMessage(char *fmt, ...) { - va_list list; - char msg[512]; - char cmd[512]; - - va_start(list, fmt); - vsprintf(msg, fmt, list); - va_end(list); - - sprintf(cmd, "message \"%s\"", msg); - ExecCfg(cmd); -} - -void USBconfigure() { - ExecCfg("configure"); -} - -void USBabout() { - ExecCfg("about"); -} - +/* USBnull + * Copyright (C) 2002-2004 USBnull 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + + +int ExecCfg(char *arg) { + char cfg[256]; + struct stat buf; + + strcpy(cfg, "./cfgUSBnull"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + strcpy(cfg, "./cfg/cfgUSBnull"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + sprintf(cfg, "%s/cfgUSBnull", getenv("HOME")); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + return system(cfg); + } + + printf("cfgUSBnull file not found!\n"); + return -1; +} + +void SysMessage(char *fmt, ...) { + va_list list; + char msg[512]; + char cmd[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + sprintf(cmd, "message \"%s\"", msg); + ExecCfg(cmd); +} + +void USBconfigure() { + ExecCfg("configure"); +} + +void USBabout() { + ExecCfg("about"); +} + diff --git a/plugins/USBnull/Linux/Makefile b/plugins/USBnull/Linux/Makefile index bcf7a489a3..f8ac680595 100644 --- a/plugins/USBnull/Linux/Makefile +++ b/plugins/USBnull/Linux/Makefile @@ -1,35 +1,35 @@ - -PLUGIN = libUSBnull.so -CFG = cfgUSBnull -CFLAGS+= -fPIC -Wall -I. -I.. -O3 -fomit-frame-pointer -fno-strict-aliasing -OBJS = ../USB.o -OBJS+= Config.o Linux.o -CFGOBJS = conf.o interface.o support.o -DEPS:= $(OBJS:.o=.d) -CFGDEPS:= $(CFGOBJS:.o=.d) -LIBS = -lpthread -CFLAGS+= $(shell pkg-config --cflags gtk+-2.0) -D__LINUX__ -CFGLIBS = $(shell pkg-config --libs gtk+-2.0) - -CC = gcc - -all: plugin cfg -install: all - -plugin: ${OBJS} -# rm -f ${PLUGIN} - ${CC} -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} - strip --strip-unneeded --strip-debug ${PLUGIN} - -cfg: ${CFGOBJS} -# rm -f ${CFG} - ${CC} ${CFLAGS} ${CFGOBJS} -o ${CFG} ${CFGLIBS} - strip ${CFG} - -clean: - rm -f ${OBJS} ${CFGOBJS} ${CFGDEPS} ${PLUGIN} ${CFG} - -%.o: %.c - ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) - -#-include ${DEPS} + +PLUGIN = libUSBnull.so +CFG = cfgUSBnull +CFLAGS+= -fPIC -Wall -I. -I.. -O3 -fomit-frame-pointer -fno-strict-aliasing +OBJS = ../USB.o +OBJS+= Config.o Linux.o +CFGOBJS = conf.o interface.o support.o +DEPS:= $(OBJS:.o=.d) +CFGDEPS:= $(CFGOBJS:.o=.d) +LIBS = -lpthread +CFLAGS+= $(shell pkg-config --cflags gtk+-2.0) -D__LINUX__ +CFGLIBS = $(shell pkg-config --libs gtk+-2.0) + +CC = gcc + +all: plugin cfg +install: all + +plugin: ${OBJS} +# rm -f ${PLUGIN} + ${CC} -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + strip --strip-unneeded --strip-debug ${PLUGIN} + +cfg: ${CFGOBJS} +# rm -f ${CFG} + ${CC} ${CFLAGS} ${CFGOBJS} -o ${CFG} ${CFGLIBS} + strip ${CFG} + +clean: + rm -f ${OBJS} ${CFGOBJS} ${CFGDEPS} ${PLUGIN} ${CFG} + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +#-include ${DEPS} diff --git a/plugins/USBnull/Linux/callbacks.c b/plugins/USBnull/Linux/callbacks.c index fa070a7842..e87ed8be2d 100644 --- a/plugins/USBnull/Linux/callbacks.c +++ b/plugins/USBnull/Linux/callbacks.c @@ -1,34 +1,34 @@ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include "callbacks.h" -#include "interface.h" -#include "support.h" - - -void -OnConf_Ok (GtkButton *button, - gpointer user_data) -{ - -} - - -void -OnConf_Cancel (GtkButton *button, - gpointer user_data) -{ - -} - - -void -OnAbout_Ok (GtkButton *button, - gpointer user_data) -{ - -} - +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data) +{ + +} + diff --git a/plugins/USBnull/Linux/callbacks.h b/plugins/USBnull/Linux/callbacks.h index 22cf74a988..e606c242f0 100644 --- a/plugins/USBnull/Linux/callbacks.h +++ b/plugins/USBnull/Linux/callbacks.h @@ -1,14 +1,14 @@ -#include - - -void -OnConf_Ok (GtkButton *button, - gpointer user_data); - -void -OnConf_Cancel (GtkButton *button, - gpointer user_data); - -void -OnAbout_Ok (GtkButton *button, - gpointer user_data); +#include + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data); + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data); + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data); diff --git a/plugins/USBnull/Linux/conf.c b/plugins/USBnull/Linux/conf.c index 74d444b96e..e0018e9753 100644 --- a/plugins/USBnull/Linux/conf.c +++ b/plugins/USBnull/Linux/conf.c @@ -1,128 +1,128 @@ -/* USBnull - * Copyright (C) 2002-2004 USBnull 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include - -#include "interface.h" -#include "support.h" -#include "callbacks.h" - -GtkWidget *MsgDlg; - -void OnMsg_Ok() { - gtk_widget_destroy(MsgDlg); - gtk_main_quit(); -} - -void cfgSysMessage(char *fmt, ...) { - GtkWidget *Ok,*Txt; - GtkWidget *Box,*Box1; - va_list list; - char msg[512]; - - va_start(list, fmt); - vsprintf(msg, fmt, list); - va_end(list); - - if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; - - MsgDlg = gtk_window_new (GTK_WINDOW_POPUP); - gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); - gtk_window_set_title(GTK_WINDOW(MsgDlg), "USBnull Msg"); - gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); - - Box = gtk_vbox_new(5, 0); - gtk_container_add(GTK_CONTAINER(MsgDlg), Box); - gtk_widget_show(Box); - - Txt = gtk_label_new(msg); - - gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); - gtk_widget_show(Txt); - - Box1 = gtk_hbutton_box_new(); - gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); - gtk_widget_show(Box1); - - Ok = gtk_button_new_with_label("Ok"); - gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); - gtk_container_add(GTK_CONTAINER(Box1), Ok); - GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); - gtk_widget_show(Ok); - - gtk_widget_show(MsgDlg); - - gtk_main(); -} - -GtkWidget *About; - -void OnAbout_Ok(GtkButton *button, gpointer user_data) { - gtk_widget_destroy(About); - gtk_main_quit(); -} - -void CFGabout() { - About = create_About(); - gtk_widget_show_all(About); - gtk_main(); -} - -GtkWidget *Conf; - -void OnConf_Ok(GtkButton *button, gpointer user_data) { - gtk_widget_destroy(Conf); - gtk_main_quit(); -} - -void OnConf_Cancel(GtkButton *button, gpointer user_data) { - gtk_widget_destroy(Conf); - gtk_main_quit(); -} - -void CFGconfigure() { - Conf = create_Config(); - - gtk_widget_show_all(Conf); - gtk_main(); -} - -long CFGmessage(char *msg) { - cfgSysMessage(msg); - - return 0; -} - -int main(int argc, char *argv[]) { - gtk_init(NULL, NULL); - - if (!strcmp(argv[1], "configure")) { - CFGconfigure(); - } else if (!strcmp(argv[1], "about")) { - CFGabout(); - } else if (!strcmp(argv[1], "message")) { - CFGmessage(argv[2]); - } - - return 0; -} +/* USBnull + * Copyright (C) 2002-2004 USBnull 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +#include "interface.h" +#include "support.h" +#include "callbacks.h" + +GtkWidget *MsgDlg; + +void OnMsg_Ok() { + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + +void cfgSysMessage(char *fmt, ...) { + GtkWidget *Ok,*Txt; + GtkWidget *Box,*Box1; + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + MsgDlg = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "USBnull Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); + + Box = gtk_vbox_new(5, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main(); +} + +GtkWidget *About; + +void OnAbout_Ok(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(About); + gtk_main_quit(); +} + +void CFGabout() { + About = create_About(); + gtk_widget_show_all(About); + gtk_main(); +} + +GtkWidget *Conf; + +void OnConf_Ok(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void OnConf_Cancel(GtkButton *button, gpointer user_data) { + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void CFGconfigure() { + Conf = create_Config(); + + gtk_widget_show_all(Conf); + gtk_main(); +} + +long CFGmessage(char *msg) { + cfgSysMessage(msg); + + return 0; +} + +int main(int argc, char *argv[]) { + gtk_init(NULL, NULL); + + if (!strcmp(argv[1], "configure")) { + CFGconfigure(); + } else if (!strcmp(argv[1], "about")) { + CFGabout(); + } else if (!strcmp(argv[1], "message")) { + CFGmessage(argv[2]); + } + + return 0; +} diff --git a/plugins/USBnull/Linux/interface.c b/plugins/USBnull/Linux/interface.c index a73c0861ed..10dcc15912 100644 --- a/plugins/USBnull/Linux/interface.c +++ b/plugins/USBnull/Linux/interface.c @@ -1,219 +1,219 @@ -/* - * DO NOT EDIT THIS FILE - it is generated by Glade. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include - -#include -#include - -#include "callbacks.h" -#include "interface.h" -#include "support.h" - -GtkWidget* -create_Config (void) -{ - GtkWidget *Config; - GtkWidget *vbox1; - GtkWidget *frame2; - GtkWidget *hbox1; - GtkWidget *label4; - GtkWidget *GtkCombo_Eth; - GtkWidget *combo_entry1; - GtkWidget *frame3; - GtkWidget *hbox2; - GtkWidget *label5; - GtkWidget *GtkCombo_Hdd; - GtkWidget *entry1; - GtkWidget *hbuttonbox1; - GtkWidget *button1; - GtkWidget *button2; - - Config = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_object_set_data (GTK_OBJECT (Config), "Config", Config); - gtk_container_set_border_width (GTK_CONTAINER (Config), 5); - gtk_window_set_title (GTK_WINDOW (Config), "DEV9config"); - gtk_window_set_position (GTK_WINDOW (Config), GTK_WIN_POS_CENTER); - - vbox1 = gtk_vbox_new (FALSE, 5); - gtk_widget_ref (vbox1); - gtk_object_set_data_full (GTK_OBJECT (Config), "vbox1", vbox1, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox1); - gtk_container_add (GTK_CONTAINER (Config), vbox1); - gtk_container_set_border_width (GTK_CONTAINER (vbox1), 5); - - frame2 = gtk_frame_new ("Ethernet"); - gtk_widget_ref (frame2); - gtk_object_set_data_full (GTK_OBJECT (Config), "frame2", frame2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (frame2); - gtk_box_pack_start (GTK_BOX (vbox1), frame2, TRUE, TRUE, 0); - - hbox1 = gtk_hbox_new (TRUE, 5); - gtk_widget_ref (hbox1); - gtk_object_set_data_full (GTK_OBJECT (Config), "hbox1", hbox1, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbox1); - gtk_container_add (GTK_CONTAINER (frame2), hbox1); - gtk_container_set_border_width (GTK_CONTAINER (hbox1), 5); - - label4 = gtk_label_new ("Device:"); - gtk_widget_ref (label4); - gtk_object_set_data_full (GTK_OBJECT (Config), "label4", label4, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label4); - gtk_box_pack_start (GTK_BOX (hbox1), label4, FALSE, FALSE, 0); - - GtkCombo_Eth = gtk_combo_new (); - gtk_widget_ref (GtkCombo_Eth); - gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Eth", GtkCombo_Eth, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (GtkCombo_Eth); - gtk_box_pack_start (GTK_BOX (hbox1), GtkCombo_Eth, FALSE, FALSE, 0); - gtk_widget_set_usize (GtkCombo_Eth, 130, -2); - - combo_entry1 = GTK_COMBO (GtkCombo_Eth)->entry; - gtk_widget_ref (combo_entry1); - gtk_object_set_data_full (GTK_OBJECT (Config), "combo_entry1", combo_entry1, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (combo_entry1); - - frame3 = gtk_frame_new ("Hdd"); - gtk_widget_ref (frame3); - gtk_object_set_data_full (GTK_OBJECT (Config), "frame3", frame3, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (frame3); - gtk_box_pack_start (GTK_BOX (vbox1), frame3, TRUE, TRUE, 0); - - hbox2 = gtk_hbox_new (TRUE, 5); - gtk_widget_ref (hbox2); - gtk_object_set_data_full (GTK_OBJECT (Config), "hbox2", hbox2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbox2); - gtk_container_add (GTK_CONTAINER (frame3), hbox2); - gtk_container_set_border_width (GTK_CONTAINER (hbox2), 5); - - label5 = gtk_label_new ("Device:"); - gtk_widget_ref (label5); - gtk_object_set_data_full (GTK_OBJECT (Config), "label5", label5, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label5); - gtk_box_pack_start (GTK_BOX (hbox2), label5, FALSE, FALSE, 0); - - GtkCombo_Hdd = gtk_combo_new (); - gtk_widget_ref (GtkCombo_Hdd); - gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Hdd", GtkCombo_Hdd, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (GtkCombo_Hdd); - gtk_box_pack_start (GTK_BOX (hbox2), GtkCombo_Hdd, FALSE, FALSE, 0); - gtk_widget_set_usize (GtkCombo_Hdd, 130, -2); - - entry1 = GTK_COMBO (GtkCombo_Hdd)->entry; - gtk_widget_ref (entry1); - gtk_object_set_data_full (GTK_OBJECT (Config), "entry1", entry1, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (entry1); - - hbuttonbox1 = gtk_hbutton_box_new (); - gtk_widget_ref (hbuttonbox1); - gtk_object_set_data_full (GTK_OBJECT (Config), "hbuttonbox1", hbuttonbox1, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbuttonbox1); - gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox1, TRUE, TRUE, 0); - - button1 = gtk_button_new_with_label ("Ok"); - gtk_widget_ref (button1); - gtk_object_set_data_full (GTK_OBJECT (Config), "button1", button1, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (button1); - gtk_container_add (GTK_CONTAINER (hbuttonbox1), button1); - GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT); - - button2 = gtk_button_new_with_label ("Cancel"); - gtk_widget_ref (button2); - gtk_object_set_data_full (GTK_OBJECT (Config), "button2", button2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (button2); - gtk_container_add (GTK_CONTAINER (hbuttonbox1), button2); - GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT); - - gtk_signal_connect (GTK_OBJECT (button1), "clicked", - GTK_SIGNAL_FUNC (OnConf_Ok), - NULL); - gtk_signal_connect (GTK_OBJECT (button2), "clicked", - GTK_SIGNAL_FUNC (OnConf_Cancel), - NULL); - - return Config; -} - -GtkWidget* -create_About (void) -{ - GtkWidget *About; - GtkWidget *vbox2; - GtkWidget *label2; - GtkWidget *label3; - GtkWidget *hbuttonbox2; - GtkWidget *button3; - - About = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_object_set_data (GTK_OBJECT (About), "About", About); - gtk_container_set_border_width (GTK_CONTAINER (About), 5); - gtk_window_set_title (GTK_WINDOW (About), "DEV9about"); - gtk_window_set_position (GTK_WINDOW (About), GTK_WIN_POS_CENTER); - - vbox2 = gtk_vbox_new (FALSE, 5); - gtk_widget_ref (vbox2); - gtk_object_set_data_full (GTK_OBJECT (About), "vbox2", vbox2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (vbox2); - gtk_container_add (GTK_CONTAINER (About), vbox2); - gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); - - label2 = gtk_label_new ("DEV9linuz Driver"); - gtk_widget_ref (label2); - gtk_object_set_data_full (GTK_OBJECT (About), "label2", label2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label2); - gtk_box_pack_start (GTK_BOX (vbox2), label2, FALSE, FALSE, 0); - - label3 = gtk_label_new ("Author: linuzappz "); - gtk_widget_ref (label3); - gtk_object_set_data_full (GTK_OBJECT (About), "label3", label3, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (label3); - gtk_box_pack_start (GTK_BOX (vbox2), label3, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (label3), GTK_JUSTIFY_LEFT); - - hbuttonbox2 = gtk_hbutton_box_new (); - gtk_widget_ref (hbuttonbox2); - gtk_object_set_data_full (GTK_OBJECT (About), "hbuttonbox2", hbuttonbox2, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (hbuttonbox2); - gtk_box_pack_start (GTK_BOX (vbox2), hbuttonbox2, TRUE, TRUE, 0); - - button3 = gtk_button_new_with_label ("Ok"); - gtk_widget_ref (button3); - gtk_object_set_data_full (GTK_OBJECT (About), "button3", button3, - (GtkDestroyNotify) gtk_widget_unref); - gtk_widget_show (button3); - gtk_container_add (GTK_CONTAINER (hbuttonbox2), button3); - GTK_WIDGET_SET_FLAGS (button3, GTK_CAN_DEFAULT); - - gtk_signal_connect (GTK_OBJECT (button3), "clicked", - GTK_SIGNAL_FUNC (OnAbout_Ok), - NULL); - - return About; -} - +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +GtkWidget* +create_Config (void) +{ + GtkWidget *Config; + GtkWidget *vbox1; + GtkWidget *frame2; + GtkWidget *hbox1; + GtkWidget *label4; + GtkWidget *GtkCombo_Eth; + GtkWidget *combo_entry1; + GtkWidget *frame3; + GtkWidget *hbox2; + GtkWidget *label5; + GtkWidget *GtkCombo_Hdd; + GtkWidget *entry1; + GtkWidget *hbuttonbox1; + GtkWidget *button1; + GtkWidget *button2; + + Config = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (Config), "Config", Config); + gtk_container_set_border_width (GTK_CONTAINER (Config), 5); + gtk_window_set_title (GTK_WINDOW (Config), "DEV9config"); + gtk_window_set_position (GTK_WINDOW (Config), GTK_WIN_POS_CENTER); + + vbox1 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "vbox1", vbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox1); + gtk_container_add (GTK_CONTAINER (Config), vbox1); + gtk_container_set_border_width (GTK_CONTAINER (vbox1), 5); + + frame2 = gtk_frame_new ("Ethernet"); + gtk_widget_ref (frame2); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame2", frame2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame2); + gtk_box_pack_start (GTK_BOX (vbox1), frame2, TRUE, TRUE, 0); + + hbox1 = gtk_hbox_new (TRUE, 5); + gtk_widget_ref (hbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox1", hbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox1); + gtk_container_add (GTK_CONTAINER (frame2), hbox1); + gtk_container_set_border_width (GTK_CONTAINER (hbox1), 5); + + label4 = gtk_label_new ("Device:"); + gtk_widget_ref (label4); + gtk_object_set_data_full (GTK_OBJECT (Config), "label4", label4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label4); + gtk_box_pack_start (GTK_BOX (hbox1), label4, FALSE, FALSE, 0); + + GtkCombo_Eth = gtk_combo_new (); + gtk_widget_ref (GtkCombo_Eth); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Eth", GtkCombo_Eth, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_Eth); + gtk_box_pack_start (GTK_BOX (hbox1), GtkCombo_Eth, FALSE, FALSE, 0); + gtk_widget_set_usize (GtkCombo_Eth, 130, -2); + + combo_entry1 = GTK_COMBO (GtkCombo_Eth)->entry; + gtk_widget_ref (combo_entry1); + gtk_object_set_data_full (GTK_OBJECT (Config), "combo_entry1", combo_entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo_entry1); + + frame3 = gtk_frame_new ("Hdd"); + gtk_widget_ref (frame3); + gtk_object_set_data_full (GTK_OBJECT (Config), "frame3", frame3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame3); + gtk_box_pack_start (GTK_BOX (vbox1), frame3, TRUE, TRUE, 0); + + hbox2 = gtk_hbox_new (TRUE, 5); + gtk_widget_ref (hbox2); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbox2", hbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox2); + gtk_container_add (GTK_CONTAINER (frame3), hbox2); + gtk_container_set_border_width (GTK_CONTAINER (hbox2), 5); + + label5 = gtk_label_new ("Device:"); + gtk_widget_ref (label5); + gtk_object_set_data_full (GTK_OBJECT (Config), "label5", label5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label5); + gtk_box_pack_start (GTK_BOX (hbox2), label5, FALSE, FALSE, 0); + + GtkCombo_Hdd = gtk_combo_new (); + gtk_widget_ref (GtkCombo_Hdd); + gtk_object_set_data_full (GTK_OBJECT (Config), "GtkCombo_Hdd", GtkCombo_Hdd, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (GtkCombo_Hdd); + gtk_box_pack_start (GTK_BOX (hbox2), GtkCombo_Hdd, FALSE, FALSE, 0); + gtk_widget_set_usize (GtkCombo_Hdd, 130, -2); + + entry1 = GTK_COMBO (GtkCombo_Hdd)->entry; + gtk_widget_ref (entry1); + gtk_object_set_data_full (GTK_OBJECT (Config), "entry1", entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (entry1); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox1); + gtk_object_set_data_full (GTK_OBJECT (Config), "hbuttonbox1", hbuttonbox1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox1); + gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox1, TRUE, TRUE, 0); + + button1 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button1); + gtk_object_set_data_full (GTK_OBJECT (Config), "button1", button1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button1); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button1); + GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT); + + button2 = gtk_button_new_with_label ("Cancel"); + gtk_widget_ref (button2); + gtk_object_set_data_full (GTK_OBJECT (Config), "button2", button2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button2); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button2); + GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (button1), "clicked", + GTK_SIGNAL_FUNC (OnConf_Ok), + NULL); + gtk_signal_connect (GTK_OBJECT (button2), "clicked", + GTK_SIGNAL_FUNC (OnConf_Cancel), + NULL); + + return Config; +} + +GtkWidget* +create_About (void) +{ + GtkWidget *About; + GtkWidget *vbox2; + GtkWidget *label2; + GtkWidget *label3; + GtkWidget *hbuttonbox2; + GtkWidget *button3; + + About = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (About), "About", About); + gtk_container_set_border_width (GTK_CONTAINER (About), 5); + gtk_window_set_title (GTK_WINDOW (About), "DEV9about"); + gtk_window_set_position (GTK_WINDOW (About), GTK_WIN_POS_CENTER); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox2); + gtk_object_set_data_full (GTK_OBJECT (About), "vbox2", vbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (About), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + label2 = gtk_label_new ("DEV9linuz Driver"); + gtk_widget_ref (label2); + gtk_object_set_data_full (GTK_OBJECT (About), "label2", label2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label2); + gtk_box_pack_start (GTK_BOX (vbox2), label2, FALSE, FALSE, 0); + + label3 = gtk_label_new ("Author: linuzappz "); + gtk_widget_ref (label3); + gtk_object_set_data_full (GTK_OBJECT (About), "label3", label3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label3); + gtk_box_pack_start (GTK_BOX (vbox2), label3, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label3), GTK_JUSTIFY_LEFT); + + hbuttonbox2 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox2); + gtk_object_set_data_full (GTK_OBJECT (About), "hbuttonbox2", hbuttonbox2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox2); + gtk_box_pack_start (GTK_BOX (vbox2), hbuttonbox2, TRUE, TRUE, 0); + + button3 = gtk_button_new_with_label ("Ok"); + gtk_widget_ref (button3); + gtk_object_set_data_full (GTK_OBJECT (About), "button3", button3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button3); + gtk_container_add (GTK_CONTAINER (hbuttonbox2), button3); + GTK_WIDGET_SET_FLAGS (button3, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (button3), "clicked", + GTK_SIGNAL_FUNC (OnAbout_Ok), + NULL); + + return About; +} + diff --git a/plugins/USBnull/Linux/interface.h b/plugins/USBnull/Linux/interface.h index ab0cb1a886..69c303ba3b 100644 --- a/plugins/USBnull/Linux/interface.h +++ b/plugins/USBnull/Linux/interface.h @@ -1,6 +1,6 @@ -/* - * DO NOT EDIT THIS FILE - it is generated by Glade. - */ - -GtkWidget* create_Config (void); -GtkWidget* create_About (void); +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_Config (void); +GtkWidget* create_About (void); diff --git a/plugins/USBnull/Linux/support.c b/plugins/USBnull/Linux/support.c index b053ba6f6d..65007c9217 100644 --- a/plugins/USBnull/Linux/support.c +++ b/plugins/USBnull/Linux/support.c @@ -1,162 +1,162 @@ -/* - * DO NOT EDIT THIS FILE - it is generated by Glade. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include - -#include - -#include "support.h" - -/* This is an internally used function to check if a pixmap file exists. */ -static gchar* check_file_exists (const gchar *directory, - const gchar *filename); - -/* This is an internally used function to create pixmaps. */ -static GtkWidget* create_dummy_pixmap (GtkWidget *widget); - -GtkWidget* -lookup_widget (GtkWidget *widget, - const gchar *widget_name) -{ - GtkWidget *parent, *found_widget; - - for (;;) - { - if (GTK_IS_MENU (widget)) - parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); - else - parent = widget->parent; - if (parent == NULL) - break; - widget = parent; - } - - found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget), - widget_name); - if (!found_widget) - g_warning ("Widget not found: %s", widget_name); - return found_widget; -} - -/* This is a dummy pixmap we use when a pixmap can't be found. */ -static char *dummy_pixmap_xpm[] = { -/* columns rows colors chars-per-pixel */ -"1 1 1 1", -" c None", -/* pixels */ -" " -}; - -/* This is an internally used function to create pixmaps. */ -static GtkWidget* -create_dummy_pixmap (GtkWidget *widget) -{ - GdkColormap *colormap; - GdkPixmap *gdkpixmap; - GdkBitmap *mask; - GtkWidget *pixmap; - - colormap = gtk_widget_get_colormap (widget); - gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, - NULL, dummy_pixmap_xpm); - if (gdkpixmap == NULL) - g_error ("Couldn't create replacement pixmap."); - pixmap = gtk_pixmap_new (gdkpixmap, mask); - gdk_pixmap_unref (gdkpixmap); - gdk_bitmap_unref (mask); - return pixmap; -} - -static GList *pixmaps_directories = NULL; - -/* Use this function to set the directory containing installed pixmaps. */ -void -add_pixmap_directory (const gchar *directory) -{ - pixmaps_directories = g_list_prepend (pixmaps_directories, - g_strdup (directory)); -} - -/* This is an internally used function to create pixmaps. */ -GtkWidget* -create_pixmap (GtkWidget *widget, - const gchar *filename) -{ - gchar *found_filename = NULL; - GdkColormap *colormap; - GdkPixmap *gdkpixmap; - GdkBitmap *mask; - GtkWidget *pixmap; - GList *elem; - - if (!filename || !filename[0]) - return create_dummy_pixmap (widget); - - /* We first try any pixmaps directories set by the application. */ - elem = pixmaps_directories; - while (elem) - { - found_filename = check_file_exists ((gchar*)elem->data, filename); - if (found_filename) - break; - elem = elem->next; - } - - /* If we haven't found the pixmap, try the source directory. */ - if (!found_filename) - { - found_filename = check_file_exists ("pixmaps", filename); - } - - if (!found_filename) - { - g_warning ("Couldn't find pixmap file: %s", filename); - return create_dummy_pixmap (widget); - } - - colormap = gtk_widget_get_colormap (widget); - gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask, - NULL, found_filename); - if (gdkpixmap == NULL) - { - g_warning ("Error loading pixmap file: %s", found_filename); - g_free (found_filename); - return create_dummy_pixmap (widget); - } - g_free (found_filename); - pixmap = gtk_pixmap_new (gdkpixmap, mask); - gdk_pixmap_unref (gdkpixmap); - gdk_bitmap_unref (mask); - return pixmap; -} - -/* This is an internally used function to check if a pixmap file exists. */ -static gchar* -check_file_exists (const gchar *directory, - const gchar *filename) -{ - gchar *full_filename; - struct stat s; - gint status; - - full_filename = (gchar*) g_malloc (strlen (directory) + 1 - + strlen (filename) + 1); - strcpy (full_filename, directory); - strcat (full_filename, G_DIR_SEPARATOR_S); - strcat (full_filename, filename); - - status = stat (full_filename, &s); - if (status == 0 && S_ISREG (s.st_mode)) - return full_filename; - g_free (full_filename); - return NULL; -} - +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include + +#include "support.h" + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* check_file_exists (const gchar *directory, + const gchar *filename); + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* create_dummy_pixmap (GtkWidget *widget); + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +/* This is a dummy pixmap we use when a pixmap can't be found. */ +static char *dummy_pixmap_xpm[] = { +/* columns rows colors chars-per-pixel */ +"1 1 1 1", +" c None", +/* pixels */ +" " +}; + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* +create_dummy_pixmap (GtkWidget *widget) +{ + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, + NULL, dummy_pixmap_xpm); + if (gdkpixmap == NULL) + g_error ("Couldn't create replacement pixmap."); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *found_filename = NULL; + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + GList *elem; + + if (!filename || !filename[0]) + return create_dummy_pixmap (widget); + + /* We first try any pixmaps directories set by the application. */ + elem = pixmaps_directories; + while (elem) + { + found_filename = check_file_exists ((gchar*)elem->data, filename); + if (found_filename) + break; + elem = elem->next; + } + + /* If we haven't found the pixmap, try the source directory. */ + if (!found_filename) + { + found_filename = check_file_exists ("pixmaps", filename); + } + + if (!found_filename) + { + g_warning ("Couldn't find pixmap file: %s", filename); + return create_dummy_pixmap (widget); + } + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask, + NULL, found_filename); + if (gdkpixmap == NULL) + { + g_warning ("Error loading pixmap file: %s", found_filename); + g_free (found_filename); + return create_dummy_pixmap (widget); + } + g_free (found_filename); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* +check_file_exists (const gchar *directory, + const gchar *filename) +{ + gchar *full_filename; + struct stat s; + gint status; + + full_filename = (gchar*) g_malloc (strlen (directory) + 1 + + strlen (filename) + 1); + strcpy (full_filename, directory); + strcat (full_filename, G_DIR_SEPARATOR_S); + strcat (full_filename, filename); + + status = stat (full_filename, &s); + if (status == 0 && S_ISREG (s.st_mode)) + return full_filename; + g_free (full_filename); + return NULL; +} + diff --git a/plugins/USBnull/Linux/support.h b/plugins/USBnull/Linux/support.h index 886615901b..aee31f935d 100644 --- a/plugins/USBnull/Linux/support.h +++ b/plugins/USBnull/Linux/support.h @@ -1,38 +1,38 @@ -/* - * DO NOT EDIT THIS FILE - it is generated by Glade. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -/* - * Public Functions. - */ - -/* - * This function returns a widget in a component created by Glade. - * Call it with the toplevel widget in the component (i.e. a window/dialog), - * or alternatively any widget in the component, and the name of the widget - * you want returned. - */ -GtkWidget* lookup_widget (GtkWidget *widget, - const gchar *widget_name); - -/* get_widget() is deprecated. Use lookup_widget instead. */ -#define get_widget lookup_widget - -/* Use this function to set the directory containing installed pixmaps. */ -void add_pixmap_directory (const gchar *directory); - - -/* - * Private Functions. - */ - -/* This is used to create the pixmaps in the interface. */ -GtkWidget* create_pixmap (GtkWidget *widget, - const gchar *filename); - +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + +/* get_widget() is deprecated. Use lookup_widget instead. */ +#define get_widget lookup_widget + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + diff --git a/plugins/USBnull/PS2Edefs.h b/plugins/USBnull/PS2Edefs.h index b2f76c96de..34bfdf54f2 100644 --- a/plugins/USBnull/PS2Edefs.h +++ b/plugins/USBnull/PS2Edefs.h @@ -1,848 +1,848 @@ -#ifndef __PS2EDEFS_H__ -#define __PS2EDEFS_H__ - -/* - * PS2E Definitions v0.6.2 (beta) - * - * Author: linuzappz@hotmail.com - * shadowpcsx2@yahoo.gr - * florinsasu@hotmail.com - */ - -/* - Notes: - * Since this is still beta things may change. - - * OSflags: - __LINUX__ (linux OS) - _WIN32 (win32 OS) - - * common return values (for ie. GSinit): - 0 - success - -1 - error - - * reserved keys: - F1 to F10 are reserved for the emulator - - * plugins should NOT change the current - working directory. - (on win32, add flag OFN_NOCHANGEDIR for - GetOpenFileName) - -*/ - -#include "PS2Etypes.h" - -#ifdef __LINUX__ -#define CALLBACK -#else -#include -#endif - - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ - defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ - defined(USBdefs) || defined(FWdefs) -#define COMMONdefs -#endif - -// PS2EgetLibType returns (may be OR'd) -#define PS2E_LT_GS 0x01 -#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- -#define PS2E_LT_SPU2 0x04 -#define PS2E_LT_CDVD 0x08 -#define PS2E_LT_DEV9 0x10 -#define PS2E_LT_USB 0x20 -#define PS2E_LT_FW 0x40 -#define PS2E_LT_SIO 0x80 - -// PS2EgetLibVersion2 (high 16 bits) -#define PS2E_GS_VERSION 0x0006 -#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- -#define PS2E_SPU2_VERSION 0x0005 -#define PS2E_CDVD_VERSION 0x0005 -#define PS2E_DEV9_VERSION 0x0003 -#define PS2E_USB_VERSION 0x0003 -#define PS2E_FW_VERSION 0x0002 -#define PS2E_SIO_VERSION 0x0001 -#ifdef COMMONdefs - -u32 CALLBACK PS2EgetLibType(void); -u32 CALLBACK PS2EgetLibVersion2(u32 type); -char* CALLBACK PS2EgetLibName(void); - -#endif - -// key values: -/* key values must be OS dependant: - win32: the VK_XXX will be used (WinUser) - linux: the XK_XXX will be used (XFree86) -*/ - -// event values: -#define KEYPRESS 1 -#define KEYRELEASE 2 - -typedef struct { - u32 key; - u32 event; -} keyEvent; - -// for 64bit compilers -typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; - -// plugin types -#define SIO_TYPE_PAD 0x00000001 -#define SIO_TYPE_MTAP 0x00000004 -#define SIO_TYPE_RM 0x00000040 -#define SIO_TYPE_MC 0x00000100 - -typedef int (CALLBACK * SIOchangeSlotCB)(int slot); - -typedef struct { - u8 ctrl:4; // control and mode bits - u8 mode:4; // control and mode bits - u8 trackNum; // current track number (1 to 99) - u8 trackIndex; // current index within track (0 to 99) - u8 trackM; // current minute location on the disc (BCD encoded) - u8 trackS; // current sector location on the disc (BCD encoded) - u8 trackF; // current frame location on the disc (BCD encoded) - u8 pad; // unused - u8 discM; // current minute offset from first track (BCD encoded) - u8 discS; // current sector offset from first track (BCD encoded) - u8 discF; // current frame offset from first track (BCD encoded) -} cdvdSubQ; - -typedef struct { // NOT bcd coded - u32 lsn; - u8 type; -} cdvdTD; - -typedef struct { - u8 strack; //number of the first track (usually 1) - u8 etrack; //number of the last track -} cdvdTN; - -// CDVDreadTrack mode values: -#define CDVD_MODE_2352 0 // full 2352 bytes -#define CDVD_MODE_2340 1 // skip sync (12) bytes -#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq - -// CDVDgetDiskType returns: -#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc -#define CDVD_TYPE_DVDV 0xfe // DVD Video -#define CDVD_TYPE_CDDA 0xfd // Audio CD -#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD -#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) -#define CDVD_TYPE_PS2CD 0x12 // PS2 CD -#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) -#define CDVD_TYPE_PSCD 0x10 // PS CD -#define CDVD_TYPE_UNKNOWN 0x05 // Unknown -#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided -#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided -#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd -#define CDVD_TYPE_DETCT 0x01 // Detecting -#define CDVD_TYPE_NODISC 0x00 // No Disc - -// CDVDgetTrayStatus returns: -#define CDVD_TRAY_CLOSE 0x00 -#define CDVD_TRAY_OPEN 0x01 - -// cdvdTD.type (track types for cds) -#define CDVD_AUDIO_TRACK 0x01 -#define CDVD_MODE1_TRACK 0x41 -#define CDVD_MODE2_TRACK 0x61 - -#define CDVD_AUDIO_MASK 0x00 -#define CDVD_DATA_MASK 0x40 -// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) - -typedef void (*DEV9callback)(int cycles); -typedef int (*DEV9handler)(void); - -typedef void (*USBcallback)(int cycles); -typedef int (*USBhandler)(void); - -// freeze modes: -#define FREEZE_LOAD 0 -#define FREEZE_SAVE 1 -#define FREEZE_SIZE 2 - -typedef struct { - char name[8]; - void *common; -} GSdriverInfo; - -#ifdef _WIN32 -typedef struct { // unsupported values must be set to zero - HWND hWnd; - HMENU hMenu; - HWND hStatusWnd; -} winInfo; -#endif - -/* GS plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef GSdefs - -// basic funcs - -s32 CALLBACK GSinit(); -s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); -void CALLBACK GSclose(); -void CALLBACK GSshutdown(); -void CALLBACK GSvsync(int field); -void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); -void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); -void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); -void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) -void CALLBACK GSgifSoftReset(u32 mask); -void CALLBACK GSreadFIFO(u64 *mem); -void CALLBACK GSreadFIFO2(u64 *mem, int qwc); - -// extended funcs - -// GSkeyEvent gets called when there is a keyEvent from the PAD plugin -void CALLBACK GSkeyEvent(keyEvent *ev); -void CALLBACK GSchangeSaveState(int, const char* filename); -void CALLBACK GSmakeSnapshot(char *path); -void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); -void CALLBACK GSirqCallback(void (*callback)()); -void CALLBACK GSprintf(int timeout, char *fmt, ...); -void CALLBACK GSsetBaseMem(void*); -void CALLBACK GSsetGameCRC(int crc, int gameoptions); - -// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done -void CALLBACK GSsetFrameSkip(int frameskip); - -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK GSsetupRecording(int start, void* pData); - -void CALLBACK GSreset(); -void CALLBACK GSwriteCSR(u32 value); -void CALLBACK GSgetDriverInfo(GSdriverInfo *info); -#ifdef _WIN32 -s32 CALLBACK GSsetWindowInfo(winInfo *info); -#endif -s32 CALLBACK GSfreeze(int mode, freezeData *data); -void CALLBACK GSconfigure(); -void CALLBACK GSabout(); -s32 CALLBACK GStest(); - -#endif - -/* PAD plugin API -=[ OBSOLETE ]=- */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef PADdefs - -// basic funcs - -s32 CALLBACK PADinit(u32 flags); -s32 CALLBACK PADopen(void *pDsp); -void CALLBACK PADclose(); -void CALLBACK PADshutdown(); -// PADkeyEvent is called every vsync (return NULL if no event) -keyEvent* CALLBACK PADkeyEvent(); -u8 CALLBACK PADstartPoll(int pad); -u8 CALLBACK PADpoll(u8 value); -// returns: 1 if supported pad1 -// 2 if supported pad2 -// 3 if both are supported -u32 CALLBACK PADquery(); - -// call to give a hint to the PAD plugin to query for the keyboard state. A -// good plugin will query the OS for keyboard state ONLY in this function. -// This function is necessary when multithreading because otherwise -// the PAD plugin can get into deadlocks with the thread that really owns -// the window (and input). Note that PADupdate can be called from a different -// thread than the other functions, so mutex or other multithreading primitives -// have to be added to maintain data integrity. -void CALLBACK PADupdate(int pad); - -// extended funcs - -void CALLBACK PADgsDriverInfo(GSdriverInfo *info); -void CALLBACK PADconfigure(); -void CALLBACK PADabout(); -s32 CALLBACK PADtest(); - -#endif - -/* SIO plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SIOdefs - -// basic funcs - -s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); -s32 CALLBACK SIOopen(void *pDsp); -void CALLBACK SIOclose(); -void CALLBACK SIOshutdown(); -u8 CALLBACK SIOstartPoll(u8 value); -u8 CALLBACK SIOpoll(u8 value); -// returns: SIO_TYPE_{PAD,MTAP,RM,MC} -u32 CALLBACK SIOquery(); - -// extended funcs - -void CALLBACK SIOconfigure(); -void CALLBACK SIOabout(); -s32 CALLBACK SIOtest(); - -#endif - -/* SPU2 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SPU2defs - -// basic funcs - -s32 CALLBACK SPU2init(); -s32 CALLBACK SPU2open(void *pDsp); -void CALLBACK SPU2close(); -void CALLBACK SPU2shutdown(); -void CALLBACK SPU2write(u32 mem, u16 value); -u16 CALLBACK SPU2read(u32 mem); -void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA4(); -void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); -void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); - -// all addresses passed by dma will be pointers to the array starting at baseaddr -// This function is necessary to successfully save and reload the spu2 state -void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); - -void CALLBACK SPU2interruptDMA7(); -u32 CALLBACK SPU2ReadMemAddr(int core); -void CALLBACK SPU2WriteMemAddr(int core,u32 value); -void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); - -// extended funcs -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK SPU2setupRecording(int start, void* pData); - -void CALLBACK SPU2async(u32 cycles); -s32 CALLBACK SPU2freeze(int mode, freezeData *data); -void CALLBACK SPU2configure(); -void CALLBACK SPU2about(); -s32 CALLBACK SPU2test(); - -#endif - -/* CDVD plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef CDVDdefs - -// basic funcs - -s32 CALLBACK CDVDinit(); -s32 CALLBACK CDVDopen(const char* pTitleFilename); -void CALLBACK CDVDclose(); -void CALLBACK CDVDshutdown(); -s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); - -// return can be NULL (for async modes) -u8* CALLBACK CDVDgetBuffer(); - -s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) -s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information -s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type -s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc -s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx -s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx -s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray -s32 CALLBACK CDVDctrlTrayClose(); //close disc tray - -// extended funcs - -void CALLBACK CDVDconfigure(); -void CALLBACK CDVDabout(); -s32 CALLBACK CDVDtest(); -void CALLBACK CDVDnewDiskCB(void (*callback)()); - -#endif - -/* DEV9 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef DEV9defs - -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK DEV9init(); -s32 CALLBACK DEV9open(void *pDsp); -void CALLBACK DEV9close(); -void CALLBACK DEV9shutdown(); -u8 CALLBACK DEV9read8(u32 addr); -u16 CALLBACK DEV9read16(u32 addr); -u32 CALLBACK DEV9read32(u32 addr); -void CALLBACK DEV9write8(u32 addr, u8 value); -void CALLBACK DEV9write16(u32 addr, u16 value); -void CALLBACK DEV9write32(u32 addr, u32 value); -void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); -void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK DEV9irqCallback(DEV9callback callback); -DEV9handler CALLBACK DEV9irqHandler(void); - -// extended funcs - -s32 CALLBACK DEV9freeze(int mode, freezeData *data); -void CALLBACK DEV9configure(); -void CALLBACK DEV9about(); -s32 CALLBACK DEV9test(); - -#endif - -/* USB plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef USBdefs - -// basic funcs - -s32 CALLBACK USBinit(); -s32 CALLBACK USBopen(void *pDsp); -void CALLBACK USBclose(); -void CALLBACK USBshutdown(); -u8 CALLBACK USBread8(u32 addr); -u16 CALLBACK USBread16(u32 addr); -u32 CALLBACK USBread32(u32 addr); -void CALLBACK USBwrite8(u32 addr, u8 value); -void CALLBACK USBwrite16(u32 addr, u16 value); -void CALLBACK USBwrite32(u32 addr, u32 value); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK USBirqCallback(USBcallback callback); -USBhandler CALLBACK USBirqHandler(void); -void CALLBACK USBsetRAM(void *mem); - -// extended funcs - -s32 CALLBACK USBfreeze(int mode, freezeData *data); -void CALLBACK USBconfigure(); -void CALLBACK USBabout(); -s32 CALLBACK USBtest(); - -#endif - -/* FW plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef FWdefs -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK FWinit(); -s32 CALLBACK FWopen(void *pDsp); -void CALLBACK FWclose(); -void CALLBACK FWshutdown(); -u32 CALLBACK FWread32(u32 addr); -void CALLBACK FWwrite32(u32 addr, u32 value); -void CALLBACK FWirqCallback(void (*callback)()); - -// extended funcs - -s32 CALLBACK FWfreeze(int mode, freezeData *data); -void CALLBACK FWconfigure(); -void CALLBACK FWabout(); -s32 CALLBACK FWtest(); -#endif - -// might be useful for emulators -#ifdef PLUGINtypedefs - -typedef u32 (CALLBACK* _PS2EgetLibType)(void); -typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); -typedef char*(CALLBACK* _PS2EgetLibName)(void); - -// GS -// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _GSinit)(); -typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); -typedef void (CALLBACK* _GSclose)(); -typedef void (CALLBACK* _GSshutdown)(); -typedef void (CALLBACK* _GSvsync)(int field); -typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); -typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) -typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); -typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); -typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); - -typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); -typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); -typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); -typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); -typedef void (CALLBACK* _GSsetBaseMem)(void*); -typedef void (CALLBACK* _GSsetGameCRC)(int, int); -typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); -typedef int (CALLBACK* _GSsetupRecording)(int, void*); -typedef void (CALLBACK* _GSreset)(); -typedef void (CALLBACK* _GSwriteCSR)(u32 value); -typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); -#ifdef _WIN32 -typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); -#endif -typedef void (CALLBACK* _GSmakeSnapshot)(char *path); -typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); -typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _GSconfigure)(); -typedef s32 (CALLBACK* _GStest)(); -typedef void (CALLBACK* _GSabout)(); - -// PAD -typedef s32 (CALLBACK* _PADinit)(u32 flags); -typedef s32 (CALLBACK* _PADopen)(void *pDsp); -typedef void (CALLBACK* _PADclose)(); -typedef void (CALLBACK* _PADshutdown)(); -typedef keyEvent* (CALLBACK* _PADkeyEvent)(); -typedef u8 (CALLBACK* _PADstartPoll)(int pad); -typedef u8 (CALLBACK* _PADpoll)(u8 value); -typedef u32 (CALLBACK* _PADquery)(); -typedef void (CALLBACK* _PADupdate)(int pad); - -typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); -typedef void (CALLBACK* _PADconfigure)(); -typedef s32 (CALLBACK* _PADtest)(); -typedef void (CALLBACK* _PADabout)(); - -// SIO -typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); -typedef s32 (CALLBACK* _SIOopen)(void *pDsp); -typedef void (CALLBACK* _SIOclose)(); -typedef void (CALLBACK* _SIOshutdown)(); -typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); -typedef u8 (CALLBACK* _SIOpoll)(u8 value); -typedef u32 (CALLBACK* _SIOquery)(); - -typedef void (CALLBACK* _SIOconfigure)(); -typedef s32 (CALLBACK* _SIOtest)(); -typedef void (CALLBACK* _SIOabout)(); - -// SPU2 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _SPU2init)(); -typedef s32 (CALLBACK* _SPU2open)(void *pDsp); -typedef void (CALLBACK* _SPU2close)(); -typedef void (CALLBACK* _SPU2shutdown)(); -typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); -typedef u16 (CALLBACK* _SPU2read)(u32 mem); -typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA4)(); -typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); -typedef void (CALLBACK* _SPU2interruptDMA7)(); -typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); -typedef int (CALLBACK* _SPU2setupRecording)(int, void*); -typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); -typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); -typedef void (CALLBACK* _SPU2async)(u32 cycles); -typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _SPU2configure)(); -typedef s32 (CALLBACK* _SPU2test)(); -typedef void (CALLBACK* _SPU2about)(); - -// CDVD -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _CDVDinit)(); -typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); -typedef void (CALLBACK* _CDVDclose)(); -typedef void (CALLBACK* _CDVDshutdown)(); -typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); -typedef u8* (CALLBACK* _CDVDgetBuffer)(); -typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); -typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); -typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); -typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); -typedef s32 (CALLBACK* _CDVDgetDiskType)(); -typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); -typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); -typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); - -typedef void (CALLBACK* _CDVDconfigure)(); -typedef s32 (CALLBACK* _CDVDtest)(); -typedef void (CALLBACK* _CDVDabout)(); -typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); - -// DEV9 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _DEV9init)(); -typedef s32 (CALLBACK* _DEV9open)(void *pDsp); -typedef void (CALLBACK* _DEV9close)(); -typedef void (CALLBACK* _DEV9shutdown)(); -typedef u8 (CALLBACK* _DEV9read8)(u32 mem); -typedef u16 (CALLBACK* _DEV9read16)(u32 mem); -typedef u32 (CALLBACK* _DEV9read32)(u32 mem); -typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); -typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); -typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); -typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); -typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); - -typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _DEV9configure)(); -typedef s32 (CALLBACK* _DEV9test)(); -typedef void (CALLBACK* _DEV9about)(); - -// USB -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _USBinit)(); -typedef s32 (CALLBACK* _USBopen)(void *pDsp); -typedef void (CALLBACK* _USBclose)(); -typedef void (CALLBACK* _USBshutdown)(); -typedef u8 (CALLBACK* _USBread8)(u32 mem); -typedef u16 (CALLBACK* _USBread16)(u32 mem); -typedef u32 (CALLBACK* _USBread32)(u32 mem); -typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); -typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); -typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); -typedef USBhandler (CALLBACK* _USBirqHandler)(void); -typedef void (CALLBACK* _USBsetRAM)(void *mem); - -typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _USBconfigure)(); -typedef s32 (CALLBACK* _USBtest)(); -typedef void (CALLBACK* _USBabout)(); - -//FW -typedef s32 (CALLBACK* _FWinit)(); -typedef s32 (CALLBACK* _FWopen)(void *pDsp); -typedef void (CALLBACK* _FWclose)(); -typedef void (CALLBACK* _FWshutdown)(); -typedef u32 (CALLBACK* _FWread32)(u32 mem); -typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); - -typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _FWconfigure)(); -typedef s32 (CALLBACK* _FWtest)(); -typedef void (CALLBACK* _FWabout)(); - -#endif - -#ifdef PLUGINfuncs - -// GS -_GSinit GSinit; -_GSopen GSopen; -_GSclose GSclose; -_GSshutdown GSshutdown; -_GSvsync GSvsync; -_GSgifTransfer1 GSgifTransfer1; -_GSgifTransfer2 GSgifTransfer2; -_GSgifTransfer3 GSgifTransfer3; -_GSgetLastTag GSgetLastTag; -_GSgifSoftReset GSgifSoftReset; -_GSreadFIFO GSreadFIFO; -_GSreadFIFO2 GSreadFIFO2; - -_GSkeyEvent GSkeyEvent; -_GSchangeSaveState GSchangeSaveState; -_GSmakeSnapshot GSmakeSnapshot; -_GSmakeSnapshot2 GSmakeSnapshot2; -_GSirqCallback GSirqCallback; -_GSprintf GSprintf; -_GSsetBaseMem GSsetBaseMem; -_GSsetGameCRC GSsetGameCRC; -_GSsetFrameSkip GSsetFrameSkip; -_GSsetupRecording GSsetupRecording; -_GSreset GSreset; -_GSwriteCSR GSwriteCSR; -_GSgetDriverInfo GSgetDriverInfo; -#ifdef _WIN32 -_GSsetWindowInfo GSsetWindowInfo; -#endif -_GSfreeze GSfreeze; -_GSconfigure GSconfigure; -_GStest GStest; -_GSabout GSabout; - -// PAD1 -_PADinit PAD1init; -_PADopen PAD1open; -_PADclose PAD1close; -_PADshutdown PAD1shutdown; -_PADkeyEvent PAD1keyEvent; -_PADstartPoll PAD1startPoll; -_PADpoll PAD1poll; -_PADquery PAD1query; -_PADupdate PAD1update; - -_PADgsDriverInfo PAD1gsDriverInfo; -_PADconfigure PAD1configure; -_PADtest PAD1test; -_PADabout PAD1about; - -// PAD2 -_PADinit PAD2init; -_PADopen PAD2open; -_PADclose PAD2close; -_PADshutdown PAD2shutdown; -_PADkeyEvent PAD2keyEvent; -_PADstartPoll PAD2startPoll; -_PADpoll PAD2poll; -_PADquery PAD2query; -_PADupdate PAD2update; - -_PADgsDriverInfo PAD2gsDriverInfo; -_PADconfigure PAD2configure; -_PADtest PAD2test; -_PADabout PAD2about; - -// SIO[2] -_SIOinit SIOinit[2][9]; -_SIOopen SIOopen[2][9]; -_SIOclose SIOclose[2][9]; -_SIOshutdown SIOshutdown[2][9]; -_SIOstartPoll SIOstartPoll[2][9]; -_SIOpoll SIOpoll[2][9]; -_SIOquery SIOquery[2][9]; - -_SIOconfigure SIOconfigure[2][9]; -_SIOtest SIOtest[2][9]; -_SIOabout SIOabout[2][9]; - -// SPU2 -_SPU2init SPU2init; -_SPU2open SPU2open; -_SPU2close SPU2close; -_SPU2shutdown SPU2shutdown; -_SPU2write SPU2write; -_SPU2read SPU2read; -_SPU2readDMA4Mem SPU2readDMA4Mem; -_SPU2writeDMA4Mem SPU2writeDMA4Mem; -_SPU2interruptDMA4 SPU2interruptDMA4; -_SPU2readDMA7Mem SPU2readDMA7Mem; -_SPU2writeDMA7Mem SPU2writeDMA7Mem; -_SPU2setDMABaseAddr SPU2setDMABaseAddr; -_SPU2interruptDMA7 SPU2interruptDMA7; -_SPU2ReadMemAddr SPU2ReadMemAddr; -_SPU2setupRecording SPU2setupRecording; -_SPU2WriteMemAddr SPU2WriteMemAddr; -_SPU2irqCallback SPU2irqCallback; - -_SPU2async SPU2async; -_SPU2freeze SPU2freeze; -_SPU2configure SPU2configure; -_SPU2test SPU2test; -_SPU2about SPU2about; - -// CDVD -_CDVDinit CDVDinit; -_CDVDopen CDVDopen; -_CDVDclose CDVDclose; -_CDVDshutdown CDVDshutdown; -_CDVDreadTrack CDVDreadTrack; -_CDVDgetBuffer CDVDgetBuffer; -_CDVDreadSubQ CDVDreadSubQ; -_CDVDgetTN CDVDgetTN; -_CDVDgetTD CDVDgetTD; -_CDVDgetTOC CDVDgetTOC; -_CDVDgetDiskType CDVDgetDiskType; -_CDVDgetTrayStatus CDVDgetTrayStatus; -_CDVDctrlTrayOpen CDVDctrlTrayOpen; -_CDVDctrlTrayClose CDVDctrlTrayClose; - -_CDVDconfigure CDVDconfigure; -_CDVDtest CDVDtest; -_CDVDabout CDVDabout; -_CDVDnewDiskCB CDVDnewDiskCB; - -// DEV9 -_DEV9init DEV9init; -_DEV9open DEV9open; -_DEV9close DEV9close; -_DEV9shutdown DEV9shutdown; -_DEV9read8 DEV9read8; -_DEV9read16 DEV9read16; -_DEV9read32 DEV9read32; -_DEV9write8 DEV9write8; -_DEV9write16 DEV9write16; -_DEV9write32 DEV9write32; -_DEV9readDMA8Mem DEV9readDMA8Mem; -_DEV9writeDMA8Mem DEV9writeDMA8Mem; -_DEV9irqCallback DEV9irqCallback; -_DEV9irqHandler DEV9irqHandler; - -_DEV9configure DEV9configure; -_DEV9freeze DEV9freeze; -_DEV9test DEV9test; -_DEV9about DEV9about; - -// USB -_USBinit USBinit; -_USBopen USBopen; -_USBclose USBclose; -_USBshutdown USBshutdown; -_USBread8 USBread8; -_USBread16 USBread16; -_USBread32 USBread32; -_USBwrite8 USBwrite8; -_USBwrite16 USBwrite16; -_USBwrite32 USBwrite32; -_USBirqCallback USBirqCallback; -_USBirqHandler USBirqHandler; -_USBsetRAM USBsetRAM; - -_USBconfigure USBconfigure; -_USBfreeze USBfreeze; -_USBtest USBtest; -_USBabout USBabout; - -// FW -_FWinit FWinit; -_FWopen FWopen; -_FWclose FWclose; -_FWshutdown FWshutdown; -_FWread32 FWread32; -_FWwrite32 FWwrite32; -_FWirqCallback FWirqCallback; - -_FWconfigure FWconfigure; -_FWfreeze FWfreeze; -_FWtest FWtest; -_FWabout FWabout; -#endif - -#endif /* __PS2EDEFS_H__ */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgetLastTag GSgetLastTag; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSsetupRecording GSsetupRecording; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; +_PADupdate PAD1update; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; +_PADupdate PAD2update; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2setDMABaseAddr SPU2setDMABaseAddr; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2setupRecording SPU2setupRecording; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/USBnull/USB.c b/plugins/USBnull/USB.c index 1f176961aa..f8b9ac9952 100644 --- a/plugins/USBnull/USB.c +++ b/plugins/USBnull/USB.c @@ -1,170 +1,170 @@ -/* USBlinuz - * Copyright (C) 2002-2005 USBlinuz 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include - -#include "USB.h" - - - -const unsigned char version = PS2E_USB_VERSION; -const unsigned char revision = 0; -const unsigned char build = 5; // increase that with each version - -static char *libraryName = "USBnull Driver"; - -u32 CALLBACK PS2EgetLibType() { - return PS2E_LT_USB; -} - -char* CALLBACK PS2EgetLibName() { - return libraryName; -} - -u32 CALLBACK PS2EgetLibVersion2(u32 type) { - return (version<<16) | (revision<<8) | build; -} - -void __Log(char *fmt, ...) { - va_list list; - - if (!conf.Log || usbLog == NULL) return; - - va_start(list, fmt); - vfprintf(usbLog, fmt, list); - va_end(list); -} - -s32 CALLBACK USBinit() { - LoadConfig(); - -#ifdef USB_LOG - usbLog = fopen("logs/usbLog.txt", "w"); - if (usbLog) setvbuf(usbLog, NULL, _IONBF, 0); - USB_LOG("usbnull plugin version %d,%d\n",revision,build); - USB_LOG("USBinit\n"); -#endif - - return 0; -} - -void CALLBACK USBshutdown() { -#ifdef USB_LOG - if (usbLog) fclose(usbLog); -#endif -} - -s32 CALLBACK USBopen(void *pDsp) { -#ifdef USB_LOG - USB_LOG("USBopen\n"); -#endif - -#ifdef _WIN32 -#else - Display* dsp = *(Display**)pDsp; -#endif - - return 0; -} - -void CALLBACK USBclose() { -} - -u8 CALLBACK USBread8(u32 addr) { - - - -#ifdef USB_LOG - USB_LOG("*UnKnown 8bit read at address %lx ", addr); -#endif - return 0; -} - -u16 CALLBACK USBread16(u32 addr) { - - - -#ifdef USB_LOG - USB_LOG("*UnKnown 16bit read at address %lx", addr); -#endif - return 0; -} - -u32 CALLBACK USBread32(u32 addr) { - -#ifdef USB_LOG - USB_LOG("*UnKnown 32bit read at address %lx", addr); -#endif - return 0; -} - -void CALLBACK USBwrite8(u32 addr, u8 value) { - -#ifdef USB_LOG - USB_LOG("*UnKnown 8bit write at address %lx value %x\n", addr, value); -#endif -} - -void CALLBACK USBwrite16(u32 addr, u16 value) { - -#ifdef USB_LOG - USB_LOG("*UnKnown 16bit write at address %lx value %x\n", addr, value); -#endif -} - -void CALLBACK USBwrite32(u32 addr, u32 value) { - -#ifdef USB_LOG - USB_LOG("*UnKnown 32bit write at address %lx value %lx\n", addr, value); -#endif -} - -void CALLBACK USBirqCallback(USBcallback callback) { - USBirq = callback; -} - -int CALLBACK _USBirqHandler(void) { - - return 0; -} - -USBhandler CALLBACK USBirqHandler(void) { - return (USBhandler)_USBirqHandler; -} - -void CALLBACK USBsetRAM(void *mem) { - -} - -// extended funcs - - - -s32 CALLBACK USBfreeze(int mode, freezeData *data) { - - - return 0; -} - - -s32 CALLBACK USBtest() { - return 0; -} - +/* USBlinuz + * Copyright (C) 2002-2005 USBlinuz 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include "USB.h" + + + +const unsigned char version = PS2E_USB_VERSION; +const unsigned char revision = 0; +const unsigned char build = 5; // increase that with each version + +static char *libraryName = "USBnull Driver"; + +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_USB; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (version<<16) | (revision<<8) | build; +} + +void __Log(char *fmt, ...) { + va_list list; + + if (!conf.Log || usbLog == NULL) return; + + va_start(list, fmt); + vfprintf(usbLog, fmt, list); + va_end(list); +} + +s32 CALLBACK USBinit() { + LoadConfig(); + +#ifdef USB_LOG + usbLog = fopen("logs/usbLog.txt", "w"); + if (usbLog) setvbuf(usbLog, NULL, _IONBF, 0); + USB_LOG("usbnull plugin version %d,%d\n",revision,build); + USB_LOG("USBinit\n"); +#endif + + return 0; +} + +void CALLBACK USBshutdown() { +#ifdef USB_LOG + if (usbLog) fclose(usbLog); +#endif +} + +s32 CALLBACK USBopen(void *pDsp) { +#ifdef USB_LOG + USB_LOG("USBopen\n"); +#endif + +#ifdef _WIN32 +#else + Display* dsp = *(Display**)pDsp; +#endif + + return 0; +} + +void CALLBACK USBclose() { +} + +u8 CALLBACK USBread8(u32 addr) { + + + +#ifdef USB_LOG + USB_LOG("*UnKnown 8bit read at address %lx ", addr); +#endif + return 0; +} + +u16 CALLBACK USBread16(u32 addr) { + + + +#ifdef USB_LOG + USB_LOG("*UnKnown 16bit read at address %lx", addr); +#endif + return 0; +} + +u32 CALLBACK USBread32(u32 addr) { + +#ifdef USB_LOG + USB_LOG("*UnKnown 32bit read at address %lx", addr); +#endif + return 0; +} + +void CALLBACK USBwrite8(u32 addr, u8 value) { + +#ifdef USB_LOG + USB_LOG("*UnKnown 8bit write at address %lx value %x\n", addr, value); +#endif +} + +void CALLBACK USBwrite16(u32 addr, u16 value) { + +#ifdef USB_LOG + USB_LOG("*UnKnown 16bit write at address %lx value %x\n", addr, value); +#endif +} + +void CALLBACK USBwrite32(u32 addr, u32 value) { + +#ifdef USB_LOG + USB_LOG("*UnKnown 32bit write at address %lx value %lx\n", addr, value); +#endif +} + +void CALLBACK USBirqCallback(USBcallback callback) { + USBirq = callback; +} + +int CALLBACK _USBirqHandler(void) { + + return 0; +} + +USBhandler CALLBACK USBirqHandler(void) { + return (USBhandler)_USBirqHandler; +} + +void CALLBACK USBsetRAM(void *mem) { + +} + +// extended funcs + + + +s32 CALLBACK USBfreeze(int mode, freezeData *data) { + + + return 0; +} + + +s32 CALLBACK USBtest() { + return 0; +} + diff --git a/plugins/USBnull/USB.h b/plugins/USBnull/USB.h index 486959ffd0..bb2243c965 100644 --- a/plugins/USBnull/USB.h +++ b/plugins/USBnull/USB.h @@ -1,66 +1,66 @@ -/* USBlinuz - * Copyright (C) 2002-2004 USBlinuz 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef __USB_H__ -#define __USB_H__ - -#include - -#define USBdefs -#include "PS2Edefs.h" - -#ifdef _WIN32 - -#define usleep(x) Sleep(x / 1000) -#include -#include - -#else - -#include -#include - -#define __inline inline - -#endif - -#define USB_LOG __Log - -typedef struct { - int Log; -} Config; - -Config conf; - - - - -#define PSXCLK 36864000 /* 36.864 Mhz */ - -USBcallback USBirq; - -void SaveConfig(); -void LoadConfig(); - -FILE *usbLog; -void __Log(char *fmt, ...); - -void SysMessage(char *fmt, ...); - -#endif +/* USBlinuz + * Copyright (C) 2002-2004 USBlinuz 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __USB_H__ +#define __USB_H__ + +#include + +#define USBdefs +#include "PS2Edefs.h" + +#ifdef _WIN32 + +#define usleep(x) Sleep(x / 1000) +#include +#include + +#else + +#include +#include + +#define __inline inline + +#endif + +#define USB_LOG __Log + +typedef struct { + int Log; +} Config; + +Config conf; + + + + +#define PSXCLK 36864000 /* 36.864 Mhz */ + +USBcallback USBirq; + +void SaveConfig(); +void LoadConfig(); + +FILE *usbLog; +void __Log(char *fmt, ...); + +void SysMessage(char *fmt, ...); + +#endif diff --git a/plugins/USBnull/Win32/Config.c b/plugins/USBnull/Win32/Config.c index ed953cf2eb..1c7bb393a1 100644 --- a/plugins/USBnull/Win32/Config.c +++ b/plugins/USBnull/Win32/Config.c @@ -1,51 +1,51 @@ -#include - -#include "USB.h" - -extern HINSTANCE hInst; -void SaveConfig() -{ - - Config *Conf1 = &conf; - char *szTemp; - char szIniFile[256], szValue[256]; - - GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); - szTemp = strrchr(szIniFile, '\\'); - - if(!szTemp) return; - strcpy(szTemp, "\\inis\\usbnull.ini"); - sprintf(szValue,"%u",Conf1->Log); - WritePrivateProfileString("Interface", "Logging",szValue,szIniFile); - -} - -void LoadConfig() { - FILE *fp; - - - Config *Conf1 = &conf; - char *szTemp; - char szIniFile[256], szValue[256]; - - GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); - szTemp = strrchr(szIniFile, '\\'); - - if(!szTemp) return ; - strcpy(szTemp, "\\inis\\usbnull.ini"); - fp=fopen("inis\\usbnull.ini","rt");//check if usbnull.ini really exists - if (!fp) - { - CreateDirectory("inis",NULL); - memset(&conf, 0, sizeof(conf)); - conf.Log = 0;//default value - SaveConfig();//save and return - return ; - } - fclose(fp); - GetPrivateProfileString("Interface", "Logging", NULL, szValue, 20, szIniFile); - Conf1->Log = strtoul(szValue, NULL, 10); - return ; - -} - +#include + +#include "USB.h" + +extern HINSTANCE hInst; +void SaveConfig() +{ + + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\usbnull.ini"); + sprintf(szValue,"%u",Conf1->Log); + WritePrivateProfileString("Interface", "Logging",szValue,szIniFile); + +} + +void LoadConfig() { + FILE *fp; + + + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return ; + strcpy(szTemp, "\\inis\\usbnull.ini"); + fp=fopen("inis\\usbnull.ini","rt");//check if usbnull.ini really exists + if (!fp) + { + CreateDirectory("inis",NULL); + memset(&conf, 0, sizeof(conf)); + conf.Log = 0;//default value + SaveConfig();//save and return + return ; + } + fclose(fp); + GetPrivateProfileString("Interface", "Logging", NULL, szValue, 20, szIniFile); + Conf1->Log = strtoul(szValue, NULL, 10); + return ; + +} + diff --git a/plugins/USBnull/Win32/Makefile b/plugins/USBnull/Win32/Makefile index f4ea1258cc..7cc8cf10cf 100644 --- a/plugins/USBnull/Win32/Makefile +++ b/plugins/USBnull/Win32/Makefile @@ -1,53 +1,53 @@ -# -# USBnull Makefile for MINGW32 -# - - -all: plugin - -CPU = ix86 -PLUGIN = USBnull.dll - -CC = gcc -NASM = nasmw -RM = rm -f -AR = ar -STRIP = strip -RC = windres - -OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing -m128bit-long-double -FLAGS = -D__WIN32__ -D__MINGW32__ # -DENABLE_NLS -DPACKAGE=\"pcsx2\" -ASMFLAGS = -D__WIN32__ -i.. -i.# -DENABLE_NLS -DPACKAGE=\"pcsx2\" -RC1FLAGS = -d__MINGW32__ -LIBS = -L./ -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 -RESOBJ = res.o - -OBJS = ../USB.o -OBJS+= Config.o Win32.o ${RESOBJ} - -DEPS:= $(OBJS:.o=.d) - -CFLAGS = -Wall ${OPTIMIZE} -I. -I.. -I/usr/local/include ${FLAGS} -ASMFLAGS = -f elf ${FLAGS} -i./ -i../ - -plugin: ${OBJS} - dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} -# ${CC} -shared -Wl,--kill-at ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} - ${STRIP} ${PLUGIN} - -.PHONY: clean plugin - -clean: - ${RM} ${OBJS} ${DEPS} ${PLUGIN} - -%.o: %.asm - ${NASM} ${ASMFLAGS} -o $@ $< - -%.o: %.c - ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) - -${RESOBJ}: USBnull.rc - ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< - --include ${DEPS} - +# +# USBnull Makefile for MINGW32 +# + + +all: plugin + +CPU = ix86 +PLUGIN = USBnull.dll + +CC = gcc +NASM = nasmw +RM = rm -f +AR = ar +STRIP = strip +RC = windres + +OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing -m128bit-long-double +FLAGS = -D__WIN32__ -D__MINGW32__ # -DENABLE_NLS -DPACKAGE=\"pcsx2\" +ASMFLAGS = -D__WIN32__ -i.. -i.# -DENABLE_NLS -DPACKAGE=\"pcsx2\" +RC1FLAGS = -d__MINGW32__ +LIBS = -L./ -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 +RESOBJ = res.o + +OBJS = ../USB.o +OBJS+= Config.o Win32.o ${RESOBJ} + +DEPS:= $(OBJS:.o=.d) + +CFLAGS = -Wall ${OPTIMIZE} -I. -I.. -I/usr/local/include ${FLAGS} +ASMFLAGS = -f elf ${FLAGS} -i./ -i../ + +plugin: ${OBJS} + dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} +# ${CC} -shared -Wl,--kill-at ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + ${STRIP} ${PLUGIN} + +.PHONY: clean plugin + +clean: + ${RM} ${OBJS} ${DEPS} ${PLUGIN} + +%.o: %.asm + ${NASM} ${ASMFLAGS} -o $@ $< + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +${RESOBJ}: USBnull.rc + ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< + +-include ${DEPS} + diff --git a/plugins/USBnull/Win32/Win32.c b/plugins/USBnull/Win32/Win32.c index a290a7782a..ab1c538f3b 100644 --- a/plugins/USBnull/Win32/Win32.c +++ b/plugins/USBnull/Win32/Win32.c @@ -1,80 +1,81 @@ -#include -#include -#include - -#include "USB.h" -#include "resource.h" - -HINSTANCE hInst; - -void SysMessage(char *fmt, ...) { - va_list list; - char tmp[512]; - - va_start(list,fmt); - vsprintf(tmp,fmt,list); - va_end(list); - MessageBox(0, tmp, "USBnull Msg", 0); -} - -BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { - - switch(uMsg) { - case WM_INITDIALOG: - LoadConfig(); - if (conf.Log) CheckDlgButton(hW, IDC_LOGGING, TRUE); - return TRUE; - - case WM_COMMAND: - switch(LOWORD(wParam)) { - case IDCANCEL: - EndDialog(hW, TRUE); - return TRUE; - case IDOK: - if (IsDlgButtonChecked(hW, IDC_LOGGING)) - conf.Log = 1; - else conf.Log = 0; - SaveConfig(); - EndDialog(hW, FALSE); - return TRUE; - } - } - return FALSE; -} - -BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { - switch(uMsg) { - case WM_INITDIALOG: - return TRUE; - - case WM_COMMAND: - switch(LOWORD(wParam)) { - case IDOK: - EndDialog(hW, FALSE); - return TRUE; - } - } - return FALSE; -} - -void CALLBACK USBconfigure() { - DialogBox(hInst, - MAKEINTRESOURCE(IDD_CONFIG), - GetActiveWindow(), - (DLGPROC)ConfigureDlgProc); -} - -void CALLBACK USBabout() { - DialogBox(hInst, - MAKEINTRESOURCE(IDD_ABOUT), - GetActiveWindow(), - (DLGPROC)AboutDlgProc); -} - -BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT - DWORD dwReason, - LPVOID lpReserved) { - hInst = (HINSTANCE)hModule; - return TRUE; // very quick :) -} - +#include +#include +#include + +#include "USB.h" +#include "resource.h" + +HINSTANCE hInst; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "USBnull Msg", 0); +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + + switch(uMsg) { + case WM_INITDIALOG: + LoadConfig(); + if (conf.Log) CheckDlgButton(hW, IDC_LOGGING, TRUE); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + case IDOK: + if (IsDlgButtonChecked(hW, IDC_LOGGING)) + conf.Log = 1; + else conf.Log = 0; + SaveConfig(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +void CALLBACK USBconfigure() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); + +} + +void CALLBACK USBabout() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc); +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + diff --git a/plugins/USBnull/Win32/afxresmw.h b/plugins/USBnull/Win32/afxresmw.h index 8a4b9df35b..99eace37c4 100644 --- a/plugins/USBnull/Win32/afxresmw.h +++ b/plugins/USBnull/Win32/afxresmw.h @@ -1,5 +1,5 @@ - -#include -#include - -#define IDC_STATIC (-1) + +#include +#include + +#define IDC_STATIC (-1) diff --git a/plugins/USBnull/Win32/mingw/Makefile.win b/plugins/USBnull/Win32/mingw/Makefile.win index 2fb5ec8792..2d7d0d030f 100644 --- a/plugins/USBnull/Win32/mingw/Makefile.win +++ b/plugins/USBnull/Win32/mingw/Makefile.win @@ -1,43 +1,43 @@ -# Project: USBnull -# Makefile created by Dev-C++ 4.9.9.2 - -CPP = mingw32-g++.exe -CC = mingw32-gcc.exe -WINDRES = windres.exe -RES = Obj//USBnull_private.res -OBJ = Obj//Win32.o Obj//Config.o Obj//USB.o $(RES) -LINKOBJ = Obj//Win32.o Obj//Config.o Obj//USB.o $(RES) -LIBS = -L"C:/Develop/Dev-Cpp/lib" --def ../plugin.def -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 -INCS = -I"C:/Develop/Dev-Cpp/include" -I"../" -I"../../" -I"../.." -CXXINCS = -I"C:/Develop/Dev-Cpp/include" -I"../" -I"../../" -I"../.." -BIN = USBnull.dll -CXXFLAGS = $(CXXINCS) -CFLAGS = $(INCS) -Wall -O2 -fomit-frame-pointer -D__WIN32__ -D__MINGW32__ -RM = rm -f - -.PHONY: all all-before all-after clean clean-custom - -all: all-before USBnull.dll all-after - - -clean: clean-custom - ${RM} $(OBJ) $(BIN) - -DLLWRAP=dllwrap.exe -DEFFILE=libUSBnull.def -STATICLIB=libUSBnull.a - -$(BIN): $(LINKOBJ) - $(DLLWRAP) --output-def $(DEFFILE) --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN) - -Obj//Win32.o: ../Win32.c - $(CC) -c ../Win32.c -o Obj//Win32.o $(CFLAGS) - -Obj//Config.o: ../Config.c - $(CC) -c ../Config.c -o Obj//Config.o $(CFLAGS) - -Obj//USB.o: ../../USB.c - $(CC) -c ../../USB.c -o Obj//USB.o $(CFLAGS) - -Obj//USBnull_private.res: USBnull_private.rc ../USBnull.rc - $(WINDRES) -i USBnull_private.rc --input-format=rc -o Obj//USBnull_private.res -O coff --include-dir ../mingw --include-dir ../ +# Project: USBnull +# Makefile created by Dev-C++ 4.9.9.2 + +CPP = mingw32-g++.exe +CC = mingw32-gcc.exe +WINDRES = windres.exe +RES = Obj//USBnull_private.res +OBJ = Obj//Win32.o Obj//Config.o Obj//USB.o $(RES) +LINKOBJ = Obj//Win32.o Obj//Config.o Obj//USB.o $(RES) +LIBS = -L"C:/Develop/Dev-Cpp/lib" --def ../plugin.def -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 +INCS = -I"C:/Develop/Dev-Cpp/include" -I"../" -I"../../" -I"../.." +CXXINCS = -I"C:/Develop/Dev-Cpp/include" -I"../" -I"../../" -I"../.." +BIN = USBnull.dll +CXXFLAGS = $(CXXINCS) +CFLAGS = $(INCS) -Wall -O2 -fomit-frame-pointer -D__WIN32__ -D__MINGW32__ +RM = rm -f + +.PHONY: all all-before all-after clean clean-custom + +all: all-before USBnull.dll all-after + + +clean: clean-custom + ${RM} $(OBJ) $(BIN) + +DLLWRAP=dllwrap.exe +DEFFILE=libUSBnull.def +STATICLIB=libUSBnull.a + +$(BIN): $(LINKOBJ) + $(DLLWRAP) --output-def $(DEFFILE) --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN) + +Obj//Win32.o: ../Win32.c + $(CC) -c ../Win32.c -o Obj//Win32.o $(CFLAGS) + +Obj//Config.o: ../Config.c + $(CC) -c ../Config.c -o Obj//Config.o $(CFLAGS) + +Obj//USB.o: ../../USB.c + $(CC) -c ../../USB.c -o Obj//USB.o $(CFLAGS) + +Obj//USBnull_private.res: USBnull_private.rc ../USBnull.rc + $(WINDRES) -i USBnull_private.rc --input-format=rc -o Obj//USBnull_private.res -O coff --include-dir ../mingw --include-dir ../ diff --git a/plugins/USBnull/Win32/mingw/afxres.h b/plugins/USBnull/Win32/mingw/afxres.h index 8a4b9df35b..99eace37c4 100644 --- a/plugins/USBnull/Win32/mingw/afxres.h +++ b/plugins/USBnull/Win32/mingw/afxres.h @@ -1,5 +1,5 @@ - -#include -#include - -#define IDC_STATIC (-1) + +#include +#include + +#define IDC_STATIC (-1) diff --git a/plugins/USBnull/Win32/resource.h b/plugins/USBnull/Win32/resource.h index 510a606c4c..6fb2e61293 100644 --- a/plugins/USBnull/Win32/resource.h +++ b/plugins/USBnull/Win32/resource.h @@ -1,21 +1,21 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by USBnull.rc -// -#define IDD_CONFDLG 101 -#define IDD_CONFIG 101 -#define IDD_ABOUT 103 -#define IDC_NAME 1000 -#define IDC_CHECK1 1007 -#define IDC_LOGGING 1007 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 105 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1008 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by USBnull.rc +// +#define IDD_CONFDLG 101 +#define IDD_CONFIG 101 +#define IDD_ABOUT 103 +#define IDC_NAME 1000 +#define IDC_CHECK1 1007 +#define IDC_LOGGING 1007 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1008 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/dev9null/src/DEV9.h b/plugins/dev9null/src/DEV9.h index 73ce78e706..a3b475d6c6 100644 --- a/plugins/dev9null/src/DEV9.h +++ b/plugins/dev9null/src/DEV9.h @@ -1,17 +1,17 @@ -#ifndef __DEV9_H__ -#define __DEV9_H__ - -#include - -#define DEV9defs - -#include "PS2Edefs.h" - - -FILE *dev9Log; -void __Log(char *fmt, ...); -void (*DEV9irq)(); -void SysMessage(char *fmt, ...); - - -#endif +#ifndef __DEV9_H__ +#define __DEV9_H__ + +#include + +#define DEV9defs + +#include "PS2Edefs.h" + + +FILE *dev9Log; +void __Log(char *fmt, ...); +void (*DEV9irq)(); +void SysMessage(char *fmt, ...); + + +#endif diff --git a/plugins/dev9null/src/Makefile b/plugins/dev9null/src/Makefile index 1b129e469b..663ab848e0 100644 --- a/plugins/dev9null/src/Makefile +++ b/plugins/dev9null/src/Makefile @@ -1,23 +1,23 @@ - -CC = gcc - -PLUGIN = libDEV9null.so -CFLAGS+= -fPIC -Wall -O2 -fomit-frame-pointer -D__LINUX__ -OBJS = dev9null.o -DEPS:= $(OBJS:.o=.d) - -all: plugin -install: all - -plugin: ${OBJS} - rm -f ${PLUGIN} - gcc -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} - strip --strip-unneeded --strip-debug ${PLUGIN} - -clean: - rm -f ${OBJS} ${DEPS} - -%.o: %.c - ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) - --include ${DEPS} + +CC = gcc + +PLUGIN = libDEV9null.so +CFLAGS+= -fPIC -Wall -O2 -fomit-frame-pointer -D__LINUX__ +OBJS = dev9null.o +DEPS:= $(OBJS:.o=.d) + +all: plugin +install: all + +plugin: ${OBJS} + rm -f ${PLUGIN} + gcc -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + strip --strip-unneeded --strip-debug ${PLUGIN} + +clean: + rm -f ${OBJS} ${DEPS} + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +-include ${DEPS} diff --git a/plugins/dev9null/src/Makefile.mingw b/plugins/dev9null/src/Makefile.mingw deleted file mode 100644 index 20bc9ef896..0000000000 --- a/plugins/dev9null/src/Makefile.mingw +++ /dev/null @@ -1,51 +0,0 @@ -# -# Makefile for MINGW32 -# - - -all: dev9null - -PLUGIN = DEV9null.dll - -CC = gcc -NASM = nasmw -RM = rm -f -AR = ar -STRIP = strip -RC = windres - -OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing -FLAGS = -D__WIN32__ -D__MINGW32__ # -DENABLE_NLS -DPACKAGE=\"pcsx2\" -RC1FLAGS = -d__MINGW32__ -LIBS = -L./ -lcomctl32 -lwinmm -lgdi32 -lcomdlg32 #-lintl -lwsock32 -RESOBJ = dev9nullrc.o - -OBJS = dev9null.o - - -DEPS:= $(OBJS:.o=.d) - -CFLAGS = -Wall ${OPTIMIZE} -I. -I/usr/local/include ${FLAGS} - -dev9null: ${OBJS} - dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} ${LIBS} -# ${CC} -shared -Wl,--kill-at,--output-def,plugin.def ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} - ${STRIP} ${PLUGIN} - -.PHONY: clean dev9null - -clean: - ${RM} ${OBJS} ${DEPS} ${PCSX2} - -%.o: %.asm - ${NASM} ${ASMFLAGS} -o $@ $< - -%.o: %.c - ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) - -${RESOBJ}: DEV9null.rc - ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< - --include ${DEPS} - - \ No newline at end of file diff --git a/plugins/dev9null/src/PS2Edefs.h b/plugins/dev9null/src/PS2Edefs.h index b2f76c96de..34bfdf54f2 100644 --- a/plugins/dev9null/src/PS2Edefs.h +++ b/plugins/dev9null/src/PS2Edefs.h @@ -1,848 +1,848 @@ -#ifndef __PS2EDEFS_H__ -#define __PS2EDEFS_H__ - -/* - * PS2E Definitions v0.6.2 (beta) - * - * Author: linuzappz@hotmail.com - * shadowpcsx2@yahoo.gr - * florinsasu@hotmail.com - */ - -/* - Notes: - * Since this is still beta things may change. - - * OSflags: - __LINUX__ (linux OS) - _WIN32 (win32 OS) - - * common return values (for ie. GSinit): - 0 - success - -1 - error - - * reserved keys: - F1 to F10 are reserved for the emulator - - * plugins should NOT change the current - working directory. - (on win32, add flag OFN_NOCHANGEDIR for - GetOpenFileName) - -*/ - -#include "PS2Etypes.h" - -#ifdef __LINUX__ -#define CALLBACK -#else -#include -#endif - - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ - defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ - defined(USBdefs) || defined(FWdefs) -#define COMMONdefs -#endif - -// PS2EgetLibType returns (may be OR'd) -#define PS2E_LT_GS 0x01 -#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- -#define PS2E_LT_SPU2 0x04 -#define PS2E_LT_CDVD 0x08 -#define PS2E_LT_DEV9 0x10 -#define PS2E_LT_USB 0x20 -#define PS2E_LT_FW 0x40 -#define PS2E_LT_SIO 0x80 - -// PS2EgetLibVersion2 (high 16 bits) -#define PS2E_GS_VERSION 0x0006 -#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- -#define PS2E_SPU2_VERSION 0x0005 -#define PS2E_CDVD_VERSION 0x0005 -#define PS2E_DEV9_VERSION 0x0003 -#define PS2E_USB_VERSION 0x0003 -#define PS2E_FW_VERSION 0x0002 -#define PS2E_SIO_VERSION 0x0001 -#ifdef COMMONdefs - -u32 CALLBACK PS2EgetLibType(void); -u32 CALLBACK PS2EgetLibVersion2(u32 type); -char* CALLBACK PS2EgetLibName(void); - -#endif - -// key values: -/* key values must be OS dependant: - win32: the VK_XXX will be used (WinUser) - linux: the XK_XXX will be used (XFree86) -*/ - -// event values: -#define KEYPRESS 1 -#define KEYRELEASE 2 - -typedef struct { - u32 key; - u32 event; -} keyEvent; - -// for 64bit compilers -typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; - -// plugin types -#define SIO_TYPE_PAD 0x00000001 -#define SIO_TYPE_MTAP 0x00000004 -#define SIO_TYPE_RM 0x00000040 -#define SIO_TYPE_MC 0x00000100 - -typedef int (CALLBACK * SIOchangeSlotCB)(int slot); - -typedef struct { - u8 ctrl:4; // control and mode bits - u8 mode:4; // control and mode bits - u8 trackNum; // current track number (1 to 99) - u8 trackIndex; // current index within track (0 to 99) - u8 trackM; // current minute location on the disc (BCD encoded) - u8 trackS; // current sector location on the disc (BCD encoded) - u8 trackF; // current frame location on the disc (BCD encoded) - u8 pad; // unused - u8 discM; // current minute offset from first track (BCD encoded) - u8 discS; // current sector offset from first track (BCD encoded) - u8 discF; // current frame offset from first track (BCD encoded) -} cdvdSubQ; - -typedef struct { // NOT bcd coded - u32 lsn; - u8 type; -} cdvdTD; - -typedef struct { - u8 strack; //number of the first track (usually 1) - u8 etrack; //number of the last track -} cdvdTN; - -// CDVDreadTrack mode values: -#define CDVD_MODE_2352 0 // full 2352 bytes -#define CDVD_MODE_2340 1 // skip sync (12) bytes -#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq - -// CDVDgetDiskType returns: -#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc -#define CDVD_TYPE_DVDV 0xfe // DVD Video -#define CDVD_TYPE_CDDA 0xfd // Audio CD -#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD -#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) -#define CDVD_TYPE_PS2CD 0x12 // PS2 CD -#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) -#define CDVD_TYPE_PSCD 0x10 // PS CD -#define CDVD_TYPE_UNKNOWN 0x05 // Unknown -#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided -#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided -#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd -#define CDVD_TYPE_DETCT 0x01 // Detecting -#define CDVD_TYPE_NODISC 0x00 // No Disc - -// CDVDgetTrayStatus returns: -#define CDVD_TRAY_CLOSE 0x00 -#define CDVD_TRAY_OPEN 0x01 - -// cdvdTD.type (track types for cds) -#define CDVD_AUDIO_TRACK 0x01 -#define CDVD_MODE1_TRACK 0x41 -#define CDVD_MODE2_TRACK 0x61 - -#define CDVD_AUDIO_MASK 0x00 -#define CDVD_DATA_MASK 0x40 -// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) - -typedef void (*DEV9callback)(int cycles); -typedef int (*DEV9handler)(void); - -typedef void (*USBcallback)(int cycles); -typedef int (*USBhandler)(void); - -// freeze modes: -#define FREEZE_LOAD 0 -#define FREEZE_SAVE 1 -#define FREEZE_SIZE 2 - -typedef struct { - char name[8]; - void *common; -} GSdriverInfo; - -#ifdef _WIN32 -typedef struct { // unsupported values must be set to zero - HWND hWnd; - HMENU hMenu; - HWND hStatusWnd; -} winInfo; -#endif - -/* GS plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef GSdefs - -// basic funcs - -s32 CALLBACK GSinit(); -s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); -void CALLBACK GSclose(); -void CALLBACK GSshutdown(); -void CALLBACK GSvsync(int field); -void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); -void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); -void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); -void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) -void CALLBACK GSgifSoftReset(u32 mask); -void CALLBACK GSreadFIFO(u64 *mem); -void CALLBACK GSreadFIFO2(u64 *mem, int qwc); - -// extended funcs - -// GSkeyEvent gets called when there is a keyEvent from the PAD plugin -void CALLBACK GSkeyEvent(keyEvent *ev); -void CALLBACK GSchangeSaveState(int, const char* filename); -void CALLBACK GSmakeSnapshot(char *path); -void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); -void CALLBACK GSirqCallback(void (*callback)()); -void CALLBACK GSprintf(int timeout, char *fmt, ...); -void CALLBACK GSsetBaseMem(void*); -void CALLBACK GSsetGameCRC(int crc, int gameoptions); - -// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done -void CALLBACK GSsetFrameSkip(int frameskip); - -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK GSsetupRecording(int start, void* pData); - -void CALLBACK GSreset(); -void CALLBACK GSwriteCSR(u32 value); -void CALLBACK GSgetDriverInfo(GSdriverInfo *info); -#ifdef _WIN32 -s32 CALLBACK GSsetWindowInfo(winInfo *info); -#endif -s32 CALLBACK GSfreeze(int mode, freezeData *data); -void CALLBACK GSconfigure(); -void CALLBACK GSabout(); -s32 CALLBACK GStest(); - -#endif - -/* PAD plugin API -=[ OBSOLETE ]=- */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef PADdefs - -// basic funcs - -s32 CALLBACK PADinit(u32 flags); -s32 CALLBACK PADopen(void *pDsp); -void CALLBACK PADclose(); -void CALLBACK PADshutdown(); -// PADkeyEvent is called every vsync (return NULL if no event) -keyEvent* CALLBACK PADkeyEvent(); -u8 CALLBACK PADstartPoll(int pad); -u8 CALLBACK PADpoll(u8 value); -// returns: 1 if supported pad1 -// 2 if supported pad2 -// 3 if both are supported -u32 CALLBACK PADquery(); - -// call to give a hint to the PAD plugin to query for the keyboard state. A -// good plugin will query the OS for keyboard state ONLY in this function. -// This function is necessary when multithreading because otherwise -// the PAD plugin can get into deadlocks with the thread that really owns -// the window (and input). Note that PADupdate can be called from a different -// thread than the other functions, so mutex or other multithreading primitives -// have to be added to maintain data integrity. -void CALLBACK PADupdate(int pad); - -// extended funcs - -void CALLBACK PADgsDriverInfo(GSdriverInfo *info); -void CALLBACK PADconfigure(); -void CALLBACK PADabout(); -s32 CALLBACK PADtest(); - -#endif - -/* SIO plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SIOdefs - -// basic funcs - -s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); -s32 CALLBACK SIOopen(void *pDsp); -void CALLBACK SIOclose(); -void CALLBACK SIOshutdown(); -u8 CALLBACK SIOstartPoll(u8 value); -u8 CALLBACK SIOpoll(u8 value); -// returns: SIO_TYPE_{PAD,MTAP,RM,MC} -u32 CALLBACK SIOquery(); - -// extended funcs - -void CALLBACK SIOconfigure(); -void CALLBACK SIOabout(); -s32 CALLBACK SIOtest(); - -#endif - -/* SPU2 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SPU2defs - -// basic funcs - -s32 CALLBACK SPU2init(); -s32 CALLBACK SPU2open(void *pDsp); -void CALLBACK SPU2close(); -void CALLBACK SPU2shutdown(); -void CALLBACK SPU2write(u32 mem, u16 value); -u16 CALLBACK SPU2read(u32 mem); -void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA4(); -void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); -void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); - -// all addresses passed by dma will be pointers to the array starting at baseaddr -// This function is necessary to successfully save and reload the spu2 state -void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); - -void CALLBACK SPU2interruptDMA7(); -u32 CALLBACK SPU2ReadMemAddr(int core); -void CALLBACK SPU2WriteMemAddr(int core,u32 value); -void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); - -// extended funcs -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK SPU2setupRecording(int start, void* pData); - -void CALLBACK SPU2async(u32 cycles); -s32 CALLBACK SPU2freeze(int mode, freezeData *data); -void CALLBACK SPU2configure(); -void CALLBACK SPU2about(); -s32 CALLBACK SPU2test(); - -#endif - -/* CDVD plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef CDVDdefs - -// basic funcs - -s32 CALLBACK CDVDinit(); -s32 CALLBACK CDVDopen(const char* pTitleFilename); -void CALLBACK CDVDclose(); -void CALLBACK CDVDshutdown(); -s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); - -// return can be NULL (for async modes) -u8* CALLBACK CDVDgetBuffer(); - -s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) -s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information -s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type -s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc -s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx -s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx -s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray -s32 CALLBACK CDVDctrlTrayClose(); //close disc tray - -// extended funcs - -void CALLBACK CDVDconfigure(); -void CALLBACK CDVDabout(); -s32 CALLBACK CDVDtest(); -void CALLBACK CDVDnewDiskCB(void (*callback)()); - -#endif - -/* DEV9 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef DEV9defs - -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK DEV9init(); -s32 CALLBACK DEV9open(void *pDsp); -void CALLBACK DEV9close(); -void CALLBACK DEV9shutdown(); -u8 CALLBACK DEV9read8(u32 addr); -u16 CALLBACK DEV9read16(u32 addr); -u32 CALLBACK DEV9read32(u32 addr); -void CALLBACK DEV9write8(u32 addr, u8 value); -void CALLBACK DEV9write16(u32 addr, u16 value); -void CALLBACK DEV9write32(u32 addr, u32 value); -void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); -void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK DEV9irqCallback(DEV9callback callback); -DEV9handler CALLBACK DEV9irqHandler(void); - -// extended funcs - -s32 CALLBACK DEV9freeze(int mode, freezeData *data); -void CALLBACK DEV9configure(); -void CALLBACK DEV9about(); -s32 CALLBACK DEV9test(); - -#endif - -/* USB plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef USBdefs - -// basic funcs - -s32 CALLBACK USBinit(); -s32 CALLBACK USBopen(void *pDsp); -void CALLBACK USBclose(); -void CALLBACK USBshutdown(); -u8 CALLBACK USBread8(u32 addr); -u16 CALLBACK USBread16(u32 addr); -u32 CALLBACK USBread32(u32 addr); -void CALLBACK USBwrite8(u32 addr, u8 value); -void CALLBACK USBwrite16(u32 addr, u16 value); -void CALLBACK USBwrite32(u32 addr, u32 value); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK USBirqCallback(USBcallback callback); -USBhandler CALLBACK USBirqHandler(void); -void CALLBACK USBsetRAM(void *mem); - -// extended funcs - -s32 CALLBACK USBfreeze(int mode, freezeData *data); -void CALLBACK USBconfigure(); -void CALLBACK USBabout(); -s32 CALLBACK USBtest(); - -#endif - -/* FW plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef FWdefs -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK FWinit(); -s32 CALLBACK FWopen(void *pDsp); -void CALLBACK FWclose(); -void CALLBACK FWshutdown(); -u32 CALLBACK FWread32(u32 addr); -void CALLBACK FWwrite32(u32 addr, u32 value); -void CALLBACK FWirqCallback(void (*callback)()); - -// extended funcs - -s32 CALLBACK FWfreeze(int mode, freezeData *data); -void CALLBACK FWconfigure(); -void CALLBACK FWabout(); -s32 CALLBACK FWtest(); -#endif - -// might be useful for emulators -#ifdef PLUGINtypedefs - -typedef u32 (CALLBACK* _PS2EgetLibType)(void); -typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); -typedef char*(CALLBACK* _PS2EgetLibName)(void); - -// GS -// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _GSinit)(); -typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); -typedef void (CALLBACK* _GSclose)(); -typedef void (CALLBACK* _GSshutdown)(); -typedef void (CALLBACK* _GSvsync)(int field); -typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); -typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) -typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); -typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); -typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); - -typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); -typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); -typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); -typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); -typedef void (CALLBACK* _GSsetBaseMem)(void*); -typedef void (CALLBACK* _GSsetGameCRC)(int, int); -typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); -typedef int (CALLBACK* _GSsetupRecording)(int, void*); -typedef void (CALLBACK* _GSreset)(); -typedef void (CALLBACK* _GSwriteCSR)(u32 value); -typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); -#ifdef _WIN32 -typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); -#endif -typedef void (CALLBACK* _GSmakeSnapshot)(char *path); -typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); -typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _GSconfigure)(); -typedef s32 (CALLBACK* _GStest)(); -typedef void (CALLBACK* _GSabout)(); - -// PAD -typedef s32 (CALLBACK* _PADinit)(u32 flags); -typedef s32 (CALLBACK* _PADopen)(void *pDsp); -typedef void (CALLBACK* _PADclose)(); -typedef void (CALLBACK* _PADshutdown)(); -typedef keyEvent* (CALLBACK* _PADkeyEvent)(); -typedef u8 (CALLBACK* _PADstartPoll)(int pad); -typedef u8 (CALLBACK* _PADpoll)(u8 value); -typedef u32 (CALLBACK* _PADquery)(); -typedef void (CALLBACK* _PADupdate)(int pad); - -typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); -typedef void (CALLBACK* _PADconfigure)(); -typedef s32 (CALLBACK* _PADtest)(); -typedef void (CALLBACK* _PADabout)(); - -// SIO -typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); -typedef s32 (CALLBACK* _SIOopen)(void *pDsp); -typedef void (CALLBACK* _SIOclose)(); -typedef void (CALLBACK* _SIOshutdown)(); -typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); -typedef u8 (CALLBACK* _SIOpoll)(u8 value); -typedef u32 (CALLBACK* _SIOquery)(); - -typedef void (CALLBACK* _SIOconfigure)(); -typedef s32 (CALLBACK* _SIOtest)(); -typedef void (CALLBACK* _SIOabout)(); - -// SPU2 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _SPU2init)(); -typedef s32 (CALLBACK* _SPU2open)(void *pDsp); -typedef void (CALLBACK* _SPU2close)(); -typedef void (CALLBACK* _SPU2shutdown)(); -typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); -typedef u16 (CALLBACK* _SPU2read)(u32 mem); -typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA4)(); -typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); -typedef void (CALLBACK* _SPU2interruptDMA7)(); -typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); -typedef int (CALLBACK* _SPU2setupRecording)(int, void*); -typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); -typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); -typedef void (CALLBACK* _SPU2async)(u32 cycles); -typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _SPU2configure)(); -typedef s32 (CALLBACK* _SPU2test)(); -typedef void (CALLBACK* _SPU2about)(); - -// CDVD -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _CDVDinit)(); -typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); -typedef void (CALLBACK* _CDVDclose)(); -typedef void (CALLBACK* _CDVDshutdown)(); -typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); -typedef u8* (CALLBACK* _CDVDgetBuffer)(); -typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); -typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); -typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); -typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); -typedef s32 (CALLBACK* _CDVDgetDiskType)(); -typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); -typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); -typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); - -typedef void (CALLBACK* _CDVDconfigure)(); -typedef s32 (CALLBACK* _CDVDtest)(); -typedef void (CALLBACK* _CDVDabout)(); -typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); - -// DEV9 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _DEV9init)(); -typedef s32 (CALLBACK* _DEV9open)(void *pDsp); -typedef void (CALLBACK* _DEV9close)(); -typedef void (CALLBACK* _DEV9shutdown)(); -typedef u8 (CALLBACK* _DEV9read8)(u32 mem); -typedef u16 (CALLBACK* _DEV9read16)(u32 mem); -typedef u32 (CALLBACK* _DEV9read32)(u32 mem); -typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); -typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); -typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); -typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); -typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); - -typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _DEV9configure)(); -typedef s32 (CALLBACK* _DEV9test)(); -typedef void (CALLBACK* _DEV9about)(); - -// USB -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _USBinit)(); -typedef s32 (CALLBACK* _USBopen)(void *pDsp); -typedef void (CALLBACK* _USBclose)(); -typedef void (CALLBACK* _USBshutdown)(); -typedef u8 (CALLBACK* _USBread8)(u32 mem); -typedef u16 (CALLBACK* _USBread16)(u32 mem); -typedef u32 (CALLBACK* _USBread32)(u32 mem); -typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); -typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); -typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); -typedef USBhandler (CALLBACK* _USBirqHandler)(void); -typedef void (CALLBACK* _USBsetRAM)(void *mem); - -typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _USBconfigure)(); -typedef s32 (CALLBACK* _USBtest)(); -typedef void (CALLBACK* _USBabout)(); - -//FW -typedef s32 (CALLBACK* _FWinit)(); -typedef s32 (CALLBACK* _FWopen)(void *pDsp); -typedef void (CALLBACK* _FWclose)(); -typedef void (CALLBACK* _FWshutdown)(); -typedef u32 (CALLBACK* _FWread32)(u32 mem); -typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); - -typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _FWconfigure)(); -typedef s32 (CALLBACK* _FWtest)(); -typedef void (CALLBACK* _FWabout)(); - -#endif - -#ifdef PLUGINfuncs - -// GS -_GSinit GSinit; -_GSopen GSopen; -_GSclose GSclose; -_GSshutdown GSshutdown; -_GSvsync GSvsync; -_GSgifTransfer1 GSgifTransfer1; -_GSgifTransfer2 GSgifTransfer2; -_GSgifTransfer3 GSgifTransfer3; -_GSgetLastTag GSgetLastTag; -_GSgifSoftReset GSgifSoftReset; -_GSreadFIFO GSreadFIFO; -_GSreadFIFO2 GSreadFIFO2; - -_GSkeyEvent GSkeyEvent; -_GSchangeSaveState GSchangeSaveState; -_GSmakeSnapshot GSmakeSnapshot; -_GSmakeSnapshot2 GSmakeSnapshot2; -_GSirqCallback GSirqCallback; -_GSprintf GSprintf; -_GSsetBaseMem GSsetBaseMem; -_GSsetGameCRC GSsetGameCRC; -_GSsetFrameSkip GSsetFrameSkip; -_GSsetupRecording GSsetupRecording; -_GSreset GSreset; -_GSwriteCSR GSwriteCSR; -_GSgetDriverInfo GSgetDriverInfo; -#ifdef _WIN32 -_GSsetWindowInfo GSsetWindowInfo; -#endif -_GSfreeze GSfreeze; -_GSconfigure GSconfigure; -_GStest GStest; -_GSabout GSabout; - -// PAD1 -_PADinit PAD1init; -_PADopen PAD1open; -_PADclose PAD1close; -_PADshutdown PAD1shutdown; -_PADkeyEvent PAD1keyEvent; -_PADstartPoll PAD1startPoll; -_PADpoll PAD1poll; -_PADquery PAD1query; -_PADupdate PAD1update; - -_PADgsDriverInfo PAD1gsDriverInfo; -_PADconfigure PAD1configure; -_PADtest PAD1test; -_PADabout PAD1about; - -// PAD2 -_PADinit PAD2init; -_PADopen PAD2open; -_PADclose PAD2close; -_PADshutdown PAD2shutdown; -_PADkeyEvent PAD2keyEvent; -_PADstartPoll PAD2startPoll; -_PADpoll PAD2poll; -_PADquery PAD2query; -_PADupdate PAD2update; - -_PADgsDriverInfo PAD2gsDriverInfo; -_PADconfigure PAD2configure; -_PADtest PAD2test; -_PADabout PAD2about; - -// SIO[2] -_SIOinit SIOinit[2][9]; -_SIOopen SIOopen[2][9]; -_SIOclose SIOclose[2][9]; -_SIOshutdown SIOshutdown[2][9]; -_SIOstartPoll SIOstartPoll[2][9]; -_SIOpoll SIOpoll[2][9]; -_SIOquery SIOquery[2][9]; - -_SIOconfigure SIOconfigure[2][9]; -_SIOtest SIOtest[2][9]; -_SIOabout SIOabout[2][9]; - -// SPU2 -_SPU2init SPU2init; -_SPU2open SPU2open; -_SPU2close SPU2close; -_SPU2shutdown SPU2shutdown; -_SPU2write SPU2write; -_SPU2read SPU2read; -_SPU2readDMA4Mem SPU2readDMA4Mem; -_SPU2writeDMA4Mem SPU2writeDMA4Mem; -_SPU2interruptDMA4 SPU2interruptDMA4; -_SPU2readDMA7Mem SPU2readDMA7Mem; -_SPU2writeDMA7Mem SPU2writeDMA7Mem; -_SPU2setDMABaseAddr SPU2setDMABaseAddr; -_SPU2interruptDMA7 SPU2interruptDMA7; -_SPU2ReadMemAddr SPU2ReadMemAddr; -_SPU2setupRecording SPU2setupRecording; -_SPU2WriteMemAddr SPU2WriteMemAddr; -_SPU2irqCallback SPU2irqCallback; - -_SPU2async SPU2async; -_SPU2freeze SPU2freeze; -_SPU2configure SPU2configure; -_SPU2test SPU2test; -_SPU2about SPU2about; - -// CDVD -_CDVDinit CDVDinit; -_CDVDopen CDVDopen; -_CDVDclose CDVDclose; -_CDVDshutdown CDVDshutdown; -_CDVDreadTrack CDVDreadTrack; -_CDVDgetBuffer CDVDgetBuffer; -_CDVDreadSubQ CDVDreadSubQ; -_CDVDgetTN CDVDgetTN; -_CDVDgetTD CDVDgetTD; -_CDVDgetTOC CDVDgetTOC; -_CDVDgetDiskType CDVDgetDiskType; -_CDVDgetTrayStatus CDVDgetTrayStatus; -_CDVDctrlTrayOpen CDVDctrlTrayOpen; -_CDVDctrlTrayClose CDVDctrlTrayClose; - -_CDVDconfigure CDVDconfigure; -_CDVDtest CDVDtest; -_CDVDabout CDVDabout; -_CDVDnewDiskCB CDVDnewDiskCB; - -// DEV9 -_DEV9init DEV9init; -_DEV9open DEV9open; -_DEV9close DEV9close; -_DEV9shutdown DEV9shutdown; -_DEV9read8 DEV9read8; -_DEV9read16 DEV9read16; -_DEV9read32 DEV9read32; -_DEV9write8 DEV9write8; -_DEV9write16 DEV9write16; -_DEV9write32 DEV9write32; -_DEV9readDMA8Mem DEV9readDMA8Mem; -_DEV9writeDMA8Mem DEV9writeDMA8Mem; -_DEV9irqCallback DEV9irqCallback; -_DEV9irqHandler DEV9irqHandler; - -_DEV9configure DEV9configure; -_DEV9freeze DEV9freeze; -_DEV9test DEV9test; -_DEV9about DEV9about; - -// USB -_USBinit USBinit; -_USBopen USBopen; -_USBclose USBclose; -_USBshutdown USBshutdown; -_USBread8 USBread8; -_USBread16 USBread16; -_USBread32 USBread32; -_USBwrite8 USBwrite8; -_USBwrite16 USBwrite16; -_USBwrite32 USBwrite32; -_USBirqCallback USBirqCallback; -_USBirqHandler USBirqHandler; -_USBsetRAM USBsetRAM; - -_USBconfigure USBconfigure; -_USBfreeze USBfreeze; -_USBtest USBtest; -_USBabout USBabout; - -// FW -_FWinit FWinit; -_FWopen FWopen; -_FWclose FWclose; -_FWshutdown FWshutdown; -_FWread32 FWread32; -_FWwrite32 FWwrite32; -_FWirqCallback FWirqCallback; - -_FWconfigure FWconfigure; -_FWfreeze FWfreeze; -_FWtest FWtest; -_FWabout FWabout; -#endif - -#endif /* __PS2EDEFS_H__ */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + +#ifdef __LINUX__ +#define CALLBACK +#else +#include +#endif + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + u32 key; + u32 event; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WIN32 +typedef struct { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WIN32 +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +_GSinit GSinit; +_GSopen GSopen; +_GSclose GSclose; +_GSshutdown GSshutdown; +_GSvsync GSvsync; +_GSgifTransfer1 GSgifTransfer1; +_GSgifTransfer2 GSgifTransfer2; +_GSgifTransfer3 GSgifTransfer3; +_GSgetLastTag GSgetLastTag; +_GSgifSoftReset GSgifSoftReset; +_GSreadFIFO GSreadFIFO; +_GSreadFIFO2 GSreadFIFO2; + +_GSkeyEvent GSkeyEvent; +_GSchangeSaveState GSchangeSaveState; +_GSmakeSnapshot GSmakeSnapshot; +_GSmakeSnapshot2 GSmakeSnapshot2; +_GSirqCallback GSirqCallback; +_GSprintf GSprintf; +_GSsetBaseMem GSsetBaseMem; +_GSsetGameCRC GSsetGameCRC; +_GSsetFrameSkip GSsetFrameSkip; +_GSsetupRecording GSsetupRecording; +_GSreset GSreset; +_GSwriteCSR GSwriteCSR; +_GSgetDriverInfo GSgetDriverInfo; +#ifdef _WIN32 +_GSsetWindowInfo GSsetWindowInfo; +#endif +_GSfreeze GSfreeze; +_GSconfigure GSconfigure; +_GStest GStest; +_GSabout GSabout; + +// PAD1 +_PADinit PAD1init; +_PADopen PAD1open; +_PADclose PAD1close; +_PADshutdown PAD1shutdown; +_PADkeyEvent PAD1keyEvent; +_PADstartPoll PAD1startPoll; +_PADpoll PAD1poll; +_PADquery PAD1query; +_PADupdate PAD1update; + +_PADgsDriverInfo PAD1gsDriverInfo; +_PADconfigure PAD1configure; +_PADtest PAD1test; +_PADabout PAD1about; + +// PAD2 +_PADinit PAD2init; +_PADopen PAD2open; +_PADclose PAD2close; +_PADshutdown PAD2shutdown; +_PADkeyEvent PAD2keyEvent; +_PADstartPoll PAD2startPoll; +_PADpoll PAD2poll; +_PADquery PAD2query; +_PADupdate PAD2update; + +_PADgsDriverInfo PAD2gsDriverInfo; +_PADconfigure PAD2configure; +_PADtest PAD2test; +_PADabout PAD2about; + +// SIO[2] +_SIOinit SIOinit[2][9]; +_SIOopen SIOopen[2][9]; +_SIOclose SIOclose[2][9]; +_SIOshutdown SIOshutdown[2][9]; +_SIOstartPoll SIOstartPoll[2][9]; +_SIOpoll SIOpoll[2][9]; +_SIOquery SIOquery[2][9]; + +_SIOconfigure SIOconfigure[2][9]; +_SIOtest SIOtest[2][9]; +_SIOabout SIOabout[2][9]; + +// SPU2 +_SPU2init SPU2init; +_SPU2open SPU2open; +_SPU2close SPU2close; +_SPU2shutdown SPU2shutdown; +_SPU2write SPU2write; +_SPU2read SPU2read; +_SPU2readDMA4Mem SPU2readDMA4Mem; +_SPU2writeDMA4Mem SPU2writeDMA4Mem; +_SPU2interruptDMA4 SPU2interruptDMA4; +_SPU2readDMA7Mem SPU2readDMA7Mem; +_SPU2writeDMA7Mem SPU2writeDMA7Mem; +_SPU2setDMABaseAddr SPU2setDMABaseAddr; +_SPU2interruptDMA7 SPU2interruptDMA7; +_SPU2ReadMemAddr SPU2ReadMemAddr; +_SPU2setupRecording SPU2setupRecording; +_SPU2WriteMemAddr SPU2WriteMemAddr; +_SPU2irqCallback SPU2irqCallback; + +_SPU2async SPU2async; +_SPU2freeze SPU2freeze; +_SPU2configure SPU2configure; +_SPU2test SPU2test; +_SPU2about SPU2about; + +// CDVD +_CDVDinit CDVDinit; +_CDVDopen CDVDopen; +_CDVDclose CDVDclose; +_CDVDshutdown CDVDshutdown; +_CDVDreadTrack CDVDreadTrack; +_CDVDgetBuffer CDVDgetBuffer; +_CDVDreadSubQ CDVDreadSubQ; +_CDVDgetTN CDVDgetTN; +_CDVDgetTD CDVDgetTD; +_CDVDgetTOC CDVDgetTOC; +_CDVDgetDiskType CDVDgetDiskType; +_CDVDgetTrayStatus CDVDgetTrayStatus; +_CDVDctrlTrayOpen CDVDctrlTrayOpen; +_CDVDctrlTrayClose CDVDctrlTrayClose; + +_CDVDconfigure CDVDconfigure; +_CDVDtest CDVDtest; +_CDVDabout CDVDabout; +_CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +_DEV9init DEV9init; +_DEV9open DEV9open; +_DEV9close DEV9close; +_DEV9shutdown DEV9shutdown; +_DEV9read8 DEV9read8; +_DEV9read16 DEV9read16; +_DEV9read32 DEV9read32; +_DEV9write8 DEV9write8; +_DEV9write16 DEV9write16; +_DEV9write32 DEV9write32; +_DEV9readDMA8Mem DEV9readDMA8Mem; +_DEV9writeDMA8Mem DEV9writeDMA8Mem; +_DEV9irqCallback DEV9irqCallback; +_DEV9irqHandler DEV9irqHandler; + +_DEV9configure DEV9configure; +_DEV9freeze DEV9freeze; +_DEV9test DEV9test; +_DEV9about DEV9about; + +// USB +_USBinit USBinit; +_USBopen USBopen; +_USBclose USBclose; +_USBshutdown USBshutdown; +_USBread8 USBread8; +_USBread16 USBread16; +_USBread32 USBread32; +_USBwrite8 USBwrite8; +_USBwrite16 USBwrite16; +_USBwrite32 USBwrite32; +_USBirqCallback USBirqCallback; +_USBirqHandler USBirqHandler; +_USBsetRAM USBsetRAM; + +_USBconfigure USBconfigure; +_USBfreeze USBfreeze; +_USBtest USBtest; +_USBabout USBabout; + +// FW +_FWinit FWinit; +_FWopen FWopen; +_FWclose FWclose; +_FWshutdown FWshutdown; +_FWread32 FWread32; +_FWwrite32 FWwrite32; +_FWirqCallback FWirqCallback; + +_FWconfigure FWconfigure; +_FWfreeze FWfreeze; +_FWtest FWtest; +_FWabout FWabout; +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/dev9null/src/dev9null.c b/plugins/dev9null/src/dev9null.c index cf4817a163..85b1d998be 100644 --- a/plugins/dev9null/src/dev9null.c +++ b/plugins/dev9null/src/dev9null.c @@ -1,152 +1,152 @@ - - -#ifdef _WIN32 - -#include -#include -#include - -#endif - -#include -#include -#include -#include -#include "PS2Etypes.h" -#include "DEV9.h" - -#ifdef _WIN32 - -HINSTANCE hInst; - -void SysMessage(char *fmt, ...) { - va_list list; - char tmp[512]; - va_start(list,fmt); - vsprintf(tmp,fmt,list); - va_end(list); - MessageBox(0, tmp, "DEV9null Msg", 0); -} - -#else - -#include - -void SysMessage(char *fmt, ...) { -} - -#endif - -const unsigned char version = PS2E_DEV9_VERSION; -const unsigned char revision = 0; -const unsigned char build = 3; // increase that with each version - -static char *libraryName = "DEV9null Driver"; - -u32 CALLBACK PS2EgetLibType() { - return PS2E_LT_DEV9; -} - -char* CALLBACK PS2EgetLibName() { - return libraryName; -} - -u32 CALLBACK PS2EgetLibVersion2(u32 type) { - return (version<<16) | (revision<<8) | build; -} - -void __Log(char *fmt, ...) { - va_list list; - -// if (!Log) return; - - va_start(list, fmt); - vfprintf(dev9Log, fmt, list); - va_end(list); -} - -s32 CALLBACK DEV9init() { - - return 0; -} - -void CALLBACK DEV9shutdown() { -} - -s32 CALLBACK DEV9open(void *pDsp) { - -#ifdef _WIN32 -#else - Display* dsp = *(Display**)pDsp; -#endif - return 0; -} - -void CALLBACK DEV9close() { - -} - - -u8 CALLBACK DEV9read8(u32 addr) { - return 0; -} - -u16 CALLBACK DEV9read16(u32 addr) { - return 0; -} - -u32 CALLBACK DEV9read32(u32 addr) { - return 0; -} - -void CALLBACK DEV9write8(u32 addr, u8 value) { -} - -void CALLBACK DEV9write16(u32 addr, u16 value) { - -} - -void CALLBACK DEV9write32(u32 addr, u32 value) { - -} - -void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size) { - -} - -void CALLBACK DEV9writeDMA8Mem(u32* pMem, int size) { - -} - - -void CALLBACK DEV9irqCallback(DEV9callback callback) { - -} - -DEV9handler CALLBACK DEV9irqHandler(void) { - return NULL; -} - - -// extended funcs - -s32 CALLBACK DEV9test() { - return 0; -} - -void CALLBACK DEV9configure() -{ - SysMessage("Nothing to Configure"); -} -void CALLBACK DEV9about(){} - -#ifdef _WIN32 - -BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT - DWORD dwReason, - LPVOID lpReserved) { - hInst = (HINSTANCE)hModule; - return TRUE; // very quick :) -} - -#endif + + +#ifdef _WIN32 + +#include +#include +#include + +#endif + +#include +#include +#include +#include +#include "PS2Etypes.h" +#include "DEV9.h" + +#ifdef _WIN32 + +HINSTANCE hInst; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "DEV9null Msg", 0); +} + +#else + +#include + +void SysMessage(char *fmt, ...) { +} + +#endif + +const unsigned char version = PS2E_DEV9_VERSION; +const unsigned char revision = 0; +const unsigned char build = 3; // increase that with each version + +static char *libraryName = "DEV9null Driver"; + +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_DEV9; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (version<<16) | (revision<<8) | build; +} + +void __Log(char *fmt, ...) { + va_list list; + +// if (!Log) return; + + va_start(list, fmt); + vfprintf(dev9Log, fmt, list); + va_end(list); +} + +s32 CALLBACK DEV9init() { + + return 0; +} + +void CALLBACK DEV9shutdown() { +} + +s32 CALLBACK DEV9open(void *pDsp) { + +#ifdef _WIN32 +#else + Display* dsp = *(Display**)pDsp; +#endif + return 0; +} + +void CALLBACK DEV9close() { + +} + + +u8 CALLBACK DEV9read8(u32 addr) { + return 0; +} + +u16 CALLBACK DEV9read16(u32 addr) { + return 0; +} + +u32 CALLBACK DEV9read32(u32 addr) { + return 0; +} + +void CALLBACK DEV9write8(u32 addr, u8 value) { +} + +void CALLBACK DEV9write16(u32 addr, u16 value) { + +} + +void CALLBACK DEV9write32(u32 addr, u32 value) { + +} + +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size) { + +} + +void CALLBACK DEV9writeDMA8Mem(u32* pMem, int size) { + +} + + +void CALLBACK DEV9irqCallback(DEV9callback callback) { + +} + +DEV9handler CALLBACK DEV9irqHandler(void) { + return NULL; +} + + +// extended funcs + +s32 CALLBACK DEV9test() { + return 0; +} + +void CALLBACK DEV9configure() +{ + SysMessage("Nothing to Configure"); +} +void CALLBACK DEV9about(){} + +#ifdef _WIN32 + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + +#endif diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/3dnow_win.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/3dnow_win.cpp index 2e369904ec..01e6dab8a7 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/3dnow_win.cpp +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/3dnow_win.cpp @@ -1,350 +1,350 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Win32 version of the AMD 3DNow! optimized routines for AMD K6-2/Athlon -/// processors. All 3DNow! optimized functions have been gathered into this -/// single source code file, regardless to their class or original source code -/// file, in order to ease porting the library to other compiler and processor -/// platforms. -/// -/// By the way; the performance gain depends heavily on the CPU generation: On -/// K6-2 these routines provided speed-up of even 2.4 times, while on Athlon the -/// difference to the original routines stayed at unremarkable 8%! Such a small -/// improvement on Athlon is due to 3DNow can perform only two operations in -/// parallel, and obviously also the Athlon FPU is doing a very good job with -/// the standard C floating point routines! Here these routines are anyway, -/// although it might not be worth the effort to convert these to GCC platform, -/// for Athlon CPU at least. The situation is different regarding the SSE -/// optimizations though, thanks to the four parallel operations of SSE that -/// already make a difference. -/// -/// This file is to be compiled in Windows platform with Microsoft Visual C++ -/// Compiler. Please see '3dnow_gcc.cpp' for the gcc compiler version for all -/// GNU platforms (if file supplied). -/// -/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ -/// 6.0 processor pack" update to support 3DNow! instruction set. The update is -/// available for download at Microsoft Developers Network, see here: -/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx -/// -/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and -/// perform a search with keywords "processor pack". -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.10 $ -// -// $Id: 3dnow_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include "cpu_detect.h" -#include "STTypes.h" - -#ifndef _WIN32 -#error "wrong platform - this source code file is exclusively for Win32 platform" -#endif - -using namespace soundtouch; - -#ifdef ALLOW_3DNOW -// 3DNow! routines available only with float sample type - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of 3DNow! optimized functions of class 'TDStretch3DNow' -// -////////////////////////////////////////////////////////////////////////////// - -#include "TDStretch.h" -#include - -// these are declared in 'TDStretch.cpp' -extern int scanOffsets[4][24]; - - -// Calculates cross correlation of two buffers -double TDStretch3DNow::calcCrossCorrStereo(const float *pV1, const float *pV2) const -{ - uint overlapLengthLocal = overlapLength; - float corr; - - // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors - /* - c-pseudocode: - - corr = 0; - for (i = 0; i < overlapLength / 4; i ++) - { - corr += pV1[0] * pV2[0]; - pV1[1] * pV2[1]; - pV1[2] * pV2[2]; - pV1[3] * pV2[3]; - pV1[4] * pV2[4]; - pV1[5] * pV2[5]; - pV1[6] * pV2[6]; - pV1[7] * pV2[7]; - - pV1 += 8; - pV2 += 8; - } - */ - - _asm - { - // give prefetch hints to CPU of what data are to be needed soonish. - // give more aggressive hints on pV1 as that changes more between different calls - // while pV2 stays the same. - prefetch [pV1] - prefetch [pV2] - prefetch [pV1 + 32] - - mov eax, dword ptr pV2 - mov ebx, dword ptr pV1 - - pxor mm0, mm0 - - mov ecx, overlapLengthLocal - shr ecx, 2 // div by four - - loop1: - movq mm1, [eax] - prefetch [eax + 32] // give a prefetch hint to CPU what data are to be needed soonish - pfmul mm1, [ebx] - prefetch [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish - - movq mm2, [eax + 8] - pfadd mm0, mm1 - pfmul mm2, [ebx + 8] - - movq mm3, [eax + 16] - pfadd mm0, mm2 - pfmul mm3, [ebx + 16] - - movq mm4, [eax + 24] - pfadd mm0, mm3 - pfmul mm4, [ebx + 24] - - add eax, 32 - pfadd mm0, mm4 - add ebx, 32 - - dec ecx - jnz loop1 - - // add halfs of mm0 together and return the result. - // note: mm1 is used as a dummy parameter only, we actually don't care about it's value - pfacc mm0, mm1 - movd corr, mm0 - femms - } - - return corr; -} - - - - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of 3DNow! optimized functions of class 'FIRFilter' -// -////////////////////////////////////////////////////////////////////////////// - -#include "FIRFilter.h" - -FIRFilter3DNow::FIRFilter3DNow() : FIRFilter() -{ - filterCoeffsUnalign = NULL; -} - - -FIRFilter3DNow::~FIRFilter3DNow() -{ - delete[] filterCoeffsUnalign; -} - - -// (overloaded) Calculates filter coefficients for 3DNow! routine -void FIRFilter3DNow::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) -{ - uint i; - float fDivider; - - FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); - - // Scale the filter coefficients so that it won't be necessary to scale the filtering result - // also rearrange coefficients suitably for 3DNow! - // Ensure that filter coeffs array is aligned to 16-byte boundary - delete[] filterCoeffsUnalign; - filterCoeffsUnalign = new float[2 * newLength + 4]; - filterCoeffsAlign = (float *)(((uint)filterCoeffsUnalign + 15) & -16); - - fDivider = (float)resultDivider; - - // rearrange the filter coefficients for mmx routines - for (i = 0; i < newLength; i ++) - { - filterCoeffsAlign[2 * i + 0] = - filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; - } -} - - -// 3DNow!-optimized version of the filter routine for stereo sound -uint FIRFilter3DNow::evaluateFilterStereo(float *dest, const float *src, const uint numSamples) const -{ - float *filterCoeffsLocal = filterCoeffsAlign; - uint count = (numSamples - length) & -2; - uint lengthLocal = length / 4; - - assert(length != 0); - assert(count % 2 == 0); - - /* original code: - - double suml1, suml2; - double sumr1, sumr2; - uint i, j; - - for (j = 0; j < count; j += 2) - { - const float *ptr; - - suml1 = sumr1 = 0.0; - suml2 = sumr2 = 0.0; - ptr = src; - filterCoeffsLocal = filterCoeffs; - for (i = 0; i < lengthLocal; i ++) - { - // unroll loop for efficiency. - - suml1 += ptr[0] * filterCoeffsLocal[0] + - ptr[2] * filterCoeffsLocal[2] + - ptr[4] * filterCoeffsLocal[4] + - ptr[6] * filterCoeffsLocal[6]; - - sumr1 += ptr[1] * filterCoeffsLocal[1] + - ptr[3] * filterCoeffsLocal[3] + - ptr[5] * filterCoeffsLocal[5] + - ptr[7] * filterCoeffsLocal[7]; - - suml2 += ptr[8] * filterCoeffsLocal[0] + - ptr[10] * filterCoeffsLocal[2] + - ptr[12] * filterCoeffsLocal[4] + - ptr[14] * filterCoeffsLocal[6]; - - sumr2 += ptr[9] * filterCoeffsLocal[1] + - ptr[11] * filterCoeffsLocal[3] + - ptr[13] * filterCoeffsLocal[5] + - ptr[15] * filterCoeffsLocal[7]; - - ptr += 16; - filterCoeffsLocal += 8; - } - dest[0] = (float)suml1; - dest[1] = (float)sumr1; - dest[2] = (float)suml2; - dest[3] = (float)sumr2; - - src += 4; - dest += 4; - } - - */ - _asm - { - mov eax, dword ptr dest - mov ebx, dword ptr src - mov edx, count - shr edx, 1 - - loop1: - // "outer loop" : during each round 2*2 output samples are calculated - prefetch [ebx] // give a prefetch hint to CPU what data are to be needed soonish - prefetch [filterCoeffsLocal] // give a prefetch hint to CPU what data are to be needed soonish - - mov esi, ebx - mov edi, filterCoeffsLocal - pxor mm0, mm0 - pxor mm1, mm1 - mov ecx, lengthLocal - - loop2: - // "inner loop" : during each round four FIR filter taps are evaluated for 2*2 output samples - movq mm2, [edi] - movq mm3, mm2 - prefetch [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish - pfmul mm2, [esi] - prefetch [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish - pfmul mm3, [esi + 8] - - movq mm4, [edi + 8] - movq mm5, mm4 - pfadd mm0, mm2 - pfmul mm4, [esi + 8] - pfadd mm1, mm3 - pfmul mm5, [esi + 16] - - movq mm2, [edi + 16] - movq mm6, mm2 - pfadd mm0, mm4 - pfmul mm2, [esi + 16] - pfadd mm1, mm5 - pfmul mm6, [esi + 24] - - movq mm3, [edi + 24] - movq mm7, mm3 - pfadd mm0, mm2 - pfmul mm3, [esi + 24] - pfadd mm1, mm6 - pfmul mm7, [esi + 32] - add esi, 32 - pfadd mm0, mm3 - add edi, 32 - pfadd mm1, mm7 - - dec ecx - jnz loop2 - - movq [eax], mm0 - add ebx, 16 - movq [eax + 8], mm1 - add eax, 16 - - dec edx - jnz loop1 - - femms - } - - return count; -} - - -#endif // ALLOW_3DNOW +//////////////////////////////////////////////////////////////////////////////// +/// +/// Win32 version of the AMD 3DNow! optimized routines for AMD K6-2/Athlon +/// processors. All 3DNow! optimized functions have been gathered into this +/// single source code file, regardless to their class or original source code +/// file, in order to ease porting the library to other compiler and processor +/// platforms. +/// +/// By the way; the performance gain depends heavily on the CPU generation: On +/// K6-2 these routines provided speed-up of even 2.4 times, while on Athlon the +/// difference to the original routines stayed at unremarkable 8%! Such a small +/// improvement on Athlon is due to 3DNow can perform only two operations in +/// parallel, and obviously also the Athlon FPU is doing a very good job with +/// the standard C floating point routines! Here these routines are anyway, +/// although it might not be worth the effort to convert these to GCC platform, +/// for Athlon CPU at least. The situation is different regarding the SSE +/// optimizations though, thanks to the four parallel operations of SSE that +/// already make a difference. +/// +/// This file is to be compiled in Windows platform with Microsoft Visual C++ +/// Compiler. Please see '3dnow_gcc.cpp' for the gcc compiler version for all +/// GNU platforms (if file supplied). +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support 3DNow! instruction set. The update is +/// available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx +/// +/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and +/// perform a search with keywords "processor pack". +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: 3dnow_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" +#include "STTypes.h" + +#ifndef _WIN32 +#error "wrong platform - this source code file is exclusively for Win32 platform" +#endif + +using namespace soundtouch; + +#ifdef ALLOW_3DNOW +// 3DNow! routines available only with float sample type + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of 3DNow! optimized functions of class 'TDStretch3DNow' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include + +// these are declared in 'TDStretch.cpp' +extern int scanOffsets[4][24]; + + +// Calculates cross correlation of two buffers +double TDStretch3DNow::calcCrossCorrStereo(const float *pV1, const float *pV2) const +{ + uint overlapLengthLocal = overlapLength; + float corr; + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + /* + c-pseudocode: + + corr = 0; + for (i = 0; i < overlapLength / 4; i ++) + { + corr += pV1[0] * pV2[0]; + pV1[1] * pV2[1]; + pV1[2] * pV2[2]; + pV1[3] * pV2[3]; + pV1[4] * pV2[4]; + pV1[5] * pV2[5]; + pV1[6] * pV2[6]; + pV1[7] * pV2[7]; + + pV1 += 8; + pV2 += 8; + } + */ + + _asm + { + // give prefetch hints to CPU of what data are to be needed soonish. + // give more aggressive hints on pV1 as that changes more between different calls + // while pV2 stays the same. + prefetch [pV1] + prefetch [pV2] + prefetch [pV1 + 32] + + mov eax, dword ptr pV2 + mov ebx, dword ptr pV1 + + pxor mm0, mm0 + + mov ecx, overlapLengthLocal + shr ecx, 2 // div by four + + loop1: + movq mm1, [eax] + prefetch [eax + 32] // give a prefetch hint to CPU what data are to be needed soonish + pfmul mm1, [ebx] + prefetch [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish + + movq mm2, [eax + 8] + pfadd mm0, mm1 + pfmul mm2, [ebx + 8] + + movq mm3, [eax + 16] + pfadd mm0, mm2 + pfmul mm3, [ebx + 16] + + movq mm4, [eax + 24] + pfadd mm0, mm3 + pfmul mm4, [ebx + 24] + + add eax, 32 + pfadd mm0, mm4 + add ebx, 32 + + dec ecx + jnz loop1 + + // add halfs of mm0 together and return the result. + // note: mm1 is used as a dummy parameter only, we actually don't care about it's value + pfacc mm0, mm1 + movd corr, mm0 + femms + } + + return corr; +} + + + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of 3DNow! optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + +FIRFilter3DNow::FIRFilter3DNow() : FIRFilter() +{ + filterCoeffsUnalign = NULL; +} + + +FIRFilter3DNow::~FIRFilter3DNow() +{ + delete[] filterCoeffsUnalign; +} + + +// (overloaded) Calculates filter coefficients for 3DNow! routine +void FIRFilter3DNow::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + float fDivider; + + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Scale the filter coefficients so that it won't be necessary to scale the filtering result + // also rearrange coefficients suitably for 3DNow! + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new float[2 * newLength + 4]; + filterCoeffsAlign = (float *)(((uint)filterCoeffsUnalign + 15) & -16); + + fDivider = (float)resultDivider; + + // rearrange the filter coefficients for mmx routines + for (i = 0; i < newLength; i ++) + { + filterCoeffsAlign[2 * i + 0] = + filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; + } +} + + +// 3DNow!-optimized version of the filter routine for stereo sound +uint FIRFilter3DNow::evaluateFilterStereo(float *dest, const float *src, const uint numSamples) const +{ + float *filterCoeffsLocal = filterCoeffsAlign; + uint count = (numSamples - length) & -2; + uint lengthLocal = length / 4; + + assert(length != 0); + assert(count % 2 == 0); + + /* original code: + + double suml1, suml2; + double sumr1, sumr2; + uint i, j; + + for (j = 0; j < count; j += 2) + { + const float *ptr; + + suml1 = sumr1 = 0.0; + suml2 = sumr2 = 0.0; + ptr = src; + filterCoeffsLocal = filterCoeffs; + for (i = 0; i < lengthLocal; i ++) + { + // unroll loop for efficiency. + + suml1 += ptr[0] * filterCoeffsLocal[0] + + ptr[2] * filterCoeffsLocal[2] + + ptr[4] * filterCoeffsLocal[4] + + ptr[6] * filterCoeffsLocal[6]; + + sumr1 += ptr[1] * filterCoeffsLocal[1] + + ptr[3] * filterCoeffsLocal[3] + + ptr[5] * filterCoeffsLocal[5] + + ptr[7] * filterCoeffsLocal[7]; + + suml2 += ptr[8] * filterCoeffsLocal[0] + + ptr[10] * filterCoeffsLocal[2] + + ptr[12] * filterCoeffsLocal[4] + + ptr[14] * filterCoeffsLocal[6]; + + sumr2 += ptr[9] * filterCoeffsLocal[1] + + ptr[11] * filterCoeffsLocal[3] + + ptr[13] * filterCoeffsLocal[5] + + ptr[15] * filterCoeffsLocal[7]; + + ptr += 16; + filterCoeffsLocal += 8; + } + dest[0] = (float)suml1; + dest[1] = (float)sumr1; + dest[2] = (float)suml2; + dest[3] = (float)sumr2; + + src += 4; + dest += 4; + } + + */ + _asm + { + mov eax, dword ptr dest + mov ebx, dword ptr src + mov edx, count + shr edx, 1 + + loop1: + // "outer loop" : during each round 2*2 output samples are calculated + prefetch [ebx] // give a prefetch hint to CPU what data are to be needed soonish + prefetch [filterCoeffsLocal] // give a prefetch hint to CPU what data are to be needed soonish + + mov esi, ebx + mov edi, filterCoeffsLocal + pxor mm0, mm0 + pxor mm1, mm1 + mov ecx, lengthLocal + + loop2: + // "inner loop" : during each round four FIR filter taps are evaluated for 2*2 output samples + movq mm2, [edi] + movq mm3, mm2 + prefetch [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish + pfmul mm2, [esi] + prefetch [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish + pfmul mm3, [esi + 8] + + movq mm4, [edi + 8] + movq mm5, mm4 + pfadd mm0, mm2 + pfmul mm4, [esi + 8] + pfadd mm1, mm3 + pfmul mm5, [esi + 16] + + movq mm2, [edi + 16] + movq mm6, mm2 + pfadd mm0, mm4 + pfmul mm2, [esi + 16] + pfadd mm1, mm5 + pfmul mm6, [esi + 24] + + movq mm3, [edi + 24] + movq mm7, mm3 + pfadd mm0, mm2 + pfmul mm3, [esi + 24] + pfadd mm1, mm6 + pfmul mm7, [esi + 32] + add esi, 32 + pfadd mm0, mm3 + add edi, 32 + pfadd mm1, mm7 + + dec ecx + jnz loop2 + + movq [eax], mm0 + add ebx, 16 + movq [eax + 8], mm1 + add eax, 16 + + dec edx + jnz loop1 + + femms + } + + return count; +} + + +#endif // ALLOW_3DNOW diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/AAFilter.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/AAFilter.cpp index 9a5cf539c0..6bf529ccec 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/AAFilter.cpp +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/AAFilter.cpp @@ -1,184 +1,184 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// FIR low-pass (anti-alias) filter with filter coefficient design routine and -/// MMX optimization. -/// -/// Anti-alias filter is used to prevent folding of high frequencies when -/// transposing the sample rate with interpolation. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.9 $ -// -// $Id: AAFilter.cpp,v 1.9 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include "AAFilter.h" -#include "FIRFilter.h" - -using namespace soundtouch; - -#define PI 3.141592655357989 -#define TWOPI (2 * PI) - -/***************************************************************************** - * - * Implementation of the class 'AAFilter' - * - *****************************************************************************/ - -AAFilter::AAFilter(const uint length) -{ - pFIR = FIRFilter::newInstance(); - cutoffFreq = 0.5; - setLength(length); -} - - - -AAFilter::~AAFilter() -{ - delete pFIR; -} - - - -// Sets new anti-alias filter cut-off edge frequency, scaled to -// sampling frequency (nyquist frequency = 0.5). -// The filter will cut frequencies higher than the given frequency. -void AAFilter::setCutoffFreq(const double newCutoffFreq) -{ - cutoffFreq = newCutoffFreq; - calculateCoeffs(); -} - - - -// Sets number of FIR filter taps -void AAFilter::setLength(const uint newLength) -{ - length = newLength; - calculateCoeffs(); -} - - - -// Calculates coefficients for a low-pass FIR filter using Hamming window -void AAFilter::calculateCoeffs() -{ - uint i; - double cntTemp, temp, tempCoeff,h, w; - double fc2, wc; - double scaleCoeff, sum; - double *work; - SAMPLETYPE *coeffs; - - assert(length > 0); - assert(length % 4 == 0); - assert(cutoffFreq >= 0); - assert(cutoffFreq <= 0.5); - - work = new double[length]; - coeffs = new SAMPLETYPE[length]; - - fc2 = 2.0 * cutoffFreq; - wc = PI * fc2; - tempCoeff = TWOPI / (double)length; - - sum = 0; - for (i = 0; i < length; i ++) - { - cntTemp = (double)i - (double)(length / 2); - - temp = cntTemp * wc; - if (temp != 0) - { - h = fc2 * sin(temp) / temp; // sinc function - } - else - { - h = 1.0; - } - w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window - - temp = w * h; - work[i] = temp; - - // calc net sum of coefficients - sum += temp; - } - - // ensure the sum of coefficients is larger than zero - assert(sum > 0); - - // ensure we've really designed a lowpass filter... - assert(work[length/2] > 0); - assert(work[length/2 + 1] > -1e-6); - assert(work[length/2 - 1] > -1e-6); - - // Calculate a scaling coefficient in such a way that the result can be - // divided by 16384 - scaleCoeff = 16384.0f / sum; - - for (i = 0; i < length; i ++) - { - // scale & round to nearest integer - temp = work[i] * scaleCoeff; - temp += (temp >= 0) ? 0.5 : -0.5; - // ensure no overfloods - assert(temp >= -32768 && temp <= 32767); - coeffs[i] = (SAMPLETYPE)temp; - } - - // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384 - pFIR->setCoefficients(coeffs, length, 14); - - delete[] work; - delete[] coeffs; -} - - -// Applies the filter to the given sequence of samples. -// Note : The amount of outputted samples is by value of 'filter length' -// smaller than the amount of input samples. -uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const -{ - return pFIR->evaluate(dest, src, numSamples, numChannels); -} - - -uint AAFilter::getLength() const -{ - return pFIR->getLength(); -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// FIR low-pass (anti-alias) filter with filter coefficient design routine and +/// MMX optimization. +/// +/// Anti-alias filter is used to prevent folding of high frequencies when +/// transposing the sample rate with interpolation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.9 $ +// +// $Id: AAFilter.cpp,v 1.9 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include "AAFilter.h" +#include "FIRFilter.h" + +using namespace soundtouch; + +#define PI 3.141592655357989 +#define TWOPI (2 * PI) + +/***************************************************************************** + * + * Implementation of the class 'AAFilter' + * + *****************************************************************************/ + +AAFilter::AAFilter(const uint length) +{ + pFIR = FIRFilter::newInstance(); + cutoffFreq = 0.5; + setLength(length); +} + + + +AAFilter::~AAFilter() +{ + delete pFIR; +} + + + +// Sets new anti-alias filter cut-off edge frequency, scaled to +// sampling frequency (nyquist frequency = 0.5). +// The filter will cut frequencies higher than the given frequency. +void AAFilter::setCutoffFreq(const double newCutoffFreq) +{ + cutoffFreq = newCutoffFreq; + calculateCoeffs(); +} + + + +// Sets number of FIR filter taps +void AAFilter::setLength(const uint newLength) +{ + length = newLength; + calculateCoeffs(); +} + + + +// Calculates coefficients for a low-pass FIR filter using Hamming window +void AAFilter::calculateCoeffs() +{ + uint i; + double cntTemp, temp, tempCoeff,h, w; + double fc2, wc; + double scaleCoeff, sum; + double *work; + SAMPLETYPE *coeffs; + + assert(length > 0); + assert(length % 4 == 0); + assert(cutoffFreq >= 0); + assert(cutoffFreq <= 0.5); + + work = new double[length]; + coeffs = new SAMPLETYPE[length]; + + fc2 = 2.0 * cutoffFreq; + wc = PI * fc2; + tempCoeff = TWOPI / (double)length; + + sum = 0; + for (i = 0; i < length; i ++) + { + cntTemp = (double)i - (double)(length / 2); + + temp = cntTemp * wc; + if (temp != 0) + { + h = fc2 * sin(temp) / temp; // sinc function + } + else + { + h = 1.0; + } + w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window + + temp = w * h; + work[i] = temp; + + // calc net sum of coefficients + sum += temp; + } + + // ensure the sum of coefficients is larger than zero + assert(sum > 0); + + // ensure we've really designed a lowpass filter... + assert(work[length/2] > 0); + assert(work[length/2 + 1] > -1e-6); + assert(work[length/2 - 1] > -1e-6); + + // Calculate a scaling coefficient in such a way that the result can be + // divided by 16384 + scaleCoeff = 16384.0f / sum; + + for (i = 0; i < length; i ++) + { + // scale & round to nearest integer + temp = work[i] * scaleCoeff; + temp += (temp >= 0) ? 0.5 : -0.5; + // ensure no overfloods + assert(temp >= -32768 && temp <= 32767); + coeffs[i] = (SAMPLETYPE)temp; + } + + // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384 + pFIR->setCoefficients(coeffs, length, 14); + + delete[] work; + delete[] coeffs; +} + + +// Applies the filter to the given sequence of samples. +// Note : The amount of outputted samples is by value of 'filter length' +// smaller than the amount of input samples. +uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const +{ + return pFIR->evaluate(dest, src, numSamples, numChannels); +} + + +uint AAFilter::getLength() const +{ + return pFIR->getLength(); +} diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/AAFilter.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/AAFilter.h index 4c85dcdbe7..68eb50d27f 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/AAFilter.h +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/AAFilter.h @@ -1,91 +1,91 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo -/// while maintaining the original pitch by using a time domain WSOLA-like method -/// with several performance-increasing tweaks. -/// -/// Anti-alias filter is used to prevent folding of high frequencies when -/// transposing the sample rate with interpolation. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.10 $ -// -// $Id: AAFilter.h,v 1.10 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef AAFilter_H -#define AAFilter_H - -#include "STTypes.h" - -namespace soundtouch -{ - -class AAFilter -{ -protected: - class FIRFilter *pFIR; - - /// Low-pass filter cut-off frequency, negative = invalid - double cutoffFreq; - - /// num of filter taps - uint length; - - /// Calculate the FIR coefficients realizing the given cutoff-frequency - void calculateCoeffs(); -public: - AAFilter(uint length); - - ~AAFilter(); - - /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling - /// frequency (nyquist frequency = 0.5). The filter will cut off the - /// frequencies than that. - void setCutoffFreq(double newCutoffFreq); - - /// Sets number of FIR filter taps, i.e. ~filter complexity - void setLength(uint newLength); - - uint getLength() const; - - /// Applies the filter to the given sequence of samples. - /// Note : The amount of outputted samples is by value of 'filter length' - /// smaller than the amount of input samples. - uint evaluate(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples, - uint numChannels) const; -}; - -} - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like method +/// with several performance-increasing tweaks. +/// +/// Anti-alias filter is used to prevent folding of high frequencies when +/// transposing the sample rate with interpolation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: AAFilter.h,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef AAFilter_H +#define AAFilter_H + +#include "STTypes.h" + +namespace soundtouch +{ + +class AAFilter +{ +protected: + class FIRFilter *pFIR; + + /// Low-pass filter cut-off frequency, negative = invalid + double cutoffFreq; + + /// num of filter taps + uint length; + + /// Calculate the FIR coefficients realizing the given cutoff-frequency + void calculateCoeffs(); +public: + AAFilter(uint length); + + ~AAFilter(); + + /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling + /// frequency (nyquist frequency = 0.5). The filter will cut off the + /// frequencies than that. + void setCutoffFreq(double newCutoffFreq); + + /// Sets number of FIR filter taps, i.e. ~filter complexity + void setLength(uint newLength); + + uint getLength() const; + + /// Applies the filter to the given sequence of samples. + /// Note : The amount of outputted samples is by value of 'filter length' + /// smaller than the amount of input samples. + uint evaluate(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples, + uint numChannels) const; +}; + +} + +#endif diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/BPMDetect.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/BPMDetect.h index ac616e7e2b..b5e393979d 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/BPMDetect.h +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/BPMDetect.h @@ -1,159 +1,159 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Beats-per-minute (BPM) detection routine. -/// -/// The beat detection algorithm works as follows: -/// - Use function 'inputSamples' to input a chunks of samples to the class for -/// analysis. It's a good idea to enter a large sound file or stream in smallish -/// chunks of around few kilosamples in order not to extinguish too much RAM memory. -/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden, -/// which is basically ok as low (bass) frequencies mostly determine the beat rate. -/// Simple averaging is used for anti-alias filtering because the resulting signal -/// quality isn't of that high importance. -/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by -/// taking absolute value that's smoothed by sliding average. Signal levels that -/// are below a couple of times the general RMS amplitude level are cut away to -/// leave only notable peaks there. -/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term -/// autocorrelation function of the enveloped signal. -/// - After whole sound data file has been analyzed as above, the bpm level is -/// detected by function 'getBpm' that finds the highest peak of the autocorrelation -/// function, calculates it's precise location and converts this reading to bpm's. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.5 $ -// -// $Id: BPMDetect.h,v 1.5 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef _BPMDetect_H_ -#define _BPMDetect_H_ - -#include "STTypes.h" -#include "FIFOSampleBuffer.h" - -/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit. -#define MIN_BPM 45 - -/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit. -#define MAX_BPM 230 - - -/// Class for calculating BPM rate for audio data. -class BPMDetect -{ -protected: - /// Auto-correlation accumulator bins. - float *xcorr; - - /// Amplitude envelope sliding average approximation level accumulator - float envelopeAccu; - - /// RMS volume sliding average approximation level accumulator - float RMSVolumeAccu; - - /// Sample average counter. - int decimateCount; - - /// Sample average accumulator for FIFO-like decimation. - soundtouch::LONG_SAMPLETYPE decimateSum; - - /// Decimate sound by this coefficient to reach approx. 500 Hz. - int decimateBy; - - /// Auto-correlation window length - int windowLen; - - /// Number of channels (1 = mono, 2 = stereo) - int channels; - - /// sample rate - int sampleRate; - - /// Beginning of auto-correlation window: Autocorrelation isn't being updated for - /// the first these many correlation bins. - int windowStart; - - /// FIFO-buffer for decimated processing samples. - soundtouch::FIFOSampleBuffer *buffer; - - /// Initialize the class for processing. - void init(int numChannels, int sampleRate); - - /// Updates auto-correlation function for given number of decimated samples that - /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe - /// though). - void updateXCorr(int process_samples /// How many samples are processed. - ); - - /// Decimates samples to approx. 500 Hz. - /// - /// \return Number of output samples. - int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer - const soundtouch::SAMPLETYPE *src, ///< Source sample buffer - int numsamples ///< Number of source samples. - ); - - /// Calculates amplitude envelope for the buffer of samples. - /// Result is output to 'samples'. - void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer - int numsamples ///< Number of samples in buffer - ); - -public: - /// Constructor. - BPMDetect(int numChannels, ///< Number of channels in sample data. - int sampleRate ///< Sample rate in Hz. - ); - - /// Destructor. - virtual ~BPMDetect(); - - /// Inputs a block of samples for analyzing: Envelopes the samples and then - /// updates the autocorrelation estimation. When whole song data has been input - /// in smaller blocks using this function, read the resulting bpm with 'getBpm' - /// function. - /// - /// Notice that data in 'samples' array can be disrupted in processing. - void inputSamples(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer - int numSamples ///< Number of samples in buffer - ); - - - /// Analyzes the results and returns the BPM rate. Use this function to read result - /// after whole song data has been input to the class by consecutive calls of - /// 'inputSamples' function. - /// - /// \return Beats-per-minute rate, or zero if detection failed. - float getBpm(); -}; - -#endif // _BPMDetect_H_ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Beats-per-minute (BPM) detection routine. +/// +/// The beat detection algorithm works as follows: +/// - Use function 'inputSamples' to input a chunks of samples to the class for +/// analysis. It's a good idea to enter a large sound file or stream in smallish +/// chunks of around few kilosamples in order not to extinguish too much RAM memory. +/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden, +/// which is basically ok as low (bass) frequencies mostly determine the beat rate. +/// Simple averaging is used for anti-alias filtering because the resulting signal +/// quality isn't of that high importance. +/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by +/// taking absolute value that's smoothed by sliding average. Signal levels that +/// are below a couple of times the general RMS amplitude level are cut away to +/// leave only notable peaks there. +/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term +/// autocorrelation function of the enveloped signal. +/// - After whole sound data file has been analyzed as above, the bpm level is +/// detected by function 'getBpm' that finds the highest peak of the autocorrelation +/// function, calculates it's precise location and converts this reading to bpm's. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.5 $ +// +// $Id: BPMDetect.h,v 1.5 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _BPMDetect_H_ +#define _BPMDetect_H_ + +#include "STTypes.h" +#include "FIFOSampleBuffer.h" + +/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit. +#define MIN_BPM 45 + +/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit. +#define MAX_BPM 230 + + +/// Class for calculating BPM rate for audio data. +class BPMDetect +{ +protected: + /// Auto-correlation accumulator bins. + float *xcorr; + + /// Amplitude envelope sliding average approximation level accumulator + float envelopeAccu; + + /// RMS volume sliding average approximation level accumulator + float RMSVolumeAccu; + + /// Sample average counter. + int decimateCount; + + /// Sample average accumulator for FIFO-like decimation. + soundtouch::LONG_SAMPLETYPE decimateSum; + + /// Decimate sound by this coefficient to reach approx. 500 Hz. + int decimateBy; + + /// Auto-correlation window length + int windowLen; + + /// Number of channels (1 = mono, 2 = stereo) + int channels; + + /// sample rate + int sampleRate; + + /// Beginning of auto-correlation window: Autocorrelation isn't being updated for + /// the first these many correlation bins. + int windowStart; + + /// FIFO-buffer for decimated processing samples. + soundtouch::FIFOSampleBuffer *buffer; + + /// Initialize the class for processing. + void init(int numChannels, int sampleRate); + + /// Updates auto-correlation function for given number of decimated samples that + /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe + /// though). + void updateXCorr(int process_samples /// How many samples are processed. + ); + + /// Decimates samples to approx. 500 Hz. + /// + /// \return Number of output samples. + int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer + const soundtouch::SAMPLETYPE *src, ///< Source sample buffer + int numsamples ///< Number of source samples. + ); + + /// Calculates amplitude envelope for the buffer of samples. + /// Result is output to 'samples'. + void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer + int numsamples ///< Number of samples in buffer + ); + +public: + /// Constructor. + BPMDetect(int numChannels, ///< Number of channels in sample data. + int sampleRate ///< Sample rate in Hz. + ); + + /// Destructor. + virtual ~BPMDetect(); + + /// Inputs a block of samples for analyzing: Envelopes the samples and then + /// updates the autocorrelation estimation. When whole song data has been input + /// in smaller blocks using this function, read the resulting bpm with 'getBpm' + /// function. + /// + /// Notice that data in 'samples' array can be disrupted in processing. + void inputSamples(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer + int numSamples ///< Number of samples in buffer + ); + + + /// Analyzes the results and returns the BPM rate. Use this function to read result + /// after whole song data has been input to the class by consecutive calls of + /// 'inputSamples' function. + /// + /// \return Beats-per-minute rate, or zero if detection failed. + float getBpm(); +}; + +#endif // _BPMDetect_H_ diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSampleBuffer.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSampleBuffer.cpp index 2bf965b763..a8918a8133 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSampleBuffer.cpp +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSampleBuffer.cpp @@ -1,252 +1,252 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// A buffer class for temporarily storaging sound samples, operates as a -/// first-in-first-out pipe. -/// -/// Samples are added to the end of the sample buffer with the 'putSamples' -/// function, and are received from the beginning of the buffer by calling -/// the 'receiveSamples' function. The class automatically removes the -/// outputted samples from the buffer, as well as grows the buffer size -/// whenever necessary. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.11 $ -// -// $Id: FIFOSampleBuffer.cpp,v 1.11 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include - -#include "FIFOSampleBuffer.h" - -using namespace soundtouch; - -// Constructor -FIFOSampleBuffer::FIFOSampleBuffer(uint numChannels) -{ - sizeInBytes = 0; // reasonable initial value - buffer = NULL; //new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE)]; - bufferUnaligned = NULL; - samplesInBuffer = 0; - bufferPos = 0; - channels = numChannels; -} - - -// destructor -FIFOSampleBuffer::~FIFOSampleBuffer() -{ - delete[] bufferUnaligned; -} - - -// Sets number of channels, 1 = mono, 2 = stereo -void FIFOSampleBuffer::setChannels(const uint numChannels) -{ - uint usedBytes; - - usedBytes = channels * samplesInBuffer; - channels = numChannels; - samplesInBuffer = usedBytes / channels; -} - - -// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and -// zeroes this pointer by copying samples from the 'bufferPos' pointer -// location on to the beginning of the buffer. -void FIFOSampleBuffer::rewind() -{ - if (bufferPos) - { - memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer); - bufferPos = 0; - } -} - - -// Adds 'numSamples' pcs of samples from the 'samples' memory position to -// the sample buffer. -void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint numSamples) -{ - memcpy(ptrEnd(numSamples), samples, sizeof(SAMPLETYPE) * numSamples * channels); - samplesInBuffer += numSamples; -} - - -// Increases the number of samples in the buffer without copying any actual -// samples. -// -// This function is used to update the number of samples in the sample buffer -// when accessing the buffer directly with 'ptrEnd' function. Please be -// careful though! -void FIFOSampleBuffer::putSamples(uint numSamples) -{ - uint req; - - req = samplesInBuffer + numSamples; - ensureCapacity(req); - samplesInBuffer += numSamples; -} - - -// Returns a pointer to the end of the used part of the sample buffer (i.e. -// where the new samples are to be inserted). This function may be used for -// inserting new samples into the sample buffer directly. Please be careful! -// -// Parameter 'slackCapacity' tells the function how much free capacity (in -// terms of samples) there _at least_ should be, in order to the caller to -// succesfully insert all the required samples to the buffer. When necessary, -// the function grows the buffer size to comply with this requirement. -// -// When using this function as means for inserting new samples, also remember -// to increase the sample count afterwards, by calling the -// 'putSamples(numSamples)' function. -SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity) -{ - ensureCapacity(samplesInBuffer + slackCapacity); - return buffer + samplesInBuffer * channels; -} - - -// Returns a pointer to the beginning of the currently non-outputted samples. -// This function is provided for accessing the output samples directly. -// Please be careful! -// -// When using this function to output samples, also remember to 'remove' the -// outputted samples from the buffer by calling the -// 'receiveSamples(numSamples)' function -SAMPLETYPE *FIFOSampleBuffer::ptrBegin() const -{ - return buffer + bufferPos * channels; -} - - -// Ensures that the buffer has enought capacity, i.e. space for _at least_ -// 'capacityRequirement' number of samples. The buffer is grown in steps of -// 4 kilobytes to eliminate the need for frequently growing up the buffer, -// as well as to round the buffer size up to the virtual memory page size. -void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement) -{ - SAMPLETYPE *tempUnaligned, *temp; - - if (capacityRequirement > getCapacity()) - { - // enlarge the buffer in 4kbyte steps (round up to next 4k boundary) - sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & -4096; - assert(sizeInBytes % 2 == 0); - tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; - if (tempUnaligned == NULL) - { - throw std::runtime_error("Couldn't allocate memory!\n"); - } - temp = (SAMPLETYPE *)(((ulongptr)tempUnaligned + 15) & -16); - memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE)); - delete[] bufferUnaligned; - buffer = temp; - bufferUnaligned = tempUnaligned; - bufferPos = 0; - } - else - { - // simply rewind the buffer (if necessary) - rewind(); - } -} - - -// Returns the current buffer capacity in terms of samples -uint FIFOSampleBuffer::getCapacity() const -{ - return sizeInBytes / (channels * sizeof(SAMPLETYPE)); -} - - -// Returns the number of samples currently in the buffer -uint FIFOSampleBuffer::numSamples() const -{ - return samplesInBuffer; -} - - -// Output samples from beginning of the sample buffer. Copies demanded number -// of samples to output and removes them from the sample buffer. If there -// are less than 'numsample' samples in the buffer, returns all available. -// -// Returns number of samples copied. -uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples) -{ - uint num; - - num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples; - - memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num); - return receiveSamples(num); -} - - -// Removes samples from the beginning of the sample buffer without copying them -// anywhere. Used to reduce the number of samples in the buffer, when accessing -// the sample buffer with the 'ptrBegin' function. -uint FIFOSampleBuffer::receiveSamples(uint maxSamples) -{ - if (maxSamples >= samplesInBuffer) - { - uint temp; - - temp = samplesInBuffer; - samplesInBuffer = 0; - return temp; - } - - samplesInBuffer -= maxSamples; - bufferPos += maxSamples; - - return maxSamples; -} - - -// Returns nonzero if the sample buffer is empty -int FIFOSampleBuffer::isEmpty() const -{ - return (samplesInBuffer == 0) ? 1 : 0; -} - - -// Clears the sample buffer -void FIFOSampleBuffer::clear() -{ - samplesInBuffer = 0; - bufferPos = 0; -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// A buffer class for temporarily storaging sound samples, operates as a +/// first-in-first-out pipe. +/// +/// Samples are added to the end of the sample buffer with the 'putSamples' +/// function, and are received from the beginning of the buffer by calling +/// the 'receiveSamples' function. The class automatically removes the +/// outputted samples from the buffer, as well as grows the buffer size +/// whenever necessary. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.11 $ +// +// $Id: FIFOSampleBuffer.cpp,v 1.11 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include "FIFOSampleBuffer.h" + +using namespace soundtouch; + +// Constructor +FIFOSampleBuffer::FIFOSampleBuffer(uint numChannels) +{ + sizeInBytes = 0; // reasonable initial value + buffer = NULL; //new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE)]; + bufferUnaligned = NULL; + samplesInBuffer = 0; + bufferPos = 0; + channels = numChannels; +} + + +// destructor +FIFOSampleBuffer::~FIFOSampleBuffer() +{ + delete[] bufferUnaligned; +} + + +// Sets number of channels, 1 = mono, 2 = stereo +void FIFOSampleBuffer::setChannels(const uint numChannels) +{ + uint usedBytes; + + usedBytes = channels * samplesInBuffer; + channels = numChannels; + samplesInBuffer = usedBytes / channels; +} + + +// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and +// zeroes this pointer by copying samples from the 'bufferPos' pointer +// location on to the beginning of the buffer. +void FIFOSampleBuffer::rewind() +{ + if (bufferPos) + { + memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer); + bufferPos = 0; + } +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position to +// the sample buffer. +void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + memcpy(ptrEnd(numSamples), samples, sizeof(SAMPLETYPE) * numSamples * channels); + samplesInBuffer += numSamples; +} + + +// Increases the number of samples in the buffer without copying any actual +// samples. +// +// This function is used to update the number of samples in the sample buffer +// when accessing the buffer directly with 'ptrEnd' function. Please be +// careful though! +void FIFOSampleBuffer::putSamples(uint numSamples) +{ + uint req; + + req = samplesInBuffer + numSamples; + ensureCapacity(req); + samplesInBuffer += numSamples; +} + + +// Returns a pointer to the end of the used part of the sample buffer (i.e. +// where the new samples are to be inserted). This function may be used for +// inserting new samples into the sample buffer directly. Please be careful! +// +// Parameter 'slackCapacity' tells the function how much free capacity (in +// terms of samples) there _at least_ should be, in order to the caller to +// succesfully insert all the required samples to the buffer. When necessary, +// the function grows the buffer size to comply with this requirement. +// +// When using this function as means for inserting new samples, also remember +// to increase the sample count afterwards, by calling the +// 'putSamples(numSamples)' function. +SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity) +{ + ensureCapacity(samplesInBuffer + slackCapacity); + return buffer + samplesInBuffer * channels; +} + + +// Returns a pointer to the beginning of the currently non-outputted samples. +// This function is provided for accessing the output samples directly. +// Please be careful! +// +// When using this function to output samples, also remember to 'remove' the +// outputted samples from the buffer by calling the +// 'receiveSamples(numSamples)' function +SAMPLETYPE *FIFOSampleBuffer::ptrBegin() const +{ + return buffer + bufferPos * channels; +} + + +// Ensures that the buffer has enought capacity, i.e. space for _at least_ +// 'capacityRequirement' number of samples. The buffer is grown in steps of +// 4 kilobytes to eliminate the need for frequently growing up the buffer, +// as well as to round the buffer size up to the virtual memory page size. +void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement) +{ + SAMPLETYPE *tempUnaligned, *temp; + + if (capacityRequirement > getCapacity()) + { + // enlarge the buffer in 4kbyte steps (round up to next 4k boundary) + sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & -4096; + assert(sizeInBytes % 2 == 0); + tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; + if (tempUnaligned == NULL) + { + throw std::runtime_error("Couldn't allocate memory!\n"); + } + temp = (SAMPLETYPE *)(((ulongptr)tempUnaligned + 15) & -16); + memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE)); + delete[] bufferUnaligned; + buffer = temp; + bufferUnaligned = tempUnaligned; + bufferPos = 0; + } + else + { + // simply rewind the buffer (if necessary) + rewind(); + } +} + + +// Returns the current buffer capacity in terms of samples +uint FIFOSampleBuffer::getCapacity() const +{ + return sizeInBytes / (channels * sizeof(SAMPLETYPE)); +} + + +// Returns the number of samples currently in the buffer +uint FIFOSampleBuffer::numSamples() const +{ + return samplesInBuffer; +} + + +// Output samples from beginning of the sample buffer. Copies demanded number +// of samples to output and removes them from the sample buffer. If there +// are less than 'numsample' samples in the buffer, returns all available. +// +// Returns number of samples copied. +uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples) +{ + uint num; + + num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples; + + memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num); + return receiveSamples(num); +} + + +// Removes samples from the beginning of the sample buffer without copying them +// anywhere. Used to reduce the number of samples in the buffer, when accessing +// the sample buffer with the 'ptrBegin' function. +uint FIFOSampleBuffer::receiveSamples(uint maxSamples) +{ + if (maxSamples >= samplesInBuffer) + { + uint temp; + + temp = samplesInBuffer; + samplesInBuffer = 0; + return temp; + } + + samplesInBuffer -= maxSamples; + bufferPos += maxSamples; + + return maxSamples; +} + + +// Returns nonzero if the sample buffer is empty +int FIFOSampleBuffer::isEmpty() const +{ + return (samplesInBuffer == 0) ? 1 : 0; +} + + +// Clears the sample buffer +void FIFOSampleBuffer::clear() +{ + samplesInBuffer = 0; + bufferPos = 0; +} diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSampleBuffer.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSampleBuffer.h index 09f74c9a65..bcbfb59d4e 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSampleBuffer.h +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSampleBuffer.h @@ -1,174 +1,174 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// A buffer class for temporarily storaging sound samples, operates as a -/// first-in-first-out pipe. -/// -/// Samples are added to the end of the sample buffer with the 'putSamples' -/// function, and are received from the beginning of the buffer by calling -/// the 'receiveSamples' function. The class automatically removes the -/// output samples from the buffer as well as grows the storage size -/// whenever necessary. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.9 $ -// -// $Id: FIFOSampleBuffer.h,v 1.9 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef FIFOSampleBuffer_H -#define FIFOSampleBuffer_H - -#include "FIFOSamplePipe.h" - -namespace soundtouch -{ - -/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes -/// care of storage size adjustment and data moving during input/output operations. -/// -/// Notice that in case of stereo audio, one sample is considered to consist of -/// both channel data. -class FIFOSampleBuffer : public FIFOSamplePipe -{ -private: - /// Sample buffer. - SAMPLETYPE *buffer; - - // Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first - // 16-byte aligned location of this buffer - SAMPLETYPE *bufferUnaligned; - - /// Sample buffer size in bytes - uint sizeInBytes; - - /// How many samples are currently in buffer. - uint samplesInBuffer; - - /// Channels, 1=mono, 2=stereo. - uint channels; - - /// Current position pointer to the buffer. This pointer is increased when samples are - /// removed from the pipe so that it's necessary to actually rewind buffer (move data) - /// only new data when is put to the pipe. - uint bufferPos; - - /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real - /// beginning of the buffer. - void rewind(); - - /// Ensures that the buffer has capacity for at least this many samples. - void ensureCapacity(const uint capacityRequirement); - - /// Returns current capacity. - uint getCapacity() const; - -public: - - /// Constructor - FIFOSampleBuffer(uint numChannels = 2 ///< Number of channels, 1=mono, 2=stereo. - ///< Default is stereo. - ); - - /// destructor - ~FIFOSampleBuffer(); - - /// Returns a pointer to the beginning of the output samples. - /// This function is provided for accessing the output samples directly. - /// Please be careful for not to corrupt the book-keeping! - /// - /// When using this function to output samples, also remember to 'remove' the - /// output samples from the buffer by calling the - /// 'receiveSamples(numSamples)' function - virtual SAMPLETYPE *ptrBegin() const; - - /// Returns a pointer to the end of the used part of the sample buffer (i.e. - /// where the new samples are to be inserted). This function may be used for - /// inserting new samples into the sample buffer directly. Please be careful - /// not corrupt the book-keeping! - /// - /// When using this function as means for inserting new samples, also remember - /// to increase the sample count afterwards, by calling the - /// 'putSamples(numSamples)' function. - SAMPLETYPE *ptrEnd( - uint slackCapacity ///< How much free capacity (in samples) there _at least_ - ///< should be so that the caller can succesfully insert the - ///< desired samples to the buffer. If necessary, the function - ///< grows the buffer size to comply with this requirement. - ); - - /// Adds 'numSamples' pcs of samples from the 'samples' memory position to - /// the sample buffer. - virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. - uint numSamples ///< Number of samples to insert. - ); - - /// Adjusts the book-keeping to increase number of samples in the buffer without - /// copying any actual samples. - /// - /// This function is used to update the number of samples in the sample buffer - /// when accessing the buffer directly with 'ptrEnd' function. Please be - /// careful though! - virtual void putSamples(uint numSamples ///< Number of samples been inserted. - ); - - /// Output samples from beginning of the sample buffer. Copies requested samples to - /// output buffer and removes them from the sample buffer. If there are less than - /// 'numsample' samples in the buffer, returns all that available. - /// - /// \return Number of samples returned. - virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. - uint maxSamples ///< How many samples to receive at max. - ); - - /// Adjusts book-keeping so that given number of samples are removed from beginning of the - /// sample buffer without copying them anywhere. - /// - /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly - /// with 'ptrBegin' function. - virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. - ); - - /// Returns number of samples currently available. - virtual uint numSamples() const; - - /// Sets number of channels, 1 = mono, 2 = stereo. - void setChannels(uint numChannels); - - /// Returns nonzero if there aren't any samples available for outputting. - virtual int isEmpty() const; - - /// Clears all the samples. - virtual void clear(); -}; - -} - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// A buffer class for temporarily storaging sound samples, operates as a +/// first-in-first-out pipe. +/// +/// Samples are added to the end of the sample buffer with the 'putSamples' +/// function, and are received from the beginning of the buffer by calling +/// the 'receiveSamples' function. The class automatically removes the +/// output samples from the buffer as well as grows the storage size +/// whenever necessary. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.9 $ +// +// $Id: FIFOSampleBuffer.h,v 1.9 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIFOSampleBuffer_H +#define FIFOSampleBuffer_H + +#include "FIFOSamplePipe.h" + +namespace soundtouch +{ + +/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes +/// care of storage size adjustment and data moving during input/output operations. +/// +/// Notice that in case of stereo audio, one sample is considered to consist of +/// both channel data. +class FIFOSampleBuffer : public FIFOSamplePipe +{ +private: + /// Sample buffer. + SAMPLETYPE *buffer; + + // Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first + // 16-byte aligned location of this buffer + SAMPLETYPE *bufferUnaligned; + + /// Sample buffer size in bytes + uint sizeInBytes; + + /// How many samples are currently in buffer. + uint samplesInBuffer; + + /// Channels, 1=mono, 2=stereo. + uint channels; + + /// Current position pointer to the buffer. This pointer is increased when samples are + /// removed from the pipe so that it's necessary to actually rewind buffer (move data) + /// only new data when is put to the pipe. + uint bufferPos; + + /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real + /// beginning of the buffer. + void rewind(); + + /// Ensures that the buffer has capacity for at least this many samples. + void ensureCapacity(const uint capacityRequirement); + + /// Returns current capacity. + uint getCapacity() const; + +public: + + /// Constructor + FIFOSampleBuffer(uint numChannels = 2 ///< Number of channels, 1=mono, 2=stereo. + ///< Default is stereo. + ); + + /// destructor + ~FIFOSampleBuffer(); + + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const; + + /// Returns a pointer to the end of the used part of the sample buffer (i.e. + /// where the new samples are to be inserted). This function may be used for + /// inserting new samples into the sample buffer directly. Please be careful + /// not corrupt the book-keeping! + /// + /// When using this function as means for inserting new samples, also remember + /// to increase the sample count afterwards, by calling the + /// 'putSamples(numSamples)' function. + SAMPLETYPE *ptrEnd( + uint slackCapacity ///< How much free capacity (in samples) there _at least_ + ///< should be so that the caller can succesfully insert the + ///< desired samples to the buffer. If necessary, the function + ///< grows the buffer size to comply with this requirement. + ); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position to + /// the sample buffer. + virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. + uint numSamples ///< Number of samples to insert. + ); + + /// Adjusts the book-keeping to increase number of samples in the buffer without + /// copying any actual samples. + /// + /// This function is used to update the number of samples in the sample buffer + /// when accessing the buffer directly with 'ptrEnd' function. Please be + /// careful though! + virtual void putSamples(uint numSamples ///< Number of samples been inserted. + ); + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ); + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ); + + /// Returns number of samples currently available. + virtual uint numSamples() const; + + /// Sets number of channels, 1 = mono, 2 = stereo. + void setChannels(uint numChannels); + + /// Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const; + + /// Clears all the samples. + virtual void clear(); +}; + +} + +#endif diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSamplePipe.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSamplePipe.h index 33e33c7e36..e10b8b26c8 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSamplePipe.h +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSamplePipe.h @@ -1,217 +1,217 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound -/// samples by operating like a first-in-first-out pipe: New samples are fed -/// into one end of the pipe with the 'putSamples' function, and the processed -/// samples are received from the other end with the 'receiveSamples' function. -/// -/// 'FIFOProcessor' : A base class for classes the do signal processing with -/// the samples while operating like a first-in-first-out pipe. When samples -/// are input with the 'putSamples' function, the class processes them -/// and moves the processed samples to the given 'output' pipe object, which -/// may be either another processing stage, or a fifo sample buffer object. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.8 $ -// -// $Id: FIFOSamplePipe.h,v 1.8 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef FIFOSamplePipe_H -#define FIFOSamplePipe_H - -#include -#include -#include "STTypes.h" - -namespace soundtouch -{ - -/// Abstract base class for FIFO (first-in-first-out) sample processing classes. -class FIFOSamplePipe -{ -public: - /// Returns a pointer to the beginning of the output samples. - /// This function is provided for accessing the output samples directly. - /// Please be careful for not to corrupt the book-keeping! - /// - /// When using this function to output samples, also remember to 'remove' the - /// output samples from the buffer by calling the - /// 'receiveSamples(numSamples)' function - virtual SAMPLETYPE *ptrBegin() const = 0; - - /// Adds 'numSamples' pcs of samples from the 'samples' memory position to - /// the sample buffer. - virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. - uint numSamples ///< Number of samples to insert. - ) = 0; - - - // Moves samples from the 'other' pipe instance to this instance. - void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data. - ) - { - int oNumSamples = other.numSamples(); - - putSamples(other.ptrBegin(), oNumSamples); - other.receiveSamples(oNumSamples); - }; - - /// Output samples from beginning of the sample buffer. Copies requested samples to - /// output buffer and removes them from the sample buffer. If there are less than - /// 'numsample' samples in the buffer, returns all that available. - /// - /// \return Number of samples returned. - virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. - uint maxSamples ///< How many samples to receive at max. - ) = 0; - - /// Adjusts book-keeping so that given number of samples are removed from beginning of the - /// sample buffer without copying them anywhere. - /// - /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly - /// with 'ptrBegin' function. - virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. - ) = 0; - - /// Returns number of samples currently available. - virtual uint numSamples() const = 0; - - // Returns nonzero if there aren't any samples available for outputting. - virtual int isEmpty() const = 0; - - /// Clears all the samples. - virtual void clear() = 0; -}; - - - -/// Base-class for sound processing routines working in FIFO principle. With this base -/// class it's easy to implement sound processing stages that can be chained together, -/// so that samples that are fed into beginning of the pipe automatically go through -/// all the processing stages. -/// -/// When samples are input to this class, they're first processed and then put to -/// the FIFO pipe that's defined as output of this class. This output pipe can be -/// either other processing stage or a FIFO sample buffer. -class FIFOProcessor :public FIFOSamplePipe -{ -protected: - /// Internal pipe where processed samples are put. - FIFOSamplePipe *output; - - /// Sets output pipe. - void setOutPipe(FIFOSamplePipe *pOutput) - { - assert(output == NULL); - assert(pOutput != NULL); - output = pOutput; - } - - - /// Constructor. Doesn't define output pipe; it has to be set be - /// 'setOutPipe' function. - FIFOProcessor() - { - output = NULL; - } - - - /// Constructor. Configures output pipe. - FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe. - ) - { - output = pOutput; - } - - - /// Destructor. - virtual ~FIFOProcessor() - { - } - - - /// Returns a pointer to the beginning of the output samples. - /// This function is provided for accessing the output samples directly. - /// Please be careful for not to corrupt the book-keeping! - /// - /// When using this function to output samples, also remember to 'remove' the - /// output samples from the buffer by calling the - /// 'receiveSamples(numSamples)' function - virtual SAMPLETYPE *ptrBegin() const - { - return output->ptrBegin(); - } - -public: - - /// Output samples from beginning of the sample buffer. Copies requested samples to - /// output buffer and removes them from the sample buffer. If there are less than - /// 'numsample' samples in the buffer, returns all that available. - /// - /// \return Number of samples returned. - virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples. - uint maxSamples ///< How many samples to receive at max. - ) - { - return output->receiveSamples(outBuffer, maxSamples); - } - - - /// Adjusts book-keeping so that given number of samples are removed from beginning of the - /// sample buffer without copying them anywhere. - /// - /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly - /// with 'ptrBegin' function. - virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. - ) - { - return output->receiveSamples(maxSamples); - } - - - /// Returns number of samples currently available. - virtual uint numSamples() const - { - return output->numSamples(); - } - - - /// Returns nonzero if there aren't any samples available for outputting. - virtual int isEmpty() const - { - return output->isEmpty(); - } -}; - -} - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound +/// samples by operating like a first-in-first-out pipe: New samples are fed +/// into one end of the pipe with the 'putSamples' function, and the processed +/// samples are received from the other end with the 'receiveSamples' function. +/// +/// 'FIFOProcessor' : A base class for classes the do signal processing with +/// the samples while operating like a first-in-first-out pipe. When samples +/// are input with the 'putSamples' function, the class processes them +/// and moves the processed samples to the given 'output' pipe object, which +/// may be either another processing stage, or a fifo sample buffer object. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.8 $ +// +// $Id: FIFOSamplePipe.h,v 1.8 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIFOSamplePipe_H +#define FIFOSamplePipe_H + +#include +#include +#include "STTypes.h" + +namespace soundtouch +{ + +/// Abstract base class for FIFO (first-in-first-out) sample processing classes. +class FIFOSamplePipe +{ +public: + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const = 0; + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position to + /// the sample buffer. + virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. + uint numSamples ///< Number of samples to insert. + ) = 0; + + + // Moves samples from the 'other' pipe instance to this instance. + void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data. + ) + { + int oNumSamples = other.numSamples(); + + putSamples(other.ptrBegin(), oNumSamples); + other.receiveSamples(oNumSamples); + }; + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ) = 0; + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ) = 0; + + /// Returns number of samples currently available. + virtual uint numSamples() const = 0; + + // Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const = 0; + + /// Clears all the samples. + virtual void clear() = 0; +}; + + + +/// Base-class for sound processing routines working in FIFO principle. With this base +/// class it's easy to implement sound processing stages that can be chained together, +/// so that samples that are fed into beginning of the pipe automatically go through +/// all the processing stages. +/// +/// When samples are input to this class, they're first processed and then put to +/// the FIFO pipe that's defined as output of this class. This output pipe can be +/// either other processing stage or a FIFO sample buffer. +class FIFOProcessor :public FIFOSamplePipe +{ +protected: + /// Internal pipe where processed samples are put. + FIFOSamplePipe *output; + + /// Sets output pipe. + void setOutPipe(FIFOSamplePipe *pOutput) + { + assert(output == NULL); + assert(pOutput != NULL); + output = pOutput; + } + + + /// Constructor. Doesn't define output pipe; it has to be set be + /// 'setOutPipe' function. + FIFOProcessor() + { + output = NULL; + } + + + /// Constructor. Configures output pipe. + FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe. + ) + { + output = pOutput; + } + + + /// Destructor. + virtual ~FIFOProcessor() + { + } + + + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const + { + return output->ptrBegin(); + } + +public: + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ) + { + return output->receiveSamples(outBuffer, maxSamples); + } + + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ) + { + return output->receiveSamples(maxSamples); + } + + + /// Returns number of samples currently available. + virtual uint numSamples() const + { + return output->numSamples(); + } + + + /// Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const + { + return output->isEmpty(); + } +}; + +} + +#endif diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/FIRFilter.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIRFilter.cpp index ac57335a18..10a0bb0299 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/FIRFilter.cpp +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIRFilter.cpp @@ -1,272 +1,272 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// General FIR digital filter routines with MMX optimization. -/// -/// Note : MMX optimized functions reside in a separate, platform-specific file, -/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.16 $ -// -// $Id: FIRFilter.cpp,v 1.16 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include "FIRFilter.h" -#include "cpu_detect.h" - -using namespace soundtouch; - -/***************************************************************************** - * - * Implementation of the class 'FIRFilter' - * - *****************************************************************************/ - -FIRFilter::FIRFilter() -{ - resultDivFactor = 0; - length = 0; - lengthDiv8 = 0; - filterCoeffs = NULL; -} - - -FIRFilter::~FIRFilter() -{ - delete[] filterCoeffs; -} - -// Usual C-version of the filter routine for stereo sound -uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const -{ - uint i, j, end; - LONG_SAMPLETYPE suml, sumr; -#ifdef FLOAT_SAMPLES - // when using floating point samples, use a scaler instead of a divider - // because division is much slower operation than multiplying. - double dScaler = 1.0 / (double)resultDivider; -#endif - - assert(length != 0); - - end = 2 * (numSamples - length); - - for (j = 0; j < end; j += 2) - { - const SAMPLETYPE *ptr; - - suml = sumr = 0; - ptr = src + j; - - for (i = 0; i < length; i += 4) - { - // loop is unrolled by factor of 4 here for efficiency - suml += ptr[2 * i + 0] * filterCoeffs[i + 0] + - ptr[2 * i + 2] * filterCoeffs[i + 1] + - ptr[2 * i + 4] * filterCoeffs[i + 2] + - ptr[2 * i + 6] * filterCoeffs[i + 3]; - sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] + - ptr[2 * i + 3] * filterCoeffs[i + 1] + - ptr[2 * i + 5] * filterCoeffs[i + 2] + - ptr[2 * i + 7] * filterCoeffs[i + 3]; - } - -#ifdef INTEGER_SAMPLES - suml >>= resultDivFactor; - sumr >>= resultDivFactor; - // saturate to 16 bit integer limits - suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml; - // saturate to 16 bit integer limits - sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr; -#else - suml *= dScaler; - sumr *= dScaler; -#endif // INTEGER_SAMPLES - dest[j] = (SAMPLETYPE)suml; - dest[j + 1] = (SAMPLETYPE)sumr; - } - return numSamples - length; -} - - - - -// Usual C-version of the filter routine for mono sound -uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const -{ - uint i, j, end; - LONG_SAMPLETYPE sum; -#ifdef FLOAT_SAMPLES - // when using floating point samples, use a scaler instead of a divider - // because division is much slower operation than multiplying. - double dScaler = 1.0 / (double)resultDivider; -#endif - - - assert(length != 0); - - end = numSamples - length; - for (j = 0; j < end; j ++) - { - sum = 0; - for (i = 0; i < length; i += 4) - { - // loop is unrolled by factor of 4 here for efficiency - sum += src[i + 0] * filterCoeffs[i + 0] + - src[i + 1] * filterCoeffs[i + 1] + - src[i + 2] * filterCoeffs[i + 2] + - src[i + 3] * filterCoeffs[i + 3]; - } -#ifdef INTEGER_SAMPLES - sum >>= resultDivFactor; - // saturate to 16 bit integer limits - sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum; -#else - sum *= dScaler; -#endif // INTEGER_SAMPLES - dest[j] = (SAMPLETYPE)sum; - src ++; - } - return end; -} - - -// Set filter coeffiecients and length. -// -// Throws an exception if filter length isn't divisible by 8 -void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor) -{ - assert(newLength > 0); - if (newLength % 8) throw std::runtime_error("FIR filter length not divisible by 8"); - - lengthDiv8 = newLength / 8; - length = lengthDiv8 * 8; - assert(length == newLength); - - resultDivFactor = uResultDivFactor; -#ifdef INTEGER_SAMPLES - resultDivider = (SAMPLETYPE)(1< 0); - assert(lengthDiv8 * 8 == length); - if (numSamples < length) return 0; - assert(resultDivFactor >= 0); - if (numChannels == 2) - { - return evaluateFilterStereo(dest, src, numSamples); - } else { - return evaluateFilterMono(dest, src, numSamples); - } -} - - - -// Operator 'new' is overloaded so that it automatically creates a suitable instance -// depending on if we've a MMX-capable CPU available or not. -void * FIRFilter::operator new(size_t s) -{ - // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! - throw std::runtime_error("Don't use 'new FIRFilter', use 'newInstance' member instead!"); - return NULL; -} - - -FIRFilter * FIRFilter::newInstance() -{ - uint uExtensions = 0; - -#if !defined(_MSC_VER) || !defined(__x86_64__) - uExtensions = detectCPUextensions(); -#endif - - // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU - -#ifdef ALLOW_MMX - // MMX routines available only with integer sample types - if (uExtensions & SUPPORT_MMX) - { - return ::new FIRFilterMMX; - } - else -#endif // ALLOW_MMX - -#ifdef ALLOW_SSE - if (uExtensions & SUPPORT_SSE) - { - // SSE support - return ::new FIRFilterSSE; - } - else -#endif // ALLOW_SSE - -#ifdef ALLOW_3DNOW - if (uExtensions & SUPPORT_3DNOW) - { - // 3DNow! support - return ::new FIRFilter3DNow; - } - else -#endif // ALLOW_3DNOW - - { - // ISA optimizations not supported, use plain C version - return ::new FIRFilter; - } -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// General FIR digital filter routines with MMX optimization. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.16 $ +// +// $Id: FIRFilter.cpp,v 1.16 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include "FIRFilter.h" +#include "cpu_detect.h" + +using namespace soundtouch; + +/***************************************************************************** + * + * Implementation of the class 'FIRFilter' + * + *****************************************************************************/ + +FIRFilter::FIRFilter() +{ + resultDivFactor = 0; + length = 0; + lengthDiv8 = 0; + filterCoeffs = NULL; +} + + +FIRFilter::~FIRFilter() +{ + delete[] filterCoeffs; +} + +// Usual C-version of the filter routine for stereo sound +uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const +{ + uint i, j, end; + LONG_SAMPLETYPE suml, sumr; +#ifdef FLOAT_SAMPLES + // when using floating point samples, use a scaler instead of a divider + // because division is much slower operation than multiplying. + double dScaler = 1.0 / (double)resultDivider; +#endif + + assert(length != 0); + + end = 2 * (numSamples - length); + + for (j = 0; j < end; j += 2) + { + const SAMPLETYPE *ptr; + + suml = sumr = 0; + ptr = src + j; + + for (i = 0; i < length; i += 4) + { + // loop is unrolled by factor of 4 here for efficiency + suml += ptr[2 * i + 0] * filterCoeffs[i + 0] + + ptr[2 * i + 2] * filterCoeffs[i + 1] + + ptr[2 * i + 4] * filterCoeffs[i + 2] + + ptr[2 * i + 6] * filterCoeffs[i + 3]; + sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] + + ptr[2 * i + 3] * filterCoeffs[i + 1] + + ptr[2 * i + 5] * filterCoeffs[i + 2] + + ptr[2 * i + 7] * filterCoeffs[i + 3]; + } + +#ifdef INTEGER_SAMPLES + suml >>= resultDivFactor; + sumr >>= resultDivFactor; + // saturate to 16 bit integer limits + suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml; + // saturate to 16 bit integer limits + sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr; +#else + suml *= dScaler; + sumr *= dScaler; +#endif // INTEGER_SAMPLES + dest[j] = (SAMPLETYPE)suml; + dest[j + 1] = (SAMPLETYPE)sumr; + } + return numSamples - length; +} + + + + +// Usual C-version of the filter routine for mono sound +uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const +{ + uint i, j, end; + LONG_SAMPLETYPE sum; +#ifdef FLOAT_SAMPLES + // when using floating point samples, use a scaler instead of a divider + // because division is much slower operation than multiplying. + double dScaler = 1.0 / (double)resultDivider; +#endif + + + assert(length != 0); + + end = numSamples - length; + for (j = 0; j < end; j ++) + { + sum = 0; + for (i = 0; i < length; i += 4) + { + // loop is unrolled by factor of 4 here for efficiency + sum += src[i + 0] * filterCoeffs[i + 0] + + src[i + 1] * filterCoeffs[i + 1] + + src[i + 2] * filterCoeffs[i + 2] + + src[i + 3] * filterCoeffs[i + 3]; + } +#ifdef INTEGER_SAMPLES + sum >>= resultDivFactor; + // saturate to 16 bit integer limits + sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum; +#else + sum *= dScaler; +#endif // INTEGER_SAMPLES + dest[j] = (SAMPLETYPE)sum; + src ++; + } + return end; +} + + +// Set filter coeffiecients and length. +// +// Throws an exception if filter length isn't divisible by 8 +void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor) +{ + assert(newLength > 0); + if (newLength % 8) throw std::runtime_error("FIR filter length not divisible by 8"); + + lengthDiv8 = newLength / 8; + length = lengthDiv8 * 8; + assert(length == newLength); + + resultDivFactor = uResultDivFactor; +#ifdef INTEGER_SAMPLES + resultDivider = (SAMPLETYPE)(1< 0); + assert(lengthDiv8 * 8 == length); + if (numSamples < length) return 0; + assert(resultDivFactor >= 0); + if (numChannels == 2) + { + return evaluateFilterStereo(dest, src, numSamples); + } else { + return evaluateFilterMono(dest, src, numSamples); + } +} + + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX-capable CPU available or not. +void * FIRFilter::operator new(size_t s) +{ + // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! + throw std::runtime_error("Don't use 'new FIRFilter', use 'newInstance' member instead!"); + return NULL; +} + + +FIRFilter * FIRFilter::newInstance() +{ + uint uExtensions = 0; + +#if !defined(_MSC_VER) || !defined(__x86_64__) + uExtensions = detectCPUextensions(); +#endif + + // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU + +#ifdef ALLOW_MMX + // MMX routines available only with integer sample types + if (uExtensions & SUPPORT_MMX) + { + return ::new FIRFilterMMX; + } + else +#endif // ALLOW_MMX + +#ifdef ALLOW_SSE + if (uExtensions & SUPPORT_SSE) + { + // SSE support + return ::new FIRFilterSSE; + } + else +#endif // ALLOW_SSE + +#ifdef ALLOW_3DNOW + if (uExtensions & SUPPORT_3DNOW) + { + // 3DNow! support + return ::new FIRFilter3DNow; + } + else +#endif // ALLOW_3DNOW + + { + // ISA optimizations not supported, use plain C version + return ::new FIRFilter; + } +} diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/FIRFilter.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIRFilter.h index be5cdd2943..5e9b3410f8 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/FIRFilter.h +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIRFilter.h @@ -1,163 +1,163 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// General FIR digital filter routines with MMX optimization. -/// -/// Note : MMX optimized functions reside in a separate, platform-specific file, -/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.17 $ -// -// $Id: FIRFilter.h,v 1.17 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef FIRFilter_H -#define FIRFilter_H - -#include "STTypes.h" - -namespace soundtouch -{ - -class FIRFilter -{ -protected: - // Number of FIR filter taps - uint length; - // Number of FIR filter taps divided by 8 - uint lengthDiv8; - - // Result divider factor in 2^k format - uint resultDivFactor; - - // Result divider value. - SAMPLETYPE resultDivider; - - // Memory for filter coefficients - SAMPLETYPE *filterCoeffs; - - virtual uint evaluateFilterStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples) const; - virtual uint evaluateFilterMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples) const; - -public: - FIRFilter(); - virtual ~FIRFilter(); - - /// Operator 'new' is overloaded so that it automatically creates a suitable instance - /// depending on if we've a MMX-capable CPU available or not. - void * operator new(size_t s); - - static FIRFilter *newInstance(); - - /// Applies the filter to the given sequence of samples. - /// Note : The amount of outputted samples is by value of 'filter_length' - /// smaller than the amount of input samples. - /// - /// \return Number of samples copied to 'dest'. - uint evaluate(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples, - uint numChannels) const; - - uint getLength() const; - - virtual void setCoefficients(const SAMPLETYPE *coeffs, - uint newLength, - uint uResultDivFactor); -}; - - -// Optional subclasses that implement CPU-specific optimizations: - -#ifdef ALLOW_MMX - - /// Class that implements MMX optimized functions exclusive for 16bit integer samples type. - class FIRFilterMMX : public FIRFilter - { - protected: - short *filterCoeffsUnalign; - short *filterCoeffsAlign; - - virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const; - public: - FIRFilterMMX(); - ~FIRFilterMMX(); - - virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor); - }; - -#endif // ALLOW_MMX - - -#ifdef ALLOW_3DNOW - - /// Class that implements 3DNow! optimized functions exclusive for floating point samples type. - class FIRFilter3DNow : public FIRFilter - { - protected: - float *filterCoeffsUnalign; - float *filterCoeffsAlign; - - virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; - public: - FIRFilter3DNow(); - ~FIRFilter3DNow(); - virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); - }; - -#endif // ALLOW_3DNOW - - -#ifdef ALLOW_SSE - /// Class that implements SSE optimized functions exclusive for floating point samples type. - class FIRFilterSSE : public FIRFilter - { - protected: - float *filterCoeffsUnalign; - float *filterCoeffsAlign; - - virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; - public: - FIRFilterSSE(); - ~FIRFilterSSE(); - - virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); - }; - -#endif // ALLOW_SSE - -} - -#endif // FIRFilter_H +//////////////////////////////////////////////////////////////////////////////// +/// +/// General FIR digital filter routines with MMX optimization. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.17 $ +// +// $Id: FIRFilter.h,v 1.17 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIRFilter_H +#define FIRFilter_H + +#include "STTypes.h" + +namespace soundtouch +{ + +class FIRFilter +{ +protected: + // Number of FIR filter taps + uint length; + // Number of FIR filter taps divided by 8 + uint lengthDiv8; + + // Result divider factor in 2^k format + uint resultDivFactor; + + // Result divider value. + SAMPLETYPE resultDivider; + + // Memory for filter coefficients + SAMPLETYPE *filterCoeffs; + + virtual uint evaluateFilterStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) const; + virtual uint evaluateFilterMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) const; + +public: + FIRFilter(); + virtual ~FIRFilter(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we've a MMX-capable CPU available or not. + void * operator new(size_t s); + + static FIRFilter *newInstance(); + + /// Applies the filter to the given sequence of samples. + /// Note : The amount of outputted samples is by value of 'filter_length' + /// smaller than the amount of input samples. + /// + /// \return Number of samples copied to 'dest'. + uint evaluate(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples, + uint numChannels) const; + + uint getLength() const; + + virtual void setCoefficients(const SAMPLETYPE *coeffs, + uint newLength, + uint uResultDivFactor); +}; + + +// Optional subclasses that implement CPU-specific optimizations: + +#ifdef ALLOW_MMX + + /// Class that implements MMX optimized functions exclusive for 16bit integer samples type. + class FIRFilterMMX : public FIRFilter + { + protected: + short *filterCoeffsUnalign; + short *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const; + public: + FIRFilterMMX(); + ~FIRFilterMMX(); + + virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // ALLOW_MMX + + +#ifdef ALLOW_3DNOW + + /// Class that implements 3DNow! optimized functions exclusive for floating point samples type. + class FIRFilter3DNow : public FIRFilter + { + protected: + float *filterCoeffsUnalign; + float *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; + public: + FIRFilter3DNow(); + ~FIRFilter3DNow(); + virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // ALLOW_3DNOW + + +#ifdef ALLOW_SSE + /// Class that implements SSE optimized functions exclusive for floating point samples type. + class FIRFilterSSE : public FIRFilter + { + protected: + float *filterCoeffsUnalign; + float *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; + public: + FIRFilterSSE(); + ~FIRFilterSSE(); + + virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // ALLOW_SSE + +} + +#endif // FIRFilter_H diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/Makefile.am b/plugins/spu2ghz/src/3rdparty/SoundTouch/Makefile.am index a09ae5f081..8e1d6d4bbf 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/Makefile.am +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/Makefile.am @@ -1,46 +1,46 @@ -## Process this file with automake to create Makefile.in -## -## $Id: Makefile.am,v 1.3 2006/02/05 18:33:34 Olli Exp $ -## -## Copyright (C) 2003 - David W. Durham -## -## This file is part of SoundTouch, an audio processing library for pitch/time adjustments -## -## SoundTouch 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. -## -## SoundTouch 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 - -AUTOMAKE_OPTIONS = foreign - -noinst_HEADERS=AAFilter.h cpu_detect.h FIRFilter.h RateTransposer.h TDStretch.h cpu_detect_x86_gcc.cpp -noinst_LIBRARIES = libSoundTouch.a - -if X86_64 -libSoundTouch_a_CXXFLAGS = -fPIC -libSoundTouch_a_CFLAGS = -fPIC -else -libSoundTouch_a_CXXFLAGS = -msse -mmmx -libSoundTouch_a_CFLAGS = -msse -mmmx -endif - -#lib_LTLIBRARIES=libSoundTouch.la -# the mmx_gcc.cpp and cpu_detect_x86_gcc.cpp may need to be conditionally included here from things discovered in configure.ac -libSoundTouch_a_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp mmx_optimized.cpp sse_optimized.cpp \ -RateTransposer.cpp SoundTouch.cpp TDStretch.cpp WavFile.cpp cpu_detect_x86_gcc.cpp - -# ??? test for -fcheck-new in configure.ac -# other compiler flags to add -AM_CXXFLAGS=-O3 -msse -fcheck-new -I../../include - -# other linking flags to add -#libSoundTouch_la_LIBADD= - +## Process this file with automake to create Makefile.in +## +## $Id: Makefile.am,v 1.3 2006/02/05 18:33:34 Olli Exp $ +## +## Copyright (C) 2003 - David W. Durham +## +## This file is part of SoundTouch, an audio processing library for pitch/time adjustments +## +## SoundTouch 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. +## +## SoundTouch 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 + +AUTOMAKE_OPTIONS = foreign + +noinst_HEADERS=AAFilter.h cpu_detect.h FIRFilter.h RateTransposer.h TDStretch.h cpu_detect_x86_gcc.cpp +noinst_LIBRARIES = libSoundTouch.a + +if X86_64 +libSoundTouch_a_CXXFLAGS = -fPIC +libSoundTouch_a_CFLAGS = -fPIC +else +libSoundTouch_a_CXXFLAGS = -msse -mmmx +libSoundTouch_a_CFLAGS = -msse -mmmx +endif + +#lib_LTLIBRARIES=libSoundTouch.la +# the mmx_gcc.cpp and cpu_detect_x86_gcc.cpp may need to be conditionally included here from things discovered in configure.ac +libSoundTouch_a_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp mmx_optimized.cpp sse_optimized.cpp \ +RateTransposer.cpp SoundTouch.cpp TDStretch.cpp WavFile.cpp cpu_detect_x86_gcc.cpp + +# ??? test for -fcheck-new in configure.ac +# other compiler flags to add +AM_CXXFLAGS=-O3 -msse -fcheck-new -I../../include + +# other linking flags to add +#libSoundTouch_la_LIBADD= + diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/RateTransposer.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/RateTransposer.cpp index b7414b90a6..9e5c962d13 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/RateTransposer.cpp +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/RateTransposer.cpp @@ -1,626 +1,626 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sample rate transposer. Changes sample rate by using linear interpolation -/// together with anti-alias filtering (first order interpolation with anti- -/// alias filtering should be quite adequate for this application) -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/03/19 10:05:49 $ -// File revision : $Revision: 1.13 $ -// -// $Id: RateTransposer.cpp,v 1.13 2006/03/19 10:05:49 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include "RateTransposer.h" -#include "AAFilter.h" - -using namespace soundtouch; - - -/// A linear samplerate transposer class that uses integer arithmetics. -/// for the transposing. -class RateTransposerInteger : public RateTransposer -{ -protected: - int iSlopeCount; - uint uRate; - SAMPLETYPE sPrevSampleL, sPrevSampleR; - - virtual void resetRegisters(); - - virtual uint transposeStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - virtual uint transposeMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - -public: - RateTransposerInteger(); - virtual ~RateTransposerInteger(); - - /// Sets new target rate. Normal rate = 1.0, smaller values represent slower - /// rate, larger faster rates. - virtual void setRate(float newRate); - -}; - - -/// A linear samplerate transposer class that uses floating point arithmetics -/// for the transposing. -class RateTransposerFloat : public RateTransposer -{ -protected: - float fSlopeCount; - float fRateStep; - SAMPLETYPE sPrevSampleL, sPrevSampleR; - - virtual void resetRegisters(); - - virtual uint transposeStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - virtual uint transposeMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - -public: - RateTransposerFloat(); - virtual ~RateTransposerFloat(); -}; - - - -#ifndef min -#define min(a,b) ((a > b) ? b : a) -#define max(a,b) ((a < b) ? b : a) -#endif - - -// Operator 'new' is overloaded so that it automatically creates a suitable instance -// depending on if we've a MMX/SSE/etc-capable CPU available or not. -void * RateTransposer::operator new(size_t s) -{ - // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! - assert(FALSE); - return NULL; -} - - -RateTransposer *RateTransposer::newInstance() -{ -#ifdef INTEGER_SAMPLES - return ::new RateTransposerInteger; -#else - return ::new RateTransposerFloat; -#endif -} - - -// Constructor -RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer) -{ - uChannels = 2; - bUseAAFilter = TRUE; - - // Instantiates the anti-alias filter with default tap length - // of 32 - pAAFilter = new AAFilter(32); -} - - - -RateTransposer::~RateTransposer() -{ - delete pAAFilter; -} - - - -/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable -void RateTransposer::enableAAFilter(const BOOL newMode) -{ - bUseAAFilter = newMode; -} - - -/// Returns nonzero if anti-alias filter is enabled. -BOOL RateTransposer::isAAFilterEnabled() const -{ - return bUseAAFilter; -} - - -AAFilter *RateTransposer::getAAFilter() const -{ - return pAAFilter; -} - - - -// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower -// uRate, larger faster uRates. -void RateTransposer::setRate(float newRate) -{ - float fCutoff; - - fRate = newRate; - - // design a new anti-alias filter - if (newRate > 1.0f) - { - fCutoff = 0.5f / newRate; - } - else - { - fCutoff = 0.5f * newRate; - } - pAAFilter->setCutoffFreq(fCutoff); -} - - -// Outputs as many samples of the 'outputBuffer' as possible, and if there's -// any room left, outputs also as many of the incoming samples as possible. -// The goal is to drive the outputBuffer empty. -// -// It's allowed for 'output' and 'input' parameters to point to the same -// memory position. -void RateTransposer::flushStoreBuffer() -{ - if (storeBuffer.isEmpty()) return; - - outputBuffer.moveSamples(storeBuffer); -} - - -// Adds 'numSamples' pcs of samples from the 'samples' memory position into -// the input of the object. -void RateTransposer::putSamples(const SAMPLETYPE *samples, uint numSamples) -{ - processSamples(samples, numSamples); -} - - - -// Transposes up the sample rate, causing the observed playback 'rate' of the -// sound to decrease -void RateTransposer::upsample(const SAMPLETYPE *src, uint numSamples) -{ - int count, sizeTemp, num; - - // If the parameter 'uRate' value is smaller than 'SCALE', first transpose - // the samples and then apply the anti-alias filter to remove aliasing. - - // First check that there's enough room in 'storeBuffer' - // (+16 is to reserve some slack in the destination buffer) - sizeTemp = (int)((float)numSamples / fRate + 16.0f); - - // Transpose the samples, store the result into the end of "storeBuffer" - count = transpose(storeBuffer.ptrEnd(sizeTemp), src, numSamples); - storeBuffer.putSamples(count); - - // Apply the anti-alias filter to samples in "store output", output the - // result to "dest" - num = storeBuffer.numSamples(); - count = pAAFilter->evaluate(outputBuffer.ptrEnd(num), - storeBuffer.ptrBegin(), num, uChannels); - outputBuffer.putSamples(count); - - // Remove the processed samples from "storeBuffer" - storeBuffer.receiveSamples(count); -} - - -// Transposes down the sample rate, causing the observed playback 'rate' of the -// sound to increase -void RateTransposer::downsample(const SAMPLETYPE *src, uint numSamples) -{ - int count, sizeTemp; - - // If the parameter 'uRate' value is larger than 'SCALE', first apply the - // anti-alias filter to remove high frequencies (prevent them from folding - // over the lover frequencies), then transpose. */ - - // Add the new samples to the end of the storeBuffer */ - storeBuffer.putSamples(src, numSamples); - - // Anti-alias filter the samples to prevent folding and output the filtered - // data to tempBuffer. Note : because of the FIR filter length, the - // filtering routine takes in 'filter_length' more samples than it outputs. - assert(tempBuffer.isEmpty()); - sizeTemp = storeBuffer.numSamples(); - - count = pAAFilter->evaluate(tempBuffer.ptrEnd(sizeTemp), - storeBuffer.ptrBegin(), sizeTemp, uChannels); - - // Remove the filtered samples from 'storeBuffer' - storeBuffer.receiveSamples(count); - - // Transpose the samples (+16 is to reserve some slack in the destination buffer) - sizeTemp = (int)((float)numSamples / fRate + 16.0f); - count = transpose(outputBuffer.ptrEnd(sizeTemp), tempBuffer.ptrBegin(), count); - outputBuffer.putSamples(count); -} - - -// Transposes sample rate by applying anti-alias filter to prevent folding. -// Returns amount of samples returned in the "dest" buffer. -// The maximum amount of samples that can be returned at a time is set by -// the 'set_returnBuffer_size' function. -void RateTransposer::processSamples(const SAMPLETYPE *src, uint numSamples) -{ - uint count; - uint sizeReq; - - if (numSamples == 0) return; - assert(pAAFilter); - - // If anti-alias filter is turned off, simply transpose without applying - // the filter - if (bUseAAFilter == FALSE) - { - sizeReq = (int)((float)numSamples / fRate + 1.0f); - count = transpose(outputBuffer.ptrEnd(sizeReq), src, numSamples); - outputBuffer.putSamples(count); - return; - } - - // Transpose with anti-alias filter - if (fRate < 1.0f) - { - upsample(src, numSamples); - } - else - { - downsample(src, numSamples); - } -} - - -// Transposes the sample rate of the given samples using linear interpolation. -// Returns the number of samples returned in the "dest" buffer -inline uint RateTransposer::transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) -{ - if (uChannels == 2) - { - return transposeStereo(dest, src, numSamples); - } - else - { - return transposeMono(dest, src, numSamples); - } -} - - -// Sets the number of channels, 1 = mono, 2 = stereo -void RateTransposer::setChannels(const uint numchannels) -{ - if (uChannels == numchannels) return; - - assert(numchannels == 1 || numchannels == 2); - uChannels = numchannels; - - storeBuffer.setChannels(uChannels); - tempBuffer.setChannels(uChannels); - outputBuffer.setChannels(uChannels); - - // Inits the linear interpolation registers - resetRegisters(); -} - - -// Clears all the samples in the object -void RateTransposer::clear() -{ - outputBuffer.clear(); - storeBuffer.clear(); -} - - -// Returns nonzero if there aren't any samples available for outputting. -uint RateTransposer::isEmpty() -{ - int res; - - res = FIFOProcessor::isEmpty(); - if (res == 0) return 0; - return storeBuffer.isEmpty(); -} - - -////////////////////////////////////////////////////////////////////////////// -// -// RateTransposerInteger - integer arithmetic implementation -// - -/// fixed-point interpolation routine precision -#define SCALE 65536 - -// Constructor -RateTransposerInteger::RateTransposerInteger() : RateTransposer() -{ - // call these here as these are virtual functions; calling these - // from the base class constructor wouldn't execute the overloaded - // versions (peculiar C++ can be). - resetRegisters(); - setRate(1.0f); -} - - -RateTransposerInteger::~RateTransposerInteger() -{ -} - - -void RateTransposerInteger::resetRegisters() -{ - iSlopeCount = 0; - sPrevSampleL = - sPrevSampleR = 0; -} - - - -// Transposes the sample rate of the given samples using linear interpolation. -// 'Mono' version of the routine. Returns the number of samples returned in -// the "dest" buffer -uint RateTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) -{ - unsigned int i, used; - LONG_SAMPLETYPE temp, vol1; - - used = 0; - i = 0; - - // Process the last sample saved from the previous call first... - while (iSlopeCount <= SCALE) - { - vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); - temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; - dest[i] = (SAMPLETYPE)(temp / SCALE); - i++; - iSlopeCount += uRate; - } - // now always (iSlopeCount > SCALE) - iSlopeCount -= SCALE; - - while (1) - { - while (iSlopeCount > SCALE) - { - iSlopeCount -= SCALE; - used ++; - if (used >= numSamples - 1) goto end; - } - vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); - temp = src[used] * vol1 + iSlopeCount * src[used + 1]; - dest[i] = (SAMPLETYPE)(temp / SCALE); - - i++; - iSlopeCount += uRate; - } -end: - // Store the last sample for the next round - sPrevSampleL = src[numSamples - 1]; - - return i; -} - - -// Transposes the sample rate of the given samples using linear interpolation. -// 'Stereo' version of the routine. Returns the number of samples returned in -// the "dest" buffer -uint RateTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) -{ - unsigned int srcPos, i, used; - LONG_SAMPLETYPE temp, vol1; - - if (numSamples == 0) return 0; // no samples, no work - - used = 0; - i = 0; - - // Process the last sample saved from the sPrevSampleLious call first... - while (iSlopeCount <= SCALE) - { - vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); - temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; - dest[2 * i] = (SAMPLETYPE)(temp / SCALE); - temp = vol1 * sPrevSampleR + iSlopeCount * src[1]; - dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); - i++; - iSlopeCount += uRate; - } - // now always (iSlopeCount > SCALE) - iSlopeCount -= SCALE; - - while (1) - { - while (iSlopeCount > SCALE) - { - iSlopeCount -= SCALE; - used ++; - if (used >= numSamples - 1) goto end; - } - srcPos = 2 * used; - vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); - temp = src[srcPos] * vol1 + iSlopeCount * src[srcPos + 2]; - dest[2 * i] = (SAMPLETYPE)(temp / SCALE); - temp = src[srcPos + 1] * vol1 + iSlopeCount * src[srcPos + 3]; - dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); - - i++; - iSlopeCount += uRate; - } -end: - // Store the last sample for the next round - sPrevSampleL = src[2 * numSamples - 2]; - sPrevSampleR = src[2 * numSamples - 1]; - - return i; -} - - -// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower -// uRate, larger faster uRates. -void RateTransposerInteger::setRate(float newRate) -{ - uRate = (int)(newRate * SCALE + 0.5f); - RateTransposer::setRate(newRate); -} - - -////////////////////////////////////////////////////////////////////////////// -// -// RateTransposerFloat - floating point arithmetic implementation -// -////////////////////////////////////////////////////////////////////////////// - -// Constructor -RateTransposerFloat::RateTransposerFloat() : RateTransposer() -{ - // call these here as these are virtual functions; calling these - // from the base class constructor wouldn't execute the overloaded - // versions (peculiar C++ can be). - resetRegisters(); - setRate(1.0f); -} - - -RateTransposerFloat::~RateTransposerFloat() -{ -} - - -void RateTransposerFloat::resetRegisters() -{ - fSlopeCount = 0; - sPrevSampleL = - sPrevSampleR = 0; -} - - - -// Transposes the sample rate of the given samples using linear interpolation. -// 'Mono' version of the routine. Returns the number of samples returned in -// the "dest" buffer -uint RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) -{ - unsigned int i, used; - - used = 0; - i = 0; - - // Process the last sample saved from the previous call first... - while (fSlopeCount <= 1.0f) - { - dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); - i++; - fSlopeCount += fRate; - } - fSlopeCount -= 1.0f; - - if (numSamples == 1) goto end; - - while (1) - { - while (fSlopeCount > 1.0f) - { - fSlopeCount -= 1.0f; - used ++; - if (used >= numSamples - 1) goto end; - } - dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[used] + fSlopeCount * src[used + 1]); - i++; - fSlopeCount += fRate; - } -end: - // Store the last sample for the next round - sPrevSampleL = src[numSamples - 1]; - - return i; -} - - -// Transposes the sample rate of the given samples using linear interpolation. -// 'Mono' version of the routine. Returns the number of samples returned in -// the "dest" buffer -uint RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) -{ - unsigned int srcPos, i, used; - - if (numSamples == 0) return 0; // no samples, no work - - used = 0; - i = 0; - - // Process the last sample saved from the sPrevSampleLious call first... - while (fSlopeCount <= 1.0f) - { - dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); - dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleR + fSlopeCount * src[1]); - i++; - fSlopeCount += fRate; - } - // now always (iSlopeCount > 1.0f) - fSlopeCount -= 1.0f; - - if (numSamples == 1) goto end; - - while (1) - { - while (fSlopeCount > 1.0f) - { - fSlopeCount -= 1.0f; - used ++; - if (used >= numSamples - 1) goto end; - } - srcPos = 2 * used; - - dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos] - + fSlopeCount * src[srcPos + 2]); - dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos + 1] - + fSlopeCount * src[srcPos + 3]); - - i++; - fSlopeCount += fRate; - } -end: - // Store the last sample for the next round - sPrevSampleL = src[2 * numSamples - 2]; - sPrevSampleR = src[2 * numSamples - 1]; - - return i; -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sample rate transposer. Changes sample rate by using linear interpolation +/// together with anti-alias filtering (first order interpolation with anti- +/// alias filtering should be quite adequate for this application) +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/03/19 10:05:49 $ +// File revision : $Revision: 1.13 $ +// +// $Id: RateTransposer.cpp,v 1.13 2006/03/19 10:05:49 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include "RateTransposer.h" +#include "AAFilter.h" + +using namespace soundtouch; + + +/// A linear samplerate transposer class that uses integer arithmetics. +/// for the transposing. +class RateTransposerInteger : public RateTransposer +{ +protected: + int iSlopeCount; + uint uRate; + SAMPLETYPE sPrevSampleL, sPrevSampleR; + + virtual void resetRegisters(); + + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + +public: + RateTransposerInteger(); + virtual ~RateTransposerInteger(); + + /// Sets new target rate. Normal rate = 1.0, smaller values represent slower + /// rate, larger faster rates. + virtual void setRate(float newRate); + +}; + + +/// A linear samplerate transposer class that uses floating point arithmetics +/// for the transposing. +class RateTransposerFloat : public RateTransposer +{ +protected: + float fSlopeCount; + float fRateStep; + SAMPLETYPE sPrevSampleL, sPrevSampleR; + + virtual void resetRegisters(); + + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + +public: + RateTransposerFloat(); + virtual ~RateTransposerFloat(); +}; + + + +#ifndef min +#define min(a,b) ((a > b) ? b : a) +#define max(a,b) ((a < b) ? b : a) +#endif + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX/SSE/etc-capable CPU available or not. +void * RateTransposer::operator new(size_t s) +{ + // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! + assert(FALSE); + return NULL; +} + + +RateTransposer *RateTransposer::newInstance() +{ +#ifdef INTEGER_SAMPLES + return ::new RateTransposerInteger; +#else + return ::new RateTransposerFloat; +#endif +} + + +// Constructor +RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer) +{ + uChannels = 2; + bUseAAFilter = TRUE; + + // Instantiates the anti-alias filter with default tap length + // of 32 + pAAFilter = new AAFilter(32); +} + + + +RateTransposer::~RateTransposer() +{ + delete pAAFilter; +} + + + +/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable +void RateTransposer::enableAAFilter(const BOOL newMode) +{ + bUseAAFilter = newMode; +} + + +/// Returns nonzero if anti-alias filter is enabled. +BOOL RateTransposer::isAAFilterEnabled() const +{ + return bUseAAFilter; +} + + +AAFilter *RateTransposer::getAAFilter() const +{ + return pAAFilter; +} + + + +// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower +// uRate, larger faster uRates. +void RateTransposer::setRate(float newRate) +{ + float fCutoff; + + fRate = newRate; + + // design a new anti-alias filter + if (newRate > 1.0f) + { + fCutoff = 0.5f / newRate; + } + else + { + fCutoff = 0.5f * newRate; + } + pAAFilter->setCutoffFreq(fCutoff); +} + + +// Outputs as many samples of the 'outputBuffer' as possible, and if there's +// any room left, outputs also as many of the incoming samples as possible. +// The goal is to drive the outputBuffer empty. +// +// It's allowed for 'output' and 'input' parameters to point to the same +// memory position. +void RateTransposer::flushStoreBuffer() +{ + if (storeBuffer.isEmpty()) return; + + outputBuffer.moveSamples(storeBuffer); +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void RateTransposer::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + processSamples(samples, numSamples); +} + + + +// Transposes up the sample rate, causing the observed playback 'rate' of the +// sound to decrease +void RateTransposer::upsample(const SAMPLETYPE *src, uint numSamples) +{ + int count, sizeTemp, num; + + // If the parameter 'uRate' value is smaller than 'SCALE', first transpose + // the samples and then apply the anti-alias filter to remove aliasing. + + // First check that there's enough room in 'storeBuffer' + // (+16 is to reserve some slack in the destination buffer) + sizeTemp = (int)((float)numSamples / fRate + 16.0f); + + // Transpose the samples, store the result into the end of "storeBuffer" + count = transpose(storeBuffer.ptrEnd(sizeTemp), src, numSamples); + storeBuffer.putSamples(count); + + // Apply the anti-alias filter to samples in "store output", output the + // result to "dest" + num = storeBuffer.numSamples(); + count = pAAFilter->evaluate(outputBuffer.ptrEnd(num), + storeBuffer.ptrBegin(), num, uChannels); + outputBuffer.putSamples(count); + + // Remove the processed samples from "storeBuffer" + storeBuffer.receiveSamples(count); +} + + +// Transposes down the sample rate, causing the observed playback 'rate' of the +// sound to increase +void RateTransposer::downsample(const SAMPLETYPE *src, uint numSamples) +{ + int count, sizeTemp; + + // If the parameter 'uRate' value is larger than 'SCALE', first apply the + // anti-alias filter to remove high frequencies (prevent them from folding + // over the lover frequencies), then transpose. */ + + // Add the new samples to the end of the storeBuffer */ + storeBuffer.putSamples(src, numSamples); + + // Anti-alias filter the samples to prevent folding and output the filtered + // data to tempBuffer. Note : because of the FIR filter length, the + // filtering routine takes in 'filter_length' more samples than it outputs. + assert(tempBuffer.isEmpty()); + sizeTemp = storeBuffer.numSamples(); + + count = pAAFilter->evaluate(tempBuffer.ptrEnd(sizeTemp), + storeBuffer.ptrBegin(), sizeTemp, uChannels); + + // Remove the filtered samples from 'storeBuffer' + storeBuffer.receiveSamples(count); + + // Transpose the samples (+16 is to reserve some slack in the destination buffer) + sizeTemp = (int)((float)numSamples / fRate + 16.0f); + count = transpose(outputBuffer.ptrEnd(sizeTemp), tempBuffer.ptrBegin(), count); + outputBuffer.putSamples(count); +} + + +// Transposes sample rate by applying anti-alias filter to prevent folding. +// Returns amount of samples returned in the "dest" buffer. +// The maximum amount of samples that can be returned at a time is set by +// the 'set_returnBuffer_size' function. +void RateTransposer::processSamples(const SAMPLETYPE *src, uint numSamples) +{ + uint count; + uint sizeReq; + + if (numSamples == 0) return; + assert(pAAFilter); + + // If anti-alias filter is turned off, simply transpose without applying + // the filter + if (bUseAAFilter == FALSE) + { + sizeReq = (int)((float)numSamples / fRate + 1.0f); + count = transpose(outputBuffer.ptrEnd(sizeReq), src, numSamples); + outputBuffer.putSamples(count); + return; + } + + // Transpose with anti-alias filter + if (fRate < 1.0f) + { + upsample(src, numSamples); + } + else + { + downsample(src, numSamples); + } +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// Returns the number of samples returned in the "dest" buffer +inline uint RateTransposer::transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + if (uChannels == 2) + { + return transposeStereo(dest, src, numSamples); + } + else + { + return transposeMono(dest, src, numSamples); + } +} + + +// Sets the number of channels, 1 = mono, 2 = stereo +void RateTransposer::setChannels(const uint numchannels) +{ + if (uChannels == numchannels) return; + + assert(numchannels == 1 || numchannels == 2); + uChannels = numchannels; + + storeBuffer.setChannels(uChannels); + tempBuffer.setChannels(uChannels); + outputBuffer.setChannels(uChannels); + + // Inits the linear interpolation registers + resetRegisters(); +} + + +// Clears all the samples in the object +void RateTransposer::clear() +{ + outputBuffer.clear(); + storeBuffer.clear(); +} + + +// Returns nonzero if there aren't any samples available for outputting. +uint RateTransposer::isEmpty() +{ + int res; + + res = FIFOProcessor::isEmpty(); + if (res == 0) return 0; + return storeBuffer.isEmpty(); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// RateTransposerInteger - integer arithmetic implementation +// + +/// fixed-point interpolation routine precision +#define SCALE 65536 + +// Constructor +RateTransposerInteger::RateTransposerInteger() : RateTransposer() +{ + // call these here as these are virtual functions; calling these + // from the base class constructor wouldn't execute the overloaded + // versions (peculiar C++ can be). + resetRegisters(); + setRate(1.0f); +} + + +RateTransposerInteger::~RateTransposerInteger() +{ +} + + +void RateTransposerInteger::resetRegisters() +{ + iSlopeCount = 0; + sPrevSampleL = + sPrevSampleR = 0; +} + + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int i, used; + LONG_SAMPLETYPE temp, vol1; + + used = 0; + i = 0; + + // Process the last sample saved from the previous call first... + while (iSlopeCount <= SCALE) + { + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; + dest[i] = (SAMPLETYPE)(temp / SCALE); + i++; + iSlopeCount += uRate; + } + // now always (iSlopeCount > SCALE) + iSlopeCount -= SCALE; + + while (1) + { + while (iSlopeCount > SCALE) + { + iSlopeCount -= SCALE; + used ++; + if (used >= numSamples - 1) goto end; + } + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = src[used] * vol1 + iSlopeCount * src[used + 1]; + dest[i] = (SAMPLETYPE)(temp / SCALE); + + i++; + iSlopeCount += uRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[numSamples - 1]; + + return i; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Stereo' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int srcPos, i, used; + LONG_SAMPLETYPE temp, vol1; + + if (numSamples == 0) return 0; // no samples, no work + + used = 0; + i = 0; + + // Process the last sample saved from the sPrevSampleLious call first... + while (iSlopeCount <= SCALE) + { + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; + dest[2 * i] = (SAMPLETYPE)(temp / SCALE); + temp = vol1 * sPrevSampleR + iSlopeCount * src[1]; + dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); + i++; + iSlopeCount += uRate; + } + // now always (iSlopeCount > SCALE) + iSlopeCount -= SCALE; + + while (1) + { + while (iSlopeCount > SCALE) + { + iSlopeCount -= SCALE; + used ++; + if (used >= numSamples - 1) goto end; + } + srcPos = 2 * used; + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = src[srcPos] * vol1 + iSlopeCount * src[srcPos + 2]; + dest[2 * i] = (SAMPLETYPE)(temp / SCALE); + temp = src[srcPos + 1] * vol1 + iSlopeCount * src[srcPos + 3]; + dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); + + i++; + iSlopeCount += uRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[2 * numSamples - 2]; + sPrevSampleR = src[2 * numSamples - 1]; + + return i; +} + + +// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower +// uRate, larger faster uRates. +void RateTransposerInteger::setRate(float newRate) +{ + uRate = (int)(newRate * SCALE + 0.5f); + RateTransposer::setRate(newRate); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// RateTransposerFloat - floating point arithmetic implementation +// +////////////////////////////////////////////////////////////////////////////// + +// Constructor +RateTransposerFloat::RateTransposerFloat() : RateTransposer() +{ + // call these here as these are virtual functions; calling these + // from the base class constructor wouldn't execute the overloaded + // versions (peculiar C++ can be). + resetRegisters(); + setRate(1.0f); +} + + +RateTransposerFloat::~RateTransposerFloat() +{ +} + + +void RateTransposerFloat::resetRegisters() +{ + fSlopeCount = 0; + sPrevSampleL = + sPrevSampleR = 0; +} + + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int i, used; + + used = 0; + i = 0; + + // Process the last sample saved from the previous call first... + while (fSlopeCount <= 1.0f) + { + dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); + i++; + fSlopeCount += fRate; + } + fSlopeCount -= 1.0f; + + if (numSamples == 1) goto end; + + while (1) + { + while (fSlopeCount > 1.0f) + { + fSlopeCount -= 1.0f; + used ++; + if (used >= numSamples - 1) goto end; + } + dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[used] + fSlopeCount * src[used + 1]); + i++; + fSlopeCount += fRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[numSamples - 1]; + + return i; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int srcPos, i, used; + + if (numSamples == 0) return 0; // no samples, no work + + used = 0; + i = 0; + + // Process the last sample saved from the sPrevSampleLious call first... + while (fSlopeCount <= 1.0f) + { + dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); + dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleR + fSlopeCount * src[1]); + i++; + fSlopeCount += fRate; + } + // now always (iSlopeCount > 1.0f) + fSlopeCount -= 1.0f; + + if (numSamples == 1) goto end; + + while (1) + { + while (fSlopeCount > 1.0f) + { + fSlopeCount -= 1.0f; + used ++; + if (used >= numSamples - 1) goto end; + } + srcPos = 2 * used; + + dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos] + + fSlopeCount * src[srcPos + 2]); + dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos + 1] + + fSlopeCount * src[srcPos + 3]); + + i++; + fSlopeCount += fRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[2 * numSamples - 2]; + sPrevSampleR = src[2 * numSamples - 1]; + + return i; +} diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/RateTransposer.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/RateTransposer.h index f73978e639..1cd6e9026d 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/RateTransposer.h +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/RateTransposer.h @@ -1,162 +1,162 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sample rate transposer. Changes sample rate by using linear interpolation -/// together with anti-alias filtering (first order interpolation with anti- -/// alias filtering should be quite adequate for this application). -/// -/// Use either of the derived classes of 'RateTransposerInteger' or -/// 'RateTransposerFloat' for corresponding integer/floating point tranposing -/// algorithm implementation. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.10 $ -// -// $Id: RateTransposer.h,v 1.10 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef RateTransposer_H -#define RateTransposer_H - -#include "AAFilter.h" -#include "FIFOSamplePipe.h" -#include "FIFOSampleBuffer.h" - -#include "STTypes.h" - -namespace soundtouch -{ - -/// A common linear samplerate transposer class. -/// -/// Note: Use function "RateTransposer::newInstance()" to create a new class -/// instance instead of the "new" operator; that function automatically -/// chooses a correct implementation depending on if integer or floating -/// arithmetics are to be used. -class RateTransposer : public FIFOProcessor -{ -protected: - /// Anti-alias filter object - AAFilter *pAAFilter; - - float fRate; - - uint uChannels; - - /// Buffer for collecting samples to feed the anti-alias filter between - /// two batches - FIFOSampleBuffer storeBuffer; - - /// Buffer for keeping samples between transposing & anti-alias filter - FIFOSampleBuffer tempBuffer; - - /// Output sample buffer - FIFOSampleBuffer outputBuffer; - - BOOL bUseAAFilter; - - void init(); - - virtual void resetRegisters() = 0; - - virtual uint transposeStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples) = 0; - virtual uint transposeMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples) = 0; - uint transpose(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - - void flushStoreBuffer(); - - void downsample(const SAMPLETYPE *src, - uint numSamples); - void upsample(const SAMPLETYPE *src, - uint numSamples); - - /// Transposes sample rate by applying anti-alias filter to prevent folding. - /// Returns amount of samples returned in the "dest" buffer. - /// The maximum amount of samples that can be returned at a time is set by - /// the 'set_returnBuffer_size' function. - void processSamples(const SAMPLETYPE *src, - uint numSamples); - - -public: - RateTransposer(); - virtual ~RateTransposer(); - - /// Operator 'new' is overloaded so that it automatically creates a suitable instance - /// depending on if we're to use integer or floating point arithmetics. - void *operator new(size_t s); - - /// Use this function instead of "new" operator to create a new instance of this class. - /// This function automatically chooses a correct implementation, depending on if - /// integer ot floating point arithmetics are to be used. - static RateTransposer *newInstance(); - - /// Returns the output buffer object - FIFOSamplePipe *getOutput() { return &outputBuffer; }; - - /// Returns the store buffer object - FIFOSamplePipe *getStore() { return &storeBuffer; }; - - /// Return anti-alias filter object - AAFilter *getAAFilter() const; - - /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable - void enableAAFilter(BOOL newMode); - - /// Returns nonzero if anti-alias filter is enabled. - BOOL isAAFilterEnabled() const; - - /// Sets new target rate. Normal rate = 1.0, smaller values represent slower - /// rate, larger faster rates. - virtual void setRate(float newRate); - - /// Sets the number of channels, 1 = mono, 2 = stereo - void setChannels(uint channels); - - /// Adds 'numSamples' pcs of samples from the 'samples' memory position into - /// the input of the object. - void putSamples(const SAMPLETYPE *samples, uint numSamples); - - /// Clears all the samples in the object - void clear(); - - /// Returns nonzero if there aren't any samples available for outputting. - uint isEmpty(); -}; - -} - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sample rate transposer. Changes sample rate by using linear interpolation +/// together with anti-alias filtering (first order interpolation with anti- +/// alias filtering should be quite adequate for this application). +/// +/// Use either of the derived classes of 'RateTransposerInteger' or +/// 'RateTransposerFloat' for corresponding integer/floating point tranposing +/// algorithm implementation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: RateTransposer.h,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef RateTransposer_H +#define RateTransposer_H + +#include "AAFilter.h" +#include "FIFOSamplePipe.h" +#include "FIFOSampleBuffer.h" + +#include "STTypes.h" + +namespace soundtouch +{ + +/// A common linear samplerate transposer class. +/// +/// Note: Use function "RateTransposer::newInstance()" to create a new class +/// instance instead of the "new" operator; that function automatically +/// chooses a correct implementation depending on if integer or floating +/// arithmetics are to be used. +class RateTransposer : public FIFOProcessor +{ +protected: + /// Anti-alias filter object + AAFilter *pAAFilter; + + float fRate; + + uint uChannels; + + /// Buffer for collecting samples to feed the anti-alias filter between + /// two batches + FIFOSampleBuffer storeBuffer; + + /// Buffer for keeping samples between transposing & anti-alias filter + FIFOSampleBuffer tempBuffer; + + /// Output sample buffer + FIFOSampleBuffer outputBuffer; + + BOOL bUseAAFilter; + + void init(); + + virtual void resetRegisters() = 0; + + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) = 0; + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) = 0; + uint transpose(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + + void flushStoreBuffer(); + + void downsample(const SAMPLETYPE *src, + uint numSamples); + void upsample(const SAMPLETYPE *src, + uint numSamples); + + /// Transposes sample rate by applying anti-alias filter to prevent folding. + /// Returns amount of samples returned in the "dest" buffer. + /// The maximum amount of samples that can be returned at a time is set by + /// the 'set_returnBuffer_size' function. + void processSamples(const SAMPLETYPE *src, + uint numSamples); + + +public: + RateTransposer(); + virtual ~RateTransposer(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we're to use integer or floating point arithmetics. + void *operator new(size_t s); + + /// Use this function instead of "new" operator to create a new instance of this class. + /// This function automatically chooses a correct implementation, depending on if + /// integer ot floating point arithmetics are to be used. + static RateTransposer *newInstance(); + + /// Returns the output buffer object + FIFOSamplePipe *getOutput() { return &outputBuffer; }; + + /// Returns the store buffer object + FIFOSamplePipe *getStore() { return &storeBuffer; }; + + /// Return anti-alias filter object + AAFilter *getAAFilter() const; + + /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable + void enableAAFilter(BOOL newMode); + + /// Returns nonzero if anti-alias filter is enabled. + BOOL isAAFilterEnabled() const; + + /// Sets new target rate. Normal rate = 1.0, smaller values represent slower + /// rate, larger faster rates. + virtual void setRate(float newRate); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint channels); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position into + /// the input of the object. + void putSamples(const SAMPLETYPE *samples, uint numSamples); + + /// Clears all the samples in the object + void clear(); + + /// Returns nonzero if there aren't any samples available for outputting. + uint isEmpty(); +}; + +} + +#endif diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/STTypes.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/STTypes.h index f3a6a5d5c0..d0969ec1c9 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/STTypes.h +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/STTypes.h @@ -1,202 +1,202 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Common type definitions for SoundTouch audio processing library. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.16 $ -// -// $Id: STTypes.h,v 1.16 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef STTypes_H -#define STTypes_H - -//#define INTEGER_SAMPLES 1 - -typedef unsigned int uint; -typedef unsigned long ulong; - -#ifdef __x86_64__ -typedef unsigned long long ulongptr; -#else -typedef unsigned long ulongptr; -#endif - - -#ifdef __GNUC__ - // In GCC, include soundtouch_config.h made by config scritps -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the `m' library (-lm). */ -#define HAVE_LIBM 1 - -/* Define to 1 if your system has a GNU libc compatible `malloc' function, and - to 0 otherwise. */ -#define HAVE_MALLOC 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Use Integer as Sample type */ -//#define INTEGER_SAMPLES 1 - -/* Define as the return type of signal handlers (`int' or `void'). */ -#define RETSIGTYPE void - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -#endif - -#ifndef _WINDEF_ - // if these aren't defined already by Windows headers, define now - - typedef int BOOL; - -#ifndef FALSE - #define FALSE 0 -#endif - -#ifndef TRUE - #define TRUE 1 -#endif - -#endif // _WINDEF_ - - -namespace soundtouch -{ -/// Activate these undef's to overrule the possible sampletype -/// setting inherited from some other header file: -//#undef INTEGER_SAMPLES -//#undef FLOAT_SAMPLES - -#if !(INTEGER_SAMPLES || FLOAT_SAMPLES) - - /// Choose either 32bit floating point or 16bit integer sampletype - /// by choosing one of the following defines, unless this selection - /// has already been done in some other file. - //// - /// Notes: - /// - In Windows environment, choose the sample format with the - /// following defines. - /// - In GNU environment, the floating point samples are used by - /// default, but integer samples can be chosen by giving the - /// following switch to the configure script: - /// ./configure --enable-integer-samples - /// However, if you still prefer to select the sample format here - /// also in GNU environment, then please #undef the INTEGER_SAMPLE - /// and FLOAT_SAMPLE defines first as in comments above. - //#define INTEGER_SAMPLES 1 //< 16bit integer samples - #define FLOAT_SAMPLES 1 //< 32bit float samples - - #endif - - /// Define this to allow CPU-specific assembler optimizations. Notice that - /// having this enabled on non-x86 platforms doesn't matter; the compiler can - /// drop unsupported extensions on different platforms automatically. - /// However, if you're having difficulties getting the optimized routines - /// compiled with your compler (e.g. some gcc compiler versions may be picky), - /// you may wish to disable the optimizations to make the library compile. - #if !defined(_MSC_VER) || !defined(__x86_64__) - #define ALLOW_OPTIMIZATIONS 1 - #define ALLOW_NONEXACT_SIMD_OPTIMIZATION 1 - #endif - - - // If defined, allows the SIMD-optimized routines to take minor shortcuts - // for improved performance. Undefine to require faithfully similar SIMD - // calculations as in normal C implementation. - - - - #ifdef INTEGER_SAMPLES - // 16bit integer sample type - typedef short SAMPLETYPE; - // data type for sample accumulation: Use 32bit integer to prevent overflows - typedef long LONG_SAMPLETYPE; - - #ifdef FLOAT_SAMPLES - // check that only one sample type is defined - #error "conflicting sample types defined" - #endif // FLOAT_SAMPLES - - #ifdef ALLOW_OPTIMIZATIONS - #if (_WIN32 || __i386__ || __x86_64__) - // Allow MMX optimizations - #define ALLOW_MMX 1 - #endif - #endif - - #else - - // floating point samples - typedef float SAMPLETYPE; - // data type for sample accumulation: Use double to utilize full precision. - typedef double LONG_SAMPLETYPE; - - #ifdef ALLOW_OPTIMIZATIONS - // Allow 3DNow! and SSE optimizations - #if _WIN32 - // #define ALLOW_3DNOW 1 - #endif - - #if (_WIN32 || __i386__ || __x86_64__) - #define ALLOW_SSE 1 - #endif - #endif - - #endif // INTEGER_SAMPLES -}; - +//////////////////////////////////////////////////////////////////////////////// +/// +/// Common type definitions for SoundTouch audio processing library. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.16 $ +// +// $Id: STTypes.h,v 1.16 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef STTypes_H +#define STTypes_H + +//#define INTEGER_SAMPLES 1 + +typedef unsigned int uint; +typedef unsigned long ulong; + +#ifdef __x86_64__ +typedef unsigned long long ulongptr; +#else +typedef unsigned long ulongptr; +#endif + + +#ifdef __GNUC__ + // In GCC, include soundtouch_config.h made by config scritps +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `m' library (-lm). */ +#define HAVE_LIBM 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Use Integer as Sample type */ +//#define INTEGER_SAMPLES 1 + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +#endif + +#ifndef _WINDEF_ + // if these aren't defined already by Windows headers, define now + + typedef int BOOL; + +#ifndef FALSE + #define FALSE 0 +#endif + +#ifndef TRUE + #define TRUE 1 +#endif + +#endif // _WINDEF_ + + +namespace soundtouch +{ +/// Activate these undef's to overrule the possible sampletype +/// setting inherited from some other header file: +//#undef INTEGER_SAMPLES +//#undef FLOAT_SAMPLES + +#if !(INTEGER_SAMPLES || FLOAT_SAMPLES) + + /// Choose either 32bit floating point or 16bit integer sampletype + /// by choosing one of the following defines, unless this selection + /// has already been done in some other file. + //// + /// Notes: + /// - In Windows environment, choose the sample format with the + /// following defines. + /// - In GNU environment, the floating point samples are used by + /// default, but integer samples can be chosen by giving the + /// following switch to the configure script: + /// ./configure --enable-integer-samples + /// However, if you still prefer to select the sample format here + /// also in GNU environment, then please #undef the INTEGER_SAMPLE + /// and FLOAT_SAMPLE defines first as in comments above. + //#define INTEGER_SAMPLES 1 //< 16bit integer samples + #define FLOAT_SAMPLES 1 //< 32bit float samples + + #endif + + /// Define this to allow CPU-specific assembler optimizations. Notice that + /// having this enabled on non-x86 platforms doesn't matter; the compiler can + /// drop unsupported extensions on different platforms automatically. + /// However, if you're having difficulties getting the optimized routines + /// compiled with your compler (e.g. some gcc compiler versions may be picky), + /// you may wish to disable the optimizations to make the library compile. + #if !defined(_MSC_VER) || !defined(__x86_64__) + #define ALLOW_OPTIMIZATIONS 1 + #define ALLOW_NONEXACT_SIMD_OPTIMIZATION 1 + #endif + + + // If defined, allows the SIMD-optimized routines to take minor shortcuts + // for improved performance. Undefine to require faithfully similar SIMD + // calculations as in normal C implementation. + + + + #ifdef INTEGER_SAMPLES + // 16bit integer sample type + typedef short SAMPLETYPE; + // data type for sample accumulation: Use 32bit integer to prevent overflows + typedef long LONG_SAMPLETYPE; + + #ifdef FLOAT_SAMPLES + // check that only one sample type is defined + #error "conflicting sample types defined" + #endif // FLOAT_SAMPLES + + #ifdef ALLOW_OPTIMIZATIONS + #if (_WIN32 || __i386__ || __x86_64__) + // Allow MMX optimizations + #define ALLOW_MMX 1 + #endif + #endif + + #else + + // floating point samples + typedef float SAMPLETYPE; + // data type for sample accumulation: Use double to utilize full precision. + typedef double LONG_SAMPLETYPE; + + #ifdef ALLOW_OPTIMIZATIONS + // Allow 3DNow! and SSE optimizations + #if _WIN32 + // #define ALLOW_3DNOW 1 + #endif + + #if (_WIN32 || __i386__ || __x86_64__) + #define ALLOW_SSE 1 + #endif + #endif + + #endif // INTEGER_SAMPLES +}; + #endif \ No newline at end of file diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/SoundTouch.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/SoundTouch.cpp index d20fd326ba..381c517162 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/SoundTouch.cpp +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/SoundTouch.cpp @@ -1,474 +1,474 @@ -////////////////////////////////////////////////////////////////////////////// -/// -/// SoundTouch - main class for tempo/pitch/rate adjusting routines. -/// -/// Notes: -/// - Initialize the SoundTouch object instance by setting up the sound stream -/// parameters with functions 'setSampleRate' and 'setChannels', then set -/// desired tempo/pitch/rate settings with the corresponding functions. -/// -/// - The SoundTouch class behaves like a first-in-first-out pipeline: The -/// samples that are to be processed are fed into one of the pipe by calling -/// function 'putSamples', while the ready processed samples can be read -/// from the other end of the pipeline with function 'receiveSamples'. -/// -/// - The SoundTouch processing classes require certain sized 'batches' of -/// samples in order to process the sound. For this reason the classes buffer -/// incoming samples until there are enough of samples available for -/// processing, then they carry out the processing step and consequently -/// make the processed samples available for outputting. -/// -/// - For the above reason, the processing routines introduce a certain -/// 'latency' between the input and output, so that the samples input to -/// SoundTouch may not be immediately available in the output, and neither -/// the amount of outputtable samples may not immediately be in direct -/// relationship with the amount of previously input samples. -/// -/// - The tempo/pitch/rate control parameters can be altered during processing. -/// Please notice though that they aren't currently protected by semaphores, -/// so in multi-thread application external semaphore protection may be -/// required. -/// -/// - This class utilizes classes 'TDStretch' for tempo change (without modifying -/// pitch) and 'RateTransposer' for changing the playback rate (that is, both -/// tempo and pitch in the same ratio) of the sound. The third available control -/// 'pitch' (change pitch but maintain tempo) is produced by a combination of -/// combining the two other controls. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.13 $ -// -// $Id: SoundTouch.cpp,v 1.13 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include - -#include "SoundTouch.h" -#include "TDStretch.h" -#include "RateTransposer.h" -#include "cpu_detect.h" - -using namespace soundtouch; - -/// Print library version string -extern "C" void soundtouch_ac_test() -{ - printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION); -} - - -SoundTouch::SoundTouch() -{ - // Initialize rate transposer and tempo changer instances - - pRateTransposer = RateTransposer::newInstance(); - pTDStretch = TDStretch::newInstance(); - - setOutPipe(pTDStretch); - - rate = tempo = 0; - - virtualPitch = - virtualRate = - virtualTempo = 1.0; - - calcEffectiveRateAndTempo(); - - channels = 0; - bSrateSet = FALSE; -} - - - -SoundTouch::~SoundTouch() -{ - delete pRateTransposer; - delete pTDStretch; -} - - - -/// Get SoundTouch library version string -const char *SoundTouch::getVersionString() -{ - static const char *_version = SOUNDTOUCH_VERSION; - - return _version; -} - - -/// Get SoundTouch library version Id -uint SoundTouch::getVersionId() -{ - return SOUNDTOUCH_VERSION_ID; -} - - -// Sets the number of channels, 1 = mono, 2 = stereo -void SoundTouch::setChannels(uint numChannels) -{ - if (numChannels != 1 && numChannels != 2) - { - throw std::runtime_error("Illegal number of channels"); - } - channels = numChannels; - pRateTransposer->setChannels(numChannels); - pTDStretch->setChannels(numChannels); -} - - - -// Sets new rate control value. Normal rate = 1.0, smaller values -// represent slower rate, larger faster rates. -void SoundTouch::setRate(float newRate) -{ - virtualRate = newRate; - calcEffectiveRateAndTempo(); -} - - - -// Sets new rate control value as a difference in percents compared -// to the original rate (-50 .. +100 %) -void SoundTouch::setRateChange(float newRate) -{ - virtualRate = 1.0f + 0.01f * newRate; - calcEffectiveRateAndTempo(); -} - - - -// Sets new tempo control value. Normal tempo = 1.0, smaller values -// represent slower tempo, larger faster tempo. -void SoundTouch::setTempo(float newTempo) -{ - virtualTempo = newTempo; - calcEffectiveRateAndTempo(); -} - - - -// Sets new tempo control value as a difference in percents compared -// to the original tempo (-50 .. +100 %) -void SoundTouch::setTempoChange(float newTempo) -{ - virtualTempo = 1.0f + 0.01f * newTempo; - calcEffectiveRateAndTempo(); -} - - - -// Sets new pitch control value. Original pitch = 1.0, smaller values -// represent lower pitches, larger values higher pitch. -void SoundTouch::setPitch(float newPitch) -{ - virtualPitch = newPitch; - calcEffectiveRateAndTempo(); -} - - - -// Sets pitch change in octaves compared to the original pitch -// (-1.00 .. +1.00) -void SoundTouch::setPitchOctaves(float newPitch) -{ - virtualPitch = (float)exp(0.69314718056f * newPitch); - calcEffectiveRateAndTempo(); -} - - - -// Sets pitch change in semi-tones compared to the original pitch -// (-12 .. +12) -void SoundTouch::setPitchSemiTones(int newPitch) -{ - setPitchOctaves((float)newPitch / 12.0f); -} - - - -void SoundTouch::setPitchSemiTones(float newPitch) -{ - setPitchOctaves(newPitch / 12.0f); -} - - -// Calculates 'effective' rate and tempo values from the -// nominal control values. -void SoundTouch::calcEffectiveRateAndTempo() -{ - float oldTempo = tempo; - float oldRate = rate; - - tempo = virtualTempo / virtualPitch; - rate = virtualPitch * virtualRate; - - if (rate != oldRate) pRateTransposer->setRate(rate); - if (tempo != oldTempo) pTDStretch->setTempo(tempo); - - if (rate > 1.0f) - { - if (output != pRateTransposer) - { - FIFOSamplePipe *transOut; - - assert(output == pTDStretch); - // move samples in the current output buffer to the output of pRateTransposer - transOut = pRateTransposer->getOutput(); - transOut->moveSamples(*output); - // move samples in tempo changer's input to pitch transposer's input - pRateTransposer->moveSamples(*pTDStretch->getInput()); - - output = pRateTransposer; - } - } - else - { - if (output != pTDStretch) - { - FIFOSamplePipe *tempoOut; - - assert(output == pRateTransposer); - // move samples in the current output buffer to the output of pTDStretch - tempoOut = pTDStretch->getOutput(); - tempoOut->moveSamples(*output); - // move samples in pitch transposer's store buffer to tempo changer's input - pTDStretch->moveSamples(*pRateTransposer->getStore()); - - output = pTDStretch; - - } - } -} - - -// Sets sample rate. -void SoundTouch::setSampleRate(uint srate) -{ - bSrateSet = TRUE; - // set sample rate, leave other tempo changer parameters as they are. - pTDStretch->setParameters(srate); -} - - -// Adds 'numSamples' pcs of samples from the 'samples' memory position into -// the input of the object. -void SoundTouch::putSamples(const SAMPLETYPE *samples, uint numSamples) -{ - if (bSrateSet == FALSE) - { - throw std::runtime_error("SoundTouch : Sample rate not defined"); - } - else if (channels == 0) - { - throw std::runtime_error("SoundTouch : Number of channels not defined"); - } - - // Transpose the rate of the new samples if necessary - /* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value... - if (rate == 1.0f) - { - // The rate value is same as the original, simply evaluate the tempo changer. - assert(output == pTDStretch); - if (pRateTransposer->isEmpty() == 0) - { - // yet flush the last samples in the pitch transposer buffer - // (may happen if 'rate' changes from a non-zero value to zero) - pTDStretch->moveSamples(*pRateTransposer); - } - pTDStretch->putSamples(samples, numSamples); - } - */ - else if (rate <= 1.0f) - { - // transpose the rate down, output the transposed sound to tempo changer buffer - assert(output == pTDStretch); - pRateTransposer->putSamples(samples, numSamples); - pTDStretch->moveSamples(*pRateTransposer); - } - else - { - assert(rate > 1.0f); - // evaluate the tempo changer, then transpose the rate up, - assert(output == pRateTransposer); - pTDStretch->putSamples(samples, numSamples); - pRateTransposer->moveSamples(*pTDStretch); - } -} - - -// Flushes the last samples from the processing pipeline to the output. -// Clears also the internal processing buffers. -// -// Note: This function is meant for extracting the last samples of a sound -// stream. This function may introduce additional blank samples in the end -// of the sound stream, and thus it's not recommended to call this function -// in the middle of a sound stream. -void SoundTouch::flush() -{ - int i; - uint nOut; - SAMPLETYPE buff[128]; - - nOut = numSamples(); - - memset(buff, 0, 128 * sizeof(SAMPLETYPE)); - // "Push" the last active samples out from the processing pipeline by - // feeding blank samples into the processing pipeline until new, - // processed samples appear in the output (not however, more than - // 8ksamples in any case) - for (i = 0; i < 128; i ++) - { - putSamples(buff, 64); - if (numSamples() != nOut) break; // new samples have appeared in the output! - } - - // Clear working buffers - pRateTransposer->clear(); - pTDStretch->clearInput(); - // yet leave the 'tempoChanger' output intouched as that's where the - // flushed samples are! -} - - -// Changes a setting controlling the processing system behaviour. See the -// 'SETTING_...' defines for available setting ID's. -BOOL SoundTouch::setSetting(uint settingId, uint value) -{ - uint sampleRate, sequenceMs, seekWindowMs, overlapMs; - - // read current tdstretch routine parameters - pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs); - - switch (settingId) - { - case SETTING_USE_AA_FILTER : - // enables / disabless anti-alias filter - pRateTransposer->enableAAFilter((value != 0) ? TRUE : FALSE); - return TRUE; - - case SETTING_AA_FILTER_LENGTH : - // sets anti-alias filter length - pRateTransposer->getAAFilter()->setLength(value); - return TRUE; - - case SETTING_USE_QUICKSEEK : - // enables / disables tempo routine quick seeking algorithm - pTDStretch->enableQuickSeek((value != 0) ? TRUE : FALSE); - return TRUE; - - case SETTING_SEQUENCE_MS: - // change time-stretch sequence duration parameter - pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs); - return TRUE; - - case SETTING_SEEKWINDOW_MS: - // change time-stretch seek window length parameter - pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs); - return TRUE; - - case SETTING_OVERLAP_MS: - // change time-stretch overlap length parameter - pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value); - return TRUE; - - default : - return FALSE; - } -} - - -// Reads a setting controlling the processing system behaviour. See the -// 'SETTING_...' defines for available setting ID's. -// -// Returns the setting value. -uint SoundTouch::getSetting(uint settingId) const -{ - uint temp; - - switch (settingId) - { - case SETTING_USE_AA_FILTER : - return pRateTransposer->isAAFilterEnabled(); - - case SETTING_AA_FILTER_LENGTH : - return pRateTransposer->getAAFilter()->getLength(); - - case SETTING_USE_QUICKSEEK : - return pTDStretch->isQuickSeekEnabled(); - - case SETTING_SEQUENCE_MS: - pTDStretch->getParameters(NULL, &temp, NULL, NULL); - return temp; - - case SETTING_SEEKWINDOW_MS: - pTDStretch->getParameters(NULL, NULL, &temp, NULL); - return temp; - - case SETTING_OVERLAP_MS: - pTDStretch->getParameters(NULL, NULL, NULL, &temp); - return temp; - - default : - return 0; - } -} - - -// Clears all the samples in the object's output and internal processing -// buffers. -void SoundTouch::clear() -{ - pRateTransposer->clear(); - pTDStretch->clear(); -} - - - -/// Returns number of samples currently unprocessed. -uint SoundTouch::numUnprocessedSamples() const -{ - FIFOSamplePipe * psp; - if (pTDStretch) - { - psp = pTDStretch->getInput(); - if (psp) - { - return psp->numSamples(); - } - } - return 0; -} +////////////////////////////////////////////////////////////////////////////// +/// +/// SoundTouch - main class for tempo/pitch/rate adjusting routines. +/// +/// Notes: +/// - Initialize the SoundTouch object instance by setting up the sound stream +/// parameters with functions 'setSampleRate' and 'setChannels', then set +/// desired tempo/pitch/rate settings with the corresponding functions. +/// +/// - The SoundTouch class behaves like a first-in-first-out pipeline: The +/// samples that are to be processed are fed into one of the pipe by calling +/// function 'putSamples', while the ready processed samples can be read +/// from the other end of the pipeline with function 'receiveSamples'. +/// +/// - The SoundTouch processing classes require certain sized 'batches' of +/// samples in order to process the sound. For this reason the classes buffer +/// incoming samples until there are enough of samples available for +/// processing, then they carry out the processing step and consequently +/// make the processed samples available for outputting. +/// +/// - For the above reason, the processing routines introduce a certain +/// 'latency' between the input and output, so that the samples input to +/// SoundTouch may not be immediately available in the output, and neither +/// the amount of outputtable samples may not immediately be in direct +/// relationship with the amount of previously input samples. +/// +/// - The tempo/pitch/rate control parameters can be altered during processing. +/// Please notice though that they aren't currently protected by semaphores, +/// so in multi-thread application external semaphore protection may be +/// required. +/// +/// - This class utilizes classes 'TDStretch' for tempo change (without modifying +/// pitch) and 'RateTransposer' for changing the playback rate (that is, both +/// tempo and pitch in the same ratio) of the sound. The third available control +/// 'pitch' (change pitch but maintain tempo) is produced by a combination of +/// combining the two other controls. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.13 $ +// +// $Id: SoundTouch.cpp,v 1.13 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include "SoundTouch.h" +#include "TDStretch.h" +#include "RateTransposer.h" +#include "cpu_detect.h" + +using namespace soundtouch; + +/// Print library version string +extern "C" void soundtouch_ac_test() +{ + printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION); +} + + +SoundTouch::SoundTouch() +{ + // Initialize rate transposer and tempo changer instances + + pRateTransposer = RateTransposer::newInstance(); + pTDStretch = TDStretch::newInstance(); + + setOutPipe(pTDStretch); + + rate = tempo = 0; + + virtualPitch = + virtualRate = + virtualTempo = 1.0; + + calcEffectiveRateAndTempo(); + + channels = 0; + bSrateSet = FALSE; +} + + + +SoundTouch::~SoundTouch() +{ + delete pRateTransposer; + delete pTDStretch; +} + + + +/// Get SoundTouch library version string +const char *SoundTouch::getVersionString() +{ + static const char *_version = SOUNDTOUCH_VERSION; + + return _version; +} + + +/// Get SoundTouch library version Id +uint SoundTouch::getVersionId() +{ + return SOUNDTOUCH_VERSION_ID; +} + + +// Sets the number of channels, 1 = mono, 2 = stereo +void SoundTouch::setChannels(uint numChannels) +{ + if (numChannels != 1 && numChannels != 2) + { + throw std::runtime_error("Illegal number of channels"); + } + channels = numChannels; + pRateTransposer->setChannels(numChannels); + pTDStretch->setChannels(numChannels); +} + + + +// Sets new rate control value. Normal rate = 1.0, smaller values +// represent slower rate, larger faster rates. +void SoundTouch::setRate(float newRate) +{ + virtualRate = newRate; + calcEffectiveRateAndTempo(); +} + + + +// Sets new rate control value as a difference in percents compared +// to the original rate (-50 .. +100 %) +void SoundTouch::setRateChange(float newRate) +{ + virtualRate = 1.0f + 0.01f * newRate; + calcEffectiveRateAndTempo(); +} + + + +// Sets new tempo control value. Normal tempo = 1.0, smaller values +// represent slower tempo, larger faster tempo. +void SoundTouch::setTempo(float newTempo) +{ + virtualTempo = newTempo; + calcEffectiveRateAndTempo(); +} + + + +// Sets new tempo control value as a difference in percents compared +// to the original tempo (-50 .. +100 %) +void SoundTouch::setTempoChange(float newTempo) +{ + virtualTempo = 1.0f + 0.01f * newTempo; + calcEffectiveRateAndTempo(); +} + + + +// Sets new pitch control value. Original pitch = 1.0, smaller values +// represent lower pitches, larger values higher pitch. +void SoundTouch::setPitch(float newPitch) +{ + virtualPitch = newPitch; + calcEffectiveRateAndTempo(); +} + + + +// Sets pitch change in octaves compared to the original pitch +// (-1.00 .. +1.00) +void SoundTouch::setPitchOctaves(float newPitch) +{ + virtualPitch = (float)exp(0.69314718056f * newPitch); + calcEffectiveRateAndTempo(); +} + + + +// Sets pitch change in semi-tones compared to the original pitch +// (-12 .. +12) +void SoundTouch::setPitchSemiTones(int newPitch) +{ + setPitchOctaves((float)newPitch / 12.0f); +} + + + +void SoundTouch::setPitchSemiTones(float newPitch) +{ + setPitchOctaves(newPitch / 12.0f); +} + + +// Calculates 'effective' rate and tempo values from the +// nominal control values. +void SoundTouch::calcEffectiveRateAndTempo() +{ + float oldTempo = tempo; + float oldRate = rate; + + tempo = virtualTempo / virtualPitch; + rate = virtualPitch * virtualRate; + + if (rate != oldRate) pRateTransposer->setRate(rate); + if (tempo != oldTempo) pTDStretch->setTempo(tempo); + + if (rate > 1.0f) + { + if (output != pRateTransposer) + { + FIFOSamplePipe *transOut; + + assert(output == pTDStretch); + // move samples in the current output buffer to the output of pRateTransposer + transOut = pRateTransposer->getOutput(); + transOut->moveSamples(*output); + // move samples in tempo changer's input to pitch transposer's input + pRateTransposer->moveSamples(*pTDStretch->getInput()); + + output = pRateTransposer; + } + } + else + { + if (output != pTDStretch) + { + FIFOSamplePipe *tempoOut; + + assert(output == pRateTransposer); + // move samples in the current output buffer to the output of pTDStretch + tempoOut = pTDStretch->getOutput(); + tempoOut->moveSamples(*output); + // move samples in pitch transposer's store buffer to tempo changer's input + pTDStretch->moveSamples(*pRateTransposer->getStore()); + + output = pTDStretch; + + } + } +} + + +// Sets sample rate. +void SoundTouch::setSampleRate(uint srate) +{ + bSrateSet = TRUE; + // set sample rate, leave other tempo changer parameters as they are. + pTDStretch->setParameters(srate); +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void SoundTouch::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + if (bSrateSet == FALSE) + { + throw std::runtime_error("SoundTouch : Sample rate not defined"); + } + else if (channels == 0) + { + throw std::runtime_error("SoundTouch : Number of channels not defined"); + } + + // Transpose the rate of the new samples if necessary + /* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value... + if (rate == 1.0f) + { + // The rate value is same as the original, simply evaluate the tempo changer. + assert(output == pTDStretch); + if (pRateTransposer->isEmpty() == 0) + { + // yet flush the last samples in the pitch transposer buffer + // (may happen if 'rate' changes from a non-zero value to zero) + pTDStretch->moveSamples(*pRateTransposer); + } + pTDStretch->putSamples(samples, numSamples); + } + */ + else if (rate <= 1.0f) + { + // transpose the rate down, output the transposed sound to tempo changer buffer + assert(output == pTDStretch); + pRateTransposer->putSamples(samples, numSamples); + pTDStretch->moveSamples(*pRateTransposer); + } + else + { + assert(rate > 1.0f); + // evaluate the tempo changer, then transpose the rate up, + assert(output == pRateTransposer); + pTDStretch->putSamples(samples, numSamples); + pRateTransposer->moveSamples(*pTDStretch); + } +} + + +// Flushes the last samples from the processing pipeline to the output. +// Clears also the internal processing buffers. +// +// Note: This function is meant for extracting the last samples of a sound +// stream. This function may introduce additional blank samples in the end +// of the sound stream, and thus it's not recommended to call this function +// in the middle of a sound stream. +void SoundTouch::flush() +{ + int i; + uint nOut; + SAMPLETYPE buff[128]; + + nOut = numSamples(); + + memset(buff, 0, 128 * sizeof(SAMPLETYPE)); + // "Push" the last active samples out from the processing pipeline by + // feeding blank samples into the processing pipeline until new, + // processed samples appear in the output (not however, more than + // 8ksamples in any case) + for (i = 0; i < 128; i ++) + { + putSamples(buff, 64); + if (numSamples() != nOut) break; // new samples have appeared in the output! + } + + // Clear working buffers + pRateTransposer->clear(); + pTDStretch->clearInput(); + // yet leave the 'tempoChanger' output intouched as that's where the + // flushed samples are! +} + + +// Changes a setting controlling the processing system behaviour. See the +// 'SETTING_...' defines for available setting ID's. +BOOL SoundTouch::setSetting(uint settingId, uint value) +{ + uint sampleRate, sequenceMs, seekWindowMs, overlapMs; + + // read current tdstretch routine parameters + pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs); + + switch (settingId) + { + case SETTING_USE_AA_FILTER : + // enables / disabless anti-alias filter + pRateTransposer->enableAAFilter((value != 0) ? TRUE : FALSE); + return TRUE; + + case SETTING_AA_FILTER_LENGTH : + // sets anti-alias filter length + pRateTransposer->getAAFilter()->setLength(value); + return TRUE; + + case SETTING_USE_QUICKSEEK : + // enables / disables tempo routine quick seeking algorithm + pTDStretch->enableQuickSeek((value != 0) ? TRUE : FALSE); + return TRUE; + + case SETTING_SEQUENCE_MS: + // change time-stretch sequence duration parameter + pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs); + return TRUE; + + case SETTING_SEEKWINDOW_MS: + // change time-stretch seek window length parameter + pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs); + return TRUE; + + case SETTING_OVERLAP_MS: + // change time-stretch overlap length parameter + pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value); + return TRUE; + + default : + return FALSE; + } +} + + +// Reads a setting controlling the processing system behaviour. See the +// 'SETTING_...' defines for available setting ID's. +// +// Returns the setting value. +uint SoundTouch::getSetting(uint settingId) const +{ + uint temp; + + switch (settingId) + { + case SETTING_USE_AA_FILTER : + return pRateTransposer->isAAFilterEnabled(); + + case SETTING_AA_FILTER_LENGTH : + return pRateTransposer->getAAFilter()->getLength(); + + case SETTING_USE_QUICKSEEK : + return pTDStretch->isQuickSeekEnabled(); + + case SETTING_SEQUENCE_MS: + pTDStretch->getParameters(NULL, &temp, NULL, NULL); + return temp; + + case SETTING_SEEKWINDOW_MS: + pTDStretch->getParameters(NULL, NULL, &temp, NULL); + return temp; + + case SETTING_OVERLAP_MS: + pTDStretch->getParameters(NULL, NULL, NULL, &temp); + return temp; + + default : + return 0; + } +} + + +// Clears all the samples in the object's output and internal processing +// buffers. +void SoundTouch::clear() +{ + pRateTransposer->clear(); + pTDStretch->clear(); +} + + + +/// Returns number of samples currently unprocessed. +uint SoundTouch::numUnprocessedSamples() const +{ + FIFOSamplePipe * psp; + if (pTDStretch) + { + psp = pTDStretch->getInput(); + if (psp) + { + return psp->numSamples(); + } + } + return 0; +} diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/SoundTouch.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/SoundTouch.h index fab3bb9845..9f3a152f26 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/SoundTouch.h +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/SoundTouch.h @@ -1,252 +1,252 @@ -////////////////////////////////////////////////////////////////////////////// -/// -/// SoundTouch - main class for tempo/pitch/rate adjusting routines. -/// -/// Notes: -/// - Initialize the SoundTouch object instance by setting up the sound stream -/// parameters with functions 'setSampleRate' and 'setChannels', then set -/// desired tempo/pitch/rate settings with the corresponding functions. -/// -/// - The SoundTouch class behaves like a first-in-first-out pipeline: The -/// samples that are to be processed are fed into one of the pipe by calling -/// function 'putSamples', while the ready processed samples can be read -/// from the other end of the pipeline with function 'receiveSamples'. -/// -/// - The SoundTouch processing classes require certain sized 'batches' of -/// samples in order to process the sound. For this reason the classes buffer -/// incoming samples until there are enough of samples available for -/// processing, then they carry out the processing step and consequently -/// make the processed samples available for outputting. -/// -/// - For the above reason, the processing routines introduce a certain -/// 'latency' between the input and output, so that the samples input to -/// SoundTouch may not be immediately available in the output, and neither -/// the amount of outputtable samples may not immediately be in direct -/// relationship with the amount of previously input samples. -/// -/// - The tempo/pitch/rate control parameters can be altered during processing. -/// Please notice though that they aren't currently protected by semaphores, -/// so in multi-thread application external semaphore protection may be -/// required. -/// -/// - This class utilizes classes 'TDStretch' for tempo change (without modifying -/// pitch) and 'RateTransposer' for changing the playback rate (that is, both -/// tempo and pitch in the same ratio) of the sound. The third available control -/// 'pitch' (change pitch but maintain tempo) is produced by a combination of -/// combining the two other controls. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.14 $ -// -// $Id: SoundTouch.h,v 1.14 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef SoundTouch_H -#define SoundTouch_H - -#include "FIFOSamplePipe.h" -#include "STTypes.h" - -namespace soundtouch -{ - -/// Soundtouch library version string -#define SOUNDTOUCH_VERSION "1.3.1" - -/// SoundTouch library version id -#define SOUNDTOUCH_VERSION_ID 010301 - -// -// Available setting IDs for the 'setSetting' & 'get_setting' functions: - -/// Enable/disable anti-alias filter in pitch transposer (0 = disable) -#define SETTING_USE_AA_FILTER 0 - -/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32) -#define SETTING_AA_FILTER_LENGTH 1 - -/// Enable/disable quick seeking algorithm in tempo changer routine -/// (enabling quick seeking lowers CPU utilization but causes a minor sound -/// quality compromising) -#define SETTING_USE_QUICKSEEK 2 - -/// Time-stretch algorithm single processing sequence length in milliseconds. This determines -/// to how long sequences the original sound is chopped in the time-stretch algorithm. -/// See "STTypes.h" or README for more information. -#define SETTING_SEQUENCE_MS 3 - -/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the -/// best possible overlapping location. This determines from how wide window the algorithm -/// may look for an optimal joining location when mixing the sound sequences back together. -/// See "STTypes.h" or README for more information. -#define SETTING_SEEKWINDOW_MS 4 - -/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences -/// are mixed back together, to form a continuous sound stream, this parameter defines over -/// how long period the two consecutive sequences are let to overlap each other. -/// See "STTypes.h" or README for more information. -#define SETTING_OVERLAP_MS 5 - - -class SoundTouch : public FIFOProcessor -{ -private: - /// Rate transposer class instance - class RateTransposer *pRateTransposer; - - /// Time-stretch class instance - class TDStretch *pTDStretch; - - /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. - float virtualRate; - - /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. - float virtualTempo; - - /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. - float virtualPitch; - - /// Flag: Has sample rate been set? - BOOL bSrateSet; - - /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and - /// 'virtualPitch' parameters. - void calcEffectiveRateAndTempo(); - -protected : - /// Number of channels - uint channels; - - /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' - float rate; - - /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' - float tempo; - -public: - SoundTouch(); - virtual ~SoundTouch(); - - /// Get SoundTouch library version string - static const char *getVersionString(); - - /// Get SoundTouch library version Id - static uint getVersionId(); - - /// Sets new rate control value. Normal rate = 1.0, smaller values - /// represent slower rate, larger faster rates. - void setRate(float newRate); - - /// Sets new tempo control value. Normal tempo = 1.0, smaller values - /// represent slower tempo, larger faster tempo. - void setTempo(float newTempo); - - /// Sets new rate control value as a difference in percents compared - /// to the original rate (-50 .. +100 %) - void setRateChange(float newRate); - - /// Sets new tempo control value as a difference in percents compared - /// to the original tempo (-50 .. +100 %) - void setTempoChange(float newTempo); - - /// Sets new pitch control value. Original pitch = 1.0, smaller values - /// represent lower pitches, larger values higher pitch. - void setPitch(float newPitch); - - /// Sets pitch change in octaves compared to the original pitch - /// (-1.00 .. +1.00) - void setPitchOctaves(float newPitch); - - /// Sets pitch change in semi-tones compared to the original pitch - /// (-12 .. +12) - void setPitchSemiTones(int newPitch); - void setPitchSemiTones(float newPitch); - - /// Sets the number of channels, 1 = mono, 2 = stereo - void setChannels(uint numChannels); - - /// Sets sample rate. - void setSampleRate(uint srate); - - /// Flushes the last samples from the processing pipeline to the output. - /// Clears also the internal processing buffers. - // - /// Note: This function is meant for extracting the last samples of a sound - /// stream. This function may introduce additional blank samples in the end - /// of the sound stream, and thus it's not recommended to call this function - /// in the middle of a sound stream. - void flush(); - - /// Adds 'numSamples' pcs of samples from the 'samples' memory position into - /// the input of the object. Notice that sample rate _has_to_ be set before - /// calling this function, otherwise throws a runtime_error exception. - virtual void putSamples( - const SAMPLETYPE *samples, ///< Pointer to sample buffer. - uint numSamples ///< Number of samples in buffer. Notice - ///< that in case of stereo-sound a single sample - ///< contains data for both channels. - ); - - /// Clears all the samples in the object's output and internal processing - /// buffers. - virtual void clear(); - - /// Changes a setting controlling the processing system behaviour. See the - /// 'SETTING_...' defines for available setting ID's. - /// - /// \return 'TRUE' if the setting was succesfully changed - BOOL setSetting(uint settingId, ///< Setting ID number. see SETTING_... defines. - uint value ///< New setting value. - ); - - /// Reads a setting controlling the processing system behaviour. See the - /// 'SETTING_...' defines for available setting ID's. - /// - /// \return the setting value. - uint getSetting(uint settingId ///< Setting ID number, see SETTING_... defines. - ) const; - - /// Returns number of samples currently unprocessed. - virtual uint numUnprocessedSamples() const; - - - /// Other handy functions that are implemented in the ancestor classes (see - /// classes 'FIFOProcessor' and 'FIFOSamplePipe') - /// - /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch. - /// - numSamples() : Get number of 'ready' samples that can be received with - /// function 'receiveSamples()' - /// - isEmpty() : Returns nonzero if there aren't any 'ready' samples. - /// - clear() : Clears all samples from ready/processing buffers. -}; - -} -#endif +////////////////////////////////////////////////////////////////////////////// +/// +/// SoundTouch - main class for tempo/pitch/rate adjusting routines. +/// +/// Notes: +/// - Initialize the SoundTouch object instance by setting up the sound stream +/// parameters with functions 'setSampleRate' and 'setChannels', then set +/// desired tempo/pitch/rate settings with the corresponding functions. +/// +/// - The SoundTouch class behaves like a first-in-first-out pipeline: The +/// samples that are to be processed are fed into one of the pipe by calling +/// function 'putSamples', while the ready processed samples can be read +/// from the other end of the pipeline with function 'receiveSamples'. +/// +/// - The SoundTouch processing classes require certain sized 'batches' of +/// samples in order to process the sound. For this reason the classes buffer +/// incoming samples until there are enough of samples available for +/// processing, then they carry out the processing step and consequently +/// make the processed samples available for outputting. +/// +/// - For the above reason, the processing routines introduce a certain +/// 'latency' between the input and output, so that the samples input to +/// SoundTouch may not be immediately available in the output, and neither +/// the amount of outputtable samples may not immediately be in direct +/// relationship with the amount of previously input samples. +/// +/// - The tempo/pitch/rate control parameters can be altered during processing. +/// Please notice though that they aren't currently protected by semaphores, +/// so in multi-thread application external semaphore protection may be +/// required. +/// +/// - This class utilizes classes 'TDStretch' for tempo change (without modifying +/// pitch) and 'RateTransposer' for changing the playback rate (that is, both +/// tempo and pitch in the same ratio) of the sound. The third available control +/// 'pitch' (change pitch but maintain tempo) is produced by a combination of +/// combining the two other controls. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.14 $ +// +// $Id: SoundTouch.h,v 1.14 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef SoundTouch_H +#define SoundTouch_H + +#include "FIFOSamplePipe.h" +#include "STTypes.h" + +namespace soundtouch +{ + +/// Soundtouch library version string +#define SOUNDTOUCH_VERSION "1.3.1" + +/// SoundTouch library version id +#define SOUNDTOUCH_VERSION_ID 010301 + +// +// Available setting IDs for the 'setSetting' & 'get_setting' functions: + +/// Enable/disable anti-alias filter in pitch transposer (0 = disable) +#define SETTING_USE_AA_FILTER 0 + +/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32) +#define SETTING_AA_FILTER_LENGTH 1 + +/// Enable/disable quick seeking algorithm in tempo changer routine +/// (enabling quick seeking lowers CPU utilization but causes a minor sound +/// quality compromising) +#define SETTING_USE_QUICKSEEK 2 + +/// Time-stretch algorithm single processing sequence length in milliseconds. This determines +/// to how long sequences the original sound is chopped in the time-stretch algorithm. +/// See "STTypes.h" or README for more information. +#define SETTING_SEQUENCE_MS 3 + +/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the +/// best possible overlapping location. This determines from how wide window the algorithm +/// may look for an optimal joining location when mixing the sound sequences back together. +/// See "STTypes.h" or README for more information. +#define SETTING_SEEKWINDOW_MS 4 + +/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences +/// are mixed back together, to form a continuous sound stream, this parameter defines over +/// how long period the two consecutive sequences are let to overlap each other. +/// See "STTypes.h" or README for more information. +#define SETTING_OVERLAP_MS 5 + + +class SoundTouch : public FIFOProcessor +{ +private: + /// Rate transposer class instance + class RateTransposer *pRateTransposer; + + /// Time-stretch class instance + class TDStretch *pTDStretch; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualRate; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualTempo; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualPitch; + + /// Flag: Has sample rate been set? + BOOL bSrateSet; + + /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and + /// 'virtualPitch' parameters. + void calcEffectiveRateAndTempo(); + +protected : + /// Number of channels + uint channels; + + /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' + float rate; + + /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' + float tempo; + +public: + SoundTouch(); + virtual ~SoundTouch(); + + /// Get SoundTouch library version string + static const char *getVersionString(); + + /// Get SoundTouch library version Id + static uint getVersionId(); + + /// Sets new rate control value. Normal rate = 1.0, smaller values + /// represent slower rate, larger faster rates. + void setRate(float newRate); + + /// Sets new tempo control value. Normal tempo = 1.0, smaller values + /// represent slower tempo, larger faster tempo. + void setTempo(float newTempo); + + /// Sets new rate control value as a difference in percents compared + /// to the original rate (-50 .. +100 %) + void setRateChange(float newRate); + + /// Sets new tempo control value as a difference in percents compared + /// to the original tempo (-50 .. +100 %) + void setTempoChange(float newTempo); + + /// Sets new pitch control value. Original pitch = 1.0, smaller values + /// represent lower pitches, larger values higher pitch. + void setPitch(float newPitch); + + /// Sets pitch change in octaves compared to the original pitch + /// (-1.00 .. +1.00) + void setPitchOctaves(float newPitch); + + /// Sets pitch change in semi-tones compared to the original pitch + /// (-12 .. +12) + void setPitchSemiTones(int newPitch); + void setPitchSemiTones(float newPitch); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint numChannels); + + /// Sets sample rate. + void setSampleRate(uint srate); + + /// Flushes the last samples from the processing pipeline to the output. + /// Clears also the internal processing buffers. + // + /// Note: This function is meant for extracting the last samples of a sound + /// stream. This function may introduce additional blank samples in the end + /// of the sound stream, and thus it's not recommended to call this function + /// in the middle of a sound stream. + void flush(); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position into + /// the input of the object. Notice that sample rate _has_to_ be set before + /// calling this function, otherwise throws a runtime_error exception. + virtual void putSamples( + const SAMPLETYPE *samples, ///< Pointer to sample buffer. + uint numSamples ///< Number of samples in buffer. Notice + ///< that in case of stereo-sound a single sample + ///< contains data for both channels. + ); + + /// Clears all the samples in the object's output and internal processing + /// buffers. + virtual void clear(); + + /// Changes a setting controlling the processing system behaviour. See the + /// 'SETTING_...' defines for available setting ID's. + /// + /// \return 'TRUE' if the setting was succesfully changed + BOOL setSetting(uint settingId, ///< Setting ID number. see SETTING_... defines. + uint value ///< New setting value. + ); + + /// Reads a setting controlling the processing system behaviour. See the + /// 'SETTING_...' defines for available setting ID's. + /// + /// \return the setting value. + uint getSetting(uint settingId ///< Setting ID number, see SETTING_... defines. + ) const; + + /// Returns number of samples currently unprocessed. + virtual uint numUnprocessedSamples() const; + + + /// Other handy functions that are implemented in the ancestor classes (see + /// classes 'FIFOProcessor' and 'FIFOSamplePipe') + /// + /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch. + /// - numSamples() : Get number of 'ready' samples that can be received with + /// function 'receiveSamples()' + /// - isEmpty() : Returns nonzero if there aren't any 'ready' samples. + /// - clear() : Clears all samples from ready/processing buffers. +}; + +} +#endif diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/TDStretch.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/TDStretch.cpp index d809623689..339c7378fb 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/TDStretch.cpp +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/TDStretch.cpp @@ -1,940 +1,940 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo -/// while maintaining the original pitch by using a time domain WSOLA-like -/// method with several performance-increasing tweaks. -/// -/// Note : MMX optimized functions reside in a separate, platform-specific -/// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.24 $ -// -// $Id: TDStretch.cpp,v 1.24 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include - -#include "STTypes.h" -#include "cpu_detect.h" -#include "TDStretch.h" - -using namespace soundtouch; - -#ifndef min -#define min(a,b) ((a > b) ? b : a) -#define max(a,b) ((a < b) ? b : a) -#endif - - - -/***************************************************************************** - * - * Constant definitions - * - *****************************************************************************/ - - -// Table for the hierarchical mixing position seeking algorithm -int scanOffsets[4][24]={ - { 124, 186, 248, 310, 372, 434, 496, 558, 620, 682, 744, 806, - 868, 930, 992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488, 0}, - {-100, -75, -50, -25, 25, 50, 75, 100, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { -20, -15, -10, -5, 5, 10, 15, 20, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { -4, -3, -2, -1, 1, 2, 3, 4, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; - -/***************************************************************************** - * - * Implementation of the class 'TDStretch' - * - *****************************************************************************/ - - -TDStretch::TDStretch() : FIFOProcessor(&outputBuffer) -{ - bQuickseek = FALSE; - channels = 2; - bMidBufferDirty = FALSE; - - pMidBuffer = NULL; - pRefMidBufferUnaligned = NULL; - overlapLength = 0; - - setParameters(48000, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS); - - setTempo(1.0f); -} - - - - -TDStretch::~TDStretch() -{ - delete[] pMidBuffer; - delete[] pRefMidBufferUnaligned; -} - - - -// Calculates the x having the closest 2^x value for the given value -static int _getClosest2Power(double value) -{ - return (int)(log(value) / log(2.0) + 0.5); -} - - - -// Sets routine control parameters. These control are certain time constants -// defining how the sound is stretched to the desired duration. -// -// 'sampleRate' = sample rate of the sound -// 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms) -// 'seekwindowMS' = seeking window length for scanning the best overlapping -// position (default = 28 ms) -// 'overlapMS' = overlapping length (default = 12 ms) - -void TDStretch::setParameters(uint aSampleRate, uint aSequenceMS, - uint aSeekWindowMS, uint aOverlapMS) -{ - this->sampleRate = aSampleRate; - this->sequenceMs = aSequenceMS; - this->seekWindowMs = aSeekWindowMS; - this->overlapMs = aOverlapMS; - - seekLength = (sampleRate * seekWindowMs) / 1000; - seekWindowLength = (sampleRate * sequenceMs) / 1000; - - maxOffset = seekLength; - - calculateOverlapLength(overlapMs); - - // set tempo to recalculate 'sampleReq' - setTempo(tempo); - -} - - - -/// Get routine control parameters, see setParameters() function. -/// Any of the parameters to this function can be NULL, in such case corresponding parameter -/// value isn't returned. -void TDStretch::getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs) -{ - if (pSampleRate) - { - *pSampleRate = sampleRate; - } - - if (pSequenceMs) - { - *pSequenceMs = sequenceMs; - } - - if (pSeekWindowMs) - { - *pSeekWindowMs = seekWindowMs; - } - - if (pOverlapMs) - { - *pOverlapMs = overlapMs; - } -} - - -// Overlaps samples in 'midBuffer' with the samples in 'input' -void TDStretch::overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const -{ - int i, itemp; - - for (i = 0; i < (int)overlapLength ; i ++) - { - itemp = overlapLength - i; - output[i] = (input[i] * i + pMidBuffer[i] * itemp ) / overlapLength; // >> overlapDividerBits; - } -} - - - -void TDStretch::clearMidBuffer() -{ - if (bMidBufferDirty) - { - memset(pMidBuffer, 0, 2 * sizeof(SAMPLETYPE) * overlapLength); - bMidBufferDirty = FALSE; - } -} - - -void TDStretch::clearInput() -{ - inputBuffer.clear(); - clearMidBuffer(); -} - - -// Clears the sample buffers -void TDStretch::clear() -{ - outputBuffer.clear(); - inputBuffer.clear(); - clearMidBuffer(); -} - - - -// Enables/disables the quick position seeking algorithm. Zero to disable, nonzero -// to enable -void TDStretch::enableQuickSeek(BOOL enable) -{ - bQuickseek = enable; -} - - -// Returns nonzero if the quick seeking algorithm is enabled. -BOOL TDStretch::isQuickSeekEnabled() const -{ - return bQuickseek; -} - - -// Seeks for the optimal overlap-mixing position. -uint TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos) -{ - if (channels == 2) - { - // stereo sound - if (bQuickseek) - { - return seekBestOverlapPositionStereoQuick(refPos); - } - else - { - return seekBestOverlapPositionStereo(refPos); - } - } - else - { - // mono sound - if (bQuickseek) - { - return seekBestOverlapPositionMonoQuick(refPos); - } - else - { - return seekBestOverlapPositionMono(refPos); - } - } -} - - - - -// Overlaps samples in 'midBuffer' with the samples in 'inputBuffer' at position -// of 'ovlPos'. -inline void TDStretch::overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const -{ - if (channels == 2) - { - // stereo sound - overlapStereo(output, input + 2 * ovlPos); - } else { - // mono sound. - overlapMono(output, input + ovlPos); - } -} - - - - -// Seeks for the optimal overlap-mixing position. The 'stereo' version of the -// routine -// -// The best position is determined as the position where the two overlapped -// sample sequences are 'most alike', in terms of the highest cross-correlation -// value over the overlapping period -uint TDStretch::seekBestOverlapPositionStereo(const SAMPLETYPE *refPos) -{ - uint bestOffs; - LONG_SAMPLETYPE bestCorr, corr; - uint i; - - // Slopes the amplitudes of the 'midBuffer' samples - precalcCorrReferenceStereo(); - - bestCorr = INT_MIN; - bestOffs = 0; - - // Scans for the best correlation value by testing each possible position - // over the permitted range. - for (i = 0; i < seekLength; i ++) - { - // Calculates correlation value for the mixing position corresponding - // to 'i' - corr = calcCrossCorrStereo(refPos + 2 * i, pRefMidBuffer); - - // Checks for the highest correlation value - if (corr > bestCorr) - { - bestCorr = corr; - bestOffs = i; - } - } - // clear cross correlation routine state if necessary (is so e.g. in MMX routines). - clearCrossCorrState(); - - return bestOffs; -} - - -// Seeks for the optimal overlap-mixing position. The 'stereo' version of the -// routine -// -// The best position is determined as the position where the two overlapped -// sample sequences are 'most alike', in terms of the highest cross-correlation -// value over the overlapping period -uint TDStretch::seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos) -{ - uint j; - uint bestOffs; - LONG_SAMPLETYPE bestCorr, corr; - uint scanCount, corrOffset, tempOffset; - - // Slopes the amplitude of the 'midBuffer' samples - precalcCorrReferenceStereo(); - - bestCorr = INT_MIN; - bestOffs = 0; - corrOffset = 0; - tempOffset = 0; - - // Scans for the best correlation value using four-pass hierarchical search. - // - // The look-up table 'scans' has hierarchical position adjusting steps. - // In first pass the routine searhes for the highest correlation with - // relatively coarse steps, then rescans the neighbourhood of the highest - // correlation with better resolution and so on. - for (scanCount = 0;scanCount < 4; scanCount ++) - { - j = 0; - while (scanOffsets[scanCount][j]) - { - tempOffset = corrOffset + scanOffsets[scanCount][j]; - if (tempOffset >= seekLength) break; - - // Calculates correlation value for the mixing position corresponding - // to 'tempOffset' - corr = calcCrossCorrStereo(refPos + 2 * tempOffset, pRefMidBuffer); - - // Checks for the highest correlation value - if (corr > bestCorr) - { - bestCorr = corr; - bestOffs = tempOffset; - } - j ++; - } - corrOffset = bestOffs; - } - // clear cross correlation routine state if necessary (is so e.g. in MMX routines). - clearCrossCorrState(); - - return bestOffs; -} - - - -// Seeks for the optimal overlap-mixing position. The 'mono' version of the -// routine -// -// The best position is determined as the position where the two overlapped -// sample sequences are 'most alike', in terms of the highest cross-correlation -// value over the overlapping period -uint TDStretch::seekBestOverlapPositionMono(const SAMPLETYPE *refPos) -{ - uint bestOffs; - LONG_SAMPLETYPE bestCorr, corr; - uint tempOffset; - const SAMPLETYPE *compare; - - // Slopes the amplitude of the 'midBuffer' samples - precalcCorrReferenceMono(); - - bestCorr = INT_MIN; - bestOffs = 0; - - // Scans for the best correlation value by testing each possible position - // over the permitted range. - for (tempOffset = 0; tempOffset < seekLength; tempOffset ++) - { - compare = refPos + tempOffset; - - // Calculates correlation value for the mixing position corresponding - // to 'tempOffset' - corr = calcCrossCorrMono(pRefMidBuffer, compare); - - // Checks for the highest correlation value - if (corr > bestCorr) - { - bestCorr = corr; - bestOffs = tempOffset; - } - } - // clear cross correlation routine state if necessary (is so e.g. in MMX routines). - clearCrossCorrState(); - - return bestOffs; -} - - -// Seeks for the optimal overlap-mixing position. The 'mono' version of the -// routine -// -// The best position is determined as the position where the two overlapped -// sample sequences are 'most alike', in terms of the highest cross-correlation -// value over the overlapping period -uint TDStretch::seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos) -{ - uint j; - uint bestOffs; - LONG_SAMPLETYPE bestCorr, corr; - uint scanCount, corrOffset, tempOffset; - - // Slopes the amplitude of the 'midBuffer' samples - precalcCorrReferenceMono(); - - bestCorr = INT_MIN; - bestOffs = 0; - corrOffset = 0; - tempOffset = 0; - - // Scans for the best correlation value using four-pass hierarchical search. - // - // The look-up table 'scans' has hierarchical position adjusting steps. - // In first pass the routine searhes for the highest correlation with - // relatively coarse steps, then rescans the neighbourhood of the highest - // correlation with better resolution and so on. - for (scanCount = 0;scanCount < 4; scanCount ++) - { - j = 0; - while (scanOffsets[scanCount][j]) - { - tempOffset = corrOffset + scanOffsets[scanCount][j]; - if (tempOffset >= seekLength) break; - - // Calculates correlation value for the mixing position corresponding - // to 'tempOffset' - corr = calcCrossCorrMono(refPos + tempOffset, pRefMidBuffer); - - // Checks for the highest correlation value - if (corr > bestCorr) - { - bestCorr = corr; - bestOffs = tempOffset; - } - j ++; - } - corrOffset = bestOffs; - } - // clear cross correlation routine state if necessary (is so e.g. in MMX routines). - clearCrossCorrState(); - - return bestOffs; -} - - -/// clear cross correlation routine state if necessary -void TDStretch::clearCrossCorrState() -{ - // default implementation is empty. -} - - -// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower -// tempo, larger faster tempo. -void TDStretch::setTempo(float newTempo) -{ - uint intskip; - - tempo = newTempo; - - // Calculate ideal skip length (according to tempo value) - nominalSkip = tempo * (seekWindowLength - overlapLength); - skipFract = 0; - intskip = (int)(nominalSkip + 0.5f); - - // Calculate how many samples are needed in the 'inputBuffer' to - // process another batch of samples - sampleReq = max(intskip + overlapLength, seekWindowLength) + maxOffset; -} - - - -// Sets the number of channels, 1 = mono, 2 = stereo -void TDStretch::setChannels(uint numChannels) -{ - if (channels == numChannels) return; - assert(numChannels == 1 || numChannels == 2); - - channels = numChannels; - inputBuffer.setChannels(channels); - outputBuffer.setChannels(channels); -} - - -// nominal tempo, no need for processing, just pass the samples through -// to outputBuffer -void TDStretch::processNominalTempo() -{ - assert(tempo == 1.0f); - - if (bMidBufferDirty) - { - // If there are samples in pMidBuffer waiting for overlapping, - // do a single sliding overlapping with them in order to prevent a - // clicking distortion in the output sound - if (inputBuffer.numSamples() < overlapLength) - { - // wait until we've got overlapLength input samples - return; - } - // Mix the samples in the beginning of 'inputBuffer' with the - // samples in 'midBuffer' using sliding overlapping - overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0); - outputBuffer.putSamples(overlapLength); - inputBuffer.receiveSamples(overlapLength); - clearMidBuffer(); - // now we've caught the nominal sample flow and may switch to - // bypass mode - } - - // Simply bypass samples from input to output - outputBuffer.moveSamples(inputBuffer); -} - - -// Processes as many processing frames of the samples 'inputBuffer', store -// the result into 'outputBuffer' -void TDStretch::processSamples() -{ - uint ovlSkip, offset; - int temp; - - /* Removed this small optimization - can introduce a click to sound when tempo setting - crosses the nominal value - if (tempo == 1.0f) - { - // tempo not changed from the original, so bypass the processing - processNominalTempo(); - return; - } - */ - - if (bMidBufferDirty == FALSE) - { - // if midBuffer is empty, move the first samples of the input stream - // into it - if (inputBuffer.numSamples() < overlapLength) - { - // wait until we've got overlapLength samples - return; - } - memcpy(pMidBuffer, inputBuffer.ptrBegin(), channels * overlapLength * sizeof(SAMPLETYPE)); - inputBuffer.receiveSamples(overlapLength); - bMidBufferDirty = TRUE; - } - - // Process samples as long as there are enough samples in 'inputBuffer' - // to form a processing frame. - while (inputBuffer.numSamples() >= sampleReq) - { - // If tempo differs from the normal ('SCALE'), scan for the best overlapping - // position - offset = seekBestOverlapPosition(inputBuffer.ptrBegin()); - - // Mix the samples in the 'inputBuffer' at position of 'offset' with the - // samples in 'midBuffer' using sliding overlapping - // ... first partially overlap with the end of the previous sequence - // (that's in 'midBuffer') - overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), offset); - outputBuffer.putSamples(overlapLength); - - // ... then copy sequence samples from 'inputBuffer' to output - temp = (seekWindowLength - 2 * overlapLength);// & 0xfffffffe; - if (temp > 0) - { - outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * (offset + overlapLength), temp); - } - - // Copies the end of the current sequence from 'inputBuffer' to - // 'midBuffer' for being mixed with the beginning of the next - // processing sequence and so on - assert(offset + seekWindowLength <= inputBuffer.numSamples()); - memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + seekWindowLength - overlapLength), - channels * sizeof(SAMPLETYPE) * overlapLength); - bMidBufferDirty = TRUE; - - // Remove the processed samples from the input buffer. Update - // the difference between integer & nominal skip step to 'skipFract' - // in order to prevent the error from accumulating over time. - skipFract += nominalSkip; // real skip size - ovlSkip = (int)skipFract; // rounded to integer skip - skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip - inputBuffer.receiveSamples(ovlSkip); - } -} - - -// Adds 'numsamples' pcs of samples from the 'samples' memory position into -// the input of the object. -void TDStretch::putSamples(const SAMPLETYPE *samples, uint numSamples) -{ - // Add the samples into the input buffer - inputBuffer.putSamples(samples, numSamples); - // Process the samples in input buffer - processSamples(); -} - - - -/// Set new overlap length parameter & reallocate RefMidBuffer if necessary. -void TDStretch::acceptNewOverlapLength(uint newOverlapLength) -{ - uint prevOvl; - - prevOvl = overlapLength; - overlapLength = newOverlapLength; - - if (overlapLength > prevOvl) - { - delete[] pMidBuffer; - delete[] pRefMidBufferUnaligned; - - pMidBuffer = new SAMPLETYPE[overlapLength * 2]; - bMidBufferDirty = TRUE; - clearMidBuffer(); - - pRefMidBufferUnaligned = new SAMPLETYPE[2 * overlapLength + 16 / sizeof(SAMPLETYPE)]; - // ensure that 'pRefMidBuffer' is aligned to 16 byte boundary for efficiency - pRefMidBuffer = (SAMPLETYPE *)((((ulongptr)pRefMidBufferUnaligned) + 15) & -16); - } -} - - -// Operator 'new' is overloaded so that it automatically creates a suitable instance -// depending on if we've a MMX/SSE/etc-capable CPU available or not. -void * TDStretch::operator new(size_t s) -{ - // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! - assert(FALSE); - return NULL; -} - - -TDStretch * TDStretch::newInstance() -{ - uint uExtensions = 0; - -#if !defined(_MSC_VER) || !defined(__x86_64__) - uExtensions = detectCPUextensions(); -#endif - - // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU - -#ifdef ALLOW_MMX - // MMX routines available only with integer sample types - if (uExtensions & SUPPORT_MMX) - { - return ::new TDStretchMMX; - } - else -#endif // ALLOW_MMX - - -#ifdef ALLOW_SSE - if (uExtensions & SUPPORT_SSE) - { - // SSE support - return ::new TDStretchSSE; - } - else -#endif // ALLOW_SSE - - -#ifdef ALLOW_3DNOW - if (uExtensions & SUPPORT_3DNOW) - { - // 3DNow! support - return ::new TDStretch3DNow; - } - else -#endif // ALLOW_3DNOW - - { - // ISA optimizations not supported, use plain C version - return ::new TDStretch; - } -} - - -////////////////////////////////////////////////////////////////////////////// -// -// Integer arithmetics specific algorithm implementations. -// -////////////////////////////////////////////////////////////////////////////// - -#ifdef INTEGER_SAMPLES - -// Slopes the amplitude of the 'midBuffer' samples so that cross correlation -// is faster to calculate -void TDStretch::precalcCorrReferenceStereo() -{ - int i, cnt2; - int temp, temp2; - - for (i=0 ; i < (int)overlapLength ;i ++) - { - temp = i * (overlapLength - i); - cnt2 = i * 2; - - temp2 = (pMidBuffer[cnt2] * temp) / slopingDivider; - pRefMidBuffer[cnt2] = (short)(temp2); - temp2 = (pMidBuffer[cnt2 + 1] * temp) / slopingDivider; - pRefMidBuffer[cnt2 + 1] = (short)(temp2); - } -} - - -// Slopes the amplitude of the 'midBuffer' samples so that cross correlation -// is faster to calculate -void TDStretch::precalcCorrReferenceMono() -{ - int i; - long temp; - long temp2; - - for (i=0 ; i < (int)overlapLength ;i ++) - { - temp = i * (overlapLength - i); - temp2 = (pMidBuffer[i] * temp) / slopingDivider; - pRefMidBuffer[i] = (short)temp2; - } -} - - -// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo' -// version of the routine. -void TDStretch::overlapStereo(short *output, const short *input) const -{ - int i; - short temp; - uint cnt2; - - for (i = 0; i < (int)overlapLength ; i ++) - { - temp = (short)(overlapLength - i); - cnt2 = 2 * i; - output[cnt2] = (input[cnt2] * i + pMidBuffer[cnt2] * temp ) / overlapLength; - output[cnt2 + 1] = (input[cnt2 + 1] * i + pMidBuffer[cnt2 + 1] * temp ) / overlapLength; - } -} - - -/// Calculates overlap period length in samples. -/// Integer version rounds overlap length to closest power of 2 -/// for a divide scaling operation. -void TDStretch::calculateOverlapLength(uint overlapMs) -{ - uint newOvl; - - overlapDividerBits = _getClosest2Power((sampleRate * overlapMs) / 1000.0); - if (overlapDividerBits > 9) overlapDividerBits = 9; - if (overlapDividerBits < 4) overlapDividerBits = 4; - newOvl = 1<> overlapDividerBits; - } - - return corr; -} - - -long TDStretch::calcCrossCorrStereo(const short *mixingPos, const short *compare) const -{ - long corr; - uint i; - - corr = 0; - for (i = 2; i < 2 * overlapLength; i += 2) - { - corr += (mixingPos[i] * compare[i] + - mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBits; - } - - return corr; -} - -#endif // INTEGER_SAMPLES - -////////////////////////////////////////////////////////////////////////////// -// -// Floating point arithmetics specific algorithm implementations. -// - -#ifdef FLOAT_SAMPLES - - -// Slopes the amplitude of the 'midBuffer' samples so that cross correlation -// is faster to calculate -void TDStretch::precalcCorrReferenceStereo() -{ - int i, cnt2; - float temp; - - for (i=0 ; i < (int)overlapLength ;i ++) - { - temp = (float)i * (float)(overlapLength - i); - cnt2 = i * 2; - pRefMidBuffer[cnt2] = (float)(pMidBuffer[cnt2] * temp); - pRefMidBuffer[cnt2 + 1] = (float)(pMidBuffer[cnt2 + 1] * temp); - } -} - - -// Slopes the amplitude of the 'midBuffer' samples so that cross correlation -// is faster to calculate -void TDStretch::precalcCorrReferenceMono() -{ - int i; - float temp; - - for (i=0 ; i < (int)overlapLength ;i ++) - { - temp = (float)i * (float)(overlapLength - i); - pRefMidBuffer[i] = (float)(pMidBuffer[i] * temp); - } -} - - -// SSE-optimized version of the function overlapStereo -void TDStretch::overlapStereo(float *output, const float *input) const -{ - int i; - uint cnt2; - float fTemp; - float fScale; - float fi; - - fScale = 1.0f / (float)overlapLength; - - for (i = 0; i < (int)overlapLength ; i ++) - { - fTemp = (float)(overlapLength - i) * fScale; - fi = (float)i * fScale; - cnt2 = 2 * i; - output[cnt2 + 0] = input[cnt2 + 0] * fi + pMidBuffer[cnt2 + 0] * fTemp; - output[cnt2 + 1] = input[cnt2 + 1] * fi + pMidBuffer[cnt2 + 1] * fTemp; - } -} - - -/// Calculates overlap period length in samples. -void TDStretch::calculateOverlapLength(uint overlapMs) -{ - uint newOvl; - - newOvl = (sampleRate * overlapMs) / 1000; - if (newOvl < 16) newOvl = 16; - - // must be divisible by 8 - newOvl -= newOvl % 8; - - acceptNewOverlapLength(newOvl); -} - - - -double TDStretch::calcCrossCorrMono(const float *mixingPos, const float *compare) const -{ - double corr; - uint i; - - corr = 0; - for (i = 1; i < overlapLength; i ++) - { - corr += mixingPos[i] * compare[i]; - } - - return corr; -} - - -double TDStretch::calcCrossCorrStereo(const float *mixingPos, const float *compare) const -{ - double corr; - uint i; - - corr = 0; - for (i = 2; i < 2 * overlapLength; i += 2) - { - corr += mixingPos[i] * compare[i] + - mixingPos[i + 1] * compare[i + 1]; - } - - return corr; -} - -#endif // FLOAT_SAMPLES +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like +/// method with several performance-increasing tweaks. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific +/// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.24 $ +// +// $Id: TDStretch.cpp,v 1.24 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include "STTypes.h" +#include "cpu_detect.h" +#include "TDStretch.h" + +using namespace soundtouch; + +#ifndef min +#define min(a,b) ((a > b) ? b : a) +#define max(a,b) ((a < b) ? b : a) +#endif + + + +/***************************************************************************** + * + * Constant definitions + * + *****************************************************************************/ + + +// Table for the hierarchical mixing position seeking algorithm +int scanOffsets[4][24]={ + { 124, 186, 248, 310, 372, 434, 496, 558, 620, 682, 744, 806, + 868, 930, 992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488, 0}, + {-100, -75, -50, -25, 25, 50, 75, 100, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { -20, -15, -10, -5, 5, 10, 15, 20, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { -4, -3, -2, -1, 1, 2, 3, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; + +/***************************************************************************** + * + * Implementation of the class 'TDStretch' + * + *****************************************************************************/ + + +TDStretch::TDStretch() : FIFOProcessor(&outputBuffer) +{ + bQuickseek = FALSE; + channels = 2; + bMidBufferDirty = FALSE; + + pMidBuffer = NULL; + pRefMidBufferUnaligned = NULL; + overlapLength = 0; + + setParameters(48000, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS); + + setTempo(1.0f); +} + + + + +TDStretch::~TDStretch() +{ + delete[] pMidBuffer; + delete[] pRefMidBufferUnaligned; +} + + + +// Calculates the x having the closest 2^x value for the given value +static int _getClosest2Power(double value) +{ + return (int)(log(value) / log(2.0) + 0.5); +} + + + +// Sets routine control parameters. These control are certain time constants +// defining how the sound is stretched to the desired duration. +// +// 'sampleRate' = sample rate of the sound +// 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms) +// 'seekwindowMS' = seeking window length for scanning the best overlapping +// position (default = 28 ms) +// 'overlapMS' = overlapping length (default = 12 ms) + +void TDStretch::setParameters(uint aSampleRate, uint aSequenceMS, + uint aSeekWindowMS, uint aOverlapMS) +{ + this->sampleRate = aSampleRate; + this->sequenceMs = aSequenceMS; + this->seekWindowMs = aSeekWindowMS; + this->overlapMs = aOverlapMS; + + seekLength = (sampleRate * seekWindowMs) / 1000; + seekWindowLength = (sampleRate * sequenceMs) / 1000; + + maxOffset = seekLength; + + calculateOverlapLength(overlapMs); + + // set tempo to recalculate 'sampleReq' + setTempo(tempo); + +} + + + +/// Get routine control parameters, see setParameters() function. +/// Any of the parameters to this function can be NULL, in such case corresponding parameter +/// value isn't returned. +void TDStretch::getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs) +{ + if (pSampleRate) + { + *pSampleRate = sampleRate; + } + + if (pSequenceMs) + { + *pSequenceMs = sequenceMs; + } + + if (pSeekWindowMs) + { + *pSeekWindowMs = seekWindowMs; + } + + if (pOverlapMs) + { + *pOverlapMs = overlapMs; + } +} + + +// Overlaps samples in 'midBuffer' with the samples in 'input' +void TDStretch::overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const +{ + int i, itemp; + + for (i = 0; i < (int)overlapLength ; i ++) + { + itemp = overlapLength - i; + output[i] = (input[i] * i + pMidBuffer[i] * itemp ) / overlapLength; // >> overlapDividerBits; + } +} + + + +void TDStretch::clearMidBuffer() +{ + if (bMidBufferDirty) + { + memset(pMidBuffer, 0, 2 * sizeof(SAMPLETYPE) * overlapLength); + bMidBufferDirty = FALSE; + } +} + + +void TDStretch::clearInput() +{ + inputBuffer.clear(); + clearMidBuffer(); +} + + +// Clears the sample buffers +void TDStretch::clear() +{ + outputBuffer.clear(); + inputBuffer.clear(); + clearMidBuffer(); +} + + + +// Enables/disables the quick position seeking algorithm. Zero to disable, nonzero +// to enable +void TDStretch::enableQuickSeek(BOOL enable) +{ + bQuickseek = enable; +} + + +// Returns nonzero if the quick seeking algorithm is enabled. +BOOL TDStretch::isQuickSeekEnabled() const +{ + return bQuickseek; +} + + +// Seeks for the optimal overlap-mixing position. +uint TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos) +{ + if (channels == 2) + { + // stereo sound + if (bQuickseek) + { + return seekBestOverlapPositionStereoQuick(refPos); + } + else + { + return seekBestOverlapPositionStereo(refPos); + } + } + else + { + // mono sound + if (bQuickseek) + { + return seekBestOverlapPositionMonoQuick(refPos); + } + else + { + return seekBestOverlapPositionMono(refPos); + } + } +} + + + + +// Overlaps samples in 'midBuffer' with the samples in 'inputBuffer' at position +// of 'ovlPos'. +inline void TDStretch::overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const +{ + if (channels == 2) + { + // stereo sound + overlapStereo(output, input + 2 * ovlPos); + } else { + // mono sound. + overlapMono(output, input + ovlPos); + } +} + + + + +// Seeks for the optimal overlap-mixing position. The 'stereo' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionStereo(const SAMPLETYPE *refPos) +{ + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint i; + + // Slopes the amplitudes of the 'midBuffer' samples + precalcCorrReferenceStereo(); + + bestCorr = INT_MIN; + bestOffs = 0; + + // Scans for the best correlation value by testing each possible position + // over the permitted range. + for (i = 0; i < seekLength; i ++) + { + // Calculates correlation value for the mixing position corresponding + // to 'i' + corr = calcCrossCorrStereo(refPos + 2 * i, pRefMidBuffer); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = i; + } + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + +// Seeks for the optimal overlap-mixing position. The 'stereo' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos) +{ + uint j; + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint scanCount, corrOffset, tempOffset; + + // Slopes the amplitude of the 'midBuffer' samples + precalcCorrReferenceStereo(); + + bestCorr = INT_MIN; + bestOffs = 0; + corrOffset = 0; + tempOffset = 0; + + // Scans for the best correlation value using four-pass hierarchical search. + // + // The look-up table 'scans' has hierarchical position adjusting steps. + // In first pass the routine searhes for the highest correlation with + // relatively coarse steps, then rescans the neighbourhood of the highest + // correlation with better resolution and so on. + for (scanCount = 0;scanCount < 4; scanCount ++) + { + j = 0; + while (scanOffsets[scanCount][j]) + { + tempOffset = corrOffset + scanOffsets[scanCount][j]; + if (tempOffset >= seekLength) break; + + // Calculates correlation value for the mixing position corresponding + // to 'tempOffset' + corr = calcCrossCorrStereo(refPos + 2 * tempOffset, pRefMidBuffer); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = tempOffset; + } + j ++; + } + corrOffset = bestOffs; + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + + +// Seeks for the optimal overlap-mixing position. The 'mono' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionMono(const SAMPLETYPE *refPos) +{ + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint tempOffset; + const SAMPLETYPE *compare; + + // Slopes the amplitude of the 'midBuffer' samples + precalcCorrReferenceMono(); + + bestCorr = INT_MIN; + bestOffs = 0; + + // Scans for the best correlation value by testing each possible position + // over the permitted range. + for (tempOffset = 0; tempOffset < seekLength; tempOffset ++) + { + compare = refPos + tempOffset; + + // Calculates correlation value for the mixing position corresponding + // to 'tempOffset' + corr = calcCrossCorrMono(pRefMidBuffer, compare); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = tempOffset; + } + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + +// Seeks for the optimal overlap-mixing position. The 'mono' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos) +{ + uint j; + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint scanCount, corrOffset, tempOffset; + + // Slopes the amplitude of the 'midBuffer' samples + precalcCorrReferenceMono(); + + bestCorr = INT_MIN; + bestOffs = 0; + corrOffset = 0; + tempOffset = 0; + + // Scans for the best correlation value using four-pass hierarchical search. + // + // The look-up table 'scans' has hierarchical position adjusting steps. + // In first pass the routine searhes for the highest correlation with + // relatively coarse steps, then rescans the neighbourhood of the highest + // correlation with better resolution and so on. + for (scanCount = 0;scanCount < 4; scanCount ++) + { + j = 0; + while (scanOffsets[scanCount][j]) + { + tempOffset = corrOffset + scanOffsets[scanCount][j]; + if (tempOffset >= seekLength) break; + + // Calculates correlation value for the mixing position corresponding + // to 'tempOffset' + corr = calcCrossCorrMono(refPos + tempOffset, pRefMidBuffer); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = tempOffset; + } + j ++; + } + corrOffset = bestOffs; + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + +/// clear cross correlation routine state if necessary +void TDStretch::clearCrossCorrState() +{ + // default implementation is empty. +} + + +// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower +// tempo, larger faster tempo. +void TDStretch::setTempo(float newTempo) +{ + uint intskip; + + tempo = newTempo; + + // Calculate ideal skip length (according to tempo value) + nominalSkip = tempo * (seekWindowLength - overlapLength); + skipFract = 0; + intskip = (int)(nominalSkip + 0.5f); + + // Calculate how many samples are needed in the 'inputBuffer' to + // process another batch of samples + sampleReq = max(intskip + overlapLength, seekWindowLength) + maxOffset; +} + + + +// Sets the number of channels, 1 = mono, 2 = stereo +void TDStretch::setChannels(uint numChannels) +{ + if (channels == numChannels) return; + assert(numChannels == 1 || numChannels == 2); + + channels = numChannels; + inputBuffer.setChannels(channels); + outputBuffer.setChannels(channels); +} + + +// nominal tempo, no need for processing, just pass the samples through +// to outputBuffer +void TDStretch::processNominalTempo() +{ + assert(tempo == 1.0f); + + if (bMidBufferDirty) + { + // If there are samples in pMidBuffer waiting for overlapping, + // do a single sliding overlapping with them in order to prevent a + // clicking distortion in the output sound + if (inputBuffer.numSamples() < overlapLength) + { + // wait until we've got overlapLength input samples + return; + } + // Mix the samples in the beginning of 'inputBuffer' with the + // samples in 'midBuffer' using sliding overlapping + overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0); + outputBuffer.putSamples(overlapLength); + inputBuffer.receiveSamples(overlapLength); + clearMidBuffer(); + // now we've caught the nominal sample flow and may switch to + // bypass mode + } + + // Simply bypass samples from input to output + outputBuffer.moveSamples(inputBuffer); +} + + +// Processes as many processing frames of the samples 'inputBuffer', store +// the result into 'outputBuffer' +void TDStretch::processSamples() +{ + uint ovlSkip, offset; + int temp; + + /* Removed this small optimization - can introduce a click to sound when tempo setting + crosses the nominal value + if (tempo == 1.0f) + { + // tempo not changed from the original, so bypass the processing + processNominalTempo(); + return; + } + */ + + if (bMidBufferDirty == FALSE) + { + // if midBuffer is empty, move the first samples of the input stream + // into it + if (inputBuffer.numSamples() < overlapLength) + { + // wait until we've got overlapLength samples + return; + } + memcpy(pMidBuffer, inputBuffer.ptrBegin(), channels * overlapLength * sizeof(SAMPLETYPE)); + inputBuffer.receiveSamples(overlapLength); + bMidBufferDirty = TRUE; + } + + // Process samples as long as there are enough samples in 'inputBuffer' + // to form a processing frame. + while (inputBuffer.numSamples() >= sampleReq) + { + // If tempo differs from the normal ('SCALE'), scan for the best overlapping + // position + offset = seekBestOverlapPosition(inputBuffer.ptrBegin()); + + // Mix the samples in the 'inputBuffer' at position of 'offset' with the + // samples in 'midBuffer' using sliding overlapping + // ... first partially overlap with the end of the previous sequence + // (that's in 'midBuffer') + overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), offset); + outputBuffer.putSamples(overlapLength); + + // ... then copy sequence samples from 'inputBuffer' to output + temp = (seekWindowLength - 2 * overlapLength);// & 0xfffffffe; + if (temp > 0) + { + outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * (offset + overlapLength), temp); + } + + // Copies the end of the current sequence from 'inputBuffer' to + // 'midBuffer' for being mixed with the beginning of the next + // processing sequence and so on + assert(offset + seekWindowLength <= inputBuffer.numSamples()); + memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + seekWindowLength - overlapLength), + channels * sizeof(SAMPLETYPE) * overlapLength); + bMidBufferDirty = TRUE; + + // Remove the processed samples from the input buffer. Update + // the difference between integer & nominal skip step to 'skipFract' + // in order to prevent the error from accumulating over time. + skipFract += nominalSkip; // real skip size + ovlSkip = (int)skipFract; // rounded to integer skip + skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip + inputBuffer.receiveSamples(ovlSkip); + } +} + + +// Adds 'numsamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void TDStretch::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + // Add the samples into the input buffer + inputBuffer.putSamples(samples, numSamples); + // Process the samples in input buffer + processSamples(); +} + + + +/// Set new overlap length parameter & reallocate RefMidBuffer if necessary. +void TDStretch::acceptNewOverlapLength(uint newOverlapLength) +{ + uint prevOvl; + + prevOvl = overlapLength; + overlapLength = newOverlapLength; + + if (overlapLength > prevOvl) + { + delete[] pMidBuffer; + delete[] pRefMidBufferUnaligned; + + pMidBuffer = new SAMPLETYPE[overlapLength * 2]; + bMidBufferDirty = TRUE; + clearMidBuffer(); + + pRefMidBufferUnaligned = new SAMPLETYPE[2 * overlapLength + 16 / sizeof(SAMPLETYPE)]; + // ensure that 'pRefMidBuffer' is aligned to 16 byte boundary for efficiency + pRefMidBuffer = (SAMPLETYPE *)((((ulongptr)pRefMidBufferUnaligned) + 15) & -16); + } +} + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX/SSE/etc-capable CPU available or not. +void * TDStretch::operator new(size_t s) +{ + // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! + assert(FALSE); + return NULL; +} + + +TDStretch * TDStretch::newInstance() +{ + uint uExtensions = 0; + +#if !defined(_MSC_VER) || !defined(__x86_64__) + uExtensions = detectCPUextensions(); +#endif + + // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU + +#ifdef ALLOW_MMX + // MMX routines available only with integer sample types + if (uExtensions & SUPPORT_MMX) + { + return ::new TDStretchMMX; + } + else +#endif // ALLOW_MMX + + +#ifdef ALLOW_SSE + if (uExtensions & SUPPORT_SSE) + { + // SSE support + return ::new TDStretchSSE; + } + else +#endif // ALLOW_SSE + + +#ifdef ALLOW_3DNOW + if (uExtensions & SUPPORT_3DNOW) + { + // 3DNow! support + return ::new TDStretch3DNow; + } + else +#endif // ALLOW_3DNOW + + { + // ISA optimizations not supported, use plain C version + return ::new TDStretch; + } +} + + +////////////////////////////////////////////////////////////////////////////// +// +// Integer arithmetics specific algorithm implementations. +// +////////////////////////////////////////////////////////////////////////////// + +#ifdef INTEGER_SAMPLES + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceStereo() +{ + int i, cnt2; + int temp, temp2; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = i * (overlapLength - i); + cnt2 = i * 2; + + temp2 = (pMidBuffer[cnt2] * temp) / slopingDivider; + pRefMidBuffer[cnt2] = (short)(temp2); + temp2 = (pMidBuffer[cnt2 + 1] * temp) / slopingDivider; + pRefMidBuffer[cnt2 + 1] = (short)(temp2); + } +} + + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceMono() +{ + int i; + long temp; + long temp2; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = i * (overlapLength - i); + temp2 = (pMidBuffer[i] * temp) / slopingDivider; + pRefMidBuffer[i] = (short)temp2; + } +} + + +// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo' +// version of the routine. +void TDStretch::overlapStereo(short *output, const short *input) const +{ + int i; + short temp; + uint cnt2; + + for (i = 0; i < (int)overlapLength ; i ++) + { + temp = (short)(overlapLength - i); + cnt2 = 2 * i; + output[cnt2] = (input[cnt2] * i + pMidBuffer[cnt2] * temp ) / overlapLength; + output[cnt2 + 1] = (input[cnt2 + 1] * i + pMidBuffer[cnt2 + 1] * temp ) / overlapLength; + } +} + + +/// Calculates overlap period length in samples. +/// Integer version rounds overlap length to closest power of 2 +/// for a divide scaling operation. +void TDStretch::calculateOverlapLength(uint overlapMs) +{ + uint newOvl; + + overlapDividerBits = _getClosest2Power((sampleRate * overlapMs) / 1000.0); + if (overlapDividerBits > 9) overlapDividerBits = 9; + if (overlapDividerBits < 4) overlapDividerBits = 4; + newOvl = 1<> overlapDividerBits; + } + + return corr; +} + + +long TDStretch::calcCrossCorrStereo(const short *mixingPos, const short *compare) const +{ + long corr; + uint i; + + corr = 0; + for (i = 2; i < 2 * overlapLength; i += 2) + { + corr += (mixingPos[i] * compare[i] + + mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBits; + } + + return corr; +} + +#endif // INTEGER_SAMPLES + +////////////////////////////////////////////////////////////////////////////// +// +// Floating point arithmetics specific algorithm implementations. +// + +#ifdef FLOAT_SAMPLES + + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceStereo() +{ + int i, cnt2; + float temp; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = (float)i * (float)(overlapLength - i); + cnt2 = i * 2; + pRefMidBuffer[cnt2] = (float)(pMidBuffer[cnt2] * temp); + pRefMidBuffer[cnt2 + 1] = (float)(pMidBuffer[cnt2 + 1] * temp); + } +} + + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceMono() +{ + int i; + float temp; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = (float)i * (float)(overlapLength - i); + pRefMidBuffer[i] = (float)(pMidBuffer[i] * temp); + } +} + + +// SSE-optimized version of the function overlapStereo +void TDStretch::overlapStereo(float *output, const float *input) const +{ + int i; + uint cnt2; + float fTemp; + float fScale; + float fi; + + fScale = 1.0f / (float)overlapLength; + + for (i = 0; i < (int)overlapLength ; i ++) + { + fTemp = (float)(overlapLength - i) * fScale; + fi = (float)i * fScale; + cnt2 = 2 * i; + output[cnt2 + 0] = input[cnt2 + 0] * fi + pMidBuffer[cnt2 + 0] * fTemp; + output[cnt2 + 1] = input[cnt2 + 1] * fi + pMidBuffer[cnt2 + 1] * fTemp; + } +} + + +/// Calculates overlap period length in samples. +void TDStretch::calculateOverlapLength(uint overlapMs) +{ + uint newOvl; + + newOvl = (sampleRate * overlapMs) / 1000; + if (newOvl < 16) newOvl = 16; + + // must be divisible by 8 + newOvl -= newOvl % 8; + + acceptNewOverlapLength(newOvl); +} + + + +double TDStretch::calcCrossCorrMono(const float *mixingPos, const float *compare) const +{ + double corr; + uint i; + + corr = 0; + for (i = 1; i < overlapLength; i ++) + { + corr += mixingPos[i] * compare[i]; + } + + return corr; +} + + +double TDStretch::calcCrossCorrStereo(const float *mixingPos, const float *compare) const +{ + double corr; + uint i; + + corr = 0; + for (i = 2; i < 2 * overlapLength; i += 2) + { + corr += mixingPos[i] * compare[i] + + mixingPos[i + 1] * compare[i + 1]; + } + + return corr; +} + +#endif // FLOAT_SAMPLES diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/TDStretch.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/TDStretch.h index a05a7072fc..133c227d49 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/TDStretch.h +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/TDStretch.h @@ -1,236 +1,236 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo -/// while maintaining the original pitch by using a time domain WSOLA-like method -/// with several performance-increasing tweaks. -/// -/// Note : MMX optimized functions reside in a separate, platform-specific file, -/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.16 $ -// -// $Id: TDStretch.h,v 1.16 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef TDStretch_H -#define TDStretch_H - -#include "STTypes.h" -#include "RateTransposer.h" -#include "FIFOSamplePipe.h" - -namespace soundtouch -{ - -// Default values for sound processing parameters: - -/// Default length of a single processing sequence, in milliseconds. This determines to how -/// long sequences the original sound is chopped in the time-stretch algorithm. -/// -/// The larger this value is, the lesser sequences are used in processing. In principle -/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo -/// and vice versa. -/// -/// Increasing this value reduces computational burden & vice versa. -#define DEFAULT_SEQUENCE_MS 61 - -#define DEFAULT_SEEKWINDOW_MS 18 - -#define DEFAULT_OVERLAP_MS 7 - - -/// Class that does the time-stretch (tempo change) effect for the processed -/// sound. -class TDStretch : public FIFOProcessor -{ -protected: - uint channels; - uint sampleReq; - float tempo; - - SAMPLETYPE *pMidBuffer; - SAMPLETYPE *pRefMidBuffer; - SAMPLETYPE *pRefMidBufferUnaligned; - uint overlapLength; - uint overlapDividerBits; - uint slopingDivider; - uint seekLength; - uint seekWindowLength; - uint maxOffset; - float nominalSkip; - float skipFract; - FIFOSampleBuffer outputBuffer; - FIFOSampleBuffer inputBuffer; - BOOL bQuickseek; - BOOL bMidBufferDirty; - - uint sampleRate; - uint sequenceMs; - uint seekWindowMs; - uint overlapMs; - - void acceptNewOverlapLength(uint newOverlapLength); - - virtual void clearCrossCorrState(); - void calculateOverlapLength(uint overlapMs); - - virtual LONG_SAMPLETYPE calcCrossCorrStereo(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; - virtual LONG_SAMPLETYPE calcCrossCorrMono(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; - - virtual uint seekBestOverlapPositionStereo(const SAMPLETYPE *refPos); - virtual uint seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos); - virtual uint seekBestOverlapPositionMono(const SAMPLETYPE *refPos); - virtual uint seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos); - uint seekBestOverlapPosition(const SAMPLETYPE *refPos); - - virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const; - virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const; - - void clearMidBuffer(); - void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const; - - void precalcCorrReferenceMono(); - void precalcCorrReferenceStereo(); - - void processNominalTempo(); - - /// Changes the tempo of the given sound samples. - /// Returns amount of samples returned in the "output" buffer. - /// The maximum amount of samples that can be returned at a time is set by - /// the 'set_returnBuffer_size' function. - void processSamples(); - -public: - TDStretch(); - virtual ~TDStretch(); - - /// Operator 'new' is overloaded so that it automatically creates a suitable instance - /// depending on if we've a MMX/SSE/etc-capable CPU available or not. - void *operator new(size_t s); - - /// Use this function instead of "new" operator to create a new instance of this class. - /// This function automatically chooses a correct feature set depending on if the CPU - /// supports MMX/SSE/etc extensions. - static TDStretch *newInstance(); - - /// Returns the output buffer object - FIFOSamplePipe *getOutput() { return &outputBuffer; }; - - /// Returns the input buffer object - FIFOSamplePipe *getInput() { return &inputBuffer; }; - - /// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower - /// tempo, larger faster tempo. - void setTempo(float newTempo); - - /// Returns nonzero if there aren't any samples available for outputting. - virtual void clear(); - - /// Clears the input buffer - void clearInput(); - - /// Sets the number of channels, 1 = mono, 2 = stereo - void setChannels(uint numChannels); - - /// Enables/disables the quick position seeking algorithm. Zero to disable, - /// nonzero to enable - void enableQuickSeek(BOOL enable); - - /// Returns nonzero if the quick seeking algorithm is enabled. - BOOL isQuickSeekEnabled() const; - - /// Sets routine control parameters. These control are certain time constants - /// defining how the sound is stretched to the desired duration. - // - /// 'sampleRate' = sample rate of the sound - /// 'sequenceMS' = one processing sequence length in milliseconds - /// 'seekwindowMS' = seeking window length for scanning the best overlapping - /// position - /// 'overlapMS' = overlapping length - void setParameters(uint sampleRate, ///< Samplerate of sound being processed (Hz) - uint sequenceMS = DEFAULT_SEQUENCE_MS, ///< Single processing sequence length (ms) - uint seekwindowMS = DEFAULT_SEEKWINDOW_MS, ///< Offset seeking window length (ms) - uint overlapMS = DEFAULT_OVERLAP_MS ///< Sequence overlapping length (ms) - ); - - /// Get routine control parameters, see setParameters() function. - /// Any of the parameters to this function can be NULL, in such case corresponding parameter - /// value isn't returned. - void getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs); - - /// Adds 'numsamples' pcs of samples from the 'samples' memory position into - /// the input of the object. - virtual void putSamples( - const SAMPLETYPE *samples, ///< Input sample data - uint numSamples ///< Number of samples in 'samples' so that one sample - ///< contains both channels if stereo - ); -}; - - - -// Implementation-specific class declarations: - -//#ifdef ALLOW_MMX -// /// Class that implements MMX optimized routines for 16bit integer samples type. -// class TDStretchMMX : public TDStretch -// { -// protected: -// long calcCrossCorrStereo(const short *mixingPos, const short *compare) const; -// virtual void overlapStereo(short *output, const short *input) const; -// virtual void clearCrossCorrState(); -// }; -//#endif /// ALLOW_MMX -// -// -//#ifdef ALLOW_3DNOW -// /// Class that implements 3DNow! optimized routines for floating point samples type. -// class TDStretch3DNow : public TDStretch -// { -// protected: -// double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; -// }; -//#endif /// ALLOW_3DNOW - - -#ifdef ALLOW_SSE - /// Class that implements SSE optimized routines for floating point samples type. - class TDStretchSSE : public TDStretch - { - protected: - double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; - }; - -#endif /// ALLOW_SSE - -} -#endif /// TDStretch_H +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like method +/// with several performance-increasing tweaks. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.16 $ +// +// $Id: TDStretch.h,v 1.16 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef TDStretch_H +#define TDStretch_H + +#include "STTypes.h" +#include "RateTransposer.h" +#include "FIFOSamplePipe.h" + +namespace soundtouch +{ + +// Default values for sound processing parameters: + +/// Default length of a single processing sequence, in milliseconds. This determines to how +/// long sequences the original sound is chopped in the time-stretch algorithm. +/// +/// The larger this value is, the lesser sequences are used in processing. In principle +/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo +/// and vice versa. +/// +/// Increasing this value reduces computational burden & vice versa. +#define DEFAULT_SEQUENCE_MS 61 + +#define DEFAULT_SEEKWINDOW_MS 18 + +#define DEFAULT_OVERLAP_MS 7 + + +/// Class that does the time-stretch (tempo change) effect for the processed +/// sound. +class TDStretch : public FIFOProcessor +{ +protected: + uint channels; + uint sampleReq; + float tempo; + + SAMPLETYPE *pMidBuffer; + SAMPLETYPE *pRefMidBuffer; + SAMPLETYPE *pRefMidBufferUnaligned; + uint overlapLength; + uint overlapDividerBits; + uint slopingDivider; + uint seekLength; + uint seekWindowLength; + uint maxOffset; + float nominalSkip; + float skipFract; + FIFOSampleBuffer outputBuffer; + FIFOSampleBuffer inputBuffer; + BOOL bQuickseek; + BOOL bMidBufferDirty; + + uint sampleRate; + uint sequenceMs; + uint seekWindowMs; + uint overlapMs; + + void acceptNewOverlapLength(uint newOverlapLength); + + virtual void clearCrossCorrState(); + void calculateOverlapLength(uint overlapMs); + + virtual LONG_SAMPLETYPE calcCrossCorrStereo(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; + virtual LONG_SAMPLETYPE calcCrossCorrMono(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; + + virtual uint seekBestOverlapPositionStereo(const SAMPLETYPE *refPos); + virtual uint seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos); + virtual uint seekBestOverlapPositionMono(const SAMPLETYPE *refPos); + virtual uint seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos); + uint seekBestOverlapPosition(const SAMPLETYPE *refPos); + + virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const; + virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const; + + void clearMidBuffer(); + void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const; + + void precalcCorrReferenceMono(); + void precalcCorrReferenceStereo(); + + void processNominalTempo(); + + /// Changes the tempo of the given sound samples. + /// Returns amount of samples returned in the "output" buffer. + /// The maximum amount of samples that can be returned at a time is set by + /// the 'set_returnBuffer_size' function. + void processSamples(); + +public: + TDStretch(); + virtual ~TDStretch(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we've a MMX/SSE/etc-capable CPU available or not. + void *operator new(size_t s); + + /// Use this function instead of "new" operator to create a new instance of this class. + /// This function automatically chooses a correct feature set depending on if the CPU + /// supports MMX/SSE/etc extensions. + static TDStretch *newInstance(); + + /// Returns the output buffer object + FIFOSamplePipe *getOutput() { return &outputBuffer; }; + + /// Returns the input buffer object + FIFOSamplePipe *getInput() { return &inputBuffer; }; + + /// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower + /// tempo, larger faster tempo. + void setTempo(float newTempo); + + /// Returns nonzero if there aren't any samples available for outputting. + virtual void clear(); + + /// Clears the input buffer + void clearInput(); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint numChannels); + + /// Enables/disables the quick position seeking algorithm. Zero to disable, + /// nonzero to enable + void enableQuickSeek(BOOL enable); + + /// Returns nonzero if the quick seeking algorithm is enabled. + BOOL isQuickSeekEnabled() const; + + /// Sets routine control parameters. These control are certain time constants + /// defining how the sound is stretched to the desired duration. + // + /// 'sampleRate' = sample rate of the sound + /// 'sequenceMS' = one processing sequence length in milliseconds + /// 'seekwindowMS' = seeking window length for scanning the best overlapping + /// position + /// 'overlapMS' = overlapping length + void setParameters(uint sampleRate, ///< Samplerate of sound being processed (Hz) + uint sequenceMS = DEFAULT_SEQUENCE_MS, ///< Single processing sequence length (ms) + uint seekwindowMS = DEFAULT_SEEKWINDOW_MS, ///< Offset seeking window length (ms) + uint overlapMS = DEFAULT_OVERLAP_MS ///< Sequence overlapping length (ms) + ); + + /// Get routine control parameters, see setParameters() function. + /// Any of the parameters to this function can be NULL, in such case corresponding parameter + /// value isn't returned. + void getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs); + + /// Adds 'numsamples' pcs of samples from the 'samples' memory position into + /// the input of the object. + virtual void putSamples( + const SAMPLETYPE *samples, ///< Input sample data + uint numSamples ///< Number of samples in 'samples' so that one sample + ///< contains both channels if stereo + ); +}; + + + +// Implementation-specific class declarations: + +//#ifdef ALLOW_MMX +// /// Class that implements MMX optimized routines for 16bit integer samples type. +// class TDStretchMMX : public TDStretch +// { +// protected: +// long calcCrossCorrStereo(const short *mixingPos, const short *compare) const; +// virtual void overlapStereo(short *output, const short *input) const; +// virtual void clearCrossCorrState(); +// }; +//#endif /// ALLOW_MMX +// +// +//#ifdef ALLOW_3DNOW +// /// Class that implements 3DNow! optimized routines for floating point samples type. +// class TDStretch3DNow : public TDStretch +// { +// protected: +// double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; +// }; +//#endif /// ALLOW_3DNOW + + +#ifdef ALLOW_SSE + /// Class that implements SSE optimized routines for floating point samples type. + class TDStretchSSE : public TDStretch + { + protected: + double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; + }; + +#endif /// ALLOW_SSE + +} +#endif /// TDStretch_H diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/WavFile.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/WavFile.cpp index 77db8cc431..15a679871c 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/WavFile.cpp +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/WavFile.cpp @@ -1,714 +1,714 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Classes for easy reading & writing of WAV sound files. -/// -/// For big-endian CPU, define _BIG_ENDIAN_ during compile-time to correctly -/// parse the WAV files with such processors. -/// -/// Admittingly, more complete WAV reader routines may exist in public domain, -/// but the reason for 'yet another' one is that those generic WAV reader -/// libraries are exhaustingly large and cumbersome! Wanted to have something -/// simpler here, i.e. something that's not already larger than rest of the -/// SoundTouch/SoundStretch program... -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.15 $ -// -// $Id: WavFile.cpp,v 1.15 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include - -#include -#include - -#include "WavFile.h" - -using namespace std; - -const static char riffStr[] = "RIFF"; -const static char waveStr[] = "WAVE"; -const static char fmtStr[] = "fmt "; -const static char dataStr[] = "data"; - - -////////////////////////////////////////////////////////////////////////////// -// -// Helper functions for swapping byte order to correctly read/write WAV files -// with big-endian CPU's: Define compile-time definition _BIG_ENDIAN_ to -// turn-on the conversion if it appears necessary. -// -// For example, Intel x86 is little-endian and doesn't require conversion, -// while PowerPC of Mac's and many other RISC cpu's are big-endian. - -#ifdef BYTE_ORDER - // In gcc compiler detect the byte order automatically - #if BYTE_ORDER == BIG_ENDIAN - // big-endian platform. - #define _BIG_ENDIAN_ - #endif -#endif - -#ifdef _BIG_ENDIAN_ - // big-endian CPU, swap bytes in 16 & 32 bit words - - // helper-function to swap byte-order of 32bit integer - static inline void _swap32(unsigned int &dwData) - { - dwData = ((dwData >> 24) & 0x000000FF) | - ((dwData >> 8) & 0x0000FF00) | - ((dwData << 8) & 0x00FF0000) | - ((dwData << 24) & 0xFF000000); - } - - // helper-function to swap byte-order of 16bit integer - static inline void _swap16(unsigned short &wData) - { - wData = ((wData >> 8) & 0x00FF) | - ((wData << 8) & 0xFF00); - } - - // helper-function to swap byte-order of buffer of 16bit integers - static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumWords) - { - unsigned long i; - - for (i = 0; i < dwNumWords; i ++) - { - _swap16(pData[i]); - } - } - -#else // BIG_ENDIAN - // little-endian CPU, WAV file is ok as such - - // dummy helper-function - static inline void _swap32(unsigned int &dwData) - { - // do nothing - } - - // dummy helper-function - static inline void _swap16(unsigned short &wData) - { - // do nothing - } - - // dummy helper-function - static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumBytes) - { - // do nothing - } - -#endif // BIG_ENDIAN - - -////////////////////////////////////////////////////////////////////////////// -// -// Class WavInFile -// - -WavInFile::WavInFile(const char *fileName) -{ - int hdrsOk; - - // Try to open the file for reading - fptr = fopen(fileName, "rb"); - if (fptr == NULL) - { - // didn't succeed - string msg = "Error : Unable to open file \""; - msg += fileName; - msg += "\" for reading."; - throw runtime_error(msg); - } - - // Read the file headers - hdrsOk = readWavHeaders(); - if (hdrsOk != 0) - { - // Something didn't match in the wav file headers - string msg = "File \""; - msg += fileName; - msg += "\" is corrupt or not a WAV file"; - throw runtime_error(msg); - } - - if (header.format.fixed != 1) - { - string msg = "File \""; - msg += fileName; - msg += "\" uses unsupported encoding."; - throw runtime_error(msg); - } - - dataRead = 0; -} - - - -WavInFile::~WavInFile() -{ - close(); -} - - - -void WavInFile::rewind() -{ - int hdrsOk; - - fseek(fptr, 0, SEEK_SET); - hdrsOk = readWavHeaders(); - assert(hdrsOk == 0); - dataRead = 0; -} - - -int WavInFile::checkCharTags() -{ - // header.format.fmt should equal to 'fmt ' - if (memcmp(fmtStr, header.format.fmt, 4) != 0) return -1; - // header.data.data_field should equal to 'data' - if (memcmp(dataStr, header.data.data_field, 4) != 0) return -1; - - return 0; -} - - -int WavInFile::read(char *buffer, int maxElems) -{ - int numBytes; - uint afterDataRead; - - // ensure it's 8 bit format - if (header.format.bits_per_sample != 8) - { - throw runtime_error("Error: WavInFile::read(char*, int) works only with 8bit samples."); - } - assert(sizeof(char) == 1); - - numBytes = maxElems; - afterDataRead = dataRead + numBytes; - if (afterDataRead > header.data.data_len) - { - // Don't read more samples than are marked available in header - numBytes = header.data.data_len - dataRead; - assert(numBytes >= 0); - } - - numBytes = fread(buffer, 1, numBytes, fptr); - dataRead += numBytes; - - return numBytes; -} - - -int WavInFile::read(short *buffer, int maxElems) -{ - unsigned int afterDataRead; - int numBytes; - int numElems; - - if (header.format.bits_per_sample == 8) - { - // 8 bit format - char *temp = new char[maxElems]; - int i; - - numElems = read(temp, maxElems); - // convert from 8 to 16 bit - for (i = 0; i < numElems; i ++) - { - buffer[i] = temp[i] << 8; - } - delete[] temp; - } - else - { - // 16 bit format - assert(header.format.bits_per_sample == 16); - assert(sizeof(short) == 2); - - numBytes = maxElems * 2; - afterDataRead = dataRead + numBytes; - if (afterDataRead > header.data.data_len) - { - // Don't read more samples than are marked available in header - numBytes = header.data.data_len - dataRead; - assert(numBytes >= 0); - } - - numBytes = fread(buffer, 1, numBytes, fptr); - dataRead += numBytes; - numElems = numBytes / 2; - - // 16bit samples, swap byte order if necessary - _swap16Buffer((unsigned short *)buffer, numElems); - } - - return numElems; -} - - - -int WavInFile::read(float *buffer, int maxElems) -{ - short *temp = new short[maxElems]; - int num; - int i; - double fscale; - - num = read(temp, maxElems); - - fscale = 1.0 / 32768.0; - // convert to floats, scale to range [-1..+1[ - for (i = 0; i < num; i ++) - { - buffer[i] = (float)(fscale * (double)temp[i]); - } - - delete[] temp; - - return num; -} - - -int WavInFile::eof() const -{ - // return true if all data has been read or file eof has reached - return (dataRead == header.data.data_len || feof(fptr)); -} - - -void WavInFile::close() -{ - fclose(fptr); - fptr = NULL; -} - - - -// test if character code is between a white space ' ' and little 'z' -static int isAlpha(char c) -{ - return (c >= ' ' && c <= 'z') ? 1 : 0; -} - - -// test if all characters are between a white space ' ' and little 'z' -static int isAlphaStr(char *str) -{ - int c; - - c = str[0]; - while (c) - { - if (isAlpha(c) == 0) return 0; - str ++; - c = str[0]; - } - - return 1; -} - - -int WavInFile::readRIFFBlock() -{ - fread(&(header.riff), sizeof(WavRiff), 1, fptr); - - // swap 32bit data byte order if necessary - _swap32((unsigned int &)header.riff.package_len); - - // header.riff.riff_char should equal to 'RIFF'); - if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1; - // header.riff.wave should equal to 'WAVE' - if (memcmp(waveStr, header.riff.wave, 4) != 0) return -1; - - return 0; -} - - - - -int WavInFile::readHeaderBlock() -{ - char label[5]; - string sLabel; - - // lead label string - fread(label, 1, 4, fptr); - label[4] = 0; - - if (isAlphaStr(label) == 0) return -1; // not a valid label - - // Decode blocks according to their label - if (strcmp(label, fmtStr) == 0) - { - int nLen, nDump; - - // 'fmt ' block - memcpy(header.format.fmt, fmtStr, 4); - - // read length of the format field - fread(&nLen, sizeof(int), 1, fptr); - // swap byte order if necessary - _swap32((unsigned int &)nLen); // int format_len; - header.format.format_len = nLen; - - // calculate how much length differs from expected - nDump = nLen - (sizeof(header.format) - 8); - - // if format_len is larger than expected, read only as much data as we've space for - if (nDump > 0) - { - nLen = sizeof(header.format) - 8; - } - - // read data - fread(&(header.format.fixed), nLen, 1, fptr); - - // swap byte order if necessary - _swap16((unsigned short &)header.format.fixed); // short int fixed; - _swap16((unsigned short &)header.format.channel_number); // short int channel_number; - _swap32((unsigned int &)header.format.sample_rate); // int sample_rate; - _swap32((unsigned int &)header.format.byte_rate); // int byte_rate; - _swap16((unsigned short &)header.format.byte_per_sample); // short int byte_per_sample; - _swap16((unsigned short &)header.format.bits_per_sample); // short int bits_per_sample; - - // if format_len is larger than expected, skip the extra data - if (nDump > 0) - { - fseek(fptr, nDump, SEEK_CUR); - } - - return 0; - } - else if (strcmp(label, dataStr) == 0) - { - // 'data' block - memcpy(header.data.data_field, dataStr, 4); - fread(&(header.data.data_len), sizeof(uint), 1, fptr); - - // swap byte order if necessary - _swap32((unsigned int &)header.data.data_len); - - return 1; - } - else - { - uint len, i; - uint temp; - // unknown block - - // read length - fread(&len, sizeof(len), 1, fptr); - // scan through the block - for (i = 0; i < len; i ++) - { - fread(&temp, 1, 1, fptr); - if (feof(fptr)) return -1; // unexpected eof - } - } - return 0; -} - - -int WavInFile::readWavHeaders() -{ - int res; - - memset(&header, 0, sizeof(header)); - - res = readRIFFBlock(); - if (res) return 1; - // read header blocks until data block is found - do - { - // read header blocks - res = readHeaderBlock(); - if (res < 0) return 1; // error in file structure - } while (res == 0); - // check that all required tags are legal - return checkCharTags(); -} - - -uint WavInFile::getNumChannels() const -{ - return header.format.channel_number; -} - - -uint WavInFile::getNumBits() const -{ - return header.format.bits_per_sample; -} - - -uint WavInFile::getBytesPerSample() const -{ - return getNumChannels() * getNumBits() / 8; -} - - -uint WavInFile::getSampleRate() const -{ - return header.format.sample_rate; -} - - - -uint WavInFile::getDataSizeInBytes() const -{ - return header.data.data_len; -} - - -uint WavInFile::getNumSamples() const -{ - return header.data.data_len / header.format.byte_per_sample; -} - - -uint WavInFile::getLengthMS() const -{ - uint numSamples; - uint sampleRate; - - numSamples = getNumSamples(); - sampleRate = getSampleRate(); - - assert(numSamples < UINT_MAX / 1000); - return (1000 * numSamples / sampleRate); -} - - -////////////////////////////////////////////////////////////////////////////// -// -// Class WavOutFile -// - -WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels) -{ - bytesWritten = 0; - fptr = fopen(fileName, "wb"); - if (fptr == NULL) - { - string msg = "Error : Unable to open file \""; - msg += fileName; - msg += "\" for writing."; - //pmsg = msg.c_str; - throw runtime_error(msg); - } - - fillInHeader(sampleRate, bits, channels); - writeHeader(); -} - - - -WavOutFile::~WavOutFile() -{ - close(); -} - - - -void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels) -{ - // fill in the 'riff' part.. - - // copy string 'RIFF' to riff_char - memcpy(&(header.riff.riff_char), riffStr, 4); - // package_len unknown so far - header.riff.package_len = 0; - // copy string 'WAVE' to wave - memcpy(&(header.riff.wave), waveStr, 4); - - - // fill in the 'format' part.. - - // copy string 'fmt ' to fmt - memcpy(&(header.format.fmt), fmtStr, 4); - - header.format.format_len = 0x10; - header.format.fixed = 1; - header.format.channel_number = (short)channels; - header.format.sample_rate = sampleRate; - header.format.bits_per_sample = (short)bits; - header.format.byte_per_sample = (short)(bits * channels / 8); - header.format.byte_rate = header.format.byte_per_sample * sampleRate; - header.format.sample_rate = sampleRate; - - // fill in the 'data' part.. - - // copy string 'data' to data_field - memcpy(&(header.data.data_field), dataStr, 4); - // data_len unknown so far - header.data.data_len = 0; -} - - -void WavOutFile::finishHeader() -{ - // supplement the file length into the header structure - header.riff.package_len = bytesWritten + 36; - header.data.data_len = bytesWritten; - - writeHeader(); -} - - - -void WavOutFile::writeHeader() -{ - WavHeader hdrTemp; - - // swap byte order if necessary - hdrTemp = header; - _swap32((unsigned int &)hdrTemp.riff.package_len); - _swap32((unsigned int &)hdrTemp.format.format_len); - _swap16((unsigned short &)hdrTemp.format.fixed); - _swap16((unsigned short &)hdrTemp.format.channel_number); - _swap32((unsigned int &)hdrTemp.format.sample_rate); - _swap32((unsigned int &)hdrTemp.format.byte_rate); - _swap16((unsigned short &)hdrTemp.format.byte_per_sample); - _swap16((unsigned short &)hdrTemp.format.bits_per_sample); - _swap32((unsigned int &)hdrTemp.data.data_len); - - // write the supplemented header in the beginning of the file - fseek(fptr, 0, SEEK_SET); - fwrite(&hdrTemp, sizeof(hdrTemp), 1, fptr); - // jump back to the end of the file - fseek(fptr, 0, SEEK_END); -} - - - -void WavOutFile::close() -{ - finishHeader(); - fclose(fptr); - fptr = NULL; -} - - -void WavOutFile::write(const char *buffer, int numElems) -{ - int res; - - if (header.format.bits_per_sample != 8) - { - throw runtime_error("Error: WavOutFile::write(const char*, int) accepts only 8bit samples."); - } - assert(sizeof(char) == 1); - - res = fwrite(buffer, 1, numElems, fptr); - if (res != numElems) - { - throw runtime_error("Error while writing to a wav file."); - } - - bytesWritten += numElems; -} - - -void WavOutFile::write(const short *buffer, int numElems) -{ - int res; - - // 16 bit samples - if (numElems < 1) return; // nothing to do - - if (header.format.bits_per_sample == 8) - { - int i; - char *temp = new char[numElems]; - // convert from 16bit format to 8bit format - for (i = 0; i < numElems; i ++) - { - temp[i] = buffer[i] >> 8; - } - // write in 8bit format - write(temp, numElems); - delete[] temp; - } - else - { - // 16bit format - unsigned short *pTemp = new unsigned short[numElems]; - - assert(header.format.bits_per_sample == 16); - - // allocate temp buffer to swap byte order if necessary - memcpy(pTemp, buffer, numElems * 2); - _swap16Buffer(pTemp, numElems); - - res = fwrite(pTemp, 2, numElems, fptr); - - delete[] pTemp; - - if (res != numElems) - { - throw runtime_error("Error while writing to a wav file."); - } - bytesWritten += 2 * numElems; - } -} - - -void WavOutFile::write(const float *buffer, int numElems) -{ - int i; - short *temp = new short[numElems]; - int iTemp; - - // convert to 16 bit integer - for (i = 0; i < numElems; i ++) - { - // convert to integer - iTemp = (int)(32768.0f * buffer[i]); - - // saturate - if (iTemp < -32768) iTemp = -32768; - if (iTemp > 32767) iTemp = 32767; - temp[i] = (short)iTemp; - } - - write(temp, numElems); - - delete[] temp; -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// Classes for easy reading & writing of WAV sound files. +/// +/// For big-endian CPU, define _BIG_ENDIAN_ during compile-time to correctly +/// parse the WAV files with such processors. +/// +/// Admittingly, more complete WAV reader routines may exist in public domain, +/// but the reason for 'yet another' one is that those generic WAV reader +/// libraries are exhaustingly large and cumbersome! Wanted to have something +/// simpler here, i.e. something that's not already larger than rest of the +/// SoundTouch/SoundStretch program... +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.15 $ +// +// $Id: WavFile.cpp,v 1.15 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include +#include + +#include "WavFile.h" + +using namespace std; + +const static char riffStr[] = "RIFF"; +const static char waveStr[] = "WAVE"; +const static char fmtStr[] = "fmt "; +const static char dataStr[] = "data"; + + +////////////////////////////////////////////////////////////////////////////// +// +// Helper functions for swapping byte order to correctly read/write WAV files +// with big-endian CPU's: Define compile-time definition _BIG_ENDIAN_ to +// turn-on the conversion if it appears necessary. +// +// For example, Intel x86 is little-endian and doesn't require conversion, +// while PowerPC of Mac's and many other RISC cpu's are big-endian. + +#ifdef BYTE_ORDER + // In gcc compiler detect the byte order automatically + #if BYTE_ORDER == BIG_ENDIAN + // big-endian platform. + #define _BIG_ENDIAN_ + #endif +#endif + +#ifdef _BIG_ENDIAN_ + // big-endian CPU, swap bytes in 16 & 32 bit words + + // helper-function to swap byte-order of 32bit integer + static inline void _swap32(unsigned int &dwData) + { + dwData = ((dwData >> 24) & 0x000000FF) | + ((dwData >> 8) & 0x0000FF00) | + ((dwData << 8) & 0x00FF0000) | + ((dwData << 24) & 0xFF000000); + } + + // helper-function to swap byte-order of 16bit integer + static inline void _swap16(unsigned short &wData) + { + wData = ((wData >> 8) & 0x00FF) | + ((wData << 8) & 0xFF00); + } + + // helper-function to swap byte-order of buffer of 16bit integers + static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumWords) + { + unsigned long i; + + for (i = 0; i < dwNumWords; i ++) + { + _swap16(pData[i]); + } + } + +#else // BIG_ENDIAN + // little-endian CPU, WAV file is ok as such + + // dummy helper-function + static inline void _swap32(unsigned int &dwData) + { + // do nothing + } + + // dummy helper-function + static inline void _swap16(unsigned short &wData) + { + // do nothing + } + + // dummy helper-function + static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumBytes) + { + // do nothing + } + +#endif // BIG_ENDIAN + + +////////////////////////////////////////////////////////////////////////////// +// +// Class WavInFile +// + +WavInFile::WavInFile(const char *fileName) +{ + int hdrsOk; + + // Try to open the file for reading + fptr = fopen(fileName, "rb"); + if (fptr == NULL) + { + // didn't succeed + string msg = "Error : Unable to open file \""; + msg += fileName; + msg += "\" for reading."; + throw runtime_error(msg); + } + + // Read the file headers + hdrsOk = readWavHeaders(); + if (hdrsOk != 0) + { + // Something didn't match in the wav file headers + string msg = "File \""; + msg += fileName; + msg += "\" is corrupt or not a WAV file"; + throw runtime_error(msg); + } + + if (header.format.fixed != 1) + { + string msg = "File \""; + msg += fileName; + msg += "\" uses unsupported encoding."; + throw runtime_error(msg); + } + + dataRead = 0; +} + + + +WavInFile::~WavInFile() +{ + close(); +} + + + +void WavInFile::rewind() +{ + int hdrsOk; + + fseek(fptr, 0, SEEK_SET); + hdrsOk = readWavHeaders(); + assert(hdrsOk == 0); + dataRead = 0; +} + + +int WavInFile::checkCharTags() +{ + // header.format.fmt should equal to 'fmt ' + if (memcmp(fmtStr, header.format.fmt, 4) != 0) return -1; + // header.data.data_field should equal to 'data' + if (memcmp(dataStr, header.data.data_field, 4) != 0) return -1; + + return 0; +} + + +int WavInFile::read(char *buffer, int maxElems) +{ + int numBytes; + uint afterDataRead; + + // ensure it's 8 bit format + if (header.format.bits_per_sample != 8) + { + throw runtime_error("Error: WavInFile::read(char*, int) works only with 8bit samples."); + } + assert(sizeof(char) == 1); + + numBytes = maxElems; + afterDataRead = dataRead + numBytes; + if (afterDataRead > header.data.data_len) + { + // Don't read more samples than are marked available in header + numBytes = header.data.data_len - dataRead; + assert(numBytes >= 0); + } + + numBytes = fread(buffer, 1, numBytes, fptr); + dataRead += numBytes; + + return numBytes; +} + + +int WavInFile::read(short *buffer, int maxElems) +{ + unsigned int afterDataRead; + int numBytes; + int numElems; + + if (header.format.bits_per_sample == 8) + { + // 8 bit format + char *temp = new char[maxElems]; + int i; + + numElems = read(temp, maxElems); + // convert from 8 to 16 bit + for (i = 0; i < numElems; i ++) + { + buffer[i] = temp[i] << 8; + } + delete[] temp; + } + else + { + // 16 bit format + assert(header.format.bits_per_sample == 16); + assert(sizeof(short) == 2); + + numBytes = maxElems * 2; + afterDataRead = dataRead + numBytes; + if (afterDataRead > header.data.data_len) + { + // Don't read more samples than are marked available in header + numBytes = header.data.data_len - dataRead; + assert(numBytes >= 0); + } + + numBytes = fread(buffer, 1, numBytes, fptr); + dataRead += numBytes; + numElems = numBytes / 2; + + // 16bit samples, swap byte order if necessary + _swap16Buffer((unsigned short *)buffer, numElems); + } + + return numElems; +} + + + +int WavInFile::read(float *buffer, int maxElems) +{ + short *temp = new short[maxElems]; + int num; + int i; + double fscale; + + num = read(temp, maxElems); + + fscale = 1.0 / 32768.0; + // convert to floats, scale to range [-1..+1[ + for (i = 0; i < num; i ++) + { + buffer[i] = (float)(fscale * (double)temp[i]); + } + + delete[] temp; + + return num; +} + + +int WavInFile::eof() const +{ + // return true if all data has been read or file eof has reached + return (dataRead == header.data.data_len || feof(fptr)); +} + + +void WavInFile::close() +{ + fclose(fptr); + fptr = NULL; +} + + + +// test if character code is between a white space ' ' and little 'z' +static int isAlpha(char c) +{ + return (c >= ' ' && c <= 'z') ? 1 : 0; +} + + +// test if all characters are between a white space ' ' and little 'z' +static int isAlphaStr(char *str) +{ + int c; + + c = str[0]; + while (c) + { + if (isAlpha(c) == 0) return 0; + str ++; + c = str[0]; + } + + return 1; +} + + +int WavInFile::readRIFFBlock() +{ + fread(&(header.riff), sizeof(WavRiff), 1, fptr); + + // swap 32bit data byte order if necessary + _swap32((unsigned int &)header.riff.package_len); + + // header.riff.riff_char should equal to 'RIFF'); + if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1; + // header.riff.wave should equal to 'WAVE' + if (memcmp(waveStr, header.riff.wave, 4) != 0) return -1; + + return 0; +} + + + + +int WavInFile::readHeaderBlock() +{ + char label[5]; + string sLabel; + + // lead label string + fread(label, 1, 4, fptr); + label[4] = 0; + + if (isAlphaStr(label) == 0) return -1; // not a valid label + + // Decode blocks according to their label + if (strcmp(label, fmtStr) == 0) + { + int nLen, nDump; + + // 'fmt ' block + memcpy(header.format.fmt, fmtStr, 4); + + // read length of the format field + fread(&nLen, sizeof(int), 1, fptr); + // swap byte order if necessary + _swap32((unsigned int &)nLen); // int format_len; + header.format.format_len = nLen; + + // calculate how much length differs from expected + nDump = nLen - (sizeof(header.format) - 8); + + // if format_len is larger than expected, read only as much data as we've space for + if (nDump > 0) + { + nLen = sizeof(header.format) - 8; + } + + // read data + fread(&(header.format.fixed), nLen, 1, fptr); + + // swap byte order if necessary + _swap16((unsigned short &)header.format.fixed); // short int fixed; + _swap16((unsigned short &)header.format.channel_number); // short int channel_number; + _swap32((unsigned int &)header.format.sample_rate); // int sample_rate; + _swap32((unsigned int &)header.format.byte_rate); // int byte_rate; + _swap16((unsigned short &)header.format.byte_per_sample); // short int byte_per_sample; + _swap16((unsigned short &)header.format.bits_per_sample); // short int bits_per_sample; + + // if format_len is larger than expected, skip the extra data + if (nDump > 0) + { + fseek(fptr, nDump, SEEK_CUR); + } + + return 0; + } + else if (strcmp(label, dataStr) == 0) + { + // 'data' block + memcpy(header.data.data_field, dataStr, 4); + fread(&(header.data.data_len), sizeof(uint), 1, fptr); + + // swap byte order if necessary + _swap32((unsigned int &)header.data.data_len); + + return 1; + } + else + { + uint len, i; + uint temp; + // unknown block + + // read length + fread(&len, sizeof(len), 1, fptr); + // scan through the block + for (i = 0; i < len; i ++) + { + fread(&temp, 1, 1, fptr); + if (feof(fptr)) return -1; // unexpected eof + } + } + return 0; +} + + +int WavInFile::readWavHeaders() +{ + int res; + + memset(&header, 0, sizeof(header)); + + res = readRIFFBlock(); + if (res) return 1; + // read header blocks until data block is found + do + { + // read header blocks + res = readHeaderBlock(); + if (res < 0) return 1; // error in file structure + } while (res == 0); + // check that all required tags are legal + return checkCharTags(); +} + + +uint WavInFile::getNumChannels() const +{ + return header.format.channel_number; +} + + +uint WavInFile::getNumBits() const +{ + return header.format.bits_per_sample; +} + + +uint WavInFile::getBytesPerSample() const +{ + return getNumChannels() * getNumBits() / 8; +} + + +uint WavInFile::getSampleRate() const +{ + return header.format.sample_rate; +} + + + +uint WavInFile::getDataSizeInBytes() const +{ + return header.data.data_len; +} + + +uint WavInFile::getNumSamples() const +{ + return header.data.data_len / header.format.byte_per_sample; +} + + +uint WavInFile::getLengthMS() const +{ + uint numSamples; + uint sampleRate; + + numSamples = getNumSamples(); + sampleRate = getSampleRate(); + + assert(numSamples < UINT_MAX / 1000); + return (1000 * numSamples / sampleRate); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// Class WavOutFile +// + +WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels) +{ + bytesWritten = 0; + fptr = fopen(fileName, "wb"); + if (fptr == NULL) + { + string msg = "Error : Unable to open file \""; + msg += fileName; + msg += "\" for writing."; + //pmsg = msg.c_str; + throw runtime_error(msg); + } + + fillInHeader(sampleRate, bits, channels); + writeHeader(); +} + + + +WavOutFile::~WavOutFile() +{ + close(); +} + + + +void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels) +{ + // fill in the 'riff' part.. + + // copy string 'RIFF' to riff_char + memcpy(&(header.riff.riff_char), riffStr, 4); + // package_len unknown so far + header.riff.package_len = 0; + // copy string 'WAVE' to wave + memcpy(&(header.riff.wave), waveStr, 4); + + + // fill in the 'format' part.. + + // copy string 'fmt ' to fmt + memcpy(&(header.format.fmt), fmtStr, 4); + + header.format.format_len = 0x10; + header.format.fixed = 1; + header.format.channel_number = (short)channels; + header.format.sample_rate = sampleRate; + header.format.bits_per_sample = (short)bits; + header.format.byte_per_sample = (short)(bits * channels / 8); + header.format.byte_rate = header.format.byte_per_sample * sampleRate; + header.format.sample_rate = sampleRate; + + // fill in the 'data' part.. + + // copy string 'data' to data_field + memcpy(&(header.data.data_field), dataStr, 4); + // data_len unknown so far + header.data.data_len = 0; +} + + +void WavOutFile::finishHeader() +{ + // supplement the file length into the header structure + header.riff.package_len = bytesWritten + 36; + header.data.data_len = bytesWritten; + + writeHeader(); +} + + + +void WavOutFile::writeHeader() +{ + WavHeader hdrTemp; + + // swap byte order if necessary + hdrTemp = header; + _swap32((unsigned int &)hdrTemp.riff.package_len); + _swap32((unsigned int &)hdrTemp.format.format_len); + _swap16((unsigned short &)hdrTemp.format.fixed); + _swap16((unsigned short &)hdrTemp.format.channel_number); + _swap32((unsigned int &)hdrTemp.format.sample_rate); + _swap32((unsigned int &)hdrTemp.format.byte_rate); + _swap16((unsigned short &)hdrTemp.format.byte_per_sample); + _swap16((unsigned short &)hdrTemp.format.bits_per_sample); + _swap32((unsigned int &)hdrTemp.data.data_len); + + // write the supplemented header in the beginning of the file + fseek(fptr, 0, SEEK_SET); + fwrite(&hdrTemp, sizeof(hdrTemp), 1, fptr); + // jump back to the end of the file + fseek(fptr, 0, SEEK_END); +} + + + +void WavOutFile::close() +{ + finishHeader(); + fclose(fptr); + fptr = NULL; +} + + +void WavOutFile::write(const char *buffer, int numElems) +{ + int res; + + if (header.format.bits_per_sample != 8) + { + throw runtime_error("Error: WavOutFile::write(const char*, int) accepts only 8bit samples."); + } + assert(sizeof(char) == 1); + + res = fwrite(buffer, 1, numElems, fptr); + if (res != numElems) + { + throw runtime_error("Error while writing to a wav file."); + } + + bytesWritten += numElems; +} + + +void WavOutFile::write(const short *buffer, int numElems) +{ + int res; + + // 16 bit samples + if (numElems < 1) return; // nothing to do + + if (header.format.bits_per_sample == 8) + { + int i; + char *temp = new char[numElems]; + // convert from 16bit format to 8bit format + for (i = 0; i < numElems; i ++) + { + temp[i] = buffer[i] >> 8; + } + // write in 8bit format + write(temp, numElems); + delete[] temp; + } + else + { + // 16bit format + unsigned short *pTemp = new unsigned short[numElems]; + + assert(header.format.bits_per_sample == 16); + + // allocate temp buffer to swap byte order if necessary + memcpy(pTemp, buffer, numElems * 2); + _swap16Buffer(pTemp, numElems); + + res = fwrite(pTemp, 2, numElems, fptr); + + delete[] pTemp; + + if (res != numElems) + { + throw runtime_error("Error while writing to a wav file."); + } + bytesWritten += 2 * numElems; + } +} + + +void WavOutFile::write(const float *buffer, int numElems) +{ + int i; + short *temp = new short[numElems]; + int iTemp; + + // convert to 16 bit integer + for (i = 0; i < numElems; i ++) + { + // convert to integer + iTemp = (int)(32768.0f * buffer[i]); + + // saturate + if (iTemp < -32768) iTemp = -32768; + if (iTemp > 32767) iTemp = 32767; + temp[i] = (short)iTemp; + } + + write(temp, numElems); + + delete[] temp; +} diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/WavFile.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/WavFile.h index dd239034d2..331ef4d3e9 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/WavFile.h +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/WavFile.h @@ -1,253 +1,253 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Classes for easy reading & writing of WAV sound files. -/// -/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly -/// parse the WAV files with such processors. -/// -/// Admittingly, more complete WAV reader routines may exist in public domain, but -/// the reason for 'yet another' one is that those generic WAV reader libraries are -/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e. -/// something that's not already larger than rest of the SoundTouch/SoundStretch program... -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.7 $ -// -// $Id: WavFile.h,v 1.7 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef WAVFILE_H -#define WAVFILE_H - -#include - -#ifndef uint -typedef unsigned int uint; -#endif - - -/// WAV audio file 'riff' section header -typedef struct -{ - char riff_char[4]; - int package_len; - char wave[4]; -} WavRiff; - -/// WAV audio file 'format' section header -typedef struct -{ - char fmt[4]; - int format_len; - short fixed; - short channel_number; - int sample_rate; - int byte_rate; - short byte_per_sample; - short bits_per_sample; -} WavFormat; - -/// WAV audio file 'data' section header -typedef struct -{ - char data_field[4]; - uint data_len; -} WavData; - - -/// WAV audio file header -typedef struct -{ - WavRiff riff; - WavFormat format; - WavData data; -} WavHeader; - - -/// Class for reading WAV audio files. -class WavInFile -{ -private: - /// File pointer. - FILE *fptr; - - /// Counter of how many bytes of sample data have been read from the file. - uint dataRead; - - /// WAV header information - WavHeader header; - - /// Read WAV file headers. - /// \return zero if all ok, nonzero if file format is invalid. - int readWavHeaders(); - - /// Checks WAV file header tags. - /// \return zero if all ok, nonzero if file format is invalid. - int checkCharTags(); - - /// Reads a single WAV file header block. - /// \return zero if all ok, nonzero if file format is invalid. - int readHeaderBlock(); - - /// Reads WAV file 'riff' block - int readRIFFBlock(); - -public: - /// Constructor: Opens the given WAV file. If the file can't be opened, - /// throws 'runtime_error' exception. - WavInFile(const char *filename); - - /// Destructor: Closes the file. - ~WavInFile(); - - /// Close the file. Notice that file is automatically closed also when the - /// class instance is deleted. - void close(); - - /// Rewind to beginning of the file - void rewind(); - - /// Get sample rate. - uint getSampleRate() const; - - /// Get number of bits per sample, i.e. 8 or 16. - uint getNumBits() const; - - /// Get sample data size in bytes. Ahem, this should return same information as - /// 'getBytesPerSample'... - uint getDataSizeInBytes() const; - - /// Get total number of samples in file. - uint getNumSamples() const; - - /// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample) - uint getBytesPerSample() const; - - /// Get number of audio channels in the file (1=mono, 2=stereo) - uint getNumChannels() const; - - /// Get the audio file length in milliseconds - uint getLengthMS() const; - - /// Reads audio samples from the WAV file. This routine works only for 8 bit samples. - /// Reads given number of elements from the file or if end-of-file reached, as many - /// elements as are left in the file. - /// - /// \return Number of 8-bit integers read from the file. - int read(char *buffer, int maxElems); - - /// Reads audio samples from the WAV file to 16 bit integer format. Reads given number - /// of elements from the file or if end-of-file reached, as many elements as are - /// left in the file. - /// - /// \return Number of 16-bit integers read from the file. - int read(short *buffer, ///< Pointer to buffer where to read data. - int maxElems ///< Size of 'buffer' array (number of array elements). - ); - - /// Reads audio samples from the WAV file to floating point format, converting - /// sample values to range [-1,1[. Reads given number of elements from the file - /// or if end-of-file reached, as many elements as are left in the file. - /// - /// \return Number of elements read from the file. - int read(float *buffer, ///< Pointer to buffer where to read data. - int maxElems ///< Size of 'buffer' array (number of array elements). - ); - - /// Check end-of-file. - /// - /// \return Nonzero if end-of-file reached. - int eof() const; -}; - - - -/// Class for writing WAV audio files. -class WavOutFile -{ -private: - /// Pointer to the WAV file - FILE *fptr; - - /// WAV file header data. - WavHeader header; - - /// Counter of how many bytes have been written to the file so far. - int bytesWritten; - - /// Fills in WAV file header information. - void fillInHeader(const uint sampleRate, const uint bits, const uint channels); - - /// Finishes the WAV file header by supplementing information of amount of - /// data written to file etc - void finishHeader(); - - /// Writes the WAV file header. - void writeHeader(); - -public: - /// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception - /// if file creation fails. - WavOutFile(const char *fileName, ///< Filename - int sampleRate, ///< Sample rate (e.g. 44100 etc) - int bits, ///< Bits per sample (8 or 16 bits) - int channels ///< Number of channels (1=mono, 2=stereo) - ); - - /// Destructor: Finalizes & closes the WAV file. - ~WavOutFile(); - - /// Write data to WAV file. This function works only with 8bit samples. - /// Throws a 'runtime_error' exception if writing to file fails. - void write(const char *buffer, ///< Pointer to sample data buffer. - int numElems ///< How many array items are to be written to file. - ); - - /// Write data to WAV file. Throws a 'runtime_error' exception if writing to - /// file fails. - void write(const short *buffer, ///< Pointer to sample data buffer. - int numElems ///< How many array items are to be written to file. - ); - - /// Write data to WAV file in floating point format, saturating sample values to range - /// [-1..+1[. Throws a 'runtime_error' exception if writing to file fails. - void write(const float *buffer, ///< Pointer to sample data buffer. - int numElems ///< How many array items are to be written to file. - ); - - /// Finalize & close the WAV file. Automatically supplements the WAV file header - /// information according to written data etc. - /// - /// Notice that file is automatically closed also when the class instance is deleted. - void close(); -}; - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// Classes for easy reading & writing of WAV sound files. +/// +/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly +/// parse the WAV files with such processors. +/// +/// Admittingly, more complete WAV reader routines may exist in public domain, but +/// the reason for 'yet another' one is that those generic WAV reader libraries are +/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e. +/// something that's not already larger than rest of the SoundTouch/SoundStretch program... +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.7 $ +// +// $Id: WavFile.h,v 1.7 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef WAVFILE_H +#define WAVFILE_H + +#include + +#ifndef uint +typedef unsigned int uint; +#endif + + +/// WAV audio file 'riff' section header +typedef struct +{ + char riff_char[4]; + int package_len; + char wave[4]; +} WavRiff; + +/// WAV audio file 'format' section header +typedef struct +{ + char fmt[4]; + int format_len; + short fixed; + short channel_number; + int sample_rate; + int byte_rate; + short byte_per_sample; + short bits_per_sample; +} WavFormat; + +/// WAV audio file 'data' section header +typedef struct +{ + char data_field[4]; + uint data_len; +} WavData; + + +/// WAV audio file header +typedef struct +{ + WavRiff riff; + WavFormat format; + WavData data; +} WavHeader; + + +/// Class for reading WAV audio files. +class WavInFile +{ +private: + /// File pointer. + FILE *fptr; + + /// Counter of how many bytes of sample data have been read from the file. + uint dataRead; + + /// WAV header information + WavHeader header; + + /// Read WAV file headers. + /// \return zero if all ok, nonzero if file format is invalid. + int readWavHeaders(); + + /// Checks WAV file header tags. + /// \return zero if all ok, nonzero if file format is invalid. + int checkCharTags(); + + /// Reads a single WAV file header block. + /// \return zero if all ok, nonzero if file format is invalid. + int readHeaderBlock(); + + /// Reads WAV file 'riff' block + int readRIFFBlock(); + +public: + /// Constructor: Opens the given WAV file. If the file can't be opened, + /// throws 'runtime_error' exception. + WavInFile(const char *filename); + + /// Destructor: Closes the file. + ~WavInFile(); + + /// Close the file. Notice that file is automatically closed also when the + /// class instance is deleted. + void close(); + + /// Rewind to beginning of the file + void rewind(); + + /// Get sample rate. + uint getSampleRate() const; + + /// Get number of bits per sample, i.e. 8 or 16. + uint getNumBits() const; + + /// Get sample data size in bytes. Ahem, this should return same information as + /// 'getBytesPerSample'... + uint getDataSizeInBytes() const; + + /// Get total number of samples in file. + uint getNumSamples() const; + + /// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample) + uint getBytesPerSample() const; + + /// Get number of audio channels in the file (1=mono, 2=stereo) + uint getNumChannels() const; + + /// Get the audio file length in milliseconds + uint getLengthMS() const; + + /// Reads audio samples from the WAV file. This routine works only for 8 bit samples. + /// Reads given number of elements from the file or if end-of-file reached, as many + /// elements as are left in the file. + /// + /// \return Number of 8-bit integers read from the file. + int read(char *buffer, int maxElems); + + /// Reads audio samples from the WAV file to 16 bit integer format. Reads given number + /// of elements from the file or if end-of-file reached, as many elements as are + /// left in the file. + /// + /// \return Number of 16-bit integers read from the file. + int read(short *buffer, ///< Pointer to buffer where to read data. + int maxElems ///< Size of 'buffer' array (number of array elements). + ); + + /// Reads audio samples from the WAV file to floating point format, converting + /// sample values to range [-1,1[. Reads given number of elements from the file + /// or if end-of-file reached, as many elements as are left in the file. + /// + /// \return Number of elements read from the file. + int read(float *buffer, ///< Pointer to buffer where to read data. + int maxElems ///< Size of 'buffer' array (number of array elements). + ); + + /// Check end-of-file. + /// + /// \return Nonzero if end-of-file reached. + int eof() const; +}; + + + +/// Class for writing WAV audio files. +class WavOutFile +{ +private: + /// Pointer to the WAV file + FILE *fptr; + + /// WAV file header data. + WavHeader header; + + /// Counter of how many bytes have been written to the file so far. + int bytesWritten; + + /// Fills in WAV file header information. + void fillInHeader(const uint sampleRate, const uint bits, const uint channels); + + /// Finishes the WAV file header by supplementing information of amount of + /// data written to file etc + void finishHeader(); + + /// Writes the WAV file header. + void writeHeader(); + +public: + /// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception + /// if file creation fails. + WavOutFile(const char *fileName, ///< Filename + int sampleRate, ///< Sample rate (e.g. 44100 etc) + int bits, ///< Bits per sample (8 or 16 bits) + int channels ///< Number of channels (1=mono, 2=stereo) + ); + + /// Destructor: Finalizes & closes the WAV file. + ~WavOutFile(); + + /// Write data to WAV file. This function works only with 8bit samples. + /// Throws a 'runtime_error' exception if writing to file fails. + void write(const char *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Write data to WAV file. Throws a 'runtime_error' exception if writing to + /// file fails. + void write(const short *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Write data to WAV file in floating point format, saturating sample values to range + /// [-1..+1[. Throws a 'runtime_error' exception if writing to file fails. + void write(const float *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Finalize & close the WAV file. Automatically supplements the WAV file header + /// information according to written data etc. + /// + /// Notice that file is automatically closed also when the class instance is deleted. + void close(); +}; + +#endif diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect.h index 568817f17b..69892102c9 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect.h +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect.h @@ -1,62 +1,62 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// A header file for detecting the Intel MMX instructions set extension. -/// -/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the -/// routine implementations for x86 Windows, x86 gnu version and non-x86 -/// platforms, respectively. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.4 $ -// -// $Id: cpu_detect.h,v 1.4 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef _CPU_DETECT_H_ -#define _CPU_DETECT_H_ - -#include "STTypes.h" - -#define SUPPORT_MMX 0x0001 -#define SUPPORT_3DNOW 0x0002 -#define SUPPORT_ALTIVEC 0x0004 -#define SUPPORT_SSE 0x0008 -#define SUPPORT_SSE2 0x0010 - -/// Checks which instruction set extensions are supported by the CPU. -/// -/// \return A bitmask of supported extensions, see SUPPORT_... defines. -uint detectCPUextensions(void); - -/// Disables given set of instruction extensions. See SUPPORT_... defines. -void disableExtensions(uint wDisableMask); - -#endif // _CPU_DETECT_H_ +//////////////////////////////////////////////////////////////////////////////// +/// +/// A header file for detecting the Intel MMX instructions set extension. +/// +/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the +/// routine implementations for x86 Windows, x86 gnu version and non-x86 +/// platforms, respectively. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.4 $ +// +// $Id: cpu_detect.h,v 1.4 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _CPU_DETECT_H_ +#define _CPU_DETECT_H_ + +#include "STTypes.h" + +#define SUPPORT_MMX 0x0001 +#define SUPPORT_3DNOW 0x0002 +#define SUPPORT_ALTIVEC 0x0004 +#define SUPPORT_SSE 0x0008 +#define SUPPORT_SSE2 0x0010 + +/// Checks which instruction set extensions are supported by the CPU. +/// +/// \return A bitmask of supported extensions, see SUPPORT_... defines. +uint detectCPUextensions(void); + +/// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint wDisableMask); + +#endif // _CPU_DETECT_H_ diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp index 75bd771099..68423c3a0e 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp @@ -1,138 +1,138 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// gcc version of the x86 CPU detect routine. -/// -/// This file is to be compiled on any platform with the GNU C compiler. -/// Compiler. Please see 'cpu_detect_x86_win.cpp' for the x86 Windows version -/// of this file. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.6 $ -// -// $Id: cpu_detect_x86_gcc.cpp,v 1.6 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include "cpu_detect.h" - -#ifndef __GNUC__ -#error wrong platform - this source code file is for the GNU C compiler. -#endif - -using namespace std; - -#include -////////////////////////////////////////////////////////////////////////////// -// -// processor instructions extension detection routines -// -////////////////////////////////////////////////////////////////////////////// - - -// Flag variable indicating whick ISA extensions are disabled (for debugging) -static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions - -// Disables given set of instruction extensions. See SUPPORT_... defines. -void disableExtensions(uint dwDisableMask) -{ - _dwDisabledISA = dwDisableMask; -} - - - -/// Checks which instruction set extensions are supported by the CPU. -uint detectCPUextensions(void) -{ -#ifndef __i386__ - return 0; // always disable extensions on non-x86 platforms. -#else - uint res = 0; - - if (_dwDisabledISA == 0xffffffff) return 0; - - asm volatile( - "\n\txor %%esi, %%esi" // clear %%esi = result register - // check if 'cpuid' instructions is available by toggling eflags bit 21 - - "\n\tpushf" // save eflags to stack - "\n\tpop %%eax" // load eax from stack (with eflags) - "\n\tmovl %%eax, %%ecx" // save the original eflags values to ecx - "\n\txor $0x00200000, %%eax" // toggle bit 21 - "\n\tpush %%eax" // store toggled eflags to stack - "\n\tpopf" // load eflags from stack - "\n\tpushf" // save updated eflags to stack - "\n\tpop %%eax" // load from stack - "\n\txor %%edx, %%edx" // clear edx for defaulting no mmx - "\n\tcmp %%ecx, %%eax" // compare to original eflags values - "\n\tjz end" // jumps to 'end' if cpuid not present - - // cpuid instruction available, test for presence of mmx instructions - - "\n\tmovl $1, %%eax" - "\n\tcpuid" -// movl $0x00800000, %edx // force enable MMX - "\n\ttest $0x00800000, %%edx" - "\n\tjz end" // branch if MMX not available - - "\n\tor $0x01, %%esi" // otherwise add MMX support bit - - "\n\ttest $0x02000000, %%edx" - "\n\tjz test3DNow" // branch if SSE not available - - "\n\tor $0x08, %%esi" // otherwise add SSE support bit - - "\n\ttest3DNow:" - // test for precense of AMD extensions - "\n\tmov $0x80000000, %%eax" - "\n\tcpuid" - "\n\tcmp $0x80000000, %%eax" - "\n\tjbe end" // branch if no AMD extensions detected - - // test for precense of 3DNow! extension - "\n\tmov $0x80000001, %%eax" - "\n\tcpuid" - "\n\ttest $0x80000000, %%edx" - "\n\tjz end" // branch if 3DNow! not detected - - "\n\tor $0x02, %%esi" // otherwise add 3DNow support bit - - "\n\tend:" - - "\n\tmov %%esi, %0" - - : "=r" (res) - : /* no inputs */ - : "%edx", "%eax", "%ecx", "%esi" ); - - return res & ~_dwDisabledISA; -#endif -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// gcc version of the x86 CPU detect routine. +/// +/// This file is to be compiled on any platform with the GNU C compiler. +/// Compiler. Please see 'cpu_detect_x86_win.cpp' for the x86 Windows version +/// of this file. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.6 $ +// +// $Id: cpu_detect_x86_gcc.cpp,v 1.6 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "cpu_detect.h" + +#ifndef __GNUC__ +#error wrong platform - this source code file is for the GNU C compiler. +#endif + +using namespace std; + +#include +////////////////////////////////////////////////////////////////////////////// +// +// processor instructions extension detection routines +// +////////////////////////////////////////////////////////////////////////////// + + +// Flag variable indicating whick ISA extensions are disabled (for debugging) +static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions + +// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint dwDisableMask) +{ + _dwDisabledISA = dwDisableMask; +} + + + +/// Checks which instruction set extensions are supported by the CPU. +uint detectCPUextensions(void) +{ +#ifndef __i386__ + return 0; // always disable extensions on non-x86 platforms. +#else + uint res = 0; + + if (_dwDisabledISA == 0xffffffff) return 0; + + asm volatile( + "\n\txor %%esi, %%esi" // clear %%esi = result register + // check if 'cpuid' instructions is available by toggling eflags bit 21 + + "\n\tpushf" // save eflags to stack + "\n\tpop %%eax" // load eax from stack (with eflags) + "\n\tmovl %%eax, %%ecx" // save the original eflags values to ecx + "\n\txor $0x00200000, %%eax" // toggle bit 21 + "\n\tpush %%eax" // store toggled eflags to stack + "\n\tpopf" // load eflags from stack + "\n\tpushf" // save updated eflags to stack + "\n\tpop %%eax" // load from stack + "\n\txor %%edx, %%edx" // clear edx for defaulting no mmx + "\n\tcmp %%ecx, %%eax" // compare to original eflags values + "\n\tjz end" // jumps to 'end' if cpuid not present + + // cpuid instruction available, test for presence of mmx instructions + + "\n\tmovl $1, %%eax" + "\n\tcpuid" +// movl $0x00800000, %edx // force enable MMX + "\n\ttest $0x00800000, %%edx" + "\n\tjz end" // branch if MMX not available + + "\n\tor $0x01, %%esi" // otherwise add MMX support bit + + "\n\ttest $0x02000000, %%edx" + "\n\tjz test3DNow" // branch if SSE not available + + "\n\tor $0x08, %%esi" // otherwise add SSE support bit + + "\n\ttest3DNow:" + // test for precense of AMD extensions + "\n\tmov $0x80000000, %%eax" + "\n\tcpuid" + "\n\tcmp $0x80000000, %%eax" + "\n\tjbe end" // branch if no AMD extensions detected + + // test for precense of 3DNow! extension + "\n\tmov $0x80000001, %%eax" + "\n\tcpuid" + "\n\ttest $0x80000000, %%edx" + "\n\tjz end" // branch if 3DNow! not detected + + "\n\tor $0x02, %%esi" // otherwise add 3DNow support bit + + "\n\tend:" + + "\n\tmov %%esi, %0" + + : "=r" (res) + : /* no inputs */ + : "%edx", "%eax", "%ecx", "%esi" ); + + return res & ~_dwDisabledISA; +#endif +} diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect_x86_win.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect_x86_win.cpp index d8f9e58dd0..ee3acf69f7 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect_x86_win.cpp +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect_x86_win.cpp @@ -1,126 +1,126 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Win32 version of the x86 CPU detect routine. -/// -/// This file is to be compiled in Windows platform with Microsoft Visual C++ -/// Compiler. Please see 'cpu_detect_x86_gcc.cpp' for the gcc compiler version -/// for all GNU platforms. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.10 $ -// -// $Id: cpu_detect_x86_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include "cpu_detect.h" - -#ifndef _WIN32 -#error wrong platform - this source code file is exclusively for Win32 platform -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// processor instructions extension detection routines -// -////////////////////////////////////////////////////////////////////////////// - -// Flag variable indicating whick ISA extensions are disabled (for debugging) -static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions - - -// Disables given set of instruction extensions. See SUPPORT_... defines. -void disableExtensions(uint dwDisableMask) -{ - _dwDisabledISA = dwDisableMask; -} - - - -/// Checks which instruction set extensions are supported by the CPU. -uint detectCPUextensions(void) -{ - uint res = 0; - - if (_dwDisabledISA == 0xffffffff) return 0; - - _asm - { - ; check if 'cpuid' instructions is available by toggling eflags bit 21 - ; - xor esi, esi ; clear esi = result register - - pushfd ; save eflags to stack - pop eax ; load eax from stack (with eflags) - mov ecx, eax ; save the original eflags values to ecx - xor eax, 0x00200000 ; toggle bit 21 - push eax ; store toggled eflags to stack - popfd ; load eflags from stack - pushfd ; save updated eflags to stack - pop eax ; load from stack - xor edx, edx ; clear edx for defaulting no mmx - cmp eax, ecx ; compare to original eflags values - jz end ; jumps to 'end' if cpuid not present - - ; cpuid instruction available, test for presence of mmx instructions - mov eax, 1 - cpuid - test edx, 0x00800000 - jz end ; branch if MMX not available - - or esi, SUPPORT_MMX ; otherwise add MMX support bit - - test edx, 0x02000000 - jz test3DNow ; branch if SSE not available - - or esi, SUPPORT_SSE ; otherwise add SSE support bit - - test3DNow: - ; test for precense of AMD extensions - mov eax, 0x80000000 - cpuid - cmp eax, 0x80000000 - jbe end ; branch if no AMD extensions detected - - ; test for precense of 3DNow! extension - mov eax, 0x80000001 - cpuid - test edx, 0x80000000 - jz end ; branch if 3DNow! not detected - - or esi, SUPPORT_3DNOW ; otherwise add 3DNow support bit - - end: - - mov res, esi - } - - return res & ~_dwDisabledISA; -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// Win32 version of the x86 CPU detect routine. +/// +/// This file is to be compiled in Windows platform with Microsoft Visual C++ +/// Compiler. Please see 'cpu_detect_x86_gcc.cpp' for the gcc compiler version +/// for all GNU platforms. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: cpu_detect_x86_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" + +#ifndef _WIN32 +#error wrong platform - this source code file is exclusively for Win32 platform +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// processor instructions extension detection routines +// +////////////////////////////////////////////////////////////////////////////// + +// Flag variable indicating whick ISA extensions are disabled (for debugging) +static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions + + +// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint dwDisableMask) +{ + _dwDisabledISA = dwDisableMask; +} + + + +/// Checks which instruction set extensions are supported by the CPU. +uint detectCPUextensions(void) +{ + uint res = 0; + + if (_dwDisabledISA == 0xffffffff) return 0; + + _asm + { + ; check if 'cpuid' instructions is available by toggling eflags bit 21 + ; + xor esi, esi ; clear esi = result register + + pushfd ; save eflags to stack + pop eax ; load eax from stack (with eflags) + mov ecx, eax ; save the original eflags values to ecx + xor eax, 0x00200000 ; toggle bit 21 + push eax ; store toggled eflags to stack + popfd ; load eflags from stack + pushfd ; save updated eflags to stack + pop eax ; load from stack + xor edx, edx ; clear edx for defaulting no mmx + cmp eax, ecx ; compare to original eflags values + jz end ; jumps to 'end' if cpuid not present + + ; cpuid instruction available, test for presence of mmx instructions + mov eax, 1 + cpuid + test edx, 0x00800000 + jz end ; branch if MMX not available + + or esi, SUPPORT_MMX ; otherwise add MMX support bit + + test edx, 0x02000000 + jz test3DNow ; branch if SSE not available + + or esi, SUPPORT_SSE ; otherwise add SSE support bit + + test3DNow: + ; test for precense of AMD extensions + mov eax, 0x80000000 + cpuid + cmp eax, 0x80000000 + jbe end ; branch if no AMD extensions detected + + ; test for precense of 3DNow! extension + mov eax, 0x80000001 + cpuid + test edx, 0x80000000 + jz end ; branch if 3DNow! not detected + + or esi, SUPPORT_3DNOW ; otherwise add 3DNow support bit + + end: + + mov res, esi + } + + return res & ~_dwDisabledISA; +} diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/mmx_optimized.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/mmx_optimized.cpp index f5afb595a5..b49584b694 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/mmx_optimized.cpp +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/mmx_optimized.cpp @@ -1,305 +1,305 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// MMX optimized routines. All MMX optimized functions have been gathered into -/// this single source code file, regardless to their class or original source -/// code file, in order to ease porting the library to other compiler and -/// processor platforms. -/// -/// The MMX-optimizations are programmed using MMX compiler intrinsics that -/// are supported both by Microsoft Visual C++ and GCC compilers, so this file -/// should compile with both toolsets. -/// -/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ -/// 6.0 processor pack" update to support compiler intrinsic syntax. The update -/// is available for download at Microsoft Developers Network, see here: -/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/06 18:52:43 $ -// File revision : $Revision: 1.1 $ -// -// $Id: mmx_optimized.cpp,v 1.1 2006/02/06 18:52:43 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include "STTypes.h" - -#ifdef ALLOW_MMX -// MMX routines available only with integer sample type - -#if !(_WIN32 || __i386__ || __x86_64__) -#error "wrong platform - this source code file is exclusively for x86 platforms" -#endif - -using namespace soundtouch; - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of MMX optimized functions of class 'TDStretchMMX' -// -////////////////////////////////////////////////////////////////////////////// - -#include "TDStretch.h" -#include -#include - - -// Calculates cross correlation of two buffers -long TDStretchMMX::calcCrossCorrStereo(const short *pV1, const short *pV2) const -{ - const __m64 *pVec1, *pVec2; - __m64 shifter; - __m64 accu; - long corr; - uint i; - - pVec1 = (__m64*)pV1; - pVec2 = (__m64*)pV2; - - shifter = _m_from_int(overlapDividerBits); - accu = _mm_setzero_si64(); - - // Process 4 parallel sets of 2 * stereo samples each during each - // round to improve CPU-level parallellization. - for (i = 0; i < overlapLength / 8; i ++) - { - __m64 temp; - - // dictionary of instructions: - // _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3] - // _mm_add_pi32 : 2*32bit add - // _m_psrad : 32bit right-shift - - temp = _mm_add_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), - _mm_madd_pi16(pVec1[1], pVec2[1])); - accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); - - temp = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), - _mm_madd_pi16(pVec1[3], pVec2[3])); - accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); - - pVec1 += 4; - pVec2 += 4; - } - - // copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1 - // and finally store the result into the variable "corr" - - accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32)); - corr = _m_to_int(accu); - - // Clear MMS state - _m_empty(); - - return corr; - // Note: Warning about the missing EMMS instruction is harmless - // as it'll be called elsewhere. -} - - - -void TDStretchMMX::clearCrossCorrState() -{ - // Clear MMS state - _m_empty(); - //_asm EMMS; -} - - - -// MMX-optimized version of the function overlapStereo -void TDStretchMMX::overlapStereo(short *output, const short *input) const -{ - const __m64 *pVinput, *pVMidBuf; - __m64 *pVdest; - __m64 mix1, mix2, adder, shifter; - uint i; - - pVinput = (const __m64*)input; - pVMidBuf = (const __m64*)pMidBuffer; - pVdest = (__m64*)output; - - // mix1 = mixer values for 1st stereo sample - // mix1 = mixer values for 2nd stereo sample - // adder = adder for updating mixer values after each round - - mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength); - adder = _mm_set_pi16(1, -1, 1, -1); - mix2 = _mm_add_pi16(mix1, adder); - adder = _mm_add_pi16(adder, adder); - - shifter = _m_from_int(overlapDividerBits); - - for (i = 0; i < overlapLength / 4; i ++) - { - __m64 temp1, temp2; - - // load & shuffle data so that input & mixbuffer data samples are paired - temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r - temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r - - // temp = (temp .* mix) >> shifter - temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); - temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); - pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit - - // update mix += adder - mix1 = _mm_add_pi16(mix1, adder); - mix2 = _mm_add_pi16(mix2, adder); - - // --- second round begins here --- - - // load & shuffle data so that input & mixbuffer data samples are paired - temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]); // = i2l m2l i2r m2r - temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]); // = i3l m3l i3r m3r - - // temp = (temp .* mix) >> shifter - temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); - temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); - pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit - - // update mix += adder - mix1 = _mm_add_pi16(mix1, adder); - mix2 = _mm_add_pi16(mix2, adder); - - pVinput += 2; - pVMidBuf += 2; - pVdest += 2; - } - - _m_empty(); // clear MMS state -} - - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of MMX optimized functions of class 'FIRFilter' -// -////////////////////////////////////////////////////////////////////////////// - -#include "FIRFilter.h" - - -FIRFilterMMX::FIRFilterMMX() : FIRFilter() -{ - filterCoeffsUnalign = NULL; -} - - -FIRFilterMMX::~FIRFilterMMX() -{ - delete[] filterCoeffsUnalign; -} - - -// (overloaded) Calculates filter coefficients for MMX routine -void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor) -{ - uint i; - FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); - - // Ensure that filter coeffs array is aligned to 16-byte boundary - delete[] filterCoeffsUnalign; - filterCoeffsUnalign = new short[2 * newLength + 8]; - filterCoeffsAlign = (short *)(((ulongptr)filterCoeffsUnalign + 15) & -16); - - // rearrange the filter coefficients for mmx routines - for (i = 0;i < length; i += 4) - { - filterCoeffsAlign[2 * i + 0] = coeffs[i + 0]; - filterCoeffsAlign[2 * i + 1] = coeffs[i + 2]; - filterCoeffsAlign[2 * i + 2] = coeffs[i + 0]; - filterCoeffsAlign[2 * i + 3] = coeffs[i + 2]; - - filterCoeffsAlign[2 * i + 4] = coeffs[i + 1]; - filterCoeffsAlign[2 * i + 5] = coeffs[i + 3]; - filterCoeffsAlign[2 * i + 6] = coeffs[i + 1]; - filterCoeffsAlign[2 * i + 7] = coeffs[i + 3]; - } -} - - - -// mmx-optimized version of the filter routine for stereo sound -uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, const uint numSamples) const -{ - // Create stack copies of the needed member variables for asm routines : - uint i, j; - __m64 *pVdest = (__m64*)dest; - - if (length < 2) return 0; - - for (i = 0; i < numSamples / 2; i ++) - { - __m64 accu1; - __m64 accu2; - const __m64 *pVsrc = (const __m64*)src; - const __m64 *pVfilter = (const __m64*)filterCoeffsAlign; - - accu1 = accu2 = _mm_setzero_si64(); - for (j = 0; j < lengthDiv8 * 2; j ++) - { - __m64 temp1, temp2; - - temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]); // = l2 l0 r2 r0 - temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]); // = l3 l1 r3 r1 - - accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0])); // += l2*f2+l0*f0 r2*f2+r0*f0 - accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1])); // += l3*f3+l1*f1 r3*f3+r1*f1 - - temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]); // = l4 l2 r4 r2 - - accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0])); // += l3*f2+l1*f0 r3*f2+r1*f0 - accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1])); // += l4*f3+l2*f1 r4*f3+r2*f1 - - // accu1 += l2*f2+l0*f0 r2*f2+r0*f0 - // += l3*f3+l1*f1 r3*f3+r1*f1 - - // accu2 += l3*f2+l1*f0 r3*f2+r1*f0 - // l4*f3+l2*f1 r4*f3+r2*f1 - - pVfilter += 2; - pVsrc += 2; - } - // accu >>= resultDivFactor - accu1 = _mm_srai_pi32(accu1, resultDivFactor); - accu2 = _mm_srai_pi32(accu2, resultDivFactor); - - // pack 2*2*32bits => 4*16 bits - pVdest[0] = _mm_packs_pi32(accu1, accu2); - src += 4; - pVdest ++; - } - - _m_empty(); // clear emms state - - return (numSamples & 0xfffffffe) - length; -} - -#endif // ALLOW_MMX +//////////////////////////////////////////////////////////////////////////////// +/// +/// MMX optimized routines. All MMX optimized functions have been gathered into +/// this single source code file, regardless to their class or original source +/// code file, in order to ease porting the library to other compiler and +/// processor platforms. +/// +/// The MMX-optimizations are programmed using MMX compiler intrinsics that +/// are supported both by Microsoft Visual C++ and GCC compilers, so this file +/// should compile with both toolsets. +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support compiler intrinsic syntax. The update +/// is available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/06 18:52:43 $ +// File revision : $Revision: 1.1 $ +// +// $Id: mmx_optimized.cpp,v 1.1 2006/02/06 18:52:43 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "STTypes.h" + +#ifdef ALLOW_MMX +// MMX routines available only with integer sample type + +#if !(_WIN32 || __i386__ || __x86_64__) +#error "wrong platform - this source code file is exclusively for x86 platforms" +#endif + +using namespace soundtouch; + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of MMX optimized functions of class 'TDStretchMMX' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include +#include + + +// Calculates cross correlation of two buffers +long TDStretchMMX::calcCrossCorrStereo(const short *pV1, const short *pV2) const +{ + const __m64 *pVec1, *pVec2; + __m64 shifter; + __m64 accu; + long corr; + uint i; + + pVec1 = (__m64*)pV1; + pVec2 = (__m64*)pV2; + + shifter = _m_from_int(overlapDividerBits); + accu = _mm_setzero_si64(); + + // Process 4 parallel sets of 2 * stereo samples each during each + // round to improve CPU-level parallellization. + for (i = 0; i < overlapLength / 8; i ++) + { + __m64 temp; + + // dictionary of instructions: + // _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3] + // _mm_add_pi32 : 2*32bit add + // _m_psrad : 32bit right-shift + + temp = _mm_add_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), + _mm_madd_pi16(pVec1[1], pVec2[1])); + accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); + + temp = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), + _mm_madd_pi16(pVec1[3], pVec2[3])); + accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); + + pVec1 += 4; + pVec2 += 4; + } + + // copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1 + // and finally store the result into the variable "corr" + + accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32)); + corr = _m_to_int(accu); + + // Clear MMS state + _m_empty(); + + return corr; + // Note: Warning about the missing EMMS instruction is harmless + // as it'll be called elsewhere. +} + + + +void TDStretchMMX::clearCrossCorrState() +{ + // Clear MMS state + _m_empty(); + //_asm EMMS; +} + + + +// MMX-optimized version of the function overlapStereo +void TDStretchMMX::overlapStereo(short *output, const short *input) const +{ + const __m64 *pVinput, *pVMidBuf; + __m64 *pVdest; + __m64 mix1, mix2, adder, shifter; + uint i; + + pVinput = (const __m64*)input; + pVMidBuf = (const __m64*)pMidBuffer; + pVdest = (__m64*)output; + + // mix1 = mixer values for 1st stereo sample + // mix1 = mixer values for 2nd stereo sample + // adder = adder for updating mixer values after each round + + mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength); + adder = _mm_set_pi16(1, -1, 1, -1); + mix2 = _mm_add_pi16(mix1, adder); + adder = _mm_add_pi16(adder, adder); + + shifter = _m_from_int(overlapDividerBits); + + for (i = 0; i < overlapLength / 4; i ++) + { + __m64 temp1, temp2; + + // load & shuffle data so that input & mixbuffer data samples are paired + temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r + temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r + + // temp = (temp .* mix) >> shifter + temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); + temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); + pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit + + // update mix += adder + mix1 = _mm_add_pi16(mix1, adder); + mix2 = _mm_add_pi16(mix2, adder); + + // --- second round begins here --- + + // load & shuffle data so that input & mixbuffer data samples are paired + temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]); // = i2l m2l i2r m2r + temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]); // = i3l m3l i3r m3r + + // temp = (temp .* mix) >> shifter + temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); + temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); + pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit + + // update mix += adder + mix1 = _mm_add_pi16(mix1, adder); + mix2 = _mm_add_pi16(mix2, adder); + + pVinput += 2; + pVMidBuf += 2; + pVdest += 2; + } + + _m_empty(); // clear MMS state +} + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of MMX optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + + +FIRFilterMMX::FIRFilterMMX() : FIRFilter() +{ + filterCoeffsUnalign = NULL; +} + + +FIRFilterMMX::~FIRFilterMMX() +{ + delete[] filterCoeffsUnalign; +} + + +// (overloaded) Calculates filter coefficients for MMX routine +void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new short[2 * newLength + 8]; + filterCoeffsAlign = (short *)(((ulongptr)filterCoeffsUnalign + 15) & -16); + + // rearrange the filter coefficients for mmx routines + for (i = 0;i < length; i += 4) + { + filterCoeffsAlign[2 * i + 0] = coeffs[i + 0]; + filterCoeffsAlign[2 * i + 1] = coeffs[i + 2]; + filterCoeffsAlign[2 * i + 2] = coeffs[i + 0]; + filterCoeffsAlign[2 * i + 3] = coeffs[i + 2]; + + filterCoeffsAlign[2 * i + 4] = coeffs[i + 1]; + filterCoeffsAlign[2 * i + 5] = coeffs[i + 3]; + filterCoeffsAlign[2 * i + 6] = coeffs[i + 1]; + filterCoeffsAlign[2 * i + 7] = coeffs[i + 3]; + } +} + + + +// mmx-optimized version of the filter routine for stereo sound +uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, const uint numSamples) const +{ + // Create stack copies of the needed member variables for asm routines : + uint i, j; + __m64 *pVdest = (__m64*)dest; + + if (length < 2) return 0; + + for (i = 0; i < numSamples / 2; i ++) + { + __m64 accu1; + __m64 accu2; + const __m64 *pVsrc = (const __m64*)src; + const __m64 *pVfilter = (const __m64*)filterCoeffsAlign; + + accu1 = accu2 = _mm_setzero_si64(); + for (j = 0; j < lengthDiv8 * 2; j ++) + { + __m64 temp1, temp2; + + temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]); // = l2 l0 r2 r0 + temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]); // = l3 l1 r3 r1 + + accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0])); // += l2*f2+l0*f0 r2*f2+r0*f0 + accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1])); // += l3*f3+l1*f1 r3*f3+r1*f1 + + temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]); // = l4 l2 r4 r2 + + accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0])); // += l3*f2+l1*f0 r3*f2+r1*f0 + accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1])); // += l4*f3+l2*f1 r4*f3+r2*f1 + + // accu1 += l2*f2+l0*f0 r2*f2+r0*f0 + // += l3*f3+l1*f1 r3*f3+r1*f1 + + // accu2 += l3*f2+l1*f0 r3*f2+r1*f0 + // l4*f3+l2*f1 r4*f3+r2*f1 + + pVfilter += 2; + pVsrc += 2; + } + // accu >>= resultDivFactor + accu1 = _mm_srai_pi32(accu1, resultDivFactor); + accu2 = _mm_srai_pi32(accu2, resultDivFactor); + + // pack 2*2*32bits => 4*16 bits + pVdest[0] = _mm_packs_pi32(accu1, accu2); + src += 4; + pVdest ++; + } + + _m_empty(); // clear emms state + + return (numSamples & 0xfffffffe) - length; +} + +#endif // ALLOW_MMX diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/sse_optimized.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/sse_optimized.cpp index 57598d78d7..1e70da6608 100644 --- a/plugins/spu2ghz/src/3rdparty/SoundTouch/sse_optimized.cpp +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/sse_optimized.cpp @@ -1,484 +1,484 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE -/// optimized functions have been gathered into this single source -/// code file, regardless to their class or original source code file, in order -/// to ease porting the library to other compiler and processor platforms. -/// -/// The SSE-optimizations are programmed using SSE compiler intrinsics that -/// are supported both by Microsoft Visual C++ and GCC compilers, so this file -/// should compile with both toolsets. -/// -/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ -/// 6.0 processor pack" update to support SSE instruction set. The update is -/// available for download at Microsoft Developers Network, see here: -/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx -/// -/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and -/// perform a search with keywords "processor pack". -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.2 $ -// -// $Id: sse_optimized.cpp,v 1.2 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include "cpu_detect.h" -#include "STTypes.h" - -using namespace soundtouch; - -#ifdef ALLOW_SSE - -// SSE routines available only with float sample type - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of SSE optimized functions of class 'TDStretchSSE' -// -////////////////////////////////////////////////////////////////////////////// - -#include "TDStretch.h" -#include - -// Calculates cross correlation of two buffers -double TDStretchSSE::calcCrossCorrStereo(const float *pV1, const float *pV2) const -{ - uint i; - __m128 vSum, *pVec2; - - // Note. It means a major slow-down if the routine needs to tolerate - // unaligned __m128 memory accesses. It's way faster if we can skip - // unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps. - // This can mean up to ~ 10-fold difference (incl. part of which is - // due to skipping every second round for stereo sound though). - // - // Compile-time define ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided - // for choosing if this little cheating is allowed. - -#ifdef ALLOW_NONEXACT_SIMD_OPTIMIZATION - // Little cheating allowed, return valid correlation only for - // aligned locations, meaning every second round for stereo sound. - - #define _MM_LOAD _mm_load_ps - - if (((ulong)pV1) & 15) return -1e50; // skip unaligned locations - -#else - // No cheating allowed, use unaligned load & take the resulting - // performance hit. - #define _MM_LOAD _mm_loadu_ps -#endif - - // ensure overlapLength is divisible by 8 - assert((overlapLength % 8) == 0); - - // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors - // Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not. - pVec2 = (__m128*)pV2; - vSum = _mm_setzero_ps(); - - // Unroll the loop by factor of 4 * 4 operations - for (i = 0; i < overlapLength / 8; i ++) - { - // vSum += pV1[0..3] * pV2[0..3] - vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1),pVec2[0])); - - // vSum += pV1[4..7] * pV2[4..7] - vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 4), pVec2[1])); - - // vSum += pV1[8..11] * pV2[8..11] - vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 8), pVec2[2])); - - // vSum += pV1[12..15] * pV2[12..15] - vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 12), pVec2[3])); - - pV1 += 16; - pVec2 += 4; - } - - // return value = vSum[0] + vSum[1] + vSum[2] + vSum[3] - float *pvSum = (float*)&vSum; - return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]); - - /* This is approximately corresponding routine in C-language: - double corr; - uint i; - - // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors - corr = 0.0; - for (i = 0; i < overlapLength / 8; i ++) - { - corr += pV1[0] * pV2[0] + - pV1[1] * pV2[1] + - pV1[2] * pV2[2] + - pV1[3] * pV2[3] + - pV1[4] * pV2[4] + - pV1[5] * pV2[5] + - pV1[6] * pV2[6] + - pV1[7] * pV2[7] + - pV1[8] * pV2[8] + - pV1[9] * pV2[9] + - pV1[10] * pV2[10] + - pV1[11] * pV2[11] + - pV1[12] * pV2[12] + - pV1[13] * pV2[13] + - pV1[14] * pV2[14] + - pV1[15] * pV2[15]; - - pV1 += 16; - pV2 += 16; - } - */ - - /* This is corresponding routine in assembler. This may be teeny-weeny bit faster - than intrinsic version, but more difficult to maintain & get compiled on multiple - platforms. - - uint overlapLengthLocal = overlapLength; - float corr; - - _asm - { - // Very important note: data in 'pV2' _must_ be aligned to - // 16-byte boundary! - - // give prefetch hints to CPU of what data are to be needed soonish - // give more aggressive hints on pV1 as that changes while pV2 stays - // same between runs - prefetcht0 [pV1] - prefetcht0 [pV2] - prefetcht0 [pV1 + 32] - - mov eax, dword ptr pV1 - mov ebx, dword ptr pV2 - - xorps xmm0, xmm0 - - mov ecx, overlapLengthLocal - shr ecx, 3 // div by eight - - loop1: - prefetcht0 [eax + 64] // give a prefetch hint to CPU what data are to be needed soonish - prefetcht0 [ebx + 32] // give a prefetch hint to CPU what data are to be needed soonish - movups xmm1, [eax] - mulps xmm1, [ebx] - addps xmm0, xmm1 - - movups xmm2, [eax + 16] - mulps xmm2, [ebx + 16] - addps xmm0, xmm2 - - prefetcht0 [eax + 96] // give a prefetch hint to CPU what data are to be needed soonish - prefetcht0 [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish - - movups xmm3, [eax + 32] - mulps xmm3, [ebx + 32] - addps xmm0, xmm3 - - movups xmm4, [eax + 48] - mulps xmm4, [ebx + 48] - addps xmm0, xmm4 - - add eax, 64 - add ebx, 64 - - dec ecx - jnz loop1 - - // add the four floats of xmm0 together and return the result. - - movhlps xmm1, xmm0 // move 3 & 4 of xmm0 to 1 & 2 of xmm1 - addps xmm1, xmm0 - movaps xmm2, xmm1 - shufps xmm2, xmm2, 0x01 // move 2 of xmm2 as 1 of xmm2 - addss xmm2, xmm1 - movss corr, xmm2 - } - - return (double)corr; - */ -} - - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of SSE optimized functions of class 'FIRFilter' -// -////////////////////////////////////////////////////////////////////////////// - -#include "FIRFilter.h" - -FIRFilterSSE::FIRFilterSSE() : FIRFilter() -{ - filterCoeffsUnalign = NULL; -} - - -FIRFilterSSE::~FIRFilterSSE() -{ - delete[] filterCoeffsUnalign; -} - - -// (overloaded) Calculates filter coefficients for SSE routine -void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) -{ - uint i; - float fDivider; - - FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); - - // Scale the filter coefficients so that it won't be necessary to scale the filtering result - // also rearrange coefficients suitably for 3DNow! - // Ensure that filter coeffs array is aligned to 16-byte boundary - delete[] filterCoeffsUnalign; - filterCoeffsUnalign = new float[2 * newLength + 4]; - filterCoeffsAlign = (float *)(((unsigned long)filterCoeffsUnalign + 15) & -16); - - fDivider = (float)resultDivider; - - // rearrange the filter coefficients for mmx routines - for (i = 0; i < newLength; i ++) - { - filterCoeffsAlign[2 * i + 0] = - filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; - } -} - - - -// SSE-optimized version of the filter routine for stereo sound -uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const -{ - int count = (numSamples - length) & -2; - int j; - - assert(count % 2 == 0); - - if (count < 2) return 0; - - assert((length % 8) == 0); - assert(((unsigned long)filterCoeffsAlign) % 16 == 0); - - // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2' - for (j = 0; j < count; j += 2) - { - const float *pSrc; - const __m128 *pFil; - __m128 sum1, sum2; - uint i; - - pSrc = source; // source audio data - pFil = (__m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients - // are aligned to 16-byte boundary - sum1 = sum2 = _mm_setzero_ps(); - - for (i = 0; i < length / 8; i ++) - { - // Unroll loop for efficiency & calculate filter for 2*2 stereo samples - // at each pass - - // sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset - // sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset. - - sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc) , pFil[0])); - sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0])); - - sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1])); - sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1])); - - sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) , pFil[2])); - sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2])); - - sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3])); - sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3])); - - pSrc += 16; - pFil += 4; - } - - // Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need - // to sum the two hi- and lo-floats of these registers together. - - // post-shuffle & add the filtered values and store to dest. - _mm_storeu_ps(dest, _mm_add_ps( - _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2 - _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0 - )); - source += 4; - dest += 4; - } - - // Ideas for further improvement: - // 1. If it could be guaranteed that 'source' were always aligned to 16-byte - // boundary, a faster aligned '_mm_load_ps' instruction could be used. - // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte - // boundary, a faster '_mm_store_ps' instruction could be used. - - return (uint)count; - - /* original routine in C-language. please notice the C-version has differently - organized coefficients though. - double suml1, suml2; - double sumr1, sumr2; - uint i, j; - - for (j = 0; j < count; j += 2) - { - const float *ptr; - const float *pFil; - - suml1 = sumr1 = 0.0; - suml2 = sumr2 = 0.0; - ptr = src; - pFil = filterCoeffs; - for (i = 0; i < lengthLocal; i ++) - { - // unroll loop for efficiency. - - suml1 += ptr[0] * pFil[0] + - ptr[2] * pFil[2] + - ptr[4] * pFil[4] + - ptr[6] * pFil[6]; - - sumr1 += ptr[1] * pFil[1] + - ptr[3] * pFil[3] + - ptr[5] * pFil[5] + - ptr[7] * pFil[7]; - - suml2 += ptr[8] * pFil[0] + - ptr[10] * pFil[2] + - ptr[12] * pFil[4] + - ptr[14] * pFil[6]; - - sumr2 += ptr[9] * pFil[1] + - ptr[11] * pFil[3] + - ptr[13] * pFil[5] + - ptr[15] * pFil[7]; - - ptr += 16; - pFil += 8; - } - dest[0] = (float)suml1; - dest[1] = (float)sumr1; - dest[2] = (float)suml2; - dest[3] = (float)sumr2; - - src += 4; - dest += 4; - } - */ - - - /* Similar routine in assembly, again obsoleted due to maintainability - _asm - { - // Very important note: data in 'src' _must_ be aligned to - // 16-byte boundary! - mov edx, count - mov ebx, dword ptr src - mov eax, dword ptr dest - shr edx, 1 - - loop1: - // "outer loop" : during each round 2*2 output samples are calculated - - // give prefetch hints to CPU of what data are to be needed soonish - prefetcht0 [ebx] - prefetcht0 [filterCoeffsLocal] - - mov esi, ebx - mov edi, filterCoeffsLocal - xorps xmm0, xmm0 - xorps xmm1, xmm1 - mov ecx, lengthLocal - - loop2: - // "inner loop" : during each round eight FIR filter taps are evaluated for 2*2 samples - prefetcht0 [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish - prefetcht0 [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish - - movups xmm2, [esi] // possibly unaligned load - movups xmm3, [esi + 8] // possibly unaligned load - mulps xmm2, [edi] - mulps xmm3, [edi] - addps xmm0, xmm2 - addps xmm1, xmm3 - - movups xmm4, [esi + 16] // possibly unaligned load - movups xmm5, [esi + 24] // possibly unaligned load - mulps xmm4, [edi + 16] - mulps xmm5, [edi + 16] - addps xmm0, xmm4 - addps xmm1, xmm5 - - prefetcht0 [esi + 64] // give a prefetch hint to CPU what data are to be needed soonish - prefetcht0 [edi + 64] // give a prefetch hint to CPU what data are to be needed soonish - - movups xmm6, [esi + 32] // possibly unaligned load - movups xmm7, [esi + 40] // possibly unaligned load - mulps xmm6, [edi + 32] - mulps xmm7, [edi + 32] - addps xmm0, xmm6 - addps xmm1, xmm7 - - movups xmm4, [esi + 48] // possibly unaligned load - movups xmm5, [esi + 56] // possibly unaligned load - mulps xmm4, [edi + 48] - mulps xmm5, [edi + 48] - addps xmm0, xmm4 - addps xmm1, xmm5 - - add esi, 64 - add edi, 64 - dec ecx - jnz loop2 - - // Now xmm0 and xmm1 both have a filtered 2-channel sample each, but we still need - // to sum the two hi- and lo-floats of these registers together. - - movhlps xmm2, xmm0 // xmm2 = xmm2_3 xmm2_2 xmm0_3 xmm0_2 - movlhps xmm2, xmm1 // xmm2 = xmm1_1 xmm1_0 xmm0_3 xmm0_2 - shufps xmm0, xmm1, 0xe4 // xmm0 = xmm1_3 xmm1_2 xmm0_1 xmm0_0 - addps xmm0, xmm2 - - movaps [eax], xmm0 - add ebx, 16 - add eax, 16 - - dec edx - jnz loop1 - } - */ -} - -#endif // ALLOW_SSE +//////////////////////////////////////////////////////////////////////////////// +/// +/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE +/// optimized functions have been gathered into this single source +/// code file, regardless to their class or original source code file, in order +/// to ease porting the library to other compiler and processor platforms. +/// +/// The SSE-optimizations are programmed using SSE compiler intrinsics that +/// are supported both by Microsoft Visual C++ and GCC compilers, so this file +/// should compile with both toolsets. +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support SSE instruction set. The update is +/// available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx +/// +/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and +/// perform a search with keywords "processor pack". +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.2 $ +// +// $Id: sse_optimized.cpp,v 1.2 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" +#include "STTypes.h" + +using namespace soundtouch; + +#ifdef ALLOW_SSE + +// SSE routines available only with float sample type + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of SSE optimized functions of class 'TDStretchSSE' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include + +// Calculates cross correlation of two buffers +double TDStretchSSE::calcCrossCorrStereo(const float *pV1, const float *pV2) const +{ + uint i; + __m128 vSum, *pVec2; + + // Note. It means a major slow-down if the routine needs to tolerate + // unaligned __m128 memory accesses. It's way faster if we can skip + // unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps. + // This can mean up to ~ 10-fold difference (incl. part of which is + // due to skipping every second round for stereo sound though). + // + // Compile-time define ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided + // for choosing if this little cheating is allowed. + +#ifdef ALLOW_NONEXACT_SIMD_OPTIMIZATION + // Little cheating allowed, return valid correlation only for + // aligned locations, meaning every second round for stereo sound. + + #define _MM_LOAD _mm_load_ps + + if (((ulong)pV1) & 15) return -1e50; // skip unaligned locations + +#else + // No cheating allowed, use unaligned load & take the resulting + // performance hit. + #define _MM_LOAD _mm_loadu_ps +#endif + + // ensure overlapLength is divisible by 8 + assert((overlapLength % 8) == 0); + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + // Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not. + pVec2 = (__m128*)pV2; + vSum = _mm_setzero_ps(); + + // Unroll the loop by factor of 4 * 4 operations + for (i = 0; i < overlapLength / 8; i ++) + { + // vSum += pV1[0..3] * pV2[0..3] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1),pVec2[0])); + + // vSum += pV1[4..7] * pV2[4..7] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 4), pVec2[1])); + + // vSum += pV1[8..11] * pV2[8..11] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 8), pVec2[2])); + + // vSum += pV1[12..15] * pV2[12..15] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 12), pVec2[3])); + + pV1 += 16; + pVec2 += 4; + } + + // return value = vSum[0] + vSum[1] + vSum[2] + vSum[3] + float *pvSum = (float*)&vSum; + return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]); + + /* This is approximately corresponding routine in C-language: + double corr; + uint i; + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + corr = 0.0; + for (i = 0; i < overlapLength / 8; i ++) + { + corr += pV1[0] * pV2[0] + + pV1[1] * pV2[1] + + pV1[2] * pV2[2] + + pV1[3] * pV2[3] + + pV1[4] * pV2[4] + + pV1[5] * pV2[5] + + pV1[6] * pV2[6] + + pV1[7] * pV2[7] + + pV1[8] * pV2[8] + + pV1[9] * pV2[9] + + pV1[10] * pV2[10] + + pV1[11] * pV2[11] + + pV1[12] * pV2[12] + + pV1[13] * pV2[13] + + pV1[14] * pV2[14] + + pV1[15] * pV2[15]; + + pV1 += 16; + pV2 += 16; + } + */ + + /* This is corresponding routine in assembler. This may be teeny-weeny bit faster + than intrinsic version, but more difficult to maintain & get compiled on multiple + platforms. + + uint overlapLengthLocal = overlapLength; + float corr; + + _asm + { + // Very important note: data in 'pV2' _must_ be aligned to + // 16-byte boundary! + + // give prefetch hints to CPU of what data are to be needed soonish + // give more aggressive hints on pV1 as that changes while pV2 stays + // same between runs + prefetcht0 [pV1] + prefetcht0 [pV2] + prefetcht0 [pV1 + 32] + + mov eax, dword ptr pV1 + mov ebx, dword ptr pV2 + + xorps xmm0, xmm0 + + mov ecx, overlapLengthLocal + shr ecx, 3 // div by eight + + loop1: + prefetcht0 [eax + 64] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [ebx + 32] // give a prefetch hint to CPU what data are to be needed soonish + movups xmm1, [eax] + mulps xmm1, [ebx] + addps xmm0, xmm1 + + movups xmm2, [eax + 16] + mulps xmm2, [ebx + 16] + addps xmm0, xmm2 + + prefetcht0 [eax + 96] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish + + movups xmm3, [eax + 32] + mulps xmm3, [ebx + 32] + addps xmm0, xmm3 + + movups xmm4, [eax + 48] + mulps xmm4, [ebx + 48] + addps xmm0, xmm4 + + add eax, 64 + add ebx, 64 + + dec ecx + jnz loop1 + + // add the four floats of xmm0 together and return the result. + + movhlps xmm1, xmm0 // move 3 & 4 of xmm0 to 1 & 2 of xmm1 + addps xmm1, xmm0 + movaps xmm2, xmm1 + shufps xmm2, xmm2, 0x01 // move 2 of xmm2 as 1 of xmm2 + addss xmm2, xmm1 + movss corr, xmm2 + } + + return (double)corr; + */ +} + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of SSE optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + +FIRFilterSSE::FIRFilterSSE() : FIRFilter() +{ + filterCoeffsUnalign = NULL; +} + + +FIRFilterSSE::~FIRFilterSSE() +{ + delete[] filterCoeffsUnalign; +} + + +// (overloaded) Calculates filter coefficients for SSE routine +void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + float fDivider; + + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Scale the filter coefficients so that it won't be necessary to scale the filtering result + // also rearrange coefficients suitably for 3DNow! + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new float[2 * newLength + 4]; + filterCoeffsAlign = (float *)(((unsigned long)filterCoeffsUnalign + 15) & -16); + + fDivider = (float)resultDivider; + + // rearrange the filter coefficients for mmx routines + for (i = 0; i < newLength; i ++) + { + filterCoeffsAlign[2 * i + 0] = + filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; + } +} + + + +// SSE-optimized version of the filter routine for stereo sound +uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const +{ + int count = (numSamples - length) & -2; + int j; + + assert(count % 2 == 0); + + if (count < 2) return 0; + + assert((length % 8) == 0); + assert(((unsigned long)filterCoeffsAlign) % 16 == 0); + + // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2' + for (j = 0; j < count; j += 2) + { + const float *pSrc; + const __m128 *pFil; + __m128 sum1, sum2; + uint i; + + pSrc = source; // source audio data + pFil = (__m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients + // are aligned to 16-byte boundary + sum1 = sum2 = _mm_setzero_ps(); + + for (i = 0; i < length / 8; i ++) + { + // Unroll loop for efficiency & calculate filter for 2*2 stereo samples + // at each pass + + // sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset + // sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset. + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc) , pFil[0])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) , pFil[2])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3])); + + pSrc += 16; + pFil += 4; + } + + // Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need + // to sum the two hi- and lo-floats of these registers together. + + // post-shuffle & add the filtered values and store to dest. + _mm_storeu_ps(dest, _mm_add_ps( + _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2 + _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0 + )); + source += 4; + dest += 4; + } + + // Ideas for further improvement: + // 1. If it could be guaranteed that 'source' were always aligned to 16-byte + // boundary, a faster aligned '_mm_load_ps' instruction could be used. + // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte + // boundary, a faster '_mm_store_ps' instruction could be used. + + return (uint)count; + + /* original routine in C-language. please notice the C-version has differently + organized coefficients though. + double suml1, suml2; + double sumr1, sumr2; + uint i, j; + + for (j = 0; j < count; j += 2) + { + const float *ptr; + const float *pFil; + + suml1 = sumr1 = 0.0; + suml2 = sumr2 = 0.0; + ptr = src; + pFil = filterCoeffs; + for (i = 0; i < lengthLocal; i ++) + { + // unroll loop for efficiency. + + suml1 += ptr[0] * pFil[0] + + ptr[2] * pFil[2] + + ptr[4] * pFil[4] + + ptr[6] * pFil[6]; + + sumr1 += ptr[1] * pFil[1] + + ptr[3] * pFil[3] + + ptr[5] * pFil[5] + + ptr[7] * pFil[7]; + + suml2 += ptr[8] * pFil[0] + + ptr[10] * pFil[2] + + ptr[12] * pFil[4] + + ptr[14] * pFil[6]; + + sumr2 += ptr[9] * pFil[1] + + ptr[11] * pFil[3] + + ptr[13] * pFil[5] + + ptr[15] * pFil[7]; + + ptr += 16; + pFil += 8; + } + dest[0] = (float)suml1; + dest[1] = (float)sumr1; + dest[2] = (float)suml2; + dest[3] = (float)sumr2; + + src += 4; + dest += 4; + } + */ + + + /* Similar routine in assembly, again obsoleted due to maintainability + _asm + { + // Very important note: data in 'src' _must_ be aligned to + // 16-byte boundary! + mov edx, count + mov ebx, dword ptr src + mov eax, dword ptr dest + shr edx, 1 + + loop1: + // "outer loop" : during each round 2*2 output samples are calculated + + // give prefetch hints to CPU of what data are to be needed soonish + prefetcht0 [ebx] + prefetcht0 [filterCoeffsLocal] + + mov esi, ebx + mov edi, filterCoeffsLocal + xorps xmm0, xmm0 + xorps xmm1, xmm1 + mov ecx, lengthLocal + + loop2: + // "inner loop" : during each round eight FIR filter taps are evaluated for 2*2 samples + prefetcht0 [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish + + movups xmm2, [esi] // possibly unaligned load + movups xmm3, [esi + 8] // possibly unaligned load + mulps xmm2, [edi] + mulps xmm3, [edi] + addps xmm0, xmm2 + addps xmm1, xmm3 + + movups xmm4, [esi + 16] // possibly unaligned load + movups xmm5, [esi + 24] // possibly unaligned load + mulps xmm4, [edi + 16] + mulps xmm5, [edi + 16] + addps xmm0, xmm4 + addps xmm1, xmm5 + + prefetcht0 [esi + 64] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [edi + 64] // give a prefetch hint to CPU what data are to be needed soonish + + movups xmm6, [esi + 32] // possibly unaligned load + movups xmm7, [esi + 40] // possibly unaligned load + mulps xmm6, [edi + 32] + mulps xmm7, [edi + 32] + addps xmm0, xmm6 + addps xmm1, xmm7 + + movups xmm4, [esi + 48] // possibly unaligned load + movups xmm5, [esi + 56] // possibly unaligned load + mulps xmm4, [edi + 48] + mulps xmm5, [edi + 48] + addps xmm0, xmm4 + addps xmm1, xmm5 + + add esi, 64 + add edi, 64 + dec ecx + jnz loop2 + + // Now xmm0 and xmm1 both have a filtered 2-channel sample each, but we still need + // to sum the two hi- and lo-floats of these registers together. + + movhlps xmm2, xmm0 // xmm2 = xmm2_3 xmm2_2 xmm0_3 xmm0_2 + movlhps xmm2, xmm1 // xmm2 = xmm1_1 xmm1_0 xmm0_3 xmm0_2 + shufps xmm0, xmm1, 0xe4 // xmm0 = xmm1_3 xmm1_2 xmm0_1 xmm0_0 + addps xmm0, xmm2 + + movaps [eax], xmm0 + add ebx, 16 + add eax, 16 + + dec edx + jnz loop1 + } + */ +} + +#endif // ALLOW_SSE diff --git a/plugins/spu2ghz/src/3rdparty/liba52/a52.h b/plugins/spu2ghz/src/3rdparty/liba52/a52.h index 2fc6c83309..9db52ccf83 100644 --- a/plugins/spu2ghz/src/3rdparty/liba52/a52.h +++ b/plugins/spu2ghz/src/3rdparty/liba52/a52.h @@ -1,62 +1,62 @@ -/* - * a52.h - * Copyright (C) 2000-2002 Michel Lespinasse - * Copyright (C) 1999-2000 Aaron Holtzman - * - * This file is part of a52dec, a free ATSC A-52 stream decoder. - * See http://liba52.sourceforge.net/ for updates. - * - * a52dec 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. - * - * a52dec 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 - */ - -#ifndef A52_H -#define A52_H - -#ifndef LIBA52_DOUBLE -typedef float sample_t; -#else -typedef double sample_t; -#endif - -typedef struct a52_state_s a52_state_t; - -#define A52_CHANNEL 0 -#define A52_MONO 1 -#define A52_STEREO 2 -#define A52_3F 3 -#define A52_2F1R 4 -#define A52_3F1R 5 -#define A52_2F2R 6 -#define A52_3F2R 7 -#define A52_CHANNEL1 8 -#define A52_CHANNEL2 9 -#define A52_DOLBY 10 -#define A52_CHANNEL_MASK 15 - -#define A52_LFE 16 -#define A52_ADJUST_LEVEL 32 - -a52_state_t * a52_init (uint32_t mm_accel); -sample_t * a52_samples (a52_state_t * state); -int a52_syncinfo (uint8_t * buf, int * flags, - int * sample_rate, int * bit_rate); -int a52_frame (a52_state_t * state, uint8_t * buf, int * flags, - sample_t * level, sample_t bias); -void a52_dynrng (a52_state_t * state, - sample_t (* call) (sample_t, void *), void * data); -int a52_block (a52_state_t * state); -void a52_free (a52_state_t * state); - -#endif /* A52_H */ +/* + * a52.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 + */ + +#ifndef A52_H +#define A52_H + +#ifndef LIBA52_DOUBLE +typedef float sample_t; +#else +typedef double sample_t; +#endif + +typedef struct a52_state_s a52_state_t; + +#define A52_CHANNEL 0 +#define A52_MONO 1 +#define A52_STEREO 2 +#define A52_3F 3 +#define A52_2F1R 4 +#define A52_3F1R 5 +#define A52_2F2R 6 +#define A52_3F2R 7 +#define A52_CHANNEL1 8 +#define A52_CHANNEL2 9 +#define A52_DOLBY 10 +#define A52_CHANNEL_MASK 15 + +#define A52_LFE 16 +#define A52_ADJUST_LEVEL 32 + +a52_state_t * a52_init (uint32_t mm_accel); +sample_t * a52_samples (a52_state_t * state); +int a52_syncinfo (uint8_t * buf, int * flags, + int * sample_rate, int * bit_rate); +int a52_frame (a52_state_t * state, uint8_t * buf, int * flags, + sample_t * level, sample_t bias); +void a52_dynrng (a52_state_t * state, + sample_t (* call) (sample_t, void *), void * data); +int a52_block (a52_state_t * state); +void a52_free (a52_state_t * state); + +#endif /* A52_H */ diff --git a/plugins/spu2ghz/src/3rdparty/liba52/a52_internal.h b/plugins/spu2ghz/src/3rdparty/liba52/a52_internal.h index bc896cb1ff..834df47a9c 100644 --- a/plugins/spu2ghz/src/3rdparty/liba52/a52_internal.h +++ b/plugins/spu2ghz/src/3rdparty/liba52/a52_internal.h @@ -1,123 +1,123 @@ -/* - * a52_internal.h - * Copyright (C) 2000-2002 Michel Lespinasse - * Copyright (C) 1999-2000 Aaron Holtzman - * - * This file is part of a52dec, a free ATSC A-52 stream decoder. - * See http://liba52.sourceforge.net/ for updates. - * - * a52dec 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. - * - * a52dec 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 - */ - -typedef struct { - uint8_t bai; /* fine SNR offset, fast gain */ - uint8_t deltbae; /* delta bit allocation exists */ - int8_t deltba[50]; /* per-band delta bit allocation */ -} ba_t; - -typedef struct { - uint8_t exp[256]; /* decoded channel exponents */ - int8_t bap[256]; /* derived channel bit allocation */ -} expbap_t; - -struct a52_state_s { - uint8_t fscod; /* sample rate */ - uint8_t halfrate; /* halfrate factor */ - uint8_t acmod; /* coded channels */ - uint8_t lfeon; /* coded lfe channel */ - sample_t clev; /* centre channel mix level */ - sample_t slev; /* surround channels mix level */ - - int output; /* type of output */ - sample_t level; /* output level */ - sample_t bias; /* output bias */ - - int dynrnge; /* apply dynamic range */ - sample_t dynrng; /* dynamic range */ - void * dynrngdata; /* dynamic range callback funtion and data */ - sample_t (* dynrngcall) (sample_t range, void * dynrngdata); - - uint8_t chincpl; /* channel coupled */ - uint8_t phsflginu; /* phase flags in use (stereo only) */ - uint8_t cplstrtmant; /* coupling channel start mantissa */ - uint8_t cplendmant; /* coupling channel end mantissa */ - uint32_t cplbndstrc; /* coupling band structure */ - sample_t cplco[5][18]; /* coupling coordinates */ - - /* derived information */ - uint8_t cplstrtbnd; /* coupling start band (for bit allocation) */ - uint8_t ncplbnd; /* number of coupling bands */ - - uint8_t rematflg; /* stereo rematrixing */ - - uint8_t endmant[5]; /* channel end mantissa */ - - uint16_t bai; /* bit allocation information */ - - uint32_t * buffer_start; - uint16_t lfsr_state; /* dither state */ - uint32_t bits_left; - uint32_t current_word; - - uint8_t csnroffst; /* coarse SNR offset */ - ba_t cplba; /* coupling bit allocation parameters */ - ba_t ba[5]; /* channel bit allocation parameters */ - ba_t lfeba; /* lfe bit allocation parameters */ - - uint8_t cplfleak; /* coupling fast leak init */ - uint8_t cplsleak; /* coupling slow leak init */ - - expbap_t cpl_expbap; - expbap_t fbw_expbap[5]; - expbap_t lfe_expbap; - - sample_t * samples; - int downmixed; -}; - -// [Air]: Added sample_t casts here. -// Improves SSE2 optimization efficiency under Visual Studio 2008 - -#define LEVEL_PLUS6DB ((sample_t)2.0) -#define LEVEL_PLUS3DB ((sample_t)1.4142135623730951) -#define LEVEL_3DB ((sample_t)0.7071067811865476) -#define LEVEL_45DB ((sample_t)0.5946035575013605) -#define LEVEL_6DB ((sample_t)0.5) - -#define EXP_REUSE (0) -#define EXP_D15 (1) -#define EXP_D25 (2) -#define EXP_D45 (3) - -#define DELTA_BIT_REUSE (0) -#define DELTA_BIT_NEW (1) -#define DELTA_BIT_NONE (2) -#define DELTA_BIT_RESERVED (3) - -void a52_bit_allocate (a52_state_t * state, ba_t * ba, int bndstart, - int start, int end, int fastleak, int slowleak, - expbap_t * expbap); - -int a52_downmix_init (int input, int flags, sample_t * level, - sample_t clev, sample_t slev); -int a52_downmix_coeff (sample_t * coeff, int acmod, int output, sample_t level, - sample_t clev, sample_t slev); -void a52_downmix (sample_t * samples, int acmod, int output, sample_t bias, - sample_t clev, sample_t slev); -void a52_upmix (sample_t * samples, int acmod, int output); - -void a52_imdct_init (uint32_t mm_accel); -void a52_imdct_256 (sample_t * data, sample_t * delay, sample_t bias); -void a52_imdct_512 (sample_t * data, sample_t * delay, sample_t bias); +/* + * a52_internal.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 + */ + +typedef struct { + uint8_t bai; /* fine SNR offset, fast gain */ + uint8_t deltbae; /* delta bit allocation exists */ + int8_t deltba[50]; /* per-band delta bit allocation */ +} ba_t; + +typedef struct { + uint8_t exp[256]; /* decoded channel exponents */ + int8_t bap[256]; /* derived channel bit allocation */ +} expbap_t; + +struct a52_state_s { + uint8_t fscod; /* sample rate */ + uint8_t halfrate; /* halfrate factor */ + uint8_t acmod; /* coded channels */ + uint8_t lfeon; /* coded lfe channel */ + sample_t clev; /* centre channel mix level */ + sample_t slev; /* surround channels mix level */ + + int output; /* type of output */ + sample_t level; /* output level */ + sample_t bias; /* output bias */ + + int dynrnge; /* apply dynamic range */ + sample_t dynrng; /* dynamic range */ + void * dynrngdata; /* dynamic range callback funtion and data */ + sample_t (* dynrngcall) (sample_t range, void * dynrngdata); + + uint8_t chincpl; /* channel coupled */ + uint8_t phsflginu; /* phase flags in use (stereo only) */ + uint8_t cplstrtmant; /* coupling channel start mantissa */ + uint8_t cplendmant; /* coupling channel end mantissa */ + uint32_t cplbndstrc; /* coupling band structure */ + sample_t cplco[5][18]; /* coupling coordinates */ + + /* derived information */ + uint8_t cplstrtbnd; /* coupling start band (for bit allocation) */ + uint8_t ncplbnd; /* number of coupling bands */ + + uint8_t rematflg; /* stereo rematrixing */ + + uint8_t endmant[5]; /* channel end mantissa */ + + uint16_t bai; /* bit allocation information */ + + uint32_t * buffer_start; + uint16_t lfsr_state; /* dither state */ + uint32_t bits_left; + uint32_t current_word; + + uint8_t csnroffst; /* coarse SNR offset */ + ba_t cplba; /* coupling bit allocation parameters */ + ba_t ba[5]; /* channel bit allocation parameters */ + ba_t lfeba; /* lfe bit allocation parameters */ + + uint8_t cplfleak; /* coupling fast leak init */ + uint8_t cplsleak; /* coupling slow leak init */ + + expbap_t cpl_expbap; + expbap_t fbw_expbap[5]; + expbap_t lfe_expbap; + + sample_t * samples; + int downmixed; +}; + +// [Air]: Added sample_t casts here. +// Improves SSE2 optimization efficiency under Visual Studio 2008 + +#define LEVEL_PLUS6DB ((sample_t)2.0) +#define LEVEL_PLUS3DB ((sample_t)1.4142135623730951) +#define LEVEL_3DB ((sample_t)0.7071067811865476) +#define LEVEL_45DB ((sample_t)0.5946035575013605) +#define LEVEL_6DB ((sample_t)0.5) + +#define EXP_REUSE (0) +#define EXP_D15 (1) +#define EXP_D25 (2) +#define EXP_D45 (3) + +#define DELTA_BIT_REUSE (0) +#define DELTA_BIT_NEW (1) +#define DELTA_BIT_NONE (2) +#define DELTA_BIT_RESERVED (3) + +void a52_bit_allocate (a52_state_t * state, ba_t * ba, int bndstart, + int start, int end, int fastleak, int slowleak, + expbap_t * expbap); + +int a52_downmix_init (int input, int flags, sample_t * level, + sample_t clev, sample_t slev); +int a52_downmix_coeff (sample_t * coeff, int acmod, int output, sample_t level, + sample_t clev, sample_t slev); +void a52_downmix (sample_t * samples, int acmod, int output, sample_t bias, + sample_t clev, sample_t slev); +void a52_upmix (sample_t * samples, int acmod, int output); + +void a52_imdct_init (uint32_t mm_accel); +void a52_imdct_256 (sample_t * data, sample_t * delay, sample_t bias); +void a52_imdct_512 (sample_t * data, sample_t * delay, sample_t bias); diff --git a/plugins/spu2ghz/src/3rdparty/liba52/attributes.h b/plugins/spu2ghz/src/3rdparty/liba52/attributes.h index 5a9d4c7aae..598f43ded5 100644 --- a/plugins/spu2ghz/src/3rdparty/liba52/attributes.h +++ b/plugins/spu2ghz/src/3rdparty/liba52/attributes.h @@ -1,29 +1,29 @@ -/* - * attributes.h - * Copyright (C) 2000-2002 Michel Lespinasse - * Copyright (C) 1999-2000 Aaron Holtzman - * - * This file is part of a52dec, a free ATSC A-52 stream decoder. - * See http://liba52.sourceforge.net/ for updates. - * - * a52dec 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. - * - * a52dec 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 - */ - -/* use gcc attribs to align critical data structures */ -#ifdef ATTRIBUTE_ALIGNED_MAX -#define ATTR_ALIGN(align) __attribute__ ((__aligned__ ((ATTRIBUTE_ALIGNED_MAX < align) ? ATTRIBUTE_ALIGNED_MAX : align))) -#else -#define ATTR_ALIGN(align) -#endif +/* + * attributes.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 + */ + +/* use gcc attribs to align critical data structures */ +#ifdef ATTRIBUTE_ALIGNED_MAX +#define ATTR_ALIGN(align) __attribute__ ((__aligned__ ((ATTRIBUTE_ALIGNED_MAX < align) ? ATTRIBUTE_ALIGNED_MAX : align))) +#else +#define ATTR_ALIGN(align) +#endif diff --git a/plugins/spu2ghz/src/3rdparty/liba52/bit_allocate.c b/plugins/spu2ghz/src/3rdparty/liba52/bit_allocate.c index 6102b5c16d..954f998cfb 100644 --- a/plugins/spu2ghz/src/3rdparty/liba52/bit_allocate.c +++ b/plugins/spu2ghz/src/3rdparty/liba52/bit_allocate.c @@ -1,265 +1,265 @@ -/* - * bit_allocate.c - * Copyright (C) 2000-2002 Michel Lespinasse - * Copyright (C) 1999-2000 Aaron Holtzman - * - * This file is part of a52dec, a free ATSC A-52 stream decoder. - * See http://liba52.sourceforge.net/ for updates. - * - * a52dec 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. - * - * a52dec 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 "config.h" - -#include "inttypes.h" - -#include "a52.h" -#include "a52_internal.h" - -static int hthtab[3][50] = { - {0x730, 0x730, 0x7c0, 0x800, 0x820, 0x840, 0x850, 0x850, 0x860, 0x860, - 0x860, 0x860, 0x860, 0x870, 0x870, 0x870, 0x880, 0x880, 0x890, 0x890, - 0x8a0, 0x8a0, 0x8b0, 0x8b0, 0x8c0, 0x8c0, 0x8d0, 0x8e0, 0x8f0, 0x900, - 0x910, 0x910, 0x910, 0x910, 0x900, 0x8f0, 0x8c0, 0x870, 0x820, 0x7e0, - 0x7a0, 0x770, 0x760, 0x7a0, 0x7c0, 0x7c0, 0x6e0, 0x400, 0x3c0, 0x3c0}, - {0x710, 0x710, 0x7a0, 0x7f0, 0x820, 0x830, 0x840, 0x850, 0x850, 0x860, - 0x860, 0x860, 0x860, 0x860, 0x870, 0x870, 0x870, 0x880, 0x880, 0x880, - 0x890, 0x890, 0x8a0, 0x8a0, 0x8b0, 0x8b0, 0x8c0, 0x8c0, 0x8e0, 0x8f0, - 0x900, 0x910, 0x910, 0x910, 0x910, 0x900, 0x8e0, 0x8b0, 0x870, 0x820, - 0x7e0, 0x7b0, 0x760, 0x770, 0x7a0, 0x7c0, 0x780, 0x5d0, 0x3c0, 0x3c0}, - {0x680, 0x680, 0x750, 0x7b0, 0x7e0, 0x810, 0x820, 0x830, 0x840, 0x850, - 0x850, 0x850, 0x860, 0x860, 0x860, 0x860, 0x860, 0x860, 0x860, 0x860, - 0x870, 0x870, 0x870, 0x870, 0x880, 0x880, 0x880, 0x890, 0x8a0, 0x8b0, - 0x8c0, 0x8d0, 0x8e0, 0x8f0, 0x900, 0x910, 0x910, 0x910, 0x900, 0x8f0, - 0x8d0, 0x8b0, 0x840, 0x7f0, 0x790, 0x760, 0x7a0, 0x7c0, 0x7b0, 0x720} -}; - -static int8_t baptab[305] = { - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, /* 93 padding elems */ - - 16, 16, 16, 16, 16, 16, 16, 16, 16, 14, 14, 14, 14, 14, 14, 14, - 14, 12, 12, 12, 12, 11, 11, 11, 11, 10, 10, 10, 10, 9, 9, 9, - 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, - 5, 4, 4, -3, -3, 3, 3, 3, -2, -2, -1, -1, -1, -1, -1, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0 /* 148 padding elems */ -}; - -static int bndtab[30] = {21, 22, 23, 24, 25, 26, 27, 28, 31, 34, - 37, 40, 43, 46, 49, 55, 61, 67, 73, 79, - 85, 97, 109, 121, 133, 157, 181, 205, 229, 253}; - -static int8_t latab[256] = { - -64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, -53, - -52, -52, -51, -50, -49, -48, -47, -47, -46, -45, -44, -44, - -43, -42, -41, -41, -40, -39, -38, -38, -37, -36, -36, -35, - -35, -34, -33, -33, -32, -32, -31, -30, -30, -29, -29, -28, - -28, -27, -27, -26, -26, -25, -25, -24, -24, -23, -23, -22, - -22, -21, -21, -21, -20, -20, -19, -19, -19, -18, -18, -18, - -17, -17, -17, -16, -16, -16, -15, -15, -15, -14, -14, -14, - -13, -13, -13, -13, -12, -12, -12, -12, -11, -11, -11, -11, - -10, -10, -10, -10, -10, -9, -9, -9, -9, -9, -8, -8, - -8, -8, -8, -8, -7, -7, -7, -7, -7, -7, -6, -6, - -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, -5, - -5, -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, - -4, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, - -3, -3, -3, -2, -2, -2, -2, -2, -2, -2, -2, -2, - -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0 -}; - -#define UPDATE_LEAK() \ -do { \ - fastleak += fdecay; \ - if (fastleak > psd + fgain) \ - fastleak = psd + fgain; \ - slowleak += sdecay; \ - if (slowleak > psd + sgain) \ - slowleak = psd + sgain; \ -} while (0) - -#define COMPUTE_MASK() \ -do { \ - if (psd > dbknee) \ - mask -= (psd - dbknee) >> 2; \ - if (mask > hth [i >> halfrate]) \ - mask = hth [i >> halfrate]; \ - mask -= snroffset + 128 * deltba[i]; \ - mask = (mask > 0) ? 0 : ((-mask) >> 5); \ - mask -= floor; \ -} while (0) - -void a52_bit_allocate (a52_state_t * state, ba_t * ba, int bndstart, - int start, int end, int fastleak, int slowleak, - expbap_t * expbap) -{ - static int slowgain[4] = {0x540, 0x4d8, 0x478, 0x410}; - static int dbpbtab[4] = {0xc00, 0x500, 0x300, 0x100}; - static int floortab[8] = {0x910, 0x950, 0x990, 0x9d0, - 0xa10, 0xa90, 0xb10, 0x1400}; - - int i, j; - uint8_t * exp; - int8_t * bap; - int fdecay, fgain, sdecay, sgain, dbknee, floor, snroffset; - int psd, mask; - int8_t * deltba; - int * hth; - int halfrate; - - halfrate = state->halfrate; - fdecay = (63 + 20 * ((state->bai >> 7) & 3)) >> halfrate; /* fdcycod */ - fgain = 128 + 128 * (ba->bai & 7); /* fgaincod */ - sdecay = (15 + 2 * (state->bai >> 9)) >> halfrate; /* sdcycod */ - sgain = slowgain[(state->bai >> 5) & 3]; /* sgaincod */ - dbknee = dbpbtab[(state->bai >> 3) & 3]; /* dbpbcod */ - hth = hthtab[state->fscod]; - /* - * if there is no delta bit allocation, make deltba point to an area - * known to contain zeroes. baptab+156 here. - */ - deltba = (ba->deltbae == DELTA_BIT_NONE) ? baptab + 156 : ba->deltba; - floor = floortab[state->bai & 7]; /* floorcod */ - snroffset = 960 - 64 * state->csnroffst - 4 * (ba->bai >> 3) + floor; - floor >>= 5; - - exp = expbap->exp; - bap = expbap->bap; - - i = bndstart; - j = start; - if (start == 0) { /* not the coupling channel */ - int lowcomp; - - lowcomp = 0; - j = end - 1; - do { - if (i < j) { - if (exp[i+1] == exp[i] - 2) - lowcomp = 384; - else if (lowcomp && (exp[i+1] > exp[i])) - lowcomp -= 64; - } - psd = 128 * exp[i]; - mask = psd + fgain + lowcomp; - COMPUTE_MASK (); - bap[i] = (baptab+156)[mask + 4 * exp[i]]; - i++; - } while ((i < 3) || ((i < 7) && (exp[i] > exp[i-1]))); - fastleak = psd + fgain; - slowleak = psd + sgain; - - while (i < 7) { - if (i < j) { - if (exp[i+1] == exp[i] - 2) - lowcomp = 384; - else if (lowcomp && (exp[i+1] > exp[i])) - lowcomp -= 64; - } - psd = 128 * exp[i]; - UPDATE_LEAK (); - mask = ((fastleak + lowcomp < slowleak) ? - fastleak + lowcomp : slowleak); - COMPUTE_MASK (); - bap[i] = (baptab+156)[mask + 4 * exp[i]]; - i++; - } - - if (end == 7) /* lfe channel */ - return; - - do { - if (exp[i+1] == exp[i] - 2) - lowcomp = 320; - else if (lowcomp && (exp[i+1] > exp[i])) - lowcomp -= 64; - psd = 128 * exp[i]; - UPDATE_LEAK (); - mask = ((fastleak + lowcomp < slowleak) ? - fastleak + lowcomp : slowleak); - COMPUTE_MASK (); - bap[i] = (baptab+156)[mask + 4 * exp[i]]; - i++; - } while (i < 20); - - while (lowcomp > 128) { /* two iterations maximum */ - lowcomp -= 128; - psd = 128 * exp[i]; - UPDATE_LEAK (); - mask = ((fastleak + lowcomp < slowleak) ? - fastleak + lowcomp : slowleak); - COMPUTE_MASK (); - bap[i] = (baptab+156)[mask + 4 * exp[i]]; - i++; - } - j = i; - } - - do { - int startband, endband; - - startband = j; - endband = ((bndtab-20)[i] < end) ? (bndtab-20)[i] : end; - psd = 128 * exp[j++]; - while (j < endband) { - int next, delta; - - next = 128 * exp[j++]; - delta = next - psd; - switch (delta >> 9) { - case -6: case -5: case -4: case -3: case -2: - psd = next; - break; - case -1: - psd = next + latab[(-delta) >> 1]; - break; - case 0: - psd += latab[delta >> 1]; - break; - } - } - /* minpsd = -289 */ - UPDATE_LEAK (); - mask = (fastleak < slowleak) ? fastleak : slowleak; - COMPUTE_MASK (); - i++; - j = startband; - do { - /* max(mask+4*exp)=147=-(minpsd+fgain-deltba-snroffset)>>5+4*exp */ - /* min(mask+4*exp)=-156=-(sgain-deltba-snroffset)>>5 */ - bap[j] = (baptab+156)[mask + 4 * exp[j]]; - } while (++j < endband); - } while (j < end); -} +/* + * bit_allocate.c + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 "config.h" + +#include "inttypes.h" + +#include "a52.h" +#include "a52_internal.h" + +static int hthtab[3][50] = { + {0x730, 0x730, 0x7c0, 0x800, 0x820, 0x840, 0x850, 0x850, 0x860, 0x860, + 0x860, 0x860, 0x860, 0x870, 0x870, 0x870, 0x880, 0x880, 0x890, 0x890, + 0x8a0, 0x8a0, 0x8b0, 0x8b0, 0x8c0, 0x8c0, 0x8d0, 0x8e0, 0x8f0, 0x900, + 0x910, 0x910, 0x910, 0x910, 0x900, 0x8f0, 0x8c0, 0x870, 0x820, 0x7e0, + 0x7a0, 0x770, 0x760, 0x7a0, 0x7c0, 0x7c0, 0x6e0, 0x400, 0x3c0, 0x3c0}, + {0x710, 0x710, 0x7a0, 0x7f0, 0x820, 0x830, 0x840, 0x850, 0x850, 0x860, + 0x860, 0x860, 0x860, 0x860, 0x870, 0x870, 0x870, 0x880, 0x880, 0x880, + 0x890, 0x890, 0x8a0, 0x8a0, 0x8b0, 0x8b0, 0x8c0, 0x8c0, 0x8e0, 0x8f0, + 0x900, 0x910, 0x910, 0x910, 0x910, 0x900, 0x8e0, 0x8b0, 0x870, 0x820, + 0x7e0, 0x7b0, 0x760, 0x770, 0x7a0, 0x7c0, 0x780, 0x5d0, 0x3c0, 0x3c0}, + {0x680, 0x680, 0x750, 0x7b0, 0x7e0, 0x810, 0x820, 0x830, 0x840, 0x850, + 0x850, 0x850, 0x860, 0x860, 0x860, 0x860, 0x860, 0x860, 0x860, 0x860, + 0x870, 0x870, 0x870, 0x870, 0x880, 0x880, 0x880, 0x890, 0x8a0, 0x8b0, + 0x8c0, 0x8d0, 0x8e0, 0x8f0, 0x900, 0x910, 0x910, 0x910, 0x900, 0x8f0, + 0x8d0, 0x8b0, 0x840, 0x7f0, 0x790, 0x760, 0x7a0, 0x7c0, 0x7b0, 0x720} +}; + +static int8_t baptab[305] = { + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, /* 93 padding elems */ + + 16, 16, 16, 16, 16, 16, 16, 16, 16, 14, 14, 14, 14, 14, 14, 14, + 14, 12, 12, 12, 12, 11, 11, 11, 11, 10, 10, 10, 10, 9, 9, 9, + 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, + 5, 4, 4, -3, -3, 3, 3, 3, -2, -2, -1, -1, -1, -1, -1, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 /* 148 padding elems */ +}; + +static int bndtab[30] = {21, 22, 23, 24, 25, 26, 27, 28, 31, 34, + 37, 40, 43, 46, 49, 55, 61, 67, 73, 79, + 85, 97, 109, 121, 133, 157, 181, 205, 229, 253}; + +static int8_t latab[256] = { + -64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, -53, + -52, -52, -51, -50, -49, -48, -47, -47, -46, -45, -44, -44, + -43, -42, -41, -41, -40, -39, -38, -38, -37, -36, -36, -35, + -35, -34, -33, -33, -32, -32, -31, -30, -30, -29, -29, -28, + -28, -27, -27, -26, -26, -25, -25, -24, -24, -23, -23, -22, + -22, -21, -21, -21, -20, -20, -19, -19, -19, -18, -18, -18, + -17, -17, -17, -16, -16, -16, -15, -15, -15, -14, -14, -14, + -13, -13, -13, -13, -12, -12, -12, -12, -11, -11, -11, -11, + -10, -10, -10, -10, -10, -9, -9, -9, -9, -9, -8, -8, + -8, -8, -8, -8, -7, -7, -7, -7, -7, -7, -6, -6, + -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, -5, + -5, -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, + -4, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, + -3, -3, -3, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 +}; + +#define UPDATE_LEAK() \ +do { \ + fastleak += fdecay; \ + if (fastleak > psd + fgain) \ + fastleak = psd + fgain; \ + slowleak += sdecay; \ + if (slowleak > psd + sgain) \ + slowleak = psd + sgain; \ +} while (0) + +#define COMPUTE_MASK() \ +do { \ + if (psd > dbknee) \ + mask -= (psd - dbknee) >> 2; \ + if (mask > hth [i >> halfrate]) \ + mask = hth [i >> halfrate]; \ + mask -= snroffset + 128 * deltba[i]; \ + mask = (mask > 0) ? 0 : ((-mask) >> 5); \ + mask -= floor; \ +} while (0) + +void a52_bit_allocate (a52_state_t * state, ba_t * ba, int bndstart, + int start, int end, int fastleak, int slowleak, + expbap_t * expbap) +{ + static int slowgain[4] = {0x540, 0x4d8, 0x478, 0x410}; + static int dbpbtab[4] = {0xc00, 0x500, 0x300, 0x100}; + static int floortab[8] = {0x910, 0x950, 0x990, 0x9d0, + 0xa10, 0xa90, 0xb10, 0x1400}; + + int i, j; + uint8_t * exp; + int8_t * bap; + int fdecay, fgain, sdecay, sgain, dbknee, floor, snroffset; + int psd, mask; + int8_t * deltba; + int * hth; + int halfrate; + + halfrate = state->halfrate; + fdecay = (63 + 20 * ((state->bai >> 7) & 3)) >> halfrate; /* fdcycod */ + fgain = 128 + 128 * (ba->bai & 7); /* fgaincod */ + sdecay = (15 + 2 * (state->bai >> 9)) >> halfrate; /* sdcycod */ + sgain = slowgain[(state->bai >> 5) & 3]; /* sgaincod */ + dbknee = dbpbtab[(state->bai >> 3) & 3]; /* dbpbcod */ + hth = hthtab[state->fscod]; + /* + * if there is no delta bit allocation, make deltba point to an area + * known to contain zeroes. baptab+156 here. + */ + deltba = (ba->deltbae == DELTA_BIT_NONE) ? baptab + 156 : ba->deltba; + floor = floortab[state->bai & 7]; /* floorcod */ + snroffset = 960 - 64 * state->csnroffst - 4 * (ba->bai >> 3) + floor; + floor >>= 5; + + exp = expbap->exp; + bap = expbap->bap; + + i = bndstart; + j = start; + if (start == 0) { /* not the coupling channel */ + int lowcomp; + + lowcomp = 0; + j = end - 1; + do { + if (i < j) { + if (exp[i+1] == exp[i] - 2) + lowcomp = 384; + else if (lowcomp && (exp[i+1] > exp[i])) + lowcomp -= 64; + } + psd = 128 * exp[i]; + mask = psd + fgain + lowcomp; + COMPUTE_MASK (); + bap[i] = (baptab+156)[mask + 4 * exp[i]]; + i++; + } while ((i < 3) || ((i < 7) && (exp[i] > exp[i-1]))); + fastleak = psd + fgain; + slowleak = psd + sgain; + + while (i < 7) { + if (i < j) { + if (exp[i+1] == exp[i] - 2) + lowcomp = 384; + else if (lowcomp && (exp[i+1] > exp[i])) + lowcomp -= 64; + } + psd = 128 * exp[i]; + UPDATE_LEAK (); + mask = ((fastleak + lowcomp < slowleak) ? + fastleak + lowcomp : slowleak); + COMPUTE_MASK (); + bap[i] = (baptab+156)[mask + 4 * exp[i]]; + i++; + } + + if (end == 7) /* lfe channel */ + return; + + do { + if (exp[i+1] == exp[i] - 2) + lowcomp = 320; + else if (lowcomp && (exp[i+1] > exp[i])) + lowcomp -= 64; + psd = 128 * exp[i]; + UPDATE_LEAK (); + mask = ((fastleak + lowcomp < slowleak) ? + fastleak + lowcomp : slowleak); + COMPUTE_MASK (); + bap[i] = (baptab+156)[mask + 4 * exp[i]]; + i++; + } while (i < 20); + + while (lowcomp > 128) { /* two iterations maximum */ + lowcomp -= 128; + psd = 128 * exp[i]; + UPDATE_LEAK (); + mask = ((fastleak + lowcomp < slowleak) ? + fastleak + lowcomp : slowleak); + COMPUTE_MASK (); + bap[i] = (baptab+156)[mask + 4 * exp[i]]; + i++; + } + j = i; + } + + do { + int startband, endband; + + startband = j; + endband = ((bndtab-20)[i] < end) ? (bndtab-20)[i] : end; + psd = 128 * exp[j++]; + while (j < endband) { + int next, delta; + + next = 128 * exp[j++]; + delta = next - psd; + switch (delta >> 9) { + case -6: case -5: case -4: case -3: case -2: + psd = next; + break; + case -1: + psd = next + latab[(-delta) >> 1]; + break; + case 0: + psd += latab[delta >> 1]; + break; + } + } + /* minpsd = -289 */ + UPDATE_LEAK (); + mask = (fastleak < slowleak) ? fastleak : slowleak; + COMPUTE_MASK (); + i++; + j = startband; + do { + /* max(mask+4*exp)=147=-(minpsd+fgain-deltba-snroffset)>>5+4*exp */ + /* min(mask+4*exp)=-156=-(sgain-deltba-snroffset)>>5 */ + bap[j] = (baptab+156)[mask + 4 * exp[j]]; + } while (++j < endband); + } while (j < end); +} diff --git a/plugins/spu2ghz/src/3rdparty/liba52/bitstream.c b/plugins/spu2ghz/src/3rdparty/liba52/bitstream.c index f1bb17369a..013d8e0afc 100644 --- a/plugins/spu2ghz/src/3rdparty/liba52/bitstream.c +++ b/plugins/spu2ghz/src/3rdparty/liba52/bitstream.c @@ -1,95 +1,95 @@ -/* - * bitstream.c - * Copyright (C) 2000-2002 Michel Lespinasse - * Copyright (C) 1999-2000 Aaron Holtzman - * - * This file is part of a52dec, a free ATSC A-52 stream decoder. - * See http://liba52.sourceforge.net/ for updates. - * - * a52dec 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. - * - * a52dec 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 "config.h" - -#include "inttypes.h" - -#include "a52.h" -#include "a52_internal.h" -#include "bitstream.h" - -#define BUFFER_SIZE 4096 - -void a52_bitstream_set_ptr (a52_state_t * state, uint8_t * buf) -{ - int align; - - align = (long)buf & 3; - state->buffer_start = (uint32_t *) (buf - align); - state->bits_left = 0; - bitstream_get (state, align * 8); -} - -static inline void bitstream_fill_current (a52_state_t * state) -{ - uint32_t tmp; - - tmp = *(state->buffer_start++); - state->current_word = swab32 (tmp); -} - -/* - * The fast paths for _get is in the - * bitstream.h header file so it can be inlined. - * - * The "bottom half" of this routine is suffixed _bh - * - * -ah - */ - -uint32_t a52_bitstream_get_bh (a52_state_t * state, uint32_t num_bits) -{ - uint32_t result; - - num_bits -= state->bits_left; - result = ((state->current_word << (32 - state->bits_left)) >> - (32 - state->bits_left)); - - bitstream_fill_current (state); - - if (num_bits != 0) - result = (result << num_bits) | (state->current_word >> (32 - num_bits)); - - state->bits_left = 32 - num_bits; - - return result; -} - -int32_t a52_bitstream_get_bh_2 (a52_state_t * state, uint32_t num_bits) -{ - int32_t result; - - num_bits -= state->bits_left; - result = ((((int32_t)state->current_word) << (32 - state->bits_left)) >> - (32 - state->bits_left)); - - bitstream_fill_current(state); - - if (num_bits != 0) - result = (result << num_bits) | (state->current_word >> (32 - num_bits)); - - state->bits_left = 32 - num_bits; - - return result; -} +/* + * bitstream.c + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 "config.h" + +#include "inttypes.h" + +#include "a52.h" +#include "a52_internal.h" +#include "bitstream.h" + +#define BUFFER_SIZE 4096 + +void a52_bitstream_set_ptr (a52_state_t * state, uint8_t * buf) +{ + int align; + + align = (long)buf & 3; + state->buffer_start = (uint32_t *) (buf - align); + state->bits_left = 0; + bitstream_get (state, align * 8); +} + +static inline void bitstream_fill_current (a52_state_t * state) +{ + uint32_t tmp; + + tmp = *(state->buffer_start++); + state->current_word = swab32 (tmp); +} + +/* + * The fast paths for _get is in the + * bitstream.h header file so it can be inlined. + * + * The "bottom half" of this routine is suffixed _bh + * + * -ah + */ + +uint32_t a52_bitstream_get_bh (a52_state_t * state, uint32_t num_bits) +{ + uint32_t result; + + num_bits -= state->bits_left; + result = ((state->current_word << (32 - state->bits_left)) >> + (32 - state->bits_left)); + + bitstream_fill_current (state); + + if (num_bits != 0) + result = (result << num_bits) | (state->current_word >> (32 - num_bits)); + + state->bits_left = 32 - num_bits; + + return result; +} + +int32_t a52_bitstream_get_bh_2 (a52_state_t * state, uint32_t num_bits) +{ + int32_t result; + + num_bits -= state->bits_left; + result = ((((int32_t)state->current_word) << (32 - state->bits_left)) >> + (32 - state->bits_left)); + + bitstream_fill_current(state); + + if (num_bits != 0) + result = (result << num_bits) | (state->current_word >> (32 - num_bits)); + + state->bits_left = 32 - num_bits; + + return result; +} diff --git a/plugins/spu2ghz/src/3rdparty/liba52/bitstream.h b/plugins/spu2ghz/src/3rdparty/liba52/bitstream.h index aad3683eed..7d7ea7679f 100644 --- a/plugins/spu2ghz/src/3rdparty/liba52/bitstream.h +++ b/plugins/spu2ghz/src/3rdparty/liba52/bitstream.h @@ -1,77 +1,77 @@ -/* - * bitstream.h - * Copyright (C) 2000-2002 Michel Lespinasse - * Copyright (C) 1999-2000 Aaron Holtzman - * - * This file is part of a52dec, a free ATSC A-52 stream decoder. - * See http://liba52.sourceforge.net/ for updates. - * - * a52dec 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. - * - * a52dec 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 - */ - -/* (stolen from the kernel) */ -#ifdef WORDS_BIGENDIAN - -# define swab32(x) (x) - -#else - -# if 0 && defined (__i386__) - -# define swab32(x) __i386_swab32(x) - static inline const uint32_t __i386_swab32(uint32_t x) - { - __asm__("bswap %0" : "=r" (x) : "0" (x)); - return x; - } - -# else - -# define swab32(x)\ -((((uint8_t*)&x)[0] << 24) | (((uint8_t*)&x)[1] << 16) | \ - (((uint8_t*)&x)[2] << 8) | (((uint8_t*)&x)[3])) - -# endif -#endif - -void a52_bitstream_set_ptr (a52_state_t * state, uint8_t * buf); -uint32_t a52_bitstream_get_bh (a52_state_t * state, uint32_t num_bits); -int32_t a52_bitstream_get_bh_2 (a52_state_t * state, uint32_t num_bits); - -static inline uint32_t bitstream_get (a52_state_t * state, uint32_t num_bits) -{ - uint32_t result; - - if (num_bits < state->bits_left) { - result = (state->current_word << (32 - state->bits_left)) >> (32 - num_bits); - state->bits_left -= num_bits; - return result; - } - - return a52_bitstream_get_bh (state, num_bits); -} - -static inline int32_t bitstream_get_2 (a52_state_t * state, uint32_t num_bits) -{ - int32_t result; - - if (num_bits < state->bits_left) { - result = (((int32_t)state->current_word) << (32 - state->bits_left)) >> (32 - num_bits); - state->bits_left -= num_bits; - return result; - } - - return a52_bitstream_get_bh_2 (state, num_bits); -} +/* + * bitstream.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 + */ + +/* (stolen from the kernel) */ +#ifdef WORDS_BIGENDIAN + +# define swab32(x) (x) + +#else + +# if 0 && defined (__i386__) + +# define swab32(x) __i386_swab32(x) + static inline const uint32_t __i386_swab32(uint32_t x) + { + __asm__("bswap %0" : "=r" (x) : "0" (x)); + return x; + } + +# else + +# define swab32(x)\ +((((uint8_t*)&x)[0] << 24) | (((uint8_t*)&x)[1] << 16) | \ + (((uint8_t*)&x)[2] << 8) | (((uint8_t*)&x)[3])) + +# endif +#endif + +void a52_bitstream_set_ptr (a52_state_t * state, uint8_t * buf); +uint32_t a52_bitstream_get_bh (a52_state_t * state, uint32_t num_bits); +int32_t a52_bitstream_get_bh_2 (a52_state_t * state, uint32_t num_bits); + +static inline uint32_t bitstream_get (a52_state_t * state, uint32_t num_bits) +{ + uint32_t result; + + if (num_bits < state->bits_left) { + result = (state->current_word << (32 - state->bits_left)) >> (32 - num_bits); + state->bits_left -= num_bits; + return result; + } + + return a52_bitstream_get_bh (state, num_bits); +} + +static inline int32_t bitstream_get_2 (a52_state_t * state, uint32_t num_bits) +{ + int32_t result; + + if (num_bits < state->bits_left) { + result = (((int32_t)state->current_word) << (32 - state->bits_left)) >> (32 - num_bits); + state->bits_left -= num_bits; + return result; + } + + return a52_bitstream_get_bh_2 (state, num_bits); +} diff --git a/plugins/spu2ghz/src/3rdparty/liba52/config.h b/plugins/spu2ghz/src/3rdparty/liba52/config.h index bf4cf927be..b1b20fe3ca 100644 --- a/plugins/spu2ghz/src/3rdparty/liba52/config.h +++ b/plugins/spu2ghz/src/3rdparty/liba52/config.h @@ -1,124 +1,124 @@ -/* vc++/config.h - manually adapted from include/config.h.in */ - -/* maximum supported data alignment */ -/* #undef ATTRIBUTE_ALIGNED_MAX */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DLFCN_H */ - -/* Define to 1 if you have the `ftime' function. */ -#define HAVE_FTIME 1 - -/* Define to 1 if you have the `gettimeofday' function. */ -/* #undef HAVE_GETTIMEOFDAY */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_INTTYPES_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_IO_H 1 - -/* Define to 1 if you have the `memalign' function. */ -/* #undef HAVE_MEMALIGN */ - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_STDINT_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_STRINGS_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TIMEB_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_TIME_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_UNISTD_H */ - -/* liba52 djbfft support */ -/* #undef LIBA52_DJBFFT */ - -/* a52 sample precision */ -/* #undef LIBA52_DOUBLE */ - -/* libao al support */ -/* #undef LIBAO_AL */ - -/* libao OSS support */ -/* #undef LIBAO_OSS */ - -/* libao solaris support */ -/* #undef LIBAO_SOLARIS */ - -/* libao win support */ -#define LIBAO_WIN - -/* Name of package */ -#define PACKAGE "a52dec" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "" - -/* Define as the return type of signal handlers (`int' or `void'). */ -#define RETSIGTYPE void - -/* The size of a `char', as computed by sizeof. */ -#define SIZEOF_CHAR 1 - -/* The size of a `int', as computed by sizeof. */ -#define SIZEOF_INT 4 - -/* The size of a `short', as computed by sizeof. */ -#define SIZEOF_SHORT 2 - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Version number of package */ -#define VERSION "0.7.4-cvs" - -/* Define to 1 if your processor stores words with the most significant byte - first (like Motorola and SPARC, unlike Intel and VAX). */ -/* #undef WORDS_BIGENDIAN */ - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Define as `__inline' if that's what the C compiler calls it, or to nothing - if it is not supported. */ -#define inline __inline - -/* Define as `__restrict' if that's what the C compiler calls it, or to - nothing if it is not supported. */ -#define restrict /*__restrict*/ - -/* Define to `unsigned' if does not define. */ -/* #undef size_t */ +/* vc++/config.h - manually adapted from include/config.h.in */ + +/* maximum supported data alignment */ +/* #undef ATTRIBUTE_ALIGNED_MAX */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DLFCN_H */ + +/* Define to 1 if you have the `ftime' function. */ +#define HAVE_FTIME 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +/* #undef HAVE_GETTIMEOFDAY */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_INTTYPES_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_IO_H 1 + +/* Define to 1 if you have the `memalign' function. */ +/* #undef HAVE_MEMALIGN */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STDINT_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STRINGS_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIMEB_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_TIME_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_UNISTD_H */ + +/* liba52 djbfft support */ +/* #undef LIBA52_DJBFFT */ + +/* a52 sample precision */ +/* #undef LIBA52_DOUBLE */ + +/* libao al support */ +/* #undef LIBAO_AL */ + +/* libao OSS support */ +/* #undef LIBAO_OSS */ + +/* libao solaris support */ +/* #undef LIBAO_SOLARIS */ + +/* libao win support */ +#define LIBAO_WIN + +/* Name of package */ +#define PACKAGE "a52dec" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "" + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* The size of a `char', as computed by sizeof. */ +#define SIZEOF_CHAR 1 + +/* The size of a `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of a `short', as computed by sizeof. */ +#define SIZEOF_SHORT 2 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "0.7.4-cvs" + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define as `__inline' if that's what the C compiler calls it, or to nothing + if it is not supported. */ +#define inline __inline + +/* Define as `__restrict' if that's what the C compiler calls it, or to + nothing if it is not supported. */ +#define restrict /*__restrict*/ + +/* Define to `unsigned' if does not define. */ +/* #undef size_t */ diff --git a/plugins/spu2ghz/src/3rdparty/liba52/downmix.c b/plugins/spu2ghz/src/3rdparty/liba52/downmix.c index a5a5c7393b..390d546a73 100644 --- a/plugins/spu2ghz/src/3rdparty/liba52/downmix.c +++ b/plugins/spu2ghz/src/3rdparty/liba52/downmix.c @@ -1,655 +1,655 @@ -/* - * downmix.c - * Copyright (C) 2000-2002 Michel Lespinasse - * Copyright (C) 1999-2000 Aaron Holtzman - * - * This file is part of a52dec, a free ATSC A-52 stream decoder. - * See http://liba52.sourceforge.net/ for updates. - * - * a52dec 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. - * - * a52dec 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 - */ -#pragma warning(disable:4244) -#include "config.h" - -#include -#include "inttypes.h" - -#include "a52.h" -#include "a52_internal.h" - -#define CONVERT(acmod,output) (((output) << 3) + (acmod)) - -int a52_downmix_init (int input, int flags, sample_t * level, - sample_t clev, sample_t slev) -{ - static uint8_t table[11][8] = { - {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_STEREO, - A52_STEREO, A52_STEREO, A52_STEREO, A52_STEREO}, - {A52_MONO, A52_MONO, A52_MONO, A52_MONO, - A52_MONO, A52_MONO, A52_MONO, A52_MONO}, - {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_STEREO, - A52_STEREO, A52_STEREO, A52_STEREO, A52_STEREO}, - {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_3F, - A52_STEREO, A52_3F, A52_STEREO, A52_3F}, - {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_STEREO, - A52_2F1R, A52_2F1R, A52_2F1R, A52_2F1R}, - {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_STEREO, - A52_2F1R, A52_3F1R, A52_2F1R, A52_3F1R}, - {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_3F, - A52_2F2R, A52_2F2R, A52_2F2R, A52_2F2R}, - {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_3F, - A52_2F2R, A52_3F2R, A52_2F2R, A52_3F2R}, - {A52_CHANNEL1, A52_MONO, A52_MONO, A52_MONO, - A52_MONO, A52_MONO, A52_MONO, A52_MONO}, - {A52_CHANNEL2, A52_MONO, A52_MONO, A52_MONO, - A52_MONO, A52_MONO, A52_MONO, A52_MONO}, - {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_DOLBY, - A52_DOLBY, A52_DOLBY, A52_DOLBY, A52_DOLBY} - }; - int output; - - output = flags & A52_CHANNEL_MASK; - if (output > A52_DOLBY) - return -1; - - output = table[output][input & 7]; - - if ((output == A52_STEREO) && - ((input == A52_DOLBY) || ((input == A52_3F) && (clev == LEVEL_3DB)))) - output = A52_DOLBY; - - if (flags & A52_ADJUST_LEVEL) - switch (CONVERT (input & 7, output)) { - - case CONVERT (A52_3F, A52_MONO): - *level *= LEVEL_3DB / (1 + clev); - break; - - case CONVERT (A52_STEREO, A52_MONO): - case CONVERT (A52_2F2R, A52_2F1R): - case CONVERT (A52_3F2R, A52_3F1R): - level_3db: - *level *= LEVEL_3DB; - break; - - case CONVERT (A52_3F2R, A52_2F1R): - if (clev < LEVEL_PLUS3DB - 1) - goto level_3db; - /* break thru */ - case CONVERT (A52_3F, A52_STEREO): - case CONVERT (A52_3F1R, A52_2F1R): - case CONVERT (A52_3F1R, A52_2F2R): - case CONVERT (A52_3F2R, A52_2F2R): - *level /= 1 + clev; - break; - - case CONVERT (A52_2F1R, A52_MONO): - *level *= LEVEL_PLUS3DB / (2 + slev); - break; - - case CONVERT (A52_2F1R, A52_STEREO): - case CONVERT (A52_3F1R, A52_3F): - *level /= 1 + slev * LEVEL_3DB; - break; - - case CONVERT (A52_3F1R, A52_MONO): - *level *= LEVEL_3DB / (1 + clev + 0.5 * slev); - break; - - case CONVERT (A52_3F1R, A52_STEREO): - *level /= 1 + clev + slev * LEVEL_3DB; - break; - - case CONVERT (A52_2F2R, A52_MONO): - *level *= LEVEL_3DB / (1 + slev); - break; - - case CONVERT (A52_2F2R, A52_STEREO): - case CONVERT (A52_3F2R, A52_3F): - *level /= 1 + slev; - break; - - case CONVERT (A52_3F2R, A52_MONO): - *level *= LEVEL_3DB / (1 + clev + slev); - break; - - case CONVERT (A52_3F2R, A52_STEREO): - *level /= 1 + clev + slev; - break; - - case CONVERT (A52_MONO, A52_DOLBY): - *level *= LEVEL_PLUS3DB; - break; - - case CONVERT (A52_3F, A52_DOLBY): - case CONVERT (A52_2F1R, A52_DOLBY): - *level *= 1 / (1 + LEVEL_3DB); - break; - - case CONVERT (A52_3F1R, A52_DOLBY): - case CONVERT (A52_2F2R, A52_DOLBY): - *level *= 1 / (1 + 2 * LEVEL_3DB); - break; - - case CONVERT (A52_3F2R, A52_DOLBY): - *level *= 1 / (1 + 3 * LEVEL_3DB); - break; - } - - return output; -} - -int a52_downmix_coeff (sample_t * coeff, int acmod, int output, sample_t level, - sample_t clev, sample_t slev) -{ - switch (CONVERT (acmod, output & A52_CHANNEL_MASK)) { - - case CONVERT (A52_CHANNEL, A52_CHANNEL): - case CONVERT (A52_MONO, A52_MONO): - case CONVERT (A52_STEREO, A52_STEREO): - case CONVERT (A52_3F, A52_3F): - case CONVERT (A52_2F1R, A52_2F1R): - case CONVERT (A52_3F1R, A52_3F1R): - case CONVERT (A52_2F2R, A52_2F2R): - case CONVERT (A52_3F2R, A52_3F2R): - case CONVERT (A52_STEREO, A52_DOLBY): - coeff[0] = coeff[1] = coeff[2] = coeff[3] = coeff[4] = level; - return 0; - - case CONVERT (A52_CHANNEL, A52_MONO): - coeff[0] = coeff[1] = level * LEVEL_6DB; - return 3; - - case CONVERT (A52_STEREO, A52_MONO): - coeff[0] = coeff[1] = level * LEVEL_3DB; - return 3; - - case CONVERT (A52_3F, A52_MONO): - coeff[0] = coeff[2] = level * LEVEL_3DB; - coeff[1] = level * clev * LEVEL_PLUS3DB; - return 7; - - case CONVERT (A52_2F1R, A52_MONO): - coeff[0] = coeff[1] = level * LEVEL_3DB; - coeff[2] = level * slev * LEVEL_3DB; - return 7; - - case CONVERT (A52_2F2R, A52_MONO): - coeff[0] = coeff[1] = level * LEVEL_3DB; - coeff[2] = coeff[3] = level * slev * LEVEL_3DB; - return 15; - - case CONVERT (A52_3F1R, A52_MONO): - coeff[0] = coeff[2] = level * LEVEL_3DB; - coeff[1] = level * clev * LEVEL_PLUS3DB; - coeff[3] = level * slev * LEVEL_3DB; - return 15; - - case CONVERT (A52_3F2R, A52_MONO): - coeff[0] = coeff[2] = level * LEVEL_3DB; - coeff[1] = level * clev * LEVEL_PLUS3DB; - coeff[3] = coeff[4] = level * slev * LEVEL_3DB; - return 31; - - case CONVERT (A52_MONO, A52_DOLBY): - coeff[0] = level * LEVEL_3DB; - return 0; - - case CONVERT (A52_3F, A52_DOLBY): - clev = LEVEL_3DB; - case CONVERT (A52_3F, A52_STEREO): - case CONVERT (A52_3F1R, A52_2F1R): - case CONVERT (A52_3F2R, A52_2F2R): - coeff[0] = coeff[2] = coeff[3] = coeff[4] = level; - coeff[1] = level * clev; - return 7; - - case CONVERT (A52_2F1R, A52_DOLBY): - slev = 1; - case CONVERT (A52_2F1R, A52_STEREO): - coeff[0] = coeff[1] = level; - coeff[2] = level * slev * LEVEL_3DB; - return 7; - - case CONVERT (A52_3F1R, A52_DOLBY): - clev = LEVEL_3DB; - slev = 1; - case CONVERT (A52_3F1R, A52_STEREO): - coeff[0] = coeff[2] = level; - coeff[1] = level * clev; - coeff[3] = level * slev * LEVEL_3DB; - return 15; - - case CONVERT (A52_2F2R, A52_DOLBY): - slev = LEVEL_3DB; - case CONVERT (A52_2F2R, A52_STEREO): - coeff[0] = coeff[1] = level; - coeff[2] = coeff[3] = level * slev; - return 15; - - case CONVERT (A52_3F2R, A52_DOLBY): - clev = LEVEL_3DB; - case CONVERT (A52_3F2R, A52_2F1R): - slev = LEVEL_3DB; - case CONVERT (A52_3F2R, A52_STEREO): - coeff[0] = coeff[2] = level; - coeff[1] = level * clev; - coeff[3] = coeff[4] = level * slev; - return 31; - - case CONVERT (A52_3F1R, A52_3F): - coeff[0] = coeff[1] = coeff[2] = level; - coeff[3] = level * slev * LEVEL_3DB; - return 13; - - case CONVERT (A52_3F2R, A52_3F): - coeff[0] = coeff[1] = coeff[2] = level; - coeff[3] = coeff[4] = level * slev; - return 29; - - case CONVERT (A52_2F2R, A52_2F1R): - coeff[0] = coeff[1] = level; - coeff[2] = coeff[3] = level * LEVEL_3DB; - return 12; - - case CONVERT (A52_3F2R, A52_3F1R): - coeff[0] = coeff[1] = coeff[2] = level; - coeff[3] = coeff[4] = level * LEVEL_3DB; - return 24; - - case CONVERT (A52_2F1R, A52_2F2R): - coeff[0] = coeff[1] = level; - coeff[2] = level * LEVEL_3DB; - return 0; - - case CONVERT (A52_3F1R, A52_2F2R): - coeff[0] = coeff[2] = level; - coeff[1] = level * clev; - coeff[3] = level * LEVEL_3DB; - return 7; - - case CONVERT (A52_3F1R, A52_3F2R): - coeff[0] = coeff[1] = coeff[2] = level; - coeff[3] = level * LEVEL_3DB; - return 0; - - case CONVERT (A52_CHANNEL, A52_CHANNEL1): - coeff[0] = level; - coeff[1] = 0; - return 0; - - case CONVERT (A52_CHANNEL, A52_CHANNEL2): - coeff[0] = 0; - coeff[1] = level; - return 0; - } - - return -1; /* NOTREACHED */ -} - -static void mix2to1 (sample_t * dest, sample_t * src, sample_t bias) -{ - int i; - - for (i = 0; i < 256; i++) - dest[i] += src[i] + bias; -} - -static void mix3to1 (sample_t * samples, sample_t bias) -{ - int i; - - for (i = 0; i < 256; i++) - samples[i] += samples[i + 256] + samples[i + 512] + bias; -} - -static void mix4to1 (sample_t * samples, sample_t bias) -{ - int i; - - for (i = 0; i < 256; i++) - samples[i] += (samples[i + 256] + samples[i + 512] + - samples[i + 768] + bias); -} - -static void mix5to1 (sample_t * samples, sample_t bias) -{ - int i; - - for (i = 0; i < 256; i++) - samples[i] += (samples[i + 256] + samples[i + 512] + - samples[i + 768] + samples[i + 1024] + bias); -} - -static void mix3to2 (sample_t * samples, sample_t bias) -{ - int i; - sample_t common; - - for (i = 0; i < 256; i++) { - common = samples[i + 256] + bias; - samples[i] += common; - samples[i + 256] = samples[i + 512] + common; - } -} - -static void mix21to2 (sample_t * left, sample_t * right, sample_t bias) -{ - int i; - sample_t common; - - for (i = 0; i < 256; i++) { - common = right[i + 256] + bias; - left[i] += common; - right[i] += common; - } -} - -static void mix21toS (sample_t * samples, sample_t bias) -{ - int i; - sample_t surround; - - for (i = 0; i < 256; i++) { - surround = samples[i + 512]; - samples[i] += bias - surround; - samples[i + 256] += bias + surround; - } -} - -static void mix31to2 (sample_t * samples, sample_t bias) -{ - int i; - sample_t common; - - for (i = 0; i < 256; i++) { - common = samples[i + 256] + samples[i + 768] + bias; - samples[i] += common; - samples[i + 256] = samples[i + 512] + common; - } -} - -static void mix31toS (sample_t * samples, sample_t bias) -{ - int i; - sample_t common, surround; - - for (i = 0; i < 256; i++) { - common = samples[i + 256] + bias; - surround = samples[i + 768]; - samples[i] += common - surround; - samples[i + 256] = samples[i + 512] + common + surround; - } -} - -static void mix22toS (sample_t * samples, sample_t bias) -{ - int i; - sample_t surround; - - for (i = 0; i < 256; i++) { - surround = samples[i + 512] + samples[i + 768]; - samples[i] += bias - surround; - samples[i + 256] += bias + surround; - } -} - -static void mix32to2 (sample_t * samples, sample_t bias) -{ - int i; - sample_t common; - - for (i = 0; i < 256; i++) { - common = samples[i + 256] + bias; - samples[i] += common + samples[i + 768]; - samples[i + 256] = common + samples[i + 512] + samples[i + 1024]; - } -} - -static void mix32toS (sample_t * samples, sample_t bias) -{ - int i; - sample_t common, surround; - - for (i = 0; i < 256; i++) { - common = samples[i + 256] + bias; - surround = samples[i + 768] + samples[i + 1024]; - samples[i] += common - surround; - samples[i + 256] = samples[i + 512] + common + surround; - } -} - -static void move2to1 (sample_t * src, sample_t * dest, sample_t bias) -{ - int i; - - for (i = 0; i < 256; i++) - dest[i] = src[i] + src[i + 256] + bias; -} - -static void zero (sample_t * samples) -{ - int i; - - for (i = 0; i < 256; i++) - samples[i] = 0; -} - -void a52_downmix (sample_t * samples, int acmod, int output, sample_t bias, - sample_t clev, sample_t slev) -{ - switch (CONVERT (acmod, output & A52_CHANNEL_MASK)) { - - case CONVERT (A52_CHANNEL, A52_CHANNEL2): - memcpy (samples, samples + 256, 256 * sizeof (sample_t)); - break; - - case CONVERT (A52_CHANNEL, A52_MONO): - case CONVERT (A52_STEREO, A52_MONO): - mix_2to1: - mix2to1 (samples, samples + 256, bias); - break; - - case CONVERT (A52_2F1R, A52_MONO): - if (slev == 0) - goto mix_2to1; - case CONVERT (A52_3F, A52_MONO): - mix_3to1: - mix3to1 (samples, bias); - break; - - case CONVERT (A52_3F1R, A52_MONO): - if (slev == 0) - goto mix_3to1; - case CONVERT (A52_2F2R, A52_MONO): - if (slev == 0) - goto mix_2to1; - mix4to1 (samples, bias); - break; - - case CONVERT (A52_3F2R, A52_MONO): - if (slev == 0) - goto mix_3to1; - mix5to1 (samples, bias); - break; - - case CONVERT (A52_MONO, A52_DOLBY): - memcpy (samples + 256, samples, 256 * sizeof (sample_t)); - break; - - case CONVERT (A52_3F, A52_STEREO): - case CONVERT (A52_3F, A52_DOLBY): - mix_3to2: - mix3to2 (samples, bias); - break; - - case CONVERT (A52_2F1R, A52_STEREO): - if (slev == 0) - break; - mix21to2 (samples, samples + 256, bias); - break; - - case CONVERT (A52_2F1R, A52_DOLBY): - mix21toS (samples, bias); - break; - - case CONVERT (A52_3F1R, A52_STEREO): - if (slev == 0) - goto mix_3to2; - mix31to2 (samples, bias); - break; - - case CONVERT (A52_3F1R, A52_DOLBY): - mix31toS (samples, bias); - break; - - case CONVERT (A52_2F2R, A52_STEREO): - if (slev == 0) - break; - mix2to1 (samples, samples + 512, bias); - mix2to1 (samples + 256, samples + 768, bias); - break; - - case CONVERT (A52_2F2R, A52_DOLBY): - mix22toS (samples, bias); - break; - - case CONVERT (A52_3F2R, A52_STEREO): - if (slev == 0) - goto mix_3to2; - mix32to2 (samples, bias); - break; - - case CONVERT (A52_3F2R, A52_DOLBY): - mix32toS (samples, bias); - break; - - case CONVERT (A52_3F1R, A52_3F): - if (slev == 0) - break; - mix21to2 (samples, samples + 512, bias); - break; - - case CONVERT (A52_3F2R, A52_3F): - if (slev == 0) - break; - mix2to1 (samples, samples + 768, bias); - mix2to1 (samples + 512, samples + 1024, bias); - break; - - case CONVERT (A52_3F1R, A52_2F1R): - mix3to2 (samples, bias); - memcpy (samples + 512, samples + 768, 256 * sizeof (sample_t)); - break; - - case CONVERT (A52_2F2R, A52_2F1R): - mix2to1 (samples + 512, samples + 768, bias); - break; - - case CONVERT (A52_3F2R, A52_2F1R): - mix3to2 (samples, bias); - move2to1 (samples + 768, samples + 512, bias); - break; - - case CONVERT (A52_3F2R, A52_3F1R): - mix2to1 (samples + 768, samples + 1024, bias); - break; - - case CONVERT (A52_2F1R, A52_2F2R): - memcpy (samples + 768, samples + 512, 256 * sizeof (sample_t)); - break; - - case CONVERT (A52_3F1R, A52_2F2R): - mix3to2 (samples, bias); - memcpy (samples + 512, samples + 768, 256 * sizeof (sample_t)); - break; - - case CONVERT (A52_3F2R, A52_2F2R): - mix3to2 (samples, bias); - memcpy (samples + 512, samples + 768, 256 * sizeof (sample_t)); - memcpy (samples + 768, samples + 1024, 256 * sizeof (sample_t)); - break; - - case CONVERT (A52_3F1R, A52_3F2R): - memcpy (samples + 1027, samples + 768, 256 * sizeof (sample_t)); - break; - } -} - -void a52_upmix (sample_t * samples, int acmod, int output) -{ - switch (CONVERT (acmod, output & A52_CHANNEL_MASK)) { - - case CONVERT (A52_CHANNEL, A52_CHANNEL2): - memcpy (samples + 256, samples, 256 * sizeof (sample_t)); - break; - - case CONVERT (A52_3F2R, A52_MONO): - zero (samples + 1024); - case CONVERT (A52_3F1R, A52_MONO): - case CONVERT (A52_2F2R, A52_MONO): - zero (samples + 768); - case CONVERT (A52_3F, A52_MONO): - case CONVERT (A52_2F1R, A52_MONO): - zero (samples + 512); - case CONVERT (A52_CHANNEL, A52_MONO): - case CONVERT (A52_STEREO, A52_MONO): - zero (samples + 256); - break; - - case CONVERT (A52_3F2R, A52_STEREO): - case CONVERT (A52_3F2R, A52_DOLBY): - zero (samples + 1024); - case CONVERT (A52_3F1R, A52_STEREO): - case CONVERT (A52_3F1R, A52_DOLBY): - zero (samples + 768); - case CONVERT (A52_3F, A52_STEREO): - case CONVERT (A52_3F, A52_DOLBY): - mix_3to2: - memcpy (samples + 512, samples + 256, 256 * sizeof (sample_t)); - zero (samples + 256); - break; - - case CONVERT (A52_2F2R, A52_STEREO): - case CONVERT (A52_2F2R, A52_DOLBY): - zero (samples + 768); - case CONVERT (A52_2F1R, A52_STEREO): - case CONVERT (A52_2F1R, A52_DOLBY): - zero (samples + 512); - break; - - case CONVERT (A52_3F2R, A52_3F): - zero (samples + 1024); - case CONVERT (A52_3F1R, A52_3F): - case CONVERT (A52_2F2R, A52_2F1R): - zero (samples + 768); - break; - - case CONVERT (A52_3F2R, A52_3F1R): - zero (samples + 1024); - break; - - case CONVERT (A52_3F2R, A52_2F1R): - zero (samples + 1024); - case CONVERT (A52_3F1R, A52_2F1R): - mix_31to21: - memcpy (samples + 768, samples + 512, 256 * sizeof (sample_t)); - goto mix_3to2; - - case CONVERT (A52_3F2R, A52_2F2R): - memcpy (samples + 1024, samples + 768, 256 * sizeof (sample_t)); - goto mix_31to21; - } -} +/* + * downmix.c + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 + */ +#pragma warning(disable:4244) +#include "config.h" + +#include +#include "inttypes.h" + +#include "a52.h" +#include "a52_internal.h" + +#define CONVERT(acmod,output) (((output) << 3) + (acmod)) + +int a52_downmix_init (int input, int flags, sample_t * level, + sample_t clev, sample_t slev) +{ + static uint8_t table[11][8] = { + {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_STEREO, + A52_STEREO, A52_STEREO, A52_STEREO, A52_STEREO}, + {A52_MONO, A52_MONO, A52_MONO, A52_MONO, + A52_MONO, A52_MONO, A52_MONO, A52_MONO}, + {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_STEREO, + A52_STEREO, A52_STEREO, A52_STEREO, A52_STEREO}, + {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_3F, + A52_STEREO, A52_3F, A52_STEREO, A52_3F}, + {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_STEREO, + A52_2F1R, A52_2F1R, A52_2F1R, A52_2F1R}, + {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_STEREO, + A52_2F1R, A52_3F1R, A52_2F1R, A52_3F1R}, + {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_3F, + A52_2F2R, A52_2F2R, A52_2F2R, A52_2F2R}, + {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_3F, + A52_2F2R, A52_3F2R, A52_2F2R, A52_3F2R}, + {A52_CHANNEL1, A52_MONO, A52_MONO, A52_MONO, + A52_MONO, A52_MONO, A52_MONO, A52_MONO}, + {A52_CHANNEL2, A52_MONO, A52_MONO, A52_MONO, + A52_MONO, A52_MONO, A52_MONO, A52_MONO}, + {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_DOLBY, + A52_DOLBY, A52_DOLBY, A52_DOLBY, A52_DOLBY} + }; + int output; + + output = flags & A52_CHANNEL_MASK; + if (output > A52_DOLBY) + return -1; + + output = table[output][input & 7]; + + if ((output == A52_STEREO) && + ((input == A52_DOLBY) || ((input == A52_3F) && (clev == LEVEL_3DB)))) + output = A52_DOLBY; + + if (flags & A52_ADJUST_LEVEL) + switch (CONVERT (input & 7, output)) { + + case CONVERT (A52_3F, A52_MONO): + *level *= LEVEL_3DB / (1 + clev); + break; + + case CONVERT (A52_STEREO, A52_MONO): + case CONVERT (A52_2F2R, A52_2F1R): + case CONVERT (A52_3F2R, A52_3F1R): + level_3db: + *level *= LEVEL_3DB; + break; + + case CONVERT (A52_3F2R, A52_2F1R): + if (clev < LEVEL_PLUS3DB - 1) + goto level_3db; + /* break thru */ + case CONVERT (A52_3F, A52_STEREO): + case CONVERT (A52_3F1R, A52_2F1R): + case CONVERT (A52_3F1R, A52_2F2R): + case CONVERT (A52_3F2R, A52_2F2R): + *level /= 1 + clev; + break; + + case CONVERT (A52_2F1R, A52_MONO): + *level *= LEVEL_PLUS3DB / (2 + slev); + break; + + case CONVERT (A52_2F1R, A52_STEREO): + case CONVERT (A52_3F1R, A52_3F): + *level /= 1 + slev * LEVEL_3DB; + break; + + case CONVERT (A52_3F1R, A52_MONO): + *level *= LEVEL_3DB / (1 + clev + 0.5 * slev); + break; + + case CONVERT (A52_3F1R, A52_STEREO): + *level /= 1 + clev + slev * LEVEL_3DB; + break; + + case CONVERT (A52_2F2R, A52_MONO): + *level *= LEVEL_3DB / (1 + slev); + break; + + case CONVERT (A52_2F2R, A52_STEREO): + case CONVERT (A52_3F2R, A52_3F): + *level /= 1 + slev; + break; + + case CONVERT (A52_3F2R, A52_MONO): + *level *= LEVEL_3DB / (1 + clev + slev); + break; + + case CONVERT (A52_3F2R, A52_STEREO): + *level /= 1 + clev + slev; + break; + + case CONVERT (A52_MONO, A52_DOLBY): + *level *= LEVEL_PLUS3DB; + break; + + case CONVERT (A52_3F, A52_DOLBY): + case CONVERT (A52_2F1R, A52_DOLBY): + *level *= 1 / (1 + LEVEL_3DB); + break; + + case CONVERT (A52_3F1R, A52_DOLBY): + case CONVERT (A52_2F2R, A52_DOLBY): + *level *= 1 / (1 + 2 * LEVEL_3DB); + break; + + case CONVERT (A52_3F2R, A52_DOLBY): + *level *= 1 / (1 + 3 * LEVEL_3DB); + break; + } + + return output; +} + +int a52_downmix_coeff (sample_t * coeff, int acmod, int output, sample_t level, + sample_t clev, sample_t slev) +{ + switch (CONVERT (acmod, output & A52_CHANNEL_MASK)) { + + case CONVERT (A52_CHANNEL, A52_CHANNEL): + case CONVERT (A52_MONO, A52_MONO): + case CONVERT (A52_STEREO, A52_STEREO): + case CONVERT (A52_3F, A52_3F): + case CONVERT (A52_2F1R, A52_2F1R): + case CONVERT (A52_3F1R, A52_3F1R): + case CONVERT (A52_2F2R, A52_2F2R): + case CONVERT (A52_3F2R, A52_3F2R): + case CONVERT (A52_STEREO, A52_DOLBY): + coeff[0] = coeff[1] = coeff[2] = coeff[3] = coeff[4] = level; + return 0; + + case CONVERT (A52_CHANNEL, A52_MONO): + coeff[0] = coeff[1] = level * LEVEL_6DB; + return 3; + + case CONVERT (A52_STEREO, A52_MONO): + coeff[0] = coeff[1] = level * LEVEL_3DB; + return 3; + + case CONVERT (A52_3F, A52_MONO): + coeff[0] = coeff[2] = level * LEVEL_3DB; + coeff[1] = level * clev * LEVEL_PLUS3DB; + return 7; + + case CONVERT (A52_2F1R, A52_MONO): + coeff[0] = coeff[1] = level * LEVEL_3DB; + coeff[2] = level * slev * LEVEL_3DB; + return 7; + + case CONVERT (A52_2F2R, A52_MONO): + coeff[0] = coeff[1] = level * LEVEL_3DB; + coeff[2] = coeff[3] = level * slev * LEVEL_3DB; + return 15; + + case CONVERT (A52_3F1R, A52_MONO): + coeff[0] = coeff[2] = level * LEVEL_3DB; + coeff[1] = level * clev * LEVEL_PLUS3DB; + coeff[3] = level * slev * LEVEL_3DB; + return 15; + + case CONVERT (A52_3F2R, A52_MONO): + coeff[0] = coeff[2] = level * LEVEL_3DB; + coeff[1] = level * clev * LEVEL_PLUS3DB; + coeff[3] = coeff[4] = level * slev * LEVEL_3DB; + return 31; + + case CONVERT (A52_MONO, A52_DOLBY): + coeff[0] = level * LEVEL_3DB; + return 0; + + case CONVERT (A52_3F, A52_DOLBY): + clev = LEVEL_3DB; + case CONVERT (A52_3F, A52_STEREO): + case CONVERT (A52_3F1R, A52_2F1R): + case CONVERT (A52_3F2R, A52_2F2R): + coeff[0] = coeff[2] = coeff[3] = coeff[4] = level; + coeff[1] = level * clev; + return 7; + + case CONVERT (A52_2F1R, A52_DOLBY): + slev = 1; + case CONVERT (A52_2F1R, A52_STEREO): + coeff[0] = coeff[1] = level; + coeff[2] = level * slev * LEVEL_3DB; + return 7; + + case CONVERT (A52_3F1R, A52_DOLBY): + clev = LEVEL_3DB; + slev = 1; + case CONVERT (A52_3F1R, A52_STEREO): + coeff[0] = coeff[2] = level; + coeff[1] = level * clev; + coeff[3] = level * slev * LEVEL_3DB; + return 15; + + case CONVERT (A52_2F2R, A52_DOLBY): + slev = LEVEL_3DB; + case CONVERT (A52_2F2R, A52_STEREO): + coeff[0] = coeff[1] = level; + coeff[2] = coeff[3] = level * slev; + return 15; + + case CONVERT (A52_3F2R, A52_DOLBY): + clev = LEVEL_3DB; + case CONVERT (A52_3F2R, A52_2F1R): + slev = LEVEL_3DB; + case CONVERT (A52_3F2R, A52_STEREO): + coeff[0] = coeff[2] = level; + coeff[1] = level * clev; + coeff[3] = coeff[4] = level * slev; + return 31; + + case CONVERT (A52_3F1R, A52_3F): + coeff[0] = coeff[1] = coeff[2] = level; + coeff[3] = level * slev * LEVEL_3DB; + return 13; + + case CONVERT (A52_3F2R, A52_3F): + coeff[0] = coeff[1] = coeff[2] = level; + coeff[3] = coeff[4] = level * slev; + return 29; + + case CONVERT (A52_2F2R, A52_2F1R): + coeff[0] = coeff[1] = level; + coeff[2] = coeff[3] = level * LEVEL_3DB; + return 12; + + case CONVERT (A52_3F2R, A52_3F1R): + coeff[0] = coeff[1] = coeff[2] = level; + coeff[3] = coeff[4] = level * LEVEL_3DB; + return 24; + + case CONVERT (A52_2F1R, A52_2F2R): + coeff[0] = coeff[1] = level; + coeff[2] = level * LEVEL_3DB; + return 0; + + case CONVERT (A52_3F1R, A52_2F2R): + coeff[0] = coeff[2] = level; + coeff[1] = level * clev; + coeff[3] = level * LEVEL_3DB; + return 7; + + case CONVERT (A52_3F1R, A52_3F2R): + coeff[0] = coeff[1] = coeff[2] = level; + coeff[3] = level * LEVEL_3DB; + return 0; + + case CONVERT (A52_CHANNEL, A52_CHANNEL1): + coeff[0] = level; + coeff[1] = 0; + return 0; + + case CONVERT (A52_CHANNEL, A52_CHANNEL2): + coeff[0] = 0; + coeff[1] = level; + return 0; + } + + return -1; /* NOTREACHED */ +} + +static void mix2to1 (sample_t * dest, sample_t * src, sample_t bias) +{ + int i; + + for (i = 0; i < 256; i++) + dest[i] += src[i] + bias; +} + +static void mix3to1 (sample_t * samples, sample_t bias) +{ + int i; + + for (i = 0; i < 256; i++) + samples[i] += samples[i + 256] + samples[i + 512] + bias; +} + +static void mix4to1 (sample_t * samples, sample_t bias) +{ + int i; + + for (i = 0; i < 256; i++) + samples[i] += (samples[i + 256] + samples[i + 512] + + samples[i + 768] + bias); +} + +static void mix5to1 (sample_t * samples, sample_t bias) +{ + int i; + + for (i = 0; i < 256; i++) + samples[i] += (samples[i + 256] + samples[i + 512] + + samples[i + 768] + samples[i + 1024] + bias); +} + +static void mix3to2 (sample_t * samples, sample_t bias) +{ + int i; + sample_t common; + + for (i = 0; i < 256; i++) { + common = samples[i + 256] + bias; + samples[i] += common; + samples[i + 256] = samples[i + 512] + common; + } +} + +static void mix21to2 (sample_t * left, sample_t * right, sample_t bias) +{ + int i; + sample_t common; + + for (i = 0; i < 256; i++) { + common = right[i + 256] + bias; + left[i] += common; + right[i] += common; + } +} + +static void mix21toS (sample_t * samples, sample_t bias) +{ + int i; + sample_t surround; + + for (i = 0; i < 256; i++) { + surround = samples[i + 512]; + samples[i] += bias - surround; + samples[i + 256] += bias + surround; + } +} + +static void mix31to2 (sample_t * samples, sample_t bias) +{ + int i; + sample_t common; + + for (i = 0; i < 256; i++) { + common = samples[i + 256] + samples[i + 768] + bias; + samples[i] += common; + samples[i + 256] = samples[i + 512] + common; + } +} + +static void mix31toS (sample_t * samples, sample_t bias) +{ + int i; + sample_t common, surround; + + for (i = 0; i < 256; i++) { + common = samples[i + 256] + bias; + surround = samples[i + 768]; + samples[i] += common - surround; + samples[i + 256] = samples[i + 512] + common + surround; + } +} + +static void mix22toS (sample_t * samples, sample_t bias) +{ + int i; + sample_t surround; + + for (i = 0; i < 256; i++) { + surround = samples[i + 512] + samples[i + 768]; + samples[i] += bias - surround; + samples[i + 256] += bias + surround; + } +} + +static void mix32to2 (sample_t * samples, sample_t bias) +{ + int i; + sample_t common; + + for (i = 0; i < 256; i++) { + common = samples[i + 256] + bias; + samples[i] += common + samples[i + 768]; + samples[i + 256] = common + samples[i + 512] + samples[i + 1024]; + } +} + +static void mix32toS (sample_t * samples, sample_t bias) +{ + int i; + sample_t common, surround; + + for (i = 0; i < 256; i++) { + common = samples[i + 256] + bias; + surround = samples[i + 768] + samples[i + 1024]; + samples[i] += common - surround; + samples[i + 256] = samples[i + 512] + common + surround; + } +} + +static void move2to1 (sample_t * src, sample_t * dest, sample_t bias) +{ + int i; + + for (i = 0; i < 256; i++) + dest[i] = src[i] + src[i + 256] + bias; +} + +static void zero (sample_t * samples) +{ + int i; + + for (i = 0; i < 256; i++) + samples[i] = 0; +} + +void a52_downmix (sample_t * samples, int acmod, int output, sample_t bias, + sample_t clev, sample_t slev) +{ + switch (CONVERT (acmod, output & A52_CHANNEL_MASK)) { + + case CONVERT (A52_CHANNEL, A52_CHANNEL2): + memcpy (samples, samples + 256, 256 * sizeof (sample_t)); + break; + + case CONVERT (A52_CHANNEL, A52_MONO): + case CONVERT (A52_STEREO, A52_MONO): + mix_2to1: + mix2to1 (samples, samples + 256, bias); + break; + + case CONVERT (A52_2F1R, A52_MONO): + if (slev == 0) + goto mix_2to1; + case CONVERT (A52_3F, A52_MONO): + mix_3to1: + mix3to1 (samples, bias); + break; + + case CONVERT (A52_3F1R, A52_MONO): + if (slev == 0) + goto mix_3to1; + case CONVERT (A52_2F2R, A52_MONO): + if (slev == 0) + goto mix_2to1; + mix4to1 (samples, bias); + break; + + case CONVERT (A52_3F2R, A52_MONO): + if (slev == 0) + goto mix_3to1; + mix5to1 (samples, bias); + break; + + case CONVERT (A52_MONO, A52_DOLBY): + memcpy (samples + 256, samples, 256 * sizeof (sample_t)); + break; + + case CONVERT (A52_3F, A52_STEREO): + case CONVERT (A52_3F, A52_DOLBY): + mix_3to2: + mix3to2 (samples, bias); + break; + + case CONVERT (A52_2F1R, A52_STEREO): + if (slev == 0) + break; + mix21to2 (samples, samples + 256, bias); + break; + + case CONVERT (A52_2F1R, A52_DOLBY): + mix21toS (samples, bias); + break; + + case CONVERT (A52_3F1R, A52_STEREO): + if (slev == 0) + goto mix_3to2; + mix31to2 (samples, bias); + break; + + case CONVERT (A52_3F1R, A52_DOLBY): + mix31toS (samples, bias); + break; + + case CONVERT (A52_2F2R, A52_STEREO): + if (slev == 0) + break; + mix2to1 (samples, samples + 512, bias); + mix2to1 (samples + 256, samples + 768, bias); + break; + + case CONVERT (A52_2F2R, A52_DOLBY): + mix22toS (samples, bias); + break; + + case CONVERT (A52_3F2R, A52_STEREO): + if (slev == 0) + goto mix_3to2; + mix32to2 (samples, bias); + break; + + case CONVERT (A52_3F2R, A52_DOLBY): + mix32toS (samples, bias); + break; + + case CONVERT (A52_3F1R, A52_3F): + if (slev == 0) + break; + mix21to2 (samples, samples + 512, bias); + break; + + case CONVERT (A52_3F2R, A52_3F): + if (slev == 0) + break; + mix2to1 (samples, samples + 768, bias); + mix2to1 (samples + 512, samples + 1024, bias); + break; + + case CONVERT (A52_3F1R, A52_2F1R): + mix3to2 (samples, bias); + memcpy (samples + 512, samples + 768, 256 * sizeof (sample_t)); + break; + + case CONVERT (A52_2F2R, A52_2F1R): + mix2to1 (samples + 512, samples + 768, bias); + break; + + case CONVERT (A52_3F2R, A52_2F1R): + mix3to2 (samples, bias); + move2to1 (samples + 768, samples + 512, bias); + break; + + case CONVERT (A52_3F2R, A52_3F1R): + mix2to1 (samples + 768, samples + 1024, bias); + break; + + case CONVERT (A52_2F1R, A52_2F2R): + memcpy (samples + 768, samples + 512, 256 * sizeof (sample_t)); + break; + + case CONVERT (A52_3F1R, A52_2F2R): + mix3to2 (samples, bias); + memcpy (samples + 512, samples + 768, 256 * sizeof (sample_t)); + break; + + case CONVERT (A52_3F2R, A52_2F2R): + mix3to2 (samples, bias); + memcpy (samples + 512, samples + 768, 256 * sizeof (sample_t)); + memcpy (samples + 768, samples + 1024, 256 * sizeof (sample_t)); + break; + + case CONVERT (A52_3F1R, A52_3F2R): + memcpy (samples + 1027, samples + 768, 256 * sizeof (sample_t)); + break; + } +} + +void a52_upmix (sample_t * samples, int acmod, int output) +{ + switch (CONVERT (acmod, output & A52_CHANNEL_MASK)) { + + case CONVERT (A52_CHANNEL, A52_CHANNEL2): + memcpy (samples + 256, samples, 256 * sizeof (sample_t)); + break; + + case CONVERT (A52_3F2R, A52_MONO): + zero (samples + 1024); + case CONVERT (A52_3F1R, A52_MONO): + case CONVERT (A52_2F2R, A52_MONO): + zero (samples + 768); + case CONVERT (A52_3F, A52_MONO): + case CONVERT (A52_2F1R, A52_MONO): + zero (samples + 512); + case CONVERT (A52_CHANNEL, A52_MONO): + case CONVERT (A52_STEREO, A52_MONO): + zero (samples + 256); + break; + + case CONVERT (A52_3F2R, A52_STEREO): + case CONVERT (A52_3F2R, A52_DOLBY): + zero (samples + 1024); + case CONVERT (A52_3F1R, A52_STEREO): + case CONVERT (A52_3F1R, A52_DOLBY): + zero (samples + 768); + case CONVERT (A52_3F, A52_STEREO): + case CONVERT (A52_3F, A52_DOLBY): + mix_3to2: + memcpy (samples + 512, samples + 256, 256 * sizeof (sample_t)); + zero (samples + 256); + break; + + case CONVERT (A52_2F2R, A52_STEREO): + case CONVERT (A52_2F2R, A52_DOLBY): + zero (samples + 768); + case CONVERT (A52_2F1R, A52_STEREO): + case CONVERT (A52_2F1R, A52_DOLBY): + zero (samples + 512); + break; + + case CONVERT (A52_3F2R, A52_3F): + zero (samples + 1024); + case CONVERT (A52_3F1R, A52_3F): + case CONVERT (A52_2F2R, A52_2F1R): + zero (samples + 768); + break; + + case CONVERT (A52_3F2R, A52_3F1R): + zero (samples + 1024); + break; + + case CONVERT (A52_3F2R, A52_2F1R): + zero (samples + 1024); + case CONVERT (A52_3F1R, A52_2F1R): + mix_31to21: + memcpy (samples + 768, samples + 512, 256 * sizeof (sample_t)); + goto mix_3to2; + + case CONVERT (A52_3F2R, A52_2F2R): + memcpy (samples + 1024, samples + 768, 256 * sizeof (sample_t)); + goto mix_31to21; + } +} diff --git a/plugins/spu2ghz/src/3rdparty/liba52/imdct.c b/plugins/spu2ghz/src/3rdparty/liba52/imdct.c index 04eb16f33e..4e81e4a099 100644 --- a/plugins/spu2ghz/src/3rdparty/liba52/imdct.c +++ b/plugins/spu2ghz/src/3rdparty/liba52/imdct.c @@ -1,432 +1,432 @@ -/* - * imdct.c - * Copyright (C) 2000-2002 Michel Lespinasse - * Copyright (C) 1999-2000 Aaron Holtzman - * - * The ifft algorithms in this file have been largely inspired by Dan - * Bernstein's work, djbfft, available at http://cr.yp.to/djbfft.html - * - * This file is part of a52dec, a free ATSC A-52 stream decoder. - * See http://liba52.sourceforge.net/ for updates. - * - * a52dec 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. - * - * a52dec 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 - */ -#pragma warning(disable:4244) -#include "config.h" - -#include -#include -#ifdef LIBA52_DJBFFT -#include -#endif -#ifndef M_PI -#define M_PI 3.1415926535897932384626433832795029 -#endif -#include "inttypes.h" - -#include "a52.h" -#include "a52_internal.h" -#include "mm_accel.h" - -typedef struct complex_s { - sample_t real; - sample_t imag; -} complex_t; - -static uint8_t fftorder[] = { - 0,128, 64,192, 32,160,224, 96, 16,144, 80,208,240,112, 48,176, - 8,136, 72,200, 40,168,232,104,248,120, 56,184, 24,152,216, 88, - 4,132, 68,196, 36,164,228,100, 20,148, 84,212,244,116, 52,180, - 252,124, 60,188, 28,156,220, 92, 12,140, 76,204,236,108, 44,172, - 2,130, 66,194, 34,162,226, 98, 18,146, 82,210,242,114, 50,178, - 10,138, 74,202, 42,170,234,106,250,122, 58,186, 26,154,218, 90, - 254,126, 62,190, 30,158,222, 94, 14,142, 78,206,238,110, 46,174, - 6,134, 70,198, 38,166,230,102,246,118, 54,182, 22,150,214, 86 -}; - -/* Root values for IFFT */ -static sample_t roots16[3]; -static sample_t roots32[7]; -static sample_t roots64[15]; -static sample_t roots128[31]; - -/* Twiddle factors for IMDCT */ -static complex_t pre1[128]; -static complex_t post1[64]; -static complex_t pre2[64]; -static complex_t post2[32]; - -static sample_t a52_imdct_window[256]; - -static void (* ifft128) (complex_t * buf); -static void (* ifft64) (complex_t * buf); - -static inline void ifft2 (complex_t * buf) -{ - double r, i; - - r = buf[0].real; - i = buf[0].imag; - buf[0].real += buf[1].real; - buf[0].imag += buf[1].imag; - buf[1].real = r - buf[1].real; - buf[1].imag = i - buf[1].imag; -} - -static inline void ifft4 (complex_t * buf) -{ - double tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8; - - tmp1 = buf[0].real + buf[1].real; - tmp2 = buf[3].real + buf[2].real; - tmp3 = buf[0].imag + buf[1].imag; - tmp4 = buf[2].imag + buf[3].imag; - tmp5 = buf[0].real - buf[1].real; - tmp6 = buf[0].imag - buf[1].imag; - tmp7 = buf[2].imag - buf[3].imag; - tmp8 = buf[3].real - buf[2].real; - - buf[0].real = tmp1 + tmp2; - buf[0].imag = tmp3 + tmp4; - buf[2].real = tmp1 - tmp2; - buf[2].imag = tmp3 - tmp4; - buf[1].real = tmp5 + tmp7; - buf[1].imag = tmp6 + tmp8; - buf[3].real = tmp5 - tmp7; - buf[3].imag = tmp6 - tmp8; -} - -/* the basic split-radix ifft butterfly */ - -#define BUTTERFLY(a0,a1,a2,a3,wr,wi) do { \ - tmp5 = a2.real * wr + a2.imag * wi; \ - tmp6 = a2.imag * wr - a2.real * wi; \ - tmp7 = a3.real * wr - a3.imag * wi; \ - tmp8 = a3.imag * wr + a3.real * wi; \ - tmp1 = tmp5 + tmp7; \ - tmp2 = tmp6 + tmp8; \ - tmp3 = tmp6 - tmp8; \ - tmp4 = tmp7 - tmp5; \ - a2.real = a0.real - tmp1; \ - a2.imag = a0.imag - tmp2; \ - a3.real = a1.real - tmp3; \ - a3.imag = a1.imag - tmp4; \ - a0.real += tmp1; \ - a0.imag += tmp2; \ - a1.real += tmp3; \ - a1.imag += tmp4; \ -} while (0) - -/* split-radix ifft butterfly, specialized for wr=1 wi=0 */ - -#define BUTTERFLY_ZERO(a0,a1,a2,a3) do { \ - tmp1 = a2.real + a3.real; \ - tmp2 = a2.imag + a3.imag; \ - tmp3 = a2.imag - a3.imag; \ - tmp4 = a3.real - a2.real; \ - a2.real = a0.real - tmp1; \ - a2.imag = a0.imag - tmp2; \ - a3.real = a1.real - tmp3; \ - a3.imag = a1.imag - tmp4; \ - a0.real += tmp1; \ - a0.imag += tmp2; \ - a1.real += tmp3; \ - a1.imag += tmp4; \ -} while (0) - -/* split-radix ifft butterfly, specialized for wr=wi */ - -#define BUTTERFLY_HALF(a0,a1,a2,a3,w) do { \ - tmp5 = (a2.real + a2.imag) * w; \ - tmp6 = (a2.imag - a2.real) * w; \ - tmp7 = (a3.real - a3.imag) * w; \ - tmp8 = (a3.imag + a3.real) * w; \ - tmp1 = tmp5 + tmp7; \ - tmp2 = tmp6 + tmp8; \ - tmp3 = tmp6 - tmp8; \ - tmp4 = tmp7 - tmp5; \ - a2.real = a0.real - tmp1; \ - a2.imag = a0.imag - tmp2; \ - a3.real = a1.real - tmp3; \ - a3.imag = a1.imag - tmp4; \ - a0.real += tmp1; \ - a0.imag += tmp2; \ - a1.real += tmp3; \ - a1.imag += tmp4; \ -} while (0) - -static inline void ifft8 (complex_t * buf) -{ - double tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8; - - ifft4 (buf); - ifft2 (buf + 4); - ifft2 (buf + 6); - BUTTERFLY_ZERO (buf[0], buf[2], buf[4], buf[6]); - BUTTERFLY_HALF (buf[1], buf[3], buf[5], buf[7], roots16[1]); -} - -static void ifft_pass (complex_t * buf, sample_t * weight, int n) -{ - complex_t * buf1; - complex_t * buf2; - complex_t * buf3; - double tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8; - int i; - - buf++; - buf1 = buf + n; - buf2 = buf + 2 * n; - buf3 = buf + 3 * n; - - BUTTERFLY_ZERO (buf[-1], buf1[-1], buf2[-1], buf3[-1]); - - i = n - 1; - - do { - BUTTERFLY (buf[0], buf1[0], buf2[0], buf3[0], weight[n], weight[2*i]); - buf++; - buf1++; - buf2++; - buf3++; - weight++; - } while (--i); -} - -static void ifft16 (complex_t * buf) -{ - ifft8 (buf); - ifft4 (buf + 8); - ifft4 (buf + 12); - ifft_pass (buf, roots16 - 4, 4); -} - -static void ifft32 (complex_t * buf) -{ - ifft16 (buf); - ifft8 (buf + 16); - ifft8 (buf + 24); - ifft_pass (buf, roots32 - 8, 8); -} - -static void ifft64_c (complex_t * buf) -{ - ifft32 (buf); - ifft16 (buf + 32); - ifft16 (buf + 48); - ifft_pass (buf, roots64 - 16, 16); -} - -static void ifft128_c (complex_t * buf) -{ - ifft32 (buf); - ifft16 (buf + 32); - ifft16 (buf + 48); - ifft_pass (buf, roots64 - 16, 16); - - ifft32 (buf + 64); - ifft32 (buf + 96); - ifft_pass (buf, roots128 - 32, 32); -} - -void a52_imdct_512 (sample_t * data, sample_t * delay, sample_t bias) -{ - int i, k; - sample_t t_r, t_i, a_r, a_i, b_r, b_i, w_1, w_2; - const sample_t * window = a52_imdct_window; - complex_t buf[128]; - - for (i = 0; i < 128; i++) { - k = fftorder[i]; - t_r = pre1[i].real; - t_i = pre1[i].imag; - - buf[i].real = t_i * data[255-k] + t_r * data[k]; - buf[i].imag = t_r * data[255-k] - t_i * data[k]; - } - - ifft128 (buf); - - /* Post IFFT complex multiply plus IFFT complex conjugate*/ - /* Window and convert to real valued signal */ - for (i = 0; i < 64; i++) { - /* y[n] = z[n] * (xcos1[n] + j * xsin1[n]) ; */ - t_r = post1[i].real; - t_i = post1[i].imag; - - a_r = t_r * buf[i].real + t_i * buf[i].imag; - a_i = t_i * buf[i].real - t_r * buf[i].imag; - b_r = t_i * buf[127-i].real + t_r * buf[127-i].imag; - b_i = t_r * buf[127-i].real - t_i * buf[127-i].imag; - - w_1 = window[2*i]; - w_2 = window[255-2*i]; - data[2*i] = delay[2*i] * w_2 - a_r * w_1 + bias; - data[255-2*i] = delay[2*i] * w_1 + a_r * w_2 + bias; - delay[2*i] = a_i; - - w_1 = window[2*i+1]; - w_2 = window[254-2*i]; - data[2*i+1] = delay[2*i+1] * w_2 + b_r * w_1 + bias; - data[254-2*i] = delay[2*i+1] * w_1 - b_r * w_2 + bias; - delay[2*i+1] = b_i; - } -} - -void a52_imdct_256(sample_t * data, sample_t * delay, sample_t bias) -{ - int i, k; - sample_t t_r, t_i, a_r, a_i, b_r, b_i, c_r, c_i, d_r, d_i, w_1, w_2; - const sample_t * window = a52_imdct_window; - complex_t buf1[64], buf2[64]; - - /* Pre IFFT complex multiply plus IFFT cmplx conjugate */ - for (i = 0; i < 64; i++) { - k = fftorder[i]; - t_r = pre2[i].real; - t_i = pre2[i].imag; - - buf1[i].real = t_i * data[254-k] + t_r * data[k]; - buf1[i].imag = t_r * data[254-k] - t_i * data[k]; - - buf2[i].real = t_i * data[255-k] + t_r * data[k+1]; - buf2[i].imag = t_r * data[255-k] - t_i * data[k+1]; - } - - ifft64 (buf1); - ifft64 (buf2); - - /* Post IFFT complex multiply */ - /* Window and convert to real valued signal */ - for (i = 0; i < 32; i++) { - /* y1[n] = z1[n] * (xcos2[n] + j * xs in2[n]) ; */ - t_r = post2[i].real; - t_i = post2[i].imag; - - a_r = t_r * buf1[i].real + t_i * buf1[i].imag; - a_i = t_i * buf1[i].real - t_r * buf1[i].imag; - b_r = t_i * buf1[63-i].real + t_r * buf1[63-i].imag; - b_i = t_r * buf1[63-i].real - t_i * buf1[63-i].imag; - - c_r = t_r * buf2[i].real + t_i * buf2[i].imag; - c_i = t_i * buf2[i].real - t_r * buf2[i].imag; - d_r = t_i * buf2[63-i].real + t_r * buf2[63-i].imag; - d_i = t_r * buf2[63-i].real - t_i * buf2[63-i].imag; - - w_1 = window[2*i]; - w_2 = window[255-2*i]; - data[2*i] = delay[2*i] * w_2 - a_r * w_1 + bias; - data[255-2*i] = delay[2*i] * w_1 + a_r * w_2 + bias; - delay[2*i] = c_i; - - w_1 = window[128+2*i]; - w_2 = window[127-2*i]; - data[128+2*i] = delay[127-2*i] * w_2 + a_i * w_1 + bias; - data[127-2*i] = delay[127-2*i] * w_1 - a_i * w_2 + bias; - delay[127-2*i] = c_r; - - w_1 = window[2*i+1]; - w_2 = window[254-2*i]; - data[2*i+1] = delay[2*i+1] * w_2 - b_i * w_1 + bias; - data[254-2*i] = delay[2*i+1] * w_1 + b_i * w_2 + bias; - delay[2*i+1] = d_r; - - w_1 = window[129+2*i]; - w_2 = window[126-2*i]; - data[129+2*i] = delay[126-2*i] * w_2 + b_r * w_1 + bias; - data[126-2*i] = delay[126-2*i] * w_1 - b_r * w_2 + bias; - delay[126-2*i] = d_i; - } -} - -static double besselI0 (double x) -{ - double bessel = 1; - int i = 100; - - do - bessel = bessel * x / (i * i) + 1; - while (--i); - return bessel; -} - -void a52_imdct_init (uint32_t mm_accel) -{ - int i, k; - double sum; - - /* compute imdct window - kaiser-bessel derived window, alpha = 5.0 */ - sum = 0; - for (i = 0; i < 256; i++) { - sum += besselI0 (i * (256 - i) * (5 * M_PI / 256) * (5 * M_PI / 256)); - a52_imdct_window[i] = sum; - } - sum++; - for (i = 0; i < 256; i++) - a52_imdct_window[i] = sqrt (a52_imdct_window[i] / sum); - - for (i = 0; i < 3; i++) - roots16[i] = cos ((M_PI / 8) * (i + 1)); - - for (i = 0; i < 7; i++) - roots32[i] = cos ((M_PI / 16) * (i + 1)); - - for (i = 0; i < 15; i++) - roots64[i] = cos ((M_PI / 32) * (i + 1)); - - for (i = 0; i < 31; i++) - roots128[i] = cos ((M_PI / 64) * (i + 1)); - - for (i = 0; i < 64; i++) { - k = fftorder[i] / 2 + 64; - pre1[i].real = cos ((M_PI / 256) * (k - 0.25)); - pre1[i].imag = sin ((M_PI / 256) * (k - 0.25)); - } - - for (i = 64; i < 128; i++) { - k = fftorder[i] / 2 + 64; - pre1[i].real = -cos ((M_PI / 256) * (k - 0.25)); - pre1[i].imag = -sin ((M_PI / 256) * (k - 0.25)); - } - - for (i = 0; i < 64; i++) { - post1[i].real = cos ((M_PI / 256) * (i + 0.5)); - post1[i].imag = sin ((M_PI / 256) * (i + 0.5)); - } - - for (i = 0; i < 64; i++) { - k = fftorder[i] / 4; - pre2[i].real = cos ((M_PI / 128) * (k - 0.25)); - pre2[i].imag = sin ((M_PI / 128) * (k - 0.25)); - } - - for (i = 0; i < 32; i++) { - post2[i].real = cos ((M_PI / 128) * (i + 0.5)); - post2[i].imag = sin ((M_PI / 128) * (i + 0.5)); - } - -#ifdef LIBA52_DJBFFT - if (mm_accel & MM_ACCEL_DJBFFT) { - fprintf (stderr, "Using djbfft for IMDCT transform\n"); - ifft128 = (void (*) (complex_t *)) fftc4_un128; - ifft64 = (void (*) (complex_t *)) fftc4_un64; - } else -#endif - { - fprintf (stderr, "No accelerated IMDCT transform found\n"); - ifft128 = ifft128_c; - ifft64 = ifft64_c; - } -} +/* + * imdct.c + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * The ifft algorithms in this file have been largely inspired by Dan + * Bernstein's work, djbfft, available at http://cr.yp.to/djbfft.html + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 + */ +#pragma warning(disable:4244) +#include "config.h" + +#include +#include +#ifdef LIBA52_DJBFFT +#include +#endif +#ifndef M_PI +#define M_PI 3.1415926535897932384626433832795029 +#endif +#include "inttypes.h" + +#include "a52.h" +#include "a52_internal.h" +#include "mm_accel.h" + +typedef struct complex_s { + sample_t real; + sample_t imag; +} complex_t; + +static uint8_t fftorder[] = { + 0,128, 64,192, 32,160,224, 96, 16,144, 80,208,240,112, 48,176, + 8,136, 72,200, 40,168,232,104,248,120, 56,184, 24,152,216, 88, + 4,132, 68,196, 36,164,228,100, 20,148, 84,212,244,116, 52,180, + 252,124, 60,188, 28,156,220, 92, 12,140, 76,204,236,108, 44,172, + 2,130, 66,194, 34,162,226, 98, 18,146, 82,210,242,114, 50,178, + 10,138, 74,202, 42,170,234,106,250,122, 58,186, 26,154,218, 90, + 254,126, 62,190, 30,158,222, 94, 14,142, 78,206,238,110, 46,174, + 6,134, 70,198, 38,166,230,102,246,118, 54,182, 22,150,214, 86 +}; + +/* Root values for IFFT */ +static sample_t roots16[3]; +static sample_t roots32[7]; +static sample_t roots64[15]; +static sample_t roots128[31]; + +/* Twiddle factors for IMDCT */ +static complex_t pre1[128]; +static complex_t post1[64]; +static complex_t pre2[64]; +static complex_t post2[32]; + +static sample_t a52_imdct_window[256]; + +static void (* ifft128) (complex_t * buf); +static void (* ifft64) (complex_t * buf); + +static inline void ifft2 (complex_t * buf) +{ + double r, i; + + r = buf[0].real; + i = buf[0].imag; + buf[0].real += buf[1].real; + buf[0].imag += buf[1].imag; + buf[1].real = r - buf[1].real; + buf[1].imag = i - buf[1].imag; +} + +static inline void ifft4 (complex_t * buf) +{ + double tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8; + + tmp1 = buf[0].real + buf[1].real; + tmp2 = buf[3].real + buf[2].real; + tmp3 = buf[0].imag + buf[1].imag; + tmp4 = buf[2].imag + buf[3].imag; + tmp5 = buf[0].real - buf[1].real; + tmp6 = buf[0].imag - buf[1].imag; + tmp7 = buf[2].imag - buf[3].imag; + tmp8 = buf[3].real - buf[2].real; + + buf[0].real = tmp1 + tmp2; + buf[0].imag = tmp3 + tmp4; + buf[2].real = tmp1 - tmp2; + buf[2].imag = tmp3 - tmp4; + buf[1].real = tmp5 + tmp7; + buf[1].imag = tmp6 + tmp8; + buf[3].real = tmp5 - tmp7; + buf[3].imag = tmp6 - tmp8; +} + +/* the basic split-radix ifft butterfly */ + +#define BUTTERFLY(a0,a1,a2,a3,wr,wi) do { \ + tmp5 = a2.real * wr + a2.imag * wi; \ + tmp6 = a2.imag * wr - a2.real * wi; \ + tmp7 = a3.real * wr - a3.imag * wi; \ + tmp8 = a3.imag * wr + a3.real * wi; \ + tmp1 = tmp5 + tmp7; \ + tmp2 = tmp6 + tmp8; \ + tmp3 = tmp6 - tmp8; \ + tmp4 = tmp7 - tmp5; \ + a2.real = a0.real - tmp1; \ + a2.imag = a0.imag - tmp2; \ + a3.real = a1.real - tmp3; \ + a3.imag = a1.imag - tmp4; \ + a0.real += tmp1; \ + a0.imag += tmp2; \ + a1.real += tmp3; \ + a1.imag += tmp4; \ +} while (0) + +/* split-radix ifft butterfly, specialized for wr=1 wi=0 */ + +#define BUTTERFLY_ZERO(a0,a1,a2,a3) do { \ + tmp1 = a2.real + a3.real; \ + tmp2 = a2.imag + a3.imag; \ + tmp3 = a2.imag - a3.imag; \ + tmp4 = a3.real - a2.real; \ + a2.real = a0.real - tmp1; \ + a2.imag = a0.imag - tmp2; \ + a3.real = a1.real - tmp3; \ + a3.imag = a1.imag - tmp4; \ + a0.real += tmp1; \ + a0.imag += tmp2; \ + a1.real += tmp3; \ + a1.imag += tmp4; \ +} while (0) + +/* split-radix ifft butterfly, specialized for wr=wi */ + +#define BUTTERFLY_HALF(a0,a1,a2,a3,w) do { \ + tmp5 = (a2.real + a2.imag) * w; \ + tmp6 = (a2.imag - a2.real) * w; \ + tmp7 = (a3.real - a3.imag) * w; \ + tmp8 = (a3.imag + a3.real) * w; \ + tmp1 = tmp5 + tmp7; \ + tmp2 = tmp6 + tmp8; \ + tmp3 = tmp6 - tmp8; \ + tmp4 = tmp7 - tmp5; \ + a2.real = a0.real - tmp1; \ + a2.imag = a0.imag - tmp2; \ + a3.real = a1.real - tmp3; \ + a3.imag = a1.imag - tmp4; \ + a0.real += tmp1; \ + a0.imag += tmp2; \ + a1.real += tmp3; \ + a1.imag += tmp4; \ +} while (0) + +static inline void ifft8 (complex_t * buf) +{ + double tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8; + + ifft4 (buf); + ifft2 (buf + 4); + ifft2 (buf + 6); + BUTTERFLY_ZERO (buf[0], buf[2], buf[4], buf[6]); + BUTTERFLY_HALF (buf[1], buf[3], buf[5], buf[7], roots16[1]); +} + +static void ifft_pass (complex_t * buf, sample_t * weight, int n) +{ + complex_t * buf1; + complex_t * buf2; + complex_t * buf3; + double tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8; + int i; + + buf++; + buf1 = buf + n; + buf2 = buf + 2 * n; + buf3 = buf + 3 * n; + + BUTTERFLY_ZERO (buf[-1], buf1[-1], buf2[-1], buf3[-1]); + + i = n - 1; + + do { + BUTTERFLY (buf[0], buf1[0], buf2[0], buf3[0], weight[n], weight[2*i]); + buf++; + buf1++; + buf2++; + buf3++; + weight++; + } while (--i); +} + +static void ifft16 (complex_t * buf) +{ + ifft8 (buf); + ifft4 (buf + 8); + ifft4 (buf + 12); + ifft_pass (buf, roots16 - 4, 4); +} + +static void ifft32 (complex_t * buf) +{ + ifft16 (buf); + ifft8 (buf + 16); + ifft8 (buf + 24); + ifft_pass (buf, roots32 - 8, 8); +} + +static void ifft64_c (complex_t * buf) +{ + ifft32 (buf); + ifft16 (buf + 32); + ifft16 (buf + 48); + ifft_pass (buf, roots64 - 16, 16); +} + +static void ifft128_c (complex_t * buf) +{ + ifft32 (buf); + ifft16 (buf + 32); + ifft16 (buf + 48); + ifft_pass (buf, roots64 - 16, 16); + + ifft32 (buf + 64); + ifft32 (buf + 96); + ifft_pass (buf, roots128 - 32, 32); +} + +void a52_imdct_512 (sample_t * data, sample_t * delay, sample_t bias) +{ + int i, k; + sample_t t_r, t_i, a_r, a_i, b_r, b_i, w_1, w_2; + const sample_t * window = a52_imdct_window; + complex_t buf[128]; + + for (i = 0; i < 128; i++) { + k = fftorder[i]; + t_r = pre1[i].real; + t_i = pre1[i].imag; + + buf[i].real = t_i * data[255-k] + t_r * data[k]; + buf[i].imag = t_r * data[255-k] - t_i * data[k]; + } + + ifft128 (buf); + + /* Post IFFT complex multiply plus IFFT complex conjugate*/ + /* Window and convert to real valued signal */ + for (i = 0; i < 64; i++) { + /* y[n] = z[n] * (xcos1[n] + j * xsin1[n]) ; */ + t_r = post1[i].real; + t_i = post1[i].imag; + + a_r = t_r * buf[i].real + t_i * buf[i].imag; + a_i = t_i * buf[i].real - t_r * buf[i].imag; + b_r = t_i * buf[127-i].real + t_r * buf[127-i].imag; + b_i = t_r * buf[127-i].real - t_i * buf[127-i].imag; + + w_1 = window[2*i]; + w_2 = window[255-2*i]; + data[2*i] = delay[2*i] * w_2 - a_r * w_1 + bias; + data[255-2*i] = delay[2*i] * w_1 + a_r * w_2 + bias; + delay[2*i] = a_i; + + w_1 = window[2*i+1]; + w_2 = window[254-2*i]; + data[2*i+1] = delay[2*i+1] * w_2 + b_r * w_1 + bias; + data[254-2*i] = delay[2*i+1] * w_1 - b_r * w_2 + bias; + delay[2*i+1] = b_i; + } +} + +void a52_imdct_256(sample_t * data, sample_t * delay, sample_t bias) +{ + int i, k; + sample_t t_r, t_i, a_r, a_i, b_r, b_i, c_r, c_i, d_r, d_i, w_1, w_2; + const sample_t * window = a52_imdct_window; + complex_t buf1[64], buf2[64]; + + /* Pre IFFT complex multiply plus IFFT cmplx conjugate */ + for (i = 0; i < 64; i++) { + k = fftorder[i]; + t_r = pre2[i].real; + t_i = pre2[i].imag; + + buf1[i].real = t_i * data[254-k] + t_r * data[k]; + buf1[i].imag = t_r * data[254-k] - t_i * data[k]; + + buf2[i].real = t_i * data[255-k] + t_r * data[k+1]; + buf2[i].imag = t_r * data[255-k] - t_i * data[k+1]; + } + + ifft64 (buf1); + ifft64 (buf2); + + /* Post IFFT complex multiply */ + /* Window and convert to real valued signal */ + for (i = 0; i < 32; i++) { + /* y1[n] = z1[n] * (xcos2[n] + j * xs in2[n]) ; */ + t_r = post2[i].real; + t_i = post2[i].imag; + + a_r = t_r * buf1[i].real + t_i * buf1[i].imag; + a_i = t_i * buf1[i].real - t_r * buf1[i].imag; + b_r = t_i * buf1[63-i].real + t_r * buf1[63-i].imag; + b_i = t_r * buf1[63-i].real - t_i * buf1[63-i].imag; + + c_r = t_r * buf2[i].real + t_i * buf2[i].imag; + c_i = t_i * buf2[i].real - t_r * buf2[i].imag; + d_r = t_i * buf2[63-i].real + t_r * buf2[63-i].imag; + d_i = t_r * buf2[63-i].real - t_i * buf2[63-i].imag; + + w_1 = window[2*i]; + w_2 = window[255-2*i]; + data[2*i] = delay[2*i] * w_2 - a_r * w_1 + bias; + data[255-2*i] = delay[2*i] * w_1 + a_r * w_2 + bias; + delay[2*i] = c_i; + + w_1 = window[128+2*i]; + w_2 = window[127-2*i]; + data[128+2*i] = delay[127-2*i] * w_2 + a_i * w_1 + bias; + data[127-2*i] = delay[127-2*i] * w_1 - a_i * w_2 + bias; + delay[127-2*i] = c_r; + + w_1 = window[2*i+1]; + w_2 = window[254-2*i]; + data[2*i+1] = delay[2*i+1] * w_2 - b_i * w_1 + bias; + data[254-2*i] = delay[2*i+1] * w_1 + b_i * w_2 + bias; + delay[2*i+1] = d_r; + + w_1 = window[129+2*i]; + w_2 = window[126-2*i]; + data[129+2*i] = delay[126-2*i] * w_2 + b_r * w_1 + bias; + data[126-2*i] = delay[126-2*i] * w_1 - b_r * w_2 + bias; + delay[126-2*i] = d_i; + } +} + +static double besselI0 (double x) +{ + double bessel = 1; + int i = 100; + + do + bessel = bessel * x / (i * i) + 1; + while (--i); + return bessel; +} + +void a52_imdct_init (uint32_t mm_accel) +{ + int i, k; + double sum; + + /* compute imdct window - kaiser-bessel derived window, alpha = 5.0 */ + sum = 0; + for (i = 0; i < 256; i++) { + sum += besselI0 (i * (256 - i) * (5 * M_PI / 256) * (5 * M_PI / 256)); + a52_imdct_window[i] = sum; + } + sum++; + for (i = 0; i < 256; i++) + a52_imdct_window[i] = sqrt (a52_imdct_window[i] / sum); + + for (i = 0; i < 3; i++) + roots16[i] = cos ((M_PI / 8) * (i + 1)); + + for (i = 0; i < 7; i++) + roots32[i] = cos ((M_PI / 16) * (i + 1)); + + for (i = 0; i < 15; i++) + roots64[i] = cos ((M_PI / 32) * (i + 1)); + + for (i = 0; i < 31; i++) + roots128[i] = cos ((M_PI / 64) * (i + 1)); + + for (i = 0; i < 64; i++) { + k = fftorder[i] / 2 + 64; + pre1[i].real = cos ((M_PI / 256) * (k - 0.25)); + pre1[i].imag = sin ((M_PI / 256) * (k - 0.25)); + } + + for (i = 64; i < 128; i++) { + k = fftorder[i] / 2 + 64; + pre1[i].real = -cos ((M_PI / 256) * (k - 0.25)); + pre1[i].imag = -sin ((M_PI / 256) * (k - 0.25)); + } + + for (i = 0; i < 64; i++) { + post1[i].real = cos ((M_PI / 256) * (i + 0.5)); + post1[i].imag = sin ((M_PI / 256) * (i + 0.5)); + } + + for (i = 0; i < 64; i++) { + k = fftorder[i] / 4; + pre2[i].real = cos ((M_PI / 128) * (k - 0.25)); + pre2[i].imag = sin ((M_PI / 128) * (k - 0.25)); + } + + for (i = 0; i < 32; i++) { + post2[i].real = cos ((M_PI / 128) * (i + 0.5)); + post2[i].imag = sin ((M_PI / 128) * (i + 0.5)); + } + +#ifdef LIBA52_DJBFFT + if (mm_accel & MM_ACCEL_DJBFFT) { + fprintf (stderr, "Using djbfft for IMDCT transform\n"); + ifft128 = (void (*) (complex_t *)) fftc4_un128; + ifft64 = (void (*) (complex_t *)) fftc4_un64; + } else +#endif + { + fprintf (stderr, "No accelerated IMDCT transform found\n"); + ifft128 = ifft128_c; + ifft64 = ifft64_c; + } +} diff --git a/plugins/spu2ghz/src/3rdparty/liba52/inttypes.h b/plugins/spu2ghz/src/3rdparty/liba52/inttypes.h index a0842e3391..5cd0239c26 100644 --- a/plugins/spu2ghz/src/3rdparty/liba52/inttypes.h +++ b/plugins/spu2ghz/src/3rdparty/liba52/inttypes.h @@ -1,13 +1,13 @@ -typedef signed char int8_t; -typedef signed short int16_t; -typedef signed int int32_t; -#ifdef ARCH_X86 -typedef signed long long int64_t; -#endif - -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -#ifdef ARCH_X86 -typedef unsigned long long uint64_t; -#endif +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +#ifdef ARCH_X86 +typedef signed long long int64_t; +#endif + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#ifdef ARCH_X86 +typedef unsigned long long uint64_t; +#endif diff --git a/plugins/spu2ghz/src/3rdparty/liba52/mm_accel.h b/plugins/spu2ghz/src/3rdparty/liba52/mm_accel.h index e6236fb4ea..25258c3683 100644 --- a/plugins/spu2ghz/src/3rdparty/liba52/mm_accel.h +++ b/plugins/spu2ghz/src/3rdparty/liba52/mm_accel.h @@ -1,37 +1,37 @@ -/* - * mm_accel.h - * Copyright (C) 2000-2002 Michel Lespinasse - * Copyright (C) 1999-2000 Aaron Holtzman - * - * This file is part of a52dec, a free ATSC A-52 stream decoder. - * See http://liba52.sourceforge.net/ for updates. - * - * a52dec 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. - * - * a52dec 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 - */ - -#ifndef MM_ACCEL_H -#define MM_ACCEL_H - -/* generic accelerations */ -#define MM_ACCEL_DJBFFT 0x00000001 - -/* x86 accelerations */ -#define MM_ACCEL_X86_MMX 0x80000000 -#define MM_ACCEL_X86_3DNOW 0x40000000 -#define MM_ACCEL_X86_MMXEXT 0x20000000 - -uint32_t mm_accel (void); - -#endif /* MM_ACCEL_H */ +/* + * mm_accel.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 + */ + +#ifndef MM_ACCEL_H +#define MM_ACCEL_H + +/* generic accelerations */ +#define MM_ACCEL_DJBFFT 0x00000001 + +/* x86 accelerations */ +#define MM_ACCEL_X86_MMX 0x80000000 +#define MM_ACCEL_X86_3DNOW 0x40000000 +#define MM_ACCEL_X86_MMXEXT 0x20000000 + +uint32_t mm_accel (void); + +#endif /* MM_ACCEL_H */ diff --git a/plugins/spu2ghz/src/3rdparty/liba52/parse.c b/plugins/spu2ghz/src/3rdparty/liba52/parse.c index 960e5c52c9..3626944f65 100644 --- a/plugins/spu2ghz/src/3rdparty/liba52/parse.c +++ b/plugins/spu2ghz/src/3rdparty/liba52/parse.c @@ -1,903 +1,903 @@ -/* - * parse.c - * Copyright (C) 2000-2002 Michel Lespinasse - * Copyright (C) 1999-2000 Aaron Holtzman - * - * This file is part of a52dec, a free ATSC A-52 stream decoder. - * See http://liba52.sourceforge.net/ for updates. - * - * a52dec 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. - * - * a52dec 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 - */ -#pragma warning(disable:4305) -#pragma warning(disable:4244) - -#include "config.h" - -#include -#include -#include "inttypes.h" - -#include "a52.h" -#include "a52_internal.h" -#include "bitstream.h" -#include "tables.h" - -#ifdef HAVE_MEMALIGN -/* some systems have memalign() but no declaration for it */ -void * memalign (size_t align, size_t size); -#else -/* assume malloc alignment is sufficient */ -#define memalign(align,size) malloc (size) -#endif - -typedef struct { - sample_t q1[2]; - sample_t q2[2]; - sample_t q4; - int q1_ptr; - int q2_ptr; - int q4_ptr; -} quantizer_t; - -static uint8_t halfrate[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3}; - -a52_state_t * a52_init (uint32_t mm_accel) -{ - a52_state_t * state; - int i; - - state = malloc (sizeof (a52_state_t)); - if (state == NULL) - return NULL; - - state->samples = memalign (16, 256 * 12 * sizeof (sample_t)); - if (state->samples == NULL) { - free (state); - return NULL; - } - - for (i = 0; i < 256 * 12; i++) - state->samples[i] = 0; - - state->downmixed = 1; - - state->lfsr_state = 1; - - a52_imdct_init (mm_accel); - - return state; -} - -sample_t * a52_samples (a52_state_t * state) -{ - return state->samples; -} - -int a52_syncinfo (uint8_t * buf, int * flags, - int * sample_rate, int * bit_rate) -{ - static int rate[] = { 32, 40, 48, 56, 64, 80, 96, 112, - 128, 160, 192, 224, 256, 320, 384, 448, - 512, 576, 640}; - static uint8_t lfeon[8] = {0x10, 0x10, 0x04, 0x04, 0x04, 0x01, 0x04, 0x01}; - int frmsizecod; - int bitrate; - int half; - int acmod; - - if ((buf[0] != 0x0b) || (buf[1] != 0x77)) /* syncword */ - return 0; - - if (buf[5] >= 0x60) /* bsid >= 12 */ - return 0; - half = halfrate[buf[5] >> 3]; - - /* acmod, dsurmod and lfeon */ - acmod = buf[6] >> 5; - *flags = ((((buf[6] & 0xf8) == 0x50) ? A52_DOLBY : acmod) | - ((buf[6] & lfeon[acmod]) ? A52_LFE : 0)); - - frmsizecod = buf[4] & 63; - if (frmsizecod >= 38) - return 0; - bitrate = rate [frmsizecod >> 1]; - *bit_rate = (bitrate * 1000) >> half; - - switch (buf[4] & 0xc0) { - case 0: - *sample_rate = 48000 >> half; - return 4 * bitrate; - case 0x40: - *sample_rate = 44100 >> half; - return 2 * (320 * bitrate / 147 + (frmsizecod & 1)); - case 0x80: - *sample_rate = 32000 >> half; - return 6 * bitrate; - default: - return 0; - } -} - -int a52_frame (a52_state_t * state, uint8_t * buf, int * flags, - sample_t * level, sample_t bias) -{ - static sample_t clev[4] = {LEVEL_3DB, LEVEL_45DB, LEVEL_6DB, LEVEL_45DB}; - static sample_t slev[4] = {LEVEL_3DB, LEVEL_6DB, 0, LEVEL_6DB}; - int chaninfo; - int acmod; - - state->fscod = buf[4] >> 6; - state->halfrate = halfrate[buf[5] >> 3]; - state->acmod = acmod = buf[6] >> 5; - - a52_bitstream_set_ptr (state, buf + 6); - bitstream_get (state, 3); /* skip acmod we already parsed */ - - if ((acmod == 2) && (bitstream_get (state, 2) == 2)) /* dsurmod */ - acmod = A52_DOLBY; - - if ((acmod & 1) && (acmod != 1)) - state->clev = clev[bitstream_get (state, 2)]; /* cmixlev */ - - if (acmod & 4) - state->slev = slev[bitstream_get (state, 2)]; /* surmixlev */ - - state->lfeon = bitstream_get (state, 1); - - state->output = a52_downmix_init (acmod, *flags, level, - state->clev, state->slev); - if (state->output < 0) - return 1; - if (state->lfeon && (*flags & A52_LFE)) - state->output |= A52_LFE; - *flags = state->output; - /* the 2* compensates for differences in imdct */ - state->dynrng = state->level = 2 * *level; - state->bias = bias; - state->dynrnge = 1; - state->dynrngcall = NULL; - state->cplba.deltbae = DELTA_BIT_NONE; - state->ba[0].deltbae = state->ba[1].deltbae = state->ba[2].deltbae = - state->ba[3].deltbae = state->ba[4].deltbae = DELTA_BIT_NONE; - - chaninfo = !acmod; - do { - bitstream_get (state, 5); /* dialnorm */ - if (bitstream_get (state, 1)) /* compre */ - bitstream_get (state, 8); /* compr */ - if (bitstream_get (state, 1)) /* langcode */ - bitstream_get (state, 8); /* langcod */ - if (bitstream_get (state, 1)) /* audprodie */ - bitstream_get (state, 7); /* mixlevel + roomtyp */ - } while (chaninfo--); - - bitstream_get (state, 2); /* copyrightb + origbs */ - - if (bitstream_get (state, 1)) /* timecod1e */ - bitstream_get (state, 14); /* timecod1 */ - if (bitstream_get (state, 1)) /* timecod2e */ - bitstream_get (state, 14); /* timecod2 */ - - if (bitstream_get (state, 1)) { /* addbsie */ - int addbsil; - - addbsil = bitstream_get (state, 6); - do { - bitstream_get (state, 8); /* addbsi */ - } while (addbsil--); - } - - return 0; -} - -void a52_dynrng (a52_state_t * state, - sample_t (* call) (sample_t, void *), void * data) -{ - state->dynrnge = 0; - if (call) { - state->dynrnge = 1; - state->dynrngcall = call; - state->dynrngdata = data; - } -} - -static int parse_exponents (a52_state_t * state, int expstr, int ngrps, - uint8_t exponent, uint8_t * dest) -{ - int exps; - - while (ngrps--) { - exps = bitstream_get (state, 7); - - exponent += exp_1[exps]; - if (exponent > 24) - return 1; - - switch (expstr) { - case EXP_D45: - *(dest++) = exponent; - *(dest++) = exponent; - case EXP_D25: - *(dest++) = exponent; - case EXP_D15: - *(dest++) = exponent; - } - - exponent += exp_2[exps]; - if (exponent > 24) - return 1; - - switch (expstr) { - case EXP_D45: - *(dest++) = exponent; - *(dest++) = exponent; - case EXP_D25: - *(dest++) = exponent; - case EXP_D15: - *(dest++) = exponent; - } - - exponent += exp_3[exps]; - if (exponent > 24) - return 1; - - switch (expstr) { - case EXP_D45: - *(dest++) = exponent; - *(dest++) = exponent; - case EXP_D25: - *(dest++) = exponent; - case EXP_D15: - *(dest++) = exponent; - } - } - - return 0; -} - -static int parse_deltba (a52_state_t * state, int8_t * deltba) -{ - int deltnseg, deltlen, delta, j; - - memset (deltba, 0, 50); - - deltnseg = bitstream_get (state, 3); - j = 0; - do { - j += bitstream_get (state, 5); - deltlen = bitstream_get (state, 4); - delta = bitstream_get (state, 3); - delta -= (delta >= 4) ? 3 : 4; - if (!deltlen) - continue; - if (j + deltlen >= 50) - return 1; - while (deltlen--) - deltba[j++] = delta; - } while (deltnseg--); - - return 0; -} - -static inline int zero_snr_offsets (int nfchans, a52_state_t * state) -{ - int i; - - if ((state->csnroffst) || - (state->chincpl && state->cplba.bai >> 3) || /* cplinu, fsnroffst */ - (state->lfeon && state->lfeba.bai >> 3)) /* fsnroffst */ - return 0; - for (i = 0; i < nfchans; i++) - if (state->ba[i].bai >> 3) /* fsnroffst */ - return 0; - return 1; -} - -static inline int16_t dither_gen (a52_state_t * state) -{ - int16_t nstate; - - nstate = dither_lut[state->lfsr_state >> 8] ^ (state->lfsr_state << 8); - - state->lfsr_state = (uint16_t) nstate; - - return nstate; -} - -static void coeff_get (a52_state_t * state, sample_t * coeff, - expbap_t * expbap, quantizer_t * quantizer, - sample_t level, int dither, int end) -{ - int i; - uint8_t * exp; - int8_t * bap; - sample_t factor[25]; - - for (i = 0; i <= 24; i++) - factor[i] = scale_factor[i] * level; - - exp = expbap->exp; - bap = expbap->bap; - - for (i = 0; i < end; i++) { - int bapi; - - bapi = bap[i]; - switch (bapi) { - case 0: - if (dither) { - coeff[i] = dither_gen (state) * LEVEL_3DB * factor[exp[i]]; - continue; - } else { - coeff[i] = 0; - continue; - } - - case -1: - if (quantizer->q1_ptr >= 0) { - coeff[i] = quantizer->q1[quantizer->q1_ptr--] * factor[exp[i]]; - continue; - } else { - int code; - - code = bitstream_get (state, 5); - - quantizer->q1_ptr = 1; - quantizer->q1[0] = q_1_2[code]; - quantizer->q1[1] = q_1_1[code]; - coeff[i] = q_1_0[code] * factor[exp[i]]; - continue; - } - - case -2: - if (quantizer->q2_ptr >= 0) { - coeff[i] = quantizer->q2[quantizer->q2_ptr--] * factor[exp[i]]; - continue; - } else { - int code; - - code = bitstream_get (state, 7); - - quantizer->q2_ptr = 1; - quantizer->q2[0] = q_2_2[code]; - quantizer->q2[1] = q_2_1[code]; - coeff[i] = q_2_0[code] * factor[exp[i]]; - continue; - } - - case 3: - coeff[i] = q_3[bitstream_get (state, 3)] * factor[exp[i]]; - continue; - - case -3: - if (quantizer->q4_ptr == 0) { - quantizer->q4_ptr = -1; - coeff[i] = quantizer->q4 * factor[exp[i]]; - continue; - } else { - int code; - - code = bitstream_get (state, 7); - - quantizer->q4_ptr = 0; - quantizer->q4 = q_4_1[code]; - coeff[i] = q_4_0[code] * factor[exp[i]]; - continue; - } - - case 4: - coeff[i] = q_5[bitstream_get (state, 4)] * factor[exp[i]]; - continue; - - default: - coeff[i] = ((bitstream_get_2 (state, bapi) << (16 - bapi)) * - factor[exp[i]]); - } - } -} - -static void coeff_get_coupling (a52_state_t * state, int nfchans, - sample_t * coeff, sample_t (* samples)[256], - quantizer_t * quantizer, uint8_t dithflag[5]) -{ - int cplbndstrc, bnd, i, i_end, ch; - uint8_t * exp; - int8_t * bap; - sample_t cplco[5]; - - exp = state->cpl_expbap.exp; - bap = state->cpl_expbap.bap; - bnd = 0; - cplbndstrc = state->cplbndstrc; - i = state->cplstrtmant; - while (i < state->cplendmant) { - i_end = i + 12; - while (cplbndstrc & 1) { - cplbndstrc >>= 1; - i_end += 12; - } - cplbndstrc >>= 1; - for (ch = 0; ch < nfchans; ch++) - cplco[ch] = state->cplco[ch][bnd] * coeff[ch]; - bnd++; - - while (i < i_end) { - sample_t cplcoeff; - int bapi; - - bapi = bap[i]; - switch (bapi) { - case 0: - cplcoeff = LEVEL_3DB * scale_factor[exp[i]]; - for (ch = 0; ch < nfchans; ch++) - if ((state->chincpl >> ch) & 1) { - if (dithflag[ch]) - samples[ch][i] = (cplcoeff * cplco[ch] * - dither_gen (state)); - else - samples[ch][i] = 0; - } - i++; - continue; - - case -1: - if (quantizer->q1_ptr >= 0) { - cplcoeff = quantizer->q1[quantizer->q1_ptr--]; - break; - } else { - int code; - - code = bitstream_get (state, 5); - - quantizer->q1_ptr = 1; - quantizer->q1[0] = q_1_2[code]; - quantizer->q1[1] = q_1_1[code]; - cplcoeff = q_1_0[code]; - break; - } - - case -2: - if (quantizer->q2_ptr >= 0) { - cplcoeff = quantizer->q2[quantizer->q2_ptr--]; - break; - } else { - int code; - - code = bitstream_get (state, 7); - - quantizer->q2_ptr = 1; - quantizer->q2[0] = q_2_2[code]; - quantizer->q2[1] = q_2_1[code]; - cplcoeff = q_2_0[code]; - break; - } - - case 3: - cplcoeff = q_3[bitstream_get (state, 3)]; - break; - - case -3: - if (quantizer->q4_ptr == 0) { - quantizer->q4_ptr = -1; - cplcoeff = quantizer->q4; - break; - } else { - int code; - - code = bitstream_get (state, 7); - - quantizer->q4_ptr = 0; - quantizer->q4 = q_4_1[code]; - cplcoeff = q_4_0[code]; - break; - } - - case 4: - cplcoeff = q_5[bitstream_get (state, 4)]; - break; - - default: - cplcoeff = bitstream_get_2 (state, bapi) << (16 - bapi); - } - - cplcoeff *= scale_factor[exp[i]]; - for (ch = 0; ch < nfchans; ch++) - if ((state->chincpl >> ch) & 1) - samples[ch][i] = cplcoeff * cplco[ch]; - i++; - } - } -} - -int a52_block (a52_state_t * state) -{ - static const uint8_t nfchans_tbl[] = {2, 1, 2, 3, 3, 4, 4, 5, 1, 1, 2}; - static int rematrix_band[4] = {25, 37, 61, 253}; - int i, nfchans, chaninfo; - uint8_t cplexpstr, chexpstr[5], lfeexpstr, do_bit_alloc, done_cpl; - uint8_t blksw[5], dithflag[5]; - sample_t coeff[5]; - int chanbias; - quantizer_t quantizer; - sample_t * samples; - - nfchans = nfchans_tbl[state->acmod]; - - for (i = 0; i < nfchans; i++) - blksw[i] = bitstream_get (state, 1); - - for (i = 0; i < nfchans; i++) - dithflag[i] = bitstream_get (state, 1); - - chaninfo = !state->acmod; - do { - if (bitstream_get (state, 1)) { /* dynrnge */ - int dynrng; - - dynrng = bitstream_get_2 (state, 8); - if (state->dynrnge) { - sample_t range; - - range = ((((dynrng & 0x1f) | 0x20) << 13) * - scale_factor[3 - (dynrng >> 5)]); - if (state->dynrngcall) - range = state->dynrngcall (range, state->dynrngdata); - state->dynrng = state->level * range; - } - } - } while (chaninfo--); - - if (bitstream_get (state, 1)) { /* cplstre */ - state->chincpl = 0; - if (bitstream_get (state, 1)) { /* cplinu */ - static uint8_t bndtab[16] = {31, 35, 37, 39, 41, 42, 43, 44, - 45, 45, 46, 46, 47, 47, 48, 48}; - int cplbegf; - int cplendf; - int ncplsubnd; - - for (i = 0; i < nfchans; i++) - state->chincpl |= bitstream_get (state, 1) << i; - switch (state->acmod) { - case 0: case 1: - return 1; - case 2: - state->phsflginu = bitstream_get (state, 1); - } - cplbegf = bitstream_get (state, 4); - cplendf = bitstream_get (state, 4); - - if (cplendf + 3 - cplbegf < 0) - return 1; - state->ncplbnd = ncplsubnd = cplendf + 3 - cplbegf; - state->cplstrtbnd = bndtab[cplbegf]; - state->cplstrtmant = cplbegf * 12 + 37; - state->cplendmant = cplendf * 12 + 73; - - state->cplbndstrc = 0; - for (i = 0; i < ncplsubnd - 1; i++) - if (bitstream_get (state, 1)) { - state->cplbndstrc |= 1 << i; - state->ncplbnd--; - } - } - } - - if (state->chincpl) { /* cplinu */ - int j, cplcoe; - - cplcoe = 0; - for (i = 0; i < nfchans; i++) - if ((state->chincpl) >> i & 1) - if (bitstream_get (state, 1)) { /* cplcoe */ - int mstrcplco, cplcoexp, cplcomant; - - cplcoe = 1; - mstrcplco = 3 * bitstream_get (state, 2); - for (j = 0; j < state->ncplbnd; j++) { - cplcoexp = bitstream_get (state, 4); - cplcomant = bitstream_get (state, 4); - if (cplcoexp == 15) - cplcomant <<= 14; - else - cplcomant = (cplcomant | 0x10) << 13; - state->cplco[i][j] = - cplcomant * scale_factor[cplcoexp + mstrcplco]; - } - } - if ((state->acmod == 2) && state->phsflginu && cplcoe) - for (j = 0; j < state->ncplbnd; j++) - if (bitstream_get (state, 1)) /* phsflg */ - state->cplco[1][j] = -state->cplco[1][j]; - } - - if ((state->acmod == 2) && (bitstream_get (state, 1))) { /* rematstr */ - int end; - - state->rematflg = 0; - end = (state->chincpl) ? state->cplstrtmant : 253; /* cplinu */ - i = 0; - do - state->rematflg |= bitstream_get (state, 1) << i; - while (rematrix_band[i++] < end); - } - - cplexpstr = EXP_REUSE; - lfeexpstr = EXP_REUSE; - if (state->chincpl) /* cplinu */ - cplexpstr = bitstream_get (state, 2); - for (i = 0; i < nfchans; i++) - chexpstr[i] = bitstream_get (state, 2); - if (state->lfeon) - lfeexpstr = bitstream_get (state, 1); - - for (i = 0; i < nfchans; i++) - if (chexpstr[i] != EXP_REUSE) { - if ((state->chincpl >> i) & 1) - state->endmant[i] = state->cplstrtmant; - else { - int chbwcod; - - chbwcod = bitstream_get (state, 6); - if (chbwcod > 60) - return 1; - state->endmant[i] = chbwcod * 3 + 73; - } - } - - do_bit_alloc = 0; - - if (cplexpstr != EXP_REUSE) { - int cplabsexp, ncplgrps; - - do_bit_alloc = 64; - ncplgrps = ((state->cplendmant - state->cplstrtmant) / - (3 << (cplexpstr - 1))); - cplabsexp = bitstream_get (state, 4) << 1; - if (parse_exponents (state, cplexpstr, ncplgrps, cplabsexp, - state->cpl_expbap.exp + state->cplstrtmant)) - return 1; - } - for (i = 0; i < nfchans; i++) - if (chexpstr[i] != EXP_REUSE) { - int grp_size, nchgrps; - - do_bit_alloc |= 1 << i; - grp_size = 3 << (chexpstr[i] - 1); - nchgrps = (state->endmant[i] + grp_size - 4) / grp_size; - state->fbw_expbap[i].exp[0] = bitstream_get (state, 4); - if (parse_exponents (state, chexpstr[i], nchgrps, - state->fbw_expbap[i].exp[0], - state->fbw_expbap[i].exp + 1)) - return 1; - bitstream_get (state, 2); /* gainrng */ - } - if (lfeexpstr != EXP_REUSE) { - do_bit_alloc |= 32; - state->lfe_expbap.exp[0] = bitstream_get (state, 4); - if (parse_exponents (state, lfeexpstr, 2, state->lfe_expbap.exp[0], - state->lfe_expbap.exp + 1)) - return 1; - } - - if (bitstream_get (state, 1)) { /* baie */ - do_bit_alloc = -1; - state->bai = bitstream_get (state, 11); - } - if (bitstream_get (state, 1)) { /* snroffste */ - do_bit_alloc = -1; - state->csnroffst = bitstream_get (state, 6); - if (state->chincpl) /* cplinu */ - state->cplba.bai = bitstream_get (state, 7); - for (i = 0; i < nfchans; i++) - state->ba[i].bai = bitstream_get (state, 7); - if (state->lfeon) - state->lfeba.bai = bitstream_get (state, 7); - } - if ((state->chincpl) && (bitstream_get (state, 1))) { /* cplleake */ - do_bit_alloc |= 64; - state->cplfleak = 9 - bitstream_get (state, 3); - state->cplsleak = 9 - bitstream_get (state, 3); - } - - if (bitstream_get (state, 1)) { /* deltbaie */ - do_bit_alloc = -1; - if (state->chincpl) /* cplinu */ - state->cplba.deltbae = bitstream_get (state, 2); - for (i = 0; i < nfchans; i++) - state->ba[i].deltbae = bitstream_get (state, 2); - if (state->chincpl && /* cplinu */ - (state->cplba.deltbae == DELTA_BIT_NEW) && - parse_deltba (state, state->cplba.deltba)) - return 1; - for (i = 0; i < nfchans; i++) - if ((state->ba[i].deltbae == DELTA_BIT_NEW) && - parse_deltba (state, state->ba[i].deltba)) - return 1; - } - - if (do_bit_alloc) { - if (zero_snr_offsets (nfchans, state)) { - memset (state->cpl_expbap.bap, 0, sizeof (state->cpl_expbap.bap)); - for (i = 0; i < nfchans; i++) - memset (state->fbw_expbap[i].bap, 0, - sizeof (state->fbw_expbap[i].bap)); - memset (state->lfe_expbap.bap, 0, sizeof (state->lfe_expbap.bap)); - } else { - if (state->chincpl && (do_bit_alloc & 64)) /* cplinu */ - a52_bit_allocate (state, &state->cplba, state->cplstrtbnd, - state->cplstrtmant, state->cplendmant, - state->cplfleak << 8, state->cplsleak << 8, - &state->cpl_expbap); - for (i = 0; i < nfchans; i++) - if (do_bit_alloc & (1 << i)) - a52_bit_allocate (state, state->ba + i, 0, 0, - state->endmant[i], 0, 0, - state->fbw_expbap +i); - if (state->lfeon && (do_bit_alloc & 32)) { - state->lfeba.deltbae = DELTA_BIT_NONE; - a52_bit_allocate (state, &state->lfeba, 0, 0, 7, 0, 0, - &state->lfe_expbap); - } - } - } - - if (bitstream_get (state, 1)) { /* skiple */ - i = bitstream_get (state, 9); /* skipl */ - while (i--) - bitstream_get (state, 8); - } - - samples = state->samples; - if (state->output & A52_LFE) - samples += 256; /* shift for LFE channel */ - - chanbias = a52_downmix_coeff (coeff, state->acmod, state->output, - state->dynrng, state->clev, state->slev); - - quantizer.q1_ptr = quantizer.q2_ptr = quantizer.q4_ptr = -1; - done_cpl = 0; - - for (i = 0; i < nfchans; i++) { - int j; - - coeff_get (state, samples + 256 * i, state->fbw_expbap +i, &quantizer, - coeff[i], dithflag[i], state->endmant[i]); - - if ((state->chincpl >> i) & 1) { - if (!done_cpl) { - done_cpl = 1; - coeff_get_coupling (state, nfchans, coeff, - (sample_t (*)[256])samples, &quantizer, - dithflag); - } - j = state->cplendmant; - } else - j = state->endmant[i]; - do - (samples + 256 * i)[j] = 0; - while (++j < 256); - } - - if (state->acmod == 2) { - int j, end, band, rematflg; - - end = ((state->endmant[0] < state->endmant[1]) ? - state->endmant[0] : state->endmant[1]); - - i = 0; - j = 13; - rematflg = state->rematflg; - do { - if (! (rematflg & 1)) { - rematflg >>= 1; - j = rematrix_band[i++]; - continue; - } - rematflg >>= 1; - band = rematrix_band[i++]; - if (band > end) - band = end; - do { - sample_t tmp0, tmp1; - - tmp0 = samples[j]; - tmp1 = (samples+256)[j]; - samples[j] = tmp0 + tmp1; - (samples+256)[j] = tmp0 - tmp1; - } while (++j < band); - } while (j < end); - } - - if (state->lfeon) { - if (state->output & A52_LFE) { - coeff_get (state, samples - 256, &state->lfe_expbap, &quantizer, - state->dynrng, 0, 7); - for (i = 7; i < 256; i++) - (samples-256)[i] = 0; - a52_imdct_512 (samples - 256, samples + 1536 - 256, state->bias); - } else { - /* just skip the LFE coefficients */ - coeff_get (state, samples + 1280, &state->lfe_expbap, &quantizer, - 0, 0, 7); - } - } - - i = 0; - if (nfchans_tbl[state->output & A52_CHANNEL_MASK] < nfchans) - for (i = 1; i < nfchans; i++) - if (blksw[i] != blksw[0]) - break; - - if (i < nfchans) { - if (state->downmixed) { - state->downmixed = 0; - a52_upmix (samples + 1536, state->acmod, state->output); - } - - for (i = 0; i < nfchans; i++) { - sample_t bias; - - bias = 0; - if (!(chanbias & (1 << i))) - bias = state->bias; - - if (coeff[i]) { - if (blksw[i]) - a52_imdct_256 (samples + 256 * i, samples + 1536 + 256 * i, - bias); - else - a52_imdct_512 (samples + 256 * i, samples + 1536 + 256 * i, - bias); - } else { - int j; - - for (j = 0; j < 256; j++) - (samples + 256 * i)[j] = bias; - } - } - - a52_downmix (samples, state->acmod, state->output, state->bias, - state->clev, state->slev); - } else { - nfchans = nfchans_tbl[state->output & A52_CHANNEL_MASK]; - - a52_downmix (samples, state->acmod, state->output, 0, - state->clev, state->slev); - - if (!state->downmixed) { - state->downmixed = 1; - a52_downmix (samples + 1536, state->acmod, state->output, 0, - state->clev, state->slev); - } - - if (blksw[0]) - for (i = 0; i < nfchans; i++) - a52_imdct_256 (samples + 256 * i, samples + 1536 + 256 * i, - state->bias); - else - for (i = 0; i < nfchans; i++) - a52_imdct_512 (samples + 256 * i, samples + 1536 + 256 * i, - state->bias); - } - - return 0; -} - -void a52_free (a52_state_t * state) -{ - free (state->samples); - free (state); -} +/* + * parse.c + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 + */ +#pragma warning(disable:4305) +#pragma warning(disable:4244) + +#include "config.h" + +#include +#include +#include "inttypes.h" + +#include "a52.h" +#include "a52_internal.h" +#include "bitstream.h" +#include "tables.h" + +#ifdef HAVE_MEMALIGN +/* some systems have memalign() but no declaration for it */ +void * memalign (size_t align, size_t size); +#else +/* assume malloc alignment is sufficient */ +#define memalign(align,size) malloc (size) +#endif + +typedef struct { + sample_t q1[2]; + sample_t q2[2]; + sample_t q4; + int q1_ptr; + int q2_ptr; + int q4_ptr; +} quantizer_t; + +static uint8_t halfrate[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3}; + +a52_state_t * a52_init (uint32_t mm_accel) +{ + a52_state_t * state; + int i; + + state = malloc (sizeof (a52_state_t)); + if (state == NULL) + return NULL; + + state->samples = memalign (16, 256 * 12 * sizeof (sample_t)); + if (state->samples == NULL) { + free (state); + return NULL; + } + + for (i = 0; i < 256 * 12; i++) + state->samples[i] = 0; + + state->downmixed = 1; + + state->lfsr_state = 1; + + a52_imdct_init (mm_accel); + + return state; +} + +sample_t * a52_samples (a52_state_t * state) +{ + return state->samples; +} + +int a52_syncinfo (uint8_t * buf, int * flags, + int * sample_rate, int * bit_rate) +{ + static int rate[] = { 32, 40, 48, 56, 64, 80, 96, 112, + 128, 160, 192, 224, 256, 320, 384, 448, + 512, 576, 640}; + static uint8_t lfeon[8] = {0x10, 0x10, 0x04, 0x04, 0x04, 0x01, 0x04, 0x01}; + int frmsizecod; + int bitrate; + int half; + int acmod; + + if ((buf[0] != 0x0b) || (buf[1] != 0x77)) /* syncword */ + return 0; + + if (buf[5] >= 0x60) /* bsid >= 12 */ + return 0; + half = halfrate[buf[5] >> 3]; + + /* acmod, dsurmod and lfeon */ + acmod = buf[6] >> 5; + *flags = ((((buf[6] & 0xf8) == 0x50) ? A52_DOLBY : acmod) | + ((buf[6] & lfeon[acmod]) ? A52_LFE : 0)); + + frmsizecod = buf[4] & 63; + if (frmsizecod >= 38) + return 0; + bitrate = rate [frmsizecod >> 1]; + *bit_rate = (bitrate * 1000) >> half; + + switch (buf[4] & 0xc0) { + case 0: + *sample_rate = 48000 >> half; + return 4 * bitrate; + case 0x40: + *sample_rate = 44100 >> half; + return 2 * (320 * bitrate / 147 + (frmsizecod & 1)); + case 0x80: + *sample_rate = 32000 >> half; + return 6 * bitrate; + default: + return 0; + } +} + +int a52_frame (a52_state_t * state, uint8_t * buf, int * flags, + sample_t * level, sample_t bias) +{ + static sample_t clev[4] = {LEVEL_3DB, LEVEL_45DB, LEVEL_6DB, LEVEL_45DB}; + static sample_t slev[4] = {LEVEL_3DB, LEVEL_6DB, 0, LEVEL_6DB}; + int chaninfo; + int acmod; + + state->fscod = buf[4] >> 6; + state->halfrate = halfrate[buf[5] >> 3]; + state->acmod = acmod = buf[6] >> 5; + + a52_bitstream_set_ptr (state, buf + 6); + bitstream_get (state, 3); /* skip acmod we already parsed */ + + if ((acmod == 2) && (bitstream_get (state, 2) == 2)) /* dsurmod */ + acmod = A52_DOLBY; + + if ((acmod & 1) && (acmod != 1)) + state->clev = clev[bitstream_get (state, 2)]; /* cmixlev */ + + if (acmod & 4) + state->slev = slev[bitstream_get (state, 2)]; /* surmixlev */ + + state->lfeon = bitstream_get (state, 1); + + state->output = a52_downmix_init (acmod, *flags, level, + state->clev, state->slev); + if (state->output < 0) + return 1; + if (state->lfeon && (*flags & A52_LFE)) + state->output |= A52_LFE; + *flags = state->output; + /* the 2* compensates for differences in imdct */ + state->dynrng = state->level = 2 * *level; + state->bias = bias; + state->dynrnge = 1; + state->dynrngcall = NULL; + state->cplba.deltbae = DELTA_BIT_NONE; + state->ba[0].deltbae = state->ba[1].deltbae = state->ba[2].deltbae = + state->ba[3].deltbae = state->ba[4].deltbae = DELTA_BIT_NONE; + + chaninfo = !acmod; + do { + bitstream_get (state, 5); /* dialnorm */ + if (bitstream_get (state, 1)) /* compre */ + bitstream_get (state, 8); /* compr */ + if (bitstream_get (state, 1)) /* langcode */ + bitstream_get (state, 8); /* langcod */ + if (bitstream_get (state, 1)) /* audprodie */ + bitstream_get (state, 7); /* mixlevel + roomtyp */ + } while (chaninfo--); + + bitstream_get (state, 2); /* copyrightb + origbs */ + + if (bitstream_get (state, 1)) /* timecod1e */ + bitstream_get (state, 14); /* timecod1 */ + if (bitstream_get (state, 1)) /* timecod2e */ + bitstream_get (state, 14); /* timecod2 */ + + if (bitstream_get (state, 1)) { /* addbsie */ + int addbsil; + + addbsil = bitstream_get (state, 6); + do { + bitstream_get (state, 8); /* addbsi */ + } while (addbsil--); + } + + return 0; +} + +void a52_dynrng (a52_state_t * state, + sample_t (* call) (sample_t, void *), void * data) +{ + state->dynrnge = 0; + if (call) { + state->dynrnge = 1; + state->dynrngcall = call; + state->dynrngdata = data; + } +} + +static int parse_exponents (a52_state_t * state, int expstr, int ngrps, + uint8_t exponent, uint8_t * dest) +{ + int exps; + + while (ngrps--) { + exps = bitstream_get (state, 7); + + exponent += exp_1[exps]; + if (exponent > 24) + return 1; + + switch (expstr) { + case EXP_D45: + *(dest++) = exponent; + *(dest++) = exponent; + case EXP_D25: + *(dest++) = exponent; + case EXP_D15: + *(dest++) = exponent; + } + + exponent += exp_2[exps]; + if (exponent > 24) + return 1; + + switch (expstr) { + case EXP_D45: + *(dest++) = exponent; + *(dest++) = exponent; + case EXP_D25: + *(dest++) = exponent; + case EXP_D15: + *(dest++) = exponent; + } + + exponent += exp_3[exps]; + if (exponent > 24) + return 1; + + switch (expstr) { + case EXP_D45: + *(dest++) = exponent; + *(dest++) = exponent; + case EXP_D25: + *(dest++) = exponent; + case EXP_D15: + *(dest++) = exponent; + } + } + + return 0; +} + +static int parse_deltba (a52_state_t * state, int8_t * deltba) +{ + int deltnseg, deltlen, delta, j; + + memset (deltba, 0, 50); + + deltnseg = bitstream_get (state, 3); + j = 0; + do { + j += bitstream_get (state, 5); + deltlen = bitstream_get (state, 4); + delta = bitstream_get (state, 3); + delta -= (delta >= 4) ? 3 : 4; + if (!deltlen) + continue; + if (j + deltlen >= 50) + return 1; + while (deltlen--) + deltba[j++] = delta; + } while (deltnseg--); + + return 0; +} + +static inline int zero_snr_offsets (int nfchans, a52_state_t * state) +{ + int i; + + if ((state->csnroffst) || + (state->chincpl && state->cplba.bai >> 3) || /* cplinu, fsnroffst */ + (state->lfeon && state->lfeba.bai >> 3)) /* fsnroffst */ + return 0; + for (i = 0; i < nfchans; i++) + if (state->ba[i].bai >> 3) /* fsnroffst */ + return 0; + return 1; +} + +static inline int16_t dither_gen (a52_state_t * state) +{ + int16_t nstate; + + nstate = dither_lut[state->lfsr_state >> 8] ^ (state->lfsr_state << 8); + + state->lfsr_state = (uint16_t) nstate; + + return nstate; +} + +static void coeff_get (a52_state_t * state, sample_t * coeff, + expbap_t * expbap, quantizer_t * quantizer, + sample_t level, int dither, int end) +{ + int i; + uint8_t * exp; + int8_t * bap; + sample_t factor[25]; + + for (i = 0; i <= 24; i++) + factor[i] = scale_factor[i] * level; + + exp = expbap->exp; + bap = expbap->bap; + + for (i = 0; i < end; i++) { + int bapi; + + bapi = bap[i]; + switch (bapi) { + case 0: + if (dither) { + coeff[i] = dither_gen (state) * LEVEL_3DB * factor[exp[i]]; + continue; + } else { + coeff[i] = 0; + continue; + } + + case -1: + if (quantizer->q1_ptr >= 0) { + coeff[i] = quantizer->q1[quantizer->q1_ptr--] * factor[exp[i]]; + continue; + } else { + int code; + + code = bitstream_get (state, 5); + + quantizer->q1_ptr = 1; + quantizer->q1[0] = q_1_2[code]; + quantizer->q1[1] = q_1_1[code]; + coeff[i] = q_1_0[code] * factor[exp[i]]; + continue; + } + + case -2: + if (quantizer->q2_ptr >= 0) { + coeff[i] = quantizer->q2[quantizer->q2_ptr--] * factor[exp[i]]; + continue; + } else { + int code; + + code = bitstream_get (state, 7); + + quantizer->q2_ptr = 1; + quantizer->q2[0] = q_2_2[code]; + quantizer->q2[1] = q_2_1[code]; + coeff[i] = q_2_0[code] * factor[exp[i]]; + continue; + } + + case 3: + coeff[i] = q_3[bitstream_get (state, 3)] * factor[exp[i]]; + continue; + + case -3: + if (quantizer->q4_ptr == 0) { + quantizer->q4_ptr = -1; + coeff[i] = quantizer->q4 * factor[exp[i]]; + continue; + } else { + int code; + + code = bitstream_get (state, 7); + + quantizer->q4_ptr = 0; + quantizer->q4 = q_4_1[code]; + coeff[i] = q_4_0[code] * factor[exp[i]]; + continue; + } + + case 4: + coeff[i] = q_5[bitstream_get (state, 4)] * factor[exp[i]]; + continue; + + default: + coeff[i] = ((bitstream_get_2 (state, bapi) << (16 - bapi)) * + factor[exp[i]]); + } + } +} + +static void coeff_get_coupling (a52_state_t * state, int nfchans, + sample_t * coeff, sample_t (* samples)[256], + quantizer_t * quantizer, uint8_t dithflag[5]) +{ + int cplbndstrc, bnd, i, i_end, ch; + uint8_t * exp; + int8_t * bap; + sample_t cplco[5]; + + exp = state->cpl_expbap.exp; + bap = state->cpl_expbap.bap; + bnd = 0; + cplbndstrc = state->cplbndstrc; + i = state->cplstrtmant; + while (i < state->cplendmant) { + i_end = i + 12; + while (cplbndstrc & 1) { + cplbndstrc >>= 1; + i_end += 12; + } + cplbndstrc >>= 1; + for (ch = 0; ch < nfchans; ch++) + cplco[ch] = state->cplco[ch][bnd] * coeff[ch]; + bnd++; + + while (i < i_end) { + sample_t cplcoeff; + int bapi; + + bapi = bap[i]; + switch (bapi) { + case 0: + cplcoeff = LEVEL_3DB * scale_factor[exp[i]]; + for (ch = 0; ch < nfchans; ch++) + if ((state->chincpl >> ch) & 1) { + if (dithflag[ch]) + samples[ch][i] = (cplcoeff * cplco[ch] * + dither_gen (state)); + else + samples[ch][i] = 0; + } + i++; + continue; + + case -1: + if (quantizer->q1_ptr >= 0) { + cplcoeff = quantizer->q1[quantizer->q1_ptr--]; + break; + } else { + int code; + + code = bitstream_get (state, 5); + + quantizer->q1_ptr = 1; + quantizer->q1[0] = q_1_2[code]; + quantizer->q1[1] = q_1_1[code]; + cplcoeff = q_1_0[code]; + break; + } + + case -2: + if (quantizer->q2_ptr >= 0) { + cplcoeff = quantizer->q2[quantizer->q2_ptr--]; + break; + } else { + int code; + + code = bitstream_get (state, 7); + + quantizer->q2_ptr = 1; + quantizer->q2[0] = q_2_2[code]; + quantizer->q2[1] = q_2_1[code]; + cplcoeff = q_2_0[code]; + break; + } + + case 3: + cplcoeff = q_3[bitstream_get (state, 3)]; + break; + + case -3: + if (quantizer->q4_ptr == 0) { + quantizer->q4_ptr = -1; + cplcoeff = quantizer->q4; + break; + } else { + int code; + + code = bitstream_get (state, 7); + + quantizer->q4_ptr = 0; + quantizer->q4 = q_4_1[code]; + cplcoeff = q_4_0[code]; + break; + } + + case 4: + cplcoeff = q_5[bitstream_get (state, 4)]; + break; + + default: + cplcoeff = bitstream_get_2 (state, bapi) << (16 - bapi); + } + + cplcoeff *= scale_factor[exp[i]]; + for (ch = 0; ch < nfchans; ch++) + if ((state->chincpl >> ch) & 1) + samples[ch][i] = cplcoeff * cplco[ch]; + i++; + } + } +} + +int a52_block (a52_state_t * state) +{ + static const uint8_t nfchans_tbl[] = {2, 1, 2, 3, 3, 4, 4, 5, 1, 1, 2}; + static int rematrix_band[4] = {25, 37, 61, 253}; + int i, nfchans, chaninfo; + uint8_t cplexpstr, chexpstr[5], lfeexpstr, do_bit_alloc, done_cpl; + uint8_t blksw[5], dithflag[5]; + sample_t coeff[5]; + int chanbias; + quantizer_t quantizer; + sample_t * samples; + + nfchans = nfchans_tbl[state->acmod]; + + for (i = 0; i < nfchans; i++) + blksw[i] = bitstream_get (state, 1); + + for (i = 0; i < nfchans; i++) + dithflag[i] = bitstream_get (state, 1); + + chaninfo = !state->acmod; + do { + if (bitstream_get (state, 1)) { /* dynrnge */ + int dynrng; + + dynrng = bitstream_get_2 (state, 8); + if (state->dynrnge) { + sample_t range; + + range = ((((dynrng & 0x1f) | 0x20) << 13) * + scale_factor[3 - (dynrng >> 5)]); + if (state->dynrngcall) + range = state->dynrngcall (range, state->dynrngdata); + state->dynrng = state->level * range; + } + } + } while (chaninfo--); + + if (bitstream_get (state, 1)) { /* cplstre */ + state->chincpl = 0; + if (bitstream_get (state, 1)) { /* cplinu */ + static uint8_t bndtab[16] = {31, 35, 37, 39, 41, 42, 43, 44, + 45, 45, 46, 46, 47, 47, 48, 48}; + int cplbegf; + int cplendf; + int ncplsubnd; + + for (i = 0; i < nfchans; i++) + state->chincpl |= bitstream_get (state, 1) << i; + switch (state->acmod) { + case 0: case 1: + return 1; + case 2: + state->phsflginu = bitstream_get (state, 1); + } + cplbegf = bitstream_get (state, 4); + cplendf = bitstream_get (state, 4); + + if (cplendf + 3 - cplbegf < 0) + return 1; + state->ncplbnd = ncplsubnd = cplendf + 3 - cplbegf; + state->cplstrtbnd = bndtab[cplbegf]; + state->cplstrtmant = cplbegf * 12 + 37; + state->cplendmant = cplendf * 12 + 73; + + state->cplbndstrc = 0; + for (i = 0; i < ncplsubnd - 1; i++) + if (bitstream_get (state, 1)) { + state->cplbndstrc |= 1 << i; + state->ncplbnd--; + } + } + } + + if (state->chincpl) { /* cplinu */ + int j, cplcoe; + + cplcoe = 0; + for (i = 0; i < nfchans; i++) + if ((state->chincpl) >> i & 1) + if (bitstream_get (state, 1)) { /* cplcoe */ + int mstrcplco, cplcoexp, cplcomant; + + cplcoe = 1; + mstrcplco = 3 * bitstream_get (state, 2); + for (j = 0; j < state->ncplbnd; j++) { + cplcoexp = bitstream_get (state, 4); + cplcomant = bitstream_get (state, 4); + if (cplcoexp == 15) + cplcomant <<= 14; + else + cplcomant = (cplcomant | 0x10) << 13; + state->cplco[i][j] = + cplcomant * scale_factor[cplcoexp + mstrcplco]; + } + } + if ((state->acmod == 2) && state->phsflginu && cplcoe) + for (j = 0; j < state->ncplbnd; j++) + if (bitstream_get (state, 1)) /* phsflg */ + state->cplco[1][j] = -state->cplco[1][j]; + } + + if ((state->acmod == 2) && (bitstream_get (state, 1))) { /* rematstr */ + int end; + + state->rematflg = 0; + end = (state->chincpl) ? state->cplstrtmant : 253; /* cplinu */ + i = 0; + do + state->rematflg |= bitstream_get (state, 1) << i; + while (rematrix_band[i++] < end); + } + + cplexpstr = EXP_REUSE; + lfeexpstr = EXP_REUSE; + if (state->chincpl) /* cplinu */ + cplexpstr = bitstream_get (state, 2); + for (i = 0; i < nfchans; i++) + chexpstr[i] = bitstream_get (state, 2); + if (state->lfeon) + lfeexpstr = bitstream_get (state, 1); + + for (i = 0; i < nfchans; i++) + if (chexpstr[i] != EXP_REUSE) { + if ((state->chincpl >> i) & 1) + state->endmant[i] = state->cplstrtmant; + else { + int chbwcod; + + chbwcod = bitstream_get (state, 6); + if (chbwcod > 60) + return 1; + state->endmant[i] = chbwcod * 3 + 73; + } + } + + do_bit_alloc = 0; + + if (cplexpstr != EXP_REUSE) { + int cplabsexp, ncplgrps; + + do_bit_alloc = 64; + ncplgrps = ((state->cplendmant - state->cplstrtmant) / + (3 << (cplexpstr - 1))); + cplabsexp = bitstream_get (state, 4) << 1; + if (parse_exponents (state, cplexpstr, ncplgrps, cplabsexp, + state->cpl_expbap.exp + state->cplstrtmant)) + return 1; + } + for (i = 0; i < nfchans; i++) + if (chexpstr[i] != EXP_REUSE) { + int grp_size, nchgrps; + + do_bit_alloc |= 1 << i; + grp_size = 3 << (chexpstr[i] - 1); + nchgrps = (state->endmant[i] + grp_size - 4) / grp_size; + state->fbw_expbap[i].exp[0] = bitstream_get (state, 4); + if (parse_exponents (state, chexpstr[i], nchgrps, + state->fbw_expbap[i].exp[0], + state->fbw_expbap[i].exp + 1)) + return 1; + bitstream_get (state, 2); /* gainrng */ + } + if (lfeexpstr != EXP_REUSE) { + do_bit_alloc |= 32; + state->lfe_expbap.exp[0] = bitstream_get (state, 4); + if (parse_exponents (state, lfeexpstr, 2, state->lfe_expbap.exp[0], + state->lfe_expbap.exp + 1)) + return 1; + } + + if (bitstream_get (state, 1)) { /* baie */ + do_bit_alloc = -1; + state->bai = bitstream_get (state, 11); + } + if (bitstream_get (state, 1)) { /* snroffste */ + do_bit_alloc = -1; + state->csnroffst = bitstream_get (state, 6); + if (state->chincpl) /* cplinu */ + state->cplba.bai = bitstream_get (state, 7); + for (i = 0; i < nfchans; i++) + state->ba[i].bai = bitstream_get (state, 7); + if (state->lfeon) + state->lfeba.bai = bitstream_get (state, 7); + } + if ((state->chincpl) && (bitstream_get (state, 1))) { /* cplleake */ + do_bit_alloc |= 64; + state->cplfleak = 9 - bitstream_get (state, 3); + state->cplsleak = 9 - bitstream_get (state, 3); + } + + if (bitstream_get (state, 1)) { /* deltbaie */ + do_bit_alloc = -1; + if (state->chincpl) /* cplinu */ + state->cplba.deltbae = bitstream_get (state, 2); + for (i = 0; i < nfchans; i++) + state->ba[i].deltbae = bitstream_get (state, 2); + if (state->chincpl && /* cplinu */ + (state->cplba.deltbae == DELTA_BIT_NEW) && + parse_deltba (state, state->cplba.deltba)) + return 1; + for (i = 0; i < nfchans; i++) + if ((state->ba[i].deltbae == DELTA_BIT_NEW) && + parse_deltba (state, state->ba[i].deltba)) + return 1; + } + + if (do_bit_alloc) { + if (zero_snr_offsets (nfchans, state)) { + memset (state->cpl_expbap.bap, 0, sizeof (state->cpl_expbap.bap)); + for (i = 0; i < nfchans; i++) + memset (state->fbw_expbap[i].bap, 0, + sizeof (state->fbw_expbap[i].bap)); + memset (state->lfe_expbap.bap, 0, sizeof (state->lfe_expbap.bap)); + } else { + if (state->chincpl && (do_bit_alloc & 64)) /* cplinu */ + a52_bit_allocate (state, &state->cplba, state->cplstrtbnd, + state->cplstrtmant, state->cplendmant, + state->cplfleak << 8, state->cplsleak << 8, + &state->cpl_expbap); + for (i = 0; i < nfchans; i++) + if (do_bit_alloc & (1 << i)) + a52_bit_allocate (state, state->ba + i, 0, 0, + state->endmant[i], 0, 0, + state->fbw_expbap +i); + if (state->lfeon && (do_bit_alloc & 32)) { + state->lfeba.deltbae = DELTA_BIT_NONE; + a52_bit_allocate (state, &state->lfeba, 0, 0, 7, 0, 0, + &state->lfe_expbap); + } + } + } + + if (bitstream_get (state, 1)) { /* skiple */ + i = bitstream_get (state, 9); /* skipl */ + while (i--) + bitstream_get (state, 8); + } + + samples = state->samples; + if (state->output & A52_LFE) + samples += 256; /* shift for LFE channel */ + + chanbias = a52_downmix_coeff (coeff, state->acmod, state->output, + state->dynrng, state->clev, state->slev); + + quantizer.q1_ptr = quantizer.q2_ptr = quantizer.q4_ptr = -1; + done_cpl = 0; + + for (i = 0; i < nfchans; i++) { + int j; + + coeff_get (state, samples + 256 * i, state->fbw_expbap +i, &quantizer, + coeff[i], dithflag[i], state->endmant[i]); + + if ((state->chincpl >> i) & 1) { + if (!done_cpl) { + done_cpl = 1; + coeff_get_coupling (state, nfchans, coeff, + (sample_t (*)[256])samples, &quantizer, + dithflag); + } + j = state->cplendmant; + } else + j = state->endmant[i]; + do + (samples + 256 * i)[j] = 0; + while (++j < 256); + } + + if (state->acmod == 2) { + int j, end, band, rematflg; + + end = ((state->endmant[0] < state->endmant[1]) ? + state->endmant[0] : state->endmant[1]); + + i = 0; + j = 13; + rematflg = state->rematflg; + do { + if (! (rematflg & 1)) { + rematflg >>= 1; + j = rematrix_band[i++]; + continue; + } + rematflg >>= 1; + band = rematrix_band[i++]; + if (band > end) + band = end; + do { + sample_t tmp0, tmp1; + + tmp0 = samples[j]; + tmp1 = (samples+256)[j]; + samples[j] = tmp0 + tmp1; + (samples+256)[j] = tmp0 - tmp1; + } while (++j < band); + } while (j < end); + } + + if (state->lfeon) { + if (state->output & A52_LFE) { + coeff_get (state, samples - 256, &state->lfe_expbap, &quantizer, + state->dynrng, 0, 7); + for (i = 7; i < 256; i++) + (samples-256)[i] = 0; + a52_imdct_512 (samples - 256, samples + 1536 - 256, state->bias); + } else { + /* just skip the LFE coefficients */ + coeff_get (state, samples + 1280, &state->lfe_expbap, &quantizer, + 0, 0, 7); + } + } + + i = 0; + if (nfchans_tbl[state->output & A52_CHANNEL_MASK] < nfchans) + for (i = 1; i < nfchans; i++) + if (blksw[i] != blksw[0]) + break; + + if (i < nfchans) { + if (state->downmixed) { + state->downmixed = 0; + a52_upmix (samples + 1536, state->acmod, state->output); + } + + for (i = 0; i < nfchans; i++) { + sample_t bias; + + bias = 0; + if (!(chanbias & (1 << i))) + bias = state->bias; + + if (coeff[i]) { + if (blksw[i]) + a52_imdct_256 (samples + 256 * i, samples + 1536 + 256 * i, + bias); + else + a52_imdct_512 (samples + 256 * i, samples + 1536 + 256 * i, + bias); + } else { + int j; + + for (j = 0; j < 256; j++) + (samples + 256 * i)[j] = bias; + } + } + + a52_downmix (samples, state->acmod, state->output, state->bias, + state->clev, state->slev); + } else { + nfchans = nfchans_tbl[state->output & A52_CHANNEL_MASK]; + + a52_downmix (samples, state->acmod, state->output, 0, + state->clev, state->slev); + + if (!state->downmixed) { + state->downmixed = 1; + a52_downmix (samples + 1536, state->acmod, state->output, 0, + state->clev, state->slev); + } + + if (blksw[0]) + for (i = 0; i < nfchans; i++) + a52_imdct_256 (samples + 256 * i, samples + 1536 + 256 * i, + state->bias); + else + for (i = 0; i < nfchans; i++) + a52_imdct_512 (samples + 256 * i, samples + 1536 + 256 * i, + state->bias); + } + + return 0; +} + +void a52_free (a52_state_t * state) +{ + free (state->samples); + free (state); +} diff --git a/plugins/spu2ghz/src/3rdparty/liba52/tables.h b/plugins/spu2ghz/src/3rdparty/liba52/tables.h index 5581779618..a35543db7c 100644 --- a/plugins/spu2ghz/src/3rdparty/liba52/tables.h +++ b/plugins/spu2ghz/src/3rdparty/liba52/tables.h @@ -1,246 +1,246 @@ -/* - * tables.h - * Copyright (C) 2000-2002 Michel Lespinasse - * Copyright (C) 1999-2000 Aaron Holtzman - * - * This file is part of a52dec, a free ATSC A-52 stream decoder. - * See http://liba52.sourceforge.net/ for updates. - * - * a52dec 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. - * - * a52dec 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 - */ - -static const int8_t exp_1[128] = { - -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 25,25,25 -}; -static const int8_t exp_2[128] = { - -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, - -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, - -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, - -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, - -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, - 25,25,25 -}; -static const int8_t exp_3[128] = { - -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, - -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, - -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, - -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, - -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, - 25,25,25 -}; - -#define Q0 ((-2 << 15) / 3.0) -#define Q1 (0) -#define Q2 ((2 << 15) / 3.0) - -static const sample_t q_1_0[32] = { - Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0, - Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1, - Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2, - 0,0,0,0,0 -}; - -static const sample_t q_1_1[32] = { - Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2, - Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2, - Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2, - 0,0,0,0,0 -}; - -static const sample_t q_1_2[32] = { - Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2, - Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2, - Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2, - 0,0,0,0,0 -}; - -#undef Q0 -#undef Q1 -#undef Q2 - -#define Q0 ((-4 << 15) / 5.0) -#define Q1 ((-2 << 15) / 5.0) -#define Q2 (0) -#define Q3 ((2 << 15) / 5.0) -#define Q4 ((4 << 15) / 5.0) - -static const sample_t q_2_0[128] = { - Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0, - Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1, - Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2, - Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3, - Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4, - 0,0,0 -}; - -static const sample_t q_2_1[128] = { - Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, - Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, - Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, - Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, - Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, - 0,0,0 -}; - -static const sample_t q_2_2[128] = { - Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, - Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, - Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, - Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, - Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, - 0,0,0 -}; - -#undef Q0 -#undef Q1 -#undef Q2 -#undef Q3 -#undef Q4 - -static const sample_t q_3[8] = { - (-6 << 15)/7.0, (-4 << 15)/7.0, (-2 << 15)/7.0, 0, - ( 2 << 15)/7.0, ( 4 << 15)/7.0, ( 6 << 15)/7.0, 0 -}; - -#define Q0 ((-10 << 15) / 11.0) -#define Q1 ((-8 << 15) / 11.0) -#define Q2 ((-6 << 15) / 11.0) -#define Q3 ((-4 << 15) / 11.0) -#define Q4 ((-2 << 15) / 11.0) -#define Q5 (0) -#define Q6 ((2 << 15) / 11.0) -#define Q7 ((4 << 15) / 11.0) -#define Q8 ((6 << 15) / 11.0) -#define Q9 ((8 << 15) / 11.0) -#define QA ((10 << 15) / 11.0) - -static const sample_t q_4_0[128] = { - Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, - Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, - Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, - Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, - Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, - Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, - Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, - Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, - Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, - Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, - QA, QA, QA, QA, QA, QA, QA, QA, QA, QA, QA, - 0, 0, 0, 0, 0, 0, 0 -}; - -static const sample_t q_4_1[128] = { - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, - 0, 0, 0, 0, 0, 0, 0 -}; - -#undef Q0 -#undef Q1 -#undef Q2 -#undef Q3 -#undef Q4 -#undef Q5 -#undef Q6 -#undef Q7 -#undef Q8 -#undef Q9 -#undef QA - -static const sample_t q_5[16] = { - (-14 << 15)/15.0,(-12 << 15)/15.0,(-10 << 15)/15.0, - ( -8 << 15)/15.0,( -6 << 15)/15.0,( -4 << 15)/15.0, - ( -2 << 15)/15.0, 0 ,( 2 << 15)/15.0, - ( 4 << 15)/15.0,( 6 << 15)/15.0,( 8 << 15)/15.0, - ( 10 << 15)/15.0,( 12 << 15)/15.0,( 14 << 15)/15.0, - 0 -}; - -static const sample_t scale_factor[25] = { - 0.000030517578125, - 0.0000152587890625, - 0.00000762939453125, - 0.000003814697265625, - 0.0000019073486328125, - 0.00000095367431640625, - 0.000000476837158203125, - 0.0000002384185791015625, - 0.00000011920928955078125, - 0.000000059604644775390625, - 0.0000000298023223876953125, - 0.00000001490116119384765625, - 0.000000007450580596923828125, - 0.0000000037252902984619140625, - 0.00000000186264514923095703125, - 0.000000000931322574615478515625, - 0.0000000004656612873077392578125, - 0.00000000023283064365386962890625, - 0.000000000116415321826934814453125, - 0.0000000000582076609134674072265625, - 0.00000000002910383045673370361328125, - 0.000000000014551915228366851806640625, - 0.0000000000072759576141834259033203125, - 0.00000000000363797880709171295166015625, - 0.000000000001818989403545856475830078125 -}; - -static const uint16_t dither_lut[256] = { - 0x0000, 0xa011, 0xe033, 0x4022, 0x6077, 0xc066, 0x8044, 0x2055, - 0xc0ee, 0x60ff, 0x20dd, 0x80cc, 0xa099, 0x0088, 0x40aa, 0xe0bb, - 0x21cd, 0x81dc, 0xc1fe, 0x61ef, 0x41ba, 0xe1ab, 0xa189, 0x0198, - 0xe123, 0x4132, 0x0110, 0xa101, 0x8154, 0x2145, 0x6167, 0xc176, - 0x439a, 0xe38b, 0xa3a9, 0x03b8, 0x23ed, 0x83fc, 0xc3de, 0x63cf, - 0x8374, 0x2365, 0x6347, 0xc356, 0xe303, 0x4312, 0x0330, 0xa321, - 0x6257, 0xc246, 0x8264, 0x2275, 0x0220, 0xa231, 0xe213, 0x4202, - 0xa2b9, 0x02a8, 0x428a, 0xe29b, 0xc2ce, 0x62df, 0x22fd, 0x82ec, - 0x8734, 0x2725, 0x6707, 0xc716, 0xe743, 0x4752, 0x0770, 0xa761, - 0x47da, 0xe7cb, 0xa7e9, 0x07f8, 0x27ad, 0x87bc, 0xc79e, 0x678f, - 0xa6f9, 0x06e8, 0x46ca, 0xe6db, 0xc68e, 0x669f, 0x26bd, 0x86ac, - 0x6617, 0xc606, 0x8624, 0x2635, 0x0660, 0xa671, 0xe653, 0x4642, - 0xc4ae, 0x64bf, 0x249d, 0x848c, 0xa4d9, 0x04c8, 0x44ea, 0xe4fb, - 0x0440, 0xa451, 0xe473, 0x4462, 0x6437, 0xc426, 0x8404, 0x2415, - 0xe563, 0x4572, 0x0550, 0xa541, 0x8514, 0x2505, 0x6527, 0xc536, - 0x258d, 0x859c, 0xc5be, 0x65af, 0x45fa, 0xe5eb, 0xa5c9, 0x05d8, - 0xae79, 0x0e68, 0x4e4a, 0xee5b, 0xce0e, 0x6e1f, 0x2e3d, 0x8e2c, - 0x6e97, 0xce86, 0x8ea4, 0x2eb5, 0x0ee0, 0xaef1, 0xeed3, 0x4ec2, - 0x8fb4, 0x2fa5, 0x6f87, 0xcf96, 0xefc3, 0x4fd2, 0x0ff0, 0xafe1, - 0x4f5a, 0xef4b, 0xaf69, 0x0f78, 0x2f2d, 0x8f3c, 0xcf1e, 0x6f0f, - 0xede3, 0x4df2, 0x0dd0, 0xadc1, 0x8d94, 0x2d85, 0x6da7, 0xcdb6, - 0x2d0d, 0x8d1c, 0xcd3e, 0x6d2f, 0x4d7a, 0xed6b, 0xad49, 0x0d58, - 0xcc2e, 0x6c3f, 0x2c1d, 0x8c0c, 0xac59, 0x0c48, 0x4c6a, 0xec7b, - 0x0cc0, 0xacd1, 0xecf3, 0x4ce2, 0x6cb7, 0xcca6, 0x8c84, 0x2c95, - 0x294d, 0x895c, 0xc97e, 0x696f, 0x493a, 0xe92b, 0xa909, 0x0918, - 0xe9a3, 0x49b2, 0x0990, 0xa981, 0x89d4, 0x29c5, 0x69e7, 0xc9f6, - 0x0880, 0xa891, 0xe8b3, 0x48a2, 0x68f7, 0xc8e6, 0x88c4, 0x28d5, - 0xc86e, 0x687f, 0x285d, 0x884c, 0xa819, 0x0808, 0x482a, 0xe83b, - 0x6ad7, 0xcac6, 0x8ae4, 0x2af5, 0x0aa0, 0xaab1, 0xea93, 0x4a82, - 0xaa39, 0x0a28, 0x4a0a, 0xea1b, 0xca4e, 0x6a5f, 0x2a7d, 0x8a6c, - 0x4b1a, 0xeb0b, 0xab29, 0x0b38, 0x2b6d, 0x8b7c, 0xcb5e, 0x6b4f, - 0x8bf4, 0x2be5, 0x6bc7, 0xcbd6, 0xeb83, 0x4b92, 0x0bb0, 0xaba1 -}; +/* + * tables.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 + */ + +static const int8_t exp_1[128] = { + -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 25,25,25 +}; +static const int8_t exp_2[128] = { + -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + 25,25,25 +}; +static const int8_t exp_3[128] = { + -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, + -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, + -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, + -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, + -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, + 25,25,25 +}; + +#define Q0 ((-2 << 15) / 3.0) +#define Q1 (0) +#define Q2 ((2 << 15) / 3.0) + +static const sample_t q_1_0[32] = { + Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0, + Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1, + Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2, + 0,0,0,0,0 +}; + +static const sample_t q_1_1[32] = { + Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2, + Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2, + Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2, + 0,0,0,0,0 +}; + +static const sample_t q_1_2[32] = { + Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2, + Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2, + Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2, + 0,0,0,0,0 +}; + +#undef Q0 +#undef Q1 +#undef Q2 + +#define Q0 ((-4 << 15) / 5.0) +#define Q1 ((-2 << 15) / 5.0) +#define Q2 (0) +#define Q3 ((2 << 15) / 5.0) +#define Q4 ((4 << 15) / 5.0) + +static const sample_t q_2_0[128] = { + Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0, + Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1, + Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2, + Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3, + Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4, + 0,0,0 +}; + +static const sample_t q_2_1[128] = { + Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, + Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, + Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, + Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, + Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, + 0,0,0 +}; + +static const sample_t q_2_2[128] = { + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + 0,0,0 +}; + +#undef Q0 +#undef Q1 +#undef Q2 +#undef Q3 +#undef Q4 + +static const sample_t q_3[8] = { + (-6 << 15)/7.0, (-4 << 15)/7.0, (-2 << 15)/7.0, 0, + ( 2 << 15)/7.0, ( 4 << 15)/7.0, ( 6 << 15)/7.0, 0 +}; + +#define Q0 ((-10 << 15) / 11.0) +#define Q1 ((-8 << 15) / 11.0) +#define Q2 ((-6 << 15) / 11.0) +#define Q3 ((-4 << 15) / 11.0) +#define Q4 ((-2 << 15) / 11.0) +#define Q5 (0) +#define Q6 ((2 << 15) / 11.0) +#define Q7 ((4 << 15) / 11.0) +#define Q8 ((6 << 15) / 11.0) +#define Q9 ((8 << 15) / 11.0) +#define QA ((10 << 15) / 11.0) + +static const sample_t q_4_0[128] = { + Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, + Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, + Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, + Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, + Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, + Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, + Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, + Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, + Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, + Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, + QA, QA, QA, QA, QA, QA, QA, QA, QA, QA, QA, + 0, 0, 0, 0, 0, 0, 0 +}; + +static const sample_t q_4_1[128] = { + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + 0, 0, 0, 0, 0, 0, 0 +}; + +#undef Q0 +#undef Q1 +#undef Q2 +#undef Q3 +#undef Q4 +#undef Q5 +#undef Q6 +#undef Q7 +#undef Q8 +#undef Q9 +#undef QA + +static const sample_t q_5[16] = { + (-14 << 15)/15.0,(-12 << 15)/15.0,(-10 << 15)/15.0, + ( -8 << 15)/15.0,( -6 << 15)/15.0,( -4 << 15)/15.0, + ( -2 << 15)/15.0, 0 ,( 2 << 15)/15.0, + ( 4 << 15)/15.0,( 6 << 15)/15.0,( 8 << 15)/15.0, + ( 10 << 15)/15.0,( 12 << 15)/15.0,( 14 << 15)/15.0, + 0 +}; + +static const sample_t scale_factor[25] = { + 0.000030517578125, + 0.0000152587890625, + 0.00000762939453125, + 0.000003814697265625, + 0.0000019073486328125, + 0.00000095367431640625, + 0.000000476837158203125, + 0.0000002384185791015625, + 0.00000011920928955078125, + 0.000000059604644775390625, + 0.0000000298023223876953125, + 0.00000001490116119384765625, + 0.000000007450580596923828125, + 0.0000000037252902984619140625, + 0.00000000186264514923095703125, + 0.000000000931322574615478515625, + 0.0000000004656612873077392578125, + 0.00000000023283064365386962890625, + 0.000000000116415321826934814453125, + 0.0000000000582076609134674072265625, + 0.00000000002910383045673370361328125, + 0.000000000014551915228366851806640625, + 0.0000000000072759576141834259033203125, + 0.00000000000363797880709171295166015625, + 0.000000000001818989403545856475830078125 +}; + +static const uint16_t dither_lut[256] = { + 0x0000, 0xa011, 0xe033, 0x4022, 0x6077, 0xc066, 0x8044, 0x2055, + 0xc0ee, 0x60ff, 0x20dd, 0x80cc, 0xa099, 0x0088, 0x40aa, 0xe0bb, + 0x21cd, 0x81dc, 0xc1fe, 0x61ef, 0x41ba, 0xe1ab, 0xa189, 0x0198, + 0xe123, 0x4132, 0x0110, 0xa101, 0x8154, 0x2145, 0x6167, 0xc176, + 0x439a, 0xe38b, 0xa3a9, 0x03b8, 0x23ed, 0x83fc, 0xc3de, 0x63cf, + 0x8374, 0x2365, 0x6347, 0xc356, 0xe303, 0x4312, 0x0330, 0xa321, + 0x6257, 0xc246, 0x8264, 0x2275, 0x0220, 0xa231, 0xe213, 0x4202, + 0xa2b9, 0x02a8, 0x428a, 0xe29b, 0xc2ce, 0x62df, 0x22fd, 0x82ec, + 0x8734, 0x2725, 0x6707, 0xc716, 0xe743, 0x4752, 0x0770, 0xa761, + 0x47da, 0xe7cb, 0xa7e9, 0x07f8, 0x27ad, 0x87bc, 0xc79e, 0x678f, + 0xa6f9, 0x06e8, 0x46ca, 0xe6db, 0xc68e, 0x669f, 0x26bd, 0x86ac, + 0x6617, 0xc606, 0x8624, 0x2635, 0x0660, 0xa671, 0xe653, 0x4642, + 0xc4ae, 0x64bf, 0x249d, 0x848c, 0xa4d9, 0x04c8, 0x44ea, 0xe4fb, + 0x0440, 0xa451, 0xe473, 0x4462, 0x6437, 0xc426, 0x8404, 0x2415, + 0xe563, 0x4572, 0x0550, 0xa541, 0x8514, 0x2505, 0x6527, 0xc536, + 0x258d, 0x859c, 0xc5be, 0x65af, 0x45fa, 0xe5eb, 0xa5c9, 0x05d8, + 0xae79, 0x0e68, 0x4e4a, 0xee5b, 0xce0e, 0x6e1f, 0x2e3d, 0x8e2c, + 0x6e97, 0xce86, 0x8ea4, 0x2eb5, 0x0ee0, 0xaef1, 0xeed3, 0x4ec2, + 0x8fb4, 0x2fa5, 0x6f87, 0xcf96, 0xefc3, 0x4fd2, 0x0ff0, 0xafe1, + 0x4f5a, 0xef4b, 0xaf69, 0x0f78, 0x2f2d, 0x8f3c, 0xcf1e, 0x6f0f, + 0xede3, 0x4df2, 0x0dd0, 0xadc1, 0x8d94, 0x2d85, 0x6da7, 0xcdb6, + 0x2d0d, 0x8d1c, 0xcd3e, 0x6d2f, 0x4d7a, 0xed6b, 0xad49, 0x0d58, + 0xcc2e, 0x6c3f, 0x2c1d, 0x8c0c, 0xac59, 0x0c48, 0x4c6a, 0xec7b, + 0x0cc0, 0xacd1, 0xecf3, 0x4ce2, 0x6cb7, 0xcca6, 0x8c84, 0x2c95, + 0x294d, 0x895c, 0xc97e, 0x696f, 0x493a, 0xe92b, 0xa909, 0x0918, + 0xe9a3, 0x49b2, 0x0990, 0xa981, 0x89d4, 0x29c5, 0x69e7, 0xc9f6, + 0x0880, 0xa891, 0xe8b3, 0x48a2, 0x68f7, 0xc8e6, 0x88c4, 0x28d5, + 0xc86e, 0x687f, 0x285d, 0x884c, 0xa819, 0x0808, 0x482a, 0xe83b, + 0x6ad7, 0xcac6, 0x8ae4, 0x2af5, 0x0aa0, 0xaab1, 0xea93, 0x4a82, + 0xaa39, 0x0a28, 0x4a0a, 0xea1b, 0xca4e, 0x6a5f, 0x2a7d, 0x8a6c, + 0x4b1a, 0xeb0b, 0xab29, 0x0b38, 0x2b6d, 0x8b7c, 0xcb5e, 0x6b4f, + 0x8bf4, 0x2be5, 0x6bc7, 0xcbd6, 0xeb83, 0x4b92, 0x0bb0, 0xaba1 +}; diff --git a/plugins/spu2ghz/src/3rdparty/liba52/tendra.h b/plugins/spu2ghz/src/3rdparty/liba52/tendra.h index c2b1b62a55..41f825a8d6 100644 --- a/plugins/spu2ghz/src/3rdparty/liba52/tendra.h +++ b/plugins/spu2ghz/src/3rdparty/liba52/tendra.h @@ -1,35 +1,35 @@ -/* - * tendra.h - * Copyright (C) 2000-2002 Michel Lespinasse - * Copyright (C) 1999-2000 Aaron Holtzman - * - * This file is part of a52dec, a free ATSC A-52 stream decoder. - * See http://liba52.sourceforge.net/ for updates. - * - * a52dec 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. - * - * a52dec 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 - */ - -#pragma TenDRA begin -#pragma TenDRA longlong type warning - -#ifdef TenDRA_check - -#pragma TenDRA conversion analysis (pointer-int explicit) off -#pragma TenDRA implicit function declaration off - -/* avoid the "No declarations in translation unit" problem */ -int TenDRA; - -#endif /* TenDRA_check */ +/* + * tendra.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 + */ + +#pragma TenDRA begin +#pragma TenDRA longlong type warning + +#ifdef TenDRA_check + +#pragma TenDRA conversion analysis (pointer-int explicit) off +#pragma TenDRA implicit function declaration off + +/* avoid the "No declarations in translation unit" problem */ +int TenDRA; + +#endif /* TenDRA_check */ diff --git a/plugins/spu2ghz/src/Win32/SPU2ghz_vs2008.vcproj b/plugins/spu2ghz/src/Win32/SPU2ghz_vs2008.vcproj index 0ba6fea770..2f858fccf8 100644 --- a/plugins/spu2ghz/src/Win32/SPU2ghz_vs2008.vcproj +++ b/plugins/spu2ghz/src/Win32/SPU2ghz_vs2008.vcproj @@ -473,7 +473,6 @@ @@ -619,7 +618,6 @@ @@ -852,14 +850,26 @@ RelativePath="..\defs.h" > + + + + + + @@ -888,7 +898,6 @@ diff --git a/plugins/spu2ghz/src/Win32/config.cpp b/plugins/spu2ghz/src/Win32/config.cpp index 704ca90b21..35dbed8505 100644 --- a/plugins/spu2ghz/src/Win32/config.cpp +++ b/plugins/spu2ghz/src/Win32/config.cpp @@ -1,618 +1,618 @@ -///GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// - -#include "spu2.h" -#include "dialogs.h" -// Config Vars - - -static bool VolumeBoostEnabled = false; -static int VolumeShiftModifier = 0; - -#ifndef PUBLIC -static const int LATENCY_MAX = 2000; -#else -static const int LATENCY_MAX = 500; -#endif - -static const int LATENCY_MIN = 40; - - -// DEBUG - -bool DebugEnabled=false; -bool _MsgToConsole=false; -bool _MsgKeyOnOff=false; -bool _MsgVoiceOff=false; -bool _MsgDMA=false; -bool _MsgAutoDMA=false; -bool _MsgOverruns=false; -bool _MsgCache=false; - -bool _AccessLog=false; -bool _DMALog=false; -bool _WaveLog=false; - -bool _CoresDump=false; -bool _MemDump=false; -bool _RegDump=false; - - - -char AccessLogFileName[255]; -char WaveLogFileName[255]; - -char DMA4LogFileName[255]; -char DMA7LogFileName[255]; - -char CoresDumpFileName[255]; -char MemDumpFileName[255]; -char RegDumpFileName[255]; - -int WaveDumpFormat; - -int AutoDMAPlayRate[2]={0,0}; - -// MIXING -int Interpolation=1; -/* values: - 0: no interpolation (use nearest) - 1. linear interpolation - 2. cubic interpolation -*/ - -bool EffectsEnabled=false; - -// OUTPUT -int SampleRate=48000; -int SndOutLatencyMS=160; -//int SndOutLatency=1024; -//int MaxBufferCount=8; -//int CurBufferCount=MaxBufferCount; -bool timeStretchEnabled=true; - -u32 OutputModule=0; //OUTPUT_DSOUND; - -//int VolumeMultiplier=1; -//int VolumeDivisor=1; - -int LimitMode=0; -/* values: - 0. No limiter - 1. Soft limiter -- less cpu-intensive, but can cause problems - 2. Hard limiter -- more cpu-intensive while limiting, but should give better (constant) speeds -*/ - - -CONFIG_DSOUNDOUT Config_DSoundOut; -CONFIG_DSOUND51 Config_DSound51; -CONFIG_WAVEOUT Config_WaveOut; - -// MISC -bool LimiterToggleEnabled=false; -int LimiterToggle=VK_SUBTRACT; - -// DSP -bool dspPluginEnabled=false; -char dspPlugin[256]; -int dspPluginModule=0; - -// OUTPUT MODULES -char AsioDriver[129]=""; - - -////// - -const char NewCfgFile[]="inis\\SPU2Ghz-v2.ini"; -const char LegacyCfgFile[]="inis\\SPU2Ghz.ini"; -const char* CfgFile=NewCfgFile; - - - /*| Config File Format: |¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*\ -+--+---------------------+------------------------+ -| | -| Option=Value | -| | -| | -| Boolean Values: TRUE,YES,1,T,Y mean 'true', | -| everything else means 'false'. | -| | -| All Values are limited to 255 chars. | -| | -+-------------------------------------------------+ - \*_____________________________________________*/ - - -void CfgWriteBool(const char *Section, const char*Name, bool Value) { - char *Data=Value?"TRUE":"FALSE"; - - WritePrivateProfileString(Section,Name,Data,CfgFile); -} - -void CfgWriteInt(const char *Section, const char*Name, int Value) { - char Data[255]; - _itoa(Value,Data,10); - - WritePrivateProfileString(Section,Name,Data,CfgFile); -} - -void CfgWriteStr(const char *Section, const char* Name, const char *Data) { - WritePrivateProfileString(Section,Name,Data,CfgFile); -} - -/*****************************************************************************/ - -bool CfgReadBool(const char *Section,const char *Name,bool Default) { - char Data[255]=""; - GetPrivateProfileString(Section,Name,"",Data,255,CfgFile); - Data[254]=0; - if(strlen(Data)==0) { - CfgWriteBool(Section,Name,Default); - return Default; - } - - if(strcmp(Data,"1")==0) return true; - if(strcmp(Data,"Y")==0) return true; - if(strcmp(Data,"T")==0) return true; - if(strcmp(Data,"YES")==0) return true; - if(strcmp(Data,"TRUE")==0) return true; - return false; -} - - -int CfgReadInt(const char *Section, const char*Name,int Default) { - char Data[255]=""; - GetPrivateProfileString(Section,Name,"",Data,255,CfgFile); - Data[254]=0; - - if(strlen(Data)==0) { - CfgWriteInt(Section,Name,Default); - return Default; - } - - return atoi(Data); -} - - -void CfgReadStr(const char *Section, const char* Name, char *Data, int DataSize, const char *Default) { - GetPrivateProfileString(Section,Name,"",Data,DataSize,CfgFile); - - if(strlen(Data)==0) { - sprintf_s( Data, DataSize, "%s", Default ); - CfgWriteStr(Section,Name,Data); - } -} - -// Tries to read the requested value. -// Returns FALSE if the value isn't found. -bool CfgFindName( const char *Section, const char* Name) -{ - // Only load 24 characters. No need to load more. - char Data[24]=""; - GetPrivateProfileString(Section,Name,"",Data,24,CfgFile); - Data[23]=0; - - if(strlen(Data)==0) return false; - return true; -} -/*****************************************************************************/ - -void ReadSettings() -{ - DebugEnabled=CfgReadBool("DEBUG","Global_Debug_Enabled",0); - _MsgToConsole=CfgReadBool("DEBUG","Show_Messages",0); - _MsgKeyOnOff =CfgReadBool("DEBUG","Show_Messages_Key_On_Off",0); - _MsgVoiceOff =CfgReadBool("DEBUG","Show_Messages_Voice_Off",0); - _MsgDMA =CfgReadBool("DEBUG","Show_Messages_DMA_Transfer",0); - _MsgAutoDMA =CfgReadBool("DEBUG","Show_Messages_AutoDMA",0); - _MsgOverruns =CfgReadBool("DEBUG","Show_Messages_Overruns",0); - _MsgCache =CfgReadBool("DEBUG","Show_Messages_CacheStats",0); - - _AccessLog =CfgReadBool("DEBUG","Log_Register_Access",0); - _DMALog =CfgReadBool("DEBUG","Log_DMA_Transfers",0); - _WaveLog =CfgReadBool("DEBUG","Log_WAVE_Output",0); - - _CoresDump =CfgReadBool("DEBUG","Dump_Info",0); - _MemDump =CfgReadBool("DEBUG","Dump_Memory",0); - _RegDump =CfgReadBool("DEBUG","Dump_Regs",0); - - CfgReadStr("DEBUG","Access_Log_Filename",AccessLogFileName,255,"logs\\SPU2Log.txt"); - CfgReadStr("DEBUG","WaveLog_Filename", WaveLogFileName, 255,"logs\\SPU2log.wav"); - CfgReadStr("DEBUG","DMA4Log_Filename", DMA4LogFileName, 255,"logs\\SPU2dma4.dat"); - CfgReadStr("DEBUG","DMA7Log_Filename", DMA7LogFileName, 255,"logs\\SPU2dma7.dat"); - - CfgReadStr("DEBUG","Info_Dump_Filename",CoresDumpFileName,255,"logs\\SPU2Cores.txt"); - CfgReadStr("DEBUG","Mem_Dump_Filename", MemDumpFileName, 255,"logs\\SPU2mem.dat"); - CfgReadStr("DEBUG","Reg_Dump_Filename", RegDumpFileName, 255,"logs\\SPU2regs.dat"); - - WaveDumpFormat=CfgReadInt("DEBUG","Wave_Log_Format",0); - - - AutoDMAPlayRate[0]=CfgReadInt("MIXING","AutoDMA_Play_Rate_0",0); - AutoDMAPlayRate[1]=CfgReadInt("MIXING","AutoDMA_Play_Rate_1",0); - - Interpolation=CfgReadInt("MIXING","Interpolation",1); - - // Moved Timestretch from DSP to Output - timeStretchEnabled = CfgReadBool( - CfgFindName( "OUTPUT", "Timestretch_Enable" ) ? "OUTPUT" : "DSP", - "Timestretch_Enable", true - ); - - // Moved Effects_Enable from Effects to Mixing - EffectsEnabled = CfgReadBool( - CfgFindName( "MIXING", "Enable_Effects" ) ? "MIXING" : "EFFECTS", - "Enable_Effects", false - ); - EffectsEnabled = false; // force disabled for now. - - SampleRate=CfgReadInt("OUTPUT","Sample_Rate",48000); - SndOutLatencyMS=CfgReadInt("OUTPUT","Latency", 160); - - //OutputModule = CfgReadInt("OUTPUT","Output_Module", OUTPUT_DSOUND ); - char omodid[128]; - CfgReadStr( "OUTPUT", "Output_Module", omodid, 127, XAudio2Out->GetIdent() ); - - // find the driver index of this module: - OutputModule = FindOutputModuleById( omodid ); - - VolumeShiftModifier = CfgReadInt( "OUTPUT","Volume_Shift", 0 ); - LimitMode=CfgReadInt("OUTPUT","Speed_Limit_Mode",0); - - CfgReadStr("DSP PLUGIN","Filename",dspPlugin,255,""); - dspPluginModule = CfgReadInt("DSP PLUGIN","ModuleNum",0); - dspPluginEnabled= CfgReadBool("DSP PLUGIN","Enabled",false); - - LimiterToggleEnabled = CfgReadBool("KEYS","Limiter_Toggle_Enabled",false); - LimiterToggle = CfgReadInt ("KEYS","Limiter_Toggle",VK_SUBTRACT); - - // Read DSOUNDOUT and WAVEOUT configs: - CfgReadStr( "DSOUNDOUT", "Device", Config_DSoundOut.Device, 254, "default" ); - CfgReadStr( "WAVEOUT", "Device", Config_WaveOut.Device, 254, "default" ); - Config_DSoundOut.NumBuffers = CfgReadInt( "DSOUNDOUT", "Buffer_Count", 5 ); - Config_WaveOut.NumBuffers = CfgReadInt( "WAVEOUT", "Buffer_Count", 4 ); - - // Read DSOUND51 config: - CfgReadStr( "DSOUND51", "Device", Config_DSound51.Device, 254, "default" ); - Config_DSound51.NumBuffers = CfgReadInt( "DSOUND51", "Buffer_Count", 5 ); - Config_DSound51.GainL =CfgReadInt("DSOUND51","Channel_Gain_L", 256); - Config_DSound51.GainR =CfgReadInt("DSOUND51","Channel_Gain_R", 256); - Config_DSound51.GainC =CfgReadInt("DSOUND51","Channel_Gain_C", 256); - Config_DSound51.GainLFE=CfgReadInt("DSOUND51","Channel_Gain_LFE",256); - Config_DSound51.GainSL =CfgReadInt("DSOUND51","Channel_Gain_SL", 200); - Config_DSound51.GainSR =CfgReadInt("DSOUND51","Channel_Gain_SR", 200); - Config_DSound51.AddCLR =CfgReadInt("DSOUND51","Channel_Center_In_LR", 56); - Config_DSound51.LowpassLFE = CfgReadInt("DSOUND51","LFE_Lowpass_Frequency", 80); - - // Sanity Checks - // ------------- - - SampleRate = 48000; // Yup nothing else is supported for now. - VolumeShiftModifier = min( max( VolumeShiftModifier, -2 ), 2 ); - SndOutVolumeShift = SndOutVolumeShiftBase - VolumeShiftModifier; - SndOutLatencyMS = min( max( SndOutLatencyMS, LATENCY_MIN ), LATENCY_MAX ); - - Config_DSoundOut.NumBuffers = min( max( Config_DSoundOut.NumBuffers, 2 ), 8 ); - Config_WaveOut.NumBuffers = min( max( Config_DSoundOut.NumBuffers, 3 ), 8 ); - - if( mods[OutputModule] == NULL ) - { - // Unsupported or legacy module. - fprintf( stderr, " * SPU2: Unknown output module '%s' specified in configuration file.\n", omodid ); - fprintf( stderr, " * SPU2: Defaulting to DirectSound (%s).\n", DSoundOut->GetIdent() ); - OutputModule = FindOutputModuleById( DSoundOut->GetIdent() ); - } - - -} - -/*****************************************************************************/ - -void WriteSettings() -{ - CfgWriteBool("DEBUG","Global_Debug_Enabled",DebugEnabled); - - // [Air] : Commented out so that we retain debug settings even if disabled... - //if(DebugEnabled) - { - CfgWriteBool("DEBUG","Show_Messages", _MsgToConsole); - CfgWriteBool("DEBUG","Show_Messages_Key_On_Off", _MsgKeyOnOff); - CfgWriteBool("DEBUG","Show_Messages_Voice_Off", _MsgVoiceOff); - CfgWriteBool("DEBUG","Show_Messages_DMA_Transfer",_MsgDMA); - CfgWriteBool("DEBUG","Show_Messages_AutoDMA", _MsgAutoDMA); - CfgWriteBool("DEBUG","Show_Messages_Overruns", _MsgOverruns); - CfgWriteBool("DEBUG","Show_Messages_CacheStats", _MsgCache); - - CfgWriteBool("DEBUG","Log_Register_Access",_AccessLog); - CfgWriteBool("DEBUG","Log_DMA_Transfers", _DMALog); - CfgWriteBool("DEBUG","Log_WAVE_Output", _WaveLog); - - CfgWriteBool("DEBUG","Dump_Info", _CoresDump); - CfgWriteBool("DEBUG","Dump_Memory",_MemDump); - CfgWriteBool("DEBUG","Dump_Regs", _RegDump); - - CfgWriteStr("DEBUG","Access_Log_Filename",AccessLogFileName); - CfgWriteStr("DEBUG","WaveLog_Filename", WaveLogFileName); - CfgWriteStr("DEBUG","DMA4Log_Filename", DMA4LogFileName); - CfgWriteStr("DEBUG","DMA7Log_Filename", DMA7LogFileName); - - CfgWriteStr("DEBUG","Info_Dump_Filename",CoresDumpFileName); - CfgWriteStr("DEBUG","Mem_Dump_Filename", MemDumpFileName); - CfgWriteStr("DEBUG","Reg_Dump_Filename", RegDumpFileName); - - CfgWriteInt("DEBUG","Wave_Log_Format", WaveDumpFormat); - } - - CfgWriteInt("MIXING","Interpolation",Interpolation); - - CfgWriteInt("MIXING","AutoDMA_Play_Rate_0",AutoDMAPlayRate[0]); - CfgWriteInt("MIXING","AutoDMA_Play_Rate_1",AutoDMAPlayRate[1]); - - CfgWriteBool("MIXING","Enable_Effects",EffectsEnabled); - - CfgWriteStr("OUTPUT","Output_Module",mods[OutputModule]->GetIdent() ); - CfgWriteInt("OUTPUT","Sample_Rate",SampleRate); - CfgWriteInt("OUTPUT","Latency",SndOutLatencyMS); - CfgWriteBool("OUTPUT","Timestretch_Enable",timeStretchEnabled); - CfgWriteInt("OUTPUT","Speed_Limit_Mode",LimitMode); - - CfgWriteInt("OUTPUT","Volume_Shift",SndOutVolumeShiftBase - SndOutVolumeShift); - - if( strlen( Config_DSoundOut.Device ) == 0 ) strcpy( Config_DSoundOut.Device, "default" ); - if( strlen( Config_DSound51.Device ) == 0 ) strcpy( Config_DSound51.Device, "default" ); - if( strlen( Config_WaveOut.Device ) == 0 ) strcpy( Config_WaveOut.Device, "default" ); - - CfgWriteStr("DSOUNDOUT","Device",Config_DSoundOut.Device); - CfgWriteInt("DSOUNDOUT","Buffer_Count",Config_DSoundOut.NumBuffers); - - CfgWriteStr("WAVEOUT","Device",Config_WaveOut.Device); - CfgWriteInt("WAVEOUT","Buffer_Count",Config_WaveOut.NumBuffers); - - CfgWriteStr("DSOUND51","Device",Config_DSound51.Device); - CfgWriteInt("DSOUND51","Buffer_Count", Config_DSound51.NumBuffers); - CfgWriteInt("DSOUND51","Channel_Gain_L", Config_DSound51.GainL); - CfgWriteInt("DSOUND51","Channel_Gain_R", Config_DSound51.GainR); - CfgWriteInt("DSOUND51","Channel_Gain_C", Config_DSound51.GainC); - CfgWriteInt("DSOUND51","Channel_Gain_LFE",Config_DSound51.GainLFE); - CfgWriteInt("DSOUND51","Channel_Gain_SL", Config_DSound51.GainSL); - CfgWriteInt("DSOUND51","Channel_Gain_SR", Config_DSound51.GainSR); - CfgWriteInt("DSOUND51","Channel_Center_In_LR", Config_DSound51.AddCLR); - CfgWriteInt("DSOUND51","LFE_Lowpass_Frequency", Config_DSound51.LowpassLFE); - - CfgWriteStr("DSP PLUGIN","Filename",dspPlugin); - CfgWriteInt("DSP PLUGIN","ModuleNum",dspPluginModule); - CfgWriteBool("DSP PLUGIN","Enabled",dspPluginEnabled); - - CfgWriteBool("KEYS","Limiter_Toggle_Enabled",LimiterToggleEnabled); - CfgWriteInt ("KEYS","Limiter_Toggle",LimiterToggle); -} - -static void EnableDebugMessages( HWND hWnd ) -{ - ENABLE_CONTROL(IDC_MSGSHOW, DebugEnabled); - ENABLE_CONTROL(IDC_MSGKEY, MsgToConsole()); - ENABLE_CONTROL(IDC_MSGVOICE,MsgToConsole()); - ENABLE_CONTROL(IDC_MSGDMA, MsgToConsole()); - ENABLE_CONTROL(IDC_MSGADMA, MsgDMA()); - ENABLE_CONTROL(IDC_DBG_OVERRUNS, MsgToConsole()); - ENABLE_CONTROL(IDC_DBG_CACHE, MsgToConsole()); -} - -static void EnableDebugControls( HWND hWnd ) -{ - EnableDebugMessages( hWnd ); - ENABLE_CONTROL(IDC_LOGREGS, DebugEnabled); - ENABLE_CONTROL(IDC_LOGDMA, DebugEnabled); - ENABLE_CONTROL(IDC_LOGWAVE, DebugEnabled); - ENABLE_CONTROL(IDC_DUMPCORE,DebugEnabled); - ENABLE_CONTROL(IDC_DUMPMEM, DebugEnabled); - ENABLE_CONTROL(IDC_DUMPREGS,DebugEnabled); -} - -static int myWidth, myDebugWidth; -static int myHeight; -static bool debugShow = false; - -BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) -{ - int wmId,wmEvent; - char temp[384]={0}; - - switch(uMsg) - { - - case WM_PAINT: - return FALSE; - - case WM_INITDIALOG: - - // If debugging is enabled, show the debug box by default: - debugShow = DebugEnabled; - - SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_RESETCONTENT,0,0); - SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"16000"); - SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"22050"); - SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"24000"); - SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"32000"); - SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"44100"); - SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"48000"); - - sprintf_s(temp,48,"%d",SampleRate); - SetDlgItemText(hWnd,IDC_SRATE,temp); - - SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_RESETCONTENT,0,0); - SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"0 - Nearest (none/fast)"); - SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"1 - Linear (recommended)"); - SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"2 - Cubic (better/slower)"); - SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_SETCURSEL,Interpolation,0); - - SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_RESETCONTENT,0,0); - - { - int modidx = 0; - while( mods[modidx] != NULL ) - { - sprintf_s( temp, 72, "%d - %s", modidx, mods[modidx]->GetLongName() ); - SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)temp); - ++modidx; - } - SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_SETCURSEL,OutputModule,0); - } - - //INIT_SLIDER(IDC_BUFFER,512,16384,4096,2048,512); - INIT_SLIDER( IDC_LATENCY_SLIDER, LATENCY_MIN, LATENCY_MAX, 100, 20, 5 ); - - SendMessage(GetDlgItem(hWnd,IDC_LATENCY_SLIDER),TBM_SETPOS,TRUE,SndOutLatencyMS); - sprintf_s(temp,80,"%d ms (avg)",SndOutLatencyMS); - SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp); - - EnableDebugControls( hWnd ); - - // Debugging / Logging Flags: - SET_CHECK(IDC_EFFECTS, EffectsEnabled); - SET_CHECK(IDC_DEBUG, DebugEnabled); - SET_CHECK(IDC_MSGSHOW, _MsgToConsole); - SET_CHECK(IDC_MSGKEY, _MsgKeyOnOff); - SET_CHECK(IDC_MSGVOICE,_MsgVoiceOff); - SET_CHECK(IDC_MSGDMA, _MsgDMA); - SET_CHECK(IDC_MSGADMA, _MsgAutoDMA); - SET_CHECK(IDC_DBG_OVERRUNS, _MsgOverruns ); - SET_CHECK(IDC_DBG_CACHE, _MsgCache ); - SET_CHECK(IDC_LOGREGS, _AccessLog); - SET_CHECK(IDC_LOGDMA, _DMALog); - SET_CHECK(IDC_LOGWAVE, _WaveLog); - SET_CHECK(IDC_DUMPCORE,_CoresDump); - SET_CHECK(IDC_DUMPMEM, _MemDump); - SET_CHECK(IDC_DUMPREGS,_RegDump); - - SET_CHECK(IDC_SPEEDLIMIT,LimitMode); - SET_CHECK(IDC_SPEEDLIMIT_RUNTIME_TOGGLE,LimiterToggleEnabled); - SET_CHECK(IDC_DSP_ENABLE,dspPluginEnabled); - SET_CHECK(IDC_TS_ENABLE,timeStretchEnabled); - - VolumeBoostEnabled = ( VolumeShiftModifier > 0 ) ? true : false; - SET_CHECK(IDC_VOLBOOST, VolumeBoostEnabled ); - - break; - - case WM_COMMAND: - wmId = LOWORD(wParam); - wmEvent = HIWORD(wParam); - // Parse the menu selections: - switch (wmId) - { - case IDOK: - GetDlgItemText(hWnd,IDC_SRATE,temp,20); - temp[19]=0; - SampleRate=atoi(temp); - - SndOutLatencyMS = (int)SendMessage( GetDlgItem( hWnd, IDC_LATENCY_SLIDER ), TBM_GETPOS, 0, 0 ); - - if( SndOutLatencyMS > LATENCY_MAX ) SndOutLatencyMS = LATENCY_MAX; - if( SndOutLatencyMS < LATENCY_MIN ) SndOutLatencyMS = LATENCY_MIN; - - Interpolation=(int)SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_GETCURSEL,0,0); - OutputModule=(int)SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_GETCURSEL,0,0); - - WriteSettings(); - EndDialog(hWnd,0); - break; - case IDCANCEL: - EndDialog(hWnd,0); - break; - - case IDC_OUTCONF: - SndConfigure( hWnd, - (int)SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_GETCURSEL,0,0) - ); - break; - - HANDLE_CHECKNB( IDC_VOLBOOST, VolumeBoostEnabled ); - VolumeShiftModifier = (VolumeBoostEnabled ? 1 : 0 ); - SndOutVolumeShift = SndOutVolumeShiftBase - VolumeShiftModifier; - break; - - HANDLE_CHECK(IDC_EFFECTS,EffectsEnabled); - HANDLE_CHECKNB(IDC_DEBUG,DebugEnabled); - EnableDebugControls( hWnd ); - break; - HANDLE_CHECKNB(IDC_MSGSHOW,_MsgToConsole); - EnableDebugMessages( hWnd ); - break; - HANDLE_CHECK(IDC_MSGKEY,_MsgKeyOnOff); - HANDLE_CHECK(IDC_MSGVOICE,_MsgVoiceOff); - HANDLE_CHECKNB(IDC_MSGDMA,_MsgDMA); - ENABLE_CONTROL(IDC_MSGADMA, MsgDMA()); - break; - HANDLE_CHECK(IDC_MSGADMA,_MsgAutoDMA); - HANDLE_CHECK(IDC_DBG_OVERRUNS,_MsgOverruns); - HANDLE_CHECK(IDC_DBG_CACHE,_MsgCache); - HANDLE_CHECK(IDC_LOGREGS,_AccessLog); - HANDLE_CHECK(IDC_LOGDMA, _DMALog); - HANDLE_CHECK(IDC_LOGWAVE,_WaveLog); - HANDLE_CHECK(IDC_DUMPCORE,_CoresDump); - HANDLE_CHECK(IDC_DUMPMEM, _MemDump); - HANDLE_CHECK(IDC_DUMPREGS,_RegDump); - HANDLE_CHECK(IDC_DSP_ENABLE,dspPluginEnabled); - HANDLE_CHECK(IDC_TS_ENABLE,timeStretchEnabled); - HANDLE_CHECK(IDC_SPEEDLIMIT,LimitMode); - HANDLE_CHECK(IDC_SPEEDLIMIT_RUNTIME_TOGGLE,LimiterToggleEnabled); - default: - return FALSE; - } - break; - case WM_HSCROLL: - wmId = LOWORD(wParam); - wmEvent = HIWORD(wParam); - switch(wmId) { - //case TB_ENDTRACK: - //case TB_THUMBPOSITION: - case TB_LINEUP: - case TB_LINEDOWN: - case TB_PAGEUP: - case TB_PAGEDOWN: - wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0); - case TB_THUMBTRACK: - if(wmEventLATENCY_MAX) wmEvent=LATENCY_MAX; - SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent); - sprintf_s(temp,80,"%d ms (avg)",wmEvent); - SetDlgItemText(hWnd,IDC_LATENCY_LABEL,temp); - break; - default: - return FALSE; - } - break; - default: - return FALSE; - } - return TRUE; -} - -void configure() -{ - INT_PTR ret; - ReadSettings(); - ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_CONFIG),GetActiveWindow(),(DLGPROC)ConfigProc,1); - if(ret==-1) - { - MessageBoxEx(GetActiveWindow(),"Error Opening the config dialog.","OMG ERROR!",MB_OK,0); - return; - } - ReadSettings(); -} +///GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#include "spu2.h" +#include "dialogs.h" +// Config Vars + + +static bool VolumeBoostEnabled = false; +static int VolumeShiftModifier = 0; + +#ifndef PUBLIC +static const int LATENCY_MAX = 2000; +#else +static const int LATENCY_MAX = 500; +#endif + +static const int LATENCY_MIN = 40; + + +// DEBUG + +bool DebugEnabled=false; +bool _MsgToConsole=false; +bool _MsgKeyOnOff=false; +bool _MsgVoiceOff=false; +bool _MsgDMA=false; +bool _MsgAutoDMA=false; +bool _MsgOverruns=false; +bool _MsgCache=false; + +bool _AccessLog=false; +bool _DMALog=false; +bool _WaveLog=false; + +bool _CoresDump=false; +bool _MemDump=false; +bool _RegDump=false; + + + +char AccessLogFileName[255]; +char WaveLogFileName[255]; + +char DMA4LogFileName[255]; +char DMA7LogFileName[255]; + +char CoresDumpFileName[255]; +char MemDumpFileName[255]; +char RegDumpFileName[255]; + +int WaveDumpFormat; + +int AutoDMAPlayRate[2]={0,0}; + +// MIXING +int Interpolation=1; +/* values: + 0: no interpolation (use nearest) + 1. linear interpolation + 2. cubic interpolation +*/ + +bool EffectsEnabled=false; + +// OUTPUT +int SampleRate=48000; +int SndOutLatencyMS=160; +//int SndOutLatency=1024; +//int MaxBufferCount=8; +//int CurBufferCount=MaxBufferCount; +bool timeStretchEnabled=true; + +u32 OutputModule=0; //OUTPUT_DSOUND; + +//int VolumeMultiplier=1; +//int VolumeDivisor=1; + +int LimitMode=0; +/* values: + 0. No limiter + 1. Soft limiter -- less cpu-intensive, but can cause problems + 2. Hard limiter -- more cpu-intensive while limiting, but should give better (constant) speeds +*/ + + +CONFIG_DSOUNDOUT Config_DSoundOut; +CONFIG_DSOUND51 Config_DSound51; +CONFIG_WAVEOUT Config_WaveOut; + +// MISC +bool LimiterToggleEnabled=false; +int LimiterToggle=VK_SUBTRACT; + +// DSP +bool dspPluginEnabled=false; +char dspPlugin[256]; +int dspPluginModule=0; + +// OUTPUT MODULES +char AsioDriver[129]=""; + + +////// + +const char NewCfgFile[]="inis\\SPU2Ghz-v2.ini"; +const char LegacyCfgFile[]="inis\\SPU2Ghz.ini"; +const char* CfgFile=NewCfgFile; + + + /*| Config File Format: |¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*\ ++--+---------------------+------------------------+ +| | +| Option=Value | +| | +| | +| Boolean Values: TRUE,YES,1,T,Y mean 'true', | +| everything else means 'false'. | +| | +| All Values are limited to 255 chars. | +| | ++-------------------------------------------------+ + \*_____________________________________________*/ + + +void CfgWriteBool(const char *Section, const char*Name, bool Value) { + char *Data=Value?"TRUE":"FALSE"; + + WritePrivateProfileString(Section,Name,Data,CfgFile); +} + +void CfgWriteInt(const char *Section, const char*Name, int Value) { + char Data[255]; + _itoa(Value,Data,10); + + WritePrivateProfileString(Section,Name,Data,CfgFile); +} + +void CfgWriteStr(const char *Section, const char* Name, const char *Data) { + WritePrivateProfileString(Section,Name,Data,CfgFile); +} + +/*****************************************************************************/ + +bool CfgReadBool(const char *Section,const char *Name,bool Default) { + char Data[255]=""; + GetPrivateProfileString(Section,Name,"",Data,255,CfgFile); + Data[254]=0; + if(strlen(Data)==0) { + CfgWriteBool(Section,Name,Default); + return Default; + } + + if(strcmp(Data,"1")==0) return true; + if(strcmp(Data,"Y")==0) return true; + if(strcmp(Data,"T")==0) return true; + if(strcmp(Data,"YES")==0) return true; + if(strcmp(Data,"TRUE")==0) return true; + return false; +} + + +int CfgReadInt(const char *Section, const char*Name,int Default) { + char Data[255]=""; + GetPrivateProfileString(Section,Name,"",Data,255,CfgFile); + Data[254]=0; + + if(strlen(Data)==0) { + CfgWriteInt(Section,Name,Default); + return Default; + } + + return atoi(Data); +} + + +void CfgReadStr(const char *Section, const char* Name, char *Data, int DataSize, const char *Default) { + GetPrivateProfileString(Section,Name,"",Data,DataSize,CfgFile); + + if(strlen(Data)==0) { + sprintf_s( Data, DataSize, "%s", Default ); + CfgWriteStr(Section,Name,Data); + } +} + +// Tries to read the requested value. +// Returns FALSE if the value isn't found. +bool CfgFindName( const char *Section, const char* Name) +{ + // Only load 24 characters. No need to load more. + char Data[24]=""; + GetPrivateProfileString(Section,Name,"",Data,24,CfgFile); + Data[23]=0; + + if(strlen(Data)==0) return false; + return true; +} +/*****************************************************************************/ + +void ReadSettings() +{ + DebugEnabled=CfgReadBool("DEBUG","Global_Debug_Enabled",0); + _MsgToConsole=CfgReadBool("DEBUG","Show_Messages",0); + _MsgKeyOnOff =CfgReadBool("DEBUG","Show_Messages_Key_On_Off",0); + _MsgVoiceOff =CfgReadBool("DEBUG","Show_Messages_Voice_Off",0); + _MsgDMA =CfgReadBool("DEBUG","Show_Messages_DMA_Transfer",0); + _MsgAutoDMA =CfgReadBool("DEBUG","Show_Messages_AutoDMA",0); + _MsgOverruns =CfgReadBool("DEBUG","Show_Messages_Overruns",0); + _MsgCache =CfgReadBool("DEBUG","Show_Messages_CacheStats",0); + + _AccessLog =CfgReadBool("DEBUG","Log_Register_Access",0); + _DMALog =CfgReadBool("DEBUG","Log_DMA_Transfers",0); + _WaveLog =CfgReadBool("DEBUG","Log_WAVE_Output",0); + + _CoresDump =CfgReadBool("DEBUG","Dump_Info",0); + _MemDump =CfgReadBool("DEBUG","Dump_Memory",0); + _RegDump =CfgReadBool("DEBUG","Dump_Regs",0); + + CfgReadStr("DEBUG","Access_Log_Filename",AccessLogFileName,255,"logs\\SPU2Log.txt"); + CfgReadStr("DEBUG","WaveLog_Filename", WaveLogFileName, 255,"logs\\SPU2log.wav"); + CfgReadStr("DEBUG","DMA4Log_Filename", DMA4LogFileName, 255,"logs\\SPU2dma4.dat"); + CfgReadStr("DEBUG","DMA7Log_Filename", DMA7LogFileName, 255,"logs\\SPU2dma7.dat"); + + CfgReadStr("DEBUG","Info_Dump_Filename",CoresDumpFileName,255,"logs\\SPU2Cores.txt"); + CfgReadStr("DEBUG","Mem_Dump_Filename", MemDumpFileName, 255,"logs\\SPU2mem.dat"); + CfgReadStr("DEBUG","Reg_Dump_Filename", RegDumpFileName, 255,"logs\\SPU2regs.dat"); + + WaveDumpFormat=CfgReadInt("DEBUG","Wave_Log_Format",0); + + + AutoDMAPlayRate[0]=CfgReadInt("MIXING","AutoDMA_Play_Rate_0",0); + AutoDMAPlayRate[1]=CfgReadInt("MIXING","AutoDMA_Play_Rate_1",0); + + Interpolation=CfgReadInt("MIXING","Interpolation",1); + + // Moved Timestretch from DSP to Output + timeStretchEnabled = CfgReadBool( + CfgFindName( "OUTPUT", "Timestretch_Enable" ) ? "OUTPUT" : "DSP", + "Timestretch_Enable", true + ); + + // Moved Effects_Enable from Effects to Mixing + EffectsEnabled = CfgReadBool( + CfgFindName( "MIXING", "Enable_Effects" ) ? "MIXING" : "EFFECTS", + "Enable_Effects", false + ); + EffectsEnabled = false; // force disabled for now. + + SampleRate=CfgReadInt("OUTPUT","Sample_Rate",48000); + SndOutLatencyMS=CfgReadInt("OUTPUT","Latency", 160); + + //OutputModule = CfgReadInt("OUTPUT","Output_Module", OUTPUT_DSOUND ); + char omodid[128]; + CfgReadStr( "OUTPUT", "Output_Module", omodid, 127, XAudio2Out->GetIdent() ); + + // find the driver index of this module: + OutputModule = FindOutputModuleById( omodid ); + + VolumeShiftModifier = CfgReadInt( "OUTPUT","Volume_Shift", 0 ); + LimitMode=CfgReadInt("OUTPUT","Speed_Limit_Mode",0); + + CfgReadStr("DSP PLUGIN","Filename",dspPlugin,255,""); + dspPluginModule = CfgReadInt("DSP PLUGIN","ModuleNum",0); + dspPluginEnabled= CfgReadBool("DSP PLUGIN","Enabled",false); + + LimiterToggleEnabled = CfgReadBool("KEYS","Limiter_Toggle_Enabled",false); + LimiterToggle = CfgReadInt ("KEYS","Limiter_Toggle",VK_SUBTRACT); + + // Read DSOUNDOUT and WAVEOUT configs: + CfgReadStr( "DSOUNDOUT", "Device", Config_DSoundOut.Device, 254, "default" ); + CfgReadStr( "WAVEOUT", "Device", Config_WaveOut.Device, 254, "default" ); + Config_DSoundOut.NumBuffers = CfgReadInt( "DSOUNDOUT", "Buffer_Count", 5 ); + Config_WaveOut.NumBuffers = CfgReadInt( "WAVEOUT", "Buffer_Count", 4 ); + + // Read DSOUND51 config: + CfgReadStr( "DSOUND51", "Device", Config_DSound51.Device, 254, "default" ); + Config_DSound51.NumBuffers = CfgReadInt( "DSOUND51", "Buffer_Count", 5 ); + Config_DSound51.GainL =CfgReadInt("DSOUND51","Channel_Gain_L", 256); + Config_DSound51.GainR =CfgReadInt("DSOUND51","Channel_Gain_R", 256); + Config_DSound51.GainC =CfgReadInt("DSOUND51","Channel_Gain_C", 256); + Config_DSound51.GainLFE=CfgReadInt("DSOUND51","Channel_Gain_LFE",256); + Config_DSound51.GainSL =CfgReadInt("DSOUND51","Channel_Gain_SL", 200); + Config_DSound51.GainSR =CfgReadInt("DSOUND51","Channel_Gain_SR", 200); + Config_DSound51.AddCLR =CfgReadInt("DSOUND51","Channel_Center_In_LR", 56); + Config_DSound51.LowpassLFE = CfgReadInt("DSOUND51","LFE_Lowpass_Frequency", 80); + + // Sanity Checks + // ------------- + + SampleRate = 48000; // Yup nothing else is supported for now. + VolumeShiftModifier = min( max( VolumeShiftModifier, -2 ), 2 ); + SndOutVolumeShift = SndOutVolumeShiftBase - VolumeShiftModifier; + SndOutLatencyMS = min( max( SndOutLatencyMS, LATENCY_MIN ), LATENCY_MAX ); + + Config_DSoundOut.NumBuffers = min( max( Config_DSoundOut.NumBuffers, 2 ), 8 ); + Config_WaveOut.NumBuffers = min( max( Config_DSoundOut.NumBuffers, 3 ), 8 ); + + if( mods[OutputModule] == NULL ) + { + // Unsupported or legacy module. + fprintf( stderr, " * SPU2: Unknown output module '%s' specified in configuration file.\n", omodid ); + fprintf( stderr, " * SPU2: Defaulting to DirectSound (%s).\n", DSoundOut->GetIdent() ); + OutputModule = FindOutputModuleById( DSoundOut->GetIdent() ); + } + + +} + +/*****************************************************************************/ + +void WriteSettings() +{ + CfgWriteBool("DEBUG","Global_Debug_Enabled",DebugEnabled); + + // [Air] : Commented out so that we retain debug settings even if disabled... + //if(DebugEnabled) + { + CfgWriteBool("DEBUG","Show_Messages", _MsgToConsole); + CfgWriteBool("DEBUG","Show_Messages_Key_On_Off", _MsgKeyOnOff); + CfgWriteBool("DEBUG","Show_Messages_Voice_Off", _MsgVoiceOff); + CfgWriteBool("DEBUG","Show_Messages_DMA_Transfer",_MsgDMA); + CfgWriteBool("DEBUG","Show_Messages_AutoDMA", _MsgAutoDMA); + CfgWriteBool("DEBUG","Show_Messages_Overruns", _MsgOverruns); + CfgWriteBool("DEBUG","Show_Messages_CacheStats", _MsgCache); + + CfgWriteBool("DEBUG","Log_Register_Access",_AccessLog); + CfgWriteBool("DEBUG","Log_DMA_Transfers", _DMALog); + CfgWriteBool("DEBUG","Log_WAVE_Output", _WaveLog); + + CfgWriteBool("DEBUG","Dump_Info", _CoresDump); + CfgWriteBool("DEBUG","Dump_Memory",_MemDump); + CfgWriteBool("DEBUG","Dump_Regs", _RegDump); + + CfgWriteStr("DEBUG","Access_Log_Filename",AccessLogFileName); + CfgWriteStr("DEBUG","WaveLog_Filename", WaveLogFileName); + CfgWriteStr("DEBUG","DMA4Log_Filename", DMA4LogFileName); + CfgWriteStr("DEBUG","DMA7Log_Filename", DMA7LogFileName); + + CfgWriteStr("DEBUG","Info_Dump_Filename",CoresDumpFileName); + CfgWriteStr("DEBUG","Mem_Dump_Filename", MemDumpFileName); + CfgWriteStr("DEBUG","Reg_Dump_Filename", RegDumpFileName); + + CfgWriteInt("DEBUG","Wave_Log_Format", WaveDumpFormat); + } + + CfgWriteInt("MIXING","Interpolation",Interpolation); + + CfgWriteInt("MIXING","AutoDMA_Play_Rate_0",AutoDMAPlayRate[0]); + CfgWriteInt("MIXING","AutoDMA_Play_Rate_1",AutoDMAPlayRate[1]); + + CfgWriteBool("MIXING","Enable_Effects",EffectsEnabled); + + CfgWriteStr("OUTPUT","Output_Module",mods[OutputModule]->GetIdent() ); + CfgWriteInt("OUTPUT","Sample_Rate",SampleRate); + CfgWriteInt("OUTPUT","Latency",SndOutLatencyMS); + CfgWriteBool("OUTPUT","Timestretch_Enable",timeStretchEnabled); + CfgWriteInt("OUTPUT","Speed_Limit_Mode",LimitMode); + + CfgWriteInt("OUTPUT","Volume_Shift",SndOutVolumeShiftBase - SndOutVolumeShift); + + if( strlen( Config_DSoundOut.Device ) == 0 ) strcpy( Config_DSoundOut.Device, "default" ); + if( strlen( Config_DSound51.Device ) == 0 ) strcpy( Config_DSound51.Device, "default" ); + if( strlen( Config_WaveOut.Device ) == 0 ) strcpy( Config_WaveOut.Device, "default" ); + + CfgWriteStr("DSOUNDOUT","Device",Config_DSoundOut.Device); + CfgWriteInt("DSOUNDOUT","Buffer_Count",Config_DSoundOut.NumBuffers); + + CfgWriteStr("WAVEOUT","Device",Config_WaveOut.Device); + CfgWriteInt("WAVEOUT","Buffer_Count",Config_WaveOut.NumBuffers); + + CfgWriteStr("DSOUND51","Device",Config_DSound51.Device); + CfgWriteInt("DSOUND51","Buffer_Count", Config_DSound51.NumBuffers); + CfgWriteInt("DSOUND51","Channel_Gain_L", Config_DSound51.GainL); + CfgWriteInt("DSOUND51","Channel_Gain_R", Config_DSound51.GainR); + CfgWriteInt("DSOUND51","Channel_Gain_C", Config_DSound51.GainC); + CfgWriteInt("DSOUND51","Channel_Gain_LFE",Config_DSound51.GainLFE); + CfgWriteInt("DSOUND51","Channel_Gain_SL", Config_DSound51.GainSL); + CfgWriteInt("DSOUND51","Channel_Gain_SR", Config_DSound51.GainSR); + CfgWriteInt("DSOUND51","Channel_Center_In_LR", Config_DSound51.AddCLR); + CfgWriteInt("DSOUND51","LFE_Lowpass_Frequency", Config_DSound51.LowpassLFE); + + CfgWriteStr("DSP PLUGIN","Filename",dspPlugin); + CfgWriteInt("DSP PLUGIN","ModuleNum",dspPluginModule); + CfgWriteBool("DSP PLUGIN","Enabled",dspPluginEnabled); + + CfgWriteBool("KEYS","Limiter_Toggle_Enabled",LimiterToggleEnabled); + CfgWriteInt ("KEYS","Limiter_Toggle",LimiterToggle); +} + +static void EnableDebugMessages( HWND hWnd ) +{ + ENABLE_CONTROL(IDC_MSGSHOW, DebugEnabled); + ENABLE_CONTROL(IDC_MSGKEY, MsgToConsole()); + ENABLE_CONTROL(IDC_MSGVOICE,MsgToConsole()); + ENABLE_CONTROL(IDC_MSGDMA, MsgToConsole()); + ENABLE_CONTROL(IDC_MSGADMA, MsgDMA()); + ENABLE_CONTROL(IDC_DBG_OVERRUNS, MsgToConsole()); + ENABLE_CONTROL(IDC_DBG_CACHE, MsgToConsole()); +} + +static void EnableDebugControls( HWND hWnd ) +{ + EnableDebugMessages( hWnd ); + ENABLE_CONTROL(IDC_LOGREGS, DebugEnabled); + ENABLE_CONTROL(IDC_LOGDMA, DebugEnabled); + ENABLE_CONTROL(IDC_LOGWAVE, DebugEnabled); + ENABLE_CONTROL(IDC_DUMPCORE,DebugEnabled); + ENABLE_CONTROL(IDC_DUMPMEM, DebugEnabled); + ENABLE_CONTROL(IDC_DUMPREGS,DebugEnabled); +} + +static int myWidth, myDebugWidth; +static int myHeight; +static bool debugShow = false; + +BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + int wmId,wmEvent; + char temp[384]={0}; + + switch(uMsg) + { + + case WM_PAINT: + return FALSE; + + case WM_INITDIALOG: + + // If debugging is enabled, show the debug box by default: + debugShow = DebugEnabled; + + SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_RESETCONTENT,0,0); + SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"16000"); + SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"22050"); + SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"24000"); + SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"32000"); + SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"44100"); + SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"48000"); + + sprintf_s(temp,48,"%d",SampleRate); + SetDlgItemText(hWnd,IDC_SRATE,temp); + + SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_RESETCONTENT,0,0); + SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"0 - Nearest (none/fast)"); + SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"1 - Linear (recommended)"); + SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"2 - Cubic (better/slower)"); + SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_SETCURSEL,Interpolation,0); + + SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_RESETCONTENT,0,0); + + { + int modidx = 0; + while( mods[modidx] != NULL ) + { + sprintf_s( temp, 72, "%d - %s", modidx, mods[modidx]->GetLongName() ); + SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)temp); + ++modidx; + } + SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_SETCURSEL,OutputModule,0); + } + + //INIT_SLIDER(IDC_BUFFER,512,16384,4096,2048,512); + INIT_SLIDER( IDC_LATENCY_SLIDER, LATENCY_MIN, LATENCY_MAX, 100, 20, 5 ); + + SendMessage(GetDlgItem(hWnd,IDC_LATENCY_SLIDER),TBM_SETPOS,TRUE,SndOutLatencyMS); + sprintf_s(temp,80,"%d ms (avg)",SndOutLatencyMS); + SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp); + + EnableDebugControls( hWnd ); + + // Debugging / Logging Flags: + SET_CHECK(IDC_EFFECTS, EffectsEnabled); + SET_CHECK(IDC_DEBUG, DebugEnabled); + SET_CHECK(IDC_MSGSHOW, _MsgToConsole); + SET_CHECK(IDC_MSGKEY, _MsgKeyOnOff); + SET_CHECK(IDC_MSGVOICE,_MsgVoiceOff); + SET_CHECK(IDC_MSGDMA, _MsgDMA); + SET_CHECK(IDC_MSGADMA, _MsgAutoDMA); + SET_CHECK(IDC_DBG_OVERRUNS, _MsgOverruns ); + SET_CHECK(IDC_DBG_CACHE, _MsgCache ); + SET_CHECK(IDC_LOGREGS, _AccessLog); + SET_CHECK(IDC_LOGDMA, _DMALog); + SET_CHECK(IDC_LOGWAVE, _WaveLog); + SET_CHECK(IDC_DUMPCORE,_CoresDump); + SET_CHECK(IDC_DUMPMEM, _MemDump); + SET_CHECK(IDC_DUMPREGS,_RegDump); + + SET_CHECK(IDC_SPEEDLIMIT,LimitMode); + SET_CHECK(IDC_SPEEDLIMIT_RUNTIME_TOGGLE,LimiterToggleEnabled); + SET_CHECK(IDC_DSP_ENABLE,dspPluginEnabled); + SET_CHECK(IDC_TS_ENABLE,timeStretchEnabled); + + VolumeBoostEnabled = ( VolumeShiftModifier > 0 ) ? true : false; + SET_CHECK(IDC_VOLBOOST, VolumeBoostEnabled ); + + break; + + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case IDOK: + GetDlgItemText(hWnd,IDC_SRATE,temp,20); + temp[19]=0; + SampleRate=atoi(temp); + + SndOutLatencyMS = (int)SendMessage( GetDlgItem( hWnd, IDC_LATENCY_SLIDER ), TBM_GETPOS, 0, 0 ); + + if( SndOutLatencyMS > LATENCY_MAX ) SndOutLatencyMS = LATENCY_MAX; + if( SndOutLatencyMS < LATENCY_MIN ) SndOutLatencyMS = LATENCY_MIN; + + Interpolation=(int)SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_GETCURSEL,0,0); + OutputModule=(int)SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_GETCURSEL,0,0); + + WriteSettings(); + EndDialog(hWnd,0); + break; + case IDCANCEL: + EndDialog(hWnd,0); + break; + + case IDC_OUTCONF: + SndConfigure( hWnd, + (int)SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_GETCURSEL,0,0) + ); + break; + + HANDLE_CHECKNB( IDC_VOLBOOST, VolumeBoostEnabled ); + VolumeShiftModifier = (VolumeBoostEnabled ? 1 : 0 ); + SndOutVolumeShift = SndOutVolumeShiftBase - VolumeShiftModifier; + break; + + HANDLE_CHECK(IDC_EFFECTS,EffectsEnabled); + HANDLE_CHECKNB(IDC_DEBUG,DebugEnabled); + EnableDebugControls( hWnd ); + break; + HANDLE_CHECKNB(IDC_MSGSHOW,_MsgToConsole); + EnableDebugMessages( hWnd ); + break; + HANDLE_CHECK(IDC_MSGKEY,_MsgKeyOnOff); + HANDLE_CHECK(IDC_MSGVOICE,_MsgVoiceOff); + HANDLE_CHECKNB(IDC_MSGDMA,_MsgDMA); + ENABLE_CONTROL(IDC_MSGADMA, MsgDMA()); + break; + HANDLE_CHECK(IDC_MSGADMA,_MsgAutoDMA); + HANDLE_CHECK(IDC_DBG_OVERRUNS,_MsgOverruns); + HANDLE_CHECK(IDC_DBG_CACHE,_MsgCache); + HANDLE_CHECK(IDC_LOGREGS,_AccessLog); + HANDLE_CHECK(IDC_LOGDMA, _DMALog); + HANDLE_CHECK(IDC_LOGWAVE,_WaveLog); + HANDLE_CHECK(IDC_DUMPCORE,_CoresDump); + HANDLE_CHECK(IDC_DUMPMEM, _MemDump); + HANDLE_CHECK(IDC_DUMPREGS,_RegDump); + HANDLE_CHECK(IDC_DSP_ENABLE,dspPluginEnabled); + HANDLE_CHECK(IDC_TS_ENABLE,timeStretchEnabled); + HANDLE_CHECK(IDC_SPEEDLIMIT,LimitMode); + HANDLE_CHECK(IDC_SPEEDLIMIT_RUNTIME_TOGGLE,LimiterToggleEnabled); + default: + return FALSE; + } + break; + case WM_HSCROLL: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + switch(wmId) { + //case TB_ENDTRACK: + //case TB_THUMBPOSITION: + case TB_LINEUP: + case TB_LINEDOWN: + case TB_PAGEUP: + case TB_PAGEDOWN: + wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0); + case TB_THUMBTRACK: + if(wmEventLATENCY_MAX) wmEvent=LATENCY_MAX; + SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent); + sprintf_s(temp,80,"%d ms (avg)",wmEvent); + SetDlgItemText(hWnd,IDC_LATENCY_LABEL,temp); + break; + default: + return FALSE; + } + break; + default: + return FALSE; + } + return TRUE; +} + +void configure() +{ + INT_PTR ret; + ReadSettings(); + ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_CONFIG),GetActiveWindow(),(DLGPROC)ConfigProc,1); + if(ret==-1) + { + MessageBoxEx(GetActiveWindow(),"Error Opening the config dialog.","OMG ERROR!",MB_OK,0); + return; + } + ReadSettings(); +} diff --git a/plugins/spu2ghz/src/Win32/config.h b/plugins/spu2ghz/src/Win32/config.h index 84031aa3e3..036d009d9b 100644 --- a/plugins/spu2ghz/src/Win32/config.h +++ b/plugins/spu2ghz/src/Win32/config.h @@ -1,169 +1,169 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// - -#ifndef CONFIG_H_INCLUDED -#define CONFIG_H_INCLUDED - -extern bool DebugEnabled; - -extern bool _MsgToConsole; -extern bool _MsgKeyOnOff; -extern bool _MsgVoiceOff; -extern bool _MsgDMA; -extern bool _MsgAutoDMA; -extern bool _MsgOverruns; -extern bool _MsgCache; - -extern bool _AccessLog; -extern bool _DMALog; -extern bool _WaveLog; - -extern bool _CoresDump; -extern bool _MemDump; -extern bool _RegDump; - -static __forceinline bool MsgToConsole() { return _MsgToConsole & DebugEnabled; } - -static __forceinline bool MsgKeyOnOff() { return _MsgKeyOnOff & MsgToConsole(); } -static __forceinline bool MsgVoiceOff() { return _MsgVoiceOff & MsgToConsole(); } -static __forceinline bool MsgDMA() { return _MsgDMA & MsgToConsole(); } -static __forceinline bool MsgAutoDMA() { return _MsgAutoDMA & MsgDMA(); } -static __forceinline bool MsgOverruns() { return _MsgOverruns & MsgToConsole(); } -static __forceinline bool MsgCache() { return _MsgCache & MsgToConsole(); } - -static __forceinline bool AccessLog() { return _AccessLog & DebugEnabled; } -static __forceinline bool DMALog() { return _DMALog & DebugEnabled; } -static __forceinline bool WaveLog() { return _WaveLog & DebugEnabled; } - -static __forceinline bool CoresDump() { return _CoresDump & DebugEnabled; } -static __forceinline bool MemDump() { return _MemDump & DebugEnabled; } -static __forceinline bool RegDump() { return _RegDump & DebugEnabled; } - - -extern char AccessLogFileName[255]; -extern char WaveLogFileName[255]; - -extern char DMA4LogFileName[255]; -extern char DMA7LogFileName[255]; - -extern char CoresDumpFileName[255]; -extern char MemDumpFileName[255]; -extern char RegDumpFileName[255]; - -extern int Interpolation; - -extern int WaveDumpFormat; - -extern int SampleRate; - -extern bool EffectsEnabled; - -extern int AutoDMAPlayRate[2]; - -extern u32 OutputModule; -extern int SndOutLatencyMS; - -//extern int VolumeMultiplier; -//extern int VolumeDivisor; - -extern int LimitMode; - -extern char AsioDriver[129]; - -extern char dspPlugin[]; -extern int dspPluginModule; - -extern bool dspPluginEnabled; -extern bool timeStretchEnabled; - -extern bool LimiterToggleEnabled; -extern int LimiterToggle; - -// *** BEGIN DRIVER-SPECIFIC CONFIGURATION *** -// ------------------------------------------- - -// DSOUND -struct CONFIG_DSOUNDOUT -{ - char Device[256]; - s8 NumBuffers; - - CONFIG_DSOUNDOUT() : - NumBuffers( 3 ) - { - memset( Device, 0, sizeof( Device ) ); - } -}; - -// WAVEOUT -struct CONFIG_WAVEOUT -{ - char Device[255]; - s8 NumBuffers; - - CONFIG_WAVEOUT() : - NumBuffers( 4 ) - { - memset( Device, 0, sizeof( Device ) ); - } -}; - -// DSOUND51 -struct CONFIG_DSOUND51 -{ - char Device[256]; - u32 NumBuffers; - - u32 GainL; - u32 GainR; - u32 GainSL; - u32 GainSR; - u32 GainC; - u32 GainLFE; - u32 AddCLR; - u32 LowpassLFE; - - // C++ style struct/class initializer - CONFIG_DSOUND51() : - NumBuffers( 4 ) - , GainL( 256 ) - , GainR( 256 ) - , GainSL( 200 ) - , GainSR( 200 ) - , GainC( 200 ) - , GainLFE( 256 ) - , AddCLR( 56 ) - , LowpassLFE( 80 ) - { - memset( Device, 0, sizeof( Device ) ); - } -}; - - -extern CONFIG_DSOUNDOUT Config_DSoundOut; -extern CONFIG_DSOUND51 Config_DSound51; -extern CONFIG_WAVEOUT Config_WaveOut; - - -////// - -void ReadSettings(); -void WriteSettings(); -void configure(); - -#endif // CONFIG_H_INCLUDED +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#ifndef CONFIG_H_INCLUDED +#define CONFIG_H_INCLUDED + +extern bool DebugEnabled; + +extern bool _MsgToConsole; +extern bool _MsgKeyOnOff; +extern bool _MsgVoiceOff; +extern bool _MsgDMA; +extern bool _MsgAutoDMA; +extern bool _MsgOverruns; +extern bool _MsgCache; + +extern bool _AccessLog; +extern bool _DMALog; +extern bool _WaveLog; + +extern bool _CoresDump; +extern bool _MemDump; +extern bool _RegDump; + +static __forceinline bool MsgToConsole() { return _MsgToConsole & DebugEnabled; } + +static __forceinline bool MsgKeyOnOff() { return _MsgKeyOnOff & MsgToConsole(); } +static __forceinline bool MsgVoiceOff() { return _MsgVoiceOff & MsgToConsole(); } +static __forceinline bool MsgDMA() { return _MsgDMA & MsgToConsole(); } +static __forceinline bool MsgAutoDMA() { return _MsgAutoDMA & MsgDMA(); } +static __forceinline bool MsgOverruns() { return _MsgOverruns & MsgToConsole(); } +static __forceinline bool MsgCache() { return _MsgCache & MsgToConsole(); } + +static __forceinline bool AccessLog() { return _AccessLog & DebugEnabled; } +static __forceinline bool DMALog() { return _DMALog & DebugEnabled; } +static __forceinline bool WaveLog() { return _WaveLog & DebugEnabled; } + +static __forceinline bool CoresDump() { return _CoresDump & DebugEnabled; } +static __forceinline bool MemDump() { return _MemDump & DebugEnabled; } +static __forceinline bool RegDump() { return _RegDump & DebugEnabled; } + + +extern char AccessLogFileName[255]; +extern char WaveLogFileName[255]; + +extern char DMA4LogFileName[255]; +extern char DMA7LogFileName[255]; + +extern char CoresDumpFileName[255]; +extern char MemDumpFileName[255]; +extern char RegDumpFileName[255]; + +extern int Interpolation; + +extern int WaveDumpFormat; + +extern int SampleRate; + +extern bool EffectsEnabled; + +extern int AutoDMAPlayRate[2]; + +extern u32 OutputModule; +extern int SndOutLatencyMS; + +//extern int VolumeMultiplier; +//extern int VolumeDivisor; + +extern int LimitMode; + +extern char AsioDriver[129]; + +extern char dspPlugin[]; +extern int dspPluginModule; + +extern bool dspPluginEnabled; +extern bool timeStretchEnabled; + +extern bool LimiterToggleEnabled; +extern int LimiterToggle; + +// *** BEGIN DRIVER-SPECIFIC CONFIGURATION *** +// ------------------------------------------- + +// DSOUND +struct CONFIG_DSOUNDOUT +{ + char Device[256]; + s8 NumBuffers; + + CONFIG_DSOUNDOUT() : + NumBuffers( 3 ) + { + memset( Device, 0, sizeof( Device ) ); + } +}; + +// WAVEOUT +struct CONFIG_WAVEOUT +{ + char Device[255]; + s8 NumBuffers; + + CONFIG_WAVEOUT() : + NumBuffers( 4 ) + { + memset( Device, 0, sizeof( Device ) ); + } +}; + +// DSOUND51 +struct CONFIG_DSOUND51 +{ + char Device[256]; + u32 NumBuffers; + + u32 GainL; + u32 GainR; + u32 GainSL; + u32 GainSR; + u32 GainC; + u32 GainLFE; + u32 AddCLR; + u32 LowpassLFE; + + // C++ style struct/class initializer + CONFIG_DSOUND51() : + NumBuffers( 4 ) + , GainL( 256 ) + , GainR( 256 ) + , GainSL( 200 ) + , GainSR( 200 ) + , GainC( 200 ) + , GainLFE( 256 ) + , AddCLR( 56 ) + , LowpassLFE( 80 ) + { + memset( Device, 0, sizeof( Device ) ); + } +}; + + +extern CONFIG_DSOUNDOUT Config_DSoundOut; +extern CONFIG_DSOUND51 Config_DSound51; +extern CONFIG_WAVEOUT Config_WaveOut; + + +////// + +void ReadSettings(); +void WriteSettings(); +void configure(); + +#endif // CONFIG_H_INCLUDED diff --git a/plugins/spu2ghz/src/Win32/dialogs.h b/plugins/spu2ghz/src/Win32/dialogs.h index 71ed7c3c4d..0e788c80c6 100644 --- a/plugins/spu2ghz/src/Win32/dialogs.h +++ b/plugins/spu2ghz/src/Win32/dialogs.h @@ -1,16 +1,16 @@ -#pragma once - -#include "resource.h" -#include - -#define SET_CHECK(idc,value) SendMessage(GetDlgItem(hWnd,idc),BM_SETCHECK,((value)==0)?BST_UNCHECKED:BST_CHECKED,0) -#define HANDLE_CHECK(idc,hvar) case idc: hvar=hvar?0:1; SendMessage(GetDlgItem(hWnd,idc),BM_SETCHECK,(hvar==1)?BST_CHECKED:BST_UNCHECKED,0); break -#define HANDLE_CHECKNB(idc,hvar)case idc: hvar=hvar?0:1; SendMessage(GetDlgItem(hWnd,idc),BM_SETCHECK,(hvar==1)?BST_CHECKED:BST_UNCHECKED,0) -#define ENABLE_CONTROL(idc,value) EnableWindow(GetDlgItem(hWnd,idc),value) - -#define INIT_SLIDER(idc,minrange,maxrange,tickfreq,pagesize,linesize) \ - SendMessage(GetDlgItem(hWnd,idc),TBM_SETRANGEMIN,FALSE,minrange); \ - SendMessage(GetDlgItem(hWnd,idc),TBM_SETRANGEMAX,FALSE,maxrange); \ - SendMessage(GetDlgItem(hWnd,idc),TBM_SETTICFREQ,tickfreq,0); \ - SendMessage(GetDlgItem(hWnd,idc),TBM_SETPAGESIZE,0,pagesize); \ - SendMessage(GetDlgItem(hWnd,idc),TBM_SETLINESIZE,0,linesize) +#pragma once + +#include "resource.h" +#include + +#define SET_CHECK(idc,value) SendMessage(GetDlgItem(hWnd,idc),BM_SETCHECK,((value)==0)?BST_UNCHECKED:BST_CHECKED,0) +#define HANDLE_CHECK(idc,hvar) case idc: hvar=hvar?0:1; SendMessage(GetDlgItem(hWnd,idc),BM_SETCHECK,(hvar==1)?BST_CHECKED:BST_UNCHECKED,0); break +#define HANDLE_CHECKNB(idc,hvar)case idc: hvar=hvar?0:1; SendMessage(GetDlgItem(hWnd,idc),BM_SETCHECK,(hvar==1)?BST_CHECKED:BST_UNCHECKED,0) +#define ENABLE_CONTROL(idc,value) EnableWindow(GetDlgItem(hWnd,idc),value) + +#define INIT_SLIDER(idc,minrange,maxrange,tickfreq,pagesize,linesize) \ + SendMessage(GetDlgItem(hWnd,idc),TBM_SETRANGEMIN,FALSE,minrange); \ + SendMessage(GetDlgItem(hWnd,idc),TBM_SETRANGEMAX,FALSE,maxrange); \ + SendMessage(GetDlgItem(hWnd,idc),TBM_SETTICFREQ,tickfreq,0); \ + SendMessage(GetDlgItem(hWnd,idc),TBM_SETPAGESIZE,0,pagesize); \ + SendMessage(GetDlgItem(hWnd,idc),TBM_SETLINESIZE,0,linesize) diff --git a/plugins/spu2ghz/src/Win32/dsound51.cpp b/plugins/spu2ghz/src/Win32/dsound51.cpp index e783585d93..1cce175d40 100644 --- a/plugins/spu2ghz/src/Win32/dsound51.cpp +++ b/plugins/spu2ghz/src/Win32/dsound51.cpp @@ -1,690 +1,690 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -#define _WIN32_DCOM -#include "spu2.h" -#include "dialogs.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "lowpass.h" - -#define ENABLE_DPLII - -struct ds_device_data { - char name[256]; - GUID guid; - bool hasGuid; -}; - -static ds_device_data devices[32]; -static int ndevs; -static GUID DevGuid; // currently employed GUID. -static bool haveGuid; - -extern HRESULT GUIDFromString(const char *str, LPGUID guid); - -class DSound51: public SndOutModule -{ -private: - # define MAX_BUFFER_COUNT 8 - - static const int PacketsPerBuffer = 1; - static const int BufferSize = SndOutPacketSize * PacketsPerBuffer * 3; - static const int BufferSizeBytes = BufferSize << 1; - - - FILE *voicelog; - - u32 numBuffers; // cached copy of our configuration setting. - int channel; - int myLastWrite; - - bool dsound_running; - HANDLE thread; - DWORD tid; - - IDirectSound8* dsound; - IDirectSoundBuffer8* buffer; - IDirectSoundNotify8* buffer_notify; - HANDLE buffer_events[MAX_BUFFER_COUNT]; - - WAVEFORMATEXTENSIBLE wfx; - - SndBuffer *buff; - - s32 LAccum; - s32 RAccum; - s32 ANum; - - s32 LBuff[128]; - s32 RBuff[128]; - - LPF_data lpf_l; - LPF_data lpf_r; - - void Convert(s16 *obuffer, s32 ValL, s32 ValR) - { - static u8 bufdone=1; - static s32 Gfl=0,Gfr=0; - - static s32 spdif_data[6]; - static s32 LMax=0,RMax=0; - - if(PlayMode&4) - { - spdif_get_samples(spdif_data); - } - else - { - spdif_data[0]=0; - spdif_data[1]=0; - spdif_data[2]=0; - spdif_data[3]=0; - spdif_data[4]=0; - spdif_data[5]=0; - } - -#ifdef ENABLE_DPLII -#ifdef USE_AVERAGING - LAccum+=abs(ValL); - RAccum+=abs(ValR); - ANum++; - - if(ANum>=512) - { - LMax=0;RMax=0; - - LAccum/=ANum; - RAccum/=ANum; - ANum=0; - - for(int i=0;i<127;i++) - { - LMax+=LBuff[i]; - RMax+=RBuff[i]; - LBuff[i]=LBuff[i+1]; - RBuff[i]=RBuff[i+1]; - } - LBuff[127]=LAccum; - RBuff[127]=RAccum; - LMax+=LAccum; - RMax+=RAccum; - - s32 TL = (LMax>>15)+1; - s32 TR = (RMax>>15)+1; - - Gfl=(RMax)/(TL); - Gfr=(LMax)/(TR); - - if(Gfl>255) Gfl=255; - if(Gfr>255) Gfr=255; - } -#else - - if(ValL>LMax) LMax = ValL; - if(-ValL>LMax) LMax = -ValL; - if(ValR>RMax) RMax = ValR; - if(-ValR>RMax) RMax = -ValR; - ANum++; - if(ANum>=128) - { - // shift into a 21 bit value - const u8 shift = SndOutVolumeShift-5; - - ANum=0; - LAccum = ((LAccum * 224) + (LMax>>shift))>>8; - RAccum = ((RAccum * 224) + (RMax>>shift))>>8; - - LMax=0; - RMax=0; - - if(LAccum<1) LAccum=1; - if(RAccum<1) RAccum=1; - - Gfl=(RAccum)*255/(LAccum); - Gfr=(LAccum)*255/(RAccum); - - int gMax = max(Gfl,Gfr); - - Gfl=Gfl*255/gMax; - Gfr=Gfr*255/gMax; - - if(Gfl>255) Gfl=255; - if(Gfr>255) Gfr=255; - if(Gfl<1) Gfl=1; - if(Gfr<1) Gfr=1; - } -#endif - - Gfr = 1; Gfl = 1; - - s32 L,R,C,LFE,SL,SR,LL,LR; - - extern double pow_2_31; - - // shift Values into 12 bits: - u8 shift2 = SndOutVolumeShift + 4; - - LL = (s32)(LPF(&lpf_l,(ValL>>shift2)/pow_2_31)*pow_2_31); - LR = (s32)(LPF(&lpf_r,(ValR>>shift2)/pow_2_31)*pow_2_31); - LFE = (LL + LR)>>4; - - C=(ValL+ValR)>>1; //16.8 - - ValL-=C;//16.8 - ValR-=C;//16.8 - - L=ValL>>SndOutVolumeShift; //16.0 - R=ValR>>SndOutVolumeShift; //16.0 - C=C>>SndOutVolumeShift; //16.0 - - s32 VL=(ValL>>4) * Gfl; //16.12 - s32 VR=(ValR>>4) * Gfr; - - SL=(VL/209 - VR/148)>>4; //16.0 (?) - SR=(VL/148 - VR/209)>>4; //16.0 (?) - - // increase surround stereo separation - int SC = (SL+SR)>>1; //16.0 - int SLd = SL - SC; //16.0 - int SRd = SL - SC; //16.0 - - SL = (SLd * 209 + SC * 148)>>8; //16.0 - SR = (SRd * 209 + SC * 148)>>8; //16.0 - - obuffer[0]=spdif_data[0] + (((L * Config_DSound51.GainL ) + (C * Config_DSound51.AddCLR))>>8); - obuffer[1]=spdif_data[1] + (((R * Config_DSound51.GainR ) + (C * Config_DSound51.AddCLR))>>8); - obuffer[2]=spdif_data[2] + (((C * Config_DSound51.GainC ))>>8); - obuffer[3]=spdif_data[3] + (((LFE * Config_DSound51.GainLFE))>>8); - obuffer[4]=spdif_data[4] + (((SL * Config_DSound51.GainSL ))>>8); - obuffer[5]=spdif_data[5] + (((SR * Config_DSound51.GainSR ))>>8); -#else - obuffer[0]=spdif_data[0]+(ValL>>8); - obuffer[1]=spdif_data[1]+(ValR>>8); - obuffer[2]=spdif_data[2]; - obuffer[3]=spdif_data[3]; - obuffer[4]=spdif_data[4]; - obuffer[5]=spdif_data[5]; -#endif - } - -# define STRFY(x) #x - -# define verifyc(x) if(Verifyc(x,STRFY(x))) return -1; - - static DWORD CALLBACK RThread(DSound51*obj) - { - return obj->Thread(); - } - - int __forceinline Verifyc(HRESULT hr,const char* fn) - { - if(FAILED(hr)) - { - SysMessage("ERROR: Call to %s Failed.",fn); - return -1; - } - return 0; - } - - DWORD Thread() - { - while( dsound_running ) - { - u32 rv = WaitForMultipleObjects(numBuffers,buffer_events,FALSE,200); - - s16* p1, *oldp1; - LPVOID p2; - DWORD s1,s2; - - u32 poffset=BufferSizeBytes * rv; - -#ifdef _DEBUG - verifyc(buffer->Lock(poffset,BufferSizeBytes,(LPVOID*)&p1,&s1,&p2,&s2,0)); -#else - if( FAILED(buffer->Lock(poffset,BufferSizeBytes,(LPVOID*)&p1,&s1,&p2,&s2,0) ) ) - { - fputs( " * SPU2 : Directsound Warning > Buffer lock failure. You may need to increase the DSound buffer count.\n", stderr ); - continue; - } -#endif - oldp1 = p1; - - for(int p=0; pReadSamples( temp ); - for(int j=0;jUnlock(oldp1,s1,p2,s2)); -#else - buffer->Unlock(oldp1,s1,p2,s2); -#endif - verifyc(buffer->Unlock(oldp1,s1,p2,s2)); - - // Set the write pointer to the beginning of the next block. - myLastWrite = (poffset + BufferSizeBytes) % (BufferSizeBytes*numBuffers); - } - return 0; - } - -public: - s32 Init(SndBuffer *sb) - { - buff = sb; - numBuffers = Config_DSound51.NumBuffers; - - // - // Initialize DSound - // - GUID cGuid; - bool success = false; - - if( (strlen(Config_DSound51.Device)>0)&&(!FAILED(GUIDFromString(Config_DSound51.Device,&cGuid)))) - { - if( !FAILED( DirectSoundCreate8(&cGuid,&dsound,NULL) ) ) - success = true; - } - - // if the GUID failed, just open up the default dsound driver: - if( !success ) - { - verifyc(DirectSoundCreate8(NULL,&dsound,NULL)); - } - - verifyc(dsound->SetCooperativeLevel(GetDesktopWindow(),DSSCL_PRIORITY)); - IDirectSoundBuffer* buffer_; - DSBUFFERDESC desc; - - // Set up WAV format structure. - - memset(&wfx, 0, sizeof(WAVEFORMATEX)); - wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - wfx.Format.nSamplesPerSec = SampleRate; - wfx.Format.nChannels=6; - wfx.Format.wBitsPerSample = 16; - wfx.Format.nBlockAlign = wfx.Format.nChannels*wfx.Format.wBitsPerSample/8; - wfx.Format.nAvgBytesPerSec = SampleRate * wfx.Format.nBlockAlign; - wfx.Format.cbSize=22; - wfx.Samples.wValidBitsPerSample=0; - wfx.dwChannelMask=SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT; - wfx.SubFormat=KSDATAFORMAT_SUBTYPE_PCM; - - verifyc(dsound->SetSpeakerConfig(DSSPEAKER_5POINT1)); - - // Set up DSBUFFERDESC structure. - - memset(&desc, 0, sizeof(DSBUFFERDESC)); - desc.dwSize = sizeof(DSBUFFERDESC); - desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; - desc.dwBufferBytes = BufferSizeBytes * numBuffers; - desc.lpwfxFormat = &wfx.Format; - - desc.dwFlags |=DSBCAPS_LOCSOFTWARE; - desc.dwFlags|=DSBCAPS_GLOBALFOCUS; - - verifyc(dsound->CreateSoundBuffer(&desc,&buffer_,0)); - verifyc(buffer_->QueryInterface(IID_IDirectSoundBuffer8,(void**)&buffer)); - buffer_->Release(); - - verifyc(buffer->QueryInterface(IID_IDirectSoundNotify8,(void**)&buffer_notify)); - - DSBPOSITIONNOTIFY not[MAX_BUFFER_COUNT]; - - for(u32 i=0;iSetNotificationPositions(numBuffers,not); - - LPVOID p1=0,p2=0; - DWORD s1=0,s2=0; - - verifyc(buffer->Lock(0,desc.dwBufferBytes,&p1,&s1,&p2,&s2,0)); - assert(p2==0); - memset(p1,0,s1); - verifyc(buffer->Unlock(p1,s1,p2,s2)); - - LPF_init(&lpf_l,Config_DSound51.LowpassLFE,SampleRate); - LPF_init(&lpf_r,Config_DSound51.LowpassLFE,SampleRate); - - //Play the buffer ! - verifyc(buffer->Play(0,0,DSBPLAY_LOOPING)); - - // Start Thread - myLastWrite = 0; - dsound_running=true; - thread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RThread,this,0,&tid); - SetThreadPriority(thread,THREAD_PRIORITY_TIME_CRITICAL); - - return 0; - } - - void Close() - { - // Stop Thread - fprintf(stderr," * SPU2: Waiting for DSound thread to finish..."); - dsound_running=false; - - WaitForSingleObject(thread,INFINITE); - CloseHandle(thread); - - fprintf(stderr," Done.\n"); - - // - // Clean up - // - if( buffer != NULL ) - { - buffer->Stop(); - - for(u32 i=0;i=0) - { - SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_SETCURSEL,tSel,0); - } - - INIT_SLIDER(IDC_LEFT_GAIN_SLIDER,0,512,64,16,8); - INIT_SLIDER(IDC_RIGHT_GAIN_SLIDER,0,512,64,16,8); - INIT_SLIDER(IDC_RLEFT_GAIN_SLIDER,0,512,64,16,8); - INIT_SLIDER(IDC_RRIGHT_GAIN_SLIDER,0,512,64,16,8); - INIT_SLIDER(IDC_CENTER_GAIN_SLIDER,0,512,64,16,8); - INIT_SLIDER(IDC_LFE_SLIDER,0,512,64,16,8); - INIT_SLIDER(IDC_LR_CENTER_SLIDER,0,512,64,16,8); - - AssignSliderValue( hWnd, IDC_LEFT_GAIN_SLIDER, IDC_LEFT_GAIN_EDIT, Config_DSound51.GainL ); - AssignSliderValue( hWnd, IDC_RIGHT_GAIN_SLIDER, IDC_RIGHT_GAIN_EDIT, Config_DSound51.GainR ); - AssignSliderValue( hWnd, IDC_RLEFT_GAIN_SLIDER, IDC_RLEFT_GAIN_EDIT, Config_DSound51.GainSL ); - AssignSliderValue( hWnd, IDC_RRIGHT_GAIN_SLIDER, IDC_RRIGHT_GAIN_EDIT, Config_DSound51.GainSR ); - AssignSliderValue( hWnd, IDC_CENTER_GAIN_SLIDER, IDC_CENTER_GAIN_EDIT, Config_DSound51.GainC); - AssignSliderValue( hWnd, IDC_LFE_SLIDER, IDC_LFE_EDIT, Config_DSound51.GainLFE); - AssignSliderValue( hWnd, IDC_LR_CENTER_SLIDER, IDC_LR_CENTER_EDIT, Config_DSound51.AddCLR ); - - char temp[128]; - INIT_SLIDER( IDC_BUFFERS_SLIDER, 2, MAX_BUFFER_COUNT, 2, 1, 1 ); - SendMessage(GetDlgItem(hWnd,IDC_BUFFERS_SLIDER),TBM_SETPOS,TRUE,Config_DSound51.NumBuffers); - sprintf_s(temp, 128, "%d (%d ms latency)",Config_DSound51.NumBuffers, 1000 / (96000 / (Config_DSound51.NumBuffers * BufferSize))); - SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL2),temp); - break; - - case WM_COMMAND: - wmId = LOWORD(wParam); - wmEvent = HIWORD(wParam); - // Parse the menu selections: - switch (wmId) - { - case IDOK: - { - int i = (int)SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_GETCURSEL,0,0); - - if(!devices[i].hasGuid) - { - Config_DSound51.Device[0]=0; // clear device name to "" - } - else - { - sprintf_s(Config_DSound51.Device,256,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", - devices[i].guid.Data1, - devices[i].guid.Data2, - devices[i].guid.Data3, - devices[i].guid.Data4[0], - devices[i].guid.Data4[1], - devices[i].guid.Data4[2], - devices[i].guid.Data4[3], - devices[i].guid.Data4[4], - devices[i].guid.Data4[5], - devices[i].guid.Data4[6], - devices[i].guid.Data4[7] - ); - - Config_DSound51.NumBuffers = GetSliderValue( hWnd, IDC_BUFFERS_SLIDER ); - Config_DSound51.GainL = GetSliderValue( hWnd, IDC_LEFT_GAIN_SLIDER ); - Config_DSound51.GainR = GetSliderValue( hWnd, IDC_RIGHT_GAIN_SLIDER ); - Config_DSound51.GainSL = GetSliderValue( hWnd, IDC_RLEFT_GAIN_SLIDER ); - Config_DSound51.GainSR = GetSliderValue( hWnd, IDC_RRIGHT_GAIN_SLIDER ); - Config_DSound51.GainLFE = GetSliderValue( hWnd, IDC_LFE_SLIDER ); - Config_DSound51.GainC = GetSliderValue( hWnd, IDC_CENTER_GAIN_SLIDER ); - Config_DSound51.AddCLR = GetSliderValue( hWnd, IDC_LR_CENTER_SLIDER ); - - if( Config_DSound51.NumBuffers < 2 ) Config_DSound51.NumBuffers = 2; - if( Config_DSound51.NumBuffers > MAX_BUFFER_COUNT ) Config_DSound51.NumBuffers = MAX_BUFFER_COUNT; - } - } - EndDialog(hWnd,0); - break; - case IDCANCEL: - EndDialog(hWnd,0); - break; - default: - return FALSE; - } - break; - - case WM_HSCROLL: - wmId = LOWORD(wParam); - wmEvent = HIWORD(wParam); - switch(wmId) { - //case TB_ENDTRACK: - //case TB_THUMBPOSITION: - case TB_LINEUP: - case TB_LINEDOWN: - case TB_PAGEUP: - case TB_PAGEDOWN: - wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0); - case TB_THUMBTRACK: - if( wmEvent < 2 ) wmEvent = 2; - if( wmEvent > MAX_BUFFER_COUNT ) wmEvent = MAX_BUFFER_COUNT; - SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent); - sprintf_s(temp,128,"%d (%d ms latency)",wmEvent, 1000 / (96000 / (wmEvent * BufferSize))); - SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL2),temp); - break; - default: - return FALSE; - } - break; - - case WM_VSCROLL: - HANDLE_SCROLL_MESSAGE(IDC_LEFT_GAIN_SLIDER,IDC_LEFT_GAIN_EDIT); - HANDLE_SCROLL_MESSAGE(IDC_RIGHT_GAIN_SLIDER,IDC_RIGHT_GAIN_EDIT); - HANDLE_SCROLL_MESSAGE(IDC_RLEFT_GAIN_SLIDER,IDC_RLEFT_GAIN_EDIT); - HANDLE_SCROLL_MESSAGE(IDC_RRIGHT_GAIN_SLIDER,IDC_RRIGHT_GAIN_EDIT); - HANDLE_SCROLL_MESSAGE(IDC_CENTER_GAIN_SLIDER,IDC_CENTER_GAIN_EDIT); - HANDLE_SCROLL_MESSAGE(IDC_LFE_SLIDER,IDC_LFE_EDIT); - HANDLE_SCROLL_MESSAGE(IDC_LR_CENTER_SLIDER,IDC_LR_CENTER_EDIT); - - default: - return FALSE; - } - return TRUE; - } - -public: - virtual void Configure(HWND parent) - { - INT_PTR ret; - ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_DSOUND51),GetActiveWindow(),(DLGPROC)ConfigProc,1); - if(ret==-1) - { - MessageBoxEx(GetActiveWindow(),"Error Opening the config dialog.","OMG ERROR!",MB_OK,0); - return; - } - } - - s32 Test() const - { - return 0; - } - - bool Is51Out() const { return true; } - - int GetEmptySampleCount() const - { - DWORD play, write; - buffer->GetCurrentPosition( &play, &write ); - - // Note: Dsound's write cursor is bogus. Use our own instead: - - int empty = play - myLastWrite; - if( empty < 0 ) - empty = -empty; - - return empty / 6; - - } - - const char* GetIdent() const - { - return "dsound51"; - } - - const char* GetLongName() const - { - return "DSound 5.1 (Experimental)"; - } -} DS51; - +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#define _WIN32_DCOM +#include "spu2.h" +#include "dialogs.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lowpass.h" + +#define ENABLE_DPLII + +struct ds_device_data { + char name[256]; + GUID guid; + bool hasGuid; +}; + +static ds_device_data devices[32]; +static int ndevs; +static GUID DevGuid; // currently employed GUID. +static bool haveGuid; + +extern HRESULT GUIDFromString(const char *str, LPGUID guid); + +class DSound51: public SndOutModule +{ +private: + # define MAX_BUFFER_COUNT 8 + + static const int PacketsPerBuffer = 1; + static const int BufferSize = SndOutPacketSize * PacketsPerBuffer * 3; + static const int BufferSizeBytes = BufferSize << 1; + + + FILE *voicelog; + + u32 numBuffers; // cached copy of our configuration setting. + int channel; + int myLastWrite; + + bool dsound_running; + HANDLE thread; + DWORD tid; + + IDirectSound8* dsound; + IDirectSoundBuffer8* buffer; + IDirectSoundNotify8* buffer_notify; + HANDLE buffer_events[MAX_BUFFER_COUNT]; + + WAVEFORMATEXTENSIBLE wfx; + + SndBuffer *buff; + + s32 LAccum; + s32 RAccum; + s32 ANum; + + s32 LBuff[128]; + s32 RBuff[128]; + + LPF_data lpf_l; + LPF_data lpf_r; + + void Convert(s16 *obuffer, s32 ValL, s32 ValR) + { + static u8 bufdone=1; + static s32 Gfl=0,Gfr=0; + + static s32 spdif_data[6]; + static s32 LMax=0,RMax=0; + + if(PlayMode&4) + { + spdif_get_samples(spdif_data); + } + else + { + spdif_data[0]=0; + spdif_data[1]=0; + spdif_data[2]=0; + spdif_data[3]=0; + spdif_data[4]=0; + spdif_data[5]=0; + } + +#ifdef ENABLE_DPLII +#ifdef USE_AVERAGING + LAccum+=abs(ValL); + RAccum+=abs(ValR); + ANum++; + + if(ANum>=512) + { + LMax=0;RMax=0; + + LAccum/=ANum; + RAccum/=ANum; + ANum=0; + + for(int i=0;i<127;i++) + { + LMax+=LBuff[i]; + RMax+=RBuff[i]; + LBuff[i]=LBuff[i+1]; + RBuff[i]=RBuff[i+1]; + } + LBuff[127]=LAccum; + RBuff[127]=RAccum; + LMax+=LAccum; + RMax+=RAccum; + + s32 TL = (LMax>>15)+1; + s32 TR = (RMax>>15)+1; + + Gfl=(RMax)/(TL); + Gfr=(LMax)/(TR); + + if(Gfl>255) Gfl=255; + if(Gfr>255) Gfr=255; + } +#else + + if(ValL>LMax) LMax = ValL; + if(-ValL>LMax) LMax = -ValL; + if(ValR>RMax) RMax = ValR; + if(-ValR>RMax) RMax = -ValR; + ANum++; + if(ANum>=128) + { + // shift into a 21 bit value + const u8 shift = SndOutVolumeShift-5; + + ANum=0; + LAccum = ((LAccum * 224) + (LMax>>shift))>>8; + RAccum = ((RAccum * 224) + (RMax>>shift))>>8; + + LMax=0; + RMax=0; + + if(LAccum<1) LAccum=1; + if(RAccum<1) RAccum=1; + + Gfl=(RAccum)*255/(LAccum); + Gfr=(LAccum)*255/(RAccum); + + int gMax = max(Gfl,Gfr); + + Gfl=Gfl*255/gMax; + Gfr=Gfr*255/gMax; + + if(Gfl>255) Gfl=255; + if(Gfr>255) Gfr=255; + if(Gfl<1) Gfl=1; + if(Gfr<1) Gfr=1; + } +#endif + + Gfr = 1; Gfl = 1; + + s32 L,R,C,LFE,SL,SR,LL,LR; + + extern double pow_2_31; + + // shift Values into 12 bits: + u8 shift2 = SndOutVolumeShift + 4; + + LL = (s32)(LPF(&lpf_l,(ValL>>shift2)/pow_2_31)*pow_2_31); + LR = (s32)(LPF(&lpf_r,(ValR>>shift2)/pow_2_31)*pow_2_31); + LFE = (LL + LR)>>4; + + C=(ValL+ValR)>>1; //16.8 + + ValL-=C;//16.8 + ValR-=C;//16.8 + + L=ValL>>SndOutVolumeShift; //16.0 + R=ValR>>SndOutVolumeShift; //16.0 + C=C>>SndOutVolumeShift; //16.0 + + s32 VL=(ValL>>4) * Gfl; //16.12 + s32 VR=(ValR>>4) * Gfr; + + SL=(VL/209 - VR/148)>>4; //16.0 (?) + SR=(VL/148 - VR/209)>>4; //16.0 (?) + + // increase surround stereo separation + int SC = (SL+SR)>>1; //16.0 + int SLd = SL - SC; //16.0 + int SRd = SL - SC; //16.0 + + SL = (SLd * 209 + SC * 148)>>8; //16.0 + SR = (SRd * 209 + SC * 148)>>8; //16.0 + + obuffer[0]=spdif_data[0] + (((L * Config_DSound51.GainL ) + (C * Config_DSound51.AddCLR))>>8); + obuffer[1]=spdif_data[1] + (((R * Config_DSound51.GainR ) + (C * Config_DSound51.AddCLR))>>8); + obuffer[2]=spdif_data[2] + (((C * Config_DSound51.GainC ))>>8); + obuffer[3]=spdif_data[3] + (((LFE * Config_DSound51.GainLFE))>>8); + obuffer[4]=spdif_data[4] + (((SL * Config_DSound51.GainSL ))>>8); + obuffer[5]=spdif_data[5] + (((SR * Config_DSound51.GainSR ))>>8); +#else + obuffer[0]=spdif_data[0]+(ValL>>8); + obuffer[1]=spdif_data[1]+(ValR>>8); + obuffer[2]=spdif_data[2]; + obuffer[3]=spdif_data[3]; + obuffer[4]=spdif_data[4]; + obuffer[5]=spdif_data[5]; +#endif + } + +# define STRFY(x) #x + +# define verifyc(x) if(Verifyc(x,STRFY(x))) return -1; + + static DWORD CALLBACK RThread(DSound51*obj) + { + return obj->Thread(); + } + + int __forceinline Verifyc(HRESULT hr,const char* fn) + { + if(FAILED(hr)) + { + SysMessage("ERROR: Call to %s Failed.",fn); + return -1; + } + return 0; + } + + DWORD Thread() + { + while( dsound_running ) + { + u32 rv = WaitForMultipleObjects(numBuffers,buffer_events,FALSE,200); + + s16* p1, *oldp1; + LPVOID p2; + DWORD s1,s2; + + u32 poffset=BufferSizeBytes * rv; + +#ifdef _DEBUG + verifyc(buffer->Lock(poffset,BufferSizeBytes,(LPVOID*)&p1,&s1,&p2,&s2,0)); +#else + if( FAILED(buffer->Lock(poffset,BufferSizeBytes,(LPVOID*)&p1,&s1,&p2,&s2,0) ) ) + { + fputs( " * SPU2 : Directsound Warning > Buffer lock failure. You may need to increase the DSound buffer count.\n", stderr ); + continue; + } +#endif + oldp1 = p1; + + for(int p=0; pReadSamples( temp ); + for(int j=0;jUnlock(oldp1,s1,p2,s2)); +#else + buffer->Unlock(oldp1,s1,p2,s2); +#endif + verifyc(buffer->Unlock(oldp1,s1,p2,s2)); + + // Set the write pointer to the beginning of the next block. + myLastWrite = (poffset + BufferSizeBytes) % (BufferSizeBytes*numBuffers); + } + return 0; + } + +public: + s32 Init(SndBuffer *sb) + { + buff = sb; + numBuffers = Config_DSound51.NumBuffers; + + // + // Initialize DSound + // + GUID cGuid; + bool success = false; + + if( (strlen(Config_DSound51.Device)>0)&&(!FAILED(GUIDFromString(Config_DSound51.Device,&cGuid)))) + { + if( !FAILED( DirectSoundCreate8(&cGuid,&dsound,NULL) ) ) + success = true; + } + + // if the GUID failed, just open up the default dsound driver: + if( !success ) + { + verifyc(DirectSoundCreate8(NULL,&dsound,NULL)); + } + + verifyc(dsound->SetCooperativeLevel(GetDesktopWindow(),DSSCL_PRIORITY)); + IDirectSoundBuffer* buffer_; + DSBUFFERDESC desc; + + // Set up WAV format structure. + + memset(&wfx, 0, sizeof(WAVEFORMATEX)); + wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wfx.Format.nSamplesPerSec = SampleRate; + wfx.Format.nChannels=6; + wfx.Format.wBitsPerSample = 16; + wfx.Format.nBlockAlign = wfx.Format.nChannels*wfx.Format.wBitsPerSample/8; + wfx.Format.nAvgBytesPerSec = SampleRate * wfx.Format.nBlockAlign; + wfx.Format.cbSize=22; + wfx.Samples.wValidBitsPerSample=0; + wfx.dwChannelMask=SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT; + wfx.SubFormat=KSDATAFORMAT_SUBTYPE_PCM; + + verifyc(dsound->SetSpeakerConfig(DSSPEAKER_5POINT1)); + + // Set up DSBUFFERDESC structure. + + memset(&desc, 0, sizeof(DSBUFFERDESC)); + desc.dwSize = sizeof(DSBUFFERDESC); + desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; + desc.dwBufferBytes = BufferSizeBytes * numBuffers; + desc.lpwfxFormat = &wfx.Format; + + desc.dwFlags |=DSBCAPS_LOCSOFTWARE; + desc.dwFlags|=DSBCAPS_GLOBALFOCUS; + + verifyc(dsound->CreateSoundBuffer(&desc,&buffer_,0)); + verifyc(buffer_->QueryInterface(IID_IDirectSoundBuffer8,(void**)&buffer)); + buffer_->Release(); + + verifyc(buffer->QueryInterface(IID_IDirectSoundNotify8,(void**)&buffer_notify)); + + DSBPOSITIONNOTIFY not[MAX_BUFFER_COUNT]; + + for(u32 i=0;iSetNotificationPositions(numBuffers,not); + + LPVOID p1=0,p2=0; + DWORD s1=0,s2=0; + + verifyc(buffer->Lock(0,desc.dwBufferBytes,&p1,&s1,&p2,&s2,0)); + assert(p2==0); + memset(p1,0,s1); + verifyc(buffer->Unlock(p1,s1,p2,s2)); + + LPF_init(&lpf_l,Config_DSound51.LowpassLFE,SampleRate); + LPF_init(&lpf_r,Config_DSound51.LowpassLFE,SampleRate); + + //Play the buffer ! + verifyc(buffer->Play(0,0,DSBPLAY_LOOPING)); + + // Start Thread + myLastWrite = 0; + dsound_running=true; + thread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RThread,this,0,&tid); + SetThreadPriority(thread,THREAD_PRIORITY_TIME_CRITICAL); + + return 0; + } + + void Close() + { + // Stop Thread + fprintf(stderr," * SPU2: Waiting for DSound thread to finish..."); + dsound_running=false; + + WaitForSingleObject(thread,INFINITE); + CloseHandle(thread); + + fprintf(stderr," Done.\n"); + + // + // Clean up + // + if( buffer != NULL ) + { + buffer->Stop(); + + for(u32 i=0;i=0) + { + SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_SETCURSEL,tSel,0); + } + + INIT_SLIDER(IDC_LEFT_GAIN_SLIDER,0,512,64,16,8); + INIT_SLIDER(IDC_RIGHT_GAIN_SLIDER,0,512,64,16,8); + INIT_SLIDER(IDC_RLEFT_GAIN_SLIDER,0,512,64,16,8); + INIT_SLIDER(IDC_RRIGHT_GAIN_SLIDER,0,512,64,16,8); + INIT_SLIDER(IDC_CENTER_GAIN_SLIDER,0,512,64,16,8); + INIT_SLIDER(IDC_LFE_SLIDER,0,512,64,16,8); + INIT_SLIDER(IDC_LR_CENTER_SLIDER,0,512,64,16,8); + + AssignSliderValue( hWnd, IDC_LEFT_GAIN_SLIDER, IDC_LEFT_GAIN_EDIT, Config_DSound51.GainL ); + AssignSliderValue( hWnd, IDC_RIGHT_GAIN_SLIDER, IDC_RIGHT_GAIN_EDIT, Config_DSound51.GainR ); + AssignSliderValue( hWnd, IDC_RLEFT_GAIN_SLIDER, IDC_RLEFT_GAIN_EDIT, Config_DSound51.GainSL ); + AssignSliderValue( hWnd, IDC_RRIGHT_GAIN_SLIDER, IDC_RRIGHT_GAIN_EDIT, Config_DSound51.GainSR ); + AssignSliderValue( hWnd, IDC_CENTER_GAIN_SLIDER, IDC_CENTER_GAIN_EDIT, Config_DSound51.GainC); + AssignSliderValue( hWnd, IDC_LFE_SLIDER, IDC_LFE_EDIT, Config_DSound51.GainLFE); + AssignSliderValue( hWnd, IDC_LR_CENTER_SLIDER, IDC_LR_CENTER_EDIT, Config_DSound51.AddCLR ); + + char temp[128]; + INIT_SLIDER( IDC_BUFFERS_SLIDER, 2, MAX_BUFFER_COUNT, 2, 1, 1 ); + SendMessage(GetDlgItem(hWnd,IDC_BUFFERS_SLIDER),TBM_SETPOS,TRUE,Config_DSound51.NumBuffers); + sprintf_s(temp, 128, "%d (%d ms latency)",Config_DSound51.NumBuffers, 1000 / (96000 / (Config_DSound51.NumBuffers * BufferSize))); + SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL2),temp); + break; + + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case IDOK: + { + int i = (int)SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_GETCURSEL,0,0); + + if(!devices[i].hasGuid) + { + Config_DSound51.Device[0]=0; // clear device name to "" + } + else + { + sprintf_s(Config_DSound51.Device,256,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + devices[i].guid.Data1, + devices[i].guid.Data2, + devices[i].guid.Data3, + devices[i].guid.Data4[0], + devices[i].guid.Data4[1], + devices[i].guid.Data4[2], + devices[i].guid.Data4[3], + devices[i].guid.Data4[4], + devices[i].guid.Data4[5], + devices[i].guid.Data4[6], + devices[i].guid.Data4[7] + ); + + Config_DSound51.NumBuffers = GetSliderValue( hWnd, IDC_BUFFERS_SLIDER ); + Config_DSound51.GainL = GetSliderValue( hWnd, IDC_LEFT_GAIN_SLIDER ); + Config_DSound51.GainR = GetSliderValue( hWnd, IDC_RIGHT_GAIN_SLIDER ); + Config_DSound51.GainSL = GetSliderValue( hWnd, IDC_RLEFT_GAIN_SLIDER ); + Config_DSound51.GainSR = GetSliderValue( hWnd, IDC_RRIGHT_GAIN_SLIDER ); + Config_DSound51.GainLFE = GetSliderValue( hWnd, IDC_LFE_SLIDER ); + Config_DSound51.GainC = GetSliderValue( hWnd, IDC_CENTER_GAIN_SLIDER ); + Config_DSound51.AddCLR = GetSliderValue( hWnd, IDC_LR_CENTER_SLIDER ); + + if( Config_DSound51.NumBuffers < 2 ) Config_DSound51.NumBuffers = 2; + if( Config_DSound51.NumBuffers > MAX_BUFFER_COUNT ) Config_DSound51.NumBuffers = MAX_BUFFER_COUNT; + } + } + EndDialog(hWnd,0); + break; + case IDCANCEL: + EndDialog(hWnd,0); + break; + default: + return FALSE; + } + break; + + case WM_HSCROLL: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + switch(wmId) { + //case TB_ENDTRACK: + //case TB_THUMBPOSITION: + case TB_LINEUP: + case TB_LINEDOWN: + case TB_PAGEUP: + case TB_PAGEDOWN: + wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0); + case TB_THUMBTRACK: + if( wmEvent < 2 ) wmEvent = 2; + if( wmEvent > MAX_BUFFER_COUNT ) wmEvent = MAX_BUFFER_COUNT; + SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent); + sprintf_s(temp,128,"%d (%d ms latency)",wmEvent, 1000 / (96000 / (wmEvent * BufferSize))); + SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL2),temp); + break; + default: + return FALSE; + } + break; + + case WM_VSCROLL: + HANDLE_SCROLL_MESSAGE(IDC_LEFT_GAIN_SLIDER,IDC_LEFT_GAIN_EDIT); + HANDLE_SCROLL_MESSAGE(IDC_RIGHT_GAIN_SLIDER,IDC_RIGHT_GAIN_EDIT); + HANDLE_SCROLL_MESSAGE(IDC_RLEFT_GAIN_SLIDER,IDC_RLEFT_GAIN_EDIT); + HANDLE_SCROLL_MESSAGE(IDC_RRIGHT_GAIN_SLIDER,IDC_RRIGHT_GAIN_EDIT); + HANDLE_SCROLL_MESSAGE(IDC_CENTER_GAIN_SLIDER,IDC_CENTER_GAIN_EDIT); + HANDLE_SCROLL_MESSAGE(IDC_LFE_SLIDER,IDC_LFE_EDIT); + HANDLE_SCROLL_MESSAGE(IDC_LR_CENTER_SLIDER,IDC_LR_CENTER_EDIT); + + default: + return FALSE; + } + return TRUE; + } + +public: + virtual void Configure(HWND parent) + { + INT_PTR ret; + ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_DSOUND51),GetActiveWindow(),(DLGPROC)ConfigProc,1); + if(ret==-1) + { + MessageBoxEx(GetActiveWindow(),"Error Opening the config dialog.","OMG ERROR!",MB_OK,0); + return; + } + } + + s32 Test() const + { + return 0; + } + + bool Is51Out() const { return true; } + + int GetEmptySampleCount() const + { + DWORD play, write; + buffer->GetCurrentPosition( &play, &write ); + + // Note: Dsound's write cursor is bogus. Use our own instead: + + int empty = play - myLastWrite; + if( empty < 0 ) + empty = -empty; + + return empty / 6; + + } + + const char* GetIdent() const + { + return "dsound51"; + } + + const char* GetLongName() const + { + return "DSound 5.1 (Experimental)"; + } +} DS51; + SndOutModule *DSound51Out=&DS51; \ No newline at end of file diff --git a/plugins/spu2ghz/src/Win32/dsoundout.cpp b/plugins/spu2ghz/src/Win32/dsoundout.cpp index fd00a3bc83..f2070d91ba 100644 --- a/plugins/spu2ghz/src/Win32/dsoundout.cpp +++ b/plugins/spu2ghz/src/Win32/dsoundout.cpp @@ -1,459 +1,459 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -#define _WIN32_DCOM -#include "spu2.h" -#include "dialogs.h" -#include -#include -#include -#include -#include -#include -#include -#include - -struct ds_device_data { - char name[256]; - GUID guid; - bool hasGuid; -}; - -static ds_device_data devices[32]; -static int ndevs; -static GUID DevGuid; // currently employed GUID. -static bool haveGuid; - -HRESULT GUIDFromString(const char *str, LPGUID guid) -{ - // "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" - - struct T{ // this is a hack because for some reason sscanf writes too much :/ - GUID g; - int k; - } t; - - int r = sscanf_s(str,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", - &t.g.Data1, - &t.g.Data2, - &t.g.Data3, - &t.g.Data4[0], - &t.g.Data4[1], - &t.g.Data4[2], - &t.g.Data4[3], - &t.g.Data4[4], - &t.g.Data4[5], - &t.g.Data4[6], - &t.g.Data4[7] - ); - - if(r!=11) return -1; - - *guid = t.g; - return 0; -} - -class DSound: public SndOutModule -{ -private: - # define MAX_BUFFER_COUNT 8 - - static const int PacketsPerBuffer = 1; - static const int BufferSize = SndOutPacketSize * PacketsPerBuffer; - static const int BufferSizeBytes = BufferSize << 1; - - - FILE *voicelog; - - u32 numBuffers; // cached copy of our configuration setting. - int channel; - int myLastWrite; // last write position, in bytes - - bool dsound_running; - HANDLE thread; - DWORD tid; - - IDirectSound8* dsound; - IDirectSoundBuffer8* buffer; - IDirectSoundNotify8* buffer_notify; - HANDLE buffer_events[MAX_BUFFER_COUNT]; - - WAVEFORMATEX wfx; - - HANDLE waitEvent; - - SndBuffer *buff; - -# define STRFY(x) #x -# define verifyc(x) if(Verifyc(x,STRFY(x))) return -1; - - int __forceinline Verifyc(HRESULT hr,const char* fn) - { - if(FAILED(hr)) - { - SysMessage("ERROR: Call to %s Failed.",fn); - return -1; - } - return 0; - } - - static DWORD CALLBACK RThread(DSound*obj) - { - return obj->Thread(); - } - - DWORD CALLBACK Thread() - { - - while( dsound_running ) - { - u32 rv = WaitForMultipleObjects(numBuffers,buffer_events,FALSE,200); - - s16* p1, *oldp1; - LPVOID p2; - DWORD s1,s2; - - u32 poffset=BufferSizeBytes * rv; - -#ifdef _DEBUG - verifyc(buffer->Lock(poffset,BufferSizeBytes,(LPVOID*)&p1,&s1,&p2,&s2,0)); -#else - if( FAILED(buffer->Lock(poffset,BufferSizeBytes,(LPVOID*)&p1,&s1,&p2,&s2,0) ) ) - { - fputs( " * SPU2 : Directsound Warning > Buffer lock failure. You may need to increase the DSound buffer count.\n", stderr ); - continue; - } -#endif - oldp1 = p1; - - for(int p=0; pReadSamples( p1 ); - -#ifndef PUBLIC - verifyc(buffer->Unlock(oldp1,s1,p2,s2)); -#else - buffer->Unlock(oldp1,s1,p2,s2); -#endif - // Set the write pointer to the beginning of the next block. - myLastWrite = (poffset + BufferSizeBytes) & ~BufferSizeBytes; - } - return 0; - } - -public: - s32 Init(SndBuffer *sb) - { - buff = sb; - numBuffers = Config_DSoundOut.NumBuffers; - - // - // Initialize DSound - // - GUID cGuid; - bool success = false; - - if( (strlen(Config_DSoundOut.Device)>0)&&(!FAILED(GUIDFromString(Config_DSoundOut.Device,&cGuid)))) - { - if( !FAILED( DirectSoundCreate8(&cGuid,&dsound,NULL) ) ) - success = true; - } - - // if the GUID failed, just open up the default dsound driver: - if( !success ) - { - verifyc(DirectSoundCreate8(NULL,&dsound,NULL)); - } - - verifyc(dsound->SetCooperativeLevel(GetDesktopWindow(),DSSCL_PRIORITY)); - IDirectSoundBuffer* buffer_; - DSBUFFERDESC desc; - - // Set up WAV format structure. - - memset(&wfx, 0, sizeof(WAVEFORMATEX)); - wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.nSamplesPerSec = SampleRate; - wfx.nChannels=2; - wfx.wBitsPerSample = 16; - wfx.nBlockAlign = 2*2; - wfx.nAvgBytesPerSec = SampleRate * wfx.nBlockAlign; - wfx.cbSize=0; - - // Set up DSBUFFERDESC structure. - - memset(&desc, 0, sizeof(DSBUFFERDESC)); - desc.dwSize = sizeof(DSBUFFERDESC); - desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; - desc.dwBufferBytes = BufferSizeBytes * numBuffers; - desc.lpwfxFormat = &wfx; - - desc.dwFlags |=DSBCAPS_LOCSOFTWARE; - desc.dwFlags|=DSBCAPS_GLOBALFOCUS; - - verifyc(dsound->CreateSoundBuffer(&desc,&buffer_,0)); - verifyc(buffer_->QueryInterface(IID_IDirectSoundBuffer8,(void**)&buffer)); - buffer_->Release(); - - verifyc(buffer->QueryInterface(IID_IDirectSoundNotify8,(void**)&buffer_notify)); - - DSBPOSITIONNOTIFY not[MAX_BUFFER_COUNT]; - - for(u32 i=0;iSetNotificationPositions(numBuffers,not); - - LPVOID p1=0,p2=0; - DWORD s1=0,s2=0; - - verifyc(buffer->Lock(0,desc.dwBufferBytes,&p1,&s1,&p2,&s2,0)); - assert(p2==0); - memset(p1,0,s1); - verifyc(buffer->Unlock(p1,s1,p2,s2)); - - //Play the buffer ! - verifyc(buffer->Play(0,0,DSBPLAY_LOOPING)); - - // Start Thread - myLastWrite = 0; - dsound_running=true; - thread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RThread,this,0,&tid); - SetThreadPriority(thread,THREAD_PRIORITY_TIME_CRITICAL); - - return 0; - } - - void Close() - { - // Stop Thread - fprintf(stderr," * SPU2: Waiting for DSound thread to finish..."); - dsound_running=false; - - WaitForSingleObject(thread,INFINITE); - CloseHandle(thread); - - fprintf(stderr," Done.\n"); - - // - // Clean up - // - if( buffer != NULL ) - { - buffer->Stop(); - - for(u32 i=0;i=0) - { - SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_SETCURSEL,tSel,0); - } - - char temp[128]; - INIT_SLIDER( IDC_BUFFERS_SLIDER, 2, MAX_BUFFER_COUNT, 2, 1, 1 ); - SendMessage(GetDlgItem(hWnd,IDC_BUFFERS_SLIDER),TBM_SETPOS,TRUE,Config_DSoundOut.NumBuffers); - sprintf_s(temp, 128, "%d (%d ms latency)",Config_DSoundOut.NumBuffers, 1000 / (96000 / (Config_DSoundOut.NumBuffers * BufferSize))); - SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp); - - break; - case WM_COMMAND: - wmId = LOWORD(wParam); - wmEvent = HIWORD(wParam); - // Parse the menu selections: - switch (wmId) - { - case IDOK: - { - int i = (int)SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_GETCURSEL,0,0); - - if(!devices[i].hasGuid) - { - Config_DSoundOut.Device[0] = 0; // clear device name to "" - } - else - { - sprintf_s(Config_DSoundOut.Device,256,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", - devices[i].guid.Data1, - devices[i].guid.Data2, - devices[i].guid.Data3, - devices[i].guid.Data4[0], - devices[i].guid.Data4[1], - devices[i].guid.Data4[2], - devices[i].guid.Data4[3], - devices[i].guid.Data4[4], - devices[i].guid.Data4[5], - devices[i].guid.Data4[6], - devices[i].guid.Data4[7] - ); - } - - Config_DSoundOut.NumBuffers = (int)SendMessage( GetDlgItem( hWnd, IDC_BUFFERS_SLIDER ), TBM_GETPOS, 0, 0 ); - - if( Config_DSoundOut.NumBuffers < 2 ) Config_DSoundOut.NumBuffers = 2; - if( Config_DSoundOut.NumBuffers > MAX_BUFFER_COUNT ) Config_DSoundOut.NumBuffers = MAX_BUFFER_COUNT; - } - EndDialog(hWnd,0); - break; - case IDCANCEL: - EndDialog(hWnd,0); - break; - default: - return FALSE; - } - break; - - case WM_HSCROLL: - wmId = LOWORD(wParam); - wmEvent = HIWORD(wParam); - switch(wmId) { - //case TB_ENDTRACK: - //case TB_THUMBPOSITION: - case TB_LINEUP: - case TB_LINEDOWN: - case TB_PAGEUP: - case TB_PAGEDOWN: - wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0); - case TB_THUMBTRACK: - if( wmEvent < 2 ) wmEvent = 2; - if( wmEvent > MAX_BUFFER_COUNT ) wmEvent = MAX_BUFFER_COUNT; - SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent); - sprintf_s(temp,128,"%d (%d ms latency)",wmEvent, 1000 / (96000 / (wmEvent * BufferSize))); - SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp); - break; - default: - return FALSE; - } - break; - - default: - return FALSE; - } - return TRUE; - } - -public: - virtual void Configure(HWND parent) - { - INT_PTR ret; - ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_DSOUND),GetActiveWindow(),(DLGPROC)ConfigProc,1); - if(ret==-1) - { - MessageBoxEx(GetActiveWindow(),"Error Opening the config dialog.","OMG ERROR!",MB_OK,0); - return; - } - } - - virtual bool Is51Out() const { return false; } - - s32 Test() const - { - return 0; - } - - int GetEmptySampleCount() const - { - DWORD play, write; - buffer->GetCurrentPosition( &play, &write ); - - // Note: Dsound's write cursor is bogus. Use our own instead: - - int empty = play - myLastWrite; - if( empty < 0 ) - empty = -empty; - - return empty / 2; - } - - const char* GetIdent() const - { - return "dsound"; - } - - const char* GetLongName() const - { - return "DirectSound (nice)"; - } - -} DS; - -SndOutModule *DSoundOut=&DS; +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#define _WIN32_DCOM +#include "spu2.h" +#include "dialogs.h" +#include +#include +#include +#include +#include +#include +#include +#include + +struct ds_device_data { + char name[256]; + GUID guid; + bool hasGuid; +}; + +static ds_device_data devices[32]; +static int ndevs; +static GUID DevGuid; // currently employed GUID. +static bool haveGuid; + +HRESULT GUIDFromString(const char *str, LPGUID guid) +{ + // "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" + + struct T{ // this is a hack because for some reason sscanf writes too much :/ + GUID g; + int k; + } t; + + int r = sscanf_s(str,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + &t.g.Data1, + &t.g.Data2, + &t.g.Data3, + &t.g.Data4[0], + &t.g.Data4[1], + &t.g.Data4[2], + &t.g.Data4[3], + &t.g.Data4[4], + &t.g.Data4[5], + &t.g.Data4[6], + &t.g.Data4[7] + ); + + if(r!=11) return -1; + + *guid = t.g; + return 0; +} + +class DSound: public SndOutModule +{ +private: + # define MAX_BUFFER_COUNT 8 + + static const int PacketsPerBuffer = 1; + static const int BufferSize = SndOutPacketSize * PacketsPerBuffer; + static const int BufferSizeBytes = BufferSize << 1; + + + FILE *voicelog; + + u32 numBuffers; // cached copy of our configuration setting. + int channel; + int myLastWrite; // last write position, in bytes + + bool dsound_running; + HANDLE thread; + DWORD tid; + + IDirectSound8* dsound; + IDirectSoundBuffer8* buffer; + IDirectSoundNotify8* buffer_notify; + HANDLE buffer_events[MAX_BUFFER_COUNT]; + + WAVEFORMATEX wfx; + + HANDLE waitEvent; + + SndBuffer *buff; + +# define STRFY(x) #x +# define verifyc(x) if(Verifyc(x,STRFY(x))) return -1; + + int __forceinline Verifyc(HRESULT hr,const char* fn) + { + if(FAILED(hr)) + { + SysMessage("ERROR: Call to %s Failed.",fn); + return -1; + } + return 0; + } + + static DWORD CALLBACK RThread(DSound*obj) + { + return obj->Thread(); + } + + DWORD CALLBACK Thread() + { + + while( dsound_running ) + { + u32 rv = WaitForMultipleObjects(numBuffers,buffer_events,FALSE,200); + + s16* p1, *oldp1; + LPVOID p2; + DWORD s1,s2; + + u32 poffset=BufferSizeBytes * rv; + +#ifdef _DEBUG + verifyc(buffer->Lock(poffset,BufferSizeBytes,(LPVOID*)&p1,&s1,&p2,&s2,0)); +#else + if( FAILED(buffer->Lock(poffset,BufferSizeBytes,(LPVOID*)&p1,&s1,&p2,&s2,0) ) ) + { + fputs( " * SPU2 : Directsound Warning > Buffer lock failure. You may need to increase the DSound buffer count.\n", stderr ); + continue; + } +#endif + oldp1 = p1; + + for(int p=0; pReadSamples( p1 ); + +#ifndef PUBLIC + verifyc(buffer->Unlock(oldp1,s1,p2,s2)); +#else + buffer->Unlock(oldp1,s1,p2,s2); +#endif + // Set the write pointer to the beginning of the next block. + myLastWrite = (poffset + BufferSizeBytes) & ~BufferSizeBytes; + } + return 0; + } + +public: + s32 Init(SndBuffer *sb) + { + buff = sb; + numBuffers = Config_DSoundOut.NumBuffers; + + // + // Initialize DSound + // + GUID cGuid; + bool success = false; + + if( (strlen(Config_DSoundOut.Device)>0)&&(!FAILED(GUIDFromString(Config_DSoundOut.Device,&cGuid)))) + { + if( !FAILED( DirectSoundCreate8(&cGuid,&dsound,NULL) ) ) + success = true; + } + + // if the GUID failed, just open up the default dsound driver: + if( !success ) + { + verifyc(DirectSoundCreate8(NULL,&dsound,NULL)); + } + + verifyc(dsound->SetCooperativeLevel(GetDesktopWindow(),DSSCL_PRIORITY)); + IDirectSoundBuffer* buffer_; + DSBUFFERDESC desc; + + // Set up WAV format structure. + + memset(&wfx, 0, sizeof(WAVEFORMATEX)); + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nSamplesPerSec = SampleRate; + wfx.nChannels=2; + wfx.wBitsPerSample = 16; + wfx.nBlockAlign = 2*2; + wfx.nAvgBytesPerSec = SampleRate * wfx.nBlockAlign; + wfx.cbSize=0; + + // Set up DSBUFFERDESC structure. + + memset(&desc, 0, sizeof(DSBUFFERDESC)); + desc.dwSize = sizeof(DSBUFFERDESC); + desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; + desc.dwBufferBytes = BufferSizeBytes * numBuffers; + desc.lpwfxFormat = &wfx; + + desc.dwFlags |=DSBCAPS_LOCSOFTWARE; + desc.dwFlags|=DSBCAPS_GLOBALFOCUS; + + verifyc(dsound->CreateSoundBuffer(&desc,&buffer_,0)); + verifyc(buffer_->QueryInterface(IID_IDirectSoundBuffer8,(void**)&buffer)); + buffer_->Release(); + + verifyc(buffer->QueryInterface(IID_IDirectSoundNotify8,(void**)&buffer_notify)); + + DSBPOSITIONNOTIFY not[MAX_BUFFER_COUNT]; + + for(u32 i=0;iSetNotificationPositions(numBuffers,not); + + LPVOID p1=0,p2=0; + DWORD s1=0,s2=0; + + verifyc(buffer->Lock(0,desc.dwBufferBytes,&p1,&s1,&p2,&s2,0)); + assert(p2==0); + memset(p1,0,s1); + verifyc(buffer->Unlock(p1,s1,p2,s2)); + + //Play the buffer ! + verifyc(buffer->Play(0,0,DSBPLAY_LOOPING)); + + // Start Thread + myLastWrite = 0; + dsound_running=true; + thread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RThread,this,0,&tid); + SetThreadPriority(thread,THREAD_PRIORITY_TIME_CRITICAL); + + return 0; + } + + void Close() + { + // Stop Thread + fprintf(stderr," * SPU2: Waiting for DSound thread to finish..."); + dsound_running=false; + + WaitForSingleObject(thread,INFINITE); + CloseHandle(thread); + + fprintf(stderr," Done.\n"); + + // + // Clean up + // + if( buffer != NULL ) + { + buffer->Stop(); + + for(u32 i=0;i=0) + { + SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_SETCURSEL,tSel,0); + } + + char temp[128]; + INIT_SLIDER( IDC_BUFFERS_SLIDER, 2, MAX_BUFFER_COUNT, 2, 1, 1 ); + SendMessage(GetDlgItem(hWnd,IDC_BUFFERS_SLIDER),TBM_SETPOS,TRUE,Config_DSoundOut.NumBuffers); + sprintf_s(temp, 128, "%d (%d ms latency)",Config_DSoundOut.NumBuffers, 1000 / (96000 / (Config_DSoundOut.NumBuffers * BufferSize))); + SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp); + + break; + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case IDOK: + { + int i = (int)SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_GETCURSEL,0,0); + + if(!devices[i].hasGuid) + { + Config_DSoundOut.Device[0] = 0; // clear device name to "" + } + else + { + sprintf_s(Config_DSoundOut.Device,256,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + devices[i].guid.Data1, + devices[i].guid.Data2, + devices[i].guid.Data3, + devices[i].guid.Data4[0], + devices[i].guid.Data4[1], + devices[i].guid.Data4[2], + devices[i].guid.Data4[3], + devices[i].guid.Data4[4], + devices[i].guid.Data4[5], + devices[i].guid.Data4[6], + devices[i].guid.Data4[7] + ); + } + + Config_DSoundOut.NumBuffers = (int)SendMessage( GetDlgItem( hWnd, IDC_BUFFERS_SLIDER ), TBM_GETPOS, 0, 0 ); + + if( Config_DSoundOut.NumBuffers < 2 ) Config_DSoundOut.NumBuffers = 2; + if( Config_DSoundOut.NumBuffers > MAX_BUFFER_COUNT ) Config_DSoundOut.NumBuffers = MAX_BUFFER_COUNT; + } + EndDialog(hWnd,0); + break; + case IDCANCEL: + EndDialog(hWnd,0); + break; + default: + return FALSE; + } + break; + + case WM_HSCROLL: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + switch(wmId) { + //case TB_ENDTRACK: + //case TB_THUMBPOSITION: + case TB_LINEUP: + case TB_LINEDOWN: + case TB_PAGEUP: + case TB_PAGEDOWN: + wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0); + case TB_THUMBTRACK: + if( wmEvent < 2 ) wmEvent = 2; + if( wmEvent > MAX_BUFFER_COUNT ) wmEvent = MAX_BUFFER_COUNT; + SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent); + sprintf_s(temp,128,"%d (%d ms latency)",wmEvent, 1000 / (96000 / (wmEvent * BufferSize))); + SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp); + break; + default: + return FALSE; + } + break; + + default: + return FALSE; + } + return TRUE; + } + +public: + virtual void Configure(HWND parent) + { + INT_PTR ret; + ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_DSOUND),GetActiveWindow(),(DLGPROC)ConfigProc,1); + if(ret==-1) + { + MessageBoxEx(GetActiveWindow(),"Error Opening the config dialog.","OMG ERROR!",MB_OK,0); + return; + } + } + + virtual bool Is51Out() const { return false; } + + s32 Test() const + { + return 0; + } + + int GetEmptySampleCount() const + { + DWORD play, write; + buffer->GetCurrentPosition( &play, &write ); + + // Note: Dsound's write cursor is bogus. Use our own instead: + + int empty = play - myLastWrite; + if( empty < 0 ) + empty = -empty; + + return empty / 2; + } + + const char* GetIdent() const + { + return "dsound"; + } + + const char* GetLongName() const + { + return "DirectSound (nice)"; + } + +} DS; + +SndOutModule *DSoundOut=&DS; diff --git a/plugins/spu2ghz/src/Win32/dsp.cpp b/plugins/spu2ghz/src/Win32/dsp.cpp index ca8fd681d4..4f37bdcb54 100644 --- a/plugins/spu2ghz/src/Win32/dsp.cpp +++ b/plugins/spu2ghz/src/Win32/dsp.cpp @@ -1,174 +1,174 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -#include "spu2.h" - -extern "C" { -#include "dsp.h" - -typedef winampDSPHeader* (*pWinampDSPGetHeader2)(); -} - -HMODULE hLib = NULL; -pWinampDSPGetHeader2 pGetHeader = NULL; -winampDSPHeader* pHeader = NULL; - -winampDSPModule* pModule = NULL; - -HWND hTemp; - -#define USE_A_THREAD -#ifdef USE_A_THREAD - -HANDLE hUpdateThread; -DWORD UpdateThreadId; - -bool running; - -DWORD WINAPI DspUpdateThread(PVOID param); -#endif -s32 DspLoadLibrary(char *fileName, int modNum) -#ifdef USE_A_THREAD -{ - if(!dspPluginEnabled) return -1; - - running=true; - hUpdateThread = CreateThread(NULL,0,DspUpdateThread,NULL,0,&UpdateThreadId); - return (hUpdateThread==INVALID_HANDLE_VALUE); -} - -s32 DspLoadLibrary2(char *fileName, int modNum) -#endif -{ - if(!dspPluginEnabled) return -1; - - hLib = LoadLibraryA(fileName); - if(!hLib) - { - return 1; - } - - pGetHeader = (pWinampDSPGetHeader2)GetProcAddress(hLib,"winampDSPGetHeader2"); - - if(!pGetHeader) - { - FreeLibrary(hLib); - hLib=NULL; - return 1; - } - - pHeader = pGetHeader(); - - pModule = pHeader->getModule(modNum); - - if(!pModule) - { - pGetHeader=NULL; - pHeader=NULL; - FreeLibrary(hLib); - hLib=NULL; - return -1; - } - - pModule->hDllInstance = hLib; - pModule->hwndParent=0; - pModule->Init(pModule); - - return 0; -} - -void DspCloseLibrary() -#ifdef USE_A_THREAD -{ - if(!dspPluginEnabled) return ; - - PostThreadMessage(UpdateThreadId,WM_QUIT,0,0); - running=false; - if(WaitForSingleObject(hUpdateThread,1000)==WAIT_TIMEOUT) - { - TerminateThread(hUpdateThread,1); - } -} - -void DspCloseLibrary2() -#endif -{ - if(!dspPluginEnabled) return ; - - if(hLib) - { - pModule->Quit(pModule); - FreeLibrary(hLib); - } - pModule=NULL; - pHeader=NULL; - pGetHeader=NULL; - hLib=NULL; -} - -int DspProcess(s16 *buffer, int samples) -{ - if(!dspPluginEnabled) return samples; - - if(hLib) - { - return pModule->ModifySamples(pModule,buffer,samples,16,2,SampleRate); - } - return samples; -} - -void DspUpdate() -#ifdef USE_A_THREAD -{ -} - -DWORD WINAPI DspUpdateThread(PVOID param) -{ - if(!dspPluginEnabled) return -1; - - if(DspLoadLibrary2(dspPlugin,dspPluginModule)) - return -1; - - MSG msg; - while(running) - { - GetMessage(&msg,0,0,0); - if((msg.hwnd==NULL)&&(msg.message==WM_QUIT)) - { - break; - } - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - DspCloseLibrary2(); - return 0; -} - -#else -{ - if(!dspPluginEnabled) return; - - MSG msg; - while(PeekMessage(&msg,0,0,0,PM_REMOVE)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } -} - +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#include "spu2.h" + +extern "C" { +#include "dsp.h" + +typedef winampDSPHeader* (*pWinampDSPGetHeader2)(); +} + +HMODULE hLib = NULL; +pWinampDSPGetHeader2 pGetHeader = NULL; +winampDSPHeader* pHeader = NULL; + +winampDSPModule* pModule = NULL; + +HWND hTemp; + +#define USE_A_THREAD +#ifdef USE_A_THREAD + +HANDLE hUpdateThread; +DWORD UpdateThreadId; + +bool running; + +DWORD WINAPI DspUpdateThread(PVOID param); +#endif +s32 DspLoadLibrary(char *fileName, int modNum) +#ifdef USE_A_THREAD +{ + if(!dspPluginEnabled) return -1; + + running=true; + hUpdateThread = CreateThread(NULL,0,DspUpdateThread,NULL,0,&UpdateThreadId); + return (hUpdateThread==INVALID_HANDLE_VALUE); +} + +s32 DspLoadLibrary2(char *fileName, int modNum) +#endif +{ + if(!dspPluginEnabled) return -1; + + hLib = LoadLibraryA(fileName); + if(!hLib) + { + return 1; + } + + pGetHeader = (pWinampDSPGetHeader2)GetProcAddress(hLib,"winampDSPGetHeader2"); + + if(!pGetHeader) + { + FreeLibrary(hLib); + hLib=NULL; + return 1; + } + + pHeader = pGetHeader(); + + pModule = pHeader->getModule(modNum); + + if(!pModule) + { + pGetHeader=NULL; + pHeader=NULL; + FreeLibrary(hLib); + hLib=NULL; + return -1; + } + + pModule->hDllInstance = hLib; + pModule->hwndParent=0; + pModule->Init(pModule); + + return 0; +} + +void DspCloseLibrary() +#ifdef USE_A_THREAD +{ + if(!dspPluginEnabled) return ; + + PostThreadMessage(UpdateThreadId,WM_QUIT,0,0); + running=false; + if(WaitForSingleObject(hUpdateThread,1000)==WAIT_TIMEOUT) + { + TerminateThread(hUpdateThread,1); + } +} + +void DspCloseLibrary2() +#endif +{ + if(!dspPluginEnabled) return ; + + if(hLib) + { + pModule->Quit(pModule); + FreeLibrary(hLib); + } + pModule=NULL; + pHeader=NULL; + pGetHeader=NULL; + hLib=NULL; +} + +int DspProcess(s16 *buffer, int samples) +{ + if(!dspPluginEnabled) return samples; + + if(hLib) + { + return pModule->ModifySamples(pModule,buffer,samples,16,2,SampleRate); + } + return samples; +} + +void DspUpdate() +#ifdef USE_A_THREAD +{ +} + +DWORD WINAPI DspUpdateThread(PVOID param) +{ + if(!dspPluginEnabled) return -1; + + if(DspLoadLibrary2(dspPlugin,dspPluginModule)) + return -1; + + MSG msg; + while(running) + { + GetMessage(&msg,0,0,0); + if((msg.hwnd==NULL)&&(msg.message==WM_QUIT)) + { + break; + } + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + DspCloseLibrary2(); + return 0; +} + +#else +{ + if(!dspPluginEnabled) return; + + MSG msg; + while(PeekMessage(&msg,0,0,0,PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + #endif \ No newline at end of file diff --git a/plugins/spu2ghz/src/Win32/dsp.h b/plugins/spu2ghz/src/Win32/dsp.h index d0675782d5..ca1d187484 100644 --- a/plugins/spu2ghz/src/Win32/dsp.h +++ b/plugins/spu2ghz/src/Win32/dsp.h @@ -1,56 +1,56 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// - -// DSP plugin interface - -// notes: -// any window that remains in foreground should optimally pass unused -// keystrokes to the parent (winamp's) window, so that the user -// can still control it. As for storing configuration, -// Configuration data should be stored in \plugin.ini -// (look at the vis plugin for configuration code) - -typedef struct winampDSPModule { - char *description; // description - HWND hwndParent; // parent window (filled in by calling app) - HINSTANCE hDllInstance; // instance handle to this DLL (filled in by calling app) - - void (*Config)(struct winampDSPModule *this_mod); // configuration dialog (if needed) - int (*Init)(struct winampDSPModule *this_mod); // 0 on success, creates window, etc (if needed) - - // modify waveform samples: returns number of samples to actually write - // (typically numsamples, but no more than twice numsamples, and no less than half numsamples) - // numsamples should always be at least 128. should, but I'm not sure - int (*ModifySamples)(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate); - - void (*Quit)(struct winampDSPModule *this_mod); // called when unloading - - void *userData; // user data, optional -} winampDSPModule; - -typedef struct { - int version; // DSP_HDRVER - char *description; // description of library - winampDSPModule* (*getModule)(int); // module retrieval function -} winampDSPHeader; - -// exported symbols -typedef winampDSPHeader* (*winampDSPGetHeaderType)(); - -// header version: 0x20 == 0.20 == winamp 2.0 -#define DSP_HDRVER 0x20 +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +// DSP plugin interface + +// notes: +// any window that remains in foreground should optimally pass unused +// keystrokes to the parent (winamp's) window, so that the user +// can still control it. As for storing configuration, +// Configuration data should be stored in \plugin.ini +// (look at the vis plugin for configuration code) + +typedef struct winampDSPModule { + char *description; // description + HWND hwndParent; // parent window (filled in by calling app) + HINSTANCE hDllInstance; // instance handle to this DLL (filled in by calling app) + + void (*Config)(struct winampDSPModule *this_mod); // configuration dialog (if needed) + int (*Init)(struct winampDSPModule *this_mod); // 0 on success, creates window, etc (if needed) + + // modify waveform samples: returns number of samples to actually write + // (typically numsamples, but no more than twice numsamples, and no less than half numsamples) + // numsamples should always be at least 128. should, but I'm not sure + int (*ModifySamples)(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate); + + void (*Quit)(struct winampDSPModule *this_mod); // called when unloading + + void *userData; // user data, optional +} winampDSPModule; + +typedef struct { + int version; // DSP_HDRVER + char *description; // description of library + winampDSPModule* (*getModule)(int); // module retrieval function +} winampDSPHeader; + +// exported symbols +typedef winampDSPHeader* (*winampDSPGetHeaderType)(); + +// header version: 0x20 == 0.20 == winamp 2.0 +#define DSP_HDRVER 0x20 diff --git a/plugins/spu2ghz/src/Win32/resource.h b/plugins/spu2ghz/src/Win32/resource.h index 6c9cf14e7c..a85052f174 100644 --- a/plugins/spu2ghz/src/Win32/resource.h +++ b/plugins/spu2ghz/src/Win32/resource.h @@ -1,86 +1,86 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by SPU2ghz.rc -// -#define IDD_CONFIG 9 -#define IDD_DEBUG 105 -#define IDD_DSOUND 106 -#define IDD_DSOUND51 107 -#define IDD_ASIO 108 -#define IDD_WAVEOUT 109 -#define IDC_EFFECTS 1001 -#define IDC_DUMPREGS 1003 -#define IDC_DUMPMEM 1004 -#define IDC_DUMPCORE 1005 -#define IDC_LOGWAVE 1006 -#define IDC_LOGDMA 1007 -#define IDC_LOGREGS 1008 -#define IDC_DEBUG 1010 -#define IDC_INTERPOLATE 1011 -#define IDC_SRATE 1012 -#define IDC_OUTPUT 1013 -#define IDC_BUFFER 1014 -#define IDC_BUFFERS_SLIDER 1014 -#define IDC_BSIZE 1016 -#define IDC_BCOUNT 1018 -#define IDC_TEXT 1019 -#define IDC_MSGKEY 1020 -#define IDC_MSGDMA 1021 -#define IDC_MSGADMA 1022 -#define IDC_MSGVOICE 1023 -#define IDC_MSGSHOW 1024 -#define IDC_SPEEDLIMIT 1025 -#define IDC_OUTCONF 1028 -#define IDC_DSP_ENABLE 1029 -#define IDC_TS_ENABLE 1030 -#define IDC_DS_DEVICE 1032 -#define IDC_SLIDER1 1033 -#define IDC_LEFT_GAIN_SLIDER 1033 -#define IDC_SLIDER2 1034 -#define IDC_CENTER_GAIN_SLIDER 1034 -#define IDC_SLIDER3 1035 -#define IDC_RIGHT_GAIN_SLIDER 1035 -#define IDC_EDIT1 1036 -#define IDC_LEFT_GAIN_EDIT 1036 -#define IDC_BUTTON1 1037 -#define IDC_SHOW_DEBUG 1037 -#define IDC_DBG_OVERRUNS 1038 -#define IDC_SLIDER4 1039 -#define IDC_DBG_CACHE 1039 -#define IDC_RLEFT_GAIN_SLIDER 1039 -#define IDC_SLIDER5 1040 -#define IDC_DEBUG_GROUP 1040 -#define IDC_LFE_SLIDER 1040 -#define IDC_SLIDER6 1041 -#define IDC_LATENCY_SLIDER 1041 -#define IDC_RRIGHT_GAIN_SLIDER 1041 -#define IDC_SLIDER7 1042 -#define IDC_LATENCY_LABEL 1042 -#define ICD_LR_CENTER_SLIDER 1042 -#define IDC_LR_CENTER_SLIDER 1042 -#define IDC_EDIT2 1043 -#define IDC_CENTER_GAIN_EDIT 1043 -#define IDC_EDIT3 1044 -#define IDC_SPEEDLIMIT_RUNTIME_TOGGLE 1044 -#define IDC_RIGHT_GAIN_EDIT 1044 -#define IDC_EDIT4 1045 -#define IDC_RLEFT_GAIN_EDIT 1045 -#define IDC_EDIT5 1046 -#define IDC_LFE_EDIT 1046 -#define IDC_EDIT6 1047 -#define IDC_VOLBOOST 1047 -#define IDC_RRIGHT_GAIN_EDIT 1047 -#define IDC_EDIT7 1048 -#define IDC_LR_CENTER_EDIT 1048 -#define IDC_LATENCY_LABEL2 1049 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 110 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1048 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by SPU2ghz.rc +// +#define IDD_CONFIG 9 +#define IDD_DEBUG 105 +#define IDD_DSOUND 106 +#define IDD_DSOUND51 107 +#define IDD_ASIO 108 +#define IDD_WAVEOUT 109 +#define IDC_EFFECTS 1001 +#define IDC_DUMPREGS 1003 +#define IDC_DUMPMEM 1004 +#define IDC_DUMPCORE 1005 +#define IDC_LOGWAVE 1006 +#define IDC_LOGDMA 1007 +#define IDC_LOGREGS 1008 +#define IDC_DEBUG 1010 +#define IDC_INTERPOLATE 1011 +#define IDC_SRATE 1012 +#define IDC_OUTPUT 1013 +#define IDC_BUFFER 1014 +#define IDC_BUFFERS_SLIDER 1014 +#define IDC_BSIZE 1016 +#define IDC_BCOUNT 1018 +#define IDC_TEXT 1019 +#define IDC_MSGKEY 1020 +#define IDC_MSGDMA 1021 +#define IDC_MSGADMA 1022 +#define IDC_MSGVOICE 1023 +#define IDC_MSGSHOW 1024 +#define IDC_SPEEDLIMIT 1025 +#define IDC_OUTCONF 1028 +#define IDC_DSP_ENABLE 1029 +#define IDC_TS_ENABLE 1030 +#define IDC_DS_DEVICE 1032 +#define IDC_SLIDER1 1033 +#define IDC_LEFT_GAIN_SLIDER 1033 +#define IDC_SLIDER2 1034 +#define IDC_CENTER_GAIN_SLIDER 1034 +#define IDC_SLIDER3 1035 +#define IDC_RIGHT_GAIN_SLIDER 1035 +#define IDC_EDIT1 1036 +#define IDC_LEFT_GAIN_EDIT 1036 +#define IDC_BUTTON1 1037 +#define IDC_SHOW_DEBUG 1037 +#define IDC_DBG_OVERRUNS 1038 +#define IDC_SLIDER4 1039 +#define IDC_DBG_CACHE 1039 +#define IDC_RLEFT_GAIN_SLIDER 1039 +#define IDC_SLIDER5 1040 +#define IDC_DEBUG_GROUP 1040 +#define IDC_LFE_SLIDER 1040 +#define IDC_SLIDER6 1041 +#define IDC_LATENCY_SLIDER 1041 +#define IDC_RRIGHT_GAIN_SLIDER 1041 +#define IDC_SLIDER7 1042 +#define IDC_LATENCY_LABEL 1042 +#define ICD_LR_CENTER_SLIDER 1042 +#define IDC_LR_CENTER_SLIDER 1042 +#define IDC_EDIT2 1043 +#define IDC_CENTER_GAIN_EDIT 1043 +#define IDC_EDIT3 1044 +#define IDC_SPEEDLIMIT_RUNTIME_TOGGLE 1044 +#define IDC_RIGHT_GAIN_EDIT 1044 +#define IDC_EDIT4 1045 +#define IDC_RLEFT_GAIN_EDIT 1045 +#define IDC_EDIT5 1046 +#define IDC_LFE_EDIT 1046 +#define IDC_EDIT6 1047 +#define IDC_VOLBOOST 1047 +#define IDC_RRIGHT_GAIN_EDIT 1047 +#define IDC_EDIT7 1048 +#define IDC_LR_CENTER_EDIT 1048 +#define IDC_LATENCY_LABEL2 1049 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 110 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1048 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/spu2ghz/src/Win32/vsprops/svnrev_template.h b/plugins/spu2ghz/src/Win32/vsprops/svnrev_template.h index afab6c4fd1..f2656ef1e8 100644 --- a/plugins/spu2ghz/src/Win32/vsprops/svnrev_template.h +++ b/plugins/spu2ghz/src/Win32/vsprops/svnrev_template.h @@ -1,18 +1,18 @@ -// svnrev_template.h --> svnrev.h -// -// This file acts as a template for the automatic SVN revision/version tag. -// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for -// whichever project is being compiled (as indicated by command line options -// passed to SubWCRev.exe during the project's pre-build step). -// -// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs -// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN -// installed on your system. If you do not have it installed, a generic template -// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not -// necessary. If you do not have it installed, everything will still compile -// fine except without the SVN revision tagged to the application/dll version. -// -// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org - -#define SVN_REV $WCREV$ +// svnrev_template.h --> svnrev.h +// +// This file acts as a template for the automatic SVN revision/version tag. +// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for +// whichever project is being compiled (as indicated by command line options +// passed to SubWCRev.exe during the project's pre-build step). +// +// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs +// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN +// installed on your system. If you do not have it installed, a generic template +// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not +// necessary. If you do not have it installed, everything will still compile +// fine except without the SVN revision tagged to the application/dll version. +// +// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV $WCREV$ #define SVN_MODS $WCMODS?1:0$ \ No newline at end of file diff --git a/plugins/spu2ghz/src/Win32/vsprops/svnrev_unknown.h b/plugins/spu2ghz/src/Win32/vsprops/svnrev_unknown.h index a2a3703186..4872e23b20 100644 --- a/plugins/spu2ghz/src/Win32/vsprops/svnrev_unknown.h +++ b/plugins/spu2ghz/src/Win32/vsprops/svnrev_unknown.h @@ -1,23 +1,23 @@ -// svnrev_genric.h --> svnrev.h -// -// This file acts as a placebo for people who do not have TortoiseSVN installed. -// It provides "empty" revision information to the Pcsx2 Playground projects in -// the absence of real revisions derived from the repository being built. -// -// This file does not affect application/dll builds in any significant manner, -// other than the lack of automatic revision tags inserted into the app (which -// is very convenient but hardly necessary). -// -// See svn_template.h for more information on how the process of revision -// templating works. -// -// If you would like to enable automatic revisin tagging, TortoiseSVN can be -// downloaded from http://tortoisesvn.tigris.org - -#define SVN_REV_UNKNOWN - -// The following defines are included so that code will still compile even if it -// doesn't check for the SVN_REV_UNKNOWN define. - -#define SVN_REV 0 +// svnrev_genric.h --> svnrev.h +// +// This file acts as a placebo for people who do not have TortoiseSVN installed. +// It provides "empty" revision information to the Pcsx2 Playground projects in +// the absence of real revisions derived from the repository being built. +// +// This file does not affect application/dll builds in any significant manner, +// other than the lack of automatic revision tags inserted into the app (which +// is very convenient but hardly necessary). +// +// See svn_template.h for more information on how the process of revision +// templating works. +// +// If you would like to enable automatic revisin tagging, TortoiseSVN can be +// downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV_UNKNOWN + +// The following defines are included so that code will still compile even if it +// doesn't check for the SVN_REV_UNKNOWN define. + +#define SVN_REV 0 #define SVN_MODS "" \ No newline at end of file diff --git a/plugins/spu2ghz/src/Win32/xaudio2out.cpp b/plugins/spu2ghz/src/Win32/xaudio2out.cpp index e9dff1d767..211b63b418 100644 --- a/plugins/spu2ghz/src/Win32/xaudio2out.cpp +++ b/plugins/spu2ghz/src/Win32/xaudio2out.cpp @@ -1,235 +1,235 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -#define _WIN32_DCOM -#include "spu2.h" -#include -#include -#include -#include -#include -#include - -class XAudio2Mod: public SndOutModule -{ -private: - static const int PacketsPerBuffer = 1; - static const int BufferSize = SndOutPacketSize * PacketsPerBuffer; - static const int BufferSizeBytes = BufferSize * 2; - - s16* qbuffer; - s32 out_num; - -#define MAX_BUFFER_COUNT 3 - - //-------------------------------------------------------------------------------------- - // Callback structure - //-------------------------------------------------------------------------------------- - class StreamingVoiceContext : public IXAudio2VoiceCallback - { - public: - SndBuffer* sndout; - IXAudio2SourceVoice* pSourceVoice; - CRITICAL_SECTION cs; - - protected: - STDMETHOD_(void, OnVoiceProcessingPassStart) () {} - STDMETHOD_(void, OnVoiceProcessingPassStart) (UINT32) { }; - STDMETHOD_(void, OnVoiceProcessingPassEnd) () {} - STDMETHOD_(void, OnStreamEnd) () {} - STDMETHOD_(void, OnBufferStart) ( void* ) {} - STDMETHOD_(void, OnBufferEnd) ( void* context ) - { - EnterCriticalSection( &cs ); - - // All of these checks are necessary because XAudio2 is wonky shizat. - if( pSourceVoice == NULL || context == NULL ) return; - - s16* qb = (s16*)context; - - for(int p=0; pReadSamples( qb ); - - XAUDIO2_BUFFER buf = {0}; - buf.AudioBytes = BufferSizeBytes; - buf.pAudioData=(BYTE*)context; - buf.pContext=context; - - pSourceVoice->SubmitSourceBuffer( &buf ); - LeaveCriticalSection( &cs ); - } - STDMETHOD_(void, OnLoopEnd) ( void* ) {} - STDMETHOD_(void, OnVoiceError) (THIS_ void* pBufferContext, HRESULT Error) { }; - - } voiceContext; - - IXAudio2* pXAudio2; - IXAudio2MasteringVoice* pMasteringVoice; - IXAudio2SourceVoice* pSourceVoice; - - WAVEFORMATEX wfx; - -public: - - s32 Init(SndBuffer *sb) - { - HRESULT hr; - - // - // Initialize XAudio2 - // - CoInitializeEx( NULL, COINIT_MULTITHREADED ); - - UINT32 flags = 0; -#ifdef _DEBUG - flags |= XAUDIO2_DEBUG_ENGINE; -#endif - - if ( FAILED(hr = XAudio2Create( &pXAudio2, flags ) ) ) - { - SysMessage( "Failed to init XAudio2 engine: %#X\n", hr ); - CoUninitialize(); - return -1; - } - - // - // Create a mastering voice - // - if ( FAILED(hr = pXAudio2->CreateMasteringVoice( &pMasteringVoice, 0, SampleRate ) ) ) - { - SysMessage( "Failed creating mastering voice: %#X\n", hr ); - SAFE_RELEASE( pXAudio2 ); - CoUninitialize(); - return -1; - } - - wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.nSamplesPerSec = SampleRate; - wfx.nChannels=2; - wfx.wBitsPerSample = 16; - wfx.nBlockAlign = 2*2; - wfx.nAvgBytesPerSec = SampleRate * wfx.nBlockAlign; - wfx.cbSize=0; - - InitializeCriticalSection( &voiceContext.cs ); - EnterCriticalSection( &voiceContext.cs ); - - // - // Create an XAudio2 voice to stream this wave - // - if( FAILED(hr = pXAudio2->CreateSourceVoice( &pSourceVoice, &wfx, - XAUDIO2_VOICE_NOSRC, 1.0f, &voiceContext ) ) ) - { - SysMessage( "Error %#X creating source voice\n", hr ); - SAFE_RELEASE( pXAudio2 ); - return -1; - } - - voiceContext.pSourceVoice = pSourceVoice; - voiceContext.sndout = sb; - pSourceVoice->FlushSourceBuffers(); - pSourceVoice->Start( 0, 0 ); - - qbuffer = new s16[BufferSize*MAX_BUFFER_COUNT]; - ZeroMemory(qbuffer,BufferSizeBytes*MAX_BUFFER_COUNT); - - // Start two buffers. - // Frankly two buffers is all we should ever need since the buffer fill code - // is tied directly to the XAudio2 engine. - - { - XAUDIO2_BUFFER buf = {0}; - buf.AudioBytes = BufferSizeBytes; - buf.pContext=qbuffer; - buf.pAudioData=(BYTE*)buf.pContext; - pSourceVoice->SubmitSourceBuffer( &buf ); - } - - { - XAUDIO2_BUFFER buf = {0}; - buf.AudioBytes = BufferSizeBytes; - buf.pContext=&qbuffer[BufferSize]; - buf.pAudioData=(BYTE*)buf.pContext; - pSourceVoice->SubmitSourceBuffer( &buf ); - } - LeaveCriticalSection( &voiceContext.cs ); - - return 0; - } - - void Close() - { - EnterCriticalSection( &voiceContext.cs ); - - // Clean up? - // All XAudio2 interfaces are released when the engine is destroyed, - // but being tidy never hurt. - - // Actually it can hurt. As of DXSDK Aug 2008, doing a full cleanup causes - // XA2 on Vista to crash. Even if you copy/paste code directly from Microsoft. - // But doing no cleanup at all causes XA2 under XP to crash. So after much trial - // and error we found a happy comprimise as follows: - - if( pSourceVoice != NULL ) - pSourceVoice->DestroyVoice(); - - if( pMasteringVoice != NULL ) - pMasteringVoice->DestroyVoice(); - - SAFE_RELEASE( pXAudio2 ); - SAFE_DELETE_ARRAY( qbuffer ); - - pMasteringVoice = NULL; - voiceContext.sndout = NULL; - voiceContext.pSourceVoice = NULL; - pSourceVoice = NULL; - LeaveCriticalSection( &voiceContext.cs ); - DeleteCriticalSection( &voiceContext.cs ); - CoUninitialize(); - } - - virtual void Configure(HWND parent) - { - } - - virtual bool Is51Out() const { return false; } - - s32 Test() const - { - return 0; - } - - int GetEmptySampleCount() const - { - XAUDIO2_VOICE_STATE state; - pSourceVoice->GetState( &state ); - return state.SamplesPlayed & (BufferSize-1); - } - - const char* GetIdent() const - { - return "xaudio2"; - } - - const char* GetLongName() const - { - return "XAudio 2 (Recommended)"; - } - -} XA2; - -SndOutModule *XAudio2Out=&XA2; +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#define _WIN32_DCOM +#include "spu2.h" +#include +#include +#include +#include +#include +#include + +class XAudio2Mod: public SndOutModule +{ +private: + static const int PacketsPerBuffer = 1; + static const int BufferSize = SndOutPacketSize * PacketsPerBuffer; + static const int BufferSizeBytes = BufferSize * 2; + + s16* qbuffer; + s32 out_num; + +#define MAX_BUFFER_COUNT 3 + + //-------------------------------------------------------------------------------------- + // Callback structure + //-------------------------------------------------------------------------------------- + class StreamingVoiceContext : public IXAudio2VoiceCallback + { + public: + SndBuffer* sndout; + IXAudio2SourceVoice* pSourceVoice; + CRITICAL_SECTION cs; + + protected: + STDMETHOD_(void, OnVoiceProcessingPassStart) () {} + STDMETHOD_(void, OnVoiceProcessingPassStart) (UINT32) { }; + STDMETHOD_(void, OnVoiceProcessingPassEnd) () {} + STDMETHOD_(void, OnStreamEnd) () {} + STDMETHOD_(void, OnBufferStart) ( void* ) {} + STDMETHOD_(void, OnBufferEnd) ( void* context ) + { + EnterCriticalSection( &cs ); + + // All of these checks are necessary because XAudio2 is wonky shizat. + if( pSourceVoice == NULL || context == NULL ) return; + + s16* qb = (s16*)context; + + for(int p=0; pReadSamples( qb ); + + XAUDIO2_BUFFER buf = {0}; + buf.AudioBytes = BufferSizeBytes; + buf.pAudioData=(BYTE*)context; + buf.pContext=context; + + pSourceVoice->SubmitSourceBuffer( &buf ); + LeaveCriticalSection( &cs ); + } + STDMETHOD_(void, OnLoopEnd) ( void* ) {} + STDMETHOD_(void, OnVoiceError) (THIS_ void* pBufferContext, HRESULT Error) { }; + + } voiceContext; + + IXAudio2* pXAudio2; + IXAudio2MasteringVoice* pMasteringVoice; + IXAudio2SourceVoice* pSourceVoice; + + WAVEFORMATEX wfx; + +public: + + s32 Init(SndBuffer *sb) + { + HRESULT hr; + + // + // Initialize XAudio2 + // + CoInitializeEx( NULL, COINIT_MULTITHREADED ); + + UINT32 flags = 0; +#ifdef _DEBUG + flags |= XAUDIO2_DEBUG_ENGINE; +#endif + + if ( FAILED(hr = XAudio2Create( &pXAudio2, flags ) ) ) + { + SysMessage( "Failed to init XAudio2 engine: %#X\n", hr ); + CoUninitialize(); + return -1; + } + + // + // Create a mastering voice + // + if ( FAILED(hr = pXAudio2->CreateMasteringVoice( &pMasteringVoice, 0, SampleRate ) ) ) + { + SysMessage( "Failed creating mastering voice: %#X\n", hr ); + SAFE_RELEASE( pXAudio2 ); + CoUninitialize(); + return -1; + } + + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nSamplesPerSec = SampleRate; + wfx.nChannels=2; + wfx.wBitsPerSample = 16; + wfx.nBlockAlign = 2*2; + wfx.nAvgBytesPerSec = SampleRate * wfx.nBlockAlign; + wfx.cbSize=0; + + InitializeCriticalSection( &voiceContext.cs ); + EnterCriticalSection( &voiceContext.cs ); + + // + // Create an XAudio2 voice to stream this wave + // + if( FAILED(hr = pXAudio2->CreateSourceVoice( &pSourceVoice, &wfx, + XAUDIO2_VOICE_NOSRC, 1.0f, &voiceContext ) ) ) + { + SysMessage( "Error %#X creating source voice\n", hr ); + SAFE_RELEASE( pXAudio2 ); + return -1; + } + + voiceContext.pSourceVoice = pSourceVoice; + voiceContext.sndout = sb; + pSourceVoice->FlushSourceBuffers(); + pSourceVoice->Start( 0, 0 ); + + qbuffer = new s16[BufferSize*MAX_BUFFER_COUNT]; + ZeroMemory(qbuffer,BufferSizeBytes*MAX_BUFFER_COUNT); + + // Start two buffers. + // Frankly two buffers is all we should ever need since the buffer fill code + // is tied directly to the XAudio2 engine. + + { + XAUDIO2_BUFFER buf = {0}; + buf.AudioBytes = BufferSizeBytes; + buf.pContext=qbuffer; + buf.pAudioData=(BYTE*)buf.pContext; + pSourceVoice->SubmitSourceBuffer( &buf ); + } + + { + XAUDIO2_BUFFER buf = {0}; + buf.AudioBytes = BufferSizeBytes; + buf.pContext=&qbuffer[BufferSize]; + buf.pAudioData=(BYTE*)buf.pContext; + pSourceVoice->SubmitSourceBuffer( &buf ); + } + LeaveCriticalSection( &voiceContext.cs ); + + return 0; + } + + void Close() + { + EnterCriticalSection( &voiceContext.cs ); + + // Clean up? + // All XAudio2 interfaces are released when the engine is destroyed, + // but being tidy never hurt. + + // Actually it can hurt. As of DXSDK Aug 2008, doing a full cleanup causes + // XA2 on Vista to crash. Even if you copy/paste code directly from Microsoft. + // But doing no cleanup at all causes XA2 under XP to crash. So after much trial + // and error we found a happy comprimise as follows: + + if( pSourceVoice != NULL ) + pSourceVoice->DestroyVoice(); + + if( pMasteringVoice != NULL ) + pMasteringVoice->DestroyVoice(); + + SAFE_RELEASE( pXAudio2 ); + SAFE_DELETE_ARRAY( qbuffer ); + + pMasteringVoice = NULL; + voiceContext.sndout = NULL; + voiceContext.pSourceVoice = NULL; + pSourceVoice = NULL; + LeaveCriticalSection( &voiceContext.cs ); + DeleteCriticalSection( &voiceContext.cs ); + CoUninitialize(); + } + + virtual void Configure(HWND parent) + { + } + + virtual bool Is51Out() const { return false; } + + s32 Test() const + { + return 0; + } + + int GetEmptySampleCount() const + { + XAUDIO2_VOICE_STATE state; + pSourceVoice->GetState( &state ); + return state.SamplesPlayed & (BufferSize-1); + } + + const char* GetIdent() const + { + return "xaudio2"; + } + + const char* GetLongName() const + { + return "XAudio 2 (Recommended)"; + } + +} XA2; + +SndOutModule *XAudio2Out=&XA2; diff --git a/plugins/spu2ghz/src/common/PS2Edefs.h b/plugins/spu2ghz/src/common/PS2Edefs.h index 1f65fc02b9..49b16e16d5 100644 --- a/plugins/spu2ghz/src/common/PS2Edefs.h +++ b/plugins/spu2ghz/src/common/PS2Edefs.h @@ -1,885 +1,885 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef __PS2EDEFS_H__ -#define __PS2EDEFS_H__ - -/* - * PS2E Definitions v0.6.2 (beta) - * - * Author: linuzappz@hotmail.com - * shadowpcsx2@yahoo.gr - * florinsasu@hotmail.com - */ - -/* - Notes: - * Since this is still beta things may change. - - * OSflags: - __LINUX__ (linux OS) - _WIN32 (win32 OS) - - * common return values (for ie. GSinit): - 0 - success - -1 - error - - * reserved keys: - F1 to F10 are reserved for the emulator - - * plugins should NOT change the current - working directory. - (on win32, add flag OFN_NOCHANGEDIR for - GetOpenFileName) - -*/ - -#include "PS2Etypes.h" - - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ - defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ - defined(USBdefs) || defined(FWdefs) -#define COMMONdefs -#endif - -// PS2EgetLibType returns (may be OR'd) -#define PS2E_LT_GS 0x01 -#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- -#define PS2E_LT_SPU2 0x04 -#define PS2E_LT_CDVD 0x08 -#define PS2E_LT_DEV9 0x10 -#define PS2E_LT_USB 0x20 -#define PS2E_LT_FW 0x40 -#define PS2E_LT_SIO 0x80 - -// PS2EgetLibVersion2 (high 16 bits) -#define PS2E_GS_VERSION 0x0006 -#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- -#define PS2E_SPU2_VERSION 0x0005 -#define PS2E_CDVD_VERSION 0x0005 -#define PS2E_DEV9_VERSION 0x0003 -#define PS2E_USB_VERSION 0x0003 -#define PS2E_FW_VERSION 0x0002 -#define PS2E_SIO_VERSION 0x0001 -#ifdef COMMONdefs - -u32 CALLBACK PS2EgetLibType(void); -u32 CALLBACK PS2EgetLibVersion2(u32 type); -char* CALLBACK PS2EgetLibName(void); - -#endif - -// key values: -/* key values must be OS dependant: - win32: the VK_XXX will be used (WinUser) - linux: the XK_XXX will be used (XFree86) -*/ - -// event values: -#define KEYPRESS 1 -#define KEYRELEASE 2 - -typedef struct _keyEvent { - u32 key; - u32 evt; -} keyEvent; - -// for 64bit compilers -typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; - -// plugin types -#define SIO_TYPE_PAD 0x00000001 -#define SIO_TYPE_MTAP 0x00000004 -#define SIO_TYPE_RM 0x00000040 -#define SIO_TYPE_MC 0x00000100 - -typedef int (CALLBACK * SIOchangeSlotCB)(int slot); - -typedef struct _cdvdSubQ { - u8 ctrl:4; // control and mode bits - u8 mode:4; // control and mode bits - u8 trackNum; // current track number (1 to 99) - u8 trackIndex; // current index within track (0 to 99) - u8 trackM; // current minute location on the disc (BCD encoded) - u8 trackS; // current sector location on the disc (BCD encoded) - u8 trackF; // current frame location on the disc (BCD encoded) - u8 pad; // unused - u8 discM; // current minute offset from first track (BCD encoded) - u8 discS; // current sector offset from first track (BCD encoded) - u8 discF; // current frame offset from first track (BCD encoded) -} cdvdSubQ; - -typedef struct _cdvdTD { // NOT bcd coded - u32 lsn; - u8 type; -} cdvdTD; - -typedef struct _cdvdTN { - u8 strack; //number of the first track (usually 1) - u8 etrack; //number of the last track -} cdvdTN; - -// CDVDreadTrack mode values: -#define CDVD_MODE_2352 0 // full 2352 bytes -#define CDVD_MODE_2340 1 // skip sync (12) bytes -#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq - -// CDVDgetDiskType returns: -#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc -#define CDVD_TYPE_DVDV 0xfe // DVD Video -#define CDVD_TYPE_CDDA 0xfd // Audio CD -#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD -#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) -#define CDVD_TYPE_PS2CD 0x12 // PS2 CD -#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) -#define CDVD_TYPE_PSCD 0x10 // PS CD -#define CDVD_TYPE_UNKNOWN 0x05 // Unknown -#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided -#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided -#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd -#define CDVD_TYPE_DETCT 0x01 // Detecting -#define CDVD_TYPE_NODISC 0x00 // No Disc - -// CDVDgetTrayStatus returns: -#define CDVD_TRAY_CLOSE 0x00 -#define CDVD_TRAY_OPEN 0x01 - -// cdvdTD.type (track types for cds) -#define CDVD_AUDIO_TRACK 0x01 -#define CDVD_MODE1_TRACK 0x41 -#define CDVD_MODE2_TRACK 0x61 - -#define CDVD_AUDIO_MASK 0x00 -#define CDVD_DATA_MASK 0x40 -// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) - -typedef void (*DEV9callback)(int cycles); -typedef int (*DEV9handler)(void); - -typedef void (*USBcallback)(int cycles); -typedef int (*USBhandler)(void); - -// freeze modes: -#define FREEZE_LOAD 0 -#define FREEZE_SAVE 1 -#define FREEZE_SIZE 2 - -typedef struct _GSdriverInfo { - char name[8]; - void *common; -} GSdriverInfo; - -#ifdef _WINDOWS_ -typedef struct _winInfo { // unsupported values must be set to zero - HWND hWnd; - HMENU hMenu; - HWND hStatusWnd; -} winInfo; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* GS plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef GSdefs - -// basic funcs - -s32 CALLBACK GSinit(); -s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); -void CALLBACK GSclose(); -void CALLBACK GSshutdown(); -void CALLBACK GSvsync(int field); -void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); -void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); -void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); -void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) -void CALLBACK GSgifSoftReset(u32 mask); -void CALLBACK GSreadFIFO(u64 *mem); -void CALLBACK GSreadFIFO2(u64 *mem, int qwc); - -// extended funcs - -// GSkeyEvent gets called when there is a keyEvent from the PAD plugin -void CALLBACK GSkeyEvent(keyEvent *ev); -void CALLBACK GSchangeSaveState(int, const char* filename); -void CALLBACK GSmakeSnapshot(char *path); -void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); -void CALLBACK GSirqCallback(void (*callback)()); -void CALLBACK GSprintf(int timeout, char *fmt, ...); -void CALLBACK GSsetBaseMem(void*); -void CALLBACK GSsetGameCRC(int crc, int gameoptions); - -// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done -void CALLBACK GSsetFrameSkip(int frameskip); - -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK GSsetupRecording(int start, void* pData); - -void CALLBACK GSreset(); -void CALLBACK GSwriteCSR(u32 value); -void CALLBACK GSgetDriverInfo(GSdriverInfo *info); -#ifdef _WIN32 -s32 CALLBACK GSsetWindowInfo(winInfo *info); -#endif -s32 CALLBACK GSfreeze(int mode, freezeData *data); -void CALLBACK GSconfigure(); -void CALLBACK GSabout(); -s32 CALLBACK GStest(); - -#endif - -/* PAD plugin API -=[ OBSOLETE ]=- */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef PADdefs - -// basic funcs - -s32 CALLBACK PADinit(u32 flags); -s32 CALLBACK PADopen(void *pDsp); -void CALLBACK PADclose(); -void CALLBACK PADshutdown(); -// PADkeyEvent is called every vsync (return NULL if no event) -keyEvent* CALLBACK PADkeyEvent(); -u8 CALLBACK PADstartPoll(int pad); -u8 CALLBACK PADpoll(u8 value); -// returns: 1 if supported pad1 -// 2 if supported pad2 -// 3 if both are supported -u32 CALLBACK PADquery(); - -// call to give a hint to the PAD plugin to query for the keyboard state. A -// good plugin will query the OS for keyboard state ONLY in this function. -// This function is necessary when multithreading because otherwise -// the PAD plugin can get into deadlocks with the thread that really owns -// the window (and input). Note that PADupdate can be called from a different -// thread than the other functions, so mutex or other multithreading primitives -// have to be added to maintain data integrity. -void CALLBACK PADupdate(int pad); - -// extended funcs - -void CALLBACK PADgsDriverInfo(GSdriverInfo *info); -void CALLBACK PADconfigure(); -void CALLBACK PADabout(); -s32 CALLBACK PADtest(); - -#endif - -/* SIO plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SIOdefs - -// basic funcs - -s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); -s32 CALLBACK SIOopen(void *pDsp); -void CALLBACK SIOclose(); -void CALLBACK SIOshutdown(); -u8 CALLBACK SIOstartPoll(u8 value); -u8 CALLBACK SIOpoll(u8 value); -// returns: SIO_TYPE_{PAD,MTAP,RM,MC} -u32 CALLBACK SIOquery(); - -// extended funcs - -void CALLBACK SIOconfigure(); -void CALLBACK SIOabout(); -s32 CALLBACK SIOtest(); - -#endif - -/* SPU2 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SPU2defs - -// basic funcs - -s32 CALLBACK SPU2init(); -s32 CALLBACK SPU2open(void *pDsp); -void CALLBACK SPU2close(); -void CALLBACK SPU2shutdown(); -void CALLBACK SPU2write(u32 mem, u16 value); -u16 CALLBACK SPU2read(u32 mem); -void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA4(); -void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); -void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); - -// all addresses passed by dma will be pointers to the array starting at baseaddr -// This function is necessary to successfully save and reload the spu2 state -void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); - -void CALLBACK SPU2interruptDMA7(); -u32 CALLBACK SPU2ReadMemAddr(int core); -void CALLBACK SPU2WriteMemAddr(int core,u32 value); -void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); - -// extended funcs -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK SPU2setupRecording(int start, void* pData); - -void CALLBACK SPU2setClockPtr(u32* ptr); -void CALLBACK SPU2setTimeStretcher(short int enable); - -void CALLBACK SPU2async(u32 cycles); -s32 CALLBACK SPU2freeze(int mode, freezeData *data); -void CALLBACK SPU2configure(); -void CALLBACK SPU2about(); -s32 CALLBACK SPU2test(); - -#endif - -/* CDVD plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef CDVDdefs - -// basic funcs - -s32 CALLBACK CDVDinit(); -s32 CALLBACK CDVDopen(const char* pTitleFilename); -void CALLBACK CDVDclose(); -void CALLBACK CDVDshutdown(); -s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); - -// return can be NULL (for async modes) -u8* CALLBACK CDVDgetBuffer(); - -s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) -s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information -s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type -s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc -s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx -s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx -s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray -s32 CALLBACK CDVDctrlTrayClose(); //close disc tray - -// extended funcs - -void CALLBACK CDVDconfigure(); -void CALLBACK CDVDabout(); -s32 CALLBACK CDVDtest(); -void CALLBACK CDVDnewDiskCB(void (*callback)()); - -#endif - -/* DEV9 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef DEV9defs - -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK DEV9init(); -s32 CALLBACK DEV9open(void *pDsp); -void CALLBACK DEV9close(); -void CALLBACK DEV9shutdown(); -u8 CALLBACK DEV9read8(u32 addr); -u16 CALLBACK DEV9read16(u32 addr); -u32 CALLBACK DEV9read32(u32 addr); -void CALLBACK DEV9write8(u32 addr, u8 value); -void CALLBACK DEV9write16(u32 addr, u16 value); -void CALLBACK DEV9write32(u32 addr, u32 value); -void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); -void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK DEV9irqCallback(DEV9callback callback); -DEV9handler CALLBACK DEV9irqHandler(void); - -// extended funcs - -s32 CALLBACK DEV9freeze(int mode, freezeData *data); -void CALLBACK DEV9configure(); -void CALLBACK DEV9about(); -s32 CALLBACK DEV9test(); - -#endif - -/* USB plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef USBdefs - -// basic funcs - -s32 CALLBACK USBinit(); -s32 CALLBACK USBopen(void *pDsp); -void CALLBACK USBclose(); -void CALLBACK USBshutdown(); -u8 CALLBACK USBread8(u32 addr); -u16 CALLBACK USBread16(u32 addr); -u32 CALLBACK USBread32(u32 addr); -void CALLBACK USBwrite8(u32 addr, u8 value); -void CALLBACK USBwrite16(u32 addr, u16 value); -void CALLBACK USBwrite32(u32 addr, u32 value); -void CALLBACK USBasync(u32 cycles); - -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK USBirqCallback(USBcallback callback); -USBhandler CALLBACK USBirqHandler(void); -void CALLBACK USBsetRAM(void *mem); - -// extended funcs - -s32 CALLBACK USBfreeze(int mode, freezeData *data); -void CALLBACK USBconfigure(); -void CALLBACK USBabout(); -s32 CALLBACK USBtest(); - -#endif - -/* FW plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef FWdefs -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK FWinit(); -s32 CALLBACK FWopen(void *pDsp); -void CALLBACK FWclose(); -void CALLBACK FWshutdown(); -u32 CALLBACK FWread32(u32 addr); -void CALLBACK FWwrite32(u32 addr, u32 value); -void CALLBACK FWirqCallback(void (*callback)()); - -// extended funcs - -s32 CALLBACK FWfreeze(int mode, freezeData *data); -void CALLBACK FWconfigure(); -void CALLBACK FWabout(); -s32 CALLBACK FWtest(); -#endif - -// might be useful for emulators -#ifdef PLUGINtypedefs - -typedef u32 (CALLBACK* _PS2EgetLibType)(void); -typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); -typedef char*(CALLBACK* _PS2EgetLibName)(void); - -// GS -// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _GSinit)(); -typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); -typedef void (CALLBACK* _GSclose)(); -typedef void (CALLBACK* _GSshutdown)(); -typedef void (CALLBACK* _GSvsync)(int field); -typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); -typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) -typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); -typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); -typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); - -typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); -typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); -typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); -typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); -typedef void (CALLBACK* _GSsetBaseMem)(void*); -typedef void (CALLBACK* _GSsetGameCRC)(int, int); -typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); -typedef int (CALLBACK* _GSsetupRecording)(int, void*); -typedef void (CALLBACK* _GSreset)(); -typedef void (CALLBACK* _GSwriteCSR)(u32 value); -typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); -#ifdef _WINDOWS_ -typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); -#endif -typedef void (CALLBACK* _GSmakeSnapshot)(const char *path); -typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); -typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _GSconfigure)(); -typedef s32 (CALLBACK* _GStest)(); -typedef void (CALLBACK* _GSabout)(); - -// PAD -typedef s32 (CALLBACK* _PADinit)(u32 flags); -typedef s32 (CALLBACK* _PADopen)(void *pDsp); -typedef void (CALLBACK* _PADclose)(); -typedef void (CALLBACK* _PADshutdown)(); -typedef keyEvent* (CALLBACK* _PADkeyEvent)(); -typedef u8 (CALLBACK* _PADstartPoll)(int pad); -typedef u8 (CALLBACK* _PADpoll)(u8 value); -typedef u32 (CALLBACK* _PADquery)(); -typedef void (CALLBACK* _PADupdate)(int pad); - -typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); -typedef void (CALLBACK* _PADconfigure)(); -typedef s32 (CALLBACK* _PADtest)(); -typedef void (CALLBACK* _PADabout)(); - -// SIO -typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); -typedef s32 (CALLBACK* _SIOopen)(void *pDsp); -typedef void (CALLBACK* _SIOclose)(); -typedef void (CALLBACK* _SIOshutdown)(); -typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); -typedef u8 (CALLBACK* _SIOpoll)(u8 value); -typedef u32 (CALLBACK* _SIOquery)(); - -typedef void (CALLBACK* _SIOconfigure)(); -typedef s32 (CALLBACK* _SIOtest)(); -typedef void (CALLBACK* _SIOabout)(); - -// SPU2 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _SPU2init)(); -typedef s32 (CALLBACK* _SPU2open)(void *pDsp); -typedef void (CALLBACK* _SPU2close)(); -typedef void (CALLBACK* _SPU2shutdown)(); -typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); -typedef u16 (CALLBACK* _SPU2read)(u32 mem); -typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA4)(); -typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); -typedef void (CALLBACK* _SPU2interruptDMA7)(); -typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); -typedef int (CALLBACK* _SPU2setupRecording)(int, void*); - -typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); -typedef void (CALLBACK* _SPU2setTimeStretcher)(short int enable); - -typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); -typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); -typedef void (CALLBACK* _SPU2async)(u32 cycles); -typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _SPU2configure)(); -typedef s32 (CALLBACK* _SPU2test)(); -typedef void (CALLBACK* _SPU2about)(); - - -// CDVD -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _CDVDinit)(); -typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); -typedef void (CALLBACK* _CDVDclose)(); -typedef void (CALLBACK* _CDVDshutdown)(); -typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); -typedef u8* (CALLBACK* _CDVDgetBuffer)(); -typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); -typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); -typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); -typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); -typedef s32 (CALLBACK* _CDVDgetDiskType)(); -typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); -typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); -typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); - -typedef void (CALLBACK* _CDVDconfigure)(); -typedef s32 (CALLBACK* _CDVDtest)(); -typedef void (CALLBACK* _CDVDabout)(); -typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); - -// DEV9 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _DEV9init)(); -typedef s32 (CALLBACK* _DEV9open)(void *pDsp); -typedef void (CALLBACK* _DEV9close)(); -typedef void (CALLBACK* _DEV9shutdown)(); -typedef u8 (CALLBACK* _DEV9read8)(u32 mem); -typedef u16 (CALLBACK* _DEV9read16)(u32 mem); -typedef u32 (CALLBACK* _DEV9read32)(u32 mem); -typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); -typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); -typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); -typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); -typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); - -typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _DEV9configure)(); -typedef s32 (CALLBACK* _DEV9test)(); -typedef void (CALLBACK* _DEV9about)(); - -// USB -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _USBinit)(); -typedef s32 (CALLBACK* _USBopen)(void *pDsp); -typedef void (CALLBACK* _USBclose)(); -typedef void (CALLBACK* _USBshutdown)(); -typedef u8 (CALLBACK* _USBread8)(u32 mem); -typedef u16 (CALLBACK* _USBread16)(u32 mem); -typedef u32 (CALLBACK* _USBread32)(u32 mem); -typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); -typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); -typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _USBasync)(u32 cycles); - - -typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); -typedef USBhandler (CALLBACK* _USBirqHandler)(void); -typedef void (CALLBACK* _USBsetRAM)(void *mem); - -typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _USBconfigure)(); -typedef s32 (CALLBACK* _USBtest)(); -typedef void (CALLBACK* _USBabout)(); - -//FW -typedef s32 (CALLBACK* _FWinit)(); -typedef s32 (CALLBACK* _FWopen)(void *pDsp); -typedef void (CALLBACK* _FWclose)(); -typedef void (CALLBACK* _FWshutdown)(); -typedef u32 (CALLBACK* _FWread32)(u32 mem); -typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); - -typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _FWconfigure)(); -typedef s32 (CALLBACK* _FWtest)(); -typedef void (CALLBACK* _FWabout)(); - -#endif - -#ifdef PLUGINfuncs - -// GS -extern _GSinit GSinit; -extern _GSopen GSopen; -extern _GSclose GSclose; -extern _GSshutdown GSshutdown; -extern _GSvsync GSvsync; -extern _GSgifTransfer1 GSgifTransfer1; -extern _GSgifTransfer2 GSgifTransfer2; -extern _GSgifTransfer3 GSgifTransfer3; -extern _GSgetLastTag GSgetLastTag; -extern _GSgifSoftReset GSgifSoftReset; -extern _GSreadFIFO GSreadFIFO; -extern _GSreadFIFO2 GSreadFIFO2; - -extern _GSkeyEvent GSkeyEvent; -extern _GSchangeSaveState GSchangeSaveState; -extern _GSmakeSnapshot GSmakeSnapshot; -extern _GSmakeSnapshot2 GSmakeSnapshot2; -extern _GSirqCallback GSirqCallback; -extern _GSprintf GSprintf; -extern _GSsetBaseMem GSsetBaseMem; -extern _GSsetGameCRC GSsetGameCRC; -extern _GSsetFrameSkip GSsetFrameSkip; -extern _GSsetupRecording GSsetupRecording; -extern _GSreset GSreset; -extern _GSwriteCSR GSwriteCSR; -extern _GSgetDriverInfo GSgetDriverInfo; -#ifdef _WINDOWS_ -extern _GSsetWindowInfo GSsetWindowInfo; -#endif -extern _GSfreeze GSfreeze; -extern _GSconfigure GSconfigure; -extern _GStest GStest; -extern _GSabout GSabout; - -// PAD1 -extern _PADinit PAD1init; -extern _PADopen PAD1open; -extern _PADclose PAD1close; -extern _PADshutdown PAD1shutdown; -extern _PADkeyEvent PAD1keyEvent; -extern _PADstartPoll PAD1startPoll; -extern _PADpoll PAD1poll; -extern _PADquery PAD1query; -extern _PADupdate PAD1update; - -extern _PADgsDriverInfo PAD1gsDriverInfo; -extern _PADconfigure PAD1configure; -extern _PADtest PAD1test; -extern _PADabout PAD1about; - -// PAD2 -extern _PADinit PAD2init; -extern _PADopen PAD2open; -extern _PADclose PAD2close; -extern _PADshutdown PAD2shutdown; -extern _PADkeyEvent PAD2keyEvent; -extern _PADstartPoll PAD2startPoll; -extern _PADpoll PAD2poll; -extern _PADquery PAD2query; -extern _PADupdate PAD2update; - -extern _PADgsDriverInfo PAD2gsDriverInfo; -extern _PADconfigure PAD2configure; -extern _PADtest PAD2test; -extern _PADabout PAD2about; - -// SIO[2] -extern _SIOinit SIOinit[2][9]; -extern _SIOopen SIOopen[2][9]; -extern _SIOclose SIOclose[2][9]; -extern _SIOshutdown SIOshutdown[2][9]; -extern _SIOstartPoll SIOstartPoll[2][9]; -extern _SIOpoll SIOpoll[2][9]; -extern _SIOquery SIOquery[2][9]; - -extern _SIOconfigure SIOconfigure[2][9]; -extern _SIOtest SIOtest[2][9]; -extern _SIOabout SIOabout[2][9]; - -// SPU2 -extern _SPU2init SPU2init; -extern _SPU2open SPU2open; -extern _SPU2close SPU2close; -extern _SPU2shutdown SPU2shutdown; -extern _SPU2write SPU2write; -extern _SPU2read SPU2read; -extern _SPU2readDMA4Mem SPU2readDMA4Mem; -extern _SPU2writeDMA4Mem SPU2writeDMA4Mem; -extern _SPU2interruptDMA4 SPU2interruptDMA4; -extern _SPU2readDMA7Mem SPU2readDMA7Mem; -extern _SPU2writeDMA7Mem SPU2writeDMA7Mem; -extern _SPU2setDMABaseAddr SPU2setDMABaseAddr; -extern _SPU2interruptDMA7 SPU2interruptDMA7; -extern _SPU2ReadMemAddr SPU2ReadMemAddr; -extern _SPU2setupRecording SPU2setupRecording; -extern _SPU2WriteMemAddr SPU2WriteMemAddr; -extern _SPU2irqCallback SPU2irqCallback; - -extern _SPU2setClockPtr SPU2setClockPtr; -extern _SPU2setTimeStretcher SPU2setTimeStretcher; - -extern _SPU2async SPU2async; -extern _SPU2freeze SPU2freeze; -extern _SPU2configure SPU2configure; -extern _SPU2test SPU2test; -extern _SPU2about SPU2about; - -// CDVD -extern _CDVDinit CDVDinit; -extern _CDVDopen CDVDopen; -extern _CDVDclose CDVDclose; -extern _CDVDshutdown CDVDshutdown; -extern _CDVDreadTrack CDVDreadTrack; -extern _CDVDgetBuffer CDVDgetBuffer; -extern _CDVDreadSubQ CDVDreadSubQ; -extern _CDVDgetTN CDVDgetTN; -extern _CDVDgetTD CDVDgetTD; -extern _CDVDgetTOC CDVDgetTOC; -extern _CDVDgetDiskType CDVDgetDiskType; -extern _CDVDgetTrayStatus CDVDgetTrayStatus; -extern _CDVDctrlTrayOpen CDVDctrlTrayOpen; -extern _CDVDctrlTrayClose CDVDctrlTrayClose; - -extern _CDVDconfigure CDVDconfigure; -extern _CDVDtest CDVDtest; -extern _CDVDabout CDVDabout; -extern _CDVDnewDiskCB CDVDnewDiskCB; - -// DEV9 -extern _DEV9init DEV9init; -extern _DEV9open DEV9open; -extern _DEV9close DEV9close; -extern _DEV9shutdown DEV9shutdown; -extern _DEV9read8 DEV9read8; -extern _DEV9read16 DEV9read16; -extern _DEV9read32 DEV9read32; -extern _DEV9write8 DEV9write8; -extern _DEV9write16 DEV9write16; -extern _DEV9write32 DEV9write32; -extern _DEV9readDMA8Mem DEV9readDMA8Mem; -extern _DEV9writeDMA8Mem DEV9writeDMA8Mem; -extern _DEV9irqCallback DEV9irqCallback; -extern _DEV9irqHandler DEV9irqHandler; - -extern _DEV9configure DEV9configure; -extern _DEV9freeze DEV9freeze; -extern _DEV9test DEV9test; -extern _DEV9about DEV9about; - -// USB -extern _USBinit USBinit; -extern _USBopen USBopen; -extern _USBclose USBclose; -extern _USBshutdown USBshutdown; -extern _USBread8 USBread8; -extern _USBread16 USBread16; -extern _USBread32 USBread32; -extern _USBwrite8 USBwrite8; -extern _USBwrite16 USBwrite16; -extern _USBwrite32 USBwrite32; -extern _USBasync USBasync; - -extern _USBirqCallback USBirqCallback; -extern _USBirqHandler USBirqHandler; -extern _USBsetRAM USBsetRAM; - -extern _USBconfigure USBconfigure; -extern _USBfreeze USBfreeze; -extern _USBtest USBtest; -extern _USBabout USBabout; - -// FW -extern _FWinit FWinit; -extern _FWopen FWopen; -extern _FWclose FWclose; -extern _FWshutdown FWshutdown; -extern _FWread32 FWread32; -extern _FWwrite32 FWwrite32; -extern _FWirqCallback FWirqCallback; - -extern _FWconfigure FWconfigure; -extern _FWfreeze FWfreeze; -extern _FWtest FWtest; -extern _FWabout FWabout; -#endif - -#ifdef __cplusplus -} // End extern "C" -#endif - -#endif /* __PS2EDEFS_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct _keyEvent { + u32 key; + u32 evt; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct _cdvdSubQ { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct _cdvdTD { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct _cdvdTN { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct _GSdriverInfo { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WINDOWS_ +typedef struct _winInfo { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2setClockPtr(u32* ptr); +void CALLBACK SPU2setTimeStretcher(short int enable); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +void CALLBACK USBasync(u32 cycles); + +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WINDOWS_ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(const char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); + +typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); +typedef void (CALLBACK* _SPU2setTimeStretcher)(short int enable); + +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBasync)(u32 cycles); + + +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +extern _GSinit GSinit; +extern _GSopen GSopen; +extern _GSclose GSclose; +extern _GSshutdown GSshutdown; +extern _GSvsync GSvsync; +extern _GSgifTransfer1 GSgifTransfer1; +extern _GSgifTransfer2 GSgifTransfer2; +extern _GSgifTransfer3 GSgifTransfer3; +extern _GSgetLastTag GSgetLastTag; +extern _GSgifSoftReset GSgifSoftReset; +extern _GSreadFIFO GSreadFIFO; +extern _GSreadFIFO2 GSreadFIFO2; + +extern _GSkeyEvent GSkeyEvent; +extern _GSchangeSaveState GSchangeSaveState; +extern _GSmakeSnapshot GSmakeSnapshot; +extern _GSmakeSnapshot2 GSmakeSnapshot2; +extern _GSirqCallback GSirqCallback; +extern _GSprintf GSprintf; +extern _GSsetBaseMem GSsetBaseMem; +extern _GSsetGameCRC GSsetGameCRC; +extern _GSsetFrameSkip GSsetFrameSkip; +extern _GSsetupRecording GSsetupRecording; +extern _GSreset GSreset; +extern _GSwriteCSR GSwriteCSR; +extern _GSgetDriverInfo GSgetDriverInfo; +#ifdef _WINDOWS_ +extern _GSsetWindowInfo GSsetWindowInfo; +#endif +extern _GSfreeze GSfreeze; +extern _GSconfigure GSconfigure; +extern _GStest GStest; +extern _GSabout GSabout; + +// PAD1 +extern _PADinit PAD1init; +extern _PADopen PAD1open; +extern _PADclose PAD1close; +extern _PADshutdown PAD1shutdown; +extern _PADkeyEvent PAD1keyEvent; +extern _PADstartPoll PAD1startPoll; +extern _PADpoll PAD1poll; +extern _PADquery PAD1query; +extern _PADupdate PAD1update; + +extern _PADgsDriverInfo PAD1gsDriverInfo; +extern _PADconfigure PAD1configure; +extern _PADtest PAD1test; +extern _PADabout PAD1about; + +// PAD2 +extern _PADinit PAD2init; +extern _PADopen PAD2open; +extern _PADclose PAD2close; +extern _PADshutdown PAD2shutdown; +extern _PADkeyEvent PAD2keyEvent; +extern _PADstartPoll PAD2startPoll; +extern _PADpoll PAD2poll; +extern _PADquery PAD2query; +extern _PADupdate PAD2update; + +extern _PADgsDriverInfo PAD2gsDriverInfo; +extern _PADconfigure PAD2configure; +extern _PADtest PAD2test; +extern _PADabout PAD2about; + +// SIO[2] +extern _SIOinit SIOinit[2][9]; +extern _SIOopen SIOopen[2][9]; +extern _SIOclose SIOclose[2][9]; +extern _SIOshutdown SIOshutdown[2][9]; +extern _SIOstartPoll SIOstartPoll[2][9]; +extern _SIOpoll SIOpoll[2][9]; +extern _SIOquery SIOquery[2][9]; + +extern _SIOconfigure SIOconfigure[2][9]; +extern _SIOtest SIOtest[2][9]; +extern _SIOabout SIOabout[2][9]; + +// SPU2 +extern _SPU2init SPU2init; +extern _SPU2open SPU2open; +extern _SPU2close SPU2close; +extern _SPU2shutdown SPU2shutdown; +extern _SPU2write SPU2write; +extern _SPU2read SPU2read; +extern _SPU2readDMA4Mem SPU2readDMA4Mem; +extern _SPU2writeDMA4Mem SPU2writeDMA4Mem; +extern _SPU2interruptDMA4 SPU2interruptDMA4; +extern _SPU2readDMA7Mem SPU2readDMA7Mem; +extern _SPU2writeDMA7Mem SPU2writeDMA7Mem; +extern _SPU2setDMABaseAddr SPU2setDMABaseAddr; +extern _SPU2interruptDMA7 SPU2interruptDMA7; +extern _SPU2ReadMemAddr SPU2ReadMemAddr; +extern _SPU2setupRecording SPU2setupRecording; +extern _SPU2WriteMemAddr SPU2WriteMemAddr; +extern _SPU2irqCallback SPU2irqCallback; + +extern _SPU2setClockPtr SPU2setClockPtr; +extern _SPU2setTimeStretcher SPU2setTimeStretcher; + +extern _SPU2async SPU2async; +extern _SPU2freeze SPU2freeze; +extern _SPU2configure SPU2configure; +extern _SPU2test SPU2test; +extern _SPU2about SPU2about; + +// CDVD +extern _CDVDinit CDVDinit; +extern _CDVDopen CDVDopen; +extern _CDVDclose CDVDclose; +extern _CDVDshutdown CDVDshutdown; +extern _CDVDreadTrack CDVDreadTrack; +extern _CDVDgetBuffer CDVDgetBuffer; +extern _CDVDreadSubQ CDVDreadSubQ; +extern _CDVDgetTN CDVDgetTN; +extern _CDVDgetTD CDVDgetTD; +extern _CDVDgetTOC CDVDgetTOC; +extern _CDVDgetDiskType CDVDgetDiskType; +extern _CDVDgetTrayStatus CDVDgetTrayStatus; +extern _CDVDctrlTrayOpen CDVDctrlTrayOpen; +extern _CDVDctrlTrayClose CDVDctrlTrayClose; + +extern _CDVDconfigure CDVDconfigure; +extern _CDVDtest CDVDtest; +extern _CDVDabout CDVDabout; +extern _CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +extern _DEV9init DEV9init; +extern _DEV9open DEV9open; +extern _DEV9close DEV9close; +extern _DEV9shutdown DEV9shutdown; +extern _DEV9read8 DEV9read8; +extern _DEV9read16 DEV9read16; +extern _DEV9read32 DEV9read32; +extern _DEV9write8 DEV9write8; +extern _DEV9write16 DEV9write16; +extern _DEV9write32 DEV9write32; +extern _DEV9readDMA8Mem DEV9readDMA8Mem; +extern _DEV9writeDMA8Mem DEV9writeDMA8Mem; +extern _DEV9irqCallback DEV9irqCallback; +extern _DEV9irqHandler DEV9irqHandler; + +extern _DEV9configure DEV9configure; +extern _DEV9freeze DEV9freeze; +extern _DEV9test DEV9test; +extern _DEV9about DEV9about; + +// USB +extern _USBinit USBinit; +extern _USBopen USBopen; +extern _USBclose USBclose; +extern _USBshutdown USBshutdown; +extern _USBread8 USBread8; +extern _USBread16 USBread16; +extern _USBread32 USBread32; +extern _USBwrite8 USBwrite8; +extern _USBwrite16 USBwrite16; +extern _USBwrite32 USBwrite32; +extern _USBasync USBasync; + +extern _USBirqCallback USBirqCallback; +extern _USBirqHandler USBirqHandler; +extern _USBsetRAM USBsetRAM; + +extern _USBconfigure USBconfigure; +extern _USBfreeze USBfreeze; +extern _USBtest USBtest; +extern _USBabout USBabout; + +// FW +extern _FWinit FWinit; +extern _FWopen FWopen; +extern _FWclose FWclose; +extern _FWshutdown FWshutdown; +extern _FWread32 FWread32; +extern _FWwrite32 FWwrite32; +extern _FWirqCallback FWirqCallback; + +extern _FWconfigure FWconfigure; +extern _FWfreeze FWfreeze; +extern _FWtest FWtest; +extern _FWabout FWabout; +#endif + +#ifdef __cplusplus +} // End extern "C" +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/spu2ghz/src/common/PS2Etypes.h b/plugins/spu2ghz/src/common/PS2Etypes.h index 59be1c3de4..4c62b47f0f 100644 --- a/plugins/spu2ghz/src/common/PS2Etypes.h +++ b/plugins/spu2ghz/src/common/PS2Etypes.h @@ -1,219 +1,219 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef __PS2ETYPES_H__ -#define __PS2ETYPES_H__ - -#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case -#define __LINUX__ -#endif - -#ifdef __CYGWIN__ -#define __LINUX__ -#endif - -#ifndef ARRAYSIZE -#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) -#endif - -#ifdef __LINUX__ -#define CALLBACK -#else -#define CALLBACK __stdcall -#endif - - -// jASSUME - give hints to the optimizer -// This is primarily useful for the default case switch optimizer, which enables VC to -// generate more compact switches. - -#ifdef NDEBUG -# define jBREAKPOINT() ((void) 0) -# ifdef _MSC_VER -# define jASSUME(exp) (__assume(exp)) -# else -# define jASSUME(exp) ((void) sizeof(exp)) -# endif -#else -# if defined(_MSC_VER) -# define jBREAKPOINT() do { __asm int 3 } while(0) -# else -# define jBREAKPOINT() ((void) *(volatile char *) 0) -# endif -# define jASSUME(exp) if(exp) ; else jBREAKPOINT() -#endif - -// disable the default case in a switch -#define jNO_DEFAULT \ -{ \ - break; \ - \ -default: \ - jASSUME(0); \ - break; \ -} - - -// Basic types -#if defined(_MSC_VER) - -typedef __int8 s8; -typedef __int16 s16; -typedef __int32 s32; -typedef __int64 s64; - -typedef unsigned __int8 u8; -typedef unsigned __int16 u16; -typedef unsigned __int32 u32; -typedef unsigned __int64 u64; - -typedef unsigned int uint; - -#define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x -#define PCSX2_ALIGNED16(x) __declspec(align(16)) x -#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x - -#define __naked __declspec(naked) - -#else // _MSC_VER - -#ifdef __LINUX__ - -#ifdef HAVE_STDINT_H -#include "stdint.h" - -typedef int8_t s8; -typedef int16_t s16; -typedef int32_t s32; -typedef int64_t s64; - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -typedef uintptr_t uptr; -typedef intptr_t sptr; - -#else // HAVE_STDINT_H - -typedef char s8; -typedef short s16; -typedef int s32; -typedef long long s64; - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long long u64; - -#endif // HAVE_STDINT_H - -typedef unsigned int uint; - -#define LONG long -typedef union _LARGE_INTEGER -{ - long long QuadPart; -} LARGE_INTEGER; - -#define __fastcall __attribute__((fastcall)) -#define __unused __attribute__((unused)) -#define _inline __inline__ __attribute__((unused)) -#define __forceinline __attribute__((always_inline,unused)) -#define __naked // GCC lacks the naked specifier - -#endif // __LINUX__ - -#define PCSX2_ALIGNED(alig,x) x __attribute((aligned(alig))) -#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) - -#define PCSX2_ALIGNED16_DECL(x) x - -#endif // _MSC_VER - -#if !defined(__LINUX__) || !defined(HAVE_STDINT_H) -#if defined(__x86_64__) -typedef u64 uptr; -typedef s64 sptr; -#else -typedef u32 uptr; -typedef s32 sptr; -#endif -#endif - -// A rough-and-ready cross platform 128-bit datatype, Non-SSE style. -#ifdef __cplusplus -struct u128 -{ - u64 lo; - u64 hi; - - // Implicit conversion from u64 - u128( u64 src ) : - lo( src ) - , hi( 0 ) {} - - // Implicit conversion from u32 - u128( u32 src ) : - lo( src ) - , hi( 0 ) {} -}; - -struct s128 -{ - s64 lo; - s64 hi; - - // Implicit conversion from u64 - s128( s64 src ) : - lo( src ) - , hi( 0 ) {} - - // Implicit conversion from u32 - s128( s32 src ) : - lo( src ) - , hi( 0 ) {} -}; - -#else - -typedef union _u128_t -{ - u64 lo; - u64 hi; -} u128; - -typedef union _s128_t -{ - s64 lo; - s64 hi; -} s128; - -#endif - -typedef struct { - int size; - s8 *data; -} freezeData; - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#endif /* __PS2ETYPES_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +#ifdef __CYGWIN__ +#define __LINUX__ +#endif + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#ifdef __LINUX__ +#define CALLBACK +#else +#define CALLBACK __stdcall +#endif + + +// jASSUME - give hints to the optimizer +// This is primarily useful for the default case switch optimizer, which enables VC to +// generate more compact switches. + +#ifdef NDEBUG +# define jBREAKPOINT() ((void) 0) +# ifdef _MSC_VER +# define jASSUME(exp) (__assume(exp)) +# else +# define jASSUME(exp) ((void) sizeof(exp)) +# endif +#else +# if defined(_MSC_VER) +# define jBREAKPOINT() do { __asm int 3 } while(0) +# else +# define jBREAKPOINT() ((void) *(volatile char *) 0) +# endif +# define jASSUME(exp) if(exp) ; else jBREAKPOINT() +#endif + +// disable the default case in a switch +#define jNO_DEFAULT \ +{ \ + break; \ + \ +default: \ + jASSUME(0); \ + break; \ +} + + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +typedef unsigned int uint; + +#define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x + +#define __naked __declspec(naked) + +#else // _MSC_VER + +#ifdef __LINUX__ + +#ifdef HAVE_STDINT_H +#include "stdint.h" + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef uintptr_t uptr; +typedef intptr_t sptr; + +#else // HAVE_STDINT_H + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#endif // HAVE_STDINT_H + +typedef unsigned int uint; + +#define LONG long +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; + +#define __fastcall __attribute__((fastcall)) +#define __unused __attribute__((unused)) +#define _inline __inline__ __attribute__((unused)) +#define __forceinline __attribute__((always_inline,unused)) +#define __naked // GCC lacks the naked specifier + +#endif // __LINUX__ + +#define PCSX2_ALIGNED(alig,x) x __attribute((aligned(alig))) +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) + +#define PCSX2_ALIGNED16_DECL(x) x + +#endif // _MSC_VER + +#if !defined(__LINUX__) || !defined(HAVE_STDINT_H) +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif +#endif + +// A rough-and-ready cross platform 128-bit datatype, Non-SSE style. +#ifdef __cplusplus +struct u128 +{ + u64 lo; + u64 hi; + + // Implicit conversion from u64 + u128( u64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + u128( u32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +struct s128 +{ + s64 lo; + s64 hi; + + // Implicit conversion from u64 + s128( s64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + s128( s32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +#else + +typedef union _u128_t +{ + u64 lo; + u64 hi; +} u128; + +typedef union _s128_t +{ + s64 lo; + s64 hi; +} s128; + +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/spu2ghz/src/debug.cpp b/plugins/spu2ghz/src/debug.cpp index 3021619dc0..8bd687dfa8 100644 --- a/plugins/spu2ghz/src/debug.cpp +++ b/plugins/spu2ghz/src/debug.cpp @@ -1,258 +1,258 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// - -#include "spu2.h" - -int crazy_debug=0; - -char s[4096]; - -FILE *spu2Log; - -void FileLog(const char *fmt, ...) { -#ifdef SPU2_LOG - int n; - va_list list; - - if(!AccessLog()) return; - if(!spu2Log) return; - - va_start(list, fmt); - n=vsprintf(s,fmt, list); - va_end(list); - - fputs(s,spu2Log); - fflush(spu2Log); - -#if 0 - if(crazy_debug) - { - fputs(s,stderr); - fflush(stderr); - } -#endif -#endif -} - -void ConLog(const char *fmt, ...) { -#ifdef SPU2_LOG - int n; - va_list list; - - if(!MsgToConsole()) return; - - va_start(list, fmt); - n=vsprintf(s,fmt, list); - va_end(list); - - fputs(s,stderr); - fflush(stderr); - - if(spu2Log) - { - fputs(s,spu2Log); - fflush(spu2Log); - } -#endif -} - -void DoFullDump() { -#ifdef SPU2_LOG - FILE *dump; - u8 c=0, v=0; - - if(MemDump()) { - dump=fopen(MemDumpFileName,"wb"); - if (dump) { - fwrite(_spu2mem,0x200000,1,dump); - fclose(dump); - } - } - if(RegDump()) { - dump=fopen(RegDumpFileName,"wb"); - if (dump) { - fwrite(spu2regs,0x2000,1,dump); - fclose(dump); - } - } - - if(!CoresDump()) return; - dump=fopen(CoresDumpFileName,"wt"); - if (dump) { - for(c=0;c<2;c++) { - fprintf(dump,"#### CORE %d DUMP.\n",c); - fprintf(dump,"Master Volume for Left Channel: %x\n" - " - Value: %x\n" - " - Mode: %x\n" - " - Increment: %x\n", - Cores[c].MasterL.Reg_VOL, - Cores[c].MasterL.Value, - Cores[c].MasterL.Mode, - Cores[c].MasterL.Increment); - fprintf(dump,"Master Volume for Right Channel: %x\n" - " - Value: %x\n" - " - Mode: %x\n" - " - Increment: %x\n", - Cores[c].MasterR.Reg_VOL, - Cores[c].MasterR.Value, - Cores[c].MasterR.Mode, - Cores[c].MasterR.Increment); - fprintf(dump,"Volume for External Data Input (Left Channel): %x\n",Cores[c].ExtL); - fprintf(dump,"Volume for External Data Input (Right Channel): %x\n",Cores[c].ExtR); - fprintf(dump,"Volume for Sound Data Input (Left Channel): %x\n",Cores[c].InpL); - fprintf(dump,"Volume for Sound Data Input (Right Channel): %x\n",Cores[c].InpR); - fprintf(dump,"Volume for Output from Effects (Left Channel): %x\n",Cores[c].FxL); - fprintf(dump,"Volume for Output from Effects (Right Channel): %x\n",Cores[c].FxR); - fprintf(dump,"Interrupt Address: %x\n",Cores[c].IRQA); - fprintf(dump,"DMA Transfer Start Address: %x\n",Cores[c].TSA); - fprintf(dump,"External Input to Direct Output (Left): %s\n",Cores[c].ExtDryL?"Yes":"No"); - fprintf(dump,"External Input to Direct Output (Right): %s\n",Cores[c].ExtDryR?"Yes":"No"); - fprintf(dump,"External Input to Effects (Left): %s\n",Cores[c].ExtWetL?"Yes":"No"); - fprintf(dump,"External Input to Effects (Right): %s\n",Cores[c].ExtWetR?"Yes":"No"); - fprintf(dump,"Sound Data Input to Direct Output (Left): %s\n",Cores[c].SndDryL?"Yes":"No"); - fprintf(dump,"Sound Data Input to Direct Output (Right): %s\n",Cores[c].SndDryR?"Yes":"No"); - fprintf(dump,"Sound Data Input to Effects (Left): %s\n",Cores[c].SndWetL?"Yes":"No"); - fprintf(dump,"Sound Data Input to Effects (Right): %s\n",Cores[c].SndWetR?"Yes":"No"); - fprintf(dump,"Voice Data Input to Direct Output (Left): %s\n",Cores[c].InpDryL?"Yes":"No"); - fprintf(dump,"Voice Data Input to Direct Output (Right): %s\n",Cores[c].InpDryR?"Yes":"No"); - fprintf(dump,"Voice Data Input to Effects (Left): %s\n",Cores[c].InpWetL?"Yes":"No"); - fprintf(dump,"Voice Data Input to Effects (Right): %s\n",Cores[c].InpWetR?"Yes":"No"); - fprintf(dump,"IRQ Enabled: %s\n",Cores[c].IRQEnable?"Yes":"No"); - fprintf(dump,"Effects Enabled: %s\n",Cores[c].FxEnable?"Yes":"No"); - fprintf(dump,"Mute Enabled: %s\n",Cores[c].Mute?"Yes":"No"); - fprintf(dump,"Noise Clock: %d\n",Cores[c].NoiseClk); - fprintf(dump,"DMA Bits: %d\n",Cores[c].DMABits); - fprintf(dump,"Effects Start: %x\n",Cores[c].EffectsStartA); - fprintf(dump,"Effects End: %x\n",Cores[c].EffectsEndA); - fprintf(dump,"Registers:\n"); - fprintf(dump," - PMON: %x\n",Cores[c].Regs.PMON); - fprintf(dump," - NON: %x\n",Cores[c].Regs.NON); - fprintf(dump," - VMIXL: %x\n",Cores[c].Regs.VMIXL); - fprintf(dump," - VMIXR: %x\n",Cores[c].Regs.VMIXR); - fprintf(dump," - VMIXEL: %x\n",Cores[c].Regs.VMIXEL); - fprintf(dump," - VMIXER: %x\n",Cores[c].Regs.VMIXER); - fprintf(dump," - MMIX: %x\n",Cores[c].Regs.VMIXEL); - fprintf(dump," - ENDX: %x\n",Cores[c].Regs.VMIXER); - fprintf(dump," - STATX: %x\n",Cores[c].Regs.VMIXEL); - fprintf(dump," - ATTR: %x\n",Cores[c].Regs.VMIXER); - for(v=0;v<24;v++) { - fprintf(dump,"Voice %d:\n",v); - fprintf(dump," - Volume for Left Channel: %x\n" - " - Value: %x\n" - " - Mode: %x\n" - " - Increment: %x\n", - Cores[c].Voices[v].VolumeL.Reg_VOL, - Cores[c].Voices[v].VolumeL.Value, - Cores[c].Voices[v].VolumeL.Mode, - Cores[c].Voices[v].VolumeL.Increment); - fprintf(dump," - Volume for Right Channel: %x\n" - " - Value: %x\n" - " - Mode: %x\n" - " - Increment: %x\n", - Cores[c].Voices[v].VolumeR.Reg_VOL, - Cores[c].Voices[v].VolumeR.Value, - Cores[c].Voices[v].VolumeR.Mode, - Cores[c].Voices[v].VolumeR.Increment); - fprintf(dump," - ADSR Envelope: %x & %x\n" - " - Ar: %x\n" - " - Am: %x\n" - " - Dr: %x\n" - " - Sl: %x\n" - " - Sr: %x\n" - " - Sm: %x\n" - " - Rr: %x\n" - " - Rm: %x\n" - " - Phase: %x\n" - " - Value: %x\n", - Cores[c].Voices[v].ADSR.Reg_ADSR1, - Cores[c].Voices[v].ADSR.Reg_ADSR2, - Cores[c].Voices[v].ADSR.Ar, - Cores[c].Voices[v].ADSR.Am, - Cores[c].Voices[v].ADSR.Dr, - Cores[c].Voices[v].ADSR.Sl, - Cores[c].Voices[v].ADSR.Sr, - Cores[c].Voices[v].ADSR.Sm, - Cores[c].Voices[v].ADSR.Rr, - Cores[c].Voices[v].ADSR.Rm, - Cores[c].Voices[v].ADSR.Phase, - Cores[c].Voices[v].ADSR.Value); - fprintf(dump," - Pitch: %x\n",Cores[c].Voices[v].Pitch); - fprintf(dump," - Modulated: %s\n",Cores[c].Voices[v].Modulated?"Yes":"No"); - fprintf(dump," - Source: %s\n",Cores[c].Voices[v].Noise?"Noise":"Wave"); - fprintf(dump," - Direct Output for Left Channel: %s\n",Cores[c].Voices[v].DryL?"Yes":"No"); - fprintf(dump," - Direct Output for Right Channel: %s\n",Cores[c].Voices[v].DryR?"Yes":"No"); - fprintf(dump," - Effects Output for Left Channel: %s\n",Cores[c].Voices[v].WetL?"Yes":"No"); - fprintf(dump," - Effects Output for Right Channel: %s\n",Cores[c].Voices[v].WetR?"Yes":"No"); - fprintf(dump," - Loop Start Adress: %x\n",Cores[c].Voices[v].LoopStartA); - fprintf(dump," - Sound Start Adress: %x\n",Cores[c].Voices[v].StartA); - fprintf(dump," - Next Data Adress: %x\n",Cores[c].Voices[v].NextA); - fprintf(dump," - Play Start Cycle: %d\n",Cores[c].Voices[v].PlayCycle); - fprintf(dump," - Play Status: %s\n",(Cores[c].Voices[v].ADSR.Phase>0)?"Playing":"Not Playing"); - fprintf(dump," - Block Sample: %d\n",Cores[c].Voices[v].SCurrent); - } - fprintf(dump,"#### END OF DUMP.\n\n"); - } - } - fclose(dump); - dump=fopen("logs/effects.txt","wt"); - if (dump) { - for(c=0;c<2;c++) { - fprintf(dump,"#### CORE %d EFFECTS PROCESSOR DUMP.\n",c); - - fprintf(dump," - IN_COEF_L: %x\n",Cores[c].Revb.IN_COEF_R); - fprintf(dump," - IN_COEF_R: %x\n",Cores[c].Revb.IN_COEF_L); - - fprintf(dump," - FB_ALPHA: %x\n",Cores[c].Revb.FB_ALPHA); - fprintf(dump," - FB_X: %x\n",Cores[c].Revb.FB_X); - fprintf(dump," - FB_SRC_A: %x\n",Cores[c].Revb.FB_SRC_A); - fprintf(dump," - FB_SRC_B: %x\n",Cores[c].Revb.FB_SRC_B); - - fprintf(dump," - IIR_ALPHA: %x\n",Cores[c].Revb.IIR_ALPHA); - fprintf(dump," - IIR_COEF: %x\n",Cores[c].Revb.IIR_COEF); - fprintf(dump," - IIR_SRC_A0: %x\n",Cores[c].Revb.IIR_SRC_A0); - fprintf(dump," - IIR_SRC_A1: %x\n",Cores[c].Revb.IIR_SRC_A1); - fprintf(dump," - IIR_SRC_B1: %x\n",Cores[c].Revb.IIR_SRC_B0); - fprintf(dump," - IIR_SRC_B0: %x\n",Cores[c].Revb.IIR_SRC_B1); - fprintf(dump," - IIR_DEST_A0: %x\n",Cores[c].Revb.IIR_DEST_A0); - fprintf(dump," - IIR_DEST_A1: %x\n",Cores[c].Revb.IIR_DEST_A1); - fprintf(dump," - IIR_DEST_B0: %x\n",Cores[c].Revb.IIR_DEST_B0); - fprintf(dump," - IIR_DEST_B1: %x\n",Cores[c].Revb.IIR_DEST_B1); - - fprintf(dump," - ACC_COEF_A: %x\n",Cores[c].Revb.ACC_COEF_A); - fprintf(dump," - ACC_COEF_B: %x\n",Cores[c].Revb.ACC_COEF_B); - fprintf(dump," - ACC_COEF_C: %x\n",Cores[c].Revb.ACC_COEF_C); - fprintf(dump," - ACC_COEF_D: %x\n",Cores[c].Revb.ACC_COEF_D); - fprintf(dump," - ACC_SRC_A0: %x\n",Cores[c].Revb.ACC_SRC_A0); - fprintf(dump," - ACC_SRC_A1: %x\n",Cores[c].Revb.ACC_SRC_A1); - fprintf(dump," - ACC_SRC_B0: %x\n",Cores[c].Revb.ACC_SRC_B0); - fprintf(dump," - ACC_SRC_B1: %x\n",Cores[c].Revb.ACC_SRC_B1); - fprintf(dump," - ACC_SRC_C0: %x\n",Cores[c].Revb.ACC_SRC_C0); - fprintf(dump," - ACC_SRC_C1: %x\n",Cores[c].Revb.ACC_SRC_C1); - fprintf(dump," - ACC_SRC_D0: %x\n",Cores[c].Revb.ACC_SRC_D0); - fprintf(dump," - ACC_SRC_D1: %x\n",Cores[c].Revb.ACC_SRC_D1); - - fprintf(dump," - MIX_DEST_A0: %x\n",Cores[c].Revb.MIX_DEST_A0); - fprintf(dump," - MIX_DEST_A1: %x\n",Cores[c].Revb.MIX_DEST_A1); - fprintf(dump," - MIX_DEST_B0: %x\n",Cores[c].Revb.MIX_DEST_B0); - fprintf(dump," - MIX_DEST_B1: %x\n",Cores[c].Revb.MIX_DEST_B1); - fprintf(dump,"#### END OF DUMP.\n\n"); - } - fclose(dump); - } -#endif -} +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#include "spu2.h" + +int crazy_debug=0; + +char s[4096]; + +FILE *spu2Log; + +void FileLog(const char *fmt, ...) { +#ifdef SPU2_LOG + int n; + va_list list; + + if(!AccessLog()) return; + if(!spu2Log) return; + + va_start(list, fmt); + n=vsprintf(s,fmt, list); + va_end(list); + + fputs(s,spu2Log); + fflush(spu2Log); + +#if 0 + if(crazy_debug) + { + fputs(s,stderr); + fflush(stderr); + } +#endif +#endif +} + +void ConLog(const char *fmt, ...) { +#ifdef SPU2_LOG + int n; + va_list list; + + if(!MsgToConsole()) return; + + va_start(list, fmt); + n=vsprintf(s,fmt, list); + va_end(list); + + fputs(s,stderr); + fflush(stderr); + + if(spu2Log) + { + fputs(s,spu2Log); + fflush(spu2Log); + } +#endif +} + +void DoFullDump() { +#ifdef SPU2_LOG + FILE *dump; + u8 c=0, v=0; + + if(MemDump()) { + dump=fopen(MemDumpFileName,"wb"); + if (dump) { + fwrite(_spu2mem,0x200000,1,dump); + fclose(dump); + } + } + if(RegDump()) { + dump=fopen(RegDumpFileName,"wb"); + if (dump) { + fwrite(spu2regs,0x2000,1,dump); + fclose(dump); + } + } + + if(!CoresDump()) return; + dump=fopen(CoresDumpFileName,"wt"); + if (dump) { + for(c=0;c<2;c++) { + fprintf(dump,"#### CORE %d DUMP.\n",c); + fprintf(dump,"Master Volume for Left Channel: %x\n" + " - Value: %x\n" + " - Mode: %x\n" + " - Increment: %x\n", + Cores[c].MasterL.Reg_VOL, + Cores[c].MasterL.Value, + Cores[c].MasterL.Mode, + Cores[c].MasterL.Increment); + fprintf(dump,"Master Volume for Right Channel: %x\n" + " - Value: %x\n" + " - Mode: %x\n" + " - Increment: %x\n", + Cores[c].MasterR.Reg_VOL, + Cores[c].MasterR.Value, + Cores[c].MasterR.Mode, + Cores[c].MasterR.Increment); + fprintf(dump,"Volume for External Data Input (Left Channel): %x\n",Cores[c].ExtL); + fprintf(dump,"Volume for External Data Input (Right Channel): %x\n",Cores[c].ExtR); + fprintf(dump,"Volume for Sound Data Input (Left Channel): %x\n",Cores[c].InpL); + fprintf(dump,"Volume for Sound Data Input (Right Channel): %x\n",Cores[c].InpR); + fprintf(dump,"Volume for Output from Effects (Left Channel): %x\n",Cores[c].FxL); + fprintf(dump,"Volume for Output from Effects (Right Channel): %x\n",Cores[c].FxR); + fprintf(dump,"Interrupt Address: %x\n",Cores[c].IRQA); + fprintf(dump,"DMA Transfer Start Address: %x\n",Cores[c].TSA); + fprintf(dump,"External Input to Direct Output (Left): %s\n",Cores[c].ExtDryL?"Yes":"No"); + fprintf(dump,"External Input to Direct Output (Right): %s\n",Cores[c].ExtDryR?"Yes":"No"); + fprintf(dump,"External Input to Effects (Left): %s\n",Cores[c].ExtWetL?"Yes":"No"); + fprintf(dump,"External Input to Effects (Right): %s\n",Cores[c].ExtWetR?"Yes":"No"); + fprintf(dump,"Sound Data Input to Direct Output (Left): %s\n",Cores[c].SndDryL?"Yes":"No"); + fprintf(dump,"Sound Data Input to Direct Output (Right): %s\n",Cores[c].SndDryR?"Yes":"No"); + fprintf(dump,"Sound Data Input to Effects (Left): %s\n",Cores[c].SndWetL?"Yes":"No"); + fprintf(dump,"Sound Data Input to Effects (Right): %s\n",Cores[c].SndWetR?"Yes":"No"); + fprintf(dump,"Voice Data Input to Direct Output (Left): %s\n",Cores[c].InpDryL?"Yes":"No"); + fprintf(dump,"Voice Data Input to Direct Output (Right): %s\n",Cores[c].InpDryR?"Yes":"No"); + fprintf(dump,"Voice Data Input to Effects (Left): %s\n",Cores[c].InpWetL?"Yes":"No"); + fprintf(dump,"Voice Data Input to Effects (Right): %s\n",Cores[c].InpWetR?"Yes":"No"); + fprintf(dump,"IRQ Enabled: %s\n",Cores[c].IRQEnable?"Yes":"No"); + fprintf(dump,"Effects Enabled: %s\n",Cores[c].FxEnable?"Yes":"No"); + fprintf(dump,"Mute Enabled: %s\n",Cores[c].Mute?"Yes":"No"); + fprintf(dump,"Noise Clock: %d\n",Cores[c].NoiseClk); + fprintf(dump,"DMA Bits: %d\n",Cores[c].DMABits); + fprintf(dump,"Effects Start: %x\n",Cores[c].EffectsStartA); + fprintf(dump,"Effects End: %x\n",Cores[c].EffectsEndA); + fprintf(dump,"Registers:\n"); + fprintf(dump," - PMON: %x\n",Cores[c].Regs.PMON); + fprintf(dump," - NON: %x\n",Cores[c].Regs.NON); + fprintf(dump," - VMIXL: %x\n",Cores[c].Regs.VMIXL); + fprintf(dump," - VMIXR: %x\n",Cores[c].Regs.VMIXR); + fprintf(dump," - VMIXEL: %x\n",Cores[c].Regs.VMIXEL); + fprintf(dump," - VMIXER: %x\n",Cores[c].Regs.VMIXER); + fprintf(dump," - MMIX: %x\n",Cores[c].Regs.VMIXEL); + fprintf(dump," - ENDX: %x\n",Cores[c].Regs.VMIXER); + fprintf(dump," - STATX: %x\n",Cores[c].Regs.VMIXEL); + fprintf(dump," - ATTR: %x\n",Cores[c].Regs.VMIXER); + for(v=0;v<24;v++) { + fprintf(dump,"Voice %d:\n",v); + fprintf(dump," - Volume for Left Channel: %x\n" + " - Value: %x\n" + " - Mode: %x\n" + " - Increment: %x\n", + Cores[c].Voices[v].VolumeL.Reg_VOL, + Cores[c].Voices[v].VolumeL.Value, + Cores[c].Voices[v].VolumeL.Mode, + Cores[c].Voices[v].VolumeL.Increment); + fprintf(dump," - Volume for Right Channel: %x\n" + " - Value: %x\n" + " - Mode: %x\n" + " - Increment: %x\n", + Cores[c].Voices[v].VolumeR.Reg_VOL, + Cores[c].Voices[v].VolumeR.Value, + Cores[c].Voices[v].VolumeR.Mode, + Cores[c].Voices[v].VolumeR.Increment); + fprintf(dump," - ADSR Envelope: %x & %x\n" + " - Ar: %x\n" + " - Am: %x\n" + " - Dr: %x\n" + " - Sl: %x\n" + " - Sr: %x\n" + " - Sm: %x\n" + " - Rr: %x\n" + " - Rm: %x\n" + " - Phase: %x\n" + " - Value: %x\n", + Cores[c].Voices[v].ADSR.Reg_ADSR1, + Cores[c].Voices[v].ADSR.Reg_ADSR2, + Cores[c].Voices[v].ADSR.Ar, + Cores[c].Voices[v].ADSR.Am, + Cores[c].Voices[v].ADSR.Dr, + Cores[c].Voices[v].ADSR.Sl, + Cores[c].Voices[v].ADSR.Sr, + Cores[c].Voices[v].ADSR.Sm, + Cores[c].Voices[v].ADSR.Rr, + Cores[c].Voices[v].ADSR.Rm, + Cores[c].Voices[v].ADSR.Phase, + Cores[c].Voices[v].ADSR.Value); + fprintf(dump," - Pitch: %x\n",Cores[c].Voices[v].Pitch); + fprintf(dump," - Modulated: %s\n",Cores[c].Voices[v].Modulated?"Yes":"No"); + fprintf(dump," - Source: %s\n",Cores[c].Voices[v].Noise?"Noise":"Wave"); + fprintf(dump," - Direct Output for Left Channel: %s\n",Cores[c].Voices[v].DryL?"Yes":"No"); + fprintf(dump," - Direct Output for Right Channel: %s\n",Cores[c].Voices[v].DryR?"Yes":"No"); + fprintf(dump," - Effects Output for Left Channel: %s\n",Cores[c].Voices[v].WetL?"Yes":"No"); + fprintf(dump," - Effects Output for Right Channel: %s\n",Cores[c].Voices[v].WetR?"Yes":"No"); + fprintf(dump," - Loop Start Adress: %x\n",Cores[c].Voices[v].LoopStartA); + fprintf(dump," - Sound Start Adress: %x\n",Cores[c].Voices[v].StartA); + fprintf(dump," - Next Data Adress: %x\n",Cores[c].Voices[v].NextA); + fprintf(dump," - Play Start Cycle: %d\n",Cores[c].Voices[v].PlayCycle); + fprintf(dump," - Play Status: %s\n",(Cores[c].Voices[v].ADSR.Phase>0)?"Playing":"Not Playing"); + fprintf(dump," - Block Sample: %d\n",Cores[c].Voices[v].SCurrent); + } + fprintf(dump,"#### END OF DUMP.\n\n"); + } + } + fclose(dump); + dump=fopen("logs/effects.txt","wt"); + if (dump) { + for(c=0;c<2;c++) { + fprintf(dump,"#### CORE %d EFFECTS PROCESSOR DUMP.\n",c); + + fprintf(dump," - IN_COEF_L: %x\n",Cores[c].Revb.IN_COEF_R); + fprintf(dump," - IN_COEF_R: %x\n",Cores[c].Revb.IN_COEF_L); + + fprintf(dump," - FB_ALPHA: %x\n",Cores[c].Revb.FB_ALPHA); + fprintf(dump," - FB_X: %x\n",Cores[c].Revb.FB_X); + fprintf(dump," - FB_SRC_A: %x\n",Cores[c].Revb.FB_SRC_A); + fprintf(dump," - FB_SRC_B: %x\n",Cores[c].Revb.FB_SRC_B); + + fprintf(dump," - IIR_ALPHA: %x\n",Cores[c].Revb.IIR_ALPHA); + fprintf(dump," - IIR_COEF: %x\n",Cores[c].Revb.IIR_COEF); + fprintf(dump," - IIR_SRC_A0: %x\n",Cores[c].Revb.IIR_SRC_A0); + fprintf(dump," - IIR_SRC_A1: %x\n",Cores[c].Revb.IIR_SRC_A1); + fprintf(dump," - IIR_SRC_B1: %x\n",Cores[c].Revb.IIR_SRC_B0); + fprintf(dump," - IIR_SRC_B0: %x\n",Cores[c].Revb.IIR_SRC_B1); + fprintf(dump," - IIR_DEST_A0: %x\n",Cores[c].Revb.IIR_DEST_A0); + fprintf(dump," - IIR_DEST_A1: %x\n",Cores[c].Revb.IIR_DEST_A1); + fprintf(dump," - IIR_DEST_B0: %x\n",Cores[c].Revb.IIR_DEST_B0); + fprintf(dump," - IIR_DEST_B1: %x\n",Cores[c].Revb.IIR_DEST_B1); + + fprintf(dump," - ACC_COEF_A: %x\n",Cores[c].Revb.ACC_COEF_A); + fprintf(dump," - ACC_COEF_B: %x\n",Cores[c].Revb.ACC_COEF_B); + fprintf(dump," - ACC_COEF_C: %x\n",Cores[c].Revb.ACC_COEF_C); + fprintf(dump," - ACC_COEF_D: %x\n",Cores[c].Revb.ACC_COEF_D); + fprintf(dump," - ACC_SRC_A0: %x\n",Cores[c].Revb.ACC_SRC_A0); + fprintf(dump," - ACC_SRC_A1: %x\n",Cores[c].Revb.ACC_SRC_A1); + fprintf(dump," - ACC_SRC_B0: %x\n",Cores[c].Revb.ACC_SRC_B0); + fprintf(dump," - ACC_SRC_B1: %x\n",Cores[c].Revb.ACC_SRC_B1); + fprintf(dump," - ACC_SRC_C0: %x\n",Cores[c].Revb.ACC_SRC_C0); + fprintf(dump," - ACC_SRC_C1: %x\n",Cores[c].Revb.ACC_SRC_C1); + fprintf(dump," - ACC_SRC_D0: %x\n",Cores[c].Revb.ACC_SRC_D0); + fprintf(dump," - ACC_SRC_D1: %x\n",Cores[c].Revb.ACC_SRC_D1); + + fprintf(dump," - MIX_DEST_A0: %x\n",Cores[c].Revb.MIX_DEST_A0); + fprintf(dump," - MIX_DEST_A1: %x\n",Cores[c].Revb.MIX_DEST_A1); + fprintf(dump," - MIX_DEST_B0: %x\n",Cores[c].Revb.MIX_DEST_B0); + fprintf(dump," - MIX_DEST_B1: %x\n",Cores[c].Revb.MIX_DEST_B1); + fprintf(dump,"#### END OF DUMP.\n\n"); + } + fclose(dump); + } +#endif +} diff --git a/plugins/spu2ghz/src/debug.h b/plugins/spu2ghz/src/debug.h index 319bdcd5ed..724a4e94c0 100644 --- a/plugins/spu2ghz/src/debug.h +++ b/plugins/spu2ghz/src/debug.h @@ -1,36 +1,36 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// - -#ifndef DEBUG_H_INCLUDED -#define DEBUG_H_INCLUDED - -extern FILE *spu2Log; - -void FileLog(const char *fmt, ...); -void ConLog(const char *fmt, ...); - -void DoFullDump(); - -extern int wavedump_ok; - -int wavedump_open(); -void wavedump_close(); -void wavedump_write(s16 left,s16 right); - - -#endif // DEBUG_H_INCLUDED // +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#ifndef DEBUG_H_INCLUDED +#define DEBUG_H_INCLUDED + +extern FILE *spu2Log; + +void FileLog(const char *fmt, ...); +void ConLog(const char *fmt, ...); + +void DoFullDump(); + +extern int wavedump_ok; + +int wavedump_open(); +void wavedump_close(); +void wavedump_write(s16 left,s16 right); + + +#endif // DEBUG_H_INCLUDED // diff --git a/plugins/spu2ghz/src/decoder.cpp b/plugins/spu2ghz/src/decoder.cpp index fa4482a472..ac7efcf57f 100644 --- a/plugins/spu2ghz/src/decoder.cpp +++ b/plugins/spu2ghz/src/decoder.cpp @@ -1,385 +1,385 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -#include "spu2.h" - -extern "C" { -#include "liba52/inttypes.h" -#include "liba52/a52.h" -#include "liba52/mm_accel.h" -} - -extern u32 spdif_read_data(u8 *buff, u32 max_data); - -#define DATA_SIZE 0x100000 - -u32 use51=0; - -u8 databuffer[DATA_SIZE]; -u32 data_in_buffer; - -s32 output_buffer[0x10000][6]; -s32 output_write_cursor=0; -s32 output_read_cursor=0; -s32 output_buffer_data=0; - -int flags,srate,bitrate; - -#define CHANNEL_CENTER 1 -#define CHANNEL_STEREO 2 -#define CHANNEL_SURROUND 4 -#define CHANNEL_LFE 8 - -int sample_flags = 0; - -u32 frame_size; - -a52_state_t* ac3dec; -sample_t *decode_buffer = NULL; - -s32 data_rate=4; - -int state=0; - -FILE *fSpdifDump; - -extern u32 core; -void __fastcall ReadInput(V_Core& thiscore, s32& PDataL,s32& PDataR); - -union spdif_frame { // total size: 32bits - struct { - u32 preamble:4; //4 - u32 databits:24; //28 - u32 valid:1; //29 - u32 subcode:1; //30 - u32 chanstat:1; //31 - u32 parity:1; //32 // parity not including preamble - } bits; - u32 whole; -}; - -union spdif_block { - spdif_frame frames[192]; - u8 bytes [192*4]; -}; - -/* -spdif_block bbuffer[2]; -u8 *bbuff = bbuffer[0].bytes; -u32 bbuff_bytes = 0; -*/ - -bool check_frame(spdif_frame f) -{ - u32 w = f.whole>>4; - u32 t = 0; - - for(int i=0;i>28;i++) - { - t=t^(w&1); - w>>=1; - } - - return (t==0)&&(f.bits.valid); -} - -void spdif_Write(s32 data) -{ - spdif_frame f; - - f.whole=data; - - if(check_frame(f)) - { - int dec = f.bits.databits; - databuffer[data_in_buffer++]=(dec )&0xFF; - databuffer[data_in_buffer++]=(dec>> 8)&0xFF; - databuffer[data_in_buffer++]=(dec>>16)&0xFF; - } -} - -void spdif_remove_data(unsigned int bytes) -{ - if(bytes0)*-1; //1 if positive, -1 if negative, 0 otherwise - n=abs(n)+1; //make it [1..2] - s32 k=*(s32*)&n; - k=k&0x7FFFFF; - return k*sign; -} - -void spdif_update() -{ - s32 Data,Zero; - - core=0; - V_Core& thiscore( Cores[core] ); - for(int i=0;i +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#include "spu2.h" + +extern "C" { +#include "liba52/inttypes.h" +#include "liba52/a52.h" +#include "liba52/mm_accel.h" +} + +extern u32 spdif_read_data(u8 *buff, u32 max_data); + +#define DATA_SIZE 0x100000 + +u32 use51=0; + +u8 databuffer[DATA_SIZE]; +u32 data_in_buffer; + +s32 output_buffer[0x10000][6]; +s32 output_write_cursor=0; +s32 output_read_cursor=0; +s32 output_buffer_data=0; + +int flags,srate,bitrate; + +#define CHANNEL_CENTER 1 +#define CHANNEL_STEREO 2 +#define CHANNEL_SURROUND 4 +#define CHANNEL_LFE 8 + +int sample_flags = 0; + +u32 frame_size; + +a52_state_t* ac3dec; +sample_t *decode_buffer = NULL; + +s32 data_rate=4; + +int state=0; + +FILE *fSpdifDump; + +extern u32 core; +void __fastcall ReadInput(V_Core& thiscore, s32& PDataL,s32& PDataR); + +union spdif_frame { // total size: 32bits + struct { + u32 preamble:4; //4 + u32 databits:24; //28 + u32 valid:1; //29 + u32 subcode:1; //30 + u32 chanstat:1; //31 + u32 parity:1; //32 // parity not including preamble + } bits; + u32 whole; +}; + +union spdif_block { + spdif_frame frames[192]; + u8 bytes [192*4]; +}; + +/* +spdif_block bbuffer[2]; +u8 *bbuff = bbuffer[0].bytes; +u32 bbuff_bytes = 0; +*/ + +bool check_frame(spdif_frame f) +{ + u32 w = f.whole>>4; + u32 t = 0; + + for(int i=0;i>28;i++) + { + t=t^(w&1); + w>>=1; + } + + return (t==0)&&(f.bits.valid); +} + +void spdif_Write(s32 data) +{ + spdif_frame f; + + f.whole=data; + + if(check_frame(f)) + { + int dec = f.bits.databits; + databuffer[data_in_buffer++]=(dec )&0xFF; + databuffer[data_in_buffer++]=(dec>> 8)&0xFF; + databuffer[data_in_buffer++]=(dec>>16)&0xFF; + } +} + +void spdif_remove_data(unsigned int bytes) +{ + if(bytes0)*-1; //1 if positive, -1 if negative, 0 otherwise + n=abs(n)+1; //make it [1..2] + s32 k=*(s32*)&n; + k=k&0x7FFFFF; + return k*sign; +} + +void spdif_update() +{ + s32 Data,Zero; + + core=0; + V_Core& thiscore( Cores[core] ); + for(int i=0;i -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// - -#ifndef DEFS_H_INCLUDED -#define DEFS_H_INCLUDED - -typedef enum {SPU2_VOL_MODE_CONST,SPU2_VOL_MODE_PLIN,SPU2_VOL_MODE_NLIN,SPU2_VOL_MODE_PLOG,SPU2_VOL_MODE_NLOG} V_VolMode; - -typedef struct { - u16 Reg_VOL; - s16 Value; //also Reg_VOLX - s8 Increment; - s8 Mode; -} V_Volume; - -typedef struct { - u16 Reg_ADSR1; - u16 Reg_ADSR2; -//also Reg_ENVX - s32 Value; // [Air] : Ranges from 0 to 0x7fffffff (signed values are clamped to 0) -// Phase - u8 Phase; -//Attack Rate - u8 Ar; -//Attack Mode - u8 Am; -//Decay Rate - u8 Dr; -//Sustain Level - u8 Sl; -//Sustain Rate - u8 Sr; -//Sustain Mode - u8 Sm; -//Release Rate - u8 Rr; -//Release Mode - u8 Rm; -//Ready To Release - u8 Releasing; -} V_ADSR; - - -typedef struct { -// SPU2 cycle where the Playing started - u32 PlayCycle; -// Left Volume - V_Volume VolumeL; -// Right Volume - V_Volume VolumeR; -// Envelope - V_ADSR ADSR; -// Pitch (also Reg_PITCH) - s16 Pitch; -// Pitch Modulated by previous voice - s8 Modulated; -// Source (Wave/Noise) - s8 Noise; -// Direct Output for Left Channel - s8 DryL; -// Direct Output for Right Channel - s8 DryR; -// Effect Output for Left Channel - s8 WetL; -// Effect Output for Right Channel - s8 WetR; -// Loop Start Adress (also Reg_LSAH/L) - u32 LoopStartA; -// Sound Start Adress (also Reg_SSAH/L) - u32 StartA; -// Next Read Data Adress (also Reg_NAXH/L) - u32 NextA; -// Voice Decoding State - s32 Prev1; - s32 Prev2; - - s8 LoopMode; - s8 LoopFlags; - -// [Air] : Replaced loop flags read from the ADPCM header with -// a single LoopFlags value (above) -- more cache-friendly. - //s8 LoopStart; - //s8 Loop; - //s8 LoopEnd; - -// Sample pointer (19:12 bit fixed point) - s32 SP; - -// Sample pointer for Cubic Interpolation -// Cubic interpolation mixes a sample behind Linear, so that it -// can have sample data to either side of the end points from which -// to extrapolate. This SP represents that late sample position. - s32 SPc; - -// Previous sample values - used for interpolation -// [Air] : Inverted order of these members to match the access order in the -// code (might improve cache hits). - s32 PV4; - s32 PV3; - s32 PV2; - s32 PV1; - -// Last outputted audio value, used for voice modulation. - s32 OutX; - -// SBuffer now points directly to an ADPCM cache entry. - s16 *SBuffer; - -// sample position within the current decoded packet. - s32 SCurrent; - -} V_Voice; - -#ifndef PUBLIC -// ** Begin Debug-only variables section ** -// Separated from the V_Voice struct to improve cache performance of -// the Public Release build. -struct V_VoiceDebug -{ - s8 FirstBlock; - s32 SampleData; - s32 PeakX; - s32 displayPeak; - s32 lastSetStartA; - s32 lastStopReason; -}; - -struct V_CoreDebug -{ - V_VoiceDebug Voices[24]; - s32 AutoDMAPeak; -// Last Transfer Size - u32 lastsize; -}; - -// Debug tracking information - 24 voices and 2 cores. -extern V_CoreDebug DebugCores[2]; -#endif - -typedef struct { - u16 IN_COEF_L; - u16 IN_COEF_R; - u32 FB_SRC_A; - u32 FB_SRC_B; - u16 FB_ALPHA; - u16 FB_X; - u32 IIR_SRC_A0; - u32 IIR_SRC_A1; - u32 IIR_SRC_B1; - u32 IIR_SRC_B0; - u32 IIR_DEST_A0; - u32 IIR_DEST_A1; - u32 IIR_DEST_B0; - u32 IIR_DEST_B1; - u16 IIR_ALPHA; - u16 IIR_COEF; - u32 ACC_SRC_A0; - u32 ACC_SRC_A1; - u32 ACC_SRC_B0; - u32 ACC_SRC_B1; - u32 ACC_SRC_C0; - u32 ACC_SRC_C1; - u32 ACC_SRC_D0; - u32 ACC_SRC_D1; - u16 ACC_COEF_A; - u16 ACC_COEF_B; - u16 ACC_COEF_C; - u16 ACC_COEF_D; - u32 MIX_DEST_A0; - u32 MIX_DEST_A1; - u32 MIX_DEST_B0; - u32 MIX_DEST_B1; -} V_Reverb; - -typedef struct { - u16 Out; - u16 Info; - u16 Unknown1; - u16 Mode; - u16 Media; - u16 Unknown2; - u16 Protection; -} V_SPDIF; - -typedef struct { - u32 PMON; - u32 NON; - u32 VMIXL; - u32 VMIXR; - u32 VMIXEL; - u32 VMIXER; - u16 MMIX; - u32 ENDX; - u16 STATX; - u16 ATTR; - u16 _1AC; -} V_CoreRegs; - -typedef struct { -// Core Voices - V_Voice Voices[24]; -// Master Volume for Left Channel - V_Volume MasterL; -// Master Volume for Right Channel - V_Volume MasterR; -// Volume for External Data Input (Left Channel) - u16 ExtL; -// Volume for External Data Input (Right Channel) - u16 ExtR; -// Volume for Sound Data Input (Left Channel) - u16 InpL; -// Volume for Sound Data Input (Right Channel) - u16 InpR; -// Volume for Output from Effects (Left Channel) - u16 FxL; -// Volume for Output from Effects (Right Channel) - u16 FxR; -// Interrupt Address - u32 IRQA; -// DMA Transfer Start Address - u32 TSA; -// DMA Transfer Data Address (Internal...) - u32 TDA; -// External Input to Direct Output (Left) - s8 ExtDryL; -// External Input to Direct Output (Right) - s8 ExtDryR; -// External Input to Effects (Left) - s8 ExtWetL; -// External Input to Effects (Right) - s8 ExtWetR; -// Sound Data Input to Direct Output (Left) - s8 InpDryL; -// Sound Data Input to Direct Output (Right) - s8 InpDryR; -// Sound Data Input to Effects (Left) - s8 InpWetL; -// Sound Data Input to Effects (Right) - s8 InpWetR; -// Voice Data to Direct Output (Left) - s8 SndDryL; -// Voice Data to Direct Output (Right) - s8 SndDryR; -// Voice Data to Effects (Left) - s8 SndWetL; -// Voice Data to Effects (Right) - s8 SndWetR; -// Interrupt Enable - s8 IRQEnable; -// DMA related? - s8 DMABits; -// Effect Enable - s8 FxEnable; -// Noise Clock - s8 NoiseClk; -// AutoDMA Status - u16 AutoDMACtrl; -// DMA Interrupt Counter - s32 DMAICounter; -// Mute - s8 Mute; -// Input Buffer - u32 InputDataLeft; - u32 InputPos; - u32 InputDataProgress; - u8 AdmaInProgress; - -// Reverb - V_Reverb Revb; - u32 EffectsStartA; - u32 EffectsEndA; - u32 ReverbX; -// Registers - V_CoreRegs Regs; - - u8 InitDelay; - - u8 CoreEnabled; - - u8 AttrBit0; - u8 AttrBit4; - u8 AttrBit5; - - u16*DMAPtr; - u32 MADR; - u32 TADR; - - s16 ADMATempBuffer[0x1000]; - - u32 ADMAPV; - u32 ADMAPL; - u32 ADMAPR; - -} V_Core; - -extern V_Core Cores[2]; -extern V_SPDIF Spdif; - -// Output Buffer Writing Position (the same for all data); -extern s16 OutPos; -// Input Buffer Reading Position (the same for all data); -extern s16 InputPos; -// SPU Mixing Cycles ("Ticks mixed" counter) -extern u32 Cycles; -extern u8 InpBuff; -// 1b0 "hack" -extern u32 Num; - - -#endif // DEFS_H_INCLUDED // +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#ifndef DEFS_H_INCLUDED +#define DEFS_H_INCLUDED + +typedef enum {SPU2_VOL_MODE_CONST,SPU2_VOL_MODE_PLIN,SPU2_VOL_MODE_NLIN,SPU2_VOL_MODE_PLOG,SPU2_VOL_MODE_NLOG} V_VolMode; + +typedef struct { + u16 Reg_VOL; + s16 Value; //also Reg_VOLX + s8 Increment; + s8 Mode; +} V_Volume; + +typedef struct { + u16 Reg_ADSR1; + u16 Reg_ADSR2; +//also Reg_ENVX + s32 Value; // [Air] : Ranges from 0 to 0x7fffffff (signed values are clamped to 0) +// Phase + u8 Phase; +//Attack Rate + u8 Ar; +//Attack Mode + u8 Am; +//Decay Rate + u8 Dr; +//Sustain Level + u8 Sl; +//Sustain Rate + u8 Sr; +//Sustain Mode + u8 Sm; +//Release Rate + u8 Rr; +//Release Mode + u8 Rm; +//Ready To Release + u8 Releasing; +} V_ADSR; + + +typedef struct { +// SPU2 cycle where the Playing started + u32 PlayCycle; +// Left Volume + V_Volume VolumeL; +// Right Volume + V_Volume VolumeR; +// Envelope + V_ADSR ADSR; +// Pitch (also Reg_PITCH) + s16 Pitch; +// Pitch Modulated by previous voice + s8 Modulated; +// Source (Wave/Noise) + s8 Noise; +// Direct Output for Left Channel + s8 DryL; +// Direct Output for Right Channel + s8 DryR; +// Effect Output for Left Channel + s8 WetL; +// Effect Output for Right Channel + s8 WetR; +// Loop Start Adress (also Reg_LSAH/L) + u32 LoopStartA; +// Sound Start Adress (also Reg_SSAH/L) + u32 StartA; +// Next Read Data Adress (also Reg_NAXH/L) + u32 NextA; +// Voice Decoding State + s32 Prev1; + s32 Prev2; + + s8 LoopMode; + s8 LoopFlags; + +// [Air] : Replaced loop flags read from the ADPCM header with +// a single LoopFlags value (above) -- more cache-friendly. + //s8 LoopStart; + //s8 Loop; + //s8 LoopEnd; + +// Sample pointer (19:12 bit fixed point) + s32 SP; + +// Sample pointer for Cubic Interpolation +// Cubic interpolation mixes a sample behind Linear, so that it +// can have sample data to either side of the end points from which +// to extrapolate. This SP represents that late sample position. + s32 SPc; + +// Previous sample values - used for interpolation +// [Air] : Inverted order of these members to match the access order in the +// code (might improve cache hits). + s32 PV4; + s32 PV3; + s32 PV2; + s32 PV1; + +// Last outputted audio value, used for voice modulation. + s32 OutX; + +// SBuffer now points directly to an ADPCM cache entry. + s16 *SBuffer; + +// sample position within the current decoded packet. + s32 SCurrent; + +} V_Voice; + +#ifndef PUBLIC +// ** Begin Debug-only variables section ** +// Separated from the V_Voice struct to improve cache performance of +// the Public Release build. +struct V_VoiceDebug +{ + s8 FirstBlock; + s32 SampleData; + s32 PeakX; + s32 displayPeak; + s32 lastSetStartA; + s32 lastStopReason; +}; + +struct V_CoreDebug +{ + V_VoiceDebug Voices[24]; + s32 AutoDMAPeak; +// Last Transfer Size + u32 lastsize; +}; + +// Debug tracking information - 24 voices and 2 cores. +extern V_CoreDebug DebugCores[2]; +#endif + +typedef struct { + u16 IN_COEF_L; + u16 IN_COEF_R; + u32 FB_SRC_A; + u32 FB_SRC_B; + u16 FB_ALPHA; + u16 FB_X; + u32 IIR_SRC_A0; + u32 IIR_SRC_A1; + u32 IIR_SRC_B1; + u32 IIR_SRC_B0; + u32 IIR_DEST_A0; + u32 IIR_DEST_A1; + u32 IIR_DEST_B0; + u32 IIR_DEST_B1; + u16 IIR_ALPHA; + u16 IIR_COEF; + u32 ACC_SRC_A0; + u32 ACC_SRC_A1; + u32 ACC_SRC_B0; + u32 ACC_SRC_B1; + u32 ACC_SRC_C0; + u32 ACC_SRC_C1; + u32 ACC_SRC_D0; + u32 ACC_SRC_D1; + u16 ACC_COEF_A; + u16 ACC_COEF_B; + u16 ACC_COEF_C; + u16 ACC_COEF_D; + u32 MIX_DEST_A0; + u32 MIX_DEST_A1; + u32 MIX_DEST_B0; + u32 MIX_DEST_B1; +} V_Reverb; + +typedef struct { + u16 Out; + u16 Info; + u16 Unknown1; + u16 Mode; + u16 Media; + u16 Unknown2; + u16 Protection; +} V_SPDIF; + +typedef struct { + u32 PMON; + u32 NON; + u32 VMIXL; + u32 VMIXR; + u32 VMIXEL; + u32 VMIXER; + u16 MMIX; + u32 ENDX; + u16 STATX; + u16 ATTR; + u16 _1AC; +} V_CoreRegs; + +typedef struct { +// Core Voices + V_Voice Voices[24]; +// Master Volume for Left Channel + V_Volume MasterL; +// Master Volume for Right Channel + V_Volume MasterR; +// Volume for External Data Input (Left Channel) + u16 ExtL; +// Volume for External Data Input (Right Channel) + u16 ExtR; +// Volume for Sound Data Input (Left Channel) + u16 InpL; +// Volume for Sound Data Input (Right Channel) + u16 InpR; +// Volume for Output from Effects (Left Channel) + u16 FxL; +// Volume for Output from Effects (Right Channel) + u16 FxR; +// Interrupt Address + u32 IRQA; +// DMA Transfer Start Address + u32 TSA; +// DMA Transfer Data Address (Internal...) + u32 TDA; +// External Input to Direct Output (Left) + s8 ExtDryL; +// External Input to Direct Output (Right) + s8 ExtDryR; +// External Input to Effects (Left) + s8 ExtWetL; +// External Input to Effects (Right) + s8 ExtWetR; +// Sound Data Input to Direct Output (Left) + s8 InpDryL; +// Sound Data Input to Direct Output (Right) + s8 InpDryR; +// Sound Data Input to Effects (Left) + s8 InpWetL; +// Sound Data Input to Effects (Right) + s8 InpWetR; +// Voice Data to Direct Output (Left) + s8 SndDryL; +// Voice Data to Direct Output (Right) + s8 SndDryR; +// Voice Data to Effects (Left) + s8 SndWetL; +// Voice Data to Effects (Right) + s8 SndWetR; +// Interrupt Enable + s8 IRQEnable; +// DMA related? + s8 DMABits; +// Effect Enable + s8 FxEnable; +// Noise Clock + s8 NoiseClk; +// AutoDMA Status + u16 AutoDMACtrl; +// DMA Interrupt Counter + s32 DMAICounter; +// Mute + s8 Mute; +// Input Buffer + u32 InputDataLeft; + u32 InputPos; + u32 InputDataProgress; + u8 AdmaInProgress; + +// Reverb + V_Reverb Revb; + u32 EffectsStartA; + u32 EffectsEndA; + u32 ReverbX; +// Registers + V_CoreRegs Regs; + + u8 InitDelay; + + u8 CoreEnabled; + + u8 AttrBit0; + u8 AttrBit4; + u8 AttrBit5; + + u16*DMAPtr; + u32 MADR; + u32 TADR; + + s16 ADMATempBuffer[0x1000]; + + u32 ADMAPV; + u32 ADMAPL; + u32 ADMAPR; + +} V_Core; + +extern V_Core Cores[2]; +extern V_SPDIF Spdif; + +// Output Buffer Writing Position (the same for all data); +extern s16 OutPos; +// Input Buffer Reading Position (the same for all data); +extern s16 InputPos; +// SPU Mixing Cycles ("Ticks mixed" counter) +extern u32 Cycles; +extern u8 InpBuff; +// 1b0 "hack" +extern u32 Num; + + +#endif // DEFS_H_INCLUDED // diff --git a/plugins/spu2ghz/src/dma.cpp b/plugins/spu2ghz/src/dma.cpp index b9e85739ea..3ec2a5f8eb 100644 --- a/plugins/spu2ghz/src/dma.cpp +++ b/plugins/spu2ghz/src/dma.cpp @@ -1,510 +1,510 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -#include "spu2.h" - -extern u8 callirq; - -FILE *DMA4LogFile=0; -FILE *DMA7LogFile=0; -FILE *ADMA4LogFile=0; -FILE *ADMA7LogFile=0; -FILE *ADMAOutLogFile=0; - -FILE *REGWRTLogFile[2]={0,0}; - -int packcount=0; - -u16* MBASE[2] = {0,0}; - -u16* DMABaseAddr; - -void DMALogOpen() { - if(!DMALog()) return; - DMA4LogFile=fopen(DMA4LogFileName,"wb"); - DMA7LogFile=fopen(DMA7LogFileName,"wb"); - ADMA4LogFile=fopen("logs/adma4.raw","wb"); - ADMA7LogFile=fopen("logs/adma7.raw","wb"); - ADMAOutLogFile=fopen("logs/admaOut.raw","wb"); - //REGWRTLogFile[0]=fopen("logs/RegWrite0.raw","wb"); - //REGWRTLogFile[1]=fopen("logs/RegWrite1.raw","wb"); -} -void DMA4LogWrite(void *lpData, u32 ulSize) { - if(!DMALog()) return; - if (!DMA4LogFile) return; - fwrite(lpData,ulSize,1,DMA4LogFile); -} - -void DMA7LogWrite(void *lpData, u32 ulSize) { - if(!DMALog()) return; - if (!DMA7LogFile) return; - fwrite(lpData,ulSize,1,DMA7LogFile); -} - -void ADMA4LogWrite(void *lpData, u32 ulSize) { - if(!DMALog()) return; - if (!ADMA4LogFile) return; - fwrite(lpData,ulSize,1,ADMA4LogFile); -} -void ADMA7LogWrite(void *lpData, u32 ulSize) { - if(!DMALog()) return; - if (!ADMA7LogFile) return; - fwrite(lpData,ulSize,1,ADMA7LogFile); -} -void ADMAOutLogWrite(void *lpData, u32 ulSize) { - if(!DMALog()) return; - if (!ADMAOutLogFile) return; - fwrite(lpData,ulSize,1,ADMAOutLogFile); -} - -void RegWriteLog(u32 core,u16 value) -{ - if(!DMALog()) return; - if (!REGWRTLogFile[core]) return; - fwrite(&value,2,1,REGWRTLogFile[core]); -} - -void DMALogClose() { - if(!DMALog()) return; - if (DMA4LogFile) fclose(DMA4LogFile); - if (DMA7LogFile) fclose(DMA7LogFile); - if (REGWRTLogFile[0]) fclose(REGWRTLogFile[0]); - if (REGWRTLogFile[1]) fclose(REGWRTLogFile[1]); - if (ADMA4LogFile) fclose(ADMA4LogFile); - if (ADMA7LogFile) fclose(ADMA7LogFile); - if (ADMAOutLogFile) fclose(ADMAOutLogFile); -} - - -__forceinline u16 DmaRead(u32 core) -{ - const u16 ret = (u16)spu2M_Read(Cores[core].TDA); - Cores[core].TDA++; - Cores[core].TDA&=0xfffff; - return ret; -} - -__forceinline void DmaWrite(u32 core, u16 value) -{ - spu2M_Write( Cores[core].TSA, value ); - Cores[core].TSA++; - Cores[core].TSA&=0xfffff; -} - -void AutoDMAReadBuffer(int core, int mode) //mode: 0= split stereo; 1 = do not split stereo -{ - int spos=((Cores[core].InputPos+0xff)&0x100); //starting position of the free buffer - - if(core==0) - ADMA4LogWrite(Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400); - else - ADMA7LogWrite(Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400); - - if(mode) - { - //hacky :p - - memcpy((Cores[core].ADMATempBuffer+(spos<<1)),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400); - Cores[core].MADR+=0x400; - Cores[core].InputDataLeft-=0x200; - Cores[core].InputDataProgress+=0x200; - } - else - { - memcpy((Cores[core].ADMATempBuffer+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200); - //memcpy((spu2mem+0x2000+(core<<10)+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200); - Cores[core].MADR+=0x200; - Cores[core].InputDataLeft-=0x100; - Cores[core].InputDataProgress+=0x100; - - memcpy((Cores[core].ADMATempBuffer+spos+0x200),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200); - //memcpy((spu2mem+0x2200+(core<<10)+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200); - Cores[core].MADR+=0x200; - Cores[core].InputDataLeft-=0x100; - Cores[core].InputDataProgress+=0x100; - } - // See ReadInput at mixer.cpp for explanation on the commented out lines - // -} - -void StartADMAWrite(int core,u16 *pMem, u32 sz) -{ - int size=(sz)&(~511); - - if(MsgAutoDMA()) ConLog(" * SPU2: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n", - (core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff); - - Cores[core].InputDataProgress=0; - if((Cores[core].AutoDMACtrl&(core+1))==0) - { - Cores[core].TSA=0x2000+(core<<10); - Cores[core].DMAICounter=size; - } - else if(size>=512) - { - Cores[core].InputDataLeft=size; - if(Cores[core].AdmaInProgress==0) - { -#ifdef PCM24_S1_INTERLEAVE - if((core==1)&&((PlayMode&8)==8)) - { - AutoDMAReadBuffer(core,1); - } - else - { - AutoDMAReadBuffer(core,0); - } -#else - if(((PlayMode&4)==4)&&(core==0)) - Cores[0].InputPos=0; - - AutoDMAReadBuffer(core,0); -#endif - - if(size==512) - Cores[core].DMAICounter=size; - } - - Cores[core].AdmaInProgress=1; - } - else - { - Cores[core].InputDataLeft=0; - Cores[core].DMAICounter=1; - } - Cores[core].TADR=Cores[core].MADR+(size<<1); -} - -void DoDMAWrite(int core,u16 *pMem,u32 size) -{ - // Perform an alignment check. - // Not really important. Everything should work regardless, - // but it could be indicative of an emulation foopah elsewhere. - -#if 0 - uptr pa = ((uptr)pMem)&7; - uptr pm = Cores[core].TSA&0x7; - - if( pa ) - { - fprintf(stderr, "* SPU2 DMA Write > Missaligned SOURCE! Core: %d TSA: 0x%x TDA: 0x%x Size: 0x%x\n", core, Cores[core].TSA, Cores[core].TDA, size); - } - - if( pm ) - { - fprintf(stderr, "* SPU2 DMA Write > Missaligned TARGET! Core: %d TSA: 0x%x TDA: 0x%x Size: 0x%x\n", core, Cores[core].TSA, Cores[core].TDA, size ); - } -#endif - - if(core==0) - DMA4LogWrite(pMem,size<<1); - else - DMA7LogWrite(pMem,size<<1); - - if(MsgDMA()) ConLog(" * SPU2: DMA%c Transfer of %d bytes to %x (%02x %x %04x).\n",(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff); - - Cores[core].TSA &= 0xfffff; - - u32 buff1end = Cores[core].TSA + size; - u32 buff2end=0; - if( buff1end > 0x100000 ) - { - buff2end = buff1end - 0x100000; - buff1end = 0x100000; - } - - const int cacheIdxStart = Cores[core].TSA / pcm_WordsPerBlock; - const int cacheIdxEnd = (buff1end+pcm_WordsPerBlock-1) / pcm_WordsPerBlock; - PcmCacheEntry* cacheLine = &pcm_cache_data[cacheIdxStart]; - PcmCacheEntry& cacheEnd = pcm_cache_data[cacheIdxEnd]; - - do - { - cacheLine->Validated = false; - cacheLine++; - } while ( cacheLine != &cacheEnd ); - -#if 0 - // Pcm Cache Invalidation! - // It's a requirement that we mask bits for the blocks that are written to *only*, - // because doing anything else can cause the cache to fail, thanks to the progressive - // nature of the SPU2's ADPCM encoding. (the same thing that makes it impossible - // to use SSE optimizations on it). - - u8* cache = (u8*)pcm_cache_flags; - - // Step 1: Clear bits in the front remainder. - - const int pcmTSA = Cores[core].TSA / pcm_WordsPerBlock; - const int pcmTDA = buff1end / pcm_WordsPerBlock; - const int remFront = pcmTSA & 31; - const int remBack = ((buff1end+pcm_WordsPerBlock-1)/pcm_WordsPerBlock) & 31; // round up to get the end remainder - - int flagTSA = pcmTSA / 32; - - if( remFront ) - { - // need to clear some upper bits of this u32 - uint mask = (1ul< 0 ) - { - // second branch needs copied: - // It starts at the beginning of memory and moves forward to buff2end - - // endpoint cache should be irrelevant, since it's almost certainly dynamic - // memory below 0x2800 (registers and such) - //const u32 endpt2 = (buff2end + roundUp) / indexer_scalar; - //memset( pcm_cache_flags, 0, endpt2 ); - - memcpy( GetMemPtr( 0 ), &pMem[buff1size], buff2end*2 ); - - Cores[core].TDA = (buff2end+1) & 0xfffff; - - if(Cores[core].IRQEnable) - { - // Flag interrupt? - // If IRQA occurs between start and dest, flag it. - // Since the buffer wraps, the conditional might seem odd, but it works. - - if( ( Cores[core].IRQA >= Cores[core].TSA ) || - ( Cores[core].IRQA <= Cores[core].TDA ) ) - { - Spdif.Info=4<= Cores[core].TSA ) && - ( Cores[core].IRQA <= Cores[core].TDA ) ) - { - Spdif.Info=4< 0x100000 ) - { - buff2end = buff1end - 0x100000; - buff1end = 0x100000; - } - - const u32 buff1size = (buff1end-Cores[core].TSA); - memcpy( pMem, GetMemPtr( Cores[core].TSA ), buff1size*2 ); - - if( buff2end > 0 ) - { - // second branch needs cleared: - // It starts at the beginning of memory and moves forward to buff2end - - memcpy( &pMem[buff1size], GetMemPtr( 0 ), buff2end*2 ); - - Cores[core].TDA = (buff2end+0x20) & 0xfffff; - - for( int i=0; i<2; i++ ) - { - if(Cores[i].IRQEnable) - { - // Flag interrupt? - // If IRQA occurs between start and dest, flag it. - // Since the buffer wraps, the conditional might seem odd, but it works. - - if( ( Cores[i].IRQA >= Cores[core].TSA ) || - ( Cores[i].IRQA <= Cores[core].TDA ) ) - { - Spdif.Info=4<= Cores[i].TSA ) && - ( Cores[i].IRQA <= Cores[i].TDA+0x1f ) ) - { - Spdif.Info=4< +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#include "spu2.h" + +extern u8 callirq; + +FILE *DMA4LogFile=0; +FILE *DMA7LogFile=0; +FILE *ADMA4LogFile=0; +FILE *ADMA7LogFile=0; +FILE *ADMAOutLogFile=0; + +FILE *REGWRTLogFile[2]={0,0}; + +int packcount=0; + +u16* MBASE[2] = {0,0}; + +u16* DMABaseAddr; + +void DMALogOpen() { + if(!DMALog()) return; + DMA4LogFile=fopen(DMA4LogFileName,"wb"); + DMA7LogFile=fopen(DMA7LogFileName,"wb"); + ADMA4LogFile=fopen("logs/adma4.raw","wb"); + ADMA7LogFile=fopen("logs/adma7.raw","wb"); + ADMAOutLogFile=fopen("logs/admaOut.raw","wb"); + //REGWRTLogFile[0]=fopen("logs/RegWrite0.raw","wb"); + //REGWRTLogFile[1]=fopen("logs/RegWrite1.raw","wb"); +} +void DMA4LogWrite(void *lpData, u32 ulSize) { + if(!DMALog()) return; + if (!DMA4LogFile) return; + fwrite(lpData,ulSize,1,DMA4LogFile); +} + +void DMA7LogWrite(void *lpData, u32 ulSize) { + if(!DMALog()) return; + if (!DMA7LogFile) return; + fwrite(lpData,ulSize,1,DMA7LogFile); +} + +void ADMA4LogWrite(void *lpData, u32 ulSize) { + if(!DMALog()) return; + if (!ADMA4LogFile) return; + fwrite(lpData,ulSize,1,ADMA4LogFile); +} +void ADMA7LogWrite(void *lpData, u32 ulSize) { + if(!DMALog()) return; + if (!ADMA7LogFile) return; + fwrite(lpData,ulSize,1,ADMA7LogFile); +} +void ADMAOutLogWrite(void *lpData, u32 ulSize) { + if(!DMALog()) return; + if (!ADMAOutLogFile) return; + fwrite(lpData,ulSize,1,ADMAOutLogFile); +} + +void RegWriteLog(u32 core,u16 value) +{ + if(!DMALog()) return; + if (!REGWRTLogFile[core]) return; + fwrite(&value,2,1,REGWRTLogFile[core]); +} + +void DMALogClose() { + if(!DMALog()) return; + if (DMA4LogFile) fclose(DMA4LogFile); + if (DMA7LogFile) fclose(DMA7LogFile); + if (REGWRTLogFile[0]) fclose(REGWRTLogFile[0]); + if (REGWRTLogFile[1]) fclose(REGWRTLogFile[1]); + if (ADMA4LogFile) fclose(ADMA4LogFile); + if (ADMA7LogFile) fclose(ADMA7LogFile); + if (ADMAOutLogFile) fclose(ADMAOutLogFile); +} + + +__forceinline u16 DmaRead(u32 core) +{ + const u16 ret = (u16)spu2M_Read(Cores[core].TDA); + Cores[core].TDA++; + Cores[core].TDA&=0xfffff; + return ret; +} + +__forceinline void DmaWrite(u32 core, u16 value) +{ + spu2M_Write( Cores[core].TSA, value ); + Cores[core].TSA++; + Cores[core].TSA&=0xfffff; +} + +void AutoDMAReadBuffer(int core, int mode) //mode: 0= split stereo; 1 = do not split stereo +{ + int spos=((Cores[core].InputPos+0xff)&0x100); //starting position of the free buffer + + if(core==0) + ADMA4LogWrite(Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400); + else + ADMA7LogWrite(Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400); + + if(mode) + { + //hacky :p + + memcpy((Cores[core].ADMATempBuffer+(spos<<1)),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400); + Cores[core].MADR+=0x400; + Cores[core].InputDataLeft-=0x200; + Cores[core].InputDataProgress+=0x200; + } + else + { + memcpy((Cores[core].ADMATempBuffer+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200); + //memcpy((spu2mem+0x2000+(core<<10)+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200); + Cores[core].MADR+=0x200; + Cores[core].InputDataLeft-=0x100; + Cores[core].InputDataProgress+=0x100; + + memcpy((Cores[core].ADMATempBuffer+spos+0x200),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200); + //memcpy((spu2mem+0x2200+(core<<10)+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200); + Cores[core].MADR+=0x200; + Cores[core].InputDataLeft-=0x100; + Cores[core].InputDataProgress+=0x100; + } + // See ReadInput at mixer.cpp for explanation on the commented out lines + // +} + +void StartADMAWrite(int core,u16 *pMem, u32 sz) +{ + int size=(sz)&(~511); + + if(MsgAutoDMA()) ConLog(" * SPU2: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n", + (core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff); + + Cores[core].InputDataProgress=0; + if((Cores[core].AutoDMACtrl&(core+1))==0) + { + Cores[core].TSA=0x2000+(core<<10); + Cores[core].DMAICounter=size; + } + else if(size>=512) + { + Cores[core].InputDataLeft=size; + if(Cores[core].AdmaInProgress==0) + { +#ifdef PCM24_S1_INTERLEAVE + if((core==1)&&((PlayMode&8)==8)) + { + AutoDMAReadBuffer(core,1); + } + else + { + AutoDMAReadBuffer(core,0); + } +#else + if(((PlayMode&4)==4)&&(core==0)) + Cores[0].InputPos=0; + + AutoDMAReadBuffer(core,0); +#endif + + if(size==512) + Cores[core].DMAICounter=size; + } + + Cores[core].AdmaInProgress=1; + } + else + { + Cores[core].InputDataLeft=0; + Cores[core].DMAICounter=1; + } + Cores[core].TADR=Cores[core].MADR+(size<<1); +} + +void DoDMAWrite(int core,u16 *pMem,u32 size) +{ + // Perform an alignment check. + // Not really important. Everything should work regardless, + // but it could be indicative of an emulation foopah elsewhere. + +#if 0 + uptr pa = ((uptr)pMem)&7; + uptr pm = Cores[core].TSA&0x7; + + if( pa ) + { + fprintf(stderr, "* SPU2 DMA Write > Missaligned SOURCE! Core: %d TSA: 0x%x TDA: 0x%x Size: 0x%x\n", core, Cores[core].TSA, Cores[core].TDA, size); + } + + if( pm ) + { + fprintf(stderr, "* SPU2 DMA Write > Missaligned TARGET! Core: %d TSA: 0x%x TDA: 0x%x Size: 0x%x\n", core, Cores[core].TSA, Cores[core].TDA, size ); + } +#endif + + if(core==0) + DMA4LogWrite(pMem,size<<1); + else + DMA7LogWrite(pMem,size<<1); + + if(MsgDMA()) ConLog(" * SPU2: DMA%c Transfer of %d bytes to %x (%02x %x %04x).\n",(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff); + + Cores[core].TSA &= 0xfffff; + + u32 buff1end = Cores[core].TSA + size; + u32 buff2end=0; + if( buff1end > 0x100000 ) + { + buff2end = buff1end - 0x100000; + buff1end = 0x100000; + } + + const int cacheIdxStart = Cores[core].TSA / pcm_WordsPerBlock; + const int cacheIdxEnd = (buff1end+pcm_WordsPerBlock-1) / pcm_WordsPerBlock; + PcmCacheEntry* cacheLine = &pcm_cache_data[cacheIdxStart]; + PcmCacheEntry& cacheEnd = pcm_cache_data[cacheIdxEnd]; + + do + { + cacheLine->Validated = false; + cacheLine++; + } while ( cacheLine != &cacheEnd ); + +#if 0 + // Pcm Cache Invalidation! + // It's a requirement that we mask bits for the blocks that are written to *only*, + // because doing anything else can cause the cache to fail, thanks to the progressive + // nature of the SPU2's ADPCM encoding. (the same thing that makes it impossible + // to use SSE optimizations on it). + + u8* cache = (u8*)pcm_cache_flags; + + // Step 1: Clear bits in the front remainder. + + const int pcmTSA = Cores[core].TSA / pcm_WordsPerBlock; + const int pcmTDA = buff1end / pcm_WordsPerBlock; + const int remFront = pcmTSA & 31; + const int remBack = ((buff1end+pcm_WordsPerBlock-1)/pcm_WordsPerBlock) & 31; // round up to get the end remainder + + int flagTSA = pcmTSA / 32; + + if( remFront ) + { + // need to clear some upper bits of this u32 + uint mask = (1ul< 0 ) + { + // second branch needs copied: + // It starts at the beginning of memory and moves forward to buff2end + + // endpoint cache should be irrelevant, since it's almost certainly dynamic + // memory below 0x2800 (registers and such) + //const u32 endpt2 = (buff2end + roundUp) / indexer_scalar; + //memset( pcm_cache_flags, 0, endpt2 ); + + memcpy( GetMemPtr( 0 ), &pMem[buff1size], buff2end*2 ); + + Cores[core].TDA = (buff2end+1) & 0xfffff; + + if(Cores[core].IRQEnable) + { + // Flag interrupt? + // If IRQA occurs between start and dest, flag it. + // Since the buffer wraps, the conditional might seem odd, but it works. + + if( ( Cores[core].IRQA >= Cores[core].TSA ) || + ( Cores[core].IRQA <= Cores[core].TDA ) ) + { + Spdif.Info=4<= Cores[core].TSA ) && + ( Cores[core].IRQA <= Cores[core].TDA ) ) + { + Spdif.Info=4< 0x100000 ) + { + buff2end = buff1end - 0x100000; + buff1end = 0x100000; + } + + const u32 buff1size = (buff1end-Cores[core].TSA); + memcpy( pMem, GetMemPtr( Cores[core].TSA ), buff1size*2 ); + + if( buff2end > 0 ) + { + // second branch needs cleared: + // It starts at the beginning of memory and moves forward to buff2end + + memcpy( &pMem[buff1size], GetMemPtr( 0 ), buff2end*2 ); + + Cores[core].TDA = (buff2end+0x20) & 0xfffff; + + for( int i=0; i<2; i++ ) + { + if(Cores[i].IRQEnable) + { + // Flag interrupt? + // If IRQA occurs between start and dest, flag it. + // Since the buffer wraps, the conditional might seem odd, but it works. + + if( ( Cores[i].IRQA >= Cores[core].TSA ) || + ( Cores[i].IRQA <= Cores[core].TDA ) ) + { + Spdif.Info=4<= Cores[i].TSA ) && + ( Cores[i].IRQA <= Cores[i].TDA+0x1f ) ) + { + Spdif.Info=4< -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -#ifndef DMA_H_INCLUDED -#define DMA_H_INCLUDED - -void DMALogOpen(); -void DMA4LogWrite(void *lpData, u32 ulSize); -void DMA7LogWrite(void *lpData, u32 ulSize); -void DMALogClose(); - -extern void DmaWrite(u32 core, u16 data); -extern u16 DmaRead(u32 core); - -extern void AutoDMAReadBuffer(int core, int mode); - +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#ifndef DMA_H_INCLUDED +#define DMA_H_INCLUDED + +void DMALogOpen(); +void DMA4LogWrite(void *lpData, u32 ulSize); +void DMA7LogWrite(void *lpData, u32 ulSize); +void DMALogClose(); + +extern void DmaWrite(u32 core, u16 data); +extern u16 DmaRead(u32 core); + +extern void AutoDMAReadBuffer(int core, int mode); + #endif // DMA_H_INCLUDED // \ No newline at end of file diff --git a/plugins/spu2ghz/src/interface.cpp b/plugins/spu2ghz/src/interface.cpp new file mode 100644 index 0000000000..852d3fab62 --- /dev/null +++ b/plugins/spu2ghz/src/interface.cpp @@ -0,0 +1,760 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#include "spu2.h" +#include "regtable.h" + +#include "svnrev.h" + +// [Air]: Adding the spu2init boolean wasn't necessary except to help me in +// debugging the spu2 suspend/resume behavior (when user hits escape). +static bool spu2open=false; // has spu2open plugin interface been called? +static bool spu2init=false; // has spu2init plugin interface been called? + +static s32 logvolume[16384]; +static u32 pClocks=0; + + +static const u8 version = PS2E_SPU2_VERSION; +static const u8 revision = 1; +static const u8 build = 9; // increase that with each version + +static char libraryName[256]; + +BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD dwReason,LPVOID lpvReserved) +{ + if(dwReason==DLL_PROCESS_ATTACH) hInstance=hinstDLL; + return TRUE; +} + +static void InitLibraryName() +{ +#ifdef PUBLIC + + // Public Release! + // Output a simplified string that's just our name: + + strcpy( libraryName, "SPU2ghz" ); + +#elif defined( SVN_REV_UNKNOWN ) + + // Unknown revision. + // Output a name that includes devbuild status but not + // subversion revision tags: + + strcpy( libraryName, "SPU2ghz" +# ifdef _DEBUG_FAST + "-Debug" +# elif defined( DEBUG ) + "-Debug/Strict" // strict debugging is slow! +# else + "-Dev" +# endif + ); +#else + + // Use TortoiseSVN's SubWCRev utility's output + // to label the specific revision: + + sprintf_s( libraryName, "SPU2ghz r%d%s" +# ifdef _DEBUG_FAST + "-Debug" +# elif defined( _DEBUG ) + "-Debug/Strict" // strict debugging is slow! +# else + "-Dev" +# endif + ,SVN_REV, + SVN_MODS ? "m" : "" + ); +#endif + +} + +EXPORT_C_(u32) PS2EgetLibType() +{ + return PS2E_LT_SPU2; +} + +EXPORT_C_(char*) PS2EgetLibName() +{ + InitLibraryName(); + return libraryName; +} + +EXPORT_C_(u32) PS2EgetLibVersion2(u32 type) +{ + return (version<<16)|(revision<<8)|build; +} + +EXPORT_C_(void) SPU2configure() { + configure(); +} + +EXPORT_C_(void) SPU2about() { + InitLibraryName(); + SysMessage( libraryName ); +} + +EXPORT_C_(s32) SPU2test() { + return SndTest(); +} + +EXPORT_C_(s32) SPU2init() +{ +#define MAKESURE(a,b) \ + /*fprintf(stderr,"%08p: %08p == %08p\n",&(regtable[a>>1]),regtable[a>>1],U16P(b));*/ \ + assert(regtable[(a)>>1]==U16P(b)) + + MAKESURE(0x800,zero); + + s32 c=0,v=0; + ReadSettings(); + +#ifdef SPU2_LOG + if(AccessLog()) + { + spu2Log = fopen(AccessLogFileName, "w"); + setvbuf(spu2Log, NULL, _IONBF, 0); + FileLog("SPU2init\n"); + } +#endif + srand((unsigned)time(NULL)); + + disableFreezes=false; + + if (spu2init) + { + ConLog( " * SPU2: Already initialized - Ignoring SPU2init signal." ); + return 0; + } + + spu2init=true; + + spu2regs = (short*)malloc(0x010000); + _spu2mem = (short*)malloc(0x200000); + + // adpcm decoder cache: + // the cache data size is determined by taking the number of adpcm blocks + // (2MB / 16) and multiplying it by the decoded block size (28 samples). + // Thus: pcm_cache_data = 7,340,032 bytes (ouch!) + // Expanded: 16 bytes expands to 56 bytes [3.5:1 ratio] + // Resulting in 2MB * 3.5. + + pcm_cache_data = (PcmCacheEntry*)calloc( pcm_BlockCount, sizeof(PcmCacheEntry) ); + + if( (spu2regs == NULL) || (_spu2mem == NULL) || + (pcm_cache_data == NULL) ) + { + SysMessage("SPU2: Error allocating Memory\n"); return -1; + } + + for(int mem=0;mem<0x800;mem++) + { + u16 *ptr=regtable[mem>>1]; + if(!ptr) { + regtable[mem>>1] = &(spu2Ru16(mem)); + } + } + + memset(spu2regs,0,0x010000); + memset(_spu2mem,0,0x200000); + memset(&Cores,0,(sizeof(V_Core) * 2)); + CoreReset(0); + CoreReset(1); + + DMALogOpen(); + + if(WaveLog()) + { + if(!wavedump_open()) + { + SysMessage("Can't open '%s'.\nWave Log disabled.",WaveLogFileName); + } + } + + for(v=0;v<16384;v++) + { + logvolume[v]=(s32)(s32)floor(log((double)(v+1))*3376.7); + } + + LowPassFilterInit(); + InitADSR(); + +#ifdef STREAM_DUMP + il0=fopen("logs/spu2input0.pcm","wb"); + il1=fopen("logs/spu2input1.pcm","wb"); +#endif + +#ifdef EFFECTS_DUMP + el0=fopen("logs/spu2fx0.pcm","wb"); + el1=fopen("logs/spu2fx1.pcm","wb"); +#endif + + +#ifdef S2R_ENABLE + if(!replay_mode) + s2r_open("replay_dump.s2r"); +#endif + return 0; +} + +EXPORT_C_(s32) SPU2open(void *pDsp) +{ + if( spu2open ) return 0; + + FileLog("[%10d] SPU2 Open\n",Cycles); + + /* + if(debugDialogOpen==0) + { + hDebugDialog = CreateDialogParam(hInstance,MAKEINTRESOURCE(IDD_DEBUG),0,DebugProc,0); + ShowWindow(hDebugDialog,SW_SHOWNORMAL); + debugDialogOpen=1; + }*/ + + spu2open=true; + if (!SndInit()) + { + srate_pv=(double)SampleRate/48000.0; + + spdif_init(); + + DspLoadLibrary(dspPlugin,dspPluginModule); + + return 0; + } + else + { + SPU2close(); + return -1; + }; +} + +EXPORT_C_(void) SPU2close() +{ + if( !spu2open ) return; + FileLog("[%10d] SPU2 Close\n",Cycles); + + DspCloseLibrary(); + spdif_shutdown(); + SndClose(); + + spu2open = false; +} + +EXPORT_C_(void) SPU2shutdown() +{ + if(!spu2init) return; + + ConLog( " * SPU2: Shutting down.\n" ); + + SPU2close(); + +#ifdef S2R_ENABLE + if(!replay_mode) + s2r_close(); +#endif + + DoFullDump(); +#ifdef STREAM_DUMP + fclose(il0); + fclose(il1); +#endif +#ifdef EFFECTS_DUMP + fclose(el0); + fclose(el1); +#endif + if(WaveLog() && wavedump_ok) wavedump_close(); + + DMALogClose(); + + spu2init = false; + + SAFE_FREE(spu2regs); + SAFE_FREE(_spu2mem); + + SAFE_FREE( pcm_cache_data ); + + spu2regs = NULL; + _spu2mem = NULL; + pcm_cache_data = NULL; + +#ifdef SPU2_LOG + if(!AccessLog()) return; + FileLog("[%10d] SPU2shutdown\n",Cycles); + if(spu2Log) fclose(spu2Log); +#endif +} + +EXPORT_C_(void) SPU2setClockPtr(u32 *ptr) +{ + cPtr=ptr; + hasPtr=(cPtr!=NULL); +} + +bool numpad_minus_old=false; +bool numpad_minus = false; +bool numpad_plus = false, numpad_plus_old = false; + +EXPORT_C_(void) SPU2async(u32 cycles) +{ +#ifndef PUBLIC + u32 oldClocks = lClocks; + static u32 timer=0,time1=0,time2=0; + timer++; + if (timer == 1){ + time1=timeGetTime(); + } + if (timer == 3000){ + time2 = timeGetTime()-time1 ; + timer=0; + } +#endif + + DspUpdate(); + + if(LimiterToggleEnabled) + { + numpad_minus = (GetAsyncKeyState(VK_SUBTRACT)&0x8000)!=0; + + if(numpad_minus && !numpad_minus_old) + { + if(LimitMode) LimitMode=0; + else LimitMode=1; + SndUpdateLimitMode(); + } + numpad_minus_old = numpad_minus; + } + +#ifndef PUBLIC + /*numpad_plus = (GetAsyncKeyState(VK_ADD)&0x8000)!=0; + if(numpad_plus && !numpad_plus_old) + { + DoFullDump(); + } + numpad_plus_old = numpad_plus;*/ +#endif + + if(hasPtr) + { + TimeUpdate(*cPtr); + } + else + { + pClocks+=cycles; + TimeUpdate(pClocks); + } +} + +EXPORT_C_(void) SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()) +{ + _irqcallback=SPU2callback; + dma4callback=DMA4callback; + dma7callback=DMA7callback; +} + +EXPORT_C_(u16) SPU2read(u32 rmem) +{ + // if(!replay_mode) + // s2r_readreg(Cycles,rmem); + + if(hasPtr) TimeUpdate(*cPtr); + + u16 ret=0xDEAD; u32 core=0, mem=rmem&0xFFFF, omem=mem; + if (mem & 0x400) { omem^=0x400; core=1; } + + if(rmem==0x1f9001AC) + { + ret = DmaRead(core); + } + else if (rmem>>16 == 0x1f80) + { + ret = SPU_ps1_read(rmem); + } + else if ((mem&0xFFFF)>=0x800) + { + ret=spu2Ru16(mem); + ConLog(" * SPU2: Read from reg>=0x800: %x value %x\n",mem,ret); + FileLog(" * SPU2: Read from reg>=0x800: %x value %x\n",mem,ret); + } + else + { + ret = *(regtable[(mem>>1)]); + + FileLog("[%10d] SPU2 read mem %x (core %d, register %x): %x\n",Cycles, mem, core, (omem & 0x7ff), ret); + } + + return ret; +} + +static __forceinline void SPU2_FastWrite( u32 rmem, u16 value ) +{ + u32 vx=0, vc=0, core=0, omem, mem; + omem=mem=rmem & 0x7FF; //FFFF; + if (mem & 0x400) { omem^=0x400; core=1; } + + //else if ((omem >= 0x0000) && (omem < 0x0180)) { // Voice Params + if (omem < 0x0180) { // Voice Params + u32 voice=(omem & 0x1F0) >> 4; + u32 param=(omem & 0xF)>>1; + //FileLog("[%10d] SPU2 write mem %08x (Core %d Voice %d Param %s) value %x\n",Cycles,rmem,core,voice,ParamNames[param],value); + switch (param) { + case 0: //VOLL (Volume L) + if (value & 0x8000) { // +Lin/-Lin/+Exp/-Exp + Cores[core].Voices[voice].VolumeL.Mode=(value & 0xF000)>>12; + Cores[core].Voices[voice].VolumeL.Increment=(value & 0x3F); + } + else { + Cores[core].Voices[voice].VolumeL.Mode=0; + Cores[core].Voices[voice].VolumeL.Increment=0; + if(value&0x4000) + value=0x3fff - (value&0x3fff); + Cores[core].Voices[voice].VolumeL.Value=value<<1; + } + Cores[core].Voices[voice].VolumeL.Reg_VOL = value; break; + case 1: //VOLR (Volume R) + if (value & 0x8000) { + Cores[core].Voices[voice].VolumeR.Mode=(value & 0xF000)>>12; + Cores[core].Voices[voice].VolumeR.Increment=(value & 0x3F); + } + else { + Cores[core].Voices[voice].VolumeR.Mode=0; + Cores[core].Voices[voice].VolumeR.Increment=0; + Cores[core].Voices[voice].VolumeR.Value=value<<1; + } + Cores[core].Voices[voice].VolumeR.Reg_VOL = value; break; + case 2: Cores[core].Voices[voice].Pitch=value; break; + case 3: // ADSR1 (Envelope) + Cores[core].Voices[voice].ADSR.Am=(value & 0x8000)>>15; + Cores[core].Voices[voice].ADSR.Ar=(value & 0x7F00)>>8; + Cores[core].Voices[voice].ADSR.Dr=(value & 0xF0)>>4; + Cores[core].Voices[voice].ADSR.Sl=(value & 0xF); + Cores[core].Voices[voice].ADSR.Reg_ADSR1 = value; break; + case 4: // ADSR2 (Envelope) + Cores[core].Voices[voice].ADSR.Sm=(value & 0xE000)>>13; + Cores[core].Voices[voice].ADSR.Sr=(value & 0x1FC0)>>6; + Cores[core].Voices[voice].ADSR.Rm=(value & 0x20)>>5; + Cores[core].Voices[voice].ADSR.Rr=(value & 0x1F); + Cores[core].Voices[voice].ADSR.Reg_ADSR2 = value; break; + case 5: + // [Air] : Mysterious volume set code. Too bad none of my games ever use it. + // (as usual... ) + Cores[core].Voices[voice].ADSR.Value = value << 15; + ConLog( "* SPU2: Mysterious ADSR Volume Set to 0x%x", value ); + break; + case 6: Cores[core].Voices[voice].VolumeL.Value=value; break; + case 7: Cores[core].Voices[voice].VolumeR.Value=value; break; + + jNO_DEFAULT; + } + } + else if ((omem >= 0x01C0) && (omem < 0x02DE)) { + u32 voice =((omem-0x01C0) / 12); + u32 address =((omem-0x01C0) % 12)>>1; + //FileLog("[%10d] SPU2 write mem %08x (Core %d Voice %d Address %s) value %x\n",Cycles,rmem,core,voice,AddressNames[address],value); + + switch (address) { + case 0: Cores[core].Voices[voice].StartA=((value & 0x0F) << 16) | (Cores[core].Voices[voice].StartA & 0xFFF8); + #ifndef PUBLIC + DebugCores[core].Voices[voice].lastSetStartA = Cores[core].Voices[voice].StartA; + #endif + break; + case 1: Cores[core].Voices[voice].StartA=(Cores[core].Voices[voice].StartA & 0x0F0000) | (value & 0xFFF8); + #ifndef PUBLIC + DebugCores[core].Voices[voice].lastSetStartA = Cores[core].Voices[voice].StartA; + #endif + //if(core==1) printf(" *** StartA for C%dV%02d set to 0x%05x\n",core,voice,Cores[core].Voices[voice].StartA); + break; + case 2: Cores[core].Voices[voice].LoopStartA=((value & 0x0F) << 16) | (Cores[core].Voices[voice].LoopStartA & 0xFFF8); + Cores[core].Voices[voice].LoopMode=3; break; + case 3: Cores[core].Voices[voice].LoopStartA=(Cores[core].Voices[voice].LoopStartA & 0x0F0000) | (value & 0xFFF8);break; + Cores[core].Voices[voice].LoopMode=3; break; + case 4: Cores[core].Voices[voice].NextA=((value & 0x0F) << 16) | (Cores[core].Voices[voice].NextA & 0xFFF8); + //printf(" *** Warning: C%dV%02d NextA MODIFIED EXTERNALLY!\n",core,voice); + break; + case 5: Cores[core].Voices[voice].NextA=(Cores[core].Voices[voice].NextA & 0x0F0000) | (value & 0xFFF8); + //printf(" *** Warning: C%dV%02d NextA MODIFIED EXTERNALLY!\n",core,voice); + break; + } + } + else + switch(omem) { + case REG_C_ATTR: + RegLog(4,"ATTR",rmem,core,value); + { + int irqe=Cores[core].IRQEnable; + int bit0=Cores[core].AttrBit0; + int bit4=Cores[core].AttrBit4; + + if(((value>>15)&1)&&(!Cores[core].CoreEnabled)&&(Cores[core].InitDelay==0)) // on init/reset + { + if(hasPtr) + { + Cores[core].InitDelay=1; + Cores[core].Regs.STATX=0; + } + else + { + CoreReset(core); + } + } + + Cores[core].AttrBit0 =(value>> 0) & 0x01; //1 bit + Cores[core].DMABits =(value>> 1) & 0x07; //3 bits + Cores[core].AttrBit4 =(value>> 4) & 0x01; //1 bit + Cores[core].AttrBit5 =(value>> 5) & 0x01; //1 bit + Cores[core].IRQEnable =(value>> 6) & 0x01; //1 bit + Cores[core].FxEnable =(value>> 7) & 0x01; //1 bit + Cores[core].NoiseClk =(value>> 8) & 0x3f; //6 bits + //Cores[core].Mute =(value>>14) & 0x01; //1 bit + Cores[core].Mute=0; + Cores[core].CoreEnabled=(value>>15) & 0x01; //1 bit + Cores[core].Regs.ATTR =value&0x7fff; + + if(value&0x000E) + { + ConLog(" * SPU2: Core %d ATTR unknown bits SET! value=%04x\n",core,value); + } + + if(Cores[core].AttrBit0!=bit0) + { + ConLog(" * SPU2: ATTR bit 0 set to %d\n",Cores[core].AttrBit0); + } + if(Cores[core].IRQEnable!=irqe) + { + ConLog(" * SPU2: IRQ %s\n",((Cores[core].IRQEnable==0)?"disabled":"enabled")); + if(!Cores[core].IRQEnable) + Spdif.Info=0; + } + + } + break; + case REG_S_PMON: + RegLog(1,"PMON0",rmem,core,value); + vx=2; for (vc=1;vc<16;vc++) { Cores[core].Voices[vc].Modulated=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.PMON = (Cores[core].Regs.PMON & 0xFFFF0000) | value; + break; + case (REG_S_PMON + 2): + RegLog(1,"PMON1",rmem,core,value); + vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].Modulated=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.PMON = (Cores[core].Regs.PMON & 0xFFFF) | (value << 16); + break; + case REG_S_NON: + RegLog(1,"NON0",rmem,core,value); + vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].Noise=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.NON = (Cores[core].Regs.NON & 0xFFFF0000) | value; + break; + case (REG_S_NON + 2): + RegLog(1,"NON1",rmem,core,value); + vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].Noise=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.NON = (Cores[core].Regs.NON & 0xFFFF) | (value << 16); + break; + case REG_S_VMIXL: + RegLog(1,"VMIXL0",rmem,core,value); + vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].DryL=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXL = (Cores[core].Regs.VMIXL & 0xFFFF0000) | value; + case (REG_S_VMIXL + 2): + RegLog(1,"VMIXL1",rmem,core,value); + vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].DryL=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXL = (Cores[core].Regs.VMIXL & 0xFFFF) | (value << 16); + case REG_S_VMIXEL: + RegLog(1,"VMIXEL0",rmem,core,value); + vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].WetL=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXEL = (Cores[core].Regs.VMIXEL & 0xFFFF0000) | value; + break; + case (REG_S_VMIXEL + 2): + RegLog(1,"VMIXEL1",rmem,core,value); + vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].WetL=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXEL = (Cores[core].Regs.VMIXEL & 0xFFFF) | (value << 16); + break; + case REG_S_VMIXR: + RegLog(1,"VMIXR0",rmem,core,value); + vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].DryR=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXR = (Cores[core].Regs.VMIXR & 0xFFFF0000) | value; + break; + case (REG_S_VMIXR + 2): + RegLog(1,"VMIXR1",rmem,core,value); + vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].DryR=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXR = (Cores[core].Regs.VMIXR & 0xFFFF) | (value << 16); + break; + case REG_S_VMIXER: + RegLog(1,"VMIXER0",rmem,core,value); + vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].WetR=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXER = (Cores[core].Regs.VMIXER & 0xFFFF0000) | value; + break; + case (REG_S_VMIXER + 2): + RegLog(1,"VMIXER1",rmem,core,value); + vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].WetR=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXER = (Cores[core].Regs.VMIXER & 0xFFFF) | (value << 16); + break; + case REG_P_MMIX: + RegLog(1,"MMIX",rmem,core,value); + vx=value; + if (core == 0) vx&=0xFF0; + Cores[core].ExtWetR=(vx & 0x001); + Cores[core].ExtWetL=(vx & 0x002)>>1; + Cores[core].ExtDryR=(vx & 0x004)>>2; + Cores[core].ExtDryL=(vx & 0x008)>>3; + Cores[core].InpWetR=(vx & 0x010)>>4; + Cores[core].InpWetL=(vx & 0x020)>>5; + Cores[core].InpDryR=(vx & 0x040)>>6; + Cores[core].InpDryL=(vx & 0x080)>>7; + Cores[core].SndWetR=(vx & 0x100)>>8; + Cores[core].SndWetL=(vx & 0x200)>>9; + Cores[core].SndDryR=(vx & 0x400)>>10; + Cores[core].SndDryL=(vx & 0x800)>>11; + Cores[core].Regs.MMIX = value; + break; + case (REG_S_KON + 2): + RegLog(2,"KON1",rmem,core,value); + StartVoices(core,((u32)value)<<16); + break; + case REG_S_KON: + RegLog(2,"KON0",rmem,core,value); + StartVoices(core,((u32)value)); + break; + case (REG_S_KOFF + 2): + RegLog(2,"KOFF1",rmem,core,value); + StopVoices(core,((u32)value)<<16); + break; + case REG_S_KOFF: + RegLog(2,"KOFF0",rmem,core,value); + StopVoices(core,((u32)value)); + break; + case REG_S_ENDX: + //ConLog(" * SPU2: Core %d ENDX cleared!\n",core); + RegLog(2,"ENDX0",rmem,core,value); + Cores[core].Regs.ENDX&=0x00FF0000; break; + case (REG_S_ENDX + 2): + //ConLog(" * SPU2: Core %d ENDX cleared!\n",core); + RegLog(2,"ENDX1",rmem,core,value); + Cores[core].Regs.ENDX&=0xFFFF; break; + case REG_P_MVOLL: + RegLog(1,"MVOLL",rmem,core,value); + if (value & 0x8000) { // +Lin/-Lin/+Exp/-Exp + Cores[core].MasterL.Mode=(value & 0xE000)/0x2000; + Cores[core].MasterL.Increment=(value & 0x3F) | ((value & 0x800)/0x10); + } + else { + Cores[core].MasterL.Mode=0; + Cores[core].MasterL.Increment=0; + Cores[core].MasterL.Value=value; + } + Cores[core].MasterL.Reg_VOL=value; + break; + case REG_P_MVOLR: + RegLog(1,"MVOLR",rmem,core,value); + if (value & 0x8000) { // +Lin/-Lin/+Exp/-Exp + Cores[core].MasterR.Mode=(value & 0xE000)/0x2000; + Cores[core].MasterR.Increment=(value & 0x3F) | ((value & 0x800)/0x10); + } + else { + Cores[core].MasterR.Mode=0; + Cores[core].MasterR.Increment=0; + Cores[core].MasterR.Value=value; + } + Cores[core].MasterR.Reg_VOL=value; + break; + case REG_S_ADMAS: + RegLog(3,"ADMAS",rmem,core,value); + //ConLog(" * SPU2: Core %d AutoDMAControl set to %d (%d)\n",core,value, Cycles); + Cores[core].AutoDMACtrl=value; + + if(value==0) + { + Cores[core].AdmaInProgress=0; + } + break; + + default: + *(regtable[mem>>1])=value; + break; + } + + SPU2writeLog(mem,value); + if ((mem>=0x07C0) && (mem<0x07CE)) + { + UpdateSpdifMode(); + } +} + +EXPORT_C_(void) SPU2write(u32 rmem, u16 value) +{ +#ifdef S2R_ENABLE + if(!replay_mode) + s2r_writereg(Cycles,rmem,value); +#endif + + if(rmem==0x1f9001ac) + { + //RegWriteLog(0,value); + if((Cores[0].IRQEnable)&&(Cores[0].TSA==Cores[0].IRQA)) + { + Spdif.Info=4; + SetIrqCall(); + } + spu2M_Write( Cores[0].TSA++, value ); + Cores[0].TSA&=0xfffff; + } + else if(rmem==0x1f9005ac) + { + //RegWriteLog(1,value); + if((Cores[0].IRQEnable)&&(Cores[0].TSA==Cores[0].IRQA)) + { + Spdif.Info=4; + SetIrqCall(); + } + spu2M_Write( Cores[1].TSA++, value ); + Cores[1].TSA&=0xfffff; + } + else + { + if(hasPtr) TimeUpdate(*cPtr); + + if (rmem>>16 == 0x1f80) + SPU_ps1_write(rmem,value); + else + SPU2_FastWrite( rmem, value ); + } +} + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +EXPORT_C_(int) SPU2setupRecording(int start, void* pData) +{ + // Don't record if we have a bogus state. + if( disableFreezes ) return 0; + + if(start==0) + { + //stop recording + RecordStop(); + if(recording==0) + return 1; + } + else if(start==1) + { + //start recording + RecordStart(); + if(recording!=0) + return 1; + } + return 0; +} diff --git a/plugins/spu2ghz/src/lowpass.cpp b/plugins/spu2ghz/src/lowpass.cpp index 6ea46d3462..da26ee7388 100644 --- a/plugins/spu2ghz/src/lowpass.cpp +++ b/plugins/spu2ghz/src/lowpass.cpp @@ -1,67 +1,67 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -#include "lowpass.h" -#include -#include - -void LPF_init(LPF_data*lpf,double freq, double srate) -{ - double omega = 2*freq/srate; - double g = 1.0; - - // calculating coefficients: - - double k,p,q,a; - double a0,a1,a2,a3,a4; - - k=(4.0*g-3.0)/(g+1.0); - p=1.0-0.25*k;p*=p; - - // LP: - a=1.0/(tan(0.5*omega)*(1.0+p)); - p=1.0+a; - q=1.0-a; - - a0=1.0/(k+p*p*p*p); - a1=4.0*(k+p*p*p*q); - a2=6.0*(k+p*p*q*q); - a3=4.0*(k+p*q*q*q); - a4= (k+q*q*q*q); - p=a0*(k+1.0); - - lpf->coef[0]=p; - lpf->coef[1]=4.0*p; - lpf->coef[2]=6.0*p; - lpf->coef[3]=4.0*p; - lpf->coef[4]=p; - lpf->coef[5]=-a1*a0; - lpf->coef[6]=-a2*a0; - lpf->coef[7]=-a3*a0; - lpf->coef[8]=-a4*a0; -} -double LPF(LPF_data* lpf, double in) -{ -// per sample: - - double out=lpf->coef[0]*in+lpf->d[0]; - lpf->d[0] =lpf->coef[1]*in+lpf->coef[5]*out+lpf->d[1]; - lpf->d[1] =lpf->coef[2]*in+lpf->coef[6]*out+lpf->d[2]; - lpf->d[2] =lpf->coef[3]*in+lpf->coef[7]*out+lpf->d[3]; - lpf->d[3] =lpf->coef[4]*in+lpf->coef[8]*out; -return out; -} +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#include "lowpass.h" +#include +#include + +void LPF_init(LPF_data*lpf,double freq, double srate) +{ + double omega = 2*freq/srate; + double g = 1.0; + + // calculating coefficients: + + double k,p,q,a; + double a0,a1,a2,a3,a4; + + k=(4.0*g-3.0)/(g+1.0); + p=1.0-0.25*k;p*=p; + + // LP: + a=1.0/(tan(0.5*omega)*(1.0+p)); + p=1.0+a; + q=1.0-a; + + a0=1.0/(k+p*p*p*p); + a1=4.0*(k+p*p*p*q); + a2=6.0*(k+p*p*q*q); + a3=4.0*(k+p*q*q*q); + a4= (k+q*q*q*q); + p=a0*(k+1.0); + + lpf->coef[0]=p; + lpf->coef[1]=4.0*p; + lpf->coef[2]=6.0*p; + lpf->coef[3]=4.0*p; + lpf->coef[4]=p; + lpf->coef[5]=-a1*a0; + lpf->coef[6]=-a2*a0; + lpf->coef[7]=-a3*a0; + lpf->coef[8]=-a4*a0; +} +double LPF(LPF_data* lpf, double in) +{ +// per sample: + + double out=lpf->coef[0]*in+lpf->d[0]; + lpf->d[0] =lpf->coef[1]*in+lpf->coef[5]*out+lpf->d[1]; + lpf->d[1] =lpf->coef[2]*in+lpf->coef[6]*out+lpf->d[2]; + lpf->d[2] =lpf->coef[3]*in+lpf->coef[7]*out+lpf->d[3]; + lpf->d[3] =lpf->coef[4]*in+lpf->coef[8]*out; +return out; +} diff --git a/plugins/spu2ghz/src/lowpass.h b/plugins/spu2ghz/src/lowpass.h index c0f18c5431..5281f31548 100644 --- a/plugins/spu2ghz/src/lowpass.h +++ b/plugins/spu2ghz/src/lowpass.h @@ -1,27 +1,27 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -#pragma once - -typedef struct IIR_data -{ - double coef[9]; - double d[4]; -} LPF_data; - -void LPF_init(LPF_data*lpf,double freq, double srate); -double LPF(LPF_data* lpf, double in); +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#pragma once + +typedef struct IIR_data +{ + double coef[9]; + double d[4]; +} LPF_data; + +void LPF_init(LPF_data*lpf,double freq, double srate); +double LPF(LPF_data* lpf, double in); diff --git a/plugins/spu2ghz/src/mixer.cpp b/plugins/spu2ghz/src/mixer.cpp index 716b452872..2b52b41b4b 100644 --- a/plugins/spu2ghz/src/mixer.cpp +++ b/plugins/spu2ghz/src/mixer.cpp @@ -1,1448 +1,1446 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// - -// [Air] Notes -----> -// Adding 'static' to the __forceinline methods hints to the linker that it need not -// actually include procedural versions of the methods in the DLL. Under normal circumstances -// the compiler will still generate the procedures even though they are never used (the inline -// code is used instead). Using static reduced the size of my generated .DLL by a few KB. -// (doesn't really make anything faster, but eh... whatever :) -// -#include "spu2.h" - -#include -#include -#include -#include "lowpass.h" - -extern void spdif_update(); - -void ADMAOutLogWrite(void *lpData, u32 ulSize); - -extern void VoiceStop(int core,int vc); - -double pow_2_31 = pow(2.0,31.0); - -LPF_data L,R; - -extern u32 core; - -u32 core, voice; - -extern u8 callirq; - -double srate_pv=1.0; - -extern u32 PsxRates[160]; - -static const s32 ADSR_MAX_VOL = 0x7fffffff; - -// Performs a 64-bit multiplication between two values and returns the -// high 32 bits as a result (discarding the fractional 32 bits). -// The combined fracional bits of both inputs must be 32 bits for this -// to work properly. -// -// This is meant to be a drop-in replacement for times when the 'div' part -// of a MulDiv is a constant. (example: 1<<8, or 4096, etc) -// -// [Air] Performance breakdown: This is over 10 times faster than MulDiv in -// a *worst case* scenario. It's also more accurate since it forces the -// caller to extend the inputs so that they make use of all 32 bits of -// precision. -// -static s32 __forceinline MulShr32( s32 srcval, s32 mulval ) -{ - s64 tmp = ((s64)srcval * mulval ); - return ((s32*)&tmp)[1]; - - // Performance note: Using the temp var and memory reference - // actually ends up being roughly 2x faster than using a bitshift. - // It won't fly on big endian machines though... :) -} - -static s32 __forceinline MulShr32su( s32 srcval, u32 mulval ) -{ - s64 tmp = ((s64)srcval * (s32)mulval ); - return ((s32*)&tmp)[1]; -} - - -void InitADSR() // INIT ADSR -{ - for (int i=0; i<(32+128); i++) - { - int shift=(i-32)>>2; - s64 rate=(i&3)+4; - if (shift<0) - { - rate>>=-shift; - } else - { - rate<<=shift; - } - PsxRates[i]=(int)min(rate,0x3fffffff); - } -} - -#define VOL(x) (((s32)x)) //24.8 volume - -///////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// -// // - -const s32 f[5][2] ={{ 0, 0 }, - { 60, 0 }, - { 115, -52 }, - { 98, -55 }, - { 122, -60 }}; - -static void __forceinline XA_decode_block(s16* buffer, const s16* block, s32& prev1, s32& prev2) -{ - const s32 header = *block; - s32 shift = ((header>> 0)&0xF)+16; - s32 pred1 = f[(header>> 4)&0xF][0]; - s32 pred2 = f[(header>> 4)&0xF][1]; - - const s8* blockbytes = (s8*)&block[1]; - - for(int i=0; i<14; i++, blockbytes++) - { - s32 pcm, pcm2; - { - s32 data = ((*blockbytes)<<28) & 0xF0000000; - pcm = data>>shift; - pcm+=((pred1*prev1)+(pred2*prev2))>>6; - if(pcm> 32767) pcm= 32767; - else if(pcm<-32768) pcm=-32768; - *(buffer++) = pcm; - } - - //prev2=prev1; - //prev1=pcm; - - { - s32 data = ((*blockbytes)<<24) & 0xF0000000; - pcm2 = data>>shift; - pcm2+=((pred1*pcm)+(pred2*prev1))>>6; - if(pcm2> 32767) pcm2= 32767; - else if(pcm2<-32768) pcm2=-32768; - *(buffer++) = pcm2; - } - - prev2=pcm; - prev1=pcm2; - } -} - -static void __forceinline XA_decode_block_unsaturated(s16* buffer, const s16* block, s32& prev1, s32& prev2) -{ - const s32 header = *block; - s32 shift = ((header>> 0)&0xF)+16; - s32 pred1 = f[(header>> 4)&0xF][0]; - s32 pred2 = f[(header>> 4)&0xF][1]; - - const s8* blockbytes = (s8*)&block[1]; - - for(int i=0; i<14; i++, blockbytes++) - { - s32 pcm, pcm2; - { - s32 data = ((*blockbytes)<<28) & 0xF0000000; - pcm = data>>shift; - pcm+=((pred1*prev1)+(pred2*prev2))>>6; - // [Air] : Fast method, no saturation is performed. - *(buffer++) = pcm; - } - - { - s32 data = ((*blockbytes)<<24) & 0xF0000000; - pcm2 = data>>shift; - pcm2+=((pred1*pcm)+(pred2*prev1))>>6; - // [Air] : Fast method, no saturation is performed. - *(buffer++) = pcm2; - } - - prev2=pcm; - prev1=pcm2; - } -} - -static void __forceinline IncrementNextA( const V_Core& thiscore, V_Voice& vc ) -{ - // Important! Both cores signal IRQ when an address is read, regardless of - // which core actually reads the address. - - for( int i=0; i<2; i++ ) - { - if( Cores[i].IRQEnable && (vc.NextA==Cores[i].IRQA ) ) - { - #ifndef PUBLIC - ConLog(" * SPU2 Core %d: IRQ Called (IRQ passed).\n", i); - #endif - Spdif.Info=4<> 8; // grab loop flags from the upper byte. - - const int cacheIdx = vc.NextA / pcm_WordsPerBlock; - PcmCacheEntry& cacheLine = pcm_cache_data[cacheIdx]; - vc.SBuffer = cacheLine.Sampledata; - - if( cacheLine.Validated ) - { - // Cached block! Read from the cache directly. - // Make sure to propagate the prev1/prev2 ADPCM: - - vc.Prev1 = vc.SBuffer[27]; - vc.Prev2 = vc.SBuffer[26]; - - //ConLog( " * SPU2 : Cache Hit! NextA=0x%x, cacheIdx=0x%x\n", vc.NextA, cacheIdx ); - - #ifndef PUBLIC - g_counter_cache_hits++; - #endif - } - else - { - // Only flag the cache if it's a non-dynamic memory range. - if( vc.NextA >= SPU2_DYN_MEMLINE ) - cacheLine.Validated = true; - - #ifndef PUBLIC - if( vc.NextA < SPU2_DYN_MEMLINE ) - g_counter_cache_ignores++; - else - g_counter_cache_misses++; - #endif - - s16* sbuffer = cacheLine.Sampledata; - - // saturated decoder - XA_decode_block( sbuffer, memptr, vc.Prev1, vc.Prev2 ); - - // [Air]: Testing use of a new unsaturated decoder. (benchmark needed) - // Chances are the saturation isn't needed, but for a very few exception games. - // This is definitely faster than the above version, but is it by enough to - // merit possible lower compatibility? Especially now that games that make - // heavy use of the SPU2 via music or sfx will mostly use the cache anyway. - - //XA_decode_block_unsaturated( vc.SBuffer, memptr, vc.Prev1, vc.Prev2 ); - } - - vc.SCurrent = 0; - if( (vc.LoopFlags & XAFLAG_LOOP_START) && !vc.LoopMode ) - vc.LoopStartA = vc.NextA; - - // [Air] : Increment will get called below (change made to avoid needless code cache clutter) - //IncrementNextA( thiscore, vc ); - } - - IncrementNextA( thiscore, vc ); - -_skipIncrement: - Data = vc.SBuffer[vc.SCurrent++]; -} - -///////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// -// // - -const int InvExpOffsets[] = { 0,4,6,8,9,10,11,12 }; - -static void __forceinline CalculateADSR( V_Voice& vc ) -{ - V_ADSR& env(vc.ADSR); - - jASSUME( env.Phase != 0 ); - - s32 SLevel = ((s32)env.Sl)<<27; - - jASSUME( SLevel >= 0 ); - - if(env.Releasing) - { - if( env.Phase < 5) - { - env.Phase=5; - } - } - - switch (env.Phase) - { - case 1: // attack - if( env.Value == ADSR_MAX_VOL ) - { - // Already maxed out. Progress phase and nothing more: - env.Phase++; - break; - } - - if (env.Am) // pseudo exponential - { - if (env.Value<0x60000000) // below 75% - { - env.Value+=PsxRates[(env.Ar^0x7f)-0x10+32]; - } - else // above 75% - { - env.Value+=PsxRates[(env.Ar^0x7f)-0x18+32]; - } - } - else // linear - { - env.Value+=PsxRates[(env.Ar^0x7f)-0x10+32]; - } - - if( env.Value < 0 ) - { - // We hit the ceiling. - env.Phase++; - env.Value = ADSR_MAX_VOL; - } - - break; - - case 2: // decay - { - u32 off = InvExpOffsets[(env.Value>>28)&7]; - env.Value-=PsxRates[((env.Dr^0x1f)<<2)-0x18+off+32]; - - if(env.Value <= SLevel) - { - // Clamp decay to SLevel or Zero - if (env.Value < 0) - env.Value = 0; - else - env.Value = SLevel; - - env.Phase++; - } - - break; - } - - case 3: // sustain - if (env.Sm&2) // decreasing - { - if (env.Sm&4) // exponential - { - u32 off = InvExpOffsets[(env.Value>>28)&7]; - env.Value-=PsxRates[(env.Sr^0x7f)-0x1b+off+32]; - } - else // linear - { - env.Value-=PsxRates[(env.Sr^0x7f)-0xf+32]; - } - if( env.Value <= 0 ) - { - env.Value = 0; - env.Phase++; - } - } - else // increasing - { - if (env.Sm&4) // pseudo exponential - { - if (env.Value<0x60000000) // below 75% - { - env.Value+=PsxRates[(env.Sr^0x7f)-0x10+32]; - } - else // above 75% - { - env.Value+=PsxRates[(env.Sr^0x7f)-0x18+32]; - } - } - else - { - // linear - - env.Value+=PsxRates[(env.Sr^0x7f)-0x10+32]; - } - - if( env.Value < 0 ) - { - env.Value = ADSR_MAX_VOL; - env.Phase++; - } - } - - break; - - case 4: // sustain end - env.Value = (env.Sm&2) ? 0 : ADSR_MAX_VOL; - if(env.Value==0) - env.Phase=6; - break; - - case 5: // release - - if (env.Rm) // exponential - { - u32 off=InvExpOffsets[(env.Value>>28)&7]; - env.Value-=PsxRates[((env.Rr^0x1f)<<2)-0x18+off+32]; - } - else // linear - { - env.Value-=PsxRates[((env.Rr^0x1f)<<2)-0xc+32]; - } - - if( env.Value <= 0 ) - { - env.Value=0; - env.Phase++; - } - - break; - - case 6: // release end - env.Value=0; - break; - - jNO_DEFAULT - } - - if (env.Phase==6) { - #ifndef PUBLIC - if(MsgVoiceOff()) ConLog(" * SPU2: Voice Off by ADSR: %d \n", voice); - DebugCores[core].Voices[voice].lastStopReason = 2; - #endif - VoiceStop(core,voice); - Cores[core].Regs.ENDX|=(1<> 7; // >> 6 is more correct, but causes a few overflows -} - -static void __forceinline UpdatePitch( V_Voice& vc ) -{ - s32 pitch; - - // [Air] : re-ordered comparisons: Modulated is much more likely to be zero than voice, - // and so the way it was before it's have to check both voice and modulated values - // most of the time. Now it'll just check Modulated and short-circuit past the voice - // check (not that it amounts to much, but eh every little bit helps). - if( (vc.Modulated==0) || (voice==0) ) - pitch=vc.Pitch; - else - pitch=(vc.Pitch*(32768 + abs(Cores[core].Voices[voice-1].OutX)))>>15; - - vc.SP+=pitch; -} - -static void __forceinline GetVoiceValues_Linear(V_Core& thiscore, V_Voice& vc, s32& Value) -{ - while( vc.SP > 0 ) - { - vc.PV2=vc.PV1; - - GetNextDataBuffered( thiscore, vc, vc.PV1 ); - - vc.SP-=4096; - } - - if( vc.ADSR.Phase==0 ) - { - Value = 0; - return; - } - - CalculateADSR( vc ); - - jASSUME( vc.ADSR.Value >= 0 ); // ADSR should never be negative... - - if(Interpolation==0) - { - Value = MulShr32( vc.PV1, vc.ADSR.Value ); - } - else //if(Interpolation==1) //must be linear - { - s32 t0 = vc.PV2 - vc.PV1; - s32 t1 = vc.PV1; - Value = MulShr32( t1 - ((t0*vc.SP)>>12), vc.ADSR.Value ); - } -} - - -static void __forceinline GetVoiceValues_Cubic(V_Core& thiscore, V_Voice& vc, s32& Value) -{ - while( vc.SP > 0 ) - { - vc.PV4=vc.PV3; - vc.PV3=vc.PV2; - vc.PV2=vc.PV1; - - GetNextDataBuffered( thiscore, vc, vc.PV1 ); - vc.PV1<<=3; - vc.SPc = vc.SP&4095; // just the fractional part, please! - vc.SP-=4096; - } - - if( vc.ADSR.Phase==0 ) - { - Value = 0; - return; - } - - CalculateADSR( vc ); - - jASSUME( vc.ADSR.Value >= 0 ); // ADSR should never be negative... - - s32 z0 = vc.PV3 - vc.PV4 + vc.PV1 - vc.PV2; - s32 z1 = (vc.PV4 - vc.PV3 - z0); - s32 z2 = (vc.PV2 - vc.PV4); - - s32 mu = vc.SPc; - - s32 val = (z0 * mu) >> 12; - val = ((val + z1) * mu) >> 12; - val = ((val + z2) * mu) >> 12; - val += vc.PV2; - - Value = MulShr32( val, vc.ADSR.Value>>3 ); -} - -// [Air]: Noise values need to be mixed without going through interpolation, since it -// can wreak havoc on the noise (causing muffling or popping). -static void __forceinline __fastcall GetNoiseValues(V_Core& thiscore, V_Voice& vc, s32& Data) -{ - while(vc.SP>=4096) - { - GetNoiseValues( Data ); - vc.SP-=4096; - } - - // GetNoiseValues can't set the phase zero on us unexpectedly - // like GetVoiceValues can. Better asster just in case though.. - jASSUME( vc.ADSR.Phase != 0 ); - - CalculateADSR( vc ); -} - -///////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// -// // - -void __fastcall ReadInput(V_Core& thiscore, s32& PDataL,s32& PDataR) -{ - if((thiscore.AutoDMACtrl&(core+1))==(core+1)) - { - s32 tl,tr; - - if((core==1)&&((PlayMode&8)==8)) - { - thiscore.InputPos&=~1; - - //CDDA mode -#ifdef PCM24_S1_INTERLEAVE - *PDataL=*(((s32*)(thiscore.ADMATempBuffer+(thiscore.InputPos<<1)))); - *PDataR=*(((s32*)(thiscore.ADMATempBuffer+(thiscore.InputPos<<1)+2))); -#else - s32 *pl=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos]); - s32 *pr=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos+0x200]); - PDataL=*pl; - PDataR=*pr; -#endif - - PDataL>>=4; //give 16.8 data - PDataR>>=4; - - thiscore.InputPos+=2; - if((thiscore.InputPos==0x100)||(thiscore.InputPos>=0x200)) { - thiscore.AdmaInProgress=0; - if(thiscore.InputDataLeft>=0x200) - { - u8 k=thiscore.InputDataLeft>=thiscore.InputDataProgress; - -#ifdef PCM24_S1_INTERLEAVE - AutoDMAReadBuffer(core,1); -#else - AutoDMAReadBuffer(core,0); -#endif - thiscore.AdmaInProgress=1; - - thiscore.TSA=(core<<10)+thiscore.InputPos; - - if (thiscore.InputDataLeft<0x200) - { - FileLog("[%10d] AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7'); - - #ifndef PUBLIC - if(thiscore.InputDataLeft>0) - { - if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n"); - } - #endif - thiscore.InputDataLeft=0; - thiscore.DMAICounter=1; - } - } - thiscore.InputPos&=0x1ff; - } - - } - else if((core==0)&&((PlayMode&4)==4)) - { - thiscore.InputPos&=~1; - - s32 *pl=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos]); - s32 *pr=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos+0x200]); - PDataL=*pl; - PDataR=*pr; - - thiscore.InputPos+=2; - if(thiscore.InputPos>=0x200) { - thiscore.AdmaInProgress=0; - if(thiscore.InputDataLeft>=0x200) - { - u8 k=thiscore.InputDataLeft>=thiscore.InputDataProgress; - - AutoDMAReadBuffer(core,0); - - thiscore.AdmaInProgress=1; - - thiscore.TSA=(core<<10)+thiscore.InputPos; - - if (thiscore.InputDataLeft<0x200) - { - FileLog("[%10d] Spdif AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7'); - - #ifndef PUBLIC - if(thiscore.InputDataLeft>0) - { - if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n"); - } - #endif - thiscore.InputDataLeft=0; - thiscore.DMAICounter=1; - } - } - thiscore.InputPos&=0x1ff; - } - - } - else - { - if((core==1)&&((PlayMode&2)!=0)) - { - tl=0; - tr=0; - } - else - { - // Using the temporary buffer because this area gets overwritten by some other code. - //*PDataL=(s32)*(s16*)(spu2mem+0x2000+(core<<10)+thiscore.InputPos); - //*PDataR=(s32)*(s16*)(spu2mem+0x2200+(core<<10)+thiscore.InputPos); - - tl=(s32)thiscore.ADMATempBuffer[thiscore.InputPos]; - tr=(s32)thiscore.ADMATempBuffer[thiscore.InputPos+0x200]; - - } - - PDataL=tl; - PDataR=tr; - - thiscore.InputPos++; - if((thiscore.InputPos==0x100)||(thiscore.InputPos>=0x200)) { - thiscore.AdmaInProgress=0; - if(thiscore.InputDataLeft>=0x200) - { - u8 k=thiscore.InputDataLeft>=thiscore.InputDataProgress; - - AutoDMAReadBuffer(core,0); - - thiscore.AdmaInProgress=1; - - thiscore.TSA=(core<<10)+thiscore.InputPos; - - if (thiscore.InputDataLeft<0x200) - { - thiscore.AutoDMACtrl |= ~3; - - #ifndef PUBLIC - FileLog("[%10d] AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7'); - if(thiscore.InputDataLeft>0) - { - if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n"); - } - #endif - thiscore.InputDataLeft=0; - thiscore.DMAICounter=1; - } - } - thiscore.InputPos&=0x1ff; - } - } - } - else { - PDataL=0; - PDataR=0; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// -// // - -static void __forceinline __fastcall ReadInputPV(V_Core& thiscore, s32& ValL,s32& ValR) -{ - s32 DL=0, DR=0; - - u32 pitch=AutoDMAPlayRate[core]; - - if(pitch==0) pitch=48000; - - thiscore.ADMAPV+=pitch; - while(thiscore.ADMAPV>=48000) - { - ReadInput(thiscore, DL,DR); - thiscore.ADMAPV-=48000; - thiscore.ADMAPL=DL; - thiscore.ADMAPR=DR; - } - - ValL=thiscore.ADMAPL; - ValR=thiscore.ADMAPR; - - #ifndef PUBLIC - s32 InputPeak = max(abs(ValL),abs(ValR)); - if(DebugCores[core].AutoDMAPeak>= 1; - //ValR >>= 1; - -} - -///////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// -// // - -#define VOLFLAG_REVERSE_PHASE (1ul<<0) -#define VOLFLAG_DECREMENT (1ul<<1) -#define VOLFLAG_EXPONENTIAL (1ul<<2) -#define VOLFLAG_SLIDE_ENABLE (1ul<<3) - -static void __fastcall UpdateVolume(V_Volume& Vol) -{ - // TIMINGS ARE FAKE!!! Need to investigate. - - // [Air]: Cleaned up this code... may have broken it. Can't really - // test it here since none of my games seem to use it. If anything's - // not sounding right, we should revert the code in this method first. - - // [Air] Reverse phasing? - // Invert our value so that exponential mathematics are applied - // as if the volume were sliding the other direction. This makes - // a lot more sense than the old method's likeliness to chop off - // sound volumes to zero abruptly. - - if(Vol.Mode & VOLFLAG_REVERSE_PHASE) - { - ConLog( " *** SPU2 > Reverse Phase in progress!\n" ); - Vol.Value = 0x7fff - Vol.Value; - } - - if (Vol.Mode & VOLFLAG_DECREMENT) - { - // Decrement - - if(Vol.Mode & VOLFLAG_EXPONENTIAL) - { - ConLog( " *** SPU2 > Exponential Volume Slide Down!\n" ); - Vol.Value *= Vol.Increment >> 7; - Vol.Value-=((32768*5)>>(Vol.Increment)); - } - else - { - Vol.Value-=Vol.Increment; - } - - if (Vol.Value<0) - { - Vol.Value = 0; - Vol.Mode=0; // disable slide - } - } - else - { - //ConLog( " *** SPU2 > Volflag > Increment!\n" ); - // Increment - if(Vol.Mode & VOLFLAG_EXPONENTIAL) - { - ConLog( " *** SPU2 > Exponential Volume Slide Up!\n" ); - int T = Vol.Increment>>(Vol.Value>>12); - Vol.Value+=T; - } - else - { - Vol.Value+=Vol.Increment; - } - - if( Vol.Value > 0x7fff ) - { - Vol.Value = 0x7fff; - Vol.Mode=0; // disable slide - } - } - - // Reverse phasing - // Invert the value back into output form: - if(Vol.Mode & VOLFLAG_REVERSE_PHASE) Vol.Value = 0x7fff-Vol.Value; - - //Vol.Value=NVal; -} - -///////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// -// // - -static s32 __forceinline clamp(s32 x) -{ - if (x>0x00ffffff) return 0x00ffffff; - if (x<0xff000000) return 0xff000000; - return x; -} - -///////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// -// // - -static void DoReverb( V_Core& thiscore, s32& OutL, s32& OutR, s32 InL, s32 InR) -{ - static s32 INPUT_SAMPLE_L,INPUT_SAMPLE_R; - static s32 OUTPUT_SAMPLE_L,OUTPUT_SAMPLE_R; - - if(!(thiscore.FxEnable&&EffectsEnabled)) - { - OUTPUT_SAMPLE_L=0; - OUTPUT_SAMPLE_R=0; - } - else if((Cycles&1)==0) - { - INPUT_SAMPLE_L=InL; - INPUT_SAMPLE_R=InR; - } - else - { -///////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// - s32 IIR_INPUT_A0,IIR_INPUT_A1,IIR_INPUT_B0,IIR_INPUT_B1; - s32 ACC0,ACC1; - s32 FB_A0,FB_A1,FB_B0,FB_B1; - s32 buffsize=thiscore.EffectsEndA-thiscore.EffectsStartA+1; - - if(buffsize<0) - { - buffsize = thiscore.EffectsEndA; - thiscore.EffectsEndA=thiscore.EffectsStartA; - thiscore.EffectsStartA=buffsize; - buffsize=thiscore.EffectsEndA-thiscore.EffectsStartA+1; - } - - //filter the 2 samples (prev then current) - LowPass(INPUT_SAMPLE_L, INPUT_SAMPLE_R); - LowPass(InL, InR); - - INPUT_SAMPLE_L=(INPUT_SAMPLE_L+InL)>>9; - INPUT_SAMPLE_R=(INPUT_SAMPLE_R+InR)>>9; - -#define BUFFER(x) ((s32)(*GetMemPtr(thiscore.EffectsStartA + ((thiscore.ReverbX + buffsize-((x)<<2))%buffsize)))) -#define SBUFFER(x) (*GetMemPtr(thiscore.EffectsStartA + ((thiscore.ReverbX + buffsize-((x)<<2))%buffsize))) - - thiscore.ReverbX=((thiscore.ReverbX + 4)%buffsize); - - IIR_INPUT_A0 = (BUFFER(thiscore.Revb.IIR_SRC_A0) * thiscore.Revb.IIR_COEF + INPUT_SAMPLE_L * thiscore.Revb.IN_COEF_L)>>16; - IIR_INPUT_A1 = (BUFFER(thiscore.Revb.IIR_SRC_A1) * thiscore.Revb.IIR_COEF + INPUT_SAMPLE_R * thiscore.Revb.IN_COEF_R)>>16; - IIR_INPUT_B0 = (BUFFER(thiscore.Revb.IIR_SRC_B0) * thiscore.Revb.IIR_COEF + INPUT_SAMPLE_L * thiscore.Revb.IN_COEF_L)>>16; - IIR_INPUT_B1 = (BUFFER(thiscore.Revb.IIR_SRC_B1) * thiscore.Revb.IIR_COEF + INPUT_SAMPLE_R * thiscore.Revb.IN_COEF_R)>>16; - - SBUFFER(thiscore.Revb.IIR_DEST_A0 + 4) = clamp((IIR_INPUT_A0 * thiscore.Revb.IIR_ALPHA + BUFFER(thiscore.Revb.IIR_DEST_A0) * (65535 - thiscore.Revb.IIR_ALPHA))>>16); - SBUFFER(thiscore.Revb.IIR_DEST_A1 + 4) = clamp((IIR_INPUT_A1 * thiscore.Revb.IIR_ALPHA + BUFFER(thiscore.Revb.IIR_DEST_A1) * (65535 - thiscore.Revb.IIR_ALPHA))>>16); - SBUFFER(thiscore.Revb.IIR_DEST_B0 + 4) = clamp((IIR_INPUT_B0 * thiscore.Revb.IIR_ALPHA + BUFFER(thiscore.Revb.IIR_DEST_B0) * (65535 - thiscore.Revb.IIR_ALPHA))>>16); - SBUFFER(thiscore.Revb.IIR_DEST_B1 + 4) = clamp((IIR_INPUT_B1 * thiscore.Revb.IIR_ALPHA + BUFFER(thiscore.Revb.IIR_DEST_B1) * (65535 - thiscore.Revb.IIR_ALPHA))>>16); - - ACC0 = (s32)(BUFFER(thiscore.Revb.ACC_SRC_A0) * thiscore.Revb.ACC_COEF_A + - BUFFER(thiscore.Revb.ACC_SRC_B0) * thiscore.Revb.ACC_COEF_B + - BUFFER(thiscore.Revb.ACC_SRC_C0) * thiscore.Revb.ACC_COEF_C + - BUFFER(thiscore.Revb.ACC_SRC_D0) * thiscore.Revb.ACC_COEF_D)>>16; - ACC1 = (s32)(BUFFER(thiscore.Revb.ACC_SRC_A1) * thiscore.Revb.ACC_COEF_A + - BUFFER(thiscore.Revb.ACC_SRC_B1) * thiscore.Revb.ACC_COEF_B + - BUFFER(thiscore.Revb.ACC_SRC_C1) * thiscore.Revb.ACC_COEF_C + - BUFFER(thiscore.Revb.ACC_SRC_D1) * thiscore.Revb.ACC_COEF_D)>>16; - - FB_A0 = BUFFER(thiscore.Revb.MIX_DEST_A0 - thiscore.Revb.FB_SRC_A); - FB_A1 = BUFFER(thiscore.Revb.MIX_DEST_A1 - thiscore.Revb.FB_SRC_A); - FB_B0 = BUFFER(thiscore.Revb.MIX_DEST_B0 - thiscore.Revb.FB_SRC_B); - FB_B1 = BUFFER(thiscore.Revb.MIX_DEST_B1 - thiscore.Revb.FB_SRC_B); - - SBUFFER(thiscore.Revb.MIX_DEST_A0) = clamp((ACC0 - FB_A0 * thiscore.Revb.FB_ALPHA)>>16); - SBUFFER(thiscore.Revb.MIX_DEST_A1) = clamp((ACC1 - FB_A1 * thiscore.Revb.FB_ALPHA)>>16); - SBUFFER(thiscore.Revb.MIX_DEST_B0) = clamp(((thiscore.Revb.FB_ALPHA * ACC0) - FB_A0 * (65535 - thiscore.Revb.FB_ALPHA) - FB_B0 * thiscore.Revb.FB_X)>>16); - SBUFFER(thiscore.Revb.MIX_DEST_B1) = clamp(((thiscore.Revb.FB_ALPHA * ACC1) - FB_A1 * (65535 - thiscore.Revb.FB_ALPHA) - FB_B1 * thiscore.Revb.FB_X)>>16); - - OUTPUT_SAMPLE_L=clamp((BUFFER(thiscore.Revb.MIX_DEST_A0)+BUFFER(thiscore.Revb.MIX_DEST_B0))>>2); - OUTPUT_SAMPLE_R=clamp((BUFFER(thiscore.Revb.MIX_DEST_B1)+BUFFER(thiscore.Revb.MIX_DEST_B1))>>2); - } - OutL=OUTPUT_SAMPLE_L; - OutR=OUTPUT_SAMPLE_R; -} - -///////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// -// // - -// writes a signed value to the SPU2 ram -// Performs no cache invalidation -- use only for dynamic memory ranges -// of the SPU2 (between 0x0000 and SPU2_DYN_MEMLINE) -static __forceinline void spu2M_WriteFast( u32 addr, s16 value ) -{ - // throw an assertion if the memory range is invalid: - jASSUME( addr < SPU2_DYN_MEMLINE ); - *GetMemPtr( addr ) = value; -} - - -static __forceinline void MixVoice( V_Core& thiscore, V_Voice& vc, s32& VValL, s32& VValR ) -{ - s32 Value=0; - - VValL=0; - VValR=0; - - // [Air] : Most games don't use much volume slide effects. So only - // call the UpdateVolume methods when needed by checking the flag - // outside the method here... - - if( vc.VolumeL.Mode & VOLFLAG_SLIDE_ENABLE ) UpdateVolume( vc.VolumeL ); - if( vc.VolumeR.Mode & VOLFLAG_SLIDE_ENABLE ) UpdateVolume( vc.VolumeR ); - - if (vc.ADSR.Phase>0) - { - UpdatePitch( vc ); - - if( vc.Noise ) - GetNoiseValues( thiscore, vc, Value ); - else - { - if( Interpolation == 2 ) - GetVoiceValues_Cubic( thiscore, vc, Value ); - else - GetVoiceValues_Linear( thiscore, vc, Value ); - } - - // Record the output (used for modulation effects) - vc.OutX = Value; - - #ifndef PUBLIC - DebugCores[core].Voices[voice].displayPeak = max(DebugCores[core].Voices[voice].displayPeak,abs(Value)); - #endif - - VValL=ApplyVolume(Value,(vc.VolumeL.Value)); - VValR=ApplyVolume(Value,(vc.VolumeR.Value)); - } - - if (voice==1) spu2M_WriteFast( 0x400 + (core<<12) + OutPos, (s16)Value ); - else if (voice==3) spu2M_WriteFast( 0x600 + (core<<12) + OutPos, (s16)Value ); - -} - - -static void __fastcall MixCore(s32& OutL, s32& OutR, s32 ExtL, s32 ExtR) -{ - s32 RVL,RVR; - s32 SDL=0,SDR=0; - s32 SWL=0,SWR=0; - - V_Core& thiscore( Cores[core] ); - - for (voice=0;voice<24;voice++) - { - s32 VValL,VValR; - - V_Voice& vc( thiscore.Voices[voice] ); - MixVoice( thiscore, vc, VValL, VValR ); - - SDL += VValL * vc.DryL; - SDR += VValR * vc.DryR; - SWL += VValL * vc.WetL; - SWR += VValR * vc.WetR; - } - - //Write To Output Area - spu2M_WriteFast( 0x1000 + (core<<12) + OutPos, (s16)(SDL>>16) ); - spu2M_WriteFast( 0x1200 + (core<<12) + OutPos, (s16)(SDR>>16) ); - spu2M_WriteFast( 0x1400 + (core<<12) + OutPos, (s16)(SWL>>16) ); - spu2M_WriteFast( 0x1600 + (core<<12) + OutPos, (s16)(SWR>>16) ); - - s32 TDL,TDR; - - // Mix in the Input data - // divide by 3 fixes some volume problems. - TDL = OutL * thiscore.InpDryL; - TDR = OutR * thiscore.InpDryR; - - // Mix in the Voice data - TDL += SDL * thiscore.SndDryL; - TDR += SDR * thiscore.SndDryR; - - // Mix in the External (nothing/core0) data - TDL += ExtL * thiscore.ExtDryL; - TDR += ExtR * thiscore.ExtDryR; - - if(EffectsEnabled) - { - s32 TWL=0,TWR=0; - - // Mix Input, Voice, and External data: - TWL = OutL * thiscore.InpWetL; - TWR = OutR * thiscore.InpWetR; - TWL += SWL * thiscore.SndWetL; - TWR += SWR * thiscore.SndWetR; - TWL += ExtL * thiscore.ExtWetL; - TWR += ExtR * thiscore.ExtWetR; - - //Apply Effects - DoReverb( thiscore, RVL,RVR,TWL>>16,TWR>>16); - - TWL=ApplyVolume(RVL,VOL(thiscore.FxL)); - TWR=ApplyVolume(RVR,VOL(thiscore.FxR)); - - //Mix Wet,Dry - OutL=(TDL + TWL); - OutR=(TDR + TWR); - } - else - { - OutL = TDL; - OutR = TDR; - } - - //Apply Master Volume - if( thiscore.MasterL.Mode & VOLFLAG_SLIDE_ENABLE ) UpdateVolume(thiscore.MasterL); - if( thiscore.MasterR.Mode & VOLFLAG_SLIDE_ENABLE ) UpdateVolume(thiscore.MasterR); - - if (thiscore.Mute==0) - { - OutL = MulShr32( OutL, ((s32)thiscore.MasterL.Value)<<16 ); - OutR = MulShr32( OutR, ((s32)thiscore.MasterR.Value)<<16 ); - } - else - { - OutL=0; - OutR=0; - } -} - -// used to throttle the output rate of cache stat reports -static int p_cachestat_counter=0; - -void __fastcall Mix() -{ - s32 ExtL=0, ExtR=0, OutL, OutR; - - // **** CORE ZERO **** - - core=0; - if( (PlayMode&4) != 4 ) - { - // get input data from input buffers - ReadInputPV(Cores[0], ExtL, ExtR); - } - - MixCore( ExtL, ExtR, 0, 0 ); - - if( PlayMode & 4 ) - { - ExtL=0; - ExtR=0; - } - - // Commit Core 0 output to ram before mixing Core 1: - ExtL>>=14; - ExtR>>=14; - spu2M_WriteFast( 0x800 + OutPos, ExtL>>3 ); - spu2M_WriteFast( 0xA00 + OutPos, ExtR>>3 ); - - // **** CORE ONE **** - - core=1; - if( (PlayMode&8) != 8 ) - { - ReadInputPV(Cores[1], OutL, OutR); // get input data from input buffers - } - - // Apply volume to the external (Core 0) input data. - - MixCore( OutL, OutR, ExtL*Cores[1].ExtL, ExtR*Cores[1].ExtR ); - - if( PlayMode & 8 ) - { - ReadInput(Cores[1], OutL, OutR); - } - -#ifndef PUBLIC - static s32 Peak0,Peak1; - static s32 PCount; - - Peak0 = max(Peak0,max(ExtL,ExtR)); - Peak1 = max(Peak1,max(OutL,OutR)); -#endif - - // Update spdif (called each sample) - if(PlayMode&4) - { - spdif_update(); - } - - // AddToBuffer - SndWrite(OutL, OutR); //ExtL,ExtR); - OutPos++; - if (OutPos>=0x200) OutPos=0; - -#ifndef PUBLIC - // [TODO]: Create an INI option to enable/disable this particular log. - p_cachestat_counter++; - if(p_cachestat_counter > (48000*10) ) - { - p_cachestat_counter = 0; - if( MsgCache() ) ConLog( " * SPU2 > CacheStats > Hits: %d Misses: %d Ignores: %d\n", - g_counter_cache_hits, - g_counter_cache_misses, - g_counter_cache_ignores ); - - g_counter_cache_hits = - g_counter_cache_misses = - g_counter_cache_ignores = 0; - } -#endif -} - -///////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// -// // -u32 PsxRates[160]={ - - //for +Lin: PsxRates[value+8] - //for -Lin: PsxRates[value+7] - - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xD744FCCB,0xB504F334,0x9837F052,0x80000000,0x6BA27E65,0x5A82799A,0x4C1BF829,0x40000000, - 0x35D13F33,0x2D413CCD,0x260DFC14,0x20000000,0x1AE89F99,0x16A09E66,0x1306FE0A,0x10000000, - 0x0D744FCD,0x0B504F33,0x09837F05,0x08000000,0x06BA27E6,0x05A8279A,0x04C1BF83,0x04000000, - 0x035D13F3,0x02D413CD,0x0260DFC1,0x02000000,0x01AE89FA,0x016A09E6,0x01306FE1,0x01000000, - 0x00D744FD,0x00B504F3,0x009837F0,0x00800000,0x006BA27E,0x005A827A,0x004C1BF8,0x00400000, - 0x0035D13F,0x002D413D,0x00260DFC,0x00200000,0x001AE8A0,0x0016A09E,0x001306FE,0x00100000, - 0x000D7450,0x000B504F,0x0009837F,0x00080000,0x0006BA28,0x0005A828,0x0004C1C0,0x00040000, - 0x00035D14,0x0002D414,0x000260E0,0x00020000,0x0001AE8A,0x00016A0A,0x00013070,0x00010000, - 0x0000D745,0x0000B505,0x00009838,0x00008000,0x00006BA2,0x00005A82,0x00004C1C,0x00004000, - 0x000035D1,0x00002D41,0x0000260E,0x00002000,0x00001AE9,0x000016A1,0x00001307,0x00001000, - 0x00000D74,0x00000B50,0x00000983,0x00000800,0x000006BA,0x000005A8,0x000004C2,0x00000400, - 0x0000035D,0x000002D4,0x00000261,0x00000200,0x000001AF,0x0000016A,0x00000130,0x00000100, - 0x000000D7,0x000000B5,0x00000098,0x00000080,0x0000006C,0x0000005B,0x0000004C,0x00000040, - 0x00000036,0x0000002D,0x00000026,0x00000020,0x0000001B,0x00000017,0x00000013,0x00000010, - 0x0000000D,0x0000000B,0x0000000A,0x00000008,0x00000007,0x00000006,0x00000005,0x00000004, - 0x00000003,0x00000003,0x00000002,0x00000002,0x00000002,0x00000001,0x00000001,0x00000000, - - //128+8 - 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, -}; - -///////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// -// // - -/* ------------------------------------------------------------------------------ -PSX reverb hardware notes -by Neill Corlett ------------------------------------------------------------------------------ - -Yadda yadda disclaimer yadda probably not perfect yadda well it's okay anyway -yadda yadda. - ------------------------------------------------------------------------------ - -Basics ------- - -- The reverb buffer is 22khz 16-bit mono PCM. -- It starts at the reverb address given by 1DA2, extends to - the end of sound RAM, and wraps back to the 1DA2 address. - -Setting the address at 1DA2 resets the current reverb work address. - -This work address ALWAYS increments every 1/22050 sec., regardless of -whether reverb is enabled (bit 7 of 1DAA set). - -And the contents of the reverb buffer ALWAYS play, scaled by the -"reverberation depth left/right" volumes (1D84/1D86). -(which, by the way, appear to be scaled so 3FFF=approx. 1.0, 4000=-1.0) - ------------------------------------------------------------------------------ - -Register names --------------- - -These are probably not their real names. -These are probably not even correct names. -We will use them anyway, because we can. - -1DC0: FB_SRC_A (offset) -1DC2: FB_SRC_B (offset) -1DC4: IIR_ALPHA (coef.) -1DC6: ACC_COEF_A (coef.) -1DC8: ACC_COEF_B (coef.) -1DCA: ACC_COEF_C (coef.) -1DCC: ACC_COEF_D (coef.) -1DCE: IIR_COEF (coef.) -1DD0: FB_ALPHA (coef.) -1DD2: FB_X (coef.) -1DD4: IIR_DEST_A0 (offset) -1DD6: IIR_DEST_A1 (offset) -1DD8: ACC_SRC_A0 (offset) -1DDA: ACC_SRC_A1 (offset) -1DDC: ACC_SRC_B0 (offset) -1DDE: ACC_SRC_B1 (offset) -1DE0: IIR_SRC_A0 (offset) -1DE2: IIR_SRC_A1 (offset) -1DE4: IIR_DEST_B0 (offset) -1DE6: IIR_DEST_B1 (offset) -1DE8: ACC_SRC_C0 (offset) -1DEA: ACC_SRC_C1 (offset) -1DEC: ACC_SRC_D0 (offset) -1DEE: ACC_SRC_D1 (offset) -1DF0: IIR_SRC_B1 (offset) -1DF2: IIR_SRC_B0 (offset) -1DF4: MIX_DEST_A0 (offset) -1DF6: MIX_DEST_A1 (offset) -1DF8: MIX_DEST_B0 (offset) -1DFA: MIX_DEST_B1 (offset) -1DFC: IN_COEF_L (coef.) -1DFE: IN_COEF_R (coef.) - -The coefficients are signed fractional values. --32768 would be -1.0 - 32768 would be 1.0 (if it were possible... the highest is of course 32767) - -The offsets are (byte/8) offsets into the reverb buffer. -i.e. you multiply them by 8, you get byte offsets. -You can also think of them as (samples/4) offsets. -They appear to be signed. They can be negative. -None of the documented presets make them negative, though. - -Yes, 1DF0 and 1DF2 appear to be backwards. Not a typo. - ------------------------------------------------------------------------------ - -What it does ------------- - -We take all reverb sources: -- regular channels that have the reverb bit on -- cd and external sources, if their reverb bits are on -and mix them into one stereo 44100hz signal. - -Lowpass/downsample that to 22050hz. The PSX uses a proper bandlimiting -algorithm here, but I haven't figured out the hysterically exact specifics. -I use an 8-tap filter with these coefficients, which are nice but probably -not the real ones: - -0.037828187894 -0.157538631280 -0.321159685278 -0.449322115345 -0.449322115345 -0.321159685278 -0.157538631280 -0.037828187894 - -So we have two input samples (INPUT_SAMPLE_L, INPUT_SAMPLE_R) every 22050hz. - -* IN MY EMULATION, I divide these by 2 to make it clip less. - (and of course the L/R output coefficients are adjusted to compensate) - The real thing appears to not do this. - -At every 22050hz tick: -- If the reverb bit is enabled (bit 7 of 1DAA), execute the reverb - steady-state algorithm described below -- AFTERWARDS, retrieve the "wet out" L and R samples from the reverb buffer - (This part may not be exactly right and I guessed at the coefs. TODO: check later.) - L is: 0.333 * (buffer[MIX_DEST_A0] + buffer[MIX_DEST_B0]) - R is: 0.333 * (buffer[MIX_DEST_A1] + buffer[MIX_DEST_B1]) -- Advance the current buffer position by 1 sample - -The wet out L and R are then upsampled to 44100hz and played at the -"reverberation depth left/right" (1D84/1D86) volume, independent of the main -volume. - ------------------------------------------------------------------------------ - -Reverb steady-state -------------------- - -The reverb steady-state algorithm is fairly clever, and of course by -"clever" I mean "batshit insane". - -buffer[x] is relative to the current buffer position, not the beginning of -the buffer. Note that all buffer offsets must wrap around so they're -contained within the reverb work area. - -Clipping is performed at the end... maybe also sooner, but definitely at -the end. - -IIR_INPUT_A0 = buffer[IIR_SRC_A0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L; -IIR_INPUT_A1 = buffer[IIR_SRC_A1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R; -IIR_INPUT_B0 = buffer[IIR_SRC_B0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L; -IIR_INPUT_B1 = buffer[IIR_SRC_B1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R; - -IIR_A0 = IIR_INPUT_A0 * IIR_ALPHA + buffer[IIR_DEST_A0] * (1.0 - IIR_ALPHA); -IIR_A1 = IIR_INPUT_A1 * IIR_ALPHA + buffer[IIR_DEST_A1] * (1.0 - IIR_ALPHA); -IIR_B0 = IIR_INPUT_B0 * IIR_ALPHA + buffer[IIR_DEST_B0] * (1.0 - IIR_ALPHA); -IIR_B1 = IIR_INPUT_B1 * IIR_ALPHA + buffer[IIR_DEST_B1] * (1.0 - IIR_ALPHA); - -buffer[IIR_DEST_A0 + 1sample] = IIR_A0; -buffer[IIR_DEST_A1 + 1sample] = IIR_A1; -buffer[IIR_DEST_B0 + 1sample] = IIR_B0; -buffer[IIR_DEST_B1 + 1sample] = IIR_B1; - -ACC0 = buffer[ACC_SRC_A0] * ACC_COEF_A + - buffer[ACC_SRC_B0] * ACC_COEF_B + - buffer[ACC_SRC_C0] * ACC_COEF_C + - buffer[ACC_SRC_D0] * ACC_COEF_D; -ACC1 = buffer[ACC_SRC_A1] * ACC_COEF_A + - buffer[ACC_SRC_B1] * ACC_COEF_B + - buffer[ACC_SRC_C1] * ACC_COEF_C + - buffer[ACC_SRC_D1] * ACC_COEF_D; - -FB_A0 = buffer[MIX_DEST_A0 - FB_SRC_A]; -FB_A1 = buffer[MIX_DEST_A1 - FB_SRC_A]; -FB_B0 = buffer[MIX_DEST_B0 - FB_SRC_B]; -FB_B1 = buffer[MIX_DEST_B1 - FB_SRC_B]; - -buffer[MIX_DEST_A0] = ACC0 - FB_A0 * FB_ALPHA; -buffer[MIX_DEST_A1] = ACC1 - FB_A1 * FB_ALPHA; -buffer[MIX_DEST_B0] = (FB_ALPHA * ACC0) - FB_A0 * (FB_ALPHA^0x8000) - FB_B0 * FB_X; -buffer[MIX_DEST_B1] = (FB_ALPHA * ACC1) - FB_A1 * (FB_ALPHA^0x8000) - FB_B1 * FB_X; - ------------------------------------------------------------------------------ -*/ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +// [Air] Notes -----> +// Adding 'static' to the __forceinline methods hints to the linker that it need not +// actually include procedural versions of the methods in the DLL. Under normal circumstances +// the compiler will still generate the procedures even though they are never used (the inline +// code is used instead). Using static reduced the size of my generated .DLL by a few KB. +// (doesn't really make anything faster, but eh... whatever :) +// +#include "spu2.h" + +#include +#include +#include +#include "lowpass.h" + +extern void spdif_update(); + +void ADMAOutLogWrite(void *lpData, u32 ulSize); + +extern void VoiceStop(int core,int vc); + +double pow_2_31 = pow(2.0,31.0); + +LPF_data L,R; + +extern u32 core; + +u32 core, voice; + +extern u8 callirq; + +double srate_pv=1.0; + +extern u32 PsxRates[160]; + +static const s32 ADSR_MAX_VOL = 0x7fffffff; + +// Performs a 64-bit multiplication between two values and returns the +// high 32 bits as a result (discarding the fractional 32 bits). +// The combined fracional bits of both inputs must be 32 bits for this +// to work properly. +// +// This is meant to be a drop-in replacement for times when the 'div' part +// of a MulDiv is a constant. (example: 1<<8, or 4096, etc) +// +// [Air] Performance breakdown: This is over 10 times faster than MulDiv in +// a *worst case* scenario. It's also more accurate since it forces the +// caller to extend the inputs so that they make use of all 32 bits of +// precision. +// +static s32 __forceinline MulShr32( s32 srcval, s32 mulval ) +{ + s64 tmp = ((s64)srcval * mulval ); + return ((s32*)&tmp)[1]; + + // Performance note: Using the temp var and memory reference + // actually ends up being roughly 2x faster than using a bitshift. + // It won't fly on big endian machines though... :) +} + +static s32 __forceinline MulShr32su( s32 srcval, u32 mulval ) +{ + s64 tmp = ((s64)srcval * (s32)mulval ); + return ((s32*)&tmp)[1]; +} + + +void InitADSR() // INIT ADSR +{ + for (int i=0; i<(32+128); i++) + { + int shift=(i-32)>>2; + s64 rate=(i&3)+4; + if (shift<0) + rate>>=-shift; + else + rate<<=shift; + + PsxRates[i]=(int)min(rate,0x3fffffff); + } +} + +#define VOL(x) (((s32)x)) //24.8 volume + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // + +const s32 f[5][2] ={{ 0, 0 }, + { 60, 0 }, + { 115, -52 }, + { 98, -55 }, + { 122, -60 }}; + +static void __forceinline XA_decode_block(s16* buffer, const s16* block, s32& prev1, s32& prev2) +{ + const s32 header = *block; + s32 shift = ((header>> 0)&0xF)+16; + s32 pred1 = f[(header>> 4)&0xF][0]; + s32 pred2 = f[(header>> 4)&0xF][1]; + + const s8* blockbytes = (s8*)&block[1]; + + for(int i=0; i<14; i++, blockbytes++) + { + s32 pcm, pcm2; + { + s32 data = ((*blockbytes)<<28) & 0xF0000000; + pcm = data>>shift; + pcm+=((pred1*prev1)+(pred2*prev2))>>6; + if(pcm> 32767) pcm= 32767; + else if(pcm<-32768) pcm=-32768; + *(buffer++) = pcm; + } + + //prev2=prev1; + //prev1=pcm; + + { + s32 data = ((*blockbytes)<<24) & 0xF0000000; + pcm2 = data>>shift; + pcm2+=((pred1*pcm)+(pred2*prev1))>>6; + if(pcm2> 32767) pcm2= 32767; + else if(pcm2<-32768) pcm2=-32768; + *(buffer++) = pcm2; + } + + prev2=pcm; + prev1=pcm2; + } +} + +static void __forceinline XA_decode_block_unsaturated(s16* buffer, const s16* block, s32& prev1, s32& prev2) +{ + const s32 header = *block; + s32 shift = ((header>> 0)&0xF)+16; + s32 pred1 = f[(header>> 4)&0xF][0]; + s32 pred2 = f[(header>> 4)&0xF][1]; + + const s8* blockbytes = (s8*)&block[1]; + + for(int i=0; i<14; i++, blockbytes++) + { + s32 pcm, pcm2; + { + s32 data = ((*blockbytes)<<28) & 0xF0000000; + pcm = data>>shift; + pcm+=((pred1*prev1)+(pred2*prev2))>>6; + // [Air] : Fast method, no saturation is performed. + *(buffer++) = pcm; + } + + { + s32 data = ((*blockbytes)<<24) & 0xF0000000; + pcm2 = data>>shift; + pcm2+=((pred1*pcm)+(pred2*prev1))>>6; + // [Air] : Fast method, no saturation is performed. + *(buffer++) = pcm2; + } + + prev2=pcm; + prev1=pcm2; + } +} + +static void __forceinline IncrementNextA( const V_Core& thiscore, V_Voice& vc ) +{ + // Important! Both cores signal IRQ when an address is read, regardless of + // which core actually reads the address. + + for( int i=0; i<2; i++ ) + { + if( Cores[i].IRQEnable && (vc.NextA==Cores[i].IRQA ) ) + { + #ifndef PUBLIC + ConLog(" * SPU2 Core %d: IRQ Called (IRQ passed).\n", i); + #endif + Spdif.Info=4<> 8; // grab loop flags from the upper byte. + + const int cacheIdx = vc.NextA / pcm_WordsPerBlock; + PcmCacheEntry& cacheLine = pcm_cache_data[cacheIdx]; + vc.SBuffer = cacheLine.Sampledata; + + if( cacheLine.Validated ) + { + // Cached block! Read from the cache directly. + // Make sure to propagate the prev1/prev2 ADPCM: + + vc.Prev1 = vc.SBuffer[27]; + vc.Prev2 = vc.SBuffer[26]; + + //ConLog( " * SPU2 : Cache Hit! NextA=0x%x, cacheIdx=0x%x\n", vc.NextA, cacheIdx ); + + #ifndef PUBLIC + g_counter_cache_hits++; + #endif + } + else + { + // Only flag the cache if it's a non-dynamic memory range. + if( vc.NextA >= SPU2_DYN_MEMLINE ) + cacheLine.Validated = true; + + #ifndef PUBLIC + if( vc.NextA < SPU2_DYN_MEMLINE ) + g_counter_cache_ignores++; + else + g_counter_cache_misses++; + #endif + + s16* sbuffer = cacheLine.Sampledata; + + // saturated decoder + XA_decode_block( sbuffer, memptr, vc.Prev1, vc.Prev2 ); + + // [Air]: Testing use of a new unsaturated decoder. (benchmark needed) + // Chances are the saturation isn't needed, but for a very few exception games. + // This is definitely faster than the above version, but is it by enough to + // merit possible lower compatibility? Especially now that games that make + // heavy use of the SPU2 via music or sfx will mostly use the cache anyway. + + //XA_decode_block_unsaturated( vc.SBuffer, memptr, vc.Prev1, vc.Prev2 ); + } + + vc.SCurrent = 0; + if( (vc.LoopFlags & XAFLAG_LOOP_START) && !vc.LoopMode ) + vc.LoopStartA = vc.NextA; + + // [Air] : Increment will get called below (change made to avoid needless code cache clutter) + //IncrementNextA( thiscore, vc ); + } + + IncrementNextA( thiscore, vc ); + +_skipIncrement: + Data = vc.SBuffer[vc.SCurrent++]; +} + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // + +const int InvExpOffsets[] = { 0,4,6,8,9,10,11,12 }; + +static void __forceinline CalculateADSR( V_Voice& vc ) +{ + V_ADSR& env(vc.ADSR); + + jASSUME( env.Phase != 0 ); + + s32 SLevel = ((s32)env.Sl)<<27; + + jASSUME( SLevel >= 0 ); + + if(env.Releasing) + { + if( env.Phase < 5) + { + env.Phase=5; + } + } + + switch (env.Phase) + { + case 1: // attack + if( env.Value == ADSR_MAX_VOL ) + { + // Already maxed out. Progress phase and nothing more: + env.Phase++; + break; + } + + if (env.Am) // pseudo exponential + { + if (env.Value<0x60000000) // below 75% + { + env.Value+=PsxRates[(env.Ar^0x7f)-0x10+32]; + } + else // above 75% + { + env.Value+=PsxRates[(env.Ar^0x7f)-0x18+32]; + } + } + else // linear + { + env.Value+=PsxRates[(env.Ar^0x7f)-0x10+32]; + } + + if( env.Value < 0 ) + { + // We hit the ceiling. + env.Phase++; + env.Value = ADSR_MAX_VOL; + } + + break; + + case 2: // decay + { + u32 off = InvExpOffsets[(env.Value>>28)&7]; + env.Value-=PsxRates[((env.Dr^0x1f)<<2)-0x18+off+32]; + + if(env.Value <= SLevel) + { + // Clamp decay to SLevel or Zero + if (env.Value < 0) + env.Value = 0; + else + env.Value = SLevel; + + env.Phase++; + } + + break; + } + + case 3: // sustain + if (env.Sm&2) // decreasing + { + if (env.Sm&4) // exponential + { + u32 off = InvExpOffsets[(env.Value>>28)&7]; + env.Value-=PsxRates[(env.Sr^0x7f)-0x1b+off+32]; + } + else // linear + { + env.Value-=PsxRates[(env.Sr^0x7f)-0xf+32]; + } + if( env.Value <= 0 ) + { + env.Value = 0; + env.Phase++; + } + } + else // increasing + { + if (env.Sm&4) // pseudo exponential + { + if (env.Value<0x60000000) // below 75% + { + env.Value+=PsxRates[(env.Sr^0x7f)-0x10+32]; + } + else // above 75% + { + env.Value+=PsxRates[(env.Sr^0x7f)-0x18+32]; + } + } + else + { + // linear + + env.Value+=PsxRates[(env.Sr^0x7f)-0x10+32]; + } + + if( env.Value < 0 ) + { + env.Value = ADSR_MAX_VOL; + env.Phase++; + } + } + + break; + + case 4: // sustain end + env.Value = (env.Sm&2) ? 0 : ADSR_MAX_VOL; + if(env.Value==0) + env.Phase=6; + break; + + case 5: // release + + if (env.Rm) // exponential + { + u32 off=InvExpOffsets[(env.Value>>28)&7]; + env.Value-=PsxRates[((env.Rr^0x1f)<<2)-0x18+off+32]; + } + else // linear + { + env.Value-=PsxRates[((env.Rr^0x1f)<<2)-0xc+32]; + } + + if( env.Value <= 0 ) + { + env.Value=0; + env.Phase++; + } + + break; + + case 6: // release end + env.Value=0; + break; + + jNO_DEFAULT + } + + if (env.Phase==6) { + #ifndef PUBLIC + if(MsgVoiceOff()) ConLog(" * SPU2: Voice Off by ADSR: %d \n", voice); + DebugCores[core].Voices[voice].lastStopReason = 2; + #endif + VoiceStop(core,voice); + Cores[core].Regs.ENDX|=(1<> 7; // >> 6 is more correct, but causes a few overflows +} + +static void __forceinline UpdatePitch( V_Voice& vc ) +{ + s32 pitch; + + // [Air] : re-ordered comparisons: Modulated is much more likely to be zero than voice, + // and so the way it was before it's have to check both voice and modulated values + // most of the time. Now it'll just check Modulated and short-circuit past the voice + // check (not that it amounts to much, but eh every little bit helps). + if( (vc.Modulated==0) || (voice==0) ) + pitch=vc.Pitch; + else + pitch=(vc.Pitch*(32768 + abs(Cores[core].Voices[voice-1].OutX)))>>15; + + vc.SP+=pitch; +} + +static void __forceinline GetVoiceValues_Linear(V_Core& thiscore, V_Voice& vc, s32& Value) +{ + while( vc.SP > 0 ) + { + vc.PV2=vc.PV1; + + GetNextDataBuffered( thiscore, vc, vc.PV1 ); + + vc.SP-=4096; + } + + if( vc.ADSR.Phase==0 ) + { + Value = 0; + return; + } + + CalculateADSR( vc ); + + jASSUME( vc.ADSR.Value >= 0 ); // ADSR should never be negative... + + if(Interpolation==0) + { + Value = MulShr32( vc.PV1, vc.ADSR.Value ); + } + else //if(Interpolation==1) //must be linear + { + s32 t0 = vc.PV2 - vc.PV1; + s32 t1 = vc.PV1; + Value = MulShr32( t1 - ((t0*vc.SP)>>12), vc.ADSR.Value ); + } +} + + +static void __forceinline GetVoiceValues_Cubic(V_Core& thiscore, V_Voice& vc, s32& Value) +{ + while( vc.SP > 0 ) + { + vc.PV4=vc.PV3; + vc.PV3=vc.PV2; + vc.PV2=vc.PV1; + + GetNextDataBuffered( thiscore, vc, vc.PV1 ); + vc.PV1<<=3; + vc.SPc = vc.SP&4095; // just the fractional part, please! + vc.SP-=4096; + } + + if( vc.ADSR.Phase==0 ) + { + Value = 0; + return; + } + + CalculateADSR( vc ); + + jASSUME( vc.ADSR.Value >= 0 ); // ADSR should never be negative... + + s32 z0 = vc.PV3 - vc.PV4 + vc.PV1 - vc.PV2; + s32 z1 = (vc.PV4 - vc.PV3 - z0); + s32 z2 = (vc.PV2 - vc.PV4); + + s32 mu = vc.SPc; + + s32 val = (z0 * mu) >> 12; + val = ((val + z1) * mu) >> 12; + val = ((val + z2) * mu) >> 12; + val += vc.PV2; + + Value = MulShr32( val, vc.ADSR.Value>>3 ); +} + +// [Air]: Noise values need to be mixed without going through interpolation, since it +// can wreak havoc on the noise (causing muffling or popping). +static void __forceinline __fastcall GetNoiseValues(V_Core& thiscore, V_Voice& vc, s32& Data) +{ + while(vc.SP>=4096) + { + GetNoiseValues( Data ); + vc.SP-=4096; + } + + // GetNoiseValues can't set the phase zero on us unexpectedly + // like GetVoiceValues can. Better asster just in case though.. + jASSUME( vc.ADSR.Phase != 0 ); + + CalculateADSR( vc ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // + +void __fastcall ReadInput(V_Core& thiscore, s32& PDataL,s32& PDataR) +{ + if((thiscore.AutoDMACtrl&(core+1))==(core+1)) + { + s32 tl,tr; + + if((core==1)&&((PlayMode&8)==8)) + { + thiscore.InputPos&=~1; + + //CDDA mode +#ifdef PCM24_S1_INTERLEAVE + *PDataL=*(((s32*)(thiscore.ADMATempBuffer+(thiscore.InputPos<<1)))); + *PDataR=*(((s32*)(thiscore.ADMATempBuffer+(thiscore.InputPos<<1)+2))); +#else + s32 *pl=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos]); + s32 *pr=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos+0x200]); + PDataL=*pl; + PDataR=*pr; +#endif + + PDataL>>=4; //give 16.8 data + PDataR>>=4; + + thiscore.InputPos+=2; + if((thiscore.InputPos==0x100)||(thiscore.InputPos>=0x200)) { + thiscore.AdmaInProgress=0; + if(thiscore.InputDataLeft>=0x200) + { + u8 k=thiscore.InputDataLeft>=thiscore.InputDataProgress; + +#ifdef PCM24_S1_INTERLEAVE + AutoDMAReadBuffer(core,1); +#else + AutoDMAReadBuffer(core,0); +#endif + thiscore.AdmaInProgress=1; + + thiscore.TSA=(core<<10)+thiscore.InputPos; + + if (thiscore.InputDataLeft<0x200) + { + FileLog("[%10d] AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7'); + + #ifndef PUBLIC + if(thiscore.InputDataLeft>0) + { + if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n"); + } + #endif + thiscore.InputDataLeft=0; + thiscore.DMAICounter=1; + } + } + thiscore.InputPos&=0x1ff; + } + + } + else if((core==0)&&((PlayMode&4)==4)) + { + thiscore.InputPos&=~1; + + s32 *pl=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos]); + s32 *pr=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos+0x200]); + PDataL=*pl; + PDataR=*pr; + + thiscore.InputPos+=2; + if(thiscore.InputPos>=0x200) { + thiscore.AdmaInProgress=0; + if(thiscore.InputDataLeft>=0x200) + { + u8 k=thiscore.InputDataLeft>=thiscore.InputDataProgress; + + AutoDMAReadBuffer(core,0); + + thiscore.AdmaInProgress=1; + + thiscore.TSA=(core<<10)+thiscore.InputPos; + + if (thiscore.InputDataLeft<0x200) + { + FileLog("[%10d] Spdif AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7'); + + #ifndef PUBLIC + if(thiscore.InputDataLeft>0) + { + if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n"); + } + #endif + thiscore.InputDataLeft=0; + thiscore.DMAICounter=1; + } + } + thiscore.InputPos&=0x1ff; + } + + } + else + { + if((core==1)&&((PlayMode&2)!=0)) + { + tl=0; + tr=0; + } + else + { + // Using the temporary buffer because this area gets overwritten by some other code. + //*PDataL=(s32)*(s16*)(spu2mem+0x2000+(core<<10)+thiscore.InputPos); + //*PDataR=(s32)*(s16*)(spu2mem+0x2200+(core<<10)+thiscore.InputPos); + + tl=(s32)thiscore.ADMATempBuffer[thiscore.InputPos]; + tr=(s32)thiscore.ADMATempBuffer[thiscore.InputPos+0x200]; + + } + + PDataL=tl; + PDataR=tr; + + thiscore.InputPos++; + if((thiscore.InputPos==0x100)||(thiscore.InputPos>=0x200)) { + thiscore.AdmaInProgress=0; + if(thiscore.InputDataLeft>=0x200) + { + u8 k=thiscore.InputDataLeft>=thiscore.InputDataProgress; + + AutoDMAReadBuffer(core,0); + + thiscore.AdmaInProgress=1; + + thiscore.TSA=(core<<10)+thiscore.InputPos; + + if (thiscore.InputDataLeft<0x200) + { + thiscore.AutoDMACtrl |= ~3; + + #ifndef PUBLIC + FileLog("[%10d] AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7'); + if(thiscore.InputDataLeft>0) + { + if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n"); + } + #endif + thiscore.InputDataLeft=0; + thiscore.DMAICounter=1; + } + } + thiscore.InputPos&=0x1ff; + } + } + } + else { + PDataL=0; + PDataR=0; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // + +static void __forceinline __fastcall ReadInputPV(V_Core& thiscore, s32& ValL,s32& ValR) +{ + s32 DL=0, DR=0; + + u32 pitch=AutoDMAPlayRate[core]; + + if(pitch==0) pitch=48000; + + thiscore.ADMAPV+=pitch; + while(thiscore.ADMAPV>=48000) + { + ReadInput(thiscore, DL,DR); + thiscore.ADMAPV-=48000; + thiscore.ADMAPL=DL; + thiscore.ADMAPR=DR; + } + + ValL=thiscore.ADMAPL; + ValR=thiscore.ADMAPR; + + #ifndef PUBLIC + s32 InputPeak = max(abs(ValL),abs(ValR)); + if(DebugCores[core].AutoDMAPeak>= 1; + //ValR >>= 1; + +} + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // + +#define VOLFLAG_REVERSE_PHASE (1ul<<0) +#define VOLFLAG_DECREMENT (1ul<<1) +#define VOLFLAG_EXPONENTIAL (1ul<<2) +#define VOLFLAG_SLIDE_ENABLE (1ul<<3) + +static void __fastcall UpdateVolume(V_Volume& Vol) +{ + // TIMINGS ARE FAKE!!! Need to investigate. + + // [Air]: Cleaned up this code... may have broken it. Can't really + // test it here since none of my games seem to use it. If anything's + // not sounding right, we should revert the code in this method first. + + // [Air] Reverse phasing? + // Invert our value so that exponential mathematics are applied + // as if the volume were sliding the other direction. This makes + // a lot more sense than the old method's likeliness to chop off + // sound volumes to zero abruptly. + + if(Vol.Mode & VOLFLAG_REVERSE_PHASE) + { + ConLog( " *** SPU2 > Reverse Phase in progress!\n" ); + Vol.Value = 0x7fff - Vol.Value; + } + + if (Vol.Mode & VOLFLAG_DECREMENT) + { + // Decrement + + if(Vol.Mode & VOLFLAG_EXPONENTIAL) + { + ConLog( " *** SPU2 > Exponential Volume Slide Down!\n" ); + Vol.Value *= Vol.Increment >> 7; + Vol.Value-=((32768*5)>>(Vol.Increment)); + } + else + { + Vol.Value-=Vol.Increment; + } + + if (Vol.Value<0) + { + Vol.Value = 0; + Vol.Mode=0; // disable slide + } + } + else + { + //ConLog( " *** SPU2 > Volflag > Increment!\n" ); + // Increment + if(Vol.Mode & VOLFLAG_EXPONENTIAL) + { + ConLog( " *** SPU2 > Exponential Volume Slide Up!\n" ); + int T = Vol.Increment>>(Vol.Value>>12); + Vol.Value+=T; + } + else + { + Vol.Value+=Vol.Increment; + } + + if( Vol.Value > 0x7fff ) + { + Vol.Value = 0x7fff; + Vol.Mode=0; // disable slide + } + } + + // Reverse phasing + // Invert the value back into output form: + if(Vol.Mode & VOLFLAG_REVERSE_PHASE) Vol.Value = 0x7fff-Vol.Value; + + //Vol.Value=NVal; +} + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // + +static s32 __forceinline clamp(s32 x) +{ + if (x>0x00ffffff) return 0x00ffffff; + if (x<0xff000000) return 0xff000000; + return x; +} + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // + +static void DoReverb( V_Core& thiscore, s32& OutL, s32& OutR, s32 InL, s32 InR) +{ + static s32 INPUT_SAMPLE_L,INPUT_SAMPLE_R; + static s32 OUTPUT_SAMPLE_L,OUTPUT_SAMPLE_R; + + if(!(thiscore.FxEnable&&EffectsEnabled)) + { + OUTPUT_SAMPLE_L=0; + OUTPUT_SAMPLE_R=0; + } + else if((Cycles&1)==0) + { + INPUT_SAMPLE_L=InL; + INPUT_SAMPLE_R=InR; + } + else + { +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + s32 IIR_INPUT_A0,IIR_INPUT_A1,IIR_INPUT_B0,IIR_INPUT_B1; + s32 ACC0,ACC1; + s32 FB_A0,FB_A1,FB_B0,FB_B1; + s32 buffsize=thiscore.EffectsEndA-thiscore.EffectsStartA+1; + + if(buffsize<0) + { + buffsize = thiscore.EffectsEndA; + thiscore.EffectsEndA=thiscore.EffectsStartA; + thiscore.EffectsStartA=buffsize; + buffsize=thiscore.EffectsEndA-thiscore.EffectsStartA+1; + } + + //filter the 2 samples (prev then current) + LowPass(INPUT_SAMPLE_L, INPUT_SAMPLE_R); + LowPass(InL, InR); + + INPUT_SAMPLE_L=(INPUT_SAMPLE_L+InL)>>9; + INPUT_SAMPLE_R=(INPUT_SAMPLE_R+InR)>>9; + +#define BUFFER(x) ((s32)(*GetMemPtr(thiscore.EffectsStartA + ((thiscore.ReverbX + buffsize-((x)<<2))%buffsize)))) +#define SBUFFER(x) (*GetMemPtr(thiscore.EffectsStartA + ((thiscore.ReverbX + buffsize-((x)<<2))%buffsize))) + + thiscore.ReverbX=((thiscore.ReverbX + 4)%buffsize); + + IIR_INPUT_A0 = (BUFFER(thiscore.Revb.IIR_SRC_A0) * thiscore.Revb.IIR_COEF + INPUT_SAMPLE_L * thiscore.Revb.IN_COEF_L)>>16; + IIR_INPUT_A1 = (BUFFER(thiscore.Revb.IIR_SRC_A1) * thiscore.Revb.IIR_COEF + INPUT_SAMPLE_R * thiscore.Revb.IN_COEF_R)>>16; + IIR_INPUT_B0 = (BUFFER(thiscore.Revb.IIR_SRC_B0) * thiscore.Revb.IIR_COEF + INPUT_SAMPLE_L * thiscore.Revb.IN_COEF_L)>>16; + IIR_INPUT_B1 = (BUFFER(thiscore.Revb.IIR_SRC_B1) * thiscore.Revb.IIR_COEF + INPUT_SAMPLE_R * thiscore.Revb.IN_COEF_R)>>16; + + SBUFFER(thiscore.Revb.IIR_DEST_A0 + 4) = clamp((IIR_INPUT_A0 * thiscore.Revb.IIR_ALPHA + BUFFER(thiscore.Revb.IIR_DEST_A0) * (65535 - thiscore.Revb.IIR_ALPHA))>>16); + SBUFFER(thiscore.Revb.IIR_DEST_A1 + 4) = clamp((IIR_INPUT_A1 * thiscore.Revb.IIR_ALPHA + BUFFER(thiscore.Revb.IIR_DEST_A1) * (65535 - thiscore.Revb.IIR_ALPHA))>>16); + SBUFFER(thiscore.Revb.IIR_DEST_B0 + 4) = clamp((IIR_INPUT_B0 * thiscore.Revb.IIR_ALPHA + BUFFER(thiscore.Revb.IIR_DEST_B0) * (65535 - thiscore.Revb.IIR_ALPHA))>>16); + SBUFFER(thiscore.Revb.IIR_DEST_B1 + 4) = clamp((IIR_INPUT_B1 * thiscore.Revb.IIR_ALPHA + BUFFER(thiscore.Revb.IIR_DEST_B1) * (65535 - thiscore.Revb.IIR_ALPHA))>>16); + + ACC0 = (s32)(BUFFER(thiscore.Revb.ACC_SRC_A0) * thiscore.Revb.ACC_COEF_A + + BUFFER(thiscore.Revb.ACC_SRC_B0) * thiscore.Revb.ACC_COEF_B + + BUFFER(thiscore.Revb.ACC_SRC_C0) * thiscore.Revb.ACC_COEF_C + + BUFFER(thiscore.Revb.ACC_SRC_D0) * thiscore.Revb.ACC_COEF_D)>>16; + ACC1 = (s32)(BUFFER(thiscore.Revb.ACC_SRC_A1) * thiscore.Revb.ACC_COEF_A + + BUFFER(thiscore.Revb.ACC_SRC_B1) * thiscore.Revb.ACC_COEF_B + + BUFFER(thiscore.Revb.ACC_SRC_C1) * thiscore.Revb.ACC_COEF_C + + BUFFER(thiscore.Revb.ACC_SRC_D1) * thiscore.Revb.ACC_COEF_D)>>16; + + FB_A0 = BUFFER(thiscore.Revb.MIX_DEST_A0 - thiscore.Revb.FB_SRC_A); + FB_A1 = BUFFER(thiscore.Revb.MIX_DEST_A1 - thiscore.Revb.FB_SRC_A); + FB_B0 = BUFFER(thiscore.Revb.MIX_DEST_B0 - thiscore.Revb.FB_SRC_B); + FB_B1 = BUFFER(thiscore.Revb.MIX_DEST_B1 - thiscore.Revb.FB_SRC_B); + + SBUFFER(thiscore.Revb.MIX_DEST_A0) = clamp((ACC0 - FB_A0 * thiscore.Revb.FB_ALPHA)>>16); + SBUFFER(thiscore.Revb.MIX_DEST_A1) = clamp((ACC1 - FB_A1 * thiscore.Revb.FB_ALPHA)>>16); + SBUFFER(thiscore.Revb.MIX_DEST_B0) = clamp(((thiscore.Revb.FB_ALPHA * ACC0) - FB_A0 * (65535 - thiscore.Revb.FB_ALPHA) - FB_B0 * thiscore.Revb.FB_X)>>16); + SBUFFER(thiscore.Revb.MIX_DEST_B1) = clamp(((thiscore.Revb.FB_ALPHA * ACC1) - FB_A1 * (65535 - thiscore.Revb.FB_ALPHA) - FB_B1 * thiscore.Revb.FB_X)>>16); + + OUTPUT_SAMPLE_L=clamp((BUFFER(thiscore.Revb.MIX_DEST_A0)+BUFFER(thiscore.Revb.MIX_DEST_B0))>>2); + OUTPUT_SAMPLE_R=clamp((BUFFER(thiscore.Revb.MIX_DEST_B1)+BUFFER(thiscore.Revb.MIX_DEST_B1))>>2); + } + OutL=OUTPUT_SAMPLE_L; + OutR=OUTPUT_SAMPLE_R; +} + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // + +// writes a signed value to the SPU2 ram +// Performs no cache invalidation -- use only for dynamic memory ranges +// of the SPU2 (between 0x0000 and SPU2_DYN_MEMLINE) +static __forceinline void spu2M_WriteFast( u32 addr, s16 value ) +{ + // throw an assertion if the memory range is invalid: + jASSUME( addr < SPU2_DYN_MEMLINE ); + *GetMemPtr( addr ) = value; +} + + +static __forceinline void MixVoice( V_Core& thiscore, V_Voice& vc, s32& VValL, s32& VValR ) +{ + s32 Value=0; + + VValL=0; + VValR=0; + + // [Air] : Most games don't use much volume slide effects. So only + // call the UpdateVolume methods when needed by checking the flag + // outside the method here... + + if( vc.VolumeL.Mode & VOLFLAG_SLIDE_ENABLE ) UpdateVolume( vc.VolumeL ); + if( vc.VolumeR.Mode & VOLFLAG_SLIDE_ENABLE ) UpdateVolume( vc.VolumeR ); + + if (vc.ADSR.Phase>0) + { + UpdatePitch( vc ); + + if( vc.Noise ) + GetNoiseValues( thiscore, vc, Value ); + else + { + if( Interpolation == 2 ) + GetVoiceValues_Cubic( thiscore, vc, Value ); + else + GetVoiceValues_Linear( thiscore, vc, Value ); + } + + // Record the output (used for modulation effects) + vc.OutX = Value; + + #ifndef PUBLIC + DebugCores[core].Voices[voice].displayPeak = max(DebugCores[core].Voices[voice].displayPeak,abs(Value)); + #endif + + VValL=ApplyVolume(Value,(vc.VolumeL.Value)); + VValR=ApplyVolume(Value,(vc.VolumeR.Value)); + } + + if (voice==1) spu2M_WriteFast( 0x400 + (core<<12) + OutPos, (s16)Value ); + else if (voice==3) spu2M_WriteFast( 0x600 + (core<<12) + OutPos, (s16)Value ); + +} + + +static void __fastcall MixCore(s32& OutL, s32& OutR, s32 ExtL, s32 ExtR) +{ + s32 RVL,RVR; + s32 SDL=0,SDR=0; + s32 SWL=0,SWR=0; + + V_Core& thiscore( Cores[core] ); + + for (voice=0;voice<24;voice++) + { + s32 VValL,VValR; + + V_Voice& vc( thiscore.Voices[voice] ); + MixVoice( thiscore, vc, VValL, VValR ); + + SDL += VValL * vc.DryL; + SDR += VValR * vc.DryR; + SWL += VValL * vc.WetL; + SWR += VValR * vc.WetR; + } + + //Write To Output Area + spu2M_WriteFast( 0x1000 + (core<<12) + OutPos, (s16)(SDL>>16) ); + spu2M_WriteFast( 0x1200 + (core<<12) + OutPos, (s16)(SDR>>16) ); + spu2M_WriteFast( 0x1400 + (core<<12) + OutPos, (s16)(SWL>>16) ); + spu2M_WriteFast( 0x1600 + (core<<12) + OutPos, (s16)(SWR>>16) ); + + s32 TDL,TDR; + + // Mix in the Input data + // divide by 3 fixes some volume problems. + TDL = OutL * thiscore.InpDryL; + TDR = OutR * thiscore.InpDryR; + + // Mix in the Voice data + TDL += SDL * thiscore.SndDryL; + TDR += SDR * thiscore.SndDryR; + + // Mix in the External (nothing/core0) data + TDL += ExtL * thiscore.ExtDryL; + TDR += ExtR * thiscore.ExtDryR; + + if(EffectsEnabled) + { + s32 TWL=0,TWR=0; + + // Mix Input, Voice, and External data: + TWL = OutL * thiscore.InpWetL; + TWR = OutR * thiscore.InpWetR; + TWL += SWL * thiscore.SndWetL; + TWR += SWR * thiscore.SndWetR; + TWL += ExtL * thiscore.ExtWetL; + TWR += ExtR * thiscore.ExtWetR; + + //Apply Effects + DoReverb( thiscore, RVL,RVR,TWL>>16,TWR>>16); + + TWL=ApplyVolume(RVL,VOL(thiscore.FxL)); + TWR=ApplyVolume(RVR,VOL(thiscore.FxR)); + + //Mix Wet,Dry + OutL=(TDL + TWL); + OutR=(TDR + TWR); + } + else + { + OutL = TDL; + OutR = TDR; + } + + //Apply Master Volume + if( thiscore.MasterL.Mode & VOLFLAG_SLIDE_ENABLE ) UpdateVolume(thiscore.MasterL); + if( thiscore.MasterR.Mode & VOLFLAG_SLIDE_ENABLE ) UpdateVolume(thiscore.MasterR); + + if (thiscore.Mute==0) + { + OutL = MulShr32( OutL, ((s32)thiscore.MasterL.Value)<<16 ); + OutR = MulShr32( OutR, ((s32)thiscore.MasterR.Value)<<16 ); + } + else + { + OutL=0; + OutR=0; + } +} + +// used to throttle the output rate of cache stat reports +static int p_cachestat_counter=0; + +void __fastcall Mix() +{ + s32 ExtL=0, ExtR=0, OutL, OutR; + + // **** CORE ZERO **** + + core=0; + if( (PlayMode&4) != 4 ) + { + // get input data from input buffers + ReadInputPV(Cores[0], ExtL, ExtR); + } + + MixCore( ExtL, ExtR, 0, 0 ); + + if( PlayMode & 4 ) + { + ExtL=0; + ExtR=0; + } + + // Commit Core 0 output to ram before mixing Core 1: + ExtL>>=14; + ExtR>>=14; + spu2M_WriteFast( 0x800 + OutPos, ExtL>>3 ); + spu2M_WriteFast( 0xA00 + OutPos, ExtR>>3 ); + + // **** CORE ONE **** + + core=1; + if( (PlayMode&8) != 8 ) + { + ReadInputPV(Cores[1], OutL, OutR); // get input data from input buffers + } + + // Apply volume to the external (Core 0) input data. + + MixCore( OutL, OutR, ExtL*Cores[1].ExtL, ExtR*Cores[1].ExtR ); + + if( PlayMode & 8 ) + { + ReadInput(Cores[1], OutL, OutR); + } + +#ifndef PUBLIC + static s32 Peak0,Peak1; + static s32 PCount; + + Peak0 = max(Peak0,max(ExtL,ExtR)); + Peak1 = max(Peak1,max(OutL,OutR)); +#endif + + // Update spdif (called each sample) + if(PlayMode&4) + { + spdif_update(); + } + + // AddToBuffer + SndWrite(OutL, OutR); //ExtL,ExtR); + OutPos++; + if (OutPos>=0x200) OutPos=0; + +#ifndef PUBLIC + // [TODO]: Create an INI option to enable/disable this particular log. + p_cachestat_counter++; + if(p_cachestat_counter > (48000*10) ) + { + p_cachestat_counter = 0; + if( MsgCache() ) ConLog( " * SPU2 > CacheStats > Hits: %d Misses: %d Ignores: %d\n", + g_counter_cache_hits, + g_counter_cache_misses, + g_counter_cache_ignores ); + + g_counter_cache_hits = + g_counter_cache_misses = + g_counter_cache_ignores = 0; + } +#endif +} + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // +u32 PsxRates[160]={ + + //for +Lin: PsxRates[value+8] + //for -Lin: PsxRates[value+7] + + 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, + 0xD744FCCB,0xB504F334,0x9837F052,0x80000000,0x6BA27E65,0x5A82799A,0x4C1BF829,0x40000000, + 0x35D13F33,0x2D413CCD,0x260DFC14,0x20000000,0x1AE89F99,0x16A09E66,0x1306FE0A,0x10000000, + 0x0D744FCD,0x0B504F33,0x09837F05,0x08000000,0x06BA27E6,0x05A8279A,0x04C1BF83,0x04000000, + 0x035D13F3,0x02D413CD,0x0260DFC1,0x02000000,0x01AE89FA,0x016A09E6,0x01306FE1,0x01000000, + 0x00D744FD,0x00B504F3,0x009837F0,0x00800000,0x006BA27E,0x005A827A,0x004C1BF8,0x00400000, + 0x0035D13F,0x002D413D,0x00260DFC,0x00200000,0x001AE8A0,0x0016A09E,0x001306FE,0x00100000, + 0x000D7450,0x000B504F,0x0009837F,0x00080000,0x0006BA28,0x0005A828,0x0004C1C0,0x00040000, + 0x00035D14,0x0002D414,0x000260E0,0x00020000,0x0001AE8A,0x00016A0A,0x00013070,0x00010000, + 0x0000D745,0x0000B505,0x00009838,0x00008000,0x00006BA2,0x00005A82,0x00004C1C,0x00004000, + 0x000035D1,0x00002D41,0x0000260E,0x00002000,0x00001AE9,0x000016A1,0x00001307,0x00001000, + 0x00000D74,0x00000B50,0x00000983,0x00000800,0x000006BA,0x000005A8,0x000004C2,0x00000400, + 0x0000035D,0x000002D4,0x00000261,0x00000200,0x000001AF,0x0000016A,0x00000130,0x00000100, + 0x000000D7,0x000000B5,0x00000098,0x00000080,0x0000006C,0x0000005B,0x0000004C,0x00000040, + 0x00000036,0x0000002D,0x00000026,0x00000020,0x0000001B,0x00000017,0x00000013,0x00000010, + 0x0000000D,0x0000000B,0x0000000A,0x00000008,0x00000007,0x00000006,0x00000005,0x00000004, + 0x00000003,0x00000003,0x00000002,0x00000002,0x00000002,0x00000001,0x00000001,0x00000000, + + //128+8 + 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, +}; + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // + +/* +----------------------------------------------------------------------------- +PSX reverb hardware notes +by Neill Corlett +----------------------------------------------------------------------------- + +Yadda yadda disclaimer yadda probably not perfect yadda well it's okay anyway +yadda yadda. + +----------------------------------------------------------------------------- + +Basics +------ + +- The reverb buffer is 22khz 16-bit mono PCM. +- It starts at the reverb address given by 1DA2, extends to + the end of sound RAM, and wraps back to the 1DA2 address. + +Setting the address at 1DA2 resets the current reverb work address. + +This work address ALWAYS increments every 1/22050 sec., regardless of +whether reverb is enabled (bit 7 of 1DAA set). + +And the contents of the reverb buffer ALWAYS play, scaled by the +"reverberation depth left/right" volumes (1D84/1D86). +(which, by the way, appear to be scaled so 3FFF=approx. 1.0, 4000=-1.0) + +----------------------------------------------------------------------------- + +Register names +-------------- + +These are probably not their real names. +These are probably not even correct names. +We will use them anyway, because we can. + +1DC0: FB_SRC_A (offset) +1DC2: FB_SRC_B (offset) +1DC4: IIR_ALPHA (coef.) +1DC6: ACC_COEF_A (coef.) +1DC8: ACC_COEF_B (coef.) +1DCA: ACC_COEF_C (coef.) +1DCC: ACC_COEF_D (coef.) +1DCE: IIR_COEF (coef.) +1DD0: FB_ALPHA (coef.) +1DD2: FB_X (coef.) +1DD4: IIR_DEST_A0 (offset) +1DD6: IIR_DEST_A1 (offset) +1DD8: ACC_SRC_A0 (offset) +1DDA: ACC_SRC_A1 (offset) +1DDC: ACC_SRC_B0 (offset) +1DDE: ACC_SRC_B1 (offset) +1DE0: IIR_SRC_A0 (offset) +1DE2: IIR_SRC_A1 (offset) +1DE4: IIR_DEST_B0 (offset) +1DE6: IIR_DEST_B1 (offset) +1DE8: ACC_SRC_C0 (offset) +1DEA: ACC_SRC_C1 (offset) +1DEC: ACC_SRC_D0 (offset) +1DEE: ACC_SRC_D1 (offset) +1DF0: IIR_SRC_B1 (offset) +1DF2: IIR_SRC_B0 (offset) +1DF4: MIX_DEST_A0 (offset) +1DF6: MIX_DEST_A1 (offset) +1DF8: MIX_DEST_B0 (offset) +1DFA: MIX_DEST_B1 (offset) +1DFC: IN_COEF_L (coef.) +1DFE: IN_COEF_R (coef.) + +The coefficients are signed fractional values. +-32768 would be -1.0 + 32768 would be 1.0 (if it were possible... the highest is of course 32767) + +The offsets are (byte/8) offsets into the reverb buffer. +i.e. you multiply them by 8, you get byte offsets. +You can also think of them as (samples/4) offsets. +They appear to be signed. They can be negative. +None of the documented presets make them negative, though. + +Yes, 1DF0 and 1DF2 appear to be backwards. Not a typo. + +----------------------------------------------------------------------------- + +What it does +------------ + +We take all reverb sources: +- regular channels that have the reverb bit on +- cd and external sources, if their reverb bits are on +and mix them into one stereo 44100hz signal. + +Lowpass/downsample that to 22050hz. The PSX uses a proper bandlimiting +algorithm here, but I haven't figured out the hysterically exact specifics. +I use an 8-tap filter with these coefficients, which are nice but probably +not the real ones: + +0.037828187894 +0.157538631280 +0.321159685278 +0.449322115345 +0.449322115345 +0.321159685278 +0.157538631280 +0.037828187894 + +So we have two input samples (INPUT_SAMPLE_L, INPUT_SAMPLE_R) every 22050hz. + +* IN MY EMULATION, I divide these by 2 to make it clip less. + (and of course the L/R output coefficients are adjusted to compensate) + The real thing appears to not do this. + +At every 22050hz tick: +- If the reverb bit is enabled (bit 7 of 1DAA), execute the reverb + steady-state algorithm described below +- AFTERWARDS, retrieve the "wet out" L and R samples from the reverb buffer + (This part may not be exactly right and I guessed at the coefs. TODO: check later.) + L is: 0.333 * (buffer[MIX_DEST_A0] + buffer[MIX_DEST_B0]) + R is: 0.333 * (buffer[MIX_DEST_A1] + buffer[MIX_DEST_B1]) +- Advance the current buffer position by 1 sample + +The wet out L and R are then upsampled to 44100hz and played at the +"reverberation depth left/right" (1D84/1D86) volume, independent of the main +volume. + +----------------------------------------------------------------------------- + +Reverb steady-state +------------------- + +The reverb steady-state algorithm is fairly clever, and of course by +"clever" I mean "batshit insane". + +buffer[x] is relative to the current buffer position, not the beginning of +the buffer. Note that all buffer offsets must wrap around so they're +contained within the reverb work area. + +Clipping is performed at the end... maybe also sooner, but definitely at +the end. + +IIR_INPUT_A0 = buffer[IIR_SRC_A0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L; +IIR_INPUT_A1 = buffer[IIR_SRC_A1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R; +IIR_INPUT_B0 = buffer[IIR_SRC_B0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L; +IIR_INPUT_B1 = buffer[IIR_SRC_B1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R; + +IIR_A0 = IIR_INPUT_A0 * IIR_ALPHA + buffer[IIR_DEST_A0] * (1.0 - IIR_ALPHA); +IIR_A1 = IIR_INPUT_A1 * IIR_ALPHA + buffer[IIR_DEST_A1] * (1.0 - IIR_ALPHA); +IIR_B0 = IIR_INPUT_B0 * IIR_ALPHA + buffer[IIR_DEST_B0] * (1.0 - IIR_ALPHA); +IIR_B1 = IIR_INPUT_B1 * IIR_ALPHA + buffer[IIR_DEST_B1] * (1.0 - IIR_ALPHA); + +buffer[IIR_DEST_A0 + 1sample] = IIR_A0; +buffer[IIR_DEST_A1 + 1sample] = IIR_A1; +buffer[IIR_DEST_B0 + 1sample] = IIR_B0; +buffer[IIR_DEST_B1 + 1sample] = IIR_B1; + +ACC0 = buffer[ACC_SRC_A0] * ACC_COEF_A + + buffer[ACC_SRC_B0] * ACC_COEF_B + + buffer[ACC_SRC_C0] * ACC_COEF_C + + buffer[ACC_SRC_D0] * ACC_COEF_D; +ACC1 = buffer[ACC_SRC_A1] * ACC_COEF_A + + buffer[ACC_SRC_B1] * ACC_COEF_B + + buffer[ACC_SRC_C1] * ACC_COEF_C + + buffer[ACC_SRC_D1] * ACC_COEF_D; + +FB_A0 = buffer[MIX_DEST_A0 - FB_SRC_A]; +FB_A1 = buffer[MIX_DEST_A1 - FB_SRC_A]; +FB_B0 = buffer[MIX_DEST_B0 - FB_SRC_B]; +FB_B1 = buffer[MIX_DEST_B1 - FB_SRC_B]; + +buffer[MIX_DEST_A0] = ACC0 - FB_A0 * FB_ALPHA; +buffer[MIX_DEST_A1] = ACC1 - FB_A1 * FB_ALPHA; +buffer[MIX_DEST_B0] = (FB_ALPHA * ACC0) - FB_A0 * (FB_ALPHA^0x8000) - FB_B0 * FB_X; +buffer[MIX_DEST_B1] = (FB_ALPHA * ACC1) - FB_A1 * (FB_ALPHA^0x8000) - FB_B1 * FB_X; + +----------------------------------------------------------------------------- +*/ diff --git a/plugins/spu2ghz/src/mixer.h b/plugins/spu2ghz/src/mixer.h index f92c947d60..ce809b95d3 100644 --- a/plugins/spu2ghz/src/mixer.h +++ b/plugins/spu2ghz/src/mixer.h @@ -1,26 +1,26 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -#ifndef MIXER_H_INCLUDED -#define MIXER_H_INCLUDED - -void __fastcall Mix(); - -void __fastcall LogVolInit(); -void __fastcall LogVolClose(); - -#endif // MIXER_H_INCLUDED // +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#ifndef MIXER_H_INCLUDED +#define MIXER_H_INCLUDED + +void __fastcall Mix(); + +void __fastcall LogVolInit(); +void __fastcall LogVolClose(); + +#endif // MIXER_H_INCLUDED // diff --git a/plugins/spu2ghz/src/regs.h b/plugins/spu2ghz/src/regs.h index dc53bb418e..455f1e82a1 100644 --- a/plugins/spu2ghz/src/regs.h +++ b/plugins/spu2ghz/src/regs.h @@ -1,184 +1,184 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -#ifndef REGS_H_INCLUDED -#define REGS_H_INCLUDED - -#define SPU2_CORE0 0x00000000 -#define SPU2_CORE1 0x00000400 - -#define SPU2_VP(voice) ((voice) * 16) -#define SPU2_VA(voice) ((voice) * 12) - -#define REG_VP_VOLL 0x0000 // Voice Volume Left -#define REG_VP_VOLR 0x0002 // Voice Volume Right -#define REG_VP_PITCH 0x0004 // Pitch -#define REG_VP_ADSR1 0x0006 // Envelope 1 (Attack-Decay-Sustain-Release) -#define REG_VP_ADSR2 0x0008 // Envelope 2 (Attack-Decay-Sustain-Release) -#define REG_VP_ENVX 0x000A // Current Envelope -#define REG_VP_VOLXL 0x000C // Current Voice Volume Left -#define REG_VP_VOLXR 0x000E // Current Voice Volume Right - -// .. repeated for each voice .. - -#define REG_S_PMON 0x0180 // Pitch Modulation Spec. -#define REG_S_NON 0x0184 // Alloc Noise Generator -#define REG_S_VMIXL 0x0188 // Voice Output Mix Left (Dry) -#define REG_S_VMIXEL 0x018C // Voice Output Mix Left (Wet) -#define REG_S_VMIXR 0x0190 // Voice Output Mix Right (Dry) -#define REG_S_VMIXER 0x0194 // Voice Output Mix Right (Wet) - -#define REG_P_MMIX 0x0198 // Output Spec. After Voice Mix -#define REG_C_ATTR 0x019A // Core X Attrib -#define REG_A_IRQA 0x019C // Interrupt Address Spec. - -#define REG_S_KON 0x01A0 // Key On 0/1 -#define REG_S_KOFF 0x01A4 // Key Off 0/1 - -#define REG_A_TSA 0x01A8 // Transfer starting address -#define REG__1AC 0x01AC // Transfer data -#define REG__1AE 0x01AE -#define REG_S_ADMAS 0x01B0 // AutoDMA Status - -// 1b2, 1b4, 1b6, 1b8, 1ba, 1bc, 1be are unknown - -#define REG_VA_SSA 0x01C0 // Waveform data starting address -#define REG_VA_LSAX 0x01C4 // Loop point address -#define REG_VA_NAX 0x01C8 // Waveform data that should be read next - -// .. repeated for each voice .. - -#define REG_A_ESA 0x02E0 //Address: Top address of working area for effects processing -#define R_FB_SRC_A 0x02E4 // Feedback Source A -#define R_FB_SRC_B 0x02E8 // Feedback Source B -#define R_IIR_DEST_A0 0x02EC -#define R_IIR_DEST_A1 0x02F0 -#define R_ACC_SRC_A0 0x02F4 -#define R_ACC_SRC_A1 0x02F8 -#define R_ACC_SRC_B0 0x02FC -#define R_ACC_SRC_B1 0x0300 -#define R_IIR_SRC_A0 0x0304 -#define R_IIR_SRC_A1 0x0308 -#define R_IIR_DEST_B0 0x030C -#define R_IIR_DEST_B1 0x0310 -#define R_ACC_SRC_C0 0x0314 -#define R_ACC_SRC_C1 0x0318 -#define R_ACC_SRC_D0 0x031C -#define R_ACC_SRC_D1 0x0320 -#define R_IIR_SRC_B1 0x0324 -#define R_IIR_SRC_B0 0x0328 -#define R_MIX_DEST_A0 0x032C -#define R_MIX_DEST_A1 0x0330 -#define R_MIX_DEST_B0 0x0334 -#define R_MIX_DEST_B1 0x0338 -#define REG_A_EEA 0x033C // Address: End address of working area for effects processing (upper part of address only!) - -#define REG_S_ENDX 0x0340 // End Point passed flag - -#define REG_P_STATX 0x0344 // Status register? - -// 0x346 .. 0x3fe are unknown (unused?) - -// core 1 has the same registers with 0x400 added. -// core 1 ends at 0x746 - -// 0x746 .. 0x75e are unknown - -// "Different" register area - -#define REG_P_MVOLL 0x0760 // Master Volume Left -#define REG_P_MVOLR 0x0762 // Master Volume Right -#define REG_P_EVOLL 0x0764 // Effect Volume Left -#define REG_P_EVOLR 0x0766 // Effect Volume Right -#define REG_P_AVOLL 0x0768 // Core External Input Volume Left (Only Core 1) -#define REG_P_AVOLR 0x076A // Core External Input Volume Right (Only Core 1) -#define REG_P_BVOLL 0x076C // Sound Data Volume Left -#define REG_P_BVOLR 0x076E // Sound Data Volume Right -#define REG_P_MVOLXL 0x0770 // Current Master Volume Left -#define REG_P_MVOLXR 0x0772 // Current Master Volume Right - -#define R_IIR_ALPHA 0x0774 //IIR alpha (% used) -#define R_ACC_COEF_A 0x0776 -#define R_ACC_COEF_B 0x0778 -#define R_ACC_COEF_C 0x077A -#define R_ACC_COEF_D 0x077C -#define R_IIR_COEF 0x077E -#define R_FB_ALPHA 0x0780 //feedback alpha (% used) -#define R_FB_X 0x0782 //feedback -#define R_IN_COEF_L 0x0784 -#define R_IN_COEF_R 0x0786 - -// values repeat for core1 - -// End OF "Different" register area - -// SPDIF interface -#define SPDIF_OUT 0x07C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass -#define IRQINFO 0x07C2 -#define SPDIF_MODE 0x07C6 -#define SPDIF_MEDIA 0x07C8 // SPDIF Media: 'CD'/DVD -#define SPDIF_COPY 0x07CC // SPDIF Copy Protection - - -/********************************************************************* -Core attributes (SD_C) - bit 1 - Unknown (this bit is sometimes set) - bit 2..3 - Unknown (usually never set) - bit 4..5 - DMA related - bit 6 - IRQ? DMA mode? wtf? - bit 7 - effect enable (reverb enable) - bit 8 - IRQ enable? - bit 9..14 - noise clock - bit 15 - mute - bit 16 - reset - -*********************************************************************/ - -#define SPDIF_OUT_OFF 0x0000 //no spdif output -#define SPDIF_OUT_PCM 0x0020 //encode spdif from spu2 pcm output -#define SPDIF_OUT_BYPASS 0x0100 //bypass spu2 processing - -#define SPDIF_MODE_BYPASS_BITSTREAM 0x0002 //bypass mode for digital bitstream data -#define SPDIF_MODE_BYPASS_PCM 0x0000 //bypass mode for pcm data (using analog output) - -#define SPDIF_MODE_MEDIA_CD 0x0800 //source media is a CD -#define SPDIF_MODE_MEDIA_DVD 0x0000 //source media is a DVD - -#define SPDIF_MEDIA_CDVD 0x0200 -#define SPDIF_MEDIA_400 0x0000 - -#define SPDIF_COPY_NORMAL 0x0000 // spdif stream is not protected -#define SPDIF_COPY_PROHIBIT 0x8000 // spdif stream can't be copied - -/********************************************************************/ - -#define VOICE_PARAM_VOLL 0x0 // Voice Volume Left -#define VOICE_PARAM_VOLR 0x2 // Voice Volume Right -#define VOICE_PARAM_PITCH 0x4 // Pitch -#define VOICE_PARAM_ADSR1 0x6 // Envelope 1 (Attack-Delay-Sustain-Release) -#define VOICE_PARAM_ADSR2 0x8 // Envelope 2 (Attack-Delay-Sustain-Release) -#define VOICE_PARAM_ENVX 0xA // Current Envelope -#define VOICE_PARAM_VOLXL 0xC // Current Voice Volume Left -#define VOICE_PARAM_VOLXR 0xE // Current Voice Volume Right - -/********************************************************************/ - -#define VOICE_ADDR_SSA 0x0 // Waveform data starting address -#define VOICE_ADDR_LSAX 0x4 // Loop point address -#define VOICE_ADDR_NAX 0x8 // Waveform data that should be read next - +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#ifndef REGS_H_INCLUDED +#define REGS_H_INCLUDED + +#define SPU2_CORE0 0x00000000 +#define SPU2_CORE1 0x00000400 + +#define SPU2_VP(voice) ((voice) * 16) +#define SPU2_VA(voice) ((voice) * 12) + +#define REG_VP_VOLL 0x0000 // Voice Volume Left +#define REG_VP_VOLR 0x0002 // Voice Volume Right +#define REG_VP_PITCH 0x0004 // Pitch +#define REG_VP_ADSR1 0x0006 // Envelope 1 (Attack-Decay-Sustain-Release) +#define REG_VP_ADSR2 0x0008 // Envelope 2 (Attack-Decay-Sustain-Release) +#define REG_VP_ENVX 0x000A // Current Envelope +#define REG_VP_VOLXL 0x000C // Current Voice Volume Left +#define REG_VP_VOLXR 0x000E // Current Voice Volume Right + +// .. repeated for each voice .. + +#define REG_S_PMON 0x0180 // Pitch Modulation Spec. +#define REG_S_NON 0x0184 // Alloc Noise Generator +#define REG_S_VMIXL 0x0188 // Voice Output Mix Left (Dry) +#define REG_S_VMIXEL 0x018C // Voice Output Mix Left (Wet) +#define REG_S_VMIXR 0x0190 // Voice Output Mix Right (Dry) +#define REG_S_VMIXER 0x0194 // Voice Output Mix Right (Wet) + +#define REG_P_MMIX 0x0198 // Output Spec. After Voice Mix +#define REG_C_ATTR 0x019A // Core X Attrib +#define REG_A_IRQA 0x019C // Interrupt Address Spec. + +#define REG_S_KON 0x01A0 // Key On 0/1 +#define REG_S_KOFF 0x01A4 // Key Off 0/1 + +#define REG_A_TSA 0x01A8 // Transfer starting address +#define REG__1AC 0x01AC // Transfer data +#define REG__1AE 0x01AE +#define REG_S_ADMAS 0x01B0 // AutoDMA Status + +// 1b2, 1b4, 1b6, 1b8, 1ba, 1bc, 1be are unknown + +#define REG_VA_SSA 0x01C0 // Waveform data starting address +#define REG_VA_LSAX 0x01C4 // Loop point address +#define REG_VA_NAX 0x01C8 // Waveform data that should be read next + +// .. repeated for each voice .. + +#define REG_A_ESA 0x02E0 //Address: Top address of working area for effects processing +#define R_FB_SRC_A 0x02E4 // Feedback Source A +#define R_FB_SRC_B 0x02E8 // Feedback Source B +#define R_IIR_DEST_A0 0x02EC +#define R_IIR_DEST_A1 0x02F0 +#define R_ACC_SRC_A0 0x02F4 +#define R_ACC_SRC_A1 0x02F8 +#define R_ACC_SRC_B0 0x02FC +#define R_ACC_SRC_B1 0x0300 +#define R_IIR_SRC_A0 0x0304 +#define R_IIR_SRC_A1 0x0308 +#define R_IIR_DEST_B0 0x030C +#define R_IIR_DEST_B1 0x0310 +#define R_ACC_SRC_C0 0x0314 +#define R_ACC_SRC_C1 0x0318 +#define R_ACC_SRC_D0 0x031C +#define R_ACC_SRC_D1 0x0320 +#define R_IIR_SRC_B1 0x0324 +#define R_IIR_SRC_B0 0x0328 +#define R_MIX_DEST_A0 0x032C +#define R_MIX_DEST_A1 0x0330 +#define R_MIX_DEST_B0 0x0334 +#define R_MIX_DEST_B1 0x0338 +#define REG_A_EEA 0x033C // Address: End address of working area for effects processing (upper part of address only!) + +#define REG_S_ENDX 0x0340 // End Point passed flag + +#define REG_P_STATX 0x0344 // Status register? + +// 0x346 .. 0x3fe are unknown (unused?) + +// core 1 has the same registers with 0x400 added. +// core 1 ends at 0x746 + +// 0x746 .. 0x75e are unknown + +// "Different" register area + +#define REG_P_MVOLL 0x0760 // Master Volume Left +#define REG_P_MVOLR 0x0762 // Master Volume Right +#define REG_P_EVOLL 0x0764 // Effect Volume Left +#define REG_P_EVOLR 0x0766 // Effect Volume Right +#define REG_P_AVOLL 0x0768 // Core External Input Volume Left (Only Core 1) +#define REG_P_AVOLR 0x076A // Core External Input Volume Right (Only Core 1) +#define REG_P_BVOLL 0x076C // Sound Data Volume Left +#define REG_P_BVOLR 0x076E // Sound Data Volume Right +#define REG_P_MVOLXL 0x0770 // Current Master Volume Left +#define REG_P_MVOLXR 0x0772 // Current Master Volume Right + +#define R_IIR_ALPHA 0x0774 //IIR alpha (% used) +#define R_ACC_COEF_A 0x0776 +#define R_ACC_COEF_B 0x0778 +#define R_ACC_COEF_C 0x077A +#define R_ACC_COEF_D 0x077C +#define R_IIR_COEF 0x077E +#define R_FB_ALPHA 0x0780 //feedback alpha (% used) +#define R_FB_X 0x0782 //feedback +#define R_IN_COEF_L 0x0784 +#define R_IN_COEF_R 0x0786 + +// values repeat for core1 + +// End OF "Different" register area + +// SPDIF interface +#define SPDIF_OUT 0x07C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass +#define IRQINFO 0x07C2 +#define SPDIF_MODE 0x07C6 +#define SPDIF_MEDIA 0x07C8 // SPDIF Media: 'CD'/DVD +#define SPDIF_COPY 0x07CC // SPDIF Copy Protection + + +/********************************************************************* +Core attributes (SD_C) + bit 1 - Unknown (this bit is sometimes set) + bit 2..3 - Unknown (usually never set) + bit 4..5 - DMA related + bit 6 - IRQ? DMA mode? wtf? + bit 7 - effect enable (reverb enable) + bit 8 - IRQ enable? + bit 9..14 - noise clock + bit 15 - mute + bit 16 - reset + +*********************************************************************/ + +#define SPDIF_OUT_OFF 0x0000 //no spdif output +#define SPDIF_OUT_PCM 0x0020 //encode spdif from spu2 pcm output +#define SPDIF_OUT_BYPASS 0x0100 //bypass spu2 processing + +#define SPDIF_MODE_BYPASS_BITSTREAM 0x0002 //bypass mode for digital bitstream data +#define SPDIF_MODE_BYPASS_PCM 0x0000 //bypass mode for pcm data (using analog output) + +#define SPDIF_MODE_MEDIA_CD 0x0800 //source media is a CD +#define SPDIF_MODE_MEDIA_DVD 0x0000 //source media is a DVD + +#define SPDIF_MEDIA_CDVD 0x0200 +#define SPDIF_MEDIA_400 0x0000 + +#define SPDIF_COPY_NORMAL 0x0000 // spdif stream is not protected +#define SPDIF_COPY_PROHIBIT 0x8000 // spdif stream can't be copied + +/********************************************************************/ + +#define VOICE_PARAM_VOLL 0x0 // Voice Volume Left +#define VOICE_PARAM_VOLR 0x2 // Voice Volume Right +#define VOICE_PARAM_PITCH 0x4 // Pitch +#define VOICE_PARAM_ADSR1 0x6 // Envelope 1 (Attack-Delay-Sustain-Release) +#define VOICE_PARAM_ADSR2 0x8 // Envelope 2 (Attack-Delay-Sustain-Release) +#define VOICE_PARAM_ENVX 0xA // Current Envelope +#define VOICE_PARAM_VOLXL 0xC // Current Voice Volume Left +#define VOICE_PARAM_VOLXR 0xE // Current Voice Volume Right + +/********************************************************************/ + +#define VOICE_ADDR_SSA 0x0 // Waveform data starting address +#define VOICE_ADDR_LSAX 0x4 // Loop point address +#define VOICE_ADDR_NAX 0x8 // Waveform data that should be read next + #endif // REGS_H_INCLUDED // \ No newline at end of file diff --git a/plugins/spu2ghz/src/regtable.cpp b/plugins/spu2ghz/src/regtable.cpp new file mode 100644 index 0000000000..a90adeb969 --- /dev/null +++ b/plugins/spu2ghz/src/regtable.cpp @@ -0,0 +1,276 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#include "spu2.h" +#include "regtable.h" + +u16* regtable[] = +{ + // Voice Params: 8 params, 24 voices = 0x180 bytes + PVC(0, 0),PVC(0, 1),PVC(0, 2),PVC(0, 3),PVC(0, 4),PVC(0, 5), + PVC(0, 6),PVC(0, 7),PVC(0, 8),PVC(0, 9),PVC(0,10),PVC(0,11), + PVC(0,12),PVC(0,13),PVC(0,14),PVC(0,15),PVC(0,16),PVC(0,17), + PVC(0,18),PVC(0,19),PVC(0,20),PVC(0,21),PVC(0,22),PVC(0,23), + + PCORE(0,Regs.PMON), + PCORE(0,Regs.PMON)+1, + PCORE(0,Regs.NON), + PCORE(0,Regs.NON)+1, + PCORE(0,Regs.VMIXL), + PCORE(0,Regs.VMIXL)+1, + PCORE(0,Regs.VMIXEL), + PCORE(0,Regs.VMIXEL)+1, + PCORE(0,Regs.VMIXR), + PCORE(0,Regs.VMIXR)+1, + PCORE(0,Regs.VMIXER), + PCORE(0,Regs.VMIXER)+1, + PCORE(0,Regs.MMIX), + + PCORE(0,Regs.ATTR), + + PCORE(0,IRQA)+1, + PCORE(0,IRQA), + + U16P(zero), + U16P(zero), + U16P(zero), + U16P(zero), + + PCORE(0,TSA)+1, + PCORE(0,TSA), + + PRAW(0x1ac), PRAW(0x1ae), + + PCORE(0,AutoDMACtrl), + + PRAW(0x1b2), PRAW(0x1b4), PRAW(0x1b6), PRAW(0x1b8), PRAW(0x1ba), PRAW(0x1bc), PRAW(0x1be), // unknown + + // Voice Addresses + PVCA(0, 0),PVCA(0, 1),PVCA(0, 2),PVCA(0, 3),PVCA(0, 4),PVCA(0, 5), + PVCA(0, 6),PVCA(0, 7),PVCA(0, 8),PVCA(0, 9),PVCA(0,10),PVCA(0,11), + PVCA(0,12),PVCA(0,13),PVCA(0,14),PVCA(0,15),PVCA(0,16),PVCA(0,17), + PVCA(0,18),PVCA(0,19),PVCA(0,20),PVCA(0,21),PVCA(0,22),PVCA(0,23), + + PCORE(0,EffectsStartA)+1, + PCORE(0,EffectsStartA), + + PREVB_REG(0,FB_SRC_A), + PREVB_REG(0,FB_SRC_B), + PREVB_REG(0,IIR_SRC_A0), + PREVB_REG(0,IIR_SRC_A1), + PREVB_REG(0,IIR_SRC_B1), + PREVB_REG(0,IIR_SRC_B0), + PREVB_REG(0,IIR_DEST_A0), + PREVB_REG(0,IIR_DEST_A1), + PREVB_REG(0,IIR_DEST_B0), + PREVB_REG(0,IIR_DEST_B1), + PREVB_REG(0,ACC_SRC_A0), + PREVB_REG(0,ACC_SRC_A1), + PREVB_REG(0,ACC_SRC_B0), + PREVB_REG(0,ACC_SRC_B1), + PREVB_REG(0,ACC_SRC_C0), + PREVB_REG(0,ACC_SRC_C1), + PREVB_REG(0,ACC_SRC_D0), + PREVB_REG(0,ACC_SRC_D1), + PREVB_REG(0,MIX_DEST_A0), + PREVB_REG(0,MIX_DEST_A1), + PREVB_REG(0,MIX_DEST_B0), + PREVB_REG(0,MIX_DEST_B1), + + PCORE(0,EffectsEndA)+1, + U16P(zero), + + PCORE(0,Regs.ENDX), + PCORE(0,Regs.ENDX)+1, + PCORE(0,Regs.STATX), + + //0x346 here + PRAW(0x346), + PRAW(0x348),PRAW(0x34A),PRAW(0x34C),PRAW(0x34E), + PRAW(0x350),PRAW(0x352),PRAW(0x354),PRAW(0x356), + PRAW(0x358),PRAW(0x35A),PRAW(0x35C),PRAW(0x35E), + PRAW(0x360),PRAW(0x362),PRAW(0x364),PRAW(0x366), + PRAW(0x368),PRAW(0x36A),PRAW(0x36C),PRAW(0x36E), + PRAW(0x370),PRAW(0x372),PRAW(0x374),PRAW(0x376), + PRAW(0x378),PRAW(0x37A),PRAW(0x37C),PRAW(0x37E), + PRAW(0x380),PRAW(0x382),PRAW(0x384),PRAW(0x386), + PRAW(0x388),PRAW(0x38A),PRAW(0x38C),PRAW(0x38E), + PRAW(0x390),PRAW(0x392),PRAW(0x394),PRAW(0x396), + PRAW(0x398),PRAW(0x39A),PRAW(0x39C),PRAW(0x39E), + PRAW(0x3A0),PRAW(0x3A2),PRAW(0x3A4),PRAW(0x3A6), + PRAW(0x3A8),PRAW(0x3AA),PRAW(0x3AC),PRAW(0x3AE), + PRAW(0x3B0),PRAW(0x3B2),PRAW(0x3B4),PRAW(0x3B6), + PRAW(0x3B8),PRAW(0x3BA),PRAW(0x3BC),PRAW(0x3BE), + PRAW(0x3C0),PRAW(0x3C2),PRAW(0x3C4),PRAW(0x3C6), + PRAW(0x3C8),PRAW(0x3CA),PRAW(0x3CC),PRAW(0x3CE), + PRAW(0x3D0),PRAW(0x3D2),PRAW(0x3D4),PRAW(0x3D6), + PRAW(0x3D8),PRAW(0x3DA),PRAW(0x3DC),PRAW(0x3DE), + PRAW(0x3E0),PRAW(0x3E2),PRAW(0x3E4),PRAW(0x3E6), + PRAW(0x3E8),PRAW(0x3EA),PRAW(0x3EC),PRAW(0x3EE), + PRAW(0x3F0),PRAW(0x3F2),PRAW(0x3F4),PRAW(0x3F6), + PRAW(0x3F8),PRAW(0x3FA),PRAW(0x3FC),PRAW(0x3FE), + + //AND... we reached 0x400! + // Voice Params: 8 params, 24 voices = 0x180 bytes + PVC(1, 0),PVC(1, 1),PVC(1, 2),PVC(1, 3),PVC(1, 4),PVC(1, 5), + PVC(1, 6),PVC(1, 7),PVC(1, 8),PVC(1, 9),PVC(1,10),PVC(1,11), + PVC(1,12),PVC(1,13),PVC(1,14),PVC(1,15),PVC(1,16),PVC(1,17), + PVC(1,18),PVC(1,19),PVC(1,20),PVC(1,21),PVC(1,22),PVC(1,23), + + PCORE(1,Regs.PMON), + PCORE(1,Regs.PMON)+1, + PCORE(1,Regs.NON), + PCORE(1,Regs.NON)+1, + PCORE(1,Regs.VMIXL), + PCORE(1,Regs.VMIXL)+1, + PCORE(1,Regs.VMIXEL), + PCORE(1,Regs.VMIXEL)+1, + PCORE(1,Regs.VMIXR), + PCORE(1,Regs.VMIXR)+1, + PCORE(1,Regs.VMIXER), + PCORE(1,Regs.VMIXER)+1, + PCORE(1,Regs.MMIX), + + PCORE(1,Regs.ATTR), + + PCORE(1,IRQA)+1, + PCORE(1,IRQA), + + U16P(zero), + U16P(zero), + U16P(zero), + U16P(zero), + + PCORE(1,TSA)+1, + PCORE(1,TSA), + + PRAW(0x5ac), PRAW(0x5ae), + + PCORE(1,AutoDMACtrl), + + PRAW(0x5b2), PRAW(0x5b4), PRAW(0x5b6), PRAW(0x5b8), PRAW(0x5ba), PRAW(0x5bc), PRAW(0x5be), // unknown + + // Voice Addresses + PVCA(1, 0),PVCA(1, 1),PVCA(1, 2),PVCA(1, 3),PVCA(1, 4),PVCA(1, 5), + PVCA(1, 6),PVCA(1, 7),PVCA(1, 8),PVCA(1, 9),PVCA(1,10),PVCA(1,11), + PVCA(1,12),PVCA(1,13),PVCA(1,14),PVCA(1,15),PVCA(1,16),PVCA(1,17), + PVCA(1,18),PVCA(1,19),PVCA(1,20),PVCA(1,21),PVCA(1,22),PVCA(1,23), + + PCORE(1,EffectsStartA)+1, + PCORE(1,EffectsStartA), + + PREVB_REG(1,FB_SRC_A), + PREVB_REG(1,FB_SRC_B), + PREVB_REG(1,IIR_SRC_A0), + PREVB_REG(1,IIR_SRC_A1), + PREVB_REG(1,IIR_SRC_B1), + PREVB_REG(1,IIR_SRC_B0), + PREVB_REG(1,IIR_DEST_A0), + PREVB_REG(1,IIR_DEST_A1), + PREVB_REG(1,IIR_DEST_B0), + PREVB_REG(1,IIR_DEST_B1), + PREVB_REG(1,ACC_SRC_A0), + PREVB_REG(1,ACC_SRC_A1), + PREVB_REG(1,ACC_SRC_B0), + PREVB_REG(1,ACC_SRC_B1), + PREVB_REG(1,ACC_SRC_C0), + PREVB_REG(1,ACC_SRC_C1), + PREVB_REG(1,ACC_SRC_D0), + PREVB_REG(1,ACC_SRC_D1), + PREVB_REG(1,MIX_DEST_A0), + PREVB_REG(1,MIX_DEST_A1), + PREVB_REG(1,MIX_DEST_B0), + PREVB_REG(1,MIX_DEST_B1), + + PCORE(1,EffectsEndA)+1, + U16P(zero), + + PCORE(1,Regs.ENDX), + PCORE(1,Regs.ENDX)+1, + PCORE(1,Regs.STATX), + + PRAW(0x746), + PRAW(0x748),PRAW(0x74A),PRAW(0x74C),PRAW(0x74E), + PRAW(0x750),PRAW(0x752),PRAW(0x754),PRAW(0x756), + PRAW(0x758),PRAW(0x75A),PRAW(0x75C),PRAW(0x75E), + + //0x760: weird area + PCORE(0,MasterL.Reg_VOL), + PCORE(0,MasterR.Reg_VOL), + PCORE(0,FxL), + PCORE(0,FxR), + PCORE(0,ExtL), + PCORE(0,ExtR), + PCORE(0,InpL), + PCORE(0,InpR), + PCORE(0,MasterL.Value), + PCORE(0,MasterR.Value), + PCORE(0,Revb.IIR_ALPHA), + PCORE(0,Revb.ACC_COEF_A), + PCORE(0,Revb.ACC_COEF_B), + PCORE(0,Revb.ACC_COEF_C), + PCORE(0,Revb.ACC_COEF_D), + PCORE(0,Revb.IIR_COEF), + PCORE(0,Revb.FB_ALPHA), + PCORE(0,Revb.FB_X), + PCORE(0,Revb.IN_COEF_L), + PCORE(0,Revb.IN_COEF_R), + + PCORE(1,MasterL.Reg_VOL), + PCORE(1,MasterR.Reg_VOL), + PCORE(1,FxL), + PCORE(1,FxR), + PCORE(1,ExtL), + PCORE(1,ExtR), + PCORE(1,InpL), + PCORE(1,InpR), + PCORE(1,MasterL.Value), + PCORE(1,MasterR.Value), + PCORE(1,Revb.IIR_ALPHA), + PCORE(1,Revb.ACC_COEF_A), + PCORE(1,Revb.ACC_COEF_B), + PCORE(1,Revb.ACC_COEF_C), + PCORE(1,Revb.ACC_COEF_D), + PCORE(1,Revb.IIR_COEF), + PCORE(1,Revb.FB_ALPHA), + PCORE(1,Revb.FB_X), + PCORE(1,Revb.IN_COEF_L), + PCORE(1,Revb.IN_COEF_R), + + PRAW(0x7B0),PRAW(0x7B2),PRAW(0x7B4),PRAW(0x7B6), + PRAW(0x7B8),PRAW(0x7BA),PRAW(0x7BC),PRAW(0x7BE), + + // SPDIF interface + U16P(Spdif.Out), + U16P(Spdif.Info), + U16P(Spdif.Unknown1), + U16P(Spdif.Mode), + U16P(Spdif.Media), + U16P(Spdif.Unknown2), + U16P(Spdif.Protection), + + PRAW(0x7CE), + PRAW(0x7D0),PRAW(0x7D2),PRAW(0x7D4),PRAW(0x7D6), + PRAW(0x7D8),PRAW(0x7DA),PRAW(0x7DC),PRAW(0x7DE), + PRAW(0x7E0),PRAW(0x7E2),PRAW(0x7E4),PRAW(0x7E6), + PRAW(0x7E8),PRAW(0x7EA),PRAW(0x7EC),PRAW(0x7EE), + PRAW(0x7F0),PRAW(0x7F2),PRAW(0x7F4),PRAW(0x7F6), + PRAW(0x7F8),PRAW(0x7FA),PRAW(0x7FC),PRAW(0x7FE), + + U16P(zero) +}; diff --git a/plugins/spu2ghz/src/regtable.h b/plugins/spu2ghz/src/regtable.h index ea962fe19c..096709db9a 100644 --- a/plugins/spu2ghz/src/regtable.h +++ b/plugins/spu2ghz/src/regtable.h @@ -1,308 +1,60 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// - -#define U16P(x) ((u16*)&(x)) - -#define PCORE(c,p) \ - U16P(Cores[c].##p) - -#define PVCP(c,v,p) \ - PCORE(c,Voices[v].##p) - -#define PVC(c,v) \ - PVCP(c,v,VolumeL.Reg_VOL), \ - PVCP(c,v,VolumeR.Reg_VOL), \ - PVCP(c,v,Pitch), \ - PVCP(c,v,ADSR.Reg_ADSR1), \ - PVCP(c,v,ADSR.Reg_ADSR2), \ - PVCP(c,v,ADSR.Value)+1, \ - PVCP(c,v,VolumeL.Value), \ - PVCP(c,v,VolumeR.Value) - -#define PVCA(c,v) \ - PVCP(c,v,StartA)+1, \ - PVCP(c,v,StartA), \ - PVCP(c,v,LoopStartA)+1, \ - PVCP(c,v,LoopStartA), \ - PVCP(c,v,NextA)+1, \ - PVCP(c,v,NextA) - -#define PRAW(a) \ - ((u16*)NULL) - -#define PREVB_REG(c,n) \ - PCORE(c,Revb.##n)+1, \ - PCORE(c,Revb.##n) - -const u16 zero=0; - -#pragma pack(push,1) -u16* /*const*/ regtable[] = { - // Voice Params: 8 params, 24 voices = 0x180 bytes - PVC(0, 0),PVC(0, 1),PVC(0, 2),PVC(0, 3),PVC(0, 4),PVC(0, 5), - PVC(0, 6),PVC(0, 7),PVC(0, 8),PVC(0, 9),PVC(0,10),PVC(0,11), - PVC(0,12),PVC(0,13),PVC(0,14),PVC(0,15),PVC(0,16),PVC(0,17), - PVC(0,18),PVC(0,19),PVC(0,20),PVC(0,21),PVC(0,22),PVC(0,23), - - PCORE(0,Regs.PMON), - PCORE(0,Regs.PMON)+1, - PCORE(0,Regs.NON), - PCORE(0,Regs.NON)+1, - PCORE(0,Regs.VMIXL), - PCORE(0,Regs.VMIXL)+1, - PCORE(0,Regs.VMIXEL), - PCORE(0,Regs.VMIXEL)+1, - PCORE(0,Regs.VMIXR), - PCORE(0,Regs.VMIXR)+1, - PCORE(0,Regs.VMIXER), - PCORE(0,Regs.VMIXER)+1, - PCORE(0,Regs.MMIX), - - PCORE(0,Regs.ATTR), - - PCORE(0,IRQA)+1, - PCORE(0,IRQA), - - U16P(zero), - U16P(zero), - U16P(zero), - U16P(zero), - - PCORE(0,TSA)+1, - PCORE(0,TSA), - - PRAW(0x1ac), PRAW(0x1ae), - - PCORE(0,AutoDMACtrl), - - PRAW(0x1b2), PRAW(0x1b4), PRAW(0x1b6), PRAW(0x1b8), PRAW(0x1ba), PRAW(0x1bc), PRAW(0x1be), // unknown - - // Voice Addresses - PVCA(0, 0),PVCA(0, 1),PVCA(0, 2),PVCA(0, 3),PVCA(0, 4),PVCA(0, 5), - PVCA(0, 6),PVCA(0, 7),PVCA(0, 8),PVCA(0, 9),PVCA(0,10),PVCA(0,11), - PVCA(0,12),PVCA(0,13),PVCA(0,14),PVCA(0,15),PVCA(0,16),PVCA(0,17), - PVCA(0,18),PVCA(0,19),PVCA(0,20),PVCA(0,21),PVCA(0,22),PVCA(0,23), - - PCORE(0,EffectsStartA)+1, - PCORE(0,EffectsStartA), - - PREVB_REG(0,FB_SRC_A), - PREVB_REG(0,FB_SRC_B), - PREVB_REG(0,IIR_SRC_A0), - PREVB_REG(0,IIR_SRC_A1), - PREVB_REG(0,IIR_SRC_B1), - PREVB_REG(0,IIR_SRC_B0), - PREVB_REG(0,IIR_DEST_A0), - PREVB_REG(0,IIR_DEST_A1), - PREVB_REG(0,IIR_DEST_B0), - PREVB_REG(0,IIR_DEST_B1), - PREVB_REG(0,ACC_SRC_A0), - PREVB_REG(0,ACC_SRC_A1), - PREVB_REG(0,ACC_SRC_B0), - PREVB_REG(0,ACC_SRC_B1), - PREVB_REG(0,ACC_SRC_C0), - PREVB_REG(0,ACC_SRC_C1), - PREVB_REG(0,ACC_SRC_D0), - PREVB_REG(0,ACC_SRC_D1), - PREVB_REG(0,MIX_DEST_A0), - PREVB_REG(0,MIX_DEST_A1), - PREVB_REG(0,MIX_DEST_B0), - PREVB_REG(0,MIX_DEST_B1), - - PCORE(0,EffectsEndA)+1, - U16P(zero), - - PCORE(0,Regs.ENDX), - PCORE(0,Regs.ENDX)+1, - PCORE(0,Regs.STATX), - - //0x346 here - PRAW(0x346), - PRAW(0x348),PRAW(0x34A),PRAW(0x34C),PRAW(0x34E), - PRAW(0x350),PRAW(0x352),PRAW(0x354),PRAW(0x356), - PRAW(0x358),PRAW(0x35A),PRAW(0x35C),PRAW(0x35E), - PRAW(0x360),PRAW(0x362),PRAW(0x364),PRAW(0x366), - PRAW(0x368),PRAW(0x36A),PRAW(0x36C),PRAW(0x36E), - PRAW(0x370),PRAW(0x372),PRAW(0x374),PRAW(0x376), - PRAW(0x378),PRAW(0x37A),PRAW(0x37C),PRAW(0x37E), - PRAW(0x380),PRAW(0x382),PRAW(0x384),PRAW(0x386), - PRAW(0x388),PRAW(0x38A),PRAW(0x38C),PRAW(0x38E), - PRAW(0x390),PRAW(0x392),PRAW(0x394),PRAW(0x396), - PRAW(0x398),PRAW(0x39A),PRAW(0x39C),PRAW(0x39E), - PRAW(0x3A0),PRAW(0x3A2),PRAW(0x3A4),PRAW(0x3A6), - PRAW(0x3A8),PRAW(0x3AA),PRAW(0x3AC),PRAW(0x3AE), - PRAW(0x3B0),PRAW(0x3B2),PRAW(0x3B4),PRAW(0x3B6), - PRAW(0x3B8),PRAW(0x3BA),PRAW(0x3BC),PRAW(0x3BE), - PRAW(0x3C0),PRAW(0x3C2),PRAW(0x3C4),PRAW(0x3C6), - PRAW(0x3C8),PRAW(0x3CA),PRAW(0x3CC),PRAW(0x3CE), - PRAW(0x3D0),PRAW(0x3D2),PRAW(0x3D4),PRAW(0x3D6), - PRAW(0x3D8),PRAW(0x3DA),PRAW(0x3DC),PRAW(0x3DE), - PRAW(0x3E0),PRAW(0x3E2),PRAW(0x3E4),PRAW(0x3E6), - PRAW(0x3E8),PRAW(0x3EA),PRAW(0x3EC),PRAW(0x3EE), - PRAW(0x3F0),PRAW(0x3F2),PRAW(0x3F4),PRAW(0x3F6), - PRAW(0x3F8),PRAW(0x3FA),PRAW(0x3FC),PRAW(0x3FE), - - //AND... we reached 0x400! - // Voice Params: 8 params, 24 voices = 0x180 bytes - PVC(1, 0),PVC(1, 1),PVC(1, 2),PVC(1, 3),PVC(1, 4),PVC(1, 5), - PVC(1, 6),PVC(1, 7),PVC(1, 8),PVC(1, 9),PVC(1,10),PVC(1,11), - PVC(1,12),PVC(1,13),PVC(1,14),PVC(1,15),PVC(1,16),PVC(1,17), - PVC(1,18),PVC(1,19),PVC(1,20),PVC(1,21),PVC(1,22),PVC(1,23), - - PCORE(1,Regs.PMON), - PCORE(1,Regs.PMON)+1, - PCORE(1,Regs.NON), - PCORE(1,Regs.NON)+1, - PCORE(1,Regs.VMIXL), - PCORE(1,Regs.VMIXL)+1, - PCORE(1,Regs.VMIXEL), - PCORE(1,Regs.VMIXEL)+1, - PCORE(1,Regs.VMIXR), - PCORE(1,Regs.VMIXR)+1, - PCORE(1,Regs.VMIXER), - PCORE(1,Regs.VMIXER)+1, - PCORE(1,Regs.MMIX), - - PCORE(1,Regs.ATTR), - - PCORE(1,IRQA)+1, - PCORE(1,IRQA), - - U16P(zero), - U16P(zero), - U16P(zero), - U16P(zero), - - PCORE(1,TSA)+1, - PCORE(1,TSA), - - PRAW(0x5ac), PRAW(0x5ae), - - PCORE(1,AutoDMACtrl), - - PRAW(0x5b2), PRAW(0x5b4), PRAW(0x5b6), PRAW(0x5b8), PRAW(0x5ba), PRAW(0x5bc), PRAW(0x5be), // unknown - - // Voice Addresses - PVCA(1, 0),PVCA(1, 1),PVCA(1, 2),PVCA(1, 3),PVCA(1, 4),PVCA(1, 5), - PVCA(1, 6),PVCA(1, 7),PVCA(1, 8),PVCA(1, 9),PVCA(1,10),PVCA(1,11), - PVCA(1,12),PVCA(1,13),PVCA(1,14),PVCA(1,15),PVCA(1,16),PVCA(1,17), - PVCA(1,18),PVCA(1,19),PVCA(1,20),PVCA(1,21),PVCA(1,22),PVCA(1,23), - - PCORE(1,EffectsStartA)+1, - PCORE(1,EffectsStartA), - - PREVB_REG(1,FB_SRC_A), - PREVB_REG(1,FB_SRC_B), - PREVB_REG(1,IIR_SRC_A0), - PREVB_REG(1,IIR_SRC_A1), - PREVB_REG(1,IIR_SRC_B1), - PREVB_REG(1,IIR_SRC_B0), - PREVB_REG(1,IIR_DEST_A0), - PREVB_REG(1,IIR_DEST_A1), - PREVB_REG(1,IIR_DEST_B0), - PREVB_REG(1,IIR_DEST_B1), - PREVB_REG(1,ACC_SRC_A0), - PREVB_REG(1,ACC_SRC_A1), - PREVB_REG(1,ACC_SRC_B0), - PREVB_REG(1,ACC_SRC_B1), - PREVB_REG(1,ACC_SRC_C0), - PREVB_REG(1,ACC_SRC_C1), - PREVB_REG(1,ACC_SRC_D0), - PREVB_REG(1,ACC_SRC_D1), - PREVB_REG(1,MIX_DEST_A0), - PREVB_REG(1,MIX_DEST_A1), - PREVB_REG(1,MIX_DEST_B0), - PREVB_REG(1,MIX_DEST_B1), - - PCORE(1,EffectsEndA)+1, - U16P(zero), - - PCORE(1,Regs.ENDX), - PCORE(1,Regs.ENDX)+1, - PCORE(1,Regs.STATX), - - PRAW(0x746), - PRAW(0x748),PRAW(0x74A),PRAW(0x74C),PRAW(0x74E), - PRAW(0x750),PRAW(0x752),PRAW(0x754),PRAW(0x756), - PRAW(0x758),PRAW(0x75A),PRAW(0x75C),PRAW(0x75E), - - //0x760: weird area - PCORE(0,MasterL.Reg_VOL), - PCORE(0,MasterR.Reg_VOL), - PCORE(0,FxL), - PCORE(0,FxR), - PCORE(0,ExtL), - PCORE(0,ExtR), - PCORE(0,InpL), - PCORE(0,InpR), - PCORE(0,MasterL.Value), - PCORE(0,MasterR.Value), - PCORE(0,Revb.IIR_ALPHA), - PCORE(0,Revb.ACC_COEF_A), - PCORE(0,Revb.ACC_COEF_B), - PCORE(0,Revb.ACC_COEF_C), - PCORE(0,Revb.ACC_COEF_D), - PCORE(0,Revb.IIR_COEF), - PCORE(0,Revb.FB_ALPHA), - PCORE(0,Revb.FB_X), - PCORE(0,Revb.IN_COEF_L), - PCORE(0,Revb.IN_COEF_R), - - PCORE(1,MasterL.Reg_VOL), - PCORE(1,MasterR.Reg_VOL), - PCORE(1,FxL), - PCORE(1,FxR), - PCORE(1,ExtL), - PCORE(1,ExtR), - PCORE(1,InpL), - PCORE(1,InpR), - PCORE(1,MasterL.Value), - PCORE(1,MasterR.Value), - PCORE(1,Revb.IIR_ALPHA), - PCORE(1,Revb.ACC_COEF_A), - PCORE(1,Revb.ACC_COEF_B), - PCORE(1,Revb.ACC_COEF_C), - PCORE(1,Revb.ACC_COEF_D), - PCORE(1,Revb.IIR_COEF), - PCORE(1,Revb.FB_ALPHA), - PCORE(1,Revb.FB_X), - PCORE(1,Revb.IN_COEF_L), - PCORE(1,Revb.IN_COEF_R), - - PRAW(0x7B0),PRAW(0x7B2),PRAW(0x7B4),PRAW(0x7B6), - PRAW(0x7B8),PRAW(0x7BA),PRAW(0x7BC),PRAW(0x7BE), - - // SPDIF interface - U16P(Spdif.Out), - U16P(Spdif.Info), - U16P(Spdif.Unknown1), - U16P(Spdif.Mode), - U16P(Spdif.Media), - U16P(Spdif.Unknown2), - U16P(Spdif.Protection), - - PRAW(0x7CE), - PRAW(0x7D0),PRAW(0x7D2),PRAW(0x7D4),PRAW(0x7D6), - PRAW(0x7D8),PRAW(0x7DA),PRAW(0x7DC),PRAW(0x7DE), - PRAW(0x7E0),PRAW(0x7E2),PRAW(0x7E4),PRAW(0x7E6), - PRAW(0x7E8),PRAW(0x7EA),PRAW(0x7EC),PRAW(0x7EE), - PRAW(0x7F0),PRAW(0x7F2),PRAW(0x7F4),PRAW(0x7F6), - PRAW(0x7F8),PRAW(0x7FA),PRAW(0x7FC),PRAW(0x7FE), - - U16P(zero) -}; +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#ifndef _REGTABLE_H_ +#define _REGTABLE_H_ + +#define U16P(x) ((u16*)&(x)) + +#define PCORE(c,p) \ + U16P(Cores[c].##p) + +#define PVCP(c,v,p) \ + PCORE(c,Voices[v].##p) + +#define PVC(c,v) \ + PVCP(c,v,VolumeL.Reg_VOL), \ + PVCP(c,v,VolumeR.Reg_VOL), \ + PVCP(c,v,Pitch), \ + PVCP(c,v,ADSR.Reg_ADSR1), \ + PVCP(c,v,ADSR.Reg_ADSR2), \ + PVCP(c,v,ADSR.Value)+1, \ + PVCP(c,v,VolumeL.Value), \ + PVCP(c,v,VolumeR.Value) + +#define PVCA(c,v) \ + PVCP(c,v,StartA)+1, \ + PVCP(c,v,StartA), \ + PVCP(c,v,LoopStartA)+1, \ + PVCP(c,v,LoopStartA), \ + PVCP(c,v,NextA)+1, \ + PVCP(c,v,NextA) + +#define PRAW(a) \ + ((u16*)NULL) + +#define PREVB_REG(c,n) \ + PCORE(c,Revb.##n)+1, \ + PCORE(c,Revb.##n) + +// Yay! Global namespace pollution 101! +static const u16 zero=0; + +extern u16* regtable[]; + +#endif \ No newline at end of file diff --git a/plugins/spu2ghz/src/savestate.cpp b/plugins/spu2ghz/src/savestate.cpp new file mode 100644 index 0000000000..756b2199c1 --- /dev/null +++ b/plugins/spu2ghz/src/savestate.cpp @@ -0,0 +1,244 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#include "SPU2.h" + +struct SPU2freezeData +{ + u32 version; + u8 unkregs[0x10000]; + u8 mem[0x200000]; + + u32 id; + V_Core Cores[2]; + V_SPDIF Spdif; + s16 OutPos; + s16 InputPos; + u8 InpBuff; + u32 Cycles; + s32 uTicks; + double srate_pv; + double opitch; + int osps; + int PlayMode; + + int lClocks; + + PcmCacheEntry cacheData; + +}; + +#define SAVE_ID 0x73326701 + +// versioning for saves. +// Increment this if changes to V_Core or V_Voice structs are made. +// Chances are we'll never explicitly support older save versions, +// but might as well version them anyway. Could come in handly someday! +#define SAVE_VERSION 0x0101 + +static int getFreezeSize() +{ + if( disableFreezes ) return 8; // length of the string id "invalid" (plus a zero!) + + int size = sizeof(SPU2freezeData); + + // calculate the amount of memory consumed by our cache: + + for( int bidx=0; bidxdata; + + if( spud->id != SAVE_ID || spud->version < 0x100 ) + { + printf("\n*** SPU2Ghz Warning:\n"); + printf(" The savestate you are trying to load was not made with this plugin.\n"); + printf(" The emulator will not be stable! Find a memorycard savespot to save your\n"); + printf(" game, reset, and then continue from there.\n\n"); + + disableFreezes=true; + lClocks = 0; + resetClock = true; + + // Do *not* reset the cores. + // We'll need some "hints" as to how the cores should be initialized, + // and the only way to get that is to use the game's existing core settings + // and hope they kinda match the settings for the savestate (IRQ enables and such). + // + + //CoreReset( 0 ); + //CoreReset( 1 ); + + // adpcm cache : Clear all the cache flags and buffers. + + wipe_the_cache(); + } + else + { + disableFreezes=false; + + // base stuff + memcpy(spu2regs, spud->unkregs, 0x010000); + memcpy(_spu2mem, spud->mem, 0x200000); + + memcpy(Cores, spud->Cores, sizeof(Cores)); + memcpy(&Spdif, &spud->Spdif, sizeof(Spdif)); + OutPos = spud->OutPos; + InputPos = spud->InputPos; + InpBuff = spud->InpBuff; + Cycles = spud->Cycles; + uTicks = spud->uTicks; + srate_pv = spud->srate_pv; + PlayMode = spud->PlayMode; + lClocks = spud->lClocks; + + // Load the ADPCM cache: + + wipe_the_cache(); + if( spud->version == 0x100 ) // don't support 0x100 cache anymore. + { + printf("\n*** SPU2Ghz Warning:\n"); + printf("\tSavestate version is from an older version of this plugin.\n"); + printf("\tAudio may not recover correctly."); + + const PcmCacheEntry* pcmSrc = &spud->cacheData; + int blksLoaded=0; + + for( int bidx=0; bidx FreezeLoad > Loaded %d cache blocks.\n", blksLoaded++ ); + } + + } else if (mode == FREEZE_SAVE) + { + if (data->data == NULL) return -1; + + if( disableFreezes ) + { + // No point in making a save state since the SPU2 + // state is completely bogus anyway... Let's just + // give this some random ID that no one will recognize. + + strcpy( data->data, "invalid" ); + return 0; + } + + + SPU2freezeData *spud = (SPU2freezeData*)data->data; + + spud->id=SAVE_ID; + spud->version=SAVE_VERSION;//ZEROSPU_VERSION; //Zero compat working bad, better not save that + + memcpy(spud->unkregs, spu2regs, 0x010000); + memcpy(spud->mem, _spu2mem, 0x200000); + memcpy(spud->Cores, Cores, sizeof(Cores)); + memcpy(&spud->Spdif, &Spdif, sizeof(Spdif)); + spud->OutPos = OutPos; + spud->InputPos = InputPos; + spud->InpBuff = InpBuff; + spud->Cycles = Cycles; + spud->uTicks = uTicks; + spud->srate_pv = srate_pv; + spud->PlayMode = PlayMode; + spud->lClocks = lClocks; + + // Save our cache: + // We could just force the user to rebuild the cache when loading + // from stavestates, but for most games the cache is pretty + // small and compresses well. + // + // Potential Alternative: + // If the cache is not saved then it is necessary to save the + // decoded blocks currently in use by active voices. This allows + // voices to resume seamlessly on load. + + PcmCacheEntry* pcmDst = &spud->cacheData; + int blksSaved=0; + + for( int bidx=0; bidx FreezeSave > Saved %d cache blocks.\n", blksSaved++ ); + + } + else if (mode == FREEZE_SIZE) + { + data->size = getFreezeSize(); + } + return 0; + +} diff --git a/plugins/spu2ghz/src/sndout.cpp b/plugins/spu2ghz/src/sndout.cpp index f63e5acb7d..d4f6d32cfd 100644 --- a/plugins/spu2ghz/src/sndout.cpp +++ b/plugins/spu2ghz/src/sndout.cpp @@ -1,892 +1,892 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// - -// [TODO] : The layout of this code file is now a complete hackish mess after -// numerous timestretch-related additions. The whole thing should really be -// rethought and redone at this point. - -#include "spu2.h" -#include "SoundTouch/SoundTouch.h" -#include "SoundTouch/WavFile.h" - -#include - -static int ts_stats_stretchblocks = 0; -static int ts_stats_normalblocks = 0; -static int ts_stats_logcounter = 0; - -class NullOutModule: public SndOutModule -{ -public: - s32 Init(SndBuffer *) { return 0; } - void Close() { } - s32 Test() const { return 0; } - void Configure(HWND parent) { } - bool Is51Out() const { return false; } - int GetEmptySampleCount() const { return 0; } - - const char* GetIdent() const - { - return "nullout"; - } - - const char* GetLongName() const - { - return "No Sound (Emulate SPU2 only)"; - } - -} NullOut; - -SndOutModule* mods[]= -{ - &NullOut, - WaveOut, - DSoundOut, - //DSound51Out, - //ASIOOut, - XAudio2Out, - NULL // signals the end of our list -}; - -int FindOutputModuleById( const char* omodid ) -{ - int modcnt = 0; - while( mods[modcnt] != NULL ) - { - if( strcmp( mods[modcnt]->GetIdent(), omodid ) == 0 ) - break; - ++modcnt; - } - return modcnt; -} - - -// Overall master volume shift. -// Converts the mixer's 32 bit value into a 16 bit value. -int SndOutVolumeShift = SndOutVolumeShiftBase + 1; - -static __forceinline s16 SndScaleVol( s32 inval ) -{ - return inval >> SndOutVolumeShift; -} - - -// records last buffer status (fill %, range -100 to 100, with 0 being 50% full) -float lastPct; -float lastEmergencyAdj; - -float cTempo=1; -float eTempo = 1; -int freezeTempo = 0; - -soundtouch::SoundTouch* pSoundTouch=NULL; - - -//usefull when timestretch isn't available -//#define DYNAMIC_BUFFER_LIMITING - -class SndBufferImpl: public SndBuffer -{ -private: - s32 *buffer; - s32 size; - s32 rpos; - s32 wpos; - s32 data; - - // data prediction amount, used to "commit" data that hasn't - // finished timestretch processing. - s32 predictData; - - bool pw; - - bool underrun_freeze; - HANDLE hSyncEvent; - CRITICAL_SECTION cs; - -protected: - int GetAlignedBufferSize( int comp ) - { - return (comp + SndOutPacketSize-1) & ~(SndOutPacketSize-1); - } - -public: - SndBufferImpl( float latencyMS ) - { - rpos=0; - wpos=0; - data=0; - size=GetAlignedBufferSize( (int)(latencyMS * SampleRate / 500.0f ) ); - buffer = new s32[size]; - pw=false; - underrun_freeze = false; - predictData = 0; - -#ifdef DYNAMIC_BUFFER_LIMITING - overflows=0; - underflows=0; - writewaits=0; - buffer_limit=size; -#endif - InitializeCriticalSection(&cs); - hSyncEvent = CreateEvent(NULL,FALSE,FALSE,NULL); - } - - virtual ~SndBufferImpl() - { - pw=false; - PulseEvent(hSyncEvent); - Sleep(10); - EnterCriticalSection(&cs); - LeaveCriticalSection(&cs); - DeleteCriticalSection(&cs); - CloseHandle(hSyncEvent); - delete buffer; - } - - virtual void WriteSamples(s32 *bData, int nSamples) - { - EnterCriticalSection(&cs); - int free = size-data; - predictData = 0; - - jASSUME( data <= size ); - - if( pw && ( free < nSamples ) ) - { - // Wait for a ReadSamples to pull some stuff out of the buffer. - // One SyncEvent will do the trick. - ResetEvent( hSyncEvent ); - LeaveCriticalSection(&cs); - WaitForSingleObject(hSyncEvent,20); - EnterCriticalSection(&cs); - } - - // Problem: - // If the SPU2 gets out of sync with the SndOut device, the writepos of the - // circular buffer will overtake the readpos, leading to a prolonged period - // of hopscotching read/write accesses (ie, lots of staticy crap sound for - // several seconds). - // - // Compromise: - // When an overrun occurs, we adapt by discarding a portion of the buffer. - // The older portion of the buffer is discarded rather than incoming data, - // so that the overall audio synchronization is better. - - if( free < nSamples ) - { - // Buffer overrun! - // Dump samples from the read portion of the buffer instead of dropping - // the newly written stuff. - - s32 comp; - - if( timeStretchEnabled ) - { - // If we overran it means the timestretcher failed. We need to speed - // up audio playback. - cTempo += cTempo * 0.12f; - eTempo += eTempo * 0.40f; - if( eTempo > 7.5f ) eTempo = 7.5f; - pSoundTouch->setTempo( eTempo ); - - // Throw out just a little bit (two packets worth) to help - // give the TS some room to work: - - comp = SndOutPacketSize*2; - } - else - { - // Toss half the buffer plus whatever's being written anew: - comp = GetAlignedBufferSize( (size + nSamples ) / 2 ); - if( comp > (size-SndOutPacketSize) ) comp = size-SndOutPacketSize; - } - - data-=comp; - rpos=(rpos+comp)%size; - if( MsgOverruns() ) - ConLog(" * SPU2 > Overrun Compensation (%d packets tossed)\n", comp / SndOutPacketSize ); - lastPct = 0.0; // normalize the timestretcher - } - - // copy in two phases, since there's a chance the packet - // wraps around the buffer (it'd be nice to deal in packets only, but - // the timestretcher and DSP options require flexibility). - - const int endPos = wpos + nSamples; - const int secondCopyLen = endPos - size; - s32* wposbuffer = &buffer[wpos]; - - data += nSamples; - if( secondCopyLen > 0 ) - { - nSamples -= secondCopyLen; - memcpy( buffer, &bData[nSamples], secondCopyLen * sizeof( *bData ) ); - wpos = secondCopyLen; - } - else - wpos += nSamples; - - memcpy( wposbuffer, bData, nSamples * sizeof( *bData ) ); - - LeaveCriticalSection(&cs); - } - - protected: - // Returns TRUE if there is data to be output, or false if no data - // is available to be copied. - bool CheckUnderrunStatus( int& nSamples, int& quietSampleCount ) - { - quietSampleCount = 0; - if( underrun_freeze ) - { - int toFill = (int)(size * ( timeStretchEnabled ? 0.1f : 0.50f ) ); - toFill = GetAlignedBufferSize( toFill ); - - // toFill is now aligned to a SndOutPacket - - if( data < toFill ) - { - quietSampleCount = nSamples; - return false; - } - - underrun_freeze = false; - if( MsgOverruns() ) - ConLog(" * SPU2 > Underrun compensation (%d packets buffered)\n", toFill / SndOutPacketSize ); - lastPct = 0.0; // normalize timestretcher - } - else if( data < nSamples ) - { - nSamples = data; - quietSampleCount = SndOutPacketSize - data; - underrun_freeze = true; - - if( timeStretchEnabled ) - { - // timeStretcher failed it's job. We need to slow down the audio some. - - cTempo -= (cTempo * 0.12f); - eTempo -= (eTempo * 0.30f); - if( eTempo < 0.1f ) eTempo = 0.1f; - pSoundTouch->setTempo( eTempo ); - } - - return nSamples != 0; - } - - return true; - } - - public: - void ReadSamples( s16* bData ) - { - int nSamples = SndOutPacketSize; - - EnterCriticalSection(&cs); - - // Problem: - // If the SPU2 gets even the least bit out of sync with the SndOut device, - // the readpos of the circular buffer will overtake the writepos, - // leading to a prolonged period of hopscotching read/write accesses (ie, - // lots of staticy crap sound for several seconds). - // - // Fix: - // If the read position overtakes the write position, abort the - // transfer immediately and force the SndOut driver to wait until - // the read buffer has filled up again before proceeding. - // This will cause one brief hiccup that can never exceed the user's - // set buffer length in duration. - - int quietSamples; - if( CheckUnderrunStatus( nSamples, quietSamples ) ) - { - jASSUME( nSamples <= SndOutPacketSize ); - - // [Air] [TODO]: This loop is probably a candidiate for SSE2 optimization. - - const int endPos = rpos + nSamples; - const int secondCopyLen = endPos - size; - const s32* rposbuffer = &buffer[rpos]; - - data -= nSamples; - - if( secondCopyLen > 0 ) - { - nSamples -= secondCopyLen; - for( int i=0; i 0 ) - { - nSamples -= secondCopyLen; - memcpy( &bData[nSamples], buffer, secondCopyLen * sizeof( *bData ) ); - rpos = secondCopyLen; - } - else - rpos += nSamples; - - memcpy( bData, &buffer[oldrpos], nSamples * sizeof( *bData ) ); - } - - // If quietSamples != 0 it means we have an underrun... - // Let's just dull out some silence, because that's usually the least - // painful way of dealing with underruns: - memset( bData, 0, quietSamples * sizeof(*bData) ); - PulseEvent(hSyncEvent); - LeaveCriticalSection(&cs); - } - - void PredictDataWrite( int samples ) - { - predictData += samples; - } - - virtual void PauseOnWrite(bool doPause) { pw = doPause; } - - // Calculate the buffer status percentage. - // Returns range from -1.0 to 1.0 - // 1.0 = buffer overflow! - // 0.0 = buffer nominal (50% full) - // -1.0 = buffer underflow! - float GetStatusPct() - { - EnterCriticalSection(&cs); - - // Get the buffer status of the output driver too, so that we can - // obtain a more accurate overall buffer status. - - int drvempty = mods[OutputModule]->GetEmptySampleCount(); // / 2; - - //ConLog( "Data %d >>> driver: %d predict: %d\n", data, drvempty, predictData ); - - float result = (float)(data + predictData - drvempty) - (size/2); - result /= (size/2); - LeaveCriticalSection(&cs); - return result; - } - -}; - -SndBufferImpl *sndBuffer=NULL; - -s32* sndTempBuffer=NULL; -s32 sndTempProgress=NULL; -s16* sndTempBuffer16=NULL; - -void UpdateTempoChange() -{ - if( --freezeTempo > 0 ) - { - return; - } - - float statusPct = sndBuffer->GetStatusPct(); - float pctChange = statusPct - lastPct; - - float tempoChange; - float emergencyAdj = 0; - float newcee = cTempo; // workspace var. for cTempo - - // IMPORTANT! - // If you plan to tweak these values, make sure you're using a release build - // OUTSIDE THE DEBUGGER to test it! The Visual Studio debugger can really cause - // erratic behavior in the audio buffers, and makes the timestretcher seem a - // lot more inconsistent than it really is. - - // We have two factors. - // * Distance from nominal buffer status (50% full) - // * The change from previous update to this update. - - // Prediction based on the buffer change: - // (linear seems to work better here) - - tempoChange = pctChange * 0.75f; - - if( statusPct * tempoChange < 0.0f ) - { - // only apply tempo change if it is in synch with the buffer status. - // In other words, if the buffer is high (over 0%), and is decreasing, - // ignore it. It'll just muck things up. - - tempoChange = 0; - } - - // Sudden spikes in framerate can cause the nominal buffer status - // to go critical, in which case we have to enact an emergency - // stretch. The following cubic formulas do that. Values near - // the extremeites give much larger results than those near 0. - // And the value is added only this time, and does not accumulate. - // (otherwise a large value like this would cause problems down the road) - - // Constants: - // Weight - weights the statusPct's "emergency" consideration. - // higher values here will make the buffer perform more drastic - // compensations at the outter edges of the buffer (at -75 or +75% - // or beyond, for example). - - // Range - scales the adjustment to the given range (more or less). - // The actual range is dependent on the weight used, so if you increase - // Weight you'll usually want to decrease Range somewhat to compensate. - - // Prediction based on the buffer fill status: - - const float statusWeight = 2.99f; - const float statusRange = 0.068f; - - // "non-emergency" deadzone: In this area stretching will be strongly discouraged. - // Note: due tot he nature of timestretch latency, it's always a wee bit harder to - // cope with low fps (underruns) tha it is high fps (overruns). So to help out a - // little, the low-end portions of this check are less forgiving than the high-sides. - - if( cTempo < 0.965f || cTempo > 1.060f || - pctChange < -0.38f || pctChange > 0.54f || - statusPct < -0.32f || statusPct > 0.39f || - eTempo < 0.89f || eTempo > 1.19f ) - { - emergencyAdj = ( pow( statusPct*statusWeight, 3.0f ) * statusRange); - } - - // Smooth things out by factoring our previous adjustment into this one. - // It helps make the system 'feel' a little smarter by giving it at least - // one packet worth of history to help work off of: - - emergencyAdj = (emergencyAdj * 0.75f) + (lastEmergencyAdj * 0.25f ); - - lastEmergencyAdj = emergencyAdj; - lastPct = statusPct; - - // Accumulate a fraction of the tempo change into the tempo itself. - // This helps the system run "smarter" to games that run consistently - // fast or slow by altering the base tempo to something closer to the - // game's active speed. In tests most games normalize within 2 seconds - // at 100ms latency, which is pretty good (larger buffers normalize even - // quicker). - - newcee += newcee * (tempoChange+emergencyAdj) * 0.03f; - - // Apply tempoChange as a scale of cTempo. That way the effect is proportional - // to the current tempo. (otherwise tempos rate of change at the extremes would - // be too drastic) - - float newTempo = newcee + ( emergencyAdj * cTempo ); - - // ... and as a final optimization, only stretch if the new tempo is outside - // a nominal threshold. Keep this threshold check small, because it could - // cause some serious side effects otherwise. (enlarging the cTempo check above - // is usually better/safer) - if( newTempo < 0.970f || newTempo > 1.045f ) - { - cTempo = (float)newcee; - - if( newTempo < 0.10f ) newTempo = 0.10f; - else if( newTempo > 10.0f ) newTempo = 10.0f; - - if( cTempo < 0.15f ) cTempo = 0.15f; - else if( cTempo > 7.5f ) cTempo = 7.5f; - - pSoundTouch->setTempo( eTempo = (float)newTempo ); - ts_stats_stretchblocks++; - - /*ConLog(" * SPU2: [Nominal %d%%] [Emergency: %d%%] (baseTempo: %d%% ) (newTempo: %d%%) (buffer: %d%%)\n", - //(relation < 0.0) ? "Normalize" : "", - (int)(tempoChange * 100.0 * 0.03), - (int)(emergencyAdj * 100.0), - (int)(cTempo * 100.0), - (int)(newTempo * 100.0), - (int)(statusPct * 100.0) - );*/ - } - else - { - // Nominal operation -- turn off stretching. - // note: eTempo 'slides' toward 1.0 for smoother audio and better - // protection against spikes. - if( cTempo != 1.0f ) - { - cTempo = 1.0f; - eTempo = ( 1.0f + eTempo ) * 0.5f; - pSoundTouch->setTempo( eTempo ); - } - else - { - if( eTempo != cTempo ) - pSoundTouch->setTempo( eTempo=cTempo ); - ts_stats_normalblocks++; - } - } -} - - -void soundtouchInit() -{ - pSoundTouch = new soundtouch::SoundTouch(); - pSoundTouch->setSampleRate(SampleRate); - pSoundTouch->setChannels(2); - - pSoundTouch->setSetting(SETTING_USE_QUICKSEEK, 0); - pSoundTouch->setSetting(SETTING_USE_AA_FILTER, 0); - pSoundTouch->setTempo(1); - - // some timestretch management vars: - - cTempo = 1.0; - eTempo = 1.0; - lastPct = 0; - lastEmergencyAdj = 0; - - // just freeze tempo changes for a while at startup. - // the driver buffers are bogus anyway. - freezeTempo = 8; -} - -static void _sndInitFail() -{ - // If a failure occurs, just initialize the NoSound driver. This'll allow - // the game to emulate properly (hopefully), albeit without sound. - OutputModule = FindOutputModuleById( NullOut.GetIdent() ); - mods[OutputModule]->Init( sndBuffer ); -} - -s32 SndInit() -{ - if( mods[OutputModule] == NULL ) - { - _sndInitFail(); - return 0; - } - - // initialize sound buffer - // Buffer actually attempts to run ~50%, so allocate near double what - // the requested latency is: - - try - { - sndBuffer = new SndBufferImpl( SndOutLatencyMS * (timeStretchEnabled ? 2.0f : 1.5f) ); - sndTempBuffer = new s32[SndOutPacketSize]; - sndTempBuffer16 = new s16[SndOutPacketSize]; - } - catch( std::bad_alloc& ) - { - // out of memory exception (most likely) - - SysMessage( "Out of memory error occured while initializing SPU2." ); - _sndInitFail(); - return 0; - } - - // clear buffers! - // Fixes loopy sounds on emu resets. - memset( sndTempBuffer, 0, sizeof(s32) * SndOutPacketSize ); - memset( sndTempBuffer16, 0, sizeof(s16) * SndOutPacketSize ); - - sndTempProgress = 0; - - soundtouchInit(); // initializes the timestretching - - if(LimitMode!=0) - { - sndBuffer->PauseOnWrite(true); - } - - // some crap - spdif_set51(mods[OutputModule]->Is51Out()); - - // initialize module - if( mods[OutputModule]->Init(sndBuffer) == -1 ) - { - _sndInitFail(); - } - - return 0; -} - -void SndClose() -{ - mods[OutputModule]->Close(); - - SAFE_DELETE_OBJ( sndBuffer ); - SAFE_DELETE_ARRAY( sndTempBuffer ); - SAFE_DELETE_ARRAY( sndTempBuffer16 ); - SAFE_DELETE_OBJ( pSoundTouch ); -} - -void SndUpdateLimitMode() -{ - //sndBuffer->PauseOnWrite(LimitMode!=0); - - if(LimitMode!=0) { - timeStretchEnabled = true; - //printf(" * SPU2 limiter is now ON.\n"); - printf(" * SPU2 timestretch is now ON.\n"); - } - else { - //printf(" * SPU2 limiter is now OFF.\n"); - printf(" * SPU2 timestretch is now OFF.\n"); - timeStretchEnabled = false; - } - -} - - -s32 SndWrite(s32 ValL, s32 ValR) -{ - #ifndef PUBLIC - if(WaveLog() && wavedump_ok) - { - wavedump_write(SndScaleVol(ValL),SndScaleVol(ValR)); - } - #endif - - if(recording!=0) - RecordWrite(SndScaleVol(ValL),SndScaleVol(ValR)); - - if(mods[OutputModule] == &NullOut) // null output doesn't need buffering or stretching! :p - return 0; - - sndTempBuffer[sndTempProgress++] = ValL; - sndTempBuffer[sndTempProgress++] = ValR; - - // If we haven't accumulated a full packet yet, do nothing more: - if(sndTempProgress < SndOutPacketSize) return 1; - - if(dspPluginEnabled) - { - for(int i=0;i>1)<<1; - - for(int i=0;iPredictDataWrite( (int)( sndTempProgress / eTempo ) ); - for(int i=0;iputSamples((float*)sndTempBuffer, sndTempProgress>>1); - - while( ( sndTempProgress = pSoundTouch->receiveSamples((float*)sndTempBuffer, sndTempProgress>>1)<<1 ) != 0 ) - { - // [Air] [TODO] : Implement an SSE downsampler to int. - for(int i=0;iWriteSamples(sndTempBuffer, sndTempProgress); - progress = true; - } - - UpdateTempoChange(); - - if( MsgOverruns() ) - { - if( progress ) - { - if( ++ts_stats_logcounter > 300 ) - { - ts_stats_logcounter = 0; - ConLog( " * SPU2 > Timestretch Stats > %d%% of packets stretched.\n", - ( ts_stats_stretchblocks * 100 ) / ( ts_stats_normalblocks + ts_stats_stretchblocks ) ); - ts_stats_normalblocks = 0; - ts_stats_stretchblocks = 0; - } - } - } - } - else - { - sndBuffer->WriteSamples(sndTempBuffer, sndTempProgress); - sndTempProgress=0; - } - - return 1; -} - -s32 SndTest() -{ - if( mods[OutputModule] == NULL ) - return -1; - - return mods[OutputModule]->Test(); -} - -void SndConfigure(HWND parent, u32 module ) -{ - if( mods[module] == NULL ) - return; - - mods[module]->Configure(parent); -} - -#if 0 -////////////////////////////////////////////////////////////// -// Basic Timestretcher (50% to 150%) -const s32 StretchBufferSize = 2048; - -s32 stretchBufferL[StretchBufferSize*2]; -s32 stretchBufferR[StretchBufferSize*2]; -s32 stretchPosition=0; - -s32 stretchOutputSize = 2048; // valid values from 1024 to 3072 - -s32 blah; - -extern float cspeed; -void TimestretchUpdate(int bufferusage,int buffersize) -{ - if(cspeed>1.01) - { - stretchOutputSize+=10; - } - else if (cspeed<0.99) - { - stretchOutputSize-=10; - } - - blah++; - if(blah>=2) - { - blah=0; - - printf(" * Stretch = %d of %d\n",stretchOutputSize,StretchBufferSize); - } -} - -s32 SndWriteStretch(s32 ValL, s32 ValR) -{ - // TODO: update stretchOutputSize according to speed :P - - stretchBufferL[stretchPosition] = ValL; - stretchBufferR[stretchPosition] = ValR; - - stretchPosition++; - if(stretchPosition>=StretchBufferSize) - { - stretchPosition=0; - - if(stretchOutputSize < (StretchBufferSize/2)) - stretchOutputSize=(StretchBufferSize/2); - if(stretchOutputSize > (StretchBufferSize*3/2)) - stretchOutputSize=(StretchBufferSize*3/2); - - if(stretchOutputSize>StretchBufferSize) - { - int K = (stretchOutputSize-StretchBufferSize); - int J = StretchBufferSize - K; - - // K samples offset - for(int i=StretchBufferSize;i +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +// [TODO] : The layout of this code file is now a complete hackish mess after +// numerous timestretch-related additions. The whole thing should really be +// rethought and redone at this point. + +#include "spu2.h" +#include "SoundTouch/SoundTouch.h" +#include "SoundTouch/WavFile.h" + +#include + +static int ts_stats_stretchblocks = 0; +static int ts_stats_normalblocks = 0; +static int ts_stats_logcounter = 0; + +class NullOutModule: public SndOutModule +{ +public: + s32 Init(SndBuffer *) { return 0; } + void Close() { } + s32 Test() const { return 0; } + void Configure(HWND parent) { } + bool Is51Out() const { return false; } + int GetEmptySampleCount() const { return 0; } + + const char* GetIdent() const + { + return "nullout"; + } + + const char* GetLongName() const + { + return "No Sound (Emulate SPU2 only)"; + } + +} NullOut; + +SndOutModule* mods[]= +{ + &NullOut, + WaveOut, + DSoundOut, + //DSound51Out, + //ASIOOut, + XAudio2Out, + NULL // signals the end of our list +}; + +int FindOutputModuleById( const char* omodid ) +{ + int modcnt = 0; + while( mods[modcnt] != NULL ) + { + if( strcmp( mods[modcnt]->GetIdent(), omodid ) == 0 ) + break; + ++modcnt; + } + return modcnt; +} + + +// Overall master volume shift. +// Converts the mixer's 32 bit value into a 16 bit value. +int SndOutVolumeShift = SndOutVolumeShiftBase + 1; + +static __forceinline s16 SndScaleVol( s32 inval ) +{ + return inval >> SndOutVolumeShift; +} + + +// records last buffer status (fill %, range -100 to 100, with 0 being 50% full) +float lastPct; +float lastEmergencyAdj; + +float cTempo=1; +float eTempo = 1; +int freezeTempo = 0; + +soundtouch::SoundTouch* pSoundTouch=NULL; + + +//usefull when timestretch isn't available +//#define DYNAMIC_BUFFER_LIMITING + +class SndBufferImpl: public SndBuffer +{ +private: + s32 *buffer; + s32 size; + s32 rpos; + s32 wpos; + s32 data; + + // data prediction amount, used to "commit" data that hasn't + // finished timestretch processing. + s32 predictData; + + bool pw; + + bool underrun_freeze; + HANDLE hSyncEvent; + CRITICAL_SECTION cs; + +protected: + int GetAlignedBufferSize( int comp ) + { + return (comp + SndOutPacketSize-1) & ~(SndOutPacketSize-1); + } + +public: + SndBufferImpl( float latencyMS ) + { + rpos=0; + wpos=0; + data=0; + size=GetAlignedBufferSize( (int)(latencyMS * SampleRate / 500.0f ) ); + buffer = new s32[size]; + pw=false; + underrun_freeze = false; + predictData = 0; + +#ifdef DYNAMIC_BUFFER_LIMITING + overflows=0; + underflows=0; + writewaits=0; + buffer_limit=size; +#endif + InitializeCriticalSection(&cs); + hSyncEvent = CreateEvent(NULL,FALSE,FALSE,NULL); + } + + virtual ~SndBufferImpl() + { + pw=false; + PulseEvent(hSyncEvent); + Sleep(10); + EnterCriticalSection(&cs); + LeaveCriticalSection(&cs); + DeleteCriticalSection(&cs); + CloseHandle(hSyncEvent); + delete buffer; + } + + virtual void WriteSamples(s32 *bData, int nSamples) + { + EnterCriticalSection(&cs); + int free = size-data; + predictData = 0; + + jASSUME( data <= size ); + + if( pw && ( free < nSamples ) ) + { + // Wait for a ReadSamples to pull some stuff out of the buffer. + // One SyncEvent will do the trick. + ResetEvent( hSyncEvent ); + LeaveCriticalSection(&cs); + WaitForSingleObject(hSyncEvent,20); + EnterCriticalSection(&cs); + } + + // Problem: + // If the SPU2 gets out of sync with the SndOut device, the writepos of the + // circular buffer will overtake the readpos, leading to a prolonged period + // of hopscotching read/write accesses (ie, lots of staticy crap sound for + // several seconds). + // + // Compromise: + // When an overrun occurs, we adapt by discarding a portion of the buffer. + // The older portion of the buffer is discarded rather than incoming data, + // so that the overall audio synchronization is better. + + if( free < nSamples ) + { + // Buffer overrun! + // Dump samples from the read portion of the buffer instead of dropping + // the newly written stuff. + + s32 comp; + + if( timeStretchEnabled ) + { + // If we overran it means the timestretcher failed. We need to speed + // up audio playback. + cTempo += cTempo * 0.12f; + eTempo += eTempo * 0.40f; + if( eTempo > 7.5f ) eTempo = 7.5f; + pSoundTouch->setTempo( eTempo ); + + // Throw out just a little bit (two packets worth) to help + // give the TS some room to work: + + comp = SndOutPacketSize*2; + } + else + { + // Toss half the buffer plus whatever's being written anew: + comp = GetAlignedBufferSize( (size + nSamples ) / 2 ); + if( comp > (size-SndOutPacketSize) ) comp = size-SndOutPacketSize; + } + + data-=comp; + rpos=(rpos+comp)%size; + if( MsgOverruns() ) + ConLog(" * SPU2 > Overrun Compensation (%d packets tossed)\n", comp / SndOutPacketSize ); + lastPct = 0.0; // normalize the timestretcher + } + + // copy in two phases, since there's a chance the packet + // wraps around the buffer (it'd be nice to deal in packets only, but + // the timestretcher and DSP options require flexibility). + + const int endPos = wpos + nSamples; + const int secondCopyLen = endPos - size; + s32* wposbuffer = &buffer[wpos]; + + data += nSamples; + if( secondCopyLen > 0 ) + { + nSamples -= secondCopyLen; + memcpy( buffer, &bData[nSamples], secondCopyLen * sizeof( *bData ) ); + wpos = secondCopyLen; + } + else + wpos += nSamples; + + memcpy( wposbuffer, bData, nSamples * sizeof( *bData ) ); + + LeaveCriticalSection(&cs); + } + + protected: + // Returns TRUE if there is data to be output, or false if no data + // is available to be copied. + bool CheckUnderrunStatus( int& nSamples, int& quietSampleCount ) + { + quietSampleCount = 0; + if( underrun_freeze ) + { + int toFill = (int)(size * ( timeStretchEnabled ? 0.1f : 0.50f ) ); + toFill = GetAlignedBufferSize( toFill ); + + // toFill is now aligned to a SndOutPacket + + if( data < toFill ) + { + quietSampleCount = nSamples; + return false; + } + + underrun_freeze = false; + if( MsgOverruns() ) + ConLog(" * SPU2 > Underrun compensation (%d packets buffered)\n", toFill / SndOutPacketSize ); + lastPct = 0.0; // normalize timestretcher + } + else if( data < nSamples ) + { + nSamples = data; + quietSampleCount = SndOutPacketSize - data; + underrun_freeze = true; + + if( timeStretchEnabled ) + { + // timeStretcher failed it's job. We need to slow down the audio some. + + cTempo -= (cTempo * 0.12f); + eTempo -= (eTempo * 0.30f); + if( eTempo < 0.1f ) eTempo = 0.1f; + pSoundTouch->setTempo( eTempo ); + } + + return nSamples != 0; + } + + return true; + } + + public: + void ReadSamples( s16* bData ) + { + int nSamples = SndOutPacketSize; + + EnterCriticalSection(&cs); + + // Problem: + // If the SPU2 gets even the least bit out of sync with the SndOut device, + // the readpos of the circular buffer will overtake the writepos, + // leading to a prolonged period of hopscotching read/write accesses (ie, + // lots of staticy crap sound for several seconds). + // + // Fix: + // If the read position overtakes the write position, abort the + // transfer immediately and force the SndOut driver to wait until + // the read buffer has filled up again before proceeding. + // This will cause one brief hiccup that can never exceed the user's + // set buffer length in duration. + + int quietSamples; + if( CheckUnderrunStatus( nSamples, quietSamples ) ) + { + jASSUME( nSamples <= SndOutPacketSize ); + + // [Air] [TODO]: This loop is probably a candidiate for SSE2 optimization. + + const int endPos = rpos + nSamples; + const int secondCopyLen = endPos - size; + const s32* rposbuffer = &buffer[rpos]; + + data -= nSamples; + + if( secondCopyLen > 0 ) + { + nSamples -= secondCopyLen; + for( int i=0; i 0 ) + { + nSamples -= secondCopyLen; + memcpy( &bData[nSamples], buffer, secondCopyLen * sizeof( *bData ) ); + rpos = secondCopyLen; + } + else + rpos += nSamples; + + memcpy( bData, &buffer[oldrpos], nSamples * sizeof( *bData ) ); + } + + // If quietSamples != 0 it means we have an underrun... + // Let's just dull out some silence, because that's usually the least + // painful way of dealing with underruns: + memset( bData, 0, quietSamples * sizeof(*bData) ); + PulseEvent(hSyncEvent); + LeaveCriticalSection(&cs); + } + + void PredictDataWrite( int samples ) + { + predictData += samples; + } + + virtual void PauseOnWrite(bool doPause) { pw = doPause; } + + // Calculate the buffer status percentage. + // Returns range from -1.0 to 1.0 + // 1.0 = buffer overflow! + // 0.0 = buffer nominal (50% full) + // -1.0 = buffer underflow! + float GetStatusPct() + { + EnterCriticalSection(&cs); + + // Get the buffer status of the output driver too, so that we can + // obtain a more accurate overall buffer status. + + int drvempty = mods[OutputModule]->GetEmptySampleCount(); // / 2; + + //ConLog( "Data %d >>> driver: %d predict: %d\n", data, drvempty, predictData ); + + float result = (float)(data + predictData - drvempty) - (size/2); + result /= (size/2); + LeaveCriticalSection(&cs); + return result; + } + +}; + +SndBufferImpl *sndBuffer=NULL; + +s32* sndTempBuffer=NULL; +s32 sndTempProgress=NULL; +s16* sndTempBuffer16=NULL; + +void UpdateTempoChange() +{ + if( --freezeTempo > 0 ) + { + return; + } + + float statusPct = sndBuffer->GetStatusPct(); + float pctChange = statusPct - lastPct; + + float tempoChange; + float emergencyAdj = 0; + float newcee = cTempo; // workspace var. for cTempo + + // IMPORTANT! + // If you plan to tweak these values, make sure you're using a release build + // OUTSIDE THE DEBUGGER to test it! The Visual Studio debugger can really cause + // erratic behavior in the audio buffers, and makes the timestretcher seem a + // lot more inconsistent than it really is. + + // We have two factors. + // * Distance from nominal buffer status (50% full) + // * The change from previous update to this update. + + // Prediction based on the buffer change: + // (linear seems to work better here) + + tempoChange = pctChange * 0.75f; + + if( statusPct * tempoChange < 0.0f ) + { + // only apply tempo change if it is in synch with the buffer status. + // In other words, if the buffer is high (over 0%), and is decreasing, + // ignore it. It'll just muck things up. + + tempoChange = 0; + } + + // Sudden spikes in framerate can cause the nominal buffer status + // to go critical, in which case we have to enact an emergency + // stretch. The following cubic formulas do that. Values near + // the extremeites give much larger results than those near 0. + // And the value is added only this time, and does not accumulate. + // (otherwise a large value like this would cause problems down the road) + + // Constants: + // Weight - weights the statusPct's "emergency" consideration. + // higher values here will make the buffer perform more drastic + // compensations at the outter edges of the buffer (at -75 or +75% + // or beyond, for example). + + // Range - scales the adjustment to the given range (more or less). + // The actual range is dependent on the weight used, so if you increase + // Weight you'll usually want to decrease Range somewhat to compensate. + + // Prediction based on the buffer fill status: + + const float statusWeight = 2.99f; + const float statusRange = 0.068f; + + // "non-emergency" deadzone: In this area stretching will be strongly discouraged. + // Note: due tot he nature of timestretch latency, it's always a wee bit harder to + // cope with low fps (underruns) tha it is high fps (overruns). So to help out a + // little, the low-end portions of this check are less forgiving than the high-sides. + + if( cTempo < 0.965f || cTempo > 1.060f || + pctChange < -0.38f || pctChange > 0.54f || + statusPct < -0.32f || statusPct > 0.39f || + eTempo < 0.89f || eTempo > 1.19f ) + { + emergencyAdj = ( pow( statusPct*statusWeight, 3.0f ) * statusRange); + } + + // Smooth things out by factoring our previous adjustment into this one. + // It helps make the system 'feel' a little smarter by giving it at least + // one packet worth of history to help work off of: + + emergencyAdj = (emergencyAdj * 0.75f) + (lastEmergencyAdj * 0.25f ); + + lastEmergencyAdj = emergencyAdj; + lastPct = statusPct; + + // Accumulate a fraction of the tempo change into the tempo itself. + // This helps the system run "smarter" to games that run consistently + // fast or slow by altering the base tempo to something closer to the + // game's active speed. In tests most games normalize within 2 seconds + // at 100ms latency, which is pretty good (larger buffers normalize even + // quicker). + + newcee += newcee * (tempoChange+emergencyAdj) * 0.03f; + + // Apply tempoChange as a scale of cTempo. That way the effect is proportional + // to the current tempo. (otherwise tempos rate of change at the extremes would + // be too drastic) + + float newTempo = newcee + ( emergencyAdj * cTempo ); + + // ... and as a final optimization, only stretch if the new tempo is outside + // a nominal threshold. Keep this threshold check small, because it could + // cause some serious side effects otherwise. (enlarging the cTempo check above + // is usually better/safer) + if( newTempo < 0.970f || newTempo > 1.045f ) + { + cTempo = (float)newcee; + + if( newTempo < 0.10f ) newTempo = 0.10f; + else if( newTempo > 10.0f ) newTempo = 10.0f; + + if( cTempo < 0.15f ) cTempo = 0.15f; + else if( cTempo > 7.5f ) cTempo = 7.5f; + + pSoundTouch->setTempo( eTempo = (float)newTempo ); + ts_stats_stretchblocks++; + + /*ConLog(" * SPU2: [Nominal %d%%] [Emergency: %d%%] (baseTempo: %d%% ) (newTempo: %d%%) (buffer: %d%%)\n", + //(relation < 0.0) ? "Normalize" : "", + (int)(tempoChange * 100.0 * 0.03), + (int)(emergencyAdj * 100.0), + (int)(cTempo * 100.0), + (int)(newTempo * 100.0), + (int)(statusPct * 100.0) + );*/ + } + else + { + // Nominal operation -- turn off stretching. + // note: eTempo 'slides' toward 1.0 for smoother audio and better + // protection against spikes. + if( cTempo != 1.0f ) + { + cTempo = 1.0f; + eTempo = ( 1.0f + eTempo ) * 0.5f; + pSoundTouch->setTempo( eTempo ); + } + else + { + if( eTempo != cTempo ) + pSoundTouch->setTempo( eTempo=cTempo ); + ts_stats_normalblocks++; + } + } +} + + +void soundtouchInit() +{ + pSoundTouch = new soundtouch::SoundTouch(); + pSoundTouch->setSampleRate(SampleRate); + pSoundTouch->setChannels(2); + + pSoundTouch->setSetting(SETTING_USE_QUICKSEEK, 0); + pSoundTouch->setSetting(SETTING_USE_AA_FILTER, 0); + pSoundTouch->setTempo(1); + + // some timestretch management vars: + + cTempo = 1.0; + eTempo = 1.0; + lastPct = 0; + lastEmergencyAdj = 0; + + // just freeze tempo changes for a while at startup. + // the driver buffers are bogus anyway. + freezeTempo = 8; +} + +static void _sndInitFail() +{ + // If a failure occurs, just initialize the NoSound driver. This'll allow + // the game to emulate properly (hopefully), albeit without sound. + OutputModule = FindOutputModuleById( NullOut.GetIdent() ); + mods[OutputModule]->Init( sndBuffer ); +} + +s32 SndInit() +{ + if( mods[OutputModule] == NULL ) + { + _sndInitFail(); + return 0; + } + + // initialize sound buffer + // Buffer actually attempts to run ~50%, so allocate near double what + // the requested latency is: + + try + { + sndBuffer = new SndBufferImpl( SndOutLatencyMS * (timeStretchEnabled ? 2.0f : 1.5f) ); + sndTempBuffer = new s32[SndOutPacketSize]; + sndTempBuffer16 = new s16[SndOutPacketSize]; + } + catch( std::bad_alloc& ) + { + // out of memory exception (most likely) + + SysMessage( "Out of memory error occured while initializing SPU2." ); + _sndInitFail(); + return 0; + } + + // clear buffers! + // Fixes loopy sounds on emu resets. + memset( sndTempBuffer, 0, sizeof(s32) * SndOutPacketSize ); + memset( sndTempBuffer16, 0, sizeof(s16) * SndOutPacketSize ); + + sndTempProgress = 0; + + soundtouchInit(); // initializes the timestretching + + if(LimitMode!=0) + { + sndBuffer->PauseOnWrite(true); + } + + // some crap + spdif_set51(mods[OutputModule]->Is51Out()); + + // initialize module + if( mods[OutputModule]->Init(sndBuffer) == -1 ) + { + _sndInitFail(); + } + + return 0; +} + +void SndClose() +{ + mods[OutputModule]->Close(); + + SAFE_DELETE_OBJ( sndBuffer ); + SAFE_DELETE_ARRAY( sndTempBuffer ); + SAFE_DELETE_ARRAY( sndTempBuffer16 ); + SAFE_DELETE_OBJ( pSoundTouch ); +} + +void SndUpdateLimitMode() +{ + //sndBuffer->PauseOnWrite(LimitMode!=0); + + if(LimitMode!=0) { + timeStretchEnabled = true; + //printf(" * SPU2 limiter is now ON.\n"); + printf(" * SPU2 timestretch is now ON.\n"); + } + else { + //printf(" * SPU2 limiter is now OFF.\n"); + printf(" * SPU2 timestretch is now OFF.\n"); + timeStretchEnabled = false; + } + +} + + +s32 SndWrite(s32 ValL, s32 ValR) +{ + #ifndef PUBLIC + if(WaveLog() && wavedump_ok) + { + wavedump_write(SndScaleVol(ValL),SndScaleVol(ValR)); + } + #endif + + if(recording!=0) + RecordWrite(SndScaleVol(ValL),SndScaleVol(ValR)); + + if(mods[OutputModule] == &NullOut) // null output doesn't need buffering or stretching! :p + return 0; + + sndTempBuffer[sndTempProgress++] = ValL; + sndTempBuffer[sndTempProgress++] = ValR; + + // If we haven't accumulated a full packet yet, do nothing more: + if(sndTempProgress < SndOutPacketSize) return 1; + + if(dspPluginEnabled) + { + for(int i=0;i>1)<<1; + + for(int i=0;iPredictDataWrite( (int)( sndTempProgress / eTempo ) ); + for(int i=0;iputSamples((float*)sndTempBuffer, sndTempProgress>>1); + + while( ( sndTempProgress = pSoundTouch->receiveSamples((float*)sndTempBuffer, sndTempProgress>>1)<<1 ) != 0 ) + { + // [Air] [TODO] : Implement an SSE downsampler to int. + for(int i=0;iWriteSamples(sndTempBuffer, sndTempProgress); + progress = true; + } + + UpdateTempoChange(); + + if( MsgOverruns() ) + { + if( progress ) + { + if( ++ts_stats_logcounter > 300 ) + { + ts_stats_logcounter = 0; + ConLog( " * SPU2 > Timestretch Stats > %d%% of packets stretched.\n", + ( ts_stats_stretchblocks * 100 ) / ( ts_stats_normalblocks + ts_stats_stretchblocks ) ); + ts_stats_normalblocks = 0; + ts_stats_stretchblocks = 0; + } + } + } + } + else + { + sndBuffer->WriteSamples(sndTempBuffer, sndTempProgress); + sndTempProgress=0; + } + + return 1; +} + +s32 SndTest() +{ + if( mods[OutputModule] == NULL ) + return -1; + + return mods[OutputModule]->Test(); +} + +void SndConfigure(HWND parent, u32 module ) +{ + if( mods[module] == NULL ) + return; + + mods[module]->Configure(parent); +} + +#if 0 +////////////////////////////////////////////////////////////// +// Basic Timestretcher (50% to 150%) +const s32 StretchBufferSize = 2048; + +s32 stretchBufferL[StretchBufferSize*2]; +s32 stretchBufferR[StretchBufferSize*2]; +s32 stretchPosition=0; + +s32 stretchOutputSize = 2048; // valid values from 1024 to 3072 + +s32 blah; + +extern float cspeed; +void TimestretchUpdate(int bufferusage,int buffersize) +{ + if(cspeed>1.01) + { + stretchOutputSize+=10; + } + else if (cspeed<0.99) + { + stretchOutputSize-=10; + } + + blah++; + if(blah>=2) + { + blah=0; + + printf(" * Stretch = %d of %d\n",stretchOutputSize,StretchBufferSize); + } +} + +s32 SndWriteStretch(s32 ValL, s32 ValR) +{ + // TODO: update stretchOutputSize according to speed :P + + stretchBufferL[stretchPosition] = ValL; + stretchBufferR[stretchPosition] = ValR; + + stretchPosition++; + if(stretchPosition>=StretchBufferSize) + { + stretchPosition=0; + + if(stretchOutputSize < (StretchBufferSize/2)) + stretchOutputSize=(StretchBufferSize/2); + if(stretchOutputSize > (StretchBufferSize*3/2)) + stretchOutputSize=(StretchBufferSize*3/2); + + if(stretchOutputSize>StretchBufferSize) + { + int K = (stretchOutputSize-StretchBufferSize); + int J = StretchBufferSize - K; + + // K samples offset + for(int i=StretchBufferSize;i -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -#ifndef SNDOUT_H_INCLUDE -#define SNDOUT_H_INCLUDE - -// Number of stereo samples per SndOut block. -// All drivers must work in units of this size when communicating with -// SndOut. -static const int SndOutPacketSize = 1024; - -static const int SndOutVolumeShiftBase = 8; -extern int SndOutVolumeShift; - -#define pcmlog -extern FILE *wavelog; - -s32 SndInit(); -void SndClose(); -s32 SndWrite(s32 ValL, s32 ValR); -s32 SndTest(); -void SndConfigure(HWND parent, u32 outmodidx ); -bool SndGetStats(u32 *written, u32 *played); - -int FindOutputModuleById( const char* omodid ); - -class SndBuffer -{ -public: - virtual ~SndBuffer() {} - - virtual void WriteSamples(s32 *buffer, int nSamples)=0; - virtual void PauseOnWrite(bool doPause)=0; - - virtual void ReadSamples( s16* bData )=0; - virtual void ReadSamples( s32* bData )=0; - - //virtual s32 GetBufferUsage()=0; - //virtual s32 GetBufferSize()=0; -}; - -class SndOutModule -{ -public: - // Virtual destructor, because it helps fight C+++ funny-business. - virtual ~SndOutModule(){}; - - // Returns a unique identification string for this driver. - // (usually just matches the driver's cpp filename) - virtual const char* GetIdent() const=0; - - // Returns the long name / description for this driver. - // (for use in configuration screen) - virtual const char* GetLongName() const=0; - - virtual s32 Init(SndBuffer *buffer)=0; - virtual void Close()=0; - virtual s32 Test() const=0; - virtual void Configure(HWND parent)=0; - virtual bool Is51Out() const=0; - - // Returns the number of empty samples in the output buffer. - // (which is effectively the amount of data played since the last update) - virtual int GetEmptySampleCount() const=0; -}; - -//internal -extern SndOutModule *WaveOut; -extern SndOutModule *DSoundOut; -extern SndOutModule *FModOut; -extern SndOutModule *ASIOOut; -extern SndOutModule *XAudio2Out; -extern SndOutModule *DSound51Out; - -extern SndOutModule* mods[]; - -#endif // SNDOUT_H_INCLUDE +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#ifndef SNDOUT_H_INCLUDE +#define SNDOUT_H_INCLUDE + +// Number of stereo samples per SndOut block. +// All drivers must work in units of this size when communicating with +// SndOut. +static const int SndOutPacketSize = 1024; + +static const int SndOutVolumeShiftBase = 8; +extern int SndOutVolumeShift; + +#define pcmlog +extern FILE *wavelog; + +s32 SndInit(); +void SndClose(); +s32 SndWrite(s32 ValL, s32 ValR); +s32 SndTest(); +void SndConfigure(HWND parent, u32 outmodidx ); +bool SndGetStats(u32 *written, u32 *played); + +int FindOutputModuleById( const char* omodid ); + +class SndBuffer +{ +public: + virtual ~SndBuffer() {} + + virtual void WriteSamples(s32 *buffer, int nSamples)=0; + virtual void PauseOnWrite(bool doPause)=0; + + virtual void ReadSamples( s16* bData )=0; + virtual void ReadSamples( s32* bData )=0; + + //virtual s32 GetBufferUsage()=0; + //virtual s32 GetBufferSize()=0; +}; + +class SndOutModule +{ +public: + // Virtual destructor, because it helps fight C+++ funny-business. + virtual ~SndOutModule(){}; + + // Returns a unique identification string for this driver. + // (usually just matches the driver's cpp filename) + virtual const char* GetIdent() const=0; + + // Returns the long name / description for this driver. + // (for use in configuration screen) + virtual const char* GetLongName() const=0; + + virtual s32 Init(SndBuffer *buffer)=0; + virtual void Close()=0; + virtual s32 Test() const=0; + virtual void Configure(HWND parent)=0; + virtual bool Is51Out() const=0; + + // Returns the number of empty samples in the output buffer. + // (which is effectively the amount of data played since the last update) + virtual int GetEmptySampleCount() const=0; +}; + +//internal +extern SndOutModule *WaveOut; +extern SndOutModule *DSoundOut; +extern SndOutModule *FModOut; +extern SndOutModule *ASIOOut; +extern SndOutModule *XAudio2Out; +extern SndOutModule *DSound51Out; + +extern SndOutModule* mods[]; + +#endif // SNDOUT_H_INCLUDE diff --git a/plugins/spu2ghz/src/spdif.h b/plugins/spu2ghz/src/spdif.h index 7d19a36c04..16cca3ef5f 100644 --- a/plugins/spu2ghz/src/spdif.h +++ b/plugins/spu2ghz/src/spdif.h @@ -1,112 +1,112 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -#ifndef SPDIF_H_INCLUDED -#define SPDIF_H_INCLUDED - -#ifndef u32 -typedef unsigned int u32; -#endif - -/* - Preamble cell-order cell-order - (last cell "0") (last cell "1") - ---------------------------------------------- - "B" 11101000 00010111 - "M" 11100010 00011101 - "W" 11100100 00011011 - - Only the lower 4 bits are used. - -Preamble B: Marks a word containing data for channel A (left) - at the start of the data-block. - -Preamble M: Marks a word with data for channel A that isn't - at the start of the data-block. - -Preamble W: Marks a word containing data for channel B. - (right, for stereo). When using more than 2 - channels, this could also be any other channel - (except for A). - - bits meaning - ---------------------------------------------------------- - 0-3 Preamble (see above; special structure) - - 4-7 Auxillary-audio-databits - - 8-27 Sample - (A 24-bit sample can be used (using bits 4-27). - A CD-player uses only 16 bits, so only bits - 13 (LSB) to 27 (MSB) are used. Bits 4-12 are - set to 0). - - 28 Validity - (When this bit is set, the sample should not - be used by the receiver. A CD-player uses - the 'error-flag' to set this bit). - - 29 Subcode-data - - 30 Channel-status-information - - 31 Parity (bit 0-3 are not included) - -*/ - -typedef struct _subframe -{ - u32 preamble:4; - u32 aux_data:4; - u32 snd_data:20; - u32 validity:1; - u32 subcode:1; - u32 chstatus:1; - u32 parity:1; -} subframe; - -/* - bit meaning - ------------------------------------------------------------- - 0-3 controlbits: - bit 0: 0 (is set to 1 during 4 channel transmission) - bit 1: 0=Digital audio, 1=Non-audio (reserved to be 0 on old S/PDIF specs) - bit 2: copy-protection. Copying is allowed when this bit is set. - bit 3: is set when pre-emphasis is used. - - 4-7 0 (reserved) - - 9-15 catagory-code: - 0 = common 2-channel format - 1 = 2-channel CD-format - (set by a CD-player when a subcode is transmitted) - 2 = 2-channel PCM-encoder-decoder format - - others are not used - - 19-191 0 (reserved) -*/ - -typedef struct _chstatus -{ - u8 ctrlbits:4; - u8 reservd1:4; - u8 category; - u8 reservd2[22]; -} chstatus: - +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#ifndef SPDIF_H_INCLUDED +#define SPDIF_H_INCLUDED + +#ifndef u32 +typedef unsigned int u32; +#endif + +/* + Preamble cell-order cell-order + (last cell "0") (last cell "1") + ---------------------------------------------- + "B" 11101000 00010111 + "M" 11100010 00011101 + "W" 11100100 00011011 + + Only the lower 4 bits are used. + +Preamble B: Marks a word containing data for channel A (left) + at the start of the data-block. + +Preamble M: Marks a word with data for channel A that isn't + at the start of the data-block. + +Preamble W: Marks a word containing data for channel B. + (right, for stereo). When using more than 2 + channels, this could also be any other channel + (except for A). + + bits meaning + ---------------------------------------------------------- + 0-3 Preamble (see above; special structure) + + 4-7 Auxillary-audio-databits + + 8-27 Sample + (A 24-bit sample can be used (using bits 4-27). + A CD-player uses only 16 bits, so only bits + 13 (LSB) to 27 (MSB) are used. Bits 4-12 are + set to 0). + + 28 Validity + (When this bit is set, the sample should not + be used by the receiver. A CD-player uses + the 'error-flag' to set this bit). + + 29 Subcode-data + + 30 Channel-status-information + + 31 Parity (bit 0-3 are not included) + +*/ + +typedef struct _subframe +{ + u32 preamble:4; + u32 aux_data:4; + u32 snd_data:20; + u32 validity:1; + u32 subcode:1; + u32 chstatus:1; + u32 parity:1; +} subframe; + +/* + bit meaning + ------------------------------------------------------------- + 0-3 controlbits: + bit 0: 0 (is set to 1 during 4 channel transmission) + bit 1: 0=Digital audio, 1=Non-audio (reserved to be 0 on old S/PDIF specs) + bit 2: copy-protection. Copying is allowed when this bit is set. + bit 3: is set when pre-emphasis is used. + + 4-7 0 (reserved) + + 9-15 catagory-code: + 0 = common 2-channel format + 1 = 2-channel CD-format + (set by a CD-player when a subcode is transmitted) + 2 = 2-channel PCM-encoder-decoder format + + others are not used + + 19-191 0 (reserved) +*/ + +typedef struct _chstatus +{ + u8 ctrlbits:4; + u8 reservd1:4; + u8 category; + u8 reservd2[22]; +} chstatus: + #endif//SPDIF_H_INCLUDED \ No newline at end of file diff --git a/plugins/spu2ghz/src/spu2.cpp b/plugins/spu2ghz/src/spu2.cpp index c59db1d134..7f228f61ed 100644 --- a/plugins/spu2ghz/src/spu2.cpp +++ b/plugins/spu2ghz/src/spu2.cpp @@ -1,2037 +1,1323 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -#include "SPU2.h" -#include "resource.h" -#include - -#include "regtable.h" -#include "svnrev.h" - -void StartVoices(int core, u32 value); -void StopVoices(int core, u32 value); - -void InitADSR(); - -const unsigned char version = PS2E_SPU2_VERSION; -const unsigned char revision = 1; -const unsigned char build = 9; // increase that with each version - -static __forceinline void SPU2_FastWrite( u32 rmem, u16 value ); -static void SPU2writeLog(u32 rmem, u16 value); -DWORD CALLBACK TimeThread(PVOID /* unused param */); - - -const char *ParamNames[8]={"VOLL","VOLR","PITCH","ADSR1","ADSR2","ENVX","VOLXL","VOLXR"}; -const char *AddressNames[6]={"SSAH","SSAL","LSAH","LSAL","NAXH","NAXL"}; - -double opitch; -int osps; - -// [Air]: Adding the spu2init boolean wasn't necessary except to help me in -// debugging the spu2 suspend/resume behavior (when user hits escape). -static bool spu2open=false; // has spu2open plugin interface been called? -static bool spu2init=false; // has spu2init plugin interface been called? - -// [Air]: fixed the hacky part of UpdateTimer with this: -static bool resetClock = true; - -// Used to make spu2 more robust at loading incompatible saves. -// Disables re-freezing of save state data. -bool disableFreezes=false; - -void (* _irqcallback)(); -void (* dma4callback)(); -void (* dma7callback)(); - -short *spu2regs; -short *_spu2mem; -s32 uTicks; - -u8 callirq; - -HANDLE hThreadFunc; -u32 ThreadFuncID; - -#ifndef PUBLIC -V_CoreDebug DebugCores[2]; -#endif -V_Core Cores[2]; -V_SPDIF Spdif; - -s16 OutPos; -s16 InputPos; -u8 InpBuff; -u32 Cycles; -u32 Num; -u32 acumCycles; - -u32* cPtr=NULL; -u32 lClocks=0; -u32 pClocks=0; - -bool hasPtr=false; - -int PlayMode; - -s16 attrhack[2]={0,0}; - -HINSTANCE hInstance; - -bool debugDialogOpen=false; -HWND hDebugDialog=NULL; - -static char libraryName[256]; - -CRITICAL_SECTION threadSync; - -s32 logvolume[16384]; - -bool has_to_call_irq=false; - -void SetIrqCall() -{ - has_to_call_irq=true; -} - -BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD dwReason,LPVOID lpvReserved) -{ - if(dwReason==DLL_PROCESS_ATTACH) hInstance=hinstDLL; - return TRUE; -} - -void SysMessage(const char *fmt, ...) -{ - va_list list; - char tmp[512]; - - va_start(list,fmt); - sprintf_s(tmp,fmt,list); - va_end(list); - MessageBox(0, tmp, "SPU2ghz Msg", 0); -} - -static void InitLibraryName() -{ -#ifdef PUBLIC - - // Public Release! - // Output a simplified string that's just our name: - - strcpy( libraryName, "SPU2ghz" ); - -#elif defined( SVN_REV_UNKNOWN ) - - // Unknown revision. - // Output a name that includes devbuild status but not - // subversion revision tags: - - strcpy( libraryName, "SPU2ghz" -# ifdef _DEBUG_FAST - "-Debug" -# elif defined( DEBUG ) - "-Debug/Strict" // strict debugging is slow! -# else - "-Dev" -# endif - ); -#else - - // Use TortoiseSVN's SubWCRev utility's output - // to label the specific revision: - - sprintf_s( libraryName, "SPU2ghz r%d%s" -# ifdef _DEBUG_FAST - "-Debug" -# elif defined( _DEBUG ) - "-Debug/Strict" // strict debugging is slow! -# else - "-Dev" -# endif - ,SVN_REV, - SVN_MODS ? "m" : "" - ); -#endif - -} - -EXPORT_C_(u32) PS2EgetLibType() -{ - return PS2E_LT_SPU2; -} - -EXPORT_C_(char*) PS2EgetLibName() -{ - InitLibraryName(); - return libraryName; -} - -EXPORT_C_(u32) PS2EgetLibVersion2(u32 type) -{ - return (version<<16)|(revision<<8)|build; -} - -EXPORT_C_(void) SPU2configure() { - configure(); -} - -EXPORT_C_(void) SPU2about() { - InitLibraryName(); - SysMessage( libraryName ); -} - -EXPORT_C_(s32) SPU2test() { - return SndTest(); -} - - -__forceinline s16 * __fastcall GetMemPtr(u32 addr) -{ -#ifndef _DEBUG_FAST - // In case you're wondering, this assert is the reason spu2ghz - // runs so incrediously slow in Debug mode. :P - assert(addr<0x100000); -#endif - return (_spu2mem+addr); -} - -__forceinline s16 __fastcall spu2M_Read( u32 addr ) -{ - return *GetMemPtr( addr & 0xfffff ); -} - -// writes a signed value to the SPU2 ram -// Invalidates the ADPCM cache in the process. -// Optimization note: don't use __forceinline because the footprint of this -// function is a little too heavy now. Better to let the compiler decide. -__inline void __fastcall spu2M_Write( u32 addr, s16 value ) -{ - // Make sure the cache is invalidated: - // (note to self : addr address WORDs, not bytes) - - addr &= 0xfffff; - if( addr >= SPU2_DYN_MEMLINE ) - { - const int cacheIdx = addr / pcm_WordsPerBlock; - pcm_cache_data[cacheIdx].Validated = false; - - ConLog( " * SPU2 : PcmCache Block Clear at 0x%x (cacheIdx=0x%x)\n", addr, cacheIdx); - } - *GetMemPtr( addr ) = value; -} - -// writes an unsigned value to the SPU2 ram -__inline void __fastcall spu2M_Write( u32 addr, u16 value ) -{ - spu2M_Write( addr, (s16)value ); -} - -void AssignVolume(V_Volume& vol, s16 value) -{ - vol.Reg_VOL = value; - if (value & 0x8000) { // +Lin/-Lin/+Exp/-Exp - vol.Mode=(value & 0xF000)>>12; - vol.Increment=(value & 0x3F); - } - else { - vol.Mode=0; - vol.Increment=0; - - value<<=1; - vol.Value=value; - - } -} - -void CoreReset(int c) -{ -#define DEFAULT_VOICE_VOLUME 0x3FFF - int v=0; - - ConLog(" * SPU2: Initializing core %d structures... ",c); - - memset(Cores+c,0,sizeof(Cores[c])); - - Cores[c].Regs.STATX=0; - Cores[c].Regs.ATTR=0; - Cores[c].ExtL=0x3FFF; - Cores[c].ExtR=0x3FFF; - Cores[c].InpL=0x3FFF; - Cores[c].InpR=0x3FFF; - Cores[c].FxL=0x7FFF; - Cores[c].FxR=0x7FFF; - Cores[c].MasterL.Reg_VOL=0x3FFF; - Cores[c].MasterL.Value=0x7FFF; - Cores[c].MasterR.Reg_VOL=0x3FFF; - Cores[c].MasterR.Value=0x7FFF; - Cores[c].ExtWetR=1; - Cores[c].ExtWetL=1; - Cores[c].ExtDryR=1; - Cores[c].ExtDryL=1; - Cores[c].InpWetR=1; - Cores[c].InpWetL=1; - Cores[c].InpDryR=1; - Cores[c].InpDryL=1; - Cores[c].SndWetR=1; - Cores[c].SndWetL=1; - Cores[c].SndDryR=1; - Cores[c].SndDryL=1; - Cores[c].Regs.MMIX = 0xFFCF; - Cores[c].Regs.VMIXL = 0xFFFFFF; - Cores[c].Regs.VMIXR = 0xFFFFFF; - Cores[c].Regs.VMIXEL = 0xFFFFFF; - Cores[c].Regs.VMIXER = 0xFFFFFF; - Cores[c].EffectsStartA= 0xEFFF8 + 0x10000*c; - Cores[c].EffectsEndA = 0xEFFFF + 0x10000*c; - Cores[c].FxEnable=0; - Cores[c].IRQA=0xFFFF0; - Cores[c].IRQEnable=1; - - for (v=0;v<24;v++) { - AssignVolume(Cores[c].Voices[v].VolumeL,DEFAULT_VOICE_VOLUME); - AssignVolume(Cores[c].Voices[v].VolumeR,DEFAULT_VOICE_VOLUME); - Cores[c].Voices[v].ADSR.Value=0; - Cores[c].Voices[v].ADSR.Phase=0; - Cores[c].Voices[v].Pitch=0x3FFF; - Cores[c].Voices[v].DryL=1; - Cores[c].Voices[v].DryR=1; - Cores[c].Voices[v].WetL=1; - Cores[c].Voices[v].WetR=1; - Cores[c].Voices[v].NextA=2800; - Cores[c].Voices[v].StartA=2800; - Cores[c].Voices[v].LoopStartA=2800; - //Cores[c].Voices[v].lastSetStartA=2800; fixme: this is part of debug now - } - Cores[c].DMAICounter=0; - Cores[c].AdmaInProgress=0; - - Cores[c].Regs.STATX=0x80; - - ConLog("done.\n"); -} - -extern void LowPassFilterInit(); - -EXPORT_C_(s32) SPU2init() -{ -#define MAKESURE(a,b) \ - /*fprintf(stderr,"%08p: %08p == %08p\n",&(regtable[a>>1]),regtable[a>>1],U16P(b));*/ \ - assert(regtable[(a)>>1]==U16P(b)) - - MAKESURE(0x800,zero); - - s32 c=0,v=0; - ReadSettings(); - acumCycles=0; - -#ifdef SPU2_LOG - if(AccessLog()) - { - spu2Log = fopen(AccessLogFileName, "w"); - setvbuf(spu2Log, NULL, _IONBF, 0); - FileLog("SPU2init\n"); - } -#endif - srand((unsigned)time(NULL)); - - disableFreezes=false; - - if (spu2init) - { - ConLog( " * SPU2: Already initialized - Ignoring SPU2init signal." ); - return 0; - } - - spu2init=true; - - spu2regs = (short*)malloc(0x010000); - _spu2mem = (short*)malloc(0x200000); - - // adpcm decoder cache: - // the cache data size is determined by taking the number of adpcm blocks - // (2MB / 16) and multiplying it by the decoded block size (28 samples). - // Thus: pcm_cache_data = 7,340,032 bytes (ouch!) - // Expanded: 16 bytes expands to 56 bytes [3.5:1 ratio] - // Resulting in 2MB * 3.5. - - pcm_cache_data = (PcmCacheEntry*)calloc( pcm_BlockCount, sizeof(PcmCacheEntry) ); - - if( (spu2regs == NULL) || (_spu2mem == NULL) || - (pcm_cache_data == NULL) ) - { - SysMessage("SPU2: Error allocating Memory\n"); return -1; - } - - for(int mem=0;mem<0x800;mem++) - { - u16 *ptr=regtable[mem>>1]; - if(!ptr) { - regtable[mem>>1] = &(spu2Ru16(mem)); - } - } - - memset(spu2regs,0,0x010000); - memset(_spu2mem,0,0x200000); - memset(&Cores,0,(sizeof(V_Core) * 2)); - CoreReset(0); - CoreReset(1); - - DMALogOpen(); - - if(WaveLog()) - { - if(!wavedump_open()) - { - SysMessage("Can't open '%s'.\nWave Log disabled.",WaveLogFileName); - } - } - - for(v=0;v<16384;v++) - { - logvolume[v]=(s32)(s32)floor(log((double)(v+1))*3376.7); - } - - LowPassFilterInit(); - InitADSR(); - -#ifdef STREAM_DUMP - il0=fopen("logs/spu2input0.pcm","wb"); - il1=fopen("logs/spu2input1.pcm","wb"); -#endif - -#ifdef EFFECTS_DUMP - el0=fopen("logs/spu2fx0.pcm","wb"); - el1=fopen("logs/spu2fx1.pcm","wb"); -#endif - - -#ifdef S2R_ENABLE - if(!replay_mode) - s2r_open("replay_dump.s2r"); -#endif - return 0; -} - - -static BOOL CALLBACK DebugProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) -{ - int wmId,wmEvent; - - switch(uMsg) - { - case WM_PAINT: - return FALSE; - case WM_INITDIALOG: - { - debugDialogOpen=true; - } - break; - case WM_COMMAND: - wmId = LOWORD(wParam); - wmEvent = HIWORD(wParam); - // Parse the menu selections: - switch (wmId) - { - case IDOK: - case IDCANCEL: - debugDialogOpen=false; - EndDialog(hWnd,0); - break; - default: - return FALSE; - } - break; - default: - return FALSE; - } - return TRUE; -} - -EXPORT_C_(s32) SPU2open(void *pDsp) -{ - if( spu2open ) return 0; - - FileLog("[%10d] SPU2 Open\n",Cycles); - - /* - if(debugDialogOpen==0) - { - hDebugDialog = CreateDialogParam(hInstance,MAKEINTRESOURCE(IDD_DEBUG),0,DebugProc,0); - ShowWindow(hDebugDialog,SW_SHOWNORMAL); - debugDialogOpen=1; - }*/ - - spu2open=true; - if (!SndInit()) - { - srate_pv=(double)SampleRate/48000.0; - - spdif_init(); - - DspLoadLibrary(dspPlugin,dspPluginModule); - - return 0; - } - else - { - SPU2close(); - return -1; - }; -} - -EXPORT_C_(void) SPU2close() -{ - if( !spu2open ) return; - FileLog("[%10d] SPU2 Close\n",Cycles); - - DspCloseLibrary(); - spdif_shutdown(); - SndClose(); - - spu2open = false; -} - -EXPORT_C_(void) SPU2shutdown() -{ - if(!spu2init) return; - - ConLog( " * SPU2: Shutting down.\n" ); - - SPU2close(); - -#ifdef S2R_ENABLE - if(!replay_mode) - s2r_close(); -#endif - - DoFullDump(); -#ifdef STREAM_DUMP - fclose(il0); - fclose(il1); -#endif -#ifdef EFFECTS_DUMP - fclose(el0); - fclose(el1); -#endif - if(WaveLog() && wavedump_ok) wavedump_close(); - - DMALogClose(); - - spu2init = false; - - SAFE_FREE(spu2regs); - SAFE_FREE(_spu2mem); - - SAFE_FREE( pcm_cache_data ); - - spu2regs = NULL; - _spu2mem = NULL; - pcm_cache_data = NULL; - -#ifdef SPU2_LOG - if(!AccessLog()) return; - FileLog("[%10d] SPU2shutdown\n",Cycles); - if(spu2Log) fclose(spu2Log); -#endif -} - -EXPORT_C_(void) SPU2setClockPtr(u32 *ptr) -{ - cPtr=ptr; - hasPtr=(cPtr!=NULL); -} - -int FillRectangle(HDC dc, int left, int top, int width, int height) -{ - RECT r = { left, top, left+width, top+height }; - - return FillRect(dc, &r, (HBRUSH)GetStockObject(DC_BRUSH)); -} - -BOOL DrawRectangle(HDC dc, int left, int top, int width, int height) -{ - RECT r = { left, top, left+width, top+height }; - - POINT p[5] = { - { r.left, r.top }, - { r.right, r.top }, - { r.right, r.bottom }, - { r.left, r.bottom }, - { r.left, r.top }, - }; - - return Polyline(dc, p, 5); -} - -#ifndef PUBLIC -HFONT hf = NULL; -int lCount=0; -void UpdateDebugDialog() -{ - if(!debugDialogOpen) return; - - lCount++; - if(lCount>=(SampleRate/10)) - { - HDC hdc = GetDC(hDebugDialog); - - if(!hf) - { - hf = CreateFont( 8, 0, 0, 0, 0, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Lucida Console"); - } - - SelectObject(hdc,hf); - SelectObject(hdc,GetStockObject(DC_BRUSH)); - SelectObject(hdc,GetStockObject(DC_PEN)); - - for(int c=0;c<2;c++) - { - for(int v=0;v<24;v++) - { - int IX = 8+256*c; - int IY = 8+ 32*v; - V_Voice& vc(Cores[c].Voices[v]); - V_VoiceDebug& vcd( DebugCores[c].Voices[v] ); - - SetDCBrushColor(hdc,RGB( 0, 0, 0)); - if((vc.ADSR.Phase>0)&&(vc.ADSR.Phase<6)) - { - SetDCBrushColor(hdc,RGB( 0, 0,128)); - } - else - { - if(vcd.lastStopReason==1) - { - SetDCBrushColor(hdc,RGB(128, 0, 0)); - } - if(vcd.lastStopReason==2) - { - SetDCBrushColor(hdc,RGB( 0,128, 0)); - } - } - - FillRectangle(hdc,IX,IY,252,30); - - SetDCPenColor(hdc,RGB( 255, 128, 32)); - - DrawRectangle(hdc,IX,IY,252,30); - - SetDCBrushColor (hdc,RGB( 0,255, 0)); - - int vl = abs(vc.VolumeL.Value * 24 / 32768); - int vr = abs(vc.VolumeR.Value * 24 / 32768); - - FillRectangle(hdc,IX+38,IY+26 - vl, 4, vl); - FillRectangle(hdc,IX+42,IY+26 - vr, 4, vr); - - int adsr = (vc.ADSR.Value>>16) * 24 / 32768; - - FillRectangle(hdc,IX+48,IY+26 - adsr, 4, adsr); - - int peak = vcd.displayPeak * 24 / 32768; - - FillRectangle(hdc,IX+56,IY+26 - peak, 4, peak); - - SetTextColor(hdc,RGB( 0,255, 0)); - SetBkColor (hdc,RGB( 0, 0, 0)); - - static char t[1024]; - - sprintf(t,"%06x",vc.StartA); - TextOut(hdc,IX+4,IY+3,t,6); - - sprintf(t,"%06x",vc.NextA); - TextOut(hdc,IX+4,IY+12,t,6); - - sprintf(t,"%06x",vc.LoopStartA); - TextOut(hdc,IX+4,IY+21,t,6); - - vcd.displayPeak = 0; - - if(vcd.lastSetStartA != vc.StartA) - { - printf(" *** Warning! Core %d Voice %d: StartA should be %06x, and is %06x.\n", - c,v,vcd.lastSetStartA,vc.StartA); - vcd.lastSetStartA = vc.StartA; - } - } - } - ReleaseDC(hDebugDialog,hdc); - lCount=0; - } - - MSG msg; - while(PeekMessage(&msg,hDebugDialog,0,0,PM_REMOVE)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } -} -#endif - -#define TickInterval 768 -#define SanityInterval 4800 - -u32 TicksCore=0; -u32 TicksThread=0; - -static DWORD CALLBACK TimeThread(PVOID /* unused param */) -{ - while(spu2open) - { - if(TicksThread>=(TicksCore+320)) - { - Sleep(1); - } - else if(TicksThread>=TicksCore) - { - Sleep(0); - } - else - { - Mix(); - TicksThread++; - } - } - return 0; -} - -void __fastcall TimeUpdate(u32 cClocks) -{ - u32 dClocks = cClocks-lClocks; - - // [Air]: Sanity Check - // If for some reason our clock value seems way off base, just mix - // out a little bit, skip the rest, and hope the ship "rights" itself later on. - - if( dClocks > TickInterval*SanityInterval ) - { - ConLog( " * SPU2 > TimeUpdate Sanity Check (Tick Delta: %d) (PS2 Ticks: %d)\n", dClocks/TickInterval, cClocks/TickInterval ); - dClocks = TickInterval*SanityInterval; - lClocks = cClocks-dClocks; - } - - //UpdateDebugDialog(); - - //Update Mixing Progress - while(dClocks>=TickInterval) - { - if(has_to_call_irq) - { - ConLog(" * SPU2: Irq Called (%04x).\n",Spdif.Info); - has_to_call_irq=false; - if(_irqcallback) _irqcallback(); - } - - if(Cores[0].InitDelay>0) - { - Cores[0].InitDelay--; - if(Cores[0].InitDelay==0) - { - CoreReset(0); - } - } - - if(Cores[1].InitDelay>0) - { - Cores[1].InitDelay--; - if(Cores[1].InitDelay==0) - { - CoreReset(1); - } - } - - //Update DMA4 interrupt delay counter - if(Cores[0].DMAICounter>0) - { - Cores[0].DMAICounter-=TickInterval; - if(Cores[0].DMAICounter<=0) - { - Cores[0].MADR=Cores[0].TADR; - Cores[0].DMAICounter=0; - if(dma4callback) dma4callback(); - } - else { - Cores[0].MADR+=TickInterval<<1; - } - } - - //Update DMA7 interrupt delay counter - if(Cores[1].DMAICounter>0) - { - Cores[1].DMAICounter-=TickInterval; - if(Cores[1].DMAICounter<=0) - { - Cores[1].MADR=Cores[1].TADR; - Cores[1].DMAICounter=0; - //ConLog( "* SPU2 > DMA 7 Callback! %d\n", Cycles ); - if(dma7callback) dma7callback(); - } - else { - Cores[1].MADR+=TickInterval<<1; - } - } - - dClocks-=TickInterval; - lClocks+=TickInterval; - Cycles++; - - Mix(); - } -} - -bool numpad_minus_old=false; -bool numpad_minus = false; - -bool numpad_plus = false, numpad_plus_old = false; - -EXPORT_C_(void) SPU2async(u32 cycles) -{ -#ifndef PUBLIC - u32 oldClocks = lClocks; - static u32 timer=0,time1=0,time2=0; - timer++; - if (timer == 1){ - time1=timeGetTime(); - } - if (timer == 3000){ - time2 = timeGetTime()-time1 ; - timer=0; - } -#endif - - DspUpdate(); - - if(LimiterToggleEnabled) - { - numpad_minus = (GetAsyncKeyState(VK_SUBTRACT)&0x8000)!=0; - - if(numpad_minus && !numpad_minus_old) - { - if(LimitMode) LimitMode=0; - else LimitMode=1; - SndUpdateLimitMode(); - } - numpad_minus_old = numpad_minus; - } - -#ifndef PUBLIC - /*numpad_plus = (GetAsyncKeyState(VK_ADD)&0x8000)!=0; - if(numpad_plus && !numpad_plus_old) - { - DoFullDump(); - } - numpad_plus_old = numpad_plus;*/ -#endif - - if(hasPtr) - { - TimeUpdate(*cPtr); - } - else - { - pClocks+=cycles; - TimeUpdate(pClocks); - } -} - -EXPORT_C_(void) SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()) -{ - _irqcallback=SPU2callback; - dma4callback=DMA4callback; - dma7callback=DMA7callback; -} - -u16 mask = 0xFFFF; - -void UpdateSpdifMode() -{ - int OPM=PlayMode; - u16 last = 0; - - if(mask&Spdif.Out) - { - last = mask & Spdif.Out; - mask=mask&(~Spdif.Out); - } - - if(Spdif.Out&0x4) // use 24/32bit PCM data streaming - { - PlayMode=8; - ConLog(" * SPU2: WARNING: Possibly CDDA mode set!\n"); - return; - } - - if(Spdif.Out&SPDIF_OUT_BYPASS) - { - PlayMode=2; - if(Spdif.Mode&SPDIF_MODE_BYPASS_BITSTREAM) - PlayMode=4; //bitstream bypass - } - else - { - PlayMode=0; //normal processing - if(Spdif.Out&SPDIF_OUT_PCM) - { - PlayMode=1; - } - } - if(OPM!=PlayMode) - { - ConLog(" * SPU2: Play Mode Set to %s (%d).\n",(PlayMode==0)?"Normal":((PlayMode==1)?"PCM Clone":((PlayMode==2)?"PCM Bypass":"BitStream Bypass")),PlayMode); - } -} - -__forceinline void RegLog(int level, char *RName,u32 mem,u32 core,u16 value) -{ - if( level > 1 ) - FileLog("[%10d] SPU2 write mem %08x (core %d, register %s) value %04x\n",Cycles,mem,core,RName,value); -} - -static void SPU_ps1_write(u32 mem, u16 value) -{ - bool show=true; - - u32 reg = mem&0xffff; - - if((reg>=0x1c00)&&(reg<0x1d80)) - { - //voice values - u8 voice = ((reg-0x1c00)>>4); - u8 vval = reg&0xf; - switch(vval) - { - case 0: //VOLL (Volume L) - Cores[0].Voices[voice].VolumeL.Mode=0; - Cores[0].Voices[voice].VolumeL.Value=value<<1; - Cores[0].Voices[voice].VolumeL.Reg_VOL = value; break; - case 1: //VOLR (Volume R) - Cores[0].Voices[voice].VolumeR.Mode=0; - Cores[0].Voices[voice].VolumeR.Value=value<<1; - Cores[0].Voices[voice].VolumeR.Reg_VOL = value; break; - case 2: Cores[0].Voices[voice].Pitch=value; break; - case 3: Cores[0].Voices[voice].StartA=(u32)value<<8; break; - case 4: // ADSR1 (Envelope) - Cores[0].Voices[voice].ADSR.Am=(value & 0x8000)>>15; - Cores[0].Voices[voice].ADSR.Ar=(value & 0x7F00)>>8; - Cores[0].Voices[voice].ADSR.Dr=(value & 0xF0)>>4; - Cores[0].Voices[voice].ADSR.Sl=(value & 0xF); - Cores[0].Voices[voice].ADSR.Reg_ADSR1 = value; break; - case 5: // ADSR2 (Envelope) - Cores[0].Voices[voice].ADSR.Sm=(value & 0xE000)>>13; - Cores[0].Voices[voice].ADSR.Sr=(value & 0x1FC0)>>6; - Cores[0].Voices[voice].ADSR.Rm=(value & 0x20)>>5; - Cores[0].Voices[voice].ADSR.Rr=(value & 0x1F); - Cores[0].Voices[voice].ADSR.Reg_ADSR2 = value; break; - case 6: - // [Air] Experimental --> shifting value into a 31 bit range. - // shifting by 16 might be more correct? - Cores[0].Voices[voice].ADSR.Value = value<<15; - ConLog( "* SPU2: Mysterious ADSR Volume Set to 0x%x", value ); - break; - case 7: Cores[0].Voices[voice].LoopStartA=(u32)value <<8; break; - - jNO_DEFAULT; - } - } - else switch(reg) - { - case 0x1d80:// Mainvolume left - Cores[0].MasterL.Mode=0; - Cores[0].MasterL.Value=value; - break; - case 0x1d82:// Mainvolume right - Cores[0].MasterL.Mode=0; - Cores[0].MasterR.Value=value; - break; - case 0x1d84:// Reverberation depth left - Cores[0].FxL=value; - break; - case 0x1d86:// Reverberation depth right - Cores[0].FxR=value; - break; - - case 0x1d88:// Voice ON (0-15) - SPU2_FastWrite(REG_S_KON,value); - break; - case 0x1d8a:// Voice ON (16-23) - SPU2_FastWrite(REG_S_KON+2,value); - break; - - case 0x1d8c:// Voice OFF (0-15) - SPU2_FastWrite(REG_S_KOFF,value); - break; - case 0x1d8e:// Voice OFF (16-23) - SPU2_FastWrite(REG_S_KOFF+2,value); - break; - - case 0x1d90:// Channel FM (pitch lfo) mode (0-15) - SPU2_FastWrite(REG_S_PMON,value); - break; - case 0x1d92:// Channel FM (pitch lfo) mode (16-23) - SPU2_FastWrite(REG_S_PMON+2,value); - break; - - - case 0x1d94:// Channel Noise mode (0-15) - SPU2_FastWrite(REG_S_NON,value); - break; - case 0x1d96:// Channel Noise mode (16-23) - SPU2_FastWrite(REG_S_NON+2,value); - break; - - case 0x1d98:// Channel Reverb mode (0-15) - SPU2_FastWrite(REG_S_VMIXEL,value); - SPU2_FastWrite(REG_S_VMIXER,value); - break; - case 0x1d9a:// Channel Reverb mode (16-23) - SPU2_FastWrite(REG_S_VMIXEL+2,value); - SPU2_FastWrite(REG_S_VMIXER+2,value); - break; - case 0x1d9c:// Channel Reverb mode (0-15) - SPU2_FastWrite(REG_S_VMIXL,value); - SPU2_FastWrite(REG_S_VMIXR,value); - break; - case 0x1d9e:// Channel Reverb mode (16-23) - SPU2_FastWrite(REG_S_VMIXL+2,value); - SPU2_FastWrite(REG_S_VMIXR+2,value); - break; - - case 0x1da2:// Reverb work area start - { - u32 val=(u32)value <<8; - - SPU2_FastWrite(REG_A_ESA, val&0xFFFF); - SPU2_FastWrite(REG_A_ESA+2,val>>16); - } - break; - case 0x1da4: - Cores[0].IRQA=(u32)value<<8; - break; - case 0x1da6: - Cores[0].TSA=(u32)value<<8; - break; - - case 0x1daa: - SPU2_FastWrite(REG_C_ATTR,value); - break; - case 0x1dae: - SPU2_FastWrite(REG_P_STATX,value); - break; - case 0x1da8:// Spu Write to Memory - DmaWrite(0,value); - show=false; - break; - } - - if(show) FileLog("[%10d] (!) SPU write mem %08x value %04x\n",Cycles,mem,value); - - spu2Ru16(mem)=value; -} - -static u16 SPU_ps1_read(u32 mem) -{ - bool show=true; - u16 value = spu2Ru16(mem); - - u32 reg = mem&0xffff; - - if((reg>=0x1c00)&&(reg<0x1d80)) - { - //voice values - u8 voice = ((reg-0x1c00)>>4); - u8 vval = reg&0xf; - switch(vval) - { - case 0: //VOLL (Volume L) - value=Cores[0].Voices[voice].VolumeL.Mode; - value=Cores[0].Voices[voice].VolumeL.Value; - value=Cores[0].Voices[voice].VolumeL.Reg_VOL; break; - case 1: //VOLR (Volume R) - value=Cores[0].Voices[voice].VolumeR.Mode; - value=Cores[0].Voices[voice].VolumeR.Value; - value=Cores[0].Voices[voice].VolumeR.Reg_VOL; break; - case 2: value=Cores[0].Voices[voice].Pitch; break; - case 3: value=Cores[0].Voices[voice].StartA; break; - case 4: value=Cores[0].Voices[voice].ADSR.Reg_ADSR1; break; - case 5: value=Cores[0].Voices[voice].ADSR.Reg_ADSR2; break; - case 6: value=Cores[0].Voices[voice].ADSR.Value >> 16; break; - case 7: value=Cores[0].Voices[voice].LoopStartA; break; - - jNO_DEFAULT; - } - } - else switch(reg) - { - case 0x1d80: value = Cores[0].MasterL.Value; break; - case 0x1d82: value = Cores[0].MasterR.Value; break; - case 0x1d84: value = Cores[0].FxL; break; - case 0x1d86: value = Cores[0].FxR; break; - - case 0x1d88: value = 0; break; - case 0x1d8a: value = 0; break; - case 0x1d8c: value = 0; break; - case 0x1d8e: value = 0; break; - - case 0x1d90: value = Cores[0].Regs.PMON&0xFFFF; break; - case 0x1d92: value = Cores[0].Regs.PMON>>16; break; - - case 0x1d94: value = Cores[0].Regs.NON&0xFFFF; break; - case 0x1d96: value = Cores[0].Regs.NON>>16; break; - - case 0x1d98: value = Cores[0].Regs.VMIXEL&0xFFFF; break; - case 0x1d9a: value = Cores[0].Regs.VMIXEL>>16; break; - case 0x1d9c: value = Cores[0].Regs.VMIXL&0xFFFF; break; - case 0x1d9e: value = Cores[0].Regs.VMIXL>>16; break; - - case 0x1da2: value = Cores[0].EffectsStartA>>3; break; - case 0x1da4: value = Cores[0].IRQA>>3; break; - case 0x1da6: value = Cores[0].TSA>>3; break; - - case 0x1daa: - value = SPU2read(REG_C_ATTR); - break; - case 0x1dae: - value = 0; //SPU2read(REG_P_STATX)<<3; - break; - case 0x1da8: - value = DmaRead(0); - show=false; - break; - } - - if(show) FileLog("[%10d] (!) SPU read mem %08x value %04x\n",Cycles,mem,value); - return value; -} - -void RegWriteLog(u32 core,u16 value); - -static void SPU2writeLog(u32 rmem, u16 value) -{ -#ifndef PUBLIC - u32 vx=0, vc=0, core=0, omem=rmem, mem=rmem&0x7FF; - omem=mem=mem&0x7FF; //FFFF; - if (mem & 0x400) { omem^=0x400; core=1; } - - /* - if ((omem >= 0x0000) && (omem < 0x0180)) { // Voice Params - u32 voice=(omem & 0x1F0) >> 4; - u32 param=(omem & 0xF)>>1; - FileLog("[%10d] SPU2 write mem %08x (Core %d Voice %d Param %s) value %x\n",Cycles,rmem,core,voice,ParamNames[param],value); - } - else if ((omem >= 0x01C0) && (omem < 0x02DE)) { - u32 voice =((omem-0x01C0) / 12); - u32 address =((omem-0x01C0) % 12)>>1; - FileLog("[%10d] SPU2 write mem %08x (Core %d Voice %d Address %s) value %x\n",Cycles,rmem,core,voice,AddressNames[address],value); - } - */ - if ((mem >= 0x0760) && (mem < 0x07b0)) { - omem=mem; core=0; - if (mem >= 0x0788) {omem-=0x28; core=1;} - switch(omem) { - case REG_P_EVOLL: RegLog(2,"EVOLL",rmem,core,value); break; - case REG_P_EVOLR: RegLog(2,"EVOLR",rmem,core,value); break; - case REG_P_AVOLL: if (core) { RegLog(2,"AVOLL",rmem,core,value); } break; - case REG_P_AVOLR: if (core) { RegLog(2,"AVOLR",rmem,core,value); } break; - case REG_P_BVOLL: RegLog(2,"BVOLL",rmem,core,value); break; - case REG_P_BVOLR: RegLog(2,"BVOLR",rmem,core,value); break; - case REG_P_MVOLXL: RegLog(2,"MVOLXL",rmem,core,value); break; - case REG_P_MVOLXR: RegLog(2,"MVOLXR",rmem,core,value); break; - case R_IIR_ALPHA: RegLog(2,"IIR_ALPHA",rmem,core,value); break; - case R_ACC_COEF_A: RegLog(2,"ACC_COEF_A",rmem,core,value); break; - case R_ACC_COEF_B: RegLog(2,"ACC_COEF_B",rmem,core,value); break; - case R_ACC_COEF_C: RegLog(2,"ACC_COEF_C",rmem,core,value); break; - case R_ACC_COEF_D: RegLog(2,"ACC_COEF_D",rmem,core,value); break; - case R_IIR_COEF: RegLog(2,"IIR_COEF",rmem,core,value); break; - case R_FB_ALPHA: RegLog(2,"FB_ALPHA",rmem,core,value); break; - case R_FB_X: RegLog(2,"FB_X",rmem,core,value); break; - case R_IN_COEF_L: RegLog(2,"IN_COEF_L",rmem,core,value); break; - case R_IN_COEF_R: RegLog(2,"IN_COEF_R",rmem,core,value); break; - - } - } - else if ((mem>=0x07C0) && (mem<0x07CE)) { - switch(mem) { - case SPDIF_OUT: - RegLog(2,"SPDIF_OUT",rmem,-1,value); - break; - case IRQINFO: - RegLog(2,"IRQINFO",rmem,-1,value); - break; - case 0x7c4: - if(Spdif.Unknown1 != value) ConLog(" * SPU2: SPDIF Unknown Register 1 set to %04x\n",value); - RegLog(2,"SPDIF_UNKNOWN1",rmem,-1,value); - break; - case SPDIF_MODE: - if(Spdif.Mode != value) ConLog(" * SPU2: SPDIF Mode set to %04x\n",value); - RegLog(2,"SPDIF_MODE",rmem,-1,value); - break; - case SPDIF_MEDIA: - if(Spdif.Media != value) ConLog(" * SPU2: SPDIF Media set to %04x\n",value); - RegLog(2,"SPDIF_MEDIA",rmem,-1,value); - break; - case 0x7ca: - if(Spdif.Unknown2 != value) ConLog(" * SPU2: SPDIF Unknown Register 2 set to %04x\n",value); - RegLog(2,"SPDIF_UNKNOWN2",rmem,-1,value); - break; - case SPDIF_COPY: - if(Spdif.Protection != value) ConLog(" * SPU2: SPDIF Copy set to %04x\n",value); - RegLog(2,"SPDIF_COPY",rmem,-1,value); - break; - } - UpdateSpdifMode(); - } - else - switch(omem) { - case REG_C_ATTR: - RegLog(4,"ATTR",rmem,core,value); - break; - case REG_S_PMON: - RegLog(1,"PMON0",rmem,core,value); - break; - case (REG_S_PMON + 2): - RegLog(1,"PMON1",rmem,core,value); - break; - case REG_S_NON: - RegLog(1,"NON0",rmem,core,value); - break; - case (REG_S_NON + 2): - RegLog(1,"NON1",rmem,core,value); - break; - case REG_S_VMIXL: - RegLog(1,"VMIXL0",rmem,core,value); - case (REG_S_VMIXL + 2): - RegLog(1,"VMIXL1",rmem,core,value); - break; - case REG_S_VMIXEL: - RegLog(1,"VMIXEL0",rmem,core,value); - break; - case (REG_S_VMIXEL + 2): - RegLog(1,"VMIXEL1",rmem,core,value); - break; - case REG_S_VMIXR: - RegLog(1,"VMIXR0",rmem,core,value); - break; - case (REG_S_VMIXR + 2): - RegLog(1,"VMIXR1",rmem,core,value); - break; - case REG_S_VMIXER: - RegLog(1,"VMIXER0",rmem,core,value); - break; - case (REG_S_VMIXER + 2): - RegLog(1,"VMIXER1",rmem,core,value); - break; - case REG_P_MMIX: - RegLog(1,"MMIX",rmem,core,value); - break; - case REG_A_IRQA: - RegLog(2,"IRQAH",rmem,core,value); - break; - case (REG_A_IRQA + 2): - RegLog(2,"IRQAL",rmem,core,value); - break; - case (REG_S_KON + 2): - RegLog(2,"KON1",rmem,core,value); - break; - case REG_S_KON: - RegLog(2,"KON0",rmem,core,value); - break; - case (REG_S_KOFF + 2): - RegLog(2,"KOFF1",rmem,core,value); - break; - case REG_S_KOFF: - RegLog(2,"KOFF0",rmem,core,value); - break; - case REG_A_TSA: - RegLog(2,"TSAH",rmem,core,value); - break; - case (REG_A_TSA + 2): - RegLog(2,"TSAL",rmem,core,value); - break; - case REG_S_ENDX: - //ConLog(" * SPU2: Core %d ENDX cleared!\n",core); - RegLog(2,"ENDX0",rmem,core,value); - break; - case (REG_S_ENDX + 2): - //ConLog(" * SPU2: Core %d ENDX cleared!\n",core); - RegLog(2,"ENDX1",rmem,core,value); - break; - case REG_P_MVOLL: - RegLog(1,"MVOLL",rmem,core,value); - break; - case REG_P_MVOLR: - RegLog(1,"MVOLR",rmem,core,value); - break; - case REG_S_ADMAS: - RegLog(3,"ADMAS",rmem,core,value); - ConLog(" * SPU2: Core %d AutoDMAControl set to %d\n",core,value); - break; - case REG_P_STATX: - RegLog(3,"STATX",rmem,core,value); - break; - case REG_A_ESA: - RegLog(1,"ESAH",rmem,core,value); - break; - case (REG_A_ESA + 2): - RegLog(1,"ESAL",rmem,core,value); - break; - case REG_A_EEA: - RegLog(1,"EEAH",rmem,core,value); - break; - -#define LOG_REVB_REG(n,t) \ - case R_##n: \ - RegLog(2,t "H",mem,core,value); \ - break; \ - case (R_##n + 2): \ - RegLog(2,t "L",mem,core,value); \ - break; - - LOG_REVB_REG(FB_SRC_A,"FB_SRC_A") - LOG_REVB_REG(FB_SRC_B,"FB_SRC_B") - LOG_REVB_REG(IIR_SRC_A0,"IIR_SRC_A0") - LOG_REVB_REG(IIR_SRC_A1,"IIR_SRC_A1") - LOG_REVB_REG(IIR_SRC_B1,"IIR_SRC_B1") - LOG_REVB_REG(IIR_SRC_B0,"IIR_SRC_B0") - LOG_REVB_REG(IIR_DEST_A0,"IIR_DEST_A0") - LOG_REVB_REG(IIR_DEST_A1,"IIR_DEST_A1") - LOG_REVB_REG(IIR_DEST_B0,"IIR_DEST_B0") - LOG_REVB_REG(IIR_DEST_B1,"IIR_DEST_B1") - LOG_REVB_REG(ACC_SRC_A0,"ACC_SRC_A0") - LOG_REVB_REG(ACC_SRC_A1,"ACC_SRC_A1") - LOG_REVB_REG(ACC_SRC_B0,"ACC_SRC_B0") - LOG_REVB_REG(ACC_SRC_B1,"ACC_SRC_B1") - LOG_REVB_REG(ACC_SRC_C0,"ACC_SRC_C0") - LOG_REVB_REG(ACC_SRC_C1,"ACC_SRC_C1") - LOG_REVB_REG(ACC_SRC_D0,"ACC_SRC_D0") - LOG_REVB_REG(ACC_SRC_D1,"ACC_SRC_D1") - LOG_REVB_REG(MIX_DEST_A0,"MIX_DEST_A0") - LOG_REVB_REG(MIX_DEST_A1,"MIX_DEST_A1") - LOG_REVB_REG(MIX_DEST_B0,"MIX_DEST_B0") - LOG_REVB_REG(MIX_DEST_B1,"MIX_DEST_B1") - - default: RegLog(2,"UNKNOWN",rmem,core,value); spu2Ru16(mem) = value; - } -#endif -} - - -static __forceinline void SPU2_FastWrite( u32 rmem, u16 value ) -{ - u32 vx=0, vc=0, core=0, omem, mem; - omem=mem=rmem & 0x7FF; //FFFF; - if (mem & 0x400) { omem^=0x400; core=1; } - - //else if ((omem >= 0x0000) && (omem < 0x0180)) { // Voice Params - if (omem < 0x0180) { // Voice Params - u32 voice=(omem & 0x1F0) >> 4; - u32 param=(omem & 0xF)>>1; - //FileLog("[%10d] SPU2 write mem %08x (Core %d Voice %d Param %s) value %x\n",Cycles,rmem,core,voice,ParamNames[param],value); - switch (param) { - case 0: //VOLL (Volume L) - if (value & 0x8000) { // +Lin/-Lin/+Exp/-Exp - Cores[core].Voices[voice].VolumeL.Mode=(value & 0xF000)>>12; - Cores[core].Voices[voice].VolumeL.Increment=(value & 0x3F); - } - else { - Cores[core].Voices[voice].VolumeL.Mode=0; - Cores[core].Voices[voice].VolumeL.Increment=0; - if(value&0x4000) - value=0x3fff - (value&0x3fff); - Cores[core].Voices[voice].VolumeL.Value=value<<1; - } - Cores[core].Voices[voice].VolumeL.Reg_VOL = value; break; - case 1: //VOLR (Volume R) - if (value & 0x8000) { - Cores[core].Voices[voice].VolumeR.Mode=(value & 0xF000)>>12; - Cores[core].Voices[voice].VolumeR.Increment=(value & 0x3F); - } - else { - Cores[core].Voices[voice].VolumeR.Mode=0; - Cores[core].Voices[voice].VolumeR.Increment=0; - Cores[core].Voices[voice].VolumeR.Value=value<<1; - } - Cores[core].Voices[voice].VolumeR.Reg_VOL = value; break; - case 2: Cores[core].Voices[voice].Pitch=value; break; - case 3: // ADSR1 (Envelope) - Cores[core].Voices[voice].ADSR.Am=(value & 0x8000)>>15; - Cores[core].Voices[voice].ADSR.Ar=(value & 0x7F00)>>8; - Cores[core].Voices[voice].ADSR.Dr=(value & 0xF0)>>4; - Cores[core].Voices[voice].ADSR.Sl=(value & 0xF); - Cores[core].Voices[voice].ADSR.Reg_ADSR1 = value; break; - case 4: // ADSR2 (Envelope) - Cores[core].Voices[voice].ADSR.Sm=(value & 0xE000)>>13; - Cores[core].Voices[voice].ADSR.Sr=(value & 0x1FC0)>>6; - Cores[core].Voices[voice].ADSR.Rm=(value & 0x20)>>5; - Cores[core].Voices[voice].ADSR.Rr=(value & 0x1F); - Cores[core].Voices[voice].ADSR.Reg_ADSR2 = value; break; - case 5: - // [Air] : Mysterious volume set code. Too bad none of my games ever use it. - // (as usual... ) - Cores[core].Voices[voice].ADSR.Value = value << 15; - ConLog( "* SPU2: Mysterious ADSR Volume Set to 0x%x", value ); - break; - case 6: Cores[core].Voices[voice].VolumeL.Value=value; break; - case 7: Cores[core].Voices[voice].VolumeR.Value=value; break; - - jNO_DEFAULT; - } - } - else if ((omem >= 0x01C0) && (omem < 0x02DE)) { - u32 voice =((omem-0x01C0) / 12); - u32 address =((omem-0x01C0) % 12)>>1; - //FileLog("[%10d] SPU2 write mem %08x (Core %d Voice %d Address %s) value %x\n",Cycles,rmem,core,voice,AddressNames[address],value); - - switch (address) { - case 0: Cores[core].Voices[voice].StartA=((value & 0x0F) << 16) | (Cores[core].Voices[voice].StartA & 0xFFF8); - #ifndef PUBLIC - DebugCores[core].Voices[voice].lastSetStartA = Cores[core].Voices[voice].StartA; - #endif - break; - case 1: Cores[core].Voices[voice].StartA=(Cores[core].Voices[voice].StartA & 0x0F0000) | (value & 0xFFF8); - #ifndef PUBLIC - DebugCores[core].Voices[voice].lastSetStartA = Cores[core].Voices[voice].StartA; - #endif - //if(core==1) printf(" *** StartA for C%dV%02d set to 0x%05x\n",core,voice,Cores[core].Voices[voice].StartA); - break; - case 2: Cores[core].Voices[voice].LoopStartA=((value & 0x0F) << 16) | (Cores[core].Voices[voice].LoopStartA & 0xFFF8); - Cores[core].Voices[voice].LoopMode=3; break; - case 3: Cores[core].Voices[voice].LoopStartA=(Cores[core].Voices[voice].LoopStartA & 0x0F0000) | (value & 0xFFF8);break; - Cores[core].Voices[voice].LoopMode=3; break; - case 4: Cores[core].Voices[voice].NextA=((value & 0x0F) << 16) | (Cores[core].Voices[voice].NextA & 0xFFF8); - //printf(" *** Warning: C%dV%02d NextA MODIFIED EXTERNALLY!\n",core,voice); - break; - case 5: Cores[core].Voices[voice].NextA=(Cores[core].Voices[voice].NextA & 0x0F0000) | (value & 0xFFF8); - //printf(" *** Warning: C%dV%02d NextA MODIFIED EXTERNALLY!\n",core,voice); - break; - } - } - else - switch(omem) { - case REG_C_ATTR: - RegLog(4,"ATTR",rmem,core,value); - { - int irqe=Cores[core].IRQEnable; - int bit0=Cores[core].AttrBit0; - int bit4=Cores[core].AttrBit4; - - if(((value>>15)&1)&&(!Cores[core].CoreEnabled)&&(Cores[core].InitDelay==0)) // on init/reset - { - if(hasPtr) - { - Cores[core].InitDelay=1; - Cores[core].Regs.STATX=0; - } - else - { - CoreReset(core); - } - } - - Cores[core].AttrBit0 =(value>> 0) & 0x01; //1 bit - Cores[core].DMABits =(value>> 1) & 0x07; //3 bits - Cores[core].AttrBit4 =(value>> 4) & 0x01; //1 bit - Cores[core].AttrBit5 =(value>> 5) & 0x01; //1 bit - Cores[core].IRQEnable =(value>> 6) & 0x01; //1 bit - Cores[core].FxEnable =(value>> 7) & 0x01; //1 bit - Cores[core].NoiseClk =(value>> 8) & 0x3f; //6 bits - //Cores[core].Mute =(value>>14) & 0x01; //1 bit - Cores[core].Mute=0; - Cores[core].CoreEnabled=(value>>15) & 0x01; //1 bit - Cores[core].Regs.ATTR =value&0x7fff; - - if(value&0x000E) - { - ConLog(" * SPU2: Core %d ATTR unknown bits SET! value=%04x\n",core,value); - } - - if(Cores[core].AttrBit0!=bit0) - { - ConLog(" * SPU2: ATTR bit 0 set to %d\n",Cores[core].AttrBit0); - } - if(Cores[core].IRQEnable!=irqe) - { - ConLog(" * SPU2: IRQ %s\n",((Cores[core].IRQEnable==0)?"disabled":"enabled")); - if(!Cores[core].IRQEnable) - Spdif.Info=0; - } - - } - break; - case REG_S_PMON: - RegLog(1,"PMON0",rmem,core,value); - vx=2; for (vc=1;vc<16;vc++) { Cores[core].Voices[vc].Modulated=(s8)((value & vx)/vx); vx<<=1; } - Cores[core].Regs.PMON = (Cores[core].Regs.PMON & 0xFFFF0000) | value; - break; - case (REG_S_PMON + 2): - RegLog(1,"PMON1",rmem,core,value); - vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].Modulated=(s8)((value & vx)/vx); vx<<=1; } - Cores[core].Regs.PMON = (Cores[core].Regs.PMON & 0xFFFF) | (value << 16); - break; - case REG_S_NON: - RegLog(1,"NON0",rmem,core,value); - vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].Noise=(s8)((value & vx)/vx); vx<<=1; } - Cores[core].Regs.NON = (Cores[core].Regs.NON & 0xFFFF0000) | value; - break; - case (REG_S_NON + 2): - RegLog(1,"NON1",rmem,core,value); - vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].Noise=(s8)((value & vx)/vx); vx<<=1; } - Cores[core].Regs.NON = (Cores[core].Regs.NON & 0xFFFF) | (value << 16); - break; - case REG_S_VMIXL: - RegLog(1,"VMIXL0",rmem,core,value); - vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].DryL=(s8)((value & vx)/vx); vx<<=1; } - Cores[core].Regs.VMIXL = (Cores[core].Regs.VMIXL & 0xFFFF0000) | value; - case (REG_S_VMIXL + 2): - RegLog(1,"VMIXL1",rmem,core,value); - vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].DryL=(s8)((value & vx)/vx); vx<<=1; } - Cores[core].Regs.VMIXL = (Cores[core].Regs.VMIXL & 0xFFFF) | (value << 16); - case REG_S_VMIXEL: - RegLog(1,"VMIXEL0",rmem,core,value); - vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].WetL=(s8)((value & vx)/vx); vx<<=1; } - Cores[core].Regs.VMIXEL = (Cores[core].Regs.VMIXEL & 0xFFFF0000) | value; - break; - case (REG_S_VMIXEL + 2): - RegLog(1,"VMIXEL1",rmem,core,value); - vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].WetL=(s8)((value & vx)/vx); vx<<=1; } - Cores[core].Regs.VMIXEL = (Cores[core].Regs.VMIXEL & 0xFFFF) | (value << 16); - break; - case REG_S_VMIXR: - RegLog(1,"VMIXR0",rmem,core,value); - vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].DryR=(s8)((value & vx)/vx); vx<<=1; } - Cores[core].Regs.VMIXR = (Cores[core].Regs.VMIXR & 0xFFFF0000) | value; - break; - case (REG_S_VMIXR + 2): - RegLog(1,"VMIXR1",rmem,core,value); - vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].DryR=(s8)((value & vx)/vx); vx<<=1; } - Cores[core].Regs.VMIXR = (Cores[core].Regs.VMIXR & 0xFFFF) | (value << 16); - break; - case REG_S_VMIXER: - RegLog(1,"VMIXER0",rmem,core,value); - vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].WetR=(s8)((value & vx)/vx); vx<<=1; } - Cores[core].Regs.VMIXER = (Cores[core].Regs.VMIXER & 0xFFFF0000) | value; - break; - case (REG_S_VMIXER + 2): - RegLog(1,"VMIXER1",rmem,core,value); - vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].WetR=(s8)((value & vx)/vx); vx<<=1; } - Cores[core].Regs.VMIXER = (Cores[core].Regs.VMIXER & 0xFFFF) | (value << 16); - break; - case REG_P_MMIX: - RegLog(1,"MMIX",rmem,core,value); - vx=value; - if (core == 0) vx&=0xFF0; - Cores[core].ExtWetR=(vx & 0x001); - Cores[core].ExtWetL=(vx & 0x002)>>1; - Cores[core].ExtDryR=(vx & 0x004)>>2; - Cores[core].ExtDryL=(vx & 0x008)>>3; - Cores[core].InpWetR=(vx & 0x010)>>4; - Cores[core].InpWetL=(vx & 0x020)>>5; - Cores[core].InpDryR=(vx & 0x040)>>6; - Cores[core].InpDryL=(vx & 0x080)>>7; - Cores[core].SndWetR=(vx & 0x100)>>8; - Cores[core].SndWetL=(vx & 0x200)>>9; - Cores[core].SndDryR=(vx & 0x400)>>10; - Cores[core].SndDryL=(vx & 0x800)>>11; - Cores[core].Regs.MMIX = value; - break; - case (REG_S_KON + 2): - RegLog(2,"KON1",rmem,core,value); - StartVoices(core,((u32)value)<<16); - break; - case REG_S_KON: - RegLog(2,"KON0",rmem,core,value); - StartVoices(core,((u32)value)); - break; - case (REG_S_KOFF + 2): - RegLog(2,"KOFF1",rmem,core,value); - StopVoices(core,((u32)value)<<16); - break; - case REG_S_KOFF: - RegLog(2,"KOFF0",rmem,core,value); - StopVoices(core,((u32)value)); - break; - case REG_S_ENDX: - //ConLog(" * SPU2: Core %d ENDX cleared!\n",core); - RegLog(2,"ENDX0",rmem,core,value); - Cores[core].Regs.ENDX&=0x00FF0000; break; - case (REG_S_ENDX + 2): - //ConLog(" * SPU2: Core %d ENDX cleared!\n",core); - RegLog(2,"ENDX1",rmem,core,value); - Cores[core].Regs.ENDX&=0xFFFF; break; - case REG_P_MVOLL: - RegLog(1,"MVOLL",rmem,core,value); - if (value & 0x8000) { // +Lin/-Lin/+Exp/-Exp - Cores[core].MasterL.Mode=(value & 0xE000)/0x2000; - Cores[core].MasterL.Increment=(value & 0x3F) | ((value & 0x800)/0x10); - } - else { - Cores[core].MasterL.Mode=0; - Cores[core].MasterL.Increment=0; - Cores[core].MasterL.Value=value; - } - Cores[core].MasterL.Reg_VOL=value; - break; - case REG_P_MVOLR: - RegLog(1,"MVOLR",rmem,core,value); - if (value & 0x8000) { // +Lin/-Lin/+Exp/-Exp - Cores[core].MasterR.Mode=(value & 0xE000)/0x2000; - Cores[core].MasterR.Increment=(value & 0x3F) | ((value & 0x800)/0x10); - } - else { - Cores[core].MasterR.Mode=0; - Cores[core].MasterR.Increment=0; - Cores[core].MasterR.Value=value; - } - Cores[core].MasterR.Reg_VOL=value; - break; - case REG_S_ADMAS: - RegLog(3,"ADMAS",rmem,core,value); - //ConLog(" * SPU2: Core %d AutoDMAControl set to %d (%d)\n",core,value, Cycles); - Cores[core].AutoDMACtrl=value; - - if(value==0) - { - Cores[core].AdmaInProgress=0; - } - break; - - default: - *(regtable[mem>>1])=value; - break; - } - - SPU2writeLog(mem,value); - if ((mem>=0x07C0) && (mem<0x07CE)) - { - UpdateSpdifMode(); - } -} - - -EXPORT_C_(void) SPU2write(u32 rmem, u16 value) -{ -#ifdef S2R_ENABLE - if(!replay_mode) - s2r_writereg(Cycles,rmem,value); -#endif - - if(rmem==0x1f9001ac) - { - //RegWriteLog(0,value); - if((Cores[0].IRQEnable)&&(Cores[0].TSA==Cores[0].IRQA)) - { - Spdif.Info=4; - SetIrqCall(); - } - spu2M_Write( Cores[0].TSA++, value ); - Cores[0].TSA&=0xfffff; - } - else if(rmem==0x1f9005ac) - { - //RegWriteLog(1,value); - if((Cores[0].IRQEnable)&&(Cores[0].TSA==Cores[0].IRQA)) - { - Spdif.Info=4; - SetIrqCall(); - } - spu2M_Write( Cores[1].TSA++, value ); - Cores[1].TSA&=0xfffff; - } - else - { - if(hasPtr) TimeUpdate(*cPtr); - - if (rmem>>16 == 0x1f80) - SPU_ps1_write(rmem,value); - else - SPU2_FastWrite( rmem, value ); - } -} - -EXPORT_C_(u16) SPU2read(u32 rmem) -{ -// if(!replay_mode) -// s2r_readreg(Cycles,rmem); - - if(hasPtr) TimeUpdate(*cPtr); - - u16 ret=0xDEAD; u32 core=0, mem=rmem&0xFFFF, omem=mem; - if (mem & 0x400) { omem^=0x400; core=1; } - - if(rmem==0x1f9001AC) - { - ret = DmaRead(core); - } - else if (rmem>>16 == 0x1f80) - { - ret = SPU_ps1_read(rmem); - } - else if ((mem&0xFFFF)>=0x800) - { - ret=spu2Ru16(mem); - ConLog(" * SPU2: Read from reg>=0x800: %x value %x\n",mem,ret); - FileLog(" * SPU2: Read from reg>=0x800: %x value %x\n",mem,ret); - } - else - { - ret = *(regtable[(mem>>1)]); - - FileLog("[%10d] SPU2 read mem %x (core %d, register %x): %x\n",Cycles, mem, core, (omem & 0x7ff), ret); - } - - return ret; -} - -typedef struct -{ - // compatibility with zerospu2 removed... - - u32 version; - u8 unkregs[0x10000]; - u8 mem[0x200000]; - - u32 id; - V_Core Cores[2]; - V_SPDIF Spdif; - s16 OutPos; - s16 InputPos; - u8 InpBuff; - u32 Cycles; - s32 uTicks; - double srate_pv; - double opitch; - int osps; - int PlayMode; - - int lClocks; - - PcmCacheEntry cacheData; - -} SPU2freezeData; - -// No more ZeroSPU compatibility... -//#define ZEROSPU_VERSION 0x70000001 - -#define SAVE_ID 0x73326701 - -// versioning for saves. -// Increment this if changes to V_Core or V_Voice structs are made. -// Chances are we'll never explicitly support older save versions, -// but might as well version them anyway. Could come in handly someday! -#define SAVE_VERSION 0x0101 - -static int getFreezeSize() -{ - if( disableFreezes ) return 8; // length of the string id "invalid" (plus a zero!) - - int size = sizeof(SPU2freezeData); - - // calculate the amount of memory consumed by our cache: - - for( int bidx=0; bidxdata; - - if( spud->id != SAVE_ID || spud->version < 0x100 ) - { - printf("\n*** SPU2Ghz Warning:\n"); - printf(" The savestate you are trying to load was not made with this plugin.\n"); - printf(" The emulator will not be stable! Find a memorycard savespot to save your\n"); - printf(" game, reset, and then continue from there.\n\n"); - - disableFreezes=true; - lClocks = 0; - resetClock = true; - - // Do *not* reset the cores. - // We'll need some "hints" as to how the cores should be initialized, - // and the only way to get that is to use the game's existing core settings - // and hope they kinda match the settings for the savestate (IRQ enables and such). - // - - //CoreReset( 0 ); - //CoreReset( 1 ); - - // adpcm cache : Clear all the cache flags and buffers. - - wipe_the_cache(); - } - else - { - disableFreezes=false; - - // base stuff - memcpy(spu2regs, spud->unkregs, 0x010000); - memcpy(_spu2mem, spud->mem, 0x200000); - - memcpy(Cores, spud->Cores, sizeof(Cores)); - memcpy(&Spdif, &spud->Spdif, sizeof(Spdif)); - OutPos = spud->OutPos; - InputPos = spud->InputPos; - InpBuff = spud->InpBuff; - Cycles = spud->Cycles; - uTicks = spud->uTicks; - srate_pv = spud->srate_pv; - opitch = spud->opitch; - osps = spud->osps; - PlayMode = spud->PlayMode; - lClocks = spud->lClocks; - - // Load the ADPCM cache: - - wipe_the_cache(); - if( spud->version == 0x100 ) // don't support 0x100 cache anymore. - { - printf("\n*** SPU2Ghz Warning:\n"); - printf("\tSavestate version is from an older version of this plugin.\n"); - printf("\tAudio may not recover correctly."); - - const PcmCacheEntry* pcmSrc = &spud->cacheData; - int blksLoaded=0; - - for( int bidx=0; bidx FreezeLoad > Loaded %d cache blocks.\n", blksLoaded++ ); - } - - } else if (mode == FREEZE_SAVE) - { - if (data->data == NULL) return -1; - - if( disableFreezes ) - { - // No point in making a save state since the SPU2 - // state is completely bogus anyway... Let's just - // give this some random ID that no one will recognize. - - strcpy( data->data, "invalid" ); - return 0; - } - - - SPU2freezeData *spud = (SPU2freezeData*)data->data; - - spud->id=SAVE_ID; - spud->version=SAVE_VERSION;//ZEROSPU_VERSION; //Zero compat working bad, better not save that - - memcpy(spud->unkregs, spu2regs, 0x010000); - memcpy(spud->mem, _spu2mem, 0x200000); - memcpy(spud->Cores, Cores, sizeof(Cores)); - memcpy(&spud->Spdif, &Spdif, sizeof(Spdif)); - spud->OutPos = OutPos; - spud->InputPos = InputPos; - spud->InpBuff = InpBuff; - spud->Cycles = Cycles; - spud->uTicks = uTicks; - spud->srate_pv = srate_pv; - spud->opitch = opitch; - spud->osps = osps; - spud->PlayMode = PlayMode; - spud->lClocks = lClocks; - - // Save our cache: - // We could just force the user to rebuild the cache when loading - // from stavestates, but for most games the cache is pretty - // small and compresses well. - // - // Potential Alternative: - // If the cache is not saved then it is necessary to save the - // decoded blocks currently in use by active voices. This allows - // voices to resume seamlessly on load. - - PcmCacheEntry* pcmDst = &spud->cacheData; - int blksSaved=0; - - for( int bidx=0; bidx FreezeSave > Saved %d cache blocks.\n", blksSaved++ ); - - } - else if (mode == FREEZE_SIZE) - { - data->size = getFreezeSize(); - } - return 0; - -} - -void VoiceStart(int core,int vc) -{ - if((Cycles-Cores[core].Voices[vc].PlayCycle)>=4) - { - if(Cores[core].Voices[vc].StartA&7) - { - fprintf( stderr, " *** Missaligned StartA %05x!\n",Cores[core].Voices[vc].StartA); - Cores[core].Voices[vc].StartA=(Cores[core].Voices[vc].StartA+0xFFFF8)+0x8; - } - - Cores[core].Voices[vc].ADSR.Releasing=0; - Cores[core].Voices[vc].ADSR.Value=1; - Cores[core].Voices[vc].ADSR.Phase=1; - Cores[core].Voices[vc].PlayCycle=Cycles; - Cores[core].Voices[vc].SCurrent=28; - Cores[core].Voices[vc].LoopMode=0; - Cores[core].Voices[vc].LoopFlags=0; - Cores[core].Voices[vc].LoopStartA=Cores[core].Voices[vc].StartA; - Cores[core].Voices[vc].NextA=Cores[core].Voices[vc].StartA; - Cores[core].Voices[vc].Prev1=0; - Cores[core].Voices[vc].Prev2=0; - - Cores[core].Voices[vc].PV1=Cores[core].Voices[vc].PV2=0; - Cores[core].Voices[vc].PV3=Cores[core].Voices[vc].PV4=0; - - Cores[core].Regs.ENDX&=~(1<>vc) & 1) { - VoiceStart(core,vc); - } - } - Cores[core].Regs.ENDX &= ~(value); - //Cores[core].Regs.ENDX = 0; -} - -void StopVoices(int core, u32 value) -{ - u32 vx=1,vc=0; - for (vc=0;vc<24;vc++) { - if ((value>>vc) & 1) { - Cores[core].Voices[vc].ADSR.Releasing=1; - //if(MsgKeyOnOff()) ConLog(" * SPU2: KeyOff: Core %d; Voice %d.\n",core,vc); - } - } -} - - -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -EXPORT_C_(int) SPU2setupRecording(int start, void* pData) -{ - // Don't record if we have a bogus state. - if( disableFreezes ) return 0; - - if(start==0) - { - //stop recording - RecordStop(); - if(recording==0) - return 1; - } - else if(start==1) - { - //start recording - RecordStart(); - if(recording!=0) - return 1; - } - return 0; -} +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#include "SPU2.h" +#include "resource.h" +#include + +#include "regtable.h" + +void StartVoices(int core, u32 value); +void StopVoices(int core, u32 value); + +void InitADSR(); + +DWORD CALLBACK TimeThread(PVOID /* unused param */); + +const char *ParamNames[8]={"VOLL","VOLR","PITCH","ADSR1","ADSR2","ENVX","VOLXL","VOLXR"}; +const char *AddressNames[6]={"SSAH","SSAL","LSAH","LSAL","NAXH","NAXL"}; + + +// [Air]: fixed the hacky part of UpdateTimer with this: +bool resetClock = true; + +// Used to make spu2 more robust at loading incompatible saves. +// Disables re-freezing of save state data. +bool disableFreezes=false; + +void (* _irqcallback)(); +void (* dma4callback)(); +void (* dma7callback)(); + +short *spu2regs; +short *_spu2mem; +s32 uTicks; + +u8 callirq; + +HANDLE hThreadFunc; +u32 ThreadFuncID; + +#ifndef PUBLIC +V_CoreDebug DebugCores[2]; +#endif +V_Core Cores[2]; +V_SPDIF Spdif; + +s16 OutPos; +s16 InputPos; +u8 InpBuff; +u32 Cycles; +u32 Num; + +u32* cPtr=NULL; +u32 lClocks=0; + +bool hasPtr=false; + +int PlayMode; + +s16 attrhack[2]={0,0}; + +HINSTANCE hInstance; + +bool debugDialogOpen=false; +HWND hDebugDialog=NULL; + +CRITICAL_SECTION threadSync; + +bool has_to_call_irq=false; + +void SetIrqCall() +{ + has_to_call_irq=true; +} + +void SysMessage(const char *fmt, ...) +{ + va_list list; + char tmp[512]; + + va_start(list,fmt); + sprintf_s(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "SPU2ghz Msg", 0); +} + +__forceinline s16 * __fastcall GetMemPtr(u32 addr) +{ +#ifndef _DEBUG_FAST + // In case you're wondering, this assert is the reason spu2ghz + // runs so incrediously slow in Debug mode. :P + assert(addr<0x100000); +#endif + return (_spu2mem+addr); +} + +__forceinline s16 __fastcall spu2M_Read( u32 addr ) +{ + return *GetMemPtr( addr & 0xfffff ); +} + +// writes a signed value to the SPU2 ram +// Invalidates the ADPCM cache in the process. +// Optimization note: don't use __forceinline because the footprint of this +// function is a little too heavy now. Better to let the compiler decide. +__inline void __fastcall spu2M_Write( u32 addr, s16 value ) +{ + // Make sure the cache is invalidated: + // (note to self : addr address WORDs, not bytes) + + addr &= 0xfffff; + if( addr >= SPU2_DYN_MEMLINE ) + { + const int cacheIdx = addr / pcm_WordsPerBlock; + pcm_cache_data[cacheIdx].Validated = false; + + ConLog( " * SPU2 : PcmCache Block Clear at 0x%x (cacheIdx=0x%x)\n", addr, cacheIdx); + } + *GetMemPtr( addr ) = value; +} + +// writes an unsigned value to the SPU2 ram +__inline void __fastcall spu2M_Write( u32 addr, u16 value ) +{ + spu2M_Write( addr, (s16)value ); +} + +__forceinline void RegLog(int level, char *RName,u32 mem,u32 core,u16 value) +{ + if( level > 1 ) + FileLog("[%10d] SPU2 write mem %08x (core %d, register %s) value %04x\n",Cycles,mem,core,RName,value); +} + +void AssignVolume(V_Volume& vol, s16 value) +{ + vol.Reg_VOL = value; + if (value & 0x8000) { // +Lin/-Lin/+Exp/-Exp + vol.Mode=(value & 0xF000)>>12; + vol.Increment=(value & 0x3F); + } + else { + vol.Mode=0; + vol.Increment=0; + + value<<=1; + vol.Value=value; + + } +} + +void CoreReset(int c) +{ +#define DEFAULT_VOICE_VOLUME 0x3FFF + int v=0; + + ConLog(" * SPU2: Initializing core %d structures... ",c); + + memset(Cores+c,0,sizeof(Cores[c])); + + Cores[c].Regs.STATX=0; + Cores[c].Regs.ATTR=0; + Cores[c].ExtL=0x3FFF; + Cores[c].ExtR=0x3FFF; + Cores[c].InpL=0x3FFF; + Cores[c].InpR=0x3FFF; + Cores[c].FxL=0x7FFF; + Cores[c].FxR=0x7FFF; + Cores[c].MasterL.Reg_VOL=0x3FFF; + Cores[c].MasterL.Value=0x7FFF; + Cores[c].MasterR.Reg_VOL=0x3FFF; + Cores[c].MasterR.Value=0x7FFF; + Cores[c].ExtWetR=1; + Cores[c].ExtWetL=1; + Cores[c].ExtDryR=1; + Cores[c].ExtDryL=1; + Cores[c].InpWetR=1; + Cores[c].InpWetL=1; + Cores[c].InpDryR=1; + Cores[c].InpDryL=1; + Cores[c].SndWetR=1; + Cores[c].SndWetL=1; + Cores[c].SndDryR=1; + Cores[c].SndDryL=1; + Cores[c].Regs.MMIX = 0xFFCF; + Cores[c].Regs.VMIXL = 0xFFFFFF; + Cores[c].Regs.VMIXR = 0xFFFFFF; + Cores[c].Regs.VMIXEL = 0xFFFFFF; + Cores[c].Regs.VMIXER = 0xFFFFFF; + Cores[c].EffectsStartA= 0xEFFF8 + 0x10000*c; + Cores[c].EffectsEndA = 0xEFFFF + 0x10000*c; + Cores[c].FxEnable=0; + Cores[c].IRQA=0xFFFF0; + Cores[c].IRQEnable=1; + + for (v=0;v<24;v++) { + AssignVolume(Cores[c].Voices[v].VolumeL,DEFAULT_VOICE_VOLUME); + AssignVolume(Cores[c].Voices[v].VolumeR,DEFAULT_VOICE_VOLUME); + Cores[c].Voices[v].ADSR.Value=0; + Cores[c].Voices[v].ADSR.Phase=0; + Cores[c].Voices[v].Pitch=0x3FFF; + Cores[c].Voices[v].DryL=1; + Cores[c].Voices[v].DryR=1; + Cores[c].Voices[v].WetL=1; + Cores[c].Voices[v].WetR=1; + Cores[c].Voices[v].NextA=2800; + Cores[c].Voices[v].StartA=2800; + Cores[c].Voices[v].LoopStartA=2800; + //Cores[c].Voices[v].lastSetStartA=2800; fixme: this is part of debug now + } + Cores[c].DMAICounter=0; + Cores[c].AdmaInProgress=0; + + Cores[c].Regs.STATX=0x80; + + ConLog("done.\n"); +} + +static BOOL CALLBACK DebugProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + int wmId,wmEvent; + + switch(uMsg) + { + case WM_PAINT: + return FALSE; + case WM_INITDIALOG: + { + debugDialogOpen=true; + } + break; + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case IDOK: + case IDCANCEL: + debugDialogOpen=false; + EndDialog(hWnd,0); + break; + default: + return FALSE; + } + break; + default: + return FALSE; + } + return TRUE; +} + +#ifndef PUBLIC + +int FillRectangle(HDC dc, int left, int top, int width, int height) +{ + RECT r = { left, top, left+width, top+height }; + + return FillRect(dc, &r, (HBRUSH)GetStockObject(DC_BRUSH)); +} + +BOOL DrawRectangle(HDC dc, int left, int top, int width, int height) +{ + RECT r = { left, top, left+width, top+height }; + + POINT p[5] = { + { r.left, r.top }, + { r.right, r.top }, + { r.right, r.bottom }, + { r.left, r.bottom }, + { r.left, r.top }, + }; + + return Polyline(dc, p, 5); +} + + +HFONT hf = NULL; +int lCount=0; +void UpdateDebugDialog() +{ + if(!debugDialogOpen) return; + + lCount++; + if(lCount>=(SampleRate/10)) + { + HDC hdc = GetDC(hDebugDialog); + + if(!hf) + { + hf = CreateFont( 8, 0, 0, 0, 0, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Lucida Console"); + } + + SelectObject(hdc,hf); + SelectObject(hdc,GetStockObject(DC_BRUSH)); + SelectObject(hdc,GetStockObject(DC_PEN)); + + for(int c=0;c<2;c++) + { + for(int v=0;v<24;v++) + { + int IX = 8+256*c; + int IY = 8+ 32*v; + V_Voice& vc(Cores[c].Voices[v]); + V_VoiceDebug& vcd( DebugCores[c].Voices[v] ); + + SetDCBrushColor(hdc,RGB( 0, 0, 0)); + if((vc.ADSR.Phase>0)&&(vc.ADSR.Phase<6)) + { + SetDCBrushColor(hdc,RGB( 0, 0,128)); + } + else + { + if(vcd.lastStopReason==1) + { + SetDCBrushColor(hdc,RGB(128, 0, 0)); + } + if(vcd.lastStopReason==2) + { + SetDCBrushColor(hdc,RGB( 0,128, 0)); + } + } + + FillRectangle(hdc,IX,IY,252,30); + + SetDCPenColor(hdc,RGB( 255, 128, 32)); + + DrawRectangle(hdc,IX,IY,252,30); + + SetDCBrushColor (hdc,RGB( 0,255, 0)); + + int vl = abs(vc.VolumeL.Value * 24 / 32768); + int vr = abs(vc.VolumeR.Value * 24 / 32768); + + FillRectangle(hdc,IX+38,IY+26 - vl, 4, vl); + FillRectangle(hdc,IX+42,IY+26 - vr, 4, vr); + + int adsr = (vc.ADSR.Value>>16) * 24 / 32768; + + FillRectangle(hdc,IX+48,IY+26 - adsr, 4, adsr); + + int peak = vcd.displayPeak * 24 / 32768; + + FillRectangle(hdc,IX+56,IY+26 - peak, 4, peak); + + SetTextColor(hdc,RGB( 0,255, 0)); + SetBkColor (hdc,RGB( 0, 0, 0)); + + static char t[1024]; + + sprintf(t,"%06x",vc.StartA); + TextOut(hdc,IX+4,IY+3,t,6); + + sprintf(t,"%06x",vc.NextA); + TextOut(hdc,IX+4,IY+12,t,6); + + sprintf(t,"%06x",vc.LoopStartA); + TextOut(hdc,IX+4,IY+21,t,6); + + vcd.displayPeak = 0; + + if(vcd.lastSetStartA != vc.StartA) + { + printf(" *** Warning! Core %d Voice %d: StartA should be %06x, and is %06x.\n", + c,v,vcd.lastSetStartA,vc.StartA); + vcd.lastSetStartA = vc.StartA; + } + } + } + ReleaseDC(hDebugDialog,hdc); + lCount=0; + } + + MSG msg; + while(PeekMessage(&msg,hDebugDialog,0,0,PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} +#endif + +#define TickInterval 768 +#define SanityInterval 4800 + +u32 TicksCore=0; +u32 TicksThread=0; + +void __fastcall TimeUpdate(u32 cClocks) +{ + u32 dClocks = cClocks-lClocks; + + // [Air]: Sanity Check + // If for some reason our clock value seems way off base, just mix + // out a little bit, skip the rest, and hope the ship "rights" itself later on. + + if( dClocks > TickInterval*SanityInterval ) + { + ConLog( " * SPU2 > TimeUpdate Sanity Check (Tick Delta: %d) (PS2 Ticks: %d)\n", dClocks/TickInterval, cClocks/TickInterval ); + dClocks = TickInterval*SanityInterval; + lClocks = cClocks-dClocks; + } + + //UpdateDebugDialog(); + + //Update Mixing Progress + while(dClocks>=TickInterval) + { + if(has_to_call_irq) + { + ConLog(" * SPU2: Irq Called (%04x).\n",Spdif.Info); + has_to_call_irq=false; + if(_irqcallback) _irqcallback(); + } + + if(Cores[0].InitDelay>0) + { + Cores[0].InitDelay--; + if(Cores[0].InitDelay==0) + { + CoreReset(0); + } + } + + if(Cores[1].InitDelay>0) + { + Cores[1].InitDelay--; + if(Cores[1].InitDelay==0) + { + CoreReset(1); + } + } + + //Update DMA4 interrupt delay counter + if(Cores[0].DMAICounter>0) + { + Cores[0].DMAICounter-=TickInterval; + if(Cores[0].DMAICounter<=0) + { + Cores[0].MADR=Cores[0].TADR; + Cores[0].DMAICounter=0; + if(dma4callback) dma4callback(); + } + else { + Cores[0].MADR+=TickInterval<<1; + } + } + + //Update DMA7 interrupt delay counter + if(Cores[1].DMAICounter>0) + { + Cores[1].DMAICounter-=TickInterval; + if(Cores[1].DMAICounter<=0) + { + Cores[1].MADR=Cores[1].TADR; + Cores[1].DMAICounter=0; + //ConLog( "* SPU2 > DMA 7 Callback! %d\n", Cycles ); + if(dma7callback) dma7callback(); + } + else { + Cores[1].MADR+=TickInterval<<1; + } + } + + dClocks-=TickInterval; + lClocks+=TickInterval; + Cycles++; + + Mix(); + } +} + +static u16 mask = 0xFFFF; + +void UpdateSpdifMode() +{ + int OPM=PlayMode; + u16 last = 0; + + if(mask&Spdif.Out) + { + last = mask & Spdif.Out; + mask=mask&(~Spdif.Out); + } + + if(Spdif.Out&0x4) // use 24/32bit PCM data streaming + { + PlayMode=8; + ConLog(" * SPU2: WARNING: Possibly CDDA mode set!\n"); + return; + } + + if(Spdif.Out&SPDIF_OUT_BYPASS) + { + PlayMode=2; + if(Spdif.Mode&SPDIF_MODE_BYPASS_BITSTREAM) + PlayMode=4; //bitstream bypass + } + else + { + PlayMode=0; //normal processing + if(Spdif.Out&SPDIF_OUT_PCM) + { + PlayMode=1; + } + } + if(OPM!=PlayMode) + { + ConLog(" * SPU2: Play Mode Set to %s (%d).\n",(PlayMode==0)?"Normal":((PlayMode==1)?"PCM Clone":((PlayMode==2)?"PCM Bypass":"BitStream Bypass")),PlayMode); + } +} + +void SPU_ps1_write(u32 mem, u16 value) +{ + bool show=true; + + u32 reg = mem&0xffff; + + if((reg>=0x1c00)&&(reg<0x1d80)) + { + //voice values + u8 voice = ((reg-0x1c00)>>4); + u8 vval = reg&0xf; + switch(vval) + { + case 0: //VOLL (Volume L) + Cores[0].Voices[voice].VolumeL.Mode=0; + Cores[0].Voices[voice].VolumeL.Value=value<<1; + Cores[0].Voices[voice].VolumeL.Reg_VOL = value; break; + case 1: //VOLR (Volume R) + Cores[0].Voices[voice].VolumeR.Mode=0; + Cores[0].Voices[voice].VolumeR.Value=value<<1; + Cores[0].Voices[voice].VolumeR.Reg_VOL = value; break; + case 2: Cores[0].Voices[voice].Pitch=value; break; + case 3: Cores[0].Voices[voice].StartA=(u32)value<<8; break; + case 4: // ADSR1 (Envelope) + Cores[0].Voices[voice].ADSR.Am=(value & 0x8000)>>15; + Cores[0].Voices[voice].ADSR.Ar=(value & 0x7F00)>>8; + Cores[0].Voices[voice].ADSR.Dr=(value & 0xF0)>>4; + Cores[0].Voices[voice].ADSR.Sl=(value & 0xF); + Cores[0].Voices[voice].ADSR.Reg_ADSR1 = value; break; + case 5: // ADSR2 (Envelope) + Cores[0].Voices[voice].ADSR.Sm=(value & 0xE000)>>13; + Cores[0].Voices[voice].ADSR.Sr=(value & 0x1FC0)>>6; + Cores[0].Voices[voice].ADSR.Rm=(value & 0x20)>>5; + Cores[0].Voices[voice].ADSR.Rr=(value & 0x1F); + Cores[0].Voices[voice].ADSR.Reg_ADSR2 = value; break; + case 6: + // [Air] Experimental --> shifting value into a 31 bit range. + // shifting by 16 might be more correct? + Cores[0].Voices[voice].ADSR.Value = value<<15; + ConLog( "* SPU2: Mysterious ADSR Volume Set to 0x%x", value ); + break; + case 7: Cores[0].Voices[voice].LoopStartA=(u32)value <<8; break; + + jNO_DEFAULT; + } + } + else switch(reg) + { + case 0x1d80:// Mainvolume left + Cores[0].MasterL.Mode=0; + Cores[0].MasterL.Value=value; + break; + case 0x1d82:// Mainvolume right + Cores[0].MasterL.Mode=0; + Cores[0].MasterR.Value=value; + break; + case 0x1d84:// Reverberation depth left + Cores[0].FxL=value; + break; + case 0x1d86:// Reverberation depth right + Cores[0].FxR=value; + break; + + case 0x1d88:// Voice ON (0-15) + SPU2_FastWrite(REG_S_KON,value); + break; + case 0x1d8a:// Voice ON (16-23) + SPU2_FastWrite(REG_S_KON+2,value); + break; + + case 0x1d8c:// Voice OFF (0-15) + SPU2_FastWrite(REG_S_KOFF,value); + break; + case 0x1d8e:// Voice OFF (16-23) + SPU2_FastWrite(REG_S_KOFF+2,value); + break; + + case 0x1d90:// Channel FM (pitch lfo) mode (0-15) + SPU2_FastWrite(REG_S_PMON,value); + break; + case 0x1d92:// Channel FM (pitch lfo) mode (16-23) + SPU2_FastWrite(REG_S_PMON+2,value); + break; + + + case 0x1d94:// Channel Noise mode (0-15) + SPU2_FastWrite(REG_S_NON,value); + break; + case 0x1d96:// Channel Noise mode (16-23) + SPU2_FastWrite(REG_S_NON+2,value); + break; + + case 0x1d98:// Channel Reverb mode (0-15) + SPU2_FastWrite(REG_S_VMIXEL,value); + SPU2_FastWrite(REG_S_VMIXER,value); + break; + case 0x1d9a:// Channel Reverb mode (16-23) + SPU2_FastWrite(REG_S_VMIXEL+2,value); + SPU2_FastWrite(REG_S_VMIXER+2,value); + break; + case 0x1d9c:// Channel Reverb mode (0-15) + SPU2_FastWrite(REG_S_VMIXL,value); + SPU2_FastWrite(REG_S_VMIXR,value); + break; + case 0x1d9e:// Channel Reverb mode (16-23) + SPU2_FastWrite(REG_S_VMIXL+2,value); + SPU2_FastWrite(REG_S_VMIXR+2,value); + break; + + case 0x1da2:// Reverb work area start + { + u32 val=(u32)value <<8; + + SPU2_FastWrite(REG_A_ESA, val&0xFFFF); + SPU2_FastWrite(REG_A_ESA+2,val>>16); + } + break; + case 0x1da4: + Cores[0].IRQA=(u32)value<<8; + break; + case 0x1da6: + Cores[0].TSA=(u32)value<<8; + break; + + case 0x1daa: + SPU2_FastWrite(REG_C_ATTR,value); + break; + case 0x1dae: + SPU2_FastWrite(REG_P_STATX,value); + break; + case 0x1da8:// Spu Write to Memory + DmaWrite(0,value); + show=false; + break; + } + + if(show) FileLog("[%10d] (!) SPU write mem %08x value %04x\n",Cycles,mem,value); + + spu2Ru16(mem)=value; +} + +u16 SPU_ps1_read(u32 mem) +{ + bool show=true; + u16 value = spu2Ru16(mem); + + u32 reg = mem&0xffff; + + if((reg>=0x1c00)&&(reg<0x1d80)) + { + //voice values + u8 voice = ((reg-0x1c00)>>4); + u8 vval = reg&0xf; + switch(vval) + { + case 0: //VOLL (Volume L) + value=Cores[0].Voices[voice].VolumeL.Mode; + value=Cores[0].Voices[voice].VolumeL.Value; + value=Cores[0].Voices[voice].VolumeL.Reg_VOL; break; + case 1: //VOLR (Volume R) + value=Cores[0].Voices[voice].VolumeR.Mode; + value=Cores[0].Voices[voice].VolumeR.Value; + value=Cores[0].Voices[voice].VolumeR.Reg_VOL; break; + case 2: value=Cores[0].Voices[voice].Pitch; break; + case 3: value=Cores[0].Voices[voice].StartA; break; + case 4: value=Cores[0].Voices[voice].ADSR.Reg_ADSR1; break; + case 5: value=Cores[0].Voices[voice].ADSR.Reg_ADSR2; break; + case 6: value=Cores[0].Voices[voice].ADSR.Value >> 16; break; + case 7: value=Cores[0].Voices[voice].LoopStartA; break; + + jNO_DEFAULT; + } + } + else switch(reg) + { + case 0x1d80: value = Cores[0].MasterL.Value; break; + case 0x1d82: value = Cores[0].MasterR.Value; break; + case 0x1d84: value = Cores[0].FxL; break; + case 0x1d86: value = Cores[0].FxR; break; + + case 0x1d88: value = 0; break; + case 0x1d8a: value = 0; break; + case 0x1d8c: value = 0; break; + case 0x1d8e: value = 0; break; + + case 0x1d90: value = Cores[0].Regs.PMON&0xFFFF; break; + case 0x1d92: value = Cores[0].Regs.PMON>>16; break; + + case 0x1d94: value = Cores[0].Regs.NON&0xFFFF; break; + case 0x1d96: value = Cores[0].Regs.NON>>16; break; + + case 0x1d98: value = Cores[0].Regs.VMIXEL&0xFFFF; break; + case 0x1d9a: value = Cores[0].Regs.VMIXEL>>16; break; + case 0x1d9c: value = Cores[0].Regs.VMIXL&0xFFFF; break; + case 0x1d9e: value = Cores[0].Regs.VMIXL>>16; break; + + case 0x1da2: value = Cores[0].EffectsStartA>>3; break; + case 0x1da4: value = Cores[0].IRQA>>3; break; + case 0x1da6: value = Cores[0].TSA>>3; break; + + case 0x1daa: + value = SPU2read(REG_C_ATTR); + break; + case 0x1dae: + value = 0; //SPU2read(REG_P_STATX)<<3; + break; + case 0x1da8: + value = DmaRead(0); + show=false; + break; + } + + if(show) FileLog("[%10d] (!) SPU read mem %08x value %04x\n",Cycles,mem,value); + return value; +} + +void RegWriteLog(u32 core,u16 value); + +void SPU2writeLog(u32 rmem, u16 value) +{ +#ifndef PUBLIC + u32 vx=0, vc=0, core=0, omem=rmem, mem=rmem&0x7FF; + omem=mem=mem&0x7FF; //FFFF; + if (mem & 0x400) { omem^=0x400; core=1; } + + /* + if ((omem >= 0x0000) && (omem < 0x0180)) { // Voice Params + u32 voice=(omem & 0x1F0) >> 4; + u32 param=(omem & 0xF)>>1; + FileLog("[%10d] SPU2 write mem %08x (Core %d Voice %d Param %s) value %x\n",Cycles,rmem,core,voice,ParamNames[param],value); + } + else if ((omem >= 0x01C0) && (omem < 0x02DE)) { + u32 voice =((omem-0x01C0) / 12); + u32 address =((omem-0x01C0) % 12)>>1; + FileLog("[%10d] SPU2 write mem %08x (Core %d Voice %d Address %s) value %x\n",Cycles,rmem,core,voice,AddressNames[address],value); + } + */ + if ((mem >= 0x0760) && (mem < 0x07b0)) { + omem=mem; core=0; + if (mem >= 0x0788) {omem-=0x28; core=1;} + switch(omem) { + case REG_P_EVOLL: RegLog(2,"EVOLL",rmem,core,value); break; + case REG_P_EVOLR: RegLog(2,"EVOLR",rmem,core,value); break; + case REG_P_AVOLL: if (core) { RegLog(2,"AVOLL",rmem,core,value); } break; + case REG_P_AVOLR: if (core) { RegLog(2,"AVOLR",rmem,core,value); } break; + case REG_P_BVOLL: RegLog(2,"BVOLL",rmem,core,value); break; + case REG_P_BVOLR: RegLog(2,"BVOLR",rmem,core,value); break; + case REG_P_MVOLXL: RegLog(2,"MVOLXL",rmem,core,value); break; + case REG_P_MVOLXR: RegLog(2,"MVOLXR",rmem,core,value); break; + case R_IIR_ALPHA: RegLog(2,"IIR_ALPHA",rmem,core,value); break; + case R_ACC_COEF_A: RegLog(2,"ACC_COEF_A",rmem,core,value); break; + case R_ACC_COEF_B: RegLog(2,"ACC_COEF_B",rmem,core,value); break; + case R_ACC_COEF_C: RegLog(2,"ACC_COEF_C",rmem,core,value); break; + case R_ACC_COEF_D: RegLog(2,"ACC_COEF_D",rmem,core,value); break; + case R_IIR_COEF: RegLog(2,"IIR_COEF",rmem,core,value); break; + case R_FB_ALPHA: RegLog(2,"FB_ALPHA",rmem,core,value); break; + case R_FB_X: RegLog(2,"FB_X",rmem,core,value); break; + case R_IN_COEF_L: RegLog(2,"IN_COEF_L",rmem,core,value); break; + case R_IN_COEF_R: RegLog(2,"IN_COEF_R",rmem,core,value); break; + + } + } + else if ((mem>=0x07C0) && (mem<0x07CE)) { + switch(mem) { + case SPDIF_OUT: + RegLog(2,"SPDIF_OUT",rmem,-1,value); + break; + case IRQINFO: + RegLog(2,"IRQINFO",rmem,-1,value); + break; + case 0x7c4: + if(Spdif.Unknown1 != value) ConLog(" * SPU2: SPDIF Unknown Register 1 set to %04x\n",value); + RegLog(2,"SPDIF_UNKNOWN1",rmem,-1,value); + break; + case SPDIF_MODE: + if(Spdif.Mode != value) ConLog(" * SPU2: SPDIF Mode set to %04x\n",value); + RegLog(2,"SPDIF_MODE",rmem,-1,value); + break; + case SPDIF_MEDIA: + if(Spdif.Media != value) ConLog(" * SPU2: SPDIF Media set to %04x\n",value); + RegLog(2,"SPDIF_MEDIA",rmem,-1,value); + break; + case 0x7ca: + if(Spdif.Unknown2 != value) ConLog(" * SPU2: SPDIF Unknown Register 2 set to %04x\n",value); + RegLog(2,"SPDIF_UNKNOWN2",rmem,-1,value); + break; + case SPDIF_COPY: + if(Spdif.Protection != value) ConLog(" * SPU2: SPDIF Copy set to %04x\n",value); + RegLog(2,"SPDIF_COPY",rmem,-1,value); + break; + } + UpdateSpdifMode(); + } + else + switch(omem) { + case REG_C_ATTR: + RegLog(4,"ATTR",rmem,core,value); + break; + case REG_S_PMON: + RegLog(1,"PMON0",rmem,core,value); + break; + case (REG_S_PMON + 2): + RegLog(1,"PMON1",rmem,core,value); + break; + case REG_S_NON: + RegLog(1,"NON0",rmem,core,value); + break; + case (REG_S_NON + 2): + RegLog(1,"NON1",rmem,core,value); + break; + case REG_S_VMIXL: + RegLog(1,"VMIXL0",rmem,core,value); + case (REG_S_VMIXL + 2): + RegLog(1,"VMIXL1",rmem,core,value); + break; + case REG_S_VMIXEL: + RegLog(1,"VMIXEL0",rmem,core,value); + break; + case (REG_S_VMIXEL + 2): + RegLog(1,"VMIXEL1",rmem,core,value); + break; + case REG_S_VMIXR: + RegLog(1,"VMIXR0",rmem,core,value); + break; + case (REG_S_VMIXR + 2): + RegLog(1,"VMIXR1",rmem,core,value); + break; + case REG_S_VMIXER: + RegLog(1,"VMIXER0",rmem,core,value); + break; + case (REG_S_VMIXER + 2): + RegLog(1,"VMIXER1",rmem,core,value); + break; + case REG_P_MMIX: + RegLog(1,"MMIX",rmem,core,value); + break; + case REG_A_IRQA: + RegLog(2,"IRQAH",rmem,core,value); + break; + case (REG_A_IRQA + 2): + RegLog(2,"IRQAL",rmem,core,value); + break; + case (REG_S_KON + 2): + RegLog(2,"KON1",rmem,core,value); + break; + case REG_S_KON: + RegLog(2,"KON0",rmem,core,value); + break; + case (REG_S_KOFF + 2): + RegLog(2,"KOFF1",rmem,core,value); + break; + case REG_S_KOFF: + RegLog(2,"KOFF0",rmem,core,value); + break; + case REG_A_TSA: + RegLog(2,"TSAH",rmem,core,value); + break; + case (REG_A_TSA + 2): + RegLog(2,"TSAL",rmem,core,value); + break; + case REG_S_ENDX: + //ConLog(" * SPU2: Core %d ENDX cleared!\n",core); + RegLog(2,"ENDX0",rmem,core,value); + break; + case (REG_S_ENDX + 2): + //ConLog(" * SPU2: Core %d ENDX cleared!\n",core); + RegLog(2,"ENDX1",rmem,core,value); + break; + case REG_P_MVOLL: + RegLog(1,"MVOLL",rmem,core,value); + break; + case REG_P_MVOLR: + RegLog(1,"MVOLR",rmem,core,value); + break; + case REG_S_ADMAS: + RegLog(3,"ADMAS",rmem,core,value); + ConLog(" * SPU2: Core %d AutoDMAControl set to %d\n",core,value); + break; + case REG_P_STATX: + RegLog(3,"STATX",rmem,core,value); + break; + case REG_A_ESA: + RegLog(1,"ESAH",rmem,core,value); + break; + case (REG_A_ESA + 2): + RegLog(1,"ESAL",rmem,core,value); + break; + case REG_A_EEA: + RegLog(1,"EEAH",rmem,core,value); + break; + +#define LOG_REVB_REG(n,t) \ + case R_##n: \ + RegLog(2,t "H",mem,core,value); \ + break; \ + case (R_##n + 2): \ + RegLog(2,t "L",mem,core,value); \ + break; + + LOG_REVB_REG(FB_SRC_A,"FB_SRC_A") + LOG_REVB_REG(FB_SRC_B,"FB_SRC_B") + LOG_REVB_REG(IIR_SRC_A0,"IIR_SRC_A0") + LOG_REVB_REG(IIR_SRC_A1,"IIR_SRC_A1") + LOG_REVB_REG(IIR_SRC_B1,"IIR_SRC_B1") + LOG_REVB_REG(IIR_SRC_B0,"IIR_SRC_B0") + LOG_REVB_REG(IIR_DEST_A0,"IIR_DEST_A0") + LOG_REVB_REG(IIR_DEST_A1,"IIR_DEST_A1") + LOG_REVB_REG(IIR_DEST_B0,"IIR_DEST_B0") + LOG_REVB_REG(IIR_DEST_B1,"IIR_DEST_B1") + LOG_REVB_REG(ACC_SRC_A0,"ACC_SRC_A0") + LOG_REVB_REG(ACC_SRC_A1,"ACC_SRC_A1") + LOG_REVB_REG(ACC_SRC_B0,"ACC_SRC_B0") + LOG_REVB_REG(ACC_SRC_B1,"ACC_SRC_B1") + LOG_REVB_REG(ACC_SRC_C0,"ACC_SRC_C0") + LOG_REVB_REG(ACC_SRC_C1,"ACC_SRC_C1") + LOG_REVB_REG(ACC_SRC_D0,"ACC_SRC_D0") + LOG_REVB_REG(ACC_SRC_D1,"ACC_SRC_D1") + LOG_REVB_REG(MIX_DEST_A0,"MIX_DEST_A0") + LOG_REVB_REG(MIX_DEST_A1,"MIX_DEST_A1") + LOG_REVB_REG(MIX_DEST_B0,"MIX_DEST_B0") + LOG_REVB_REG(MIX_DEST_B1,"MIX_DEST_B1") + + default: RegLog(2,"UNKNOWN",rmem,core,value); spu2Ru16(mem) = value; + } +#endif +} + +__forceinline void SPU2_FastWrite( u32 rmem, u16 value ) +{ + u32 vx=0, vc=0, core=0, omem, mem; + omem=mem=rmem & 0x7FF; //FFFF; + if (mem & 0x400) { omem^=0x400; core=1; } + + //else if ((omem >= 0x0000) && (omem < 0x0180)) { // Voice Params + if (omem < 0x0180) { // Voice Params + u32 voice=(omem & 0x1F0) >> 4; + u32 param=(omem & 0xF)>>1; + //FileLog("[%10d] SPU2 write mem %08x (Core %d Voice %d Param %s) value %x\n",Cycles,rmem,core,voice,ParamNames[param],value); + switch (param) { + case 0: //VOLL (Volume L) + if (value & 0x8000) { // +Lin/-Lin/+Exp/-Exp + Cores[core].Voices[voice].VolumeL.Mode=(value & 0xF000)>>12; + Cores[core].Voices[voice].VolumeL.Increment=(value & 0x3F); + } + else { + Cores[core].Voices[voice].VolumeL.Mode=0; + Cores[core].Voices[voice].VolumeL.Increment=0; + if(value&0x4000) + value=0x3fff - (value&0x3fff); + Cores[core].Voices[voice].VolumeL.Value=value<<1; + } + Cores[core].Voices[voice].VolumeL.Reg_VOL = value; break; + case 1: //VOLR (Volume R) + if (value & 0x8000) { + Cores[core].Voices[voice].VolumeR.Mode=(value & 0xF000)>>12; + Cores[core].Voices[voice].VolumeR.Increment=(value & 0x3F); + } + else { + Cores[core].Voices[voice].VolumeR.Mode=0; + Cores[core].Voices[voice].VolumeR.Increment=0; + Cores[core].Voices[voice].VolumeR.Value=value<<1; + } + Cores[core].Voices[voice].VolumeR.Reg_VOL = value; break; + case 2: Cores[core].Voices[voice].Pitch=value; break; + case 3: // ADSR1 (Envelope) + Cores[core].Voices[voice].ADSR.Am=(value & 0x8000)>>15; + Cores[core].Voices[voice].ADSR.Ar=(value & 0x7F00)>>8; + Cores[core].Voices[voice].ADSR.Dr=(value & 0xF0)>>4; + Cores[core].Voices[voice].ADSR.Sl=(value & 0xF); + Cores[core].Voices[voice].ADSR.Reg_ADSR1 = value; break; + case 4: // ADSR2 (Envelope) + Cores[core].Voices[voice].ADSR.Sm=(value & 0xE000)>>13; + Cores[core].Voices[voice].ADSR.Sr=(value & 0x1FC0)>>6; + Cores[core].Voices[voice].ADSR.Rm=(value & 0x20)>>5; + Cores[core].Voices[voice].ADSR.Rr=(value & 0x1F); + Cores[core].Voices[voice].ADSR.Reg_ADSR2 = value; break; + case 5: + // [Air] : Mysterious volume set code. Too bad none of my games ever use it. + // (as usual... ) + Cores[core].Voices[voice].ADSR.Value = value << 15; + ConLog( "* SPU2: Mysterious ADSR Volume Set to 0x%x", value ); + break; + case 6: Cores[core].Voices[voice].VolumeL.Value=value; break; + case 7: Cores[core].Voices[voice].VolumeR.Value=value; break; + + jNO_DEFAULT; + } + } + else if ((omem >= 0x01C0) && (omem < 0x02DE)) { + u32 voice =((omem-0x01C0) / 12); + u32 address =((omem-0x01C0) % 12)>>1; + //FileLog("[%10d] SPU2 write mem %08x (Core %d Voice %d Address %s) value %x\n",Cycles,rmem,core,voice,AddressNames[address],value); + + switch (address) { + case 0: Cores[core].Voices[voice].StartA=((value & 0x0F) << 16) | (Cores[core].Voices[voice].StartA & 0xFFF8); + #ifndef PUBLIC + DebugCores[core].Voices[voice].lastSetStartA = Cores[core].Voices[voice].StartA; + #endif + break; + case 1: Cores[core].Voices[voice].StartA=(Cores[core].Voices[voice].StartA & 0x0F0000) | (value & 0xFFF8); + #ifndef PUBLIC + DebugCores[core].Voices[voice].lastSetStartA = Cores[core].Voices[voice].StartA; + #endif + //if(core==1) printf(" *** StartA for C%dV%02d set to 0x%05x\n",core,voice,Cores[core].Voices[voice].StartA); + break; + case 2: Cores[core].Voices[voice].LoopStartA=((value & 0x0F) << 16) | (Cores[core].Voices[voice].LoopStartA & 0xFFF8); + Cores[core].Voices[voice].LoopMode=3; break; + case 3: Cores[core].Voices[voice].LoopStartA=(Cores[core].Voices[voice].LoopStartA & 0x0F0000) | (value & 0xFFF8);break; + Cores[core].Voices[voice].LoopMode=3; break; + case 4: Cores[core].Voices[voice].NextA=((value & 0x0F) << 16) | (Cores[core].Voices[voice].NextA & 0xFFF8); + //printf(" *** Warning: C%dV%02d NextA MODIFIED EXTERNALLY!\n",core,voice); + break; + case 5: Cores[core].Voices[voice].NextA=(Cores[core].Voices[voice].NextA & 0x0F0000) | (value & 0xFFF8); + //printf(" *** Warning: C%dV%02d NextA MODIFIED EXTERNALLY!\n",core,voice); + break; + } + } + else + switch(omem) { + case REG_C_ATTR: + RegLog(4,"ATTR",rmem,core,value); + { + int irqe=Cores[core].IRQEnable; + int bit0=Cores[core].AttrBit0; + int bit4=Cores[core].AttrBit4; + + if(((value>>15)&1)&&(!Cores[core].CoreEnabled)&&(Cores[core].InitDelay==0)) // on init/reset + { + if(hasPtr) + { + Cores[core].InitDelay=1; + Cores[core].Regs.STATX=0; + } + else + { + CoreReset(core); + } + } + + Cores[core].AttrBit0 =(value>> 0) & 0x01; //1 bit + Cores[core].DMABits =(value>> 1) & 0x07; //3 bits + Cores[core].AttrBit4 =(value>> 4) & 0x01; //1 bit + Cores[core].AttrBit5 =(value>> 5) & 0x01; //1 bit + Cores[core].IRQEnable =(value>> 6) & 0x01; //1 bit + Cores[core].FxEnable =(value>> 7) & 0x01; //1 bit + Cores[core].NoiseClk =(value>> 8) & 0x3f; //6 bits + //Cores[core].Mute =(value>>14) & 0x01; //1 bit + Cores[core].Mute=0; + Cores[core].CoreEnabled=(value>>15) & 0x01; //1 bit + Cores[core].Regs.ATTR =value&0x7fff; + + if(value&0x000E) + { + ConLog(" * SPU2: Core %d ATTR unknown bits SET! value=%04x\n",core,value); + } + + if(Cores[core].AttrBit0!=bit0) + { + ConLog(" * SPU2: ATTR bit 0 set to %d\n",Cores[core].AttrBit0); + } + if(Cores[core].IRQEnable!=irqe) + { + ConLog(" * SPU2: IRQ %s\n",((Cores[core].IRQEnable==0)?"disabled":"enabled")); + if(!Cores[core].IRQEnable) + Spdif.Info=0; + } + + } + break; + case REG_S_PMON: + RegLog(1,"PMON0",rmem,core,value); + vx=2; for (vc=1;vc<16;vc++) { Cores[core].Voices[vc].Modulated=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.PMON = (Cores[core].Regs.PMON & 0xFFFF0000) | value; + break; + case (REG_S_PMON + 2): + RegLog(1,"PMON1",rmem,core,value); + vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].Modulated=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.PMON = (Cores[core].Regs.PMON & 0xFFFF) | (value << 16); + break; + case REG_S_NON: + RegLog(1,"NON0",rmem,core,value); + vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].Noise=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.NON = (Cores[core].Regs.NON & 0xFFFF0000) | value; + break; + case (REG_S_NON + 2): + RegLog(1,"NON1",rmem,core,value); + vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].Noise=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.NON = (Cores[core].Regs.NON & 0xFFFF) | (value << 16); + break; + case REG_S_VMIXL: + RegLog(1,"VMIXL0",rmem,core,value); + vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].DryL=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXL = (Cores[core].Regs.VMIXL & 0xFFFF0000) | value; + case (REG_S_VMIXL + 2): + RegLog(1,"VMIXL1",rmem,core,value); + vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].DryL=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXL = (Cores[core].Regs.VMIXL & 0xFFFF) | (value << 16); + case REG_S_VMIXEL: + RegLog(1,"VMIXEL0",rmem,core,value); + vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].WetL=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXEL = (Cores[core].Regs.VMIXEL & 0xFFFF0000) | value; + break; + case (REG_S_VMIXEL + 2): + RegLog(1,"VMIXEL1",rmem,core,value); + vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].WetL=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXEL = (Cores[core].Regs.VMIXEL & 0xFFFF) | (value << 16); + break; + case REG_S_VMIXR: + RegLog(1,"VMIXR0",rmem,core,value); + vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].DryR=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXR = (Cores[core].Regs.VMIXR & 0xFFFF0000) | value; + break; + case (REG_S_VMIXR + 2): + RegLog(1,"VMIXR1",rmem,core,value); + vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].DryR=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXR = (Cores[core].Regs.VMIXR & 0xFFFF) | (value << 16); + break; + case REG_S_VMIXER: + RegLog(1,"VMIXER0",rmem,core,value); + vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].WetR=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXER = (Cores[core].Regs.VMIXER & 0xFFFF0000) | value; + break; + case (REG_S_VMIXER + 2): + RegLog(1,"VMIXER1",rmem,core,value); + vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].WetR=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXER = (Cores[core].Regs.VMIXER & 0xFFFF) | (value << 16); + break; + case REG_P_MMIX: + RegLog(1,"MMIX",rmem,core,value); + vx=value; + if (core == 0) vx&=0xFF0; + Cores[core].ExtWetR=(vx & 0x001); + Cores[core].ExtWetL=(vx & 0x002)>>1; + Cores[core].ExtDryR=(vx & 0x004)>>2; + Cores[core].ExtDryL=(vx & 0x008)>>3; + Cores[core].InpWetR=(vx & 0x010)>>4; + Cores[core].InpWetL=(vx & 0x020)>>5; + Cores[core].InpDryR=(vx & 0x040)>>6; + Cores[core].InpDryL=(vx & 0x080)>>7; + Cores[core].SndWetR=(vx & 0x100)>>8; + Cores[core].SndWetL=(vx & 0x200)>>9; + Cores[core].SndDryR=(vx & 0x400)>>10; + Cores[core].SndDryL=(vx & 0x800)>>11; + Cores[core].Regs.MMIX = value; + break; + case (REG_S_KON + 2): + RegLog(2,"KON1",rmem,core,value); + StartVoices(core,((u32)value)<<16); + break; + case REG_S_KON: + RegLog(2,"KON0",rmem,core,value); + StartVoices(core,((u32)value)); + break; + case (REG_S_KOFF + 2): + RegLog(2,"KOFF1",rmem,core,value); + StopVoices(core,((u32)value)<<16); + break; + case REG_S_KOFF: + RegLog(2,"KOFF0",rmem,core,value); + StopVoices(core,((u32)value)); + break; + case REG_S_ENDX: + //ConLog(" * SPU2: Core %d ENDX cleared!\n",core); + RegLog(2,"ENDX0",rmem,core,value); + Cores[core].Regs.ENDX&=0x00FF0000; break; + case (REG_S_ENDX + 2): + //ConLog(" * SPU2: Core %d ENDX cleared!\n",core); + RegLog(2,"ENDX1",rmem,core,value); + Cores[core].Regs.ENDX&=0xFFFF; break; + case REG_P_MVOLL: + RegLog(1,"MVOLL",rmem,core,value); + if (value & 0x8000) { // +Lin/-Lin/+Exp/-Exp + Cores[core].MasterL.Mode=(value & 0xE000)/0x2000; + Cores[core].MasterL.Increment=(value & 0x3F) | ((value & 0x800)/0x10); + } + else { + Cores[core].MasterL.Mode=0; + Cores[core].MasterL.Increment=0; + Cores[core].MasterL.Value=value; + } + Cores[core].MasterL.Reg_VOL=value; + break; + case REG_P_MVOLR: + RegLog(1,"MVOLR",rmem,core,value); + if (value & 0x8000) { // +Lin/-Lin/+Exp/-Exp + Cores[core].MasterR.Mode=(value & 0xE000)/0x2000; + Cores[core].MasterR.Increment=(value & 0x3F) | ((value & 0x800)/0x10); + } + else { + Cores[core].MasterR.Mode=0; + Cores[core].MasterR.Increment=0; + Cores[core].MasterR.Value=value; + } + Cores[core].MasterR.Reg_VOL=value; + break; + case REG_S_ADMAS: + RegLog(3,"ADMAS",rmem,core,value); + //ConLog(" * SPU2: Core %d AutoDMAControl set to %d (%d)\n",core,value, Cycles); + Cores[core].AutoDMACtrl=value; + + if(value==0) + { + Cores[core].AdmaInProgress=0; + } + break; + + default: + *(regtable[mem>>1])=value; + break; + } + + SPU2writeLog(mem,value); + if ((mem>=0x07C0) && (mem<0x07CE)) + { + UpdateSpdifMode(); + } +} + + +void VoiceStart(int core,int vc) +{ + if((Cycles-Cores[core].Voices[vc].PlayCycle)>=4) + { + if(Cores[core].Voices[vc].StartA&7) + { + fprintf( stderr, " *** Missaligned StartA %05x!\n",Cores[core].Voices[vc].StartA); + Cores[core].Voices[vc].StartA=(Cores[core].Voices[vc].StartA+0xFFFF8)+0x8; + } + + Cores[core].Voices[vc].ADSR.Releasing=0; + Cores[core].Voices[vc].ADSR.Value=1; + Cores[core].Voices[vc].ADSR.Phase=1; + Cores[core].Voices[vc].PlayCycle=Cycles; + Cores[core].Voices[vc].SCurrent=28; + Cores[core].Voices[vc].LoopMode=0; + Cores[core].Voices[vc].LoopFlags=0; + Cores[core].Voices[vc].LoopStartA=Cores[core].Voices[vc].StartA; + Cores[core].Voices[vc].NextA=Cores[core].Voices[vc].StartA; + Cores[core].Voices[vc].Prev1=0; + Cores[core].Voices[vc].Prev2=0; + + Cores[core].Voices[vc].PV1=Cores[core].Voices[vc].PV2=0; + Cores[core].Voices[vc].PV3=Cores[core].Voices[vc].PV4=0; + + Cores[core].Regs.ENDX&=~(1<>vc) & 1) { + VoiceStart(core,vc); + } + } + Cores[core].Regs.ENDX &= ~(value); + //Cores[core].Regs.ENDX = 0; +} + +void StopVoices(int core, u32 value) +{ + u32 vx=1,vc=0; + for (vc=0;vc<24;vc++) { + if ((value>>vc) & 1) { + Cores[core].Voices[vc].ADSR.Releasing=1; + //if(MsgKeyOnOff()) ConLog(" * SPU2: KeyOff: Core %d; Voice %d.\n",core,vc); + } + } +} + diff --git a/plugins/spu2ghz/src/spu2.h b/plugins/spu2ghz/src/spu2.h index 3e2e60a1db..619b9be2dc 100644 --- a/plugins/spu2ghz/src/spu2.h +++ b/plugins/spu2ghz/src/spu2.h @@ -1,227 +1,242 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -#ifndef SPU2_H_INCLUDED -#define SPU2_H_INCLUDED -//system defines -#ifdef __LINUX__ - #include -#else -# define WINVER 0x0501 -# define _WIN32_WINNT 0x0501 -# include -# include -#endif -#include "stdlib.h" -#include "stdio.h" -#include "stdarg.h" -#include "math.h" -#include "time.h" - -//SPU2 plugin defines -//#define SPU2defs // not using the PCSX2 defs (see below) -#include "PS2Edefs.h" - -#define EXPORT_C_(type) extern "C" __declspec(dllexport) type __stdcall - -// We have our own versions that have the DLLExport attribute configured: - -EXPORT_C_(s32) SPU2init(); -EXPORT_C_(s32) SPU2open(void *pDsp); -EXPORT_C_(void) SPU2close(); -EXPORT_C_(void) SPU2shutdown(); -EXPORT_C_(void) SPU2write(u32 mem, u16 value); -EXPORT_C_(u16) SPU2read(u32 mem); -EXPORT_C_(void) SPU2readDMA4Mem(u16 *pMem, u32 size); -EXPORT_C_(void) SPU2writeDMA4Mem(u16 *pMem, u32 size); -EXPORT_C_(void) SPU2interruptDMA4(); -EXPORT_C_(void) SPU2readDMA7Mem(u16* pMem, u32 size); -EXPORT_C_(void) SPU2writeDMA7Mem(u16 *pMem, u32 size); - -// all addresses passed by dma will be pointers to the array starting at baseaddr -// This function is necessary to successfully save and reload the spu2 state -EXPORT_C_(void) SPU2setDMABaseAddr(uptr baseaddr); - -EXPORT_C_(void) SPU2interruptDMA7(); -EXPORT_C_(u32) SPU2ReadMemAddr(int core); -EXPORT_C_(void) SPU2WriteMemAddr(int core,u32 value); -EXPORT_C_(void) SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); - -// extended funcs -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -EXPORT_C_(int) SPU2setupRecording(int start, void* pData); - -EXPORT_C_(void) SPU2setClockPtr(u32* ptr); - -EXPORT_C_(void) SPU2async(u32 cycles); -EXPORT_C_(s32) SPU2freeze(int mode, freezeData *data); -EXPORT_C_(void) SPU2configure(); -EXPORT_C_(void) SPU2about(); -EXPORT_C_(s32) SPU2test(); - - -//#define EFFECTS_DUMP - -//Plugin parts -#include "config.h" -#include "defs.h" -#include "regs.h" -#include "dma.h" -#include "mixer.h" -#include "sndout.h" - -#include "spu2replay.h" - -#define SPU2_LOG - -#include "debug.h" - -// [Air] : give hints to the optimizer -// This is primarily useful for the default case switch optimizer, which enables VC to -// generate more compact switches. - -#ifdef NDEBUG -# define jBREAKPOINT() ((void) 0) -# ifdef _MSC_VER -# define jASSUME(exp) (__assume(exp)) -# else -# define jASSUME(exp) ((void) sizeof(exp)) -# endif -#else -# if defined(_MSC_VER) -# define jBREAKPOINT() do { __asm int 3 } while(0) -# else -# define jBREAKPOINT() ((void) *(volatile char *) 0) -# endif -# define jASSUME(exp) if(exp) ; else jBREAKPOINT() -#endif - -// disable the default case in a switch -#define jNO_DEFAULT \ -{ \ - break; \ - \ -default: \ - jASSUME(0); \ - break; \ -} - -//-------------------------------------------------------------------------------------- -// Helper macros -//-------------------------------------------------------------------------------------- -#ifndef SAFE_FREE -# define SAFE_FREE(p) { if(p) { free(p); (p)=NULL; } } -#endif -#ifndef SAFE_DELETE_ARRAY -# define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } } -#endif -#ifndef SAFE_DELETE -# define SAFE_DELETE_OBJ(p) { if(p) { delete (p); (p)=NULL; } } -#endif -#ifndef SAFE_RELEASE -# define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } -#endif - -// The SPU2 has a dynamic memory range which is used for several internal operations, such as -// registers, CORE 1/2 mixing, AutoDMAs, and some other fancy stuff. We exclude this range -// from the cache here: -static const s32 SPU2_DYN_MEMLINE = 0x2800; - -// 8 short words per encoded PCM block. (as stored in SPU2 ram) -static const int pcm_WordsPerBlock = 8; - -// number of cachable ADPCM blocks (any blocks above the SPU2_DYN_MEMLINE) -static const int pcm_BlockCount = 0x100000 / pcm_WordsPerBlock; - -// 28 samples per decoded PCM block (as stored in our cache) -static const int pcm_DecodedSamplesPerBlock = 28; - -struct PcmCacheEntry -{ - bool Validated; - s16 Sampledata[pcm_DecodedSamplesPerBlock]; -}; - -extern void spdif_set51(u32 is_5_1_out); -extern u32 spdif_init(); -extern void spdif_shutdown(); -extern void spdif_get_samples(s32 *samples); // fills the buffer with [l,r,c,lfe,sl,sr] if using 5.1 output, or [l,r] if using stereo - -extern short *spu2regs; -extern short *_spu2mem; - -extern PcmCacheEntry* pcm_cache_data; - -extern s16 __forceinline * __fastcall GetMemPtr(u32 addr); -extern s16 __forceinline __fastcall spu2M_Read( u32 addr ); -extern void __inline __fastcall spu2M_Write( u32 addr, s16 value ); -extern void __inline __fastcall spu2M_Write( u32 addr, u16 value ); - -#define spu2Rs16(mmem) (*(s16 *)((s8 *)spu2regs + ((mmem) & 0x1fff))) -#define spu2Ru16(mmem) (*(u16 *)((s8 *)spu2regs + ((mmem) & 0x1fff))) - -void SysMessage(const char *fmt, ...); - -extern void VoiceStart(int core,int vc); -extern void VoiceStop(int core,int vc); - -extern s32 uTicks; - -extern void (* _irqcallback)(); -extern void (* dma4callback)(); -extern void (* dma7callback)(); - -extern void SetIrqCall(); - -extern double srate_pv; - -extern s16 *input_data; -extern u32 input_data_ptr; - -extern HINSTANCE hInstance; - -extern int PlayMode; - -extern int recording; -void RecordStart(); -void RecordStop(); -void RecordWrite(s16 left, s16 right); - -extern CRITICAL_SECTION threadSync; - -extern u32 lClocks; - -extern u32* cPtr; -extern bool hasPtr; - -extern bool disableFreezes; - -void __fastcall TimeUpdate(u32 cClocks); - -void TimestretchUpdate(int bufferusage,int buffersize); - -s32 DspLoadLibrary(char *fileName, int modNum); -void DspCloseLibrary(); -int DspProcess(s16 *buffer, int samples); -void DspUpdate(); // to let the Dsp process window messages - -void SndUpdateLimitMode(); -//#define PCM24_S1_INTERLEAVE - -#endif // SPU2_H_INCLUDED // +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#ifndef SPU2_H_INCLUDED +#define SPU2_H_INCLUDED + +//system defines +#ifdef __LINUX__ + #include +#else +# define WINVER 0x0501 +# define _WIN32_WINNT 0x0501 +# include +# include +#endif + +#include + +#include +#include +#include +#include +#include + +//SPU2 plugin defines +//#define SPU2defs // not using the PCSX2 defs (see below) +#include "PS2Edefs.h" + +#define EXPORT_C_(type) extern "C" __declspec(dllexport) type __stdcall + +// We have our own versions that have the DLLExport attribute configured: + +EXPORT_C_(s32) SPU2init(); +EXPORT_C_(s32) SPU2open(void *pDsp); +EXPORT_C_(void) SPU2close(); +EXPORT_C_(void) SPU2shutdown(); +EXPORT_C_(void) SPU2write(u32 mem, u16 value); +EXPORT_C_(u16) SPU2read(u32 mem); +EXPORT_C_(void) SPU2readDMA4Mem(u16 *pMem, u32 size); +EXPORT_C_(void) SPU2writeDMA4Mem(u16 *pMem, u32 size); +EXPORT_C_(void) SPU2interruptDMA4(); +EXPORT_C_(void) SPU2readDMA7Mem(u16* pMem, u32 size); +EXPORT_C_(void) SPU2writeDMA7Mem(u16 *pMem, u32 size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +EXPORT_C_(void) SPU2setDMABaseAddr(uptr baseaddr); + +EXPORT_C_(void) SPU2interruptDMA7(); +EXPORT_C_(u32) SPU2ReadMemAddr(int core); +EXPORT_C_(void) SPU2WriteMemAddr(int core,u32 value); +EXPORT_C_(void) SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +EXPORT_C_(int) SPU2setupRecording(int start, void* pData); + +EXPORT_C_(void) SPU2setClockPtr(u32* ptr); + +EXPORT_C_(void) SPU2async(u32 cycles); +EXPORT_C_(s32) SPU2freeze(int mode, freezeData *data); +EXPORT_C_(void) SPU2configure(); +EXPORT_C_(void) SPU2about(); +EXPORT_C_(s32) SPU2test(); + + +//#define EFFECTS_DUMP + +//Plugin parts +#include "config.h" +#include "defs.h" +#include "regs.h" +#include "dma.h" +#include "mixer.h" +#include "sndout.h" + +#include "spu2replay.h" + +#define SPU2_LOG + +#include "debug.h" + +// [Air] : give hints to the optimizer +// This is primarily useful for the default case switch optimizer, which enables VC to +// generate more compact switches. + +#ifdef NDEBUG +# define jBREAKPOINT() ((void) 0) +# ifdef _MSC_VER +# define jASSUME(exp) (__assume(exp)) +# else +# define jASSUME(exp) ((void) sizeof(exp)) +# endif +#else +# if defined(_MSC_VER) +# define jBREAKPOINT() do { __asm int 3 } while(0) +# else +# define jBREAKPOINT() ((void) *(volatile char *) 0) +# endif +# define jASSUME(exp) if(exp) ; else jBREAKPOINT() +#endif + +// disable the default case in a switch +#define jNO_DEFAULT \ +{ \ + break; \ + \ +default: \ + jASSUME(0); \ + break; \ +} + +//-------------------------------------------------------------------------------------- +// Helper macros +//-------------------------------------------------------------------------------------- +#ifndef SAFE_FREE +# define SAFE_FREE(p) { if(p) { free(p); (p)=NULL; } } +#endif +#ifndef SAFE_DELETE_ARRAY +# define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } } +#endif +#ifndef SAFE_DELETE +# define SAFE_DELETE_OBJ(p) { if(p) { delete (p); (p)=NULL; } } +#endif +#ifndef SAFE_RELEASE +# define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } +#endif + +// The SPU2 has a dynamic memory range which is used for several internal operations, such as +// registers, CORE 1/2 mixing, AutoDMAs, and some other fancy stuff. We exclude this range +// from the cache here: +static const s32 SPU2_DYN_MEMLINE = 0x2800; + +// 8 short words per encoded PCM block. (as stored in SPU2 ram) +static const int pcm_WordsPerBlock = 8; + +// number of cachable ADPCM blocks (any blocks above the SPU2_DYN_MEMLINE) +static const int pcm_BlockCount = 0x100000 / pcm_WordsPerBlock; + +// 28 samples per decoded PCM block (as stored in our cache) +static const int pcm_DecodedSamplesPerBlock = 28; + +struct PcmCacheEntry +{ + bool Validated; + s16 Sampledata[pcm_DecodedSamplesPerBlock]; +}; + +extern void spdif_set51(u32 is_5_1_out); +extern u32 spdif_init(); +extern void spdif_shutdown(); +extern void spdif_get_samples(s32 *samples); // fills the buffer with [l,r,c,lfe,sl,sr] if using 5.1 output, or [l,r] if using stereo + +extern short *spu2regs; +extern short *_spu2mem; + +extern PcmCacheEntry* pcm_cache_data; + +extern s16 __forceinline * __fastcall GetMemPtr(u32 addr); +extern s16 __forceinline __fastcall spu2M_Read( u32 addr ); +extern void __inline __fastcall spu2M_Write( u32 addr, s16 value ); +extern void __inline __fastcall spu2M_Write( u32 addr, u16 value ); + +#define spu2Rs16(mmem) (*(s16 *)((s8 *)spu2regs + ((mmem) & 0x1fff))) +#define spu2Ru16(mmem) (*(u16 *)((s8 *)spu2regs + ((mmem) & 0x1fff))) + +void SysMessage(const char *fmt, ...); + +extern void VoiceStart(int core,int vc); +extern void VoiceStop(int core,int vc); + +extern s32 uTicks; + +extern void (* _irqcallback)(); +extern void (* dma4callback)(); +extern void (* dma7callback)(); + +extern void SetIrqCall(); + +extern double srate_pv; + +extern s16 *input_data; +extern u32 input_data_ptr; + +extern HINSTANCE hInstance; + +extern int PlayMode; +extern int recording; + +extern u32 lClocks; + +extern u32* cPtr; +extern bool hasPtr; + +extern bool disableFreezes; +extern bool resetClock; + +extern void RegLog(int level, char *RName,u32 mem,u32 core,u16 value); +extern void SPU2writeLog(u32 rmem, u16 value); + +extern void __fastcall TimeUpdate(u32 cClocks); +extern u16 SPU_ps1_read(u32 mem); +extern void SPU_ps1_write(u32 mem, u16 value); +extern void SPU2_FastWrite( u32 rmem, u16 value ); + +extern void CoreReset(int c); +extern void StartVoices(int core, u32 value); +extern void StopVoices(int core, u32 value); + +extern s32 DspLoadLibrary(char *fileName, int modNum); +extern void DspCloseLibrary(); +extern int DspProcess(s16 *buffer, int samples); +extern void DspUpdate(); // to let the Dsp process window messages + +extern void RecordStart(); +extern void RecordStop(); +extern void RecordWrite(s16 left, s16 right); + +extern void UpdateSpdifMode(); +extern void LowPassFilterInit(); +extern void InitADSR(); +extern void SndUpdateLimitMode(); + +//#define PCM24_S1_INTERLEAVE + +#endif // SPU2_H_INCLUDED // diff --git a/plugins/spu2ghz/src/spu2replay.cpp b/plugins/spu2ghz/src/spu2replay.cpp index f613e0160c..51e08e5ed3 100644 --- a/plugins/spu2ghz/src/spu2replay.cpp +++ b/plugins/spu2ghz/src/spu2replay.cpp @@ -1,196 +1,196 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// - -#include - -#include "spu2.h" - -FILE* s2rfile; - -void s2r_write16(s16 data) -{ - fwrite(&data,2,1,s2rfile); -} - -void s2r_write32(u32 data) -{ - fwrite(&data,4,1,s2rfile); -} - -#define EMITC(i,a) s2r_write32(((u32)(i&0xFF)<<24)|(a&0xFFFFFF)) - -int s2r_open(char *filename) -{ - s2rfile=fopen(filename,"wb"); - return s2rfile?0:-1; -} - -void s2r_readreg(u32 ticks,u32 addr) -{ - if(!s2rfile) return; - s2r_write32(ticks); - EMITC(0,addr); -} - -void s2r_writereg(u32 ticks,u32 addr,s16 value) -{ - if(!s2rfile) return; - s2r_write32(ticks); - EMITC(1,addr); - s2r_write16(value); -} - -void s2r_writedma4(u32 ticks,u16*data,u32 len) -{ - u32 i; - if(!s2rfile) return; - s2r_write32(ticks); - EMITC(2,len); - for(i=0;i>24; - sval&=0xFFFFFF; - - while((ccycle-lasync)>64) - { - lasync+=64; - pcycles=lasync; - pclocks=pcycles*768; - - SPU2async(pclocks); - } - pcycles=ccycle; - pclocks=pcycles*768; - - - switch(evid) - { - case 0: - SPU2read(sval); - break; - case 1: - Cread(&tval,2,1,file); - SPU2write(sval,tval); - break; - case 2: - Cread(dmabuffer,sval,2,file); - SPU2writeDMA4Mem(dmabuffer,sval); - break; - case 3: - Cread(dmabuffer,sval,2,file); - SPU2writeDMA7Mem(dmabuffer,sval); - break; - default: - // not implemented - return; - break; - } - } - - //shutdown - SPU2close(); - SPU2shutdown(); - fclose(file); - - replay_mode=false; -} +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#include + +#include "spu2.h" + +FILE* s2rfile; + +void s2r_write16(s16 data) +{ + fwrite(&data,2,1,s2rfile); +} + +void s2r_write32(u32 data) +{ + fwrite(&data,4,1,s2rfile); +} + +#define EMITC(i,a) s2r_write32(((u32)(i&0xFF)<<24)|(a&0xFFFFFF)) + +int s2r_open(char *filename) +{ + s2rfile=fopen(filename,"wb"); + return s2rfile?0:-1; +} + +void s2r_readreg(u32 ticks,u32 addr) +{ + if(!s2rfile) return; + s2r_write32(ticks); + EMITC(0,addr); +} + +void s2r_writereg(u32 ticks,u32 addr,s16 value) +{ + if(!s2rfile) return; + s2r_write32(ticks); + EMITC(1,addr); + s2r_write16(value); +} + +void s2r_writedma4(u32 ticks,u16*data,u32 len) +{ + u32 i; + if(!s2rfile) return; + s2r_write32(ticks); + EMITC(2,len); + for(i=0;i>24; + sval&=0xFFFFFF; + + while((ccycle-lasync)>64) + { + lasync+=64; + pcycles=lasync; + pclocks=pcycles*768; + + SPU2async(pclocks); + } + pcycles=ccycle; + pclocks=pcycles*768; + + + switch(evid) + { + case 0: + SPU2read(sval); + break; + case 1: + Cread(&tval,2,1,file); + SPU2write(sval,tval); + break; + case 2: + Cread(dmabuffer,sval,2,file); + SPU2writeDMA4Mem(dmabuffer,sval); + break; + case 3: + Cread(dmabuffer,sval,2,file); + SPU2writeDMA7Mem(dmabuffer,sval); + break; + default: + // not implemented + return; + break; + } + } + + //shutdown + SPU2close(); + SPU2shutdown(); + fclose(file); + + replay_mode=false; +} diff --git a/plugins/spu2ghz/src/spu2replay.h b/plugins/spu2ghz/src/spu2replay.h index 6e3765f0fd..ea6aac62af 100644 --- a/plugins/spu2ghz/src/spu2replay.h +++ b/plugins/spu2ghz/src/spu2replay.h @@ -1,35 +1,35 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// - -#ifndef SPU2REPLAY_H_INCLUDED -#define SPU2REPLAY_H_INCLUDED - -// s2r dumping -int s2r_open(char *filename); -void s2r_readreg(u32 ticks,u32 addr); -void s2r_writereg(u32 ticks,u32 addr,s16 value); -void s2r_writedma4(u32 ticks,u16*data,u32 len); -void s2r_writedma7(u32 ticks,u16*data,u32 len); -void s2r_close(); - -// s2r playing -void CALLBACK s2r_replay(HWND hwnd, HINSTANCE hinst, LPSTR filename, int nCmdShow); - -extern bool replay_mode; - +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#ifndef SPU2REPLAY_H_INCLUDED +#define SPU2REPLAY_H_INCLUDED + +// s2r dumping +int s2r_open(char *filename); +void s2r_readreg(u32 ticks,u32 addr); +void s2r_writereg(u32 ticks,u32 addr,s16 value); +void s2r_writedma4(u32 ticks,u16*data,u32 len); +void s2r_writedma7(u32 ticks,u16*data,u32 len); +void s2r_close(); + +// s2r playing +void CALLBACK s2r_replay(HWND hwnd, HINSTANCE hinst, LPSTR filename, int nCmdShow); + +extern bool replay_mode; + #endif//SPU2REPLAY_H_INCLUDED \ No newline at end of file diff --git a/plugins/spu2ghz/src/utf8.cpp b/plugins/spu2ghz/src/utf8.cpp index 1a53d5cd80..6dd8c2e876 100644 --- a/plugins/spu2ghz/src/utf8.cpp +++ b/plugins/spu2ghz/src/utf8.cpp @@ -1,320 +1,320 @@ -/* - * Copyright (C) 2001 Peter Harris - * Copyright (C) 2001 Edmund Grimley Evans - * - * 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 - */ - -/* - * Convert a string between UTF-8 and the locale's charset. - */ - -#include -#include - -#include "utf8.h" - - -#ifdef _WIN32 - - /* Thanks to Peter Harris for this win32 - * code. - */ - -#include -#include - -static unsigned char *make_utf8_string(const wchar_t *unicode) -{ - int size = 0, index = 0, out_index = 0; - unsigned char *out; - unsigned short c; - - /* first calculate the size of the target string */ - c = unicode[index++]; - while(c) { - if(c < 0x0080) { - size += 1; - } else if(c < 0x0800) { - size += 2; - } else { - size += 3; - } - c = unicode[index++]; - } - - out = (unsigned char*)malloc(size + 1); - if (out == NULL) - return NULL; - index = 0; - - c = unicode[index++]; - while(c) - { - if(c < 0x080) { - out[out_index++] = (unsigned char)c; - } else if(c < 0x800) { - out[out_index++] = 0xc0 | (c >> 6); - out[out_index++] = 0x80 | (c & 0x3f); - } else { - out[out_index++] = 0xe0 | (c >> 12); - out[out_index++] = 0x80 | ((c >> 6) & 0x3f); - out[out_index++] = 0x80 | (c & 0x3f); - } - c = unicode[index++]; - } - out[out_index] = 0x00; - - return out; -} - -static wchar_t *make_unicode_string(const unsigned char *utf8) -{ - int size = 0, index = 0, out_index = 0; - wchar_t *out; - unsigned char c; - - /* first calculate the size of the target string */ - c = utf8[index++]; - while(c) { - if((c & 0x80) == 0) { - index += 0; - } else if((c & 0xe0) == 0xe0) { - index += 2; - } else { - index += 1; - } - size += 1; - c = utf8[index++]; - } - - out = (wchar_t*)malloc((size + 1) * sizeof(wchar_t)); - if (out == NULL) - return NULL; - index = 0; - - c = utf8[index++]; - while(c) - { - if((c & 0x80) == 0) { - out[out_index++] = c; - } else if((c & 0xe0) == 0xe0) { - out[out_index] = (c & 0x1F) << 12; - c = utf8[index++]; - out[out_index] |= (c & 0x3F) << 6; - c = utf8[index++]; - out[out_index++] |= (c & 0x3F); - } else { - out[out_index] = (c & 0x3F) << 6; - c = utf8[index++]; - out[out_index++] |= (c & 0x3F); - } - c = utf8[index++]; - } - out[out_index] = 0; - - return out; -} - -int utf8_encode(const char *from, char **to) -{ - wchar_t *unicode; - int wchars, err; - - wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, - strlen(from), NULL, 0); - - if(wchars == 0) - { - fprintf(stderr, "Unicode translation error %d\n", GetLastError()); - return -1; - } - - unicode = (wchar_t*)calloc(wchars + 1, sizeof(unsigned short)); - if(unicode == NULL) - { - fprintf(stderr, "Out of memory processing string to UTF8\n"); - return -1; - } - - err = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, - strlen(from), unicode, wchars); - if(err != wchars) - { - free(unicode); - fprintf(stderr, "Unicode translation error %d\n", GetLastError()); - return -1; - } - - /* On NT-based windows systems, we could use WideCharToMultiByte(), but - * MS doesn't actually have a consistent API across win32. - */ - *to = (char*)make_utf8_string(unicode); - - free(unicode); - return 0; -} - -int utf8_decode(const char *from, char **to) -{ - wchar_t *unicode; - int chars, err; - - /* On NT-based windows systems, we could use MultiByteToWideChar(CP_UTF8), but - * MS doesn't actually have a consistent API across win32. - */ - unicode = make_unicode_string((unsigned char*)from); - if(unicode == NULL) - { - fprintf(stderr, "Out of memory processing string from UTF8 to UNICODE16\n"); - return -1; - } - - chars = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, - -1, NULL, 0, NULL, NULL); - - if(chars == 0) - { - fprintf(stderr, "Unicode translation error %d\n", GetLastError()); - free(unicode); - return -1; - } - - *to = (char *)calloc(chars + 1, sizeof(unsigned char)); - if(*to == NULL) - { - fprintf(stderr, "Out of memory processing string to local charset\n"); - free(unicode); - return -1; - } - - err = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, - -1, *to, chars, NULL, NULL); - if(err != chars) - { - fprintf(stderr, "Unicode translation error %d\n", GetLastError()); - free(unicode); - free(*to); - *to = NULL; - return -1; - } - - free(unicode); - return 0; -} - -#else /* End win32. Rest is for real operating systems */ - - -#ifdef HAVE_LANGINFO_CODESET -#include -#endif - -int iconvert(const char *fromcode, const char *tocode, - const char *from, size_t fromlen, - char **to, size_t *tolen); - -static char *current_charset = 0; /* means "US-ASCII" */ - -void convert_set_charset(const char *charset) -{ - - if (!charset) - charset = getenv("CHARSET"); - -#ifdef HAVE_LANGINFO_CODESET - if (!charset) - charset = nl_langinfo(CODESET); -#endif - - free(current_charset); - current_charset = 0; - if (charset && *charset) - current_charset = strdup(charset); -} - -static int convert_buffer(const char *fromcode, const char *tocode, - const char *from, size_t fromlen, - char **to, size_t *tolen) -{ - int ret = -1; - -#ifdef HAVE_ICONV - ret = iconvert(fromcode, tocode, from, fromlen, to, tolen); - if (ret != -1) - return ret; -#endif - -#ifndef HAVE_ICONV /* should be ifdef USE_CHARSET_CONVERT */ - ret = charset_convert(fromcode, tocode, from, fromlen, to, tolen); - if (ret != -1) - return ret; -#endif - - return ret; -} - -static int convert_string(const char *fromcode, const char *tocode, - const char *from, char **to, char replace) -{ - int ret; - size_t fromlen; - char *s; - - fromlen = strlen(from); - ret = convert_buffer(fromcode, tocode, from, fromlen, to, 0); - if (ret == -2) - return -1; - if (ret != -1) - return ret; - - s = malloc(fromlen + 1); - if (!s) - return -1; - strcpy(s, from); - *to = s; - for (; *s; s++) - if (*s & ~0x7f) - *s = replace; - return 3; -} - -int utf8_encode(const char *from, char **to) -{ - char *charset; - - if (!current_charset) - convert_set_charset(0); - charset = current_charset ? current_charset : "US-ASCII"; - return convert_string(charset, "UTF-8", from, to, '#'); -} - -int utf8_decode(const char *from, char **to) -{ - char *charset; - - if(*from == 0) { - *to = malloc(1); - **to = 0; - return 1; - } - - if (!current_charset) - convert_set_charset(0); - charset = current_charset ? current_charset : "US-ASCII"; - return convert_string("UTF-8", charset, from, to, '?'); -} - -#endif +/* + * Copyright (C) 2001 Peter Harris + * Copyright (C) 2001 Edmund Grimley Evans + * + * 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 + */ + +/* + * Convert a string between UTF-8 and the locale's charset. + */ + +#include +#include + +#include "utf8.h" + + +#ifdef _WIN32 + + /* Thanks to Peter Harris for this win32 + * code. + */ + +#include +#include + +static unsigned char *make_utf8_string(const wchar_t *unicode) +{ + int size = 0, index = 0, out_index = 0; + unsigned char *out; + unsigned short c; + + /* first calculate the size of the target string */ + c = unicode[index++]; + while(c) { + if(c < 0x0080) { + size += 1; + } else if(c < 0x0800) { + size += 2; + } else { + size += 3; + } + c = unicode[index++]; + } + + out = (unsigned char*)malloc(size + 1); + if (out == NULL) + return NULL; + index = 0; + + c = unicode[index++]; + while(c) + { + if(c < 0x080) { + out[out_index++] = (unsigned char)c; + } else if(c < 0x800) { + out[out_index++] = 0xc0 | (c >> 6); + out[out_index++] = 0x80 | (c & 0x3f); + } else { + out[out_index++] = 0xe0 | (c >> 12); + out[out_index++] = 0x80 | ((c >> 6) & 0x3f); + out[out_index++] = 0x80 | (c & 0x3f); + } + c = unicode[index++]; + } + out[out_index] = 0x00; + + return out; +} + +static wchar_t *make_unicode_string(const unsigned char *utf8) +{ + int size = 0, index = 0, out_index = 0; + wchar_t *out; + unsigned char c; + + /* first calculate the size of the target string */ + c = utf8[index++]; + while(c) { + if((c & 0x80) == 0) { + index += 0; + } else if((c & 0xe0) == 0xe0) { + index += 2; + } else { + index += 1; + } + size += 1; + c = utf8[index++]; + } + + out = (wchar_t*)malloc((size + 1) * sizeof(wchar_t)); + if (out == NULL) + return NULL; + index = 0; + + c = utf8[index++]; + while(c) + { + if((c & 0x80) == 0) { + out[out_index++] = c; + } else if((c & 0xe0) == 0xe0) { + out[out_index] = (c & 0x1F) << 12; + c = utf8[index++]; + out[out_index] |= (c & 0x3F) << 6; + c = utf8[index++]; + out[out_index++] |= (c & 0x3F); + } else { + out[out_index] = (c & 0x3F) << 6; + c = utf8[index++]; + out[out_index++] |= (c & 0x3F); + } + c = utf8[index++]; + } + out[out_index] = 0; + + return out; +} + +int utf8_encode(const char *from, char **to) +{ + wchar_t *unicode; + int wchars, err; + + wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, + strlen(from), NULL, 0); + + if(wchars == 0) + { + fprintf(stderr, "Unicode translation error %d\n", GetLastError()); + return -1; + } + + unicode = (wchar_t*)calloc(wchars + 1, sizeof(unsigned short)); + if(unicode == NULL) + { + fprintf(stderr, "Out of memory processing string to UTF8\n"); + return -1; + } + + err = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, + strlen(from), unicode, wchars); + if(err != wchars) + { + free(unicode); + fprintf(stderr, "Unicode translation error %d\n", GetLastError()); + return -1; + } + + /* On NT-based windows systems, we could use WideCharToMultiByte(), but + * MS doesn't actually have a consistent API across win32. + */ + *to = (char*)make_utf8_string(unicode); + + free(unicode); + return 0; +} + +int utf8_decode(const char *from, char **to) +{ + wchar_t *unicode; + int chars, err; + + /* On NT-based windows systems, we could use MultiByteToWideChar(CP_UTF8), but + * MS doesn't actually have a consistent API across win32. + */ + unicode = make_unicode_string((unsigned char*)from); + if(unicode == NULL) + { + fprintf(stderr, "Out of memory processing string from UTF8 to UNICODE16\n"); + return -1; + } + + chars = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, + -1, NULL, 0, NULL, NULL); + + if(chars == 0) + { + fprintf(stderr, "Unicode translation error %d\n", GetLastError()); + free(unicode); + return -1; + } + + *to = (char *)calloc(chars + 1, sizeof(unsigned char)); + if(*to == NULL) + { + fprintf(stderr, "Out of memory processing string to local charset\n"); + free(unicode); + return -1; + } + + err = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, + -1, *to, chars, NULL, NULL); + if(err != chars) + { + fprintf(stderr, "Unicode translation error %d\n", GetLastError()); + free(unicode); + free(*to); + *to = NULL; + return -1; + } + + free(unicode); + return 0; +} + +#else /* End win32. Rest is for real operating systems */ + + +#ifdef HAVE_LANGINFO_CODESET +#include +#endif + +int iconvert(const char *fromcode, const char *tocode, + const char *from, size_t fromlen, + char **to, size_t *tolen); + +static char *current_charset = 0; /* means "US-ASCII" */ + +void convert_set_charset(const char *charset) +{ + + if (!charset) + charset = getenv("CHARSET"); + +#ifdef HAVE_LANGINFO_CODESET + if (!charset) + charset = nl_langinfo(CODESET); +#endif + + free(current_charset); + current_charset = 0; + if (charset && *charset) + current_charset = strdup(charset); +} + +static int convert_buffer(const char *fromcode, const char *tocode, + const char *from, size_t fromlen, + char **to, size_t *tolen) +{ + int ret = -1; + +#ifdef HAVE_ICONV + ret = iconvert(fromcode, tocode, from, fromlen, to, tolen); + if (ret != -1) + return ret; +#endif + +#ifndef HAVE_ICONV /* should be ifdef USE_CHARSET_CONVERT */ + ret = charset_convert(fromcode, tocode, from, fromlen, to, tolen); + if (ret != -1) + return ret; +#endif + + return ret; +} + +static int convert_string(const char *fromcode, const char *tocode, + const char *from, char **to, char replace) +{ + int ret; + size_t fromlen; + char *s; + + fromlen = strlen(from); + ret = convert_buffer(fromcode, tocode, from, fromlen, to, 0); + if (ret == -2) + return -1; + if (ret != -1) + return ret; + + s = malloc(fromlen + 1); + if (!s) + return -1; + strcpy(s, from); + *to = s; + for (; *s; s++) + if (*s & ~0x7f) + *s = replace; + return 3; +} + +int utf8_encode(const char *from, char **to) +{ + char *charset; + + if (!current_charset) + convert_set_charset(0); + charset = current_charset ? current_charset : "US-ASCII"; + return convert_string(charset, "UTF-8", from, to, '#'); +} + +int utf8_decode(const char *from, char **to) +{ + char *charset; + + if(*from == 0) { + *to = malloc(1); + **to = 0; + return 1; + } + + if (!current_charset) + convert_set_charset(0); + charset = current_charset ? current_charset : "US-ASCII"; + return convert_string("UTF-8", charset, from, to, '?'); +} + +#endif diff --git a/plugins/spu2ghz/src/utf8.h b/plugins/spu2ghz/src/utf8.h index 0f799a43cd..f701319bdf 100644 --- a/plugins/spu2ghz/src/utf8.h +++ b/plugins/spu2ghz/src/utf8.h @@ -1,36 +1,36 @@ - -/* - * Convert a string between UTF-8 and the locale's charset. - * Invalid bytes are replaced by '#', and characters that are - * not available in the target encoding are replaced by '?'. - * - * If the locale's charset is not set explicitly then it is - * obtained using nl_langinfo(CODESET), where available, the - * environment variable CHARSET, or assumed to be US-ASCII. - * - * Return value of conversion functions: - * - * -1 : memory allocation failed - * 0 : data was converted exactly - * 1 : valid data was converted approximately (using '?') - * 2 : input was invalid (but still converted, using '#') - * 3 : unknown encoding (but still converted, using '?') - */ - -#ifndef __UTF8_H -#define __UTF8_H - -#ifdef __cplusplus -extern "C" { -#endif - -void convert_set_charset(const char *charset); - -int utf8_encode(const char *from, char **to); -int utf8_decode(const char *from, char **to); - -#ifdef __cplusplus -} -#endif - -#endif /* __UTF8_H */ + +/* + * Convert a string between UTF-8 and the locale's charset. + * Invalid bytes are replaced by '#', and characters that are + * not available in the target encoding are replaced by '?'. + * + * If the locale's charset is not set explicitly then it is + * obtained using nl_langinfo(CODESET), where available, the + * environment variable CHARSET, or assumed to be US-ASCII. + * + * Return value of conversion functions: + * + * -1 : memory allocation failed + * 0 : data was converted exactly + * 1 : valid data was converted approximately (using '?') + * 2 : input was invalid (but still converted, using '#') + * 3 : unknown encoding (but still converted, using '?') + */ + +#ifndef __UTF8_H +#define __UTF8_H + +#ifdef __cplusplus +extern "C" { +#endif + +void convert_set_charset(const char *charset); + +int utf8_encode(const char *from, char **to); +int utf8_decode(const char *from, char **to); + +#ifdef __cplusplus +} +#endif + +#endif /* __UTF8_H */ diff --git a/plugins/spu2ghz/src/wavedump_wav.cpp b/plugins/spu2ghz/src/wavedump_wav.cpp index c90d64df58..4971c559f2 100644 --- a/plugins/spu2ghz/src/wavedump_wav.cpp +++ b/plugins/spu2ghz/src/wavedump_wav.cpp @@ -1,196 +1,196 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// - -#include "spu2.h" -#include - -#define WAVONLY - -typedef struct { - //Main Header - char riffID[4]; - long riffSize; - char riffTYPE[4]; - //Format Tag - char chunkID[4]; - long chunkSize; - short wFormatTag; - unsigned short wChannels; - unsigned long dwSamplesPerSec; - unsigned long dwAvgBytesPerSec; - unsigned short wBlockAlign; - unsigned short wBitsPerSample; - //Data Tag - char dataID[4]; - long dataSize; -} WAVEHeader; - -int wavedump_ok=0; -int datasize; -FILE *fdump; - -#ifndef WAVONLY -int flacdump_open(); -void flacdump_close(); -void flacdump_write(s16 left,s16 right); -int oggvdump_open(); -void oggvdump_close(); -void oggvdump_write(s16 left,s16 right); -#endif - -int wavedump_open() -{ -#ifndef WAVONLY - if(WaveDumpFormat==1) return flacdump_open(); - if(WaveDumpFormat==2) return oggvdump_open(); -#endif - - fdump=fopen(WaveLogFileName,"wb"); - if(fdump==NULL) return 0; - - fseek(fdump,sizeof(WAVEHeader),SEEK_SET); - - datasize=0; - wavedump_ok=1; - return 1; -} - -void wavedump_flush() -{ - WAVEHeader w; - - memcpy(w.riffID,"RIFF",4); - w.riffSize=datasize+36; - memcpy(w.riffTYPE,"WAVE",4); - memcpy(w.chunkID,"fmt ",4); - w.chunkSize=0x10; - w.wFormatTag=1; - w.wChannels=2; - w.dwSamplesPerSec=48000; - w.dwAvgBytesPerSec=48000*4; - w.wBlockAlign=4; - w.wBitsPerSample=16; - memcpy(w.dataID,"data",4); - w.dataSize=datasize; - - fseek(fdump,0,SEEK_SET); - fwrite(&w,sizeof(w),1,fdump); - - fseek(fdump,datasize+sizeof(w),SEEK_SET); -} - -void wavedump_close() -{ - if(!wavedump_ok) return; - - wavedump_flush(); -#ifndef WAVONLY - if(WaveDumpFormat==1) { flacdump_close(); return;} - if(WaveDumpFormat==2) { oggvdump_close(); return;} -#endif - - - fclose(fdump); - wavedump_ok=0; -} - -void wavedump_write(s16 left,s16 right) -{ - s16 buffer[2]={left,right}; - - if(!wavedump_ok) return; - -#ifndef WAVONLY - if(WaveDumpFormat==1) return flacdump_write(left,right); - if(WaveDumpFormat==2) return oggvdump_write(left,right); -#endif - datasize+=4; - - fwrite(buffer,4,1,fdump); - - if((datasize&1023)==0) - wavedump_flush(); -} - -FILE *recordFile; -int recordSize; -int recording; - -void RecordStart() -{ - if(recording&&recordFile) - fclose(recordFile); - - recordFile=fopen("recording.wav","wb"); - if(recordFile==NULL) return; - - fseek(recordFile,sizeof(WAVEHeader),SEEK_SET); - - recordSize=0; - recording=1; -} - -void RecordFlush() -{ - WAVEHeader w; - - memcpy(w.riffID,"RIFF",4); - w.riffSize=recordSize+36; - memcpy(w.riffTYPE,"WAVE",4); - memcpy(w.chunkID,"fmt ",4); - w.chunkSize=0x10; - w.wFormatTag=1; - w.wChannels=2; - w.dwSamplesPerSec=48000; - w.dwAvgBytesPerSec=48000*4; - w.wBlockAlign=4; - w.wBitsPerSample=16; - memcpy(w.dataID,"data",4); - w.dataSize=recordSize; - - fseek(recordFile,0,SEEK_SET); - fwrite(&w,sizeof(w),1,recordFile); - fseek(recordFile,recordSize+sizeof(w),SEEK_SET); -} - -void RecordStop() -{ - if(!recording) - return; - recording=0; - - RecordFlush(); - - fclose(recordFile); -} - -void RecordWrite(s16 left, s16 right) -{ - if(!recording) - return; - - s16 buffer[2]={left,right}; - - recordSize+=4; - - fwrite(buffer,4,1,recordFile); - - if((recordSize&1023)==0) - RecordFlush(); - -} +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#include "spu2.h" +#include + +#define WAVONLY + +typedef struct { + //Main Header + char riffID[4]; + long riffSize; + char riffTYPE[4]; + //Format Tag + char chunkID[4]; + long chunkSize; + short wFormatTag; + unsigned short wChannels; + unsigned long dwSamplesPerSec; + unsigned long dwAvgBytesPerSec; + unsigned short wBlockAlign; + unsigned short wBitsPerSample; + //Data Tag + char dataID[4]; + long dataSize; +} WAVEHeader; + +int wavedump_ok=0; +int datasize; +FILE *fdump; + +#ifndef WAVONLY +int flacdump_open(); +void flacdump_close(); +void flacdump_write(s16 left,s16 right); +int oggvdump_open(); +void oggvdump_close(); +void oggvdump_write(s16 left,s16 right); +#endif + +int wavedump_open() +{ +#ifndef WAVONLY + if(WaveDumpFormat==1) return flacdump_open(); + if(WaveDumpFormat==2) return oggvdump_open(); +#endif + + fdump=fopen(WaveLogFileName,"wb"); + if(fdump==NULL) return 0; + + fseek(fdump,sizeof(WAVEHeader),SEEK_SET); + + datasize=0; + wavedump_ok=1; + return 1; +} + +void wavedump_flush() +{ + WAVEHeader w; + + memcpy(w.riffID,"RIFF",4); + w.riffSize=datasize+36; + memcpy(w.riffTYPE,"WAVE",4); + memcpy(w.chunkID,"fmt ",4); + w.chunkSize=0x10; + w.wFormatTag=1; + w.wChannels=2; + w.dwSamplesPerSec=48000; + w.dwAvgBytesPerSec=48000*4; + w.wBlockAlign=4; + w.wBitsPerSample=16; + memcpy(w.dataID,"data",4); + w.dataSize=datasize; + + fseek(fdump,0,SEEK_SET); + fwrite(&w,sizeof(w),1,fdump); + + fseek(fdump,datasize+sizeof(w),SEEK_SET); +} + +void wavedump_close() +{ + if(!wavedump_ok) return; + + wavedump_flush(); +#ifndef WAVONLY + if(WaveDumpFormat==1) { flacdump_close(); return;} + if(WaveDumpFormat==2) { oggvdump_close(); return;} +#endif + + + fclose(fdump); + wavedump_ok=0; +} + +void wavedump_write(s16 left,s16 right) +{ + s16 buffer[2]={left,right}; + + if(!wavedump_ok) return; + +#ifndef WAVONLY + if(WaveDumpFormat==1) return flacdump_write(left,right); + if(WaveDumpFormat==2) return oggvdump_write(left,right); +#endif + datasize+=4; + + fwrite(buffer,4,1,fdump); + + if((datasize&1023)==0) + wavedump_flush(); +} + +FILE *recordFile; +int recordSize; +int recording; + +void RecordStart() +{ + if(recording&&recordFile) + fclose(recordFile); + + recordFile=fopen("recording.wav","wb"); + if(recordFile==NULL) return; + + fseek(recordFile,sizeof(WAVEHeader),SEEK_SET); + + recordSize=0; + recording=1; +} + +void RecordFlush() +{ + WAVEHeader w; + + memcpy(w.riffID,"RIFF",4); + w.riffSize=recordSize+36; + memcpy(w.riffTYPE,"WAVE",4); + memcpy(w.chunkID,"fmt ",4); + w.chunkSize=0x10; + w.wFormatTag=1; + w.wChannels=2; + w.dwSamplesPerSec=48000; + w.dwAvgBytesPerSec=48000*4; + w.wBlockAlign=4; + w.wBitsPerSample=16; + memcpy(w.dataID,"data",4); + w.dataSize=recordSize; + + fseek(recordFile,0,SEEK_SET); + fwrite(&w,sizeof(w),1,recordFile); + fseek(recordFile,recordSize+sizeof(w),SEEK_SET); +} + +void RecordStop() +{ + if(!recording) + return; + recording=0; + + RecordFlush(); + + fclose(recordFile); +} + +void RecordWrite(s16 left, s16 right) +{ + if(!recording) + return; + + s16 buffer[2]={left,right}; + + recordSize+=4; + + fwrite(buffer,4,1,recordFile); + + if((recordSize&1023)==0) + RecordFlush(); + +} diff --git a/plugins/spu2ghz/src/waveout.cpp b/plugins/spu2ghz/src/waveout.cpp index a9c6a14ae8..ad315f6db3 100644 --- a/plugins/spu2ghz/src/waveout.cpp +++ b/plugins/spu2ghz/src/waveout.cpp @@ -1,278 +1,278 @@ -//GiGaHeRz's SPU2 Driver -//Copyright (c) 2003-2008, David Quintana -// -//This library is free software; you can redistribute it and/or -//modify it under the terms of the GNU Lesser General Public -//License as published by the Free Software Foundation; either -//version 2.1 of the License, or (at your option) any later version. -// -//This library 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 -//Lesser General Public License for more details. -// -//You should have received a copy of the GNU Lesser General Public -//License along with this library; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -#include "spu2.h" -#include "dialogs.h" -#include - - -class WaveOutModule: public SndOutModule -{ -private: -# define MAX_BUFFER_COUNT 8 - - static const int PacketsPerBuffer = (1024 / SndOutPacketSize); - static const int BufferSize = SndOutPacketSize*PacketsPerBuffer; - static const int BufferSizeBytes = BufferSize << 1; - - u32 numBuffers; - HWAVEOUT hwodevice; - WAVEFORMATEX wformat; - WAVEHDR whbuffer[MAX_BUFFER_COUNT]; - - s16* qbuffer; - - #define QBUFFER(x) (qbuffer + BufferSize * (x)) - - bool waveout_running; - HANDLE thread; - DWORD tid; - - SndBuffer *buff; - - FILE *voicelog; - - char ErrText[256]; - - static DWORD CALLBACK RThread(WaveOutModule*obj) - { - return obj->Thread(); - } - - DWORD CALLBACK Thread() - { - while( waveout_running ) - { - bool didsomething = false; - for(u32 i=0;idwBytesRecorded = buf->dwBufferLength; - - s16 *t = (s16*)buf->lpData; - for(int p=0; pReadSamples( t ); - - whbuffer[i].dwFlags&=~WHDR_DONE; - waveOutWrite(hwodevice,buf,sizeof(WAVEHDR)); - didsomething = true; - } - - if( didsomething ) - Sleep(1); - else - Sleep(0); - } - return 0; - } - -public: - s32 Init(SndBuffer *sb) - { - buff = sb; - numBuffers = Config_WaveOut.NumBuffers; - - MMRESULT woores; - - if (Test()) return -1; - - wformat.wFormatTag=WAVE_FORMAT_PCM; - wformat.nSamplesPerSec=SampleRate; - wformat.wBitsPerSample=16; - wformat.nChannels=2; - wformat.nBlockAlign=((wformat.wBitsPerSample * wformat.nChannels) / 8); - wformat.nAvgBytesPerSec=(wformat.nSamplesPerSec * wformat.nBlockAlign); - wformat.cbSize=0; - - qbuffer=new s16[BufferSize*numBuffers]; - - woores = waveOutOpen(&hwodevice,WAVE_MAPPER,&wformat,0,0,0); - if (woores != MMSYSERR_NOERROR) - { - waveOutGetErrorText(woores,(char *)&ErrText,255); - SysMessage("WaveOut Error: %s",ErrText); - return -1; - } - - for(u32 i=0;i MAX_BUFFER_COUNT ) Config_WaveOut.NumBuffers = MAX_BUFFER_COUNT; - } - EndDialog(hWnd,0); - break; - case IDCANCEL: - EndDialog(hWnd,0); - break; - default: - return FALSE; - } - break; - - case WM_HSCROLL: - wmId = LOWORD(wParam); - wmEvent = HIWORD(wParam); - switch(wmId) { - //case TB_ENDTRACK: - //case TB_THUMBPOSITION: - case TB_LINEUP: - case TB_LINEDOWN: - case TB_PAGEUP: - case TB_PAGEDOWN: - wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0); - case TB_THUMBTRACK: - if( wmEvent < 3 ) wmEvent = 3; - if( wmEvent > MAX_BUFFER_COUNT ) wmEvent = MAX_BUFFER_COUNT; - SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent); - sprintf_s(temp,128,"%d (%d ms latency)",wmEvent, 1000 / (96000 / (wmEvent * BufferSize))); - SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp); - break; - default: - return FALSE; - } - break; - - default: - return FALSE; - } - return TRUE; - } - -public: - virtual void Configure(HWND parent) - { - INT_PTR ret; - ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_WAVEOUT),GetActiveWindow(),(DLGPROC)ConfigProc,1); - if(ret==-1) - { - MessageBoxEx(GetActiveWindow(),"Error Opening the config dialog.","OMG ERROR!",MB_OK,0); - return; - } - } - - virtual bool Is51Out() const { return false; } - - s32 Test() const - { - if (waveOutGetNumDevs() == 0) { - SysMessage("No waveOut Devices Present\n"); return -1; - } - return 0; - } - - int GetEmptySampleCount() const - { - int result = 0; - for(int i=0;i +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#include "spu2.h" +#include "dialogs.h" +#include + + +class WaveOutModule: public SndOutModule +{ +private: +# define MAX_BUFFER_COUNT 8 + + static const int PacketsPerBuffer = (1024 / SndOutPacketSize); + static const int BufferSize = SndOutPacketSize*PacketsPerBuffer; + static const int BufferSizeBytes = BufferSize << 1; + + u32 numBuffers; + HWAVEOUT hwodevice; + WAVEFORMATEX wformat; + WAVEHDR whbuffer[MAX_BUFFER_COUNT]; + + s16* qbuffer; + + #define QBUFFER(x) (qbuffer + BufferSize * (x)) + + bool waveout_running; + HANDLE thread; + DWORD tid; + + SndBuffer *buff; + + FILE *voicelog; + + char ErrText[256]; + + static DWORD CALLBACK RThread(WaveOutModule*obj) + { + return obj->Thread(); + } + + DWORD CALLBACK Thread() + { + while( waveout_running ) + { + bool didsomething = false; + for(u32 i=0;idwBytesRecorded = buf->dwBufferLength; + + s16 *t = (s16*)buf->lpData; + for(int p=0; pReadSamples( t ); + + whbuffer[i].dwFlags&=~WHDR_DONE; + waveOutWrite(hwodevice,buf,sizeof(WAVEHDR)); + didsomething = true; + } + + if( didsomething ) + Sleep(1); + else + Sleep(0); + } + return 0; + } + +public: + s32 Init(SndBuffer *sb) + { + buff = sb; + numBuffers = Config_WaveOut.NumBuffers; + + MMRESULT woores; + + if (Test()) return -1; + + wformat.wFormatTag=WAVE_FORMAT_PCM; + wformat.nSamplesPerSec=SampleRate; + wformat.wBitsPerSample=16; + wformat.nChannels=2; + wformat.nBlockAlign=((wformat.wBitsPerSample * wformat.nChannels) / 8); + wformat.nAvgBytesPerSec=(wformat.nSamplesPerSec * wformat.nBlockAlign); + wformat.cbSize=0; + + qbuffer=new s16[BufferSize*numBuffers]; + + woores = waveOutOpen(&hwodevice,WAVE_MAPPER,&wformat,0,0,0); + if (woores != MMSYSERR_NOERROR) + { + waveOutGetErrorText(woores,(char *)&ErrText,255); + SysMessage("WaveOut Error: %s",ErrText); + return -1; + } + + for(u32 i=0;i MAX_BUFFER_COUNT ) Config_WaveOut.NumBuffers = MAX_BUFFER_COUNT; + } + EndDialog(hWnd,0); + break; + case IDCANCEL: + EndDialog(hWnd,0); + break; + default: + return FALSE; + } + break; + + case WM_HSCROLL: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + switch(wmId) { + //case TB_ENDTRACK: + //case TB_THUMBPOSITION: + case TB_LINEUP: + case TB_LINEDOWN: + case TB_PAGEUP: + case TB_PAGEDOWN: + wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0); + case TB_THUMBTRACK: + if( wmEvent < 3 ) wmEvent = 3; + if( wmEvent > MAX_BUFFER_COUNT ) wmEvent = MAX_BUFFER_COUNT; + SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent); + sprintf_s(temp,128,"%d (%d ms latency)",wmEvent, 1000 / (96000 / (wmEvent * BufferSize))); + SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp); + break; + default: + return FALSE; + } + break; + + default: + return FALSE; + } + return TRUE; + } + +public: + virtual void Configure(HWND parent) + { + INT_PTR ret; + ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_WAVEOUT),GetActiveWindow(),(DLGPROC)ConfigProc,1); + if(ret==-1) + { + MessageBoxEx(GetActiveWindow(),"Error Opening the config dialog.","OMG ERROR!",MB_OK,0); + return; + } + } + + virtual bool Is51Out() const { return false; } + + s32 Test() const + { + if (waveOutGetNumDevs() == 0) { + SysMessage("No waveOut Devices Present\n"); return -1; + } + return 0; + } + + int GetEmptySampleCount() const + { + int result = 0; + for(int i=0;i // MFC core and standard components -//#include // MFC extensions -#ifndef _AFX_NO_AFXCMN_SUPPORT -#include // MFC support for Windows Common Controls -#endif // _AFX_NO_AFXCMN_SUPPORT -//#include -#include -#include -#include -#include -#include - -#define countof(a) (sizeof(a)/sizeof(a[0])) - -#define EXPORT_C extern "C" __declspec(dllexport) void __stdcall -#define EXPORT_C_(type) extern "C" __declspec(dllexport) type __stdcall - -#ifndef RESTRICT - #ifdef __INTEL_COMPILER - #define RESTRICT restrict - #elif _MSC_VER >= 1400 - #define RESTRICT __restrict - #else - #define RESTRICT - #endif -#endif - -#pragma warning(disable : 4995 4324 4100) - +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently + +#pragma once + +#pragma warning(disable: 4996) + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers +#endif + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef WINVER // Allow use of features specific to Windows 95 and Windows NT 4 or later. +#define WINVER 0x0510 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later. +#endif + +#ifndef _WIN32_WINNT // Allow use of features specific to Windows NT 4 or later. +#define _WIN32_WINNT 0x0400 // Change this to the appropriate value to target Windows 2000 or later. +#endif + +#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later. +#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. +#endif + +#ifndef _WIN32_IE // Allow use of features specific to IE 4.0 or later. +#define _WIN32_IE 0x0400 // Change this to the appropriate value to target IE 5.0 or later. +#endif + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit + +#include // MFC core and standard components +//#include // MFC extensions +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT +//#include +#include +#include +#include +#include +#include + +#define countof(a) (sizeof(a)/sizeof(a[0])) + +#define EXPORT_C extern "C" __declspec(dllexport) void __stdcall +#define EXPORT_C_(type) extern "C" __declspec(dllexport) type __stdcall + +#ifndef RESTRICT + #ifdef __INTEL_COMPILER + #define RESTRICT restrict + #elif _MSC_VER >= 1400 + #define RESTRICT __restrict + #else + #define RESTRICT + #endif +#endif + +#pragma warning(disable : 4995 4324 4100) + diff --git a/plugins/xpad/svnrev_template.h b/plugins/xpad/svnrev_template.h index 678f7916d3..c8806d96ae 100644 --- a/plugins/xpad/svnrev_template.h +++ b/plugins/xpad/svnrev_template.h @@ -1,2 +1,2 @@ -#define SVN_REV $WCREV$ +#define SVN_REV $WCREV$ #define SVN_MODS $WCMODS?1:0$ \ No newline at end of file diff --git a/plugins/xpad/xpad.cpp b/plugins/xpad/xpad.cpp index ebcacac212..16979faf86 100644 --- a/plugins/xpad/xpad.cpp +++ b/plugins/xpad/xpad.cpp @@ -1,649 +1,649 @@ -/* - * Copyright (C) 2007 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "stdafx.h" -#include "xpad.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#endif - -// -// Note! -// -// If this DLL is dynamically linked against the MFC -// DLLs, any functions exported from this DLL which -// call into MFC must have the AFX_MANAGE_STATE macro -// added at the very beginning of the function. -// -// For example: -// -// extern "C" BOOL PASCAL EXPORT ExportedFunction() -// { -// AFX_MANAGE_STATE(AfxGetStaticModuleState()); -// // normal function body here -// } -// -// It is very important that this macro appear in each -// function, prior to any calls into MFC. This means that -// it must appear as the first statement within the -// function, even before any object variable declarations -// as their constructors may generate calls into the MFC -// DLL. -// -// Please see MFC Technical Notes 33 and 58 for additional -// details. -// - -BEGIN_MESSAGE_MAP(xpadApp, CWinApp) -END_MESSAGE_MAP() - -xpadApp::xpadApp() -{ -} - -xpadApp theApp; - -BOOL xpadApp::InitInstance() -{ - __super::InitInstance(); - - SetRegistryKey(_T("Gabest")); - - return TRUE; -} - -// - -#define PS2E_LT_PAD 0x02 -#define PS2E_PAD_VERSION 0x0002 - -EXPORT_C_(UINT32) PS2EgetLibType() -{ - return PS2E_LT_PAD; -} - -EXPORT_C_(char*) PS2EgetLibName() -{ - return "XPad"; -} - -EXPORT_C_(UINT32) PS2EgetLibVersion2(UINT32 type) -{ - const UINT32 revision = 0; - const UINT32 build = 1; - const UINT32 minor = 0; - - return (build << 0) | (revision << 8) | (PS2E_PAD_VERSION << 16) | (minor << 24); -} - -// - -struct XPadButton -{ - enum - { - Select = 0x0001, - L3 = 0x0002, - R3 = 0x0004, - Start = 0x0008, - Up = 0x0010, - Right = 0x0020, - Down = 0x0040, - Left = 0x0080, - L2 = 0x0100, - R2 = 0x0200, - L1 = 0x0400, - R1 = 0x0800, - Triangle = 0x1000, - Circle = 0x2000, - Cross = 0x4000, - Square = 0x8000, - }; -}; - -class XPad -{ -public: - int m_pad; - bool m_connected; - bool m_ds2native; - bool m_analog; - bool m_locked; - bool m_vibration; - BYTE m_small; - BYTE m_large; - WORD m_buttons; - struct {BYTE x, y;} m_left; - struct {BYTE x, y;} m_right; - - void SetButton(WORD buttons, WORD mask, int flag) - { - if(buttons & mask) - { - m_buttons &= ~flag; - } - else - { - m_buttons |= flag; - } - } - - void SetAnalog(short src, BYTE& dst, short deadzone) - { - if(abs(src) < deadzone) src = 0; - - dst = (src >> 8) + 128; - } - -public: - XPad(int pad) - : m_pad(pad) - , m_connected(false) - , m_ds2native(false) - , m_analog(false) - , m_locked(false) - , m_vibration(true) - , m_small(0) - , m_large(0) - , m_buttons(0xffff) - { - } - - virtual ~XPad() - { - } - - BYTE GetId() - { - return m_analog ? (m_ds2native ? 0x79 : 0x73) : 0x41; - } - - BYTE ReadData(int index) - { - if(index == 0) - { - XINPUT_STATE state; - - memset(&state, 0, sizeof(state)); - - m_connected = SUCCEEDED(XInputGetState(m_pad, &state)); - - if(m_connected) - { - SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_BACK, XPadButton::Select); - SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_THUMB, XPadButton::L3); - SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_RIGHT_THUMB, XPadButton::R3); - SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_START, XPadButton::Start); - SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_UP, XPadButton::Up); - SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_RIGHT, XPadButton::Right); - SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_DOWN, XPadButton::Down); - SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_LEFT, XPadButton::Left); - SetButton(state.Gamepad.bLeftTrigger, 0xe0, XPadButton::L2); - SetButton(state.Gamepad.bRightTrigger, 0xe0, XPadButton::R2); - SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_SHOULDER, XPadButton::L1); - SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_RIGHT_SHOULDER, XPadButton::R1); - SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_Y, XPadButton::Triangle); - SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_B, XPadButton::Circle); - SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_A, XPadButton::Cross); - SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_X, XPadButton::Square); - - SetAnalog(state.Gamepad.sThumbLX, m_left.x, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); - SetAnalog(~state.Gamepad.sThumbLY, m_left.y, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); - SetAnalog(state.Gamepad.sThumbRX, m_right.x, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); - SetAnalog(~state.Gamepad.sThumbRY, m_right.y, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); - } - else - { - m_buttons = 0xffff; - m_left.x = 128; - m_left.y = 128; - m_right.x = 128; - m_right.y = 128; - } - } - - if(index == 1) - { - if(m_connected) - { - XINPUT_VIBRATION vibraton; - - memset(&vibraton, 0, sizeof(vibraton)); - - if(m_vibration && (m_small || m_large)) - { - vibraton.wLeftMotorSpeed = m_large << 8; - vibraton.wRightMotorSpeed = m_small << 8; - } - - XInputSetState(m_pad, &vibraton); - } - } - - switch(index) - { - case 0: - return (BYTE)(m_buttons & 0xff); - case 1: - return (BYTE)(m_buttons >> 8); - case 2: - return m_right.x; - case 3: - return m_right.y; - case 4: - return m_left.x; - case 5: - return m_left.y; - } - - return 0xff; - } -}; - -static class XPadPlugin -{ - CAtlArray m_pads; - XPad* m_pad; - int m_index; - bool m_cfgreaddata; - BYTE m_unknown1; - BYTE m_unknown3; - - typedef BYTE (XPadPlugin::*CommandHandler)(int, BYTE); - - CommandHandler m_handlers[256]; - CommandHandler m_handler; - - BYTE DS2Enabler(int index, BYTE value) - { - switch(index) - { - case 2: - return 0x02; - case 5: - return 'Z'; - } - - return 0; - } - - BYTE QueryDS2AnalogMode(int index, BYTE value) - { - if(m_pad->m_ds2native) - { - switch(index) - { - case 0: - return 0xff; - case 1: - return 0xff; - case 2: - return 3; - case 3: - return 0; - case 4: - return 0; - case 5: - return 'Z'; - } - } - - return 0; - } - - BYTE ReadDataAndVibrate(int index, BYTE value) - { - switch(index) - { - case 0: - m_pad->m_small = value == 1 ? 128 : 0; // RE4 map menu, value = 2 - break; - case 1: - m_pad->m_large = value; - break; - } - - return m_pad->ReadData(index); - } - - BYTE ConfigMode(int index, BYTE value) - { - switch(index) - { - case 0: - switch(value) - { - case 0: - m_cfgreaddata = false; - break; - case 1: - m_cfgreaddata = true; - break; - } - break; - } - - if(m_cfgreaddata) - { - return m_pad->ReadData(index); - } - - return 0; - } - - BYTE SetModeAndLock(int index, BYTE value) - { - switch(index) - { - case 0: - // if(!m_pad->m_locked) ? - m_pad->m_analog = value == 1; - break; - case 1: - m_pad->m_locked = value == 3; - break; - } - - return 0; - } - - BYTE QueryModelAndMode(int index, BYTE value) - { - switch(index) - { - case 0: - return 3; - case 1: - return 2; - case 2: - return m_pad->m_analog ? 1 : 0; - case 3: - return m_pad->m_ds2native ? 1 : 2; - case 4: - return 1; - } - - return 0; - } - - BYTE QueryUnknown1(int index, BYTE value) - { - switch(index) - { - case 0: - m_unknown1 = value; - return 0; - case 1: - return 0; - case 2: - return 1; - case 3: - return m_unknown1 ? 0x01 : 0x02; - case 4: - return m_unknown1 ? 0x01 : 0x00; - case 5: - return m_unknown1 ? 0x14 : 0x0a; - } - - return 0; - } - - BYTE QueryUnknown2(int index, BYTE value) - { - switch(index) - { - case 2: - return 2; - case 4: - return 1; - } - - return 0; - } - - BYTE QueryUnknown3(int index, BYTE value) - { - switch(index) - { - case 0: - m_unknown3 = value; - return 0; - case 3: - return m_unknown3 ? 0x07 : 0x04; - } - - return 0; - } - - BYTE ConfigVibration(int index, BYTE value) - { - switch(index) - { - case 0: - return value; - case 1: - m_pad->m_vibration = value == 1; - return value; - } - - return 0xff; - } - - BYTE SetDS2NativeMode(int index, BYTE value) - { - switch(index) - { - case 5: - m_pad->m_ds2native = true; - return 'Z'; - } - - return 0; - } - - BYTE m_cmd; - - BYTE UnknownCommand(int index, BYTE value) - { - TRACE(_T("Unknown command %02x (%d, %02x)\n"), m_cmd, index, value); - - return 0; - } - -public: - - XPadPlugin() - : m_pad(NULL) - , m_index(-1) - , m_cfgreaddata(false) - , m_handler(NULL) - { - m_pads.Add(new XPad(0)); - m_pads.Add(new XPad(1)); - - for(int i = 0; i < countof(m_handlers); i++) - { - m_handlers[i] = &XPadPlugin::UnknownCommand; - } - - m_handlers['@'] = &XPadPlugin::DS2Enabler; - m_handlers['A'] = &XPadPlugin::QueryDS2AnalogMode; - m_handlers['B'] = &XPadPlugin::ReadDataAndVibrate; - m_handlers['C'] = &XPadPlugin::ConfigMode; - m_handlers['D'] = &XPadPlugin::SetModeAndLock; - m_handlers['E'] = &XPadPlugin::QueryModelAndMode; - m_handlers['F'] = &XPadPlugin::QueryUnknown1; - m_handlers['G'] = &XPadPlugin::QueryUnknown2; - m_handlers['L'] = &XPadPlugin::QueryUnknown3; - m_handlers['M'] = &XPadPlugin::ConfigVibration; - m_handlers['O'] = &XPadPlugin::SetDS2NativeMode; - } - - void StartPoll(int pad) - { - m_pad = m_pads[pad & 1]; - m_index = 0; - } - - BYTE Poll(BYTE value) - { - BYTE ret = 0; - - switch(++m_index) - { - case 1: - m_cmd = value; - m_handler = m_handlers[value]; - ret = (value == 'B' || value == 'C') ? m_pad->GetId() : 0xf3; - break; - case 2: - ASSERT(value == 0); - ret = 'Z'; - break; - default: - ret = (this->*m_handler)(m_index - 3, value); - break; - } -/* -//if(m_cmd != 'B') -{ -static FILE* log = NULL; -if(log == NULL) -{ - log = fopen("c:\\log.txt", "w"); -} -if(m_index == 1) fprintf(log, "\n"); -fprintf(log, "*** %02x %d %02x %02x\n", m_cmd, m_index - 1, value, ret); -fflush(log); -} -*/ - return ret; - } - -} s_padplugin; - -// - -static int s_nRefs = 0; -static HWND s_hWnd = NULL; -static WNDPROC s_GSWndProc = NULL; -static KeyEvent s_event = {0, 0}; - -LRESULT WINAPI PADwndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch(msg) - { - case WM_KEYDOWN: - if(lParam & 0x40000000) return TRUE; - s_event.event = KEYPRESS; - s_event.key = wParam; - return TRUE; - case WM_KEYUP: - s_event.event = KEYRELEASE; - s_event.key = wParam; - return TRUE; - case WM_DESTROY: - case WM_QUIT: - s_event.event = KEYPRESS; - s_event.key = VK_ESCAPE; - break; - } - - return s_GSWndProc(hWnd, msg, wParam, lParam); -} - -// - -EXPORT_C_(UINT32) PADinit(UINT32 flags) -{ - return 0; -} - -EXPORT_C PADshutdown() -{ -} - -EXPORT_C_(UINT32) PADopen(void* pDsp) -{ - XInputEnable(TRUE); - - if(s_nRefs == 0) - { - s_hWnd = *(HWND*)pDsp; - s_GSWndProc = (WNDPROC)SetWindowLongPtr(s_hWnd, GWLP_WNDPROC, (LPARAM)PADwndProc); - } - - s_nRefs++; - - return 0; -} - -EXPORT_C PADclose() -{ - s_nRefs--; - - if(s_nRefs == 0) - { - SetWindowLongPtr(s_hWnd, GWLP_WNDPROC, (LPARAM)s_GSWndProc); - } - - XInputEnable(FALSE); -} - -EXPORT_C_(UINT32) CALLBACK PADquery() -{ - return 3; -} - -EXPORT_C_(BYTE) PADstartPoll(int pad) -{ - s_padplugin.StartPoll(pad - 1); - - return 0xff; -} - -EXPORT_C_(BYTE) PADpoll(BYTE value) -{ - return s_padplugin.Poll(value); -} - -EXPORT_C_(KeyEvent*) PADkeyEvent() -{ - static KeyEvent event; - event = s_event; - s_event.event = 0; - return &event; -} - -EXPORT_C PADconfigure() -{ -} - -EXPORT_C PADabout() -{ -} - -EXPORT_C_(UINT32) PADtest() -{ - return 0; -} - +/* + * Copyright (C) 2007 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "xpad.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + +// +// Note! +// +// If this DLL is dynamically linked against the MFC +// DLLs, any functions exported from this DLL which +// call into MFC must have the AFX_MANAGE_STATE macro +// added at the very beginning of the function. +// +// For example: +// +// extern "C" BOOL PASCAL EXPORT ExportedFunction() +// { +// AFX_MANAGE_STATE(AfxGetStaticModuleState()); +// // normal function body here +// } +// +// It is very important that this macro appear in each +// function, prior to any calls into MFC. This means that +// it must appear as the first statement within the +// function, even before any object variable declarations +// as their constructors may generate calls into the MFC +// DLL. +// +// Please see MFC Technical Notes 33 and 58 for additional +// details. +// + +BEGIN_MESSAGE_MAP(xpadApp, CWinApp) +END_MESSAGE_MAP() + +xpadApp::xpadApp() +{ +} + +xpadApp theApp; + +BOOL xpadApp::InitInstance() +{ + __super::InitInstance(); + + SetRegistryKey(_T("Gabest")); + + return TRUE; +} + +// + +#define PS2E_LT_PAD 0x02 +#define PS2E_PAD_VERSION 0x0002 + +EXPORT_C_(UINT32) PS2EgetLibType() +{ + return PS2E_LT_PAD; +} + +EXPORT_C_(char*) PS2EgetLibName() +{ + return "XPad"; +} + +EXPORT_C_(UINT32) PS2EgetLibVersion2(UINT32 type) +{ + const UINT32 revision = 0; + const UINT32 build = 1; + const UINT32 minor = 0; + + return (build << 0) | (revision << 8) | (PS2E_PAD_VERSION << 16) | (minor << 24); +} + +// + +struct XPadButton +{ + enum + { + Select = 0x0001, + L3 = 0x0002, + R3 = 0x0004, + Start = 0x0008, + Up = 0x0010, + Right = 0x0020, + Down = 0x0040, + Left = 0x0080, + L2 = 0x0100, + R2 = 0x0200, + L1 = 0x0400, + R1 = 0x0800, + Triangle = 0x1000, + Circle = 0x2000, + Cross = 0x4000, + Square = 0x8000, + }; +}; + +class XPad +{ +public: + int m_pad; + bool m_connected; + bool m_ds2native; + bool m_analog; + bool m_locked; + bool m_vibration; + BYTE m_small; + BYTE m_large; + WORD m_buttons; + struct {BYTE x, y;} m_left; + struct {BYTE x, y;} m_right; + + void SetButton(WORD buttons, WORD mask, int flag) + { + if(buttons & mask) + { + m_buttons &= ~flag; + } + else + { + m_buttons |= flag; + } + } + + void SetAnalog(short src, BYTE& dst, short deadzone) + { + if(abs(src) < deadzone) src = 0; + + dst = (src >> 8) + 128; + } + +public: + XPad(int pad) + : m_pad(pad) + , m_connected(false) + , m_ds2native(false) + , m_analog(false) + , m_locked(false) + , m_vibration(true) + , m_small(0) + , m_large(0) + , m_buttons(0xffff) + { + } + + virtual ~XPad() + { + } + + BYTE GetId() + { + return m_analog ? (m_ds2native ? 0x79 : 0x73) : 0x41; + } + + BYTE ReadData(int index) + { + if(index == 0) + { + XINPUT_STATE state; + + memset(&state, 0, sizeof(state)); + + m_connected = SUCCEEDED(XInputGetState(m_pad, &state)); + + if(m_connected) + { + SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_BACK, XPadButton::Select); + SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_THUMB, XPadButton::L3); + SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_RIGHT_THUMB, XPadButton::R3); + SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_START, XPadButton::Start); + SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_UP, XPadButton::Up); + SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_RIGHT, XPadButton::Right); + SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_DOWN, XPadButton::Down); + SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_LEFT, XPadButton::Left); + SetButton(state.Gamepad.bLeftTrigger, 0xe0, XPadButton::L2); + SetButton(state.Gamepad.bRightTrigger, 0xe0, XPadButton::R2); + SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_SHOULDER, XPadButton::L1); + SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_RIGHT_SHOULDER, XPadButton::R1); + SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_Y, XPadButton::Triangle); + SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_B, XPadButton::Circle); + SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_A, XPadButton::Cross); + SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_X, XPadButton::Square); + + SetAnalog(state.Gamepad.sThumbLX, m_left.x, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); + SetAnalog(~state.Gamepad.sThumbLY, m_left.y, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); + SetAnalog(state.Gamepad.sThumbRX, m_right.x, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); + SetAnalog(~state.Gamepad.sThumbRY, m_right.y, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); + } + else + { + m_buttons = 0xffff; + m_left.x = 128; + m_left.y = 128; + m_right.x = 128; + m_right.y = 128; + } + } + + if(index == 1) + { + if(m_connected) + { + XINPUT_VIBRATION vibraton; + + memset(&vibraton, 0, sizeof(vibraton)); + + if(m_vibration && (m_small || m_large)) + { + vibraton.wLeftMotorSpeed = m_large << 8; + vibraton.wRightMotorSpeed = m_small << 8; + } + + XInputSetState(m_pad, &vibraton); + } + } + + switch(index) + { + case 0: + return (BYTE)(m_buttons & 0xff); + case 1: + return (BYTE)(m_buttons >> 8); + case 2: + return m_right.x; + case 3: + return m_right.y; + case 4: + return m_left.x; + case 5: + return m_left.y; + } + + return 0xff; + } +}; + +static class XPadPlugin +{ + CAtlArray m_pads; + XPad* m_pad; + int m_index; + bool m_cfgreaddata; + BYTE m_unknown1; + BYTE m_unknown3; + + typedef BYTE (XPadPlugin::*CommandHandler)(int, BYTE); + + CommandHandler m_handlers[256]; + CommandHandler m_handler; + + BYTE DS2Enabler(int index, BYTE value) + { + switch(index) + { + case 2: + return 0x02; + case 5: + return 'Z'; + } + + return 0; + } + + BYTE QueryDS2AnalogMode(int index, BYTE value) + { + if(m_pad->m_ds2native) + { + switch(index) + { + case 0: + return 0xff; + case 1: + return 0xff; + case 2: + return 3; + case 3: + return 0; + case 4: + return 0; + case 5: + return 'Z'; + } + } + + return 0; + } + + BYTE ReadDataAndVibrate(int index, BYTE value) + { + switch(index) + { + case 0: + m_pad->m_small = value == 1 ? 128 : 0; // RE4 map menu, value = 2 + break; + case 1: + m_pad->m_large = value; + break; + } + + return m_pad->ReadData(index); + } + + BYTE ConfigMode(int index, BYTE value) + { + switch(index) + { + case 0: + switch(value) + { + case 0: + m_cfgreaddata = false; + break; + case 1: + m_cfgreaddata = true; + break; + } + break; + } + + if(m_cfgreaddata) + { + return m_pad->ReadData(index); + } + + return 0; + } + + BYTE SetModeAndLock(int index, BYTE value) + { + switch(index) + { + case 0: + // if(!m_pad->m_locked) ? + m_pad->m_analog = value == 1; + break; + case 1: + m_pad->m_locked = value == 3; + break; + } + + return 0; + } + + BYTE QueryModelAndMode(int index, BYTE value) + { + switch(index) + { + case 0: + return 3; + case 1: + return 2; + case 2: + return m_pad->m_analog ? 1 : 0; + case 3: + return m_pad->m_ds2native ? 1 : 2; + case 4: + return 1; + } + + return 0; + } + + BYTE QueryUnknown1(int index, BYTE value) + { + switch(index) + { + case 0: + m_unknown1 = value; + return 0; + case 1: + return 0; + case 2: + return 1; + case 3: + return m_unknown1 ? 0x01 : 0x02; + case 4: + return m_unknown1 ? 0x01 : 0x00; + case 5: + return m_unknown1 ? 0x14 : 0x0a; + } + + return 0; + } + + BYTE QueryUnknown2(int index, BYTE value) + { + switch(index) + { + case 2: + return 2; + case 4: + return 1; + } + + return 0; + } + + BYTE QueryUnknown3(int index, BYTE value) + { + switch(index) + { + case 0: + m_unknown3 = value; + return 0; + case 3: + return m_unknown3 ? 0x07 : 0x04; + } + + return 0; + } + + BYTE ConfigVibration(int index, BYTE value) + { + switch(index) + { + case 0: + return value; + case 1: + m_pad->m_vibration = value == 1; + return value; + } + + return 0xff; + } + + BYTE SetDS2NativeMode(int index, BYTE value) + { + switch(index) + { + case 5: + m_pad->m_ds2native = true; + return 'Z'; + } + + return 0; + } + + BYTE m_cmd; + + BYTE UnknownCommand(int index, BYTE value) + { + TRACE(_T("Unknown command %02x (%d, %02x)\n"), m_cmd, index, value); + + return 0; + } + +public: + + XPadPlugin() + : m_pad(NULL) + , m_index(-1) + , m_cfgreaddata(false) + , m_handler(NULL) + { + m_pads.Add(new XPad(0)); + m_pads.Add(new XPad(1)); + + for(int i = 0; i < countof(m_handlers); i++) + { + m_handlers[i] = &XPadPlugin::UnknownCommand; + } + + m_handlers['@'] = &XPadPlugin::DS2Enabler; + m_handlers['A'] = &XPadPlugin::QueryDS2AnalogMode; + m_handlers['B'] = &XPadPlugin::ReadDataAndVibrate; + m_handlers['C'] = &XPadPlugin::ConfigMode; + m_handlers['D'] = &XPadPlugin::SetModeAndLock; + m_handlers['E'] = &XPadPlugin::QueryModelAndMode; + m_handlers['F'] = &XPadPlugin::QueryUnknown1; + m_handlers['G'] = &XPadPlugin::QueryUnknown2; + m_handlers['L'] = &XPadPlugin::QueryUnknown3; + m_handlers['M'] = &XPadPlugin::ConfigVibration; + m_handlers['O'] = &XPadPlugin::SetDS2NativeMode; + } + + void StartPoll(int pad) + { + m_pad = m_pads[pad & 1]; + m_index = 0; + } + + BYTE Poll(BYTE value) + { + BYTE ret = 0; + + switch(++m_index) + { + case 1: + m_cmd = value; + m_handler = m_handlers[value]; + ret = (value == 'B' || value == 'C') ? m_pad->GetId() : 0xf3; + break; + case 2: + ASSERT(value == 0); + ret = 'Z'; + break; + default: + ret = (this->*m_handler)(m_index - 3, value); + break; + } +/* +//if(m_cmd != 'B') +{ +static FILE* log = NULL; +if(log == NULL) +{ + log = fopen("c:\\log.txt", "w"); +} +if(m_index == 1) fprintf(log, "\n"); +fprintf(log, "*** %02x %d %02x %02x\n", m_cmd, m_index - 1, value, ret); +fflush(log); +} +*/ + return ret; + } + +} s_padplugin; + +// + +static int s_nRefs = 0; +static HWND s_hWnd = NULL; +static WNDPROC s_GSWndProc = NULL; +static KeyEvent s_event = {0, 0}; + +LRESULT WINAPI PADwndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) + { + case WM_KEYDOWN: + if(lParam & 0x40000000) return TRUE; + s_event.event = KEYPRESS; + s_event.key = wParam; + return TRUE; + case WM_KEYUP: + s_event.event = KEYRELEASE; + s_event.key = wParam; + return TRUE; + case WM_DESTROY: + case WM_QUIT: + s_event.event = KEYPRESS; + s_event.key = VK_ESCAPE; + break; + } + + return s_GSWndProc(hWnd, msg, wParam, lParam); +} + +// + +EXPORT_C_(UINT32) PADinit(UINT32 flags) +{ + return 0; +} + +EXPORT_C PADshutdown() +{ +} + +EXPORT_C_(UINT32) PADopen(void* pDsp) +{ + XInputEnable(TRUE); + + if(s_nRefs == 0) + { + s_hWnd = *(HWND*)pDsp; + s_GSWndProc = (WNDPROC)SetWindowLongPtr(s_hWnd, GWLP_WNDPROC, (LPARAM)PADwndProc); + } + + s_nRefs++; + + return 0; +} + +EXPORT_C PADclose() +{ + s_nRefs--; + + if(s_nRefs == 0) + { + SetWindowLongPtr(s_hWnd, GWLP_WNDPROC, (LPARAM)s_GSWndProc); + } + + XInputEnable(FALSE); +} + +EXPORT_C_(UINT32) CALLBACK PADquery() +{ + return 3; +} + +EXPORT_C_(BYTE) PADstartPoll(int pad) +{ + s_padplugin.StartPoll(pad - 1); + + return 0xff; +} + +EXPORT_C_(BYTE) PADpoll(BYTE value) +{ + return s_padplugin.Poll(value); +} + +EXPORT_C_(KeyEvent*) PADkeyEvent() +{ + static KeyEvent event; + event = s_event; + s_event.event = 0; + return &event; +} + +EXPORT_C PADconfigure() +{ +} + +EXPORT_C PADabout() +{ +} + +EXPORT_C_(UINT32) PADtest() +{ + return 0; +} + diff --git a/plugins/xpad/xpad.h b/plugins/xpad/xpad.h index 56b0c072ea..e209581e6f 100644 --- a/plugins/xpad/xpad.h +++ b/plugins/xpad/xpad.h @@ -1,47 +1,47 @@ -/* - * Copyright (C) 2007 Gabest - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#pragma once - -#ifndef __AFXWIN_H__ - #error include 'stdafx.h' before including this file for PCH -#endif - -class xpadApp : public CWinApp -{ -public: - xpadApp(); - -public: - virtual BOOL InitInstance(); - - DECLARE_MESSAGE_MAP() -}; - -struct KeyEvent -{ - UINT32 key; - UINT32 event; -}; - -#define KEYPRESS 1 -#define KEYRELEASE 2 - +/* + * Copyright (C) 2007 Gabest + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +class xpadApp : public CWinApp +{ +public: + xpadApp(); + +public: + virtual BOOL InitInstance(); + + DECLARE_MESSAGE_MAP() +}; + +struct KeyEvent +{ + UINT32 key; + UINT32 event; +}; + +#define KEYPRESS 1 +#define KEYRELEASE 2 + diff --git a/plugins/zerogs/dx/GS.h b/plugins/zerogs/dx/GS.h index 38f350892f..871f6ff0de 100644 --- a/plugins/zerogs/dx/GS.h +++ b/plugins/zerogs/dx/GS.h @@ -1,749 +1,749 @@ -/* ZeroGS - * Copyright (C) 2005-2006 zerofrog@gmail.com - * - * 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 - */ - -#ifndef __GS_H__ -#define __GS_H__ - -#include -#include - -// need C definitions -extern "C" { -#define GSdefs -#include "PS2Edefs.h" -} - -#ifdef _WIN32 - -#include -#include - -extern HWND GShwnd; - -#else - -#include -#include -#include -#include - -#define __inline inline - -typedef int BOOL; - -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#define min(a,b) (((a) < (b)) ? (a) : (b)) - -#endif - -#if defined(_MSC_VER) -#define FASTCALL(fn) __fastcall fn -#else - -#ifdef __x86_64 -#define FASTCALL(fn) fn -#else -#define FASTCALL(fn) __attribute__((fastcall)) fn -#endif -#endif - -struct Vector_16F -{ - u16 x, y, z, w; -}; - - -///////////////////// -// define when releasing -// The only code that uses it is commented out! -//#define ZEROGS_CACHEDCLEAR // much better performance -//#define RELEASE_TO_PUBLIC - -#if defined(ZEROGS_DEVBUILD) -#define GS_LOG __Log -#else -#define GS_LOG 0&& -#endif - -#define ERROR_LOG __LogToConsole -#define DEBUG_LOG printf - -#ifdef RELEASE_TO_PUBLIC -#define WARN_LOG 0&& -#define PRIM_LOG 0&& -#else -#define WARN_LOG printf -#define PRIM_LOG if (conf.log & 0x00000010) GS_LOG -#endif - -#ifndef GREG_LOG -#define GREG_LOG 0&& -#endif -#ifndef PRIM_LOG -#define PRIM_LOG 0&& -#endif -#ifndef WARN_LOG -#define WARN_LOG 0&& -#endif - -#define REG64(name) \ -union name \ -{ \ - u64 i64; \ - u32 ai32[2]; \ - struct { \ - -#define REG128(name)\ -union name \ -{ \ - u64 ai64[2]; \ - u32 ai32[4]; \ - struct { \ - -#define REG64_(prefix, name) REG64(prefix##name) -#define REG128_(prefix, name) REG128(prefix##name) - -#define REG_END }; }; -#define REG_END2 }; - -#define REG64_SET(name) \ -union name \ -{ \ - u64 i64; \ - u32 ai32[2]; \ - -#define REG128_SET(name)\ -union name \ -{ \ - u64 ai64[2]; \ - u32 ai32[4]; \ - -#define REG_SET_END }; - -REG64_(GSReg, BGCOLOR) - u32 R:8; - u32 G:8; - u32 B:8; - u32 _PAD1:8; - u32 _PAD2:32; -REG_END - -REG64_(GSReg, BUSDIR) - u32 DIR:1; - u32 _PAD1:31; - u32 _PAD2:32; -REG_END - -REG64_(GSReg, CSR) - u32 SIGNAL:1; - u32 FINISH:1; - u32 HSINT:1; - u32 VSINT:1; - u32 EDWINT:1; - u32 ZERO1:1; - u32 ZERO2:1; - u32 _PAD1:1; - u32 FLUSH:1; - u32 RESET:1; - u32 _PAD2:2; - u32 NFIELD:1; - u32 FIELD:1; - u32 FIFO:2; - u32 REV:8; - u32 ID:8; - u32 _PAD3:32; -REG_END - -REG64_(GSReg, DISPFB) // (-1/2) - u32 FBP:9; - u32 FBW:6; - u32 PSM:5; - u32 _PAD:12; - u32 DBX:11; - u32 DBY:11; - u32 _PAD2:10; -REG_END - -REG64_(GSReg, DISPLAY) // (-1/2) - u32 DX:12; - u32 DY:11; - u32 MAGH:4; - u32 MAGV:2; - u32 _PAD:3; - u32 DW:12; - u32 DH:11; - u32 _PAD2:9; -REG_END - -REG64_(GSReg, EXTBUF) - u32 EXBP:14; - u32 EXBW:6; - u32 FBIN:2; - u32 WFFMD:1; - u32 EMODA:2; - u32 EMODC:2; - u32 _PAD1:5; - u32 WDX:11; - u32 WDY:11; - u32 _PAD2:10; -REG_END - -REG64_(GSReg, EXTDATA) - u32 SX:12; - u32 SY:11; - u32 SMPH:4; - u32 SMPV:2; - u32 _PAD1:3; - u32 WW:12; - u32 WH:11; - u32 _PAD2:9; -REG_END - -REG64_(GSReg, EXTWRITE) - u32 WRITE; - u32 _PAD2:32; -REG_END - -REG64_(GSReg, IMR) - u32 _PAD1:8; - u32 SIGMSK:1; - u32 FINISHMSK:1; - u32 HSMSK:1; - u32 VSMSK:1; - u32 EDWMSK:1; - u32 _PAD2:19; - u32 _PAD3:32; -REG_END - -REG64_(GSReg, PMODE) - u32 EN1:1; - u32 EN2:1; - u32 CRTMD:3; - u32 MMOD:1; - u32 AMOD:1; - u32 SLBG:1; - u32 ALP:8; - u32 _PAD:16; - u32 _PAD1:32; -REG_END - -REG64_(GSReg, SIGLBLID) - u32 SIGID:32; - u32 LBLID:32; -REG_END - -REG64_(GSReg, SMODE1) - u32 RC:3; - u32 LC:7; - u32 T1248:2; - u32 SLCK:1; - u32 CMOD:2; - u32 EX:1; - u32 PRST:1; - u32 SINT:1; - u32 XPCK:1; - u32 PCK2:2; - u32 SPML:4; - u32 GCONT:1; - u32 PHS:1; - u32 PVS:1; - u32 PEHS:1; - u32 PEVS:1; - u32 CLKSEL:2; - u32 NVCK:1; - u32 SLCK2:1; - u32 VCKSEL:2; - u32 VHP:1; - u32 _PAD1:27; -REG_END - -REG64_(GSReg, SMODE2) - u32 INT:1; - u32 FFMD:1; - u32 DPMS:2; - u32 _PAD2:28; - u32 _PAD3:32; -REG_END - -REG64_(GSReg, SIGBLID) - u32 SIGID; - u32 LBLID; -REG_END - -extern int g_LastCRC; -extern u8* g_pBasePS2Mem; -#define PMODE ((GSRegPMODE*)(g_pBasePS2Mem+0x0000)) -#define SMODE1 ((GSRegSMODE1*)(g_pBasePS2Mem+0x0010)) -#define SMODE2 ((GSRegSMODE2*)(g_pBasePS2Mem+0x0020)) -// SRFSH -#define SYNCH1 ((GSRegSYNCH1*)(g_pBasePS2Mem+0x0040)) -#define SYNCH2 ((GSRegSYNCH2*)(g_pBasePS2Mem+0x0050)) -#define SYNCV ((GSRegSYNCV*)(g_pBasePS2Mem+0x0060)) -#define DISPFB1 ((GSRegDISPFB*)(g_pBasePS2Mem+0x0070)) -#define DISPLAY1 ((GSRegDISPLAY*)(g_pBasePS2Mem+0x0080)) -#define DISPFB2 ((GSRegDISPFB*)(g_pBasePS2Mem+0x0090)) -#define DISPLAY2 ((GSRegDISPLAY*)(g_pBasePS2Mem+0x00a0)) -#define EXTBUF ((GSRegEXTBUF*)(g_pBasePS2Mem+0x00b0)) -#define EXTDATA ((GSRegEXTDATA*)(g_pBasePS2Mem+0x00c0)) -#define EXTWRITE ((GSRegEXTWRITE*)(g_pBasePS2Mem+0x00d0)) -#define BGCOLOR ((GSRegBGCOLOR*)(g_pBasePS2Mem+0x00e0)) -#define CSR ((GSRegCSR*)(g_pBasePS2Mem+0x1000)) -#define IMR ((GSRegIMR*)(g_pBasePS2Mem+0x1010)) -#define BUSDIR ((GSRegBUSDIR*)(g_pBasePS2Mem+0x1040)) -#define SIGLBLID ((GSRegSIGBLID*)(g_pBasePS2Mem+0x1080)) - -#define GET_GSFPS (((SMODE1->CMOD&1) ? 50 : 60) / (SMODE2->INT ? 1 : 2)) - -// -// sps2tags.h -// -#ifdef _M_AMD64 -#define GET_GIF_REG(tag, reg) \ - (((tag).ai64[1] >> ((reg) << 2)) & 0xf) -#else -#define GET_GIF_REG(tag, reg) \ - (((tag).ai32[2 + ((reg) >> 3)] >> (((reg) & 7) << 2)) & 0xf) -#endif - -// -// GIFTag -REG128(GIFTag) - u32 NLOOP:15; - u32 EOP:1; - u32 _PAD1:16; - u32 _PAD2:14; - u32 PRE:1; - u32 PRIM:11; - u32 FLG:2; // enum GIF_FLG - u32 NREG:4; - u64 REGS:64; -REG_END - -typedef struct { - int x, y, w, h; -} Rect; - -typedef struct { - int x, y; -} Point; - -typedef struct { - int x0, y0; - int x1, y1; -} Rect2; - -typedef struct { - int x, y, c; -} PointC; - -#define GSOPTION_FULLSCREEN 0x2 -#define GSOPTION_BMPSNAP 0x4 -#define GSOPTION_CAPTUREAVI 0x8 - -#define GSOPTION_WINDIMS 0x70 -#define GSOPTION_WIN640 0x00 -#define GSOPTION_WIN800 0x10 -#define GSOPTION_WIN1024 0x20 -#define GSOPTION_WIN1280 0x30 -#define GSOPTION_WIN960W 0x40 -#define GSOPTION_WIN1280W 0x50 -#define GSOPTION_WIN1920W 0x60 - -#define GSOPTION_WIREFRAME 0x100 -#define GSOPTION_WIDESCREEN 0x200 -#define GSOPTION_LOADED 0x8000 - -typedef struct { - u8 mrtdepth; // write color in render target - u8 interlace; - u8 aa; // antialiasing 0 - off, 1 - 2x, 2 - 4x - u8 bilinear; // set to enable bilinear support - u32 options; - u32 gamesettings; // default game settings - int width, height; - int winstyle; // window style before full screen -#ifdef GS_LOG - u32 log; -#endif -} GSconf; - -#define VERTEXGPU \ - union \ - { \ - struct \ - { \ - u16 x, y, f, resv0; /* note: xy is 12d3*/ \ - u32 rgba; \ - u32 z; \ - }; \ - }; \ - \ - float s, t, q; \ - -typedef struct { - s16 x, y, f, resv0; /* note: xy is 12d3*/ \ - u32 rgba; - u32 z; - float s, t, q; -} VertexGPU; - -typedef struct { - VERTEXGPU - u16 u, v; -} Vertex; - -extern int g_GameSettings; -extern GSconf conf; -extern int ppf; - -#define PSMCT32 0 -#define PSMCT24 1 -#define PSMCT16 2 -#define PSMCT16S 10 -#define PSMT8 19 -#define PSMT4 20 -#define PSMT8H 27 -#define PSMT4HL 36 -#define PSMT4HH 44 -#define PSMT32Z 48 -#define PSMT24Z 49 -#define PSMT16Z 50 -#define PSMT16SZ 58 - -#define PSMT_ISCLUT(psm) (((psm)&0x7)>2) -#define PSMT_IS16BIT(psm) (((psm)&7)==2||((psm)&7)==10) - -typedef struct { - int nloop; - int eop; - int nreg; -} tagInfo; - -typedef union { - s64 SD; - u64 UD; - s32 SL[2]; - u32 UL[2]; - s16 SS[4]; - u16 US[4]; - s8 SC[8]; - u8 UC[8]; -} reg64; - -/* general purpose regs structs */ -typedef struct { - int fbp; - int fbw; - int fbh; - int psm; - u32 fbm; -} frameInfo; - -typedef struct { - u16 prim; - - union { - struct { - u16 iip : 1; - u16 tme : 1; - u16 fge : 1; - u16 abe : 1; - u16 aa1 : 1; - u16 fst : 1; - u16 ctxt : 1; - u16 fix : 1; - u16 resv : 8; - }; - u16 _val; - }; -} primInfo; - -extern primInfo *prim; - -typedef union { - struct { - u32 ate : 1; - u32 atst : 3; - u32 aref : 8; - u32 afail : 2; - u32 date : 1; - u32 datm : 1; - u32 zte : 1; - u32 ztst : 2; - u32 resv : 13; - }; - u32 _val; -} pixTest; - -typedef struct { - int bp; - int bw; - int psm; -} bufInfo; - -typedef struct { - int tbp0; - int tbw; - int cbp; - u16 tw, th; - u8 psm; - u8 tcc; - u8 tfx; - u8 cpsm; - u8 csm; - u8 csa; - u8 cld; -} tex0Info; - -#define TEX_MODULATE 0 -#define TEX_DECAL 1 -#define TEX_HIGHLIGHT 2 -#define TEX_HIGHLIGHT2 3 - -typedef struct { - int lcm; - int mxl; - int mmag; - int mmin; - int mtba; - int l; - int k; -} tex1Info; - -typedef struct { - int wms; - int wmt; - int minu; - int maxu; - int minv; - int maxv; -} clampInfo; - -typedef struct { - int cbw; - int cou; - int cov; -} clutInfo; - -typedef struct { - int tbp[3]; - int tbw[3]; -} miptbpInfo; - -typedef struct { - u16 aem; - u8 ta[2]; - float fta[2]; -} texaInfo; - -typedef struct { - int sx; - int sy; - int dx; - int dy; - int dir; -} trxposInfo; - -typedef struct { - union { - struct { - u8 a : 2; - u8 b : 2; - u8 c : 2; - u8 d : 2; - }; - u8 abcd; - }; - - u8 fix : 8; -} alphaInfo; - -typedef struct { - u16 zbp; // word address / 64 - u8 psm; - u8 zmsk; -} zbufInfo; - -typedef struct { - int fba; -} fbaInfo; - -typedef struct { - int mode; - int regn; - u64 regs; - tagInfo tag; -} pathInfo; - -typedef struct { - Vertex gsvertex[3]; - u32 rgba; - float q; - Vertex vertexregs; - - int primC; // number of verts current storing - int primIndex; // current prim index - int nTriFanVert; - - int prac; - int dthe; - int colclamp; - int fogcol; - int smask; - int pabe; - u64 buff[2]; - int buffsize; - int cbp[2]; // internal cbp registers - - u32 CSRw; - - primInfo _prim[2]; - bufInfo srcbuf, srcbufnew; - bufInfo dstbuf, dstbufnew; - - clutInfo clut; - - texaInfo texa; - trxposInfo trxpos, trxposnew; - - int imageWtemp, imageHtemp; - - int imageTransfer; - int imageWnew, imageHnew, imageX, imageY, imageEndX, imageEndY; - - pathInfo path1; - pathInfo path2; - pathInfo path3; - -} GSinternal; - -extern GSinternal gs; - -extern FILE *gsLog; - -void __Log(const char *fmt, ...); -void __LogToConsole(const char *fmt, ...); - -void LoadConfig(); -void SaveConfig(); - -extern void (*GSirq)(); - -void *SysLoadLibrary(char *lib); // Loads Library -void *SysLoadSym(void *lib, char *sym); // Loads Symbol from Library -char *SysLibError(); // Gets previous error loading sysbols -void SysCloseLibrary(void *lib); // Closes Library -void SysMessage(char *fmt, ...); - -extern "C" void * memcpy_amd(void *dest, const void *src, size_t n); -extern "C" u8 memcmp_mmx(const void *dest, const void *src, int n); - -template -class CInterfacePtr -{ -public: - inline CInterfacePtr() : ptr(NULL) {} - inline explicit CInterfacePtr(T* newptr) : ptr(newptr) { if ( ptr != NULL ) ptr->AddRef(); } - inline ~CInterfacePtr() { if( ptr != NULL ) ptr->Release(); } - - inline T* operator* () { assert( ptr != NULL); return *ptr; } - inline T* operator->() { return ptr; } - inline T* get() { return ptr; } - - inline void release() { - if( ptr != NULL ) { ptr->Release(); ptr = NULL; } - } - - inline operator T*() { return ptr; } - - inline bool operator==(T* rhs) { return ptr == rhs; } - inline bool operator!=(T* rhs) { return ptr != rhs; } - - inline CInterfacePtr& operator= (T* newptr) { - if( ptr != NULL ) ptr->Release(); - ptr = newptr; - - if( ptr != NULL ) ptr->AddRef(); - return *this; - } - -private: - T* ptr; -}; - -#define RGBA32to16(c) \ - (u16)((((c) & 0x000000f8) >> 3) | \ - (((c) & 0x0000f800) >> 6) | \ - (((c) & 0x00f80000) >> 9) | \ - (((c) & 0x80000000) >> 16)) \ - -#define RGBA16to32(c) \ - (((c) & 0x001f) << 3) | \ - (((c) & 0x03e0) << 6) | \ - (((c) & 0x7c00) << 9) | \ - (((c) & 0x8000) ? 0xff000000 : 0) \ - -// converts float16 [0,1] to BYTE [0,255] (assumes value is in range, otherwise will take lower 8bits) -// f is a u16 -__forceinline u16 Float16ToBYTE(u16 f) { - //assert( !(f & 0x8000) ); - if( f & 0x8000 ) return 0; - - u16 d = ((((f&0x3ff)|0x400)*255)>>(10-((f>>10)&0x1f)+15)); - return d > 255 ? 255 : d; -} - -__forceinline u16 Float16ToALPHA(u16 f) { - //assert( !(f & 0x8000) ); - if( f & 0x8000 ) return 0; - - // round up instead of down (crash and burn), too much and charlie breaks - u16 d = (((((f&0x3ff)|0x400))*255)>>(10-((f>>10)&0x1f)+15)); - d = (d)>>1; - return d > 255 ? 255 : d; -} - -#ifndef COLOR_ARGB -#define COLOR_ARGB(a,r,g,b) \ - ((u32)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff))) -#endif - -// assumes that positive in [1,2] (then extracts fraction by just looking at the specified bits) -#define Float16ToBYTE_2(f) ((u8)(*(u16*)&f>>2)) -#define Float16To5BIT(f) (Float16ToBYTE(f)>>3) - -#define Float16Alpha(f) (((*(u16*)&f&0x7c00)>=0x3900)?0x8000:0) // alpha is >= 1 - -// converts an array of 4 u16s to a u32 color -// f is a pointer to a u16 -#define Float16ToARGB(f) COLOR_ARGB(Float16ToALPHA(f.w), Float16ToBYTE(f.x), Float16ToBYTE(f.y), Float16ToBYTE(f.z)); - -#define Float16ToARGB16(f) (Float16Alpha(f.w)|(Float16To5BIT(f.x)<<10)|(Float16To5BIT(f.y)<<5)|Float16To5BIT(f.z)) - -// used for Z values -#define Float16ToARGB_Z(f) COLOR_ARGB((u32)Float16ToBYTE_2(f.w), Float16ToBYTE_2(f.x), Float16ToBYTE_2(f.y), Float16ToBYTE_2(f.z)) -#define Float16ToARGB16_Z(f) ((Float16ToBYTE_2(f.y)<<8)|Float16ToBYTE_2(f.z)) - - -inline float Clamp(float fx, float fmin, float fmax) -{ - if( fx < fmin ) return fmin; - return fx > fmax ? fmax : fx; -} - -#endif +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#ifndef __GS_H__ +#define __GS_H__ + +#include +#include + +// need C definitions +extern "C" { +#define GSdefs +#include "PS2Edefs.h" +} + +#ifdef _WIN32 + +#include +#include + +extern HWND GShwnd; + +#else + +#include +#include +#include +#include + +#define __inline inline + +typedef int BOOL; + +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +#endif + +#if defined(_MSC_VER) +#define FASTCALL(fn) __fastcall fn +#else + +#ifdef __x86_64 +#define FASTCALL(fn) fn +#else +#define FASTCALL(fn) __attribute__((fastcall)) fn +#endif +#endif + +struct Vector_16F +{ + u16 x, y, z, w; +}; + + +///////////////////// +// define when releasing +// The only code that uses it is commented out! +//#define ZEROGS_CACHEDCLEAR // much better performance +//#define RELEASE_TO_PUBLIC + +#if defined(ZEROGS_DEVBUILD) +#define GS_LOG __Log +#else +#define GS_LOG 0&& +#endif + +#define ERROR_LOG __LogToConsole +#define DEBUG_LOG printf + +#ifdef RELEASE_TO_PUBLIC +#define WARN_LOG 0&& +#define PRIM_LOG 0&& +#else +#define WARN_LOG printf +#define PRIM_LOG if (conf.log & 0x00000010) GS_LOG +#endif + +#ifndef GREG_LOG +#define GREG_LOG 0&& +#endif +#ifndef PRIM_LOG +#define PRIM_LOG 0&& +#endif +#ifndef WARN_LOG +#define WARN_LOG 0&& +#endif + +#define REG64(name) \ +union name \ +{ \ + u64 i64; \ + u32 ai32[2]; \ + struct { \ + +#define REG128(name)\ +union name \ +{ \ + u64 ai64[2]; \ + u32 ai32[4]; \ + struct { \ + +#define REG64_(prefix, name) REG64(prefix##name) +#define REG128_(prefix, name) REG128(prefix##name) + +#define REG_END }; }; +#define REG_END2 }; + +#define REG64_SET(name) \ +union name \ +{ \ + u64 i64; \ + u32 ai32[2]; \ + +#define REG128_SET(name)\ +union name \ +{ \ + u64 ai64[2]; \ + u32 ai32[4]; \ + +#define REG_SET_END }; + +REG64_(GSReg, BGCOLOR) + u32 R:8; + u32 G:8; + u32 B:8; + u32 _PAD1:8; + u32 _PAD2:32; +REG_END + +REG64_(GSReg, BUSDIR) + u32 DIR:1; + u32 _PAD1:31; + u32 _PAD2:32; +REG_END + +REG64_(GSReg, CSR) + u32 SIGNAL:1; + u32 FINISH:1; + u32 HSINT:1; + u32 VSINT:1; + u32 EDWINT:1; + u32 ZERO1:1; + u32 ZERO2:1; + u32 _PAD1:1; + u32 FLUSH:1; + u32 RESET:1; + u32 _PAD2:2; + u32 NFIELD:1; + u32 FIELD:1; + u32 FIFO:2; + u32 REV:8; + u32 ID:8; + u32 _PAD3:32; +REG_END + +REG64_(GSReg, DISPFB) // (-1/2) + u32 FBP:9; + u32 FBW:6; + u32 PSM:5; + u32 _PAD:12; + u32 DBX:11; + u32 DBY:11; + u32 _PAD2:10; +REG_END + +REG64_(GSReg, DISPLAY) // (-1/2) + u32 DX:12; + u32 DY:11; + u32 MAGH:4; + u32 MAGV:2; + u32 _PAD:3; + u32 DW:12; + u32 DH:11; + u32 _PAD2:9; +REG_END + +REG64_(GSReg, EXTBUF) + u32 EXBP:14; + u32 EXBW:6; + u32 FBIN:2; + u32 WFFMD:1; + u32 EMODA:2; + u32 EMODC:2; + u32 _PAD1:5; + u32 WDX:11; + u32 WDY:11; + u32 _PAD2:10; +REG_END + +REG64_(GSReg, EXTDATA) + u32 SX:12; + u32 SY:11; + u32 SMPH:4; + u32 SMPV:2; + u32 _PAD1:3; + u32 WW:12; + u32 WH:11; + u32 _PAD2:9; +REG_END + +REG64_(GSReg, EXTWRITE) + u32 WRITE; + u32 _PAD2:32; +REG_END + +REG64_(GSReg, IMR) + u32 _PAD1:8; + u32 SIGMSK:1; + u32 FINISHMSK:1; + u32 HSMSK:1; + u32 VSMSK:1; + u32 EDWMSK:1; + u32 _PAD2:19; + u32 _PAD3:32; +REG_END + +REG64_(GSReg, PMODE) + u32 EN1:1; + u32 EN2:1; + u32 CRTMD:3; + u32 MMOD:1; + u32 AMOD:1; + u32 SLBG:1; + u32 ALP:8; + u32 _PAD:16; + u32 _PAD1:32; +REG_END + +REG64_(GSReg, SIGLBLID) + u32 SIGID:32; + u32 LBLID:32; +REG_END + +REG64_(GSReg, SMODE1) + u32 RC:3; + u32 LC:7; + u32 T1248:2; + u32 SLCK:1; + u32 CMOD:2; + u32 EX:1; + u32 PRST:1; + u32 SINT:1; + u32 XPCK:1; + u32 PCK2:2; + u32 SPML:4; + u32 GCONT:1; + u32 PHS:1; + u32 PVS:1; + u32 PEHS:1; + u32 PEVS:1; + u32 CLKSEL:2; + u32 NVCK:1; + u32 SLCK2:1; + u32 VCKSEL:2; + u32 VHP:1; + u32 _PAD1:27; +REG_END + +REG64_(GSReg, SMODE2) + u32 INT:1; + u32 FFMD:1; + u32 DPMS:2; + u32 _PAD2:28; + u32 _PAD3:32; +REG_END + +REG64_(GSReg, SIGBLID) + u32 SIGID; + u32 LBLID; +REG_END + +extern int g_LastCRC; +extern u8* g_pBasePS2Mem; +#define PMODE ((GSRegPMODE*)(g_pBasePS2Mem+0x0000)) +#define SMODE1 ((GSRegSMODE1*)(g_pBasePS2Mem+0x0010)) +#define SMODE2 ((GSRegSMODE2*)(g_pBasePS2Mem+0x0020)) +// SRFSH +#define SYNCH1 ((GSRegSYNCH1*)(g_pBasePS2Mem+0x0040)) +#define SYNCH2 ((GSRegSYNCH2*)(g_pBasePS2Mem+0x0050)) +#define SYNCV ((GSRegSYNCV*)(g_pBasePS2Mem+0x0060)) +#define DISPFB1 ((GSRegDISPFB*)(g_pBasePS2Mem+0x0070)) +#define DISPLAY1 ((GSRegDISPLAY*)(g_pBasePS2Mem+0x0080)) +#define DISPFB2 ((GSRegDISPFB*)(g_pBasePS2Mem+0x0090)) +#define DISPLAY2 ((GSRegDISPLAY*)(g_pBasePS2Mem+0x00a0)) +#define EXTBUF ((GSRegEXTBUF*)(g_pBasePS2Mem+0x00b0)) +#define EXTDATA ((GSRegEXTDATA*)(g_pBasePS2Mem+0x00c0)) +#define EXTWRITE ((GSRegEXTWRITE*)(g_pBasePS2Mem+0x00d0)) +#define BGCOLOR ((GSRegBGCOLOR*)(g_pBasePS2Mem+0x00e0)) +#define CSR ((GSRegCSR*)(g_pBasePS2Mem+0x1000)) +#define IMR ((GSRegIMR*)(g_pBasePS2Mem+0x1010)) +#define BUSDIR ((GSRegBUSDIR*)(g_pBasePS2Mem+0x1040)) +#define SIGLBLID ((GSRegSIGBLID*)(g_pBasePS2Mem+0x1080)) + +#define GET_GSFPS (((SMODE1->CMOD&1) ? 50 : 60) / (SMODE2->INT ? 1 : 2)) + +// +// sps2tags.h +// +#ifdef _M_AMD64 +#define GET_GIF_REG(tag, reg) \ + (((tag).ai64[1] >> ((reg) << 2)) & 0xf) +#else +#define GET_GIF_REG(tag, reg) \ + (((tag).ai32[2 + ((reg) >> 3)] >> (((reg) & 7) << 2)) & 0xf) +#endif + +// +// GIFTag +REG128(GIFTag) + u32 NLOOP:15; + u32 EOP:1; + u32 _PAD1:16; + u32 _PAD2:14; + u32 PRE:1; + u32 PRIM:11; + u32 FLG:2; // enum GIF_FLG + u32 NREG:4; + u64 REGS:64; +REG_END + +typedef struct { + int x, y, w, h; +} Rect; + +typedef struct { + int x, y; +} Point; + +typedef struct { + int x0, y0; + int x1, y1; +} Rect2; + +typedef struct { + int x, y, c; +} PointC; + +#define GSOPTION_FULLSCREEN 0x2 +#define GSOPTION_BMPSNAP 0x4 +#define GSOPTION_CAPTUREAVI 0x8 + +#define GSOPTION_WINDIMS 0x70 +#define GSOPTION_WIN640 0x00 +#define GSOPTION_WIN800 0x10 +#define GSOPTION_WIN1024 0x20 +#define GSOPTION_WIN1280 0x30 +#define GSOPTION_WIN960W 0x40 +#define GSOPTION_WIN1280W 0x50 +#define GSOPTION_WIN1920W 0x60 + +#define GSOPTION_WIREFRAME 0x100 +#define GSOPTION_WIDESCREEN 0x200 +#define GSOPTION_LOADED 0x8000 + +typedef struct { + u8 mrtdepth; // write color in render target + u8 interlace; + u8 aa; // antialiasing 0 - off, 1 - 2x, 2 - 4x + u8 bilinear; // set to enable bilinear support + u32 options; + u32 gamesettings; // default game settings + int width, height; + int winstyle; // window style before full screen +#ifdef GS_LOG + u32 log; +#endif +} GSconf; + +#define VERTEXGPU \ + union \ + { \ + struct \ + { \ + u16 x, y, f, resv0; /* note: xy is 12d3*/ \ + u32 rgba; \ + u32 z; \ + }; \ + }; \ + \ + float s, t, q; \ + +typedef struct { + s16 x, y, f, resv0; /* note: xy is 12d3*/ \ + u32 rgba; + u32 z; + float s, t, q; +} VertexGPU; + +typedef struct { + VERTEXGPU + u16 u, v; +} Vertex; + +extern int g_GameSettings; +extern GSconf conf; +extern int ppf; + +#define PSMCT32 0 +#define PSMCT24 1 +#define PSMCT16 2 +#define PSMCT16S 10 +#define PSMT8 19 +#define PSMT4 20 +#define PSMT8H 27 +#define PSMT4HL 36 +#define PSMT4HH 44 +#define PSMT32Z 48 +#define PSMT24Z 49 +#define PSMT16Z 50 +#define PSMT16SZ 58 + +#define PSMT_ISCLUT(psm) (((psm)&0x7)>2) +#define PSMT_IS16BIT(psm) (((psm)&7)==2||((psm)&7)==10) + +typedef struct { + int nloop; + int eop; + int nreg; +} tagInfo; + +typedef union { + s64 SD; + u64 UD; + s32 SL[2]; + u32 UL[2]; + s16 SS[4]; + u16 US[4]; + s8 SC[8]; + u8 UC[8]; +} reg64; + +/* general purpose regs structs */ +typedef struct { + int fbp; + int fbw; + int fbh; + int psm; + u32 fbm; +} frameInfo; + +typedef struct { + u16 prim; + + union { + struct { + u16 iip : 1; + u16 tme : 1; + u16 fge : 1; + u16 abe : 1; + u16 aa1 : 1; + u16 fst : 1; + u16 ctxt : 1; + u16 fix : 1; + u16 resv : 8; + }; + u16 _val; + }; +} primInfo; + +extern primInfo *prim; + +typedef union { + struct { + u32 ate : 1; + u32 atst : 3; + u32 aref : 8; + u32 afail : 2; + u32 date : 1; + u32 datm : 1; + u32 zte : 1; + u32 ztst : 2; + u32 resv : 13; + }; + u32 _val; +} pixTest; + +typedef struct { + int bp; + int bw; + int psm; +} bufInfo; + +typedef struct { + int tbp0; + int tbw; + int cbp; + u16 tw, th; + u8 psm; + u8 tcc; + u8 tfx; + u8 cpsm; + u8 csm; + u8 csa; + u8 cld; +} tex0Info; + +#define TEX_MODULATE 0 +#define TEX_DECAL 1 +#define TEX_HIGHLIGHT 2 +#define TEX_HIGHLIGHT2 3 + +typedef struct { + int lcm; + int mxl; + int mmag; + int mmin; + int mtba; + int l; + int k; +} tex1Info; + +typedef struct { + int wms; + int wmt; + int minu; + int maxu; + int minv; + int maxv; +} clampInfo; + +typedef struct { + int cbw; + int cou; + int cov; +} clutInfo; + +typedef struct { + int tbp[3]; + int tbw[3]; +} miptbpInfo; + +typedef struct { + u16 aem; + u8 ta[2]; + float fta[2]; +} texaInfo; + +typedef struct { + int sx; + int sy; + int dx; + int dy; + int dir; +} trxposInfo; + +typedef struct { + union { + struct { + u8 a : 2; + u8 b : 2; + u8 c : 2; + u8 d : 2; + }; + u8 abcd; + }; + + u8 fix : 8; +} alphaInfo; + +typedef struct { + u16 zbp; // word address / 64 + u8 psm; + u8 zmsk; +} zbufInfo; + +typedef struct { + int fba; +} fbaInfo; + +typedef struct { + int mode; + int regn; + u64 regs; + tagInfo tag; +} pathInfo; + +typedef struct { + Vertex gsvertex[3]; + u32 rgba; + float q; + Vertex vertexregs; + + int primC; // number of verts current storing + int primIndex; // current prim index + int nTriFanVert; + + int prac; + int dthe; + int colclamp; + int fogcol; + int smask; + int pabe; + u64 buff[2]; + int buffsize; + int cbp[2]; // internal cbp registers + + u32 CSRw; + + primInfo _prim[2]; + bufInfo srcbuf, srcbufnew; + bufInfo dstbuf, dstbufnew; + + clutInfo clut; + + texaInfo texa; + trxposInfo trxpos, trxposnew; + + int imageWtemp, imageHtemp; + + int imageTransfer; + int imageWnew, imageHnew, imageX, imageY, imageEndX, imageEndY; + + pathInfo path1; + pathInfo path2; + pathInfo path3; + +} GSinternal; + +extern GSinternal gs; + +extern FILE *gsLog; + +void __Log(const char *fmt, ...); +void __LogToConsole(const char *fmt, ...); + +void LoadConfig(); +void SaveConfig(); + +extern void (*GSirq)(); + +void *SysLoadLibrary(char *lib); // Loads Library +void *SysLoadSym(void *lib, char *sym); // Loads Symbol from Library +char *SysLibError(); // Gets previous error loading sysbols +void SysCloseLibrary(void *lib); // Closes Library +void SysMessage(char *fmt, ...); + +extern "C" void * memcpy_amd(void *dest, const void *src, size_t n); +extern "C" u8 memcmp_mmx(const void *dest, const void *src, int n); + +template +class CInterfacePtr +{ +public: + inline CInterfacePtr() : ptr(NULL) {} + inline explicit CInterfacePtr(T* newptr) : ptr(newptr) { if ( ptr != NULL ) ptr->AddRef(); } + inline ~CInterfacePtr() { if( ptr != NULL ) ptr->Release(); } + + inline T* operator* () { assert( ptr != NULL); return *ptr; } + inline T* operator->() { return ptr; } + inline T* get() { return ptr; } + + inline void release() { + if( ptr != NULL ) { ptr->Release(); ptr = NULL; } + } + + inline operator T*() { return ptr; } + + inline bool operator==(T* rhs) { return ptr == rhs; } + inline bool operator!=(T* rhs) { return ptr != rhs; } + + inline CInterfacePtr& operator= (T* newptr) { + if( ptr != NULL ) ptr->Release(); + ptr = newptr; + + if( ptr != NULL ) ptr->AddRef(); + return *this; + } + +private: + T* ptr; +}; + +#define RGBA32to16(c) \ + (u16)((((c) & 0x000000f8) >> 3) | \ + (((c) & 0x0000f800) >> 6) | \ + (((c) & 0x00f80000) >> 9) | \ + (((c) & 0x80000000) >> 16)) \ + +#define RGBA16to32(c) \ + (((c) & 0x001f) << 3) | \ + (((c) & 0x03e0) << 6) | \ + (((c) & 0x7c00) << 9) | \ + (((c) & 0x8000) ? 0xff000000 : 0) \ + +// converts float16 [0,1] to BYTE [0,255] (assumes value is in range, otherwise will take lower 8bits) +// f is a u16 +__forceinline u16 Float16ToBYTE(u16 f) { + //assert( !(f & 0x8000) ); + if( f & 0x8000 ) return 0; + + u16 d = ((((f&0x3ff)|0x400)*255)>>(10-((f>>10)&0x1f)+15)); + return d > 255 ? 255 : d; +} + +__forceinline u16 Float16ToALPHA(u16 f) { + //assert( !(f & 0x8000) ); + if( f & 0x8000 ) return 0; + + // round up instead of down (crash and burn), too much and charlie breaks + u16 d = (((((f&0x3ff)|0x400))*255)>>(10-((f>>10)&0x1f)+15)); + d = (d)>>1; + return d > 255 ? 255 : d; +} + +#ifndef COLOR_ARGB +#define COLOR_ARGB(a,r,g,b) \ + ((u32)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff))) +#endif + +// assumes that positive in [1,2] (then extracts fraction by just looking at the specified bits) +#define Float16ToBYTE_2(f) ((u8)(*(u16*)&f>>2)) +#define Float16To5BIT(f) (Float16ToBYTE(f)>>3) + +#define Float16Alpha(f) (((*(u16*)&f&0x7c00)>=0x3900)?0x8000:0) // alpha is >= 1 + +// converts an array of 4 u16s to a u32 color +// f is a pointer to a u16 +#define Float16ToARGB(f) COLOR_ARGB(Float16ToALPHA(f.w), Float16ToBYTE(f.x), Float16ToBYTE(f.y), Float16ToBYTE(f.z)); + +#define Float16ToARGB16(f) (Float16Alpha(f.w)|(Float16To5BIT(f.x)<<10)|(Float16To5BIT(f.y)<<5)|Float16To5BIT(f.z)) + +// used for Z values +#define Float16ToARGB_Z(f) COLOR_ARGB((u32)Float16ToBYTE_2(f.w), Float16ToBYTE_2(f.x), Float16ToBYTE_2(f.y), Float16ToBYTE_2(f.z)) +#define Float16ToARGB16_Z(f) ((Float16ToBYTE_2(f.y)<<8)|Float16ToBYTE_2(f.z)) + + +inline float Clamp(float fx, float fmin, float fmax) +{ + if( fx < fmin ) return fmin; + return fx > fmax ? fmax : fx; +} + +#endif diff --git a/plugins/zerogs/dx/GSmain.cpp b/plugins/zerogs/dx/GSmain.cpp index 2745e88d19..8db67deef4 100644 --- a/plugins/zerogs/dx/GSmain.cpp +++ b/plugins/zerogs/dx/GSmain.cpp @@ -1,1049 +1,1049 @@ -/* ZeroGS - * Copyright (C) 2005-2006 zerofrog@gmail.com - * - * 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 - */ -#if defined(_WIN32) || defined(_WIN32) -#include -#include -#endif - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -using namespace std; - -#include "Win32.h" - -#include "GS.h" -#include "Mem.h" -#include "Regs.h" - -#include "zerogs.h" -#include "targets.h" -#include "zerogsshaders/zerogsshaders.h" - -#ifdef _MSC_VER -#pragma warning(disable:4244) -#endif - -#ifdef _DEBUG -HANDLE g_hCurrentThread = NULL; -#endif - -GSinternal gs; -char GStitle[256]; -GSconf conf; -int ppf; -primInfo *prim; -FILE *gsLog; -int g_GSMultiThreaded = 0; -void (*GSirq)(); -u8* g_pBasePS2Mem = NULL; -int g_TransferredToGPU = 0; -int g_GameSettings = 0; - -static LARGE_INTEGER luPerfFreq; - -// statistics -u32 g_nGenVars = 0, g_nTexVars = 0, g_nAlphaVars = 0, g_nResolve = 0; - -#define VER 97 -const unsigned char version = PS2E_GS_VERSION; -unsigned char revision = 0; // revision and build gives plugin version -unsigned char build = VER; -unsigned char minor = 1; - -#ifdef _DEBUG -char *libraryName = "ZeroGS (Debug) "; -#elif defined(RELEASE_TO_PUBLIC) - -#ifdef ZEROGS_SSE2 -char *libraryName = "ZeroGS"; -#else -char *libraryName = "ZeroGS (no SSE2)"; -#endif - -#else -char *libraryName = "ZeroGS (Dev) "; -#endif - -static const char* s_aa[5] = { "AA none |", "AA 2x |", "AA 4x |", "AA 8x", "AA 16x" }; - -extern GIFRegHandler g_GIFPackedRegHandlers[]; -extern GIFRegHandler g_GIFRegHandlers[]; -GIFRegHandler g_GIFTempRegHandlers[16] = {0}; -extern int g_nPixelShaderVer; -extern int g_nFrameRender; -extern int g_nFramesSkipped; - -const char* pbilinear[] = { "off", "normal", "forced" }; - -int s_frameskipping = 0; -u32 CALLBACK PS2EgetLibType() { - return PS2E_LT_GS; -} - -char* CALLBACK PS2EgetLibName() { - return libraryName; -} - -u32 CALLBACK PS2EgetLibVersion2(u32 type) { - return (version<<16) | (revision<<8) | build | (minor << 24); -} - -#ifdef _WIN32 - -HWND GShwnd; - -void SysMessage(char *fmt, ...) { - va_list list; - char tmp[512]; - - va_start(list,fmt); - vsprintf(tmp,fmt,list); - va_end(list); - MessageBox(0, tmp, "GSsoftdx Msg", 0); -} - -#endif - -void __Log(const char *fmt, ...) { - va_list list; - - // gsLog can be null if the config dialog is used prior to Pcsx2 an emulation session. - // (GSinit won't have been called then) - - if (gsLog == NULL || !conf.log) return; - - va_start(list, fmt); - vfprintf(gsLog, fmt, list); - va_end(list); -} - -void __LogToConsole(const char *fmt, ...) { - va_list list; - - printf("ZeroGS: "); - - // gsLog can be null if the config dialog is used prior to Pcsx2 an emulation session. - // (GSinit won't have been called then) - - va_start(list, fmt); - if( gsLog != NULL ) - vfprintf(gsLog, fmt, list); - vprintf(fmt, list); - va_end(list); -} - -void CALLBACK GSsetBaseMem(void* pmem) { - g_pBasePS2Mem = (u8*)pmem; -} - -extern int VALIDATE_THRESH; -extern u32 TEXDESTROY_THRESH; -int g_LastCRC = 0; -void CALLBACK GSsetGameCRC(int crc, int options) -{ - VALIDATE_THRESH = 8; - g_GameSettings = conf.gamesettings|options; - conf.mrtdepth = !(conf.gamesettings&GAME_DISABLEMRTDEPTH); - - g_GameSettings |= GAME_PATH3HACK; - g_LastCRC = crc; - - //g_GameSettings |= GAME_PARTIALDEPTH; - -// g_GameSettings |= GAME_DOPARALLELCTX|GAME_XENOSPECHACK; -// VALIDATE_THRESH = 64; -// TEXDESTROY_THRESH = 32; - - switch(crc) { - case 0x54A548B4: // crash n burn - // overbright - if( pd3dDevice != NULL ) { - pd3dDevice->SetPixelShaderConstantF(27, DXVEC4(0.5f, 0.9f/256.0f, 0,1/255.0f), 1); // g_fExactColor - } - break; - - case 0xA3D63039: // xenosaga(j) - case 0x0E7807B2: // xenosaga(u) - g_GameSettings |= GAME_DOPARALLELCTX; - VALIDATE_THRESH = 64; - TEXDESTROY_THRESH = 32; - break; - - case 0x7D2FE035: // espgaluda (j) - VALIDATE_THRESH = 24; - //g_GameSettings |= GAME_BIGVALIDATE; - break; - } - - DEBUG_LOG("ZeroGS: Set game options: 0x%8.8x\n", g_GameSettings); -} - -void CALLBACK GSsetFrameSkip(int frameskip) -{ - s_frameskipping |= frameskip; - if( frameskip && g_nFrameRender > 1 ) { - - for(int i = 0; i < 16; ++i) { - g_GIFPackedRegHandlers[i] = GIFPackedRegHandlerNOP; - } - - // still keep certain handlers - g_GIFPackedRegHandlers[6] = GIFRegHandlerTEX0_1; - g_GIFPackedRegHandlers[7] = GIFRegHandlerTEX0_2; - g_GIFPackedRegHandlers[14] = GIFPackedRegHandlerA_D; - - g_GIFRegHandlers[0] = GIFRegHandlerNOP; - g_GIFRegHandlers[1] = GIFRegHandlerNOP; - g_GIFRegHandlers[2] = GIFRegHandlerNOP; - g_GIFRegHandlers[3] = GIFRegHandlerNOP; - g_GIFRegHandlers[4] = GIFRegHandlerNOP; - g_GIFRegHandlers[5] = GIFRegHandlerNOP; - g_GIFRegHandlers[12] = GIFRegHandlerNOP; - g_GIFRegHandlers[13] = GIFRegHandlerNOP; - g_GIFRegHandlers[26] = GIFRegHandlerNOP; - g_GIFRegHandlers[27] = GIFRegHandlerNOP; - g_nFrameRender = 0; - } - else if( !frameskip && g_nFrameRender <= 0 ) { - g_nFrameRender = 1; - - if( g_GIFTempRegHandlers[0] == NULL ) return; // not init yet - - // restore - memcpy(g_GIFPackedRegHandlers, g_GIFTempRegHandlers, sizeof(g_GIFTempRegHandlers)); - - g_GIFRegHandlers[0] = GIFRegHandlerPRIM; - g_GIFRegHandlers[1] = GIFRegHandlerRGBAQ; - g_GIFRegHandlers[2] = GIFRegHandlerST; - g_GIFRegHandlers[3] = GIFRegHandlerUV; - g_GIFRegHandlers[4] = GIFRegHandlerXYZF2; - g_GIFRegHandlers[5] = GIFRegHandlerXYZ2; - g_GIFRegHandlers[12] = GIFRegHandlerXYZF3; - g_GIFRegHandlers[13] = GIFRegHandlerXYZ2; - g_GIFRegHandlers[26] = GIFRegHandlerPRMODECONT; - g_GIFRegHandlers[27] = GIFRegHandlerPRMODE; - } -} - -void CALLBACK GSreset() { - - memset(&gs, 0, sizeof(gs)); - - ZeroGS::GSStateReset(); - - gs.prac = 1; - prim = &gs._prim[0]; - gs.nTriFanVert = -1; - gs.imageTransfer = -1; - gs.q = 1; -} - -void CALLBACK GSgifSoftReset(u32 mask) -{ - if( mask & 1 ) memset(&gs.path1, 0, sizeof(gs.path1)); - if( mask & 2 ) memset(&gs.path2, 0, sizeof(gs.path2)); - if( mask & 4 ) memset(&gs.path3, 0, sizeof(gs.path3)); - gs.imageTransfer = -1; - gs.q = 1; - gs.nTriFanVert = -1; -} - -s32 CALLBACK GSinit() -{ - memcpy(g_GIFTempRegHandlers, g_GIFPackedRegHandlers, sizeof(g_GIFTempRegHandlers)); - -#ifdef GS_LOG - gsLog = fopen("logs/gsLog.txt", "w"); - if (gsLog == NULL) { - gsLog = fopen("gsLog.txt", "w"); - if (gsLog == NULL) { - SysMessage("Can't create gsLog.txt"); return -1; - } - } - setvbuf(gsLog, NULL, _IONBF, 0); - GS_LOG("GSinit\n"); -#endif - - GSreset(); - GS_LOG("GSinit ok\n"); - - return 0; -} - -void CALLBACK GSshutdown() -{ -#ifdef GS_LOG - fclose(gsLog); -#endif -} - -LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - static int nWindowWidth = 0, nWindowHeight = 0; - - switch( msg ) { - case WM_DESTROY: - PostQuitMessage( 0 ); - return 0; - - case WM_KEYDOWN: -// switch(wParam) { -// case VK_ESCAPE: -// SendMessage(hWnd, WM_DESTROY, 0L, 0L); -// break; -// } - break; - - case WM_ACTIVATE: - - if( wParam != WA_INACTIVE ) { - //DEBUG_LOG("restoring device\n"); - ZeroGS::Restore(); - } - - break; - - case WM_SIZE: - nWindowWidth = lParam&0xffff; - nWindowHeight = lParam>>16; - ZeroGS::ChangeWindowSize(nWindowWidth, nWindowHeight); - - break; - - case WM_SIZING: - // if button is 0, then just released so can resize - if( GetSystemMetrics(SM_SWAPBUTTON) ? !GetAsyncKeyState(VK_RBUTTON) : !GetAsyncKeyState(VK_LBUTTON) ) { - ZeroGS::SetChangeDeviceSize(nWindowWidth, nWindowHeight); - } - break; - - case WM_SETCURSOR: - SetCursor(NULL); - break; - } - - return DefWindowProc( hWnd, msg, wParam, lParam ); -} - -s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread) { - - g_GSMultiThreaded = multithread; - - GS_LOG("GSopen\n"); - -#ifdef _DEBUG - g_hCurrentThread = GetCurrentThread(); -#endif - - assert( GSirq != NULL ); - LoadConfig(); - g_GameSettings = 0; - - strcpy(GStitle, Title); - - RECT rc, rcdesktop; - rc.left = 0; rc.top = 0; - rc.right = conf.width; rc.bottom = conf.height; - - WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, - GetModuleHandle(NULL), NULL, NULL, NULL, NULL, - "PS2EMU_ZEROGS", NULL }; - RegisterClassEx( &wc ); - - AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); - - GetWindowRect(GetDesktopWindow(), &rcdesktop); - - GShwnd = CreateWindow( "PS2EMU_ZEROGS", "ZeroGS", WS_OVERLAPPEDWINDOW, - (rcdesktop.right-(rc.right-rc.left))/2, (rcdesktop.bottom-(rc.bottom-rc.top))/2, - rc.right-rc.left, rc.bottom-rc.top, NULL, NULL, wc.hInstance, NULL ); - - if(GShwnd == NULL) { - GS_LOG("Failed to create window. Exiting..."); - return -1; - } - - if( pDsp != NULL ) - *(int*)pDsp = (int)GShwnd; - - DEBUG_LOG("creating zerogs\n"); - //if (conf.record) recOpen(); - if( FAILED(ZeroGS::Create(conf.width, conf.height)) ) - return -1; - - DEBUG_LOG("initialization successful\n"); - - if( FAILED(ZeroGS::InitDeviceObjects()) ) - return -1; - - if( conf.bilinear == 2 ) { - ZeroGS::AddMessage("forced bilinear filtering - on", 1000); - } - else if( conf.bilinear == 1 ) { - ZeroGS::AddMessage("normal bilinear filtering - on", 1000); - } - if( conf.aa ) { - char strtitle[64]; - sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa], 1000); - ZeroGS::AddMessage(strtitle); - } - if( conf.options & GSOPTION_WIDESCREEN ) { - ZeroGS::AddMessage("16:9 widescreen - on", 1000); - } - - // set just in case - SetWindowLongPtr(GShwnd, GWLP_WNDPROC, (LPARAM)(WNDPROC)MsgProc); - - ShowWindow( GShwnd, SW_SHOWDEFAULT ); - UpdateWindow( GShwnd ); - SetFocus(GShwnd); - - conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); - conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style - -#ifdef _WIN32 - QueryPerformanceFrequency(&luPerfFreq); -#else - luPerfFreq.QuadPart = 1; -#endif - - GS_LOG("GSopen ok\n"); - - gs.path1.mode = 0; - gs.path2.mode = 0; - gs.path3.mode = 0; - - return 0; -} - -void CALLBACK GSclose() { - ZeroGS::Destroy(1); - - //if (conf.record) recClose(); - -#ifdef _WIN32 - DestroyWindow(GShwnd); -#endif -} - -void CALLBACK GSirqCallback(void (*callback)()) { - GSirq = callback; -} - -void CALLBACK GSwriteCSR(u32 write) -{ - gs.CSRw = write; -} - -void CALLBACK GSchangeSaveState(int newstate, const char* filename) -{ - char str[255]; - sprintf(str, "save state %d", newstate); - ZeroGS::AddMessage(str); -} - -void CALLBACK GSmakeSnapshot(char *path) -{ - FILE *bmpfile; - char filename[256]; - u32 snapshotnr = 0; - - // increment snapshot value & try to get filename - for (;;) { - snapshotnr++; - - sprintf(filename,"%ssnap%03ld.%s", path, snapshotnr, (conf.options&GSOPTION_BMPSNAP)?"bmp":"jpg"); - - bmpfile=fopen(filename,"rb"); - if (bmpfile == NULL) break; - fclose(bmpfile); - } - - // try opening new snapshot file - if((bmpfile=fopen(filename,"wb"))==NULL) { - char strdir[255]; - sprintf(strdir, "%s", path); - CreateDirectory(strdir, NULL); - - if((bmpfile=fopen(filename,"wb"))==NULL) return; - } - - fclose(bmpfile); - - // get the bits - ZeroGS::SaveSnapshot(filename); -} - -int UPDATE_FRAMES = 16; -int g_nFrame = 0; -int g_nRealFrame = 0; -static BOOL g_bHidden = 0; - -float fFPS = 0; - -void CALLBACK GSvsync(int interlace) -{ - GS_LOG("\nGSvsync\n\n"); - - static u32 dwTime = timeGetTime(); - static int nToNextUpdate = 1; - - char strtitle[512]; - - g_nRealFrame++; - - MSG msg; - ZeroMemory( &msg, sizeof(msg) ); - while( 1 ) { - if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) - { - switch( msg.message ) { - case WM_KEYDOWN : - if( msg.wParam == VK_F5 ) { - - if( (GetKeyState(VK_SHIFT)&0x8000) ) { - if( g_nPixelShaderVer == SHADER_20 ) { - conf.bilinear = 0; - sprintf(strtitle, "ps 2.0 doesn't support bilinear filtering"); - } - else { - conf.bilinear = (conf.bilinear+1)%3; - sprintf(strtitle, "bilinear filtering - %s", pbilinear[conf.bilinear]); - } - } - else { - conf.interlace++; - if( conf.interlace > 2 ) conf.interlace = 0; - if( conf.interlace < 2 ) sprintf(strtitle, "interlace on - mode %d", conf.interlace); - else sprintf(strtitle, "interlace off"); - } - - ZeroGS::AddMessage(strtitle); - SaveConfig(); - } - else if( msg.wParam == VK_F6 ) { - - if( (GetKeyState(VK_SHIFT)&0x8000) ) { - conf.aa--; // -1 - if( conf.aa > 4) conf.aa = 4; - sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa]); - ZeroGS::SetAA(conf.aa); - } - else { - conf.aa++; - if( conf.aa > 4 ) conf.aa = 0; - sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa]); - ZeroGS::SetAA(conf.aa); - } - - ZeroGS::AddMessage(strtitle); - SaveConfig(); - } - else if( msg.wParam == VK_F7 ) { - - if( (GetKeyState(VK_SHIFT)&0x8000) ) { - extern BOOL g_bDisplayFPS; - g_bDisplayFPS ^= 1; - } - else { - conf.options ^= GSOPTION_WIREFRAME; - SETRS(D3DRS_FILLMODE, (conf.options&GSOPTION_WIREFRAME)?D3DFILL_WIREFRAME:D3DFILL_SOLID); - sprintf(strtitle, "wireframe rendering - %s", (conf.options&GSOPTION_WIREFRAME)?"on":"off"); -// conf.options ^= GSOPTION_CAPTUREAVI; -// if( conf.options & GSOPTION_CAPTUREAVI ) ZeroGS::StartCapture(); -// else ZeroGS::StopCapture(); -// -// sprintf(strtitle, "capture avi (zerogs_dump.avi) - %s", (conf.options&GSOPTION_CAPTUREAVI) ? "on" : "off"); -// ZeroGS::AddMessage(strtitle); -// SaveConfig(); - } - } - else if( msg.wParam == VK_F9 ) { - - if( (GetKeyState(VK_SHIFT)&0x8000) ) { - conf.options ^= GSOPTION_WIDESCREEN; - sprintf(strtitle, "16:9 widescreen - %s", (conf.options&GSOPTION_WIDESCREEN)?"on":"off"); - } - else { - g_GameSettings ^= GAME_PATH3HACK; - sprintf(strtitle, "path3 hack - %s", (g_GameSettings&GAME_PATH3HACK) ? "on" : "off"); - } - ZeroGS::AddMessage(strtitle); - } - else if( msg.wParam == VK_ESCAPE ) { - - if( conf.options & GSOPTION_FULLSCREEN ) { - // destroy that msg - conf.options &= ~GSOPTION_FULLSCREEN; - conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); - conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style - ZeroGS::ChangeDeviceSize(conf.width, conf.height); - UpdateWindow(GShwnd); - continue; // so that msg doesn't get sent - } - else { - SendMessage(GShwnd, WM_DESTROY, 0, 0); - g_bHidden = 1; - return; - } - } - - break; - } - - TranslateMessage( &msg ); - DispatchMessage( &msg ); - } - else - break; - } - - if( (GetKeyState(VK_MENU)&0x8000) && (GetKeyState(VK_RETURN)&0x8000) ) { - conf.options ^= GSOPTION_FULLSCREEN; - - if( conf.options & GSOPTION_FULLSCREEN ) { - conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); - conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style - } - - ZeroGS::SetChangeDeviceSize( - (conf.options&GSOPTION_FULLSCREEN) ? 1280 : conf.width, - (conf.options&GSOPTION_FULLSCREEN) ? 960 : conf.height); - } - -// if( conf.fullscreen && (GetKeyState(VK_ESCAPE)&0x8000)) { -// conf.fullscreen &= ~GSOPTION_FULLSCREEN; -// ZeroGS::SetChangeDeviceSize(conf.width, conf.height); -// } - - //if( conf.interlace && g_nGenVars + g_nTexVars + g_nAlphaVars + g_nResolve == 0 ) - // CSR->FIELD = 0; // 0 should always be the repeating at 0 - - ZeroGS::RenderCRTC(!interlace); - - if( --nToNextUpdate <= 0 ) { - - u32 d = timeGetTime(); - fFPS = UPDATE_FRAMES * 1000.0f / (float)max(d-dwTime,1); - dwTime = d; - g_nFrame += UPDATE_FRAMES; - -#ifdef RELEASE_TO_PUBLIC - const char* g_pShaders[4] = { "ps 2.0", "ps 2.0a", "ps 2.0b", "ps 3.0" }; - - _snprintf(strtitle, 512, "%s 0.%d.%d %.1f fps | %s%s%s%s %s (%.1f)", libraryName, build, minor, fFPS, - (conf.interlace < 2) ? "interlace | " : "", - conf.bilinear ? (conf.bilinear==2?"forced bilinear | ":"bilinear | ") : "", - conf.aa ? s_aa[conf.aa] : "", - (g_GameSettings&GAME_FFXHACK) ? "ffxhack | " : "", - g_pShaders[g_nPixelShaderVer], (ppf&0xfffff)/(float)UPDATE_FRAMES); -#else - _snprintf(strtitle, 512, "%d | %.1f fps (sk:%d%%) | g: %.1f, t: %.1f, a: %.1f, r: %.1f | p: %.1f | tex: %d %d (%d kbpf)", g_nFrame, fFPS, - 100*g_nFramesSkipped/g_nFrame, - g_nGenVars/(float)UPDATE_FRAMES, g_nTexVars/(float)UPDATE_FRAMES, g_nAlphaVars/(float)UPDATE_FRAMES, - g_nResolve/(float)UPDATE_FRAMES, (ppf&0xfffff)/(float)UPDATE_FRAMES, - ZeroGS::g_MemTargs.listTargets.size(), ZeroGS::g_MemTargs.listClearedTargets.size(), g_TransferredToGPU>>10); - //_snprintf(strtitle, 512, "%x %x", *(int*)(ZeroGS::g_pbyGSMemory + 256 * 0x3e0c + 4), *(int*)(ZeroGS::g_pbyGSMemory + 256 * 0x3e04 + 4)); - -#endif - - if( !(conf.options&GSOPTION_FULLSCREEN) ) - SetWindowText(GShwnd, strtitle); - - if( fFPS < 16 ) UPDATE_FRAMES = 4; - else if( fFPS < 32 ) UPDATE_FRAMES = 8; - else UPDATE_FRAMES = 16; - - nToNextUpdate = UPDATE_FRAMES; - - g_TransferredToGPU = 0; - g_nGenVars = 0; - g_nTexVars = 0; - g_nAlphaVars = 0; - g_nResolve = 0; - ppf = 0; - g_nFramesSkipped = 0; - } -} - -void GIFtag(pathInfo *path, u32 *data) { - - path->tag.nloop = data[0] & 0x7fff; - path->tag.eop = (data[0] >> 15) & 0x1; - u32 tagpre = (data[1] >> 14) & 0x1; - u32 tagprim = (data[1] >> 15) & 0x7ff; - u32 tagflg = (data[1] >> 26) & 0x3; - path->tag.nreg = (data[1] >> 28)<<2; - - if (path->tag.nreg == 0) path->tag.nreg = 64; - - gs.q = 1; - -// GS_LOG("GIFtag: %8.8lx_%8.8lx_%8.8lx_%8.8lx: EOP=%d, NLOOP=%x, FLG=%x, NREG=%d, PRE=%d\n", -// data[3], data[2], data[1], data[0], -// path->tag.eop, path->tag.nloop, tagflg, path->tag.nreg, tagpre); - - path->mode = tagflg+1; - - switch (tagflg) { - case 0x0: - path->regs = *(u64 *)(data+2); - path->regn = 0; - if (tagpre) - GIFRegHandlerPRIM((u32*)&tagprim); - - break; - - case 0x1: - path->regs = *(u64 *)(data+2); - path->regn = 0; - break; - } -} - -void _GSgifPacket(pathInfo *path, u32 *pMem) { // 128bit - - int reg = (int)((path->regs >> path->regn) & 0xf); - g_GIFPackedRegHandlers[reg](pMem); - - path->regn += 4; - if (path->tag.nreg == path->regn) { - path->regn = 0; - path->tag.nloop--; - } -} - -void _GSgifRegList(pathInfo *path, u32 *pMem) { // 64bit - int reg; - - reg = (int)((path->regs >> path->regn) & 0xf); - - g_GIFRegHandlers[reg](pMem); - path->regn += 4; - if (path->tag.nreg == path->regn) { - path->regn = 0; - path->tag.nloop--; - } -} - -//static pathInfo* s_pLastPath = &gs.path3; -static int nPath3Hack = 0; - -void CALLBACK GSgetLastTag(u64* ptag) -{ - *(u32*)ptag = nPath3Hack; - nPath3Hack = 0; -} - -void _GSgifTransfer(pathInfo *path, u32 *pMem, u32 size) -{ -#ifdef _DEBUG - assert( g_hCurrentThread == GetCurrentThread() ); -#endif - - //s_pLastPath = path; - //BOOL bAfter0Tag = 0; - -// if( conf.log & 0x20 ) { -// __Log("%d: %x:%x\n", (path==&gs.path3)?3:(path==&gs.path2?2:1), pMem, size); -// for(int i = 0; i < size; i++) { -// __Log("%x %x %x %x\n", pMem[4*i+0], pMem[4*i+1], pMem[4*i+2], pMem[4*i+3]); -// } -// } - - while(size > 0) - { - //LOG(_T("Transfer(%08x, %d) START\n"), pMem, size); - if (path->tag.nloop == 0) - { - GIFtag(path, pMem); - pMem+= 4; - size--; - - if ((g_GameSettings & GAME_PATH3HACK) && path == &gs.path3 && gs.path3.tag.eop) - nPath3Hack = 1; - - if (path == &gs.path1) - { - // if too much data, just ignore - if (path->tag.nloop * (path->tag.nreg / 4) > (int)size * (path->mode==2?2:1)) - { - static int lasttime = 0; - if( timeGetTime() - lasttime > 5000 ) - { - ERROR_LOG("VU1 too much data, ignore if gfx are fine\n"); - lasttime = timeGetTime(); - } - path->tag.nloop = 0; - return; - } - - if (path->mode == 1) - { - // check if 0xb is in any reg, if yes, exit (kh2) - for(int i = 0; i < path->tag.nreg; i += 4) - { - if (((path->regs >> i)&0xf) == 11) - { - static int lasttime = 0; - if( timeGetTime() - lasttime > 5000 ) - { - ERROR_LOG("Invalid unpack type\n"); - lasttime = timeGetTime(); - } - path->tag.nloop = 0; - return; - } - } - } - } - - if(path->tag.nloop == 0 ) - { - if( path == &gs.path1 ) - { - // ffx hack - if( g_GameSettings & GAME_FFXHACK ) - { - if( path->tag.eop ) - return; - continue; - } - - return; - } - - if( !path->tag.eop ) - { - //DEBUG_LOG("continuing from eop\n"); - continue; - } - - break; - } - } - - switch(path->mode) { - case 1: // PACKED - { - assert( path->tag.nloop > 0 ); - for(; size > 0; size--, pMem += 4) - { - int reg = (int)((path->regs >> path->regn) & 0xf); - - g_GIFPackedRegHandlers[reg](pMem); - - path->regn += 4; - if (path->tag.nreg == path->regn) - { - path->regn = 0; - if( path->tag.nloop-- <= 1 ) - { - size--; - pMem += 4; - break; - } - } - } - break; - } - case 2: // REGLIST - { - //GS_LOG("%8.8x%8.8x %d L\n", ((u32*)&gs.regs)[1], *(u32*)&gs.regs, path->tag.nreg/4); - assert( path->tag.nloop > 0 ); - size *= 2; - for(; size > 0; pMem+= 2, size--) - { - int reg = (int)((path->regs >> path->regn) & 0xf); - g_GIFRegHandlers[reg](pMem); - path->regn += 4; - if (path->tag.nreg == path->regn) - { - path->regn = 0; - if( path->tag.nloop-- <= 1 ) - { - size--; - pMem += 2; - break; - } - } - } - - if( size & 1 ) pMem += 2; - size /= 2; - break; - } - case 3: // GIF_IMAGE (FROM_VFRAM) - case 4: - { - if(gs.imageTransfer >= 0 && gs.imageTransfer <= 1) - { - int process = min((int)size, path->tag.nloop); - - if( process > 0 ) - { - if (gs.imageTransfer) - ZeroGS::TransferLocalHost(pMem, process); - else - ZeroGS::TransferHostLocal(pMem, process*4); - - path->tag.nloop -= process; - pMem += process*4; size -= process; - - assert( size == 0 || path->tag.nloop == 0 ); - } - break; - } - else - { - // simulate - int process = min((int)size, path->tag.nloop); - path->tag.nloop -= process; - pMem += process*4; size -= process; - } - - break; - } - default: // GIF_IMAGE - GS_LOG("*** WARNING **** Unexpected GIFTag flag\n"); - assert(0); - path->tag.nloop = 0; - break; - - } - - if( path == &gs.path1 && path->tag.eop ) - return; - } -} - -void CALLBACK GSgifTransfer2(u32 *pMem, u32 size) -{ - //GS_LOG("GSgifTransfer2 size = %lx (mode %d, gs.path2.tag.nloop = %d)\n", size, gs.path2.mode, gs.path2.tag.nloop); - - _GSgifTransfer(&gs.path2, pMem, size); -} - -void CALLBACK GSgifTransfer3(u32 *pMem, u32 size) -{ - //GS_LOG("GSgifTransfer3 size = %lx (mode %d, gs.path3.tag.nloop = %d)\n", size, gs.path3.mode, gs.path3.tag.nloop); - - nPath3Hack = 0; - _GSgifTransfer(&gs.path3, pMem, size); -} - -static int count = 0; -void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr) -{ - pathInfo *path = &gs.path1; - - //GS_LOG("GSgifTransfer1 0x%x (mode %d)\n", addr, path->mode); - - addr &= 0x3fff; - -#ifdef _DEBUG - PRIM_LOG("count: %d\n", count); - count++; -#endif - - gs.path1.tag.nloop = 0; - gs.path1.tag.eop = 0; - _GSgifTransfer(&gs.path1, (u32*)((u8*)pMem+addr), (0x4000-addr)/16); - - if( !gs.path1.tag.eop && gs.path1.tag.nloop > 0 ) { - assert( (addr&0xf) == 0 ); //BUG - gs.path1.tag.nloop = 0; - ERROR_LOG("Transfer1 - 2\n"); - return; - } -} - -void CALLBACK GSreadFIFO(u64 *pMem) -{ - //GS_LOG("GSreadFIFO\n"); - - ZeroGS::TransferLocalHost((u32*)pMem, 1); -} - -void CALLBACK GSreadFIFO2(u64 *pMem, int qwc) -{ - //GS_LOG("GSreadFIFO2\n"); - - ZeroGS::TransferLocalHost((u32*)pMem, qwc); -} - -int CALLBACK GSsetupRecording(int start, void* pData) -{ - if( start ) { - if( conf.options & GSOPTION_CAPTUREAVI ) - return 1; - if( !ZeroGS::StartCapture() ) - return 0; - conf.options |= GSOPTION_CAPTUREAVI; - DEBUG_LOG("ZeroGS: started recording at zerogs.avi\n"); - } - else { - if( !(conf.options & GSOPTION_CAPTUREAVI) ) - return 1; - conf.options &= ~GSOPTION_CAPTUREAVI; - ZeroGS::StopCapture(); - DEBUG_LOG("ZeroGS: stopped recording\n"); - } - - return 1; -} - -s32 CALLBACK GSfreeze(int mode, freezeData *data) -{ - switch (mode) - { - case FREEZE_LOAD: - if (!ZeroGS::Load(data->data)) DEBUG_LOG("GS: Bad load format!"); - g_nRealFrame += 100; - break; - case FREEZE_SAVE: - ZeroGS::Save(data->data); - break; - case FREEZE_SIZE: - data->size = ZeroGS::Save(NULL); - break; - default: - break; - } - - return 0; -} - -extern HINSTANCE hInst; -void CALLBACK GSconfigure() { - DialogBox(hInst, - MAKEINTRESOURCE(IDD_CONFIG), - GetActiveWindow(), - (DLGPROC)ConfigureDlgProc); - - if( g_nPixelShaderVer == SHADER_20 ) - conf.bilinear = 0; -} +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ +#if defined(_WIN32) || defined(_WIN32) +#include +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +using namespace std; + +#include "Win32.h" + +#include "GS.h" +#include "Mem.h" +#include "Regs.h" + +#include "zerogs.h" +#include "targets.h" +#include "zerogsshaders/zerogsshaders.h" + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif + +#ifdef _DEBUG +HANDLE g_hCurrentThread = NULL; +#endif + +GSinternal gs; +char GStitle[256]; +GSconf conf; +int ppf; +primInfo *prim; +FILE *gsLog; +int g_GSMultiThreaded = 0; +void (*GSirq)(); +u8* g_pBasePS2Mem = NULL; +int g_TransferredToGPU = 0; +int g_GameSettings = 0; + +static LARGE_INTEGER luPerfFreq; + +// statistics +u32 g_nGenVars = 0, g_nTexVars = 0, g_nAlphaVars = 0, g_nResolve = 0; + +#define VER 97 +const unsigned char version = PS2E_GS_VERSION; +unsigned char revision = 0; // revision and build gives plugin version +unsigned char build = VER; +unsigned char minor = 1; + +#ifdef _DEBUG +char *libraryName = "ZeroGS (Debug) "; +#elif defined(RELEASE_TO_PUBLIC) + +#ifdef ZEROGS_SSE2 +char *libraryName = "ZeroGS"; +#else +char *libraryName = "ZeroGS (no SSE2)"; +#endif + +#else +char *libraryName = "ZeroGS (Dev) "; +#endif + +static const char* s_aa[5] = { "AA none |", "AA 2x |", "AA 4x |", "AA 8x", "AA 16x" }; + +extern GIFRegHandler g_GIFPackedRegHandlers[]; +extern GIFRegHandler g_GIFRegHandlers[]; +GIFRegHandler g_GIFTempRegHandlers[16] = {0}; +extern int g_nPixelShaderVer; +extern int g_nFrameRender; +extern int g_nFramesSkipped; + +const char* pbilinear[] = { "off", "normal", "forced" }; + +int s_frameskipping = 0; +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_GS; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (version<<16) | (revision<<8) | build | (minor << 24); +} + +#ifdef _WIN32 + +HWND GShwnd; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "GSsoftdx Msg", 0); +} + +#endif + +void __Log(const char *fmt, ...) { + va_list list; + + // gsLog can be null if the config dialog is used prior to Pcsx2 an emulation session. + // (GSinit won't have been called then) + + if (gsLog == NULL || !conf.log) return; + + va_start(list, fmt); + vfprintf(gsLog, fmt, list); + va_end(list); +} + +void __LogToConsole(const char *fmt, ...) { + va_list list; + + printf("ZeroGS: "); + + // gsLog can be null if the config dialog is used prior to Pcsx2 an emulation session. + // (GSinit won't have been called then) + + va_start(list, fmt); + if( gsLog != NULL ) + vfprintf(gsLog, fmt, list); + vprintf(fmt, list); + va_end(list); +} + +void CALLBACK GSsetBaseMem(void* pmem) { + g_pBasePS2Mem = (u8*)pmem; +} + +extern int VALIDATE_THRESH; +extern u32 TEXDESTROY_THRESH; +int g_LastCRC = 0; +void CALLBACK GSsetGameCRC(int crc, int options) +{ + VALIDATE_THRESH = 8; + g_GameSettings = conf.gamesettings|options; + conf.mrtdepth = !(conf.gamesettings&GAME_DISABLEMRTDEPTH); + + g_GameSettings |= GAME_PATH3HACK; + g_LastCRC = crc; + + //g_GameSettings |= GAME_PARTIALDEPTH; + +// g_GameSettings |= GAME_DOPARALLELCTX|GAME_XENOSPECHACK; +// VALIDATE_THRESH = 64; +// TEXDESTROY_THRESH = 32; + + switch(crc) { + case 0x54A548B4: // crash n burn + // overbright + if( pd3dDevice != NULL ) { + pd3dDevice->SetPixelShaderConstantF(27, DXVEC4(0.5f, 0.9f/256.0f, 0,1/255.0f), 1); // g_fExactColor + } + break; + + case 0xA3D63039: // xenosaga(j) + case 0x0E7807B2: // xenosaga(u) + g_GameSettings |= GAME_DOPARALLELCTX; + VALIDATE_THRESH = 64; + TEXDESTROY_THRESH = 32; + break; + + case 0x7D2FE035: // espgaluda (j) + VALIDATE_THRESH = 24; + //g_GameSettings |= GAME_BIGVALIDATE; + break; + } + + DEBUG_LOG("ZeroGS: Set game options: 0x%8.8x\n", g_GameSettings); +} + +void CALLBACK GSsetFrameSkip(int frameskip) +{ + s_frameskipping |= frameskip; + if( frameskip && g_nFrameRender > 1 ) { + + for(int i = 0; i < 16; ++i) { + g_GIFPackedRegHandlers[i] = GIFPackedRegHandlerNOP; + } + + // still keep certain handlers + g_GIFPackedRegHandlers[6] = GIFRegHandlerTEX0_1; + g_GIFPackedRegHandlers[7] = GIFRegHandlerTEX0_2; + g_GIFPackedRegHandlers[14] = GIFPackedRegHandlerA_D; + + g_GIFRegHandlers[0] = GIFRegHandlerNOP; + g_GIFRegHandlers[1] = GIFRegHandlerNOP; + g_GIFRegHandlers[2] = GIFRegHandlerNOP; + g_GIFRegHandlers[3] = GIFRegHandlerNOP; + g_GIFRegHandlers[4] = GIFRegHandlerNOP; + g_GIFRegHandlers[5] = GIFRegHandlerNOP; + g_GIFRegHandlers[12] = GIFRegHandlerNOP; + g_GIFRegHandlers[13] = GIFRegHandlerNOP; + g_GIFRegHandlers[26] = GIFRegHandlerNOP; + g_GIFRegHandlers[27] = GIFRegHandlerNOP; + g_nFrameRender = 0; + } + else if( !frameskip && g_nFrameRender <= 0 ) { + g_nFrameRender = 1; + + if( g_GIFTempRegHandlers[0] == NULL ) return; // not init yet + + // restore + memcpy(g_GIFPackedRegHandlers, g_GIFTempRegHandlers, sizeof(g_GIFTempRegHandlers)); + + g_GIFRegHandlers[0] = GIFRegHandlerPRIM; + g_GIFRegHandlers[1] = GIFRegHandlerRGBAQ; + g_GIFRegHandlers[2] = GIFRegHandlerST; + g_GIFRegHandlers[3] = GIFRegHandlerUV; + g_GIFRegHandlers[4] = GIFRegHandlerXYZF2; + g_GIFRegHandlers[5] = GIFRegHandlerXYZ2; + g_GIFRegHandlers[12] = GIFRegHandlerXYZF3; + g_GIFRegHandlers[13] = GIFRegHandlerXYZ2; + g_GIFRegHandlers[26] = GIFRegHandlerPRMODECONT; + g_GIFRegHandlers[27] = GIFRegHandlerPRMODE; + } +} + +void CALLBACK GSreset() { + + memset(&gs, 0, sizeof(gs)); + + ZeroGS::GSStateReset(); + + gs.prac = 1; + prim = &gs._prim[0]; + gs.nTriFanVert = -1; + gs.imageTransfer = -1; + gs.q = 1; +} + +void CALLBACK GSgifSoftReset(u32 mask) +{ + if( mask & 1 ) memset(&gs.path1, 0, sizeof(gs.path1)); + if( mask & 2 ) memset(&gs.path2, 0, sizeof(gs.path2)); + if( mask & 4 ) memset(&gs.path3, 0, sizeof(gs.path3)); + gs.imageTransfer = -1; + gs.q = 1; + gs.nTriFanVert = -1; +} + +s32 CALLBACK GSinit() +{ + memcpy(g_GIFTempRegHandlers, g_GIFPackedRegHandlers, sizeof(g_GIFTempRegHandlers)); + +#ifdef GS_LOG + gsLog = fopen("logs/gsLog.txt", "w"); + if (gsLog == NULL) { + gsLog = fopen("gsLog.txt", "w"); + if (gsLog == NULL) { + SysMessage("Can't create gsLog.txt"); return -1; + } + } + setvbuf(gsLog, NULL, _IONBF, 0); + GS_LOG("GSinit\n"); +#endif + + GSreset(); + GS_LOG("GSinit ok\n"); + + return 0; +} + +void CALLBACK GSshutdown() +{ +#ifdef GS_LOG + fclose(gsLog); +#endif +} + +LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + static int nWindowWidth = 0, nWindowHeight = 0; + + switch( msg ) { + case WM_DESTROY: + PostQuitMessage( 0 ); + return 0; + + case WM_KEYDOWN: +// switch(wParam) { +// case VK_ESCAPE: +// SendMessage(hWnd, WM_DESTROY, 0L, 0L); +// break; +// } + break; + + case WM_ACTIVATE: + + if( wParam != WA_INACTIVE ) { + //DEBUG_LOG("restoring device\n"); + ZeroGS::Restore(); + } + + break; + + case WM_SIZE: + nWindowWidth = lParam&0xffff; + nWindowHeight = lParam>>16; + ZeroGS::ChangeWindowSize(nWindowWidth, nWindowHeight); + + break; + + case WM_SIZING: + // if button is 0, then just released so can resize + if( GetSystemMetrics(SM_SWAPBUTTON) ? !GetAsyncKeyState(VK_RBUTTON) : !GetAsyncKeyState(VK_LBUTTON) ) { + ZeroGS::SetChangeDeviceSize(nWindowWidth, nWindowHeight); + } + break; + + case WM_SETCURSOR: + SetCursor(NULL); + break; + } + + return DefWindowProc( hWnd, msg, wParam, lParam ); +} + +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread) { + + g_GSMultiThreaded = multithread; + + GS_LOG("GSopen\n"); + +#ifdef _DEBUG + g_hCurrentThread = GetCurrentThread(); +#endif + + assert( GSirq != NULL ); + LoadConfig(); + g_GameSettings = 0; + + strcpy(GStitle, Title); + + RECT rc, rcdesktop; + rc.left = 0; rc.top = 0; + rc.right = conf.width; rc.bottom = conf.height; + + WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, + GetModuleHandle(NULL), NULL, NULL, NULL, NULL, + "PS2EMU_ZEROGS", NULL }; + RegisterClassEx( &wc ); + + AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); + + GetWindowRect(GetDesktopWindow(), &rcdesktop); + + GShwnd = CreateWindow( "PS2EMU_ZEROGS", "ZeroGS", WS_OVERLAPPEDWINDOW, + (rcdesktop.right-(rc.right-rc.left))/2, (rcdesktop.bottom-(rc.bottom-rc.top))/2, + rc.right-rc.left, rc.bottom-rc.top, NULL, NULL, wc.hInstance, NULL ); + + if(GShwnd == NULL) { + GS_LOG("Failed to create window. Exiting..."); + return -1; + } + + if( pDsp != NULL ) + *(int*)pDsp = (int)GShwnd; + + DEBUG_LOG("creating zerogs\n"); + //if (conf.record) recOpen(); + if( FAILED(ZeroGS::Create(conf.width, conf.height)) ) + return -1; + + DEBUG_LOG("initialization successful\n"); + + if( FAILED(ZeroGS::InitDeviceObjects()) ) + return -1; + + if( conf.bilinear == 2 ) { + ZeroGS::AddMessage("forced bilinear filtering - on", 1000); + } + else if( conf.bilinear == 1 ) { + ZeroGS::AddMessage("normal bilinear filtering - on", 1000); + } + if( conf.aa ) { + char strtitle[64]; + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa], 1000); + ZeroGS::AddMessage(strtitle); + } + if( conf.options & GSOPTION_WIDESCREEN ) { + ZeroGS::AddMessage("16:9 widescreen - on", 1000); + } + + // set just in case + SetWindowLongPtr(GShwnd, GWLP_WNDPROC, (LPARAM)(WNDPROC)MsgProc); + + ShowWindow( GShwnd, SW_SHOWDEFAULT ); + UpdateWindow( GShwnd ); + SetFocus(GShwnd); + + conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); + conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style + +#ifdef _WIN32 + QueryPerformanceFrequency(&luPerfFreq); +#else + luPerfFreq.QuadPart = 1; +#endif + + GS_LOG("GSopen ok\n"); + + gs.path1.mode = 0; + gs.path2.mode = 0; + gs.path3.mode = 0; + + return 0; +} + +void CALLBACK GSclose() { + ZeroGS::Destroy(1); + + //if (conf.record) recClose(); + +#ifdef _WIN32 + DestroyWindow(GShwnd); +#endif +} + +void CALLBACK GSirqCallback(void (*callback)()) { + GSirq = callback; +} + +void CALLBACK GSwriteCSR(u32 write) +{ + gs.CSRw = write; +} + +void CALLBACK GSchangeSaveState(int newstate, const char* filename) +{ + char str[255]; + sprintf(str, "save state %d", newstate); + ZeroGS::AddMessage(str); +} + +void CALLBACK GSmakeSnapshot(char *path) +{ + FILE *bmpfile; + char filename[256]; + u32 snapshotnr = 0; + + // increment snapshot value & try to get filename + for (;;) { + snapshotnr++; + + sprintf(filename,"%ssnap%03ld.%s", path, snapshotnr, (conf.options&GSOPTION_BMPSNAP)?"bmp":"jpg"); + + bmpfile=fopen(filename,"rb"); + if (bmpfile == NULL) break; + fclose(bmpfile); + } + + // try opening new snapshot file + if((bmpfile=fopen(filename,"wb"))==NULL) { + char strdir[255]; + sprintf(strdir, "%s", path); + CreateDirectory(strdir, NULL); + + if((bmpfile=fopen(filename,"wb"))==NULL) return; + } + + fclose(bmpfile); + + // get the bits + ZeroGS::SaveSnapshot(filename); +} + +int UPDATE_FRAMES = 16; +int g_nFrame = 0; +int g_nRealFrame = 0; +static BOOL g_bHidden = 0; + +float fFPS = 0; + +void CALLBACK GSvsync(int interlace) +{ + GS_LOG("\nGSvsync\n\n"); + + static u32 dwTime = timeGetTime(); + static int nToNextUpdate = 1; + + char strtitle[512]; + + g_nRealFrame++; + + MSG msg; + ZeroMemory( &msg, sizeof(msg) ); + while( 1 ) { + if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) + { + switch( msg.message ) { + case WM_KEYDOWN : + if( msg.wParam == VK_F5 ) { + + if( (GetKeyState(VK_SHIFT)&0x8000) ) { + if( g_nPixelShaderVer == SHADER_20 ) { + conf.bilinear = 0; + sprintf(strtitle, "ps 2.0 doesn't support bilinear filtering"); + } + else { + conf.bilinear = (conf.bilinear+1)%3; + sprintf(strtitle, "bilinear filtering - %s", pbilinear[conf.bilinear]); + } + } + else { + conf.interlace++; + if( conf.interlace > 2 ) conf.interlace = 0; + if( conf.interlace < 2 ) sprintf(strtitle, "interlace on - mode %d", conf.interlace); + else sprintf(strtitle, "interlace off"); + } + + ZeroGS::AddMessage(strtitle); + SaveConfig(); + } + else if( msg.wParam == VK_F6 ) { + + if( (GetKeyState(VK_SHIFT)&0x8000) ) { + conf.aa--; // -1 + if( conf.aa > 4) conf.aa = 4; + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa]); + ZeroGS::SetAA(conf.aa); + } + else { + conf.aa++; + if( conf.aa > 4 ) conf.aa = 0; + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa]); + ZeroGS::SetAA(conf.aa); + } + + ZeroGS::AddMessage(strtitle); + SaveConfig(); + } + else if( msg.wParam == VK_F7 ) { + + if( (GetKeyState(VK_SHIFT)&0x8000) ) { + extern BOOL g_bDisplayFPS; + g_bDisplayFPS ^= 1; + } + else { + conf.options ^= GSOPTION_WIREFRAME; + SETRS(D3DRS_FILLMODE, (conf.options&GSOPTION_WIREFRAME)?D3DFILL_WIREFRAME:D3DFILL_SOLID); + sprintf(strtitle, "wireframe rendering - %s", (conf.options&GSOPTION_WIREFRAME)?"on":"off"); +// conf.options ^= GSOPTION_CAPTUREAVI; +// if( conf.options & GSOPTION_CAPTUREAVI ) ZeroGS::StartCapture(); +// else ZeroGS::StopCapture(); +// +// sprintf(strtitle, "capture avi (zerogs_dump.avi) - %s", (conf.options&GSOPTION_CAPTUREAVI) ? "on" : "off"); +// ZeroGS::AddMessage(strtitle); +// SaveConfig(); + } + } + else if( msg.wParam == VK_F9 ) { + + if( (GetKeyState(VK_SHIFT)&0x8000) ) { + conf.options ^= GSOPTION_WIDESCREEN; + sprintf(strtitle, "16:9 widescreen - %s", (conf.options&GSOPTION_WIDESCREEN)?"on":"off"); + } + else { + g_GameSettings ^= GAME_PATH3HACK; + sprintf(strtitle, "path3 hack - %s", (g_GameSettings&GAME_PATH3HACK) ? "on" : "off"); + } + ZeroGS::AddMessage(strtitle); + } + else if( msg.wParam == VK_ESCAPE ) { + + if( conf.options & GSOPTION_FULLSCREEN ) { + // destroy that msg + conf.options &= ~GSOPTION_FULLSCREEN; + conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); + conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style + ZeroGS::ChangeDeviceSize(conf.width, conf.height); + UpdateWindow(GShwnd); + continue; // so that msg doesn't get sent + } + else { + SendMessage(GShwnd, WM_DESTROY, 0, 0); + g_bHidden = 1; + return; + } + } + + break; + } + + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + else + break; + } + + if( (GetKeyState(VK_MENU)&0x8000) && (GetKeyState(VK_RETURN)&0x8000) ) { + conf.options ^= GSOPTION_FULLSCREEN; + + if( conf.options & GSOPTION_FULLSCREEN ) { + conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); + conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style + } + + ZeroGS::SetChangeDeviceSize( + (conf.options&GSOPTION_FULLSCREEN) ? 1280 : conf.width, + (conf.options&GSOPTION_FULLSCREEN) ? 960 : conf.height); + } + +// if( conf.fullscreen && (GetKeyState(VK_ESCAPE)&0x8000)) { +// conf.fullscreen &= ~GSOPTION_FULLSCREEN; +// ZeroGS::SetChangeDeviceSize(conf.width, conf.height); +// } + + //if( conf.interlace && g_nGenVars + g_nTexVars + g_nAlphaVars + g_nResolve == 0 ) + // CSR->FIELD = 0; // 0 should always be the repeating at 0 + + ZeroGS::RenderCRTC(!interlace); + + if( --nToNextUpdate <= 0 ) { + + u32 d = timeGetTime(); + fFPS = UPDATE_FRAMES * 1000.0f / (float)max(d-dwTime,1); + dwTime = d; + g_nFrame += UPDATE_FRAMES; + +#ifdef RELEASE_TO_PUBLIC + const char* g_pShaders[4] = { "ps 2.0", "ps 2.0a", "ps 2.0b", "ps 3.0" }; + + _snprintf(strtitle, 512, "%s 0.%d.%d %.1f fps | %s%s%s%s %s (%.1f)", libraryName, build, minor, fFPS, + (conf.interlace < 2) ? "interlace | " : "", + conf.bilinear ? (conf.bilinear==2?"forced bilinear | ":"bilinear | ") : "", + conf.aa ? s_aa[conf.aa] : "", + (g_GameSettings&GAME_FFXHACK) ? "ffxhack | " : "", + g_pShaders[g_nPixelShaderVer], (ppf&0xfffff)/(float)UPDATE_FRAMES); +#else + _snprintf(strtitle, 512, "%d | %.1f fps (sk:%d%%) | g: %.1f, t: %.1f, a: %.1f, r: %.1f | p: %.1f | tex: %d %d (%d kbpf)", g_nFrame, fFPS, + 100*g_nFramesSkipped/g_nFrame, + g_nGenVars/(float)UPDATE_FRAMES, g_nTexVars/(float)UPDATE_FRAMES, g_nAlphaVars/(float)UPDATE_FRAMES, + g_nResolve/(float)UPDATE_FRAMES, (ppf&0xfffff)/(float)UPDATE_FRAMES, + ZeroGS::g_MemTargs.listTargets.size(), ZeroGS::g_MemTargs.listClearedTargets.size(), g_TransferredToGPU>>10); + //_snprintf(strtitle, 512, "%x %x", *(int*)(ZeroGS::g_pbyGSMemory + 256 * 0x3e0c + 4), *(int*)(ZeroGS::g_pbyGSMemory + 256 * 0x3e04 + 4)); + +#endif + + if( !(conf.options&GSOPTION_FULLSCREEN) ) + SetWindowText(GShwnd, strtitle); + + if( fFPS < 16 ) UPDATE_FRAMES = 4; + else if( fFPS < 32 ) UPDATE_FRAMES = 8; + else UPDATE_FRAMES = 16; + + nToNextUpdate = UPDATE_FRAMES; + + g_TransferredToGPU = 0; + g_nGenVars = 0; + g_nTexVars = 0; + g_nAlphaVars = 0; + g_nResolve = 0; + ppf = 0; + g_nFramesSkipped = 0; + } +} + +void GIFtag(pathInfo *path, u32 *data) { + + path->tag.nloop = data[0] & 0x7fff; + path->tag.eop = (data[0] >> 15) & 0x1; + u32 tagpre = (data[1] >> 14) & 0x1; + u32 tagprim = (data[1] >> 15) & 0x7ff; + u32 tagflg = (data[1] >> 26) & 0x3; + path->tag.nreg = (data[1] >> 28)<<2; + + if (path->tag.nreg == 0) path->tag.nreg = 64; + + gs.q = 1; + +// GS_LOG("GIFtag: %8.8lx_%8.8lx_%8.8lx_%8.8lx: EOP=%d, NLOOP=%x, FLG=%x, NREG=%d, PRE=%d\n", +// data[3], data[2], data[1], data[0], +// path->tag.eop, path->tag.nloop, tagflg, path->tag.nreg, tagpre); + + path->mode = tagflg+1; + + switch (tagflg) { + case 0x0: + path->regs = *(u64 *)(data+2); + path->regn = 0; + if (tagpre) + GIFRegHandlerPRIM((u32*)&tagprim); + + break; + + case 0x1: + path->regs = *(u64 *)(data+2); + path->regn = 0; + break; + } +} + +void _GSgifPacket(pathInfo *path, u32 *pMem) { // 128bit + + int reg = (int)((path->regs >> path->regn) & 0xf); + g_GIFPackedRegHandlers[reg](pMem); + + path->regn += 4; + if (path->tag.nreg == path->regn) { + path->regn = 0; + path->tag.nloop--; + } +} + +void _GSgifRegList(pathInfo *path, u32 *pMem) { // 64bit + int reg; + + reg = (int)((path->regs >> path->regn) & 0xf); + + g_GIFRegHandlers[reg](pMem); + path->regn += 4; + if (path->tag.nreg == path->regn) { + path->regn = 0; + path->tag.nloop--; + } +} + +//static pathInfo* s_pLastPath = &gs.path3; +static int nPath3Hack = 0; + +void CALLBACK GSgetLastTag(u64* ptag) +{ + *(u32*)ptag = nPath3Hack; + nPath3Hack = 0; +} + +void _GSgifTransfer(pathInfo *path, u32 *pMem, u32 size) +{ +#ifdef _DEBUG + assert( g_hCurrentThread == GetCurrentThread() ); +#endif + + //s_pLastPath = path; + //BOOL bAfter0Tag = 0; + +// if( conf.log & 0x20 ) { +// __Log("%d: %x:%x\n", (path==&gs.path3)?3:(path==&gs.path2?2:1), pMem, size); +// for(int i = 0; i < size; i++) { +// __Log("%x %x %x %x\n", pMem[4*i+0], pMem[4*i+1], pMem[4*i+2], pMem[4*i+3]); +// } +// } + + while(size > 0) + { + //LOG(_T("Transfer(%08x, %d) START\n"), pMem, size); + if (path->tag.nloop == 0) + { + GIFtag(path, pMem); + pMem+= 4; + size--; + + if ((g_GameSettings & GAME_PATH3HACK) && path == &gs.path3 && gs.path3.tag.eop) + nPath3Hack = 1; + + if (path == &gs.path1) + { + // if too much data, just ignore + if (path->tag.nloop * (path->tag.nreg / 4) > (int)size * (path->mode==2?2:1)) + { + static int lasttime = 0; + if( timeGetTime() - lasttime > 5000 ) + { + ERROR_LOG("VU1 too much data, ignore if gfx are fine\n"); + lasttime = timeGetTime(); + } + path->tag.nloop = 0; + return; + } + + if (path->mode == 1) + { + // check if 0xb is in any reg, if yes, exit (kh2) + for(int i = 0; i < path->tag.nreg; i += 4) + { + if (((path->regs >> i)&0xf) == 11) + { + static int lasttime = 0; + if( timeGetTime() - lasttime > 5000 ) + { + ERROR_LOG("Invalid unpack type\n"); + lasttime = timeGetTime(); + } + path->tag.nloop = 0; + return; + } + } + } + } + + if(path->tag.nloop == 0 ) + { + if( path == &gs.path1 ) + { + // ffx hack + if( g_GameSettings & GAME_FFXHACK ) + { + if( path->tag.eop ) + return; + continue; + } + + return; + } + + if( !path->tag.eop ) + { + //DEBUG_LOG("continuing from eop\n"); + continue; + } + + break; + } + } + + switch(path->mode) { + case 1: // PACKED + { + assert( path->tag.nloop > 0 ); + for(; size > 0; size--, pMem += 4) + { + int reg = (int)((path->regs >> path->regn) & 0xf); + + g_GIFPackedRegHandlers[reg](pMem); + + path->regn += 4; + if (path->tag.nreg == path->regn) + { + path->regn = 0; + if( path->tag.nloop-- <= 1 ) + { + size--; + pMem += 4; + break; + } + } + } + break; + } + case 2: // REGLIST + { + //GS_LOG("%8.8x%8.8x %d L\n", ((u32*)&gs.regs)[1], *(u32*)&gs.regs, path->tag.nreg/4); + assert( path->tag.nloop > 0 ); + size *= 2; + for(; size > 0; pMem+= 2, size--) + { + int reg = (int)((path->regs >> path->regn) & 0xf); + g_GIFRegHandlers[reg](pMem); + path->regn += 4; + if (path->tag.nreg == path->regn) + { + path->regn = 0; + if( path->tag.nloop-- <= 1 ) + { + size--; + pMem += 2; + break; + } + } + } + + if( size & 1 ) pMem += 2; + size /= 2; + break; + } + case 3: // GIF_IMAGE (FROM_VFRAM) + case 4: + { + if(gs.imageTransfer >= 0 && gs.imageTransfer <= 1) + { + int process = min((int)size, path->tag.nloop); + + if( process > 0 ) + { + if (gs.imageTransfer) + ZeroGS::TransferLocalHost(pMem, process); + else + ZeroGS::TransferHostLocal(pMem, process*4); + + path->tag.nloop -= process; + pMem += process*4; size -= process; + + assert( size == 0 || path->tag.nloop == 0 ); + } + break; + } + else + { + // simulate + int process = min((int)size, path->tag.nloop); + path->tag.nloop -= process; + pMem += process*4; size -= process; + } + + break; + } + default: // GIF_IMAGE + GS_LOG("*** WARNING **** Unexpected GIFTag flag\n"); + assert(0); + path->tag.nloop = 0; + break; + + } + + if( path == &gs.path1 && path->tag.eop ) + return; + } +} + +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size) +{ + //GS_LOG("GSgifTransfer2 size = %lx (mode %d, gs.path2.tag.nloop = %d)\n", size, gs.path2.mode, gs.path2.tag.nloop); + + _GSgifTransfer(&gs.path2, pMem, size); +} + +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size) +{ + //GS_LOG("GSgifTransfer3 size = %lx (mode %d, gs.path3.tag.nloop = %d)\n", size, gs.path3.mode, gs.path3.tag.nloop); + + nPath3Hack = 0; + _GSgifTransfer(&gs.path3, pMem, size); +} + +static int count = 0; +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr) +{ + pathInfo *path = &gs.path1; + + //GS_LOG("GSgifTransfer1 0x%x (mode %d)\n", addr, path->mode); + + addr &= 0x3fff; + +#ifdef _DEBUG + PRIM_LOG("count: %d\n", count); + count++; +#endif + + gs.path1.tag.nloop = 0; + gs.path1.tag.eop = 0; + _GSgifTransfer(&gs.path1, (u32*)((u8*)pMem+addr), (0x4000-addr)/16); + + if( !gs.path1.tag.eop && gs.path1.tag.nloop > 0 ) { + assert( (addr&0xf) == 0 ); //BUG + gs.path1.tag.nloop = 0; + ERROR_LOG("Transfer1 - 2\n"); + return; + } +} + +void CALLBACK GSreadFIFO(u64 *pMem) +{ + //GS_LOG("GSreadFIFO\n"); + + ZeroGS::TransferLocalHost((u32*)pMem, 1); +} + +void CALLBACK GSreadFIFO2(u64 *pMem, int qwc) +{ + //GS_LOG("GSreadFIFO2\n"); + + ZeroGS::TransferLocalHost((u32*)pMem, qwc); +} + +int CALLBACK GSsetupRecording(int start, void* pData) +{ + if( start ) { + if( conf.options & GSOPTION_CAPTUREAVI ) + return 1; + if( !ZeroGS::StartCapture() ) + return 0; + conf.options |= GSOPTION_CAPTUREAVI; + DEBUG_LOG("ZeroGS: started recording at zerogs.avi\n"); + } + else { + if( !(conf.options & GSOPTION_CAPTUREAVI) ) + return 1; + conf.options &= ~GSOPTION_CAPTUREAVI; + ZeroGS::StopCapture(); + DEBUG_LOG("ZeroGS: stopped recording\n"); + } + + return 1; +} + +s32 CALLBACK GSfreeze(int mode, freezeData *data) +{ + switch (mode) + { + case FREEZE_LOAD: + if (!ZeroGS::Load(data->data)) DEBUG_LOG("GS: Bad load format!"); + g_nRealFrame += 100; + break; + case FREEZE_SAVE: + ZeroGS::Save(data->data); + break; + case FREEZE_SIZE: + data->size = ZeroGS::Save(NULL); + break; + default: + break; + } + + return 0; +} + +extern HINSTANCE hInst; +void CALLBACK GSconfigure() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); + + if( g_nPixelShaderVer == SHADER_20 ) + conf.bilinear = 0; +} diff --git a/plugins/zerogs/dx/Mem.cpp b/plugins/zerogs/dx/Mem.cpp index 4bcc7dcf02..91554f437b 100644 --- a/plugins/zerogs/dx/Mem.cpp +++ b/plugins/zerogs/dx/Mem.cpp @@ -1,904 +1,904 @@ -/* ZeroGS - * Copyright (C) 2005-2006 zerofrog@gmail.com - * - * 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 - -#include "GS.h" -#include "Mem.h" -#include "zerogs.h" -#include "targets.h" -#include "x86.h" - -u32 g_blockTable32[4][8] = { - { 0, 1, 4, 5, 16, 17, 20, 21}, - { 2, 3, 6, 7, 18, 19, 22, 23}, - { 8, 9, 12, 13, 24, 25, 28, 29}, - { 10, 11, 14, 15, 26, 27, 30, 31} -}; - -u32 g_blockTable32Z[4][8] = { - { 24, 25, 28, 29, 8, 9, 12, 13}, - { 26, 27, 30, 31, 10, 11, 14, 15}, - { 16, 17, 20, 21, 0, 1, 4, 5}, - { 18, 19, 22, 23, 2, 3, 6, 7} -}; - -u32 g_blockTable16[8][4] = { - { 0, 2, 8, 10 }, - { 1, 3, 9, 11 }, - { 4, 6, 12, 14 }, - { 5, 7, 13, 15 }, - { 16, 18, 24, 26 }, - { 17, 19, 25, 27 }, - { 20, 22, 28, 30 }, - { 21, 23, 29, 31 } -}; - -u32 g_blockTable16S[8][4] = { - { 0, 2, 16, 18 }, - { 1, 3, 17, 19 }, - { 8, 10, 24, 26 }, - { 9, 11, 25, 27 }, - { 4, 6, 20, 22 }, - { 5, 7, 21, 23 }, - { 12, 14, 28, 30 }, - { 13, 15, 29, 31 } -}; - -u32 g_blockTable16Z[8][4] = { - { 24, 26, 16, 18 }, - { 25, 27, 17, 19 }, - { 28, 30, 20, 22 }, - { 29, 31, 21, 23 }, - { 8, 10, 0, 2 }, - { 9, 11, 1, 3 }, - { 12, 14, 4, 6 }, - { 13, 15, 5, 7 } -}; - -u32 g_blockTable16SZ[8][4] = { - { 24, 26, 8, 10 }, - { 25, 27, 9, 11 }, - { 16, 18, 0, 2 }, - { 17, 19, 1, 3 }, - { 28, 30, 12, 14 }, - { 29, 31, 13, 15 }, - { 20, 22, 4, 6 }, - { 21, 23, 5, 7 } -}; - -u32 g_blockTable8[4][8] = { - { 0, 1, 4, 5, 16, 17, 20, 21}, - { 2, 3, 6, 7, 18, 19, 22, 23}, - { 8, 9, 12, 13, 24, 25, 28, 29}, - { 10, 11, 14, 15, 26, 27, 30, 31} -}; - -u32 g_blockTable4[8][4] = { - { 0, 2, 8, 10 }, - { 1, 3, 9, 11 }, - { 4, 6, 12, 14 }, - { 5, 7, 13, 15 }, - { 16, 18, 24, 26 }, - { 17, 19, 25, 27 }, - { 20, 22, 28, 30 }, - { 21, 23, 29, 31 } -}; - -u32 g_columnTable32[8][8] = { - { 0, 1, 4, 5, 8, 9, 12, 13 }, - { 2, 3, 6, 7, 10, 11, 14, 15 }, - { 16, 17, 20, 21, 24, 25, 28, 29 }, - { 18, 19, 22, 23, 26, 27, 30, 31 }, - { 32, 33, 36, 37, 40, 41, 44, 45 }, - { 34, 35, 38, 39, 42, 43, 46, 47 }, - { 48, 49, 52, 53, 56, 57, 60, 61 }, - { 50, 51, 54, 55, 58, 59, 62, 63 }, -}; - -u32 g_columnTable16[8][16] = { - { 0, 2, 8, 10, 16, 18, 24, 26, - 1, 3, 9, 11, 17, 19, 25, 27 }, - { 4, 6, 12, 14, 20, 22, 28, 30, - 5, 7, 13, 15, 21, 23, 29, 31 }, - { 32, 34, 40, 42, 48, 50, 56, 58, - 33, 35, 41, 43, 49, 51, 57, 59 }, - { 36, 38, 44, 46, 52, 54, 60, 62, - 37, 39, 45, 47, 53, 55, 61, 63 }, - { 64, 66, 72, 74, 80, 82, 88, 90, - 65, 67, 73, 75, 81, 83, 89, 91 }, - { 68, 70, 76, 78, 84, 86, 92, 94, - 69, 71, 77, 79, 85, 87, 93, 95 }, - { 96, 98, 104, 106, 112, 114, 120, 122, - 97, 99, 105, 107, 113, 115, 121, 123 }, - { 100, 102, 108, 110, 116, 118, 124, 126, - 101, 103, 109, 111, 117, 119, 125, 127 }, -}; - -u32 g_columnTable8[16][16] = { - { 0, 4, 16, 20, 32, 36, 48, 52, // column 0 - 2, 6, 18, 22, 34, 38, 50, 54 }, - { 8, 12, 24, 28, 40, 44, 56, 60, - 10, 14, 26, 30, 42, 46, 58, 62 }, - { 33, 37, 49, 53, 1, 5, 17, 21, - 35, 39, 51, 55, 3, 7, 19, 23 }, - { 41, 45, 57, 61, 9, 13, 25, 29, - 43, 47, 59, 63, 11, 15, 27, 31 }, - { 96, 100, 112, 116, 64, 68, 80, 84, // column 1 - 98, 102, 114, 118, 66, 70, 82, 86 }, - { 104, 108, 120, 124, 72, 76, 88, 92, - 106, 110, 122, 126, 74, 78, 90, 94 }, - { 65, 69, 81, 85, 97, 101, 113, 117, - 67, 71, 83, 87, 99, 103, 115, 119 }, - { 73, 77, 89, 93, 105, 109, 121, 125, - 75, 79, 91, 95, 107, 111, 123, 127 }, - { 128, 132, 144, 148, 160, 164, 176, 180, // column 2 - 130, 134, 146, 150, 162, 166, 178, 182 }, - { 136, 140, 152, 156, 168, 172, 184, 188, - 138, 142, 154, 158, 170, 174, 186, 190 }, - { 161, 165, 177, 181, 129, 133, 145, 149, - 163, 167, 179, 183, 131, 135, 147, 151 }, - { 169, 173, 185, 189, 137, 141, 153, 157, - 171, 175, 187, 191, 139, 143, 155, 159 }, - { 224, 228, 240, 244, 192, 196, 208, 212, // column 3 - 226, 230, 242, 246, 194, 198, 210, 214 }, - { 232, 236, 248, 252, 200, 204, 216, 220, - 234, 238, 250, 254, 202, 206, 218, 222 }, - { 193, 197, 209, 213, 225, 229, 241, 245, - 195, 199, 211, 215, 227, 231, 243, 247 }, - { 201, 205, 217, 221, 233, 237, 249, 253, - 203, 207, 219, 223, 235, 239, 251, 255 }, -}; - -u32 g_columnTable4[16][32] = { - { 0, 8, 32, 40, 64, 72, 96, 104, // column 0 - 2, 10, 34, 42, 66, 74, 98, 106, - 4, 12, 36, 44, 68, 76, 100, 108, - 6, 14, 38, 46, 70, 78, 102, 110 }, - { 16, 24, 48, 56, 80, 88, 112, 120, - 18, 26, 50, 58, 82, 90, 114, 122, - 20, 28, 52, 60, 84, 92, 116, 124, - 22, 30, 54, 62, 86, 94, 118, 126 }, - { 65, 73, 97, 105, 1, 9, 33, 41, - 67, 75, 99, 107, 3, 11, 35, 43, - 69, 77, 101, 109, 5, 13, 37, 45, - 71, 79, 103, 111, 7, 15, 39, 47 }, - { 81, 89, 113, 121, 17, 25, 49, 57, - 83, 91, 115, 123, 19, 27, 51, 59, - 85, 93, 117, 125, 21, 29, 53, 61, - 87, 95, 119, 127, 23, 31, 55, 63 }, - { 192, 200, 224, 232, 128, 136, 160, 168, // column 1 - 194, 202, 226, 234, 130, 138, 162, 170, - 196, 204, 228, 236, 132, 140, 164, 172, - 198, 206, 230, 238, 134, 142, 166, 174 }, - { 208, 216, 240, 248, 144, 152, 176, 184, - 210, 218, 242, 250, 146, 154, 178, 186, - 212, 220, 244, 252, 148, 156, 180, 188, - 214, 222, 246, 254, 150, 158, 182, 190 }, - { 129, 137, 161, 169, 193, 201, 225, 233, - 131, 139, 163, 171, 195, 203, 227, 235, - 133, 141, 165, 173, 197, 205, 229, 237, - 135, 143, 167, 175, 199, 207, 231, 239 }, - { 145, 153, 177, 185, 209, 217, 241, 249, - 147, 155, 179, 187, 211, 219, 243, 251, - 149, 157, 181, 189, 213, 221, 245, 253, - 151, 159, 183, 191, 215, 223, 247, 255 }, - { 256, 264, 288, 296, 320, 328, 352, 360, // column 2 - 258, 266, 290, 298, 322, 330, 354, 362, - 260, 268, 292, 300, 324, 332, 356, 364, - 262, 270, 294, 302, 326, 334, 358, 366 }, - { 272, 280, 304, 312, 336, 344, 368, 376, - 274, 282, 306, 314, 338, 346, 370, 378, - 276, 284, 308, 316, 340, 348, 372, 380, - 278, 286, 310, 318, 342, 350, 374, 382 }, - { 321, 329, 353, 361, 257, 265, 289, 297, - 323, 331, 355, 363, 259, 267, 291, 299, - 325, 333, 357, 365, 261, 269, 293, 301, - 327, 335, 359, 367, 263, 271, 295, 303 }, - { 337, 345, 369, 377, 273, 281, 305, 313, - 339, 347, 371, 379, 275, 283, 307, 315, - 341, 349, 373, 381, 277, 285, 309, 317, - 343, 351, 375, 383, 279, 287, 311, 319 }, - { 448, 456, 480, 488, 384, 392, 416, 424, // column 3 - 450, 458, 482, 490, 386, 394, 418, 426, - 452, 460, 484, 492, 388, 396, 420, 428, - 454, 462, 486, 494, 390, 398, 422, 430 }, - { 464, 472, 496, 504, 400, 408, 432, 440, - 466, 474, 498, 506, 402, 410, 434, 442, - 468, 476, 500, 508, 404, 412, 436, 444, - 470, 478, 502, 510, 406, 414, 438, 446 }, - { 385, 393, 417, 425, 449, 457, 481, 489, - 387, 395, 419, 427, 451, 459, 483, 491, - 389, 397, 421, 429, 453, 461, 485, 493, - 391, 399, 423, 431, 455, 463, 487, 495 }, - { 401, 409, 433, 441, 465, 473, 497, 505, - 403, 411, 435, 443, 467, 475, 499, 507, - 405, 413, 437, 445, 469, 477, 501, 509, - 407, 415, 439, 447, 471, 479, 503, 511 }, -}; - -u32 g_pageTable32[32][64]; -u32 g_pageTable32Z[32][64]; -u32 g_pageTable16[64][64]; -u32 g_pageTable16S[64][64]; -u32 g_pageTable16Z[64][64]; -u32 g_pageTable16SZ[64][64]; -u32 g_pageTable8[64][128]; -u32 g_pageTable4[128][128]; - -BLOCK m_Blocks[0x40]; // do so blocks are indexable -static PCSX2_ALIGNED16(u32 tempblock[64]); - -#define DSTPSM gs.dstbuf.psm - -#define START_HOSTLOCAL() \ - assert( gs.imageTransfer == 0 ); \ - u8* pstart = ZeroGS::g_pbyGSMemory + gs.dstbuf.bp*256; \ - \ - const u8* pendbuf = (const u8*)pbyMem + nQWordSize*4; \ - int i = gs.imageY, j = gs.imageX; \ - -extern BOOL g_bSaveTrans; - -#define END_HOSTLOCAL() \ -End: \ - if( i >= gs.imageEndY ) { \ - assert( gs.imageTransfer == -1 || i == gs.imageEndY ); \ - gs.imageTransfer = -1; \ - /*int start, end; \ - ZeroGS::GetRectMemAddress(start, end, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); \ - ZeroGS::g_MemTargs.ClearRange(start, end);*/ \ - } \ - else { \ - /* update new params */ \ - gs.imageY = i; \ - gs.imageX = j; \ - } \ - -// transfers whole rows -#define TRANSMIT_HOSTLOCAL_Y_(psm, T, widthlimit, endY) { \ - assert( (nSize%widthlimit) == 0 && widthlimit <= 4 ); \ - if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { \ - /*GS_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM);*/ \ - for(; i < endY; ++i) { \ - for(; j < gs.imageEndX && nSize > 0; j += 1, nSize -= 1, pbuf += 1) { \ - /* write as many pixel at one time as possible */ \ - writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ - } \ - } \ - } \ - for(; i < endY; ++i) { \ - for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += widthlimit) { \ - /* write as many pixel at one time as possible */ \ - if( nSize < widthlimit ) goto End; \ - writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ - \ - if( widthlimit > 1 ) { \ - writePixel##psm##_0(pstart, (j+1)%2048, i%2048, pbuf[1], gs.dstbuf.bw); \ - \ - if( widthlimit > 2 ) { \ - writePixel##psm##_0(pstart, (j+2)%2048, i%2048, pbuf[2], gs.dstbuf.bw); \ - \ - if( widthlimit > 3 ) { \ - writePixel##psm##_0(pstart, (j+3)%2048, i%2048, pbuf[3], gs.dstbuf.bw); \ - } \ - } \ - } \ - } \ - \ - if( j >= gs.imageEndX ) { assert(j == gs.imageEndX); j = gs.trxpos.dx; } \ - else { assert( gs.imageTransfer == -1 || nSize*sizeof(T)/4 == 0 ); goto End; } \ - } \ -} \ - -// transmit until endX, don't check size since it has already been prevalidated -#define TRANSMIT_HOSTLOCAL_X_(psm, T, widthlimit, blockheight, startX) { \ - for(int tempi = 0; tempi < blockheight; ++tempi) { \ - for(j = startX; j < gs.imageEndX; j++, pbuf++) { \ - writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, pbuf[0], gs.dstbuf.bw); \ - } \ - pbuf += pitch-fracX; \ - } \ -} \ - -// transfers whole rows -#define TRANSMIT_HOSTLOCAL_Y_24(psm, T, widthlimit, endY) { \ - if( widthlimit != 8 || ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) { \ - /*GS_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM);*/ \ - for(; i < endY; ++i) { \ - for(; j < gs.imageEndX && nSize > 0; j += 1, nSize -= 1, pbuf += 3) { \ - writePixel##psm##_0(pstart, j%2048, i%2048, *(u32*)(pbuf), gs.dstbuf.bw); \ - } \ - \ - if( j >= gs.imageEndX ) { assert(gs.imageTransfer == -1 || j == gs.imageEndX); j = gs.trxpos.dx; } \ - else { assert( gs.imageTransfer == -1 || nSize == 0 ); goto End; } \ - } \ - } \ - else { \ - assert( /*(nSize%widthlimit) == 0 &&*/ widthlimit == 8 ); \ - for(; i < endY; ++i) { \ - for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += 3*widthlimit) { \ - if( nSize < widthlimit ) goto End; \ - /* write as many pixel at one time as possible */ \ - writePixel##psm##_0(pstart, j%2048, i%2048, *(u32*)(pbuf+0), gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *(u32*)(pbuf+3), gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *(u32*)(pbuf+6), gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *(u32*)(pbuf+9), gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *(u32*)(pbuf+12), gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *(u32*)(pbuf+15), gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *(u32*)(pbuf+18), gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *(u32*)(pbuf+21), gs.dstbuf.bw); \ - } \ - \ - if( j >= gs.imageEndX ) { assert(gs.imageTransfer == -1 || j == gs.imageEndX); j = gs.trxpos.dx; } \ - else { \ - if( nSize < 0 ) { \ - /* extracted too much */ \ - assert( (nSize%3)==0 && nSize > -24 ); \ - j += nSize/3; \ - nSize = 0; \ - } \ - assert( gs.imageTransfer == -1 || nSize == 0 ); \ - goto End; \ - } \ - } \ - } \ -} \ - -// transmit until endX, don't check size since it has already been prevalidated -#define TRANSMIT_HOSTLOCAL_X_24(psm, T, widthlimit, blockheight, startX) { \ - for(int tempi = 0; tempi < blockheight; ++tempi) { \ - for(j = startX; j < gs.imageEndX; j++, pbuf += 3) { \ - writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, *(u32*)pbuf, gs.dstbuf.bw); \ - } \ - pbuf += 3*(pitch-fracX); \ - } \ -} \ - -// meant for 4bit transfers -#define TRANSMIT_HOSTLOCAL_Y_4(psm, T, widthlimit, endY) { \ - for(; i < endY; ++i) { \ - for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit) { \ - /* write as many pixel at one time as possible */ \ - writePixel##psm##_0(pstart, j%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ - pbuf++; \ - if( widthlimit > 2 ) { \ - writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ - pbuf++; \ - \ - if( widthlimit > 4 ) { \ - writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ - pbuf++; \ - \ - if( widthlimit > 6 ) { \ - writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ - pbuf++; \ - } \ - } \ - } \ - } \ - \ - if( j >= gs.imageEndX ) { j = gs.trxpos.dx; } \ - else { assert( gs.imageTransfer == -1 || (nSize/32) == 0 ); goto End; } \ - } \ -} \ - -// transmit until endX, don't check size since it has already been prevalidated -#define TRANSMIT_HOSTLOCAL_X_4(psm, T, widthlimit, blockheight, startX) { \ - for(int tempi = 0; tempi < blockheight; ++tempi) { \ - for(j = startX; j < gs.imageEndX; j+=2, pbuf++) { \ - writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, pbuf[0]&0x0f, gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+1)%2048, (i+tempi)%2048, pbuf[0]>>4, gs.dstbuf.bw); \ - } \ - pbuf += (pitch-fracX)/2; \ - } \ -} \ - -// calculate pitch in source buffer -#define TRANSMIT_PITCH_(pitch, T) (pitch*sizeof(T)) -#define TRANSMIT_PITCH_24(pitch, T) (pitch*3) -#define TRANSMIT_PITCH_4(pitch, T) (pitch/2) - -// special swizzle macros -#define SwizzleBlock24(dst, src, pitch) { \ - u8* pnewsrc = src; \ - u32* pblock = tempblock; \ - \ - for(int by = 0; by < 7; ++by, pblock += 8, pnewsrc += pitch-24) { \ - for(int bx = 0; bx < 8; ++bx, pnewsrc += 3) { \ - pblock[bx] = *(u32*)pnewsrc; \ - } \ - } \ - for(int bx = 0; bx < 7; ++bx, pnewsrc += 3) { \ - /* might be 1 byte out of bounds of GS memory */ \ - pblock[bx] = *(u32*)pnewsrc; \ - } \ - /* do 3 bytes for the last copy */ \ - *((u8*)pblock+28) = pnewsrc[0]; \ - *((u8*)pblock+29) = pnewsrc[1]; \ - *((u8*)pblock+30) = pnewsrc[2]; \ - SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0x00ffffff); \ -} \ - -#define SwizzleBlock24u SwizzleBlock24 - -#define SwizzleBlock8H(dst, src, pitch) { \ - u8* pnewsrc = src; \ - u32* pblock = tempblock; \ - \ - for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ - u32 u = *(u32*)pnewsrc; \ - pblock[0] = u<<24; \ - pblock[1] = u<<16; \ - pblock[2] = u<<8; \ - pblock[3] = u; \ - u = *(u32*)(pnewsrc+4); \ - pblock[4] = u<<24; \ - pblock[5] = u<<16; \ - pblock[6] = u<<8; \ - pblock[7] = u; \ - } \ - SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0xff000000); \ -} \ - -#define SwizzleBlock8Hu SwizzleBlock8H - -#define SwizzleBlock4HH(dst, src, pitch) { \ - u8* pnewsrc = src; \ - u32* pblock = tempblock; \ - \ - for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ - u32 u = *(u32*)pnewsrc; \ - pblock[0] = u<<28; \ - pblock[1] = u<<24; \ - pblock[2] = u<<20; \ - pblock[3] = u<<16; \ - pblock[4] = u<<12; \ - pblock[5] = u<<8; \ - pblock[6] = u<<4; \ - pblock[7] = u; \ - } \ - SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0xf0000000); \ -} \ - -#define SwizzleBlock4HHu SwizzleBlock4HH - -#define SwizzleBlock4HL(dst, src, pitch) { \ - u8* pnewsrc = src; \ - u32* pblock = tempblock; \ - \ - for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ - u32 u = *(u32*)pnewsrc; \ - pblock[0] = u<<24; \ - pblock[1] = u<<20; \ - pblock[2] = u<<16; \ - pblock[3] = u<<12; \ - pblock[4] = u<<8; \ - pblock[5] = u<<4; \ - pblock[6] = u; \ - pblock[7] = u>>4; \ - } \ - SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0x0f000000); \ -} \ - -#define SwizzleBlock4HLu SwizzleBlock4HL - -// ------------------------ -// | Y | -// ------------------------ -// | block | | -// | aligned area | X | -// | | | -// ------------------------ -// | Y | -// ------------------------ -#define DEFINE_TRANSFERLOCAL(psm, T, widthlimit, blockbits, blockwidth, blockheight, TransSfx, SwizzleBlock) \ -int TransferHostLocal##psm(const void* pbyMem, u32 nQWordSize) \ -{ \ - START_HOSTLOCAL(); \ - \ - const T* pbuf = (const T*)pbyMem; \ - int nLeftOver = (nQWordSize*4*2)%(TRANSMIT_PITCH##TransSfx(2, T)); \ - int nSize = nQWordSize*4*2/TRANSMIT_PITCH##TransSfx(2, T); \ - nSize = min(nSize, gs.imageWnew * gs.imageHnew); \ - \ - int pitch, area, fracX; \ - int endY = ROUND_UPPOW2(i, blockheight); \ - int alignedY = ROUND_DOWNPOW2(gs.imageEndY, blockheight); \ - int alignedX = ROUND_DOWNPOW2(gs.imageEndX, blockwidth); \ - bool bAligned, bCanAlign = MOD_POW2(gs.trxpos.dx, blockwidth) == 0 && (j == gs.trxpos.dx) && (alignedY > endY) && alignedX > gs.trxpos.dx; \ - \ - if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { \ - /* hack */ \ - int testwidth = (int)nSize - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx); \ - if ((testwidth <= widthlimit) && (testwidth >= -widthlimit)) { \ - /* Don't transfer */ \ - /*DEBUG_LOG("bad texture %s: %d %d %d\n", #psm, gs.trxpos.dx, gs.imageEndX, nQWordSize);*/ \ - gs.imageTransfer = -1; \ - } \ - bCanAlign = false; \ - } \ - \ - /* first align on block boundary */ \ - if( MOD_POW2(i, blockheight) || !bCanAlign ) { \ - \ - if( !bCanAlign ) \ - endY = gs.imageEndY; /* transfer the whole image */ \ - else \ - assert( endY < gs.imageEndY); /* part of alignment condition */ \ - \ - if( ((gs.imageEndX-gs.trxpos.dx)%widthlimit) || ((gs.imageEndX-j)%widthlimit) ) { \ - /* transmit with a width of 1 */ \ - TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, (1+(DSTPSM == 0x14)), endY); \ - } \ - else { \ - TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, widthlimit, endY); \ - } \ - \ - if( nSize == 0 || i == gs.imageEndY ) \ - goto End; \ - } \ - \ - assert( MOD_POW2(i, blockheight) == 0 && j == gs.trxpos.dx); \ - \ - /* can align! */ \ - pitch = gs.imageEndX-gs.trxpos.dx; \ - area = pitch*blockheight; \ - fracX = gs.imageEndX-alignedX; \ - \ - /* on top of checking whether pbuf is alinged, make sure that the width is at least aligned to its limits (due to bugs in pcsx2) */ \ - bAligned = !((uptr)pbuf & 0xf) && (TRANSMIT_PITCH##TransSfx(pitch, T)&0xf) == 0; \ - \ - /* transfer aligning to blocks */ \ - for(; i < alignedY && nSize >= area; i += blockheight, nSize -= area) { \ - \ - if( bAligned || ((DSTPSM==PSMCT24) || (DSTPSM==PSMT8H) || (DSTPSM==PSMT4HH) || (DSTPSM==PSMT4HL)) ) { \ - for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH##TransSfx(blockwidth, T)/sizeof(T)) { \ - SwizzleBlock(pstart + getPixelAddress##psm##_0(tempj, i, gs.dstbuf.bw)*blockbits/8, \ - (u8*)pbuf, TRANSMIT_PITCH##TransSfx(pitch, T)); \ - } \ - } \ - else { \ - for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH##TransSfx(blockwidth, T)/sizeof(T)) { \ - SwizzleBlock##u(pstart + getPixelAddress##psm##_0(tempj, i, gs.dstbuf.bw)*blockbits/8, \ - (u8*)pbuf, TRANSMIT_PITCH##TransSfx(pitch, T)); \ - } \ - } \ - \ - /* transfer the rest */ \ - if( alignedX < gs.imageEndX ) { \ - TRANSMIT_HOSTLOCAL_X##TransSfx(psm, T, widthlimit, blockheight, alignedX); \ - pbuf -= TRANSMIT_PITCH##TransSfx((alignedX-gs.trxpos.dx), T)/sizeof(T); \ - } \ - else pbuf += (blockheight-1)*TRANSMIT_PITCH##TransSfx(pitch, T)/sizeof(T); \ - j = gs.trxpos.dx; \ - } \ - \ - if( TRANSMIT_PITCH##TransSfx(nSize, T)/4 > 0 ) { \ - TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, widthlimit, gs.imageEndY); \ - /* sometimes wrong sizes are sent (tekken tag) */ \ - assert( gs.imageTransfer == -1 || TRANSMIT_PITCH##TransSfx(nSize,T)/4 <= 2 ); \ - } \ - \ - END_HOSTLOCAL(); \ - return (nSize * TRANSMIT_PITCH##TransSfx(2, T) + nLeftOver)/2; \ -} \ - -DEFINE_TRANSFERLOCAL(32, u32, 2, 32, 8, 8, _, SwizzleBlock32); -DEFINE_TRANSFERLOCAL(32Z, u32, 2, 32, 8, 8, _, SwizzleBlock32); -DEFINE_TRANSFERLOCAL(24, u8, 8, 32, 8, 8, _24, SwizzleBlock24); -DEFINE_TRANSFERLOCAL(24Z, u8, 8, 32, 8, 8, _24, SwizzleBlock24); -DEFINE_TRANSFERLOCAL(16, u16, 4, 16, 16, 8, _, SwizzleBlock16); -DEFINE_TRANSFERLOCAL(16S, u16, 4, 16, 16, 8, _, SwizzleBlock16); -DEFINE_TRANSFERLOCAL(16Z, u16, 4, 16, 16, 8, _, SwizzleBlock16); -DEFINE_TRANSFERLOCAL(16SZ, u16, 4, 16, 16, 8, _, SwizzleBlock16); -DEFINE_TRANSFERLOCAL(8, u8, 4, 8, 16, 16, _, SwizzleBlock8); -DEFINE_TRANSFERLOCAL(4, u8, 8, 4, 32, 16, _4, SwizzleBlock4); -DEFINE_TRANSFERLOCAL(8H, u8, 4, 32, 8, 8, _, SwizzleBlock8H); -DEFINE_TRANSFERLOCAL(4HL, u8, 8, 32, 8, 8, _4, SwizzleBlock4HL); -DEFINE_TRANSFERLOCAL(4HH, u8, 8, 32, 8, 8, _4, SwizzleBlock4HH); - -//#define T u8 -//#define widthlimit 8 -//#define blockbits 4 -//#define blockwidth 32 -//#define blockheight 16 -// -//void TransferHostLocal4(const void* pbyMem, u32 nQWordSize) -//{ -// START_HOSTLOCAL(); -// -// const T* pbuf = (const T*)pbyMem; -// u32 nSize = nQWordSize*16*2/TRANSMIT_PITCH_4(2, T); -// nSize = min(nSize, gs.imageWnew * gs.imageHnew); -// -// int endY = ROUND_UPPOW2(i, blockheight); -// int alignedY = ROUND_DOWNPOW2(gs.imageEndY, blockheight); -// int alignedX = ROUND_DOWNPOW2(gs.imageEndX, blockwidth); -// bool bCanAlign = MOD_POW2(gs.trxpos.dx, blockwidth) == 0 && (j == gs.trxpos.dx) && (alignedY > endY) && alignedX > gs.trxpos.dx; -// -// if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { -// /* hack */ -// if( abs((int)nSize - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx)) <= widthlimit ) { -// /* don't transfer */ -// /*DEBUG_LOG("bad texture %s: %d %d %d\n", #psm, gs.trxpos.dx, gs.imageEndX, nQWordSize);*/ -// gs.imageTransfer = -1; -// } -// bCanAlign = false; -// } -// -// /* first align on block boundary */ -// if( MOD_POW2(i, blockheight) || !bCanAlign ) { -// -// if( !bCanAlign ) -// endY = gs.imageEndY; /* transfer the whole image */ -// else -// assert( endY < gs.imageEndY); /* part of alignment condition */ -// -// if( (DSTPSM == 0x13 || DSTPSM == 0x14) && ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) { -// /* transmit with a width of 1 */ -// TRANSMIT_HOSTLOCAL_Y_4(4, T, (1+(DSTPSM == 0x14)), endY); -// } -// else { -// TRANSMIT_HOSTLOCAL_Y_4(4, T, widthlimit, endY); -// } -// -// if( nSize == 0 || i == gs.imageEndY ) -// goto End; -// } -// -// assert( MOD_POW2(i, blockheight) == 0 && j == gs.trxpos.dx); -// -// /* can align! */ -// int pitch = gs.imageEndX-gs.trxpos.dx; -// u32 area = pitch*blockheight; -// int fracX = gs.imageEndX-alignedX; -// -// /* on top of checking whether pbuf is alinged, make sure that the width is at least aligned to its limits (due to bugs in pcsx2) */ -// bool bAligned = !((u32)pbuf & 0xf) && (TRANSMIT_PITCH_4(pitch, T)&0xf) == 0; -// -// /* transfer aligning to blocks */ -// for(; i < alignedY && nSize >= area; i += blockheight, nSize -= area) { -// -// if( bAligned || ((DSTPSM==PSMCT24) || (DSTPSM==PSMT8H) || (DSTPSM==PSMT4HH) || (DSTPSM==PSMT4HL)) ) { -// for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH_4(blockwidth, T)/sizeof(T)) { -// SwizzleBlock4(pstart + getPixelAddress4_0(tempj, i, gs.dstbuf.bw)*blockbits/8, -// (u8*)pbuf, TRANSMIT_PITCH_4(pitch, T)); -// } -// } -// else { -// for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH_4(blockwidth, T)/sizeof(T)) { -// SwizzleBlock4u(pstart + getPixelAddress4_0(tempj, i, gs.dstbuf.bw)*blockbits/8, -// (u8*)pbuf, TRANSMIT_PITCH_4(pitch, T)); -// } -// } -// -// /* transfer the rest */ -// if( alignedX < gs.imageEndX ) { -// TRANSMIT_HOSTLOCAL_X_4(4, T, widthlimit, blockheight, alignedX); -// pbuf -= TRANSMIT_PITCH_4((alignedX-gs.trxpos.dx), T)/sizeof(T); -// } -// else pbuf += (blockheight-1)*TRANSMIT_PITCH_4(pitch, T)/sizeof(T); -// j = 0; -// } -// -// if( TRANSMIT_PITCH_4(nSize, T)/4 > 0 ) { -// TRANSMIT_HOSTLOCAL_Y_4(4, T, widthlimit, gs.imageEndY); -// /* sometimes wrong sizes are sent (tekken tag) */ -// assert( gs.imageTransfer == -1 || TRANSMIT_PITCH_4(nSize,T)/4 <= 2 ); -// } -// -// END_HOSTLOCAL(); -//} - -void TransferLocalHost32(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost24(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost16(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost16S(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost8(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost4(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost8H(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost4HL(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost4HH(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost32Z(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost24Z(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost16Z(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost16SZ(void* pbyMem, u32 nQWordSize) -{ -} - -#define FILL_BLOCK(bw, bh, ox, oy, mult, psm, psmcol) { \ - b.vTexDims = D3DXVECTOR2(BLOCK_TEXWIDTH/(float)(bw), BLOCK_TEXHEIGHT/(float)bh); \ - b.vTexBlock = D3DXVECTOR4((float)bw/BLOCK_TEXWIDTH, (float)bh/BLOCK_TEXHEIGHT, ((float)ox+0.2f)/BLOCK_TEXWIDTH, ((float)oy+0.05f)/BLOCK_TEXHEIGHT); \ - b.width = bw; \ - b.height = bh; \ - b.colwidth = bh / 4; \ - b.colheight = bw / 8; \ - b.bpp = 32/mult; \ - \ - b.pageTable = &g_pageTable##psm[0][0]; \ - b.blockTable = &g_blockTable##psm[0][0]; \ - b.columnTable = &g_columnTable##psmcol[0][0]; \ - assert( sizeof(g_pageTable##psm) == bw*bh*sizeof(g_pageTable##psm[0][0]) ); \ - psrcf = (float*)pBlockTexture->pBits + ox + oy * pBlockTexture->Pitch/sizeof(float); \ - psrcw = (WORD*)pBlockTexture->pBits + ox + oy * pBlockTexture->Pitch/sizeof(WORD); \ - for(i = 0; i < bh; ++i) { \ - for(j = 0; j < bw; ++j) { \ - /* fill the table */ \ - u32 u = g_blockTable##psm[(i / b.colheight)][(j / b.colwidth)] * 64 * mult + g_columnTable##psmcol[i%b.colheight][j%b.colwidth]; \ - b.pageTable[i*bw+j] = u; \ - if( format == D3DFMT_R32F ) { \ - psrcf[i*pBlockTexture->Pitch/sizeof(float)+j] = (float)(u) / (float)(GPU_TEXWIDTH*mult); \ - } \ - else { \ - psrcw[i*pBlockTexture->Pitch/sizeof(WORD)+j] = u; \ - } \ - } \ - } \ - \ - if( pBilinearTexture != NULL ) { \ - assert( format == D3DFMT_R32F ); \ - psrcv = (DXVEC4*)pBilinearTexture->pBits + ox + oy * pBilinearTexture->Pitch/sizeof(DXVEC4); \ - for(i = 0; i < bh; ++i) { \ - for(j = 0; j < bw; ++j) { \ - DXVEC4* pv = &psrcv[i*pBilinearTexture->Pitch/sizeof(DXVEC4)+j]; \ - pv->x = psrcf[i*pBlockTexture->Pitch/sizeof(float)+j]; \ - pv->y = psrcf[i*pBlockTexture->Pitch/sizeof(float)+((j+1)%bw)]; \ - pv->z = psrcf[((i+1)%bh)*pBlockTexture->Pitch/sizeof(float)+j]; \ - pv->w = psrcf[((i+1)%bh)*pBlockTexture->Pitch/sizeof(float)+((j+1)%bw)]; \ - } \ - } \ - } \ - b.getPixelAddress = getPixelAddress##psm; \ - b.getPixelAddress_0 = getPixelAddress##psm##_0; \ - b.writePixel = writePixel##psm; \ - b.writePixel_0 = writePixel##psm##_0; \ - b.readPixel = readPixel##psm; \ - b.readPixel_0 = readPixel##psm##_0; \ - b.TransferHostLocal = TransferHostLocal##psm; \ - b.TransferLocalHost = TransferLocalHost##psm; \ -} \ - -void BLOCK::FillBlocks(const D3DLOCKED_RECT* pBlockTexture, const D3DLOCKED_RECT* pBilinearTexture, D3DFORMAT format) -{ - assert( pBlockTexture != NULL ); - assert( format == D3DFMT_R32F || format == D3DFMT_G16R16 ); - - int i, j; - BLOCK b; - float* psrcf = NULL; - WORD* psrcw = NULL; - DXVEC4* psrcv = NULL; - - memset(m_Blocks, 0, sizeof(m_Blocks)); - - // 32 - FILL_BLOCK(64, 32, 0, 0, 1, 32, 32); - m_Blocks[PSMCT32] = b; - - // 24 (same as 32 except write/readPixel are different) - m_Blocks[PSMCT24] = b; - m_Blocks[PSMCT24].writePixel = writePixel24; - m_Blocks[PSMCT24].writePixel_0 = writePixel24_0; - m_Blocks[PSMCT24].readPixel = readPixel24; - m_Blocks[PSMCT24].readPixel_0 = readPixel24_0; - m_Blocks[PSMCT24].TransferHostLocal = TransferHostLocal24; - m_Blocks[PSMCT24].TransferLocalHost = TransferLocalHost24; - - // 8H (same as 32 except write/readPixel are different) - m_Blocks[PSMT8H] = b; - m_Blocks[PSMT8H].writePixel = writePixel8H; - m_Blocks[PSMT8H].writePixel_0 = writePixel8H_0; - m_Blocks[PSMT8H].readPixel = readPixel8H; - m_Blocks[PSMT8H].readPixel_0 = readPixel8H_0; - m_Blocks[PSMT8H].TransferHostLocal = TransferHostLocal8H; - m_Blocks[PSMT8H].TransferLocalHost = TransferLocalHost8H; - - m_Blocks[PSMT4HL] = b; - m_Blocks[PSMT4HL].writePixel = writePixel4HL; - m_Blocks[PSMT4HL].writePixel_0 = writePixel4HL_0; - m_Blocks[PSMT4HL].readPixel = readPixel4HL; - m_Blocks[PSMT4HL].readPixel_0 = readPixel4HL_0; - m_Blocks[PSMT4HL].TransferHostLocal = TransferHostLocal4HL; - m_Blocks[PSMT4HL].TransferLocalHost = TransferLocalHost4HL; - - m_Blocks[PSMT4HH] = b; - m_Blocks[PSMT4HH].writePixel = writePixel4HH; - m_Blocks[PSMT4HH].writePixel_0 = writePixel4HH_0; - m_Blocks[PSMT4HH].readPixel = readPixel4HH; - m_Blocks[PSMT4HH].readPixel_0 = readPixel4HH_0; - m_Blocks[PSMT4HH].TransferHostLocal = TransferHostLocal4HH; - m_Blocks[PSMT4HH].TransferLocalHost = TransferLocalHost4HH; - - // 32z - FILL_BLOCK(64, 32, 64, 0, 1, 32Z, 32); - m_Blocks[PSMT32Z] = b; - - // 24Z (same as 32Z except write/readPixel are different) - m_Blocks[PSMT24Z] = b; - m_Blocks[PSMT24Z].writePixel = writePixel24Z; - m_Blocks[PSMT24Z].writePixel_0 = writePixel24Z_0; - m_Blocks[PSMT24Z].readPixel = readPixel24Z; - m_Blocks[PSMT24Z].readPixel_0 = readPixel24Z_0; - m_Blocks[PSMT24Z].TransferHostLocal = TransferHostLocal24Z; - m_Blocks[PSMT24Z].TransferLocalHost = TransferLocalHost24Z; - - // 16 - FILL_BLOCK(64, 64, 0, 32, 2, 16, 16); - m_Blocks[PSMCT16] = b; - - // 16s - FILL_BLOCK(64, 64, 64, 32, 2, 16S, 16); - m_Blocks[PSMCT16S] = b; - - // 16z - FILL_BLOCK(64, 64, 0, 96, 2, 16Z, 16); - m_Blocks[PSMT16Z] = b; - - // 16sz - FILL_BLOCK(64, 64, 64, 96, 2, 16SZ, 16); - m_Blocks[PSMT16SZ] = b; - - // 8 - FILL_BLOCK(128, 64, 0, 160, 4, 8, 8); - m_Blocks[PSMT8] = b; - - // 4 - FILL_BLOCK(128, 128, 0, 224, 8, 4, 4); - m_Blocks[PSMT4] = b; -} +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + +#include "GS.h" +#include "Mem.h" +#include "zerogs.h" +#include "targets.h" +#include "x86.h" + +u32 g_blockTable32[4][8] = { + { 0, 1, 4, 5, 16, 17, 20, 21}, + { 2, 3, 6, 7, 18, 19, 22, 23}, + { 8, 9, 12, 13, 24, 25, 28, 29}, + { 10, 11, 14, 15, 26, 27, 30, 31} +}; + +u32 g_blockTable32Z[4][8] = { + { 24, 25, 28, 29, 8, 9, 12, 13}, + { 26, 27, 30, 31, 10, 11, 14, 15}, + { 16, 17, 20, 21, 0, 1, 4, 5}, + { 18, 19, 22, 23, 2, 3, 6, 7} +}; + +u32 g_blockTable16[8][4] = { + { 0, 2, 8, 10 }, + { 1, 3, 9, 11 }, + { 4, 6, 12, 14 }, + { 5, 7, 13, 15 }, + { 16, 18, 24, 26 }, + { 17, 19, 25, 27 }, + { 20, 22, 28, 30 }, + { 21, 23, 29, 31 } +}; + +u32 g_blockTable16S[8][4] = { + { 0, 2, 16, 18 }, + { 1, 3, 17, 19 }, + { 8, 10, 24, 26 }, + { 9, 11, 25, 27 }, + { 4, 6, 20, 22 }, + { 5, 7, 21, 23 }, + { 12, 14, 28, 30 }, + { 13, 15, 29, 31 } +}; + +u32 g_blockTable16Z[8][4] = { + { 24, 26, 16, 18 }, + { 25, 27, 17, 19 }, + { 28, 30, 20, 22 }, + { 29, 31, 21, 23 }, + { 8, 10, 0, 2 }, + { 9, 11, 1, 3 }, + { 12, 14, 4, 6 }, + { 13, 15, 5, 7 } +}; + +u32 g_blockTable16SZ[8][4] = { + { 24, 26, 8, 10 }, + { 25, 27, 9, 11 }, + { 16, 18, 0, 2 }, + { 17, 19, 1, 3 }, + { 28, 30, 12, 14 }, + { 29, 31, 13, 15 }, + { 20, 22, 4, 6 }, + { 21, 23, 5, 7 } +}; + +u32 g_blockTable8[4][8] = { + { 0, 1, 4, 5, 16, 17, 20, 21}, + { 2, 3, 6, 7, 18, 19, 22, 23}, + { 8, 9, 12, 13, 24, 25, 28, 29}, + { 10, 11, 14, 15, 26, 27, 30, 31} +}; + +u32 g_blockTable4[8][4] = { + { 0, 2, 8, 10 }, + { 1, 3, 9, 11 }, + { 4, 6, 12, 14 }, + { 5, 7, 13, 15 }, + { 16, 18, 24, 26 }, + { 17, 19, 25, 27 }, + { 20, 22, 28, 30 }, + { 21, 23, 29, 31 } +}; + +u32 g_columnTable32[8][8] = { + { 0, 1, 4, 5, 8, 9, 12, 13 }, + { 2, 3, 6, 7, 10, 11, 14, 15 }, + { 16, 17, 20, 21, 24, 25, 28, 29 }, + { 18, 19, 22, 23, 26, 27, 30, 31 }, + { 32, 33, 36, 37, 40, 41, 44, 45 }, + { 34, 35, 38, 39, 42, 43, 46, 47 }, + { 48, 49, 52, 53, 56, 57, 60, 61 }, + { 50, 51, 54, 55, 58, 59, 62, 63 }, +}; + +u32 g_columnTable16[8][16] = { + { 0, 2, 8, 10, 16, 18, 24, 26, + 1, 3, 9, 11, 17, 19, 25, 27 }, + { 4, 6, 12, 14, 20, 22, 28, 30, + 5, 7, 13, 15, 21, 23, 29, 31 }, + { 32, 34, 40, 42, 48, 50, 56, 58, + 33, 35, 41, 43, 49, 51, 57, 59 }, + { 36, 38, 44, 46, 52, 54, 60, 62, + 37, 39, 45, 47, 53, 55, 61, 63 }, + { 64, 66, 72, 74, 80, 82, 88, 90, + 65, 67, 73, 75, 81, 83, 89, 91 }, + { 68, 70, 76, 78, 84, 86, 92, 94, + 69, 71, 77, 79, 85, 87, 93, 95 }, + { 96, 98, 104, 106, 112, 114, 120, 122, + 97, 99, 105, 107, 113, 115, 121, 123 }, + { 100, 102, 108, 110, 116, 118, 124, 126, + 101, 103, 109, 111, 117, 119, 125, 127 }, +}; + +u32 g_columnTable8[16][16] = { + { 0, 4, 16, 20, 32, 36, 48, 52, // column 0 + 2, 6, 18, 22, 34, 38, 50, 54 }, + { 8, 12, 24, 28, 40, 44, 56, 60, + 10, 14, 26, 30, 42, 46, 58, 62 }, + { 33, 37, 49, 53, 1, 5, 17, 21, + 35, 39, 51, 55, 3, 7, 19, 23 }, + { 41, 45, 57, 61, 9, 13, 25, 29, + 43, 47, 59, 63, 11, 15, 27, 31 }, + { 96, 100, 112, 116, 64, 68, 80, 84, // column 1 + 98, 102, 114, 118, 66, 70, 82, 86 }, + { 104, 108, 120, 124, 72, 76, 88, 92, + 106, 110, 122, 126, 74, 78, 90, 94 }, + { 65, 69, 81, 85, 97, 101, 113, 117, + 67, 71, 83, 87, 99, 103, 115, 119 }, + { 73, 77, 89, 93, 105, 109, 121, 125, + 75, 79, 91, 95, 107, 111, 123, 127 }, + { 128, 132, 144, 148, 160, 164, 176, 180, // column 2 + 130, 134, 146, 150, 162, 166, 178, 182 }, + { 136, 140, 152, 156, 168, 172, 184, 188, + 138, 142, 154, 158, 170, 174, 186, 190 }, + { 161, 165, 177, 181, 129, 133, 145, 149, + 163, 167, 179, 183, 131, 135, 147, 151 }, + { 169, 173, 185, 189, 137, 141, 153, 157, + 171, 175, 187, 191, 139, 143, 155, 159 }, + { 224, 228, 240, 244, 192, 196, 208, 212, // column 3 + 226, 230, 242, 246, 194, 198, 210, 214 }, + { 232, 236, 248, 252, 200, 204, 216, 220, + 234, 238, 250, 254, 202, 206, 218, 222 }, + { 193, 197, 209, 213, 225, 229, 241, 245, + 195, 199, 211, 215, 227, 231, 243, 247 }, + { 201, 205, 217, 221, 233, 237, 249, 253, + 203, 207, 219, 223, 235, 239, 251, 255 }, +}; + +u32 g_columnTable4[16][32] = { + { 0, 8, 32, 40, 64, 72, 96, 104, // column 0 + 2, 10, 34, 42, 66, 74, 98, 106, + 4, 12, 36, 44, 68, 76, 100, 108, + 6, 14, 38, 46, 70, 78, 102, 110 }, + { 16, 24, 48, 56, 80, 88, 112, 120, + 18, 26, 50, 58, 82, 90, 114, 122, + 20, 28, 52, 60, 84, 92, 116, 124, + 22, 30, 54, 62, 86, 94, 118, 126 }, + { 65, 73, 97, 105, 1, 9, 33, 41, + 67, 75, 99, 107, 3, 11, 35, 43, + 69, 77, 101, 109, 5, 13, 37, 45, + 71, 79, 103, 111, 7, 15, 39, 47 }, + { 81, 89, 113, 121, 17, 25, 49, 57, + 83, 91, 115, 123, 19, 27, 51, 59, + 85, 93, 117, 125, 21, 29, 53, 61, + 87, 95, 119, 127, 23, 31, 55, 63 }, + { 192, 200, 224, 232, 128, 136, 160, 168, // column 1 + 194, 202, 226, 234, 130, 138, 162, 170, + 196, 204, 228, 236, 132, 140, 164, 172, + 198, 206, 230, 238, 134, 142, 166, 174 }, + { 208, 216, 240, 248, 144, 152, 176, 184, + 210, 218, 242, 250, 146, 154, 178, 186, + 212, 220, 244, 252, 148, 156, 180, 188, + 214, 222, 246, 254, 150, 158, 182, 190 }, + { 129, 137, 161, 169, 193, 201, 225, 233, + 131, 139, 163, 171, 195, 203, 227, 235, + 133, 141, 165, 173, 197, 205, 229, 237, + 135, 143, 167, 175, 199, 207, 231, 239 }, + { 145, 153, 177, 185, 209, 217, 241, 249, + 147, 155, 179, 187, 211, 219, 243, 251, + 149, 157, 181, 189, 213, 221, 245, 253, + 151, 159, 183, 191, 215, 223, 247, 255 }, + { 256, 264, 288, 296, 320, 328, 352, 360, // column 2 + 258, 266, 290, 298, 322, 330, 354, 362, + 260, 268, 292, 300, 324, 332, 356, 364, + 262, 270, 294, 302, 326, 334, 358, 366 }, + { 272, 280, 304, 312, 336, 344, 368, 376, + 274, 282, 306, 314, 338, 346, 370, 378, + 276, 284, 308, 316, 340, 348, 372, 380, + 278, 286, 310, 318, 342, 350, 374, 382 }, + { 321, 329, 353, 361, 257, 265, 289, 297, + 323, 331, 355, 363, 259, 267, 291, 299, + 325, 333, 357, 365, 261, 269, 293, 301, + 327, 335, 359, 367, 263, 271, 295, 303 }, + { 337, 345, 369, 377, 273, 281, 305, 313, + 339, 347, 371, 379, 275, 283, 307, 315, + 341, 349, 373, 381, 277, 285, 309, 317, + 343, 351, 375, 383, 279, 287, 311, 319 }, + { 448, 456, 480, 488, 384, 392, 416, 424, // column 3 + 450, 458, 482, 490, 386, 394, 418, 426, + 452, 460, 484, 492, 388, 396, 420, 428, + 454, 462, 486, 494, 390, 398, 422, 430 }, + { 464, 472, 496, 504, 400, 408, 432, 440, + 466, 474, 498, 506, 402, 410, 434, 442, + 468, 476, 500, 508, 404, 412, 436, 444, + 470, 478, 502, 510, 406, 414, 438, 446 }, + { 385, 393, 417, 425, 449, 457, 481, 489, + 387, 395, 419, 427, 451, 459, 483, 491, + 389, 397, 421, 429, 453, 461, 485, 493, + 391, 399, 423, 431, 455, 463, 487, 495 }, + { 401, 409, 433, 441, 465, 473, 497, 505, + 403, 411, 435, 443, 467, 475, 499, 507, + 405, 413, 437, 445, 469, 477, 501, 509, + 407, 415, 439, 447, 471, 479, 503, 511 }, +}; + +u32 g_pageTable32[32][64]; +u32 g_pageTable32Z[32][64]; +u32 g_pageTable16[64][64]; +u32 g_pageTable16S[64][64]; +u32 g_pageTable16Z[64][64]; +u32 g_pageTable16SZ[64][64]; +u32 g_pageTable8[64][128]; +u32 g_pageTable4[128][128]; + +BLOCK m_Blocks[0x40]; // do so blocks are indexable +static PCSX2_ALIGNED16(u32 tempblock[64]); + +#define DSTPSM gs.dstbuf.psm + +#define START_HOSTLOCAL() \ + assert( gs.imageTransfer == 0 ); \ + u8* pstart = ZeroGS::g_pbyGSMemory + gs.dstbuf.bp*256; \ + \ + const u8* pendbuf = (const u8*)pbyMem + nQWordSize*4; \ + int i = gs.imageY, j = gs.imageX; \ + +extern BOOL g_bSaveTrans; + +#define END_HOSTLOCAL() \ +End: \ + if( i >= gs.imageEndY ) { \ + assert( gs.imageTransfer == -1 || i == gs.imageEndY ); \ + gs.imageTransfer = -1; \ + /*int start, end; \ + ZeroGS::GetRectMemAddress(start, end, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); \ + ZeroGS::g_MemTargs.ClearRange(start, end);*/ \ + } \ + else { \ + /* update new params */ \ + gs.imageY = i; \ + gs.imageX = j; \ + } \ + +// transfers whole rows +#define TRANSMIT_HOSTLOCAL_Y_(psm, T, widthlimit, endY) { \ + assert( (nSize%widthlimit) == 0 && widthlimit <= 4 ); \ + if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { \ + /*GS_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM);*/ \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += 1, nSize -= 1, pbuf += 1) { \ + /* write as many pixel at one time as possible */ \ + writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ + } \ + } \ + } \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += widthlimit) { \ + /* write as many pixel at one time as possible */ \ + if( nSize < widthlimit ) goto End; \ + writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ + \ + if( widthlimit > 1 ) { \ + writePixel##psm##_0(pstart, (j+1)%2048, i%2048, pbuf[1], gs.dstbuf.bw); \ + \ + if( widthlimit > 2 ) { \ + writePixel##psm##_0(pstart, (j+2)%2048, i%2048, pbuf[2], gs.dstbuf.bw); \ + \ + if( widthlimit > 3 ) { \ + writePixel##psm##_0(pstart, (j+3)%2048, i%2048, pbuf[3], gs.dstbuf.bw); \ + } \ + } \ + } \ + } \ + \ + if( j >= gs.imageEndX ) { assert(j == gs.imageEndX); j = gs.trxpos.dx; } \ + else { assert( gs.imageTransfer == -1 || nSize*sizeof(T)/4 == 0 ); goto End; } \ + } \ +} \ + +// transmit until endX, don't check size since it has already been prevalidated +#define TRANSMIT_HOSTLOCAL_X_(psm, T, widthlimit, blockheight, startX) { \ + for(int tempi = 0; tempi < blockheight; ++tempi) { \ + for(j = startX; j < gs.imageEndX; j++, pbuf++) { \ + writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, pbuf[0], gs.dstbuf.bw); \ + } \ + pbuf += pitch-fracX; \ + } \ +} \ + +// transfers whole rows +#define TRANSMIT_HOSTLOCAL_Y_24(psm, T, widthlimit, endY) { \ + if( widthlimit != 8 || ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) { \ + /*GS_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM);*/ \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += 1, nSize -= 1, pbuf += 3) { \ + writePixel##psm##_0(pstart, j%2048, i%2048, *(u32*)(pbuf), gs.dstbuf.bw); \ + } \ + \ + if( j >= gs.imageEndX ) { assert(gs.imageTransfer == -1 || j == gs.imageEndX); j = gs.trxpos.dx; } \ + else { assert( gs.imageTransfer == -1 || nSize == 0 ); goto End; } \ + } \ + } \ + else { \ + assert( /*(nSize%widthlimit) == 0 &&*/ widthlimit == 8 ); \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += 3*widthlimit) { \ + if( nSize < widthlimit ) goto End; \ + /* write as many pixel at one time as possible */ \ + writePixel##psm##_0(pstart, j%2048, i%2048, *(u32*)(pbuf+0), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *(u32*)(pbuf+3), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *(u32*)(pbuf+6), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *(u32*)(pbuf+9), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *(u32*)(pbuf+12), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *(u32*)(pbuf+15), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *(u32*)(pbuf+18), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *(u32*)(pbuf+21), gs.dstbuf.bw); \ + } \ + \ + if( j >= gs.imageEndX ) { assert(gs.imageTransfer == -1 || j == gs.imageEndX); j = gs.trxpos.dx; } \ + else { \ + if( nSize < 0 ) { \ + /* extracted too much */ \ + assert( (nSize%3)==0 && nSize > -24 ); \ + j += nSize/3; \ + nSize = 0; \ + } \ + assert( gs.imageTransfer == -1 || nSize == 0 ); \ + goto End; \ + } \ + } \ + } \ +} \ + +// transmit until endX, don't check size since it has already been prevalidated +#define TRANSMIT_HOSTLOCAL_X_24(psm, T, widthlimit, blockheight, startX) { \ + for(int tempi = 0; tempi < blockheight; ++tempi) { \ + for(j = startX; j < gs.imageEndX; j++, pbuf += 3) { \ + writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, *(u32*)pbuf, gs.dstbuf.bw); \ + } \ + pbuf += 3*(pitch-fracX); \ + } \ +} \ + +// meant for 4bit transfers +#define TRANSMIT_HOSTLOCAL_Y_4(psm, T, widthlimit, endY) { \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit) { \ + /* write as many pixel at one time as possible */ \ + writePixel##psm##_0(pstart, j%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + if( widthlimit > 2 ) { \ + writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + \ + if( widthlimit > 4 ) { \ + writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + \ + if( widthlimit > 6 ) { \ + writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + } \ + } \ + } \ + } \ + \ + if( j >= gs.imageEndX ) { j = gs.trxpos.dx; } \ + else { assert( gs.imageTransfer == -1 || (nSize/32) == 0 ); goto End; } \ + } \ +} \ + +// transmit until endX, don't check size since it has already been prevalidated +#define TRANSMIT_HOSTLOCAL_X_4(psm, T, widthlimit, blockheight, startX) { \ + for(int tempi = 0; tempi < blockheight; ++tempi) { \ + for(j = startX; j < gs.imageEndX; j+=2, pbuf++) { \ + writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, pbuf[0]&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+1)%2048, (i+tempi)%2048, pbuf[0]>>4, gs.dstbuf.bw); \ + } \ + pbuf += (pitch-fracX)/2; \ + } \ +} \ + +// calculate pitch in source buffer +#define TRANSMIT_PITCH_(pitch, T) (pitch*sizeof(T)) +#define TRANSMIT_PITCH_24(pitch, T) (pitch*3) +#define TRANSMIT_PITCH_4(pitch, T) (pitch/2) + +// special swizzle macros +#define SwizzleBlock24(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 7; ++by, pblock += 8, pnewsrc += pitch-24) { \ + for(int bx = 0; bx < 8; ++bx, pnewsrc += 3) { \ + pblock[bx] = *(u32*)pnewsrc; \ + } \ + } \ + for(int bx = 0; bx < 7; ++bx, pnewsrc += 3) { \ + /* might be 1 byte out of bounds of GS memory */ \ + pblock[bx] = *(u32*)pnewsrc; \ + } \ + /* do 3 bytes for the last copy */ \ + *((u8*)pblock+28) = pnewsrc[0]; \ + *((u8*)pblock+29) = pnewsrc[1]; \ + *((u8*)pblock+30) = pnewsrc[2]; \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0x00ffffff); \ +} \ + +#define SwizzleBlock24u SwizzleBlock24 + +#define SwizzleBlock8H(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ + u32 u = *(u32*)pnewsrc; \ + pblock[0] = u<<24; \ + pblock[1] = u<<16; \ + pblock[2] = u<<8; \ + pblock[3] = u; \ + u = *(u32*)(pnewsrc+4); \ + pblock[4] = u<<24; \ + pblock[5] = u<<16; \ + pblock[6] = u<<8; \ + pblock[7] = u; \ + } \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0xff000000); \ +} \ + +#define SwizzleBlock8Hu SwizzleBlock8H + +#define SwizzleBlock4HH(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ + u32 u = *(u32*)pnewsrc; \ + pblock[0] = u<<28; \ + pblock[1] = u<<24; \ + pblock[2] = u<<20; \ + pblock[3] = u<<16; \ + pblock[4] = u<<12; \ + pblock[5] = u<<8; \ + pblock[6] = u<<4; \ + pblock[7] = u; \ + } \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0xf0000000); \ +} \ + +#define SwizzleBlock4HHu SwizzleBlock4HH + +#define SwizzleBlock4HL(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ + u32 u = *(u32*)pnewsrc; \ + pblock[0] = u<<24; \ + pblock[1] = u<<20; \ + pblock[2] = u<<16; \ + pblock[3] = u<<12; \ + pblock[4] = u<<8; \ + pblock[5] = u<<4; \ + pblock[6] = u; \ + pblock[7] = u>>4; \ + } \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0x0f000000); \ +} \ + +#define SwizzleBlock4HLu SwizzleBlock4HL + +// ------------------------ +// | Y | +// ------------------------ +// | block | | +// | aligned area | X | +// | | | +// ------------------------ +// | Y | +// ------------------------ +#define DEFINE_TRANSFERLOCAL(psm, T, widthlimit, blockbits, blockwidth, blockheight, TransSfx, SwizzleBlock) \ +int TransferHostLocal##psm(const void* pbyMem, u32 nQWordSize) \ +{ \ + START_HOSTLOCAL(); \ + \ + const T* pbuf = (const T*)pbyMem; \ + int nLeftOver = (nQWordSize*4*2)%(TRANSMIT_PITCH##TransSfx(2, T)); \ + int nSize = nQWordSize*4*2/TRANSMIT_PITCH##TransSfx(2, T); \ + nSize = min(nSize, gs.imageWnew * gs.imageHnew); \ + \ + int pitch, area, fracX; \ + int endY = ROUND_UPPOW2(i, blockheight); \ + int alignedY = ROUND_DOWNPOW2(gs.imageEndY, blockheight); \ + int alignedX = ROUND_DOWNPOW2(gs.imageEndX, blockwidth); \ + bool bAligned, bCanAlign = MOD_POW2(gs.trxpos.dx, blockwidth) == 0 && (j == gs.trxpos.dx) && (alignedY > endY) && alignedX > gs.trxpos.dx; \ + \ + if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { \ + /* hack */ \ + int testwidth = (int)nSize - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx); \ + if ((testwidth <= widthlimit) && (testwidth >= -widthlimit)) { \ + /* Don't transfer */ \ + /*DEBUG_LOG("bad texture %s: %d %d %d\n", #psm, gs.trxpos.dx, gs.imageEndX, nQWordSize);*/ \ + gs.imageTransfer = -1; \ + } \ + bCanAlign = false; \ + } \ + \ + /* first align on block boundary */ \ + if( MOD_POW2(i, blockheight) || !bCanAlign ) { \ + \ + if( !bCanAlign ) \ + endY = gs.imageEndY; /* transfer the whole image */ \ + else \ + assert( endY < gs.imageEndY); /* part of alignment condition */ \ + \ + if( ((gs.imageEndX-gs.trxpos.dx)%widthlimit) || ((gs.imageEndX-j)%widthlimit) ) { \ + /* transmit with a width of 1 */ \ + TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, (1+(DSTPSM == 0x14)), endY); \ + } \ + else { \ + TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, widthlimit, endY); \ + } \ + \ + if( nSize == 0 || i == gs.imageEndY ) \ + goto End; \ + } \ + \ + assert( MOD_POW2(i, blockheight) == 0 && j == gs.trxpos.dx); \ + \ + /* can align! */ \ + pitch = gs.imageEndX-gs.trxpos.dx; \ + area = pitch*blockheight; \ + fracX = gs.imageEndX-alignedX; \ + \ + /* on top of checking whether pbuf is alinged, make sure that the width is at least aligned to its limits (due to bugs in pcsx2) */ \ + bAligned = !((uptr)pbuf & 0xf) && (TRANSMIT_PITCH##TransSfx(pitch, T)&0xf) == 0; \ + \ + /* transfer aligning to blocks */ \ + for(; i < alignedY && nSize >= area; i += blockheight, nSize -= area) { \ + \ + if( bAligned || ((DSTPSM==PSMCT24) || (DSTPSM==PSMT8H) || (DSTPSM==PSMT4HH) || (DSTPSM==PSMT4HL)) ) { \ + for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH##TransSfx(blockwidth, T)/sizeof(T)) { \ + SwizzleBlock(pstart + getPixelAddress##psm##_0(tempj, i, gs.dstbuf.bw)*blockbits/8, \ + (u8*)pbuf, TRANSMIT_PITCH##TransSfx(pitch, T)); \ + } \ + } \ + else { \ + for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH##TransSfx(blockwidth, T)/sizeof(T)) { \ + SwizzleBlock##u(pstart + getPixelAddress##psm##_0(tempj, i, gs.dstbuf.bw)*blockbits/8, \ + (u8*)pbuf, TRANSMIT_PITCH##TransSfx(pitch, T)); \ + } \ + } \ + \ + /* transfer the rest */ \ + if( alignedX < gs.imageEndX ) { \ + TRANSMIT_HOSTLOCAL_X##TransSfx(psm, T, widthlimit, blockheight, alignedX); \ + pbuf -= TRANSMIT_PITCH##TransSfx((alignedX-gs.trxpos.dx), T)/sizeof(T); \ + } \ + else pbuf += (blockheight-1)*TRANSMIT_PITCH##TransSfx(pitch, T)/sizeof(T); \ + j = gs.trxpos.dx; \ + } \ + \ + if( TRANSMIT_PITCH##TransSfx(nSize, T)/4 > 0 ) { \ + TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, widthlimit, gs.imageEndY); \ + /* sometimes wrong sizes are sent (tekken tag) */ \ + assert( gs.imageTransfer == -1 || TRANSMIT_PITCH##TransSfx(nSize,T)/4 <= 2 ); \ + } \ + \ + END_HOSTLOCAL(); \ + return (nSize * TRANSMIT_PITCH##TransSfx(2, T) + nLeftOver)/2; \ +} \ + +DEFINE_TRANSFERLOCAL(32, u32, 2, 32, 8, 8, _, SwizzleBlock32); +DEFINE_TRANSFERLOCAL(32Z, u32, 2, 32, 8, 8, _, SwizzleBlock32); +DEFINE_TRANSFERLOCAL(24, u8, 8, 32, 8, 8, _24, SwizzleBlock24); +DEFINE_TRANSFERLOCAL(24Z, u8, 8, 32, 8, 8, _24, SwizzleBlock24); +DEFINE_TRANSFERLOCAL(16, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(16S, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(16Z, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(16SZ, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(8, u8, 4, 8, 16, 16, _, SwizzleBlock8); +DEFINE_TRANSFERLOCAL(4, u8, 8, 4, 32, 16, _4, SwizzleBlock4); +DEFINE_TRANSFERLOCAL(8H, u8, 4, 32, 8, 8, _, SwizzleBlock8H); +DEFINE_TRANSFERLOCAL(4HL, u8, 8, 32, 8, 8, _4, SwizzleBlock4HL); +DEFINE_TRANSFERLOCAL(4HH, u8, 8, 32, 8, 8, _4, SwizzleBlock4HH); + +//#define T u8 +//#define widthlimit 8 +//#define blockbits 4 +//#define blockwidth 32 +//#define blockheight 16 +// +//void TransferHostLocal4(const void* pbyMem, u32 nQWordSize) +//{ +// START_HOSTLOCAL(); +// +// const T* pbuf = (const T*)pbyMem; +// u32 nSize = nQWordSize*16*2/TRANSMIT_PITCH_4(2, T); +// nSize = min(nSize, gs.imageWnew * gs.imageHnew); +// +// int endY = ROUND_UPPOW2(i, blockheight); +// int alignedY = ROUND_DOWNPOW2(gs.imageEndY, blockheight); +// int alignedX = ROUND_DOWNPOW2(gs.imageEndX, blockwidth); +// bool bCanAlign = MOD_POW2(gs.trxpos.dx, blockwidth) == 0 && (j == gs.trxpos.dx) && (alignedY > endY) && alignedX > gs.trxpos.dx; +// +// if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { +// /* hack */ +// if( abs((int)nSize - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx)) <= widthlimit ) { +// /* don't transfer */ +// /*DEBUG_LOG("bad texture %s: %d %d %d\n", #psm, gs.trxpos.dx, gs.imageEndX, nQWordSize);*/ +// gs.imageTransfer = -1; +// } +// bCanAlign = false; +// } +// +// /* first align on block boundary */ +// if( MOD_POW2(i, blockheight) || !bCanAlign ) { +// +// if( !bCanAlign ) +// endY = gs.imageEndY; /* transfer the whole image */ +// else +// assert( endY < gs.imageEndY); /* part of alignment condition */ +// +// if( (DSTPSM == 0x13 || DSTPSM == 0x14) && ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) { +// /* transmit with a width of 1 */ +// TRANSMIT_HOSTLOCAL_Y_4(4, T, (1+(DSTPSM == 0x14)), endY); +// } +// else { +// TRANSMIT_HOSTLOCAL_Y_4(4, T, widthlimit, endY); +// } +// +// if( nSize == 0 || i == gs.imageEndY ) +// goto End; +// } +// +// assert( MOD_POW2(i, blockheight) == 0 && j == gs.trxpos.dx); +// +// /* can align! */ +// int pitch = gs.imageEndX-gs.trxpos.dx; +// u32 area = pitch*blockheight; +// int fracX = gs.imageEndX-alignedX; +// +// /* on top of checking whether pbuf is alinged, make sure that the width is at least aligned to its limits (due to bugs in pcsx2) */ +// bool bAligned = !((u32)pbuf & 0xf) && (TRANSMIT_PITCH_4(pitch, T)&0xf) == 0; +// +// /* transfer aligning to blocks */ +// for(; i < alignedY && nSize >= area; i += blockheight, nSize -= area) { +// +// if( bAligned || ((DSTPSM==PSMCT24) || (DSTPSM==PSMT8H) || (DSTPSM==PSMT4HH) || (DSTPSM==PSMT4HL)) ) { +// for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH_4(blockwidth, T)/sizeof(T)) { +// SwizzleBlock4(pstart + getPixelAddress4_0(tempj, i, gs.dstbuf.bw)*blockbits/8, +// (u8*)pbuf, TRANSMIT_PITCH_4(pitch, T)); +// } +// } +// else { +// for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH_4(blockwidth, T)/sizeof(T)) { +// SwizzleBlock4u(pstart + getPixelAddress4_0(tempj, i, gs.dstbuf.bw)*blockbits/8, +// (u8*)pbuf, TRANSMIT_PITCH_4(pitch, T)); +// } +// } +// +// /* transfer the rest */ +// if( alignedX < gs.imageEndX ) { +// TRANSMIT_HOSTLOCAL_X_4(4, T, widthlimit, blockheight, alignedX); +// pbuf -= TRANSMIT_PITCH_4((alignedX-gs.trxpos.dx), T)/sizeof(T); +// } +// else pbuf += (blockheight-1)*TRANSMIT_PITCH_4(pitch, T)/sizeof(T); +// j = 0; +// } +// +// if( TRANSMIT_PITCH_4(nSize, T)/4 > 0 ) { +// TRANSMIT_HOSTLOCAL_Y_4(4, T, widthlimit, gs.imageEndY); +// /* sometimes wrong sizes are sent (tekken tag) */ +// assert( gs.imageTransfer == -1 || TRANSMIT_PITCH_4(nSize,T)/4 <= 2 ); +// } +// +// END_HOSTLOCAL(); +//} + +void TransferLocalHost32(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost24(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16S(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost8(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost4(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost8H(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost4HL(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost4HH(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost32Z(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost24Z(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16Z(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16SZ(void* pbyMem, u32 nQWordSize) +{ +} + +#define FILL_BLOCK(bw, bh, ox, oy, mult, psm, psmcol) { \ + b.vTexDims = D3DXVECTOR2(BLOCK_TEXWIDTH/(float)(bw), BLOCK_TEXHEIGHT/(float)bh); \ + b.vTexBlock = D3DXVECTOR4((float)bw/BLOCK_TEXWIDTH, (float)bh/BLOCK_TEXHEIGHT, ((float)ox+0.2f)/BLOCK_TEXWIDTH, ((float)oy+0.05f)/BLOCK_TEXHEIGHT); \ + b.width = bw; \ + b.height = bh; \ + b.colwidth = bh / 4; \ + b.colheight = bw / 8; \ + b.bpp = 32/mult; \ + \ + b.pageTable = &g_pageTable##psm[0][0]; \ + b.blockTable = &g_blockTable##psm[0][0]; \ + b.columnTable = &g_columnTable##psmcol[0][0]; \ + assert( sizeof(g_pageTable##psm) == bw*bh*sizeof(g_pageTable##psm[0][0]) ); \ + psrcf = (float*)pBlockTexture->pBits + ox + oy * pBlockTexture->Pitch/sizeof(float); \ + psrcw = (WORD*)pBlockTexture->pBits + ox + oy * pBlockTexture->Pitch/sizeof(WORD); \ + for(i = 0; i < bh; ++i) { \ + for(j = 0; j < bw; ++j) { \ + /* fill the table */ \ + u32 u = g_blockTable##psm[(i / b.colheight)][(j / b.colwidth)] * 64 * mult + g_columnTable##psmcol[i%b.colheight][j%b.colwidth]; \ + b.pageTable[i*bw+j] = u; \ + if( format == D3DFMT_R32F ) { \ + psrcf[i*pBlockTexture->Pitch/sizeof(float)+j] = (float)(u) / (float)(GPU_TEXWIDTH*mult); \ + } \ + else { \ + psrcw[i*pBlockTexture->Pitch/sizeof(WORD)+j] = u; \ + } \ + } \ + } \ + \ + if( pBilinearTexture != NULL ) { \ + assert( format == D3DFMT_R32F ); \ + psrcv = (DXVEC4*)pBilinearTexture->pBits + ox + oy * pBilinearTexture->Pitch/sizeof(DXVEC4); \ + for(i = 0; i < bh; ++i) { \ + for(j = 0; j < bw; ++j) { \ + DXVEC4* pv = &psrcv[i*pBilinearTexture->Pitch/sizeof(DXVEC4)+j]; \ + pv->x = psrcf[i*pBlockTexture->Pitch/sizeof(float)+j]; \ + pv->y = psrcf[i*pBlockTexture->Pitch/sizeof(float)+((j+1)%bw)]; \ + pv->z = psrcf[((i+1)%bh)*pBlockTexture->Pitch/sizeof(float)+j]; \ + pv->w = psrcf[((i+1)%bh)*pBlockTexture->Pitch/sizeof(float)+((j+1)%bw)]; \ + } \ + } \ + } \ + b.getPixelAddress = getPixelAddress##psm; \ + b.getPixelAddress_0 = getPixelAddress##psm##_0; \ + b.writePixel = writePixel##psm; \ + b.writePixel_0 = writePixel##psm##_0; \ + b.readPixel = readPixel##psm; \ + b.readPixel_0 = readPixel##psm##_0; \ + b.TransferHostLocal = TransferHostLocal##psm; \ + b.TransferLocalHost = TransferLocalHost##psm; \ +} \ + +void BLOCK::FillBlocks(const D3DLOCKED_RECT* pBlockTexture, const D3DLOCKED_RECT* pBilinearTexture, D3DFORMAT format) +{ + assert( pBlockTexture != NULL ); + assert( format == D3DFMT_R32F || format == D3DFMT_G16R16 ); + + int i, j; + BLOCK b; + float* psrcf = NULL; + WORD* psrcw = NULL; + DXVEC4* psrcv = NULL; + + memset(m_Blocks, 0, sizeof(m_Blocks)); + + // 32 + FILL_BLOCK(64, 32, 0, 0, 1, 32, 32); + m_Blocks[PSMCT32] = b; + + // 24 (same as 32 except write/readPixel are different) + m_Blocks[PSMCT24] = b; + m_Blocks[PSMCT24].writePixel = writePixel24; + m_Blocks[PSMCT24].writePixel_0 = writePixel24_0; + m_Blocks[PSMCT24].readPixel = readPixel24; + m_Blocks[PSMCT24].readPixel_0 = readPixel24_0; + m_Blocks[PSMCT24].TransferHostLocal = TransferHostLocal24; + m_Blocks[PSMCT24].TransferLocalHost = TransferLocalHost24; + + // 8H (same as 32 except write/readPixel are different) + m_Blocks[PSMT8H] = b; + m_Blocks[PSMT8H].writePixel = writePixel8H; + m_Blocks[PSMT8H].writePixel_0 = writePixel8H_0; + m_Blocks[PSMT8H].readPixel = readPixel8H; + m_Blocks[PSMT8H].readPixel_0 = readPixel8H_0; + m_Blocks[PSMT8H].TransferHostLocal = TransferHostLocal8H; + m_Blocks[PSMT8H].TransferLocalHost = TransferLocalHost8H; + + m_Blocks[PSMT4HL] = b; + m_Blocks[PSMT4HL].writePixel = writePixel4HL; + m_Blocks[PSMT4HL].writePixel_0 = writePixel4HL_0; + m_Blocks[PSMT4HL].readPixel = readPixel4HL; + m_Blocks[PSMT4HL].readPixel_0 = readPixel4HL_0; + m_Blocks[PSMT4HL].TransferHostLocal = TransferHostLocal4HL; + m_Blocks[PSMT4HL].TransferLocalHost = TransferLocalHost4HL; + + m_Blocks[PSMT4HH] = b; + m_Blocks[PSMT4HH].writePixel = writePixel4HH; + m_Blocks[PSMT4HH].writePixel_0 = writePixel4HH_0; + m_Blocks[PSMT4HH].readPixel = readPixel4HH; + m_Blocks[PSMT4HH].readPixel_0 = readPixel4HH_0; + m_Blocks[PSMT4HH].TransferHostLocal = TransferHostLocal4HH; + m_Blocks[PSMT4HH].TransferLocalHost = TransferLocalHost4HH; + + // 32z + FILL_BLOCK(64, 32, 64, 0, 1, 32Z, 32); + m_Blocks[PSMT32Z] = b; + + // 24Z (same as 32Z except write/readPixel are different) + m_Blocks[PSMT24Z] = b; + m_Blocks[PSMT24Z].writePixel = writePixel24Z; + m_Blocks[PSMT24Z].writePixel_0 = writePixel24Z_0; + m_Blocks[PSMT24Z].readPixel = readPixel24Z; + m_Blocks[PSMT24Z].readPixel_0 = readPixel24Z_0; + m_Blocks[PSMT24Z].TransferHostLocal = TransferHostLocal24Z; + m_Blocks[PSMT24Z].TransferLocalHost = TransferLocalHost24Z; + + // 16 + FILL_BLOCK(64, 64, 0, 32, 2, 16, 16); + m_Blocks[PSMCT16] = b; + + // 16s + FILL_BLOCK(64, 64, 64, 32, 2, 16S, 16); + m_Blocks[PSMCT16S] = b; + + // 16z + FILL_BLOCK(64, 64, 0, 96, 2, 16Z, 16); + m_Blocks[PSMT16Z] = b; + + // 16sz + FILL_BLOCK(64, 64, 64, 96, 2, 16SZ, 16); + m_Blocks[PSMT16SZ] = b; + + // 8 + FILL_BLOCK(128, 64, 0, 160, 4, 8, 8); + m_Blocks[PSMT8] = b; + + // 4 + FILL_BLOCK(128, 128, 0, 224, 8, 4, 4); + m_Blocks[PSMT4] = b; +} diff --git a/plugins/zerogs/dx/Mem.h b/plugins/zerogs/dx/Mem.h index 5d3e89ec8e..12a3e9a280 100644 --- a/plugins/zerogs/dx/Mem.h +++ b/plugins/zerogs/dx/Mem.h @@ -1,486 +1,486 @@ -/* ZeroGS - * Copyright (C) 2005-2006 zerofrog@gmail.com - * - * 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 - */ - -#ifndef __MEM_H__ -#define __MEM_H__ - -#include - -// works only when base is a power of 2 -#define ROUND_UPPOW2(val, base) (((val)+(base-1))&~(base-1)) -#define ROUND_DOWNPOW2(val, base) ((val)&~(base-1)) -#define MOD_POW2(val, base) ((val)&(base-1)) - -// d3d texture dims -#define BLOCK_TEXWIDTH 128 -#define BLOCK_TEXHEIGHT 512 - -// rest not visible externally -struct BLOCK -{ - BLOCK() { memset(this, 0, sizeof(BLOCK)); } - - // shader constants for this block - D3DXVECTOR4 vTexBlock; - D3DXVECTOR2 vTexDims; - int width, height; // dims of one page in pixels - int bpp; - int colwidth, colheight; - u32* pageTable; // offset inside each page - u32* blockTable; - u32* columnTable; - - u32 (*getPixelAddress)(int x, int y, u32 bp, u32 bw); - u32 (*getPixelAddress_0)(int x, int y, u32 bw); - void (*writePixel)(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw); - void (*writePixel_0)(void* pmem, int x, int y, u32 pixel, u32 bw); - u32 (*readPixel)(const void* pmem, int x, int y, u32 bp, u32 bw); - u32 (*readPixel_0)(const void* pmem, int x, int y, u32 bw); - int (*TransferHostLocal)(const void* pbyMem, u32 nQWordSize); - void (*TransferLocalHost)(void* pbyMem, u32 nQWordSize); - - // texture must be of dims BLOCK_TEXWIDTH and BLOCK_TEXHEIGHT - static void FillBlocks(const D3DLOCKED_RECT* pBlockTexture, const D3DLOCKED_RECT* pBilinearTexture, D3DFORMAT format); -}; - -extern BLOCK m_Blocks[]; - -extern u32 g_blockTable32[4][8]; -extern u32 g_blockTable32Z[4][8]; -extern u32 g_blockTable16[8][4]; -extern u32 g_blockTable16S[8][4]; -extern u32 g_blockTable16Z[8][4]; -extern u32 g_blockTable16SZ[8][4]; -extern u32 g_blockTable8[4][8]; -extern u32 g_blockTable4[8][4]; - -extern u32 g_columnTable32[8][8]; -extern u32 g_columnTable16[8][16]; -extern u32 g_columnTable8[16][16]; -extern u32 g_columnTable4[16][32]; - -extern u32 g_pageTable32[32][64]; -extern u32 g_pageTable32Z[32][64]; -extern u32 g_pageTable16[64][64]; -extern u32 g_pageTable16S[64][64]; -extern u32 g_pageTable16Z[64][64]; -extern u32 g_pageTable16SZ[64][64]; -extern u32 g_pageTable8[64][128]; -extern u32 g_pageTable4[128][128]; - -static __forceinline u32 getPixelAddress32(int x, int y, u32 bp, u32 bw) { - u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); - u32 word = bp * 64 + basepage * 2048 + g_pageTable32[y&31][x&63]; - //assert (word < 0x100000); - //word = min(word, 0xfffff); - return word; -} - -static __forceinline u32 getPixelAddress32_0(int x, int y, u32 bw) { - u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); - u32 word = basepage * 2048 + g_pageTable32[y&31][x&63]; - //assert (word < 0x100000); - //word = min(word, 0xfffff); - return word; -} - -#define getPixelAddress24 getPixelAddress32 -#define getPixelAddress24_0 getPixelAddress32_0 -#define getPixelAddress8H getPixelAddress32 -#define getPixelAddress8H_0 getPixelAddress32_0 -#define getPixelAddress4HL getPixelAddress32 -#define getPixelAddress4HL_0 getPixelAddress32_0 -#define getPixelAddress4HH getPixelAddress32 -#define getPixelAddress4HH_0 getPixelAddress32_0 - -static __forceinline u32 getPixelAddress16(int x, int y, u32 bp, u32 bw) { - u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); - u32 word = bp * 128 + basepage * 4096 + g_pageTable16[y&63][x&63]; - //assert (word < 0x200000); - //word = min(word, 0x1fffff); - return word; -} - -static __forceinline u32 getPixelAddress16_0(int x, int y, u32 bw) { - u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); - u32 word = basepage * 4096 + g_pageTable16[y&63][x&63]; - //assert (word < 0x200000); - //word = min(word, 0x1fffff); - return word; -} - -static __forceinline u32 getPixelAddress16S(int x, int y, u32 bp, u32 bw) { - u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); - u32 word = bp * 128 + basepage * 4096 + g_pageTable16S[y&63][x&63]; - //assert (word < 0x200000); - //word = min(word, 0x1fffff); - return word; -} - -static __forceinline u32 getPixelAddress16S_0(int x, int y, u32 bw) { - u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); - u32 word = basepage * 4096 + g_pageTable16S[y&63][x&63]; - //assert (word < 0x200000); - //word = min(word, 0x1fffff); - return word; -} - -static __forceinline u32 getPixelAddress8(int x, int y, u32 bp, u32 bw) { - u32 basepage = ((y>>6) * ((bw+127)>>7)) + (x>>7); - u32 word = bp * 256 + basepage * 8192 + g_pageTable8[y&63][x&127]; - //assert (word < 0x400000); - //word = min(word, 0x3fffff); - return word; -} - -static __forceinline u32 getPixelAddress8_0(int x, int y, u32 bw) { - u32 basepage = ((y>>6) * ((bw+127)>>7)) + (x>>7); - u32 word = basepage * 8192 + g_pageTable8[y&63][x&127]; - //assert (word < 0x400000); - //word = min(word, 0x3fffff); - return word; -} - -static __forceinline u32 getPixelAddress4(int x, int y, u32 bp, u32 bw) { - u32 basepage = ((y>>7) * ((bw+127)>>7)) + (x>>7); - u32 word = bp * 512 + basepage * 16384 + g_pageTable4[y&127][x&127]; - //assert (word < 0x800000); - //word = min(word, 0x7fffff); - return word; -} - -static __forceinline u32 getPixelAddress4_0(int x, int y, u32 bw) { - u32 basepage = ((y>>7) * ((bw+127)>>7)) + (x>>7); - u32 word = basepage * 16384 + g_pageTable4[y&127][x&127]; - //assert (word < 0x800000); - //word = min(word, 0x7fffff); - return word; -} - -static __forceinline u32 getPixelAddress32Z(int x, int y, u32 bp, u32 bw) { - u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); - u32 word = bp * 64 + basepage * 2048 + g_pageTable32Z[y&31][x&63]; - //assert (word < 0x100000); - //word = min(word, 0xfffff); - return word; -} - -static __forceinline u32 getPixelAddress32Z_0(int x, int y, u32 bw) { - u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); - u32 word = basepage * 2048 + g_pageTable32Z[y&31][x&63]; - //assert (word < 0x100000); - //word = min(word, 0xfffff); - return word; -} - -#define getPixelAddress24Z getPixelAddress32Z -#define getPixelAddress24Z_0 getPixelAddress32Z_0 - -static __forceinline u32 getPixelAddress16Z(int x, int y, u32 bp, u32 bw) { - u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); - u32 word = bp * 128 + basepage * 4096 + g_pageTable16Z[y&63][x&63]; - //assert (word < 0x200000); - //word = min(word, 0x1fffff); - return word; -} - -static __forceinline u32 getPixelAddress16Z_0(int x, int y, u32 bw) { - u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); - u32 word = basepage * 4096 + g_pageTable16Z[y&63][x&63]; - //assert (word < 0x200000); - //word = min(word, 0x1fffff); - return word; -} - -static __forceinline u32 getPixelAddress16SZ(int x, int y, u32 bp, u32 bw) { - u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); - u32 word = bp * 128 + basepage * 4096 + g_pageTable16SZ[y&63][x&63]; - //assert (word < 0x200000); - //word = min(word, 0x1fffff); - return word; -} - -static __forceinline u32 getPixelAddress16SZ_0(int x, int y, u32 bw) { - u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); - u32 word = basepage * 4096 + g_pageTable16SZ[y&63][x&63]; - //assert (word < 0x200000); - //word = min(word, 0x1fffff); - return word; -} - -static __forceinline void writePixel32(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - ((u32*)pmem)[getPixelAddress32(x, y, bp, bw)] = pixel; -} - -static __forceinline void writePixel24(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - u8 *buf = (u8*)&((u32*)pmem)[getPixelAddress32(x, y, bp, bw)]; - u8 *pix = (u8*)&pixel; - buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; -} - -static __forceinline void writePixel16(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - ((u16*)pmem)[getPixelAddress16(x, y, bp, bw)] = pixel; -} - -static __forceinline void writePixel16S(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - ((u16*)pmem)[getPixelAddress16S(x, y, bp, bw)] = pixel; -} - -static __forceinline void writePixel8(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - ((u8*)pmem)[getPixelAddress8(x, y, bp, bw)] = pixel; -} - -static __forceinline void writePixel8H(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - ((u8*)pmem)[4*getPixelAddress32(x, y, bp, bw)+3] = pixel; -} - -static __forceinline void writePixel4(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - u32 addr = getPixelAddress4(x, y, bp, bw); - u8 pix = ((u8*)pmem)[addr/2]; - if (addr & 0x1) ((u8*)pmem)[addr/2] = (pix & 0x0f) | (pixel << 4); - else ((u8*)pmem)[addr/2] = (pix & 0xf0) | (pixel); -} - -static __forceinline void writePixel4HL(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - u8 *p = (u8*)pmem + 4*getPixelAddress4HL(x, y, bp, bw)+3; - *p = (*p & 0xf0) | pixel; -} - -static __forceinline void writePixel4HH(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - u8 *p = (u8*)pmem + 4*getPixelAddress4HH(x, y, bp, bw)+3; - *p = (*p & 0x0f) | (pixel<<4); -} - -static __forceinline void writePixel32Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - ((u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)] = pixel; -} - -static __forceinline void writePixel24Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - u8 *buf = (u8*)pmem + 4*getPixelAddress32Z(x, y, bp, bw); - u8 *pix = (u8*)&pixel; - buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; -} - -static __forceinline void writePixel16Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - ((u16*)pmem)[getPixelAddress16Z(x, y, bp, bw)] = pixel; -} - -static __forceinline void writePixel16SZ(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - ((u16*)pmem)[getPixelAddress16SZ(x, y, bp, bw)] = pixel; -} - - -/////////////// - -static __forceinline u32 readPixel32(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u32*)pmem)[getPixelAddress32(x, y, bp, bw)]; -} - -static __forceinline u32 readPixel24(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u32*)pmem)[getPixelAddress32(x, y, bp, bw)] & 0xffffff; -} - -static __forceinline u32 readPixel16(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u16*)pmem)[getPixelAddress16(x, y, bp, bw)]; -} - -static __forceinline u32 readPixel16S(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u16*)pmem)[getPixelAddress16S(x, y, bp, bw)]; -} - -static __forceinline u32 readPixel8(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u8*)pmem)[getPixelAddress8(x, y, bp, bw)]; -} - -static __forceinline u32 readPixel8H(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u8*)pmem)[4*getPixelAddress32(x, y, bp, bw) + 3]; -} - -static __forceinline u32 readPixel4(const void* pmem, int x, int y, u32 bp, u32 bw) { - u32 addr = getPixelAddress4(x, y, bp, bw); - u8 pix = ((const u8*)pmem)[addr/2]; - if (addr & 0x1) - return pix >> 4; - else return pix & 0xf; -} - -static __forceinline u32 readPixel4HL(const void* pmem, int x, int y, u32 bp, u32 bw) { - const u8 *p = (const u8*)pmem+4*getPixelAddress4HL(x, y, bp, bw)+3; - return *p & 0x0f; -} - -static __forceinline u32 readPixel4HH(const void* pmem, int x, int y, u32 bp, u32 bw) { - const u8 *p = (const u8*)pmem+4*getPixelAddress4HH(x, y, bp, bw) + 3; - return *p >> 4; -} - -/////////////// - -static __forceinline u32 readPixel32Z(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)]; -} - -static __forceinline u32 readPixel24Z(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)] & 0xffffff; -} - -static __forceinline u32 readPixel16Z(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u16*)pmem)[getPixelAddress16Z(x, y, bp, bw)]; -} - -static __forceinline u32 readPixel16SZ(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u16*)pmem)[getPixelAddress16SZ(x, y, bp, bw)]; -} - -/////////////////////////////// -// Functions that take 0 bps // -/////////////////////////////// - -static __forceinline void writePixel32_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - ((u32*)pmem)[getPixelAddress32_0(x, y, bw)] = pixel; -} - -static __forceinline void writePixel24_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - u8 *buf = (u8*)&((u32*)pmem)[getPixelAddress32_0(x, y, bw)]; - u8 *pix = (u8*)&pixel; -#if defined(_MSC_VER) && defined(__x86_64__) - memcpy(buf, pix, 3); -#else - buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; -#endif -} - -static __forceinline void writePixel16_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - ((u16*)pmem)[getPixelAddress16_0(x, y, bw)] = pixel; -} - -static __forceinline void writePixel16S_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - ((u16*)pmem)[getPixelAddress16S_0(x, y, bw)] = pixel; -} - -static __forceinline void writePixel8_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - ((u8*)pmem)[getPixelAddress8_0(x, y, bw)] = pixel; -} - -static __forceinline void writePixel8H_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - ((u8*)pmem)[4*getPixelAddress32_0(x, y, bw)+3] = pixel; -} - -static __forceinline void writePixel4_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - u32 addr = getPixelAddress4_0(x, y, bw); - u8 pix = ((u8*)pmem)[addr/2]; - if (addr & 0x1) ((u8*)pmem)[addr/2] = (pix & 0x0f) | (pixel << 4); - else ((u8*)pmem)[addr/2] = (pix & 0xf0) | (pixel); -} - -static __forceinline void writePixel4HL_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - u8 *p = (u8*)pmem + 4*getPixelAddress4HL_0(x, y, bw)+3; - *p = (*p & 0xf0) | pixel; -} - -static __forceinline void writePixel4HH_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - u8 *p = (u8*)pmem + 4*getPixelAddress4HH_0(x, y, bw)+3; - *p = (*p & 0x0f) | (pixel<<4); -} - -static __forceinline void writePixel32Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - ((u32*)pmem)[getPixelAddress32Z_0(x, y, bw)] = pixel; -} - -static __forceinline void writePixel24Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - u8 *buf = (u8*)pmem + 4*getPixelAddress32Z_0(x, y, bw); - u8 *pix = (u8*)&pixel; -#if defined(_MSC_VER) && defined(__x86_64__) - memcpy(buf, pix, 3); -#else - buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; -#endif -} - -static __forceinline void writePixel16Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - ((u16*)pmem)[getPixelAddress16Z_0(x, y, bw)] = pixel; -} - -static __forceinline void writePixel16SZ_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - ((u16*)pmem)[getPixelAddress16SZ_0(x, y, bw)] = pixel; -} - - -/////////////// - -static __forceinline u32 readPixel32_0(const void* pmem, int x, int y, u32 bw) { - return ((const u32*)pmem)[getPixelAddress32_0(x, y, bw)]; -} - -static __forceinline u32 readPixel24_0(const void* pmem, int x, int y, u32 bw) { - return ((const u32*)pmem)[getPixelAddress32_0(x, y, bw)] & 0xffffff; -} - -static __forceinline u32 readPixel16_0(const void* pmem, int x, int y, u32 bw) { - return ((const u16*)pmem)[getPixelAddress16_0(x, y, bw)]; -} - -static __forceinline u32 readPixel16S_0(const void* pmem, int x, int y, u32 bw) { - return ((const u16*)pmem)[getPixelAddress16S_0(x, y, bw)]; -} - -static __forceinline u32 readPixel8_0(const void* pmem, int x, int y, u32 bw) { - return ((const u8*)pmem)[getPixelAddress8_0(x, y, bw)]; -} - -static __forceinline u32 readPixel8H_0(const void* pmem, int x, int y, u32 bw) { - return ((const u8*)pmem)[4*getPixelAddress32_0(x, y, bw) + 3]; -} - -static __forceinline u32 readPixel4_0(const void* pmem, int x, int y, u32 bw) { - u32 addr = getPixelAddress4_0(x, y, bw); - u8 pix = ((const u8*)pmem)[addr/2]; - if (addr & 0x1) - return pix >> 4; - else return pix & 0xf; -} - -static __forceinline u32 readPixel4HL_0(const void* pmem, int x, int y, u32 bw) { - const u8 *p = (const u8*)pmem+4*getPixelAddress4HL_0(x, y, bw)+3; - return *p & 0x0f; -} - -static __forceinline u32 readPixel4HH_0(const void* pmem, int x, int y, u32 bw) { - const u8 *p = (const u8*)pmem+4*getPixelAddress4HH_0(x, y, bw) + 3; - return *p >> 4; -} - -/////////////// - -static __forceinline u32 readPixel32Z_0(const void* pmem, int x, int y, u32 bw) { - return ((const u32*)pmem)[getPixelAddress32Z_0(x, y, bw)]; -} - -static __forceinline u32 readPixel24Z_0(const void* pmem, int x, int y, u32 bw) { - return ((const u32*)pmem)[getPixelAddress32Z_0(x, y, bw)] & 0xffffff; -} - -static __forceinline u32 readPixel16Z_0(const void* pmem, int x, int y, u32 bw) { - return ((const u16*)pmem)[getPixelAddress16Z_0(x, y, bw)]; -} - -static __forceinline u32 readPixel16SZ_0(const void* pmem, int x, int y, u32 bw) { - return ((const u16*)pmem)[getPixelAddress16SZ_0(x, y, bw)]; -} - -#endif /* __MEM_H__ */ +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#ifndef __MEM_H__ +#define __MEM_H__ + +#include + +// works only when base is a power of 2 +#define ROUND_UPPOW2(val, base) (((val)+(base-1))&~(base-1)) +#define ROUND_DOWNPOW2(val, base) ((val)&~(base-1)) +#define MOD_POW2(val, base) ((val)&(base-1)) + +// d3d texture dims +#define BLOCK_TEXWIDTH 128 +#define BLOCK_TEXHEIGHT 512 + +// rest not visible externally +struct BLOCK +{ + BLOCK() { memset(this, 0, sizeof(BLOCK)); } + + // shader constants for this block + D3DXVECTOR4 vTexBlock; + D3DXVECTOR2 vTexDims; + int width, height; // dims of one page in pixels + int bpp; + int colwidth, colheight; + u32* pageTable; // offset inside each page + u32* blockTable; + u32* columnTable; + + u32 (*getPixelAddress)(int x, int y, u32 bp, u32 bw); + u32 (*getPixelAddress_0)(int x, int y, u32 bw); + void (*writePixel)(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw); + void (*writePixel_0)(void* pmem, int x, int y, u32 pixel, u32 bw); + u32 (*readPixel)(const void* pmem, int x, int y, u32 bp, u32 bw); + u32 (*readPixel_0)(const void* pmem, int x, int y, u32 bw); + int (*TransferHostLocal)(const void* pbyMem, u32 nQWordSize); + void (*TransferLocalHost)(void* pbyMem, u32 nQWordSize); + + // texture must be of dims BLOCK_TEXWIDTH and BLOCK_TEXHEIGHT + static void FillBlocks(const D3DLOCKED_RECT* pBlockTexture, const D3DLOCKED_RECT* pBilinearTexture, D3DFORMAT format); +}; + +extern BLOCK m_Blocks[]; + +extern u32 g_blockTable32[4][8]; +extern u32 g_blockTable32Z[4][8]; +extern u32 g_blockTable16[8][4]; +extern u32 g_blockTable16S[8][4]; +extern u32 g_blockTable16Z[8][4]; +extern u32 g_blockTable16SZ[8][4]; +extern u32 g_blockTable8[4][8]; +extern u32 g_blockTable4[8][4]; + +extern u32 g_columnTable32[8][8]; +extern u32 g_columnTable16[8][16]; +extern u32 g_columnTable8[16][16]; +extern u32 g_columnTable4[16][32]; + +extern u32 g_pageTable32[32][64]; +extern u32 g_pageTable32Z[32][64]; +extern u32 g_pageTable16[64][64]; +extern u32 g_pageTable16S[64][64]; +extern u32 g_pageTable16Z[64][64]; +extern u32 g_pageTable16SZ[64][64]; +extern u32 g_pageTable8[64][128]; +extern u32 g_pageTable4[128][128]; + +static __forceinline u32 getPixelAddress32(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = bp * 64 + basepage * 2048 + g_pageTable32[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +static __forceinline u32 getPixelAddress32_0(int x, int y, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = basepage * 2048 + g_pageTable32[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +#define getPixelAddress24 getPixelAddress32 +#define getPixelAddress24_0 getPixelAddress32_0 +#define getPixelAddress8H getPixelAddress32 +#define getPixelAddress8H_0 getPixelAddress32_0 +#define getPixelAddress4HL getPixelAddress32 +#define getPixelAddress4HL_0 getPixelAddress32_0 +#define getPixelAddress4HH getPixelAddress32 +#define getPixelAddress4HH_0 getPixelAddress32_0 + +static __forceinline u32 getPixelAddress16(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16S(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16S[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16S_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16S[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress8(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * ((bw+127)>>7)) + (x>>7); + u32 word = bp * 256 + basepage * 8192 + g_pageTable8[y&63][x&127]; + //assert (word < 0x400000); + //word = min(word, 0x3fffff); + return word; +} + +static __forceinline u32 getPixelAddress8_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * ((bw+127)>>7)) + (x>>7); + u32 word = basepage * 8192 + g_pageTable8[y&63][x&127]; + //assert (word < 0x400000); + //word = min(word, 0x3fffff); + return word; +} + +static __forceinline u32 getPixelAddress4(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>7) * ((bw+127)>>7)) + (x>>7); + u32 word = bp * 512 + basepage * 16384 + g_pageTable4[y&127][x&127]; + //assert (word < 0x800000); + //word = min(word, 0x7fffff); + return word; +} + +static __forceinline u32 getPixelAddress4_0(int x, int y, u32 bw) { + u32 basepage = ((y>>7) * ((bw+127)>>7)) + (x>>7); + u32 word = basepage * 16384 + g_pageTable4[y&127][x&127]; + //assert (word < 0x800000); + //word = min(word, 0x7fffff); + return word; +} + +static __forceinline u32 getPixelAddress32Z(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = bp * 64 + basepage * 2048 + g_pageTable32Z[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +static __forceinline u32 getPixelAddress32Z_0(int x, int y, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = basepage * 2048 + g_pageTable32Z[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +#define getPixelAddress24Z getPixelAddress32Z +#define getPixelAddress24Z_0 getPixelAddress32Z_0 + +static __forceinline u32 getPixelAddress16Z(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16Z[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16Z_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16Z[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16SZ(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16SZ[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16SZ_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16SZ[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline void writePixel32(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u32*)pmem)[getPixelAddress32(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel24(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *buf = (u8*)&((u32*)pmem)[getPixelAddress32(x, y, bp, bw)]; + u8 *pix = (u8*)&pixel; + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +} + +static __forceinline void writePixel16(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel16S(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16S(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel8(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u8*)pmem)[getPixelAddress8(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel8H(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u8*)pmem)[4*getPixelAddress32(x, y, bp, bw)+3] = pixel; +} + +static __forceinline void writePixel4(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u32 addr = getPixelAddress4(x, y, bp, bw); + u8 pix = ((u8*)pmem)[addr/2]; + if (addr & 0x1) ((u8*)pmem)[addr/2] = (pix & 0x0f) | (pixel << 4); + else ((u8*)pmem)[addr/2] = (pix & 0xf0) | (pixel); +} + +static __forceinline void writePixel4HL(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HL(x, y, bp, bw)+3; + *p = (*p & 0xf0) | pixel; +} + +static __forceinline void writePixel4HH(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HH(x, y, bp, bw)+3; + *p = (*p & 0x0f) | (pixel<<4); +} + +static __forceinline void writePixel32Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel24Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *buf = (u8*)pmem + 4*getPixelAddress32Z(x, y, bp, bw); + u8 *pix = (u8*)&pixel; + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +} + +static __forceinline void writePixel16Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16Z(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel16SZ(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16SZ(x, y, bp, bw)] = pixel; +} + + +/////////////// + +static __forceinline u32 readPixel32(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel24(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32(x, y, bp, bw)] & 0xffffff; +} + +static __forceinline u32 readPixel16(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel16S(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16S(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel8(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u8*)pmem)[getPixelAddress8(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel8H(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u8*)pmem)[4*getPixelAddress32(x, y, bp, bw) + 3]; +} + +static __forceinline u32 readPixel4(const void* pmem, int x, int y, u32 bp, u32 bw) { + u32 addr = getPixelAddress4(x, y, bp, bw); + u8 pix = ((const u8*)pmem)[addr/2]; + if (addr & 0x1) + return pix >> 4; + else return pix & 0xf; +} + +static __forceinline u32 readPixel4HL(const void* pmem, int x, int y, u32 bp, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HL(x, y, bp, bw)+3; + return *p & 0x0f; +} + +static __forceinline u32 readPixel4HH(const void* pmem, int x, int y, u32 bp, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HH(x, y, bp, bw) + 3; + return *p >> 4; +} + +/////////////// + +static __forceinline u32 readPixel32Z(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel24Z(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)] & 0xffffff; +} + +static __forceinline u32 readPixel16Z(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16Z(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel16SZ(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16SZ(x, y, bp, bw)]; +} + +/////////////////////////////// +// Functions that take 0 bps // +/////////////////////////////// + +static __forceinline void writePixel32_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u32*)pmem)[getPixelAddress32_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel24_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *buf = (u8*)&((u32*)pmem)[getPixelAddress32_0(x, y, bw)]; + u8 *pix = (u8*)&pixel; +#if defined(_MSC_VER) && defined(__x86_64__) + memcpy(buf, pix, 3); +#else + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +#endif +} + +static __forceinline void writePixel16_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel16S_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16S_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel8_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u8*)pmem)[getPixelAddress8_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel8H_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u8*)pmem)[4*getPixelAddress32_0(x, y, bw)+3] = pixel; +} + +static __forceinline void writePixel4_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u32 addr = getPixelAddress4_0(x, y, bw); + u8 pix = ((u8*)pmem)[addr/2]; + if (addr & 0x1) ((u8*)pmem)[addr/2] = (pix & 0x0f) | (pixel << 4); + else ((u8*)pmem)[addr/2] = (pix & 0xf0) | (pixel); +} + +static __forceinline void writePixel4HL_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HL_0(x, y, bw)+3; + *p = (*p & 0xf0) | pixel; +} + +static __forceinline void writePixel4HH_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HH_0(x, y, bw)+3; + *p = (*p & 0x0f) | (pixel<<4); +} + +static __forceinline void writePixel32Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u32*)pmem)[getPixelAddress32Z_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel24Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *buf = (u8*)pmem + 4*getPixelAddress32Z_0(x, y, bw); + u8 *pix = (u8*)&pixel; +#if defined(_MSC_VER) && defined(__x86_64__) + memcpy(buf, pix, 3); +#else + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +#endif +} + +static __forceinline void writePixel16Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16Z_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel16SZ_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16SZ_0(x, y, bw)] = pixel; +} + + +/////////////// + +static __forceinline u32 readPixel32_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32_0(x, y, bw)]; +} + +static __forceinline u32 readPixel24_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32_0(x, y, bw)] & 0xffffff; +} + +static __forceinline u32 readPixel16_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16_0(x, y, bw)]; +} + +static __forceinline u32 readPixel16S_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16S_0(x, y, bw)]; +} + +static __forceinline u32 readPixel8_0(const void* pmem, int x, int y, u32 bw) { + return ((const u8*)pmem)[getPixelAddress8_0(x, y, bw)]; +} + +static __forceinline u32 readPixel8H_0(const void* pmem, int x, int y, u32 bw) { + return ((const u8*)pmem)[4*getPixelAddress32_0(x, y, bw) + 3]; +} + +static __forceinline u32 readPixel4_0(const void* pmem, int x, int y, u32 bw) { + u32 addr = getPixelAddress4_0(x, y, bw); + u8 pix = ((const u8*)pmem)[addr/2]; + if (addr & 0x1) + return pix >> 4; + else return pix & 0xf; +} + +static __forceinline u32 readPixel4HL_0(const void* pmem, int x, int y, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HL_0(x, y, bw)+3; + return *p & 0x0f; +} + +static __forceinline u32 readPixel4HH_0(const void* pmem, int x, int y, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HH_0(x, y, bw) + 3; + return *p >> 4; +} + +/////////////// + +static __forceinline u32 readPixel32Z_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z_0(x, y, bw)]; +} + +static __forceinline u32 readPixel24Z_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z_0(x, y, bw)] & 0xffffff; +} + +static __forceinline u32 readPixel16Z_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16Z_0(x, y, bw)]; +} + +static __forceinline u32 readPixel16SZ_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16SZ_0(x, y, bw)]; +} + +#endif /* __MEM_H__ */ diff --git a/plugins/zerogs/dx/Regs.cpp b/plugins/zerogs/dx/Regs.cpp index 6515389b05..2ae3b8e464 100644 --- a/plugins/zerogs/dx/Regs.cpp +++ b/plugins/zerogs/dx/Regs.cpp @@ -1,1116 +1,1116 @@ -/* ZeroGS - * Copyright (C) 2005-2006 zerofrog@gmail.com - * - * 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 - */ - -#if defined(_WIN32) || defined(__WIN32__) -#include -#include -#endif - -#include -#include -#include -#include - -#include "GS.h" -#include "Mem.h" -#include "Regs.h" - -#include "zerogs.h" -#include "targets.h" - -#ifdef _MSC_VER -#pragma warning(disable:4244) -#endif - -GIFRegHandler g_GIFPackedRegHandlers[16] = { - GIFRegHandlerPRIM, GIFPackedRegHandlerRGBA, GIFPackedRegHandlerSTQ, GIFPackedRegHandlerUV, - GIFPackedRegHandlerXYZF2, GIFPackedRegHandlerXYZ2, GIFRegHandlerTEX0_1, GIFRegHandlerTEX0_2, - GIFRegHandlerCLAMP_1, GIFRegHandlerCLAMP_2, GIFPackedRegHandlerFOG, GIFPackedRegHandlerNull, - GIFRegHandlerXYZF3, GIFRegHandlerXYZ3, GIFPackedRegHandlerA_D, GIFPackedRegHandlerNOP }; - -GIFRegHandler g_GIFRegHandlers[] = { - GIFRegHandlerPRIM, GIFRegHandlerRGBAQ, GIFRegHandlerST, GIFRegHandlerUV, - GIFRegHandlerXYZF2, GIFRegHandlerXYZ2, GIFRegHandlerTEX0_1, GIFRegHandlerTEX0_2, - GIFRegHandlerCLAMP_1, GIFRegHandlerCLAMP_2, GIFRegHandlerFOG, GIFRegHandlerNull, - GIFRegHandlerXYZF3, GIFRegHandlerXYZ3, GIFRegHandlerNOP, GIFRegHandlerNOP, - GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, - GIFRegHandlerTEX1_1, GIFRegHandlerTEX1_2, GIFRegHandlerTEX2_1, GIFRegHandlerTEX2_2, - GIFRegHandlerXYOFFSET_1,GIFRegHandlerXYOFFSET_2,GIFRegHandlerPRMODECONT,GIFRegHandlerPRMODE, - GIFRegHandlerTEXCLUT, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, - GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerSCANMSK, GIFRegHandlerNull, - GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, - GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, - GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, - GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, - GIFRegHandlerMIPTBP1_1, GIFRegHandlerMIPTBP1_2, GIFRegHandlerMIPTBP2_1, GIFRegHandlerMIPTBP2_2, - GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerTEXA, - GIFRegHandlerNull, GIFRegHandlerFOGCOL, GIFRegHandlerNull, GIFRegHandlerTEXFLUSH, - GIFRegHandlerSCISSOR_1, GIFRegHandlerSCISSOR_2, GIFRegHandlerALPHA_1, GIFRegHandlerALPHA_2, - GIFRegHandlerDIMX, GIFRegHandlerDTHE, GIFRegHandlerCOLCLAMP, GIFRegHandlerTEST_1, - GIFRegHandlerTEST_2, GIFRegHandlerPABE, GIFRegHandlerFBA_1, GIFRegHandlerFBA_2, - GIFRegHandlerFRAME_1, GIFRegHandlerFRAME_2, GIFRegHandlerZBUF_1, GIFRegHandlerZBUF_2, - GIFRegHandlerBITBLTBUF, GIFRegHandlerTRXPOS, GIFRegHandlerTRXREG, GIFRegHandlerTRXDIR, - GIFRegHandlerHWREG, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, - GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, - GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, - GIFRegHandlerSIGNAL, GIFRegHandlerFINISH, GIFRegHandlerLABEL, GIFRegHandlerNull }; - -C_ASSERT(sizeof(g_GIFRegHandlers)/sizeof(g_GIFRegHandlers[0]) == 100 ); - -// values for keeping track of changes -u32 s_uTex1Data[2][2] = {0}, s_uClampData[2] = {0}; - -void __fastcall GIFPackedRegHandlerNull(u32* data) -{ -#ifdef _DEBUG - DEBUG_LOG("Unexpected packed reg handler %8.8lx_%8.8lx %x\n", data[0], data[1], data[2]); -#endif -} - -void __fastcall GIFPackedRegHandlerRGBA(u32* data) -{ - gs.rgba = (data[0] & 0xff) | - ((data[1] & 0xff) << 8) | - ((data[2] & 0xff) << 16) | - ((data[3] & 0xff) << 24); - gs.vertexregs.rgba = gs.rgba; - gs.vertexregs.q = gs.q; -} - -void __fastcall GIFPackedRegHandlerSTQ(u32* data) -{ - *(u32*)&gs.vertexregs.s = data[0]&0xffffff00; - *(u32*)&gs.vertexregs.t = data[1]&0xffffff00; - *(u32*)&gs.q = data[2]; -} - -void __fastcall GIFPackedRegHandlerUV(u32* data) -{ - gs.vertexregs.u = data[0] & 0x3fff; - gs.vertexregs.v = data[1] & 0x3fff; -} - -void __forceinline KICK_VERTEX2() -{ - if (++gs.primC >= (int)g_primmult[prim->prim]) - { - if (!(g_GameSettings&GAME_XENOSPECHACK) || !ZeroGS::vb[prim->ctxt].zbuf.zmsk) - (*ZeroGS::drawfn[prim->prim])(); - gs.primC -= g_primsub[prim->prim]; - } -} - -void __forceinline KICK_VERTEX3() -{ - if (++gs.primC >= (int)g_primmult[prim->prim]) - { - gs.primC -= g_primsub[prim->prim]; - if (prim->prim == 5) - { - /* tri fans need special processing */ - if (gs.nTriFanVert == gs.primIndex) - gs.primIndex = (gs.primIndex+1) % ARRAYSIZE(gs.gsvertex); - } - } -} - -void __fastcall GIFPackedRegHandlerXYZF2(u32* data) -{ - gs.vertexregs.x = (data[0] >> 0) & 0xffff; - gs.vertexregs.y = (data[1] >> 0) & 0xffff; - gs.vertexregs.z = (data[2] >> 4) & 0xffffff; - gs.vertexregs.f = (data[3] >> 4) & 0xff; - gs.gsvertex[gs.primIndex] = gs.vertexregs; - gs.primIndex = (gs.primIndex+1) % ARRAYSIZE(gs.gsvertex); - - if( data[3] & 0x8000 ) { - KICK_VERTEX3(); - } - else { - KICK_VERTEX2(); - } -} - -void __fastcall GIFPackedRegHandlerXYZ2(u32* data) -{ - gs.vertexregs.x = (data[0] >> 0) & 0xffff; - gs.vertexregs.y = (data[1] >> 0) & 0xffff; - gs.vertexregs.z = data[2]; - gs.gsvertex[gs.primIndex] = gs.vertexregs; - gs.primIndex = (gs.primIndex+1) % ARRAYSIZE(gs.gsvertex); - - if( data[3] & 0x8000 ) { - KICK_VERTEX3(); - } - else { - KICK_VERTEX2(); - } -} - -void __fastcall GIFPackedRegHandlerFOG(u32* data) -{ - gs.vertexregs.f = (data[3]&0xff0)>>4; -} - -void __fastcall GIFPackedRegHandlerA_D(u32* data) -{ - if((data[2] & 0xff) < 100) - g_GIFRegHandlers[data[2] & 0xff](data); - else - GIFRegHandlerNull(data); -} - -void __fastcall GIFPackedRegHandlerNOP(u32* data) -{ -} - -extern int g_PrevBitwiseTexX, g_PrevBitwiseTexY; - -void tex0Write(int i, u32 *data) -{ - u32 psm = (data[0] >> 20) & 0x3f; - if( psm == 9 ) psm = 1; // hmm..., ffx intro menu - - if( m_Blocks[psm].bpp == 0 ) { - // kh and others - return; - } - - ZeroGS::vb[i].uNextTex0Data[0] = data[0]; - ZeroGS::vb[i].uNextTex0Data[1] = data[1]; - ZeroGS::vb[i].bNeedTexCheck = 1; - - // don't update unless necessary - if( PSMT_ISCLUT(psm) ) { - if( ZeroGS::CheckChangeInClut(data[1], psm) ) { - // loading clut, so flush whole texture - ZeroGS::vb[i].FlushTexData(); - } - // check if csa is the same!! (ffx bisaid island, grass) - else if( (data[1]&0x1f780000) != (ZeroGS::vb[i].uCurTex0Data[1]&0x1f780000) ) { - ZeroGS::Flush(i); // flush any previous entries - } - } -} - -void tex2Write(int i, u32 *data) -{ - tex0Info& tex0 = ZeroGS::vb[i].tex0; - - if( ZeroGS::vb[i].bNeedTexCheck ) - ZeroGS::vb[i].FlushTexData(); - - u32 psm = (data[0] >> 20) & 0x3f; - if( psm == 9 ) psm = 1; // hmm..., ffx intro menu - - u32* s_uTex0Data = ZeroGS::vb[i].uCurTex0Data; - - // don't update unless necessary - if( (s_uTex0Data[0]&0x03f00000) == (data[0]&0x03f00000) ) { // psm is the same - - if( PSMT_ISCLUT(psm) ) { - // have to write the CLUT again if changed - if( (s_uTex0Data[1]&0x1fffffe0) == (data[1]&0x1fffffe0) ) { - - if( data[1]&0xe0000000 ) { - tex0.cld = (data[1]>>29)&7; - ZeroGS::texClutWrite(i); - // invalidate to make sure target didn't change! - ZeroGS::vb[i].bVarsTexSync = FALSE; - } - - return; - } - - // CSAs have to be the same! -// if( (data[1]&0xe0000000) == 0 ) { -// -// if( (s_uTex0Data[1]&0x1f100000) != (data[1]&0x1f100000) ) -// ZeroGS::Flush(i); -// -// // clut isn't going to be loaded so can ignore, but at least update CSA and CPSM! -// ZeroGS::vb[i].uCurTex0Data[1] = (ZeroGS::vb[i].uCurTex0Data[1]&0xe087ffff)|(data[1]&0x1f780000); -// -// if( ZeroGS::vb[i].tex0.cpsm <= 1 ) ZeroGS::vb[i].tex0.csa = (data[1] >> 24) & 0xf; -// else ZeroGS::vb[i].tex0.csa = (data[1] >> 24) & 0x1f; -// -// ZeroGS::vb[i].tex0.cpsm = (data[1] >> 19) & 0xe; -// -// ZeroGS::vb[i].bVarsTexSync = FALSE; -// return; -// } - - // fall through - } - else { - //ZeroGS::vb[i].bVarsTexSync = FALSE; - return; - } - } - - ZeroGS::Flush(i); - ZeroGS::vb[i].bVarsTexSync = FALSE; - ZeroGS::vb[i].bTexConstsSync = FALSE; - - s_uTex0Data[0] = (s_uTex0Data[0]&~0x03f00000)|(psm<<20); - s_uTex0Data[1] = (s_uTex0Data[1]&0x1f)|(data[1]&~0x1f); - - tex0.psm = psm; - - if( PSMT_ISCLUT(tex0.psm) ) { - tex0.cbp = (data[1] >> 5) & 0x3fff; - tex0.cpsm = (data[1] >> 19) & 0xe; - tex0.csm = (data[1] >> 23) & 0x1; - - if( tex0.cpsm <= 1 ) tex0.csa = (data[1] >> 24) & 0xf; - else tex0.csa = (data[1] >> 24) & 0x1f; - - tex0.cld = (data[1] >> 29) & 0x7; - ZeroGS::texClutWrite(i); - } -} - -__forceinline void frameWrite(int i, u32 *data) -{ - frameInfo& gsfb = ZeroGS::vb[i].gsfb; - - if( (gsfb.fbp == ((data[0] ) & 0x1ff) * 32) && - (gsfb.fbw == ((data[0] >> 16) & 0x3f) * 64) && - gsfb.psm == ((data[0] >> 24) & 0x3f) && - (gsfb.fbm == data[1]) ) { - return; - } - - ZeroGS::Flush(0); - ZeroGS::Flush(1); - - gsfb.fbp = ((data[0] ) & 0x1ff) * 32; - gsfb.fbw = ((data[0] >> 16) & 0x3f) * 64; - gsfb.psm = (data[0] >> 24) & 0x3f; - gsfb.fbm = data[1]; - - if (gsfb.fbw > 0) { - - gsfb.fbh = (1024*1024-64*gsfb.fbp) / gsfb.fbw; - gsfb.fbh &= ~0x1f; - if( gsfb.psm & 2 ) - gsfb.fbh *= 2; - if( gsfb.fbh > 1024 ) gsfb.fbh = 1024; - } - else gsfb.fbh = 0; - - if( gsfb.psm == 1 ) gsfb.fbm |= 0xff000000; - else if( gsfb.psm & 2 ) { - - } - - ZeroGS::vb[i].bNeedFrameCheck = 1; -} - -__forceinline void testWrite(int i, u32 *data) -{ - pixTest* test = &ZeroGS::vb[i].test; - - if( (*(u32*)test & 0x0007ffff) == (data[0] & 0x0007ffff) ) - return; - - ZeroGS::Flush(i); - *(u32*)test = data[0]; - -// test.ate = (data[0] ) & 0x1; -// test.atst = (data[0] >> 1) & 0x7; -// test.aref = (data[0] >> 4) & 0xff; -// test.afail = (data[0] >> 12) & 0x3; -// test.date = (data[0] >> 14) & 0x1; -// test.datm = (data[0] >> 15) & 0x1; -// test.zte = (data[0] >> 16) & 0x1; -// test.ztst = (data[0] >> 17) & 0x3; -} - -__forceinline void clampWrite(int i, u32 *data) -{ - clampInfo& clamp = ZeroGS::vb[i].clamp; - - if( s_uClampData[i] != data[0] || ((clamp.minv>>8)|(clamp.maxv<<2)) != (data[1]&0x0fff) ) { - -// if( ZeroGS::vb[i].bNeedTexCheck ) -// ZeroGS::vb[i].FlushTexData(); - - ZeroGS::Flush(i); - s_uClampData[i] = data[0]; - - clamp.wms = (data[0] ) & 0x3; - clamp.wmt = (data[0] >> 2) & 0x3; - clamp.minu = (data[0] >> 4) & 0x3ff; - clamp.maxu = (data[0] >> 14) & 0x3ff; - clamp.minv =((data[0] >> 24) & 0xff) | ((data[1] & 0x3) << 8); - clamp.maxv = (data[1] >> 2) & 0x3ff; - - ZeroGS::vb[i].bTexConstsSync = FALSE; - } -} - -void __fastcall GIFRegHandlerNull(u32* data) -{ -#ifdef _DEBUG - if( (((uptr)&data[2])&0xffff) == 0 ) - return; - - // 0x7f happens on a lot of games - if( data[2] != 0x7f && (data[0] || data[1]) ) { - DEBUG_LOG("Unexpected reg handler %x %x %x\n", data[0], data[1], data[2]); - } -#endif -} - -void __fastcall GIFRegHandlerPRIM(u32 *data) { - if (data[0] & ~0x3ff) { - //WARN_LOG("warning: unknown bits in prim %8.8lx_%8.8lx\n", data[1], data[0]); - } - - gs.nTriFanVert = gs.primIndex; - gs.primC = 0; - prim->prim = (data[0]) & 0x7; - gs._prim[0].prim = (data[0]) & 0x7; - gs._prim[1].prim = (data[0]) & 0x7; - gs._prim[1]._val = (data[0]>>3)&0xff; - - ZeroGS::Prim(); -} - -void __fastcall GIFRegHandlerRGBAQ(u32* data) -{ - gs.rgba = data[0]; - gs.vertexregs.rgba = data[0]; - *(u32*)&gs.vertexregs.q = data[1]; -} - -void __fastcall GIFRegHandlerST(u32* data) -{ - *(u32*)&gs.vertexregs.s = data[0]&0xffffff00; - *(u32*)&gs.vertexregs.t = data[1]&0xffffff00; - //*(u32*)&gs.q = data[2]; -} - -void __fastcall GIFRegHandlerUV(u32* data) -{ - gs.vertexregs.u = (data[0]) & 0x3fff; - gs.vertexregs.v = (data[0] >> 16) & 0x3fff; -} - -void __fastcall GIFRegHandlerXYZF2(u32* data) -{ - gs.vertexregs.x = (data[0]) & 0xffff; - gs.vertexregs.y = (data[0] >> (16)) & 0xffff; - gs.vertexregs.z = data[1] & 0xffffff; - gs.vertexregs.f = data[1] >> 24; - gs.gsvertex[gs.primIndex] = gs.vertexregs; - gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); - - KICK_VERTEX2(); -} - -void __fastcall GIFRegHandlerXYZ2(u32* data) -{ - gs.vertexregs.x = (data[0]) & 0xffff; - gs.vertexregs.y = (data[0] >> (16)) & 0xffff; - gs.vertexregs.z = data[1]; - gs.gsvertex[gs.primIndex] = gs.vertexregs; - gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); - - KICK_VERTEX2(); -} - -void __fastcall GIFRegHandlerTEX0_1(u32* data) -{ - if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { - return; - } - tex0Write(0, data); -} - -void __fastcall GIFRegHandlerTEX0_2(u32* data) -{ - if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) { - return; - } - tex0Write(1, data); -} - -void __fastcall GIFRegHandlerCLAMP_1(u32* data) -{ - if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { - return; - } - clampWrite(0, data); -} - -void __fastcall GIFRegHandlerCLAMP_2(u32* data) -{ - if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) { - return; - } - clampWrite(1, data); -} - -void __fastcall GIFRegHandlerFOG(u32* data) -{ - //gs.gsvertex[gs.primIndex].f = (data[1] >> 24); // shift to upper bits - gs.vertexregs.f = data[1]>>24; -} - -void __fastcall GIFRegHandlerXYZF3(u32* data) -{ - gs.vertexregs.x = (data[0]) & 0xffff; - gs.vertexregs.y = (data[0] >> (16)) & 0xffff; - gs.vertexregs.z = data[1] & 0xffffff; - gs.vertexregs.f = data[1] >> 24; - gs.gsvertex[gs.primIndex] = gs.vertexregs; - gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); - - KICK_VERTEX3(); -} - -void __fastcall GIFRegHandlerXYZ3(u32* data) -{ - gs.vertexregs.x = (data[0]) & 0xffff; - gs.vertexregs.y = (data[0] >> (16)) & 0xffff; - gs.vertexregs.z = data[1]; - gs.gsvertex[gs.primIndex] = gs.vertexregs; - gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); - - KICK_VERTEX3(); -} - -void __fastcall GIFRegHandlerNOP(u32* data) -{ -} - -void tex1Write(int i, u32* data) -{ - tex1Info& tex1 = ZeroGS::vb[i].tex1; - - if( conf.bilinear == 1 && (tex1.mmag != ((data[0] >> 5) & 0x1) || tex1.mmin != ((data[0] >> 6) & 0x7)) ) { - ZeroGS::Flush(i); - ZeroGS::vb[i].bVarsTexSync = FALSE; - } - tex1.lcm = (data[0] ) & 0x1; - tex1.mxl = (data[0] >> 2) & 0x7; - tex1.mmag = (data[0] >> 5) & 0x1; - tex1.mmin = (data[0] >> 6) & 0x7; - tex1.mtba = (data[0] >> 9) & 0x1; - tex1.l = (data[0] >> 19) & 0x3; - tex1.k = (data[1] >> 4) & 0xff; -} - -void __fastcall GIFRegHandlerTEX1_1(u32* data) -{ - if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { - return; - } - - tex1Write(0, data); -} - -void __fastcall GIFRegHandlerTEX1_2(u32* data) -{ - if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) - return; - - tex1Write(1, data); -} - -void __fastcall GIFRegHandlerTEX2_1(u32* data) -{ - tex2Write(0, data); -} - -void __fastcall GIFRegHandlerTEX2_2(u32* data) -{ - tex2Write(1, data); -} - -void __fastcall GIFRegHandlerXYOFFSET_1(u32* data) -{ - // eliminator low 4 bits for now - ZeroGS::vb[0].offset.x = (data[0]) & 0xffff; - ZeroGS::vb[0].offset.y = (data[1]) & 0xffff; - -// if( !conf.interlace ) { -// ZeroGS::vb[0].offset.x &= ~15; -// ZeroGS::vb[0].offset.y &= ~15; -// } -} - -void __fastcall GIFRegHandlerXYOFFSET_2(u32* data) -{ - ZeroGS::vb[1].offset.x = (data[0]) & 0xffff; - ZeroGS::vb[1].offset.y = (data[1]) & 0xffff; - -// if( !conf.interlace ) { -// ZeroGS::vb[1].offset.x &= ~15; -// ZeroGS::vb[1].offset.y &= ~15; -// } -} - -void __fastcall GIFRegHandlerPRMODECONT(u32* data) -{ - gs.prac = data[0] & 0x1; - prim = &gs._prim[gs.prac]; - - ZeroGS::Prim(); -} - -void __fastcall GIFRegHandlerPRMODE(u32* data) -{ - gs._prim[0]._val = (data[0]>>3)&0xff; - - if (gs.prac == 0) - ZeroGS::Prim(); -} - -void __fastcall GIFRegHandlerTEXCLUT(u32* data) -{ - if( ZeroGS::vb[0].bNeedTexCheck ) - ZeroGS::vb[0].FlushTexData(); - if( ZeroGS::vb[1].bNeedTexCheck ) - ZeroGS::vb[1].FlushTexData(); - gs.clut.cbw = ((data[0] ) & 0x3f) * 64; - gs.clut.cou = ((data[0] >> 6) & 0x3f) * 16; - gs.clut.cov = (data[0] >> 12) & 0x3ff; -} - -void __fastcall GIFRegHandlerSCANMSK(u32* data) -{ -// ZeroGS::Flush(0); -// ZeroGS::Flush(1); -// ZeroGS::ResolveC(&ZeroGS::vb[0]); -// ZeroGS::ResolveZ(&ZeroGS::vb[0]); - - gs.smask = data[0] & 0x3; -} - -void __fastcall GIFRegHandlerMIPTBP1_1(u32* data) -{ - miptbpInfo& miptbp0 = ZeroGS::vb[0].miptbp0; - miptbp0.tbp[0] = (data[0] ) & 0x3fff; - miptbp0.tbw[0] = (data[0] >> 14) & 0x3f; - miptbp0.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); - miptbp0.tbw[1] = (data[1] >> 2) & 0x3f; - miptbp0.tbp[2] = (data[1] >> 8) & 0x3fff; - miptbp0.tbw[2] = (data[1] >> 22) & 0x3f; -} - -void __fastcall GIFRegHandlerMIPTBP1_2(u32* data) -{ - miptbpInfo& miptbp0 = ZeroGS::vb[1].miptbp0; - miptbp0.tbp[0] = (data[0] ) & 0x3fff; - miptbp0.tbw[0] = (data[0] >> 14) & 0x3f; - miptbp0.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); - miptbp0.tbw[1] = (data[1] >> 2) & 0x3f; - miptbp0.tbp[2] = (data[1] >> 8) & 0x3fff; - miptbp0.tbw[2] = (data[1] >> 22) & 0x3f; -} - -void __fastcall GIFRegHandlerMIPTBP2_1(u32* data) -{ - miptbpInfo& miptbp1 = ZeroGS::vb[0].miptbp1; - miptbp1.tbp[0] = (data[0] ) & 0x3fff; - miptbp1.tbw[0] = (data[0] >> 14) & 0x3f; - miptbp1.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); - miptbp1.tbw[1] = (data[1] >> 2) & 0x3f; - miptbp1.tbp[2] = (data[1] >> 8) & 0x3fff; - miptbp1.tbw[2] = (data[1] >> 22) & 0x3f; -} - -void __fastcall GIFRegHandlerMIPTBP2_2(u32* data) -{ - miptbpInfo& miptbp1 = ZeroGS::vb[1].miptbp1; - miptbp1.tbp[0] = (data[0] ) & 0x3fff; - miptbp1.tbw[0] = (data[0] >> 14) & 0x3f; - miptbp1.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); - miptbp1.tbw[1] = (data[1] >> 2) & 0x3f; - miptbp1.tbp[2] = (data[1] >> 8) & 0x3fff; - miptbp1.tbw[2] = (data[1] >> 22) & 0x3f; -} - -void __fastcall GIFRegHandlerTEXA(u32* data) -{ - texaInfo newinfo; - newinfo.aem = (data[0] >> 15) & 0x1; - newinfo.ta[0] = data[0] & 0xff; - newinfo.ta[1] = data[1] & 0xff; - - if( *(u32*)&newinfo != *(u32*)&gs.texa ) { - ZeroGS::Flush(0); - ZeroGS::Flush(1); - *(u32*)&gs.texa = *(u32*)&newinfo; - gs.texa.fta[0] = newinfo.ta[0]/255.0f; - gs.texa.fta[1] = newinfo.ta[1]/255.0f; - - ZeroGS::vb[0].bTexConstsSync = FALSE; - ZeroGS::vb[1].bTexConstsSync = FALSE; - } -} - -void __fastcall GIFRegHandlerFOGCOL(u32* data) -{ - ZeroGS::SetFogColor(data[0]&0xffffff); -} - -void __fastcall GIFRegHandlerTEXFLUSH(u32* data) -{ - ZeroGS::SetTexFlush(); -} - -void __fastcall GIFRegHandlerSCISSOR_1(u32* data) -{ - Rect2& scissor = ZeroGS::vb[0].scissor; - - Rect2 newscissor; - - newscissor.x0 = ((data[0] ) & 0x7ff) << 3; - newscissor.x1 = ((data[0] >> 16) & 0x7ff) << 3; - newscissor.y0 = ((data[1] ) & 0x7ff) << 3; - newscissor.y1 = ((data[1] >> 16) & 0x7ff) << 3; - - if( newscissor.x1 != scissor.x1 || newscissor.y1 != scissor.y1 || - newscissor.x0 != scissor.x0 || newscissor.y0 != scissor.y0 ) { - - ZeroGS::Flush(0); - scissor = newscissor; - - ZeroGS::vb[0].bNeedFrameCheck = 1; - } -} - -void __fastcall GIFRegHandlerSCISSOR_2(u32* data) -{ - Rect2& scissor = ZeroGS::vb[1].scissor; - - Rect2 newscissor; - - newscissor.x0 = ((data[0] ) & 0x7ff) << 3; - newscissor.x1 = ((data[0] >> 16) & 0x7ff) << 3; - newscissor.y0 = ((data[1] ) & 0x7ff) << 3; - newscissor.y1 = ((data[1] >> 16) & 0x7ff) << 3; - - if( newscissor.x1 != scissor.x1 || newscissor.y1 != scissor.y1 || - newscissor.x0 != scissor.x0 || newscissor.y0 != scissor.y0 ) { - - ZeroGS::Flush(1); - scissor = newscissor; - - // flush everything - ZeroGS::vb[1].bNeedFrameCheck = 1; - } -} - -void __fastcall GIFRegHandlerALPHA_1(u32* data) -{ - alphaInfo newalpha; - newalpha.abcd = *(u8*)data; - newalpha.fix = *(u8*)(data+1); - - if( *(WORD*)&newalpha != *(WORD*)&ZeroGS::vb[0].alpha ) { - ZeroGS::Flush(0); - - if( newalpha.a == 3 ) newalpha.a = 0; - if( newalpha.b == 3 ) newalpha.b = 0; - if( newalpha.c == 3 ) newalpha.c = 0; - if( newalpha.d == 3 ) newalpha.d = 0; - - *(WORD*)&ZeroGS::vb[0].alpha = *(WORD*)&newalpha; - } -} - -void __fastcall GIFRegHandlerALPHA_2(u32* data) -{ - alphaInfo newalpha; - newalpha.abcd = *(u8*)data; - newalpha.fix = *(u8*)(data+1); - - if( *(WORD*)&newalpha != *(WORD*)&ZeroGS::vb[1].alpha ) { - ZeroGS::Flush(1); - - if( newalpha.a == 3 ) newalpha.a = 0; - if( newalpha.b == 3 ) newalpha.b = 0; - if( newalpha.c == 3 ) newalpha.c = 0; - if( newalpha.d == 3 ) newalpha.d = 0; - - *(WORD*)&ZeroGS::vb[1].alpha = *(WORD*)&newalpha; - } -} - -void __fastcall GIFRegHandlerDIMX(u32* data) -{ -} - -void __fastcall GIFRegHandlerDTHE(u32* data) -{ - gs.dthe = data[0] & 0x1; -} - -void __fastcall GIFRegHandlerCOLCLAMP(u32* data) -{ - gs.colclamp = data[0] & 0x1; -} - -void __fastcall GIFRegHandlerTEST_1(u32* data) -{ - testWrite(0, data); -} - -void __fastcall GIFRegHandlerTEST_2(u32* data) -{ - testWrite(1, data); -} - -void __fastcall GIFRegHandlerPABE(u32* data) -{ - //ZeroGS::SetAlphaChanged(0, GPUREG_PABE); - //ZeroGS::SetAlphaChanged(1, GPUREG_PABE); - ZeroGS::Flush(0); - ZeroGS::Flush(1); - - gs.pabe = *data & 0x1; -} - -void __fastcall GIFRegHandlerFBA_1(u32* data) -{ - ZeroGS::Flush(0); - ZeroGS::Flush(1); - ZeroGS::vb[0].fba.fba = *data & 0x1; -} - -void __fastcall GIFRegHandlerFBA_2(u32* data) -{ - ZeroGS::Flush(0); - ZeroGS::Flush(1); - ZeroGS::vb[1].fba.fba = *data & 0x1; -} - -void __fastcall GIFRegHandlerFRAME_1(u32* data) -{ - frameWrite(0, data); -} - -void __fastcall GIFRegHandlerFRAME_2(u32* data) -{ - frameWrite(1, data); -} - -void __fastcall GIFRegHandlerZBUF_1(u32* data) -{ - zbufInfo& zbuf = ZeroGS::vb[0].zbuf; - - int psm = (0x30|((data[0] >> 24) & 0xf)); - if( zbuf.zbp == (data[0] & 0x1ff) * 32 && - zbuf.psm == psm && - zbuf.zmsk == (data[1] & 0x1) ) { - return; - } - - // error detection - if( m_Blocks[psm].bpp == 0 ) - return; - - ZeroGS::Flush(0); - ZeroGS::Flush(1); - - zbuf.zbp = (data[0] & 0x1ff) * 32; - zbuf.psm = 0x30|((data[0] >> 24) & 0xf); - zbuf.zmsk = data[1] & 0x1; - - ZeroGS::vb[0].zprimmask = 0xffffffff; - if( zbuf.psm > 0x31 ) ZeroGS::vb[0].zprimmask = 0xffff; - - ZeroGS::vb[0].bNeedZCheck = 1; -} - -void __fastcall GIFRegHandlerZBUF_2(u32* data) -{ - zbufInfo& zbuf = ZeroGS::vb[1].zbuf; - - int psm = (0x30|((data[0] >> 24) & 0xf)); - if( zbuf.zbp == (data[0] & 0x1ff) * 32 && - zbuf.psm == psm && - zbuf.zmsk == (data[1] & 0x1) ) { - return; - } - - // error detection - if( m_Blocks[psm].bpp == 0 ) - return; - - ZeroGS::Flush(0); - ZeroGS::Flush(1); - - zbuf.zbp = (data[0] & 0x1ff) * 32; - zbuf.psm = 0x30|((data[0] >> 24) & 0xf); - zbuf.zmsk = data[1] & 0x1; - - ZeroGS::vb[1].bNeedZCheck = 1; - - ZeroGS::vb[1].zprimmask = 0xffffffff; - if( zbuf.psm > 0x31 ) ZeroGS::vb[1].zprimmask = 0xffff; -} - -void __fastcall GIFRegHandlerBITBLTBUF(u32* data) -{ - gs.srcbufnew.bp = ((data[0] ) & 0x3fff);// * 64; - gs.srcbufnew.bw = ((data[0] >> 16) & 0x3f) * 64; - gs.srcbufnew.psm = (data[0] >> 24) & 0x3f; - gs.dstbufnew.bp = ((data[1] ) & 0x3fff);// * 64; - gs.dstbufnew.bw = ((data[1] >> 16) & 0x3f) * 64; - gs.dstbufnew.psm = (data[1] >> 24) & 0x3f; - - if (gs.dstbufnew.bw == 0) gs.dstbufnew.bw = 64; -} - -void __fastcall GIFRegHandlerTRXPOS(u32* data) -{ - gs.trxposnew.sx = (data[0] ) & 0x7ff; - gs.trxposnew.sy = (data[0] >> 16) & 0x7ff; - gs.trxposnew.dx = (data[1] ) & 0x7ff; - gs.trxposnew.dy = (data[1] >> 16) & 0x7ff; - gs.trxposnew.dir = (data[1] >> 27) & 0x3; -} - -void __fastcall GIFRegHandlerTRXREG(u32* data) -{ - gs.imageWtemp = data[0]&0xfff; - gs.imageHtemp = data[1]&0xfff; -} - -void __fastcall GIFRegHandlerTRXDIR(u32* data) -{ - // terminate any previous transfers - switch( gs.imageTransfer ) { - case 0: // host->loc - gs.imageTransfer = -1; - break; - case 1: // loc->host - ZeroGS::TerminateLocalHost(); - break; - } - - gs.srcbuf = gs.srcbufnew; - gs.dstbuf = gs.dstbufnew; - gs.trxpos = gs.trxposnew; - gs.imageTransfer = data[0] & 0x3; - gs.imageWnew = gs.imageWtemp; - gs.imageHnew = gs.imageHtemp; - - if( gs.imageWnew > 0 && gs.imageHnew > 0 ) { - switch(gs.imageTransfer) { - case 0: // host->loc - ZeroGS::InitTransferHostLocal(); - break; - - case 1: // loc->host - - ZeroGS::InitTransferLocalHost(); - break; - case 2: - - ZeroGS::TransferLocalLocal(); - break; - - case 3: - gs.imageTransfer = -1; - break; - - default: assert(0); - } - } - else { -#ifndef RELEASE_TO_PUBLIC - //WARN_LOG("ZeroGS: dummy transfer\n"); -#endif - gs.imageTransfer = -1; - } -} - -static u32 oldhw[4]; -void __fastcall GIFRegHandlerHWREG(u32* data) -{ - if( gs.imageTransfer == 0 ) { - ZeroGS::TransferHostLocal(data, 2); - } - else { -#ifndef RELEASE_TO_PUBLIC - ERROR_LOG("ZeroGS: HWREG!? %8.8x_%8.8x\n", data[0], data[1]); - //assert(0); -#endif - } -} - -extern int g_GSMultiThreaded; - -void __fastcall GIFRegHandlerSIGNAL(u32* data) -{ - if(!g_GSMultiThreaded) { - SIGLBLID->SIGID = (SIGLBLID->SIGID&~data[1])|(data[0]&data[1]); - -// if (gs.CSRw & 0x1) CSR->SIGNAL = 1; -// if (!IMR->SIGMSK && GSirq) -// GSirq(); - - if (gs.CSRw & 0x1) { - CSR->SIGNAL = 1; - //gs.CSRw &= ~1; - } - if (!IMR->SIGMSK && GSirq) - GSirq(); - } -} - -void __fastcall GIFRegHandlerFINISH(u32* data) -{ - if(!g_GSMultiThreaded) { - - if (gs.CSRw & 0x2) - CSR->FINISH = 1; - if (!IMR->FINISHMSK && GSirq) - GSirq(); - -// if( gs.CSRw & 2 ) { -// //gs.CSRw &= ~2; -// //CSR->FINISH = 0; -// -// -// } -// CSR->FINISH = 1; -// -// if( !IMR->FINISHMSK && GSirq ) -// GSirq(); - } -} - -void __fastcall GIFRegHandlerLABEL(u32* data) -{ - if(!g_GSMultiThreaded) { - SIGLBLID->LBLID = (SIGLBLID->LBLID&~data[1])|(data[0]&data[1]); - } -} - - -// special execute buffers -//ExecuteBufferXeno g_ebXeno; -// -//ExecuteBufferXeno::ExecuteBufferXeno() -//{ -// clampdata[0] = clampdata[1] = 0; -// tex0data[0] = tex0data[1] = 0; -// tex1data[0] = tex1data[1] = 0; -// bCanExecute = true; -// curprim._val = 0; -//} -// -//void ExecuteBufferXeno::Execute() -//{ -// if( vertices.size() == 0 || !bCanExecute) -// return; -// -// bCanExecute = false; -// ZeroGS::Flush(0); -// ZeroGS::Flush(1); -// -// int oldC = gs.primC; -// int ctx = curprim.ctxt; -// -// Vertex oldverts[3]; -// oldverts[0] = gs.gsvertex[0]; -// oldverts[1] = gs.gsvertex[1]; -// oldverts[2] = gs.gsvertex[2]; -// -// u32 oldtex0[2]; -// tex1Info oldtex1 = ZeroGS::vb[ctx].tex1; -// clampInfo oldclamp = ZeroGS::vb[ctx].clamp; -// oldtex0[0] = ZeroGS::vb[ctx].uNextTex0Data[0]; -// oldtex0[1] = ZeroGS::vb[ctx].uNextTex0Data[1]; -// -// int oldmask = ZeroGS::vb[ctx].zbuf.zmsk; -// ZeroGS::vb[ctx].zbuf.zmsk = 1; -// tex0Write(0, tex0data); -// tex1Write(0, tex1data); -// clampWrite(0, clampdata); -// ZeroGS::vb[ctx].bTexConstsSync = FALSE; -// gs.primC = 3; -// u32 oldprim = prim->_val; -// prim->_val = curprim._val; -// for(int i = 0; i < (int)vertices.size(); i += 3) { -// gs.gsvertex[0] = vertices[i]; -// gs.gsvertex[1] = vertices[i+1]; -// gs.gsvertex[2] = vertices[i+2]; -// (*ZeroGS::drawfn[4])(); // draw a triangle -// } -// vertices.resize(0); -// -// ZeroGS::Flush(ctx); -// -// ZeroGS::vb[ctx].zbuf.zmsk = oldmask; -// gs.primC = oldC; -// gs.gsvertex[0] = oldverts[0]; -// gs.gsvertex[1] = oldverts[1]; -// gs.gsvertex[2] = oldverts[2]; -// ZeroGS::vb[ctx].clamp = oldclamp; -// ZeroGS::vb[ctx].tex1 = oldtex1; -// tex0Write(0, oldtex0); -// ZeroGS::vb[ctx].bTexConstsSync = FALSE; -// prim->_val = oldprim; -// bCanExecute = true; -//} -// -//void ExecuteBufferXeno::SetTex0(u32* data) -//{ -// if( data[0] != tex0data[0] || (data[1]&0x1fffffff) != (tex0data[1]&0x1fffffff) ) -// Execute(); -// -// tex0data[0] = data[0]; -// tex0data[1] = data[1]; -//} -// -//void ExecuteBufferXeno::SetTex1(u32* data) -//{ -// if( data[0] != tex1data[0] ) -// Execute(); -// -// tex1data[0] = data[0]; -// tex1data[1] = data[1]; -//} -// -//void ExecuteBufferXeno::SetClamp(u32* data) -//{ -// if( data[0] != clampdata[0] || (data[1]&0xfff) != clampdata[1] ) -// Execute(); -// -// clampdata[0] = data[0]; -// clampdata[1] = data[1]&0xfff; -//} -// -//void ExecuteBufferXeno::SetTri() -//{ -// if( prim->_val != curprim._val ) -// Execute(); -// curprim._val = prim->_val; -// vertices.push_back(gs.gsvertex[0]); -// vertices.push_back(gs.gsvertex[1]); -// vertices.push_back(gs.gsvertex[2]); -//} +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#if defined(_WIN32) || defined(__WIN32__) +#include +#include +#endif + +#include +#include +#include +#include + +#include "GS.h" +#include "Mem.h" +#include "Regs.h" + +#include "zerogs.h" +#include "targets.h" + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif + +GIFRegHandler g_GIFPackedRegHandlers[16] = { + GIFRegHandlerPRIM, GIFPackedRegHandlerRGBA, GIFPackedRegHandlerSTQ, GIFPackedRegHandlerUV, + GIFPackedRegHandlerXYZF2, GIFPackedRegHandlerXYZ2, GIFRegHandlerTEX0_1, GIFRegHandlerTEX0_2, + GIFRegHandlerCLAMP_1, GIFRegHandlerCLAMP_2, GIFPackedRegHandlerFOG, GIFPackedRegHandlerNull, + GIFRegHandlerXYZF3, GIFRegHandlerXYZ3, GIFPackedRegHandlerA_D, GIFPackedRegHandlerNOP }; + +GIFRegHandler g_GIFRegHandlers[] = { + GIFRegHandlerPRIM, GIFRegHandlerRGBAQ, GIFRegHandlerST, GIFRegHandlerUV, + GIFRegHandlerXYZF2, GIFRegHandlerXYZ2, GIFRegHandlerTEX0_1, GIFRegHandlerTEX0_2, + GIFRegHandlerCLAMP_1, GIFRegHandlerCLAMP_2, GIFRegHandlerFOG, GIFRegHandlerNull, + GIFRegHandlerXYZF3, GIFRegHandlerXYZ3, GIFRegHandlerNOP, GIFRegHandlerNOP, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerTEX1_1, GIFRegHandlerTEX1_2, GIFRegHandlerTEX2_1, GIFRegHandlerTEX2_2, + GIFRegHandlerXYOFFSET_1,GIFRegHandlerXYOFFSET_2,GIFRegHandlerPRMODECONT,GIFRegHandlerPRMODE, + GIFRegHandlerTEXCLUT, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerSCANMSK, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerMIPTBP1_1, GIFRegHandlerMIPTBP1_2, GIFRegHandlerMIPTBP2_1, GIFRegHandlerMIPTBP2_2, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerTEXA, + GIFRegHandlerNull, GIFRegHandlerFOGCOL, GIFRegHandlerNull, GIFRegHandlerTEXFLUSH, + GIFRegHandlerSCISSOR_1, GIFRegHandlerSCISSOR_2, GIFRegHandlerALPHA_1, GIFRegHandlerALPHA_2, + GIFRegHandlerDIMX, GIFRegHandlerDTHE, GIFRegHandlerCOLCLAMP, GIFRegHandlerTEST_1, + GIFRegHandlerTEST_2, GIFRegHandlerPABE, GIFRegHandlerFBA_1, GIFRegHandlerFBA_2, + GIFRegHandlerFRAME_1, GIFRegHandlerFRAME_2, GIFRegHandlerZBUF_1, GIFRegHandlerZBUF_2, + GIFRegHandlerBITBLTBUF, GIFRegHandlerTRXPOS, GIFRegHandlerTRXREG, GIFRegHandlerTRXDIR, + GIFRegHandlerHWREG, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerSIGNAL, GIFRegHandlerFINISH, GIFRegHandlerLABEL, GIFRegHandlerNull }; + +C_ASSERT(sizeof(g_GIFRegHandlers)/sizeof(g_GIFRegHandlers[0]) == 100 ); + +// values for keeping track of changes +u32 s_uTex1Data[2][2] = {0}, s_uClampData[2] = {0}; + +void __fastcall GIFPackedRegHandlerNull(u32* data) +{ +#ifdef _DEBUG + DEBUG_LOG("Unexpected packed reg handler %8.8lx_%8.8lx %x\n", data[0], data[1], data[2]); +#endif +} + +void __fastcall GIFPackedRegHandlerRGBA(u32* data) +{ + gs.rgba = (data[0] & 0xff) | + ((data[1] & 0xff) << 8) | + ((data[2] & 0xff) << 16) | + ((data[3] & 0xff) << 24); + gs.vertexregs.rgba = gs.rgba; + gs.vertexregs.q = gs.q; +} + +void __fastcall GIFPackedRegHandlerSTQ(u32* data) +{ + *(u32*)&gs.vertexregs.s = data[0]&0xffffff00; + *(u32*)&gs.vertexregs.t = data[1]&0xffffff00; + *(u32*)&gs.q = data[2]; +} + +void __fastcall GIFPackedRegHandlerUV(u32* data) +{ + gs.vertexregs.u = data[0] & 0x3fff; + gs.vertexregs.v = data[1] & 0x3fff; +} + +void __forceinline KICK_VERTEX2() +{ + if (++gs.primC >= (int)g_primmult[prim->prim]) + { + if (!(g_GameSettings&GAME_XENOSPECHACK) || !ZeroGS::vb[prim->ctxt].zbuf.zmsk) + (*ZeroGS::drawfn[prim->prim])(); + gs.primC -= g_primsub[prim->prim]; + } +} + +void __forceinline KICK_VERTEX3() +{ + if (++gs.primC >= (int)g_primmult[prim->prim]) + { + gs.primC -= g_primsub[prim->prim]; + if (prim->prim == 5) + { + /* tri fans need special processing */ + if (gs.nTriFanVert == gs.primIndex) + gs.primIndex = (gs.primIndex+1) % ARRAYSIZE(gs.gsvertex); + } + } +} + +void __fastcall GIFPackedRegHandlerXYZF2(u32* data) +{ + gs.vertexregs.x = (data[0] >> 0) & 0xffff; + gs.vertexregs.y = (data[1] >> 0) & 0xffff; + gs.vertexregs.z = (data[2] >> 4) & 0xffffff; + gs.vertexregs.f = (data[3] >> 4) & 0xff; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1) % ARRAYSIZE(gs.gsvertex); + + if( data[3] & 0x8000 ) { + KICK_VERTEX3(); + } + else { + KICK_VERTEX2(); + } +} + +void __fastcall GIFPackedRegHandlerXYZ2(u32* data) +{ + gs.vertexregs.x = (data[0] >> 0) & 0xffff; + gs.vertexregs.y = (data[1] >> 0) & 0xffff; + gs.vertexregs.z = data[2]; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1) % ARRAYSIZE(gs.gsvertex); + + if( data[3] & 0x8000 ) { + KICK_VERTEX3(); + } + else { + KICK_VERTEX2(); + } +} + +void __fastcall GIFPackedRegHandlerFOG(u32* data) +{ + gs.vertexregs.f = (data[3]&0xff0)>>4; +} + +void __fastcall GIFPackedRegHandlerA_D(u32* data) +{ + if((data[2] & 0xff) < 100) + g_GIFRegHandlers[data[2] & 0xff](data); + else + GIFRegHandlerNull(data); +} + +void __fastcall GIFPackedRegHandlerNOP(u32* data) +{ +} + +extern int g_PrevBitwiseTexX, g_PrevBitwiseTexY; + +void tex0Write(int i, u32 *data) +{ + u32 psm = (data[0] >> 20) & 0x3f; + if( psm == 9 ) psm = 1; // hmm..., ffx intro menu + + if( m_Blocks[psm].bpp == 0 ) { + // kh and others + return; + } + + ZeroGS::vb[i].uNextTex0Data[0] = data[0]; + ZeroGS::vb[i].uNextTex0Data[1] = data[1]; + ZeroGS::vb[i].bNeedTexCheck = 1; + + // don't update unless necessary + if( PSMT_ISCLUT(psm) ) { + if( ZeroGS::CheckChangeInClut(data[1], psm) ) { + // loading clut, so flush whole texture + ZeroGS::vb[i].FlushTexData(); + } + // check if csa is the same!! (ffx bisaid island, grass) + else if( (data[1]&0x1f780000) != (ZeroGS::vb[i].uCurTex0Data[1]&0x1f780000) ) { + ZeroGS::Flush(i); // flush any previous entries + } + } +} + +void tex2Write(int i, u32 *data) +{ + tex0Info& tex0 = ZeroGS::vb[i].tex0; + + if( ZeroGS::vb[i].bNeedTexCheck ) + ZeroGS::vb[i].FlushTexData(); + + u32 psm = (data[0] >> 20) & 0x3f; + if( psm == 9 ) psm = 1; // hmm..., ffx intro menu + + u32* s_uTex0Data = ZeroGS::vb[i].uCurTex0Data; + + // don't update unless necessary + if( (s_uTex0Data[0]&0x03f00000) == (data[0]&0x03f00000) ) { // psm is the same + + if( PSMT_ISCLUT(psm) ) { + // have to write the CLUT again if changed + if( (s_uTex0Data[1]&0x1fffffe0) == (data[1]&0x1fffffe0) ) { + + if( data[1]&0xe0000000 ) { + tex0.cld = (data[1]>>29)&7; + ZeroGS::texClutWrite(i); + // invalidate to make sure target didn't change! + ZeroGS::vb[i].bVarsTexSync = FALSE; + } + + return; + } + + // CSAs have to be the same! +// if( (data[1]&0xe0000000) == 0 ) { +// +// if( (s_uTex0Data[1]&0x1f100000) != (data[1]&0x1f100000) ) +// ZeroGS::Flush(i); +// +// // clut isn't going to be loaded so can ignore, but at least update CSA and CPSM! +// ZeroGS::vb[i].uCurTex0Data[1] = (ZeroGS::vb[i].uCurTex0Data[1]&0xe087ffff)|(data[1]&0x1f780000); +// +// if( ZeroGS::vb[i].tex0.cpsm <= 1 ) ZeroGS::vb[i].tex0.csa = (data[1] >> 24) & 0xf; +// else ZeroGS::vb[i].tex0.csa = (data[1] >> 24) & 0x1f; +// +// ZeroGS::vb[i].tex0.cpsm = (data[1] >> 19) & 0xe; +// +// ZeroGS::vb[i].bVarsTexSync = FALSE; +// return; +// } + + // fall through + } + else { + //ZeroGS::vb[i].bVarsTexSync = FALSE; + return; + } + } + + ZeroGS::Flush(i); + ZeroGS::vb[i].bVarsTexSync = FALSE; + ZeroGS::vb[i].bTexConstsSync = FALSE; + + s_uTex0Data[0] = (s_uTex0Data[0]&~0x03f00000)|(psm<<20); + s_uTex0Data[1] = (s_uTex0Data[1]&0x1f)|(data[1]&~0x1f); + + tex0.psm = psm; + + if( PSMT_ISCLUT(tex0.psm) ) { + tex0.cbp = (data[1] >> 5) & 0x3fff; + tex0.cpsm = (data[1] >> 19) & 0xe; + tex0.csm = (data[1] >> 23) & 0x1; + + if( tex0.cpsm <= 1 ) tex0.csa = (data[1] >> 24) & 0xf; + else tex0.csa = (data[1] >> 24) & 0x1f; + + tex0.cld = (data[1] >> 29) & 0x7; + ZeroGS::texClutWrite(i); + } +} + +__forceinline void frameWrite(int i, u32 *data) +{ + frameInfo& gsfb = ZeroGS::vb[i].gsfb; + + if( (gsfb.fbp == ((data[0] ) & 0x1ff) * 32) && + (gsfb.fbw == ((data[0] >> 16) & 0x3f) * 64) && + gsfb.psm == ((data[0] >> 24) & 0x3f) && + (gsfb.fbm == data[1]) ) { + return; + } + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + gsfb.fbp = ((data[0] ) & 0x1ff) * 32; + gsfb.fbw = ((data[0] >> 16) & 0x3f) * 64; + gsfb.psm = (data[0] >> 24) & 0x3f; + gsfb.fbm = data[1]; + + if (gsfb.fbw > 0) { + + gsfb.fbh = (1024*1024-64*gsfb.fbp) / gsfb.fbw; + gsfb.fbh &= ~0x1f; + if( gsfb.psm & 2 ) + gsfb.fbh *= 2; + if( gsfb.fbh > 1024 ) gsfb.fbh = 1024; + } + else gsfb.fbh = 0; + + if( gsfb.psm == 1 ) gsfb.fbm |= 0xff000000; + else if( gsfb.psm & 2 ) { + + } + + ZeroGS::vb[i].bNeedFrameCheck = 1; +} + +__forceinline void testWrite(int i, u32 *data) +{ + pixTest* test = &ZeroGS::vb[i].test; + + if( (*(u32*)test & 0x0007ffff) == (data[0] & 0x0007ffff) ) + return; + + ZeroGS::Flush(i); + *(u32*)test = data[0]; + +// test.ate = (data[0] ) & 0x1; +// test.atst = (data[0] >> 1) & 0x7; +// test.aref = (data[0] >> 4) & 0xff; +// test.afail = (data[0] >> 12) & 0x3; +// test.date = (data[0] >> 14) & 0x1; +// test.datm = (data[0] >> 15) & 0x1; +// test.zte = (data[0] >> 16) & 0x1; +// test.ztst = (data[0] >> 17) & 0x3; +} + +__forceinline void clampWrite(int i, u32 *data) +{ + clampInfo& clamp = ZeroGS::vb[i].clamp; + + if( s_uClampData[i] != data[0] || ((clamp.minv>>8)|(clamp.maxv<<2)) != (data[1]&0x0fff) ) { + +// if( ZeroGS::vb[i].bNeedTexCheck ) +// ZeroGS::vb[i].FlushTexData(); + + ZeroGS::Flush(i); + s_uClampData[i] = data[0]; + + clamp.wms = (data[0] ) & 0x3; + clamp.wmt = (data[0] >> 2) & 0x3; + clamp.minu = (data[0] >> 4) & 0x3ff; + clamp.maxu = (data[0] >> 14) & 0x3ff; + clamp.minv =((data[0] >> 24) & 0xff) | ((data[1] & 0x3) << 8); + clamp.maxv = (data[1] >> 2) & 0x3ff; + + ZeroGS::vb[i].bTexConstsSync = FALSE; + } +} + +void __fastcall GIFRegHandlerNull(u32* data) +{ +#ifdef _DEBUG + if( (((uptr)&data[2])&0xffff) == 0 ) + return; + + // 0x7f happens on a lot of games + if( data[2] != 0x7f && (data[0] || data[1]) ) { + DEBUG_LOG("Unexpected reg handler %x %x %x\n", data[0], data[1], data[2]); + } +#endif +} + +void __fastcall GIFRegHandlerPRIM(u32 *data) { + if (data[0] & ~0x3ff) { + //WARN_LOG("warning: unknown bits in prim %8.8lx_%8.8lx\n", data[1], data[0]); + } + + gs.nTriFanVert = gs.primIndex; + gs.primC = 0; + prim->prim = (data[0]) & 0x7; + gs._prim[0].prim = (data[0]) & 0x7; + gs._prim[1].prim = (data[0]) & 0x7; + gs._prim[1]._val = (data[0]>>3)&0xff; + + ZeroGS::Prim(); +} + +void __fastcall GIFRegHandlerRGBAQ(u32* data) +{ + gs.rgba = data[0]; + gs.vertexregs.rgba = data[0]; + *(u32*)&gs.vertexregs.q = data[1]; +} + +void __fastcall GIFRegHandlerST(u32* data) +{ + *(u32*)&gs.vertexregs.s = data[0]&0xffffff00; + *(u32*)&gs.vertexregs.t = data[1]&0xffffff00; + //*(u32*)&gs.q = data[2]; +} + +void __fastcall GIFRegHandlerUV(u32* data) +{ + gs.vertexregs.u = (data[0]) & 0x3fff; + gs.vertexregs.v = (data[0] >> 16) & 0x3fff; +} + +void __fastcall GIFRegHandlerXYZF2(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1] & 0xffffff; + gs.vertexregs.f = data[1] >> 24; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + + KICK_VERTEX2(); +} + +void __fastcall GIFRegHandlerXYZ2(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1]; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + + KICK_VERTEX2(); +} + +void __fastcall GIFRegHandlerTEX0_1(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { + return; + } + tex0Write(0, data); +} + +void __fastcall GIFRegHandlerTEX0_2(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) { + return; + } + tex0Write(1, data); +} + +void __fastcall GIFRegHandlerCLAMP_1(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { + return; + } + clampWrite(0, data); +} + +void __fastcall GIFRegHandlerCLAMP_2(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) { + return; + } + clampWrite(1, data); +} + +void __fastcall GIFRegHandlerFOG(u32* data) +{ + //gs.gsvertex[gs.primIndex].f = (data[1] >> 24); // shift to upper bits + gs.vertexregs.f = data[1]>>24; +} + +void __fastcall GIFRegHandlerXYZF3(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1] & 0xffffff; + gs.vertexregs.f = data[1] >> 24; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + + KICK_VERTEX3(); +} + +void __fastcall GIFRegHandlerXYZ3(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1]; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + + KICK_VERTEX3(); +} + +void __fastcall GIFRegHandlerNOP(u32* data) +{ +} + +void tex1Write(int i, u32* data) +{ + tex1Info& tex1 = ZeroGS::vb[i].tex1; + + if( conf.bilinear == 1 && (tex1.mmag != ((data[0] >> 5) & 0x1) || tex1.mmin != ((data[0] >> 6) & 0x7)) ) { + ZeroGS::Flush(i); + ZeroGS::vb[i].bVarsTexSync = FALSE; + } + tex1.lcm = (data[0] ) & 0x1; + tex1.mxl = (data[0] >> 2) & 0x7; + tex1.mmag = (data[0] >> 5) & 0x1; + tex1.mmin = (data[0] >> 6) & 0x7; + tex1.mtba = (data[0] >> 9) & 0x1; + tex1.l = (data[0] >> 19) & 0x3; + tex1.k = (data[1] >> 4) & 0xff; +} + +void __fastcall GIFRegHandlerTEX1_1(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { + return; + } + + tex1Write(0, data); +} + +void __fastcall GIFRegHandlerTEX1_2(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) + return; + + tex1Write(1, data); +} + +void __fastcall GIFRegHandlerTEX2_1(u32* data) +{ + tex2Write(0, data); +} + +void __fastcall GIFRegHandlerTEX2_2(u32* data) +{ + tex2Write(1, data); +} + +void __fastcall GIFRegHandlerXYOFFSET_1(u32* data) +{ + // eliminator low 4 bits for now + ZeroGS::vb[0].offset.x = (data[0]) & 0xffff; + ZeroGS::vb[0].offset.y = (data[1]) & 0xffff; + +// if( !conf.interlace ) { +// ZeroGS::vb[0].offset.x &= ~15; +// ZeroGS::vb[0].offset.y &= ~15; +// } +} + +void __fastcall GIFRegHandlerXYOFFSET_2(u32* data) +{ + ZeroGS::vb[1].offset.x = (data[0]) & 0xffff; + ZeroGS::vb[1].offset.y = (data[1]) & 0xffff; + +// if( !conf.interlace ) { +// ZeroGS::vb[1].offset.x &= ~15; +// ZeroGS::vb[1].offset.y &= ~15; +// } +} + +void __fastcall GIFRegHandlerPRMODECONT(u32* data) +{ + gs.prac = data[0] & 0x1; + prim = &gs._prim[gs.prac]; + + ZeroGS::Prim(); +} + +void __fastcall GIFRegHandlerPRMODE(u32* data) +{ + gs._prim[0]._val = (data[0]>>3)&0xff; + + if (gs.prac == 0) + ZeroGS::Prim(); +} + +void __fastcall GIFRegHandlerTEXCLUT(u32* data) +{ + if( ZeroGS::vb[0].bNeedTexCheck ) + ZeroGS::vb[0].FlushTexData(); + if( ZeroGS::vb[1].bNeedTexCheck ) + ZeroGS::vb[1].FlushTexData(); + gs.clut.cbw = ((data[0] ) & 0x3f) * 64; + gs.clut.cou = ((data[0] >> 6) & 0x3f) * 16; + gs.clut.cov = (data[0] >> 12) & 0x3ff; +} + +void __fastcall GIFRegHandlerSCANMSK(u32* data) +{ +// ZeroGS::Flush(0); +// ZeroGS::Flush(1); +// ZeroGS::ResolveC(&ZeroGS::vb[0]); +// ZeroGS::ResolveZ(&ZeroGS::vb[0]); + + gs.smask = data[0] & 0x3; +} + +void __fastcall GIFRegHandlerMIPTBP1_1(u32* data) +{ + miptbpInfo& miptbp0 = ZeroGS::vb[0].miptbp0; + miptbp0.tbp[0] = (data[0] ) & 0x3fff; + miptbp0.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp0.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp0.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp0.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp0.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerMIPTBP1_2(u32* data) +{ + miptbpInfo& miptbp0 = ZeroGS::vb[1].miptbp0; + miptbp0.tbp[0] = (data[0] ) & 0x3fff; + miptbp0.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp0.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp0.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp0.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp0.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerMIPTBP2_1(u32* data) +{ + miptbpInfo& miptbp1 = ZeroGS::vb[0].miptbp1; + miptbp1.tbp[0] = (data[0] ) & 0x3fff; + miptbp1.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp1.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp1.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp1.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp1.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerMIPTBP2_2(u32* data) +{ + miptbpInfo& miptbp1 = ZeroGS::vb[1].miptbp1; + miptbp1.tbp[0] = (data[0] ) & 0x3fff; + miptbp1.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp1.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp1.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp1.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp1.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerTEXA(u32* data) +{ + texaInfo newinfo; + newinfo.aem = (data[0] >> 15) & 0x1; + newinfo.ta[0] = data[0] & 0xff; + newinfo.ta[1] = data[1] & 0xff; + + if( *(u32*)&newinfo != *(u32*)&gs.texa ) { + ZeroGS::Flush(0); + ZeroGS::Flush(1); + *(u32*)&gs.texa = *(u32*)&newinfo; + gs.texa.fta[0] = newinfo.ta[0]/255.0f; + gs.texa.fta[1] = newinfo.ta[1]/255.0f; + + ZeroGS::vb[0].bTexConstsSync = FALSE; + ZeroGS::vb[1].bTexConstsSync = FALSE; + } +} + +void __fastcall GIFRegHandlerFOGCOL(u32* data) +{ + ZeroGS::SetFogColor(data[0]&0xffffff); +} + +void __fastcall GIFRegHandlerTEXFLUSH(u32* data) +{ + ZeroGS::SetTexFlush(); +} + +void __fastcall GIFRegHandlerSCISSOR_1(u32* data) +{ + Rect2& scissor = ZeroGS::vb[0].scissor; + + Rect2 newscissor; + + newscissor.x0 = ((data[0] ) & 0x7ff) << 3; + newscissor.x1 = ((data[0] >> 16) & 0x7ff) << 3; + newscissor.y0 = ((data[1] ) & 0x7ff) << 3; + newscissor.y1 = ((data[1] >> 16) & 0x7ff) << 3; + + if( newscissor.x1 != scissor.x1 || newscissor.y1 != scissor.y1 || + newscissor.x0 != scissor.x0 || newscissor.y0 != scissor.y0 ) { + + ZeroGS::Flush(0); + scissor = newscissor; + + ZeroGS::vb[0].bNeedFrameCheck = 1; + } +} + +void __fastcall GIFRegHandlerSCISSOR_2(u32* data) +{ + Rect2& scissor = ZeroGS::vb[1].scissor; + + Rect2 newscissor; + + newscissor.x0 = ((data[0] ) & 0x7ff) << 3; + newscissor.x1 = ((data[0] >> 16) & 0x7ff) << 3; + newscissor.y0 = ((data[1] ) & 0x7ff) << 3; + newscissor.y1 = ((data[1] >> 16) & 0x7ff) << 3; + + if( newscissor.x1 != scissor.x1 || newscissor.y1 != scissor.y1 || + newscissor.x0 != scissor.x0 || newscissor.y0 != scissor.y0 ) { + + ZeroGS::Flush(1); + scissor = newscissor; + + // flush everything + ZeroGS::vb[1].bNeedFrameCheck = 1; + } +} + +void __fastcall GIFRegHandlerALPHA_1(u32* data) +{ + alphaInfo newalpha; + newalpha.abcd = *(u8*)data; + newalpha.fix = *(u8*)(data+1); + + if( *(WORD*)&newalpha != *(WORD*)&ZeroGS::vb[0].alpha ) { + ZeroGS::Flush(0); + + if( newalpha.a == 3 ) newalpha.a = 0; + if( newalpha.b == 3 ) newalpha.b = 0; + if( newalpha.c == 3 ) newalpha.c = 0; + if( newalpha.d == 3 ) newalpha.d = 0; + + *(WORD*)&ZeroGS::vb[0].alpha = *(WORD*)&newalpha; + } +} + +void __fastcall GIFRegHandlerALPHA_2(u32* data) +{ + alphaInfo newalpha; + newalpha.abcd = *(u8*)data; + newalpha.fix = *(u8*)(data+1); + + if( *(WORD*)&newalpha != *(WORD*)&ZeroGS::vb[1].alpha ) { + ZeroGS::Flush(1); + + if( newalpha.a == 3 ) newalpha.a = 0; + if( newalpha.b == 3 ) newalpha.b = 0; + if( newalpha.c == 3 ) newalpha.c = 0; + if( newalpha.d == 3 ) newalpha.d = 0; + + *(WORD*)&ZeroGS::vb[1].alpha = *(WORD*)&newalpha; + } +} + +void __fastcall GIFRegHandlerDIMX(u32* data) +{ +} + +void __fastcall GIFRegHandlerDTHE(u32* data) +{ + gs.dthe = data[0] & 0x1; +} + +void __fastcall GIFRegHandlerCOLCLAMP(u32* data) +{ + gs.colclamp = data[0] & 0x1; +} + +void __fastcall GIFRegHandlerTEST_1(u32* data) +{ + testWrite(0, data); +} + +void __fastcall GIFRegHandlerTEST_2(u32* data) +{ + testWrite(1, data); +} + +void __fastcall GIFRegHandlerPABE(u32* data) +{ + //ZeroGS::SetAlphaChanged(0, GPUREG_PABE); + //ZeroGS::SetAlphaChanged(1, GPUREG_PABE); + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + gs.pabe = *data & 0x1; +} + +void __fastcall GIFRegHandlerFBA_1(u32* data) +{ + ZeroGS::Flush(0); + ZeroGS::Flush(1); + ZeroGS::vb[0].fba.fba = *data & 0x1; +} + +void __fastcall GIFRegHandlerFBA_2(u32* data) +{ + ZeroGS::Flush(0); + ZeroGS::Flush(1); + ZeroGS::vb[1].fba.fba = *data & 0x1; +} + +void __fastcall GIFRegHandlerFRAME_1(u32* data) +{ + frameWrite(0, data); +} + +void __fastcall GIFRegHandlerFRAME_2(u32* data) +{ + frameWrite(1, data); +} + +void __fastcall GIFRegHandlerZBUF_1(u32* data) +{ + zbufInfo& zbuf = ZeroGS::vb[0].zbuf; + + int psm = (0x30|((data[0] >> 24) & 0xf)); + if( zbuf.zbp == (data[0] & 0x1ff) * 32 && + zbuf.psm == psm && + zbuf.zmsk == (data[1] & 0x1) ) { + return; + } + + // error detection + if( m_Blocks[psm].bpp == 0 ) + return; + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + zbuf.zbp = (data[0] & 0x1ff) * 32; + zbuf.psm = 0x30|((data[0] >> 24) & 0xf); + zbuf.zmsk = data[1] & 0x1; + + ZeroGS::vb[0].zprimmask = 0xffffffff; + if( zbuf.psm > 0x31 ) ZeroGS::vb[0].zprimmask = 0xffff; + + ZeroGS::vb[0].bNeedZCheck = 1; +} + +void __fastcall GIFRegHandlerZBUF_2(u32* data) +{ + zbufInfo& zbuf = ZeroGS::vb[1].zbuf; + + int psm = (0x30|((data[0] >> 24) & 0xf)); + if( zbuf.zbp == (data[0] & 0x1ff) * 32 && + zbuf.psm == psm && + zbuf.zmsk == (data[1] & 0x1) ) { + return; + } + + // error detection + if( m_Blocks[psm].bpp == 0 ) + return; + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + zbuf.zbp = (data[0] & 0x1ff) * 32; + zbuf.psm = 0x30|((data[0] >> 24) & 0xf); + zbuf.zmsk = data[1] & 0x1; + + ZeroGS::vb[1].bNeedZCheck = 1; + + ZeroGS::vb[1].zprimmask = 0xffffffff; + if( zbuf.psm > 0x31 ) ZeroGS::vb[1].zprimmask = 0xffff; +} + +void __fastcall GIFRegHandlerBITBLTBUF(u32* data) +{ + gs.srcbufnew.bp = ((data[0] ) & 0x3fff);// * 64; + gs.srcbufnew.bw = ((data[0] >> 16) & 0x3f) * 64; + gs.srcbufnew.psm = (data[0] >> 24) & 0x3f; + gs.dstbufnew.bp = ((data[1] ) & 0x3fff);// * 64; + gs.dstbufnew.bw = ((data[1] >> 16) & 0x3f) * 64; + gs.dstbufnew.psm = (data[1] >> 24) & 0x3f; + + if (gs.dstbufnew.bw == 0) gs.dstbufnew.bw = 64; +} + +void __fastcall GIFRegHandlerTRXPOS(u32* data) +{ + gs.trxposnew.sx = (data[0] ) & 0x7ff; + gs.trxposnew.sy = (data[0] >> 16) & 0x7ff; + gs.trxposnew.dx = (data[1] ) & 0x7ff; + gs.trxposnew.dy = (data[1] >> 16) & 0x7ff; + gs.trxposnew.dir = (data[1] >> 27) & 0x3; +} + +void __fastcall GIFRegHandlerTRXREG(u32* data) +{ + gs.imageWtemp = data[0]&0xfff; + gs.imageHtemp = data[1]&0xfff; +} + +void __fastcall GIFRegHandlerTRXDIR(u32* data) +{ + // terminate any previous transfers + switch( gs.imageTransfer ) { + case 0: // host->loc + gs.imageTransfer = -1; + break; + case 1: // loc->host + ZeroGS::TerminateLocalHost(); + break; + } + + gs.srcbuf = gs.srcbufnew; + gs.dstbuf = gs.dstbufnew; + gs.trxpos = gs.trxposnew; + gs.imageTransfer = data[0] & 0x3; + gs.imageWnew = gs.imageWtemp; + gs.imageHnew = gs.imageHtemp; + + if( gs.imageWnew > 0 && gs.imageHnew > 0 ) { + switch(gs.imageTransfer) { + case 0: // host->loc + ZeroGS::InitTransferHostLocal(); + break; + + case 1: // loc->host + + ZeroGS::InitTransferLocalHost(); + break; + case 2: + + ZeroGS::TransferLocalLocal(); + break; + + case 3: + gs.imageTransfer = -1; + break; + + default: assert(0); + } + } + else { +#ifndef RELEASE_TO_PUBLIC + //WARN_LOG("ZeroGS: dummy transfer\n"); +#endif + gs.imageTransfer = -1; + } +} + +static u32 oldhw[4]; +void __fastcall GIFRegHandlerHWREG(u32* data) +{ + if( gs.imageTransfer == 0 ) { + ZeroGS::TransferHostLocal(data, 2); + } + else { +#ifndef RELEASE_TO_PUBLIC + ERROR_LOG("ZeroGS: HWREG!? %8.8x_%8.8x\n", data[0], data[1]); + //assert(0); +#endif + } +} + +extern int g_GSMultiThreaded; + +void __fastcall GIFRegHandlerSIGNAL(u32* data) +{ + if(!g_GSMultiThreaded) { + SIGLBLID->SIGID = (SIGLBLID->SIGID&~data[1])|(data[0]&data[1]); + +// if (gs.CSRw & 0x1) CSR->SIGNAL = 1; +// if (!IMR->SIGMSK && GSirq) +// GSirq(); + + if (gs.CSRw & 0x1) { + CSR->SIGNAL = 1; + //gs.CSRw &= ~1; + } + if (!IMR->SIGMSK && GSirq) + GSirq(); + } +} + +void __fastcall GIFRegHandlerFINISH(u32* data) +{ + if(!g_GSMultiThreaded) { + + if (gs.CSRw & 0x2) + CSR->FINISH = 1; + if (!IMR->FINISHMSK && GSirq) + GSirq(); + +// if( gs.CSRw & 2 ) { +// //gs.CSRw &= ~2; +// //CSR->FINISH = 0; +// +// +// } +// CSR->FINISH = 1; +// +// if( !IMR->FINISHMSK && GSirq ) +// GSirq(); + } +} + +void __fastcall GIFRegHandlerLABEL(u32* data) +{ + if(!g_GSMultiThreaded) { + SIGLBLID->LBLID = (SIGLBLID->LBLID&~data[1])|(data[0]&data[1]); + } +} + + +// special execute buffers +//ExecuteBufferXeno g_ebXeno; +// +//ExecuteBufferXeno::ExecuteBufferXeno() +//{ +// clampdata[0] = clampdata[1] = 0; +// tex0data[0] = tex0data[1] = 0; +// tex1data[0] = tex1data[1] = 0; +// bCanExecute = true; +// curprim._val = 0; +//} +// +//void ExecuteBufferXeno::Execute() +//{ +// if( vertices.size() == 0 || !bCanExecute) +// return; +// +// bCanExecute = false; +// ZeroGS::Flush(0); +// ZeroGS::Flush(1); +// +// int oldC = gs.primC; +// int ctx = curprim.ctxt; +// +// Vertex oldverts[3]; +// oldverts[0] = gs.gsvertex[0]; +// oldverts[1] = gs.gsvertex[1]; +// oldverts[2] = gs.gsvertex[2]; +// +// u32 oldtex0[2]; +// tex1Info oldtex1 = ZeroGS::vb[ctx].tex1; +// clampInfo oldclamp = ZeroGS::vb[ctx].clamp; +// oldtex0[0] = ZeroGS::vb[ctx].uNextTex0Data[0]; +// oldtex0[1] = ZeroGS::vb[ctx].uNextTex0Data[1]; +// +// int oldmask = ZeroGS::vb[ctx].zbuf.zmsk; +// ZeroGS::vb[ctx].zbuf.zmsk = 1; +// tex0Write(0, tex0data); +// tex1Write(0, tex1data); +// clampWrite(0, clampdata); +// ZeroGS::vb[ctx].bTexConstsSync = FALSE; +// gs.primC = 3; +// u32 oldprim = prim->_val; +// prim->_val = curprim._val; +// for(int i = 0; i < (int)vertices.size(); i += 3) { +// gs.gsvertex[0] = vertices[i]; +// gs.gsvertex[1] = vertices[i+1]; +// gs.gsvertex[2] = vertices[i+2]; +// (*ZeroGS::drawfn[4])(); // draw a triangle +// } +// vertices.resize(0); +// +// ZeroGS::Flush(ctx); +// +// ZeroGS::vb[ctx].zbuf.zmsk = oldmask; +// gs.primC = oldC; +// gs.gsvertex[0] = oldverts[0]; +// gs.gsvertex[1] = oldverts[1]; +// gs.gsvertex[2] = oldverts[2]; +// ZeroGS::vb[ctx].clamp = oldclamp; +// ZeroGS::vb[ctx].tex1 = oldtex1; +// tex0Write(0, oldtex0); +// ZeroGS::vb[ctx].bTexConstsSync = FALSE; +// prim->_val = oldprim; +// bCanExecute = true; +//} +// +//void ExecuteBufferXeno::SetTex0(u32* data) +//{ +// if( data[0] != tex0data[0] || (data[1]&0x1fffffff) != (tex0data[1]&0x1fffffff) ) +// Execute(); +// +// tex0data[0] = data[0]; +// tex0data[1] = data[1]; +//} +// +//void ExecuteBufferXeno::SetTex1(u32* data) +//{ +// if( data[0] != tex1data[0] ) +// Execute(); +// +// tex1data[0] = data[0]; +// tex1data[1] = data[1]; +//} +// +//void ExecuteBufferXeno::SetClamp(u32* data) +//{ +// if( data[0] != clampdata[0] || (data[1]&0xfff) != clampdata[1] ) +// Execute(); +// +// clampdata[0] = data[0]; +// clampdata[1] = data[1]&0xfff; +//} +// +//void ExecuteBufferXeno::SetTri() +//{ +// if( prim->_val != curprim._val ) +// Execute(); +// curprim._val = prim->_val; +// vertices.push_back(gs.gsvertex[0]); +// vertices.push_back(gs.gsvertex[1]); +// vertices.push_back(gs.gsvertex[2]); +//} diff --git a/plugins/zerogs/dx/Regs.h b/plugins/zerogs/dx/Regs.h index 6ec859a6b3..b46799e2c3 100644 --- a/plugins/zerogs/dx/Regs.h +++ b/plugins/zerogs/dx/Regs.h @@ -1,122 +1,122 @@ -/* ZeroGS - * Copyright (C) 2005-2006 zerofrog@gmail.com - * - * 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 - */ - -#ifndef __GSREGS_H__ -#define __GSREGS_H__ - -typedef void (__fastcall *GIFRegHandler)(u32* data); - -void __fastcall GIFPackedRegHandlerNull(u32* data); -void __fastcall GIFPackedRegHandlerRGBA(u32* data); -void __fastcall GIFPackedRegHandlerSTQ(u32* data); -void __fastcall GIFPackedRegHandlerUV(u32* data); -void __fastcall GIFPackedRegHandlerXYZF2(u32* data); -void __fastcall GIFPackedRegHandlerXYZ2(u32* data); -void __fastcall GIFPackedRegHandlerFOG(u32* data); -void __fastcall GIFPackedRegHandlerA_D(u32* data); -void __fastcall GIFPackedRegHandlerNOP(u32* data); - -void __fastcall GIFRegHandlerNull(u32* data); -void __fastcall GIFRegHandlerPRIM(u32* data); -void __fastcall GIFRegHandlerRGBAQ(u32* data); -void __fastcall GIFRegHandlerST(u32* data); -void __fastcall GIFRegHandlerUV(u32* data); -void __fastcall GIFRegHandlerXYZF2(u32* data); -void __fastcall GIFRegHandlerXYZ2(u32* data); -void __fastcall GIFRegHandlerTEX0_1(u32* data); -void __fastcall GIFRegHandlerTEX0_2(u32* data); -void __fastcall GIFRegHandlerCLAMP_1(u32* data); -void __fastcall GIFRegHandlerCLAMP_2(u32* data); -void __fastcall GIFRegHandlerFOG(u32* data); -void __fastcall GIFRegHandlerXYZF3(u32* data); -void __fastcall GIFRegHandlerXYZ3(u32* data); -void __fastcall GIFRegHandlerNOP(u32* data); -void __fastcall GIFRegHandlerTEX1_1(u32* data); -void __fastcall GIFRegHandlerTEX1_2(u32* data); -void __fastcall GIFRegHandlerTEX2_1(u32* data); -void __fastcall GIFRegHandlerTEX2_2(u32* data); -void __fastcall GIFRegHandlerXYOFFSET_1(u32* data); -void __fastcall GIFRegHandlerXYOFFSET_2(u32* data); -void __fastcall GIFRegHandlerPRMODECONT(u32* data); -void __fastcall GIFRegHandlerPRMODE(u32* data); -void __fastcall GIFRegHandlerTEXCLUT(u32* data); -void __fastcall GIFRegHandlerSCANMSK(u32* data); -void __fastcall GIFRegHandlerMIPTBP1_1(u32* data); -void __fastcall GIFRegHandlerMIPTBP1_2(u32* data); -void __fastcall GIFRegHandlerMIPTBP2_1(u32* data); -void __fastcall GIFRegHandlerMIPTBP2_2(u32* data); -void __fastcall GIFRegHandlerTEXA(u32* data); -void __fastcall GIFRegHandlerFOGCOL(u32* data); -void __fastcall GIFRegHandlerTEXFLUSH(u32* data); -void __fastcall GIFRegHandlerSCISSOR_1(u32* data); -void __fastcall GIFRegHandlerSCISSOR_2(u32* data); -void __fastcall GIFRegHandlerALPHA_1(u32* data); -void __fastcall GIFRegHandlerALPHA_2(u32* data); -void __fastcall GIFRegHandlerDIMX(u32* data); -void __fastcall GIFRegHandlerDTHE(u32* data); -void __fastcall GIFRegHandlerCOLCLAMP(u32* data); -void __fastcall GIFRegHandlerTEST_1(u32* data); -void __fastcall GIFRegHandlerTEST_2(u32* data); -void __fastcall GIFRegHandlerPABE(u32* data); -void __fastcall GIFRegHandlerFBA_1(u32* data); -void __fastcall GIFRegHandlerFBA_2(u32* data); -void __fastcall GIFRegHandlerFRAME_1(u32* data); -void __fastcall GIFRegHandlerFRAME_2(u32* data); -void __fastcall GIFRegHandlerZBUF_1(u32* data); -void __fastcall GIFRegHandlerZBUF_2(u32* data); -void __fastcall GIFRegHandlerBITBLTBUF(u32* data); -void __fastcall GIFRegHandlerTRXPOS(u32* data); -void __fastcall GIFRegHandlerTRXREG(u32* data); -void __fastcall GIFRegHandlerTRXDIR(u32* data); -void __fastcall GIFRegHandlerHWREG(u32* data); -void __fastcall GIFRegHandlerSIGNAL(u32* data); -void __fastcall GIFRegHandlerFINISH(u32* data); -void __fastcall GIFRegHandlerLABEL(u32* data); - -// special buffers that delay executing some insturctions -//#include -// -//class ExecuteBuffer -//{ -//public: -// virtual void Execute()=0; -//}; -// -//class ExecuteBufferXeno : public ExecuteBuffer -//{ -//public: -// ExecuteBufferXeno(); -// virtual void Execute(); -// -// void SetTex0(u32* data); -// void SetTex1(u32* data); -// void SetClamp(u32* data); -// void SetTri(); -// -// u32 clampdata[2]; -// u32 tex0data[2]; -// u32 tex1data[2]; -// primInfo curprim; -// -// std::vector vertices; -// bool bCanExecute; -//}; -// -//extern ExecuteBufferXeno g_ebXeno; - -#endif +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#ifndef __GSREGS_H__ +#define __GSREGS_H__ + +typedef void (__fastcall *GIFRegHandler)(u32* data); + +void __fastcall GIFPackedRegHandlerNull(u32* data); +void __fastcall GIFPackedRegHandlerRGBA(u32* data); +void __fastcall GIFPackedRegHandlerSTQ(u32* data); +void __fastcall GIFPackedRegHandlerUV(u32* data); +void __fastcall GIFPackedRegHandlerXYZF2(u32* data); +void __fastcall GIFPackedRegHandlerXYZ2(u32* data); +void __fastcall GIFPackedRegHandlerFOG(u32* data); +void __fastcall GIFPackedRegHandlerA_D(u32* data); +void __fastcall GIFPackedRegHandlerNOP(u32* data); + +void __fastcall GIFRegHandlerNull(u32* data); +void __fastcall GIFRegHandlerPRIM(u32* data); +void __fastcall GIFRegHandlerRGBAQ(u32* data); +void __fastcall GIFRegHandlerST(u32* data); +void __fastcall GIFRegHandlerUV(u32* data); +void __fastcall GIFRegHandlerXYZF2(u32* data); +void __fastcall GIFRegHandlerXYZ2(u32* data); +void __fastcall GIFRegHandlerTEX0_1(u32* data); +void __fastcall GIFRegHandlerTEX0_2(u32* data); +void __fastcall GIFRegHandlerCLAMP_1(u32* data); +void __fastcall GIFRegHandlerCLAMP_2(u32* data); +void __fastcall GIFRegHandlerFOG(u32* data); +void __fastcall GIFRegHandlerXYZF3(u32* data); +void __fastcall GIFRegHandlerXYZ3(u32* data); +void __fastcall GIFRegHandlerNOP(u32* data); +void __fastcall GIFRegHandlerTEX1_1(u32* data); +void __fastcall GIFRegHandlerTEX1_2(u32* data); +void __fastcall GIFRegHandlerTEX2_1(u32* data); +void __fastcall GIFRegHandlerTEX2_2(u32* data); +void __fastcall GIFRegHandlerXYOFFSET_1(u32* data); +void __fastcall GIFRegHandlerXYOFFSET_2(u32* data); +void __fastcall GIFRegHandlerPRMODECONT(u32* data); +void __fastcall GIFRegHandlerPRMODE(u32* data); +void __fastcall GIFRegHandlerTEXCLUT(u32* data); +void __fastcall GIFRegHandlerSCANMSK(u32* data); +void __fastcall GIFRegHandlerMIPTBP1_1(u32* data); +void __fastcall GIFRegHandlerMIPTBP1_2(u32* data); +void __fastcall GIFRegHandlerMIPTBP2_1(u32* data); +void __fastcall GIFRegHandlerMIPTBP2_2(u32* data); +void __fastcall GIFRegHandlerTEXA(u32* data); +void __fastcall GIFRegHandlerFOGCOL(u32* data); +void __fastcall GIFRegHandlerTEXFLUSH(u32* data); +void __fastcall GIFRegHandlerSCISSOR_1(u32* data); +void __fastcall GIFRegHandlerSCISSOR_2(u32* data); +void __fastcall GIFRegHandlerALPHA_1(u32* data); +void __fastcall GIFRegHandlerALPHA_2(u32* data); +void __fastcall GIFRegHandlerDIMX(u32* data); +void __fastcall GIFRegHandlerDTHE(u32* data); +void __fastcall GIFRegHandlerCOLCLAMP(u32* data); +void __fastcall GIFRegHandlerTEST_1(u32* data); +void __fastcall GIFRegHandlerTEST_2(u32* data); +void __fastcall GIFRegHandlerPABE(u32* data); +void __fastcall GIFRegHandlerFBA_1(u32* data); +void __fastcall GIFRegHandlerFBA_2(u32* data); +void __fastcall GIFRegHandlerFRAME_1(u32* data); +void __fastcall GIFRegHandlerFRAME_2(u32* data); +void __fastcall GIFRegHandlerZBUF_1(u32* data); +void __fastcall GIFRegHandlerZBUF_2(u32* data); +void __fastcall GIFRegHandlerBITBLTBUF(u32* data); +void __fastcall GIFRegHandlerTRXPOS(u32* data); +void __fastcall GIFRegHandlerTRXREG(u32* data); +void __fastcall GIFRegHandlerTRXDIR(u32* data); +void __fastcall GIFRegHandlerHWREG(u32* data); +void __fastcall GIFRegHandlerSIGNAL(u32* data); +void __fastcall GIFRegHandlerFINISH(u32* data); +void __fastcall GIFRegHandlerLABEL(u32* data); + +// special buffers that delay executing some insturctions +//#include +// +//class ExecuteBuffer +//{ +//public: +// virtual void Execute()=0; +//}; +// +//class ExecuteBufferXeno : public ExecuteBuffer +//{ +//public: +// ExecuteBufferXeno(); +// virtual void Execute(); +// +// void SetTex0(u32* data); +// void SetTex1(u32* data); +// void SetClamp(u32* data); +// void SetTri(); +// +// u32 clampdata[2]; +// u32 tex0data[2]; +// u32 tex1data[2]; +// primInfo curprim; +// +// std::vector vertices; +// bool bCanExecute; +//}; +// +//extern ExecuteBufferXeno g_ebXeno; + +#endif diff --git a/plugins/zerogs/dx/Win32/Conf.cpp b/plugins/zerogs/dx/Win32/Conf.cpp index e887ad3e81..c20e0187c7 100644 --- a/plugins/zerogs/dx/Win32/Conf.cpp +++ b/plugins/zerogs/dx/Win32/Conf.cpp @@ -1,117 +1,117 @@ -#if defined(_WIN32) || defined(__WIN32__) -#include -#include -#endif - -#include - -#include "GS.h" -#include "Win32.h" - -extern HINSTANCE hInst; - - -void SaveConfig() { - - char *szTemp; - char szIniFile[256], szValue[256]; - - GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); - szTemp = strrchr(szIniFile, '\\'); - - if(!szTemp) return; - strcpy(szTemp, "\\inis\\zerogs.ini"); - - sprintf(szValue,"%u",conf.interlace); - WritePrivateProfileString("Settings", "Interlace",szValue,szIniFile); - sprintf(szValue,"%u",conf.aa); - WritePrivateProfileString("Settings", "Antialiasing",szValue,szIniFile); - sprintf(szValue,"%u",conf.bilinear); - WritePrivateProfileString("Settings", "Bilinear",szValue,szIniFile); - sprintf(szValue,"%u",conf.options); - WritePrivateProfileString("Settings", "Options",szValue,szIniFile); - sprintf(szValue,"%u",conf.gamesettings); - WritePrivateProfileString("Settings", "AdvancedOptions",szValue,szIniFile); -} - -void LoadConfig() { - - FILE *fp; - char *szTemp; - char szIniFile[256], szValue[256]; - - GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); - szTemp = strrchr(szIniFile, '\\'); - - memset(&conf, 0, sizeof(conf)); - conf.interlace = 0; // on, mode 1 - conf.mrtdepth = 1; - conf.options = 0; - conf.bilinear = 1; - conf.width = 640; - conf.height = 480; - - if(!szTemp) return ; - strcpy(szTemp, "\\inis\\zerogs.ini"); - fp=fopen("inis\\zerogs.ini","rt"); - if (!fp) - { - CreateDirectory("inis",NULL); - SaveConfig();//save and return - return ; - } - fclose(fp); - - GetPrivateProfileString("Settings", "Interlace", NULL, szValue, 20, szIniFile); - conf.interlace = (u8)strtoul(szValue, NULL, 10); - GetPrivateProfileString("Settings", "Antialiasing", NULL, szValue, 20, szIniFile); - conf.aa = (u8)strtoul(szValue, NULL, 10); - GetPrivateProfileString("Settings", "Options", NULL, szValue, 20, szIniFile); - conf.options = strtoul(szValue, NULL, 10); - GetPrivateProfileString("Settings", "AdvancedOptions", NULL, szValue, 20, szIniFile); - conf.gamesettings = strtoul(szValue, NULL, 10); - GetPrivateProfileString("Settings", "Bilinear", NULL, szValue, 20, szIniFile); - conf.bilinear = strtoul(szValue, NULL, 10); - - if( conf.aa < 0 || conf.aa > 4 ) conf.aa = 0; - - switch(conf.options&GSOPTION_WINDIMS) { - case GSOPTION_WIN640: - conf.width = 640; - conf.height = 480; - break; - case GSOPTION_WIN800: - conf.width = 800; - conf.height = 600; - break; - case GSOPTION_WIN1024: - conf.width = 1024; - conf.height = 768; - break; - case GSOPTION_WIN1280: - conf.width = 1280; - conf.height = 960; - break; - case GSOPTION_WIN960W: - conf.width = 960; - conf.height = 540; - break; - case GSOPTION_WIN1280W: - conf.width = 1280; - conf.height = 720; - break; - case GSOPTION_WIN1920W: - conf.width = 1920; - conf.height = 1080; - break; - } - - // turn off all hacks by defaultof - conf.options &= ~(GSOPTION_FULLSCREEN|GSOPTION_WIREFRAME|GSOPTION_CAPTUREAVI); - conf.options |= GSOPTION_LOADED; - - if( conf.width <= 0 || conf.height <= 0 ) { - conf.width = 640; - conf.height = 480; - } -} +#if defined(_WIN32) || defined(__WIN32__) +#include +#include +#endif + +#include + +#include "GS.h" +#include "Win32.h" + +extern HINSTANCE hInst; + + +void SaveConfig() { + + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\zerogs.ini"); + + sprintf(szValue,"%u",conf.interlace); + WritePrivateProfileString("Settings", "Interlace",szValue,szIniFile); + sprintf(szValue,"%u",conf.aa); + WritePrivateProfileString("Settings", "Antialiasing",szValue,szIniFile); + sprintf(szValue,"%u",conf.bilinear); + WritePrivateProfileString("Settings", "Bilinear",szValue,szIniFile); + sprintf(szValue,"%u",conf.options); + WritePrivateProfileString("Settings", "Options",szValue,szIniFile); + sprintf(szValue,"%u",conf.gamesettings); + WritePrivateProfileString("Settings", "AdvancedOptions",szValue,szIniFile); +} + +void LoadConfig() { + + FILE *fp; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + memset(&conf, 0, sizeof(conf)); + conf.interlace = 0; // on, mode 1 + conf.mrtdepth = 1; + conf.options = 0; + conf.bilinear = 1; + conf.width = 640; + conf.height = 480; + + if(!szTemp) return ; + strcpy(szTemp, "\\inis\\zerogs.ini"); + fp=fopen("inis\\zerogs.ini","rt"); + if (!fp) + { + CreateDirectory("inis",NULL); + SaveConfig();//save and return + return ; + } + fclose(fp); + + GetPrivateProfileString("Settings", "Interlace", NULL, szValue, 20, szIniFile); + conf.interlace = (u8)strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Antialiasing", NULL, szValue, 20, szIniFile); + conf.aa = (u8)strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Options", NULL, szValue, 20, szIniFile); + conf.options = strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "AdvancedOptions", NULL, szValue, 20, szIniFile); + conf.gamesettings = strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Bilinear", NULL, szValue, 20, szIniFile); + conf.bilinear = strtoul(szValue, NULL, 10); + + if( conf.aa < 0 || conf.aa > 4 ) conf.aa = 0; + + switch(conf.options&GSOPTION_WINDIMS) { + case GSOPTION_WIN640: + conf.width = 640; + conf.height = 480; + break; + case GSOPTION_WIN800: + conf.width = 800; + conf.height = 600; + break; + case GSOPTION_WIN1024: + conf.width = 1024; + conf.height = 768; + break; + case GSOPTION_WIN1280: + conf.width = 1280; + conf.height = 960; + break; + case GSOPTION_WIN960W: + conf.width = 960; + conf.height = 540; + break; + case GSOPTION_WIN1280W: + conf.width = 1280; + conf.height = 720; + break; + case GSOPTION_WIN1920W: + conf.width = 1920; + conf.height = 1080; + break; + } + + // turn off all hacks by defaultof + conf.options &= ~(GSOPTION_FULLSCREEN|GSOPTION_WIREFRAME|GSOPTION_CAPTUREAVI); + conf.options |= GSOPTION_LOADED; + + if( conf.width <= 0 || conf.height <= 0 ) { + conf.width = 640; + conf.height = 480; + } +} diff --git a/plugins/zerogs/dx/Win32/Win32.cpp b/plugins/zerogs/dx/Win32/Win32.cpp index 25bc1f68d1..4da563ba5a 100644 --- a/plugins/zerogs/dx/Win32/Win32.cpp +++ b/plugins/zerogs/dx/Win32/Win32.cpp @@ -1,269 +1,269 @@ -#if defined(_WIN32) || defined(__WIN32__) -#include -#include -#endif - -#include -#include -#include - -#include "resrc1.h" - -#include "GS.h" -#include "Win32.h" - -#include -using namespace std; - -extern int g_nPixelShaderVer; -HINSTANCE hInst=NULL; -static int prevbilinearfilter = 0; - -void CALLBACK GSkeyEvent(keyEvent *ev) { -// switch (ev->event) { -// case KEYPRESS: -// switch (ev->key) { -// case VK_PRIOR: -// if (conf.fps) fpspos++; break; -// case VK_NEXT: -// if (conf.fps) fpspos--; break; -// case VK_END: -// if (conf.fps) fpspress = 1; break; -// case VK_DELETE: -// conf.fps = 1 - conf.fps; -// break; -// } -// break; -// } -} - -#include "Win32/resource.h" - -BOOL CALLBACK LoggingDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { - switch(uMsg) { - case WM_INITDIALOG: - if (conf.log) CheckDlgButton(hW, IDC_LOG, TRUE); - return TRUE; - - case WM_COMMAND: - switch(LOWORD(wParam)) { - case IDCANCEL: - EndDialog(hW, FALSE); - return TRUE; - case IDOK: - if (IsDlgButtonChecked(hW, IDC_LOG)) - conf.log = 1; - else conf.log = 0; - - SaveConfig(); - EndDialog(hW, FALSE); - return TRUE; - } - } - return FALSE; -} - -map mapConfOpts; -#define PUT_CONF(id) mapConfOpts[IDC_CONFOPT_##id] = 0x##id; - -void OnInitDialog(HWND hW) -{ - if( !(conf.options & GSOPTION_LOADED) ) - LoadConfig(); - - CheckDlgButton(hW, IDC_CONFIG_INTERLACE, conf.interlace); - CheckDlgButton(hW, IDC_CONFIG_BILINEAR, !!conf.bilinear); - CheckDlgButton(hW, IDC_CONFIG_DEPTHWRITE, conf.mrtdepth); - CheckRadioButton(hW,IDC_CONFIG_AANONE,IDC_CONFIG_AA16, IDC_CONFIG_AANONE+conf.aa); - CheckDlgButton(hW, IDC_CONFIG_WIREFRAME, (conf.options&GSOPTION_WIREFRAME)?1:0); - CheckDlgButton(hW, IDC_CONFIG_CAPTUREAVI, (conf.options&GSOPTION_CAPTUREAVI)?1:0); - CheckDlgButton(hW, IDC_CONFIG_FULLSCREEN, (conf.options&GSOPTION_FULLSCREEN)?1:0); - //CheckDlgButton(hW, IDC_CONFIG_FFX, (conf.options&GSOPTION_FFXHACK)?1:0); - CheckDlgButton(hW, IDC_CONFIG_BMPSS, (conf.options&GSOPTION_BMPSNAP)?1:0); - CheckRadioButton(hW,IDC_CONF_WIN640, IDC_CONF_WIN1920W, IDC_CONF_WIN640+((conf.options&GSOPTION_WINDIMS)>>4)); - - prevbilinearfilter = conf.bilinear; - - mapConfOpts.clear(); - PUT_CONF(00000001); - PUT_CONF(00000002); - PUT_CONF(00000004); - PUT_CONF(00000008); - PUT_CONF(00000010); - PUT_CONF(00000020); - PUT_CONF(00000040); - PUT_CONF(00000080); - PUT_CONF(00000200); - PUT_CONF(00000400); - PUT_CONF(00000800); - PUT_CONF(00001000); - PUT_CONF(00002000); - PUT_CONF(00004000); - PUT_CONF(00008000); - PUT_CONF(00010000); - PUT_CONF(00020000); - PUT_CONF(00040000); - PUT_CONF(00080000); - PUT_CONF(00100000); - PUT_CONF(00200000); - PUT_CONF(01000000); - PUT_CONF(02000000); - PUT_CONF(04000000); - PUT_CONF(08000000); - - for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { - CheckDlgButton(hW, it->first, (conf.gamesettings&it->second)?1:0); - } -} - -void OnOK(HWND hW) { - - u32 newinterlace = IsDlgButtonChecked(hW, IDC_CONFIG_INTERLACE); - - if( !conf.interlace ) conf.interlace = newinterlace; - else if( !newinterlace ) conf.interlace = 2; // off - - conf.bilinear = IsDlgButtonChecked(hW, IDC_CONFIG_BILINEAR); - // restore - if( conf.bilinear && prevbilinearfilter ) - conf.bilinear = prevbilinearfilter; - - if( SendDlgItemMessage(hW,IDC_CONFIG_AANONE,BM_GETCHECK,0,0) ) { - conf.aa = 0; - } - else if( SendDlgItemMessage(hW,IDC_CONFIG_AA2,BM_GETCHECK,0,0) ) { - conf.aa = 1; - } - else if( SendDlgItemMessage(hW,IDC_CONFIG_AA4,BM_GETCHECK,0,0) ) { - conf.aa = 2; - } - else if( SendDlgItemMessage(hW,IDC_CONFIG_AA8,BM_GETCHECK,0,0) ) { - conf.aa = 3; - } - else if( SendDlgItemMessage(hW,IDC_CONFIG_AA16,BM_GETCHECK,0,0) ) { - conf.aa = 4; - } - else conf.aa = 0; - - conf.options = 0; - conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_CAPTUREAVI) ? GSOPTION_CAPTUREAVI : 0; - conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_WIREFRAME) ? GSOPTION_WIREFRAME : 0; - conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_FULLSCREEN) ? GSOPTION_FULLSCREEN : 0; - conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_BMPSS) ? GSOPTION_BMPSNAP : 0; - - conf.gamesettings = 0; - for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { - if( IsDlgButtonChecked(hW, it->first) ) - conf.gamesettings |= it->second; - } - GSsetGameCRC(g_LastCRC, conf.gamesettings); - - if( SendDlgItemMessage(hW,IDC_CONF_WIN640,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN640; - else if( SendDlgItemMessage(hW,IDC_CONF_WIN800,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN800; - else if( SendDlgItemMessage(hW,IDC_CONF_WIN1024,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1024; - else if( SendDlgItemMessage(hW,IDC_CONF_WIN1280,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1280; - else if( SendDlgItemMessage(hW,IDC_CONF_WIN960W,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN960W; - else if( SendDlgItemMessage(hW,IDC_CONF_WIN1280W,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1280W; - else if( SendDlgItemMessage(hW,IDC_CONF_WIN1920W,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1920W; - - SaveConfig(); - EndDialog(hW, FALSE); -} - -BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { - switch(uMsg) { - case WM_INITDIALOG: - OnInitDialog(hW); - return TRUE; - - case WM_COMMAND: - switch(LOWORD(wParam)) { - case IDCANCEL: - EndDialog(hW, TRUE); - return TRUE; - case IDOK: - OnOK(hW); - return TRUE; - case IDC_CONFOPT_COMPUTEOR: - { - int value = 0; - for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { - if( IsDlgButtonChecked(hW, it->first) ) - value|= it->second; - } - char str[20]; - sprintf(str, "%.8x", value); - SetWindowText(GetDlgItem(hW, IDC_CONFOPT_IDS), str); - break; - } - case IDC_CONF_DEFAULT: - { - for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { - CheckDlgButton(hW, it->first, 0); - } - break; - } - } - } - return FALSE; -} - -BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { - switch(uMsg) { - case WM_INITDIALOG: - - //ZeroGS uses floating point render targets because A8R8G8B8 format is not sufficient for ps2 blending and this requires alpha blending on floating point render targets - //There might be a problem with pixel shader precision with older geforce models (textures will look blocky). - - return TRUE; - - case WM_COMMAND: - switch(LOWORD(wParam)) { - case IDOK: - EndDialog(hW, FALSE); - return TRUE; - } - } - return FALSE; -} - -s32 CALLBACK GStest() { - return 0; -} - -void CALLBACK GSabout() { - DialogBox(hInst, - MAKEINTRESOURCE(IDD_ABOUT), - GetActiveWindow(), - (DLGPROC)AboutDlgProc); -} - -BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT - DWORD dwReason, - LPVOID lpReserved) { - hInst = (HINSTANCE)hModule; - return TRUE; // very quick :) -} - -static char *err = "Error Loading Symbol"; -static int errval; - -void *SysLoadLibrary(char *lib) { - return LoadLibrary(lib); -} - -void *SysLoadSym(void *lib, char *sym) { - void *tmp = GetProcAddress((HINSTANCE)lib, sym); - if (tmp == NULL) errval = 1; - else errval = 0; - return tmp; -} - -char *SysLibError() { - if (errval) { errval = 0; return err; } - return NULL; -} - -void SysCloseLibrary(void *lib) { - FreeLibrary((HINSTANCE)lib); -} +#if defined(_WIN32) || defined(__WIN32__) +#include +#include +#endif + +#include +#include +#include + +#include "resrc1.h" + +#include "GS.h" +#include "Win32.h" + +#include +using namespace std; + +extern int g_nPixelShaderVer; +HINSTANCE hInst=NULL; +static int prevbilinearfilter = 0; + +void CALLBACK GSkeyEvent(keyEvent *ev) { +// switch (ev->event) { +// case KEYPRESS: +// switch (ev->key) { +// case VK_PRIOR: +// if (conf.fps) fpspos++; break; +// case VK_NEXT: +// if (conf.fps) fpspos--; break; +// case VK_END: +// if (conf.fps) fpspress = 1; break; +// case VK_DELETE: +// conf.fps = 1 - conf.fps; +// break; +// } +// break; +// } +} + +#include "Win32/resource.h" + +BOOL CALLBACK LoggingDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + if (conf.log) CheckDlgButton(hW, IDC_LOG, TRUE); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, FALSE); + return TRUE; + case IDOK: + if (IsDlgButtonChecked(hW, IDC_LOG)) + conf.log = 1; + else conf.log = 0; + + SaveConfig(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +map mapConfOpts; +#define PUT_CONF(id) mapConfOpts[IDC_CONFOPT_##id] = 0x##id; + +void OnInitDialog(HWND hW) +{ + if( !(conf.options & GSOPTION_LOADED) ) + LoadConfig(); + + CheckDlgButton(hW, IDC_CONFIG_INTERLACE, conf.interlace); + CheckDlgButton(hW, IDC_CONFIG_BILINEAR, !!conf.bilinear); + CheckDlgButton(hW, IDC_CONFIG_DEPTHWRITE, conf.mrtdepth); + CheckRadioButton(hW,IDC_CONFIG_AANONE,IDC_CONFIG_AA16, IDC_CONFIG_AANONE+conf.aa); + CheckDlgButton(hW, IDC_CONFIG_WIREFRAME, (conf.options&GSOPTION_WIREFRAME)?1:0); + CheckDlgButton(hW, IDC_CONFIG_CAPTUREAVI, (conf.options&GSOPTION_CAPTUREAVI)?1:0); + CheckDlgButton(hW, IDC_CONFIG_FULLSCREEN, (conf.options&GSOPTION_FULLSCREEN)?1:0); + //CheckDlgButton(hW, IDC_CONFIG_FFX, (conf.options&GSOPTION_FFXHACK)?1:0); + CheckDlgButton(hW, IDC_CONFIG_BMPSS, (conf.options&GSOPTION_BMPSNAP)?1:0); + CheckRadioButton(hW,IDC_CONF_WIN640, IDC_CONF_WIN1920W, IDC_CONF_WIN640+((conf.options&GSOPTION_WINDIMS)>>4)); + + prevbilinearfilter = conf.bilinear; + + mapConfOpts.clear(); + PUT_CONF(00000001); + PUT_CONF(00000002); + PUT_CONF(00000004); + PUT_CONF(00000008); + PUT_CONF(00000010); + PUT_CONF(00000020); + PUT_CONF(00000040); + PUT_CONF(00000080); + PUT_CONF(00000200); + PUT_CONF(00000400); + PUT_CONF(00000800); + PUT_CONF(00001000); + PUT_CONF(00002000); + PUT_CONF(00004000); + PUT_CONF(00008000); + PUT_CONF(00010000); + PUT_CONF(00020000); + PUT_CONF(00040000); + PUT_CONF(00080000); + PUT_CONF(00100000); + PUT_CONF(00200000); + PUT_CONF(01000000); + PUT_CONF(02000000); + PUT_CONF(04000000); + PUT_CONF(08000000); + + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + CheckDlgButton(hW, it->first, (conf.gamesettings&it->second)?1:0); + } +} + +void OnOK(HWND hW) { + + u32 newinterlace = IsDlgButtonChecked(hW, IDC_CONFIG_INTERLACE); + + if( !conf.interlace ) conf.interlace = newinterlace; + else if( !newinterlace ) conf.interlace = 2; // off + + conf.bilinear = IsDlgButtonChecked(hW, IDC_CONFIG_BILINEAR); + // restore + if( conf.bilinear && prevbilinearfilter ) + conf.bilinear = prevbilinearfilter; + + if( SendDlgItemMessage(hW,IDC_CONFIG_AANONE,BM_GETCHECK,0,0) ) { + conf.aa = 0; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA2,BM_GETCHECK,0,0) ) { + conf.aa = 1; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA4,BM_GETCHECK,0,0) ) { + conf.aa = 2; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA8,BM_GETCHECK,0,0) ) { + conf.aa = 3; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA16,BM_GETCHECK,0,0) ) { + conf.aa = 4; + } + else conf.aa = 0; + + conf.options = 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_CAPTUREAVI) ? GSOPTION_CAPTUREAVI : 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_WIREFRAME) ? GSOPTION_WIREFRAME : 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_FULLSCREEN) ? GSOPTION_FULLSCREEN : 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_BMPSS) ? GSOPTION_BMPSNAP : 0; + + conf.gamesettings = 0; + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + if( IsDlgButtonChecked(hW, it->first) ) + conf.gamesettings |= it->second; + } + GSsetGameCRC(g_LastCRC, conf.gamesettings); + + if( SendDlgItemMessage(hW,IDC_CONF_WIN640,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN640; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN800,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN800; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN1024,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1024; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN1280,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1280; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN960W,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN960W; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN1280W,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1280W; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN1920W,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1920W; + + SaveConfig(); + EndDialog(hW, FALSE); +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + OnInitDialog(hW); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + case IDOK: + OnOK(hW); + return TRUE; + case IDC_CONFOPT_COMPUTEOR: + { + int value = 0; + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + if( IsDlgButtonChecked(hW, it->first) ) + value|= it->second; + } + char str[20]; + sprintf(str, "%.8x", value); + SetWindowText(GetDlgItem(hW, IDC_CONFOPT_IDS), str); + break; + } + case IDC_CONF_DEFAULT: + { + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + CheckDlgButton(hW, it->first, 0); + } + break; + } + } + } + return FALSE; +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + + //ZeroGS uses floating point render targets because A8R8G8B8 format is not sufficient for ps2 blending and this requires alpha blending on floating point render targets + //There might be a problem with pixel shader precision with older geforce models (textures will look blocky). + + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +s32 CALLBACK GStest() { + return 0; +} + +void CALLBACK GSabout() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc); +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + +static char *err = "Error Loading Symbol"; +static int errval; + +void *SysLoadLibrary(char *lib) { + return LoadLibrary(lib); +} + +void *SysLoadSym(void *lib, char *sym) { + void *tmp = GetProcAddress((HINSTANCE)lib, sym); + if (tmp == NULL) errval = 1; + else errval = 0; + return tmp; +} + +char *SysLibError() { + if (errval) { errval = 0; return err; } + return NULL; +} + +void SysCloseLibrary(void *lib) { + FreeLibrary((HINSTANCE)lib); +} diff --git a/plugins/zerogs/dx/Win32/Win32.h b/plugins/zerogs/dx/Win32/Win32.h index 45322b3d01..acea999c8b 100644 --- a/plugins/zerogs/dx/Win32/Win32.h +++ b/plugins/zerogs/dx/Win32/Win32.h @@ -1,9 +1,9 @@ -#ifndef __WIN32_H__ -#define __WIN32_H__ - -#include "resrc1.h" -#include "Win32/resource.h" - -BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); - -#endif /* __WIN32_H__ */ +#ifndef __WIN32_H__ +#define __WIN32_H__ + +#include "resrc1.h" +#include "Win32/resource.h" + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); + +#endif /* __WIN32_H__ */ diff --git a/plugins/zerogs/dx/Win32/aviUtil.h b/plugins/zerogs/dx/Win32/aviUtil.h index 945fd3d68a..10a7f91805 100644 --- a/plugins/zerogs/dx/Win32/aviUtil.h +++ b/plugins/zerogs/dx/Win32/aviUtil.h @@ -1,484 +1,484 @@ -#define AVIIF_KEYFRAME 0x00000010L // this frame is a key frame. - -#include -using namespace std; - -#include -#include -#include - -BOOL AVI_Init() -{ - /* first let's make sure we are running on 1.1 */ - WORD wVer = HIWORD(VideoForWindowsVersion()); - if (wVer < 0x010a){ - /* oops, we are too old, blow out of here */ - //MessageBeep(MB_ICONHAND); - MessageBox(NULL, "Cant't init AVI File - Video for Windows version is to old", "Error", MB_OK|MB_ICONSTOP); - return FALSE; - } - - AVIFileInit(); - - return TRUE; -} - -BOOL AVI_FileOpenWrite(PAVIFILE * pfile, const char *filename) -{ - HRESULT hr = AVIFileOpen(pfile, // returned file pointer - filename, // file name - OF_WRITE | OF_CREATE, // mode to open file with - NULL); // use handler determined - // from file extension.... - if (hr != AVIERR_OK) - return FALSE; - - return TRUE; -} - -DWORD getFOURCC(const char* value) -{ - if(_stricmp(value, "DIB") == 0) - { - return mmioFOURCC(value[0],value[1],value[2],' '); - } - else if((_stricmp(value, "CVID") == 0) - || (_stricmp(value, "IV32") == 0) - || (_stricmp(value, "MSVC") == 0) - || (_stricmp(value, "IV50") == 0)) - { - return mmioFOURCC(value[0],value[1],value[2],value[3]); - } - else - { - return NULL; - } -} - -// Fill in the header for the video stream.... -// The video stream will run in rate ths of a second.... -BOOL AVI_CreateStream(PAVIFILE pfile, PAVISTREAM * ps, int rate, // sample/second - unsigned long buffersize, int rectwidth, int rectheight, - const char* _compressor) -{ - AVISTREAMINFO strhdr; - memset(&strhdr, 0, sizeof(strhdr)); - strhdr.fccType = streamtypeVIDEO;// stream type - strhdr.fccHandler = getFOURCC(_compressor); - //strhdr.fccHandler = 0; // no compression! - //strhdr.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed - //strhdr.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak - //strhdr.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2 - //strhdr.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1 - //strhdr.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0 - //strhdr.dwFlags = AVISTREAMINFO_DISABLED; - //strhdr.dwCaps = - //strhdr.wPriority = - //strhdr.wLanguage = - strhdr.dwScale = 1; - strhdr.dwRate = rate; // rate fps - //strhdr.dwStart = - //strhdr.dwLength = - //strhdr.dwInitialFrames = - strhdr.dwSuggestedBufferSize = buffersize; - strhdr.dwQuality = -1; // use the default - //strhdr.dwSampleSize = - SetRect(&strhdr.rcFrame, 0, 0, // rectangle for stream - (int) rectwidth, - (int) rectheight); - //strhdr.dwEditCount = - //strhdr.dwFormatChangeCount = - //strcpy(strhdr.szName, "Full Frames (Uncompressed)"); - - // And create the stream; - HRESULT hr = AVIFileCreateStream(pfile, // file pointer - ps, // returned stream pointer - &strhdr); // stream header - if (hr != AVIERR_OK) { - return FALSE; - } - - return TRUE; -} - -string getFOURCCVAsString(DWORD value) -{ - string returnValue = ""; - if( value == 0 ) - return returnValue; - - DWORD ch0 = value & 0x000000FF; - returnValue.push_back((char) ch0); - DWORD ch1 = (value & 0x0000FF00)>>8; - returnValue.push_back((char) ch1); - DWORD ch2 = (value & 0x00FF0000)>>16; - returnValue.push_back((char) ch2); - DWORD ch3 = (value & 0xFF000000)>>24; - returnValue.push_back((char) ch3); - - return returnValue; -} - -string dumpAVICOMPRESSOPTIONS(AVICOMPRESSOPTIONS opts) -{ - char tmp[255]; - string returnValue = "Dump of AVICOMPRESSOPTIONS\n"; - - returnValue += "DWORD fccType = streamtype("; returnValue += getFOURCCVAsString(opts.fccType); returnValue += ")\n"; - returnValue += "DWORD fccHandler = "; returnValue += getFOURCCVAsString(opts.fccHandler); returnValue += "\n"; - - _snprintf(tmp, 255, "DWORD dwKeyFrameEvery = %d\n", opts.dwKeyFrameEvery); - returnValue += tmp; - - _snprintf(tmp, 255, "DWORD dwQuality = %d\n", opts.dwQuality); - returnValue += tmp; - - _snprintf(tmp, 255, "DWORD dwBytesPerSecond = %d\n", opts.dwBytesPerSecond); - returnValue += tmp; - - if((opts.dwFlags & AVICOMPRESSF_DATARATE) == AVICOMPRESSF_DATARATE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_DATARATE\n");} - else if((opts.dwFlags & AVICOMPRESSF_INTERLEAVE) == AVICOMPRESSF_INTERLEAVE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_INTERLEAVE\n");} - else if((opts.dwFlags & AVICOMPRESSF_KEYFRAMES) == AVICOMPRESSF_KEYFRAMES){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_KEYFRAMES\n");} - else if((opts.dwFlags & AVICOMPRESSF_VALID) == AVICOMPRESSF_VALID){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_VALID\n");} - else {_snprintf(tmp, 255, "DWORD dwFlags = Unknown(%d)\n", opts.dwFlags);} - returnValue += tmp; - - _snprintf(tmp, 255, "LPVOID lpFormat = %d\n", opts.lpFormat); - returnValue += tmp; - - _snprintf(tmp, 255, "DWORD cbFormat = %d\n", opts.cbFormat); - returnValue += tmp; - - _snprintf(tmp, 255, "LPVOID lpParms = %d\n", opts.lpParms); - returnValue += tmp; - - _snprintf(tmp, 255, "DWORD cbParms = %d\n", opts.cbParms); - returnValue += tmp; - - _snprintf(tmp, 255, "DWORD dwInterleaveEvery = %d\n", opts.dwInterleaveEvery); - returnValue += tmp; - - return returnValue; -} - -BOOL AVI_SetOptions(PAVISTREAM * ps, PAVISTREAM * psCompressed, LPBITMAPINFOHEADER lpbi, - const char* _compressor) -{ - - AVICOMPRESSOPTIONS opts; - AVICOMPRESSOPTIONS FAR * aopts[1] = {&opts}; - - memset(&opts, 0, sizeof(opts)); - opts.fccType = streamtypeVIDEO; - opts.fccHandler = getFOURCC(_compressor); - //opts.fccHandler = 0; - //opts.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed - //opts.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak - //opts.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2 - //opts.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1 - //opts.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0 - //opts.dwKeyFrameEvery = 5; - //opts.dwQuality - //opts.dwBytesPerSecond - //opts.dwFlags = AVICOMPRESSF_KEYFRAMES; - //opts.lpFormat - //opts.cbFormat - //opts.lpParms - //opts.cbParms - //opts.dwInterleaveEvery - - /* display the compression options dialog box if specified compressor is unknown */ - if(getFOURCC(_compressor) == NULL) - { - if (!AVISaveOptions(NULL, 0, 1, ps, (LPAVICOMPRESSOPTIONS FAR *) &aopts)) - { - return FALSE; - } - - //printf("%s", dumpAVICOMPRESSOPTIONS(opts)); - //MessageBox(NULL, dumpAVICOMPRESSOPTIONS(opts).c_str(), "AVICOMPRESSOPTIONS", MB_OK); - } - - HRESULT hr = AVIMakeCompressedStream(psCompressed, *ps, &opts, NULL); - if (hr != AVIERR_OK) { - return FALSE; - } - - hr = AVIStreamSetFormat(*psCompressed, 0, - lpbi, // stream format - lpbi->biSize // format size - + lpbi->biClrUsed * sizeof(RGBQUAD) - ); - if (hr != AVIERR_OK) { - return FALSE; - } - - return TRUE; -} - -BOOL AVI_SetText(PAVIFILE pfile, PAVISTREAM psText, char *szText, int width, int height, int TextHeight) -{ - // Fill in the stream header for the text stream.... - AVISTREAMINFO strhdr; - DWORD dwTextFormat; - // The text stream is in 60ths of a second.... - - memset(&strhdr, 0, sizeof(strhdr)); - strhdr.fccType = streamtypeTEXT; - strhdr.fccHandler = mmioFOURCC('D', 'R', 'A', 'W'); - strhdr.dwScale = 1; - strhdr.dwRate = 60; - strhdr.dwSuggestedBufferSize = sizeof(szText); - SetRect(&strhdr.rcFrame, 0, (int) height, - (int) width, (int) height + TextHeight); // #define TEXT_HEIGHT 20 - - // ....and create the stream. - HRESULT hr = AVIFileCreateStream(pfile, &psText, &strhdr); - if (hr != AVIERR_OK) { - return FALSE; - } - - dwTextFormat = sizeof(dwTextFormat); - hr = AVIStreamSetFormat(psText, 0, &dwTextFormat, sizeof(dwTextFormat)); - if (hr != AVIERR_OK) { - return FALSE; - } - - return TRUE; -} - -BOOL AVI_AddFrame(PAVISTREAM psCompressed, int time, LPBITMAPINFOHEADER lpbi) -{ - int ImageSize = lpbi->biSizeImage; - if (ImageSize == 0) - { - if (lpbi->biBitCount == 24) - { - ImageSize = lpbi->biWidth * lpbi->biHeight * 3; - } - } - HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer - time, // time of this frame - 1, // number to write - (LPBYTE) lpbi + // pointer to data - lpbi->biSize + - lpbi->biClrUsed * sizeof(RGBQUAD), - ImageSize, // lpbi->biSizeImage, // size of this frame - AVIIF_KEYFRAME, // flags.... - NULL, - NULL); - if (hr != AVIERR_OK) - { - char strMsg[255]; - _snprintf(strMsg, 255, "Error: AVIStreamWrite, error %d",hr); - MessageBox(NULL, strMsg, "", MB_OK); - return FALSE; - } - - return TRUE; -} - -BOOL AVI_AddText(PAVISTREAM psText, int time, char *szText) -{ - int iLen = strlen(szText); - - HRESULT hr = AVIStreamWrite(psText, - time, - 1, - szText, - iLen + 1, - AVIIF_KEYFRAME, - NULL, - NULL); - if (hr != AVIERR_OK) - return FALSE; - - return TRUE; -} - -BOOL AVI_CloseStream(PAVISTREAM ps, PAVISTREAM psCompressed, PAVISTREAM psText) -{ - if (ps) - AVIStreamClose(ps); - - if (psCompressed) - AVIStreamClose(psCompressed); - - if (psText) - AVIStreamClose(psText); - - - - return TRUE; -} - -BOOL AVI_CloseFile(PAVIFILE pfile) -{ - if (pfile) - AVIFileClose(pfile); - - return TRUE; -} - -BOOL AVI_Exit() -{ - AVIFileExit(); - - return TRUE; -} - - - - - - - - - - - - - - - - -/* Here are the additional functions we need! */ - - -static PAVIFILE pfile = NULL; -static PAVISTREAM ps = NULL; -static PAVISTREAM psCompressed = NULL; -static int count = 0; - - -// Initialization... -bool START_AVI(const char* file_name) -{ - if(! AVI_Init()) - { - //printf("Error - AVI_Init()\n"); - return false; - } - - if(! AVI_FileOpenWrite(&pfile, file_name)) - { - //printf("Error - AVI_FileOpenWrite()\n"); - return false; - } - - return true; -} - -bool ADD_FRAME_FROM_DIB_TO_AVI(const char* _compressor, int _frameRate, int width, int height, int bits, void* pdata) -{ - if(count == 0) - { - if(! AVI_CreateStream(pfile, &ps, _frameRate, - width*height/bits, - width, - height, _compressor)) - { - //printf("Error - AVI_CreateStream()\n"); - return false; - } - - BITMAPINFOHEADER bi; - memset(&bi, 0, sizeof(bi)); - bi.biSize = sizeof(BITMAPINFOHEADER); - bi.biWidth = width; - bi.biHeight = height; - bi.biPlanes = 1; - bi.biBitCount = bits; - bi.biCompression = BI_RGB; - bi.biSizeImage = width * height * bits /8; - if(! AVI_SetOptions(&ps, &psCompressed, &bi, _compressor)) - { - return false; - } - } - - HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer - count, // time of this frame - 1, // number to write - pdata, - width*height/8, // lpbi->biSizeImage, // size of this frame - AVIIF_KEYFRAME, // flags.... - NULL, - NULL); - if (hr != AVIERR_OK) - { - char strMsg[255]; - _snprintf(strMsg, 255, "Error: AVIStreamWrite, error %d",hr); - MessageBox(NULL, strMsg, "", MB_OK); - return FALSE; - } - - count++; - return true; -} - -//Now we can add frames -// ie. ADD_FRAME_FROM_DIB_TO_AVI(yourDIB, "CVID", 25); -bool ADD_FRAME_FROM_DIB_TO_AVI(HANDLE dib, const char* _compressor, int _frameRate) -{ - LPBITMAPINFOHEADER lpbi; - if(count == 0) - { - lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib); - if(! AVI_CreateStream(pfile, &ps, _frameRate, - (unsigned long) lpbi->biSizeImage, - (int) lpbi->biWidth, - (int) lpbi->biHeight, _compressor)) - { - //printf("Error - AVI_CreateStream()\n"); - GlobalUnlock(lpbi); - return false; - } - - if(! AVI_SetOptions(&ps, &psCompressed, lpbi, _compressor)) - { - //printf("Error - AVI_SetOptions()\n"); - GlobalUnlock(lpbi); - return false; - } - - GlobalUnlock(lpbi); - } - - lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib); - if(! AVI_AddFrame(psCompressed, count * 1, lpbi)) - { - //printf("Error - AVI_AddFrame()\n"); - GlobalUnlock(lpbi); - return false; - } - - GlobalUnlock(lpbi); - count++; - return true; -} - -// The end... -bool STOP_AVI() -{ - if(! AVI_CloseStream(ps, psCompressed, NULL)) - { - //printf("Error - AVI_CloseStream()\n"); - return false; - } - - if(! AVI_CloseFile(pfile)) - { - //printf("Error - AVI_CloseFile()\n"); - return false; - } - - if(! AVI_Exit()) - { - //printf("Error - AVI_Exit()\n"); - return false; - } - - return true; -} - +#define AVIIF_KEYFRAME 0x00000010L // this frame is a key frame. + +#include +using namespace std; + +#include +#include +#include + +BOOL AVI_Init() +{ + /* first let's make sure we are running on 1.1 */ + WORD wVer = HIWORD(VideoForWindowsVersion()); + if (wVer < 0x010a){ + /* oops, we are too old, blow out of here */ + //MessageBeep(MB_ICONHAND); + MessageBox(NULL, "Cant't init AVI File - Video for Windows version is to old", "Error", MB_OK|MB_ICONSTOP); + return FALSE; + } + + AVIFileInit(); + + return TRUE; +} + +BOOL AVI_FileOpenWrite(PAVIFILE * pfile, const char *filename) +{ + HRESULT hr = AVIFileOpen(pfile, // returned file pointer + filename, // file name + OF_WRITE | OF_CREATE, // mode to open file with + NULL); // use handler determined + // from file extension.... + if (hr != AVIERR_OK) + return FALSE; + + return TRUE; +} + +DWORD getFOURCC(const char* value) +{ + if(_stricmp(value, "DIB") == 0) + { + return mmioFOURCC(value[0],value[1],value[2],' '); + } + else if((_stricmp(value, "CVID") == 0) + || (_stricmp(value, "IV32") == 0) + || (_stricmp(value, "MSVC") == 0) + || (_stricmp(value, "IV50") == 0)) + { + return mmioFOURCC(value[0],value[1],value[2],value[3]); + } + else + { + return NULL; + } +} + +// Fill in the header for the video stream.... +// The video stream will run in rate ths of a second.... +BOOL AVI_CreateStream(PAVIFILE pfile, PAVISTREAM * ps, int rate, // sample/second + unsigned long buffersize, int rectwidth, int rectheight, + const char* _compressor) +{ + AVISTREAMINFO strhdr; + memset(&strhdr, 0, sizeof(strhdr)); + strhdr.fccType = streamtypeVIDEO;// stream type + strhdr.fccHandler = getFOURCC(_compressor); + //strhdr.fccHandler = 0; // no compression! + //strhdr.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed + //strhdr.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak + //strhdr.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2 + //strhdr.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1 + //strhdr.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0 + //strhdr.dwFlags = AVISTREAMINFO_DISABLED; + //strhdr.dwCaps = + //strhdr.wPriority = + //strhdr.wLanguage = + strhdr.dwScale = 1; + strhdr.dwRate = rate; // rate fps + //strhdr.dwStart = + //strhdr.dwLength = + //strhdr.dwInitialFrames = + strhdr.dwSuggestedBufferSize = buffersize; + strhdr.dwQuality = -1; // use the default + //strhdr.dwSampleSize = + SetRect(&strhdr.rcFrame, 0, 0, // rectangle for stream + (int) rectwidth, + (int) rectheight); + //strhdr.dwEditCount = + //strhdr.dwFormatChangeCount = + //strcpy(strhdr.szName, "Full Frames (Uncompressed)"); + + // And create the stream; + HRESULT hr = AVIFileCreateStream(pfile, // file pointer + ps, // returned stream pointer + &strhdr); // stream header + if (hr != AVIERR_OK) { + return FALSE; + } + + return TRUE; +} + +string getFOURCCVAsString(DWORD value) +{ + string returnValue = ""; + if( value == 0 ) + return returnValue; + + DWORD ch0 = value & 0x000000FF; + returnValue.push_back((char) ch0); + DWORD ch1 = (value & 0x0000FF00)>>8; + returnValue.push_back((char) ch1); + DWORD ch2 = (value & 0x00FF0000)>>16; + returnValue.push_back((char) ch2); + DWORD ch3 = (value & 0xFF000000)>>24; + returnValue.push_back((char) ch3); + + return returnValue; +} + +string dumpAVICOMPRESSOPTIONS(AVICOMPRESSOPTIONS opts) +{ + char tmp[255]; + string returnValue = "Dump of AVICOMPRESSOPTIONS\n"; + + returnValue += "DWORD fccType = streamtype("; returnValue += getFOURCCVAsString(opts.fccType); returnValue += ")\n"; + returnValue += "DWORD fccHandler = "; returnValue += getFOURCCVAsString(opts.fccHandler); returnValue += "\n"; + + _snprintf(tmp, 255, "DWORD dwKeyFrameEvery = %d\n", opts.dwKeyFrameEvery); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD dwQuality = %d\n", opts.dwQuality); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD dwBytesPerSecond = %d\n", opts.dwBytesPerSecond); + returnValue += tmp; + + if((opts.dwFlags & AVICOMPRESSF_DATARATE) == AVICOMPRESSF_DATARATE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_DATARATE\n");} + else if((opts.dwFlags & AVICOMPRESSF_INTERLEAVE) == AVICOMPRESSF_INTERLEAVE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_INTERLEAVE\n");} + else if((opts.dwFlags & AVICOMPRESSF_KEYFRAMES) == AVICOMPRESSF_KEYFRAMES){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_KEYFRAMES\n");} + else if((opts.dwFlags & AVICOMPRESSF_VALID) == AVICOMPRESSF_VALID){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_VALID\n");} + else {_snprintf(tmp, 255, "DWORD dwFlags = Unknown(%d)\n", opts.dwFlags);} + returnValue += tmp; + + _snprintf(tmp, 255, "LPVOID lpFormat = %d\n", opts.lpFormat); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD cbFormat = %d\n", opts.cbFormat); + returnValue += tmp; + + _snprintf(tmp, 255, "LPVOID lpParms = %d\n", opts.lpParms); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD cbParms = %d\n", opts.cbParms); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD dwInterleaveEvery = %d\n", opts.dwInterleaveEvery); + returnValue += tmp; + + return returnValue; +} + +BOOL AVI_SetOptions(PAVISTREAM * ps, PAVISTREAM * psCompressed, LPBITMAPINFOHEADER lpbi, + const char* _compressor) +{ + + AVICOMPRESSOPTIONS opts; + AVICOMPRESSOPTIONS FAR * aopts[1] = {&opts}; + + memset(&opts, 0, sizeof(opts)); + opts.fccType = streamtypeVIDEO; + opts.fccHandler = getFOURCC(_compressor); + //opts.fccHandler = 0; + //opts.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed + //opts.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak + //opts.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2 + //opts.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1 + //opts.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0 + //opts.dwKeyFrameEvery = 5; + //opts.dwQuality + //opts.dwBytesPerSecond + //opts.dwFlags = AVICOMPRESSF_KEYFRAMES; + //opts.lpFormat + //opts.cbFormat + //opts.lpParms + //opts.cbParms + //opts.dwInterleaveEvery + + /* display the compression options dialog box if specified compressor is unknown */ + if(getFOURCC(_compressor) == NULL) + { + if (!AVISaveOptions(NULL, 0, 1, ps, (LPAVICOMPRESSOPTIONS FAR *) &aopts)) + { + return FALSE; + } + + //printf("%s", dumpAVICOMPRESSOPTIONS(opts)); + //MessageBox(NULL, dumpAVICOMPRESSOPTIONS(opts).c_str(), "AVICOMPRESSOPTIONS", MB_OK); + } + + HRESULT hr = AVIMakeCompressedStream(psCompressed, *ps, &opts, NULL); + if (hr != AVIERR_OK) { + return FALSE; + } + + hr = AVIStreamSetFormat(*psCompressed, 0, + lpbi, // stream format + lpbi->biSize // format size + + lpbi->biClrUsed * sizeof(RGBQUAD) + ); + if (hr != AVIERR_OK) { + return FALSE; + } + + return TRUE; +} + +BOOL AVI_SetText(PAVIFILE pfile, PAVISTREAM psText, char *szText, int width, int height, int TextHeight) +{ + // Fill in the stream header for the text stream.... + AVISTREAMINFO strhdr; + DWORD dwTextFormat; + // The text stream is in 60ths of a second.... + + memset(&strhdr, 0, sizeof(strhdr)); + strhdr.fccType = streamtypeTEXT; + strhdr.fccHandler = mmioFOURCC('D', 'R', 'A', 'W'); + strhdr.dwScale = 1; + strhdr.dwRate = 60; + strhdr.dwSuggestedBufferSize = sizeof(szText); + SetRect(&strhdr.rcFrame, 0, (int) height, + (int) width, (int) height + TextHeight); // #define TEXT_HEIGHT 20 + + // ....and create the stream. + HRESULT hr = AVIFileCreateStream(pfile, &psText, &strhdr); + if (hr != AVIERR_OK) { + return FALSE; + } + + dwTextFormat = sizeof(dwTextFormat); + hr = AVIStreamSetFormat(psText, 0, &dwTextFormat, sizeof(dwTextFormat)); + if (hr != AVIERR_OK) { + return FALSE; + } + + return TRUE; +} + +BOOL AVI_AddFrame(PAVISTREAM psCompressed, int time, LPBITMAPINFOHEADER lpbi) +{ + int ImageSize = lpbi->biSizeImage; + if (ImageSize == 0) + { + if (lpbi->biBitCount == 24) + { + ImageSize = lpbi->biWidth * lpbi->biHeight * 3; + } + } + HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer + time, // time of this frame + 1, // number to write + (LPBYTE) lpbi + // pointer to data + lpbi->biSize + + lpbi->biClrUsed * sizeof(RGBQUAD), + ImageSize, // lpbi->biSizeImage, // size of this frame + AVIIF_KEYFRAME, // flags.... + NULL, + NULL); + if (hr != AVIERR_OK) + { + char strMsg[255]; + _snprintf(strMsg, 255, "Error: AVIStreamWrite, error %d",hr); + MessageBox(NULL, strMsg, "", MB_OK); + return FALSE; + } + + return TRUE; +} + +BOOL AVI_AddText(PAVISTREAM psText, int time, char *szText) +{ + int iLen = strlen(szText); + + HRESULT hr = AVIStreamWrite(psText, + time, + 1, + szText, + iLen + 1, + AVIIF_KEYFRAME, + NULL, + NULL); + if (hr != AVIERR_OK) + return FALSE; + + return TRUE; +} + +BOOL AVI_CloseStream(PAVISTREAM ps, PAVISTREAM psCompressed, PAVISTREAM psText) +{ + if (ps) + AVIStreamClose(ps); + + if (psCompressed) + AVIStreamClose(psCompressed); + + if (psText) + AVIStreamClose(psText); + + + + return TRUE; +} + +BOOL AVI_CloseFile(PAVIFILE pfile) +{ + if (pfile) + AVIFileClose(pfile); + + return TRUE; +} + +BOOL AVI_Exit() +{ + AVIFileExit(); + + return TRUE; +} + + + + + + + + + + + + + + + + +/* Here are the additional functions we need! */ + + +static PAVIFILE pfile = NULL; +static PAVISTREAM ps = NULL; +static PAVISTREAM psCompressed = NULL; +static int count = 0; + + +// Initialization... +bool START_AVI(const char* file_name) +{ + if(! AVI_Init()) + { + //printf("Error - AVI_Init()\n"); + return false; + } + + if(! AVI_FileOpenWrite(&pfile, file_name)) + { + //printf("Error - AVI_FileOpenWrite()\n"); + return false; + } + + return true; +} + +bool ADD_FRAME_FROM_DIB_TO_AVI(const char* _compressor, int _frameRate, int width, int height, int bits, void* pdata) +{ + if(count == 0) + { + if(! AVI_CreateStream(pfile, &ps, _frameRate, + width*height/bits, + width, + height, _compressor)) + { + //printf("Error - AVI_CreateStream()\n"); + return false; + } + + BITMAPINFOHEADER bi; + memset(&bi, 0, sizeof(bi)); + bi.biSize = sizeof(BITMAPINFOHEADER); + bi.biWidth = width; + bi.biHeight = height; + bi.biPlanes = 1; + bi.biBitCount = bits; + bi.biCompression = BI_RGB; + bi.biSizeImage = width * height * bits /8; + if(! AVI_SetOptions(&ps, &psCompressed, &bi, _compressor)) + { + return false; + } + } + + HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer + count, // time of this frame + 1, // number to write + pdata, + width*height/8, // lpbi->biSizeImage, // size of this frame + AVIIF_KEYFRAME, // flags.... + NULL, + NULL); + if (hr != AVIERR_OK) + { + char strMsg[255]; + _snprintf(strMsg, 255, "Error: AVIStreamWrite, error %d",hr); + MessageBox(NULL, strMsg, "", MB_OK); + return FALSE; + } + + count++; + return true; +} + +//Now we can add frames +// ie. ADD_FRAME_FROM_DIB_TO_AVI(yourDIB, "CVID", 25); +bool ADD_FRAME_FROM_DIB_TO_AVI(HANDLE dib, const char* _compressor, int _frameRate) +{ + LPBITMAPINFOHEADER lpbi; + if(count == 0) + { + lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib); + if(! AVI_CreateStream(pfile, &ps, _frameRate, + (unsigned long) lpbi->biSizeImage, + (int) lpbi->biWidth, + (int) lpbi->biHeight, _compressor)) + { + //printf("Error - AVI_CreateStream()\n"); + GlobalUnlock(lpbi); + return false; + } + + if(! AVI_SetOptions(&ps, &psCompressed, lpbi, _compressor)) + { + //printf("Error - AVI_SetOptions()\n"); + GlobalUnlock(lpbi); + return false; + } + + GlobalUnlock(lpbi); + } + + lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib); + if(! AVI_AddFrame(psCompressed, count * 1, lpbi)) + { + //printf("Error - AVI_AddFrame()\n"); + GlobalUnlock(lpbi); + return false; + } + + GlobalUnlock(lpbi); + count++; + return true; +} + +// The end... +bool STOP_AVI() +{ + if(! AVI_CloseStream(ps, psCompressed, NULL)) + { + //printf("Error - AVI_CloseStream()\n"); + return false; + } + + if(! AVI_CloseFile(pfile)) + { + //printf("Error - AVI_CloseFile()\n"); + return false; + } + + if(! AVI_Exit()) + { + //printf("Error - AVI_Exit()\n"); + return false; + } + + return true; +} + diff --git a/plugins/zerogs/dx/Win32/resource.h b/plugins/zerogs/dx/Win32/resource.h index 053ec92e01..13bbdd0ce2 100644 --- a/plugins/zerogs/dx/Win32/resource.h +++ b/plugins/zerogs/dx/Win32/resource.h @@ -1,45 +1,45 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by GSsoftdx.rc -// -#define IDD_CONFIG 101 -#define IDD_ABOUT 102 -#define IDD_LOGGING 106 -#define IDB_ZEROGSLOGO 108 -#define IDR_REALPS2_FX 109 -#define IDR_SHADERS 110 -#define IDC_CHECK1 1000 -#define IDC_FULLSCREEN 1000 -#define IDC_NAME 1000 -#define IDC_LOG 1000 -#define IDC_CHECK2 1001 -#define IDC_FPSCOUNT 1001 -#define IDC_CHECK5 1002 -#define IDC_FRAMESKIP 1002 -#define IDC_STRETCH 1003 -#define IDC_LOGGING 1004 -#define IDC_COMBO1 1005 -#define IDC_CACHE 1005 -#define IDC_CACHESIZE 1006 -#define IDC_CHECK3 1007 -#define IDC_RECORD 1007 -#define IDC_COMBO2 1008 -#define IDC_DSPRES 1008 -#define IDC_WRES 1008 -#define IDC_COMBO3 1009 -#define IDC_DDDRV 1009 -#define IDC_FRES 1009 -#define IDC_COMBO4 1012 -#define IDC_CODEC 1012 -#define IDC_FILTERS 1014 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 112 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1015 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by GSsoftdx.rc +// +#define IDD_CONFIG 101 +#define IDD_ABOUT 102 +#define IDD_LOGGING 106 +#define IDB_ZEROGSLOGO 108 +#define IDR_REALPS2_FX 109 +#define IDR_SHADERS 110 +#define IDC_CHECK1 1000 +#define IDC_FULLSCREEN 1000 +#define IDC_NAME 1000 +#define IDC_LOG 1000 +#define IDC_CHECK2 1001 +#define IDC_FPSCOUNT 1001 +#define IDC_CHECK5 1002 +#define IDC_FRAMESKIP 1002 +#define IDC_STRETCH 1003 +#define IDC_LOGGING 1004 +#define IDC_COMBO1 1005 +#define IDC_CACHE 1005 +#define IDC_CACHESIZE 1006 +#define IDC_CHECK3 1007 +#define IDC_RECORD 1007 +#define IDC_COMBO2 1008 +#define IDC_DSPRES 1008 +#define IDC_WRES 1008 +#define IDC_COMBO3 1009 +#define IDC_DDDRV 1009 +#define IDC_FRES 1009 +#define IDC_COMBO4 1012 +#define IDC_CODEC 1012 +#define IDC_FILTERS 1014 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 112 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1015 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/zerogs/dx/Win32/resrc1.h b/plugins/zerogs/dx/Win32/resrc1.h index 1bb1070cb2..1c68bfd57a 100644 --- a/plugins/zerogs/dx/Win32/resrc1.h +++ b/plugins/zerogs/dx/Win32/resrc1.h @@ -1,87 +1,87 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by zerogs.rc -// -#define IDC_CONF_DEFAULT 3 -#define IDR_DATA1 112 -#define IDC_ABOUTTEXT 1015 -#define IDC_CONFIG_AA 1016 -#define IDC_CONFIG_INTERLACE 1017 -#define IDC_CONFIG_AA3 1018 -#define IDC_CONFIG_CAPTUREAVI 1018 -#define IDC_CONFIG_CAPTUREAVI2 1019 -#define IDC_CONFIG_FULLSCREEN 1019 -#define IDC_CONFIG_FULLSCREEN2 1020 -#define IDC_CONFIG_FFX 1020 -#define IDC_CONFIG_WIDESCREEN 1020 -#define IDC_CONFIG_INTERLACE2 1021 -#define IDC_CONFIG_DEPTHWRITE 1021 -#define IDC_CONFIG_FFX2 1021 -#define IDC_CONFIG_BMPSS 1021 -#define IDC_RADIO3 1024 -#define IDC_CONFIG_INTERLACE3 1025 -#define IDC_CONFIG_BILINEAR 1025 -#define IDC_CONF_WIN640 1026 -#define IDC_CONF_WIN800 1027 -#define IDC_CONF_WIN1024 1028 -#define IDC_CONF_WIN1280 1029 -#define IDC_CONF_WIN960W 1030 -#define IDC_CONF_WIN1280W 1031 -#define IDC_CONF_WIN1920W 1032 -#define IDC_CONFOPT_00002000 1033 -#define IDC_CONFIG_CAPTUREAVI3 1034 -#define IDC_CONFIG_WIREFRAME 1034 -#define IDC_CONFOPT_00001000 1035 -#define IDC_CONFIG_CAPTUREAVI4 1036 -#define IDC_CONFIG_CACHEFBP 1036 -#define IDC_CONFIG_SHOWFPS 1036 -#define IDC_CONFOPT_00100000 1036 -#define IDC_CONFOPT_00000200 1037 -#define IDC_CONFOPT_00000080 1038 -#define IDC_CONFOPT_201 1039 -#define IDC_CONFOPT_00000040 1039 -#define IDC_CONFOPT_00000020 1040 -#define IDC_CONFOPT_00080000 1041 -#define IDC_CONF_WIN1283 1041 -#define IDC_CONFOPT_00000001 1042 -#define IDC_CONFOPT_00000004 1044 -#define IDC_CONFOPT_IDS 1045 -#define IDC_CONFOPT_00200000 1046 -#define IDC_CONFOPT_00004000 1047 -#define IDC_BUTTON1 1048 -#define IDC_CONFOPT_COMPUTEOR 1048 -#define IDC_CONFOPT_4001 1049 -#define IDC_CONFOPT_00000010 1049 -#define IDC_CONFOPT_00008000 1050 -#define IDC_CONFOPT_00010000 1052 -#define IDC_CONFOPT_00020000 1054 -#define IDC_CONFOPT_00000002 1055 -#define IDC_CONFOPT_20001 1056 -#define IDC_CONFOPT_01000000 1056 -#define IDC_CONFOPT_16961 1057 -#define IDC_CONFOPT_08000000 1057 -#define IDC_CONFOPT_00000008 1058 -#define IDC_CONFOPT_00000400 1060 -#define IDC_CONFOPT_00000800 1061 -#define IDC_CONFOPT_NOALPHABLEND30 1062 -#define IDC_CONFOPT_00040000 1063 -#define IDC_CONFOPT_40001 1064 -#define IDC_CONFOPT_02000000 1064 -#define IDC_CONFOPT_33921 1065 -#define IDC_CONFOPT_04000000 1065 -#define IDC_CONFIG_AANONE 2000 -#define IDC_CONFIG_AA2 2001 -#define IDC_CONFIG_AA4 2002 -#define IDC_CONFIG_AA8 2003 -#define IDC_CONFIG_AA16 2004 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 113 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1052 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by zerogs.rc +// +#define IDC_CONF_DEFAULT 3 +#define IDR_DATA1 112 +#define IDC_ABOUTTEXT 1015 +#define IDC_CONFIG_AA 1016 +#define IDC_CONFIG_INTERLACE 1017 +#define IDC_CONFIG_AA3 1018 +#define IDC_CONFIG_CAPTUREAVI 1018 +#define IDC_CONFIG_CAPTUREAVI2 1019 +#define IDC_CONFIG_FULLSCREEN 1019 +#define IDC_CONFIG_FULLSCREEN2 1020 +#define IDC_CONFIG_FFX 1020 +#define IDC_CONFIG_WIDESCREEN 1020 +#define IDC_CONFIG_INTERLACE2 1021 +#define IDC_CONFIG_DEPTHWRITE 1021 +#define IDC_CONFIG_FFX2 1021 +#define IDC_CONFIG_BMPSS 1021 +#define IDC_RADIO3 1024 +#define IDC_CONFIG_INTERLACE3 1025 +#define IDC_CONFIG_BILINEAR 1025 +#define IDC_CONF_WIN640 1026 +#define IDC_CONF_WIN800 1027 +#define IDC_CONF_WIN1024 1028 +#define IDC_CONF_WIN1280 1029 +#define IDC_CONF_WIN960W 1030 +#define IDC_CONF_WIN1280W 1031 +#define IDC_CONF_WIN1920W 1032 +#define IDC_CONFOPT_00002000 1033 +#define IDC_CONFIG_CAPTUREAVI3 1034 +#define IDC_CONFIG_WIREFRAME 1034 +#define IDC_CONFOPT_00001000 1035 +#define IDC_CONFIG_CAPTUREAVI4 1036 +#define IDC_CONFIG_CACHEFBP 1036 +#define IDC_CONFIG_SHOWFPS 1036 +#define IDC_CONFOPT_00100000 1036 +#define IDC_CONFOPT_00000200 1037 +#define IDC_CONFOPT_00000080 1038 +#define IDC_CONFOPT_201 1039 +#define IDC_CONFOPT_00000040 1039 +#define IDC_CONFOPT_00000020 1040 +#define IDC_CONFOPT_00080000 1041 +#define IDC_CONF_WIN1283 1041 +#define IDC_CONFOPT_00000001 1042 +#define IDC_CONFOPT_00000004 1044 +#define IDC_CONFOPT_IDS 1045 +#define IDC_CONFOPT_00200000 1046 +#define IDC_CONFOPT_00004000 1047 +#define IDC_BUTTON1 1048 +#define IDC_CONFOPT_COMPUTEOR 1048 +#define IDC_CONFOPT_4001 1049 +#define IDC_CONFOPT_00000010 1049 +#define IDC_CONFOPT_00008000 1050 +#define IDC_CONFOPT_00010000 1052 +#define IDC_CONFOPT_00020000 1054 +#define IDC_CONFOPT_00000002 1055 +#define IDC_CONFOPT_20001 1056 +#define IDC_CONFOPT_01000000 1056 +#define IDC_CONFOPT_16961 1057 +#define IDC_CONFOPT_08000000 1057 +#define IDC_CONFOPT_00000008 1058 +#define IDC_CONFOPT_00000400 1060 +#define IDC_CONFOPT_00000800 1061 +#define IDC_CONFOPT_NOALPHABLEND30 1062 +#define IDC_CONFOPT_00040000 1063 +#define IDC_CONFOPT_40001 1064 +#define IDC_CONFOPT_02000000 1064 +#define IDC_CONFOPT_33921 1065 +#define IDC_CONFOPT_04000000 1065 +#define IDC_CONFIG_AANONE 2000 +#define IDC_CONFIG_AA2 2001 +#define IDC_CONFIG_AA4 2002 +#define IDC_CONFIG_AA8 2003 +#define IDC_CONFIG_AA16 2004 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 113 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1052 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/zerogs/dx/Win32/vsprops/svnrev_template.h b/plugins/zerogs/dx/Win32/vsprops/svnrev_template.h index afab6c4fd1..f2656ef1e8 100644 --- a/plugins/zerogs/dx/Win32/vsprops/svnrev_template.h +++ b/plugins/zerogs/dx/Win32/vsprops/svnrev_template.h @@ -1,18 +1,18 @@ -// svnrev_template.h --> svnrev.h -// -// This file acts as a template for the automatic SVN revision/version tag. -// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for -// whichever project is being compiled (as indicated by command line options -// passed to SubWCRev.exe during the project's pre-build step). -// -// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs -// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN -// installed on your system. If you do not have it installed, a generic template -// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not -// necessary. If you do not have it installed, everything will still compile -// fine except without the SVN revision tagged to the application/dll version. -// -// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org - -#define SVN_REV $WCREV$ +// svnrev_template.h --> svnrev.h +// +// This file acts as a template for the automatic SVN revision/version tag. +// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for +// whichever project is being compiled (as indicated by command line options +// passed to SubWCRev.exe during the project's pre-build step). +// +// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs +// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN +// installed on your system. If you do not have it installed, a generic template +// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not +// necessary. If you do not have it installed, everything will still compile +// fine except without the SVN revision tagged to the application/dll version. +// +// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV $WCREV$ #define SVN_MODS $WCMODS?1:0$ \ No newline at end of file diff --git a/plugins/zerogs/dx/Win32/vsprops/svnrev_unknown.h b/plugins/zerogs/dx/Win32/vsprops/svnrev_unknown.h index a2a3703186..4872e23b20 100644 --- a/plugins/zerogs/dx/Win32/vsprops/svnrev_unknown.h +++ b/plugins/zerogs/dx/Win32/vsprops/svnrev_unknown.h @@ -1,23 +1,23 @@ -// svnrev_genric.h --> svnrev.h -// -// This file acts as a placebo for people who do not have TortoiseSVN installed. -// It provides "empty" revision information to the Pcsx2 Playground projects in -// the absence of real revisions derived from the repository being built. -// -// This file does not affect application/dll builds in any significant manner, -// other than the lack of automatic revision tags inserted into the app (which -// is very convenient but hardly necessary). -// -// See svn_template.h for more information on how the process of revision -// templating works. -// -// If you would like to enable automatic revisin tagging, TortoiseSVN can be -// downloaded from http://tortoisesvn.tigris.org - -#define SVN_REV_UNKNOWN - -// The following defines are included so that code will still compile even if it -// doesn't check for the SVN_REV_UNKNOWN define. - -#define SVN_REV 0 +// svnrev_genric.h --> svnrev.h +// +// This file acts as a placebo for people who do not have TortoiseSVN installed. +// It provides "empty" revision information to the Pcsx2 Playground projects in +// the absence of real revisions derived from the repository being built. +// +// This file does not affect application/dll builds in any significant manner, +// other than the lack of automatic revision tags inserted into the app (which +// is very convenient but hardly necessary). +// +// See svn_template.h for more information on how the process of revision +// templating works. +// +// If you would like to enable automatic revisin tagging, TortoiseSVN can be +// downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV_UNKNOWN + +// The following defines are included so that code will still compile even if it +// doesn't check for the SVN_REV_UNKNOWN define. + +#define SVN_REV 0 #define SVN_MODS "" \ No newline at end of file diff --git a/plugins/zerogs/dx/ZeroGSShaders/zerogsshaders.cpp b/plugins/zerogs/dx/ZeroGSShaders/zerogsshaders.cpp index 99a631081f..0601ef271a 100644 --- a/plugins/zerogs/dx/ZeroGSShaders/zerogsshaders.cpp +++ b/plugins/zerogs/dx/ZeroGSShaders/zerogsshaders.cpp @@ -1,407 +1,407 @@ -// Builds all possible shader files from ps2hw.fx and stores them in -// a preprocessed database -#include - -#include -#include -#include - -#define SAFE_RELEASE(x) { if( (x) != NULL ) { (x)->Release(); x = NULL; } } - -#include -#include - -using namespace std; - -#include "zerogsshaders.h" - -char* srcfilename = "ps2hw.fx"; -char* dstfilename = "ps2hw.dat"; -DWORD dwFlags = 0; - -#ifndef ARRAYSIZE -#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0])) -#endif - -struct SHADERINFO -{ - DWORD type; // 1 - ps, 0 - vs - LPD3DXBUFFER pbuf; -}; - -map mapShaders; - -class ZeroGSShaderInclude : public ID3DXInclude -{ -public: - int context; - int ps2x; // if 0, ps20 only - char* pEffectDir; - - STDMETHOD(Open)(D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes) - { - const char* pfilename = pFileName; - char strfile[255]; - if( strstr(pFileName, "ps2hw_ctx") != NULL ) { - - _snprintf(strfile, 255, "%sps2hw_ctx%d.fx", pEffectDir, context); - pfilename = strfile; - } -// else if( strstr(pFileName, "ps2hw_ps2x") != NULL ) { -// _snprintf(strfile, 255, "%sps2hw_ps2%c.fx", pEffectDir, ps2x?'x':'0'); -// pfilename = strfile; -// } - else if( strstr(pFileName, "ps2hw.fx") != NULL ) { - _snprintf(strfile, 255, "%s%s", pEffectDir, pFileName); - pfilename = strfile; - } - - FILE* f = fopen(pfilename, "rb"); - - if( f == NULL ) - return E_FAIL; - - fseek(f, 0, SEEK_END); - DWORD size = ftell(f); - fseek(f, 0, SEEK_SET); - char* buffer = new char[size+1]; - fread(buffer, size, 1, f); - buffer[size] = 0; - - *ppData = buffer; - *pBytes = size; - fclose(f); - - return S_OK; - } - - STDMETHOD(Close)(LPCVOID pData) - { - delete[] (char*)pData; - return S_OK; - } -}; - -void LoadShader(int index, const char* name, const char* pshader, D3DXMACRO* pmacros, ID3DXInclude* pInclude) -{ - LPD3DXBUFFER pShader = NULL, pError = NULL; - - HRESULT hr = D3DXCompileShaderFromFile(srcfilename, pmacros, pInclude, name, pshader, dwFlags, &pShader, &pError, NULL); - - if( FAILED(hr) ) - { - printf("Failed to load %s\n%s\n", name, pError->GetBufferPointer()); - SAFE_RELEASE(pShader); - SAFE_RELEASE(pError); - return; - } - - SAFE_RELEASE(pError); - - if( mapShaders.find(index) != mapShaders.end() ) { - printf("two shaders share the same index %d\n", index); - exit(0); - } - - SHADERINFO info; - info.type = name[0] == 'p' ? 0x80000000 : 0; - info.pbuf = pShader; - mapShaders[index] = info; -} - -int main(int argc, char** argv) -{ - printf("usage: [src] [dst] [opts]\n"); - - if( argc >= 2 ) srcfilename = argv[1]; - if( argc >= 3 ) dstfilename = argv[2]; - if( argc >= 4 ) { - dwFlags = atoi(argv[3]); - } - - FILE* fsrc = fopen(srcfilename, "r"); - if( fsrc == NULL ) { - printf("cannot open %s\n", srcfilename); - return 0; - } - fclose(fsrc); - - LoadShader(SH_BITBLTVS, "BitBltVS", "vs_2_0", NULL, NULL); - LoadShader(SH_BITBLTVS|SH_30, "BitBltVS", "vs_3_0", NULL, NULL); - LoadShader(SH_BITBLTPS, "BitBltPS", "ps_2_0", NULL, NULL); - LoadShader(SH_BITBLTDEPTHPS, "BitBltDepthPS", "ps_2_0", NULL, NULL); - LoadShader(SH_BITBLTDEPTHMRTPS, "BitBltDepthMRTPS", "ps_2_0", NULL, NULL); - LoadShader(SH_BITBLTDEPTHTEXPS, "BitBltDepthTexPS", "ps_2_0", NULL, NULL); - LoadShader(SH_BITBLTDEPTHTEXMRTPS, "BitBltDepthTexMRTPS", "ps_2_0", NULL, NULL); - LoadShader(SH_CRTCTARGPS, "CRTCTargPS", "ps_2_0", NULL, NULL); - LoadShader(SH_CRTCPS, "CRTCPS", "ps_2_0", NULL, NULL); - LoadShader(SH_CRTC24PS, "CRTC24PS", "ps_2_0", NULL, NULL); - LoadShader(SH_ZEROPS, "ZeroPS", "ps_2_0", NULL, NULL); - LoadShader(SH_ZEROPS|SH_30, "ZeroPS", "ps_3_0", NULL, NULL); - LoadShader(SH_BASETEXTUREPS, "BaseTexturePS", "ps_2_0", NULL, NULL); - LoadShader(SH_BITBLTAAPS, "BitBltPS", "ps_2_0", NULL, NULL); - LoadShader(SH_CRTCTARGINTERPS, "CRTCTargInterPS", "ps_2_0", NULL, NULL); - LoadShader(SH_CRTCINTERPS, "CRTCInterPS", "ps_2_0", NULL, NULL); - LoadShader(SH_CRTC24INTERPS, "CRTC24InterPS", "ps_2_0", NULL, NULL); - LoadShader(SH_CONVERT16TO32PS, "Convert16to32PS", "ps_2_0", NULL, NULL); - LoadShader(SH_CONVERT32TO16PS, "Convert32to16PS", "ps_2_0", NULL, NULL); - - const int vsshaders[4] = { SH_REGULARVS, SH_TEXTUREVS, SH_REGULARFOGVS, SH_TEXTUREFOGVS }; - const char* pvsshaders[4] = { "RegularVS", "TextureVS", "RegularFogVS", "TextureFogVS" }; - - // load the texture shaders - char str[255], strdir[255]; - - strcpy(strdir, srcfilename); - int i = (int)strlen(strdir); - while(i > 0) { - if( strdir[i-1] == '/' || strdir[i-1] == '\\' ) - break; - --i; - } - - strdir[i] = 0; - - ZeroGSShaderInclude inc; - inc.pEffectDir = strdir; - - D3DXMACRO macros[10]; - memset(macros, 0, sizeof(macros)); - - macros[0].Name = "WRITE_DEPTH"; - macros[0].Definition = "1"; - - for(i = 0; i < ARRAYSIZE(vsshaders); ++i) { - for(int vs30 = 0; vs30 < 2; ++vs30 ) { - for(int writedepth = 0; writedepth < 2; ++writedepth ) { - inc.context = 0; - LoadShader(vsshaders[i]|(vs30?SH_30:0)|(writedepth?SH_WRITEDEPTH:0), pvsshaders[i], vs30 ? "vs_3_0" : "vs_2_0", writedepth ? macros : NULL, &inc); - inc.context = 1; - LoadShader(vsshaders[i]|(vs30?SH_30:0)|(writedepth?SH_WRITEDEPTH:0)|SH_CONTEXT1, pvsshaders[i], vs30 ? "vs_3_0" : "vs_2_0", writedepth ? macros : NULL, &inc); - } - } - } - - const int psshaders[2] = { SH_REGULARPS, SH_REGULARFOGPS }; - const char* ppsshaders[2] = { "RegularPS", "RegularFogPS" }; - - for(i = 0; i < ARRAYSIZE(psshaders); ++i) { - for(int ps30 = 0; ps30 < 2; ++ps30 ) { - for(int writedepth = 0; writedepth < 2; ++writedepth ) { - LoadShader(psshaders[i]|(ps30?SH_30:0)|(writedepth?SH_WRITEDEPTH:0), ppsshaders[i], ps30 ? "ps_3_0" : "ps_2_0", writedepth ? macros : NULL, NULL); - } - } - } - - printf("creating shaders, note that ps2hw_ctx0.fx, and ps2hw_ctx1.fx are required\n"); - - for(int texwrap = 0; texwrap < NUM_TEXWRAPS; ++texwrap ) { - - int macroindex = 0; - memset(macros, 0, sizeof(macros)); - - if( g_pPsTexWrap[texwrap] != NULL ) { - macros[0].Name = g_pPsTexWrap[texwrap]; - macros[0].Definition = "1"; - macroindex++; - } - - for(int context = 0; context < 2; ++context) { - inc.context = context; - - for(int texfilter = 0; texfilter < NUM_FILTERS; ++texfilter) { - for(int fog = 0; fog < 2; ++fog ) { - for(int writedepth = 0; writedepth < 2; ++writedepth ) { - - if( writedepth ) { - macros[macroindex].Name = "WRITE_DEPTH"; - macros[macroindex].Definition = "1"; - macroindex++; - } - else { - macros[macroindex].Name = NULL; - macros[macroindex].Definition = NULL; - } - - for(int testaem = 0; testaem < 2; ++testaem ) { - - if( testaem ) { - macros[macroindex].Name = "TEST_AEM"; - macros[macroindex].Definition = "1"; - macroindex++; - } - else { - macros[macroindex].Name = NULL; - macros[macroindex].Definition = NULL; - } - - for(int exactcolor = 0; exactcolor < 2; ++exactcolor ) { - - if( exactcolor ) { - macros[macroindex].Name = "EXACT_COLOR"; - macros[macroindex].Definition = "1"; - macroindex++; - } - else { - macros[macroindex].Name = NULL; - macros[macroindex].Definition = NULL; - } - - // 32 - sprintf(str, "Texture%s%d_32PS", fog?"Fog":"", texfilter); - inc.ps2x = 0; - - if( macros[macroindex].Name != NULL ) - printf("error[%d] %s: %d %d %d %d!\n", macroindex, macros[macroindex].Name, texfilter, fog, writedepth, testaem); - - macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; - macros[macroindex].Definition = "1"; - - if( texfilter == 0 && exactcolor == 0 ) { - LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20), str, g_pShaders[SHADER_20], macros, &inc); - } - - inc.ps2x = 1; - LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); - - macros[macroindex].Name = NULL; - macros[macroindex].Definition = NULL; - - LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); - LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); - - if( texfilter == 0 ) { - // tex32 - sprintf(str, "Texture%s%d_tex32PS", fog?"Fog":"", texfilter); - inc.ps2x = 0; - - macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; - macros[macroindex].Definition = "1"; - - if( texfilter == 0 && exactcolor == 0 ) { - LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20), str, g_pShaders[SHADER_20], macros, &inc); - } - - inc.ps2x = 1; - - LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); - - macros[macroindex].Name = NULL; - macros[macroindex].Definition = NULL; - - LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); - LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); - - // clut32 - sprintf(str, "Texture%s%d_clut32PS", fog?"Fog":"", texfilter); - inc.ps2x = 0; - - macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; - macros[macroindex].Definition = "1"; - - if( texfilter == 0 && exactcolor == 0 ) { - LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20), str, g_pShaders[SHADER_20], macros, &inc); - } - - inc.ps2x = 1; - - LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); - - macros[macroindex].Name = NULL; - macros[macroindex].Definition = NULL; - - LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); - LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); - - // tex32to16 - sprintf(str, "Texture%s%d_tex32to16PS", fog?"Fog":"", texfilter); - inc.ps2x = 0; - - macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; - macros[macroindex].Definition = "1"; - - if( texfilter == 0 && exactcolor == 0 ) { - LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20), str, g_pShaders[SHADER_20], macros, &inc); - } - - inc.ps2x = 1; - - LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); - - macros[macroindex].Name = NULL; - macros[macroindex].Definition = NULL; - - LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); - LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); - - // tex16to8h - sprintf(str, "Texture%s%d_tex16to8hPS", fog?"Fog":"", texfilter); - inc.ps2x = 0; - - macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; - macros[macroindex].Definition = "1"; - - inc.ps2x = 1; - - LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); - - macros[macroindex].Name = NULL; - macros[macroindex].Definition = NULL; - - LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); - LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); - } - } - - --macroindex; - macros[macroindex].Name = NULL; - macros[macroindex].Definition = NULL; - } - - --macroindex; - macros[macroindex].Name = NULL; - macros[macroindex].Definition = NULL; - } - - --macroindex; - macros[macroindex].Name = NULL; - macros[macroindex].Definition = NULL; - } - } - } - } - - // create the database - FILE* fdst = fopen(dstfilename, "wb"); - if( fdst == NULL ) { - printf("failed to open %s\n", dstfilename); - return 0; - } - - DWORD num = (DWORD)mapShaders.size(); - fwrite(&num, 4, 1, fdst); - - i = 0; - DWORD totaloffset = 4+sizeof(SHADERHEADER)*num; - for(map::iterator it = mapShaders.begin(); it != mapShaders.end(); ++it, ++i) { - SHADERHEADER h; - h.index = it->first | it->second.type; - h.offset = totaloffset; - h.size = it->second.pbuf->GetBufferSize(); - - fseek(fdst, 4+i*sizeof(SHADERHEADER), SEEK_SET); - fwrite(&h, sizeof(SHADERHEADER), 1, fdst); - - fseek(fdst, totaloffset, SEEK_SET); - fwrite(it->second.pbuf->GetBufferPointer(), it->second.pbuf->GetBufferSize(), 1, fdst); - - totaloffset += it->second.pbuf->GetBufferSize(); - it->second.pbuf->Release(); - } - - fclose(fdst); - - printf("wrote %s\n", dstfilename); - - return 0; -} +// Builds all possible shader files from ps2hw.fx and stores them in +// a preprocessed database +#include + +#include +#include +#include + +#define SAFE_RELEASE(x) { if( (x) != NULL ) { (x)->Release(); x = NULL; } } + +#include +#include + +using namespace std; + +#include "zerogsshaders.h" + +char* srcfilename = "ps2hw.fx"; +char* dstfilename = "ps2hw.dat"; +DWORD dwFlags = 0; + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +struct SHADERINFO +{ + DWORD type; // 1 - ps, 0 - vs + LPD3DXBUFFER pbuf; +}; + +map mapShaders; + +class ZeroGSShaderInclude : public ID3DXInclude +{ +public: + int context; + int ps2x; // if 0, ps20 only + char* pEffectDir; + + STDMETHOD(Open)(D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes) + { + const char* pfilename = pFileName; + char strfile[255]; + if( strstr(pFileName, "ps2hw_ctx") != NULL ) { + + _snprintf(strfile, 255, "%sps2hw_ctx%d.fx", pEffectDir, context); + pfilename = strfile; + } +// else if( strstr(pFileName, "ps2hw_ps2x") != NULL ) { +// _snprintf(strfile, 255, "%sps2hw_ps2%c.fx", pEffectDir, ps2x?'x':'0'); +// pfilename = strfile; +// } + else if( strstr(pFileName, "ps2hw.fx") != NULL ) { + _snprintf(strfile, 255, "%s%s", pEffectDir, pFileName); + pfilename = strfile; + } + + FILE* f = fopen(pfilename, "rb"); + + if( f == NULL ) + return E_FAIL; + + fseek(f, 0, SEEK_END); + DWORD size = ftell(f); + fseek(f, 0, SEEK_SET); + char* buffer = new char[size+1]; + fread(buffer, size, 1, f); + buffer[size] = 0; + + *ppData = buffer; + *pBytes = size; + fclose(f); + + return S_OK; + } + + STDMETHOD(Close)(LPCVOID pData) + { + delete[] (char*)pData; + return S_OK; + } +}; + +void LoadShader(int index, const char* name, const char* pshader, D3DXMACRO* pmacros, ID3DXInclude* pInclude) +{ + LPD3DXBUFFER pShader = NULL, pError = NULL; + + HRESULT hr = D3DXCompileShaderFromFile(srcfilename, pmacros, pInclude, name, pshader, dwFlags, &pShader, &pError, NULL); + + if( FAILED(hr) ) + { + printf("Failed to load %s\n%s\n", name, pError->GetBufferPointer()); + SAFE_RELEASE(pShader); + SAFE_RELEASE(pError); + return; + } + + SAFE_RELEASE(pError); + + if( mapShaders.find(index) != mapShaders.end() ) { + printf("two shaders share the same index %d\n", index); + exit(0); + } + + SHADERINFO info; + info.type = name[0] == 'p' ? 0x80000000 : 0; + info.pbuf = pShader; + mapShaders[index] = info; +} + +int main(int argc, char** argv) +{ + printf("usage: [src] [dst] [opts]\n"); + + if( argc >= 2 ) srcfilename = argv[1]; + if( argc >= 3 ) dstfilename = argv[2]; + if( argc >= 4 ) { + dwFlags = atoi(argv[3]); + } + + FILE* fsrc = fopen(srcfilename, "r"); + if( fsrc == NULL ) { + printf("cannot open %s\n", srcfilename); + return 0; + } + fclose(fsrc); + + LoadShader(SH_BITBLTVS, "BitBltVS", "vs_2_0", NULL, NULL); + LoadShader(SH_BITBLTVS|SH_30, "BitBltVS", "vs_3_0", NULL, NULL); + LoadShader(SH_BITBLTPS, "BitBltPS", "ps_2_0", NULL, NULL); + LoadShader(SH_BITBLTDEPTHPS, "BitBltDepthPS", "ps_2_0", NULL, NULL); + LoadShader(SH_BITBLTDEPTHMRTPS, "BitBltDepthMRTPS", "ps_2_0", NULL, NULL); + LoadShader(SH_BITBLTDEPTHTEXPS, "BitBltDepthTexPS", "ps_2_0", NULL, NULL); + LoadShader(SH_BITBLTDEPTHTEXMRTPS, "BitBltDepthTexMRTPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CRTCTARGPS, "CRTCTargPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CRTCPS, "CRTCPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CRTC24PS, "CRTC24PS", "ps_2_0", NULL, NULL); + LoadShader(SH_ZEROPS, "ZeroPS", "ps_2_0", NULL, NULL); + LoadShader(SH_ZEROPS|SH_30, "ZeroPS", "ps_3_0", NULL, NULL); + LoadShader(SH_BASETEXTUREPS, "BaseTexturePS", "ps_2_0", NULL, NULL); + LoadShader(SH_BITBLTAAPS, "BitBltPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CRTCTARGINTERPS, "CRTCTargInterPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CRTCINTERPS, "CRTCInterPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CRTC24INTERPS, "CRTC24InterPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CONVERT16TO32PS, "Convert16to32PS", "ps_2_0", NULL, NULL); + LoadShader(SH_CONVERT32TO16PS, "Convert32to16PS", "ps_2_0", NULL, NULL); + + const int vsshaders[4] = { SH_REGULARVS, SH_TEXTUREVS, SH_REGULARFOGVS, SH_TEXTUREFOGVS }; + const char* pvsshaders[4] = { "RegularVS", "TextureVS", "RegularFogVS", "TextureFogVS" }; + + // load the texture shaders + char str[255], strdir[255]; + + strcpy(strdir, srcfilename); + int i = (int)strlen(strdir); + while(i > 0) { + if( strdir[i-1] == '/' || strdir[i-1] == '\\' ) + break; + --i; + } + + strdir[i] = 0; + + ZeroGSShaderInclude inc; + inc.pEffectDir = strdir; + + D3DXMACRO macros[10]; + memset(macros, 0, sizeof(macros)); + + macros[0].Name = "WRITE_DEPTH"; + macros[0].Definition = "1"; + + for(i = 0; i < ARRAYSIZE(vsshaders); ++i) { + for(int vs30 = 0; vs30 < 2; ++vs30 ) { + for(int writedepth = 0; writedepth < 2; ++writedepth ) { + inc.context = 0; + LoadShader(vsshaders[i]|(vs30?SH_30:0)|(writedepth?SH_WRITEDEPTH:0), pvsshaders[i], vs30 ? "vs_3_0" : "vs_2_0", writedepth ? macros : NULL, &inc); + inc.context = 1; + LoadShader(vsshaders[i]|(vs30?SH_30:0)|(writedepth?SH_WRITEDEPTH:0)|SH_CONTEXT1, pvsshaders[i], vs30 ? "vs_3_0" : "vs_2_0", writedepth ? macros : NULL, &inc); + } + } + } + + const int psshaders[2] = { SH_REGULARPS, SH_REGULARFOGPS }; + const char* ppsshaders[2] = { "RegularPS", "RegularFogPS" }; + + for(i = 0; i < ARRAYSIZE(psshaders); ++i) { + for(int ps30 = 0; ps30 < 2; ++ps30 ) { + for(int writedepth = 0; writedepth < 2; ++writedepth ) { + LoadShader(psshaders[i]|(ps30?SH_30:0)|(writedepth?SH_WRITEDEPTH:0), ppsshaders[i], ps30 ? "ps_3_0" : "ps_2_0", writedepth ? macros : NULL, NULL); + } + } + } + + printf("creating shaders, note that ps2hw_ctx0.fx, and ps2hw_ctx1.fx are required\n"); + + for(int texwrap = 0; texwrap < NUM_TEXWRAPS; ++texwrap ) { + + int macroindex = 0; + memset(macros, 0, sizeof(macros)); + + if( g_pPsTexWrap[texwrap] != NULL ) { + macros[0].Name = g_pPsTexWrap[texwrap]; + macros[0].Definition = "1"; + macroindex++; + } + + for(int context = 0; context < 2; ++context) { + inc.context = context; + + for(int texfilter = 0; texfilter < NUM_FILTERS; ++texfilter) { + for(int fog = 0; fog < 2; ++fog ) { + for(int writedepth = 0; writedepth < 2; ++writedepth ) { + + if( writedepth ) { + macros[macroindex].Name = "WRITE_DEPTH"; + macros[macroindex].Definition = "1"; + macroindex++; + } + else { + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + } + + for(int testaem = 0; testaem < 2; ++testaem ) { + + if( testaem ) { + macros[macroindex].Name = "TEST_AEM"; + macros[macroindex].Definition = "1"; + macroindex++; + } + else { + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + } + + for(int exactcolor = 0; exactcolor < 2; ++exactcolor ) { + + if( exactcolor ) { + macros[macroindex].Name = "EXACT_COLOR"; + macros[macroindex].Definition = "1"; + macroindex++; + } + else { + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + } + + // 32 + sprintf(str, "Texture%s%d_32PS", fog?"Fog":"", texfilter); + inc.ps2x = 0; + + if( macros[macroindex].Name != NULL ) + printf("error[%d] %s: %d %d %d %d!\n", macroindex, macros[macroindex].Name, texfilter, fog, writedepth, testaem); + + macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; + macros[macroindex].Definition = "1"; + + if( texfilter == 0 && exactcolor == 0 ) { + LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20), str, g_pShaders[SHADER_20], macros, &inc); + } + + inc.ps2x = 1; + LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); + + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + + LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); + LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); + + if( texfilter == 0 ) { + // tex32 + sprintf(str, "Texture%s%d_tex32PS", fog?"Fog":"", texfilter); + inc.ps2x = 0; + + macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; + macros[macroindex].Definition = "1"; + + if( texfilter == 0 && exactcolor == 0 ) { + LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20), str, g_pShaders[SHADER_20], macros, &inc); + } + + inc.ps2x = 1; + + LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); + + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + + LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); + LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); + + // clut32 + sprintf(str, "Texture%s%d_clut32PS", fog?"Fog":"", texfilter); + inc.ps2x = 0; + + macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; + macros[macroindex].Definition = "1"; + + if( texfilter == 0 && exactcolor == 0 ) { + LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20), str, g_pShaders[SHADER_20], macros, &inc); + } + + inc.ps2x = 1; + + LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); + + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + + LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); + LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); + + // tex32to16 + sprintf(str, "Texture%s%d_tex32to16PS", fog?"Fog":"", texfilter); + inc.ps2x = 0; + + macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; + macros[macroindex].Definition = "1"; + + if( texfilter == 0 && exactcolor == 0 ) { + LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20), str, g_pShaders[SHADER_20], macros, &inc); + } + + inc.ps2x = 1; + + LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); + + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + + LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); + LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); + + // tex16to8h + sprintf(str, "Texture%s%d_tex16to8hPS", fog?"Fog":"", texfilter); + inc.ps2x = 0; + + macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; + macros[macroindex].Definition = "1"; + + inc.ps2x = 1; + + LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); + + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + + LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); + LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); + } + } + + --macroindex; + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + } + + --macroindex; + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + } + + --macroindex; + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + } + } + } + } + + // create the database + FILE* fdst = fopen(dstfilename, "wb"); + if( fdst == NULL ) { + printf("failed to open %s\n", dstfilename); + return 0; + } + + DWORD num = (DWORD)mapShaders.size(); + fwrite(&num, 4, 1, fdst); + + i = 0; + DWORD totaloffset = 4+sizeof(SHADERHEADER)*num; + for(map::iterator it = mapShaders.begin(); it != mapShaders.end(); ++it, ++i) { + SHADERHEADER h; + h.index = it->first | it->second.type; + h.offset = totaloffset; + h.size = it->second.pbuf->GetBufferSize(); + + fseek(fdst, 4+i*sizeof(SHADERHEADER), SEEK_SET); + fwrite(&h, sizeof(SHADERHEADER), 1, fdst); + + fseek(fdst, totaloffset, SEEK_SET); + fwrite(it->second.pbuf->GetBufferPointer(), it->second.pbuf->GetBufferSize(), 1, fdst); + + totaloffset += it->second.pbuf->GetBufferSize(); + it->second.pbuf->Release(); + } + + fclose(fdst); + + printf("wrote %s\n", dstfilename); + + return 0; +} diff --git a/plugins/zerogs/dx/ZeroGSShaders/zerogsshaders.h b/plugins/zerogs/dx/ZeroGSShaders/zerogsshaders.h index a3742f6931..d42191fc52 100644 --- a/plugins/zerogs/dx/ZeroGSShaders/zerogsshaders.h +++ b/plugins/zerogs/dx/ZeroGSShaders/zerogsshaders.h @@ -1,118 +1,118 @@ -#define NUM_FILTERS 2 // texture filtering -#define NUM_TYPES 5 // types of texture read modes -#define NUM_TEXWRAPS 4 // texture wrapping - -#define NUM_SHADERS (NUM_FILTERS*NUM_TYPES*NUM_TEXWRAPS*32) // # shaders for a given ps - -#define SHADER_20 0 -#define SHADER_20a 1 -#define SHADER_20b 2 -#define SHADER_30 3 - -// ps == 0, 2.0 -// ps == 1, 2.0a, nvidia -// ps == 2, 2.0b, ati -const static char* g_pShaders[4] = { "ps_2_0", "ps_2_a", "ps_2_b", "ps_3_0" }; -const static char* g_pPsTexWrap[] = { "REPEAT", "CLAMP", "REGION_REPEAT", NULL }; -const static char* g_pTexTypes[] = { "32", "tex32", "clut32", "tex32to16", "tex16to8h" }; - -#define TEXWRAP_REPEAT 0 -#define TEXWRAP_CLAMP 1 -#define TEXWRAP_REGION_REPEAT 2 -#define TEXWRAP_REPEAT_CLAMP 3 - -inline int GET_SHADER_INDEX(int type, int texfilter, int texwrap, int fog, int writedepth, int testaem, int exactcolor, int context, int ps) -{ - return type + texfilter*NUM_TYPES + NUM_FILTERS*NUM_TYPES*texwrap + NUM_TEXWRAPS*NUM_FILTERS*NUM_TYPES*(fog+2*writedepth+4*testaem+8*exactcolor+16*context+32*ps); -} - -static HRESULT LoadShaderFromType(const char* srcfile, int type, int texfilter, int texwrap, int fog, int writedepth, int testaem, int exactcolor, int ps, DWORD flags, - IDirect3DDevice9* pd3dDevice, ID3DXInclude* pInclude, IDirect3DPixelShader9** pps) -{ - assert( texwrap < NUM_TEXWRAPS); - assert( type < NUM_TYPES ); - - char str[255]; - sprintf(str, "Texture%s%d_%sPS", fog?"Fog":"", texfilter, g_pTexTypes[type]); - - LPD3DXBUFFER pShader = NULL, pError = NULL; - SAFE_RELEASE(*pps); - - vector macros; - D3DXMACRO dummy; dummy.Definition = NULL; dummy.Name = NULL; - if( g_pPsTexWrap[texwrap] != NULL ) { - D3DXMACRO m; - m.Name = g_pPsTexWrap[texwrap]; - m.Definition = "1"; - macros.push_back(m); - } - if( writedepth ) { - D3DXMACRO m; - m.Name = "WRITE_DEPTH"; - m.Definition = "1"; - macros.push_back(m); - } - if( testaem ) { - D3DXMACRO m; - m.Name = "TEST_AEM"; - m.Definition = "1"; - macros.push_back(m); - } - if( exactcolor ) { - D3DXMACRO m; - m.Name = "EXACT_COLOR"; - m.Definition = "1"; - macros.push_back(m); - } - - macros.push_back(dummy); - HRESULT hr = D3DXCompileShaderFromFile(srcfile, ¯os[0], pInclude, str, g_pShaders[ps], flags, &pShader, &pError, NULL); - - if( FAILED(hr) ) - { - printf("Failed to load %s\n%s\n", str, pError->GetBufferPointer()); - SAFE_RELEASE(pShader); - SAFE_RELEASE(pError); - return hr; - } - - DWORD* ptr = (DWORD*)pShader->GetBufferPointer(); - hr = pd3dDevice->CreatePixelShader(ptr, pps); - SAFE_RELEASE(pShader); - SAFE_RELEASE(pError); - - return hr; -} - -struct SHADERHEADER -{ - DWORD index, offset, size; // if highest bit of index is set, pixel shader -}; - -#define SH_30 0x4000 // or for vs3.0 shaders -#define SH_WRITEDEPTH 0x2000 // depth is written -#define SH_CONTEXT1 0x1000 // context1 is used - -#define SH_REGULARVS 0x8000 -#define SH_TEXTUREVS 0x8001 -#define SH_REGULARFOGVS 0x8002 -#define SH_TEXTUREFOGVS 0x8003 -#define SH_REGULARPS 0x8004 -#define SH_REGULARFOGPS 0x8005 -#define SH_BITBLTVS 0x8006 -#define SH_BITBLTPS 0x8007 -#define SH_BITBLTDEPTHPS 0x8009 -#define SH_CRTCTARGPS 0x800a -#define SH_CRTCPS 0x800b -#define SH_CRTC24PS 0x800c -#define SH_ZEROPS 0x800e -#define SH_BASETEXTUREPS 0x800f -#define SH_BITBLTAAPS 0x8010 -#define SH_CRTCTARGINTERPS 0x8012 -#define SH_CRTCINTERPS 0x8013 -#define SH_CRTC24INTERPS 0x8014 -#define SH_BITBLTDEPTHMRTPS 0x8016 -#define SH_BITBLTDEPTHTEXPS 0x8017 -#define SH_BITBLTDEPTHTEXMRTPS 0x8018 -#define SH_CONVERT16TO32PS 0x8020 -#define SH_CONVERT32TO16PS 0x8021 +#define NUM_FILTERS 2 // texture filtering +#define NUM_TYPES 5 // types of texture read modes +#define NUM_TEXWRAPS 4 // texture wrapping + +#define NUM_SHADERS (NUM_FILTERS*NUM_TYPES*NUM_TEXWRAPS*32) // # shaders for a given ps + +#define SHADER_20 0 +#define SHADER_20a 1 +#define SHADER_20b 2 +#define SHADER_30 3 + +// ps == 0, 2.0 +// ps == 1, 2.0a, nvidia +// ps == 2, 2.0b, ati +const static char* g_pShaders[4] = { "ps_2_0", "ps_2_a", "ps_2_b", "ps_3_0" }; +const static char* g_pPsTexWrap[] = { "REPEAT", "CLAMP", "REGION_REPEAT", NULL }; +const static char* g_pTexTypes[] = { "32", "tex32", "clut32", "tex32to16", "tex16to8h" }; + +#define TEXWRAP_REPEAT 0 +#define TEXWRAP_CLAMP 1 +#define TEXWRAP_REGION_REPEAT 2 +#define TEXWRAP_REPEAT_CLAMP 3 + +inline int GET_SHADER_INDEX(int type, int texfilter, int texwrap, int fog, int writedepth, int testaem, int exactcolor, int context, int ps) +{ + return type + texfilter*NUM_TYPES + NUM_FILTERS*NUM_TYPES*texwrap + NUM_TEXWRAPS*NUM_FILTERS*NUM_TYPES*(fog+2*writedepth+4*testaem+8*exactcolor+16*context+32*ps); +} + +static HRESULT LoadShaderFromType(const char* srcfile, int type, int texfilter, int texwrap, int fog, int writedepth, int testaem, int exactcolor, int ps, DWORD flags, + IDirect3DDevice9* pd3dDevice, ID3DXInclude* pInclude, IDirect3DPixelShader9** pps) +{ + assert( texwrap < NUM_TEXWRAPS); + assert( type < NUM_TYPES ); + + char str[255]; + sprintf(str, "Texture%s%d_%sPS", fog?"Fog":"", texfilter, g_pTexTypes[type]); + + LPD3DXBUFFER pShader = NULL, pError = NULL; + SAFE_RELEASE(*pps); + + vector macros; + D3DXMACRO dummy; dummy.Definition = NULL; dummy.Name = NULL; + if( g_pPsTexWrap[texwrap] != NULL ) { + D3DXMACRO m; + m.Name = g_pPsTexWrap[texwrap]; + m.Definition = "1"; + macros.push_back(m); + } + if( writedepth ) { + D3DXMACRO m; + m.Name = "WRITE_DEPTH"; + m.Definition = "1"; + macros.push_back(m); + } + if( testaem ) { + D3DXMACRO m; + m.Name = "TEST_AEM"; + m.Definition = "1"; + macros.push_back(m); + } + if( exactcolor ) { + D3DXMACRO m; + m.Name = "EXACT_COLOR"; + m.Definition = "1"; + macros.push_back(m); + } + + macros.push_back(dummy); + HRESULT hr = D3DXCompileShaderFromFile(srcfile, ¯os[0], pInclude, str, g_pShaders[ps], flags, &pShader, &pError, NULL); + + if( FAILED(hr) ) + { + printf("Failed to load %s\n%s\n", str, pError->GetBufferPointer()); + SAFE_RELEASE(pShader); + SAFE_RELEASE(pError); + return hr; + } + + DWORD* ptr = (DWORD*)pShader->GetBufferPointer(); + hr = pd3dDevice->CreatePixelShader(ptr, pps); + SAFE_RELEASE(pShader); + SAFE_RELEASE(pError); + + return hr; +} + +struct SHADERHEADER +{ + DWORD index, offset, size; // if highest bit of index is set, pixel shader +}; + +#define SH_30 0x4000 // or for vs3.0 shaders +#define SH_WRITEDEPTH 0x2000 // depth is written +#define SH_CONTEXT1 0x1000 // context1 is used + +#define SH_REGULARVS 0x8000 +#define SH_TEXTUREVS 0x8001 +#define SH_REGULARFOGVS 0x8002 +#define SH_TEXTUREFOGVS 0x8003 +#define SH_REGULARPS 0x8004 +#define SH_REGULARFOGPS 0x8005 +#define SH_BITBLTVS 0x8006 +#define SH_BITBLTPS 0x8007 +#define SH_BITBLTDEPTHPS 0x8009 +#define SH_CRTCTARGPS 0x800a +#define SH_CRTCPS 0x800b +#define SH_CRTC24PS 0x800c +#define SH_ZEROPS 0x800e +#define SH_BASETEXTUREPS 0x800f +#define SH_BITBLTAAPS 0x8010 +#define SH_CRTCTARGINTERPS 0x8012 +#define SH_CRTCINTERPS 0x8013 +#define SH_CRTC24INTERPS 0x8014 +#define SH_BITBLTDEPTHMRTPS 0x8016 +#define SH_BITBLTDEPTHTEXPS 0x8017 +#define SH_BITBLTDEPTHTEXMRTPS 0x8018 +#define SH_CONVERT16TO32PS 0x8020 +#define SH_CONVERT32TO16PS 0x8021 diff --git a/plugins/zerogs/dx/common.h b/plugins/zerogs/dx/common.h index 280d62a70c..698c45c5b9 100644 --- a/plugins/zerogs/dx/common.h +++ b/plugins/zerogs/dx/common.h @@ -1,1142 +1,1142 @@ -/** - * @file common.h - * common internal api header. - */ - -#ifndef COMMON_H -#define COMMON_H - -#if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) -# define CONFIG_WIN32 -#endif - -//#define ALT_BITSTREAM_WRITER -//#define ALIGNED_BITSTREAM_WRITER - -#define ALT_BITSTREAM_READER -//#define LIBMPEG2_BITSTREAM_READER -//#define A32_BITSTREAM_READER -#define LIBMPEG2_BITSTREAM_READER_HACK //add BERO - -#ifdef HAVE_AV_CONFIG_H -/* only include the following when compiling package */ -# include "config.h" - -# include -# include -# include -# include -# ifndef __BEOS__ -# include -# else -# include "berrno.h" -# endif -# include - -# ifndef ENODATA -# define ENODATA 61 -# endif - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#include -#ifndef offsetof -# define offsetof(T,F) ((unsigned int)((char *)&((T *)0)->F)) -#endif - -#define AVOPTION_CODEC_BOOL(name, help, field) \ - { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_BOOL } -#define AVOPTION_CODEC_DOUBLE(name, help, field, minv, maxv, defval) \ - { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_DOUBLE, minv, maxv, defval } -#define AVOPTION_CODEC_FLAG(name, help, field, flag, defval) \ - { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_FLAG, flag, 0, defval } -#define AVOPTION_CODEC_INT(name, help, field, minv, maxv, defval) \ - { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_INT, minv, maxv, defval } -#define AVOPTION_CODEC_STRING(name, help, field, str, val) \ - { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_STRING, .defval = val, .defstr = str } -#define AVOPTION_CODEC_RCOVERRIDE(name, help, field) \ - { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_RCOVERRIDE, .defval = 0, .defstr = NULL } -#define AVOPTION_SUB(ptr) { .name = NULL, .help = (const char*)ptr } -#define AVOPTION_END() AVOPTION_SUB(NULL) - -struct AVOption; -#ifdef HAVE_MMX -extern const struct AVOption avoptions_common[3 + 5]; -#else -extern const struct AVOption avoptions_common[3]; -#endif -extern const struct AVOption avoptions_workaround_bug[11]; - -#endif /* HAVE_AV_CONFIG_H */ - -/* Suppress restrict if it was not defined in config.h. */ -#ifndef restrict -# define restrict -#endif - -#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0) -# define always_inline __attribute__((always_inline)) inline -#else -# define always_inline inline -#endif - -#ifdef CONFIG_WIN32 - -/* windows */ - -typedef unsigned short uint16_t; -typedef signed short int16_t; -typedef unsigned char uint8_t; -typedef unsigned int uint32_t; -typedef unsigned __int64 uint64_t; -typedef signed char int8_t; -typedef signed int int32_t; -typedef signed __int64 int64_t; - -# ifndef __MINGW32__ -# define int64_t_C(c) (c ## i64) -# define uint64_t_C(c) (c ## i64) - -# define inline __inline - -# else -# define int64_t_C(c) (c ## LL) -# define uint64_t_C(c) (c ## ULL) -# endif /* __MINGW32__ */ - -# ifdef _DEBUG -# define DEBUG -# endif - -# define snprintf _snprintf -# define vsnprintf _vsnprintf - -/* CONFIG_WIN32 end */ -#elif defined (CONFIG_OS2) -/* OS/2 EMX */ - -#include - -#ifndef int64_t_C -#define int64_t_C(c) (c ## LL) -#define uint64_t_C(c) (c ## ULL) -#endif - -#ifdef HAVE_AV_CONFIG_H - -#ifdef USE_FASTMEMCPY -#include "fastmemcpy.h" -#endif - -#include - -#endif /* HAVE_AV_CONFIG_H */ - -/* CONFIG_OS2 end */ -#else - -/* unix */ - -#include - -#ifndef int64_t_C -#define int64_t_C(c) (c ## LL) -#define uint64_t_C(c) (c ## ULL) -#endif - -#ifdef HAVE_AV_CONFIG_H - -# ifdef USE_FASTMEMCPY -# include "fastmemcpy.h" -# endif -# endif /* HAVE_AV_CONFIG_H */ - -#endif /* !CONFIG_WIN32 && !CONFIG_OS2 */ - -#ifdef HAVE_AV_CONFIG_H - -# include "bswap.h" - -# if defined(__MINGW32__) || defined(__CYGWIN__) || \ - defined(__OS2__) || (defined (__OpenBSD__) && !defined(__ELF__)) -# define MANGLE(a) "_" #a -# else -# define MANGLE(a) #a -# endif - -/* debug stuff */ - -# ifndef DEBUG -# define NDEBUG -# endif -# include - -/* dprintf macros */ -# if defined(CONFIG_WIN32) && !defined(__MINGW32__) - -inline void dprintf(const char* fmt,...) {} - -# else - -# ifdef DEBUG -# define dprintf(fmt,args...) printf(fmt, ## args) -# else -# define dprintf(fmt,args...) -# endif - -# endif /* !CONFIG_WIN32 */ - -# define av_abort() do { fprintf(stderr, "Abort at %s:%d\n", __FILE__, __LINE__); abort(); } while (0) - -//rounded divison & shift -#define RSHIFT(a,b) ((a) > 0 ? ((a) + (1<<((b)-1)))>>(b) : ((a) + (1<<((b)-1))-1)>>(b)) -/* assume b>0 */ -#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) -#define ABS(a) ((a) >= 0 ? (a) : (-(a))) - -#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) -#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) - -extern const uint32_t inverse[256]; - -#ifdef ARCH_X86 -# define FASTDIV(a,b) \ - ({\ - int ret,dmy;\ - asm volatile(\ - "mull %3"\ - :"=d"(ret),"=a"(dmy)\ - :"1"(a),"g"(inverse[b])\ - );\ - ret;\ - }) -#elif defined(CONFIG_FASTDIV) -# define FASTDIV(a,b) ((uint32_t)((((uint64_t)a)*inverse[b])>>32)) -#else -# define FASTDIV(a,b) ((a)/(b)) -#endif - -#ifdef ARCH_X86 -// avoid +32 for shift optimization (gcc should do that ...) -static inline int32_t NEG_SSR32( int32_t a, int8_t s){ - asm ("sarl %1, %0\n\t" - : "+r" (a) - : "ic" ((uint8_t)(-s)) - ); - return a; -} -static inline uint32_t NEG_USR32(uint32_t a, int8_t s){ - asm ("shrl %1, %0\n\t" - : "+r" (a) - : "ic" ((uint8_t)(-s)) - ); - return a; -} -#else -# define NEG_SSR32(a,s) ((( int32_t)(a))>>(32-(s))) -# define NEG_USR32(a,s) (((uint32_t)(a))>>(32-(s))) -#endif - -/* bit output */ - -struct PutBitContext; - -typedef void (*WriteDataFunc)(void *, uint8_t *, int); - -typedef struct PutBitContext { -#ifdef ALT_BITSTREAM_WRITER - uint8_t *buf, *buf_end; - int index; -#else - uint32_t bit_buf; - int bit_left; - uint8_t *buf, *buf_ptr, *buf_end; -#endif - int64_t data_out_size; /* in bytes */ -} PutBitContext; - -void init_put_bits(PutBitContext *s, - uint8_t *buffer, int buffer_size, - void *opaque, - void (*write_data)(void *, uint8_t *, int)); - -int64_t get_bit_count(PutBitContext *s); /* XXX: change function name */ -void align_put_bits(PutBitContext *s); -void flush_put_bits(PutBitContext *s); -void put_string(PutBitContext * pbc, char *s); - -/* bit input */ - -typedef struct GetBitContext { - const uint8_t *buffer, *buffer_end; -#ifdef ALT_BITSTREAM_READER - int index; -#elif defined LIBMPEG2_BITSTREAM_READER - uint8_t *buffer_ptr; - uint32_t cache; - int bit_count; -#elif defined A32_BITSTREAM_READER - uint32_t *buffer_ptr; - uint32_t cache0; - uint32_t cache1; - int bit_count; -#endif - int size_in_bits; -} GetBitContext; - -static inline int get_bits_count(GetBitContext *s); - -#define VLC_TYPE int16_t - -typedef struct VLC { - int bits; - VLC_TYPE (*table)[2]; ///< code, bits - int table_size, table_allocated; -} VLC; - -typedef struct RL_VLC_ELEM { - int16_t level; - int8_t len; - uint8_t run; -} RL_VLC_ELEM; - -#ifdef ARCH_SPARC64 -#define UNALIGNED_STORES_ARE_BAD -#endif - -/* used to avoid missaligned exceptions on some archs (alpha, ...) */ -#ifdef ARCH_X86 -# define unaligned32(a) (*(uint32_t*)(a)) -#else -# ifdef __GNUC__ -static inline uint32_t unaligned32(const void *v) { - struct Unaligned { - uint32_t i; - } __attribute__((packed)); - - return ((const struct Unaligned *) v)->i; -} -# elif defined(__DECC) -static inline uint32_t unaligned32(const void *v) { - return *(const __unaligned uint32_t *) v; -} -# else -static inline uint32_t unaligned32(const void *v) { - return *(const uint32_t *) v; -} -# endif -#endif //!ARCH_X86 - -#ifndef ALT_BITSTREAM_WRITER -static inline void put_bits(PutBitContext *s, int n, unsigned int value) -{ - unsigned int bit_buf; - int bit_left; - -#ifdef STATS - st_out_bit_counts[st_current_index] += n; -#endif - // DEBUG_LOG("put_bits=%d %x\n", n, value); - assert(n == 32 || value < (1U << n)); - - bit_buf = s->bit_buf; - bit_left = s->bit_left; - - // DEBUG_LOG("n=%d value=%x cnt=%d buf=%x\n", n, value, bit_cnt, bit_buf); - /* XXX: optimize */ - if (n < bit_left) { - bit_buf = (bit_buf<> (n - bit_left); -#ifdef UNALIGNED_STORES_ARE_BAD - if (3 & (int) s->buf_ptr) { - s->buf_ptr[0] = bit_buf >> 24; - s->buf_ptr[1] = bit_buf >> 16; - s->buf_ptr[2] = bit_buf >> 8; - s->buf_ptr[3] = bit_buf ; - } else -#endif - *(uint32_t *)s->buf_ptr = be2me_32(bit_buf); - //DEBUG_LOG("bitbuf = %08x\n", bit_buf); - s->buf_ptr+=4; - bit_left+=32 - n; - bit_buf = value; - } - - s->bit_buf = bit_buf; - s->bit_left = bit_left; -} -#endif - - -#ifdef ALT_BITSTREAM_WRITER -static inline void put_bits(PutBitContext *s, int n, unsigned int value) -{ -# ifdef ALIGNED_BITSTREAM_WRITER -# ifdef ARCH_X86 - asm volatile( - "movl %0, %%ecx \n\t" - "xorl %%eax, %%eax \n\t" - "shrdl %%cl, %1, %%eax \n\t" - "shrl %%cl, %1 \n\t" - "movl %0, %%ecx \n\t" - "shrl $3, %%ecx \n\t" - "andl $0xFFFFFFFC, %%ecx \n\t" - "bswapl %1 \n\t" - "orl %1, (%2, %%ecx) \n\t" - "bswapl %%eax \n\t" - "addl %3, %0 \n\t" - "movl %%eax, 4(%2, %%ecx) \n\t" - : "=&r" (s->index), "=&r" (value) - : "r" (s->buf), "r" (n), "0" (s->index), "1" (value<<(-n)) - : "%eax", "%ecx" - ); -# else - int index= s->index; - uint32_t *ptr= ((uint32_t *)s->buf)+(index>>5); - - value<<= 32-n; - - ptr[0] |= be2me_32(value>>(index&31)); - ptr[1] = be2me_32(value<<(32-(index&31))); -//if(n>24) DEBUG_LOG("%d %d\n", n, value); - index+= n; - s->index= index; -# endif -# else //ALIGNED_BITSTREAM_WRITER -# ifdef ARCH_X86 - asm volatile( - "movl $7, %%ecx \n\t" - "andl %0, %%ecx \n\t" - "addl %3, %%ecx \n\t" - "negl %%ecx \n\t" - "shll %%cl, %1 \n\t" - "bswapl %1 \n\t" - "movl %0, %%ecx \n\t" - "shrl $3, %%ecx \n\t" - "orl %1, (%%ecx, %2) \n\t" - "addl %3, %0 \n\t" - "movl $0, 4(%%ecx, %2) \n\t" - : "=&r" (s->index), "=&r" (value) - : "r" (s->buf), "r" (n), "0" (s->index), "1" (value) - : "%ecx" - ); -# else - int index= s->index; - uint32_t *ptr= (uint32_t*)(((uint8_t *)s->buf)+(index>>3)); - - ptr[0] |= be2me_32(value<<(32-n-(index&7) )); - ptr[1] = 0; -//if(n>24) DEBUG_LOG("%d %d\n", n, value); - index+= n; - s->index= index; -# endif -# endif //!ALIGNED_BITSTREAM_WRITER -} -#endif - - -static inline uint8_t* pbBufPtr(PutBitContext *s) -{ -#ifdef ALT_BITSTREAM_WRITER - return s->buf + (s->index>>3); -#else - return s->buf_ptr; -#endif -} - -/* Bitstream reader API docs: -name - abritary name which is used as prefix for the internal variables - -gb - getbitcontext - -OPEN_READER(name, gb) - loads gb into local variables - -CLOSE_READER(name, gb) - stores local vars in gb - -UPDATE_CACHE(name, gb) - refills the internal cache from the bitstream - after this call at least MIN_CACHE_BITS will be available, - -GET_CACHE(name, gb) - will output the contents of the internal cache, next bit is MSB of 32 or 64 bit (FIXME 64bit) - -SHOW_UBITS(name, gb, num) - will return the nest num bits - -SHOW_SBITS(name, gb, num) - will return the nest num bits and do sign extension - -SKIP_BITS(name, gb, num) - will skip over the next num bits - note, this is equinvalent to SKIP_CACHE; SKIP_COUNTER - -SKIP_CACHE(name, gb, num) - will remove the next num bits from the cache (note SKIP_COUNTER MUST be called before UPDATE_CACHE / CLOSE_READER) - -SKIP_COUNTER(name, gb, num) - will increment the internal bit counter (see SKIP_CACHE & SKIP_BITS) - -LAST_SKIP_CACHE(name, gb, num) - will remove the next num bits from the cache if it is needed for UPDATE_CACHE otherwise it will do nothing - -LAST_SKIP_BITS(name, gb, num) - is equinvalent to SKIP_LAST_CACHE; SKIP_COUNTER - -for examples see get_bits, show_bits, skip_bits, get_vlc -*/ - -static inline int unaligned32_be(const void *v) -{ -#ifdef CONFIG_ALIGN - const uint8_t *p=v; - return (((p[0]<<8) | p[1])<<16) | (p[2]<<8) | (p[3]); -#else - return be2me_32( unaligned32(v)); //original -#endif -} - -#ifdef ALT_BITSTREAM_READER -# define MIN_CACHE_BITS 25 - -# define OPEN_READER(name, gb)\ - int name##_index= (gb)->index;\ - int name##_cache= 0;\ - -# define CLOSE_READER(name, gb)\ - (gb)->index= name##_index;\ - -# define UPDATE_CACHE(name, gb)\ - name##_cache= unaligned32_be( ((uint8_t *)(gb)->buffer)+(name##_index>>3) ) << (name##_index&0x07);\ - -# define SKIP_CACHE(name, gb, num)\ - name##_cache <<= (num);\ - -// FIXME name? -# define SKIP_COUNTER(name, gb, num)\ - name##_index += (num);\ - -# define SKIP_BITS(name, gb, num)\ - {\ - SKIP_CACHE(name, gb, num)\ - SKIP_COUNTER(name, gb, num)\ - }\ - -# define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num) -# define LAST_SKIP_CACHE(name, gb, num) ; - -# define SHOW_UBITS(name, gb, num)\ - NEG_USR32(name##_cache, num) - -# define SHOW_SBITS(name, gb, num)\ - NEG_SSR32(name##_cache, num) - -# define GET_CACHE(name, gb)\ - ((uint32_t)name##_cache) - -static inline int get_bits_count(GetBitContext *s){ - return s->index; -} -#elif defined LIBMPEG2_BITSTREAM_READER -//libmpeg2 like reader - -# define MIN_CACHE_BITS 17 - -# define OPEN_READER(name, gb)\ - int name##_bit_count=(gb)->bit_count;\ - int name##_cache= (gb)->cache;\ - uint8_t * name##_buffer_ptr=(gb)->buffer_ptr;\ - -# define CLOSE_READER(name, gb)\ - (gb)->bit_count= name##_bit_count;\ - (gb)->cache= name##_cache;\ - (gb)->buffer_ptr= name##_buffer_ptr;\ - -#ifdef LIBMPEG2_BITSTREAM_READER_HACK - -# define UPDATE_CACHE(name, gb)\ - if(name##_bit_count >= 0){\ - name##_cache+= (int)be2me_16(*(uint16_t*)name##_buffer_ptr) << name##_bit_count;\ - ((uint16_t*)name##_buffer_ptr)++;\ - name##_bit_count-= 16;\ - }\ - -#else - -# define UPDATE_CACHE(name, gb)\ - if(name##_bit_count >= 0){\ - name##_cache+= ((name##_buffer_ptr[0]<<8) + name##_buffer_ptr[1]) << name##_bit_count;\ - name##_buffer_ptr+=2;\ - name##_bit_count-= 16;\ - }\ - -#endif - -# define SKIP_CACHE(name, gb, num)\ - name##_cache <<= (num);\ - -# define SKIP_COUNTER(name, gb, num)\ - name##_bit_count += (num);\ - -# define SKIP_BITS(name, gb, num)\ - {\ - SKIP_CACHE(name, gb, num)\ - SKIP_COUNTER(name, gb, num)\ - }\ - -# define LAST_SKIP_BITS(name, gb, num) SKIP_BITS(name, gb, num) -# define LAST_SKIP_CACHE(name, gb, num) SKIP_CACHE(name, gb, num) - -# define SHOW_UBITS(name, gb, num)\ - NEG_USR32(name##_cache, num) - -# define SHOW_SBITS(name, gb, num)\ - NEG_SSR32(name##_cache, num) - -# define GET_CACHE(name, gb)\ - ((uint32_t)name##_cache) - -static inline int get_bits_count(GetBitContext *s){ - return (s->buffer_ptr - s->buffer)*8 - 16 + s->bit_count; -} - -#elif defined A32_BITSTREAM_READER - -# define MIN_CACHE_BITS 32 - -# define OPEN_READER(name, gb)\ - int name##_bit_count=(gb)->bit_count;\ - uint32_t name##_cache0= (gb)->cache0;\ - uint32_t name##_cache1= (gb)->cache1;\ - uint32_t * name##_buffer_ptr=(gb)->buffer_ptr;\ - -# define CLOSE_READER(name, gb)\ - (gb)->bit_count= name##_bit_count;\ - (gb)->cache0= name##_cache0;\ - (gb)->cache1= name##_cache1;\ - (gb)->buffer_ptr= name##_buffer_ptr;\ - -# define UPDATE_CACHE(name, gb)\ - if(name##_bit_count > 0){\ - const uint32_t next= be2me_32( *name##_buffer_ptr );\ - name##_cache0 |= NEG_USR32(next,name##_bit_count);\ - name##_cache1 |= next<buffer_ptr - s->buffer)*8 - 32 + s->bit_count; -} - -#endif - -/** - * read mpeg1 dc style vlc (sign bit + mantisse with no MSB). - * if MSB not set it is negative - * @param n length in bits - * @author BERO - */ -static inline int get_xbits(GetBitContext *s, int n){ - register int tmp; - register int32_t cache; - OPEN_READER(re, s) - UPDATE_CACHE(re, s) - cache = GET_CACHE(re,s); - if ((int32_t)cache<0) { //MSB=1 - tmp = NEG_USR32(cache,n); - } else { - // tmp = (-1<index+=n for the ALT_READER :)) - OPEN_READER(re, s) - UPDATE_CACHE(re, s) - LAST_SKIP_BITS(re, s, n) - CLOSE_READER(re, s) -} - -static inline unsigned int get_bits1(GetBitContext *s){ -#ifdef ALT_BITSTREAM_READER - int index= s->index; - uint8_t result= s->buffer[ index>>3 ]; - result<<= (index&0x07); - result>>= 8 - 1; - index++; - s->index= index; - - return result; -#else - return get_bits(s, 1); -#endif -} - -static inline unsigned int show_bits1(GetBitContext *s){ - return show_bits(s, 1); -} - -static inline void skip_bits1(GetBitContext *s){ - skip_bits(s, 1); -} - -void init_get_bits(GetBitContext *s, - const uint8_t *buffer, int buffer_size); - -int check_marker(GetBitContext *s, const char *msg); -void align_get_bits(GetBitContext *s); -int init_vlc(VLC *vlc, int nb_bits, int nb_codes, - const void *bits, int bits_wrap, int bits_size, - const void *codes, int codes_wrap, int codes_size); -void free_vlc(VLC *vlc); - -/** - * - * if the vlc code is invalid and max_depth=1 than no bits will be removed - * if the vlc code is invalid and max_depth>1 than the number of bits removed - * is undefined - */ -#define GET_VLC(code, name, gb, table, bits, max_depth)\ -{\ - int n, index, nb_bits;\ -\ - index= SHOW_UBITS(name, gb, bits);\ - code = table[index][0];\ - n = table[index][1];\ -\ - if(max_depth > 1 && n < 0){\ - LAST_SKIP_BITS(name, gb, bits)\ - UPDATE_CACHE(name, gb)\ -\ - nb_bits = -n;\ -\ - index= SHOW_UBITS(name, gb, nb_bits) + code;\ - code = table[index][0];\ - n = table[index][1];\ - if(max_depth > 2 && n < 0){\ - LAST_SKIP_BITS(name, gb, nb_bits)\ - UPDATE_CACHE(name, gb)\ -\ - nb_bits = -n;\ -\ - index= SHOW_UBITS(name, gb, nb_bits) + code;\ - code = table[index][0];\ - n = table[index][1];\ - }\ - }\ - SKIP_BITS(name, gb, n)\ -} - -#define GET_RL_VLC(level, run, name, gb, table, bits, max_depth)\ -{\ - int n, index, nb_bits;\ -\ - index= SHOW_UBITS(name, gb, bits);\ - level = table[index].level;\ - n = table[index].len;\ -\ - if(max_depth > 1 && n < 0){\ - LAST_SKIP_BITS(name, gb, bits)\ - UPDATE_CACHE(name, gb)\ -\ - nb_bits = -n;\ -\ - index= SHOW_UBITS(name, gb, nb_bits) + level;\ - level = table[index].level;\ - n = table[index].len;\ - }\ - run= table[index].run;\ - SKIP_BITS(name, gb, n)\ -} - -// deprecated, dont use get_vlc for new code, use get_vlc2 instead or use GET_VLC directly -static inline int get_vlc(GetBitContext *s, VLC *vlc) -{ - int code; - VLC_TYPE (*table)[2]= vlc->table; - - OPEN_READER(re, s) - UPDATE_CACHE(re, s) - - GET_VLC(code, re, s, table, vlc->bits, 3) - - CLOSE_READER(re, s) - return code; -} - -/** - * parses a vlc code, faster then get_vlc() - * @param bits is the number of bits which will be read at once, must be - * identical to nb_bits in init_vlc() - * @param max_depth is the number of times bits bits must be readed to completly - * read the longest vlc code - * = (max_vlc_length + bits - 1) / bits - */ -static always_inline int get_vlc2(GetBitContext *s, VLC_TYPE (*table)[2], - int bits, int max_depth) -{ - int code; - - OPEN_READER(re, s) - UPDATE_CACHE(re, s) - - GET_VLC(code, re, s, table, bits, max_depth) - - CLOSE_READER(re, s) - return code; -} - -//#define TRACE - -#ifdef TRACE - -static inline void print_bin(int bits, int n){ - int i; - - for(i=n-1; i>=0; i--){ - DEBUG_LOG("%d", (bits>>i)&1); - } - for(i=n; i<24; i++) - DEBUG_LOG(" "); -} - -static inline int get_bits_trace(GetBitContext *s, int n, char *file, char *func, int line){ - int r= get_bits(s, n); - - print_bin(r, n); - DEBUG_LOG("%5d %2d %3d bit @%5d in %s %s:%d\n", r, n, r, get_bits_count(s)-n, file, func, line); - return r; -} -static inline int get_vlc_trace(GetBitContext *s, VLC_TYPE (*table)[2], int bits, int max_depth, char *file, char *func, int line){ - int show= show_bits(s, 24); - int pos= get_bits_count(s); - int r= get_vlc2(s, table, bits, max_depth); - int len= get_bits_count(s) - pos; - int bits2= show>>(24-len); - - print_bin(bits2, len); - - DEBUG_LOG("%5d %2d %3d vlc @%5d in %s %s:%d\n", bits2, len, r, pos, file, func, line); - return r; -} -static inline int get_xbits_trace(GetBitContext *s, int n, char *file, char *func, int line){ - int show= show_bits(s, n); - int r= get_xbits(s, n); - - print_bin(show, n); - DEBUG_LOG("%5d %2d %3d xbt @%5d in %s %s:%d\n", show, n, r, get_bits_count(s)-n, file, func, line); - return r; -} - -#define get_bits(s, n) get_bits_trace(s, n, __FILE__, __PRETTY_FUNCTION__, __LINE__) -#define get_bits1(s) get_bits_trace(s, 1, __FILE__, __PRETTY_FUNCTION__, __LINE__) -#define get_xbits(s, n) get_xbits_trace(s, n, __FILE__, __PRETTY_FUNCTION__, __LINE__) -#define get_vlc(s, vlc) get_vlc_trace(s, (vlc)->table, (vlc)->bits, 3, __FILE__, __PRETTY_FUNCTION__, __LINE__) -#define get_vlc2(s, tab, bits, max) get_vlc_trace(s, tab, bits, max, __FILE__, __PRETTY_FUNCTION__, __LINE__) - -#define tprintf printf - -#else //TRACE -#define tprintf(_arg...) {} -#endif - -/* define it to include statistics code (useful only for optimizing - codec efficiency */ -//#define STATS - -#ifdef STATS - -enum { - ST_UNKNOWN, - ST_DC, - ST_INTRA_AC, - ST_INTER_AC, - ST_INTRA_MB, - ST_INTER_MB, - ST_MV, - ST_NB, -}; - -extern int st_current_index; -extern unsigned int st_bit_counts[ST_NB]; -extern unsigned int st_out_bit_counts[ST_NB]; - -void print_stats(void); -#endif - -/* misc math functions */ -extern const uint8_t ff_log2_tab[256]; - -static inline int av_log2(unsigned int v) -{ - int n; - - n = 0; - if (v & 0xffff0000) { - v >>= 16; - n += 16; - } - if (v & 0xff00) { - v >>= 8; - n += 8; - } - n += ff_log2_tab[v]; - - return n; -} - -static inline int av_log2_16bit(unsigned int v) -{ - int n; - - n = 0; - if (v & 0xff00) { - v >>= 8; - n += 8; - } - n += ff_log2_tab[v]; - - return n; -} - - -/* median of 3 */ -static inline int mid_pred(int a, int b, int c) -{ - int vmin, vmax; - vmax = vmin = a; - if (b < vmin) - vmin = b; - else - vmax = b; - - if (c < vmin) - vmin = c; - else if (c > vmax) - vmax = c; - - return a + b + c - vmin - vmax; -} - -static inline int clip(int a, int amin, int amax) -{ - if (a < amin) - return amin; - else if (a > amax) - return amax; - else - return a; -} - -/* math */ -extern const uint8_t ff_sqrt_tab[128]; - -int64_t ff_gcd(int64_t a, int64_t b); - -static inline int ff_sqrt(int a) -{ - int ret=0; - int s; - int ret_sq=0; - - if(a<128) return ff_sqrt_tab[a]; - - for(s=15; s>=0; s--){ - int b= ret_sq + (1<<(s*2)) + (ret<>31;\ - level= (level^mask)-mask; -#endif - - -#if __CPU__ >= 686 && !defined(RUNTIME_CPUDETECT) -#define COPY3_IF_LT(x,y,a,b,c,d)\ -asm volatile (\ - "cmpl %0, %3 \n\t"\ - "cmovl %3, %0 \n\t"\ - "cmovl %4, %1 \n\t"\ - "cmovl %5, %2 \n\t"\ - : "+r" (x), "+r" (a), "+r" (c)\ - : "r" (y), "r" (b), "r" (d)\ -); -#else -#define COPY3_IF_LT(x,y,a,b,c,d)\ -if((y)<(x)){\ - (x)=(y);\ - (a)=(b);\ - (c)=(d);\ -} -#endif - -#ifdef ARCH_X86 -static inline long long rdtsc() -{ - long long l; - asm volatile( "rdtsc\n\t" - : "=A" (l) - ); - return l; -} - -#define START_TIMER \ -static uint64_t tsum=0;\ -static int tcount=0;\ -static int tskip_count=0;\ -uint64_t tend;\ -uint64_t tstart= rdtsc();\ - -#define STOP_TIMER(id) \ -tend= rdtsc();\ -if(tcount<2 || tend - tstart < 4*tsum/tcount){\ - tsum+= tend - tstart;\ - tcount++;\ -}else\ - tskip_count++;\ -if(256*256*256*64%(tcount+tskip_count)==0){\ - fprintf(stderr, "%Ld dezicycles in %s, %d runs, %d skips\n", tsum*10/tcount, id, tcount, tskip_count);\ -} -#endif - -#define CLAMP_TO_8BIT(d) ((d > 0xff) ? 0xff : (d < 0) ? 0 : d) - -/* avoid usage of various functions */ -#define malloc please_use_av_malloc -#define free please_use_av_free -#define realloc please_use_av_realloc - -#define CHECKED_ALLOCZ(p, size)\ -{\ - p= av_mallocz(size);\ - if(p==NULL && (size)!=0){\ - perror("malloc");\ - goto fail;\ - }\ -} - -#endif /* HAVE_AV_CONFIG_H */ - -#endif /* COMMON_H */ +/** + * @file common.h + * common internal api header. + */ + +#ifndef COMMON_H +#define COMMON_H + +#if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) +# define CONFIG_WIN32 +#endif + +//#define ALT_BITSTREAM_WRITER +//#define ALIGNED_BITSTREAM_WRITER + +#define ALT_BITSTREAM_READER +//#define LIBMPEG2_BITSTREAM_READER +//#define A32_BITSTREAM_READER +#define LIBMPEG2_BITSTREAM_READER_HACK //add BERO + +#ifdef HAVE_AV_CONFIG_H +/* only include the following when compiling package */ +# include "config.h" + +# include +# include +# include +# include +# ifndef __BEOS__ +# include +# else +# include "berrno.h" +# endif +# include + +# ifndef ENODATA +# define ENODATA 61 +# endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#include +#ifndef offsetof +# define offsetof(T,F) ((unsigned int)((char *)&((T *)0)->F)) +#endif + +#define AVOPTION_CODEC_BOOL(name, help, field) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_BOOL } +#define AVOPTION_CODEC_DOUBLE(name, help, field, minv, maxv, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_DOUBLE, minv, maxv, defval } +#define AVOPTION_CODEC_FLAG(name, help, field, flag, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_FLAG, flag, 0, defval } +#define AVOPTION_CODEC_INT(name, help, field, minv, maxv, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_INT, minv, maxv, defval } +#define AVOPTION_CODEC_STRING(name, help, field, str, val) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_STRING, .defval = val, .defstr = str } +#define AVOPTION_CODEC_RCOVERRIDE(name, help, field) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_RCOVERRIDE, .defval = 0, .defstr = NULL } +#define AVOPTION_SUB(ptr) { .name = NULL, .help = (const char*)ptr } +#define AVOPTION_END() AVOPTION_SUB(NULL) + +struct AVOption; +#ifdef HAVE_MMX +extern const struct AVOption avoptions_common[3 + 5]; +#else +extern const struct AVOption avoptions_common[3]; +#endif +extern const struct AVOption avoptions_workaround_bug[11]; + +#endif /* HAVE_AV_CONFIG_H */ + +/* Suppress restrict if it was not defined in config.h. */ +#ifndef restrict +# define restrict +#endif + +#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0) +# define always_inline __attribute__((always_inline)) inline +#else +# define always_inline inline +#endif + +#ifdef CONFIG_WIN32 + +/* windows */ + +typedef unsigned short uint16_t; +typedef signed short int16_t; +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; +typedef signed char int8_t; +typedef signed int int32_t; +typedef signed __int64 int64_t; + +# ifndef __MINGW32__ +# define int64_t_C(c) (c ## i64) +# define uint64_t_C(c) (c ## i64) + +# define inline __inline + +# else +# define int64_t_C(c) (c ## LL) +# define uint64_t_C(c) (c ## ULL) +# endif /* __MINGW32__ */ + +# ifdef _DEBUG +# define DEBUG +# endif + +# define snprintf _snprintf +# define vsnprintf _vsnprintf + +/* CONFIG_WIN32 end */ +#elif defined (CONFIG_OS2) +/* OS/2 EMX */ + +#include + +#ifndef int64_t_C +#define int64_t_C(c) (c ## LL) +#define uint64_t_C(c) (c ## ULL) +#endif + +#ifdef HAVE_AV_CONFIG_H + +#ifdef USE_FASTMEMCPY +#include "fastmemcpy.h" +#endif + +#include + +#endif /* HAVE_AV_CONFIG_H */ + +/* CONFIG_OS2 end */ +#else + +/* unix */ + +#include + +#ifndef int64_t_C +#define int64_t_C(c) (c ## LL) +#define uint64_t_C(c) (c ## ULL) +#endif + +#ifdef HAVE_AV_CONFIG_H + +# ifdef USE_FASTMEMCPY +# include "fastmemcpy.h" +# endif +# endif /* HAVE_AV_CONFIG_H */ + +#endif /* !CONFIG_WIN32 && !CONFIG_OS2 */ + +#ifdef HAVE_AV_CONFIG_H + +# include "bswap.h" + +# if defined(__MINGW32__) || defined(__CYGWIN__) || \ + defined(__OS2__) || (defined (__OpenBSD__) && !defined(__ELF__)) +# define MANGLE(a) "_" #a +# else +# define MANGLE(a) #a +# endif + +/* debug stuff */ + +# ifndef DEBUG +# define NDEBUG +# endif +# include + +/* dprintf macros */ +# if defined(CONFIG_WIN32) && !defined(__MINGW32__) + +inline void dprintf(const char* fmt,...) {} + +# else + +# ifdef DEBUG +# define dprintf(fmt,args...) printf(fmt, ## args) +# else +# define dprintf(fmt,args...) +# endif + +# endif /* !CONFIG_WIN32 */ + +# define av_abort() do { fprintf(stderr, "Abort at %s:%d\n", __FILE__, __LINE__); abort(); } while (0) + +//rounded divison & shift +#define RSHIFT(a,b) ((a) > 0 ? ((a) + (1<<((b)-1)))>>(b) : ((a) + (1<<((b)-1))-1)>>(b)) +/* assume b>0 */ +#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) +#define ABS(a) ((a) >= 0 ? (a) : (-(a))) + +#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) +#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) + +extern const uint32_t inverse[256]; + +#ifdef ARCH_X86 +# define FASTDIV(a,b) \ + ({\ + int ret,dmy;\ + asm volatile(\ + "mull %3"\ + :"=d"(ret),"=a"(dmy)\ + :"1"(a),"g"(inverse[b])\ + );\ + ret;\ + }) +#elif defined(CONFIG_FASTDIV) +# define FASTDIV(a,b) ((uint32_t)((((uint64_t)a)*inverse[b])>>32)) +#else +# define FASTDIV(a,b) ((a)/(b)) +#endif + +#ifdef ARCH_X86 +// avoid +32 for shift optimization (gcc should do that ...) +static inline int32_t NEG_SSR32( int32_t a, int8_t s){ + asm ("sarl %1, %0\n\t" + : "+r" (a) + : "ic" ((uint8_t)(-s)) + ); + return a; +} +static inline uint32_t NEG_USR32(uint32_t a, int8_t s){ + asm ("shrl %1, %0\n\t" + : "+r" (a) + : "ic" ((uint8_t)(-s)) + ); + return a; +} +#else +# define NEG_SSR32(a,s) ((( int32_t)(a))>>(32-(s))) +# define NEG_USR32(a,s) (((uint32_t)(a))>>(32-(s))) +#endif + +/* bit output */ + +struct PutBitContext; + +typedef void (*WriteDataFunc)(void *, uint8_t *, int); + +typedef struct PutBitContext { +#ifdef ALT_BITSTREAM_WRITER + uint8_t *buf, *buf_end; + int index; +#else + uint32_t bit_buf; + int bit_left; + uint8_t *buf, *buf_ptr, *buf_end; +#endif + int64_t data_out_size; /* in bytes */ +} PutBitContext; + +void init_put_bits(PutBitContext *s, + uint8_t *buffer, int buffer_size, + void *opaque, + void (*write_data)(void *, uint8_t *, int)); + +int64_t get_bit_count(PutBitContext *s); /* XXX: change function name */ +void align_put_bits(PutBitContext *s); +void flush_put_bits(PutBitContext *s); +void put_string(PutBitContext * pbc, char *s); + +/* bit input */ + +typedef struct GetBitContext { + const uint8_t *buffer, *buffer_end; +#ifdef ALT_BITSTREAM_READER + int index; +#elif defined LIBMPEG2_BITSTREAM_READER + uint8_t *buffer_ptr; + uint32_t cache; + int bit_count; +#elif defined A32_BITSTREAM_READER + uint32_t *buffer_ptr; + uint32_t cache0; + uint32_t cache1; + int bit_count; +#endif + int size_in_bits; +} GetBitContext; + +static inline int get_bits_count(GetBitContext *s); + +#define VLC_TYPE int16_t + +typedef struct VLC { + int bits; + VLC_TYPE (*table)[2]; ///< code, bits + int table_size, table_allocated; +} VLC; + +typedef struct RL_VLC_ELEM { + int16_t level; + int8_t len; + uint8_t run; +} RL_VLC_ELEM; + +#ifdef ARCH_SPARC64 +#define UNALIGNED_STORES_ARE_BAD +#endif + +/* used to avoid missaligned exceptions on some archs (alpha, ...) */ +#ifdef ARCH_X86 +# define unaligned32(a) (*(uint32_t*)(a)) +#else +# ifdef __GNUC__ +static inline uint32_t unaligned32(const void *v) { + struct Unaligned { + uint32_t i; + } __attribute__((packed)); + + return ((const struct Unaligned *) v)->i; +} +# elif defined(__DECC) +static inline uint32_t unaligned32(const void *v) { + return *(const __unaligned uint32_t *) v; +} +# else +static inline uint32_t unaligned32(const void *v) { + return *(const uint32_t *) v; +} +# endif +#endif //!ARCH_X86 + +#ifndef ALT_BITSTREAM_WRITER +static inline void put_bits(PutBitContext *s, int n, unsigned int value) +{ + unsigned int bit_buf; + int bit_left; + +#ifdef STATS + st_out_bit_counts[st_current_index] += n; +#endif + // DEBUG_LOG("put_bits=%d %x\n", n, value); + assert(n == 32 || value < (1U << n)); + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + + // DEBUG_LOG("n=%d value=%x cnt=%d buf=%x\n", n, value, bit_cnt, bit_buf); + /* XXX: optimize */ + if (n < bit_left) { + bit_buf = (bit_buf<> (n - bit_left); +#ifdef UNALIGNED_STORES_ARE_BAD + if (3 & (int) s->buf_ptr) { + s->buf_ptr[0] = bit_buf >> 24; + s->buf_ptr[1] = bit_buf >> 16; + s->buf_ptr[2] = bit_buf >> 8; + s->buf_ptr[3] = bit_buf ; + } else +#endif + *(uint32_t *)s->buf_ptr = be2me_32(bit_buf); + //DEBUG_LOG("bitbuf = %08x\n", bit_buf); + s->buf_ptr+=4; + bit_left+=32 - n; + bit_buf = value; + } + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} +#endif + + +#ifdef ALT_BITSTREAM_WRITER +static inline void put_bits(PutBitContext *s, int n, unsigned int value) +{ +# ifdef ALIGNED_BITSTREAM_WRITER +# ifdef ARCH_X86 + asm volatile( + "movl %0, %%ecx \n\t" + "xorl %%eax, %%eax \n\t" + "shrdl %%cl, %1, %%eax \n\t" + "shrl %%cl, %1 \n\t" + "movl %0, %%ecx \n\t" + "shrl $3, %%ecx \n\t" + "andl $0xFFFFFFFC, %%ecx \n\t" + "bswapl %1 \n\t" + "orl %1, (%2, %%ecx) \n\t" + "bswapl %%eax \n\t" + "addl %3, %0 \n\t" + "movl %%eax, 4(%2, %%ecx) \n\t" + : "=&r" (s->index), "=&r" (value) + : "r" (s->buf), "r" (n), "0" (s->index), "1" (value<<(-n)) + : "%eax", "%ecx" + ); +# else + int index= s->index; + uint32_t *ptr= ((uint32_t *)s->buf)+(index>>5); + + value<<= 32-n; + + ptr[0] |= be2me_32(value>>(index&31)); + ptr[1] = be2me_32(value<<(32-(index&31))); +//if(n>24) DEBUG_LOG("%d %d\n", n, value); + index+= n; + s->index= index; +# endif +# else //ALIGNED_BITSTREAM_WRITER +# ifdef ARCH_X86 + asm volatile( + "movl $7, %%ecx \n\t" + "andl %0, %%ecx \n\t" + "addl %3, %%ecx \n\t" + "negl %%ecx \n\t" + "shll %%cl, %1 \n\t" + "bswapl %1 \n\t" + "movl %0, %%ecx \n\t" + "shrl $3, %%ecx \n\t" + "orl %1, (%%ecx, %2) \n\t" + "addl %3, %0 \n\t" + "movl $0, 4(%%ecx, %2) \n\t" + : "=&r" (s->index), "=&r" (value) + : "r" (s->buf), "r" (n), "0" (s->index), "1" (value) + : "%ecx" + ); +# else + int index= s->index; + uint32_t *ptr= (uint32_t*)(((uint8_t *)s->buf)+(index>>3)); + + ptr[0] |= be2me_32(value<<(32-n-(index&7) )); + ptr[1] = 0; +//if(n>24) DEBUG_LOG("%d %d\n", n, value); + index+= n; + s->index= index; +# endif +# endif //!ALIGNED_BITSTREAM_WRITER +} +#endif + + +static inline uint8_t* pbBufPtr(PutBitContext *s) +{ +#ifdef ALT_BITSTREAM_WRITER + return s->buf + (s->index>>3); +#else + return s->buf_ptr; +#endif +} + +/* Bitstream reader API docs: +name + abritary name which is used as prefix for the internal variables + +gb + getbitcontext + +OPEN_READER(name, gb) + loads gb into local variables + +CLOSE_READER(name, gb) + stores local vars in gb + +UPDATE_CACHE(name, gb) + refills the internal cache from the bitstream + after this call at least MIN_CACHE_BITS will be available, + +GET_CACHE(name, gb) + will output the contents of the internal cache, next bit is MSB of 32 or 64 bit (FIXME 64bit) + +SHOW_UBITS(name, gb, num) + will return the nest num bits + +SHOW_SBITS(name, gb, num) + will return the nest num bits and do sign extension + +SKIP_BITS(name, gb, num) + will skip over the next num bits + note, this is equinvalent to SKIP_CACHE; SKIP_COUNTER + +SKIP_CACHE(name, gb, num) + will remove the next num bits from the cache (note SKIP_COUNTER MUST be called before UPDATE_CACHE / CLOSE_READER) + +SKIP_COUNTER(name, gb, num) + will increment the internal bit counter (see SKIP_CACHE & SKIP_BITS) + +LAST_SKIP_CACHE(name, gb, num) + will remove the next num bits from the cache if it is needed for UPDATE_CACHE otherwise it will do nothing + +LAST_SKIP_BITS(name, gb, num) + is equinvalent to SKIP_LAST_CACHE; SKIP_COUNTER + +for examples see get_bits, show_bits, skip_bits, get_vlc +*/ + +static inline int unaligned32_be(const void *v) +{ +#ifdef CONFIG_ALIGN + const uint8_t *p=v; + return (((p[0]<<8) | p[1])<<16) | (p[2]<<8) | (p[3]); +#else + return be2me_32( unaligned32(v)); //original +#endif +} + +#ifdef ALT_BITSTREAM_READER +# define MIN_CACHE_BITS 25 + +# define OPEN_READER(name, gb)\ + int name##_index= (gb)->index;\ + int name##_cache= 0;\ + +# define CLOSE_READER(name, gb)\ + (gb)->index= name##_index;\ + +# define UPDATE_CACHE(name, gb)\ + name##_cache= unaligned32_be( ((uint8_t *)(gb)->buffer)+(name##_index>>3) ) << (name##_index&0x07);\ + +# define SKIP_CACHE(name, gb, num)\ + name##_cache <<= (num);\ + +// FIXME name? +# define SKIP_COUNTER(name, gb, num)\ + name##_index += (num);\ + +# define SKIP_BITS(name, gb, num)\ + {\ + SKIP_CACHE(name, gb, num)\ + SKIP_COUNTER(name, gb, num)\ + }\ + +# define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num) +# define LAST_SKIP_CACHE(name, gb, num) ; + +# define SHOW_UBITS(name, gb, num)\ + NEG_USR32(name##_cache, num) + +# define SHOW_SBITS(name, gb, num)\ + NEG_SSR32(name##_cache, num) + +# define GET_CACHE(name, gb)\ + ((uint32_t)name##_cache) + +static inline int get_bits_count(GetBitContext *s){ + return s->index; +} +#elif defined LIBMPEG2_BITSTREAM_READER +//libmpeg2 like reader + +# define MIN_CACHE_BITS 17 + +# define OPEN_READER(name, gb)\ + int name##_bit_count=(gb)->bit_count;\ + int name##_cache= (gb)->cache;\ + uint8_t * name##_buffer_ptr=(gb)->buffer_ptr;\ + +# define CLOSE_READER(name, gb)\ + (gb)->bit_count= name##_bit_count;\ + (gb)->cache= name##_cache;\ + (gb)->buffer_ptr= name##_buffer_ptr;\ + +#ifdef LIBMPEG2_BITSTREAM_READER_HACK + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count >= 0){\ + name##_cache+= (int)be2me_16(*(uint16_t*)name##_buffer_ptr) << name##_bit_count;\ + ((uint16_t*)name##_buffer_ptr)++;\ + name##_bit_count-= 16;\ + }\ + +#else + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count >= 0){\ + name##_cache+= ((name##_buffer_ptr[0]<<8) + name##_buffer_ptr[1]) << name##_bit_count;\ + name##_buffer_ptr+=2;\ + name##_bit_count-= 16;\ + }\ + +#endif + +# define SKIP_CACHE(name, gb, num)\ + name##_cache <<= (num);\ + +# define SKIP_COUNTER(name, gb, num)\ + name##_bit_count += (num);\ + +# define SKIP_BITS(name, gb, num)\ + {\ + SKIP_CACHE(name, gb, num)\ + SKIP_COUNTER(name, gb, num)\ + }\ + +# define LAST_SKIP_BITS(name, gb, num) SKIP_BITS(name, gb, num) +# define LAST_SKIP_CACHE(name, gb, num) SKIP_CACHE(name, gb, num) + +# define SHOW_UBITS(name, gb, num)\ + NEG_USR32(name##_cache, num) + +# define SHOW_SBITS(name, gb, num)\ + NEG_SSR32(name##_cache, num) + +# define GET_CACHE(name, gb)\ + ((uint32_t)name##_cache) + +static inline int get_bits_count(GetBitContext *s){ + return (s->buffer_ptr - s->buffer)*8 - 16 + s->bit_count; +} + +#elif defined A32_BITSTREAM_READER + +# define MIN_CACHE_BITS 32 + +# define OPEN_READER(name, gb)\ + int name##_bit_count=(gb)->bit_count;\ + uint32_t name##_cache0= (gb)->cache0;\ + uint32_t name##_cache1= (gb)->cache1;\ + uint32_t * name##_buffer_ptr=(gb)->buffer_ptr;\ + +# define CLOSE_READER(name, gb)\ + (gb)->bit_count= name##_bit_count;\ + (gb)->cache0= name##_cache0;\ + (gb)->cache1= name##_cache1;\ + (gb)->buffer_ptr= name##_buffer_ptr;\ + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count > 0){\ + const uint32_t next= be2me_32( *name##_buffer_ptr );\ + name##_cache0 |= NEG_USR32(next,name##_bit_count);\ + name##_cache1 |= next<buffer_ptr - s->buffer)*8 - 32 + s->bit_count; +} + +#endif + +/** + * read mpeg1 dc style vlc (sign bit + mantisse with no MSB). + * if MSB not set it is negative + * @param n length in bits + * @author BERO + */ +static inline int get_xbits(GetBitContext *s, int n){ + register int tmp; + register int32_t cache; + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + cache = GET_CACHE(re,s); + if ((int32_t)cache<0) { //MSB=1 + tmp = NEG_USR32(cache,n); + } else { + // tmp = (-1<index+=n for the ALT_READER :)) + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + LAST_SKIP_BITS(re, s, n) + CLOSE_READER(re, s) +} + +static inline unsigned int get_bits1(GetBitContext *s){ +#ifdef ALT_BITSTREAM_READER + int index= s->index; + uint8_t result= s->buffer[ index>>3 ]; + result<<= (index&0x07); + result>>= 8 - 1; + index++; + s->index= index; + + return result; +#else + return get_bits(s, 1); +#endif +} + +static inline unsigned int show_bits1(GetBitContext *s){ + return show_bits(s, 1); +} + +static inline void skip_bits1(GetBitContext *s){ + skip_bits(s, 1); +} + +void init_get_bits(GetBitContext *s, + const uint8_t *buffer, int buffer_size); + +int check_marker(GetBitContext *s, const char *msg); +void align_get_bits(GetBitContext *s); +int init_vlc(VLC *vlc, int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size); +void free_vlc(VLC *vlc); + +/** + * + * if the vlc code is invalid and max_depth=1 than no bits will be removed + * if the vlc code is invalid and max_depth>1 than the number of bits removed + * is undefined + */ +#define GET_VLC(code, name, gb, table, bits, max_depth)\ +{\ + int n, index, nb_bits;\ +\ + index= SHOW_UBITS(name, gb, bits);\ + code = table[index][0];\ + n = table[index][1];\ +\ + if(max_depth > 1 && n < 0){\ + LAST_SKIP_BITS(name, gb, bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + code;\ + code = table[index][0];\ + n = table[index][1];\ + if(max_depth > 2 && n < 0){\ + LAST_SKIP_BITS(name, gb, nb_bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + code;\ + code = table[index][0];\ + n = table[index][1];\ + }\ + }\ + SKIP_BITS(name, gb, n)\ +} + +#define GET_RL_VLC(level, run, name, gb, table, bits, max_depth)\ +{\ + int n, index, nb_bits;\ +\ + index= SHOW_UBITS(name, gb, bits);\ + level = table[index].level;\ + n = table[index].len;\ +\ + if(max_depth > 1 && n < 0){\ + LAST_SKIP_BITS(name, gb, bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + level;\ + level = table[index].level;\ + n = table[index].len;\ + }\ + run= table[index].run;\ + SKIP_BITS(name, gb, n)\ +} + +// deprecated, dont use get_vlc for new code, use get_vlc2 instead or use GET_VLC directly +static inline int get_vlc(GetBitContext *s, VLC *vlc) +{ + int code; + VLC_TYPE (*table)[2]= vlc->table; + + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + + GET_VLC(code, re, s, table, vlc->bits, 3) + + CLOSE_READER(re, s) + return code; +} + +/** + * parses a vlc code, faster then get_vlc() + * @param bits is the number of bits which will be read at once, must be + * identical to nb_bits in init_vlc() + * @param max_depth is the number of times bits bits must be readed to completly + * read the longest vlc code + * = (max_vlc_length + bits - 1) / bits + */ +static always_inline int get_vlc2(GetBitContext *s, VLC_TYPE (*table)[2], + int bits, int max_depth) +{ + int code; + + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + + GET_VLC(code, re, s, table, bits, max_depth) + + CLOSE_READER(re, s) + return code; +} + +//#define TRACE + +#ifdef TRACE + +static inline void print_bin(int bits, int n){ + int i; + + for(i=n-1; i>=0; i--){ + DEBUG_LOG("%d", (bits>>i)&1); + } + for(i=n; i<24; i++) + DEBUG_LOG(" "); +} + +static inline int get_bits_trace(GetBitContext *s, int n, char *file, char *func, int line){ + int r= get_bits(s, n); + + print_bin(r, n); + DEBUG_LOG("%5d %2d %3d bit @%5d in %s %s:%d\n", r, n, r, get_bits_count(s)-n, file, func, line); + return r; +} +static inline int get_vlc_trace(GetBitContext *s, VLC_TYPE (*table)[2], int bits, int max_depth, char *file, char *func, int line){ + int show= show_bits(s, 24); + int pos= get_bits_count(s); + int r= get_vlc2(s, table, bits, max_depth); + int len= get_bits_count(s) - pos; + int bits2= show>>(24-len); + + print_bin(bits2, len); + + DEBUG_LOG("%5d %2d %3d vlc @%5d in %s %s:%d\n", bits2, len, r, pos, file, func, line); + return r; +} +static inline int get_xbits_trace(GetBitContext *s, int n, char *file, char *func, int line){ + int show= show_bits(s, n); + int r= get_xbits(s, n); + + print_bin(show, n); + DEBUG_LOG("%5d %2d %3d xbt @%5d in %s %s:%d\n", show, n, r, get_bits_count(s)-n, file, func, line); + return r; +} + +#define get_bits(s, n) get_bits_trace(s, n, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_bits1(s) get_bits_trace(s, 1, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_xbits(s, n) get_xbits_trace(s, n, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_vlc(s, vlc) get_vlc_trace(s, (vlc)->table, (vlc)->bits, 3, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_vlc2(s, tab, bits, max) get_vlc_trace(s, tab, bits, max, __FILE__, __PRETTY_FUNCTION__, __LINE__) + +#define tprintf printf + +#else //TRACE +#define tprintf(_arg...) {} +#endif + +/* define it to include statistics code (useful only for optimizing + codec efficiency */ +//#define STATS + +#ifdef STATS + +enum { + ST_UNKNOWN, + ST_DC, + ST_INTRA_AC, + ST_INTER_AC, + ST_INTRA_MB, + ST_INTER_MB, + ST_MV, + ST_NB, +}; + +extern int st_current_index; +extern unsigned int st_bit_counts[ST_NB]; +extern unsigned int st_out_bit_counts[ST_NB]; + +void print_stats(void); +#endif + +/* misc math functions */ +extern const uint8_t ff_log2_tab[256]; + +static inline int av_log2(unsigned int v) +{ + int n; + + n = 0; + if (v & 0xffff0000) { + v >>= 16; + n += 16; + } + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} + +static inline int av_log2_16bit(unsigned int v) +{ + int n; + + n = 0; + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} + + +/* median of 3 */ +static inline int mid_pred(int a, int b, int c) +{ + int vmin, vmax; + vmax = vmin = a; + if (b < vmin) + vmin = b; + else + vmax = b; + + if (c < vmin) + vmin = c; + else if (c > vmax) + vmax = c; + + return a + b + c - vmin - vmax; +} + +static inline int clip(int a, int amin, int amax) +{ + if (a < amin) + return amin; + else if (a > amax) + return amax; + else + return a; +} + +/* math */ +extern const uint8_t ff_sqrt_tab[128]; + +int64_t ff_gcd(int64_t a, int64_t b); + +static inline int ff_sqrt(int a) +{ + int ret=0; + int s; + int ret_sq=0; + + if(a<128) return ff_sqrt_tab[a]; + + for(s=15; s>=0; s--){ + int b= ret_sq + (1<<(s*2)) + (ret<>31;\ + level= (level^mask)-mask; +#endif + + +#if __CPU__ >= 686 && !defined(RUNTIME_CPUDETECT) +#define COPY3_IF_LT(x,y,a,b,c,d)\ +asm volatile (\ + "cmpl %0, %3 \n\t"\ + "cmovl %3, %0 \n\t"\ + "cmovl %4, %1 \n\t"\ + "cmovl %5, %2 \n\t"\ + : "+r" (x), "+r" (a), "+r" (c)\ + : "r" (y), "r" (b), "r" (d)\ +); +#else +#define COPY3_IF_LT(x,y,a,b,c,d)\ +if((y)<(x)){\ + (x)=(y);\ + (a)=(b);\ + (c)=(d);\ +} +#endif + +#ifdef ARCH_X86 +static inline long long rdtsc() +{ + long long l; + asm volatile( "rdtsc\n\t" + : "=A" (l) + ); + return l; +} + +#define START_TIMER \ +static uint64_t tsum=0;\ +static int tcount=0;\ +static int tskip_count=0;\ +uint64_t tend;\ +uint64_t tstart= rdtsc();\ + +#define STOP_TIMER(id) \ +tend= rdtsc();\ +if(tcount<2 || tend - tstart < 4*tsum/tcount){\ + tsum+= tend - tstart;\ + tcount++;\ +}else\ + tskip_count++;\ +if(256*256*256*64%(tcount+tskip_count)==0){\ + fprintf(stderr, "%Ld dezicycles in %s, %d runs, %d skips\n", tsum*10/tcount, id, tcount, tskip_count);\ +} +#endif + +#define CLAMP_TO_8BIT(d) ((d > 0xff) ? 0xff : (d < 0) ? 0 : d) + +/* avoid usage of various functions */ +#define malloc please_use_av_malloc +#define free please_use_av_free +#define realloc please_use_av_realloc + +#define CHECKED_ALLOCZ(p, size)\ +{\ + p= av_mallocz(size);\ + if(p==NULL && (size)!=0){\ + perror("malloc");\ + goto fail;\ + }\ +} + +#endif /* HAVE_AV_CONFIG_H */ + +#endif /* COMMON_H */ diff --git a/plugins/zerogs/dx/common/PS2Edefs.h b/plugins/zerogs/dx/common/PS2Edefs.h index 1f65fc02b9..49b16e16d5 100644 --- a/plugins/zerogs/dx/common/PS2Edefs.h +++ b/plugins/zerogs/dx/common/PS2Edefs.h @@ -1,885 +1,885 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef __PS2EDEFS_H__ -#define __PS2EDEFS_H__ - -/* - * PS2E Definitions v0.6.2 (beta) - * - * Author: linuzappz@hotmail.com - * shadowpcsx2@yahoo.gr - * florinsasu@hotmail.com - */ - -/* - Notes: - * Since this is still beta things may change. - - * OSflags: - __LINUX__ (linux OS) - _WIN32 (win32 OS) - - * common return values (for ie. GSinit): - 0 - success - -1 - error - - * reserved keys: - F1 to F10 are reserved for the emulator - - * plugins should NOT change the current - working directory. - (on win32, add flag OFN_NOCHANGEDIR for - GetOpenFileName) - -*/ - -#include "PS2Etypes.h" - - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ - defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ - defined(USBdefs) || defined(FWdefs) -#define COMMONdefs -#endif - -// PS2EgetLibType returns (may be OR'd) -#define PS2E_LT_GS 0x01 -#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- -#define PS2E_LT_SPU2 0x04 -#define PS2E_LT_CDVD 0x08 -#define PS2E_LT_DEV9 0x10 -#define PS2E_LT_USB 0x20 -#define PS2E_LT_FW 0x40 -#define PS2E_LT_SIO 0x80 - -// PS2EgetLibVersion2 (high 16 bits) -#define PS2E_GS_VERSION 0x0006 -#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- -#define PS2E_SPU2_VERSION 0x0005 -#define PS2E_CDVD_VERSION 0x0005 -#define PS2E_DEV9_VERSION 0x0003 -#define PS2E_USB_VERSION 0x0003 -#define PS2E_FW_VERSION 0x0002 -#define PS2E_SIO_VERSION 0x0001 -#ifdef COMMONdefs - -u32 CALLBACK PS2EgetLibType(void); -u32 CALLBACK PS2EgetLibVersion2(u32 type); -char* CALLBACK PS2EgetLibName(void); - -#endif - -// key values: -/* key values must be OS dependant: - win32: the VK_XXX will be used (WinUser) - linux: the XK_XXX will be used (XFree86) -*/ - -// event values: -#define KEYPRESS 1 -#define KEYRELEASE 2 - -typedef struct _keyEvent { - u32 key; - u32 evt; -} keyEvent; - -// for 64bit compilers -typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; - -// plugin types -#define SIO_TYPE_PAD 0x00000001 -#define SIO_TYPE_MTAP 0x00000004 -#define SIO_TYPE_RM 0x00000040 -#define SIO_TYPE_MC 0x00000100 - -typedef int (CALLBACK * SIOchangeSlotCB)(int slot); - -typedef struct _cdvdSubQ { - u8 ctrl:4; // control and mode bits - u8 mode:4; // control and mode bits - u8 trackNum; // current track number (1 to 99) - u8 trackIndex; // current index within track (0 to 99) - u8 trackM; // current minute location on the disc (BCD encoded) - u8 trackS; // current sector location on the disc (BCD encoded) - u8 trackF; // current frame location on the disc (BCD encoded) - u8 pad; // unused - u8 discM; // current minute offset from first track (BCD encoded) - u8 discS; // current sector offset from first track (BCD encoded) - u8 discF; // current frame offset from first track (BCD encoded) -} cdvdSubQ; - -typedef struct _cdvdTD { // NOT bcd coded - u32 lsn; - u8 type; -} cdvdTD; - -typedef struct _cdvdTN { - u8 strack; //number of the first track (usually 1) - u8 etrack; //number of the last track -} cdvdTN; - -// CDVDreadTrack mode values: -#define CDVD_MODE_2352 0 // full 2352 bytes -#define CDVD_MODE_2340 1 // skip sync (12) bytes -#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq - -// CDVDgetDiskType returns: -#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc -#define CDVD_TYPE_DVDV 0xfe // DVD Video -#define CDVD_TYPE_CDDA 0xfd // Audio CD -#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD -#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) -#define CDVD_TYPE_PS2CD 0x12 // PS2 CD -#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) -#define CDVD_TYPE_PSCD 0x10 // PS CD -#define CDVD_TYPE_UNKNOWN 0x05 // Unknown -#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided -#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided -#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd -#define CDVD_TYPE_DETCT 0x01 // Detecting -#define CDVD_TYPE_NODISC 0x00 // No Disc - -// CDVDgetTrayStatus returns: -#define CDVD_TRAY_CLOSE 0x00 -#define CDVD_TRAY_OPEN 0x01 - -// cdvdTD.type (track types for cds) -#define CDVD_AUDIO_TRACK 0x01 -#define CDVD_MODE1_TRACK 0x41 -#define CDVD_MODE2_TRACK 0x61 - -#define CDVD_AUDIO_MASK 0x00 -#define CDVD_DATA_MASK 0x40 -// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) - -typedef void (*DEV9callback)(int cycles); -typedef int (*DEV9handler)(void); - -typedef void (*USBcallback)(int cycles); -typedef int (*USBhandler)(void); - -// freeze modes: -#define FREEZE_LOAD 0 -#define FREEZE_SAVE 1 -#define FREEZE_SIZE 2 - -typedef struct _GSdriverInfo { - char name[8]; - void *common; -} GSdriverInfo; - -#ifdef _WINDOWS_ -typedef struct _winInfo { // unsupported values must be set to zero - HWND hWnd; - HMENU hMenu; - HWND hStatusWnd; -} winInfo; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* GS plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef GSdefs - -// basic funcs - -s32 CALLBACK GSinit(); -s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); -void CALLBACK GSclose(); -void CALLBACK GSshutdown(); -void CALLBACK GSvsync(int field); -void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); -void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); -void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); -void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) -void CALLBACK GSgifSoftReset(u32 mask); -void CALLBACK GSreadFIFO(u64 *mem); -void CALLBACK GSreadFIFO2(u64 *mem, int qwc); - -// extended funcs - -// GSkeyEvent gets called when there is a keyEvent from the PAD plugin -void CALLBACK GSkeyEvent(keyEvent *ev); -void CALLBACK GSchangeSaveState(int, const char* filename); -void CALLBACK GSmakeSnapshot(char *path); -void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); -void CALLBACK GSirqCallback(void (*callback)()); -void CALLBACK GSprintf(int timeout, char *fmt, ...); -void CALLBACK GSsetBaseMem(void*); -void CALLBACK GSsetGameCRC(int crc, int gameoptions); - -// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done -void CALLBACK GSsetFrameSkip(int frameskip); - -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK GSsetupRecording(int start, void* pData); - -void CALLBACK GSreset(); -void CALLBACK GSwriteCSR(u32 value); -void CALLBACK GSgetDriverInfo(GSdriverInfo *info); -#ifdef _WIN32 -s32 CALLBACK GSsetWindowInfo(winInfo *info); -#endif -s32 CALLBACK GSfreeze(int mode, freezeData *data); -void CALLBACK GSconfigure(); -void CALLBACK GSabout(); -s32 CALLBACK GStest(); - -#endif - -/* PAD plugin API -=[ OBSOLETE ]=- */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef PADdefs - -// basic funcs - -s32 CALLBACK PADinit(u32 flags); -s32 CALLBACK PADopen(void *pDsp); -void CALLBACK PADclose(); -void CALLBACK PADshutdown(); -// PADkeyEvent is called every vsync (return NULL if no event) -keyEvent* CALLBACK PADkeyEvent(); -u8 CALLBACK PADstartPoll(int pad); -u8 CALLBACK PADpoll(u8 value); -// returns: 1 if supported pad1 -// 2 if supported pad2 -// 3 if both are supported -u32 CALLBACK PADquery(); - -// call to give a hint to the PAD plugin to query for the keyboard state. A -// good plugin will query the OS for keyboard state ONLY in this function. -// This function is necessary when multithreading because otherwise -// the PAD plugin can get into deadlocks with the thread that really owns -// the window (and input). Note that PADupdate can be called from a different -// thread than the other functions, so mutex or other multithreading primitives -// have to be added to maintain data integrity. -void CALLBACK PADupdate(int pad); - -// extended funcs - -void CALLBACK PADgsDriverInfo(GSdriverInfo *info); -void CALLBACK PADconfigure(); -void CALLBACK PADabout(); -s32 CALLBACK PADtest(); - -#endif - -/* SIO plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SIOdefs - -// basic funcs - -s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); -s32 CALLBACK SIOopen(void *pDsp); -void CALLBACK SIOclose(); -void CALLBACK SIOshutdown(); -u8 CALLBACK SIOstartPoll(u8 value); -u8 CALLBACK SIOpoll(u8 value); -// returns: SIO_TYPE_{PAD,MTAP,RM,MC} -u32 CALLBACK SIOquery(); - -// extended funcs - -void CALLBACK SIOconfigure(); -void CALLBACK SIOabout(); -s32 CALLBACK SIOtest(); - -#endif - -/* SPU2 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SPU2defs - -// basic funcs - -s32 CALLBACK SPU2init(); -s32 CALLBACK SPU2open(void *pDsp); -void CALLBACK SPU2close(); -void CALLBACK SPU2shutdown(); -void CALLBACK SPU2write(u32 mem, u16 value); -u16 CALLBACK SPU2read(u32 mem); -void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA4(); -void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); -void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); - -// all addresses passed by dma will be pointers to the array starting at baseaddr -// This function is necessary to successfully save and reload the spu2 state -void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); - -void CALLBACK SPU2interruptDMA7(); -u32 CALLBACK SPU2ReadMemAddr(int core); -void CALLBACK SPU2WriteMemAddr(int core,u32 value); -void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); - -// extended funcs -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK SPU2setupRecording(int start, void* pData); - -void CALLBACK SPU2setClockPtr(u32* ptr); -void CALLBACK SPU2setTimeStretcher(short int enable); - -void CALLBACK SPU2async(u32 cycles); -s32 CALLBACK SPU2freeze(int mode, freezeData *data); -void CALLBACK SPU2configure(); -void CALLBACK SPU2about(); -s32 CALLBACK SPU2test(); - -#endif - -/* CDVD plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef CDVDdefs - -// basic funcs - -s32 CALLBACK CDVDinit(); -s32 CALLBACK CDVDopen(const char* pTitleFilename); -void CALLBACK CDVDclose(); -void CALLBACK CDVDshutdown(); -s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); - -// return can be NULL (for async modes) -u8* CALLBACK CDVDgetBuffer(); - -s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) -s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information -s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type -s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc -s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx -s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx -s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray -s32 CALLBACK CDVDctrlTrayClose(); //close disc tray - -// extended funcs - -void CALLBACK CDVDconfigure(); -void CALLBACK CDVDabout(); -s32 CALLBACK CDVDtest(); -void CALLBACK CDVDnewDiskCB(void (*callback)()); - -#endif - -/* DEV9 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef DEV9defs - -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK DEV9init(); -s32 CALLBACK DEV9open(void *pDsp); -void CALLBACK DEV9close(); -void CALLBACK DEV9shutdown(); -u8 CALLBACK DEV9read8(u32 addr); -u16 CALLBACK DEV9read16(u32 addr); -u32 CALLBACK DEV9read32(u32 addr); -void CALLBACK DEV9write8(u32 addr, u8 value); -void CALLBACK DEV9write16(u32 addr, u16 value); -void CALLBACK DEV9write32(u32 addr, u32 value); -void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); -void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK DEV9irqCallback(DEV9callback callback); -DEV9handler CALLBACK DEV9irqHandler(void); - -// extended funcs - -s32 CALLBACK DEV9freeze(int mode, freezeData *data); -void CALLBACK DEV9configure(); -void CALLBACK DEV9about(); -s32 CALLBACK DEV9test(); - -#endif - -/* USB plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef USBdefs - -// basic funcs - -s32 CALLBACK USBinit(); -s32 CALLBACK USBopen(void *pDsp); -void CALLBACK USBclose(); -void CALLBACK USBshutdown(); -u8 CALLBACK USBread8(u32 addr); -u16 CALLBACK USBread16(u32 addr); -u32 CALLBACK USBread32(u32 addr); -void CALLBACK USBwrite8(u32 addr, u8 value); -void CALLBACK USBwrite16(u32 addr, u16 value); -void CALLBACK USBwrite32(u32 addr, u32 value); -void CALLBACK USBasync(u32 cycles); - -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK USBirqCallback(USBcallback callback); -USBhandler CALLBACK USBirqHandler(void); -void CALLBACK USBsetRAM(void *mem); - -// extended funcs - -s32 CALLBACK USBfreeze(int mode, freezeData *data); -void CALLBACK USBconfigure(); -void CALLBACK USBabout(); -s32 CALLBACK USBtest(); - -#endif - -/* FW plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef FWdefs -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK FWinit(); -s32 CALLBACK FWopen(void *pDsp); -void CALLBACK FWclose(); -void CALLBACK FWshutdown(); -u32 CALLBACK FWread32(u32 addr); -void CALLBACK FWwrite32(u32 addr, u32 value); -void CALLBACK FWirqCallback(void (*callback)()); - -// extended funcs - -s32 CALLBACK FWfreeze(int mode, freezeData *data); -void CALLBACK FWconfigure(); -void CALLBACK FWabout(); -s32 CALLBACK FWtest(); -#endif - -// might be useful for emulators -#ifdef PLUGINtypedefs - -typedef u32 (CALLBACK* _PS2EgetLibType)(void); -typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); -typedef char*(CALLBACK* _PS2EgetLibName)(void); - -// GS -// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _GSinit)(); -typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); -typedef void (CALLBACK* _GSclose)(); -typedef void (CALLBACK* _GSshutdown)(); -typedef void (CALLBACK* _GSvsync)(int field); -typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); -typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) -typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); -typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); -typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); - -typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); -typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); -typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); -typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); -typedef void (CALLBACK* _GSsetBaseMem)(void*); -typedef void (CALLBACK* _GSsetGameCRC)(int, int); -typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); -typedef int (CALLBACK* _GSsetupRecording)(int, void*); -typedef void (CALLBACK* _GSreset)(); -typedef void (CALLBACK* _GSwriteCSR)(u32 value); -typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); -#ifdef _WINDOWS_ -typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); -#endif -typedef void (CALLBACK* _GSmakeSnapshot)(const char *path); -typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); -typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _GSconfigure)(); -typedef s32 (CALLBACK* _GStest)(); -typedef void (CALLBACK* _GSabout)(); - -// PAD -typedef s32 (CALLBACK* _PADinit)(u32 flags); -typedef s32 (CALLBACK* _PADopen)(void *pDsp); -typedef void (CALLBACK* _PADclose)(); -typedef void (CALLBACK* _PADshutdown)(); -typedef keyEvent* (CALLBACK* _PADkeyEvent)(); -typedef u8 (CALLBACK* _PADstartPoll)(int pad); -typedef u8 (CALLBACK* _PADpoll)(u8 value); -typedef u32 (CALLBACK* _PADquery)(); -typedef void (CALLBACK* _PADupdate)(int pad); - -typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); -typedef void (CALLBACK* _PADconfigure)(); -typedef s32 (CALLBACK* _PADtest)(); -typedef void (CALLBACK* _PADabout)(); - -// SIO -typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); -typedef s32 (CALLBACK* _SIOopen)(void *pDsp); -typedef void (CALLBACK* _SIOclose)(); -typedef void (CALLBACK* _SIOshutdown)(); -typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); -typedef u8 (CALLBACK* _SIOpoll)(u8 value); -typedef u32 (CALLBACK* _SIOquery)(); - -typedef void (CALLBACK* _SIOconfigure)(); -typedef s32 (CALLBACK* _SIOtest)(); -typedef void (CALLBACK* _SIOabout)(); - -// SPU2 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _SPU2init)(); -typedef s32 (CALLBACK* _SPU2open)(void *pDsp); -typedef void (CALLBACK* _SPU2close)(); -typedef void (CALLBACK* _SPU2shutdown)(); -typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); -typedef u16 (CALLBACK* _SPU2read)(u32 mem); -typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA4)(); -typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); -typedef void (CALLBACK* _SPU2interruptDMA7)(); -typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); -typedef int (CALLBACK* _SPU2setupRecording)(int, void*); - -typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); -typedef void (CALLBACK* _SPU2setTimeStretcher)(short int enable); - -typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); -typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); -typedef void (CALLBACK* _SPU2async)(u32 cycles); -typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _SPU2configure)(); -typedef s32 (CALLBACK* _SPU2test)(); -typedef void (CALLBACK* _SPU2about)(); - - -// CDVD -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _CDVDinit)(); -typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); -typedef void (CALLBACK* _CDVDclose)(); -typedef void (CALLBACK* _CDVDshutdown)(); -typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); -typedef u8* (CALLBACK* _CDVDgetBuffer)(); -typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); -typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); -typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); -typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); -typedef s32 (CALLBACK* _CDVDgetDiskType)(); -typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); -typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); -typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); - -typedef void (CALLBACK* _CDVDconfigure)(); -typedef s32 (CALLBACK* _CDVDtest)(); -typedef void (CALLBACK* _CDVDabout)(); -typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); - -// DEV9 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _DEV9init)(); -typedef s32 (CALLBACK* _DEV9open)(void *pDsp); -typedef void (CALLBACK* _DEV9close)(); -typedef void (CALLBACK* _DEV9shutdown)(); -typedef u8 (CALLBACK* _DEV9read8)(u32 mem); -typedef u16 (CALLBACK* _DEV9read16)(u32 mem); -typedef u32 (CALLBACK* _DEV9read32)(u32 mem); -typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); -typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); -typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); -typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); -typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); - -typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _DEV9configure)(); -typedef s32 (CALLBACK* _DEV9test)(); -typedef void (CALLBACK* _DEV9about)(); - -// USB -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _USBinit)(); -typedef s32 (CALLBACK* _USBopen)(void *pDsp); -typedef void (CALLBACK* _USBclose)(); -typedef void (CALLBACK* _USBshutdown)(); -typedef u8 (CALLBACK* _USBread8)(u32 mem); -typedef u16 (CALLBACK* _USBread16)(u32 mem); -typedef u32 (CALLBACK* _USBread32)(u32 mem); -typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); -typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); -typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _USBasync)(u32 cycles); - - -typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); -typedef USBhandler (CALLBACK* _USBirqHandler)(void); -typedef void (CALLBACK* _USBsetRAM)(void *mem); - -typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _USBconfigure)(); -typedef s32 (CALLBACK* _USBtest)(); -typedef void (CALLBACK* _USBabout)(); - -//FW -typedef s32 (CALLBACK* _FWinit)(); -typedef s32 (CALLBACK* _FWopen)(void *pDsp); -typedef void (CALLBACK* _FWclose)(); -typedef void (CALLBACK* _FWshutdown)(); -typedef u32 (CALLBACK* _FWread32)(u32 mem); -typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); - -typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _FWconfigure)(); -typedef s32 (CALLBACK* _FWtest)(); -typedef void (CALLBACK* _FWabout)(); - -#endif - -#ifdef PLUGINfuncs - -// GS -extern _GSinit GSinit; -extern _GSopen GSopen; -extern _GSclose GSclose; -extern _GSshutdown GSshutdown; -extern _GSvsync GSvsync; -extern _GSgifTransfer1 GSgifTransfer1; -extern _GSgifTransfer2 GSgifTransfer2; -extern _GSgifTransfer3 GSgifTransfer3; -extern _GSgetLastTag GSgetLastTag; -extern _GSgifSoftReset GSgifSoftReset; -extern _GSreadFIFO GSreadFIFO; -extern _GSreadFIFO2 GSreadFIFO2; - -extern _GSkeyEvent GSkeyEvent; -extern _GSchangeSaveState GSchangeSaveState; -extern _GSmakeSnapshot GSmakeSnapshot; -extern _GSmakeSnapshot2 GSmakeSnapshot2; -extern _GSirqCallback GSirqCallback; -extern _GSprintf GSprintf; -extern _GSsetBaseMem GSsetBaseMem; -extern _GSsetGameCRC GSsetGameCRC; -extern _GSsetFrameSkip GSsetFrameSkip; -extern _GSsetupRecording GSsetupRecording; -extern _GSreset GSreset; -extern _GSwriteCSR GSwriteCSR; -extern _GSgetDriverInfo GSgetDriverInfo; -#ifdef _WINDOWS_ -extern _GSsetWindowInfo GSsetWindowInfo; -#endif -extern _GSfreeze GSfreeze; -extern _GSconfigure GSconfigure; -extern _GStest GStest; -extern _GSabout GSabout; - -// PAD1 -extern _PADinit PAD1init; -extern _PADopen PAD1open; -extern _PADclose PAD1close; -extern _PADshutdown PAD1shutdown; -extern _PADkeyEvent PAD1keyEvent; -extern _PADstartPoll PAD1startPoll; -extern _PADpoll PAD1poll; -extern _PADquery PAD1query; -extern _PADupdate PAD1update; - -extern _PADgsDriverInfo PAD1gsDriverInfo; -extern _PADconfigure PAD1configure; -extern _PADtest PAD1test; -extern _PADabout PAD1about; - -// PAD2 -extern _PADinit PAD2init; -extern _PADopen PAD2open; -extern _PADclose PAD2close; -extern _PADshutdown PAD2shutdown; -extern _PADkeyEvent PAD2keyEvent; -extern _PADstartPoll PAD2startPoll; -extern _PADpoll PAD2poll; -extern _PADquery PAD2query; -extern _PADupdate PAD2update; - -extern _PADgsDriverInfo PAD2gsDriverInfo; -extern _PADconfigure PAD2configure; -extern _PADtest PAD2test; -extern _PADabout PAD2about; - -// SIO[2] -extern _SIOinit SIOinit[2][9]; -extern _SIOopen SIOopen[2][9]; -extern _SIOclose SIOclose[2][9]; -extern _SIOshutdown SIOshutdown[2][9]; -extern _SIOstartPoll SIOstartPoll[2][9]; -extern _SIOpoll SIOpoll[2][9]; -extern _SIOquery SIOquery[2][9]; - -extern _SIOconfigure SIOconfigure[2][9]; -extern _SIOtest SIOtest[2][9]; -extern _SIOabout SIOabout[2][9]; - -// SPU2 -extern _SPU2init SPU2init; -extern _SPU2open SPU2open; -extern _SPU2close SPU2close; -extern _SPU2shutdown SPU2shutdown; -extern _SPU2write SPU2write; -extern _SPU2read SPU2read; -extern _SPU2readDMA4Mem SPU2readDMA4Mem; -extern _SPU2writeDMA4Mem SPU2writeDMA4Mem; -extern _SPU2interruptDMA4 SPU2interruptDMA4; -extern _SPU2readDMA7Mem SPU2readDMA7Mem; -extern _SPU2writeDMA7Mem SPU2writeDMA7Mem; -extern _SPU2setDMABaseAddr SPU2setDMABaseAddr; -extern _SPU2interruptDMA7 SPU2interruptDMA7; -extern _SPU2ReadMemAddr SPU2ReadMemAddr; -extern _SPU2setupRecording SPU2setupRecording; -extern _SPU2WriteMemAddr SPU2WriteMemAddr; -extern _SPU2irqCallback SPU2irqCallback; - -extern _SPU2setClockPtr SPU2setClockPtr; -extern _SPU2setTimeStretcher SPU2setTimeStretcher; - -extern _SPU2async SPU2async; -extern _SPU2freeze SPU2freeze; -extern _SPU2configure SPU2configure; -extern _SPU2test SPU2test; -extern _SPU2about SPU2about; - -// CDVD -extern _CDVDinit CDVDinit; -extern _CDVDopen CDVDopen; -extern _CDVDclose CDVDclose; -extern _CDVDshutdown CDVDshutdown; -extern _CDVDreadTrack CDVDreadTrack; -extern _CDVDgetBuffer CDVDgetBuffer; -extern _CDVDreadSubQ CDVDreadSubQ; -extern _CDVDgetTN CDVDgetTN; -extern _CDVDgetTD CDVDgetTD; -extern _CDVDgetTOC CDVDgetTOC; -extern _CDVDgetDiskType CDVDgetDiskType; -extern _CDVDgetTrayStatus CDVDgetTrayStatus; -extern _CDVDctrlTrayOpen CDVDctrlTrayOpen; -extern _CDVDctrlTrayClose CDVDctrlTrayClose; - -extern _CDVDconfigure CDVDconfigure; -extern _CDVDtest CDVDtest; -extern _CDVDabout CDVDabout; -extern _CDVDnewDiskCB CDVDnewDiskCB; - -// DEV9 -extern _DEV9init DEV9init; -extern _DEV9open DEV9open; -extern _DEV9close DEV9close; -extern _DEV9shutdown DEV9shutdown; -extern _DEV9read8 DEV9read8; -extern _DEV9read16 DEV9read16; -extern _DEV9read32 DEV9read32; -extern _DEV9write8 DEV9write8; -extern _DEV9write16 DEV9write16; -extern _DEV9write32 DEV9write32; -extern _DEV9readDMA8Mem DEV9readDMA8Mem; -extern _DEV9writeDMA8Mem DEV9writeDMA8Mem; -extern _DEV9irqCallback DEV9irqCallback; -extern _DEV9irqHandler DEV9irqHandler; - -extern _DEV9configure DEV9configure; -extern _DEV9freeze DEV9freeze; -extern _DEV9test DEV9test; -extern _DEV9about DEV9about; - -// USB -extern _USBinit USBinit; -extern _USBopen USBopen; -extern _USBclose USBclose; -extern _USBshutdown USBshutdown; -extern _USBread8 USBread8; -extern _USBread16 USBread16; -extern _USBread32 USBread32; -extern _USBwrite8 USBwrite8; -extern _USBwrite16 USBwrite16; -extern _USBwrite32 USBwrite32; -extern _USBasync USBasync; - -extern _USBirqCallback USBirqCallback; -extern _USBirqHandler USBirqHandler; -extern _USBsetRAM USBsetRAM; - -extern _USBconfigure USBconfigure; -extern _USBfreeze USBfreeze; -extern _USBtest USBtest; -extern _USBabout USBabout; - -// FW -extern _FWinit FWinit; -extern _FWopen FWopen; -extern _FWclose FWclose; -extern _FWshutdown FWshutdown; -extern _FWread32 FWread32; -extern _FWwrite32 FWwrite32; -extern _FWirqCallback FWirqCallback; - -extern _FWconfigure FWconfigure; -extern _FWfreeze FWfreeze; -extern _FWtest FWtest; -extern _FWabout FWabout; -#endif - -#ifdef __cplusplus -} // End extern "C" -#endif - -#endif /* __PS2EDEFS_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct _keyEvent { + u32 key; + u32 evt; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct _cdvdSubQ { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct _cdvdTD { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct _cdvdTN { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct _GSdriverInfo { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WINDOWS_ +typedef struct _winInfo { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2setClockPtr(u32* ptr); +void CALLBACK SPU2setTimeStretcher(short int enable); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +void CALLBACK USBasync(u32 cycles); + +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WINDOWS_ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(const char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); + +typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); +typedef void (CALLBACK* _SPU2setTimeStretcher)(short int enable); + +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBasync)(u32 cycles); + + +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +extern _GSinit GSinit; +extern _GSopen GSopen; +extern _GSclose GSclose; +extern _GSshutdown GSshutdown; +extern _GSvsync GSvsync; +extern _GSgifTransfer1 GSgifTransfer1; +extern _GSgifTransfer2 GSgifTransfer2; +extern _GSgifTransfer3 GSgifTransfer3; +extern _GSgetLastTag GSgetLastTag; +extern _GSgifSoftReset GSgifSoftReset; +extern _GSreadFIFO GSreadFIFO; +extern _GSreadFIFO2 GSreadFIFO2; + +extern _GSkeyEvent GSkeyEvent; +extern _GSchangeSaveState GSchangeSaveState; +extern _GSmakeSnapshot GSmakeSnapshot; +extern _GSmakeSnapshot2 GSmakeSnapshot2; +extern _GSirqCallback GSirqCallback; +extern _GSprintf GSprintf; +extern _GSsetBaseMem GSsetBaseMem; +extern _GSsetGameCRC GSsetGameCRC; +extern _GSsetFrameSkip GSsetFrameSkip; +extern _GSsetupRecording GSsetupRecording; +extern _GSreset GSreset; +extern _GSwriteCSR GSwriteCSR; +extern _GSgetDriverInfo GSgetDriverInfo; +#ifdef _WINDOWS_ +extern _GSsetWindowInfo GSsetWindowInfo; +#endif +extern _GSfreeze GSfreeze; +extern _GSconfigure GSconfigure; +extern _GStest GStest; +extern _GSabout GSabout; + +// PAD1 +extern _PADinit PAD1init; +extern _PADopen PAD1open; +extern _PADclose PAD1close; +extern _PADshutdown PAD1shutdown; +extern _PADkeyEvent PAD1keyEvent; +extern _PADstartPoll PAD1startPoll; +extern _PADpoll PAD1poll; +extern _PADquery PAD1query; +extern _PADupdate PAD1update; + +extern _PADgsDriverInfo PAD1gsDriverInfo; +extern _PADconfigure PAD1configure; +extern _PADtest PAD1test; +extern _PADabout PAD1about; + +// PAD2 +extern _PADinit PAD2init; +extern _PADopen PAD2open; +extern _PADclose PAD2close; +extern _PADshutdown PAD2shutdown; +extern _PADkeyEvent PAD2keyEvent; +extern _PADstartPoll PAD2startPoll; +extern _PADpoll PAD2poll; +extern _PADquery PAD2query; +extern _PADupdate PAD2update; + +extern _PADgsDriverInfo PAD2gsDriverInfo; +extern _PADconfigure PAD2configure; +extern _PADtest PAD2test; +extern _PADabout PAD2about; + +// SIO[2] +extern _SIOinit SIOinit[2][9]; +extern _SIOopen SIOopen[2][9]; +extern _SIOclose SIOclose[2][9]; +extern _SIOshutdown SIOshutdown[2][9]; +extern _SIOstartPoll SIOstartPoll[2][9]; +extern _SIOpoll SIOpoll[2][9]; +extern _SIOquery SIOquery[2][9]; + +extern _SIOconfigure SIOconfigure[2][9]; +extern _SIOtest SIOtest[2][9]; +extern _SIOabout SIOabout[2][9]; + +// SPU2 +extern _SPU2init SPU2init; +extern _SPU2open SPU2open; +extern _SPU2close SPU2close; +extern _SPU2shutdown SPU2shutdown; +extern _SPU2write SPU2write; +extern _SPU2read SPU2read; +extern _SPU2readDMA4Mem SPU2readDMA4Mem; +extern _SPU2writeDMA4Mem SPU2writeDMA4Mem; +extern _SPU2interruptDMA4 SPU2interruptDMA4; +extern _SPU2readDMA7Mem SPU2readDMA7Mem; +extern _SPU2writeDMA7Mem SPU2writeDMA7Mem; +extern _SPU2setDMABaseAddr SPU2setDMABaseAddr; +extern _SPU2interruptDMA7 SPU2interruptDMA7; +extern _SPU2ReadMemAddr SPU2ReadMemAddr; +extern _SPU2setupRecording SPU2setupRecording; +extern _SPU2WriteMemAddr SPU2WriteMemAddr; +extern _SPU2irqCallback SPU2irqCallback; + +extern _SPU2setClockPtr SPU2setClockPtr; +extern _SPU2setTimeStretcher SPU2setTimeStretcher; + +extern _SPU2async SPU2async; +extern _SPU2freeze SPU2freeze; +extern _SPU2configure SPU2configure; +extern _SPU2test SPU2test; +extern _SPU2about SPU2about; + +// CDVD +extern _CDVDinit CDVDinit; +extern _CDVDopen CDVDopen; +extern _CDVDclose CDVDclose; +extern _CDVDshutdown CDVDshutdown; +extern _CDVDreadTrack CDVDreadTrack; +extern _CDVDgetBuffer CDVDgetBuffer; +extern _CDVDreadSubQ CDVDreadSubQ; +extern _CDVDgetTN CDVDgetTN; +extern _CDVDgetTD CDVDgetTD; +extern _CDVDgetTOC CDVDgetTOC; +extern _CDVDgetDiskType CDVDgetDiskType; +extern _CDVDgetTrayStatus CDVDgetTrayStatus; +extern _CDVDctrlTrayOpen CDVDctrlTrayOpen; +extern _CDVDctrlTrayClose CDVDctrlTrayClose; + +extern _CDVDconfigure CDVDconfigure; +extern _CDVDtest CDVDtest; +extern _CDVDabout CDVDabout; +extern _CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +extern _DEV9init DEV9init; +extern _DEV9open DEV9open; +extern _DEV9close DEV9close; +extern _DEV9shutdown DEV9shutdown; +extern _DEV9read8 DEV9read8; +extern _DEV9read16 DEV9read16; +extern _DEV9read32 DEV9read32; +extern _DEV9write8 DEV9write8; +extern _DEV9write16 DEV9write16; +extern _DEV9write32 DEV9write32; +extern _DEV9readDMA8Mem DEV9readDMA8Mem; +extern _DEV9writeDMA8Mem DEV9writeDMA8Mem; +extern _DEV9irqCallback DEV9irqCallback; +extern _DEV9irqHandler DEV9irqHandler; + +extern _DEV9configure DEV9configure; +extern _DEV9freeze DEV9freeze; +extern _DEV9test DEV9test; +extern _DEV9about DEV9about; + +// USB +extern _USBinit USBinit; +extern _USBopen USBopen; +extern _USBclose USBclose; +extern _USBshutdown USBshutdown; +extern _USBread8 USBread8; +extern _USBread16 USBread16; +extern _USBread32 USBread32; +extern _USBwrite8 USBwrite8; +extern _USBwrite16 USBwrite16; +extern _USBwrite32 USBwrite32; +extern _USBasync USBasync; + +extern _USBirqCallback USBirqCallback; +extern _USBirqHandler USBirqHandler; +extern _USBsetRAM USBsetRAM; + +extern _USBconfigure USBconfigure; +extern _USBfreeze USBfreeze; +extern _USBtest USBtest; +extern _USBabout USBabout; + +// FW +extern _FWinit FWinit; +extern _FWopen FWopen; +extern _FWclose FWclose; +extern _FWshutdown FWshutdown; +extern _FWread32 FWread32; +extern _FWwrite32 FWwrite32; +extern _FWirqCallback FWirqCallback; + +extern _FWconfigure FWconfigure; +extern _FWfreeze FWfreeze; +extern _FWtest FWtest; +extern _FWabout FWabout; +#endif + +#ifdef __cplusplus +} // End extern "C" +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/zerogs/dx/common/PS2Etypes.h b/plugins/zerogs/dx/common/PS2Etypes.h index 59be1c3de4..4c62b47f0f 100644 --- a/plugins/zerogs/dx/common/PS2Etypes.h +++ b/plugins/zerogs/dx/common/PS2Etypes.h @@ -1,219 +1,219 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef __PS2ETYPES_H__ -#define __PS2ETYPES_H__ - -#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case -#define __LINUX__ -#endif - -#ifdef __CYGWIN__ -#define __LINUX__ -#endif - -#ifndef ARRAYSIZE -#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) -#endif - -#ifdef __LINUX__ -#define CALLBACK -#else -#define CALLBACK __stdcall -#endif - - -// jASSUME - give hints to the optimizer -// This is primarily useful for the default case switch optimizer, which enables VC to -// generate more compact switches. - -#ifdef NDEBUG -# define jBREAKPOINT() ((void) 0) -# ifdef _MSC_VER -# define jASSUME(exp) (__assume(exp)) -# else -# define jASSUME(exp) ((void) sizeof(exp)) -# endif -#else -# if defined(_MSC_VER) -# define jBREAKPOINT() do { __asm int 3 } while(0) -# else -# define jBREAKPOINT() ((void) *(volatile char *) 0) -# endif -# define jASSUME(exp) if(exp) ; else jBREAKPOINT() -#endif - -// disable the default case in a switch -#define jNO_DEFAULT \ -{ \ - break; \ - \ -default: \ - jASSUME(0); \ - break; \ -} - - -// Basic types -#if defined(_MSC_VER) - -typedef __int8 s8; -typedef __int16 s16; -typedef __int32 s32; -typedef __int64 s64; - -typedef unsigned __int8 u8; -typedef unsigned __int16 u16; -typedef unsigned __int32 u32; -typedef unsigned __int64 u64; - -typedef unsigned int uint; - -#define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x -#define PCSX2_ALIGNED16(x) __declspec(align(16)) x -#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x - -#define __naked __declspec(naked) - -#else // _MSC_VER - -#ifdef __LINUX__ - -#ifdef HAVE_STDINT_H -#include "stdint.h" - -typedef int8_t s8; -typedef int16_t s16; -typedef int32_t s32; -typedef int64_t s64; - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -typedef uintptr_t uptr; -typedef intptr_t sptr; - -#else // HAVE_STDINT_H - -typedef char s8; -typedef short s16; -typedef int s32; -typedef long long s64; - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long long u64; - -#endif // HAVE_STDINT_H - -typedef unsigned int uint; - -#define LONG long -typedef union _LARGE_INTEGER -{ - long long QuadPart; -} LARGE_INTEGER; - -#define __fastcall __attribute__((fastcall)) -#define __unused __attribute__((unused)) -#define _inline __inline__ __attribute__((unused)) -#define __forceinline __attribute__((always_inline,unused)) -#define __naked // GCC lacks the naked specifier - -#endif // __LINUX__ - -#define PCSX2_ALIGNED(alig,x) x __attribute((aligned(alig))) -#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) - -#define PCSX2_ALIGNED16_DECL(x) x - -#endif // _MSC_VER - -#if !defined(__LINUX__) || !defined(HAVE_STDINT_H) -#if defined(__x86_64__) -typedef u64 uptr; -typedef s64 sptr; -#else -typedef u32 uptr; -typedef s32 sptr; -#endif -#endif - -// A rough-and-ready cross platform 128-bit datatype, Non-SSE style. -#ifdef __cplusplus -struct u128 -{ - u64 lo; - u64 hi; - - // Implicit conversion from u64 - u128( u64 src ) : - lo( src ) - , hi( 0 ) {} - - // Implicit conversion from u32 - u128( u32 src ) : - lo( src ) - , hi( 0 ) {} -}; - -struct s128 -{ - s64 lo; - s64 hi; - - // Implicit conversion from u64 - s128( s64 src ) : - lo( src ) - , hi( 0 ) {} - - // Implicit conversion from u32 - s128( s32 src ) : - lo( src ) - , hi( 0 ) {} -}; - -#else - -typedef union _u128_t -{ - u64 lo; - u64 hi; -} u128; - -typedef union _s128_t -{ - s64 lo; - s64 hi; -} s128; - -#endif - -typedef struct { - int size; - s8 *data; -} freezeData; - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#endif /* __PS2ETYPES_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +#ifdef __CYGWIN__ +#define __LINUX__ +#endif + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#ifdef __LINUX__ +#define CALLBACK +#else +#define CALLBACK __stdcall +#endif + + +// jASSUME - give hints to the optimizer +// This is primarily useful for the default case switch optimizer, which enables VC to +// generate more compact switches. + +#ifdef NDEBUG +# define jBREAKPOINT() ((void) 0) +# ifdef _MSC_VER +# define jASSUME(exp) (__assume(exp)) +# else +# define jASSUME(exp) ((void) sizeof(exp)) +# endif +#else +# if defined(_MSC_VER) +# define jBREAKPOINT() do { __asm int 3 } while(0) +# else +# define jBREAKPOINT() ((void) *(volatile char *) 0) +# endif +# define jASSUME(exp) if(exp) ; else jBREAKPOINT() +#endif + +// disable the default case in a switch +#define jNO_DEFAULT \ +{ \ + break; \ + \ +default: \ + jASSUME(0); \ + break; \ +} + + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +typedef unsigned int uint; + +#define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x + +#define __naked __declspec(naked) + +#else // _MSC_VER + +#ifdef __LINUX__ + +#ifdef HAVE_STDINT_H +#include "stdint.h" + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef uintptr_t uptr; +typedef intptr_t sptr; + +#else // HAVE_STDINT_H + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#endif // HAVE_STDINT_H + +typedef unsigned int uint; + +#define LONG long +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; + +#define __fastcall __attribute__((fastcall)) +#define __unused __attribute__((unused)) +#define _inline __inline__ __attribute__((unused)) +#define __forceinline __attribute__((always_inline,unused)) +#define __naked // GCC lacks the naked specifier + +#endif // __LINUX__ + +#define PCSX2_ALIGNED(alig,x) x __attribute((aligned(alig))) +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) + +#define PCSX2_ALIGNED16_DECL(x) x + +#endif // _MSC_VER + +#if !defined(__LINUX__) || !defined(HAVE_STDINT_H) +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif +#endif + +// A rough-and-ready cross platform 128-bit datatype, Non-SSE style. +#ifdef __cplusplus +struct u128 +{ + u64 lo; + u64 hi; + + // Implicit conversion from u64 + u128( u64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + u128( u32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +struct s128 +{ + s64 lo; + s64 hi; + + // Implicit conversion from u64 + s128( s64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + s128( s32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +#else + +typedef union _u128_t +{ + u64 lo; + u64 hi; +} u128; + +typedef union _s128_t +{ + s64 lo; + s64 hi; +} s128; + +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/zerogs/dx/memcpy_amd.cpp b/plugins/zerogs/dx/memcpy_amd.cpp index 9d22f60f36..17d546213b 100644 --- a/plugins/zerogs/dx/memcpy_amd.cpp +++ b/plugins/zerogs/dx/memcpy_amd.cpp @@ -1,479 +1,479 @@ -/****************************************************************************** - - Copyright (c) 2001 Advanced Micro Devices, Inc. - - LIMITATION OF LIABILITY: THE MATERIALS ARE PROVIDED *AS IS* WITHOUT ANY - EXPRESS OR IMPLIED WARRANTY OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, - NONINFRINGEMENT OF THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY - PARTICULAR PURPOSE. IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY - DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, - BUSINESS INTERRUPTION, LOSS OF INFORMATION) ARISING OUT OF THE USE OF OR - INABILITY TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY - OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE EXCLUSION OR LIMITATION - OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY - NOT APPLY TO YOU. - - AMD does not assume any responsibility for any errors which may appear in the - Materials nor any responsibility to support or update the Materials. AMD retains - the right to make changes to its test specifications at any time, without notice. - - NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any - further information, software, technical information, know-how, or show-how - available to you. - - So that all may benefit from your experience, please report any problems - or suggestions about this software to 3dsdk.support@amd.com - - AMD Developer Technologies, M/S 585 - Advanced Micro Devices, Inc. - 5900 E. Ben White Blvd. - Austin, TX 78741 - 3dsdk.support@amd.com -******************************************************************************/ - -#include - -/***************************************************************************** -MEMCPY_AMD.CPP -******************************************************************************/ - -// Very optimized memcpy() routine for AMD Athlon and Duron family. -// This code uses any of FOUR different basic copy methods, depending -// on the transfer size. -// NOTE: Since this code uses MOVNTQ (also known as "Non-Temporal MOV" or -// "Streaming Store"), and also uses the software prefetch instructions, -// be sure you're running on Athlon/Duron or other recent CPU before calling! - -#define TINY_BLOCK_COPY 64 // upper limit for movsd type copy -// The smallest copy uses the X86 "movsd" instruction, in an optimized -// form which is an "unrolled loop". - -#define IN_CACHE_COPY 2 * 1024 // upper limit for movq/movq copy w/SW prefetch -// Next is a copy that uses the MMX registers to copy 8 bytes at a time, -// also using the "unrolled loop" optimization. This code uses -// the software prefetch instruction to get the data into the cache. - -#define UNCACHED_COPY 4 * 1024 // upper limit for movq/movntq w/SW prefetch -// For larger blocks, which will spill beyond the cache, it's faster to -// use the Streaming Store instruction MOVNTQ. This write instruction -// bypasses the cache and writes straight to main memory. This code also -// uses the software prefetch instruction to pre-read the data. -// USE 64 * 1024 FOR THIS VALUE IF YOU'RE ALWAYS FILLING A "CLEAN CACHE" - -#define BLOCK_PREFETCH_COPY infinity // no limit for movq/movntq w/block prefetch -#define CACHEBLOCK 80h // number of 64-byte blocks (cache lines) for block prefetch -// For the largest size blocks, a special technique called Block Prefetch -// can be used to accelerate the read operations. Block Prefetch reads -// one address per cache line, for a series of cache lines, in a short loop. -// This is faster than using software prefetch. The technique is great for -// getting maximum read bandwidth, especially in DDR memory systems. - -//#include - -// Inline assembly syntax for use with Visual C++ -#ifdef _WIN32 -#include -#endif - -extern "C" { - -#include "PS2Etypes.h" - -#if defined(_MSC_VER) && !defined(__x86_64__) - -void * memcpy_amd(void *dest, const void *src, size_t n) -{ - __asm { - mov ecx, [n] ; number of bytes to copy - mov edi, [dest] ; destination - mov esi, [src] ; source - mov ebx, ecx ; keep a copy of count - - cld - cmp ecx, TINY_BLOCK_COPY - jb $memcpy_ic_3 ; tiny? skip mmx copy - - cmp ecx, 32*1024 ; don't align between 32k-64k because - jbe $memcpy_do_align ; it appears to be slower - cmp ecx, 64*1024 - jbe $memcpy_align_done -$memcpy_do_align: - mov ecx, 8 ; a trick that's faster than rep movsb... - sub ecx, edi ; align destination to qword - and ecx, 111b ; get the low bits - sub ebx, ecx ; update copy count - neg ecx ; set up to jump into the array - add ecx, offset $memcpy_align_done - jmp ecx ; jump to array of movsb's - -align 4 - movsb - movsb - movsb - movsb - movsb - movsb - movsb - movsb - -$memcpy_align_done: ; destination is dword aligned - mov ecx, ebx ; number of bytes left to copy - shr ecx, 6 ; get 64-byte block count - jz $memcpy_ic_2 ; finish the last few bytes - - cmp ecx, IN_CACHE_COPY/64 ; too big 4 cache? use uncached copy - jae $memcpy_uc_test - -// This is small block copy that uses the MMX registers to copy 8 bytes -// at a time. It uses the "unrolled loop" optimization, and also uses -// the software prefetch instruction to get the data into the cache. -align 16 -$memcpy_ic_1: ; 64-byte block copies, in-cache copy - - prefetchnta [esi + (200*64/34+192)] ; start reading ahead - - movq mm0, [esi+0] ; read 64 bits - movq mm1, [esi+8] - movq [edi+0], mm0 ; write 64 bits - movq [edi+8], mm1 ; note: the normal movq writes the - movq mm2, [esi+16] ; data to cache; a cache line will be - movq mm3, [esi+24] ; allocated as needed, to store the data - movq [edi+16], mm2 - movq [edi+24], mm3 - movq mm0, [esi+32] - movq mm1, [esi+40] - movq [edi+32], mm0 - movq [edi+40], mm1 - movq mm2, [esi+48] - movq mm3, [esi+56] - movq [edi+48], mm2 - movq [edi+56], mm3 - - add esi, 64 ; update source pointer - add edi, 64 ; update destination pointer - dec ecx ; count down - jnz $memcpy_ic_1 ; last 64-byte block? - -$memcpy_ic_2: - mov ecx, ebx ; has valid low 6 bits of the byte count -$memcpy_ic_3: - shr ecx, 2 ; dword count - and ecx, 1111b ; only look at the "remainder" bits - neg ecx ; set up to jump into the array - add ecx, offset $memcpy_last_few - jmp ecx ; jump to array of movsd's - -$memcpy_uc_test: - cmp ecx, UNCACHED_COPY/64 ; big enough? use block prefetch copy - jae $memcpy_bp_1 - -$memcpy_64_test: - or ecx, ecx ; tail end of block prefetch will jump here - jz $memcpy_ic_2 ; no more 64-byte blocks left - -// For larger blocks, which will spill beyond the cache, it's faster to -// use the Streaming Store instruction MOVNTQ. This write instruction -// bypasses the cache and writes straight to main memory. This code also -// uses the software prefetch instruction to pre-read the data. -align 16 -$memcpy_uc_1: ; 64-byte blocks, uncached copy - - prefetchnta [esi + (200*64/34+192)] ; start reading ahead - - movq mm0,[esi+0] ; read 64 bits - add edi,64 ; update destination pointer - movq mm1,[esi+8] - add esi,64 ; update source pointer - movq mm2,[esi-48] - movntq [edi-64], mm0 ; write 64 bits, bypassing the cache - movq mm0,[esi-40] ; note: movntq also prevents the CPU - movntq [edi-56], mm1 ; from READING the destination address - movq mm1,[esi-32] ; into the cache, only to be over-written - movntq [edi-48], mm2 ; so that also helps performance - movq mm2,[esi-24] - movntq [edi-40], mm0 - movq mm0,[esi-16] - movntq [edi-32], mm1 - movq mm1,[esi-8] - movntq [edi-24], mm2 - movntq [edi-16], mm0 - dec ecx - movntq [edi-8], mm1 - jnz $memcpy_uc_1 ; last 64-byte block? - - jmp $memcpy_ic_2 ; almost done - -// For the largest size blocks, a special technique called Block Prefetch -// can be used to accelerate the read operations. Block Prefetch reads -// one address per cache line, for a series of cache lines, in a short loop. -// This is faster than using software prefetch. The technique is great for -// getting maximum read bandwidth, especially in DDR memory systems. -$memcpy_bp_1: ; large blocks, block prefetch copy - - cmp ecx, CACHEBLOCK ; big enough to run another prefetch loop? - jl $memcpy_64_test ; no, back to regular uncached copy - - mov eax, CACHEBLOCK / 2 ; block prefetch loop, unrolled 2X - add esi, CACHEBLOCK * 64 ; move to the top of the block -align 16 -$memcpy_bp_2: - mov edx, [esi-64] ; grab one address per cache line - mov edx, [esi-128] ; grab one address per cache line - sub esi, 128 ; go reverse order to suppress HW prefetcher - dec eax ; count down the cache lines - jnz $memcpy_bp_2 ; keep grabbing more lines into cache - - mov eax, CACHEBLOCK ; now that it's in cache, do the copy -align 16 -$memcpy_bp_3: - movq mm0, [esi ] ; read 64 bits - movq mm1, [esi+ 8] - movq mm2, [esi+16] - movq mm3, [esi+24] - movq mm4, [esi+32] - movq mm5, [esi+40] - movq mm6, [esi+48] - movq mm7, [esi+56] - add esi, 64 ; update source pointer - movntq [edi ], mm0 ; write 64 bits, bypassing cache - movntq [edi+ 8], mm1 ; note: movntq also prevents the CPU - movntq [edi+16], mm2 ; from READING the destination address - movntq [edi+24], mm3 ; into the cache, only to be over-written, - movntq [edi+32], mm4 ; so that also helps performance - movntq [edi+40], mm5 - movntq [edi+48], mm6 - movntq [edi+56], mm7 - add edi, 64 ; update dest pointer - - dec eax ; count down - - jnz $memcpy_bp_3 ; keep copying - sub ecx, CACHEBLOCK ; update the 64-byte block count - jmp $memcpy_bp_1 ; keep processing chunks - -// The smallest copy uses the X86 "movsd" instruction, in an optimized -// form which is an "unrolled loop". Then it handles the last few bytes. -align 4 - movsd - movsd ; perform last 1-15 dword copies - movsd - movsd - movsd - movsd - movsd - movsd - movsd - movsd ; perform last 1-7 dword copies - movsd - movsd - movsd - movsd - movsd - movsd - -$memcpy_last_few: ; dword aligned from before movsd's - mov ecx, ebx ; has valid low 2 bits of the byte count - and ecx, 11b ; the last few cows must come home - jz $memcpy_final ; no more, let's leave - rep movsb ; the last 1, 2, or 3 bytes - -$memcpy_final: - emms ; clean up the MMX state - sfence ; flush the write buffer - mov eax, [dest] ; ret value = destination pointer - - } -} - -// mmx memcpy implementation, size has to be a multiple of 8 -// returns 0 is equal, nonzero value if not equal -// ~10 times faster than standard memcmp -// (zerofrog) -u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) -{ - assert( (cmpsize&7) == 0 ); - - __asm { -push esi - mov ecx, cmpsize - mov edx, src1 - mov esi, src2 - - cmp ecx, 32 - jl Done4 - - // custom test first 8 to make sure things are ok - movq mm0, [esi] - movq mm1, [esi+8] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pand mm0, mm1 - movq mm2, [esi+16] - pmovmskb eax, mm0 - movq mm3, [esi+24] - - // check if eq - cmp eax, 0xff - je NextComp - mov eax, 1 - jmp End - -NextComp: - pcmpeqd mm2, [edx+16] - pcmpeqd mm3, [edx+24] - pand mm2, mm3 - pmovmskb eax, mm2 - - sub ecx, 32 - add esi, 32 - add edx, 32 - - // check if eq - cmp eax, 0xff - je ContinueTest - mov eax, 1 - jmp End - - cmp ecx, 64 - jl Done8 - -Cmp8: - movq mm0, [esi] - movq mm1, [esi+8] - movq mm2, [esi+16] - movq mm3, [esi+24] - movq mm4, [esi+32] - movq mm5, [esi+40] - movq mm6, [esi+48] - movq mm7, [esi+56] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pcmpeqd mm2, [edx+16] - pcmpeqd mm3, [edx+24] - pand mm0, mm1 - pcmpeqd mm4, [edx+32] - pand mm0, mm2 - pcmpeqd mm5, [edx+40] - pand mm0, mm3 - pcmpeqd mm6, [edx+48] - pand mm0, mm4 - pcmpeqd mm7, [edx+56] - pand mm0, mm5 - pand mm0, mm6 - pand mm0, mm7 - pmovmskb eax, mm0 - - // check if eq - cmp eax, 0xff - je Continue - mov eax, 1 - jmp End - -Continue: - sub ecx, 64 - add esi, 64 - add edx, 64 -ContinueTest: - cmp ecx, 64 - jge Cmp8 - -Done8: - test ecx, 0x20 - jz Done4 - movq mm0, [esi] - movq mm1, [esi+8] - movq mm2, [esi+16] - movq mm3, [esi+24] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pcmpeqd mm2, [edx+16] - pcmpeqd mm3, [edx+24] - pand mm0, mm1 - pand mm0, mm2 - pand mm0, mm3 - pmovmskb eax, mm0 - sub ecx, 32 - add esi, 32 - add edx, 32 - - // check if eq - cmp eax, 0xff - je Done4 - mov eax, 1 - jmp End - -Done4: - cmp ecx, 24 - jne Done2 - movq mm0, [esi] - movq mm1, [esi+8] - movq mm2, [esi+16] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pcmpeqd mm2, [edx+16] - pand mm0, mm1 - pand mm0, mm2 - pmovmskb eax, mm0 - - // check if eq - cmp eax, 0xff - setne al - jmp End - -Done2: - cmp ecx, 16 - jne Done1 - - movq mm0, [esi] - movq mm1, [esi+8] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pand mm0, mm1 - pmovmskb eax, mm0 - - // check if eq - cmp eax, 0xff - setne al - jmp End - -Done1: - cmp ecx, 8 - jne Done - - mov eax, [esi] - mov esi, [esi+4] - cmp eax, [edx] - je Next - mov eax, 1 - jmp End - -Next: - cmp esi, [edx+4] - setne al - jmp End - -Done: - xor eax, eax - -End: - pop esi - emms - } -} - -#else // _MSC_VER -// assume gcc or mingw or win x64 - -#include -#include - -void * memcpy_amd(void *dest, const void *src, size_t n) -{ -memcpy(dest, src, n); -return dest; -} - - -#endif - -} +/****************************************************************************** + + Copyright (c) 2001 Advanced Micro Devices, Inc. + + LIMITATION OF LIABILITY: THE MATERIALS ARE PROVIDED *AS IS* WITHOUT ANY + EXPRESS OR IMPLIED WARRANTY OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, + NONINFRINGEMENT OF THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY + PARTICULAR PURPOSE. IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY + DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, + BUSINESS INTERRUPTION, LOSS OF INFORMATION) ARISING OUT OF THE USE OF OR + INABILITY TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY + OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE EXCLUSION OR LIMITATION + OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY + NOT APPLY TO YOU. + + AMD does not assume any responsibility for any errors which may appear in the + Materials nor any responsibility to support or update the Materials. AMD retains + the right to make changes to its test specifications at any time, without notice. + + NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any + further information, software, technical information, know-how, or show-how + available to you. + + So that all may benefit from your experience, please report any problems + or suggestions about this software to 3dsdk.support@amd.com + + AMD Developer Technologies, M/S 585 + Advanced Micro Devices, Inc. + 5900 E. Ben White Blvd. + Austin, TX 78741 + 3dsdk.support@amd.com +******************************************************************************/ + +#include + +/***************************************************************************** +MEMCPY_AMD.CPP +******************************************************************************/ + +// Very optimized memcpy() routine for AMD Athlon and Duron family. +// This code uses any of FOUR different basic copy methods, depending +// on the transfer size. +// NOTE: Since this code uses MOVNTQ (also known as "Non-Temporal MOV" or +// "Streaming Store"), and also uses the software prefetch instructions, +// be sure you're running on Athlon/Duron or other recent CPU before calling! + +#define TINY_BLOCK_COPY 64 // upper limit for movsd type copy +// The smallest copy uses the X86 "movsd" instruction, in an optimized +// form which is an "unrolled loop". + +#define IN_CACHE_COPY 2 * 1024 // upper limit for movq/movq copy w/SW prefetch +// Next is a copy that uses the MMX registers to copy 8 bytes at a time, +// also using the "unrolled loop" optimization. This code uses +// the software prefetch instruction to get the data into the cache. + +#define UNCACHED_COPY 4 * 1024 // upper limit for movq/movntq w/SW prefetch +// For larger blocks, which will spill beyond the cache, it's faster to +// use the Streaming Store instruction MOVNTQ. This write instruction +// bypasses the cache and writes straight to main memory. This code also +// uses the software prefetch instruction to pre-read the data. +// USE 64 * 1024 FOR THIS VALUE IF YOU'RE ALWAYS FILLING A "CLEAN CACHE" + +#define BLOCK_PREFETCH_COPY infinity // no limit for movq/movntq w/block prefetch +#define CACHEBLOCK 80h // number of 64-byte blocks (cache lines) for block prefetch +// For the largest size blocks, a special technique called Block Prefetch +// can be used to accelerate the read operations. Block Prefetch reads +// one address per cache line, for a series of cache lines, in a short loop. +// This is faster than using software prefetch. The technique is great for +// getting maximum read bandwidth, especially in DDR memory systems. + +//#include + +// Inline assembly syntax for use with Visual C++ +#ifdef _WIN32 +#include +#endif + +extern "C" { + +#include "PS2Etypes.h" + +#if defined(_MSC_VER) && !defined(__x86_64__) + +void * memcpy_amd(void *dest, const void *src, size_t n) +{ + __asm { + mov ecx, [n] ; number of bytes to copy + mov edi, [dest] ; destination + mov esi, [src] ; source + mov ebx, ecx ; keep a copy of count + + cld + cmp ecx, TINY_BLOCK_COPY + jb $memcpy_ic_3 ; tiny? skip mmx copy + + cmp ecx, 32*1024 ; don't align between 32k-64k because + jbe $memcpy_do_align ; it appears to be slower + cmp ecx, 64*1024 + jbe $memcpy_align_done +$memcpy_do_align: + mov ecx, 8 ; a trick that's faster than rep movsb... + sub ecx, edi ; align destination to qword + and ecx, 111b ; get the low bits + sub ebx, ecx ; update copy count + neg ecx ; set up to jump into the array + add ecx, offset $memcpy_align_done + jmp ecx ; jump to array of movsb's + +align 4 + movsb + movsb + movsb + movsb + movsb + movsb + movsb + movsb + +$memcpy_align_done: ; destination is dword aligned + mov ecx, ebx ; number of bytes left to copy + shr ecx, 6 ; get 64-byte block count + jz $memcpy_ic_2 ; finish the last few bytes + + cmp ecx, IN_CACHE_COPY/64 ; too big 4 cache? use uncached copy + jae $memcpy_uc_test + +// This is small block copy that uses the MMX registers to copy 8 bytes +// at a time. It uses the "unrolled loop" optimization, and also uses +// the software prefetch instruction to get the data into the cache. +align 16 +$memcpy_ic_1: ; 64-byte block copies, in-cache copy + + prefetchnta [esi + (200*64/34+192)] ; start reading ahead + + movq mm0, [esi+0] ; read 64 bits + movq mm1, [esi+8] + movq [edi+0], mm0 ; write 64 bits + movq [edi+8], mm1 ; note: the normal movq writes the + movq mm2, [esi+16] ; data to cache; a cache line will be + movq mm3, [esi+24] ; allocated as needed, to store the data + movq [edi+16], mm2 + movq [edi+24], mm3 + movq mm0, [esi+32] + movq mm1, [esi+40] + movq [edi+32], mm0 + movq [edi+40], mm1 + movq mm2, [esi+48] + movq mm3, [esi+56] + movq [edi+48], mm2 + movq [edi+56], mm3 + + add esi, 64 ; update source pointer + add edi, 64 ; update destination pointer + dec ecx ; count down + jnz $memcpy_ic_1 ; last 64-byte block? + +$memcpy_ic_2: + mov ecx, ebx ; has valid low 6 bits of the byte count +$memcpy_ic_3: + shr ecx, 2 ; dword count + and ecx, 1111b ; only look at the "remainder" bits + neg ecx ; set up to jump into the array + add ecx, offset $memcpy_last_few + jmp ecx ; jump to array of movsd's + +$memcpy_uc_test: + cmp ecx, UNCACHED_COPY/64 ; big enough? use block prefetch copy + jae $memcpy_bp_1 + +$memcpy_64_test: + or ecx, ecx ; tail end of block prefetch will jump here + jz $memcpy_ic_2 ; no more 64-byte blocks left + +// For larger blocks, which will spill beyond the cache, it's faster to +// use the Streaming Store instruction MOVNTQ. This write instruction +// bypasses the cache and writes straight to main memory. This code also +// uses the software prefetch instruction to pre-read the data. +align 16 +$memcpy_uc_1: ; 64-byte blocks, uncached copy + + prefetchnta [esi + (200*64/34+192)] ; start reading ahead + + movq mm0,[esi+0] ; read 64 bits + add edi,64 ; update destination pointer + movq mm1,[esi+8] + add esi,64 ; update source pointer + movq mm2,[esi-48] + movntq [edi-64], mm0 ; write 64 bits, bypassing the cache + movq mm0,[esi-40] ; note: movntq also prevents the CPU + movntq [edi-56], mm1 ; from READING the destination address + movq mm1,[esi-32] ; into the cache, only to be over-written + movntq [edi-48], mm2 ; so that also helps performance + movq mm2,[esi-24] + movntq [edi-40], mm0 + movq mm0,[esi-16] + movntq [edi-32], mm1 + movq mm1,[esi-8] + movntq [edi-24], mm2 + movntq [edi-16], mm0 + dec ecx + movntq [edi-8], mm1 + jnz $memcpy_uc_1 ; last 64-byte block? + + jmp $memcpy_ic_2 ; almost done + +// For the largest size blocks, a special technique called Block Prefetch +// can be used to accelerate the read operations. Block Prefetch reads +// one address per cache line, for a series of cache lines, in a short loop. +// This is faster than using software prefetch. The technique is great for +// getting maximum read bandwidth, especially in DDR memory systems. +$memcpy_bp_1: ; large blocks, block prefetch copy + + cmp ecx, CACHEBLOCK ; big enough to run another prefetch loop? + jl $memcpy_64_test ; no, back to regular uncached copy + + mov eax, CACHEBLOCK / 2 ; block prefetch loop, unrolled 2X + add esi, CACHEBLOCK * 64 ; move to the top of the block +align 16 +$memcpy_bp_2: + mov edx, [esi-64] ; grab one address per cache line + mov edx, [esi-128] ; grab one address per cache line + sub esi, 128 ; go reverse order to suppress HW prefetcher + dec eax ; count down the cache lines + jnz $memcpy_bp_2 ; keep grabbing more lines into cache + + mov eax, CACHEBLOCK ; now that it's in cache, do the copy +align 16 +$memcpy_bp_3: + movq mm0, [esi ] ; read 64 bits + movq mm1, [esi+ 8] + movq mm2, [esi+16] + movq mm3, [esi+24] + movq mm4, [esi+32] + movq mm5, [esi+40] + movq mm6, [esi+48] + movq mm7, [esi+56] + add esi, 64 ; update source pointer + movntq [edi ], mm0 ; write 64 bits, bypassing cache + movntq [edi+ 8], mm1 ; note: movntq also prevents the CPU + movntq [edi+16], mm2 ; from READING the destination address + movntq [edi+24], mm3 ; into the cache, only to be over-written, + movntq [edi+32], mm4 ; so that also helps performance + movntq [edi+40], mm5 + movntq [edi+48], mm6 + movntq [edi+56], mm7 + add edi, 64 ; update dest pointer + + dec eax ; count down + + jnz $memcpy_bp_3 ; keep copying + sub ecx, CACHEBLOCK ; update the 64-byte block count + jmp $memcpy_bp_1 ; keep processing chunks + +// The smallest copy uses the X86 "movsd" instruction, in an optimized +// form which is an "unrolled loop". Then it handles the last few bytes. +align 4 + movsd + movsd ; perform last 1-15 dword copies + movsd + movsd + movsd + movsd + movsd + movsd + movsd + movsd ; perform last 1-7 dword copies + movsd + movsd + movsd + movsd + movsd + movsd + +$memcpy_last_few: ; dword aligned from before movsd's + mov ecx, ebx ; has valid low 2 bits of the byte count + and ecx, 11b ; the last few cows must come home + jz $memcpy_final ; no more, let's leave + rep movsb ; the last 1, 2, or 3 bytes + +$memcpy_final: + emms ; clean up the MMX state + sfence ; flush the write buffer + mov eax, [dest] ; ret value = destination pointer + + } +} + +// mmx memcpy implementation, size has to be a multiple of 8 +// returns 0 is equal, nonzero value if not equal +// ~10 times faster than standard memcmp +// (zerofrog) +u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) +{ + assert( (cmpsize&7) == 0 ); + + __asm { +push esi + mov ecx, cmpsize + mov edx, src1 + mov esi, src2 + + cmp ecx, 32 + jl Done4 + + // custom test first 8 to make sure things are ok + movq mm0, [esi] + movq mm1, [esi+8] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pand mm0, mm1 + movq mm2, [esi+16] + pmovmskb eax, mm0 + movq mm3, [esi+24] + + // check if eq + cmp eax, 0xff + je NextComp + mov eax, 1 + jmp End + +NextComp: + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm2, mm3 + pmovmskb eax, mm2 + + sub ecx, 32 + add esi, 32 + add edx, 32 + + // check if eq + cmp eax, 0xff + je ContinueTest + mov eax, 1 + jmp End + + cmp ecx, 64 + jl Done8 + +Cmp8: + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + movq mm3, [esi+24] + movq mm4, [esi+32] + movq mm5, [esi+40] + movq mm6, [esi+48] + movq mm7, [esi+56] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm0, mm1 + pcmpeqd mm4, [edx+32] + pand mm0, mm2 + pcmpeqd mm5, [edx+40] + pand mm0, mm3 + pcmpeqd mm6, [edx+48] + pand mm0, mm4 + pcmpeqd mm7, [edx+56] + pand mm0, mm5 + pand mm0, mm6 + pand mm0, mm7 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + je Continue + mov eax, 1 + jmp End + +Continue: + sub ecx, 64 + add esi, 64 + add edx, 64 +ContinueTest: + cmp ecx, 64 + jge Cmp8 + +Done8: + test ecx, 0x20 + jz Done4 + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + movq mm3, [esi+24] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm0, mm1 + pand mm0, mm2 + pand mm0, mm3 + pmovmskb eax, mm0 + sub ecx, 32 + add esi, 32 + add edx, 32 + + // check if eq + cmp eax, 0xff + je Done4 + mov eax, 1 + jmp End + +Done4: + cmp ecx, 24 + jne Done2 + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pand mm0, mm1 + pand mm0, mm2 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + setne al + jmp End + +Done2: + cmp ecx, 16 + jne Done1 + + movq mm0, [esi] + movq mm1, [esi+8] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pand mm0, mm1 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + setne al + jmp End + +Done1: + cmp ecx, 8 + jne Done + + mov eax, [esi] + mov esi, [esi+4] + cmp eax, [edx] + je Next + mov eax, 1 + jmp End + +Next: + cmp esi, [edx+4] + setne al + jmp End + +Done: + xor eax, eax + +End: + pop esi + emms + } +} + +#else // _MSC_VER +// assume gcc or mingw or win x64 + +#include +#include + +void * memcpy_amd(void *dest, const void *src, size_t n) +{ +memcpy(dest, src, n); +return dest; +} + + +#endif + +} diff --git a/plugins/zerogs/dx/targets.cpp b/plugins/zerogs/dx/targets.cpp index ea8bd8af88..84b867cda0 100644 --- a/plugins/zerogs/dx/targets.cpp +++ b/plugins/zerogs/dx/targets.cpp @@ -1,3729 +1,3729 @@ -/* ZeroGS - * Copyright (C) 2005-2006 zerofrog@gmail.com - * - * 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 - */ - -#if defined(_WIN32) || defined(__WIN32__) -#include -#include -#endif - -#include - -#include -#include -#include -#include -#include - -#include "GS.h" -#include "Mem.h" -#include "x86.h" -#include "Regs.h" -#include "zerogs.h" -#include "resource.h" - -#include "targets.h" - -const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); - -extern int g_GameSettings; -using namespace ZeroGS; -extern int g_TransferredToGPU; -extern BOOL g_bIsLost; -extern LPD3DTEX ptexConv16to32; - -#ifdef RELEASE_TO_PUBLIC -#define INC_RESOLVE() -#else -#define INC_RESOLVE() ++g_nResolve -extern u32 g_nResolve; -extern BOOL g_bSaveTrans; -#endif - -namespace ZeroGS { - CRenderTargetMngr s_RTs, s_DepthRTs; - CBitwiseTextureMngr s_BitwiseTextures; - CMemoryTargetMngr g_MemTargs; - - extern BYTE s_AAx, s_AAy; - extern BYTE bIndepWriteMasks; - extern BOOL s_bBeginScene; - extern D3DFORMAT g_RenderFormat; - extern DXVEC4 g_vdepth; - extern int icurctx; - - extern LPD3DVS pvsBitBlt; - extern LPD3DPS ppsBitBlt[2], ppsBitBltDepth[2], ppsBitBltDepthTex[2], ppsOne; - extern LPD3DPS ppsBaseTexture, ppsConvert16to32, ppsConvert32to16; - extern LPD3DVB pvbRect; -} - -extern LPD3DTEX s_ptexCurSet[2]; -extern LPD3DTEX ptexBilinearBlocks; -extern IDirect3DVolumeTexture9* ptexConv32to16; -BOOL g_bSaveZUpdate = 0; - -//////////////////// -// Render Targets // -//////////////////// -ZeroGS::CRenderTarget::CRenderTarget() : psurf(NULL), psys(NULL), ptex(NULL), ptexFeedback(NULL), psurfFeedback(NULL) -{ - nUpdateTarg = 0; - targoffx = targoffy = 0; -} - -ZeroGS::CRenderTarget::~CRenderTarget() -{ - Destroy(); -} - -CRenderTarget::CRenderTarget(const frameInfo& frame, CRenderTarget& r) -{ - lastused = timeGetTime(); - fbp = frame.fbp; - fbw = frame.fbw; - fbh = frame.fbh; - psm = (u8)frame.psm; - fbm = frame.fbm; - - // find the xy offset - int blockheight = (frame.psm&2) ? 64 : 32; - int scanlinewidth = 0x2000*(fbw>>6); - - // round down to nearest block and scanline - int startheight = ((256*(fbp-r.fbp))/scanlinewidth) * blockheight; - int offset = ((256*(fbp-r.fbp))%scanlinewidth) / 0x2000; - - targoffx = offset*64; - targoffy = startheight; - targheight = r.targheight; - - pmimicparent = &r; - - vposxy.x = 2.0f * (32767.0f / 8.0f) / (float)fbw; - vposxy.y = -2.0f * (32767.0f / 8.0f) / (float)targheight; - vposxy.z = -1+(2.0f*(float)targoffx-0.5f)/fbw; - vposxy.w = 1+(-2.0f*(float)targoffy+0.5f)/(float)targheight; - status = 0; - - GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); - - ptex = r.ptex; - if( ptex != NULL ) ptex->AddRef(); - psurf = r.psurf; - if( psurf != NULL ) psurf->AddRef(); - psys = r.psys; - if( psys != NULL ) psys->AddRef(); - - nUpdateTarg = 0; - ptexFeedback = NULL; - psurfFeedback = NULL; -} - -BOOL ZeroGS::CRenderTarget::Create(const frameInfo& frame) -{ - Resolve(); - Destroy(); - - lastused = timeGetTime(); - fbp = frame.fbp; - fbw = frame.fbw; - fbh = frame.fbh; - psm = (u8)frame.psm; - fbm = frame.fbm; - pmimicparent = NULL; - - vposxy.x = 2.0f * (32767.0f / 8.0f) / (float)fbw; - vposxy.y = -2.0f * (32767.0f / 8.0f) / (float)fbh; - vposxy.z = -1+((float)targoffx-0.5f)/fbw; - vposxy.w = 1+((float)targoffy+0.5f)/fbh; - status = 0; - - if( fbw > 0 && fbh > 0 ) { - GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); - - HRESULT hr; - V(pd3dDevice->CreateTexture(fbw<CreateOffscreenPlainSurface(fbw<GetSurfaceLevel(0, &psurf)); - } - - if( FAILED(hr) ) { - Destroy(); - return FALSE; - } - - targheight = fbh; - status = TS_NeedUpdate; - } - else { - start = end = 0; - } - - return TRUE; -} - -void ZeroGS::CRenderTarget::Destroy() -{ - SAFE_RELEASE(psurf); - SAFE_RELEASE(psys); - SAFE_RELEASE(ptex); - SAFE_RELEASE(ptexFeedback); - SAFE_RELEASE(psurfFeedback); -} - -void ZeroGS::CRenderTarget::SetTarget(int fbplocal, const Rect2& scissor, int context) -{ - int dy = 0; - - if( fbplocal != fbp ) { - DXVEC4 v; - - // will be rendering to a subregion - u32 bpp = (psm&2) ? 2 : 4; - assert( ((256/bpp)*(fbplocal-fbp)) % fbw == 0 ); - assert( fbplocal >= fbp ); - - dy = ((256/bpp)*(fbplocal-fbp)) / fbw; - - v.x = vposxy.x; - v.y = vposxy.y; - v.z = vposxy.z; - v.w = vposxy.w - dy*2.0f/(float)fbh; - SETCONSTF(GPU_POSXY0+context, v); - } - else - SETCONSTF(GPU_POSXY0+context, vposxy); - - RECT rc; - - // set render states - rc.left = scissor.x0>>3; - rc.top = (scissor.y0>>3) + dy; - rc.right = (scissor.x1>>3)+1; - rc.bottom = (scissor.y1>>3)+1+dy; - rc.right = min(rc.right, fbw); - rc.bottom = min(rc.bottom, fbh); - - rc.left += targoffx; rc.right += targoffx; - rc.top += targoffy; rc.bottom += targoffy; - rc.left <<= s_AAx; - rc.top <<= s_AAy; - rc.right <<= s_AAx; - rc.bottom <<= s_AAy; -// rc.right--; -// rc.bottom--; - - scissorrect = rc; -} - -void ZeroGS::CRenderTarget::SetViewport() -{ - D3DVIEWPORT9 view; - view.Width = fbw<SetViewport(&view); -} - -static int g_bSaveResolved = 0; -extern int s_nResolved; - -void ZeroGS::CRenderTarget::Resolve() -{ - if( psurf != NULL && !(status&TS_Resolved) && !(status&TS_NeedUpdate) ) { - - // flush if necessary - if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); - if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); - - if( (IsDepth() && !ZeroGS::IsWriteDepth()) || s_nResolved > 10 || (g_GameSettings&GAME_NOTARGETRESOLVE) || targoffx != 0 || targoffy != 0) { - // don't resolve if depths aren't used - status = TS_Resolved; - return; - } - - D3DLOCKED_RECT locksrc; - pd3dDevice->GetRenderTargetData(psurf, psys); - -#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) - if( g_bSaveResolved ) { - D3DXSaveSurfaceToFile("resolved.tga", D3DXIFF_TGA, psys, NULL, NULL); - g_bSaveResolved = 0; - } -#endif - - psys->LockRect(&locksrc, NULL, D3DLOCK_READONLY); - _Resolve(locksrc, fbp, fbw, fbh, psm, fbm); - psys->UnlockRect(); - - status = TS_Resolved; - } -} - -void ZeroGS::CRenderTarget::Resolve(int startrange, int endrange) -{ - assert( startrange < end && endrange > start ); // make sure it at least intersects - - if( psurf != NULL && !(status&TS_Resolved) && !(status&TS_NeedUpdate) ) { - - // flush if necessary - if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); - if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); - -#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) - if( g_bSaveResolved ) { - D3DXSaveSurfaceToFile("resolved.tga", D3DXIFF_TGA, psys, NULL, NULL); - g_bSaveResolved = 0; - } -#endif - - if((g_GameSettings&GAME_NOTARGETRESOLVE) || targoffx != 0 || targoffy != 0) { - status = TS_Resolved; - return; - } - - int blockheight = (psm&2) ? 64 : 32; - int resolvefbp = fbp, resolveheight = fbh; - - int scanlinewidth = 0x2000*(fbw>>6); - - // in now way should data be overwritten!, instead resolve less - if( endrange < end ) { - // round down to nearest block and scanline - resolveheight = ((endrange-start)/(0x2000*(fbw>>6))) * blockheight; - if( resolveheight <= 32 ) { - status = TS_Resolved; - return; - } - } - else if( startrange > start ) { - // round up to nearest block and scanline - resolvefbp = startrange + scanlinewidth - 1; - resolvefbp -= resolvefbp % scanlinewidth; - - resolveheight = fbh-((resolvefbp-fbp)*blockheight/scanlinewidth); - if( resolveheight <= 64 ) { // this is a total hack, but kh doesn't resolve now - status = TS_Resolved; - return; - } - - resolvefbp >>= 8; - } - - D3DLOCKED_RECT locksrc; - pd3dDevice->GetRenderTargetData(psurf, psys); - - psys->LockRect(&locksrc, NULL, D3DLOCK_READONLY); - - if( fbp != resolvefbp ) - locksrc.pBits = (u8*)locksrc.pBits + ((resolvefbp-fbp)*256/scanlinewidth)*blockheight*locksrc.Pitch; - - _Resolve(locksrc, resolvefbp, fbw, resolveheight, psm, fbm); - psys->UnlockRect(); - - status = TS_Resolved; - } -} - -void ZeroGS::CRenderTarget::Update(int context, ZeroGS::CRenderTarget* pdepth) -{ - if( !s_bBeginScene ) { - pd3dDevice->BeginScene(); - s_bBeginScene = TRUE; - } - - assert( targoffx == 0 && targoffy == 0 ); - - SETRS(D3DRS_SCISSORTESTENABLE, FALSE); - SETRS(D3DRS_ALPHABLENDENABLE, FALSE); - SETRS(D3DRS_ALPHATESTENABLE, FALSE); - SETRS(D3DRS_ZENABLE, FALSE); - SETRS(D3DRS_ZWRITEENABLE, FALSE); - SETRS(D3DRS_COLORWRITEENABLE, 0xf); - - pd3dDevice->SetVertexShader(pvsBitBlt); - pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); - - // assume depth already set - //pd3dDevice->SetDepthStencilSurface(psurfDepth); -// if( conf.mrtdepth && bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); -// else - pd3dDevice->SetRenderTarget(1, NULL); - - pd3dDevice->SetRenderTarget(0, psurf); - - DXVEC4 v = DXVEC4(1,1,-0.5f/(float)(fbw<second == this ) { - DEBUG_LOG("zerogs: updating self"); - nUpdateTarg = 0; - } - } - else if( ittarg->second == this ) { - DEBUG_LOG("zerogs: updating self"); - nUpdateTarg = 0; - } - } - - if( nUpdateTarg ) { - - pd3dDevice->SetTexture(SAMP_FINAL, ittarg->second->ptex); - - //assert( ittarg->second->fbw == fbw ); - int offset = (fbp-ittarg->second->fbp)*64/fbw; - if( psm & 2 ) // 16 bit - offset *= 2; - - v.x = 1; - v.y = (float)targheight / ittarg->second->fbh; - v.z = 0.25f / (fbw << s_AAx); - v.w = (float)offset / ittarg->second->fbh + 0.25f / (ittarg->second->fbh << s_AAy); - SETCONSTF(GPU_BITBLTTEX, v); - - v.x = v.y = v.z = v.w = 1; - SETCONSTF(GPU_ONECOLOR, v); - - pd3dDevice->SetPixelShader(ppsBaseTexture); - nUpdateTarg = 0; - } - else { - // align the rect to the nearest page - // note that fbp is always aligned on page boundaries - tex0Info texframe; - texframe.tbp0 = fbp; - texframe.tbw = fbw; - texframe.tw = fbw; - texframe.th = fbh; - texframe.psm = psm; - CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); - - // write color and zero out stencil buf, always 0 context! - // force bilinear if using AA - SetTexVariablesInt(0, (s_AAx || s_AAy)?2:0, texframe, pmemtarg, 1); - - v = DXVEC4(1,1,0,0); - SETCONSTF(GPU_BITBLTTEX, v); - - v.x = 1; - v.y = 2; - SETCONSTF(GPU_ONECOLOR, v); - - assert( psurf != NULL ); - - SetViewport(); - - if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); - - if( ZeroGS::IsWriteDestAlphaTest() ) { - SETRS(D3DRS_STENCILENABLE, TRUE); - SETRS(D3DRS_STENCILWRITEMASK, 0xff); - SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); - SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_ZERO); - } - - // render with an AA shader if possible (bilinearly interpolates data) - pd3dDevice->SetPixelShader(ppsBitBlt[s_AAx]); - } - - pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); - - // fill stencil buf only - if( ZeroGS::IsWriteDestAlphaTest() && !(g_GameSettings&GAME_NOSTENCIL) ) { - SETRS(D3DRS_COLORWRITEENABLE, 0); - SETRS(D3DRS_ALPHATESTENABLE, TRUE); - SETRS(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); - SETRS(D3DRS_ALPHAREF, 0xff); - - SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); - SETRS(D3DRS_STENCILREF, 1); - - pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); - SETRS(D3DRS_COLORWRITEENABLE, 0xf); - } - - SETRS(D3DRS_SCISSORTESTENABLE, TRUE); - - if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); - -// if( conf.mrtdepth && bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); -// else - if( conf.mrtdepth && pdepth != NULL && ZeroGS::IsWriteDepth() ) - pd3dDevice->SetRenderTarget(1, pdepth->psurf); - - status = TS_Resolved; - - // reset since settings changed - vb[0].bVarsTexSync = 0; - ZeroGS::ResetAlphaVariables(); -} - -void ZeroGS::CRenderTarget::ConvertTo32() -{ - LPD3DTEX ptexConv; - LPD3DSURF psurfConv; - - s_RTs.DestroyChildren(this); - - // create - HRESULT hr; - V(pd3dDevice->CreateTexture(fbw<GetSurfaceLevel(0, &psurfConv)); - - if( !s_bBeginScene ) { - pd3dDevice->BeginScene(); - s_bBeginScene = TRUE; - } - - SETRS(D3DRS_SCISSORTESTENABLE, FALSE); - SETRS(D3DRS_ALPHABLENDENABLE, FALSE); - SETRS(D3DRS_ALPHATESTENABLE, FALSE); - SETRS(D3DRS_ZENABLE, FALSE); - SETRS(D3DRS_ZWRITEENABLE, FALSE); - SETRS(D3DRS_STENCILENABLE, FALSE); - SETRS(D3DRS_COLORWRITEENABLE, 0xf); - - // tex coords, test ffx bikanel island when changing these - float dx = 0.5f / (fbw << s_AAx); - float dy = 0.5f / (fbh << s_AAy); - - DXVEC4 v = DXVEC4(1, 1, -dx, dy); - SETCONSTF(GPU_BITBLTPOS, v); - - v.z = 0.5f*dx; - v.w = 0.5f*dy; - SETCONSTF(GPU_BITBLTTEX, v); - - v.x = v.y = v.z = 1; - v.w = 1; // since all alpha is mult by 2 - SETCONSTF(GPU_ONECOLOR, v); - - v.x = 16.0f / (float)fbw; - v.y = 64.0f / (float)fbh; - v.z = 0.5f * v.x; - v.w = 0.5f * v.y; - SETCONSTF(GPU_TEXOFFSET0, v); - - v.x = 8.0f / (float)fbw; - v.y = 0; - v.z = 0; - v.w = 0.25f; - SETCONSTF(GPU_PAGEOFFSET0, v); - - v.x = 1; - v.y = -0.5f; - v.z = 0; - v.w = 0.0001f; - SETCONSTF(GPU_TEXDIMS0, v); - - v.x = 0; - SETCONSTF(GPU_TEXBLOCK0, v); - - pd3dDevice->SetVertexShader(pvsBitBlt); - pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); - - // assume depth already set !? - pd3dDevice->SetRenderTarget(1, NULL); - pd3dDevice->SetRenderTarget(0, psurfConv); - pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexConv32to16); - pd3dDevice->SetTexture(SAMP_FINAL, ptex); - - pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_POINT); - - if( s_ptexCurSet[0] == ptex ) { - s_ptexCurSet[0] = NULL; - pd3dDevice->SetTexture(SAMP_MEMORY0, NULL); - } - if( s_ptexCurSet[1] == ptex ) { - s_ptexCurSet[1] = NULL; - pd3dDevice->SetTexture(SAMP_MEMORY1, NULL); - } - - fbh /= 2; // have 16 bit surfaces are usually 2x higher - targheight /= 2; - - SetViewport(); - - if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); - - // render with an AA shader if possible (bilinearly interpolates data) - pd3dDevice->SetPixelShader(ppsConvert16to32); - pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); - -#ifdef _DEBUG - //g_bSaveZUpdate = 1; - //D3DXSaveSurfaceToFile("tex3.tga", D3DXIFF_TGA, psurfConv, NULL, NULL); - if( g_bSaveZUpdate ) { - // buggy - D3DXSaveSurfaceToFile("tex3.tga", D3DXIFF_TGA, psurfConv, NULL, NULL); - D3DXSaveSurfaceToFile("tex1.tga", D3DXIFF_TGA, psurf, NULL, NULL); - - //LPD3DTEX ptemp; - //pd3dDevice->CreateTexture(fbw, fbh, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &ptemp, NULL); - - LPD3DSURF ptempsys; - V(pd3dDevice->CreateOffscreenPlainSurface(fbw<GetRenderTargetData(psurf, psys); - - psys->LockRect(&srclock, NULL, D3DLOCK_READONLY); - ptempsys->LockRect(&dstlock, NULL, 0); - DWORD cols[2]; - float tempf[4]; - for(int i = 0; i < fbh; ++i) { - for(int j = 0; j < fbw; ++j) { - D3DXVECTOR4_16F* pdst = (D3DXVECTOR4_16F*)dstlock.pBits + fbw*i + j; - int jj = 2*j - (j%16); - if( (j%16) >=8 ) jj += 8; - int ii = 2*i - (i%8); - if( j >= fbw/2 ) { ii += 8; jj -= fbw; } - D3DXVECTOR4_16F* psrc = (D3DXVECTOR4_16F*)srclock.pBits + fbw*ii + jj; - //D3DXFloat16To32Array(out, (D3DXFLOAT16*)psrc, 4); - cols[0] = Float16ToARGB(psrc[0]); - cols[1] = Float16ToARGB(psrc[8]); - //cols[0] = (cols[0]&0xff00ff00)|((cols[0]&0xff)<<16)|((cols[0]&0xff0000)>>16); - //cols[1] = (cols[1]&0xff00ff00)|((cols[1]&0xff)<<16)|((cols[1]&0xff0000)>>16); - DWORD col = RGBA32to16(cols[0])|(RGBA32to16(cols[1])<<16); - tempf[2] = (col&0xff)/255.0f; - tempf[1] = ((col>>8)&0xff)/255.0f; - tempf[0] = ((col>>16)&0xff)/255.0f; - tempf[3] = 2*(((col>>24)&0xff)/255.0f); - D3DXFloat32To16Array((D3DXFLOAT16*)pdst, tempf, 4); - } - } - psys->UnlockRect(); - ptempsys->UnlockRect(); - - D3DXSaveSurfaceToFile("tex2.tga", D3DXIFF_TGA, ptempsys, NULL, NULL); - -// SAFE_RELEASE(psys); -// psys = ptempsys; -// -// pd3dDevice->UpdateSurface(ptempsys, NULL, psurfConv, NULL); - } -#endif - - vposxy.y = -2.0f * (32767.0f / 8.0f) / (float)fbh; - vposxy.w = 1+0.5f/fbh; - - // restore - SAFE_RELEASE(ptex); - SAFE_RELEASE(psurf); - SAFE_RELEASE(psys); - SAFE_RELEASE(ptexFeedback); - SAFE_RELEASE(psurfFeedback); - ptex = ptexConv; - psurf = psurfConv; - - V(pd3dDevice->CreateOffscreenPlainSurface(fbw<SetTexture(SAMP_FINAL, NULL); - pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexBilinearBlocks); // restore - pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); - pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); - pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - SETRS(D3DRS_SCISSORTESTENABLE, TRUE); - - status = TS_Resolved; - - // TODO, reset depth? - if( ZeroGS::icurctx >= 0 ) { - // reset since settings changed - vb[icurctx].bVarsTexSync = 0; - vb[icurctx].bVarsSetTarg = 0; - } - vb[0].bVarsTexSync = 0; -} - -// use when texture is not tiled and converting from 32bit to 16bit -// one condition is that the converted texture has to keep the same block configuration -// every 16 32bit horz pixels gets converted to 16x2 16bit horz pixels. -// the first row is the first 8 pixels, the second row is the last 8 pixels -// the last 8 columns are the upper bits -void ZeroGS::CRenderTarget::ConvertTo16() -{ - LPD3DTEX ptexConv; - LPD3DSURF psurfConv; - - s_RTs.DestroyChildren(this); - - // create - HRESULT hr; - V(pd3dDevice->CreateTexture(fbw<GetSurfaceLevel(0, &psurfConv)); - - if( !s_bBeginScene ) { - pd3dDevice->BeginScene(); - s_bBeginScene = TRUE; - } - - SETRS(D3DRS_SCISSORTESTENABLE, FALSE); - SETRS(D3DRS_ALPHABLENDENABLE, FALSE); - SETRS(D3DRS_ALPHATESTENABLE, FALSE); - SETRS(D3DRS_ZENABLE, FALSE); - SETRS(D3DRS_ZWRITEENABLE, FALSE); - SETRS(D3DRS_STENCILENABLE, FALSE); - SETRS(D3DRS_COLORWRITEENABLE, 0xf); - - // tex coords, test ffx bikanel island when changing these - float dx = 0.5f / (fbw << s_AAx); - float dy = 0.5f / (fbh << s_AAy); - - DXVEC4 v = DXVEC4(1, 1, -dx, dy); - SETCONSTF(GPU_BITBLTPOS, v); - - v.z = 0.5f*dx; - v.w = 0.5f*dy; - SETCONSTF(GPU_BITBLTTEX, v); - - v.x = v.y = v.z = 1; - v.w = 2; // since all alpha is mult by 2 - SETCONSTF(GPU_ONECOLOR, v); - - v.x = 16.0f / (float)fbw; - v.y = 32.0f / (float)fbh; - v.z = 0.5f * v.x; - v.w = 0.5f * v.y; - SETCONSTF(GPU_TEXOFFSET0, v); - - v.x = 256.0f / 255.0f; - v.y = 256.0f / 255.0f; - v.z = 0.05f / 256.0f; - v.w = -0.001f / 256.0f; - SETCONSTF(GPU_PAGEOFFSET0, v); - - v.x = -0.5f; - v.y = 1; - v.z = 0; - v.w = -0.1f/fbh; - SETCONSTF(GPU_TEXDIMS0, v); - - pd3dDevice->SetVertexShader(pvsBitBlt); - pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); - - // assume depth already set !? - pd3dDevice->SetRenderTarget(1, NULL); - pd3dDevice->SetRenderTarget(0, psurfConv); - pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexConv16to32); - pd3dDevice->SetTexture(SAMP_FINAL, ptex); - - pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_POINT); - - if( s_ptexCurSet[0] == ptex ) { - s_ptexCurSet[0] = NULL; - pd3dDevice->SetTexture(SAMP_MEMORY0, NULL); - } - if( s_ptexCurSet[1] == ptex ) { - s_ptexCurSet[1] = NULL; - pd3dDevice->SetTexture(SAMP_MEMORY1, NULL); - } - - fbh *= 2; // have 16 bit surfaces are usually 2x higher - targheight *= 2; - - // need to set a dummy target! -// CRenderTargetMngr::MAPTARGETS::iterator itdepth = s_DepthRTs.mapDummyTargs.find( (fbw<<16)|fbh ); -// CDepthTarget* pnewdepth = NULL; -// if( itdepth == s_DepthRTs.mapDummyTargs.end() ) { -// frameInfo frame; -// frame.fbh = fbh; -// frame.fbw = fbw; -// frame.psm = 0x30; //? -// frame.fbw = fbw; -// frame.fbm = 0; -// pnewdepth = new CDepthTarget(); -// pnewdepth->Create(frame); -// s_DepthRTs.mapDummyTargs[(fbw<<16)|fbh] = pnewdepth; -// } -// else pnewdepth = (CDepthTarget*)itdepth->second; -// -// assert( pnewdepth != NULL ); -// pd3dDevice->SetDepthStencilSurface(pnewdepth->pdepth); - - SetViewport(); - - if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); - - // render with an AA shader if possible (bilinearly interpolates data) - pd3dDevice->SetPixelShader(ppsConvert32to16); - pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); - -#ifdef _DEBUG - //g_bSaveZUpdate = 1; - if( g_bSaveZUpdate ) { - pd3dDevice->GetRenderTargetData(psurf, psys); - - D3DXSaveSurfaceToFile("tex1.tga", D3DXIFF_TGA, psurfConv, NULL, NULL); - - LPD3DSURF ptempsys; - V(pd3dDevice->CreateOffscreenPlainSurface(fbw<LockRect(&srclock, NULL, D3DLOCK_READONLY); - ptempsys->LockRect(&dstlock, NULL, 0); - DWORD col; - float temp[4]; - for(int i = 0; i < fbh; ++i) { - for(int j = 0; j < fbw; ++j) { - D3DXVECTOR4_16F* pdst = (D3DXVECTOR4_16F*)dstlock.pBits + fbw*i + j; - int jj = j; - int upper = 0; - if( (j%16) >=8 ) { - jj -= 8; - upper = 1; - } - int ii = (i - (i%64))/2 + (i%64); - if( (i%64) >= 32 ) { - ii -= 32; - jj += 8; - } - D3DXVECTOR4_16F* psrc = (D3DXVECTOR4_16F*)srclock.pBits + fbw*ii + jj; - //D3DXFloat16To32Array(out, (D3DXFLOAT16*)psrc, 4); - col = Float16ToARGB(psrc[0]); - if( upper ) col >>= 16; - else col &= 0xffff; - col = RGBA16to32(col); - temp[2] = (col&0xff)/255.0f; - temp[1] = ((col>>8)&0xff)/255.0f; - temp[0] = ((col>>16)&0xff)/255.0f; - temp[3] = 2*(((col>>24)&0xff)/255.0f); - D3DXFloat32To16Array((D3DXFLOAT16*)pdst, temp, 4); - - } - } - psys->UnlockRect(); - ptempsys->UnlockRect(); - - D3DXSaveSurfaceToFile("tex2.tga", D3DXIFF_TGA, ptempsys, NULL, NULL); - - SAFE_RELEASE(psys); - psys = ptempsys; - - pd3dDevice->UpdateSurface(ptempsys, NULL, psurfConv, NULL); - } -#endif - - vposxy.y = -2.0f * (32767.0f / 8.0f) / (float)fbh; - vposxy.w = 1+0.5f/fbh; - - // restore - SAFE_RELEASE(ptex); - SAFE_RELEASE(psurf); - SAFE_RELEASE(psys); - SAFE_RELEASE(ptexFeedback); - SAFE_RELEASE(psurfFeedback); - ptex = ptexConv; - psurf = psurfConv; - - V(pd3dDevice->CreateOffscreenPlainSurface(fbw<SetTexture(SAMP_FINAL, NULL); - pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexBilinearBlocks); // restore - pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); - pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); - pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - SETRS(D3DRS_SCISSORTESTENABLE, TRUE); - - status = TS_Resolved; - - // TODO, reset depth? - if( ZeroGS::icurctx >= 0 ) { - // reset since settings changed - vb[icurctx].bVarsTexSync = 0; - vb[icurctx].bVarsSetTarg = 0; - } - vb[0].bVarsTexSync = 0; -} - -void ZeroGS::CRenderTarget::_CreateFeedback() -{ - if( ptexFeedback == NULL ) { - // create - assert( pmimicparent == NULL ); - - HRESULT hr; - V(pd3dDevice->CreateTexture(fbw<GetSurfaceLevel(0, &psurfFeedback)); - } - - if( !s_bBeginScene ) { - pd3dDevice->BeginScene(); - s_bBeginScene = TRUE; - } - - SETRS(D3DRS_SCISSORTESTENABLE, FALSE); - SETRS(D3DRS_ALPHABLENDENABLE, FALSE); - SETRS(D3DRS_ALPHATESTENABLE, FALSE); - SETRS(D3DRS_ZENABLE, FALSE); - SETRS(D3DRS_ZWRITEENABLE, FALSE); - SETRS(D3DRS_STENCILENABLE, FALSE); - SETRS(D3DRS_COLORWRITEENABLE, 0xf); - - // assume depth already set -// if( conf.mrtdepth && bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); -// else - pd3dDevice->SetRenderTarget(1, NULL); - - // tex coords, test ffx bikanel island when changing these - float dx = 0.5f / (fbw << s_AAx); - float dy = 0.5f / (fbh << s_AAy); - - DXVEC4 v = DXVEC4(1, 1, -dx, dy); - SETCONSTF(GPU_BITBLTPOS, v); - - v.z = 0.5f*dx; - v.w = 0.5f*dy; - SETCONSTF(GPU_BITBLTTEX, v); - - v.x = v.y = v.z = 1; - v.w = 1; // since all alpha is mult by 2 - SETCONSTF(GPU_ONECOLOR, v); - - pd3dDevice->SetVertexShader(pvsBitBlt); - pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); - - pd3dDevice->SetRenderTarget(0, psurfFeedback); - pd3dDevice->SetTexture(SAMP_FINAL, ptex); - - if( s_ptexCurSet[0] == ptexFeedback ) { - s_ptexCurSet[0] = NULL; - pd3dDevice->SetTexture(SAMP_MEMORY0, NULL); - } - if( s_ptexCurSet[1] == ptexFeedback ) { - s_ptexCurSet[1] = NULL; - pd3dDevice->SetTexture(SAMP_MEMORY1, NULL); - } - - SetViewport(); - - if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); - - // render with an AA shader if possible (bilinearly interpolates data) - pd3dDevice->SetPixelShader(ppsBaseTexture); - pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); - - // restore - swap(ptex, ptexFeedback); - swap(psurf, psurfFeedback); - - if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); - - pd3dDevice->SetTexture(SAMP_FINAL, NULL); - SETRS(D3DRS_SCISSORTESTENABLE, TRUE); - status |= TS_FeedbackReady; - - // TODO, reset depth? - if( ZeroGS::icurctx >= 0 ) { - // reset since settings changed - vb[icurctx].bVarsTexSync = 0; - } -} - -ZeroGS::CDepthTarget::CDepthTarget() : CRenderTarget(), pdepth(NULL) {} - -ZeroGS::CDepthTarget::~CDepthTarget() -{ - Destroy(); -} - -BOOL ZeroGS::CDepthTarget::Create(const frameInfo& frame) -{ - if( !CRenderTarget::Create(frame) ) return FALSE; - - if( psm == 0x31 ) fbm = 0xff000000; - else fbm = 0; - - HRESULT hr; - V(pd3dDevice->CreateDepthStencilSurface(fbw<CreateDepthStencilSurface(fbw, fbh, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, FALSE, &pdepth, NULL)); - } - - if( FAILED(hr) ) - return FALSE; - - status = TS_NeedUpdate; - - return TRUE; -} - -void ZeroGS::CDepthTarget::Destroy() -{ - if( pd3dDevice != NULL ) { - pd3dDevice->SetRenderTarget(1, NULL); - pd3dDevice->SetDepthStencilSurface(NULL); - vb[0].bVarsSetTarg = 0; - vb[1].bVarsSetTarg = 0; - } - - CRenderTarget::Destroy(); - SAFE_RELEASE(pdepth); -} - -extern int g_nDepthUsed; // > 0 if depth is used - -void ZeroGS::CDepthTarget::Resolve() -{ - if( g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && ZeroGS::IsWriteDepth() && !(g_GameSettings&GAME_NODEPTHRESOLVE) ) - CRenderTarget::Resolve(); - else { - // flush if necessary - if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); - if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); - - if( !(status & TS_Virtual) || targoffx != 0 || targoffy != 0 ) - status |= TS_Resolved; - } - - if( !(status&TS_Virtual) ) { - ZeroGS::SetWriteDepth(); - } -} - -void ZeroGS::CDepthTarget::Resolve(int startrange, int endrange) -{ - if( g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && ZeroGS::IsWriteDepth() ) CRenderTarget::Resolve(startrange, endrange); - else { - // flush if necessary - if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); - if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); - - if( !(status & TS_Virtual) ) - status |= TS_Resolved; - } - - if( !(status&TS_Virtual) ) { - ZeroGS::SetWriteDepth(); - } -} - -extern int g_nDepthUpdateCount; - -void ZeroGS::CDepthTarget::Update(int context, ZeroGS::CRenderTarget* prndr) -{ - assert( !(status & TS_Virtual) ); - - CRenderTarget* pusetarg = NULL; - if( nUpdateTarg ) { - CRenderTargetMngr::MAPTARGETS::iterator ittarg = s_DepthRTs.mapTargets.find(nUpdateTarg); - if( ittarg == s_DepthRTs.mapTargets.end() || ittarg->second == this) { - DEBUG_LOG("zerogs: updating self"); - nUpdateTarg = 0; - } - else pusetarg = ittarg->second; - } - - tex0Info texframe; - CMemoryTarget* pmemtarg = NULL; - if( pusetarg == NULL ) { - // align the rect to the nearest page - // note that fbp is always aligned on page boundaries - texframe.tbp0 = fbp; - texframe.tbw = fbw; - texframe.tw = fbw; - texframe.th = fbh; - texframe.psm = psm; - pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); - } - - if( !s_bBeginScene ) { - pd3dDevice->BeginScene(); - s_bBeginScene = TRUE; - } - - SETRS(D3DRS_SCISSORTESTENABLE, FALSE); - SETRS(D3DRS_ALPHABLENDENABLE, FALSE); - SETRS(D3DRS_ALPHATESTENABLE, FALSE); - SETRS(D3DRS_ZENABLE, TRUE); - SETRS(D3DRS_ZWRITEENABLE, TRUE); - SETRS(D3DRS_STENCILENABLE, FALSE); - SETRS(D3DRS_ZFUNC, D3DCMP_ALWAYS); - - DXVEC4 v = DXVEC4(1,1,-0.5f/(float)(fbw<SetTexture(SAMP_FINAL, pusetarg->ptex); - - //assert( pusetarg->fbw == fbw ); - int offset = (fbp-pusetarg->fbp)*64/fbw; - if( psm & 2 ) // 16 bit - offset *= 2; - - v.x = 1; - v.y = (float)fbh / pusetarg->fbh; - v.z = 0.25f / (fbw << s_AAx); - v.w = (float)offset / pusetarg->fbh + 0.25f / (pusetarg->fbh << s_AAy); - SETCONSTF(GPU_BITBLTTEX, v); - } - else { - // write color and zero out stencil buf, always 0 context! - SetTexVariablesInt(0, 0, texframe, pmemtarg, 1); - - DXVEC4 v = DXVEC4(1,1,0.5f/(float)fbw,0.5f/(float)fbh); - SETCONSTF(GPU_BITBLTTEX, v); - } - - pd3dDevice->SetVertexShader(pvsBitBlt); - pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); - - v.x = 1; - v.y = 2; - v.z = (psm&3)==2?1.0f:0.0f; - v.w = g_filog32; - SETCONSTF(GPU_ONECOLOR, v); - - assert( psurf != NULL ); - - DXVEC4 vdepth = ((255.0f/256.0f)*g_vdepth); - if( psm == PSMT24Z ) vdepth.w = 0; - else if( psm != PSMT32Z ) { vdepth.z = vdepth.w = 0; } - SETCONSTF(GPU_BITBLTZ, ((255.0f/256.0f)*vdepth)); - - assert( pdepth != NULL ); - - if( ZeroGS::IsWriteDepth() && conf.mrtdepth && bIndepWriteMasks) { - // write in MRT1 - pd3dDevice->SetRenderTarget(1, psurf); - pd3dDevice->SetRenderTarget(0, prndr->psurf); - SETRS(D3DRS_COLORWRITEENABLE, 0); - SETRS(D3DRS_COLORWRITEENABLE1, 0xf); - } - else { - // turn off writes? - if( bIndepWriteMasks ) { - pd3dDevice->SetRenderTarget(0, prndr->psurf); - SETRS(D3DRS_COLORWRITEENABLE, 0); - } - else pd3dDevice->SetRenderTarget(0, psurf); - } - - SetViewport(); - if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); - - pd3dDevice->SetDepthStencilSurface(pdepth); - - if( pusetarg != NULL ) { - pd3dDevice->SetPixelShader(ppsBitBltDepthTex[conf.mrtdepth]); - } - else { - pd3dDevice->SetPixelShader(ppsBitBltDepth[conf.mrtdepth]); - } - pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); - - status = TS_Resolved; - - if( conf.mrtdepth && bIndepWriteMasks ) { - SETRS(D3DRS_COLORWRITEENABLE, 0xf); - } - - if( !ZeroGS::IsWriteDepth() ) { - pd3dDevice->SetRenderTarget(1, NULL); - } - - if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); - SETRS(D3DRS_SCISSORTESTENABLE, TRUE); - -#ifdef _DEBUG - if( g_bSaveZUpdate ) { - if( pusetarg != NULL ) - D3DXSaveTextureToFile("tex.tga", D3DXIFF_TGA, pusetarg->ptex, NULL); - else - SaveTex(&texframe, 1); - D3DXSaveSurfaceToFile("frame1.tga", D3DXIFF_TGA, psurf, NULL, NULL); - } - //pd3dDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0, 0, 0); -#endif -} - -void ZeroGS::CDepthTarget::SetDepthTarget() -{ - pd3dDevice->SetDepthStencilSurface(pdepth); - - if( conf.mrtdepth && ZeroGS::IsWriteDepth() ) - pd3dDevice->SetRenderTarget(1, psurf); -} - -void ZeroGS::CRenderTargetMngr::Destroy() -{ - for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) - delete it->second; - mapTargets.clear(); - for(MAPTARGETS::iterator it = mapDummyTargs.begin(); it != mapDummyTargs.end(); ++it) - delete it->second; - mapDummyTargs.clear(); -} - -CRenderTarget* ZeroGS::CRenderTargetMngr::GetTarg(const frameInfo& frame, DWORD opts, int maxposheight) -{ - if( frame.fbw <= 0 || frame.fbh <= 0 ) - return NULL; - - u32 key = frame.fbp|(frame.fbw<<16); - MAPTARGETS::iterator it = mapTargets.find(key); - - // only enforce height if frame.fbh <= 0x1c0 - bool bfound = it != mapTargets.end(); - if( bfound ) { - if( opts&TO_StrictHeight ) { - bfound = it->second->fbh == frame.fbh; - - if( (g_GameSettings&GAME_PARTIALDEPTH) && !bfound ) { - MAPTARGETS::iterator itnew = mapTargets.find(key+1); - if( itnew != mapTargets.end() && itnew->second->fbh == frame.fbh ) { - // found! delete the previous and restore - delete it->second; - mapTargets.erase(it); - - it = mapTargets.insert(MAPTARGETS::value_type(key, itnew->second)).first; // readd - mapTargets.erase(itnew); // delete old - - bfound = true; - } - } - } - else { - if( (frame.psm&2)==(it->second->psm&2) && !(g_GameSettings & GAME_FULL16BITRES) ) - bfound = (frame.fbh > 0x1c0 || it->second->fbh >= frame.fbh) && it->second->fbh <= maxposheight; - } - } - - if( !bfound ) { - // might be a virtual target - it = mapTargets.find(key|TARGET_VIRTUAL_KEY); - bfound = it != mapTargets.end() && ((opts&TO_StrictHeight) ? it->second->fbh == frame.fbh : it->second->fbh >= frame.fbh) && it->second->fbh <= maxposheight; - } - - if( bfound && (frame.psm&2) && !(it->second->psm&2) && (g_GameSettings&GAME_FULL16BITRES) ) { - // mgs3 - if( frame.fbh > it->second->fbh ) { - bfound = false; - } - } - - if( bfound ) { - - // can be both 16bit and 32bit - if( (frame.psm&2) != (it->second->psm&2) ) { - // a lot of games do this actually... -#ifdef _DEBUG - WARN_LOG("Really bad formats! %d %d\n", frame.psm, it->second->psm); -#endif - if( !(opts&TO_StrictHeight) ) { - if( !(g_GameSettings & GAME_VSSHACKOFF) ) { - if( it->second->psm & 2 ) { - it->second->status |= CRenderTarget::TS_NeedConvert32; - it->second->fbh /= 2; - it->second->targheight /= 2; - } - else { - it->second->status |= CRenderTarget::TS_NeedConvert16; - it->second->fbh *= 2; - it->second->targheight *= 2; - } - } - } - - // recalc extents - GetRectMemAddress(it->second->start, it->second->end, frame.psm, 0, 0, frame.fbw, it->second->fbh, it->second->fbp, frame.fbw); - } - else { - // certain variables have to be reset every time - if( (it->second->psm&~1) != (frame.psm&~1) ) { -#ifndef RELEASE_TO_PUBLIC - WARN_LOG("bad formats 2: %d %d\n", frame.psm, it->second->psm); -#endif - it->second->psm = frame.psm; - - // recalc extents - GetRectMemAddress(it->second->start, it->second->end, frame.psm, 0, 0, frame.fbw, it->second->fbh, it->second->fbp, frame.fbw); - } - } - - if( it->second->fbm != frame.fbm ) { - //WARN_LOG("bad fbm: 0x%8.8x 0x%8.8x, psm: %d\n", frame.fbm, it->second->fbm, frame.psm); - } - - it->second->fbm &= frame.fbm; - it->second->psm = frame.psm; // have to convert (ffx2) - - if( (it->first & TARGET_VIRTUAL_KEY) && !(opts&TO_Virtual) ) { - // switch - it->second->lastused = timeGetTime(); - return Promote(it->first&~TARGET_VIRTUAL_KEY); - } - - // check if there exists a more recent target that this target could update from - // only update if target isn't mirrored - bool bCheckHalfCovering = (g_GameSettings&GAME_FULL16BITRES) && (it->second->psm&2) && it->second->fbh +32 < frame.fbh; - - for(MAPTARGETS::iterator itnew = mapTargets.begin(); itnew != mapTargets.end(); ++itnew) { - if( itnew->second != it->second && itnew->second->ptex != it->second->ptex && itnew->second->ptexFeedback != it->second->ptex && - itnew->second->lastused > it->second->lastused && !(itnew->second->status & CRenderTarget::TS_NeedUpdate) ) { - - // if new target totally encompasses the current one - if( itnew->second->start <= it->second->start && itnew->second->end >= it->second->end ) { - it->second->status |= CRenderTarget::TS_NeedUpdate; - it->second->nUpdateTarg = itnew->first; - break; - } - - // if 16bit, then check for half encompassing targets - if( bCheckHalfCovering && itnew->second->start > it->second->start && itnew->second->start < it->second->end && itnew->second->end <= it->second->end+0x2000 ) { - it->second->status |= CRenderTarget::TS_NeedUpdate; - it->second->nUpdateTarg = itnew->first; - break; - } - } - } - - it->second->lastused = timeGetTime(); - - return it->second; - } - - // NOTE: instead of resolving, if current render targ is completely outside of old, can transfer - // the data like that. - - // first search for the target - CRenderTarget* ptarg = NULL; - - // have to change, so recreate (find all intersecting targets and Resolve) - u32 besttarg = 0; - - if( !(opts & CRenderTargetMngr::TO_Virtual) ) { - - int start, end; - GetRectMemAddress(start, end, frame.psm, 0, 0, frame.fbw, frame.fbh, frame.fbp, frame.fbw); - - if( !(opts & CRenderTargetMngr::TO_StrictHeight) ) { - - if( g_GameSettings&GAME_PARTIALPOINTERS ) { - // if there is a render target that wholly encompasses this one, then use the pointer directly - // this render target also has to be small (mgs3) - if( frame.fbh <= 0x40 ) { - for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { - if( it->second->start < end && start < it->second->end && (it->second->psm&~1) == (frame.psm&~1) && (it->second->fbp&0xff) == 0 ) { - ptarg = new CRenderTarget(frame, *it->second); - besttarg = it->first; - break; - } - } - } - } - } - - CRenderTarget* pbesttarg = NULL; - - if( besttarg == 0 ) { - // if there is only one intersecting target and it encompasses the current one, update the new render target with - // its data instead of resolving then updating (ffx2). Do not change the original target. - for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { - if( it->second->start < end && start < it->second->end ) { -// if( g_GameSettings&GAME_FASTUPDATE ) { -// besttarg = it->first; -// //break; -// } -// else { - if( (g_GameSettings&GAME_FASTUPDATE) || (it->second->fbw == frame.fbw && - // check depth targets only if partialdepth option - (it->second->fbp != frame.fbp|| ((g_GameSettings&GAME_PARTIALDEPTH)&&(opts&CRenderTargetMngr::TO_DepthBuffer))) ) ) { - - if( besttarg != 0 ) { - besttarg = 0; - break; - } - - if( start >= it->second->start && end <= it->second->end ) { - besttarg = it->first; - pbesttarg = it->second; - } - } -// } - } - } - } - - if( besttarg == 0 ) { - // if none found, resolve all - DestroyAll(start, end, frame.fbw); - } - else if( key == besttarg && pbesttarg != NULL ) { - // add one and store in a different location until best targ is processed - mapTargets.erase(besttarg); - besttarg++; - mapTargets[besttarg] = pbesttarg; - } - } - - if( mapTargets.size() > 8 ) { - // release some resources - it = GetOldestTarg(mapTargets); - - // if more than 5s passed since target used, destroy - if( it->second != vb[0].prndr && it->second != vb[1].prndr && it->second != vb[0].pdepth && it->second != vb[1].pdepth && - timeGetTime()-it->second->lastused > 5000 ) { - DestroyChildren(it->second); - delete it->second; - mapTargets.erase(it); - } - } - - if( ptarg == NULL ) { - // not found yet, so create - - if( mapDummyTargs.size() > 8 ) { - it = GetOldestTarg(mapDummyTargs); - - DestroyChildren(it->second); - delete it->second; - mapDummyTargs.erase(it); - } - - it = mapDummyTargs.find( (frame.fbw<<16)|frame.fbh ); - if( it != mapDummyTargs.end() ) { - ptarg = it->second; - mapDummyTargs.erase(it); - - // restore all setttings - ptarg->psm = frame.psm; - ptarg->fbm = frame.fbm; - ptarg->fbp = frame.fbp; - GetRectMemAddress(ptarg->start, ptarg->end, frame.psm, 0, 0, frame.fbw, frame.fbh, frame.fbp, frame.fbw); - - ptarg->status = CRenderTarget::TS_NeedUpdate; - } - else { - // create anew - ptarg = (opts&TO_DepthBuffer) ? new CDepthTarget() : new CRenderTarget(); - CRenderTargetMngr* pmngrs[2] = { &s_DepthRTs, this == &s_RTs ? &s_RTs : NULL }; - int cur = 0; - - while( !ptarg->Create(frame) ) { - - // destroy unused targets - if( mapDummyTargs.size() > 0 ) { - it = mapDummyTargs.begin(); - delete it->second; - mapDummyTargs.erase(it); - continue; - } - - if( g_MemTargs.listClearedTargets.size() > 0 ) { - g_MemTargs.DestroyCleared(); - continue; - } - else - if( g_MemTargs.listTargets.size() > 32 ) { - g_MemTargs.DestroyOldest(); - continue; - } - - if( pmngrs[cur] == NULL ) { - cur = !cur; - if( pmngrs[cur] == NULL ) { - WARN_LOG("Out of memory!\n"); - delete ptarg; - return NULL; - } - } - - if( pmngrs[cur]->mapTargets.size() == 0 ) - { - pmngrs[cur] = NULL; - cur = !cur; - continue; - } - - it = GetOldestTarg(pmngrs[cur]->mapTargets); - - DestroyTarg(it->second); - pmngrs[cur]->mapTargets.erase(it); - cur = !cur; - } - } - } - - if( (opts & CRenderTargetMngr::TO_Virtual) ) { - ptarg->status = CRenderTarget::TS_Virtual; - key |= TARGET_VIRTUAL_KEY; - - if( (it = mapTargets.find(key)) != mapTargets.end() ) { - - DestroyTarg(it->second); - it->second = ptarg; - ptarg->nUpdateTarg = besttarg; - return ptarg; - } - } - else - assert( mapTargets.find(key) == mapTargets.end()); - - ptarg->nUpdateTarg = besttarg; - mapTargets[key] = ptarg; - return ptarg; -} - -void CRenderTargetMngr::DestroyChildren(CRenderTarget* ptarg) -{ - if(ptarg == NULL) - return; - - MAPTARGETS::iterator ittarg = mapTargets.begin(); - while(ittarg != mapTargets.end()) { - if( ittarg->second->pmimicparent == ptarg ) { - assert( ittarg->second != ptarg ); - delete ittarg->second; - ittarg = mapTargets.erase(ittarg); - } - else ++ittarg; - } -} - -ZeroGS::CRenderTargetMngr::MAPTARGETS::iterator ZeroGS::CRenderTargetMngr::GetOldestTarg(MAPTARGETS& m) -{ - if( m.size() == 0 ) { - return m.end(); - } - - // release some resources - u32 curtime = timeGetTime(); - MAPTARGETS::iterator itmaxtarg = m.begin(); - for(MAPTARGETS::iterator it = ++m.begin(); it != m.end(); ++it) { - if( itmaxtarg->second->lastused-curtime < it->second->lastused-curtime ) itmaxtarg = it; - } - - return itmaxtarg; -} - -void ZeroGS::CRenderTargetMngr::GetTargs(int start, int end, list& listTargets) const -{ - for(MAPTARGETS::const_iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { - if( it->second->start < end && start < it->second->end ) listTargets.push_back(it->second); - } -} - -void ZeroGS::CRenderTargetMngr::Resolve(int start, int end) -{ - for(MAPTARGETS::const_iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { - if( it->second->start < end && start < it->second->end ) - it->second->Resolve(); - } -} - -void ZeroGS::CMemoryTargetMngr::Destroy() -{ - listTargets.clear(); - listClearedTargets.clear(); -} - -int memcmp_clut16(u16* pSavedBuffer, u16* pClutBuffer, int clutsize) -{ - assert( (clutsize&31) == 0 ); - - // left > 0 only when csa < 16 - int left = ((u32)pClutBuffer & 2) ? 0 : (((u32)pClutBuffer & 0x3ff)/2) + clutsize - 512; - if( left > 0 ) clutsize -= left; - - while(clutsize > 0) { - for(int i = 0; i < 16; ++i) { - if( pSavedBuffer[i] != pClutBuffer[2*i] ) - return 1; - } - - clutsize -= 32; - pSavedBuffer += 16; - pClutBuffer += 32; - } - - if( left > 0 ) { - pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + 2); - - while(left > 0) { - for(int i = 0; i < 16; ++i) { - if( pSavedBuffer[i] != pClutBuffer[2*i] ) - return 1; - } - - left -= 32; - pSavedBuffer += 16; - pClutBuffer += 32; - } - } - - return 0; -} - -bool ZeroGS::CMemoryTarget::ValidateClut(const tex0Info& tex0) -{ - assert( tex0.psm == psm && PSMT_ISCLUT(psm) && cpsm == tex0.cpsm ); - - int nClutOffset = 0; - int clutsize = 0; - - int entries = (tex0.psm&3)==3 ? 256 : 16; - if( tex0.cpsm <= 1 ) { // 32 bit - nClutOffset = 64 * tex0.csa; - clutsize = min(entries, 256-tex0.csa*16)*4; - } - else { - nClutOffset = 32 * (tex0.csa&15) + (tex0.csa>=16?2:0); - clutsize = min(entries, 512-tex0.csa*16)*2; - } - - assert( clutsize == clut.size() ); - - if( cpsm <= 1 ) { - // memcmp_mmx doesn't work on x86-64 -#ifdef __x86_64__ - if( memcmp(&clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize) ) -#else - if( memcmp_mmx(&clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize) ) -#endif - return false; - } - else { - if( memcmp_clut16((u16*)&clut[0], (u16*)(ZeroGS::g_pbyGSClut+nClutOffset), clutsize) ) - return false; - } - - return true; -} - -int VALIDATE_THRESH = 8; -u32 TEXDESTROY_THRESH = 16; - -bool ZeroGS::CMemoryTarget::ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex) -{ - if( clearmaxy == 0 ) - return true; - - int checkstarty = max(starttex, clearminy); - int checkendy = min(endtex, clearmaxy); - if( checkstarty >= checkendy ) - return true; - - if( validatecount++ > VALIDATE_THRESH ) { - height = 0; - return false; - } - - // lock and compare - D3DLOCKED_RECT lock; - assert( ptex != NULL ); - - if( memory != NULL ) { - assert( memory->ptr != NULL ); - lock.pBits = memory->ptr; - } - else { - assert( ptexsys != NULL ); - ptexsys->LockRect(0, &lock, NULL, D3DLOCK_READONLY); - } - - // memcmp_mmx doesn't work on x86_64 -#ifdef __x86_64__ - int result = memcmp((u8*)lock.pBits + (checkstarty-realy)*4*GPU_TEXWIDTH, ZeroGS::g_pbyGSMemory+checkstarty*4*GPU_TEXWIDTH, (checkendy-checkstarty)*4*GPU_TEXWIDTH); -#else - int result = memcmp_mmx((u8*)lock.pBits + (checkstarty-realy)*4*GPU_TEXWIDTH, ZeroGS::g_pbyGSMemory+checkstarty*4*GPU_TEXWIDTH, (checkendy-checkstarty)*4*GPU_TEXWIDTH); -#endif - - if( memory == NULL ) - ptexsys->UnlockRect(0); - - if( result == 0 || !bDeleteBadTex ) { - if( result == 0 ) clearmaxy = 0; - return result == 0; - } - - // delete clearminy, clearmaxy range (not the checkstarty, checkendy range) - int newstarty = 0; - if( clearminy <= starty ) { - if( clearmaxy < starty + height) { - // preserve end - height = starty+height-clearmaxy; - starty = clearmaxy; - assert(height > 0); - } - else { - // destroy - height = 0; - } - } - else { - // beginning can be preserved - height = clearminy-starty; - } - - clearmaxy = 0; - assert( starty >= realy && starty+height<=realy+realheight ); - - return false; -} - -// used to build clut textures (note that this is for both 16 and 32 bit cluts) -#define BUILDCLUT() { \ - switch(tex0.psm) { \ - case PSMT8: \ - for(int i = 0; i < targ->height; ++i) { \ - for(int j = 0; j < GPU_TEXWIDTH/2; ++j) { \ - pdst[0] = pclut[psrc[0]]; \ - pdst[1] = pclut[psrc[1]]; \ - pdst[2] = pclut[psrc[2]]; \ - pdst[3] = pclut[psrc[3]]; \ - pdst[4] = pclut[psrc[4]]; \ - pdst[5] = pclut[psrc[5]]; \ - pdst[6] = pclut[psrc[6]]; \ - pdst[7] = pclut[psrc[7]]; \ - pdst += 8; \ - psrc += 8; \ - } \ - } \ - break; \ - case PSMT4: \ - for(int i = 0; i < targ->height; ++i) { \ - for(int j = 0; j < GPU_TEXWIDTH; ++j) { \ - pdst[0] = pclut[psrc[0]&15]; \ - pdst[1] = pclut[psrc[0]>>4]; \ - pdst[2] = pclut[psrc[1]&15]; \ - pdst[3] = pclut[psrc[1]>>4]; \ - pdst[4] = pclut[psrc[2]&15]; \ - pdst[5] = pclut[psrc[2]>>4]; \ - pdst[6] = pclut[psrc[3]&15]; \ - pdst[7] = pclut[psrc[3]>>4]; \ - \ - pdst += 8; \ - psrc += 4; \ - } \ - } \ - break; \ - case PSMT8H: \ - for(int i = 0; i < targ->height; ++i) { \ - for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ - pdst[0] = pclut[psrc[3]]; \ - pdst[1] = pclut[psrc[7]]; \ - pdst[2] = pclut[psrc[11]]; \ - pdst[3] = pclut[psrc[15]]; \ - pdst[4] = pclut[psrc[19]]; \ - pdst[5] = pclut[psrc[23]]; \ - pdst[6] = pclut[psrc[27]]; \ - pdst[7] = pclut[psrc[31]]; \ - pdst += 8; \ - psrc += 32; \ - } \ - } \ - break; \ - case PSMT4HH: \ - for(int i = 0; i < targ->height; ++i) { \ - for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ - pdst[0] = pclut[psrc[3]>>4]; \ - pdst[1] = pclut[psrc[7]>>4]; \ - pdst[2] = pclut[psrc[11]>>4]; \ - pdst[3] = pclut[psrc[15]>>4]; \ - pdst[4] = pclut[psrc[19]>>4]; \ - pdst[5] = pclut[psrc[23]>>4]; \ - pdst[6] = pclut[psrc[27]>>4]; \ - pdst[7] = pclut[psrc[31]>>4]; \ - pdst += 8; \ - psrc += 32; \ - } \ - } \ - break; \ - case PSMT4HL: \ - for(int i = 0; i < targ->height; ++i) { \ - for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ - pdst[0] = pclut[psrc[3]&15]; \ - pdst[1] = pclut[psrc[7]&15]; \ - pdst[2] = pclut[psrc[11]&15]; \ - pdst[3] = pclut[psrc[15]&15]; \ - pdst[4] = pclut[psrc[19]&15]; \ - pdst[5] = pclut[psrc[23]&15]; \ - pdst[6] = pclut[psrc[27]&15]; \ - pdst[7] = pclut[psrc[31]&15]; \ - pdst += 8; \ - psrc += 32; \ - } \ - } \ - break; \ - default: \ - assert(0); \ - } \ -} \ - -#define TARGET_THRESH 0x500 - -extern int g_MaxTexWidth, g_MaxTexHeight; - -//#define SORT_TARGETS -inline list::iterator ZeroGS::CMemoryTargetMngr::DestroyTargetIter(list::iterator& it) -{ - // find the target and destroy - list::iterator itprev = it; ++it; - listClearedTargets.splice(listClearedTargets.end(), listTargets, itprev); - - if( listClearedTargets.size() > TEXDESTROY_THRESH ) { - listClearedTargets.pop_front(); - } - - return it; -} - -#if defined(_MSC_VER) && defined(__x86_64__) -extern "C" void UnswizzleZ16Target(void* dst, void* src, int iters); -#endif - -ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::GetMemoryTarget(const tex0Info& tex0, int forcevalidate) -{ - int nbStart, nbEnd; - GetRectMemAddress(nbStart, nbEnd, tex0.psm, 0, 0, tex0.tw, tex0.th, tex0.tbp0, tex0.tbw); - assert( nbStart < nbEnd ); - nbEnd = min(nbEnd, 0x00400000); - - int nClutOffset = 0; - int clutsize = 0; - - if( PSMT_ISCLUT(tex0.psm) ) { - int entries = (tex0.psm&3)==3 ? 256 : 16; - if( tex0.cpsm <= 1 ) { // 32 bit - nClutOffset = 64 * tex0.csa; - clutsize = min(entries, 256-tex0.csa*16)*4; - } - else { - nClutOffset = 64 * (tex0.csa&15) + (tex0.csa>=16?2:0); - clutsize = min(entries, 512-tex0.csa*16)*2; - } - } - - int start = nbStart / (4*GPU_TEXWIDTH); - int end = (nbEnd + GPU_TEXWIDTH*4 - 1) / (4*GPU_TEXWIDTH); - assert( start < end ); - - for(list::iterator it = listTargets.begin(); it != listTargets.end();) { - - if( it->starty <= start && it->starty+it->height >= end ) { - - assert( it->psm != 0xd ); - - // using clut, validate that same data - if( PSMT_ISCLUT(it->psm) != PSMT_ISCLUT(tex0.psm) ) { - if( it->validatecount++ > VALIDATE_THRESH ) { - it = DestroyTargetIter(it); - if( listTargets.size() == 0 ) - break; - } - else - ++it; - continue; - } - - if( PSMT_ISCLUT(tex0.psm) ) { - assert( it->clut.size() > 0 ); - - if( it->psm != tex0.psm || it->cpsm != tex0.cpsm || it->clut.size() != clutsize ) { - // wrong clut - list::iterator itprev = it; - if( it->validatecount++ > VALIDATE_THRESH ) { - it = DestroyTargetIter(it); - if( listTargets.size() == 0 ) - break; - } - else - ++it; - continue; - } - - if( tex0.cpsm <= 1 ) { -#ifdef __x86_64__ - if( memcmp(&it->clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize) ) { -#else - if( memcmp_mmx(&it->clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize) ) { -#endif - ++it; - continue; - } - } - else { - if( memcmp_clut16((u16*)&it->clut[0], (u16*)(ZeroGS::g_pbyGSClut+nClutOffset), clutsize) ) { - ++it; - continue; - } - } - } - else if( PSMT_IS16BIT(tex0.psm) != PSMT_IS16BIT(it->psm) ) { - - if( it->validatecount++ > VALIDATE_THRESH ) { - it = DestroyTargetIter(it); - if( listTargets.size() == 0 ) - break; - } - else ++it; - - continue; - } - - if( forcevalidate ) {//&& listTargets.size() < TARGET_THRESH ) { - // do more validation checking. delete if not been used for a while - if( !it->ValidateTex(tex0, start, end, curstamp > it->usedstamp + 3) ) { - if( it->height <= 0 ) { - - it = DestroyTargetIter(it); - if( listTargets.size() == 0 ) - break; - } - else ++it; - continue; - } - } - - it->usedstamp = curstamp; - it->validatecount = 0; - - return &(*it); - } -#ifdef SORT_TARGETS - else if( it->starty >= end ) - break; -#endif - ++it; - } - -#ifdef _DEBUG - PRIM_LOG("memtarget: tbp: %x tbw: %x th: %x psm: %x\n", tex0.tbp0, tex0.tbw, tex0.th, tex0.psm); -#endif - - // couldn't find so create - HRESULT hr; - CMemoryTarget* targ; - - D3DFORMAT fmt = D3DFMT_A8R8G8B8; - if( (PSMT_ISCLUT(tex0.psm) && tex0.cpsm > 1) || tex0.psm == PSMCT16 || tex0.psm == PSMCT16S) { - fmt = D3DFMT_A1R5G5B5; - } - - int widthmult = 1; - if( g_MaxTexHeight < 4096 ) { - if( end-start > g_MaxTexHeight ) - widthmult = 2; - } - - int channels = 1; - if( PSMT_ISCLUT(tex0.psm) ) { - if( tex0.psm == PSMT8 ) channels = 4; - else if( tex0.psm == PSMT4 ) channels = 8; - } - else { - if( PSMT_IS16BIT(tex0.psm) ) { - // 16z needs to be a8r8g8b8 - channels = 2; - } - } - - if( listClearedTargets.size() > 0 ) { - - list::iterator itbest = listClearedTargets.begin(); - while(itbest != listClearedTargets.end()) { - - if( end-start <= itbest->realheight && itbest->fmt == fmt && itbest->widthmult == widthmult ) { - - // check channels - int targchannels = 1; - if( PSMT_ISCLUT(itbest->psm) ) { - if( itbest->psm == PSMT8 ) targchannels = 4; - else if( itbest->psm == PSMT4 ) targchannels = 8; - } - else if( PSMT_IS16BIT(itbest->psm) ) { - targchannels = 2; - } - if( targchannels == channels ) - break; - } - ++itbest; - } - - if( itbest != listClearedTargets.end()) { - listTargets.splice(listTargets.end(), listClearedTargets, itbest); - targ = &listTargets.back(); - targ->validatecount = 0; - } - else { - // create a new - listTargets.push_back(CMemoryTarget()); - targ = &listTargets.back(); - } - } - else { - listTargets.push_back(CMemoryTarget()); - targ = &listTargets.back(); - } - - // fill local clut - if( PSMT_ISCLUT(tex0.psm) ) { - assert( clutsize > 0 ); - targ->cpsm = tex0.cpsm; - targ->clut.reserve(256*4); // no matter what - targ->clut.resize(clutsize); - - if( tex0.cpsm <= 1 ) { // 32 bit - memcpy_amd(&targ->clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize); - } - else { - u16* pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + nClutOffset); - u16* pclut = (u16*)&targ->clut[0]; - int left = ((u32)nClutOffset & 2) ? 0 : ((nClutOffset&0x3ff)/2)+clutsize-512; - if( left > 0 ) clutsize -= left; - - while(clutsize > 0) { - pclut[0] = pClutBuffer[0]; - pclut++; - pClutBuffer+=2; - clutsize -= 2; - } - - if( left > 0) { - pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + 2); - while(left > 0) { - pclut[0] = pClutBuffer[0]; - left -= 2; - pClutBuffer += 2; - pclut++; - } - } - } - } - - if( targ->ptex != NULL ) { - - assert( end-start <= targ->realheight && targ->fmt == fmt && targ->widthmult == widthmult ); - // good enough, so init - targ->realy = targ->starty = start; - targ->usedstamp = curstamp; - targ->psm = tex0.psm; - targ->cpsm = tex0.cpsm; - targ->height = end-start; - } - - if( targ->ptex == NULL ) { - - // not initialized yet - targ->fmt = fmt; - targ->realy = targ->starty = start; - targ->realheight = targ->height = end-start; - targ->usedstamp = curstamp; - targ->psm = tex0.psm; - targ->cpsm = tex0.cpsm; - targ->widthmult = widthmult; - - // alloc the mem - while( FAILED(pd3dDevice->CreateTexture(GPU_TEXWIDTH*channels*widthmult, (targ->realheight+widthmult-1)/widthmult, 1, 0, fmt, D3DPOOL_DEFAULT, &targ->ptex, NULL)) ) { - - if( listClearedTargets.size() > 0 ) - listClearedTargets.pop_front(); - else { - if( listTargets.size() == 0 ) { - DEBUG_LOG("Failed to create %dx%x texture\n", GPU_TEXWIDTH*channels*widthmult, (targ->realheight+widthmult-1)/widthmult); - channels = 1; - } - DestroyOldest(); - } - } - - // lock - V(pd3dDevice->CreateTexture(GPU_TEXWIDTH*channels*widthmult, (targ->realheight+widthmult-1)/widthmult, 1, 0, fmt, D3DPOOL_SYSTEMMEM, &targ->ptexsys, NULL)); - assert( targ->ptexsys != NULL ); - } - -#ifndef RELEASE_TO_PUBLIC - g_TransferredToGPU += GPU_TEXWIDTH * channels * 4 * targ->height; -#endif - - D3DLOCKED_RECT lock; - targ->ptexsys->LockRect(0, &lock, NULL, 0); - - // fill with data - if( PSMT_ISCLUT(tex0.psm) ) { - - if( targ->memory == NULL ) { - targ->memory = new CMemoryTarget::MEMORY(); - targ->memory->ptr = (BYTE*)_aligned_malloc(4 * GPU_TEXWIDTH * targ->realheight, 16); - targ->memory->ref = 1; - } - - memcpy_amd(targ->memory->ptr, ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy, 4 * GPU_TEXWIDTH * targ->height); - - u8* psrc = (u8*)(ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy); - - if( tex0.cpsm <= 1 ) { // 32bit - u32* pclut = (u32*)&targ->clut[0]; - u32* pdst = (u32*)lock.pBits; - - BUILDCLUT(); - } - else { - u16* pclut = (u16*)&targ->clut[0]; - u16* pdst = (u16*)lock.pBits; - - BUILDCLUT(); - } - } - else { - if( tex0.psm == PSMT16Z || tex0.psm == PSMT16SZ ) { - - if( targ->memory == NULL ) { - targ->memory = new CMemoryTarget::MEMORY(); - targ->memory->ptr = (BYTE*)_aligned_malloc(4 * GPU_TEXWIDTH * targ->realheight, 16); - targ->memory->ref = 1; - } - - memcpy_amd(targ->memory->ptr, ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy, 4 * GPU_TEXWIDTH * targ->height); - - // needs to be 8 bit, use xmm for unpacking - u16* dst = (u16*)lock.pBits; - u16* src = (u16*)(ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy); - - assert( ((u32)dst)%16 == 0 ); - -#if defined(ZEROGS_SSE2) - int iters = targ->height*GPU_TEXWIDTH/16; - -#if defined(__x86_64__) - UnswizzleZ16Target(dst, src, iters); -#else - __asm { - mov edx, iters - pxor xmm7, xmm7 - mov eax, dst - mov ecx, src - -Z16Loop: - // unpack 64 bytes at a time - movdqa xmm0, [ecx] - movdqa xmm2, [ecx+16] - movdqa xmm4, [ecx+32] - movdqa xmm6, [ecx+48] - - movdqa xmm1, xmm0 - movdqa xmm3, xmm2 - movdqa xmm5, xmm4 - - punpcklwd xmm0, xmm7 - punpckhwd xmm1, xmm7 - punpcklwd xmm2, xmm7 - punpckhwd xmm3, xmm7 - - // start saving - movdqa [eax], xmm0 - movdqa [eax+16], xmm1 - - punpcklwd xmm4, xmm7 - punpckhwd xmm5, xmm7 - - movdqa [eax+32], xmm2 - movdqa [eax+48], xmm3 - - movdqa xmm0, xmm6 - punpcklwd xmm6, xmm7 - - movdqa [eax+64], xmm4 - movdqa [eax+80], xmm5 - - punpckhwd xmm0, xmm7 - - movdqa [eax+96], xmm6 - movdqa [eax+112], xmm0 - - add ecx, 64 - add eax, 128 - sub edx, 1 - jne Z16Loop - } -#endif // __x86_64__ -#else - for(int i = 0; i < targ->height; ++i) { - for(int j = 0; j < GPU_TEXWIDTH; ++j) { - dst[0] = src[0]; dst[1] = 0; - dst[2] = src[1]; dst[3] = 0; - dst += 4; - src += 2; - } - } -#endif - } - else { - if( targ->memory != NULL ) { - // release - if( targ->memory->ref > 0 && --targ->memory->ref <= 0 ) { - SAFE_DELETE(targ->memory); - } - targ->memory = NULL; - } - - memcpy_amd(lock.pBits, ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy, 4 * GPU_TEXWIDTH * targ->height ); - } - } - - targ->ptexsys->UnlockRect(0); - - V(pd3dDevice->UpdateTexture(targ->ptexsys, targ->ptex)); - - assert( tex0.psm != 0xd ); - if( PSMT_ISCLUT(tex0.psm) ) - assert( targ->clut.size() > 0 ); - - return targ; -} - -void ZeroGS::CMemoryTargetMngr::ClearRange(int nbStartY, int nbEndY) -{ - int starty = nbStartY / (4*GPU_TEXWIDTH); - int endy = (nbEndY+4*GPU_TEXWIDTH-1) / (4*GPU_TEXWIDTH); - //int endy = (nbEndY+4096-1) / 4096; - - //if( listTargets.size() < TARGET_THRESH ) { - for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { - - if( it->starty < endy && (it->starty+it->height) > starty ) { - - // intersects, reduce valid texture mem (or totally delete texture) - // there are 4 cases - int miny = max(it->starty, starty); - int maxy = min(it->starty+it->height, endy); - assert(miny < maxy); - - if( it->clearmaxy == 0 ) { - it->clearminy = miny; - it->clearmaxy = maxy; - } - else { - if( it->clearminy > miny ) it->clearminy = miny; - if( it->clearmaxy < maxy ) it->clearmaxy = maxy; - } - } - - ++it; - } -// } -// else { -// for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { -// -// if( it->starty < endy && (it->starty+it->height) > starty ) { -// int newstarty = 0; -// if( starty <= it->starty ) { -// if( endy < it->starty + it->height) { -// // preserve end -// it->height = it->starty+it->height-endy; -// it->starty = endy; -// assert(it->height > 0); -// } -// else { -// // destroy -// it->height = 0; -// } -// } -// else { -// // beginning can be preserved -// it->height = starty-it->starty; -// } -// -// assert( it->starty >= it->realy && it->starty+it->height<=it->realy+it->realheight ); -// if( it->height <= 0 ) { -// list::iterator itprev = it; ++it; -// listClearedTargets.splice(listClearedTargets.end(), listTargets, itprev); -// continue; -// } -// } -// -// ++it; -// } -// } -} - -void ZeroGS::CMemoryTargetMngr::DestroyCleared() -{ - for(list::iterator it = listClearedTargets.begin(); it != listClearedTargets.end(); ) { - if( it->usedstamp < curstamp - 2 ) { - it = listClearedTargets.erase(it); - continue; - } - - ++it; - } - - if( (curstamp % 3) == 0 ) { - // purge old targets every 3 frames - for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { - if( it->usedstamp < curstamp - 3 ) { - it = listTargets.erase(it); - continue; - } - - ++it; - } - } - - ++curstamp; -} - -void ZeroGS::CMemoryTargetMngr::DestroyOldest() -{ - if( listTargets.size() == 0 ) - return; - - list::iterator it, itbest; - it = itbest = listTargets.begin(); - - while(it != listTargets.end()) { - if( it->usedstamp < itbest->usedstamp ) - itbest = it; - ++it; - } - - listTargets.erase(itbest); -} - -////////////////////////////////////// -// Texture Mngr For Bitwise AND Ops // -////////////////////////////////////// -void ZeroGS::CBitwiseTextureMngr::Destroy() -{ - for(map::iterator it = mapTextures.begin(); it != mapTextures.end(); ++it) - it->second->Release(); - mapTextures.clear(); -} - -LPD3DTEX ZeroGS::CBitwiseTextureMngr::GetTexInt(u32 bitvalue, LPD3DTEX ptexDoNotDelete) -{ - if( mapTextures.size() > 32 ) { - // randomly delete 8 - for(map::iterator it = mapTextures.begin(); it != mapTextures.end();) { - if( !(rand()&3) && it->second != ptexDoNotDelete) { - it->second->Release(); - it = mapTextures.erase(it); - } - else ++it; - } - } - - // create a new tex - LPD3DTEX ptex; - HRESULT hr = S_OK; - V(pd3dDevice->CreateTexture(GPU_TEXMASKWIDTH, 1, 1, 0, D3DFMT_L16, D3DPOOL_MANAGED, &ptex, NULL)); - - D3DLOCKED_RECT lock; - ptex->LockRect(0, &lock, NULL, 0); - for(u32 i = 0; i < GPU_TEXMASKWIDTH; ++i) ((u16*)lock.pBits)[i] = ((i&bitvalue)<<6)|0x1f; // add the 1/2 offset so that - ptex->UnlockRect(0); - - mapTextures[bitvalue] = ptex; - return ptex; -} - -void ZeroGS::CRangeManager::Insert(int start, int end) -{ - int imin = 0, imax = (int)ranges.size(), imid; - -#ifdef _DEBUG - // sanity check - for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); -#endif - - switch( ranges.size() ) { - case 0: - ranges.push_back(RANGE(start, end)); - return; - - case 1: - if( end < ranges.front().start ) { - ranges.insert(ranges.begin(), RANGE(start, end)); - } - else if( start > ranges.front().end ) { - ranges.push_back(RANGE(start, end)); - } - else { - if( start < ranges.front().start ) ranges.front().start = start; - if( end > ranges.front().end ) ranges.front().end = end; - } - - return; - } - - // find where start is - while(imin < imax) { - imid = (imin+imax)>>1; - - assert( imid < (int)ranges.size() ); - - if( ranges[imid].end >= start && (imid == 0 || ranges[imid-1].end < start) ) { - imin = imid; - break; - } - else if( ranges[imid].start > start ) imax = imid; - else imin = imid+1; - } - - int startindex = imin; - - if( startindex >= (int)ranges.size() ) { - // non intersecting - assert( start > ranges.back().end ); - ranges.push_back(RANGE(start, end)); - return; - } - if( startindex == 0 && end < ranges.front().start ) { - ranges.insert(ranges.begin(), RANGE(start, end)); - -#ifdef _DEBUG - // sanity check - for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); -#endif - return; - } - - imin = 0; imax = (int)ranges.size(); - - // find where end is - while(imin < imax) { - imid = (imin+imax)>>1; - - assert( imid < (int)ranges.size() ); - - if( ranges[imid].end <= end && (imid == ranges.size()-1 || ranges[imid+1].start > end ) ) { - imin = imid; - break; - } - else if( ranges[imid].start >= end ) imax = imid; - else imin = imid+1; - } - - int endindex = imin; - - if( startindex > endindex ) { - // create a new range - ranges.insert(ranges.begin()+startindex, RANGE(start, end)); - -#ifdef _DEBUG - // sanity check - for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); -#endif - return; - } - - if( endindex >= (int)ranges.size()-1 ) { - // pop until startindex is reached - int lastend = ranges.back().end; - int numpop = (int)ranges.size() - startindex - 1; - while(numpop-- > 0 ) ranges.pop_back(); - - assert( start <= ranges.back().end ); - if( start < ranges.back().start ) ranges.back().start = start; - if( lastend > ranges.back().end ) ranges.back().end = lastend; - if( end > ranges.back().end ) ranges.back().end = end; - -#ifdef _DEBUG - // sanity check - for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); -#endif - - return; - } - - if( endindex == 0 ) { - assert( end >= ranges.front().start ); - if( start < ranges.front().start ) ranges.front().start = start; - if( end > ranges.front().end ) ranges.front().end = end; - -#ifdef _DEBUG - // sanity check - for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); -#endif - } - - // somewhere in the middle - if( ranges[startindex].start < start ) start = ranges[startindex].start; - - if( startindex < endindex ) { - ranges.erase(ranges.begin() + startindex, ranges.begin() + endindex ); - } - - if( start < ranges[startindex].start ) ranges[startindex].start = start; - if( end > ranges[startindex].end ) ranges[startindex].end = end; - -#ifdef _DEBUG - // sanity check - for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); -#endif -} - -namespace ZeroGS { - -CRangeManager s_RangeMngr; // manages overwritten memory -static int gs_imageEnd = 0; - -void ResolveInRange(int start, int end) -{ - list listTargs; - s_DepthRTs.GetTargs(start, end, listTargs); - s_RTs.GetTargs(start, end, listTargs); - - if( listTargs.size() > 0 ) { - // flushes can delete targets! - Flush(0); - Flush(1); - - listTargs.clear(); - s_DepthRTs.GetTargs(start, end, listTargs); - s_RTs.GetTargs(start, end, listTargs); - - for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) { - // only resolve if not completely covered - (*it)->Resolve(); - } - } -} - -////////////////// -// Transferring // -////////////////// -void FlushTransferRanges(const tex0Info* ptex) -{ - assert( s_RangeMngr.ranges.size() > 0 ); - bool bHasFlushed = false; - list listTransmissionUpdateTargs; - - int texstart = -1, texend = -1; - if( ptex != NULL ) { - GetRectMemAddress(texstart, texend, ptex->psm, 0, 0, ptex->tw, ptex->th, ptex->tbp0, ptex->tbw); - } - - for(vector::iterator itrange = s_RangeMngr.ranges.begin(); itrange != s_RangeMngr.ranges.end(); ++itrange ) { - - int start = itrange->start; - int end = itrange->end; - - listTransmissionUpdateTargs.clear(); - s_DepthRTs.GetTargs(start, end, listTransmissionUpdateTargs); - s_RTs.GetTargs(start, end, listTransmissionUpdateTargs); - -// if( !bHasFlushed && listTransmissionUpdateTargs.size() > 0 ) { -// Flush(0); -// Flush(1); -// -//#ifdef _DEBUG -// // make sure targets are still the same -// list::iterator it; -// FORIT(it, listTransmissionUpdateTargs) { -// CRenderTargetMngr::MAPTARGETS::iterator itmap; -// for(itmap = s_RTs.mapTargets.begin(); itmap != s_RTs.mapTargets.end(); ++itmap) { -// if( itmap->second == *it ) -// break; -// } -// -// if( itmap == s_RTs.mapTargets.end() ) { -// -// for(itmap = s_DepthRTs.mapTargets.begin(); itmap != s_DepthRTs.mapTargets.end(); ++itmap) { -// if( itmap->second == *it ) -// break; -// } -// -// assert( itmap != s_DepthRTs.mapTargets.end() ); -// } -// } -//#endif -// } - - for(list::iterator it = listTransmissionUpdateTargs.begin(); it != listTransmissionUpdateTargs.end(); ++it) { - - CRenderTarget* ptarg = *it; - - if( (ptarg->status & CRenderTarget::TS_Virtual) || ptarg->targoffx != 0 || ptarg->targoffy != 0) - continue; - - if( !(ptarg->start < texend && ptarg->end > texstart) ) { - // chekc if target is currently being used - - if( !(g_GameSettings & GAME_NOQUICKRESOLVE) ) { - if( ptarg->fbp != vb[0].gsfb.fbp ) {//&& (vb[0].prndr == NULL || ptarg->fbp != vb[0].prndr->fbp) ) { - - if( ptarg->fbp != vb[1].gsfb.fbp ) { //&& (vb[1].prndr == NULL || ptarg->fbp != vb[1].prndr->fbp) ) { - // this render target currently isn't used and is not in the texture's way, so can safely ignore - // resolving it. Also the range has to be big enough compared to the target to really call it resolved - // (ffx changing screens, shadowhearts) - // start == ptarg->start, used for kh to transfer text - if( ptarg->IsDepth() || end-start > 0x50000 || ((g_GameSettings&GAME_QUICKRESOLVE1)&&start == ptarg->start) ) - ptarg->status |= CRenderTarget::TS_NeedUpdate|CRenderTarget::TS_Resolved; - - continue; - } - } - } - } - else { -// if( start <= texstart && end >= texend ) { -// // texture taken care of so can skip!? -// continue; -// } - } - - // the first range check was very rough; some games (dragonball z) have the zbuf in the same page as textures (but not overlapping) - // so detect that condition - if( ptarg->fbh % m_Blocks[ptarg->psm].height ) { - - // get start of left-most boundry page - int targstart, targend; - ZeroGS::GetRectMemAddress(targstart, targend, ptarg->psm, 0, 0, ptarg->fbw, ptarg->fbh & ~(m_Blocks[ptarg->psm].height-1), ptarg->fbp, ptarg->fbw); - - if( start >= targend ) { - - // don't bother - if( (ptarg->fbh % m_Blocks[ptarg->psm].height) <= 2 ) - continue; - - // calc how many bytes of the block that the page spans - } - } - - if( !(ptarg->status & CRenderTarget::TS_Virtual) ) { - - if( start < ptarg->end && end > ptarg->start ) { - - // suikoden5 is faster with check, but too big of a value and kh screens mess up - if( end - start > 0x8000 ) { - // intersects, do only one sided resolves - if( end-start > 4*ptarg->fbw ) { // at least it be greater than one scanline (spiro is faster) - if( start > ptarg->start ) { - ptarg->Resolve(ptarg->start, start); - } - else if( end < ptarg->end ) { - ptarg->Resolve(end, ptarg->end); - } - } - } - - ptarg->status |= CRenderTarget::TS_Resolved; - if( !ptarg->IsDepth() || (!(g_GameSettings & GAME_NODEPTHUPDATE) || end-start > 0x1000) ) - ptarg->status |= CRenderTarget::TS_NeedUpdate; - } - } - } - - ZeroGS::g_MemTargs.ClearRange(start, end); - } - - s_RangeMngr.Clear(); -} - -// need to take into account left over data of 24bit transfers (always <= 5) -static vector s_vTempBuffer, s_vTransferCache; - -void InitTransferHostLocal() -{ - if( g_bIsLost ) - return; - -#ifndef RELEASE_TO_PUBLIC - if( gs.trxpos.dx+gs.imageWnew > gs.dstbuf.bw ) - WARN_LOG("Transfer error, width exceeds\n"); -#endif - - bool bHasFlushed = false; - - gs.imageX = gs.trxpos.dx; - gs.imageY = gs.trxpos.dy; - gs.imageEndX = gs.imageX + gs.imageWnew; - gs.imageEndY = gs.imageY + gs.imageHnew; - s_vTransferCache.resize(0); - - assert( gs.imageEndX < 2048 && gs.imageEndY < 2048 ); - - // hack! viewful joe - if( gs.dstbuf.psm == 63 ) - gs.dstbuf.psm = 0; - - int start, end; - GetRectMemAddress(start, end, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); - - if( end > 0x00400000 ) { - WARN_LOG("host local out of bounds!\n"); - //gs.imageTransfer = -1; - end = 0x00400000; - } - - gs_imageEnd = end; - - if( vb[0].dwCount > 0 ) - Flush(0); - if( vb[1].dwCount > 0 ) - Flush(1); - - //PRIM_LOG("trans: bp:%x x:%x y:%x w:%x h:%x\n", gs.dstbuf.bp, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew); - -// if( !bHasFlushed && (vb[0].bNeedFrameCheck || vb[0].bNeedZCheck || vb[1].bNeedFrameCheck || vb[1].bNeedZCheck)) { -// Flush(0); -// Flush(1); -// bHasFlushed = 1; -// } -// -// // for all ranges, flush the targets -// // check if new rect intersects with current rendering texture, if so, flush -// if( vb[0].dwCount > 0 && vb[0].curprim.tme ) { -// int tstart, tend; -// GetRectMemAddress(tstart, tend, vb[0].tex0.psm, 0, 0, vb[0].tex0.tw, vb[0].tex0.th, vb[0].tex0.tbp0, vb[0].tex0.tbw); -// -// if( start < tend && end > tstart ) { -// Flush(0); -// Flush(1); -// bHasFlushed = 1; -// } -// } -// -// if( !bHasFlushed && vb[1].dwCount > 0 && vb[1].curprim.tme ) { -// int tstart, tend; -// GetRectMemAddress(tstart, tend, vb[1].tex0.psm, 0, 0, vb[1].tex0.tw, vb[1].tex0.th, vb[1].tex0.tbp0, vb[1].tex0.tbw); -// -// if( start < tend && end > tstart ) { -// Flush(0); -// Flush(1); -// bHasFlushed = 1; -// } -// } - - //ZeroGS::g_MemTargs.ClearRange(start, end); - //s_RangeMngr.Insert(start, end); -} - -void TransferHostLocal(const void* pbyMem, u32 nQWordSize) -{ - if( g_bIsLost ) - return; - - int start, end; - GetRectMemAddress(start, end, gs.dstbuf.psm, gs.imageX, gs.imageY, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); - assert( start < gs_imageEnd ); - - end = gs_imageEnd; - - // sometimes games can decompress to alpha channel of render target only, in this case - // do a resolve right away. wolverine x2 - if( gs.dstbuf.psm == PSMT8H || gs.dstbuf.psm == PSMT4HL || gs.dstbuf.psm == PSMT4HH ) { - list listTransmissionUpdateTargs; - s_RTs.GetTargs(start, end, listTransmissionUpdateTargs); - - for(list::iterator it = listTransmissionUpdateTargs.begin(); it != listTransmissionUpdateTargs.end(); ++it) { - - CRenderTarget* ptarg = *it; - - if( (ptarg->status & CRenderTarget::TS_Virtual) ) - continue; - - //DEBUG_LOG("zerogs: resolving to alpha channel\n"); - ptarg->Resolve(); - } - } - - s_RangeMngr.Insert(start, min(end, start+(int)nQWordSize*16)); - - const u8* porgend = (const u8*)pbyMem + 4 * nQWordSize; - - if( s_vTransferCache.size() > 0 ) { - - int imagecache = s_vTransferCache.size(); - s_vTempBuffer.resize(imagecache + nQWordSize*4); - memcpy(&s_vTempBuffer[0], &s_vTransferCache[0], imagecache); - memcpy(&s_vTempBuffer[imagecache], pbyMem, nQWordSize*4); - - pbyMem = (const void*)&s_vTempBuffer[0]; - porgend = &s_vTempBuffer[0]+s_vTempBuffer.size(); - - int wordinc = imagecache / 4; - if( (nQWordSize * 4 + imagecache)/3 == ((nQWordSize+wordinc) * 4) / 3 ) { - // can use the data - nQWordSize += wordinc; - } - } - - int leftover = m_Blocks[gs.dstbuf.psm].TransferHostLocal(pbyMem, nQWordSize); - - if( leftover > 0 ) { - // copy the last gs.image24bitOffset to the cache - s_vTransferCache.resize(leftover); - memcpy(&s_vTransferCache[0], porgend - leftover, leftover); - } - else s_vTransferCache.resize(0); - -#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) - if( g_bSaveTrans ) { - tex0Info t; - t.tbp0 = gs.dstbuf.bp; - t.tw = gs.imageWnew; - t.th = gs.imageHnew; - t.tbw = gs.dstbuf.bw; - t.psm = gs.dstbuf.psm; - SaveTex(&t, 0); - } -#endif -} - -// left/right, top/down -//void TransferHostLocal(const void* pbyMem, u32 nQWordSize) -//{ -// assert( gs.imageTransfer == 0 ); -// u8* pstart = g_pbyGSMemory + gs.dstbuf.bp*256; -// -// const u8* pendbuf = (const u8*)pbyMem + nQWordSize*4; -// int i = gs.imageY, j = gs.imageX; -// -//#define DSTPSM gs.dstbuf.psm -// -//#define TRANSFERHOSTLOCAL(psm, T, widthlimit) { \ -// const T* pbuf = (const T*)pbyMem; \ -// u32 nSize = nQWordSize*(4/sizeof(T)); \ -// assert( (nSize%widthlimit) == 0 && widthlimit <= 4 ); \ -// if( ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) DEBUG_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM); \ -// for(; i < gs.imageEndY; ++i) { \ -// for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += widthlimit) { \ -// /* write as many pixel at one time as possible */ \ -// writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ -// \ -// if( widthlimit > 1 ) { \ -// writePixel##psm##_0(pstart, (j+1)%2048, i%2048, pbuf[1], gs.dstbuf.bw); \ -// \ -// if( widthlimit > 2 ) { \ -// writePixel##psm##_0(pstart, (j+2)%2048, i%2048, pbuf[2], gs.dstbuf.bw); \ -// \ -// if( widthlimit > 3 ) { \ -// writePixel##psm##_0(pstart, (j+3)%2048, i%2048, pbuf[3], gs.dstbuf.bw); \ -// } \ -// } \ -// } \ -// } \ -// \ -// if( j >= gs.imageEndX ) { assert(j == gs.imageEndX); j = gs.trxpos.dx; } \ -// else { assert( nSize == 0 ); goto End; } \ -// } \ -//} \ -// -//#define TRANSFERHOSTLOCAL_4(psm) { \ -// const u8* pbuf = (const u8*)pbyMem; \ -// u32 nSize = nQWordSize*8; \ -// for(; i < gs.imageEndY; ++i) { \ -// for(; j < gs.imageEndX && nSize > 0; j += 8, nSize -= 8) { \ -// /* write as many pixel at one time as possible */ \ -// writePixel##psm##_0(pstart, j%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ -// writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ -// pbuf++; \ -// writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ -// writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ -// pbuf++; \ -// writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ -// writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ -// pbuf++; \ -// writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ -// writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ -// pbuf++; \ -// } \ -// \ -// if( j >= gs.imageEndX ) { /*assert(j == gs.imageEndX);*/ j = gs.trxpos.dx; } \ -// else { assert( nSize == 0 ); goto End; } \ -// } \ -//} \ -// -// switch (gs.dstbuf.psm) { -// case 0x0: TRANSFERHOSTLOCAL(32, u32, 2); break; -// case 0x1: TRANSFERHOSTLOCAL(24, u32, 4); break; -// case 0x2: TRANSFERHOSTLOCAL(16, u16, 4); break; -// case 0xA: TRANSFERHOSTLOCAL(16S, u16, 4); break; -// case 0x13: -// if( ((gs.imageEndX-gs.trxpos.dx)%4) ) { -// TRANSFERHOSTLOCAL(8, u8, 1); -// } -// else { -// TRANSFERHOSTLOCAL(8, u8, 4); -// } -// break; -// -// case 0x14: -//// if( (gs.imageEndX-gs.trxpos.dx)%8 ) { -//// // hack -//// if( abs((int)nQWordSize*8 - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx)) <= 8 ) { -//// // don't transfer -//// DEBUG_LOG("bad texture 4: %d %d %d\n", gs.trxpos.dx, gs.imageEndX, nQWordSize); -//// gs.imageEndX = gs.trxpos.dx + (gs.imageEndX-gs.trxpos.dx)&~7; -//// //i = gs.imageEndY; -//// //goto End; -//// gs.imageTransfer = -1; -//// } -//// } -// TRANSFERHOSTLOCAL_4(4); -// break; -// case 0x1B: TRANSFERHOSTLOCAL(8H, u8, 4); break; -// case 0x24: TRANSFERHOSTLOCAL_4(4HL); break; -// case 0x2C: TRANSFERHOSTLOCAL_4(4HH); break; -// case 0x30: TRANSFERHOSTLOCAL(32Z, u32, 2); break; -// case 0x31: TRANSFERHOSTLOCAL(24Z, u32, 4); break; -// case 0x32: TRANSFERHOSTLOCAL(16Z, u16, 4); break; -// case 0x3A: TRANSFERHOSTLOCAL(16SZ, u16, 4); break; -// } -// -//End: -// if( i >= gs.imageEndY ) { -// assert( i == gs.imageEndY ); -// gs.imageTransfer = -1; -// -// if( g_bSaveTrans ) { -// tex0Info t; -// t.tbp0 = gs.dstbuf.bp; -// t.tw = gs.imageWnew; -// t.th = gs.imageHnew; -// t.tbw = gs.dstbuf.bw; -// t.psm = gs.dstbuf.psm; -// SaveTex(&t, 0); -// } -// } -// else { -// /* update new params */ -// gs.imageY = i; -// gs.imageX = j; -// } -//} - -void InitTransferLocalHost() -{ - assert( gs.trxpos.sx+gs.imageWnew <= 2048 && gs.trxpos.sy+gs.imageHnew <= 2048 ); - -#ifndef RELEASE_TO_PUBLIC - if( gs.trxpos.sx+gs.imageWnew > gs.srcbuf.bw ) - WARN_LOG("Transfer error, width exceeds\n"); -#endif - - gs.imageX = gs.trxpos.sx; - gs.imageY = gs.trxpos.sy; - gs.imageEndX = gs.imageX + gs.imageWnew; - gs.imageEndY = gs.imageY + gs.imageHnew; - - int start, end; - GetRectMemAddress(start, end, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw); - ResolveInRange(start, end); -} - -// left/right, top/down -void TransferLocalHost(void* pbyMem, u32 nQWordSize) -{ - assert( gs.imageTransfer == 1 ); - - u8* pstart = g_pbyGSMemory + 256*gs.srcbuf.bp; - int i = gs.imageY, j = gs.imageX; - -#define TRANSFERLOCALHOST(psm, T) { \ - T* pbuf = (T*)pbyMem; \ - u32 nSize = nQWordSize*16/sizeof(T); \ - for(; i < gs.imageEndY; ++i) { \ - for(; j < gs.imageEndX && nSize > 0; ++j, --nSize) { \ - *pbuf++ = readPixel##psm##_0(pstart, j%2048, i%2048, gs.srcbuf.bw); \ - } \ - \ - if( j >= gs.imageEndX ) { assert( j == gs.imageEndX); j = gs.trxpos.sx; } \ - else { assert( nSize == 0 ); break; } \ - } \ -} \ - -#define TRANSFERLOCALHOST_24(psm) { \ - u8* pbuf = (u8*)pbyMem; \ - u32 nSize = nQWordSize*16/3; \ - for(; i < gs.imageEndY; ++i) { \ - for(; j < gs.imageEndX && nSize > 0; ++j, --nSize) { \ - u32 p = readPixel##psm##_0(pstart, j%2048, i%2048, gs.srcbuf.bw); \ - pbuf[0] = (u8)p; \ - pbuf[1] = (u8)(p>>8); \ - pbuf[2] = (u8)(p>>16); \ - pbuf += 3; \ - } \ - \ - if( j >= gs.imageEndX ) { assert( j == gs.imageEndX); j = gs.trxpos.sx; } \ - else { assert( nSize == 0 ); break; } \ - } \ -} \ - - switch (gs.srcbuf.psm) { - case 0x0: TRANSFERLOCALHOST(32, u32); break; - case 0x1: TRANSFERLOCALHOST_24(24); break; - case 0x2: TRANSFERLOCALHOST(16, u16); break; - case 0xA: TRANSFERLOCALHOST(16S, u16); break; - case 0x13: TRANSFERLOCALHOST(8, u8); break; - case 0x1B: TRANSFERLOCALHOST(8H, u8); break; - case 0x30: TRANSFERLOCALHOST(32Z, u32); break; - case 0x31: TRANSFERLOCALHOST_24(24Z); break; - case 0x32: TRANSFERLOCALHOST(16Z, u16); break; - case 0x3A: TRANSFERLOCALHOST(16SZ, u16); break; - default: assert(0); - } - - gs.imageY = i; - gs.imageX = j; - - if( gs.imageY >= gs.imageEndY ) { - assert( gs.imageY == gs.imageEndY ); - gs.imageTransfer = -1; - } -} - -// dir depends on trxpos.dir -void TransferLocalLocal() -{ - assert( gs.imageTransfer == 2 ); - assert( gs.trxpos.sx+gs.imageWnew < 2048 && gs.trxpos.sy+gs.imageHnew < 2048 ); - assert( gs.trxpos.dx+gs.imageWnew < 2048 && gs.trxpos.dy+gs.imageHnew < 2048 ); - assert( (gs.srcbuf.psm&0x7) == (gs.dstbuf.psm&0x7) ); - if( gs.trxpos.sx+gs.imageWnew > gs.srcbuf.bw ) - WARN_LOG("Transfer error, src width exceeds\n"); - if( gs.trxpos.dx+gs.imageWnew > gs.dstbuf.bw ) - WARN_LOG("Transfer error, dst width exceeds\n"); - - int srcstart, srcend, dststart, dstend; - - GetRectMemAddress(srcstart, srcend, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw); - GetRectMemAddress(dststart, dstend, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); - - // resolve the targs - ResolveInRange(srcstart, srcend); - - list listTargs; - s_RTs.GetTargs(dststart, dstend, listTargs); - for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) { - if( !((*it)->status & CRenderTarget::TS_Virtual) ) { - (*it)->Resolve(); - (*it)->status |= CRenderTarget::TS_NeedUpdate; - } - } - - u8* pSrcBuf = g_pbyGSMemory + gs.srcbuf.bp*256; - u8* pDstBuf = g_pbyGSMemory + gs.dstbuf.bp*256; - -#define TRANSFERLOCALLOCAL(srcpsm, dstpsm, widthlimit) { \ - if( (gs.imageWnew&widthlimit)!=0 ) break; \ - assert( (gs.imageWnew&widthlimit)==0 && widthlimit <= 4); \ - for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < gs.trxpos.sy+gs.imageHnew; i++, i2++) { \ - for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < gs.trxpos.sx+gs.imageWnew; j+=widthlimit, j2+=widthlimit) { \ - \ - writePixel##dstpsm##_0(pDstBuf, j2%2048, i2%2048, \ - readPixel##srcpsm##_0(pSrcBuf, j%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ - \ - if( widthlimit > 1 ) { \ - writePixel##dstpsm##_0(pDstBuf, (j2+1)%2048, i2%2048, \ - readPixel##srcpsm##_0(pSrcBuf, (j+1)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ - \ - if( widthlimit > 2 ) { \ - writePixel##dstpsm##_0(pDstBuf, (j2+2)%2048, i2%2048, \ - readPixel##srcpsm##_0(pSrcBuf, (j+2)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ - \ - if( widthlimit > 3 ) { \ - writePixel##dstpsm##_0(pDstBuf, (j2+3)%2048, i2%2048, \ - readPixel##srcpsm##_0(pSrcBuf, (j+3)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ - } \ - } \ - } \ - } \ - } \ -} \ - -#define TRANSFERLOCALLOCAL_4(srcpsm, dstpsm) { \ - assert( (gs.imageWnew%8) == 0 ); \ - for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < gs.trxpos.sy+gs.imageHnew; ++i, ++i2) { \ - for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < gs.trxpos.sx+gs.imageWnew; j+=8, j2+=8) { \ - /* NOTE: the 2 conseq 4bit values are in NOT in the same byte */ \ - u32 read = getPixelAddress##srcpsm##_0(j%2048, i%2048, gs.srcbuf.bw); \ - u32 write = getPixelAddress##dstpsm##_0(j2%2048, i2%2048, gs.dstbuf.bw); \ - pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ - \ - read = getPixelAddress##srcpsm##_0((j+1)%2048, i%2048, gs.srcbuf.bw); \ - write = getPixelAddress##dstpsm##_0((j2+1)%2048, i2%2048, gs.dstbuf.bw); \ - pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ - \ - read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ - write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ - pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ - \ - read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ - write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ - pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ - \ - read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ - write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ - pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ - \ - read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ - write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ - pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ - \ - read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ - write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ - pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ - \ - read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ - write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ - pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ - } \ - } \ -} \ - - switch (gs.srcbuf.psm) { - case PSMCT32: - if( gs.dstbuf.psm == PSMCT32 ) { - TRANSFERLOCALLOCAL(32, 32, 2); - } - else { - TRANSFERLOCALLOCAL(32, 32Z, 2); - } - break; - - case PSMCT24: - if( gs.dstbuf.psm == PSMCT24 ) { - TRANSFERLOCALLOCAL(24, 24, 4); - } - else { - TRANSFERLOCALLOCAL(24, 24Z, 4); - } - break; - - case PSMCT16: - switch(gs.dstbuf.psm) { - case PSMCT16: TRANSFERLOCALLOCAL(16, 16, 4); break; - case PSMCT16S: TRANSFERLOCALLOCAL(16, 16S, 4); break; - case PSMT16Z: TRANSFERLOCALLOCAL(16, 16Z, 4); break; - case PSMT16SZ: TRANSFERLOCALLOCAL(16, 16SZ, 4); break; - } - break; - - case PSMCT16S: - switch(gs.dstbuf.psm) { - case PSMCT16: TRANSFERLOCALLOCAL(16S, 16, 4); break; - case PSMCT16S: TRANSFERLOCALLOCAL(16S, 16S, 4); break; - case PSMT16Z: TRANSFERLOCALLOCAL(16S, 16Z, 4); break; - case PSMT16SZ: TRANSFERLOCALLOCAL(16S, 16SZ, 4); break; - } - break; - - case PSMT8: - if( gs.dstbuf.psm == PSMT8 ) { - TRANSFERLOCALLOCAL(8, 8, 4); - } - else { - TRANSFERLOCALLOCAL(8, 8H, 4); - } - break; - - case PSMT4: - - switch(gs.dstbuf.psm ) { - case PSMT4: TRANSFERLOCALLOCAL_4(4, 4); break; - case PSMT4HL: TRANSFERLOCALLOCAL_4(4, 4HL); break; - case PSMT4HH: TRANSFERLOCALLOCAL_4(4, 4HH); break; - } - break; - - case PSMT8H: - if( gs.dstbuf.psm == PSMT8 ) { - TRANSFERLOCALLOCAL(8H, 8, 4); - } - else { - TRANSFERLOCALLOCAL(8H, 8H, 4); - } - break; - - case PSMT4HL: - switch(gs.dstbuf.psm ) { - case PSMT4: TRANSFERLOCALLOCAL_4(4HL, 4); break; - case PSMT4HL: TRANSFERLOCALLOCAL_4(4HL, 4HL); break; - case PSMT4HH: TRANSFERLOCALLOCAL_4(4HL, 4HH); break; - } - break; - case PSMT4HH: - switch(gs.dstbuf.psm ) { - case PSMT4: TRANSFERLOCALLOCAL_4(4HH, 4); break; - case PSMT4HL: TRANSFERLOCALLOCAL_4(4HH, 4HL); break; - case PSMT4HH: TRANSFERLOCALLOCAL_4(4HH, 4HH); break; - } - break; - - case PSMT32Z: - if( gs.dstbuf.psm == PSMCT32 ) { - TRANSFERLOCALLOCAL(32Z, 32, 2); - } - else { - TRANSFERLOCALLOCAL(32Z, 32Z, 2); - } - break; - - case PSMT24Z: - if( gs.dstbuf.psm == PSMCT24 ) { - TRANSFERLOCALLOCAL(24Z, 24, 4); - } - else { - TRANSFERLOCALLOCAL(24Z, 24Z, 4); - } - break; - - case PSMT16Z: - switch(gs.dstbuf.psm) { - case PSMCT16: TRANSFERLOCALLOCAL(16Z, 16, 4); break; - case PSMCT16S: TRANSFERLOCALLOCAL(16Z, 16S, 4); break; - case PSMT16Z: TRANSFERLOCALLOCAL(16Z, 16Z, 4); break; - case PSMT16SZ: TRANSFERLOCALLOCAL(16Z, 16SZ, 4); break; - } - break; - - case PSMT16SZ: - switch(gs.dstbuf.psm) { - case PSMCT16: TRANSFERLOCALLOCAL(16SZ, 16, 4); break; - case PSMCT16S: TRANSFERLOCALLOCAL(16SZ, 16S, 4); break; - case PSMT16Z: TRANSFERLOCALLOCAL(16SZ, 16Z, 4); break; - case PSMT16SZ: TRANSFERLOCALLOCAL(16SZ, 16SZ, 4); break; - } - break; - } - - g_MemTargs.ClearRange(dststart, dstend); - -#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) - if( g_bSaveTrans ) { - tex0Info t; - t.tbp0 = gs.dstbuf.bp; - t.tw = gs.imageWnew; - t.th = gs.imageHnew; - t.tbw = gs.dstbuf.bw; - t.psm = gs.dstbuf.psm; - SaveTex(&t, 0); - - t.tbp0 = gs.srcbuf.bp; - t.tw = gs.imageWnew; - t.th = gs.imageHnew; - t.tbw = gs.srcbuf.bw; - t.psm = gs.srcbuf.psm; - SaveTex(&t, 0); - } -#endif -} - -void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw) -{ - if( m_Blocks[psm].bpp == 0 ) { - ERROR_LOG("ZeroGS: Bad psm 0x%x\n", psm); - start = 0; - end = 0x00400000; - return; - } - - if( (psm&0x30) == 0x30 || psm == 0xa ) { - - const BLOCK& b = m_Blocks[psm]; - - bw = (bw + b.width -1)/b.width; - start = bp*256 + ((y/b.height) * bw + (x/b.width) )*0x2000; - end = bp*256 + (((y+h-1)/b.height) * bw + (x + w + b.width - 1)/b.width)*0x2000; - } - else { - // just take the addresses - switch(psm) { - case 0x00: - case 0x01: - case 0x1b: - case 0x24: - case 0x2c: - start = 4*getPixelAddress32(x, y, bp, bw); - end = 4*getPixelAddress32(x+w-1, y+h-1, bp, bw) + 4; - break; - case 0x02: - start = 2*getPixelAddress16(x, y, bp, bw); - end = 2*getPixelAddress16(x+w-1, y+h-1, bp, bw)+2; - break; - case 0x13: - start = getPixelAddress8(x, y, bp, bw); - end = getPixelAddress8(x+w-1, y+h-1, bp, bw)+1; - break; - case 0x14: - { - start = getPixelAddress4(x, y, bp, bw)/2; - int newx = ((x+w-1+31)&~31)-1; - int newy = ((y+h-1+15)&~15)-1; - end = (getPixelAddress4(max(newx,x), max(newy,y), bp, bw)+2)/2; - break; - } - } - } -} - -void _Resolve(const D3DLOCKED_RECT& locksrc, int fbp, int fbw, int fbh, int psm, u32 fbm) -{ - s_nResolved += 2; - - // align the rect to the nearest page - // note that fbp is always aligned on page boundaries - int start, end; - GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); - - PRIM_LOG("resolve: %x %x %x (%x-%x)\n", fbp, fbw, fbh, start, end); - - int i, j; - short smask1 = gs.smask&1; - short smask2 = gs.smask&2; - u32 mask, imask; - - if( psm&2 ) { // 16 bit - // mask is shifted - imask = RGBA32to16(fbm); - mask = (~imask)&0xffff; - } - else { - mask = ~fbm; - imask = fbm; - - if( (psm&0xf)>0 ) { - // preserve the alpha? - mask &= 0x00ffffff; - imask |= 0xff000000; - } - } - -#define RESOLVE_32BIT(psm, T, Tsrc, blockbits, blockwidth, blockheight, convfn, frame, aax, aay) \ - { \ - Tsrc* src = (Tsrc*)locksrc.pBits; \ - T* pPageOffset = (T*)g_pbyGSMemory + fbp*(256/sizeof(T)), *dst; \ - int srcpitch = locksrc.Pitch * blockheight/sizeof(Tsrc); \ - int maxfbh = (0x00400000-fbp*256) / (sizeof(T) * fbw); \ - if( maxfbh > fbh ) maxfbh = fbh; \ - for(i = 0; i < (maxfbh&~(blockheight-1)); i += blockheight) { \ - /*if( smask2 && (i&1) == smask1 ) continue; */ \ - for(j = 0; j < fbw; j += blockwidth) { \ - /* have to write in the tiled format*/ \ - ##frame##SwizzleBlock##blockbits##(pPageOffset + getPixelAddress##psm##_0(j, i, fbw), \ - src+(j< psm - switch(psm) { - case PSMCT32: - case PSMCT24: - if( s_AAy ) { - RESOLVE_32BIT(32, u32, u32, 32A4, 8, 8, (u32), Frame, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(32, u32, u32, 32A2, 8, 8, (u32), Frame, 1, 0); - } - else { - RESOLVE_32BIT(32, u32, u32, 32, 8, 8, (u32), Frame, 0, 0); - } - break; - case PSMCT16: - if( s_AAy ) { - RESOLVE_32BIT(16, u16, u32, 16A4, 16, 8, RGBA32to16, Frame, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(16, u16, u32, 16A2, 16, 8, RGBA32to16, Frame, 1, 0); - } - else { - RESOLVE_32BIT(16, u16, u32, 16, 16, 8, RGBA32to16, Frame, 0, 0); - } - - break; - case PSMCT16S: - if( s_AAy ) { - RESOLVE_32BIT(16S, u16, u32, 16A4, 16, 8, RGBA32to16, Frame, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(16S, u16, u32, 16A2, 16, 8, RGBA32to16, Frame, 1, 0); - } - else { - RESOLVE_32BIT(16S, u16, u32, 16, 16, 8, RGBA32to16, Frame, 0, 0); - } - - break; - case PSMT32Z: - case PSMT24Z: - if( s_AAy ) { - RESOLVE_32BIT(32Z, u32, u32, 32A4, 8, 8, (u32), Frame, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(32Z, u32, u32, 32A2, 8, 8, (u32), Frame, 1, 0); - } - else { - RESOLVE_32BIT(32Z, u32, u32, 32, 8, 8, (u32), Frame, 0, 0); - } - - break; - case PSMT16Z: - if( s_AAy ) { - RESOLVE_32BIT(16Z, u16, u32, 16A4, 16, 8, (u16), Frame, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(16Z, u16, u32, 16A2, 16, 8, (u16), Frame, 1, 0); - } - else { - RESOLVE_32BIT(16Z, u16, u32, 16, 16, 8, (u16), Frame, 0, 0); - } - - break; - case PSMT16SZ: - if( s_AAy ) { - RESOLVE_32BIT(16SZ, u16, u32, 16A4, 16, 8, (u16), Frame, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(16SZ, u16, u32, 16A2, 16, 8, (u16), Frame, 1, 0); - } - else { - RESOLVE_32BIT(16SZ, u16, u32, 16, 16, 8, (u16), Frame, 0, 0); - } - - break; - } - } - else { - switch(psm) { - case PSMCT32: - case PSMCT24: - if( s_AAy ) { - RESOLVE_32BIT(32, u32, Vector_16F, 32A4, 8, 8, Float16ToARGB, Frame16, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(32, u32, Vector_16F, 32A2, 8, 8, Float16ToARGB, Frame16, 1, 0); - } - else { - RESOLVE_32BIT(32, u32, Vector_16F, 32, 8, 8, Float16ToARGB, Frame16, 0, 0); - } - - break; - case PSMCT16: - if( s_AAy ) { - RESOLVE_32BIT(16, u16, Vector_16F, 16A4, 16, 8, Float16ToARGB16, Frame16, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(16, u16, Vector_16F, 16A2, 16, 8, Float16ToARGB16, Frame16, 1, 0); - } - else { - RESOLVE_32BIT(16, u16, Vector_16F, 16, 16, 8, Float16ToARGB16, Frame16, 0, 0); - } - - break; - case PSMCT16S: - if( s_AAy ) { - RESOLVE_32BIT(16S, u16, Vector_16F, 16A4, 16, 8, Float16ToARGB16, Frame16, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(16S, u16, Vector_16F, 16A2, 16, 8, Float16ToARGB16, Frame16, 1, 0); - } - else { - RESOLVE_32BIT(16S, u16, Vector_16F, 16, 16, 8, Float16ToARGB16, Frame16, 0, 0); - } - - break; - case PSMT32Z: - case PSMT24Z: - if( s_AAy ) { - RESOLVE_32BIT(32Z, u32, Vector_16F, 32ZA4, 8, 8, Float16ToARGB_Z, Frame16, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(32Z, u32, Vector_16F, 32ZA2, 8, 8, Float16ToARGB_Z, Frame16, 1, 0); - } - else { - RESOLVE_32BIT(32Z, u32, Vector_16F, 32Z, 8, 8, Float16ToARGB_Z, Frame16, 0, 0); - } - - break; - case PSMT16Z: - if( s_AAy ) { - RESOLVE_32BIT(16Z, u16, Vector_16F, 16ZA4, 16, 8, Float16ToARGB16_Z, Frame16, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(16Z, u16, Vector_16F, 16ZA2, 16, 8, Float16ToARGB16_Z, Frame16, 1, 0); - } - else { - RESOLVE_32BIT(16Z, u16, Vector_16F, 16Z, 16, 8, Float16ToARGB16_Z, Frame16, 0, 0); - } - - break; - case PSMT16SZ: - if( s_AAy ) { - RESOLVE_32BIT(16SZ, u16, Vector_16F, 16ZA4, 16, 8, Float16ToARGB16_Z, Frame16, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(16SZ, u16, Vector_16F, 16ZA2, 16, 8, Float16ToARGB16_Z, Frame16, 1, 0); - } - else { - RESOLVE_32BIT(16SZ, u16, Vector_16F, 16Z, 16, 8, Float16ToARGB16_Z, Frame16, 0, 0); - } - - break; - } - } - - g_MemTargs.ClearRange(start, end); - INC_RESOLVE(); -} - -//////////// -// Saving // -//////////// -void SaveTex(tex0Info* ptex, int usevid) -{ - LPD3DTEX pTexture; - pd3dDevice->CreateTexture(ptex->tw, ptex->th, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &pTexture, NULL); - - D3DLOCKED_RECT lockdst; - pTexture->LockRect(0, &lockdst, NULL, 0); - - DWORD* dst = (DWORD*)lockdst.pBits; - u8* psrc = g_pbyGSMemory; - - CMemoryTarget* pmemtarg = NULL; - - if( usevid ) { - pmemtarg = g_MemTargs.GetMemoryTarget(*ptex, 1); - assert( pmemtarg != NULL ); - D3DLOCKED_RECT lock; - HRESULT hr = pmemtarg->ptexsys->LockRect(0, &lock, NULL, D3DLOCK_READONLY); - if( FAILED(hr) ) - return; - u32 offset = pmemtarg->realy * 4 * GPU_TEXWIDTH; - if( ptex->psm == PSMT8 ) offset *= ptex->cpsm <= 1 ? 4 : 2; - else if( ptex->psm == PSMT4 ) offset *= ptex->cpsm <= 1 ? 8 : 4; - - psrc = (u8*)lock.pBits - offset; - } - - for(int i = 0; i < ptex->th; ++i) { - for(int j = 0; j < ptex->tw; ++j) { - u32 u, addr; - switch(ptex->psm) { - case PSMCT32: - addr = getPixelAddress32(j, i, ptex->tbp0, ptex->tbw); - - if( addr*4 < 0x00400000 ) - u = readPixel32(psrc, j, i, ptex->tbp0, ptex->tbw); - else u = 0; - - break; - case PSMCT24: - addr = getPixelAddress24(j, i, ptex->tbp0, ptex->tbw); - - if( addr*4 < 0x00400000 ) - u = readPixel24(psrc, j, i, ptex->tbp0, ptex->tbw); - else u = 0; - - break; - case PSMCT16: - addr = getPixelAddress16(j, i, ptex->tbp0, ptex->tbw); - - if( addr*2 < 0x00400000 ) { - u = readPixel16(psrc, j, i, ptex->tbp0, ptex->tbw); - u = RGBA16to32(u); - } - else u = 0; - - break; - case PSMCT16S: - addr = getPixelAddress16(j, i, ptex->tbp0, ptex->tbw); - - if( addr*2 < 0x00400000 ) { - u = readPixel16S(psrc, j, i, ptex->tbp0, ptex->tbw); - u = RGBA16to32(u); - } - else u = 0; - break; - - case PSMT8: - addr = getPixelAddress8(j, i, ptex->tbp0, ptex->tbw); - - if( addr < 0x00400000 ) { - if( usevid ) { - if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); - else u = RGBA16to32(*(u16*)(psrc+2*addr)); - } - else - u = readPixel8(psrc, j, i, ptex->tbp0, ptex->tbw); - } - else u = 0; - break; - - case PSMT4: - addr = getPixelAddress4(j, i, ptex->tbp0, ptex->tbw); - - if( addr < 2*0x00400000 ) { - if( usevid ) { - if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); - else u = RGBA16to32(*(u16*)(psrc+2*addr)); - } - else - u = readPixel4(psrc, j, i, ptex->tbp0, ptex->tbw); - } - else u = 0; - break; - - case PSMT8H: - addr = getPixelAddress8H(j, i, ptex->tbp0, ptex->tbw); - - if( 4*addr < 0x00400000 ) { - if( usevid ) { - if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); - else u = RGBA16to32(*(u16*)(psrc+2*addr)); - } - else - u = readPixel8H(psrc, j, i, ptex->tbp0, ptex->tbw); - } - else u = 0; - - break; - - case PSMT4HL: - addr = getPixelAddress4HL(j, i, ptex->tbp0, ptex->tbw); - - if( 4*addr < 0x00400000 ) { - if( usevid ) { - if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); - else u = RGBA16to32(*(u16*)(psrc+2*addr)); - } - else - u = readPixel4HL(psrc, j, i, ptex->tbp0, ptex->tbw); - } - else u = 0; - break; - - case PSMT4HH: - addr = getPixelAddress4HH(j, i, ptex->tbp0, ptex->tbw); - - if( 4*addr < 0x00400000 ) { - if( usevid ) { - if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); - else u = RGBA16to32(*(u16*)(psrc+2*addr)); - } - else - u = readPixel4HH(psrc, j, i, ptex->tbp0, ptex->tbw); - } - else u = 0; - break; - - case PSMT32Z: - addr = getPixelAddress32Z(j, i, ptex->tbp0, ptex->tbw); - - if( 4*addr < 0x00400000 ) - u = readPixel32Z(psrc, j, i, ptex->tbp0, ptex->tbw); - else u = 0; - break; - - case PSMT24Z: - addr = getPixelAddress24Z(j, i, ptex->tbp0, ptex->tbw); - - if( 4*addr < 0x00400000 ) - u = readPixel24Z(psrc, j, i, ptex->tbp0, ptex->tbw); - else u = 0; - break; - - case PSMT16Z: - addr = getPixelAddress16Z(j, i, ptex->tbp0, ptex->tbw); - - if( 2*addr < 0x00400000 ) - u = readPixel16Z(psrc, j, i, ptex->tbp0, ptex->tbw); - else u = 0; - break; - - case PSMT16SZ: - addr = getPixelAddress16SZ(j, i, ptex->tbp0, ptex->tbw); - - if( 2*addr < 0x00400000 ) - u = readPixel16SZ(psrc, j, i, ptex->tbp0, ptex->tbw); - else u = 0; - break; - - default: - assert(0); - } - - *dst++ = u; - } - - dst += lockdst.Pitch/4 - ptex->tw; - } - - pTexture->UnlockRect(0); - - if( usevid ) { - pmemtarg->ptexsys->UnlockRect(0); - } - - D3DXSaveTextureToFile("tex.tga", D3DXIFF_TGA, pTexture, NULL); - - SAFE_RELEASE(pTexture); - -} - -} +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#if defined(_WIN32) || defined(__WIN32__) +#include +#include +#endif + +#include + +#include +#include +#include +#include +#include + +#include "GS.h" +#include "Mem.h" +#include "x86.h" +#include "Regs.h" +#include "zerogs.h" +#include "resource.h" + +#include "targets.h" + +const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); + +extern int g_GameSettings; +using namespace ZeroGS; +extern int g_TransferredToGPU; +extern BOOL g_bIsLost; +extern LPD3DTEX ptexConv16to32; + +#ifdef RELEASE_TO_PUBLIC +#define INC_RESOLVE() +#else +#define INC_RESOLVE() ++g_nResolve +extern u32 g_nResolve; +extern BOOL g_bSaveTrans; +#endif + +namespace ZeroGS { + CRenderTargetMngr s_RTs, s_DepthRTs; + CBitwiseTextureMngr s_BitwiseTextures; + CMemoryTargetMngr g_MemTargs; + + extern BYTE s_AAx, s_AAy; + extern BYTE bIndepWriteMasks; + extern BOOL s_bBeginScene; + extern D3DFORMAT g_RenderFormat; + extern DXVEC4 g_vdepth; + extern int icurctx; + + extern LPD3DVS pvsBitBlt; + extern LPD3DPS ppsBitBlt[2], ppsBitBltDepth[2], ppsBitBltDepthTex[2], ppsOne; + extern LPD3DPS ppsBaseTexture, ppsConvert16to32, ppsConvert32to16; + extern LPD3DVB pvbRect; +} + +extern LPD3DTEX s_ptexCurSet[2]; +extern LPD3DTEX ptexBilinearBlocks; +extern IDirect3DVolumeTexture9* ptexConv32to16; +BOOL g_bSaveZUpdate = 0; + +//////////////////// +// Render Targets // +//////////////////// +ZeroGS::CRenderTarget::CRenderTarget() : psurf(NULL), psys(NULL), ptex(NULL), ptexFeedback(NULL), psurfFeedback(NULL) +{ + nUpdateTarg = 0; + targoffx = targoffy = 0; +} + +ZeroGS::CRenderTarget::~CRenderTarget() +{ + Destroy(); +} + +CRenderTarget::CRenderTarget(const frameInfo& frame, CRenderTarget& r) +{ + lastused = timeGetTime(); + fbp = frame.fbp; + fbw = frame.fbw; + fbh = frame.fbh; + psm = (u8)frame.psm; + fbm = frame.fbm; + + // find the xy offset + int blockheight = (frame.psm&2) ? 64 : 32; + int scanlinewidth = 0x2000*(fbw>>6); + + // round down to nearest block and scanline + int startheight = ((256*(fbp-r.fbp))/scanlinewidth) * blockheight; + int offset = ((256*(fbp-r.fbp))%scanlinewidth) / 0x2000; + + targoffx = offset*64; + targoffy = startheight; + targheight = r.targheight; + + pmimicparent = &r; + + vposxy.x = 2.0f * (32767.0f / 8.0f) / (float)fbw; + vposxy.y = -2.0f * (32767.0f / 8.0f) / (float)targheight; + vposxy.z = -1+(2.0f*(float)targoffx-0.5f)/fbw; + vposxy.w = 1+(-2.0f*(float)targoffy+0.5f)/(float)targheight; + status = 0; + + GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); + + ptex = r.ptex; + if( ptex != NULL ) ptex->AddRef(); + psurf = r.psurf; + if( psurf != NULL ) psurf->AddRef(); + psys = r.psys; + if( psys != NULL ) psys->AddRef(); + + nUpdateTarg = 0; + ptexFeedback = NULL; + psurfFeedback = NULL; +} + +BOOL ZeroGS::CRenderTarget::Create(const frameInfo& frame) +{ + Resolve(); + Destroy(); + + lastused = timeGetTime(); + fbp = frame.fbp; + fbw = frame.fbw; + fbh = frame.fbh; + psm = (u8)frame.psm; + fbm = frame.fbm; + pmimicparent = NULL; + + vposxy.x = 2.0f * (32767.0f / 8.0f) / (float)fbw; + vposxy.y = -2.0f * (32767.0f / 8.0f) / (float)fbh; + vposxy.z = -1+((float)targoffx-0.5f)/fbw; + vposxy.w = 1+((float)targoffy+0.5f)/fbh; + status = 0; + + if( fbw > 0 && fbh > 0 ) { + GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); + + HRESULT hr; + V(pd3dDevice->CreateTexture(fbw<CreateOffscreenPlainSurface(fbw<GetSurfaceLevel(0, &psurf)); + } + + if( FAILED(hr) ) { + Destroy(); + return FALSE; + } + + targheight = fbh; + status = TS_NeedUpdate; + } + else { + start = end = 0; + } + + return TRUE; +} + +void ZeroGS::CRenderTarget::Destroy() +{ + SAFE_RELEASE(psurf); + SAFE_RELEASE(psys); + SAFE_RELEASE(ptex); + SAFE_RELEASE(ptexFeedback); + SAFE_RELEASE(psurfFeedback); +} + +void ZeroGS::CRenderTarget::SetTarget(int fbplocal, const Rect2& scissor, int context) +{ + int dy = 0; + + if( fbplocal != fbp ) { + DXVEC4 v; + + // will be rendering to a subregion + u32 bpp = (psm&2) ? 2 : 4; + assert( ((256/bpp)*(fbplocal-fbp)) % fbw == 0 ); + assert( fbplocal >= fbp ); + + dy = ((256/bpp)*(fbplocal-fbp)) / fbw; + + v.x = vposxy.x; + v.y = vposxy.y; + v.z = vposxy.z; + v.w = vposxy.w - dy*2.0f/(float)fbh; + SETCONSTF(GPU_POSXY0+context, v); + } + else + SETCONSTF(GPU_POSXY0+context, vposxy); + + RECT rc; + + // set render states + rc.left = scissor.x0>>3; + rc.top = (scissor.y0>>3) + dy; + rc.right = (scissor.x1>>3)+1; + rc.bottom = (scissor.y1>>3)+1+dy; + rc.right = min(rc.right, fbw); + rc.bottom = min(rc.bottom, fbh); + + rc.left += targoffx; rc.right += targoffx; + rc.top += targoffy; rc.bottom += targoffy; + rc.left <<= s_AAx; + rc.top <<= s_AAy; + rc.right <<= s_AAx; + rc.bottom <<= s_AAy; +// rc.right--; +// rc.bottom--; + + scissorrect = rc; +} + +void ZeroGS::CRenderTarget::SetViewport() +{ + D3DVIEWPORT9 view; + view.Width = fbw<SetViewport(&view); +} + +static int g_bSaveResolved = 0; +extern int s_nResolved; + +void ZeroGS::CRenderTarget::Resolve() +{ + if( psurf != NULL && !(status&TS_Resolved) && !(status&TS_NeedUpdate) ) { + + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + + if( (IsDepth() && !ZeroGS::IsWriteDepth()) || s_nResolved > 10 || (g_GameSettings&GAME_NOTARGETRESOLVE) || targoffx != 0 || targoffy != 0) { + // don't resolve if depths aren't used + status = TS_Resolved; + return; + } + + D3DLOCKED_RECT locksrc; + pd3dDevice->GetRenderTargetData(psurf, psys); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveResolved ) { + D3DXSaveSurfaceToFile("resolved.tga", D3DXIFF_TGA, psys, NULL, NULL); + g_bSaveResolved = 0; + } +#endif + + psys->LockRect(&locksrc, NULL, D3DLOCK_READONLY); + _Resolve(locksrc, fbp, fbw, fbh, psm, fbm); + psys->UnlockRect(); + + status = TS_Resolved; + } +} + +void ZeroGS::CRenderTarget::Resolve(int startrange, int endrange) +{ + assert( startrange < end && endrange > start ); // make sure it at least intersects + + if( psurf != NULL && !(status&TS_Resolved) && !(status&TS_NeedUpdate) ) { + + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveResolved ) { + D3DXSaveSurfaceToFile("resolved.tga", D3DXIFF_TGA, psys, NULL, NULL); + g_bSaveResolved = 0; + } +#endif + + if((g_GameSettings&GAME_NOTARGETRESOLVE) || targoffx != 0 || targoffy != 0) { + status = TS_Resolved; + return; + } + + int blockheight = (psm&2) ? 64 : 32; + int resolvefbp = fbp, resolveheight = fbh; + + int scanlinewidth = 0x2000*(fbw>>6); + + // in now way should data be overwritten!, instead resolve less + if( endrange < end ) { + // round down to nearest block and scanline + resolveheight = ((endrange-start)/(0x2000*(fbw>>6))) * blockheight; + if( resolveheight <= 32 ) { + status = TS_Resolved; + return; + } + } + else if( startrange > start ) { + // round up to nearest block and scanline + resolvefbp = startrange + scanlinewidth - 1; + resolvefbp -= resolvefbp % scanlinewidth; + + resolveheight = fbh-((resolvefbp-fbp)*blockheight/scanlinewidth); + if( resolveheight <= 64 ) { // this is a total hack, but kh doesn't resolve now + status = TS_Resolved; + return; + } + + resolvefbp >>= 8; + } + + D3DLOCKED_RECT locksrc; + pd3dDevice->GetRenderTargetData(psurf, psys); + + psys->LockRect(&locksrc, NULL, D3DLOCK_READONLY); + + if( fbp != resolvefbp ) + locksrc.pBits = (u8*)locksrc.pBits + ((resolvefbp-fbp)*256/scanlinewidth)*blockheight*locksrc.Pitch; + + _Resolve(locksrc, resolvefbp, fbw, resolveheight, psm, fbm); + psys->UnlockRect(); + + status = TS_Resolved; + } +} + +void ZeroGS::CRenderTarget::Update(int context, ZeroGS::CRenderTarget* pdepth) +{ + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + assert( targoffx == 0 && targoffy == 0 ); + + SETRS(D3DRS_SCISSORTESTENABLE, FALSE); + SETRS(D3DRS_ALPHABLENDENABLE, FALSE); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + + // assume depth already set + //pd3dDevice->SetDepthStencilSurface(psurfDepth); +// if( conf.mrtdepth && bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); +// else + pd3dDevice->SetRenderTarget(1, NULL); + + pd3dDevice->SetRenderTarget(0, psurf); + + DXVEC4 v = DXVEC4(1,1,-0.5f/(float)(fbw<second == this ) { + DEBUG_LOG("zerogs: updating self"); + nUpdateTarg = 0; + } + } + else if( ittarg->second == this ) { + DEBUG_LOG("zerogs: updating self"); + nUpdateTarg = 0; + } + } + + if( nUpdateTarg ) { + + pd3dDevice->SetTexture(SAMP_FINAL, ittarg->second->ptex); + + //assert( ittarg->second->fbw == fbw ); + int offset = (fbp-ittarg->second->fbp)*64/fbw; + if( psm & 2 ) // 16 bit + offset *= 2; + + v.x = 1; + v.y = (float)targheight / ittarg->second->fbh; + v.z = 0.25f / (fbw << s_AAx); + v.w = (float)offset / ittarg->second->fbh + 0.25f / (ittarg->second->fbh << s_AAy); + SETCONSTF(GPU_BITBLTTEX, v); + + v.x = v.y = v.z = v.w = 1; + SETCONSTF(GPU_ONECOLOR, v); + + pd3dDevice->SetPixelShader(ppsBaseTexture); + nUpdateTarg = 0; + } + else { + // align the rect to the nearest page + // note that fbp is always aligned on page boundaries + tex0Info texframe; + texframe.tbp0 = fbp; + texframe.tbw = fbw; + texframe.tw = fbw; + texframe.th = fbh; + texframe.psm = psm; + CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); + + // write color and zero out stencil buf, always 0 context! + // force bilinear if using AA + SetTexVariablesInt(0, (s_AAx || s_AAy)?2:0, texframe, pmemtarg, 1); + + v = DXVEC4(1,1,0,0); + SETCONSTF(GPU_BITBLTTEX, v); + + v.x = 1; + v.y = 2; + SETCONSTF(GPU_ONECOLOR, v); + + assert( psurf != NULL ); + + SetViewport(); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + + if( ZeroGS::IsWriteDestAlphaTest() ) { + SETRS(D3DRS_STENCILENABLE, TRUE); + SETRS(D3DRS_STENCILWRITEMASK, 0xff); + SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_ZERO); + } + + // render with an AA shader if possible (bilinearly interpolates data) + pd3dDevice->SetPixelShader(ppsBitBlt[s_AAx]); + } + + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + + // fill stencil buf only + if( ZeroGS::IsWriteDestAlphaTest() && !(g_GameSettings&GAME_NOSTENCIL) ) { + SETRS(D3DRS_COLORWRITEENABLE, 0); + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + SETRS(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); + SETRS(D3DRS_ALPHAREF, 0xff); + + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILREF, 1); + + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + } + + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + +// if( conf.mrtdepth && bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); +// else + if( conf.mrtdepth && pdepth != NULL && ZeroGS::IsWriteDepth() ) + pd3dDevice->SetRenderTarget(1, pdepth->psurf); + + status = TS_Resolved; + + // reset since settings changed + vb[0].bVarsTexSync = 0; + ZeroGS::ResetAlphaVariables(); +} + +void ZeroGS::CRenderTarget::ConvertTo32() +{ + LPD3DTEX ptexConv; + LPD3DSURF psurfConv; + + s_RTs.DestroyChildren(this); + + // create + HRESULT hr; + V(pd3dDevice->CreateTexture(fbw<GetSurfaceLevel(0, &psurfConv)); + + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + SETRS(D3DRS_SCISSORTESTENABLE, FALSE); + SETRS(D3DRS_ALPHABLENDENABLE, FALSE); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_STENCILENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + + // tex coords, test ffx bikanel island when changing these + float dx = 0.5f / (fbw << s_AAx); + float dy = 0.5f / (fbh << s_AAy); + + DXVEC4 v = DXVEC4(1, 1, -dx, dy); + SETCONSTF(GPU_BITBLTPOS, v); + + v.z = 0.5f*dx; + v.w = 0.5f*dy; + SETCONSTF(GPU_BITBLTTEX, v); + + v.x = v.y = v.z = 1; + v.w = 1; // since all alpha is mult by 2 + SETCONSTF(GPU_ONECOLOR, v); + + v.x = 16.0f / (float)fbw; + v.y = 64.0f / (float)fbh; + v.z = 0.5f * v.x; + v.w = 0.5f * v.y; + SETCONSTF(GPU_TEXOFFSET0, v); + + v.x = 8.0f / (float)fbw; + v.y = 0; + v.z = 0; + v.w = 0.25f; + SETCONSTF(GPU_PAGEOFFSET0, v); + + v.x = 1; + v.y = -0.5f; + v.z = 0; + v.w = 0.0001f; + SETCONSTF(GPU_TEXDIMS0, v); + + v.x = 0; + SETCONSTF(GPU_TEXBLOCK0, v); + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + + // assume depth already set !? + pd3dDevice->SetRenderTarget(1, NULL); + pd3dDevice->SetRenderTarget(0, psurfConv); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexConv32to16); + pd3dDevice->SetTexture(SAMP_FINAL, ptex); + + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_POINT); + + if( s_ptexCurSet[0] == ptex ) { + s_ptexCurSet[0] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY0, NULL); + } + if( s_ptexCurSet[1] == ptex ) { + s_ptexCurSet[1] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY1, NULL); + } + + fbh /= 2; // have 16 bit surfaces are usually 2x higher + targheight /= 2; + + SetViewport(); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + + // render with an AA shader if possible (bilinearly interpolates data) + pd3dDevice->SetPixelShader(ppsConvert16to32); + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + +#ifdef _DEBUG + //g_bSaveZUpdate = 1; + //D3DXSaveSurfaceToFile("tex3.tga", D3DXIFF_TGA, psurfConv, NULL, NULL); + if( g_bSaveZUpdate ) { + // buggy + D3DXSaveSurfaceToFile("tex3.tga", D3DXIFF_TGA, psurfConv, NULL, NULL); + D3DXSaveSurfaceToFile("tex1.tga", D3DXIFF_TGA, psurf, NULL, NULL); + + //LPD3DTEX ptemp; + //pd3dDevice->CreateTexture(fbw, fbh, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &ptemp, NULL); + + LPD3DSURF ptempsys; + V(pd3dDevice->CreateOffscreenPlainSurface(fbw<GetRenderTargetData(psurf, psys); + + psys->LockRect(&srclock, NULL, D3DLOCK_READONLY); + ptempsys->LockRect(&dstlock, NULL, 0); + DWORD cols[2]; + float tempf[4]; + for(int i = 0; i < fbh; ++i) { + for(int j = 0; j < fbw; ++j) { + D3DXVECTOR4_16F* pdst = (D3DXVECTOR4_16F*)dstlock.pBits + fbw*i + j; + int jj = 2*j - (j%16); + if( (j%16) >=8 ) jj += 8; + int ii = 2*i - (i%8); + if( j >= fbw/2 ) { ii += 8; jj -= fbw; } + D3DXVECTOR4_16F* psrc = (D3DXVECTOR4_16F*)srclock.pBits + fbw*ii + jj; + //D3DXFloat16To32Array(out, (D3DXFLOAT16*)psrc, 4); + cols[0] = Float16ToARGB(psrc[0]); + cols[1] = Float16ToARGB(psrc[8]); + //cols[0] = (cols[0]&0xff00ff00)|((cols[0]&0xff)<<16)|((cols[0]&0xff0000)>>16); + //cols[1] = (cols[1]&0xff00ff00)|((cols[1]&0xff)<<16)|((cols[1]&0xff0000)>>16); + DWORD col = RGBA32to16(cols[0])|(RGBA32to16(cols[1])<<16); + tempf[2] = (col&0xff)/255.0f; + tempf[1] = ((col>>8)&0xff)/255.0f; + tempf[0] = ((col>>16)&0xff)/255.0f; + tempf[3] = 2*(((col>>24)&0xff)/255.0f); + D3DXFloat32To16Array((D3DXFLOAT16*)pdst, tempf, 4); + } + } + psys->UnlockRect(); + ptempsys->UnlockRect(); + + D3DXSaveSurfaceToFile("tex2.tga", D3DXIFF_TGA, ptempsys, NULL, NULL); + +// SAFE_RELEASE(psys); +// psys = ptempsys; +// +// pd3dDevice->UpdateSurface(ptempsys, NULL, psurfConv, NULL); + } +#endif + + vposxy.y = -2.0f * (32767.0f / 8.0f) / (float)fbh; + vposxy.w = 1+0.5f/fbh; + + // restore + SAFE_RELEASE(ptex); + SAFE_RELEASE(psurf); + SAFE_RELEASE(psys); + SAFE_RELEASE(ptexFeedback); + SAFE_RELEASE(psurfFeedback); + ptex = ptexConv; + psurf = psurfConv; + + V(pd3dDevice->CreateOffscreenPlainSurface(fbw<SetTexture(SAMP_FINAL, NULL); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexBilinearBlocks); // restore + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + + status = TS_Resolved; + + // TODO, reset depth? + if( ZeroGS::icurctx >= 0 ) { + // reset since settings changed + vb[icurctx].bVarsTexSync = 0; + vb[icurctx].bVarsSetTarg = 0; + } + vb[0].bVarsTexSync = 0; +} + +// use when texture is not tiled and converting from 32bit to 16bit +// one condition is that the converted texture has to keep the same block configuration +// every 16 32bit horz pixels gets converted to 16x2 16bit horz pixels. +// the first row is the first 8 pixels, the second row is the last 8 pixels +// the last 8 columns are the upper bits +void ZeroGS::CRenderTarget::ConvertTo16() +{ + LPD3DTEX ptexConv; + LPD3DSURF psurfConv; + + s_RTs.DestroyChildren(this); + + // create + HRESULT hr; + V(pd3dDevice->CreateTexture(fbw<GetSurfaceLevel(0, &psurfConv)); + + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + SETRS(D3DRS_SCISSORTESTENABLE, FALSE); + SETRS(D3DRS_ALPHABLENDENABLE, FALSE); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_STENCILENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + + // tex coords, test ffx bikanel island when changing these + float dx = 0.5f / (fbw << s_AAx); + float dy = 0.5f / (fbh << s_AAy); + + DXVEC4 v = DXVEC4(1, 1, -dx, dy); + SETCONSTF(GPU_BITBLTPOS, v); + + v.z = 0.5f*dx; + v.w = 0.5f*dy; + SETCONSTF(GPU_BITBLTTEX, v); + + v.x = v.y = v.z = 1; + v.w = 2; // since all alpha is mult by 2 + SETCONSTF(GPU_ONECOLOR, v); + + v.x = 16.0f / (float)fbw; + v.y = 32.0f / (float)fbh; + v.z = 0.5f * v.x; + v.w = 0.5f * v.y; + SETCONSTF(GPU_TEXOFFSET0, v); + + v.x = 256.0f / 255.0f; + v.y = 256.0f / 255.0f; + v.z = 0.05f / 256.0f; + v.w = -0.001f / 256.0f; + SETCONSTF(GPU_PAGEOFFSET0, v); + + v.x = -0.5f; + v.y = 1; + v.z = 0; + v.w = -0.1f/fbh; + SETCONSTF(GPU_TEXDIMS0, v); + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + + // assume depth already set !? + pd3dDevice->SetRenderTarget(1, NULL); + pd3dDevice->SetRenderTarget(0, psurfConv); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexConv16to32); + pd3dDevice->SetTexture(SAMP_FINAL, ptex); + + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_POINT); + + if( s_ptexCurSet[0] == ptex ) { + s_ptexCurSet[0] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY0, NULL); + } + if( s_ptexCurSet[1] == ptex ) { + s_ptexCurSet[1] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY1, NULL); + } + + fbh *= 2; // have 16 bit surfaces are usually 2x higher + targheight *= 2; + + // need to set a dummy target! +// CRenderTargetMngr::MAPTARGETS::iterator itdepth = s_DepthRTs.mapDummyTargs.find( (fbw<<16)|fbh ); +// CDepthTarget* pnewdepth = NULL; +// if( itdepth == s_DepthRTs.mapDummyTargs.end() ) { +// frameInfo frame; +// frame.fbh = fbh; +// frame.fbw = fbw; +// frame.psm = 0x30; //? +// frame.fbw = fbw; +// frame.fbm = 0; +// pnewdepth = new CDepthTarget(); +// pnewdepth->Create(frame); +// s_DepthRTs.mapDummyTargs[(fbw<<16)|fbh] = pnewdepth; +// } +// else pnewdepth = (CDepthTarget*)itdepth->second; +// +// assert( pnewdepth != NULL ); +// pd3dDevice->SetDepthStencilSurface(pnewdepth->pdepth); + + SetViewport(); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + + // render with an AA shader if possible (bilinearly interpolates data) + pd3dDevice->SetPixelShader(ppsConvert32to16); + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + +#ifdef _DEBUG + //g_bSaveZUpdate = 1; + if( g_bSaveZUpdate ) { + pd3dDevice->GetRenderTargetData(psurf, psys); + + D3DXSaveSurfaceToFile("tex1.tga", D3DXIFF_TGA, psurfConv, NULL, NULL); + + LPD3DSURF ptempsys; + V(pd3dDevice->CreateOffscreenPlainSurface(fbw<LockRect(&srclock, NULL, D3DLOCK_READONLY); + ptempsys->LockRect(&dstlock, NULL, 0); + DWORD col; + float temp[4]; + for(int i = 0; i < fbh; ++i) { + for(int j = 0; j < fbw; ++j) { + D3DXVECTOR4_16F* pdst = (D3DXVECTOR4_16F*)dstlock.pBits + fbw*i + j; + int jj = j; + int upper = 0; + if( (j%16) >=8 ) { + jj -= 8; + upper = 1; + } + int ii = (i - (i%64))/2 + (i%64); + if( (i%64) >= 32 ) { + ii -= 32; + jj += 8; + } + D3DXVECTOR4_16F* psrc = (D3DXVECTOR4_16F*)srclock.pBits + fbw*ii + jj; + //D3DXFloat16To32Array(out, (D3DXFLOAT16*)psrc, 4); + col = Float16ToARGB(psrc[0]); + if( upper ) col >>= 16; + else col &= 0xffff; + col = RGBA16to32(col); + temp[2] = (col&0xff)/255.0f; + temp[1] = ((col>>8)&0xff)/255.0f; + temp[0] = ((col>>16)&0xff)/255.0f; + temp[3] = 2*(((col>>24)&0xff)/255.0f); + D3DXFloat32To16Array((D3DXFLOAT16*)pdst, temp, 4); + + } + } + psys->UnlockRect(); + ptempsys->UnlockRect(); + + D3DXSaveSurfaceToFile("tex2.tga", D3DXIFF_TGA, ptempsys, NULL, NULL); + + SAFE_RELEASE(psys); + psys = ptempsys; + + pd3dDevice->UpdateSurface(ptempsys, NULL, psurfConv, NULL); + } +#endif + + vposxy.y = -2.0f * (32767.0f / 8.0f) / (float)fbh; + vposxy.w = 1+0.5f/fbh; + + // restore + SAFE_RELEASE(ptex); + SAFE_RELEASE(psurf); + SAFE_RELEASE(psys); + SAFE_RELEASE(ptexFeedback); + SAFE_RELEASE(psurfFeedback); + ptex = ptexConv; + psurf = psurfConv; + + V(pd3dDevice->CreateOffscreenPlainSurface(fbw<SetTexture(SAMP_FINAL, NULL); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexBilinearBlocks); // restore + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + + status = TS_Resolved; + + // TODO, reset depth? + if( ZeroGS::icurctx >= 0 ) { + // reset since settings changed + vb[icurctx].bVarsTexSync = 0; + vb[icurctx].bVarsSetTarg = 0; + } + vb[0].bVarsTexSync = 0; +} + +void ZeroGS::CRenderTarget::_CreateFeedback() +{ + if( ptexFeedback == NULL ) { + // create + assert( pmimicparent == NULL ); + + HRESULT hr; + V(pd3dDevice->CreateTexture(fbw<GetSurfaceLevel(0, &psurfFeedback)); + } + + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + SETRS(D3DRS_SCISSORTESTENABLE, FALSE); + SETRS(D3DRS_ALPHABLENDENABLE, FALSE); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_STENCILENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + + // assume depth already set +// if( conf.mrtdepth && bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); +// else + pd3dDevice->SetRenderTarget(1, NULL); + + // tex coords, test ffx bikanel island when changing these + float dx = 0.5f / (fbw << s_AAx); + float dy = 0.5f / (fbh << s_AAy); + + DXVEC4 v = DXVEC4(1, 1, -dx, dy); + SETCONSTF(GPU_BITBLTPOS, v); + + v.z = 0.5f*dx; + v.w = 0.5f*dy; + SETCONSTF(GPU_BITBLTTEX, v); + + v.x = v.y = v.z = 1; + v.w = 1; // since all alpha is mult by 2 + SETCONSTF(GPU_ONECOLOR, v); + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + + pd3dDevice->SetRenderTarget(0, psurfFeedback); + pd3dDevice->SetTexture(SAMP_FINAL, ptex); + + if( s_ptexCurSet[0] == ptexFeedback ) { + s_ptexCurSet[0] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY0, NULL); + } + if( s_ptexCurSet[1] == ptexFeedback ) { + s_ptexCurSet[1] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY1, NULL); + } + + SetViewport(); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + + // render with an AA shader if possible (bilinearly interpolates data) + pd3dDevice->SetPixelShader(ppsBaseTexture); + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + + // restore + swap(ptex, ptexFeedback); + swap(psurf, psurfFeedback); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + + pd3dDevice->SetTexture(SAMP_FINAL, NULL); + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + status |= TS_FeedbackReady; + + // TODO, reset depth? + if( ZeroGS::icurctx >= 0 ) { + // reset since settings changed + vb[icurctx].bVarsTexSync = 0; + } +} + +ZeroGS::CDepthTarget::CDepthTarget() : CRenderTarget(), pdepth(NULL) {} + +ZeroGS::CDepthTarget::~CDepthTarget() +{ + Destroy(); +} + +BOOL ZeroGS::CDepthTarget::Create(const frameInfo& frame) +{ + if( !CRenderTarget::Create(frame) ) return FALSE; + + if( psm == 0x31 ) fbm = 0xff000000; + else fbm = 0; + + HRESULT hr; + V(pd3dDevice->CreateDepthStencilSurface(fbw<CreateDepthStencilSurface(fbw, fbh, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, FALSE, &pdepth, NULL)); + } + + if( FAILED(hr) ) + return FALSE; + + status = TS_NeedUpdate; + + return TRUE; +} + +void ZeroGS::CDepthTarget::Destroy() +{ + if( pd3dDevice != NULL ) { + pd3dDevice->SetRenderTarget(1, NULL); + pd3dDevice->SetDepthStencilSurface(NULL); + vb[0].bVarsSetTarg = 0; + vb[1].bVarsSetTarg = 0; + } + + CRenderTarget::Destroy(); + SAFE_RELEASE(pdepth); +} + +extern int g_nDepthUsed; // > 0 if depth is used + +void ZeroGS::CDepthTarget::Resolve() +{ + if( g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && ZeroGS::IsWriteDepth() && !(g_GameSettings&GAME_NODEPTHRESOLVE) ) + CRenderTarget::Resolve(); + else { + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + + if( !(status & TS_Virtual) || targoffx != 0 || targoffy != 0 ) + status |= TS_Resolved; + } + + if( !(status&TS_Virtual) ) { + ZeroGS::SetWriteDepth(); + } +} + +void ZeroGS::CDepthTarget::Resolve(int startrange, int endrange) +{ + if( g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && ZeroGS::IsWriteDepth() ) CRenderTarget::Resolve(startrange, endrange); + else { + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + + if( !(status & TS_Virtual) ) + status |= TS_Resolved; + } + + if( !(status&TS_Virtual) ) { + ZeroGS::SetWriteDepth(); + } +} + +extern int g_nDepthUpdateCount; + +void ZeroGS::CDepthTarget::Update(int context, ZeroGS::CRenderTarget* prndr) +{ + assert( !(status & TS_Virtual) ); + + CRenderTarget* pusetarg = NULL; + if( nUpdateTarg ) { + CRenderTargetMngr::MAPTARGETS::iterator ittarg = s_DepthRTs.mapTargets.find(nUpdateTarg); + if( ittarg == s_DepthRTs.mapTargets.end() || ittarg->second == this) { + DEBUG_LOG("zerogs: updating self"); + nUpdateTarg = 0; + } + else pusetarg = ittarg->second; + } + + tex0Info texframe; + CMemoryTarget* pmemtarg = NULL; + if( pusetarg == NULL ) { + // align the rect to the nearest page + // note that fbp is always aligned on page boundaries + texframe.tbp0 = fbp; + texframe.tbw = fbw; + texframe.tw = fbw; + texframe.th = fbh; + texframe.psm = psm; + pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); + } + + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + SETRS(D3DRS_SCISSORTESTENABLE, FALSE); + SETRS(D3DRS_ALPHABLENDENABLE, FALSE); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_ZENABLE, TRUE); + SETRS(D3DRS_ZWRITEENABLE, TRUE); + SETRS(D3DRS_STENCILENABLE, FALSE); + SETRS(D3DRS_ZFUNC, D3DCMP_ALWAYS); + + DXVEC4 v = DXVEC4(1,1,-0.5f/(float)(fbw<SetTexture(SAMP_FINAL, pusetarg->ptex); + + //assert( pusetarg->fbw == fbw ); + int offset = (fbp-pusetarg->fbp)*64/fbw; + if( psm & 2 ) // 16 bit + offset *= 2; + + v.x = 1; + v.y = (float)fbh / pusetarg->fbh; + v.z = 0.25f / (fbw << s_AAx); + v.w = (float)offset / pusetarg->fbh + 0.25f / (pusetarg->fbh << s_AAy); + SETCONSTF(GPU_BITBLTTEX, v); + } + else { + // write color and zero out stencil buf, always 0 context! + SetTexVariablesInt(0, 0, texframe, pmemtarg, 1); + + DXVEC4 v = DXVEC4(1,1,0.5f/(float)fbw,0.5f/(float)fbh); + SETCONSTF(GPU_BITBLTTEX, v); + } + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + + v.x = 1; + v.y = 2; + v.z = (psm&3)==2?1.0f:0.0f; + v.w = g_filog32; + SETCONSTF(GPU_ONECOLOR, v); + + assert( psurf != NULL ); + + DXVEC4 vdepth = ((255.0f/256.0f)*g_vdepth); + if( psm == PSMT24Z ) vdepth.w = 0; + else if( psm != PSMT32Z ) { vdepth.z = vdepth.w = 0; } + SETCONSTF(GPU_BITBLTZ, ((255.0f/256.0f)*vdepth)); + + assert( pdepth != NULL ); + + if( ZeroGS::IsWriteDepth() && conf.mrtdepth && bIndepWriteMasks) { + // write in MRT1 + pd3dDevice->SetRenderTarget(1, psurf); + pd3dDevice->SetRenderTarget(0, prndr->psurf); + SETRS(D3DRS_COLORWRITEENABLE, 0); + SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + } + else { + // turn off writes? + if( bIndepWriteMasks ) { + pd3dDevice->SetRenderTarget(0, prndr->psurf); + SETRS(D3DRS_COLORWRITEENABLE, 0); + } + else pd3dDevice->SetRenderTarget(0, psurf); + } + + SetViewport(); + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + + pd3dDevice->SetDepthStencilSurface(pdepth); + + if( pusetarg != NULL ) { + pd3dDevice->SetPixelShader(ppsBitBltDepthTex[conf.mrtdepth]); + } + else { + pd3dDevice->SetPixelShader(ppsBitBltDepth[conf.mrtdepth]); + } + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + + status = TS_Resolved; + + if( conf.mrtdepth && bIndepWriteMasks ) { + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + } + + if( !ZeroGS::IsWriteDepth() ) { + pd3dDevice->SetRenderTarget(1, NULL); + } + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + +#ifdef _DEBUG + if( g_bSaveZUpdate ) { + if( pusetarg != NULL ) + D3DXSaveTextureToFile("tex.tga", D3DXIFF_TGA, pusetarg->ptex, NULL); + else + SaveTex(&texframe, 1); + D3DXSaveSurfaceToFile("frame1.tga", D3DXIFF_TGA, psurf, NULL, NULL); + } + //pd3dDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0, 0, 0); +#endif +} + +void ZeroGS::CDepthTarget::SetDepthTarget() +{ + pd3dDevice->SetDepthStencilSurface(pdepth); + + if( conf.mrtdepth && ZeroGS::IsWriteDepth() ) + pd3dDevice->SetRenderTarget(1, psurf); +} + +void ZeroGS::CRenderTargetMngr::Destroy() +{ + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) + delete it->second; + mapTargets.clear(); + for(MAPTARGETS::iterator it = mapDummyTargs.begin(); it != mapDummyTargs.end(); ++it) + delete it->second; + mapDummyTargs.clear(); +} + +CRenderTarget* ZeroGS::CRenderTargetMngr::GetTarg(const frameInfo& frame, DWORD opts, int maxposheight) +{ + if( frame.fbw <= 0 || frame.fbh <= 0 ) + return NULL; + + u32 key = frame.fbp|(frame.fbw<<16); + MAPTARGETS::iterator it = mapTargets.find(key); + + // only enforce height if frame.fbh <= 0x1c0 + bool bfound = it != mapTargets.end(); + if( bfound ) { + if( opts&TO_StrictHeight ) { + bfound = it->second->fbh == frame.fbh; + + if( (g_GameSettings&GAME_PARTIALDEPTH) && !bfound ) { + MAPTARGETS::iterator itnew = mapTargets.find(key+1); + if( itnew != mapTargets.end() && itnew->second->fbh == frame.fbh ) { + // found! delete the previous and restore + delete it->second; + mapTargets.erase(it); + + it = mapTargets.insert(MAPTARGETS::value_type(key, itnew->second)).first; // readd + mapTargets.erase(itnew); // delete old + + bfound = true; + } + } + } + else { + if( (frame.psm&2)==(it->second->psm&2) && !(g_GameSettings & GAME_FULL16BITRES) ) + bfound = (frame.fbh > 0x1c0 || it->second->fbh >= frame.fbh) && it->second->fbh <= maxposheight; + } + } + + if( !bfound ) { + // might be a virtual target + it = mapTargets.find(key|TARGET_VIRTUAL_KEY); + bfound = it != mapTargets.end() && ((opts&TO_StrictHeight) ? it->second->fbh == frame.fbh : it->second->fbh >= frame.fbh) && it->second->fbh <= maxposheight; + } + + if( bfound && (frame.psm&2) && !(it->second->psm&2) && (g_GameSettings&GAME_FULL16BITRES) ) { + // mgs3 + if( frame.fbh > it->second->fbh ) { + bfound = false; + } + } + + if( bfound ) { + + // can be both 16bit and 32bit + if( (frame.psm&2) != (it->second->psm&2) ) { + // a lot of games do this actually... +#ifdef _DEBUG + WARN_LOG("Really bad formats! %d %d\n", frame.psm, it->second->psm); +#endif + if( !(opts&TO_StrictHeight) ) { + if( !(g_GameSettings & GAME_VSSHACKOFF) ) { + if( it->second->psm & 2 ) { + it->second->status |= CRenderTarget::TS_NeedConvert32; + it->second->fbh /= 2; + it->second->targheight /= 2; + } + else { + it->second->status |= CRenderTarget::TS_NeedConvert16; + it->second->fbh *= 2; + it->second->targheight *= 2; + } + } + } + + // recalc extents + GetRectMemAddress(it->second->start, it->second->end, frame.psm, 0, 0, frame.fbw, it->second->fbh, it->second->fbp, frame.fbw); + } + else { + // certain variables have to be reset every time + if( (it->second->psm&~1) != (frame.psm&~1) ) { +#ifndef RELEASE_TO_PUBLIC + WARN_LOG("bad formats 2: %d %d\n", frame.psm, it->second->psm); +#endif + it->second->psm = frame.psm; + + // recalc extents + GetRectMemAddress(it->second->start, it->second->end, frame.psm, 0, 0, frame.fbw, it->second->fbh, it->second->fbp, frame.fbw); + } + } + + if( it->second->fbm != frame.fbm ) { + //WARN_LOG("bad fbm: 0x%8.8x 0x%8.8x, psm: %d\n", frame.fbm, it->second->fbm, frame.psm); + } + + it->second->fbm &= frame.fbm; + it->second->psm = frame.psm; // have to convert (ffx2) + + if( (it->first & TARGET_VIRTUAL_KEY) && !(opts&TO_Virtual) ) { + // switch + it->second->lastused = timeGetTime(); + return Promote(it->first&~TARGET_VIRTUAL_KEY); + } + + // check if there exists a more recent target that this target could update from + // only update if target isn't mirrored + bool bCheckHalfCovering = (g_GameSettings&GAME_FULL16BITRES) && (it->second->psm&2) && it->second->fbh +32 < frame.fbh; + + for(MAPTARGETS::iterator itnew = mapTargets.begin(); itnew != mapTargets.end(); ++itnew) { + if( itnew->second != it->second && itnew->second->ptex != it->second->ptex && itnew->second->ptexFeedback != it->second->ptex && + itnew->second->lastused > it->second->lastused && !(itnew->second->status & CRenderTarget::TS_NeedUpdate) ) { + + // if new target totally encompasses the current one + if( itnew->second->start <= it->second->start && itnew->second->end >= it->second->end ) { + it->second->status |= CRenderTarget::TS_NeedUpdate; + it->second->nUpdateTarg = itnew->first; + break; + } + + // if 16bit, then check for half encompassing targets + if( bCheckHalfCovering && itnew->second->start > it->second->start && itnew->second->start < it->second->end && itnew->second->end <= it->second->end+0x2000 ) { + it->second->status |= CRenderTarget::TS_NeedUpdate; + it->second->nUpdateTarg = itnew->first; + break; + } + } + } + + it->second->lastused = timeGetTime(); + + return it->second; + } + + // NOTE: instead of resolving, if current render targ is completely outside of old, can transfer + // the data like that. + + // first search for the target + CRenderTarget* ptarg = NULL; + + // have to change, so recreate (find all intersecting targets and Resolve) + u32 besttarg = 0; + + if( !(opts & CRenderTargetMngr::TO_Virtual) ) { + + int start, end; + GetRectMemAddress(start, end, frame.psm, 0, 0, frame.fbw, frame.fbh, frame.fbp, frame.fbw); + + if( !(opts & CRenderTargetMngr::TO_StrictHeight) ) { + + if( g_GameSettings&GAME_PARTIALPOINTERS ) { + // if there is a render target that wholly encompasses this one, then use the pointer directly + // this render target also has to be small (mgs3) + if( frame.fbh <= 0x40 ) { + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end && (it->second->psm&~1) == (frame.psm&~1) && (it->second->fbp&0xff) == 0 ) { + ptarg = new CRenderTarget(frame, *it->second); + besttarg = it->first; + break; + } + } + } + } + } + + CRenderTarget* pbesttarg = NULL; + + if( besttarg == 0 ) { + // if there is only one intersecting target and it encompasses the current one, update the new render target with + // its data instead of resolving then updating (ffx2). Do not change the original target. + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end ) { +// if( g_GameSettings&GAME_FASTUPDATE ) { +// besttarg = it->first; +// //break; +// } +// else { + if( (g_GameSettings&GAME_FASTUPDATE) || (it->second->fbw == frame.fbw && + // check depth targets only if partialdepth option + (it->second->fbp != frame.fbp|| ((g_GameSettings&GAME_PARTIALDEPTH)&&(opts&CRenderTargetMngr::TO_DepthBuffer))) ) ) { + + if( besttarg != 0 ) { + besttarg = 0; + break; + } + + if( start >= it->second->start && end <= it->second->end ) { + besttarg = it->first; + pbesttarg = it->second; + } + } +// } + } + } + } + + if( besttarg == 0 ) { + // if none found, resolve all + DestroyAll(start, end, frame.fbw); + } + else if( key == besttarg && pbesttarg != NULL ) { + // add one and store in a different location until best targ is processed + mapTargets.erase(besttarg); + besttarg++; + mapTargets[besttarg] = pbesttarg; + } + } + + if( mapTargets.size() > 8 ) { + // release some resources + it = GetOldestTarg(mapTargets); + + // if more than 5s passed since target used, destroy + if( it->second != vb[0].prndr && it->second != vb[1].prndr && it->second != vb[0].pdepth && it->second != vb[1].pdepth && + timeGetTime()-it->second->lastused > 5000 ) { + DestroyChildren(it->second); + delete it->second; + mapTargets.erase(it); + } + } + + if( ptarg == NULL ) { + // not found yet, so create + + if( mapDummyTargs.size() > 8 ) { + it = GetOldestTarg(mapDummyTargs); + + DestroyChildren(it->second); + delete it->second; + mapDummyTargs.erase(it); + } + + it = mapDummyTargs.find( (frame.fbw<<16)|frame.fbh ); + if( it != mapDummyTargs.end() ) { + ptarg = it->second; + mapDummyTargs.erase(it); + + // restore all setttings + ptarg->psm = frame.psm; + ptarg->fbm = frame.fbm; + ptarg->fbp = frame.fbp; + GetRectMemAddress(ptarg->start, ptarg->end, frame.psm, 0, 0, frame.fbw, frame.fbh, frame.fbp, frame.fbw); + + ptarg->status = CRenderTarget::TS_NeedUpdate; + } + else { + // create anew + ptarg = (opts&TO_DepthBuffer) ? new CDepthTarget() : new CRenderTarget(); + CRenderTargetMngr* pmngrs[2] = { &s_DepthRTs, this == &s_RTs ? &s_RTs : NULL }; + int cur = 0; + + while( !ptarg->Create(frame) ) { + + // destroy unused targets + if( mapDummyTargs.size() > 0 ) { + it = mapDummyTargs.begin(); + delete it->second; + mapDummyTargs.erase(it); + continue; + } + + if( g_MemTargs.listClearedTargets.size() > 0 ) { + g_MemTargs.DestroyCleared(); + continue; + } + else + if( g_MemTargs.listTargets.size() > 32 ) { + g_MemTargs.DestroyOldest(); + continue; + } + + if( pmngrs[cur] == NULL ) { + cur = !cur; + if( pmngrs[cur] == NULL ) { + WARN_LOG("Out of memory!\n"); + delete ptarg; + return NULL; + } + } + + if( pmngrs[cur]->mapTargets.size() == 0 ) + { + pmngrs[cur] = NULL; + cur = !cur; + continue; + } + + it = GetOldestTarg(pmngrs[cur]->mapTargets); + + DestroyTarg(it->second); + pmngrs[cur]->mapTargets.erase(it); + cur = !cur; + } + } + } + + if( (opts & CRenderTargetMngr::TO_Virtual) ) { + ptarg->status = CRenderTarget::TS_Virtual; + key |= TARGET_VIRTUAL_KEY; + + if( (it = mapTargets.find(key)) != mapTargets.end() ) { + + DestroyTarg(it->second); + it->second = ptarg; + ptarg->nUpdateTarg = besttarg; + return ptarg; + } + } + else + assert( mapTargets.find(key) == mapTargets.end()); + + ptarg->nUpdateTarg = besttarg; + mapTargets[key] = ptarg; + return ptarg; +} + +void CRenderTargetMngr::DestroyChildren(CRenderTarget* ptarg) +{ + if(ptarg == NULL) + return; + + MAPTARGETS::iterator ittarg = mapTargets.begin(); + while(ittarg != mapTargets.end()) { + if( ittarg->second->pmimicparent == ptarg ) { + assert( ittarg->second != ptarg ); + delete ittarg->second; + ittarg = mapTargets.erase(ittarg); + } + else ++ittarg; + } +} + +ZeroGS::CRenderTargetMngr::MAPTARGETS::iterator ZeroGS::CRenderTargetMngr::GetOldestTarg(MAPTARGETS& m) +{ + if( m.size() == 0 ) { + return m.end(); + } + + // release some resources + u32 curtime = timeGetTime(); + MAPTARGETS::iterator itmaxtarg = m.begin(); + for(MAPTARGETS::iterator it = ++m.begin(); it != m.end(); ++it) { + if( itmaxtarg->second->lastused-curtime < it->second->lastused-curtime ) itmaxtarg = it; + } + + return itmaxtarg; +} + +void ZeroGS::CRenderTargetMngr::GetTargs(int start, int end, list& listTargets) const +{ + for(MAPTARGETS::const_iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end ) listTargets.push_back(it->second); + } +} + +void ZeroGS::CRenderTargetMngr::Resolve(int start, int end) +{ + for(MAPTARGETS::const_iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end ) + it->second->Resolve(); + } +} + +void ZeroGS::CMemoryTargetMngr::Destroy() +{ + listTargets.clear(); + listClearedTargets.clear(); +} + +int memcmp_clut16(u16* pSavedBuffer, u16* pClutBuffer, int clutsize) +{ + assert( (clutsize&31) == 0 ); + + // left > 0 only when csa < 16 + int left = ((u32)pClutBuffer & 2) ? 0 : (((u32)pClutBuffer & 0x3ff)/2) + clutsize - 512; + if( left > 0 ) clutsize -= left; + + while(clutsize > 0) { + for(int i = 0; i < 16; ++i) { + if( pSavedBuffer[i] != pClutBuffer[2*i] ) + return 1; + } + + clutsize -= 32; + pSavedBuffer += 16; + pClutBuffer += 32; + } + + if( left > 0 ) { + pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + 2); + + while(left > 0) { + for(int i = 0; i < 16; ++i) { + if( pSavedBuffer[i] != pClutBuffer[2*i] ) + return 1; + } + + left -= 32; + pSavedBuffer += 16; + pClutBuffer += 32; + } + } + + return 0; +} + +bool ZeroGS::CMemoryTarget::ValidateClut(const tex0Info& tex0) +{ + assert( tex0.psm == psm && PSMT_ISCLUT(psm) && cpsm == tex0.cpsm ); + + int nClutOffset = 0; + int clutsize = 0; + + int entries = (tex0.psm&3)==3 ? 256 : 16; + if( tex0.cpsm <= 1 ) { // 32 bit + nClutOffset = 64 * tex0.csa; + clutsize = min(entries, 256-tex0.csa*16)*4; + } + else { + nClutOffset = 32 * (tex0.csa&15) + (tex0.csa>=16?2:0); + clutsize = min(entries, 512-tex0.csa*16)*2; + } + + assert( clutsize == clut.size() ); + + if( cpsm <= 1 ) { + // memcmp_mmx doesn't work on x86-64 +#ifdef __x86_64__ + if( memcmp(&clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize) ) +#else + if( memcmp_mmx(&clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize) ) +#endif + return false; + } + else { + if( memcmp_clut16((u16*)&clut[0], (u16*)(ZeroGS::g_pbyGSClut+nClutOffset), clutsize) ) + return false; + } + + return true; +} + +int VALIDATE_THRESH = 8; +u32 TEXDESTROY_THRESH = 16; + +bool ZeroGS::CMemoryTarget::ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex) +{ + if( clearmaxy == 0 ) + return true; + + int checkstarty = max(starttex, clearminy); + int checkendy = min(endtex, clearmaxy); + if( checkstarty >= checkendy ) + return true; + + if( validatecount++ > VALIDATE_THRESH ) { + height = 0; + return false; + } + + // lock and compare + D3DLOCKED_RECT lock; + assert( ptex != NULL ); + + if( memory != NULL ) { + assert( memory->ptr != NULL ); + lock.pBits = memory->ptr; + } + else { + assert( ptexsys != NULL ); + ptexsys->LockRect(0, &lock, NULL, D3DLOCK_READONLY); + } + + // memcmp_mmx doesn't work on x86_64 +#ifdef __x86_64__ + int result = memcmp((u8*)lock.pBits + (checkstarty-realy)*4*GPU_TEXWIDTH, ZeroGS::g_pbyGSMemory+checkstarty*4*GPU_TEXWIDTH, (checkendy-checkstarty)*4*GPU_TEXWIDTH); +#else + int result = memcmp_mmx((u8*)lock.pBits + (checkstarty-realy)*4*GPU_TEXWIDTH, ZeroGS::g_pbyGSMemory+checkstarty*4*GPU_TEXWIDTH, (checkendy-checkstarty)*4*GPU_TEXWIDTH); +#endif + + if( memory == NULL ) + ptexsys->UnlockRect(0); + + if( result == 0 || !bDeleteBadTex ) { + if( result == 0 ) clearmaxy = 0; + return result == 0; + } + + // delete clearminy, clearmaxy range (not the checkstarty, checkendy range) + int newstarty = 0; + if( clearminy <= starty ) { + if( clearmaxy < starty + height) { + // preserve end + height = starty+height-clearmaxy; + starty = clearmaxy; + assert(height > 0); + } + else { + // destroy + height = 0; + } + } + else { + // beginning can be preserved + height = clearminy-starty; + } + + clearmaxy = 0; + assert( starty >= realy && starty+height<=realy+realheight ); + + return false; +} + +// used to build clut textures (note that this is for both 16 and 32 bit cluts) +#define BUILDCLUT() { \ + switch(tex0.psm) { \ + case PSMT8: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/2; ++j) { \ + pdst[0] = pclut[psrc[0]]; \ + pdst[1] = pclut[psrc[1]]; \ + pdst[2] = pclut[psrc[2]]; \ + pdst[3] = pclut[psrc[3]]; \ + pdst[4] = pclut[psrc[4]]; \ + pdst[5] = pclut[psrc[5]]; \ + pdst[6] = pclut[psrc[6]]; \ + pdst[7] = pclut[psrc[7]]; \ + pdst += 8; \ + psrc += 8; \ + } \ + } \ + break; \ + case PSMT4: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH; ++j) { \ + pdst[0] = pclut[psrc[0]&15]; \ + pdst[1] = pclut[psrc[0]>>4]; \ + pdst[2] = pclut[psrc[1]&15]; \ + pdst[3] = pclut[psrc[1]>>4]; \ + pdst[4] = pclut[psrc[2]&15]; \ + pdst[5] = pclut[psrc[2]>>4]; \ + pdst[6] = pclut[psrc[3]&15]; \ + pdst[7] = pclut[psrc[3]>>4]; \ + \ + pdst += 8; \ + psrc += 4; \ + } \ + } \ + break; \ + case PSMT8H: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ + pdst[0] = pclut[psrc[3]]; \ + pdst[1] = pclut[psrc[7]]; \ + pdst[2] = pclut[psrc[11]]; \ + pdst[3] = pclut[psrc[15]]; \ + pdst[4] = pclut[psrc[19]]; \ + pdst[5] = pclut[psrc[23]]; \ + pdst[6] = pclut[psrc[27]]; \ + pdst[7] = pclut[psrc[31]]; \ + pdst += 8; \ + psrc += 32; \ + } \ + } \ + break; \ + case PSMT4HH: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ + pdst[0] = pclut[psrc[3]>>4]; \ + pdst[1] = pclut[psrc[7]>>4]; \ + pdst[2] = pclut[psrc[11]>>4]; \ + pdst[3] = pclut[psrc[15]>>4]; \ + pdst[4] = pclut[psrc[19]>>4]; \ + pdst[5] = pclut[psrc[23]>>4]; \ + pdst[6] = pclut[psrc[27]>>4]; \ + pdst[7] = pclut[psrc[31]>>4]; \ + pdst += 8; \ + psrc += 32; \ + } \ + } \ + break; \ + case PSMT4HL: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ + pdst[0] = pclut[psrc[3]&15]; \ + pdst[1] = pclut[psrc[7]&15]; \ + pdst[2] = pclut[psrc[11]&15]; \ + pdst[3] = pclut[psrc[15]&15]; \ + pdst[4] = pclut[psrc[19]&15]; \ + pdst[5] = pclut[psrc[23]&15]; \ + pdst[6] = pclut[psrc[27]&15]; \ + pdst[7] = pclut[psrc[31]&15]; \ + pdst += 8; \ + psrc += 32; \ + } \ + } \ + break; \ + default: \ + assert(0); \ + } \ +} \ + +#define TARGET_THRESH 0x500 + +extern int g_MaxTexWidth, g_MaxTexHeight; + +//#define SORT_TARGETS +inline list::iterator ZeroGS::CMemoryTargetMngr::DestroyTargetIter(list::iterator& it) +{ + // find the target and destroy + list::iterator itprev = it; ++it; + listClearedTargets.splice(listClearedTargets.end(), listTargets, itprev); + + if( listClearedTargets.size() > TEXDESTROY_THRESH ) { + listClearedTargets.pop_front(); + } + + return it; +} + +#if defined(_MSC_VER) && defined(__x86_64__) +extern "C" void UnswizzleZ16Target(void* dst, void* src, int iters); +#endif + +ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::GetMemoryTarget(const tex0Info& tex0, int forcevalidate) +{ + int nbStart, nbEnd; + GetRectMemAddress(nbStart, nbEnd, tex0.psm, 0, 0, tex0.tw, tex0.th, tex0.tbp0, tex0.tbw); + assert( nbStart < nbEnd ); + nbEnd = min(nbEnd, 0x00400000); + + int nClutOffset = 0; + int clutsize = 0; + + if( PSMT_ISCLUT(tex0.psm) ) { + int entries = (tex0.psm&3)==3 ? 256 : 16; + if( tex0.cpsm <= 1 ) { // 32 bit + nClutOffset = 64 * tex0.csa; + clutsize = min(entries, 256-tex0.csa*16)*4; + } + else { + nClutOffset = 64 * (tex0.csa&15) + (tex0.csa>=16?2:0); + clutsize = min(entries, 512-tex0.csa*16)*2; + } + } + + int start = nbStart / (4*GPU_TEXWIDTH); + int end = (nbEnd + GPU_TEXWIDTH*4 - 1) / (4*GPU_TEXWIDTH); + assert( start < end ); + + for(list::iterator it = listTargets.begin(); it != listTargets.end();) { + + if( it->starty <= start && it->starty+it->height >= end ) { + + assert( it->psm != 0xd ); + + // using clut, validate that same data + if( PSMT_ISCLUT(it->psm) != PSMT_ISCLUT(tex0.psm) ) { + if( it->validatecount++ > VALIDATE_THRESH ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else + ++it; + continue; + } + + if( PSMT_ISCLUT(tex0.psm) ) { + assert( it->clut.size() > 0 ); + + if( it->psm != tex0.psm || it->cpsm != tex0.cpsm || it->clut.size() != clutsize ) { + // wrong clut + list::iterator itprev = it; + if( it->validatecount++ > VALIDATE_THRESH ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else + ++it; + continue; + } + + if( tex0.cpsm <= 1 ) { +#ifdef __x86_64__ + if( memcmp(&it->clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize) ) { +#else + if( memcmp_mmx(&it->clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize) ) { +#endif + ++it; + continue; + } + } + else { + if( memcmp_clut16((u16*)&it->clut[0], (u16*)(ZeroGS::g_pbyGSClut+nClutOffset), clutsize) ) { + ++it; + continue; + } + } + } + else if( PSMT_IS16BIT(tex0.psm) != PSMT_IS16BIT(it->psm) ) { + + if( it->validatecount++ > VALIDATE_THRESH ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else ++it; + + continue; + } + + if( forcevalidate ) {//&& listTargets.size() < TARGET_THRESH ) { + // do more validation checking. delete if not been used for a while + if( !it->ValidateTex(tex0, start, end, curstamp > it->usedstamp + 3) ) { + if( it->height <= 0 ) { + + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else ++it; + continue; + } + } + + it->usedstamp = curstamp; + it->validatecount = 0; + + return &(*it); + } +#ifdef SORT_TARGETS + else if( it->starty >= end ) + break; +#endif + ++it; + } + +#ifdef _DEBUG + PRIM_LOG("memtarget: tbp: %x tbw: %x th: %x psm: %x\n", tex0.tbp0, tex0.tbw, tex0.th, tex0.psm); +#endif + + // couldn't find so create + HRESULT hr; + CMemoryTarget* targ; + + D3DFORMAT fmt = D3DFMT_A8R8G8B8; + if( (PSMT_ISCLUT(tex0.psm) && tex0.cpsm > 1) || tex0.psm == PSMCT16 || tex0.psm == PSMCT16S) { + fmt = D3DFMT_A1R5G5B5; + } + + int widthmult = 1; + if( g_MaxTexHeight < 4096 ) { + if( end-start > g_MaxTexHeight ) + widthmult = 2; + } + + int channels = 1; + if( PSMT_ISCLUT(tex0.psm) ) { + if( tex0.psm == PSMT8 ) channels = 4; + else if( tex0.psm == PSMT4 ) channels = 8; + } + else { + if( PSMT_IS16BIT(tex0.psm) ) { + // 16z needs to be a8r8g8b8 + channels = 2; + } + } + + if( listClearedTargets.size() > 0 ) { + + list::iterator itbest = listClearedTargets.begin(); + while(itbest != listClearedTargets.end()) { + + if( end-start <= itbest->realheight && itbest->fmt == fmt && itbest->widthmult == widthmult ) { + + // check channels + int targchannels = 1; + if( PSMT_ISCLUT(itbest->psm) ) { + if( itbest->psm == PSMT8 ) targchannels = 4; + else if( itbest->psm == PSMT4 ) targchannels = 8; + } + else if( PSMT_IS16BIT(itbest->psm) ) { + targchannels = 2; + } + if( targchannels == channels ) + break; + } + ++itbest; + } + + if( itbest != listClearedTargets.end()) { + listTargets.splice(listTargets.end(), listClearedTargets, itbest); + targ = &listTargets.back(); + targ->validatecount = 0; + } + else { + // create a new + listTargets.push_back(CMemoryTarget()); + targ = &listTargets.back(); + } + } + else { + listTargets.push_back(CMemoryTarget()); + targ = &listTargets.back(); + } + + // fill local clut + if( PSMT_ISCLUT(tex0.psm) ) { + assert( clutsize > 0 ); + targ->cpsm = tex0.cpsm; + targ->clut.reserve(256*4); // no matter what + targ->clut.resize(clutsize); + + if( tex0.cpsm <= 1 ) { // 32 bit + memcpy_amd(&targ->clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize); + } + else { + u16* pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + nClutOffset); + u16* pclut = (u16*)&targ->clut[0]; + int left = ((u32)nClutOffset & 2) ? 0 : ((nClutOffset&0x3ff)/2)+clutsize-512; + if( left > 0 ) clutsize -= left; + + while(clutsize > 0) { + pclut[0] = pClutBuffer[0]; + pclut++; + pClutBuffer+=2; + clutsize -= 2; + } + + if( left > 0) { + pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + 2); + while(left > 0) { + pclut[0] = pClutBuffer[0]; + left -= 2; + pClutBuffer += 2; + pclut++; + } + } + } + } + + if( targ->ptex != NULL ) { + + assert( end-start <= targ->realheight && targ->fmt == fmt && targ->widthmult == widthmult ); + // good enough, so init + targ->realy = targ->starty = start; + targ->usedstamp = curstamp; + targ->psm = tex0.psm; + targ->cpsm = tex0.cpsm; + targ->height = end-start; + } + + if( targ->ptex == NULL ) { + + // not initialized yet + targ->fmt = fmt; + targ->realy = targ->starty = start; + targ->realheight = targ->height = end-start; + targ->usedstamp = curstamp; + targ->psm = tex0.psm; + targ->cpsm = tex0.cpsm; + targ->widthmult = widthmult; + + // alloc the mem + while( FAILED(pd3dDevice->CreateTexture(GPU_TEXWIDTH*channels*widthmult, (targ->realheight+widthmult-1)/widthmult, 1, 0, fmt, D3DPOOL_DEFAULT, &targ->ptex, NULL)) ) { + + if( listClearedTargets.size() > 0 ) + listClearedTargets.pop_front(); + else { + if( listTargets.size() == 0 ) { + DEBUG_LOG("Failed to create %dx%x texture\n", GPU_TEXWIDTH*channels*widthmult, (targ->realheight+widthmult-1)/widthmult); + channels = 1; + } + DestroyOldest(); + } + } + + // lock + V(pd3dDevice->CreateTexture(GPU_TEXWIDTH*channels*widthmult, (targ->realheight+widthmult-1)/widthmult, 1, 0, fmt, D3DPOOL_SYSTEMMEM, &targ->ptexsys, NULL)); + assert( targ->ptexsys != NULL ); + } + +#ifndef RELEASE_TO_PUBLIC + g_TransferredToGPU += GPU_TEXWIDTH * channels * 4 * targ->height; +#endif + + D3DLOCKED_RECT lock; + targ->ptexsys->LockRect(0, &lock, NULL, 0); + + // fill with data + if( PSMT_ISCLUT(tex0.psm) ) { + + if( targ->memory == NULL ) { + targ->memory = new CMemoryTarget::MEMORY(); + targ->memory->ptr = (BYTE*)_aligned_malloc(4 * GPU_TEXWIDTH * targ->realheight, 16); + targ->memory->ref = 1; + } + + memcpy_amd(targ->memory->ptr, ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy, 4 * GPU_TEXWIDTH * targ->height); + + u8* psrc = (u8*)(ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy); + + if( tex0.cpsm <= 1 ) { // 32bit + u32* pclut = (u32*)&targ->clut[0]; + u32* pdst = (u32*)lock.pBits; + + BUILDCLUT(); + } + else { + u16* pclut = (u16*)&targ->clut[0]; + u16* pdst = (u16*)lock.pBits; + + BUILDCLUT(); + } + } + else { + if( tex0.psm == PSMT16Z || tex0.psm == PSMT16SZ ) { + + if( targ->memory == NULL ) { + targ->memory = new CMemoryTarget::MEMORY(); + targ->memory->ptr = (BYTE*)_aligned_malloc(4 * GPU_TEXWIDTH * targ->realheight, 16); + targ->memory->ref = 1; + } + + memcpy_amd(targ->memory->ptr, ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy, 4 * GPU_TEXWIDTH * targ->height); + + // needs to be 8 bit, use xmm for unpacking + u16* dst = (u16*)lock.pBits; + u16* src = (u16*)(ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy); + + assert( ((u32)dst)%16 == 0 ); + +#if defined(ZEROGS_SSE2) + int iters = targ->height*GPU_TEXWIDTH/16; + +#if defined(__x86_64__) + UnswizzleZ16Target(dst, src, iters); +#else + __asm { + mov edx, iters + pxor xmm7, xmm7 + mov eax, dst + mov ecx, src + +Z16Loop: + // unpack 64 bytes at a time + movdqa xmm0, [ecx] + movdqa xmm2, [ecx+16] + movdqa xmm4, [ecx+32] + movdqa xmm6, [ecx+48] + + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + movdqa xmm5, xmm4 + + punpcklwd xmm0, xmm7 + punpckhwd xmm1, xmm7 + punpcklwd xmm2, xmm7 + punpckhwd xmm3, xmm7 + + // start saving + movdqa [eax], xmm0 + movdqa [eax+16], xmm1 + + punpcklwd xmm4, xmm7 + punpckhwd xmm5, xmm7 + + movdqa [eax+32], xmm2 + movdqa [eax+48], xmm3 + + movdqa xmm0, xmm6 + punpcklwd xmm6, xmm7 + + movdqa [eax+64], xmm4 + movdqa [eax+80], xmm5 + + punpckhwd xmm0, xmm7 + + movdqa [eax+96], xmm6 + movdqa [eax+112], xmm0 + + add ecx, 64 + add eax, 128 + sub edx, 1 + jne Z16Loop + } +#endif // __x86_64__ +#else + for(int i = 0; i < targ->height; ++i) { + for(int j = 0; j < GPU_TEXWIDTH; ++j) { + dst[0] = src[0]; dst[1] = 0; + dst[2] = src[1]; dst[3] = 0; + dst += 4; + src += 2; + } + } +#endif + } + else { + if( targ->memory != NULL ) { + // release + if( targ->memory->ref > 0 && --targ->memory->ref <= 0 ) { + SAFE_DELETE(targ->memory); + } + targ->memory = NULL; + } + + memcpy_amd(lock.pBits, ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy, 4 * GPU_TEXWIDTH * targ->height ); + } + } + + targ->ptexsys->UnlockRect(0); + + V(pd3dDevice->UpdateTexture(targ->ptexsys, targ->ptex)); + + assert( tex0.psm != 0xd ); + if( PSMT_ISCLUT(tex0.psm) ) + assert( targ->clut.size() > 0 ); + + return targ; +} + +void ZeroGS::CMemoryTargetMngr::ClearRange(int nbStartY, int nbEndY) +{ + int starty = nbStartY / (4*GPU_TEXWIDTH); + int endy = (nbEndY+4*GPU_TEXWIDTH-1) / (4*GPU_TEXWIDTH); + //int endy = (nbEndY+4096-1) / 4096; + + //if( listTargets.size() < TARGET_THRESH ) { + for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { + + if( it->starty < endy && (it->starty+it->height) > starty ) { + + // intersects, reduce valid texture mem (or totally delete texture) + // there are 4 cases + int miny = max(it->starty, starty); + int maxy = min(it->starty+it->height, endy); + assert(miny < maxy); + + if( it->clearmaxy == 0 ) { + it->clearminy = miny; + it->clearmaxy = maxy; + } + else { + if( it->clearminy > miny ) it->clearminy = miny; + if( it->clearmaxy < maxy ) it->clearmaxy = maxy; + } + } + + ++it; + } +// } +// else { +// for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { +// +// if( it->starty < endy && (it->starty+it->height) > starty ) { +// int newstarty = 0; +// if( starty <= it->starty ) { +// if( endy < it->starty + it->height) { +// // preserve end +// it->height = it->starty+it->height-endy; +// it->starty = endy; +// assert(it->height > 0); +// } +// else { +// // destroy +// it->height = 0; +// } +// } +// else { +// // beginning can be preserved +// it->height = starty-it->starty; +// } +// +// assert( it->starty >= it->realy && it->starty+it->height<=it->realy+it->realheight ); +// if( it->height <= 0 ) { +// list::iterator itprev = it; ++it; +// listClearedTargets.splice(listClearedTargets.end(), listTargets, itprev); +// continue; +// } +// } +// +// ++it; +// } +// } +} + +void ZeroGS::CMemoryTargetMngr::DestroyCleared() +{ + for(list::iterator it = listClearedTargets.begin(); it != listClearedTargets.end(); ) { + if( it->usedstamp < curstamp - 2 ) { + it = listClearedTargets.erase(it); + continue; + } + + ++it; + } + + if( (curstamp % 3) == 0 ) { + // purge old targets every 3 frames + for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { + if( it->usedstamp < curstamp - 3 ) { + it = listTargets.erase(it); + continue; + } + + ++it; + } + } + + ++curstamp; +} + +void ZeroGS::CMemoryTargetMngr::DestroyOldest() +{ + if( listTargets.size() == 0 ) + return; + + list::iterator it, itbest; + it = itbest = listTargets.begin(); + + while(it != listTargets.end()) { + if( it->usedstamp < itbest->usedstamp ) + itbest = it; + ++it; + } + + listTargets.erase(itbest); +} + +////////////////////////////////////// +// Texture Mngr For Bitwise AND Ops // +////////////////////////////////////// +void ZeroGS::CBitwiseTextureMngr::Destroy() +{ + for(map::iterator it = mapTextures.begin(); it != mapTextures.end(); ++it) + it->second->Release(); + mapTextures.clear(); +} + +LPD3DTEX ZeroGS::CBitwiseTextureMngr::GetTexInt(u32 bitvalue, LPD3DTEX ptexDoNotDelete) +{ + if( mapTextures.size() > 32 ) { + // randomly delete 8 + for(map::iterator it = mapTextures.begin(); it != mapTextures.end();) { + if( !(rand()&3) && it->second != ptexDoNotDelete) { + it->second->Release(); + it = mapTextures.erase(it); + } + else ++it; + } + } + + // create a new tex + LPD3DTEX ptex; + HRESULT hr = S_OK; + V(pd3dDevice->CreateTexture(GPU_TEXMASKWIDTH, 1, 1, 0, D3DFMT_L16, D3DPOOL_MANAGED, &ptex, NULL)); + + D3DLOCKED_RECT lock; + ptex->LockRect(0, &lock, NULL, 0); + for(u32 i = 0; i < GPU_TEXMASKWIDTH; ++i) ((u16*)lock.pBits)[i] = ((i&bitvalue)<<6)|0x1f; // add the 1/2 offset so that + ptex->UnlockRect(0); + + mapTextures[bitvalue] = ptex; + return ptex; +} + +void ZeroGS::CRangeManager::Insert(int start, int end) +{ + int imin = 0, imax = (int)ranges.size(), imid; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + + switch( ranges.size() ) { + case 0: + ranges.push_back(RANGE(start, end)); + return; + + case 1: + if( end < ranges.front().start ) { + ranges.insert(ranges.begin(), RANGE(start, end)); + } + else if( start > ranges.front().end ) { + ranges.push_back(RANGE(start, end)); + } + else { + if( start < ranges.front().start ) ranges.front().start = start; + if( end > ranges.front().end ) ranges.front().end = end; + } + + return; + } + + // find where start is + while(imin < imax) { + imid = (imin+imax)>>1; + + assert( imid < (int)ranges.size() ); + + if( ranges[imid].end >= start && (imid == 0 || ranges[imid-1].end < start) ) { + imin = imid; + break; + } + else if( ranges[imid].start > start ) imax = imid; + else imin = imid+1; + } + + int startindex = imin; + + if( startindex >= (int)ranges.size() ) { + // non intersecting + assert( start > ranges.back().end ); + ranges.push_back(RANGE(start, end)); + return; + } + if( startindex == 0 && end < ranges.front().start ) { + ranges.insert(ranges.begin(), RANGE(start, end)); + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + return; + } + + imin = 0; imax = (int)ranges.size(); + + // find where end is + while(imin < imax) { + imid = (imin+imax)>>1; + + assert( imid < (int)ranges.size() ); + + if( ranges[imid].end <= end && (imid == ranges.size()-1 || ranges[imid+1].start > end ) ) { + imin = imid; + break; + } + else if( ranges[imid].start >= end ) imax = imid; + else imin = imid+1; + } + + int endindex = imin; + + if( startindex > endindex ) { + // create a new range + ranges.insert(ranges.begin()+startindex, RANGE(start, end)); + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + return; + } + + if( endindex >= (int)ranges.size()-1 ) { + // pop until startindex is reached + int lastend = ranges.back().end; + int numpop = (int)ranges.size() - startindex - 1; + while(numpop-- > 0 ) ranges.pop_back(); + + assert( start <= ranges.back().end ); + if( start < ranges.back().start ) ranges.back().start = start; + if( lastend > ranges.back().end ) ranges.back().end = lastend; + if( end > ranges.back().end ) ranges.back().end = end; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + + return; + } + + if( endindex == 0 ) { + assert( end >= ranges.front().start ); + if( start < ranges.front().start ) ranges.front().start = start; + if( end > ranges.front().end ) ranges.front().end = end; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + } + + // somewhere in the middle + if( ranges[startindex].start < start ) start = ranges[startindex].start; + + if( startindex < endindex ) { + ranges.erase(ranges.begin() + startindex, ranges.begin() + endindex ); + } + + if( start < ranges[startindex].start ) ranges[startindex].start = start; + if( end > ranges[startindex].end ) ranges[startindex].end = end; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif +} + +namespace ZeroGS { + +CRangeManager s_RangeMngr; // manages overwritten memory +static int gs_imageEnd = 0; + +void ResolveInRange(int start, int end) +{ + list listTargs; + s_DepthRTs.GetTargs(start, end, listTargs); + s_RTs.GetTargs(start, end, listTargs); + + if( listTargs.size() > 0 ) { + // flushes can delete targets! + Flush(0); + Flush(1); + + listTargs.clear(); + s_DepthRTs.GetTargs(start, end, listTargs); + s_RTs.GetTargs(start, end, listTargs); + + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) { + // only resolve if not completely covered + (*it)->Resolve(); + } + } +} + +////////////////// +// Transferring // +////////////////// +void FlushTransferRanges(const tex0Info* ptex) +{ + assert( s_RangeMngr.ranges.size() > 0 ); + bool bHasFlushed = false; + list listTransmissionUpdateTargs; + + int texstart = -1, texend = -1; + if( ptex != NULL ) { + GetRectMemAddress(texstart, texend, ptex->psm, 0, 0, ptex->tw, ptex->th, ptex->tbp0, ptex->tbw); + } + + for(vector::iterator itrange = s_RangeMngr.ranges.begin(); itrange != s_RangeMngr.ranges.end(); ++itrange ) { + + int start = itrange->start; + int end = itrange->end; + + listTransmissionUpdateTargs.clear(); + s_DepthRTs.GetTargs(start, end, listTransmissionUpdateTargs); + s_RTs.GetTargs(start, end, listTransmissionUpdateTargs); + +// if( !bHasFlushed && listTransmissionUpdateTargs.size() > 0 ) { +// Flush(0); +// Flush(1); +// +//#ifdef _DEBUG +// // make sure targets are still the same +// list::iterator it; +// FORIT(it, listTransmissionUpdateTargs) { +// CRenderTargetMngr::MAPTARGETS::iterator itmap; +// for(itmap = s_RTs.mapTargets.begin(); itmap != s_RTs.mapTargets.end(); ++itmap) { +// if( itmap->second == *it ) +// break; +// } +// +// if( itmap == s_RTs.mapTargets.end() ) { +// +// for(itmap = s_DepthRTs.mapTargets.begin(); itmap != s_DepthRTs.mapTargets.end(); ++itmap) { +// if( itmap->second == *it ) +// break; +// } +// +// assert( itmap != s_DepthRTs.mapTargets.end() ); +// } +// } +//#endif +// } + + for(list::iterator it = listTransmissionUpdateTargs.begin(); it != listTransmissionUpdateTargs.end(); ++it) { + + CRenderTarget* ptarg = *it; + + if( (ptarg->status & CRenderTarget::TS_Virtual) || ptarg->targoffx != 0 || ptarg->targoffy != 0) + continue; + + if( !(ptarg->start < texend && ptarg->end > texstart) ) { + // chekc if target is currently being used + + if( !(g_GameSettings & GAME_NOQUICKRESOLVE) ) { + if( ptarg->fbp != vb[0].gsfb.fbp ) {//&& (vb[0].prndr == NULL || ptarg->fbp != vb[0].prndr->fbp) ) { + + if( ptarg->fbp != vb[1].gsfb.fbp ) { //&& (vb[1].prndr == NULL || ptarg->fbp != vb[1].prndr->fbp) ) { + // this render target currently isn't used and is not in the texture's way, so can safely ignore + // resolving it. Also the range has to be big enough compared to the target to really call it resolved + // (ffx changing screens, shadowhearts) + // start == ptarg->start, used for kh to transfer text + if( ptarg->IsDepth() || end-start > 0x50000 || ((g_GameSettings&GAME_QUICKRESOLVE1)&&start == ptarg->start) ) + ptarg->status |= CRenderTarget::TS_NeedUpdate|CRenderTarget::TS_Resolved; + + continue; + } + } + } + } + else { +// if( start <= texstart && end >= texend ) { +// // texture taken care of so can skip!? +// continue; +// } + } + + // the first range check was very rough; some games (dragonball z) have the zbuf in the same page as textures (but not overlapping) + // so detect that condition + if( ptarg->fbh % m_Blocks[ptarg->psm].height ) { + + // get start of left-most boundry page + int targstart, targend; + ZeroGS::GetRectMemAddress(targstart, targend, ptarg->psm, 0, 0, ptarg->fbw, ptarg->fbh & ~(m_Blocks[ptarg->psm].height-1), ptarg->fbp, ptarg->fbw); + + if( start >= targend ) { + + // don't bother + if( (ptarg->fbh % m_Blocks[ptarg->psm].height) <= 2 ) + continue; + + // calc how many bytes of the block that the page spans + } + } + + if( !(ptarg->status & CRenderTarget::TS_Virtual) ) { + + if( start < ptarg->end && end > ptarg->start ) { + + // suikoden5 is faster with check, but too big of a value and kh screens mess up + if( end - start > 0x8000 ) { + // intersects, do only one sided resolves + if( end-start > 4*ptarg->fbw ) { // at least it be greater than one scanline (spiro is faster) + if( start > ptarg->start ) { + ptarg->Resolve(ptarg->start, start); + } + else if( end < ptarg->end ) { + ptarg->Resolve(end, ptarg->end); + } + } + } + + ptarg->status |= CRenderTarget::TS_Resolved; + if( !ptarg->IsDepth() || (!(g_GameSettings & GAME_NODEPTHUPDATE) || end-start > 0x1000) ) + ptarg->status |= CRenderTarget::TS_NeedUpdate; + } + } + } + + ZeroGS::g_MemTargs.ClearRange(start, end); + } + + s_RangeMngr.Clear(); +} + +// need to take into account left over data of 24bit transfers (always <= 5) +static vector s_vTempBuffer, s_vTransferCache; + +void InitTransferHostLocal() +{ + if( g_bIsLost ) + return; + +#ifndef RELEASE_TO_PUBLIC + if( gs.trxpos.dx+gs.imageWnew > gs.dstbuf.bw ) + WARN_LOG("Transfer error, width exceeds\n"); +#endif + + bool bHasFlushed = false; + + gs.imageX = gs.trxpos.dx; + gs.imageY = gs.trxpos.dy; + gs.imageEndX = gs.imageX + gs.imageWnew; + gs.imageEndY = gs.imageY + gs.imageHnew; + s_vTransferCache.resize(0); + + assert( gs.imageEndX < 2048 && gs.imageEndY < 2048 ); + + // hack! viewful joe + if( gs.dstbuf.psm == 63 ) + gs.dstbuf.psm = 0; + + int start, end; + GetRectMemAddress(start, end, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); + + if( end > 0x00400000 ) { + WARN_LOG("host local out of bounds!\n"); + //gs.imageTransfer = -1; + end = 0x00400000; + } + + gs_imageEnd = end; + + if( vb[0].dwCount > 0 ) + Flush(0); + if( vb[1].dwCount > 0 ) + Flush(1); + + //PRIM_LOG("trans: bp:%x x:%x y:%x w:%x h:%x\n", gs.dstbuf.bp, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew); + +// if( !bHasFlushed && (vb[0].bNeedFrameCheck || vb[0].bNeedZCheck || vb[1].bNeedFrameCheck || vb[1].bNeedZCheck)) { +// Flush(0); +// Flush(1); +// bHasFlushed = 1; +// } +// +// // for all ranges, flush the targets +// // check if new rect intersects with current rendering texture, if so, flush +// if( vb[0].dwCount > 0 && vb[0].curprim.tme ) { +// int tstart, tend; +// GetRectMemAddress(tstart, tend, vb[0].tex0.psm, 0, 0, vb[0].tex0.tw, vb[0].tex0.th, vb[0].tex0.tbp0, vb[0].tex0.tbw); +// +// if( start < tend && end > tstart ) { +// Flush(0); +// Flush(1); +// bHasFlushed = 1; +// } +// } +// +// if( !bHasFlushed && vb[1].dwCount > 0 && vb[1].curprim.tme ) { +// int tstart, tend; +// GetRectMemAddress(tstart, tend, vb[1].tex0.psm, 0, 0, vb[1].tex0.tw, vb[1].tex0.th, vb[1].tex0.tbp0, vb[1].tex0.tbw); +// +// if( start < tend && end > tstart ) { +// Flush(0); +// Flush(1); +// bHasFlushed = 1; +// } +// } + + //ZeroGS::g_MemTargs.ClearRange(start, end); + //s_RangeMngr.Insert(start, end); +} + +void TransferHostLocal(const void* pbyMem, u32 nQWordSize) +{ + if( g_bIsLost ) + return; + + int start, end; + GetRectMemAddress(start, end, gs.dstbuf.psm, gs.imageX, gs.imageY, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); + assert( start < gs_imageEnd ); + + end = gs_imageEnd; + + // sometimes games can decompress to alpha channel of render target only, in this case + // do a resolve right away. wolverine x2 + if( gs.dstbuf.psm == PSMT8H || gs.dstbuf.psm == PSMT4HL || gs.dstbuf.psm == PSMT4HH ) { + list listTransmissionUpdateTargs; + s_RTs.GetTargs(start, end, listTransmissionUpdateTargs); + + for(list::iterator it = listTransmissionUpdateTargs.begin(); it != listTransmissionUpdateTargs.end(); ++it) { + + CRenderTarget* ptarg = *it; + + if( (ptarg->status & CRenderTarget::TS_Virtual) ) + continue; + + //DEBUG_LOG("zerogs: resolving to alpha channel\n"); + ptarg->Resolve(); + } + } + + s_RangeMngr.Insert(start, min(end, start+(int)nQWordSize*16)); + + const u8* porgend = (const u8*)pbyMem + 4 * nQWordSize; + + if( s_vTransferCache.size() > 0 ) { + + int imagecache = s_vTransferCache.size(); + s_vTempBuffer.resize(imagecache + nQWordSize*4); + memcpy(&s_vTempBuffer[0], &s_vTransferCache[0], imagecache); + memcpy(&s_vTempBuffer[imagecache], pbyMem, nQWordSize*4); + + pbyMem = (const void*)&s_vTempBuffer[0]; + porgend = &s_vTempBuffer[0]+s_vTempBuffer.size(); + + int wordinc = imagecache / 4; + if( (nQWordSize * 4 + imagecache)/3 == ((nQWordSize+wordinc) * 4) / 3 ) { + // can use the data + nQWordSize += wordinc; + } + } + + int leftover = m_Blocks[gs.dstbuf.psm].TransferHostLocal(pbyMem, nQWordSize); + + if( leftover > 0 ) { + // copy the last gs.image24bitOffset to the cache + s_vTransferCache.resize(leftover); + memcpy(&s_vTransferCache[0], porgend - leftover, leftover); + } + else s_vTransferCache.resize(0); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveTrans ) { + tex0Info t; + t.tbp0 = gs.dstbuf.bp; + t.tw = gs.imageWnew; + t.th = gs.imageHnew; + t.tbw = gs.dstbuf.bw; + t.psm = gs.dstbuf.psm; + SaveTex(&t, 0); + } +#endif +} + +// left/right, top/down +//void TransferHostLocal(const void* pbyMem, u32 nQWordSize) +//{ +// assert( gs.imageTransfer == 0 ); +// u8* pstart = g_pbyGSMemory + gs.dstbuf.bp*256; +// +// const u8* pendbuf = (const u8*)pbyMem + nQWordSize*4; +// int i = gs.imageY, j = gs.imageX; +// +//#define DSTPSM gs.dstbuf.psm +// +//#define TRANSFERHOSTLOCAL(psm, T, widthlimit) { \ +// const T* pbuf = (const T*)pbyMem; \ +// u32 nSize = nQWordSize*(4/sizeof(T)); \ +// assert( (nSize%widthlimit) == 0 && widthlimit <= 4 ); \ +// if( ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) DEBUG_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM); \ +// for(; i < gs.imageEndY; ++i) { \ +// for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += widthlimit) { \ +// /* write as many pixel at one time as possible */ \ +// writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ +// \ +// if( widthlimit > 1 ) { \ +// writePixel##psm##_0(pstart, (j+1)%2048, i%2048, pbuf[1], gs.dstbuf.bw); \ +// \ +// if( widthlimit > 2 ) { \ +// writePixel##psm##_0(pstart, (j+2)%2048, i%2048, pbuf[2], gs.dstbuf.bw); \ +// \ +// if( widthlimit > 3 ) { \ +// writePixel##psm##_0(pstart, (j+3)%2048, i%2048, pbuf[3], gs.dstbuf.bw); \ +// } \ +// } \ +// } \ +// } \ +// \ +// if( j >= gs.imageEndX ) { assert(j == gs.imageEndX); j = gs.trxpos.dx; } \ +// else { assert( nSize == 0 ); goto End; } \ +// } \ +//} \ +// +//#define TRANSFERHOSTLOCAL_4(psm) { \ +// const u8* pbuf = (const u8*)pbyMem; \ +// u32 nSize = nQWordSize*8; \ +// for(; i < gs.imageEndY; ++i) { \ +// for(; j < gs.imageEndX && nSize > 0; j += 8, nSize -= 8) { \ +// /* write as many pixel at one time as possible */ \ +// writePixel##psm##_0(pstart, j%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// } \ +// \ +// if( j >= gs.imageEndX ) { /*assert(j == gs.imageEndX);*/ j = gs.trxpos.dx; } \ +// else { assert( nSize == 0 ); goto End; } \ +// } \ +//} \ +// +// switch (gs.dstbuf.psm) { +// case 0x0: TRANSFERHOSTLOCAL(32, u32, 2); break; +// case 0x1: TRANSFERHOSTLOCAL(24, u32, 4); break; +// case 0x2: TRANSFERHOSTLOCAL(16, u16, 4); break; +// case 0xA: TRANSFERHOSTLOCAL(16S, u16, 4); break; +// case 0x13: +// if( ((gs.imageEndX-gs.trxpos.dx)%4) ) { +// TRANSFERHOSTLOCAL(8, u8, 1); +// } +// else { +// TRANSFERHOSTLOCAL(8, u8, 4); +// } +// break; +// +// case 0x14: +//// if( (gs.imageEndX-gs.trxpos.dx)%8 ) { +//// // hack +//// if( abs((int)nQWordSize*8 - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx)) <= 8 ) { +//// // don't transfer +//// DEBUG_LOG("bad texture 4: %d %d %d\n", gs.trxpos.dx, gs.imageEndX, nQWordSize); +//// gs.imageEndX = gs.trxpos.dx + (gs.imageEndX-gs.trxpos.dx)&~7; +//// //i = gs.imageEndY; +//// //goto End; +//// gs.imageTransfer = -1; +//// } +//// } +// TRANSFERHOSTLOCAL_4(4); +// break; +// case 0x1B: TRANSFERHOSTLOCAL(8H, u8, 4); break; +// case 0x24: TRANSFERHOSTLOCAL_4(4HL); break; +// case 0x2C: TRANSFERHOSTLOCAL_4(4HH); break; +// case 0x30: TRANSFERHOSTLOCAL(32Z, u32, 2); break; +// case 0x31: TRANSFERHOSTLOCAL(24Z, u32, 4); break; +// case 0x32: TRANSFERHOSTLOCAL(16Z, u16, 4); break; +// case 0x3A: TRANSFERHOSTLOCAL(16SZ, u16, 4); break; +// } +// +//End: +// if( i >= gs.imageEndY ) { +// assert( i == gs.imageEndY ); +// gs.imageTransfer = -1; +// +// if( g_bSaveTrans ) { +// tex0Info t; +// t.tbp0 = gs.dstbuf.bp; +// t.tw = gs.imageWnew; +// t.th = gs.imageHnew; +// t.tbw = gs.dstbuf.bw; +// t.psm = gs.dstbuf.psm; +// SaveTex(&t, 0); +// } +// } +// else { +// /* update new params */ +// gs.imageY = i; +// gs.imageX = j; +// } +//} + +void InitTransferLocalHost() +{ + assert( gs.trxpos.sx+gs.imageWnew <= 2048 && gs.trxpos.sy+gs.imageHnew <= 2048 ); + +#ifndef RELEASE_TO_PUBLIC + if( gs.trxpos.sx+gs.imageWnew > gs.srcbuf.bw ) + WARN_LOG("Transfer error, width exceeds\n"); +#endif + + gs.imageX = gs.trxpos.sx; + gs.imageY = gs.trxpos.sy; + gs.imageEndX = gs.imageX + gs.imageWnew; + gs.imageEndY = gs.imageY + gs.imageHnew; + + int start, end; + GetRectMemAddress(start, end, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw); + ResolveInRange(start, end); +} + +// left/right, top/down +void TransferLocalHost(void* pbyMem, u32 nQWordSize) +{ + assert( gs.imageTransfer == 1 ); + + u8* pstart = g_pbyGSMemory + 256*gs.srcbuf.bp; + int i = gs.imageY, j = gs.imageX; + +#define TRANSFERLOCALHOST(psm, T) { \ + T* pbuf = (T*)pbyMem; \ + u32 nSize = nQWordSize*16/sizeof(T); \ + for(; i < gs.imageEndY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; ++j, --nSize) { \ + *pbuf++ = readPixel##psm##_0(pstart, j%2048, i%2048, gs.srcbuf.bw); \ + } \ + \ + if( j >= gs.imageEndX ) { assert( j == gs.imageEndX); j = gs.trxpos.sx; } \ + else { assert( nSize == 0 ); break; } \ + } \ +} \ + +#define TRANSFERLOCALHOST_24(psm) { \ + u8* pbuf = (u8*)pbyMem; \ + u32 nSize = nQWordSize*16/3; \ + for(; i < gs.imageEndY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; ++j, --nSize) { \ + u32 p = readPixel##psm##_0(pstart, j%2048, i%2048, gs.srcbuf.bw); \ + pbuf[0] = (u8)p; \ + pbuf[1] = (u8)(p>>8); \ + pbuf[2] = (u8)(p>>16); \ + pbuf += 3; \ + } \ + \ + if( j >= gs.imageEndX ) { assert( j == gs.imageEndX); j = gs.trxpos.sx; } \ + else { assert( nSize == 0 ); break; } \ + } \ +} \ + + switch (gs.srcbuf.psm) { + case 0x0: TRANSFERLOCALHOST(32, u32); break; + case 0x1: TRANSFERLOCALHOST_24(24); break; + case 0x2: TRANSFERLOCALHOST(16, u16); break; + case 0xA: TRANSFERLOCALHOST(16S, u16); break; + case 0x13: TRANSFERLOCALHOST(8, u8); break; + case 0x1B: TRANSFERLOCALHOST(8H, u8); break; + case 0x30: TRANSFERLOCALHOST(32Z, u32); break; + case 0x31: TRANSFERLOCALHOST_24(24Z); break; + case 0x32: TRANSFERLOCALHOST(16Z, u16); break; + case 0x3A: TRANSFERLOCALHOST(16SZ, u16); break; + default: assert(0); + } + + gs.imageY = i; + gs.imageX = j; + + if( gs.imageY >= gs.imageEndY ) { + assert( gs.imageY == gs.imageEndY ); + gs.imageTransfer = -1; + } +} + +// dir depends on trxpos.dir +void TransferLocalLocal() +{ + assert( gs.imageTransfer == 2 ); + assert( gs.trxpos.sx+gs.imageWnew < 2048 && gs.trxpos.sy+gs.imageHnew < 2048 ); + assert( gs.trxpos.dx+gs.imageWnew < 2048 && gs.trxpos.dy+gs.imageHnew < 2048 ); + assert( (gs.srcbuf.psm&0x7) == (gs.dstbuf.psm&0x7) ); + if( gs.trxpos.sx+gs.imageWnew > gs.srcbuf.bw ) + WARN_LOG("Transfer error, src width exceeds\n"); + if( gs.trxpos.dx+gs.imageWnew > gs.dstbuf.bw ) + WARN_LOG("Transfer error, dst width exceeds\n"); + + int srcstart, srcend, dststart, dstend; + + GetRectMemAddress(srcstart, srcend, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw); + GetRectMemAddress(dststart, dstend, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); + + // resolve the targs + ResolveInRange(srcstart, srcend); + + list listTargs; + s_RTs.GetTargs(dststart, dstend, listTargs); + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) { + if( !((*it)->status & CRenderTarget::TS_Virtual) ) { + (*it)->Resolve(); + (*it)->status |= CRenderTarget::TS_NeedUpdate; + } + } + + u8* pSrcBuf = g_pbyGSMemory + gs.srcbuf.bp*256; + u8* pDstBuf = g_pbyGSMemory + gs.dstbuf.bp*256; + +#define TRANSFERLOCALLOCAL(srcpsm, dstpsm, widthlimit) { \ + if( (gs.imageWnew&widthlimit)!=0 ) break; \ + assert( (gs.imageWnew&widthlimit)==0 && widthlimit <= 4); \ + for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < gs.trxpos.sy+gs.imageHnew; i++, i2++) { \ + for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < gs.trxpos.sx+gs.imageWnew; j+=widthlimit, j2+=widthlimit) { \ + \ + writePixel##dstpsm##_0(pDstBuf, j2%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, j%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + \ + if( widthlimit > 1 ) { \ + writePixel##dstpsm##_0(pDstBuf, (j2+1)%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, (j+1)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + \ + if( widthlimit > 2 ) { \ + writePixel##dstpsm##_0(pDstBuf, (j2+2)%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, (j+2)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + \ + if( widthlimit > 3 ) { \ + writePixel##dstpsm##_0(pDstBuf, (j2+3)%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, (j+3)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + } \ + } \ + } \ + } \ + } \ +} \ + +#define TRANSFERLOCALLOCAL_4(srcpsm, dstpsm) { \ + assert( (gs.imageWnew%8) == 0 ); \ + for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < gs.trxpos.sy+gs.imageHnew; ++i, ++i2) { \ + for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < gs.trxpos.sx+gs.imageWnew; j+=8, j2+=8) { \ + /* NOTE: the 2 conseq 4bit values are in NOT in the same byte */ \ + u32 read = getPixelAddress##srcpsm##_0(j%2048, i%2048, gs.srcbuf.bw); \ + u32 write = getPixelAddress##dstpsm##_0(j2%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+1)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+1)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + \ + read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + \ + read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + \ + read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + } \ + } \ +} \ + + switch (gs.srcbuf.psm) { + case PSMCT32: + if( gs.dstbuf.psm == PSMCT32 ) { + TRANSFERLOCALLOCAL(32, 32, 2); + } + else { + TRANSFERLOCALLOCAL(32, 32Z, 2); + } + break; + + case PSMCT24: + if( gs.dstbuf.psm == PSMCT24 ) { + TRANSFERLOCALLOCAL(24, 24, 4); + } + else { + TRANSFERLOCALLOCAL(24, 24Z, 4); + } + break; + + case PSMCT16: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16, 16SZ, 4); break; + } + break; + + case PSMCT16S: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16S, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16S, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16S, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16S, 16SZ, 4); break; + } + break; + + case PSMT8: + if( gs.dstbuf.psm == PSMT8 ) { + TRANSFERLOCALLOCAL(8, 8, 4); + } + else { + TRANSFERLOCALLOCAL(8, 8H, 4); + } + break; + + case PSMT4: + + switch(gs.dstbuf.psm ) { + case PSMT4: TRANSFERLOCALLOCAL_4(4, 4); break; + case PSMT4HL: TRANSFERLOCALLOCAL_4(4, 4HL); break; + case PSMT4HH: TRANSFERLOCALLOCAL_4(4, 4HH); break; + } + break; + + case PSMT8H: + if( gs.dstbuf.psm == PSMT8 ) { + TRANSFERLOCALLOCAL(8H, 8, 4); + } + else { + TRANSFERLOCALLOCAL(8H, 8H, 4); + } + break; + + case PSMT4HL: + switch(gs.dstbuf.psm ) { + case PSMT4: TRANSFERLOCALLOCAL_4(4HL, 4); break; + case PSMT4HL: TRANSFERLOCALLOCAL_4(4HL, 4HL); break; + case PSMT4HH: TRANSFERLOCALLOCAL_4(4HL, 4HH); break; + } + break; + case PSMT4HH: + switch(gs.dstbuf.psm ) { + case PSMT4: TRANSFERLOCALLOCAL_4(4HH, 4); break; + case PSMT4HL: TRANSFERLOCALLOCAL_4(4HH, 4HL); break; + case PSMT4HH: TRANSFERLOCALLOCAL_4(4HH, 4HH); break; + } + break; + + case PSMT32Z: + if( gs.dstbuf.psm == PSMCT32 ) { + TRANSFERLOCALLOCAL(32Z, 32, 2); + } + else { + TRANSFERLOCALLOCAL(32Z, 32Z, 2); + } + break; + + case PSMT24Z: + if( gs.dstbuf.psm == PSMCT24 ) { + TRANSFERLOCALLOCAL(24Z, 24, 4); + } + else { + TRANSFERLOCALLOCAL(24Z, 24Z, 4); + } + break; + + case PSMT16Z: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16Z, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16Z, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16Z, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16Z, 16SZ, 4); break; + } + break; + + case PSMT16SZ: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16SZ, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16SZ, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16SZ, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16SZ, 16SZ, 4); break; + } + break; + } + + g_MemTargs.ClearRange(dststart, dstend); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveTrans ) { + tex0Info t; + t.tbp0 = gs.dstbuf.bp; + t.tw = gs.imageWnew; + t.th = gs.imageHnew; + t.tbw = gs.dstbuf.bw; + t.psm = gs.dstbuf.psm; + SaveTex(&t, 0); + + t.tbp0 = gs.srcbuf.bp; + t.tw = gs.imageWnew; + t.th = gs.imageHnew; + t.tbw = gs.srcbuf.bw; + t.psm = gs.srcbuf.psm; + SaveTex(&t, 0); + } +#endif +} + +void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw) +{ + if( m_Blocks[psm].bpp == 0 ) { + ERROR_LOG("ZeroGS: Bad psm 0x%x\n", psm); + start = 0; + end = 0x00400000; + return; + } + + if( (psm&0x30) == 0x30 || psm == 0xa ) { + + const BLOCK& b = m_Blocks[psm]; + + bw = (bw + b.width -1)/b.width; + start = bp*256 + ((y/b.height) * bw + (x/b.width) )*0x2000; + end = bp*256 + (((y+h-1)/b.height) * bw + (x + w + b.width - 1)/b.width)*0x2000; + } + else { + // just take the addresses + switch(psm) { + case 0x00: + case 0x01: + case 0x1b: + case 0x24: + case 0x2c: + start = 4*getPixelAddress32(x, y, bp, bw); + end = 4*getPixelAddress32(x+w-1, y+h-1, bp, bw) + 4; + break; + case 0x02: + start = 2*getPixelAddress16(x, y, bp, bw); + end = 2*getPixelAddress16(x+w-1, y+h-1, bp, bw)+2; + break; + case 0x13: + start = getPixelAddress8(x, y, bp, bw); + end = getPixelAddress8(x+w-1, y+h-1, bp, bw)+1; + break; + case 0x14: + { + start = getPixelAddress4(x, y, bp, bw)/2; + int newx = ((x+w-1+31)&~31)-1; + int newy = ((y+h-1+15)&~15)-1; + end = (getPixelAddress4(max(newx,x), max(newy,y), bp, bw)+2)/2; + break; + } + } + } +} + +void _Resolve(const D3DLOCKED_RECT& locksrc, int fbp, int fbw, int fbh, int psm, u32 fbm) +{ + s_nResolved += 2; + + // align the rect to the nearest page + // note that fbp is always aligned on page boundaries + int start, end; + GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); + + PRIM_LOG("resolve: %x %x %x (%x-%x)\n", fbp, fbw, fbh, start, end); + + int i, j; + short smask1 = gs.smask&1; + short smask2 = gs.smask&2; + u32 mask, imask; + + if( psm&2 ) { // 16 bit + // mask is shifted + imask = RGBA32to16(fbm); + mask = (~imask)&0xffff; + } + else { + mask = ~fbm; + imask = fbm; + + if( (psm&0xf)>0 ) { + // preserve the alpha? + mask &= 0x00ffffff; + imask |= 0xff000000; + } + } + +#define RESOLVE_32BIT(psm, T, Tsrc, blockbits, blockwidth, blockheight, convfn, frame, aax, aay) \ + { \ + Tsrc* src = (Tsrc*)locksrc.pBits; \ + T* pPageOffset = (T*)g_pbyGSMemory + fbp*(256/sizeof(T)), *dst; \ + int srcpitch = locksrc.Pitch * blockheight/sizeof(Tsrc); \ + int maxfbh = (0x00400000-fbp*256) / (sizeof(T) * fbw); \ + if( maxfbh > fbh ) maxfbh = fbh; \ + for(i = 0; i < (maxfbh&~(blockheight-1)); i += blockheight) { \ + /*if( smask2 && (i&1) == smask1 ) continue; */ \ + for(j = 0; j < fbw; j += blockwidth) { \ + /* have to write in the tiled format*/ \ + ##frame##SwizzleBlock##blockbits##(pPageOffset + getPixelAddress##psm##_0(j, i, fbw), \ + src+(j< psm + switch(psm) { + case PSMCT32: + case PSMCT24: + if( s_AAy ) { + RESOLVE_32BIT(32, u32, u32, 32A4, 8, 8, (u32), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32, u32, u32, 32A2, 8, 8, (u32), Frame, 1, 0); + } + else { + RESOLVE_32BIT(32, u32, u32, 32, 8, 8, (u32), Frame, 0, 0); + } + break; + case PSMCT16: + if( s_AAy ) { + RESOLVE_32BIT(16, u16, u32, 16A4, 16, 8, RGBA32to16, Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16, u16, u32, 16A2, 16, 8, RGBA32to16, Frame, 1, 0); + } + else { + RESOLVE_32BIT(16, u16, u32, 16, 16, 8, RGBA32to16, Frame, 0, 0); + } + + break; + case PSMCT16S: + if( s_AAy ) { + RESOLVE_32BIT(16S, u16, u32, 16A4, 16, 8, RGBA32to16, Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16S, u16, u32, 16A2, 16, 8, RGBA32to16, Frame, 1, 0); + } + else { + RESOLVE_32BIT(16S, u16, u32, 16, 16, 8, RGBA32to16, Frame, 0, 0); + } + + break; + case PSMT32Z: + case PSMT24Z: + if( s_AAy ) { + RESOLVE_32BIT(32Z, u32, u32, 32A4, 8, 8, (u32), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32Z, u32, u32, 32A2, 8, 8, (u32), Frame, 1, 0); + } + else { + RESOLVE_32BIT(32Z, u32, u32, 32, 8, 8, (u32), Frame, 0, 0); + } + + break; + case PSMT16Z: + if( s_AAy ) { + RESOLVE_32BIT(16Z, u16, u32, 16A4, 16, 8, (u16), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16Z, u16, u32, 16A2, 16, 8, (u16), Frame, 1, 0); + } + else { + RESOLVE_32BIT(16Z, u16, u32, 16, 16, 8, (u16), Frame, 0, 0); + } + + break; + case PSMT16SZ: + if( s_AAy ) { + RESOLVE_32BIT(16SZ, u16, u32, 16A4, 16, 8, (u16), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16SZ, u16, u32, 16A2, 16, 8, (u16), Frame, 1, 0); + } + else { + RESOLVE_32BIT(16SZ, u16, u32, 16, 16, 8, (u16), Frame, 0, 0); + } + + break; + } + } + else { + switch(psm) { + case PSMCT32: + case PSMCT24: + if( s_AAy ) { + RESOLVE_32BIT(32, u32, Vector_16F, 32A4, 8, 8, Float16ToARGB, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32, u32, Vector_16F, 32A2, 8, 8, Float16ToARGB, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(32, u32, Vector_16F, 32, 8, 8, Float16ToARGB, Frame16, 0, 0); + } + + break; + case PSMCT16: + if( s_AAy ) { + RESOLVE_32BIT(16, u16, Vector_16F, 16A4, 16, 8, Float16ToARGB16, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16, u16, Vector_16F, 16A2, 16, 8, Float16ToARGB16, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16, u16, Vector_16F, 16, 16, 8, Float16ToARGB16, Frame16, 0, 0); + } + + break; + case PSMCT16S: + if( s_AAy ) { + RESOLVE_32BIT(16S, u16, Vector_16F, 16A4, 16, 8, Float16ToARGB16, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16S, u16, Vector_16F, 16A2, 16, 8, Float16ToARGB16, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16S, u16, Vector_16F, 16, 16, 8, Float16ToARGB16, Frame16, 0, 0); + } + + break; + case PSMT32Z: + case PSMT24Z: + if( s_AAy ) { + RESOLVE_32BIT(32Z, u32, Vector_16F, 32ZA4, 8, 8, Float16ToARGB_Z, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32Z, u32, Vector_16F, 32ZA2, 8, 8, Float16ToARGB_Z, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(32Z, u32, Vector_16F, 32Z, 8, 8, Float16ToARGB_Z, Frame16, 0, 0); + } + + break; + case PSMT16Z: + if( s_AAy ) { + RESOLVE_32BIT(16Z, u16, Vector_16F, 16ZA4, 16, 8, Float16ToARGB16_Z, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16Z, u16, Vector_16F, 16ZA2, 16, 8, Float16ToARGB16_Z, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16Z, u16, Vector_16F, 16Z, 16, 8, Float16ToARGB16_Z, Frame16, 0, 0); + } + + break; + case PSMT16SZ: + if( s_AAy ) { + RESOLVE_32BIT(16SZ, u16, Vector_16F, 16ZA4, 16, 8, Float16ToARGB16_Z, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16SZ, u16, Vector_16F, 16ZA2, 16, 8, Float16ToARGB16_Z, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16SZ, u16, Vector_16F, 16Z, 16, 8, Float16ToARGB16_Z, Frame16, 0, 0); + } + + break; + } + } + + g_MemTargs.ClearRange(start, end); + INC_RESOLVE(); +} + +//////////// +// Saving // +//////////// +void SaveTex(tex0Info* ptex, int usevid) +{ + LPD3DTEX pTexture; + pd3dDevice->CreateTexture(ptex->tw, ptex->th, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &pTexture, NULL); + + D3DLOCKED_RECT lockdst; + pTexture->LockRect(0, &lockdst, NULL, 0); + + DWORD* dst = (DWORD*)lockdst.pBits; + u8* psrc = g_pbyGSMemory; + + CMemoryTarget* pmemtarg = NULL; + + if( usevid ) { + pmemtarg = g_MemTargs.GetMemoryTarget(*ptex, 1); + assert( pmemtarg != NULL ); + D3DLOCKED_RECT lock; + HRESULT hr = pmemtarg->ptexsys->LockRect(0, &lock, NULL, D3DLOCK_READONLY); + if( FAILED(hr) ) + return; + u32 offset = pmemtarg->realy * 4 * GPU_TEXWIDTH; + if( ptex->psm == PSMT8 ) offset *= ptex->cpsm <= 1 ? 4 : 2; + else if( ptex->psm == PSMT4 ) offset *= ptex->cpsm <= 1 ? 8 : 4; + + psrc = (u8*)lock.pBits - offset; + } + + for(int i = 0; i < ptex->th; ++i) { + for(int j = 0; j < ptex->tw; ++j) { + u32 u, addr; + switch(ptex->psm) { + case PSMCT32: + addr = getPixelAddress32(j, i, ptex->tbp0, ptex->tbw); + + if( addr*4 < 0x00400000 ) + u = readPixel32(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + + break; + case PSMCT24: + addr = getPixelAddress24(j, i, ptex->tbp0, ptex->tbw); + + if( addr*4 < 0x00400000 ) + u = readPixel24(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + + break; + case PSMCT16: + addr = getPixelAddress16(j, i, ptex->tbp0, ptex->tbw); + + if( addr*2 < 0x00400000 ) { + u = readPixel16(psrc, j, i, ptex->tbp0, ptex->tbw); + u = RGBA16to32(u); + } + else u = 0; + + break; + case PSMCT16S: + addr = getPixelAddress16(j, i, ptex->tbp0, ptex->tbw); + + if( addr*2 < 0x00400000 ) { + u = readPixel16S(psrc, j, i, ptex->tbp0, ptex->tbw); + u = RGBA16to32(u); + } + else u = 0; + break; + + case PSMT8: + addr = getPixelAddress8(j, i, ptex->tbp0, ptex->tbw); + + if( addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel8(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT4: + addr = getPixelAddress4(j, i, ptex->tbp0, ptex->tbw); + + if( addr < 2*0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel4(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT8H: + addr = getPixelAddress8H(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel8H(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + + break; + + case PSMT4HL: + addr = getPixelAddress4HL(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel4HL(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT4HH: + addr = getPixelAddress4HH(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel4HH(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT32Z: + addr = getPixelAddress32Z(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) + u = readPixel32Z(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + case PSMT24Z: + addr = getPixelAddress24Z(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) + u = readPixel24Z(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + case PSMT16Z: + addr = getPixelAddress16Z(j, i, ptex->tbp0, ptex->tbw); + + if( 2*addr < 0x00400000 ) + u = readPixel16Z(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + case PSMT16SZ: + addr = getPixelAddress16SZ(j, i, ptex->tbp0, ptex->tbw); + + if( 2*addr < 0x00400000 ) + u = readPixel16SZ(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + default: + assert(0); + } + + *dst++ = u; + } + + dst += lockdst.Pitch/4 - ptex->tw; + } + + pTexture->UnlockRect(0); + + if( usevid ) { + pmemtarg->ptexsys->UnlockRect(0); + } + + D3DXSaveTextureToFile("tex.tga", D3DXIFF_TGA, pTexture, NULL); + + SAFE_RELEASE(pTexture); + +} + +} diff --git a/plugins/zerogs/dx/targets.h b/plugins/zerogs/dx/targets.h index d104bbf68c..5e691f36a8 100644 --- a/plugins/zerogs/dx/targets.h +++ b/plugins/zerogs/dx/targets.h @@ -1,232 +1,232 @@ -#define TARGET_VIRTUAL_KEY 0x80000000 - -namespace ZeroGS -{ - // manages render targets - class CRenderTargetMngr - { - public: - typedef map MAPTARGETS; - - enum TargetOptions - { - TO_DepthBuffer = 1, - TO_StrictHeight = 2, // height returned has to be the same as requested - TO_Virtual = 4 - }; - - ~CRenderTargetMngr() { Destroy(); } - - void Destroy(); - static MAPTARGETS::iterator GetOldestTarg(MAPTARGETS& m); - - CRenderTarget* GetTarg(const frameInfo& frame, DWORD Options, int maxposheight); - inline CRenderTarget* GetTarg(int fbp, int fbw) { - MAPTARGETS::iterator it = mapTargets.find(fbp|(fbw<<16)); - return it != mapTargets.end() ? it->second : NULL; - } - - // gets all targets with a range - void GetTargs(int start, int end, list& listTargets) const; - - virtual void DestroyChildren(CRenderTarget* ptarg); - - // resolves all targets within a range - __forceinline void Resolve(int start, int end); - __forceinline void ResolveAll() { - for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it ) - it->second->Resolve(); - } - - void DestroyTarg(CRenderTarget* ptarg) { - for(int i = 0; i < 2; ++i) { - if( ptarg == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } - if( ptarg == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } - } - - DestroyChildren(ptarg); - delete ptarg; - } - - inline void DestroyAll(int start, int end, int fbw) { - for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end();) { - if( it->second->start < end && start < it->second->end ) { - // if is depth, only resolve if fbw is the same - if( !it->second->IsDepth() ) { - // only resolve if the widths are the same or it->second has bit outside the range - // shadow of colossus swaps between fbw=256,fbh=256 and fbw=512,fbh=448. This kills the game if doing || it->second->end > end - - // kh hack, sometimes kh movies do this to clear the target, so have a static count that periodically checks end - static int count = 0; - - if( it->second->fbw == fbw || (it->second->fbw != fbw && (it->second->start < start || ((count++&0xf)?0:it->second->end > end) )) ) - it->second->Resolve(); - else { - if( vb[0].prndr == it->second || vb[0].pdepth == it->second ) Flush(0); - if( vb[1].prndr == it->second || vb[1].pdepth == it->second ) Flush(1); - - it->second->status |= CRenderTarget::TS_Resolved; - } - } - else { - if( it->second->fbw == fbw ) - it->second->Resolve(); - else { - if( vb[0].prndr == it->second || vb[0].pdepth == it->second ) Flush(0); - if( vb[1].prndr == it->second || vb[1].pdepth == it->second ) Flush(1); - - it->second->status |= CRenderTarget::TS_Resolved; - } - } - - for(int i = 0; i < 2; ++i) { - if( it->second == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } - if( it->second == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } - } - - u32 dummykey = (it->second->fbw<<16)|it->second->fbh; - if( it->second->pmimicparent != NULL && mapDummyTargs.find(dummykey) == mapDummyTargs.end() ) { - DestroyChildren(it->second); - mapDummyTargs[dummykey] = it->second; - } - else { - DestroyChildren(it->second); - delete it->second; - } - it = mapTargets.erase(it); - } - else ++it; - } - } - - inline void DestroyIntersecting(CRenderTarget* prndr) - { - assert( prndr != NULL ); - - int start, end; - GetRectMemAddress(start, end, prndr->psm, 0, 0, prndr->fbw, prndr->fbh, prndr->fbp, prndr->fbw); - - for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end();) { - if( it->second != prndr && it->second->start < end && start < it->second->end ) { - it->second->Resolve(); - - for(int i = 0; i < 2; ++i) { - if( it->second == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } - if( it->second == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } - } - - u32 dummykey = (it->second->fbw<<16)|it->second->fbh; - if( it->second->pmimicparent != NULL && mapDummyTargs.find(dummykey) == mapDummyTargs.end() ) { - DestroyChildren(it->second); - mapDummyTargs[dummykey] = it->second; - } - else { - DestroyChildren(it->second); - delete it->second; - } - - it = mapTargets.erase(it); - } - else ++it; - } - } - - // promotes a target from virtual to real - inline CRenderTarget* Promote(u32 key) { - assert( !(key & TARGET_VIRTUAL_KEY) ); - - // promote to regular targ - CRenderTargetMngr::MAPTARGETS::iterator it = mapTargets.find(key|TARGET_VIRTUAL_KEY); - assert( it != mapTargets.end() ); - - CRenderTarget* ptarg = it->second; - mapTargets.erase(it); - - DestroyIntersecting(ptarg); - - it = mapTargets.find(key); - if( it != mapTargets.end() ) { - DestroyTarg(it->second); - it->second = ptarg; - } - else - mapTargets[key] = ptarg; - - if( g_GameSettings & GAME_RESOLVEPROMOTED ) - ptarg->status = CRenderTarget::TS_Resolved; - else - ptarg->status = CRenderTarget::TS_NeedUpdate; - return ptarg; - } - - MAPTARGETS mapTargets, mapDummyTargs; - }; - - class CMemoryTargetMngr - { - public: - CMemoryTargetMngr() : curstamp(0) {} - CMemoryTarget* GetMemoryTarget(const tex0Info& tex0, int forcevalidate); // pcbp is pointer to start of clut - - void Destroy(); // destroy all targs - - void ClearRange(int starty, int endy); // set all targets to cleared - void DestroyCleared(); // flush all cleared targes - void DestroyOldest(); - - list listTargets, listClearedTargets; - u32 curstamp; - - private: - list::iterator DestroyTargetIter(list::iterator& it); - }; - - class CBitwiseTextureMngr - { - public: - ~CBitwiseTextureMngr() { Destroy(); } - - void Destroy(); - - // since GetTex can delete textures to free up mem, it is dangerous if using that texture, so specify at least one other tex to save - __forceinline LPD3DTEX GetTex(u32 bitvalue, LPD3DTEX ptexDoNotDelete) { - map::iterator it = mapTextures.find(bitvalue); - if( it != mapTextures.end() ) - return it->second; - return GetTexInt(bitvalue, ptexDoNotDelete); - } - - private: - LPD3DTEX GetTexInt(u32 bitvalue, LPD3DTEX ptexDoNotDelete); - - map mapTextures; - }; - - // manages - class CRangeManager - { - public: - CRangeManager() - { - ranges.reserve(16); - } - - // [start, end) - struct RANGE - { - RANGE() {} - inline RANGE(int start, int end) : start(start), end(end) {} - int start, end; - }; - - // works in semi logN - void Insert(int start, int end); - inline void Clear() { ranges.resize(0); } - - vector ranges; // organized in ascending order, non-intersecting - }; - - extern CRenderTargetMngr s_RTs, s_DepthRTs; - extern CBitwiseTextureMngr s_BitwiseTextures; - extern CMemoryTargetMngr g_MemTargs; -} +#define TARGET_VIRTUAL_KEY 0x80000000 + +namespace ZeroGS +{ + // manages render targets + class CRenderTargetMngr + { + public: + typedef map MAPTARGETS; + + enum TargetOptions + { + TO_DepthBuffer = 1, + TO_StrictHeight = 2, // height returned has to be the same as requested + TO_Virtual = 4 + }; + + ~CRenderTargetMngr() { Destroy(); } + + void Destroy(); + static MAPTARGETS::iterator GetOldestTarg(MAPTARGETS& m); + + CRenderTarget* GetTarg(const frameInfo& frame, DWORD Options, int maxposheight); + inline CRenderTarget* GetTarg(int fbp, int fbw) { + MAPTARGETS::iterator it = mapTargets.find(fbp|(fbw<<16)); + return it != mapTargets.end() ? it->second : NULL; + } + + // gets all targets with a range + void GetTargs(int start, int end, list& listTargets) const; + + virtual void DestroyChildren(CRenderTarget* ptarg); + + // resolves all targets within a range + __forceinline void Resolve(int start, int end); + __forceinline void ResolveAll() { + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it ) + it->second->Resolve(); + } + + void DestroyTarg(CRenderTarget* ptarg) { + for(int i = 0; i < 2; ++i) { + if( ptarg == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } + if( ptarg == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } + } + + DestroyChildren(ptarg); + delete ptarg; + } + + inline void DestroyAll(int start, int end, int fbw) { + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end();) { + if( it->second->start < end && start < it->second->end ) { + // if is depth, only resolve if fbw is the same + if( !it->second->IsDepth() ) { + // only resolve if the widths are the same or it->second has bit outside the range + // shadow of colossus swaps between fbw=256,fbh=256 and fbw=512,fbh=448. This kills the game if doing || it->second->end > end + + // kh hack, sometimes kh movies do this to clear the target, so have a static count that periodically checks end + static int count = 0; + + if( it->second->fbw == fbw || (it->second->fbw != fbw && (it->second->start < start || ((count++&0xf)?0:it->second->end > end) )) ) + it->second->Resolve(); + else { + if( vb[0].prndr == it->second || vb[0].pdepth == it->second ) Flush(0); + if( vb[1].prndr == it->second || vb[1].pdepth == it->second ) Flush(1); + + it->second->status |= CRenderTarget::TS_Resolved; + } + } + else { + if( it->second->fbw == fbw ) + it->second->Resolve(); + else { + if( vb[0].prndr == it->second || vb[0].pdepth == it->second ) Flush(0); + if( vb[1].prndr == it->second || vb[1].pdepth == it->second ) Flush(1); + + it->second->status |= CRenderTarget::TS_Resolved; + } + } + + for(int i = 0; i < 2; ++i) { + if( it->second == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } + if( it->second == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } + } + + u32 dummykey = (it->second->fbw<<16)|it->second->fbh; + if( it->second->pmimicparent != NULL && mapDummyTargs.find(dummykey) == mapDummyTargs.end() ) { + DestroyChildren(it->second); + mapDummyTargs[dummykey] = it->second; + } + else { + DestroyChildren(it->second); + delete it->second; + } + it = mapTargets.erase(it); + } + else ++it; + } + } + + inline void DestroyIntersecting(CRenderTarget* prndr) + { + assert( prndr != NULL ); + + int start, end; + GetRectMemAddress(start, end, prndr->psm, 0, 0, prndr->fbw, prndr->fbh, prndr->fbp, prndr->fbw); + + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end();) { + if( it->second != prndr && it->second->start < end && start < it->second->end ) { + it->second->Resolve(); + + for(int i = 0; i < 2; ++i) { + if( it->second == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } + if( it->second == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } + } + + u32 dummykey = (it->second->fbw<<16)|it->second->fbh; + if( it->second->pmimicparent != NULL && mapDummyTargs.find(dummykey) == mapDummyTargs.end() ) { + DestroyChildren(it->second); + mapDummyTargs[dummykey] = it->second; + } + else { + DestroyChildren(it->second); + delete it->second; + } + + it = mapTargets.erase(it); + } + else ++it; + } + } + + // promotes a target from virtual to real + inline CRenderTarget* Promote(u32 key) { + assert( !(key & TARGET_VIRTUAL_KEY) ); + + // promote to regular targ + CRenderTargetMngr::MAPTARGETS::iterator it = mapTargets.find(key|TARGET_VIRTUAL_KEY); + assert( it != mapTargets.end() ); + + CRenderTarget* ptarg = it->second; + mapTargets.erase(it); + + DestroyIntersecting(ptarg); + + it = mapTargets.find(key); + if( it != mapTargets.end() ) { + DestroyTarg(it->second); + it->second = ptarg; + } + else + mapTargets[key] = ptarg; + + if( g_GameSettings & GAME_RESOLVEPROMOTED ) + ptarg->status = CRenderTarget::TS_Resolved; + else + ptarg->status = CRenderTarget::TS_NeedUpdate; + return ptarg; + } + + MAPTARGETS mapTargets, mapDummyTargs; + }; + + class CMemoryTargetMngr + { + public: + CMemoryTargetMngr() : curstamp(0) {} + CMemoryTarget* GetMemoryTarget(const tex0Info& tex0, int forcevalidate); // pcbp is pointer to start of clut + + void Destroy(); // destroy all targs + + void ClearRange(int starty, int endy); // set all targets to cleared + void DestroyCleared(); // flush all cleared targes + void DestroyOldest(); + + list listTargets, listClearedTargets; + u32 curstamp; + + private: + list::iterator DestroyTargetIter(list::iterator& it); + }; + + class CBitwiseTextureMngr + { + public: + ~CBitwiseTextureMngr() { Destroy(); } + + void Destroy(); + + // since GetTex can delete textures to free up mem, it is dangerous if using that texture, so specify at least one other tex to save + __forceinline LPD3DTEX GetTex(u32 bitvalue, LPD3DTEX ptexDoNotDelete) { + map::iterator it = mapTextures.find(bitvalue); + if( it != mapTextures.end() ) + return it->second; + return GetTexInt(bitvalue, ptexDoNotDelete); + } + + private: + LPD3DTEX GetTexInt(u32 bitvalue, LPD3DTEX ptexDoNotDelete); + + map mapTextures; + }; + + // manages + class CRangeManager + { + public: + CRangeManager() + { + ranges.reserve(16); + } + + // [start, end) + struct RANGE + { + RANGE() {} + inline RANGE(int start, int end) : start(start), end(end) {} + int start, end; + }; + + // works in semi logN + void Insert(int start, int end); + inline void Clear() { ranges.resize(0); } + + vector ranges; // organized in ascending order, non-intersecting + }; + + extern CRenderTargetMngr s_RTs, s_DepthRTs; + extern CBitwiseTextureMngr s_BitwiseTextures; + extern CMemoryTargetMngr g_MemTargs; +} diff --git a/plugins/zerogs/dx/x86.cpp b/plugins/zerogs/dx/x86.cpp index 6b3a2d9b42..469bd3ecf7 100644 --- a/plugins/zerogs/dx/x86.cpp +++ b/plugins/zerogs/dx/x86.cpp @@ -1,573 +1,573 @@ -/* ZeroGS KOSMOS - * Copyright (C) 2005-2006 Gabest/zerofrog@gmail.com - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 Gabest/zerofrog@gmail.com + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + #include - -#include "GS.h" -#include "Mem.h" -#include "x86.h" - -#if defined(ZEROGS_SSE2) && (defined(_WIN32)||defined(__x86_64__)) -#include -#include -#endif - -// swizzling - -void FASTCALL(SwizzleBlock32_c(u8* dst, u8* src, int srcpitch, u32 WriteMask)) -{ - u32* d = &g_columnTable32[0][0]; - - if(WriteMask == 0xffffffff) - { - for(int j = 0; j < 8; j++, d += 8, src += srcpitch) - for(int i = 0; i < 8; i++) - ((u32*)dst)[d[i]] = ((u32*)src)[i]; - } - else - { - for(int j = 0; j < 8; j++, d += 8, src += srcpitch) - for(int i = 0; i < 8; i++) - ((u32*)dst)[d[i]] = (((u32*)dst)[d[i]] & ~WriteMask) | (((u32*)src)[i] & WriteMask); - } -} - -void FASTCALL(SwizzleBlock16_c(u8* dst, u8* src, int srcpitch)) -{ - u32* d = &g_columnTable16[0][0]; - - for(int j = 0; j < 8; j++, d += 16, src += srcpitch) - for(int i = 0; i < 16; i++) - ((u16*)dst)[d[i]] = ((u16*)src)[i]; -} - -void FASTCALL(SwizzleBlock8_c(u8* dst, u8* src, int srcpitch)) -{ - u32* d = &g_columnTable8[0][0]; - - for(int j = 0; j < 16; j++, d += 16, src += srcpitch) - for(int i = 0; i < 16; i++) - dst[d[i]] = src[i]; -} - -void FASTCALL(SwizzleBlock4_c(u8* dst, u8* src, int srcpitch)) -{ - u32* d = &g_columnTable4[0][0]; - - for(int j = 0; j < 16; j++, d += 32, src += srcpitch) - { - for(int i = 0; i < 32; i++) - { - u32 addr = d[i]; - u8 c = (src[i>>1] >> ((i&1) << 2)) & 0x0f; - u32 shift = (addr&1) << 2; - dst[addr >> 1] = (dst[addr >> 1] & (0xf0 >> shift)) | (c << shift); - } - } -} - -#define _FrameSwizzleBlock(type, transfer, transfer16, incsrc) \ -/* FrameSwizzleBlock32 */ \ -void FASTCALL(FrameSwizzleBlock32##type##c(u32* dst, u32* src, int srcpitch, u32 WriteMask)) \ -{ \ - u32* d = &g_columnTable32[0][0]; \ - \ - if( WriteMask == 0xffffffff ) { \ - for(int i = 0; i < 8; ++i, d += 8) { \ - for(int j = 0; j < 8; ++j) { \ - dst[d[j]] = (transfer); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ - else { \ - for(int i = 0; i < 8; ++i, d += 8) { \ - for(int j = 0; j < 8; ++j) { \ - dst[d[j]] = ((transfer)&WriteMask)|(dst[d[j]]&~WriteMask); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ -} \ -\ -/* FrameSwizzleBlock16 */ \ -void FASTCALL(FrameSwizzleBlock16##type##c(u16* dst, u32* src, int srcpitch, u32 WriteMask)) \ -{ \ - u32* d = &g_columnTable16[0][0]; \ - \ - if( WriteMask == 0xffff ) { \ - for(int i = 0; i < 8; ++i, d += 16) { \ - for(int j = 0; j < 16; ++j) { \ - u32 temp = (transfer); \ - dst[d[j]] = RGBA32to16(temp); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ - else { \ - for(int i = 0; i < 8; ++i, d += 16) { \ - for(int j = 0; j < 16; ++j) { \ - u32 temp = (transfer); \ - u32 dsrc = RGBA32to16(temp); \ - dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ -} \ -\ -/* Frame16SwizzleBlock32 */ \ -void FASTCALL(Frame16SwizzleBlock32##type##c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ -{ \ - u32* d = &g_columnTable32[0][0]; \ -\ - if( WriteMask == 0xffffffff ) { \ - for(int i = 0; i < 8; ++i, d += 8) { \ - for(int j = 0; j < 8; ++j) { \ - Vector_16F dsrc16 = (transfer16); \ - dst[d[j]] = Float16ToARGB(dsrc16); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ - else { \ - for(int i = 0; i < 8; ++i, d += 8) { \ - for(int j = 0; j < 8; ++j) { \ - Vector_16F dsrc16 = (transfer16); \ - u32 dsrc = Float16ToARGB(dsrc16); \ - dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ - } \ -\ -/* Frame16SwizzleBlock32Z */ \ -void FASTCALL(Frame16SwizzleBlock32Z##type##c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ -{ \ - u32* d = &g_columnTable32[0][0]; \ - if( WriteMask == 0xffffffff ) { /* breaks KH text if not checked */ \ - for(int i = 0; i < 8; ++i, d += 8) { \ - for(int j = 0; j < 8; ++j) { \ - Vector_16F dsrc16 = (transfer16); \ - dst[d[j]] = Float16ToARGB_Z(dsrc16); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ - else { \ - for(int i = 0; i < 8; ++i, d += 8) { \ - for(int j = 0; j < 8; ++j) { \ - Vector_16F dsrc16 = (transfer16); \ - u32 dsrc = Float16ToARGB_Z(dsrc16); \ - dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ - } \ - \ - /* Frame16SwizzleBlock16 */ \ -void FASTCALL(Frame16SwizzleBlock16##type##c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ -{ \ - u32* d = &g_columnTable16[0][0]; \ - \ - if( (WriteMask&0xfff8f8f8) == 0xfff8f8f8) { \ - for(int i = 0; i < 8; ++i, d += 16) { \ - for(int j = 0; j < 16; ++j) { \ - Vector_16F dsrc16 = (transfer16); \ - dst[d[j]] = Float16ToARGB16(dsrc16); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ - else { \ - for(int i = 0; i < 8; ++i, d += 16) { \ - for(int j = 0; j < 16; ++j) { \ - Vector_16F dsrc16 = (transfer16); \ - u32 dsrc = Float16ToARGB16(dsrc16); \ - dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ - } \ - \ - /* Frame16SwizzleBlock16Z */ \ -void FASTCALL(Frame16SwizzleBlock16Z##type##c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ -{ \ - u32* d = &g_columnTable16[0][0]; \ - \ - for(int i = 0; i < 8; ++i, d += 16) { \ - for(int j = 0; j < 16; ++j) { \ - Vector_16F dsrc16 = (transfer16); \ - dst[d[j]] = Float16ToARGB16_Z(dsrc16); \ - } \ - src += srcpitch << incsrc; \ - } \ -} \ - -_FrameSwizzleBlock(_, src[j], src[j], 0); -_FrameSwizzleBlock(A2_, (src[2*j]+src[2*j+1])>>1, src[2*j], 0); -_FrameSwizzleBlock(A4_, (src[2*j]+src[2*j+1]+src[2*j+srcpitch]+src[2*j+srcpitch+1])>>2, src[2*j], 1); - -#ifdef ZEROGS_SSE2 - -//void FASTCALL(WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32* clut) -//{ -// __asm { -// mov eax, vm -// mov ecx, clut -// mov edx, 8 -// } -// -//Extract32x2: -// __asm { -// movdqa xmm0, qword ptr [eax] -// movdqa xmm1, qword ptr [eax+16] -// movdqa xmm2, qword ptr [eax+32] -// movdqa xmm3, qword ptr [eax+48] -// -// // rearrange -// pshuflw xmm0, xmm0, 0xd8 -// pshufhw xmm0, xmm0, 0xd8 -// pshuflw xmm1, xmm1, 0xd8 -// pshufhw xmm1, xmm1, 0xd8 -// pshuflw xmm2, xmm2, 0xd8 -// pshufhw xmm2, xmm2, 0xd8 -// pshuflw xmm3, xmm3, 0xd8 -// pshufhw xmm3, xmm3, 0xd8 -// -// movdqa xmm4, xmm0 -// movdqa xmm6, xmm2 -// -// shufps xmm0, xmm1, 0x88 -// shufps xmm2, xmm3, 0x88 -// -// shufps xmm4, xmm1, 0xdd -// shufps xmm6, xmm3, 0xdd -// -// pshufd xmm0, xmm0, 0xd8 -// pshufd xmm2, xmm2, 0xd8 -// pshufd xmm4, xmm4, 0xd8 -// pshufd xmm6, xmm6, 0xd8 -// -// // left column -// movhlps xmm1, xmm0 -// movlhps xmm0, xmm2 -// //movdqa xmm7, [ecx] -// -// movdqa [ecx], xmm0 -// shufps xmm1, xmm2, 0xe4 -// movdqa [ecx+16], xmm1 -// -// // right column -// movhlps xmm3, xmm4 -// movlhps xmm4, xmm6 -// movdqa [ecx+32], xmm4 -// shufps xmm3, xmm6, 0xe4 -// movdqa [ecx+48], xmm3 -// -// add eax, 16*4 -// add ecx, 16*8 -// sub edx, 1 -// cmp edx, 0 -// jne Extract32x2 -// } -//} - -#if (defined(_WIN32)||defined(__x86_64__)) - -extern "C" void FASTCALL(WriteCLUT_T32_I8_CSM1_sse2(u32* vm, u32* clut)) -{ - __m128i* src = (__m128i*)vm; - __m128i* dst = (__m128i*)clut; - - for(int j = 0; j < 64; j += 32, src += 32, dst += 32) - { - for(int i = 0; i < 16; i += 4) - { - __m128i r0 = _mm_load_si128(&src[i+0]); - __m128i r1 = _mm_load_si128(&src[i+1]); - __m128i r2 = _mm_load_si128(&src[i+2]); - __m128i r3 = _mm_load_si128(&src[i+3]); - - _mm_store_si128(&dst[i*2+0], _mm_unpacklo_epi64(r0, r1)); - _mm_store_si128(&dst[i*2+1], _mm_unpacklo_epi64(r2, r3)); - _mm_store_si128(&dst[i*2+2], _mm_unpackhi_epi64(r0, r1)); - _mm_store_si128(&dst[i*2+3], _mm_unpackhi_epi64(r2, r3)); - - __m128i r4 = _mm_load_si128(&src[i+0+16]); - __m128i r5 = _mm_load_si128(&src[i+1+16]); - __m128i r6 = _mm_load_si128(&src[i+2+16]); - __m128i r7 = _mm_load_si128(&src[i+3+16]); - - _mm_store_si128(&dst[i*2+4], _mm_unpacklo_epi64(r4, r5)); - _mm_store_si128(&dst[i*2+5], _mm_unpacklo_epi64(r6, r7)); - _mm_store_si128(&dst[i*2+6], _mm_unpackhi_epi64(r4, r5)); - _mm_store_si128(&dst[i*2+7], _mm_unpackhi_epi64(r6, r7)); - } - } -} - -extern "C" void FASTCALL(WriteCLUT_T32_I4_CSM1_sse2(u32* vm, u32* clut)) -{ - __m128i* src = (__m128i*)vm; - __m128i* dst = (__m128i*)clut; - - __m128i r0 = _mm_load_si128(&src[0]); - __m128i r1 = _mm_load_si128(&src[1]); - __m128i r2 = _mm_load_si128(&src[2]); - __m128i r3 = _mm_load_si128(&src[3]); - - _mm_store_si128(&dst[0], _mm_unpacklo_epi64(r0, r1)); - _mm_store_si128(&dst[1], _mm_unpacklo_epi64(r2, r3)); - _mm_store_si128(&dst[2], _mm_unpackhi_epi64(r0, r1)); - _mm_store_si128(&dst[3], _mm_unpackhi_epi64(r2, r3)); -} -#endif - -#if defined(_MSC_VER) - -extern "C" { -PCSX2_ALIGNED16(int s_clut16mask2[4]) = { 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff }; -PCSX2_ALIGNED16(int s_clut16mask[8]) = { 0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000, - 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff}; -} - -#if !defined(__x86_64__) - -extern "C" void FASTCALL(WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut)) -{ - __asm { - mov eax, vm - mov ecx, clut - movdqa xmm0, qword ptr [eax] - movdqa xmm1, qword ptr [eax+16] - movdqa xmm2, qword ptr [eax+32] - movdqa xmm3, qword ptr [eax+48] - - // rearrange - pshuflw xmm0, xmm0, 0x88 - pshufhw xmm0, xmm0, 0x88 - pshuflw xmm1, xmm1, 0x88 - pshufhw xmm1, xmm1, 0x88 - pshuflw xmm2, xmm2, 0x88 - pshufhw xmm2, xmm2, 0x88 - pshuflw xmm3, xmm3, 0x88 - pshufhw xmm3, xmm3, 0x88 - - shufps xmm0, xmm1, 0x88 - shufps xmm2, xmm3, 0x88 - - pshufd xmm0, xmm0, 0xd8 - pshufd xmm2, xmm2, 0xd8 - - pxor xmm6, xmm6 - - test ecx, 15 - jnz WriteUnaligned - - movdqa xmm7, s_clut16mask // saves upper 16 bits - - // have to save interlaced with the old data - movdqa xmm4, [ecx] - movdqa xmm5, [ecx+32] - movhlps xmm1, xmm0 - movlhps xmm0, xmm2 // lower 8 colors - - pand xmm4, xmm7 - pand xmm5, xmm7 - - shufps xmm1, xmm2, 0xe4 // upper 8 colors - movdqa xmm2, xmm0 - movdqa xmm3, xmm1 - - punpcklwd xmm0, xmm6 - punpcklwd xmm1, xmm6 - por xmm0, xmm4 - por xmm1, xmm5 - - punpckhwd xmm2, xmm6 - punpckhwd xmm3, xmm6 - - movdqa [ecx], xmm0 - movdqa [ecx+32], xmm1 - - movdqa xmm5, xmm7 - pand xmm7, [ecx+16] - pand xmm5, [ecx+48] - - por xmm2, xmm7 - por xmm3, xmm5 - - movdqa [ecx+16], xmm2 - movdqa [ecx+48], xmm3 - jmp End - -WriteUnaligned: - // ecx is offset by 2 - sub ecx, 2 - - movdqa xmm7, s_clut16mask2 // saves lower 16 bits - - // have to save interlaced with the old data - movdqa xmm4, [ecx] - movdqa xmm5, [ecx+32] - movhlps xmm1, xmm0 - movlhps xmm0, xmm2 // lower 8 colors - - pand xmm4, xmm7 - pand xmm5, xmm7 - - shufps xmm1, xmm2, 0xe4 // upper 8 colors - movdqa xmm2, xmm0 - movdqa xmm3, xmm1 - - punpcklwd xmm0, xmm6 - punpcklwd xmm1, xmm6 - pslld xmm0, 16 - pslld xmm1, 16 - por xmm0, xmm4 - por xmm1, xmm5 - - punpckhwd xmm2, xmm6 - punpckhwd xmm3, xmm6 - pslld xmm2, 16 - pslld xmm3, 16 - - movdqa [ecx], xmm0 - movdqa [ecx+32], xmm1 - - movdqa xmm5, xmm7 - pand xmm7, [ecx+16] - pand xmm5, [ecx+48] - - por xmm2, xmm7 - por xmm3, xmm5 - - movdqa [ecx+16], xmm2 - movdqa [ecx+48], xmm3 -End: - } -} -#endif // __x86_64__ -#endif // _MSC_VER - -#endif // ZEROGS_SSE2 - -void FASTCALL(WriteCLUT_T16_I8_CSM1_c(u32* _vm, u32* _clut)) -{ - const static u32 map[] = - { - 0, 2, 8, 10, 16, 18, 24, 26, - 4, 6, 12, 14, 20, 22, 28, 30, - 1, 3, 9, 11, 17, 19, 25, 27, - 5, 7, 13, 15, 21, 23, 29, 31 - }; - - u16* vm = (u16*)_vm; - u16* clut = (u16*)_clut; - - int left = ((u32)(uptr)clut&2) ? 512 : 512-(((u32)(uptr)clut)&0x3ff)/2; - - for(int j = 0; j < 8; j++, vm += 32, clut += 64, left -= 32) - { - if(left == 32) { - assert( left == 32 ); - for(int i = 0; i < 16; i++) - clut[2*i] = vm[map[i]]; - - clut = (u16*)((uptr)clut & ~0x3ff) + 1; - - for(int i = 16; i < 32; i++) - clut[2*i] = vm[map[i]]; - } - else { - if( left == 0 ) { - clut = (u16*)((uptr)clut & ~0x3ff) + 1; - left = -1; - } - - for(int i = 0; i < 32; i++) - clut[2*i] = vm[map[i]]; - } - } -} - -void FASTCALL(WriteCLUT_T32_I8_CSM1_c(u32* vm, u32* clut)) -{ - u64* src = (u64*)vm; - u64* dst = (u64*)clut; - - for(int j = 0; j < 2; j++, src += 32) { - for(int i = 0; i < 4; i++, dst+=16, src+=8) - { - dst[0] = src[0]; - dst[1] = src[2]; - dst[2] = src[4]; - dst[3] = src[6]; - dst[4] = src[1]; - dst[5] = src[3]; - dst[6] = src[5]; - dst[7] = src[7]; - - dst[8] = src[32]; - dst[9] = src[32+2]; - dst[10] = src[32+4]; - dst[11] = src[32+6]; - dst[12] = src[32+1]; - dst[13] = src[32+3]; - dst[14] = src[32+5]; - dst[15] = src[32+7]; - } - } -} - -void FASTCALL(WriteCLUT_T16_I4_CSM1_c(u32* _vm, u32* _clut)) -{ - u16* dst = (u16*)_clut; - u16* src = (u16*)_vm; - - dst[0] = src[0]; dst[2] = src[2]; - dst[4] = src[8]; dst[6] = src[10]; - dst[8] = src[16]; dst[10] = src[18]; - dst[12] = src[24]; dst[14] = src[26]; - dst[16] = src[4]; dst[18] = src[6]; - dst[20] = src[12]; dst[22] = src[14]; - dst[24] = src[20]; dst[26] = src[22]; - dst[28] = src[28]; dst[30] = src[30]; -} - -void FASTCALL(WriteCLUT_T32_I4_CSM1_c(u32* vm, u32* clut)) -{ - u64* src = (u64*)vm; - u64* dst = (u64*)clut; - - dst[0] = src[0]; - dst[1] = src[2]; - dst[2] = src[4]; - dst[3] = src[6]; - dst[4] = src[1]; - dst[5] = src[3]; - dst[6] = src[5]; - dst[7] = src[7]; -} + +#include "GS.h" +#include "Mem.h" +#include "x86.h" + +#if defined(ZEROGS_SSE2) && (defined(_WIN32)||defined(__x86_64__)) +#include +#include +#endif + +// swizzling + +void FASTCALL(SwizzleBlock32_c(u8* dst, u8* src, int srcpitch, u32 WriteMask)) +{ + u32* d = &g_columnTable32[0][0]; + + if(WriteMask == 0xffffffff) + { + for(int j = 0; j < 8; j++, d += 8, src += srcpitch) + for(int i = 0; i < 8; i++) + ((u32*)dst)[d[i]] = ((u32*)src)[i]; + } + else + { + for(int j = 0; j < 8; j++, d += 8, src += srcpitch) + for(int i = 0; i < 8; i++) + ((u32*)dst)[d[i]] = (((u32*)dst)[d[i]] & ~WriteMask) | (((u32*)src)[i] & WriteMask); + } +} + +void FASTCALL(SwizzleBlock16_c(u8* dst, u8* src, int srcpitch)) +{ + u32* d = &g_columnTable16[0][0]; + + for(int j = 0; j < 8; j++, d += 16, src += srcpitch) + for(int i = 0; i < 16; i++) + ((u16*)dst)[d[i]] = ((u16*)src)[i]; +} + +void FASTCALL(SwizzleBlock8_c(u8* dst, u8* src, int srcpitch)) +{ + u32* d = &g_columnTable8[0][0]; + + for(int j = 0; j < 16; j++, d += 16, src += srcpitch) + for(int i = 0; i < 16; i++) + dst[d[i]] = src[i]; +} + +void FASTCALL(SwizzleBlock4_c(u8* dst, u8* src, int srcpitch)) +{ + u32* d = &g_columnTable4[0][0]; + + for(int j = 0; j < 16; j++, d += 32, src += srcpitch) + { + for(int i = 0; i < 32; i++) + { + u32 addr = d[i]; + u8 c = (src[i>>1] >> ((i&1) << 2)) & 0x0f; + u32 shift = (addr&1) << 2; + dst[addr >> 1] = (dst[addr >> 1] & (0xf0 >> shift)) | (c << shift); + } + } +} + +#define _FrameSwizzleBlock(type, transfer, transfer16, incsrc) \ +/* FrameSwizzleBlock32 */ \ +void FASTCALL(FrameSwizzleBlock32##type##c(u32* dst, u32* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable32[0][0]; \ + \ + if( WriteMask == 0xffffffff ) { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + dst[d[j]] = (transfer); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + dst[d[j]] = ((transfer)&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ +} \ +\ +/* FrameSwizzleBlock16 */ \ +void FASTCALL(FrameSwizzleBlock16##type##c(u16* dst, u32* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable16[0][0]; \ + \ + if( WriteMask == 0xffff ) { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + u32 temp = (transfer); \ + dst[d[j]] = RGBA32to16(temp); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + u32 temp = (transfer); \ + u32 dsrc = RGBA32to16(temp); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ +} \ +\ +/* Frame16SwizzleBlock32 */ \ +void FASTCALL(Frame16SwizzleBlock32##type##c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable32[0][0]; \ +\ + if( WriteMask == 0xffffffff ) { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + u32 dsrc = Float16ToARGB(dsrc16); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + } \ +\ +/* Frame16SwizzleBlock32Z */ \ +void FASTCALL(Frame16SwizzleBlock32Z##type##c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable32[0][0]; \ + if( WriteMask == 0xffffffff ) { /* breaks KH text if not checked */ \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB_Z(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + u32 dsrc = Float16ToARGB_Z(dsrc16); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + } \ + \ + /* Frame16SwizzleBlock16 */ \ +void FASTCALL(Frame16SwizzleBlock16##type##c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable16[0][0]; \ + \ + if( (WriteMask&0xfff8f8f8) == 0xfff8f8f8) { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB16(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + u32 dsrc = Float16ToARGB16(dsrc16); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + } \ + \ + /* Frame16SwizzleBlock16Z */ \ +void FASTCALL(Frame16SwizzleBlock16Z##type##c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable16[0][0]; \ + \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB16_Z(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ +} \ + +_FrameSwizzleBlock(_, src[j], src[j], 0); +_FrameSwizzleBlock(A2_, (src[2*j]+src[2*j+1])>>1, src[2*j], 0); +_FrameSwizzleBlock(A4_, (src[2*j]+src[2*j+1]+src[2*j+srcpitch]+src[2*j+srcpitch+1])>>2, src[2*j], 1); + +#ifdef ZEROGS_SSE2 + +//void FASTCALL(WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32* clut) +//{ +// __asm { +// mov eax, vm +// mov ecx, clut +// mov edx, 8 +// } +// +//Extract32x2: +// __asm { +// movdqa xmm0, qword ptr [eax] +// movdqa xmm1, qword ptr [eax+16] +// movdqa xmm2, qword ptr [eax+32] +// movdqa xmm3, qword ptr [eax+48] +// +// // rearrange +// pshuflw xmm0, xmm0, 0xd8 +// pshufhw xmm0, xmm0, 0xd8 +// pshuflw xmm1, xmm1, 0xd8 +// pshufhw xmm1, xmm1, 0xd8 +// pshuflw xmm2, xmm2, 0xd8 +// pshufhw xmm2, xmm2, 0xd8 +// pshuflw xmm3, xmm3, 0xd8 +// pshufhw xmm3, xmm3, 0xd8 +// +// movdqa xmm4, xmm0 +// movdqa xmm6, xmm2 +// +// shufps xmm0, xmm1, 0x88 +// shufps xmm2, xmm3, 0x88 +// +// shufps xmm4, xmm1, 0xdd +// shufps xmm6, xmm3, 0xdd +// +// pshufd xmm0, xmm0, 0xd8 +// pshufd xmm2, xmm2, 0xd8 +// pshufd xmm4, xmm4, 0xd8 +// pshufd xmm6, xmm6, 0xd8 +// +// // left column +// movhlps xmm1, xmm0 +// movlhps xmm0, xmm2 +// //movdqa xmm7, [ecx] +// +// movdqa [ecx], xmm0 +// shufps xmm1, xmm2, 0xe4 +// movdqa [ecx+16], xmm1 +// +// // right column +// movhlps xmm3, xmm4 +// movlhps xmm4, xmm6 +// movdqa [ecx+32], xmm4 +// shufps xmm3, xmm6, 0xe4 +// movdqa [ecx+48], xmm3 +// +// add eax, 16*4 +// add ecx, 16*8 +// sub edx, 1 +// cmp edx, 0 +// jne Extract32x2 +// } +//} + +#if (defined(_WIN32)||defined(__x86_64__)) + +extern "C" void FASTCALL(WriteCLUT_T32_I8_CSM1_sse2(u32* vm, u32* clut)) +{ + __m128i* src = (__m128i*)vm; + __m128i* dst = (__m128i*)clut; + + for(int j = 0; j < 64; j += 32, src += 32, dst += 32) + { + for(int i = 0; i < 16; i += 4) + { + __m128i r0 = _mm_load_si128(&src[i+0]); + __m128i r1 = _mm_load_si128(&src[i+1]); + __m128i r2 = _mm_load_si128(&src[i+2]); + __m128i r3 = _mm_load_si128(&src[i+3]); + + _mm_store_si128(&dst[i*2+0], _mm_unpacklo_epi64(r0, r1)); + _mm_store_si128(&dst[i*2+1], _mm_unpacklo_epi64(r2, r3)); + _mm_store_si128(&dst[i*2+2], _mm_unpackhi_epi64(r0, r1)); + _mm_store_si128(&dst[i*2+3], _mm_unpackhi_epi64(r2, r3)); + + __m128i r4 = _mm_load_si128(&src[i+0+16]); + __m128i r5 = _mm_load_si128(&src[i+1+16]); + __m128i r6 = _mm_load_si128(&src[i+2+16]); + __m128i r7 = _mm_load_si128(&src[i+3+16]); + + _mm_store_si128(&dst[i*2+4], _mm_unpacklo_epi64(r4, r5)); + _mm_store_si128(&dst[i*2+5], _mm_unpacklo_epi64(r6, r7)); + _mm_store_si128(&dst[i*2+6], _mm_unpackhi_epi64(r4, r5)); + _mm_store_si128(&dst[i*2+7], _mm_unpackhi_epi64(r6, r7)); + } + } +} + +extern "C" void FASTCALL(WriteCLUT_T32_I4_CSM1_sse2(u32* vm, u32* clut)) +{ + __m128i* src = (__m128i*)vm; + __m128i* dst = (__m128i*)clut; + + __m128i r0 = _mm_load_si128(&src[0]); + __m128i r1 = _mm_load_si128(&src[1]); + __m128i r2 = _mm_load_si128(&src[2]); + __m128i r3 = _mm_load_si128(&src[3]); + + _mm_store_si128(&dst[0], _mm_unpacklo_epi64(r0, r1)); + _mm_store_si128(&dst[1], _mm_unpacklo_epi64(r2, r3)); + _mm_store_si128(&dst[2], _mm_unpackhi_epi64(r0, r1)); + _mm_store_si128(&dst[3], _mm_unpackhi_epi64(r2, r3)); +} +#endif + +#if defined(_MSC_VER) + +extern "C" { +PCSX2_ALIGNED16(int s_clut16mask2[4]) = { 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff }; +PCSX2_ALIGNED16(int s_clut16mask[8]) = { 0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000, + 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff}; +} + +#if !defined(__x86_64__) + +extern "C" void FASTCALL(WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut)) +{ + __asm { + mov eax, vm + mov ecx, clut + movdqa xmm0, qword ptr [eax] + movdqa xmm1, qword ptr [eax+16] + movdqa xmm2, qword ptr [eax+32] + movdqa xmm3, qword ptr [eax+48] + + // rearrange + pshuflw xmm0, xmm0, 0x88 + pshufhw xmm0, xmm0, 0x88 + pshuflw xmm1, xmm1, 0x88 + pshufhw xmm1, xmm1, 0x88 + pshuflw xmm2, xmm2, 0x88 + pshufhw xmm2, xmm2, 0x88 + pshuflw xmm3, xmm3, 0x88 + pshufhw xmm3, xmm3, 0x88 + + shufps xmm0, xmm1, 0x88 + shufps xmm2, xmm3, 0x88 + + pshufd xmm0, xmm0, 0xd8 + pshufd xmm2, xmm2, 0xd8 + + pxor xmm6, xmm6 + + test ecx, 15 + jnz WriteUnaligned + + movdqa xmm7, s_clut16mask // saves upper 16 bits + + // have to save interlaced with the old data + movdqa xmm4, [ecx] + movdqa xmm5, [ecx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 // lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0xe4 // upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + + movdqa [ecx], xmm0 + movdqa [ecx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [ecx+16] + pand xmm5, [ecx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [ecx+16], xmm2 + movdqa [ecx+48], xmm3 + jmp End + +WriteUnaligned: + // ecx is offset by 2 + sub ecx, 2 + + movdqa xmm7, s_clut16mask2 // saves lower 16 bits + + // have to save interlaced with the old data + movdqa xmm4, [ecx] + movdqa xmm5, [ecx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 // lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0xe4 // upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + pslld xmm0, 16 + pslld xmm1, 16 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + pslld xmm2, 16 + pslld xmm3, 16 + + movdqa [ecx], xmm0 + movdqa [ecx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [ecx+16] + pand xmm5, [ecx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [ecx+16], xmm2 + movdqa [ecx+48], xmm3 +End: + } +} +#endif // __x86_64__ +#endif // _MSC_VER + +#endif // ZEROGS_SSE2 + +void FASTCALL(WriteCLUT_T16_I8_CSM1_c(u32* _vm, u32* _clut)) +{ + const static u32 map[] = + { + 0, 2, 8, 10, 16, 18, 24, 26, + 4, 6, 12, 14, 20, 22, 28, 30, + 1, 3, 9, 11, 17, 19, 25, 27, + 5, 7, 13, 15, 21, 23, 29, 31 + }; + + u16* vm = (u16*)_vm; + u16* clut = (u16*)_clut; + + int left = ((u32)(uptr)clut&2) ? 512 : 512-(((u32)(uptr)clut)&0x3ff)/2; + + for(int j = 0; j < 8; j++, vm += 32, clut += 64, left -= 32) + { + if(left == 32) { + assert( left == 32 ); + for(int i = 0; i < 16; i++) + clut[2*i] = vm[map[i]]; + + clut = (u16*)((uptr)clut & ~0x3ff) + 1; + + for(int i = 16; i < 32; i++) + clut[2*i] = vm[map[i]]; + } + else { + if( left == 0 ) { + clut = (u16*)((uptr)clut & ~0x3ff) + 1; + left = -1; + } + + for(int i = 0; i < 32; i++) + clut[2*i] = vm[map[i]]; + } + } +} + +void FASTCALL(WriteCLUT_T32_I8_CSM1_c(u32* vm, u32* clut)) +{ + u64* src = (u64*)vm; + u64* dst = (u64*)clut; + + for(int j = 0; j < 2; j++, src += 32) { + for(int i = 0; i < 4; i++, dst+=16, src+=8) + { + dst[0] = src[0]; + dst[1] = src[2]; + dst[2] = src[4]; + dst[3] = src[6]; + dst[4] = src[1]; + dst[5] = src[3]; + dst[6] = src[5]; + dst[7] = src[7]; + + dst[8] = src[32]; + dst[9] = src[32+2]; + dst[10] = src[32+4]; + dst[11] = src[32+6]; + dst[12] = src[32+1]; + dst[13] = src[32+3]; + dst[14] = src[32+5]; + dst[15] = src[32+7]; + } + } +} + +void FASTCALL(WriteCLUT_T16_I4_CSM1_c(u32* _vm, u32* _clut)) +{ + u16* dst = (u16*)_clut; + u16* src = (u16*)_vm; + + dst[0] = src[0]; dst[2] = src[2]; + dst[4] = src[8]; dst[6] = src[10]; + dst[8] = src[16]; dst[10] = src[18]; + dst[12] = src[24]; dst[14] = src[26]; + dst[16] = src[4]; dst[18] = src[6]; + dst[20] = src[12]; dst[22] = src[14]; + dst[24] = src[20]; dst[26] = src[22]; + dst[28] = src[28]; dst[30] = src[30]; +} + +void FASTCALL(WriteCLUT_T32_I4_CSM1_c(u32* vm, u32* clut)) +{ + u64* src = (u64*)vm; + u64* dst = (u64*)clut; + + dst[0] = src[0]; + dst[1] = src[2]; + dst[2] = src[4]; + dst[3] = src[6]; + dst[4] = src[1]; + dst[5] = src[3]; + dst[6] = src[5]; + dst[7] = src[7]; +} diff --git a/plugins/zerogs/dx/x86.h b/plugins/zerogs/dx/x86.h index 6859c1a313..2e19e07ba1 100644 --- a/plugins/zerogs/dx/x86.h +++ b/plugins/zerogs/dx/x86.h @@ -1,184 +1,184 @@ -/* ZeroGS KOSMOS - * Copyright (C) 2005-2006 Gabest/zerofrog@gmail.com - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#ifndef ZEROGS_X86 -#define ZEROGS_X86 - -#include -#include -#include "GS.h" - -extern "C" void FASTCALL(SwizzleBlock32_sse2(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); -extern "C" void FASTCALL(SwizzleBlock16_sse2(u8* dst, u8* src, int srcpitch)); -extern "C" void FASTCALL(SwizzleBlock8_sse2(u8* dst, u8* src, int srcpitch)); -extern "C" void FASTCALL(SwizzleBlock4_sse2(u8* dst, u8* src, int srcpitch)); -extern "C" void FASTCALL(SwizzleBlock32u_sse2(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); -extern "C" void FASTCALL(SwizzleBlock16u_sse2(u8* dst, u8* src, int srcpitch)); -extern "C" void FASTCALL(SwizzleBlock8u_sse2(u8* dst, u8* src, int srcpitch)); -extern "C" void FASTCALL(SwizzleBlock4u_sse2(u8* dst, u8* src, int srcpitch)); - -// frame swizzling - -// no AA -extern "C" void FASTCALL(FrameSwizzleBlock32_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask)); -extern "C" void FASTCALL(FrameSwizzleBlock16_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask)); -extern "C" void FASTCALL(Frame16SwizzleBlock32_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); -extern "C" void FASTCALL(Frame16SwizzleBlock32Z_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); -extern "C" void FASTCALL(Frame16SwizzleBlock16_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); -extern "C" void FASTCALL(Frame16SwizzleBlock16Z_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); - -// AA 2x -extern "C" void FASTCALL(FrameSwizzleBlock32A2_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask)); -extern "C" void FASTCALL(FrameSwizzleBlock16A2_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask)); -extern "C" void FASTCALL(Frame16SwizzleBlock32A2_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); -extern "C" void FASTCALL(Frame16SwizzleBlock32ZA2_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); -extern "C" void FASTCALL(Frame16SwizzleBlock16A2_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); -extern "C" void FASTCALL(Frame16SwizzleBlock16ZA2_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); - -// AA 4x -extern "C" void FASTCALL(FrameSwizzleBlock32A4_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask)); -extern "C" void FASTCALL(FrameSwizzleBlock16A4_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask)); -extern "C" void FASTCALL(Frame16SwizzleBlock32A4_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); -extern "C" void FASTCALL(Frame16SwizzleBlock32ZA4_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); -extern "C" void FASTCALL(Frame16SwizzleBlock16A4_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); -extern "C" void FASTCALL(Frame16SwizzleBlock16ZA4_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); - -extern void FASTCALL(SwizzleBlock32_c(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); -extern void FASTCALL(SwizzleBlock16_c(u8* dst, u8* src, int srcpitch)); -extern void FASTCALL(SwizzleBlock8_c(u8* dst, u8* src, int srcpitch)); -extern void FASTCALL(SwizzleBlock4_c(u8* dst, u8* src, int srcpitch)); - -// no AA -extern void FASTCALL(FrameSwizzleBlock32_c(u32* dst, u32* src, int srcpitch, u32 WriteMask)); -extern void FASTCALL(FrameSwizzleBlock16_c(u16* dst, u32* src, int srcpitch, u32 WriteMask)); -extern void FASTCALL(Frame16SwizzleBlock32_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); -extern void FASTCALL(Frame16SwizzleBlock32Z_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); -extern void FASTCALL(Frame16SwizzleBlock16_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); -extern void FASTCALL(Frame16SwizzleBlock16Z_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); - -// AA 2x -extern void FASTCALL(FrameSwizzleBlock32A2_c(u32* dst, u32* src, int srcpitch, u32 WriteMask)); -extern void FASTCALL(FrameSwizzleBlock16A2_c(u16* dst, u32* src, int srcpitch, u32 WriteMask)); -extern void FASTCALL(Frame16SwizzleBlock32A2_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); -extern void FASTCALL(Frame16SwizzleBlock32ZA2_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); -extern void FASTCALL(Frame16SwizzleBlock16A2_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); -extern void FASTCALL(Frame16SwizzleBlock16ZA2_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); - -// AA 4x -extern void FASTCALL(FrameSwizzleBlock32A4_c(u32* dst, u32* src, int srcpitch, u32 WriteMask)); -extern void FASTCALL(FrameSwizzleBlock16A4_c(u16* dst, u32* src, int srcpitch, u32 WriteMask)); -extern void FASTCALL(Frame16SwizzleBlock32A4_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); -extern void FASTCALL(Frame16SwizzleBlock32ZA4_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); -extern void FASTCALL(Frame16SwizzleBlock16A4_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); -extern void FASTCALL(Frame16SwizzleBlock16ZA4_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); - -extern void FASTCALL(SwizzleColumn32_c(int y, u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); -extern void FASTCALL(SwizzleColumn16_c(int y, u8* dst, u8* src, int srcpitch)); -extern void FASTCALL(SwizzleColumn8_c(int y, u8* dst, u8* src, int srcpitch)); -extern void FASTCALL(SwizzleColumn4_c(int y, u8* dst, u8* src, int srcpitch)); - -extern "C" void FASTCALL(WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32* clut)); -extern "C" void FASTCALL(WriteCLUT_T32_I8_CSM1_sse2(u32* vm, u32* clut)); -extern "C" void FASTCALL(WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut)); -extern "C" void FASTCALL(WriteCLUT_T32_I4_CSM1_sse2(u32* vm, u32* clut)); -extern void FASTCALL(WriteCLUT_T16_I8_CSM1_c(u32* vm, u32* clut)); -extern void FASTCALL(WriteCLUT_T32_I8_CSM1_c(u32* vm, u32* clut)); - -extern void FASTCALL(WriteCLUT_T16_I4_CSM1_c(u32* vm, u32* clut)); -extern void FASTCALL(WriteCLUT_T32_I4_CSM1_c(u32* vm, u32* clut)); - -#ifdef ZEROGS_SSE2 - -#define SwizzleBlock32 SwizzleBlock32_sse2 -#define SwizzleBlock16 SwizzleBlock16_sse2 -#define SwizzleBlock8 SwizzleBlock8_sse2 -#define SwizzleBlock4 SwizzleBlock4_sse2 -#define SwizzleBlock32u SwizzleBlock32u_sse2 -#define SwizzleBlock16u SwizzleBlock16u_sse2 -#define SwizzleBlock8u SwizzleBlock8u_sse2 -#define SwizzleBlock4u SwizzleBlock4u_sse2 - -#define FrameSwizzleBlock32 FrameSwizzleBlock32_c -#define FrameSwizzleBlock16 FrameSwizzleBlock16_c -#define Frame16SwizzleBlock32 Frame16SwizzleBlock32_c -#define Frame16SwizzleBlock32Z Frame16SwizzleBlock32Z_c -#define Frame16SwizzleBlock16 Frame16SwizzleBlock16_c -#define Frame16SwizzleBlock16Z Frame16SwizzleBlock16Z_c - -#define FrameSwizzleBlock32A2 FrameSwizzleBlock32A2_c -#define FrameSwizzleBlock16A2 FrameSwizzleBlock16A2_c -#define Frame16SwizzleBlock32A2 Frame16SwizzleBlock32A2_c -#define Frame16SwizzleBlock32ZA2 Frame16SwizzleBlock32ZA2_c -#define Frame16SwizzleBlock16A2 Frame16SwizzleBlock16A2_c -#define Frame16SwizzleBlock16ZA2 Frame16SwizzleBlock16ZA2_c - -#define FrameSwizzleBlock32A4 FrameSwizzleBlock32A4_c -#define FrameSwizzleBlock16A4 FrameSwizzleBlock16A4_c -#define Frame16SwizzleBlock32A4 Frame16SwizzleBlock32A4_c -#define Frame16SwizzleBlock32ZA4 Frame16SwizzleBlock32ZA4_c -#define Frame16SwizzleBlock16A4 Frame16SwizzleBlock16A4_c -#define Frame16SwizzleBlock16ZA4 Frame16SwizzleBlock16ZA4_c - -#define WriteCLUT_T16_I8_CSM1 WriteCLUT_T16_I8_CSM1_sse2 -#define WriteCLUT_T32_I8_CSM1 WriteCLUT_T32_I8_CSM1_sse2 -#define WriteCLUT_T16_I4_CSM1 WriteCLUT_T16_I4_CSM1_sse2 -#define WriteCLUT_T32_I4_CSM1 WriteCLUT_T32_I4_CSM1_sse2 - -#else - -#define SwizzleBlock32 SwizzleBlock32_c -#define SwizzleBlock16 SwizzleBlock16_c -#define SwizzleBlock8 SwizzleBlock8_c -#define SwizzleBlock4 SwizzleBlock4_c -#define SwizzleBlock32u SwizzleBlock32_c -#define SwizzleBlock16u SwizzleBlock16_c -#define SwizzleBlock8u SwizzleBlock8_c -#define SwizzleBlock4u SwizzleBlock4_c - -#define FrameSwizzleBlock32 FrameSwizzleBlock32_c -#define FrameSwizzleBlock16 FrameSwizzleBlock16_c -#define Frame16SwizzleBlock32 Frame16SwizzleBlock32_c -#define Frame16SwizzleBlock32Z Frame16SwizzleBlock32Z_c -#define Frame16SwizzleBlock16 Frame16SwizzleBlock16_c -#define Frame16SwizzleBlock16Z Frame16SwizzleBlock16Z_c - -#define FrameSwizzleBlock32A2 FrameSwizzleBlock32A2_c -#define FrameSwizzleBlock16A2 FrameSwizzleBlock16A2_c -#define Frame16SwizzleBlock32A2 Frame16SwizzleBlock32A2_c -#define Frame16SwizzleBlock32ZA2 Frame16SwizzleBlock32ZA2_c -#define Frame16SwizzleBlock16A2 Frame16SwizzleBlock16A2_c -#define Frame16SwizzleBlock16ZA2 Frame16SwizzleBlock16ZA2_c - -#define FrameSwizzleBlock32A4 FrameSwizzleBlock32A4_c -#define FrameSwizzleBlock16A4 FrameSwizzleBlock16A4_c -#define Frame16SwizzleBlock32A4 Frame16SwizzleBlock32A4_c -#define Frame16SwizzleBlock32ZA4 Frame16SwizzleBlock32ZA4_c -#define Frame16SwizzleBlock16A4 Frame16SwizzleBlock16A4_c -#define Frame16SwizzleBlock16ZA4 Frame16SwizzleBlock16ZA4_c - -#define WriteCLUT_T16_I8_CSM1 WriteCLUT_T16_I8_CSM1_c -#define WriteCLUT_T32_I8_CSM1 WriteCLUT_T32_I8_CSM1_c -#define WriteCLUT_T16_I4_CSM1 WriteCLUT_T16_I4_CSM1_c -#define WriteCLUT_T32_I4_CSM1 WriteCLUT_T32_I4_CSM1_c - -#endif - -#endif +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 Gabest/zerofrog@gmail.com + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#ifndef ZEROGS_X86 +#define ZEROGS_X86 + +#include +#include +#include "GS.h" + +extern "C" void FASTCALL(SwizzleBlock32_sse2(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); +extern "C" void FASTCALL(SwizzleBlock16_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock8_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock4_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock32u_sse2(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); +extern "C" void FASTCALL(SwizzleBlock16u_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock8u_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock4u_sse2(u8* dst, u8* src, int srcpitch)); + +// frame swizzling + +// no AA +extern "C" void FASTCALL(FrameSwizzleBlock32_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(FrameSwizzleBlock16_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32Z_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16Z_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +// AA 2x +extern "C" void FASTCALL(FrameSwizzleBlock32A2_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(FrameSwizzleBlock16A2_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32A2_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32ZA2_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16A2_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16ZA2_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +// AA 4x +extern "C" void FASTCALL(FrameSwizzleBlock32A4_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(FrameSwizzleBlock16A4_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32A4_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32ZA4_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16A4_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16ZA4_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +extern void FASTCALL(SwizzleBlock32_c(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); +extern void FASTCALL(SwizzleBlock16_c(u8* dst, u8* src, int srcpitch)); +extern void FASTCALL(SwizzleBlock8_c(u8* dst, u8* src, int srcpitch)); +extern void FASTCALL(SwizzleBlock4_c(u8* dst, u8* src, int srcpitch)); + +// no AA +extern void FASTCALL(FrameSwizzleBlock32_c(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(FrameSwizzleBlock16_c(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32Z_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16Z_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +// AA 2x +extern void FASTCALL(FrameSwizzleBlock32A2_c(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(FrameSwizzleBlock16A2_c(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32A2_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32ZA2_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16A2_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16ZA2_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +// AA 4x +extern void FASTCALL(FrameSwizzleBlock32A4_c(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(FrameSwizzleBlock16A4_c(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32A4_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32ZA4_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16A4_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16ZA4_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +extern void FASTCALL(SwizzleColumn32_c(int y, u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); +extern void FASTCALL(SwizzleColumn16_c(int y, u8* dst, u8* src, int srcpitch)); +extern void FASTCALL(SwizzleColumn8_c(int y, u8* dst, u8* src, int srcpitch)); +extern void FASTCALL(SwizzleColumn4_c(int y, u8* dst, u8* src, int srcpitch)); + +extern "C" void FASTCALL(WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32* clut)); +extern "C" void FASTCALL(WriteCLUT_T32_I8_CSM1_sse2(u32* vm, u32* clut)); +extern "C" void FASTCALL(WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut)); +extern "C" void FASTCALL(WriteCLUT_T32_I4_CSM1_sse2(u32* vm, u32* clut)); +extern void FASTCALL(WriteCLUT_T16_I8_CSM1_c(u32* vm, u32* clut)); +extern void FASTCALL(WriteCLUT_T32_I8_CSM1_c(u32* vm, u32* clut)); + +extern void FASTCALL(WriteCLUT_T16_I4_CSM1_c(u32* vm, u32* clut)); +extern void FASTCALL(WriteCLUT_T32_I4_CSM1_c(u32* vm, u32* clut)); + +#ifdef ZEROGS_SSE2 + +#define SwizzleBlock32 SwizzleBlock32_sse2 +#define SwizzleBlock16 SwizzleBlock16_sse2 +#define SwizzleBlock8 SwizzleBlock8_sse2 +#define SwizzleBlock4 SwizzleBlock4_sse2 +#define SwizzleBlock32u SwizzleBlock32u_sse2 +#define SwizzleBlock16u SwizzleBlock16u_sse2 +#define SwizzleBlock8u SwizzleBlock8u_sse2 +#define SwizzleBlock4u SwizzleBlock4u_sse2 + +#define FrameSwizzleBlock32 FrameSwizzleBlock32_c +#define FrameSwizzleBlock16 FrameSwizzleBlock16_c +#define Frame16SwizzleBlock32 Frame16SwizzleBlock32_c +#define Frame16SwizzleBlock32Z Frame16SwizzleBlock32Z_c +#define Frame16SwizzleBlock16 Frame16SwizzleBlock16_c +#define Frame16SwizzleBlock16Z Frame16SwizzleBlock16Z_c + +#define FrameSwizzleBlock32A2 FrameSwizzleBlock32A2_c +#define FrameSwizzleBlock16A2 FrameSwizzleBlock16A2_c +#define Frame16SwizzleBlock32A2 Frame16SwizzleBlock32A2_c +#define Frame16SwizzleBlock32ZA2 Frame16SwizzleBlock32ZA2_c +#define Frame16SwizzleBlock16A2 Frame16SwizzleBlock16A2_c +#define Frame16SwizzleBlock16ZA2 Frame16SwizzleBlock16ZA2_c + +#define FrameSwizzleBlock32A4 FrameSwizzleBlock32A4_c +#define FrameSwizzleBlock16A4 FrameSwizzleBlock16A4_c +#define Frame16SwizzleBlock32A4 Frame16SwizzleBlock32A4_c +#define Frame16SwizzleBlock32ZA4 Frame16SwizzleBlock32ZA4_c +#define Frame16SwizzleBlock16A4 Frame16SwizzleBlock16A4_c +#define Frame16SwizzleBlock16ZA4 Frame16SwizzleBlock16ZA4_c + +#define WriteCLUT_T16_I8_CSM1 WriteCLUT_T16_I8_CSM1_sse2 +#define WriteCLUT_T32_I8_CSM1 WriteCLUT_T32_I8_CSM1_sse2 +#define WriteCLUT_T16_I4_CSM1 WriteCLUT_T16_I4_CSM1_sse2 +#define WriteCLUT_T32_I4_CSM1 WriteCLUT_T32_I4_CSM1_sse2 + +#else + +#define SwizzleBlock32 SwizzleBlock32_c +#define SwizzleBlock16 SwizzleBlock16_c +#define SwizzleBlock8 SwizzleBlock8_c +#define SwizzleBlock4 SwizzleBlock4_c +#define SwizzleBlock32u SwizzleBlock32_c +#define SwizzleBlock16u SwizzleBlock16_c +#define SwizzleBlock8u SwizzleBlock8_c +#define SwizzleBlock4u SwizzleBlock4_c + +#define FrameSwizzleBlock32 FrameSwizzleBlock32_c +#define FrameSwizzleBlock16 FrameSwizzleBlock16_c +#define Frame16SwizzleBlock32 Frame16SwizzleBlock32_c +#define Frame16SwizzleBlock32Z Frame16SwizzleBlock32Z_c +#define Frame16SwizzleBlock16 Frame16SwizzleBlock16_c +#define Frame16SwizzleBlock16Z Frame16SwizzleBlock16Z_c + +#define FrameSwizzleBlock32A2 FrameSwizzleBlock32A2_c +#define FrameSwizzleBlock16A2 FrameSwizzleBlock16A2_c +#define Frame16SwizzleBlock32A2 Frame16SwizzleBlock32A2_c +#define Frame16SwizzleBlock32ZA2 Frame16SwizzleBlock32ZA2_c +#define Frame16SwizzleBlock16A2 Frame16SwizzleBlock16A2_c +#define Frame16SwizzleBlock16ZA2 Frame16SwizzleBlock16ZA2_c + +#define FrameSwizzleBlock32A4 FrameSwizzleBlock32A4_c +#define FrameSwizzleBlock16A4 FrameSwizzleBlock16A4_c +#define Frame16SwizzleBlock32A4 Frame16SwizzleBlock32A4_c +#define Frame16SwizzleBlock32ZA4 Frame16SwizzleBlock32ZA4_c +#define Frame16SwizzleBlock16A4 Frame16SwizzleBlock16A4_c +#define Frame16SwizzleBlock16ZA4 Frame16SwizzleBlock16ZA4_c + +#define WriteCLUT_T16_I8_CSM1 WriteCLUT_T16_I8_CSM1_c +#define WriteCLUT_T32_I8_CSM1 WriteCLUT_T32_I8_CSM1_c +#define WriteCLUT_T16_I4_CSM1 WriteCLUT_T16_I4_CSM1_c +#define WriteCLUT_T32_I4_CSM1 WriteCLUT_T32_I4_CSM1_c + +#endif + +#endif diff --git a/plugins/zerogs/dx/zerogs.cpp b/plugins/zerogs/dx/zerogs.cpp index 22bb7c51e1..a138928da3 100644 --- a/plugins/zerogs/dx/zerogs.cpp +++ b/plugins/zerogs/dx/zerogs.cpp @@ -1,5106 +1,5106 @@ -/* ZeroGS - * Copyright (C) 2005-2006 zerofrog@gmail.com - * - * 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 - */ - -#if defined(_WIN32) || defined(__WIN32__) -#include -#include -#include -#endif - -#include - -#include -#include -#include -#include -#include - -#include "GS.h" -#include "Mem.h" -#include "x86.h" -#include "Regs.h" -#include "zerogs.h" -#include "resource.h" - -#include "zerogsshaders/zerogsshaders.h" -#include "targets.h" - -#define DEBUG_PS2 0 - -#define POINT_BUFFERFLUSH 512 -#define POINT_BUFFERSIZE (1<<18) - -#define MINMAX_SHIFT 3 -#define MAX_ACTIVECLUTS 16 - -#define ZEROGS_SAVEVER 0xaa000005 - -#define STENCIL_ALPHABIT 1 // if set, dest alpha >= 0x80 -#define STENCIL_PIXELWRITE 2 // if set, pixel just written (reset after every Flush) -#define STENCIL_FBA 4 // if set, just written pixel's alpha >= 0 (reset after every Flush) -#define STENCIL_SPECIAL 8 // if set, indicates that pixel passed its alpha test (reset after every Flush) -//#define STENCIL_PBE 16 -#define STENCIL_CLEAR (2|4|8|16) - -#define VBSAVELIMIT ((u32)((u8*)&vb[0].nNextFrameHeight-(u8*)&vb[0])) - -using namespace ZeroGS; - -static LPDIRECT3D9 pD3D = NULL; // Used to create the D3DDevice -LPDIRECT3DDEVICE9 pd3dDevice = NULL; -static DXVEC4 s_vznorm; -extern u32 g_nGenVars, g_nTexVars, g_nAlphaVars, g_nResolve; -extern char *libraryName; -extern int g_nFrame, g_nRealFrame; -extern float fFPS; -extern unsigned char revision, build, minor; - -BOOL g_bDisplayMsg = 1; - -extern HINSTANCE hInst; - -BOOL g_bSaveFlushedFrame = 1; -BOOL g_bIsLost = 0; -int g_nFrameRender = 10; -int g_nFramesSkipped = 0; -int g_MaxRenderedHeight = 0; - -#ifdef RELEASE_TO_PUBLIC - -#define INC_GENVARS() -#define INC_TEXVARS() -#define INC_ALPHAVARS() -#define INC_RESOLVE() - -#define g_bUpdateEffect 0 -#define g_bWriteProfile 0 -#define g_bSaveTex 0 -#define g_bSaveTrans 0 -#define g_bSaveFrame 0 -#define g_bSaveFinalFrame 0 -#define g_bUpdateStencil 1 -#define g_bSaveResolved 0 - -#else - -#define INC_GENVARS() ++g_nGenVars -#define INC_TEXVARS() ++g_nTexVars -#define INC_ALPHAVARS() ++g_nAlphaVars -#define INC_RESOLVE() ++g_nResolve - -BOOL g_bSaveTrans = 0; -BOOL g_bUpdateEffect = 0; -BOOL g_bWriteProfile = 0; -BOOL g_bSaveTex = 0; // saves the curent texture -BOOL g_bSaveFrame = 0; // saves the current psurfTarget -BOOL g_bSaveFinalFrame = 0; // saves the input to the CRTC -BOOL g_bUpdateStencil = 1; // only needed for dest alpha test (unfortunately, it has to be on all the time) -BOOL g_bSaveResolved = 0; - -#endif - -#define DRAW() pd3dDevice->DrawPrimitive(primtype[curvb.curprim.prim], 0, curvb.dwCount) - -extern int s_frameskipping; - -//inline void SetRenderTarget_(int index, LPD3DSURF psurf, int counter, const char* pname) -//{ -// static LPD3DSURF ptargs[4] = {NULL}; -// static int counters[4] = {0}; -// static const char* pnames[4] = {NULL}; -// -// if( ptargs[index] == psurf && psurf != NULL ) -// DEBUG_LOG("duplicate targets\n"); -// pd3dDevice->SetRenderTarget(index, psurf); -// ptargs[index] = psurf; -// counters[index] = counter; -// pnames[index] = pname; -//} -// -//#define SetRenderTarget(index, psurf) SetRenderTarget_(index, psurf, __COUNTER__, __FUNCTION__) - -static u32 g_SaveFrameNum = 0; -BOOL g_bMakeSnapshot = 0; -string strSnapshot; - -int GPU_TEXWIDTH = 512; -float g_fiGPU_TEXWIDTH = 1/512.0f; - -int g_MaxTexWidth = 4096, g_MaxTexHeight = 4096; - -// AVI Capture -static int s_aviinit = 0; -static int s_avicapturing = 0; -static LPD3DSURF s_ptexAVICapture = NULL; // system memory texture - -const u32 g_primmult[8] = { 1, 2, 2, 3, 3, 3, 2, 0xff }; -const u32 g_primsub[8] = { 1, 2, 1, 3, 1, 1, 2, 0 }; - -inline DWORD FtoDW(float f) { return (*((DWORD*)&f)); } - -float g_fBlockMult = 1; -static int s_nFullscreen = 0; -int g_nDepthUpdateCount = 0; -int g_nDepthBias = 0; - -// Consts -static const D3DPRIMITIVETYPE primtype[8] = { D3DPT_POINTLIST, D3DPT_LINELIST, D3DPT_LINELIST, D3DPT_TRIANGLELIST, D3DPT_TRIANGLELIST, D3DPT_TRIANGLELIST, D3DPT_TRIANGLELIST, D3DPT_FORCE_DWORD }; -static const DWORD blendalpha[3] = { D3DBLEND_SRCALPHA, D3DBLEND_DESTALPHA, D3DBLEND_BLENDFACTOR }; -static const DWORD blendinvalpha[3] = { D3DBLEND_INVSRCALPHA, D3DBLEND_INVDESTALPHA, D3DBLEND_INVBLENDFACTOR }; - -static const int PRIMMASK = 0x0e; // for now ignore 0x10 (AA) - -static const DWORD g_dwAlphaCmp[] = { D3DCMP_NEVER, D3DCMP_ALWAYS, D3DCMP_LESS, D3DCMP_LESSEQUAL, - D3DCMP_EQUAL, D3DCMP_GREATEREQUAL, D3DCMP_GREATER, D3DCMP_NOTEQUAL }; - -// used for afail case -static const DWORD g_dwReverseAlphaCmp[] = { D3DCMP_ALWAYS, D3DCMP_NEVER, D3DCMP_GREATEREQUAL, D3DCMP_GREATER, - D3DCMP_NOTEQUAL, D3DCMP_LESS, D3DCMP_LESSEQUAL, D3DCMP_EQUAL }; - -static const DWORD g_dwZCmp[] = { D3DCMP_NEVER, D3DCMP_ALWAYS, D3DCMP_GREATEREQUAL, D3DCMP_GREATER }; - -///////////////////// -// graphics resources -static LPD3DDECL pdecl = NULL; -static LPD3DVS pvs[16] = {NULL}; -static LPD3DPS ppsRegular[4] = {NULL}, ppsTexture[NUM_SHADERS] = {NULL}; -static LPD3DPS ppsCRTC[2] = {NULL}, ppsCRTC24[2] = {NULL}, ppsCRTCTarg[2] = {NULL}; - -int g_nPixelShaderVer = SHADER_30; // default - -static BYTE* s_lpShaderResources = NULL; -static map mapShaderResources; - -LPD3DTEX s_ptexCurSet[2] = {NULL}; - -#define s_bForceTexFlush 1 -static LPD3DTEX s_ptexNextSet[2] = {NULL}; - -static ID3DXFont* pFont = NULL; -static ID3DXSprite* pSprite = NULL; - -static LPD3DSURF psurfOrgTarg = NULL, psurfOrgDepth = NULL; - -LPD3DTEX ptexBlocks = NULL, ptexConv16to32 = NULL; // holds information on block tiling -LPD3DTEX ptexBilinearBlocks = NULL; -IDirect3DVolumeTexture9* ptexConv32to16 = NULL; -static LPD3DTEX s_ptexInterlace = NULL; // holds interlace fields -static int s_nInterlaceTexWidth = 0; // width of texture -static list s_vecTempTextures; // temporary textures, released at the end of every frame - -static BOOL s_bTexFlush = FALSE; -static LPD3DTEX ptexLogo = NULL; -static BOOL s_bWriteDepth = FALSE; -static BOOL s_bDestAlphaTest = FALSE; -static int s_nLastResolveReset = 0; -static int s_nResolveCounts[30] = {0}; // resolve counts for last 30 frames -static int s_nCurResolveIndex = 0; -int s_nResolved = 0; // number of targets resolved this frame -int g_nDepthUsed = 0; // ffx2 pal movies -static int s_nWriteDepthCount = 0; -static int s_nWireframeCount = 0; -static int s_nWriteDestAlphaTest = 0; - -//////////////////// -// State parameters -static float fiRendWidth, fiRendHeight; - -static DWORD dwStencilRef, dwStencilMask; - -static DXVEC4 vAlphaBlendColor; // used for GPU_COLOR - -static BYTE bNeedBlendFactorInAlpha; // set if the output source alpha is different from the real source alpha (only when blend factor > 0x80) -static DWORD s_dwColorWrite = 0xf; // the color write mask of the current target - -BOOL g_bDisplayFPS = FALSE; - -union { - struct { - BYTE _bNeedAlphaColor; // set if vAlphaBlendColor needs to be set - BYTE _b2XAlphaTest; // Only valid when bNeedAlphaColor is set. if 1st bit set set, double all alpha testing values - // otherwise alpha testing needs to be done separately. - BYTE _bDestAlphaColor; // set to 1 if blending with dest color (process only one tri at a time). If 2, dest alpha is always 1. - BYTE _bAlphaClamping; // if first bit is set, do min; if second bit, do max - }; - u32 _bAlphaState; -} g_vars; - -#define bNeedAlphaColor g_vars._bNeedAlphaColor -#define b2XAlphaTest g_vars._b2XAlphaTest -#define bDestAlphaColor g_vars._bDestAlphaColor -#define bAlphaClamping g_vars._bAlphaClamping - -int g_PrevBitwiseTexX = -1, g_PrevBitwiseTexY = -1; // textures stored in SAMP_BITWISEANDX and SAMP_BITWISEANDY - -// stores the buffers for the last RenderCRTC -const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); - -static BOOL s_bAlphaSet = FALSE; -static alphaInfo s_alphaInfo; - -namespace ZeroGS -{ - VB vb[2]; - float fiTexWidth[2], fiTexHeight[2]; // current tex width and height - LONG width, height; - u8* g_pbyGSMemory = NULL; // 4Mb GS system mem - u8* g_pbyGSClut = NULL; - - D3DPRESENT_PARAMETERS d3dpp; - - BYTE s_AAx = 0, s_AAy = 0; // if AAy is set, then AAx has to be set - BYTE bIndepWriteMasks = 1; - BOOL s_bBeginScene = FALSE; - D3DFORMAT g_RenderFormat = D3DFMT_A16B16G16R16F; - int icurctx = -1; - - LPD3DVB pvbRect = NULL; - - DXVEC4 g_vdepth = DXVEC4(65536.0f, 256.0f, 1.0f, 65536.0f*256.0f); - - LPD3DVS pvsBitBlt = NULL, pvsBitBlt30 = NULL; - LPD3DPS ppsBitBlt[2] = {NULL}, ppsBitBltDepth[2] = {NULL}, ppsBitBltDepthTex[2] = {NULL}, ppsOne = NULL; - LPD3DPS ppsBaseTexture = NULL, ppsConvert16to32 = NULL, ppsConvert32to16 = NULL; - - extern CRangeManager s_RangeMngr; // manages overwritten memory - void FlushTransferRanges(const tex0Info* ptex); - - // returns the first and last addresses aligned to a page that cover - void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw); - - HRESULT LoadEffects(); - HRESULT LoadExtraEffects(); - LPD3DPS LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context); - - static int s_nNewWidth = -1, s_nNewHeight = -1; - void ChangeDeviceSize(int nNewWidth, int nNewHeight); - - void ProcessMessages(); - void RenderCustom(float fAlpha); // intro anim - - struct MESSAGE - { - MESSAGE() {} - MESSAGE(const char* p, DWORD dw) { strcpy(str, p); dwTimeStamp = dw; } - char str[255]; - DWORD dwTimeStamp; - }; - - static list listMsgs; - - /////////////////////// - // Method Prototypes // - /////////////////////// - - void AdjustTransToAspect(DXVEC4& v, int dispwidth, int dispheight); - - void KickPoint(); - void KickLine(); - void KickTriangle(); - void KickTriangleFan(); - void KickSprite(); - void KickDummy(); - - inline void SetContextTarget(int context); - - // use to update the d3d state - void SetTexVariables(int context); - void SetAlphaVariables(const alphaInfo& ainfo); - void ResetAlphaVariables(); - - __forceinline void SetAlphaTestInt(pixTest curtest); - - __forceinline void RenderAlphaTest(const VB& curvb); - __forceinline void RenderStencil(const VB& curvb, DWORD dwUsingSpecialTesting); - __forceinline void ProcessStencil(const VB& curvb); - __forceinline void RenderFBA(const VB& curvb); - __forceinline void ProcessFBA(const VB& curvb); - - void ResolveInRange(int start, int end); - - void ExtWrite(); - - inline LPD3DTEX CreateInterlaceTex(int width) { - if( width == s_nInterlaceTexWidth && s_ptexInterlace != NULL ) return s_ptexInterlace; - - SAFE_RELEASE(s_ptexInterlace); - s_nInterlaceTexWidth = width; - - HRESULT hr; - V(pd3dDevice->CreateTexture(width, 1, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &s_ptexInterlace, NULL)); - - D3DLOCKED_RECT lock; - s_ptexInterlace->LockRect(0, &lock, NULL, 0); - for(int i = 0; i < width; ++i) ((u32*)lock.pBits)[i] = (i&1) ? 0xffffffff : 0; - s_ptexInterlace->UnlockRect(0); - - return s_ptexInterlace; - } - - DrawFn drawfn[8] = { KickDummy, KickDummy, KickDummy, KickDummy, - KickDummy, KickDummy, KickDummy, KickDummy }; - -}; // end namespace - -/////////////////// -// Context State // -/////////////////// -ZeroGS::VB::VB() -{ - memset(this, 0, sizeof(VB)); - tex0.tw = 1; - tex0.th = 1; -} - -ZeroGS::VB::~VB() -{ - Destroy(); -} - -void ZeroGS::VB::Destroy() -{ - Unlock(); - SAFE_RELEASE(pvb); - - prndr = NULL; - pdepth = NULL; -} - -void ZeroGS::VB::Lock() -{ - assert(pvb != NULL); - if( pbuf == NULL ) - { - if( dwCurOff+POINT_BUFFERFLUSH > POINT_BUFFERSIZE ) dwCurOff = 0; - - pvb->Lock(dwCurOff*sizeof(VertexGPU), sizeof(VertexGPU)*POINT_BUFFERFLUSH, (void**)&pbuf, dwCurOff ? D3DLOCK_NOOVERWRITE|D3DLOCK_NOSYSLOCK : D3DLOCK_DISCARD|D3DLOCK_NOSYSLOCK); - dwCount = 0; - assert( pbuf != NULL ); - } -} - -bool ZeroGS::VB::CheckPrim() -{ - Lock(); - - if( (PRIMMASK & prim->_val) != (PRIMMASK & curprim._val) || primtype[prim->prim] != primtype[curprim.prim] ) - return dwCount > 0; - - return false; -} - -// upper bound on max possible height -#define GET_MAXHEIGHT(fbp, fbw, psm) ((((0x00100000-64*(fbp))/(fbw))&~0x1f)<<((psm&2)?1:0)) - -#include -static int maxmin = 608; -//static set s_setFBP[2]; // previous frame/zbuf pointers for the last 2 frames -//static int s_nCurFBPSet = 0; -//static map s_mapFrameHeights[2]; -//static int s_nCurFrameMap = 0; - -// a lot of times, target is too big and overwrites the texture using, if tbp != 0, use it to bound -void ZeroGS::VB::CheckFrame(int tbp) -{ - static int bChanged; - - if( bNeedZCheck ) { - PRIM_LOG("zbuf_%d: zbp=0x%x psm=0x%x, zmsk=%d\n", ictx, zbuf.zbp, zbuf.psm, zbuf.zmsk); - //zbuf = *zb; - } - - // invalid bpp - if( m_Blocks[gsfb.psm].bpp == 0 ) { - ERROR_LOG("CheckFrame invalid bpp %d\n", gsfb.psm); - return; - } - - bChanged = 0; - - if( gsfb.fbw <= 0 ) { - return; - } - - if( bNeedFrameCheck ) { - - int maxpos = 0x00100000; - - // important to set before calling GetTarg - bNeedFrameCheck = 0; - bNeedZCheck = 0; - - // add constraints of other targets - if( gsfb.fbw > 0 ) { - maxpos = 0x00100000-64*gsfb.fbp; - - // make sure texture is far away from tbp - if( gsfb.fbp < tbp && gsfb.fbp + 0x2000 < tbp) { - maxpos = min(64*(tbp-gsfb.fbp), maxpos); - } - if( prndr != NULL ) { - // offroad uses 0x80 fbp which messes up targets - if( gsfb.fbp + 0x80 < frame.fbp ) { - // special case when double buffering (hamsterball) - maxpos = min(64*(frame.fbp-gsfb.fbp), maxpos); - } - } - if( zbuf.zbp < tbp && !zbuf.zmsk ) { - maxpos = min((tbp-zbuf.zbp)*((zbuf.psm&2)?128:64), maxpos); - } - - // old caching method - if( gsfb.fbp < zbuf.zbp && !zbuf.zmsk ) { // zmsk necessary for KH movie - int temp = 64*(zbuf.zbp-gsfb.fbp);//min( (0x00100000-64*zbuf.zbp) , 64*(zbuf.zbp-gsfb.fbp) ); - maxpos = min(temp, maxpos); - } - - maxpos /= gsfb.fbw; - if( gsfb.psm & 2 ) - maxpos *= 2; - - maxpos = min(gsfb.fbh, maxpos); - maxpos = min(maxmin, maxpos); - //? atelier iris crashes without it - if( maxpos > 256 ) - maxpos &= ~0x1f; - } - else { - ERROR_LOG("render target null, ignoring\n"); - //prndr = NULL; - //pdepth = NULL; - return; - } - - gsfb.psm &= 0xf; // shadow tower - - if( prndr != NULL ) { - - // render target - if( prndr->psm != gsfb.psm ) { - // behavior for dest alpha varies - ResetAlphaVariables(); - } - } - - int fbh = (scissor.y1>>MINMAX_SHIFT)+1; - if( fbh > 2 && (fbh&1) ) fbh -= 1; - - if( !(gsfb.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) { - fbh = min(fbh, maxpos); - } - - frame = gsfb; - if (frame.fbw > 1024) frame.fbw = 1024; - -// if( fbh > 256 && (fbh % m_Blocks[gsfb.psm].height) <= 2 ) { -// // dragon ball z -// fbh -= fbh%m_Blocks[gsfb.psm].height; -// } - if( !(frame.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) - frame.fbh = fbh; - - if( !(frame.psm&2) ) {//|| !(g_GameSettings&GAME_FULL16BITRES) ) { - if( frame.fbh >= 512 ) { - // neopets hack - maxmin = min(maxmin, frame.fbh); - frame.fbh = maxmin; - } - } - - // mgs3 hack to get proper resolution, targets after 0x2000 are usually feedback - if( g_MaxRenderedHeight >= 0xe0 && frame.fbp >= 0x2000 ) { - int considerheight = (g_MaxRenderedHeight/8+31)&~31; - if( frame.fbh > considerheight ) - frame.fbh = considerheight; - else if( frame.fbh <= 32 ) - frame.fbh = considerheight; - - if( frame.fbh == considerheight ) { - // stops bad resolves (mgs3) - if( !curprim.abe && (!test.ate || test.atst == 0) ) - s_nResolved |= 0x100; - } - } - - // ffxii hack to stop resolving - if( !(frame.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) { - if( frame.fbp >= 0x3000 && fbh >= 0x1a0 ) { - int endfbp = frame.fbp + frame.fbw*fbh/((gsfb.psm&2)?128:64); - - // see if there is a previous render target in the way, reduce - for(CRenderTargetMngr::MAPTARGETS::iterator itnew = s_RTs.mapTargets.begin(); itnew != s_RTs.mapTargets.end(); ++itnew) { - if( itnew->second->fbp > frame.fbp && endfbp > itnew->second->fbp ) { - endfbp = itnew->second->fbp; - } - } - - frame.fbh = (endfbp-frame.fbp)*((gsfb.psm&2)?128:64)/frame.fbw; - } - } - - CRenderTarget* pprevrndr = prndr; - CDepthTarget* pprevdepth = pdepth; - - // reset so that Resolve doesn't call Flush - prndr = NULL; - pdepth = NULL; - - CRenderTarget* pnewtarg = s_RTs.GetTarg(frame, 0, maxmin); - assert( pnewtarg != NULL ); - - // pnewtarg->fbh >= 0x1c0 needed for ffx - if( pnewtarg->fbh >= 0x1c0 && pnewtarg->fbh > frame.fbh && zbuf.zbp < tbp && !zbuf.zmsk ) { - // check if zbuf is in the way of the texture (suikoden5) - int maxallowedfbh = (tbp-zbuf.zbp)*((zbuf.psm&2)?128:64) / gsfb.fbw; - if( gsfb.psm & 2 ) - maxallowedfbh *= 2; - - if( pnewtarg->fbh > maxallowedfbh+32 ) { // +32 needed for ffx2 - // destroy and recreate - s_RTs.DestroyAll(0, 0x100, pnewtarg->fbw); - pnewtarg = s_RTs.GetTarg(frame, 0, maxmin); - assert( pnewtarg != NULL ); - } - } - - PRIM_LOG("frame_%d: fbp=0x%x fbw=%d fbh=%d(%d) psm=0x%x fbm=0x%x\n", ictx, gsfb.fbp, gsfb.fbw, gsfb.fbh, pnewtarg->fbh, gsfb.psm, gsfb.fbm); - - if( (pprevrndr != pnewtarg) || (prndr != NULL && (prndr->status & CRenderTarget::TS_NeedUpdate)) ) - bChanged = 1; - - prndr = pnewtarg; - - // update z - frameInfo tempfb; - tempfb.fbw = prndr->fbw; - tempfb.fbp = zbuf.zbp; - tempfb.psm = zbuf.psm; - tempfb.fbh = prndr->targheight; - if( zbuf.psm == 0x31 ) tempfb.fbm = 0xff000000; - else tempfb.fbm = 0; - - // check if there is a target that exactly aligns with zbuf (zbuf can be cleared this way, gunbird 2) - //u32 key = zbuf.zbp|(frame.fbw<<16); - //CRenderTargetMngr::MAPTARGETS::iterator it = s_RTs.mapTargets.find(key); -// if( it != s_RTs.mapTargets.end() ) { -//#ifdef _DEBUG -// DEBUG_LOG("zbuf resolve\n"); -//#endif -// if( it->second->status & CRenderTarget::TS_Resolved ) -// it->second->Resolve(); -// } - - CDepthTarget* pnewdepth = (CDepthTarget*)s_DepthRTs.GetTarg(tempfb, CRenderTargetMngr::TO_DepthBuffer | - CRenderTargetMngr::TO_StrictHeight|(zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), - prndr->targheight);//GET_MAXHEIGHT(zbuf.zbp, gsfb.fbw, 0)); - assert( pnewdepth != NULL && prndr != NULL ); - assert( pnewdepth->fbh == prndr->targheight ); - - if( (pprevdepth != pnewdepth) || (pdepth != NULL && (pdepth->status & CRenderTarget::TS_NeedUpdate)) ) - bChanged |= 2; - - pdepth = pnewdepth; - - if( prndr->status & CRenderTarget::TS_NeedConvert32) { - if( pdepth->pdepth != NULL ) - pd3dDevice->SetDepthStencilSurface(pdepth->pdepth); - prndr->fbh *= 2; - prndr->targheight *= 2; - prndr->ConvertTo32(); - prndr->status &= ~CRenderTarget::TS_NeedConvert32; - } - else if( prndr->status & CRenderTarget::TS_NeedConvert16 ) { - if( pdepth->pdepth != NULL ) - pd3dDevice->SetDepthStencilSurface(pdepth->pdepth); - prndr->fbh /= 2; - prndr->targheight /= 2; - prndr->ConvertTo16(); - prndr->status &= ~CRenderTarget::TS_NeedConvert16; - } - } - else if( bNeedZCheck ) { - - bNeedZCheck = 0; - CDepthTarget* pprevdepth = pdepth; - pdepth = NULL; - - if( prndr != NULL && gsfb.fbw > 0 ) { - // just z changed - frameInfo f; - f.fbp = zbuf.zbp; - f.fbw = prndr->fbw; - f.fbh = prndr->fbh; - f.psm = zbuf.psm; - - if( zbuf.psm == 0x31 ) f.fbm = 0xff000000; - else f.fbm = 0; - CDepthTarget* pnewdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| - (zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), prndr->fbh);//GET_MAXHEIGHT(zbuf.zbp, gsfb.fbw, 0)); - - assert( pnewdepth != NULL && prndr != NULL ); - assert( pnewdepth->fbh == prndr->fbh ); - - if( (pprevdepth != pnewdepth) || (pdepth != NULL && (pdepth->status & CRenderTarget::TS_NeedUpdate)) ) - bChanged = 2; - - pdepth = pnewdepth; - } - } - - s_nResolved &= 0xff; // restore - - if( prndr != NULL ) - SetContextTarget(ictx); - - //if( prndr != NULL && ictx == icurctx) - //else bVarsSetTarg = 0; - -// if( prndr != NULL && bChanged ) { -// if( ictx == icurctx ) SetContextTarget(icurctx); -// else -// bVarsSetTarg = 0; -// } -} - -void ZeroGS::VB::FlushTexData() -{ - assert( bNeedTexCheck ); - - bNeedTexCheck = 0; - - u32 psm = (uNextTex0Data[0] >> 20) & 0x3f; - if( psm == 9 ) psm = 1; // hmm..., ffx intro menu - - // don't update unless necessary - if( uCurTex0Data[0] == uNextTex0Data[0] && (uCurTex0Data[1]&0x1f) == (uNextTex0Data[1]&0x1f) ) { - - if( PSMT_ISCLUT(psm) ) { - - // have to write the CLUT again if changed - if( (uCurTex0Data[1]&0x1fffffe0) == (uNextTex0Data[1]&0x1fffffe0) ) { - - if( uNextTex0Data[1]&0xe0000000 ) { - //ZeroGS::Flush(ictx); - ZeroGS::texClutWrite(ictx); - // invalidate to make sure target didn't change! - bVarsTexSync = FALSE; - } - - return; - } - - if( (uNextTex0Data[1]&0xe0000000) == 0 ) { - - if( (uCurTex0Data[1]&0x1ff10000) != (uNextTex0Data[1]&0x1ff10000) ) - ZeroGS::Flush(ictx); - - // clut isn't going to be loaded so can ignore, but at least update CSA and CPSM! - uCurTex0Data[1] = (uCurTex0Data[1]&0xe087ffff)|(uNextTex0Data[1]&0x1f780000); - - if( tex0.cpsm <= 1 ) tex0.csa = (uNextTex0Data[1] >> 24) & 0xf; - else tex0.csa = (uNextTex0Data[1] >> 24) & 0x1f; - - tex0.cpsm = (uNextTex0Data[1] >> 19) & 0xe; - ZeroGS::texClutWrite(ictx); - - bVarsTexSync = FALSE; - return; - } - - // fall through - } - else { - //bVarsTexSync = FALSE; - return; - } - } - - ZeroGS::Flush(ictx); - bVarsTexSync = FALSE; - bTexConstsSync = FALSE; - - uCurTex0Data[0] = uNextTex0Data[0]; - uCurTex0Data[1] = uNextTex0Data[1]; - - tex0.tbp0 = (uNextTex0Data[0] & 0x3fff); - tex0.tbw = ((uNextTex0Data[0] >> 14) & 0x3f) * 64; - tex0.psm = psm; - tex0.tw = (uNextTex0Data[0] >> 26) & 0xf; - if (tex0.tw > 10) tex0.tw = 10; - tex0.tw = 1<> 30) & 0x3) | ((uNextTex0Data[1] & 0x3) << 2); - if (tex0.th > 10) tex0.th = 10; - tex0.th = 1<> 2) & 0x1; - tex0.tfx = (uNextTex0Data[1] >> 3) & 0x3; - - ZeroGS::fiTexWidth[ictx] = (1/16.0f)/ tex0.tw; - ZeroGS::fiTexHeight[ictx] = (1/16.0f) / tex0.th; - - if (tex0.tbw == 0) tex0.tbw = 64; - - if( PSMT_ISCLUT(psm) ) { - tex0.cbp = ((uNextTex0Data[1] >> 5) & 0x3fff); - tex0.cpsm = (uNextTex0Data[1] >> 19) & 0xe; - tex0.csm = (uNextTex0Data[1] >> 23) & 0x1; - - if( tex0.cpsm <= 1 ) tex0.csa = (uNextTex0Data[1] >> 24) & 0xf; - else tex0.csa = (uNextTex0Data[1] >> 24) & 0x1f; - - tex0.cld = (uNextTex0Data[1] >> 29) & 0x7; - - ZeroGS::texClutWrite(ictx); - } -} - -// does one time only initializing/destruction -class ZeroGSInit -{ -public: - ZeroGSInit() { - // clear - g_pbyGSMemory = (u8*)_aligned_malloc(0x00410000, 1024); // leave some room for out of range accesses (saves on the checks) - memset(g_pbyGSMemory, 0, 0x00410000); - - g_pbyGSClut = (u8*)_aligned_malloc(256*8, 1024); // need 512 alignment! - memset(g_pbyGSClut, 0, 256*8); - } - ~ZeroGSInit() { - _aligned_free(g_pbyGSMemory); g_pbyGSMemory = NULL; - _aligned_free(g_pbyGSClut); g_pbyGSClut = NULL; - } -}; - -static ZeroGSInit s_ZeroGSInit; - -HRESULT ZeroGS::Create(LONG _width, LONG _height) -{ - Destroy(1); - GSStateReset(); - - width = _width; - height = _height; - fiRendWidth = 1.0f / width; - fiRendHeight = 1.0f / height; - - HRESULT hr; - - if( NULL == (pD3D = Direct3DCreate9(D3D_SDK_VERSION)) ) { - ERROR_LOG(_T("Failed to create the direct3d interface.")); - return E_FAIL; - } - - D3DDISPLAYMODE d3ddm; - if( FAILED( hr = pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) ) { - ERROR_LOG(_T("Error geting default adapter.")); - return hr; - } - - if( conf.options & GSOPTION_FULLSCREEN ) { - // choose best mode -// RECT rcdesktop; -// GetWindowRect(GetDesktopWindow(), &rcdesktop); -// width = rcdesktop.right - rcdesktop.left; -// height = rcdesktop.bottom - rcdesktop.top; - -// width = height = 0; -// D3DDISPLAYMODE d3ddmtemp; -// -// int modes = pD3D->GetAdapterModeCount(D3DADAPTER_DEFAULT, d3ddm.Format); -// for(int i= 0; i < modes; ++i) { -// pD3D->EnumAdapterModes(D3DADAPTER_DEFAULT, d3ddm.Format, i, &d3ddmtemp); -// -// if( abs(1024-(int)d3ddmtemp.Width) <= abs(1280-width) && abs(768-(int)d3ddmtemp.Height) <= abs(1024-height) ) { -// width = d3ddmtemp.Width; -// height = d3ddmtemp.Height; -// } -// } - } - else { - // change to default resolution - ChangeDisplaySettings(NULL, 0); - } - - // Set up the structure used to create the D3DDevice. Since we are now - // using more complex geometry, we will create a device with a zbuffer. - ZeroMemory( &d3dpp, sizeof(d3dpp) ); - d3dpp.Windowed = !(conf.options & GSOPTION_FULLSCREEN); - d3dpp.hDeviceWindow = GShwnd; - d3dpp.SwapEffect = (conf.options & GSOPTION_FULLSCREEN) ? D3DSWAPEFFECT_FLIP : D3DSWAPEFFECT_DISCARD; - d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; - d3dpp.EnableAutoDepthStencil = TRUE; - d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; - d3dpp.BackBufferWidth = width; - d3dpp.BackBufferHeight = height; - d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;//(conf.options & GSOPTION_FULLSCREEN) ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE; - d3dpp.Flags = DEBUG_PS2 ? D3DPRESENTFLAG_LOCKABLE_BACKBUFFER : 0; - - s_nFullscreen = (conf.options & GSOPTION_FULLSCREEN) ? 1 : 0; - - // Create the D3DDevice - UINT adapter = D3DADAPTER_DEFAULT; - D3DDEVTYPE devtype = !DEBUG_PS2 ? D3DDEVTYPE_HAL : D3DDEVTYPE_REF; - -#ifndef _DEBUG - DWORD hwoptions = D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_PUREDEVICE; -#else - DWORD hwoptions = D3DCREATE_HARDWARE_VERTEXPROCESSING; -#endif - -#ifndef RELEASE_TO_PUBLIC - for(UINT i = 0; i < pD3D->GetAdapterCount(); ++i) { - D3DADAPTER_IDENTIFIER9 id; - HRESULT hr = pD3D->GetAdapterIdentifier(i, 0, &id); - if( strcmp(id.Description, "NVIDIA NVPerfHUD") == 0 ) { - DEBUG_LOG("Using %s adapter\n", id.Description); - adapter = i; - devtype = D3DDEVTYPE_REF; - break; - } - } -#endif - - if( FAILED( hr = pD3D->CreateDevice( adapter, devtype, GShwnd, - !DEBUG_PS2 ? hwoptions : D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice ) ) ) - { - ERROR_LOG(_T("Failed to create hardware device, creating software.\n")); - - if( FAILED( hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GShwnd, - D3DCREATE_SOFTWARE_VERTEXPROCESSING, - &d3dpp, &pd3dDevice ) ) ) - { - ERROR_LOG(_T("Failed to create software device, switching to reference rasterizer.\n")); - - if( FAILED( hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, GShwnd, - D3DCREATE_SOFTWARE_VERTEXPROCESSING, - &d3dpp, &pd3dDevice ) ) ) - return hr; - } - } - - // get caps and check if gfx card is ok - D3DCAPS9 caps; - pd3dDevice->GetDeviceCaps(&caps); - - if( caps.VertexShaderVersion < D3DVS_VERSION(2,0) ) { - ERROR_LOG("*********\nGS ERROR: Need at least vs2.0\n*********\n"); - Destroy(1); - return E_FAIL; - } - - conf.mrtdepth = 1; - - if( caps.NumSimultaneousRTs == 1 ) { - ERROR_LOG("*********\nGS WARNING: Need at least 2 simultaneous render targets. Some zbuffer effects will look wrong\n*********\n"); - conf.mrtdepth = 0; - } - if( !(caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) ) { - ERROR_LOG("*********\nGS ERROR: Need separate alpha blending! Some effects will look bad\n*********\n"); - } - if( !(caps.PrimitiveMiscCaps & D3DPMISCCAPS_INDEPENDENTWRITEMASKS) ) { - ERROR_LOG("******\nGS WARNING: Need independent write masks! Some z buffer effects might look bad\n*********\n"); - bIndepWriteMasks = 0; - } - - if( !(caps.PrimitiveMiscCaps & D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING) ) { - ERROR_LOG("******\nGS WARNING: Need MRT Post Pixel Shader Blending for some effects\n*********\n"); - } - - hr = pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, - D3DUSAGE_RENDERTARGET|D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, g_RenderFormat); - - if( g_GameSettings & GAME_32BITTARGS ) { - g_RenderFormat = D3DFMT_A8R8G8B8; - ERROR_LOG("Setting 32 bit render target\n"); - } - else if( FAILED(hr) ) { - ERROR_LOG("******\nGS ERROR: Device doesn't support alpha blending for 16bit floating point targets.\nQuality will reduce.\n*********\n"); - g_RenderFormat = D3DFMT_A8R8G8B8; - } - -// hr = pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_G32R32F); -// -// if( FAILED(hr) ) { -// ERROR_LOG("******\nGS ERROR: Device doesn't support G32R32F textures.\nTextures will look bad.\n*********\n"); -// } - - g_MaxTexWidth = caps.MaxTextureWidth; - g_MaxTexHeight = caps.MaxTextureHeight; - GPU_TEXWIDTH = caps.MaxTextureWidth/8; - g_fiGPU_TEXWIDTH = 1.0f / GPU_TEXWIDTH; - - //g_RenderFormat = D3DFMT_A8R8G8B8; - - pd3dDevice->GetRenderTarget(0, &psurfOrgTarg); - pd3dDevice->GetDepthStencilSurface(&psurfOrgDepth); - - SETRS(D3DRS_ZENABLE, TRUE); - SETRS(D3DRS_LIGHTING, FALSE); - SETRS(D3DRS_SPECULARENABLE, FALSE); - - V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, - OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, - "Arial", &pFont ) ); - - // create the vertex decl - const D3DVERTEXELEMENT9 Decl[] = { - { 0, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, - { 0, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }, - { 0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, - { 0, 16, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 }, - D3DDECL_END() }; - V_RETURN(pd3dDevice->CreateVertexDeclaration(Decl, &pdecl)); - -#ifdef RELEASE_TO_PUBLIC - HRSRC hShaderSrc = FindResource(hInst, MAKEINTRESOURCE(IDR_SHADERS), RT_RCDATA); - assert( hShaderSrc != NULL ); - HGLOBAL hShaderGlob = LoadResource(hInst, hShaderSrc); - assert( hShaderGlob != NULL ); - s_lpShaderResources = (BYTE*)LockResource(hShaderGlob); -#endif - - // load the effect - ERROR_LOG("Creating effects\n"); - V_RETURN(LoadEffects()); - - g_bDisplayMsg = 0; - if( caps.VertexShaderVersion >= D3DVS_VERSION(3,0) && caps.PixelShaderVersion >= D3DPS_VERSION(2,0) ) - g_nPixelShaderVer = SHADER_30; - else if( caps.PixelShaderVersion == D3DPS_VERSION(2,0) ) - g_nPixelShaderVer = SHADER_20; - else - g_nPixelShaderVer = SHADER_20a; - -#ifdef RELEASE_TO_PUBLIC - // create a sample shader - clampInfo temp; - memset(&temp, 0, sizeof(temp)); - temp.wms = 3; temp.wmt = 3; - - if( g_nPixelShaderVer != SHADER_30 ) { - // test more - if( LoadShadeEffect(0, 1, 1, 1, 1, temp, 0) == NULL ) { - g_nPixelShaderVer = SHADER_20b; - if( LoadShadeEffect(0, 1, 1, 1, 1, temp, 0) == NULL ) { - - g_nPixelShaderVer = SHADER_20; - if( LoadShadeEffect(0, 0, 1, 1, 0, temp, 0) == NULL ) { - - ERROR_LOG("*********\nGS ERROR: Need at least ps2.0 (ps2.0a+ recommended)\n*********\n"); - Destroy(1); - return E_FAIL; - } - } - } - } -#endif - - // set global shader constants - pd3dDevice->SetPixelShaderConstantF(27, DXVEC4(0.5f, (g_GameSettings&GAME_EXACTCOLOR)?0.9f/256.0f:0.5f/256.0f, 0,1/255.0f), 1); // g_fExactColor - pd3dDevice->SetPixelShaderConstantF(28, DXVEC4(-0.7f, -0.65f, 0.9f,0), 1); // g_fBilinear - pd3dDevice->SetPixelShaderConstantF(29, DXVEC4(1.0f/256.0f, 1.0004f, 1, 0.5f), 1); // g_fZBias - pd3dDevice->SetPixelShaderConstantF(30, DXVEC4(0,1, 0.001f, 0.5f), 1); // g_fc0 - pd3dDevice->SetPixelShaderConstantF(31, DXVEC4(1/1024.0f, 0.2f/1024.0f, 1/128.0f, 1/512.0f), 1); // g_fMult - - pd3dDevice->SetVertexShaderConstantF(29, DXVEC4(1.0f/256.0f, 1.0004f, 1, 0.5f), 1); // g_fZBias - pd3dDevice->SetVertexShaderConstantF(30, DXVEC4(0,1, 0.001f, 0.5f), 1); // g_fc0 - pd3dDevice->SetVertexShaderConstantF(31, DXVEC4(0.5f, -0.5f, 0.5f, 0.5f + 0.4f/416.0f), 1); // g_fBitBltTrans - - g_bDisplayMsg = 1; - if( g_nPixelShaderVer == SHADER_20 ) - conf.bilinear = 0; - - ERROR_LOG("Creating extra effects\n"); - V_RETURN(LoadExtraEffects()); - - ERROR_LOG("GS Using pixel shaders %s\n", g_pShaders[g_nPixelShaderVer]); - - pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER, 0, 1, 0); - - // init draw fns - drawfn[0] = KickPoint; - drawfn[1] = KickLine; - drawfn[2] = KickLine; - drawfn[3] = KickTriangle; - drawfn[4] = KickTriangle; - drawfn[5] = KickTriangleFan; - drawfn[6] = KickSprite; - drawfn[7] = KickDummy; - - SetAA(conf.aa); - GSsetGameCRC(g_LastCRC, g_GameSettings); - - return S_OK; -} - -void ZeroGS::Destroy(BOOL bD3D) -{ - DeleteDeviceObjects(); - - vb[0].Destroy(); - vb[1].Destroy(); - - for(int i = 0; i < ARRAYSIZE(pvs); ++i) { - SAFE_RELEASE(pvs[i]); - } - for(int i = 0; i < ARRAYSIZE(ppsRegular); ++i) { - SAFE_RELEASE(ppsRegular[i]); - } - for(int i = 0; i < ARRAYSIZE(ppsTexture); ++i) { - SAFE_RELEASE(ppsTexture[i]); - } - - SAFE_RELEASE(pvsBitBlt); - SAFE_RELEASE(pvsBitBlt30); - SAFE_RELEASE(ppsBitBlt[0]); SAFE_RELEASE(ppsBitBlt[1]); - SAFE_RELEASE(ppsBitBltDepth[0]); SAFE_RELEASE(ppsBitBltDepth[1]); - SAFE_RELEASE(ppsBitBltDepthTex[0]); SAFE_RELEASE(ppsBitBltDepthTex[1]); - SAFE_RELEASE(ppsCRTCTarg[0]); SAFE_RELEASE(ppsCRTCTarg[1]); - SAFE_RELEASE(ppsCRTC[0]); SAFE_RELEASE(ppsCRTC[1]); - SAFE_RELEASE(ppsCRTC24[0]); SAFE_RELEASE(ppsCRTC24[1]); - SAFE_RELEASE(ppsOne); - - SAFE_RELEASE(pdecl); - SAFE_RELEASE(pFont); - SAFE_RELEASE(psurfOrgTarg); - SAFE_RELEASE(psurfOrgDepth); - - if( bD3D ) { - SAFE_RELEASE(pd3dDevice); - SAFE_RELEASE(pD3D); - } -} - -void ZeroGS::GSStateReset() -{ - icurctx = -1; - - for(int i = 0; i < 2; ++i) { - LPD3DVB pvb = vb[i].pvb; - if( pvb != NULL ) pvb->AddRef(); - vb[i].Destroy(); - memset(&vb[i], 0, sizeof(VB)); - - vb[i].tex0.tw = 1; - vb[i].tex0.th = 1; - vb[i].pvb = pvb; - vb[i].scissor.x1 = 639; - vb[i].scissor.y1 = 479; - vb[i].tex0.tbw = 64; - } - - s_RangeMngr.Clear(); - g_MemTargs.Destroy(); - s_RTs.Destroy(); - s_DepthRTs.Destroy(); - s_BitwiseTextures.Destroy(); - - vb[0].ictx = 0; - vb[1].ictx = 1; - s_bAlphaSet = FALSE; -} - -void ZeroGS::AddMessage(const char* pstr, DWORD ms) -{ - listMsgs.push_back(MESSAGE(pstr, timeGetTime()+ms)); -} - -void ZeroGS::ChangeWindowSize(int nNewWidth, int nNewHeight) -{ - width = nNewWidth > 16 ? nNewWidth : 16; - height = nNewHeight > 16 ? nNewHeight : 16; - - if( !(conf.options & GSOPTION_FULLSCREEN) ) { - conf.width = nNewWidth; - conf.height = nNewHeight; - //SaveConfig(); - } -} - -void ZeroGS::SetChangeDeviceSize(int nNewWidth, int nNewHeight) -{ - s_nNewWidth = nNewWidth; - s_nNewHeight = nNewHeight; - - if( !(conf.options & GSOPTION_FULLSCREEN) ) { - conf.width = nNewWidth; - conf.height = nNewHeight; - //SaveConfig(); - } -} - -void ZeroGS::Reset() -{ - s_RTs.ResolveAll(); - s_DepthRTs.ResolveAll(); - - vb[0].Unlock(); - vb[1].Unlock(); - - memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); - s_nLastResolveReset = 0; - - icurctx = -1; - - GSStateReset(); - Destroy(0); - - drawfn[0] = KickDummy; - drawfn[1] = KickDummy; - drawfn[2] = KickDummy; - drawfn[3] = KickDummy; - drawfn[4] = KickDummy; - drawfn[5] = KickDummy; - drawfn[6] = KickDummy; - drawfn[7] = KickDummy; -} - -void ZeroGS::ChangeDeviceSize(int nNewWidth, int nNewHeight) -{ - int oldscreen = s_nFullscreen; - - int oldwidth = width, oldheight = height; - if( FAILED(Create(nNewWidth&~7, nNewHeight&~7)) ) { - DEBUG_LOG("Failed to recreate, changing to old\n"); - if( FAILED(Create(oldwidth, oldheight)) ) { - MessageBox(NULL, "failed to create dev, exiting...\n", "Error", MB_OK); - exit(0); - } - } - - if( FAILED(InitDeviceObjects()) ) { - MessageBox(NULL, "failed to init dev objs, exiting...\n", "Error", MB_OK); - exit(0); - } - - for(int i = 0; i < 2; ++i) { - vb[i].bNeedFrameCheck = vb[i].bNeedZCheck = 1; - vb[i].CheckFrame(0); - } - - if( oldscreen && !(conf.options & GSOPTION_FULLSCREEN) ) { // if transitioning from full screen - RECT rc; - rc.left = 0; rc.top = 0; - rc.right = conf.width; rc.bottom = conf.height; - AdjustWindowRect(&rc, conf.winstyle, FALSE); - - RECT rcdesktop; - GetWindowRect(GetDesktopWindow(), &rcdesktop); - - SetWindowLong( GShwnd, GWL_STYLE, conf.winstyle ); - SetWindowPos(GShwnd, HWND_TOP, ((rcdesktop.right-rcdesktop.left)-(rc.right-rc.left))/2, - ((rcdesktop.bottom-rcdesktop.top)-(rc.bottom-rc.top))/2, - rc.right-rc.left, rc.bottom-rc.top, SWP_SHOWWINDOW); - UpdateWindow(GShwnd); - } - - vb[0].Lock(); - vb[1].Lock(); - - assert( vb[0].pbuf != NULL && vb[1].pbuf != NULL ); -} - -void ZeroGS::SetAA(int mode) -{ - float f; - - // need to flush all targets - s_RTs.ResolveAll(); - s_RTs.Destroy(); - s_DepthRTs.ResolveAll(); - s_DepthRTs.Destroy(); - - s_AAx = s_AAy = 0; - if( mode > 0 ) - { - s_AAx = (mode+1) / 2; - s_AAy = mode / 2; - } - memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); - s_nLastResolveReset = 0; - - vb[0].prndr = NULL; vb[0].pdepth = NULL; vb[0].bNeedFrameCheck = 1; vb[0].bNeedZCheck = 1; - vb[1].prndr = NULL; vb[1].pdepth = NULL; vb[1].bNeedFrameCheck = 1; vb[1].bNeedZCheck = 1; - - f = mode > 0 ? 2.0f : 1.0f; - SETRS(D3DRS_POINTSIZE, FtoDW(f)); -} - -#ifdef RELEASE_TO_PUBLIC - -#define LOAD_VS(Index, ptr) { \ - assert( mapShaderResources.find(Index) != mapShaderResources.end() ); \ - header = mapShaderResources[Index]; \ - assert( (header) != NULL && (header)->index == (Index) ); \ - hr = pd3dDevice->CreateVertexShader((DWORD*)(s_lpShaderResources + (header)->offset), &(ptr)); \ - if( FAILED(hr) || ptr == NULL ) { \ - DEBUG_LOG("errors 0x%x for %d, failed.. try updating your drivers or dx\n", hr, Index); \ - return E_FAIL; \ - } \ -} \ - -#define LOAD_PS(index, ptr) { \ - assert( mapShaderResources.find(index) != mapShaderResources.end() ); \ - header = mapShaderResources[index]; \ - hr = pd3dDevice->CreatePixelShader((DWORD*)(s_lpShaderResources + (header)->offset), &(ptr)); \ - if( FAILED(hr) || ptr == NULL ) { \ - DEBUG_LOG("errors 0x%x for %s, failed.. try updating your drivers or dx\n", hr, index); \ - return E_FAIL; \ - } \ -} \ - -HRESULT ZeroGS::LoadEffects() -{ - assert( s_lpShaderResources != NULL ); - - // process the header - DWORD num = *(DWORD*)s_lpShaderResources; - SHADERHEADER* header = (SHADERHEADER*)((BYTE*)s_lpShaderResources + 4); - - mapShaderResources.clear(); - while(num-- > 0 ) { - mapShaderResources[header->index] = header; - ++header; - } - - // clear the textures - for(int i = 0; i < ARRAYSIZE(ppsTexture); ++i) { - SAFE_RELEASE(ppsTexture[i]); - } - memset(ppsTexture, 0, sizeof(ppsTexture)); - - return S_OK; -} - -// called -HRESULT ZeroGS::LoadExtraEffects() -{ - HRESULT hr; - - SHADERHEADER* header; - - DWORD mask = g_nPixelShaderVer == SHADER_30 ? SH_30 : 0; - - const int vsshaders[4] = { SH_REGULARVS, SH_TEXTUREVS, SH_REGULARFOGVS, SH_TEXTUREFOGVS }; - for(int i = 0; i < 4; ++i) { - LOAD_VS(vsshaders[i]|mask, pvs[2*i]); - LOAD_VS(vsshaders[i]|mask|SH_CONTEXT1, pvs[2*i+1]); - LOAD_VS(vsshaders[i]|mask|SH_WRITEDEPTH, pvs[2*i+8]); - LOAD_VS(vsshaders[i]|mask|SH_WRITEDEPTH|SH_CONTEXT1, pvs[2*i+8+1]); - } - - LOAD_VS(SH_BITBLTVS, pvsBitBlt); - //LOAD_VS(SH_BITBLTVS|SH_30, pvsBitBlt30); - - LOAD_PS(SH_REGULARPS|mask, ppsRegular[0]); - LOAD_PS(SH_REGULARFOGPS|mask, ppsRegular[1]); - LOAD_PS(SH_REGULARPS|SH_WRITEDEPTH|mask, ppsRegular[2]); - LOAD_PS(SH_REGULARFOGPS|SH_WRITEDEPTH|mask, ppsRegular[3]); - - LOAD_PS(SH_BITBLTPS, ppsBitBlt[0]); LOAD_PS(SH_BITBLTAAPS, ppsBitBlt[0]); - LOAD_PS(SH_BITBLTDEPTHPS, ppsBitBltDepth[0]); LOAD_PS(SH_BITBLTDEPTHMRTPS, ppsBitBltDepth[1]); - LOAD_PS(SH_BITBLTDEPTHTEXPS, ppsBitBltDepthTex[0]); LOAD_PS(SH_BITBLTDEPTHTEXMRTPS, ppsBitBltDepthTex[1]); - LOAD_PS(SH_CRTCTARGPS, ppsCRTCTarg[0]); LOAD_PS(SH_CRTCTARGINTERPS, ppsCRTCTarg[1]); - LOAD_PS(SH_CRTCPS, ppsCRTC[0]); LOAD_PS(SH_CRTCINTERPS, ppsCRTC[1]); - LOAD_PS(SH_CRTC24PS, ppsCRTC24[0]); LOAD_PS(SH_CRTC24INTERPS, ppsCRTC24[1]); - LOAD_PS(SH_ZEROPS|mask, ppsOne); - LOAD_PS(SH_BASETEXTUREPS, ppsBaseTexture); - LOAD_PS(SH_CONVERT16TO32PS, ppsConvert16to32); - LOAD_PS(SH_CONVERT32TO16PS, ppsConvert32to16); - - return S_OK; -} - -LPD3DPS ZeroGS::LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context) -{ - int texwrap; - assert( texfilter < NUM_FILTERS ); - - if(g_nPixelShaderVer == SHADER_20 ) - texfilter = 0; - if(g_nPixelShaderVer == SHADER_20 ) - exactcolor = 0; - - if( clamp.wms == clamp.wmt ) { - switch( clamp.wms ) { - case 0: texwrap = TEXWRAP_REPEAT; break; - case 1: texwrap = TEXWRAP_CLAMP; break; - case 2: texwrap = TEXWRAP_CLAMP; break; - default: texwrap = TEXWRAP_REGION_REPEAT; break; - } - } - else if( clamp.wms==3||clamp.wmt==3) - texwrap = TEXWRAP_REGION_REPEAT; - else - texwrap = TEXWRAP_REPEAT_CLAMP; - - int index = GET_SHADER_INDEX(type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, context, 0); - - assert( index < ARRAYSIZE(ppsTexture) ); - LPD3DPS* pps = ppsTexture+index; - - if( *pps != NULL ) - return *pps; - - index += NUM_SHADERS*g_nPixelShaderVer; - assert( mapShaderResources.find(index) != mapShaderResources.end() ); - SHADERHEADER* header = mapShaderResources[index]; - if( header == NULL ) DEBUG_LOG("%d %d\n", index%NUM_SHADERS, g_nPixelShaderVer); - assert( header != NULL ); - HRESULT hr = pd3dDevice->CreatePixelShader((DWORD*)(s_lpShaderResources + header->offset), pps); - - if( SUCCEEDED(hr) ) - return *pps; - - if( g_bDisplayMsg ) - ERROR_LOG("Failed to create shader %d,%d,%d,%d\n", 3, fog, texfilter, 4*clamp.wms+clamp.wmt); - - return NULL; -} - -#else // not RELEASE_TO_PUBLIC - -//#define EFFECT_NAME "f:\\ps2dev\\pcsx2\\zerogs\\dx\\" -#define EFFECT_NAME ".\\" -#define COMPILE_SHADER(name, type, flags) - -class ZeroGSShaderInclude : public ID3DXInclude -{ -public: - int context; - STDMETHOD(Open)(D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes) - { - const char* pfilename = pFileName; - char strfile[255]; - if( strstr(pFileName, "ps2hw_ctx") != NULL ) { - - _snprintf(strfile, 255, "%sps2hw_ctx%d.fx", EFFECT_NAME, context); - pfilename = strfile; - } - else if( strstr(pFileName, "\\") == NULL ) { - _snprintf(strfile, 255, "%s%s", EFFECT_NAME, pFileName); - pfilename = strfile; - } - - FILE* f = fopen(pfilename, "rb"); - - if( f == NULL ) - return E_FAIL; - - fseek(f, 0, SEEK_END); - DWORD size = ftell(f); - fseek(f, 0, SEEK_SET); - char* buffer = new char[size+1]; - fread(buffer, size, 1, f); - buffer[size] = 0; - - *ppData = buffer; - *pBytes = size; - fclose(f); - - return S_OK; - } - - STDMETHOD(Close)(LPCVOID pData) - { - delete[] (char*)pData; - return S_OK; - } -}; - -#define LOAD_VS(name, ptr, shaderver) { \ - LPD3DXBUFFER pShader, pError; \ - V(D3DXCompileShaderFromFile(EFFECT_NAME"ps2hw.fx", pmacros, pInclude, name, shaderver, ShaderFlagsVS, &pShader, &pError, NULL)); \ - if( FAILED(hr) ) \ - { \ - DEBUG_LOG("Failed to load vs %s: \n%s\n", name, pError->GetBufferPointer()); \ - SAFE_RELEASE(pShader); \ - SAFE_RELEASE(pError); \ - return hr; \ - } \ - hr = pd3dDevice->CreateVertexShader((const DWORD*)pShader->GetBufferPointer(), &(ptr)); \ - SAFE_RELEASE(pShader); \ - SAFE_RELEASE(pError); \ -} \ - -#define LOAD_PS(name, ptr, shmodel) { \ - LPD3DXBUFFER pShader, pError; \ - SAFE_RELEASE(ptr); \ - V(D3DXCompileShaderFromFile(EFFECT_NAME"ps2hw.fx", pmacros, pInclude, name, shmodel, ShaderFlagsPS, &pShader, &pError, NULL)); \ - if( FAILED(hr) ) \ - { \ - DEBUG_LOG("Failed to load ps %s: \n%s\n", name, pError->GetBufferPointer()); \ - SAFE_RELEASE(pShader); \ - SAFE_RELEASE(pError); \ - return hr; \ - } \ - hr = pd3dDevice->CreatePixelShader((const DWORD*)pShader->GetBufferPointer(), &(ptr)); \ - SAFE_RELEASE(pShader); \ - SAFE_RELEASE(pError); \ - if( FAILED(hr) || ptr == NULL ) { \ - DEBUG_LOG("errors 0x%x for %s, failed.. try updating your drivers or dx\n", hr, name); \ - return E_FAIL; \ - } \ -} \ - -HRESULT ZeroGS::LoadEffects() -{ - // clear the textures - for(int i = 0; i < ARRAYSIZE(ppsTexture); ++i) { - SAFE_RELEASE(ppsTexture[i]); - } - memset(ppsTexture, 0, sizeof(ppsTexture)); - - return S_OK; -} - -#define VS_VER (g_nPixelShaderVer == SHADER_20?"vs_2_0":"vs_3_0") -#define PS_VER (g_nPixelShaderVer == SHADER_20?"ps_2_0":"ps_3_0") - -HRESULT ZeroGS::LoadExtraEffects() -{ - HRESULT hr; - DWORD ShaderFlagsPS = !DEBUG_PS2 ? 0 : (D3DXSHADER_DEBUG|D3DXSHADER_SKIPOPTIMIZATION); - DWORD ShaderFlagsVS = !DEBUG_PS2 ? 0 : (D3DXSHADER_DEBUG|D3DXSHADER_SKIPOPTIMIZATION); - - ZeroGSShaderInclude inc; - inc.context = 0; - ZeroGSShaderInclude* pInclude = &inc; - - //assert( g_nPixelShaderVer == SHADER_30) ; - const char* pstrps = g_nPixelShaderVer == SHADER_20 ? "ps_2_0" : "ps_2_a"; - const char* pvsshaders[4] = { "RegularVS", "TextureVS", "RegularFogVS", "TextureFogVS" }; - - D3DXMACRO macros[2] = {0}; - D3DXMACRO* pmacros = NULL; - - macros[0].Name = "WRITE_DEPTH"; - macros[0].Definition = "1"; - - for(int i = 0; i < 4; ++i) { - pmacros = NULL; - inc.context = 0; - LOAD_VS(pvsshaders[i], pvs[2*i], VS_VER); - inc.context = 1; - LOAD_VS(pvsshaders[i], pvs[2*i+1], VS_VER); - - pmacros = macros; - inc.context = 0; - LOAD_VS(pvsshaders[i], pvs[2*i+8], VS_VER); - inc.context = 1; - LOAD_VS(pvsshaders[i], pvs[2*i+8+1], VS_VER); - } - - inc.context = 0; - pmacros = NULL; - LOAD_PS("RegularPS", ppsRegular[0], PS_VER); - LOAD_PS("RegularFogPS", ppsRegular[1], PS_VER); - - pmacros = macros; - LOAD_PS("RegularPS", ppsRegular[2], PS_VER); - LOAD_PS("RegularFogPS", ppsRegular[3], PS_VER); - - pmacros = NULL; - LOAD_VS("BitBltVS", pvsBitBlt, "vs_2_0"); - LOAD_PS("BitBltPS", ppsBitBlt[0], pstrps); - LOAD_PS("BitBltAAPS", ppsBitBlt[1], pstrps); - LOAD_PS("BitBltDepthPS", ppsBitBltDepth[0], pstrps); - LOAD_PS("BitBltDepthMRTPS", ppsBitBltDepth[1], pstrps); - LOAD_PS("BitBltDepthTexPS", ppsBitBltDepthTex[0], pstrps); - LOAD_PS("BitBltDepthTexMRTPS", ppsBitBltDepthTex[1], pstrps); - LOAD_PS("CRTCTargPS", ppsCRTCTarg[0], pstrps); LOAD_PS("CRTCTargInterPS", ppsCRTCTarg[1], pstrps); - LOAD_PS("CRTCPS", ppsCRTC[0], pstrps); LOAD_PS("CRTCInterPS", ppsCRTC[1], pstrps); - LOAD_PS("CRTC24PS", ppsCRTC24[0], pstrps); LOAD_PS("CRTC24InterPS", ppsCRTC24[1], pstrps); - LOAD_PS("ZeroPS", ppsOne, PS_VER); - LOAD_PS("BaseTexturePS", ppsBaseTexture, pstrps); - LOAD_PS("Convert16to32PS", ppsConvert16to32, pstrps); - LOAD_PS("Convert32to16PS", ppsConvert32to16, pstrps); - - return S_OK; -} - -LPD3DPS ZeroGS::LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context) -{ - int texwrap; - - assert( texfilter < NUM_FILTERS ); - //assert( g_nPixelShaderVer == SHADER_30 ); - if( clamp.wms == clamp.wmt ) { - switch( clamp.wms ) { - case 0: texwrap = TEXWRAP_REPEAT; break; - case 1: texwrap = TEXWRAP_CLAMP; break; - case 2: texwrap = TEXWRAP_CLAMP; break; - default: - texwrap = TEXWRAP_REGION_REPEAT; break; - } - } - else if( clamp.wms==3||clamp.wmt==3) - texwrap = TEXWRAP_REGION_REPEAT; - else - texwrap = TEXWRAP_REPEAT_CLAMP; - - int index = GET_SHADER_INDEX(type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, context, 0); - - LPD3DPS* pps = ppsTexture+index; - - if( *pps != NULL ) - return *pps; - - ZeroGSShaderInclude inc; - inc.context = context; - - HRESULT hr = LoadShaderFromType(EFFECT_NAME"ps2hw.fx", type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, g_nPixelShaderVer, 0, pd3dDevice, &inc, pps); - - if( SUCCEEDED(hr) ) - return *pps; - - DEBUG_LOG("Failed to create shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); - - return NULL; -} - -#endif // RELEASE_TO_PUBLIC - -HRESULT ZeroGS::InitDeviceObjects() -{ - //g_GameSettings |= 0;//GAME_VSSHACK|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE|GAME_FASTUPDATE; - //s_bWriteDepth = TRUE; - DeleteDeviceObjects(); - - int i; - HRESULT hr; - SETRS(D3DRS_SRCBLEND, D3DBLEND_ONE); - SETRS(D3DRS_DESTBLEND, D3DBLEND_ONE); - - if( pFont ) V_RETURN( pFont->OnResetDevice() ); - V_RETURN( D3DXCreateSprite( pd3dDevice, &pSprite ) ); - - V(D3DXCreateTextureFromResource(pd3dDevice, hInst, MAKEINTRESOURCE( IDB_ZEROGSLOGO ), &ptexLogo)); - - for(i = 0; i < 2; ++i) - { - V_RETURN(pd3dDevice->CreateVertexBuffer( sizeof(VertexGPU) * POINT_BUFFERSIZE, D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &vb[i].pvb, NULL)); - } - - // create the blocks texture - D3DFORMAT blockfmt = D3DFMT_R32F; - g_fBlockMult = 1; - - if( FAILED(hr = pd3dDevice->CreateTexture(BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 1, 0, blockfmt, D3DPOOL_MANAGED, &ptexBlocks, NULL)) ) { - blockfmt = D3DFMT_G16R16; - g_fBlockMult = 65535.0f*(float)g_fiGPU_TEXWIDTH; - V_RETURN(pd3dDevice->CreateTexture(BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 1, 0, blockfmt, D3DPOOL_MANAGED, &ptexBlocks, NULL)); - } - - if( blockfmt == D3DFMT_R32F ) { - if( FAILED(hr = pd3dDevice->CreateTexture(BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 1, 0, D3DFMT_A32B32G32R32F, D3DPOOL_MANAGED, &ptexBilinearBlocks, NULL)) ) { - DEBUG_LOG("Failed to create bilinear block texture, fmt = D3DFMT_A32B32G32R32F\n"); - } - } - else ptexBilinearBlocks = NULL; - - // fill a simple rect - V_RETURN(pd3dDevice->CreateVertexBuffer( 4 * sizeof(VertexGPU), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &pvbRect, NULL)); - VertexGPU* pvert; - - pvbRect->Lock(0, 0, (void**)&pvert, 0); - pvert->x = -0x7fff; pvert->y = 0x7fff; pvert->z = 0; pvert->s = 0; pvert->t = 0; pvert++; - pvert->x = 0x7fff; pvert->y = 0x7fff; pvert->z = 0; pvert->s = 1; pvert->t = 0; pvert++; - pvert->x = -0x7fff; pvert->y = -0x7fff; pvert->z = 0; pvert->s = 0; pvert->t = 1; pvert++; - pvert->x = 0x7fff; pvert->y = -0x7fff; pvert->z = 0; pvert->s = 1; pvert->t = 1; pvert++; - pvbRect->Unlock(); - - D3DLOCKED_RECT lock, lockbilinear; - ptexBlocks->LockRect(0, &lock, NULL, 0); - - if( ptexBilinearBlocks != NULL ) - ptexBilinearBlocks->LockRect(0, &lockbilinear, NULL, 0); - - BLOCK::FillBlocks(&lock, ptexBilinearBlocks != NULL ? &lockbilinear : NULL, blockfmt); - - ptexBlocks->UnlockRect(0); - if( ptexBilinearBlocks != NULL ) - ptexBilinearBlocks->UnlockRect(0); - - // create the conversion textures - V_RETURN(pd3dDevice->CreateTexture(256, 256, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &ptexConv16to32, NULL)); - ptexConv16to32->LockRect(0, &lock, NULL, 0); - assert(lock.Pitch == 256*4); - u32* dst = (u32*)lock.pBits; - for(i = 0; i < 256*256; ++i) { - DWORD tempcol = RGBA16to32(i); - // have to flip r and b - *dst++ = (tempcol&0xff00ff00)|((tempcol&0xff)<<16)|((tempcol&0xff0000)>>16); - } - ptexConv16to32->UnlockRect(0); - - V_RETURN(pd3dDevice->CreateVolumeTexture(32, 32, 32, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &ptexConv32to16, NULL)); - D3DLOCKED_BOX lockbox; - ptexConv32to16->LockBox(0, &lockbox, NULL, 0); - dst = (u32*)lockbox.pBits; - for(i = 0; i < 32; ++i) { - for(int j = 0; j < 32; ++j) { - for(int k = 0; k < 32; ++k) { - u32 col = (i<<10)|(j<<5)|k; - *dst++ = ((col&0xff)<<16)|(col&0xff00); - } - } - } - ptexConv32to16->UnlockBox(0); - - // set samplers - for(i = 0; i < 8; ++i) { - pd3dDevice->SetSamplerState(i, D3DSAMP_MINFILTER, D3DTEXF_POINT); - pd3dDevice->SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - pd3dDevice->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - pd3dDevice->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - } - - //pd3dDevice->SetSamplerState(SAMP_SRC, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); - //pd3dDevice->SetSamplerState(SAMP_SRC, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); - pd3dDevice->SetSamplerState(SAMP_BLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); - pd3dDevice->SetSamplerState(SAMP_BLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); - pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); - pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); - pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP); // can be used as a 3d texture - pd3dDevice->SetSamplerState(SAMP_BITWISEANDX, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); - pd3dDevice->SetSamplerState(SAMP_BITWISEANDX, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); - pd3dDevice->SetSamplerState(SAMP_BITWISEANDY, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); - pd3dDevice->SetSamplerState(SAMP_BITWISEANDY, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); - - pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - - pd3dDevice->SetTexture(SAMP_BLOCKS, ptexBlocks); - pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexBilinearBlocks); - pd3dDevice->SetVertexDeclaration(pdecl); - - SETRS(D3DRS_STENCILENABLE, FALSE); - SETRS(D3DRS_SCISSORTESTENABLE, 1); - SETRS(D3DRS_SEPARATEALPHABLENDENABLE, USEALPHABLENDING); - SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); - SETRS(D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO); - SETRS(D3DRS_CULLMODE, D3DCULL_NONE); - SETRS(D3DRS_BLENDFACTOR, 0x80000000); - SETRS(D3DRS_COLORWRITEENABLE1, 0); - - // points - SETRS(D3DRS_POINTSCALEENABLE, FALSE); - SETRS(D3DRS_POINTSIZE, FtoDW(1.0f)); - - g_nDepthBias = 0; - SETRS(D3DRS_DEPTHBIAS, FtoDW(0.000015f)); - - SETCONSTF(GPU_Z, g_vdepth);//vb[icurctx].zbuf.psm&3]); - - s_vznorm = DXVEC4(g_filog32, 0, 0,0); - SETCONSTF(GPU_ZNORM, s_vznorm); - - return S_OK; -} - -void ZeroGS::DeleteDeviceObjects() -{ - if( s_aviinit ) { - StopCapture(); - STOP_AVI(); - DEBUG_LOG("zerogs.avi stopped"); - s_aviinit = 0; - } - - SAFE_RELEASE(s_ptexAVICapture); - - if( pFont ) pFont->OnLostDevice(); - SAFE_RELEASE(pSprite); - - g_MemTargs.Destroy(); - s_RTs.Destroy(); - s_DepthRTs.Destroy(); - s_BitwiseTextures.Destroy(); - - SAFE_RELEASE(s_ptexInterlace); - SAFE_RELEASE(pvbRect); - SAFE_RELEASE(ptexBlocks); - SAFE_RELEASE(ptexBilinearBlocks); - SAFE_RELEASE(ptexConv16to32); - SAFE_RELEASE(ptexConv32to16); - s_bAlphaSet = FALSE; - - vb[0].Unlock(); - SAFE_RELEASE(vb[0].pvb); - - vb[1].Unlock(); - SAFE_RELEASE(vb[1].pvb); -} - -void ZeroGS::Prim() -{ - if( g_bIsLost ) - return; - - VB& curvb = vb[prim->ctxt]; - if( curvb.CheckPrim() ) - Flush(prim->ctxt); - curvb.curprim._val = prim->_val; - - // flush the other pipe if sharing the same buffer -// if( vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp && vb[!prim->ctxt].dwCount > 0 ) -// { -// assert( vb[prim->ctxt].dwCount == 0 ); -// Flush(!prim->ctxt); -// } - - curvb.curprim.prim = prim->prim; - vb[prim->ctxt].Lock(); -} - -int GetTexFilter(const tex1Info& tex1) -{ - // always force - if( conf.bilinear == 2 ) - return 1; - - int texfilter = 0; - if( conf.bilinear && ptexBilinearBlocks != NULL ) { - if( tex1.mmin <= 1 ) - texfilter = tex1.mmin|tex1.mmag; - else - texfilter = tex1.mmag ? ((tex1.mmin+2)&5) : tex1.mmin; - - texfilter = texfilter == 1 || texfilter == 4 || texfilter == 5; - } - return texfilter; -} - -void ZeroGS::ReloadEffects() -{ -#ifndef RELEASE_TO_PUBLIC - for(int i = 0; i < ARRAYSIZE(ppsTexture); ++i) { - SAFE_RELEASE(ppsTexture[i]); - } - memset(ppsTexture, 0, sizeof(ppsTexture)); - LoadExtraEffects(); -#endif -} - -static int s_ClutResolve = 0; -static int s_PSM8Resolve = 0; -void ZeroGS::Flush(int context) -{ - assert( context >= 0 && context <= 1 ); - -#ifndef RELEASE_TO_PUBLIC - if( g_bUpdateEffect ) { - ReloadEffects(); - g_bUpdateEffect = 0; - } -#endif - - VB& curvb = vb[context]; - const pixTest curtest = curvb.test; - if( curvb.dwCount == 0 || (curtest.zte && curtest.ztst == 0) || g_bIsLost ) { - curvb.dwCount = 0; - return; - } - - if( s_RangeMngr.ranges.size() > 0 ) { - - // don't want infinite loop - DWORD prevcount = curvb.dwCount; - curvb.dwCount = 0; - FlushTransferRanges(curvb.curprim.tme ? &curvb.tex0 : NULL); - - curvb.dwCount = prevcount; - //if( curvb.dwCount == 0 ) - // return; - } - - if( curvb.bNeedTexCheck ) { - curvb.FlushTexData(); - - if( curvb.dwCount == 0 ) - return; - } - - if( !s_bBeginScene ) { - pd3dDevice->BeginScene(); - s_bBeginScene = TRUE; - } - - curvb.Unlock(); - - LPD3DTEX ptexRenderTargetCached = NULL; - int cachedtbp0, cachedtbw, cachedtbh; - - //s_bWriteDepth = TRUE; - - //static int lasttime = 0; - //fprintf(gsLog, "%d: %d\n", g_SaveFrameNum, timeGetTime()-lasttime); - //lasttime = timeGetTime(); - - if( curvb.bNeedFrameCheck || curvb.bNeedZCheck ) { - - int tpsm = curvb.tex0.psm; - if( curvb.bNeedTexCheck ) - tpsm = (curvb.uNextTex0Data[0] >> 20) & 0x3f; - - if( tpsm == PSMT8H && (g_GameSettings&GAME_NOTARGETCLUT) ) { - curvb.dwCount = 0; - return; - } - - // check for the texture before checking the frame (since things could get destroyed) - if( (g_GameSettings&GAME_PARTIALPOINTERS) &&curvb.curprim.tme ) { - -// if( (curvb.gsfb.fbp&0xff) != 0 ) { -// curvb.dwCount = 0; -// return; -// } - - // if texture is part of a previous target, use that instead - int tbw = curvb.tex0.tbw; - int tbp0 = curvb.tex0.tbp0; - - if( curvb.bNeedTexCheck ) { - // not yet initied, but still need to get correct target! (xeno3 ingame) - tbp0 = (curvb.uNextTex0Data[0] & 0x3fff); - tbw = ((curvb.uNextTex0Data[0] >> 14) & 0x3f) * 64; - } - - if( (tpsm&~1) == 0 ) { - CRenderTarget* ptemptarg = s_RTs.GetTarg(tbp0, tbw); - if( ptemptarg != NULL && (ptemptarg->psm&~1) == (tpsm&~1) ) { - ptexRenderTargetCached = ptemptarg->ptex; - ptexRenderTargetCached->AddRef(); - cachedtbp0 = ptemptarg->fbp; - cachedtbw = ptemptarg->fbw; - cachedtbh = ptemptarg->fbh; - } - } - } - curvb.CheckFrame(curvb.curprim.tme ? curvb.tex0.tbp0 : 0); - } - -// if( g_SaveFrameNum == 976 ) { -// curvb.prndr->ConvertTo32(); -// } - if( curvb.prndr == NULL || curvb.pdepth == NULL ) { - WARN_LOG("Current render target NULL (ctx: %d)", context); - curvb.dwCount = 0; - SAFE_RELEASE(ptexRenderTargetCached); - return; - } - -#if defined(PRIM_LOG) && defined(_DEBUG) - static const char* patst[8] = { "NEVER", "ALWAYS", "LESS", "LEQUAL", "EQUAL", "GEQUAL", "GREATER", "NOTEQUAL"}; - static const char* pztst[4] = { "NEVER", "ALWAYS", "GEQUAL", "GREATER" }; - static const char* pafail[4] = { "KEEP", "FB_ONLY", "ZB_ONLY", "RGB_ONLY" }; - PRIM_LOG("**Drawing ctx %d, num %d, fbp: 0x%x, zbp: 0x%x, fpsm: %d, zpsm: %d, fbw: %d\n", context, vb[context].dwCount, curvb.prndr->fbp, curvb.zbuf.zbp, curvb.prndr->psm, curvb.zbuf.psm, curvb.prndr->fbw); - PRIM_LOG("prim: prim=%x iip=%x tme=%x fge=%x abe=%x aa1=%x fst=%x ctxt=%x fix=%x\n", - curvb.curprim.prim, curvb.curprim.iip, curvb.curprim.tme, curvb.curprim.fge, curvb.curprim.abe, curvb.curprim.aa1, curvb.curprim.fst, curvb.curprim.ctxt, curvb.curprim.fix); - PRIM_LOG("test: ate:%d, atst: %s, aref: %d, afail: %s, date: %d, datm: %d, zte: %d, ztst: %s, fba: %d\n", - curvb.test.ate, patst[curvb.test.atst], curvb.test.aref, pafail[curvb.test.afail], curvb.test.date, curvb.test.datm, curvb.test.zte, pztst[curvb.test.ztst], curvb.fba.fba); - PRIM_LOG("alpha: A%d B%d C%d D%d FIX:%d pabe: %d; aem: %d, ta0: %d, ta1: %d\n", curvb.alpha.a, curvb.alpha.b, curvb.alpha.c, curvb.alpha.d, curvb.alpha.fix, gs.pabe, gs.texa.aem, gs.texa.ta[0], gs.texa.ta[1]); - PRIM_LOG("tex0: tbp0=0x%x, tbw=%d, psm=0x%x, tw=%d, th=%d, tcc=%d, tfx=%d, cbp=0x%x, cpsm=0x%x, csm=%d, csa=%d, cld=%d\n", - curvb.tex0.tbp0, curvb.tex0.tbw, curvb.tex0.psm, curvb.tex0.tw, - curvb.tex0.th, curvb.tex0.tcc, curvb.tex0.tfx, curvb.tex0.cbp, - curvb.tex0.cpsm, curvb.tex0.csm, curvb.tex0.csa, curvb.tex0.cld); - PRIM_LOG("frame: %d\n\n", g_SaveFrameNum); -#endif - - CMemoryTarget* pmemtarg = NULL; - CRenderTarget* ptextarg = NULL; - - // kh2 hack -// if( curvb.dwCount == 2 && curvb.curprim.tme == 0 && curvb.curprim.abe == 0 && (curvb.tex0.tbp0 == 0x2a00 || curvb.tex0.tbp0==0x1d00) ) { -// // skip -// DEBUG_LOG("skipping\n"); -// g_SaveFrameNum++; -// curvb.dwCount = 0; -// return; -// } - - if( curtest.date || gs.pabe ) - SetDestAlphaTest(); - - // set the correct pixel shaders - if( curvb.curprim.tme && ptexRenderTargetCached == NULL ) { - - // if texture is part of a previous target, use that instead - int tbw = curvb.tex0.tbw; - int tbp0 = curvb.tex0.tbp0; - int tpsm = curvb.tex0.psm; - - if( curvb.bNeedTexCheck ) { - // not yet initied, but still need to get correct target! (xeno3 ingame) - tbp0 = (curvb.uNextTex0Data[0] & 0x3fff); - tbw = ((curvb.uNextTex0Data[0] >> 14) & 0x3f) * 64; - tpsm = (curvb.uNextTex0Data[0] >> 20) & 0x3f; - } - ptextarg = s_RTs.GetTarg(tbp0, tbw); - - if( ptextarg == NULL && tpsm == PSMT8 ) { - // check for targets with half the width - ptextarg = s_RTs.GetTarg(tbp0, tbw/2); - if( ptextarg == NULL ) { - tbp0 &= ~0x7ff; - ptextarg = s_RTs.GetTarg(tbp0, tbw/2); // mgs3 hack - - if( ptextarg == NULL ) { - // check the next level (mgs3) - tbp0 &= ~0xfff; - ptextarg = s_RTs.GetTarg(tbp0, tbw/2); // mgs3 hack - } - - if( ptextarg != NULL && ptextarg->start > tbp0*256 ) { - // target beyond range, so ignore - ptextarg = NULL; - } - } - -// if( ptextarg != NULL ) { -// // make sure target isn't invalidated by the ranges -// for(vector::iterator itrange = s_RangeMngr.ranges.begin(); itrange != s_RangeMngr.ranges.end(); ++itrange ) { -// -// int start = itrange->start; -// int end = itrange->end; -// -// // if start and end are in the range or there's a range that is between tbp0 and start, then remove -// if( (start <= tbp0*256 && end > tbp0*256) || (start >= ptextarg->fbp*256 && start <= tbp0*256) ) { -// ptextarg = NULL; -// break; -// } -// } -// } - - if( ptextarg != NULL && !(ptextarg->status&CRenderTarget::TS_NeedUpdate) ) { - // find the equivalent memtarg - if( s_PSM8Resolve == 0 ) { //|| (s_PSM8Resolve > 0 && s_PSM8Resolve+128 < g_SaveFrameNum) ) { - DWORD prevcount = curvb.dwCount; - curvb.dwCount = 0; - if( ptextarg->pmimicparent != NULL ) - ptextarg->pmimicparent->Resolve(); - else - ptextarg->Resolve(); - curvb.dwCount = prevcount; - s_PSM8Resolve = g_SaveFrameNum; // stop from resolving again (once per frame) - } - - tex0Info mytex0 = curvb.tex0; - mytex0.tbp0 = tbp0; - if( ptextarg->pmimicparent != NULL ) { - mytex0.tbp0 = ptextarg->pmimicparent->fbp; - } - pmemtarg = g_MemTargs.GetMemoryTarget(mytex0, 1); - - // have to add an offset to all texture reads - mytex0.tbp0 = tbp0; // change so that SetTexVariablesInt can set the right offsets - - SetTexVariablesInt(context, GetTexFilter(curvb.tex1), mytex0, pmemtarg, s_bForceTexFlush); - curvb.bVarsTexSync = TRUE; - - ptextarg = NULL; // won't be needing this anymore - } - } - - if( (tpsm&0x30)==0x30 && ptextarg == NULL ) { - // try depth - ptextarg = s_DepthRTs.GetTarg(tbp0, tbw); - } - - if( ptextarg == NULL && (g_GameSettings&GAME_TEXTURETARGS) ) { - // check if any part of the texture intersects the current target - if( !PSMT_ISCLUT(tpsm) && curvb.tex0.tbp0 >= curvb.frame.fbp && (curvb.tex0.tbp0 << 8) < curvb.prndr->end) { - ptextarg = curvb.prndr; - } - } - - if( ptextarg != NULL && !(ptextarg->status&CRenderTarget::TS_NeedUpdate) ) { - if( PSMT_ISCLUT(tpsm) && tpsm != PSMT8H && tpsm != PSMT8 ) { // handle 8h cluts - // don't support clut targets, read from mem - // 4hl - kh2 check - if( tpsm != PSMT4HL && tpsm != PSMT4HH && s_ClutResolve <= 1 ) { // xenosaga requires 2 resolves - DWORD prevcount = curvb.dwCount; - curvb.dwCount = 0; - ptextarg->Resolve(); - s_ClutResolve++; - curvb.dwCount = prevcount; - } - ptextarg = NULL; - } - else { - if( ptextarg == curvb.prndr ) { - // need feedback - if( ptextarg->pmimicparent != NULL ) { - // if the target is mimic, create the feedback of the parent - assert( ptextarg->pmimicparent->ptex == ptextarg->ptex || ptextarg->pmimicparent->ptexFeedback == ptextarg->ptex ); - SAFE_RELEASE(ptextarg->ptexFeedback); - SAFE_RELEASE(ptextarg->psurfFeedback); - ptextarg->pmimicparent->CreateFeedback(); - ptextarg->ptex = ptextarg->pmimicparent->ptex; - ptextarg->ptexFeedback = ptextarg->pmimicparent->ptexFeedback; ptextarg->ptexFeedback->AddRef(); - ptextarg->psurf = ptextarg->pmimicparent->psurf; - ptextarg->psurfFeedback = ptextarg->pmimicparent->psurfFeedback; ptextarg->psurfFeedback->AddRef(); - } - else - curvb.prndr->CreateFeedback(); - - pd3dDevice->SetRenderTarget(1, (s_bWriteDepth && curvb.pdepth != NULL) ? curvb.pdepth->psurf : NULL); - } - } - } - else ptextarg = NULL; - } - -#ifdef _DEBUG - if( g_bSaveFlushedFrame & 0x80000000 ) { - char str[255]; - sprintf(str, "rndr.tga", g_SaveFrameNum); - D3DXSaveSurfaceToFile(str, D3DXIFF_TGA, curvb.prndr->psurf, NULL, NULL); - } -#endif - - if( conf.options & GSOPTION_WIREFRAME ) { - // always render first few geometry as solid - if( s_nWireframeCount > 0 ) { - SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); - } - } - - if( !curvb.bVarsSetTarg ) - SetContextTarget(context); - else { - assert( curvb.pdepth != NULL ); - - if( curvb.pdepth->status & CRenderTarget::TS_Virtual) { - - if( !curvb.zbuf.zmsk ) { - CRenderTarget* ptemp = s_DepthRTs.Promote(curvb.pdepth->fbp|(curvb.pdepth->fbw<<16)); - assert( ptemp == curvb.pdepth ); - } - else - curvb.pdepth->status &= ~CRenderTarget::TS_NeedUpdate; - } - - if( (curvb.pdepth->status & CRenderTarget::TS_NeedUpdate) || (curvb.prndr->status & CRenderTarget::TS_NeedUpdate) ) - SetContextTarget(context); - } - - SetTexVariables(context); - if( ptextarg == NULL && pmemtarg == NULL ) { - pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 1); - - if( vb[context].bVarsTexSync ) { - if( vb[context].pmemtarg != pmemtarg ) { - SetTexVariablesInt(context, GetTexFilter(curvb.tex1), curvb.tex0, pmemtarg, s_bForceTexFlush); - vb[context].bVarsTexSync = TRUE; - } - } - else { - SetTexVariablesInt(context, GetTexFilter(curvb.tex1), curvb.tex0, pmemtarg, s_bForceTexFlush); - vb[context].bVarsTexSync = TRUE; - - INC_TEXVARS(); - } - } - - icurctx = context; - - assert( !(curvb.prndr->status&CRenderTarget::TS_NeedUpdate) ); - curvb.prndr->status = 0; - - if( curvb.pdepth != NULL ) { - assert( !(curvb.pdepth->status&CRenderTarget::TS_NeedUpdate) ); - if( !curvb.zbuf.zmsk ) { - assert( !(curvb.pdepth->status & CRenderTarget::TS_Virtual) ); - curvb.pdepth->status = 0; - } - } - - s_dwColorWrite = (curvb.prndr->psm&0xf) == 1 ? (D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED) : 0xf; - - if( ((curvb.frame.fbm)&0xff) == 0xff) s_dwColorWrite &= ~D3DCOLORWRITEENABLE_RED; - if( ((curvb.frame.fbm>>8)&0xff) == 0xff) s_dwColorWrite &= ~D3DCOLORWRITEENABLE_GREEN; - if( ((curvb.frame.fbm>>16)&0xff) == 0xff) s_dwColorWrite &= ~D3DCOLORWRITEENABLE_BLUE; - if( ((curvb.frame.fbm>>24)&0xff) == 0xff) s_dwColorWrite &= ~D3DCOLORWRITEENABLE_ALPHA; - - SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); - - pd3dDevice->SetScissorRect(&curvb.prndr->scissorrect); // need to always set it since something in this code resets it - - // set the shaders - pd3dDevice->SetVertexShader(pvs[2*((curvb.curprim._val>>1)&3)+8*s_bWriteDepth+context]); - pd3dDevice->SetStreamSource(0, curvb.pvb, curvb.dwCurOff*sizeof(VertexGPU), sizeof(VertexGPU)); - - DWORD dwUsingSpecialTesting = 0; - DWORD dwFilterOpts = 0; - - IDirect3DPixelShader9* pps; - - // need exact if equal or notequal - int exactcolor = 0; - if( g_nPixelShaderVer != SHADER_20 ) - // ffx2 breaks when ==7 - exactcolor = (curtest.ate && curtest.aref <= 128) && (curtest.atst==4);//||curtest.atst==7); - - int shadertype = 0; - - // set the correct pixel shaders - if( curvb.curprim.tme ) { - - if( curvb.ptexClamp[0] != NULL ) pd3dDevice->SetTexture(SAMP_BITWISEANDX, curvb.ptexClamp[0]); - if( curvb.ptexClamp[1] != NULL ) pd3dDevice->SetTexture(SAMP_BITWISEANDY, curvb.ptexClamp[1]); - - if( ptexRenderTargetCached != NULL ) { - DXVEC4 vpageoffset; - vpageoffset.w = 0; - - int psm = curvb.tex0.psm; - assert( !PSMT_ISCLUT(curvb.tex0.psm)); - - pps = LoadShadeEffect(1, 0, curvb.curprim.fge, curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), - exactcolor, curvb.clamp, context); - pd3dDevice->SetTexture(SAMP_MEMORY0+context, ptexRenderTargetCached); - s_ptexCurSet[context] = ptexRenderTargetCached; - - if( curvb.tex1.mmag ) { - pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - dwFilterOpts |= 1; - } - - if( curvb.tex1.mmin ) { - pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - dwFilterOpts |= 2; - } - - DXVEC4 vTexDims; - vTexDims.x = curvb.tex0.tw / (float)cachedtbw; - vTexDims.y = curvb.tex0.th / (float)cachedtbh; - -// u32 tbp0 = curvb.tex0.tbp0 >> 5; // align to a page -// int blockheight = 32; -// int ycoord = ((curvb.tex0.tbp0-cachedtbp0)/(32*(cachedtbw>>6))) * blockheight; -// int xcoord = (((curvb.tex0.tbp0-cachedtbp0)%(32*(cachedtbw>>6)))) * 2; -//// xcoord += ptextarg->targoffx; -//// ycoord += ptextarg->targoffy; -// vTexDims.z = (float)xcoord / (float)cachedtbw; -// vTexDims.w = (float)ycoord / (float)cachedtbh; - vTexDims.z = vTexDims.w = 0; - SETCONSTF(GPU_TEXDIMS0+context, vTexDims); - - SETCONSTF(GPU_PAGEOFFSET0+context, vpageoffset); - - if( g_bSaveTex ) - D3DXSaveTextureToFile("tex.tga", D3DXIFF_TGA, ptexRenderTargetCached, NULL); - } - else if( ptextarg != NULL ) { - - if( ptextarg->IsDepth() ) - SetWriteDepth(); - - DXVEC4 vpageoffset; - vpageoffset.w = 0; - - shadertype = 1; - if( (curvb.tex0.psm == PSMT8 || curvb.tex0.psm == PSMT8H) && !(g_GameSettings&GAME_NOTARGETCLUT) ) { - // load the clut to memory - LPD3DTEX ptexclut = NULL; - pd3dDevice->CreateTexture(256, 1, 1, 0, (curvb.tex0.cpsm&2) ? D3DFMT_A1R5G5B5 : D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &ptexclut, NULL); - if( ptexclut != NULL ) { - - D3DLOCKED_RECT lock; - ptexclut->LockRect(0, &lock, NULL, D3DLOCK_NOSYSLOCK); - - // fill the buffer by decoding the clut - int nClutOffset = 0, clutsize; - int entries = (curvb.tex0.psm&3)==3 ? 256 : 16; - if( curvb.tex0.cpsm <= 1 ) { // 32 bit - nClutOffset = 64 * curvb.tex0.csa; - clutsize = min(entries, 256-curvb.tex0.csa*16)*4; - } - else { - nClutOffset = 64 * (curvb.tex0.csa&15) + (curvb.tex0.csa>=16?2:0); - clutsize = min(entries, 512-curvb.tex0.csa*16)*2; - } - - if( curvb.tex0.cpsm <= 1 ) { // 32 bit - memcpy_amd(lock.pBits, ZeroGS::g_pbyGSClut+nClutOffset, clutsize); - } - else { - u16* pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + nClutOffset); - u16* pclut = (u16*)lock.pBits; - int left = ((u32)nClutOffset & 2) ? 0 : ((nClutOffset&0x3ff)/2)+clutsize-512; - if( left > 0 ) clutsize -= left; - - while(clutsize > 0) { - pclut[0] = pClutBuffer[0]; - pclut++; - pClutBuffer+=2; - clutsize -= 2; - } - - if( left > 0) { - pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + 2); - while(left > 0) { - pclut[0] = pClutBuffer[0]; - left -= 2; - pClutBuffer += 2; - pclut++; - } - } - } - - ptexclut->UnlockRect(0); - - s_vecTempTextures.push_back(ptexclut); - pd3dDevice->SetTexture(SAMP_FINAL, ptexclut); - - if( g_bSaveTex ) - D3DXSaveTextureToFile("clut.tga", D3DXIFF_TGA, ptexclut, NULL); - } - - if( g_nPixelShaderVer != SHADER_20 && (ptextarg->psm & 2) ) { - // 16 bit texture - shadertype = 4; - - DXVEC4 v; - v.x = 16.0f / (float)ptextarg->fbw; - v.y = 64.0f / (float)ptextarg->fbh; - v.z = 0.5f * v.x; - v.w = 0.5f * v.y; - SETCONSTF(GPU_TEXOFFSET0, v); - - v.x = 1; - v.y = -0.5f; - v.z = 0; - v.w = 0.0001f; - SETCONSTF(GPU_PAGEOFFSET0, v); - - pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexConv32to16); - } - else - shadertype = 2; - } - else { - if( PSMT_ISCLUT(curvb.tex0.psm) ) - WARN_LOG("Using render target with CLUTs %d!\n", curvb.tex0.psm); - else { - if( (curvb.tex0.psm&2) != (ptextarg->psm&2) && (g_nPixelShaderVer != SHADER_20 || !curvb.curprim.fge) ) { - if( curvb.tex0.psm & 2 ) { - // converting from 32->16 - shadertype = 3; - - DXVEC4 v; - v.x = 16.0f / (float)curvb.tex0.tw; - v.y = 64.0f / (float)curvb.tex0.th; - v.z = 0.5f * v.x; - v.w = 0.5f * v.y; - SETCONSTF(GPU_TEXOFFSET0+context, v); - - vpageoffset.x = -0.1f / 256.0f; - vpageoffset.y = -0.001f / 256.0f; - vpageoffset.z = -0.1f / ptextarg->fbh; - vpageoffset.w = ((ptextarg->psm&0x30)==0x30)?-1.0f:0.0f; - - pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexConv16to32); - } - else { - // converting from 16->32 - WARN_LOG("ZeroGS: converting from 16 to 32bit RTs\n"); - //shadetype = 4; - } - } - } - } - - int psm = curvb.tex0.psm; - if( PSMT_ISCLUT(curvb.tex0.psm) ) psm = curvb.tex0.cpsm; - - pps = LoadShadeEffect(shadertype, 0, curvb.curprim.fge, curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), - exactcolor, curvb.clamp, context); - LPD3DTEX ptexset = ptextarg == curvb.prndr ? ptextarg->ptexFeedback : ptextarg->ptex; - pd3dDevice->SetTexture(SAMP_MEMORY0+context, ptexset); - s_ptexCurSet[context] = ptexset; - - if( curvb.tex1.mmag ) { - pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - dwFilterOpts |= 1; - } - - if( curvb.tex1.mmin ) { - pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - dwFilterOpts |= 2; - } - - DXVEC4 vTexDims; - vTexDims.x = curvb.tex0.tw / (float)ptextarg->fbw; - vTexDims.y = curvb.tex0.th / (float)ptextarg->targheight; - - // look at the offset of tbp0 from fbp - if( curvb.tex0.tbp0 <= ptextarg->fbp ) { - vTexDims.z = 0;//-0.5f/(float)ptextarg->fbw; - vTexDims.w = 0;//0.2f/(float)ptextarg->fbh; - } - else { - u32 tbp0 = curvb.tex0.tbp0 >> 5; // align to a page - int blockheight = (ptextarg->psm&2) ? 64 : 32; - int ycoord = ((curvb.tex0.tbp0-ptextarg->fbp)/(32*(ptextarg->fbw>>6))) * blockheight; - int xcoord = (((curvb.tex0.tbp0-ptextarg->fbp)%(32*(ptextarg->fbw>>6)))) * 2; - xcoord += ptextarg->targoffx; - ycoord += ptextarg->targoffy; - vTexDims.z = (float)xcoord / (float)ptextarg->fbw; - vTexDims.w = (float)ycoord / (float)ptextarg->targheight; - } - - if( shadertype == 4 ) { - vTexDims.z += 8.0f / (float)ptextarg->fbw; - } - - SETCONSTF(GPU_TEXDIMS0+context, vTexDims); - - // zoe2 - if( (ptextarg->psm&0x30) == 0x30 ) {//&& (psm&2) == (ptextarg->psm&2) ) { - // target of zbuf has +1 added to it, don't do 16bit - vpageoffset.w = -1; -// DXVEC4 valpha2; -// valpha2.x = 1; valpha2.y = 0; -// valpha2.z = -1; valpha2.w = 0; -// SETCONSTF(GPU_TEXALPHA20+context, &valpha2); - } - SETCONSTF(GPU_PAGEOFFSET0+context, vpageoffset); - - if( g_bSaveTex ) - D3DXSaveTextureToFile("tex.tga", D3DXIFF_TGA, ptextarg == curvb.prndr ? ptextarg->ptexFeedback : ptextarg->ptex, NULL); - } - else { - // save the texture -#ifdef _DEBUG -// CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 0); -// assert( curvb.pmemtarg == pmemtarg ); -// if( PSMT_ISCLUT(curvb.tex0.psm) ) -// assert( curvb.pmemtarg->ValidateClut(curvb.tex0) ); -#endif - -//#ifdef ZEROGS_CACHEDCLEAR -// if( !curvb.pmemtarg->ValidateTex(curvb.tex0, true) ) { -// CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 1); -// SetTexVariablesInt(context, GetTexFilter(curvb.tex1), curvb.tex0, pmemtarg, s_bForceTexFlush); -// vb[context].bVarsTexSync = TRUE; -// } -//#endif - - if( g_bSaveTex ) { - if( g_bSaveTex == 1 ) SaveTex(&curvb.tex0, 1); - else SaveTex(&curvb.tex0, 0); - } - - int psm = curvb.tex0.psm; - if( PSMT_ISCLUT(curvb.tex0.psm) ) psm = curvb.tex0.cpsm; - - pps = LoadShadeEffect(0, GetTexFilter(curvb.tex1), curvb.curprim.fge, - curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), - exactcolor, curvb.clamp, context); - } - } - else pps = ppsRegular[curvb.curprim.fge+2*s_bWriteDepth]; - - pd3dDevice->SetPixelShader(pps); - - BOOL bCanRenderStencil = g_bUpdateStencil && (curvb.prndr->psm&0xf) != 1 && !(curvb.frame.fbm&0x80000000); - if( g_GameSettings & GAME_NOSTENCIL ) - bCanRenderStencil = 0; - - if( s_bDestAlphaTest) { - SETRS(D3DRS_STENCILENABLE, bCanRenderStencil); - SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); - SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); - } - else SETRS(D3DRS_STENCILENABLE, 0); - - SETRS(D3DRS_ZWRITEENABLE, !curvb.zbuf.zmsk); - SETRS(D3DRS_ZENABLE, curtest.zte); - if( curtest.zte ) { - if( curtest.ztst > 1 ) g_nDepthUsed = 2; - if( (curtest.ztst == 2) ^ (g_nDepthBias != 0) ) { - g_nDepthBias = curtest.ztst == 2; - if( g_GameSettings & GAME_RELAXEDDEPTH ) - SETRS(D3DRS_DEPTHBIAS, g_nDepthBias?FtoDW(0.00003f):FtoDW(0.0001f)); - else - SETRS(D3DRS_DEPTHBIAS, g_nDepthBias?FtoDW(0.0003f):FtoDW(0.000015f)); - } - - SETRS(D3DRS_ZFUNC, g_dwZCmp[curtest.ztst]); - -// if( curtest.ztst == 3 ) { -// // gequal -// if( s_vznorm.y == 0 ) { -// s_vznorm.y = 0.00001f; -// SETCONSTF(GPU_ZNORM, s_vznorm); -// } -// } -// else { -// if( s_vznorm.y > 0 ) { -// s_vznorm.y = 0; -// SETCONSTF(GPU_ZNORM, s_vznorm); -// } -// } - } - - SETRS(D3DRS_ALPHATESTENABLE, curtest.ate&&USEALPHATESTING); - if( curtest.ate ) { - - if( curtest.atst == 7 && curtest.aref == 255 ) { - // when it is at the very top, do a less than rather than not equal (gekibo2) - SETRS(D3DRS_ALPHAFUNC, D3DCMP_LESS); - SETRS(D3DRS_ALPHAREF, 255); - } - else { - SETRS(D3DRS_ALPHAFUNC, g_dwAlphaCmp[curtest.atst]); - SETRS(D3DRS_ALPHAREF, b2XAlphaTest ? min(255,2 * curtest.aref) : curtest.aref); - } - } - - if( s_bWriteDepth ) { - //pd3dDevice->SetRenderTarget(0, curvb.prndr->psurf); - //pd3dDevice->SetRenderTarget(1, !curvb.zbuf.zmsk?curvb.pdepth->psurf:NULL); - if( bIndepWriteMasks ) - SETRS(D3DRS_COLORWRITEENABLE1, !curvb.zbuf.zmsk?0xf:0); - else - pd3dDevice->SetRenderTarget(1, !curvb.zbuf.zmsk?curvb.pdepth->psurf:NULL); - } - - if( curvb.curprim.abe ) - SetAlphaVariables(curvb.alpha); - else - SETRS(D3DRS_ALPHABLENDENABLE, 0); - - // needs to be before RenderAlphaTest - if( curvb.fba.fba || s_bDestAlphaTest ) { - if( gs.pabe || (curvb.fba.fba || bCanRenderStencil) && !(curvb.frame.fbm&0x80000000) ) { - RenderFBA(curvb); - } - } - - u32 oldabe = curvb.curprim.abe; - if( gs.pabe ) { - //WARN_LOG("PBE!\n"); - curvb.curprim.abe = 1; - SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); - } - - if( curvb.curprim.abe && bNeedAlphaColor ) { - - if( //bCanRenderStencil && - (bNeedBlendFactorInAlpha || ((curtest.ate && curtest.atst>1) && (curtest.aref > 0x80))) ) { - // need special stencil processing for the alpha - RenderAlphaTest(curvb); - dwUsingSpecialTesting = 1; - } - - // harvest fishing - DXVEC4 v = vAlphaBlendColor;// + DXVEC4(0,0,0,(curvb.test.atst==4 && curvb.test.aref>=128)?-0.004f:0); - if( exactcolor ) { v.y *= 255; v.w *= 255; } - SETCONSTF(GPU_ONECOLOR, v); - } - else { - // not using blending so set to defaults - DXVEC4 v = exactcolor ? DXVEC4(1, 510*255.0f/256.0f, 0, 0) : DXVEC4(1,2*255.0f/256.0f,0,0); - SETCONSTF(GPU_ONECOLOR, v); - } - - if( s_bDestAlphaTest && bCanRenderStencil ) { - // if not 24bit and can write to high alpha bit - RenderStencil(curvb, dwUsingSpecialTesting); - } - else { - dwStencilRef = STENCIL_SPECIAL; - dwStencilMask = STENCIL_SPECIAL; - - // setup the stencil to only accept the test pixels - if( dwUsingSpecialTesting ) { - SETRS(D3DRS_STENCILENABLE, TRUE); - SETRS(D3DRS_STENCILWRITEMASK, STENCIL_PIXELWRITE); - SETRS(D3DRS_STENCILMASK, STENCIL_SPECIAL); - SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); - SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); - SETRS(D3DRS_STENCILREF, STENCIL_SPECIAL|STENCIL_PIXELWRITE); - } - } - -#ifdef _DEBUG - if( bDestAlphaColor == 1 ) { - WARN_LOG("dest alpha blending! manipulate alpha here\n"); - } -#endif - - if( bCanRenderStencil && gs.pabe ) { - // only render the pixels with alpha values >= 0x80 - SETRS(D3DRS_STENCILREF, dwStencilRef|STENCIL_FBA); - SETRS(D3DRS_STENCILMASK, dwStencilMask|STENCIL_FBA); - if( !dwStencilMask ) SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); - } - -// curvb.prndr->SetViewport(); -// pd3dDevice->SetScissorRect(&curvb.prndr->scissorrect); -// SETRS(D3DRS_SCISSORTESTENABLE, TRUE); - - if( !curvb.test.ate || curvb.test.atst > 0 ) { - DRAW(); - } - - if( gs.pabe ) { - // only render the pixels with alpha values < 0x80 - SETRS(D3DRS_ALPHABLENDENABLE, 0); - SETRS(D3DRS_STENCILREF, dwStencilRef); - - DXVEC4 v; - v.x = 1; v.y = 2; v.z = 0; v.w = 0; - if( exactcolor ) v.y *= 255; - SETCONSTF(GPU_ONECOLOR, v); - - DRAW(); - - // reset - SETRS(D3DRS_STENCILMASK, dwStencilMask); - if( !dwStencilMask ) SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); - } - - // more work on alpha failure case - if( curtest.ate && curtest.atst != 1 && curtest.afail > 0 ) { - - // need to reverse the test and disable some targets - SETRS(D3DRS_ALPHAFUNC, g_dwReverseAlphaCmp[curtest.atst]); - - if( curtest.afail & 1 ) { // front buffer update only - - if( curtest.afail == 3 ) // disable alpha - SETRS(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED); - - SETRS(D3DRS_ZWRITEENABLE, FALSE); - - if( s_bWriteDepth ) { - if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); - else pd3dDevice->SetRenderTarget(1,NULL); - } - } - else { - // zbuffer update only - SETRS(D3DRS_COLORWRITEENABLE, 0); - } - - if( gs.pabe && bCanRenderStencil ) { - // only render the pixels with alpha values >= 0x80 - DXVEC4 v = vAlphaBlendColor; - if( exactcolor ) { v.y *= 255; v.w *= 255; } - SETCONSTF(GPU_ONECOLOR, v); - SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); - SETRS(D3DRS_STENCILREF, dwStencilRef|STENCIL_FBA); - SETRS(D3DRS_STENCILMASK, dwStencilMask|STENCIL_FBA); - if( !dwStencilMask ) SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); - } - - // setup the stencil to only accept the test pixels - if( dwUsingSpecialTesting ) { - - if( !s_bDestAlphaTest || !bCanRenderStencil ) { - SETRS(D3DRS_STENCILENABLE, FALSE); - } - } - -// IDirect3DQuery9* pOcclusionQuery; -// DWORD numberOfPixelsDrawn; -// -// pd3dDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &pOcclusionQuery); -// -// // Add an end marker to the command buffer queue. -// pOcclusionQuery->Issue(D3DISSUE_BEGIN); - - DRAW(); - -// pOcclusionQuery->Issue(D3DISSUE_END); - // Force the driver to execute the commands from the command buffer. - // Empty the command buffer and wait until the GPU is idle. -// while(S_FALSE == pOcclusionQuery->GetData( &numberOfPixelsDrawn, sizeof(DWORD), D3DGETDATA_FLUSH )); -// SAFE_RELEASE(pOcclusionQuery); - - if( gs.pabe ) { - // only render the pixels with alpha values < 0x80 - SETRS(D3DRS_ALPHABLENDENABLE, 0); - SETRS(D3DRS_STENCILREF, dwStencilRef); - - DXVEC4 v; - v.x = 1; v.y = 2; v.z = 0; v.w = 0; - if( exactcolor ) v.y *= 255; - SETCONSTF(GPU_ONECOLOR, v); - - DRAW(); - - // reset - SETRS(D3DRS_STENCILMASK, dwStencilMask); - SETRS(D3DRS_ALPHABLENDENABLE, oldabe); - if( !dwStencilMask ) SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); - } - - // restore - - if( (curtest.afail & 1) && !curvb.zbuf.zmsk ) { - SETRS(D3DRS_ZWRITEENABLE, TRUE); - - if( s_bWriteDepth ) { - assert( curvb.pdepth != NULL); - if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); - else pd3dDevice->SetRenderTarget(1,curvb.pdepth->psurf); - } - } - - SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); - - // not needed anymore since rest of ops concentrate on image processing - //SETRS(D3DRS_ALPHAFUNC, g_dwAlphaCmp[curtest.atst]); - } - - if( dwUsingSpecialTesting ) { - // render the real alpha - SETRS(D3DRS_ALPHATESTENABLE, FALSE); - SETRS(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA); - - if( s_bWriteDepth ) { - if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); - else pd3dDevice->SetRenderTarget(1,NULL); - } - - SETRS(D3DRS_ZWRITEENABLE, FALSE); - - SETRS(D3DRS_STENCILMASK, STENCIL_SPECIAL|STENCIL_PIXELWRITE); - SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); - SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); - SETRS(D3DRS_STENCILREF, STENCIL_SPECIAL|STENCIL_PIXELWRITE); - - DXVEC4 v = DXVEC4(0,exactcolor ? 510.0f : 2.0f,0,0); - SETCONSTF(GPU_ONECOLOR, v); - DRAW(); - - // don't need to restore - } - - if( s_bDestAlphaTest ) { - if( (s_dwColorWrite&D3DCOLORWRITEENABLE_ALPHA) ) { - if( curvb.fba.fba ) - ProcessFBA(curvb); - else if( bCanRenderStencil ) - // finally make sure all entries are 1 when the dest alpha >= 0x80 (if fba is 1, this is already the case) - ProcessStencil(curvb); - } - } - else if( (s_dwColorWrite&D3DCOLORWRITEENABLE_ALPHA) && curvb.fba.fba ) - ProcessFBA(curvb); - - if( bDestAlphaColor == 1 ) { - // need to reset the dest colors to their original counter parts - //WARN_LOG("Need to reset dest alpha color\n"); - } - -#ifdef _DEBUG - if( g_bSaveFlushedFrame & 0xf ) { - char str[255]; - sprintf(str, "frames\\frame%.4d.jpg", g_SaveFrameNum++); - if( (g_bSaveFlushedFrame & 2) ) - D3DXSaveSurfaceToFile(str, D3DXIFF_JPG, curvb.prndr->psurf, NULL, NULL); - } -#endif - - // clamp the final colors, when enabled ffx2 credits mess up - if( curvb.curprim.abe && bAlphaClamping && g_RenderFormat != D3DFMT_A8R8G8B8 && !(g_GameSettings&GAME_NOCOLORCLAMP) ) { // if !colclamp, skip - - ResetAlphaVariables(); - - // if processing the clamping case, make sure can write to the front buffer - SETRS(D3DRS_STENCILENABLE, 0); - SETRS(D3DRS_ALPHABLENDENABLE, TRUE); - SETRS(D3DRS_ALPHATESTENABLE, FALSE); - SETRS(D3DRS_ZENABLE, FALSE); - SETRS(D3DRS_ZWRITEENABLE, FALSE); - SETRS(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RED|D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN); - - if( s_bWriteDepth ) { - if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); - else pd3dDevice->SetRenderTarget(1,NULL); - } - - pd3dDevice->SetPixelShader(ppsOne); - - // (dest&0x7f)+0x80, blend factor for alpha is always 0x80 - SETRS(D3DRS_DESTBLEND, D3DBLEND_ONE); - SETRS(D3DRS_SRCBLEND, D3DBLEND_ONE); - - float f; - - if( bAlphaClamping & 1 ) { // min - f = 0; - SETCONSTF(GPU_ONECOLOR, &f); - SETRS(D3DRS_BLENDOP, D3DBLENDOP_MAX); - DRAW(); - } - - // bios shows white screen - if( bAlphaClamping & 2 ) { // max - f = 1; - SETCONSTF(GPU_ONECOLOR, &f); - SETRS(D3DRS_BLENDOP, D3DBLENDOP_MIN); - DRAW(); - } - - if( !curvb.zbuf.zmsk ) { - SETRS(D3DRS_ZWRITEENABLE, TRUE); - - if( s_bWriteDepth ) { - assert( curvb.pdepth != NULL ); - if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); - else pd3dDevice->SetRenderTarget(1,curvb.pdepth->psurf); - } - } - - if( curvb.test.ate && USEALPHATESTING ) - SETRS(D3DRS_ALPHATESTENABLE, TRUE); - - SETRS(D3DRS_ZENABLE, curtest.zte); - } - - if( dwFilterOpts ) { - // undo filter changes - if( dwFilterOpts & 1 ) pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - if( dwFilterOpts & 2 ) pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MINFILTER, D3DTEXF_POINT); - } - - // reset used textures - if( shadertype > 2 ) { - pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); - pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); - pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexBilinearBlocks); - } - - SETRS(D3DRS_CLIPPLANEENABLE, 0); -//#ifndef RELEASE_TO_PUBLIC - ppf += curvb.dwCount+0x100000; -//#endif - curvb.dwCurOff += POINT_BUFFERFLUSH; - SAFE_RELEASE(ptexRenderTargetCached); - - g_MaxRenderedHeight = 0; - curvb.dwCount = 0; - //curvb.Lock(); - curvb.curprim.abe = oldabe; - //if( oldabe ) SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); - - if( conf.options & GSOPTION_WIREFRAME ) { - // always render first few geometry as solid - if( s_nWireframeCount > 0 ) { - SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); - --s_nWireframeCount; - } - } -} - -void ZeroGS::ProcessMessages() -{ - if( listMsgs.size() > 0 ) { - pSprite->Begin(D3DXSPRITE_ALPHABLEND|D3DXSPRITE_SORT_TEXTURE); - - RECT rctext; - rctext.left = 25; rctext.top = 15; - list::iterator it = listMsgs.begin(); - - while( it != listMsgs.end() ) { - rctext.left += 1; - rctext.top += 1; - pFont->DrawText(pSprite, it->str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xff000000); - rctext.left -= 1; - rctext.top -= 1; - pFont->DrawText(pSprite, it->str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xffffff30); - rctext.top += 15; - - if( (int)(it->dwTimeStamp - timeGetTime()) < 0 ) - it = listMsgs.erase(it); - else ++it; - } - - pSprite->End(); - } -} - -void ZeroGS::RenderCustom(float fAlpha) -{ - if( !s_bBeginScene ) - pd3dDevice->BeginScene(); - - pd3dDevice->SetDepthStencilSurface(psurfOrgDepth); - - pd3dDevice->SetRenderTarget(0, psurfOrgTarg); - - if( s_bWriteDepth ) - pd3dDevice->SetRenderTarget(1, NULL); - - SETRS(D3DRS_STENCILENABLE, 0); - SETRS(D3DRS_ZENABLE, FALSE); - SETRS(D3DRS_ZWRITEENABLE, FALSE); - SETRS(D3DRS_COLORWRITEENABLE, 0xf); - SETRS(D3DRS_ALPHABLENDENABLE, 0); - SETRS(D3DRS_ALPHATESTENABLE, 0); - SETRS(D3DRS_SCISSORTESTENABLE, 0); - - // play custom animation - pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, 0, 1, 0); - - // tex coords - DXVEC4 v = DXVEC4(1, 1, 0, 0); - SETCONSTF(GPU_BITBLTTEX, v); - SETCONSTF(GPU_BITBLTPOS, v); - - v.x = v.y = v.z = v.w = fAlpha; - SETCONSTF(GPU_ONECOLOR, v); - - if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); - - pd3dDevice->SetVertexShader(pvsBitBlt); - pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); - pd3dDevice->SetPixelShader(ppsBaseTexture); - - // inside vb[0]'s target area, so render that region only - pd3dDevice->SetTexture(SAMP_FINAL, ptexLogo); - //pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - //pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - - pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); - - // restore - //pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - //pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_POINT); - if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); - - ProcessMessages(); - - pd3dDevice->EndScene(); - s_bBeginScene = FALSE; - - pd3dDevice->Present(NULL, NULL, NULL, NULL); - - SETRS(D3DRS_SCISSORTESTENABLE, TRUE); - SETRS(D3DRS_STENCILENABLE, 1); - - if( icurctx >= 0 ) vb[icurctx].bSyncVars = 0; -} - -// adjusts trans to preserve aspect ratio -void ZeroGS::AdjustTransToAspect(DXVEC4& v, int dispwidth, int dispheight) -{ - float temp, f; - if( dispwidth * height > dispheight * width ) { - // limited by width - - // change in ratio - f = ((float)width / (float)dispwidth) / ((float)height / (float)dispheight); - v.y *= f; - v.w *= f; - - // scanlines mess up when not aligned right - v.y += (1-modf(v.y*height/2+0.05f, &temp))*2.0f/(float)height; - v.w += (1-modf(v.w*height/2+0.05f, &temp))*2.0f/(float)height; - } - else { - // limited by height - f = ((float)height / (float)dispheight) / ((float)width / (float)dispwidth); - f -= modf(f*width, &temp)/(float)width; - v.x *= f; - v.z *= f; - } -} - -void ZeroGS::Restore() -{ - if( !g_bIsLost ) - return; - - if( SUCCEEDED(pd3dDevice->Reset(&d3dpp)) ) { - g_bIsLost = 0; - // handle lost states - ZeroGS::ChangeDeviceSize(width, height); - } -} - -void ZeroGS::RenderCRTC(int interlace) -{ - if( pd3dDevice == NULL ) { - return; - } - - if( g_bIsLost ) return; - -#ifdef RELEASE_TO_PUBLIC - if( g_nRealFrame < 80 ) { - RenderCustom( min(1.0f, 2.0f - (float)g_nRealFrame / 40.0f) ); - - if( g_nRealFrame == 79 ) - SAFE_RELEASE(ptexLogo); - return; - } -#endif - - Flush(0); - Flush(1); - - // frame skipping - if( g_nFrameRender > 0 ) { - - if( g_nFrameRender < 8 ) { - g_nFrameRender++; - if( g_nFrameRender <= 3 ) { - g_nFramesSkipped++; - return; - } - } - } - else { - if( g_nFrameRender < -1 ) { - g_nFramesSkipped++; - return; - } - g_nFrameRender--; - } - - if( g_bSaveFrame ) { - if( vb[0].prndr != NULL ) D3DXSaveSurfaceToFile("frame1.tga", D3DXIFF_TGA, vb[0].prndr->psurf, NULL, NULL); - - if( vb[1].prndr != NULL && vb[0].prndr != vb[1].prndr ) D3DXSaveSurfaceToFile("frame2.tga", D3DXIFF_TGA, vb[1].prndr->psurf, NULL, NULL); - else DeleteFile("frame2.tga"); - } - - if( s_RangeMngr.ranges.size() > 0 ) - FlushTransferRanges(NULL); - - if( icurctx >= 0 && vb[icurctx].bVarsSetTarg ) { // check if anything rendered - pd3dDevice->SetRenderTarget(0, psurfOrgTarg); - pd3dDevice->SetRenderTarget(1, NULL); - - pd3dDevice->SetDepthStencilSurface(psurfOrgDepth); - } - - D3DVIEWPORT9 view; - view.Width = width; - view.Height = height; - view.X = 0; - view.Y = 0; - view.MinZ = 0; - view.MaxZ = 1.0f; - pd3dDevice->SetViewport(&view); - - //g_GameSettings |= GAME_VSSHACK|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE; - //s_bWriteDepth = TRUE; - g_SaveFrameNum = 0; - g_bSaveFlushedFrame = 1; -// static int counter = 0; -// counter++; - // reset fba after every frame - //if( !(g_GameSettings&GAME_NOFBARESET) ) { - vb[0].fba.fba = 0; - vb[1].fba.fba = 0; - //} - u32 bInterlace = SMODE2->INT && SMODE2->FFMD && (conf.interlace<2); - - // if interlace, only clear every other vsync - if(!bInterlace ) { - u32 color = D3DCOLOR_ARGB(0, BGCOLOR->R, BGCOLOR->G, BGCOLOR->B); - pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_STENCIL, color, 1, 0); - } - - if( !s_bBeginScene ) { - pd3dDevice->BeginScene(); - s_bBeginScene = TRUE; - } - - pd3dDevice->SetVertexShader(pvsBitBlt); - pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); - - if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); - SETRS(D3DRS_ZENABLE, 0); - SETRS(D3DRS_ZWRITEENABLE, 0); - SETRS(D3DRS_COLORWRITEENABLE, 0xf); - SETRS(D3DRS_ALPHABLENDENABLE, 0); - SETRS(D3DRS_ALPHATESTENABLE, 0); - SETRS(D3DRS_SCISSORTESTENABLE, 0); - SETRS(D3DRS_STENCILENABLE, 0); - - BOOL bUsingStencil = 0; - - if( bInterlace ) g_PrevBitwiseTexX = -1; // reset since will be using - - tex0Info dispinfo[2]; - - for(int i = 0; i < 2; ++i) { - - if( !(*(u32*)(PMODE) & (1<MAGH+1; - int magv = pd->MAGV+1; - - dispinfo[i].tbp0 = pfb->FBP << 5; - dispinfo[i].tbw = pfb->FBW << 6; - dispinfo[i].tw = (pd->DW + 1) / magh; - dispinfo[i].th = (pd->DH + 1) / magv; - dispinfo[i].psm = pfb->PSM; - - // hack!! - // 2 * dispinfo[i].tw / dispinfo[i].th <= 1, metal slug 4 - if( bInterlace && 2 * dispinfo[i].tw / dispinfo[i].th <= 1 && !(g_GameSettings&GAME_INTERLACE2X) ) { - dispinfo[i].th >>= 1; - } - } - - //int dispwidth = max(dispinfo[0].tw, dispinfo[1].tw), dispheight = max(dispinfo[0].th, dispinfo[1].th); - - // hack!, CMOD != 3, gradius -// if( SMODE2->INT && SMODE2->FFMD && SMODE1->CMOD == 3 && dispwidth <= 320) -// dispwidth *= 2; - - // hack! makai - //if( !bInterlace && dispheight * 2 < dispwidth ) dispheight *= 2; - - // start from the last circuit - for(int i = !PMODE->SLBG; i >= 0; --i) { - - tex0Info& texframe = dispinfo[i]; - if( texframe.th <= 1 ) - continue; - - GSRegDISPFB* pfb = i ? DISPFB2 : DISPFB1; - GSRegDISPLAY* pd = i ? DISPLAY2 : DISPLAY1; - - DXVEC4 v, valpha; - - if( bInterlace ) { - - texframe.th >>= 1; - - // interlace mode - pd3dDevice->SetTexture(SAMP_INTERLACE, CreateInterlaceTex(2*texframe.th)); - - if( interlace == (conf.interlace&1) ) { - // pass if odd - valpha.z = 1.0f; - valpha.w = -0.4999f; - } - else { - // pass if even - valpha.z = -1.0f; - valpha.w = 0.5001f; - } - } - else { - - if( SMODE2->INT && SMODE2->FFMD ) { - texframe.th >>= 1; - } - - // always pass interlace test - valpha.z = 0; - valpha.w = 1; - } - - int bpp = 4; - if( texframe.psm == 0x12 ) bpp = 3; - else if( texframe.psm & 2 ) bpp = 2; - - // get the start and end addresses of the buffer - int start, end; - GetRectMemAddress(start, end, texframe.psm, 0, 0, texframe.tw, texframe.th, texframe.tbp0, texframe.tbw); - - if( i == 0 ) { - // setup right blending - SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); - SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); - SETRS(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD); - - if( PMODE->MMOD ) { - SETRS(D3DRS_BLENDFACTOR, D3DCOLOR_ARGB(0x80, PMODE->ALP, PMODE->ALP, PMODE->ALP)); - SETRS(D3DRS_SRCBLEND, D3DBLEND_BLENDFACTOR); - SETRS(D3DRS_DESTBLEND, D3DBLEND_INVBLENDFACTOR); - } - else { - SETRS(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - SETRS(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); - } - - SETRS(D3DRS_SRCBLENDALPHA, PMODE->AMOD ? D3DBLEND_ZERO : D3DBLEND_ONE); - SETRS(D3DRS_DESTBLENDALPHA, PMODE->AMOD? D3DBLEND_ONE : D3DBLEND_ZERO); - } - - if( bUsingStencil ) { - SETRS(D3DRS_STENCILWRITEMASK, 1<SetPixelShader(ppsCRTC24[bInterlace]); - valpha.x = 0; - valpha.y = 1; - SETCONSTF(GPU_ONECOLOR, valpha); - pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); - continue; - } - - // first render the current render targets, then from ptexMem - if( texframe.psm == 1 ) { - valpha.x = 0; - valpha.y = 1; - } - else { - valpha.x = 1; - valpha.y = 0; - } - - SETCONSTF(GPU_ONECOLOR, valpha); - - BOOL bSkip = 0; - BOOL bResolveTargs = 1; - - //s_mapFrameHeights[s_nCurFrameMap][texframe.tbp0] = texframe.th; - list listTargs; - - s_RTs.GetTargs(start, end, listTargs); - - for(list::iterator it = listTargs.begin(); it != listTargs.end(); ) { - - CRenderTarget* ptarg = *it; - - if( ptarg->fbw == texframe.tbw && !(ptarg->status&CRenderTarget::TS_NeedUpdate) && ((256/bpp)*(texframe.tbp0-ptarg->fbp))%texframe.tbw == 0 ) { - - if( ptarg->fbp != texframe.tbp0 ) { - // look for a better target (metal slug 5) - list::iterator itbetter; - for(itbetter = listTargs.begin(); itbetter != listTargs.end(); ++itbetter ) { - if( (*itbetter)->fbp == texframe.tbp0 ) - break; - } - - if( itbetter != listTargs.end() ) { - it = listTargs.erase(it); - continue; - } - } - - static int sindex = 0; - char strtemp[25]; - sprintf(strtemp, "frames/frame%d.jpg", sindex++); -// D3DXSaveSurfaceToFile(strtemp, D3DXIFF_JPG, ptarg->psurf, NULL, NULL); -// if( g_bSaveFinalFrame ) -// D3DXSaveSurfaceToFile("frame1.tga", D3DXIFF_TGA, ptarg->psurf, NULL, NULL); - - int dby = pfb->DBY; - int movy = 0; - - // determine the rectangle to render - if( ptarg->fbp < texframe.tbp0 ) { - dby += (256/bpp)*(texframe.tbp0-ptarg->fbp)/texframe.tbw; - } - else if( ptarg->fbp > texframe.tbp0 ) { - dby -= (256/bpp)*(ptarg->fbp-texframe.tbp0)/texframe.tbw; - - if( dby < 0 ) { - movy = -dby; - dby = 0; - } - } - - int dh = min(ptarg->fbh - dby, texframe.th-movy); - - if( dh >= 64 ) { - - if( ptarg->fbh - dby < texframe.th-movy && !bUsingStencil ) { - - if( !bUsingStencil ) { - pd3dDevice->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 1, 0); - } - bUsingStencil = 1; - SETRS(D3DRS_STENCILENABLE, TRUE); - SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); - SETRS(D3DRS_STENCILFUNC, D3DCMP_NOTEQUAL); - SETRS(D3DRS_STENCILREF, 3); - SETRS(D3DRS_STENCILWRITEMASK, 1<fbh; - - // tex coords - v = DXVEC4(fiw*(float)texframe.tw, fih*(float)(dh), fiw*(float)(pfb->DBX), fih*((float)dby-0.5f)); - SETCONSTF(GPU_BITBLTTEX, v); - - // dest rect - v.x = 1; - v.y = dh/(float)texframe.th; - v.z = 0; - v.w = 1-v.y; - - if( movy > 0 ) - v.w -= movy/(float)texframe.th; - - if (bInterlace && interlace == (conf.interlace&1) ) { - // move down by 1 pixel - v.w += 1.0f / (float)dh; - } - - AdjustTransToAspect(v, (conf.options&GSOPTION_WIDESCREEN)?960:640, (conf.options&GSOPTION_WIDESCREEN)?540:480); - SETCONSTF(GPU_BITBLTPOS, v); - - // use GPU_INVTEXDIMS to store inverse texture dims - v.x = fiw; - v.y = fih; - v.z = 0; - SETCONSTF(GPU_INVTEXDIMS, v); - - // inside vb[0]'s target area, so render that region only - pd3dDevice->SetTexture(SAMP_FINAL, ptarg->ptex); - pd3dDevice->SetPixelShader(ppsCRTCTarg[bInterlace]); - - pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); - - if( abs(dh - (int)texframe.th) <= 1 ) { - bSkip = 1; - break; - } - if( abs(dh - (int)ptarg->fbh) <= 1 ) { - it = listTargs.erase(it); - continue; - } - } - } - - ++it; - } - - if( !bSkip ) { - for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) - (*it)->Resolve(); - - // context has to be 0 - SetTexVariablesInt(0, 2, texframe, g_MemTargs.GetMemoryTarget(texframe, 1), 1); - - if( g_bSaveFinalFrame ) - SaveTex(&texframe, g_bSaveFinalFrame-1>0); - - // finally render from the memory (note that the stencil buffer will keep previous regions) - v = DXVEC4(1,1,0,0); - - if (bInterlace && interlace == (conf.interlace)) { - // move down by 1 pixel - v.w += 1.0f / (float)texframe.th; - } - - AdjustTransToAspect(v, (conf.options&GSOPTION_WIDESCREEN)?960:640, (conf.options&GSOPTION_WIDESCREEN)?540:480); - SETCONSTF(GPU_BITBLTPOS, v); - - v = DXVEC4(texframe.tw,texframe.th,-0.5f,-0.5f); - SETCONSTF(GPU_BITBLTTEX, v); - - // use GPU_INVTEXDIMS to store inverse texture dims - v.x = 1.0f / (float)texframe.tw; - v.y = 1.0f / (float)texframe.th; - v.z = 0;//-0.5f * v.x; - v.w = -0.5f * v.y; - SETCONSTF(GPU_INVTEXDIMS, v); - - pd3dDevice->SetPixelShader(ppsCRTC[bInterlace]); - pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); - } - } - - if(1) {// || !bInterlace) { - s_bBeginScene = FALSE; - - ProcessMessages(); - - if( g_bMakeSnapshot ) { - RECT rctext; - char str[64]; - rctext.left = 200; rctext.top = 15; - sprintf(str, "ZeroGS %d.%d.%d - %.1f fps %s", revision, build, minor, fFPS, s_frameskipping?" - frameskipping":""); - - pSprite->Begin(D3DXSPRITE_ALPHABLEND|D3DXSPRITE_SORT_TEXTURE); - rctext.left += 1; - rctext.top += 1; - pFont->DrawText(pSprite, str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xff000000); - rctext.left -= 1; - rctext.top -= 1; - pFont->DrawText(pSprite, str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xffc0ffff); - pSprite->End(); - } - - if( g_bDisplayFPS ) { - RECT rctext; - char str[64]; - rctext.left = 10; rctext.top = 10; - sprintf(str, "%.1f fps", fFPS); - - pSprite->Begin(D3DXSPRITE_ALPHABLEND|D3DXSPRITE_SORT_TEXTURE); - rctext.left += 1; - rctext.top += 1; - pFont->DrawText(pSprite, str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xff000000); - rctext.left -= 1; - rctext.top -= 1; - pFont->DrawText(pSprite, str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xffc0ffff); - pSprite->End(); - } - - pd3dDevice->EndScene(); - if( pd3dDevice->Present(NULL, NULL, NULL, NULL) == D3DERR_DEVICELOST ) { - // device is lost, need to recreate - DEBUG_LOG("device lost\n"); - g_bIsLost = TRUE; - Reset(); - return; - } - - if( conf.options & GSOPTION_WIREFRAME ) { - // clear all targets - s_nWireframeCount = 1; - } - - if( g_bMakeSnapshot ) { - - if( SUCCEEDED(D3DXSaveSurfaceToFile(strSnapshot != ""?strSnapshot.c_str():"temp.jpg", (conf.options&GSOPTION_BMPSNAP)?D3DXIFF_BMP:D3DXIFF_JPG, psurfOrgTarg, NULL, NULL)) ) { - char str[255]; - sprintf(str, "saved %s\n", strSnapshot.c_str()); - AddMessage(str, 500); - } - g_bMakeSnapshot = 0; - } - - if( s_avicapturing ) { - CaptureFrame(); - } - - if( s_nNewWidth >= 0 && s_nNewHeight >= 0 && !g_bIsLost ) { - Reset(); - ChangeDeviceSize(s_nNewWidth, s_nNewHeight); - s_nNewWidth = s_nNewHeight = -1; - } - - // switch the fbp lists -// s_nCurFBPSet ^= 1; -// s_setFBP[s_nCurFBPSet].clear(); - //s_nCurFrameMap ^= 1; - //s_mapFrameHeights[s_nCurFrameMap].clear(); - } - - pd3dDevice->SetTexture(SAMP_FINAL, NULL); // d3d debug complains if not - g_MemTargs.DestroyCleared(); - - for(list::iterator it = s_vecTempTextures.begin(); it != s_vecTempTextures.end(); ++it) - (*it)->Release(); - s_vecTempTextures.clear(); - - if( EXTWRITE->WRITE&1 ) { - WARN_LOG("EXTWRITE\n"); - ExtWrite(); - EXTWRITE->WRITE = 0; - } - - if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); - SETRS(D3DRS_SCISSORTESTENABLE, TRUE); - - if( icurctx >= 0 ) { - vb[icurctx].bVarsSetTarg = FALSE; - vb[icurctx].bVarsTexSync = FALSE; - vb[0].bVarsTexSync = FALSE; - } - - // statistics - if( s_nWriteDepthCount > 0 ) { - assert( conf.mrtdepth ); - if( --s_nWriteDepthCount <= 0 ) { - s_bWriteDepth = FALSE; - } - } - - if( s_nWriteDestAlphaTest > 0 ) { - if( --s_nWriteDestAlphaTest <= 0 ) { - s_bDestAlphaTest = FALSE; - } - } - - if( g_GameSettings & GAME_AUTORESET ) { - s_nResolveCounts[s_nCurResolveIndex] = s_nResolved; - s_nCurResolveIndex = (s_nCurResolveIndex+1)%ARRAYSIZE(s_nResolveCounts); - - int total = 0; - for(int i = 0; i < ARRAYSIZE(s_nResolveCounts); ++i) total += s_nResolveCounts[i]; - - if( total / ARRAYSIZE(s_nResolveCounts) > 3 ) { - if( s_nLastResolveReset > (int)(fFPS * 8) ) { - // reset - DEBUG_LOG("ZeroGS: video mem reset\n"); - s_nLastResolveReset = 0; - memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); - - s_RTs.ResolveAll(); - s_RTs.Destroy(); - s_DepthRTs.ResolveAll(); - s_DepthRTs.Destroy(); - - vb[0].prndr = NULL; vb[0].pdepth = NULL; vb[0].bNeedFrameCheck = 1; vb[0].bNeedZCheck = 1; - vb[1].prndr = NULL; vb[1].pdepth = NULL; vb[1].bNeedFrameCheck = 1; vb[1].bNeedZCheck = 1; - } - } - - s_nLastResolveReset++; - } - - if( s_nResolved > 8 ) s_nResolved = 2; - else if( s_nResolved > 0 ) --s_nResolved; - - if( g_nDepthUsed > 0 ) --g_nDepthUsed; - - s_ClutResolve = 0; - s_PSM8Resolve = 0; - g_nDepthUpdateCount = 0; - - maxmin = 608; -} - -////////////////////////// -// Internal Definitions // -////////////////////////// - -__forceinline void MOVZ(VertexGPU *p, u32 gsz, const VB& curvb) -{ - p->z = curvb.zprimmask==0xffff?min((u32)0xffff, gsz):gsz; -} - -__forceinline void MOVFOG(VertexGPU *p, Vertex gsf) -{ - p->f = ((s16)(gsf).f<<7)|0x7f; -} - -__forceinline void SET_VERTEX(VertexGPU *p, int Index, const VB& curvb) -{ - int index = Index; - - p->x = (((int)gs.gsvertex[index].x - curvb.offset.x)>>1)&0xffff; - p->y = (((int)gs.gsvertex[index].y - curvb.offset.y)>>1)&0xffff; - - /*x = ((int)gs.gsvertex[index].x - curvb.offset.x); - y = ((int)gs.gsvertex[index].y - curvb.offset.y); - p.x = (x&0x7fff) | (x < 0 ? 0x8000 : 0); - p.y = (y&0x7fff) | (y < 0 ? 0x8000 : 0);*/ - - p->f = ((s16)gs.gsvertex[index].f<<7)|0x7f; - MOVZ(p, gs.gsvertex[index].z, curvb); - p->rgba = prim->iip ? gs.gsvertex[index].rgba : gs.rgba; - - if ((g_GameSettings & GAME_TEXAHACK) && !(p->rgba&0xffffff)) - p->rgba = 0; - if (prim->tme ) - { - if( prim->fst ) - { - p->s = (float)gs.gsvertex[index].u * fiTexWidth[prim->ctxt]; - p->t = (float)gs.gsvertex[index].v * fiTexHeight[prim->ctxt]; - p->q = 1; - } - else - { - p->s = gs.gsvertex[index].s; - p->t = gs.gsvertex[index].t; - p->q = gs.gsvertex[index].q; - } - } -} - -#define OUTPUT_VERT(fn, vert, id) { \ - fn("%c%d(%d): xyzf=(%4d,%4d,0x%x,%3d), rgba=0x%8.8x, stq = (%2.5f,%2.5f,%2.5f)\n", id==0?'*':' ', id, prim->prim, vert.x/8, vert.y/8, vert.z, vert.f/128, \ - vert.rgba, Clamp(vert.s, -10, 10), Clamp(vert.t, -10, 10), Clamp(vert.q, -10, 10)); \ -} \ - - -void ZeroGS::KickPoint() -{ - assert( gs.primC >= 1 ); - - VB& curvb = vb[prim->ctxt]; - if (curvb.bNeedTexCheck) curvb.FlushTexData(); - - if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) - { - assert( vb[prim->ctxt].dwCount == 0 ); - Flush(!prim->ctxt); - } - - if( curvb.dwCount >= POINT_BUFFERFLUSH) - Flush(prim->ctxt); - - curvb.Lock(); - int last = (gs.primIndex+2)%ARRAYSIZE(gs.gsvertex); - - VertexGPU* p = curvb.pbuf+curvb.dwCount; - SET_VERTEX(&p[0], last, curvb); - curvb.dwCount++; - -#ifdef PRIM_LOG - OUTPUT_VERT(PRIM_LOG, p[0], 0); -#endif -} - -void ZeroGS::KickLine() -{ - assert( gs.primC >= 2 ); - VB& curvb = vb[prim->ctxt]; - if( curvb.bNeedTexCheck ) - curvb.FlushTexData(); - - if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) - { - assert( vb[prim->ctxt].dwCount == 0 ); - Flush(!prim->ctxt); - } - - if( curvb.dwCount >= POINT_BUFFERFLUSH/2 ) - Flush(prim->ctxt); - - curvb.Lock(); - int next = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); - int last = (gs.primIndex+2)%ARRAYSIZE(gs.gsvertex); - - VertexGPU* p = curvb.pbuf+curvb.dwCount*2; - SET_VERTEX(&p[0], next, curvb); - SET_VERTEX(&p[1], last, curvb); - - curvb.dwCount++; - -#ifdef PRIM_LOG - OUTPUT_VERT(PRIM_LOG, p[0], 0); - OUTPUT_VERT(PRIM_LOG, p[1], 1); -#endif -} - -void ZeroGS::KickTriangle() -{ - assert( gs.primC >= 3 ); - VB& curvb = vb[prim->ctxt]; - if (curvb.bNeedTexCheck) curvb.FlushTexData(); - - if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) - { - assert( vb[prim->ctxt].dwCount == 0 ); - Flush(!prim->ctxt); - } - - if( curvb.dwCount >= POINT_BUFFERFLUSH/3 ) - Flush(prim->ctxt); - - curvb.Lock(); - VertexGPU* p = curvb.pbuf+curvb.dwCount*3; - SET_VERTEX(&p[0], 0, curvb); - SET_VERTEX(&p[1], 1, curvb); - SET_VERTEX(&p[2], 2, curvb); - - curvb.dwCount++; - -#ifdef PRIM_LOG - OUTPUT_VERT(PRIM_LOG, p[0], 0); - OUTPUT_VERT(PRIM_LOG, p[1], 1); - OUTPUT_VERT(PRIM_LOG, p[2], 2); -#endif -} - -void ZeroGS::KickTriangleFan() -{ - assert( gs.primC >= 3 ); - VB& curvb = vb[prim->ctxt]; - if (curvb.bNeedTexCheck) curvb.FlushTexData(); - - if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) - { - assert( vb[prim->ctxt].dwCount == 0 ); - Flush(!prim->ctxt); - } - - if( curvb.dwCount >= POINT_BUFFERFLUSH/3 ) - Flush(prim->ctxt); - - curvb.Lock(); - VertexGPU* p = curvb.pbuf+curvb.dwCount*3; - SET_VERTEX(&p[0], 0, curvb); - SET_VERTEX(&p[1], 1, curvb); - SET_VERTEX(&p[2], 2, curvb); - - curvb.dwCount++; - - // add 1 to skip the first vertex - if( gs.primIndex == gs.nTriFanVert ) - gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); - -#ifdef PRIM_LOG - OUTPUT_VERT(PRIM_LOG, p[0], 0); - OUTPUT_VERT(PRIM_LOG, p[1], 1); - OUTPUT_VERT(PRIM_LOG, p[2], 2); -#endif -} - -__forceinline void SetKickVertex(VertexGPU *p, Vertex v, int next, const VB& curvb) -{ - SET_VERTEX(p, next, curvb); - MOVZ(p, v.z, curvb); - MOVFOG(p, v); -} - -void ZeroGS::KickSprite() -{ - assert( gs.primC >= 2 ); - VB& curvb = vb[prim->ctxt]; - if( curvb.bNeedTexCheck ) - curvb.FlushTexData(); - - if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) - { - assert( vb[prim->ctxt].dwCount == 0 ); - Flush(!prim->ctxt); - } - - if (curvb.dwCount >= POINT_BUFFERFLUSH/3) Flush(prim->ctxt); - - curvb.Lock(); - int next = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); - int last = (gs.primIndex+2)%ARRAYSIZE(gs.gsvertex); - - // sprite is too small and AA shows lines (tek4) - if( s_AAx ) - { - gs.gsvertex[last].x += 4; - if (s_AAy) gs.gsvertex[last].y += 4; - } - - // might be bad sprite (KH dialog text) - //if( gs.gsvertex[next].x == gs.gsvertex[last].x || gs.gsvertex[next].y == gs.gsvertex[last].y ) - // return; - - VertexGPU* p = curvb.pbuf+curvb.dwCount*3; - - SetKickVertex(&p[0], gs.gsvertex[last], next, curvb); - SetKickVertex(&p[3], gs.gsvertex[last], next, curvb); - SetKickVertex(&p[1], gs.gsvertex[last], last, curvb); - SetKickVertex(&p[4], gs.gsvertex[last], last, curvb); - - if (g_MaxRenderedHeight < p[0].y) g_MaxRenderedHeight = p[0].y; - if (g_MaxRenderedHeight < p[1].y) g_MaxRenderedHeight = p[1].y; - - SetKickVertex(&p[2], gs.gsvertex[last], next, curvb); - p[2].s = p[1].s; - p[2].x = p[1].x; - - SetKickVertex(&p[5], gs.gsvertex[last], last, curvb); - p[5].s = p[0].s; - p[5].x = p[0].x; - - curvb.dwCount += 2; - -#ifdef PRIM_LOG - OUTPUT_VERT(PRIM_LOG, p[0], 0); - OUTPUT_VERT(PRIM_LOG, p[1], 1); -#endif -} - -void ZeroGS::KickDummy() -{ - //GREG_LOG("Kicking bad primitive: %.8x\n", *(u32*)prim); -} - -__forceinline void ZeroGS::RenderFBA(const VB& curvb) -{ - // add fba to all pixels - SETRS(D3DRS_STENCILWRITEMASK, STENCIL_CLEAR); - SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); - SETRS(D3DRS_STENCILFAIL, D3DSTENCILOP_ZERO); - SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); - SETRS(D3DRS_STENCILREF, STENCIL_FBA); - - SETRS(D3DRS_ZENABLE, FALSE); - SETRS(D3DRS_ZWRITEENABLE, FALSE); - SETRS(D3DRS_COLORWRITEENABLE, 0); - - if( s_bWriteDepth ) { - if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); - else pd3dDevice->SetRenderTarget(1, NULL); - } - - SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); - SETRS(D3DRS_ALPHATESTENABLE, TRUE); - SETRS(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); - SETRS(D3DRS_ALPHAREF, 0xff); - - DXVEC4 v; - v.x = 1; v.y = 2; v.z = 0; v.w = 0; - SETCONSTF(GPU_ONECOLOR, v); - - DRAW(); - - if( !curvb.test.ate ) - SETRS(D3DRS_ALPHATESTENABLE, FALSE); - else { - SETRS(D3DRS_ALPHAFUNC, g_dwAlphaCmp[curvb.test.atst]); - SETRS(D3DRS_ALPHAREF, b2XAlphaTest ? min(255,2 * curvb.test.aref) : curvb.test.aref); - } - - // reset (not necessary) - SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); - SETRS(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); - - if( !curvb.zbuf.zmsk ) { - SETRS(D3DRS_ZWRITEENABLE, TRUE); - - assert( curvb.pdepth != NULL ); - if( s_bWriteDepth ) { - if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); - else pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); - } - } - SETRS(D3DRS_ZENABLE, curvb.test.zte); -} - -__forceinline void ZeroGS::RenderAlphaTest(const VB& curvb) -{ - if( !g_bUpdateStencil ) return; - - if( curvb.test.ate ) { - if( curvb.test.afail == 1 ) SETRS(D3DRS_ALPHATESTENABLE, FALSE); - } - - SETRS(D3DRS_ZWRITEENABLE, FALSE); - SETRS(D3DRS_COLORWRITEENABLE, 0); - - DXVEC4 v; - v.x = 1; v.y = 2; v.z = 0; v.w = 0; - SETCONSTF(GPU_ONECOLOR, v); - - if( s_bWriteDepth ) { - if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); - else pd3dDevice->SetRenderTarget(1,NULL); - } - - // or a 1 to the stencil buffer wherever alpha passes - SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); - SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); - - SETRS(D3DRS_STENCILENABLE, TRUE); - - if( !s_bDestAlphaTest ) { - // clear everything - SETRS(D3DRS_STENCILREF, 0); - SETRS(D3DRS_STENCILWRITEMASK, STENCIL_CLEAR); - SETRS(D3DRS_ALPHATESTENABLE, FALSE); - DRAW(); - - if( curvb.test.ate && curvb.test.afail != 1 && USEALPHATESTING) - SETRS(D3DRS_ALPHATESTENABLE, TRUE); - } - - if( curvb.test.ate && curvb.test.atst>1 && curvb.test.aref > 0x80) { - v.x = 1; v.y = 1; v.z = 0; v.w = 0; - SETCONSTF(GPU_ONECOLOR, v); - SETRS(D3DRS_ALPHAREF, curvb.test.aref); - } - - SETRS(D3DRS_STENCILREF, STENCIL_SPECIAL); - SETRS(D3DRS_STENCILWRITEMASK, STENCIL_SPECIAL); - SETRS(D3DRS_ZENABLE, FALSE); - - DRAW(); - - if( curvb.test.zte ) SETRS(D3DRS_ZENABLE, TRUE); - SETRS(D3DRS_ALPHATESTENABLE, 0); - SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); - - if( !curvb.zbuf.zmsk ) { - SETRS(D3DRS_ZWRITEENABLE, TRUE); - - // set rt next level - if( s_bWriteDepth ) { - if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); - else pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); - } - } -} - -__forceinline void ZeroGS::RenderStencil(const VB& curvb, DWORD dwUsingSpecialTesting) -{ - //NOTE: This stencil hack for dest alpha testing ONLY works when - // the geometry in one DrawPrimitive call does not overlap - - // mark the stencil buffer for the new data's bits (mark 4 if alpha is >= 0xff) - // mark 4 if a pixel was written (so that the stencil buf can be changed with new values) - SETRS(D3DRS_STENCILWRITEMASK, STENCIL_PIXELWRITE); - - dwStencilMask = (curvb.test.date?STENCIL_ALPHABIT:0)|(dwUsingSpecialTesting?STENCIL_SPECIAL:0); - SETRS(D3DRS_STENCILMASK, dwStencilMask); - SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); - SETRS(D3DRS_STENCILFUNC, dwStencilMask ? D3DCMP_EQUAL : D3DCMP_ALWAYS); - - dwStencilRef = curvb.test.date*curvb.test.datm|STENCIL_PIXELWRITE|(dwUsingSpecialTesting?STENCIL_SPECIAL:0); - SETRS(D3DRS_STENCILREF, dwStencilRef); -} - -__forceinline void ZeroGS::ProcessStencil(const VB& curvb) -{ - assert( !curvb.fba.fba ); - - // set new alpha bit - SETRS(D3DRS_STENCILWRITEMASK, STENCIL_ALPHABIT); - SETRS(D3DRS_STENCILMASK, STENCIL_PIXELWRITE|STENCIL_FBA); - SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); - SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); - SETRS(D3DRS_STENCILREF, STENCIL_PIXELWRITE); - - SETRS(D3DRS_ZENABLE, FALSE); - SETRS(D3DRS_ZWRITEENABLE, FALSE); - SETRS(D3DRS_COLORWRITEENABLE, 0); - - if( s_bWriteDepth ) { - if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); - else pd3dDevice->SetRenderTarget(1, NULL); - } - - SETRS(D3DRS_ALPHATESTENABLE, 0); - - pd3dDevice->SetPixelShader(ppsOne); - DRAW(); - - // process when alpha >= 0xff - SETRS(D3DRS_STENCILREF, STENCIL_PIXELWRITE|STENCIL_FBA|STENCIL_ALPHABIT); - SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); - DRAW(); - - // clear STENCIL_PIXELWRITE bit - SETRS(D3DRS_STENCILWRITEMASK, STENCIL_CLEAR); - SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); - SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); - SETRS(D3DRS_STENCILREF, 0); - - DRAW(); - - // restore state - SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); - - if( curvb.test.ate && USEALPHATESTING) - SETRS(D3DRS_ALPHATESTENABLE, TRUE); - - if( !curvb.zbuf.zmsk ) { - SETRS(D3DRS_ZWRITEENABLE, TRUE); - - if( s_bWriteDepth ) { - assert( curvb.pdepth != NULL ); - if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); - else pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); - } - } - - SETRS(D3DRS_ZENABLE, curvb.test.zte); - - SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); -} - -__forceinline void ZeroGS::ProcessFBA(const VB& curvb) -{ - if( (curvb.frame.fbm&0x80000000) ) return; - - // add fba to all pixels that were written and alpha was less than 0xff - SETRS(D3DRS_STENCILWRITEMASK, STENCIL_ALPHABIT); - SETRS(D3DRS_STENCILMASK, STENCIL_PIXELWRITE|STENCIL_FBA); - SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); - SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); - SETRS(D3DRS_STENCILREF, STENCIL_FBA|STENCIL_PIXELWRITE|STENCIL_ALPHABIT); - - SETRS(D3DRS_ZENABLE, FALSE); - SETRS(D3DRS_ZWRITEENABLE, FALSE); - SETRS(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA); - - if( s_bWriteDepth ) { - if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); - else pd3dDevice->SetRenderTarget(1, NULL); - } - - // processes the pixels with ALPHA < 0x80*2 - SETRS(D3DRS_ALPHATESTENABLE, TRUE); - SETRS(D3DRS_ALPHAFUNC, D3DCMP_LESSEQUAL); - SETRS(D3DRS_ALPHAREF, 0xff); - - // add 1 to dest - SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); - SETRS(D3DRS_DESTBLENDALPHA, D3DBLEND_ONE); - SETRS(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD); - - float f = 1; - SETCONSTF(GPU_ONECOLOR, &f); - pd3dDevice->SetPixelShader(ppsOne); - - DRAW(); - - SETRS(D3DRS_ALPHATESTENABLE, FALSE); - - // reset bits - SETRS(D3DRS_STENCILWRITEMASK, STENCIL_CLEAR); - SETRS(D3DRS_STENCILMASK, STENCIL_PIXELWRITE|STENCIL_FBA); - SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_ZERO); - SETRS(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); - SETRS(D3DRS_STENCILFUNC, D3DCMP_GREATER); - SETRS(D3DRS_STENCILREF, 0); - - DRAW(); - - if( curvb.test.atst && USEALPHATESTING) { - SETRS(D3DRS_ALPHATESTENABLE, TRUE); - SETRS(D3DRS_ALPHAFUNC, g_dwAlphaCmp[curvb.test.atst]); - SETRS(D3DRS_ALPHAREF, b2XAlphaTest ? min(255,2 * curvb.test.aref) : curvb.test.aref); - } - - // restore (SetAlphaVariables) - if( !bNeedAlphaColor ) SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);//(bNeedBlendFactorInAlpha ? D3DBLEND_ZERO : D3DBLEND_ONE)); - SETRS(D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO);//bNeedBlendFactorInAlpha ? D3DBLEND_ONE : D3DBLEND_ZERO); - if(bNeedAlphaColor && vAlphaBlendColor.y<0) SETRS(D3DRS_BLENDOPALPHA, D3DBLENDOP_REVSUBTRACT); - - // reset (not necessary) - SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); - - if( !curvb.zbuf.zmsk ) { - SETRS(D3DRS_ZWRITEENABLE, TRUE); - - if( s_bWriteDepth ) { - if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); - else pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); - } - } - SETRS(D3DRS_ZENABLE, curvb.test.zte); -} - -inline void ZeroGS::SetContextTarget(int context) -{ - VB& curvb = vb[context]; - - if( curvb.prndr == NULL ) - curvb.prndr = s_RTs.GetTarg(curvb.frame, 0, GET_MAXHEIGHT(curvb.gsfb.fbp, curvb.gsfb.fbw, curvb.gsfb.psm)); - - // make sure targets are valid - if( curvb.pdepth == NULL ) { - frameInfo f; - f.fbp = curvb.zbuf.zbp; - f.fbw = curvb.frame.fbw; - f.fbh = curvb.prndr->fbh; - f.psm = curvb.zbuf.psm; - f.fbm = 0; - curvb.pdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| - (curvb.zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), GET_MAXHEIGHT(curvb.zbuf.zbp, curvb.gsfb.fbw, 0)); - } - - assert( curvb.prndr != NULL && curvb.pdepth != NULL ); - assert( curvb.pdepth->fbh == curvb.prndr->targheight ); - -// if( curvb.pdepth->fbh != curvb.prndr->fbh ) { -// -// s_DepthRTs.DestroyTarg(curvb.pdepth); -// ERROR_LOG("ZeroGS: render and depth heights different: %x %x\n", curvb.prndr->fbh, curvb.pdepth->fbh); -// frameInfo f; -// f.fbp = curvb.zbuf.zbp; -// f.fbw = curvb.frame.fbw; -// f.fbh = curvb.prndr->fbh; -// f.psm = curvb.zbuf.psm; -// f.fbm = 0; -// curvb.pdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| -// (curvb.zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), GET_MAXHEIGHT(curvb.zbuf.zbp, curvb.gsfb.fbw, 0)); -// } - - if( curvb.pdepth->status & CRenderTarget::TS_Virtual) { - - if( !curvb.zbuf.zmsk ) { - CRenderTarget* ptemp = s_DepthRTs.Promote(curvb.pdepth->fbp|(curvb.pdepth->fbw<<16)); - assert( ptemp == curvb.pdepth ); - } - else - curvb.pdepth->status &= ~CRenderTarget::TS_NeedUpdate; - } - - BOOL bSetTarg = 1; - if( curvb.pdepth->status & CRenderTarget::TS_NeedUpdate ) { - - assert( !(curvb.pdepth->status & CRenderTarget::TS_Virtual) ); - - // don't update if virtual - curvb.pdepth->Update(context, curvb.prndr); - bSetTarg = 0; - } - - if( curvb.prndr->status & CRenderTarget::TS_NeedUpdate ) { - - if( s_bWriteDepth ) { - if( bSetTarg ) { - pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); - pd3dDevice->SetDepthStencilSurface(curvb.pdepth->pdepth); - } - } - else if( bSetTarg ) - pd3dDevice->SetDepthStencilSurface(curvb.pdepth->pdepth); - - curvb.prndr->Update(context, curvb.pdepth); - // note, targ already set - } - else { - - //if( (vb[0].prndr != vb[1].prndr && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg ) - pd3dDevice->SetRenderTarget(0, curvb.prndr->psurf); - //if( bSetTarg && ((vb[0].pdepth != vb[1].pdepth && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg) ) - curvb.pdepth->SetDepthTarget(); - - if( s_ptexCurSet[0] == curvb.prndr->ptex ) { - s_ptexCurSet[0] = NULL; - pd3dDevice->SetTexture(SAMP_MEMORY0, NULL); - } - if( s_ptexCurSet[1] == curvb.prndr->ptex ) { - s_ptexCurSet[1] = NULL; - pd3dDevice->SetTexture(SAMP_MEMORY1, NULL); - } - - curvb.prndr->SetViewport(); - } - - curvb.prndr->SetTarget(curvb.frame.fbp, curvb.scissor, context); - - if( (curvb.zbuf.zbp-curvb.pdepth->fbp) != (curvb.frame.fbp - curvb.prndr->fbp) && curvb.test.zte ) { - WARN_LOG("frame and zbuf not aligned\n"); - } - - curvb.bVarsSetTarg = TRUE; - if( vb[!context].prndr != curvb.prndr ) - vb[!context].bVarsSetTarg = FALSE; - - assert( !(curvb.prndr->status&CRenderTarget::TS_NeedUpdate) ); - assert( curvb.pdepth == NULL || !(curvb.pdepth->status&CRenderTarget::TS_NeedUpdate) ); -} - -void ZeroGS::SetTexVariables(int context) -{ - if( !vb[context].curprim.tme ) { - return; - } - - assert( !vb[context].bNeedTexCheck ); - - DXVEC4 v, v2; - tex0Info& tex0 = vb[context].tex0; - - float fw = (float)tex0.tw; - float fh = (float)tex0.th; - - if( !vb[context].bTexConstsSync ) { - // alpha and texture highlighting - DXVEC4 valpha, valpha2; - - // if clut, use the frame format - int psm = tex0.psm; - if( PSMT_ISCLUT(tex0.psm) ) psm = tex0.cpsm; - - int nNeedAlpha = (psm == 1 || psm == 2 || psm == 10); - - DXVEC4 vblack; - vblack.x = vblack.y = vblack.z = vblack.w = 10; - - switch(tex0.tfx) { - case 0: - valpha.z = 0; valpha.w = 0; - valpha2.x = 0; valpha2.y = 0; - valpha2.z = 2; valpha2.w = 1; - - break; - case 1: - valpha.z = 0; valpha.w = 1; - valpha2.x = 1; valpha2.y = 0; - valpha2.z = 0; valpha2.w = 0; - - break; - case 2: - valpha.z = 1; valpha.w = 1.0f; - valpha2.x = 0; valpha2.y = tex0.tcc ? 1.0f : 0.0f; - valpha2.z = 2; valpha2.w = 0; - - break; - - case 3: - valpha.z = 1; valpha.w = tex0.tcc ? 0.0f : 1.0f; - valpha2.x = 0; valpha2.y = tex0.tcc ? 1.0f : 0.0f; - valpha2.z = 2; valpha2.w = 0; - - break; - default: __assume(0); - } - - if( tex0.tcc ) { - - if( tex0.tfx == 1 ) { - //mode.x = 10; - valpha.z = 0; valpha.w = 0; - valpha2.x = 1; valpha2.y = 1; - valpha2.z = 0; valpha2.w = 0; - } - - if( nNeedAlpha ) { - - if( tex0.tfx == 0 ) { - // make sure alpha is mult by two when the output is Cv = Ct*Cf - valpha.x = 2*gs.texa.fta[0]; - // if 24bit, always choose ta[0] - valpha.y = 2*gs.texa.fta[psm != 1]; - valpha.y -= valpha.x; - } - else { - valpha.x = gs.texa.fta[0]; - // if 24bit, always choose ta[0] - valpha.y = gs.texa.fta[psm != 1]; - valpha.y -= valpha.x; - } - - // need black detection - if( gs.texa.aem && psm == PSMCT24 ) - vblack.w = 0; - } - else { - if( tex0.tfx == 0 ) { - valpha.x = 0; - valpha.y = 2; - } - else { - valpha.x = 0; - valpha.y = 1; - } - } - } - else { - - // reset alpha to color - valpha.x = valpha.y = 0; - valpha.w = 1; - } - - SETCONSTF(GPU_TEXALPHA0+context, &valpha); - SETCONSTF(GPU_TEXALPHA20+context, &valpha2); - if( tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S) ) - SETCONSTF(GPU_TESTBLACK0+context, &vblack); - - // clamp relies on texture width - { - clampInfo* pclamp = &ZeroGS::vb[context].clamp; - DXVEC4 v, v2; - v.x = v.y = 0; - LPD3DTEX* ptex = ZeroGS::vb[context].ptexClamp; - ptex[0] = ptex[1] = NULL; - - float fw = ZeroGS::vb[context].tex0.tw; - float fh = ZeroGS::vb[context].tex0.th; - - switch(pclamp->wms) { - case 0: - v2.x = -1e10; v2.z = 1e10; - break; - case 1: // pclamp - // suikoden5 movie text - v2.x = 0; v2.z = 1-0.5f/fw; - break; - case 2: // reg pclamp - v2.x = (pclamp->minu+0.5f)/fw; v2.z = (pclamp->maxu-0.5f)/fw; - break; - - case 3: // region rep x - v.x = 0.9999f; - v.z = fw / (float)GPU_TEXMASKWIDTH; - v2.x = (float)GPU_TEXMASKWIDTH / fw; - v2.z = pclamp->maxu / fw; - - if( pclamp->minu != g_PrevBitwiseTexX ) { - g_PrevBitwiseTexX = pclamp->minu; - ptex[0] = ZeroGS::s_BitwiseTextures.GetTex(pclamp->minu, NULL); - } - break; - - default: __assume(0); - } - - switch(pclamp->wmt) { - case 0: - v2.y = -1e10; v2.w = 1e10; - break; - case 1: // pclamp - // suikoden5 movie text - v2.y = 0; v2.w = 1-0.5f/fh; - break; - case 2: // reg pclamp - v2.y = (pclamp->minv+0.5f)/fh; v2.w = (pclamp->maxv-0.5f)/fh; - break; - - case 3: // region rep y - v.y = 0.9999f; - v.w = fh / (float)GPU_TEXMASKWIDTH; - v2.y = (float)GPU_TEXMASKWIDTH / fh; - v2.w = pclamp->maxv / fh; - - if( pclamp->minv != g_PrevBitwiseTexY ) { - g_PrevBitwiseTexY = pclamp->minv; - ptex[1] = ZeroGS::s_BitwiseTextures.GetTex(pclamp->minv, ptex[0]); - } - break; - - default: __assume(0); - } - - SETCONSTF(GPU_TEXWRAPMODE0+context, v); - SETCONSTF(GPU_CLAMPEXTS0+context, v2); - } - - vb[context].bTexConstsSync = TRUE; - } - - if(s_bTexFlush ) { - if( PSMT_ISCLUT(tex0.psm) ) - texClutWrite(context); - else - s_bTexFlush = FALSE; - } -} - -void ZeroGS::SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, CMemoryTarget* pmemtarg, int force) -{ - DXVEC4 v; - assert( pmemtarg != NULL ); - - float fw = (float)tex0.tw; - float fh = (float)tex0.th; - - if( bilinear > 1 || (bilinear && conf.bilinear)) { - v.x = (float)fw; - v.y = (float)fh; - v.z = 1.0f / (float)fw; - v.w = 1.0f / (float)fh; - SETCONSTF(GPU_REALTEXDIMS0+context, v); - } - - if( m_Blocks[tex0.psm].bpp == 0 ) { - ERROR_LOG("ZeroGS: Undefined tex psm 0x%x!\n", tex0.psm); - return; - } - - const BLOCK& b = m_Blocks[tex0.psm]; - - float fbw = (float)tex0.tbw; - - v.x = b.vTexDims.x * fw; - v.y = b.vTexDims.y * fh; - v.z = (float)BLOCK_TEXWIDTH*(0.002f / 64.0f + 0.01f/128.0f); - v.w = (float)BLOCK_TEXHEIGHT*0.2f/512.0f; - - if( bilinear > 1 || (conf.bilinear && bilinear) ) { - v.x *= 1/128.0f; - v.y *= 1/512.0f; - v.z *= 1/128.0f; - v.w *= 1/512.0f; - } - SETCONSTF(GPU_TEXDIMS0+context, v); - - float g_fitexwidth = g_fiGPU_TEXWIDTH/(float)pmemtarg->widthmult; - float g_texwidth = GPU_TEXWIDTH*(float)pmemtarg->widthmult; - - SETCONSTF(GPU_TEXBLOCK0+context, &b.vTexBlock.x); - - float fpage = tex0.tbp0*(64.0f*g_fitexwidth) + 0.05f * g_fitexwidth; - float fpageint = floorf(fpage); - int starttbp = (int)fpage; - - // 2048 is number of words to span one page - float fblockstride = (2048.0f /(float)(g_texwidth*BLOCK_TEXWIDTH)) * b.vTexDims.x * fbw; - assert( fblockstride >= 1.0f ); - - v.x = (float)(2048 * g_fitexwidth); - v.y = fblockstride; - v.z = g_fBlockMult/(float)pmemtarg->widthmult; - v.w = fpage-fpageint; - - if( g_fBlockMult > 1 ) { - // make sure to divide by mult (since the G16R16 texture loses info) - v.z *= b.bpp * (1/32.0f); - } - - SETCONSTF(GPU_TEXOFFSET0+context, v); - - v.y = (float)1.0f / (float)((pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult); - v.x = (fpageint-(float)pmemtarg->realy/(float)pmemtarg->widthmult+0.5f)*v.y; - - SETCONSTF(GPU_PAGEOFFSET0+context, v); - - if( force ) { - pd3dDevice->SetTexture(SAMP_MEMORY0+context, pmemtarg->ptex); - s_ptexCurSet[context] = pmemtarg->ptex; - } - else s_ptexNextSet[context] = pmemtarg->ptex; - vb[context].pmemtarg = pmemtarg; - - vb[context].bVarsTexSync = FALSE; -} - -// assumes texture factor is unused -#define SET_ALPHA_COLOR_FACTOR(sign) { \ - switch(a.c) { \ - case 0: \ - bNeedAlphaColor = 1; \ - vAlphaBlendColor.y = (sign) ? 2.0f*255.0f/256.0f : -2.0f*255.0f/256.0f; \ - SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); \ - SETRS(D3DRS_BLENDOPALPHA, (sign) ? D3DBLENDOP_ADD : D3DBLENDOP_REVSUBTRACT); \ - break; \ - case 1: \ - /* if in 24 bit mode, dest alpha should be one */ \ - switch(vb[icurctx].prndr->psm&0xf) { \ - case 0: \ - bDestAlphaColor = (a.d!=2)&&((a.a==a.d)||(a.b==a.d)); \ - break; \ - case 1: \ - /* dest alpha should be one */ \ - bDestAlphaColor = 2; \ - break; \ - /* default: 16bit surface, so returned alpha is ok */ \ - } \ - break; \ - \ - case 2: \ - bNeedBlendFactorInAlpha = 1; /* should disable alpha channel writing */ \ - bNeedAlphaColor = 1; \ - vAlphaBlendColor.y = 0; \ - vAlphaBlendColor.w = (sign) ? (float)a.fix * (2.0f/255.0f) : (float)a.fix * (-2.0f/255.0f); \ - usec = 0; /* change so that alpha comes from source*/ \ - break; \ - } \ -} \ - -//if( a.fix <= 0x80 ) { \ -// dwTemp = (a.fix*2)>255?255:(a.fix*2); \ -// dwTemp = dwTemp|(dwTemp<<8)|(dwTemp<<16)|0x80000000; \ -// DEBUG_LOG("bfactor: %8.8x\n", dwTemp); \ -// SETRS(D3DRS_BLENDFACTOR, dwTemp); \ -// } \ -// else { \ - -void ZeroGS::ResetAlphaVariables() -{ - s_bAlphaSet = FALSE; -} - -void ZeroGS::SetAlphaVariables(const alphaInfo& a) -{ - SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); // always set - - if( s_bAlphaSet && a.abcd == s_alphaInfo.abcd && a.fix == s_alphaInfo.fix ) { - return; - } - - // TODO: negative color when not clamping turns to positive??? - g_vars._bAlphaState = 0; // set all to zero - bNeedBlendFactorInAlpha = 0; - b2XAlphaTest = 1; - DWORD dwTemp = 0xffffffff; - - // default - SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); - SETRS(D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO); - SETRS(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD); - - s_alphaInfo = a; - - vAlphaBlendColor = DXVEC4(1,2*255.0f/256.0f,0,0); - DWORD usec = a.c; - - if( a.a == a.b ) { // just d remains - SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); - - if( a.d == 0 ) { - SETRS(D3DRS_ALPHABLENDENABLE, 0); - } - else { - SETRS(D3DRS_DESTBLEND, a.d == 1 ? D3DBLEND_ONE : D3DBLEND_ZERO); - SETRS(D3DRS_SRCBLEND, D3DBLEND_ZERO); - SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); - } - - goto EndSetAlpha; - } - else if( a.d == 2 ) { // zero - - if( a.a == 2 ) { - // zero all color - SETRS(D3DRS_SRCBLEND, D3DBLEND_ZERO); - SETRS(D3DRS_DESTBLEND, D3DBLEND_ZERO); - goto EndSetAlpha; - } - else if( a.b == 2 ) { - //b2XAlphaTest = 1; - - SET_ALPHA_COLOR_FACTOR(1); - - if( bDestAlphaColor == 2 ) { - SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); - SETRS(D3DRS_SRCBLEND, a.a == 0 ? D3DBLEND_ONE : D3DBLEND_ZERO); - SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_ZERO : D3DBLEND_ONE); - } - else { - if( bNeedAlphaColor ) bAlphaClamping = 2; - - SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); - SETRS(D3DRS_SRCBLEND, a.a == 0 ? blendalpha[usec] : D3DBLEND_ZERO); - SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_ZERO : blendalpha[usec]); - } - - goto EndSetAlpha; - } - - // nothing is zero, so must do some real blending - //b2XAlphaTest = 1; - bAlphaClamping = 3; - - SET_ALPHA_COLOR_FACTOR(1); - - SETRS(D3DRS_BLENDOP, a.a == 0 ? D3DBLENDOP_SUBTRACT : D3DBLENDOP_REVSUBTRACT); - SETRS(D3DRS_SRCBLEND, bDestAlphaColor == 2 ? D3DBLEND_ONE : blendalpha[usec]); - SETRS(D3DRS_DESTBLEND, bDestAlphaColor == 2 ? D3DBLEND_ONE : blendalpha[usec]); - } - else if( a.a == 2 ) { // zero - - //b2XAlphaTest = 1; - bAlphaClamping = 1; // min testing - - SET_ALPHA_COLOR_FACTOR(1); - - if( a.b == a.d ) { - // can get away with 1-A - SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); - SETRS(D3DRS_SRCBLEND, (a.b == 0 && bDestAlphaColor != 2) ? blendinvalpha[usec] : D3DBLEND_ZERO); - SETRS(D3DRS_DESTBLEND, (a.b == 0 || bDestAlphaColor == 2) ? D3DBLEND_ZERO : blendinvalpha[usec]); - } - else { - SETRS(D3DRS_BLENDOP, a.b==0 ? D3DBLENDOP_REVSUBTRACT : D3DBLENDOP_SUBTRACT); - SETRS(D3DRS_SRCBLEND, (a.b == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : D3DBLEND_ONE); - SETRS(D3DRS_DESTBLEND, (a.b == 0 || bDestAlphaColor == 2 ) ? D3DBLEND_ONE : blendalpha[usec]); - } - } - else if( a.b == 2 ) { - bAlphaClamping = 2; // max testing - - SET_ALPHA_COLOR_FACTOR(a.a!=a.d); - - if( a.a == a.d ) { - // can get away with 1+A, but need to set alpha to negative - SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); - - if( bDestAlphaColor == 2 ) { - assert(usec==1); - - // all ones - bNeedAlphaColor = 1; - bNeedBlendFactorInAlpha = 1; - vAlphaBlendColor.y = 0; - vAlphaBlendColor.w = -1; - SETRS(D3DRS_SRCBLEND, a.a == 0 ? D3DBLEND_INVSRCALPHA : D3DBLEND_ZERO); - SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_ZERO : D3DBLEND_INVSRCALPHA); - } - else { - SETRS(D3DRS_SRCBLEND, a.a == 0 ? blendinvalpha[usec] : D3DBLEND_ZERO); - SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_ZERO : blendinvalpha[usec]); - } - } - else { - //b2XAlphaTest = 1; - SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); - SETRS(D3DRS_SRCBLEND, (a.a == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : D3DBLEND_ONE); - SETRS(D3DRS_DESTBLEND, (a.a == 0 || bDestAlphaColor == 2) ? D3DBLEND_ONE : blendalpha[usec]); - } - } - else { - // all 3 components are valid! - bAlphaClamping = 3; // all testing - SET_ALPHA_COLOR_FACTOR(a.a!=a.d); - - if( a.a == a.d ) { - // can get away with 1+A, but need to set alpha to negative - SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); - - if( bDestAlphaColor == 2 ) { - assert(usec==1); - - // all ones - bNeedAlphaColor = 1; - bNeedBlendFactorInAlpha = 1; - vAlphaBlendColor.y = 0; - vAlphaBlendColor.w = -1; - SETRS(D3DRS_SRCBLEND, a.a == 0 ? D3DBLEND_INVSRCALPHA : D3DBLEND_SRCALPHA); - SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_SRCALPHA : D3DBLEND_INVSRCALPHA); - } - else { - SETRS(D3DRS_SRCBLEND, a.a == 0 ? blendinvalpha[usec] : blendalpha[usec]); - SETRS(D3DRS_DESTBLEND, a.a == 0 ? blendalpha[usec] : blendinvalpha[usec]); - } - } - else { - assert(a.b == a.d); - SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); - - if( bDestAlphaColor == 2 ) { - assert(usec==1); - - // all ones - bNeedAlphaColor = 1; - bNeedBlendFactorInAlpha = 1; - vAlphaBlendColor.y = 0; - vAlphaBlendColor.w = 1; - SETRS(D3DRS_SRCBLEND, a.a != 0 ? D3DBLEND_INVSRCALPHA : D3DBLEND_SRCALPHA); - SETRS(D3DRS_DESTBLEND, a.a != 0 ? D3DBLEND_SRCALPHA : D3DBLEND_INVSRCALPHA); - } - else { - //b2XAlphaTest = 1; - SETRS(D3DRS_SRCBLEND, a.a != 0 ? blendinvalpha[usec] : blendalpha[usec]); - SETRS(D3DRS_DESTBLEND, a.a != 0 ? blendalpha[usec] : blendinvalpha[usec]); - } - } - } - -EndSetAlpha: - //b2XAlphaTest = b2XAlphaTest && bNeedAlphaColor && !bNeedBlendFactorInAlpha; - - INC_ALPHAVARS(); -} - -void ZeroGS::SetWriteDepth() -{ - if( conf.mrtdepth ) { - s_bWriteDepth = TRUE; - s_nWriteDepthCount = 4; - } -} - -BOOL ZeroGS::IsWriteDepth() -{ - return s_bWriteDepth; -} - -BOOL ZeroGS::IsWriteDestAlphaTest() -{ - return s_bWriteDepth; -} - -void ZeroGS::SetDestAlphaTest() -{ - s_bDestAlphaTest = TRUE; - s_nWriteDestAlphaTest = 4; -} - -void ZeroGS::SetFogColor(u32 fog) -{ - if( 1||gs.fogcol != fog ) { - gs.fogcol = fog; - - ZeroGS::Flush(0); - ZeroGS::Flush(1); - - if( !g_bIsLost ) { - DXVEC4 v; - - // set it immediately - v.x = (gs.fogcol&0xff)/255.0f; - v.y = ((gs.fogcol>>8)&0xff)/255.0f; - v.z = ((gs.fogcol>>16)&0xff)/255.0f; - SETCONSTF(GPU_FOGCOLOR, v); - } - } -} - -void ZeroGS::ExtWrite() -{ - WARN_LOG("ExtWrite\n"); - - // use local DISPFB, EXTDATA, EXTBUF, and PMODE -// int bpp, start, end; -// tex0Info texframe; - -// bpp = 4; -// if( texframe.psm == 0x12 ) bpp = 3; -// else if( texframe.psm & 2 ) bpp = 2; -// -// // get the start and end addresses of the buffer -// GetRectMemAddress(start, end, texframe.psm, 0, 0, texframe.tw, texframe.th, texframe.tbp0, texframe.tbw); -} - -//////////// -// Caches // -//////////// -#ifdef __x86_64__ -extern "C" void TestClutChangeMMX(void* src, void* dst, int entries, void* pret); -#endif - -bool ZeroGS::CheckChangeInClut(u32 highdword, u32 psm) -{ - int cld = (highdword >> 29) & 0x7; - int cbp = ((highdword >> 5) & 0x3fff); - - // processing the CLUT after tex0/2 are written - switch(cld) { - case 0: return false; - case 1: break; // Seems to rarely not be 1. - // note sure about changing cbp[0,1] - case 4: return gs.cbp[0] != cbp; - case 5: return gs.cbp[1] != cbp; - - // default: load - default: break; - } - - int cpsm = (highdword >> 19) & 0xe; - int csm = (highdword >> 23) & 0x1; - - if( cpsm > 1 || csm ) - // don't support 16bit for now - return true; - - int csa = (highdword >> 24) & 0x1f; - - int entries = (psm&3)==3 ? 256 : 16; - - u64* src = (u64*)(g_pbyGSMemory + cbp*256); - u64* dst = (u64*)(g_pbyGSClut+64*csa); - - bool bRet = false; - -#ifdef __x86_64__ - TestClutChangeMMX(dst, src, entries, &bRet); -#else - int storeebx; - // do a fast test with MMX - __asm { - mov storeebx, ebx - mov edx, dst - mov ecx, src - mov ebx, entries - -Start: - movq mm0, [edx] - movq mm1, [edx+8] - pcmpeqd mm0, [ecx] - pcmpeqd mm1, [ecx+16] - - movq mm2, [edx+16] - movq mm3, [edx+24] - pcmpeqd mm2, [ecx+32] - pcmpeqd mm3, [ecx+48] - - pand mm0, mm1 - pand mm2, mm3 - movq mm4, [edx+32] - movq mm5, [edx+40] - pcmpeqd mm4, [ecx+8] - pcmpeqd mm5, [ecx+24] - - pand mm0, mm2 - pand mm4, mm5 - movq mm6, [edx+48] - movq mm7, [edx+56] - pcmpeqd mm6, [ecx+40] - pcmpeqd mm7, [ecx+56] - - pand mm0, mm4 - pand mm6, mm7 - pand mm0, mm6 - - pmovmskb eax, mm0 - cmp eax, 0xff - je Continue - mov bRet, 1 - jmp Return - -Continue: - cmp ebx, 16 - jle Return - - test ebx, 0x10 - jz AddEcx - sub ecx, 448 // go back and down one column, -AddEcx: - add ecx, 256 // go to the right block - - cmp ebx, 0x90 - jne Continue1 - add ecx, 256 // skip whole block -Continue1: - add edx, 64 - sub ebx, 16 - jmp Start - } - -Return: - __asm { - emms - mov ebx, storeebx - } -#endif - - return bRet; -} - -void ZeroGS::texClutWrite(int ctx) -{ - s_bTexFlush = 0; - if( g_bIsLost ) - return; - - tex0Info& tex0 = vb[ctx].tex0; - assert( PSMT_ISCLUT(tex0.psm) ); - - // processing the CLUT after tex0/2 are written - switch(tex0.cld) { - case 0: return; - case 1: break; // tex0.cld is usually 1. - case 2: gs.cbp[0] = tex0.cbp; break; - case 3: gs.cbp[1] = tex0.cbp; break; - // not sure about changing cbp[0,1] - case 4: - if( gs.cbp[0] == tex0.cbp ) - return; - gs.cbp[0] = tex0.cbp; - break; - case 5: - if( gs.cbp[1] == tex0.cbp ) - return; - gs.cbp[1] = tex0.cbp; - break; - default: //DEBUG_LOG("cld isn't 0-5!"); - break; - } - - Flush(!ctx); - - int entries = (tex0.psm&3)==3 ? 256 : 16; -if (tex0.csm) - { - switch (tex0.cpsm) - { - // 16bit psm - // eggomania uses non16bit textures for csm2 - case PSMCT16: - { - u16* src = (u16*)g_pbyGSMemory + tex0.cbp*128; - u16 *dst = (u16*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0)); - - for (int i = 0; i < entries; ++i) - { - *dst = src[getPixelAddress16_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; - dst += 2; - - // check for wrapping - if (((u32)dst & 0x3ff) == 0) dst = (u16*)(g_pbyGSClut+2); - } - break; - } - - case PSMCT16S: - { - u16* src = (u16*)g_pbyGSMemory + tex0.cbp*128; - u16 *dst = (u16*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0)); - - for (int i = 0; i < entries; ++i) - { - *dst = src[getPixelAddress16S_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; - dst += 2; - - // check for wrapping - if (((u32)dst & 0x3ff) == 0) dst = (u16*)(g_pbyGSClut+2); - } - break; - } - - case PSMCT32: - case PSMCT24: - { - u32* src = (u32*)g_pbyGSMemory + tex0.cbp*64; - u32 *dst = (u32*)(g_pbyGSClut+64*tex0.csa); - - // check if address exceeds src - if( src+getPixelAddress32_0(gs.clut.cou+entries-1, gs.clut.cov, gs.clut.cbw) >= (u32*)g_pbyGSMemory + 0x00100000 ) - ERROR_LOG("texClutWrite out of bounds\n"); - else - for(int i = 0; i < entries; ++i) - { - *dst = src[getPixelAddress32_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; - dst++; - } - } - break; - - default: - { -#ifndef RELEASE_TO_PUBLIC - //DEBUG_LOG("unknown cpsm: %x (%x)\n", tex0.cpsm, tex0.psm); -#endif - break; - } - } - } - else - { - switch (tex0.cpsm) - { - case PSMCT24: - case PSMCT32: - if( entries == 16 ) - WriteCLUT_T32_I4_CSM1((u32*)(g_pbyGSMemory + tex0.cbp*256), (u32*)(g_pbyGSClut+64*tex0.csa)); - else - WriteCLUT_T32_I8_CSM1((u32*)(g_pbyGSMemory + tex0.cbp*256), (u32*)(g_pbyGSClut+64*tex0.csa)); - break; - - default: - if( entries == 16 ) - WriteCLUT_T16_I4_CSM1((u32*)(g_pbyGSMemory + 256 * tex0.cbp), (u32*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0))); - else // sse2 for 256 is more complicated, so use regular - WriteCLUT_T16_I8_CSM1_c((u32*)(g_pbyGSMemory + 256 * tex0.cbp), (u32*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0))); - break; - - } - } -} - -void ZeroGS::SetTexFlush() -{ - s_bTexFlush = TRUE; - -// if( PSMT_ISCLUT(vb[0].tex0.psm) ) -// texClutWrite(0); -// if( PSMT_ISCLUT(vb[1].tex0.psm) ) -// texClutWrite(1); - - if( !s_bForceTexFlush ) - { - if( s_ptexCurSet[0] != s_ptexNextSet[0] ) - { - s_ptexCurSet[0] = s_ptexNextSet[0]; - pd3dDevice->SetTexture(SAMP_MEMORY0, s_ptexNextSet[0]); - } - if( s_ptexCurSet[1] != s_ptexNextSet[1] ) - { - s_ptexCurSet[1] = s_ptexNextSet[1]; - pd3dDevice->SetTexture(SAMP_MEMORY1, s_ptexNextSet[1]); - } - } -} - -int ZeroGS::Save(char* pbydata) -{ - if( pbydata == NULL ) - return 40 + 0x00400000 + sizeof(gs) + 2*VBSAVELIMIT + 2*sizeof(frameInfo) + 4 + 256*4; - - s_RTs.ResolveAll(); - s_DepthRTs.ResolveAll(); - - vb[0].Unlock(); - vb[1].Unlock(); - - strcpy(pbydata, libraryName); - *(u32*)(pbydata+16) = ZEROGS_SAVEVER; - pbydata += 32; - - *(int*)pbydata = icurctx; pbydata += 4; - *(int*)pbydata = VBSAVELIMIT; pbydata += 4; - - memcpy(pbydata, g_pbyGSMemory, 0x00400000); - pbydata += 0x00400000; - - memcpy(pbydata, g_pbyGSClut, 256*4); - pbydata += 256*4; - - *(int*)pbydata = sizeof(gs); - pbydata += 4; - memcpy(pbydata, &gs, sizeof(gs)); - pbydata += sizeof(gs); - - for(int i = 0; i < 2; ++i) { - memcpy(pbydata, &vb[i], VBSAVELIMIT); - pbydata += VBSAVELIMIT; - } - - vb[0].Lock(); - vb[1].Lock(); - - return 0; -} - -extern u32 s_uTex1Data[2][2], s_uClampData[2]; -extern char *libraryName; -bool ZeroGS::Load(char* pbydata) -{ - memset(s_uTex1Data, 0, sizeof(s_uTex1Data)); - memset(s_uClampData, 0, sizeof(s_uClampData)); - - // first 32 bytes are the id - u32 savever = *(u32*)(pbydata+16); - - if( strncmp(pbydata, libraryName, 6) == 0 && (savever == ZEROGS_SAVEVER || savever == 0xaa000004) ) { - - g_MemTargs.Destroy(); - - GSStateReset(); - pbydata += 32; - - int context = *(int*)pbydata; pbydata += 4; - u32 savelimit = VBSAVELIMIT; - - savelimit = *(u32*)pbydata; pbydata += 4; - - memcpy(g_pbyGSMemory, pbydata, 0x00400000); - pbydata += 0x00400000; - - memcpy(g_pbyGSClut, pbydata, 256*4); - pbydata += 256*4; - - memset(&gs, 0, sizeof(gs)); - - int savedgssize; - if( savever == 0xaa000004 ) - savedgssize = 0x1d0; - else { - savedgssize = *(int*)pbydata; - pbydata += 4; - } - - memcpy(&gs, pbydata, savedgssize); - pbydata += savedgssize; - prim = &gs._prim[gs.prac]; - - LPD3DVB pvb = vb[0].pvb; - memcpy(&vb[0], pbydata, min(savelimit, VBSAVELIMIT)); - pbydata += savelimit; - vb[0].pvb = pvb; - - pvb = vb[1].pvb; - memcpy(&vb[1], pbydata, min(savelimit, VBSAVELIMIT)); - pbydata += savelimit; - vb[1].pvb = pvb; - - for(int i = 0; i < 2; ++i) { - vb[i].bNeedZCheck = vb[i].bNeedFrameCheck = 1; - - vb[i].bSyncVars = 0; vb[i].bNeedTexCheck = 1; - memset(vb[i].uCurTex0Data, 0, sizeof(vb[i].uCurTex0Data)); - } - - icurctx = -1; - - pd3dDevice->SetRenderTarget(0, psurfOrgTarg); - pd3dDevice->SetRenderTarget(1, NULL); - pd3dDevice->SetDepthStencilSurface(psurfOrgDepth); - SetFogColor(gs.fogcol); - - vb[0].Lock(); - vb[1].Lock(); - - return true; - } - - return false; -} - -void ZeroGS::SaveSnapshot(const char* filename) -{ - g_bMakeSnapshot = 1; - strSnapshot = filename; -} - -// AVI capture stuff -bool ZeroGS::StartCapture() -{ - if( !s_aviinit ) { - START_AVI("zerogs.avi"); - - assert( s_ptexAVICapture == NULL ); - if( FAILED(pd3dDevice->CreateOffscreenPlainSurface(width, height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &s_ptexAVICapture, NULL)) ) { - STOP_AVI(); - ZeroGS::AddMessage("Failed to create avi"); - return false; - } - - s_aviinit = 1; - } - else { - DEBUG_LOG("ZeroGS: Continuing from previous capture"); - } - - s_avicapturing = 1; - return true; -} - -void ZeroGS::StopCapture() -{ - s_avicapturing = 0; -} - -void ZeroGS::CaptureFrame() -{ - assert( s_avicapturing && s_aviinit && s_ptexAVICapture != NULL ); - - vector mem; - - pd3dDevice->GetRenderTargetData(psurfOrgTarg, s_ptexAVICapture); - - D3DLOCKED_RECT lock; - mem.resize(width * height * 4); - - s_ptexAVICapture->LockRect(&lock, NULL, D3DLOCK_READONLY); - assert( lock.Pitch == width*4 ); - - BYTE* pend = (BYTE*)lock.pBits + (conf.height-1)*width*4; - for(int i = 0; i < conf.height; ++i) { - memcpy_amd(&mem[width*4*i], pend - width*4*i, width * 4); - } - s_ptexAVICapture->UnlockRect(); - - int fps = SMODE1->CMOD == 3 ? 50 : 60; - bool bSuccess = ADD_FRAME_FROM_DIB_TO_AVI("AAAA", fps, width, height, 32, &mem[0]); - - if( !bSuccess ) { - s_avicapturing = 0; - STOP_AVI(); - s_aviinit = 0; - ZeroGS::AddMessage("Failed to create avi"); - return; - } -} +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#if defined(_WIN32) || defined(__WIN32__) +#include +#include +#include +#endif + +#include + +#include +#include +#include +#include +#include + +#include "GS.h" +#include "Mem.h" +#include "x86.h" +#include "Regs.h" +#include "zerogs.h" +#include "resource.h" + +#include "zerogsshaders/zerogsshaders.h" +#include "targets.h" + +#define DEBUG_PS2 0 + +#define POINT_BUFFERFLUSH 512 +#define POINT_BUFFERSIZE (1<<18) + +#define MINMAX_SHIFT 3 +#define MAX_ACTIVECLUTS 16 + +#define ZEROGS_SAVEVER 0xaa000005 + +#define STENCIL_ALPHABIT 1 // if set, dest alpha >= 0x80 +#define STENCIL_PIXELWRITE 2 // if set, pixel just written (reset after every Flush) +#define STENCIL_FBA 4 // if set, just written pixel's alpha >= 0 (reset after every Flush) +#define STENCIL_SPECIAL 8 // if set, indicates that pixel passed its alpha test (reset after every Flush) +//#define STENCIL_PBE 16 +#define STENCIL_CLEAR (2|4|8|16) + +#define VBSAVELIMIT ((u32)((u8*)&vb[0].nNextFrameHeight-(u8*)&vb[0])) + +using namespace ZeroGS; + +static LPDIRECT3D9 pD3D = NULL; // Used to create the D3DDevice +LPDIRECT3DDEVICE9 pd3dDevice = NULL; +static DXVEC4 s_vznorm; +extern u32 g_nGenVars, g_nTexVars, g_nAlphaVars, g_nResolve; +extern char *libraryName; +extern int g_nFrame, g_nRealFrame; +extern float fFPS; +extern unsigned char revision, build, minor; + +BOOL g_bDisplayMsg = 1; + +extern HINSTANCE hInst; + +BOOL g_bSaveFlushedFrame = 1; +BOOL g_bIsLost = 0; +int g_nFrameRender = 10; +int g_nFramesSkipped = 0; +int g_MaxRenderedHeight = 0; + +#ifdef RELEASE_TO_PUBLIC + +#define INC_GENVARS() +#define INC_TEXVARS() +#define INC_ALPHAVARS() +#define INC_RESOLVE() + +#define g_bUpdateEffect 0 +#define g_bWriteProfile 0 +#define g_bSaveTex 0 +#define g_bSaveTrans 0 +#define g_bSaveFrame 0 +#define g_bSaveFinalFrame 0 +#define g_bUpdateStencil 1 +#define g_bSaveResolved 0 + +#else + +#define INC_GENVARS() ++g_nGenVars +#define INC_TEXVARS() ++g_nTexVars +#define INC_ALPHAVARS() ++g_nAlphaVars +#define INC_RESOLVE() ++g_nResolve + +BOOL g_bSaveTrans = 0; +BOOL g_bUpdateEffect = 0; +BOOL g_bWriteProfile = 0; +BOOL g_bSaveTex = 0; // saves the curent texture +BOOL g_bSaveFrame = 0; // saves the current psurfTarget +BOOL g_bSaveFinalFrame = 0; // saves the input to the CRTC +BOOL g_bUpdateStencil = 1; // only needed for dest alpha test (unfortunately, it has to be on all the time) +BOOL g_bSaveResolved = 0; + +#endif + +#define DRAW() pd3dDevice->DrawPrimitive(primtype[curvb.curprim.prim], 0, curvb.dwCount) + +extern int s_frameskipping; + +//inline void SetRenderTarget_(int index, LPD3DSURF psurf, int counter, const char* pname) +//{ +// static LPD3DSURF ptargs[4] = {NULL}; +// static int counters[4] = {0}; +// static const char* pnames[4] = {NULL}; +// +// if( ptargs[index] == psurf && psurf != NULL ) +// DEBUG_LOG("duplicate targets\n"); +// pd3dDevice->SetRenderTarget(index, psurf); +// ptargs[index] = psurf; +// counters[index] = counter; +// pnames[index] = pname; +//} +// +//#define SetRenderTarget(index, psurf) SetRenderTarget_(index, psurf, __COUNTER__, __FUNCTION__) + +static u32 g_SaveFrameNum = 0; +BOOL g_bMakeSnapshot = 0; +string strSnapshot; + +int GPU_TEXWIDTH = 512; +float g_fiGPU_TEXWIDTH = 1/512.0f; + +int g_MaxTexWidth = 4096, g_MaxTexHeight = 4096; + +// AVI Capture +static int s_aviinit = 0; +static int s_avicapturing = 0; +static LPD3DSURF s_ptexAVICapture = NULL; // system memory texture + +const u32 g_primmult[8] = { 1, 2, 2, 3, 3, 3, 2, 0xff }; +const u32 g_primsub[8] = { 1, 2, 1, 3, 1, 1, 2, 0 }; + +inline DWORD FtoDW(float f) { return (*((DWORD*)&f)); } + +float g_fBlockMult = 1; +static int s_nFullscreen = 0; +int g_nDepthUpdateCount = 0; +int g_nDepthBias = 0; + +// Consts +static const D3DPRIMITIVETYPE primtype[8] = { D3DPT_POINTLIST, D3DPT_LINELIST, D3DPT_LINELIST, D3DPT_TRIANGLELIST, D3DPT_TRIANGLELIST, D3DPT_TRIANGLELIST, D3DPT_TRIANGLELIST, D3DPT_FORCE_DWORD }; +static const DWORD blendalpha[3] = { D3DBLEND_SRCALPHA, D3DBLEND_DESTALPHA, D3DBLEND_BLENDFACTOR }; +static const DWORD blendinvalpha[3] = { D3DBLEND_INVSRCALPHA, D3DBLEND_INVDESTALPHA, D3DBLEND_INVBLENDFACTOR }; + +static const int PRIMMASK = 0x0e; // for now ignore 0x10 (AA) + +static const DWORD g_dwAlphaCmp[] = { D3DCMP_NEVER, D3DCMP_ALWAYS, D3DCMP_LESS, D3DCMP_LESSEQUAL, + D3DCMP_EQUAL, D3DCMP_GREATEREQUAL, D3DCMP_GREATER, D3DCMP_NOTEQUAL }; + +// used for afail case +static const DWORD g_dwReverseAlphaCmp[] = { D3DCMP_ALWAYS, D3DCMP_NEVER, D3DCMP_GREATEREQUAL, D3DCMP_GREATER, + D3DCMP_NOTEQUAL, D3DCMP_LESS, D3DCMP_LESSEQUAL, D3DCMP_EQUAL }; + +static const DWORD g_dwZCmp[] = { D3DCMP_NEVER, D3DCMP_ALWAYS, D3DCMP_GREATEREQUAL, D3DCMP_GREATER }; + +///////////////////// +// graphics resources +static LPD3DDECL pdecl = NULL; +static LPD3DVS pvs[16] = {NULL}; +static LPD3DPS ppsRegular[4] = {NULL}, ppsTexture[NUM_SHADERS] = {NULL}; +static LPD3DPS ppsCRTC[2] = {NULL}, ppsCRTC24[2] = {NULL}, ppsCRTCTarg[2] = {NULL}; + +int g_nPixelShaderVer = SHADER_30; // default + +static BYTE* s_lpShaderResources = NULL; +static map mapShaderResources; + +LPD3DTEX s_ptexCurSet[2] = {NULL}; + +#define s_bForceTexFlush 1 +static LPD3DTEX s_ptexNextSet[2] = {NULL}; + +static ID3DXFont* pFont = NULL; +static ID3DXSprite* pSprite = NULL; + +static LPD3DSURF psurfOrgTarg = NULL, psurfOrgDepth = NULL; + +LPD3DTEX ptexBlocks = NULL, ptexConv16to32 = NULL; // holds information on block tiling +LPD3DTEX ptexBilinearBlocks = NULL; +IDirect3DVolumeTexture9* ptexConv32to16 = NULL; +static LPD3DTEX s_ptexInterlace = NULL; // holds interlace fields +static int s_nInterlaceTexWidth = 0; // width of texture +static list s_vecTempTextures; // temporary textures, released at the end of every frame + +static BOOL s_bTexFlush = FALSE; +static LPD3DTEX ptexLogo = NULL; +static BOOL s_bWriteDepth = FALSE; +static BOOL s_bDestAlphaTest = FALSE; +static int s_nLastResolveReset = 0; +static int s_nResolveCounts[30] = {0}; // resolve counts for last 30 frames +static int s_nCurResolveIndex = 0; +int s_nResolved = 0; // number of targets resolved this frame +int g_nDepthUsed = 0; // ffx2 pal movies +static int s_nWriteDepthCount = 0; +static int s_nWireframeCount = 0; +static int s_nWriteDestAlphaTest = 0; + +//////////////////// +// State parameters +static float fiRendWidth, fiRendHeight; + +static DWORD dwStencilRef, dwStencilMask; + +static DXVEC4 vAlphaBlendColor; // used for GPU_COLOR + +static BYTE bNeedBlendFactorInAlpha; // set if the output source alpha is different from the real source alpha (only when blend factor > 0x80) +static DWORD s_dwColorWrite = 0xf; // the color write mask of the current target + +BOOL g_bDisplayFPS = FALSE; + +union { + struct { + BYTE _bNeedAlphaColor; // set if vAlphaBlendColor needs to be set + BYTE _b2XAlphaTest; // Only valid when bNeedAlphaColor is set. if 1st bit set set, double all alpha testing values + // otherwise alpha testing needs to be done separately. + BYTE _bDestAlphaColor; // set to 1 if blending with dest color (process only one tri at a time). If 2, dest alpha is always 1. + BYTE _bAlphaClamping; // if first bit is set, do min; if second bit, do max + }; + u32 _bAlphaState; +} g_vars; + +#define bNeedAlphaColor g_vars._bNeedAlphaColor +#define b2XAlphaTest g_vars._b2XAlphaTest +#define bDestAlphaColor g_vars._bDestAlphaColor +#define bAlphaClamping g_vars._bAlphaClamping + +int g_PrevBitwiseTexX = -1, g_PrevBitwiseTexY = -1; // textures stored in SAMP_BITWISEANDX and SAMP_BITWISEANDY + +// stores the buffers for the last RenderCRTC +const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); + +static BOOL s_bAlphaSet = FALSE; +static alphaInfo s_alphaInfo; + +namespace ZeroGS +{ + VB vb[2]; + float fiTexWidth[2], fiTexHeight[2]; // current tex width and height + LONG width, height; + u8* g_pbyGSMemory = NULL; // 4Mb GS system mem + u8* g_pbyGSClut = NULL; + + D3DPRESENT_PARAMETERS d3dpp; + + BYTE s_AAx = 0, s_AAy = 0; // if AAy is set, then AAx has to be set + BYTE bIndepWriteMasks = 1; + BOOL s_bBeginScene = FALSE; + D3DFORMAT g_RenderFormat = D3DFMT_A16B16G16R16F; + int icurctx = -1; + + LPD3DVB pvbRect = NULL; + + DXVEC4 g_vdepth = DXVEC4(65536.0f, 256.0f, 1.0f, 65536.0f*256.0f); + + LPD3DVS pvsBitBlt = NULL, pvsBitBlt30 = NULL; + LPD3DPS ppsBitBlt[2] = {NULL}, ppsBitBltDepth[2] = {NULL}, ppsBitBltDepthTex[2] = {NULL}, ppsOne = NULL; + LPD3DPS ppsBaseTexture = NULL, ppsConvert16to32 = NULL, ppsConvert32to16 = NULL; + + extern CRangeManager s_RangeMngr; // manages overwritten memory + void FlushTransferRanges(const tex0Info* ptex); + + // returns the first and last addresses aligned to a page that cover + void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw); + + HRESULT LoadEffects(); + HRESULT LoadExtraEffects(); + LPD3DPS LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context); + + static int s_nNewWidth = -1, s_nNewHeight = -1; + void ChangeDeviceSize(int nNewWidth, int nNewHeight); + + void ProcessMessages(); + void RenderCustom(float fAlpha); // intro anim + + struct MESSAGE + { + MESSAGE() {} + MESSAGE(const char* p, DWORD dw) { strcpy(str, p); dwTimeStamp = dw; } + char str[255]; + DWORD dwTimeStamp; + }; + + static list listMsgs; + + /////////////////////// + // Method Prototypes // + /////////////////////// + + void AdjustTransToAspect(DXVEC4& v, int dispwidth, int dispheight); + + void KickPoint(); + void KickLine(); + void KickTriangle(); + void KickTriangleFan(); + void KickSprite(); + void KickDummy(); + + inline void SetContextTarget(int context); + + // use to update the d3d state + void SetTexVariables(int context); + void SetAlphaVariables(const alphaInfo& ainfo); + void ResetAlphaVariables(); + + __forceinline void SetAlphaTestInt(pixTest curtest); + + __forceinline void RenderAlphaTest(const VB& curvb); + __forceinline void RenderStencil(const VB& curvb, DWORD dwUsingSpecialTesting); + __forceinline void ProcessStencil(const VB& curvb); + __forceinline void RenderFBA(const VB& curvb); + __forceinline void ProcessFBA(const VB& curvb); + + void ResolveInRange(int start, int end); + + void ExtWrite(); + + inline LPD3DTEX CreateInterlaceTex(int width) { + if( width == s_nInterlaceTexWidth && s_ptexInterlace != NULL ) return s_ptexInterlace; + + SAFE_RELEASE(s_ptexInterlace); + s_nInterlaceTexWidth = width; + + HRESULT hr; + V(pd3dDevice->CreateTexture(width, 1, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &s_ptexInterlace, NULL)); + + D3DLOCKED_RECT lock; + s_ptexInterlace->LockRect(0, &lock, NULL, 0); + for(int i = 0; i < width; ++i) ((u32*)lock.pBits)[i] = (i&1) ? 0xffffffff : 0; + s_ptexInterlace->UnlockRect(0); + + return s_ptexInterlace; + } + + DrawFn drawfn[8] = { KickDummy, KickDummy, KickDummy, KickDummy, + KickDummy, KickDummy, KickDummy, KickDummy }; + +}; // end namespace + +/////////////////// +// Context State // +/////////////////// +ZeroGS::VB::VB() +{ + memset(this, 0, sizeof(VB)); + tex0.tw = 1; + tex0.th = 1; +} + +ZeroGS::VB::~VB() +{ + Destroy(); +} + +void ZeroGS::VB::Destroy() +{ + Unlock(); + SAFE_RELEASE(pvb); + + prndr = NULL; + pdepth = NULL; +} + +void ZeroGS::VB::Lock() +{ + assert(pvb != NULL); + if( pbuf == NULL ) + { + if( dwCurOff+POINT_BUFFERFLUSH > POINT_BUFFERSIZE ) dwCurOff = 0; + + pvb->Lock(dwCurOff*sizeof(VertexGPU), sizeof(VertexGPU)*POINT_BUFFERFLUSH, (void**)&pbuf, dwCurOff ? D3DLOCK_NOOVERWRITE|D3DLOCK_NOSYSLOCK : D3DLOCK_DISCARD|D3DLOCK_NOSYSLOCK); + dwCount = 0; + assert( pbuf != NULL ); + } +} + +bool ZeroGS::VB::CheckPrim() +{ + Lock(); + + if( (PRIMMASK & prim->_val) != (PRIMMASK & curprim._val) || primtype[prim->prim] != primtype[curprim.prim] ) + return dwCount > 0; + + return false; +} + +// upper bound on max possible height +#define GET_MAXHEIGHT(fbp, fbw, psm) ((((0x00100000-64*(fbp))/(fbw))&~0x1f)<<((psm&2)?1:0)) + +#include +static int maxmin = 608; +//static set s_setFBP[2]; // previous frame/zbuf pointers for the last 2 frames +//static int s_nCurFBPSet = 0; +//static map s_mapFrameHeights[2]; +//static int s_nCurFrameMap = 0; + +// a lot of times, target is too big and overwrites the texture using, if tbp != 0, use it to bound +void ZeroGS::VB::CheckFrame(int tbp) +{ + static int bChanged; + + if( bNeedZCheck ) { + PRIM_LOG("zbuf_%d: zbp=0x%x psm=0x%x, zmsk=%d\n", ictx, zbuf.zbp, zbuf.psm, zbuf.zmsk); + //zbuf = *zb; + } + + // invalid bpp + if( m_Blocks[gsfb.psm].bpp == 0 ) { + ERROR_LOG("CheckFrame invalid bpp %d\n", gsfb.psm); + return; + } + + bChanged = 0; + + if( gsfb.fbw <= 0 ) { + return; + } + + if( bNeedFrameCheck ) { + + int maxpos = 0x00100000; + + // important to set before calling GetTarg + bNeedFrameCheck = 0; + bNeedZCheck = 0; + + // add constraints of other targets + if( gsfb.fbw > 0 ) { + maxpos = 0x00100000-64*gsfb.fbp; + + // make sure texture is far away from tbp + if( gsfb.fbp < tbp && gsfb.fbp + 0x2000 < tbp) { + maxpos = min(64*(tbp-gsfb.fbp), maxpos); + } + if( prndr != NULL ) { + // offroad uses 0x80 fbp which messes up targets + if( gsfb.fbp + 0x80 < frame.fbp ) { + // special case when double buffering (hamsterball) + maxpos = min(64*(frame.fbp-gsfb.fbp), maxpos); + } + } + if( zbuf.zbp < tbp && !zbuf.zmsk ) { + maxpos = min((tbp-zbuf.zbp)*((zbuf.psm&2)?128:64), maxpos); + } + + // old caching method + if( gsfb.fbp < zbuf.zbp && !zbuf.zmsk ) { // zmsk necessary for KH movie + int temp = 64*(zbuf.zbp-gsfb.fbp);//min( (0x00100000-64*zbuf.zbp) , 64*(zbuf.zbp-gsfb.fbp) ); + maxpos = min(temp, maxpos); + } + + maxpos /= gsfb.fbw; + if( gsfb.psm & 2 ) + maxpos *= 2; + + maxpos = min(gsfb.fbh, maxpos); + maxpos = min(maxmin, maxpos); + //? atelier iris crashes without it + if( maxpos > 256 ) + maxpos &= ~0x1f; + } + else { + ERROR_LOG("render target null, ignoring\n"); + //prndr = NULL; + //pdepth = NULL; + return; + } + + gsfb.psm &= 0xf; // shadow tower + + if( prndr != NULL ) { + + // render target + if( prndr->psm != gsfb.psm ) { + // behavior for dest alpha varies + ResetAlphaVariables(); + } + } + + int fbh = (scissor.y1>>MINMAX_SHIFT)+1; + if( fbh > 2 && (fbh&1) ) fbh -= 1; + + if( !(gsfb.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) { + fbh = min(fbh, maxpos); + } + + frame = gsfb; + if (frame.fbw > 1024) frame.fbw = 1024; + +// if( fbh > 256 && (fbh % m_Blocks[gsfb.psm].height) <= 2 ) { +// // dragon ball z +// fbh -= fbh%m_Blocks[gsfb.psm].height; +// } + if( !(frame.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) + frame.fbh = fbh; + + if( !(frame.psm&2) ) {//|| !(g_GameSettings&GAME_FULL16BITRES) ) { + if( frame.fbh >= 512 ) { + // neopets hack + maxmin = min(maxmin, frame.fbh); + frame.fbh = maxmin; + } + } + + // mgs3 hack to get proper resolution, targets after 0x2000 are usually feedback + if( g_MaxRenderedHeight >= 0xe0 && frame.fbp >= 0x2000 ) { + int considerheight = (g_MaxRenderedHeight/8+31)&~31; + if( frame.fbh > considerheight ) + frame.fbh = considerheight; + else if( frame.fbh <= 32 ) + frame.fbh = considerheight; + + if( frame.fbh == considerheight ) { + // stops bad resolves (mgs3) + if( !curprim.abe && (!test.ate || test.atst == 0) ) + s_nResolved |= 0x100; + } + } + + // ffxii hack to stop resolving + if( !(frame.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) { + if( frame.fbp >= 0x3000 && fbh >= 0x1a0 ) { + int endfbp = frame.fbp + frame.fbw*fbh/((gsfb.psm&2)?128:64); + + // see if there is a previous render target in the way, reduce + for(CRenderTargetMngr::MAPTARGETS::iterator itnew = s_RTs.mapTargets.begin(); itnew != s_RTs.mapTargets.end(); ++itnew) { + if( itnew->second->fbp > frame.fbp && endfbp > itnew->second->fbp ) { + endfbp = itnew->second->fbp; + } + } + + frame.fbh = (endfbp-frame.fbp)*((gsfb.psm&2)?128:64)/frame.fbw; + } + } + + CRenderTarget* pprevrndr = prndr; + CDepthTarget* pprevdepth = pdepth; + + // reset so that Resolve doesn't call Flush + prndr = NULL; + pdepth = NULL; + + CRenderTarget* pnewtarg = s_RTs.GetTarg(frame, 0, maxmin); + assert( pnewtarg != NULL ); + + // pnewtarg->fbh >= 0x1c0 needed for ffx + if( pnewtarg->fbh >= 0x1c0 && pnewtarg->fbh > frame.fbh && zbuf.zbp < tbp && !zbuf.zmsk ) { + // check if zbuf is in the way of the texture (suikoden5) + int maxallowedfbh = (tbp-zbuf.zbp)*((zbuf.psm&2)?128:64) / gsfb.fbw; + if( gsfb.psm & 2 ) + maxallowedfbh *= 2; + + if( pnewtarg->fbh > maxallowedfbh+32 ) { // +32 needed for ffx2 + // destroy and recreate + s_RTs.DestroyAll(0, 0x100, pnewtarg->fbw); + pnewtarg = s_RTs.GetTarg(frame, 0, maxmin); + assert( pnewtarg != NULL ); + } + } + + PRIM_LOG("frame_%d: fbp=0x%x fbw=%d fbh=%d(%d) psm=0x%x fbm=0x%x\n", ictx, gsfb.fbp, gsfb.fbw, gsfb.fbh, pnewtarg->fbh, gsfb.psm, gsfb.fbm); + + if( (pprevrndr != pnewtarg) || (prndr != NULL && (prndr->status & CRenderTarget::TS_NeedUpdate)) ) + bChanged = 1; + + prndr = pnewtarg; + + // update z + frameInfo tempfb; + tempfb.fbw = prndr->fbw; + tempfb.fbp = zbuf.zbp; + tempfb.psm = zbuf.psm; + tempfb.fbh = prndr->targheight; + if( zbuf.psm == 0x31 ) tempfb.fbm = 0xff000000; + else tempfb.fbm = 0; + + // check if there is a target that exactly aligns with zbuf (zbuf can be cleared this way, gunbird 2) + //u32 key = zbuf.zbp|(frame.fbw<<16); + //CRenderTargetMngr::MAPTARGETS::iterator it = s_RTs.mapTargets.find(key); +// if( it != s_RTs.mapTargets.end() ) { +//#ifdef _DEBUG +// DEBUG_LOG("zbuf resolve\n"); +//#endif +// if( it->second->status & CRenderTarget::TS_Resolved ) +// it->second->Resolve(); +// } + + CDepthTarget* pnewdepth = (CDepthTarget*)s_DepthRTs.GetTarg(tempfb, CRenderTargetMngr::TO_DepthBuffer | + CRenderTargetMngr::TO_StrictHeight|(zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), + prndr->targheight);//GET_MAXHEIGHT(zbuf.zbp, gsfb.fbw, 0)); + assert( pnewdepth != NULL && prndr != NULL ); + assert( pnewdepth->fbh == prndr->targheight ); + + if( (pprevdepth != pnewdepth) || (pdepth != NULL && (pdepth->status & CRenderTarget::TS_NeedUpdate)) ) + bChanged |= 2; + + pdepth = pnewdepth; + + if( prndr->status & CRenderTarget::TS_NeedConvert32) { + if( pdepth->pdepth != NULL ) + pd3dDevice->SetDepthStencilSurface(pdepth->pdepth); + prndr->fbh *= 2; + prndr->targheight *= 2; + prndr->ConvertTo32(); + prndr->status &= ~CRenderTarget::TS_NeedConvert32; + } + else if( prndr->status & CRenderTarget::TS_NeedConvert16 ) { + if( pdepth->pdepth != NULL ) + pd3dDevice->SetDepthStencilSurface(pdepth->pdepth); + prndr->fbh /= 2; + prndr->targheight /= 2; + prndr->ConvertTo16(); + prndr->status &= ~CRenderTarget::TS_NeedConvert16; + } + } + else if( bNeedZCheck ) { + + bNeedZCheck = 0; + CDepthTarget* pprevdepth = pdepth; + pdepth = NULL; + + if( prndr != NULL && gsfb.fbw > 0 ) { + // just z changed + frameInfo f; + f.fbp = zbuf.zbp; + f.fbw = prndr->fbw; + f.fbh = prndr->fbh; + f.psm = zbuf.psm; + + if( zbuf.psm == 0x31 ) f.fbm = 0xff000000; + else f.fbm = 0; + CDepthTarget* pnewdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| + (zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), prndr->fbh);//GET_MAXHEIGHT(zbuf.zbp, gsfb.fbw, 0)); + + assert( pnewdepth != NULL && prndr != NULL ); + assert( pnewdepth->fbh == prndr->fbh ); + + if( (pprevdepth != pnewdepth) || (pdepth != NULL && (pdepth->status & CRenderTarget::TS_NeedUpdate)) ) + bChanged = 2; + + pdepth = pnewdepth; + } + } + + s_nResolved &= 0xff; // restore + + if( prndr != NULL ) + SetContextTarget(ictx); + + //if( prndr != NULL && ictx == icurctx) + //else bVarsSetTarg = 0; + +// if( prndr != NULL && bChanged ) { +// if( ictx == icurctx ) SetContextTarget(icurctx); +// else +// bVarsSetTarg = 0; +// } +} + +void ZeroGS::VB::FlushTexData() +{ + assert( bNeedTexCheck ); + + bNeedTexCheck = 0; + + u32 psm = (uNextTex0Data[0] >> 20) & 0x3f; + if( psm == 9 ) psm = 1; // hmm..., ffx intro menu + + // don't update unless necessary + if( uCurTex0Data[0] == uNextTex0Data[0] && (uCurTex0Data[1]&0x1f) == (uNextTex0Data[1]&0x1f) ) { + + if( PSMT_ISCLUT(psm) ) { + + // have to write the CLUT again if changed + if( (uCurTex0Data[1]&0x1fffffe0) == (uNextTex0Data[1]&0x1fffffe0) ) { + + if( uNextTex0Data[1]&0xe0000000 ) { + //ZeroGS::Flush(ictx); + ZeroGS::texClutWrite(ictx); + // invalidate to make sure target didn't change! + bVarsTexSync = FALSE; + } + + return; + } + + if( (uNextTex0Data[1]&0xe0000000) == 0 ) { + + if( (uCurTex0Data[1]&0x1ff10000) != (uNextTex0Data[1]&0x1ff10000) ) + ZeroGS::Flush(ictx); + + // clut isn't going to be loaded so can ignore, but at least update CSA and CPSM! + uCurTex0Data[1] = (uCurTex0Data[1]&0xe087ffff)|(uNextTex0Data[1]&0x1f780000); + + if( tex0.cpsm <= 1 ) tex0.csa = (uNextTex0Data[1] >> 24) & 0xf; + else tex0.csa = (uNextTex0Data[1] >> 24) & 0x1f; + + tex0.cpsm = (uNextTex0Data[1] >> 19) & 0xe; + ZeroGS::texClutWrite(ictx); + + bVarsTexSync = FALSE; + return; + } + + // fall through + } + else { + //bVarsTexSync = FALSE; + return; + } + } + + ZeroGS::Flush(ictx); + bVarsTexSync = FALSE; + bTexConstsSync = FALSE; + + uCurTex0Data[0] = uNextTex0Data[0]; + uCurTex0Data[1] = uNextTex0Data[1]; + + tex0.tbp0 = (uNextTex0Data[0] & 0x3fff); + tex0.tbw = ((uNextTex0Data[0] >> 14) & 0x3f) * 64; + tex0.psm = psm; + tex0.tw = (uNextTex0Data[0] >> 26) & 0xf; + if (tex0.tw > 10) tex0.tw = 10; + tex0.tw = 1<> 30) & 0x3) | ((uNextTex0Data[1] & 0x3) << 2); + if (tex0.th > 10) tex0.th = 10; + tex0.th = 1<> 2) & 0x1; + tex0.tfx = (uNextTex0Data[1] >> 3) & 0x3; + + ZeroGS::fiTexWidth[ictx] = (1/16.0f)/ tex0.tw; + ZeroGS::fiTexHeight[ictx] = (1/16.0f) / tex0.th; + + if (tex0.tbw == 0) tex0.tbw = 64; + + if( PSMT_ISCLUT(psm) ) { + tex0.cbp = ((uNextTex0Data[1] >> 5) & 0x3fff); + tex0.cpsm = (uNextTex0Data[1] >> 19) & 0xe; + tex0.csm = (uNextTex0Data[1] >> 23) & 0x1; + + if( tex0.cpsm <= 1 ) tex0.csa = (uNextTex0Data[1] >> 24) & 0xf; + else tex0.csa = (uNextTex0Data[1] >> 24) & 0x1f; + + tex0.cld = (uNextTex0Data[1] >> 29) & 0x7; + + ZeroGS::texClutWrite(ictx); + } +} + +// does one time only initializing/destruction +class ZeroGSInit +{ +public: + ZeroGSInit() { + // clear + g_pbyGSMemory = (u8*)_aligned_malloc(0x00410000, 1024); // leave some room for out of range accesses (saves on the checks) + memset(g_pbyGSMemory, 0, 0x00410000); + + g_pbyGSClut = (u8*)_aligned_malloc(256*8, 1024); // need 512 alignment! + memset(g_pbyGSClut, 0, 256*8); + } + ~ZeroGSInit() { + _aligned_free(g_pbyGSMemory); g_pbyGSMemory = NULL; + _aligned_free(g_pbyGSClut); g_pbyGSClut = NULL; + } +}; + +static ZeroGSInit s_ZeroGSInit; + +HRESULT ZeroGS::Create(LONG _width, LONG _height) +{ + Destroy(1); + GSStateReset(); + + width = _width; + height = _height; + fiRendWidth = 1.0f / width; + fiRendHeight = 1.0f / height; + + HRESULT hr; + + if( NULL == (pD3D = Direct3DCreate9(D3D_SDK_VERSION)) ) { + ERROR_LOG(_T("Failed to create the direct3d interface.")); + return E_FAIL; + } + + D3DDISPLAYMODE d3ddm; + if( FAILED( hr = pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) ) { + ERROR_LOG(_T("Error geting default adapter.")); + return hr; + } + + if( conf.options & GSOPTION_FULLSCREEN ) { + // choose best mode +// RECT rcdesktop; +// GetWindowRect(GetDesktopWindow(), &rcdesktop); +// width = rcdesktop.right - rcdesktop.left; +// height = rcdesktop.bottom - rcdesktop.top; + +// width = height = 0; +// D3DDISPLAYMODE d3ddmtemp; +// +// int modes = pD3D->GetAdapterModeCount(D3DADAPTER_DEFAULT, d3ddm.Format); +// for(int i= 0; i < modes; ++i) { +// pD3D->EnumAdapterModes(D3DADAPTER_DEFAULT, d3ddm.Format, i, &d3ddmtemp); +// +// if( abs(1024-(int)d3ddmtemp.Width) <= abs(1280-width) && abs(768-(int)d3ddmtemp.Height) <= abs(1024-height) ) { +// width = d3ddmtemp.Width; +// height = d3ddmtemp.Height; +// } +// } + } + else { + // change to default resolution + ChangeDisplaySettings(NULL, 0); + } + + // Set up the structure used to create the D3DDevice. Since we are now + // using more complex geometry, we will create a device with a zbuffer. + ZeroMemory( &d3dpp, sizeof(d3dpp) ); + d3dpp.Windowed = !(conf.options & GSOPTION_FULLSCREEN); + d3dpp.hDeviceWindow = GShwnd; + d3dpp.SwapEffect = (conf.options & GSOPTION_FULLSCREEN) ? D3DSWAPEFFECT_FLIP : D3DSWAPEFFECT_DISCARD; + d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; + d3dpp.EnableAutoDepthStencil = TRUE; + d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; + d3dpp.BackBufferWidth = width; + d3dpp.BackBufferHeight = height; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;//(conf.options & GSOPTION_FULLSCREEN) ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Flags = DEBUG_PS2 ? D3DPRESENTFLAG_LOCKABLE_BACKBUFFER : 0; + + s_nFullscreen = (conf.options & GSOPTION_FULLSCREEN) ? 1 : 0; + + // Create the D3DDevice + UINT adapter = D3DADAPTER_DEFAULT; + D3DDEVTYPE devtype = !DEBUG_PS2 ? D3DDEVTYPE_HAL : D3DDEVTYPE_REF; + +#ifndef _DEBUG + DWORD hwoptions = D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_PUREDEVICE; +#else + DWORD hwoptions = D3DCREATE_HARDWARE_VERTEXPROCESSING; +#endif + +#ifndef RELEASE_TO_PUBLIC + for(UINT i = 0; i < pD3D->GetAdapterCount(); ++i) { + D3DADAPTER_IDENTIFIER9 id; + HRESULT hr = pD3D->GetAdapterIdentifier(i, 0, &id); + if( strcmp(id.Description, "NVIDIA NVPerfHUD") == 0 ) { + DEBUG_LOG("Using %s adapter\n", id.Description); + adapter = i; + devtype = D3DDEVTYPE_REF; + break; + } + } +#endif + + if( FAILED( hr = pD3D->CreateDevice( adapter, devtype, GShwnd, + !DEBUG_PS2 ? hwoptions : D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice ) ) ) + { + ERROR_LOG(_T("Failed to create hardware device, creating software.\n")); + + if( FAILED( hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GShwnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &d3dpp, &pd3dDevice ) ) ) + { + ERROR_LOG(_T("Failed to create software device, switching to reference rasterizer.\n")); + + if( FAILED( hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, GShwnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &d3dpp, &pd3dDevice ) ) ) + return hr; + } + } + + // get caps and check if gfx card is ok + D3DCAPS9 caps; + pd3dDevice->GetDeviceCaps(&caps); + + if( caps.VertexShaderVersion < D3DVS_VERSION(2,0) ) { + ERROR_LOG("*********\nGS ERROR: Need at least vs2.0\n*********\n"); + Destroy(1); + return E_FAIL; + } + + conf.mrtdepth = 1; + + if( caps.NumSimultaneousRTs == 1 ) { + ERROR_LOG("*********\nGS WARNING: Need at least 2 simultaneous render targets. Some zbuffer effects will look wrong\n*********\n"); + conf.mrtdepth = 0; + } + if( !(caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) ) { + ERROR_LOG("*********\nGS ERROR: Need separate alpha blending! Some effects will look bad\n*********\n"); + } + if( !(caps.PrimitiveMiscCaps & D3DPMISCCAPS_INDEPENDENTWRITEMASKS) ) { + ERROR_LOG("******\nGS WARNING: Need independent write masks! Some z buffer effects might look bad\n*********\n"); + bIndepWriteMasks = 0; + } + + if( !(caps.PrimitiveMiscCaps & D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING) ) { + ERROR_LOG("******\nGS WARNING: Need MRT Post Pixel Shader Blending for some effects\n*********\n"); + } + + hr = pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, + D3DUSAGE_RENDERTARGET|D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, g_RenderFormat); + + if( g_GameSettings & GAME_32BITTARGS ) { + g_RenderFormat = D3DFMT_A8R8G8B8; + ERROR_LOG("Setting 32 bit render target\n"); + } + else if( FAILED(hr) ) { + ERROR_LOG("******\nGS ERROR: Device doesn't support alpha blending for 16bit floating point targets.\nQuality will reduce.\n*********\n"); + g_RenderFormat = D3DFMT_A8R8G8B8; + } + +// hr = pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_G32R32F); +// +// if( FAILED(hr) ) { +// ERROR_LOG("******\nGS ERROR: Device doesn't support G32R32F textures.\nTextures will look bad.\n*********\n"); +// } + + g_MaxTexWidth = caps.MaxTextureWidth; + g_MaxTexHeight = caps.MaxTextureHeight; + GPU_TEXWIDTH = caps.MaxTextureWidth/8; + g_fiGPU_TEXWIDTH = 1.0f / GPU_TEXWIDTH; + + //g_RenderFormat = D3DFMT_A8R8G8B8; + + pd3dDevice->GetRenderTarget(0, &psurfOrgTarg); + pd3dDevice->GetDepthStencilSurface(&psurfOrgDepth); + + SETRS(D3DRS_ZENABLE, TRUE); + SETRS(D3DRS_LIGHTING, FALSE); + SETRS(D3DRS_SPECULARENABLE, FALSE); + + V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, + "Arial", &pFont ) ); + + // create the vertex decl + const D3DVERTEXELEMENT9 Decl[] = { + { 0, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, + { 0, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }, + { 0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, + { 0, 16, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 }, + D3DDECL_END() }; + V_RETURN(pd3dDevice->CreateVertexDeclaration(Decl, &pdecl)); + +#ifdef RELEASE_TO_PUBLIC + HRSRC hShaderSrc = FindResource(hInst, MAKEINTRESOURCE(IDR_SHADERS), RT_RCDATA); + assert( hShaderSrc != NULL ); + HGLOBAL hShaderGlob = LoadResource(hInst, hShaderSrc); + assert( hShaderGlob != NULL ); + s_lpShaderResources = (BYTE*)LockResource(hShaderGlob); +#endif + + // load the effect + ERROR_LOG("Creating effects\n"); + V_RETURN(LoadEffects()); + + g_bDisplayMsg = 0; + if( caps.VertexShaderVersion >= D3DVS_VERSION(3,0) && caps.PixelShaderVersion >= D3DPS_VERSION(2,0) ) + g_nPixelShaderVer = SHADER_30; + else if( caps.PixelShaderVersion == D3DPS_VERSION(2,0) ) + g_nPixelShaderVer = SHADER_20; + else + g_nPixelShaderVer = SHADER_20a; + +#ifdef RELEASE_TO_PUBLIC + // create a sample shader + clampInfo temp; + memset(&temp, 0, sizeof(temp)); + temp.wms = 3; temp.wmt = 3; + + if( g_nPixelShaderVer != SHADER_30 ) { + // test more + if( LoadShadeEffect(0, 1, 1, 1, 1, temp, 0) == NULL ) { + g_nPixelShaderVer = SHADER_20b; + if( LoadShadeEffect(0, 1, 1, 1, 1, temp, 0) == NULL ) { + + g_nPixelShaderVer = SHADER_20; + if( LoadShadeEffect(0, 0, 1, 1, 0, temp, 0) == NULL ) { + + ERROR_LOG("*********\nGS ERROR: Need at least ps2.0 (ps2.0a+ recommended)\n*********\n"); + Destroy(1); + return E_FAIL; + } + } + } + } +#endif + + // set global shader constants + pd3dDevice->SetPixelShaderConstantF(27, DXVEC4(0.5f, (g_GameSettings&GAME_EXACTCOLOR)?0.9f/256.0f:0.5f/256.0f, 0,1/255.0f), 1); // g_fExactColor + pd3dDevice->SetPixelShaderConstantF(28, DXVEC4(-0.7f, -0.65f, 0.9f,0), 1); // g_fBilinear + pd3dDevice->SetPixelShaderConstantF(29, DXVEC4(1.0f/256.0f, 1.0004f, 1, 0.5f), 1); // g_fZBias + pd3dDevice->SetPixelShaderConstantF(30, DXVEC4(0,1, 0.001f, 0.5f), 1); // g_fc0 + pd3dDevice->SetPixelShaderConstantF(31, DXVEC4(1/1024.0f, 0.2f/1024.0f, 1/128.0f, 1/512.0f), 1); // g_fMult + + pd3dDevice->SetVertexShaderConstantF(29, DXVEC4(1.0f/256.0f, 1.0004f, 1, 0.5f), 1); // g_fZBias + pd3dDevice->SetVertexShaderConstantF(30, DXVEC4(0,1, 0.001f, 0.5f), 1); // g_fc0 + pd3dDevice->SetVertexShaderConstantF(31, DXVEC4(0.5f, -0.5f, 0.5f, 0.5f + 0.4f/416.0f), 1); // g_fBitBltTrans + + g_bDisplayMsg = 1; + if( g_nPixelShaderVer == SHADER_20 ) + conf.bilinear = 0; + + ERROR_LOG("Creating extra effects\n"); + V_RETURN(LoadExtraEffects()); + + ERROR_LOG("GS Using pixel shaders %s\n", g_pShaders[g_nPixelShaderVer]); + + pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER, 0, 1, 0); + + // init draw fns + drawfn[0] = KickPoint; + drawfn[1] = KickLine; + drawfn[2] = KickLine; + drawfn[3] = KickTriangle; + drawfn[4] = KickTriangle; + drawfn[5] = KickTriangleFan; + drawfn[6] = KickSprite; + drawfn[7] = KickDummy; + + SetAA(conf.aa); + GSsetGameCRC(g_LastCRC, g_GameSettings); + + return S_OK; +} + +void ZeroGS::Destroy(BOOL bD3D) +{ + DeleteDeviceObjects(); + + vb[0].Destroy(); + vb[1].Destroy(); + + for(int i = 0; i < ARRAYSIZE(pvs); ++i) { + SAFE_RELEASE(pvs[i]); + } + for(int i = 0; i < ARRAYSIZE(ppsRegular); ++i) { + SAFE_RELEASE(ppsRegular[i]); + } + for(int i = 0; i < ARRAYSIZE(ppsTexture); ++i) { + SAFE_RELEASE(ppsTexture[i]); + } + + SAFE_RELEASE(pvsBitBlt); + SAFE_RELEASE(pvsBitBlt30); + SAFE_RELEASE(ppsBitBlt[0]); SAFE_RELEASE(ppsBitBlt[1]); + SAFE_RELEASE(ppsBitBltDepth[0]); SAFE_RELEASE(ppsBitBltDepth[1]); + SAFE_RELEASE(ppsBitBltDepthTex[0]); SAFE_RELEASE(ppsBitBltDepthTex[1]); + SAFE_RELEASE(ppsCRTCTarg[0]); SAFE_RELEASE(ppsCRTCTarg[1]); + SAFE_RELEASE(ppsCRTC[0]); SAFE_RELEASE(ppsCRTC[1]); + SAFE_RELEASE(ppsCRTC24[0]); SAFE_RELEASE(ppsCRTC24[1]); + SAFE_RELEASE(ppsOne); + + SAFE_RELEASE(pdecl); + SAFE_RELEASE(pFont); + SAFE_RELEASE(psurfOrgTarg); + SAFE_RELEASE(psurfOrgDepth); + + if( bD3D ) { + SAFE_RELEASE(pd3dDevice); + SAFE_RELEASE(pD3D); + } +} + +void ZeroGS::GSStateReset() +{ + icurctx = -1; + + for(int i = 0; i < 2; ++i) { + LPD3DVB pvb = vb[i].pvb; + if( pvb != NULL ) pvb->AddRef(); + vb[i].Destroy(); + memset(&vb[i], 0, sizeof(VB)); + + vb[i].tex0.tw = 1; + vb[i].tex0.th = 1; + vb[i].pvb = pvb; + vb[i].scissor.x1 = 639; + vb[i].scissor.y1 = 479; + vb[i].tex0.tbw = 64; + } + + s_RangeMngr.Clear(); + g_MemTargs.Destroy(); + s_RTs.Destroy(); + s_DepthRTs.Destroy(); + s_BitwiseTextures.Destroy(); + + vb[0].ictx = 0; + vb[1].ictx = 1; + s_bAlphaSet = FALSE; +} + +void ZeroGS::AddMessage(const char* pstr, DWORD ms) +{ + listMsgs.push_back(MESSAGE(pstr, timeGetTime()+ms)); +} + +void ZeroGS::ChangeWindowSize(int nNewWidth, int nNewHeight) +{ + width = nNewWidth > 16 ? nNewWidth : 16; + height = nNewHeight > 16 ? nNewHeight : 16; + + if( !(conf.options & GSOPTION_FULLSCREEN) ) { + conf.width = nNewWidth; + conf.height = nNewHeight; + //SaveConfig(); + } +} + +void ZeroGS::SetChangeDeviceSize(int nNewWidth, int nNewHeight) +{ + s_nNewWidth = nNewWidth; + s_nNewHeight = nNewHeight; + + if( !(conf.options & GSOPTION_FULLSCREEN) ) { + conf.width = nNewWidth; + conf.height = nNewHeight; + //SaveConfig(); + } +} + +void ZeroGS::Reset() +{ + s_RTs.ResolveAll(); + s_DepthRTs.ResolveAll(); + + vb[0].Unlock(); + vb[1].Unlock(); + + memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); + s_nLastResolveReset = 0; + + icurctx = -1; + + GSStateReset(); + Destroy(0); + + drawfn[0] = KickDummy; + drawfn[1] = KickDummy; + drawfn[2] = KickDummy; + drawfn[3] = KickDummy; + drawfn[4] = KickDummy; + drawfn[5] = KickDummy; + drawfn[6] = KickDummy; + drawfn[7] = KickDummy; +} + +void ZeroGS::ChangeDeviceSize(int nNewWidth, int nNewHeight) +{ + int oldscreen = s_nFullscreen; + + int oldwidth = width, oldheight = height; + if( FAILED(Create(nNewWidth&~7, nNewHeight&~7)) ) { + DEBUG_LOG("Failed to recreate, changing to old\n"); + if( FAILED(Create(oldwidth, oldheight)) ) { + MessageBox(NULL, "failed to create dev, exiting...\n", "Error", MB_OK); + exit(0); + } + } + + if( FAILED(InitDeviceObjects()) ) { + MessageBox(NULL, "failed to init dev objs, exiting...\n", "Error", MB_OK); + exit(0); + } + + for(int i = 0; i < 2; ++i) { + vb[i].bNeedFrameCheck = vb[i].bNeedZCheck = 1; + vb[i].CheckFrame(0); + } + + if( oldscreen && !(conf.options & GSOPTION_FULLSCREEN) ) { // if transitioning from full screen + RECT rc; + rc.left = 0; rc.top = 0; + rc.right = conf.width; rc.bottom = conf.height; + AdjustWindowRect(&rc, conf.winstyle, FALSE); + + RECT rcdesktop; + GetWindowRect(GetDesktopWindow(), &rcdesktop); + + SetWindowLong( GShwnd, GWL_STYLE, conf.winstyle ); + SetWindowPos(GShwnd, HWND_TOP, ((rcdesktop.right-rcdesktop.left)-(rc.right-rc.left))/2, + ((rcdesktop.bottom-rcdesktop.top)-(rc.bottom-rc.top))/2, + rc.right-rc.left, rc.bottom-rc.top, SWP_SHOWWINDOW); + UpdateWindow(GShwnd); + } + + vb[0].Lock(); + vb[1].Lock(); + + assert( vb[0].pbuf != NULL && vb[1].pbuf != NULL ); +} + +void ZeroGS::SetAA(int mode) +{ + float f; + + // need to flush all targets + s_RTs.ResolveAll(); + s_RTs.Destroy(); + s_DepthRTs.ResolveAll(); + s_DepthRTs.Destroy(); + + s_AAx = s_AAy = 0; + if( mode > 0 ) + { + s_AAx = (mode+1) / 2; + s_AAy = mode / 2; + } + memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); + s_nLastResolveReset = 0; + + vb[0].prndr = NULL; vb[0].pdepth = NULL; vb[0].bNeedFrameCheck = 1; vb[0].bNeedZCheck = 1; + vb[1].prndr = NULL; vb[1].pdepth = NULL; vb[1].bNeedFrameCheck = 1; vb[1].bNeedZCheck = 1; + + f = mode > 0 ? 2.0f : 1.0f; + SETRS(D3DRS_POINTSIZE, FtoDW(f)); +} + +#ifdef RELEASE_TO_PUBLIC + +#define LOAD_VS(Index, ptr) { \ + assert( mapShaderResources.find(Index) != mapShaderResources.end() ); \ + header = mapShaderResources[Index]; \ + assert( (header) != NULL && (header)->index == (Index) ); \ + hr = pd3dDevice->CreateVertexShader((DWORD*)(s_lpShaderResources + (header)->offset), &(ptr)); \ + if( FAILED(hr) || ptr == NULL ) { \ + DEBUG_LOG("errors 0x%x for %d, failed.. try updating your drivers or dx\n", hr, Index); \ + return E_FAIL; \ + } \ +} \ + +#define LOAD_PS(index, ptr) { \ + assert( mapShaderResources.find(index) != mapShaderResources.end() ); \ + header = mapShaderResources[index]; \ + hr = pd3dDevice->CreatePixelShader((DWORD*)(s_lpShaderResources + (header)->offset), &(ptr)); \ + if( FAILED(hr) || ptr == NULL ) { \ + DEBUG_LOG("errors 0x%x for %s, failed.. try updating your drivers or dx\n", hr, index); \ + return E_FAIL; \ + } \ +} \ + +HRESULT ZeroGS::LoadEffects() +{ + assert( s_lpShaderResources != NULL ); + + // process the header + DWORD num = *(DWORD*)s_lpShaderResources; + SHADERHEADER* header = (SHADERHEADER*)((BYTE*)s_lpShaderResources + 4); + + mapShaderResources.clear(); + while(num-- > 0 ) { + mapShaderResources[header->index] = header; + ++header; + } + + // clear the textures + for(int i = 0; i < ARRAYSIZE(ppsTexture); ++i) { + SAFE_RELEASE(ppsTexture[i]); + } + memset(ppsTexture, 0, sizeof(ppsTexture)); + + return S_OK; +} + +// called +HRESULT ZeroGS::LoadExtraEffects() +{ + HRESULT hr; + + SHADERHEADER* header; + + DWORD mask = g_nPixelShaderVer == SHADER_30 ? SH_30 : 0; + + const int vsshaders[4] = { SH_REGULARVS, SH_TEXTUREVS, SH_REGULARFOGVS, SH_TEXTUREFOGVS }; + for(int i = 0; i < 4; ++i) { + LOAD_VS(vsshaders[i]|mask, pvs[2*i]); + LOAD_VS(vsshaders[i]|mask|SH_CONTEXT1, pvs[2*i+1]); + LOAD_VS(vsshaders[i]|mask|SH_WRITEDEPTH, pvs[2*i+8]); + LOAD_VS(vsshaders[i]|mask|SH_WRITEDEPTH|SH_CONTEXT1, pvs[2*i+8+1]); + } + + LOAD_VS(SH_BITBLTVS, pvsBitBlt); + //LOAD_VS(SH_BITBLTVS|SH_30, pvsBitBlt30); + + LOAD_PS(SH_REGULARPS|mask, ppsRegular[0]); + LOAD_PS(SH_REGULARFOGPS|mask, ppsRegular[1]); + LOAD_PS(SH_REGULARPS|SH_WRITEDEPTH|mask, ppsRegular[2]); + LOAD_PS(SH_REGULARFOGPS|SH_WRITEDEPTH|mask, ppsRegular[3]); + + LOAD_PS(SH_BITBLTPS, ppsBitBlt[0]); LOAD_PS(SH_BITBLTAAPS, ppsBitBlt[0]); + LOAD_PS(SH_BITBLTDEPTHPS, ppsBitBltDepth[0]); LOAD_PS(SH_BITBLTDEPTHMRTPS, ppsBitBltDepth[1]); + LOAD_PS(SH_BITBLTDEPTHTEXPS, ppsBitBltDepthTex[0]); LOAD_PS(SH_BITBLTDEPTHTEXMRTPS, ppsBitBltDepthTex[1]); + LOAD_PS(SH_CRTCTARGPS, ppsCRTCTarg[0]); LOAD_PS(SH_CRTCTARGINTERPS, ppsCRTCTarg[1]); + LOAD_PS(SH_CRTCPS, ppsCRTC[0]); LOAD_PS(SH_CRTCINTERPS, ppsCRTC[1]); + LOAD_PS(SH_CRTC24PS, ppsCRTC24[0]); LOAD_PS(SH_CRTC24INTERPS, ppsCRTC24[1]); + LOAD_PS(SH_ZEROPS|mask, ppsOne); + LOAD_PS(SH_BASETEXTUREPS, ppsBaseTexture); + LOAD_PS(SH_CONVERT16TO32PS, ppsConvert16to32); + LOAD_PS(SH_CONVERT32TO16PS, ppsConvert32to16); + + return S_OK; +} + +LPD3DPS ZeroGS::LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context) +{ + int texwrap; + assert( texfilter < NUM_FILTERS ); + + if(g_nPixelShaderVer == SHADER_20 ) + texfilter = 0; + if(g_nPixelShaderVer == SHADER_20 ) + exactcolor = 0; + + if( clamp.wms == clamp.wmt ) { + switch( clamp.wms ) { + case 0: texwrap = TEXWRAP_REPEAT; break; + case 1: texwrap = TEXWRAP_CLAMP; break; + case 2: texwrap = TEXWRAP_CLAMP; break; + default: texwrap = TEXWRAP_REGION_REPEAT; break; + } + } + else if( clamp.wms==3||clamp.wmt==3) + texwrap = TEXWRAP_REGION_REPEAT; + else + texwrap = TEXWRAP_REPEAT_CLAMP; + + int index = GET_SHADER_INDEX(type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, context, 0); + + assert( index < ARRAYSIZE(ppsTexture) ); + LPD3DPS* pps = ppsTexture+index; + + if( *pps != NULL ) + return *pps; + + index += NUM_SHADERS*g_nPixelShaderVer; + assert( mapShaderResources.find(index) != mapShaderResources.end() ); + SHADERHEADER* header = mapShaderResources[index]; + if( header == NULL ) DEBUG_LOG("%d %d\n", index%NUM_SHADERS, g_nPixelShaderVer); + assert( header != NULL ); + HRESULT hr = pd3dDevice->CreatePixelShader((DWORD*)(s_lpShaderResources + header->offset), pps); + + if( SUCCEEDED(hr) ) + return *pps; + + if( g_bDisplayMsg ) + ERROR_LOG("Failed to create shader %d,%d,%d,%d\n", 3, fog, texfilter, 4*clamp.wms+clamp.wmt); + + return NULL; +} + +#else // not RELEASE_TO_PUBLIC + +//#define EFFECT_NAME "f:\\ps2dev\\pcsx2\\zerogs\\dx\\" +#define EFFECT_NAME ".\\" +#define COMPILE_SHADER(name, type, flags) + +class ZeroGSShaderInclude : public ID3DXInclude +{ +public: + int context; + STDMETHOD(Open)(D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes) + { + const char* pfilename = pFileName; + char strfile[255]; + if( strstr(pFileName, "ps2hw_ctx") != NULL ) { + + _snprintf(strfile, 255, "%sps2hw_ctx%d.fx", EFFECT_NAME, context); + pfilename = strfile; + } + else if( strstr(pFileName, "\\") == NULL ) { + _snprintf(strfile, 255, "%s%s", EFFECT_NAME, pFileName); + pfilename = strfile; + } + + FILE* f = fopen(pfilename, "rb"); + + if( f == NULL ) + return E_FAIL; + + fseek(f, 0, SEEK_END); + DWORD size = ftell(f); + fseek(f, 0, SEEK_SET); + char* buffer = new char[size+1]; + fread(buffer, size, 1, f); + buffer[size] = 0; + + *ppData = buffer; + *pBytes = size; + fclose(f); + + return S_OK; + } + + STDMETHOD(Close)(LPCVOID pData) + { + delete[] (char*)pData; + return S_OK; + } +}; + +#define LOAD_VS(name, ptr, shaderver) { \ + LPD3DXBUFFER pShader, pError; \ + V(D3DXCompileShaderFromFile(EFFECT_NAME"ps2hw.fx", pmacros, pInclude, name, shaderver, ShaderFlagsVS, &pShader, &pError, NULL)); \ + if( FAILED(hr) ) \ + { \ + DEBUG_LOG("Failed to load vs %s: \n%s\n", name, pError->GetBufferPointer()); \ + SAFE_RELEASE(pShader); \ + SAFE_RELEASE(pError); \ + return hr; \ + } \ + hr = pd3dDevice->CreateVertexShader((const DWORD*)pShader->GetBufferPointer(), &(ptr)); \ + SAFE_RELEASE(pShader); \ + SAFE_RELEASE(pError); \ +} \ + +#define LOAD_PS(name, ptr, shmodel) { \ + LPD3DXBUFFER pShader, pError; \ + SAFE_RELEASE(ptr); \ + V(D3DXCompileShaderFromFile(EFFECT_NAME"ps2hw.fx", pmacros, pInclude, name, shmodel, ShaderFlagsPS, &pShader, &pError, NULL)); \ + if( FAILED(hr) ) \ + { \ + DEBUG_LOG("Failed to load ps %s: \n%s\n", name, pError->GetBufferPointer()); \ + SAFE_RELEASE(pShader); \ + SAFE_RELEASE(pError); \ + return hr; \ + } \ + hr = pd3dDevice->CreatePixelShader((const DWORD*)pShader->GetBufferPointer(), &(ptr)); \ + SAFE_RELEASE(pShader); \ + SAFE_RELEASE(pError); \ + if( FAILED(hr) || ptr == NULL ) { \ + DEBUG_LOG("errors 0x%x for %s, failed.. try updating your drivers or dx\n", hr, name); \ + return E_FAIL; \ + } \ +} \ + +HRESULT ZeroGS::LoadEffects() +{ + // clear the textures + for(int i = 0; i < ARRAYSIZE(ppsTexture); ++i) { + SAFE_RELEASE(ppsTexture[i]); + } + memset(ppsTexture, 0, sizeof(ppsTexture)); + + return S_OK; +} + +#define VS_VER (g_nPixelShaderVer == SHADER_20?"vs_2_0":"vs_3_0") +#define PS_VER (g_nPixelShaderVer == SHADER_20?"ps_2_0":"ps_3_0") + +HRESULT ZeroGS::LoadExtraEffects() +{ + HRESULT hr; + DWORD ShaderFlagsPS = !DEBUG_PS2 ? 0 : (D3DXSHADER_DEBUG|D3DXSHADER_SKIPOPTIMIZATION); + DWORD ShaderFlagsVS = !DEBUG_PS2 ? 0 : (D3DXSHADER_DEBUG|D3DXSHADER_SKIPOPTIMIZATION); + + ZeroGSShaderInclude inc; + inc.context = 0; + ZeroGSShaderInclude* pInclude = &inc; + + //assert( g_nPixelShaderVer == SHADER_30) ; + const char* pstrps = g_nPixelShaderVer == SHADER_20 ? "ps_2_0" : "ps_2_a"; + const char* pvsshaders[4] = { "RegularVS", "TextureVS", "RegularFogVS", "TextureFogVS" }; + + D3DXMACRO macros[2] = {0}; + D3DXMACRO* pmacros = NULL; + + macros[0].Name = "WRITE_DEPTH"; + macros[0].Definition = "1"; + + for(int i = 0; i < 4; ++i) { + pmacros = NULL; + inc.context = 0; + LOAD_VS(pvsshaders[i], pvs[2*i], VS_VER); + inc.context = 1; + LOAD_VS(pvsshaders[i], pvs[2*i+1], VS_VER); + + pmacros = macros; + inc.context = 0; + LOAD_VS(pvsshaders[i], pvs[2*i+8], VS_VER); + inc.context = 1; + LOAD_VS(pvsshaders[i], pvs[2*i+8+1], VS_VER); + } + + inc.context = 0; + pmacros = NULL; + LOAD_PS("RegularPS", ppsRegular[0], PS_VER); + LOAD_PS("RegularFogPS", ppsRegular[1], PS_VER); + + pmacros = macros; + LOAD_PS("RegularPS", ppsRegular[2], PS_VER); + LOAD_PS("RegularFogPS", ppsRegular[3], PS_VER); + + pmacros = NULL; + LOAD_VS("BitBltVS", pvsBitBlt, "vs_2_0"); + LOAD_PS("BitBltPS", ppsBitBlt[0], pstrps); + LOAD_PS("BitBltAAPS", ppsBitBlt[1], pstrps); + LOAD_PS("BitBltDepthPS", ppsBitBltDepth[0], pstrps); + LOAD_PS("BitBltDepthMRTPS", ppsBitBltDepth[1], pstrps); + LOAD_PS("BitBltDepthTexPS", ppsBitBltDepthTex[0], pstrps); + LOAD_PS("BitBltDepthTexMRTPS", ppsBitBltDepthTex[1], pstrps); + LOAD_PS("CRTCTargPS", ppsCRTCTarg[0], pstrps); LOAD_PS("CRTCTargInterPS", ppsCRTCTarg[1], pstrps); + LOAD_PS("CRTCPS", ppsCRTC[0], pstrps); LOAD_PS("CRTCInterPS", ppsCRTC[1], pstrps); + LOAD_PS("CRTC24PS", ppsCRTC24[0], pstrps); LOAD_PS("CRTC24InterPS", ppsCRTC24[1], pstrps); + LOAD_PS("ZeroPS", ppsOne, PS_VER); + LOAD_PS("BaseTexturePS", ppsBaseTexture, pstrps); + LOAD_PS("Convert16to32PS", ppsConvert16to32, pstrps); + LOAD_PS("Convert32to16PS", ppsConvert32to16, pstrps); + + return S_OK; +} + +LPD3DPS ZeroGS::LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context) +{ + int texwrap; + + assert( texfilter < NUM_FILTERS ); + //assert( g_nPixelShaderVer == SHADER_30 ); + if( clamp.wms == clamp.wmt ) { + switch( clamp.wms ) { + case 0: texwrap = TEXWRAP_REPEAT; break; + case 1: texwrap = TEXWRAP_CLAMP; break; + case 2: texwrap = TEXWRAP_CLAMP; break; + default: + texwrap = TEXWRAP_REGION_REPEAT; break; + } + } + else if( clamp.wms==3||clamp.wmt==3) + texwrap = TEXWRAP_REGION_REPEAT; + else + texwrap = TEXWRAP_REPEAT_CLAMP; + + int index = GET_SHADER_INDEX(type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, context, 0); + + LPD3DPS* pps = ppsTexture+index; + + if( *pps != NULL ) + return *pps; + + ZeroGSShaderInclude inc; + inc.context = context; + + HRESULT hr = LoadShaderFromType(EFFECT_NAME"ps2hw.fx", type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, g_nPixelShaderVer, 0, pd3dDevice, &inc, pps); + + if( SUCCEEDED(hr) ) + return *pps; + + DEBUG_LOG("Failed to create shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); + + return NULL; +} + +#endif // RELEASE_TO_PUBLIC + +HRESULT ZeroGS::InitDeviceObjects() +{ + //g_GameSettings |= 0;//GAME_VSSHACK|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE|GAME_FASTUPDATE; + //s_bWriteDepth = TRUE; + DeleteDeviceObjects(); + + int i; + HRESULT hr; + SETRS(D3DRS_SRCBLEND, D3DBLEND_ONE); + SETRS(D3DRS_DESTBLEND, D3DBLEND_ONE); + + if( pFont ) V_RETURN( pFont->OnResetDevice() ); + V_RETURN( D3DXCreateSprite( pd3dDevice, &pSprite ) ); + + V(D3DXCreateTextureFromResource(pd3dDevice, hInst, MAKEINTRESOURCE( IDB_ZEROGSLOGO ), &ptexLogo)); + + for(i = 0; i < 2; ++i) + { + V_RETURN(pd3dDevice->CreateVertexBuffer( sizeof(VertexGPU) * POINT_BUFFERSIZE, D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &vb[i].pvb, NULL)); + } + + // create the blocks texture + D3DFORMAT blockfmt = D3DFMT_R32F; + g_fBlockMult = 1; + + if( FAILED(hr = pd3dDevice->CreateTexture(BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 1, 0, blockfmt, D3DPOOL_MANAGED, &ptexBlocks, NULL)) ) { + blockfmt = D3DFMT_G16R16; + g_fBlockMult = 65535.0f*(float)g_fiGPU_TEXWIDTH; + V_RETURN(pd3dDevice->CreateTexture(BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 1, 0, blockfmt, D3DPOOL_MANAGED, &ptexBlocks, NULL)); + } + + if( blockfmt == D3DFMT_R32F ) { + if( FAILED(hr = pd3dDevice->CreateTexture(BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 1, 0, D3DFMT_A32B32G32R32F, D3DPOOL_MANAGED, &ptexBilinearBlocks, NULL)) ) { + DEBUG_LOG("Failed to create bilinear block texture, fmt = D3DFMT_A32B32G32R32F\n"); + } + } + else ptexBilinearBlocks = NULL; + + // fill a simple rect + V_RETURN(pd3dDevice->CreateVertexBuffer( 4 * sizeof(VertexGPU), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &pvbRect, NULL)); + VertexGPU* pvert; + + pvbRect->Lock(0, 0, (void**)&pvert, 0); + pvert->x = -0x7fff; pvert->y = 0x7fff; pvert->z = 0; pvert->s = 0; pvert->t = 0; pvert++; + pvert->x = 0x7fff; pvert->y = 0x7fff; pvert->z = 0; pvert->s = 1; pvert->t = 0; pvert++; + pvert->x = -0x7fff; pvert->y = -0x7fff; pvert->z = 0; pvert->s = 0; pvert->t = 1; pvert++; + pvert->x = 0x7fff; pvert->y = -0x7fff; pvert->z = 0; pvert->s = 1; pvert->t = 1; pvert++; + pvbRect->Unlock(); + + D3DLOCKED_RECT lock, lockbilinear; + ptexBlocks->LockRect(0, &lock, NULL, 0); + + if( ptexBilinearBlocks != NULL ) + ptexBilinearBlocks->LockRect(0, &lockbilinear, NULL, 0); + + BLOCK::FillBlocks(&lock, ptexBilinearBlocks != NULL ? &lockbilinear : NULL, blockfmt); + + ptexBlocks->UnlockRect(0); + if( ptexBilinearBlocks != NULL ) + ptexBilinearBlocks->UnlockRect(0); + + // create the conversion textures + V_RETURN(pd3dDevice->CreateTexture(256, 256, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &ptexConv16to32, NULL)); + ptexConv16to32->LockRect(0, &lock, NULL, 0); + assert(lock.Pitch == 256*4); + u32* dst = (u32*)lock.pBits; + for(i = 0; i < 256*256; ++i) { + DWORD tempcol = RGBA16to32(i); + // have to flip r and b + *dst++ = (tempcol&0xff00ff00)|((tempcol&0xff)<<16)|((tempcol&0xff0000)>>16); + } + ptexConv16to32->UnlockRect(0); + + V_RETURN(pd3dDevice->CreateVolumeTexture(32, 32, 32, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &ptexConv32to16, NULL)); + D3DLOCKED_BOX lockbox; + ptexConv32to16->LockBox(0, &lockbox, NULL, 0); + dst = (u32*)lockbox.pBits; + for(i = 0; i < 32; ++i) { + for(int j = 0; j < 32; ++j) { + for(int k = 0; k < 32; ++k) { + u32 col = (i<<10)|(j<<5)|k; + *dst++ = ((col&0xff)<<16)|(col&0xff00); + } + } + } + ptexConv32to16->UnlockBox(0); + + // set samplers + for(i = 0; i < 8; ++i) { + pd3dDevice->SetSamplerState(i, D3DSAMP_MINFILTER, D3DTEXF_POINT); + pd3dDevice->SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + pd3dDevice->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + } + + //pd3dDevice->SetSamplerState(SAMP_SRC, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + //pd3dDevice->SetSamplerState(SAMP_SRC, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP); // can be used as a 3d texture + pd3dDevice->SetSamplerState(SAMP_BITWISEANDX, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BITWISEANDX, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BITWISEANDY, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BITWISEANDY, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + + pd3dDevice->SetTexture(SAMP_BLOCKS, ptexBlocks); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexBilinearBlocks); + pd3dDevice->SetVertexDeclaration(pdecl); + + SETRS(D3DRS_STENCILENABLE, FALSE); + SETRS(D3DRS_SCISSORTESTENABLE, 1); + SETRS(D3DRS_SEPARATEALPHABLENDENABLE, USEALPHABLENDING); + SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); + SETRS(D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO); + SETRS(D3DRS_CULLMODE, D3DCULL_NONE); + SETRS(D3DRS_BLENDFACTOR, 0x80000000); + SETRS(D3DRS_COLORWRITEENABLE1, 0); + + // points + SETRS(D3DRS_POINTSCALEENABLE, FALSE); + SETRS(D3DRS_POINTSIZE, FtoDW(1.0f)); + + g_nDepthBias = 0; + SETRS(D3DRS_DEPTHBIAS, FtoDW(0.000015f)); + + SETCONSTF(GPU_Z, g_vdepth);//vb[icurctx].zbuf.psm&3]); + + s_vznorm = DXVEC4(g_filog32, 0, 0,0); + SETCONSTF(GPU_ZNORM, s_vznorm); + + return S_OK; +} + +void ZeroGS::DeleteDeviceObjects() +{ + if( s_aviinit ) { + StopCapture(); + STOP_AVI(); + DEBUG_LOG("zerogs.avi stopped"); + s_aviinit = 0; + } + + SAFE_RELEASE(s_ptexAVICapture); + + if( pFont ) pFont->OnLostDevice(); + SAFE_RELEASE(pSprite); + + g_MemTargs.Destroy(); + s_RTs.Destroy(); + s_DepthRTs.Destroy(); + s_BitwiseTextures.Destroy(); + + SAFE_RELEASE(s_ptexInterlace); + SAFE_RELEASE(pvbRect); + SAFE_RELEASE(ptexBlocks); + SAFE_RELEASE(ptexBilinearBlocks); + SAFE_RELEASE(ptexConv16to32); + SAFE_RELEASE(ptexConv32to16); + s_bAlphaSet = FALSE; + + vb[0].Unlock(); + SAFE_RELEASE(vb[0].pvb); + + vb[1].Unlock(); + SAFE_RELEASE(vb[1].pvb); +} + +void ZeroGS::Prim() +{ + if( g_bIsLost ) + return; + + VB& curvb = vb[prim->ctxt]; + if( curvb.CheckPrim() ) + Flush(prim->ctxt); + curvb.curprim._val = prim->_val; + + // flush the other pipe if sharing the same buffer +// if( vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp && vb[!prim->ctxt].dwCount > 0 ) +// { +// assert( vb[prim->ctxt].dwCount == 0 ); +// Flush(!prim->ctxt); +// } + + curvb.curprim.prim = prim->prim; + vb[prim->ctxt].Lock(); +} + +int GetTexFilter(const tex1Info& tex1) +{ + // always force + if( conf.bilinear == 2 ) + return 1; + + int texfilter = 0; + if( conf.bilinear && ptexBilinearBlocks != NULL ) { + if( tex1.mmin <= 1 ) + texfilter = tex1.mmin|tex1.mmag; + else + texfilter = tex1.mmag ? ((tex1.mmin+2)&5) : tex1.mmin; + + texfilter = texfilter == 1 || texfilter == 4 || texfilter == 5; + } + return texfilter; +} + +void ZeroGS::ReloadEffects() +{ +#ifndef RELEASE_TO_PUBLIC + for(int i = 0; i < ARRAYSIZE(ppsTexture); ++i) { + SAFE_RELEASE(ppsTexture[i]); + } + memset(ppsTexture, 0, sizeof(ppsTexture)); + LoadExtraEffects(); +#endif +} + +static int s_ClutResolve = 0; +static int s_PSM8Resolve = 0; +void ZeroGS::Flush(int context) +{ + assert( context >= 0 && context <= 1 ); + +#ifndef RELEASE_TO_PUBLIC + if( g_bUpdateEffect ) { + ReloadEffects(); + g_bUpdateEffect = 0; + } +#endif + + VB& curvb = vb[context]; + const pixTest curtest = curvb.test; + if( curvb.dwCount == 0 || (curtest.zte && curtest.ztst == 0) || g_bIsLost ) { + curvb.dwCount = 0; + return; + } + + if( s_RangeMngr.ranges.size() > 0 ) { + + // don't want infinite loop + DWORD prevcount = curvb.dwCount; + curvb.dwCount = 0; + FlushTransferRanges(curvb.curprim.tme ? &curvb.tex0 : NULL); + + curvb.dwCount = prevcount; + //if( curvb.dwCount == 0 ) + // return; + } + + if( curvb.bNeedTexCheck ) { + curvb.FlushTexData(); + + if( curvb.dwCount == 0 ) + return; + } + + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + curvb.Unlock(); + + LPD3DTEX ptexRenderTargetCached = NULL; + int cachedtbp0, cachedtbw, cachedtbh; + + //s_bWriteDepth = TRUE; + + //static int lasttime = 0; + //fprintf(gsLog, "%d: %d\n", g_SaveFrameNum, timeGetTime()-lasttime); + //lasttime = timeGetTime(); + + if( curvb.bNeedFrameCheck || curvb.bNeedZCheck ) { + + int tpsm = curvb.tex0.psm; + if( curvb.bNeedTexCheck ) + tpsm = (curvb.uNextTex0Data[0] >> 20) & 0x3f; + + if( tpsm == PSMT8H && (g_GameSettings&GAME_NOTARGETCLUT) ) { + curvb.dwCount = 0; + return; + } + + // check for the texture before checking the frame (since things could get destroyed) + if( (g_GameSettings&GAME_PARTIALPOINTERS) &&curvb.curprim.tme ) { + +// if( (curvb.gsfb.fbp&0xff) != 0 ) { +// curvb.dwCount = 0; +// return; +// } + + // if texture is part of a previous target, use that instead + int tbw = curvb.tex0.tbw; + int tbp0 = curvb.tex0.tbp0; + + if( curvb.bNeedTexCheck ) { + // not yet initied, but still need to get correct target! (xeno3 ingame) + tbp0 = (curvb.uNextTex0Data[0] & 0x3fff); + tbw = ((curvb.uNextTex0Data[0] >> 14) & 0x3f) * 64; + } + + if( (tpsm&~1) == 0 ) { + CRenderTarget* ptemptarg = s_RTs.GetTarg(tbp0, tbw); + if( ptemptarg != NULL && (ptemptarg->psm&~1) == (tpsm&~1) ) { + ptexRenderTargetCached = ptemptarg->ptex; + ptexRenderTargetCached->AddRef(); + cachedtbp0 = ptemptarg->fbp; + cachedtbw = ptemptarg->fbw; + cachedtbh = ptemptarg->fbh; + } + } + } + curvb.CheckFrame(curvb.curprim.tme ? curvb.tex0.tbp0 : 0); + } + +// if( g_SaveFrameNum == 976 ) { +// curvb.prndr->ConvertTo32(); +// } + if( curvb.prndr == NULL || curvb.pdepth == NULL ) { + WARN_LOG("Current render target NULL (ctx: %d)", context); + curvb.dwCount = 0; + SAFE_RELEASE(ptexRenderTargetCached); + return; + } + +#if defined(PRIM_LOG) && defined(_DEBUG) + static const char* patst[8] = { "NEVER", "ALWAYS", "LESS", "LEQUAL", "EQUAL", "GEQUAL", "GREATER", "NOTEQUAL"}; + static const char* pztst[4] = { "NEVER", "ALWAYS", "GEQUAL", "GREATER" }; + static const char* pafail[4] = { "KEEP", "FB_ONLY", "ZB_ONLY", "RGB_ONLY" }; + PRIM_LOG("**Drawing ctx %d, num %d, fbp: 0x%x, zbp: 0x%x, fpsm: %d, zpsm: %d, fbw: %d\n", context, vb[context].dwCount, curvb.prndr->fbp, curvb.zbuf.zbp, curvb.prndr->psm, curvb.zbuf.psm, curvb.prndr->fbw); + PRIM_LOG("prim: prim=%x iip=%x tme=%x fge=%x abe=%x aa1=%x fst=%x ctxt=%x fix=%x\n", + curvb.curprim.prim, curvb.curprim.iip, curvb.curprim.tme, curvb.curprim.fge, curvb.curprim.abe, curvb.curprim.aa1, curvb.curprim.fst, curvb.curprim.ctxt, curvb.curprim.fix); + PRIM_LOG("test: ate:%d, atst: %s, aref: %d, afail: %s, date: %d, datm: %d, zte: %d, ztst: %s, fba: %d\n", + curvb.test.ate, patst[curvb.test.atst], curvb.test.aref, pafail[curvb.test.afail], curvb.test.date, curvb.test.datm, curvb.test.zte, pztst[curvb.test.ztst], curvb.fba.fba); + PRIM_LOG("alpha: A%d B%d C%d D%d FIX:%d pabe: %d; aem: %d, ta0: %d, ta1: %d\n", curvb.alpha.a, curvb.alpha.b, curvb.alpha.c, curvb.alpha.d, curvb.alpha.fix, gs.pabe, gs.texa.aem, gs.texa.ta[0], gs.texa.ta[1]); + PRIM_LOG("tex0: tbp0=0x%x, tbw=%d, psm=0x%x, tw=%d, th=%d, tcc=%d, tfx=%d, cbp=0x%x, cpsm=0x%x, csm=%d, csa=%d, cld=%d\n", + curvb.tex0.tbp0, curvb.tex0.tbw, curvb.tex0.psm, curvb.tex0.tw, + curvb.tex0.th, curvb.tex0.tcc, curvb.tex0.tfx, curvb.tex0.cbp, + curvb.tex0.cpsm, curvb.tex0.csm, curvb.tex0.csa, curvb.tex0.cld); + PRIM_LOG("frame: %d\n\n", g_SaveFrameNum); +#endif + + CMemoryTarget* pmemtarg = NULL; + CRenderTarget* ptextarg = NULL; + + // kh2 hack +// if( curvb.dwCount == 2 && curvb.curprim.tme == 0 && curvb.curprim.abe == 0 && (curvb.tex0.tbp0 == 0x2a00 || curvb.tex0.tbp0==0x1d00) ) { +// // skip +// DEBUG_LOG("skipping\n"); +// g_SaveFrameNum++; +// curvb.dwCount = 0; +// return; +// } + + if( curtest.date || gs.pabe ) + SetDestAlphaTest(); + + // set the correct pixel shaders + if( curvb.curprim.tme && ptexRenderTargetCached == NULL ) { + + // if texture is part of a previous target, use that instead + int tbw = curvb.tex0.tbw; + int tbp0 = curvb.tex0.tbp0; + int tpsm = curvb.tex0.psm; + + if( curvb.bNeedTexCheck ) { + // not yet initied, but still need to get correct target! (xeno3 ingame) + tbp0 = (curvb.uNextTex0Data[0] & 0x3fff); + tbw = ((curvb.uNextTex0Data[0] >> 14) & 0x3f) * 64; + tpsm = (curvb.uNextTex0Data[0] >> 20) & 0x3f; + } + ptextarg = s_RTs.GetTarg(tbp0, tbw); + + if( ptextarg == NULL && tpsm == PSMT8 ) { + // check for targets with half the width + ptextarg = s_RTs.GetTarg(tbp0, tbw/2); + if( ptextarg == NULL ) { + tbp0 &= ~0x7ff; + ptextarg = s_RTs.GetTarg(tbp0, tbw/2); // mgs3 hack + + if( ptextarg == NULL ) { + // check the next level (mgs3) + tbp0 &= ~0xfff; + ptextarg = s_RTs.GetTarg(tbp0, tbw/2); // mgs3 hack + } + + if( ptextarg != NULL && ptextarg->start > tbp0*256 ) { + // target beyond range, so ignore + ptextarg = NULL; + } + } + +// if( ptextarg != NULL ) { +// // make sure target isn't invalidated by the ranges +// for(vector::iterator itrange = s_RangeMngr.ranges.begin(); itrange != s_RangeMngr.ranges.end(); ++itrange ) { +// +// int start = itrange->start; +// int end = itrange->end; +// +// // if start and end are in the range or there's a range that is between tbp0 and start, then remove +// if( (start <= tbp0*256 && end > tbp0*256) || (start >= ptextarg->fbp*256 && start <= tbp0*256) ) { +// ptextarg = NULL; +// break; +// } +// } +// } + + if( ptextarg != NULL && !(ptextarg->status&CRenderTarget::TS_NeedUpdate) ) { + // find the equivalent memtarg + if( s_PSM8Resolve == 0 ) { //|| (s_PSM8Resolve > 0 && s_PSM8Resolve+128 < g_SaveFrameNum) ) { + DWORD prevcount = curvb.dwCount; + curvb.dwCount = 0; + if( ptextarg->pmimicparent != NULL ) + ptextarg->pmimicparent->Resolve(); + else + ptextarg->Resolve(); + curvb.dwCount = prevcount; + s_PSM8Resolve = g_SaveFrameNum; // stop from resolving again (once per frame) + } + + tex0Info mytex0 = curvb.tex0; + mytex0.tbp0 = tbp0; + if( ptextarg->pmimicparent != NULL ) { + mytex0.tbp0 = ptextarg->pmimicparent->fbp; + } + pmemtarg = g_MemTargs.GetMemoryTarget(mytex0, 1); + + // have to add an offset to all texture reads + mytex0.tbp0 = tbp0; // change so that SetTexVariablesInt can set the right offsets + + SetTexVariablesInt(context, GetTexFilter(curvb.tex1), mytex0, pmemtarg, s_bForceTexFlush); + curvb.bVarsTexSync = TRUE; + + ptextarg = NULL; // won't be needing this anymore + } + } + + if( (tpsm&0x30)==0x30 && ptextarg == NULL ) { + // try depth + ptextarg = s_DepthRTs.GetTarg(tbp0, tbw); + } + + if( ptextarg == NULL && (g_GameSettings&GAME_TEXTURETARGS) ) { + // check if any part of the texture intersects the current target + if( !PSMT_ISCLUT(tpsm) && curvb.tex0.tbp0 >= curvb.frame.fbp && (curvb.tex0.tbp0 << 8) < curvb.prndr->end) { + ptextarg = curvb.prndr; + } + } + + if( ptextarg != NULL && !(ptextarg->status&CRenderTarget::TS_NeedUpdate) ) { + if( PSMT_ISCLUT(tpsm) && tpsm != PSMT8H && tpsm != PSMT8 ) { // handle 8h cluts + // don't support clut targets, read from mem + // 4hl - kh2 check + if( tpsm != PSMT4HL && tpsm != PSMT4HH && s_ClutResolve <= 1 ) { // xenosaga requires 2 resolves + DWORD prevcount = curvb.dwCount; + curvb.dwCount = 0; + ptextarg->Resolve(); + s_ClutResolve++; + curvb.dwCount = prevcount; + } + ptextarg = NULL; + } + else { + if( ptextarg == curvb.prndr ) { + // need feedback + if( ptextarg->pmimicparent != NULL ) { + // if the target is mimic, create the feedback of the parent + assert( ptextarg->pmimicparent->ptex == ptextarg->ptex || ptextarg->pmimicparent->ptexFeedback == ptextarg->ptex ); + SAFE_RELEASE(ptextarg->ptexFeedback); + SAFE_RELEASE(ptextarg->psurfFeedback); + ptextarg->pmimicparent->CreateFeedback(); + ptextarg->ptex = ptextarg->pmimicparent->ptex; + ptextarg->ptexFeedback = ptextarg->pmimicparent->ptexFeedback; ptextarg->ptexFeedback->AddRef(); + ptextarg->psurf = ptextarg->pmimicparent->psurf; + ptextarg->psurfFeedback = ptextarg->pmimicparent->psurfFeedback; ptextarg->psurfFeedback->AddRef(); + } + else + curvb.prndr->CreateFeedback(); + + pd3dDevice->SetRenderTarget(1, (s_bWriteDepth && curvb.pdepth != NULL) ? curvb.pdepth->psurf : NULL); + } + } + } + else ptextarg = NULL; + } + +#ifdef _DEBUG + if( g_bSaveFlushedFrame & 0x80000000 ) { + char str[255]; + sprintf(str, "rndr.tga", g_SaveFrameNum); + D3DXSaveSurfaceToFile(str, D3DXIFF_TGA, curvb.prndr->psurf, NULL, NULL); + } +#endif + + if( conf.options & GSOPTION_WIREFRAME ) { + // always render first few geometry as solid + if( s_nWireframeCount > 0 ) { + SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + } + } + + if( !curvb.bVarsSetTarg ) + SetContextTarget(context); + else { + assert( curvb.pdepth != NULL ); + + if( curvb.pdepth->status & CRenderTarget::TS_Virtual) { + + if( !curvb.zbuf.zmsk ) { + CRenderTarget* ptemp = s_DepthRTs.Promote(curvb.pdepth->fbp|(curvb.pdepth->fbw<<16)); + assert( ptemp == curvb.pdepth ); + } + else + curvb.pdepth->status &= ~CRenderTarget::TS_NeedUpdate; + } + + if( (curvb.pdepth->status & CRenderTarget::TS_NeedUpdate) || (curvb.prndr->status & CRenderTarget::TS_NeedUpdate) ) + SetContextTarget(context); + } + + SetTexVariables(context); + if( ptextarg == NULL && pmemtarg == NULL ) { + pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 1); + + if( vb[context].bVarsTexSync ) { + if( vb[context].pmemtarg != pmemtarg ) { + SetTexVariablesInt(context, GetTexFilter(curvb.tex1), curvb.tex0, pmemtarg, s_bForceTexFlush); + vb[context].bVarsTexSync = TRUE; + } + } + else { + SetTexVariablesInt(context, GetTexFilter(curvb.tex1), curvb.tex0, pmemtarg, s_bForceTexFlush); + vb[context].bVarsTexSync = TRUE; + + INC_TEXVARS(); + } + } + + icurctx = context; + + assert( !(curvb.prndr->status&CRenderTarget::TS_NeedUpdate) ); + curvb.prndr->status = 0; + + if( curvb.pdepth != NULL ) { + assert( !(curvb.pdepth->status&CRenderTarget::TS_NeedUpdate) ); + if( !curvb.zbuf.zmsk ) { + assert( !(curvb.pdepth->status & CRenderTarget::TS_Virtual) ); + curvb.pdepth->status = 0; + } + } + + s_dwColorWrite = (curvb.prndr->psm&0xf) == 1 ? (D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED) : 0xf; + + if( ((curvb.frame.fbm)&0xff) == 0xff) s_dwColorWrite &= ~D3DCOLORWRITEENABLE_RED; + if( ((curvb.frame.fbm>>8)&0xff) == 0xff) s_dwColorWrite &= ~D3DCOLORWRITEENABLE_GREEN; + if( ((curvb.frame.fbm>>16)&0xff) == 0xff) s_dwColorWrite &= ~D3DCOLORWRITEENABLE_BLUE; + if( ((curvb.frame.fbm>>24)&0xff) == 0xff) s_dwColorWrite &= ~D3DCOLORWRITEENABLE_ALPHA; + + SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); + + pd3dDevice->SetScissorRect(&curvb.prndr->scissorrect); // need to always set it since something in this code resets it + + // set the shaders + pd3dDevice->SetVertexShader(pvs[2*((curvb.curprim._val>>1)&3)+8*s_bWriteDepth+context]); + pd3dDevice->SetStreamSource(0, curvb.pvb, curvb.dwCurOff*sizeof(VertexGPU), sizeof(VertexGPU)); + + DWORD dwUsingSpecialTesting = 0; + DWORD dwFilterOpts = 0; + + IDirect3DPixelShader9* pps; + + // need exact if equal or notequal + int exactcolor = 0; + if( g_nPixelShaderVer != SHADER_20 ) + // ffx2 breaks when ==7 + exactcolor = (curtest.ate && curtest.aref <= 128) && (curtest.atst==4);//||curtest.atst==7); + + int shadertype = 0; + + // set the correct pixel shaders + if( curvb.curprim.tme ) { + + if( curvb.ptexClamp[0] != NULL ) pd3dDevice->SetTexture(SAMP_BITWISEANDX, curvb.ptexClamp[0]); + if( curvb.ptexClamp[1] != NULL ) pd3dDevice->SetTexture(SAMP_BITWISEANDY, curvb.ptexClamp[1]); + + if( ptexRenderTargetCached != NULL ) { + DXVEC4 vpageoffset; + vpageoffset.w = 0; + + int psm = curvb.tex0.psm; + assert( !PSMT_ISCLUT(curvb.tex0.psm)); + + pps = LoadShadeEffect(1, 0, curvb.curprim.fge, curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), + exactcolor, curvb.clamp, context); + pd3dDevice->SetTexture(SAMP_MEMORY0+context, ptexRenderTargetCached); + s_ptexCurSet[context] = ptexRenderTargetCached; + + if( curvb.tex1.mmag ) { + pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + dwFilterOpts |= 1; + } + + if( curvb.tex1.mmin ) { + pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + dwFilterOpts |= 2; + } + + DXVEC4 vTexDims; + vTexDims.x = curvb.tex0.tw / (float)cachedtbw; + vTexDims.y = curvb.tex0.th / (float)cachedtbh; + +// u32 tbp0 = curvb.tex0.tbp0 >> 5; // align to a page +// int blockheight = 32; +// int ycoord = ((curvb.tex0.tbp0-cachedtbp0)/(32*(cachedtbw>>6))) * blockheight; +// int xcoord = (((curvb.tex0.tbp0-cachedtbp0)%(32*(cachedtbw>>6)))) * 2; +//// xcoord += ptextarg->targoffx; +//// ycoord += ptextarg->targoffy; +// vTexDims.z = (float)xcoord / (float)cachedtbw; +// vTexDims.w = (float)ycoord / (float)cachedtbh; + vTexDims.z = vTexDims.w = 0; + SETCONSTF(GPU_TEXDIMS0+context, vTexDims); + + SETCONSTF(GPU_PAGEOFFSET0+context, vpageoffset); + + if( g_bSaveTex ) + D3DXSaveTextureToFile("tex.tga", D3DXIFF_TGA, ptexRenderTargetCached, NULL); + } + else if( ptextarg != NULL ) { + + if( ptextarg->IsDepth() ) + SetWriteDepth(); + + DXVEC4 vpageoffset; + vpageoffset.w = 0; + + shadertype = 1; + if( (curvb.tex0.psm == PSMT8 || curvb.tex0.psm == PSMT8H) && !(g_GameSettings&GAME_NOTARGETCLUT) ) { + // load the clut to memory + LPD3DTEX ptexclut = NULL; + pd3dDevice->CreateTexture(256, 1, 1, 0, (curvb.tex0.cpsm&2) ? D3DFMT_A1R5G5B5 : D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &ptexclut, NULL); + if( ptexclut != NULL ) { + + D3DLOCKED_RECT lock; + ptexclut->LockRect(0, &lock, NULL, D3DLOCK_NOSYSLOCK); + + // fill the buffer by decoding the clut + int nClutOffset = 0, clutsize; + int entries = (curvb.tex0.psm&3)==3 ? 256 : 16; + if( curvb.tex0.cpsm <= 1 ) { // 32 bit + nClutOffset = 64 * curvb.tex0.csa; + clutsize = min(entries, 256-curvb.tex0.csa*16)*4; + } + else { + nClutOffset = 64 * (curvb.tex0.csa&15) + (curvb.tex0.csa>=16?2:0); + clutsize = min(entries, 512-curvb.tex0.csa*16)*2; + } + + if( curvb.tex0.cpsm <= 1 ) { // 32 bit + memcpy_amd(lock.pBits, ZeroGS::g_pbyGSClut+nClutOffset, clutsize); + } + else { + u16* pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + nClutOffset); + u16* pclut = (u16*)lock.pBits; + int left = ((u32)nClutOffset & 2) ? 0 : ((nClutOffset&0x3ff)/2)+clutsize-512; + if( left > 0 ) clutsize -= left; + + while(clutsize > 0) { + pclut[0] = pClutBuffer[0]; + pclut++; + pClutBuffer+=2; + clutsize -= 2; + } + + if( left > 0) { + pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + 2); + while(left > 0) { + pclut[0] = pClutBuffer[0]; + left -= 2; + pClutBuffer += 2; + pclut++; + } + } + } + + ptexclut->UnlockRect(0); + + s_vecTempTextures.push_back(ptexclut); + pd3dDevice->SetTexture(SAMP_FINAL, ptexclut); + + if( g_bSaveTex ) + D3DXSaveTextureToFile("clut.tga", D3DXIFF_TGA, ptexclut, NULL); + } + + if( g_nPixelShaderVer != SHADER_20 && (ptextarg->psm & 2) ) { + // 16 bit texture + shadertype = 4; + + DXVEC4 v; + v.x = 16.0f / (float)ptextarg->fbw; + v.y = 64.0f / (float)ptextarg->fbh; + v.z = 0.5f * v.x; + v.w = 0.5f * v.y; + SETCONSTF(GPU_TEXOFFSET0, v); + + v.x = 1; + v.y = -0.5f; + v.z = 0; + v.w = 0.0001f; + SETCONSTF(GPU_PAGEOFFSET0, v); + + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexConv32to16); + } + else + shadertype = 2; + } + else { + if( PSMT_ISCLUT(curvb.tex0.psm) ) + WARN_LOG("Using render target with CLUTs %d!\n", curvb.tex0.psm); + else { + if( (curvb.tex0.psm&2) != (ptextarg->psm&2) && (g_nPixelShaderVer != SHADER_20 || !curvb.curprim.fge) ) { + if( curvb.tex0.psm & 2 ) { + // converting from 32->16 + shadertype = 3; + + DXVEC4 v; + v.x = 16.0f / (float)curvb.tex0.tw; + v.y = 64.0f / (float)curvb.tex0.th; + v.z = 0.5f * v.x; + v.w = 0.5f * v.y; + SETCONSTF(GPU_TEXOFFSET0+context, v); + + vpageoffset.x = -0.1f / 256.0f; + vpageoffset.y = -0.001f / 256.0f; + vpageoffset.z = -0.1f / ptextarg->fbh; + vpageoffset.w = ((ptextarg->psm&0x30)==0x30)?-1.0f:0.0f; + + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexConv16to32); + } + else { + // converting from 16->32 + WARN_LOG("ZeroGS: converting from 16 to 32bit RTs\n"); + //shadetype = 4; + } + } + } + } + + int psm = curvb.tex0.psm; + if( PSMT_ISCLUT(curvb.tex0.psm) ) psm = curvb.tex0.cpsm; + + pps = LoadShadeEffect(shadertype, 0, curvb.curprim.fge, curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), + exactcolor, curvb.clamp, context); + LPD3DTEX ptexset = ptextarg == curvb.prndr ? ptextarg->ptexFeedback : ptextarg->ptex; + pd3dDevice->SetTexture(SAMP_MEMORY0+context, ptexset); + s_ptexCurSet[context] = ptexset; + + if( curvb.tex1.mmag ) { + pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + dwFilterOpts |= 1; + } + + if( curvb.tex1.mmin ) { + pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + dwFilterOpts |= 2; + } + + DXVEC4 vTexDims; + vTexDims.x = curvb.tex0.tw / (float)ptextarg->fbw; + vTexDims.y = curvb.tex0.th / (float)ptextarg->targheight; + + // look at the offset of tbp0 from fbp + if( curvb.tex0.tbp0 <= ptextarg->fbp ) { + vTexDims.z = 0;//-0.5f/(float)ptextarg->fbw; + vTexDims.w = 0;//0.2f/(float)ptextarg->fbh; + } + else { + u32 tbp0 = curvb.tex0.tbp0 >> 5; // align to a page + int blockheight = (ptextarg->psm&2) ? 64 : 32; + int ycoord = ((curvb.tex0.tbp0-ptextarg->fbp)/(32*(ptextarg->fbw>>6))) * blockheight; + int xcoord = (((curvb.tex0.tbp0-ptextarg->fbp)%(32*(ptextarg->fbw>>6)))) * 2; + xcoord += ptextarg->targoffx; + ycoord += ptextarg->targoffy; + vTexDims.z = (float)xcoord / (float)ptextarg->fbw; + vTexDims.w = (float)ycoord / (float)ptextarg->targheight; + } + + if( shadertype == 4 ) { + vTexDims.z += 8.0f / (float)ptextarg->fbw; + } + + SETCONSTF(GPU_TEXDIMS0+context, vTexDims); + + // zoe2 + if( (ptextarg->psm&0x30) == 0x30 ) {//&& (psm&2) == (ptextarg->psm&2) ) { + // target of zbuf has +1 added to it, don't do 16bit + vpageoffset.w = -1; +// DXVEC4 valpha2; +// valpha2.x = 1; valpha2.y = 0; +// valpha2.z = -1; valpha2.w = 0; +// SETCONSTF(GPU_TEXALPHA20+context, &valpha2); + } + SETCONSTF(GPU_PAGEOFFSET0+context, vpageoffset); + + if( g_bSaveTex ) + D3DXSaveTextureToFile("tex.tga", D3DXIFF_TGA, ptextarg == curvb.prndr ? ptextarg->ptexFeedback : ptextarg->ptex, NULL); + } + else { + // save the texture +#ifdef _DEBUG +// CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 0); +// assert( curvb.pmemtarg == pmemtarg ); +// if( PSMT_ISCLUT(curvb.tex0.psm) ) +// assert( curvb.pmemtarg->ValidateClut(curvb.tex0) ); +#endif + +//#ifdef ZEROGS_CACHEDCLEAR +// if( !curvb.pmemtarg->ValidateTex(curvb.tex0, true) ) { +// CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 1); +// SetTexVariablesInt(context, GetTexFilter(curvb.tex1), curvb.tex0, pmemtarg, s_bForceTexFlush); +// vb[context].bVarsTexSync = TRUE; +// } +//#endif + + if( g_bSaveTex ) { + if( g_bSaveTex == 1 ) SaveTex(&curvb.tex0, 1); + else SaveTex(&curvb.tex0, 0); + } + + int psm = curvb.tex0.psm; + if( PSMT_ISCLUT(curvb.tex0.psm) ) psm = curvb.tex0.cpsm; + + pps = LoadShadeEffect(0, GetTexFilter(curvb.tex1), curvb.curprim.fge, + curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), + exactcolor, curvb.clamp, context); + } + } + else pps = ppsRegular[curvb.curprim.fge+2*s_bWriteDepth]; + + pd3dDevice->SetPixelShader(pps); + + BOOL bCanRenderStencil = g_bUpdateStencil && (curvb.prndr->psm&0xf) != 1 && !(curvb.frame.fbm&0x80000000); + if( g_GameSettings & GAME_NOSTENCIL ) + bCanRenderStencil = 0; + + if( s_bDestAlphaTest) { + SETRS(D3DRS_STENCILENABLE, bCanRenderStencil); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); + SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + } + else SETRS(D3DRS_STENCILENABLE, 0); + + SETRS(D3DRS_ZWRITEENABLE, !curvb.zbuf.zmsk); + SETRS(D3DRS_ZENABLE, curtest.zte); + if( curtest.zte ) { + if( curtest.ztst > 1 ) g_nDepthUsed = 2; + if( (curtest.ztst == 2) ^ (g_nDepthBias != 0) ) { + g_nDepthBias = curtest.ztst == 2; + if( g_GameSettings & GAME_RELAXEDDEPTH ) + SETRS(D3DRS_DEPTHBIAS, g_nDepthBias?FtoDW(0.00003f):FtoDW(0.0001f)); + else + SETRS(D3DRS_DEPTHBIAS, g_nDepthBias?FtoDW(0.0003f):FtoDW(0.000015f)); + } + + SETRS(D3DRS_ZFUNC, g_dwZCmp[curtest.ztst]); + +// if( curtest.ztst == 3 ) { +// // gequal +// if( s_vznorm.y == 0 ) { +// s_vznorm.y = 0.00001f; +// SETCONSTF(GPU_ZNORM, s_vznorm); +// } +// } +// else { +// if( s_vznorm.y > 0 ) { +// s_vznorm.y = 0; +// SETCONSTF(GPU_ZNORM, s_vznorm); +// } +// } + } + + SETRS(D3DRS_ALPHATESTENABLE, curtest.ate&&USEALPHATESTING); + if( curtest.ate ) { + + if( curtest.atst == 7 && curtest.aref == 255 ) { + // when it is at the very top, do a less than rather than not equal (gekibo2) + SETRS(D3DRS_ALPHAFUNC, D3DCMP_LESS); + SETRS(D3DRS_ALPHAREF, 255); + } + else { + SETRS(D3DRS_ALPHAFUNC, g_dwAlphaCmp[curtest.atst]); + SETRS(D3DRS_ALPHAREF, b2XAlphaTest ? min(255,2 * curtest.aref) : curtest.aref); + } + } + + if( s_bWriteDepth ) { + //pd3dDevice->SetRenderTarget(0, curvb.prndr->psurf); + //pd3dDevice->SetRenderTarget(1, !curvb.zbuf.zmsk?curvb.pdepth->psurf:NULL); + if( bIndepWriteMasks ) + SETRS(D3DRS_COLORWRITEENABLE1, !curvb.zbuf.zmsk?0xf:0); + else + pd3dDevice->SetRenderTarget(1, !curvb.zbuf.zmsk?curvb.pdepth->psurf:NULL); + } + + if( curvb.curprim.abe ) + SetAlphaVariables(curvb.alpha); + else + SETRS(D3DRS_ALPHABLENDENABLE, 0); + + // needs to be before RenderAlphaTest + if( curvb.fba.fba || s_bDestAlphaTest ) { + if( gs.pabe || (curvb.fba.fba || bCanRenderStencil) && !(curvb.frame.fbm&0x80000000) ) { + RenderFBA(curvb); + } + } + + u32 oldabe = curvb.curprim.abe; + if( gs.pabe ) { + //WARN_LOG("PBE!\n"); + curvb.curprim.abe = 1; + SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); + } + + if( curvb.curprim.abe && bNeedAlphaColor ) { + + if( //bCanRenderStencil && + (bNeedBlendFactorInAlpha || ((curtest.ate && curtest.atst>1) && (curtest.aref > 0x80))) ) { + // need special stencil processing for the alpha + RenderAlphaTest(curvb); + dwUsingSpecialTesting = 1; + } + + // harvest fishing + DXVEC4 v = vAlphaBlendColor;// + DXVEC4(0,0,0,(curvb.test.atst==4 && curvb.test.aref>=128)?-0.004f:0); + if( exactcolor ) { v.y *= 255; v.w *= 255; } + SETCONSTF(GPU_ONECOLOR, v); + } + else { + // not using blending so set to defaults + DXVEC4 v = exactcolor ? DXVEC4(1, 510*255.0f/256.0f, 0, 0) : DXVEC4(1,2*255.0f/256.0f,0,0); + SETCONSTF(GPU_ONECOLOR, v); + } + + if( s_bDestAlphaTest && bCanRenderStencil ) { + // if not 24bit and can write to high alpha bit + RenderStencil(curvb, dwUsingSpecialTesting); + } + else { + dwStencilRef = STENCIL_SPECIAL; + dwStencilMask = STENCIL_SPECIAL; + + // setup the stencil to only accept the test pixels + if( dwUsingSpecialTesting ) { + SETRS(D3DRS_STENCILENABLE, TRUE); + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_PIXELWRITE); + SETRS(D3DRS_STENCILMASK, STENCIL_SPECIAL); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + SETRS(D3DRS_STENCILREF, STENCIL_SPECIAL|STENCIL_PIXELWRITE); + } + } + +#ifdef _DEBUG + if( bDestAlphaColor == 1 ) { + WARN_LOG("dest alpha blending! manipulate alpha here\n"); + } +#endif + + if( bCanRenderStencil && gs.pabe ) { + // only render the pixels with alpha values >= 0x80 + SETRS(D3DRS_STENCILREF, dwStencilRef|STENCIL_FBA); + SETRS(D3DRS_STENCILMASK, dwStencilMask|STENCIL_FBA); + if( !dwStencilMask ) SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + } + +// curvb.prndr->SetViewport(); +// pd3dDevice->SetScissorRect(&curvb.prndr->scissorrect); +// SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + + if( !curvb.test.ate || curvb.test.atst > 0 ) { + DRAW(); + } + + if( gs.pabe ) { + // only render the pixels with alpha values < 0x80 + SETRS(D3DRS_ALPHABLENDENABLE, 0); + SETRS(D3DRS_STENCILREF, dwStencilRef); + + DXVEC4 v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + if( exactcolor ) v.y *= 255; + SETCONSTF(GPU_ONECOLOR, v); + + DRAW(); + + // reset + SETRS(D3DRS_STENCILMASK, dwStencilMask); + if( !dwStencilMask ) SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + } + + // more work on alpha failure case + if( curtest.ate && curtest.atst != 1 && curtest.afail > 0 ) { + + // need to reverse the test and disable some targets + SETRS(D3DRS_ALPHAFUNC, g_dwReverseAlphaCmp[curtest.atst]); + + if( curtest.afail & 1 ) { // front buffer update only + + if( curtest.afail == 3 ) // disable alpha + SETRS(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED); + + SETRS(D3DRS_ZWRITEENABLE, FALSE); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1,NULL); + } + } + else { + // zbuffer update only + SETRS(D3DRS_COLORWRITEENABLE, 0); + } + + if( gs.pabe && bCanRenderStencil ) { + // only render the pixels with alpha values >= 0x80 + DXVEC4 v = vAlphaBlendColor; + if( exactcolor ) { v.y *= 255; v.w *= 255; } + SETCONSTF(GPU_ONECOLOR, v); + SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); + SETRS(D3DRS_STENCILREF, dwStencilRef|STENCIL_FBA); + SETRS(D3DRS_STENCILMASK, dwStencilMask|STENCIL_FBA); + if( !dwStencilMask ) SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + } + + // setup the stencil to only accept the test pixels + if( dwUsingSpecialTesting ) { + + if( !s_bDestAlphaTest || !bCanRenderStencil ) { + SETRS(D3DRS_STENCILENABLE, FALSE); + } + } + +// IDirect3DQuery9* pOcclusionQuery; +// DWORD numberOfPixelsDrawn; +// +// pd3dDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &pOcclusionQuery); +// +// // Add an end marker to the command buffer queue. +// pOcclusionQuery->Issue(D3DISSUE_BEGIN); + + DRAW(); + +// pOcclusionQuery->Issue(D3DISSUE_END); + // Force the driver to execute the commands from the command buffer. + // Empty the command buffer and wait until the GPU is idle. +// while(S_FALSE == pOcclusionQuery->GetData( &numberOfPixelsDrawn, sizeof(DWORD), D3DGETDATA_FLUSH )); +// SAFE_RELEASE(pOcclusionQuery); + + if( gs.pabe ) { + // only render the pixels with alpha values < 0x80 + SETRS(D3DRS_ALPHABLENDENABLE, 0); + SETRS(D3DRS_STENCILREF, dwStencilRef); + + DXVEC4 v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + if( exactcolor ) v.y *= 255; + SETCONSTF(GPU_ONECOLOR, v); + + DRAW(); + + // reset + SETRS(D3DRS_STENCILMASK, dwStencilMask); + SETRS(D3DRS_ALPHABLENDENABLE, oldabe); + if( !dwStencilMask ) SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + } + + // restore + + if( (curtest.afail & 1) && !curvb.zbuf.zmsk ) { + SETRS(D3DRS_ZWRITEENABLE, TRUE); + + if( s_bWriteDepth ) { + assert( curvb.pdepth != NULL); + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + else pd3dDevice->SetRenderTarget(1,curvb.pdepth->psurf); + } + } + + SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); + + // not needed anymore since rest of ops concentrate on image processing + //SETRS(D3DRS_ALPHAFUNC, g_dwAlphaCmp[curtest.atst]); + } + + if( dwUsingSpecialTesting ) { + // render the real alpha + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1,NULL); + } + + SETRS(D3DRS_ZWRITEENABLE, FALSE); + + SETRS(D3DRS_STENCILMASK, STENCIL_SPECIAL|STENCIL_PIXELWRITE); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); + SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + SETRS(D3DRS_STENCILREF, STENCIL_SPECIAL|STENCIL_PIXELWRITE); + + DXVEC4 v = DXVEC4(0,exactcolor ? 510.0f : 2.0f,0,0); + SETCONSTF(GPU_ONECOLOR, v); + DRAW(); + + // don't need to restore + } + + if( s_bDestAlphaTest ) { + if( (s_dwColorWrite&D3DCOLORWRITEENABLE_ALPHA) ) { + if( curvb.fba.fba ) + ProcessFBA(curvb); + else if( bCanRenderStencil ) + // finally make sure all entries are 1 when the dest alpha >= 0x80 (if fba is 1, this is already the case) + ProcessStencil(curvb); + } + } + else if( (s_dwColorWrite&D3DCOLORWRITEENABLE_ALPHA) && curvb.fba.fba ) + ProcessFBA(curvb); + + if( bDestAlphaColor == 1 ) { + // need to reset the dest colors to their original counter parts + //WARN_LOG("Need to reset dest alpha color\n"); + } + +#ifdef _DEBUG + if( g_bSaveFlushedFrame & 0xf ) { + char str[255]; + sprintf(str, "frames\\frame%.4d.jpg", g_SaveFrameNum++); + if( (g_bSaveFlushedFrame & 2) ) + D3DXSaveSurfaceToFile(str, D3DXIFF_JPG, curvb.prndr->psurf, NULL, NULL); + } +#endif + + // clamp the final colors, when enabled ffx2 credits mess up + if( curvb.curprim.abe && bAlphaClamping && g_RenderFormat != D3DFMT_A8R8G8B8 && !(g_GameSettings&GAME_NOCOLORCLAMP) ) { // if !colclamp, skip + + ResetAlphaVariables(); + + // if processing the clamping case, make sure can write to the front buffer + SETRS(D3DRS_STENCILENABLE, 0); + SETRS(D3DRS_ALPHABLENDENABLE, TRUE); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RED|D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1,NULL); + } + + pd3dDevice->SetPixelShader(ppsOne); + + // (dest&0x7f)+0x80, blend factor for alpha is always 0x80 + SETRS(D3DRS_DESTBLEND, D3DBLEND_ONE); + SETRS(D3DRS_SRCBLEND, D3DBLEND_ONE); + + float f; + + if( bAlphaClamping & 1 ) { // min + f = 0; + SETCONSTF(GPU_ONECOLOR, &f); + SETRS(D3DRS_BLENDOP, D3DBLENDOP_MAX); + DRAW(); + } + + // bios shows white screen + if( bAlphaClamping & 2 ) { // max + f = 1; + SETCONSTF(GPU_ONECOLOR, &f); + SETRS(D3DRS_BLENDOP, D3DBLENDOP_MIN); + DRAW(); + } + + if( !curvb.zbuf.zmsk ) { + SETRS(D3DRS_ZWRITEENABLE, TRUE); + + if( s_bWriteDepth ) { + assert( curvb.pdepth != NULL ); + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + else pd3dDevice->SetRenderTarget(1,curvb.pdepth->psurf); + } + } + + if( curvb.test.ate && USEALPHATESTING ) + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + + SETRS(D3DRS_ZENABLE, curtest.zte); + } + + if( dwFilterOpts ) { + // undo filter changes + if( dwFilterOpts & 1 ) pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + if( dwFilterOpts & 2 ) pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MINFILTER, D3DTEXF_POINT); + } + + // reset used textures + if( shadertype > 2 ) { + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexBilinearBlocks); + } + + SETRS(D3DRS_CLIPPLANEENABLE, 0); +//#ifndef RELEASE_TO_PUBLIC + ppf += curvb.dwCount+0x100000; +//#endif + curvb.dwCurOff += POINT_BUFFERFLUSH; + SAFE_RELEASE(ptexRenderTargetCached); + + g_MaxRenderedHeight = 0; + curvb.dwCount = 0; + //curvb.Lock(); + curvb.curprim.abe = oldabe; + //if( oldabe ) SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); + + if( conf.options & GSOPTION_WIREFRAME ) { + // always render first few geometry as solid + if( s_nWireframeCount > 0 ) { + SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + --s_nWireframeCount; + } + } +} + +void ZeroGS::ProcessMessages() +{ + if( listMsgs.size() > 0 ) { + pSprite->Begin(D3DXSPRITE_ALPHABLEND|D3DXSPRITE_SORT_TEXTURE); + + RECT rctext; + rctext.left = 25; rctext.top = 15; + list::iterator it = listMsgs.begin(); + + while( it != listMsgs.end() ) { + rctext.left += 1; + rctext.top += 1; + pFont->DrawText(pSprite, it->str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xff000000); + rctext.left -= 1; + rctext.top -= 1; + pFont->DrawText(pSprite, it->str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xffffff30); + rctext.top += 15; + + if( (int)(it->dwTimeStamp - timeGetTime()) < 0 ) + it = listMsgs.erase(it); + else ++it; + } + + pSprite->End(); + } +} + +void ZeroGS::RenderCustom(float fAlpha) +{ + if( !s_bBeginScene ) + pd3dDevice->BeginScene(); + + pd3dDevice->SetDepthStencilSurface(psurfOrgDepth); + + pd3dDevice->SetRenderTarget(0, psurfOrgTarg); + + if( s_bWriteDepth ) + pd3dDevice->SetRenderTarget(1, NULL); + + SETRS(D3DRS_STENCILENABLE, 0); + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + SETRS(D3DRS_ALPHABLENDENABLE, 0); + SETRS(D3DRS_ALPHATESTENABLE, 0); + SETRS(D3DRS_SCISSORTESTENABLE, 0); + + // play custom animation + pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, 0, 1, 0); + + // tex coords + DXVEC4 v = DXVEC4(1, 1, 0, 0); + SETCONSTF(GPU_BITBLTTEX, v); + SETCONSTF(GPU_BITBLTPOS, v); + + v.x = v.y = v.z = v.w = fAlpha; + SETCONSTF(GPU_ONECOLOR, v); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + pd3dDevice->SetPixelShader(ppsBaseTexture); + + // inside vb[0]'s target area, so render that region only + pd3dDevice->SetTexture(SAMP_FINAL, ptexLogo); + //pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + //pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + + // restore + //pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + //pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_POINT); + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + + ProcessMessages(); + + pd3dDevice->EndScene(); + s_bBeginScene = FALSE; + + pd3dDevice->Present(NULL, NULL, NULL, NULL); + + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + SETRS(D3DRS_STENCILENABLE, 1); + + if( icurctx >= 0 ) vb[icurctx].bSyncVars = 0; +} + +// adjusts trans to preserve aspect ratio +void ZeroGS::AdjustTransToAspect(DXVEC4& v, int dispwidth, int dispheight) +{ + float temp, f; + if( dispwidth * height > dispheight * width ) { + // limited by width + + // change in ratio + f = ((float)width / (float)dispwidth) / ((float)height / (float)dispheight); + v.y *= f; + v.w *= f; + + // scanlines mess up when not aligned right + v.y += (1-modf(v.y*height/2+0.05f, &temp))*2.0f/(float)height; + v.w += (1-modf(v.w*height/2+0.05f, &temp))*2.0f/(float)height; + } + else { + // limited by height + f = ((float)height / (float)dispheight) / ((float)width / (float)dispwidth); + f -= modf(f*width, &temp)/(float)width; + v.x *= f; + v.z *= f; + } +} + +void ZeroGS::Restore() +{ + if( !g_bIsLost ) + return; + + if( SUCCEEDED(pd3dDevice->Reset(&d3dpp)) ) { + g_bIsLost = 0; + // handle lost states + ZeroGS::ChangeDeviceSize(width, height); + } +} + +void ZeroGS::RenderCRTC(int interlace) +{ + if( pd3dDevice == NULL ) { + return; + } + + if( g_bIsLost ) return; + +#ifdef RELEASE_TO_PUBLIC + if( g_nRealFrame < 80 ) { + RenderCustom( min(1.0f, 2.0f - (float)g_nRealFrame / 40.0f) ); + + if( g_nRealFrame == 79 ) + SAFE_RELEASE(ptexLogo); + return; + } +#endif + + Flush(0); + Flush(1); + + // frame skipping + if( g_nFrameRender > 0 ) { + + if( g_nFrameRender < 8 ) { + g_nFrameRender++; + if( g_nFrameRender <= 3 ) { + g_nFramesSkipped++; + return; + } + } + } + else { + if( g_nFrameRender < -1 ) { + g_nFramesSkipped++; + return; + } + g_nFrameRender--; + } + + if( g_bSaveFrame ) { + if( vb[0].prndr != NULL ) D3DXSaveSurfaceToFile("frame1.tga", D3DXIFF_TGA, vb[0].prndr->psurf, NULL, NULL); + + if( vb[1].prndr != NULL && vb[0].prndr != vb[1].prndr ) D3DXSaveSurfaceToFile("frame2.tga", D3DXIFF_TGA, vb[1].prndr->psurf, NULL, NULL); + else DeleteFile("frame2.tga"); + } + + if( s_RangeMngr.ranges.size() > 0 ) + FlushTransferRanges(NULL); + + if( icurctx >= 0 && vb[icurctx].bVarsSetTarg ) { // check if anything rendered + pd3dDevice->SetRenderTarget(0, psurfOrgTarg); + pd3dDevice->SetRenderTarget(1, NULL); + + pd3dDevice->SetDepthStencilSurface(psurfOrgDepth); + } + + D3DVIEWPORT9 view; + view.Width = width; + view.Height = height; + view.X = 0; + view.Y = 0; + view.MinZ = 0; + view.MaxZ = 1.0f; + pd3dDevice->SetViewport(&view); + + //g_GameSettings |= GAME_VSSHACK|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE; + //s_bWriteDepth = TRUE; + g_SaveFrameNum = 0; + g_bSaveFlushedFrame = 1; +// static int counter = 0; +// counter++; + // reset fba after every frame + //if( !(g_GameSettings&GAME_NOFBARESET) ) { + vb[0].fba.fba = 0; + vb[1].fba.fba = 0; + //} + u32 bInterlace = SMODE2->INT && SMODE2->FFMD && (conf.interlace<2); + + // if interlace, only clear every other vsync + if(!bInterlace ) { + u32 color = D3DCOLOR_ARGB(0, BGCOLOR->R, BGCOLOR->G, BGCOLOR->B); + pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_STENCIL, color, 1, 0); + } + + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + SETRS(D3DRS_ZENABLE, 0); + SETRS(D3DRS_ZWRITEENABLE, 0); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + SETRS(D3DRS_ALPHABLENDENABLE, 0); + SETRS(D3DRS_ALPHATESTENABLE, 0); + SETRS(D3DRS_SCISSORTESTENABLE, 0); + SETRS(D3DRS_STENCILENABLE, 0); + + BOOL bUsingStencil = 0; + + if( bInterlace ) g_PrevBitwiseTexX = -1; // reset since will be using + + tex0Info dispinfo[2]; + + for(int i = 0; i < 2; ++i) { + + if( !(*(u32*)(PMODE) & (1<MAGH+1; + int magv = pd->MAGV+1; + + dispinfo[i].tbp0 = pfb->FBP << 5; + dispinfo[i].tbw = pfb->FBW << 6; + dispinfo[i].tw = (pd->DW + 1) / magh; + dispinfo[i].th = (pd->DH + 1) / magv; + dispinfo[i].psm = pfb->PSM; + + // hack!! + // 2 * dispinfo[i].tw / dispinfo[i].th <= 1, metal slug 4 + if( bInterlace && 2 * dispinfo[i].tw / dispinfo[i].th <= 1 && !(g_GameSettings&GAME_INTERLACE2X) ) { + dispinfo[i].th >>= 1; + } + } + + //int dispwidth = max(dispinfo[0].tw, dispinfo[1].tw), dispheight = max(dispinfo[0].th, dispinfo[1].th); + + // hack!, CMOD != 3, gradius +// if( SMODE2->INT && SMODE2->FFMD && SMODE1->CMOD == 3 && dispwidth <= 320) +// dispwidth *= 2; + + // hack! makai + //if( !bInterlace && dispheight * 2 < dispwidth ) dispheight *= 2; + + // start from the last circuit + for(int i = !PMODE->SLBG; i >= 0; --i) { + + tex0Info& texframe = dispinfo[i]; + if( texframe.th <= 1 ) + continue; + + GSRegDISPFB* pfb = i ? DISPFB2 : DISPFB1; + GSRegDISPLAY* pd = i ? DISPLAY2 : DISPLAY1; + + DXVEC4 v, valpha; + + if( bInterlace ) { + + texframe.th >>= 1; + + // interlace mode + pd3dDevice->SetTexture(SAMP_INTERLACE, CreateInterlaceTex(2*texframe.th)); + + if( interlace == (conf.interlace&1) ) { + // pass if odd + valpha.z = 1.0f; + valpha.w = -0.4999f; + } + else { + // pass if even + valpha.z = -1.0f; + valpha.w = 0.5001f; + } + } + else { + + if( SMODE2->INT && SMODE2->FFMD ) { + texframe.th >>= 1; + } + + // always pass interlace test + valpha.z = 0; + valpha.w = 1; + } + + int bpp = 4; + if( texframe.psm == 0x12 ) bpp = 3; + else if( texframe.psm & 2 ) bpp = 2; + + // get the start and end addresses of the buffer + int start, end; + GetRectMemAddress(start, end, texframe.psm, 0, 0, texframe.tw, texframe.th, texframe.tbp0, texframe.tbw); + + if( i == 0 ) { + // setup right blending + SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + SETRS(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD); + + if( PMODE->MMOD ) { + SETRS(D3DRS_BLENDFACTOR, D3DCOLOR_ARGB(0x80, PMODE->ALP, PMODE->ALP, PMODE->ALP)); + SETRS(D3DRS_SRCBLEND, D3DBLEND_BLENDFACTOR); + SETRS(D3DRS_DESTBLEND, D3DBLEND_INVBLENDFACTOR); + } + else { + SETRS(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + SETRS(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + } + + SETRS(D3DRS_SRCBLENDALPHA, PMODE->AMOD ? D3DBLEND_ZERO : D3DBLEND_ONE); + SETRS(D3DRS_DESTBLENDALPHA, PMODE->AMOD? D3DBLEND_ONE : D3DBLEND_ZERO); + } + + if( bUsingStencil ) { + SETRS(D3DRS_STENCILWRITEMASK, 1<SetPixelShader(ppsCRTC24[bInterlace]); + valpha.x = 0; + valpha.y = 1; + SETCONSTF(GPU_ONECOLOR, valpha); + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + continue; + } + + // first render the current render targets, then from ptexMem + if( texframe.psm == 1 ) { + valpha.x = 0; + valpha.y = 1; + } + else { + valpha.x = 1; + valpha.y = 0; + } + + SETCONSTF(GPU_ONECOLOR, valpha); + + BOOL bSkip = 0; + BOOL bResolveTargs = 1; + + //s_mapFrameHeights[s_nCurFrameMap][texframe.tbp0] = texframe.th; + list listTargs; + + s_RTs.GetTargs(start, end, listTargs); + + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ) { + + CRenderTarget* ptarg = *it; + + if( ptarg->fbw == texframe.tbw && !(ptarg->status&CRenderTarget::TS_NeedUpdate) && ((256/bpp)*(texframe.tbp0-ptarg->fbp))%texframe.tbw == 0 ) { + + if( ptarg->fbp != texframe.tbp0 ) { + // look for a better target (metal slug 5) + list::iterator itbetter; + for(itbetter = listTargs.begin(); itbetter != listTargs.end(); ++itbetter ) { + if( (*itbetter)->fbp == texframe.tbp0 ) + break; + } + + if( itbetter != listTargs.end() ) { + it = listTargs.erase(it); + continue; + } + } + + static int sindex = 0; + char strtemp[25]; + sprintf(strtemp, "frames/frame%d.jpg", sindex++); +// D3DXSaveSurfaceToFile(strtemp, D3DXIFF_JPG, ptarg->psurf, NULL, NULL); +// if( g_bSaveFinalFrame ) +// D3DXSaveSurfaceToFile("frame1.tga", D3DXIFF_TGA, ptarg->psurf, NULL, NULL); + + int dby = pfb->DBY; + int movy = 0; + + // determine the rectangle to render + if( ptarg->fbp < texframe.tbp0 ) { + dby += (256/bpp)*(texframe.tbp0-ptarg->fbp)/texframe.tbw; + } + else if( ptarg->fbp > texframe.tbp0 ) { + dby -= (256/bpp)*(ptarg->fbp-texframe.tbp0)/texframe.tbw; + + if( dby < 0 ) { + movy = -dby; + dby = 0; + } + } + + int dh = min(ptarg->fbh - dby, texframe.th-movy); + + if( dh >= 64 ) { + + if( ptarg->fbh - dby < texframe.th-movy && !bUsingStencil ) { + + if( !bUsingStencil ) { + pd3dDevice->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 1, 0); + } + bUsingStencil = 1; + SETRS(D3DRS_STENCILENABLE, TRUE); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, D3DCMP_NOTEQUAL); + SETRS(D3DRS_STENCILREF, 3); + SETRS(D3DRS_STENCILWRITEMASK, 1<fbh; + + // tex coords + v = DXVEC4(fiw*(float)texframe.tw, fih*(float)(dh), fiw*(float)(pfb->DBX), fih*((float)dby-0.5f)); + SETCONSTF(GPU_BITBLTTEX, v); + + // dest rect + v.x = 1; + v.y = dh/(float)texframe.th; + v.z = 0; + v.w = 1-v.y; + + if( movy > 0 ) + v.w -= movy/(float)texframe.th; + + if (bInterlace && interlace == (conf.interlace&1) ) { + // move down by 1 pixel + v.w += 1.0f / (float)dh; + } + + AdjustTransToAspect(v, (conf.options&GSOPTION_WIDESCREEN)?960:640, (conf.options&GSOPTION_WIDESCREEN)?540:480); + SETCONSTF(GPU_BITBLTPOS, v); + + // use GPU_INVTEXDIMS to store inverse texture dims + v.x = fiw; + v.y = fih; + v.z = 0; + SETCONSTF(GPU_INVTEXDIMS, v); + + // inside vb[0]'s target area, so render that region only + pd3dDevice->SetTexture(SAMP_FINAL, ptarg->ptex); + pd3dDevice->SetPixelShader(ppsCRTCTarg[bInterlace]); + + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + + if( abs(dh - (int)texframe.th) <= 1 ) { + bSkip = 1; + break; + } + if( abs(dh - (int)ptarg->fbh) <= 1 ) { + it = listTargs.erase(it); + continue; + } + } + } + + ++it; + } + + if( !bSkip ) { + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) + (*it)->Resolve(); + + // context has to be 0 + SetTexVariablesInt(0, 2, texframe, g_MemTargs.GetMemoryTarget(texframe, 1), 1); + + if( g_bSaveFinalFrame ) + SaveTex(&texframe, g_bSaveFinalFrame-1>0); + + // finally render from the memory (note that the stencil buffer will keep previous regions) + v = DXVEC4(1,1,0,0); + + if (bInterlace && interlace == (conf.interlace)) { + // move down by 1 pixel + v.w += 1.0f / (float)texframe.th; + } + + AdjustTransToAspect(v, (conf.options&GSOPTION_WIDESCREEN)?960:640, (conf.options&GSOPTION_WIDESCREEN)?540:480); + SETCONSTF(GPU_BITBLTPOS, v); + + v = DXVEC4(texframe.tw,texframe.th,-0.5f,-0.5f); + SETCONSTF(GPU_BITBLTTEX, v); + + // use GPU_INVTEXDIMS to store inverse texture dims + v.x = 1.0f / (float)texframe.tw; + v.y = 1.0f / (float)texframe.th; + v.z = 0;//-0.5f * v.x; + v.w = -0.5f * v.y; + SETCONSTF(GPU_INVTEXDIMS, v); + + pd3dDevice->SetPixelShader(ppsCRTC[bInterlace]); + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + } + } + + if(1) {// || !bInterlace) { + s_bBeginScene = FALSE; + + ProcessMessages(); + + if( g_bMakeSnapshot ) { + RECT rctext; + char str[64]; + rctext.left = 200; rctext.top = 15; + sprintf(str, "ZeroGS %d.%d.%d - %.1f fps %s", revision, build, minor, fFPS, s_frameskipping?" - frameskipping":""); + + pSprite->Begin(D3DXSPRITE_ALPHABLEND|D3DXSPRITE_SORT_TEXTURE); + rctext.left += 1; + rctext.top += 1; + pFont->DrawText(pSprite, str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xff000000); + rctext.left -= 1; + rctext.top -= 1; + pFont->DrawText(pSprite, str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xffc0ffff); + pSprite->End(); + } + + if( g_bDisplayFPS ) { + RECT rctext; + char str[64]; + rctext.left = 10; rctext.top = 10; + sprintf(str, "%.1f fps", fFPS); + + pSprite->Begin(D3DXSPRITE_ALPHABLEND|D3DXSPRITE_SORT_TEXTURE); + rctext.left += 1; + rctext.top += 1; + pFont->DrawText(pSprite, str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xff000000); + rctext.left -= 1; + rctext.top -= 1; + pFont->DrawText(pSprite, str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xffc0ffff); + pSprite->End(); + } + + pd3dDevice->EndScene(); + if( pd3dDevice->Present(NULL, NULL, NULL, NULL) == D3DERR_DEVICELOST ) { + // device is lost, need to recreate + DEBUG_LOG("device lost\n"); + g_bIsLost = TRUE; + Reset(); + return; + } + + if( conf.options & GSOPTION_WIREFRAME ) { + // clear all targets + s_nWireframeCount = 1; + } + + if( g_bMakeSnapshot ) { + + if( SUCCEEDED(D3DXSaveSurfaceToFile(strSnapshot != ""?strSnapshot.c_str():"temp.jpg", (conf.options&GSOPTION_BMPSNAP)?D3DXIFF_BMP:D3DXIFF_JPG, psurfOrgTarg, NULL, NULL)) ) { + char str[255]; + sprintf(str, "saved %s\n", strSnapshot.c_str()); + AddMessage(str, 500); + } + g_bMakeSnapshot = 0; + } + + if( s_avicapturing ) { + CaptureFrame(); + } + + if( s_nNewWidth >= 0 && s_nNewHeight >= 0 && !g_bIsLost ) { + Reset(); + ChangeDeviceSize(s_nNewWidth, s_nNewHeight); + s_nNewWidth = s_nNewHeight = -1; + } + + // switch the fbp lists +// s_nCurFBPSet ^= 1; +// s_setFBP[s_nCurFBPSet].clear(); + //s_nCurFrameMap ^= 1; + //s_mapFrameHeights[s_nCurFrameMap].clear(); + } + + pd3dDevice->SetTexture(SAMP_FINAL, NULL); // d3d debug complains if not + g_MemTargs.DestroyCleared(); + + for(list::iterator it = s_vecTempTextures.begin(); it != s_vecTempTextures.end(); ++it) + (*it)->Release(); + s_vecTempTextures.clear(); + + if( EXTWRITE->WRITE&1 ) { + WARN_LOG("EXTWRITE\n"); + ExtWrite(); + EXTWRITE->WRITE = 0; + } + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + + if( icurctx >= 0 ) { + vb[icurctx].bVarsSetTarg = FALSE; + vb[icurctx].bVarsTexSync = FALSE; + vb[0].bVarsTexSync = FALSE; + } + + // statistics + if( s_nWriteDepthCount > 0 ) { + assert( conf.mrtdepth ); + if( --s_nWriteDepthCount <= 0 ) { + s_bWriteDepth = FALSE; + } + } + + if( s_nWriteDestAlphaTest > 0 ) { + if( --s_nWriteDestAlphaTest <= 0 ) { + s_bDestAlphaTest = FALSE; + } + } + + if( g_GameSettings & GAME_AUTORESET ) { + s_nResolveCounts[s_nCurResolveIndex] = s_nResolved; + s_nCurResolveIndex = (s_nCurResolveIndex+1)%ARRAYSIZE(s_nResolveCounts); + + int total = 0; + for(int i = 0; i < ARRAYSIZE(s_nResolveCounts); ++i) total += s_nResolveCounts[i]; + + if( total / ARRAYSIZE(s_nResolveCounts) > 3 ) { + if( s_nLastResolveReset > (int)(fFPS * 8) ) { + // reset + DEBUG_LOG("ZeroGS: video mem reset\n"); + s_nLastResolveReset = 0; + memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); + + s_RTs.ResolveAll(); + s_RTs.Destroy(); + s_DepthRTs.ResolveAll(); + s_DepthRTs.Destroy(); + + vb[0].prndr = NULL; vb[0].pdepth = NULL; vb[0].bNeedFrameCheck = 1; vb[0].bNeedZCheck = 1; + vb[1].prndr = NULL; vb[1].pdepth = NULL; vb[1].bNeedFrameCheck = 1; vb[1].bNeedZCheck = 1; + } + } + + s_nLastResolveReset++; + } + + if( s_nResolved > 8 ) s_nResolved = 2; + else if( s_nResolved > 0 ) --s_nResolved; + + if( g_nDepthUsed > 0 ) --g_nDepthUsed; + + s_ClutResolve = 0; + s_PSM8Resolve = 0; + g_nDepthUpdateCount = 0; + + maxmin = 608; +} + +////////////////////////// +// Internal Definitions // +////////////////////////// + +__forceinline void MOVZ(VertexGPU *p, u32 gsz, const VB& curvb) +{ + p->z = curvb.zprimmask==0xffff?min((u32)0xffff, gsz):gsz; +} + +__forceinline void MOVFOG(VertexGPU *p, Vertex gsf) +{ + p->f = ((s16)(gsf).f<<7)|0x7f; +} + +__forceinline void SET_VERTEX(VertexGPU *p, int Index, const VB& curvb) +{ + int index = Index; + + p->x = (((int)gs.gsvertex[index].x - curvb.offset.x)>>1)&0xffff; + p->y = (((int)gs.gsvertex[index].y - curvb.offset.y)>>1)&0xffff; + + /*x = ((int)gs.gsvertex[index].x - curvb.offset.x); + y = ((int)gs.gsvertex[index].y - curvb.offset.y); + p.x = (x&0x7fff) | (x < 0 ? 0x8000 : 0); + p.y = (y&0x7fff) | (y < 0 ? 0x8000 : 0);*/ + + p->f = ((s16)gs.gsvertex[index].f<<7)|0x7f; + MOVZ(p, gs.gsvertex[index].z, curvb); + p->rgba = prim->iip ? gs.gsvertex[index].rgba : gs.rgba; + + if ((g_GameSettings & GAME_TEXAHACK) && !(p->rgba&0xffffff)) + p->rgba = 0; + if (prim->tme ) + { + if( prim->fst ) + { + p->s = (float)gs.gsvertex[index].u * fiTexWidth[prim->ctxt]; + p->t = (float)gs.gsvertex[index].v * fiTexHeight[prim->ctxt]; + p->q = 1; + } + else + { + p->s = gs.gsvertex[index].s; + p->t = gs.gsvertex[index].t; + p->q = gs.gsvertex[index].q; + } + } +} + +#define OUTPUT_VERT(fn, vert, id) { \ + fn("%c%d(%d): xyzf=(%4d,%4d,0x%x,%3d), rgba=0x%8.8x, stq = (%2.5f,%2.5f,%2.5f)\n", id==0?'*':' ', id, prim->prim, vert.x/8, vert.y/8, vert.z, vert.f/128, \ + vert.rgba, Clamp(vert.s, -10, 10), Clamp(vert.t, -10, 10), Clamp(vert.q, -10, 10)); \ +} \ + + +void ZeroGS::KickPoint() +{ + assert( gs.primC >= 1 ); + + VB& curvb = vb[prim->ctxt]; + if (curvb.bNeedTexCheck) curvb.FlushTexData(); + + if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].dwCount == 0 ); + Flush(!prim->ctxt); + } + + if( curvb.dwCount >= POINT_BUFFERFLUSH) + Flush(prim->ctxt); + + curvb.Lock(); + int last = (gs.primIndex+2)%ARRAYSIZE(gs.gsvertex); + + VertexGPU* p = curvb.pbuf+curvb.dwCount; + SET_VERTEX(&p[0], last, curvb); + curvb.dwCount++; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); +#endif +} + +void ZeroGS::KickLine() +{ + assert( gs.primC >= 2 ); + VB& curvb = vb[prim->ctxt]; + if( curvb.bNeedTexCheck ) + curvb.FlushTexData(); + + if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].dwCount == 0 ); + Flush(!prim->ctxt); + } + + if( curvb.dwCount >= POINT_BUFFERFLUSH/2 ) + Flush(prim->ctxt); + + curvb.Lock(); + int next = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + int last = (gs.primIndex+2)%ARRAYSIZE(gs.gsvertex); + + VertexGPU* p = curvb.pbuf+curvb.dwCount*2; + SET_VERTEX(&p[0], next, curvb); + SET_VERTEX(&p[1], last, curvb); + + curvb.dwCount++; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); +#endif +} + +void ZeroGS::KickTriangle() +{ + assert( gs.primC >= 3 ); + VB& curvb = vb[prim->ctxt]; + if (curvb.bNeedTexCheck) curvb.FlushTexData(); + + if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].dwCount == 0 ); + Flush(!prim->ctxt); + } + + if( curvb.dwCount >= POINT_BUFFERFLUSH/3 ) + Flush(prim->ctxt); + + curvb.Lock(); + VertexGPU* p = curvb.pbuf+curvb.dwCount*3; + SET_VERTEX(&p[0], 0, curvb); + SET_VERTEX(&p[1], 1, curvb); + SET_VERTEX(&p[2], 2, curvb); + + curvb.dwCount++; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); + OUTPUT_VERT(PRIM_LOG, p[2], 2); +#endif +} + +void ZeroGS::KickTriangleFan() +{ + assert( gs.primC >= 3 ); + VB& curvb = vb[prim->ctxt]; + if (curvb.bNeedTexCheck) curvb.FlushTexData(); + + if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].dwCount == 0 ); + Flush(!prim->ctxt); + } + + if( curvb.dwCount >= POINT_BUFFERFLUSH/3 ) + Flush(prim->ctxt); + + curvb.Lock(); + VertexGPU* p = curvb.pbuf+curvb.dwCount*3; + SET_VERTEX(&p[0], 0, curvb); + SET_VERTEX(&p[1], 1, curvb); + SET_VERTEX(&p[2], 2, curvb); + + curvb.dwCount++; + + // add 1 to skip the first vertex + if( gs.primIndex == gs.nTriFanVert ) + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); + OUTPUT_VERT(PRIM_LOG, p[2], 2); +#endif +} + +__forceinline void SetKickVertex(VertexGPU *p, Vertex v, int next, const VB& curvb) +{ + SET_VERTEX(p, next, curvb); + MOVZ(p, v.z, curvb); + MOVFOG(p, v); +} + +void ZeroGS::KickSprite() +{ + assert( gs.primC >= 2 ); + VB& curvb = vb[prim->ctxt]; + if( curvb.bNeedTexCheck ) + curvb.FlushTexData(); + + if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].dwCount == 0 ); + Flush(!prim->ctxt); + } + + if (curvb.dwCount >= POINT_BUFFERFLUSH/3) Flush(prim->ctxt); + + curvb.Lock(); + int next = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + int last = (gs.primIndex+2)%ARRAYSIZE(gs.gsvertex); + + // sprite is too small and AA shows lines (tek4) + if( s_AAx ) + { + gs.gsvertex[last].x += 4; + if (s_AAy) gs.gsvertex[last].y += 4; + } + + // might be bad sprite (KH dialog text) + //if( gs.gsvertex[next].x == gs.gsvertex[last].x || gs.gsvertex[next].y == gs.gsvertex[last].y ) + // return; + + VertexGPU* p = curvb.pbuf+curvb.dwCount*3; + + SetKickVertex(&p[0], gs.gsvertex[last], next, curvb); + SetKickVertex(&p[3], gs.gsvertex[last], next, curvb); + SetKickVertex(&p[1], gs.gsvertex[last], last, curvb); + SetKickVertex(&p[4], gs.gsvertex[last], last, curvb); + + if (g_MaxRenderedHeight < p[0].y) g_MaxRenderedHeight = p[0].y; + if (g_MaxRenderedHeight < p[1].y) g_MaxRenderedHeight = p[1].y; + + SetKickVertex(&p[2], gs.gsvertex[last], next, curvb); + p[2].s = p[1].s; + p[2].x = p[1].x; + + SetKickVertex(&p[5], gs.gsvertex[last], last, curvb); + p[5].s = p[0].s; + p[5].x = p[0].x; + + curvb.dwCount += 2; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); +#endif +} + +void ZeroGS::KickDummy() +{ + //GREG_LOG("Kicking bad primitive: %.8x\n", *(u32*)prim); +} + +__forceinline void ZeroGS::RenderFBA(const VB& curvb) +{ + // add fba to all pixels + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_CLEAR); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFAIL, D3DSTENCILOP_ZERO); + SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + SETRS(D3DRS_STENCILREF, STENCIL_FBA); + + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1, NULL); + } + + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + SETRS(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); + SETRS(D3DRS_ALPHAREF, 0xff); + + DXVEC4 v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + SETCONSTF(GPU_ONECOLOR, v); + + DRAW(); + + if( !curvb.test.ate ) + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + else { + SETRS(D3DRS_ALPHAFUNC, g_dwAlphaCmp[curvb.test.atst]); + SETRS(D3DRS_ALPHAREF, b2XAlphaTest ? min(255,2 * curvb.test.aref) : curvb.test.aref); + } + + // reset (not necessary) + SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); + SETRS(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); + + if( !curvb.zbuf.zmsk ) { + SETRS(D3DRS_ZWRITEENABLE, TRUE); + + assert( curvb.pdepth != NULL ); + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + else pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); + } + } + SETRS(D3DRS_ZENABLE, curvb.test.zte); +} + +__forceinline void ZeroGS::RenderAlphaTest(const VB& curvb) +{ + if( !g_bUpdateStencil ) return; + + if( curvb.test.ate ) { + if( curvb.test.afail == 1 ) SETRS(D3DRS_ALPHATESTENABLE, FALSE); + } + + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0); + + DXVEC4 v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + SETCONSTF(GPU_ONECOLOR, v); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1,NULL); + } + + // or a 1 to the stencil buffer wherever alpha passes + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + + SETRS(D3DRS_STENCILENABLE, TRUE); + + if( !s_bDestAlphaTest ) { + // clear everything + SETRS(D3DRS_STENCILREF, 0); + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_CLEAR); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + DRAW(); + + if( curvb.test.ate && curvb.test.afail != 1 && USEALPHATESTING) + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + } + + if( curvb.test.ate && curvb.test.atst>1 && curvb.test.aref > 0x80) { + v.x = 1; v.y = 1; v.z = 0; v.w = 0; + SETCONSTF(GPU_ONECOLOR, v); + SETRS(D3DRS_ALPHAREF, curvb.test.aref); + } + + SETRS(D3DRS_STENCILREF, STENCIL_SPECIAL); + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_SPECIAL); + SETRS(D3DRS_ZENABLE, FALSE); + + DRAW(); + + if( curvb.test.zte ) SETRS(D3DRS_ZENABLE, TRUE); + SETRS(D3DRS_ALPHATESTENABLE, 0); + SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); + + if( !curvb.zbuf.zmsk ) { + SETRS(D3DRS_ZWRITEENABLE, TRUE); + + // set rt next level + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + else pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); + } + } +} + +__forceinline void ZeroGS::RenderStencil(const VB& curvb, DWORD dwUsingSpecialTesting) +{ + //NOTE: This stencil hack for dest alpha testing ONLY works when + // the geometry in one DrawPrimitive call does not overlap + + // mark the stencil buffer for the new data's bits (mark 4 if alpha is >= 0xff) + // mark 4 if a pixel was written (so that the stencil buf can be changed with new values) + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_PIXELWRITE); + + dwStencilMask = (curvb.test.date?STENCIL_ALPHABIT:0)|(dwUsingSpecialTesting?STENCIL_SPECIAL:0); + SETRS(D3DRS_STENCILMASK, dwStencilMask); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, dwStencilMask ? D3DCMP_EQUAL : D3DCMP_ALWAYS); + + dwStencilRef = curvb.test.date*curvb.test.datm|STENCIL_PIXELWRITE|(dwUsingSpecialTesting?STENCIL_SPECIAL:0); + SETRS(D3DRS_STENCILREF, dwStencilRef); +} + +__forceinline void ZeroGS::ProcessStencil(const VB& curvb) +{ + assert( !curvb.fba.fba ); + + // set new alpha bit + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_ALPHABIT); + SETRS(D3DRS_STENCILMASK, STENCIL_PIXELWRITE|STENCIL_FBA); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + SETRS(D3DRS_STENCILREF, STENCIL_PIXELWRITE); + + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1, NULL); + } + + SETRS(D3DRS_ALPHATESTENABLE, 0); + + pd3dDevice->SetPixelShader(ppsOne); + DRAW(); + + // process when alpha >= 0xff + SETRS(D3DRS_STENCILREF, STENCIL_PIXELWRITE|STENCIL_FBA|STENCIL_ALPHABIT); + SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + DRAW(); + + // clear STENCIL_PIXELWRITE bit + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_CLEAR); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + SETRS(D3DRS_STENCILREF, 0); + + DRAW(); + + // restore state + SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); + + if( curvb.test.ate && USEALPHATESTING) + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + + if( !curvb.zbuf.zmsk ) { + SETRS(D3DRS_ZWRITEENABLE, TRUE); + + if( s_bWriteDepth ) { + assert( curvb.pdepth != NULL ); + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + else pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); + } + } + + SETRS(D3DRS_ZENABLE, curvb.test.zte); + + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); +} + +__forceinline void ZeroGS::ProcessFBA(const VB& curvb) +{ + if( (curvb.frame.fbm&0x80000000) ) return; + + // add fba to all pixels that were written and alpha was less than 0xff + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_ALPHABIT); + SETRS(D3DRS_STENCILMASK, STENCIL_PIXELWRITE|STENCIL_FBA); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + SETRS(D3DRS_STENCILREF, STENCIL_FBA|STENCIL_PIXELWRITE|STENCIL_ALPHABIT); + + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1, NULL); + } + + // processes the pixels with ALPHA < 0x80*2 + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + SETRS(D3DRS_ALPHAFUNC, D3DCMP_LESSEQUAL); + SETRS(D3DRS_ALPHAREF, 0xff); + + // add 1 to dest + SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); + SETRS(D3DRS_DESTBLENDALPHA, D3DBLEND_ONE); + SETRS(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD); + + float f = 1; + SETCONSTF(GPU_ONECOLOR, &f); + pd3dDevice->SetPixelShader(ppsOne); + + DRAW(); + + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + + // reset bits + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_CLEAR); + SETRS(D3DRS_STENCILMASK, STENCIL_PIXELWRITE|STENCIL_FBA); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_ZERO); + SETRS(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); + SETRS(D3DRS_STENCILFUNC, D3DCMP_GREATER); + SETRS(D3DRS_STENCILREF, 0); + + DRAW(); + + if( curvb.test.atst && USEALPHATESTING) { + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + SETRS(D3DRS_ALPHAFUNC, g_dwAlphaCmp[curvb.test.atst]); + SETRS(D3DRS_ALPHAREF, b2XAlphaTest ? min(255,2 * curvb.test.aref) : curvb.test.aref); + } + + // restore (SetAlphaVariables) + if( !bNeedAlphaColor ) SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);//(bNeedBlendFactorInAlpha ? D3DBLEND_ZERO : D3DBLEND_ONE)); + SETRS(D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO);//bNeedBlendFactorInAlpha ? D3DBLEND_ONE : D3DBLEND_ZERO); + if(bNeedAlphaColor && vAlphaBlendColor.y<0) SETRS(D3DRS_BLENDOPALPHA, D3DBLENDOP_REVSUBTRACT); + + // reset (not necessary) + SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); + + if( !curvb.zbuf.zmsk ) { + SETRS(D3DRS_ZWRITEENABLE, TRUE); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + else pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); + } + } + SETRS(D3DRS_ZENABLE, curvb.test.zte); +} + +inline void ZeroGS::SetContextTarget(int context) +{ + VB& curvb = vb[context]; + + if( curvb.prndr == NULL ) + curvb.prndr = s_RTs.GetTarg(curvb.frame, 0, GET_MAXHEIGHT(curvb.gsfb.fbp, curvb.gsfb.fbw, curvb.gsfb.psm)); + + // make sure targets are valid + if( curvb.pdepth == NULL ) { + frameInfo f; + f.fbp = curvb.zbuf.zbp; + f.fbw = curvb.frame.fbw; + f.fbh = curvb.prndr->fbh; + f.psm = curvb.zbuf.psm; + f.fbm = 0; + curvb.pdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| + (curvb.zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), GET_MAXHEIGHT(curvb.zbuf.zbp, curvb.gsfb.fbw, 0)); + } + + assert( curvb.prndr != NULL && curvb.pdepth != NULL ); + assert( curvb.pdepth->fbh == curvb.prndr->targheight ); + +// if( curvb.pdepth->fbh != curvb.prndr->fbh ) { +// +// s_DepthRTs.DestroyTarg(curvb.pdepth); +// ERROR_LOG("ZeroGS: render and depth heights different: %x %x\n", curvb.prndr->fbh, curvb.pdepth->fbh); +// frameInfo f; +// f.fbp = curvb.zbuf.zbp; +// f.fbw = curvb.frame.fbw; +// f.fbh = curvb.prndr->fbh; +// f.psm = curvb.zbuf.psm; +// f.fbm = 0; +// curvb.pdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| +// (curvb.zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), GET_MAXHEIGHT(curvb.zbuf.zbp, curvb.gsfb.fbw, 0)); +// } + + if( curvb.pdepth->status & CRenderTarget::TS_Virtual) { + + if( !curvb.zbuf.zmsk ) { + CRenderTarget* ptemp = s_DepthRTs.Promote(curvb.pdepth->fbp|(curvb.pdepth->fbw<<16)); + assert( ptemp == curvb.pdepth ); + } + else + curvb.pdepth->status &= ~CRenderTarget::TS_NeedUpdate; + } + + BOOL bSetTarg = 1; + if( curvb.pdepth->status & CRenderTarget::TS_NeedUpdate ) { + + assert( !(curvb.pdepth->status & CRenderTarget::TS_Virtual) ); + + // don't update if virtual + curvb.pdepth->Update(context, curvb.prndr); + bSetTarg = 0; + } + + if( curvb.prndr->status & CRenderTarget::TS_NeedUpdate ) { + + if( s_bWriteDepth ) { + if( bSetTarg ) { + pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); + pd3dDevice->SetDepthStencilSurface(curvb.pdepth->pdepth); + } + } + else if( bSetTarg ) + pd3dDevice->SetDepthStencilSurface(curvb.pdepth->pdepth); + + curvb.prndr->Update(context, curvb.pdepth); + // note, targ already set + } + else { + + //if( (vb[0].prndr != vb[1].prndr && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg ) + pd3dDevice->SetRenderTarget(0, curvb.prndr->psurf); + //if( bSetTarg && ((vb[0].pdepth != vb[1].pdepth && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg) ) + curvb.pdepth->SetDepthTarget(); + + if( s_ptexCurSet[0] == curvb.prndr->ptex ) { + s_ptexCurSet[0] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY0, NULL); + } + if( s_ptexCurSet[1] == curvb.prndr->ptex ) { + s_ptexCurSet[1] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY1, NULL); + } + + curvb.prndr->SetViewport(); + } + + curvb.prndr->SetTarget(curvb.frame.fbp, curvb.scissor, context); + + if( (curvb.zbuf.zbp-curvb.pdepth->fbp) != (curvb.frame.fbp - curvb.prndr->fbp) && curvb.test.zte ) { + WARN_LOG("frame and zbuf not aligned\n"); + } + + curvb.bVarsSetTarg = TRUE; + if( vb[!context].prndr != curvb.prndr ) + vb[!context].bVarsSetTarg = FALSE; + + assert( !(curvb.prndr->status&CRenderTarget::TS_NeedUpdate) ); + assert( curvb.pdepth == NULL || !(curvb.pdepth->status&CRenderTarget::TS_NeedUpdate) ); +} + +void ZeroGS::SetTexVariables(int context) +{ + if( !vb[context].curprim.tme ) { + return; + } + + assert( !vb[context].bNeedTexCheck ); + + DXVEC4 v, v2; + tex0Info& tex0 = vb[context].tex0; + + float fw = (float)tex0.tw; + float fh = (float)tex0.th; + + if( !vb[context].bTexConstsSync ) { + // alpha and texture highlighting + DXVEC4 valpha, valpha2; + + // if clut, use the frame format + int psm = tex0.psm; + if( PSMT_ISCLUT(tex0.psm) ) psm = tex0.cpsm; + + int nNeedAlpha = (psm == 1 || psm == 2 || psm == 10); + + DXVEC4 vblack; + vblack.x = vblack.y = vblack.z = vblack.w = 10; + + switch(tex0.tfx) { + case 0: + valpha.z = 0; valpha.w = 0; + valpha2.x = 0; valpha2.y = 0; + valpha2.z = 2; valpha2.w = 1; + + break; + case 1: + valpha.z = 0; valpha.w = 1; + valpha2.x = 1; valpha2.y = 0; + valpha2.z = 0; valpha2.w = 0; + + break; + case 2: + valpha.z = 1; valpha.w = 1.0f; + valpha2.x = 0; valpha2.y = tex0.tcc ? 1.0f : 0.0f; + valpha2.z = 2; valpha2.w = 0; + + break; + + case 3: + valpha.z = 1; valpha.w = tex0.tcc ? 0.0f : 1.0f; + valpha2.x = 0; valpha2.y = tex0.tcc ? 1.0f : 0.0f; + valpha2.z = 2; valpha2.w = 0; + + break; + default: __assume(0); + } + + if( tex0.tcc ) { + + if( tex0.tfx == 1 ) { + //mode.x = 10; + valpha.z = 0; valpha.w = 0; + valpha2.x = 1; valpha2.y = 1; + valpha2.z = 0; valpha2.w = 0; + } + + if( nNeedAlpha ) { + + if( tex0.tfx == 0 ) { + // make sure alpha is mult by two when the output is Cv = Ct*Cf + valpha.x = 2*gs.texa.fta[0]; + // if 24bit, always choose ta[0] + valpha.y = 2*gs.texa.fta[psm != 1]; + valpha.y -= valpha.x; + } + else { + valpha.x = gs.texa.fta[0]; + // if 24bit, always choose ta[0] + valpha.y = gs.texa.fta[psm != 1]; + valpha.y -= valpha.x; + } + + // need black detection + if( gs.texa.aem && psm == PSMCT24 ) + vblack.w = 0; + } + else { + if( tex0.tfx == 0 ) { + valpha.x = 0; + valpha.y = 2; + } + else { + valpha.x = 0; + valpha.y = 1; + } + } + } + else { + + // reset alpha to color + valpha.x = valpha.y = 0; + valpha.w = 1; + } + + SETCONSTF(GPU_TEXALPHA0+context, &valpha); + SETCONSTF(GPU_TEXALPHA20+context, &valpha2); + if( tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S) ) + SETCONSTF(GPU_TESTBLACK0+context, &vblack); + + // clamp relies on texture width + { + clampInfo* pclamp = &ZeroGS::vb[context].clamp; + DXVEC4 v, v2; + v.x = v.y = 0; + LPD3DTEX* ptex = ZeroGS::vb[context].ptexClamp; + ptex[0] = ptex[1] = NULL; + + float fw = ZeroGS::vb[context].tex0.tw; + float fh = ZeroGS::vb[context].tex0.th; + + switch(pclamp->wms) { + case 0: + v2.x = -1e10; v2.z = 1e10; + break; + case 1: // pclamp + // suikoden5 movie text + v2.x = 0; v2.z = 1-0.5f/fw; + break; + case 2: // reg pclamp + v2.x = (pclamp->minu+0.5f)/fw; v2.z = (pclamp->maxu-0.5f)/fw; + break; + + case 3: // region rep x + v.x = 0.9999f; + v.z = fw / (float)GPU_TEXMASKWIDTH; + v2.x = (float)GPU_TEXMASKWIDTH / fw; + v2.z = pclamp->maxu / fw; + + if( pclamp->minu != g_PrevBitwiseTexX ) { + g_PrevBitwiseTexX = pclamp->minu; + ptex[0] = ZeroGS::s_BitwiseTextures.GetTex(pclamp->minu, NULL); + } + break; + + default: __assume(0); + } + + switch(pclamp->wmt) { + case 0: + v2.y = -1e10; v2.w = 1e10; + break; + case 1: // pclamp + // suikoden5 movie text + v2.y = 0; v2.w = 1-0.5f/fh; + break; + case 2: // reg pclamp + v2.y = (pclamp->minv+0.5f)/fh; v2.w = (pclamp->maxv-0.5f)/fh; + break; + + case 3: // region rep y + v.y = 0.9999f; + v.w = fh / (float)GPU_TEXMASKWIDTH; + v2.y = (float)GPU_TEXMASKWIDTH / fh; + v2.w = pclamp->maxv / fh; + + if( pclamp->minv != g_PrevBitwiseTexY ) { + g_PrevBitwiseTexY = pclamp->minv; + ptex[1] = ZeroGS::s_BitwiseTextures.GetTex(pclamp->minv, ptex[0]); + } + break; + + default: __assume(0); + } + + SETCONSTF(GPU_TEXWRAPMODE0+context, v); + SETCONSTF(GPU_CLAMPEXTS0+context, v2); + } + + vb[context].bTexConstsSync = TRUE; + } + + if(s_bTexFlush ) { + if( PSMT_ISCLUT(tex0.psm) ) + texClutWrite(context); + else + s_bTexFlush = FALSE; + } +} + +void ZeroGS::SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, CMemoryTarget* pmemtarg, int force) +{ + DXVEC4 v; + assert( pmemtarg != NULL ); + + float fw = (float)tex0.tw; + float fh = (float)tex0.th; + + if( bilinear > 1 || (bilinear && conf.bilinear)) { + v.x = (float)fw; + v.y = (float)fh; + v.z = 1.0f / (float)fw; + v.w = 1.0f / (float)fh; + SETCONSTF(GPU_REALTEXDIMS0+context, v); + } + + if( m_Blocks[tex0.psm].bpp == 0 ) { + ERROR_LOG("ZeroGS: Undefined tex psm 0x%x!\n", tex0.psm); + return; + } + + const BLOCK& b = m_Blocks[tex0.psm]; + + float fbw = (float)tex0.tbw; + + v.x = b.vTexDims.x * fw; + v.y = b.vTexDims.y * fh; + v.z = (float)BLOCK_TEXWIDTH*(0.002f / 64.0f + 0.01f/128.0f); + v.w = (float)BLOCK_TEXHEIGHT*0.2f/512.0f; + + if( bilinear > 1 || (conf.bilinear && bilinear) ) { + v.x *= 1/128.0f; + v.y *= 1/512.0f; + v.z *= 1/128.0f; + v.w *= 1/512.0f; + } + SETCONSTF(GPU_TEXDIMS0+context, v); + + float g_fitexwidth = g_fiGPU_TEXWIDTH/(float)pmemtarg->widthmult; + float g_texwidth = GPU_TEXWIDTH*(float)pmemtarg->widthmult; + + SETCONSTF(GPU_TEXBLOCK0+context, &b.vTexBlock.x); + + float fpage = tex0.tbp0*(64.0f*g_fitexwidth) + 0.05f * g_fitexwidth; + float fpageint = floorf(fpage); + int starttbp = (int)fpage; + + // 2048 is number of words to span one page + float fblockstride = (2048.0f /(float)(g_texwidth*BLOCK_TEXWIDTH)) * b.vTexDims.x * fbw; + assert( fblockstride >= 1.0f ); + + v.x = (float)(2048 * g_fitexwidth); + v.y = fblockstride; + v.z = g_fBlockMult/(float)pmemtarg->widthmult; + v.w = fpage-fpageint; + + if( g_fBlockMult > 1 ) { + // make sure to divide by mult (since the G16R16 texture loses info) + v.z *= b.bpp * (1/32.0f); + } + + SETCONSTF(GPU_TEXOFFSET0+context, v); + + v.y = (float)1.0f / (float)((pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult); + v.x = (fpageint-(float)pmemtarg->realy/(float)pmemtarg->widthmult+0.5f)*v.y; + + SETCONSTF(GPU_PAGEOFFSET0+context, v); + + if( force ) { + pd3dDevice->SetTexture(SAMP_MEMORY0+context, pmemtarg->ptex); + s_ptexCurSet[context] = pmemtarg->ptex; + } + else s_ptexNextSet[context] = pmemtarg->ptex; + vb[context].pmemtarg = pmemtarg; + + vb[context].bVarsTexSync = FALSE; +} + +// assumes texture factor is unused +#define SET_ALPHA_COLOR_FACTOR(sign) { \ + switch(a.c) { \ + case 0: \ + bNeedAlphaColor = 1; \ + vAlphaBlendColor.y = (sign) ? 2.0f*255.0f/256.0f : -2.0f*255.0f/256.0f; \ + SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); \ + SETRS(D3DRS_BLENDOPALPHA, (sign) ? D3DBLENDOP_ADD : D3DBLENDOP_REVSUBTRACT); \ + break; \ + case 1: \ + /* if in 24 bit mode, dest alpha should be one */ \ + switch(vb[icurctx].prndr->psm&0xf) { \ + case 0: \ + bDestAlphaColor = (a.d!=2)&&((a.a==a.d)||(a.b==a.d)); \ + break; \ + case 1: \ + /* dest alpha should be one */ \ + bDestAlphaColor = 2; \ + break; \ + /* default: 16bit surface, so returned alpha is ok */ \ + } \ + break; \ + \ + case 2: \ + bNeedBlendFactorInAlpha = 1; /* should disable alpha channel writing */ \ + bNeedAlphaColor = 1; \ + vAlphaBlendColor.y = 0; \ + vAlphaBlendColor.w = (sign) ? (float)a.fix * (2.0f/255.0f) : (float)a.fix * (-2.0f/255.0f); \ + usec = 0; /* change so that alpha comes from source*/ \ + break; \ + } \ +} \ + +//if( a.fix <= 0x80 ) { \ +// dwTemp = (a.fix*2)>255?255:(a.fix*2); \ +// dwTemp = dwTemp|(dwTemp<<8)|(dwTemp<<16)|0x80000000; \ +// DEBUG_LOG("bfactor: %8.8x\n", dwTemp); \ +// SETRS(D3DRS_BLENDFACTOR, dwTemp); \ +// } \ +// else { \ + +void ZeroGS::ResetAlphaVariables() +{ + s_bAlphaSet = FALSE; +} + +void ZeroGS::SetAlphaVariables(const alphaInfo& a) +{ + SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); // always set + + if( s_bAlphaSet && a.abcd == s_alphaInfo.abcd && a.fix == s_alphaInfo.fix ) { + return; + } + + // TODO: negative color when not clamping turns to positive??? + g_vars._bAlphaState = 0; // set all to zero + bNeedBlendFactorInAlpha = 0; + b2XAlphaTest = 1; + DWORD dwTemp = 0xffffffff; + + // default + SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); + SETRS(D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO); + SETRS(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD); + + s_alphaInfo = a; + + vAlphaBlendColor = DXVEC4(1,2*255.0f/256.0f,0,0); + DWORD usec = a.c; + + if( a.a == a.b ) { // just d remains + SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); + + if( a.d == 0 ) { + SETRS(D3DRS_ALPHABLENDENABLE, 0); + } + else { + SETRS(D3DRS_DESTBLEND, a.d == 1 ? D3DBLEND_ONE : D3DBLEND_ZERO); + SETRS(D3DRS_SRCBLEND, D3DBLEND_ZERO); + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + } + + goto EndSetAlpha; + } + else if( a.d == 2 ) { // zero + + if( a.a == 2 ) { + // zero all color + SETRS(D3DRS_SRCBLEND, D3DBLEND_ZERO); + SETRS(D3DRS_DESTBLEND, D3DBLEND_ZERO); + goto EndSetAlpha; + } + else if( a.b == 2 ) { + //b2XAlphaTest = 1; + + SET_ALPHA_COLOR_FACTOR(1); + + if( bDestAlphaColor == 2 ) { + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + SETRS(D3DRS_SRCBLEND, a.a == 0 ? D3DBLEND_ONE : D3DBLEND_ZERO); + SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_ZERO : D3DBLEND_ONE); + } + else { + if( bNeedAlphaColor ) bAlphaClamping = 2; + + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + SETRS(D3DRS_SRCBLEND, a.a == 0 ? blendalpha[usec] : D3DBLEND_ZERO); + SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_ZERO : blendalpha[usec]); + } + + goto EndSetAlpha; + } + + // nothing is zero, so must do some real blending + //b2XAlphaTest = 1; + bAlphaClamping = 3; + + SET_ALPHA_COLOR_FACTOR(1); + + SETRS(D3DRS_BLENDOP, a.a == 0 ? D3DBLENDOP_SUBTRACT : D3DBLENDOP_REVSUBTRACT); + SETRS(D3DRS_SRCBLEND, bDestAlphaColor == 2 ? D3DBLEND_ONE : blendalpha[usec]); + SETRS(D3DRS_DESTBLEND, bDestAlphaColor == 2 ? D3DBLEND_ONE : blendalpha[usec]); + } + else if( a.a == 2 ) { // zero + + //b2XAlphaTest = 1; + bAlphaClamping = 1; // min testing + + SET_ALPHA_COLOR_FACTOR(1); + + if( a.b == a.d ) { + // can get away with 1-A + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + SETRS(D3DRS_SRCBLEND, (a.b == 0 && bDestAlphaColor != 2) ? blendinvalpha[usec] : D3DBLEND_ZERO); + SETRS(D3DRS_DESTBLEND, (a.b == 0 || bDestAlphaColor == 2) ? D3DBLEND_ZERO : blendinvalpha[usec]); + } + else { + SETRS(D3DRS_BLENDOP, a.b==0 ? D3DBLENDOP_REVSUBTRACT : D3DBLENDOP_SUBTRACT); + SETRS(D3DRS_SRCBLEND, (a.b == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : D3DBLEND_ONE); + SETRS(D3DRS_DESTBLEND, (a.b == 0 || bDestAlphaColor == 2 ) ? D3DBLEND_ONE : blendalpha[usec]); + } + } + else if( a.b == 2 ) { + bAlphaClamping = 2; // max testing + + SET_ALPHA_COLOR_FACTOR(a.a!=a.d); + + if( a.a == a.d ) { + // can get away with 1+A, but need to set alpha to negative + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + + if( bDestAlphaColor == 2 ) { + assert(usec==1); + + // all ones + bNeedAlphaColor = 1; + bNeedBlendFactorInAlpha = 1; + vAlphaBlendColor.y = 0; + vAlphaBlendColor.w = -1; + SETRS(D3DRS_SRCBLEND, a.a == 0 ? D3DBLEND_INVSRCALPHA : D3DBLEND_ZERO); + SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_ZERO : D3DBLEND_INVSRCALPHA); + } + else { + SETRS(D3DRS_SRCBLEND, a.a == 0 ? blendinvalpha[usec] : D3DBLEND_ZERO); + SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_ZERO : blendinvalpha[usec]); + } + } + else { + //b2XAlphaTest = 1; + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + SETRS(D3DRS_SRCBLEND, (a.a == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : D3DBLEND_ONE); + SETRS(D3DRS_DESTBLEND, (a.a == 0 || bDestAlphaColor == 2) ? D3DBLEND_ONE : blendalpha[usec]); + } + } + else { + // all 3 components are valid! + bAlphaClamping = 3; // all testing + SET_ALPHA_COLOR_FACTOR(a.a!=a.d); + + if( a.a == a.d ) { + // can get away with 1+A, but need to set alpha to negative + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + + if( bDestAlphaColor == 2 ) { + assert(usec==1); + + // all ones + bNeedAlphaColor = 1; + bNeedBlendFactorInAlpha = 1; + vAlphaBlendColor.y = 0; + vAlphaBlendColor.w = -1; + SETRS(D3DRS_SRCBLEND, a.a == 0 ? D3DBLEND_INVSRCALPHA : D3DBLEND_SRCALPHA); + SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_SRCALPHA : D3DBLEND_INVSRCALPHA); + } + else { + SETRS(D3DRS_SRCBLEND, a.a == 0 ? blendinvalpha[usec] : blendalpha[usec]); + SETRS(D3DRS_DESTBLEND, a.a == 0 ? blendalpha[usec] : blendinvalpha[usec]); + } + } + else { + assert(a.b == a.d); + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + + if( bDestAlphaColor == 2 ) { + assert(usec==1); + + // all ones + bNeedAlphaColor = 1; + bNeedBlendFactorInAlpha = 1; + vAlphaBlendColor.y = 0; + vAlphaBlendColor.w = 1; + SETRS(D3DRS_SRCBLEND, a.a != 0 ? D3DBLEND_INVSRCALPHA : D3DBLEND_SRCALPHA); + SETRS(D3DRS_DESTBLEND, a.a != 0 ? D3DBLEND_SRCALPHA : D3DBLEND_INVSRCALPHA); + } + else { + //b2XAlphaTest = 1; + SETRS(D3DRS_SRCBLEND, a.a != 0 ? blendinvalpha[usec] : blendalpha[usec]); + SETRS(D3DRS_DESTBLEND, a.a != 0 ? blendalpha[usec] : blendinvalpha[usec]); + } + } + } + +EndSetAlpha: + //b2XAlphaTest = b2XAlphaTest && bNeedAlphaColor && !bNeedBlendFactorInAlpha; + + INC_ALPHAVARS(); +} + +void ZeroGS::SetWriteDepth() +{ + if( conf.mrtdepth ) { + s_bWriteDepth = TRUE; + s_nWriteDepthCount = 4; + } +} + +BOOL ZeroGS::IsWriteDepth() +{ + return s_bWriteDepth; +} + +BOOL ZeroGS::IsWriteDestAlphaTest() +{ + return s_bWriteDepth; +} + +void ZeroGS::SetDestAlphaTest() +{ + s_bDestAlphaTest = TRUE; + s_nWriteDestAlphaTest = 4; +} + +void ZeroGS::SetFogColor(u32 fog) +{ + if( 1||gs.fogcol != fog ) { + gs.fogcol = fog; + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + if( !g_bIsLost ) { + DXVEC4 v; + + // set it immediately + v.x = (gs.fogcol&0xff)/255.0f; + v.y = ((gs.fogcol>>8)&0xff)/255.0f; + v.z = ((gs.fogcol>>16)&0xff)/255.0f; + SETCONSTF(GPU_FOGCOLOR, v); + } + } +} + +void ZeroGS::ExtWrite() +{ + WARN_LOG("ExtWrite\n"); + + // use local DISPFB, EXTDATA, EXTBUF, and PMODE +// int bpp, start, end; +// tex0Info texframe; + +// bpp = 4; +// if( texframe.psm == 0x12 ) bpp = 3; +// else if( texframe.psm & 2 ) bpp = 2; +// +// // get the start and end addresses of the buffer +// GetRectMemAddress(start, end, texframe.psm, 0, 0, texframe.tw, texframe.th, texframe.tbp0, texframe.tbw); +} + +//////////// +// Caches // +//////////// +#ifdef __x86_64__ +extern "C" void TestClutChangeMMX(void* src, void* dst, int entries, void* pret); +#endif + +bool ZeroGS::CheckChangeInClut(u32 highdword, u32 psm) +{ + int cld = (highdword >> 29) & 0x7; + int cbp = ((highdword >> 5) & 0x3fff); + + // processing the CLUT after tex0/2 are written + switch(cld) { + case 0: return false; + case 1: break; // Seems to rarely not be 1. + // note sure about changing cbp[0,1] + case 4: return gs.cbp[0] != cbp; + case 5: return gs.cbp[1] != cbp; + + // default: load + default: break; + } + + int cpsm = (highdword >> 19) & 0xe; + int csm = (highdword >> 23) & 0x1; + + if( cpsm > 1 || csm ) + // don't support 16bit for now + return true; + + int csa = (highdword >> 24) & 0x1f; + + int entries = (psm&3)==3 ? 256 : 16; + + u64* src = (u64*)(g_pbyGSMemory + cbp*256); + u64* dst = (u64*)(g_pbyGSClut+64*csa); + + bool bRet = false; + +#ifdef __x86_64__ + TestClutChangeMMX(dst, src, entries, &bRet); +#else + int storeebx; + // do a fast test with MMX + __asm { + mov storeebx, ebx + mov edx, dst + mov ecx, src + mov ebx, entries + +Start: + movq mm0, [edx] + movq mm1, [edx+8] + pcmpeqd mm0, [ecx] + pcmpeqd mm1, [ecx+16] + + movq mm2, [edx+16] + movq mm3, [edx+24] + pcmpeqd mm2, [ecx+32] + pcmpeqd mm3, [ecx+48] + + pand mm0, mm1 + pand mm2, mm3 + movq mm4, [edx+32] + movq mm5, [edx+40] + pcmpeqd mm4, [ecx+8] + pcmpeqd mm5, [ecx+24] + + pand mm0, mm2 + pand mm4, mm5 + movq mm6, [edx+48] + movq mm7, [edx+56] + pcmpeqd mm6, [ecx+40] + pcmpeqd mm7, [ecx+56] + + pand mm0, mm4 + pand mm6, mm7 + pand mm0, mm6 + + pmovmskb eax, mm0 + cmp eax, 0xff + je Continue + mov bRet, 1 + jmp Return + +Continue: + cmp ebx, 16 + jle Return + + test ebx, 0x10 + jz AddEcx + sub ecx, 448 // go back and down one column, +AddEcx: + add ecx, 256 // go to the right block + + cmp ebx, 0x90 + jne Continue1 + add ecx, 256 // skip whole block +Continue1: + add edx, 64 + sub ebx, 16 + jmp Start + } + +Return: + __asm { + emms + mov ebx, storeebx + } +#endif + + return bRet; +} + +void ZeroGS::texClutWrite(int ctx) +{ + s_bTexFlush = 0; + if( g_bIsLost ) + return; + + tex0Info& tex0 = vb[ctx].tex0; + assert( PSMT_ISCLUT(tex0.psm) ); + + // processing the CLUT after tex0/2 are written + switch(tex0.cld) { + case 0: return; + case 1: break; // tex0.cld is usually 1. + case 2: gs.cbp[0] = tex0.cbp; break; + case 3: gs.cbp[1] = tex0.cbp; break; + // not sure about changing cbp[0,1] + case 4: + if( gs.cbp[0] == tex0.cbp ) + return; + gs.cbp[0] = tex0.cbp; + break; + case 5: + if( gs.cbp[1] == tex0.cbp ) + return; + gs.cbp[1] = tex0.cbp; + break; + default: //DEBUG_LOG("cld isn't 0-5!"); + break; + } + + Flush(!ctx); + + int entries = (tex0.psm&3)==3 ? 256 : 16; +if (tex0.csm) + { + switch (tex0.cpsm) + { + // 16bit psm + // eggomania uses non16bit textures for csm2 + case PSMCT16: + { + u16* src = (u16*)g_pbyGSMemory + tex0.cbp*128; + u16 *dst = (u16*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0)); + + for (int i = 0; i < entries; ++i) + { + *dst = src[getPixelAddress16_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + dst += 2; + + // check for wrapping + if (((u32)dst & 0x3ff) == 0) dst = (u16*)(g_pbyGSClut+2); + } + break; + } + + case PSMCT16S: + { + u16* src = (u16*)g_pbyGSMemory + tex0.cbp*128; + u16 *dst = (u16*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0)); + + for (int i = 0; i < entries; ++i) + { + *dst = src[getPixelAddress16S_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + dst += 2; + + // check for wrapping + if (((u32)dst & 0x3ff) == 0) dst = (u16*)(g_pbyGSClut+2); + } + break; + } + + case PSMCT32: + case PSMCT24: + { + u32* src = (u32*)g_pbyGSMemory + tex0.cbp*64; + u32 *dst = (u32*)(g_pbyGSClut+64*tex0.csa); + + // check if address exceeds src + if( src+getPixelAddress32_0(gs.clut.cou+entries-1, gs.clut.cov, gs.clut.cbw) >= (u32*)g_pbyGSMemory + 0x00100000 ) + ERROR_LOG("texClutWrite out of bounds\n"); + else + for(int i = 0; i < entries; ++i) + { + *dst = src[getPixelAddress32_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + dst++; + } + } + break; + + default: + { +#ifndef RELEASE_TO_PUBLIC + //DEBUG_LOG("unknown cpsm: %x (%x)\n", tex0.cpsm, tex0.psm); +#endif + break; + } + } + } + else + { + switch (tex0.cpsm) + { + case PSMCT24: + case PSMCT32: + if( entries == 16 ) + WriteCLUT_T32_I4_CSM1((u32*)(g_pbyGSMemory + tex0.cbp*256), (u32*)(g_pbyGSClut+64*tex0.csa)); + else + WriteCLUT_T32_I8_CSM1((u32*)(g_pbyGSMemory + tex0.cbp*256), (u32*)(g_pbyGSClut+64*tex0.csa)); + break; + + default: + if( entries == 16 ) + WriteCLUT_T16_I4_CSM1((u32*)(g_pbyGSMemory + 256 * tex0.cbp), (u32*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0))); + else // sse2 for 256 is more complicated, so use regular + WriteCLUT_T16_I8_CSM1_c((u32*)(g_pbyGSMemory + 256 * tex0.cbp), (u32*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0))); + break; + + } + } +} + +void ZeroGS::SetTexFlush() +{ + s_bTexFlush = TRUE; + +// if( PSMT_ISCLUT(vb[0].tex0.psm) ) +// texClutWrite(0); +// if( PSMT_ISCLUT(vb[1].tex0.psm) ) +// texClutWrite(1); + + if( !s_bForceTexFlush ) + { + if( s_ptexCurSet[0] != s_ptexNextSet[0] ) + { + s_ptexCurSet[0] = s_ptexNextSet[0]; + pd3dDevice->SetTexture(SAMP_MEMORY0, s_ptexNextSet[0]); + } + if( s_ptexCurSet[1] != s_ptexNextSet[1] ) + { + s_ptexCurSet[1] = s_ptexNextSet[1]; + pd3dDevice->SetTexture(SAMP_MEMORY1, s_ptexNextSet[1]); + } + } +} + +int ZeroGS::Save(char* pbydata) +{ + if( pbydata == NULL ) + return 40 + 0x00400000 + sizeof(gs) + 2*VBSAVELIMIT + 2*sizeof(frameInfo) + 4 + 256*4; + + s_RTs.ResolveAll(); + s_DepthRTs.ResolveAll(); + + vb[0].Unlock(); + vb[1].Unlock(); + + strcpy(pbydata, libraryName); + *(u32*)(pbydata+16) = ZEROGS_SAVEVER; + pbydata += 32; + + *(int*)pbydata = icurctx; pbydata += 4; + *(int*)pbydata = VBSAVELIMIT; pbydata += 4; + + memcpy(pbydata, g_pbyGSMemory, 0x00400000); + pbydata += 0x00400000; + + memcpy(pbydata, g_pbyGSClut, 256*4); + pbydata += 256*4; + + *(int*)pbydata = sizeof(gs); + pbydata += 4; + memcpy(pbydata, &gs, sizeof(gs)); + pbydata += sizeof(gs); + + for(int i = 0; i < 2; ++i) { + memcpy(pbydata, &vb[i], VBSAVELIMIT); + pbydata += VBSAVELIMIT; + } + + vb[0].Lock(); + vb[1].Lock(); + + return 0; +} + +extern u32 s_uTex1Data[2][2], s_uClampData[2]; +extern char *libraryName; +bool ZeroGS::Load(char* pbydata) +{ + memset(s_uTex1Data, 0, sizeof(s_uTex1Data)); + memset(s_uClampData, 0, sizeof(s_uClampData)); + + // first 32 bytes are the id + u32 savever = *(u32*)(pbydata+16); + + if( strncmp(pbydata, libraryName, 6) == 0 && (savever == ZEROGS_SAVEVER || savever == 0xaa000004) ) { + + g_MemTargs.Destroy(); + + GSStateReset(); + pbydata += 32; + + int context = *(int*)pbydata; pbydata += 4; + u32 savelimit = VBSAVELIMIT; + + savelimit = *(u32*)pbydata; pbydata += 4; + + memcpy(g_pbyGSMemory, pbydata, 0x00400000); + pbydata += 0x00400000; + + memcpy(g_pbyGSClut, pbydata, 256*4); + pbydata += 256*4; + + memset(&gs, 0, sizeof(gs)); + + int savedgssize; + if( savever == 0xaa000004 ) + savedgssize = 0x1d0; + else { + savedgssize = *(int*)pbydata; + pbydata += 4; + } + + memcpy(&gs, pbydata, savedgssize); + pbydata += savedgssize; + prim = &gs._prim[gs.prac]; + + LPD3DVB pvb = vb[0].pvb; + memcpy(&vb[0], pbydata, min(savelimit, VBSAVELIMIT)); + pbydata += savelimit; + vb[0].pvb = pvb; + + pvb = vb[1].pvb; + memcpy(&vb[1], pbydata, min(savelimit, VBSAVELIMIT)); + pbydata += savelimit; + vb[1].pvb = pvb; + + for(int i = 0; i < 2; ++i) { + vb[i].bNeedZCheck = vb[i].bNeedFrameCheck = 1; + + vb[i].bSyncVars = 0; vb[i].bNeedTexCheck = 1; + memset(vb[i].uCurTex0Data, 0, sizeof(vb[i].uCurTex0Data)); + } + + icurctx = -1; + + pd3dDevice->SetRenderTarget(0, psurfOrgTarg); + pd3dDevice->SetRenderTarget(1, NULL); + pd3dDevice->SetDepthStencilSurface(psurfOrgDepth); + SetFogColor(gs.fogcol); + + vb[0].Lock(); + vb[1].Lock(); + + return true; + } + + return false; +} + +void ZeroGS::SaveSnapshot(const char* filename) +{ + g_bMakeSnapshot = 1; + strSnapshot = filename; +} + +// AVI capture stuff +bool ZeroGS::StartCapture() +{ + if( !s_aviinit ) { + START_AVI("zerogs.avi"); + + assert( s_ptexAVICapture == NULL ); + if( FAILED(pd3dDevice->CreateOffscreenPlainSurface(width, height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &s_ptexAVICapture, NULL)) ) { + STOP_AVI(); + ZeroGS::AddMessage("Failed to create avi"); + return false; + } + + s_aviinit = 1; + } + else { + DEBUG_LOG("ZeroGS: Continuing from previous capture"); + } + + s_avicapturing = 1; + return true; +} + +void ZeroGS::StopCapture() +{ + s_avicapturing = 0; +} + +void ZeroGS::CaptureFrame() +{ + assert( s_avicapturing && s_aviinit && s_ptexAVICapture != NULL ); + + vector mem; + + pd3dDevice->GetRenderTargetData(psurfOrgTarg, s_ptexAVICapture); + + D3DLOCKED_RECT lock; + mem.resize(width * height * 4); + + s_ptexAVICapture->LockRect(&lock, NULL, D3DLOCK_READONLY); + assert( lock.Pitch == width*4 ); + + BYTE* pend = (BYTE*)lock.pBits + (conf.height-1)*width*4; + for(int i = 0; i < conf.height; ++i) { + memcpy_amd(&mem[width*4*i], pend - width*4*i, width * 4); + } + s_ptexAVICapture->UnlockRect(); + + int fps = SMODE1->CMOD == 3 ? 50 : 60; + bool bSuccess = ADD_FRAME_FROM_DIB_TO_AVI("AAAA", fps, width, height, 32, &mem[0]); + + if( !bSuccess ) { + s_avicapturing = 0; + STOP_AVI(); + s_aviinit = 0; + ZeroGS::AddMessage("Failed to create avi"); + return; + } +} diff --git a/plugins/zerogs/dx/zerogs.h b/plugins/zerogs/dx/zerogs.h index 530288d82e..c4fc3c86b5 100644 --- a/plugins/zerogs/dx/zerogs.h +++ b/plugins/zerogs/dx/zerogs.h @@ -1,514 +1,514 @@ -/* ZeroGS - * Copyright (C) 2005-2006 zerofrog@gmail.com - * - * 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 - */ - -#ifndef __ZEROGS__H -#define __ZEROGS__H - -#pragma warning(disable:4200) // nonstandard extension used : zero-sized array in struct/union - -#include -#include - -#include -#include -#include -#include -#include -using namespace std; - -#ifndef SAFE_DELETE -#define SAFE_DELETE(x) if( (x) != NULL ) { delete (x); (x) = NULL; } -#endif -#ifndef SAFE_DELETE_ARRAY -#define SAFE_DELETE_ARRAY(x) if( (x) != NULL ) { delete[] (x); (x) = NULL; } -#endif -#ifndef SAFE_RELEASE -#define SAFE_RELEASE(x) if( (x) != NULL ) { (x)->Release(); (x) = NULL; } -#endif - -#define FORIT(it, v) for(it = (v).begin(); it != (v).end(); ++(it)) - -typedef D3DXVECTOR2 DXVEC2; -typedef D3DXVECTOR3 DXVEC3; -typedef D3DXVECTOR4 DXVEC4; -typedef D3DXMATRIX DXMAT; - -// sends a message to output window if assert fails -#define BMSG(x, str) { if( !(x) ) { GS_LOG(str); GS_LOG(str); } } -#define BMSG_RETURN(x, str) { if( !(x) ) { GS_LOG(str); GS_LOG(str); return; } } -#define BMSG_RETURNX(x, str, rtype) { if( !(x) ) { GS_LOG(str); GS_LOG(str); return (##rtype); } } -#define B(x) { if( !(x) ) { GS_LOG(_T(#x"\n")); GS_LOG(#x"\n"); } } -#define B_RETURN(x) { if( !(x) ) { GS_LOG(_T(#x"\n")); GS_LOG(#x"\n"); return; } } -#define B_RETURNX(x, rtype) { if( !(x) ) { GS_LOG(_T(#x"\n")); GS_LOG(#x"\n"); return (##rtype); } } -#define B_G(x, action) { if( !(x) ) { GS_LOG(#x"\n"); action; } } - -#ifndef RELEASE_TO_PUBLIC - #ifndef V -#define V(x) { hr = x; if( FAILED(hr) ) { ERROR_LOG("%s:%d: %s (%8.8x)\n", __FILE__, (DWORD)__LINE__, _T(#x), hr); } } - #endif - #ifndef V_RETURN - #define V_RETURN(x) { hr = x; if( FAILED(hr) ) { ERROR_LOG("%s:%d: %s (%8.8x)\n", __FILE__, (DWORD)__LINE__, _T(#x), hr); return hr; } } - #endif -#else - #ifndef V - #define V(x) { hr = x; } - #endif - #ifndef V_RETURN - #define V_RETURN(x) { hr = x; if( FAILED(hr) ) { return hr; } } - #endif -#endif - -#define SETRS(state, val) pd3dDevice->SetRenderState(state, val) -#ifndef ARRAYSIZE -#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0])) -#endif - -// all textures have this width -//#define GPU_TEXWIDTH 512 -extern int GPU_TEXWIDTH; -extern float g_fiGPU_TEXWIDTH; -#define GPU_TEXMASKWIDTH 1024 // bitwise mask width for region repeat mode - -// set these shader constants -#define GPU_TEXALPHA20 (2|0x8000) -#define GPU_TEXOFFSET0 (4|0x8000) -#define GPU_TEXDIMS0 (6|0x8000) -#define GPU_TEXBLOCK0 (8|0x8000) -#define GPU_CLAMPEXTS0 (10|0x8000) -#define GPU_TEXWRAPMODE0 (12|0x8000) -#define GPU_REALTEXDIMS0 (14|0x8000) -#define GPU_TESTBLACK0 (16|0x8000) -#define GPU_PAGEOFFSET0 (18|0x8000) -#define GPU_TEXALPHA0 (20|0x8000) - -#define GPU_INVTEXDIMS (22|0x8000) -#define GPU_FOGCOLOR (23|0x8000) -#define GPU_BITBLTZ (24|0x8000) -#define GPU_ONECOLOR (25|0x8000) - -#define GPU_CLIPPLANE0 (24|0x8000) -#define GPU_CLIPPLANE1 (26|0x8000) - -#define GPU_POSXY0 2 - -#define GPU_BITBLTPOS 4 -#define GPU_Z 5 -#define GPU_ZNORM 6 -#define GPU_BITBLTTEX 7 - -#define SETCONSTF(id, ptr) { if( id & 0x8000 ) pd3dDevice->SetPixelShaderConstantF(id&0x7fff, (FLOAT*)ptr, 1); \ - else pd3dDevice->SetVertexShaderConstantF(id&0x7fff, (FLOAT*)ptr, 1); } - -#define SAMP_MEMORY0 0 -#define SAMP_MEMORY1 1 -#define SAMP_FINAL 2 -#define SAMP_BLOCKS 3 -#define SAMP_BILINEARBLOCKS 4 -#define SAMP_INTERLACE 5 -#define SAMP_BITWISEANDX 5 -#define SAMP_BITWISEANDY 6 - -// don't change these values! -#define GAME_TEXTURETARGS 0x01 -#define GAME_AUTORESET 0x02 -#define GAME_INTERLACE2X 0x04 -#define GAME_TEXAHACK 0x08 // apply texa to non textured polys -#define GAME_NOTARGETRESOLVE 0x10 -#define GAME_EXACTCOLOR 0x20 -#define GAME_NOCOLORCLAMP 0x40 -#define GAME_FFXHACK 0x80 -#define GAME_NODEPTHUPDATE 0x0200 -#define GAME_QUICKRESOLVE1 0x0400 -#define GAME_NOQUICKRESOLVE 0x0800 -#define GAME_NOTARGETCLUT 0x1000 // full 16 bit resolution -#define GAME_NOSTENCIL 0x2000 -#define GAME_VSSHACKOFF 0x4000 // vertical stripe syndrome -#define GAME_NODEPTHRESOLVE 0x8000 -#define GAME_FULL16BITRES 0x00010000 -#define GAME_RESOLVEPROMOTED 0x00020000 -#define GAME_FASTUPDATE 0x00040000 -#define GAME_NOALPHATEST 0x00080000 -#define GAME_DISABLEMRTDEPTH 0x00100000 -#define GAME_32BITTARGS 0x00200000 -#define GAME_PATH3HACK 0x00400000 -#define GAME_DOPARALLELCTX 0x00800000 // tries to parallelize both contexts so that render calls are reduced (xenosaga) - // makes the game faster, but can be buggy -#define GAME_XENOSPECHACK 0x01000000 // xenosaga specularity hack (ignore any zmask=1 draws) -#define GAME_PARTIALPOINTERS 0x02000000 // whenver the texture or render target are small, tries to look for bigger ones to read from -#define GAME_PARTIALDEPTH 0x04000000 // tries to save depth targets as much as possible across height changes -#define GAME_RELAXEDDEPTH 0x08000000 // tries to save depth targets as much as possible across height changes - -#define USEALPHABLENDING 1//(!(g_GameSettings&GAME_NOALPHABLEND)) -#define USEALPHATESTING (!(g_GameSettings&GAME_NOALPHATEST)) - -typedef IDirect3DDevice9* LPD3DDEV; -typedef IDirect3DVertexBuffer9* LPD3DVB; -typedef IDirect3DIndexBuffer9* LPD3DIB; -typedef IDirect3DBaseTexture9* LPD3DBASETEX; -typedef IDirect3DTexture9* LPD3DTEX; -typedef IDirect3DCubeTexture9* LPD3DCUBETEX; -typedef IDirect3DVolumeTexture9* LPD3DVOLUMETEX; -typedef IDirect3DSurface9* LPD3DSURF; -typedef IDirect3DVertexDeclaration9* LPD3DDECL; -typedef IDirect3DVertexShader9* LPD3DVS; -typedef IDirect3DPixelShader9* LPD3DPS; -typedef ID3DXAnimationController* LPD3DXAC; - -namespace ZeroGS -{ - typedef void (*DrawFn)(); - - // managers render-to-texture targets - class CRenderTarget - { - public: - CRenderTarget(); - CRenderTarget(const frameInfo& frame, CRenderTarget& r); // virtualized a target - virtual ~CRenderTarget(); - - virtual BOOL Create(const frameInfo& frame); - virtual void Destroy(); - - // set the GPU_POSXY variable, scissor rect, and current render target - void SetTarget(int fbplocal, const Rect2& scissor, int context); - void SetViewport(); - - // copies/creates the feedback contents - inline void CreateFeedback() { - if( ptexFeedback == NULL || !(status&TS_FeedbackReady) ) - _CreateFeedback(); - } - - virtual void Resolve(); - virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range - virtual void Update(int context, CRenderTarget* pdepth); - virtual void ConvertTo32(); // converts a psm==2 target, to a psm==0 - virtual void ConvertTo16(); // converts a psm==0 target, to a psm==2 - - virtual bool IsDepth() { return false; } - - LPD3DSURF psurf, psys; - LPD3DTEX ptex; - - int targoffx, targoffy; // the offset from the target that the real fbp starts at (in pixels) - int targheight; // height of ptex - CRenderTarget* pmimicparent; // if not NULL, this target is a subtarget of pmimicparent - - int fbp, fbw, fbh; // if fbp is negative, virtual target (not mapped to any real addr) - int start, end; // in bytes - u32 lastused; // time stamp since last used - DXVEC4 vposxy; - - u32 fbm; - u16 status; - u8 psm; - u8 resv0; - RECT scissorrect; - - //int startresolve, endresolve; - u32 nUpdateTarg; // use this target to update the texture if non 0 (one time only) - - // this is optionally used when feedback effects are used (render target is used as a texture when rendering to itself) - LPD3DTEX ptexFeedback; - LPD3DSURF psurfFeedback; - - enum TargetStatus { - TS_Resolved = 1, - TS_NeedUpdate = 2, - TS_Virtual = 4, // currently not mapped to memory - TS_FeedbackReady = 8, // feedback effect is ready and doesn't need to be updated - TS_NeedConvert32 = 16, - TS_NeedConvert16 = 32, - }; - - private: - void _CreateFeedback(); - }; - - // manages zbuffers - class CDepthTarget : public CRenderTarget - { - public: - CDepthTarget(); - virtual ~CDepthTarget(); - - virtual BOOL Create(const frameInfo& frame); - virtual void Destroy(); - - virtual void Resolve(); - virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range - virtual void Update(int context, CRenderTarget* prndr); - - virtual bool IsDepth() { return true; } - - void SetDepthTarget(); - - LPD3DSURF pdepth; - }; - - // manages contiguous chunks of memory (width is always 1024) - class CMemoryTarget - { - public: - struct MEMORY - { - inline MEMORY() : ptr(NULL), ref(0) {} - inline ~MEMORY() { _aligned_free(ptr); } - - BYTE* ptr; - int ref; - }; - - inline CMemoryTarget() : ptex(NULL), ptexsys(NULL), starty(0), height(0), realy(0), realheight(0), usedstamp(0), psm(0), - cpsm(0), memory(NULL), clearminy(0), clearmaxy(0), validatecount(0) {} - inline CMemoryTarget(const CMemoryTarget& r) { - ptex = r.ptex; - ptexsys = r.ptexsys; - if( ptex != NULL ) ptex->AddRef(); - if( ptexsys != NULL ) ptexsys->AddRef(); - starty = r.starty; - height = r.height; - realy = r.realy; - realheight = r.realheight; - usedstamp = r.usedstamp; - psm = r.psm; - cpsm = r.cpsm; - clut = r.clut; - memory = r.memory; - clearminy = r.clearminy; - clearmaxy = r.clearmaxy; - widthmult = r.widthmult; - validatecount = r.validatecount; - fmt = r.fmt; - if( memory != NULL ) memory->ref++; - } - - ~CMemoryTarget() { Destroy(); } - - inline void Destroy() { - SAFE_RELEASE(ptex); - SAFE_RELEASE(ptexsys); - - if( memory != NULL && memory->ref > 0 ) { - if( --memory->ref <= 0 ) { - SAFE_DELETE(memory); - } - } - memory = NULL; - } - - // returns true if clut data is synced - bool ValidateClut(const tex0Info& tex0); - // returns true if tex data is synced - bool ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex); - - int clearminy, clearmaxy; // when maxy > 0, need to check for clearing - - // realy is offset in pixels from start of valid region - // so texture in memory is [realy,starty+height] - // valid texture is [starty,starty+height] - // offset in mem [starty-realy, height] - int starty, height; // assert(starty >= realy) - int realy, realheight; // this is never touched once allocated - u32 usedstamp; - LPD3DTEX ptex; // can be 16bit if - LPD3DTEX ptexsys; - D3DFORMAT fmt; - - int widthmult; - - int validatecount; // count how many times has been validated, if too many, destroy - - vector clut; // if nonzero, texture uses CLUT - MEMORY* memory; // system memory used to compare for changes - u8 psm, cpsm; // texture and clut format. For psm, only 16bit/32bit differentiation matters - }; - - - struct VB - { - VB(); - ~VB(); - - void Destroy(); - - inline bool IsLocked() { return pbuf != NULL; } - inline void Lock(); - inline void Unlock() { - if( pbuf != NULL ) { - pvb->Unlock(); - pbuf = NULL; - } - } - - __forceinline bool CheckPrim(); - void CheckFrame(int tbp); - - // context specific state - Point offset; - Rect2 scissor; - tex0Info tex0; - tex1Info tex1; - miptbpInfo miptbp0; - miptbpInfo miptbp1; - alphaInfo alpha; - fbaInfo fba; - clampInfo clamp; - pixTest test; - LPD3DTEX ptexClamp[2]; // textures for x and y dir region clamping - - public: - - void FlushTexData(); - - u8 bNeedFrameCheck; - u8 bNeedZCheck; - u8 bNeedTexCheck; - u8 dummy0; - - union { - struct { - u8 bTexConstsSync; // only pixel shader constants that context owns - u8 bVarsTexSync; // texture info - u8 bVarsSetTarg; - u8 dummy1; - }; - u32 bSyncVars; - }; - - int ictx; - VertexGPU* pbuf; - DWORD dwCurOff; - DWORD dwCount; - primInfo curprim; // the previous prim the current buffers are set to - - zbufInfo zbuf; - frameInfo gsfb; // the real info set by FRAME cmd - frameInfo frame; - int zprimmask; // zmask for incoming points - - u32 uCurTex0Data[2]; // current tex0 data - u32 uNextTex0Data[2]; // tex0 data that has to be applied if bNeedTexCheck is 1 - - //int nFrameHeights[8]; // frame heights for the past frame changes - int nNextFrameHeight; - - CMemoryTarget* pmemtarg; // the current mem target set - LPD3DVB pvb; - CRenderTarget* prndr; - CDepthTarget* pdepth; - }; - - // visible members - extern DrawFn drawfn[8]; - extern VB vb[2]; - extern float fiTexWidth[2], fiTexHeight[2]; // current tex width and height - extern LONG width, height; - extern u8* g_pbyGSMemory; - extern u8* g_pbyGSClut; // the temporary clut buffer - - void AddMessage(const char* pstr, DWORD ms = 5000); - void ChangeWindowSize(int nNewWidth, int nNewHeight); - void SetChangeDeviceSize(int nNewWidth, int nNewHeight); - void ChangeDeviceSize(int nNewWidth, int nNewHeight); - void SetAA(int mode); - void SetCRC(int crc); - - void ReloadEffects(); - - // Methods // - - HRESULT Create(LONG width, LONG height); - void Destroy(BOOL bD3D); - - void Restore(); // call to restore device - void Reset(); // call to destroy video resources - - HRESULT InitDeviceObjects(); - void DeleteDeviceObjects(); - - void GSStateReset(); - - // called on a primitive switch - void Prim(); - - void SetTexFlush(); - // flush current vertices, call before setting new registers (the main render method) - void Flush(int context); - - void ExtWrite(); - - void SetWriteDepth(); - BOOL IsWriteDepth(); - - void SetDestAlphaTest(); - BOOL IsWriteDestAlphaTest(); - - void SetFogColor(u32 fog); - void SaveTex(tex0Info* ptex, int usevid); - - // called when trxdir is accessed. If host is involved, transfers memory to temp buffer byTransferBuf. - // Otherwise performs the transfer. TODO: Perhaps divide the transfers into chunks? - void InitTransferHostLocal(); - void TransferHostLocal(const void* pbyMem, u32 nQWordSize); - - void InitTransferLocalHost(); - void TransferLocalHost(void* pbyMem, u32 nQWordSize); - inline void TerminateLocalHost() {} - - void TransferLocalLocal(); - - // switches the render target to the real target, flushes the current render targets and renders the real image - void RenderCRTC(int interlace); - - bool CheckChangeInClut(u32 highdword, u32 psm); // returns true if clut will change after this tex0 op - - // call to load CLUT data (depending on CLD) - void texClutWrite(int ctx); - - int Save(char* pbydata); - bool Load(char* pbydata); - - void SaveSnapshot(const char* filename); - - // private methods - void FlushSysMem(const RECT* prc); - void _Resolve(const D3DLOCKED_RECT& locksrc, int fbp, int fbw, int fbh, int psm, u32 fbm); - - // returns the first and last addresses aligned to a page that cover - void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw); - - // inits the smallest rectangle in ptexMem that covers this region in ptexMem - // returns the offset that needs to be added to the locked rect to get the beginning of the buffer - //void GetMemRect(RECT& rc, int psm, int x, int y, int w, int h, int bp, int bw); - - // only sets a limited amount of state (for Update) - void SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, ZeroGS::CMemoryTarget* pmemtarg, int force); - - void ResetAlphaVariables(); - - bool StartCapture(); - void StopCapture(); - void CaptureFrame(); -}; - -extern LPDIRECT3DDEVICE9 pd3dDevice; -extern const u32 g_primmult[8]; -extern const u32 g_primsub[8]; - -#endif +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#ifndef __ZEROGS__H +#define __ZEROGS__H + +#pragma warning(disable:4200) // nonstandard extension used : zero-sized array in struct/union + +#include +#include + +#include +#include +#include +#include +#include +using namespace std; + +#ifndef SAFE_DELETE +#define SAFE_DELETE(x) if( (x) != NULL ) { delete (x); (x) = NULL; } +#endif +#ifndef SAFE_DELETE_ARRAY +#define SAFE_DELETE_ARRAY(x) if( (x) != NULL ) { delete[] (x); (x) = NULL; } +#endif +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(x) if( (x) != NULL ) { (x)->Release(); (x) = NULL; } +#endif + +#define FORIT(it, v) for(it = (v).begin(); it != (v).end(); ++(it)) + +typedef D3DXVECTOR2 DXVEC2; +typedef D3DXVECTOR3 DXVEC3; +typedef D3DXVECTOR4 DXVEC4; +typedef D3DXMATRIX DXMAT; + +// sends a message to output window if assert fails +#define BMSG(x, str) { if( !(x) ) { GS_LOG(str); GS_LOG(str); } } +#define BMSG_RETURN(x, str) { if( !(x) ) { GS_LOG(str); GS_LOG(str); return; } } +#define BMSG_RETURNX(x, str, rtype) { if( !(x) ) { GS_LOG(str); GS_LOG(str); return (##rtype); } } +#define B(x) { if( !(x) ) { GS_LOG(_T(#x"\n")); GS_LOG(#x"\n"); } } +#define B_RETURN(x) { if( !(x) ) { GS_LOG(_T(#x"\n")); GS_LOG(#x"\n"); return; } } +#define B_RETURNX(x, rtype) { if( !(x) ) { GS_LOG(_T(#x"\n")); GS_LOG(#x"\n"); return (##rtype); } } +#define B_G(x, action) { if( !(x) ) { GS_LOG(#x"\n"); action; } } + +#ifndef RELEASE_TO_PUBLIC + #ifndef V +#define V(x) { hr = x; if( FAILED(hr) ) { ERROR_LOG("%s:%d: %s (%8.8x)\n", __FILE__, (DWORD)__LINE__, _T(#x), hr); } } + #endif + #ifndef V_RETURN + #define V_RETURN(x) { hr = x; if( FAILED(hr) ) { ERROR_LOG("%s:%d: %s (%8.8x)\n", __FILE__, (DWORD)__LINE__, _T(#x), hr); return hr; } } + #endif +#else + #ifndef V + #define V(x) { hr = x; } + #endif + #ifndef V_RETURN + #define V_RETURN(x) { hr = x; if( FAILED(hr) ) { return hr; } } + #endif +#endif + +#define SETRS(state, val) pd3dDevice->SetRenderState(state, val) +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +// all textures have this width +//#define GPU_TEXWIDTH 512 +extern int GPU_TEXWIDTH; +extern float g_fiGPU_TEXWIDTH; +#define GPU_TEXMASKWIDTH 1024 // bitwise mask width for region repeat mode + +// set these shader constants +#define GPU_TEXALPHA20 (2|0x8000) +#define GPU_TEXOFFSET0 (4|0x8000) +#define GPU_TEXDIMS0 (6|0x8000) +#define GPU_TEXBLOCK0 (8|0x8000) +#define GPU_CLAMPEXTS0 (10|0x8000) +#define GPU_TEXWRAPMODE0 (12|0x8000) +#define GPU_REALTEXDIMS0 (14|0x8000) +#define GPU_TESTBLACK0 (16|0x8000) +#define GPU_PAGEOFFSET0 (18|0x8000) +#define GPU_TEXALPHA0 (20|0x8000) + +#define GPU_INVTEXDIMS (22|0x8000) +#define GPU_FOGCOLOR (23|0x8000) +#define GPU_BITBLTZ (24|0x8000) +#define GPU_ONECOLOR (25|0x8000) + +#define GPU_CLIPPLANE0 (24|0x8000) +#define GPU_CLIPPLANE1 (26|0x8000) + +#define GPU_POSXY0 2 + +#define GPU_BITBLTPOS 4 +#define GPU_Z 5 +#define GPU_ZNORM 6 +#define GPU_BITBLTTEX 7 + +#define SETCONSTF(id, ptr) { if( id & 0x8000 ) pd3dDevice->SetPixelShaderConstantF(id&0x7fff, (FLOAT*)ptr, 1); \ + else pd3dDevice->SetVertexShaderConstantF(id&0x7fff, (FLOAT*)ptr, 1); } + +#define SAMP_MEMORY0 0 +#define SAMP_MEMORY1 1 +#define SAMP_FINAL 2 +#define SAMP_BLOCKS 3 +#define SAMP_BILINEARBLOCKS 4 +#define SAMP_INTERLACE 5 +#define SAMP_BITWISEANDX 5 +#define SAMP_BITWISEANDY 6 + +// don't change these values! +#define GAME_TEXTURETARGS 0x01 +#define GAME_AUTORESET 0x02 +#define GAME_INTERLACE2X 0x04 +#define GAME_TEXAHACK 0x08 // apply texa to non textured polys +#define GAME_NOTARGETRESOLVE 0x10 +#define GAME_EXACTCOLOR 0x20 +#define GAME_NOCOLORCLAMP 0x40 +#define GAME_FFXHACK 0x80 +#define GAME_NODEPTHUPDATE 0x0200 +#define GAME_QUICKRESOLVE1 0x0400 +#define GAME_NOQUICKRESOLVE 0x0800 +#define GAME_NOTARGETCLUT 0x1000 // full 16 bit resolution +#define GAME_NOSTENCIL 0x2000 +#define GAME_VSSHACKOFF 0x4000 // vertical stripe syndrome +#define GAME_NODEPTHRESOLVE 0x8000 +#define GAME_FULL16BITRES 0x00010000 +#define GAME_RESOLVEPROMOTED 0x00020000 +#define GAME_FASTUPDATE 0x00040000 +#define GAME_NOALPHATEST 0x00080000 +#define GAME_DISABLEMRTDEPTH 0x00100000 +#define GAME_32BITTARGS 0x00200000 +#define GAME_PATH3HACK 0x00400000 +#define GAME_DOPARALLELCTX 0x00800000 // tries to parallelize both contexts so that render calls are reduced (xenosaga) + // makes the game faster, but can be buggy +#define GAME_XENOSPECHACK 0x01000000 // xenosaga specularity hack (ignore any zmask=1 draws) +#define GAME_PARTIALPOINTERS 0x02000000 // whenver the texture or render target are small, tries to look for bigger ones to read from +#define GAME_PARTIALDEPTH 0x04000000 // tries to save depth targets as much as possible across height changes +#define GAME_RELAXEDDEPTH 0x08000000 // tries to save depth targets as much as possible across height changes + +#define USEALPHABLENDING 1//(!(g_GameSettings&GAME_NOALPHABLEND)) +#define USEALPHATESTING (!(g_GameSettings&GAME_NOALPHATEST)) + +typedef IDirect3DDevice9* LPD3DDEV; +typedef IDirect3DVertexBuffer9* LPD3DVB; +typedef IDirect3DIndexBuffer9* LPD3DIB; +typedef IDirect3DBaseTexture9* LPD3DBASETEX; +typedef IDirect3DTexture9* LPD3DTEX; +typedef IDirect3DCubeTexture9* LPD3DCUBETEX; +typedef IDirect3DVolumeTexture9* LPD3DVOLUMETEX; +typedef IDirect3DSurface9* LPD3DSURF; +typedef IDirect3DVertexDeclaration9* LPD3DDECL; +typedef IDirect3DVertexShader9* LPD3DVS; +typedef IDirect3DPixelShader9* LPD3DPS; +typedef ID3DXAnimationController* LPD3DXAC; + +namespace ZeroGS +{ + typedef void (*DrawFn)(); + + // managers render-to-texture targets + class CRenderTarget + { + public: + CRenderTarget(); + CRenderTarget(const frameInfo& frame, CRenderTarget& r); // virtualized a target + virtual ~CRenderTarget(); + + virtual BOOL Create(const frameInfo& frame); + virtual void Destroy(); + + // set the GPU_POSXY variable, scissor rect, and current render target + void SetTarget(int fbplocal, const Rect2& scissor, int context); + void SetViewport(); + + // copies/creates the feedback contents + inline void CreateFeedback() { + if( ptexFeedback == NULL || !(status&TS_FeedbackReady) ) + _CreateFeedback(); + } + + virtual void Resolve(); + virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range + virtual void Update(int context, CRenderTarget* pdepth); + virtual void ConvertTo32(); // converts a psm==2 target, to a psm==0 + virtual void ConvertTo16(); // converts a psm==0 target, to a psm==2 + + virtual bool IsDepth() { return false; } + + LPD3DSURF psurf, psys; + LPD3DTEX ptex; + + int targoffx, targoffy; // the offset from the target that the real fbp starts at (in pixels) + int targheight; // height of ptex + CRenderTarget* pmimicparent; // if not NULL, this target is a subtarget of pmimicparent + + int fbp, fbw, fbh; // if fbp is negative, virtual target (not mapped to any real addr) + int start, end; // in bytes + u32 lastused; // time stamp since last used + DXVEC4 vposxy; + + u32 fbm; + u16 status; + u8 psm; + u8 resv0; + RECT scissorrect; + + //int startresolve, endresolve; + u32 nUpdateTarg; // use this target to update the texture if non 0 (one time only) + + // this is optionally used when feedback effects are used (render target is used as a texture when rendering to itself) + LPD3DTEX ptexFeedback; + LPD3DSURF psurfFeedback; + + enum TargetStatus { + TS_Resolved = 1, + TS_NeedUpdate = 2, + TS_Virtual = 4, // currently not mapped to memory + TS_FeedbackReady = 8, // feedback effect is ready and doesn't need to be updated + TS_NeedConvert32 = 16, + TS_NeedConvert16 = 32, + }; + + private: + void _CreateFeedback(); + }; + + // manages zbuffers + class CDepthTarget : public CRenderTarget + { + public: + CDepthTarget(); + virtual ~CDepthTarget(); + + virtual BOOL Create(const frameInfo& frame); + virtual void Destroy(); + + virtual void Resolve(); + virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range + virtual void Update(int context, CRenderTarget* prndr); + + virtual bool IsDepth() { return true; } + + void SetDepthTarget(); + + LPD3DSURF pdepth; + }; + + // manages contiguous chunks of memory (width is always 1024) + class CMemoryTarget + { + public: + struct MEMORY + { + inline MEMORY() : ptr(NULL), ref(0) {} + inline ~MEMORY() { _aligned_free(ptr); } + + BYTE* ptr; + int ref; + }; + + inline CMemoryTarget() : ptex(NULL), ptexsys(NULL), starty(0), height(0), realy(0), realheight(0), usedstamp(0), psm(0), + cpsm(0), memory(NULL), clearminy(0), clearmaxy(0), validatecount(0) {} + inline CMemoryTarget(const CMemoryTarget& r) { + ptex = r.ptex; + ptexsys = r.ptexsys; + if( ptex != NULL ) ptex->AddRef(); + if( ptexsys != NULL ) ptexsys->AddRef(); + starty = r.starty; + height = r.height; + realy = r.realy; + realheight = r.realheight; + usedstamp = r.usedstamp; + psm = r.psm; + cpsm = r.cpsm; + clut = r.clut; + memory = r.memory; + clearminy = r.clearminy; + clearmaxy = r.clearmaxy; + widthmult = r.widthmult; + validatecount = r.validatecount; + fmt = r.fmt; + if( memory != NULL ) memory->ref++; + } + + ~CMemoryTarget() { Destroy(); } + + inline void Destroy() { + SAFE_RELEASE(ptex); + SAFE_RELEASE(ptexsys); + + if( memory != NULL && memory->ref > 0 ) { + if( --memory->ref <= 0 ) { + SAFE_DELETE(memory); + } + } + memory = NULL; + } + + // returns true if clut data is synced + bool ValidateClut(const tex0Info& tex0); + // returns true if tex data is synced + bool ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex); + + int clearminy, clearmaxy; // when maxy > 0, need to check for clearing + + // realy is offset in pixels from start of valid region + // so texture in memory is [realy,starty+height] + // valid texture is [starty,starty+height] + // offset in mem [starty-realy, height] + int starty, height; // assert(starty >= realy) + int realy, realheight; // this is never touched once allocated + u32 usedstamp; + LPD3DTEX ptex; // can be 16bit if + LPD3DTEX ptexsys; + D3DFORMAT fmt; + + int widthmult; + + int validatecount; // count how many times has been validated, if too many, destroy + + vector clut; // if nonzero, texture uses CLUT + MEMORY* memory; // system memory used to compare for changes + u8 psm, cpsm; // texture and clut format. For psm, only 16bit/32bit differentiation matters + }; + + + struct VB + { + VB(); + ~VB(); + + void Destroy(); + + inline bool IsLocked() { return pbuf != NULL; } + inline void Lock(); + inline void Unlock() { + if( pbuf != NULL ) { + pvb->Unlock(); + pbuf = NULL; + } + } + + __forceinline bool CheckPrim(); + void CheckFrame(int tbp); + + // context specific state + Point offset; + Rect2 scissor; + tex0Info tex0; + tex1Info tex1; + miptbpInfo miptbp0; + miptbpInfo miptbp1; + alphaInfo alpha; + fbaInfo fba; + clampInfo clamp; + pixTest test; + LPD3DTEX ptexClamp[2]; // textures for x and y dir region clamping + + public: + + void FlushTexData(); + + u8 bNeedFrameCheck; + u8 bNeedZCheck; + u8 bNeedTexCheck; + u8 dummy0; + + union { + struct { + u8 bTexConstsSync; // only pixel shader constants that context owns + u8 bVarsTexSync; // texture info + u8 bVarsSetTarg; + u8 dummy1; + }; + u32 bSyncVars; + }; + + int ictx; + VertexGPU* pbuf; + DWORD dwCurOff; + DWORD dwCount; + primInfo curprim; // the previous prim the current buffers are set to + + zbufInfo zbuf; + frameInfo gsfb; // the real info set by FRAME cmd + frameInfo frame; + int zprimmask; // zmask for incoming points + + u32 uCurTex0Data[2]; // current tex0 data + u32 uNextTex0Data[2]; // tex0 data that has to be applied if bNeedTexCheck is 1 + + //int nFrameHeights[8]; // frame heights for the past frame changes + int nNextFrameHeight; + + CMemoryTarget* pmemtarg; // the current mem target set + LPD3DVB pvb; + CRenderTarget* prndr; + CDepthTarget* pdepth; + }; + + // visible members + extern DrawFn drawfn[8]; + extern VB vb[2]; + extern float fiTexWidth[2], fiTexHeight[2]; // current tex width and height + extern LONG width, height; + extern u8* g_pbyGSMemory; + extern u8* g_pbyGSClut; // the temporary clut buffer + + void AddMessage(const char* pstr, DWORD ms = 5000); + void ChangeWindowSize(int nNewWidth, int nNewHeight); + void SetChangeDeviceSize(int nNewWidth, int nNewHeight); + void ChangeDeviceSize(int nNewWidth, int nNewHeight); + void SetAA(int mode); + void SetCRC(int crc); + + void ReloadEffects(); + + // Methods // + + HRESULT Create(LONG width, LONG height); + void Destroy(BOOL bD3D); + + void Restore(); // call to restore device + void Reset(); // call to destroy video resources + + HRESULT InitDeviceObjects(); + void DeleteDeviceObjects(); + + void GSStateReset(); + + // called on a primitive switch + void Prim(); + + void SetTexFlush(); + // flush current vertices, call before setting new registers (the main render method) + void Flush(int context); + + void ExtWrite(); + + void SetWriteDepth(); + BOOL IsWriteDepth(); + + void SetDestAlphaTest(); + BOOL IsWriteDestAlphaTest(); + + void SetFogColor(u32 fog); + void SaveTex(tex0Info* ptex, int usevid); + + // called when trxdir is accessed. If host is involved, transfers memory to temp buffer byTransferBuf. + // Otherwise performs the transfer. TODO: Perhaps divide the transfers into chunks? + void InitTransferHostLocal(); + void TransferHostLocal(const void* pbyMem, u32 nQWordSize); + + void InitTransferLocalHost(); + void TransferLocalHost(void* pbyMem, u32 nQWordSize); + inline void TerminateLocalHost() {} + + void TransferLocalLocal(); + + // switches the render target to the real target, flushes the current render targets and renders the real image + void RenderCRTC(int interlace); + + bool CheckChangeInClut(u32 highdword, u32 psm); // returns true if clut will change after this tex0 op + + // call to load CLUT data (depending on CLD) + void texClutWrite(int ctx); + + int Save(char* pbydata); + bool Load(char* pbydata); + + void SaveSnapshot(const char* filename); + + // private methods + void FlushSysMem(const RECT* prc); + void _Resolve(const D3DLOCKED_RECT& locksrc, int fbp, int fbw, int fbh, int psm, u32 fbm); + + // returns the first and last addresses aligned to a page that cover + void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw); + + // inits the smallest rectangle in ptexMem that covers this region in ptexMem + // returns the offset that needs to be added to the locked rect to get the beginning of the buffer + //void GetMemRect(RECT& rc, int psm, int x, int y, int w, int h, int bp, int bw); + + // only sets a limited amount of state (for Update) + void SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, ZeroGS::CMemoryTarget* pmemtarg, int force); + + void ResetAlphaVariables(); + + bool StartCapture(); + void StopCapture(); + void CaptureFrame(); +}; + +extern LPDIRECT3DDEVICE9 pd3dDevice; +extern const u32 g_primmult[8]; +extern const u32 g_primsub[8]; + +#endif diff --git a/plugins/zerogs/opengl/GS.h b/plugins/zerogs/opengl/GS.h index 37f962b7c5..61565d2804 100644 --- a/plugins/zerogs/opengl/GS.h +++ b/plugins/zerogs/opengl/GS.h @@ -1,845 +1,845 @@ -/* ZeroGS KOSMOS - * Copyright (C) 2005-2006 zerofrog@gmail.com - * - * 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 - */ - -#ifndef __GS_H__ -#define __GS_H__ - -#ifdef _WIN32 - -#include -#include - -extern HWND GShwnd; - -#else // linux basic definitions - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif - -#include -#include -#include - -// need C definitions -extern "C" { -#define GSdefs -#include "PS2Edefs.h" - -extern "C" u32 CALLBACK PS2EgetLibType(void); -extern "C" u32 CALLBACK PS2EgetLibVersion2(u32 type); -extern "C" char* CALLBACK PS2EgetLibName(void); -} - -#include "zerogsmath.h" - -#ifndef _WIN32 -#include - -#include -#include -using namespace std; - -extern u32 THR_KeyEvent; // value for passing out key events beetwen threads -extern bool THR_bShift; - -#if !defined(_MSC_VER) && !defined(HAVE_ALIGNED_MALLOC) - -// declare linux equivalents -static __forceinline void* pcsx2_aligned_malloc(size_t size, size_t align) -{ - assert( align < 0x10000 ); - char* p = (char*)malloc(size+align); - int off = 2+align - ((int)(uptr)(p+2) % align); - - p += off; - *(u16*)(p-2) = off; - - return p; -} - -static __forceinline void pcsx2_aligned_free(void* pmem) -{ - if( pmem != NULL ) { - char* p = (char*)pmem; - free(p - (int)*(u16*)(p-2)); - } -} - -#define _aligned_malloc pcsx2_aligned_malloc -#define _aligned_free pcsx2_aligned_free - -#endif - -#include // ftime(), struct timeb - -inline unsigned long timeGetTime() -{ -#ifdef _WIN32 - _timeb t; - _ftime(&t); -#else - timeb t; - ftime(&t); -#endif - - return (unsigned long)(t.time*1000+t.millitm); -} - -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#define min(a,b) (((a) < (b)) ? (a) : (b)) - -struct RECT -{ - int left, top; - int right, bottom; -}; - -typedef struct { - Display *dpy; - int screen; - Window win; - GLXContext ctx; - XSetWindowAttributes attr; - Bool fs; - Bool doubleBuffered; - XF86VidModeModeInfo deskMode; - int x, y; - unsigned int width, height; - unsigned int depth; -} GLWindow; - -extern GLWindow GLWin; - -#endif // linux basic definitions - -struct Vector_16F -{ - u16 x, y, z, w; -}; - -///////////////////// -// define when releasing -// The only code that uses it is commented out! -//#define ZEROGS_CACHEDCLEAR // much better performance -//#define RELEASE_TO_PUBLIC -// fixme - We should use ZEROGS_DEVBUILD to determine devel/debug builds from "public release" builds. -// Means a lot of search-and-replace though. (air) - -#ifdef ZEROGS_DEVBUILD -#define GS_LOG __Log -#else -#define GS_LOG 0&& -#endif - -#define ERROR_LOG __LogToConsole -#define DEBUG_LOG printf - -#ifdef RELEASE_TO_PUBLIC -#define WARN_LOG 0&& -#define PRIM_LOG 0&& -#else -#define WARN_LOG printf -#define PRIM_LOG if (conf.log & 0x00000010) GS_LOG -#endif - -#ifndef GREG_LOG -#define GREG_LOG 0&& -#endif -#ifndef PRIM_LOG -#define PRIM_LOG 0&& -#endif -#ifndef WARN_LOG -#define WARN_LOG 0&& -#endif - -#define REG64(name) \ -union name \ -{ \ - u64 i64; \ - u32 ai32[2]; \ - struct { \ - -#define REG128(name)\ -union name \ -{ \ - u64 ai64[2]; \ - u32 ai32[4]; \ - struct { \ - -#define REG64_(prefix, name) REG64(prefix##name) -#define REG128_(prefix, name) REG128(prefix##name) - -#define REG_END }; }; -#define REG_END2 }; - -#define REG64_SET(name) \ -union name \ -{ \ - u64 i64; \ - u32 ai32[2]; \ - -#define REG128_SET(name)\ -union name \ -{ \ - u64 ai64[2]; \ - u32 ai32[4]; \ - -#define REG_SET_END }; - -REG64_(GSReg, BGCOLOR) - u32 R:8; - u32 G:8; - u32 B:8; - u32 _PAD1:8; - u32 _PAD2:32; -REG_END - -REG64_(GSReg, BUSDIR) - u32 DIR:1; - u32 _PAD1:31; - u32 _PAD2:32; -REG_END - -REG64_(GSReg, CSR) - u32 SIGNAL:1; - u32 FINISH:1; - u32 HSINT:1; - u32 VSINT:1; - u32 EDWINT:1; - u32 ZERO1:1; - u32 ZERO2:1; - u32 _PAD1:1; - u32 FLUSH:1; - u32 RESET:1; - u32 _PAD2:2; - u32 NFIELD:1; - u32 FIELD:1; - u32 FIFO:2; - u32 REV:8; - u32 ID:8; - u32 _PAD3:32; -REG_END - -REG64_(GSReg, DISPFB) // (-1/2) - u32 FBP:9; - u32 FBW:6; - u32 PSM:5; - u32 _PAD:12; - u32 DBX:11; - u32 DBY:11; - u32 _PAD2:10; -REG_END - -REG64_(GSReg, DISPLAY) // (-1/2) - u32 DX:12; - u32 DY:11; - u32 MAGH:4; - u32 MAGV:2; - u32 _PAD:3; - u32 DW:12; - u32 DH:11; - u32 _PAD2:9; -REG_END - -REG64_(GSReg, EXTBUF) - u32 EXBP:14; - u32 EXBW:6; - u32 FBIN:2; - u32 WFFMD:1; - u32 EMODA:2; - u32 EMODC:2; - u32 _PAD1:5; - u32 WDX:11; - u32 WDY:11; - u32 _PAD2:10; -REG_END - -REG64_(GSReg, EXTDATA) - u32 SX:12; - u32 SY:11; - u32 SMPH:4; - u32 SMPV:2; - u32 _PAD1:3; - u32 WW:12; - u32 WH:11; - u32 _PAD2:9; -REG_END - -REG64_(GSReg, EXTWRITE) - u32 WRITE; - u32 _PAD2:32; -REG_END - -REG64_(GSReg, IMR) - u32 _PAD1:8; - u32 SIGMSK:1; - u32 FINISHMSK:1; - u32 HSMSK:1; - u32 VSMSK:1; - u32 EDWMSK:1; - u32 _PAD2:19; - u32 _PAD3:32; -REG_END - -REG64_(GSReg, PMODE) - u32 EN1:1; - u32 EN2:1; - u32 CRTMD:3; - u32 MMOD:1; - u32 AMOD:1; - u32 SLBG:1; - u32 ALP:8; - u32 _PAD:16; - u32 _PAD1:32; -REG_END - -REG64_(GSReg, SIGLBLID) - u32 SIGID:32; - u32 LBLID:32; -REG_END - -REG64_(GSReg, SMODE1) - u32 RC:3; - u32 LC:7; - u32 T1248:2; - u32 SLCK:1; - u32 CMOD:2; - u32 EX:1; - u32 PRST:1; - u32 SINT:1; - u32 XPCK:1; - u32 PCK2:2; - u32 SPML:4; - u32 GCONT:1; - u32 PHS:1; - u32 PVS:1; - u32 PEHS:1; - u32 PEVS:1; - u32 CLKSEL:2; - u32 NVCK:1; - u32 SLCK2:1; - u32 VCKSEL:2; - u32 VHP:1; - u32 _PAD1:27; -REG_END - -REG64_(GSReg, SMODE2) - u32 INT:1; - u32 FFMD:1; - u32 DPMS:2; - u32 _PAD2:28; - u32 _PAD3:32; -REG_END - -REG64_(GSReg, SIGBLID) - u32 SIGID; - u32 LBLID; -REG_END - -extern int g_LastCRC; -extern u8* g_pBasePS2Mem; - -#define PMODE ((GSRegPMODE*)(g_pBasePS2Mem+0x0000)) -#define SMODE1 ((GSRegSMODE1*)(g_pBasePS2Mem+0x0010)) -#define SMODE2 ((GSRegSMODE2*)(g_pBasePS2Mem+0x0020)) -// SRFSH -#define SYNCH1 ((GSRegSYNCH1*)(g_pBasePS2Mem+0x0040)) -#define SYNCH2 ((GSRegSYNCH2*)(g_pBasePS2Mem+0x0050)) -#define SYNCV ((GSRegSYNCV*)(g_pBasePS2Mem+0x0060)) -#define DISPFB1 ((GSRegDISPFB*)(g_pBasePS2Mem+0x0070)) -#define DISPLAY1 ((GSRegDISPLAY*)(g_pBasePS2Mem+0x0080)) -#define DISPFB2 ((GSRegDISPFB*)(g_pBasePS2Mem+0x0090)) -#define DISPLAY2 ((GSRegDISPLAY*)(g_pBasePS2Mem+0x00a0)) -#define EXTBUF ((GSRegEXTBUF*)(g_pBasePS2Mem+0x00b0)) -#define EXTDATA ((GSRegEXTDATA*)(g_pBasePS2Mem+0x00c0)) -#define EXTWRITE ((GSRegEXTWRITE*)(g_pBasePS2Mem+0x00d0)) -#define BGCOLOR ((GSRegBGCOLOR*)(g_pBasePS2Mem+0x00e0)) -#define CSR ((GSRegCSR*)(g_pBasePS2Mem+0x1000)) -#define IMR ((GSRegIMR*)(g_pBasePS2Mem+0x1010)) -#define BUSDIR ((GSRegBUSDIR*)(g_pBasePS2Mem+0x1040)) -#define SIGLBLID ((GSRegSIGBLID*)(g_pBasePS2Mem+0x1080)) - -#define GET_GSFPS (((SMODE1->CMOD&1) ? 50 : 60) / (SMODE2->INT ? 1 : 2)) - -// -// sps2tags.h -// -#ifdef _M_AMD64 -#define GET_GIF_REG(tag, reg) \ - (((tag).ai64[1] >> ((reg) << 2)) & 0xf) -#else -#define GET_GIF_REG(tag, reg) \ - (((tag).ai32[2 + ((reg) >> 3)] >> (((reg) & 7) << 2)) & 0xf) -#endif - -// -// GIFTag -REG128(GIFTag) - u32 NLOOP:15; - u32 EOP:1; - u32 _PAD1:16; - u32 _PAD2:14; - u32 PRE:1; - u32 PRIM:11; - u32 FLG:2; // enum GIF_FLG - u32 NREG:4; - u64 REGS:64; -REG_END - -typedef struct { - int x, y, w, h; -} Rect; - -typedef struct { - int x, y; -} Point; - -typedef struct { - int x0, y0; - int x1, y1; -} Rect2; - -typedef struct { - int x, y, c; -} PointC; - -#define GSOPTION_FULLSCREEN 0x2 -#define GSOPTION_TGASNAP 0x4 -#define GSOPTION_CAPTUREAVI 0x8 - -#define GSOPTION_WINDIMS 0x30 -#define GSOPTION_WIN640 0x00 -#define GSOPTION_WIN800 0x10 -#define GSOPTION_WIN1024 0x20 -#define GSOPTION_WIN1280 0x30 - -#define GSOPTION_WIREFRAME 0x100 -#define GSOPTION_LOADED 0x8000 - -typedef struct { - u8 mrtdepth; // write color in render target - u8 interlace; - u8 aa; // antialiasing 0 - off, 1 - 2x, 2 - 4x - u8 bilinear; // set to enable bilinear support - u32 options; - u32 gamesettings; // default game settings - int width, height; - int winstyle; // window style before full screen -#ifdef GS_LOG - u32 log; -#endif -} GSconf; - -struct VertexGPU -{ - s16 x, y, f, resv0; // note: xy is 12d3 - u32 rgba; - u32 z; - float s, t, q; -}; - -struct Vertex -{ - u16 x, y, f, resv0; // note: xy is 12d3 - u32 rgba; - u32 z; - float s, t, q; - u16 u, v; -}; - -extern int g_GameSettings; -extern GSconf conf; -extern int ppf; - -#define PSMCT32 0 -#define PSMCT24 1 -#define PSMCT16 2 -#define PSMCT16S 10 -#define PSMT8 19 -#define PSMT4 20 -#define PSMT8H 27 -#define PSMT4HL 36 -#define PSMT4HH 44 -#define PSMT32Z 48 -#define PSMT24Z 49 -#define PSMT16Z 50 -#define PSMT16SZ 58 - -#define PSMT_ISCLUT(psm) (((psm)&0x7)>2) -#define PSMT_IS16BIT(psm) (((psm)&7)==2||((psm)&7)==10) - -typedef struct { - int nloop; - int eop; - int nreg; -} tagInfo; - -typedef union { - s64 SD; - u64 UD; - s32 SL[2]; - u32 UL[2]; - s16 SS[4]; - u16 US[4]; - s8 SC[8]; - u8 UC[8]; -} reg64; - -/* general purpose regs structs */ -typedef struct { - int fbp; - int fbw; - int fbh; - int psm; - u32 fbm; -} frameInfo; - -typedef struct { - u16 prim; - - union { - struct { - u16 iip : 1; - u16 tme : 1; - u16 fge : 1; - u16 abe : 1; - u16 aa1 : 1; - u16 fst : 1; - u16 ctxt : 1; - u16 fix : 1; - u16 resv : 8; - }; - u16 _val; - }; -} primInfo; - -extern primInfo *prim; - -typedef union { - struct { - u32 ate : 1; - u32 atst : 3; - u32 aref : 8; - u32 afail : 2; - u32 date : 1; - u32 datm : 1; - u32 zte : 1; - u32 ztst : 2; - u32 resv : 13; - }; - u32 _val; -} pixTest; - -typedef struct { - int bp; - int bw; - int psm; -} bufInfo; - -typedef struct { - int tbp0; - int tbw; - int cbp; - u16 tw, th; - u8 psm; - u8 tcc; - u8 tfx; - u8 cpsm; - u8 csm; - u8 csa; - u8 cld; -} tex0Info; - -#define TEX_MODULATE 0 -#define TEX_DECAL 1 -#define TEX_HIGHLIGHT 2 -#define TEX_HIGHLIGHT2 3 - -typedef struct { - int lcm; - int mxl; - int mmag; - int mmin; - int mtba; - int l; - int k; -} tex1Info; - -typedef struct { - int wms; - int wmt; - int minu; - int maxu; - int minv; - int maxv; -} clampInfo; - -typedef struct { - int cbw; - int cou; - int cov; -} clutInfo; - -typedef struct { - int tbp[3]; - int tbw[3]; -} miptbpInfo; - -typedef struct { - u16 aem; - u8 ta[2]; - float fta[2]; -} texaInfo; - -typedef struct { - int sx; - int sy; - int dx; - int dy; - int dir; -} trxposInfo; - -typedef struct { - union { - struct { - u8 a : 2; - u8 b : 2; - u8 c : 2; - u8 d : 2; - }; - u8 abcd; - }; - - u8 fix : 8; -} alphaInfo; - -typedef struct { - u16 zbp; // u16 address / 64 - u8 psm; - u8 zmsk; -} zbufInfo; - -typedef struct { - int fba; -} fbaInfo; - -typedef struct { - int mode; - int regn; - u64 regs; - tagInfo tag; -} pathInfo; - -typedef struct { - Vertex gsvertex[3]; - u32 rgba; - float q; - Vertex vertexregs; - - int primC; // number of verts current storing - int primIndex; // current prim index - int nTriFanVert; - - int prac; - int dthe; - int colclamp; - int fogcol; - int smask; - int pabe; - u64 buff[2]; - int buffsize; - int cbp[2]; // internal cbp registers - - u32 CSRw; - - primInfo _prim[2]; - bufInfo srcbuf, srcbufnew; - bufInfo dstbuf, dstbufnew; - - clutInfo clut; - - texaInfo texa; - trxposInfo trxpos, trxposnew; - - int imageWtemp, imageHtemp; - - int imageTransfer; - int imageWnew, imageHnew, imageX, imageY, imageEndX, imageEndY; - - pathInfo path1; - pathInfo path2; - pathInfo path3; - -} GSinternal; - -extern GSinternal gs; - -extern FILE *gsLog; - -void __Log(const char *fmt, ...); -void __LogToConsole(const char *fmt, ...); - -void LoadConfig(); -void SaveConfig(); - -extern void (*GSirq)(); - -void *SysLoadLibrary(char *lib); // Loads Library -void *SysLoadSym(void *lib, char *sym); // Loads Symbol from Library -char *SysLibError(); // Gets previous error loading sysbols -void SysCloseLibrary(void *lib); // Closes Library -void SysMessage(char *fmt, ...); - -extern "C" void * memcpy_amd(void *dest, const void *src, size_t n); -extern "C" u8 memcmp_mmx(const void *dest, const void *src, int n); - -template -class CInterfacePtr -{ -public: - inline CInterfacePtr() : ptr(NULL) {} - inline explicit CInterfacePtr(T* newptr) : ptr(newptr) { if ( ptr != NULL ) ptr->AddRef(); } - inline ~CInterfacePtr() { if( ptr != NULL ) ptr->Release(); } - - inline T* operator* () { assert( ptr != NULL); return *ptr; } - inline T* operator->() { return ptr; } - inline T* get() { return ptr; } - - inline void release() { - if( ptr != NULL ) { ptr->Release(); ptr = NULL; } - } - - inline operator T*() { return ptr; } - - inline bool operator==(T* rhs) { return ptr == rhs; } - inline bool operator!=(T* rhs) { return ptr != rhs; } - - inline CInterfacePtr& operator= (T* newptr) { - if( ptr != NULL ) ptr->Release(); - ptr = newptr; - - if( ptr != NULL ) ptr->AddRef(); - return *this; - } - -private: - T* ptr; -}; - -#define RGBA32to16(c) \ - (u16)((((c) & 0x000000f8) >> 3) | \ - (((c) & 0x0000f800) >> 6) | \ - (((c) & 0x00f80000) >> 9) | \ - (((c) & 0x80000000) >> 16)) \ - -#define RGBA16to32(c) \ - (((c) & 0x001f) << 3) | \ - (((c) & 0x03e0) << 6) | \ - (((c) & 0x7c00) << 9) | \ - (((c) & 0x8000) ? 0xff000000 : 0) \ - -// converts float16 [0,1] to BYTE [0,255] (assumes value is in range, otherwise will take lower 8bits) -// f is a u16 -static __forceinline u16 Float16ToBYTE(u16 f) { - //assert( !(f & 0x8000) ); - if( f & 0x8000 ) return 0; - - u16 d = ((((f&0x3ff)|0x400)*255)>>(10-((f>>10)&0x1f)+15)); - return d > 255 ? 255 : d; -} - -static __forceinline u16 Float16ToALPHA(u16 f) { - //assert( !(f & 0x8000) ); - if( f & 0x8000 ) return 0; - - // round up instead of down (crash and burn), too much and charlie breaks - u16 d = (((((f&0x3ff)|0x400))*255)>>(10-((f>>10)&0x1f)+15)); - d = (d)>>1; - return d > 255 ? 255 : d; -} - -#ifndef COLOR_ARGB -#define COLOR_ARGB(a,r,g,b) \ - ((u32)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff))) -#endif - -// assumes that positive in [1,2] (then extracts fraction by just looking at the specified bits) -#define Float16ToBYTE_2(f) ((u8)(*(u16*)&f>>2)) -#define Float16To5BIT(f) (Float16ToBYTE(f)>>3) - -#define Float16Alpha(f) (((*(u16*)&f&0x7c00)>=0x3900)?0x8000:0) // alpha is >= 1 - -// converts an array of 4 u16s to a u32 color -// f is a pointer to a u16 -#define Float16ToARGB(f) COLOR_ARGB(Float16ToALPHA(f.w), Float16ToBYTE(f.x), Float16ToBYTE(f.y), Float16ToBYTE(f.z)); - -#define Float16ToARGB16(f) (Float16Alpha(f.w)|(Float16To5BIT(f.x)<<10)|(Float16To5BIT(f.y)<<5)|Float16To5BIT(f.z)) - -// used for Z values -#define Float16ToARGB_Z(f) COLOR_ARGB((u32)Float16ToBYTE_2(f.w), Float16ToBYTE_2(f.x), Float16ToBYTE_2(f.y), Float16ToBYTE_2(f.z)) -#define Float16ToARGB16_Z(f) ((Float16ToBYTE_2(f.y)<<8)|Float16ToBYTE_2(f.z)) - - -inline float Clamp(float fx, float fmin, float fmax) -{ - if( fx < fmin ) return fmin; - return fx > fmax ? fmax : fx; -} - -// IMPORTANT: For every Register there must be an End -void DVProfRegister(char* pname); // first checks if this profiler exists in g_listProfilers -void DVProfEnd(u32 dwUserData); -void DVProfWrite(char* pfilename, u32 frames = 0); -void DVProfClear(); // clears all the profilers - -#define DVPROFILE -#ifdef DVPROFILE - -class DVProfileFunc -{ -public: - u32 dwUserData; - DVProfileFunc(char* pname) { DVProfRegister(pname); dwUserData = 0; } - DVProfileFunc(char* pname, u32 dwUserData) : dwUserData(dwUserData) { DVProfRegister(pname); } - ~DVProfileFunc() { DVProfEnd(dwUserData); } -}; - -#else - -class DVProfileFunc -{ -public: - u32 dwUserData; - static __forceinline DVProfileFunc(char* pname) {} - static __forceinline DVProfileFunc(char* pname, u32 dwUserData) { } - ~DVProfileFunc() {} -}; - -#endif - -#endif +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#ifndef __GS_H__ +#define __GS_H__ + +#ifdef _WIN32 + +#include +#include + +extern HWND GShwnd; + +#else // linux basic definitions + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + +#include +#include +#include + +// need C definitions +extern "C" { +#define GSdefs +#include "PS2Edefs.h" + +extern "C" u32 CALLBACK PS2EgetLibType(void); +extern "C" u32 CALLBACK PS2EgetLibVersion2(u32 type); +extern "C" char* CALLBACK PS2EgetLibName(void); +} + +#include "zerogsmath.h" + +#ifndef _WIN32 +#include + +#include +#include +using namespace std; + +extern u32 THR_KeyEvent; // value for passing out key events beetwen threads +extern bool THR_bShift; + +#if !defined(_MSC_VER) && !defined(HAVE_ALIGNED_MALLOC) + +// declare linux equivalents +static __forceinline void* pcsx2_aligned_malloc(size_t size, size_t align) +{ + assert( align < 0x10000 ); + char* p = (char*)malloc(size+align); + int off = 2+align - ((int)(uptr)(p+2) % align); + + p += off; + *(u16*)(p-2) = off; + + return p; +} + +static __forceinline void pcsx2_aligned_free(void* pmem) +{ + if( pmem != NULL ) { + char* p = (char*)pmem; + free(p - (int)*(u16*)(p-2)); + } +} + +#define _aligned_malloc pcsx2_aligned_malloc +#define _aligned_free pcsx2_aligned_free + +#endif + +#include // ftime(), struct timeb + +inline unsigned long timeGetTime() +{ +#ifdef _WIN32 + _timeb t; + _ftime(&t); +#else + timeb t; + ftime(&t); +#endif + + return (unsigned long)(t.time*1000+t.millitm); +} + +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +struct RECT +{ + int left, top; + int right, bottom; +}; + +typedef struct { + Display *dpy; + int screen; + Window win; + GLXContext ctx; + XSetWindowAttributes attr; + Bool fs; + Bool doubleBuffered; + XF86VidModeModeInfo deskMode; + int x, y; + unsigned int width, height; + unsigned int depth; +} GLWindow; + +extern GLWindow GLWin; + +#endif // linux basic definitions + +struct Vector_16F +{ + u16 x, y, z, w; +}; + +///////////////////// +// define when releasing +// The only code that uses it is commented out! +//#define ZEROGS_CACHEDCLEAR // much better performance +//#define RELEASE_TO_PUBLIC +// fixme - We should use ZEROGS_DEVBUILD to determine devel/debug builds from "public release" builds. +// Means a lot of search-and-replace though. (air) + +#ifdef ZEROGS_DEVBUILD +#define GS_LOG __Log +#else +#define GS_LOG 0&& +#endif + +#define ERROR_LOG __LogToConsole +#define DEBUG_LOG printf + +#ifdef RELEASE_TO_PUBLIC +#define WARN_LOG 0&& +#define PRIM_LOG 0&& +#else +#define WARN_LOG printf +#define PRIM_LOG if (conf.log & 0x00000010) GS_LOG +#endif + +#ifndef GREG_LOG +#define GREG_LOG 0&& +#endif +#ifndef PRIM_LOG +#define PRIM_LOG 0&& +#endif +#ifndef WARN_LOG +#define WARN_LOG 0&& +#endif + +#define REG64(name) \ +union name \ +{ \ + u64 i64; \ + u32 ai32[2]; \ + struct { \ + +#define REG128(name)\ +union name \ +{ \ + u64 ai64[2]; \ + u32 ai32[4]; \ + struct { \ + +#define REG64_(prefix, name) REG64(prefix##name) +#define REG128_(prefix, name) REG128(prefix##name) + +#define REG_END }; }; +#define REG_END2 }; + +#define REG64_SET(name) \ +union name \ +{ \ + u64 i64; \ + u32 ai32[2]; \ + +#define REG128_SET(name)\ +union name \ +{ \ + u64 ai64[2]; \ + u32 ai32[4]; \ + +#define REG_SET_END }; + +REG64_(GSReg, BGCOLOR) + u32 R:8; + u32 G:8; + u32 B:8; + u32 _PAD1:8; + u32 _PAD2:32; +REG_END + +REG64_(GSReg, BUSDIR) + u32 DIR:1; + u32 _PAD1:31; + u32 _PAD2:32; +REG_END + +REG64_(GSReg, CSR) + u32 SIGNAL:1; + u32 FINISH:1; + u32 HSINT:1; + u32 VSINT:1; + u32 EDWINT:1; + u32 ZERO1:1; + u32 ZERO2:1; + u32 _PAD1:1; + u32 FLUSH:1; + u32 RESET:1; + u32 _PAD2:2; + u32 NFIELD:1; + u32 FIELD:1; + u32 FIFO:2; + u32 REV:8; + u32 ID:8; + u32 _PAD3:32; +REG_END + +REG64_(GSReg, DISPFB) // (-1/2) + u32 FBP:9; + u32 FBW:6; + u32 PSM:5; + u32 _PAD:12; + u32 DBX:11; + u32 DBY:11; + u32 _PAD2:10; +REG_END + +REG64_(GSReg, DISPLAY) // (-1/2) + u32 DX:12; + u32 DY:11; + u32 MAGH:4; + u32 MAGV:2; + u32 _PAD:3; + u32 DW:12; + u32 DH:11; + u32 _PAD2:9; +REG_END + +REG64_(GSReg, EXTBUF) + u32 EXBP:14; + u32 EXBW:6; + u32 FBIN:2; + u32 WFFMD:1; + u32 EMODA:2; + u32 EMODC:2; + u32 _PAD1:5; + u32 WDX:11; + u32 WDY:11; + u32 _PAD2:10; +REG_END + +REG64_(GSReg, EXTDATA) + u32 SX:12; + u32 SY:11; + u32 SMPH:4; + u32 SMPV:2; + u32 _PAD1:3; + u32 WW:12; + u32 WH:11; + u32 _PAD2:9; +REG_END + +REG64_(GSReg, EXTWRITE) + u32 WRITE; + u32 _PAD2:32; +REG_END + +REG64_(GSReg, IMR) + u32 _PAD1:8; + u32 SIGMSK:1; + u32 FINISHMSK:1; + u32 HSMSK:1; + u32 VSMSK:1; + u32 EDWMSK:1; + u32 _PAD2:19; + u32 _PAD3:32; +REG_END + +REG64_(GSReg, PMODE) + u32 EN1:1; + u32 EN2:1; + u32 CRTMD:3; + u32 MMOD:1; + u32 AMOD:1; + u32 SLBG:1; + u32 ALP:8; + u32 _PAD:16; + u32 _PAD1:32; +REG_END + +REG64_(GSReg, SIGLBLID) + u32 SIGID:32; + u32 LBLID:32; +REG_END + +REG64_(GSReg, SMODE1) + u32 RC:3; + u32 LC:7; + u32 T1248:2; + u32 SLCK:1; + u32 CMOD:2; + u32 EX:1; + u32 PRST:1; + u32 SINT:1; + u32 XPCK:1; + u32 PCK2:2; + u32 SPML:4; + u32 GCONT:1; + u32 PHS:1; + u32 PVS:1; + u32 PEHS:1; + u32 PEVS:1; + u32 CLKSEL:2; + u32 NVCK:1; + u32 SLCK2:1; + u32 VCKSEL:2; + u32 VHP:1; + u32 _PAD1:27; +REG_END + +REG64_(GSReg, SMODE2) + u32 INT:1; + u32 FFMD:1; + u32 DPMS:2; + u32 _PAD2:28; + u32 _PAD3:32; +REG_END + +REG64_(GSReg, SIGBLID) + u32 SIGID; + u32 LBLID; +REG_END + +extern int g_LastCRC; +extern u8* g_pBasePS2Mem; + +#define PMODE ((GSRegPMODE*)(g_pBasePS2Mem+0x0000)) +#define SMODE1 ((GSRegSMODE1*)(g_pBasePS2Mem+0x0010)) +#define SMODE2 ((GSRegSMODE2*)(g_pBasePS2Mem+0x0020)) +// SRFSH +#define SYNCH1 ((GSRegSYNCH1*)(g_pBasePS2Mem+0x0040)) +#define SYNCH2 ((GSRegSYNCH2*)(g_pBasePS2Mem+0x0050)) +#define SYNCV ((GSRegSYNCV*)(g_pBasePS2Mem+0x0060)) +#define DISPFB1 ((GSRegDISPFB*)(g_pBasePS2Mem+0x0070)) +#define DISPLAY1 ((GSRegDISPLAY*)(g_pBasePS2Mem+0x0080)) +#define DISPFB2 ((GSRegDISPFB*)(g_pBasePS2Mem+0x0090)) +#define DISPLAY2 ((GSRegDISPLAY*)(g_pBasePS2Mem+0x00a0)) +#define EXTBUF ((GSRegEXTBUF*)(g_pBasePS2Mem+0x00b0)) +#define EXTDATA ((GSRegEXTDATA*)(g_pBasePS2Mem+0x00c0)) +#define EXTWRITE ((GSRegEXTWRITE*)(g_pBasePS2Mem+0x00d0)) +#define BGCOLOR ((GSRegBGCOLOR*)(g_pBasePS2Mem+0x00e0)) +#define CSR ((GSRegCSR*)(g_pBasePS2Mem+0x1000)) +#define IMR ((GSRegIMR*)(g_pBasePS2Mem+0x1010)) +#define BUSDIR ((GSRegBUSDIR*)(g_pBasePS2Mem+0x1040)) +#define SIGLBLID ((GSRegSIGBLID*)(g_pBasePS2Mem+0x1080)) + +#define GET_GSFPS (((SMODE1->CMOD&1) ? 50 : 60) / (SMODE2->INT ? 1 : 2)) + +// +// sps2tags.h +// +#ifdef _M_AMD64 +#define GET_GIF_REG(tag, reg) \ + (((tag).ai64[1] >> ((reg) << 2)) & 0xf) +#else +#define GET_GIF_REG(tag, reg) \ + (((tag).ai32[2 + ((reg) >> 3)] >> (((reg) & 7) << 2)) & 0xf) +#endif + +// +// GIFTag +REG128(GIFTag) + u32 NLOOP:15; + u32 EOP:1; + u32 _PAD1:16; + u32 _PAD2:14; + u32 PRE:1; + u32 PRIM:11; + u32 FLG:2; // enum GIF_FLG + u32 NREG:4; + u64 REGS:64; +REG_END + +typedef struct { + int x, y, w, h; +} Rect; + +typedef struct { + int x, y; +} Point; + +typedef struct { + int x0, y0; + int x1, y1; +} Rect2; + +typedef struct { + int x, y, c; +} PointC; + +#define GSOPTION_FULLSCREEN 0x2 +#define GSOPTION_TGASNAP 0x4 +#define GSOPTION_CAPTUREAVI 0x8 + +#define GSOPTION_WINDIMS 0x30 +#define GSOPTION_WIN640 0x00 +#define GSOPTION_WIN800 0x10 +#define GSOPTION_WIN1024 0x20 +#define GSOPTION_WIN1280 0x30 + +#define GSOPTION_WIREFRAME 0x100 +#define GSOPTION_LOADED 0x8000 + +typedef struct { + u8 mrtdepth; // write color in render target + u8 interlace; + u8 aa; // antialiasing 0 - off, 1 - 2x, 2 - 4x + u8 bilinear; // set to enable bilinear support + u32 options; + u32 gamesettings; // default game settings + int width, height; + int winstyle; // window style before full screen +#ifdef GS_LOG + u32 log; +#endif +} GSconf; + +struct VertexGPU +{ + s16 x, y, f, resv0; // note: xy is 12d3 + u32 rgba; + u32 z; + float s, t, q; +}; + +struct Vertex +{ + u16 x, y, f, resv0; // note: xy is 12d3 + u32 rgba; + u32 z; + float s, t, q; + u16 u, v; +}; + +extern int g_GameSettings; +extern GSconf conf; +extern int ppf; + +#define PSMCT32 0 +#define PSMCT24 1 +#define PSMCT16 2 +#define PSMCT16S 10 +#define PSMT8 19 +#define PSMT4 20 +#define PSMT8H 27 +#define PSMT4HL 36 +#define PSMT4HH 44 +#define PSMT32Z 48 +#define PSMT24Z 49 +#define PSMT16Z 50 +#define PSMT16SZ 58 + +#define PSMT_ISCLUT(psm) (((psm)&0x7)>2) +#define PSMT_IS16BIT(psm) (((psm)&7)==2||((psm)&7)==10) + +typedef struct { + int nloop; + int eop; + int nreg; +} tagInfo; + +typedef union { + s64 SD; + u64 UD; + s32 SL[2]; + u32 UL[2]; + s16 SS[4]; + u16 US[4]; + s8 SC[8]; + u8 UC[8]; +} reg64; + +/* general purpose regs structs */ +typedef struct { + int fbp; + int fbw; + int fbh; + int psm; + u32 fbm; +} frameInfo; + +typedef struct { + u16 prim; + + union { + struct { + u16 iip : 1; + u16 tme : 1; + u16 fge : 1; + u16 abe : 1; + u16 aa1 : 1; + u16 fst : 1; + u16 ctxt : 1; + u16 fix : 1; + u16 resv : 8; + }; + u16 _val; + }; +} primInfo; + +extern primInfo *prim; + +typedef union { + struct { + u32 ate : 1; + u32 atst : 3; + u32 aref : 8; + u32 afail : 2; + u32 date : 1; + u32 datm : 1; + u32 zte : 1; + u32 ztst : 2; + u32 resv : 13; + }; + u32 _val; +} pixTest; + +typedef struct { + int bp; + int bw; + int psm; +} bufInfo; + +typedef struct { + int tbp0; + int tbw; + int cbp; + u16 tw, th; + u8 psm; + u8 tcc; + u8 tfx; + u8 cpsm; + u8 csm; + u8 csa; + u8 cld; +} tex0Info; + +#define TEX_MODULATE 0 +#define TEX_DECAL 1 +#define TEX_HIGHLIGHT 2 +#define TEX_HIGHLIGHT2 3 + +typedef struct { + int lcm; + int mxl; + int mmag; + int mmin; + int mtba; + int l; + int k; +} tex1Info; + +typedef struct { + int wms; + int wmt; + int minu; + int maxu; + int minv; + int maxv; +} clampInfo; + +typedef struct { + int cbw; + int cou; + int cov; +} clutInfo; + +typedef struct { + int tbp[3]; + int tbw[3]; +} miptbpInfo; + +typedef struct { + u16 aem; + u8 ta[2]; + float fta[2]; +} texaInfo; + +typedef struct { + int sx; + int sy; + int dx; + int dy; + int dir; +} trxposInfo; + +typedef struct { + union { + struct { + u8 a : 2; + u8 b : 2; + u8 c : 2; + u8 d : 2; + }; + u8 abcd; + }; + + u8 fix : 8; +} alphaInfo; + +typedef struct { + u16 zbp; // u16 address / 64 + u8 psm; + u8 zmsk; +} zbufInfo; + +typedef struct { + int fba; +} fbaInfo; + +typedef struct { + int mode; + int regn; + u64 regs; + tagInfo tag; +} pathInfo; + +typedef struct { + Vertex gsvertex[3]; + u32 rgba; + float q; + Vertex vertexregs; + + int primC; // number of verts current storing + int primIndex; // current prim index + int nTriFanVert; + + int prac; + int dthe; + int colclamp; + int fogcol; + int smask; + int pabe; + u64 buff[2]; + int buffsize; + int cbp[2]; // internal cbp registers + + u32 CSRw; + + primInfo _prim[2]; + bufInfo srcbuf, srcbufnew; + bufInfo dstbuf, dstbufnew; + + clutInfo clut; + + texaInfo texa; + trxposInfo trxpos, trxposnew; + + int imageWtemp, imageHtemp; + + int imageTransfer; + int imageWnew, imageHnew, imageX, imageY, imageEndX, imageEndY; + + pathInfo path1; + pathInfo path2; + pathInfo path3; + +} GSinternal; + +extern GSinternal gs; + +extern FILE *gsLog; + +void __Log(const char *fmt, ...); +void __LogToConsole(const char *fmt, ...); + +void LoadConfig(); +void SaveConfig(); + +extern void (*GSirq)(); + +void *SysLoadLibrary(char *lib); // Loads Library +void *SysLoadSym(void *lib, char *sym); // Loads Symbol from Library +char *SysLibError(); // Gets previous error loading sysbols +void SysCloseLibrary(void *lib); // Closes Library +void SysMessage(char *fmt, ...); + +extern "C" void * memcpy_amd(void *dest, const void *src, size_t n); +extern "C" u8 memcmp_mmx(const void *dest, const void *src, int n); + +template +class CInterfacePtr +{ +public: + inline CInterfacePtr() : ptr(NULL) {} + inline explicit CInterfacePtr(T* newptr) : ptr(newptr) { if ( ptr != NULL ) ptr->AddRef(); } + inline ~CInterfacePtr() { if( ptr != NULL ) ptr->Release(); } + + inline T* operator* () { assert( ptr != NULL); return *ptr; } + inline T* operator->() { return ptr; } + inline T* get() { return ptr; } + + inline void release() { + if( ptr != NULL ) { ptr->Release(); ptr = NULL; } + } + + inline operator T*() { return ptr; } + + inline bool operator==(T* rhs) { return ptr == rhs; } + inline bool operator!=(T* rhs) { return ptr != rhs; } + + inline CInterfacePtr& operator= (T* newptr) { + if( ptr != NULL ) ptr->Release(); + ptr = newptr; + + if( ptr != NULL ) ptr->AddRef(); + return *this; + } + +private: + T* ptr; +}; + +#define RGBA32to16(c) \ + (u16)((((c) & 0x000000f8) >> 3) | \ + (((c) & 0x0000f800) >> 6) | \ + (((c) & 0x00f80000) >> 9) | \ + (((c) & 0x80000000) >> 16)) \ + +#define RGBA16to32(c) \ + (((c) & 0x001f) << 3) | \ + (((c) & 0x03e0) << 6) | \ + (((c) & 0x7c00) << 9) | \ + (((c) & 0x8000) ? 0xff000000 : 0) \ + +// converts float16 [0,1] to BYTE [0,255] (assumes value is in range, otherwise will take lower 8bits) +// f is a u16 +static __forceinline u16 Float16ToBYTE(u16 f) { + //assert( !(f & 0x8000) ); + if( f & 0x8000 ) return 0; + + u16 d = ((((f&0x3ff)|0x400)*255)>>(10-((f>>10)&0x1f)+15)); + return d > 255 ? 255 : d; +} + +static __forceinline u16 Float16ToALPHA(u16 f) { + //assert( !(f & 0x8000) ); + if( f & 0x8000 ) return 0; + + // round up instead of down (crash and burn), too much and charlie breaks + u16 d = (((((f&0x3ff)|0x400))*255)>>(10-((f>>10)&0x1f)+15)); + d = (d)>>1; + return d > 255 ? 255 : d; +} + +#ifndef COLOR_ARGB +#define COLOR_ARGB(a,r,g,b) \ + ((u32)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff))) +#endif + +// assumes that positive in [1,2] (then extracts fraction by just looking at the specified bits) +#define Float16ToBYTE_2(f) ((u8)(*(u16*)&f>>2)) +#define Float16To5BIT(f) (Float16ToBYTE(f)>>3) + +#define Float16Alpha(f) (((*(u16*)&f&0x7c00)>=0x3900)?0x8000:0) // alpha is >= 1 + +// converts an array of 4 u16s to a u32 color +// f is a pointer to a u16 +#define Float16ToARGB(f) COLOR_ARGB(Float16ToALPHA(f.w), Float16ToBYTE(f.x), Float16ToBYTE(f.y), Float16ToBYTE(f.z)); + +#define Float16ToARGB16(f) (Float16Alpha(f.w)|(Float16To5BIT(f.x)<<10)|(Float16To5BIT(f.y)<<5)|Float16To5BIT(f.z)) + +// used for Z values +#define Float16ToARGB_Z(f) COLOR_ARGB((u32)Float16ToBYTE_2(f.w), Float16ToBYTE_2(f.x), Float16ToBYTE_2(f.y), Float16ToBYTE_2(f.z)) +#define Float16ToARGB16_Z(f) ((Float16ToBYTE_2(f.y)<<8)|Float16ToBYTE_2(f.z)) + + +inline float Clamp(float fx, float fmin, float fmax) +{ + if( fx < fmin ) return fmin; + return fx > fmax ? fmax : fx; +} + +// IMPORTANT: For every Register there must be an End +void DVProfRegister(char* pname); // first checks if this profiler exists in g_listProfilers +void DVProfEnd(u32 dwUserData); +void DVProfWrite(char* pfilename, u32 frames = 0); +void DVProfClear(); // clears all the profilers + +#define DVPROFILE +#ifdef DVPROFILE + +class DVProfileFunc +{ +public: + u32 dwUserData; + DVProfileFunc(char* pname) { DVProfRegister(pname); dwUserData = 0; } + DVProfileFunc(char* pname, u32 dwUserData) : dwUserData(dwUserData) { DVProfRegister(pname); } + ~DVProfileFunc() { DVProfEnd(dwUserData); } +}; + +#else + +class DVProfileFunc +{ +public: + u32 dwUserData; + static __forceinline DVProfileFunc(char* pname) {} + static __forceinline DVProfileFunc(char* pname, u32 dwUserData) { } + ~DVProfileFunc() {} +}; + +#endif + +#endif diff --git a/plugins/zerogs/opengl/GSmain.cpp b/plugins/zerogs/opengl/GSmain.cpp index e197e4f78e..766ff20be3 100644 --- a/plugins/zerogs/opengl/GSmain.cpp +++ b/plugins/zerogs/opengl/GSmain.cpp @@ -1,1400 +1,1400 @@ -/* ZeroGS KOSMOS - * Copyright (C) 2005-2006 zerofrog@gmail.com - * - * 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 - */ -#if defined(_WIN32) -#include -#include "Win32.h" -#endif - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -using namespace std; - -#include "GS.h" -#include "Mem.h" -#include "Regs.h" - -#include "zerogs.h" -#include "targets.h" -#include "ZeroGSShaders/zerogsshaders.h" - -#ifdef _MSC_VER -#pragma warning(disable:4244) -#endif - -GSinternal gs; -char GStitle[256]; -GSconf conf; -int ppf; -primInfo *prim; -FILE *gsLog; -int g_GSMultiThreaded = 0; -void (*GSirq)(); -u8* g_pBasePS2Mem = NULL; -int g_TransferredToGPU = 0; -string s_strIniPath="inis/zerogs.ini"; - -static BOOL g_bHidden = 0; -int g_GameSettings = 0; - -// statistics -u32 g_nGenVars = 0, g_nTexVars = 0, g_nAlphaVars = 0, g_nResolve = 0; - -#define VER 96 -const unsigned char zgsversion = PS2E_GS_VERSION; -unsigned char zgsrevision = 0; // revision and build gives plugin version -unsigned char zgsbuild = VER; -unsigned char zgsminor = 7; - -#ifdef _DEBUG -char *libraryName = "ZeroGS-Pg OpenGL (Debug) "; -#elif defined(RELEASE_TO_PUBLIC) -char *libraryName = "ZeroGS Playground OpenGL "; -#else -char *libraryName = "ZeroGS-Pg OpenGL (Dev) "; -#endif - -static const char* s_aa[5] = { "AA none |", "AA 2x |", "AA 4x |", "AA 8x |", "AA 16x |" }; -static const char* pbilinear[] = { "off", "normal", "forced" }; - -extern GIFRegHandler g_GIFPackedRegHandlers[]; -extern GIFRegHandler g_GIFRegHandlers[]; -GIFRegHandler g_GIFTempRegHandlers[16] = {0}; -extern int g_nPixelShaderVer; -extern int g_nFrameRender; -extern int g_nFramesSkipped; - -#ifdef RELEASE_TO_PUBLIC -#define g_bWriteProfile 0 -#else -BOOL g_bWriteProfile = 0; -#endif - -int s_frameskipping = 0; -u32 CALLBACK PS2EgetLibType() { - return PS2E_LT_GS; -} - -char* CALLBACK PS2EgetLibName() { - return libraryName; -} - -u32 CALLBACK PS2EgetLibVersion2(u32 type) { - return (zgsversion<<16) | (zgsrevision<<8) | zgsbuild | (zgsminor << 24); -} - -static u64 luPerfFreq; - -#ifdef _WIN32 - -HWND GShwnd = NULL; - -void SysMessage(char *fmt, ...) { - va_list list; - char tmp[512]; - - va_start(list,fmt); - vsprintf(tmp,fmt,list); - va_end(list); - MessageBox(0, tmp, "GSsoftdx Msg", 0); -} -#else - -GLWindow GLWin; -u32 THR_KeyEvent = 0; // Value for key event processing between threads -bool THR_bShift = false; - -#endif - -void __Log(const char *fmt, ...) { - va_list list; - - // gsLog can be null if the config dialog is used prior to Pcsx2 an emulation session. - // (GSinit won't have been called then) - - if (gsLog == NULL || !conf.log) return; - - va_start(list, fmt); - vfprintf(gsLog, fmt, list); - va_end(list); -} - -void __LogToConsole(const char *fmt, ...) { - va_list list; - - va_start(list, fmt); - - // gsLog can be null if the config dialog is used prior to Pcsx2 an emulation session. - // (GSinit won't have been called then) - - if( gsLog != NULL ) - vfprintf(gsLog, fmt, list); - - printf("ZeroGS: "); - vprintf(fmt, list); - va_end(list); -} - -void CALLBACK GSsetBaseMem(void* pmem) { - g_pBasePS2Mem = (u8*)pmem; -} - -extern int VALIDATE_THRESH; -extern u32 TEXDESTROY_THRESH; -int g_LastCRC = 0; -void CALLBACK GSsetGameCRC(int crc, int options) -{ - VALIDATE_THRESH = 8; - g_GameSettings = conf.gamesettings|options; - conf.mrtdepth = 0;//!(conf.gamesettings&GAME_DISABLEMRTDEPTH); - - if( !conf.mrtdepth ) ERROR_LOG("Disabling MRT depth writing\n"); - - g_GameSettings |= GAME_PATH3HACK; - g_LastCRC = crc; - - switch(crc) { - case 0x54A548B4: // crash n burn - // overbright - break; - - case 0xA3D63039: // xenosaga(j) - case 0x0E7807B2: // xenosaga(u) - g_GameSettings |= GAME_DOPARALLELCTX; - VALIDATE_THRESH = 64; - TEXDESTROY_THRESH = 32; - break; - - case 0x7D2FE035: // espgaluda (j) - VALIDATE_THRESH = 24; - //g_GameSettings |= GAME_BIGVALIDATE; - break; - } -} - -void CALLBACK GSsetFrameSkip(int frameskip) -{ - s_frameskipping |= frameskip; - if( frameskip && g_nFrameRender > 1 ) { - - for(int i = 0; i < 16; ++i) { - g_GIFPackedRegHandlers[i] = GIFPackedRegHandlerNOP; - } - - // still keep certain handlers - g_GIFPackedRegHandlers[6] = GIFRegHandlerTEX0_1; - g_GIFPackedRegHandlers[7] = GIFRegHandlerTEX0_2; - g_GIFPackedRegHandlers[14] = GIFPackedRegHandlerA_D; - - g_GIFRegHandlers[0] = GIFRegHandlerNOP; - g_GIFRegHandlers[1] = GIFRegHandlerNOP; - g_GIFRegHandlers[2] = GIFRegHandlerNOP; - g_GIFRegHandlers[3] = GIFRegHandlerNOP; - g_GIFRegHandlers[4] = GIFRegHandlerNOP; - g_GIFRegHandlers[5] = GIFRegHandlerNOP; - g_GIFRegHandlers[12] = GIFRegHandlerNOP; - g_GIFRegHandlers[13] = GIFRegHandlerNOP; - g_GIFRegHandlers[26] = GIFRegHandlerNOP; - g_GIFRegHandlers[27] = GIFRegHandlerNOP; - g_nFrameRender = 0; - } - else if( !frameskip && g_nFrameRender <= 0 ) { - g_nFrameRender = 1; - - if( g_GIFTempRegHandlers[0] == NULL ) return; // not init yet - - // restore - memcpy(g_GIFPackedRegHandlers, g_GIFTempRegHandlers, sizeof(g_GIFTempRegHandlers)); - - g_GIFRegHandlers[0] = GIFRegHandlerPRIM; - g_GIFRegHandlers[1] = GIFRegHandlerRGBAQ; - g_GIFRegHandlers[2] = GIFRegHandlerST; - g_GIFRegHandlers[3] = GIFRegHandlerUV; - g_GIFRegHandlers[4] = GIFRegHandlerXYZF2; - g_GIFRegHandlers[5] = GIFRegHandlerXYZ2; - g_GIFRegHandlers[12] = GIFRegHandlerXYZF3; - g_GIFRegHandlers[13] = GIFRegHandlerXYZ2; - g_GIFRegHandlers[26] = GIFRegHandlerPRMODECONT; - g_GIFRegHandlers[27] = GIFRegHandlerPRMODE; - } -} - -void CALLBACK GSreset() { - - memset(&gs, 0, sizeof(gs)); - - ZeroGS::GSStateReset(); - - gs.prac = 1; - prim = &gs._prim[0]; - gs.nTriFanVert = -1; - gs.imageTransfer = -1; - gs.q = 1; -} - -void CALLBACK GSgifSoftReset(u32 mask) -{ - if( mask & 1 ) memset(&gs.path1, 0, sizeof(gs.path1)); - if( mask & 2 ) memset(&gs.path2, 0, sizeof(gs.path2)); - if( mask & 4 ) memset(&gs.path3, 0, sizeof(gs.path3)); - gs.imageTransfer = -1; - gs.q = 1; - gs.nTriFanVert = -1; -} - -s32 CALLBACK GSinit() -{ - memcpy(g_GIFTempRegHandlers, g_GIFPackedRegHandlers, sizeof(g_GIFTempRegHandlers)); - -#ifdef GS_LOG - gsLog = fopen("logs/gsLog.txt", "w"); - if (gsLog == NULL) { - gsLog = fopen("gsLog.txt", "w"); - if (gsLog == NULL) { - SysMessage("Can't create gsLog.txt"); return -1; - } - } - setvbuf(gsLog, NULL, _IONBF, 0); - GS_LOG("GSinit\n"); -#endif - -#ifdef __LINUX__ - char strcurdir[256]; - getcwd(strcurdir, 256); - s_strIniPath = strcurdir; - s_strIniPath += "/inis/zerogs.ini"; -#endif - - GSreset(); - GS_LOG("GSinit ok\n"); - return 0; -} - -void CALLBACK GSshutdown() -{ -#ifdef GS_LOG - fclose(gsLog); -#endif -} - -// keyboard functions -void OnKeyboardF5(int shift) -{ - char strtitle[256]; - if( shift ) { - if( g_nPixelShaderVer == SHADER_REDUCED ) { - conf.bilinear = 0; - sprintf(strtitle, "reduced shaders don't support bilinear filtering"); - } - else { - conf.bilinear = (conf.bilinear+1)%3; - sprintf(strtitle, "bilinear filtering - %s", pbilinear[conf.bilinear]); - } - } - else { - conf.interlace++; - if( conf.interlace > 2 ) conf.interlace = 0; - if( conf.interlace < 2 ) sprintf(strtitle, "interlace on - mode %d", conf.interlace); - else sprintf(strtitle, "interlace off"); - } - - ZeroGS::AddMessage(strtitle); - SaveConfig(); -} - -void OnKeyboardF6(int shift) -{ - char strtitle[256]; - if( shift ) { - conf.aa--; // -1 - if( conf.aa > 4 ) conf.aa = 4; // u8 in unsigned, so negative value is 255. - sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa]); - ZeroGS::SetAA(conf.aa); - } - else { - conf.aa++; - if( conf.aa > 4 ) conf.aa = 0; - sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa]); - ZeroGS::SetAA(conf.aa); - } - - ZeroGS::AddMessage(strtitle); - SaveConfig(); -} - -void OnKeyboardF7(int shift) -{ - char strtitle[256]; - if( shift ) { - extern BOOL g_bDisplayFPS; - g_bDisplayFPS ^= 1; - } - else { - conf.options ^= GSOPTION_WIREFRAME; - glPolygonMode(GL_FRONT_AND_BACK, (conf.options&GSOPTION_WIREFRAME)?GL_LINE:GL_FILL); - sprintf(strtitle, "wireframe rendering - %s", (conf.options&GSOPTION_WIREFRAME)?"on":"off"); - } -} - -void OnKeyboardF9(int shift) -{ - char strtitle[256]; - g_GameSettings ^= GAME_PATH3HACK; - sprintf(strtitle, "path3 hack - %s", (g_GameSettings&GAME_PATH3HACK) ? "on" : "off"); - ZeroGS::AddMessage(strtitle); - //SaveConfig(); -} - -#ifdef _WIN32 - -#ifdef _DEBUG -HANDLE g_hCurrentThread = NULL; -#endif - -LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - static int nWindowWidth = 0, nWindowHeight = 0; - - switch( msg ) { - case WM_DESTROY: - PostQuitMessage( 0 ); - return 0; - - case WM_KEYDOWN: -// switch(wParam) { -// case VK_ESCAPE: -// SendMessage(hWnd, WM_DESTROY, 0L, 0L); -// break; -// } - break; - - case WM_ACTIVATE: - - if( wParam != WA_INACTIVE ) { - //DEBUG_LOG("restoring device\n"); - ZeroGS::Restore(); - } - - break; - - case WM_SIZE: - nWindowWidth = lParam&0xffff; - nWindowHeight = lParam>>16; - ZeroGS::ChangeWindowSize(nWindowWidth, nWindowHeight); - - break; - - case WM_SIZING: - // if button is 0, then just released so can resize - if( GetSystemMetrics(SM_SWAPBUTTON) ? !GetAsyncKeyState(VK_RBUTTON) : !GetAsyncKeyState(VK_LBUTTON) ) { - ZeroGS::SetChangeDeviceSize(nWindowWidth, nWindowHeight); - } - break; - - case WM_SETCURSOR: - SetCursor(NULL); - break; - } - - return DefWindowProc( hWnd, msg, wParam, lParam ); -} - -extern HINSTANCE hInst; -void CALLBACK GSconfigure() { - DialogBox(hInst, - MAKEINTRESOURCE(IDD_CONFIG), - GetActiveWindow(), - (DLGPROC)ConfigureDlgProc); - - if( g_nPixelShaderVer == SHADER_REDUCED ) - conf.bilinear = 0; -} - - -s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread) { - - g_GSMultiThreaded = multithread; - - GS_LOG("GSopen\n"); - -#ifdef _DEBUG - g_hCurrentThread = GetCurrentThread(); -#endif - - assert( GSirq != NULL ); - LoadConfig(); - - strcpy(GStitle, Title); - - RECT rc, rcdesktop; - rc.left = 0; rc.top = 0; - rc.right = conf.width; rc.bottom = conf.height; - - WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, - GetModuleHandle(NULL), NULL, NULL, NULL, NULL, - "PS2EMU_ZEROGS", NULL }; - RegisterClassEx( &wc ); - - AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); - - GetWindowRect(GetDesktopWindow(), &rcdesktop); - - GShwnd = CreateWindow( "PS2EMU_ZEROGS", "ZeroGS", WS_OVERLAPPEDWINDOW, - (rcdesktop.right-(rc.right-rc.left))/2, (rcdesktop.bottom-(rc.bottom-rc.top))/2, - rc.right-rc.left, rc.bottom-rc.top, NULL, NULL, wc.hInstance, NULL ); - - if(GShwnd == NULL) { - GS_LOG("Failed to create window. Exiting..."); - return -1; - } - - if( pDsp != NULL ) - *(HWND*)pDsp = GShwnd; - - ERROR_LOG("creating zerogs\n"); - //if (conf.record) recOpen(); - if( !ZeroGS::Create(conf.width, conf.height) ) - return -1; - - ERROR_LOG("initialization successful\n"); - - if( conf.bilinear == 2 ) { - ZeroGS::AddMessage("forced bilinear filtering - on", 1000); - } - else if( conf.bilinear == 1 ) { - ZeroGS::AddMessage("normal bilinear filtering - on", 1000); - } - if( conf.aa ) { - char strtitle[64]; - sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa], 1000); - ZeroGS::AddMessage(strtitle); - } - - // set just in case - SetWindowLongPtr(GShwnd, GWLP_WNDPROC, (LPARAM)(WNDPROC)MsgProc); - - ShowWindow( GShwnd, SW_SHOWDEFAULT ); - UpdateWindow( GShwnd ); - SetFocus(GShwnd); - - conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); - conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style - - GS_LOG("GSopen ok\n"); - - LARGE_INTEGER temp; - QueryPerformanceFrequency(&temp); - luPerfFreq = temp.QuadPart; - - gs.path1.mode = 0; - gs.path2.mode = 0; - gs.path3.mode = 0; - - return 0; -} - -void ProcessMessages() -{ - MSG msg; - ZeroMemory( &msg, sizeof(msg) ); - while( 1 ) { - if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) - { - switch( msg.message ) { - case WM_KEYDOWN : - if( msg.wParam == VK_F5 ) { - OnKeyboardF5(GetKeyState(VK_SHIFT)&0x8000); - } - else if( msg.wParam == VK_F6 ) { - OnKeyboardF6(GetKeyState(VK_SHIFT)&0x8000); - } - else if( msg.wParam == VK_F7 ) { - OnKeyboardF7(GetKeyState(VK_SHIFT)&0x8000); - } - else if( msg.wParam == VK_F9 ) { - OnKeyboardF9(GetKeyState(VK_SHIFT)&0x8000); - } - else if( msg.wParam == VK_ESCAPE ) { - - if( conf.options & GSOPTION_FULLSCREEN ) { - // destroy that msg - conf.options &= ~GSOPTION_FULLSCREEN; - conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); - conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style - ZeroGS::ChangeDeviceSize(conf.width, conf.height); - UpdateWindow(GShwnd); - continue; // so that msg doesn't get sent - } - else { - SendMessage(GShwnd, WM_DESTROY, 0, 0); - g_bHidden = 1; - return; - } - } - - break; - } - - TranslateMessage( &msg ); - DispatchMessage( &msg ); - } - else - break; - } - - if( (GetKeyState(VK_MENU)&0x8000) && (GetKeyState(VK_RETURN)&0x8000) ) { - conf.options ^= GSOPTION_FULLSCREEN; - - if( conf.options & GSOPTION_FULLSCREEN ) { - conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); - conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style - } - - ZeroGS::SetChangeDeviceSize( - (conf.options&GSOPTION_FULLSCREEN) ? 1280 : conf.width, - (conf.options&GSOPTION_FULLSCREEN) ? 960 : conf.height); - } - -// if( conf.fullscreen && (GetKeyState(VK_ESCAPE)&0x8000)) { -// conf.fullscreen &= ~GSOPTION_FULLSCREEN; -// ZeroGS::SetChangeDeviceSize(conf.width, conf.height); -// } - - //if( conf.interlace && g_nGenVars + g_nTexVars + g_nAlphaVars + g_nResolve == 0 ) - // CSR->FIELD = 0; // 0 should always be the repeating at 0 -} - -#else // linux - -s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread) -{ - GS_LOG("GSopen\n"); - - assert( GSirq != NULL ); - LoadConfig(); - - strcpy(GStitle, Title); - - GLWin.dpy = XOpenDisplay(0); - GLWin.screen = DefaultScreen(GLWin.dpy); - - if( pDsp != NULL ) - *(Display**)pDsp = GLWin.dpy; - - ERROR_LOG("creating zerogs\n"); - //if (conf.record) recOpen(); - if( !ZeroGS::Create(conf.width, conf.height) ) - return -1; - - ERROR_LOG("initialization successful\n"); - - if( conf.bilinear == 2 ) { - ZeroGS::AddMessage("bilinear filtering - forced", 1000); - } - else if( conf.bilinear == 1 ) { - ZeroGS::AddMessage("bilinear filtering - normal", 1000); - } - if( conf.aa ) { - char strtitle[64]; - sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa], 1000); - ZeroGS::AddMessage(strtitle); - } - - GS_LOG("GSopen ok\n"); - - gs.path1.mode = 0; - gs.path2.mode = 0; - gs.path3.mode = 0; - luPerfFreq = 1; - - return 0; -} - -void ProcessMessages() -{ - - XEvent event; - // check resizing - while(XCheckTypedEvent(GLWin.dpy, ConfigureNotify, &event)) { - if ((event.xconfigure.width != GLWin.width) || (event.xconfigure.height != GLWin.height)) { - ZeroGS::ChangeWindowSize(event.xconfigure.width, event.xconfigure.height); - GLWin.width = event.xconfigure.width; - GLWin.height = event.xconfigure.height; - } - } - - if ( THR_KeyEvent ) { // This values was passed from GSKeyEvents witch could be in another thread - int my_KeyEvent = THR_KeyEvent; - bool my_bShift = THR_bShift; - THR_KeyEvent = 0; - switch ( my_KeyEvent ) { - case XK_F5: - OnKeyboardF5(my_bShift); - break; - case XK_F6: - OnKeyboardF6(my_bShift); - break; - case XK_F7: - OnKeyboardF7(my_bShift); - break; - case XK_F9: - OnKeyboardF9(my_bShift); - break; - } - } -} - -#endif // linux - -void CALLBACK GSclose() { - ZeroGS::Destroy(1); - -#ifdef _WIN32 - if( GShwnd != NULL ) { - DestroyWindow(GShwnd); - GShwnd = NULL; - } -#else - if( GLWin.dpy != NULL ) { - XCloseDisplay(GLWin.dpy); - GLWin.dpy = NULL; - } -#endif -} - -void CALLBACK GSirqCallback(void (*callback)()) { - GSirq = callback; -} - -void CALLBACK GSwriteCSR(u32 write) -{ - gs.CSRw = write; -} - -void CALLBACK GSchangeSaveState(int newstate, const char* filename) -{ - char str[255]; - sprintf(str, "save state %d", newstate); - ZeroGS::AddMessage(str); -} - -void CALLBACK GSmakeSnapshot(char *path) -{ - FILE *bmpfile; - char filename[256]; - u32 snapshotnr = 0; - - // increment snapshot value & try to get filename - for (;;) { - snapshotnr++; - - sprintf(filename,"%ssnap%03ld.%s", path, snapshotnr, (conf.options&GSOPTION_TGASNAP)?"bmp":"jpg"); - - bmpfile=fopen(filename,"rb"); - if (bmpfile == NULL) break; - fclose(bmpfile); - } - - // try opening new snapshot file - if((bmpfile=fopen(filename,"wb"))==NULL) { - char strdir[255]; - -#ifdef _WIN32 - sprintf(strdir, "%s", path); - CreateDirectory(strdir, NULL); -#else - sprintf(strdir, "mkdir %s", path); - system(strdir); -#endif - - if((bmpfile=fopen(filename,"wb"))==NULL) return; - } - - fclose(bmpfile); - - // get the bits - ZeroGS::SaveSnapshot(filename); -} - -int UPDATE_FRAMES = 16; -int g_nFrame = 0; -int g_nRealFrame = 0; - -float fFPS = 0; - -void CALLBACK GSvsync(int interlace) -{ - GS_LOG("\nGSvsync\n\n"); - - static u32 dwTime = timeGetTime(); - static int nToNextUpdate = 1; - char strtitle[256]; - - GL_REPORT_ERRORD(); - - g_nRealFrame++; - - ZeroGS::RenderCRTC(!interlace); - - ProcessMessages(); - - if( --nToNextUpdate <= 0 ) { - - u32 d = timeGetTime(); - fFPS = UPDATE_FRAMES * 1000.0f / (float)max(d-dwTime,1); - dwTime = d; - g_nFrame += UPDATE_FRAMES; - -#ifdef RELEASE_TO_PUBLIC - const char* g_pShaders[4] = { "full", "reduced", "accurate", "accurate-reduced" }; - - sprintf(strtitle, "ZeroGS KOSMOS 0.%d.%d %.1f fps | %s%s%s%s %s (%.1f)", zgsbuild, zgsminor, fFPS, - (conf.interlace < 2) ? "interlace | " : "", - conf.bilinear ? (conf.bilinear==2?"forced bilinear | ":"bilinear | ") : "", - conf.aa ? s_aa[conf.aa] : "", - (g_GameSettings&GAME_FFXHACK) ? "ffxhack | " : "", - g_pShaders[g_nPixelShaderVer], (ppf&0xfffff)/(float)UPDATE_FRAMES); -#else - sprintf(strtitle, "%d | %.1f fps (sk:%d%%) | g: %.1f, t: %.1f, a: %.1f, r: %.1f | p: %.1f | tex: %d %d (%d kbpf)", g_nFrame, fFPS, - 100*g_nFramesSkipped/g_nFrame, - g_nGenVars/(float)UPDATE_FRAMES, g_nTexVars/(float)UPDATE_FRAMES, g_nAlphaVars/(float)UPDATE_FRAMES, - g_nResolve/(float)UPDATE_FRAMES, (ppf&0xfffff)/(float)UPDATE_FRAMES, - ZeroGS::g_MemTargs.listTargets.size(), ZeroGS::g_MemTargs.listClearedTargets.size(), g_TransferredToGPU>>10); - //_snprintf(strtitle, 512, "%x %x", *(int*)(g_pbyGSMemory + 256 * 0x3e0c + 4), *(int*)(g_pbyGSMemory + 256 * 0x3e04 + 4)); - -#endif - -// if( g_nFrame > 100 && fFPS > 60.0f ) { -// DEBUG_LOG("set profile\n"); -// g_bWriteProfile = 1; -// } - -#ifdef _WIN32 - if( !(conf.options&GSOPTION_FULLSCREEN) ) - SetWindowText(GShwnd, strtitle); -#else // linux - XTextProperty prop; - memset(&prop, 0, sizeof(prop)); - char* ptitle = strtitle; - if( XStringListToTextProperty(&ptitle, 1, &prop) ) - XSetWMName(GLWin.dpy, GLWin.win, &prop); - XFree(prop.value); -#endif - - if( fFPS < 16 ) UPDATE_FRAMES = 4; - else if( fFPS < 32 ) UPDATE_FRAMES = 8; - else UPDATE_FRAMES = 16; - - nToNextUpdate = UPDATE_FRAMES; - - g_TransferredToGPU = 0; - g_nGenVars = 0; - g_nTexVars = 0; - g_nAlphaVars = 0; - g_nResolve = 0; - ppf = 0; - g_nFramesSkipped = 0; - } - -#ifndef RELEASE_TO_PUBLIC - if( g_bWriteProfile ) { - //g_bWriteProfile = 0; - DVProfWrite("prof.txt", UPDATE_FRAMES); - DVProfClear(); - } -#endif - GL_REPORT_ERRORD(); -} - -void GIFtag(pathInfo *path, u32 *data) { - - path->tag.nloop = data[0] & 0x7fff; - path->tag.eop = (data[0] >> 15) & 0x1; - u32 tagpre = (data[1] >> 14) & 0x1; - u32 tagprim = (data[1] >> 15) & 0x7ff; - u32 tagflg = (data[1] >> 26) & 0x3; - path->tag.nreg = (data[1] >> 28)<<2; - - if (path->tag.nreg == 0) path->tag.nreg = 64; - - gs.q = 1; - -// GS_LOG("GIFtag: %8.8lx_%8.8lx_%8.8lx_%8.8lx: EOP=%d, NLOOP=%x, FLG=%x, NREG=%d, PRE=%d\n", -// data[3], data[2], data[1], data[0], -// path->tag.eop, path->tag.nloop, tagflg, path->tag.nreg, tagpre); - - path->mode = tagflg+1; - - switch (tagflg) { - case 0x0: - path->regs = *(u64 *)(data+2); - path->regn = 0; - if (tagpre) - GIFRegHandlerPRIM((u32*)&tagprim); - - break; - - case 0x1: - path->regs = *(u64 *)(data+2); - path->regn = 0; - break; - } -} - -void _GSgifPacket(pathInfo *path, u32 *pMem) { // 128bit - - int reg = (int)((path->regs >> path->regn) & 0xf); - g_GIFPackedRegHandlers[reg](pMem); - - path->regn += 4; - if (path->tag.nreg == path->regn) { - path->regn = 0; - path->tag.nloop--; - } -} - -void _GSgifRegList(pathInfo *path, u32 *pMem) { // 64bit - int reg; - - reg = (int)((path->regs >> path->regn) & 0xf); - - g_GIFRegHandlers[reg](pMem); - path->regn += 4; - if (path->tag.nreg == path->regn) { - path->regn = 0; - path->tag.nloop--; - } -} - -static int nPath3Hack = 0; - -void CALLBACK GSgetLastTag(u64* ptag) -{ - *(u32*)ptag = nPath3Hack; - nPath3Hack = 0; -} - -void _GSgifTransfer(pathInfo *path, u32 *pMem, u32 size) -{ -#ifdef _WIN32 - assert( g_hCurrentThread == GetCurrentThread() ); -#endif - -#ifdef _DEBUG - if( conf.log & 0x20 ) { - static int nSaveIndex=0; - GS_LOG("%d: p:%d %x\n", nSaveIndex++, (path==&gs.path3)?3:(path==&gs.path2?2:1), size); - int vals[4] = {0}; - for(int i = 0; i < size; i++) { - for(int j = 0; j < 4; ++j ) - vals[j] ^= pMem[4*i+j]; - } - GS_LOG("%x %x %x %x\n", vals[0], vals[1], vals[2], vals[3]); - } -#endif - - while(size > 0) - { - //LOG(_T("Transfer(%08x, %d) START\n"), pMem, size); - if (path->tag.nloop == 0) - { - GIFtag(path, pMem); - pMem+= 4; - size--; - - if ((g_GameSettings & GAME_PATH3HACK) && path == &gs.path3 && gs.path3.tag.eop) - nPath3Hack = 1; - - if (path == &gs.path1) - { - // if too much data, just ignore - if (path->tag.nloop * (path->tag.nreg / 4) > (int)size * (path->mode==2?2:1)) - { - static int lasttime = 0; - if( timeGetTime() - lasttime > 5000 ) - { - ERROR_LOG("VU1 too much data, ignore if gfx are fine\n"); - lasttime = timeGetTime(); - } - path->tag.nloop = 0; - return; - } - - if (path->mode == 1) - { - // check if 0xb is in any reg, if yes, exit (kh2) - for(int i = 0; i < path->tag.nreg; i += 4) - { - if (((path->regs >> i)&0xf) == 11) - { - static int lasttime = 0; - if( timeGetTime() - lasttime > 5000 ) - { - ERROR_LOG("Invalid unpack type\n"); - lasttime = timeGetTime(); - } - path->tag.nloop = 0; - return; - } - } - } - } - - if(path->tag.nloop == 0 ) - { - if( path == &gs.path1 ) - { - // ffx hack - if( g_GameSettings & GAME_FFXHACK ) - { - if( path->tag.eop ) - return; - continue; - } - - return; - } - - if( !path->tag.eop ) - { - //DEBUG_LOG("continuing from eop\n"); - continue; - } - - break; - } - } - - switch(path->mode) { - case 1: // PACKED - { - assert( path->tag.nloop > 0 ); - for(; size > 0; size--, pMem += 4) - { - int reg = (int)((path->regs >> path->regn) & 0xf); - - g_GIFPackedRegHandlers[reg](pMem); - - path->regn += 4; - if (path->tag.nreg == path->regn) - { - path->regn = 0; - if( path->tag.nloop-- <= 1 ) - { - size--; - pMem += 4; - break; - } - } - } - break; - } - case 2: // REGLIST - { - //GS_LOG("%8.8x%8.8x %d L\n", ((u32*)&gs.regs)[1], *(u32*)&gs.regs, path->tag.nreg/4); - assert( path->tag.nloop > 0 ); - size *= 2; - for(; size > 0; pMem+= 2, size--) - { - int reg = (int)((path->regs >> path->regn) & 0xf); - g_GIFRegHandlers[reg](pMem); - path->regn += 4; - if (path->tag.nreg == path->regn) - { - path->regn = 0; - if( path->tag.nloop-- <= 1 ) - { - size--; - pMem += 2; - break; - } - } - } - - if( size & 1 ) pMem += 2; - size /= 2; - break; - } - case 3: // GIF_IMAGE (FROM_VFRAM) - case 4: // Used in the DirectX version, so we'll use it here too. - { - if(gs.imageTransfer >= 0 && gs.imageTransfer <= 1) - { - int process = min((int)size, path->tag.nloop); - - if( process > 0 ) - { - if ( gs.imageTransfer ) - ZeroGS::TransferLocalHost(pMem, process); - else - ZeroGS::TransferHostLocal(pMem, process*4); - - path->tag.nloop -= process; - pMem += process*4; size -= process; - - assert( size == 0 || path->tag.nloop == 0 ); - } - break; - } - else - { - // simulate - int process = min((int)size, path->tag.nloop); - path->tag.nloop -= process; - pMem += process*4; size -= process; - } - - break; - } - default: // GIF_IMAGE - GS_LOG("*** WARNING **** Unexpected GIFTag flag\n"); - assert(0); - path->tag.nloop = 0; - break; - } - - if( path == &gs.path1 && path->tag.eop ) - return; - } -} - -void CALLBACK GSgifTransfer2(u32 *pMem, u32 size) -{ - //GS_LOG("GSgifTransfer2 size = %lx (mode %d, gs.path2.tag.nloop = %d)\n", size, gs.path2.mode, gs.path2.tag.nloop); - - _GSgifTransfer(&gs.path2, pMem, size); -} - -void CALLBACK GSgifTransfer3(u32 *pMem, u32 size) -{ - //GS_LOG("GSgifTransfer3 size = %lx (mode %d, gs.path3.tag.nloop = %d)\n", size, gs.path3.mode, gs.path3.tag.nloop); - - nPath3Hack = 0; - _GSgifTransfer(&gs.path3, pMem, size); -} - -static int count = 0; -void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr) -{ - pathInfo *path = &gs.path1; - - //GS_LOG("GSgifTransfer1 0x%x (mode %d)\n", addr, path->mode); - - addr &= 0x3fff; - -#ifdef _DEBUG - PRIM_LOG("count: %d\n", count); - count++; -#endif - - gs.path1.tag.nloop = 0; - gs.path1.tag.eop = 0; - _GSgifTransfer(&gs.path1, (u32*)((u8*)pMem+addr), (0x4000-addr)/16); - - if( !gs.path1.tag.eop && gs.path1.tag.nloop > 0 ) { - assert( (addr&0xf) == 0 ); //BUG - gs.path1.tag.nloop = 0; - ERROR_LOG("Transfer1 - 2\n"); - return; - } -} - -void CALLBACK GSreadFIFO(u64 *pMem) -{ - //GS_LOG("GSreadFIFO\n"); - - ZeroGS::TransferLocalHost((u32*)pMem, 1); -} - -void CALLBACK GSreadFIFO2(u64 *pMem, int qwc) -{ - //GS_LOG("GSreadFIFO2\n"); - - ZeroGS::TransferLocalHost((u32*)pMem, qwc); -} - -int CALLBACK GSsetupRecording(int start, void* pData) -{ - if( start ) { - if( conf.options & GSOPTION_CAPTUREAVI ) - return 1; - ZeroGS::StartCapture(); - conf.options |= GSOPTION_CAPTUREAVI; - WARN_LOG("ZeroGS: started recording at zerogs.avi\n"); - } - else { - if( !(conf.options & GSOPTION_CAPTUREAVI) ) - return 1; - conf.options &= ~GSOPTION_CAPTUREAVI; - ZeroGS::StopCapture(); - WARN_LOG("ZeroGS: stopped recording\n"); - } - - return 1; -} - -s32 CALLBACK GSfreeze(int mode, freezeData *data) -{ - switch (mode) - { - case FREEZE_LOAD: - if (!ZeroGS::Load(data->data)) ERROR_LOG("GS: Bad load format!"); - g_nRealFrame += 100; - break; - case FREEZE_SAVE: - ZeroGS::Save(data->data); - break; - case FREEZE_SIZE: - data->size = ZeroGS::Save(NULL); - break; - default: - break; - } - - return 0; -} - -//////////////////// -// Small profiler // -//////////////////// -#include -#include -#include -using namespace std; - -#ifdef _WIN32 - -__forceinline u64 GET_PROFILE_TIME() -{ - LARGE_INTEGER lu; - QueryPerformanceCounter(&lu); - return lu.QuadPart; -} -#else -#define GET_PROFILE_TIME() //GetCpuTick() -#endif - - -struct DVPROFSTRUCT; - -struct DVPROFSTRUCT -{ - struct DATA - { - DATA(u64 time, u32 user = 0) : dwTime(time), dwUserData(user) {} - DATA() : dwTime(0), dwUserData(0) {} - - u64 dwTime; - u32 dwUserData; - }; - - ~DVPROFSTRUCT() { - list::iterator it = listpChild.begin(); - while(it != listpChild.end() ) { - SAFE_DELETE(*it); - ++it; - } - } - - list listTimes; // before DVProfEnd is called, contains the global time it started - // after DVProfEnd is called, contains the time it lasted - // the list contains all the tracked times - char pname[256]; - - list listpChild; // other profilers called during this profiler period -}; - -struct DVPROFTRACK -{ - u32 dwUserData; - DVPROFSTRUCT::DATA* pdwTime; - DVPROFSTRUCT* pprof; -}; - -list g_listCurTracking; // the current profiling functions, the back element is the - // one that will first get popped off the list when DVProfEnd is called - // the pointer is an element in DVPROFSTRUCT::listTimes -list g_listProfilers; // the current profilers, note that these are the parents - // any profiler started during the time of another is held in - // DVPROFSTRUCT::listpChild -list g_listAllProfilers; // ignores the hierarchy, pointer to elements in g_listProfilers - -void DVProfRegister(char* pname) -{ - if( !g_bWriteProfile ) - return; - - list::iterator it = g_listAllProfilers.begin(); - -// while(it != g_listAllProfilers.end() ) { -// -// if( _tcscmp(pname, (*it)->pname) == 0 ) { -// (*it)->listTimes.push_back(timeGetTime()); -// DVPROFTRACK dvtrack; -// dvtrack.pdwTime = &(*it)->listTimes.back(); -// dvtrack.pprof = *it; -// g_listCurTracking.push_back(dvtrack); -// return; -// } -// -// ++it; -// } - - // else add in a new profiler to the appropriate parent profiler - DVPROFSTRUCT* pprof = NULL; - - if( g_listCurTracking.size() > 0 ) { - assert( g_listCurTracking.back().pprof != NULL ); - g_listCurTracking.back().pprof->listpChild.push_back(new DVPROFSTRUCT()); - pprof = g_listCurTracking.back().pprof->listpChild.back(); - } - else { - g_listProfilers.push_back(DVPROFSTRUCT()); - pprof = &g_listProfilers.back(); - } - - strncpy(pprof->pname, pname, 256); - - // setup the profiler for tracking - pprof->listTimes.push_back(DVPROFSTRUCT::DATA(GET_PROFILE_TIME())); - - DVPROFTRACK dvtrack; - dvtrack.pdwTime = &pprof->listTimes.back(); - dvtrack.pprof = pprof; - dvtrack.dwUserData = 0; - - g_listCurTracking.push_back(dvtrack); - - // add to all profiler list - g_listAllProfilers.push_back(pprof); -} - -void DVProfEnd(u32 dwUserData) -{ - if( !g_bWriteProfile ) - return; - B_RETURN( g_listCurTracking.size() > 0 ); - - DVPROFTRACK dvtrack = g_listCurTracking.back(); - - assert( dvtrack.pdwTime != NULL && dvtrack.pprof != NULL ); - - dvtrack.pdwTime->dwTime = 1000000 * (GET_PROFILE_TIME()- dvtrack.pdwTime->dwTime) / luPerfFreq; - dvtrack.pdwTime->dwUserData= dwUserData; - - g_listCurTracking.pop_back(); -} - -struct DVTIMEINFO -{ - DVTIMEINFO() : uInclusive(0), uExclusive(0) {} - u64 uInclusive, uExclusive; -}; - -map mapAggregateTimes; - -u64 DVProfWriteStruct(FILE* f, DVPROFSTRUCT* p, int ident) -{ - fprintf(f, "%*s%s - ", ident, "", p->pname); - - list::iterator ittime = p->listTimes.begin(); - - u32 utime = 0; - - while(ittime != p->listTimes.end() ) { - utime += (u32)ittime->dwTime; - - if( ittime->dwUserData ) - fprintf(f, "time: %d, user: 0x%8.8x", (u32)ittime->dwTime, ittime->dwUserData); - else - fprintf(f, "time: %d", (u32)ittime->dwTime); - ++ittime; - } - - mapAggregateTimes[p->pname].uInclusive += utime; - - fprintf(f, "\n"); - - list::iterator itprof = p->listpChild.begin(); - - u32 uex = utime; - while(itprof != p->listpChild.end() ) { - - uex -= DVProfWriteStruct(f, *itprof, ident+4); - ++itprof; - } - - mapAggregateTimes[p->pname].uExclusive += uex; - return utime; -} - -void DVProfWrite(char* pfilename, u32 frames) -{ - assert( pfilename != NULL ); - FILE* f = fopen(pfilename, "wb"); - - mapAggregateTimes.clear(); - list::iterator it = g_listProfilers.begin(); - - while(it != g_listProfilers.end() ) { - DVProfWriteStruct(f, &(*it), 0); - ++it; - } - - { - map::iterator it; - fprintf(f, "\n\n-------------------------------------------------------------------\n\n"); - - u64 uTotal[2] = {0}; - double fiTotalTime[2]; - - for(it = mapAggregateTimes.begin(); it != mapAggregateTimes.end(); ++it) { - uTotal[0] += it->second.uExclusive; - uTotal[1] += it->second.uInclusive; - } - - fprintf(f, "total times (%d): ex: %Lu ", frames, uTotal[0]/frames); - fprintf(f, "inc: %Lu\n", uTotal[1]/frames); - - fiTotalTime[0] = 1.0 / (double)uTotal[0]; - fiTotalTime[1] = 1.0 / (double)uTotal[1]; - - // output the combined times - for(it = mapAggregateTimes.begin(); it != mapAggregateTimes.end(); ++it) { - fprintf(f, "%s - ex: %f inc: %f\n", it->first.c_str(), (double)it->second.uExclusive * fiTotalTime[0], - (double)it->second.uInclusive * fiTotalTime[1]); - } - } - - - fclose(f); -} - -void DVProfClear() -{ - g_listCurTracking.clear(); - g_listProfilers.clear(); - g_listAllProfilers.clear(); -} +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ +#if defined(_WIN32) +#include +#include "Win32.h" +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +using namespace std; + +#include "GS.h" +#include "Mem.h" +#include "Regs.h" + +#include "zerogs.h" +#include "targets.h" +#include "ZeroGSShaders/zerogsshaders.h" + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif + +GSinternal gs; +char GStitle[256]; +GSconf conf; +int ppf; +primInfo *prim; +FILE *gsLog; +int g_GSMultiThreaded = 0; +void (*GSirq)(); +u8* g_pBasePS2Mem = NULL; +int g_TransferredToGPU = 0; +string s_strIniPath="inis/zerogs.ini"; + +static BOOL g_bHidden = 0; +int g_GameSettings = 0; + +// statistics +u32 g_nGenVars = 0, g_nTexVars = 0, g_nAlphaVars = 0, g_nResolve = 0; + +#define VER 96 +const unsigned char zgsversion = PS2E_GS_VERSION; +unsigned char zgsrevision = 0; // revision and build gives plugin version +unsigned char zgsbuild = VER; +unsigned char zgsminor = 7; + +#ifdef _DEBUG +char *libraryName = "ZeroGS-Pg OpenGL (Debug) "; +#elif defined(RELEASE_TO_PUBLIC) +char *libraryName = "ZeroGS Playground OpenGL "; +#else +char *libraryName = "ZeroGS-Pg OpenGL (Dev) "; +#endif + +static const char* s_aa[5] = { "AA none |", "AA 2x |", "AA 4x |", "AA 8x |", "AA 16x |" }; +static const char* pbilinear[] = { "off", "normal", "forced" }; + +extern GIFRegHandler g_GIFPackedRegHandlers[]; +extern GIFRegHandler g_GIFRegHandlers[]; +GIFRegHandler g_GIFTempRegHandlers[16] = {0}; +extern int g_nPixelShaderVer; +extern int g_nFrameRender; +extern int g_nFramesSkipped; + +#ifdef RELEASE_TO_PUBLIC +#define g_bWriteProfile 0 +#else +BOOL g_bWriteProfile = 0; +#endif + +int s_frameskipping = 0; +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_GS; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (zgsversion<<16) | (zgsrevision<<8) | zgsbuild | (zgsminor << 24); +} + +static u64 luPerfFreq; + +#ifdef _WIN32 + +HWND GShwnd = NULL; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "GSsoftdx Msg", 0); +} +#else + +GLWindow GLWin; +u32 THR_KeyEvent = 0; // Value for key event processing between threads +bool THR_bShift = false; + +#endif + +void __Log(const char *fmt, ...) { + va_list list; + + // gsLog can be null if the config dialog is used prior to Pcsx2 an emulation session. + // (GSinit won't have been called then) + + if (gsLog == NULL || !conf.log) return; + + va_start(list, fmt); + vfprintf(gsLog, fmt, list); + va_end(list); +} + +void __LogToConsole(const char *fmt, ...) { + va_list list; + + va_start(list, fmt); + + // gsLog can be null if the config dialog is used prior to Pcsx2 an emulation session. + // (GSinit won't have been called then) + + if( gsLog != NULL ) + vfprintf(gsLog, fmt, list); + + printf("ZeroGS: "); + vprintf(fmt, list); + va_end(list); +} + +void CALLBACK GSsetBaseMem(void* pmem) { + g_pBasePS2Mem = (u8*)pmem; +} + +extern int VALIDATE_THRESH; +extern u32 TEXDESTROY_THRESH; +int g_LastCRC = 0; +void CALLBACK GSsetGameCRC(int crc, int options) +{ + VALIDATE_THRESH = 8; + g_GameSettings = conf.gamesettings|options; + conf.mrtdepth = 0;//!(conf.gamesettings&GAME_DISABLEMRTDEPTH); + + if( !conf.mrtdepth ) ERROR_LOG("Disabling MRT depth writing\n"); + + g_GameSettings |= GAME_PATH3HACK; + g_LastCRC = crc; + + switch(crc) { + case 0x54A548B4: // crash n burn + // overbright + break; + + case 0xA3D63039: // xenosaga(j) + case 0x0E7807B2: // xenosaga(u) + g_GameSettings |= GAME_DOPARALLELCTX; + VALIDATE_THRESH = 64; + TEXDESTROY_THRESH = 32; + break; + + case 0x7D2FE035: // espgaluda (j) + VALIDATE_THRESH = 24; + //g_GameSettings |= GAME_BIGVALIDATE; + break; + } +} + +void CALLBACK GSsetFrameSkip(int frameskip) +{ + s_frameskipping |= frameskip; + if( frameskip && g_nFrameRender > 1 ) { + + for(int i = 0; i < 16; ++i) { + g_GIFPackedRegHandlers[i] = GIFPackedRegHandlerNOP; + } + + // still keep certain handlers + g_GIFPackedRegHandlers[6] = GIFRegHandlerTEX0_1; + g_GIFPackedRegHandlers[7] = GIFRegHandlerTEX0_2; + g_GIFPackedRegHandlers[14] = GIFPackedRegHandlerA_D; + + g_GIFRegHandlers[0] = GIFRegHandlerNOP; + g_GIFRegHandlers[1] = GIFRegHandlerNOP; + g_GIFRegHandlers[2] = GIFRegHandlerNOP; + g_GIFRegHandlers[3] = GIFRegHandlerNOP; + g_GIFRegHandlers[4] = GIFRegHandlerNOP; + g_GIFRegHandlers[5] = GIFRegHandlerNOP; + g_GIFRegHandlers[12] = GIFRegHandlerNOP; + g_GIFRegHandlers[13] = GIFRegHandlerNOP; + g_GIFRegHandlers[26] = GIFRegHandlerNOP; + g_GIFRegHandlers[27] = GIFRegHandlerNOP; + g_nFrameRender = 0; + } + else if( !frameskip && g_nFrameRender <= 0 ) { + g_nFrameRender = 1; + + if( g_GIFTempRegHandlers[0] == NULL ) return; // not init yet + + // restore + memcpy(g_GIFPackedRegHandlers, g_GIFTempRegHandlers, sizeof(g_GIFTempRegHandlers)); + + g_GIFRegHandlers[0] = GIFRegHandlerPRIM; + g_GIFRegHandlers[1] = GIFRegHandlerRGBAQ; + g_GIFRegHandlers[2] = GIFRegHandlerST; + g_GIFRegHandlers[3] = GIFRegHandlerUV; + g_GIFRegHandlers[4] = GIFRegHandlerXYZF2; + g_GIFRegHandlers[5] = GIFRegHandlerXYZ2; + g_GIFRegHandlers[12] = GIFRegHandlerXYZF3; + g_GIFRegHandlers[13] = GIFRegHandlerXYZ2; + g_GIFRegHandlers[26] = GIFRegHandlerPRMODECONT; + g_GIFRegHandlers[27] = GIFRegHandlerPRMODE; + } +} + +void CALLBACK GSreset() { + + memset(&gs, 0, sizeof(gs)); + + ZeroGS::GSStateReset(); + + gs.prac = 1; + prim = &gs._prim[0]; + gs.nTriFanVert = -1; + gs.imageTransfer = -1; + gs.q = 1; +} + +void CALLBACK GSgifSoftReset(u32 mask) +{ + if( mask & 1 ) memset(&gs.path1, 0, sizeof(gs.path1)); + if( mask & 2 ) memset(&gs.path2, 0, sizeof(gs.path2)); + if( mask & 4 ) memset(&gs.path3, 0, sizeof(gs.path3)); + gs.imageTransfer = -1; + gs.q = 1; + gs.nTriFanVert = -1; +} + +s32 CALLBACK GSinit() +{ + memcpy(g_GIFTempRegHandlers, g_GIFPackedRegHandlers, sizeof(g_GIFTempRegHandlers)); + +#ifdef GS_LOG + gsLog = fopen("logs/gsLog.txt", "w"); + if (gsLog == NULL) { + gsLog = fopen("gsLog.txt", "w"); + if (gsLog == NULL) { + SysMessage("Can't create gsLog.txt"); return -1; + } + } + setvbuf(gsLog, NULL, _IONBF, 0); + GS_LOG("GSinit\n"); +#endif + +#ifdef __LINUX__ + char strcurdir[256]; + getcwd(strcurdir, 256); + s_strIniPath = strcurdir; + s_strIniPath += "/inis/zerogs.ini"; +#endif + + GSreset(); + GS_LOG("GSinit ok\n"); + return 0; +} + +void CALLBACK GSshutdown() +{ +#ifdef GS_LOG + fclose(gsLog); +#endif +} + +// keyboard functions +void OnKeyboardF5(int shift) +{ + char strtitle[256]; + if( shift ) { + if( g_nPixelShaderVer == SHADER_REDUCED ) { + conf.bilinear = 0; + sprintf(strtitle, "reduced shaders don't support bilinear filtering"); + } + else { + conf.bilinear = (conf.bilinear+1)%3; + sprintf(strtitle, "bilinear filtering - %s", pbilinear[conf.bilinear]); + } + } + else { + conf.interlace++; + if( conf.interlace > 2 ) conf.interlace = 0; + if( conf.interlace < 2 ) sprintf(strtitle, "interlace on - mode %d", conf.interlace); + else sprintf(strtitle, "interlace off"); + } + + ZeroGS::AddMessage(strtitle); + SaveConfig(); +} + +void OnKeyboardF6(int shift) +{ + char strtitle[256]; + if( shift ) { + conf.aa--; // -1 + if( conf.aa > 4 ) conf.aa = 4; // u8 in unsigned, so negative value is 255. + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa]); + ZeroGS::SetAA(conf.aa); + } + else { + conf.aa++; + if( conf.aa > 4 ) conf.aa = 0; + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa]); + ZeroGS::SetAA(conf.aa); + } + + ZeroGS::AddMessage(strtitle); + SaveConfig(); +} + +void OnKeyboardF7(int shift) +{ + char strtitle[256]; + if( shift ) { + extern BOOL g_bDisplayFPS; + g_bDisplayFPS ^= 1; + } + else { + conf.options ^= GSOPTION_WIREFRAME; + glPolygonMode(GL_FRONT_AND_BACK, (conf.options&GSOPTION_WIREFRAME)?GL_LINE:GL_FILL); + sprintf(strtitle, "wireframe rendering - %s", (conf.options&GSOPTION_WIREFRAME)?"on":"off"); + } +} + +void OnKeyboardF9(int shift) +{ + char strtitle[256]; + g_GameSettings ^= GAME_PATH3HACK; + sprintf(strtitle, "path3 hack - %s", (g_GameSettings&GAME_PATH3HACK) ? "on" : "off"); + ZeroGS::AddMessage(strtitle); + //SaveConfig(); +} + +#ifdef _WIN32 + +#ifdef _DEBUG +HANDLE g_hCurrentThread = NULL; +#endif + +LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + static int nWindowWidth = 0, nWindowHeight = 0; + + switch( msg ) { + case WM_DESTROY: + PostQuitMessage( 0 ); + return 0; + + case WM_KEYDOWN: +// switch(wParam) { +// case VK_ESCAPE: +// SendMessage(hWnd, WM_DESTROY, 0L, 0L); +// break; +// } + break; + + case WM_ACTIVATE: + + if( wParam != WA_INACTIVE ) { + //DEBUG_LOG("restoring device\n"); + ZeroGS::Restore(); + } + + break; + + case WM_SIZE: + nWindowWidth = lParam&0xffff; + nWindowHeight = lParam>>16; + ZeroGS::ChangeWindowSize(nWindowWidth, nWindowHeight); + + break; + + case WM_SIZING: + // if button is 0, then just released so can resize + if( GetSystemMetrics(SM_SWAPBUTTON) ? !GetAsyncKeyState(VK_RBUTTON) : !GetAsyncKeyState(VK_LBUTTON) ) { + ZeroGS::SetChangeDeviceSize(nWindowWidth, nWindowHeight); + } + break; + + case WM_SETCURSOR: + SetCursor(NULL); + break; + } + + return DefWindowProc( hWnd, msg, wParam, lParam ); +} + +extern HINSTANCE hInst; +void CALLBACK GSconfigure() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); + + if( g_nPixelShaderVer == SHADER_REDUCED ) + conf.bilinear = 0; +} + + +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread) { + + g_GSMultiThreaded = multithread; + + GS_LOG("GSopen\n"); + +#ifdef _DEBUG + g_hCurrentThread = GetCurrentThread(); +#endif + + assert( GSirq != NULL ); + LoadConfig(); + + strcpy(GStitle, Title); + + RECT rc, rcdesktop; + rc.left = 0; rc.top = 0; + rc.right = conf.width; rc.bottom = conf.height; + + WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, + GetModuleHandle(NULL), NULL, NULL, NULL, NULL, + "PS2EMU_ZEROGS", NULL }; + RegisterClassEx( &wc ); + + AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); + + GetWindowRect(GetDesktopWindow(), &rcdesktop); + + GShwnd = CreateWindow( "PS2EMU_ZEROGS", "ZeroGS", WS_OVERLAPPEDWINDOW, + (rcdesktop.right-(rc.right-rc.left))/2, (rcdesktop.bottom-(rc.bottom-rc.top))/2, + rc.right-rc.left, rc.bottom-rc.top, NULL, NULL, wc.hInstance, NULL ); + + if(GShwnd == NULL) { + GS_LOG("Failed to create window. Exiting..."); + return -1; + } + + if( pDsp != NULL ) + *(HWND*)pDsp = GShwnd; + + ERROR_LOG("creating zerogs\n"); + //if (conf.record) recOpen(); + if( !ZeroGS::Create(conf.width, conf.height) ) + return -1; + + ERROR_LOG("initialization successful\n"); + + if( conf.bilinear == 2 ) { + ZeroGS::AddMessage("forced bilinear filtering - on", 1000); + } + else if( conf.bilinear == 1 ) { + ZeroGS::AddMessage("normal bilinear filtering - on", 1000); + } + if( conf.aa ) { + char strtitle[64]; + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa], 1000); + ZeroGS::AddMessage(strtitle); + } + + // set just in case + SetWindowLongPtr(GShwnd, GWLP_WNDPROC, (LPARAM)(WNDPROC)MsgProc); + + ShowWindow( GShwnd, SW_SHOWDEFAULT ); + UpdateWindow( GShwnd ); + SetFocus(GShwnd); + + conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); + conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style + + GS_LOG("GSopen ok\n"); + + LARGE_INTEGER temp; + QueryPerformanceFrequency(&temp); + luPerfFreq = temp.QuadPart; + + gs.path1.mode = 0; + gs.path2.mode = 0; + gs.path3.mode = 0; + + return 0; +} + +void ProcessMessages() +{ + MSG msg; + ZeroMemory( &msg, sizeof(msg) ); + while( 1 ) { + if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) + { + switch( msg.message ) { + case WM_KEYDOWN : + if( msg.wParam == VK_F5 ) { + OnKeyboardF5(GetKeyState(VK_SHIFT)&0x8000); + } + else if( msg.wParam == VK_F6 ) { + OnKeyboardF6(GetKeyState(VK_SHIFT)&0x8000); + } + else if( msg.wParam == VK_F7 ) { + OnKeyboardF7(GetKeyState(VK_SHIFT)&0x8000); + } + else if( msg.wParam == VK_F9 ) { + OnKeyboardF9(GetKeyState(VK_SHIFT)&0x8000); + } + else if( msg.wParam == VK_ESCAPE ) { + + if( conf.options & GSOPTION_FULLSCREEN ) { + // destroy that msg + conf.options &= ~GSOPTION_FULLSCREEN; + conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); + conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style + ZeroGS::ChangeDeviceSize(conf.width, conf.height); + UpdateWindow(GShwnd); + continue; // so that msg doesn't get sent + } + else { + SendMessage(GShwnd, WM_DESTROY, 0, 0); + g_bHidden = 1; + return; + } + } + + break; + } + + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + else + break; + } + + if( (GetKeyState(VK_MENU)&0x8000) && (GetKeyState(VK_RETURN)&0x8000) ) { + conf.options ^= GSOPTION_FULLSCREEN; + + if( conf.options & GSOPTION_FULLSCREEN ) { + conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); + conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style + } + + ZeroGS::SetChangeDeviceSize( + (conf.options&GSOPTION_FULLSCREEN) ? 1280 : conf.width, + (conf.options&GSOPTION_FULLSCREEN) ? 960 : conf.height); + } + +// if( conf.fullscreen && (GetKeyState(VK_ESCAPE)&0x8000)) { +// conf.fullscreen &= ~GSOPTION_FULLSCREEN; +// ZeroGS::SetChangeDeviceSize(conf.width, conf.height); +// } + + //if( conf.interlace && g_nGenVars + g_nTexVars + g_nAlphaVars + g_nResolve == 0 ) + // CSR->FIELD = 0; // 0 should always be the repeating at 0 +} + +#else // linux + +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread) +{ + GS_LOG("GSopen\n"); + + assert( GSirq != NULL ); + LoadConfig(); + + strcpy(GStitle, Title); + + GLWin.dpy = XOpenDisplay(0); + GLWin.screen = DefaultScreen(GLWin.dpy); + + if( pDsp != NULL ) + *(Display**)pDsp = GLWin.dpy; + + ERROR_LOG("creating zerogs\n"); + //if (conf.record) recOpen(); + if( !ZeroGS::Create(conf.width, conf.height) ) + return -1; + + ERROR_LOG("initialization successful\n"); + + if( conf.bilinear == 2 ) { + ZeroGS::AddMessage("bilinear filtering - forced", 1000); + } + else if( conf.bilinear == 1 ) { + ZeroGS::AddMessage("bilinear filtering - normal", 1000); + } + if( conf.aa ) { + char strtitle[64]; + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa], 1000); + ZeroGS::AddMessage(strtitle); + } + + GS_LOG("GSopen ok\n"); + + gs.path1.mode = 0; + gs.path2.mode = 0; + gs.path3.mode = 0; + luPerfFreq = 1; + + return 0; +} + +void ProcessMessages() +{ + + XEvent event; + // check resizing + while(XCheckTypedEvent(GLWin.dpy, ConfigureNotify, &event)) { + if ((event.xconfigure.width != GLWin.width) || (event.xconfigure.height != GLWin.height)) { + ZeroGS::ChangeWindowSize(event.xconfigure.width, event.xconfigure.height); + GLWin.width = event.xconfigure.width; + GLWin.height = event.xconfigure.height; + } + } + + if ( THR_KeyEvent ) { // This values was passed from GSKeyEvents witch could be in another thread + int my_KeyEvent = THR_KeyEvent; + bool my_bShift = THR_bShift; + THR_KeyEvent = 0; + switch ( my_KeyEvent ) { + case XK_F5: + OnKeyboardF5(my_bShift); + break; + case XK_F6: + OnKeyboardF6(my_bShift); + break; + case XK_F7: + OnKeyboardF7(my_bShift); + break; + case XK_F9: + OnKeyboardF9(my_bShift); + break; + } + } +} + +#endif // linux + +void CALLBACK GSclose() { + ZeroGS::Destroy(1); + +#ifdef _WIN32 + if( GShwnd != NULL ) { + DestroyWindow(GShwnd); + GShwnd = NULL; + } +#else + if( GLWin.dpy != NULL ) { + XCloseDisplay(GLWin.dpy); + GLWin.dpy = NULL; + } +#endif +} + +void CALLBACK GSirqCallback(void (*callback)()) { + GSirq = callback; +} + +void CALLBACK GSwriteCSR(u32 write) +{ + gs.CSRw = write; +} + +void CALLBACK GSchangeSaveState(int newstate, const char* filename) +{ + char str[255]; + sprintf(str, "save state %d", newstate); + ZeroGS::AddMessage(str); +} + +void CALLBACK GSmakeSnapshot(char *path) +{ + FILE *bmpfile; + char filename[256]; + u32 snapshotnr = 0; + + // increment snapshot value & try to get filename + for (;;) { + snapshotnr++; + + sprintf(filename,"%ssnap%03ld.%s", path, snapshotnr, (conf.options&GSOPTION_TGASNAP)?"bmp":"jpg"); + + bmpfile=fopen(filename,"rb"); + if (bmpfile == NULL) break; + fclose(bmpfile); + } + + // try opening new snapshot file + if((bmpfile=fopen(filename,"wb"))==NULL) { + char strdir[255]; + +#ifdef _WIN32 + sprintf(strdir, "%s", path); + CreateDirectory(strdir, NULL); +#else + sprintf(strdir, "mkdir %s", path); + system(strdir); +#endif + + if((bmpfile=fopen(filename,"wb"))==NULL) return; + } + + fclose(bmpfile); + + // get the bits + ZeroGS::SaveSnapshot(filename); +} + +int UPDATE_FRAMES = 16; +int g_nFrame = 0; +int g_nRealFrame = 0; + +float fFPS = 0; + +void CALLBACK GSvsync(int interlace) +{ + GS_LOG("\nGSvsync\n\n"); + + static u32 dwTime = timeGetTime(); + static int nToNextUpdate = 1; + char strtitle[256]; + + GL_REPORT_ERRORD(); + + g_nRealFrame++; + + ZeroGS::RenderCRTC(!interlace); + + ProcessMessages(); + + if( --nToNextUpdate <= 0 ) { + + u32 d = timeGetTime(); + fFPS = UPDATE_FRAMES * 1000.0f / (float)max(d-dwTime,1); + dwTime = d; + g_nFrame += UPDATE_FRAMES; + +#ifdef RELEASE_TO_PUBLIC + const char* g_pShaders[4] = { "full", "reduced", "accurate", "accurate-reduced" }; + + sprintf(strtitle, "ZeroGS KOSMOS 0.%d.%d %.1f fps | %s%s%s%s %s (%.1f)", zgsbuild, zgsminor, fFPS, + (conf.interlace < 2) ? "interlace | " : "", + conf.bilinear ? (conf.bilinear==2?"forced bilinear | ":"bilinear | ") : "", + conf.aa ? s_aa[conf.aa] : "", + (g_GameSettings&GAME_FFXHACK) ? "ffxhack | " : "", + g_pShaders[g_nPixelShaderVer], (ppf&0xfffff)/(float)UPDATE_FRAMES); +#else + sprintf(strtitle, "%d | %.1f fps (sk:%d%%) | g: %.1f, t: %.1f, a: %.1f, r: %.1f | p: %.1f | tex: %d %d (%d kbpf)", g_nFrame, fFPS, + 100*g_nFramesSkipped/g_nFrame, + g_nGenVars/(float)UPDATE_FRAMES, g_nTexVars/(float)UPDATE_FRAMES, g_nAlphaVars/(float)UPDATE_FRAMES, + g_nResolve/(float)UPDATE_FRAMES, (ppf&0xfffff)/(float)UPDATE_FRAMES, + ZeroGS::g_MemTargs.listTargets.size(), ZeroGS::g_MemTargs.listClearedTargets.size(), g_TransferredToGPU>>10); + //_snprintf(strtitle, 512, "%x %x", *(int*)(g_pbyGSMemory + 256 * 0x3e0c + 4), *(int*)(g_pbyGSMemory + 256 * 0x3e04 + 4)); + +#endif + +// if( g_nFrame > 100 && fFPS > 60.0f ) { +// DEBUG_LOG("set profile\n"); +// g_bWriteProfile = 1; +// } + +#ifdef _WIN32 + if( !(conf.options&GSOPTION_FULLSCREEN) ) + SetWindowText(GShwnd, strtitle); +#else // linux + XTextProperty prop; + memset(&prop, 0, sizeof(prop)); + char* ptitle = strtitle; + if( XStringListToTextProperty(&ptitle, 1, &prop) ) + XSetWMName(GLWin.dpy, GLWin.win, &prop); + XFree(prop.value); +#endif + + if( fFPS < 16 ) UPDATE_FRAMES = 4; + else if( fFPS < 32 ) UPDATE_FRAMES = 8; + else UPDATE_FRAMES = 16; + + nToNextUpdate = UPDATE_FRAMES; + + g_TransferredToGPU = 0; + g_nGenVars = 0; + g_nTexVars = 0; + g_nAlphaVars = 0; + g_nResolve = 0; + ppf = 0; + g_nFramesSkipped = 0; + } + +#ifndef RELEASE_TO_PUBLIC + if( g_bWriteProfile ) { + //g_bWriteProfile = 0; + DVProfWrite("prof.txt", UPDATE_FRAMES); + DVProfClear(); + } +#endif + GL_REPORT_ERRORD(); +} + +void GIFtag(pathInfo *path, u32 *data) { + + path->tag.nloop = data[0] & 0x7fff; + path->tag.eop = (data[0] >> 15) & 0x1; + u32 tagpre = (data[1] >> 14) & 0x1; + u32 tagprim = (data[1] >> 15) & 0x7ff; + u32 tagflg = (data[1] >> 26) & 0x3; + path->tag.nreg = (data[1] >> 28)<<2; + + if (path->tag.nreg == 0) path->tag.nreg = 64; + + gs.q = 1; + +// GS_LOG("GIFtag: %8.8lx_%8.8lx_%8.8lx_%8.8lx: EOP=%d, NLOOP=%x, FLG=%x, NREG=%d, PRE=%d\n", +// data[3], data[2], data[1], data[0], +// path->tag.eop, path->tag.nloop, tagflg, path->tag.nreg, tagpre); + + path->mode = tagflg+1; + + switch (tagflg) { + case 0x0: + path->regs = *(u64 *)(data+2); + path->regn = 0; + if (tagpre) + GIFRegHandlerPRIM((u32*)&tagprim); + + break; + + case 0x1: + path->regs = *(u64 *)(data+2); + path->regn = 0; + break; + } +} + +void _GSgifPacket(pathInfo *path, u32 *pMem) { // 128bit + + int reg = (int)((path->regs >> path->regn) & 0xf); + g_GIFPackedRegHandlers[reg](pMem); + + path->regn += 4; + if (path->tag.nreg == path->regn) { + path->regn = 0; + path->tag.nloop--; + } +} + +void _GSgifRegList(pathInfo *path, u32 *pMem) { // 64bit + int reg; + + reg = (int)((path->regs >> path->regn) & 0xf); + + g_GIFRegHandlers[reg](pMem); + path->regn += 4; + if (path->tag.nreg == path->regn) { + path->regn = 0; + path->tag.nloop--; + } +} + +static int nPath3Hack = 0; + +void CALLBACK GSgetLastTag(u64* ptag) +{ + *(u32*)ptag = nPath3Hack; + nPath3Hack = 0; +} + +void _GSgifTransfer(pathInfo *path, u32 *pMem, u32 size) +{ +#ifdef _WIN32 + assert( g_hCurrentThread == GetCurrentThread() ); +#endif + +#ifdef _DEBUG + if( conf.log & 0x20 ) { + static int nSaveIndex=0; + GS_LOG("%d: p:%d %x\n", nSaveIndex++, (path==&gs.path3)?3:(path==&gs.path2?2:1), size); + int vals[4] = {0}; + for(int i = 0; i < size; i++) { + for(int j = 0; j < 4; ++j ) + vals[j] ^= pMem[4*i+j]; + } + GS_LOG("%x %x %x %x\n", vals[0], vals[1], vals[2], vals[3]); + } +#endif + + while(size > 0) + { + //LOG(_T("Transfer(%08x, %d) START\n"), pMem, size); + if (path->tag.nloop == 0) + { + GIFtag(path, pMem); + pMem+= 4; + size--; + + if ((g_GameSettings & GAME_PATH3HACK) && path == &gs.path3 && gs.path3.tag.eop) + nPath3Hack = 1; + + if (path == &gs.path1) + { + // if too much data, just ignore + if (path->tag.nloop * (path->tag.nreg / 4) > (int)size * (path->mode==2?2:1)) + { + static int lasttime = 0; + if( timeGetTime() - lasttime > 5000 ) + { + ERROR_LOG("VU1 too much data, ignore if gfx are fine\n"); + lasttime = timeGetTime(); + } + path->tag.nloop = 0; + return; + } + + if (path->mode == 1) + { + // check if 0xb is in any reg, if yes, exit (kh2) + for(int i = 0; i < path->tag.nreg; i += 4) + { + if (((path->regs >> i)&0xf) == 11) + { + static int lasttime = 0; + if( timeGetTime() - lasttime > 5000 ) + { + ERROR_LOG("Invalid unpack type\n"); + lasttime = timeGetTime(); + } + path->tag.nloop = 0; + return; + } + } + } + } + + if(path->tag.nloop == 0 ) + { + if( path == &gs.path1 ) + { + // ffx hack + if( g_GameSettings & GAME_FFXHACK ) + { + if( path->tag.eop ) + return; + continue; + } + + return; + } + + if( !path->tag.eop ) + { + //DEBUG_LOG("continuing from eop\n"); + continue; + } + + break; + } + } + + switch(path->mode) { + case 1: // PACKED + { + assert( path->tag.nloop > 0 ); + for(; size > 0; size--, pMem += 4) + { + int reg = (int)((path->regs >> path->regn) & 0xf); + + g_GIFPackedRegHandlers[reg](pMem); + + path->regn += 4; + if (path->tag.nreg == path->regn) + { + path->regn = 0; + if( path->tag.nloop-- <= 1 ) + { + size--; + pMem += 4; + break; + } + } + } + break; + } + case 2: // REGLIST + { + //GS_LOG("%8.8x%8.8x %d L\n", ((u32*)&gs.regs)[1], *(u32*)&gs.regs, path->tag.nreg/4); + assert( path->tag.nloop > 0 ); + size *= 2; + for(; size > 0; pMem+= 2, size--) + { + int reg = (int)((path->regs >> path->regn) & 0xf); + g_GIFRegHandlers[reg](pMem); + path->regn += 4; + if (path->tag.nreg == path->regn) + { + path->regn = 0; + if( path->tag.nloop-- <= 1 ) + { + size--; + pMem += 2; + break; + } + } + } + + if( size & 1 ) pMem += 2; + size /= 2; + break; + } + case 3: // GIF_IMAGE (FROM_VFRAM) + case 4: // Used in the DirectX version, so we'll use it here too. + { + if(gs.imageTransfer >= 0 && gs.imageTransfer <= 1) + { + int process = min((int)size, path->tag.nloop); + + if( process > 0 ) + { + if ( gs.imageTransfer ) + ZeroGS::TransferLocalHost(pMem, process); + else + ZeroGS::TransferHostLocal(pMem, process*4); + + path->tag.nloop -= process; + pMem += process*4; size -= process; + + assert( size == 0 || path->tag.nloop == 0 ); + } + break; + } + else + { + // simulate + int process = min((int)size, path->tag.nloop); + path->tag.nloop -= process; + pMem += process*4; size -= process; + } + + break; + } + default: // GIF_IMAGE + GS_LOG("*** WARNING **** Unexpected GIFTag flag\n"); + assert(0); + path->tag.nloop = 0; + break; + } + + if( path == &gs.path1 && path->tag.eop ) + return; + } +} + +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size) +{ + //GS_LOG("GSgifTransfer2 size = %lx (mode %d, gs.path2.tag.nloop = %d)\n", size, gs.path2.mode, gs.path2.tag.nloop); + + _GSgifTransfer(&gs.path2, pMem, size); +} + +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size) +{ + //GS_LOG("GSgifTransfer3 size = %lx (mode %d, gs.path3.tag.nloop = %d)\n", size, gs.path3.mode, gs.path3.tag.nloop); + + nPath3Hack = 0; + _GSgifTransfer(&gs.path3, pMem, size); +} + +static int count = 0; +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr) +{ + pathInfo *path = &gs.path1; + + //GS_LOG("GSgifTransfer1 0x%x (mode %d)\n", addr, path->mode); + + addr &= 0x3fff; + +#ifdef _DEBUG + PRIM_LOG("count: %d\n", count); + count++; +#endif + + gs.path1.tag.nloop = 0; + gs.path1.tag.eop = 0; + _GSgifTransfer(&gs.path1, (u32*)((u8*)pMem+addr), (0x4000-addr)/16); + + if( !gs.path1.tag.eop && gs.path1.tag.nloop > 0 ) { + assert( (addr&0xf) == 0 ); //BUG + gs.path1.tag.nloop = 0; + ERROR_LOG("Transfer1 - 2\n"); + return; + } +} + +void CALLBACK GSreadFIFO(u64 *pMem) +{ + //GS_LOG("GSreadFIFO\n"); + + ZeroGS::TransferLocalHost((u32*)pMem, 1); +} + +void CALLBACK GSreadFIFO2(u64 *pMem, int qwc) +{ + //GS_LOG("GSreadFIFO2\n"); + + ZeroGS::TransferLocalHost((u32*)pMem, qwc); +} + +int CALLBACK GSsetupRecording(int start, void* pData) +{ + if( start ) { + if( conf.options & GSOPTION_CAPTUREAVI ) + return 1; + ZeroGS::StartCapture(); + conf.options |= GSOPTION_CAPTUREAVI; + WARN_LOG("ZeroGS: started recording at zerogs.avi\n"); + } + else { + if( !(conf.options & GSOPTION_CAPTUREAVI) ) + return 1; + conf.options &= ~GSOPTION_CAPTUREAVI; + ZeroGS::StopCapture(); + WARN_LOG("ZeroGS: stopped recording\n"); + } + + return 1; +} + +s32 CALLBACK GSfreeze(int mode, freezeData *data) +{ + switch (mode) + { + case FREEZE_LOAD: + if (!ZeroGS::Load(data->data)) ERROR_LOG("GS: Bad load format!"); + g_nRealFrame += 100; + break; + case FREEZE_SAVE: + ZeroGS::Save(data->data); + break; + case FREEZE_SIZE: + data->size = ZeroGS::Save(NULL); + break; + default: + break; + } + + return 0; +} + +//////////////////// +// Small profiler // +//////////////////// +#include +#include +#include +using namespace std; + +#ifdef _WIN32 + +__forceinline u64 GET_PROFILE_TIME() +{ + LARGE_INTEGER lu; + QueryPerformanceCounter(&lu); + return lu.QuadPart; +} +#else +#define GET_PROFILE_TIME() //GetCpuTick() +#endif + + +struct DVPROFSTRUCT; + +struct DVPROFSTRUCT +{ + struct DATA + { + DATA(u64 time, u32 user = 0) : dwTime(time), dwUserData(user) {} + DATA() : dwTime(0), dwUserData(0) {} + + u64 dwTime; + u32 dwUserData; + }; + + ~DVPROFSTRUCT() { + list::iterator it = listpChild.begin(); + while(it != listpChild.end() ) { + SAFE_DELETE(*it); + ++it; + } + } + + list listTimes; // before DVProfEnd is called, contains the global time it started + // after DVProfEnd is called, contains the time it lasted + // the list contains all the tracked times + char pname[256]; + + list listpChild; // other profilers called during this profiler period +}; + +struct DVPROFTRACK +{ + u32 dwUserData; + DVPROFSTRUCT::DATA* pdwTime; + DVPROFSTRUCT* pprof; +}; + +list g_listCurTracking; // the current profiling functions, the back element is the + // one that will first get popped off the list when DVProfEnd is called + // the pointer is an element in DVPROFSTRUCT::listTimes +list g_listProfilers; // the current profilers, note that these are the parents + // any profiler started during the time of another is held in + // DVPROFSTRUCT::listpChild +list g_listAllProfilers; // ignores the hierarchy, pointer to elements in g_listProfilers + +void DVProfRegister(char* pname) +{ + if( !g_bWriteProfile ) + return; + + list::iterator it = g_listAllProfilers.begin(); + +// while(it != g_listAllProfilers.end() ) { +// +// if( _tcscmp(pname, (*it)->pname) == 0 ) { +// (*it)->listTimes.push_back(timeGetTime()); +// DVPROFTRACK dvtrack; +// dvtrack.pdwTime = &(*it)->listTimes.back(); +// dvtrack.pprof = *it; +// g_listCurTracking.push_back(dvtrack); +// return; +// } +// +// ++it; +// } + + // else add in a new profiler to the appropriate parent profiler + DVPROFSTRUCT* pprof = NULL; + + if( g_listCurTracking.size() > 0 ) { + assert( g_listCurTracking.back().pprof != NULL ); + g_listCurTracking.back().pprof->listpChild.push_back(new DVPROFSTRUCT()); + pprof = g_listCurTracking.back().pprof->listpChild.back(); + } + else { + g_listProfilers.push_back(DVPROFSTRUCT()); + pprof = &g_listProfilers.back(); + } + + strncpy(pprof->pname, pname, 256); + + // setup the profiler for tracking + pprof->listTimes.push_back(DVPROFSTRUCT::DATA(GET_PROFILE_TIME())); + + DVPROFTRACK dvtrack; + dvtrack.pdwTime = &pprof->listTimes.back(); + dvtrack.pprof = pprof; + dvtrack.dwUserData = 0; + + g_listCurTracking.push_back(dvtrack); + + // add to all profiler list + g_listAllProfilers.push_back(pprof); +} + +void DVProfEnd(u32 dwUserData) +{ + if( !g_bWriteProfile ) + return; + B_RETURN( g_listCurTracking.size() > 0 ); + + DVPROFTRACK dvtrack = g_listCurTracking.back(); + + assert( dvtrack.pdwTime != NULL && dvtrack.pprof != NULL ); + + dvtrack.pdwTime->dwTime = 1000000 * (GET_PROFILE_TIME()- dvtrack.pdwTime->dwTime) / luPerfFreq; + dvtrack.pdwTime->dwUserData= dwUserData; + + g_listCurTracking.pop_back(); +} + +struct DVTIMEINFO +{ + DVTIMEINFO() : uInclusive(0), uExclusive(0) {} + u64 uInclusive, uExclusive; +}; + +map mapAggregateTimes; + +u64 DVProfWriteStruct(FILE* f, DVPROFSTRUCT* p, int ident) +{ + fprintf(f, "%*s%s - ", ident, "", p->pname); + + list::iterator ittime = p->listTimes.begin(); + + u32 utime = 0; + + while(ittime != p->listTimes.end() ) { + utime += (u32)ittime->dwTime; + + if( ittime->dwUserData ) + fprintf(f, "time: %d, user: 0x%8.8x", (u32)ittime->dwTime, ittime->dwUserData); + else + fprintf(f, "time: %d", (u32)ittime->dwTime); + ++ittime; + } + + mapAggregateTimes[p->pname].uInclusive += utime; + + fprintf(f, "\n"); + + list::iterator itprof = p->listpChild.begin(); + + u32 uex = utime; + while(itprof != p->listpChild.end() ) { + + uex -= DVProfWriteStruct(f, *itprof, ident+4); + ++itprof; + } + + mapAggregateTimes[p->pname].uExclusive += uex; + return utime; +} + +void DVProfWrite(char* pfilename, u32 frames) +{ + assert( pfilename != NULL ); + FILE* f = fopen(pfilename, "wb"); + + mapAggregateTimes.clear(); + list::iterator it = g_listProfilers.begin(); + + while(it != g_listProfilers.end() ) { + DVProfWriteStruct(f, &(*it), 0); + ++it; + } + + { + map::iterator it; + fprintf(f, "\n\n-------------------------------------------------------------------\n\n"); + + u64 uTotal[2] = {0}; + double fiTotalTime[2]; + + for(it = mapAggregateTimes.begin(); it != mapAggregateTimes.end(); ++it) { + uTotal[0] += it->second.uExclusive; + uTotal[1] += it->second.uInclusive; + } + + fprintf(f, "total times (%d): ex: %Lu ", frames, uTotal[0]/frames); + fprintf(f, "inc: %Lu\n", uTotal[1]/frames); + + fiTotalTime[0] = 1.0 / (double)uTotal[0]; + fiTotalTime[1] = 1.0 / (double)uTotal[1]; + + // output the combined times + for(it = mapAggregateTimes.begin(); it != mapAggregateTimes.end(); ++it) { + fprintf(f, "%s - ex: %f inc: %f\n", it->first.c_str(), (double)it->second.uExclusive * fiTotalTime[0], + (double)it->second.uInclusive * fiTotalTime[1]); + } + } + + + fclose(f); +} + +void DVProfClear() +{ + g_listCurTracking.clear(); + g_listProfilers.clear(); + g_listAllProfilers.clear(); +} diff --git a/plugins/zerogs/opengl/Linux/Conf.cpp b/plugins/zerogs/opengl/Linux/Conf.cpp index 23cf91b75a..75e75a715a 100644 --- a/plugins/zerogs/opengl/Linux/Conf.cpp +++ b/plugins/zerogs/opengl/Linux/Conf.cpp @@ -1,114 +1,114 @@ -/* GSsoft - * Copyright (C) 2002-2004 GSsoft 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include "GS.h" - -extern string s_strIniPath; - -void SaveConfig() -{ - FILE *f; - char cfg[255]; - - strcpy(cfg, s_strIniPath.c_str()); - f = fopen(cfg,"w"); - if (f == NULL) - { - printf("failed to open %s\n", s_strIniPath.c_str()); - return; - } - - fprintf(f, "interlace = %x\n", conf.interlace); - fprintf(f, "mrtdepth = %x\n", conf.mrtdepth); - fprintf(f, "options = %x\n", conf.options); - fprintf(f, "bilinear = %x\n", conf.bilinear); - fprintf(f, "aliasing = %x\n", conf.aa); - fprintf(f, "gamesettings = %x\n", conf.gamesettings); - fclose(f); -} - -void LoadConfig() -{ - FILE *f; - char cfg[255]; - - memset(&conf, 0, sizeof(conf)); - conf.interlace = 0; // on, mode 1 - conf.mrtdepth = 1; - conf.options = 0; - conf.bilinear = 1; - conf.width = 640; - conf.height = 480; - conf.aa = 0; - - strcpy(cfg, s_strIniPath.c_str()); - f = fopen(cfg, "r"); - if (f == NULL) - { - printf("failed to open %s\n", s_strIniPath.c_str()); - SaveConfig();//save and return - return; - } - fscanf(f, "interlace = %x\n", &conf.interlace); - fscanf(f, "mrtdepth = %x\n", &conf.mrtdepth); - fscanf(f, "options = %x\n", &conf.options); - fscanf(f, "bilinear = %x\n", &conf.bilinear); - fscanf(f, "aliasing = %x\n", &conf.aa); - fscanf(f, "gamesettings = %x\n", &conf.gamesettings); - fclose(f); - - // filter bad files - if ((conf.aa < 0) || (conf.aa > 4)) conf.aa = 0; - - switch(conf.options & GSOPTION_WINDIMS) - { - case GSOPTION_WIN640: - conf.width = 640; - conf.height = 480; - break; - case GSOPTION_WIN800: - conf.width = 800; - conf.height = 600; - break; - case GSOPTION_WIN1024: - conf.width = 1024; - conf.height = 768; - break; - case GSOPTION_WIN1280: - conf.width = 1280; - conf.height = 960; - break; - } - - // turn off all hacks by default - conf.options &= ~(GSOPTION_FULLSCREEN | GSOPTION_WIREFRAME | GSOPTION_CAPTUREAVI); - conf.options |= GSOPTION_LOADED; - - if( conf.width <= 0 || conf.height <= 0 ) - { - conf.width = 640; - conf.height = 480; - } -} - +/* GSsoft + * Copyright (C) 2002-2004 GSsoft 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include "GS.h" + +extern string s_strIniPath; + +void SaveConfig() +{ + FILE *f; + char cfg[255]; + + strcpy(cfg, s_strIniPath.c_str()); + f = fopen(cfg,"w"); + if (f == NULL) + { + printf("failed to open %s\n", s_strIniPath.c_str()); + return; + } + + fprintf(f, "interlace = %x\n", conf.interlace); + fprintf(f, "mrtdepth = %x\n", conf.mrtdepth); + fprintf(f, "options = %x\n", conf.options); + fprintf(f, "bilinear = %x\n", conf.bilinear); + fprintf(f, "aliasing = %x\n", conf.aa); + fprintf(f, "gamesettings = %x\n", conf.gamesettings); + fclose(f); +} + +void LoadConfig() +{ + FILE *f; + char cfg[255]; + + memset(&conf, 0, sizeof(conf)); + conf.interlace = 0; // on, mode 1 + conf.mrtdepth = 1; + conf.options = 0; + conf.bilinear = 1; + conf.width = 640; + conf.height = 480; + conf.aa = 0; + + strcpy(cfg, s_strIniPath.c_str()); + f = fopen(cfg, "r"); + if (f == NULL) + { + printf("failed to open %s\n", s_strIniPath.c_str()); + SaveConfig();//save and return + return; + } + fscanf(f, "interlace = %x\n", &conf.interlace); + fscanf(f, "mrtdepth = %x\n", &conf.mrtdepth); + fscanf(f, "options = %x\n", &conf.options); + fscanf(f, "bilinear = %x\n", &conf.bilinear); + fscanf(f, "aliasing = %x\n", &conf.aa); + fscanf(f, "gamesettings = %x\n", &conf.gamesettings); + fclose(f); + + // filter bad files + if ((conf.aa < 0) || (conf.aa > 4)) conf.aa = 0; + + switch(conf.options & GSOPTION_WINDIMS) + { + case GSOPTION_WIN640: + conf.width = 640; + conf.height = 480; + break; + case GSOPTION_WIN800: + conf.width = 800; + conf.height = 600; + break; + case GSOPTION_WIN1024: + conf.width = 1024; + conf.height = 768; + break; + case GSOPTION_WIN1280: + conf.width = 1280; + conf.height = 960; + break; + } + + // turn off all hacks by default + conf.options &= ~(GSOPTION_FULLSCREEN | GSOPTION_WIREFRAME | GSOPTION_CAPTUREAVI); + conf.options |= GSOPTION_LOADED; + + if( conf.width <= 0 || conf.height <= 0 ) + { + conf.width = 640; + conf.height = 480; + } +} + diff --git a/plugins/zerogs/opengl/Linux/Linux.cpp b/plugins/zerogs/opengl/Linux/Linux.cpp index 88f81d61c0..3ce41ec09b 100644 --- a/plugins/zerogs/opengl/Linux/Linux.cpp +++ b/plugins/zerogs/opengl/Linux/Linux.cpp @@ -1,430 +1,430 @@ -/* ZeroGS - * Copyright (C) 2002-2004 GSsoft 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include - -#include "GS.h" - -extern "C" { -#include "interface.h" -#include "support.h" -#include "callbacks.h" -} - -#include "Linux.h" - -#include - -static int prevbilinearfilter; -//static map mapConfOpts; -struct confOptsStruct -{ - int value; - const char *desc; -}confOpts; - -static map mapConfOpts; - -extern void OnKeyboardF5(int); -extern void OnKeyboardF6(int); -extern void OnKeyboardF7(int); -extern void OnKeyboardF9(int); - -GtkWidget *About; - -void CALLBACK GSkeyEvent(keyEvent *ev) -{ - //static bool bShift = false; - static bool bAlt = false; - - switch(ev->evt) { - case KEYPRESS: - switch(ev->key) { - case XK_F5: - case XK_F6: - case XK_F7: - case XK_F9: - THR_KeyEvent = ev->key ; - break; - case XK_Escape: - break; - case XK_Shift_L: - case XK_Shift_R: - //bShift = true; - THR_bShift = true; - break; - case XK_Alt_L: - case XK_Alt_R: - bAlt = true; - break; - } - break; - case KEYRELEASE: - switch(ev->key) { - case XK_Shift_L: - case XK_Shift_R: - //bShift = false; - THR_bShift = false; - break; - case XK_Alt_L: - case XK_Alt_R: - bAlt = false; - break; - } - } -} - -GtkWidget *Conf; -GtkWidget *Logging; -GList *fresl; -GList *wresl; -GList *cachesizel; -GList *codecl; -GList *filtersl; - -void OnConf_Ok(GtkButton *button, gpointer user_data) -{ - GtkWidget *Btn; - GtkWidget *treeview; - GtkTreeModel *treemodel; - GtkTreeIter treeiter; - gboolean treeoptval; - gchar *gbuf; - char *str; - int i; - - u32 newinterlace = is_checked(Conf, "checkInterlace"); - - if (!conf.interlace ) - conf.interlace = newinterlace; - else if (!newinterlace ) - conf.interlace = 2; // off - - conf.bilinear = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkBilinear"))); - // restore - if (conf.bilinear && prevbilinearfilter) - conf.bilinear = prevbilinearfilter; - - //conf.mrtdepth = 1;//IsDlgButtonChecked(hW, IDC_CONFIG_DEPTHWRITE); - - if is_checked(Conf, "radioAANone") - conf.aa = 0; - else if is_checked(Conf, "radioAA2X") - conf.aa = 1; - else if is_checked(Conf, "radioAA4X") - conf.aa = 2; - else if is_checked(Conf, "radioAA8X") - conf.aa = 3; - else - conf.aa = 4; - - conf.options = 0; - conf.options |= is_checked(Conf, "checkAVI") ? GSOPTION_CAPTUREAVI : 0; - conf.options |= is_checked(Conf, "checkWireframe") ? GSOPTION_WIREFRAME : 0; - conf.options |= is_checked(Conf, "checkfullscreen") ? GSOPTION_FULLSCREEN : 0; - conf.options |= is_checked(Conf, "checkTGA") ? GSOPTION_TGASNAP : 0; - - //------- get advanced options from the treeview model -------// - treeview = lookup_widget(Conf,"treeview1"); - treemodel = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)); - gtk_tree_model_get_iter_first(treemodel, &treeiter); - - conf.gamesettings = 0; - for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) - { - treeoptval = FALSE; - gtk_tree_model_get(treemodel, &treeiter, 0, &treeoptval, -1); - - if(treeoptval) conf.gamesettings |= it->second.value; - - gtk_tree_model_iter_next(treemodel,&treeiter); - } - - GSsetGameCRC(0, conf.gamesettings); - //---------- done getting advanced options ---------// - - if is_checked(Conf, "radioSize640") - conf.options |= GSOPTION_WIN640; - else if is_checked(Conf, "radioSize800") - conf.options |= GSOPTION_WIN800; - else if is_checked(Conf, "radioSize1024") - conf.options |= GSOPTION_WIN1024; - else if is_checked(Conf, "radioSize1280") - conf.options |= GSOPTION_WIN1280; - - SaveConfig(); - - gtk_widget_destroy(Conf); - gtk_main_quit(); -} - -void OnConf_Cancel(GtkButton *button, gpointer user_data) -{ - gtk_widget_destroy(Conf); - gtk_main_quit(); -} - -void CALLBACK GSconfigure() -{ - char name[32]; - char descbuf[255]; - int nmodes, i; - bool itval; - GtkWidget *treeview; - GtkCellRenderer *treerend; - GtkListStore *treestore;//Gets typecast as GtkTreeModel as needed. - GtkTreeIter treeiter; - GtkTreeViewColumn *treecol; - - if (!(conf.options & GSOPTION_LOADED)) LoadConfig(); - Conf = create_Config(); - - set_checked(Conf, "checkBilinear", !!conf.bilinear); - //set_checked(Conf, "checkbutton6", conf.mrtdepth); - set_checked(Conf, "radioAANone", conf.aa==0); - set_checked(Conf, "radioAA2X", conf.aa==1); - set_checked(Conf, "radioAA4X", conf.aa==2); - set_checked(Conf, "radioAA8X", conf.aa==3); - set_checked(Conf, "radioAA16X", conf.aa==4); - set_checked(Conf, "checkWireframe", (conf.options&GSOPTION_WIREFRAME)?1:0); - set_checked(Conf, "checkAVI", (conf.options&GSOPTION_CAPTUREAVI)?1:0); - set_checked(Conf, "checkfullscreen", (conf.options&GSOPTION_FULLSCREEN)?1:0); - set_checked(Conf, "checkTGA", (conf.options&GSOPTION_TGASNAP)?1:0); - - set_checked(Conf, "radioSize640", ((conf.options&GSOPTION_WINDIMS)>>4)==0); - set_checked(Conf, "radioSize800", ((conf.options&GSOPTION_WINDIMS)>>4)==1); - set_checked(Conf, "radioSize1024", ((conf.options&GSOPTION_WINDIMS)>>4)==2); - set_checked(Conf, "radioSize1280", ((conf.options&GSOPTION_WINDIMS)>>4)==3); - - prevbilinearfilter = conf.bilinear; - - //--------- Let's build a treeview for our advanced options! --------// - treeview = lookup_widget(Conf,"treeview1"); - treestore = gtk_list_store_new(2,G_TYPE_BOOLEAN, G_TYPE_STRING); - - //setup columns in treeview - //COLUMN 0 is the checkboxes - treecol = gtk_tree_view_column_new(); - gtk_tree_view_column_set_title(treecol, "Select"); - gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), treecol); - treerend = gtk_cell_renderer_toggle_new(); - gtk_tree_view_column_pack_start(treecol, treerend, TRUE); - gtk_tree_view_column_add_attribute(treecol, treerend, "active", 0);//link 'active' attrib to first column of model - g_object_set(treerend, "activatable", TRUE, NULL);//set 'activatable' attrib true by default for all rows regardless of model. - g_signal_connect(treerend, "toggled", (GCallback) OnToggle_advopts, treestore);//set a global callback, we also pass a reference to our treestore. - - //COLUMN 1 is the text descriptions - treecol = gtk_tree_view_column_new(); - gtk_tree_view_column_set_title(treecol, "Description"); - gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), treecol); - treerend = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(treecol, treerend, TRUE); - gtk_tree_view_column_add_attribute(treecol, treerend, "text", 1);//link 'text' attrib to second column of model - - //setup the model with all our rows of option data - mapConfOpts.clear(); - confOpts.value = 0x00000001; - confOpts.desc = "Tex Target checking - 00000001\nLego Racers"; - mapConfOpts["00000001"] = confOpts; - confOpts.value = 0x00000002; - confOpts.desc = "Auto reset targs - 00000002\nShadow Hearts, Samurai Warriors. Use when game is slow and toggling AA fixes it."; - mapConfOpts["00000002"] = confOpts; - confOpts.value = 0x00000004; - confOpts.desc = "Interlace 2X - 00000004\nFixes 2x bigger screen (Gradius 3)."; - mapConfOpts["00000004"] = confOpts; - confOpts.value = 0x00000008; - confOpts.desc = "Text Alpha hack - 00000008\nNightmare Before Christmas."; - mapConfOpts["00000008"] = confOpts; - confOpts.value = 0x00000010; - confOpts.desc = "No target resolves - 00000010\nStops all resolving of targets. Try this first for really slow games."; - mapConfOpts["00000010"] = confOpts; - confOpts.value = 0x00000020; - confOpts.desc = "Exact color testing - 00000020\nFixes overbright or shadow/black artifacts (Crash 'n Burn)."; - mapConfOpts["00000020"] = confOpts; - confOpts.value = 0x00000040; - confOpts.desc = "No color clamping - 00000040\nSpeeds up games, but might be too bright or too dim."; - mapConfOpts["00000040"] = confOpts; - confOpts.value = 0x00000080; - confOpts.desc = "FFX hack - 00000080\nShows missing geometry."; - mapConfOpts["00000080"] = confOpts; - confOpts.value = 0x00000200; - confOpts.desc = "Disable depth updates - 00000200"; - mapConfOpts["00000200"] = confOpts; - confOpts.value = 0x00000400; - confOpts.desc = "Resolve Hack #1 - 00000400\nKingdom Hearts. Speeds some games."; - mapConfOpts["00000400"] = confOpts; - confOpts.value = 0x00000800; - confOpts.desc = "Resolve Hack #2 - 00000800\nShadow Hearts, Urbz."; - mapConfOpts["00000800"] = confOpts; - confOpts.value = 0x00001000; - confOpts.desc = "No target CLUT - 00001000\nResident Evil 4, or foggy scenes."; - mapConfOpts["00001000"] = confOpts; - confOpts.value = 0x00002000; - confOpts.desc = "Disable stencil buffer - 00002000\nUsually safe to do for simple scenes."; - mapConfOpts["00002000"] = confOpts; - confOpts.value = 0x00004000; - confOpts.desc = "No vertical stripes - 00004000\nTry when there's a lot of garbage on screen."; - mapConfOpts["00004000"] = confOpts; - confOpts.value = 0x00008000; - confOpts.desc = "No depth resolve - 00008000\nMight give z buffer artifacts."; - mapConfOpts["00008000"] = confOpts; - confOpts.value = 0x00010000; - confOpts.desc = "Full 16 bit resolution - 00010000\nUse when half the screen is missing."; - mapConfOpts["00010000"] = confOpts; - confOpts.value = 0x00020000; - confOpts.desc = "Resolve Hack #3 - 00020000\nNeopets"; - mapConfOpts["00020000"] = confOpts; - confOpts.value = 0x00040000; - confOpts.desc = "Fast Update - 00040000\nOkami. Speeds some games."; - mapConfOpts["00040000"] = confOpts; - confOpts.value = 0x00080000; - confOpts.desc = "Disable alpha testing - 00080000"; - mapConfOpts["00080000"] = confOpts; - confOpts.value = 0x00100000; - confOpts.desc = "Disable Multiple RTs - 00100000"; - mapConfOpts["00100000"] = confOpts; - confOpts.value = 0x00200000; - confOpts.desc = "32 bit render targets - 00200000"; - mapConfOpts["00200000"] = confOpts; - - for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) - { - gtk_list_store_append(treestore, &treeiter);//new row - itval = (conf.gamesettings&it->second.value)?TRUE:FALSE; - snprintf(descbuf, 254, "%s", it->second.desc); - gtk_list_store_set(treestore, &treeiter, 0, itval, 1, descbuf, -1); - } - - gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(treestore));//NB: store is cast as tree model. - g_object_unref(treestore);//allow model to be destroyed when the tree is destroyed. - - //don't select/highlight rows - gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), GTK_SELECTION_NONE); - //------treeview done -------// - - //Let's do it! - gtk_widget_show_all(Conf); - gtk_main(); -} - -void OnToggle_advopts(GtkCellRendererToggle *cell, gchar *path, gpointer user_data) -{ - GtkTreeIter treeiter; - gboolean val; - - gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(user_data), &treeiter, path); - gtk_tree_model_get(GTK_TREE_MODEL(user_data), &treeiter, 0, &val, -1); - val = !val; - gtk_list_store_set(GTK_LIST_STORE(user_data), &treeiter, 0, val, -1); - -} - -void OnAbout_Ok(GtkButton *button, gpointer user_data) -{ - gtk_widget_destroy(About); - gtk_main_quit(); -} - -void CALLBACK GSabout() -{ - About = create_About(); - - gtk_widget_show_all(About); - gtk_main(); -} - -s32 CALLBACK GStest() -{ - return 0; -} - -GtkWidget *MsgDlg; - -void OnMsg_Ok() -{ - gtk_widget_destroy(MsgDlg); - gtk_main_quit(); -} - -void SysMessage(char *fmt, ...) -{ - GtkWidget *Ok,*Txt; - GtkWidget *Box,*Box1; - va_list list; - char msg[512]; - - va_start(list, fmt); - vsprintf(msg, fmt, list); - va_end(list); - - if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; - - MsgDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); - gtk_window_set_title(GTK_WINDOW(MsgDlg), "GSsoft Msg"); - gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); - - Box = gtk_vbox_new(5, 0); - gtk_container_add(GTK_CONTAINER(MsgDlg), Box); - gtk_widget_show(Box); - - Txt = gtk_label_new(msg); - - gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); - gtk_widget_show(Txt); - - Box1 = gtk_hbutton_box_new(); - gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); - gtk_widget_show(Box1); - - Ok = gtk_button_new_with_label("Ok"); - gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); - gtk_container_add(GTK_CONTAINER(Box1), Ok); - GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); - gtk_widget_show(Ok); - - gtk_widget_show(MsgDlg); - - gtk_main(); -} - -void *SysLoadLibrary(char *lib) -{ - return dlopen(lib, RTLD_NOW | RTLD_GLOBAL); -} - -void *SysLoadSym(void *lib, char *sym) -{ - void *ret = dlsym(lib, sym); - if (ret == NULL) printf("null: %s\n", sym); - return dlsym(lib, sym); -} - -char *SysLibError() -{ - return dlerror(); -} - -void SysCloseLibrary(void *lib) -{ - dlclose(lib); -} +/* ZeroGS + * Copyright (C) 2002-2004 GSsoft 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include "GS.h" + +extern "C" { +#include "interface.h" +#include "support.h" +#include "callbacks.h" +} + +#include "Linux.h" + +#include + +static int prevbilinearfilter; +//static map mapConfOpts; +struct confOptsStruct +{ + int value; + const char *desc; +}confOpts; + +static map mapConfOpts; + +extern void OnKeyboardF5(int); +extern void OnKeyboardF6(int); +extern void OnKeyboardF7(int); +extern void OnKeyboardF9(int); + +GtkWidget *About; + +void CALLBACK GSkeyEvent(keyEvent *ev) +{ + //static bool bShift = false; + static bool bAlt = false; + + switch(ev->evt) { + case KEYPRESS: + switch(ev->key) { + case XK_F5: + case XK_F6: + case XK_F7: + case XK_F9: + THR_KeyEvent = ev->key ; + break; + case XK_Escape: + break; + case XK_Shift_L: + case XK_Shift_R: + //bShift = true; + THR_bShift = true; + break; + case XK_Alt_L: + case XK_Alt_R: + bAlt = true; + break; + } + break; + case KEYRELEASE: + switch(ev->key) { + case XK_Shift_L: + case XK_Shift_R: + //bShift = false; + THR_bShift = false; + break; + case XK_Alt_L: + case XK_Alt_R: + bAlt = false; + break; + } + } +} + +GtkWidget *Conf; +GtkWidget *Logging; +GList *fresl; +GList *wresl; +GList *cachesizel; +GList *codecl; +GList *filtersl; + +void OnConf_Ok(GtkButton *button, gpointer user_data) +{ + GtkWidget *Btn; + GtkWidget *treeview; + GtkTreeModel *treemodel; + GtkTreeIter treeiter; + gboolean treeoptval; + gchar *gbuf; + char *str; + int i; + + u32 newinterlace = is_checked(Conf, "checkInterlace"); + + if (!conf.interlace ) + conf.interlace = newinterlace; + else if (!newinterlace ) + conf.interlace = 2; // off + + conf.bilinear = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkBilinear"))); + // restore + if (conf.bilinear && prevbilinearfilter) + conf.bilinear = prevbilinearfilter; + + //conf.mrtdepth = 1;//IsDlgButtonChecked(hW, IDC_CONFIG_DEPTHWRITE); + + if is_checked(Conf, "radioAANone") + conf.aa = 0; + else if is_checked(Conf, "radioAA2X") + conf.aa = 1; + else if is_checked(Conf, "radioAA4X") + conf.aa = 2; + else if is_checked(Conf, "radioAA8X") + conf.aa = 3; + else + conf.aa = 4; + + conf.options = 0; + conf.options |= is_checked(Conf, "checkAVI") ? GSOPTION_CAPTUREAVI : 0; + conf.options |= is_checked(Conf, "checkWireframe") ? GSOPTION_WIREFRAME : 0; + conf.options |= is_checked(Conf, "checkfullscreen") ? GSOPTION_FULLSCREEN : 0; + conf.options |= is_checked(Conf, "checkTGA") ? GSOPTION_TGASNAP : 0; + + //------- get advanced options from the treeview model -------// + treeview = lookup_widget(Conf,"treeview1"); + treemodel = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)); + gtk_tree_model_get_iter_first(treemodel, &treeiter); + + conf.gamesettings = 0; + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) + { + treeoptval = FALSE; + gtk_tree_model_get(treemodel, &treeiter, 0, &treeoptval, -1); + + if(treeoptval) conf.gamesettings |= it->second.value; + + gtk_tree_model_iter_next(treemodel,&treeiter); + } + + GSsetGameCRC(0, conf.gamesettings); + //---------- done getting advanced options ---------// + + if is_checked(Conf, "radioSize640") + conf.options |= GSOPTION_WIN640; + else if is_checked(Conf, "radioSize800") + conf.options |= GSOPTION_WIN800; + else if is_checked(Conf, "radioSize1024") + conf.options |= GSOPTION_WIN1024; + else if is_checked(Conf, "radioSize1280") + conf.options |= GSOPTION_WIN1280; + + SaveConfig(); + + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void OnConf_Cancel(GtkButton *button, gpointer user_data) +{ + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void CALLBACK GSconfigure() +{ + char name[32]; + char descbuf[255]; + int nmodes, i; + bool itval; + GtkWidget *treeview; + GtkCellRenderer *treerend; + GtkListStore *treestore;//Gets typecast as GtkTreeModel as needed. + GtkTreeIter treeiter; + GtkTreeViewColumn *treecol; + + if (!(conf.options & GSOPTION_LOADED)) LoadConfig(); + Conf = create_Config(); + + set_checked(Conf, "checkBilinear", !!conf.bilinear); + //set_checked(Conf, "checkbutton6", conf.mrtdepth); + set_checked(Conf, "radioAANone", conf.aa==0); + set_checked(Conf, "radioAA2X", conf.aa==1); + set_checked(Conf, "radioAA4X", conf.aa==2); + set_checked(Conf, "radioAA8X", conf.aa==3); + set_checked(Conf, "radioAA16X", conf.aa==4); + set_checked(Conf, "checkWireframe", (conf.options&GSOPTION_WIREFRAME)?1:0); + set_checked(Conf, "checkAVI", (conf.options&GSOPTION_CAPTUREAVI)?1:0); + set_checked(Conf, "checkfullscreen", (conf.options&GSOPTION_FULLSCREEN)?1:0); + set_checked(Conf, "checkTGA", (conf.options&GSOPTION_TGASNAP)?1:0); + + set_checked(Conf, "radioSize640", ((conf.options&GSOPTION_WINDIMS)>>4)==0); + set_checked(Conf, "radioSize800", ((conf.options&GSOPTION_WINDIMS)>>4)==1); + set_checked(Conf, "radioSize1024", ((conf.options&GSOPTION_WINDIMS)>>4)==2); + set_checked(Conf, "radioSize1280", ((conf.options&GSOPTION_WINDIMS)>>4)==3); + + prevbilinearfilter = conf.bilinear; + + //--------- Let's build a treeview for our advanced options! --------// + treeview = lookup_widget(Conf,"treeview1"); + treestore = gtk_list_store_new(2,G_TYPE_BOOLEAN, G_TYPE_STRING); + + //setup columns in treeview + //COLUMN 0 is the checkboxes + treecol = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(treecol, "Select"); + gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), treecol); + treerend = gtk_cell_renderer_toggle_new(); + gtk_tree_view_column_pack_start(treecol, treerend, TRUE); + gtk_tree_view_column_add_attribute(treecol, treerend, "active", 0);//link 'active' attrib to first column of model + g_object_set(treerend, "activatable", TRUE, NULL);//set 'activatable' attrib true by default for all rows regardless of model. + g_signal_connect(treerend, "toggled", (GCallback) OnToggle_advopts, treestore);//set a global callback, we also pass a reference to our treestore. + + //COLUMN 1 is the text descriptions + treecol = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(treecol, "Description"); + gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), treecol); + treerend = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(treecol, treerend, TRUE); + gtk_tree_view_column_add_attribute(treecol, treerend, "text", 1);//link 'text' attrib to second column of model + + //setup the model with all our rows of option data + mapConfOpts.clear(); + confOpts.value = 0x00000001; + confOpts.desc = "Tex Target checking - 00000001\nLego Racers"; + mapConfOpts["00000001"] = confOpts; + confOpts.value = 0x00000002; + confOpts.desc = "Auto reset targs - 00000002\nShadow Hearts, Samurai Warriors. Use when game is slow and toggling AA fixes it."; + mapConfOpts["00000002"] = confOpts; + confOpts.value = 0x00000004; + confOpts.desc = "Interlace 2X - 00000004\nFixes 2x bigger screen (Gradius 3)."; + mapConfOpts["00000004"] = confOpts; + confOpts.value = 0x00000008; + confOpts.desc = "Text Alpha hack - 00000008\nNightmare Before Christmas."; + mapConfOpts["00000008"] = confOpts; + confOpts.value = 0x00000010; + confOpts.desc = "No target resolves - 00000010\nStops all resolving of targets. Try this first for really slow games."; + mapConfOpts["00000010"] = confOpts; + confOpts.value = 0x00000020; + confOpts.desc = "Exact color testing - 00000020\nFixes overbright or shadow/black artifacts (Crash 'n Burn)."; + mapConfOpts["00000020"] = confOpts; + confOpts.value = 0x00000040; + confOpts.desc = "No color clamping - 00000040\nSpeeds up games, but might be too bright or too dim."; + mapConfOpts["00000040"] = confOpts; + confOpts.value = 0x00000080; + confOpts.desc = "FFX hack - 00000080\nShows missing geometry."; + mapConfOpts["00000080"] = confOpts; + confOpts.value = 0x00000200; + confOpts.desc = "Disable depth updates - 00000200"; + mapConfOpts["00000200"] = confOpts; + confOpts.value = 0x00000400; + confOpts.desc = "Resolve Hack #1 - 00000400\nKingdom Hearts. Speeds some games."; + mapConfOpts["00000400"] = confOpts; + confOpts.value = 0x00000800; + confOpts.desc = "Resolve Hack #2 - 00000800\nShadow Hearts, Urbz."; + mapConfOpts["00000800"] = confOpts; + confOpts.value = 0x00001000; + confOpts.desc = "No target CLUT - 00001000\nResident Evil 4, or foggy scenes."; + mapConfOpts["00001000"] = confOpts; + confOpts.value = 0x00002000; + confOpts.desc = "Disable stencil buffer - 00002000\nUsually safe to do for simple scenes."; + mapConfOpts["00002000"] = confOpts; + confOpts.value = 0x00004000; + confOpts.desc = "No vertical stripes - 00004000\nTry when there's a lot of garbage on screen."; + mapConfOpts["00004000"] = confOpts; + confOpts.value = 0x00008000; + confOpts.desc = "No depth resolve - 00008000\nMight give z buffer artifacts."; + mapConfOpts["00008000"] = confOpts; + confOpts.value = 0x00010000; + confOpts.desc = "Full 16 bit resolution - 00010000\nUse when half the screen is missing."; + mapConfOpts["00010000"] = confOpts; + confOpts.value = 0x00020000; + confOpts.desc = "Resolve Hack #3 - 00020000\nNeopets"; + mapConfOpts["00020000"] = confOpts; + confOpts.value = 0x00040000; + confOpts.desc = "Fast Update - 00040000\nOkami. Speeds some games."; + mapConfOpts["00040000"] = confOpts; + confOpts.value = 0x00080000; + confOpts.desc = "Disable alpha testing - 00080000"; + mapConfOpts["00080000"] = confOpts; + confOpts.value = 0x00100000; + confOpts.desc = "Disable Multiple RTs - 00100000"; + mapConfOpts["00100000"] = confOpts; + confOpts.value = 0x00200000; + confOpts.desc = "32 bit render targets - 00200000"; + mapConfOpts["00200000"] = confOpts; + + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) + { + gtk_list_store_append(treestore, &treeiter);//new row + itval = (conf.gamesettings&it->second.value)?TRUE:FALSE; + snprintf(descbuf, 254, "%s", it->second.desc); + gtk_list_store_set(treestore, &treeiter, 0, itval, 1, descbuf, -1); + } + + gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(treestore));//NB: store is cast as tree model. + g_object_unref(treestore);//allow model to be destroyed when the tree is destroyed. + + //don't select/highlight rows + gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), GTK_SELECTION_NONE); + //------treeview done -------// + + //Let's do it! + gtk_widget_show_all(Conf); + gtk_main(); +} + +void OnToggle_advopts(GtkCellRendererToggle *cell, gchar *path, gpointer user_data) +{ + GtkTreeIter treeiter; + gboolean val; + + gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(user_data), &treeiter, path); + gtk_tree_model_get(GTK_TREE_MODEL(user_data), &treeiter, 0, &val, -1); + val = !val; + gtk_list_store_set(GTK_LIST_STORE(user_data), &treeiter, 0, val, -1); + +} + +void OnAbout_Ok(GtkButton *button, gpointer user_data) +{ + gtk_widget_destroy(About); + gtk_main_quit(); +} + +void CALLBACK GSabout() +{ + About = create_About(); + + gtk_widget_show_all(About); + gtk_main(); +} + +s32 CALLBACK GStest() +{ + return 0; +} + +GtkWidget *MsgDlg; + +void OnMsg_Ok() +{ + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + +void SysMessage(char *fmt, ...) +{ + GtkWidget *Ok,*Txt; + GtkWidget *Box,*Box1; + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + MsgDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "GSsoft Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); + + Box = gtk_vbox_new(5, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main(); +} + +void *SysLoadLibrary(char *lib) +{ + return dlopen(lib, RTLD_NOW | RTLD_GLOBAL); +} + +void *SysLoadSym(void *lib, char *sym) +{ + void *ret = dlsym(lib, sym); + if (ret == NULL) printf("null: %s\n", sym); + return dlsym(lib, sym); +} + +char *SysLibError() +{ + return dlerror(); +} + +void SysCloseLibrary(void *lib) +{ + dlclose(lib); +} diff --git a/plugins/zerogs/opengl/Linux/Linux.h b/plugins/zerogs/opengl/Linux/Linux.h index 6e52bc220f..cfead3b7ee 100644 --- a/plugins/zerogs/opengl/Linux/Linux.h +++ b/plugins/zerogs/opengl/Linux/Linux.h @@ -1,26 +1,26 @@ -/* - * Copyright (C) 2002-2004 GSsoft 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __LINUX_H__ -#define __LINUX_H__ -#endif - -void OnToggle_advopts(GtkCellRendererToggle *cell, gchar *path, gpointer user_data); - -#define is_checked(main_widget, widget_name) (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(main_widget, widget_name)))) -#define set_checked(main_widget,widget_name, state) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(main_widget, widget_name)), state) +/* + * Copyright (C) 2002-2004 GSsoft 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LINUX_H__ +#define __LINUX_H__ +#endif + +void OnToggle_advopts(GtkCellRendererToggle *cell, gchar *path, gpointer user_data); + +#define is_checked(main_widget, widget_name) (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(main_widget, widget_name)))) +#define set_checked(main_widget,widget_name, state) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(main_widget, widget_name)), state) diff --git a/plugins/zerogs/opengl/Mem.cpp b/plugins/zerogs/opengl/Mem.cpp index 2133533409..8b63efb1bf 100644 --- a/plugins/zerogs/opengl/Mem.cpp +++ b/plugins/zerogs/opengl/Mem.cpp @@ -1,903 +1,903 @@ -/* ZeroGS KOSMOS - * Copyright (C) 2005-2006 zerofrog@gmail.com - * - * 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 "GS.h" -#include "Mem.h" -#include "zerogs.h" -#include "targets.h" -#include "x86.h" - -u32 g_blockTable32[4][8] = { - { 0, 1, 4, 5, 16, 17, 20, 21}, - { 2, 3, 6, 7, 18, 19, 22, 23}, - { 8, 9, 12, 13, 24, 25, 28, 29}, - { 10, 11, 14, 15, 26, 27, 30, 31} -}; - -u32 g_blockTable32Z[4][8] = { - { 24, 25, 28, 29, 8, 9, 12, 13}, - { 26, 27, 30, 31, 10, 11, 14, 15}, - { 16, 17, 20, 21, 0, 1, 4, 5}, - { 18, 19, 22, 23, 2, 3, 6, 7} -}; - -u32 g_blockTable16[8][4] = { - { 0, 2, 8, 10 }, - { 1, 3, 9, 11 }, - { 4, 6, 12, 14 }, - { 5, 7, 13, 15 }, - { 16, 18, 24, 26 }, - { 17, 19, 25, 27 }, - { 20, 22, 28, 30 }, - { 21, 23, 29, 31 } -}; - -u32 g_blockTable16S[8][4] = { - { 0, 2, 16, 18 }, - { 1, 3, 17, 19 }, - { 8, 10, 24, 26 }, - { 9, 11, 25, 27 }, - { 4, 6, 20, 22 }, - { 5, 7, 21, 23 }, - { 12, 14, 28, 30 }, - { 13, 15, 29, 31 } -}; - -u32 g_blockTable16Z[8][4] = { - { 24, 26, 16, 18 }, - { 25, 27, 17, 19 }, - { 28, 30, 20, 22 }, - { 29, 31, 21, 23 }, - { 8, 10, 0, 2 }, - { 9, 11, 1, 3 }, - { 12, 14, 4, 6 }, - { 13, 15, 5, 7 } -}; - -u32 g_blockTable16SZ[8][4] = { - { 24, 26, 8, 10 }, - { 25, 27, 9, 11 }, - { 16, 18, 0, 2 }, - { 17, 19, 1, 3 }, - { 28, 30, 12, 14 }, - { 29, 31, 13, 15 }, - { 20, 22, 4, 6 }, - { 21, 23, 5, 7 } -}; - -u32 g_blockTable8[4][8] = { - { 0, 1, 4, 5, 16, 17, 20, 21}, - { 2, 3, 6, 7, 18, 19, 22, 23}, - { 8, 9, 12, 13, 24, 25, 28, 29}, - { 10, 11, 14, 15, 26, 27, 30, 31} -}; - -u32 g_blockTable4[8][4] = { - { 0, 2, 8, 10 }, - { 1, 3, 9, 11 }, - { 4, 6, 12, 14 }, - { 5, 7, 13, 15 }, - { 16, 18, 24, 26 }, - { 17, 19, 25, 27 }, - { 20, 22, 28, 30 }, - { 21, 23, 29, 31 } -}; - -u32 g_columnTable32[8][8] = { - { 0, 1, 4, 5, 8, 9, 12, 13 }, - { 2, 3, 6, 7, 10, 11, 14, 15 }, - { 16, 17, 20, 21, 24, 25, 28, 29 }, - { 18, 19, 22, 23, 26, 27, 30, 31 }, - { 32, 33, 36, 37, 40, 41, 44, 45 }, - { 34, 35, 38, 39, 42, 43, 46, 47 }, - { 48, 49, 52, 53, 56, 57, 60, 61 }, - { 50, 51, 54, 55, 58, 59, 62, 63 }, -}; - -u32 g_columnTable16[8][16] = { - { 0, 2, 8, 10, 16, 18, 24, 26, - 1, 3, 9, 11, 17, 19, 25, 27 }, - { 4, 6, 12, 14, 20, 22, 28, 30, - 5, 7, 13, 15, 21, 23, 29, 31 }, - { 32, 34, 40, 42, 48, 50, 56, 58, - 33, 35, 41, 43, 49, 51, 57, 59 }, - { 36, 38, 44, 46, 52, 54, 60, 62, - 37, 39, 45, 47, 53, 55, 61, 63 }, - { 64, 66, 72, 74, 80, 82, 88, 90, - 65, 67, 73, 75, 81, 83, 89, 91 }, - { 68, 70, 76, 78, 84, 86, 92, 94, - 69, 71, 77, 79, 85, 87, 93, 95 }, - { 96, 98, 104, 106, 112, 114, 120, 122, - 97, 99, 105, 107, 113, 115, 121, 123 }, - { 100, 102, 108, 110, 116, 118, 124, 126, - 101, 103, 109, 111, 117, 119, 125, 127 }, -}; - -u32 g_columnTable8[16][16] = { - { 0, 4, 16, 20, 32, 36, 48, 52, // column 0 - 2, 6, 18, 22, 34, 38, 50, 54 }, - { 8, 12, 24, 28, 40, 44, 56, 60, - 10, 14, 26, 30, 42, 46, 58, 62 }, - { 33, 37, 49, 53, 1, 5, 17, 21, - 35, 39, 51, 55, 3, 7, 19, 23 }, - { 41, 45, 57, 61, 9, 13, 25, 29, - 43, 47, 59, 63, 11, 15, 27, 31 }, - { 96, 100, 112, 116, 64, 68, 80, 84, // column 1 - 98, 102, 114, 118, 66, 70, 82, 86 }, - { 104, 108, 120, 124, 72, 76, 88, 92, - 106, 110, 122, 126, 74, 78, 90, 94 }, - { 65, 69, 81, 85, 97, 101, 113, 117, - 67, 71, 83, 87, 99, 103, 115, 119 }, - { 73, 77, 89, 93, 105, 109, 121, 125, - 75, 79, 91, 95, 107, 111, 123, 127 }, - { 128, 132, 144, 148, 160, 164, 176, 180, // column 2 - 130, 134, 146, 150, 162, 166, 178, 182 }, - { 136, 140, 152, 156, 168, 172, 184, 188, - 138, 142, 154, 158, 170, 174, 186, 190 }, - { 161, 165, 177, 181, 129, 133, 145, 149, - 163, 167, 179, 183, 131, 135, 147, 151 }, - { 169, 173, 185, 189, 137, 141, 153, 157, - 171, 175, 187, 191, 139, 143, 155, 159 }, - { 224, 228, 240, 244, 192, 196, 208, 212, // column 3 - 226, 230, 242, 246, 194, 198, 210, 214 }, - { 232, 236, 248, 252, 200, 204, 216, 220, - 234, 238, 250, 254, 202, 206, 218, 222 }, - { 193, 197, 209, 213, 225, 229, 241, 245, - 195, 199, 211, 215, 227, 231, 243, 247 }, - { 201, 205, 217, 221, 233, 237, 249, 253, - 203, 207, 219, 223, 235, 239, 251, 255 }, -}; - -u32 g_columnTable4[16][32] = { - { 0, 8, 32, 40, 64, 72, 96, 104, // column 0 - 2, 10, 34, 42, 66, 74, 98, 106, - 4, 12, 36, 44, 68, 76, 100, 108, - 6, 14, 38, 46, 70, 78, 102, 110 }, - { 16, 24, 48, 56, 80, 88, 112, 120, - 18, 26, 50, 58, 82, 90, 114, 122, - 20, 28, 52, 60, 84, 92, 116, 124, - 22, 30, 54, 62, 86, 94, 118, 126 }, - { 65, 73, 97, 105, 1, 9, 33, 41, - 67, 75, 99, 107, 3, 11, 35, 43, - 69, 77, 101, 109, 5, 13, 37, 45, - 71, 79, 103, 111, 7, 15, 39, 47 }, - { 81, 89, 113, 121, 17, 25, 49, 57, - 83, 91, 115, 123, 19, 27, 51, 59, - 85, 93, 117, 125, 21, 29, 53, 61, - 87, 95, 119, 127, 23, 31, 55, 63 }, - { 192, 200, 224, 232, 128, 136, 160, 168, // column 1 - 194, 202, 226, 234, 130, 138, 162, 170, - 196, 204, 228, 236, 132, 140, 164, 172, - 198, 206, 230, 238, 134, 142, 166, 174 }, - { 208, 216, 240, 248, 144, 152, 176, 184, - 210, 218, 242, 250, 146, 154, 178, 186, - 212, 220, 244, 252, 148, 156, 180, 188, - 214, 222, 246, 254, 150, 158, 182, 190 }, - { 129, 137, 161, 169, 193, 201, 225, 233, - 131, 139, 163, 171, 195, 203, 227, 235, - 133, 141, 165, 173, 197, 205, 229, 237, - 135, 143, 167, 175, 199, 207, 231, 239 }, - { 145, 153, 177, 185, 209, 217, 241, 249, - 147, 155, 179, 187, 211, 219, 243, 251, - 149, 157, 181, 189, 213, 221, 245, 253, - 151, 159, 183, 191, 215, 223, 247, 255 }, - { 256, 264, 288, 296, 320, 328, 352, 360, // column 2 - 258, 266, 290, 298, 322, 330, 354, 362, - 260, 268, 292, 300, 324, 332, 356, 364, - 262, 270, 294, 302, 326, 334, 358, 366 }, - { 272, 280, 304, 312, 336, 344, 368, 376, - 274, 282, 306, 314, 338, 346, 370, 378, - 276, 284, 308, 316, 340, 348, 372, 380, - 278, 286, 310, 318, 342, 350, 374, 382 }, - { 321, 329, 353, 361, 257, 265, 289, 297, - 323, 331, 355, 363, 259, 267, 291, 299, - 325, 333, 357, 365, 261, 269, 293, 301, - 327, 335, 359, 367, 263, 271, 295, 303 }, - { 337, 345, 369, 377, 273, 281, 305, 313, - 339, 347, 371, 379, 275, 283, 307, 315, - 341, 349, 373, 381, 277, 285, 309, 317, - 343, 351, 375, 383, 279, 287, 311, 319 }, - { 448, 456, 480, 488, 384, 392, 416, 424, // column 3 - 450, 458, 482, 490, 386, 394, 418, 426, - 452, 460, 484, 492, 388, 396, 420, 428, - 454, 462, 486, 494, 390, 398, 422, 430 }, - { 464, 472, 496, 504, 400, 408, 432, 440, - 466, 474, 498, 506, 402, 410, 434, 442, - 468, 476, 500, 508, 404, 412, 436, 444, - 470, 478, 502, 510, 406, 414, 438, 446 }, - { 385, 393, 417, 425, 449, 457, 481, 489, - 387, 395, 419, 427, 451, 459, 483, 491, - 389, 397, 421, 429, 453, 461, 485, 493, - 391, 399, 423, 431, 455, 463, 487, 495 }, - { 401, 409, 433, 441, 465, 473, 497, 505, - 403, 411, 435, 443, 467, 475, 499, 507, - 405, 413, 437, 445, 469, 477, 501, 509, - 407, 415, 439, 447, 471, 479, 503, 511 }, -}; - -u32 g_pageTable32[32][64]; -u32 g_pageTable32Z[32][64]; -u32 g_pageTable16[64][64]; -u32 g_pageTable16S[64][64]; -u32 g_pageTable16Z[64][64]; -u32 g_pageTable16SZ[64][64]; -u32 g_pageTable8[64][128]; -u32 g_pageTable4[128][128]; - -BLOCK m_Blocks[0x40]; // do so blocks are indexable -static PCSX2_ALIGNED16(u32 tempblock[64]); - -#define DSTPSM gs.dstbuf.psm - -#define START_HOSTLOCAL() \ - assert( gs.imageTransfer == 0 ); \ - u8* pstart = g_pbyGSMemory + gs.dstbuf.bp*256; \ - \ - const u8* pendbuf = (const u8*)pbyMem + nQWordSize*4; \ - int i = gs.imageY, j = gs.imageX; \ - -extern BOOL g_bSaveTrans; - -#define END_HOSTLOCAL() \ -End: \ - if( i >= gs.imageEndY ) { \ - assert( gs.imageTransfer == -1 || i == gs.imageEndY ); \ - gs.imageTransfer = -1; \ - /*int start, end; \ - ZeroGS::GetRectMemAddress(start, end, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); \ - ZeroGS::g_MemTargs.ClearRange(start, end);*/ \ - } \ - else { \ - /* update new params */ \ - gs.imageY = i; \ - gs.imageX = j; \ - } \ - -// transfers whole rows -#define TRANSMIT_HOSTLOCAL_Y_(psm, T, widthlimit, endY) { \ - assert( (nSize%widthlimit) == 0 && widthlimit <= 4 ); \ - if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { \ - /*GS_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM);*/ \ - for(; i < endY; ++i) { \ - for(; j < gs.imageEndX && nSize > 0; j += 1, nSize -= 1, pbuf += 1) { \ - /* write as many pixel at one time as possible */ \ - writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ - } \ - } \ - } \ - for(; i < endY; ++i) { \ - for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += widthlimit) { \ - /* write as many pixel at one time as possible */ \ - if( nSize < widthlimit ) goto End; \ - writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ - \ - if( widthlimit > 1 ) { \ - writePixel##psm##_0(pstart, (j+1)%2048, i%2048, pbuf[1], gs.dstbuf.bw); \ - \ - if( widthlimit > 2 ) { \ - writePixel##psm##_0(pstart, (j+2)%2048, i%2048, pbuf[2], gs.dstbuf.bw); \ - \ - if( widthlimit > 3 ) { \ - writePixel##psm##_0(pstart, (j+3)%2048, i%2048, pbuf[3], gs.dstbuf.bw); \ - } \ - } \ - } \ - } \ - \ - if( j >= gs.imageEndX ) { assert(j == gs.imageEndX); j = gs.trxpos.dx; } \ - else { assert( gs.imageTransfer == -1 || nSize*sizeof(T)/4 == 0 ); goto End; } \ - } \ -} \ - -// transmit until endX, don't check size since it has already been prevalidated -#define TRANSMIT_HOSTLOCAL_X_(psm, T, widthlimit, blockheight, startX) { \ - for(int tempi = 0; tempi < blockheight; ++tempi) { \ - for(j = startX; j < gs.imageEndX; j++, pbuf++) { \ - writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, pbuf[0], gs.dstbuf.bw); \ - } \ - pbuf += pitch-fracX; \ - } \ -} \ - -// transfers whole rows -#define TRANSMIT_HOSTLOCAL_Y_24(psm, T, widthlimit, endY) { \ - if( widthlimit != 8 || ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) { \ - /*GS_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM);*/ \ - for(; i < endY; ++i) { \ - for(; j < gs.imageEndX && nSize > 0; j += 1, nSize -= 1, pbuf += 3) { \ - writePixel##psm##_0(pstart, j%2048, i%2048, *(u32*)(pbuf), gs.dstbuf.bw); \ - } \ - \ - if( j >= gs.imageEndX ) { assert(gs.imageTransfer == -1 || j == gs.imageEndX); j = gs.trxpos.dx; } \ - else { assert( gs.imageTransfer == -1 || nSize == 0 ); goto End; } \ - } \ - } \ - else { \ - assert( /*(nSize%widthlimit) == 0 &&*/ widthlimit == 8 ); \ - for(; i < endY; ++i) { \ - for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += 3*widthlimit) { \ - if( nSize < widthlimit ) goto End; \ - /* write as many pixel at one time as possible */ \ - writePixel##psm##_0(pstart, j%2048, i%2048, *(u32*)(pbuf+0), gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *(u32*)(pbuf+3), gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *(u32*)(pbuf+6), gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *(u32*)(pbuf+9), gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *(u32*)(pbuf+12), gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *(u32*)(pbuf+15), gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *(u32*)(pbuf+18), gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *(u32*)(pbuf+21), gs.dstbuf.bw); \ - } \ - \ - if( j >= gs.imageEndX ) { assert(gs.imageTransfer == -1 || j == gs.imageEndX); j = gs.trxpos.dx; } \ - else { \ - if( nSize < 0 ) { \ - /* extracted too much */ \ - assert( (nSize%3)==0 && nSize > -24 ); \ - j += nSize/3; \ - nSize = 0; \ - } \ - assert( gs.imageTransfer == -1 || nSize == 0 ); \ - goto End; \ - } \ - } \ - } \ -} \ - -// transmit until endX, don't check size since it has already been prevalidated -#define TRANSMIT_HOSTLOCAL_X_24(psm, T, widthlimit, blockheight, startX) { \ - for(int tempi = 0; tempi < blockheight; ++tempi) { \ - for(j = startX; j < gs.imageEndX; j++, pbuf += 3) { \ - writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, *(u32*)pbuf, gs.dstbuf.bw); \ - } \ - pbuf += 3*(pitch-fracX); \ - } \ -} \ - -// meant for 4bit transfers -#define TRANSMIT_HOSTLOCAL_Y_4(psm, T, widthlimit, endY) { \ - for(; i < endY; ++i) { \ - for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit) { \ - /* write as many pixel at one time as possible */ \ - writePixel##psm##_0(pstart, j%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ - pbuf++; \ - if( widthlimit > 2 ) { \ - writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ - pbuf++; \ - \ - if( widthlimit > 4 ) { \ - writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ - pbuf++; \ - \ - if( widthlimit > 6 ) { \ - writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ - pbuf++; \ - } \ - } \ - } \ - } \ - \ - if( j >= gs.imageEndX ) { j = gs.trxpos.dx; } \ - else { assert( gs.imageTransfer == -1 || (nSize/32) == 0 ); goto End; } \ - } \ -} \ - -// transmit until endX, don't check size since it has already been prevalidated -#define TRANSMIT_HOSTLOCAL_X_4(psm, T, widthlimit, blockheight, startX) { \ - for(int tempi = 0; tempi < blockheight; ++tempi) { \ - for(j = startX; j < gs.imageEndX; j+=2, pbuf++) { \ - writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, pbuf[0]&0x0f, gs.dstbuf.bw); \ - writePixel##psm##_0(pstart, (j+1)%2048, (i+tempi)%2048, pbuf[0]>>4, gs.dstbuf.bw); \ - } \ - pbuf += (pitch-fracX)/2; \ - } \ -} \ - -// calculate pitch in source buffer -#define TRANSMIT_PITCH_(pitch, T) (pitch*sizeof(T)) -#define TRANSMIT_PITCH_24(pitch, T) (pitch*3) -#define TRANSMIT_PITCH_4(pitch, T) (pitch/2) - -// special swizzle macros -#define SwizzleBlock24(dst, src, pitch) { \ - u8* pnewsrc = src; \ - u32* pblock = tempblock; \ - \ - for(int by = 0; by < 7; ++by, pblock += 8, pnewsrc += pitch-24) { \ - for(int bx = 0; bx < 8; ++bx, pnewsrc += 3) { \ - pblock[bx] = *(u32*)pnewsrc; \ - } \ - } \ - for(int bx = 0; bx < 7; ++bx, pnewsrc += 3) { \ - /* might be 1 byte out of bounds of GS memory */ \ - pblock[bx] = *(u32*)pnewsrc; \ - } \ - /* do 3 bytes for the last copy */ \ - *((u8*)pblock+28) = pnewsrc[0]; \ - *((u8*)pblock+29) = pnewsrc[1]; \ - *((u8*)pblock+30) = pnewsrc[2]; \ - SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0x00ffffff); \ -} \ - -#define SwizzleBlock24u SwizzleBlock24 - -#define SwizzleBlock8H(dst, src, pitch) { \ - u8* pnewsrc = src; \ - u32* pblock = tempblock; \ - \ - for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ - u32 u = *(u32*)pnewsrc; \ - pblock[0] = u<<24; \ - pblock[1] = u<<16; \ - pblock[2] = u<<8; \ - pblock[3] = u; \ - u = *(u32*)(pnewsrc+4); \ - pblock[4] = u<<24; \ - pblock[5] = u<<16; \ - pblock[6] = u<<8; \ - pblock[7] = u; \ - } \ - SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0xff000000); \ -} \ - -#define SwizzleBlock8Hu SwizzleBlock8H - -#define SwizzleBlock4HH(dst, src, pitch) { \ - u8* pnewsrc = src; \ - u32* pblock = tempblock; \ - \ - for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ - u32 u = *(u32*)pnewsrc; \ - pblock[0] = u<<28; \ - pblock[1] = u<<24; \ - pblock[2] = u<<20; \ - pblock[3] = u<<16; \ - pblock[4] = u<<12; \ - pblock[5] = u<<8; \ - pblock[6] = u<<4; \ - pblock[7] = u; \ - } \ - SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0xf0000000); \ -} \ - -#define SwizzleBlock4HHu SwizzleBlock4HH - -#define SwizzleBlock4HL(dst, src, pitch) { \ - u8* pnewsrc = src; \ - u32* pblock = tempblock; \ - \ - for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ - u32 u = *(u32*)pnewsrc; \ - pblock[0] = u<<24; \ - pblock[1] = u<<20; \ - pblock[2] = u<<16; \ - pblock[3] = u<<12; \ - pblock[4] = u<<8; \ - pblock[5] = u<<4; \ - pblock[6] = u; \ - pblock[7] = u>>4; \ - } \ - SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0x0f000000); \ -} \ - -#define SwizzleBlock4HLu SwizzleBlock4HL - -// ------------------------ -// | Y | -// ------------------------ -// | block | | -// | aligned area | X | -// | | | -// ------------------------ -// | Y | -// ------------------------ -#define DEFINE_TRANSFERLOCAL(psm, T, widthlimit, blockbits, blockwidth, blockheight, TransSfx, SwizzleBlock) \ -int TransferHostLocal##psm(const void* pbyMem, u32 nQWordSize) \ -{ \ - START_HOSTLOCAL(); \ - \ - const T* pbuf = (const T*)pbyMem; \ - int nLeftOver = (nQWordSize*4*2)%(TRANSMIT_PITCH##TransSfx(2, T)); \ - int nSize = nQWordSize*4*2/TRANSMIT_PITCH##TransSfx(2, T); \ - nSize = min(nSize, gs.imageWnew * gs.imageHnew); \ - \ - int pitch, area, fracX; \ - int endY = ROUND_UPPOW2(i, blockheight); \ - int alignedY = ROUND_DOWNPOW2(gs.imageEndY, blockheight); \ - int alignedX = ROUND_DOWNPOW2(gs.imageEndX, blockwidth); \ - bool bAligned, bCanAlign = MOD_POW2(gs.trxpos.dx, blockwidth) == 0 && (j == gs.trxpos.dx) && (alignedY > endY) && alignedX > gs.trxpos.dx; \ - \ - if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { \ - /* hack */ \ - int testwidth = (int)nSize - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx); \ - if( testwidth <= widthlimit && testwidth >= -widthlimit ) { \ - /* don't transfer */ \ - /*DEBUG_LOG("bad texture %s: %d %d %d\n", #psm, gs.trxpos.dx, gs.imageEndX, nQWordSize);*/ \ - gs.imageTransfer = -1; \ - } \ - bCanAlign = false; \ - } \ - \ - /* first align on block boundary */ \ - if( MOD_POW2(i, blockheight) || !bCanAlign ) { \ - \ - if( !bCanAlign ) \ - endY = gs.imageEndY; /* transfer the whole image */ \ - else \ - assert( endY < gs.imageEndY); /* part of alignment condition */ \ - \ - if( ((gs.imageEndX-gs.trxpos.dx)%widthlimit) || ((gs.imageEndX-j)%widthlimit) ) { \ - /* transmit with a width of 1 */ \ - TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, (1+(DSTPSM == 0x14)), endY); \ - } \ - else { \ - TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, widthlimit, endY); \ - } \ - \ - if( nSize == 0 || i == gs.imageEndY ) \ - goto End; \ - } \ - \ - assert( MOD_POW2(i, blockheight) == 0 && j == gs.trxpos.dx); \ - \ - /* can align! */ \ - pitch = gs.imageEndX-gs.trxpos.dx; \ - area = pitch*blockheight; \ - fracX = gs.imageEndX-alignedX; \ - \ - /* on top of checking whether pbuf is alinged, make sure that the width is at least aligned to its limits (due to bugs in pcsx2) */ \ - bAligned = !((uptr)pbuf & 0xf) && (TRANSMIT_PITCH##TransSfx(pitch, T)&0xf) == 0; \ - \ - /* transfer aligning to blocks */ \ - for(; i < alignedY && nSize >= area; i += blockheight, nSize -= area) { \ - \ - if( bAligned || ((DSTPSM==PSMCT24) || (DSTPSM==PSMT8H) || (DSTPSM==PSMT4HH) || (DSTPSM==PSMT4HL)) ) { \ - for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH##TransSfx(blockwidth, T)/sizeof(T)) { \ - SwizzleBlock(pstart + getPixelAddress##psm##_0(tempj, i, gs.dstbuf.bw)*blockbits/8, \ - (u8*)pbuf, TRANSMIT_PITCH##TransSfx(pitch, T)); \ - } \ - } \ - else { \ - for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH##TransSfx(blockwidth, T)/sizeof(T)) { \ - SwizzleBlock##u(pstart + getPixelAddress##psm##_0(tempj, i, gs.dstbuf.bw)*blockbits/8, \ - (u8*)pbuf, TRANSMIT_PITCH##TransSfx(pitch, T)); \ - } \ - } \ - \ - /* transfer the rest */ \ - if( alignedX < gs.imageEndX ) { \ - TRANSMIT_HOSTLOCAL_X##TransSfx(psm, T, widthlimit, blockheight, alignedX); \ - pbuf -= TRANSMIT_PITCH##TransSfx((alignedX-gs.trxpos.dx), T)/sizeof(T); \ - } \ - else pbuf += (blockheight-1)*TRANSMIT_PITCH##TransSfx(pitch, T)/sizeof(T); \ - j = gs.trxpos.dx; \ - } \ - \ - if( TRANSMIT_PITCH##TransSfx(nSize, T)/4 > 0 ) { \ - TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, widthlimit, gs.imageEndY); \ - /* sometimes wrong sizes are sent (tekken tag) */ \ - assert( gs.imageTransfer == -1 || TRANSMIT_PITCH##TransSfx(nSize,T)/4 <= 2 ); \ - } \ - \ - END_HOSTLOCAL(); \ - return (nSize * TRANSMIT_PITCH##TransSfx(2, T) + nLeftOver)/2; \ -} \ - -DEFINE_TRANSFERLOCAL(32, u32, 2, 32, 8, 8, _, SwizzleBlock32); -DEFINE_TRANSFERLOCAL(32Z, u32, 2, 32, 8, 8, _, SwizzleBlock32); -DEFINE_TRANSFERLOCAL(24, u8, 8, 32, 8, 8, _24, SwizzleBlock24); -DEFINE_TRANSFERLOCAL(24Z, u8, 8, 32, 8, 8, _24, SwizzleBlock24); -DEFINE_TRANSFERLOCAL(16, u16, 4, 16, 16, 8, _, SwizzleBlock16); -DEFINE_TRANSFERLOCAL(16S, u16, 4, 16, 16, 8, _, SwizzleBlock16); -DEFINE_TRANSFERLOCAL(16Z, u16, 4, 16, 16, 8, _, SwizzleBlock16); -DEFINE_TRANSFERLOCAL(16SZ, u16, 4, 16, 16, 8, _, SwizzleBlock16); -DEFINE_TRANSFERLOCAL(8, u8, 4, 8, 16, 16, _, SwizzleBlock8); -DEFINE_TRANSFERLOCAL(4, u8, 8, 4, 32, 16, _4, SwizzleBlock4); -DEFINE_TRANSFERLOCAL(8H, u8, 4, 32, 8, 8, _, SwizzleBlock8H); -DEFINE_TRANSFERLOCAL(4HL, u8, 8, 32, 8, 8, _4, SwizzleBlock4HL); -DEFINE_TRANSFERLOCAL(4HH, u8, 8, 32, 8, 8, _4, SwizzleBlock4HH); - -//#define T u8 -//#define widthlimit 8 -//#define blockbits 4 -//#define blockwidth 32 -//#define blockheight 16 -// -//void TransferHostLocal4(const void* pbyMem, u32 nQWordSize) -//{ -// START_HOSTLOCAL(); -// -// const T* pbuf = (const T*)pbyMem; -// u32 nSize = nQWordSize*16*2/TRANSMIT_PITCH_4(2, T); -// nSize = min(nSize, gs.imageWnew * gs.imageHnew); -// -// int endY = ROUND_UPPOW2(i, blockheight); -// int alignedY = ROUND_DOWNPOW2(gs.imageEndY, blockheight); -// int alignedX = ROUND_DOWNPOW2(gs.imageEndX, blockwidth); -// bool bCanAlign = MOD_POW2(gs.trxpos.dx, blockwidth) == 0 && (j == gs.trxpos.dx) && (alignedY > endY) && alignedX > gs.trxpos.dx; -// -// if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { -// /* hack */ -// if( abs((int)nSize - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx)) <= widthlimit ) { -// /* don't transfer */ -// /*DEBUG_LOG("bad texture %s: %d %d %d\n", #psm, gs.trxpos.dx, gs.imageEndX, nQWordSize);*/ -// gs.imageTransfer = -1; -// } -// bCanAlign = false; -// } -// -// /* first align on block boundary */ -// if( MOD_POW2(i, blockheight) || !bCanAlign ) { -// -// if( !bCanAlign ) -// endY = gs.imageEndY; /* transfer the whole image */ -// else -// assert( endY < gs.imageEndY); /* part of alignment condition */ -// -// if( (DSTPSM == 0x13 || DSTPSM == 0x14) && ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) { -// /* transmit with a width of 1 */ -// TRANSMIT_HOSTLOCAL_Y_4(4, T, (1+(DSTPSM == 0x14)), endY); -// } -// else { -// TRANSMIT_HOSTLOCAL_Y_4(4, T, widthlimit, endY); -// } -// -// if( nSize == 0 || i == gs.imageEndY ) -// goto End; -// } -// -// assert( MOD_POW2(i, blockheight) == 0 && j == gs.trxpos.dx); -// -// /* can align! */ -// int pitch = gs.imageEndX-gs.trxpos.dx; -// u32 area = pitch*blockheight; -// int fracX = gs.imageEndX-alignedX; -// -// /* on top of checking whether pbuf is alinged, make sure that the width is at least aligned to its limits (due to bugs in pcsx2) */ -// bool bAligned = !((u32)pbuf & 0xf) && (TRANSMIT_PITCH_4(pitch, T)&0xf) == 0; -// -// /* transfer aligning to blocks */ -// for(; i < alignedY && nSize >= area; i += blockheight, nSize -= area) { -// -// if( bAligned || ((DSTPSM==PSMCT24) || (DSTPSM==PSMT8H) || (DSTPSM==PSMT4HH) || (DSTPSM==PSMT4HL)) ) { -// for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH_4(blockwidth, T)/sizeof(T)) { -// SwizzleBlock4(pstart + getPixelAddress4_0(tempj, i, gs.dstbuf.bw)*blockbits/8, -// (u8*)pbuf, TRANSMIT_PITCH_4(pitch, T)); -// } -// } -// else { -// for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH_4(blockwidth, T)/sizeof(T)) { -// SwizzleBlock4u(pstart + getPixelAddress4_0(tempj, i, gs.dstbuf.bw)*blockbits/8, -// (u8*)pbuf, TRANSMIT_PITCH_4(pitch, T)); -// } -// } -// -// /* transfer the rest */ -// if( alignedX < gs.imageEndX ) { -// TRANSMIT_HOSTLOCAL_X_4(4, T, widthlimit, blockheight, alignedX); -// pbuf -= TRANSMIT_PITCH_4((alignedX-gs.trxpos.dx), T)/sizeof(T); -// } -// else pbuf += (blockheight-1)*TRANSMIT_PITCH_4(pitch, T)/sizeof(T); -// j = 0; -// } -// -// if( TRANSMIT_PITCH_4(nSize, T)/4 > 0 ) { -// TRANSMIT_HOSTLOCAL_Y_4(4, T, widthlimit, gs.imageEndY); -// /* sometimes wrong sizes are sent (tekken tag) */ -// assert( gs.imageTransfer == -1 || TRANSMIT_PITCH_4(nSize,T)/4 <= 2 ); -// } -// -// END_HOSTLOCAL(); -//} - -void TransferLocalHost32(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost24(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost16(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost16S(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost8(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost4(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost8H(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost4HL(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost4HH(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost32Z(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost24Z(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost16Z(void* pbyMem, u32 nQWordSize) -{ -} - -void TransferLocalHost16SZ(void* pbyMem, u32 nQWordSize) -{ -} - -#define FILL_BLOCK(bw, bh, ox, oy, mult, psm, psmcol) { \ - b.vTexDims = Vector(BLOCK_TEXWIDTH/(float)(bw), BLOCK_TEXHEIGHT/(float)bh, 0, 0); \ - b.vTexBlock = Vector((float)bw/BLOCK_TEXWIDTH, (float)bh/BLOCK_TEXHEIGHT, ((float)ox+0.2f)/BLOCK_TEXWIDTH, ((float)oy+0.05f)/BLOCK_TEXHEIGHT); \ - b.width = bw; \ - b.height = bh; \ - b.colwidth = bh / 4; \ - b.colheight = bw / 8; \ - b.bpp = 32/mult; \ - \ - b.pageTable = &g_pageTable##psm[0][0]; \ - b.blockTable = &g_blockTable##psm[0][0]; \ - b.columnTable = &g_columnTable##psmcol[0][0]; \ - assert( sizeof(g_pageTable##psm) == bw*bh*sizeof(g_pageTable##psm[0][0]) ); \ - psrcf = (float*)&vBlockData[0] + ox + oy * BLOCK_TEXWIDTH; \ - psrcw = (u16*)&vBlockData[0] + ox + oy * BLOCK_TEXWIDTH; \ - for(i = 0; i < bh; ++i) { \ - for(j = 0; j < bw; ++j) { \ - /* fill the table */ \ - u32 u = g_blockTable##psm[(i / b.colheight)][(j / b.colwidth)] * 64 * mult + g_columnTable##psmcol[i%b.colheight][j%b.colwidth]; \ - b.pageTable[i*bw+j] = u; \ - if( floatfmt ) { \ - psrcf[i*BLOCK_TEXWIDTH+j] = (float)(u) / (float)(GPU_TEXWIDTH*mult); \ - } \ - else { \ - psrcw[i*BLOCK_TEXWIDTH+j] = u; \ - } \ - } \ - } \ - \ - if( floatfmt ) { \ - assert( floatfmt ); \ - psrcv = (Vector*)&vBilinearData[0] + ox + oy * BLOCK_TEXWIDTH; \ - for(i = 0; i < bh; ++i) { \ - for(j = 0; j < bw; ++j) { \ - Vector* pv = &psrcv[i*BLOCK_TEXWIDTH+j]; \ - pv->x = psrcf[i*BLOCK_TEXWIDTH+j]; \ - pv->y = psrcf[i*BLOCK_TEXWIDTH+((j+1)%bw)]; \ - pv->z = psrcf[((i+1)%bh)*BLOCK_TEXWIDTH+j]; \ - pv->w = psrcf[((i+1)%bh)*BLOCK_TEXWIDTH+((j+1)%bw)]; \ - } \ - } \ - } \ - b.getPixelAddress = getPixelAddress##psm; \ - b.getPixelAddress_0 = getPixelAddress##psm##_0; \ - b.writePixel = writePixel##psm; \ - b.writePixel_0 = writePixel##psm##_0; \ - b.readPixel = readPixel##psm; \ - b.readPixel_0 = readPixel##psm##_0; \ - b.TransferHostLocal = TransferHostLocal##psm; \ - b.TransferLocalHost = TransferLocalHost##psm; \ -} \ - -void BLOCK::FillBlocks(vector& vBlockData, vector& vBilinearData, int floatfmt) -{ - vBlockData.resize(BLOCK_TEXWIDTH * BLOCK_TEXHEIGHT * (floatfmt ? 4 : 2)); - if( floatfmt ) - vBilinearData.resize(BLOCK_TEXWIDTH * BLOCK_TEXHEIGHT * sizeof(Vector)); - - int i, j; - BLOCK b; - float* psrcf = NULL; - u16* psrcw = NULL; - Vector* psrcv = NULL; - - memset(m_Blocks, 0, sizeof(m_Blocks)); - - // 32 - FILL_BLOCK(64, 32, 0, 0, 1, 32, 32); - m_Blocks[PSMCT32] = b; - - // 24 (same as 32 except write/readPixel are different) - m_Blocks[PSMCT24] = b; - m_Blocks[PSMCT24].writePixel = writePixel24; - m_Blocks[PSMCT24].writePixel_0 = writePixel24_0; - m_Blocks[PSMCT24].readPixel = readPixel24; - m_Blocks[PSMCT24].readPixel_0 = readPixel24_0; - m_Blocks[PSMCT24].TransferHostLocal = TransferHostLocal24; - m_Blocks[PSMCT24].TransferLocalHost = TransferLocalHost24; - - // 8H (same as 32 except write/readPixel are different) - m_Blocks[PSMT8H] = b; - m_Blocks[PSMT8H].writePixel = writePixel8H; - m_Blocks[PSMT8H].writePixel_0 = writePixel8H_0; - m_Blocks[PSMT8H].readPixel = readPixel8H; - m_Blocks[PSMT8H].readPixel_0 = readPixel8H_0; - m_Blocks[PSMT8H].TransferHostLocal = TransferHostLocal8H; - m_Blocks[PSMT8H].TransferLocalHost = TransferLocalHost8H; - - m_Blocks[PSMT4HL] = b; - m_Blocks[PSMT4HL].writePixel = writePixel4HL; - m_Blocks[PSMT4HL].writePixel_0 = writePixel4HL_0; - m_Blocks[PSMT4HL].readPixel = readPixel4HL; - m_Blocks[PSMT4HL].readPixel_0 = readPixel4HL_0; - m_Blocks[PSMT4HL].TransferHostLocal = TransferHostLocal4HL; - m_Blocks[PSMT4HL].TransferLocalHost = TransferLocalHost4HL; - - m_Blocks[PSMT4HH] = b; - m_Blocks[PSMT4HH].writePixel = writePixel4HH; - m_Blocks[PSMT4HH].writePixel_0 = writePixel4HH_0; - m_Blocks[PSMT4HH].readPixel = readPixel4HH; - m_Blocks[PSMT4HH].readPixel_0 = readPixel4HH_0; - m_Blocks[PSMT4HH].TransferHostLocal = TransferHostLocal4HH; - m_Blocks[PSMT4HH].TransferLocalHost = TransferLocalHost4HH; - - // 32z - FILL_BLOCK(64, 32, 64, 0, 1, 32Z, 32); - m_Blocks[PSMT32Z] = b; - - // 24Z (same as 32Z except write/readPixel are different) - m_Blocks[PSMT24Z] = b; - m_Blocks[PSMT24Z].writePixel = writePixel24Z; - m_Blocks[PSMT24Z].writePixel_0 = writePixel24Z_0; - m_Blocks[PSMT24Z].readPixel = readPixel24Z; - m_Blocks[PSMT24Z].readPixel_0 = readPixel24Z_0; - m_Blocks[PSMT24Z].TransferHostLocal = TransferHostLocal24Z; - m_Blocks[PSMT24Z].TransferLocalHost = TransferLocalHost24Z; - - // 16 - FILL_BLOCK(64, 64, 0, 32, 2, 16, 16); - m_Blocks[PSMCT16] = b; - - // 16s - FILL_BLOCK(64, 64, 64, 32, 2, 16S, 16); - m_Blocks[PSMCT16S] = b; - - // 16z - FILL_BLOCK(64, 64, 0, 96, 2, 16Z, 16); - m_Blocks[PSMT16Z] = b; - - // 16sz - FILL_BLOCK(64, 64, 64, 96, 2, 16SZ, 16); - m_Blocks[PSMT16SZ] = b; - - // 8 - FILL_BLOCK(128, 64, 0, 160, 4, 8, 8); - m_Blocks[PSMT8] = b; - - // 4 - FILL_BLOCK(128, 128, 0, 224, 8, 4, 4); - m_Blocks[PSMT4] = b; -} +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 "GS.h" +#include "Mem.h" +#include "zerogs.h" +#include "targets.h" +#include "x86.h" + +u32 g_blockTable32[4][8] = { + { 0, 1, 4, 5, 16, 17, 20, 21}, + { 2, 3, 6, 7, 18, 19, 22, 23}, + { 8, 9, 12, 13, 24, 25, 28, 29}, + { 10, 11, 14, 15, 26, 27, 30, 31} +}; + +u32 g_blockTable32Z[4][8] = { + { 24, 25, 28, 29, 8, 9, 12, 13}, + { 26, 27, 30, 31, 10, 11, 14, 15}, + { 16, 17, 20, 21, 0, 1, 4, 5}, + { 18, 19, 22, 23, 2, 3, 6, 7} +}; + +u32 g_blockTable16[8][4] = { + { 0, 2, 8, 10 }, + { 1, 3, 9, 11 }, + { 4, 6, 12, 14 }, + { 5, 7, 13, 15 }, + { 16, 18, 24, 26 }, + { 17, 19, 25, 27 }, + { 20, 22, 28, 30 }, + { 21, 23, 29, 31 } +}; + +u32 g_blockTable16S[8][4] = { + { 0, 2, 16, 18 }, + { 1, 3, 17, 19 }, + { 8, 10, 24, 26 }, + { 9, 11, 25, 27 }, + { 4, 6, 20, 22 }, + { 5, 7, 21, 23 }, + { 12, 14, 28, 30 }, + { 13, 15, 29, 31 } +}; + +u32 g_blockTable16Z[8][4] = { + { 24, 26, 16, 18 }, + { 25, 27, 17, 19 }, + { 28, 30, 20, 22 }, + { 29, 31, 21, 23 }, + { 8, 10, 0, 2 }, + { 9, 11, 1, 3 }, + { 12, 14, 4, 6 }, + { 13, 15, 5, 7 } +}; + +u32 g_blockTable16SZ[8][4] = { + { 24, 26, 8, 10 }, + { 25, 27, 9, 11 }, + { 16, 18, 0, 2 }, + { 17, 19, 1, 3 }, + { 28, 30, 12, 14 }, + { 29, 31, 13, 15 }, + { 20, 22, 4, 6 }, + { 21, 23, 5, 7 } +}; + +u32 g_blockTable8[4][8] = { + { 0, 1, 4, 5, 16, 17, 20, 21}, + { 2, 3, 6, 7, 18, 19, 22, 23}, + { 8, 9, 12, 13, 24, 25, 28, 29}, + { 10, 11, 14, 15, 26, 27, 30, 31} +}; + +u32 g_blockTable4[8][4] = { + { 0, 2, 8, 10 }, + { 1, 3, 9, 11 }, + { 4, 6, 12, 14 }, + { 5, 7, 13, 15 }, + { 16, 18, 24, 26 }, + { 17, 19, 25, 27 }, + { 20, 22, 28, 30 }, + { 21, 23, 29, 31 } +}; + +u32 g_columnTable32[8][8] = { + { 0, 1, 4, 5, 8, 9, 12, 13 }, + { 2, 3, 6, 7, 10, 11, 14, 15 }, + { 16, 17, 20, 21, 24, 25, 28, 29 }, + { 18, 19, 22, 23, 26, 27, 30, 31 }, + { 32, 33, 36, 37, 40, 41, 44, 45 }, + { 34, 35, 38, 39, 42, 43, 46, 47 }, + { 48, 49, 52, 53, 56, 57, 60, 61 }, + { 50, 51, 54, 55, 58, 59, 62, 63 }, +}; + +u32 g_columnTable16[8][16] = { + { 0, 2, 8, 10, 16, 18, 24, 26, + 1, 3, 9, 11, 17, 19, 25, 27 }, + { 4, 6, 12, 14, 20, 22, 28, 30, + 5, 7, 13, 15, 21, 23, 29, 31 }, + { 32, 34, 40, 42, 48, 50, 56, 58, + 33, 35, 41, 43, 49, 51, 57, 59 }, + { 36, 38, 44, 46, 52, 54, 60, 62, + 37, 39, 45, 47, 53, 55, 61, 63 }, + { 64, 66, 72, 74, 80, 82, 88, 90, + 65, 67, 73, 75, 81, 83, 89, 91 }, + { 68, 70, 76, 78, 84, 86, 92, 94, + 69, 71, 77, 79, 85, 87, 93, 95 }, + { 96, 98, 104, 106, 112, 114, 120, 122, + 97, 99, 105, 107, 113, 115, 121, 123 }, + { 100, 102, 108, 110, 116, 118, 124, 126, + 101, 103, 109, 111, 117, 119, 125, 127 }, +}; + +u32 g_columnTable8[16][16] = { + { 0, 4, 16, 20, 32, 36, 48, 52, // column 0 + 2, 6, 18, 22, 34, 38, 50, 54 }, + { 8, 12, 24, 28, 40, 44, 56, 60, + 10, 14, 26, 30, 42, 46, 58, 62 }, + { 33, 37, 49, 53, 1, 5, 17, 21, + 35, 39, 51, 55, 3, 7, 19, 23 }, + { 41, 45, 57, 61, 9, 13, 25, 29, + 43, 47, 59, 63, 11, 15, 27, 31 }, + { 96, 100, 112, 116, 64, 68, 80, 84, // column 1 + 98, 102, 114, 118, 66, 70, 82, 86 }, + { 104, 108, 120, 124, 72, 76, 88, 92, + 106, 110, 122, 126, 74, 78, 90, 94 }, + { 65, 69, 81, 85, 97, 101, 113, 117, + 67, 71, 83, 87, 99, 103, 115, 119 }, + { 73, 77, 89, 93, 105, 109, 121, 125, + 75, 79, 91, 95, 107, 111, 123, 127 }, + { 128, 132, 144, 148, 160, 164, 176, 180, // column 2 + 130, 134, 146, 150, 162, 166, 178, 182 }, + { 136, 140, 152, 156, 168, 172, 184, 188, + 138, 142, 154, 158, 170, 174, 186, 190 }, + { 161, 165, 177, 181, 129, 133, 145, 149, + 163, 167, 179, 183, 131, 135, 147, 151 }, + { 169, 173, 185, 189, 137, 141, 153, 157, + 171, 175, 187, 191, 139, 143, 155, 159 }, + { 224, 228, 240, 244, 192, 196, 208, 212, // column 3 + 226, 230, 242, 246, 194, 198, 210, 214 }, + { 232, 236, 248, 252, 200, 204, 216, 220, + 234, 238, 250, 254, 202, 206, 218, 222 }, + { 193, 197, 209, 213, 225, 229, 241, 245, + 195, 199, 211, 215, 227, 231, 243, 247 }, + { 201, 205, 217, 221, 233, 237, 249, 253, + 203, 207, 219, 223, 235, 239, 251, 255 }, +}; + +u32 g_columnTable4[16][32] = { + { 0, 8, 32, 40, 64, 72, 96, 104, // column 0 + 2, 10, 34, 42, 66, 74, 98, 106, + 4, 12, 36, 44, 68, 76, 100, 108, + 6, 14, 38, 46, 70, 78, 102, 110 }, + { 16, 24, 48, 56, 80, 88, 112, 120, + 18, 26, 50, 58, 82, 90, 114, 122, + 20, 28, 52, 60, 84, 92, 116, 124, + 22, 30, 54, 62, 86, 94, 118, 126 }, + { 65, 73, 97, 105, 1, 9, 33, 41, + 67, 75, 99, 107, 3, 11, 35, 43, + 69, 77, 101, 109, 5, 13, 37, 45, + 71, 79, 103, 111, 7, 15, 39, 47 }, + { 81, 89, 113, 121, 17, 25, 49, 57, + 83, 91, 115, 123, 19, 27, 51, 59, + 85, 93, 117, 125, 21, 29, 53, 61, + 87, 95, 119, 127, 23, 31, 55, 63 }, + { 192, 200, 224, 232, 128, 136, 160, 168, // column 1 + 194, 202, 226, 234, 130, 138, 162, 170, + 196, 204, 228, 236, 132, 140, 164, 172, + 198, 206, 230, 238, 134, 142, 166, 174 }, + { 208, 216, 240, 248, 144, 152, 176, 184, + 210, 218, 242, 250, 146, 154, 178, 186, + 212, 220, 244, 252, 148, 156, 180, 188, + 214, 222, 246, 254, 150, 158, 182, 190 }, + { 129, 137, 161, 169, 193, 201, 225, 233, + 131, 139, 163, 171, 195, 203, 227, 235, + 133, 141, 165, 173, 197, 205, 229, 237, + 135, 143, 167, 175, 199, 207, 231, 239 }, + { 145, 153, 177, 185, 209, 217, 241, 249, + 147, 155, 179, 187, 211, 219, 243, 251, + 149, 157, 181, 189, 213, 221, 245, 253, + 151, 159, 183, 191, 215, 223, 247, 255 }, + { 256, 264, 288, 296, 320, 328, 352, 360, // column 2 + 258, 266, 290, 298, 322, 330, 354, 362, + 260, 268, 292, 300, 324, 332, 356, 364, + 262, 270, 294, 302, 326, 334, 358, 366 }, + { 272, 280, 304, 312, 336, 344, 368, 376, + 274, 282, 306, 314, 338, 346, 370, 378, + 276, 284, 308, 316, 340, 348, 372, 380, + 278, 286, 310, 318, 342, 350, 374, 382 }, + { 321, 329, 353, 361, 257, 265, 289, 297, + 323, 331, 355, 363, 259, 267, 291, 299, + 325, 333, 357, 365, 261, 269, 293, 301, + 327, 335, 359, 367, 263, 271, 295, 303 }, + { 337, 345, 369, 377, 273, 281, 305, 313, + 339, 347, 371, 379, 275, 283, 307, 315, + 341, 349, 373, 381, 277, 285, 309, 317, + 343, 351, 375, 383, 279, 287, 311, 319 }, + { 448, 456, 480, 488, 384, 392, 416, 424, // column 3 + 450, 458, 482, 490, 386, 394, 418, 426, + 452, 460, 484, 492, 388, 396, 420, 428, + 454, 462, 486, 494, 390, 398, 422, 430 }, + { 464, 472, 496, 504, 400, 408, 432, 440, + 466, 474, 498, 506, 402, 410, 434, 442, + 468, 476, 500, 508, 404, 412, 436, 444, + 470, 478, 502, 510, 406, 414, 438, 446 }, + { 385, 393, 417, 425, 449, 457, 481, 489, + 387, 395, 419, 427, 451, 459, 483, 491, + 389, 397, 421, 429, 453, 461, 485, 493, + 391, 399, 423, 431, 455, 463, 487, 495 }, + { 401, 409, 433, 441, 465, 473, 497, 505, + 403, 411, 435, 443, 467, 475, 499, 507, + 405, 413, 437, 445, 469, 477, 501, 509, + 407, 415, 439, 447, 471, 479, 503, 511 }, +}; + +u32 g_pageTable32[32][64]; +u32 g_pageTable32Z[32][64]; +u32 g_pageTable16[64][64]; +u32 g_pageTable16S[64][64]; +u32 g_pageTable16Z[64][64]; +u32 g_pageTable16SZ[64][64]; +u32 g_pageTable8[64][128]; +u32 g_pageTable4[128][128]; + +BLOCK m_Blocks[0x40]; // do so blocks are indexable +static PCSX2_ALIGNED16(u32 tempblock[64]); + +#define DSTPSM gs.dstbuf.psm + +#define START_HOSTLOCAL() \ + assert( gs.imageTransfer == 0 ); \ + u8* pstart = g_pbyGSMemory + gs.dstbuf.bp*256; \ + \ + const u8* pendbuf = (const u8*)pbyMem + nQWordSize*4; \ + int i = gs.imageY, j = gs.imageX; \ + +extern BOOL g_bSaveTrans; + +#define END_HOSTLOCAL() \ +End: \ + if( i >= gs.imageEndY ) { \ + assert( gs.imageTransfer == -1 || i == gs.imageEndY ); \ + gs.imageTransfer = -1; \ + /*int start, end; \ + ZeroGS::GetRectMemAddress(start, end, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); \ + ZeroGS::g_MemTargs.ClearRange(start, end);*/ \ + } \ + else { \ + /* update new params */ \ + gs.imageY = i; \ + gs.imageX = j; \ + } \ + +// transfers whole rows +#define TRANSMIT_HOSTLOCAL_Y_(psm, T, widthlimit, endY) { \ + assert( (nSize%widthlimit) == 0 && widthlimit <= 4 ); \ + if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { \ + /*GS_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM);*/ \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += 1, nSize -= 1, pbuf += 1) { \ + /* write as many pixel at one time as possible */ \ + writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ + } \ + } \ + } \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += widthlimit) { \ + /* write as many pixel at one time as possible */ \ + if( nSize < widthlimit ) goto End; \ + writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ + \ + if( widthlimit > 1 ) { \ + writePixel##psm##_0(pstart, (j+1)%2048, i%2048, pbuf[1], gs.dstbuf.bw); \ + \ + if( widthlimit > 2 ) { \ + writePixel##psm##_0(pstart, (j+2)%2048, i%2048, pbuf[2], gs.dstbuf.bw); \ + \ + if( widthlimit > 3 ) { \ + writePixel##psm##_0(pstart, (j+3)%2048, i%2048, pbuf[3], gs.dstbuf.bw); \ + } \ + } \ + } \ + } \ + \ + if( j >= gs.imageEndX ) { assert(j == gs.imageEndX); j = gs.trxpos.dx; } \ + else { assert( gs.imageTransfer == -1 || nSize*sizeof(T)/4 == 0 ); goto End; } \ + } \ +} \ + +// transmit until endX, don't check size since it has already been prevalidated +#define TRANSMIT_HOSTLOCAL_X_(psm, T, widthlimit, blockheight, startX) { \ + for(int tempi = 0; tempi < blockheight; ++tempi) { \ + for(j = startX; j < gs.imageEndX; j++, pbuf++) { \ + writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, pbuf[0], gs.dstbuf.bw); \ + } \ + pbuf += pitch-fracX; \ + } \ +} \ + +// transfers whole rows +#define TRANSMIT_HOSTLOCAL_Y_24(psm, T, widthlimit, endY) { \ + if( widthlimit != 8 || ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) { \ + /*GS_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM);*/ \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += 1, nSize -= 1, pbuf += 3) { \ + writePixel##psm##_0(pstart, j%2048, i%2048, *(u32*)(pbuf), gs.dstbuf.bw); \ + } \ + \ + if( j >= gs.imageEndX ) { assert(gs.imageTransfer == -1 || j == gs.imageEndX); j = gs.trxpos.dx; } \ + else { assert( gs.imageTransfer == -1 || nSize == 0 ); goto End; } \ + } \ + } \ + else { \ + assert( /*(nSize%widthlimit) == 0 &&*/ widthlimit == 8 ); \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += 3*widthlimit) { \ + if( nSize < widthlimit ) goto End; \ + /* write as many pixel at one time as possible */ \ + writePixel##psm##_0(pstart, j%2048, i%2048, *(u32*)(pbuf+0), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *(u32*)(pbuf+3), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *(u32*)(pbuf+6), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *(u32*)(pbuf+9), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *(u32*)(pbuf+12), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *(u32*)(pbuf+15), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *(u32*)(pbuf+18), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *(u32*)(pbuf+21), gs.dstbuf.bw); \ + } \ + \ + if( j >= gs.imageEndX ) { assert(gs.imageTransfer == -1 || j == gs.imageEndX); j = gs.trxpos.dx; } \ + else { \ + if( nSize < 0 ) { \ + /* extracted too much */ \ + assert( (nSize%3)==0 && nSize > -24 ); \ + j += nSize/3; \ + nSize = 0; \ + } \ + assert( gs.imageTransfer == -1 || nSize == 0 ); \ + goto End; \ + } \ + } \ + } \ +} \ + +// transmit until endX, don't check size since it has already been prevalidated +#define TRANSMIT_HOSTLOCAL_X_24(psm, T, widthlimit, blockheight, startX) { \ + for(int tempi = 0; tempi < blockheight; ++tempi) { \ + for(j = startX; j < gs.imageEndX; j++, pbuf += 3) { \ + writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, *(u32*)pbuf, gs.dstbuf.bw); \ + } \ + pbuf += 3*(pitch-fracX); \ + } \ +} \ + +// meant for 4bit transfers +#define TRANSMIT_HOSTLOCAL_Y_4(psm, T, widthlimit, endY) { \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit) { \ + /* write as many pixel at one time as possible */ \ + writePixel##psm##_0(pstart, j%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + if( widthlimit > 2 ) { \ + writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + \ + if( widthlimit > 4 ) { \ + writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + \ + if( widthlimit > 6 ) { \ + writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + } \ + } \ + } \ + } \ + \ + if( j >= gs.imageEndX ) { j = gs.trxpos.dx; } \ + else { assert( gs.imageTransfer == -1 || (nSize/32) == 0 ); goto End; } \ + } \ +} \ + +// transmit until endX, don't check size since it has already been prevalidated +#define TRANSMIT_HOSTLOCAL_X_4(psm, T, widthlimit, blockheight, startX) { \ + for(int tempi = 0; tempi < blockheight; ++tempi) { \ + for(j = startX; j < gs.imageEndX; j+=2, pbuf++) { \ + writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, pbuf[0]&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+1)%2048, (i+tempi)%2048, pbuf[0]>>4, gs.dstbuf.bw); \ + } \ + pbuf += (pitch-fracX)/2; \ + } \ +} \ + +// calculate pitch in source buffer +#define TRANSMIT_PITCH_(pitch, T) (pitch*sizeof(T)) +#define TRANSMIT_PITCH_24(pitch, T) (pitch*3) +#define TRANSMIT_PITCH_4(pitch, T) (pitch/2) + +// special swizzle macros +#define SwizzleBlock24(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 7; ++by, pblock += 8, pnewsrc += pitch-24) { \ + for(int bx = 0; bx < 8; ++bx, pnewsrc += 3) { \ + pblock[bx] = *(u32*)pnewsrc; \ + } \ + } \ + for(int bx = 0; bx < 7; ++bx, pnewsrc += 3) { \ + /* might be 1 byte out of bounds of GS memory */ \ + pblock[bx] = *(u32*)pnewsrc; \ + } \ + /* do 3 bytes for the last copy */ \ + *((u8*)pblock+28) = pnewsrc[0]; \ + *((u8*)pblock+29) = pnewsrc[1]; \ + *((u8*)pblock+30) = pnewsrc[2]; \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0x00ffffff); \ +} \ + +#define SwizzleBlock24u SwizzleBlock24 + +#define SwizzleBlock8H(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ + u32 u = *(u32*)pnewsrc; \ + pblock[0] = u<<24; \ + pblock[1] = u<<16; \ + pblock[2] = u<<8; \ + pblock[3] = u; \ + u = *(u32*)(pnewsrc+4); \ + pblock[4] = u<<24; \ + pblock[5] = u<<16; \ + pblock[6] = u<<8; \ + pblock[7] = u; \ + } \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0xff000000); \ +} \ + +#define SwizzleBlock8Hu SwizzleBlock8H + +#define SwizzleBlock4HH(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ + u32 u = *(u32*)pnewsrc; \ + pblock[0] = u<<28; \ + pblock[1] = u<<24; \ + pblock[2] = u<<20; \ + pblock[3] = u<<16; \ + pblock[4] = u<<12; \ + pblock[5] = u<<8; \ + pblock[6] = u<<4; \ + pblock[7] = u; \ + } \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0xf0000000); \ +} \ + +#define SwizzleBlock4HHu SwizzleBlock4HH + +#define SwizzleBlock4HL(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ + u32 u = *(u32*)pnewsrc; \ + pblock[0] = u<<24; \ + pblock[1] = u<<20; \ + pblock[2] = u<<16; \ + pblock[3] = u<<12; \ + pblock[4] = u<<8; \ + pblock[5] = u<<4; \ + pblock[6] = u; \ + pblock[7] = u>>4; \ + } \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0x0f000000); \ +} \ + +#define SwizzleBlock4HLu SwizzleBlock4HL + +// ------------------------ +// | Y | +// ------------------------ +// | block | | +// | aligned area | X | +// | | | +// ------------------------ +// | Y | +// ------------------------ +#define DEFINE_TRANSFERLOCAL(psm, T, widthlimit, blockbits, blockwidth, blockheight, TransSfx, SwizzleBlock) \ +int TransferHostLocal##psm(const void* pbyMem, u32 nQWordSize) \ +{ \ + START_HOSTLOCAL(); \ + \ + const T* pbuf = (const T*)pbyMem; \ + int nLeftOver = (nQWordSize*4*2)%(TRANSMIT_PITCH##TransSfx(2, T)); \ + int nSize = nQWordSize*4*2/TRANSMIT_PITCH##TransSfx(2, T); \ + nSize = min(nSize, gs.imageWnew * gs.imageHnew); \ + \ + int pitch, area, fracX; \ + int endY = ROUND_UPPOW2(i, blockheight); \ + int alignedY = ROUND_DOWNPOW2(gs.imageEndY, blockheight); \ + int alignedX = ROUND_DOWNPOW2(gs.imageEndX, blockwidth); \ + bool bAligned, bCanAlign = MOD_POW2(gs.trxpos.dx, blockwidth) == 0 && (j == gs.trxpos.dx) && (alignedY > endY) && alignedX > gs.trxpos.dx; \ + \ + if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { \ + /* hack */ \ + int testwidth = (int)nSize - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx); \ + if( testwidth <= widthlimit && testwidth >= -widthlimit ) { \ + /* don't transfer */ \ + /*DEBUG_LOG("bad texture %s: %d %d %d\n", #psm, gs.trxpos.dx, gs.imageEndX, nQWordSize);*/ \ + gs.imageTransfer = -1; \ + } \ + bCanAlign = false; \ + } \ + \ + /* first align on block boundary */ \ + if( MOD_POW2(i, blockheight) || !bCanAlign ) { \ + \ + if( !bCanAlign ) \ + endY = gs.imageEndY; /* transfer the whole image */ \ + else \ + assert( endY < gs.imageEndY); /* part of alignment condition */ \ + \ + if( ((gs.imageEndX-gs.trxpos.dx)%widthlimit) || ((gs.imageEndX-j)%widthlimit) ) { \ + /* transmit with a width of 1 */ \ + TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, (1+(DSTPSM == 0x14)), endY); \ + } \ + else { \ + TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, widthlimit, endY); \ + } \ + \ + if( nSize == 0 || i == gs.imageEndY ) \ + goto End; \ + } \ + \ + assert( MOD_POW2(i, blockheight) == 0 && j == gs.trxpos.dx); \ + \ + /* can align! */ \ + pitch = gs.imageEndX-gs.trxpos.dx; \ + area = pitch*blockheight; \ + fracX = gs.imageEndX-alignedX; \ + \ + /* on top of checking whether pbuf is alinged, make sure that the width is at least aligned to its limits (due to bugs in pcsx2) */ \ + bAligned = !((uptr)pbuf & 0xf) && (TRANSMIT_PITCH##TransSfx(pitch, T)&0xf) == 0; \ + \ + /* transfer aligning to blocks */ \ + for(; i < alignedY && nSize >= area; i += blockheight, nSize -= area) { \ + \ + if( bAligned || ((DSTPSM==PSMCT24) || (DSTPSM==PSMT8H) || (DSTPSM==PSMT4HH) || (DSTPSM==PSMT4HL)) ) { \ + for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH##TransSfx(blockwidth, T)/sizeof(T)) { \ + SwizzleBlock(pstart + getPixelAddress##psm##_0(tempj, i, gs.dstbuf.bw)*blockbits/8, \ + (u8*)pbuf, TRANSMIT_PITCH##TransSfx(pitch, T)); \ + } \ + } \ + else { \ + for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH##TransSfx(blockwidth, T)/sizeof(T)) { \ + SwizzleBlock##u(pstart + getPixelAddress##psm##_0(tempj, i, gs.dstbuf.bw)*blockbits/8, \ + (u8*)pbuf, TRANSMIT_PITCH##TransSfx(pitch, T)); \ + } \ + } \ + \ + /* transfer the rest */ \ + if( alignedX < gs.imageEndX ) { \ + TRANSMIT_HOSTLOCAL_X##TransSfx(psm, T, widthlimit, blockheight, alignedX); \ + pbuf -= TRANSMIT_PITCH##TransSfx((alignedX-gs.trxpos.dx), T)/sizeof(T); \ + } \ + else pbuf += (blockheight-1)*TRANSMIT_PITCH##TransSfx(pitch, T)/sizeof(T); \ + j = gs.trxpos.dx; \ + } \ + \ + if( TRANSMIT_PITCH##TransSfx(nSize, T)/4 > 0 ) { \ + TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, widthlimit, gs.imageEndY); \ + /* sometimes wrong sizes are sent (tekken tag) */ \ + assert( gs.imageTransfer == -1 || TRANSMIT_PITCH##TransSfx(nSize,T)/4 <= 2 ); \ + } \ + \ + END_HOSTLOCAL(); \ + return (nSize * TRANSMIT_PITCH##TransSfx(2, T) + nLeftOver)/2; \ +} \ + +DEFINE_TRANSFERLOCAL(32, u32, 2, 32, 8, 8, _, SwizzleBlock32); +DEFINE_TRANSFERLOCAL(32Z, u32, 2, 32, 8, 8, _, SwizzleBlock32); +DEFINE_TRANSFERLOCAL(24, u8, 8, 32, 8, 8, _24, SwizzleBlock24); +DEFINE_TRANSFERLOCAL(24Z, u8, 8, 32, 8, 8, _24, SwizzleBlock24); +DEFINE_TRANSFERLOCAL(16, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(16S, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(16Z, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(16SZ, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(8, u8, 4, 8, 16, 16, _, SwizzleBlock8); +DEFINE_TRANSFERLOCAL(4, u8, 8, 4, 32, 16, _4, SwizzleBlock4); +DEFINE_TRANSFERLOCAL(8H, u8, 4, 32, 8, 8, _, SwizzleBlock8H); +DEFINE_TRANSFERLOCAL(4HL, u8, 8, 32, 8, 8, _4, SwizzleBlock4HL); +DEFINE_TRANSFERLOCAL(4HH, u8, 8, 32, 8, 8, _4, SwizzleBlock4HH); + +//#define T u8 +//#define widthlimit 8 +//#define blockbits 4 +//#define blockwidth 32 +//#define blockheight 16 +// +//void TransferHostLocal4(const void* pbyMem, u32 nQWordSize) +//{ +// START_HOSTLOCAL(); +// +// const T* pbuf = (const T*)pbyMem; +// u32 nSize = nQWordSize*16*2/TRANSMIT_PITCH_4(2, T); +// nSize = min(nSize, gs.imageWnew * gs.imageHnew); +// +// int endY = ROUND_UPPOW2(i, blockheight); +// int alignedY = ROUND_DOWNPOW2(gs.imageEndY, blockheight); +// int alignedX = ROUND_DOWNPOW2(gs.imageEndX, blockwidth); +// bool bCanAlign = MOD_POW2(gs.trxpos.dx, blockwidth) == 0 && (j == gs.trxpos.dx) && (alignedY > endY) && alignedX > gs.trxpos.dx; +// +// if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { +// /* hack */ +// if( abs((int)nSize - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx)) <= widthlimit ) { +// /* don't transfer */ +// /*DEBUG_LOG("bad texture %s: %d %d %d\n", #psm, gs.trxpos.dx, gs.imageEndX, nQWordSize);*/ +// gs.imageTransfer = -1; +// } +// bCanAlign = false; +// } +// +// /* first align on block boundary */ +// if( MOD_POW2(i, blockheight) || !bCanAlign ) { +// +// if( !bCanAlign ) +// endY = gs.imageEndY; /* transfer the whole image */ +// else +// assert( endY < gs.imageEndY); /* part of alignment condition */ +// +// if( (DSTPSM == 0x13 || DSTPSM == 0x14) && ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) { +// /* transmit with a width of 1 */ +// TRANSMIT_HOSTLOCAL_Y_4(4, T, (1+(DSTPSM == 0x14)), endY); +// } +// else { +// TRANSMIT_HOSTLOCAL_Y_4(4, T, widthlimit, endY); +// } +// +// if( nSize == 0 || i == gs.imageEndY ) +// goto End; +// } +// +// assert( MOD_POW2(i, blockheight) == 0 && j == gs.trxpos.dx); +// +// /* can align! */ +// int pitch = gs.imageEndX-gs.trxpos.dx; +// u32 area = pitch*blockheight; +// int fracX = gs.imageEndX-alignedX; +// +// /* on top of checking whether pbuf is alinged, make sure that the width is at least aligned to its limits (due to bugs in pcsx2) */ +// bool bAligned = !((u32)pbuf & 0xf) && (TRANSMIT_PITCH_4(pitch, T)&0xf) == 0; +// +// /* transfer aligning to blocks */ +// for(; i < alignedY && nSize >= area; i += blockheight, nSize -= area) { +// +// if( bAligned || ((DSTPSM==PSMCT24) || (DSTPSM==PSMT8H) || (DSTPSM==PSMT4HH) || (DSTPSM==PSMT4HL)) ) { +// for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH_4(blockwidth, T)/sizeof(T)) { +// SwizzleBlock4(pstart + getPixelAddress4_0(tempj, i, gs.dstbuf.bw)*blockbits/8, +// (u8*)pbuf, TRANSMIT_PITCH_4(pitch, T)); +// } +// } +// else { +// for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH_4(blockwidth, T)/sizeof(T)) { +// SwizzleBlock4u(pstart + getPixelAddress4_0(tempj, i, gs.dstbuf.bw)*blockbits/8, +// (u8*)pbuf, TRANSMIT_PITCH_4(pitch, T)); +// } +// } +// +// /* transfer the rest */ +// if( alignedX < gs.imageEndX ) { +// TRANSMIT_HOSTLOCAL_X_4(4, T, widthlimit, blockheight, alignedX); +// pbuf -= TRANSMIT_PITCH_4((alignedX-gs.trxpos.dx), T)/sizeof(T); +// } +// else pbuf += (blockheight-1)*TRANSMIT_PITCH_4(pitch, T)/sizeof(T); +// j = 0; +// } +// +// if( TRANSMIT_PITCH_4(nSize, T)/4 > 0 ) { +// TRANSMIT_HOSTLOCAL_Y_4(4, T, widthlimit, gs.imageEndY); +// /* sometimes wrong sizes are sent (tekken tag) */ +// assert( gs.imageTransfer == -1 || TRANSMIT_PITCH_4(nSize,T)/4 <= 2 ); +// } +// +// END_HOSTLOCAL(); +//} + +void TransferLocalHost32(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost24(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16S(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost8(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost4(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost8H(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost4HL(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost4HH(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost32Z(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost24Z(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16Z(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16SZ(void* pbyMem, u32 nQWordSize) +{ +} + +#define FILL_BLOCK(bw, bh, ox, oy, mult, psm, psmcol) { \ + b.vTexDims = Vector(BLOCK_TEXWIDTH/(float)(bw), BLOCK_TEXHEIGHT/(float)bh, 0, 0); \ + b.vTexBlock = Vector((float)bw/BLOCK_TEXWIDTH, (float)bh/BLOCK_TEXHEIGHT, ((float)ox+0.2f)/BLOCK_TEXWIDTH, ((float)oy+0.05f)/BLOCK_TEXHEIGHT); \ + b.width = bw; \ + b.height = bh; \ + b.colwidth = bh / 4; \ + b.colheight = bw / 8; \ + b.bpp = 32/mult; \ + \ + b.pageTable = &g_pageTable##psm[0][0]; \ + b.blockTable = &g_blockTable##psm[0][0]; \ + b.columnTable = &g_columnTable##psmcol[0][0]; \ + assert( sizeof(g_pageTable##psm) == bw*bh*sizeof(g_pageTable##psm[0][0]) ); \ + psrcf = (float*)&vBlockData[0] + ox + oy * BLOCK_TEXWIDTH; \ + psrcw = (u16*)&vBlockData[0] + ox + oy * BLOCK_TEXWIDTH; \ + for(i = 0; i < bh; ++i) { \ + for(j = 0; j < bw; ++j) { \ + /* fill the table */ \ + u32 u = g_blockTable##psm[(i / b.colheight)][(j / b.colwidth)] * 64 * mult + g_columnTable##psmcol[i%b.colheight][j%b.colwidth]; \ + b.pageTable[i*bw+j] = u; \ + if( floatfmt ) { \ + psrcf[i*BLOCK_TEXWIDTH+j] = (float)(u) / (float)(GPU_TEXWIDTH*mult); \ + } \ + else { \ + psrcw[i*BLOCK_TEXWIDTH+j] = u; \ + } \ + } \ + } \ + \ + if( floatfmt ) { \ + assert( floatfmt ); \ + psrcv = (Vector*)&vBilinearData[0] + ox + oy * BLOCK_TEXWIDTH; \ + for(i = 0; i < bh; ++i) { \ + for(j = 0; j < bw; ++j) { \ + Vector* pv = &psrcv[i*BLOCK_TEXWIDTH+j]; \ + pv->x = psrcf[i*BLOCK_TEXWIDTH+j]; \ + pv->y = psrcf[i*BLOCK_TEXWIDTH+((j+1)%bw)]; \ + pv->z = psrcf[((i+1)%bh)*BLOCK_TEXWIDTH+j]; \ + pv->w = psrcf[((i+1)%bh)*BLOCK_TEXWIDTH+((j+1)%bw)]; \ + } \ + } \ + } \ + b.getPixelAddress = getPixelAddress##psm; \ + b.getPixelAddress_0 = getPixelAddress##psm##_0; \ + b.writePixel = writePixel##psm; \ + b.writePixel_0 = writePixel##psm##_0; \ + b.readPixel = readPixel##psm; \ + b.readPixel_0 = readPixel##psm##_0; \ + b.TransferHostLocal = TransferHostLocal##psm; \ + b.TransferLocalHost = TransferLocalHost##psm; \ +} \ + +void BLOCK::FillBlocks(vector& vBlockData, vector& vBilinearData, int floatfmt) +{ + vBlockData.resize(BLOCK_TEXWIDTH * BLOCK_TEXHEIGHT * (floatfmt ? 4 : 2)); + if( floatfmt ) + vBilinearData.resize(BLOCK_TEXWIDTH * BLOCK_TEXHEIGHT * sizeof(Vector)); + + int i, j; + BLOCK b; + float* psrcf = NULL; + u16* psrcw = NULL; + Vector* psrcv = NULL; + + memset(m_Blocks, 0, sizeof(m_Blocks)); + + // 32 + FILL_BLOCK(64, 32, 0, 0, 1, 32, 32); + m_Blocks[PSMCT32] = b; + + // 24 (same as 32 except write/readPixel are different) + m_Blocks[PSMCT24] = b; + m_Blocks[PSMCT24].writePixel = writePixel24; + m_Blocks[PSMCT24].writePixel_0 = writePixel24_0; + m_Blocks[PSMCT24].readPixel = readPixel24; + m_Blocks[PSMCT24].readPixel_0 = readPixel24_0; + m_Blocks[PSMCT24].TransferHostLocal = TransferHostLocal24; + m_Blocks[PSMCT24].TransferLocalHost = TransferLocalHost24; + + // 8H (same as 32 except write/readPixel are different) + m_Blocks[PSMT8H] = b; + m_Blocks[PSMT8H].writePixel = writePixel8H; + m_Blocks[PSMT8H].writePixel_0 = writePixel8H_0; + m_Blocks[PSMT8H].readPixel = readPixel8H; + m_Blocks[PSMT8H].readPixel_0 = readPixel8H_0; + m_Blocks[PSMT8H].TransferHostLocal = TransferHostLocal8H; + m_Blocks[PSMT8H].TransferLocalHost = TransferLocalHost8H; + + m_Blocks[PSMT4HL] = b; + m_Blocks[PSMT4HL].writePixel = writePixel4HL; + m_Blocks[PSMT4HL].writePixel_0 = writePixel4HL_0; + m_Blocks[PSMT4HL].readPixel = readPixel4HL; + m_Blocks[PSMT4HL].readPixel_0 = readPixel4HL_0; + m_Blocks[PSMT4HL].TransferHostLocal = TransferHostLocal4HL; + m_Blocks[PSMT4HL].TransferLocalHost = TransferLocalHost4HL; + + m_Blocks[PSMT4HH] = b; + m_Blocks[PSMT4HH].writePixel = writePixel4HH; + m_Blocks[PSMT4HH].writePixel_0 = writePixel4HH_0; + m_Blocks[PSMT4HH].readPixel = readPixel4HH; + m_Blocks[PSMT4HH].readPixel_0 = readPixel4HH_0; + m_Blocks[PSMT4HH].TransferHostLocal = TransferHostLocal4HH; + m_Blocks[PSMT4HH].TransferLocalHost = TransferLocalHost4HH; + + // 32z + FILL_BLOCK(64, 32, 64, 0, 1, 32Z, 32); + m_Blocks[PSMT32Z] = b; + + // 24Z (same as 32Z except write/readPixel are different) + m_Blocks[PSMT24Z] = b; + m_Blocks[PSMT24Z].writePixel = writePixel24Z; + m_Blocks[PSMT24Z].writePixel_0 = writePixel24Z_0; + m_Blocks[PSMT24Z].readPixel = readPixel24Z; + m_Blocks[PSMT24Z].readPixel_0 = readPixel24Z_0; + m_Blocks[PSMT24Z].TransferHostLocal = TransferHostLocal24Z; + m_Blocks[PSMT24Z].TransferLocalHost = TransferLocalHost24Z; + + // 16 + FILL_BLOCK(64, 64, 0, 32, 2, 16, 16); + m_Blocks[PSMCT16] = b; + + // 16s + FILL_BLOCK(64, 64, 64, 32, 2, 16S, 16); + m_Blocks[PSMCT16S] = b; + + // 16z + FILL_BLOCK(64, 64, 0, 96, 2, 16Z, 16); + m_Blocks[PSMT16Z] = b; + + // 16sz + FILL_BLOCK(64, 64, 64, 96, 2, 16SZ, 16); + m_Blocks[PSMT16SZ] = b; + + // 8 + FILL_BLOCK(128, 64, 0, 160, 4, 8, 8); + m_Blocks[PSMT8] = b; + + // 4 + FILL_BLOCK(128, 128, 0, 224, 8, 4, 4); + m_Blocks[PSMT4] = b; +} diff --git a/plugins/zerogs/opengl/Mem.h b/plugins/zerogs/opengl/Mem.h index e77f6b370c..63317313a8 100644 --- a/plugins/zerogs/opengl/Mem.h +++ b/plugins/zerogs/opengl/Mem.h @@ -1,487 +1,487 @@ -/* ZeroGS KOSMOS - * Copyright (C) 2005-2006 zerofrog@gmail.com - * - * 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 - */ - -#ifndef __MEM_H__ -#define __MEM_H__ - -#include -#include - -// works only when base is a power of 2 -#define ROUND_UPPOW2(val, base) (((val)+(base-1))&~(base-1)) -#define ROUND_DOWNPOW2(val, base) ((val)&~(base-1)) -#define MOD_POW2(val, base) ((val)&(base-1)) - -// d3d texture dims -#define BLOCK_TEXWIDTH 128 -#define BLOCK_TEXHEIGHT 512 - -// rest not visible externally -struct BLOCK -{ - BLOCK() { memset(this, 0, sizeof(BLOCK)); } - - // shader constants for this block - Vector vTexBlock; - Vector vTexDims; - int width, height; // dims of one page in pixels - int bpp; - int colwidth, colheight; - u32* pageTable; // offset inside each page - u32* blockTable; - u32* columnTable; - - u32 (*getPixelAddress)(int x, int y, u32 bp, u32 bw); - u32 (*getPixelAddress_0)(int x, int y, u32 bw); - void (*writePixel)(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw); - void (*writePixel_0)(void* pmem, int x, int y, u32 pixel, u32 bw); - u32 (*readPixel)(const void* pmem, int x, int y, u32 bp, u32 bw); - u32 (*readPixel_0)(const void* pmem, int x, int y, u32 bw); - int (*TransferHostLocal)(const void* pbyMem, u32 nQWordSize); - void (*TransferLocalHost)(void* pbyMem, u32 nQWordSize); - - // texture must be of dims BLOCK_TEXWIDTH and BLOCK_TEXHEIGHT - static void FillBlocks(std::vector& vBlockData, std::vector& vBilinearData, int floatfmt); -}; - -extern BLOCK m_Blocks[]; - -extern u32 g_blockTable32[4][8]; -extern u32 g_blockTable32Z[4][8]; -extern u32 g_blockTable16[8][4]; -extern u32 g_blockTable16S[8][4]; -extern u32 g_blockTable16Z[8][4]; -extern u32 g_blockTable16SZ[8][4]; -extern u32 g_blockTable8[4][8]; -extern u32 g_blockTable4[8][4]; - -extern u32 g_columnTable32[8][8]; -extern u32 g_columnTable16[8][16]; -extern u32 g_columnTable8[16][16]; -extern u32 g_columnTable4[16][32]; - -extern u32 g_pageTable32[32][64]; -extern u32 g_pageTable32Z[32][64]; -extern u32 g_pageTable16[64][64]; -extern u32 g_pageTable16S[64][64]; -extern u32 g_pageTable16Z[64][64]; -extern u32 g_pageTable16SZ[64][64]; -extern u32 g_pageTable8[64][128]; -extern u32 g_pageTable4[128][128]; - -static __forceinline u32 getPixelAddress32(int x, int y, u32 bp, u32 bw) { - u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); - u32 word = bp * 64 + basepage * 2048 + g_pageTable32[y&31][x&63]; - //assert (word < 0x100000); - //word = min(word, 0xfffff); - return word; -} - -static __forceinline u32 getPixelAddress32_0(int x, int y, u32 bw) { - u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); - u32 word = basepage * 2048 + g_pageTable32[y&31][x&63]; - //assert (word < 0x100000); - //word = min(word, 0xfffff); - return word; -} - -#define getPixelAddress24 getPixelAddress32 -#define getPixelAddress24_0 getPixelAddress32_0 -#define getPixelAddress8H getPixelAddress32 -#define getPixelAddress8H_0 getPixelAddress32_0 -#define getPixelAddress4HL getPixelAddress32 -#define getPixelAddress4HL_0 getPixelAddress32_0 -#define getPixelAddress4HH getPixelAddress32 -#define getPixelAddress4HH_0 getPixelAddress32_0 - -static __forceinline u32 getPixelAddress16(int x, int y, u32 bp, u32 bw) { - u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); - u32 word = bp * 128 + basepage * 4096 + g_pageTable16[y&63][x&63]; - //assert (word < 0x200000); - //word = min(word, 0x1fffff); - return word; -} - -static __forceinline u32 getPixelAddress16_0(int x, int y, u32 bw) { - u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); - u32 word = basepage * 4096 + g_pageTable16[y&63][x&63]; - //assert (word < 0x200000); - //word = min(word, 0x1fffff); - return word; -} - -static __forceinline u32 getPixelAddress16S(int x, int y, u32 bp, u32 bw) { - u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); - u32 word = bp * 128 + basepage * 4096 + g_pageTable16S[y&63][x&63]; - //assert (word < 0x200000); - //word = min(word, 0x1fffff); - return word; -} - -static __forceinline u32 getPixelAddress16S_0(int x, int y, u32 bw) { - u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); - u32 word = basepage * 4096 + g_pageTable16S[y&63][x&63]; - //assert (word < 0x200000); - //word = min(word, 0x1fffff); - return word; -} - -static __forceinline u32 getPixelAddress8(int x, int y, u32 bp, u32 bw) { - u32 basepage = ((y>>6) * ((bw+127)>>7)) + (x>>7); - u32 word = bp * 256 + basepage * 8192 + g_pageTable8[y&63][x&127]; - //assert (word < 0x400000); - //word = min(word, 0x3fffff); - return word; -} - -static __forceinline u32 getPixelAddress8_0(int x, int y, u32 bw) { - u32 basepage = ((y>>6) * ((bw+127)>>7)) + (x>>7); - u32 word = basepage * 8192 + g_pageTable8[y&63][x&127]; - //assert (word < 0x400000); - //word = min(word, 0x3fffff); - return word; -} - -static __forceinline u32 getPixelAddress4(int x, int y, u32 bp, u32 bw) { - u32 basepage = ((y>>7) * ((bw+127)>>7)) + (x>>7); - u32 word = bp * 512 + basepage * 16384 + g_pageTable4[y&127][x&127]; - //assert (word < 0x800000); - //word = min(word, 0x7fffff); - return word; -} - -static __forceinline u32 getPixelAddress4_0(int x, int y, u32 bw) { - u32 basepage = ((y>>7) * ((bw+127)>>7)) + (x>>7); - u32 word = basepage * 16384 + g_pageTable4[y&127][x&127]; - //assert (word < 0x800000); - //word = min(word, 0x7fffff); - return word; -} - -static __forceinline u32 getPixelAddress32Z(int x, int y, u32 bp, u32 bw) { - u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); - u32 word = bp * 64 + basepage * 2048 + g_pageTable32Z[y&31][x&63]; - //assert (word < 0x100000); - //word = min(word, 0xfffff); - return word; -} - -static __forceinline u32 getPixelAddress32Z_0(int x, int y, u32 bw) { - u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); - u32 word = basepage * 2048 + g_pageTable32Z[y&31][x&63]; - //assert (word < 0x100000); - //word = min(word, 0xfffff); - return word; -} - -#define getPixelAddress24Z getPixelAddress32Z -#define getPixelAddress24Z_0 getPixelAddress32Z_0 - -static __forceinline u32 getPixelAddress16Z(int x, int y, u32 bp, u32 bw) { - u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); - u32 word = bp * 128 + basepage * 4096 + g_pageTable16Z[y&63][x&63]; - //assert (word < 0x200000); - //word = min(word, 0x1fffff); - return word; -} - -static __forceinline u32 getPixelAddress16Z_0(int x, int y, u32 bw) { - u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); - u32 word = basepage * 4096 + g_pageTable16Z[y&63][x&63]; - //assert (word < 0x200000); - //word = min(word, 0x1fffff); - return word; -} - -static __forceinline u32 getPixelAddress16SZ(int x, int y, u32 bp, u32 bw) { - u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); - u32 word = bp * 128 + basepage * 4096 + g_pageTable16SZ[y&63][x&63]; - //assert (word < 0x200000); - //word = min(word, 0x1fffff); - return word; -} - -static __forceinline u32 getPixelAddress16SZ_0(int x, int y, u32 bw) { - u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); - u32 word = basepage * 4096 + g_pageTable16SZ[y&63][x&63]; - //assert (word < 0x200000); - //word = min(word, 0x1fffff); - return word; -} - -static __forceinline void writePixel32(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - ((u32*)pmem)[getPixelAddress32(x, y, bp, bw)] = pixel; -} - -static __forceinline void writePixel24(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - u8 *buf = (u8*)&((u32*)pmem)[getPixelAddress32(x, y, bp, bw)]; - u8 *pix = (u8*)&pixel; - buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; -} - -static __forceinline void writePixel16(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - ((u16*)pmem)[getPixelAddress16(x, y, bp, bw)] = pixel; -} - -static __forceinline void writePixel16S(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - ((u16*)pmem)[getPixelAddress16S(x, y, bp, bw)] = pixel; -} - -static __forceinline void writePixel8(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - ((u8*)pmem)[getPixelAddress8(x, y, bp, bw)] = pixel; -} - -static __forceinline void writePixel8H(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - ((u8*)pmem)[4*getPixelAddress32(x, y, bp, bw)+3] = pixel; -} - -static __forceinline void writePixel4(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - u32 addr = getPixelAddress4(x, y, bp, bw); - u8 pix = ((u8*)pmem)[addr/2]; - if (addr & 0x1) ((u8*)pmem)[addr/2] = (pix & 0x0f) | (pixel << 4); - else ((u8*)pmem)[addr/2] = (pix & 0xf0) | (pixel); -} - -static __forceinline void writePixel4HL(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - u8 *p = (u8*)pmem + 4*getPixelAddress4HL(x, y, bp, bw)+3; - *p = (*p & 0xf0) | pixel; -} - -static __forceinline void writePixel4HH(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - u8 *p = (u8*)pmem + 4*getPixelAddress4HH(x, y, bp, bw)+3; - *p = (*p & 0x0f) | (pixel<<4); -} - -static __forceinline void writePixel32Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - ((u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)] = pixel; -} - -static __forceinline void writePixel24Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - u8 *buf = (u8*)pmem + 4*getPixelAddress32Z(x, y, bp, bw); - u8 *pix = (u8*)&pixel; - buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; -} - -static __forceinline void writePixel16Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - ((u16*)pmem)[getPixelAddress16Z(x, y, bp, bw)] = pixel; -} - -static __forceinline void writePixel16SZ(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { - ((u16*)pmem)[getPixelAddress16SZ(x, y, bp, bw)] = pixel; -} - - -/////////////// - -static __forceinline u32 readPixel32(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u32*)pmem)[getPixelAddress32(x, y, bp, bw)]; -} - -static __forceinline u32 readPixel24(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u32*)pmem)[getPixelAddress32(x, y, bp, bw)] & 0xffffff; -} - -static __forceinline u32 readPixel16(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u16*)pmem)[getPixelAddress16(x, y, bp, bw)]; -} - -static __forceinline u32 readPixel16S(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u16*)pmem)[getPixelAddress16S(x, y, bp, bw)]; -} - -static __forceinline u32 readPixel8(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u8*)pmem)[getPixelAddress8(x, y, bp, bw)]; -} - -static __forceinline u32 readPixel8H(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u8*)pmem)[4*getPixelAddress32(x, y, bp, bw) + 3]; -} - -static __forceinline u32 readPixel4(const void* pmem, int x, int y, u32 bp, u32 bw) { - u32 addr = getPixelAddress4(x, y, bp, bw); - u8 pix = ((const u8*)pmem)[addr/2]; - if (addr & 0x1) - return pix >> 4; - else return pix & 0xf; -} - -static __forceinline u32 readPixel4HL(const void* pmem, int x, int y, u32 bp, u32 bw) { - const u8 *p = (const u8*)pmem+4*getPixelAddress4HL(x, y, bp, bw)+3; - return *p & 0x0f; -} - -static __forceinline u32 readPixel4HH(const void* pmem, int x, int y, u32 bp, u32 bw) { - const u8 *p = (const u8*)pmem+4*getPixelAddress4HH(x, y, bp, bw) + 3; - return *p >> 4; -} - -/////////////// - -static __forceinline u32 readPixel32Z(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)]; -} - -static __forceinline u32 readPixel24Z(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)] & 0xffffff; -} - -static __forceinline u32 readPixel16Z(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u16*)pmem)[getPixelAddress16Z(x, y, bp, bw)]; -} - -static __forceinline u32 readPixel16SZ(const void* pmem, int x, int y, u32 bp, u32 bw) { - return ((const u16*)pmem)[getPixelAddress16SZ(x, y, bp, bw)]; -} - -/////////////////////////////// -// Functions that take 0 bps // -/////////////////////////////// - -static __forceinline void writePixel32_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - ((u32*)pmem)[getPixelAddress32_0(x, y, bw)] = pixel; -} - -static __forceinline void writePixel24_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - u8 *buf = (u8*)&((u32*)pmem)[getPixelAddress32_0(x, y, bw)]; - u8 *pix = (u8*)&pixel; -#if defined(_MSC_VER) && defined(__x86_64__) - memcpy(buf, pix, 3); -#else - buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; -#endif -} - -static __forceinline void writePixel16_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - ((u16*)pmem)[getPixelAddress16_0(x, y, bw)] = pixel; -} - -static __forceinline void writePixel16S_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - ((u16*)pmem)[getPixelAddress16S_0(x, y, bw)] = pixel; -} - -static __forceinline void writePixel8_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - ((u8*)pmem)[getPixelAddress8_0(x, y, bw)] = pixel; -} - -static __forceinline void writePixel8H_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - ((u8*)pmem)[4*getPixelAddress32_0(x, y, bw)+3] = pixel; -} - -static __forceinline void writePixel4_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - u32 addr = getPixelAddress4_0(x, y, bw); - u8 pix = ((u8*)pmem)[addr/2]; - if (addr & 0x1) ((u8*)pmem)[addr/2] = (pix & 0x0f) | (pixel << 4); - else ((u8*)pmem)[addr/2] = (pix & 0xf0) | (pixel); -} - -static __forceinline void writePixel4HL_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - u8 *p = (u8*)pmem + 4*getPixelAddress4HL_0(x, y, bw)+3; - *p = (*p & 0xf0) | pixel; -} - -static __forceinline void writePixel4HH_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - u8 *p = (u8*)pmem + 4*getPixelAddress4HH_0(x, y, bw)+3; - *p = (*p & 0x0f) | (pixel<<4); -} - -static __forceinline void writePixel32Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - ((u32*)pmem)[getPixelAddress32Z_0(x, y, bw)] = pixel; -} - -static __forceinline void writePixel24Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - u8 *buf = (u8*)pmem + 4*getPixelAddress32Z_0(x, y, bw); - u8 *pix = (u8*)&pixel; -#if defined(_MSC_VER) && defined(__x86_64__) - memcpy(buf, pix, 3); -#else - buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; -#endif -} - -static __forceinline void writePixel16Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - ((u16*)pmem)[getPixelAddress16Z_0(x, y, bw)] = pixel; -} - -static __forceinline void writePixel16SZ_0(void* pmem, int x, int y, u32 pixel, u32 bw) { - ((u16*)pmem)[getPixelAddress16SZ_0(x, y, bw)] = pixel; -} - - -/////////////// - -static __forceinline u32 readPixel32_0(const void* pmem, int x, int y, u32 bw) { - return ((const u32*)pmem)[getPixelAddress32_0(x, y, bw)]; -} - -static __forceinline u32 readPixel24_0(const void* pmem, int x, int y, u32 bw) { - return ((const u32*)pmem)[getPixelAddress32_0(x, y, bw)] & 0xffffff; -} - -static __forceinline u32 readPixel16_0(const void* pmem, int x, int y, u32 bw) { - return ((const u16*)pmem)[getPixelAddress16_0(x, y, bw)]; -} - -static __forceinline u32 readPixel16S_0(const void* pmem, int x, int y, u32 bw) { - return ((const u16*)pmem)[getPixelAddress16S_0(x, y, bw)]; -} - -static __forceinline u32 readPixel8_0(const void* pmem, int x, int y, u32 bw) { - return ((const u8*)pmem)[getPixelAddress8_0(x, y, bw)]; -} - -static __forceinline u32 readPixel8H_0(const void* pmem, int x, int y, u32 bw) { - return ((const u8*)pmem)[4*getPixelAddress32_0(x, y, bw) + 3]; -} - -static __forceinline u32 readPixel4_0(const void* pmem, int x, int y, u32 bw) { - u32 addr = getPixelAddress4_0(x, y, bw); - u8 pix = ((const u8*)pmem)[addr/2]; - if (addr & 0x1) - return pix >> 4; - else return pix & 0xf; -} - -static __forceinline u32 readPixel4HL_0(const void* pmem, int x, int y, u32 bw) { - const u8 *p = (const u8*)pmem+4*getPixelAddress4HL_0(x, y, bw)+3; - return *p & 0x0f; -} - -static __forceinline u32 readPixel4HH_0(const void* pmem, int x, int y, u32 bw) { - const u8 *p = (const u8*)pmem+4*getPixelAddress4HH_0(x, y, bw) + 3; - return *p >> 4; -} - -/////////////// - -static __forceinline u32 readPixel32Z_0(const void* pmem, int x, int y, u32 bw) { - return ((const u32*)pmem)[getPixelAddress32Z_0(x, y, bw)]; -} - -static __forceinline u32 readPixel24Z_0(const void* pmem, int x, int y, u32 bw) { - return ((const u32*)pmem)[getPixelAddress32Z_0(x, y, bw)] & 0xffffff; -} - -static __forceinline u32 readPixel16Z_0(const void* pmem, int x, int y, u32 bw) { - return ((const u16*)pmem)[getPixelAddress16Z_0(x, y, bw)]; -} - -static __forceinline u32 readPixel16SZ_0(const void* pmem, int x, int y, u32 bw) { - return ((const u16*)pmem)[getPixelAddress16SZ_0(x, y, bw)]; -} - -#endif /* __MEM_H__ */ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#ifndef __MEM_H__ +#define __MEM_H__ + +#include +#include + +// works only when base is a power of 2 +#define ROUND_UPPOW2(val, base) (((val)+(base-1))&~(base-1)) +#define ROUND_DOWNPOW2(val, base) ((val)&~(base-1)) +#define MOD_POW2(val, base) ((val)&(base-1)) + +// d3d texture dims +#define BLOCK_TEXWIDTH 128 +#define BLOCK_TEXHEIGHT 512 + +// rest not visible externally +struct BLOCK +{ + BLOCK() { memset(this, 0, sizeof(BLOCK)); } + + // shader constants for this block + Vector vTexBlock; + Vector vTexDims; + int width, height; // dims of one page in pixels + int bpp; + int colwidth, colheight; + u32* pageTable; // offset inside each page + u32* blockTable; + u32* columnTable; + + u32 (*getPixelAddress)(int x, int y, u32 bp, u32 bw); + u32 (*getPixelAddress_0)(int x, int y, u32 bw); + void (*writePixel)(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw); + void (*writePixel_0)(void* pmem, int x, int y, u32 pixel, u32 bw); + u32 (*readPixel)(const void* pmem, int x, int y, u32 bp, u32 bw); + u32 (*readPixel_0)(const void* pmem, int x, int y, u32 bw); + int (*TransferHostLocal)(const void* pbyMem, u32 nQWordSize); + void (*TransferLocalHost)(void* pbyMem, u32 nQWordSize); + + // texture must be of dims BLOCK_TEXWIDTH and BLOCK_TEXHEIGHT + static void FillBlocks(std::vector& vBlockData, std::vector& vBilinearData, int floatfmt); +}; + +extern BLOCK m_Blocks[]; + +extern u32 g_blockTable32[4][8]; +extern u32 g_blockTable32Z[4][8]; +extern u32 g_blockTable16[8][4]; +extern u32 g_blockTable16S[8][4]; +extern u32 g_blockTable16Z[8][4]; +extern u32 g_blockTable16SZ[8][4]; +extern u32 g_blockTable8[4][8]; +extern u32 g_blockTable4[8][4]; + +extern u32 g_columnTable32[8][8]; +extern u32 g_columnTable16[8][16]; +extern u32 g_columnTable8[16][16]; +extern u32 g_columnTable4[16][32]; + +extern u32 g_pageTable32[32][64]; +extern u32 g_pageTable32Z[32][64]; +extern u32 g_pageTable16[64][64]; +extern u32 g_pageTable16S[64][64]; +extern u32 g_pageTable16Z[64][64]; +extern u32 g_pageTable16SZ[64][64]; +extern u32 g_pageTable8[64][128]; +extern u32 g_pageTable4[128][128]; + +static __forceinline u32 getPixelAddress32(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = bp * 64 + basepage * 2048 + g_pageTable32[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +static __forceinline u32 getPixelAddress32_0(int x, int y, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = basepage * 2048 + g_pageTable32[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +#define getPixelAddress24 getPixelAddress32 +#define getPixelAddress24_0 getPixelAddress32_0 +#define getPixelAddress8H getPixelAddress32 +#define getPixelAddress8H_0 getPixelAddress32_0 +#define getPixelAddress4HL getPixelAddress32 +#define getPixelAddress4HL_0 getPixelAddress32_0 +#define getPixelAddress4HH getPixelAddress32 +#define getPixelAddress4HH_0 getPixelAddress32_0 + +static __forceinline u32 getPixelAddress16(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16S(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16S[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16S_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16S[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress8(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * ((bw+127)>>7)) + (x>>7); + u32 word = bp * 256 + basepage * 8192 + g_pageTable8[y&63][x&127]; + //assert (word < 0x400000); + //word = min(word, 0x3fffff); + return word; +} + +static __forceinline u32 getPixelAddress8_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * ((bw+127)>>7)) + (x>>7); + u32 word = basepage * 8192 + g_pageTable8[y&63][x&127]; + //assert (word < 0x400000); + //word = min(word, 0x3fffff); + return word; +} + +static __forceinline u32 getPixelAddress4(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>7) * ((bw+127)>>7)) + (x>>7); + u32 word = bp * 512 + basepage * 16384 + g_pageTable4[y&127][x&127]; + //assert (word < 0x800000); + //word = min(word, 0x7fffff); + return word; +} + +static __forceinline u32 getPixelAddress4_0(int x, int y, u32 bw) { + u32 basepage = ((y>>7) * ((bw+127)>>7)) + (x>>7); + u32 word = basepage * 16384 + g_pageTable4[y&127][x&127]; + //assert (word < 0x800000); + //word = min(word, 0x7fffff); + return word; +} + +static __forceinline u32 getPixelAddress32Z(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = bp * 64 + basepage * 2048 + g_pageTable32Z[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +static __forceinline u32 getPixelAddress32Z_0(int x, int y, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = basepage * 2048 + g_pageTable32Z[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +#define getPixelAddress24Z getPixelAddress32Z +#define getPixelAddress24Z_0 getPixelAddress32Z_0 + +static __forceinline u32 getPixelAddress16Z(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16Z[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16Z_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16Z[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16SZ(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16SZ[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16SZ_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16SZ[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline void writePixel32(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u32*)pmem)[getPixelAddress32(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel24(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *buf = (u8*)&((u32*)pmem)[getPixelAddress32(x, y, bp, bw)]; + u8 *pix = (u8*)&pixel; + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +} + +static __forceinline void writePixel16(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel16S(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16S(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel8(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u8*)pmem)[getPixelAddress8(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel8H(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u8*)pmem)[4*getPixelAddress32(x, y, bp, bw)+3] = pixel; +} + +static __forceinline void writePixel4(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u32 addr = getPixelAddress4(x, y, bp, bw); + u8 pix = ((u8*)pmem)[addr/2]; + if (addr & 0x1) ((u8*)pmem)[addr/2] = (pix & 0x0f) | (pixel << 4); + else ((u8*)pmem)[addr/2] = (pix & 0xf0) | (pixel); +} + +static __forceinline void writePixel4HL(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HL(x, y, bp, bw)+3; + *p = (*p & 0xf0) | pixel; +} + +static __forceinline void writePixel4HH(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HH(x, y, bp, bw)+3; + *p = (*p & 0x0f) | (pixel<<4); +} + +static __forceinline void writePixel32Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel24Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *buf = (u8*)pmem + 4*getPixelAddress32Z(x, y, bp, bw); + u8 *pix = (u8*)&pixel; + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +} + +static __forceinline void writePixel16Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16Z(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel16SZ(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16SZ(x, y, bp, bw)] = pixel; +} + + +/////////////// + +static __forceinline u32 readPixel32(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel24(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32(x, y, bp, bw)] & 0xffffff; +} + +static __forceinline u32 readPixel16(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel16S(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16S(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel8(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u8*)pmem)[getPixelAddress8(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel8H(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u8*)pmem)[4*getPixelAddress32(x, y, bp, bw) + 3]; +} + +static __forceinline u32 readPixel4(const void* pmem, int x, int y, u32 bp, u32 bw) { + u32 addr = getPixelAddress4(x, y, bp, bw); + u8 pix = ((const u8*)pmem)[addr/2]; + if (addr & 0x1) + return pix >> 4; + else return pix & 0xf; +} + +static __forceinline u32 readPixel4HL(const void* pmem, int x, int y, u32 bp, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HL(x, y, bp, bw)+3; + return *p & 0x0f; +} + +static __forceinline u32 readPixel4HH(const void* pmem, int x, int y, u32 bp, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HH(x, y, bp, bw) + 3; + return *p >> 4; +} + +/////////////// + +static __forceinline u32 readPixel32Z(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel24Z(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)] & 0xffffff; +} + +static __forceinline u32 readPixel16Z(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16Z(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel16SZ(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16SZ(x, y, bp, bw)]; +} + +/////////////////////////////// +// Functions that take 0 bps // +/////////////////////////////// + +static __forceinline void writePixel32_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u32*)pmem)[getPixelAddress32_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel24_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *buf = (u8*)&((u32*)pmem)[getPixelAddress32_0(x, y, bw)]; + u8 *pix = (u8*)&pixel; +#if defined(_MSC_VER) && defined(__x86_64__) + memcpy(buf, pix, 3); +#else + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +#endif +} + +static __forceinline void writePixel16_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel16S_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16S_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel8_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u8*)pmem)[getPixelAddress8_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel8H_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u8*)pmem)[4*getPixelAddress32_0(x, y, bw)+3] = pixel; +} + +static __forceinline void writePixel4_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u32 addr = getPixelAddress4_0(x, y, bw); + u8 pix = ((u8*)pmem)[addr/2]; + if (addr & 0x1) ((u8*)pmem)[addr/2] = (pix & 0x0f) | (pixel << 4); + else ((u8*)pmem)[addr/2] = (pix & 0xf0) | (pixel); +} + +static __forceinline void writePixel4HL_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HL_0(x, y, bw)+3; + *p = (*p & 0xf0) | pixel; +} + +static __forceinline void writePixel4HH_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HH_0(x, y, bw)+3; + *p = (*p & 0x0f) | (pixel<<4); +} + +static __forceinline void writePixel32Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u32*)pmem)[getPixelAddress32Z_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel24Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *buf = (u8*)pmem + 4*getPixelAddress32Z_0(x, y, bw); + u8 *pix = (u8*)&pixel; +#if defined(_MSC_VER) && defined(__x86_64__) + memcpy(buf, pix, 3); +#else + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +#endif +} + +static __forceinline void writePixel16Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16Z_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel16SZ_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16SZ_0(x, y, bw)] = pixel; +} + + +/////////////// + +static __forceinline u32 readPixel32_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32_0(x, y, bw)]; +} + +static __forceinline u32 readPixel24_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32_0(x, y, bw)] & 0xffffff; +} + +static __forceinline u32 readPixel16_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16_0(x, y, bw)]; +} + +static __forceinline u32 readPixel16S_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16S_0(x, y, bw)]; +} + +static __forceinline u32 readPixel8_0(const void* pmem, int x, int y, u32 bw) { + return ((const u8*)pmem)[getPixelAddress8_0(x, y, bw)]; +} + +static __forceinline u32 readPixel8H_0(const void* pmem, int x, int y, u32 bw) { + return ((const u8*)pmem)[4*getPixelAddress32_0(x, y, bw) + 3]; +} + +static __forceinline u32 readPixel4_0(const void* pmem, int x, int y, u32 bw) { + u32 addr = getPixelAddress4_0(x, y, bw); + u8 pix = ((const u8*)pmem)[addr/2]; + if (addr & 0x1) + return pix >> 4; + else return pix & 0xf; +} + +static __forceinline u32 readPixel4HL_0(const void* pmem, int x, int y, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HL_0(x, y, bw)+3; + return *p & 0x0f; +} + +static __forceinline u32 readPixel4HH_0(const void* pmem, int x, int y, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HH_0(x, y, bw) + 3; + return *p >> 4; +} + +/////////////// + +static __forceinline u32 readPixel32Z_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z_0(x, y, bw)]; +} + +static __forceinline u32 readPixel24Z_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z_0(x, y, bw)] & 0xffffff; +} + +static __forceinline u32 readPixel16Z_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16Z_0(x, y, bw)]; +} + +static __forceinline u32 readPixel16SZ_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16SZ_0(x, y, bw)]; +} + +#endif /* __MEM_H__ */ diff --git a/plugins/zerogs/opengl/Regs.cpp b/plugins/zerogs/opengl/Regs.cpp index f092c4f9e8..09e9aa9221 100644 --- a/plugins/zerogs/opengl/Regs.cpp +++ b/plugins/zerogs/opengl/Regs.cpp @@ -1,1008 +1,1008 @@ -/* ZeroGS KOSMOS - * Copyright (C) 2005-2006 zerorog@gmail.com - * - * 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 -#include -#include -#include - -#include "GS.h" -#include "Mem.h" -#include "Regs.h" - -#include "zerogs.h" -#include "targets.h" - -const u32 g_primmult[8] = { 1, 2, 2, 3, 3, 3, 2, 0xff }; -const u32 g_primsub[8] = { 1, 2, 1, 3, 1, 1, 2, 0 }; - -#ifdef _MSC_VER -#pragma warning(disable:4244) -#endif - -GIFRegHandler g_GIFPackedRegHandlers[16] = { - GIFRegHandlerPRIM, GIFPackedRegHandlerRGBA, GIFPackedRegHandlerSTQ, GIFPackedRegHandlerUV, - GIFPackedRegHandlerXYZF2, GIFPackedRegHandlerXYZ2, GIFRegHandlerTEX0_1, GIFRegHandlerTEX0_2, - GIFRegHandlerCLAMP_1, GIFRegHandlerCLAMP_2, GIFPackedRegHandlerFOG, GIFPackedRegHandlerNull, - GIFRegHandlerXYZF3, GIFRegHandlerXYZ3, GIFPackedRegHandlerA_D, GIFPackedRegHandlerNOP }; - -GIFRegHandler g_GIFRegHandlers[] = { - GIFRegHandlerPRIM, GIFRegHandlerRGBAQ, GIFRegHandlerST, GIFRegHandlerUV, - GIFRegHandlerXYZF2, GIFRegHandlerXYZ2, GIFRegHandlerTEX0_1, GIFRegHandlerTEX0_2, - GIFRegHandlerCLAMP_1, GIFRegHandlerCLAMP_2, GIFRegHandlerFOG, GIFRegHandlerNull, - GIFRegHandlerXYZF3, GIFRegHandlerXYZ3, GIFRegHandlerNOP, GIFRegHandlerNOP, - GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, - GIFRegHandlerTEX1_1, GIFRegHandlerTEX1_2, GIFRegHandlerTEX2_1, GIFRegHandlerTEX2_2, - GIFRegHandlerXYOFFSET_1,GIFRegHandlerXYOFFSET_2,GIFRegHandlerPRMODECONT,GIFRegHandlerPRMODE, - GIFRegHandlerTEXCLUT, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, - GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerSCANMSK, GIFRegHandlerNull, - GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, - GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, - GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, - GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, - GIFRegHandlerMIPTBP1_1, GIFRegHandlerMIPTBP1_2, GIFRegHandlerMIPTBP2_1, GIFRegHandlerMIPTBP2_2, - GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerTEXA, - GIFRegHandlerNull, GIFRegHandlerFOGCOL, GIFRegHandlerNull, GIFRegHandlerTEXFLUSH, - GIFRegHandlerSCISSOR_1, GIFRegHandlerSCISSOR_2, GIFRegHandlerALPHA_1, GIFRegHandlerALPHA_2, - GIFRegHandlerDIMX, GIFRegHandlerDTHE, GIFRegHandlerCOLCLAMP, GIFRegHandlerTEST_1, - GIFRegHandlerTEST_2, GIFRegHandlerPABE, GIFRegHandlerFBA_1, GIFRegHandlerFBA_2, - GIFRegHandlerFRAME_1, GIFRegHandlerFRAME_2, GIFRegHandlerZBUF_1, GIFRegHandlerZBUF_2, - GIFRegHandlerBITBLTBUF, GIFRegHandlerTRXPOS, GIFRegHandlerTRXREG, GIFRegHandlerTRXDIR, - GIFRegHandlerHWREG, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, - GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, - GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, - GIFRegHandlerSIGNAL, GIFRegHandlerFINISH, GIFRegHandlerLABEL, GIFRegHandlerNull }; - -C_ASSERT(sizeof(g_GIFRegHandlers)/sizeof(g_GIFRegHandlers[0]) == 100 ); - -// values for keeping track of changes -u32 s_uTex1Data[2][2] = {0}, s_uClampData[2] = {0}; - -void __fastcall GIFPackedRegHandlerNull(u32* data) -{ - DEBUG_LOG("Unexpected packed reg handler %8.8lx_%8.8lx %x\n", data[0], data[1], data[2]); -} - -void __fastcall GIFPackedRegHandlerRGBA(u32* data) -{ - gs.rgba = (data[0] & 0xff) | - ((data[1] & 0xff) << 8) | - ((data[2] & 0xff) << 16) | - ((data[3] & 0xff) << 24); - gs.vertexregs.rgba = gs.rgba; - gs.vertexregs.q = gs.q; -} - -void __fastcall GIFPackedRegHandlerSTQ(u32* data) -{ - *(u32*)&gs.vertexregs.s = data[0]&0xffffff00; - *(u32*)&gs.vertexregs.t = data[1]&0xffffff00; - *(u32*)&gs.q = data[2]; -} - -void __fastcall GIFPackedRegHandlerUV(u32* data) -{ - gs.vertexregs.u = data[0] & 0x3fff; - gs.vertexregs.v = data[1] & 0x3fff; -} - -void __forceinline KICK_VERTEX2() -{ - if (++gs.primC >= (int)g_primmult[prim->prim]) - { - if (!(g_GameSettings&GAME_XENOSPECHACK) || !ZeroGS::vb[prim->ctxt].zbuf.zmsk) - (*ZeroGS::drawfn[prim->prim])(); - gs.primC -= g_primsub[prim->prim]; - } -} - -void __forceinline KICK_VERTEX3() -{ - if (++gs.primC >= (int)g_primmult[prim->prim]) - { - gs.primC -= g_primsub[prim->prim]; - if (prim->prim == 5) - { - /* tri fans need special processing */ - if (gs.nTriFanVert == gs.primIndex) - gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); - } - } -} - -void __fastcall GIFPackedRegHandlerXYZF2(u32* data) -{ - gs.vertexregs.x = (data[0] >> 0) & 0xffff; - gs.vertexregs.y = (data[1] >> 0) & 0xffff; - gs.vertexregs.z = (data[2] >> 4) & 0xffffff; - gs.vertexregs.f = (data[3] >> 4) & 0xff; - gs.gsvertex[gs.primIndex] = gs.vertexregs; - gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); - - if( data[3] & 0x8000 ) { - KICK_VERTEX3(); - } - else { - KICK_VERTEX2(); - } -} - -void __fastcall GIFPackedRegHandlerXYZ2(u32* data) -{ - gs.vertexregs.x = (data[0] >> 0) & 0xffff; - gs.vertexregs.y = (data[1] >> 0) & 0xffff; - gs.vertexregs.z = data[2]; - gs.gsvertex[gs.primIndex] = gs.vertexregs; - gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); - - if( data[3] & 0x8000 ) { - KICK_VERTEX3(); - } - else { - KICK_VERTEX2(); - } -} - -void __fastcall GIFPackedRegHandlerFOG(u32* data) -{ - gs.vertexregs.f = (data[3]&0xff0)>>4; -} - -void __fastcall GIFPackedRegHandlerA_D(u32* data) -{ - if((data[2] & 0xff) < 100) - g_GIFRegHandlers[data[2] & 0xff](data); - else - GIFRegHandlerNull(data); -} - -void __fastcall GIFPackedRegHandlerNOP(u32* data) -{ -} - -extern int g_PrevBitwiseTexX, g_PrevBitwiseTexY; - -void tex0Write(int i, u32 *data) -{ - u32 psm = (data[0] >> 20) & 0x3f; - if( psm == 9 ) psm = 1; // hmm..., ffx intro menu - - if( m_Blocks[psm].bpp == 0 ) { - // kh and others - return; - } - - ZeroGS::vb[i].uNextTex0Data[0] = data[0]; - ZeroGS::vb[i].uNextTex0Data[1] = data[1]; - ZeroGS::vb[i].bNeedTexCheck = 1; - - // don't update unless necessary - if( PSMT_ISCLUT(psm) ) { - if( ZeroGS::CheckChangeInClut(data[1], psm) ) { - // loading clut, so flush whole texture - ZeroGS::vb[i].FlushTexData(); - } - // check if csa is the same!! (ffx bisaid island, grass) - else if( (data[1]&0x1f780000) != (ZeroGS::vb[i].uCurTex0Data[1]&0x1f780000) ) { - ZeroGS::Flush(i); // flush any previous entries - } - } -} - -void tex2Write(int i, u32 *data) -{ - tex0Info& tex0 = ZeroGS::vb[i].tex0; - - if( ZeroGS::vb[i].bNeedTexCheck ) - ZeroGS::vb[i].FlushTexData(); - - u32 psm = (data[0] >> 20) & 0x3f; - if( psm == 9 ) psm = 1; // hmm..., ffx intro menu - - u32* s_uTex0Data = ZeroGS::vb[i].uCurTex0Data; - - // don't update unless necessary - if( (s_uTex0Data[0]&0x03f00000) == (data[0]&0x03f00000) ) { // psm is the same - - if( PSMT_ISCLUT(psm) ) { - // have to write the CLUT again if changed - if( (s_uTex0Data[1]&0x1fffffe0) == (data[1]&0x1fffffe0) ) { - - if( data[1]&0xe0000000 ) { - tex0.cld = (data[1]>>29)&7; - ZeroGS::texClutWrite(i); - // invalidate to make sure target didn't change! - ZeroGS::vb[i].bVarsTexSync = FALSE; - } - - return; - } - - // CSAs have to be the same! -// if( (data[1]&0xe0000000) == 0 ) { -// -// if( (s_uTex0Data[1]&0x1f100000) != (data[1]&0x1f100000) ) -// ZeroGS::Flush(i); -// -// // clut isn't going to be loaded so can ignore, but at least update CSA and CPSM! -// ZeroGS::vb[i].uCurTex0Data[1] = (ZeroGS::vb[i].uCurTex0Data[1]&0xe087ffff)|(data[1]&0x1f780000); -// -// if( ZeroGS::vb[i].tex0.cpsm <= 1 ) ZeroGS::vb[i].tex0.csa = (data[1] >> 24) & 0xf; -// else ZeroGS::vb[i].tex0.csa = (data[1] >> 24) & 0x1f; -// -// ZeroGS::vb[i].tex0.cpsm = (data[1] >> 19) & 0xe; -// -// ZeroGS::vb[i].bVarsTexSync = FALSE; -// return; -// } - - // fall through - } - else { - //ZeroGS::vb[i].bVarsTexSync = FALSE; - return; - } - } - - ZeroGS::Flush(i); - ZeroGS::vb[i].bVarsTexSync = FALSE; - ZeroGS::vb[i].bTexConstsSync = FALSE; - - s_uTex0Data[0] = (s_uTex0Data[0]&~0x03f00000)|(psm<<20); - s_uTex0Data[1] = (s_uTex0Data[1]&0x1f)|(data[1]&~0x1f); - - tex0.psm = psm; - - if( PSMT_ISCLUT(tex0.psm) ) { - tex0.cbp = (data[1] >> 5) & 0x3fff; - tex0.cpsm = (data[1] >> 19) & 0xe; - tex0.csm = (data[1] >> 23) & 0x1; - - if( tex0.cpsm <= 1 ) tex0.csa = (data[1] >> 24) & 0xf; - else tex0.csa = (data[1] >> 24) & 0x1f; - - tex0.cld = (data[1] >> 29) & 0x7; - ZeroGS::texClutWrite(i); - } -} - -__forceinline void frameWrite(int i, u32 *data) -{ - frameInfo& gsfb = ZeroGS::vb[i].gsfb; - - if( (gsfb.fbp == ((data[0] ) & 0x1ff) * 32) && - (gsfb.fbw == ((data[0] >> 16) & 0x3f) * 64) && - gsfb.psm == ((data[0] >> 24) & 0x3f) && - (gsfb.fbm == data[1]) ) { - return; - } - - ZeroGS::Flush(0); - ZeroGS::Flush(1); - - gsfb.fbp = ((data[0] ) & 0x1ff) * 32; - gsfb.fbw = ((data[0] >> 16) & 0x3f) * 64; - gsfb.psm = (data[0] >> 24) & 0x3f; - gsfb.fbm = data[1]; - - if (gsfb.fbw > 0) { - - gsfb.fbh = (1024*1024-64*gsfb.fbp) / gsfb.fbw; - gsfb.fbh &= ~0x1f; - if( gsfb.psm & 2 ) - gsfb.fbh *= 2; - if( gsfb.fbh > 1024 ) gsfb.fbh = 1024; - } - else gsfb.fbh = 0; - - if( gsfb.psm == 1 ) gsfb.fbm |= 0xff000000; - else if( gsfb.psm & 2 ) { - - } - - ZeroGS::vb[i].bNeedFrameCheck = 1; -} - -__forceinline void testWrite(int i, u32 *data) -{ - pixTest* test = &ZeroGS::vb[i].test; - - if( (*(u32*)test & 0x0007ffff) == (data[0] & 0x0007ffff) ) - return; - - ZeroGS::Flush(i); - *(u32*)test = data[0]; - -// test.ate = (data[0] ) & 0x1; -// test.atst = (data[0] >> 1) & 0x7; -// test.aref = (data[0] >> 4) & 0xff; -// test.afail = (data[0] >> 12) & 0x3; -// test.date = (data[0] >> 14) & 0x1; -// test.datm = (data[0] >> 15) & 0x1; -// test.zte = (data[0] >> 16) & 0x1; -// test.ztst = (data[0] >> 17) & 0x3; -} - -__forceinline void clampWrite(int i, u32 *data) -{ - clampInfo& clamp = ZeroGS::vb[i].clamp; - - if( s_uClampData[i] != data[0] || ((clamp.minv>>8)|(clamp.maxv<<2)) != (data[1]&0x0fff) ) { - -// if( ZeroGS::vb[i].bNeedTexCheck ) -// ZeroGS::vb[i].FlushTexData(); - - ZeroGS::Flush(i); - s_uClampData[i] = data[0]; - - clamp.wms = (data[0] ) & 0x3; - clamp.wmt = (data[0] >> 2) & 0x3; - clamp.minu = (data[0] >> 4) & 0x3ff; - clamp.maxu = (data[0] >> 14) & 0x3ff; - clamp.minv =((data[0] >> 24) & 0xff) | ((data[1] & 0x3) << 8); - clamp.maxv = (data[1] >> 2) & 0x3ff; - - ZeroGS::vb[i].bTexConstsSync = FALSE; - } -} - -void __fastcall GIFRegHandlerNull(u32* data) -{ -#ifdef _DEBUG - if( (((uptr)&data[2])&0xffff) == 0 ) - return; - - // 0x7f happens on a lot of games - if( data[2] != 0x7f && (data[0] || data[1]) ) { - DEBUG_LOG("Unexpected reg handler %x %x %x\n", data[0], data[1], data[2]); - } -#endif -} - -void __fastcall GIFRegHandlerPRIM(u32 *data) -{ - if (data[0] & ~0x3ff) { - //WARN_LOG("warning: unknown bits in prim %8.8lx_%8.8lx\n", data[1], data[0]); - } - - gs.nTriFanVert = gs.primIndex; - gs.primC = 0; - prim->prim = (data[0]) & 0x7; - gs._prim[0].prim = (data[0]) & 0x7; - gs._prim[1].prim = (data[0]) & 0x7; - gs._prim[1]._val = (data[0]>>3)&0xff; - - ZeroGS::Prim(); -} - -void __fastcall GIFRegHandlerRGBAQ(u32* data) -{ - gs.rgba = data[0]; - gs.vertexregs.rgba = data[0]; - *(u32*)&gs.vertexregs.q = data[1]; -} - -void __fastcall GIFRegHandlerST(u32* data) -{ - *(u32*)&gs.vertexregs.s = data[0]&0xffffff00; - *(u32*)&gs.vertexregs.t = data[1]&0xffffff00; - //*(u32*)&gs.q = data[2]; -} - -void __fastcall GIFRegHandlerUV(u32* data) -{ - gs.vertexregs.u = (data[0]) & 0x3fff; - gs.vertexregs.v = (data[0] >> 16) & 0x3fff; -} - -void __fastcall GIFRegHandlerXYZF2(u32* data) -{ - gs.vertexregs.x = (data[0]) & 0xffff; - gs.vertexregs.y = (data[0] >> (16)) & 0xffff; - gs.vertexregs.z = data[1] & 0xffffff; - gs.vertexregs.f = data[1] >> 24; - gs.gsvertex[gs.primIndex] = gs.vertexregs; - gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); - - KICK_VERTEX2(); -} - -void __fastcall GIFRegHandlerXYZ2(u32* data) -{ - gs.vertexregs.x = (data[0]) & 0xffff; - gs.vertexregs.y = (data[0] >> (16)) & 0xffff; - gs.vertexregs.z = data[1]; - gs.gsvertex[gs.primIndex] = gs.vertexregs; - gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); - - KICK_VERTEX2(); -} - -void __fastcall GIFRegHandlerTEX0_1(u32* data) -{ - if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { - return; - } - tex0Write(0, data); -} - -void __fastcall GIFRegHandlerTEX0_2(u32* data) -{ - if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) { - return; - } - tex0Write(1, data); -} - -void __fastcall GIFRegHandlerCLAMP_1(u32* data) -{ - if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { - return; - } - clampWrite(0, data); -} - -void __fastcall GIFRegHandlerCLAMP_2(u32* data) -{ - if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) { - return; - } - clampWrite(1, data); -} - -void __fastcall GIFRegHandlerFOG(u32* data) -{ - //gs.gsvertex[gs.primIndex].f = (data[1] >> 24); // shift to upper bits - gs.vertexregs.f = data[1]>>24; -} - -void __fastcall GIFRegHandlerXYZF3(u32* data) -{ - gs.vertexregs.x = (data[0]) & 0xffff; - gs.vertexregs.y = (data[0] >> (16)) & 0xffff; - gs.vertexregs.z = data[1] & 0xffffff; - gs.vertexregs.f = data[1] >> 24; - gs.gsvertex[gs.primIndex] = gs.vertexregs; - gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); - - KICK_VERTEX3(); -} - -void __fastcall GIFRegHandlerXYZ3(u32* data) -{ - gs.vertexregs.x = (data[0]) & 0xffff; - gs.vertexregs.y = (data[0] >> (16)) & 0xffff; - gs.vertexregs.z = data[1]; - gs.gsvertex[gs.primIndex] = gs.vertexregs; - gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); - - KICK_VERTEX3(); -} - -void __fastcall GIFRegHandlerNOP(u32* data) -{ -} - -void tex1Write(int i, u32* data) -{ - tex1Info& tex1 = ZeroGS::vb[i].tex1; - - if( conf.bilinear == 1 && (tex1.mmag != ((data[0] >> 5) & 0x1) || tex1.mmin != ((data[0] >> 6) & 0x7)) ) { - ZeroGS::Flush(i); - ZeroGS::vb[i].bVarsTexSync = FALSE; - } - tex1.lcm = (data[0] ) & 0x1; - tex1.mxl = (data[0] >> 2) & 0x7; - tex1.mmag = (data[0] >> 5) & 0x1; - tex1.mmin = (data[0] >> 6) & 0x7; - tex1.mtba = (data[0] >> 9) & 0x1; - tex1.l = (data[0] >> 19) & 0x3; - tex1.k = (data[1] >> 4) & 0xff; -} - -void __fastcall GIFRegHandlerTEX1_1(u32* data) -{ - if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { - return; - } - - tex1Write(0, data); -} - -void __fastcall GIFRegHandlerTEX1_2(u32* data) -{ - if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) - return; - - tex1Write(1, data); -} - -void __fastcall GIFRegHandlerTEX2_1(u32* data) -{ - tex2Write(0, data); -} - -void __fastcall GIFRegHandlerTEX2_2(u32* data) -{ - tex2Write(1, data); -} - -void __fastcall GIFRegHandlerXYOFFSET_1(u32* data) -{ - // eliminator low 4 bits for now - ZeroGS::vb[0].offset.x = (data[0]) & 0xffff; - ZeroGS::vb[0].offset.y = (data[1]) & 0xffff; - -// if( !conf.interlace ) { -// ZeroGS::vb[0].offset.x &= ~15; -// ZeroGS::vb[0].offset.y &= ~15; -// } -} - -void __fastcall GIFRegHandlerXYOFFSET_2(u32* data) -{ - ZeroGS::vb[1].offset.x = (data[0]) & 0xffff; - ZeroGS::vb[1].offset.y = (data[1]) & 0xffff; - -// if( !conf.interlace ) { -// ZeroGS::vb[1].offset.x &= ~15; -// ZeroGS::vb[1].offset.y &= ~15; -// } -} - -void __fastcall GIFRegHandlerPRMODECONT(u32* data) -{ - gs.prac = data[0] & 0x1; - prim = &gs._prim[gs.prac]; - - ZeroGS::Prim(); -} - -void __fastcall GIFRegHandlerPRMODE(u32* data) -{ - gs._prim[0]._val = (data[0]>>3)&0xff; - - if (gs.prac == 0) - ZeroGS::Prim(); -} - -void __fastcall GIFRegHandlerTEXCLUT(u32* data) -{ - if( ZeroGS::vb[0].bNeedTexCheck ) - ZeroGS::vb[0].FlushTexData(); - if( ZeroGS::vb[1].bNeedTexCheck ) - ZeroGS::vb[1].FlushTexData(); - gs.clut.cbw = ((data[0] ) & 0x3f) * 64; - gs.clut.cou = ((data[0] >> 6) & 0x3f) * 16; - gs.clut.cov = (data[0] >> 12) & 0x3ff; -} - -void __fastcall GIFRegHandlerSCANMSK(u32* data) -{ -// ZeroGS::Flush(0); -// ZeroGS::Flush(1); -// ZeroGS::ResolveC(&ZeroGS::vb[0]); -// ZeroGS::ResolveZ(&ZeroGS::vb[0]); - - gs.smask = data[0] & 0x3; -} - -void __fastcall GIFRegHandlerMIPTBP1_1(u32* data) -{ - miptbpInfo& miptbp0 = ZeroGS::vb[0].miptbp0; - miptbp0.tbp[0] = (data[0] ) & 0x3fff; - miptbp0.tbw[0] = (data[0] >> 14) & 0x3f; - miptbp0.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); - miptbp0.tbw[1] = (data[1] >> 2) & 0x3f; - miptbp0.tbp[2] = (data[1] >> 8) & 0x3fff; - miptbp0.tbw[2] = (data[1] >> 22) & 0x3f; -} - -void __fastcall GIFRegHandlerMIPTBP1_2(u32* data) -{ - miptbpInfo& miptbp0 = ZeroGS::vb[1].miptbp0; - miptbp0.tbp[0] = (data[0] ) & 0x3fff; - miptbp0.tbw[0] = (data[0] >> 14) & 0x3f; - miptbp0.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); - miptbp0.tbw[1] = (data[1] >> 2) & 0x3f; - miptbp0.tbp[2] = (data[1] >> 8) & 0x3fff; - miptbp0.tbw[2] = (data[1] >> 22) & 0x3f; -} - -void __fastcall GIFRegHandlerMIPTBP2_1(u32* data) -{ - miptbpInfo& miptbp1 = ZeroGS::vb[0].miptbp1; - miptbp1.tbp[0] = (data[0] ) & 0x3fff; - miptbp1.tbw[0] = (data[0] >> 14) & 0x3f; - miptbp1.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); - miptbp1.tbw[1] = (data[1] >> 2) & 0x3f; - miptbp1.tbp[2] = (data[1] >> 8) & 0x3fff; - miptbp1.tbw[2] = (data[1] >> 22) & 0x3f; -} - -void __fastcall GIFRegHandlerMIPTBP2_2(u32* data) -{ - miptbpInfo& miptbp1 = ZeroGS::vb[1].miptbp1; - miptbp1.tbp[0] = (data[0] ) & 0x3fff; - miptbp1.tbw[0] = (data[0] >> 14) & 0x3f; - miptbp1.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); - miptbp1.tbw[1] = (data[1] >> 2) & 0x3f; - miptbp1.tbp[2] = (data[1] >> 8) & 0x3fff; - miptbp1.tbw[2] = (data[1] >> 22) & 0x3f; -} - -void __fastcall GIFRegHandlerTEXA(u32* data) -{ - texaInfo newinfo; - newinfo.aem = (data[0] >> 15) & 0x1; - newinfo.ta[0] = data[0] & 0xff; - newinfo.ta[1] = data[1] & 0xff; - - if( *(u32*)&newinfo != *(u32*)&gs.texa ) { - ZeroGS::Flush(0); - ZeroGS::Flush(1); - *(u32*)&gs.texa = *(u32*)&newinfo; - gs.texa.fta[0] = newinfo.ta[0]/255.0f; - gs.texa.fta[1] = newinfo.ta[1]/255.0f; - - ZeroGS::vb[0].bTexConstsSync = FALSE; - ZeroGS::vb[1].bTexConstsSync = FALSE; - } -} - -void __fastcall GIFRegHandlerFOGCOL(u32* data) -{ - ZeroGS::SetFogColor(data[0]&0xffffff); -} - -void __fastcall GIFRegHandlerTEXFLUSH(u32* data) -{ - ZeroGS::SetTexFlush(); -} - -void __fastcall GIFRegHandlerSCISSOR_1(u32* data) -{ - Rect2& scissor = ZeroGS::vb[0].scissor; - - Rect2 newscissor; - - newscissor.x0 = ((data[0] ) & 0x7ff) << 3; - newscissor.x1 = ((data[0] >> 16) & 0x7ff) << 3; - newscissor.y0 = ((data[1] ) & 0x7ff) << 3; - newscissor.y1 = ((data[1] >> 16) & 0x7ff) << 3; - - if( newscissor.x1 != scissor.x1 || newscissor.y1 != scissor.y1 || - newscissor.x0 != scissor.x0 || newscissor.y0 != scissor.y0 ) { - - ZeroGS::Flush(0); - scissor = newscissor; - - ZeroGS::vb[0].bNeedFrameCheck = 1; - } -} - -void __fastcall GIFRegHandlerSCISSOR_2(u32* data) -{ - Rect2& scissor = ZeroGS::vb[1].scissor; - - Rect2 newscissor; - - newscissor.x0 = ((data[0] ) & 0x7ff) << 3; - newscissor.x1 = ((data[0] >> 16) & 0x7ff) << 3; - newscissor.y0 = ((data[1] ) & 0x7ff) << 3; - newscissor.y1 = ((data[1] >> 16) & 0x7ff) << 3; - - if( newscissor.x1 != scissor.x1 || newscissor.y1 != scissor.y1 || - newscissor.x0 != scissor.x0 || newscissor.y0 != scissor.y0 ) { - - ZeroGS::Flush(1); - scissor = newscissor; - - // flush everything - ZeroGS::vb[1].bNeedFrameCheck = 1; - } -} - -void __fastcall GIFRegHandlerALPHA_1(u32* data) -{ - alphaInfo newalpha; - newalpha.abcd = *(u8*)data; - newalpha.fix = *(u8*)(data+1); - - if( *(u16*)&newalpha != *(u16*)&ZeroGS::vb[0].alpha ) { - ZeroGS::Flush(0); - - if( newalpha.a == 3 ) newalpha.a = 0; - if( newalpha.b == 3 ) newalpha.b = 0; - if( newalpha.c == 3 ) newalpha.c = 0; - if( newalpha.d == 3 ) newalpha.d = 0; - - *(u16*)&ZeroGS::vb[0].alpha = *(u16*)&newalpha; - } -} - -void __fastcall GIFRegHandlerALPHA_2(u32* data) -{ - alphaInfo newalpha; - newalpha.abcd = *(u8*)data; - newalpha.fix = *(u8*)(data+1); - - if( *(u16*)&newalpha != *(u16*)&ZeroGS::vb[1].alpha ) { - ZeroGS::Flush(1); - - if( newalpha.a == 3 ) newalpha.a = 0; - if( newalpha.b == 3 ) newalpha.b = 0; - if( newalpha.c == 3 ) newalpha.c = 0; - if( newalpha.d == 3 ) newalpha.d = 0; - - *(u16*)&ZeroGS::vb[1].alpha = *(u16*)&newalpha; - } -} - -void __fastcall GIFRegHandlerDIMX(u32* data) -{ -} - -void __fastcall GIFRegHandlerDTHE(u32* data) -{ - gs.dthe = data[0] & 0x1; -} - -void __fastcall GIFRegHandlerCOLCLAMP(u32* data) -{ - gs.colclamp = data[0] & 0x1; -} - -void __fastcall GIFRegHandlerTEST_1(u32* data) -{ - testWrite(0, data); -} - -void __fastcall GIFRegHandlerTEST_2(u32* data) -{ - testWrite(1, data); -} - -void __fastcall GIFRegHandlerPABE(u32* data) -{ - //ZeroGS::SetAlphaChanged(0, GPUREG_PABE); - //ZeroGS::SetAlphaChanged(1, GPUREG_PABE); - ZeroGS::Flush(0); - ZeroGS::Flush(1); - - gs.pabe = *data & 0x1; -} - -void __fastcall GIFRegHandlerFBA_1(u32* data) -{ - ZeroGS::Flush(0); - ZeroGS::Flush(1); - ZeroGS::vb[0].fba.fba = *data & 0x1; -} - -void __fastcall GIFRegHandlerFBA_2(u32* data) -{ - ZeroGS::Flush(0); - ZeroGS::Flush(1); - ZeroGS::vb[1].fba.fba = *data & 0x1; -} - -void __fastcall GIFRegHandlerFRAME_1(u32* data) -{ - frameWrite(0, data); -} - -void __fastcall GIFRegHandlerFRAME_2(u32* data) -{ - frameWrite(1, data); -} - -void __fastcall GIFRegHandlerZBUF_1(u32* data) -{ - zbufInfo& zbuf = ZeroGS::vb[0].zbuf; - - int psm = (0x30|((data[0] >> 24) & 0xf)); - if( zbuf.zbp == (data[0] & 0x1ff) * 32 && - zbuf.psm == psm && - zbuf.zmsk == (data[1] & 0x1) ) { - return; - } - - // error detection - if( m_Blocks[psm].bpp == 0 ) - return; - - ZeroGS::Flush(0); - ZeroGS::Flush(1); - - zbuf.zbp = (data[0] & 0x1ff) * 32; - zbuf.psm = 0x30|((data[0] >> 24) & 0xf); - zbuf.zmsk = data[1] & 0x1; - - ZeroGS::vb[0].zprimmask = 0xffffffff; - if( zbuf.psm > 0x31 ) ZeroGS::vb[0].zprimmask = 0xffff; - - ZeroGS::vb[0].bNeedZCheck = 1; -} - -void __fastcall GIFRegHandlerZBUF_2(u32* data) -{ - zbufInfo& zbuf = ZeroGS::vb[1].zbuf; - - int psm = (0x30|((data[0] >> 24) & 0xf)); - if( zbuf.zbp == (data[0] & 0x1ff) * 32 && - zbuf.psm == psm && - zbuf.zmsk == (data[1] & 0x1) ) { - return; - } - - // error detection - if( m_Blocks[psm].bpp == 0 ) - return; - - ZeroGS::Flush(0); - ZeroGS::Flush(1); - - zbuf.zbp = (data[0] & 0x1ff) * 32; - zbuf.psm = 0x30|((data[0] >> 24) & 0xf); - zbuf.zmsk = data[1] & 0x1; - - ZeroGS::vb[1].bNeedZCheck = 1; - - ZeroGS::vb[1].zprimmask = 0xffffffff; - if( zbuf.psm > 0x31 ) ZeroGS::vb[1].zprimmask = 0xffff; -} - -void __fastcall GIFRegHandlerBITBLTBUF(u32* data) -{ - gs.srcbufnew.bp = ((data[0] ) & 0x3fff);// * 64; - gs.srcbufnew.bw = ((data[0] >> 16) & 0x3f) * 64; - gs.srcbufnew.psm = (data[0] >> 24) & 0x3f; - gs.dstbufnew.bp = ((data[1] ) & 0x3fff);// * 64; - gs.dstbufnew.bw = ((data[1] >> 16) & 0x3f) * 64; - gs.dstbufnew.psm = (data[1] >> 24) & 0x3f; - - if (gs.dstbufnew.bw == 0) gs.dstbufnew.bw = 64; -} - -void __fastcall GIFRegHandlerTRXPOS(u32* data) -{ - gs.trxposnew.sx = (data[0] ) & 0x7ff; - gs.trxposnew.sy = (data[0] >> 16) & 0x7ff; - gs.trxposnew.dx = (data[1] ) & 0x7ff; - gs.trxposnew.dy = (data[1] >> 16) & 0x7ff; - gs.trxposnew.dir = (data[1] >> 27) & 0x3; -} - -void __fastcall GIFRegHandlerTRXREG(u32* data) -{ - gs.imageWtemp = data[0]&0xfff; - gs.imageHtemp = data[1]&0xfff; -} - -void __fastcall GIFRegHandlerTRXDIR(u32* data) -{ - // terminate any previous transfers - switch( gs.imageTransfer ) { - case 0: // host->loc - gs.imageTransfer = -1; - break; - case 1: // loc->host - ZeroGS::TerminateLocalHost(); - break; - } - - gs.srcbuf = gs.srcbufnew; - gs.dstbuf = gs.dstbufnew; - gs.trxpos = gs.trxposnew; - gs.imageTransfer = data[0] & 0x3; - gs.imageWnew = gs.imageWtemp; - gs.imageHnew = gs.imageHtemp; - - if( gs.imageWnew > 0 && gs.imageHnew > 0 ) { - switch(gs.imageTransfer) { - case 0: // host->loc - ZeroGS::InitTransferHostLocal(); - break; - - case 1: // loc->host - - ZeroGS::InitTransferLocalHost(); - break; - case 2: - - ZeroGS::TransferLocalLocal(); - break; - - case 3: - gs.imageTransfer = -1; - break; - - default: assert(0); - } - } - else { -#ifndef RELEASE_TO_PUBLIC - WARN_LOG("ZeroGS: dummy transfer\n"); -#endif - gs.imageTransfer = -1; - } -} - -static u32 oldhw[4]; -void __fastcall GIFRegHandlerHWREG(u32* data) -{ - if( gs.imageTransfer == 0 ) { - ZeroGS::TransferHostLocal(data, 2); - } - else { -#ifndef RELEASE_TO_PUBLIC - ERROR_LOG("ZeroGS: HWREG!? %8.8x_%8.8x\n", data[0], data[1]); - //assert(0); -#endif - } -} - -extern int g_GSMultiThreaded; - -void __fastcall GIFRegHandlerSIGNAL(u32* data) -{ - if(!g_GSMultiThreaded) { - SIGLBLID->SIGID = (SIGLBLID->SIGID&~data[1])|(data[0]&data[1]); - -// if (gs.CSRw & 0x1) CSR->SIGNAL = 1; -// if (!IMR->SIGMSK && GSirq) -// GSirq(); - - if (gs.CSRw & 0x1) { - CSR->SIGNAL = 1; - //gs.CSRw &= ~1; - } - if (!IMR->SIGMSK && GSirq) - GSirq(); - } -} - -void __fastcall GIFRegHandlerFINISH(u32* data) -{ - if(!g_GSMultiThreaded) { - - if (gs.CSRw & 0x2) - CSR->FINISH = 1; - if (!IMR->FINISHMSK && GSirq) - GSirq(); - -// if( gs.CSRw & 2 ) { -// //gs.CSRw &= ~2; -// //CSR->FINISH = 0; -// -// -// } -// CSR->FINISH = 1; -// -// if( !IMR->FINISHMSK && GSirq ) -// GSirq(); - } -} - -void __fastcall GIFRegHandlerLABEL(u32* data) -{ - if(!g_GSMultiThreaded) { - SIGLBLID->LBLID = (SIGLBLID->LBLID&~data[1])|(data[0]&data[1]); - } -} +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerorog@gmail.com + * + * 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 +#include +#include +#include + +#include "GS.h" +#include "Mem.h" +#include "Regs.h" + +#include "zerogs.h" +#include "targets.h" + +const u32 g_primmult[8] = { 1, 2, 2, 3, 3, 3, 2, 0xff }; +const u32 g_primsub[8] = { 1, 2, 1, 3, 1, 1, 2, 0 }; + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif + +GIFRegHandler g_GIFPackedRegHandlers[16] = { + GIFRegHandlerPRIM, GIFPackedRegHandlerRGBA, GIFPackedRegHandlerSTQ, GIFPackedRegHandlerUV, + GIFPackedRegHandlerXYZF2, GIFPackedRegHandlerXYZ2, GIFRegHandlerTEX0_1, GIFRegHandlerTEX0_2, + GIFRegHandlerCLAMP_1, GIFRegHandlerCLAMP_2, GIFPackedRegHandlerFOG, GIFPackedRegHandlerNull, + GIFRegHandlerXYZF3, GIFRegHandlerXYZ3, GIFPackedRegHandlerA_D, GIFPackedRegHandlerNOP }; + +GIFRegHandler g_GIFRegHandlers[] = { + GIFRegHandlerPRIM, GIFRegHandlerRGBAQ, GIFRegHandlerST, GIFRegHandlerUV, + GIFRegHandlerXYZF2, GIFRegHandlerXYZ2, GIFRegHandlerTEX0_1, GIFRegHandlerTEX0_2, + GIFRegHandlerCLAMP_1, GIFRegHandlerCLAMP_2, GIFRegHandlerFOG, GIFRegHandlerNull, + GIFRegHandlerXYZF3, GIFRegHandlerXYZ3, GIFRegHandlerNOP, GIFRegHandlerNOP, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerTEX1_1, GIFRegHandlerTEX1_2, GIFRegHandlerTEX2_1, GIFRegHandlerTEX2_2, + GIFRegHandlerXYOFFSET_1,GIFRegHandlerXYOFFSET_2,GIFRegHandlerPRMODECONT,GIFRegHandlerPRMODE, + GIFRegHandlerTEXCLUT, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerSCANMSK, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerMIPTBP1_1, GIFRegHandlerMIPTBP1_2, GIFRegHandlerMIPTBP2_1, GIFRegHandlerMIPTBP2_2, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerTEXA, + GIFRegHandlerNull, GIFRegHandlerFOGCOL, GIFRegHandlerNull, GIFRegHandlerTEXFLUSH, + GIFRegHandlerSCISSOR_1, GIFRegHandlerSCISSOR_2, GIFRegHandlerALPHA_1, GIFRegHandlerALPHA_2, + GIFRegHandlerDIMX, GIFRegHandlerDTHE, GIFRegHandlerCOLCLAMP, GIFRegHandlerTEST_1, + GIFRegHandlerTEST_2, GIFRegHandlerPABE, GIFRegHandlerFBA_1, GIFRegHandlerFBA_2, + GIFRegHandlerFRAME_1, GIFRegHandlerFRAME_2, GIFRegHandlerZBUF_1, GIFRegHandlerZBUF_2, + GIFRegHandlerBITBLTBUF, GIFRegHandlerTRXPOS, GIFRegHandlerTRXREG, GIFRegHandlerTRXDIR, + GIFRegHandlerHWREG, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerSIGNAL, GIFRegHandlerFINISH, GIFRegHandlerLABEL, GIFRegHandlerNull }; + +C_ASSERT(sizeof(g_GIFRegHandlers)/sizeof(g_GIFRegHandlers[0]) == 100 ); + +// values for keeping track of changes +u32 s_uTex1Data[2][2] = {0}, s_uClampData[2] = {0}; + +void __fastcall GIFPackedRegHandlerNull(u32* data) +{ + DEBUG_LOG("Unexpected packed reg handler %8.8lx_%8.8lx %x\n", data[0], data[1], data[2]); +} + +void __fastcall GIFPackedRegHandlerRGBA(u32* data) +{ + gs.rgba = (data[0] & 0xff) | + ((data[1] & 0xff) << 8) | + ((data[2] & 0xff) << 16) | + ((data[3] & 0xff) << 24); + gs.vertexregs.rgba = gs.rgba; + gs.vertexregs.q = gs.q; +} + +void __fastcall GIFPackedRegHandlerSTQ(u32* data) +{ + *(u32*)&gs.vertexregs.s = data[0]&0xffffff00; + *(u32*)&gs.vertexregs.t = data[1]&0xffffff00; + *(u32*)&gs.q = data[2]; +} + +void __fastcall GIFPackedRegHandlerUV(u32* data) +{ + gs.vertexregs.u = data[0] & 0x3fff; + gs.vertexregs.v = data[1] & 0x3fff; +} + +void __forceinline KICK_VERTEX2() +{ + if (++gs.primC >= (int)g_primmult[prim->prim]) + { + if (!(g_GameSettings&GAME_XENOSPECHACK) || !ZeroGS::vb[prim->ctxt].zbuf.zmsk) + (*ZeroGS::drawfn[prim->prim])(); + gs.primC -= g_primsub[prim->prim]; + } +} + +void __forceinline KICK_VERTEX3() +{ + if (++gs.primC >= (int)g_primmult[prim->prim]) + { + gs.primC -= g_primsub[prim->prim]; + if (prim->prim == 5) + { + /* tri fans need special processing */ + if (gs.nTriFanVert == gs.primIndex) + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + } + } +} + +void __fastcall GIFPackedRegHandlerXYZF2(u32* data) +{ + gs.vertexregs.x = (data[0] >> 0) & 0xffff; + gs.vertexregs.y = (data[1] >> 0) & 0xffff; + gs.vertexregs.z = (data[2] >> 4) & 0xffffff; + gs.vertexregs.f = (data[3] >> 4) & 0xff; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + + if( data[3] & 0x8000 ) { + KICK_VERTEX3(); + } + else { + KICK_VERTEX2(); + } +} + +void __fastcall GIFPackedRegHandlerXYZ2(u32* data) +{ + gs.vertexregs.x = (data[0] >> 0) & 0xffff; + gs.vertexregs.y = (data[1] >> 0) & 0xffff; + gs.vertexregs.z = data[2]; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + + if( data[3] & 0x8000 ) { + KICK_VERTEX3(); + } + else { + KICK_VERTEX2(); + } +} + +void __fastcall GIFPackedRegHandlerFOG(u32* data) +{ + gs.vertexregs.f = (data[3]&0xff0)>>4; +} + +void __fastcall GIFPackedRegHandlerA_D(u32* data) +{ + if((data[2] & 0xff) < 100) + g_GIFRegHandlers[data[2] & 0xff](data); + else + GIFRegHandlerNull(data); +} + +void __fastcall GIFPackedRegHandlerNOP(u32* data) +{ +} + +extern int g_PrevBitwiseTexX, g_PrevBitwiseTexY; + +void tex0Write(int i, u32 *data) +{ + u32 psm = (data[0] >> 20) & 0x3f; + if( psm == 9 ) psm = 1; // hmm..., ffx intro menu + + if( m_Blocks[psm].bpp == 0 ) { + // kh and others + return; + } + + ZeroGS::vb[i].uNextTex0Data[0] = data[0]; + ZeroGS::vb[i].uNextTex0Data[1] = data[1]; + ZeroGS::vb[i].bNeedTexCheck = 1; + + // don't update unless necessary + if( PSMT_ISCLUT(psm) ) { + if( ZeroGS::CheckChangeInClut(data[1], psm) ) { + // loading clut, so flush whole texture + ZeroGS::vb[i].FlushTexData(); + } + // check if csa is the same!! (ffx bisaid island, grass) + else if( (data[1]&0x1f780000) != (ZeroGS::vb[i].uCurTex0Data[1]&0x1f780000) ) { + ZeroGS::Flush(i); // flush any previous entries + } + } +} + +void tex2Write(int i, u32 *data) +{ + tex0Info& tex0 = ZeroGS::vb[i].tex0; + + if( ZeroGS::vb[i].bNeedTexCheck ) + ZeroGS::vb[i].FlushTexData(); + + u32 psm = (data[0] >> 20) & 0x3f; + if( psm == 9 ) psm = 1; // hmm..., ffx intro menu + + u32* s_uTex0Data = ZeroGS::vb[i].uCurTex0Data; + + // don't update unless necessary + if( (s_uTex0Data[0]&0x03f00000) == (data[0]&0x03f00000) ) { // psm is the same + + if( PSMT_ISCLUT(psm) ) { + // have to write the CLUT again if changed + if( (s_uTex0Data[1]&0x1fffffe0) == (data[1]&0x1fffffe0) ) { + + if( data[1]&0xe0000000 ) { + tex0.cld = (data[1]>>29)&7; + ZeroGS::texClutWrite(i); + // invalidate to make sure target didn't change! + ZeroGS::vb[i].bVarsTexSync = FALSE; + } + + return; + } + + // CSAs have to be the same! +// if( (data[1]&0xe0000000) == 0 ) { +// +// if( (s_uTex0Data[1]&0x1f100000) != (data[1]&0x1f100000) ) +// ZeroGS::Flush(i); +// +// // clut isn't going to be loaded so can ignore, but at least update CSA and CPSM! +// ZeroGS::vb[i].uCurTex0Data[1] = (ZeroGS::vb[i].uCurTex0Data[1]&0xe087ffff)|(data[1]&0x1f780000); +// +// if( ZeroGS::vb[i].tex0.cpsm <= 1 ) ZeroGS::vb[i].tex0.csa = (data[1] >> 24) & 0xf; +// else ZeroGS::vb[i].tex0.csa = (data[1] >> 24) & 0x1f; +// +// ZeroGS::vb[i].tex0.cpsm = (data[1] >> 19) & 0xe; +// +// ZeroGS::vb[i].bVarsTexSync = FALSE; +// return; +// } + + // fall through + } + else { + //ZeroGS::vb[i].bVarsTexSync = FALSE; + return; + } + } + + ZeroGS::Flush(i); + ZeroGS::vb[i].bVarsTexSync = FALSE; + ZeroGS::vb[i].bTexConstsSync = FALSE; + + s_uTex0Data[0] = (s_uTex0Data[0]&~0x03f00000)|(psm<<20); + s_uTex0Data[1] = (s_uTex0Data[1]&0x1f)|(data[1]&~0x1f); + + tex0.psm = psm; + + if( PSMT_ISCLUT(tex0.psm) ) { + tex0.cbp = (data[1] >> 5) & 0x3fff; + tex0.cpsm = (data[1] >> 19) & 0xe; + tex0.csm = (data[1] >> 23) & 0x1; + + if( tex0.cpsm <= 1 ) tex0.csa = (data[1] >> 24) & 0xf; + else tex0.csa = (data[1] >> 24) & 0x1f; + + tex0.cld = (data[1] >> 29) & 0x7; + ZeroGS::texClutWrite(i); + } +} + +__forceinline void frameWrite(int i, u32 *data) +{ + frameInfo& gsfb = ZeroGS::vb[i].gsfb; + + if( (gsfb.fbp == ((data[0] ) & 0x1ff) * 32) && + (gsfb.fbw == ((data[0] >> 16) & 0x3f) * 64) && + gsfb.psm == ((data[0] >> 24) & 0x3f) && + (gsfb.fbm == data[1]) ) { + return; + } + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + gsfb.fbp = ((data[0] ) & 0x1ff) * 32; + gsfb.fbw = ((data[0] >> 16) & 0x3f) * 64; + gsfb.psm = (data[0] >> 24) & 0x3f; + gsfb.fbm = data[1]; + + if (gsfb.fbw > 0) { + + gsfb.fbh = (1024*1024-64*gsfb.fbp) / gsfb.fbw; + gsfb.fbh &= ~0x1f; + if( gsfb.psm & 2 ) + gsfb.fbh *= 2; + if( gsfb.fbh > 1024 ) gsfb.fbh = 1024; + } + else gsfb.fbh = 0; + + if( gsfb.psm == 1 ) gsfb.fbm |= 0xff000000; + else if( gsfb.psm & 2 ) { + + } + + ZeroGS::vb[i].bNeedFrameCheck = 1; +} + +__forceinline void testWrite(int i, u32 *data) +{ + pixTest* test = &ZeroGS::vb[i].test; + + if( (*(u32*)test & 0x0007ffff) == (data[0] & 0x0007ffff) ) + return; + + ZeroGS::Flush(i); + *(u32*)test = data[0]; + +// test.ate = (data[0] ) & 0x1; +// test.atst = (data[0] >> 1) & 0x7; +// test.aref = (data[0] >> 4) & 0xff; +// test.afail = (data[0] >> 12) & 0x3; +// test.date = (data[0] >> 14) & 0x1; +// test.datm = (data[0] >> 15) & 0x1; +// test.zte = (data[0] >> 16) & 0x1; +// test.ztst = (data[0] >> 17) & 0x3; +} + +__forceinline void clampWrite(int i, u32 *data) +{ + clampInfo& clamp = ZeroGS::vb[i].clamp; + + if( s_uClampData[i] != data[0] || ((clamp.minv>>8)|(clamp.maxv<<2)) != (data[1]&0x0fff) ) { + +// if( ZeroGS::vb[i].bNeedTexCheck ) +// ZeroGS::vb[i].FlushTexData(); + + ZeroGS::Flush(i); + s_uClampData[i] = data[0]; + + clamp.wms = (data[0] ) & 0x3; + clamp.wmt = (data[0] >> 2) & 0x3; + clamp.minu = (data[0] >> 4) & 0x3ff; + clamp.maxu = (data[0] >> 14) & 0x3ff; + clamp.minv =((data[0] >> 24) & 0xff) | ((data[1] & 0x3) << 8); + clamp.maxv = (data[1] >> 2) & 0x3ff; + + ZeroGS::vb[i].bTexConstsSync = FALSE; + } +} + +void __fastcall GIFRegHandlerNull(u32* data) +{ +#ifdef _DEBUG + if( (((uptr)&data[2])&0xffff) == 0 ) + return; + + // 0x7f happens on a lot of games + if( data[2] != 0x7f && (data[0] || data[1]) ) { + DEBUG_LOG("Unexpected reg handler %x %x %x\n", data[0], data[1], data[2]); + } +#endif +} + +void __fastcall GIFRegHandlerPRIM(u32 *data) +{ + if (data[0] & ~0x3ff) { + //WARN_LOG("warning: unknown bits in prim %8.8lx_%8.8lx\n", data[1], data[0]); + } + + gs.nTriFanVert = gs.primIndex; + gs.primC = 0; + prim->prim = (data[0]) & 0x7; + gs._prim[0].prim = (data[0]) & 0x7; + gs._prim[1].prim = (data[0]) & 0x7; + gs._prim[1]._val = (data[0]>>3)&0xff; + + ZeroGS::Prim(); +} + +void __fastcall GIFRegHandlerRGBAQ(u32* data) +{ + gs.rgba = data[0]; + gs.vertexregs.rgba = data[0]; + *(u32*)&gs.vertexregs.q = data[1]; +} + +void __fastcall GIFRegHandlerST(u32* data) +{ + *(u32*)&gs.vertexregs.s = data[0]&0xffffff00; + *(u32*)&gs.vertexregs.t = data[1]&0xffffff00; + //*(u32*)&gs.q = data[2]; +} + +void __fastcall GIFRegHandlerUV(u32* data) +{ + gs.vertexregs.u = (data[0]) & 0x3fff; + gs.vertexregs.v = (data[0] >> 16) & 0x3fff; +} + +void __fastcall GIFRegHandlerXYZF2(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1] & 0xffffff; + gs.vertexregs.f = data[1] >> 24; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + + KICK_VERTEX2(); +} + +void __fastcall GIFRegHandlerXYZ2(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1]; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + + KICK_VERTEX2(); +} + +void __fastcall GIFRegHandlerTEX0_1(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { + return; + } + tex0Write(0, data); +} + +void __fastcall GIFRegHandlerTEX0_2(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) { + return; + } + tex0Write(1, data); +} + +void __fastcall GIFRegHandlerCLAMP_1(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { + return; + } + clampWrite(0, data); +} + +void __fastcall GIFRegHandlerCLAMP_2(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) { + return; + } + clampWrite(1, data); +} + +void __fastcall GIFRegHandlerFOG(u32* data) +{ + //gs.gsvertex[gs.primIndex].f = (data[1] >> 24); // shift to upper bits + gs.vertexregs.f = data[1]>>24; +} + +void __fastcall GIFRegHandlerXYZF3(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1] & 0xffffff; + gs.vertexregs.f = data[1] >> 24; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + + KICK_VERTEX3(); +} + +void __fastcall GIFRegHandlerXYZ3(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1]; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + + KICK_VERTEX3(); +} + +void __fastcall GIFRegHandlerNOP(u32* data) +{ +} + +void tex1Write(int i, u32* data) +{ + tex1Info& tex1 = ZeroGS::vb[i].tex1; + + if( conf.bilinear == 1 && (tex1.mmag != ((data[0] >> 5) & 0x1) || tex1.mmin != ((data[0] >> 6) & 0x7)) ) { + ZeroGS::Flush(i); + ZeroGS::vb[i].bVarsTexSync = FALSE; + } + tex1.lcm = (data[0] ) & 0x1; + tex1.mxl = (data[0] >> 2) & 0x7; + tex1.mmag = (data[0] >> 5) & 0x1; + tex1.mmin = (data[0] >> 6) & 0x7; + tex1.mtba = (data[0] >> 9) & 0x1; + tex1.l = (data[0] >> 19) & 0x3; + tex1.k = (data[1] >> 4) & 0xff; +} + +void __fastcall GIFRegHandlerTEX1_1(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { + return; + } + + tex1Write(0, data); +} + +void __fastcall GIFRegHandlerTEX1_2(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) + return; + + tex1Write(1, data); +} + +void __fastcall GIFRegHandlerTEX2_1(u32* data) +{ + tex2Write(0, data); +} + +void __fastcall GIFRegHandlerTEX2_2(u32* data) +{ + tex2Write(1, data); +} + +void __fastcall GIFRegHandlerXYOFFSET_1(u32* data) +{ + // eliminator low 4 bits for now + ZeroGS::vb[0].offset.x = (data[0]) & 0xffff; + ZeroGS::vb[0].offset.y = (data[1]) & 0xffff; + +// if( !conf.interlace ) { +// ZeroGS::vb[0].offset.x &= ~15; +// ZeroGS::vb[0].offset.y &= ~15; +// } +} + +void __fastcall GIFRegHandlerXYOFFSET_2(u32* data) +{ + ZeroGS::vb[1].offset.x = (data[0]) & 0xffff; + ZeroGS::vb[1].offset.y = (data[1]) & 0xffff; + +// if( !conf.interlace ) { +// ZeroGS::vb[1].offset.x &= ~15; +// ZeroGS::vb[1].offset.y &= ~15; +// } +} + +void __fastcall GIFRegHandlerPRMODECONT(u32* data) +{ + gs.prac = data[0] & 0x1; + prim = &gs._prim[gs.prac]; + + ZeroGS::Prim(); +} + +void __fastcall GIFRegHandlerPRMODE(u32* data) +{ + gs._prim[0]._val = (data[0]>>3)&0xff; + + if (gs.prac == 0) + ZeroGS::Prim(); +} + +void __fastcall GIFRegHandlerTEXCLUT(u32* data) +{ + if( ZeroGS::vb[0].bNeedTexCheck ) + ZeroGS::vb[0].FlushTexData(); + if( ZeroGS::vb[1].bNeedTexCheck ) + ZeroGS::vb[1].FlushTexData(); + gs.clut.cbw = ((data[0] ) & 0x3f) * 64; + gs.clut.cou = ((data[0] >> 6) & 0x3f) * 16; + gs.clut.cov = (data[0] >> 12) & 0x3ff; +} + +void __fastcall GIFRegHandlerSCANMSK(u32* data) +{ +// ZeroGS::Flush(0); +// ZeroGS::Flush(1); +// ZeroGS::ResolveC(&ZeroGS::vb[0]); +// ZeroGS::ResolveZ(&ZeroGS::vb[0]); + + gs.smask = data[0] & 0x3; +} + +void __fastcall GIFRegHandlerMIPTBP1_1(u32* data) +{ + miptbpInfo& miptbp0 = ZeroGS::vb[0].miptbp0; + miptbp0.tbp[0] = (data[0] ) & 0x3fff; + miptbp0.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp0.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp0.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp0.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp0.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerMIPTBP1_2(u32* data) +{ + miptbpInfo& miptbp0 = ZeroGS::vb[1].miptbp0; + miptbp0.tbp[0] = (data[0] ) & 0x3fff; + miptbp0.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp0.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp0.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp0.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp0.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerMIPTBP2_1(u32* data) +{ + miptbpInfo& miptbp1 = ZeroGS::vb[0].miptbp1; + miptbp1.tbp[0] = (data[0] ) & 0x3fff; + miptbp1.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp1.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp1.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp1.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp1.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerMIPTBP2_2(u32* data) +{ + miptbpInfo& miptbp1 = ZeroGS::vb[1].miptbp1; + miptbp1.tbp[0] = (data[0] ) & 0x3fff; + miptbp1.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp1.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp1.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp1.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp1.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerTEXA(u32* data) +{ + texaInfo newinfo; + newinfo.aem = (data[0] >> 15) & 0x1; + newinfo.ta[0] = data[0] & 0xff; + newinfo.ta[1] = data[1] & 0xff; + + if( *(u32*)&newinfo != *(u32*)&gs.texa ) { + ZeroGS::Flush(0); + ZeroGS::Flush(1); + *(u32*)&gs.texa = *(u32*)&newinfo; + gs.texa.fta[0] = newinfo.ta[0]/255.0f; + gs.texa.fta[1] = newinfo.ta[1]/255.0f; + + ZeroGS::vb[0].bTexConstsSync = FALSE; + ZeroGS::vb[1].bTexConstsSync = FALSE; + } +} + +void __fastcall GIFRegHandlerFOGCOL(u32* data) +{ + ZeroGS::SetFogColor(data[0]&0xffffff); +} + +void __fastcall GIFRegHandlerTEXFLUSH(u32* data) +{ + ZeroGS::SetTexFlush(); +} + +void __fastcall GIFRegHandlerSCISSOR_1(u32* data) +{ + Rect2& scissor = ZeroGS::vb[0].scissor; + + Rect2 newscissor; + + newscissor.x0 = ((data[0] ) & 0x7ff) << 3; + newscissor.x1 = ((data[0] >> 16) & 0x7ff) << 3; + newscissor.y0 = ((data[1] ) & 0x7ff) << 3; + newscissor.y1 = ((data[1] >> 16) & 0x7ff) << 3; + + if( newscissor.x1 != scissor.x1 || newscissor.y1 != scissor.y1 || + newscissor.x0 != scissor.x0 || newscissor.y0 != scissor.y0 ) { + + ZeroGS::Flush(0); + scissor = newscissor; + + ZeroGS::vb[0].bNeedFrameCheck = 1; + } +} + +void __fastcall GIFRegHandlerSCISSOR_2(u32* data) +{ + Rect2& scissor = ZeroGS::vb[1].scissor; + + Rect2 newscissor; + + newscissor.x0 = ((data[0] ) & 0x7ff) << 3; + newscissor.x1 = ((data[0] >> 16) & 0x7ff) << 3; + newscissor.y0 = ((data[1] ) & 0x7ff) << 3; + newscissor.y1 = ((data[1] >> 16) & 0x7ff) << 3; + + if( newscissor.x1 != scissor.x1 || newscissor.y1 != scissor.y1 || + newscissor.x0 != scissor.x0 || newscissor.y0 != scissor.y0 ) { + + ZeroGS::Flush(1); + scissor = newscissor; + + // flush everything + ZeroGS::vb[1].bNeedFrameCheck = 1; + } +} + +void __fastcall GIFRegHandlerALPHA_1(u32* data) +{ + alphaInfo newalpha; + newalpha.abcd = *(u8*)data; + newalpha.fix = *(u8*)(data+1); + + if( *(u16*)&newalpha != *(u16*)&ZeroGS::vb[0].alpha ) { + ZeroGS::Flush(0); + + if( newalpha.a == 3 ) newalpha.a = 0; + if( newalpha.b == 3 ) newalpha.b = 0; + if( newalpha.c == 3 ) newalpha.c = 0; + if( newalpha.d == 3 ) newalpha.d = 0; + + *(u16*)&ZeroGS::vb[0].alpha = *(u16*)&newalpha; + } +} + +void __fastcall GIFRegHandlerALPHA_2(u32* data) +{ + alphaInfo newalpha; + newalpha.abcd = *(u8*)data; + newalpha.fix = *(u8*)(data+1); + + if( *(u16*)&newalpha != *(u16*)&ZeroGS::vb[1].alpha ) { + ZeroGS::Flush(1); + + if( newalpha.a == 3 ) newalpha.a = 0; + if( newalpha.b == 3 ) newalpha.b = 0; + if( newalpha.c == 3 ) newalpha.c = 0; + if( newalpha.d == 3 ) newalpha.d = 0; + + *(u16*)&ZeroGS::vb[1].alpha = *(u16*)&newalpha; + } +} + +void __fastcall GIFRegHandlerDIMX(u32* data) +{ +} + +void __fastcall GIFRegHandlerDTHE(u32* data) +{ + gs.dthe = data[0] & 0x1; +} + +void __fastcall GIFRegHandlerCOLCLAMP(u32* data) +{ + gs.colclamp = data[0] & 0x1; +} + +void __fastcall GIFRegHandlerTEST_1(u32* data) +{ + testWrite(0, data); +} + +void __fastcall GIFRegHandlerTEST_2(u32* data) +{ + testWrite(1, data); +} + +void __fastcall GIFRegHandlerPABE(u32* data) +{ + //ZeroGS::SetAlphaChanged(0, GPUREG_PABE); + //ZeroGS::SetAlphaChanged(1, GPUREG_PABE); + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + gs.pabe = *data & 0x1; +} + +void __fastcall GIFRegHandlerFBA_1(u32* data) +{ + ZeroGS::Flush(0); + ZeroGS::Flush(1); + ZeroGS::vb[0].fba.fba = *data & 0x1; +} + +void __fastcall GIFRegHandlerFBA_2(u32* data) +{ + ZeroGS::Flush(0); + ZeroGS::Flush(1); + ZeroGS::vb[1].fba.fba = *data & 0x1; +} + +void __fastcall GIFRegHandlerFRAME_1(u32* data) +{ + frameWrite(0, data); +} + +void __fastcall GIFRegHandlerFRAME_2(u32* data) +{ + frameWrite(1, data); +} + +void __fastcall GIFRegHandlerZBUF_1(u32* data) +{ + zbufInfo& zbuf = ZeroGS::vb[0].zbuf; + + int psm = (0x30|((data[0] >> 24) & 0xf)); + if( zbuf.zbp == (data[0] & 0x1ff) * 32 && + zbuf.psm == psm && + zbuf.zmsk == (data[1] & 0x1) ) { + return; + } + + // error detection + if( m_Blocks[psm].bpp == 0 ) + return; + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + zbuf.zbp = (data[0] & 0x1ff) * 32; + zbuf.psm = 0x30|((data[0] >> 24) & 0xf); + zbuf.zmsk = data[1] & 0x1; + + ZeroGS::vb[0].zprimmask = 0xffffffff; + if( zbuf.psm > 0x31 ) ZeroGS::vb[0].zprimmask = 0xffff; + + ZeroGS::vb[0].bNeedZCheck = 1; +} + +void __fastcall GIFRegHandlerZBUF_2(u32* data) +{ + zbufInfo& zbuf = ZeroGS::vb[1].zbuf; + + int psm = (0x30|((data[0] >> 24) & 0xf)); + if( zbuf.zbp == (data[0] & 0x1ff) * 32 && + zbuf.psm == psm && + zbuf.zmsk == (data[1] & 0x1) ) { + return; + } + + // error detection + if( m_Blocks[psm].bpp == 0 ) + return; + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + zbuf.zbp = (data[0] & 0x1ff) * 32; + zbuf.psm = 0x30|((data[0] >> 24) & 0xf); + zbuf.zmsk = data[1] & 0x1; + + ZeroGS::vb[1].bNeedZCheck = 1; + + ZeroGS::vb[1].zprimmask = 0xffffffff; + if( zbuf.psm > 0x31 ) ZeroGS::vb[1].zprimmask = 0xffff; +} + +void __fastcall GIFRegHandlerBITBLTBUF(u32* data) +{ + gs.srcbufnew.bp = ((data[0] ) & 0x3fff);// * 64; + gs.srcbufnew.bw = ((data[0] >> 16) & 0x3f) * 64; + gs.srcbufnew.psm = (data[0] >> 24) & 0x3f; + gs.dstbufnew.bp = ((data[1] ) & 0x3fff);// * 64; + gs.dstbufnew.bw = ((data[1] >> 16) & 0x3f) * 64; + gs.dstbufnew.psm = (data[1] >> 24) & 0x3f; + + if (gs.dstbufnew.bw == 0) gs.dstbufnew.bw = 64; +} + +void __fastcall GIFRegHandlerTRXPOS(u32* data) +{ + gs.trxposnew.sx = (data[0] ) & 0x7ff; + gs.trxposnew.sy = (data[0] >> 16) & 0x7ff; + gs.trxposnew.dx = (data[1] ) & 0x7ff; + gs.trxposnew.dy = (data[1] >> 16) & 0x7ff; + gs.trxposnew.dir = (data[1] >> 27) & 0x3; +} + +void __fastcall GIFRegHandlerTRXREG(u32* data) +{ + gs.imageWtemp = data[0]&0xfff; + gs.imageHtemp = data[1]&0xfff; +} + +void __fastcall GIFRegHandlerTRXDIR(u32* data) +{ + // terminate any previous transfers + switch( gs.imageTransfer ) { + case 0: // host->loc + gs.imageTransfer = -1; + break; + case 1: // loc->host + ZeroGS::TerminateLocalHost(); + break; + } + + gs.srcbuf = gs.srcbufnew; + gs.dstbuf = gs.dstbufnew; + gs.trxpos = gs.trxposnew; + gs.imageTransfer = data[0] & 0x3; + gs.imageWnew = gs.imageWtemp; + gs.imageHnew = gs.imageHtemp; + + if( gs.imageWnew > 0 && gs.imageHnew > 0 ) { + switch(gs.imageTransfer) { + case 0: // host->loc + ZeroGS::InitTransferHostLocal(); + break; + + case 1: // loc->host + + ZeroGS::InitTransferLocalHost(); + break; + case 2: + + ZeroGS::TransferLocalLocal(); + break; + + case 3: + gs.imageTransfer = -1; + break; + + default: assert(0); + } + } + else { +#ifndef RELEASE_TO_PUBLIC + WARN_LOG("ZeroGS: dummy transfer\n"); +#endif + gs.imageTransfer = -1; + } +} + +static u32 oldhw[4]; +void __fastcall GIFRegHandlerHWREG(u32* data) +{ + if( gs.imageTransfer == 0 ) { + ZeroGS::TransferHostLocal(data, 2); + } + else { +#ifndef RELEASE_TO_PUBLIC + ERROR_LOG("ZeroGS: HWREG!? %8.8x_%8.8x\n", data[0], data[1]); + //assert(0); +#endif + } +} + +extern int g_GSMultiThreaded; + +void __fastcall GIFRegHandlerSIGNAL(u32* data) +{ + if(!g_GSMultiThreaded) { + SIGLBLID->SIGID = (SIGLBLID->SIGID&~data[1])|(data[0]&data[1]); + +// if (gs.CSRw & 0x1) CSR->SIGNAL = 1; +// if (!IMR->SIGMSK && GSirq) +// GSirq(); + + if (gs.CSRw & 0x1) { + CSR->SIGNAL = 1; + //gs.CSRw &= ~1; + } + if (!IMR->SIGMSK && GSirq) + GSirq(); + } +} + +void __fastcall GIFRegHandlerFINISH(u32* data) +{ + if(!g_GSMultiThreaded) { + + if (gs.CSRw & 0x2) + CSR->FINISH = 1; + if (!IMR->FINISHMSK && GSirq) + GSirq(); + +// if( gs.CSRw & 2 ) { +// //gs.CSRw &= ~2; +// //CSR->FINISH = 0; +// +// +// } +// CSR->FINISH = 1; +// +// if( !IMR->FINISHMSK && GSirq ) +// GSirq(); + } +} + +void __fastcall GIFRegHandlerLABEL(u32* data) +{ + if(!g_GSMultiThreaded) { + SIGLBLID->LBLID = (SIGLBLID->LBLID&~data[1])|(data[0]&data[1]); + } +} diff --git a/plugins/zerogs/opengl/Regs.h b/plugins/zerogs/opengl/Regs.h index 230ae2ac7d..40a4b4b065 100644 --- a/plugins/zerogs/opengl/Regs.h +++ b/plugins/zerogs/opengl/Regs.h @@ -1,101 +1,101 @@ -/* ZeroGS KOSMOS - * Copyright (C) 2005-2006 zerofrog@gmail.com - * - * 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 - */ - -#ifndef __GSREGS_H__ -#define __GSREGS_H__ - -#ifdef _MSC_VER -typedef void (__fastcall *GIFRegHandler)(u32* data); -#else - -#ifdef __x86_64__ -typedef void (*GIFRegHandler)(u32* data); -#else -typedef void (__fastcall *GIFRegHandler)(u32* data); -#endif - -#endif - -void __fastcall GIFPackedRegHandlerNull(u32* data); -void __fastcall GIFPackedRegHandlerRGBA(u32* data); -void __fastcall GIFPackedRegHandlerSTQ(u32* data); -void __fastcall GIFPackedRegHandlerUV(u32* data); -void __fastcall GIFPackedRegHandlerXYZF2(u32* data); -void __fastcall GIFPackedRegHandlerXYZ2(u32* data); -void __fastcall GIFPackedRegHandlerFOG(u32* data); -void __fastcall GIFPackedRegHandlerA_D(u32* data); -void __fastcall GIFPackedRegHandlerNOP(u32* data); - -void __fastcall GIFRegHandlerNull(u32* data); -void __fastcall GIFRegHandlerPRIM(u32* data); -void __fastcall GIFRegHandlerRGBAQ(u32* data); -void __fastcall GIFRegHandlerST(u32* data); -void __fastcall GIFRegHandlerUV(u32* data); -void __fastcall GIFRegHandlerXYZF2(u32* data); -void __fastcall GIFRegHandlerXYZ2(u32* data); -void __fastcall GIFRegHandlerTEX0_1(u32* data); -void __fastcall GIFRegHandlerTEX0_2(u32* data); -void __fastcall GIFRegHandlerCLAMP_1(u32* data); -void __fastcall GIFRegHandlerCLAMP_2(u32* data); -void __fastcall GIFRegHandlerFOG(u32* data); -void __fastcall GIFRegHandlerXYZF3(u32* data); -void __fastcall GIFRegHandlerXYZ3(u32* data); -void __fastcall GIFRegHandlerNOP(u32* data); -void __fastcall GIFRegHandlerTEX1_1(u32* data); -void __fastcall GIFRegHandlerTEX1_2(u32* data); -void __fastcall GIFRegHandlerTEX2_1(u32* data); -void __fastcall GIFRegHandlerTEX2_2(u32* data); -void __fastcall GIFRegHandlerXYOFFSET_1(u32* data); -void __fastcall GIFRegHandlerXYOFFSET_2(u32* data); -void __fastcall GIFRegHandlerPRMODECONT(u32* data); -void __fastcall GIFRegHandlerPRMODE(u32* data); -void __fastcall GIFRegHandlerTEXCLUT(u32* data); -void __fastcall GIFRegHandlerSCANMSK(u32* data); -void __fastcall GIFRegHandlerMIPTBP1_1(u32* data); -void __fastcall GIFRegHandlerMIPTBP1_2(u32* data); -void __fastcall GIFRegHandlerMIPTBP2_1(u32* data); -void __fastcall GIFRegHandlerMIPTBP2_2(u32* data); -void __fastcall GIFRegHandlerTEXA(u32* data); -void __fastcall GIFRegHandlerFOGCOL(u32* data); -void __fastcall GIFRegHandlerTEXFLUSH(u32* data); -void __fastcall GIFRegHandlerSCISSOR_1(u32* data); -void __fastcall GIFRegHandlerSCISSOR_2(u32* data); -void __fastcall GIFRegHandlerALPHA_1(u32* data); -void __fastcall GIFRegHandlerALPHA_2(u32* data); -void __fastcall GIFRegHandlerDIMX(u32* data); -void __fastcall GIFRegHandlerDTHE(u32* data); -void __fastcall GIFRegHandlerCOLCLAMP(u32* data); -void __fastcall GIFRegHandlerTEST_1(u32* data); -void __fastcall GIFRegHandlerTEST_2(u32* data); -void __fastcall GIFRegHandlerPABE(u32* data); -void __fastcall GIFRegHandlerFBA_1(u32* data); -void __fastcall GIFRegHandlerFBA_2(u32* data); -void __fastcall GIFRegHandlerFRAME_1(u32* data); -void __fastcall GIFRegHandlerFRAME_2(u32* data); -void __fastcall GIFRegHandlerZBUF_1(u32* data); -void __fastcall GIFRegHandlerZBUF_2(u32* data); -void __fastcall GIFRegHandlerBITBLTBUF(u32* data); -void __fastcall GIFRegHandlerTRXPOS(u32* data); -void __fastcall GIFRegHandlerTRXREG(u32* data); -void __fastcall GIFRegHandlerTRXDIR(u32* data); -void __fastcall GIFRegHandlerHWREG(u32* data); -void __fastcall GIFRegHandlerSIGNAL(u32* data); -void __fastcall GIFRegHandlerFINISH(u32* data); -void __fastcall GIFRegHandlerLABEL(u32* data); - -#endif +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#ifndef __GSREGS_H__ +#define __GSREGS_H__ + +#ifdef _MSC_VER +typedef void (__fastcall *GIFRegHandler)(u32* data); +#else + +#ifdef __x86_64__ +typedef void (*GIFRegHandler)(u32* data); +#else +typedef void (__fastcall *GIFRegHandler)(u32* data); +#endif + +#endif + +void __fastcall GIFPackedRegHandlerNull(u32* data); +void __fastcall GIFPackedRegHandlerRGBA(u32* data); +void __fastcall GIFPackedRegHandlerSTQ(u32* data); +void __fastcall GIFPackedRegHandlerUV(u32* data); +void __fastcall GIFPackedRegHandlerXYZF2(u32* data); +void __fastcall GIFPackedRegHandlerXYZ2(u32* data); +void __fastcall GIFPackedRegHandlerFOG(u32* data); +void __fastcall GIFPackedRegHandlerA_D(u32* data); +void __fastcall GIFPackedRegHandlerNOP(u32* data); + +void __fastcall GIFRegHandlerNull(u32* data); +void __fastcall GIFRegHandlerPRIM(u32* data); +void __fastcall GIFRegHandlerRGBAQ(u32* data); +void __fastcall GIFRegHandlerST(u32* data); +void __fastcall GIFRegHandlerUV(u32* data); +void __fastcall GIFRegHandlerXYZF2(u32* data); +void __fastcall GIFRegHandlerXYZ2(u32* data); +void __fastcall GIFRegHandlerTEX0_1(u32* data); +void __fastcall GIFRegHandlerTEX0_2(u32* data); +void __fastcall GIFRegHandlerCLAMP_1(u32* data); +void __fastcall GIFRegHandlerCLAMP_2(u32* data); +void __fastcall GIFRegHandlerFOG(u32* data); +void __fastcall GIFRegHandlerXYZF3(u32* data); +void __fastcall GIFRegHandlerXYZ3(u32* data); +void __fastcall GIFRegHandlerNOP(u32* data); +void __fastcall GIFRegHandlerTEX1_1(u32* data); +void __fastcall GIFRegHandlerTEX1_2(u32* data); +void __fastcall GIFRegHandlerTEX2_1(u32* data); +void __fastcall GIFRegHandlerTEX2_2(u32* data); +void __fastcall GIFRegHandlerXYOFFSET_1(u32* data); +void __fastcall GIFRegHandlerXYOFFSET_2(u32* data); +void __fastcall GIFRegHandlerPRMODECONT(u32* data); +void __fastcall GIFRegHandlerPRMODE(u32* data); +void __fastcall GIFRegHandlerTEXCLUT(u32* data); +void __fastcall GIFRegHandlerSCANMSK(u32* data); +void __fastcall GIFRegHandlerMIPTBP1_1(u32* data); +void __fastcall GIFRegHandlerMIPTBP1_2(u32* data); +void __fastcall GIFRegHandlerMIPTBP2_1(u32* data); +void __fastcall GIFRegHandlerMIPTBP2_2(u32* data); +void __fastcall GIFRegHandlerTEXA(u32* data); +void __fastcall GIFRegHandlerFOGCOL(u32* data); +void __fastcall GIFRegHandlerTEXFLUSH(u32* data); +void __fastcall GIFRegHandlerSCISSOR_1(u32* data); +void __fastcall GIFRegHandlerSCISSOR_2(u32* data); +void __fastcall GIFRegHandlerALPHA_1(u32* data); +void __fastcall GIFRegHandlerALPHA_2(u32* data); +void __fastcall GIFRegHandlerDIMX(u32* data); +void __fastcall GIFRegHandlerDTHE(u32* data); +void __fastcall GIFRegHandlerCOLCLAMP(u32* data); +void __fastcall GIFRegHandlerTEST_1(u32* data); +void __fastcall GIFRegHandlerTEST_2(u32* data); +void __fastcall GIFRegHandlerPABE(u32* data); +void __fastcall GIFRegHandlerFBA_1(u32* data); +void __fastcall GIFRegHandlerFBA_2(u32* data); +void __fastcall GIFRegHandlerFRAME_1(u32* data); +void __fastcall GIFRegHandlerFRAME_2(u32* data); +void __fastcall GIFRegHandlerZBUF_1(u32* data); +void __fastcall GIFRegHandlerZBUF_2(u32* data); +void __fastcall GIFRegHandlerBITBLTBUF(u32* data); +void __fastcall GIFRegHandlerTRXPOS(u32* data); +void __fastcall GIFRegHandlerTRXREG(u32* data); +void __fastcall GIFRegHandlerTRXDIR(u32* data); +void __fastcall GIFRegHandlerHWREG(u32* data); +void __fastcall GIFRegHandlerSIGNAL(u32* data); +void __fastcall GIFRegHandlerFINISH(u32* data); +void __fastcall GIFRegHandlerLABEL(u32* data); + +#endif diff --git a/plugins/zerogs/opengl/Win32/Conf.cpp b/plugins/zerogs/opengl/Win32/Conf.cpp index faec02584d..db3ccdcfe1 100644 --- a/plugins/zerogs/opengl/Win32/Conf.cpp +++ b/plugins/zerogs/opengl/Win32/Conf.cpp @@ -1,100 +1,100 @@ -#include - -#include "GS.h" -#include "Win32.h" - -extern HINSTANCE hInst; - - -void SaveConfig() { - - char *szTemp; - char szIniFile[256], szValue[256]; - - GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); - szTemp = strrchr(szIniFile, '\\'); - - if(!szTemp) return; - strcpy(szTemp, "\\inis\\zerogs.ini"); - - sprintf(szValue,"%u",conf.interlace); - WritePrivateProfileString("Settings", "Interlace",szValue,szIniFile); - sprintf(szValue,"%u",conf.aa); - WritePrivateProfileString("Settings", "Antialiasing",szValue,szIniFile); - sprintf(szValue,"%u",conf.bilinear); - WritePrivateProfileString("Settings", "Bilinear",szValue,szIniFile); - sprintf(szValue,"%u",conf.options); - WritePrivateProfileString("Settings", "Options",szValue,szIniFile); - sprintf(szValue,"%u",conf.gamesettings); - WritePrivateProfileString("Settings", "AdvancedOptions",szValue,szIniFile); -} - -void LoadConfig() { - - FILE *fp; - char *szTemp; - char szIniFile[256], szValue[256]; - - GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); - szTemp = strrchr(szIniFile, '\\'); - - memset(&conf, 0, sizeof(conf)); - conf.interlace = 0; // on, mode 1 - conf.mrtdepth = 1; - conf.options = 0; - conf.bilinear = 1; - conf.width = 640; - conf.height = 480; - - if(!szTemp) return ; - strcpy(szTemp, "\\inis\\zerogs.ini"); - fp=fopen("inis\\zerogs.ini","rt"); - if (!fp) - { - CreateDirectory("inis",NULL); - SaveConfig();//save and return - return ; - } - fclose(fp); - - GetPrivateProfileString("Settings", "Interlace", NULL, szValue, 20, szIniFile); - conf.interlace = (u8)strtoul(szValue, NULL, 10); - GetPrivateProfileString("Settings", "Antialiasing", NULL, szValue, 20, szIniFile); - conf.aa = (u8)strtoul(szValue, NULL, 10); - GetPrivateProfileString("Settings", "Options", NULL, szValue, 20, szIniFile); - conf.options = strtoul(szValue, NULL, 10); - GetPrivateProfileString("Settings", "AdvancedOptions", NULL, szValue, 20, szIniFile); - conf.gamesettings = strtoul(szValue, NULL, 10); - GetPrivateProfileString("Settings", "Bilinear", NULL, szValue, 20, szIniFile); - conf.bilinear = strtoul(szValue, NULL, 10); - - if( conf.aa < 0 || conf.aa > 2 ) conf.aa = 0; - - switch(conf.options&GSOPTION_WINDIMS) { - case GSOPTION_WIN640: - conf.width = 640; - conf.height = 480; - break; - case GSOPTION_WIN800: - conf.width = 800; - conf.height = 600; - break; - case GSOPTION_WIN1024: - conf.width = 1024; - conf.height = 768; - break; - case GSOPTION_WIN1280: - conf.width = 1280; - conf.height = 960; - break; - } - - // turn off all hacks by defaultof - conf.options &= ~(GSOPTION_FULLSCREEN|GSOPTION_WIREFRAME|GSOPTION_CAPTUREAVI); - conf.options |= GSOPTION_LOADED; - - if( conf.width <= 0 || conf.height <= 0 ) { - conf.width = 640; - conf.height = 480; - } -} +#include + +#include "GS.h" +#include "Win32.h" + +extern HINSTANCE hInst; + + +void SaveConfig() { + + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\zerogs.ini"); + + sprintf(szValue,"%u",conf.interlace); + WritePrivateProfileString("Settings", "Interlace",szValue,szIniFile); + sprintf(szValue,"%u",conf.aa); + WritePrivateProfileString("Settings", "Antialiasing",szValue,szIniFile); + sprintf(szValue,"%u",conf.bilinear); + WritePrivateProfileString("Settings", "Bilinear",szValue,szIniFile); + sprintf(szValue,"%u",conf.options); + WritePrivateProfileString("Settings", "Options",szValue,szIniFile); + sprintf(szValue,"%u",conf.gamesettings); + WritePrivateProfileString("Settings", "AdvancedOptions",szValue,szIniFile); +} + +void LoadConfig() { + + FILE *fp; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + memset(&conf, 0, sizeof(conf)); + conf.interlace = 0; // on, mode 1 + conf.mrtdepth = 1; + conf.options = 0; + conf.bilinear = 1; + conf.width = 640; + conf.height = 480; + + if(!szTemp) return ; + strcpy(szTemp, "\\inis\\zerogs.ini"); + fp=fopen("inis\\zerogs.ini","rt"); + if (!fp) + { + CreateDirectory("inis",NULL); + SaveConfig();//save and return + return ; + } + fclose(fp); + + GetPrivateProfileString("Settings", "Interlace", NULL, szValue, 20, szIniFile); + conf.interlace = (u8)strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Antialiasing", NULL, szValue, 20, szIniFile); + conf.aa = (u8)strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Options", NULL, szValue, 20, szIniFile); + conf.options = strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "AdvancedOptions", NULL, szValue, 20, szIniFile); + conf.gamesettings = strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Bilinear", NULL, szValue, 20, szIniFile); + conf.bilinear = strtoul(szValue, NULL, 10); + + if( conf.aa < 0 || conf.aa > 2 ) conf.aa = 0; + + switch(conf.options&GSOPTION_WINDIMS) { + case GSOPTION_WIN640: + conf.width = 640; + conf.height = 480; + break; + case GSOPTION_WIN800: + conf.width = 800; + conf.height = 600; + break; + case GSOPTION_WIN1024: + conf.width = 1024; + conf.height = 768; + break; + case GSOPTION_WIN1280: + conf.width = 1280; + conf.height = 960; + break; + } + + // turn off all hacks by defaultof + conf.options &= ~(GSOPTION_FULLSCREEN|GSOPTION_WIREFRAME|GSOPTION_CAPTUREAVI); + conf.options |= GSOPTION_LOADED; + + if( conf.width <= 0 || conf.height <= 0 ) { + conf.width = 640; + conf.height = 480; + } +} diff --git a/plugins/zerogs/opengl/Win32/Win32.cpp b/plugins/zerogs/opengl/Win32/Win32.cpp index a6d680fdfd..7a516d2bbf 100644 --- a/plugins/zerogs/opengl/Win32/Win32.cpp +++ b/plugins/zerogs/opengl/Win32/Win32.cpp @@ -1,246 +1,246 @@ -#include -#include -#include - -#include "resrc1.h" - -#include "GS.h" -#include "Win32.h" - -#include -using namespace std; - -extern int g_nPixelShaderVer; -static int prevbilinearfilter; -HINSTANCE hInst=NULL; - -void CALLBACK GSkeyEvent(keyEvent *ev) { -// switch (ev->event) { -// case KEYPRESS: -// switch (ev->key) { -// case VK_PRIOR: -// if (conf.fps) fpspos++; break; -// case VK_NEXT: -// if (conf.fps) fpspos--; break; -// case VK_END: -// if (conf.fps) fpspress = 1; break; -// case VK_DELETE: -// conf.fps = 1 - conf.fps; -// break; -// } -// break; -// } -} - -#include "Win32/resource.h" - -BOOL CALLBACK LoggingDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { - switch(uMsg) { - case WM_INITDIALOG: - if (conf.log) CheckDlgButton(hW, IDC_LOG, TRUE); - return TRUE; - - case WM_COMMAND: - switch(LOWORD(wParam)) { - case IDCANCEL: - EndDialog(hW, FALSE); - return TRUE; - case IDOK: - if (IsDlgButtonChecked(hW, IDC_LOG)) - conf.log = 1; - else conf.log = 0; - - SaveConfig(); - EndDialog(hW, FALSE); - return TRUE; - } - } - return FALSE; -} - -map mapConfOpts; -#define PUT_CONF(id) mapConfOpts[IDC_CONFOPT_##id] = 0x##id; - -void OnInitDialog(HWND hW) -{ - if( !(conf.options & GSOPTION_LOADED) ) - LoadConfig(); - - CheckDlgButton(hW, IDC_CONFIG_INTERLACE, conf.interlace); - CheckDlgButton(hW, IDC_CONFIG_BILINEAR, conf.bilinear); - CheckDlgButton(hW, IDC_CONFIG_DEPTHWRITE, conf.mrtdepth); - CheckRadioButton(hW,IDC_CONFIG_AANONE,IDC_CONFIG_AA4, IDC_CONFIG_AANONE+conf.aa); - CheckDlgButton(hW, IDC_CONFIG_WIREFRAME, (conf.options&GSOPTION_WIREFRAME)?1:0); - CheckDlgButton(hW, IDC_CONFIG_CAPTUREAVI, (conf.options&GSOPTION_CAPTUREAVI)?1:0); - //CheckDlgButton(hW, IDC_CONFIG_CACHEFBP, (conf.options&GSOPTION_ALPHACLAMP)?1:0); - CheckDlgButton(hW, IDC_CONFIG_FULLSCREEN, (conf.options&GSOPTION_FULLSCREEN)?1:0); - //CheckDlgButton(hW, IDC_CONFIG_FFX, (conf.options&GSOPTION_FFXHACK)?1:0); - CheckDlgButton(hW, IDC_CONFIG_BMPSS, (conf.options&GSOPTION_TGASNAP)?1:0); - CheckRadioButton(hW,IDC_CONF_WIN640, IDC_CONF_WIN1280, IDC_CONF_WIN640+((conf.options&GSOPTION_WINDIMS)>>4)); - - prevbilinearfilter = conf.bilinear; - - mapConfOpts.clear(); - PUT_CONF(00000001); - PUT_CONF(00000002); - PUT_CONF(00000004); - PUT_CONF(00000008); - PUT_CONF(00000010); - PUT_CONF(00000020); - PUT_CONF(00000040); - PUT_CONF(00000080); - PUT_CONF(00000200); - PUT_CONF(00000400); - PUT_CONF(00000800); - PUT_CONF(00001000); - PUT_CONF(00002000); - PUT_CONF(00004000); - PUT_CONF(00008000); - PUT_CONF(00010000); - PUT_CONF(00020000); - PUT_CONF(00040000); - PUT_CONF(00080000); - PUT_CONF(00100000); - PUT_CONF(00200000); - PUT_CONF(00800000); - PUT_CONF(01000000); - PUT_CONF(02000000); - PUT_CONF(04000000); - - for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { - CheckDlgButton(hW, it->first, (conf.gamesettings&it->second)?1:0); - } -} - -void OnOK(HWND hW) { - - u32 newinterlace = IsDlgButtonChecked(hW, IDC_CONFIG_INTERLACE); - - if( !conf.interlace ) conf.interlace = newinterlace; - else if( !newinterlace ) conf.interlace = 2; // off - - conf.bilinear = IsDlgButtonChecked(hW, IDC_CONFIG_BILINEAR); - // restore - if( conf.bilinear && prevbilinearfilter ) - conf.bilinear = prevbilinearfilter; - - //conf.mrtdepth = 1;//IsDlgButtonChecked(hW, IDC_CONFIG_DEPTHWRITE); - - if( SendDlgItemMessage(hW,IDC_CONFIG_AANONE,BM_GETCHECK,0,0) ) { - conf.aa = 0; - } - else if( SendDlgItemMessage(hW,IDC_CONFIG_AA2,BM_GETCHECK,0,0) ) { - conf.aa = 1; - } - else if( SendDlgItemMessage(hW,IDC_CONFIG_AA4,BM_GETCHECK,0,0) ) { - conf.aa = 2; - } - else if( SendDlgItemMessage(hW,IDC_CONFIG_AA8,BM_GETCHECK,0,0) ) { - conf.aa = 3; - } - else if( SendDlgItemMessage(hW,IDC_CONFIG_AA16,BM_GETCHECK,0,0) ) { - conf.aa = 4; - } - else conf.aa = 0; - - conf.options = 0; - conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_CAPTUREAVI) ? GSOPTION_CAPTUREAVI : 0; - conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_WIREFRAME) ? GSOPTION_WIREFRAME : 0; - conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_FULLSCREEN) ? GSOPTION_FULLSCREEN : 0; - //conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_FFX) ? GSOPTION_FFXHACK : 0; - conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_BMPSS) ? GSOPTION_TGASNAP : 0; - - conf.gamesettings = 0; - for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { - if( IsDlgButtonChecked(hW, it->first) ) - conf.gamesettings |= it->second; - } - GSsetGameCRC(g_LastCRC, conf.gamesettings); - - if( SendDlgItemMessage(hW,IDC_CONF_WIN640,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN640; - else if( SendDlgItemMessage(hW,IDC_CONF_WIN800,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN800; - else if( SendDlgItemMessage(hW,IDC_CONF_WIN1024,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1024; - else if( SendDlgItemMessage(hW,IDC_CONF_WIN1280,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1280; - - SaveConfig(); - EndDialog(hW, FALSE); -} - -BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { - switch(uMsg) { - case WM_INITDIALOG: - OnInitDialog(hW); - return TRUE; - - case WM_COMMAND: - switch(LOWORD(wParam)) { - case IDCANCEL: - EndDialog(hW, TRUE); - return TRUE; - case IDOK: - OnOK(hW); - return TRUE; - } - } - return FALSE; -} - -BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { - switch(uMsg) { - case WM_INITDIALOG: - - //ZeroGS uses floating point render targets because A8R8G8B8 format is not sufficient for ps2 blending and this requires alpha blending on floating point render targets - //There might be a problem with pixel shader precision with older geforce models (textures will look blocky). - - return TRUE; - - case WM_COMMAND: - switch(LOWORD(wParam)) { - case IDOK: - EndDialog(hW, FALSE); - return TRUE; - } - } - return FALSE; -} - -s32 CALLBACK GStest() { - return 0; -} - -void CALLBACK GSabout() { - DialogBox(hInst, - MAKEINTRESOURCE(IDD_ABOUT), - GetActiveWindow(), - (DLGPROC)AboutDlgProc); -} - -BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT - DWORD dwReason, - LPVOID lpReserved) { - hInst = (HINSTANCE)hModule; - return TRUE; // very quick :) -} - -static char *err = "Error Loading Symbol"; -static int errval; - -void *SysLoadLibrary(char *lib) { - return LoadLibrary(lib); -} - -void *SysLoadSym(void *lib, char *sym) { - void *tmp = GetProcAddress((HINSTANCE)lib, sym); - if (tmp == NULL) errval = 1; - else errval = 0; - return tmp; -} - -char *SysLibError() { - if (errval) { errval = 0; return err; } - return NULL; -} - -void SysCloseLibrary(void *lib) { - FreeLibrary((HINSTANCE)lib); -} +#include +#include +#include + +#include "resrc1.h" + +#include "GS.h" +#include "Win32.h" + +#include +using namespace std; + +extern int g_nPixelShaderVer; +static int prevbilinearfilter; +HINSTANCE hInst=NULL; + +void CALLBACK GSkeyEvent(keyEvent *ev) { +// switch (ev->event) { +// case KEYPRESS: +// switch (ev->key) { +// case VK_PRIOR: +// if (conf.fps) fpspos++; break; +// case VK_NEXT: +// if (conf.fps) fpspos--; break; +// case VK_END: +// if (conf.fps) fpspress = 1; break; +// case VK_DELETE: +// conf.fps = 1 - conf.fps; +// break; +// } +// break; +// } +} + +#include "Win32/resource.h" + +BOOL CALLBACK LoggingDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + if (conf.log) CheckDlgButton(hW, IDC_LOG, TRUE); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, FALSE); + return TRUE; + case IDOK: + if (IsDlgButtonChecked(hW, IDC_LOG)) + conf.log = 1; + else conf.log = 0; + + SaveConfig(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +map mapConfOpts; +#define PUT_CONF(id) mapConfOpts[IDC_CONFOPT_##id] = 0x##id; + +void OnInitDialog(HWND hW) +{ + if( !(conf.options & GSOPTION_LOADED) ) + LoadConfig(); + + CheckDlgButton(hW, IDC_CONFIG_INTERLACE, conf.interlace); + CheckDlgButton(hW, IDC_CONFIG_BILINEAR, conf.bilinear); + CheckDlgButton(hW, IDC_CONFIG_DEPTHWRITE, conf.mrtdepth); + CheckRadioButton(hW,IDC_CONFIG_AANONE,IDC_CONFIG_AA4, IDC_CONFIG_AANONE+conf.aa); + CheckDlgButton(hW, IDC_CONFIG_WIREFRAME, (conf.options&GSOPTION_WIREFRAME)?1:0); + CheckDlgButton(hW, IDC_CONFIG_CAPTUREAVI, (conf.options&GSOPTION_CAPTUREAVI)?1:0); + //CheckDlgButton(hW, IDC_CONFIG_CACHEFBP, (conf.options&GSOPTION_ALPHACLAMP)?1:0); + CheckDlgButton(hW, IDC_CONFIG_FULLSCREEN, (conf.options&GSOPTION_FULLSCREEN)?1:0); + //CheckDlgButton(hW, IDC_CONFIG_FFX, (conf.options&GSOPTION_FFXHACK)?1:0); + CheckDlgButton(hW, IDC_CONFIG_BMPSS, (conf.options&GSOPTION_TGASNAP)?1:0); + CheckRadioButton(hW,IDC_CONF_WIN640, IDC_CONF_WIN1280, IDC_CONF_WIN640+((conf.options&GSOPTION_WINDIMS)>>4)); + + prevbilinearfilter = conf.bilinear; + + mapConfOpts.clear(); + PUT_CONF(00000001); + PUT_CONF(00000002); + PUT_CONF(00000004); + PUT_CONF(00000008); + PUT_CONF(00000010); + PUT_CONF(00000020); + PUT_CONF(00000040); + PUT_CONF(00000080); + PUT_CONF(00000200); + PUT_CONF(00000400); + PUT_CONF(00000800); + PUT_CONF(00001000); + PUT_CONF(00002000); + PUT_CONF(00004000); + PUT_CONF(00008000); + PUT_CONF(00010000); + PUT_CONF(00020000); + PUT_CONF(00040000); + PUT_CONF(00080000); + PUT_CONF(00100000); + PUT_CONF(00200000); + PUT_CONF(00800000); + PUT_CONF(01000000); + PUT_CONF(02000000); + PUT_CONF(04000000); + + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + CheckDlgButton(hW, it->first, (conf.gamesettings&it->second)?1:0); + } +} + +void OnOK(HWND hW) { + + u32 newinterlace = IsDlgButtonChecked(hW, IDC_CONFIG_INTERLACE); + + if( !conf.interlace ) conf.interlace = newinterlace; + else if( !newinterlace ) conf.interlace = 2; // off + + conf.bilinear = IsDlgButtonChecked(hW, IDC_CONFIG_BILINEAR); + // restore + if( conf.bilinear && prevbilinearfilter ) + conf.bilinear = prevbilinearfilter; + + //conf.mrtdepth = 1;//IsDlgButtonChecked(hW, IDC_CONFIG_DEPTHWRITE); + + if( SendDlgItemMessage(hW,IDC_CONFIG_AANONE,BM_GETCHECK,0,0) ) { + conf.aa = 0; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA2,BM_GETCHECK,0,0) ) { + conf.aa = 1; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA4,BM_GETCHECK,0,0) ) { + conf.aa = 2; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA8,BM_GETCHECK,0,0) ) { + conf.aa = 3; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA16,BM_GETCHECK,0,0) ) { + conf.aa = 4; + } + else conf.aa = 0; + + conf.options = 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_CAPTUREAVI) ? GSOPTION_CAPTUREAVI : 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_WIREFRAME) ? GSOPTION_WIREFRAME : 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_FULLSCREEN) ? GSOPTION_FULLSCREEN : 0; + //conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_FFX) ? GSOPTION_FFXHACK : 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_BMPSS) ? GSOPTION_TGASNAP : 0; + + conf.gamesettings = 0; + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + if( IsDlgButtonChecked(hW, it->first) ) + conf.gamesettings |= it->second; + } + GSsetGameCRC(g_LastCRC, conf.gamesettings); + + if( SendDlgItemMessage(hW,IDC_CONF_WIN640,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN640; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN800,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN800; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN1024,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1024; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN1280,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1280; + + SaveConfig(); + EndDialog(hW, FALSE); +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + OnInitDialog(hW); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + case IDOK: + OnOK(hW); + return TRUE; + } + } + return FALSE; +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + + //ZeroGS uses floating point render targets because A8R8G8B8 format is not sufficient for ps2 blending and this requires alpha blending on floating point render targets + //There might be a problem with pixel shader precision with older geforce models (textures will look blocky). + + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +s32 CALLBACK GStest() { + return 0; +} + +void CALLBACK GSabout() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc); +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + +static char *err = "Error Loading Symbol"; +static int errval; + +void *SysLoadLibrary(char *lib) { + return LoadLibrary(lib); +} + +void *SysLoadSym(void *lib, char *sym) { + void *tmp = GetProcAddress((HINSTANCE)lib, sym); + if (tmp == NULL) errval = 1; + else errval = 0; + return tmp; +} + +char *SysLibError() { + if (errval) { errval = 0; return err; } + return NULL; +} + +void SysCloseLibrary(void *lib) { + FreeLibrary((HINSTANCE)lib); +} diff --git a/plugins/zerogs/opengl/Win32/Win32.h b/plugins/zerogs/opengl/Win32/Win32.h index 45322b3d01..acea999c8b 100644 --- a/plugins/zerogs/opengl/Win32/Win32.h +++ b/plugins/zerogs/opengl/Win32/Win32.h @@ -1,9 +1,9 @@ -#ifndef __WIN32_H__ -#define __WIN32_H__ - -#include "resrc1.h" -#include "Win32/resource.h" - -BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); - -#endif /* __WIN32_H__ */ +#ifndef __WIN32_H__ +#define __WIN32_H__ + +#include "resrc1.h" +#include "Win32/resource.h" + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); + +#endif /* __WIN32_H__ */ diff --git a/plugins/zerogs/opengl/Win32/aviUtil.h b/plugins/zerogs/opengl/Win32/aviUtil.h index bb7897fa2d..866271fe04 100644 --- a/plugins/zerogs/opengl/Win32/aviUtil.h +++ b/plugins/zerogs/opengl/Win32/aviUtil.h @@ -1,484 +1,484 @@ -#define AVIIF_KEYFRAME 0x00000010L // this frame is a key frame. - -#include -using namespace std; - -#include -#include -#include - -BOOL AVI_Init() -{ - /* first let's make sure we are running on 1.1 */ - WORD wVer = HIWORD(VideoForWindowsVersion()); - if (wVer < 0x010a){ - /* oops, we are too old, blow out of here */ - //MessageBeep(MB_ICONHAND); - MessageBox(NULL, "Cant't init AVI File - Video for Windows version is to old", "Error", MB_OK|MB_ICONSTOP); - return FALSE; - } - - AVIFileInit(); - - return TRUE; -} - -BOOL AVI_FileOpenWrite(PAVIFILE * pfile, const char *filename) -{ - HRESULT hr = AVIFileOpen(pfile, // returned file pointer - filename, // file name - OF_WRITE | OF_CREATE, // mode to open file with - NULL); // use handler determined - // from file extension.... - if (hr != AVIERR_OK) - return FALSE; - - return TRUE; -} - -DWORD getFOURCC(const char* value) -{ - if(_stricmp(value, "DIB") == 0) - { - return mmioFOURCC(value[0],value[1],value[2],' '); - } - else if((_stricmp(value, "CVID") == 0) - || (_stricmp(value, "IV32") == 0) - || (_stricmp(value, "MSVC") == 0) - || (_stricmp(value, "IV50") == 0)) - { - return mmioFOURCC(value[0],value[1],value[2],value[3]); - } - else - { - return NULL; - } -} - -// Fill in the header for the video stream.... -// The video stream will run in rate ths of a second.... -BOOL AVI_CreateStream(PAVIFILE pfile, PAVISTREAM * ps, int rate, // sample/second - unsigned long buffersize, int rectwidth, int rectheight, - const char* _compressor) -{ - AVISTREAMINFO strhdr; - memset(&strhdr, 0, sizeof(strhdr)); - strhdr.fccType = streamtypeVIDEO;// stream type - strhdr.fccHandler = getFOURCC(_compressor); - //strhdr.fccHandler = 0; // no compression! - //strhdr.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed - //strhdr.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak - //strhdr.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2 - //strhdr.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1 - //strhdr.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0 - //strhdr.dwFlags = AVISTREAMINFO_DISABLED; - //strhdr.dwCaps = - //strhdr.wPriority = - //strhdr.wLanguage = - strhdr.dwScale = 1; - strhdr.dwRate = rate; // rate fps - //strhdr.dwStart = - //strhdr.dwLength = - //strhdr.dwInitialFrames = - strhdr.dwSuggestedBufferSize = buffersize; - strhdr.dwQuality = -1; // use the default - //strhdr.dwSampleSize = - SetRect(&strhdr.rcFrame, 0, 0, // rectangle for stream - (int) rectwidth, - (int) rectheight); - //strhdr.dwEditCount = - //strhdr.dwFormatChangeCount = - //strcpy(strhdr.szName, "Full Frames (Uncompressed)"); - - // And create the stream; - HRESULT hr = AVIFileCreateStream(pfile, // file pointer - ps, // returned stream pointer - &strhdr); // stream header - if (hr != AVIERR_OK) { - return FALSE; - } - - return TRUE; -} - -string getFOURCCVAsString(DWORD value) -{ - string returnValue = ""; - if( value == 0 ) - return returnValue; - - DWORD ch0 = value & 0x000000FF; - returnValue.push_back((char) ch0); - DWORD ch1 = (value & 0x0000FF00)>>8; - returnValue.push_back((char) ch1); - DWORD ch2 = (value & 0x00FF0000)>>16; - returnValue.push_back((char) ch2); - DWORD ch3 = (value & 0xFF000000)>>24; - returnValue.push_back((char) ch3); - - return returnValue; -} - -string dumpAVICOMPRESSOPTIONS(AVICOMPRESSOPTIONS opts) -{ - char tmp[255]; - string returnValue = "Dump of AVICOMPRESSOPTIONS\n"; - - returnValue += "DWORD fccType = streamtype("; returnValue += getFOURCCVAsString(opts.fccType); returnValue += ")\n"; - returnValue += "DWORD fccHandler = "; returnValue += getFOURCCVAsString(opts.fccHandler); returnValue += "\n"; - - _snprintf(tmp, 255, "DWORD dwKeyFrameEvery = %d\n", opts.dwKeyFrameEvery); - returnValue += tmp; - - _snprintf(tmp, 255, "DWORD dwQuality = %d\n", opts.dwQuality); - returnValue += tmp; - - _snprintf(tmp, 255, "DWORD dwBytesPerSecond = %d\n", opts.dwBytesPerSecond); - returnValue += tmp; - - if((opts.dwFlags & AVICOMPRESSF_DATARATE) == AVICOMPRESSF_DATARATE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_DATARATE\n");} - else if((opts.dwFlags & AVICOMPRESSF_INTERLEAVE) == AVICOMPRESSF_INTERLEAVE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_INTERLEAVE\n");} - else if((opts.dwFlags & AVICOMPRESSF_KEYFRAMES) == AVICOMPRESSF_KEYFRAMES){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_KEYFRAMES\n");} - else if((opts.dwFlags & AVICOMPRESSF_VALID) == AVICOMPRESSF_VALID){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_VALID\n");} - else {_snprintf(tmp, 255, "DWORD dwFlags = Unknown(%d)\n", opts.dwFlags);} - returnValue += tmp; - - _snprintf(tmp, 255, "LPVOID lpFormat = %d\n", (int)opts.lpFormat); - returnValue += tmp; - - _snprintf(tmp, 255, "DWORD cbFormat = %d\n", opts.cbFormat); - returnValue += tmp; - - _snprintf(tmp, 255, "LPVOID lpParms = %d\n", (int)opts.lpParms); - returnValue += tmp; - - _snprintf(tmp, 255, "DWORD cbParms = %d\n", opts.cbParms); - returnValue += tmp; - - _snprintf(tmp, 255, "DWORD dwInterleaveEvery = %d\n", opts.dwInterleaveEvery); - returnValue += tmp; - - return returnValue; -} - -BOOL AVI_SetOptions(PAVISTREAM * ps, PAVISTREAM * psCompressed, LPBITMAPINFOHEADER lpbi, - const char* _compressor) -{ - - AVICOMPRESSOPTIONS opts; - AVICOMPRESSOPTIONS FAR * aopts[1] = {&opts}; - - memset(&opts, 0, sizeof(opts)); - opts.fccType = streamtypeVIDEO; - opts.fccHandler = getFOURCC(_compressor); - //opts.fccHandler = 0; - //opts.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed - //opts.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak - //opts.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2 - //opts.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1 - //opts.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0 - //opts.dwKeyFrameEvery = 5; - //opts.dwQuality - //opts.dwBytesPerSecond - //opts.dwFlags = AVICOMPRESSF_KEYFRAMES; - //opts.lpFormat - //opts.cbFormat - //opts.lpParms - //opts.cbParms - //opts.dwInterleaveEvery - - /* display the compression options dialog box if specified compressor is unknown */ - if(getFOURCC(_compressor) == NULL) - { - if (!AVISaveOptions(NULL, 0, 1, ps, (LPAVICOMPRESSOPTIONS FAR *) &aopts)) - { - return FALSE; - } - - //printf("%s", dumpAVICOMPRESSOPTIONS(opts)); - //MessageBox(NULL, dumpAVICOMPRESSOPTIONS(opts).c_str(), "AVICOMPRESSOPTIONS", MB_OK); - } - - HRESULT hr = AVIMakeCompressedStream(psCompressed, *ps, &opts, NULL); - if (hr != AVIERR_OK) { - return FALSE; - } - - hr = AVIStreamSetFormat(*psCompressed, 0, - lpbi, // stream format - lpbi->biSize // format size - + lpbi->biClrUsed * sizeof(RGBQUAD) - ); - if (hr != AVIERR_OK) { - return FALSE; - } - - return TRUE; -} - -BOOL AVI_SetText(PAVIFILE pfile, PAVISTREAM psText, char *szText, int width, int height, int TextHeight) -{ - // Fill in the stream header for the text stream.... - AVISTREAMINFO strhdr; - DWORD dwTextFormat; - // The text stream is in 60ths of a second.... - - memset(&strhdr, 0, sizeof(strhdr)); - strhdr.fccType = streamtypeTEXT; - strhdr.fccHandler = mmioFOURCC('D', 'R', 'A', 'W'); - strhdr.dwScale = 1; - strhdr.dwRate = 60; - strhdr.dwSuggestedBufferSize = sizeof(szText); - SetRect(&strhdr.rcFrame, 0, (int) height, - (int) width, (int) height + TextHeight); // #define TEXT_HEIGHT 20 - - // ....and create the stream. - HRESULT hr = AVIFileCreateStream(pfile, &psText, &strhdr); - if (hr != AVIERR_OK) { - return FALSE; - } - - dwTextFormat = sizeof(dwTextFormat); - hr = AVIStreamSetFormat(psText, 0, &dwTextFormat, sizeof(dwTextFormat)); - if (hr != AVIERR_OK) { - return FALSE; - } - - return TRUE; -} - -BOOL AVI_AddFrame(PAVISTREAM psCompressed, int time, LPBITMAPINFOHEADER lpbi) -{ - int ImageSize = lpbi->biSizeImage; - if (ImageSize == 0) - { - if (lpbi->biBitCount == 24) - { - ImageSize = lpbi->biWidth * lpbi->biHeight * 3; - } - } - HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer - time, // time of this frame - 1, // number to write - (LPBYTE) lpbi + // pointer to data - lpbi->biSize + - lpbi->biClrUsed * sizeof(RGBQUAD), - ImageSize, // lpbi->biSizeImage, // size of this frame - AVIIF_KEYFRAME, // flags.... - NULL, - NULL); - if (hr != AVIERR_OK) - { - char strMsg[255]; - _snprintf(strMsg, 255, "Error: AVIStreamWrite, error %d",hr); - MessageBox(NULL, strMsg, "", MB_OK); - return FALSE; - } - - return TRUE; -} - -BOOL AVI_AddText(PAVISTREAM psText, int time, char *szText) -{ - int iLen = (int)strlen(szText); - - HRESULT hr = AVIStreamWrite(psText, - time, - 1, - szText, - iLen + 1, - AVIIF_KEYFRAME, - NULL, - NULL); - if (hr != AVIERR_OK) - return FALSE; - - return TRUE; -} - -BOOL AVI_CloseStream(PAVISTREAM ps, PAVISTREAM psCompressed, PAVISTREAM psText) -{ - if (ps) - AVIStreamClose(ps); - - if (psCompressed) - AVIStreamClose(psCompressed); - - if (psText) - AVIStreamClose(psText); - - - - return TRUE; -} - -BOOL AVI_CloseFile(PAVIFILE pfile) -{ - if (pfile) - AVIFileClose(pfile); - - return TRUE; -} - -BOOL AVI_Exit() -{ - AVIFileExit(); - - return TRUE; -} - - - - - - - - - - - - - - - - -/* Here are the additional functions we need! */ - - -static PAVIFILE pfile = NULL; -static PAVISTREAM ps = NULL; -static PAVISTREAM psCompressed = NULL; -static int count = 0; - - -// Initialization... -bool START_AVI(const char* file_name) -{ - if(! AVI_Init()) - { - //printf("Error - AVI_Init()\n"); - return false; - } - - if(! AVI_FileOpenWrite(&pfile, file_name)) - { - //printf("Error - AVI_FileOpenWrite()\n"); - return false; - } - - return true; -} - -bool ADD_FRAME_FROM_DIB_TO_AVI(const char* _compressor, int _frameRate, int width, int height, int bits, void* pdata) -{ - if(count == 0) - { - if(! AVI_CreateStream(pfile, &ps, _frameRate, - width*height/bits, - width, - height, _compressor)) - { - //printf("Error - AVI_CreateStream()\n"); - return false; - } - - BITMAPINFOHEADER bi; - memset(&bi, 0, sizeof(bi)); - bi.biSize = sizeof(BITMAPINFOHEADER); - bi.biWidth = width; - bi.biHeight = height; - bi.biPlanes = 1; - bi.biBitCount = bits; - bi.biCompression = BI_RGB; - bi.biSizeImage = width * height * bits /8; - if(! AVI_SetOptions(&ps, &psCompressed, &bi, _compressor)) - { - return false; - } - } - - HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer - count, // time of this frame - 1, // number to write - pdata, - width*height/8, // lpbi->biSizeImage, // size of this frame - AVIIF_KEYFRAME, // flags.... - NULL, - NULL); - if (hr != AVIERR_OK) - { - char strMsg[255]; - _snprintf(strMsg, 255, "Error: AVIStreamWrite, error %d",hr); - MessageBox(NULL, strMsg, "", MB_OK); - return FALSE; - } - - count++; - return true; -} - -//Now we can add frames -// ie. ADD_FRAME_FROM_DIB_TO_AVI(yourDIB, "CVID", 25); -bool ADD_FRAME_FROM_DIB_TO_AVI(HANDLE dib, const char* _compressor, int _frameRate) -{ - LPBITMAPINFOHEADER lpbi; - if(count == 0) - { - lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib); - if(! AVI_CreateStream(pfile, &ps, _frameRate, - (unsigned long) lpbi->biSizeImage, - (int) lpbi->biWidth, - (int) lpbi->biHeight, _compressor)) - { - //printf("Error - AVI_CreateStream()\n"); - GlobalUnlock(lpbi); - return false; - } - - if(! AVI_SetOptions(&ps, &psCompressed, lpbi, _compressor)) - { - //printf("Error - AVI_SetOptions()\n"); - GlobalUnlock(lpbi); - return false; - } - - GlobalUnlock(lpbi); - } - - lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib); - if(! AVI_AddFrame(psCompressed, count * 1, lpbi)) - { - //printf("Error - AVI_AddFrame()\n"); - GlobalUnlock(lpbi); - return false; - } - - GlobalUnlock(lpbi); - count++; - return true; -} - -// The end... -bool STOP_AVI() -{ - if(! AVI_CloseStream(ps, psCompressed, NULL)) - { - //printf("Error - AVI_CloseStream()\n"); - return false; - } - - if(! AVI_CloseFile(pfile)) - { - //printf("Error - AVI_CloseFile()\n"); - return false; - } - - if(! AVI_Exit()) - { - //printf("Error - AVI_Exit()\n"); - return false; - } - - return true; -} - +#define AVIIF_KEYFRAME 0x00000010L // this frame is a key frame. + +#include +using namespace std; + +#include +#include +#include + +BOOL AVI_Init() +{ + /* first let's make sure we are running on 1.1 */ + WORD wVer = HIWORD(VideoForWindowsVersion()); + if (wVer < 0x010a){ + /* oops, we are too old, blow out of here */ + //MessageBeep(MB_ICONHAND); + MessageBox(NULL, "Cant't init AVI File - Video for Windows version is to old", "Error", MB_OK|MB_ICONSTOP); + return FALSE; + } + + AVIFileInit(); + + return TRUE; +} + +BOOL AVI_FileOpenWrite(PAVIFILE * pfile, const char *filename) +{ + HRESULT hr = AVIFileOpen(pfile, // returned file pointer + filename, // file name + OF_WRITE | OF_CREATE, // mode to open file with + NULL); // use handler determined + // from file extension.... + if (hr != AVIERR_OK) + return FALSE; + + return TRUE; +} + +DWORD getFOURCC(const char* value) +{ + if(_stricmp(value, "DIB") == 0) + { + return mmioFOURCC(value[0],value[1],value[2],' '); + } + else if((_stricmp(value, "CVID") == 0) + || (_stricmp(value, "IV32") == 0) + || (_stricmp(value, "MSVC") == 0) + || (_stricmp(value, "IV50") == 0)) + { + return mmioFOURCC(value[0],value[1],value[2],value[3]); + } + else + { + return NULL; + } +} + +// Fill in the header for the video stream.... +// The video stream will run in rate ths of a second.... +BOOL AVI_CreateStream(PAVIFILE pfile, PAVISTREAM * ps, int rate, // sample/second + unsigned long buffersize, int rectwidth, int rectheight, + const char* _compressor) +{ + AVISTREAMINFO strhdr; + memset(&strhdr, 0, sizeof(strhdr)); + strhdr.fccType = streamtypeVIDEO;// stream type + strhdr.fccHandler = getFOURCC(_compressor); + //strhdr.fccHandler = 0; // no compression! + //strhdr.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed + //strhdr.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak + //strhdr.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2 + //strhdr.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1 + //strhdr.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0 + //strhdr.dwFlags = AVISTREAMINFO_DISABLED; + //strhdr.dwCaps = + //strhdr.wPriority = + //strhdr.wLanguage = + strhdr.dwScale = 1; + strhdr.dwRate = rate; // rate fps + //strhdr.dwStart = + //strhdr.dwLength = + //strhdr.dwInitialFrames = + strhdr.dwSuggestedBufferSize = buffersize; + strhdr.dwQuality = -1; // use the default + //strhdr.dwSampleSize = + SetRect(&strhdr.rcFrame, 0, 0, // rectangle for stream + (int) rectwidth, + (int) rectheight); + //strhdr.dwEditCount = + //strhdr.dwFormatChangeCount = + //strcpy(strhdr.szName, "Full Frames (Uncompressed)"); + + // And create the stream; + HRESULT hr = AVIFileCreateStream(pfile, // file pointer + ps, // returned stream pointer + &strhdr); // stream header + if (hr != AVIERR_OK) { + return FALSE; + } + + return TRUE; +} + +string getFOURCCVAsString(DWORD value) +{ + string returnValue = ""; + if( value == 0 ) + return returnValue; + + DWORD ch0 = value & 0x000000FF; + returnValue.push_back((char) ch0); + DWORD ch1 = (value & 0x0000FF00)>>8; + returnValue.push_back((char) ch1); + DWORD ch2 = (value & 0x00FF0000)>>16; + returnValue.push_back((char) ch2); + DWORD ch3 = (value & 0xFF000000)>>24; + returnValue.push_back((char) ch3); + + return returnValue; +} + +string dumpAVICOMPRESSOPTIONS(AVICOMPRESSOPTIONS opts) +{ + char tmp[255]; + string returnValue = "Dump of AVICOMPRESSOPTIONS\n"; + + returnValue += "DWORD fccType = streamtype("; returnValue += getFOURCCVAsString(opts.fccType); returnValue += ")\n"; + returnValue += "DWORD fccHandler = "; returnValue += getFOURCCVAsString(opts.fccHandler); returnValue += "\n"; + + _snprintf(tmp, 255, "DWORD dwKeyFrameEvery = %d\n", opts.dwKeyFrameEvery); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD dwQuality = %d\n", opts.dwQuality); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD dwBytesPerSecond = %d\n", opts.dwBytesPerSecond); + returnValue += tmp; + + if((opts.dwFlags & AVICOMPRESSF_DATARATE) == AVICOMPRESSF_DATARATE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_DATARATE\n");} + else if((opts.dwFlags & AVICOMPRESSF_INTERLEAVE) == AVICOMPRESSF_INTERLEAVE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_INTERLEAVE\n");} + else if((opts.dwFlags & AVICOMPRESSF_KEYFRAMES) == AVICOMPRESSF_KEYFRAMES){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_KEYFRAMES\n");} + else if((opts.dwFlags & AVICOMPRESSF_VALID) == AVICOMPRESSF_VALID){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_VALID\n");} + else {_snprintf(tmp, 255, "DWORD dwFlags = Unknown(%d)\n", opts.dwFlags);} + returnValue += tmp; + + _snprintf(tmp, 255, "LPVOID lpFormat = %d\n", (int)opts.lpFormat); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD cbFormat = %d\n", opts.cbFormat); + returnValue += tmp; + + _snprintf(tmp, 255, "LPVOID lpParms = %d\n", (int)opts.lpParms); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD cbParms = %d\n", opts.cbParms); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD dwInterleaveEvery = %d\n", opts.dwInterleaveEvery); + returnValue += tmp; + + return returnValue; +} + +BOOL AVI_SetOptions(PAVISTREAM * ps, PAVISTREAM * psCompressed, LPBITMAPINFOHEADER lpbi, + const char* _compressor) +{ + + AVICOMPRESSOPTIONS opts; + AVICOMPRESSOPTIONS FAR * aopts[1] = {&opts}; + + memset(&opts, 0, sizeof(opts)); + opts.fccType = streamtypeVIDEO; + opts.fccHandler = getFOURCC(_compressor); + //opts.fccHandler = 0; + //opts.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed + //opts.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak + //opts.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2 + //opts.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1 + //opts.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0 + //opts.dwKeyFrameEvery = 5; + //opts.dwQuality + //opts.dwBytesPerSecond + //opts.dwFlags = AVICOMPRESSF_KEYFRAMES; + //opts.lpFormat + //opts.cbFormat + //opts.lpParms + //opts.cbParms + //opts.dwInterleaveEvery + + /* display the compression options dialog box if specified compressor is unknown */ + if(getFOURCC(_compressor) == NULL) + { + if (!AVISaveOptions(NULL, 0, 1, ps, (LPAVICOMPRESSOPTIONS FAR *) &aopts)) + { + return FALSE; + } + + //printf("%s", dumpAVICOMPRESSOPTIONS(opts)); + //MessageBox(NULL, dumpAVICOMPRESSOPTIONS(opts).c_str(), "AVICOMPRESSOPTIONS", MB_OK); + } + + HRESULT hr = AVIMakeCompressedStream(psCompressed, *ps, &opts, NULL); + if (hr != AVIERR_OK) { + return FALSE; + } + + hr = AVIStreamSetFormat(*psCompressed, 0, + lpbi, // stream format + lpbi->biSize // format size + + lpbi->biClrUsed * sizeof(RGBQUAD) + ); + if (hr != AVIERR_OK) { + return FALSE; + } + + return TRUE; +} + +BOOL AVI_SetText(PAVIFILE pfile, PAVISTREAM psText, char *szText, int width, int height, int TextHeight) +{ + // Fill in the stream header for the text stream.... + AVISTREAMINFO strhdr; + DWORD dwTextFormat; + // The text stream is in 60ths of a second.... + + memset(&strhdr, 0, sizeof(strhdr)); + strhdr.fccType = streamtypeTEXT; + strhdr.fccHandler = mmioFOURCC('D', 'R', 'A', 'W'); + strhdr.dwScale = 1; + strhdr.dwRate = 60; + strhdr.dwSuggestedBufferSize = sizeof(szText); + SetRect(&strhdr.rcFrame, 0, (int) height, + (int) width, (int) height + TextHeight); // #define TEXT_HEIGHT 20 + + // ....and create the stream. + HRESULT hr = AVIFileCreateStream(pfile, &psText, &strhdr); + if (hr != AVIERR_OK) { + return FALSE; + } + + dwTextFormat = sizeof(dwTextFormat); + hr = AVIStreamSetFormat(psText, 0, &dwTextFormat, sizeof(dwTextFormat)); + if (hr != AVIERR_OK) { + return FALSE; + } + + return TRUE; +} + +BOOL AVI_AddFrame(PAVISTREAM psCompressed, int time, LPBITMAPINFOHEADER lpbi) +{ + int ImageSize = lpbi->biSizeImage; + if (ImageSize == 0) + { + if (lpbi->biBitCount == 24) + { + ImageSize = lpbi->biWidth * lpbi->biHeight * 3; + } + } + HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer + time, // time of this frame + 1, // number to write + (LPBYTE) lpbi + // pointer to data + lpbi->biSize + + lpbi->biClrUsed * sizeof(RGBQUAD), + ImageSize, // lpbi->biSizeImage, // size of this frame + AVIIF_KEYFRAME, // flags.... + NULL, + NULL); + if (hr != AVIERR_OK) + { + char strMsg[255]; + _snprintf(strMsg, 255, "Error: AVIStreamWrite, error %d",hr); + MessageBox(NULL, strMsg, "", MB_OK); + return FALSE; + } + + return TRUE; +} + +BOOL AVI_AddText(PAVISTREAM psText, int time, char *szText) +{ + int iLen = (int)strlen(szText); + + HRESULT hr = AVIStreamWrite(psText, + time, + 1, + szText, + iLen + 1, + AVIIF_KEYFRAME, + NULL, + NULL); + if (hr != AVIERR_OK) + return FALSE; + + return TRUE; +} + +BOOL AVI_CloseStream(PAVISTREAM ps, PAVISTREAM psCompressed, PAVISTREAM psText) +{ + if (ps) + AVIStreamClose(ps); + + if (psCompressed) + AVIStreamClose(psCompressed); + + if (psText) + AVIStreamClose(psText); + + + + return TRUE; +} + +BOOL AVI_CloseFile(PAVIFILE pfile) +{ + if (pfile) + AVIFileClose(pfile); + + return TRUE; +} + +BOOL AVI_Exit() +{ + AVIFileExit(); + + return TRUE; +} + + + + + + + + + + + + + + + + +/* Here are the additional functions we need! */ + + +static PAVIFILE pfile = NULL; +static PAVISTREAM ps = NULL; +static PAVISTREAM psCompressed = NULL; +static int count = 0; + + +// Initialization... +bool START_AVI(const char* file_name) +{ + if(! AVI_Init()) + { + //printf("Error - AVI_Init()\n"); + return false; + } + + if(! AVI_FileOpenWrite(&pfile, file_name)) + { + //printf("Error - AVI_FileOpenWrite()\n"); + return false; + } + + return true; +} + +bool ADD_FRAME_FROM_DIB_TO_AVI(const char* _compressor, int _frameRate, int width, int height, int bits, void* pdata) +{ + if(count == 0) + { + if(! AVI_CreateStream(pfile, &ps, _frameRate, + width*height/bits, + width, + height, _compressor)) + { + //printf("Error - AVI_CreateStream()\n"); + return false; + } + + BITMAPINFOHEADER bi; + memset(&bi, 0, sizeof(bi)); + bi.biSize = sizeof(BITMAPINFOHEADER); + bi.biWidth = width; + bi.biHeight = height; + bi.biPlanes = 1; + bi.biBitCount = bits; + bi.biCompression = BI_RGB; + bi.biSizeImage = width * height * bits /8; + if(! AVI_SetOptions(&ps, &psCompressed, &bi, _compressor)) + { + return false; + } + } + + HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer + count, // time of this frame + 1, // number to write + pdata, + width*height/8, // lpbi->biSizeImage, // size of this frame + AVIIF_KEYFRAME, // flags.... + NULL, + NULL); + if (hr != AVIERR_OK) + { + char strMsg[255]; + _snprintf(strMsg, 255, "Error: AVIStreamWrite, error %d",hr); + MessageBox(NULL, strMsg, "", MB_OK); + return FALSE; + } + + count++; + return true; +} + +//Now we can add frames +// ie. ADD_FRAME_FROM_DIB_TO_AVI(yourDIB, "CVID", 25); +bool ADD_FRAME_FROM_DIB_TO_AVI(HANDLE dib, const char* _compressor, int _frameRate) +{ + LPBITMAPINFOHEADER lpbi; + if(count == 0) + { + lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib); + if(! AVI_CreateStream(pfile, &ps, _frameRate, + (unsigned long) lpbi->biSizeImage, + (int) lpbi->biWidth, + (int) lpbi->biHeight, _compressor)) + { + //printf("Error - AVI_CreateStream()\n"); + GlobalUnlock(lpbi); + return false; + } + + if(! AVI_SetOptions(&ps, &psCompressed, lpbi, _compressor)) + { + //printf("Error - AVI_SetOptions()\n"); + GlobalUnlock(lpbi); + return false; + } + + GlobalUnlock(lpbi); + } + + lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib); + if(! AVI_AddFrame(psCompressed, count * 1, lpbi)) + { + //printf("Error - AVI_AddFrame()\n"); + GlobalUnlock(lpbi); + return false; + } + + GlobalUnlock(lpbi); + count++; + return true; +} + +// The end... +bool STOP_AVI() +{ + if(! AVI_CloseStream(ps, psCompressed, NULL)) + { + //printf("Error - AVI_CloseStream()\n"); + return false; + } + + if(! AVI_CloseFile(pfile)) + { + //printf("Error - AVI_CloseFile()\n"); + return false; + } + + if(! AVI_Exit()) + { + //printf("Error - AVI_Exit()\n"); + return false; + } + + return true; +} + diff --git a/plugins/zerogs/opengl/Win32/jconfig.h b/plugins/zerogs/opengl/Win32/jconfig.h index 1f43a6e119..cf6420d500 100644 --- a/plugins/zerogs/opengl/Win32/jconfig.h +++ b/plugins/zerogs/opengl/Win32/jconfig.h @@ -1,52 +1,52 @@ -/* jconfig.mc6 --- jconfig.h for Microsoft C on MS-DOS, version 6.00A & up. */ -/* see jconfig.doc for explanations */ - -#define HAVE_PROTOTYPES -#define HAVE_UNSIGNED_CHAR -#define HAVE_UNSIGNED_SHORT -/* #define void char */ -/* #define const */ -#undef CHAR_IS_UNSIGNED -#define HAVE_STDDEF_H -#define HAVE_STDLIB_H -#undef NEED_BSD_STRINGS -#undef NEED_SYS_TYPES_H -//#define NEED_FAR_POINTERS /* for small or medium memory model */ -#undef NEED_SHORT_EXTERNAL_NAMES -#undef INCOMPLETE_TYPES_BROKEN - -#ifdef JPEG_INTERNALS - -#undef RIGHT_SHIFT_IS_UNSIGNED - -//#define USE_MSDOS_MEMMGR /* Define this if you use jmemdos.c */ - -#define MAX_ALLOC_CHUNK 65520L /* Maximum request to malloc() */ - -//#define USE_FMEM /* Microsoft has _fmemcpy() and _fmemset() */ - -#define NEED_FHEAPMIN /* far heap management routines are broken */ - -#define SHORTxLCONST_32 /* enable compiler-specific DCT optimization */ -/* Note: the above define is known to improve the code with Microsoft C 6.00A. - * I do not know whether it is good for later compiler versions. - * Please report any info on this point to jpeg-info@uunet.uu.net. - */ - -#endif /* JPEG_INTERNALS */ - -#ifdef JPEG_CJPEG_DJPEG - -#define BMP_SUPPORTED /* BMP image file format */ -#define GIF_SUPPORTED /* GIF image file format */ -#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ -#undef RLE_SUPPORTED /* Utah RLE image file format */ -#define TARGA_SUPPORTED /* Targa image file format */ - -#define TWO_FILE_COMMANDLINE -#define USE_SETMODE /* Microsoft has setmode() */ -#define NEED_SIGNAL_CATCHER /* Define this if you use jmemdos.c */ -#undef DONT_USE_B_MODE -#undef PROGRESS_REPORT /* optional */ - -#endif /* JPEG_CJPEG_DJPEG */ +/* jconfig.mc6 --- jconfig.h for Microsoft C on MS-DOS, version 6.00A & up. */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +/* #define void char */ +/* #define const */ +#undef CHAR_IS_UNSIGNED +#define HAVE_STDDEF_H +#define HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +//#define NEED_FAR_POINTERS /* for small or medium memory model */ +#undef NEED_SHORT_EXTERNAL_NAMES +#undef INCOMPLETE_TYPES_BROKEN + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED + +//#define USE_MSDOS_MEMMGR /* Define this if you use jmemdos.c */ + +#define MAX_ALLOC_CHUNK 65520L /* Maximum request to malloc() */ + +//#define USE_FMEM /* Microsoft has _fmemcpy() and _fmemset() */ + +#define NEED_FHEAPMIN /* far heap management routines are broken */ + +#define SHORTxLCONST_32 /* enable compiler-specific DCT optimization */ +/* Note: the above define is known to improve the code with Microsoft C 6.00A. + * I do not know whether it is good for later compiler versions. + * Please report any info on this point to jpeg-info@uunet.uu.net. + */ + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#define TWO_FILE_COMMANDLINE +#define USE_SETMODE /* Microsoft has setmode() */ +#define NEED_SIGNAL_CATCHER /* Define this if you use jmemdos.c */ +#undef DONT_USE_B_MODE +#undef PROGRESS_REPORT /* optional */ + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/plugins/zerogs/opengl/Win32/jmorecfg.h b/plugins/zerogs/opengl/Win32/jmorecfg.h index c856e2260c..54a7d1c447 100644 --- a/plugins/zerogs/opengl/Win32/jmorecfg.h +++ b/plugins/zerogs/opengl/Win32/jmorecfg.h @@ -1,363 +1,363 @@ -/* - * jmorecfg.h - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains additional configuration options that customize the - * JPEG software for special applications or support machine-dependent - * optimizations. Most users will not need to touch this file. - */ - - -/* - * Define BITS_IN_JSAMPLE as either - * 8 for 8-bit sample values (the usual setting) - * 12 for 12-bit sample values - * Only 8 and 12 are legal data precisions for lossy JPEG according to the - * JPEG standard, and the IJG code does not support anything else! - * We do not support run-time selection of data precision, sorry. - */ - -#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ - - -/* - * Maximum number of components (color channels) allowed in JPEG image. - * To meet the letter of the JPEG spec, set this to 255. However, darn - * few applications need more than 4 channels (maybe 5 for CMYK + alpha - * mask). We recommend 10 as a reasonable compromise; use 4 if you are - * really short on memory. (Each allowed component costs a hundred or so - * bytes of storage, whether actually used in an image or not.) - */ - -#define MAX_COMPONENTS 10 /* maximum number of image components */ - - -/* - * Basic data types. - * You may need to change these if you have a machine with unusual data - * type sizes; for example, "char" not 8 bits, "short" not 16 bits, - * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, - * but it had better be at least 16. - */ - -/* Representation of a single sample (pixel element value). - * We frequently allocate large arrays of these, so it's important to keep - * them small. But if you have memory to burn and access to char or short - * arrays is very slow on your hardware, you might want to change these. - */ - -#if BITS_IN_JSAMPLE == 8 -/* JSAMPLE should be the smallest type that will hold the values 0..255. - * You can use a signed char by having GETJSAMPLE mask it with 0xFF. - */ - -#ifdef HAVE_UNSIGNED_CHAR - -typedef unsigned char JSAMPLE; -#define GETJSAMPLE(value) ((int) (value)) - -#else /* not HAVE_UNSIGNED_CHAR */ - -typedef char JSAMPLE; -#ifdef CHAR_IS_UNSIGNED -#define GETJSAMPLE(value) ((int) (value)) -#else -#define GETJSAMPLE(value) ((int) (value) & 0xFF) -#endif /* CHAR_IS_UNSIGNED */ - -#endif /* HAVE_UNSIGNED_CHAR */ - -#define MAXJSAMPLE 255 -#define CENTERJSAMPLE 128 - -#endif /* BITS_IN_JSAMPLE == 8 */ - - -#if BITS_IN_JSAMPLE == 12 -/* JSAMPLE should be the smallest type that will hold the values 0..4095. - * On nearly all machines "short" will do nicely. - */ - -typedef short JSAMPLE; -#define GETJSAMPLE(value) ((int) (value)) - -#define MAXJSAMPLE 4095 -#define CENTERJSAMPLE 2048 - -#endif /* BITS_IN_JSAMPLE == 12 */ - - -/* Representation of a DCT frequency coefficient. - * This should be a signed value of at least 16 bits; "short" is usually OK. - * Again, we allocate large arrays of these, but you can change to int - * if you have memory to burn and "short" is really slow. - */ - -typedef short JCOEF; - - -/* Compressed datastreams are represented as arrays of JOCTET. - * These must be EXACTLY 8 bits wide, at least once they are written to - * external storage. Note that when using the stdio data source/destination - * managers, this is also the data type passed to fread/fwrite. - */ - -#ifdef HAVE_UNSIGNED_CHAR - -typedef unsigned char JOCTET; -#define GETJOCTET(value) (value) - -#else /* not HAVE_UNSIGNED_CHAR */ - -typedef char JOCTET; -#ifdef CHAR_IS_UNSIGNED -#define GETJOCTET(value) (value) -#else -#define GETJOCTET(value) ((value) & 0xFF) -#endif /* CHAR_IS_UNSIGNED */ - -#endif /* HAVE_UNSIGNED_CHAR */ - - -/* These typedefs are used for various table entries and so forth. - * They must be at least as wide as specified; but making them too big - * won't cost a huge amount of memory, so we don't provide special - * extraction code like we did for JSAMPLE. (In other words, these - * typedefs live at a different point on the speed/space tradeoff curve.) - */ - -/* UINT8 must hold at least the values 0..255. */ - -#ifdef HAVE_UNSIGNED_CHAR -typedef unsigned char UINT8; -#else /* not HAVE_UNSIGNED_CHAR */ -#ifdef CHAR_IS_UNSIGNED -typedef char UINT8; -#else /* not CHAR_IS_UNSIGNED */ -typedef short UINT8; -#endif /* CHAR_IS_UNSIGNED */ -#endif /* HAVE_UNSIGNED_CHAR */ - -/* UINT16 must hold at least the values 0..65535. */ - -#ifdef HAVE_UNSIGNED_SHORT -typedef unsigned short UINT16; -#else /* not HAVE_UNSIGNED_SHORT */ -typedef unsigned int UINT16; -#endif /* HAVE_UNSIGNED_SHORT */ - -/* INT16 must hold at least the values -32768..32767. */ - -#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ -typedef short INT16; -#endif - -/* INT32 must hold at least signed 32-bit values. */ - -#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ -typedef long INT32; -#endif - -/* Datatype used for image dimensions. The JPEG standard only supports - * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore - * "unsigned int" is sufficient on all machines. However, if you need to - * handle larger images and you don't mind deviating from the spec, you - * can change this datatype. - */ - -typedef unsigned int JDIMENSION; - -#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ - - -/* These macros are used in all function definitions and extern declarations. - * You could modify them if you need to change function linkage conventions; - * in particular, you'll need to do that to make the library a Windows DLL. - * Another application is to make all functions global for use with debuggers - * or code profilers that require it. - */ - -/* a function called through method pointers: */ -#define METHODDEF(type) static type -/* a function used only in its module: */ -#define LOCAL(type) static type -/* a function referenced thru EXTERNs: */ -#define GLOBAL(type) type -/* a reference to a GLOBAL function: */ -#define EXTERN(type) extern type - - -/* This macro is used to declare a "method", that is, a function pointer. - * We want to supply prototype parameters if the compiler can cope. - * Note that the arglist parameter must be parenthesized! - * Again, you can customize this if you need special linkage keywords. - */ - -#ifdef HAVE_PROTOTYPES -#define JMETHOD(type,methodname,arglist) type (*methodname) arglist -#else -#define JMETHOD(type,methodname,arglist) type (*methodname) () -#endif - - -/* Here is the pseudo-keyword for declaring pointers that must be "far" - * on 80x86 machines. Most of the specialized coding for 80x86 is handled - * by just saying "FAR *" where such a pointer is needed. In a few places - * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. - */ - -#ifdef NEED_FAR_POINTERS -#define FAR far -#else -#define FAR -#endif - - -/* - * On a few systems, type boolean and/or its values FALSE, TRUE may appear - * in standard header files. Or you may have conflicts with application- - * specific header files that you want to include together with these files. - * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. - */ - -#ifndef HAVE_BOOLEAN -typedef int boolean; -#endif -#ifndef FALSE /* in case these macros already exist */ -#define FALSE 0 /* values of boolean */ -#endif -#ifndef TRUE -#define TRUE 1 -#endif - - -/* - * The remaining options affect code selection within the JPEG library, - * but they don't need to be visible to most applications using the library. - * To minimize application namespace pollution, the symbols won't be - * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. - */ - -#ifdef JPEG_INTERNALS -#define JPEG_INTERNAL_OPTIONS -#endif - -#ifdef JPEG_INTERNAL_OPTIONS - - -/* - * These defines indicate whether to include various optional functions. - * Undefining some of these symbols will produce a smaller but less capable - * library. Note that you can leave certain source files out of the - * compilation/linking process if you've #undef'd the corresponding symbols. - * (You may HAVE to do that if your compiler doesn't like null source files.) - */ - -/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */ - -/* Capability options common to encoder and decoder: */ - -#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ -#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ -#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ - -/* Encoder capability options: */ - -#undef C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ -#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ -#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ -#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ -/* Note: if you selected 12-bit data precision, it is dangerous to turn off - * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit - * precision, so jchuff.c normally uses entropy optimization to compute - * usable tables for higher precision. If you don't want to do optimization, - * you'll have to supply different default Huffman tables. - * The exact same statements apply for progressive JPEG: the default tables - * don't work for progressive mode. (This may get fixed, however.) - */ -#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ - -/* Decoder capability options: */ - -#undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ -#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ -#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ -#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ -#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ -#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ -#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ -#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ -#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ -#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ - -/* more capability options later, no doubt */ - - -/* - * Ordering of RGB data in scanlines passed to or from the application. - * If your application wants to deal with data in the order B,G,R, just - * change these macros. You can also deal with formats such as R,G,B,X - * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing - * the offsets will also change the order in which colormap data is organized. - * RESTRICTIONS: - * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. - * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not - * useful if you are using JPEG color spaces other than YCbCr or grayscale. - * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE - * is not 3 (they don't understand about dummy color components!). So you - * can't use color quantization if you change that value. - */ - -#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ -#define RGB_GREEN 1 /* Offset of Green */ -#define RGB_BLUE 2 /* Offset of Blue */ -#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ - - -/* Definitions for speed-related optimizations. */ - - -/* If your compiler supports inline functions, define INLINE - * as the inline keyword; otherwise define it as empty. - */ - -#ifndef INLINE -#ifdef __GNUC__ /* for instance, GNU C knows about inline */ -#define INLINE __inline__ -#endif -#ifndef INLINE -#define INLINE /* default is to define it as empty */ -#endif -#endif - - -/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying - * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER - * as short on such a machine. MULTIPLIER must be at least 16 bits wide. - */ - -#ifndef MULTIPLIER -#define MULTIPLIER int /* type for fastest integer multiply */ -#endif - - -/* FAST_FLOAT should be either float or double, whichever is done faster - * by your compiler. (Note that this type is only used in the floating point - * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) - * Typically, float is faster in ANSI C compilers, while double is faster in - * pre-ANSI compilers (because they insist on converting to double anyway). - * The code below therefore chooses float if we have ANSI-style prototypes. - */ - -#ifndef FAST_FLOAT -#ifdef HAVE_PROTOTYPES -#define FAST_FLOAT float -#else -#define FAST_FLOAT double -#endif -#endif - -#endif /* JPEG_INTERNAL_OPTIONS */ +/* + * jmorecfg.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains additional configuration options that customize the + * JPEG software for special applications or support machine-dependent + * optimizations. Most users will not need to touch this file. + */ + + +/* + * Define BITS_IN_JSAMPLE as either + * 8 for 8-bit sample values (the usual setting) + * 12 for 12-bit sample values + * Only 8 and 12 are legal data precisions for lossy JPEG according to the + * JPEG standard, and the IJG code does not support anything else! + * We do not support run-time selection of data precision, sorry. + */ + +#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ + + +/* + * Maximum number of components (color channels) allowed in JPEG image. + * To meet the letter of the JPEG spec, set this to 255. However, darn + * few applications need more than 4 channels (maybe 5 for CMYK + alpha + * mask). We recommend 10 as a reasonable compromise; use 4 if you are + * really short on memory. (Each allowed component costs a hundred or so + * bytes of storage, whether actually used in an image or not.) + */ + +#define MAX_COMPONENTS 10 /* maximum number of image components */ + + +/* + * Basic data types. + * You may need to change these if you have a machine with unusual data + * type sizes; for example, "char" not 8 bits, "short" not 16 bits, + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + * but it had better be at least 16. + */ + +/* Representation of a single sample (pixel element value). + * We frequently allocate large arrays of these, so it's important to keep + * them small. But if you have memory to burn and access to char or short + * arrays is very slow on your hardware, you might want to change these. + */ + +#if BITS_IN_JSAMPLE == 8 +/* JSAMPLE should be the smallest type that will hold the values 0..255. + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JSAMPLE; +#ifdef CHAR_IS_UNSIGNED +#define GETJSAMPLE(value) ((int) (value)) +#else +#define GETJSAMPLE(value) ((int) (value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 + +#endif /* BITS_IN_JSAMPLE == 8 */ + + +#if BITS_IN_JSAMPLE == 12 +/* JSAMPLE should be the smallest type that will hold the values 0..4095. + * On nearly all machines "short" will do nicely. + */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#define MAXJSAMPLE 4095 +#define CENTERJSAMPLE 2048 + +#endif /* BITS_IN_JSAMPLE == 12 */ + + +/* Representation of a DCT frequency coefficient. + * This should be a signed value of at least 16 bits; "short" is usually OK. + * Again, we allocate large arrays of these, but you can change to int + * if you have memory to burn and "short" is really slow. + */ + +typedef short JCOEF; + + +/* Compressed datastreams are represented as arrays of JOCTET. + * These must be EXACTLY 8 bits wide, at least once they are written to + * external storage. Note that when using the stdio data source/destination + * managers, this is also the data type passed to fread/fwrite. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JOCTET; +#define GETJOCTET(value) (value) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JOCTET; +#ifdef CHAR_IS_UNSIGNED +#define GETJOCTET(value) (value) +#else +#define GETJOCTET(value) ((value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + + +/* These typedefs are used for various table entries and so forth. + * They must be at least as wide as specified; but making them too big + * won't cost a huge amount of memory, so we don't provide special + * extraction code like we did for JSAMPLE. (In other words, these + * typedefs live at a different point on the speed/space tradeoff curve.) + */ + +/* UINT8 must hold at least the values 0..255. */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char UINT8; +#else /* not HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char UINT8; +#else /* not CHAR_IS_UNSIGNED */ +typedef short UINT8; +#endif /* CHAR_IS_UNSIGNED */ +#endif /* HAVE_UNSIGNED_CHAR */ + +/* UINT16 must hold at least the values 0..65535. */ + +#ifdef HAVE_UNSIGNED_SHORT +typedef unsigned short UINT16; +#else /* not HAVE_UNSIGNED_SHORT */ +typedef unsigned int UINT16; +#endif /* HAVE_UNSIGNED_SHORT */ + +/* INT16 must hold at least the values -32768..32767. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ +typedef short INT16; +#endif + +/* INT32 must hold at least signed 32-bit values. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ +typedef long INT32; +#endif + +/* Datatype used for image dimensions. The JPEG standard only supports + * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore + * "unsigned int" is sufficient on all machines. However, if you need to + * handle larger images and you don't mind deviating from the spec, you + * can change this datatype. + */ + +typedef unsigned int JDIMENSION; + +#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ + + +/* These macros are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions; + * in particular, you'll need to do that to make the library a Windows DLL. + * Another application is to make all functions global for use with debuggers + * or code profilers that require it. + */ + +/* a function called through method pointers: */ +#define METHODDEF(type) static type +/* a function used only in its module: */ +#define LOCAL(type) static type +/* a function referenced thru EXTERNs: */ +#define GLOBAL(type) type +/* a reference to a GLOBAL function: */ +#define EXTERN(type) extern type + + +/* This macro is used to declare a "method", that is, a function pointer. + * We want to supply prototype parameters if the compiler can cope. + * Note that the arglist parameter must be parenthesized! + * Again, you can customize this if you need special linkage keywords. + */ + +#ifdef HAVE_PROTOTYPES +#define JMETHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define JMETHOD(type,methodname,arglist) type (*methodname) () +#endif + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + * by just saying "FAR *" where such a pointer is needed. In a few places + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + */ + +#ifdef NEED_FAR_POINTERS +#define FAR far +#else +#define FAR +#endif + + +/* + * On a few systems, type boolean and/or its values FALSE, TRUE may appear + * in standard header files. Or you may have conflicts with application- + * specific header files that you want to include together with these files. + * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. + */ + +#ifndef HAVE_BOOLEAN +typedef int boolean; +#endif +#ifndef FALSE /* in case these macros already exist */ +#define FALSE 0 /* values of boolean */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif + + +/* + * The remaining options affect code selection within the JPEG library, + * but they don't need to be visible to most applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. + */ + +#ifdef JPEG_INTERNALS +#define JPEG_INTERNAL_OPTIONS +#endif + +#ifdef JPEG_INTERNAL_OPTIONS + + +/* + * These defines indicate whether to include various optional functions. + * Undefining some of these symbols will produce a smaller but less capable + * library. Note that you can leave certain source files out of the + * compilation/linking process if you've #undef'd the corresponding symbols. + * (You may HAVE to do that if your compiler doesn't like null source files.) + */ + +/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */ + +/* Capability options common to encoder and decoder: */ + +#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ +#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ +#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ + +/* Encoder capability options: */ + +#undef C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ +/* Note: if you selected 12-bit data precision, it is dangerous to turn off + * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit + * precision, so jchuff.c normally uses entropy optimization to compute + * usable tables for higher precision. If you don't want to do optimization, + * you'll have to supply different default Huffman tables. + * The exact same statements apply for progressive JPEG: the default tables + * don't work for progressive mode. (This may get fixed, however.) + */ +#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ + +/* Decoder capability options: */ + +#undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ +#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ +#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ +#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ +#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ + +/* more capability options later, no doubt */ + + +/* + * Ordering of RGB data in scanlines passed to or from the application. + * If your application wants to deal with data in the order B,G,R, just + * change these macros. You can also deal with formats such as R,G,B,X + * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing + * the offsets will also change the order in which colormap data is organized. + * RESTRICTIONS: + * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. + * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not + * useful if you are using JPEG color spaces other than YCbCr or grayscale. + * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE + * is not 3 (they don't understand about dummy color components!). So you + * can't use color quantization if you change that value. + */ + +#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ +#define RGB_GREEN 1 /* Offset of Green */ +#define RGB_BLUE 2 /* Offset of Blue */ +#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ + + +/* Definitions for speed-related optimizations. */ + + +/* If your compiler supports inline functions, define INLINE + * as the inline keyword; otherwise define it as empty. + */ + +#ifndef INLINE +#ifdef __GNUC__ /* for instance, GNU C knows about inline */ +#define INLINE __inline__ +#endif +#ifndef INLINE +#define INLINE /* default is to define it as empty */ +#endif +#endif + + +/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying + * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER + * as short on such a machine. MULTIPLIER must be at least 16 bits wide. + */ + +#ifndef MULTIPLIER +#define MULTIPLIER int /* type for fastest integer multiply */ +#endif + + +/* FAST_FLOAT should be either float or double, whichever is done faster + * by your compiler. (Note that this type is only used in the floating point + * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) + * Typically, float is faster in ANSI C compilers, while double is faster in + * pre-ANSI compilers (because they insist on converting to double anyway). + * The code below therefore chooses float if we have ANSI-style prototypes. + */ + +#ifndef FAST_FLOAT +#ifdef HAVE_PROTOTYPES +#define FAST_FLOAT float +#else +#define FAST_FLOAT double +#endif +#endif + +#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/plugins/zerogs/opengl/Win32/jpeglib.h b/plugins/zerogs/opengl/Win32/jpeglib.h index a893130b38..c1d119199a 100644 --- a/plugins/zerogs/opengl/Win32/jpeglib.h +++ b/plugins/zerogs/opengl/Win32/jpeglib.h @@ -1,1099 +1,1099 @@ -/* - * jpeglib.h - * - * Copyright (C) 1991-1998, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file defines the application interface for the JPEG library. - * Most applications using the library need only include this file, - * and perhaps jerror.h if they want to know the exact error codes. - */ - -#ifndef JPEGLIB_H -#define JPEGLIB_H - -/* - * First we include the configuration files that record how this - * installation of the JPEG library is set up. jconfig.h can be - * generated automatically for many systems. jmorecfg.h contains - * manual configuration options that most people need not worry about. - */ - -#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ -#include "jconfig.h" /* widely used configuration options */ -#endif -#include "jmorecfg.h" /* seldom changed options */ - - -/* Version ID for the JPEG library. - * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". - */ - -#define JPEG_LIB_VERSION 62 /* Version 6b */ - - -/* Various constants determining the sizes of things. - * All of these are specified by the JPEG standard, so don't change them - * if you want to be compatible. - */ - -#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ -#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ -#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ -#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ -#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ -#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ -#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ -/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; - * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. - * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU - * to handle it. We even let you do this from the jconfig.h file. However, - * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe - * sometimes emits noncompliant files doesn't mean you should too. - */ -#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ -#ifndef D_MAX_BLOCKS_IN_MCU -#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ -#endif - - -/* Data structures for images (arrays of samples and of DCT coefficients). - * On 80x86 machines, the image arrays are too big for near pointers, - * but the pointer arrays can fit in near memory. - */ - -#undef FAR -#define FAR - -typedef JSAMPLE *JSAMPROW; /* ptr to one image row of pixel samples. */ -typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ -typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ - -typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ -typedef JBLOCK *JBLOCKROW; /* pointer to one row of coefficient blocks */ -typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ -typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ - -typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ - - -/* Types for JPEG compression parameters and working tables. */ - - -/* DCT coefficient quantization tables. */ - -typedef struct { - /* This array gives the coefficient quantizers in natural array order - * (not the zigzag order in which they are stored in a JPEG DQT marker). - * CAUTION: IJG versions prior to v6a kept this array in zigzag order. - */ - UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ - /* This field is used only during compression. It's initialized FALSE when - * the table is created, and set TRUE when it's been output to the file. - * You could suppress output of a table by setting this to TRUE. - * (See jpeg_suppress_tables for an example.) - */ - boolean sent_table; /* TRUE when table has been output */ -} JQUANT_TBL; - - -/* Huffman coding tables. */ - -typedef struct { - /* These two fields directly represent the contents of a JPEG DHT marker */ - UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ - /* length k bits; bits[0] is unused */ - UINT8 huffval[256]; /* The symbols, in order of incr code length */ - /* This field is used only during compression. It's initialized FALSE when - * the table is created, and set TRUE when it's been output to the file. - * You could suppress output of a table by setting this to TRUE. - * (See jpeg_suppress_tables for an example.) - */ - boolean sent_table; /* TRUE when table has been output */ -} JHUFF_TBL; - - -/* Basic info about one component (color channel). */ - -typedef struct { - /* These values are fixed over the whole image. */ - /* For compression, they must be supplied by parameter setup; */ - /* for decompression, they are read from the SOF marker. */ - int component_id; /* identifier for this component (0..255) */ - int component_index; /* its index in SOF or cinfo->comp_info[] */ - int h_samp_factor; /* horizontal sampling factor (1..4) */ - int v_samp_factor; /* vertical sampling factor (1..4) */ - int quant_tbl_no; /* quantization table selector (0..3) */ - /* These values may vary between scans. */ - /* For compression, they must be supplied by parameter setup; */ - /* for decompression, they are read from the SOS marker. */ - /* The decompressor output side may not use these variables. */ - int dc_tbl_no; /* DC entropy table selector (0..3) */ - int ac_tbl_no; /* AC entropy table selector (0..3) */ - - /* Remaining fields should be treated as private by applications. */ - - /* These values are computed during compression or decompression startup: */ - /* Component's size in DCT blocks. - * Any dummy blocks added to complete an MCU are not counted; therefore - * these values do not depend on whether a scan is interleaved or not. - */ - JDIMENSION width_in_blocks; - JDIMENSION height_in_blocks; - /* Size of a DCT block in samples. Always DCTSIZE for compression. - * For decompression this is the size of the output from one DCT block, - * reflecting any scaling we choose to apply during the IDCT step. - * Values of 1,2,4,8 are likely to be supported. Note that different - * components may receive different IDCT scalings. - */ - int DCT_scaled_size; - /* The downsampled dimensions are the component's actual, unpadded number - * of samples at the main buffer (preprocessing/compression interface), thus - * downsampled_width = ceil(image_width * Hi/Hmax) - * and similarly for height. For decompression, IDCT scaling is included, so - * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE) - */ - JDIMENSION downsampled_width; /* actual width in samples */ - JDIMENSION downsampled_height; /* actual height in samples */ - /* This flag is used only for decompression. In cases where some of the - * components will be ignored (eg grayscale output from YCbCr image), - * we can skip most computations for the unused components. - */ - boolean component_needed; /* do we need the value of this component? */ - - /* These values are computed before starting a scan of the component. */ - /* The decompressor output side may not use these variables. */ - int MCU_width; /* number of blocks per MCU, horizontally */ - int MCU_height; /* number of blocks per MCU, vertically */ - int MCU_blocks; /* MCU_width * MCU_height */ - int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */ - int last_col_width; /* # of non-dummy blocks across in last MCU */ - int last_row_height; /* # of non-dummy blocks down in last MCU */ - - /* Saved quantization table for component; NULL if none yet saved. - * See jdinput.c comments about the need for this information. - * This field is currently used only for decompression. - */ - JQUANT_TBL * quant_table; - - /* Private per-component storage for DCT or IDCT subsystem. */ - void * dct_table; -} jpeg_component_info; - - -/* The script for encoding a multiple-scan file is an array of these: */ - -typedef struct { - int comps_in_scan; /* number of components encoded in this scan */ - int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ - int Ss, Se; /* progressive JPEG spectral selection parms */ - int Ah, Al; /* progressive JPEG successive approx. parms */ -} jpeg_scan_info; - -/* The decompressor can save APPn and COM markers in a list of these: */ - -typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; - -struct jpeg_marker_struct { - jpeg_saved_marker_ptr next; /* next in list, or NULL */ - UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ - unsigned int original_length; /* # bytes of data in the file */ - unsigned int data_length; /* # bytes of data saved at data[] */ - JOCTET FAR * data; /* the data contained in the marker */ - /* the marker length word is not counted in data_length or original_length */ -}; - -/* Known color spaces. */ - -typedef enum { - JCS_UNKNOWN, /* error/unspecified */ - JCS_GRAYSCALE, /* monochrome */ - JCS_RGB, /* red/green/blue */ - JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ - JCS_CMYK, /* C/M/Y/K */ - JCS_YCCK /* Y/Cb/Cr/K */ -} J_COLOR_SPACE; - -/* DCT/IDCT algorithm options. */ - -typedef enum { - JDCT_ISLOW, /* slow but accurate integer algorithm */ - JDCT_IFAST, /* faster, less accurate integer method */ - JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ -} J_DCT_METHOD; - -#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ -#define JDCT_DEFAULT JDCT_ISLOW -#endif -#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ -#define JDCT_FASTEST JDCT_IFAST -#endif - -/* Dithering options for decompression. */ - -typedef enum { - JDITHER_NONE, /* no dithering */ - JDITHER_ORDERED, /* simple ordered dither */ - JDITHER_FS /* Floyd-Steinberg error diffusion dither */ -} J_DITHER_MODE; - - -/* Common fields between JPEG compression and decompression master structs. */ - -#define jpeg_common_fields \ - struct jpeg_error_mgr * err; /* Error handler module */\ - struct jpeg_memory_mgr * mem; /* Memory manager module */\ - struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ - void * client_data; /* Available for use by application */\ - boolean is_decompressor; /* So common code can tell which is which */\ - int global_state /* For checking call sequence validity */ - -/* Routines that are to be used by both halves of the library are declared - * to receive a pointer to this structure. There are no actual instances of - * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. - */ -struct jpeg_common_struct { - jpeg_common_fields; /* Fields common to both master struct types */ - /* Additional fields follow in an actual jpeg_compress_struct or - * jpeg_decompress_struct. All three structs must agree on these - * initial fields! (This would be a lot cleaner in C++.) - */ -}; - -typedef struct jpeg_common_struct * j_common_ptr; -typedef struct jpeg_compress_struct * j_compress_ptr; -typedef struct jpeg_decompress_struct * j_decompress_ptr; - - -/* Master record for a compression instance */ - -struct jpeg_compress_struct { - jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ - - /* Destination for compressed data */ - struct jpeg_destination_mgr * dest; - - /* Description of source image --- these fields must be filled in by - * outer application before starting compression. in_color_space must - * be correct before you can even call jpeg_set_defaults(). - */ - - JDIMENSION image_width; /* input image width */ - JDIMENSION image_height; /* input image height */ - int input_components; /* # of color components in input image */ - J_COLOR_SPACE in_color_space; /* colorspace of input image */ - - double input_gamma; /* image gamma of input image */ - - /* Compression parameters --- these fields must be set before calling - * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to - * initialize everything to reasonable defaults, then changing anything - * the application specifically wants to change. That way you won't get - * burnt when new parameters are added. Also note that there are several - * helper routines to simplify changing parameters. - */ - - int data_precision; /* bits of precision in image data */ - - int num_components; /* # of color components in JPEG image */ - J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ - - jpeg_component_info * comp_info; - /* comp_info[i] describes component that appears i'th in SOF */ - - JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; - /* ptrs to coefficient quantization tables, or NULL if not defined */ - - JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; - JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; - /* ptrs to Huffman coding tables, or NULL if not defined */ - - UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ - UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ - UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ - - int num_scans; /* # of entries in scan_info array */ - const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ - /* The default value of scan_info is NULL, which causes a single-scan - * sequential JPEG file to be emitted. To create a multi-scan file, - * set num_scans and scan_info to point to an array of scan definitions. - */ - - boolean raw_data_in; /* TRUE=caller supplies downsampled data */ - boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ - boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ - boolean CCIR601_sampling; /* TRUE=first samples are cosited */ - int smoothing_factor; /* 1..100, or 0 for no input smoothing */ - J_DCT_METHOD dct_method; /* DCT algorithm selector */ - - /* The restart interval can be specified in absolute MCUs by setting - * restart_interval, or in MCU rows by setting restart_in_rows - * (in which case the correct restart_interval will be figured - * for each scan). - */ - unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ - int restart_in_rows; /* if > 0, MCU rows per restart interval */ - - /* Parameters controlling emission of special markers. */ - - boolean write_JFIF_header; /* should a JFIF marker be written? */ - UINT8 JFIF_major_version; /* What to write for the JFIF version number */ - UINT8 JFIF_minor_version; - /* These three values are not used by the JPEG code, merely copied */ - /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ - /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ - /* ratio is defined by X_density/Y_density even when density_unit=0. */ - UINT8 density_unit; /* JFIF code for pixel size units */ - UINT16 X_density; /* Horizontal pixel density */ - UINT16 Y_density; /* Vertical pixel density */ - boolean write_Adobe_marker; /* should an Adobe marker be written? */ - - /* State variable: index of next scanline to be written to - * jpeg_write_scanlines(). Application may use this to control its - * processing loop, e.g., "while (next_scanline < image_height)". - */ - - JDIMENSION next_scanline; /* 0 .. image_height-1 */ - - /* Remaining fields are known throughout compressor, but generally - * should not be touched by a surrounding application. - */ - - /* - * These fields are computed during compression startup - */ - boolean progressive_mode; /* TRUE if scan script uses progressive mode */ - int max_h_samp_factor; /* largest h_samp_factor */ - int max_v_samp_factor; /* largest v_samp_factor */ - - JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ - /* The coefficient controller receives data in units of MCU rows as defined - * for fully interleaved scans (whether the JPEG file is interleaved or not). - * There are v_samp_factor * DCTSIZE sample rows of each component in an - * "iMCU" (interleaved MCU) row. - */ - - /* - * These fields are valid during any one scan. - * They describe the components and MCUs actually appearing in the scan. - */ - int comps_in_scan; /* # of JPEG components in this scan */ - jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; - /* *cur_comp_info[i] describes component that appears i'th in SOS */ - - JDIMENSION MCUs_per_row; /* # of MCUs across the image */ - JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ - - int blocks_in_MCU; /* # of DCT blocks per MCU */ - int MCU_membership[C_MAX_BLOCKS_IN_MCU]; - /* MCU_membership[i] is index in cur_comp_info of component owning */ - /* i'th block in an MCU */ - - int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ - - /* - * Links to compression subobjects (methods and private variables of modules) - */ - struct jpeg_comp_master * master; - struct jpeg_c_main_controller * main; - struct jpeg_c_prep_controller * prep; - struct jpeg_c_coef_controller * coef; - struct jpeg_marker_writer * marker; - struct jpeg_color_converter * cconvert; - struct jpeg_downsampler * downsample; - struct jpeg_forward_dct * fdct; - struct jpeg_entropy_encoder * entropy; - jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ - int script_space_size; -}; - - -/* Master record for a decompression instance */ - -struct jpeg_decompress_struct { - jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ - - /* Source of compressed data */ - struct jpeg_source_mgr * src; - - /* Basic description of image --- filled in by jpeg_read_header(). */ - /* Application may inspect these values to decide how to process image. */ - - JDIMENSION image_width; /* nominal image width (from SOF marker) */ - JDIMENSION image_height; /* nominal image height */ - int num_components; /* # of color components in JPEG image */ - J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ - - /* Decompression processing parameters --- these fields must be set before - * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes - * them to default values. - */ - - J_COLOR_SPACE out_color_space; /* colorspace for output */ - - unsigned int scale_num, scale_denom; /* fraction by which to scale image */ - - double output_gamma; /* image gamma wanted in output */ - - boolean buffered_image; /* TRUE=multiple output passes */ - boolean raw_data_out; /* TRUE=downsampled data wanted */ - - J_DCT_METHOD dct_method; /* IDCT algorithm selector */ - boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ - boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ - - boolean quantize_colors; /* TRUE=colormapped output wanted */ - /* the following are ignored if not quantize_colors: */ - J_DITHER_MODE dither_mode; /* type of color dithering to use */ - boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ - int desired_number_of_colors; /* max # colors to use in created colormap */ - /* these are significant only in buffered-image mode: */ - boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ - boolean enable_external_quant;/* enable future use of external colormap */ - boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ - - /* Description of actual output image that will be returned to application. - * These fields are computed by jpeg_start_decompress(). - * You can also use jpeg_calc_output_dimensions() to determine these values - * in advance of calling jpeg_start_decompress(). - */ - - JDIMENSION output_width; /* scaled image width */ - JDIMENSION output_height; /* scaled image height */ - int out_color_components; /* # of color components in out_color_space */ - int output_components; /* # of color components returned */ - /* output_components is 1 (a colormap index) when quantizing colors; - * otherwise it equals out_color_components. - */ - int rec_outbuf_height; /* min recommended height of scanline buffer */ - /* If the buffer passed to jpeg_read_scanlines() is less than this many rows - * high, space and time will be wasted due to unnecessary data copying. - * Usually rec_outbuf_height will be 1 or 2, at most 4. - */ - - /* When quantizing colors, the output colormap is described by these fields. - * The application can supply a colormap by setting colormap non-NULL before - * calling jpeg_start_decompress; otherwise a colormap is created during - * jpeg_start_decompress or jpeg_start_output. - * The map has out_color_components rows and actual_number_of_colors columns. - */ - int actual_number_of_colors; /* number of entries in use */ - JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ - - /* State variables: these variables indicate the progress of decompression. - * The application may examine these but must not modify them. - */ - - /* Row index of next scanline to be read from jpeg_read_scanlines(). - * Application may use this to control its processing loop, e.g., - * "while (output_scanline < output_height)". - */ - JDIMENSION output_scanline; /* 0 .. output_height-1 */ - - /* Current input scan number and number of iMCU rows completed in scan. - * These indicate the progress of the decompressor input side. - */ - int input_scan_number; /* Number of SOS markers seen so far */ - JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ - - /* The "output scan number" is the notional scan being displayed by the - * output side. The decompressor will not allow output scan/row number - * to get ahead of input scan/row, but it can fall arbitrarily far behind. - */ - int output_scan_number; /* Nominal scan number being displayed */ - JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ - - /* Current progression status. coef_bits[c][i] indicates the precision - * with which component c's DCT coefficient i (in zigzag order) is known. - * It is -1 when no data has yet been received, otherwise it is the point - * transform (shift) value for the most recent scan of the coefficient - * (thus, 0 at completion of the progression). - * This pointer is NULL when reading a non-progressive file. - */ - int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ - - /* Internal JPEG parameters --- the application usually need not look at - * these fields. Note that the decompressor output side may not use - * any parameters that can change between scans. - */ - - /* Quantization and Huffman tables are carried forward across input - * datastreams when processing abbreviated JPEG datastreams. - */ - - JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; - /* ptrs to coefficient quantization tables, or NULL if not defined */ - - JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; - JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; - /* ptrs to Huffman coding tables, or NULL if not defined */ - - /* These parameters are never carried across datastreams, since they - * are given in SOF/SOS markers or defined to be reset by SOI. - */ - - int data_precision; /* bits of precision in image data */ - - jpeg_component_info * comp_info; - /* comp_info[i] describes component that appears i'th in SOF */ - - boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ - boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ - - UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ - UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ - UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ - - unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ - - /* These fields record data obtained from optional markers recognized by - * the JPEG library. - */ - boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ - /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ - UINT8 JFIF_major_version; /* JFIF version number */ - UINT8 JFIF_minor_version; - UINT8 density_unit; /* JFIF code for pixel size units */ - UINT16 X_density; /* Horizontal pixel density */ - UINT16 Y_density; /* Vertical pixel density */ - boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ - UINT8 Adobe_transform; /* Color transform code from Adobe marker */ - - boolean CCIR601_sampling; /* TRUE=first samples are cosited */ - - /* Aside from the specific data retained from APPn markers known to the - * library, the uninterpreted contents of any or all APPn and COM markers - * can be saved in a list for examination by the application. - */ - jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ - - /* Remaining fields are known throughout decompressor, but generally - * should not be touched by a surrounding application. - */ - - /* - * These fields are computed during decompression startup - */ - int max_h_samp_factor; /* largest h_samp_factor */ - int max_v_samp_factor; /* largest v_samp_factor */ - - int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */ - - JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ - /* The coefficient controller's input and output progress is measured in - * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows - * in fully interleaved JPEG scans, but are used whether the scan is - * interleaved or not. We define an iMCU row as v_samp_factor DCT block - * rows of each component. Therefore, the IDCT output contains - * v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row. - */ - - JSAMPLE * sample_range_limit; /* table for fast range-limiting */ - - /* - * These fields are valid during any one scan. - * They describe the components and MCUs actually appearing in the scan. - * Note that the decompressor output side must not use these fields. - */ - int comps_in_scan; /* # of JPEG components in this scan */ - jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; - /* *cur_comp_info[i] describes component that appears i'th in SOS */ - - JDIMENSION MCUs_per_row; /* # of MCUs across the image */ - JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ - - int blocks_in_MCU; /* # of DCT blocks per MCU */ - int MCU_membership[D_MAX_BLOCKS_IN_MCU]; - /* MCU_membership[i] is index in cur_comp_info of component owning */ - /* i'th block in an MCU */ - - int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ - - /* This field is shared between entropy decoder and marker parser. - * It is either zero or the code of a JPEG marker that has been - * read from the data source, but has not yet been processed. - */ - int unread_marker; - - /* - * Links to decompression subobjects (methods, private variables of modules) - */ - struct jpeg_decomp_master * master; - struct jpeg_d_main_controller * main; - struct jpeg_d_coef_controller * coef; - struct jpeg_d_post_controller * post; - struct jpeg_input_controller * inputctl; - struct jpeg_marker_reader * marker; - struct jpeg_entropy_decoder * entropy; - struct jpeg_inverse_dct * idct; - struct jpeg_upsampler * upsample; - struct jpeg_color_deconverter * cconvert; - struct jpeg_color_quantizer * cquantize; -}; - - -/* "Object" declarations for JPEG modules that may be supplied or called - * directly by the surrounding application. - * As with all objects in the JPEG library, these structs only define the - * publicly visible methods and state variables of a module. Additional - * private fields may exist after the public ones. - */ - - -/* Error handler object */ - -struct jpeg_error_mgr { - /* Error exit handler: does not return to caller */ - JMETHOD(void, error_exit, (j_common_ptr cinfo)); - /* Conditionally emit a trace or warning message */ - JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); - /* Routine that actually outputs a trace or error message */ - JMETHOD(void, output_message, (j_common_ptr cinfo)); - /* Format a message string for the most recent JPEG error or message */ - JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); -#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ - /* Reset error state variables at start of a new image */ - JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); - - /* The message ID code and any parameters are saved here. - * A message can have one string parameter or up to 8 int parameters. - */ - int msg_code; -#define JMSG_STR_PARM_MAX 80 - union { - int i[8]; - char s[JMSG_STR_PARM_MAX]; - } msg_parm; - - /* Standard state variables for error facility */ - - int trace_level; /* max msg_level that will be displayed */ - - /* For recoverable corrupt-data errors, we emit a warning message, - * but keep going unless emit_message chooses to abort. emit_message - * should count warnings in num_warnings. The surrounding application - * can check for bad data by seeing if num_warnings is nonzero at the - * end of processing. - */ - long num_warnings; /* number of corrupt-data warnings */ - - /* These fields point to the table(s) of error message strings. - * An application can change the table pointer to switch to a different - * message list (typically, to change the language in which errors are - * reported). Some applications may wish to add additional error codes - * that will be handled by the JPEG library error mechanism; the second - * table pointer is used for this purpose. - * - * First table includes all errors generated by JPEG library itself. - * Error code 0 is reserved for a "no such error string" message. - */ - const char * const * jpeg_message_table; /* Library errors */ - int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ - /* Second table can be added by application (see cjpeg/djpeg for example). - * It contains strings numbered first_addon_message..last_addon_message. - */ - const char * const * addon_message_table; /* Non-library errors */ - int first_addon_message; /* code for first string in addon table */ - int last_addon_message; /* code for last string in addon table */ -}; - - -/* Progress monitor object */ - -struct jpeg_progress_mgr { - JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); - - long pass_counter; /* work units completed in this pass */ - long pass_limit; /* total number of work units in this pass */ - int completed_passes; /* passes completed so far */ - int total_passes; /* total number of passes expected */ -}; - - -/* Data destination object for compression */ - -struct jpeg_destination_mgr { - JOCTET * next_output_byte; /* => next byte to write in buffer */ - size_t free_in_buffer; /* # of byte spaces remaining in buffer */ - - JMETHOD(void, init_destination, (j_compress_ptr cinfo)); - JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); - JMETHOD(void, term_destination, (j_compress_ptr cinfo)); -}; - - -/* Data source object for decompression */ - -struct jpeg_source_mgr { - const JOCTET * next_input_byte; /* => next byte to read from buffer */ - size_t bytes_in_buffer; /* # of bytes remaining in buffer */ - - JMETHOD(void, init_source, (j_decompress_ptr cinfo)); - JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); - JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); - JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); - JMETHOD(void, term_source, (j_decompress_ptr cinfo)); -}; - - -/* Memory manager object. - * Allocates "small" objects (a few K total), "large" objects (tens of K), - * and "really big" objects (virtual arrays with backing store if needed). - * The memory manager does not allow individual objects to be freed; rather, - * each created object is assigned to a pool, and whole pools can be freed - * at once. This is faster and more convenient than remembering exactly what - * to free, especially where malloc()/free() are not too speedy. - * NB: alloc routines never return NULL. They exit to error_exit if not - * successful. - */ - -#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ -#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ -#define JPOOL_NUMPOOLS 2 - -typedef struct jvirt_sarray_control * jvirt_sarray_ptr; -typedef struct jvirt_barray_control * jvirt_barray_ptr; - - -struct jpeg_memory_mgr { - /* Method pointers */ - JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, - size_t sizeofobject)); - JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, - size_t sizeofobject)); - JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, - JDIMENSION samplesperrow, - JDIMENSION numrows)); - JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, - JDIMENSION blocksperrow, - JDIMENSION numrows)); - JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, - int pool_id, - boolean pre_zero, - JDIMENSION samplesperrow, - JDIMENSION numrows, - JDIMENSION maxaccess)); - JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, - int pool_id, - boolean pre_zero, - JDIMENSION blocksperrow, - JDIMENSION numrows, - JDIMENSION maxaccess)); - JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); - JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, - jvirt_sarray_ptr ptr, - JDIMENSION start_row, - JDIMENSION num_rows, - boolean writable)); - JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, - jvirt_barray_ptr ptr, - JDIMENSION start_row, - JDIMENSION num_rows, - boolean writable)); - JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); - JMETHOD(void, self_destruct, (j_common_ptr cinfo)); - - /* Limit on memory allocation for this JPEG object. (Note that this is - * merely advisory, not a guaranteed maximum; it only affects the space - * used for virtual-array buffers.) May be changed by outer application - * after creating the JPEG object. - */ - long max_memory_to_use; - - /* Maximum allocation request accepted by alloc_large. */ - long max_alloc_chunk; -}; - - -/* Routine signature for application-supplied marker processing methods. - * Need not pass marker code since it is stored in cinfo->unread_marker. - */ -typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); - - -/* Declarations for routines called by application. - * The JPP macro hides prototype parameters from compilers that can't cope. - * Note JPP requires double parentheses. - */ - -#ifdef HAVE_PROTOTYPES -#define JPP(arglist) arglist -#else -#define JPP(arglist) () -#endif - - -/* Short forms of external names for systems with brain-damaged linkers. - * We shorten external names to be unique in the first six letters, which - * is good enough for all known systems. - * (If your compiler itself needs names to be unique in less than 15 - * characters, you are out of luck. Get a better compiler.) - */ - -#ifdef NEED_SHORT_EXTERNAL_NAMES -#define jpeg_std_error jStdError -#define jpeg_CreateCompress jCreaCompress -#define jpeg_CreateDecompress jCreaDecompress -#define jpeg_destroy_compress jDestCompress -#define jpeg_destroy_decompress jDestDecompress -#define jpeg_stdio_dest jStdDest -#define jpeg_stdio_src jStdSrc -#define jpeg_set_defaults jSetDefaults -#define jpeg_set_colorspace jSetColorspace -#define jpeg_default_colorspace jDefColorspace -#define jpeg_set_quality jSetQuality -#define jpeg_set_linear_quality jSetLQuality -#define jpeg_add_quant_table jAddQuantTable -#define jpeg_quality_scaling jQualityScaling -#define jpeg_simple_progression jSimProgress -#define jpeg_suppress_tables jSuppressTables -#define jpeg_alloc_quant_table jAlcQTable -#define jpeg_alloc_huff_table jAlcHTable -#define jpeg_start_compress jStrtCompress -#define jpeg_write_scanlines jWrtScanlines -#define jpeg_finish_compress jFinCompress -#define jpeg_write_raw_data jWrtRawData -#define jpeg_write_marker jWrtMarker -#define jpeg_write_m_header jWrtMHeader -#define jpeg_write_m_byte jWrtMByte -#define jpeg_write_tables jWrtTables -#define jpeg_read_header jReadHeader -#define jpeg_start_decompress jStrtDecompress -#define jpeg_read_scanlines jReadScanlines -#define jpeg_finish_decompress jFinDecompress -#define jpeg_read_raw_data jReadRawData -#define jpeg_has_multiple_scans jHasMultScn -#define jpeg_start_output jStrtOutput -#define jpeg_finish_output jFinOutput -#define jpeg_input_complete jInComplete -#define jpeg_new_colormap jNewCMap -#define jpeg_consume_input jConsumeInput -#define jpeg_calc_output_dimensions jCalcDimensions -#define jpeg_save_markers jSaveMarkers -#define jpeg_set_marker_processor jSetMarker -#define jpeg_read_coefficients jReadCoefs -#define jpeg_write_coefficients jWrtCoefs -#define jpeg_copy_critical_parameters jCopyCrit -#define jpeg_abort_compress jAbrtCompress -#define jpeg_abort_decompress jAbrtDecompress -#define jpeg_abort jAbort -#define jpeg_destroy jDestroy -#define jpeg_resync_to_restart jResyncRestart -#endif /* NEED_SHORT_EXTERNAL_NAMES */ - - -/* Default error-management setup */ -EXTERN(struct jpeg_error_mgr *) jpeg_std_error - JPP((struct jpeg_error_mgr * err)); - -/* Initialization of JPEG compression objects. - * jpeg_create_compress() and jpeg_create_decompress() are the exported - * names that applications should call. These expand to calls on - * jpeg_CreateCompress and jpeg_CreateDecompress with additional information - * passed for version mismatch checking. - * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. - */ -#define jpeg_create_compress(cinfo) \ - jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ - (size_t) sizeof(struct jpeg_compress_struct)) -#define jpeg_create_decompress(cinfo) \ - jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ - (size_t) sizeof(struct jpeg_decompress_struct)) -EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, - int version, size_t structsize)); -EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, - int version, size_t structsize)); -/* Destruction of JPEG compression objects */ -EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); -EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); - -/* Standard data source and destination managers: stdio streams. */ -/* Caller is responsible for opening the file before and closing after. */ -EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); -EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); - -/* Default parameter setup for compression */ -EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); -/* Compression parameter setup aids */ -EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, - J_COLOR_SPACE colorspace)); -EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); -EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, - boolean force_baseline)); -EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, - int scale_factor, - boolean force_baseline)); -EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, - const unsigned int *basic_table, - int scale_factor, - boolean force_baseline)); -EXTERN(int) jpeg_quality_scaling JPP((int quality)); -EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); -EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, - boolean suppress)); -EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); -EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); - -/* Main entry points for compression */ -EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, - boolean write_all_tables)); -EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, - JSAMPARRAY scanlines, - JDIMENSION num_lines)); -EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); - -/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ -EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, - JSAMPIMAGE data, - JDIMENSION num_lines)); - -/* Write a special marker. See libjpeg.doc concerning safe usage. */ -EXTERN(void) jpeg_write_marker - JPP((j_compress_ptr cinfo, int marker, - const JOCTET * dataptr, unsigned int datalen)); -/* Same, but piecemeal. */ -EXTERN(void) jpeg_write_m_header - JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); -EXTERN(void) jpeg_write_m_byte - JPP((j_compress_ptr cinfo, int val)); - -/* Alternate compression function: just write an abbreviated table file */ -EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); - -/* Decompression startup: read start of JPEG datastream to see what's there */ -EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, - boolean require_image)); -/* Return value is one of: */ -#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ -#define JPEG_HEADER_OK 1 /* Found valid image datastream */ -#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ -/* If you pass require_image = TRUE (normal case), you need not check for - * a TABLES_ONLY return code; an abbreviated file will cause an error exit. - * JPEG_SUSPENDED is only possible if you use a data source module that can - * give a suspension return (the stdio source module doesn't). - */ - -/* Main entry points for decompression */ -EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); -EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, - JSAMPARRAY scanlines, - JDIMENSION max_lines)); -EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); - -/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ -EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, - JSAMPIMAGE data, - JDIMENSION max_lines)); - -/* Additional entry points for buffered-image mode. */ -EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); -EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo, - int scan_number)); -EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo)); -EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo)); -EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); -EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); -/* Return value is one of: */ -/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ -#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ -#define JPEG_REACHED_EOI 2 /* Reached end of image */ -#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ -#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ - -/* Precalculate output dimensions for current decompression parameters. */ -EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); - -/* Control saving of COM and APPn markers into marker_list. */ -EXTERN(void) jpeg_save_markers - JPP((j_decompress_ptr cinfo, int marker_code, - unsigned int length_limit)); - -/* Install a special processing method for COM or APPn markers. */ -EXTERN(void) jpeg_set_marker_processor - JPP((j_decompress_ptr cinfo, int marker_code, - jpeg_marker_parser_method routine)); - -/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ -EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); -EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, - jvirt_barray_ptr * coef_arrays)); -EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, - j_compress_ptr dstinfo)); - -/* If you choose to abort compression or decompression before completing - * jpeg_finish_(de)compress, then you need to clean up to release memory, - * temporary files, etc. You can just call jpeg_destroy_(de)compress - * if you're done with the JPEG object, but if you want to clean it up and - * reuse it, call this: - */ -EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); -EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); - -/* Generic versions of jpeg_abort and jpeg_destroy that work on either - * flavor of JPEG object. These may be more convenient in some places. - */ -EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); -EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); - -/* Default restart-marker-resync procedure for use by data source modules */ -EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, - int desired)); - - -/* These marker codes are exported since applications and data source modules - * are likely to want to use them. - */ - -#define JPEG_RST0 0xD0 /* RST0 marker code */ -#define JPEG_EOI 0xD9 /* EOI marker code */ -#define JPEG_APP0 0xE0 /* APP0 marker code */ -#define JPEG_COM 0xFE /* COM marker code */ - - -/* If we have a brain-damaged compiler that emits warnings (or worse, errors) - * for structure definitions that are never filled in, keep it quiet by - * supplying dummy definitions for the various substructures. - */ - -#ifdef INCOMPLETE_TYPES_BROKEN -#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ -struct jvirt_sarray_control { long dummy; }; -struct jvirt_barray_control { long dummy; }; -struct jpeg_comp_master { long dummy; }; -struct jpeg_c_main_controller { long dummy; }; -struct jpeg_c_prep_controller { long dummy; }; -struct jpeg_c_coef_controller { long dummy; }; -struct jpeg_marker_writer { long dummy; }; -struct jpeg_color_converter { long dummy; }; -struct jpeg_downsampler { long dummy; }; -struct jpeg_forward_dct { long dummy; }; -struct jpeg_entropy_encoder { long dummy; }; -struct jpeg_decomp_master { long dummy; }; -struct jpeg_d_main_controller { long dummy; }; -struct jpeg_d_coef_controller { long dummy; }; -struct jpeg_d_post_controller { long dummy; }; -struct jpeg_input_controller { long dummy; }; -struct jpeg_marker_reader { long dummy; }; -struct jpeg_entropy_decoder { long dummy; }; -struct jpeg_inverse_dct { long dummy; }; -struct jpeg_upsampler { long dummy; }; -struct jpeg_color_deconverter { long dummy; }; -struct jpeg_color_quantizer { long dummy; }; -#endif /* JPEG_INTERNALS */ -#endif /* INCOMPLETE_TYPES_BROKEN */ - - -/* - * The JPEG library modules define JPEG_INTERNALS before including this file. - * The internal structure declarations are read only when that is true. - * Applications using the library should not include jpegint.h, but may wish - * to include jerror.h. - */ - -#ifdef JPEG_INTERNALS -#include "jpegint.h" /* fetch private declarations */ -#include "jerror.h" /* fetch error codes too */ -#endif - -#endif /* JPEGLIB_H */ +/* + * jpeglib.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the application interface for the JPEG library. + * Most applications using the library need only include this file, + * and perhaps jerror.h if they want to know the exact error codes. + */ + +#ifndef JPEGLIB_H +#define JPEGLIB_H + +/* + * First we include the configuration files that record how this + * installation of the JPEG library is set up. jconfig.h can be + * generated automatically for many systems. jmorecfg.h contains + * manual configuration options that most people need not worry about. + */ + +#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ +#include "jconfig.h" /* widely used configuration options */ +#endif +#include "jmorecfg.h" /* seldom changed options */ + + +/* Version ID for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". + */ + +#define JPEG_LIB_VERSION 62 /* Version 6b */ + + +/* Various constants determining the sizes of things. + * All of these are specified by the JPEG standard, so don't change them + * if you want to be compatible. + */ + +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ +#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; + * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. + * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU + * to handle it. We even let you do this from the jconfig.h file. However, + * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe + * sometimes emits noncompliant files doesn't mean you should too. + */ +#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ +#ifndef D_MAX_BLOCKS_IN_MCU +#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ +#endif + + +/* Data structures for images (arrays of samples and of DCT coefficients). + * On 80x86 machines, the image arrays are too big for near pointers, + * but the pointer arrays can fit in near memory. + */ + +#undef FAR +#define FAR + +typedef JSAMPLE *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + + +/* Types for JPEG compression parameters and working tables. */ + + +/* DCT coefficient quantization tables. */ + +typedef struct { + /* This array gives the coefficient quantizers in natural array order + * (not the zigzag order in which they are stored in a JPEG DQT marker). + * CAUTION: IJG versions prior to v6a kept this array in zigzag order. + */ + UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JQUANT_TBL; + + +/* Huffman coding tables. */ + +typedef struct { + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JHUFF_TBL; + + +/* Basic info about one component (color channel). */ + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; /* identifier for this component (0..255) */ + int component_index; /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; /* horizontal sampling factor (1..4) */ + int v_samp_factor; /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in DCT blocks. + * Any dummy blocks added to complete an MCU are not counted; therefore + * these values do not depend on whether a scan is interleaved or not. + */ + JDIMENSION width_in_blocks; + JDIMENSION height_in_blocks; + /* Size of a DCT block in samples. Always DCTSIZE for compression. + * For decompression this is the size of the output from one DCT block, + * reflecting any scaling we choose to apply during the IDCT step. + * Values of 1,2,4,8 are likely to be supported. Note that different + * components may receive different IDCT scalings. + */ + int DCT_scaled_size; + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface), thus + * downsampled_width = ceil(image_width * Hi/Hmax) + * and similarly for height. For decompression, IDCT scaling is included, so + * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE) + */ + JDIMENSION downsampled_width; /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* This flag is used only for decompression. In cases where some of the + * components will be ignored (eg grayscale output from YCbCr image), + * we can skip most computations for the unused components. + */ + boolean component_needed; /* do we need the value of this component? */ + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; /* number of blocks per MCU, horizontally */ + int MCU_height; /* number of blocks per MCU, vertically */ + int MCU_blocks; /* MCU_width * MCU_height */ + int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */ + int last_col_width; /* # of non-dummy blocks across in last MCU */ + int last_row_height; /* # of non-dummy blocks down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is currently used only for decompression. + */ + JQUANT_TBL * quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void * dct_table; +} jpeg_component_info; + + +/* The script for encoding a multiple-scan file is an array of these: */ + +typedef struct { + int comps_in_scan; /* number of components encoded in this scan */ + int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ + int Ss, Se; /* progressive JPEG spectral selection parms */ + int Ah, Al; /* progressive JPEG successive approx. parms */ +} jpeg_scan_info; + +/* The decompressor can save APPn and COM markers in a list of these: */ + +typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; + +struct jpeg_marker_struct { + jpeg_saved_marker_ptr next; /* next in list, or NULL */ + UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ + unsigned int original_length; /* # bytes of data in the file */ + unsigned int data_length; /* # bytes of data saved at data[] */ + JOCTET FAR * data; /* the data contained in the marker */ + /* the marker length word is not counted in data_length or original_length */ +}; + +/* Known color spaces. */ + +typedef enum { + JCS_UNKNOWN, /* error/unspecified */ + JCS_GRAYSCALE, /* monochrome */ + JCS_RGB, /* red/green/blue */ + JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + JCS_CMYK, /* C/M/Y/K */ + JCS_YCCK /* Y/Cb/Cr/K */ +} J_COLOR_SPACE; + +/* DCT/IDCT algorithm options. */ + +typedef enum { + JDCT_ISLOW, /* slow but accurate integer algorithm */ + JDCT_IFAST, /* faster, less accurate integer method */ + JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ +} J_DCT_METHOD; + +#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ +#define JDCT_DEFAULT JDCT_ISLOW +#endif +#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ +#define JDCT_FASTEST JDCT_IFAST +#endif + +/* Dithering options for decompression. */ + +typedef enum { + JDITHER_NONE, /* no dithering */ + JDITHER_ORDERED, /* simple ordered dither */ + JDITHER_FS /* Floyd-Steinberg error diffusion dither */ +} J_DITHER_MODE; + + +/* Common fields between JPEG compression and decompression master structs. */ + +#define jpeg_common_fields \ + struct jpeg_error_mgr * err; /* Error handler module */\ + struct jpeg_memory_mgr * mem; /* Memory manager module */\ + struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ + void * client_data; /* Available for use by application */\ + boolean is_decompressor; /* So common code can tell which is which */\ + int global_state /* For checking call sequence validity */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. + */ +struct jpeg_common_struct { + jpeg_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual jpeg_compress_struct or + * jpeg_decompress_struct. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct jpeg_common_struct * j_common_ptr; +typedef struct jpeg_compress_struct * j_compress_ptr; +typedef struct jpeg_decompress_struct * j_decompress_ptr; + + +/* Master record for a compression instance */ + +struct jpeg_compress_struct { + jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ + + /* Destination for compressed data */ + struct jpeg_destination_mgr * dest; + + /* Description of source image --- these fields must be filled in by + * outer application before starting compression. in_color_space must + * be correct before you can even call jpeg_set_defaults(). + */ + + JDIMENSION image_width; /* input image width */ + JDIMENSION image_height; /* input image height */ + int input_components; /* # of color components in input image */ + J_COLOR_SPACE in_color_space; /* colorspace of input image */ + + double input_gamma; /* image gamma of input image */ + + /* Compression parameters --- these fields must be set before calling + * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to + * initialize everything to reasonable defaults, then changing anything + * the application specifically wants to change. That way you won't get + * burnt when new parameters are added. Also note that there are several + * helper routines to simplify changing parameters. + */ + + int data_precision; /* bits of precision in image data */ + + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + int num_scans; /* # of entries in scan_info array */ + const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ + /* The default value of scan_info is NULL, which causes a single-scan + * sequential JPEG file to be emitted. To create a multi-scan file, + * set num_scans and scan_info to point to an array of scan definitions. + */ + + boolean raw_data_in; /* TRUE=caller supplies downsampled data */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + int smoothing_factor; /* 1..100, or 0 for no input smoothing */ + J_DCT_METHOD dct_method; /* DCT algorithm selector */ + + /* The restart interval can be specified in absolute MCUs by setting + * restart_interval, or in MCU rows by setting restart_in_rows + * (in which case the correct restart_interval will be figured + * for each scan). + */ + unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ + int restart_in_rows; /* if > 0, MCU rows per restart interval */ + + /* Parameters controlling emission of special markers. */ + + boolean write_JFIF_header; /* should a JFIF marker be written? */ + UINT8 JFIF_major_version; /* What to write for the JFIF version number */ + UINT8 JFIF_minor_version; + /* These three values are not used by the JPEG code, merely copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean write_Adobe_marker; /* should an Adobe marker be written? */ + + /* State variable: index of next scanline to be written to + * jpeg_write_scanlines(). Application may use this to control its + * processing loop, e.g., "while (next_scanline < image_height)". + */ + + JDIMENSION next_scanline; /* 0 .. image_height-1 */ + + /* Remaining fields are known throughout compressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during compression startup + */ + boolean progressive_mode; /* TRUE if scan script uses progressive mode */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ + /* The coefficient controller receives data in units of MCU rows as defined + * for fully interleaved scans (whether the JPEG file is interleaved or not). + * There are v_samp_factor * DCTSIZE sample rows of each component in an + * "iMCU" (interleaved MCU) row. + */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[C_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* + * Links to compression subobjects (methods and private variables of modules) + */ + struct jpeg_comp_master * master; + struct jpeg_c_main_controller * main; + struct jpeg_c_prep_controller * prep; + struct jpeg_c_coef_controller * coef; + struct jpeg_marker_writer * marker; + struct jpeg_color_converter * cconvert; + struct jpeg_downsampler * downsample; + struct jpeg_forward_dct * fdct; + struct jpeg_entropy_encoder * entropy; + jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ + int script_space_size; +}; + + +/* Master record for a decompression instance */ + +struct jpeg_decompress_struct { + jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ + + /* Source of compressed data */ + struct jpeg_source_mgr * src; + + /* Basic description of image --- filled in by jpeg_read_header(). */ + /* Application may inspect these values to decide how to process image. */ + + JDIMENSION image_width; /* nominal image width (from SOF marker) */ + JDIMENSION image_height; /* nominal image height */ + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + J_COLOR_SPACE out_color_space; /* colorspace for output */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + double output_gamma; /* image gamma wanted in output */ + + boolean buffered_image; /* TRUE=multiple output passes */ + boolean raw_data_out; /* TRUE=downsampled data wanted */ + + J_DCT_METHOD dct_method; /* IDCT algorithm selector */ + boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ + boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ + + boolean quantize_colors; /* TRUE=colormapped output wanted */ + /* the following are ignored if not quantize_colors: */ + J_DITHER_MODE dither_mode; /* type of color dithering to use */ + boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ + int desired_number_of_colors; /* max # colors to use in created colormap */ + /* these are significant only in buffered-image mode: */ + boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ + boolean enable_external_quant;/* enable future use of external colormap */ + boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + JDIMENSION output_width; /* scaled image width */ + JDIMENSION output_height; /* scaled image height */ + int out_color_components; /* # of color components in out_color_space */ + int output_components; /* # of color components returned */ + /* output_components is 1 (a colormap index) when quantizing colors; + * otherwise it equals out_color_components. + */ + int rec_outbuf_height; /* min recommended height of scanline buffer */ + /* If the buffer passed to jpeg_read_scanlines() is less than this many rows + * high, space and time will be wasted due to unnecessary data copying. + * Usually rec_outbuf_height will be 1 or 2, at most 4. + */ + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-NULL before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + int actual_number_of_colors; /* number of entries in use */ + JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ + + /* State variables: these variables indicate the progress of decompression. + * The application may examine these but must not modify them. + */ + + /* Row index of next scanline to be read from jpeg_read_scanlines(). + * Application may use this to control its processing loop, e.g., + * "while (output_scanline < output_height)". + */ + JDIMENSION output_scanline; /* 0 .. output_height-1 */ + + /* Current input scan number and number of iMCU rows completed in scan. + * These indicate the progress of the decompressor input side. + */ + int input_scan_number; /* Number of SOS markers seen so far */ + JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ + + /* The "output scan number" is the notional scan being displayed by the + * output side. The decompressor will not allow output scan/row number + * to get ahead of input scan/row, but it can fall arbitrarily far behind. + */ + int output_scan_number; /* Nominal scan number being displayed */ + JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ + + /* Current progression status. coef_bits[c][i] indicates the precision + * with which component c's DCT coefficient i (in zigzag order) is known. + * It is -1 when no data has yet been received, otherwise it is the point + * transform (shift) value for the most recent scan of the coefficient + * (thus, 0 at completion of the progression). + * This pointer is NULL when reading a non-progressive file. + */ + int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ + + /* Internal JPEG parameters --- the application usually need not look at + * these fields. Note that the decompressor output side may not use + * any parameters that can change between scans. + */ + + /* Quantization and Huffman tables are carried forward across input + * datastreams when processing abbreviated JPEG datastreams. + */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + /* These parameters are never carried across datastreams, since they + * are given in SOF/SOS markers or defined to be reset by SOI. + */ + + int data_precision; /* bits of precision in image data */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ + + /* These fields record data obtained from optional markers recognized by + * the JPEG library. + */ + boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ + /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ + UINT8 JFIF_major_version; /* JFIF version number */ + UINT8 JFIF_minor_version; + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ + UINT8 Adobe_transform; /* Color transform code from Adobe marker */ + + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + /* Aside from the specific data retained from APPn markers known to the + * library, the uninterpreted contents of any or all APPn and COM markers + * can be saved in a list for examination by the application. + */ + jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ + + /* Remaining fields are known throughout decompressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during decompression startup + */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ + /* The coefficient controller's input and output progress is measured in + * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows + * in fully interleaved JPEG scans, but are used whether the scan is + * interleaved or not. We define an iMCU row as v_samp_factor DCT block + * rows of each component. Therefore, the IDCT output contains + * v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row. + */ + + JSAMPLE * sample_range_limit; /* table for fast range-limiting */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + * Note that the decompressor output side must not use these fields. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[D_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* This field is shared between entropy decoder and marker parser. + * It is either zero or the code of a JPEG marker that has been + * read from the data source, but has not yet been processed. + */ + int unread_marker; + + /* + * Links to decompression subobjects (methods, private variables of modules) + */ + struct jpeg_decomp_master * master; + struct jpeg_d_main_controller * main; + struct jpeg_d_coef_controller * coef; + struct jpeg_d_post_controller * post; + struct jpeg_input_controller * inputctl; + struct jpeg_marker_reader * marker; + struct jpeg_entropy_decoder * entropy; + struct jpeg_inverse_dct * idct; + struct jpeg_upsampler * upsample; + struct jpeg_color_deconverter * cconvert; + struct jpeg_color_quantizer * cquantize; +}; + + +/* "Object" declarations for JPEG modules that may be supplied or called + * directly by the surrounding application. + * As with all objects in the JPEG library, these structs only define the + * publicly visible methods and state variables of a module. Additional + * private fields may exist after the public ones. + */ + + +/* Error handler object */ + +struct jpeg_error_mgr { + /* Error exit handler: does not return to caller */ + JMETHOD(void, error_exit, (j_common_ptr cinfo)); + /* Conditionally emit a trace or warning message */ + JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); + /* Routine that actually outputs a trace or error message */ + JMETHOD(void, output_message, (j_common_ptr cinfo)); + /* Format a message string for the most recent JPEG error or message */ + JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); +#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ + /* Reset error state variables at start of a new image */ + JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); + + /* The message ID code and any parameters are saved here. + * A message can have one string parameter or up to 8 int parameters. + */ + int msg_code; +#define JMSG_STR_PARM_MAX 80 + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + + /* Standard state variables for error facility */ + + int trace_level; /* max msg_level that will be displayed */ + + /* For recoverable corrupt-data errors, we emit a warning message, + * but keep going unless emit_message chooses to abort. emit_message + * should count warnings in num_warnings. The surrounding application + * can check for bad data by seeing if num_warnings is nonzero at the + * end of processing. + */ + long num_warnings; /* number of corrupt-data warnings */ + + /* These fields point to the table(s) of error message strings. + * An application can change the table pointer to switch to a different + * message list (typically, to change the language in which errors are + * reported). Some applications may wish to add additional error codes + * that will be handled by the JPEG library error mechanism; the second + * table pointer is used for this purpose. + * + * First table includes all errors generated by JPEG library itself. + * Error code 0 is reserved for a "no such error string" message. + */ + const char * const * jpeg_message_table; /* Library errors */ + int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ + /* Second table can be added by application (see cjpeg/djpeg for example). + * It contains strings numbered first_addon_message..last_addon_message. + */ + const char * const * addon_message_table; /* Non-library errors */ + int first_addon_message; /* code for first string in addon table */ + int last_addon_message; /* code for last string in addon table */ +}; + + +/* Progress monitor object */ + +struct jpeg_progress_mgr { + JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); + + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +}; + + +/* Data destination object for compression */ + +struct jpeg_destination_mgr { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + + JMETHOD(void, init_destination, (j_compress_ptr cinfo)); + JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); + JMETHOD(void, term_destination, (j_compress_ptr cinfo)); +}; + + +/* Data source object for decompression */ + +struct jpeg_source_mgr { + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + + JMETHOD(void, init_source, (j_decompress_ptr cinfo)); + JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); + JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); + JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); + JMETHOD(void, term_source, (j_decompress_ptr cinfo)); +}; + + +/* Memory manager object. + * Allocates "small" objects (a few K total), "large" objects (tens of K), + * and "really big" objects (virtual arrays with backing store if needed). + * The memory manager does not allow individual objects to be freed; rather, + * each created object is assigned to a pool, and whole pools can be freed + * at once. This is faster and more convenient than remembering exactly what + * to free, especially where malloc()/free() are not too speedy. + * NB: alloc routines never return NULL. They exit to error_exit if not + * successful. + */ + +#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ +#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ +#define JPOOL_NUMPOOLS 2 + +typedef struct jvirt_sarray_control * jvirt_sarray_ptr; +typedef struct jvirt_barray_control * jvirt_barray_ptr; + + +struct jpeg_memory_mgr { + /* Method pointers */ + JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, + JDIMENSION numrows)); + JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, + JDIMENSION numrows)); + JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION samplesperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION blocksperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); + JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, + jvirt_sarray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, + jvirt_barray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); + JMETHOD(void, self_destruct, (j_common_ptr cinfo)); + + /* Limit on memory allocation for this JPEG object. (Note that this is + * merely advisory, not a guaranteed maximum; it only affects the space + * used for virtual-array buffers.) May be changed by outer application + * after creating the JPEG object. + */ + long max_memory_to_use; + + /* Maximum allocation request accepted by alloc_large. */ + long max_alloc_chunk; +}; + + +/* Routine signature for application-supplied marker processing methods. + * Need not pass marker code since it is stored in cinfo->unread_marker. + */ +typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); + + +/* Declarations for routines called by application. + * The JPP macro hides prototype parameters from compilers that can't cope. + * Note JPP requires double parentheses. + */ + +#ifdef HAVE_PROTOTYPES +#define JPP(arglist) arglist +#else +#define JPP(arglist) () +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. + * We shorten external names to be unique in the first six letters, which + * is good enough for all known systems. + * (If your compiler itself needs names to be unique in less than 15 + * characters, you are out of luck. Get a better compiler.) + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_error jStdError +#define jpeg_CreateCompress jCreaCompress +#define jpeg_CreateDecompress jCreaDecompress +#define jpeg_destroy_compress jDestCompress +#define jpeg_destroy_decompress jDestDecompress +#define jpeg_stdio_dest jStdDest +#define jpeg_stdio_src jStdSrc +#define jpeg_set_defaults jSetDefaults +#define jpeg_set_colorspace jSetColorspace +#define jpeg_default_colorspace jDefColorspace +#define jpeg_set_quality jSetQuality +#define jpeg_set_linear_quality jSetLQuality +#define jpeg_add_quant_table jAddQuantTable +#define jpeg_quality_scaling jQualityScaling +#define jpeg_simple_progression jSimProgress +#define jpeg_suppress_tables jSuppressTables +#define jpeg_alloc_quant_table jAlcQTable +#define jpeg_alloc_huff_table jAlcHTable +#define jpeg_start_compress jStrtCompress +#define jpeg_write_scanlines jWrtScanlines +#define jpeg_finish_compress jFinCompress +#define jpeg_write_raw_data jWrtRawData +#define jpeg_write_marker jWrtMarker +#define jpeg_write_m_header jWrtMHeader +#define jpeg_write_m_byte jWrtMByte +#define jpeg_write_tables jWrtTables +#define jpeg_read_header jReadHeader +#define jpeg_start_decompress jStrtDecompress +#define jpeg_read_scanlines jReadScanlines +#define jpeg_finish_decompress jFinDecompress +#define jpeg_read_raw_data jReadRawData +#define jpeg_has_multiple_scans jHasMultScn +#define jpeg_start_output jStrtOutput +#define jpeg_finish_output jFinOutput +#define jpeg_input_complete jInComplete +#define jpeg_new_colormap jNewCMap +#define jpeg_consume_input jConsumeInput +#define jpeg_calc_output_dimensions jCalcDimensions +#define jpeg_save_markers jSaveMarkers +#define jpeg_set_marker_processor jSetMarker +#define jpeg_read_coefficients jReadCoefs +#define jpeg_write_coefficients jWrtCoefs +#define jpeg_copy_critical_parameters jCopyCrit +#define jpeg_abort_compress jAbrtCompress +#define jpeg_abort_decompress jAbrtDecompress +#define jpeg_abort jAbort +#define jpeg_destroy jDestroy +#define jpeg_resync_to_restart jResyncRestart +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Default error-management setup */ +EXTERN(struct jpeg_error_mgr *) jpeg_std_error + JPP((struct jpeg_error_mgr * err)); + +/* Initialization of JPEG compression objects. + * jpeg_create_compress() and jpeg_create_decompress() are the exported + * names that applications should call. These expand to calls on + * jpeg_CreateCompress and jpeg_CreateDecompress with additional information + * passed for version mismatch checking. + * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. + */ +#define jpeg_create_compress(cinfo) \ + jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_compress_struct)) +#define jpeg_create_decompress(cinfo) \ + jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_decompress_struct)) +EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, + int version, size_t structsize)); +EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, + int version, size_t structsize)); +/* Destruction of JPEG compression objects */ +EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); + +/* Standard data source and destination managers: stdio streams. */ +/* Caller is responsible for opening the file before and closing after. */ +EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); +EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); + +/* Default parameter setup for compression */ +EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); +/* Compression parameter setup aids */ +EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, + J_COLOR_SPACE colorspace)); +EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, + boolean force_baseline)); +EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, + int scale_factor, + boolean force_baseline)); +EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, + boolean force_baseline)); +EXTERN(int) jpeg_quality_scaling JPP((int quality)); +EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, + boolean suppress)); +EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); +EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); + +/* Main entry points for compression */ +EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, + boolean write_all_tables)); +EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION num_lines)); +EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); + +/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION num_lines)); + +/* Write a special marker. See libjpeg.doc concerning safe usage. */ +EXTERN(void) jpeg_write_marker + JPP((j_compress_ptr cinfo, int marker, + const JOCTET * dataptr, unsigned int datalen)); +/* Same, but piecemeal. */ +EXTERN(void) jpeg_write_m_header + JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); +EXTERN(void) jpeg_write_m_byte + JPP((j_compress_ptr cinfo, int val)); + +/* Alternate compression function: just write an abbreviated table file */ +EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); + +/* Decompression startup: read start of JPEG datastream to see what's there */ +EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, + boolean require_image)); +/* Return value is one of: */ +#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ +#define JPEG_HEADER_OK 1 /* Found valid image datastream */ +#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ +/* If you pass require_image = TRUE (normal case), you need not check for + * a TABLES_ONLY return code; an abbreviated file will cause an error exit. + * JPEG_SUSPENDED is only possible if you use a data source module that can + * give a suspension return (the stdio source module doesn't). + */ + +/* Main entry points for decompression */ +EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION max_lines)); +EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); + +/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION max_lines)); + +/* Additional entry points for buffered-image mode. */ +EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo, + int scan_number)); +EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); +EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); +/* Return value is one of: */ +/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ +#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ +#define JPEG_REACHED_EOI 2 /* Reached end of image */ +#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ +#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ + +/* Precalculate output dimensions for current decompression parameters. */ +EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); + +/* Control saving of COM and APPn markers into marker_list. */ +EXTERN(void) jpeg_save_markers + JPP((j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit)); + +/* Install a special processing method for COM or APPn markers. */ +EXTERN(void) jpeg_set_marker_processor + JPP((j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine)); + +/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ +EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays)); +EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, + j_compress_ptr dstinfo)); + +/* If you choose to abort compression or decompression before completing + * jpeg_finish_(de)compress, then you need to clean up to release memory, + * temporary files, etc. You can just call jpeg_destroy_(de)compress + * if you're done with the JPEG object, but if you want to clean it up and + * reuse it, call this: + */ +EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); + +/* Generic versions of jpeg_abort and jpeg_destroy that work on either + * flavor of JPEG object. These may be more convenient in some places. + */ +EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); + +/* Default restart-marker-resync procedure for use by data source modules */ +EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, + int desired)); + + +/* These marker codes are exported since applications and data source modules + * are likely to want to use them. + */ + +#define JPEG_RST0 0xD0 /* RST0 marker code */ +#define JPEG_EOI 0xD9 /* EOI marker code */ +#define JPEG_APP0 0xE0 /* APP0 marker code */ +#define JPEG_COM 0xFE /* COM marker code */ + + +/* If we have a brain-damaged compiler that emits warnings (or worse, errors) + * for structure definitions that are never filled in, keep it quiet by + * supplying dummy definitions for the various substructures. + */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +struct jpeg_comp_master { long dummy; }; +struct jpeg_c_main_controller { long dummy; }; +struct jpeg_c_prep_controller { long dummy; }; +struct jpeg_c_coef_controller { long dummy; }; +struct jpeg_marker_writer { long dummy; }; +struct jpeg_color_converter { long dummy; }; +struct jpeg_downsampler { long dummy; }; +struct jpeg_forward_dct { long dummy; }; +struct jpeg_entropy_encoder { long dummy; }; +struct jpeg_decomp_master { long dummy; }; +struct jpeg_d_main_controller { long dummy; }; +struct jpeg_d_coef_controller { long dummy; }; +struct jpeg_d_post_controller { long dummy; }; +struct jpeg_input_controller { long dummy; }; +struct jpeg_marker_reader { long dummy; }; +struct jpeg_entropy_decoder { long dummy; }; +struct jpeg_inverse_dct { long dummy; }; +struct jpeg_upsampler { long dummy; }; +struct jpeg_color_deconverter { long dummy; }; +struct jpeg_color_quantizer { long dummy; }; +#endif /* JPEG_INTERNALS */ +#endif /* INCOMPLETE_TYPES_BROKEN */ + + +/* + * The JPEG library modules define JPEG_INTERNALS before including this file. + * The internal structure declarations are read only when that is true. + * Applications using the library should not include jpegint.h, but may wish + * to include jerror.h. + */ + +#ifdef JPEG_INTERNALS +#include "jpegint.h" /* fetch private declarations */ +#include "jerror.h" /* fetch error codes too */ +#endif + +#endif /* JPEGLIB_H */ diff --git a/plugins/zerogs/opengl/Win32/resource.h b/plugins/zerogs/opengl/Win32/resource.h index 053ec92e01..13bbdd0ce2 100644 --- a/plugins/zerogs/opengl/Win32/resource.h +++ b/plugins/zerogs/opengl/Win32/resource.h @@ -1,45 +1,45 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by GSsoftdx.rc -// -#define IDD_CONFIG 101 -#define IDD_ABOUT 102 -#define IDD_LOGGING 106 -#define IDB_ZEROGSLOGO 108 -#define IDR_REALPS2_FX 109 -#define IDR_SHADERS 110 -#define IDC_CHECK1 1000 -#define IDC_FULLSCREEN 1000 -#define IDC_NAME 1000 -#define IDC_LOG 1000 -#define IDC_CHECK2 1001 -#define IDC_FPSCOUNT 1001 -#define IDC_CHECK5 1002 -#define IDC_FRAMESKIP 1002 -#define IDC_STRETCH 1003 -#define IDC_LOGGING 1004 -#define IDC_COMBO1 1005 -#define IDC_CACHE 1005 -#define IDC_CACHESIZE 1006 -#define IDC_CHECK3 1007 -#define IDC_RECORD 1007 -#define IDC_COMBO2 1008 -#define IDC_DSPRES 1008 -#define IDC_WRES 1008 -#define IDC_COMBO3 1009 -#define IDC_DDDRV 1009 -#define IDC_FRES 1009 -#define IDC_COMBO4 1012 -#define IDC_CODEC 1012 -#define IDC_FILTERS 1014 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 112 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1015 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by GSsoftdx.rc +// +#define IDD_CONFIG 101 +#define IDD_ABOUT 102 +#define IDD_LOGGING 106 +#define IDB_ZEROGSLOGO 108 +#define IDR_REALPS2_FX 109 +#define IDR_SHADERS 110 +#define IDC_CHECK1 1000 +#define IDC_FULLSCREEN 1000 +#define IDC_NAME 1000 +#define IDC_LOG 1000 +#define IDC_CHECK2 1001 +#define IDC_FPSCOUNT 1001 +#define IDC_CHECK5 1002 +#define IDC_FRAMESKIP 1002 +#define IDC_STRETCH 1003 +#define IDC_LOGGING 1004 +#define IDC_COMBO1 1005 +#define IDC_CACHE 1005 +#define IDC_CACHESIZE 1006 +#define IDC_CHECK3 1007 +#define IDC_RECORD 1007 +#define IDC_COMBO2 1008 +#define IDC_DSPRES 1008 +#define IDC_WRES 1008 +#define IDC_COMBO3 1009 +#define IDC_DDDRV 1009 +#define IDC_FRES 1009 +#define IDC_COMBO4 1012 +#define IDC_CODEC 1012 +#define IDC_FILTERS 1014 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 112 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1015 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/zerogs/opengl/Win32/resrc1.h b/plugins/zerogs/opengl/Win32/resrc1.h index 6c2956f489..ef58a2ca0f 100644 --- a/plugins/zerogs/opengl/Win32/resrc1.h +++ b/plugins/zerogs/opengl/Win32/resrc1.h @@ -1,79 +1,79 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by zerogs.rc -// -#define IDC_CONF_DEFAULT 3 -#define IDR_DATA1 112 -#define IDC_ABOUTTEXT 1015 -#define IDC_CONFIG_AA 1016 -#define IDC_CONFIG_INTERLACE 1017 -#define IDC_CONFIG_AA3 1018 -#define IDC_CONFIG_CAPTUREAVI 1018 -#define IDC_CONFIG_CAPTUREAVI2 1019 -#define IDC_CONFIG_FULLSCREEN 1019 -#define IDC_CONFIG_FULLSCREEN2 1020 -#define IDC_CONFIG_FFX 1020 -#define IDC_CONFIG_INTERLACE2 1021 -#define IDC_CONFIG_DEPTHWRITE 1021 -#define IDC_CONFIG_FFX2 1021 -#define IDC_CONFIG_BMPSS 1021 -#define IDC_CONFIG_AANONE 1022 -#define IDC_CONFIG_AA2 1023 -#define IDC_RADIO3 1024 -#define IDC_CONFIG_AA4 1024 -#define IDC_CONFIG_INTERLACE3 1025 -#define IDC_CONFIG_BILINEAR 1025 -#define IDC_CONF_WIN640 1026 -#define IDC_CONF_WIN800 1027 -#define IDC_CONF_WIN1024 1028 -#define IDC_RADIO5 1029 -#define IDC_CONF_WIN1280 1029 -#define IDC_CONFIG_CAPTUREAVI3 1030 -#define IDC_CONFIG_WIREFRAME 1030 -#define IDC_CONFIG_CAPTUREAVI4 1031 -#define IDC_CONFIG_CACHEFBP 1031 -#define IDC_CONFIG_SHOWFPS 1031 -#define IDC_CONFOPT_00100000 1031 -#define IDC_CONFOPT_00080000 1032 -#define IDC_CONFOPT_00002000 1033 -#define IDC_CONFOPT_00001000 1035 -#define IDC_CONFOPT_00000200 1037 -#define IDC_CONFOPT_00000080 1038 -#define IDC_CONFOPT_201 1039 -#define IDC_CONFOPT_00000040 1039 -#define IDC_CONFOPT_00000020 1040 -#define IDC_CONFOPT_00000001 1042 -#define IDC_CONFOPT_00000004 1044 -#define IDC_CONFOPT_IDS 1045 -#define IDC_CONFOPT_00200000 1046 -#define IDC_CONFOPT_00004000 1047 -#define IDC_BUTTON1 1048 -#define IDC_CONFOPT_COMPUTEOR 1048 -#define IDC_CONFOPT_4001 1049 -#define IDC_CONFOPT_00000010 1049 -#define IDC_CONFOPT_00008000 1050 -#define IDC_CONFOPT_00010000 1052 -#define IDC_CONFOPT_00020000 1054 -#define IDC_CONFOPT_00000002 1055 -#define IDC_CONFOPT_01000000 1056 -#define IDC_CONFOPT_00800000 1057 -#define IDC_CONFOPT_00000008 1058 -#define IDC_CONFOPT_00000400 1060 -#define IDC_CONFOPT_00000800 1061 -#define IDC_CONFOPT_NOALPHABLEND30 1062 -#define IDC_CONFOPT_00040000 1063 -#define IDC_CONFOPT_02000000 1064 -#define IDC_CONFOPT_04000000 1065 -#define IDC_CONFIG_AA8 2003 -#define IDC_CONFIG_AA16 2004 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 113 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1049 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by zerogs.rc +// +#define IDC_CONF_DEFAULT 3 +#define IDR_DATA1 112 +#define IDC_ABOUTTEXT 1015 +#define IDC_CONFIG_AA 1016 +#define IDC_CONFIG_INTERLACE 1017 +#define IDC_CONFIG_AA3 1018 +#define IDC_CONFIG_CAPTUREAVI 1018 +#define IDC_CONFIG_CAPTUREAVI2 1019 +#define IDC_CONFIG_FULLSCREEN 1019 +#define IDC_CONFIG_FULLSCREEN2 1020 +#define IDC_CONFIG_FFX 1020 +#define IDC_CONFIG_INTERLACE2 1021 +#define IDC_CONFIG_DEPTHWRITE 1021 +#define IDC_CONFIG_FFX2 1021 +#define IDC_CONFIG_BMPSS 1021 +#define IDC_CONFIG_AANONE 1022 +#define IDC_CONFIG_AA2 1023 +#define IDC_RADIO3 1024 +#define IDC_CONFIG_AA4 1024 +#define IDC_CONFIG_INTERLACE3 1025 +#define IDC_CONFIG_BILINEAR 1025 +#define IDC_CONF_WIN640 1026 +#define IDC_CONF_WIN800 1027 +#define IDC_CONF_WIN1024 1028 +#define IDC_RADIO5 1029 +#define IDC_CONF_WIN1280 1029 +#define IDC_CONFIG_CAPTUREAVI3 1030 +#define IDC_CONFIG_WIREFRAME 1030 +#define IDC_CONFIG_CAPTUREAVI4 1031 +#define IDC_CONFIG_CACHEFBP 1031 +#define IDC_CONFIG_SHOWFPS 1031 +#define IDC_CONFOPT_00100000 1031 +#define IDC_CONFOPT_00080000 1032 +#define IDC_CONFOPT_00002000 1033 +#define IDC_CONFOPT_00001000 1035 +#define IDC_CONFOPT_00000200 1037 +#define IDC_CONFOPT_00000080 1038 +#define IDC_CONFOPT_201 1039 +#define IDC_CONFOPT_00000040 1039 +#define IDC_CONFOPT_00000020 1040 +#define IDC_CONFOPT_00000001 1042 +#define IDC_CONFOPT_00000004 1044 +#define IDC_CONFOPT_IDS 1045 +#define IDC_CONFOPT_00200000 1046 +#define IDC_CONFOPT_00004000 1047 +#define IDC_BUTTON1 1048 +#define IDC_CONFOPT_COMPUTEOR 1048 +#define IDC_CONFOPT_4001 1049 +#define IDC_CONFOPT_00000010 1049 +#define IDC_CONFOPT_00008000 1050 +#define IDC_CONFOPT_00010000 1052 +#define IDC_CONFOPT_00020000 1054 +#define IDC_CONFOPT_00000002 1055 +#define IDC_CONFOPT_01000000 1056 +#define IDC_CONFOPT_00800000 1057 +#define IDC_CONFOPT_00000008 1058 +#define IDC_CONFOPT_00000400 1060 +#define IDC_CONFOPT_00000800 1061 +#define IDC_CONFOPT_NOALPHABLEND30 1062 +#define IDC_CONFOPT_00040000 1063 +#define IDC_CONFOPT_02000000 1064 +#define IDC_CONFOPT_04000000 1065 +#define IDC_CONFIG_AA8 2003 +#define IDC_CONFIG_AA16 2004 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 113 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1049 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/zerogs/opengl/Win32/vsprops/svnrev_template.h b/plugins/zerogs/opengl/Win32/vsprops/svnrev_template.h index afab6c4fd1..f2656ef1e8 100644 --- a/plugins/zerogs/opengl/Win32/vsprops/svnrev_template.h +++ b/plugins/zerogs/opengl/Win32/vsprops/svnrev_template.h @@ -1,18 +1,18 @@ -// svnrev_template.h --> svnrev.h -// -// This file acts as a template for the automatic SVN revision/version tag. -// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for -// whichever project is being compiled (as indicated by command line options -// passed to SubWCRev.exe during the project's pre-build step). -// -// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs -// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN -// installed on your system. If you do not have it installed, a generic template -// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not -// necessary. If you do not have it installed, everything will still compile -// fine except without the SVN revision tagged to the application/dll version. -// -// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org - -#define SVN_REV $WCREV$ +// svnrev_template.h --> svnrev.h +// +// This file acts as a template for the automatic SVN revision/version tag. +// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for +// whichever project is being compiled (as indicated by command line options +// passed to SubWCRev.exe during the project's pre-build step). +// +// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs +// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN +// installed on your system. If you do not have it installed, a generic template +// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not +// necessary. If you do not have it installed, everything will still compile +// fine except without the SVN revision tagged to the application/dll version. +// +// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV $WCREV$ #define SVN_MODS $WCMODS?1:0$ \ No newline at end of file diff --git a/plugins/zerogs/opengl/Win32/vsprops/svnrev_unknown.h b/plugins/zerogs/opengl/Win32/vsprops/svnrev_unknown.h index a2a3703186..4872e23b20 100644 --- a/plugins/zerogs/opengl/Win32/vsprops/svnrev_unknown.h +++ b/plugins/zerogs/opengl/Win32/vsprops/svnrev_unknown.h @@ -1,23 +1,23 @@ -// svnrev_genric.h --> svnrev.h -// -// This file acts as a placebo for people who do not have TortoiseSVN installed. -// It provides "empty" revision information to the Pcsx2 Playground projects in -// the absence of real revisions derived from the repository being built. -// -// This file does not affect application/dll builds in any significant manner, -// other than the lack of automatic revision tags inserted into the app (which -// is very convenient but hardly necessary). -// -// See svn_template.h for more information on how the process of revision -// templating works. -// -// If you would like to enable automatic revisin tagging, TortoiseSVN can be -// downloaded from http://tortoisesvn.tigris.org - -#define SVN_REV_UNKNOWN - -// The following defines are included so that code will still compile even if it -// doesn't check for the SVN_REV_UNKNOWN define. - -#define SVN_REV 0 +// svnrev_genric.h --> svnrev.h +// +// This file acts as a placebo for people who do not have TortoiseSVN installed. +// It provides "empty" revision information to the Pcsx2 Playground projects in +// the absence of real revisions derived from the repository being built. +// +// This file does not affect application/dll builds in any significant manner, +// other than the lack of automatic revision tags inserted into the app (which +// is very convenient but hardly necessary). +// +// See svn_template.h for more information on how the process of revision +// templating works. +// +// If you would like to enable automatic revisin tagging, TortoiseSVN can be +// downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV_UNKNOWN + +// The following defines are included so that code will still compile even if it +// doesn't check for the SVN_REV_UNKNOWN define. + +#define SVN_REV 0 #define SVN_MODS "" \ No newline at end of file diff --git a/plugins/zerogs/opengl/Win32/zlib/adler32.c b/plugins/zerogs/opengl/Win32/zlib/adler32.c index bc0842f01b..20dd55c94b 100644 --- a/plugins/zerogs/opengl/Win32/zlib/adler32.c +++ b/plugins/zerogs/opengl/Win32/zlib/adler32.c @@ -1,74 +1,74 @@ -/* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id: adler32.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -#define BASE 65521UL /* largest prime smaller than 65536 */ -#define NMAX 5552 -/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ - -#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} -#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); -#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); -#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); -#define DO16(buf) DO8(buf,0); DO8(buf,8); - -#ifdef NO_DIVIDE -# define MOD(a) \ - do { \ - if (a >= (BASE << 16)) a -= (BASE << 16); \ - if (a >= (BASE << 15)) a -= (BASE << 15); \ - if (a >= (BASE << 14)) a -= (BASE << 14); \ - if (a >= (BASE << 13)) a -= (BASE << 13); \ - if (a >= (BASE << 12)) a -= (BASE << 12); \ - if (a >= (BASE << 11)) a -= (BASE << 11); \ - if (a >= (BASE << 10)) a -= (BASE << 10); \ - if (a >= (BASE << 9)) a -= (BASE << 9); \ - if (a >= (BASE << 8)) a -= (BASE << 8); \ - if (a >= (BASE << 7)) a -= (BASE << 7); \ - if (a >= (BASE << 6)) a -= (BASE << 6); \ - if (a >= (BASE << 5)) a -= (BASE << 5); \ - if (a >= (BASE << 4)) a -= (BASE << 4); \ - if (a >= (BASE << 3)) a -= (BASE << 3); \ - if (a >= (BASE << 2)) a -= (BASE << 2); \ - if (a >= (BASE << 1)) a -= (BASE << 1); \ - if (a >= BASE) a -= BASE; \ - } while (0) -#else -# define MOD(a) a %= BASE -#endif - -/* ========================================================================= */ -uLong ZEXPORT adler32(adler, buf, len) - uLong adler; - const Bytef *buf; - uInt len; -{ - unsigned long s1 = adler & 0xffff; - unsigned long s2 = (adler >> 16) & 0xffff; - int k; - - if (buf == Z_NULL) return 1L; - - while (len > 0) { - k = len < NMAX ? (int)len : NMAX; - len -= k; - while (k >= 16) { - DO16(buf); - buf += 16; - k -= 16; - } - if (k != 0) do { - s1 += *buf++; - s2 += s1; - } while (--k); - MOD(s1); - MOD(s2); - } - return (s2 << 16) | s1; -} +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: adler32.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? (int)len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + MOD(s1); + MOD(s2); + } + return (s2 << 16) | s1; +} diff --git a/plugins/zerogs/opengl/Win32/zlib/compress.c b/plugins/zerogs/opengl/Win32/zlib/compress.c index e7ea2c518b..87910ef046 100644 --- a/plugins/zerogs/opengl/Win32/zlib/compress.c +++ b/plugins/zerogs/opengl/Win32/zlib/compress.c @@ -1,79 +1,79 @@ -/* compress.c -- compress a memory buffer - * Copyright (C) 1995-2002 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id: compress.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -/* =========================================================================== - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least 0.1% larger than sourceLen plus - 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ -int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; - int level; -{ - z_stream stream; - int err; - - stream.next_in = (Bytef*)source; - stream.avail_in = (uInt)sourceLen; -#ifdef MAXSEG_64K - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; -#endif - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; - - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - stream.opaque = (voidpf)0; - - err = deflateInit(&stream, level); - if (err != Z_OK) return err; - - err = deflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - deflateEnd(&stream); - return err == Z_OK ? Z_BUF_ERROR : err; - } - *destLen = stream.total_out; - - err = deflateEnd(&stream); - return err; -} - -/* =========================================================================== - */ -int ZEXPORT compress (dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ - return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); -} - -/* =========================================================================== - If the default memLevel or windowBits for deflateInit() is changed, then - this function needs to be updated. - */ -uLong ZEXPORT compressBound (sourceLen) - uLong sourceLen; -{ - return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; -} +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: compress.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/plugins/zerogs/opengl/Win32/zlib/crc32.c b/plugins/zerogs/opengl/Win32/zlib/crc32.c index aa8b984a34..39db700d64 100644 --- a/plugins/zerogs/opengl/Win32/zlib/crc32.c +++ b/plugins/zerogs/opengl/Win32/zlib/crc32.c @@ -1,311 +1,311 @@ -/* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Thanks to Rodney Brown for his contribution of faster - * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing - * tables for updating the shift register in one step with three exclusive-ors - * instead of four steps with four exclusive-ors. This results about a factor - * of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. - */ - -/* @(#) $Id: crc32.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ - -#ifdef MAKECRCH -# include -# ifndef DYNAMIC_CRC_TABLE -# define DYNAMIC_CRC_TABLE -# endif /* !DYNAMIC_CRC_TABLE */ -#endif /* MAKECRCH */ - -#include "zutil.h" /* for STDC and FAR definitions */ - -#define local static - -/* Find a four-byte integer type for crc32_little() and crc32_big(). */ -#ifndef NOBYFOUR -# ifdef STDC /* need ANSI C limits.h to determine sizes */ -# include -# define BYFOUR -# if (UINT_MAX == 0xffffffffUL) - typedef unsigned int u4; -# else -# if (ULONG_MAX == 0xffffffffUL) - typedef unsigned long u4; -# else -# if (USHRT_MAX == 0xffffffffUL) - typedef unsigned short u4; -# else -# undef BYFOUR /* can't find a four-byte integer type! */ -# endif -# endif -# endif -# endif /* STDC */ -#endif /* !NOBYFOUR */ - -/* Definitions for doing the crc four data bytes at a time. */ -#ifdef BYFOUR -# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ - (((w)&0xff00)<<8)+(((w)&0xff)<<24)) - local unsigned long crc32_little OF((unsigned long, - const unsigned char FAR *, unsigned)); - local unsigned long crc32_big OF((unsigned long, - const unsigned char FAR *, unsigned)); -# define TBLS 8 -#else -# define TBLS 1 -#endif /* BYFOUR */ - -#ifdef DYNAMIC_CRC_TABLE - -local int crc_table_empty = 1; -local unsigned long FAR crc_table[TBLS][256]; -local void make_crc_table OF((void)); -#ifdef MAKECRCH - local void write_table OF((FILE *, const unsigned long FAR *)); -#endif /* MAKECRCH */ - -/* - Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: - x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. - - Polynomials over GF(2) are represented in binary, one bit per coefficient, - with the lowest powers in the most significant bit. Then adding polynomials - is just exclusive-or, and multiplying a polynomial by x is a right shift by - one. If we call the above polynomial p, and represent a byte as the - polynomial q, also with the lowest power in the most significant bit (so the - byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, - where a mod b means the remainder after dividing a by b. - - This calculation is done using the shift-register method of multiplying and - taking the remainder. The register is initialized to zero, and for each - incoming bit, x^32 is added mod p to the register if the bit is a one (where - x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by - x (which is shifting right by one and adding x^32 mod p if the bit shifted - out is a one). We start with the highest power (least significant bit) of - q and repeat for all eight bits of q. - - The first table is simply the CRC of all possible eight bit values. This is - all the information needed to generate CRCs on data a byte at a time for all - combinations of CRC register values and incoming bytes. The remaining tables - allow for word-at-a-time CRC calculation for both big-endian and little- - endian machines, where a word is four bytes. -*/ -local void make_crc_table() -{ - unsigned long c; - int n, k; - unsigned long poly; /* polynomial exclusive-or pattern */ - /* terms of polynomial defining this crc (except x^32): */ - static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - /* make exclusive-or pattern from polynomial (0xedb88320UL) */ - poly = 0UL; - for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) - poly |= 1UL << (31 - p[n]); - - /* generate a crc for every 8-bit value */ - for (n = 0; n < 256; n++) { - c = (unsigned long)n; - for (k = 0; k < 8; k++) - c = c & 1 ? poly ^ (c >> 1) : c >> 1; - crc_table[0][n] = c; - } - -#ifdef BYFOUR - /* generate crc for each value followed by one, two, and three zeros, and - then the byte reversal of those as well as the first table */ - for (n = 0; n < 256; n++) { - c = crc_table[0][n]; - crc_table[4][n] = REV(c); - for (k = 1; k < 4; k++) { - c = crc_table[0][c & 0xff] ^ (c >> 8); - crc_table[k][n] = c; - crc_table[k + 4][n] = REV(c); - } - } -#endif /* BYFOUR */ - - crc_table_empty = 0; - -#ifdef MAKECRCH - /* write out CRC tables to crc32.h */ - { - FILE *out; - - out = fopen("crc32.h", "w"); - if (out == NULL) return; - fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); - fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); - fprintf(out, "local const unsigned long FAR "); - fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); - write_table(out, crc_table[0]); -# ifdef BYFOUR - fprintf(out, "#ifdef BYFOUR\n"); - for (k = 1; k < 8; k++) { - fprintf(out, " },\n {\n"); - write_table(out, crc_table[k]); - } - fprintf(out, "#endif\n"); -# endif /* BYFOUR */ - fprintf(out, " }\n};\n"); - fclose(out); - } -#endif /* MAKECRCH */ -} - -#ifdef MAKECRCH -local void write_table(out, table) - FILE *out; - const unsigned long FAR *table; -{ - int n; - - for (n = 0; n < 256; n++) - fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], - n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); -} -#endif /* MAKECRCH */ - -#else /* !DYNAMIC_CRC_TABLE */ -/* ======================================================================== - * Tables of CRC-32s of all single-byte values, made by make_crc_table(). - */ -#include "crc32.h" -#endif /* DYNAMIC_CRC_TABLE */ - -/* ========================================================================= - * This function can be used by asm versions of crc32() - */ -const unsigned long FAR * ZEXPORT get_crc_table() -{ -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) make_crc_table(); -#endif /* DYNAMIC_CRC_TABLE */ - return (const unsigned long FAR *)crc_table; -} - -/* ========================================================================= */ -#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) -#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 - -/* ========================================================================= */ -unsigned long ZEXPORT crc32(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - if (buf == Z_NULL) return 0UL; - -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); -#endif /* DYNAMIC_CRC_TABLE */ - -#ifdef BYFOUR - if (sizeof(void *) == sizeof(ptrdiff_t)) { - u4 endian; - - endian = 1; - if (*((unsigned char *)(&endian))) - return crc32_little(crc, buf, len); - else - return crc32_big(crc, buf, len); - } -#endif /* BYFOUR */ - crc = crc ^ 0xffffffffUL; - while (len >= 8) { - DO8; - len -= 8; - } - if (len) do { - DO1; - } while (--len); - return crc ^ 0xffffffffUL; -} - -#ifdef BYFOUR - -/* ========================================================================= */ -#define DOLIT4 c ^= *buf4++; \ - c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ - crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] -#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 - -/* ========================================================================= */ -local unsigned long crc32_little(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - register u4 c; - register const u4 FAR *buf4; - - c = (u4)crc; - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - len--; - } - - buf4 = (const u4 FAR *)buf; - while (len >= 32) { - DOLIT32; - len -= 32; - } - while (len >= 4) { - DOLIT4; - len -= 4; - } - buf = (const unsigned char FAR *)buf4; - - if (len) do { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - } while (--len); - c = ~c; - return (unsigned long)c; -} - -/* ========================================================================= */ -#define DOBIG4 c ^= *++buf4; \ - c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ - crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] -#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 - -/* ========================================================================= */ -local unsigned long crc32_big(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - unsigned len; -{ - register u4 c; - register const u4 FAR *buf4; - - c = REV((u4)crc); - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - len--; - } - - buf4 = (const u4 FAR *)buf; - buf4--; - while (len >= 32) { - DOBIG32; - len -= 32; - } - while (len >= 4) { - DOBIG4; - len -= 4; - } - buf4++; - buf = (const unsigned char FAR *)buf4; - - if (len) do { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - } while (--len); - c = ~c; - return (unsigned long)(REV(c)); -} - -#endif /* BYFOUR */ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results about a factor + * of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id: crc32.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +#ifdef DYNAMIC_CRC_TABLE + +local int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ + +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, and + then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ diff --git a/plugins/zerogs/opengl/Win32/zlib/crc32.h b/plugins/zerogs/opengl/Win32/zlib/crc32.h index 5de49bc978..8053b6117c 100644 --- a/plugins/zerogs/opengl/Win32/zlib/crc32.h +++ b/plugins/zerogs/opengl/Win32/zlib/crc32.h @@ -1,441 +1,441 @@ -/* crc32.h -- tables for rapid CRC calculation - * Generated automatically by crc32.c - */ - -local const unsigned long FAR crc_table[TBLS][256] = -{ - { - 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, - 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, - 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, - 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, - 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, - 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, - 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, - 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, - 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, - 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, - 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, - 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, - 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, - 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, - 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, - 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, - 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, - 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, - 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, - 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, - 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, - 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, - 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, - 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, - 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, - 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, - 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, - 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, - 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, - 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, - 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, - 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, - 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, - 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, - 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, - 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, - 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, - 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, - 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, - 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, - 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, - 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, - 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, - 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, - 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, - 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, - 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, - 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, - 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, - 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, - 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, - 0x2d02ef8dUL -#ifdef BYFOUR - }, - { - 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, - 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, - 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, - 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, - 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, - 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, - 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, - 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, - 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, - 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, - 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, - 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, - 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, - 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, - 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, - 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, - 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, - 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, - 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, - 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, - 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, - 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, - 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, - 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, - 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, - 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, - 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, - 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, - 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, - 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, - 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, - 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, - 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, - 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, - 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, - 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, - 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, - 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, - 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, - 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, - 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, - 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, - 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, - 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, - 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, - 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, - 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, - 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, - 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, - 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, - 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, - 0x9324fd72UL - }, - { - 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, - 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, - 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, - 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, - 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, - 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, - 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, - 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, - 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, - 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, - 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, - 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, - 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, - 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, - 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, - 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, - 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, - 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, - 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, - 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, - 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, - 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, - 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, - 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, - 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, - 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, - 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, - 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, - 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, - 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, - 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, - 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, - 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, - 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, - 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, - 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, - 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, - 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, - 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, - 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, - 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, - 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, - 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, - 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, - 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, - 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, - 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, - 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, - 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, - 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, - 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, - 0xbe9834edUL - }, - { - 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, - 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, - 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, - 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, - 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, - 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, - 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, - 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, - 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, - 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, - 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, - 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, - 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, - 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, - 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, - 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, - 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, - 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, - 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, - 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, - 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, - 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, - 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, - 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, - 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, - 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, - 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, - 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, - 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, - 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, - 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, - 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, - 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, - 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, - 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, - 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, - 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, - 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, - 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, - 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, - 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, - 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, - 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, - 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, - 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, - 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, - 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, - 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, - 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, - 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, - 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, - 0xde0506f1UL - }, - { - 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, - 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, - 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, - 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, - 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, - 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, - 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, - 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, - 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, - 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, - 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, - 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, - 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, - 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, - 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, - 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, - 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, - 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, - 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, - 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, - 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, - 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, - 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, - 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, - 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, - 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, - 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, - 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, - 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, - 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, - 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, - 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, - 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, - 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, - 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, - 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, - 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, - 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, - 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, - 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, - 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, - 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, - 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, - 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, - 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, - 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, - 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, - 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, - 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, - 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, - 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, - 0x8def022dUL - }, - { - 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, - 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, - 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, - 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, - 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, - 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, - 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, - 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, - 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, - 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, - 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, - 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, - 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, - 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, - 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, - 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, - 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, - 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, - 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, - 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, - 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, - 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, - 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, - 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, - 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, - 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, - 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, - 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, - 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, - 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, - 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, - 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, - 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, - 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, - 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, - 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, - 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, - 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, - 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, - 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, - 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, - 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, - 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, - 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, - 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, - 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, - 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, - 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, - 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, - 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, - 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, - 0x72fd2493UL - }, - { - 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, - 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, - 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, - 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, - 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, - 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, - 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, - 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, - 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, - 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, - 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, - 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, - 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, - 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, - 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, - 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, - 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, - 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, - 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, - 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, - 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, - 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, - 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, - 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, - 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, - 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, - 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, - 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, - 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, - 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, - 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, - 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, - 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, - 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, - 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, - 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, - 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, - 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, - 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, - 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, - 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, - 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, - 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, - 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, - 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, - 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, - 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, - 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, - 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, - 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, - 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, - 0xed3498beUL - }, - { - 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, - 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, - 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, - 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, - 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, - 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, - 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, - 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, - 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, - 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, - 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, - 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, - 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, - 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, - 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, - 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, - 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, - 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, - 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, - 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, - 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, - 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, - 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, - 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, - 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, - 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, - 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, - 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, - 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, - 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, - 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, - 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, - 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, - 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, - 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, - 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, - 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, - 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, - 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, - 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, - 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, - 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, - 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, - 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, - 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, - 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, - 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, - 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, - 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, - 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, - 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, - 0xf10605deUL -#endif - } -}; +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/plugins/zerogs/opengl/Win32/zlib/deflate.c b/plugins/zerogs/opengl/Win32/zlib/deflate.c index efe7b63aba..10374817ad 100644 --- a/plugins/zerogs/opengl/Win32/zlib/deflate.c +++ b/plugins/zerogs/opengl/Win32/zlib/deflate.c @@ -1,1502 +1,1502 @@ -/* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process depends on being able to identify portions - * of the input text which are identical to earlier input (within a - * sliding window trailing behind the input currently being processed). - * - * The most straightforward technique turns out to be the fastest for - * most input files: try all possible matches and select the longest. - * The key feature of this algorithm is that insertions into the string - * dictionary are very simple and thus fast, and deletions are avoided - * completely. Insertions are performed at each input character, whereas - * string matches are performed only when the previous match ends. So it - * is preferable to spend more time in matches to allow very fast string - * insertions and avoid deletions. The matching algorithm for small - * strings is inspired from that of Rabin & Karp. A brute force approach - * is used to find longer strings when a small match has been found. - * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze - * (by Leonid Broukhis). - * A previous version of this file used a more sophisticated algorithm - * (by Fiala and Greene) which is guaranteed to run in linear amortized - * time, but has a larger average cost, uses more memory and is patented. - * However the F&G algorithm may be faster for some highly redundant - * files if the parameter max_chain_length (described below) is too large. - * - * ACKNOWLEDGEMENTS - * - * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and - * I found it in 'freeze' written by Leonid Broukhis. - * Thanks to many people for bug reports and testing. - * - * REFERENCES - * - * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". - * Available in http://www.ietf.org/rfc/rfc1951.txt - * - * A description of the Rabin and Karp algorithm is given in the book - * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. - * - * Fiala,E.R., and Greene,D.H. - * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 - * - */ - -/* @(#) $Id: deflate.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ - -#include "deflate.h" - -const char deflate_copyright[] = - " deflate 1.2.1 Copyright 1995-2003 Jean-loup Gailly "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* =========================================================================== - * Function prototypes. - */ -typedef enum { - need_more, /* block not completed, need more input or more output */ - block_done, /* block flush performed */ - finish_started, /* finish started, need only more output at next deflate */ - finish_done /* finish done, accept no more input or output */ -} block_state; - -typedef block_state (*compress_func) OF((deflate_state *s, int flush)); -/* Compression function. Returns the block state after the call. */ - -local void fill_window OF((deflate_state *s)); -local block_state deflate_stored OF((deflate_state *s, int flush)); -local block_state deflate_fast OF((deflate_state *s, int flush)); -#ifndef FASTEST -local block_state deflate_slow OF((deflate_state *s, int flush)); -#endif -local void lm_init OF((deflate_state *s)); -local void putShortMSB OF((deflate_state *s, uInt b)); -local void flush_pending OF((z_streamp strm)); -local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); -#ifndef FASTEST -#ifdef ASMV - void match_init OF((void)); /* asm code initialization */ - uInt longest_match OF((deflate_state *s, IPos cur_match)); -#else -local uInt longest_match OF((deflate_state *s, IPos cur_match)); -#endif -#endif -local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); - -#ifdef DEBUG -local void check_match OF((deflate_state *s, IPos start, IPos match, - int length)); -#endif - -/* =========================================================================== - * Local data - */ - -#define NIL 0 -/* Tail of hash chains */ - -#ifndef TOO_FAR -# define TOO_FAR 4096 -#endif -/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -/* Values for max_lazy_match, good_match and max_chain_length, depending on - * the desired pack level (0..9). The values given below have been tuned to - * exclude worst case performance for pathological files. Better values may be - * found for specific files. - */ -typedef struct config_s { - ush good_length; /* reduce lazy search above this match length */ - ush max_lazy; /* do not perform lazy search above this match length */ - ush nice_length; /* quit search above this match length */ - ush max_chain; - compress_func func; -} config; - -#ifdef FASTEST -local const config configuration_table[2] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ -#else -local const config configuration_table[10] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ -/* 2 */ {4, 5, 16, 8, deflate_fast}, -/* 3 */ {4, 6, 32, 32, deflate_fast}, - -/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ -/* 5 */ {8, 16, 32, 32, deflate_slow}, -/* 6 */ {8, 16, 128, 128, deflate_slow}, -/* 7 */ {8, 32, 128, 256, deflate_slow}, -/* 8 */ {32, 128, 258, 1024, deflate_slow}, -/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ -#endif - -/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 - * For deflate_fast() (levels <= 3) good is ignored and lazy has a different - * meaning. - */ - -#define EQUAL 0 -/* result of memcmp for equal strings */ - -#ifndef NO_DUMMY_DECL -struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ -#endif - -/* =========================================================================== - * Update a hash value with the given input byte - * IN assertion: all calls to to UPDATE_HASH are made with consecutive - * input characters, so that a running hash key can be computed from the - * previous key instead of complete recalculation each time. - */ -#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) - - -/* =========================================================================== - * Insert string str in the dictionary and set match_head to the previous head - * of the hash chain (the most recent string with same hash key). Return - * the previous length of the hash chain. - * If this file is compiled with -DFASTEST, the compression level is forced - * to 1, and no hash chains are maintained. - * IN assertion: all calls to to INSERT_STRING are made with consecutive - * input characters and the first MIN_MATCH bytes of str are valid - * (except for the last MIN_MATCH-1 bytes of the input file). - */ -#ifdef FASTEST -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - match_head = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) -#else -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) -#endif - -/* =========================================================================== - * Initialize the hash table (avoiding 64K overflow for 16 bit systems). - * prev[] will be initialized on the fly. - */ -#define CLEAR_HASH(s) \ - s->head[s->hash_size-1] = NIL; \ - zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); - -/* ========================================================================= */ -int ZEXPORT deflateInit_(strm, level, version, stream_size) - z_streamp strm; - int level; - const char *version; - int stream_size; -{ - return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, version, stream_size); - /* To do: ignore strm->next_in if we use it as window */ -} - -/* ========================================================================= */ -int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, - version, stream_size) - z_streamp strm; - int level; - int method; - int windowBits; - int memLevel; - int strategy; - const char *version; - int stream_size; -{ - deflate_state *s; - int wrap = 1; - static const char my_version[] = ZLIB_VERSION; - - ushf *overlay; - /* We overlay pending_buf and d_buf+l_buf. This works since the average - * output size for (length,distance) codes is <= 24 bits. - */ - - if (version == Z_NULL || version[0] != my_version[0] || - stream_size != sizeof(z_stream)) { - return Z_VERSION_ERROR; - } - if (strm == Z_NULL) return Z_STREAM_ERROR; - - strm->msg = Z_NULL; - if (strm->zalloc == (alloc_func)0) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; - -#ifdef FASTEST - if (level != 0) level = 1; -#else - if (level == Z_DEFAULT_COMPRESSION) level = 6; -#endif - - if (windowBits < 0) { /* suppress zlib wrapper */ - wrap = 0; - windowBits = -windowBits; - } -#ifdef GZIP - else if (windowBits > 15) { - wrap = 2; /* write gzip wrapper instead */ - windowBits -= 16; - } -#endif - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || - windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_RLE) { - return Z_STREAM_ERROR; - } - if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ - s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); - if (s == Z_NULL) return Z_MEM_ERROR; - strm->state = (struct internal_state FAR *)s; - s->strm = strm; - - s->wrap = wrap; - s->w_bits = windowBits; - s->w_size = 1 << s->w_bits; - s->w_mask = s->w_size - 1; - - s->hash_bits = memLevel + 7; - s->hash_size = 1 << s->hash_bits; - s->hash_mask = s->hash_size - 1; - s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); - - s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); - s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); - s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); - - s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ - - overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); - s->pending_buf = (uchf *) overlay; - s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); - - if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || - s->pending_buf == Z_NULL) { - s->status = FINISH_STATE; - strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); - deflateEnd (strm); - return Z_MEM_ERROR; - } - s->d_buf = overlay + s->lit_bufsize/sizeof(ush); - s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; - - s->level = level; - s->strategy = strategy; - s->method = (Byte)method; - - return deflateReset(strm); -} - -/* ========================================================================= */ -int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) - z_streamp strm; - const Bytef *dictionary; - uInt dictLength; -{ - deflate_state *s; - uInt length = dictLength; - uInt n; - IPos hash_head = 0; - - if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || - strm->state->wrap == 2 || - (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) - return Z_STREAM_ERROR; - - s = strm->state; - if (s->wrap) - strm->adler = adler32(strm->adler, dictionary, dictLength); - - if (length < MIN_MATCH) return Z_OK; - if (length > MAX_DIST(s)) { - length = MAX_DIST(s); -#ifndef USE_DICT_HEAD - dictionary += dictLength - length; /* use the tail of the dictionary */ -#endif - } - zmemcpy(s->window, dictionary, length); - s->strstart = length; - s->block_start = (long)length; - - /* Insert all strings in the hash table (except for the last two bytes). - * s->lookahead stays null, so s->ins_h will be recomputed at the next - * call of fill_window. - */ - s->ins_h = s->window[0]; - UPDATE_HASH(s, s->ins_h, s->window[1]); - for (n = 0; n <= length - MIN_MATCH; n++) { - INSERT_STRING(s, n, hash_head); - } - if (hash_head) hash_head = 0; /* to make compiler happy */ - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateReset (strm) - z_streamp strm; -{ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL || - strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { - return Z_STREAM_ERROR; - } - - strm->total_in = strm->total_out = 0; - strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ - strm->data_type = Z_UNKNOWN; - - s = (deflate_state *)strm->state; - s->pending = 0; - s->pending_out = s->pending_buf; - - if (s->wrap < 0) { - s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ - } - s->status = s->wrap ? INIT_STATE : BUSY_STATE; - strm->adler = -#ifdef GZIP - s->wrap == 2 ? crc32(0L, Z_NULL, 0) : -#endif - adler32(0L, Z_NULL, 0); - s->last_flush = Z_NO_FLUSH; - - _tr_init(s); - lm_init(s); - - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflatePrime (strm, bits, value) - z_streamp strm; - int bits; - int value; -{ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - strm->state->bi_valid = bits; - strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateParams(strm, level, strategy) - z_streamp strm; - int level; - int strategy; -{ - deflate_state *s; - compress_func func; - int err = Z_OK; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - s = strm->state; - -#ifdef FASTEST - if (level != 0) level = 1; -#else - if (level == Z_DEFAULT_COMPRESSION) level = 6; -#endif - if (level < 0 || level > 9 || strategy < 0 || strategy > Z_RLE) { - return Z_STREAM_ERROR; - } - func = configuration_table[s->level].func; - - if (func != configuration_table[level].func && strm->total_in != 0) { - /* Flush the last buffer: */ - err = deflate(strm, Z_PARTIAL_FLUSH); - } - if (s->level != level) { - s->level = level; - s->max_lazy_match = configuration_table[level].max_lazy; - s->good_match = configuration_table[level].good_length; - s->nice_match = configuration_table[level].nice_length; - s->max_chain_length = configuration_table[level].max_chain; - } - s->strategy = strategy; - return err; -} - -/* ========================================================================= - * For the default windowBits of 15 and memLevel of 8, this function returns - * a close to exact, as well as small, upper bound on the compressed size. - * They are coded as constants here for a reason--if the #define's are - * changed, then this function needs to be changed as well. The return - * value for 15 and 8 only works for those exact settings. - * - * For any setting other than those defaults for windowBits and memLevel, - * the value returned is a conservative worst case for the maximum expansion - * resulting from using fixed blocks instead of stored blocks, which deflate - * can emit on compressed data for some combinations of the parameters. - * - * This function could be more sophisticated to provide closer upper bounds - * for every combination of windowBits and memLevel, as well as wrap. - * But even the conservative upper bound of about 14% expansion does not - * seem onerous for output buffer allocation. - */ -uLong ZEXPORT deflateBound(strm, sourceLen) - z_streamp strm; - uLong sourceLen; -{ - deflate_state *s; - uLong destLen; - - /* conservative upper bound */ - destLen = sourceLen + - ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; - - /* if can't get parameters, return conservative bound */ - if (strm == Z_NULL || strm->state == Z_NULL) - return destLen; - - /* if not default parameters, return conservative bound */ - s = strm->state; - if (s->w_bits != 15 || s->hash_bits != 8 + 7) - return destLen; - - /* default settings: return tight bound for that case */ - return compressBound(sourceLen); -} - -/* ========================================================================= - * Put a short in the pending buffer. The 16-bit value is put in MSB order. - * IN assertion: the stream state is correct and there is enough room in - * pending_buf. - */ -local void putShortMSB (s, b) - deflate_state *s; - uInt b; -{ - put_byte(s, (Byte)(b >> 8)); - put_byte(s, (Byte)(b & 0xff)); -} - -/* ========================================================================= - * Flush as much pending output as possible. All deflate() output goes - * through this function so some applications may wish to modify it - * to avoid allocating a large strm->next_out buffer and copying into it. - * (See also read_buf()). - */ -local void flush_pending(strm) - z_streamp strm; -{ - unsigned len = strm->state->pending; - - if (len > strm->avail_out) len = strm->avail_out; - if (len == 0) return; - - zmemcpy(strm->next_out, strm->state->pending_out, len); - strm->next_out += len; - strm->state->pending_out += len; - strm->total_out += len; - strm->avail_out -= len; - strm->state->pending -= len; - if (strm->state->pending == 0) { - strm->state->pending_out = strm->state->pending_buf; - } -} - -/* ========================================================================= */ -int ZEXPORT deflate (strm, flush) - z_streamp strm; - int flush; -{ - int old_flush; /* value of flush param for previous deflate call */ - deflate_state *s; - - if (strm == Z_NULL || strm->state == Z_NULL || - flush > Z_FINISH || flush < 0) { - return Z_STREAM_ERROR; - } - s = strm->state; - - if (strm->next_out == Z_NULL || - (strm->next_in == Z_NULL && strm->avail_in != 0) || - (s->status == FINISH_STATE && flush != Z_FINISH)) { - ERR_RETURN(strm, Z_STREAM_ERROR); - } - if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); - - s->strm = strm; /* just in case */ - old_flush = s->last_flush; - s->last_flush = flush; - - /* Write the header */ - if (s->status == INIT_STATE) { -#ifdef GZIP - if (s->wrap == 2) { - put_byte(s, 31); - put_byte(s, 139); - put_byte(s, 8); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, 255); - s->status = BUSY_STATE; - strm->adler = crc32(0L, Z_NULL, 0); - } - else -#endif - { - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; - uInt level_flags; - - if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) - level_flags = 0; - else if (s->level < 6) - level_flags = 1; - else if (s->level == 6) - level_flags = 2; - else - level_flags = 3; - header |= (level_flags << 6); - if (s->strstart != 0) header |= PRESET_DICT; - header += 31 - (header % 31); - - s->status = BUSY_STATE; - putShortMSB(s, header); - - /* Save the adler32 of the preset dictionary: */ - if (s->strstart != 0) { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - strm->adler = adler32(0L, Z_NULL, 0); - } - } - - /* Flush as much pending output as possible */ - if (s->pending != 0) { - flush_pending(strm); - if (strm->avail_out == 0) { - /* Since avail_out is 0, deflate will be called again with - * more output space, but possibly with both pending and - * avail_in equal to zero. There won't be anything to do, - * but this is not an error situation so make sure we - * return OK instead of BUF_ERROR at next call of deflate: - */ - s->last_flush = -1; - return Z_OK; - } - - /* Make sure there is something to do and avoid duplicate consecutive - * flushes. For repeated and useless calls with Z_FINISH, we keep - * returning Z_STREAM_END instead of Z_BUF_ERROR. - */ - } else if (strm->avail_in == 0 && flush <= old_flush && - flush != Z_FINISH) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* User must not provide more input after the first FINISH: */ - if (s->status == FINISH_STATE && strm->avail_in != 0) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* Start a new block or continue the current one. - */ - if (strm->avail_in != 0 || s->lookahead != 0 || - (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { - block_state bstate; - - bstate = (*(configuration_table[s->level].func))(s, flush); - - if (bstate == finish_started || bstate == finish_done) { - s->status = FINISH_STATE; - } - if (bstate == need_more || bstate == finish_started) { - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ - } - return Z_OK; - /* If flush != Z_NO_FLUSH && avail_out == 0, the next call - * of deflate should use the same flush parameter to make sure - * that the flush is complete. So we don't have to output an - * empty block here, this will be done at next call. This also - * ensures that for a very small output buffer, we emit at most - * one empty block. - */ - } - if (bstate == block_done) { - if (flush == Z_PARTIAL_FLUSH) { - _tr_align(s); - } else { /* FULL_FLUSH or SYNC_FLUSH */ - _tr_stored_block(s, (char*)0, 0L, 0); - /* For a full flush, this empty block will be recognized - * as a special marker by inflate_sync(). - */ - if (flush == Z_FULL_FLUSH) { - CLEAR_HASH(s); /* forget history */ - } - } - flush_pending(strm); - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ - return Z_OK; - } - } - } - Assert(strm->avail_out > 0, "bug2"); - - if (flush != Z_FINISH) return Z_OK; - if (s->wrap <= 0) return Z_STREAM_END; - - /* Write the trailer */ -#ifdef GZIP - if (s->wrap == 2) { - put_byte(s, (Byte)(strm->adler & 0xff)); - put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); - put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); - put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); - put_byte(s, (Byte)(strm->total_in & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); - } - else -#endif - { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - flush_pending(strm); - /* If avail_out is zero, the application will call deflate again - * to flush the rest. - */ - if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ - return s->pending != 0 ? Z_OK : Z_STREAM_END; -} - -/* ========================================================================= */ -int ZEXPORT deflateEnd (strm) - z_streamp strm; -{ - int status; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - - status = strm->state->status; - if (status != INIT_STATE && status != BUSY_STATE && - status != FINISH_STATE) { - return Z_STREAM_ERROR; - } - - /* Deallocate in reverse order of allocations: */ - TRY_FREE(strm, strm->state->pending_buf); - TRY_FREE(strm, strm->state->head); - TRY_FREE(strm, strm->state->prev); - TRY_FREE(strm, strm->state->window); - - ZFREE(strm, strm->state); - strm->state = Z_NULL; - - return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; -} - -/* ========================================================================= - * Copy the source state to the destination state. - * To simplify the source, this is not supported for 16-bit MSDOS (which - * doesn't have enough memory anyway to duplicate compression states). - */ -int ZEXPORT deflateCopy (dest, source) - z_streamp dest; - z_streamp source; -{ -#ifdef MAXSEG_64K - return Z_STREAM_ERROR; -#else - deflate_state *ds; - deflate_state *ss; - ushf *overlay; - - - if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { - return Z_STREAM_ERROR; - } - - ss = source->state; - - *dest = *source; - - ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); - if (ds == Z_NULL) return Z_MEM_ERROR; - dest->state = (struct internal_state FAR *) ds; - *ds = *ss; - ds->strm = dest; - - ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); - ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); - ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); - overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); - ds->pending_buf = (uchf *) overlay; - - if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || - ds->pending_buf == Z_NULL) { - deflateEnd (dest); - return Z_MEM_ERROR; - } - /* following zmemcpy do not work for 16-bit MSDOS */ - zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); - zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); - zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); - zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); - - ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); - ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); - ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; - - ds->l_desc.dyn_tree = ds->dyn_ltree; - ds->d_desc.dyn_tree = ds->dyn_dtree; - ds->bl_desc.dyn_tree = ds->bl_tree; - - return Z_OK; -#endif /* MAXSEG_64K */ -} - -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->next_in buffer and copying from it. - * (See also flush_pending()). - */ -local int read_buf(strm, buf, size) - z_streamp strm; - Bytef *buf; - unsigned size; -{ - unsigned len = strm->avail_in; - - if (len > size) len = size; - if (len == 0) return 0; - - strm->avail_in -= len; - - if (strm->state->wrap == 1) { - strm->adler = adler32(strm->adler, strm->next_in, len); - } -#ifdef GZIP - else if (strm->state->wrap == 2) { - strm->adler = crc32(strm->adler, strm->next_in, len); - } -#endif - zmemcpy(buf, strm->next_in, len); - strm->next_in += len; - strm->total_in += len; - - return (int)len; -} - -/* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ -local void lm_init (s) - deflate_state *s; -{ - s->window_size = (ulg)2L*s->w_size; - - CLEAR_HASH(s); - - /* Set the default configuration parameters: - */ - s->max_lazy_match = configuration_table[s->level].max_lazy; - s->good_match = configuration_table[s->level].good_length; - s->nice_match = configuration_table[s->level].nice_length; - s->max_chain_length = configuration_table[s->level].max_chain; - - s->strstart = 0; - s->block_start = 0L; - s->lookahead = 0; - s->match_length = s->prev_length = MIN_MATCH-1; - s->match_available = 0; - s->ins_h = 0; -#ifdef ASMV - match_init(); /* initialize the asm code */ -#endif -} - -#ifndef FASTEST -/* =========================================================================== - * Set match_start to the longest match starting at the given string and - * return its length. Matches shorter or equal to prev_length are discarded, - * in which case the result is equal to prev_length and match_start is - * garbage. - * IN assertions: cur_match is the head of the hash chain for the current - * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 - * OUT assertion: the match length is not greater than s->lookahead. - */ -#ifndef ASMV -/* For 80x86 and 680x0, an optimized version will be provided in match.asm or - * match.S. The code will be functionally equivalent. - */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - unsigned chain_length = s->max_chain_length;/* max hash chain length */ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - int best_len = s->prev_length; /* best match length so far */ - int nice_match = s->nice_match; /* stop if match long enough */ - IPos limit = s->strstart > (IPos)MAX_DIST(s) ? - s->strstart - (IPos)MAX_DIST(s) : NIL; - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0. - */ - Posf *prev = s->prev; - uInt wmask = s->w_mask; - -#ifdef UNALIGNED_OK - /* Compare two bytes at a time. Note: this is not always beneficial. - * Try with and without -DUNALIGNED_OK to check. - */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; - register ush scan_start = *(ushf*)scan; - register ush scan_end = *(ushf*)(scan+best_len-1); -#else - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - register Byte scan_end1 = scan[best_len-1]; - register Byte scan_end = scan[best_len]; -#endif - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - /* Do not waste too much time if we already have a good match: */ - if (s->prev_length >= s->good_match) { - chain_length >>= 2; - } - /* Do not look for matches beyond the end of the input. This is necessary - * to make deflate deterministic. - */ - if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - do { - Assert(cur_match < s->strstart, "no future"); - match = s->window + cur_match; - - /* Skip to next match if the match length cannot increase - * or if the match length is less than 2: - */ -#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) - /* This code assumes sizeof(unsigned short) == 2. Do not use - * UNALIGNED_OK if your compiler uses a different size. - */ - if (*(ushf*)(match+best_len-1) != scan_end || - *(ushf*)match != scan_start) continue; - - /* It is not necessary to compare scan[2] and match[2] since they are - * always equal when the other bytes match, given that the hash keys - * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at - * strstart+3, +5, ... up to strstart+257. We check for insufficient - * lookahead only every 4th comparison; the 128th check will be made - * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is - * necessary to put more guard bytes at the end of the window, or - * to check more often for insufficient lookahead. - */ - Assert(scan[2] == match[2], "scan[2]?"); - scan++, match++; - do { - } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - scan < strend); - /* The funny "do {}" generates better code on most compilers */ - - /* Here, scan <= window+strstart+257 */ - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - if (*scan == *match) scan++; - - len = (MAX_MATCH - 1) - (int)(strend-scan); - scan = strend - (MAX_MATCH-1); - -#else /* UNALIGNED_OK */ - - if (match[best_len] != scan_end || - match[best_len-1] != scan_end1 || - *match != *scan || - *++match != scan[1]) continue; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match++; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - scan = strend - MAX_MATCH; - -#endif /* UNALIGNED_OK */ - - if (len > best_len) { - s->match_start = cur_match; - best_len = len; - if (len >= nice_match) break; -#ifdef UNALIGNED_OK - scan_end = *(ushf*)(scan+best_len-1); -#else - scan_end1 = scan[best_len-1]; - scan_end = scan[best_len]; -#endif - } - } while ((cur_match = prev[cur_match & wmask]) > limit - && --chain_length != 0); - - if ((uInt)best_len <= s->lookahead) return (uInt)best_len; - return s->lookahead; -} -#endif /* ASMV */ -#endif /* FASTEST */ - -/* --------------------------------------------------------------------------- - * Optimized version for level == 1 or strategy == Z_RLE only - */ -local uInt longest_match_fast(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - Assert(cur_match < s->strstart, "no future"); - - match = s->window + cur_match; - - /* Return failure if the match length is less than 2: - */ - if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match += 2; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - - if (len < MIN_MATCH) return MIN_MATCH - 1; - - s->match_start = cur_match; - return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; -} - -#ifdef DEBUG -/* =========================================================================== - * Check that the match at match_start is indeed a match. - */ -local void check_match(s, start, match, length) - deflate_state *s; - IPos start, match; - int length; -{ - /* check that the match is indeed a match */ - if (zmemcmp(s->window + match, - s->window + start, length) != EQUAL) { - fprintf(stderr, " start %u, match %u, length %d\n", - start, match, length); - do { - fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); - } while (--length != 0); - z_error("invalid match"); - } - if (z_verbose > 1) { - fprintf(stderr,"\\[%d,%d]", start-match, length); - do { putc(s->window[start++], stderr); } while (--length != 0); - } -} -#else -# define check_match(s, start, match, length) -#endif /* DEBUG */ - -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ -local void fill_window(s) - deflate_state *s; -{ - register unsigned n, m; - register Posf *p; - unsigned more; /* Amount of free space at the end of the window. */ - uInt wsize = s->w_size; - - do { - more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); - - /* Deal with !@#$% 64K limit: */ - if (sizeof(int) <= 2) { - if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - more = wsize; - - } else if (more == (unsigned)(-1)) { - /* Very unlikely, but possible on 16 bit machine if - * strstart == 0 && lookahead == 1 (input done a byte at time) - */ - more--; - } - } - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (s->strstart >= wsize+MAX_DIST(s)) { - - zmemcpy(s->window, s->window+wsize, (unsigned)wsize); - s->match_start -= wsize; - s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ - s->block_start -= (long) wsize; - - /* Slide the hash table (could be avoided with 32 bit values - at the expense of memory usage). We slide even when level == 0 - to keep the hash table consistent if we switch back to level > 0 - later. (Using level 0 permanently is not an optimal usage of - zlib, so we don't care about this pathological case.) - */ - n = s->hash_size; - p = &s->head[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - } while (--n); - - n = wsize; -#ifndef FASTEST - p = &s->prev[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); -#endif - more += wsize; - } - if (s->strm->avail_in == 0) return; - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - Assert(more >= 2, "more < 2"); - - n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); - s->lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s->lookahead >= MIN_MATCH) { - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ - - } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); -} - -/* =========================================================================== - * Flush the current block, with given end-of-file flag. - * IN assertion: strstart is set to the end of the current match. - */ -#define FLUSH_BLOCK_ONLY(s, eof) { \ - _tr_flush_block(s, (s->block_start >= 0L ? \ - (charf *)&s->window[(unsigned)s->block_start] : \ - (charf *)Z_NULL), \ - (ulg)((long)s->strstart - s->block_start), \ - (eof)); \ - s->block_start = s->strstart; \ - flush_pending(s->strm); \ - Tracev((stderr,"[FLUSH]")); \ -} - -/* Same but force premature exit if necessary. */ -#define FLUSH_BLOCK(s, eof) { \ - FLUSH_BLOCK_ONLY(s, eof); \ - if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ -} - -/* =========================================================================== - * Copy without compression as much as possible from the input stream, return - * the current block state. - * This function does not insert new strings in the dictionary since - * uncompressible data is probably not useful. This function is used - * only for the level=0 compression option. - * NOTE: this function should be optimized to avoid extra copying from - * window to pending_buf. - */ -local block_state deflate_stored(s, flush) - deflate_state *s; - int flush; -{ - /* Stored blocks are limited to 0xffff bytes, pending_buf is limited - * to pending_buf_size, and each stored block has a 5 byte header: - */ - ulg max_block_size = 0xffff; - ulg max_start; - - if (max_block_size > s->pending_buf_size - 5) { - max_block_size = s->pending_buf_size - 5; - } - - /* Copy as much as possible from input to output: */ - for (;;) { - /* Fill the window as much as possible: */ - if (s->lookahead <= 1) { - - Assert(s->strstart < s->w_size+MAX_DIST(s) || - s->block_start >= (long)s->w_size, "slide too late"); - - fill_window(s); - if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; - - if (s->lookahead == 0) break; /* flush the current block */ - } - Assert(s->block_start >= 0L, "block gone"); - - s->strstart += s->lookahead; - s->lookahead = 0; - - /* Emit a stored block if pending_buf will be full: */ - max_start = s->block_start + max_block_size; - if (s->strstart == 0 || (ulg)s->strstart >= max_start) { - /* strstart == 0 is possible when wraparound on 16-bit machine */ - s->lookahead = (uInt)(s->strstart - max_start); - s->strstart = (uInt)max_start; - FLUSH_BLOCK(s, 0); - } - /* Flush if we may have to slide, otherwise block_start may become - * negative and the data will be gone: - */ - if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { - FLUSH_BLOCK(s, 0); - } - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} - -/* =========================================================================== - * Compress as much as possible from the input stream, return the current - * block state. - * This function does not perform lazy evaluation of matches and inserts - * new strings in the dictionary only for unmatched strings or for short - * matches. It is used only for the fast compression options. - */ -local block_state deflate_fast(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head = NIL; /* head of the hash chain */ - int bflush; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - * At this point we have always match_length < MIN_MATCH - */ - if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ -#ifdef FASTEST - if ((s->strategy < Z_HUFFMAN_ONLY) || - (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { - s->match_length = longest_match_fast (s, hash_head); - } -#else - if (s->strategy < Z_HUFFMAN_ONLY) { - s->match_length = longest_match (s, hash_head); - } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { - s->match_length = longest_match_fast (s, hash_head); - } -#endif - /* longest_match() or longest_match_fast() sets match_start */ - } - if (s->match_length >= MIN_MATCH) { - check_match(s, s->strstart, s->match_start, s->match_length); - - _tr_tally_dist(s, s->strstart - s->match_start, - s->match_length - MIN_MATCH, bflush); - - s->lookahead -= s->match_length; - - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ -#ifndef FASTEST - if (s->match_length <= s->max_insert_length && - s->lookahead >= MIN_MATCH) { - s->match_length--; /* string at strstart already in table */ - do { - s->strstart++; - INSERT_STRING(s, s->strstart, hash_head); - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. - */ - } while (--s->match_length != 0); - s->strstart++; - } else -#endif - { - s->strstart += s->match_length; - s->match_length = 0; - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not - * matter since it will be recomputed at next deflate call. - */ - } - } else { - /* No match, output a literal byte */ - Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - } - if (bflush) FLUSH_BLOCK(s, 0); - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} - -#ifndef FASTEST -/* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ -local block_state deflate_slow(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head = NIL; /* head of hash chain */ - int bflush; /* set if current block must be flushed */ - - /* Process the input block. */ - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - */ - s->prev_length = s->match_length, s->prev_match = s->match_start; - s->match_length = MIN_MATCH-1; - - if (hash_head != NIL && s->prev_length < s->max_lazy_match && - s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - if (s->strategy < Z_HUFFMAN_ONLY) { - s->match_length = longest_match (s, hash_head); - } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { - s->match_length = longest_match_fast (s, hash_head); - } - /* longest_match() or longest_match_fast() sets match_start */ - - if (s->match_length <= 5 && (s->strategy == Z_FILTERED -#if TOO_FAR <= 32767 - || (s->match_length == MIN_MATCH && - s->strstart - s->match_start > TOO_FAR) -#endif - )) { - - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - s->match_length = MIN_MATCH-1; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { - uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; - /* Do not insert strings in hash table beyond this. */ - - check_match(s, s->strstart-1, s->prev_match, s->prev_length); - - _tr_tally_dist(s, s->strstart -1 - s->prev_match, - s->prev_length - MIN_MATCH, bflush); - - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not - * enough lookahead, the last two strings are not inserted in - * the hash table. - */ - s->lookahead -= s->prev_length-1; - s->prev_length -= 2; - do { - if (++s->strstart <= max_insert) { - INSERT_STRING(s, s->strstart, hash_head); - } - } while (--s->prev_length != 0); - s->match_available = 0; - s->match_length = MIN_MATCH-1; - s->strstart++; - - if (bflush) FLUSH_BLOCK(s, 0); - - } else if (s->match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - if (bflush) { - FLUSH_BLOCK_ONLY(s, 0); - } - s->strstart++; - s->lookahead--; - if (s->strm->avail_out == 0) return need_more; - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - s->match_available = 1; - s->strstart++; - s->lookahead--; - } - } - Assert (flush != Z_NO_FLUSH, "no flush?"); - if (s->match_available) { - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - s->match_available = 0; - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} -#endif /* FASTEST */ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id: deflate.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.1 Copyright 1995-2003 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_RLE) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); +#ifndef USE_DICT_HEAD + dictionary += dictLength - length; /* use the tail of the dictionary */ +#endif + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_RLE) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, 255); + s->status = BUSY_STATE; + strm->adler = crc32(0L, Z_NULL, 0); + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + *dest = *source; + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + *ds = *ss; + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy < Z_HUFFMAN_ONLY) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy < Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy < Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ diff --git a/plugins/zerogs/opengl/Win32/zlib/deflate.h b/plugins/zerogs/opengl/Win32/zlib/deflate.h index 26775e9d12..08aa37c792 100644 --- a/plugins/zerogs/opengl/Win32/zlib/deflate.h +++ b/plugins/zerogs/opengl/Win32/zlib/deflate.h @@ -1,326 +1,326 @@ -/* deflate.h -- internal compression state - * Copyright (C) 1995-2002 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id: deflate.h,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ - -#ifndef DEFLATE_H -#define DEFLATE_H - -#include "zutil.h" - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer creation by deflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip encoding - should be left enabled. */ -#ifndef NO_GZIP -# define GZIP -#endif - -/* =========================================================================== - * Internal compression state. - */ - -#define LENGTH_CODES 29 -/* number of length codes, not counting the special END_BLOCK code */ - -#define LITERALS 256 -/* number of literal bytes 0..255 */ - -#define L_CODES (LITERALS+1+LENGTH_CODES) -/* number of Literal or Length codes, including the END_BLOCK code */ - -#define D_CODES 30 -/* number of distance codes */ - -#define BL_CODES 19 -/* number of codes used to transfer the bit lengths */ - -#define HEAP_SIZE (2*L_CODES+1) -/* maximum heap size */ - -#define MAX_BITS 15 -/* All codes must not exceed MAX_BITS bits */ - -#define INIT_STATE 42 -#define BUSY_STATE 113 -#define FINISH_STATE 666 -/* Stream status */ - - -/* Data structure describing a single value and its code string. */ -typedef struct ct_data_s { - union { - ush freq; /* frequency count */ - ush code; /* bit string */ - } fc; - union { - ush dad; /* father node in Huffman tree */ - ush len; /* length of bit string */ - } dl; -} FAR ct_data; - -#define Freq fc.freq -#define Code fc.code -#define Dad dl.dad -#define Len dl.len - -typedef struct static_tree_desc_s static_tree_desc; - -typedef struct tree_desc_s { - ct_data *dyn_tree; /* the dynamic tree */ - int max_code; /* largest code with non zero frequency */ - static_tree_desc *stat_desc; /* the corresponding static tree */ -} FAR tree_desc; - -typedef ush Pos; -typedef Pos FAR Posf; -typedef unsigned IPos; - -/* A Pos is an index in the character window. We use short instead of int to - * save space in the various tables. IPos is used only for parameter passing. - */ - -typedef struct internal_state { - z_streamp strm; /* pointer back to this zlib stream */ - int status; /* as the name implies */ - Bytef *pending_buf; /* output still pending */ - ulg pending_buf_size; /* size of pending_buf */ - Bytef *pending_out; /* next pending byte to output to the stream */ - int pending; /* nb of bytes in the pending buffer */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - Byte data_type; /* UNKNOWN, BINARY or ASCII */ - Byte method; /* STORED (for zip only) or DEFLATED */ - int last_flush; /* value of flush param for previous deflate call */ - - /* used by deflate.c: */ - - uInt w_size; /* LZ77 window size (32K by default) */ - uInt w_bits; /* log2(w_size) (8..16) */ - uInt w_mask; /* w_size - 1 */ - - Bytef *window; - /* Sliding window. Input bytes are read into the second half of the window, - * and move to the first half later to keep a dictionary of at least wSize - * bytes. With this organization, matches are limited to a distance of - * wSize-MAX_MATCH bytes, but this ensures that IO is always - * performed with a length multiple of the block size. Also, it limits - * the window size to 64K, which is quite useful on MSDOS. - * To do: use the user input buffer as sliding window. - */ - - ulg window_size; - /* Actual size of window: 2*wSize, except when the user input buffer - * is directly used as sliding window. - */ - - Posf *prev; - /* Link to older string with same hash index. To limit the size of this - * array to 64K, this link is maintained only for the last 32K strings. - * An index in this array is thus a window index modulo 32K. - */ - - Posf *head; /* Heads of the hash chains or NIL. */ - - uInt ins_h; /* hash index of string to be inserted */ - uInt hash_size; /* number of elements in hash table */ - uInt hash_bits; /* log2(hash_size) */ - uInt hash_mask; /* hash_size-1 */ - - uInt hash_shift; - /* Number of bits by which ins_h must be shifted at each input - * step. It must be such that after MIN_MATCH steps, the oldest - * byte no longer takes part in the hash key, that is: - * hash_shift * MIN_MATCH >= hash_bits - */ - - long block_start; - /* Window position at the beginning of the current output block. Gets - * negative when the window is moved backwards. - */ - - uInt match_length; /* length of best match */ - IPos prev_match; /* previous match */ - int match_available; /* set if previous match exists */ - uInt strstart; /* start of string to insert */ - uInt match_start; /* start of matching string */ - uInt lookahead; /* number of valid bytes ahead in window */ - - uInt prev_length; - /* Length of the best match at previous step. Matches not greater than this - * are discarded. This is used in the lazy match evaluation. - */ - - uInt max_chain_length; - /* To speed up deflation, hash chains are never searched beyond this - * length. A higher limit improves compression ratio but degrades the - * speed. - */ - - uInt max_lazy_match; - /* Attempt to find a better match only when the current match is strictly - * smaller than this value. This mechanism is used only for compression - * levels >= 4. - */ -# define max_insert_length max_lazy_match - /* Insert new strings in the hash table only if the match length is not - * greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 3. - */ - - int level; /* compression level (1..9) */ - int strategy; /* favor or force Huffman coding*/ - - uInt good_match; - /* Use a faster search when the previous match is longer than this */ - - int nice_match; /* Stop searching when current match exceeds this */ - - /* used by trees.c: */ - /* Didn't use ct_data typedef below to supress compiler warning */ - struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ - struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ - struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ - - struct tree_desc_s l_desc; /* desc. for literal tree */ - struct tree_desc_s d_desc; /* desc. for distance tree */ - struct tree_desc_s bl_desc; /* desc. for bit length tree */ - - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ - int heap_len; /* number of elements in the heap */ - int heap_max; /* element of largest frequency */ - /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - * The same heap array is used to build all trees. - */ - - uch depth[2*L_CODES+1]; - /* Depth of each subtree used as tie breaker for trees of equal frequency - */ - - uchf *l_buf; /* buffer for literals or lengths */ - - uInt lit_bufsize; - /* Size of match buffer for literals/lengths. There are 4 reasons for - * limiting lit_bufsize to 64K: - * - frequencies can be kept in 16 bit counters - * - if compression is not successful for the first block, all input - * data is still in the window so we can still emit a stored block even - * when input comes from standard input. (This can also be done for - * all blocks if lit_bufsize is not greater than 32K.) - * - if compression is not successful for a file smaller than 64K, we can - * even emit a stored file instead of a stored block (saving 5 bytes). - * This is applicable only for zip (not gzip or zlib). - * - creating new Huffman trees less frequently may not provide fast - * adaptation to changes in the input data statistics. (Take for - * example a binary file with poorly compressible code followed by - * a highly compressible string table.) Smaller buffer sizes give - * fast adaptation but have of course the overhead of transmitting - * trees more frequently. - * - I can't count above 4 - */ - - uInt last_lit; /* running index in l_buf */ - - ushf *d_buf; - /* Buffer for distances. To simplify the code, d_buf and l_buf have - * the same number of elements. To use different lengths, an extra flag - * array would be necessary. - */ - - ulg opt_len; /* bit length of current block with optimal trees */ - ulg static_len; /* bit length of current block with static trees */ - uInt matches; /* number of string matches in current block */ - int last_eob_len; /* bit length of EOB code for last block */ - -#ifdef DEBUG - ulg compressed_len; /* total bit length of compressed file mod 2^32 */ - ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ -#endif - - ush bi_buf; - /* Output buffer. bits are inserted starting at the bottom (least - * significant bits). - */ - int bi_valid; - /* Number of valid bits in bi_buf. All bits above the last valid bit - * are always zero. - */ - -} FAR deflate_state; - -/* Output a byte on the stream. - * IN assertion: there is enough room in pending_buf. - */ -#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} - - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) -/* In order to simplify the code, particularly on 16 bit machines, match - * distances are limited to MAX_DIST instead of WSIZE. - */ - - /* in trees.c */ -void _tr_init OF((deflate_state *s)); -int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); -void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); -void _tr_align OF((deflate_state *s)); -void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); - -#define d_code(dist) \ - ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) -/* Mapping from a distance to a distance code. dist is the distance - 1 and - * must not have side effects. _dist_code[256] and _dist_code[257] are never - * used. - */ - -#ifndef DEBUG -/* Inline versions of _tr_tally for speed: */ - -#if defined(GEN_TREES_H) || !defined(STDC) - extern uch _length_code[]; - extern uch _dist_code[]; -#else - extern const uch _length_code[]; - extern const uch _dist_code[]; -#endif - -# define _tr_tally_lit(s, c, flush) \ - { uch cc = (c); \ - s->d_buf[s->last_lit] = 0; \ - s->l_buf[s->last_lit++] = cc; \ - s->dyn_ltree[cc].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -# define _tr_tally_dist(s, distance, length, flush) \ - { uch len = (length); \ - ush dist = (distance); \ - s->d_buf[s->last_lit] = dist; \ - s->l_buf[s->last_lit++] = len; \ - dist--; \ - s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ - s->dyn_dtree[d_code(dist)].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -#else -# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) -# define _tr_tally_dist(s, distance, length, flush) \ - flush = _tr_tally(s, distance, length) -#endif - -#endif /* DEFLATE_H */ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2002 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: deflate.h,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + int pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + Byte data_type; /* UNKNOWN, BINARY or ASCII */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/plugins/zerogs/opengl/Win32/zlib/gzio.c b/plugins/zerogs/opengl/Win32/zlib/gzio.c index 4cfd64fc45..89d40993f5 100644 --- a/plugins/zerogs/opengl/Win32/zlib/gzio.c +++ b/plugins/zerogs/opengl/Win32/zlib/gzio.c @@ -1,1005 +1,1005 @@ -/* gzio.c -- IO on .gz files - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. - */ - -/* @(#) $Id: gzio.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ - -#include - -#include "zutil.h" - -#ifdef NO_DEFLATE /* for compatiblity with old definition */ -# define NO_GZCOMPRESS -#endif - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -#ifndef Z_BUFSIZE -# ifdef MAXSEG_64K -# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ -# else -# define Z_BUFSIZE 16384 -# endif -#endif -#ifndef Z_PRINTF_BUFSIZE -# define Z_PRINTF_BUFSIZE 4096 -#endif - -#ifdef __MVS__ -# pragma map (fdopen , "\174\174FDOPEN") - FILE *fdopen(int, const char *); -#endif - -#ifndef STDC -extern voidp malloc OF((uInt size)); -extern void free OF((voidpf ptr)); -#endif - -#define ALLOC(size) malloc(size) -#define TRYFREE(p) {if (p) free(p);} - -static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ - -/* gzip flag byte */ -#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ -#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ -#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ -#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ -#define COMMENT 0x10 /* bit 4 set: file comment present */ -#define RESERVED 0xE0 /* bits 5..7: reserved */ - -typedef struct gz_stream { - z_stream stream; - int z_err; /* error code for last stream operation */ - int z_eof; /* set if end of input file */ - FILE *file; /* .gz file */ - Byte *inbuf; /* input buffer */ - Byte *outbuf; /* output buffer */ - uLong crc; /* crc32 of uncompressed data */ - char *msg; /* error message */ - char *path; /* path name for debugging only */ - int transparent; /* 1 if input file is not a .gz file */ - char mode; /* 'w' or 'r' */ - z_off_t start; /* start of compressed data in file (header skipped) */ - z_off_t in; /* bytes into deflate or inflate */ - z_off_t out; /* bytes out of deflate or inflate */ - int back; /* one character push-back */ - int last; /* true if push-back is last character */ -} gz_stream; - - -local gzFile gz_open OF((const char *path, const char *mode, int fd)); -local int do_flush OF((gzFile file, int flush)); -local int get_byte OF((gz_stream *s)); -local void check_header OF((gz_stream *s)); -local int destroy OF((gz_stream *s)); -local void putLong OF((FILE *file, uLong x)); -local uLong getLong OF((gz_stream *s)); - -/* =========================================================================== - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb"). The file is given either by file descriptor - or path name (if fd == -1). - gz_open returns NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). -*/ -local gzFile gz_open (path, mode, fd) - const char *path; - const char *mode; - int fd; -{ - int err; - int level = Z_DEFAULT_COMPRESSION; /* compression level */ - int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ - char *p = (char*)mode; - gz_stream *s; - char fmode[80]; /* copy of mode, without the compression level */ - char *m = fmode; - - if (!path || !mode) return Z_NULL; - - s = (gz_stream *)ALLOC(sizeof(gz_stream)); - if (!s) return Z_NULL; - - s->stream.zalloc = (alloc_func)0; - s->stream.zfree = (free_func)0; - s->stream.opaque = (voidpf)0; - s->stream.next_in = s->inbuf = Z_NULL; - s->stream.next_out = s->outbuf = Z_NULL; - s->stream.avail_in = s->stream.avail_out = 0; - s->file = NULL; - s->z_err = Z_OK; - s->z_eof = 0; - s->in = 0; - s->out = 0; - s->back = EOF; - s->crc = crc32(0L, Z_NULL, 0); - s->msg = NULL; - s->transparent = 0; - - s->path = (char*)ALLOC(strlen(path)+1); - if (s->path == NULL) { - return destroy(s), (gzFile)Z_NULL; - } - strcpy(s->path, path); /* do this early for debugging */ - - s->mode = '\0'; - do { - if (*p == 'r') s->mode = 'r'; - if (*p == 'w' || *p == 'a') s->mode = 'w'; - if (*p >= '0' && *p <= '9') { - level = *p - '0'; - } else if (*p == 'f') { - strategy = Z_FILTERED; - } else if (*p == 'h') { - strategy = Z_HUFFMAN_ONLY; - } else if (*p == 'R') { - strategy = Z_RLE; - } else { - *m++ = *p; /* copy the mode */ - } - } while (*p++ && m != fmode + sizeof(fmode)); - if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - err = Z_STREAM_ERROR; -#else - err = deflateInit2(&(s->stream), level, - Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); - /* windowBits is passed < 0 to suppress zlib header */ - - s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); -#endif - if (err != Z_OK || s->outbuf == Z_NULL) { - return destroy(s), (gzFile)Z_NULL; - } - } else { - s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); - - err = inflateInit2(&(s->stream), -MAX_WBITS); - /* windowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are - * present after the compressed stream. - */ - if (err != Z_OK || s->inbuf == Z_NULL) { - return destroy(s), (gzFile)Z_NULL; - } - } - s->stream.avail_out = Z_BUFSIZE; - - errno = 0; - s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); - - if (s->file == NULL) { - return destroy(s), (gzFile)Z_NULL; - } - if (s->mode == 'w') { - /* Write a very simple .gz header: - */ - fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], - Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); - s->start = 10L; - /* We use 10L instead of ftell(s->file) to because ftell causes an - * fflush on some systems. This version of the library doesn't use - * start anyway in write mode, so this initialization is not - * necessary. - */ - } else { - check_header(s); /* skip the .gz header */ - s->start = ftell(s->file) - s->stream.avail_in; - } - - return (gzFile)s; -} - -/* =========================================================================== - Opens a gzip (.gz) file for reading or writing. -*/ -gzFile ZEXPORT gzopen (path, mode) - const char *path; - const char *mode; -{ - return gz_open (path, mode, -1); -} - -/* =========================================================================== - Associate a gzFile with the file descriptor fd. fd is not dup'ed here - to mimic the behavio(u)r of fdopen. -*/ -gzFile ZEXPORT gzdopen (fd, mode) - int fd; - const char *mode; -{ - char name[20]; - - if (fd < 0) return (gzFile)Z_NULL; - sprintf(name, "", fd); /* for debugging */ - - return gz_open (name, mode, fd); -} - -/* =========================================================================== - * Update the compression level and strategy - */ -int ZEXPORT gzsetparams (file, level, strategy) - gzFile file; - int level; - int strategy; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - /* Make room to allow flushing */ - if (s->stream.avail_out == 0) { - - s->stream.next_out = s->outbuf; - if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { - s->z_err = Z_ERRNO; - } - s->stream.avail_out = Z_BUFSIZE; - } - - return deflateParams (&(s->stream), level, strategy); -} - -/* =========================================================================== - Read a byte from a gz_stream; update next_in and avail_in. Return EOF - for end of file. - IN assertion: the stream s has been sucessfully opened for reading. -*/ -local int get_byte(s) - gz_stream *s; -{ - if (s->z_eof) return EOF; - if (s->stream.avail_in == 0) { - errno = 0; - s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); - if (s->stream.avail_in == 0) { - s->z_eof = 1; - if (ferror(s->file)) s->z_err = Z_ERRNO; - return EOF; - } - s->stream.next_in = s->inbuf; - } - s->stream.avail_in--; - return *(s->stream.next_in)++; -} - -/* =========================================================================== - Check the gzip header of a gz_stream opened for reading. Set the stream - mode to transparent if the gzip magic header is not present; set s->err - to Z_DATA_ERROR if the magic header is present but the rest of the header - is incorrect. - IN assertion: the stream s has already been created sucessfully; - s->stream.avail_in is zero for the first time, but may be non-zero - for concatenated .gz files. -*/ -local void check_header(s) - gz_stream *s; -{ - int method; /* method byte */ - int flags; /* flags byte */ - uInt len; - int c; - - /* Assure two bytes in the buffer so we can peek ahead -- handle case - where first byte of header is at the end of the buffer after the last - gzip segment */ - len = s->stream.avail_in; - if (len < 2) { - if (len) s->inbuf[0] = s->stream.next_in[0]; - errno = 0; - len = fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); - if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; - s->stream.avail_in += len; - s->stream.next_in = s->inbuf; - if (s->stream.avail_in < 2) { - s->transparent = s->stream.avail_in; - return; - } - } - - /* Peek ahead to check the gzip magic header */ - if (s->stream.next_in[0] != gz_magic[0] || - s->stream.next_in[1] != gz_magic[1]) { - s->transparent = 1; - return; - } - s->stream.avail_in -= 2; - s->stream.next_in += 2; - - /* Check the rest of the gzip header */ - method = get_byte(s); - flags = get_byte(s); - if (method != Z_DEFLATED || (flags & RESERVED) != 0) { - s->z_err = Z_DATA_ERROR; - return; - } - - /* Discard time, xflags and OS code: */ - for (len = 0; len < 6; len++) (void)get_byte(s); - - if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ - len = (uInt)get_byte(s); - len += ((uInt)get_byte(s))<<8; - /* len is garbage if EOF but the loop below will quit anyway */ - while (len-- != 0 && get_byte(s) != EOF) ; - } - if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ - while ((c = get_byte(s)) != 0 && c != EOF) ; - } - if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ - while ((c = get_byte(s)) != 0 && c != EOF) ; - } - if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ - for (len = 0; len < 2; len++) (void)get_byte(s); - } - s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; -} - - /* =========================================================================== - * Cleanup then free the given gz_stream. Return a zlib error code. - Try freeing in the reverse order of allocations. - */ -local int destroy (s) - gz_stream *s; -{ - int err = Z_OK; - - if (!s) return Z_STREAM_ERROR; - - TRYFREE(s->msg); - - if (s->stream.state != NULL) { - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - err = Z_STREAM_ERROR; -#else - err = deflateEnd(&(s->stream)); -#endif - } else if (s->mode == 'r') { - err = inflateEnd(&(s->stream)); - } - } - if (s->file != NULL && fclose(s->file)) { -#ifdef ESPIPE - if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ -#endif - err = Z_ERRNO; - } - if (s->z_err < 0) err = s->z_err; - - TRYFREE(s->inbuf); - TRYFREE(s->outbuf); - TRYFREE(s->path); - TRYFREE(s); - return err; -} - -/* =========================================================================== - Reads the given number of uncompressed bytes from the compressed file. - gzread returns the number of bytes actually read (0 for end of file). -*/ -int ZEXPORT gzread (file, buf, len) - gzFile file; - voidp buf; - unsigned len; -{ - gz_stream *s = (gz_stream*)file; - Bytef *start = (Bytef*)buf; /* starting point for crc computation */ - Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ - - if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; - - if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; - if (s->z_err == Z_STREAM_END) return 0; /* EOF */ - - next_out = (Byte*)buf; - s->stream.next_out = (Bytef*)buf; - s->stream.avail_out = len; - - if (s->stream.avail_out && s->back != EOF) { - *next_out++ = s->back; - s->stream.next_out++; - s->stream.avail_out--; - s->back = EOF; - s->out++; - if (s->last) { - s->z_err = Z_STREAM_END; - return 1; - } - } - - while (s->stream.avail_out != 0) { - - if (s->transparent) { - /* Copy first the lookahead bytes: */ - uInt n = s->stream.avail_in; - if (n > s->stream.avail_out) n = s->stream.avail_out; - if (n > 0) { - zmemcpy(s->stream.next_out, s->stream.next_in, n); - next_out += n; - s->stream.next_out = next_out; - s->stream.next_in += n; - s->stream.avail_out -= n; - s->stream.avail_in -= n; - } - if (s->stream.avail_out > 0) { - s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, - s->file); - } - len -= s->stream.avail_out; - s->in += len; - s->out += len; - if (len == 0) s->z_eof = 1; - return (int)len; - } - if (s->stream.avail_in == 0 && !s->z_eof) { - - errno = 0; - s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); - if (s->stream.avail_in == 0) { - s->z_eof = 1; - if (ferror(s->file)) { - s->z_err = Z_ERRNO; - break; - } - } - s->stream.next_in = s->inbuf; - } - s->in += s->stream.avail_in; - s->out += s->stream.avail_out; - s->z_err = inflate(&(s->stream), Z_NO_FLUSH); - s->in -= s->stream.avail_in; - s->out -= s->stream.avail_out; - - if (s->z_err == Z_STREAM_END) { - /* Check CRC and original size */ - s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); - start = s->stream.next_out; - - if (getLong(s) != s->crc) { - s->z_err = Z_DATA_ERROR; - } else { - (void)getLong(s); - /* The uncompressed length returned by above getlong() may be - * different from s->out in case of concatenated .gz files. - * Check for such files: - */ - check_header(s); - if (s->z_err == Z_OK) { - inflateReset(&(s->stream)); - s->crc = crc32(0L, Z_NULL, 0); - } - } - } - if (s->z_err != Z_OK || s->z_eof) break; - } - s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); - - return (int)(len - s->stream.avail_out); -} - - -/* =========================================================================== - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. -*/ -int ZEXPORT gzgetc(file) - gzFile file; -{ - unsigned char c; - - return gzread(file, &c, 1) == 1 ? c : -1; -} - - -/* =========================================================================== - Push one byte back onto the stream. -*/ -int ZEXPORT gzungetc(c, file) - int c; - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; - s->back = c; - s->out--; - s->last = (s->z_err == Z_STREAM_END); - if (s->last) s->z_err = Z_OK; - s->z_eof = 0; - return c; -} - - -/* =========================================================================== - Reads bytes from the compressed file until len-1 characters are - read, or a newline character is read and transferred to buf, or an - end-of-file condition is encountered. The string is then terminated - with a null character. - gzgets returns buf, or Z_NULL in case of error. - - The current implementation is not optimized at all. -*/ -char * ZEXPORT gzgets(file, buf, len) - gzFile file; - char *buf; - int len; -{ - char *b = buf; - if (buf == Z_NULL || len <= 0) return Z_NULL; - - while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; - *buf = '\0'; - return b == buf && len > 0 ? Z_NULL : b; -} - - -#ifndef NO_GZCOMPRESS -/* =========================================================================== - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of bytes actually written (0 in case of error). -*/ -int ZEXPORT gzwrite (file, buf, len) - gzFile file; - voidpc buf; - unsigned len; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - s->stream.next_in = (Bytef*)buf; - s->stream.avail_in = len; - - while (s->stream.avail_in != 0) { - - if (s->stream.avail_out == 0) { - - s->stream.next_out = s->outbuf; - if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { - s->z_err = Z_ERRNO; - break; - } - s->stream.avail_out = Z_BUFSIZE; - } - s->in += s->stream.avail_in; - s->out += s->stream.avail_out; - s->z_err = deflate(&(s->stream), Z_NO_FLUSH); - s->in -= s->stream.avail_in; - s->out -= s->stream.avail_out; - if (s->z_err != Z_OK) break; - } - s->crc = crc32(s->crc, (const Bytef *)buf, len); - - return (int)(len - s->stream.avail_in); -} - - -/* =========================================================================== - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). -*/ -#ifdef STDC -#include - -int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) -{ - char buf[Z_PRINTF_BUFSIZE]; - va_list va; - int len; - - buf[sizeof(buf) - 1] = 0; - va_start(va, format); -#ifdef NO_vsnprintf -# ifdef HAS_vsprintf_void - (void)vsprintf(buf, format, va); - va_end(va); - for (len = 0; len < sizeof(buf); len++) - if (buf[len] == 0) break; -# else - len = vsprintf(buf, format, va); - va_end(va); -# endif -#else -# ifdef HAS_vsnprintf_void - (void)vsnprintf(buf, sizeof(buf), format, va); - va_end(va); - len = strlen(buf); -# else - len = vsnprintf(buf, sizeof(buf), format, va); - va_end(va); -# endif -#endif - if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) - return 0; - return gzwrite(file, buf, (unsigned)len); -} -#else /* not ANSI C */ - -int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) - gzFile file; - const char *format; - int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; -{ - char buf[Z_PRINTF_BUFSIZE]; - int len; - - buf[sizeof(buf) - 1] = 0; -#ifdef NO_snprintf -# ifdef HAS_sprintf_void - sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); - for (len = 0; len < sizeof(buf); len++) - if (buf[len] == 0) break; -# else - len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); -# endif -#else -# ifdef HAS_snprintf_void - snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); - len = strlen(buf); -# else - len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); -# endif -#endif - if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) - return 0; - return gzwrite(file, buf, len); -} -#endif - -/* =========================================================================== - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. -*/ -int ZEXPORT gzputc(file, c) - gzFile file; - int c; -{ - unsigned char cc = (unsigned char) c; /* required for big endian systems */ - - return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; -} - - -/* =========================================================================== - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. -*/ -int ZEXPORT gzputs(file, s) - gzFile file; - const char *s; -{ - return gzwrite(file, (char*)s, (unsigned)strlen(s)); -} - - -/* =========================================================================== - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. -*/ -local int do_flush (file, flush) - gzFile file; - int flush; -{ - uInt len; - int done = 0; - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; - - s->stream.avail_in = 0; /* should be zero already anyway */ - - for (;;) { - len = Z_BUFSIZE - s->stream.avail_out; - - if (len != 0) { - if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { - s->z_err = Z_ERRNO; - return Z_ERRNO; - } - s->stream.next_out = s->outbuf; - s->stream.avail_out = Z_BUFSIZE; - } - if (done) break; - s->out += s->stream.avail_out; - s->z_err = deflate(&(s->stream), flush); - s->out -= s->stream.avail_out; - - /* Ignore the second of two consecutive flushes: */ - if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; - - /* deflate has finished flushing only when it hasn't used up - * all the available space in the output buffer: - */ - done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); - - if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; - } - return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; -} - -int ZEXPORT gzflush (file, flush) - gzFile file; - int flush; -{ - gz_stream *s = (gz_stream*)file; - int err = do_flush (file, flush); - - if (err) return err; - fflush(s->file); - return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; -} -#endif /* NO_GZCOMPRESS */ - -/* =========================================================================== - Sets the starting position for the next gzread or gzwrite on the given - compressed file. The offset represents a number of bytes in the - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error. - SEEK_END is not implemented, returns error. - In this version of the library, gzseek can be extremely slow. -*/ -z_off_t ZEXPORT gzseek (file, offset, whence) - gzFile file; - z_off_t offset; - int whence; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || whence == SEEK_END || - s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { - return -1L; - } - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - return -1L; -#else - if (whence == SEEK_SET) { - offset -= s->in; - } - if (offset < 0) return -1L; - - /* At this point, offset is the number of zero bytes to write. */ - if (s->inbuf == Z_NULL) { - s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ - if (s->inbuf == Z_NULL) return -1L; - zmemzero(s->inbuf, Z_BUFSIZE); - } - while (offset > 0) { - uInt size = Z_BUFSIZE; - if (offset < Z_BUFSIZE) size = (uInt)offset; - - size = gzwrite(file, s->inbuf, size); - if (size == 0) return -1L; - - offset -= size; - } - return s->in; -#endif - } - /* Rest of function is for reading only */ - - /* compute absolute position */ - if (whence == SEEK_CUR) { - offset += s->out; - } - if (offset < 0) return -1L; - - if (s->transparent) { - /* map to fseek */ - s->back = EOF; - s->stream.avail_in = 0; - s->stream.next_in = s->inbuf; - if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; - - s->in = s->out = offset; - return offset; - } - - /* For a negative seek, rewind and use positive seek */ - if (offset >= s->out) { - offset -= s->out; - } else if (gzrewind(file) < 0) { - return -1L; - } - /* offset is now the number of bytes to skip. */ - - if (offset != 0 && s->outbuf == Z_NULL) { - s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); - if (s->outbuf == Z_NULL) return -1L; - } - if (offset && s->back != EOF) { - s->back = EOF; - s->out++; - offset--; - if (s->last) s->z_err = Z_STREAM_END; - } - while (offset > 0) { - int size = Z_BUFSIZE; - if (offset < Z_BUFSIZE) size = (int)offset; - - size = gzread(file, s->outbuf, (uInt)size); - if (size <= 0) return -1L; - offset -= size; - } - return s->out; -} - -/* =========================================================================== - Rewinds input file. -*/ -int ZEXPORT gzrewind (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL || s->mode != 'r') return -1; - - s->z_err = Z_OK; - s->z_eof = 0; - s->back = EOF; - s->stream.avail_in = 0; - s->stream.next_in = s->inbuf; - s->crc = crc32(0L, Z_NULL, 0); - if (!s->transparent) (void)inflateReset(&s->stream); - s->in = 0; - s->out = 0; - return fseek(s->file, s->start, SEEK_SET); -} - -/* =========================================================================== - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. -*/ -z_off_t ZEXPORT gztell (file) - gzFile file; -{ - return gzseek(file, 0L, SEEK_CUR); -} - -/* =========================================================================== - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. -*/ -int ZEXPORT gzeof (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - /* With concatenated compressed files that can have embedded - * crc trailers, z_eof is no longer the only/best indicator of EOF - * on a gz_stream. Handle end-of-stream error explicitly here. - */ - if (s == NULL || s->mode != 'r') return 0; - if (s->z_eof) return 1; - return s->z_err == Z_STREAM_END; -} - -/* =========================================================================== - Outputs a long in LSB order to the given file -*/ -local void putLong (file, x) - FILE *file; - uLong x; -{ - int n; - for (n = 0; n < 4; n++) { - fputc((int)(x & 0xff), file); - x >>= 8; - } -} - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets z_err in case - of error. -*/ -local uLong getLong (s) - gz_stream *s; -{ - uLong x = (uLong)get_byte(s); - int c; - - x += ((uLong)get_byte(s))<<8; - x += ((uLong)get_byte(s))<<16; - c = get_byte(s); - if (c == EOF) s->z_err = Z_DATA_ERROR; - x += ((uLong)c)<<24; - return x; -} - -/* =========================================================================== - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. -*/ -int ZEXPORT gzclose (file) - gzFile file; -{ - int err; - gz_stream *s = (gz_stream*)file; - - if (s == NULL) return Z_STREAM_ERROR; - - if (s->mode == 'w') { -#ifdef NO_GZCOMPRESS - return Z_STREAM_ERROR; -#else - err = do_flush (file, Z_FINISH); - if (err != Z_OK) return destroy((gz_stream*)file); - - putLong (s->file, s->crc); - putLong (s->file, (uLong)(s->in & 0xffffffff)); -#endif - } - return destroy((gz_stream*)file); -} - -/* =========================================================================== - Returns the error message for the last error which occured on the - given compressed file. errnum is set to zlib error number. If an - error occured in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. -*/ -const char * ZEXPORT gzerror (file, errnum) - gzFile file; - int *errnum; -{ - char *m; - gz_stream *s = (gz_stream*)file; - - if (s == NULL) { - *errnum = Z_STREAM_ERROR; - return (const char*)ERR_MSG(Z_STREAM_ERROR); - } - *errnum = s->z_err; - if (*errnum == Z_OK) return (const char*)""; - - m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); - - if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); - - TRYFREE(s->msg); - s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); - if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); - strcpy(s->msg, s->path); - strcat(s->msg, ": "); - strcat(s->msg, m); - return (const char*)s->msg; -} - -/* =========================================================================== - Clear the error and end-of-file flags, and do the same for the real file. -*/ -void ZEXPORT gzclearerr (file) - gzFile file; -{ - gz_stream *s = (gz_stream*)file; - - if (s == NULL) return; - if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; - s->z_eof = 0; - clearerr(s->file); -} +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id: gzio.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#include + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatiblity with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[20]; + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, + s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + int err; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + err = do_flush (file, Z_FINISH); + if (err != Z_OK) return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +/* =========================================================================== + Returns the error message for the last error which occured on the + given compressed file. errnum is set to zlib error number. If an + error occured in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/plugins/zerogs/opengl/Win32/zlib/infback.c b/plugins/zerogs/opengl/Win32/zlib/infback.c index 5cf5d22cf9..110b03b857 100644 --- a/plugins/zerogs/opengl/Win32/zlib/infback.c +++ b/plugins/zerogs/opengl/Win32/zlib/infback.c @@ -1,619 +1,619 @@ -/* infback.c -- inflate using a call-back interface - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - This code is largely copied from inflate.c. Normally either infback.o or - inflate.o would be linked into an application--not both. The interface - with inffast.c is retained so that optimized assembler-coded versions of - inflate_fast() can be used with either inflate.c or infback.c. - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -/* function prototypes */ -local void fixedtables OF((struct inflate_state FAR *state)); - -/* - strm provides memory allocation functions in zalloc and zfree, or - Z_NULL to use the library memory allocation functions. - - windowBits is in the range 8..15, and window is a user-supplied - window and output buffer that is 2**windowBits bytes. - */ -int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) -z_stream FAR *strm; -int windowBits; -unsigned char FAR *window; -const char *version; -int stream_size; -{ - struct inflate_state FAR *state; - - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != (int)(sizeof(z_stream))) - return Z_VERSION_ERROR; - if (strm == Z_NULL || window == Z_NULL || - windowBits < 8 || windowBits > 15) - return Z_STREAM_ERROR; - strm->msg = Z_NULL; /* in case we return an error */ - if (strm->zalloc == (alloc_func)0) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; - state = (struct inflate_state FAR *)ZALLOC(strm, 1, - sizeof(struct inflate_state)); - if (state == Z_NULL) return Z_MEM_ERROR; - Tracev((stderr, "inflate: allocated\n")); - strm->state = (voidpf)state; - state->wbits = windowBits; - state->wsize = 1U << windowBits; - state->window = window; - state->write = 0; - state->whave = 0; - return Z_OK; -} - -/* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ -#ifdef BUILDFIXED - static int virgin = 1; - static code *lenfix, *distfix; - static code fixed[544]; - - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - unsigned sym, bits; - static code *next; - - /* literal/length table */ - sym = 0; - while (sym < 144) state->lens[sym++] = 8; - while (sym < 256) state->lens[sym++] = 9; - while (sym < 280) state->lens[sym++] = 7; - while (sym < 288) state->lens[sym++] = 8; - next = fixed; - lenfix = next; - bits = 9; - inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); - - /* distance table */ - sym = 0; - while (sym < 32) state->lens[sym++] = 5; - distfix = next; - bits = 5; - inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); - - /* do this just once */ - virgin = 0; - } -#else /* !BUILDFIXED */ -# include "inffixed.h" -#endif /* BUILDFIXED */ - state->lencode = lenfix; - state->lenbits = 9; - state->distcode = distfix; - state->distbits = 5; -} - -/* Macros for inflateBack(): */ - -/* Load returned state from inflate_fast() */ -#define LOAD() \ - do { \ - put = strm->next_out; \ - left = strm->avail_out; \ - next = strm->next_in; \ - have = strm->avail_in; \ - hold = state->hold; \ - bits = state->bits; \ - } while (0) - -/* Set state from registers for inflate_fast() */ -#define RESTORE() \ - do { \ - strm->next_out = put; \ - strm->avail_out = left; \ - strm->next_in = next; \ - strm->avail_in = have; \ - state->hold = hold; \ - state->bits = bits; \ - } while (0) - -/* Clear the input bit accumulator */ -#define INITBITS() \ - do { \ - hold = 0; \ - bits = 0; \ - } while (0) - -/* Assure that some input is available. If input is requested, but denied, - then return a Z_BUF_ERROR from inflateBack(). */ -#define PULL() \ - do { \ - if (have == 0) { \ - have = in(in_desc, &next); \ - if (have == 0) { \ - next = Z_NULL; \ - ret = Z_BUF_ERROR; \ - goto inf_leave; \ - } \ - } \ - } while (0) - -/* Get a byte of input into the bit accumulator, or return from inflateBack() - with an error if there is no input available. */ -#define PULLBYTE() \ - do { \ - PULL(); \ - have--; \ - hold += (unsigned long)(*next++) << bits; \ - bits += 8; \ - } while (0) - -/* Assure that there are at least n bits in the bit accumulator. If there is - not enough available input to do that, then return from inflateBack() with - an error. */ -#define NEEDBITS(n) \ - do { \ - while (bits < (unsigned)(n)) \ - PULLBYTE(); \ - } while (0) - -/* Return the low n bits of the bit accumulator (n < 16) */ -#define BITS(n) \ - ((unsigned)hold & ((1U << (n)) - 1)) - -/* Remove n bits from the bit accumulator */ -#define DROPBITS(n) \ - do { \ - hold >>= (n); \ - bits -= (unsigned)(n); \ - } while (0) - -/* Remove zero to seven bits as needed to go to a byte boundary */ -#define BYTEBITS() \ - do { \ - hold >>= bits & 7; \ - bits -= bits & 7; \ - } while (0) - -/* Assure that some output space is available, by writing out the window - if it's full. If the write fails, return from inflateBack() with a - Z_BUF_ERROR. */ -#define ROOM() \ - do { \ - if (left == 0) { \ - put = state->window; \ - left = state->wsize; \ - state->whave = left; \ - if (out(out_desc, put, left)) { \ - ret = Z_BUF_ERROR; \ - goto inf_leave; \ - } \ - } \ - } while (0) - -/* - strm provides the memory allocation functions and window buffer on input, - and provides information on the unused input on return. For Z_DATA_ERROR - returns, strm will also provide an error message. - - in() and out() are the call-back input and output functions. When - inflateBack() needs more input, it calls in(). When inflateBack() has - filled the window with output, or when it completes with data in the - window, it calls out() to write out the data. The application must not - change the provided input until in() is called again or inflateBack() - returns. The application must not change the window/output buffer until - inflateBack() returns. - - in() and out() are called with a descriptor parameter provided in the - inflateBack() call. This parameter can be a structure that provides the - information required to do the read or write, as well as accumulated - information on the input and output such as totals and check values. - - in() should return zero on failure. out() should return non-zero on - failure. If either in() or out() fails, than inflateBack() returns a - Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it - was in() or out() that caused in the error. Otherwise, inflateBack() - returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format - error, or Z_MEM_ERROR if it could not allocate memory for the state. - inflateBack() can also return Z_STREAM_ERROR if the input parameters - are not correct, i.e. strm is Z_NULL or the state was not initialized. - */ -int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) -z_stream FAR *strm; -in_func in; -void FAR *in_desc; -out_func out; -void FAR *out_desc; -{ - struct inflate_state FAR *state; - unsigned char FAR *next; /* next input */ - unsigned char FAR *put; /* next output */ - unsigned have, left; /* available input and output */ - unsigned long hold; /* bit buffer */ - unsigned bits; /* bits in bit buffer */ - unsigned copy; /* number of stored or match bytes to copy */ - unsigned char FAR *from; /* where to copy match bytes from */ - code this; /* current decoding table entry */ - code last; /* parent table entry */ - unsigned len; /* length to copy for repeats, bits to drop */ - int ret; /* return code */ - static const unsigned short order[19] = /* permutation of code lengths */ - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - /* Check that the strm exists and that the state was initialized */ - if (strm == Z_NULL || strm->state == Z_NULL) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - - /* Reset the state */ - strm->msg = Z_NULL; - state->mode = TYPE; - state->last = 0; - state->whave = 0; - next = strm->next_in; - have = next != Z_NULL ? strm->avail_in : 0; - hold = 0; - bits = 0; - put = state->window; - left = state->wsize; - - /* Inflate until end of block marked as last */ - for (;;) - switch (state->mode) { - case TYPE: - /* determine and dispatch block type */ - if (state->last) { - BYTEBITS(); - state->mode = DONE; - break; - } - NEEDBITS(3); - state->last = BITS(1); - DROPBITS(1); - switch (BITS(2)) { - case 0: /* stored block */ - Tracev((stderr, "inflate: stored block%s\n", - state->last ? " (last)" : "")); - state->mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - Tracev((stderr, "inflate: fixed codes block%s\n", - state->last ? " (last)" : "")); - state->mode = LEN; /* decode codes */ - break; - case 2: /* dynamic block */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - state->last ? " (last)" : "")); - state->mode = TABLE; - break; - case 3: - strm->msg = (char *)"invalid block type"; - state->mode = BAD; - } - DROPBITS(2); - break; - - case STORED: - /* get and verify stored block length */ - BYTEBITS(); /* go to byte boundary */ - NEEDBITS(32); - if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - strm->msg = (char *)"invalid stored block lengths"; - state->mode = BAD; - break; - } - state->length = (unsigned)hold & 0xffff; - Tracev((stderr, "inflate: stored length %u\n", - state->length)); - INITBITS(); - - /* copy stored block from input to output */ - while (state->length != 0) { - copy = state->length; - PULL(); - ROOM(); - if (copy > have) copy = have; - if (copy > left) copy = left; - zmemcpy(put, next, copy); - have -= copy; - next += copy; - left -= copy; - put += copy; - state->length -= copy; - } - Tracev((stderr, "inflate: stored end\n")); - state->mode = TYPE; - break; - - case TABLE: - /* get dynamic table entries descriptor */ - NEEDBITS(14); - state->nlen = BITS(5) + 257; - DROPBITS(5); - state->ndist = BITS(5) + 1; - DROPBITS(5); - state->ncode = BITS(4) + 4; - DROPBITS(4); -#ifndef PKZIP_BUG_WORKAROUND - if (state->nlen > 286 || state->ndist > 30) { - strm->msg = (char *)"too many length or distance symbols"; - state->mode = BAD; - break; - } -#endif - Tracev((stderr, "inflate: table sizes ok\n")); - - /* get code length code lengths (not a typo) */ - state->have = 0; - while (state->have < state->ncode) { - NEEDBITS(3); - state->lens[order[state->have++]] = (unsigned short)BITS(3); - DROPBITS(3); - } - while (state->have < 19) - state->lens[order[state->have++]] = 0; - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 7; - ret = inflate_table(CODES, state->lens, 19, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid code lengths set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: code lengths ok\n")); - - /* get length and distance code code lengths */ - state->have = 0; - while (state->have < state->nlen + state->ndist) { - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.val < 16) { - NEEDBITS(this.bits); - DROPBITS(this.bits); - state->lens[state->have++] = this.val; - } - else { - if (this.val == 16) { - NEEDBITS(this.bits + 2); - DROPBITS(this.bits); - if (state->have == 0) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - len = (unsigned)(state->lens[state->have - 1]); - copy = 3 + BITS(2); - DROPBITS(2); - } - else if (this.val == 17) { - NEEDBITS(this.bits + 3); - DROPBITS(this.bits); - len = 0; - copy = 3 + BITS(3); - DROPBITS(3); - } - else { - NEEDBITS(this.bits + 7); - DROPBITS(this.bits); - len = 0; - copy = 11 + BITS(7); - DROPBITS(7); - } - if (state->have + copy > state->nlen + state->ndist) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - while (copy--) - state->lens[state->have++] = (unsigned short)len; - } - } - - /* build code tables */ - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 9; - ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid literal/lengths set"; - state->mode = BAD; - break; - } - state->distcode = (code const FAR *)(state->next); - state->distbits = 6; - ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, - &(state->next), &(state->distbits), state->work); - if (ret) { - strm->msg = (char *)"invalid distances set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: codes ok\n")); - state->mode = LEN; - - case LEN: - /* use inflate_fast() if we have enough input and output */ - if (have >= 6 && left >= 258) { - RESTORE(); - if (state->whave < state->wsize) - state->whave = state->wsize - left; - inflate_fast(strm, state->wsize); - LOAD(); - break; - } - - /* get a literal, length, or end-of-block code */ - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.op && (this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->lencode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - state->length = (unsigned)this.val; - - /* process literal */ - if (this.op == 0) { - Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", this.val)); - ROOM(); - *put++ = (unsigned char)(state->length); - left--; - state->mode = LEN; - break; - } - - /* process end of block */ - if (this.op & 32) { - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - - /* invalid code */ - if (this.op & 64) { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - - /* length code -- get extra bits, if any */ - state->extra = (unsigned)(this.op) & 15; - if (state->extra != 0) { - NEEDBITS(state->extra); - state->length += BITS(state->extra); - DROPBITS(state->extra); - } - Tracevv((stderr, "inflate: length %u\n", state->length)); - - /* get distance code */ - for (;;) { - this = state->distcode[BITS(state->distbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if ((this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->distcode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - if (this.op & 64) { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - state->offset = (unsigned)this.val; - - /* get distance extra bits, if any */ - state->extra = (unsigned)(this.op) & 15; - if (state->extra != 0) { - NEEDBITS(state->extra); - state->offset += BITS(state->extra); - DROPBITS(state->extra); - } - if (state->offset > state->wsize - (state->whave < state->wsize ? - left : 0)) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - Tracevv((stderr, "inflate: distance %u\n", state->offset)); - - /* copy match from window to output */ - do { - ROOM(); - copy = state->wsize - state->offset; - if (copy < left) { - from = put + copy; - copy = left - copy; - } - else { - from = put - state->offset; - copy = left; - } - if (copy > state->length) copy = state->length; - state->length -= copy; - left -= copy; - do { - *put++ = *from++; - } while (--copy); - } while (state->length != 0); - break; - - case DONE: - /* inflate stream terminated properly -- write leftover output */ - ret = Z_STREAM_END; - if (left < state->wsize) { - if (out(out_desc, state->window, state->wsize - left)) - ret = Z_BUF_ERROR; - } - goto inf_leave; - - case BAD: - ret = Z_DATA_ERROR; - goto inf_leave; - - default: /* can't happen, but makes compilers happy */ - ret = Z_STREAM_ERROR; - goto inf_leave; - } - - /* Return unused input */ - inf_leave: - strm->next_in = next; - strm->avail_in = have; - return ret; -} - -int ZEXPORT inflateBackEnd(strm) -z_stream FAR *strm; -{ - if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) - return Z_STREAM_ERROR; - ZFREE(strm, strm->state); - strm->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; -} +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_stream FAR *strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_stream FAR *strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_stream FAR *strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/plugins/zerogs/opengl/Win32/zlib/inffast.c b/plugins/zerogs/opengl/Win32/zlib/inffast.c index 63aa4402fc..c716440a92 100644 --- a/plugins/zerogs/opengl/Win32/zlib/inffast.c +++ b/plugins/zerogs/opengl/Win32/zlib/inffast.c @@ -1,305 +1,305 @@ -/* inffast.c -- fast decoding - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -#ifndef ASMINF - -/* Allow machine dependent optimization for post-increment or pre-increment. - Based on testing to date, - Pre-increment preferred for: - - PowerPC G3 (Adler) - - MIPS R5000 (Randers-Pehrson) - Post-increment preferred for: - - none - No measurable difference: - - Pentium III (Anderson) - - 68060 (Nikl) - */ -#ifdef POSTINC -# define OFF 0 -# define PUP(a) *(a)++ -#else -# define OFF 1 -# define PUP(a) *++(a) -#endif - -/* - Decode literal, length, and distance codes and write out the resulting - literal and match bytes until either not enough input or output is - available, an end-of-block is encountered, or a data error is encountered. - When large enough input and output buffers are supplied to inflate(), for - example, a 16K input buffer and a 64K output buffer, more than 95% of the - inflate execution time is spent in this routine. - - Entry assumptions: - - state->mode == LEN - strm->avail_in >= 6 - strm->avail_out >= 258 - start >= strm->avail_out - state->bits < 8 - - On return, state->mode is one of: - - LEN -- ran out of enough output space or enough available input - TYPE -- reached end of block code, inflate() to interpret next block - BAD -- error in block data - - Notes: - - - The maximum input bits used by a length/distance pair is 15 bits for the - length code, 5 bits for the length extra, 15 bits for the distance code, - and 13 bits for the distance extra. This totals 48 bits, or six bytes. - Therefore if strm->avail_in >= 6, then there is enough input to avoid - checking for available input while decoding. - - - The maximum bytes that a single length/distance pair can output is 258 - bytes, which is the maximum length that can be coded. inflate_fast() - requires strm->avail_out >= 258 for each loop to avoid checking for - output space. - */ -void inflate_fast(strm, start) -z_streamp strm; -unsigned start; /* inflate()'s starting value for strm->avail_out */ -{ - struct inflate_state FAR *state; - unsigned char FAR *in; /* local strm->next_in */ - unsigned char FAR *last; /* while in < last, enough input available */ - unsigned char FAR *out; /* local strm->next_out */ - unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ - unsigned char FAR *end; /* while out < end, enough space available */ - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned write; /* window write index */ - unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ - unsigned long hold; /* local strm->hold */ - unsigned bits; /* local strm->bits */ - code const FAR *lcode; /* local strm->lencode */ - code const FAR *dcode; /* local strm->distcode */ - unsigned lmask; /* mask for first level of length codes */ - unsigned dmask; /* mask for first level of distance codes */ - code this; /* retrieved table entry */ - unsigned op; /* code bits, operation, extra bits, or */ - /* window position, window bytes to copy */ - unsigned len; /* match length, unused bytes */ - unsigned dist; /* match distance */ - unsigned char FAR *from; /* where to copy match from */ - - /* copy state to local variables */ - state = (struct inflate_state FAR *)strm->state; - in = strm->next_in - OFF; - last = in + (strm->avail_in - 5); - out = strm->next_out - OFF; - beg = out - (start - strm->avail_out); - end = out + (strm->avail_out - 257); - wsize = state->wsize; - whave = state->whave; - write = state->write; - window = state->window; - hold = state->hold; - bits = state->bits; - lcode = state->lencode; - dcode = state->distcode; - lmask = (1U << state->lenbits) - 1; - dmask = (1U << state->distbits) - 1; - - /* decode literals and length/distances until end-of-block or not enough - input data or output space */ - do { - if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - this = lcode[hold & lmask]; - dolen: - op = (unsigned)(this.bits); - hold >>= op; - bits -= op; - op = (unsigned)(this.op); - if (op == 0) { /* literal */ - Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", this.val)); - PUP(out) = (unsigned char)(this.val); - } - else if (op & 16) { /* length base */ - len = (unsigned)(this.val); - op &= 15; /* number of extra bits */ - if (op) { - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - len += (unsigned)hold & ((1U << op) - 1); - hold >>= op; - bits -= op; - } - Tracevv((stderr, "inflate: length %u\n", len)); - if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - this = dcode[hold & dmask]; - dodist: - op = (unsigned)(this.bits); - hold >>= op; - bits -= op; - op = (unsigned)(this.op); - if (op & 16) { /* distance base */ - dist = (unsigned)(this.val); - op &= 15; /* number of extra bits */ - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - } - dist += (unsigned)hold & ((1U << op) - 1); - hold >>= op; - bits -= op; - Tracevv((stderr, "inflate: distance %u\n", dist)); - op = (unsigned)(out - beg); /* max distance in output */ - if (dist > op) { /* see if copy from window */ - op = dist - op; /* distance back in window */ - if (op > whave) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - from = window - OFF; - if (write == 0) { /* very common case */ - from += wsize - op; - if (op < len) { /* some from window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - else if (write < op) { /* wrap around window */ - from += wsize + write - op; - op -= write; - if (op < len) { /* some from end of window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = window - OFF; - if (write < len) { /* some from start of window */ - op = write; - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - } - else { /* contiguous in window */ - from += write - op; - if (op < len) { /* some from window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - while (len > 2) { - PUP(out) = PUP(from); - PUP(out) = PUP(from); - PUP(out) = PUP(from); - len -= 3; - } - if (len) { - PUP(out) = PUP(from); - if (len > 1) - PUP(out) = PUP(from); - } - } - else { - from = out - dist; /* copy direct from output */ - do { /* minimum length is three */ - PUP(out) = PUP(from); - PUP(out) = PUP(from); - PUP(out) = PUP(from); - len -= 3; - } while (len > 2); - if (len) { - PUP(out) = PUP(from); - if (len > 1) - PUP(out) = PUP(from); - } - } - } - else if ((op & 64) == 0) { /* 2nd level distance code */ - this = dcode[this.val + (hold & ((1U << op) - 1))]; - goto dodist; - } - else { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - } - else if ((op & 64) == 0) { /* 2nd level length code */ - this = lcode[this.val + (hold & ((1U << op) - 1))]; - goto dolen; - } - else if (op & 32) { /* end-of-block */ - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - else { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - } while (in < last && out < end); - - /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ - len = bits >> 3; - in -= len; - bits -= len << 3; - hold &= (1U << bits) - 1; - - /* update state and return */ - strm->next_in = in + OFF; - strm->next_out = out + OFF; - strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); - strm->avail_out = (unsigned)(out < end ? - 257 + (end - out) : 257 - (out - end)); - state->hold = hold; - state->bits = bits; - return; -} - -/* - inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - - Using bit fields for code structure - - Different op definition to avoid & for extra bits (do & for table bits) - - Three separate decoding do-loops for direct, window, and write == 0 - - Special case for distance > 1 copies to do overlapped load and store copy - - Explicit branch predictions (based on measured branch probabilities) - - Deferring match copy and interspersed it with decoding subsequent codes - - Swapping literal/length else - - Swapping window/direct else - - Larger unrolled copy loops (three is about right) - - Moving len -= 3 statement into middle of loop - */ - -#endif /* !ASMINF */ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - 68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/plugins/zerogs/opengl/Win32/zlib/inffast.h b/plugins/zerogs/opengl/Win32/zlib/inffast.h index 614fa7877d..1e88d2d97b 100644 --- a/plugins/zerogs/opengl/Win32/zlib/inffast.h +++ b/plugins/zerogs/opengl/Win32/zlib/inffast.h @@ -1,11 +1,11 @@ -/* inffast.h -- header to use inffast.c - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -void inflate_fast OF((z_streamp strm, unsigned start)); +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/plugins/zerogs/opengl/Win32/zlib/inffixed.h b/plugins/zerogs/opengl/Win32/zlib/inffixed.h index 423d5c5b50..75ed4b5978 100644 --- a/plugins/zerogs/opengl/Win32/zlib/inffixed.h +++ b/plugins/zerogs/opengl/Win32/zlib/inffixed.h @@ -1,94 +1,94 @@ - /* inffixed.h -- table for decoding fixed codes - * Generated automatically by makefixed(). - */ - - /* WARNING: this file should *not* be used by applications. It - is part of the implementation of the compression library and - is subject to change. Applications should only use zlib.h. - */ - - static const code lenfix[512] = { - {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, - {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, - {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, - {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, - {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, - {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, - {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, - {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, - {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, - {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, - {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, - {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, - {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, - {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, - {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, - {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, - {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, - {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, - {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, - {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, - {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, - {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, - {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, - {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, - {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, - {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, - {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, - {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, - {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, - {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, - {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, - {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, - {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, - {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, - {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, - {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, - {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, - {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, - {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, - {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, - {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, - {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, - {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, - {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, - {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, - {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, - {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, - {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, - {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, - {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, - {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, - {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, - {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, - {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, - {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, - {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, - {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, - {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, - {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, - {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, - {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, - {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, - {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, - {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, - {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, - {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, - {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, - {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, - {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, - {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, - {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, - {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, - {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, - {0,9,255} - }; - - static const code distfix[32] = { - {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, - {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, - {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, - {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, - {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, - {22,5,193},{64,5,0} - }; + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/plugins/zerogs/opengl/Win32/zlib/inflate.c b/plugins/zerogs/opengl/Win32/zlib/inflate.c index 71fe3ccd0e..a53b5c7446 100644 --- a/plugins/zerogs/opengl/Win32/zlib/inflate.c +++ b/plugins/zerogs/opengl/Win32/zlib/inflate.c @@ -1,1270 +1,1270 @@ -/* inflate.c -- zlib decompression - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * Change history: - * - * 1.2.beta0 24 Nov 2002 - * - First version -- complete rewrite of inflate to simplify code, avoid - * creation of window when not needed, minimize use of window when it is - * needed, make inffast.c even faster, implement gzip decoding, and to - * improve code readability and style over the previous zlib inflate code - * - * 1.2.beta1 25 Nov 2002 - * - Use pointers for available input and output checking in inffast.c - * - Remove input and output counters in inffast.c - * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 - * - Remove unnecessary second byte pull from length extra in inffast.c - * - Unroll direct copy to three copies per loop in inffast.c - * - * 1.2.beta2 4 Dec 2002 - * - Change external routine names to reduce potential conflicts - * - Correct filename to inffixed.h for fixed tables in inflate.c - * - Make hbuf[] unsigned char to match parameter type in inflate.c - * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) - * to avoid negation problem on Alphas (64 bit) in inflate.c - * - * 1.2.beta3 22 Dec 2002 - * - Add comments on state->bits assertion in inffast.c - * - Add comments on op field in inftrees.h - * - Fix bug in reuse of allocated window after inflateReset() - * - Remove bit fields--back to byte structure for speed - * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths - * - Change post-increments to pre-increments in inflate_fast(), PPC biased? - * - Add compile time option, POSTINC, to use post-increments instead (Intel?) - * - Make MATCH copy in inflate() much faster for when inflate_fast() not used - * - Use local copies of stream next and avail values, as well as local bit - * buffer and bit count in inflate()--for speed when inflate_fast() not used - * - * 1.2.beta4 1 Jan 2003 - * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings - * - Move a comment on output buffer sizes from inffast.c to inflate.c - * - Add comments in inffast.c to introduce the inflate_fast() routine - * - Rearrange window copies in inflate_fast() for speed and simplification - * - Unroll last copy for window match in inflate_fast() - * - Use local copies of window variables in inflate_fast() for speed - * - Pull out common write == 0 case for speed in inflate_fast() - * - Make op and len in inflate_fast() unsigned for consistency - * - Add FAR to lcode and dcode declarations in inflate_fast() - * - Simplified bad distance check in inflate_fast() - * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new - * source file infback.c to provide a call-back interface to inflate for - * programs like gzip and unzip -- uses window as output buffer to avoid - * window copying - * - * 1.2.beta5 1 Jan 2003 - * - Improved inflateBack() interface to allow the caller to provide initial - * input in strm. - * - Fixed stored blocks bug in inflateBack() - * - * 1.2.beta6 4 Jan 2003 - * - Added comments in inffast.c on effectiveness of POSTINC - * - Typecasting all around to reduce compiler warnings - * - Changed loops from while (1) or do {} while (1) to for (;;), again to - * make compilers happy - * - Changed type of window in inflateBackInit() to unsigned char * - * - * 1.2.beta7 27 Jan 2003 - * - Changed many types to unsigned or unsigned short to avoid warnings - * - Added inflateCopy() function - * - * 1.2.0 9 Mar 2003 - * - Changed inflateBack() interface to provide separate opaque descriptors - * for the in() and out() functions - * - Changed inflateBack() argument and in_func typedef to swap the length - * and buffer address return values for the input function - * - Check next_in and next_out for Z_NULL on entry to inflate() - * - * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -#ifdef MAKEFIXED -# ifndef BUILDFIXED -# define BUILDFIXED -# endif -#endif - -/* function prototypes */ -local void fixedtables OF((struct inflate_state FAR *state)); -local int updatewindow OF((z_streamp strm, unsigned out)); -#ifdef BUILDFIXED - void makefixed OF((void)); -#endif -local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, - unsigned len)); - -int ZEXPORT inflateReset(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - strm->total_in = strm->total_out = state->total = 0; - strm->msg = Z_NULL; - state->mode = HEAD; - state->last = 0; - state->havedict = 0; - state->wsize = 0; - state->whave = 0; - state->hold = 0; - state->bits = 0; - state->lencode = state->distcode = state->next = state->codes; - Tracev((stderr, "inflate: reset\n")); - return Z_OK; -} - -int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) -z_streamp strm; -int windowBits; -const char *version; -int stream_size; -{ - struct inflate_state FAR *state; - - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != (int)(sizeof(z_stream))) - return Z_VERSION_ERROR; - if (strm == Z_NULL) return Z_STREAM_ERROR; - strm->msg = Z_NULL; /* in case we return an error */ - if (strm->zalloc == (alloc_func)0) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == (free_func)0) strm->zfree = zcfree; - state = (struct inflate_state FAR *) - ZALLOC(strm, 1, sizeof(struct inflate_state)); - if (state == Z_NULL) return Z_MEM_ERROR; - Tracev((stderr, "inflate: allocated\n")); - strm->state = (voidpf)state; - if (windowBits < 0) { - state->wrap = 0; - windowBits = -windowBits; - } - else { - state->wrap = (windowBits >> 4) + 1; -#ifdef GUNZIP - if (windowBits < 48) windowBits &= 15; -#endif - } - if (windowBits < 8 || windowBits > 15) { - ZFREE(strm, state); - strm->state = Z_NULL; - return Z_STREAM_ERROR; - } - state->wbits = (unsigned)windowBits; - state->window = Z_NULL; - return inflateReset(strm); -} - -int ZEXPORT inflateInit_(strm, version, stream_size) -z_streamp strm; -const char *version; -int stream_size; -{ - return inflateInit2_(strm, DEF_WBITS, version, stream_size); -} - -/* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ -#ifdef BUILDFIXED - static int virgin = 1; - static code *lenfix, *distfix; - static code fixed[544]; - - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - unsigned sym, bits; - static code *next; - - /* literal/length table */ - sym = 0; - while (sym < 144) state->lens[sym++] = 8; - while (sym < 256) state->lens[sym++] = 9; - while (sym < 280) state->lens[sym++] = 7; - while (sym < 288) state->lens[sym++] = 8; - next = fixed; - lenfix = next; - bits = 9; - inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); - - /* distance table */ - sym = 0; - while (sym < 32) state->lens[sym++] = 5; - distfix = next; - bits = 5; - inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); - - /* do this just once */ - virgin = 0; - } -#else /* !BUILDFIXED */ -# include "inffixed.h" -#endif /* BUILDFIXED */ - state->lencode = lenfix; - state->lenbits = 9; - state->distcode = distfix; - state->distbits = 5; -} - -#ifdef MAKEFIXED -#include - -/* - Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also - defines BUILDFIXED, so the tables are built on the fly. makefixed() writes - those tables to stdout, which would be piped to inffixed.h. A small program - can simply call makefixed to do this: - - void makefixed(void); - - int main(void) - { - makefixed(); - return 0; - } - - Then that can be linked with zlib built with MAKEFIXED defined and run: - - a.out > inffixed.h - */ -void makefixed() -{ - unsigned low, size; - struct inflate_state state; - - fixedtables(&state); - puts(" /* inffixed.h -- table for decoding fixed codes"); - puts(" * Generated automatically by makefixed()."); - puts(" */"); - puts(""); - puts(" /* WARNING: this file should *not* be used by applications."); - puts(" It is part of the implementation of this library and is"); - puts(" subject to change. Applications should only use zlib.h."); - puts(" */"); - puts(""); - size = 1U << 9; - printf(" static const code lenfix[%u] = {", size); - low = 0; - for (;;) { - if ((low % 7) == 0) printf("\n "); - printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, - state.lencode[low].val); - if (++low == size) break; - putchar(','); - } - puts("\n };"); - size = 1U << 5; - printf("\n static const code distfix[%u] = {", size); - low = 0; - for (;;) { - if ((low % 6) == 0) printf("\n "); - printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, - state.distcode[low].val); - if (++low == size) break; - putchar(','); - } - puts("\n };"); -} -#endif /* MAKEFIXED */ - -/* - Update the window with the last wsize (normally 32K) bytes written before - returning. If window does not exist yet, create it. This is only called - when a window is already in use, or when output has been written during this - inflate call, but the end of the deflate stream has not been reached yet. - It is also called to create a window for dictionary data when a dictionary - is loaded. - - Providing output buffers larger than 32K to inflate() should provide a speed - advantage, since only the last 32K of output is copied to the sliding window - upon return from inflate(), and since all distances after the first 32K of - output will fall in the output data, making match copies simpler and faster. - The advantage may be dependent on the size of the processor's data caches. - */ -local int updatewindow(strm, out) -z_streamp strm; -unsigned out; -{ - struct inflate_state FAR *state; - unsigned copy, dist; - - state = (struct inflate_state FAR *)strm->state; - - /* if it hasn't been done already, allocate space for the window */ - if (state->window == Z_NULL) { - state->window = (unsigned char FAR *) - ZALLOC(strm, 1U << state->wbits, - sizeof(unsigned char)); - if (state->window == Z_NULL) return 1; - } - - /* if window not in use yet, initialize */ - if (state->wsize == 0) { - state->wsize = 1U << state->wbits; - state->write = 0; - state->whave = 0; - } - - /* copy state->wsize or less output bytes into the circular window */ - copy = out - strm->avail_out; - if (copy >= state->wsize) { - zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); - state->write = 0; - state->whave = state->wsize; - } - else { - dist = state->wsize - state->write; - if (dist > copy) dist = copy; - zmemcpy(state->window + state->write, strm->next_out - copy, dist); - copy -= dist; - if (copy) { - zmemcpy(state->window, strm->next_out - copy, copy); - state->write = copy; - state->whave = state->wsize; - } - else { - state->write += dist; - if (state->write == state->wsize) state->write = 0; - if (state->whave < state->wsize) state->whave += dist; - } - } - return 0; -} - -/* Macros for inflate(): */ - -/* check function to use adler32() for zlib or crc32() for gzip */ -#ifdef GUNZIP -# define UPDATE(check, buf, len) \ - (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) -#else -# define UPDATE(check, buf, len) adler32(check, buf, len) -#endif - -/* check macros for header crc */ -#ifdef GUNZIP -# define CRC2(check, word) \ - do { \ - hbuf[0] = (unsigned char)(word); \ - hbuf[1] = (unsigned char)((word) >> 8); \ - check = crc32(check, hbuf, 2); \ - } while (0) - -# define CRC4(check, word) \ - do { \ - hbuf[0] = (unsigned char)(word); \ - hbuf[1] = (unsigned char)((word) >> 8); \ - hbuf[2] = (unsigned char)((word) >> 16); \ - hbuf[3] = (unsigned char)((word) >> 24); \ - check = crc32(check, hbuf, 4); \ - } while (0) -#endif - -/* Load registers with state in inflate() for speed */ -#define LOAD() \ - do { \ - put = strm->next_out; \ - left = strm->avail_out; \ - next = strm->next_in; \ - have = strm->avail_in; \ - hold = state->hold; \ - bits = state->bits; \ - } while (0) - -/* Restore state from registers in inflate() */ -#define RESTORE() \ - do { \ - strm->next_out = put; \ - strm->avail_out = left; \ - strm->next_in = next; \ - strm->avail_in = have; \ - state->hold = hold; \ - state->bits = bits; \ - } while (0) - -/* Clear the input bit accumulator */ -#define INITBITS() \ - do { \ - hold = 0; \ - bits = 0; \ - } while (0) - -/* Get a byte of input into the bit accumulator, or return from inflate() - if there is no input available. */ -#define PULLBYTE() \ - do { \ - if (have == 0) goto inf_leave; \ - have--; \ - hold += (unsigned long)(*next++) << bits; \ - bits += 8; \ - } while (0) - -/* Assure that there are at least n bits in the bit accumulator. If there is - not enough available input to do that, then return from inflate(). */ -#define NEEDBITS(n) \ - do { \ - while (bits < (unsigned)(n)) \ - PULLBYTE(); \ - } while (0) - -/* Return the low n bits of the bit accumulator (n < 16) */ -#define BITS(n) \ - ((unsigned)hold & ((1U << (n)) - 1)) - -/* Remove n bits from the bit accumulator */ -#define DROPBITS(n) \ - do { \ - hold >>= (n); \ - bits -= (unsigned)(n); \ - } while (0) - -/* Remove zero to seven bits as needed to go to a byte boundary */ -#define BYTEBITS() \ - do { \ - hold >>= bits & 7; \ - bits -= bits & 7; \ - } while (0) - -/* Reverse the bytes in a 32-bit value */ -#define REVERSE(q) \ - ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ - (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) - -/* - inflate() uses a state machine to process as much input data and generate as - much output data as possible before returning. The state machine is - structured roughly as follows: - - for (;;) switch (state) { - ... - case STATEn: - if (not enough input data or output space to make progress) - return; - ... make progress ... - state = STATEm; - break; - ... - } - - so when inflate() is called again, the same case is attempted again, and - if the appropriate resources are provided, the machine proceeds to the - next state. The NEEDBITS() macro is usually the way the state evaluates - whether it can proceed or should return. NEEDBITS() does the return if - the requested bits are not available. The typical use of the BITS macros - is: - - NEEDBITS(n); - ... do something with BITS(n) ... - DROPBITS(n); - - where NEEDBITS(n) either returns from inflate() if there isn't enough - input left to load n bits into the accumulator, or it continues. BITS(n) - gives the low n bits in the accumulator. When done, DROPBITS(n) drops - the low n bits off the accumulator. INITBITS() clears the accumulator - and sets the number of available bits to zero. BYTEBITS() discards just - enough bits to put the accumulator on a byte boundary. After BYTEBITS() - and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. - - NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return - if there is no input available. The decoding of variable length codes uses - PULLBYTE() directly in order to pull just enough bytes to decode the next - code, and no more. - - Some states loop until they get enough input, making sure that enough - state information is maintained to continue the loop where it left off - if NEEDBITS() returns in the loop. For example, want, need, and keep - would all have to actually be part of the saved state in case NEEDBITS() - returns: - - case STATEw: - while (want < need) { - NEEDBITS(n); - keep[want++] = BITS(n); - DROPBITS(n); - } - state = STATEx; - case STATEx: - - As shown above, if the next state is also the next case, then the break - is omitted. - - A state may also return if there is not enough output space available to - complete that state. Those states are copying stored data, writing a - literal byte, and copying a matching string. - - When returning, a "goto inf_leave" is used to update the total counters, - update the check value, and determine whether any progress has been made - during that inflate() call in order to return the proper return code. - Progress is defined as a change in either strm->avail_in or strm->avail_out. - When there is a window, goto inf_leave will update the window with the last - output written. If a goto inf_leave occurs in the middle of decompression - and there is no window currently, goto inf_leave will create one and copy - output to the window for the next call of inflate(). - - In this implementation, the flush parameter of inflate() only affects the - return code (per zlib.h). inflate() always writes as much as possible to - strm->next_out, given the space available and the provided input--the effect - documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers - the allocation of and copying into a sliding window until necessary, which - provides the effect documented in zlib.h for Z_FINISH when the entire input - stream available. So the only thing the flush parameter actually does is: - when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it - will return Z_BUF_ERROR if it has not reached the end of the stream. - */ - -int ZEXPORT inflate(strm, flush) -z_streamp strm; -int flush; -{ - struct inflate_state FAR *state; - unsigned char FAR *next; /* next input */ - unsigned char FAR *put; /* next output */ - unsigned have, left; /* available input and output */ - unsigned long hold; /* bit buffer */ - unsigned bits; /* bits in bit buffer */ - unsigned in, out; /* save starting available input and output */ - unsigned copy; /* number of stored or match bytes to copy */ - unsigned char FAR *from; /* where to copy match bytes from */ - code this; /* current decoding table entry */ - code last; /* parent table entry */ - unsigned len; /* length to copy for repeats, bits to drop */ - int ret; /* return code */ -#ifdef GUNZIP - unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ -#endif - static const unsigned short order[19] = /* permutation of code lengths */ - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || - (strm->next_in == Z_NULL && strm->avail_in != 0)) - return Z_STREAM_ERROR; - - state = (struct inflate_state FAR *)strm->state; - if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ - LOAD(); - in = have; - out = left; - ret = Z_OK; - for (;;) - switch (state->mode) { - case HEAD: - if (state->wrap == 0) { - state->mode = TYPEDO; - break; - } - NEEDBITS(16); -#ifdef GUNZIP - if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ - state->check = crc32(0L, Z_NULL, 0); - CRC2(state->check, hold); - INITBITS(); - state->mode = FLAGS; - break; - } - state->flags = 0; /* expect zlib header */ - if (!(state->wrap & 1) || /* check if zlib header allowed */ -#else - if ( -#endif - ((BITS(8) << 8) + (hold >> 8)) % 31) { - strm->msg = (char *)"incorrect header check"; - state->mode = BAD; - break; - } - if (BITS(4) != Z_DEFLATED) { - strm->msg = (char *)"unknown compression method"; - state->mode = BAD; - break; - } - DROPBITS(4); - if (BITS(4) + 8 > state->wbits) { - strm->msg = (char *)"invalid window size"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: zlib header ok\n")); - strm->adler = state->check = adler32(0L, Z_NULL, 0); - state->mode = hold & 0x200 ? DICTID : TYPE; - INITBITS(); - break; -#ifdef GUNZIP - case FLAGS: - NEEDBITS(16); - state->flags = (int)(hold); - if ((state->flags & 0xff) != Z_DEFLATED) { - strm->msg = (char *)"unknown compression method"; - state->mode = BAD; - break; - } - if (state->flags & 0xe000) { - strm->msg = (char *)"unknown header flags set"; - state->mode = BAD; - break; - } - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - state->mode = TIME; - case TIME: - NEEDBITS(32); - if (state->flags & 0x0200) CRC4(state->check, hold); - INITBITS(); - state->mode = OS; - case OS: - NEEDBITS(16); - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - state->mode = EXLEN; - case EXLEN: - if (state->flags & 0x0400) { - NEEDBITS(16); - state->length = (unsigned)(hold); - if (state->flags & 0x0200) CRC2(state->check, hold); - INITBITS(); - } - state->mode = EXTRA; - case EXTRA: - if (state->flags & 0x0400) { - copy = state->length; - if (copy > have) copy = have; - if (copy) { - if (state->flags & 0x0200) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - state->length -= copy; - } - if (state->length) goto inf_leave; - } - state->mode = NAME; - case NAME: - if (state->flags & 0x0800) { - if (have == 0) goto inf_leave; - copy = 0; - do { - len = (unsigned)(next[copy++]); - } while (len && copy < have); - if (state->flags & 0x02000) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - if (len) goto inf_leave; - } - state->mode = COMMENT; - case COMMENT: - if (state->flags & 0x1000) { - if (have == 0) goto inf_leave; - copy = 0; - do { - len = (unsigned)(next[copy++]); - } while (len && copy < have); - if (state->flags & 0x02000) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - if (len) goto inf_leave; - } - state->mode = HCRC; - case HCRC: - if (state->flags & 0x0200) { - NEEDBITS(16); - if (hold != (state->check & 0xffff)) { - strm->msg = (char *)"header crc mismatch"; - state->mode = BAD; - break; - } - INITBITS(); - } - strm->adler = state->check = crc32(0L, Z_NULL, 0); - state->mode = TYPE; - break; -#endif - case DICTID: - NEEDBITS(32); - strm->adler = state->check = REVERSE(hold); - INITBITS(); - state->mode = DICT; - case DICT: - if (state->havedict == 0) { - RESTORE(); - return Z_NEED_DICT; - } - strm->adler = state->check = adler32(0L, Z_NULL, 0); - state->mode = TYPE; - case TYPE: - if (flush == Z_BLOCK) goto inf_leave; - case TYPEDO: - if (state->last) { - BYTEBITS(); - state->mode = CHECK; - break; - } - NEEDBITS(3); - state->last = BITS(1); - DROPBITS(1); - switch (BITS(2)) { - case 0: /* stored block */ - Tracev((stderr, "inflate: stored block%s\n", - state->last ? " (last)" : "")); - state->mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - Tracev((stderr, "inflate: fixed codes block%s\n", - state->last ? " (last)" : "")); - state->mode = LEN; /* decode codes */ - break; - case 2: /* dynamic block */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - state->last ? " (last)" : "")); - state->mode = TABLE; - break; - case 3: - strm->msg = (char *)"invalid block type"; - state->mode = BAD; - } - DROPBITS(2); - break; - case STORED: - BYTEBITS(); /* go to byte boundary */ - NEEDBITS(32); - if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - strm->msg = (char *)"invalid stored block lengths"; - state->mode = BAD; - break; - } - state->length = (unsigned)hold & 0xffff; - Tracev((stderr, "inflate: stored length %u\n", - state->length)); - INITBITS(); - state->mode = COPY; - case COPY: - copy = state->length; - if (copy) { - if (copy > have) copy = have; - if (copy > left) copy = left; - if (copy == 0) goto inf_leave; - zmemcpy(put, next, copy); - have -= copy; - next += copy; - left -= copy; - put += copy; - state->length -= copy; - break; - } - Tracev((stderr, "inflate: stored end\n")); - state->mode = TYPE; - break; - case TABLE: - NEEDBITS(14); - state->nlen = BITS(5) + 257; - DROPBITS(5); - state->ndist = BITS(5) + 1; - DROPBITS(5); - state->ncode = BITS(4) + 4; - DROPBITS(4); -#ifndef PKZIP_BUG_WORKAROUND - if (state->nlen > 286 || state->ndist > 30) { - strm->msg = (char *)"too many length or distance symbols"; - state->mode = BAD; - break; - } -#endif - Tracev((stderr, "inflate: table sizes ok\n")); - state->have = 0; - state->mode = LENLENS; - case LENLENS: - while (state->have < state->ncode) { - NEEDBITS(3); - state->lens[order[state->have++]] = (unsigned short)BITS(3); - DROPBITS(3); - } - while (state->have < 19) - state->lens[order[state->have++]] = 0; - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 7; - ret = inflate_table(CODES, state->lens, 19, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid code lengths set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: code lengths ok\n")); - state->have = 0; - state->mode = CODELENS; - case CODELENS: - while (state->have < state->nlen + state->ndist) { - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.val < 16) { - NEEDBITS(this.bits); - DROPBITS(this.bits); - state->lens[state->have++] = this.val; - } - else { - if (this.val == 16) { - NEEDBITS(this.bits + 2); - DROPBITS(this.bits); - if (state->have == 0) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - len = state->lens[state->have - 1]; - copy = 3 + BITS(2); - DROPBITS(2); - } - else if (this.val == 17) { - NEEDBITS(this.bits + 3); - DROPBITS(this.bits); - len = 0; - copy = 3 + BITS(3); - DROPBITS(3); - } - else { - NEEDBITS(this.bits + 7); - DROPBITS(this.bits); - len = 0; - copy = 11 + BITS(7); - DROPBITS(7); - } - if (state->have + copy > state->nlen + state->ndist) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - while (copy--) - state->lens[state->have++] = (unsigned short)len; - } - } - - /* build code tables */ - state->next = state->codes; - state->lencode = (code const FAR *)(state->next); - state->lenbits = 9; - ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid literal/lengths set"; - state->mode = BAD; - break; - } - state->distcode = (code const FAR *)(state->next); - state->distbits = 6; - ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, - &(state->next), &(state->distbits), state->work); - if (ret) { - strm->msg = (char *)"invalid distances set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: codes ok\n")); - state->mode = LEN; - case LEN: - if (have >= 6 && left >= 258) { - RESTORE(); - inflate_fast(strm, out); - LOAD(); - break; - } - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.op && (this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->lencode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - state->length = (unsigned)this.val; - if ((int)(this.op) == 0) { - Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", this.val)); - state->mode = LIT; - break; - } - if (this.op & 32) { - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - if (this.op & 64) { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - state->extra = (unsigned)(this.op) & 15; - state->mode = LENEXT; - case LENEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->length += BITS(state->extra); - DROPBITS(state->extra); - } - Tracevv((stderr, "inflate: length %u\n", state->length)); - state->mode = DIST; - case DIST: - for (;;) { - this = state->distcode[BITS(state->distbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if ((this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->distcode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - if (this.op & 64) { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - state->offset = (unsigned)this.val; - state->extra = (unsigned)(this.op) & 15; - state->mode = DISTEXT; - case DISTEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->offset += BITS(state->extra); - DROPBITS(state->extra); - } - if (state->offset > state->whave + out - left) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - Tracevv((stderr, "inflate: distance %u\n", state->offset)); - state->mode = MATCH; - case MATCH: - if (left == 0) goto inf_leave; - copy = out - left; - if (state->offset > copy) { /* copy from window */ - copy = state->offset - copy; - if (copy > state->write) { - copy -= state->write; - from = state->window + (state->wsize - copy); - } - else - from = state->window + (state->write - copy); - if (copy > state->length) copy = state->length; - } - else { /* copy from output */ - from = put - state->offset; - copy = state->length; - } - if (copy > left) copy = left; - left -= copy; - state->length -= copy; - do { - *put++ = *from++; - } while (--copy); - if (state->length == 0) state->mode = LEN; - break; - case LIT: - if (left == 0) goto inf_leave; - *put++ = (unsigned char)(state->length); - left--; - state->mode = LEN; - break; - case CHECK: - if (state->wrap) { - NEEDBITS(32); - out -= left; - strm->total_out += out; - state->total += out; - if (out) - strm->adler = state->check = - UPDATE(state->check, put - out, out); - out = left; - if (( -#ifdef GUNZIP - state->flags ? hold : -#endif - REVERSE(hold)) != state->check) { - strm->msg = (char *)"incorrect data check"; - state->mode = BAD; - break; - } - INITBITS(); - Tracev((stderr, "inflate: check matches trailer\n")); - } -#ifdef GUNZIP - state->mode = LENGTH; - case LENGTH: - if (state->wrap && state->flags) { - NEEDBITS(32); - if (hold != (state->total & 0xffffffffUL)) { - strm->msg = (char *)"incorrect length check"; - state->mode = BAD; - break; - } - INITBITS(); - Tracev((stderr, "inflate: length matches trailer\n")); - } -#endif - state->mode = DONE; - case DONE: - ret = Z_STREAM_END; - goto inf_leave; - case BAD: - ret = Z_DATA_ERROR; - goto inf_leave; - case MEM: - return Z_MEM_ERROR; - case SYNC: - default: - return Z_STREAM_ERROR; - } - - /* - Return from inflate(), updating the total counts and the check value. - If there was no progress during the inflate() call, return a buffer - error. Call updatewindow() to create and/or update the window state. - Note: a memory error from inflate() is non-recoverable. - */ - inf_leave: - RESTORE(); - if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) - if (updatewindow(strm, out)) { - state->mode = MEM; - return Z_MEM_ERROR; - } - in -= strm->avail_in; - out -= strm->avail_out; - strm->total_in += in; - strm->total_out += out; - state->total += out; - if (state->wrap && out) - strm->adler = state->check = - UPDATE(state->check, strm->next_out - out, out); - strm->data_type = state->bits + (state->last ? 64 : 0) + - (state->mode == TYPE ? 128 : 0); - if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) - ret = Z_BUF_ERROR; - return ret; -} - -int ZEXPORT inflateEnd(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (state->window != Z_NULL) ZFREE(strm, state->window); - ZFREE(strm, strm->state); - strm->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; -} - -int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) -z_streamp strm; -const Bytef *dictionary; -uInt dictLength; -{ - struct inflate_state FAR *state; - unsigned long id; - - /* check state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (state->mode != DICT) return Z_STREAM_ERROR; - - /* check for correct dictionary id */ - id = adler32(0L, Z_NULL, 0); - id = adler32(id, dictionary, dictLength); - if (id != state->check) return Z_DATA_ERROR; - - /* copy dictionary to window */ - if (updatewindow(strm, strm->avail_out)) { - state->mode = MEM; - return Z_MEM_ERROR; - } - if (dictLength > state->wsize) { - zmemcpy(state->window, dictionary + dictLength - state->wsize, - state->wsize); - state->whave = state->wsize; - } - else { - zmemcpy(state->window + state->wsize - dictLength, dictionary, - dictLength); - state->whave = dictLength; - } - state->havedict = 1; - Tracev((stderr, "inflate: dictionary set\n")); - return Z_OK; -} - -/* - Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found - or when out of input. When called, *have is the number of pattern bytes - found in order so far, in 0..3. On return *have is updated to the new - state. If on return *have equals four, then the pattern was found and the - return value is how many bytes were read including the last byte of the - pattern. If *have is less than four, then the pattern has not been found - yet and the return value is len. In the latter case, syncsearch() can be - called again with more data and the *have state. *have is initialized to - zero for the first call. - */ -local unsigned syncsearch(have, buf, len) -unsigned FAR *have; -unsigned char FAR *buf; -unsigned len; -{ - unsigned got; - unsigned next; - - got = *have; - next = 0; - while (next < len && got < 4) { - if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) - got++; - else if (buf[next]) - got = 0; - else - got = 4 - got; - next++; - } - *have = got; - return next; -} - -int ZEXPORT inflateSync(strm) -z_streamp strm; -{ - unsigned len; /* number of bytes to look at or looked at */ - unsigned long in, out; /* temporary to save total_in and total_out */ - unsigned char buf[4]; /* to restore bit buffer to byte string */ - struct inflate_state FAR *state; - - /* check parameters */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; - - /* if first time, start search in bit buffer */ - if (state->mode != SYNC) { - state->mode = SYNC; - state->hold <<= state->bits & 7; - state->bits -= state->bits & 7; - len = 0; - while (state->bits >= 8) { - buf[len++] = (unsigned char)(state->hold); - state->hold >>= 8; - state->bits -= 8; - } - state->have = 0; - syncsearch(&(state->have), buf, len); - } - - /* search available input */ - len = syncsearch(&(state->have), strm->next_in, strm->avail_in); - strm->avail_in -= len; - strm->next_in += len; - strm->total_in += len; - - /* return no joy or set up to restart inflate() on a new block */ - if (state->have != 4) return Z_DATA_ERROR; - in = strm->total_in; out = strm->total_out; - inflateReset(strm); - strm->total_in = in; strm->total_out = out; - state->mode = TYPE; - return Z_OK; -} - -/* - Returns true if inflate is currently at the end of a block generated by - Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP - implementation to provide an additional safety check. PPP uses - Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored - block. When decompressing, PPP checks that at the end of input packet, - inflate is waiting for these length bytes. - */ -int ZEXPORT inflateSyncPoint(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - return state->mode == STORED && state->bits == 0; -} - -int ZEXPORT inflateCopy(dest, source) -z_streamp dest; -z_streamp source; -{ - struct inflate_state FAR *state; - struct inflate_state FAR *copy; - unsigned char FAR *window; - - /* check input */ - if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || - source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)source->state; - - /* allocate space */ - copy = (struct inflate_state FAR *) - ZALLOC(source, 1, sizeof(struct inflate_state)); - if (copy == Z_NULL) return Z_MEM_ERROR; - window = Z_NULL; - if (state->window != Z_NULL) { - window = (unsigned char FAR *) - ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); - if (window == Z_NULL) { - ZFREE(source, copy); - return Z_MEM_ERROR; - } - } - - /* copy state */ - *dest = *source; - *copy = *state; - copy->lencode = copy->codes + (state->lencode - state->codes); - copy->distcode = copy->codes + (state->distcode - state->codes); - copy->next = copy->codes + (state->next - state->codes); - if (window != Z_NULL) - zmemcpy(window, state->window, 1U << state->wbits); - copy->window = window; - dest->state = (voidpf)copy; - return Z_OK; -} +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->wsize = 0; + state->whave = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + if (BITS(4) + 8 > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + } while (len && copy < have); + if (state->flags & 0x02000) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + } while (len && copy < have); + if (state->flags & 0x02000) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->mode != DICT) return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) return Z_DATA_ERROR; + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + *dest = *source; + *copy = *state; + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) + zmemcpy(window, state->window, 1U << state->wbits); + copy->window = window; + dest->state = (voidpf)copy; + return Z_OK; +} diff --git a/plugins/zerogs/opengl/Win32/zlib/inflate.h b/plugins/zerogs/opengl/Win32/zlib/inflate.h index b6965127b9..9a12c8fd29 100644 --- a/plugins/zerogs/opengl/Win32/zlib/inflate.h +++ b/plugins/zerogs/opengl/Win32/zlib/inflate.h @@ -1,117 +1,117 @@ -/* inflate.h -- internal inflate state definition - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer decoding by inflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip decoding - should be left enabled. */ -#ifndef NO_GZIP -# define GUNZIP -#endif - -/* Possible inflate modes between inflate() calls */ -typedef enum { - HEAD, /* i: waiting for magic header */ -#ifdef GUNZIP - FLAGS, /* i: waiting for method and flags (gzip) */ - TIME, /* i: waiting for modification time (gzip) */ - OS, /* i: waiting for extra flags and operating system (gzip) */ - EXLEN, /* i: waiting for extra length (gzip) */ - EXTRA, /* i: waiting for extra bytes (gzip) */ - NAME, /* i: waiting for end of file name (gzip) */ - COMMENT, /* i: waiting for end of comment (gzip) */ - HCRC, /* i: waiting for header crc (gzip) */ -#endif - DICTID, /* i: waiting for dictionary check value */ - DICT, /* waiting for inflateSetDictionary() call */ - TYPE, /* i: waiting for type bits, including last-flag bit */ - TYPEDO, /* i: same, but skip check to exit inflate on new block */ - STORED, /* i: waiting for stored size (length and complement) */ - COPY, /* i/o: waiting for input or output to copy stored block */ - TABLE, /* i: waiting for dynamic block table lengths */ - LENLENS, /* i: waiting for code length code lengths */ - CODELENS, /* i: waiting for length/lit and distance code lengths */ - LEN, /* i: waiting for length/lit code */ - LENEXT, /* i: waiting for length extra bits */ - DIST, /* i: waiting for distance code */ - DISTEXT, /* i: waiting for distance extra bits */ - MATCH, /* o: waiting for output space to copy string */ - LIT, /* o: waiting for output space to write literal */ - CHECK, /* i: waiting for 32-bit check value */ -#ifdef GUNZIP - LENGTH, /* i: waiting for 32-bit length (gzip) */ -#endif - DONE, /* finished check, done -- remain here until reset */ - BAD, /* got a data error -- remain here until reset */ - MEM, /* got an inflate() memory error -- remain here until reset */ - SYNC /* looking for synchronization bytes to restart inflate() */ -} inflate_mode; - -/* - State transitions between above modes - - - (most modes can go to the BAD or MEM mode -- not shown for clarity) - - Process header: - HEAD -> (gzip) or (zlib) - (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME - NAME -> COMMENT -> HCRC -> TYPE - (zlib) -> DICTID or TYPE - DICTID -> DICT -> TYPE - Read deflate blocks: - TYPE -> STORED or TABLE or LEN or CHECK - STORED -> COPY -> TYPE - TABLE -> LENLENS -> CODELENS -> LEN - Read deflate codes: - LEN -> LENEXT or LIT or TYPE - LENEXT -> DIST -> DISTEXT -> MATCH -> LEN - LIT -> LEN - Process trailer: - CHECK -> LENGTH -> DONE - */ - -/* state maintained between inflate() calls. Approximately 7K bytes. */ -struct inflate_state { - inflate_mode mode; /* current inflate mode */ - int last; /* true if processing last block */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - int havedict; /* true if dictionary provided */ - int flags; /* gzip header method and flags (0 if zlib) */ - unsigned long check; /* protected copy of check value */ - unsigned long total; /* protected copy of output count */ - /* sliding window */ - unsigned wbits; /* log base 2 of requested window size */ - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned write; /* window write index */ - unsigned char FAR *window; /* allocated sliding window, if needed */ - /* bit accumulator */ - unsigned long hold; /* input bit accumulator */ - unsigned bits; /* number of bits in "in" */ - /* for string and stored block copying */ - unsigned length; /* literal or length of data to copy */ - unsigned offset; /* distance back to copy string from */ - /* for table and code decoding */ - unsigned extra; /* extra bits needed */ - /* fixed and dynamic code tables */ - code const FAR *lencode; /* starting table for length/literal codes */ - code const FAR *distcode; /* starting table for distance codes */ - unsigned lenbits; /* index bits for lencode */ - unsigned distbits; /* index bits for distcode */ - /* dynamic table building */ - unsigned ncode; /* number of code length code lengths */ - unsigned nlen; /* number of length code lengths */ - unsigned ndist; /* number of distance code lengths */ - unsigned have; /* number of code lengths in lens[] */ - code FAR *next; /* next available space in codes[] */ - unsigned short lens[320]; /* temporary storage for code lengths */ - unsigned short work[288]; /* work area for code table building */ - code codes[ENOUGH]; /* space for code tables */ -}; +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ +#ifdef GUNZIP + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ +#endif + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ +#ifdef GUNZIP + LENGTH, /* i: waiting for 32-bit length (gzip) */ +#endif + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/plugins/zerogs/opengl/Win32/zlib/inftrees.c b/plugins/zerogs/opengl/Win32/zlib/inftrees.c index 55fd27b601..3bb56398e1 100644 --- a/plugins/zerogs/opengl/Win32/zlib/inftrees.c +++ b/plugins/zerogs/opengl/Win32/zlib/inftrees.c @@ -1,321 +1,321 @@ -/* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" - -#define MAXBITS 15 - -const char inflate_copyright[] = - " inflate 1.2.1 Copyright 1995-2003 Mark Adler "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* - Build a set of tables to decode the provided canonical Huffman code. - The code lengths are lens[0..codes-1]. The result starts at *table, - whose indices are 0..2^bits-1. work is a writable array of at least - lens shorts, which is used as a work area. type is the type of code - to be generated, CODES, LENS, or DISTS. On return, zero is success, - -1 is an invalid code, and +1 means that ENOUGH isn't enough. table - on return points to the next available entry's address. bits is the - requested root table index bits, and on return it is the actual root - table index bits. It will differ if the request is greater than the - longest code or if it is less than the shortest code. - */ -int inflate_table(type, lens, codes, table, bits, work) -codetype type; -unsigned short FAR *lens; -unsigned codes; -code FAR * FAR *table; -unsigned FAR *bits; -unsigned short FAR *work; -{ - unsigned len; /* a code's length in bits */ - unsigned sym; /* index of code symbols */ - unsigned min, max; /* minimum and maximum code lengths */ - unsigned root; /* number of index bits for root table */ - unsigned curr; /* number of index bits for current table */ - unsigned drop; /* code bits to drop for sub-table */ - int left; /* number of prefix codes available */ - unsigned used; /* code entries in table used */ - unsigned huff; /* Huffman code */ - unsigned incr; /* for incrementing code, index */ - unsigned fill; /* index for replicating entries */ - unsigned low; /* low bits for current root entry */ - unsigned mask; /* mask for low root bits */ - code this; /* table entry for duplication */ - code FAR *next; /* next available space in table */ - const unsigned short FAR *base; /* base value table to use */ - const unsigned short FAR *extra; /* extra bits table to use */ - int end; /* use base and extra for symbol > end */ - unsigned short count[MAXBITS+1]; /* number of codes of each length */ - unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ - static const unsigned short lbase[31] = { /* Length codes 257..285 base */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - static const unsigned short lext[31] = { /* Length codes 257..285 extra */ - 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 76, 66}; - static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577, 0, 0}; - static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ - 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, - 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, - 28, 28, 29, 29, 64, 64}; - - /* - Process a set of code lengths to create a canonical Huffman code. The - code lengths are lens[0..codes-1]. Each length corresponds to the - symbols 0..codes-1. The Huffman code is generated by first sorting the - symbols by length from short to long, and retaining the symbol order - for codes with equal lengths. Then the code starts with all zero bits - for the first code of the shortest length, and the codes are integer - increments for the same length, and zeros are appended as the length - increases. For the deflate format, these bits are stored backwards - from their more natural integer increment ordering, and so when the - decoding tables are built in the large loop below, the integer codes - are incremented backwards. - - This routine assumes, but does not check, that all of the entries in - lens[] are in the range 0..MAXBITS. The caller must assure this. - 1..MAXBITS is interpreted as that code length. zero means that that - symbol does not occur in this code. - - The codes are sorted by computing a count of codes for each length, - creating from that a table of starting indices for each length in the - sorted table, and then entering the symbols in order in the sorted - table. The sorted table is work[], with that space being provided by - the caller. - - The length counts are used for other purposes as well, i.e. finding - the minimum and maximum length codes, determining if there are any - codes at all, checking for a valid set of lengths, and looking ahead - at length counts to determine sub-table sizes when building the - decoding tables. - */ - - /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ - for (len = 0; len <= MAXBITS; len++) - count[len] = 0; - for (sym = 0; sym < codes; sym++) - count[lens[sym]]++; - - /* bound code lengths, force root to be within code lengths */ - root = *bits; - for (max = MAXBITS; max >= 1; max--) - if (count[max] != 0) break; - if (root > max) root = max; - if (max == 0) return -1; /* no codes! */ - for (min = 1; min <= MAXBITS; min++) - if (count[min] != 0) break; - if (root < min) root = min; - - /* check for an over-subscribed or incomplete set of lengths */ - left = 1; - for (len = 1; len <= MAXBITS; len++) { - left <<= 1; - left -= count[len]; - if (left < 0) return -1; /* over-subscribed */ - } - if (left > 0 && (type == CODES || (codes - count[0] != 1))) - return -1; /* incomplete set */ - - /* generate offsets into symbol table for each length for sorting */ - offs[1] = 0; - for (len = 1; len < MAXBITS; len++) - offs[len + 1] = offs[len] + count[len]; - - /* sort symbols by length, by symbol order within each length */ - for (sym = 0; sym < codes; sym++) - if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; - - /* - Create and fill in decoding tables. In this loop, the table being - filled is at next and has curr index bits. The code being used is huff - with length len. That code is converted to an index by dropping drop - bits off of the bottom. For codes where len is less than drop + curr, - those top drop + curr - len bits are incremented through all values to - fill the table with replicated entries. - - root is the number of index bits for the root table. When len exceeds - root, sub-tables are created pointed to by the root entry with an index - of the low root bits of huff. This is saved in low to check for when a - new sub-table should be started. drop is zero when the root table is - being filled, and drop is root when sub-tables are being filled. - - When a new sub-table is needed, it is necessary to look ahead in the - code lengths to determine what size sub-table is needed. The length - counts are used for this, and so count[] is decremented as codes are - entered in the tables. - - used keeps track of how many table entries have been allocated from the - provided *table space. It is checked when a LENS table is being made - against the space in *table, ENOUGH, minus the maximum space needed by - the worst case distance code, MAXD. This should never happen, but the - sufficiency of ENOUGH has not been proven exhaustively, hence the check. - This assumes that when type == LENS, bits == 9. - - sym increments through all symbols, and the loop terminates when - all codes of length max, i.e. all codes, have been processed. This - routine permits incomplete codes, so another loop after this one fills - in the rest of the decoding tables with invalid code markers. - */ - - /* set up for code type */ - switch (type) { - case CODES: - base = extra = work; /* dummy value--not used */ - end = 19; - break; - case LENS: - base = lbase; - base -= 257; - extra = lext; - extra -= 257; - end = 256; - break; - default: /* DISTS */ - base = dbase; - extra = dext; - end = -1; - } - - /* initialize state for loop */ - huff = 0; /* starting code */ - sym = 0; /* starting code symbol */ - len = min; /* starting code length */ - next = *table; /* current table to fill in */ - curr = root; /* current table index bits */ - drop = 0; /* current bits to drop from code for index */ - low = (unsigned)(-1); /* trigger new sub-table when len > root */ - used = 1U << root; /* use root table entries */ - mask = used - 1; /* mask for comparing low */ - - /* check available table space */ - if (type == LENS && used >= ENOUGH - MAXD) - return 1; - - /* process all codes and make table entries */ - for (;;) { - /* create table entry */ - this.bits = (unsigned char)(len - drop); - if ((int)(work[sym]) < end) { - this.op = (unsigned char)0; - this.val = work[sym]; - } - else if ((int)(work[sym]) > end) { - this.op = (unsigned char)(extra[work[sym]]); - this.val = base[work[sym]]; - } - else { - this.op = (unsigned char)(32 + 64); /* end of block */ - this.val = 0; - } - - /* replicate for those indices with low len bits equal to huff */ - incr = 1U << (len - drop); - fill = 1U << curr; - do { - fill -= incr; - next[(huff >> drop) + fill] = this; - } while (fill != 0); - - /* backwards increment the len-bit code huff */ - incr = 1U << (len - 1); - while (huff & incr) - incr >>= 1; - if (incr != 0) { - huff &= incr - 1; - huff += incr; - } - else - huff = 0; - - /* go to next symbol, update count, len */ - sym++; - if (--(count[len]) == 0) { - if (len == max) break; - len = lens[work[sym]]; - } - - /* create new sub-table if needed */ - if (len > root && (huff & mask) != low) { - /* if first time, transition to sub-tables */ - if (drop == 0) - drop = root; - - /* increment past last table */ - next += 1U << curr; - - /* determine length of next table */ - curr = len - drop; - left = (int)(1 << curr); - while (curr + drop < max) { - left -= count[curr + drop]; - if (left <= 0) break; - curr++; - left <<= 1; - } - - /* check for enough space */ - used += 1U << curr; - if (type == LENS && used >= ENOUGH - MAXD) - return 1; - - /* point entry in root table to sub-table */ - low = huff & mask; - (*table)[low].op = (unsigned char)curr; - (*table)[low].bits = (unsigned char)root; - (*table)[low].val = (unsigned short)(next - *table); - } - } - - /* - Fill in rest of table for incomplete codes. This loop is similar to the - loop above in incrementing huff for table indices. It is assumed that - len is equal to curr + drop, so there is no loop needed to increment - through high index bits. When the current sub-table is filled, the loop - drops back to the root table to fill in any remaining entries there. - */ - this.op = (unsigned char)64; /* invalid code marker */ - this.bits = (unsigned char)(len - drop); - this.val = (unsigned short)0; - while (huff != 0) { - /* when done with sub-table, drop back to root table */ - if (drop != 0 && (huff & mask) != low) { - drop = 0; - len = root; - next = *table; - curr = root; - this.bits = (unsigned char)len; - } - - /* put invalid code marker in table */ - next[huff >> drop] = this; - - /* backwards increment the len-bit code huff */ - incr = 1U << (len - 1); - while (huff & incr) - incr >>= 1; - if (incr != 0) { - huff &= incr - 1; - huff += incr; - } - else - huff = 0; - } - - /* set return parameters */ - *table += used; - *bits = root; - return 0; -} +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.1 Copyright 1995-2003 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 76, 66}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) return -1; /* no codes! */ + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || (codes - count[0] != 1))) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += 1U << curr; + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + curr = root; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/plugins/zerogs/opengl/Win32/zlib/inftrees.h b/plugins/zerogs/opengl/Win32/zlib/inftrees.h index 1dbfe53a6a..82d365a7e9 100644 --- a/plugins/zerogs/opengl/Win32/zlib/inftrees.h +++ b/plugins/zerogs/opengl/Win32/zlib/inftrees.h @@ -1,55 +1,55 @@ -/* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* Structure for decoding tables. Each entry provides either the - information needed to do the operation requested by the code that - indexed that table entry, or it provides a pointer to another - table that indexes more bits of the code. op indicates whether - the entry is a pointer to another table, a literal, a length or - distance, an end-of-block, or an invalid code. For a table - pointer, the low four bits of op is the number of index bits of - that table. For a length or distance, the low four bits of op - is the number of extra bits to get after the code. bits is - the number of bits in this code or part of the code to drop off - of the bit buffer. val is the actual byte to output in the case - of a literal, the base length or distance, or the offset from - the current table to the next table. Each entry is four bytes. */ -typedef struct { - unsigned char op; /* operation, extra bits, table bits */ - unsigned char bits; /* bits in this part of the code */ - unsigned short val; /* offset in table or code value */ -} code; - -/* op values as set by inflate_table(): - 00000000 - literal - 0000tttt - table link, tttt != 0 is the number of table index bits - 0001eeee - length or distance, eeee is the number of extra bits - 01100000 - end of block - 01000000 - invalid code - */ - -/* Maximum size of dynamic tree. The maximum found in a long but non- - exhaustive search was 1004 code structures (850 for length/literals - and 154 for distances, the latter actually the result of an - exhaustive search). The true maximum is not known, but the value - below is more than safe. */ -#define ENOUGH 1440 -#define MAXD 154 - -/* Type of code to build for inftable() */ -typedef enum { - CODES, - LENS, - DISTS -} codetype; - -extern int inflate_table OF((codetype type, unsigned short FAR *lens, - unsigned codes, code FAR * FAR *table, - unsigned FAR *bits, unsigned short FAR *work)); +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 code structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 1440 +#define MAXD 154 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/plugins/zerogs/opengl/Win32/zlib/trees.c b/plugins/zerogs/opengl/Win32/zlib/trees.c index d0bce9f2f1..b0c6e41c70 100644 --- a/plugins/zerogs/opengl/Win32/zlib/trees.c +++ b/plugins/zerogs/opengl/Win32/zlib/trees.c @@ -1,1215 +1,1215 @@ -/* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2003 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process uses several Huffman trees. The more - * common source values are represented by shorter bit sequences. - * - * Each code tree is stored in a compressed form which is itself - * a Huffman encoding of the lengths of all the code strings (in - * ascending order by source values). The actual code strings are - * reconstructed from the lengths in the inflate process, as described - * in the deflate specification. - * - * REFERENCES - * - * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". - * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc - * - * Storer, James A. - * Data Compression: Methods and Theory, pp. 49-50. - * Computer Science Press, 1988. ISBN 0-7167-8156-5. - * - * Sedgewick, R. - * Algorithms, p290. - * Addison-Wesley, 1983. ISBN 0-201-06672-6. - */ - -/* @(#) $Id: trees.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ - -/* #define GEN_TREES_H */ - -#include "deflate.h" - -#ifdef DEBUG -# include -#endif - -/* =========================================================================== - * Constants - */ - -#define MAX_BL_BITS 7 -/* Bit length codes must not exceed MAX_BL_BITS bits */ - -#define END_BLOCK 256 -/* end of block literal code */ - -#define REP_3_6 16 -/* repeat previous bit length 3-6 times (2 bits of repeat count) */ - -#define REPZ_3_10 17 -/* repeat a zero length 3-10 times (3 bits of repeat count) */ - -#define REPZ_11_138 18 -/* repeat a zero length 11-138 times (7 bits of repeat count) */ - -local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ - = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; - -local const int extra_dbits[D_CODES] /* extra bits for each distance code */ - = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ - = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; - -local const uch bl_order[BL_CODES] - = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; -/* The lengths of the bit length codes are sent in order of decreasing - * probability, to avoid transmitting the lengths for unused bit length codes. - */ - -#define Buf_size (8 * 2*sizeof(char)) -/* Number of bits used within bi_buf. (bi_buf might be implemented on - * more than 16 bits on some systems.) - */ - -/* =========================================================================== - * Local data. These are initialized only once. - */ - -#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ - -#if defined(GEN_TREES_H) || !defined(STDC) -/* non ANSI compilers may not accept trees.h */ - -local ct_data static_ltree[L_CODES+2]; -/* The static literal tree. Since the bit lengths are imposed, there is no - * need for the L_CODES extra codes used during heap construction. However - * The codes 286 and 287 are needed to build a canonical tree (see _tr_init - * below). - */ - -local ct_data static_dtree[D_CODES]; -/* The static distance tree. (Actually a trivial tree since all codes use - * 5 bits.) - */ - -uch _dist_code[DIST_CODE_LEN]; -/* Distance codes. The first 256 values correspond to the distances - * 3 .. 258, the last 256 values correspond to the top 8 bits of - * the 15 bit distances. - */ - -uch _length_code[MAX_MATCH-MIN_MATCH+1]; -/* length code for each normalized match length (0 == MIN_MATCH) */ - -local int base_length[LENGTH_CODES]; -/* First normalized length for each code (0 = MIN_MATCH) */ - -local int base_dist[D_CODES]; -/* First normalized distance for each code (0 = distance of 1) */ - -#else -# include "trees.h" -#endif /* GEN_TREES_H */ - -struct static_tree_desc_s { - const ct_data *static_tree; /* static tree or NULL */ - const intf *extra_bits; /* extra bits for each code or NULL */ - int extra_base; /* base index for extra_bits */ - int elems; /* max number of elements in the tree */ - int max_length; /* max bit length for the codes */ -}; - -local static_tree_desc static_l_desc = -{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; - -local static_tree_desc static_d_desc = -{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; - -local static_tree_desc static_bl_desc = -{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; - -/* =========================================================================== - * Local (static) routines in this file. - */ - -local void tr_static_init OF((void)); -local void init_block OF((deflate_state *s)); -local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); -local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); -local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); -local void build_tree OF((deflate_state *s, tree_desc *desc)); -local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local int build_bl_tree OF((deflate_state *s)); -local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, - int blcodes)); -local void compress_block OF((deflate_state *s, ct_data *ltree, - ct_data *dtree)); -local void set_data_type OF((deflate_state *s)); -local unsigned bi_reverse OF((unsigned value, int length)); -local void bi_windup OF((deflate_state *s)); -local void bi_flush OF((deflate_state *s)); -local void copy_block OF((deflate_state *s, charf *buf, unsigned len, - int header)); - -#ifdef GEN_TREES_H -local void gen_trees_header OF((void)); -#endif - -#ifndef DEBUG -# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) - /* Send a code of the given tree. c and tree must not have side effects */ - -#else /* DEBUG */ -# define send_code(s, c, tree) \ - { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ - send_bits(s, tree[c].Code, tree[c].Len); } -#endif - -/* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ -#define put_short(s, w) { \ - put_byte(s, (uch)((w) & 0xff)); \ - put_byte(s, (uch)((ush)(w) >> 8)); \ -} - -/* =========================================================================== - * Send a value on a given number of bits. - * IN assertion: length <= 16 and value fits in length bits. - */ -#ifdef DEBUG -local void send_bits OF((deflate_state *s, int value, int length)); - -local void send_bits(s, value, length) - deflate_state *s; - int value; /* value to send */ - int length; /* number of bits */ -{ - Tracevv((stderr," l %2d v %4x ", length, value)); - Assert(length > 0 && length <= 15, "invalid length"); - s->bits_sent += (ulg)length; - - /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) - * unused bits in value. - */ - if (s->bi_valid > (int)Buf_size - length) { - s->bi_buf |= (value << s->bi_valid); - put_short(s, s->bi_buf); - s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); - s->bi_valid += length - Buf_size; - } else { - s->bi_buf |= value << s->bi_valid; - s->bi_valid += length; - } -} -#else /* !DEBUG */ - -#define send_bits(s, value, length) \ -{ int len = length;\ - if (s->bi_valid > (int)Buf_size - len) {\ - int val = value;\ - s->bi_buf |= (val << s->bi_valid);\ - put_short(s, s->bi_buf);\ - s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ - s->bi_valid += len - Buf_size;\ - } else {\ - s->bi_buf |= (value) << s->bi_valid;\ - s->bi_valid += len;\ - }\ -} -#endif /* DEBUG */ - - -/* the arguments must not have side effects */ - -/* =========================================================================== - * Initialize the various 'constant' tables. - */ -local void tr_static_init() -{ -#if defined(GEN_TREES_H) || !defined(STDC) - static int static_init_done = 0; - int n; /* iterates over tree elements */ - int bits; /* bit counter */ - int length; /* length value */ - int code; /* code value */ - int dist; /* distance index */ - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - if (static_init_done) return; - - /* For some embedded targets, global variables are not initialized: */ - static_l_desc.static_tree = static_ltree; - static_l_desc.extra_bits = extra_lbits; - static_d_desc.static_tree = static_dtree; - static_d_desc.extra_bits = extra_dbits; - static_bl_desc.extra_bits = extra_blbits; - - /* Initialize the mapping length (0..255) -> length code (0..28) */ - length = 0; - for (code = 0; code < LENGTH_CODES-1; code++) { - base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ - dist = 0; - for (code = 0 ; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ - for ( ; code < D_CODES; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { - _dist_code[256 + dist++] = (uch)code; - } - } - Assert (dist == 256, "tr_static_init: 256+dist != 512"); - - /* Construct the codes of the static literal tree */ - for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; - n = 0; - while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; - while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; - while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; - while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; - /* Codes 286 and 287 do not exist, but we must include them in the - * tree construction to get a canonical Huffman tree (longest code - * all ones) - */ - gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); - - /* The static distance tree is trivial: */ - for (n = 0; n < D_CODES; n++) { - static_dtree[n].Len = 5; - static_dtree[n].Code = bi_reverse((unsigned)n, 5); - } - static_init_done = 1; - -# ifdef GEN_TREES_H - gen_trees_header(); -# endif -#endif /* defined(GEN_TREES_H) || !defined(STDC) */ -} - -/* =========================================================================== - * Genererate the file trees.h describing the static trees. - */ -#ifdef GEN_TREES_H -# ifndef DEBUG -# include -# endif - -# define SEPARATOR(i, last, width) \ - ((i) == (last)? "\n};\n\n" : \ - ((i) % (width) == (width)-1 ? ",\n" : ", ")) - -void gen_trees_header() -{ - FILE *header = fopen("trees.h", "w"); - int i; - - Assert (header != NULL, "Can't open trees.h"); - fprintf(header, - "/* header created automatically with -DGEN_TREES_H */\n\n"); - - fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); - for (i = 0; i < L_CODES+2; i++) { - fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, - static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); - } - - fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); - for (i = 0; i < D_CODES; i++) { - fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, - static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); - } - - fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); - for (i = 0; i < DIST_CODE_LEN; i++) { - fprintf(header, "%2u%s", _dist_code[i], - SEPARATOR(i, DIST_CODE_LEN-1, 20)); - } - - fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); - for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { - fprintf(header, "%2u%s", _length_code[i], - SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); - } - - fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); - for (i = 0; i < LENGTH_CODES; i++) { - fprintf(header, "%1u%s", base_length[i], - SEPARATOR(i, LENGTH_CODES-1, 20)); - } - - fprintf(header, "local const int base_dist[D_CODES] = {\n"); - for (i = 0; i < D_CODES; i++) { - fprintf(header, "%5u%s", base_dist[i], - SEPARATOR(i, D_CODES-1, 10)); - } - - fclose(header); -} -#endif /* GEN_TREES_H */ - -/* =========================================================================== - * Initialize the tree data structures for a new zlib stream. - */ -void _tr_init(s) - deflate_state *s; -{ - tr_static_init(); - - s->l_desc.dyn_tree = s->dyn_ltree; - s->l_desc.stat_desc = &static_l_desc; - - s->d_desc.dyn_tree = s->dyn_dtree; - s->d_desc.stat_desc = &static_d_desc; - - s->bl_desc.dyn_tree = s->bl_tree; - s->bl_desc.stat_desc = &static_bl_desc; - - s->bi_buf = 0; - s->bi_valid = 0; - s->last_eob_len = 8; /* enough lookahead for inflate */ -#ifdef DEBUG - s->compressed_len = 0L; - s->bits_sent = 0L; -#endif - - /* Initialize the first block of the first file: */ - init_block(s); -} - -/* =========================================================================== - * Initialize a new block. - */ -local void init_block(s) - deflate_state *s; -{ - int n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; - for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; - for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; - - s->dyn_ltree[END_BLOCK].Freq = 1; - s->opt_len = s->static_len = 0L; - s->last_lit = s->matches = 0; -} - -#define SMALLEST 1 -/* Index within the heap array of least frequent node in the Huffman tree */ - - -/* =========================================================================== - * Remove the smallest element from the heap and recreate the heap with - * one less element. Updates heap and heap_len. - */ -#define pqremove(s, tree, top) \ -{\ - top = s->heap[SMALLEST]; \ - s->heap[SMALLEST] = s->heap[s->heap_len--]; \ - pqdownheap(s, tree, SMALLEST); \ -} - -/* =========================================================================== - * Compares to subtrees, using the tree depth as tie breaker when - * the subtrees have equal frequency. This minimizes the worst case length. - */ -#define smaller(tree, n, m, depth) \ - (tree[n].Freq < tree[m].Freq || \ - (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) - -/* =========================================================================== - * Restore the heap property by moving down the tree starting at node k, - * exchanging a node with the smallest of its two sons if necessary, stopping - * when the heap property is re-established (each father smaller than its - * two sons). - */ -local void pqdownheap(s, tree, k) - deflate_state *s; - ct_data *tree; /* the tree to restore */ - int k; /* node to move down */ -{ - int v = s->heap[k]; - int j = k << 1; /* left son of k */ - while (j <= s->heap_len) { - /* Set j to the smallest of the two sons: */ - if (j < s->heap_len && - smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { - j++; - } - /* Exit if v is smaller than both sons */ - if (smaller(tree, v, s->heap[j], s->depth)) break; - - /* Exchange v with the smallest son */ - s->heap[k] = s->heap[j]; k = j; - - /* And continue down the tree, setting j to the left son of k */ - j <<= 1; - } - s->heap[k] = v; -} - -/* =========================================================================== - * Compute the optimal bit lengths for a tree and update the total bit length - * for the current block. - * IN assertion: the fields freq and dad are set, heap[heap_max] and - * above are the tree nodes sorted by increasing frequency. - * OUT assertions: the field len is set to the optimal bit length, the - * array bl_count contains the frequencies for each bit length. - * The length opt_len is updated; static_len is also updated if stree is - * not null. - */ -local void gen_bitlen(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ -{ - ct_data *tree = desc->dyn_tree; - int max_code = desc->max_code; - const ct_data *stree = desc->stat_desc->static_tree; - const intf *extra = desc->stat_desc->extra_bits; - int base = desc->stat_desc->extra_base; - int max_length = desc->stat_desc->max_length; - int h; /* heap index */ - int n, m; /* iterate over the tree elements */ - int bits; /* bit length */ - int xbits; /* extra bits */ - ush f; /* frequency */ - int overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; - - /* In a first pass, compute the optimal bit lengths (which may - * overflow in the case of the bit length tree). - */ - tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - - for (h = s->heap_max+1; h < HEAP_SIZE; h++) { - n = s->heap[h]; - bits = tree[tree[n].Dad].Len + 1; - if (bits > max_length) bits = max_length, overflow++; - tree[n].Len = (ush)bits; - /* We overwrite tree[n].Dad which is no longer needed */ - - if (n > max_code) continue; /* not a leaf node */ - - s->bl_count[bits]++; - xbits = 0; - if (n >= base) xbits = extra[n-base]; - f = tree[n].Freq; - s->opt_len += (ulg)f * (bits + xbits); - if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); - } - if (overflow == 0) return; - - Trace((stderr,"\nbit length overflow\n")); - /* This happens for example on obj2 and pic of the Calgary corpus */ - - /* Find the first bit length which could increase: */ - do { - bits = max_length-1; - while (s->bl_count[bits] == 0) bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ - s->bl_count[max_length]--; - /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] - */ - overflow -= 2; - } while (overflow > 0); - - /* Now recompute all bit lengths, scanning in increasing frequency. - * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - * lengths instead of fixing only the wrong ones. This idea is taken - * from 'ar' written by Haruhiko Okumura.) - */ - for (bits = max_length; bits != 0; bits--) { - n = s->bl_count[bits]; - while (n != 0) { - m = s->heap[--h]; - if (m > max_code) continue; - if (tree[m].Len != (unsigned) bits) { - Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); - s->opt_len += ((long)bits - (long)tree[m].Len) - *(long)tree[m].Freq; - tree[m].Len = (ush)bits; - } - n--; - } - } -} - -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -local void gen_codes (tree, max_code, bl_count) - ct_data *tree; /* the tree to decorate */ - int max_code; /* largest code with non zero frequency */ - ushf *bl_count; /* number of codes at each bit length */ -{ - ush next_code[MAX_BITS+1]; /* next code value for each bit length */ - ush code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (code + bl_count[bits-1]) << 1; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; - const ct_data *stree = desc->stat_desc->static_tree; - int elems = desc->stat_desc->elems; - int n, m; /* iterate over heap elements */ - int max_code = -1; /* largest code with non zero frequency */ - int node; /* new node being created */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - s->heap_len = 0, s->heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) { - if (tree[n].Freq != 0) { - s->heap[++(s->heap_len)] = max_code = n; - s->depth[n] = 0; - } else { - tree[n].Len = 0; - } - } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (s->heap_len < 2) { - node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); - tree[node].Freq = 1; - s->depth[node] = 0; - s->opt_len--; if (stree) s->static_len -= stree[node].Len; - /* node is 0 or 1 so it does not have extra bits */ - } - desc->max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - node = elems; /* next internal node of the tree */ - do { - pqremove(s, tree, n); /* n = node of least frequency */ - m = s->heap[SMALLEST]; /* m = node of next least frequency */ - - s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ - s->heap[--(s->heap_max)] = m; - - /* Create a new node father of n and m */ - tree[node].Freq = tree[n].Freq + tree[m].Freq; - s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? - s->depth[n] : s->depth[m]) + 1); - tree[n].Dad = tree[m].Dad = (ush)node; -#ifdef DUMP_BL_TREE - if (tree == s->bl_tree) { - fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", - node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); - } -#endif - /* and insert the new node in the heap */ - s->heap[SMALLEST] = node++; - pqdownheap(s, tree, SMALLEST); - - } while (s->heap_len >= 2); - - s->heap[--(s->heap_max)] = s->heap[SMALLEST]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen(s, (tree_desc *)desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes ((ct_data *)tree, max_code, s->bl_count); -} - -/* =========================================================================== - * Scan a literal or distance tree to determine the frequencies of the codes - * in the bit length tree. - */ -local void scan_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].Len = (ush)0xffff; /* guard */ - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - s->bl_tree[curlen].Freq += count; - } else if (curlen != 0) { - if (curlen != prevlen) s->bl_tree[curlen].Freq++; - s->bl_tree[REP_3_6].Freq++; - } else if (count <= 10) { - s->bl_tree[REPZ_3_10].Freq++; - } else { - s->bl_tree[REPZ_11_138].Freq++; - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Send a literal or distance tree in compressed form, using the codes in - * bl_tree. - */ -local void send_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - /* tree[max_code+1].Len = -1; */ /* guard already set */ - if (nextlen == 0) max_count = 138, min_count = 3; - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - do { send_code(s, curlen, s->bl_tree); } while (--count != 0); - - } else if (curlen != 0) { - if (curlen != prevlen) { - send_code(s, curlen, s->bl_tree); count--; - } - Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); - - } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); - - } else { - send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Construct the Huffman tree for the bit lengths and return the index in - * bl_order of the last bit length code to send. - */ -local int build_bl_tree(s) - deflate_state *s; -{ - int max_blindex; /* index of last bit length code of non zero freq */ - - /* Determine the bit length frequencies for literal and distance trees */ - scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); - scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); - - /* Build the bit length tree: */ - build_tree(s, (tree_desc *)(&(s->bl_desc))); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - */ - - /* Determine the number of bit length codes to send. The pkzip format - * requires that at least 4 bit length codes be sent. (appnote.txt says - * 3 but the actual value used is 4.) - */ - for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { - if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; - } - /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*(max_blindex+1) + 5+5+4; - Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", - s->opt_len, s->static_len)); - - return max_blindex; -} - -/* =========================================================================== - * Send the header for a block using dynamic Huffman trees: the counts, the - * lengths of the bit length codes, the literal tree and the distance tree. - * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - */ -local void send_all_trees(s, lcodes, dcodes, blcodes) - deflate_state *s; - int lcodes, dcodes, blcodes; /* number of codes for each tree */ -{ - int rank; /* index in bl_order */ - - Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); - Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, - "too many codes"); - Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ - for (rank = 0; rank < blcodes; rank++) { - Tracev((stderr, "\nbl code %2d ", bl_order[rank])); - send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); - } - Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ - Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ - Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); -} - -/* =========================================================================== - * Send a stored block - */ -void _tr_stored_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ -{ - send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ -#ifdef DEBUG - s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; - s->compressed_len += (stored_len + 4) << 3; -#endif - copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ -} - -/* =========================================================================== - * Send one empty static block to give enough lookahead for inflate. - * This takes 10 bits, of which 7 may remain in the bit buffer. - * The current inflate code requires 9 bits of lookahead. If the - * last two codes for the previous block (real code plus EOB) were coded - * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode - * the last real code. In this case we send two empty static blocks instead - * of one. (There are no problems if the previous block is stored or fixed.) - * To simplify the code, we assume the worst case of last real code encoded - * on one bit only. - */ -void _tr_align(s) - deflate_state *s; -{ - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); -#ifdef DEBUG - s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ -#endif - bi_flush(s); - /* Of the 10 bits for the empty block, we have already sent - * (10 - bi_valid) bits. The lookahead for the last real code (before - * the EOB of the previous block) was thus at least one plus the length - * of the EOB plus what we have just sent of the empty static block. - */ - if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); -#ifdef DEBUG - s->compressed_len += 10L; -#endif - bi_flush(s); - } - s->last_eob_len = 7; -} - -/* =========================================================================== - * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. - */ -void _tr_flush_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block, or NULL if too old */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ -{ - ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ - int max_blindex = 0; /* index of last bit length code of non zero freq */ - - /* Build the Huffman trees unless a stored block is forced */ - if (s->level > 0) { - - /* Check if the file is ascii or binary */ - if (s->data_type == Z_UNKNOWN) set_data_type(s); - - /* Construct the literal and distance trees */ - build_tree(s, (tree_desc *)(&(s->l_desc))); - Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - - build_tree(s, (tree_desc *)(&(s->d_desc))); - Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ - - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(s); - - /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; - - Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", - opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - s->last_lit)); - - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; - - } else { - Assert(buf != (char*)0, "lost buf"); - opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ - } - -#ifdef FORCE_STORED - if (buf != (char*)0) { /* force stored block */ -#else - if (stored_len+4 <= opt_lenb && buf != (char*)0) { - /* 4: two words for the lengths */ -#endif - /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - * Otherwise we can't have processed more than WSIZE input bytes since - * the last block flush, because compression would have been - * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - * transform a block into a stored block. - */ - _tr_stored_block(s, buf, stored_len, eof); - -#ifdef FORCE_STATIC - } else if (static_lenb >= 0) { /* force static trees */ -#else - } else if (static_lenb == opt_lenb) { -#endif - send_bits(s, (STATIC_TREES<<1)+eof, 3); - compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); -#ifdef DEBUG - s->compressed_len += 3 + s->static_len; -#endif - } else { - send_bits(s, (DYN_TREES<<1)+eof, 3); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, - max_blindex+1); - compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); -#ifdef DEBUG - s->compressed_len += 3 + s->opt_len; -#endif - } - Assert (s->compressed_len == s->bits_sent, "bad compressed size"); - /* The above check is made mod 2^32, for files larger than 512 MB - * and uLong implemented on 32 bits. - */ - init_block(s); - - if (eof) { - bi_windup(s); -#ifdef DEBUG - s->compressed_len += 7; /* align on byte boundary */ -#endif - } - Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - s->compressed_len-7*eof)); -} - -/* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ -int _tr_tally (s, dist, lc) - deflate_state *s; - unsigned dist; /* distance of matched string */ - unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ -{ - s->d_buf[s->last_lit] = (ush)dist; - s->l_buf[s->last_lit++] = (uch)lc; - if (dist == 0) { - /* lc is the unmatched char */ - s->dyn_ltree[lc].Freq++; - } else { - s->matches++; - /* Here, lc is the match length - MIN_MATCH */ - dist--; /* dist = match distance - 1 */ - Assert((ush)dist < (ush)MAX_DIST(s) && - (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && - (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - - s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; - s->dyn_dtree[d_code(dist)].Freq++; - } - -#ifdef TRUNCATE_BLOCK - /* Try to guess if it is profitable to stop the current block here */ - if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { - /* Compute an upper bound for the compressed length */ - ulg out_length = (ulg)s->last_lit*8L; - ulg in_length = (ulg)((long)s->strstart - s->block_start); - int dcode; - for (dcode = 0; dcode < D_CODES; dcode++) { - out_length += (ulg)s->dyn_dtree[dcode].Freq * - (5L+extra_dbits[dcode]); - } - out_length >>= 3; - Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", - s->last_lit, in_length, out_length, - 100L - out_length*100L/in_length)); - if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; - } -#endif - return (s->last_lit == s->lit_bufsize-1); - /* We avoid equality with lit_bufsize because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ -} - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -local void compress_block(s, ltree, dtree) - deflate_state *s; - ct_data *ltree; /* literal tree */ - ct_data *dtree; /* distance tree */ -{ - unsigned dist; /* distance of matched string */ - int lc; /* match length or unmatched char (if dist == 0) */ - unsigned lx = 0; /* running index in l_buf */ - unsigned code; /* the code to send */ - int extra; /* number of extra bits to send */ - - if (s->last_lit != 0) do { - dist = s->d_buf[lx]; - lc = s->l_buf[lx++]; - if (dist == 0) { - send_code(s, lc, ltree); /* send a literal byte */ - Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = _length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra != 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra != 0) { - dist -= base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ - Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, - "pendingBuf overflow"); - - } while (lx < s->last_lit); - - send_code(s, END_BLOCK, ltree); - s->last_eob_len = ltree[END_BLOCK].Len; -} - -/* =========================================================================== - * Set the data type to ASCII or BINARY, using a crude approximation: - * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. - * IN assertion: the fields freq of dyn_ltree are set and the total of all - * frequencies does not exceed 64K (to fit in an int on 16 bit machines). - */ -local void set_data_type(s) - deflate_state *s; -{ - int n = 0; - unsigned ascii_freq = 0; - unsigned bin_freq = 0; - while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; - while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; - while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; - s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); -} - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -local unsigned bi_reverse(code, len) - unsigned code; /* the value to invert */ - int len; /* its bit length */ -{ - register unsigned res = 0; - do { - res |= code & 1; - code >>= 1, res <<= 1; - } while (--len > 0); - return res >> 1; -} - -/* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ -local void bi_flush(s) - deflate_state *s; -{ - if (s->bi_valid == 16) { - put_short(s, s->bi_buf); - s->bi_buf = 0; - s->bi_valid = 0; - } else if (s->bi_valid >= 8) { - put_byte(s, (Byte)s->bi_buf); - s->bi_buf >>= 8; - s->bi_valid -= 8; - } -} - -/* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ -local void bi_windup(s) - deflate_state *s; -{ - if (s->bi_valid > 8) { - put_short(s, s->bi_buf); - } else if (s->bi_valid > 0) { - put_byte(s, (Byte)s->bi_buf); - } - s->bi_buf = 0; - s->bi_valid = 0; -#ifdef DEBUG - s->bits_sent = (s->bits_sent+7) & ~7; -#endif -} - -/* =========================================================================== - * Copy a stored block, storing first the length and its - * one's complement if requested. - */ -local void copy_block(s, buf, len, header) - deflate_state *s; - charf *buf; /* the input data */ - unsigned len; /* its length */ - int header; /* true if block header must be written */ -{ - bi_windup(s); /* align on byte boundary */ - s->last_eob_len = 8; /* enough lookahead for inflate */ - - if (header) { - put_short(s, (ush)len); - put_short(s, (ush)~len); -#ifdef DEBUG - s->bits_sent += 2*16; -#endif - } -#ifdef DEBUG - s->bits_sent += (ulg)len<<3; -#endif - while (len--) { - put_byte(s, *buf++); - } -} +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2003 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id: trees.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if (tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is ascii or binary */ + if (s->data_type == Z_UNKNOWN) set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +local void set_data_type(s) + deflate_state *s; +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; + while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; + while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; + s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/plugins/zerogs/opengl/Win32/zlib/trees.h b/plugins/zerogs/opengl/Win32/zlib/trees.h index 1ca868b848..72facf900f 100644 --- a/plugins/zerogs/opengl/Win32/zlib/trees.h +++ b/plugins/zerogs/opengl/Win32/zlib/trees.h @@ -1,128 +1,128 @@ -/* header created automatically with -DGEN_TREES_H */ - -local const ct_data static_ltree[L_CODES+2] = { -{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, -{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, -{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, -{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, -{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, -{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, -{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, -{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, -{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, -{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, -{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, -{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, -{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, -{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, -{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, -{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, -{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, -{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, -{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, -{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, -{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, -{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, -{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, -{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, -{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, -{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, -{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, -{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, -{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, -{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, -{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, -{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, -{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, -{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, -{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, -{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, -{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, -{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, -{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, -{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, -{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, -{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, -{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, -{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, -{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, -{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, -{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, -{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, -{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, -{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, -{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, -{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, -{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, -{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, -{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, -{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, -{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, -{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} -}; - -local const ct_data static_dtree[D_CODES] = { -{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, -{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, -{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, -{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, -{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, -{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} -}; - -const uch _dist_code[DIST_CODE_LEN] = { - 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, - 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, -10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, -11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, -12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, -18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 -}; - -const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, -13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, -17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, -19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, -21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, -22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 -}; - -local const int base_length[LENGTH_CODES] = { -0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, -64, 80, 96, 112, 128, 160, 192, 224, 0 -}; - -local const int base_dist[D_CODES] = { - 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, - 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, - 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 -}; - +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/plugins/zerogs/opengl/Win32/zlib/uncompr.c b/plugins/zerogs/opengl/Win32/zlib/uncompr.c index 82ebef75f8..12eec9fec9 100644 --- a/plugins/zerogs/opengl/Win32/zlib/uncompr.c +++ b/plugins/zerogs/opengl/Win32/zlib/uncompr.c @@ -1,61 +1,61 @@ -/* uncompr.c -- decompress a memory buffer - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id: uncompr.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -/* =========================================================================== - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted. -*/ -int ZEXPORT uncompress (dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ - z_stream stream; - int err; - - stream.next_in = (Bytef*)source; - stream.avail_in = (uInt)sourceLen; - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; - - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; - - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - - err = inflateInit(&stream); - if (err != Z_OK) return err; - - err = inflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - inflateEnd(&stream); - if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) - return Z_DATA_ERROR; - return err; - } - *destLen = stream.total_out; - - err = inflateEnd(&stream); - return err; -} +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: uncompr.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/plugins/zerogs/opengl/Win32/zlib/zconf.h b/plugins/zerogs/opengl/Win32/zlib/zconf.h index b073c9e60d..1277c7ce17 100644 --- a/plugins/zerogs/opengl/Win32/zlib/zconf.h +++ b/plugins/zerogs/opengl/Win32/zlib/zconf.h @@ -1,323 +1,323 @@ -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id: zconf.h,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ - -#ifndef ZCONF_H -#define ZCONF_H - -/* - * If you *really* need a unique prefix for all types and library functions, - * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. - */ -#ifdef Z_PREFIX -# define deflateInit_ z_deflateInit_ -# define deflate z_deflate -# define deflateEnd z_deflateEnd -# define inflateInit_ z_inflateInit_ -# define inflate z_inflate -# define inflateEnd z_inflateEnd -# define deflateInit2_ z_deflateInit2_ -# define deflateSetDictionary z_deflateSetDictionary -# define deflateCopy z_deflateCopy -# define deflateReset z_deflateReset -# define deflatePrime z_deflatePrime -# define deflateParams z_deflateParams -# define deflateBound z_deflateBound -# define inflateInit2_ z_inflateInit2_ -# define inflateSetDictionary z_inflateSetDictionary -# define inflateSync z_inflateSync -# define inflateSyncPoint z_inflateSyncPoint -# define inflateCopy z_inflateCopy -# define inflateReset z_inflateReset -# define compress z_compress -# define compress2 z_compress2 -# define compressBound z_compressBound -# define uncompress z_uncompress -# define adler32 z_adler32 -# define crc32 z_crc32 -# define get_crc_table z_get_crc_table - -# define Byte z_Byte -# define uInt z_uInt -# define uLong z_uLong -# define Bytef z_Bytef -# define charf z_charf -# define intf z_intf -# define uIntf z_uIntf -# define uLongf z_uLongf -# define voidpf z_voidpf -# define voidp z_voidp -#endif - -#if defined(__MSDOS__) && !defined(MSDOS) -# define MSDOS -#endif -#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) -# define OS2 -#endif -#if defined(_WINDOWS) && !defined(WINDOWS) -# define WINDOWS -#endif -#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) -# define WIN32 -#endif -#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) -# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) -# ifndef SYS16BIT -# define SYS16BIT -# endif -# endif -#endif - -/* - * Compile with -DMAXSEG_64K if the alloc function cannot allocate more - * than 64k bytes at a time (needed on systems with 16-bit int). - */ -#ifdef SYS16BIT -# define MAXSEG_64K -#endif -#ifdef MSDOS -# define UNALIGNED_OK -#endif - -#ifdef __STDC_VERSION__ -# ifndef STDC -# define STDC -# endif -# if __STDC_VERSION__ >= 199901L -# ifndef STDC99 -# define STDC99 -# endif -# endif -#endif -#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) -# define STDC -#endif -#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) -# define STDC -#endif -#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) -# define STDC -#endif -#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) -# define STDC -#endif - -#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ -# define STDC -#endif - -#ifndef STDC -# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ -# define const /* note: need a more gentle solution here */ -# endif -#endif - -/* Some Mac compilers merge all .h files incorrectly: */ -#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) -# define NO_DUMMY_DECL -#endif - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# ifdef MAXSEG_64K -# define MAX_MEM_LEVEL 8 -# else -# define MAX_MEM_LEVEL 9 -# endif -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2. - * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files - * created by gzip. (Files created by minigzip can still be extracted by - * gzip.) - */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - (1 << (windowBits+2)) + (1 << (memLevel+9)) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects. -*/ - - /* Type declarations */ - -#ifndef OF /* function prototypes */ -# ifdef STDC -# define OF(args) args -# else -# define OF(args) () -# endif -#endif - -/* The following definitions for FAR are needed only for MSDOS mixed - * model programming (small or medium model with some far allocations). - * This was tested only with MSC; for other MSDOS compilers you may have - * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, - * just define FAR to be empty. - */ -#ifdef SYS16BIT -# if defined(M_I86SM) || defined(M_I86MM) - /* MSC small or medium model */ -# define SMALL_MEDIUM -# ifdef _MSC_VER -# define FAR _far -# else -# define FAR far -# endif -# endif -# if (defined(__SMALL__) || defined(__MEDIUM__)) - /* Turbo C small or medium model */ -# define SMALL_MEDIUM -# ifdef __BORLANDC__ -# define FAR _far -# else -# define FAR far -# endif -# endif -#endif - -#if defined(WINDOWS) || defined(WIN32) - /* If building or using zlib as a DLL, define ZLIB_DLL. - * This is not mandatory, but it offers a little performance increase. - */ -# ifdef ZLIB_DLL -# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) -# ifdef ZLIB_INTERNAL -# define ZEXTERN extern __declspec(dllexport) -# else -# define ZEXTERN extern __declspec(dllimport) -# endif -# endif -# endif /* ZLIB_DLL */ - /* If building or using zlib with the WINAPI/WINAPIV calling convention, - * define ZLIB_WINAPI. - * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. - */ -# ifdef ZLIB_WINAPI -# ifdef FAR -# undef FAR -# endif -# include - /* No need for _export, use ZLIB.DEF instead. */ - /* For complete Windows compatibility, use WINAPI, not __stdcall. */ -# define ZEXPORT WINAPI -# ifdef WIN32 -# define ZEXPORTVA WINAPIV -# else -# define ZEXPORTVA FAR CDECL -# endif -# endif -#endif - -#if defined (__BEOS__) -# ifdef ZLIB_DLL -# ifdef ZLIB_INTERNAL -# define ZEXPORT __declspec(dllexport) -# define ZEXPORTVA __declspec(dllexport) -# else -# define ZEXPORT __declspec(dllimport) -# define ZEXPORTVA __declspec(dllimport) -# endif -# endif -#endif - -#ifndef ZEXTERN -# define ZEXTERN extern -#endif -#ifndef ZEXPORT -# define ZEXPORT -#endif -#ifndef ZEXPORTVA -# define ZEXPORTVA -#endif - -#ifndef FAR -# define FAR -#endif - -#if !defined(__MACTYPES__) -typedef unsigned char Byte; /* 8 bits */ -#endif -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ - -#ifdef SMALL_MEDIUM - /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ -# define Bytef Byte FAR -#else - typedef Byte FAR Bytef; -#endif -typedef char FAR charf; -typedef int FAR intf; -typedef uInt FAR uIntf; -typedef uLong FAR uLongf; - -#ifdef STDC - typedef void const *voidpc; - typedef void FAR *voidpf; - typedef void *voidp; -#else - typedef Byte const *voidpc; - typedef Byte FAR *voidpf; - typedef Byte *voidp; -#endif - -#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ -# include /* for off_t */ -# include /* for SEEK_* and off_t */ -# ifdef VMS -# include /* for off_t */ -# endif -# define z_off_t off_t -#endif -#ifndef SEEK_SET -# define SEEK_SET 0 /* Seek from beginning of file. */ -# define SEEK_CUR 1 /* Seek from current position. */ -# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ -#endif -#ifndef z_off_t -# define z_off_t long -#endif - -#if defined(__OS400__) -#define NO_vsnprintf -#endif - -#if defined(__MVS__) -# define NO_vsnprintf -# ifdef FAR -# undef FAR -# endif -#endif - -/* MVS linker does not support external names larger than 8 bytes */ -#if defined(__MVS__) -# pragma map(deflateInit_,"DEIN") -# pragma map(deflateInit2_,"DEIN2") -# pragma map(deflateEnd,"DEEND") -# pragma map(deflateBound,"DEBND") -# pragma map(inflateInit_,"ININ") -# pragma map(inflateInit2_,"ININ2") -# pragma map(inflateEnd,"INEND") -# pragma map(inflateSync,"INSY") -# pragma map(inflateSetDictionary,"INSEDI") -# pragma map(compressBound,"CMBND") -# pragma map(inflate_table,"INTABL") -# pragma map(inflate_fast,"INFA") -# pragma map(inflate_copyright,"INCOPY") -#endif - -#endif /* ZCONF_H */ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.h,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflatePrime z_deflatePrime +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +#define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/plugins/zerogs/opengl/Win32/zlib/zlib.h b/plugins/zerogs/opengl/Win32/zlib/zlib.h index d54ac9433f..92edf96ff3 100644 --- a/plugins/zerogs/opengl/Win32/zlib/zlib.h +++ b/plugins/zerogs/opengl/Win32/zlib/zlib.h @@ -1,1200 +1,1200 @@ -/* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.1, November 17th, 2003 - - Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - - - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). -*/ - -#ifndef ZLIB_H -#define ZLIB_H - -#include "zconf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define ZLIB_VERSION "1.2.1" -#define ZLIB_VERNUM 0x1210 - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed - data. This version of the library supports only one compression method - (deflation) but other algorithms will be added later and will have the same - stream interface. - - Compression can be done in a single step if the buffers are large - enough (for example if an input file is mmap'ed), or can be done by - repeated calls of the compression function. In the latter case, the - application must provide more input and/or consume the output - (providing more output space) before each call. - - The compressed data format used by the in-memory functions is the zlib - format, which is a zlib wrapper documented in RFC 1950, wrapped around a - deflate stream, which is itself documented in RFC 1951. - - The library also supports reading and writing files in gzip (.gz) format - with an interface similar to that of stdio using the functions that start - with "gz". The gzip format is different from the zlib format. gzip is a - gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. - - The zlib format was designed to be compact and fast for use in memory - and on communications channels. The gzip format was designed for single- - file compression on file systems, has a larger header than zlib to maintain - directory information, and uses a different, slower check method than zlib. - - This library does not provide any functions to write gzip files in memory. - However such functions could be easily written using zlib's deflate function, - the documentation in the gzip RFC, and the examples in gzio.c. - - The library does not install any signal handler. The decoder checks - the consistency of the compressed data, so the library should never - crash even in case of corrupted input. -*/ - -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address)); - -struct internal_state; - -typedef struct z_stream_s { - Bytef *next_in; /* next input byte */ - uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total nb of input bytes read so far */ - - Bytef *next_out; /* next output byte should be put there */ - uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total nb of bytes output so far */ - - char *msg; /* last error message, NULL if no error */ - struct internal_state FAR *state; /* not visible by applications */ - - alloc_func zalloc; /* used to allocate the internal state */ - free_func zfree; /* used to free the internal state */ - voidpf opaque; /* private data object passed to zalloc and zfree */ - - int data_type; /* best guess about the data type: ascii or binary */ - uLong adler; /* adler32 value of the uncompressed data */ - uLong reserved; /* reserved for future use */ -} z_stream; - -typedef z_stream FAR *z_streamp; - -/* - The application must update next_in and avail_in when avail_in has - dropped to zero. It must update next_out and avail_out when avail_out - has dropped to zero. The application must initialize zalloc, zfree and - opaque before calling the init function. All other fields are set by the - compression library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - If zlib is used in a multi-threaded application, zalloc and zfree must be - thread safe. - - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this - if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, - pointers returned by zalloc for objects of exactly 65536 bytes *must* - have their offset normalized to zero. The default allocation function - provided by this library ensures this (see zutil.c). To reduce memory - requirements and avoid any allocation of 64K objects, at the expense of - compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or - progress reports. After compression, total_in holds the total size of - the uncompressed data and may be saved for use in the decompressor - (particularly if the decompressor wants to decompress everything in - a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ -#define Z_SYNC_FLUSH 2 -#define Z_FULL_FLUSH 3 -#define Z_FINISH 4 -#define Z_BLOCK 5 -/* Allowed flush values; see deflate() and inflate() below for details */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_NEED_DICT 2 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -#define Z_VERSION_ERROR (-6) -/* Return codes for the compression/decompression functions. Negative - * values are errors, positive values are used for special but normal events. - */ - -#define Z_NO_COMPRESSION 0 -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_RLE 3 -#define Z_DEFAULT_STRATEGY 0 -/* compression strategy; see deflateInit2() below for details */ - -#define Z_BINARY 0 -#define Z_ASCII 1 -#define Z_UNKNOWN 2 -/* Possible values of the data_type field (though see inflate()) */ - -#define Z_DEFLATED 8 -/* The deflate compression method (the only one supported in this version) */ - -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - -#define zlib_version zlibVersion() -/* for compatibility with versions < 1.0.2 */ - - /* basic functions */ - -ZEXTERN const char * ZEXPORT zlibVersion OF((void)); -/* The application can compare zlibVersion and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is - not compatible with the zlib.h header file used by the application. - This check is automatically made by deflateInit and inflateInit. - */ - -/* -ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); - - Initializes the internal stream state for compression. The fields - zalloc, zfree and opaque must be initialized before by the caller. - If zalloc and zfree are set to Z_NULL, deflateInit updates them to - use default allocation functions. - - The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: - 1 gives best speed, 9 gives best compression, 0 gives no compression at - all (the input data is simply copied a block at a time). - Z_DEFAULT_COMPRESSION requests a default compromise between speed and - compression (currently equivalent to level 6). - - deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if level is not a valid compression level, - Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible - with the version assumed by the caller (ZLIB_VERSION). - msg is set to null if there is no error message. deflateInit does not - perform any compression: this will be done by deflate(). -*/ - - -ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); -/* - deflate compresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce some - output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. deflate performs one or both of the - following actions: - - - Compress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in and avail_in are updated and - processing will resume at this point for the next call of deflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. This action is forced if the parameter flush is non zero. - Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary (in interactive applications). - Some output may be provided even if flush is not set. - - Before the call of deflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating avail_in or avail_out accordingly; avail_out - should never be zero before the call. The application can consume the - compressed output when it wants, for example when the output buffer is full - (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK - and with zero avail_out, it must be called again after making room in the - output buffer because there might be more output pending. - - If the parameter flush is set to Z_SYNC_FLUSH, all pending output is - flushed to the output buffer and the output is aligned on a byte boundary, so - that the decompressor can get all input data available so far. (In particular - avail_in is zero after the call if enough output space has been provided - before the call.) Flushing may degrade compression for some compression - algorithms and so it should be used only when necessary. - - If flush is set to Z_FULL_FLUSH, all output is flushed as with - Z_SYNC_FLUSH, and the compression state is reset so that decompression can - restart from this point if previous compressed data has been damaged or if - random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - the compression. - - If deflate returns with avail_out == 0, this function must be called again - with the same value of the flush parameter and more output space (updated - avail_out), until the flush is complete (deflate returns with non-zero - avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that - avail_out is greater than six to avoid repeated flush markers due to - avail_out == 0 on return. - - If the parameter flush is set to Z_FINISH, pending input is processed, - pending output is flushed and deflate returns with Z_STREAM_END if there - was enough output space; if deflate returns with Z_OK, this function must be - called again with Z_FINISH and more output space (updated avail_out) but no - more input data, until it returns with Z_STREAM_END or an error. After - deflate has returned Z_STREAM_END, the only possible operations on the - stream are deflateReset or deflateEnd. - - Z_FINISH can be used immediately after deflateInit if all the compression - is to be done in a single step. In this case, avail_out must be at least - the value returned by deflateBound (see below). If deflate does not return - Z_STREAM_END, then it must be called again as described above. - - deflate() sets strm->adler to the adler32 checksum of all input read - so far (that is, total_in bytes). - - deflate() may update data_type if it can make a good guess about - the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered - binary. This field is only for information purposes and does not affect - the compression algorithm in any manner. - - deflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if all input has been - consumed and all output has been produced (only when flush is set to - Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible - (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not - fatal, and deflate() can be called again with more input and more output - space to continue compressing. -*/ - - -ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the - stream state was inconsistent, Z_DATA_ERROR if the stream was freed - prematurely (some input or output was discarded). In the error case, - msg may be set but then points to a static string (which must not be - deallocated). -*/ - - -/* -ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); - - Initializes the internal stream state for decompression. The fields - next_in, avail_in, zalloc, zfree and opaque must be initialized before by - the caller. If next_in is not Z_NULL and avail_in is large enough (the exact - value depends on the compression method), inflateInit determines the - compression method from the zlib header and allocates all data structures - accordingly; otherwise the allocation will be deferred to the first call of - inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to - use default allocation functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller. msg is set to null if there is no error - message. inflateInit does not perform any decompression apart from reading - the zlib header if present: this will be done by inflate(). (So next_in and - avail_in may be modified, but next_out and avail_out are unchanged.) -*/ - - -ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); -/* - inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce - some output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. inflate performs one or both of the - following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing - will resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() provides as much output as possible, until there - is no more input data or no more space in the output buffer (see below - about the flush parameter). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating the next_* and avail_* values accordingly. - The application can consume the uncompressed output when it wants, for - example when the output buffer is full (avail_out == 0), or after each - call of inflate(). If inflate returns Z_OK and with zero avail_out, it - must be called again after making room in the output buffer because there - might be more output pending. - - The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, - Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much - output as possible to the output buffer. Z_BLOCK requests that inflate() stop - if and when it get to the next deflate block boundary. When decoding the zlib - or gzip format, this will cause inflate() to return immediately after the - header and before the first block. When doing a raw inflate, inflate() will - go ahead and process the first block, and will return when it gets to the end - of that block, or when it runs out of data. - - The Z_BLOCK option assists in appending to or combining deflate streams. - Also to assist in this, on return inflate() will set strm->data_type to the - number of unused bits in the last byte taken from strm->next_in, plus 64 - if inflate() is currently decoding the last block in the deflate stream, - plus 128 if inflate() returned immediately after decoding an end-of-block - code or decoding the complete header up to just before the first byte of the - deflate stream. The end-of-block will not be indicated until all of the - uncompressed data from that block has been written to strm->next_out. The - number of unused bits may in general be greater than seven, except when - bit 7 of data_type is set, in which case the number of unused bits will be - less than eight. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step - (a single call of inflate), the parameter flush should be set to - Z_FINISH. In this case all pending input is processed and all pending - output is flushed; avail_out must be large enough to hold all the - uncompressed data. (The size of the uncompressed data may have been saved - by the compressor for this purpose.) The next operation on this stream must - be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster approach - may be used for the single inflate() call. - - In this implementation, inflate() always flushes as much output as - possible to the output buffer, and always uses the faster approach on the - first call. So the only effect of the flush parameter in this implementation - is on the return value of inflate(), as noted below, or when it returns early - because Z_BLOCK is used. - - If a preset dictionary is needed after this call (see inflateSetDictionary - below), inflate sets strm-adler to the adler32 checksum of the dictionary - chosen by the compressor and returns Z_NEED_DICT; otherwise it sets - strm->adler to the adler32 checksum of all output produced so far (that is, - total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described - below. At the end of the stream, inflate() checks that its computed adler32 - checksum is equal to that saved by the compressor and returns Z_STREAM_END - only if the checksum is correct. - - inflate() will decompress and check either zlib-wrapped or gzip-wrapped - deflate data. The header type is detected automatically. Any information - contained in the gzip header is not retained, so applications that need that - information should instead use raw inflate, see inflateInit2() below, or - inflateBack() and perform their own processing of the gzip header and - trailer. - - inflate() returns Z_OK if some progress has been made (more input processed - or more output produced), Z_STREAM_END if the end of the compressed data has - been reached and all uncompressed output has been produced, Z_NEED_DICT if a - preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect check - value), Z_STREAM_ERROR if the stream structure was inconsistent (for example - if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, - Z_BUF_ERROR if no progress is possible or if there was not enough room in the - output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and - inflate() can be called again with more input and more output space to - continue decompressing. If Z_DATA_ERROR is returned, the application may then - call inflateSync() to look for a good compression block if a partial recovery - of the data is desired. -*/ - - -ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). -*/ - - /* Advanced functions */ - -/* - The following functions are needed only in some special applications. -*/ - -/* -ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); - - This is another version of deflateInit with more compression options. The - fields next_in, zalloc, zfree and opaque must be initialized before by - the caller. - - The method parameter is the compression method. It must be Z_DEFLATED in - this version of the library. - - The windowBits parameter is the base two logarithm of the window size - (the size of the history buffer). It should be in the range 8..15 for this - version of the library. Larger values of this parameter result in better - compression at the expense of memory usage. The default value is 15 if - deflateInit is used instead. - - windowBits can also be -8..-15 for raw deflate. In this case, -windowBits - determines the window size. deflate() will then generate raw deflate data - with no zlib header or trailer, and will not compute an adler32 check value. - - windowBits can also be greater than 15 for optional gzip encoding. Add - 16 to windowBits to write a simple gzip header and trailer around the - compressed data instead of a zlib wrapper. The gzip header will have no - file name, no extra data, no comment, no modification time (set to zero), - no header crc, and the operating system will be set to 255 (unknown). - - The memLevel parameter specifies how much memory should be allocated - for the internal compression state. memLevel=1 uses minimum memory but - is slow and reduces compression ratio; memLevel=9 uses maximum memory - for optimal speed. The default value is 8. See zconf.h for total memory - usage as a function of windowBits and memLevel. - - The strategy parameter is used to tune the compression algorithm. Use the - value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match), or Z_RLE to limit match distances to one (run-length - encoding). Filtered data consists mostly of small values with a somewhat - random distribution. In this case, the compression algorithm is tuned to - compress them better. The effect of Z_FILTERED is to force more Huffman - coding and less string matching; it is somewhat intermediate between - Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as - Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy - parameter only affects the compression ratio but not the correctness of the - compressed output even if it is not set appropriately. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid - method). msg is set to null if there is no error message. deflateInit2 does - not perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the compression dictionary from the given byte sequence - without producing any compressed output. This function must be called - immediately after deflateInit, deflateInit2 or deflateReset, before any - call of deflate. The compressor and decompressor must use exactly the same - dictionary (see inflateSetDictionary). - - The dictionary should consist of strings (byte sequences) that are likely - to be encountered later in the data to be compressed, with the most commonly - used strings preferably put towards the end of the dictionary. Using a - dictionary is most useful when the data to be compressed is short and can be - predicted with good accuracy; the data can then be compressed better than - with the default empty dictionary. - - Depending on the size of the compression data structures selected by - deflateInit or deflateInit2, a part of the dictionary may in effect be - discarded, for example if the dictionary is larger than the window size in - deflate or deflate2. Thus the strings most likely to be useful should be - put at the end of the dictionary, not at the front. - - Upon return of this function, strm->adler is set to the adler32 value - of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The adler32 value - applies to the whole dictionary even if only a subset of the dictionary is - actually used by the compressor.) If a raw deflate was requested, then the - adler32 value is not computed and strm->adler is not set. - - deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent (for example if deflate has already been called for this stream - or if the compression method is bsort). deflateSetDictionary does not - perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when several compression strategies will be - tried, for example when there are several ways of pre-processing the input - data with a filter. The streams that will be discarded should then be freed - by calling deflateEnd. Note that deflateCopy duplicates the internal - compression state which can be quite large, so this strategy is slow and - can consume lots of memory. - - deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); -/* - This function is equivalent to deflateEnd followed by deflateInit, - but does not free and reallocate all the internal compression state. - The stream will keep the same compression level and any other attributes - that may have been set by deflateInit2. - - deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, - int level, - int strategy)); -/* - Dynamically update the compression level and compression strategy. The - interpretation of level and strategy is as in deflateInit2. This can be - used to switch between compression and straight copy of the input data, or - to switch to a different kind of input data requiring a different - strategy. If the compression level is changed, the input available so far - is compressed with the old level (and may be flushed); the new level will - take effect only at the next call of deflate(). - - Before the call of deflateParams, the stream state must be set as for - a call of deflate(), since the currently available input may have to - be compressed and flushed. In particular, strm->avail_out must be non-zero. - - deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source - stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR - if strm->avail_out was zero. -*/ - -ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, - uLong sourceLen)); -/* - deflateBound() returns an upper bound on the compressed size after - deflation of sourceLen bytes. It must be called after deflateInit() - or deflateInit2(). This would be used to allocate an output buffer - for deflation in a single pass, and so would be called before deflate(). -*/ - -ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - deflatePrime() inserts bits in the deflate output stream. The intent - is that this function is used to start off the deflate output with the - bits leftover from a previous deflate stream when appending to it. As such, - this function can only be used for raw deflate, and must be used before the - first deflate() call after a deflateInit2() or deflateReset(). bits must be - less than or equal to 16, and that many of the least significant bits of - value will be inserted in the output. - - deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, - int windowBits)); - - This is another version of inflateInit with an extra parameter. The - fields next_in, avail_in, zalloc, zfree and opaque must be initialized - before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library. The default value is 15 if inflateInit is used - instead. windowBits must be greater than or equal to the windowBits value - provided to deflateInit2() while compressing, or it must be equal to 15 if - deflateInit2() was not used. If a compressed stream with a larger window - size is given as input, inflate() will return with the error code - Z_DATA_ERROR instead of trying to allocate a larger window. - - windowBits can also be -8..-15 for raw inflate. In this case, -windowBits - determines the window size. inflate() will then process raw deflate data, - not looking for a zlib or gzip header, not generating a check value, and not - looking for any check values for comparison at the end of the stream. This - is for use with other formats that use the deflate compressed data format - such as zip. Those formats provide their own check values. If a custom - format is developed using the raw deflate format for compressed data, it is - recommended that a check value such as an adler32 or a crc32 be applied to - the uncompressed data as is done in the zlib, gzip, and zip formats. For - most applications, the zlib format should be used as is. Note that comments - above on the use in deflateInit2() applies to the magnitude of windowBits. - - windowBits can also be greater than 15 for optional gzip decoding. Add - 32 to windowBits to enable zlib and gzip decoding with automatic header - detection, or add 16 to decode only the gzip format (the zlib format will - return a Z_DATA_ERROR). - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative - memLevel). msg is set to null if there is no error message. inflateInit2 - does not perform any decompression apart from reading the zlib header if - present: this will be done by inflate(). (So next_in and avail_in may be - modified, but next_out and avail_out are unchanged.) -*/ - -ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate - if this call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the adler32 value returned by this call of - inflate. The compressor and decompressor must use exactly the same - dictionary (see deflateSetDictionary). - - inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect adler32 value). inflateSetDictionary does not - perform any decompression: this will be done by subsequent calls of - inflate(). -*/ - -ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); -/* - Skips invalid compressed data until a full flush point (see above the - description of deflate with Z_FULL_FLUSH) can be found, or until all - available input is skipped. No output is provided. - - inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR - if no more input was provided, Z_DATA_ERROR if no flush point has been found, - or Z_STREAM_ERROR if the stream structure was inconsistent. In the success - case, the application may save the current current value of total_in which - indicates where valid compressed data was found. In the error case, the - application may repeatedly call inflateSync, providing more input each time, - until success or end of the input data. -*/ - -ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when randomly accessing a large stream. The - first pass through the stream can periodically record the inflate state, - allowing restarting inflate at those points when randomly accessing the - stream. - - inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); -/* - This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate all the internal decompression state. - The stream will keep attributes that may have been set by inflateInit2. - - inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -/* -ZEXTERN int ZEXPORT inflateBackInit OF((z_stream FAR *strm, int windowBits, - unsigned char FAR *window)); - - Initialize the internal stream state for decompression using inflateBack() - calls. The fields zalloc, zfree and opaque in strm must be initialized - before the call. If zalloc and zfree are Z_NULL, then the default library- - derived memory allocation routines are used. windowBits is the base two - logarithm of the window size, in the range 8..15. window is a caller - supplied buffer of that size. Except for special applications where it is - assured that deflate was used with small window sizes, windowBits must be 15 - and a 32K byte window must be supplied to be able to decompress general - deflate streams. - - See inflateBack() for the usage of these routines. - - inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of - the paramaters are invalid, Z_MEM_ERROR if the internal state could not - be allocated, or Z_VERSION_ERROR if the version of the library does not - match the version of the header file. -*/ - -typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); -typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); - -ZEXTERN int ZEXPORT inflateBack OF((z_stream FAR *strm, - in_func in, void FAR *in_desc, - out_func out, void FAR *out_desc)); -/* - inflateBack() does a raw inflate with a single call using a call-back - interface for input and output. This is more efficient than inflate() for - file i/o applications in that it avoids copying between the output and the - sliding window by simply making the window itself the output buffer. This - function trusts the application to not change the output buffer passed by - the output function, at least until inflateBack() returns. - - inflateBackInit() must be called first to allocate the internal state - and to initialize the state with the user-provided window buffer. - inflateBack() may then be used multiple times to inflate a complete, raw - deflate stream with each call. inflateBackEnd() is then called to free - the allocated state. - - A raw deflate stream is one with no zlib or gzip header or trailer. - This routine would normally be used in a utility that reads zip or gzip - files and writes out uncompressed files. The utility would decode the - header and process the trailer on its own, hence this routine expects - only the raw deflate stream to decompress. This is different from the - normal behavior of inflate(), which expects either a zlib or gzip header and - trailer around the deflate stream. - - inflateBack() uses two subroutines supplied by the caller that are then - called by inflateBack() for input and output. inflateBack() calls those - routines until it reads a complete deflate stream and writes out all of the - uncompressed data, or until it encounters an error. The function's - parameters and return types are defined above in the in_func and out_func - typedefs. inflateBack() will call in(in_desc, &buf) which should return the - number of bytes of provided input, and a pointer to that input in buf. If - there is no input available, in() must return zero--buf is ignored in that - case--and inflateBack() will return a buffer error. inflateBack() will call - out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() - should return zero on success, or non-zero on failure. If out() returns - non-zero, inflateBack() will return with an error. Neither in() nor out() - are permitted to change the contents of the window provided to - inflateBackInit(), which is also the buffer that out() uses to write from. - The length written by out() will be at most the window size. Any non-zero - amount of input may be provided by in(). - - For convenience, inflateBack() can be provided input on the first call by - setting strm->next_in and strm->avail_in. If that input is exhausted, then - in() will be called. Therefore strm->next_in must be initialized before - calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called - immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in - must also be initialized, and then if strm->avail_in is not zero, input will - initially be taken from strm->next_in[0 .. strm->avail_in - 1]. - - The in_desc and out_desc parameters of inflateBack() is passed as the - first parameter of in() and out() respectively when they are called. These - descriptors can be optionally used to pass any information that the caller- - supplied in() and out() functions need to do their job. - - On return, inflateBack() will set strm->next_in and strm->avail_in to - pass back any unused input that was provided by the last in() call. The - return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR - if in() or out() returned an error, Z_DATA_ERROR if there was a format - error in the deflate stream (in which case strm->msg is set to indicate the - nature of the error), or Z_STREAM_ERROR if the stream was not properly - initialized. In the case of Z_BUF_ERROR, an input or output error can be - distinguished using strm->next_in which will be Z_NULL only if in() returned - an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to - out() returning non-zero. (in() will always be called before out(), so - strm->next_in is assured to be defined if out() returns non-zero.) Note - that inflateBack() cannot return Z_OK. -*/ - -ZEXTERN int ZEXPORT inflateBackEnd OF((z_stream FAR *strm)); -/* - All memory allocated by inflateBackInit() is freed. - - inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream - state was inconsistent. -*/ - -ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); -/* Return flags indicating compile-time options. - - Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: - 1.0: size of uInt - 3.2: size of uLong - 5.4: size of voidpf (pointer) - 7.6: size of z_off_t - - Compiler, assembler, and debug options: - 8: DEBUG - 9: ASMV or ASMINF -- use ASM code - 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention - 11: 0 (reserved) - - One-time table building (smaller code, but not thread-safe if true): - 12: BUILDFIXED -- build static block decoding tables when needed - 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed - 14,15: 0 (reserved) - - Library content (indicates missing functionality): - 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking - deflate code when not needed) - 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect - and decode gzip streams (to avoid linking crc code) - 18-19: 0 (reserved) - - Operation variations (changes in library functionality): - 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate - 21: FASTEST -- deflate algorithm with only one, lowest compression level - 22,23: 0 (reserved) - - The sprintf variant used by gzprintf (zero is best): - 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format - 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! - 26: 0 = returns value, 1 = void -- 1 means inferred string length returned - - Remainder: - 27-31: 0 (reserved) - */ - - - /* utility functions */ - -/* - The following utility functions are implemented on top of the - basic stream-oriented functions. To simplify the interface, some - default options are assumed (compression level and memory usage, - standard memory allocation functions). The source code of these - utility functions can easily be modified if you need special options. -*/ - -ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Compresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be at least the value returned - by compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - This function can be used to compress a whole file at once if the - input file is mmap'ed. - compress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer. -*/ - -ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen, - int level)); -/* - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least the value returned by - compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ - -ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); -/* - compressBound() returns an upper bound on the compressed size after - compress() or compress2() on sourceLen bytes. It would be used before - a compress() or compress2() call to allocate the destination buffer. -*/ - -ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. -*/ - - -typedef voidp gzFile; - -ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); -/* - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb") but can also include a compression level - ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for - Huffman only compression as in "wb1h", or 'R' for run-length encoding - as in "wb1R". (See the description of deflateInit2 for more information - about the strategy parameter.) - - gzopen can be used to read a file which is not in gzip format; in this - case gzread will directly read from the file without decompression. - - gzopen returns NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). */ - -ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); -/* - gzdopen() associates a gzFile with the file descriptor fd. File - descriptors are obtained from calls like open, dup, creat, pipe or - fileno (in the file has been previously opened with fopen). - The mode parameter is as in gzopen. - The next call of gzclose on the returned gzFile will also close the - file descriptor fd, just like fclose(fdopen(fd), mode) closes the file - descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). - gzdopen returns NULL if there was insufficient memory to allocate - the (de)compression state. -*/ - -ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); -/* - Dynamically update the compression level or strategy. See the description - of deflateInit2 for the meaning of these parameters. - gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not - opened for writing. -*/ - -ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); -/* - Reads the given number of uncompressed bytes from the compressed file. - If the input file was not in gzip format, gzread copies the given number - of bytes into the buffer. - gzread returns the number of uncompressed bytes actually read (0 for - end of file, -1 for error). */ - -ZEXTERN int ZEXPORT gzwrite OF((gzFile file, - voidpc buf, unsigned len)); -/* - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of uncompressed bytes actually written - (0 in case of error). -*/ - -ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); -/* - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). The number of - uncompressed bytes written is limited to 4095. The caller should assure that - this limit is not exceeded. If it is exceeded, then gzprintf() will return - return an error (0) with nothing written. In this case, there may also be a - buffer overflow with unpredictable consequences, which is possible only if - zlib was compiled with the insecure functions sprintf() or vsprintf() - because the secure snprintf() or vsnprintf() functions were not available. -*/ - -ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); -/* - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. -*/ - -ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); -/* - Reads bytes from the compressed file until len-1 characters are read, or - a newline character is read and transferred to buf, or an end-of-file - condition is encountered. The string is then terminated with a null - character. - gzgets returns buf, or Z_NULL in case of error. -*/ - -ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); -/* - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. -*/ - -ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); -/* - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. -*/ - -ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); -/* - Push one character back onto the stream to be read again later. - Only one character of push-back is allowed. gzungetc() returns the - character pushed, or -1 on failure. gzungetc() will fail if a - character has been pushed but not read yet, or if c is -1. The pushed - character will be discarded if the stream is repositioned with gzseek() - or gzrewind(). -*/ - -ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); -/* - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. The return value is the zlib - error number (see function gzerror below). gzflush returns Z_OK if - the flush parameter is Z_FINISH and all output could be flushed. - gzflush should be called only when strictly necessary because it can - degrade compression. -*/ - -ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, - z_off_t offset, int whence)); -/* - Sets the starting position for the next gzread or gzwrite on the - given compressed file. The offset represents a number of bytes in the - uncompressed data stream. The whence parameter is defined as in lseek(2); - the value SEEK_END is not supported. - If the file is opened for reading, this function is emulated but can be - extremely slow. If the file is opened for writing, only forward seeks are - supported; gzseek then compresses a sequence of zeroes up to the new - starting position. - - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error, in - particular if the file is opened for writing and the new starting position - would be before the current position. -*/ - -ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); -/* - Rewinds the given file. This function is supported only for reading. - - gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) -*/ - -ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); -/* - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. - - gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) -*/ - -ZEXTERN int ZEXPORT gzeof OF((gzFile file)); -/* - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. -*/ - -ZEXTERN int ZEXPORT gzclose OF((gzFile file)); -/* - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. The return value is the zlib - error number (see function gzerror below). -*/ - -ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); -/* - Returns the error message for the last error which occurred on the - given compressed file. errnum is set to zlib error number. If an - error occurred in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. -*/ - -ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); -/* - Clears the error and end-of-file flags for file. This is analogous to the - clearerr() function in stdio. This is useful for continuing to read a gzip - file that is being written concurrently. -*/ - - /* checksum functions */ - -/* - These functions are not related to compression but are exported - anyway because they might be useful in applications using the - compression library. -*/ - -ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); - -/* - Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. If buf is NULL, this function returns - the required initial value for the checksum. - An Adler-32 checksum is almost as reliable as a CRC32 but can be computed - much faster. Usage example: - - uLong adler = adler32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - adler = adler32(adler, buffer, length); - } - if (adler != original_adler) error(); -*/ - -ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); -/* - Update a running crc with the bytes buf[0..len-1] and return the updated - crc. If buf is NULL, this function returns the required initial value - for the crc. Pre- and post-conditioning (one's complement) is performed - within this function so it shouldn't be done by the application. - Usage example: - - uLong crc = crc32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - crc = crc32(crc, buffer, length); - } - if (crc != original_crc) error(); -*/ - - - /* various hacks, don't look :) */ - -/* deflateInit and inflateInit are macros to allow checking the zlib version - * and the compiler's view of z_stream: - */ -ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy, const char *version, - int stream_size)); -ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateBackInit_ OF((z_stream FAR *strm, int windowBits, - unsigned char FAR *window, - const char *version, - int stream_size)); -#define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) -#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) -#define inflateBackInit(strm, windowBits, window) \ - inflateBackInit_((strm), (windowBits), (window), \ - ZLIB_VERSION, sizeof(z_stream)) - - -#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) - struct internal_state {int dummy;}; /* hack for buggy compilers */ -#endif - -ZEXTERN const char * ZEXPORT zError OF((int err)); -ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); -ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); - -#ifdef __cplusplus -} -#endif - -#endif /* ZLIB_H */ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.1, November 17th, 2003 + + Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.1" +#define ZLIB_VERNUM 0x1210 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by the in-memory functions is the zlib + format, which is a zlib wrapper documented in RFC 1950, wrapped around a + deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + This library does not provide any functions to write gzip files in memory. + However such functions could be easily written using zlib's deflate function, + the documentation in the gzip RFC, and the examples in gzio.c. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it get to the next deflate block boundary. When decoding the zlib + or gzip format, this will cause inflate() to return immediately after the + header and before the first block. When doing a raw inflate, inflate() will + go ahead and process the first block, and will return when it gets to the end + of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_stream FAR *strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_stream FAR *strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int err)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/plugins/zerogs/opengl/Win32/zlib/zutil.c b/plugins/zerogs/opengl/Win32/zlib/zutil.c index db137f8a48..646f572d59 100644 --- a/plugins/zerogs/opengl/Win32/zlib/zutil.c +++ b/plugins/zerogs/opengl/Win32/zlib/zutil.c @@ -1,319 +1,319 @@ -/* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id: zutil.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ - -#include "zutil.h" - -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - -#ifndef STDC -extern void exit OF((int)); -#endif - -const char * const z_errmsg[10] = { -"need dictionary", /* Z_NEED_DICT 2 */ -"stream end", /* Z_STREAM_END 1 */ -"", /* Z_OK 0 */ -"file error", /* Z_ERRNO (-1) */ -"stream error", /* Z_STREAM_ERROR (-2) */ -"data error", /* Z_DATA_ERROR (-3) */ -"insufficient memory", /* Z_MEM_ERROR (-4) */ -"buffer error", /* Z_BUF_ERROR (-5) */ -"incompatible version",/* Z_VERSION_ERROR (-6) */ -""}; - - -const char * ZEXPORT zlibVersion() -{ - return ZLIB_VERSION; -} - -uLong ZEXPORT zlibCompileFlags() -{ - uLong flags; - - flags = 0; - switch (sizeof(uInt)) { - case 2: break; - case 4: flags += 1; break; - case 8: flags += 2; break; - default: flags += 3; - } - switch (sizeof(uLong)) { - case 2: break; - case 4: flags += 1 << 2; break; - case 8: flags += 2 << 2; break; - default: flags += 3 << 2; - } - switch (sizeof(voidpf)) { - case 2: break; - case 4: flags += 1 << 4; break; - case 8: flags += 2 << 4; break; - default: flags += 3 << 4; - } - switch (sizeof(z_off_t)) { - case 2: break; - case 4: flags += 1 << 6; break; - case 8: flags += 2 << 6; break; - default: flags += 3 << 6; - } -#ifdef DEBUG - flags += 1 << 8; -#endif -#if defined(ASMV) || defined(ASMINF) - flags += 1 << 9; -#endif -#ifdef ZLIB_WINAPI - flags += 1 << 10; -#endif -#ifdef BUILDFIXED - flags += 1 << 12; -#endif -#ifdef DYNAMIC_CRC_TABLE - flags += 1 << 13; -#endif -#ifdef NO_GZCOMPRESS - flags += 1 << 16; -#endif -#ifdef NO_GZIP - flags += 1 << 17; -#endif -#ifdef PKZIP_BUG_WORKAROUND - flags += 1 << 20; -#endif -#ifdef FASTEST - flags += 1 << 21; -#endif -#ifdef STDC -# ifdef NO_vsnprintf - flags += 1 << 25; -# ifdef HAS_vsprintf_void - flags += 1 << 26; -# endif -# else -# ifdef HAS_vsnprintf_void - flags += 1 << 26; -# endif -# endif -#else - flags += 1 << 24; -# ifdef NO_snprintf - flags += 1 << 25; -# ifdef HAS_sprintf_void - flags += 1 << 26; -# endif -# else -# ifdef HAS_snprintf_void - flags += 1 << 26; -# endif -# endif -#endif - return flags; -} - -#ifdef DEBUG - -# ifndef verbose -# define verbose 0 -# endif -int z_verbose = verbose; - -void z_error (m) - char *m; -{ - fprintf(stderr, "%s\n", m); - exit(1); -} -#endif - -/* exported to allow conversion of error code to string for compress() and - * uncompress() - */ -const char * ZEXPORT zError(err) - int err; -{ - return ERR_MSG(err); -} - -#if defined(_WIN32_WCE) - /* does not exist on WCE */ - int errno = 0; -#endif - -#ifndef HAVE_MEMCPY - -void zmemcpy(dest, source, len) - Bytef* dest; - const Bytef* source; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = *source++; /* ??? to be unrolled */ - } while (--len != 0); -} - -int zmemcmp(s1, s2, len) - const Bytef* s1; - const Bytef* s2; - uInt len; -{ - uInt j; - - for (j = 0; j < len; j++) { - if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; - } - return 0; -} - -void zmemzero(dest, len) - Bytef* dest; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = 0; /* ??? to be unrolled */ - } while (--len != 0); -} -#endif - - -#ifdef SYS16BIT - -#ifdef __TURBOC__ -/* Turbo C in 16-bit mode */ - -# define MY_ZCALLOC - -/* Turbo C malloc() does not allow dynamic allocation of 64K bytes - * and farmalloc(64K) returns a pointer with an offset of 8, so we - * must fix the pointer. Warning: the pointer must be put back to its - * original form in order to free it, use zcfree(). - */ - -#define MAX_PTR 10 -/* 10*64K = 640K */ - -local int next_ptr = 0; - -typedef struct ptr_table_s { - voidpf org_ptr; - voidpf new_ptr; -} ptr_table; - -local ptr_table table[MAX_PTR]; -/* This table is used to remember the original form of pointers - * to large buffers (64K). Such pointers are normalized with a zero offset. - * Since MSDOS is not a preemptive multitasking OS, this table is not - * protected from concurrent access. This hack doesn't work anyway on - * a protected system like OS/2. Use Microsoft C instead. - */ - -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - voidpf buf = opaque; /* just to make some compilers happy */ - ulg bsize = (ulg)items*size; - - /* If we allocate less than 65520 bytes, we assume that farmalloc - * will return a usable pointer which doesn't have to be normalized. - */ - if (bsize < 65520L) { - buf = farmalloc(bsize); - if (*(ush*)&buf != 0) return buf; - } else { - buf = farmalloc(bsize + 16L); - } - if (buf == NULL || next_ptr >= MAX_PTR) return NULL; - table[next_ptr].org_ptr = buf; - - /* Normalize the pointer to seg:0 */ - *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; - *(ush*)&buf = 0; - table[next_ptr++].new_ptr = buf; - return buf; -} - -void zcfree (voidpf opaque, voidpf ptr) -{ - int n; - if (*(ush*)&ptr != 0) { /* object < 64K */ - farfree(ptr); - return; - } - /* Find the original pointer */ - for (n = 0; n < next_ptr; n++) { - if (ptr != table[n].new_ptr) continue; - - farfree(table[n].org_ptr); - while (++n < next_ptr) { - table[n-1] = table[n]; - } - next_ptr--; - return; - } - ptr = opaque; /* just to make some compilers happy */ - Assert(0, "zcfree: ptr not found"); -} - -#endif /* __TURBOC__ */ - - -#ifdef M_I86 -/* Microsoft C in 16-bit mode */ - -# define MY_ZCALLOC - -#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) -# define _halloc halloc -# define _hfree hfree -#endif - -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - if (opaque) opaque = 0; /* to make compiler happy */ - return _halloc((long)items, size); -} - -void zcfree (voidpf opaque, voidpf ptr) -{ - if (opaque) opaque = 0; /* to make compiler happy */ - _hfree(ptr); -} - -#endif /* M_I86 */ - -#endif /* SYS16BIT */ - - -#ifndef MY_ZCALLOC /* Any system without a special alloc function */ - -#ifndef STDC -extern voidp malloc OF((uInt size)); -extern voidp calloc OF((uInt items, uInt size)); -extern void free OF((voidpf ptr)); -#endif - -voidpf zcalloc (opaque, items, size) - voidpf opaque; - unsigned items; - unsigned size; -{ - if (opaque) items += size - size; /* make compiler happy */ - return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : - (voidpf)calloc(items, size); -} - -void zcfree (opaque, ptr) - voidpf opaque; - voidpf ptr; -{ - free(ptr); - if (opaque) return; /* make compiler happy */ -} - -#endif /* MY_ZCALLOC */ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zutil.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef STDC +extern void exit OF((int)); +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1 << 16; +#endif +#ifdef NO_GZIP + flags += 1 << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1 << 20; +#endif +#ifdef FASTEST + flags += 1 << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1 << 25; +# ifdef HAS_vsprintf_void + flags += 1 << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1 << 26; +# endif +# endif +#else + flags += 1 << 24; +# ifdef NO_snprintf + flags += 1 << 25; +# ifdef HAS_sprintf_void + flags += 1 << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1 << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* does not exist on WCE */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/plugins/zerogs/opengl/Win32/zlib/zutil.h b/plugins/zerogs/opengl/Win32/zlib/zutil.h index e300f7c767..d0f21d6d86 100644 --- a/plugins/zerogs/opengl/Win32/zlib/zutil.h +++ b/plugins/zerogs/opengl/Win32/zlib/zutil.h @@ -1,258 +1,258 @@ -/* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2003 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id: zutil.h,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ - -#ifndef ZUTIL_H -#define ZUTIL_H - -#define ZLIB_INTERNAL -#include "zlib.h" - -#ifdef STDC -# include -# include -# include -#endif -#ifdef NO_ERRNO_H - extern int errno; -#else -# include -#endif - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -typedef unsigned char uch; -typedef uch FAR uchf; -typedef unsigned short ush; -typedef ush FAR ushf; -typedef unsigned long ulg; - -extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ -/* (size given to avoid silly warnings with Visual C++) */ - -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] - -#define ERR_RETURN(strm,err) \ - return (strm->msg = (char*)ERR_MSG(err), (err)) -/* To be used only when the state is known to be valid */ - - /* common constants */ - -#ifndef DEF_WBITS -# define DEF_WBITS MAX_WBITS -#endif -/* default windowBits for decompression. MAX_WBITS is for compression only */ - -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -/* default memLevel */ - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - -#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ - - /* target dependencies */ - -#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) -# define OS_CODE 0x00 -# if defined(__TURBOC__) || defined(__BORLANDC__) -# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) - /* Allow compilation with ANSI keywords only enabled */ - void _Cdecl farfree( void *block ); - void *_Cdecl farmalloc( unsigned long nbytes ); -# else -# include -# endif -# else /* MSC or DJGPP */ -# include -# endif -#endif - -#ifdef AMIGA -# define OS_CODE 0x01 -#endif - -#if defined(VAXC) || defined(VMS) -# define OS_CODE 0x02 -# define F_OPEN(name, mode) \ - fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") -#endif - -#if defined(ATARI) || defined(atarist) -# define OS_CODE 0x05 -#endif - -#ifdef OS2 -# define OS_CODE 0x06 -#endif - -#if defined(MACOS) || defined(TARGET_OS_MAC) -# define OS_CODE 0x07 -# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os -# include /* for fdopen */ -# else -# ifndef fdopen -# define fdopen(fd,mode) NULL /* No fdopen() */ -# endif -# endif -#endif - -#ifdef TOPS20 -# define OS_CODE 0x0a -#endif - -#ifdef WIN32 -# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ -# define OS_CODE 0x0b -# endif -#endif - -#ifdef __50SERIES /* Prime/PRIMOS */ -# define OS_CODE 0x0f -#endif - -#if defined(_BEOS_) || defined(RISCOS) -# define fdopen(fd,mode) NULL /* No fdopen() */ -#endif - -#if (defined(_MSC_VER) && (_MSC_VER > 600)) -# if defined(_WIN32_WCE) -# define fdopen(fd,mode) NULL /* No fdopen() */ -# ifndef _PTRDIFF_T_DEFINED - typedef int ptrdiff_t; -# define _PTRDIFF_T_DEFINED -# endif -# else -# define fdopen(fd,type) _fdopen(fd,type) -# endif -#endif - - /* common defaults */ - -#ifndef OS_CODE -# define OS_CODE 0x03 /* assume Unix */ -#endif - -#ifndef F_OPEN -# define F_OPEN(name, mode) fopen((name), (mode)) -#endif - - /* functions */ - -#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif -#if defined(__CYGWIN__) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif -#ifndef HAVE_VSNPRINTF -# ifdef MSDOS - /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), - but for now we just assume it doesn't. */ -# define NO_vsnprintf -# endif -# ifdef __TURBOC__ -# define NO_vsnprintf -# endif -# ifdef WIN32 - /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ -# if !defined(vsnprintf) && !defined(NO_vsnprintf) -# define vsnprintf _vsnprintf -# endif -# endif -# ifdef __SASC -# define NO_vsnprintf -# endif -#endif - -#ifdef HAVE_STRERROR - extern char *strerror OF((int)); -# define zstrerror(errnum) strerror(errnum) -#else -# define zstrerror(errnum) "" -#endif - -#if defined(pyr) -# define NO_MEMCPY -#endif -#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) - /* Use our own functions for small and medium model with MSC <= 5.0. - * You may have to use the same strategy for Borland C (untested). - * The __SC__ check is for Symantec. - */ -# define NO_MEMCPY -#endif -#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) -# define HAVE_MEMCPY -#endif -#ifdef HAVE_MEMCPY -# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ -# define zmemcpy _fmemcpy -# define zmemcmp _fmemcmp -# define zmemzero(dest, len) _fmemset(dest, 0, len) -# else -# define zmemcpy memcpy -# define zmemcmp memcmp -# define zmemzero(dest, len) memset(dest, 0, len) -# endif -#else - extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); - extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); - extern void zmemzero OF((Bytef* dest, uInt len)); -#endif - -/* Diagnostic functions */ -#ifdef DEBUG -# include - extern int z_verbose; - extern void z_error OF((char *m)); -# define Assert(cond,msg) {if(!(cond)) z_error(msg);} -# define Trace(x) {if (z_verbose>=0) fprintf x ;} -# define Tracev(x) {if (z_verbose>0) fprintf x ;} -# define Tracevv(x) {if (z_verbose>1) fprintf x ;} -# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} -# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - - -voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); -void zcfree OF((voidpf opaque, voidpf ptr)); - -#define ZALLOC(strm, items, size) \ - (*((strm)->zalloc))((strm)->opaque, (items), (size)) -#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) -#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} - -#endif /* ZUTIL_H */ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: zutil.h,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/plugins/zerogs/opengl/ZeroGSShaders/Makefile.am b/plugins/zerogs/opengl/ZeroGSShaders/Makefile.am index 97da2236f6..6d409c54d0 100644 --- a/plugins/zerogs/opengl/ZeroGSShaders/Makefile.am +++ b/plugins/zerogs/opengl/ZeroGSShaders/Makefile.am @@ -1,2 +1,2 @@ -noinst_PROGRAMS = zgsbuild -zgsbuild_SOURCES = zpipe.cpp zerogsshaders.cpp +noinst_PROGRAMS = zgsbuild +zgsbuild_SOURCES = zpipe.cpp zerogsshaders.cpp diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zerogsshaders.cpp b/plugins/zerogs/opengl/ZeroGSShaders/zerogsshaders.cpp index a2d7815173..336438912f 100644 --- a/plugins/zerogs/opengl/ZeroGSShaders/zerogsshaders.cpp +++ b/plugins/zerogs/opengl/ZeroGSShaders/zerogsshaders.cpp @@ -1,337 +1,337 @@ -#define _CRT_SECURE_NO_DEPRECATE - -// Builds all possible shader files from ps2hw.fx and stores them in -// a preprocessed database -#include -#include - -#include -#include "zpipe.h" - -#include -#include - -#define SAFE_RELEASE(x) { if( (x) != NULL ) { (x)->Release(); x = NULL; } } - -#include -#include - -using namespace std; - -#include "zerogsshaders.h" - -char* srcfilename = "ps2hw.fx"; -char* dstfilename = "ps2hw.dat"; - -#ifndef ARRAYSIZE -#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0])) -#endif - -struct SHADERINFO -{ - int type; - vector buf; -}; - -map mapShaders; -CGcontext g_cgcontext; - -void LoadShader(int index, const char* pshader, CGprofile prof, vector& vargs, int context) -{ - vector realargs; - realargs.reserve(16); - realargs.resize(vargs.size()); - if( vargs.size() > 0 ) - memcpy(&realargs[0], &vargs[0], realargs.size() * sizeof(realargs[0])); - realargs.push_back(context ? "-Ictx1" : "-Ictx0"); - realargs.push_back(NULL); - - CGprogram prog = cgCreateProgramFromFile(g_cgcontext, CG_SOURCE, srcfilename, prof, pshader, &realargs[0]); - if( !cgIsProgram(prog) ) { - printf("Failed to load shader %s: \n%s\n", pshader, cgGetLastListing(g_cgcontext)); - return; - } - - if( mapShaders.find(index) != mapShaders.end() ) { - printf("error: two shaders share the same index %d\n", index); - exit(0); - } - - if( !cgIsProgramCompiled(prog) ) - cgCompileProgram(prog); - - const char* pstr = cgGetProgramString(prog, CG_COMPILED_PROGRAM); - - const char* pprog = strstr(pstr, "#program"); - if( pprog == NULL ) { - printf("program field not found!\n"); - return; - } - pprog += 9; - const char* progend = strchr(pprog, '\r'); - if( progend == NULL ) progend = strchr(pprog, '\n'); - - if( progend == NULL ) { - printf("prog end not found!\n"); - return; - } - - const char* defname = "main"; - - SHADERINFO info; - info.type = 0; - info.buf.resize(strlen(pstr)+1); - - // change the program name to main - memset(&info.buf[0], 0, info.buf.size()); - memcpy(&info.buf[0], pstr, pprog-pstr); - memcpy(&info.buf[pprog-pstr], defname, 4); - memcpy(&info.buf[pprog-pstr+4], progend, strlen(pstr)-(progend-pstr)); - - if( mapShaders.find(index) != mapShaders.end() ) - printf("same shader\n"); - assert( mapShaders.find(index) == mapShaders.end() ); - mapShaders[index] = info; - - cgDestroyProgram(prog); -} - -int main(int argc, char** argv) -{ - printf("usage: [src] [dst] [opts]\n"); - - if( argc >= 2 ) srcfilename = argv[1]; - if( argc >= 3 ) dstfilename = argv[2]; - - FILE* fsrc = fopen(srcfilename, "r"); - if( fsrc == NULL ) { - printf("cannot open %s\n", srcfilename); - return 0; - } - fclose(fsrc); - - g_cgcontext = cgCreateContext(); - if( !cgIsContext(g_cgcontext) ) { - printf("failed to create cg context\n"); - return -1; - } - - CGprofile cgvProf = CG_PROFILE_ARBVP1; - CGprofile cgfProf = CG_PROFILE_ARBFP1; - if( !cgGLIsProfileSupported(cgvProf) != CG_TRUE ) { - printf("arbvp1 not supported\n"); - return 0; - } - if( !cgGLIsProfileSupported(cgfProf) != CG_TRUE ) { - printf("arbfp1 not supported\n"); - return 0; - } - - cgGLEnableProfile(cgvProf); - cgGLEnableProfile(cgfProf); - cgGLSetOptimalOptions(cgvProf); - cgGLSetOptimalOptions(cgfProf); - - vector vmacros; - - LoadShader(SH_BITBLTVS, "BitBltVS", cgvProf, vmacros, 0); - LoadShader(SH_BITBLTPS, "BitBltPS", cgfProf, vmacros, 0); - LoadShader(SH_BITBLTDEPTHPS, "BitBltDepthPS", cgfProf, vmacros, 0); - LoadShader(SH_BITBLTDEPTHMRTPS, "BitBltDepthMRTPS", cgfProf, vmacros, 0); - LoadShader(SH_CRTCTARGPS, "CRTCTargPS", cgfProf, vmacros, 0); - LoadShader(SH_CRTCPS, "CRTCPS", cgfProf, vmacros, 0); - LoadShader(SH_CRTC_NEARESTPS, "CRTCPS_Nearest", cgfProf, vmacros, 0); - LoadShader(SH_CRTC24PS, "CRTC24PS", cgfProf, vmacros, 0); - LoadShader(SH_ZEROPS, "ZeroPS", cgfProf, vmacros, 0); - LoadShader(SH_BASETEXTUREPS, "BaseTexturePS", cgfProf, vmacros, 0); - LoadShader(SH_BITBLTAAPS, "BitBltPS", cgfProf, vmacros, 0); - LoadShader(SH_CRTCTARGINTERPS, "CRTCTargInterPS", cgfProf, vmacros, 0); - LoadShader(SH_CRTCINTERPS, "CRTCInterPS", cgfProf, vmacros, 0); - LoadShader(SH_CRTCINTER_NEARESTPS, "CRTCInterPS_Nearest", cgfProf, vmacros, 0); - LoadShader(SH_CRTC24INTERPS, "CRTC24InterPS", cgfProf, vmacros, 0); - LoadShader(SH_CONVERT16TO32PS, "Convert16to32PS", cgfProf, vmacros, 0); - LoadShader(SH_CONVERT32TO16PS, "Convert32to16PS", cgfProf, vmacros, 0); - - const int vsshaders[4] = { SH_REGULARVS, SH_TEXTUREVS, SH_REGULARFOGVS, SH_TEXTUREFOGVS }; - const char* pvsshaders[4] = { "RegularVS", "TextureVS", "RegularFogVS", "TextureFogVS" }; - - // load the texture shaders - char str[255], strdir[255]; - - strcpy(strdir, srcfilename); - int i = (int)strlen(strdir); - while(i > 0) { - if( strdir[i-1] == '/' || strdir[i-1] == '\\' ) - break; - --i; - } - - strdir[i] = 0; - - for(i = 0; i < ARRAYSIZE(vsshaders); ++i) { - for(int writedepth = 0; writedepth < 2; ++writedepth ) { - - if( writedepth ) vmacros.push_back("-DWRITE_DEPTH"); - LoadShader(vsshaders[i]|(writedepth?SH_WRITEDEPTH:0), pvsshaders[i], cgvProf, vmacros, 0); - LoadShader(vsshaders[i]|(writedepth?SH_WRITEDEPTH:0)|SH_CONTEXT1, pvsshaders[i], cgvProf, vmacros, 1); - if( writedepth ) vmacros.pop_back(); - } - } - - const int psshaders[2] = { SH_REGULARPS, SH_REGULARFOGPS }; - const char* ppsshaders[2] = { "RegularPS", "RegularFogPS" }; - - for(i = 0; i < ARRAYSIZE(psshaders); ++i) { - for(int writedepth = 0; writedepth < 2; ++writedepth ) { - if( writedepth ) vmacros.push_back("-DWRITE_DEPTH"); - LoadShader(psshaders[i]|(writedepth?SH_WRITEDEPTH:0), ppsshaders[i], cgfProf, vmacros, 0); - if( writedepth ) vmacros.pop_back(); - } - } - - printf("creating shaders, note that ctx0/ps2hw_ctx.fx, and ctx1/ps2hw_ctx.fx are required\n"); - vmacros.resize(0); - - for(int texwrap = 0; texwrap < NUM_TEXWRAPS; ++texwrap ) { - - if( g_pPsTexWrap[texwrap] != NULL ) - vmacros.push_back(g_pPsTexWrap[texwrap]); - - for(int context = 0; context < 2; ++context) { - - for(int texfilter = 0; texfilter < NUM_FILTERS; ++texfilter) { - for(int fog = 0; fog < 2; ++fog ) { - for(int writedepth = 0; writedepth < 2; ++writedepth ) { - - if( writedepth ) - vmacros.push_back("-DWRITE_DEPTH"); - - for(int testaem = 0; testaem < 2; ++testaem ) { - - if( testaem ) - vmacros.push_back("-DTEST_AEM"); - - for(int exactcolor = 0; exactcolor < 2; ++exactcolor ) { - - if( exactcolor ) - vmacros.push_back("-DEXACT_COLOR"); - - // 32 - sprintf(str, "Texture%s%d_32PS", fog?"Fog":"", texfilter); - - vmacros.push_back("-DACCURATE_DECOMPRESSION"); - LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); - vmacros.pop_back(); - - LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); - - if( texfilter == 0 ) { - // tex32 - sprintf(str, "Texture%s%d_tex32PS", fog?"Fog":"", texfilter); - -// vmacros.push_back("-DACCURATE_DECOMPRESSION"); -// LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); -// vmacros.pop_back(); - - LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); - - // clut32 - sprintf(str, "Texture%s%d_clut32PS", fog?"Fog":"", texfilter); - -// vmacros.push_back("-DACCURATE_DECOMPRESSION"); -// LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); -// vmacros.pop_back(); - - LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); - - // tex32to16 - sprintf(str, "Texture%s%d_tex32to16PS", fog?"Fog":"", texfilter); - -// vmacros.push_back("-DACCURATE_DECOMPRESSION"); -// LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); -// vmacros.pop_back(); - - LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); - - // tex16to8h - sprintf(str, "Texture%s%d_tex16to8hPS", fog?"Fog":"", texfilter); - -// vmacros.push_back("-DACCURATE_DECOMPRESSION"); -// LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); -// vmacros.pop_back(); - - LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); - } - - if( exactcolor ) - vmacros.pop_back(); - } - - if( testaem ) - vmacros.pop_back(); - } - - if( writedepth ) - vmacros.pop_back(); - } - } - } - } - - if( g_pPsTexWrap[texwrap] != NULL ) - vmacros.pop_back(); - } - - if( vmacros.size() != 0 ) - printf("error with macros!\n"); - - // create the database - - int num = (int)mapShaders.size(); - - // first compress - vector buffer; - buffer.reserve(10000000); // 10mb - buffer.resize(sizeof(SHADERHEADER)*num); - - i = 0; - for(map::iterator it = mapShaders.begin(); it != mapShaders.end(); ++it, ++i) { - SHADERHEADER h; - h.index = it->first | it->second.type; - h.offset = (int)buffer.size(); - h.size = (int)it->second.buf.size(); - - memcpy(&buffer[0] + i*sizeof(SHADERHEADER), &h, sizeof(SHADERHEADER)); - - size_t cur = buffer.size(); - buffer.resize(cur + it->second.buf.size()); - memcpy(&buffer[cur], &it->second.buf[0], it->second.buf.size()); - } - - int compressed_size; - int real_size = (int)buffer.size(); - vector dst; - dst.resize(buffer.size()); - def(&buffer[0], &dst[0], (int)buffer.size(), &compressed_size); - - // write to file - // fmt: num shaders, size of compressed, compressed data - FILE* fdst = fopen(dstfilename, "wb"); - if( fdst == NULL ) { - printf("failed to open %s\n", dstfilename); - return 0; - } - - fwrite(&num, 4, 1, fdst); - fwrite(&compressed_size, 4, 1, fdst); - fwrite(&real_size, 4, 1, fdst); - fwrite(&dst[0], compressed_size, 1, fdst); - - fclose(fdst); - - printf("wrote %s\n", dstfilename); - - cgDestroyContext(g_cgcontext); - - return 0; -} +#define _CRT_SECURE_NO_DEPRECATE + +// Builds all possible shader files from ps2hw.fx and stores them in +// a preprocessed database +#include +#include + +#include +#include "zpipe.h" + +#include +#include + +#define SAFE_RELEASE(x) { if( (x) != NULL ) { (x)->Release(); x = NULL; } } + +#include +#include + +using namespace std; + +#include "zerogsshaders.h" + +char* srcfilename = "ps2hw.fx"; +char* dstfilename = "ps2hw.dat"; + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +struct SHADERINFO +{ + int type; + vector buf; +}; + +map mapShaders; +CGcontext g_cgcontext; + +void LoadShader(int index, const char* pshader, CGprofile prof, vector& vargs, int context) +{ + vector realargs; + realargs.reserve(16); + realargs.resize(vargs.size()); + if( vargs.size() > 0 ) + memcpy(&realargs[0], &vargs[0], realargs.size() * sizeof(realargs[0])); + realargs.push_back(context ? "-Ictx1" : "-Ictx0"); + realargs.push_back(NULL); + + CGprogram prog = cgCreateProgramFromFile(g_cgcontext, CG_SOURCE, srcfilename, prof, pshader, &realargs[0]); + if( !cgIsProgram(prog) ) { + printf("Failed to load shader %s: \n%s\n", pshader, cgGetLastListing(g_cgcontext)); + return; + } + + if( mapShaders.find(index) != mapShaders.end() ) { + printf("error: two shaders share the same index %d\n", index); + exit(0); + } + + if( !cgIsProgramCompiled(prog) ) + cgCompileProgram(prog); + + const char* pstr = cgGetProgramString(prog, CG_COMPILED_PROGRAM); + + const char* pprog = strstr(pstr, "#program"); + if( pprog == NULL ) { + printf("program field not found!\n"); + return; + } + pprog += 9; + const char* progend = strchr(pprog, '\r'); + if( progend == NULL ) progend = strchr(pprog, '\n'); + + if( progend == NULL ) { + printf("prog end not found!\n"); + return; + } + + const char* defname = "main"; + + SHADERINFO info; + info.type = 0; + info.buf.resize(strlen(pstr)+1); + + // change the program name to main + memset(&info.buf[0], 0, info.buf.size()); + memcpy(&info.buf[0], pstr, pprog-pstr); + memcpy(&info.buf[pprog-pstr], defname, 4); + memcpy(&info.buf[pprog-pstr+4], progend, strlen(pstr)-(progend-pstr)); + + if( mapShaders.find(index) != mapShaders.end() ) + printf("same shader\n"); + assert( mapShaders.find(index) == mapShaders.end() ); + mapShaders[index] = info; + + cgDestroyProgram(prog); +} + +int main(int argc, char** argv) +{ + printf("usage: [src] [dst] [opts]\n"); + + if( argc >= 2 ) srcfilename = argv[1]; + if( argc >= 3 ) dstfilename = argv[2]; + + FILE* fsrc = fopen(srcfilename, "r"); + if( fsrc == NULL ) { + printf("cannot open %s\n", srcfilename); + return 0; + } + fclose(fsrc); + + g_cgcontext = cgCreateContext(); + if( !cgIsContext(g_cgcontext) ) { + printf("failed to create cg context\n"); + return -1; + } + + CGprofile cgvProf = CG_PROFILE_ARBVP1; + CGprofile cgfProf = CG_PROFILE_ARBFP1; + if( !cgGLIsProfileSupported(cgvProf) != CG_TRUE ) { + printf("arbvp1 not supported\n"); + return 0; + } + if( !cgGLIsProfileSupported(cgfProf) != CG_TRUE ) { + printf("arbfp1 not supported\n"); + return 0; + } + + cgGLEnableProfile(cgvProf); + cgGLEnableProfile(cgfProf); + cgGLSetOptimalOptions(cgvProf); + cgGLSetOptimalOptions(cgfProf); + + vector vmacros; + + LoadShader(SH_BITBLTVS, "BitBltVS", cgvProf, vmacros, 0); + LoadShader(SH_BITBLTPS, "BitBltPS", cgfProf, vmacros, 0); + LoadShader(SH_BITBLTDEPTHPS, "BitBltDepthPS", cgfProf, vmacros, 0); + LoadShader(SH_BITBLTDEPTHMRTPS, "BitBltDepthMRTPS", cgfProf, vmacros, 0); + LoadShader(SH_CRTCTARGPS, "CRTCTargPS", cgfProf, vmacros, 0); + LoadShader(SH_CRTCPS, "CRTCPS", cgfProf, vmacros, 0); + LoadShader(SH_CRTC_NEARESTPS, "CRTCPS_Nearest", cgfProf, vmacros, 0); + LoadShader(SH_CRTC24PS, "CRTC24PS", cgfProf, vmacros, 0); + LoadShader(SH_ZEROPS, "ZeroPS", cgfProf, vmacros, 0); + LoadShader(SH_BASETEXTUREPS, "BaseTexturePS", cgfProf, vmacros, 0); + LoadShader(SH_BITBLTAAPS, "BitBltPS", cgfProf, vmacros, 0); + LoadShader(SH_CRTCTARGINTERPS, "CRTCTargInterPS", cgfProf, vmacros, 0); + LoadShader(SH_CRTCINTERPS, "CRTCInterPS", cgfProf, vmacros, 0); + LoadShader(SH_CRTCINTER_NEARESTPS, "CRTCInterPS_Nearest", cgfProf, vmacros, 0); + LoadShader(SH_CRTC24INTERPS, "CRTC24InterPS", cgfProf, vmacros, 0); + LoadShader(SH_CONVERT16TO32PS, "Convert16to32PS", cgfProf, vmacros, 0); + LoadShader(SH_CONVERT32TO16PS, "Convert32to16PS", cgfProf, vmacros, 0); + + const int vsshaders[4] = { SH_REGULARVS, SH_TEXTUREVS, SH_REGULARFOGVS, SH_TEXTUREFOGVS }; + const char* pvsshaders[4] = { "RegularVS", "TextureVS", "RegularFogVS", "TextureFogVS" }; + + // load the texture shaders + char str[255], strdir[255]; + + strcpy(strdir, srcfilename); + int i = (int)strlen(strdir); + while(i > 0) { + if( strdir[i-1] == '/' || strdir[i-1] == '\\' ) + break; + --i; + } + + strdir[i] = 0; + + for(i = 0; i < ARRAYSIZE(vsshaders); ++i) { + for(int writedepth = 0; writedepth < 2; ++writedepth ) { + + if( writedepth ) vmacros.push_back("-DWRITE_DEPTH"); + LoadShader(vsshaders[i]|(writedepth?SH_WRITEDEPTH:0), pvsshaders[i], cgvProf, vmacros, 0); + LoadShader(vsshaders[i]|(writedepth?SH_WRITEDEPTH:0)|SH_CONTEXT1, pvsshaders[i], cgvProf, vmacros, 1); + if( writedepth ) vmacros.pop_back(); + } + } + + const int psshaders[2] = { SH_REGULARPS, SH_REGULARFOGPS }; + const char* ppsshaders[2] = { "RegularPS", "RegularFogPS" }; + + for(i = 0; i < ARRAYSIZE(psshaders); ++i) { + for(int writedepth = 0; writedepth < 2; ++writedepth ) { + if( writedepth ) vmacros.push_back("-DWRITE_DEPTH"); + LoadShader(psshaders[i]|(writedepth?SH_WRITEDEPTH:0), ppsshaders[i], cgfProf, vmacros, 0); + if( writedepth ) vmacros.pop_back(); + } + } + + printf("creating shaders, note that ctx0/ps2hw_ctx.fx, and ctx1/ps2hw_ctx.fx are required\n"); + vmacros.resize(0); + + for(int texwrap = 0; texwrap < NUM_TEXWRAPS; ++texwrap ) { + + if( g_pPsTexWrap[texwrap] != NULL ) + vmacros.push_back(g_pPsTexWrap[texwrap]); + + for(int context = 0; context < 2; ++context) { + + for(int texfilter = 0; texfilter < NUM_FILTERS; ++texfilter) { + for(int fog = 0; fog < 2; ++fog ) { + for(int writedepth = 0; writedepth < 2; ++writedepth ) { + + if( writedepth ) + vmacros.push_back("-DWRITE_DEPTH"); + + for(int testaem = 0; testaem < 2; ++testaem ) { + + if( testaem ) + vmacros.push_back("-DTEST_AEM"); + + for(int exactcolor = 0; exactcolor < 2; ++exactcolor ) { + + if( exactcolor ) + vmacros.push_back("-DEXACT_COLOR"); + + // 32 + sprintf(str, "Texture%s%d_32PS", fog?"Fog":"", texfilter); + + vmacros.push_back("-DACCURATE_DECOMPRESSION"); + LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); + vmacros.pop_back(); + + LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); + + if( texfilter == 0 ) { + // tex32 + sprintf(str, "Texture%s%d_tex32PS", fog?"Fog":"", texfilter); + +// vmacros.push_back("-DACCURATE_DECOMPRESSION"); +// LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); +// vmacros.pop_back(); + + LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); + + // clut32 + sprintf(str, "Texture%s%d_clut32PS", fog?"Fog":"", texfilter); + +// vmacros.push_back("-DACCURATE_DECOMPRESSION"); +// LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); +// vmacros.pop_back(); + + LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); + + // tex32to16 + sprintf(str, "Texture%s%d_tex32to16PS", fog?"Fog":"", texfilter); + +// vmacros.push_back("-DACCURATE_DECOMPRESSION"); +// LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); +// vmacros.pop_back(); + + LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); + + // tex16to8h + sprintf(str, "Texture%s%d_tex16to8hPS", fog?"Fog":"", texfilter); + +// vmacros.push_back("-DACCURATE_DECOMPRESSION"); +// LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); +// vmacros.pop_back(); + + LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); + } + + if( exactcolor ) + vmacros.pop_back(); + } + + if( testaem ) + vmacros.pop_back(); + } + + if( writedepth ) + vmacros.pop_back(); + } + } + } + } + + if( g_pPsTexWrap[texwrap] != NULL ) + vmacros.pop_back(); + } + + if( vmacros.size() != 0 ) + printf("error with macros!\n"); + + // create the database + + int num = (int)mapShaders.size(); + + // first compress + vector buffer; + buffer.reserve(10000000); // 10mb + buffer.resize(sizeof(SHADERHEADER)*num); + + i = 0; + for(map::iterator it = mapShaders.begin(); it != mapShaders.end(); ++it, ++i) { + SHADERHEADER h; + h.index = it->first | it->second.type; + h.offset = (int)buffer.size(); + h.size = (int)it->second.buf.size(); + + memcpy(&buffer[0] + i*sizeof(SHADERHEADER), &h, sizeof(SHADERHEADER)); + + size_t cur = buffer.size(); + buffer.resize(cur + it->second.buf.size()); + memcpy(&buffer[cur], &it->second.buf[0], it->second.buf.size()); + } + + int compressed_size; + int real_size = (int)buffer.size(); + vector dst; + dst.resize(buffer.size()); + def(&buffer[0], &dst[0], (int)buffer.size(), &compressed_size); + + // write to file + // fmt: num shaders, size of compressed, compressed data + FILE* fdst = fopen(dstfilename, "wb"); + if( fdst == NULL ) { + printf("failed to open %s\n", dstfilename); + return 0; + } + + fwrite(&num, 4, 1, fdst); + fwrite(&compressed_size, 4, 1, fdst); + fwrite(&real_size, 4, 1, fdst); + fwrite(&dst[0], compressed_size, 1, fdst); + + fclose(fdst); + + printf("wrote %s\n", dstfilename); + + cgDestroyContext(g_cgcontext); + + return 0; +} diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zerogsshaders.h b/plugins/zerogs/opengl/ZeroGSShaders/zerogsshaders.h index e2695618d5..05da9f37e5 100644 --- a/plugins/zerogs/opengl/ZeroGSShaders/zerogsshaders.h +++ b/plugins/zerogs/opengl/ZeroGSShaders/zerogsshaders.h @@ -1,89 +1,89 @@ -#include -#include - -#define NUM_FILTERS 2 // texture filtering -#define NUM_TYPES 5 // types of texture read modes -#define NUM_TEXWRAPS 4 // texture wrapping - -#define SHADER_REDUCED 1 // equivalent to ps2.0 -#define SHADER_ACCURATE 2 // for older cards with less accurate math (ps2.x+) - -#define NUM_SHADERS (NUM_FILTERS*NUM_TYPES*NUM_TEXWRAPS*32) // # shaders for a given ps - -const static char* g_pShaders[] = { "full", "reduced", "accurate", "accurate-reduced" }; -const static char* g_pPsTexWrap[] = { "-DREPEAT", "-DCLAMP", "-DREGION_REPEAT", NULL }; -const static char* g_pTexTypes[] = { "32", "tex32", "clut32", "tex32to16", "tex16to8h" }; - -#define TEXWRAP_REPEAT 0 -#define TEXWRAP_CLAMP 1 -#define TEXWRAP_REGION_REPEAT 2 -#define TEXWRAP_REPEAT_CLAMP 3 - -inline int GET_SHADER_INDEX(int type, int texfilter, int texwrap, int fog, int writedepth, int testaem, int exactcolor, int context, int ps) -{ - return type + texfilter*NUM_TYPES + NUM_FILTERS*NUM_TYPES*texwrap + NUM_TEXWRAPS*NUM_FILTERS*NUM_TYPES*(fog+2*writedepth+4*testaem+8*exactcolor+16*context+32*ps); -} - -extern CGcontext g_cgcontext; - -static CGprogram LoadShaderFromType(const char* srcdir, const char* srcfile, int type, int texfilter, int texwrap, int fog, int writedepth, int testaem, int exactcolor, int ps, int context) -{ - assert( texwrap < NUM_TEXWRAPS); - assert( type < NUM_TYPES ); - - char str[255], strctx[255]; - sprintf(str, "Texture%s%d_%sPS", fog?"Fog":"", texfilter, g_pTexTypes[type]); - sprintf(strctx, "-I%s%s", srcdir, context?"ctx1":"ctx0"); - - vector macros; - macros.push_back(strctx); -#ifdef _DEBUG - macros.push_back("-bestprecision"); -#endif - if( g_pPsTexWrap[texwrap] != NULL ) macros.push_back(g_pPsTexWrap[texwrap]); - if( writedepth ) macros.push_back("-DWRITE_DEPTH"); - if( testaem ) macros.push_back("-DTEST_AEM"); - if( exactcolor ) macros.push_back("-DEXACT_COLOR"); - if( ps & SHADER_ACCURATE ) macros.push_back("-DACCURATE_DECOMPRESSION"); - macros.push_back(NULL); - - CGprogram prog = cgCreateProgramFromFile(g_cgcontext, CG_SOURCE, srcfile, CG_PROFILE_ARBFP1, str, ¯os[0]); - if( !cgIsProgram(prog) ) { - printf("Failed to load shader %s: \n%s\n", str, cgGetLastListing(g_cgcontext)); - return NULL; - } - - return prog; -} - -struct SHADERHEADER -{ - unsigned int index, offset, size; // if highest bit of index is set, pixel shader -}; - -#define SH_WRITEDEPTH 0x2000 // depth is written -#define SH_CONTEXT1 0x1000 // context1 is used - -#define SH_REGULARVS 0x8000 -#define SH_TEXTUREVS 0x8001 -#define SH_REGULARFOGVS 0x8002 -#define SH_TEXTUREFOGVS 0x8003 -#define SH_REGULARPS 0x8004 -#define SH_REGULARFOGPS 0x8005 -#define SH_BITBLTVS 0x8006 -#define SH_BITBLTPS 0x8007 -#define SH_BITBLTDEPTHPS 0x8009 -#define SH_CRTCTARGPS 0x800a -#define SH_CRTCPS 0x800b -#define SH_CRTC24PS 0x800c -#define SH_ZEROPS 0x800e -#define SH_BASETEXTUREPS 0x800f -#define SH_BITBLTAAPS 0x8010 -#define SH_CRTCTARGINTERPS 0x8012 -#define SH_CRTCINTERPS 0x8013 -#define SH_CRTC24INTERPS 0x8014 -#define SH_BITBLTDEPTHMRTPS 0x8016 -#define SH_CONVERT16TO32PS 0x8020 -#define SH_CONVERT32TO16PS 0x8021 -#define SH_CRTC_NEARESTPS 0x8022 -#define SH_CRTCINTER_NEARESTPS 0x8023 +#include +#include + +#define NUM_FILTERS 2 // texture filtering +#define NUM_TYPES 5 // types of texture read modes +#define NUM_TEXWRAPS 4 // texture wrapping + +#define SHADER_REDUCED 1 // equivalent to ps2.0 +#define SHADER_ACCURATE 2 // for older cards with less accurate math (ps2.x+) + +#define NUM_SHADERS (NUM_FILTERS*NUM_TYPES*NUM_TEXWRAPS*32) // # shaders for a given ps + +const static char* g_pShaders[] = { "full", "reduced", "accurate", "accurate-reduced" }; +const static char* g_pPsTexWrap[] = { "-DREPEAT", "-DCLAMP", "-DREGION_REPEAT", NULL }; +const static char* g_pTexTypes[] = { "32", "tex32", "clut32", "tex32to16", "tex16to8h" }; + +#define TEXWRAP_REPEAT 0 +#define TEXWRAP_CLAMP 1 +#define TEXWRAP_REGION_REPEAT 2 +#define TEXWRAP_REPEAT_CLAMP 3 + +inline int GET_SHADER_INDEX(int type, int texfilter, int texwrap, int fog, int writedepth, int testaem, int exactcolor, int context, int ps) +{ + return type + texfilter*NUM_TYPES + NUM_FILTERS*NUM_TYPES*texwrap + NUM_TEXWRAPS*NUM_FILTERS*NUM_TYPES*(fog+2*writedepth+4*testaem+8*exactcolor+16*context+32*ps); +} + +extern CGcontext g_cgcontext; + +static CGprogram LoadShaderFromType(const char* srcdir, const char* srcfile, int type, int texfilter, int texwrap, int fog, int writedepth, int testaem, int exactcolor, int ps, int context) +{ + assert( texwrap < NUM_TEXWRAPS); + assert( type < NUM_TYPES ); + + char str[255], strctx[255]; + sprintf(str, "Texture%s%d_%sPS", fog?"Fog":"", texfilter, g_pTexTypes[type]); + sprintf(strctx, "-I%s%s", srcdir, context?"ctx1":"ctx0"); + + vector macros; + macros.push_back(strctx); +#ifdef _DEBUG + macros.push_back("-bestprecision"); +#endif + if( g_pPsTexWrap[texwrap] != NULL ) macros.push_back(g_pPsTexWrap[texwrap]); + if( writedepth ) macros.push_back("-DWRITE_DEPTH"); + if( testaem ) macros.push_back("-DTEST_AEM"); + if( exactcolor ) macros.push_back("-DEXACT_COLOR"); + if( ps & SHADER_ACCURATE ) macros.push_back("-DACCURATE_DECOMPRESSION"); + macros.push_back(NULL); + + CGprogram prog = cgCreateProgramFromFile(g_cgcontext, CG_SOURCE, srcfile, CG_PROFILE_ARBFP1, str, ¯os[0]); + if( !cgIsProgram(prog) ) { + printf("Failed to load shader %s: \n%s\n", str, cgGetLastListing(g_cgcontext)); + return NULL; + } + + return prog; +} + +struct SHADERHEADER +{ + unsigned int index, offset, size; // if highest bit of index is set, pixel shader +}; + +#define SH_WRITEDEPTH 0x2000 // depth is written +#define SH_CONTEXT1 0x1000 // context1 is used + +#define SH_REGULARVS 0x8000 +#define SH_TEXTUREVS 0x8001 +#define SH_REGULARFOGVS 0x8002 +#define SH_TEXTUREFOGVS 0x8003 +#define SH_REGULARPS 0x8004 +#define SH_REGULARFOGPS 0x8005 +#define SH_BITBLTVS 0x8006 +#define SH_BITBLTPS 0x8007 +#define SH_BITBLTDEPTHPS 0x8009 +#define SH_CRTCTARGPS 0x800a +#define SH_CRTCPS 0x800b +#define SH_CRTC24PS 0x800c +#define SH_ZEROPS 0x800e +#define SH_BASETEXTUREPS 0x800f +#define SH_BITBLTAAPS 0x8010 +#define SH_CRTCTARGINTERPS 0x8012 +#define SH_CRTCINTERPS 0x8013 +#define SH_CRTC24INTERPS 0x8014 +#define SH_BITBLTDEPTHMRTPS 0x8016 +#define SH_CONVERT16TO32PS 0x8020 +#define SH_CONVERT32TO16PS 0x8021 +#define SH_CRTC_NEARESTPS 0x8022 +#define SH_CRTCINTER_NEARESTPS 0x8023 diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/crc32.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/crc32.h index 5de49bc978..8053b6117c 100644 --- a/plugins/zerogs/opengl/ZeroGSShaders/zlib/crc32.h +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/crc32.h @@ -1,441 +1,441 @@ -/* crc32.h -- tables for rapid CRC calculation - * Generated automatically by crc32.c - */ - -local const unsigned long FAR crc_table[TBLS][256] = -{ - { - 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, - 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, - 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, - 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, - 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, - 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, - 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, - 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, - 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, - 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, - 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, - 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, - 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, - 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, - 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, - 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, - 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, - 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, - 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, - 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, - 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, - 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, - 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, - 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, - 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, - 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, - 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, - 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, - 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, - 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, - 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, - 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, - 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, - 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, - 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, - 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, - 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, - 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, - 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, - 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, - 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, - 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, - 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, - 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, - 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, - 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, - 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, - 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, - 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, - 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, - 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, - 0x2d02ef8dUL -#ifdef BYFOUR - }, - { - 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, - 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, - 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, - 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, - 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, - 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, - 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, - 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, - 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, - 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, - 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, - 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, - 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, - 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, - 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, - 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, - 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, - 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, - 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, - 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, - 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, - 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, - 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, - 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, - 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, - 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, - 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, - 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, - 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, - 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, - 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, - 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, - 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, - 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, - 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, - 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, - 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, - 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, - 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, - 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, - 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, - 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, - 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, - 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, - 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, - 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, - 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, - 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, - 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, - 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, - 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, - 0x9324fd72UL - }, - { - 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, - 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, - 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, - 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, - 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, - 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, - 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, - 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, - 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, - 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, - 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, - 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, - 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, - 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, - 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, - 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, - 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, - 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, - 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, - 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, - 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, - 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, - 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, - 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, - 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, - 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, - 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, - 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, - 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, - 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, - 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, - 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, - 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, - 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, - 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, - 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, - 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, - 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, - 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, - 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, - 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, - 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, - 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, - 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, - 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, - 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, - 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, - 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, - 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, - 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, - 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, - 0xbe9834edUL - }, - { - 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, - 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, - 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, - 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, - 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, - 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, - 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, - 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, - 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, - 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, - 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, - 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, - 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, - 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, - 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, - 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, - 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, - 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, - 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, - 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, - 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, - 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, - 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, - 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, - 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, - 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, - 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, - 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, - 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, - 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, - 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, - 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, - 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, - 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, - 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, - 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, - 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, - 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, - 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, - 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, - 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, - 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, - 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, - 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, - 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, - 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, - 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, - 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, - 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, - 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, - 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, - 0xde0506f1UL - }, - { - 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, - 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, - 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, - 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, - 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, - 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, - 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, - 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, - 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, - 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, - 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, - 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, - 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, - 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, - 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, - 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, - 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, - 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, - 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, - 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, - 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, - 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, - 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, - 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, - 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, - 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, - 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, - 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, - 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, - 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, - 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, - 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, - 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, - 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, - 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, - 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, - 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, - 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, - 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, - 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, - 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, - 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, - 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, - 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, - 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, - 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, - 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, - 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, - 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, - 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, - 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, - 0x8def022dUL - }, - { - 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, - 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, - 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, - 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, - 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, - 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, - 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, - 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, - 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, - 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, - 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, - 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, - 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, - 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, - 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, - 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, - 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, - 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, - 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, - 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, - 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, - 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, - 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, - 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, - 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, - 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, - 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, - 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, - 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, - 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, - 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, - 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, - 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, - 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, - 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, - 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, - 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, - 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, - 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, - 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, - 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, - 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, - 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, - 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, - 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, - 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, - 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, - 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, - 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, - 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, - 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, - 0x72fd2493UL - }, - { - 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, - 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, - 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, - 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, - 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, - 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, - 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, - 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, - 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, - 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, - 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, - 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, - 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, - 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, - 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, - 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, - 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, - 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, - 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, - 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, - 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, - 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, - 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, - 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, - 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, - 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, - 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, - 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, - 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, - 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, - 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, - 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, - 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, - 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, - 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, - 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, - 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, - 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, - 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, - 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, - 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, - 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, - 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, - 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, - 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, - 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, - 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, - 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, - 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, - 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, - 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, - 0xed3498beUL - }, - { - 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, - 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, - 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, - 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, - 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, - 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, - 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, - 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, - 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, - 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, - 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, - 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, - 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, - 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, - 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, - 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, - 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, - 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, - 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, - 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, - 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, - 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, - 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, - 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, - 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, - 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, - 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, - 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, - 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, - 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, - 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, - 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, - 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, - 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, - 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, - 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, - 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, - 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, - 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, - 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, - 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, - 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, - 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, - 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, - 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, - 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, - 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, - 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, - 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, - 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, - 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, - 0xf10605deUL -#endif - } -}; +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/deflate.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/deflate.h index 0b5dd9bb49..804d3abe8f 100644 --- a/plugins/zerogs/opengl/ZeroGSShaders/zlib/deflate.h +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/deflate.h @@ -1,331 +1,331 @@ -/* deflate.h -- internal compression state - * Copyright (C) 1995-2004 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id: deflate.h,v 1.2 2006/03/02 00:10:34 zerocool Exp $ */ - -#ifndef DEFLATE_H -#define DEFLATE_H - -#include "zutil.h" - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer creation by deflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip encoding - should be left enabled. */ -#ifndef NO_GZIP -# define GZIP -#endif - -/* =========================================================================== - * Internal compression state. - */ - -#define LENGTH_CODES 29 -/* number of length codes, not counting the special END_BLOCK code */ - -#define LITERALS 256 -/* number of literal bytes 0..255 */ - -#define L_CODES (LITERALS+1+LENGTH_CODES) -/* number of Literal or Length codes, including the END_BLOCK code */ - -#define D_CODES 30 -/* number of distance codes */ - -#define BL_CODES 19 -/* number of codes used to transfer the bit lengths */ - -#define HEAP_SIZE (2*L_CODES+1) -/* maximum heap size */ - -#define MAX_BITS 15 -/* All codes must not exceed MAX_BITS bits */ - -#define INIT_STATE 42 -#define EXTRA_STATE 69 -#define NAME_STATE 73 -#define COMMENT_STATE 91 -#define HCRC_STATE 103 -#define BUSY_STATE 113 -#define FINISH_STATE 666 -/* Stream status */ - - -/* Data structure describing a single value and its code string. */ -typedef struct ct_data_s { - union { - ush freq; /* frequency count */ - ush code; /* bit string */ - } fc; - union { - ush dad; /* father node in Huffman tree */ - ush len; /* length of bit string */ - } dl; -} FAR ct_data; - -#define Freq fc.freq -#define Code fc.code -#define Dad dl.dad -#define Len dl.len - -typedef struct static_tree_desc_s static_tree_desc; - -typedef struct tree_desc_s { - ct_data *dyn_tree; /* the dynamic tree */ - int max_code; /* largest code with non zero frequency */ - static_tree_desc *stat_desc; /* the corresponding static tree */ -} FAR tree_desc; - -typedef ush Pos; -typedef Pos FAR Posf; -typedef unsigned IPos; - -/* A Pos is an index in the character window. We use short instead of int to - * save space in the various tables. IPos is used only for parameter passing. - */ - -typedef struct internal_state { - z_streamp strm; /* pointer back to this zlib stream */ - int status; /* as the name implies */ - Bytef *pending_buf; /* output still pending */ - ulg pending_buf_size; /* size of pending_buf */ - Bytef *pending_out; /* next pending byte to output to the stream */ - uInt pending; /* nb of bytes in the pending buffer */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - gz_headerp gzhead; /* gzip header information to write */ - uInt gzindex; /* where in extra, name, or comment */ - Byte method; /* STORED (for zip only) or DEFLATED */ - int last_flush; /* value of flush param for previous deflate call */ - - /* used by deflate.c: */ - - uInt w_size; /* LZ77 window size (32K by default) */ - uInt w_bits; /* log2(w_size) (8..16) */ - uInt w_mask; /* w_size - 1 */ - - Bytef *window; - /* Sliding window. Input bytes are read into the second half of the window, - * and move to the first half later to keep a dictionary of at least wSize - * bytes. With this organization, matches are limited to a distance of - * wSize-MAX_MATCH bytes, but this ensures that IO is always - * performed with a length multiple of the block size. Also, it limits - * the window size to 64K, which is quite useful on MSDOS. - * To do: use the user input buffer as sliding window. - */ - - ulg window_size; - /* Actual size of window: 2*wSize, except when the user input buffer - * is directly used as sliding window. - */ - - Posf *prev; - /* Link to older string with same hash index. To limit the size of this - * array to 64K, this link is maintained only for the last 32K strings. - * An index in this array is thus a window index modulo 32K. - */ - - Posf *head; /* Heads of the hash chains or NIL. */ - - uInt ins_h; /* hash index of string to be inserted */ - uInt hash_size; /* number of elements in hash table */ - uInt hash_bits; /* log2(hash_size) */ - uInt hash_mask; /* hash_size-1 */ - - uInt hash_shift; - /* Number of bits by which ins_h must be shifted at each input - * step. It must be such that after MIN_MATCH steps, the oldest - * byte no longer takes part in the hash key, that is: - * hash_shift * MIN_MATCH >= hash_bits - */ - - long block_start; - /* Window position at the beginning of the current output block. Gets - * negative when the window is moved backwards. - */ - - uInt match_length; /* length of best match */ - IPos prev_match; /* previous match */ - int match_available; /* set if previous match exists */ - uInt strstart; /* start of string to insert */ - uInt match_start; /* start of matching string */ - uInt lookahead; /* number of valid bytes ahead in window */ - - uInt prev_length; - /* Length of the best match at previous step. Matches not greater than this - * are discarded. This is used in the lazy match evaluation. - */ - - uInt max_chain_length; - /* To speed up deflation, hash chains are never searched beyond this - * length. A higher limit improves compression ratio but degrades the - * speed. - */ - - uInt max_lazy_match; - /* Attempt to find a better match only when the current match is strictly - * smaller than this value. This mechanism is used only for compression - * levels >= 4. - */ -# define max_insert_length max_lazy_match - /* Insert new strings in the hash table only if the match length is not - * greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 3. - */ - - int level; /* compression level (1..9) */ - int strategy; /* favor or force Huffman coding*/ - - uInt good_match; - /* Use a faster search when the previous match is longer than this */ - - int nice_match; /* Stop searching when current match exceeds this */ - - /* used by trees.c: */ - /* Didn't use ct_data typedef below to supress compiler warning */ - struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ - struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ - struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ - - struct tree_desc_s l_desc; /* desc. for literal tree */ - struct tree_desc_s d_desc; /* desc. for distance tree */ - struct tree_desc_s bl_desc; /* desc. for bit length tree */ - - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ - int heap_len; /* number of elements in the heap */ - int heap_max; /* element of largest frequency */ - /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - * The same heap array is used to build all trees. - */ - - uch depth[2*L_CODES+1]; - /* Depth of each subtree used as tie breaker for trees of equal frequency - */ - - uchf *l_buf; /* buffer for literals or lengths */ - - uInt lit_bufsize; - /* Size of match buffer for literals/lengths. There are 4 reasons for - * limiting lit_bufsize to 64K: - * - frequencies can be kept in 16 bit counters - * - if compression is not successful for the first block, all input - * data is still in the window so we can still emit a stored block even - * when input comes from standard input. (This can also be done for - * all blocks if lit_bufsize is not greater than 32K.) - * - if compression is not successful for a file smaller than 64K, we can - * even emit a stored file instead of a stored block (saving 5 bytes). - * This is applicable only for zip (not gzip or zlib). - * - creating new Huffman trees less frequently may not provide fast - * adaptation to changes in the input data statistics. (Take for - * example a binary file with poorly compressible code followed by - * a highly compressible string table.) Smaller buffer sizes give - * fast adaptation but have of course the overhead of transmitting - * trees more frequently. - * - I can't count above 4 - */ - - uInt last_lit; /* running index in l_buf */ - - ushf *d_buf; - /* Buffer for distances. To simplify the code, d_buf and l_buf have - * the same number of elements. To use different lengths, an extra flag - * array would be necessary. - */ - - ulg opt_len; /* bit length of current block with optimal trees */ - ulg static_len; /* bit length of current block with static trees */ - uInt matches; /* number of string matches in current block */ - int last_eob_len; /* bit length of EOB code for last block */ - -#ifdef DEBUG - ulg compressed_len; /* total bit length of compressed file mod 2^32 */ - ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ -#endif - - ush bi_buf; - /* Output buffer. bits are inserted starting at the bottom (least - * significant bits). - */ - int bi_valid; - /* Number of valid bits in bi_buf. All bits above the last valid bit - * are always zero. - */ - -} FAR deflate_state; - -/* Output a byte on the stream. - * IN assertion: there is enough room in pending_buf. - */ -#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} - - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) -/* In order to simplify the code, particularly on 16 bit machines, match - * distances are limited to MAX_DIST instead of WSIZE. - */ - - /* in trees.c */ -void _tr_init OF((deflate_state *s)); -int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); -void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); -void _tr_align OF((deflate_state *s)); -void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); - -#define d_code(dist) \ - ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) -/* Mapping from a distance to a distance code. dist is the distance - 1 and - * must not have side effects. _dist_code[256] and _dist_code[257] are never - * used. - */ - -#ifndef DEBUG -/* Inline versions of _tr_tally for speed: */ - -#if defined(GEN_TREES_H) || !defined(STDC) - extern uch _length_code[]; - extern uch _dist_code[]; -#else - extern const uch _length_code[]; - extern const uch _dist_code[]; -#endif - -# define _tr_tally_lit(s, c, flush) \ - { uch cc = (c); \ - s->d_buf[s->last_lit] = 0; \ - s->l_buf[s->last_lit++] = cc; \ - s->dyn_ltree[cc].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -# define _tr_tally_dist(s, distance, length, flush) \ - { uch len = (length); \ - ush dist = (distance); \ - s->d_buf[s->last_lit] = dist; \ - s->l_buf[s->last_lit++] = len; \ - dist--; \ - s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ - s->dyn_dtree[d_code(dist)].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -#else -# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) -# define _tr_tally_dist(s, distance, length, flush) \ - flush = _tr_tally(s, distance, length) -#endif - -#endif /* DEFLATE_H */ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2004 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: deflate.h,v 1.2 2006/03/02 00:10:34 zerocool Exp $ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/inffast.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/inffast.h index 614fa7877d..1e88d2d97b 100644 --- a/plugins/zerogs/opengl/ZeroGSShaders/zlib/inffast.h +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/inffast.h @@ -1,11 +1,11 @@ -/* inffast.h -- header to use inffast.c - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -void inflate_fast OF((z_streamp strm, unsigned start)); +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/inffixed.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/inffixed.h index 423d5c5b50..75ed4b5978 100644 --- a/plugins/zerogs/opengl/ZeroGSShaders/zlib/inffixed.h +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/inffixed.h @@ -1,94 +1,94 @@ - /* inffixed.h -- table for decoding fixed codes - * Generated automatically by makefixed(). - */ - - /* WARNING: this file should *not* be used by applications. It - is part of the implementation of the compression library and - is subject to change. Applications should only use zlib.h. - */ - - static const code lenfix[512] = { - {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, - {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, - {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, - {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, - {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, - {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, - {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, - {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, - {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, - {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, - {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, - {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, - {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, - {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, - {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, - {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, - {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, - {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, - {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, - {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, - {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, - {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, - {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, - {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, - {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, - {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, - {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, - {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, - {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, - {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, - {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, - {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, - {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, - {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, - {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, - {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, - {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, - {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, - {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, - {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, - {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, - {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, - {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, - {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, - {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, - {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, - {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, - {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, - {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, - {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, - {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, - {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, - {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, - {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, - {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, - {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, - {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, - {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, - {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, - {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, - {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, - {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, - {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, - {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, - {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, - {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, - {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, - {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, - {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, - {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, - {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, - {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, - {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, - {0,9,255} - }; - - static const code distfix[32] = { - {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, - {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, - {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, - {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, - {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, - {22,5,193},{64,5,0} - }; + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/inflate.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/inflate.h index fbbc871432..07bd3e78a7 100644 --- a/plugins/zerogs/opengl/ZeroGSShaders/zlib/inflate.h +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/inflate.h @@ -1,115 +1,115 @@ -/* inflate.h -- internal inflate state definition - * Copyright (C) 1995-2004 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer decoding by inflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip decoding - should be left enabled. */ -#ifndef NO_GZIP -# define GUNZIP -#endif - -/* Possible inflate modes between inflate() calls */ -typedef enum { - HEAD, /* i: waiting for magic header */ - FLAGS, /* i: waiting for method and flags (gzip) */ - TIME, /* i: waiting for modification time (gzip) */ - OS, /* i: waiting for extra flags and operating system (gzip) */ - EXLEN, /* i: waiting for extra length (gzip) */ - EXTRA, /* i: waiting for extra bytes (gzip) */ - NAME, /* i: waiting for end of file name (gzip) */ - COMMENT, /* i: waiting for end of comment (gzip) */ - HCRC, /* i: waiting for header crc (gzip) */ - DICTID, /* i: waiting for dictionary check value */ - DICT, /* waiting for inflateSetDictionary() call */ - TYPE, /* i: waiting for type bits, including last-flag bit */ - TYPEDO, /* i: same, but skip check to exit inflate on new block */ - STORED, /* i: waiting for stored size (length and complement) */ - COPY, /* i/o: waiting for input or output to copy stored block */ - TABLE, /* i: waiting for dynamic block table lengths */ - LENLENS, /* i: waiting for code length code lengths */ - CODELENS, /* i: waiting for length/lit and distance code lengths */ - LEN, /* i: waiting for length/lit code */ - LENEXT, /* i: waiting for length extra bits */ - DIST, /* i: waiting for distance code */ - DISTEXT, /* i: waiting for distance extra bits */ - MATCH, /* o: waiting for output space to copy string */ - LIT, /* o: waiting for output space to write literal */ - CHECK, /* i: waiting for 32-bit check value */ - LENGTH, /* i: waiting for 32-bit length (gzip) */ - DONE, /* finished check, done -- remain here until reset */ - BAD, /* got a data error -- remain here until reset */ - MEM, /* got an inflate() memory error -- remain here until reset */ - SYNC /* looking for synchronization bytes to restart inflate() */ -} inflate_mode; - -/* - State transitions between above modes - - - (most modes can go to the BAD or MEM mode -- not shown for clarity) - - Process header: - HEAD -> (gzip) or (zlib) - (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME - NAME -> COMMENT -> HCRC -> TYPE - (zlib) -> DICTID or TYPE - DICTID -> DICT -> TYPE - Read deflate blocks: - TYPE -> STORED or TABLE or LEN or CHECK - STORED -> COPY -> TYPE - TABLE -> LENLENS -> CODELENS -> LEN - Read deflate codes: - LEN -> LENEXT or LIT or TYPE - LENEXT -> DIST -> DISTEXT -> MATCH -> LEN - LIT -> LEN - Process trailer: - CHECK -> LENGTH -> DONE - */ - -/* state maintained between inflate() calls. Approximately 7K bytes. */ -struct inflate_state { - inflate_mode mode; /* current inflate mode */ - int last; /* true if processing last block */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - int havedict; /* true if dictionary provided */ - int flags; /* gzip header method and flags (0 if zlib) */ - unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ - unsigned long check; /* protected copy of check value */ - unsigned long total; /* protected copy of output count */ - gz_headerp head; /* where to save gzip header information */ - /* sliding window */ - unsigned wbits; /* log base 2 of requested window size */ - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned write; /* window write index */ - unsigned char FAR *window; /* allocated sliding window, if needed */ - /* bit accumulator */ - unsigned long hold; /* input bit accumulator */ - unsigned bits; /* number of bits in "in" */ - /* for string and stored block copying */ - unsigned length; /* literal or length of data to copy */ - unsigned offset; /* distance back to copy string from */ - /* for table and code decoding */ - unsigned extra; /* extra bits needed */ - /* fixed and dynamic code tables */ - code const FAR *lencode; /* starting table for length/literal codes */ - code const FAR *distcode; /* starting table for distance codes */ - unsigned lenbits; /* index bits for lencode */ - unsigned distbits; /* index bits for distcode */ - /* dynamic table building */ - unsigned ncode; /* number of code length code lengths */ - unsigned nlen; /* number of length code lengths */ - unsigned ndist; /* number of distance code lengths */ - unsigned have; /* number of code lengths in lens[] */ - code FAR *next; /* next available space in codes[] */ - unsigned short lens[320]; /* temporary storage for code lengths */ - unsigned short work[288]; /* work area for code table building */ - code codes[ENOUGH]; /* space for code tables */ -}; +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/inftrees.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/inftrees.h index dc0fd567ea..b1104c87e7 100644 --- a/plugins/zerogs/opengl/ZeroGSShaders/zlib/inftrees.h +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/inftrees.h @@ -1,55 +1,55 @@ -/* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* Structure for decoding tables. Each entry provides either the - information needed to do the operation requested by the code that - indexed that table entry, or it provides a pointer to another - table that indexes more bits of the code. op indicates whether - the entry is a pointer to another table, a literal, a length or - distance, an end-of-block, or an invalid code. For a table - pointer, the low four bits of op is the number of index bits of - that table. For a length or distance, the low four bits of op - is the number of extra bits to get after the code. bits is - the number of bits in this code or part of the code to drop off - of the bit buffer. val is the actual byte to output in the case - of a literal, the base length or distance, or the offset from - the current table to the next table. Each entry is four bytes. */ -typedef struct { - unsigned char op; /* operation, extra bits, table bits */ - unsigned char bits; /* bits in this part of the code */ - unsigned short val; /* offset in table or code value */ -} code; - -/* op values as set by inflate_table(): - 00000000 - literal - 0000tttt - table link, tttt != 0 is the number of table index bits - 0001eeee - length or distance, eeee is the number of extra bits - 01100000 - end of block - 01000000 - invalid code - */ - -/* Maximum size of dynamic tree. The maximum found in a long but non- - exhaustive search was 1444 code structures (852 for length/literals - and 592 for distances, the latter actually the result of an - exhaustive search). The true maximum is not known, but the value - below is more than safe. */ -#define ENOUGH 2048 -#define MAXD 592 - -/* Type of code to build for inftable() */ -typedef enum { - CODES, - LENS, - DISTS -} codetype; - -extern int inflate_table OF((codetype type, unsigned short FAR *lens, - unsigned codes, code FAR * FAR *table, - unsigned FAR *bits, unsigned short FAR *work)); +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1444 code structures (852 for length/literals + and 592 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 2048 +#define MAXD 592 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/trees.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/trees.h index 1ca868b848..72facf900f 100644 --- a/plugins/zerogs/opengl/ZeroGSShaders/zlib/trees.h +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/trees.h @@ -1,128 +1,128 @@ -/* header created automatically with -DGEN_TREES_H */ - -local const ct_data static_ltree[L_CODES+2] = { -{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, -{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, -{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, -{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, -{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, -{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, -{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, -{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, -{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, -{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, -{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, -{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, -{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, -{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, -{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, -{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, -{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, -{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, -{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, -{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, -{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, -{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, -{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, -{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, -{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, -{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, -{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, -{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, -{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, -{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, -{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, -{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, -{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, -{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, -{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, -{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, -{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, -{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, -{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, -{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, -{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, -{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, -{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, -{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, -{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, -{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, -{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, -{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, -{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, -{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, -{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, -{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, -{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, -{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, -{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, -{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, -{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, -{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} -}; - -local const ct_data static_dtree[D_CODES] = { -{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, -{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, -{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, -{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, -{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, -{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} -}; - -const uch _dist_code[DIST_CODE_LEN] = { - 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, - 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, -10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, -11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, -12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, -18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 -}; - -const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, -13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, -17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, -19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, -21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, -22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 -}; - -local const int base_length[LENGTH_CODES] = { -0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, -64, 80, 96, 112, 128, 160, 192, 224, 0 -}; - -local const int base_dist[D_CODES] = { - 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, - 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, - 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 -}; - +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/zconf.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/zconf.h index a5248c8b65..5bdcd2c56c 100644 --- a/plugins/zerogs/opengl/ZeroGSShaders/zlib/zconf.h +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/zconf.h @@ -1,332 +1,332 @@ -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id: zconf.h,v 1.2 2006/03/02 00:10:34 zerocool Exp $ */ - -#ifndef ZCONF_H -#define ZCONF_H - -/* - * If you *really* need a unique prefix for all types and library functions, - * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. - */ -#ifdef Z_PREFIX -# define deflateInit_ z_deflateInit_ -# define deflate z_deflate -# define deflateEnd z_deflateEnd -# define inflateInit_ z_inflateInit_ -# define inflate z_inflate -# define inflateEnd z_inflateEnd -# define deflateInit2_ z_deflateInit2_ -# define deflateSetDictionary z_deflateSetDictionary -# define deflateCopy z_deflateCopy -# define deflateReset z_deflateReset -# define deflateParams z_deflateParams -# define deflateBound z_deflateBound -# define deflatePrime z_deflatePrime -# define inflateInit2_ z_inflateInit2_ -# define inflateSetDictionary z_inflateSetDictionary -# define inflateSync z_inflateSync -# define inflateSyncPoint z_inflateSyncPoint -# define inflateCopy z_inflateCopy -# define inflateReset z_inflateReset -# define inflateBack z_inflateBack -# define inflateBackEnd z_inflateBackEnd -# define compress z_compress -# define compress2 z_compress2 -# define compressBound z_compressBound -# define uncompress z_uncompress -# define adler32 z_adler32 -# define crc32 z_crc32 -# define get_crc_table z_get_crc_table -# define zError z_zError - -# define alloc_func z_alloc_func -# define free_func z_free_func -# define in_func z_in_func -# define out_func z_out_func -# define Byte z_Byte -# define uInt z_uInt -# define uLong z_uLong -# define Bytef z_Bytef -# define charf z_charf -# define intf z_intf -# define uIntf z_uIntf -# define uLongf z_uLongf -# define voidpf z_voidpf -# define voidp z_voidp -#endif - -#if defined(__MSDOS__) && !defined(MSDOS) -# define MSDOS -#endif -#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) -# define OS2 -#endif -#if defined(_WINDOWS) && !defined(WINDOWS) -# define WINDOWS -#endif -#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) -# ifndef WIN32 -# define WIN32 -# endif -#endif -#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) -# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) -# ifndef SYS16BIT -# define SYS16BIT -# endif -# endif -#endif - -/* - * Compile with -DMAXSEG_64K if the alloc function cannot allocate more - * than 64k bytes at a time (needed on systems with 16-bit int). - */ -#ifdef SYS16BIT -# define MAXSEG_64K -#endif -#ifdef MSDOS -# define UNALIGNED_OK -#endif - -#ifdef __STDC_VERSION__ -# ifndef STDC -# define STDC -# endif -# if __STDC_VERSION__ >= 199901L -# ifndef STDC99 -# define STDC99 -# endif -# endif -#endif -#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) -# define STDC -#endif -#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) -# define STDC -#endif -#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) -# define STDC -#endif -#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) -# define STDC -#endif - -#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ -# define STDC -#endif - -#ifndef STDC -# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ -# define const /* note: need a more gentle solution here */ -# endif -#endif - -/* Some Mac compilers merge all .h files incorrectly: */ -#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) -# define NO_DUMMY_DECL -#endif - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# ifdef MAXSEG_64K -# define MAX_MEM_LEVEL 8 -# else -# define MAX_MEM_LEVEL 9 -# endif -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2. - * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files - * created by gzip. (Files created by minigzip can still be extracted by - * gzip.) - */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - (1 << (windowBits+2)) + (1 << (memLevel+9)) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects. -*/ - - /* Type declarations */ - -#ifndef OF /* function prototypes */ -# ifdef STDC -# define OF(args) args -# else -# define OF(args) () -# endif -#endif - -/* The following definitions for FAR are needed only for MSDOS mixed - * model programming (small or medium model with some far allocations). - * This was tested only with MSC; for other MSDOS compilers you may have - * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, - * just define FAR to be empty. - */ -#ifdef SYS16BIT -# if defined(M_I86SM) || defined(M_I86MM) - /* MSC small or medium model */ -# define SMALL_MEDIUM -# ifdef _MSC_VER -# define FAR _far -# else -# define FAR far -# endif -# endif -# if (defined(__SMALL__) || defined(__MEDIUM__)) - /* Turbo C small or medium model */ -# define SMALL_MEDIUM -# ifdef __BORLANDC__ -# define FAR _far -# else -# define FAR far -# endif -# endif -#endif - -#if defined(WINDOWS) || defined(WIN32) - /* If building or using zlib as a DLL, define ZLIB_DLL. - * This is not mandatory, but it offers a little performance increase. - */ -# ifdef ZLIB_DLL -# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) -# ifdef ZLIB_INTERNAL -# define ZEXTERN extern __declspec(dllexport) -# else -# define ZEXTERN extern __declspec(dllimport) -# endif -# endif -# endif /* ZLIB_DLL */ - /* If building or using zlib with the WINAPI/WINAPIV calling convention, - * define ZLIB_WINAPI. - * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. - */ -# ifdef ZLIB_WINAPI -# ifdef FAR -# undef FAR -# endif -# include - /* No need for _export, use ZLIB.DEF instead. */ - /* For complete Windows compatibility, use WINAPI, not __stdcall. */ -# define ZEXPORT WINAPI -# ifdef WIN32 -# define ZEXPORTVA WINAPIV -# else -# define ZEXPORTVA FAR CDECL -# endif -# endif -#endif - -#if defined (__BEOS__) -# ifdef ZLIB_DLL -# ifdef ZLIB_INTERNAL -# define ZEXPORT __declspec(dllexport) -# define ZEXPORTVA __declspec(dllexport) -# else -# define ZEXPORT __declspec(dllimport) -# define ZEXPORTVA __declspec(dllimport) -# endif -# endif -#endif - -#ifndef ZEXTERN -# define ZEXTERN extern -#endif -#ifndef ZEXPORT -# define ZEXPORT -#endif -#ifndef ZEXPORTVA -# define ZEXPORTVA -#endif - -#ifndef FAR -# define FAR -#endif - -#if !defined(__MACTYPES__) -typedef unsigned char Byte; /* 8 bits */ -#endif -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ - -#ifdef SMALL_MEDIUM - /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ -# define Bytef Byte FAR -#else - typedef Byte FAR Bytef; -#endif -typedef char FAR charf; -typedef int FAR intf; -typedef uInt FAR uIntf; -typedef uLong FAR uLongf; - -#ifdef STDC - typedef void const *voidpc; - typedef void FAR *voidpf; - typedef void *voidp; -#else - typedef Byte const *voidpc; - typedef Byte FAR *voidpf; - typedef Byte *voidp; -#endif - -#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ -# include /* for off_t */ -# include /* for SEEK_* and off_t */ -# ifdef VMS -# include /* for off_t */ -# endif -# define z_off_t off_t -#endif -#ifndef SEEK_SET -# define SEEK_SET 0 /* Seek from beginning of file. */ -# define SEEK_CUR 1 /* Seek from current position. */ -# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ -#endif -#ifndef z_off_t -# define z_off_t long -#endif - -#if defined(__OS400__) -# define NO_vsnprintf -#endif - -#if defined(__MVS__) -# define NO_vsnprintf -# ifdef FAR -# undef FAR -# endif -#endif - -/* MVS linker does not support external names larger than 8 bytes */ -#if defined(__MVS__) -# pragma map(deflateInit_,"DEIN") -# pragma map(deflateInit2_,"DEIN2") -# pragma map(deflateEnd,"DEEND") -# pragma map(deflateBound,"DEBND") -# pragma map(inflateInit_,"ININ") -# pragma map(inflateInit2_,"ININ2") -# pragma map(inflateEnd,"INEND") -# pragma map(inflateSync,"INSY") -# pragma map(inflateSetDictionary,"INSEDI") -# pragma map(compressBound,"CMBND") -# pragma map(inflate_table,"INTABL") -# pragma map(inflate_fast,"INFA") -# pragma map(inflate_copyright,"INCOPY") -#endif - -#endif /* ZCONF_H */ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.h,v 1.2 2006/03/02 00:10:34 zerocool Exp $ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/zconf.in.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/zconf.in.h index 48200f8d72..f7176a3b64 100644 --- a/plugins/zerogs/opengl/ZeroGSShaders/zlib/zconf.in.h +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/zconf.in.h @@ -1,332 +1,332 @@ -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id: zconf.in.h,v 1.2 2006/03/02 00:10:34 zerocool Exp $ */ - -#ifndef ZCONF_H -#define ZCONF_H - -/* - * If you *really* need a unique prefix for all types and library functions, - * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. - */ -#ifdef Z_PREFIX -# define deflateInit_ z_deflateInit_ -# define deflate z_deflate -# define deflateEnd z_deflateEnd -# define inflateInit_ z_inflateInit_ -# define inflate z_inflate -# define inflateEnd z_inflateEnd -# define deflateInit2_ z_deflateInit2_ -# define deflateSetDictionary z_deflateSetDictionary -# define deflateCopy z_deflateCopy -# define deflateReset z_deflateReset -# define deflateParams z_deflateParams -# define deflateBound z_deflateBound -# define deflatePrime z_deflatePrime -# define inflateInit2_ z_inflateInit2_ -# define inflateSetDictionary z_inflateSetDictionary -# define inflateSync z_inflateSync -# define inflateSyncPoint z_inflateSyncPoint -# define inflateCopy z_inflateCopy -# define inflateReset z_inflateReset -# define inflateBack z_inflateBack -# define inflateBackEnd z_inflateBackEnd -# define compress z_compress -# define compress2 z_compress2 -# define compressBound z_compressBound -# define uncompress z_uncompress -# define adler32 z_adler32 -# define crc32 z_crc32 -# define get_crc_table z_get_crc_table -# define zError z_zError - -# define alloc_func z_alloc_func -# define free_func z_free_func -# define in_func z_in_func -# define out_func z_out_func -# define Byte z_Byte -# define uInt z_uInt -# define uLong z_uLong -# define Bytef z_Bytef -# define charf z_charf -# define intf z_intf -# define uIntf z_uIntf -# define uLongf z_uLongf -# define voidpf z_voidpf -# define voidp z_voidp -#endif - -#if defined(__MSDOS__) && !defined(MSDOS) -# define MSDOS -#endif -#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) -# define OS2 -#endif -#if defined(_WINDOWS) && !defined(WINDOWS) -# define WINDOWS -#endif -#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) -# ifndef WIN32 -# define WIN32 -# endif -#endif -#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) -# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) -# ifndef SYS16BIT -# define SYS16BIT -# endif -# endif -#endif - -/* - * Compile with -DMAXSEG_64K if the alloc function cannot allocate more - * than 64k bytes at a time (needed on systems with 16-bit int). - */ -#ifdef SYS16BIT -# define MAXSEG_64K -#endif -#ifdef MSDOS -# define UNALIGNED_OK -#endif - -#ifdef __STDC_VERSION__ -# ifndef STDC -# define STDC -# endif -# if __STDC_VERSION__ >= 199901L -# ifndef STDC99 -# define STDC99 -# endif -# endif -#endif -#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) -# define STDC -#endif -#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) -# define STDC -#endif -#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) -# define STDC -#endif -#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) -# define STDC -#endif - -#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ -# define STDC -#endif - -#ifndef STDC -# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ -# define const /* note: need a more gentle solution here */ -# endif -#endif - -/* Some Mac compilers merge all .h files incorrectly: */ -#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) -# define NO_DUMMY_DECL -#endif - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# ifdef MAXSEG_64K -# define MAX_MEM_LEVEL 8 -# else -# define MAX_MEM_LEVEL 9 -# endif -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2. - * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files - * created by gzip. (Files created by minigzip can still be extracted by - * gzip.) - */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - (1 << (windowBits+2)) + (1 << (memLevel+9)) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects. -*/ - - /* Type declarations */ - -#ifndef OF /* function prototypes */ -# ifdef STDC -# define OF(args) args -# else -# define OF(args) () -# endif -#endif - -/* The following definitions for FAR are needed only for MSDOS mixed - * model programming (small or medium model with some far allocations). - * This was tested only with MSC; for other MSDOS compilers you may have - * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, - * just define FAR to be empty. - */ -#ifdef SYS16BIT -# if defined(M_I86SM) || defined(M_I86MM) - /* MSC small or medium model */ -# define SMALL_MEDIUM -# ifdef _MSC_VER -# define FAR _far -# else -# define FAR far -# endif -# endif -# if (defined(__SMALL__) || defined(__MEDIUM__)) - /* Turbo C small or medium model */ -# define SMALL_MEDIUM -# ifdef __BORLANDC__ -# define FAR _far -# else -# define FAR far -# endif -# endif -#endif - -#if defined(WINDOWS) || defined(WIN32) - /* If building or using zlib as a DLL, define ZLIB_DLL. - * This is not mandatory, but it offers a little performance increase. - */ -# ifdef ZLIB_DLL -# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) -# ifdef ZLIB_INTERNAL -# define ZEXTERN extern __declspec(dllexport) -# else -# define ZEXTERN extern __declspec(dllimport) -# endif -# endif -# endif /* ZLIB_DLL */ - /* If building or using zlib with the WINAPI/WINAPIV calling convention, - * define ZLIB_WINAPI. - * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. - */ -# ifdef ZLIB_WINAPI -# ifdef FAR -# undef FAR -# endif -# include - /* No need for _export, use ZLIB.DEF instead. */ - /* For complete Windows compatibility, use WINAPI, not __stdcall. */ -# define ZEXPORT WINAPI -# ifdef WIN32 -# define ZEXPORTVA WINAPIV -# else -# define ZEXPORTVA FAR CDECL -# endif -# endif -#endif - -#if defined (__BEOS__) -# ifdef ZLIB_DLL -# ifdef ZLIB_INTERNAL -# define ZEXPORT __declspec(dllexport) -# define ZEXPORTVA __declspec(dllexport) -# else -# define ZEXPORT __declspec(dllimport) -# define ZEXPORTVA __declspec(dllimport) -# endif -# endif -#endif - -#ifndef ZEXTERN -# define ZEXTERN extern -#endif -#ifndef ZEXPORT -# define ZEXPORT -#endif -#ifndef ZEXPORTVA -# define ZEXPORTVA -#endif - -#ifndef FAR -# define FAR -#endif - -#if !defined(__MACTYPES__) -typedef unsigned char Byte; /* 8 bits */ -#endif -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ - -#ifdef SMALL_MEDIUM - /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ -# define Bytef Byte FAR -#else - typedef Byte FAR Bytef; -#endif -typedef char FAR charf; -typedef int FAR intf; -typedef uInt FAR uIntf; -typedef uLong FAR uLongf; - -#ifdef STDC - typedef void const *voidpc; - typedef void FAR *voidpf; - typedef void *voidp; -#else - typedef Byte const *voidpc; - typedef Byte FAR *voidpf; - typedef Byte *voidp; -#endif - -#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ -# include /* for off_t */ -# include /* for SEEK_* and off_t */ -# ifdef VMS -# include /* for off_t */ -# endif -# define z_off_t off_t -#endif -#ifndef SEEK_SET -# define SEEK_SET 0 /* Seek from beginning of file. */ -# define SEEK_CUR 1 /* Seek from current position. */ -# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ -#endif -#ifndef z_off_t -# define z_off_t long -#endif - -#if defined(__OS400__) -# define NO_vsnprintf -#endif - -#if defined(__MVS__) -# define NO_vsnprintf -# ifdef FAR -# undef FAR -# endif -#endif - -/* MVS linker does not support external names larger than 8 bytes */ -#if defined(__MVS__) -# pragma map(deflateInit_,"DEIN") -# pragma map(deflateInit2_,"DEIN2") -# pragma map(deflateEnd,"DEEND") -# pragma map(deflateBound,"DEBND") -# pragma map(inflateInit_,"ININ") -# pragma map(inflateInit2_,"ININ2") -# pragma map(inflateEnd,"INEND") -# pragma map(inflateSync,"INSY") -# pragma map(inflateSetDictionary,"INSEDI") -# pragma map(compressBound,"CMBND") -# pragma map(inflate_table,"INTABL") -# pragma map(inflate_fast,"INFA") -# pragma map(inflate_copyright,"INCOPY") -#endif - -#endif /* ZCONF_H */ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.in.h,v 1.2 2006/03/02 00:10:34 zerocool Exp $ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/zlib.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/zlib.h index 62d0e4675b..022817927c 100644 --- a/plugins/zerogs/opengl/ZeroGSShaders/zlib/zlib.h +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/zlib.h @@ -1,1357 +1,1357 @@ -/* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.3, July 18th, 2005 - - Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - - - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). -*/ - -#ifndef ZLIB_H -#define ZLIB_H - -#include "zconf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define ZLIB_VERSION "1.2.3" -#define ZLIB_VERNUM 0x1230 - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed - data. This version of the library supports only one compression method - (deflation) but other algorithms will be added later and will have the same - stream interface. - - Compression can be done in a single step if the buffers are large - enough (for example if an input file is mmap'ed), or can be done by - repeated calls of the compression function. In the latter case, the - application must provide more input and/or consume the output - (providing more output space) before each call. - - The compressed data format used by default by the in-memory functions is - the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped - around a deflate stream, which is itself documented in RFC 1951. - - The library also supports reading and writing files in gzip (.gz) format - with an interface similar to that of stdio using the functions that start - with "gz". The gzip format is different from the zlib format. gzip is a - gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. - - This library can optionally read and write gzip streams in memory as well. - - The zlib format was designed to be compact and fast for use in memory - and on communications channels. The gzip format was designed for single- - file compression on file systems, has a larger header than zlib to maintain - directory information, and uses a different, slower check method than zlib. - - The library does not install any signal handler. The decoder checks - the consistency of the compressed data, so the library should never - crash even in case of corrupted input. -*/ - -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address)); - -struct internal_state; - -typedef struct z_stream_s { - Bytef *next_in; /* next input byte */ - uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total nb of input bytes read so far */ - - Bytef *next_out; /* next output byte should be put there */ - uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total nb of bytes output so far */ - - char *msg; /* last error message, NULL if no error */ - struct internal_state FAR *state; /* not visible by applications */ - - alloc_func zalloc; /* used to allocate the internal state */ - free_func zfree; /* used to free the internal state */ - voidpf opaque; /* private data object passed to zalloc and zfree */ - - int data_type; /* best guess about the data type: binary or text */ - uLong adler; /* adler32 value of the uncompressed data */ - uLong reserved; /* reserved for future use */ -} z_stream; - -typedef z_stream FAR *z_streamp; - -/* - gzip header information passed to and from zlib routines. See RFC 1952 - for more details on the meanings of these fields. -*/ -typedef struct gz_header_s { - int text; /* true if compressed data believed to be text */ - uLong time; /* modification time */ - int xflags; /* extra flags (not used when writing a gzip file) */ - int os; /* operating system */ - Bytef *extra; /* pointer to extra field or Z_NULL if none */ - uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ - uInt extra_max; /* space at extra (only when reading header) */ - Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ - uInt name_max; /* space at name (only when reading header) */ - Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ - uInt comm_max; /* space at comment (only when reading header) */ - int hcrc; /* true if there was or will be a header crc */ - int done; /* true when done reading gzip header (not used - when writing a gzip file) */ -} gz_header; - -typedef gz_header FAR *gz_headerp; - -/* - The application must update next_in and avail_in when avail_in has - dropped to zero. It must update next_out and avail_out when avail_out - has dropped to zero. The application must initialize zalloc, zfree and - opaque before calling the init function. All other fields are set by the - compression library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - If zlib is used in a multi-threaded application, zalloc and zfree must be - thread safe. - - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this - if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, - pointers returned by zalloc for objects of exactly 65536 bytes *must* - have their offset normalized to zero. The default allocation function - provided by this library ensures this (see zutil.c). To reduce memory - requirements and avoid any allocation of 64K objects, at the expense of - compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or - progress reports. After compression, total_in holds the total size of - the uncompressed data and may be saved for use in the decompressor - (particularly if the decompressor wants to decompress everything in - a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ -#define Z_SYNC_FLUSH 2 -#define Z_FULL_FLUSH 3 -#define Z_FINISH 4 -#define Z_BLOCK 5 -/* Allowed flush values; see deflate() and inflate() below for details */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_NEED_DICT 2 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -#define Z_VERSION_ERROR (-6) -/* Return codes for the compression/decompression functions. Negative - * values are errors, positive values are used for special but normal events. - */ - -#define Z_NO_COMPRESSION 0 -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_RLE 3 -#define Z_FIXED 4 -#define Z_DEFAULT_STRATEGY 0 -/* compression strategy; see deflateInit2() below for details */ - -#define Z_BINARY 0 -#define Z_TEXT 1 -#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ -#define Z_UNKNOWN 2 -/* Possible values of the data_type field (though see inflate()) */ - -#define Z_DEFLATED 8 -/* The deflate compression method (the only one supported in this version) */ - -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - -#define zlib_version zlibVersion() -/* for compatibility with versions < 1.0.2 */ - - /* basic functions */ - -ZEXTERN const char * ZEXPORT zlibVersion OF((void)); -/* The application can compare zlibVersion and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is - not compatible with the zlib.h header file used by the application. - This check is automatically made by deflateInit and inflateInit. - */ - -/* -ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); - - Initializes the internal stream state for compression. The fields - zalloc, zfree and opaque must be initialized before by the caller. - If zalloc and zfree are set to Z_NULL, deflateInit updates them to - use default allocation functions. - - The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: - 1 gives best speed, 9 gives best compression, 0 gives no compression at - all (the input data is simply copied a block at a time). - Z_DEFAULT_COMPRESSION requests a default compromise between speed and - compression (currently equivalent to level 6). - - deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if level is not a valid compression level, - Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible - with the version assumed by the caller (ZLIB_VERSION). - msg is set to null if there is no error message. deflateInit does not - perform any compression: this will be done by deflate(). -*/ - - -ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); -/* - deflate compresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce some - output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. deflate performs one or both of the - following actions: - - - Compress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in and avail_in are updated and - processing will resume at this point for the next call of deflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. This action is forced if the parameter flush is non zero. - Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary (in interactive applications). - Some output may be provided even if flush is not set. - - Before the call of deflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating avail_in or avail_out accordingly; avail_out - should never be zero before the call. The application can consume the - compressed output when it wants, for example when the output buffer is full - (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK - and with zero avail_out, it must be called again after making room in the - output buffer because there might be more output pending. - - Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to - decide how much data to accumualte before producing output, in order to - maximize compression. - - If the parameter flush is set to Z_SYNC_FLUSH, all pending output is - flushed to the output buffer and the output is aligned on a byte boundary, so - that the decompressor can get all input data available so far. (In particular - avail_in is zero after the call if enough output space has been provided - before the call.) Flushing may degrade compression for some compression - algorithms and so it should be used only when necessary. - - If flush is set to Z_FULL_FLUSH, all output is flushed as with - Z_SYNC_FLUSH, and the compression state is reset so that decompression can - restart from this point if previous compressed data has been damaged or if - random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - compression. - - If deflate returns with avail_out == 0, this function must be called again - with the same value of the flush parameter and more output space (updated - avail_out), until the flush is complete (deflate returns with non-zero - avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that - avail_out is greater than six to avoid repeated flush markers due to - avail_out == 0 on return. - - If the parameter flush is set to Z_FINISH, pending input is processed, - pending output is flushed and deflate returns with Z_STREAM_END if there - was enough output space; if deflate returns with Z_OK, this function must be - called again with Z_FINISH and more output space (updated avail_out) but no - more input data, until it returns with Z_STREAM_END or an error. After - deflate has returned Z_STREAM_END, the only possible operations on the - stream are deflateReset or deflateEnd. - - Z_FINISH can be used immediately after deflateInit if all the compression - is to be done in a single step. In this case, avail_out must be at least - the value returned by deflateBound (see below). If deflate does not return - Z_STREAM_END, then it must be called again as described above. - - deflate() sets strm->adler to the adler32 checksum of all input read - so far (that is, total_in bytes). - - deflate() may update strm->data_type if it can make a good guess about - the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered - binary. This field is only for information purposes and does not affect - the compression algorithm in any manner. - - deflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if all input has been - consumed and all output has been produced (only when flush is set to - Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible - (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not - fatal, and deflate() can be called again with more input and more output - space to continue compressing. -*/ - - -ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the - stream state was inconsistent, Z_DATA_ERROR if the stream was freed - prematurely (some input or output was discarded). In the error case, - msg may be set but then points to a static string (which must not be - deallocated). -*/ - - -/* -ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); - - Initializes the internal stream state for decompression. The fields - next_in, avail_in, zalloc, zfree and opaque must be initialized before by - the caller. If next_in is not Z_NULL and avail_in is large enough (the exact - value depends on the compression method), inflateInit determines the - compression method from the zlib header and allocates all data structures - accordingly; otherwise the allocation will be deferred to the first call of - inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to - use default allocation functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller. msg is set to null if there is no error - message. inflateInit does not perform any decompression apart from reading - the zlib header if present: this will be done by inflate(). (So next_in and - avail_in may be modified, but next_out and avail_out are unchanged.) -*/ - - -ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); -/* - inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce - some output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. inflate performs one or both of the - following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing - will resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() provides as much output as possible, until there - is no more input data or no more space in the output buffer (see below - about the flush parameter). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating the next_* and avail_* values accordingly. - The application can consume the uncompressed output when it wants, for - example when the output buffer is full (avail_out == 0), or after each - call of inflate(). If inflate returns Z_OK and with zero avail_out, it - must be called again after making room in the output buffer because there - might be more output pending. - - The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, - Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much - output as possible to the output buffer. Z_BLOCK requests that inflate() stop - if and when it gets to the next deflate block boundary. When decoding the - zlib or gzip format, this will cause inflate() to return immediately after - the header and before the first block. When doing a raw inflate, inflate() - will go ahead and process the first block, and will return when it gets to - the end of that block, or when it runs out of data. - - The Z_BLOCK option assists in appending to or combining deflate streams. - Also to assist in this, on return inflate() will set strm->data_type to the - number of unused bits in the last byte taken from strm->next_in, plus 64 - if inflate() is currently decoding the last block in the deflate stream, - plus 128 if inflate() returned immediately after decoding an end-of-block - code or decoding the complete header up to just before the first byte of the - deflate stream. The end-of-block will not be indicated until all of the - uncompressed data from that block has been written to strm->next_out. The - number of unused bits may in general be greater than seven, except when - bit 7 of data_type is set, in which case the number of unused bits will be - less than eight. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step - (a single call of inflate), the parameter flush should be set to - Z_FINISH. In this case all pending input is processed and all pending - output is flushed; avail_out must be large enough to hold all the - uncompressed data. (The size of the uncompressed data may have been saved - by the compressor for this purpose.) The next operation on this stream must - be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster approach - may be used for the single inflate() call. - - In this implementation, inflate() always flushes as much output as - possible to the output buffer, and always uses the faster approach on the - first call. So the only effect of the flush parameter in this implementation - is on the return value of inflate(), as noted below, or when it returns early - because Z_BLOCK is used. - - If a preset dictionary is needed after this call (see inflateSetDictionary - below), inflate sets strm->adler to the adler32 checksum of the dictionary - chosen by the compressor and returns Z_NEED_DICT; otherwise it sets - strm->adler to the adler32 checksum of all output produced so far (that is, - total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described - below. At the end of the stream, inflate() checks that its computed adler32 - checksum is equal to that saved by the compressor and returns Z_STREAM_END - only if the checksum is correct. - - inflate() will decompress and check either zlib-wrapped or gzip-wrapped - deflate data. The header type is detected automatically. Any information - contained in the gzip header is not retained, so applications that need that - information should instead use raw inflate, see inflateInit2() below, or - inflateBack() and perform their own processing of the gzip header and - trailer. - - inflate() returns Z_OK if some progress has been made (more input processed - or more output produced), Z_STREAM_END if the end of the compressed data has - been reached and all uncompressed output has been produced, Z_NEED_DICT if a - preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect check - value), Z_STREAM_ERROR if the stream structure was inconsistent (for example - if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, - Z_BUF_ERROR if no progress is possible or if there was not enough room in the - output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and - inflate() can be called again with more input and more output space to - continue decompressing. If Z_DATA_ERROR is returned, the application may then - call inflateSync() to look for a good compression block if a partial recovery - of the data is desired. -*/ - - -ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). -*/ - - /* Advanced functions */ - -/* - The following functions are needed only in some special applications. -*/ - -/* -ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); - - This is another version of deflateInit with more compression options. The - fields next_in, zalloc, zfree and opaque must be initialized before by - the caller. - - The method parameter is the compression method. It must be Z_DEFLATED in - this version of the library. - - The windowBits parameter is the base two logarithm of the window size - (the size of the history buffer). It should be in the range 8..15 for this - version of the library. Larger values of this parameter result in better - compression at the expense of memory usage. The default value is 15 if - deflateInit is used instead. - - windowBits can also be -8..-15 for raw deflate. In this case, -windowBits - determines the window size. deflate() will then generate raw deflate data - with no zlib header or trailer, and will not compute an adler32 check value. - - windowBits can also be greater than 15 for optional gzip encoding. Add - 16 to windowBits to write a simple gzip header and trailer around the - compressed data instead of a zlib wrapper. The gzip header will have no - file name, no extra data, no comment, no modification time (set to zero), - no header crc, and the operating system will be set to 255 (unknown). If a - gzip stream is being written, strm->adler is a crc32 instead of an adler32. - - The memLevel parameter specifies how much memory should be allocated - for the internal compression state. memLevel=1 uses minimum memory but - is slow and reduces compression ratio; memLevel=9 uses maximum memory - for optimal speed. The default value is 8. See zconf.h for total memory - usage as a function of windowBits and memLevel. - - The strategy parameter is used to tune the compression algorithm. Use the - value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match), or Z_RLE to limit match distances to one (run-length - encoding). Filtered data consists mostly of small values with a somewhat - random distribution. In this case, the compression algorithm is tuned to - compress them better. The effect of Z_FILTERED is to force more Huffman - coding and less string matching; it is somewhat intermediate between - Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as - Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy - parameter only affects the compression ratio but not the correctness of the - compressed output even if it is not set appropriately. Z_FIXED prevents the - use of dynamic Huffman codes, allowing for a simpler decoder for special - applications. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid - method). msg is set to null if there is no error message. deflateInit2 does - not perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the compression dictionary from the given byte sequence - without producing any compressed output. This function must be called - immediately after deflateInit, deflateInit2 or deflateReset, before any - call of deflate. The compressor and decompressor must use exactly the same - dictionary (see inflateSetDictionary). - - The dictionary should consist of strings (byte sequences) that are likely - to be encountered later in the data to be compressed, with the most commonly - used strings preferably put towards the end of the dictionary. Using a - dictionary is most useful when the data to be compressed is short and can be - predicted with good accuracy; the data can then be compressed better than - with the default empty dictionary. - - Depending on the size of the compression data structures selected by - deflateInit or deflateInit2, a part of the dictionary may in effect be - discarded, for example if the dictionary is larger than the window size in - deflate or deflate2. Thus the strings most likely to be useful should be - put at the end of the dictionary, not at the front. In addition, the - current implementation of deflate will use at most the window size minus - 262 bytes of the provided dictionary. - - Upon return of this function, strm->adler is set to the adler32 value - of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The adler32 value - applies to the whole dictionary even if only a subset of the dictionary is - actually used by the compressor.) If a raw deflate was requested, then the - adler32 value is not computed and strm->adler is not set. - - deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent (for example if deflate has already been called for this stream - or if the compression method is bsort). deflateSetDictionary does not - perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when several compression strategies will be - tried, for example when there are several ways of pre-processing the input - data with a filter. The streams that will be discarded should then be freed - by calling deflateEnd. Note that deflateCopy duplicates the internal - compression state which can be quite large, so this strategy is slow and - can consume lots of memory. - - deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); -/* - This function is equivalent to deflateEnd followed by deflateInit, - but does not free and reallocate all the internal compression state. - The stream will keep the same compression level and any other attributes - that may have been set by deflateInit2. - - deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, - int level, - int strategy)); -/* - Dynamically update the compression level and compression strategy. The - interpretation of level and strategy is as in deflateInit2. This can be - used to switch between compression and straight copy of the input data, or - to switch to a different kind of input data requiring a different - strategy. If the compression level is changed, the input available so far - is compressed with the old level (and may be flushed); the new level will - take effect only at the next call of deflate(). - - Before the call of deflateParams, the stream state must be set as for - a call of deflate(), since the currently available input may have to - be compressed and flushed. In particular, strm->avail_out must be non-zero. - - deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source - stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR - if strm->avail_out was zero. -*/ - -ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, - int good_length, - int max_lazy, - int nice_length, - int max_chain)); -/* - Fine tune deflate's internal compression parameters. This should only be - used by someone who understands the algorithm used by zlib's deflate for - searching for the best matching string, and even then only by the most - fanatic optimizer trying to squeeze out the last compressed bit for their - specific input data. Read the deflate.c source code for the meaning of the - max_lazy, good_length, nice_length, and max_chain parameters. - - deflateTune() can be called after deflateInit() or deflateInit2(), and - returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. - */ - -ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, - uLong sourceLen)); -/* - deflateBound() returns an upper bound on the compressed size after - deflation of sourceLen bytes. It must be called after deflateInit() - or deflateInit2(). This would be used to allocate an output buffer - for deflation in a single pass, and so would be called before deflate(). -*/ - -ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - deflatePrime() inserts bits in the deflate output stream. The intent - is that this function is used to start off the deflate output with the - bits leftover from a previous deflate stream when appending to it. As such, - this function can only be used for raw deflate, and must be used before the - first deflate() call after a deflateInit2() or deflateReset(). bits must be - less than or equal to 16, and that many of the least significant bits of - value will be inserted in the output. - - deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, - gz_headerp head)); -/* - deflateSetHeader() provides gzip header information for when a gzip - stream is requested by deflateInit2(). deflateSetHeader() may be called - after deflateInit2() or deflateReset() and before the first call of - deflate(). The text, time, os, extra field, name, and comment information - in the provided gz_header structure are written to the gzip header (xflag is - ignored -- the extra flags are set according to the compression level). The - caller must assure that, if not Z_NULL, name and comment are terminated with - a zero byte, and that if extra is not Z_NULL, that extra_len bytes are - available there. If hcrc is true, a gzip header crc is included. Note that - the current versions of the command-line version of gzip (up through version - 1.3.x) do not support header crc's, and will report that it is a "multi-part - gzip file" and give up. - - If deflateSetHeader is not used, the default gzip header has text false, - the time set to zero, and os set to 255, with no extra, name, or comment - fields. The gzip header is returned to the default state by deflateReset(). - - deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, - int windowBits)); - - This is another version of inflateInit with an extra parameter. The - fields next_in, avail_in, zalloc, zfree and opaque must be initialized - before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library. The default value is 15 if inflateInit is used - instead. windowBits must be greater than or equal to the windowBits value - provided to deflateInit2() while compressing, or it must be equal to 15 if - deflateInit2() was not used. If a compressed stream with a larger window - size is given as input, inflate() will return with the error code - Z_DATA_ERROR instead of trying to allocate a larger window. - - windowBits can also be -8..-15 for raw inflate. In this case, -windowBits - determines the window size. inflate() will then process raw deflate data, - not looking for a zlib or gzip header, not generating a check value, and not - looking for any check values for comparison at the end of the stream. This - is for use with other formats that use the deflate compressed data format - such as zip. Those formats provide their own check values. If a custom - format is developed using the raw deflate format for compressed data, it is - recommended that a check value such as an adler32 or a crc32 be applied to - the uncompressed data as is done in the zlib, gzip, and zip formats. For - most applications, the zlib format should be used as is. Note that comments - above on the use in deflateInit2() applies to the magnitude of windowBits. - - windowBits can also be greater than 15 for optional gzip decoding. Add - 32 to windowBits to enable zlib and gzip decoding with automatic header - detection, or add 16 to decode only the gzip format (the zlib format will - return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is - a crc32 instead of an adler32. - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg - is set to null if there is no error message. inflateInit2 does not perform - any decompression apart from reading the zlib header if present: this will - be done by inflate(). (So next_in and avail_in may be modified, but next_out - and avail_out are unchanged.) -*/ - -ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate, - if that call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the adler32 value returned by that call of inflate. - The compressor and decompressor must use exactly the same dictionary (see - deflateSetDictionary). For raw inflate, this function can be called - immediately after inflateInit2() or inflateReset() and before any call of - inflate() to set the dictionary. The application must insure that the - dictionary that was used for compression is provided. - - inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect adler32 value). inflateSetDictionary does not - perform any decompression: this will be done by subsequent calls of - inflate(). -*/ - -ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); -/* - Skips invalid compressed data until a full flush point (see above the - description of deflate with Z_FULL_FLUSH) can be found, or until all - available input is skipped. No output is provided. - - inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR - if no more input was provided, Z_DATA_ERROR if no flush point has been found, - or Z_STREAM_ERROR if the stream structure was inconsistent. In the success - case, the application may save the current current value of total_in which - indicates where valid compressed data was found. In the error case, the - application may repeatedly call inflateSync, providing more input each time, - until success or end of the input data. -*/ - -ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when randomly accessing a large stream. The - first pass through the stream can periodically record the inflate state, - allowing restarting inflate at those points when randomly accessing the - stream. - - inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); -/* - This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate all the internal decompression state. - The stream will keep attributes that may have been set by inflateInit2. - - inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - This function inserts bits in the inflate input stream. The intent is - that this function is used to start inflating at a bit position in the - middle of a byte. The provided bits will be used before any bytes are used - from next_in. This function should only be used with raw inflate, and - should be used before the first inflate() call after inflateInit2() or - inflateReset(). bits must be less than or equal to 16, and that many of the - least significant bits of value will be inserted in the input. - - inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, - gz_headerp head)); -/* - inflateGetHeader() requests that gzip header information be stored in the - provided gz_header structure. inflateGetHeader() may be called after - inflateInit2() or inflateReset(), and before the first call of inflate(). - As inflate() processes the gzip stream, head->done is zero until the header - is completed, at which time head->done is set to one. If a zlib stream is - being decoded, then head->done is set to -1 to indicate that there will be - no gzip header information forthcoming. Note that Z_BLOCK can be used to - force inflate() to return immediately after header processing is complete - and before any actual data is decompressed. - - The text, time, xflags, and os fields are filled in with the gzip header - contents. hcrc is set to true if there is a header CRC. (The header CRC - was valid if done is set to one.) If extra is not Z_NULL, then extra_max - contains the maximum number of bytes to write to extra. Once done is true, - extra_len contains the actual extra field length, and extra contains the - extra field, or that field truncated if extra_max is less than extra_len. - If name is not Z_NULL, then up to name_max characters are written there, - terminated with a zero unless the length is greater than name_max. If - comment is not Z_NULL, then up to comm_max characters are written there, - terminated with a zero unless the length is greater than comm_max. When - any of extra, name, or comment are not Z_NULL and the respective field is - not present in the header, then that field is set to Z_NULL to signal its - absence. This allows the use of deflateSetHeader() with the returned - structure to duplicate the header. However if those fields are set to - allocated memory, then the application will need to save those pointers - elsewhere so that they can be eventually freed. - - If inflateGetHeader is not used, then the header information is simply - discarded. The header is always checked for validity, including the header - CRC if present. inflateReset() will reset the process to discard the header - information. The application would need to call inflateGetHeader() again to - retrieve the header from the next gzip stream. - - inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, - unsigned char FAR *window)); - - Initialize the internal stream state for decompression using inflateBack() - calls. The fields zalloc, zfree and opaque in strm must be initialized - before the call. If zalloc and zfree are Z_NULL, then the default library- - derived memory allocation routines are used. windowBits is the base two - logarithm of the window size, in the range 8..15. window is a caller - supplied buffer of that size. Except for special applications where it is - assured that deflate was used with small window sizes, windowBits must be 15 - and a 32K byte window must be supplied to be able to decompress general - deflate streams. - - See inflateBack() for the usage of these routines. - - inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of - the paramaters are invalid, Z_MEM_ERROR if the internal state could not - be allocated, or Z_VERSION_ERROR if the version of the library does not - match the version of the header file. -*/ - -typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); -typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); - -ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, - in_func in, void FAR *in_desc, - out_func out, void FAR *out_desc)); -/* - inflateBack() does a raw inflate with a single call using a call-back - interface for input and output. This is more efficient than inflate() for - file i/o applications in that it avoids copying between the output and the - sliding window by simply making the window itself the output buffer. This - function trusts the application to not change the output buffer passed by - the output function, at least until inflateBack() returns. - - inflateBackInit() must be called first to allocate the internal state - and to initialize the state with the user-provided window buffer. - inflateBack() may then be used multiple times to inflate a complete, raw - deflate stream with each call. inflateBackEnd() is then called to free - the allocated state. - - A raw deflate stream is one with no zlib or gzip header or trailer. - This routine would normally be used in a utility that reads zip or gzip - files and writes out uncompressed files. The utility would decode the - header and process the trailer on its own, hence this routine expects - only the raw deflate stream to decompress. This is different from the - normal behavior of inflate(), which expects either a zlib or gzip header and - trailer around the deflate stream. - - inflateBack() uses two subroutines supplied by the caller that are then - called by inflateBack() for input and output. inflateBack() calls those - routines until it reads a complete deflate stream and writes out all of the - uncompressed data, or until it encounters an error. The function's - parameters and return types are defined above in the in_func and out_func - typedefs. inflateBack() will call in(in_desc, &buf) which should return the - number of bytes of provided input, and a pointer to that input in buf. If - there is no input available, in() must return zero--buf is ignored in that - case--and inflateBack() will return a buffer error. inflateBack() will call - out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() - should return zero on success, or non-zero on failure. If out() returns - non-zero, inflateBack() will return with an error. Neither in() nor out() - are permitted to change the contents of the window provided to - inflateBackInit(), which is also the buffer that out() uses to write from. - The length written by out() will be at most the window size. Any non-zero - amount of input may be provided by in(). - - For convenience, inflateBack() can be provided input on the first call by - setting strm->next_in and strm->avail_in. If that input is exhausted, then - in() will be called. Therefore strm->next_in must be initialized before - calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called - immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in - must also be initialized, and then if strm->avail_in is not zero, input will - initially be taken from strm->next_in[0 .. strm->avail_in - 1]. - - The in_desc and out_desc parameters of inflateBack() is passed as the - first parameter of in() and out() respectively when they are called. These - descriptors can be optionally used to pass any information that the caller- - supplied in() and out() functions need to do their job. - - On return, inflateBack() will set strm->next_in and strm->avail_in to - pass back any unused input that was provided by the last in() call. The - return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR - if in() or out() returned an error, Z_DATA_ERROR if there was a format - error in the deflate stream (in which case strm->msg is set to indicate the - nature of the error), or Z_STREAM_ERROR if the stream was not properly - initialized. In the case of Z_BUF_ERROR, an input or output error can be - distinguished using strm->next_in which will be Z_NULL only if in() returned - an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to - out() returning non-zero. (in() will always be called before out(), so - strm->next_in is assured to be defined if out() returns non-zero.) Note - that inflateBack() cannot return Z_OK. -*/ - -ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); -/* - All memory allocated by inflateBackInit() is freed. - - inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream - state was inconsistent. -*/ - -ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); -/* Return flags indicating compile-time options. - - Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: - 1.0: size of uInt - 3.2: size of uLong - 5.4: size of voidpf (pointer) - 7.6: size of z_off_t - - Compiler, assembler, and debug options: - 8: DEBUG - 9: ASMV or ASMINF -- use ASM code - 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention - 11: 0 (reserved) - - One-time table building (smaller code, but not thread-safe if true): - 12: BUILDFIXED -- build static block decoding tables when needed - 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed - 14,15: 0 (reserved) - - Library content (indicates missing functionality): - 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking - deflate code when not needed) - 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect - and decode gzip streams (to avoid linking crc code) - 18-19: 0 (reserved) - - Operation variations (changes in library functionality): - 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate - 21: FASTEST -- deflate algorithm with only one, lowest compression level - 22,23: 0 (reserved) - - The sprintf variant used by gzprintf (zero is best): - 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format - 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! - 26: 0 = returns value, 1 = void -- 1 means inferred string length returned - - Remainder: - 27-31: 0 (reserved) - */ - - - /* utility functions */ - -/* - The following utility functions are implemented on top of the - basic stream-oriented functions. To simplify the interface, some - default options are assumed (compression level and memory usage, - standard memory allocation functions). The source code of these - utility functions can easily be modified if you need special options. -*/ - -ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Compresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be at least the value returned - by compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - This function can be used to compress a whole file at once if the - input file is mmap'ed. - compress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer. -*/ - -ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen, - int level)); -/* - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least the value returned by - compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ - -ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); -/* - compressBound() returns an upper bound on the compressed size after - compress() or compress2() on sourceLen bytes. It would be used before - a compress() or compress2() call to allocate the destination buffer. -*/ - -ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. -*/ - - -typedef voidp gzFile; - -ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); -/* - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb") but can also include a compression level - ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for - Huffman only compression as in "wb1h", or 'R' for run-length encoding - as in "wb1R". (See the description of deflateInit2 for more information - about the strategy parameter.) - - gzopen can be used to read a file which is not in gzip format; in this - case gzread will directly read from the file without decompression. - - gzopen returns NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). */ - -ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); -/* - gzdopen() associates a gzFile with the file descriptor fd. File - descriptors are obtained from calls like open, dup, creat, pipe or - fileno (in the file has been previously opened with fopen). - The mode parameter is as in gzopen. - The next call of gzclose on the returned gzFile will also close the - file descriptor fd, just like fclose(fdopen(fd), mode) closes the file - descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). - gzdopen returns NULL if there was insufficient memory to allocate - the (de)compression state. -*/ - -ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); -/* - Dynamically update the compression level or strategy. See the description - of deflateInit2 for the meaning of these parameters. - gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not - opened for writing. -*/ - -ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); -/* - Reads the given number of uncompressed bytes from the compressed file. - If the input file was not in gzip format, gzread copies the given number - of bytes into the buffer. - gzread returns the number of uncompressed bytes actually read (0 for - end of file, -1 for error). */ - -ZEXTERN int ZEXPORT gzwrite OF((gzFile file, - voidpc buf, unsigned len)); -/* - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of uncompressed bytes actually written - (0 in case of error). -*/ - -ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); -/* - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). The number of - uncompressed bytes written is limited to 4095. The caller should assure that - this limit is not exceeded. If it is exceeded, then gzprintf() will return - return an error (0) with nothing written. In this case, there may also be a - buffer overflow with unpredictable consequences, which is possible only if - zlib was compiled with the insecure functions sprintf() or vsprintf() - because the secure snprintf() or vsnprintf() functions were not available. -*/ - -ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); -/* - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. -*/ - -ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); -/* - Reads bytes from the compressed file until len-1 characters are read, or - a newline character is read and transferred to buf, or an end-of-file - condition is encountered. The string is then terminated with a null - character. - gzgets returns buf, or Z_NULL in case of error. -*/ - -ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); -/* - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. -*/ - -ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); -/* - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. -*/ - -ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); -/* - Push one character back onto the stream to be read again later. - Only one character of push-back is allowed. gzungetc() returns the - character pushed, or -1 on failure. gzungetc() will fail if a - character has been pushed but not read yet, or if c is -1. The pushed - character will be discarded if the stream is repositioned with gzseek() - or gzrewind(). -*/ - -ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); -/* - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. The return value is the zlib - error number (see function gzerror below). gzflush returns Z_OK if - the flush parameter is Z_FINISH and all output could be flushed. - gzflush should be called only when strictly necessary because it can - degrade compression. -*/ - -ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, - z_off_t offset, int whence)); -/* - Sets the starting position for the next gzread or gzwrite on the - given compressed file. The offset represents a number of bytes in the - uncompressed data stream. The whence parameter is defined as in lseek(2); - the value SEEK_END is not supported. - If the file is opened for reading, this function is emulated but can be - extremely slow. If the file is opened for writing, only forward seeks are - supported; gzseek then compresses a sequence of zeroes up to the new - starting position. - - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error, in - particular if the file is opened for writing and the new starting position - would be before the current position. -*/ - -ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); -/* - Rewinds the given file. This function is supported only for reading. - - gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) -*/ - -ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); -/* - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. - - gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) -*/ - -ZEXTERN int ZEXPORT gzeof OF((gzFile file)); -/* - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. -*/ - -ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); -/* - Returns 1 if file is being read directly without decompression, otherwise - zero. -*/ - -ZEXTERN int ZEXPORT gzclose OF((gzFile file)); -/* - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. The return value is the zlib - error number (see function gzerror below). -*/ - -ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); -/* - Returns the error message for the last error which occurred on the - given compressed file. errnum is set to zlib error number. If an - error occurred in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. -*/ - -ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); -/* - Clears the error and end-of-file flags for file. This is analogous to the - clearerr() function in stdio. This is useful for continuing to read a gzip - file that is being written concurrently. -*/ - - /* checksum functions */ - -/* - These functions are not related to compression but are exported - anyway because they might be useful in applications using the - compression library. -*/ - -ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); -/* - Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. If buf is NULL, this function returns - the required initial value for the checksum. - An Adler-32 checksum is almost as reliable as a CRC32 but can be computed - much faster. Usage example: - - uLong adler = adler32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - adler = adler32(adler, buffer, length); - } - if (adler != original_adler) error(); -*/ - -ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, - z_off_t len2)); -/* - Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 - and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for - each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of - seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. -*/ - -ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); -/* - Update a running CRC-32 with the bytes buf[0..len-1] and return the - updated CRC-32. If buf is NULL, this function returns the required initial - value for the for the crc. Pre- and post-conditioning (one's complement) is - performed within this function so it shouldn't be done by the application. - Usage example: - - uLong crc = crc32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - crc = crc32(crc, buffer, length); - } - if (crc != original_crc) error(); -*/ - -ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); - -/* - Combine two CRC-32 check values into one. For two sequences of bytes, - seq1 and seq2 with lengths len1 and len2, CRC-32 check values were - calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 - check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and - len2. -*/ - - - /* various hacks, don't look :) */ - -/* deflateInit and inflateInit are macros to allow checking the zlib version - * and the compiler's view of z_stream: - */ -ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy, const char *version, - int stream_size)); -ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, - unsigned char FAR *window, - const char *version, - int stream_size)); -#define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) -#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) -#define inflateBackInit(strm, windowBits, window) \ - inflateBackInit_((strm), (windowBits), (window), \ - ZLIB_VERSION, sizeof(z_stream)) - - -#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) - struct internal_state {int dummy;}; /* hack for buggy compilers */ -#endif - -ZEXTERN const char * ZEXPORT zError OF((int)); -ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); -ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); - -#ifdef __cplusplus -} -#endif - -#endif /* ZLIB_H */ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/zutil.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/zutil.h index b691f27c26..ecfeb756e7 100644 --- a/plugins/zerogs/opengl/ZeroGSShaders/zlib/zutil.h +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/zutil.h @@ -1,269 +1,269 @@ -/* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id: zutil.h,v 1.2 2006/03/02 00:10:34 zerocool Exp $ */ - -#ifndef ZUTIL_H -#define ZUTIL_H - -#define ZLIB_INTERNAL -#include "zlib.h" - -#ifdef STDC -# ifndef _WIN32_WCE -# include -# endif -# include -# include -#endif -#ifdef NO_ERRNO_H -# ifdef _WIN32_WCE - /* The Microsoft C Run-Time Library for Windows CE doesn't have - * errno. We define it as a global variable to simplify porting. - * Its value is always 0 and should not be used. We rename it to - * avoid conflict with other libraries that use the same workaround. - */ -# define errno z_errno -# endif - extern int errno; -#else -# ifndef _WIN32_WCE -# include -# endif -#endif - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -typedef unsigned char uch; -typedef uch FAR uchf; -typedef unsigned short ush; -typedef ush FAR ushf; -typedef unsigned long ulg; - -extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ -/* (size given to avoid silly warnings with Visual C++) */ - -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] - -#define ERR_RETURN(strm,err) \ - return (strm->msg = (char*)ERR_MSG(err), (err)) -/* To be used only when the state is known to be valid */ - - /* common constants */ - -#ifndef DEF_WBITS -# define DEF_WBITS MAX_WBITS -#endif -/* default windowBits for decompression. MAX_WBITS is for compression only */ - -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -/* default memLevel */ - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - -#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ - - /* target dependencies */ - -#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) -# define OS_CODE 0x00 -# if defined(__TURBOC__) || defined(__BORLANDC__) -# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) - /* Allow compilation with ANSI keywords only enabled */ - void _Cdecl farfree( void *block ); - void *_Cdecl farmalloc( unsigned long nbytes ); -# else -# include -# endif -# else /* MSC or DJGPP */ -# include -# endif -#endif - -#ifdef AMIGA -# define OS_CODE 0x01 -#endif - -#if defined(VAXC) || defined(VMS) -# define OS_CODE 0x02 -# define F_OPEN(name, mode) \ - fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") -#endif - -#if defined(ATARI) || defined(atarist) -# define OS_CODE 0x05 -#endif - -#ifdef OS2 -# define OS_CODE 0x06 -# ifdef M_I86 - #include -# endif -#endif - -#if defined(MACOS) || defined(TARGET_OS_MAC) -# define OS_CODE 0x07 -# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os -# include /* for fdopen */ -# else -# ifndef fdopen -# define fdopen(fd,mode) NULL /* No fdopen() */ -# endif -# endif -#endif - -#ifdef TOPS20 -# define OS_CODE 0x0a -#endif - -#ifdef WIN32 -# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ -# define OS_CODE 0x0b -# endif -#endif - -#ifdef __50SERIES /* Prime/PRIMOS */ -# define OS_CODE 0x0f -#endif - -#if defined(_BEOS_) || defined(RISCOS) -# define fdopen(fd,mode) NULL /* No fdopen() */ -#endif - -#if (defined(_MSC_VER) && (_MSC_VER > 600)) -# if defined(_WIN32_WCE) -# define fdopen(fd,mode) NULL /* No fdopen() */ -# ifndef _PTRDIFF_T_DEFINED - typedef int ptrdiff_t; -# define _PTRDIFF_T_DEFINED -# endif -# else -# define fdopen(fd,type) _fdopen(fd,type) -# endif -#endif - - /* common defaults */ - -#ifndef OS_CODE -# define OS_CODE 0x03 /* assume Unix */ -#endif - -#ifndef F_OPEN -# define F_OPEN(name, mode) fopen((name), (mode)) -#endif - - /* functions */ - -#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif -#if defined(__CYGWIN__) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif -#ifndef HAVE_VSNPRINTF -# ifdef MSDOS - /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), - but for now we just assume it doesn't. */ -# define NO_vsnprintf -# endif -# ifdef __TURBOC__ -# define NO_vsnprintf -# endif -# ifdef WIN32 - /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ -# if !defined(vsnprintf) && !defined(NO_vsnprintf) -# define vsnprintf _vsnprintf -# endif -# endif -# ifdef __SASC -# define NO_vsnprintf -# endif -#endif -#ifdef VMS -# define NO_vsnprintf -#endif - -#if defined(pyr) -# define NO_MEMCPY -#endif -#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) - /* Use our own functions for small and medium model with MSC <= 5.0. - * You may have to use the same strategy for Borland C (untested). - * The __SC__ check is for Symantec. - */ -# define NO_MEMCPY -#endif -#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) -# define HAVE_MEMCPY -#endif -#ifdef HAVE_MEMCPY -# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ -# define zmemcpy _fmemcpy -# define zmemcmp _fmemcmp -# define zmemzero(dest, len) _fmemset(dest, 0, len) -# else -# define zmemcpy memcpy -# define zmemcmp memcmp -# define zmemzero(dest, len) memset(dest, 0, len) -# endif -#else - extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); - extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); - extern void zmemzero OF((Bytef* dest, uInt len)); -#endif - -/* Diagnostic functions */ -#ifdef DEBUG -# include - extern int z_verbose; - extern void z_error OF((char *m)); -# define Assert(cond,msg) {if(!(cond)) z_error(msg);} -# define Trace(x) {if (z_verbose>=0) fprintf x ;} -# define Tracev(x) {if (z_verbose>0) fprintf x ;} -# define Tracevv(x) {if (z_verbose>1) fprintf x ;} -# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} -# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - - -voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); -void zcfree OF((voidpf opaque, voidpf ptr)); - -#define ZALLOC(strm, items, size) \ - (*((strm)->zalloc))((strm)->opaque, (items), (size)) -#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) -#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} - -#endif /* ZUTIL_H */ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: zutil.h,v 1.2 2006/03/02 00:10:34 zerocool Exp $ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# ifndef _WIN32_WCE +# include +# endif +# include +# include +#endif +#ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif + extern int errno; +#else +# ifndef _WIN32_WCE +# include +# endif +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 + #include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zpipe.cpp b/plugins/zerogs/opengl/ZeroGSShaders/zpipe.cpp index 4a94499be8..c259407e32 100644 --- a/plugins/zerogs/opengl/ZeroGSShaders/zpipe.cpp +++ b/plugins/zerogs/opengl/ZeroGSShaders/zpipe.cpp @@ -1,115 +1,115 @@ -// zpipe.cpp : Defines the entry point for the console application. -// - -#include - -#include -#include -#include - -//#define ZLIB_WINAPI -#include - -int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) ; -int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress) ; - -int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) -{ - z_stream strm; - - int ret;//, flush; - unsigned have; - - /* allocate deflate state */ - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION) ; - if (ret != Z_OK) - return ret; - - /* compress */ - strm.avail_in = bytes_to_compress ; - strm.avail_out = bytes_to_compress ; - strm.next_in = (Bytef *)src ; - strm.next_out = (Bytef *)dst ; - - ret = deflate(&strm, Z_FINISH) ; - have = bytes_to_compress - strm.avail_out ; - *bytes_after_compressed = have ; - - assert(ret == Z_STREAM_END); /* stream will be complete */ - - /* clean up and return */ - (void)deflateEnd(&strm); - return Z_OK; -} - -int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress, int* outbytes) -{ - z_stream strm; - - int ret; - //unsigned have; - - /* allocate inflate state */ - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = 0; - strm.next_in = Z_NULL; - ret = inflateInit(&strm); - if (ret != Z_OK) - return ret; - - /* decompress */ - strm.avail_in = bytes_to_decompress ; - strm.next_in = (Bytef *)src ; - strm.next_out = (Bytef *)dst ; - strm.avail_out = maximum_after_decompress ; - - ret = inflate(&strm, Z_NO_FLUSH) ; - assert(ret != Z_STREAM_ERROR); /* state not clobbered */ - switch (ret) { - case Z_NEED_DICT: - ret = Z_DATA_ERROR; /* and fall through */ - case Z_DATA_ERROR: - case Z_MEM_ERROR: - (void)inflateEnd(&strm); - return ret; - } - - assert(strm.avail_in == 0); /* all input will be used */ - - if( outbytes != NULL ) - *outbytes = strm.total_out; - - /* clean up and return */ - (void)inflateEnd(&strm); - return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; -} - -/* report a zlib or i/o error */ -void zerr(int ret) -{ - fputs("zpipe: ", stderr); - switch (ret) { - case Z_ERRNO: - if (ferror(stdin)) - fputs("error reading stdin\n", stderr); - if (ferror(stdout)) - fputs("error writing stdout\n", stderr); - break; - case Z_STREAM_ERROR: - fputs("invalid compression level\n", stderr); - break; - case Z_DATA_ERROR: - fputs("invalid or incomplete deflate data\n", stderr); - break; - case Z_MEM_ERROR: - fputs("out of memory\n", stderr); - break; - case Z_VERSION_ERROR: - fputs("zlib version mismatch!\n", stderr); - } -} +// zpipe.cpp : Defines the entry point for the console application. +// + +#include + +#include +#include +#include + +//#define ZLIB_WINAPI +#include + +int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) ; +int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress) ; + +int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) +{ + z_stream strm; + + int ret;//, flush; + unsigned have; + + /* allocate deflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION) ; + if (ret != Z_OK) + return ret; + + /* compress */ + strm.avail_in = bytes_to_compress ; + strm.avail_out = bytes_to_compress ; + strm.next_in = (Bytef *)src ; + strm.next_out = (Bytef *)dst ; + + ret = deflate(&strm, Z_FINISH) ; + have = bytes_to_compress - strm.avail_out ; + *bytes_after_compressed = have ; + + assert(ret == Z_STREAM_END); /* stream will be complete */ + + /* clean up and return */ + (void)deflateEnd(&strm); + return Z_OK; +} + +int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress, int* outbytes) +{ + z_stream strm; + + int ret; + //unsigned have; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit(&strm); + if (ret != Z_OK) + return ret; + + /* decompress */ + strm.avail_in = bytes_to_decompress ; + strm.next_in = (Bytef *)src ; + strm.next_out = (Bytef *)dst ; + strm.avail_out = maximum_after_decompress ; + + ret = inflate(&strm, Z_NO_FLUSH) ; + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + switch (ret) { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; /* and fall through */ + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + return ret; + } + + assert(strm.avail_in == 0); /* all input will be used */ + + if( outbytes != NULL ) + *outbytes = strm.total_out; + + /* clean up and return */ + (void)inflateEnd(&strm); + return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; +} + +/* report a zlib or i/o error */ +void zerr(int ret) +{ + fputs("zpipe: ", stderr); + switch (ret) { + case Z_ERRNO: + if (ferror(stdin)) + fputs("error reading stdin\n", stderr); + if (ferror(stdout)) + fputs("error writing stdout\n", stderr); + break; + case Z_STREAM_ERROR: + fputs("invalid compression level\n", stderr); + break; + case Z_DATA_ERROR: + fputs("invalid or incomplete deflate data\n", stderr); + break; + case Z_MEM_ERROR: + fputs("out of memory\n", stderr); + break; + case Z_VERSION_ERROR: + fputs("zlib version mismatch!\n", stderr); + } +} diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zpipe.h b/plugins/zerogs/opengl/ZeroGSShaders/zpipe.h index cb96229553..2b3f8b3262 100644 --- a/plugins/zerogs/opengl/ZeroGSShaders/zpipe.h +++ b/plugins/zerogs/opengl/ZeroGSShaders/zpipe.h @@ -1,7 +1,7 @@ -#ifndef zpipe_h -#define zpipe_h - -int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) ; -int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress, int* outbytes); - -#endif +#ifndef zpipe_h +#define zpipe_h + +int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) ; +int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress, int* outbytes); + +#endif diff --git a/plugins/zerogs/opengl/common.h b/plugins/zerogs/opengl/common.h index 280d62a70c..698c45c5b9 100644 --- a/plugins/zerogs/opengl/common.h +++ b/plugins/zerogs/opengl/common.h @@ -1,1142 +1,1142 @@ -/** - * @file common.h - * common internal api header. - */ - -#ifndef COMMON_H -#define COMMON_H - -#if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) -# define CONFIG_WIN32 -#endif - -//#define ALT_BITSTREAM_WRITER -//#define ALIGNED_BITSTREAM_WRITER - -#define ALT_BITSTREAM_READER -//#define LIBMPEG2_BITSTREAM_READER -//#define A32_BITSTREAM_READER -#define LIBMPEG2_BITSTREAM_READER_HACK //add BERO - -#ifdef HAVE_AV_CONFIG_H -/* only include the following when compiling package */ -# include "config.h" - -# include -# include -# include -# include -# ifndef __BEOS__ -# include -# else -# include "berrno.h" -# endif -# include - -# ifndef ENODATA -# define ENODATA 61 -# endif - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#include -#ifndef offsetof -# define offsetof(T,F) ((unsigned int)((char *)&((T *)0)->F)) -#endif - -#define AVOPTION_CODEC_BOOL(name, help, field) \ - { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_BOOL } -#define AVOPTION_CODEC_DOUBLE(name, help, field, minv, maxv, defval) \ - { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_DOUBLE, minv, maxv, defval } -#define AVOPTION_CODEC_FLAG(name, help, field, flag, defval) \ - { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_FLAG, flag, 0, defval } -#define AVOPTION_CODEC_INT(name, help, field, minv, maxv, defval) \ - { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_INT, minv, maxv, defval } -#define AVOPTION_CODEC_STRING(name, help, field, str, val) \ - { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_STRING, .defval = val, .defstr = str } -#define AVOPTION_CODEC_RCOVERRIDE(name, help, field) \ - { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_RCOVERRIDE, .defval = 0, .defstr = NULL } -#define AVOPTION_SUB(ptr) { .name = NULL, .help = (const char*)ptr } -#define AVOPTION_END() AVOPTION_SUB(NULL) - -struct AVOption; -#ifdef HAVE_MMX -extern const struct AVOption avoptions_common[3 + 5]; -#else -extern const struct AVOption avoptions_common[3]; -#endif -extern const struct AVOption avoptions_workaround_bug[11]; - -#endif /* HAVE_AV_CONFIG_H */ - -/* Suppress restrict if it was not defined in config.h. */ -#ifndef restrict -# define restrict -#endif - -#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0) -# define always_inline __attribute__((always_inline)) inline -#else -# define always_inline inline -#endif - -#ifdef CONFIG_WIN32 - -/* windows */ - -typedef unsigned short uint16_t; -typedef signed short int16_t; -typedef unsigned char uint8_t; -typedef unsigned int uint32_t; -typedef unsigned __int64 uint64_t; -typedef signed char int8_t; -typedef signed int int32_t; -typedef signed __int64 int64_t; - -# ifndef __MINGW32__ -# define int64_t_C(c) (c ## i64) -# define uint64_t_C(c) (c ## i64) - -# define inline __inline - -# else -# define int64_t_C(c) (c ## LL) -# define uint64_t_C(c) (c ## ULL) -# endif /* __MINGW32__ */ - -# ifdef _DEBUG -# define DEBUG -# endif - -# define snprintf _snprintf -# define vsnprintf _vsnprintf - -/* CONFIG_WIN32 end */ -#elif defined (CONFIG_OS2) -/* OS/2 EMX */ - -#include - -#ifndef int64_t_C -#define int64_t_C(c) (c ## LL) -#define uint64_t_C(c) (c ## ULL) -#endif - -#ifdef HAVE_AV_CONFIG_H - -#ifdef USE_FASTMEMCPY -#include "fastmemcpy.h" -#endif - -#include - -#endif /* HAVE_AV_CONFIG_H */ - -/* CONFIG_OS2 end */ -#else - -/* unix */ - -#include - -#ifndef int64_t_C -#define int64_t_C(c) (c ## LL) -#define uint64_t_C(c) (c ## ULL) -#endif - -#ifdef HAVE_AV_CONFIG_H - -# ifdef USE_FASTMEMCPY -# include "fastmemcpy.h" -# endif -# endif /* HAVE_AV_CONFIG_H */ - -#endif /* !CONFIG_WIN32 && !CONFIG_OS2 */ - -#ifdef HAVE_AV_CONFIG_H - -# include "bswap.h" - -# if defined(__MINGW32__) || defined(__CYGWIN__) || \ - defined(__OS2__) || (defined (__OpenBSD__) && !defined(__ELF__)) -# define MANGLE(a) "_" #a -# else -# define MANGLE(a) #a -# endif - -/* debug stuff */ - -# ifndef DEBUG -# define NDEBUG -# endif -# include - -/* dprintf macros */ -# if defined(CONFIG_WIN32) && !defined(__MINGW32__) - -inline void dprintf(const char* fmt,...) {} - -# else - -# ifdef DEBUG -# define dprintf(fmt,args...) printf(fmt, ## args) -# else -# define dprintf(fmt,args...) -# endif - -# endif /* !CONFIG_WIN32 */ - -# define av_abort() do { fprintf(stderr, "Abort at %s:%d\n", __FILE__, __LINE__); abort(); } while (0) - -//rounded divison & shift -#define RSHIFT(a,b) ((a) > 0 ? ((a) + (1<<((b)-1)))>>(b) : ((a) + (1<<((b)-1))-1)>>(b)) -/* assume b>0 */ -#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) -#define ABS(a) ((a) >= 0 ? (a) : (-(a))) - -#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) -#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) - -extern const uint32_t inverse[256]; - -#ifdef ARCH_X86 -# define FASTDIV(a,b) \ - ({\ - int ret,dmy;\ - asm volatile(\ - "mull %3"\ - :"=d"(ret),"=a"(dmy)\ - :"1"(a),"g"(inverse[b])\ - );\ - ret;\ - }) -#elif defined(CONFIG_FASTDIV) -# define FASTDIV(a,b) ((uint32_t)((((uint64_t)a)*inverse[b])>>32)) -#else -# define FASTDIV(a,b) ((a)/(b)) -#endif - -#ifdef ARCH_X86 -// avoid +32 for shift optimization (gcc should do that ...) -static inline int32_t NEG_SSR32( int32_t a, int8_t s){ - asm ("sarl %1, %0\n\t" - : "+r" (a) - : "ic" ((uint8_t)(-s)) - ); - return a; -} -static inline uint32_t NEG_USR32(uint32_t a, int8_t s){ - asm ("shrl %1, %0\n\t" - : "+r" (a) - : "ic" ((uint8_t)(-s)) - ); - return a; -} -#else -# define NEG_SSR32(a,s) ((( int32_t)(a))>>(32-(s))) -# define NEG_USR32(a,s) (((uint32_t)(a))>>(32-(s))) -#endif - -/* bit output */ - -struct PutBitContext; - -typedef void (*WriteDataFunc)(void *, uint8_t *, int); - -typedef struct PutBitContext { -#ifdef ALT_BITSTREAM_WRITER - uint8_t *buf, *buf_end; - int index; -#else - uint32_t bit_buf; - int bit_left; - uint8_t *buf, *buf_ptr, *buf_end; -#endif - int64_t data_out_size; /* in bytes */ -} PutBitContext; - -void init_put_bits(PutBitContext *s, - uint8_t *buffer, int buffer_size, - void *opaque, - void (*write_data)(void *, uint8_t *, int)); - -int64_t get_bit_count(PutBitContext *s); /* XXX: change function name */ -void align_put_bits(PutBitContext *s); -void flush_put_bits(PutBitContext *s); -void put_string(PutBitContext * pbc, char *s); - -/* bit input */ - -typedef struct GetBitContext { - const uint8_t *buffer, *buffer_end; -#ifdef ALT_BITSTREAM_READER - int index; -#elif defined LIBMPEG2_BITSTREAM_READER - uint8_t *buffer_ptr; - uint32_t cache; - int bit_count; -#elif defined A32_BITSTREAM_READER - uint32_t *buffer_ptr; - uint32_t cache0; - uint32_t cache1; - int bit_count; -#endif - int size_in_bits; -} GetBitContext; - -static inline int get_bits_count(GetBitContext *s); - -#define VLC_TYPE int16_t - -typedef struct VLC { - int bits; - VLC_TYPE (*table)[2]; ///< code, bits - int table_size, table_allocated; -} VLC; - -typedef struct RL_VLC_ELEM { - int16_t level; - int8_t len; - uint8_t run; -} RL_VLC_ELEM; - -#ifdef ARCH_SPARC64 -#define UNALIGNED_STORES_ARE_BAD -#endif - -/* used to avoid missaligned exceptions on some archs (alpha, ...) */ -#ifdef ARCH_X86 -# define unaligned32(a) (*(uint32_t*)(a)) -#else -# ifdef __GNUC__ -static inline uint32_t unaligned32(const void *v) { - struct Unaligned { - uint32_t i; - } __attribute__((packed)); - - return ((const struct Unaligned *) v)->i; -} -# elif defined(__DECC) -static inline uint32_t unaligned32(const void *v) { - return *(const __unaligned uint32_t *) v; -} -# else -static inline uint32_t unaligned32(const void *v) { - return *(const uint32_t *) v; -} -# endif -#endif //!ARCH_X86 - -#ifndef ALT_BITSTREAM_WRITER -static inline void put_bits(PutBitContext *s, int n, unsigned int value) -{ - unsigned int bit_buf; - int bit_left; - -#ifdef STATS - st_out_bit_counts[st_current_index] += n; -#endif - // DEBUG_LOG("put_bits=%d %x\n", n, value); - assert(n == 32 || value < (1U << n)); - - bit_buf = s->bit_buf; - bit_left = s->bit_left; - - // DEBUG_LOG("n=%d value=%x cnt=%d buf=%x\n", n, value, bit_cnt, bit_buf); - /* XXX: optimize */ - if (n < bit_left) { - bit_buf = (bit_buf<> (n - bit_left); -#ifdef UNALIGNED_STORES_ARE_BAD - if (3 & (int) s->buf_ptr) { - s->buf_ptr[0] = bit_buf >> 24; - s->buf_ptr[1] = bit_buf >> 16; - s->buf_ptr[2] = bit_buf >> 8; - s->buf_ptr[3] = bit_buf ; - } else -#endif - *(uint32_t *)s->buf_ptr = be2me_32(bit_buf); - //DEBUG_LOG("bitbuf = %08x\n", bit_buf); - s->buf_ptr+=4; - bit_left+=32 - n; - bit_buf = value; - } - - s->bit_buf = bit_buf; - s->bit_left = bit_left; -} -#endif - - -#ifdef ALT_BITSTREAM_WRITER -static inline void put_bits(PutBitContext *s, int n, unsigned int value) -{ -# ifdef ALIGNED_BITSTREAM_WRITER -# ifdef ARCH_X86 - asm volatile( - "movl %0, %%ecx \n\t" - "xorl %%eax, %%eax \n\t" - "shrdl %%cl, %1, %%eax \n\t" - "shrl %%cl, %1 \n\t" - "movl %0, %%ecx \n\t" - "shrl $3, %%ecx \n\t" - "andl $0xFFFFFFFC, %%ecx \n\t" - "bswapl %1 \n\t" - "orl %1, (%2, %%ecx) \n\t" - "bswapl %%eax \n\t" - "addl %3, %0 \n\t" - "movl %%eax, 4(%2, %%ecx) \n\t" - : "=&r" (s->index), "=&r" (value) - : "r" (s->buf), "r" (n), "0" (s->index), "1" (value<<(-n)) - : "%eax", "%ecx" - ); -# else - int index= s->index; - uint32_t *ptr= ((uint32_t *)s->buf)+(index>>5); - - value<<= 32-n; - - ptr[0] |= be2me_32(value>>(index&31)); - ptr[1] = be2me_32(value<<(32-(index&31))); -//if(n>24) DEBUG_LOG("%d %d\n", n, value); - index+= n; - s->index= index; -# endif -# else //ALIGNED_BITSTREAM_WRITER -# ifdef ARCH_X86 - asm volatile( - "movl $7, %%ecx \n\t" - "andl %0, %%ecx \n\t" - "addl %3, %%ecx \n\t" - "negl %%ecx \n\t" - "shll %%cl, %1 \n\t" - "bswapl %1 \n\t" - "movl %0, %%ecx \n\t" - "shrl $3, %%ecx \n\t" - "orl %1, (%%ecx, %2) \n\t" - "addl %3, %0 \n\t" - "movl $0, 4(%%ecx, %2) \n\t" - : "=&r" (s->index), "=&r" (value) - : "r" (s->buf), "r" (n), "0" (s->index), "1" (value) - : "%ecx" - ); -# else - int index= s->index; - uint32_t *ptr= (uint32_t*)(((uint8_t *)s->buf)+(index>>3)); - - ptr[0] |= be2me_32(value<<(32-n-(index&7) )); - ptr[1] = 0; -//if(n>24) DEBUG_LOG("%d %d\n", n, value); - index+= n; - s->index= index; -# endif -# endif //!ALIGNED_BITSTREAM_WRITER -} -#endif - - -static inline uint8_t* pbBufPtr(PutBitContext *s) -{ -#ifdef ALT_BITSTREAM_WRITER - return s->buf + (s->index>>3); -#else - return s->buf_ptr; -#endif -} - -/* Bitstream reader API docs: -name - abritary name which is used as prefix for the internal variables - -gb - getbitcontext - -OPEN_READER(name, gb) - loads gb into local variables - -CLOSE_READER(name, gb) - stores local vars in gb - -UPDATE_CACHE(name, gb) - refills the internal cache from the bitstream - after this call at least MIN_CACHE_BITS will be available, - -GET_CACHE(name, gb) - will output the contents of the internal cache, next bit is MSB of 32 or 64 bit (FIXME 64bit) - -SHOW_UBITS(name, gb, num) - will return the nest num bits - -SHOW_SBITS(name, gb, num) - will return the nest num bits and do sign extension - -SKIP_BITS(name, gb, num) - will skip over the next num bits - note, this is equinvalent to SKIP_CACHE; SKIP_COUNTER - -SKIP_CACHE(name, gb, num) - will remove the next num bits from the cache (note SKIP_COUNTER MUST be called before UPDATE_CACHE / CLOSE_READER) - -SKIP_COUNTER(name, gb, num) - will increment the internal bit counter (see SKIP_CACHE & SKIP_BITS) - -LAST_SKIP_CACHE(name, gb, num) - will remove the next num bits from the cache if it is needed for UPDATE_CACHE otherwise it will do nothing - -LAST_SKIP_BITS(name, gb, num) - is equinvalent to SKIP_LAST_CACHE; SKIP_COUNTER - -for examples see get_bits, show_bits, skip_bits, get_vlc -*/ - -static inline int unaligned32_be(const void *v) -{ -#ifdef CONFIG_ALIGN - const uint8_t *p=v; - return (((p[0]<<8) | p[1])<<16) | (p[2]<<8) | (p[3]); -#else - return be2me_32( unaligned32(v)); //original -#endif -} - -#ifdef ALT_BITSTREAM_READER -# define MIN_CACHE_BITS 25 - -# define OPEN_READER(name, gb)\ - int name##_index= (gb)->index;\ - int name##_cache= 0;\ - -# define CLOSE_READER(name, gb)\ - (gb)->index= name##_index;\ - -# define UPDATE_CACHE(name, gb)\ - name##_cache= unaligned32_be( ((uint8_t *)(gb)->buffer)+(name##_index>>3) ) << (name##_index&0x07);\ - -# define SKIP_CACHE(name, gb, num)\ - name##_cache <<= (num);\ - -// FIXME name? -# define SKIP_COUNTER(name, gb, num)\ - name##_index += (num);\ - -# define SKIP_BITS(name, gb, num)\ - {\ - SKIP_CACHE(name, gb, num)\ - SKIP_COUNTER(name, gb, num)\ - }\ - -# define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num) -# define LAST_SKIP_CACHE(name, gb, num) ; - -# define SHOW_UBITS(name, gb, num)\ - NEG_USR32(name##_cache, num) - -# define SHOW_SBITS(name, gb, num)\ - NEG_SSR32(name##_cache, num) - -# define GET_CACHE(name, gb)\ - ((uint32_t)name##_cache) - -static inline int get_bits_count(GetBitContext *s){ - return s->index; -} -#elif defined LIBMPEG2_BITSTREAM_READER -//libmpeg2 like reader - -# define MIN_CACHE_BITS 17 - -# define OPEN_READER(name, gb)\ - int name##_bit_count=(gb)->bit_count;\ - int name##_cache= (gb)->cache;\ - uint8_t * name##_buffer_ptr=(gb)->buffer_ptr;\ - -# define CLOSE_READER(name, gb)\ - (gb)->bit_count= name##_bit_count;\ - (gb)->cache= name##_cache;\ - (gb)->buffer_ptr= name##_buffer_ptr;\ - -#ifdef LIBMPEG2_BITSTREAM_READER_HACK - -# define UPDATE_CACHE(name, gb)\ - if(name##_bit_count >= 0){\ - name##_cache+= (int)be2me_16(*(uint16_t*)name##_buffer_ptr) << name##_bit_count;\ - ((uint16_t*)name##_buffer_ptr)++;\ - name##_bit_count-= 16;\ - }\ - -#else - -# define UPDATE_CACHE(name, gb)\ - if(name##_bit_count >= 0){\ - name##_cache+= ((name##_buffer_ptr[0]<<8) + name##_buffer_ptr[1]) << name##_bit_count;\ - name##_buffer_ptr+=2;\ - name##_bit_count-= 16;\ - }\ - -#endif - -# define SKIP_CACHE(name, gb, num)\ - name##_cache <<= (num);\ - -# define SKIP_COUNTER(name, gb, num)\ - name##_bit_count += (num);\ - -# define SKIP_BITS(name, gb, num)\ - {\ - SKIP_CACHE(name, gb, num)\ - SKIP_COUNTER(name, gb, num)\ - }\ - -# define LAST_SKIP_BITS(name, gb, num) SKIP_BITS(name, gb, num) -# define LAST_SKIP_CACHE(name, gb, num) SKIP_CACHE(name, gb, num) - -# define SHOW_UBITS(name, gb, num)\ - NEG_USR32(name##_cache, num) - -# define SHOW_SBITS(name, gb, num)\ - NEG_SSR32(name##_cache, num) - -# define GET_CACHE(name, gb)\ - ((uint32_t)name##_cache) - -static inline int get_bits_count(GetBitContext *s){ - return (s->buffer_ptr - s->buffer)*8 - 16 + s->bit_count; -} - -#elif defined A32_BITSTREAM_READER - -# define MIN_CACHE_BITS 32 - -# define OPEN_READER(name, gb)\ - int name##_bit_count=(gb)->bit_count;\ - uint32_t name##_cache0= (gb)->cache0;\ - uint32_t name##_cache1= (gb)->cache1;\ - uint32_t * name##_buffer_ptr=(gb)->buffer_ptr;\ - -# define CLOSE_READER(name, gb)\ - (gb)->bit_count= name##_bit_count;\ - (gb)->cache0= name##_cache0;\ - (gb)->cache1= name##_cache1;\ - (gb)->buffer_ptr= name##_buffer_ptr;\ - -# define UPDATE_CACHE(name, gb)\ - if(name##_bit_count > 0){\ - const uint32_t next= be2me_32( *name##_buffer_ptr );\ - name##_cache0 |= NEG_USR32(next,name##_bit_count);\ - name##_cache1 |= next<buffer_ptr - s->buffer)*8 - 32 + s->bit_count; -} - -#endif - -/** - * read mpeg1 dc style vlc (sign bit + mantisse with no MSB). - * if MSB not set it is negative - * @param n length in bits - * @author BERO - */ -static inline int get_xbits(GetBitContext *s, int n){ - register int tmp; - register int32_t cache; - OPEN_READER(re, s) - UPDATE_CACHE(re, s) - cache = GET_CACHE(re,s); - if ((int32_t)cache<0) { //MSB=1 - tmp = NEG_USR32(cache,n); - } else { - // tmp = (-1<index+=n for the ALT_READER :)) - OPEN_READER(re, s) - UPDATE_CACHE(re, s) - LAST_SKIP_BITS(re, s, n) - CLOSE_READER(re, s) -} - -static inline unsigned int get_bits1(GetBitContext *s){ -#ifdef ALT_BITSTREAM_READER - int index= s->index; - uint8_t result= s->buffer[ index>>3 ]; - result<<= (index&0x07); - result>>= 8 - 1; - index++; - s->index= index; - - return result; -#else - return get_bits(s, 1); -#endif -} - -static inline unsigned int show_bits1(GetBitContext *s){ - return show_bits(s, 1); -} - -static inline void skip_bits1(GetBitContext *s){ - skip_bits(s, 1); -} - -void init_get_bits(GetBitContext *s, - const uint8_t *buffer, int buffer_size); - -int check_marker(GetBitContext *s, const char *msg); -void align_get_bits(GetBitContext *s); -int init_vlc(VLC *vlc, int nb_bits, int nb_codes, - const void *bits, int bits_wrap, int bits_size, - const void *codes, int codes_wrap, int codes_size); -void free_vlc(VLC *vlc); - -/** - * - * if the vlc code is invalid and max_depth=1 than no bits will be removed - * if the vlc code is invalid and max_depth>1 than the number of bits removed - * is undefined - */ -#define GET_VLC(code, name, gb, table, bits, max_depth)\ -{\ - int n, index, nb_bits;\ -\ - index= SHOW_UBITS(name, gb, bits);\ - code = table[index][0];\ - n = table[index][1];\ -\ - if(max_depth > 1 && n < 0){\ - LAST_SKIP_BITS(name, gb, bits)\ - UPDATE_CACHE(name, gb)\ -\ - nb_bits = -n;\ -\ - index= SHOW_UBITS(name, gb, nb_bits) + code;\ - code = table[index][0];\ - n = table[index][1];\ - if(max_depth > 2 && n < 0){\ - LAST_SKIP_BITS(name, gb, nb_bits)\ - UPDATE_CACHE(name, gb)\ -\ - nb_bits = -n;\ -\ - index= SHOW_UBITS(name, gb, nb_bits) + code;\ - code = table[index][0];\ - n = table[index][1];\ - }\ - }\ - SKIP_BITS(name, gb, n)\ -} - -#define GET_RL_VLC(level, run, name, gb, table, bits, max_depth)\ -{\ - int n, index, nb_bits;\ -\ - index= SHOW_UBITS(name, gb, bits);\ - level = table[index].level;\ - n = table[index].len;\ -\ - if(max_depth > 1 && n < 0){\ - LAST_SKIP_BITS(name, gb, bits)\ - UPDATE_CACHE(name, gb)\ -\ - nb_bits = -n;\ -\ - index= SHOW_UBITS(name, gb, nb_bits) + level;\ - level = table[index].level;\ - n = table[index].len;\ - }\ - run= table[index].run;\ - SKIP_BITS(name, gb, n)\ -} - -// deprecated, dont use get_vlc for new code, use get_vlc2 instead or use GET_VLC directly -static inline int get_vlc(GetBitContext *s, VLC *vlc) -{ - int code; - VLC_TYPE (*table)[2]= vlc->table; - - OPEN_READER(re, s) - UPDATE_CACHE(re, s) - - GET_VLC(code, re, s, table, vlc->bits, 3) - - CLOSE_READER(re, s) - return code; -} - -/** - * parses a vlc code, faster then get_vlc() - * @param bits is the number of bits which will be read at once, must be - * identical to nb_bits in init_vlc() - * @param max_depth is the number of times bits bits must be readed to completly - * read the longest vlc code - * = (max_vlc_length + bits - 1) / bits - */ -static always_inline int get_vlc2(GetBitContext *s, VLC_TYPE (*table)[2], - int bits, int max_depth) -{ - int code; - - OPEN_READER(re, s) - UPDATE_CACHE(re, s) - - GET_VLC(code, re, s, table, bits, max_depth) - - CLOSE_READER(re, s) - return code; -} - -//#define TRACE - -#ifdef TRACE - -static inline void print_bin(int bits, int n){ - int i; - - for(i=n-1; i>=0; i--){ - DEBUG_LOG("%d", (bits>>i)&1); - } - for(i=n; i<24; i++) - DEBUG_LOG(" "); -} - -static inline int get_bits_trace(GetBitContext *s, int n, char *file, char *func, int line){ - int r= get_bits(s, n); - - print_bin(r, n); - DEBUG_LOG("%5d %2d %3d bit @%5d in %s %s:%d\n", r, n, r, get_bits_count(s)-n, file, func, line); - return r; -} -static inline int get_vlc_trace(GetBitContext *s, VLC_TYPE (*table)[2], int bits, int max_depth, char *file, char *func, int line){ - int show= show_bits(s, 24); - int pos= get_bits_count(s); - int r= get_vlc2(s, table, bits, max_depth); - int len= get_bits_count(s) - pos; - int bits2= show>>(24-len); - - print_bin(bits2, len); - - DEBUG_LOG("%5d %2d %3d vlc @%5d in %s %s:%d\n", bits2, len, r, pos, file, func, line); - return r; -} -static inline int get_xbits_trace(GetBitContext *s, int n, char *file, char *func, int line){ - int show= show_bits(s, n); - int r= get_xbits(s, n); - - print_bin(show, n); - DEBUG_LOG("%5d %2d %3d xbt @%5d in %s %s:%d\n", show, n, r, get_bits_count(s)-n, file, func, line); - return r; -} - -#define get_bits(s, n) get_bits_trace(s, n, __FILE__, __PRETTY_FUNCTION__, __LINE__) -#define get_bits1(s) get_bits_trace(s, 1, __FILE__, __PRETTY_FUNCTION__, __LINE__) -#define get_xbits(s, n) get_xbits_trace(s, n, __FILE__, __PRETTY_FUNCTION__, __LINE__) -#define get_vlc(s, vlc) get_vlc_trace(s, (vlc)->table, (vlc)->bits, 3, __FILE__, __PRETTY_FUNCTION__, __LINE__) -#define get_vlc2(s, tab, bits, max) get_vlc_trace(s, tab, bits, max, __FILE__, __PRETTY_FUNCTION__, __LINE__) - -#define tprintf printf - -#else //TRACE -#define tprintf(_arg...) {} -#endif - -/* define it to include statistics code (useful only for optimizing - codec efficiency */ -//#define STATS - -#ifdef STATS - -enum { - ST_UNKNOWN, - ST_DC, - ST_INTRA_AC, - ST_INTER_AC, - ST_INTRA_MB, - ST_INTER_MB, - ST_MV, - ST_NB, -}; - -extern int st_current_index; -extern unsigned int st_bit_counts[ST_NB]; -extern unsigned int st_out_bit_counts[ST_NB]; - -void print_stats(void); -#endif - -/* misc math functions */ -extern const uint8_t ff_log2_tab[256]; - -static inline int av_log2(unsigned int v) -{ - int n; - - n = 0; - if (v & 0xffff0000) { - v >>= 16; - n += 16; - } - if (v & 0xff00) { - v >>= 8; - n += 8; - } - n += ff_log2_tab[v]; - - return n; -} - -static inline int av_log2_16bit(unsigned int v) -{ - int n; - - n = 0; - if (v & 0xff00) { - v >>= 8; - n += 8; - } - n += ff_log2_tab[v]; - - return n; -} - - -/* median of 3 */ -static inline int mid_pred(int a, int b, int c) -{ - int vmin, vmax; - vmax = vmin = a; - if (b < vmin) - vmin = b; - else - vmax = b; - - if (c < vmin) - vmin = c; - else if (c > vmax) - vmax = c; - - return a + b + c - vmin - vmax; -} - -static inline int clip(int a, int amin, int amax) -{ - if (a < amin) - return amin; - else if (a > amax) - return amax; - else - return a; -} - -/* math */ -extern const uint8_t ff_sqrt_tab[128]; - -int64_t ff_gcd(int64_t a, int64_t b); - -static inline int ff_sqrt(int a) -{ - int ret=0; - int s; - int ret_sq=0; - - if(a<128) return ff_sqrt_tab[a]; - - for(s=15; s>=0; s--){ - int b= ret_sq + (1<<(s*2)) + (ret<>31;\ - level= (level^mask)-mask; -#endif - - -#if __CPU__ >= 686 && !defined(RUNTIME_CPUDETECT) -#define COPY3_IF_LT(x,y,a,b,c,d)\ -asm volatile (\ - "cmpl %0, %3 \n\t"\ - "cmovl %3, %0 \n\t"\ - "cmovl %4, %1 \n\t"\ - "cmovl %5, %2 \n\t"\ - : "+r" (x), "+r" (a), "+r" (c)\ - : "r" (y), "r" (b), "r" (d)\ -); -#else -#define COPY3_IF_LT(x,y,a,b,c,d)\ -if((y)<(x)){\ - (x)=(y);\ - (a)=(b);\ - (c)=(d);\ -} -#endif - -#ifdef ARCH_X86 -static inline long long rdtsc() -{ - long long l; - asm volatile( "rdtsc\n\t" - : "=A" (l) - ); - return l; -} - -#define START_TIMER \ -static uint64_t tsum=0;\ -static int tcount=0;\ -static int tskip_count=0;\ -uint64_t tend;\ -uint64_t tstart= rdtsc();\ - -#define STOP_TIMER(id) \ -tend= rdtsc();\ -if(tcount<2 || tend - tstart < 4*tsum/tcount){\ - tsum+= tend - tstart;\ - tcount++;\ -}else\ - tskip_count++;\ -if(256*256*256*64%(tcount+tskip_count)==0){\ - fprintf(stderr, "%Ld dezicycles in %s, %d runs, %d skips\n", tsum*10/tcount, id, tcount, tskip_count);\ -} -#endif - -#define CLAMP_TO_8BIT(d) ((d > 0xff) ? 0xff : (d < 0) ? 0 : d) - -/* avoid usage of various functions */ -#define malloc please_use_av_malloc -#define free please_use_av_free -#define realloc please_use_av_realloc - -#define CHECKED_ALLOCZ(p, size)\ -{\ - p= av_mallocz(size);\ - if(p==NULL && (size)!=0){\ - perror("malloc");\ - goto fail;\ - }\ -} - -#endif /* HAVE_AV_CONFIG_H */ - -#endif /* COMMON_H */ +/** + * @file common.h + * common internal api header. + */ + +#ifndef COMMON_H +#define COMMON_H + +#if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) +# define CONFIG_WIN32 +#endif + +//#define ALT_BITSTREAM_WRITER +//#define ALIGNED_BITSTREAM_WRITER + +#define ALT_BITSTREAM_READER +//#define LIBMPEG2_BITSTREAM_READER +//#define A32_BITSTREAM_READER +#define LIBMPEG2_BITSTREAM_READER_HACK //add BERO + +#ifdef HAVE_AV_CONFIG_H +/* only include the following when compiling package */ +# include "config.h" + +# include +# include +# include +# include +# ifndef __BEOS__ +# include +# else +# include "berrno.h" +# endif +# include + +# ifndef ENODATA +# define ENODATA 61 +# endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#include +#ifndef offsetof +# define offsetof(T,F) ((unsigned int)((char *)&((T *)0)->F)) +#endif + +#define AVOPTION_CODEC_BOOL(name, help, field) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_BOOL } +#define AVOPTION_CODEC_DOUBLE(name, help, field, minv, maxv, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_DOUBLE, minv, maxv, defval } +#define AVOPTION_CODEC_FLAG(name, help, field, flag, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_FLAG, flag, 0, defval } +#define AVOPTION_CODEC_INT(name, help, field, minv, maxv, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_INT, minv, maxv, defval } +#define AVOPTION_CODEC_STRING(name, help, field, str, val) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_STRING, .defval = val, .defstr = str } +#define AVOPTION_CODEC_RCOVERRIDE(name, help, field) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_RCOVERRIDE, .defval = 0, .defstr = NULL } +#define AVOPTION_SUB(ptr) { .name = NULL, .help = (const char*)ptr } +#define AVOPTION_END() AVOPTION_SUB(NULL) + +struct AVOption; +#ifdef HAVE_MMX +extern const struct AVOption avoptions_common[3 + 5]; +#else +extern const struct AVOption avoptions_common[3]; +#endif +extern const struct AVOption avoptions_workaround_bug[11]; + +#endif /* HAVE_AV_CONFIG_H */ + +/* Suppress restrict if it was not defined in config.h. */ +#ifndef restrict +# define restrict +#endif + +#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0) +# define always_inline __attribute__((always_inline)) inline +#else +# define always_inline inline +#endif + +#ifdef CONFIG_WIN32 + +/* windows */ + +typedef unsigned short uint16_t; +typedef signed short int16_t; +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; +typedef signed char int8_t; +typedef signed int int32_t; +typedef signed __int64 int64_t; + +# ifndef __MINGW32__ +# define int64_t_C(c) (c ## i64) +# define uint64_t_C(c) (c ## i64) + +# define inline __inline + +# else +# define int64_t_C(c) (c ## LL) +# define uint64_t_C(c) (c ## ULL) +# endif /* __MINGW32__ */ + +# ifdef _DEBUG +# define DEBUG +# endif + +# define snprintf _snprintf +# define vsnprintf _vsnprintf + +/* CONFIG_WIN32 end */ +#elif defined (CONFIG_OS2) +/* OS/2 EMX */ + +#include + +#ifndef int64_t_C +#define int64_t_C(c) (c ## LL) +#define uint64_t_C(c) (c ## ULL) +#endif + +#ifdef HAVE_AV_CONFIG_H + +#ifdef USE_FASTMEMCPY +#include "fastmemcpy.h" +#endif + +#include + +#endif /* HAVE_AV_CONFIG_H */ + +/* CONFIG_OS2 end */ +#else + +/* unix */ + +#include + +#ifndef int64_t_C +#define int64_t_C(c) (c ## LL) +#define uint64_t_C(c) (c ## ULL) +#endif + +#ifdef HAVE_AV_CONFIG_H + +# ifdef USE_FASTMEMCPY +# include "fastmemcpy.h" +# endif +# endif /* HAVE_AV_CONFIG_H */ + +#endif /* !CONFIG_WIN32 && !CONFIG_OS2 */ + +#ifdef HAVE_AV_CONFIG_H + +# include "bswap.h" + +# if defined(__MINGW32__) || defined(__CYGWIN__) || \ + defined(__OS2__) || (defined (__OpenBSD__) && !defined(__ELF__)) +# define MANGLE(a) "_" #a +# else +# define MANGLE(a) #a +# endif + +/* debug stuff */ + +# ifndef DEBUG +# define NDEBUG +# endif +# include + +/* dprintf macros */ +# if defined(CONFIG_WIN32) && !defined(__MINGW32__) + +inline void dprintf(const char* fmt,...) {} + +# else + +# ifdef DEBUG +# define dprintf(fmt,args...) printf(fmt, ## args) +# else +# define dprintf(fmt,args...) +# endif + +# endif /* !CONFIG_WIN32 */ + +# define av_abort() do { fprintf(stderr, "Abort at %s:%d\n", __FILE__, __LINE__); abort(); } while (0) + +//rounded divison & shift +#define RSHIFT(a,b) ((a) > 0 ? ((a) + (1<<((b)-1)))>>(b) : ((a) + (1<<((b)-1))-1)>>(b)) +/* assume b>0 */ +#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) +#define ABS(a) ((a) >= 0 ? (a) : (-(a))) + +#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) +#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) + +extern const uint32_t inverse[256]; + +#ifdef ARCH_X86 +# define FASTDIV(a,b) \ + ({\ + int ret,dmy;\ + asm volatile(\ + "mull %3"\ + :"=d"(ret),"=a"(dmy)\ + :"1"(a),"g"(inverse[b])\ + );\ + ret;\ + }) +#elif defined(CONFIG_FASTDIV) +# define FASTDIV(a,b) ((uint32_t)((((uint64_t)a)*inverse[b])>>32)) +#else +# define FASTDIV(a,b) ((a)/(b)) +#endif + +#ifdef ARCH_X86 +// avoid +32 for shift optimization (gcc should do that ...) +static inline int32_t NEG_SSR32( int32_t a, int8_t s){ + asm ("sarl %1, %0\n\t" + : "+r" (a) + : "ic" ((uint8_t)(-s)) + ); + return a; +} +static inline uint32_t NEG_USR32(uint32_t a, int8_t s){ + asm ("shrl %1, %0\n\t" + : "+r" (a) + : "ic" ((uint8_t)(-s)) + ); + return a; +} +#else +# define NEG_SSR32(a,s) ((( int32_t)(a))>>(32-(s))) +# define NEG_USR32(a,s) (((uint32_t)(a))>>(32-(s))) +#endif + +/* bit output */ + +struct PutBitContext; + +typedef void (*WriteDataFunc)(void *, uint8_t *, int); + +typedef struct PutBitContext { +#ifdef ALT_BITSTREAM_WRITER + uint8_t *buf, *buf_end; + int index; +#else + uint32_t bit_buf; + int bit_left; + uint8_t *buf, *buf_ptr, *buf_end; +#endif + int64_t data_out_size; /* in bytes */ +} PutBitContext; + +void init_put_bits(PutBitContext *s, + uint8_t *buffer, int buffer_size, + void *opaque, + void (*write_data)(void *, uint8_t *, int)); + +int64_t get_bit_count(PutBitContext *s); /* XXX: change function name */ +void align_put_bits(PutBitContext *s); +void flush_put_bits(PutBitContext *s); +void put_string(PutBitContext * pbc, char *s); + +/* bit input */ + +typedef struct GetBitContext { + const uint8_t *buffer, *buffer_end; +#ifdef ALT_BITSTREAM_READER + int index; +#elif defined LIBMPEG2_BITSTREAM_READER + uint8_t *buffer_ptr; + uint32_t cache; + int bit_count; +#elif defined A32_BITSTREAM_READER + uint32_t *buffer_ptr; + uint32_t cache0; + uint32_t cache1; + int bit_count; +#endif + int size_in_bits; +} GetBitContext; + +static inline int get_bits_count(GetBitContext *s); + +#define VLC_TYPE int16_t + +typedef struct VLC { + int bits; + VLC_TYPE (*table)[2]; ///< code, bits + int table_size, table_allocated; +} VLC; + +typedef struct RL_VLC_ELEM { + int16_t level; + int8_t len; + uint8_t run; +} RL_VLC_ELEM; + +#ifdef ARCH_SPARC64 +#define UNALIGNED_STORES_ARE_BAD +#endif + +/* used to avoid missaligned exceptions on some archs (alpha, ...) */ +#ifdef ARCH_X86 +# define unaligned32(a) (*(uint32_t*)(a)) +#else +# ifdef __GNUC__ +static inline uint32_t unaligned32(const void *v) { + struct Unaligned { + uint32_t i; + } __attribute__((packed)); + + return ((const struct Unaligned *) v)->i; +} +# elif defined(__DECC) +static inline uint32_t unaligned32(const void *v) { + return *(const __unaligned uint32_t *) v; +} +# else +static inline uint32_t unaligned32(const void *v) { + return *(const uint32_t *) v; +} +# endif +#endif //!ARCH_X86 + +#ifndef ALT_BITSTREAM_WRITER +static inline void put_bits(PutBitContext *s, int n, unsigned int value) +{ + unsigned int bit_buf; + int bit_left; + +#ifdef STATS + st_out_bit_counts[st_current_index] += n; +#endif + // DEBUG_LOG("put_bits=%d %x\n", n, value); + assert(n == 32 || value < (1U << n)); + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + + // DEBUG_LOG("n=%d value=%x cnt=%d buf=%x\n", n, value, bit_cnt, bit_buf); + /* XXX: optimize */ + if (n < bit_left) { + bit_buf = (bit_buf<> (n - bit_left); +#ifdef UNALIGNED_STORES_ARE_BAD + if (3 & (int) s->buf_ptr) { + s->buf_ptr[0] = bit_buf >> 24; + s->buf_ptr[1] = bit_buf >> 16; + s->buf_ptr[2] = bit_buf >> 8; + s->buf_ptr[3] = bit_buf ; + } else +#endif + *(uint32_t *)s->buf_ptr = be2me_32(bit_buf); + //DEBUG_LOG("bitbuf = %08x\n", bit_buf); + s->buf_ptr+=4; + bit_left+=32 - n; + bit_buf = value; + } + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} +#endif + + +#ifdef ALT_BITSTREAM_WRITER +static inline void put_bits(PutBitContext *s, int n, unsigned int value) +{ +# ifdef ALIGNED_BITSTREAM_WRITER +# ifdef ARCH_X86 + asm volatile( + "movl %0, %%ecx \n\t" + "xorl %%eax, %%eax \n\t" + "shrdl %%cl, %1, %%eax \n\t" + "shrl %%cl, %1 \n\t" + "movl %0, %%ecx \n\t" + "shrl $3, %%ecx \n\t" + "andl $0xFFFFFFFC, %%ecx \n\t" + "bswapl %1 \n\t" + "orl %1, (%2, %%ecx) \n\t" + "bswapl %%eax \n\t" + "addl %3, %0 \n\t" + "movl %%eax, 4(%2, %%ecx) \n\t" + : "=&r" (s->index), "=&r" (value) + : "r" (s->buf), "r" (n), "0" (s->index), "1" (value<<(-n)) + : "%eax", "%ecx" + ); +# else + int index= s->index; + uint32_t *ptr= ((uint32_t *)s->buf)+(index>>5); + + value<<= 32-n; + + ptr[0] |= be2me_32(value>>(index&31)); + ptr[1] = be2me_32(value<<(32-(index&31))); +//if(n>24) DEBUG_LOG("%d %d\n", n, value); + index+= n; + s->index= index; +# endif +# else //ALIGNED_BITSTREAM_WRITER +# ifdef ARCH_X86 + asm volatile( + "movl $7, %%ecx \n\t" + "andl %0, %%ecx \n\t" + "addl %3, %%ecx \n\t" + "negl %%ecx \n\t" + "shll %%cl, %1 \n\t" + "bswapl %1 \n\t" + "movl %0, %%ecx \n\t" + "shrl $3, %%ecx \n\t" + "orl %1, (%%ecx, %2) \n\t" + "addl %3, %0 \n\t" + "movl $0, 4(%%ecx, %2) \n\t" + : "=&r" (s->index), "=&r" (value) + : "r" (s->buf), "r" (n), "0" (s->index), "1" (value) + : "%ecx" + ); +# else + int index= s->index; + uint32_t *ptr= (uint32_t*)(((uint8_t *)s->buf)+(index>>3)); + + ptr[0] |= be2me_32(value<<(32-n-(index&7) )); + ptr[1] = 0; +//if(n>24) DEBUG_LOG("%d %d\n", n, value); + index+= n; + s->index= index; +# endif +# endif //!ALIGNED_BITSTREAM_WRITER +} +#endif + + +static inline uint8_t* pbBufPtr(PutBitContext *s) +{ +#ifdef ALT_BITSTREAM_WRITER + return s->buf + (s->index>>3); +#else + return s->buf_ptr; +#endif +} + +/* Bitstream reader API docs: +name + abritary name which is used as prefix for the internal variables + +gb + getbitcontext + +OPEN_READER(name, gb) + loads gb into local variables + +CLOSE_READER(name, gb) + stores local vars in gb + +UPDATE_CACHE(name, gb) + refills the internal cache from the bitstream + after this call at least MIN_CACHE_BITS will be available, + +GET_CACHE(name, gb) + will output the contents of the internal cache, next bit is MSB of 32 or 64 bit (FIXME 64bit) + +SHOW_UBITS(name, gb, num) + will return the nest num bits + +SHOW_SBITS(name, gb, num) + will return the nest num bits and do sign extension + +SKIP_BITS(name, gb, num) + will skip over the next num bits + note, this is equinvalent to SKIP_CACHE; SKIP_COUNTER + +SKIP_CACHE(name, gb, num) + will remove the next num bits from the cache (note SKIP_COUNTER MUST be called before UPDATE_CACHE / CLOSE_READER) + +SKIP_COUNTER(name, gb, num) + will increment the internal bit counter (see SKIP_CACHE & SKIP_BITS) + +LAST_SKIP_CACHE(name, gb, num) + will remove the next num bits from the cache if it is needed for UPDATE_CACHE otherwise it will do nothing + +LAST_SKIP_BITS(name, gb, num) + is equinvalent to SKIP_LAST_CACHE; SKIP_COUNTER + +for examples see get_bits, show_bits, skip_bits, get_vlc +*/ + +static inline int unaligned32_be(const void *v) +{ +#ifdef CONFIG_ALIGN + const uint8_t *p=v; + return (((p[0]<<8) | p[1])<<16) | (p[2]<<8) | (p[3]); +#else + return be2me_32( unaligned32(v)); //original +#endif +} + +#ifdef ALT_BITSTREAM_READER +# define MIN_CACHE_BITS 25 + +# define OPEN_READER(name, gb)\ + int name##_index= (gb)->index;\ + int name##_cache= 0;\ + +# define CLOSE_READER(name, gb)\ + (gb)->index= name##_index;\ + +# define UPDATE_CACHE(name, gb)\ + name##_cache= unaligned32_be( ((uint8_t *)(gb)->buffer)+(name##_index>>3) ) << (name##_index&0x07);\ + +# define SKIP_CACHE(name, gb, num)\ + name##_cache <<= (num);\ + +// FIXME name? +# define SKIP_COUNTER(name, gb, num)\ + name##_index += (num);\ + +# define SKIP_BITS(name, gb, num)\ + {\ + SKIP_CACHE(name, gb, num)\ + SKIP_COUNTER(name, gb, num)\ + }\ + +# define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num) +# define LAST_SKIP_CACHE(name, gb, num) ; + +# define SHOW_UBITS(name, gb, num)\ + NEG_USR32(name##_cache, num) + +# define SHOW_SBITS(name, gb, num)\ + NEG_SSR32(name##_cache, num) + +# define GET_CACHE(name, gb)\ + ((uint32_t)name##_cache) + +static inline int get_bits_count(GetBitContext *s){ + return s->index; +} +#elif defined LIBMPEG2_BITSTREAM_READER +//libmpeg2 like reader + +# define MIN_CACHE_BITS 17 + +# define OPEN_READER(name, gb)\ + int name##_bit_count=(gb)->bit_count;\ + int name##_cache= (gb)->cache;\ + uint8_t * name##_buffer_ptr=(gb)->buffer_ptr;\ + +# define CLOSE_READER(name, gb)\ + (gb)->bit_count= name##_bit_count;\ + (gb)->cache= name##_cache;\ + (gb)->buffer_ptr= name##_buffer_ptr;\ + +#ifdef LIBMPEG2_BITSTREAM_READER_HACK + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count >= 0){\ + name##_cache+= (int)be2me_16(*(uint16_t*)name##_buffer_ptr) << name##_bit_count;\ + ((uint16_t*)name##_buffer_ptr)++;\ + name##_bit_count-= 16;\ + }\ + +#else + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count >= 0){\ + name##_cache+= ((name##_buffer_ptr[0]<<8) + name##_buffer_ptr[1]) << name##_bit_count;\ + name##_buffer_ptr+=2;\ + name##_bit_count-= 16;\ + }\ + +#endif + +# define SKIP_CACHE(name, gb, num)\ + name##_cache <<= (num);\ + +# define SKIP_COUNTER(name, gb, num)\ + name##_bit_count += (num);\ + +# define SKIP_BITS(name, gb, num)\ + {\ + SKIP_CACHE(name, gb, num)\ + SKIP_COUNTER(name, gb, num)\ + }\ + +# define LAST_SKIP_BITS(name, gb, num) SKIP_BITS(name, gb, num) +# define LAST_SKIP_CACHE(name, gb, num) SKIP_CACHE(name, gb, num) + +# define SHOW_UBITS(name, gb, num)\ + NEG_USR32(name##_cache, num) + +# define SHOW_SBITS(name, gb, num)\ + NEG_SSR32(name##_cache, num) + +# define GET_CACHE(name, gb)\ + ((uint32_t)name##_cache) + +static inline int get_bits_count(GetBitContext *s){ + return (s->buffer_ptr - s->buffer)*8 - 16 + s->bit_count; +} + +#elif defined A32_BITSTREAM_READER + +# define MIN_CACHE_BITS 32 + +# define OPEN_READER(name, gb)\ + int name##_bit_count=(gb)->bit_count;\ + uint32_t name##_cache0= (gb)->cache0;\ + uint32_t name##_cache1= (gb)->cache1;\ + uint32_t * name##_buffer_ptr=(gb)->buffer_ptr;\ + +# define CLOSE_READER(name, gb)\ + (gb)->bit_count= name##_bit_count;\ + (gb)->cache0= name##_cache0;\ + (gb)->cache1= name##_cache1;\ + (gb)->buffer_ptr= name##_buffer_ptr;\ + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count > 0){\ + const uint32_t next= be2me_32( *name##_buffer_ptr );\ + name##_cache0 |= NEG_USR32(next,name##_bit_count);\ + name##_cache1 |= next<buffer_ptr - s->buffer)*8 - 32 + s->bit_count; +} + +#endif + +/** + * read mpeg1 dc style vlc (sign bit + mantisse with no MSB). + * if MSB not set it is negative + * @param n length in bits + * @author BERO + */ +static inline int get_xbits(GetBitContext *s, int n){ + register int tmp; + register int32_t cache; + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + cache = GET_CACHE(re,s); + if ((int32_t)cache<0) { //MSB=1 + tmp = NEG_USR32(cache,n); + } else { + // tmp = (-1<index+=n for the ALT_READER :)) + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + LAST_SKIP_BITS(re, s, n) + CLOSE_READER(re, s) +} + +static inline unsigned int get_bits1(GetBitContext *s){ +#ifdef ALT_BITSTREAM_READER + int index= s->index; + uint8_t result= s->buffer[ index>>3 ]; + result<<= (index&0x07); + result>>= 8 - 1; + index++; + s->index= index; + + return result; +#else + return get_bits(s, 1); +#endif +} + +static inline unsigned int show_bits1(GetBitContext *s){ + return show_bits(s, 1); +} + +static inline void skip_bits1(GetBitContext *s){ + skip_bits(s, 1); +} + +void init_get_bits(GetBitContext *s, + const uint8_t *buffer, int buffer_size); + +int check_marker(GetBitContext *s, const char *msg); +void align_get_bits(GetBitContext *s); +int init_vlc(VLC *vlc, int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size); +void free_vlc(VLC *vlc); + +/** + * + * if the vlc code is invalid and max_depth=1 than no bits will be removed + * if the vlc code is invalid and max_depth>1 than the number of bits removed + * is undefined + */ +#define GET_VLC(code, name, gb, table, bits, max_depth)\ +{\ + int n, index, nb_bits;\ +\ + index= SHOW_UBITS(name, gb, bits);\ + code = table[index][0];\ + n = table[index][1];\ +\ + if(max_depth > 1 && n < 0){\ + LAST_SKIP_BITS(name, gb, bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + code;\ + code = table[index][0];\ + n = table[index][1];\ + if(max_depth > 2 && n < 0){\ + LAST_SKIP_BITS(name, gb, nb_bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + code;\ + code = table[index][0];\ + n = table[index][1];\ + }\ + }\ + SKIP_BITS(name, gb, n)\ +} + +#define GET_RL_VLC(level, run, name, gb, table, bits, max_depth)\ +{\ + int n, index, nb_bits;\ +\ + index= SHOW_UBITS(name, gb, bits);\ + level = table[index].level;\ + n = table[index].len;\ +\ + if(max_depth > 1 && n < 0){\ + LAST_SKIP_BITS(name, gb, bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + level;\ + level = table[index].level;\ + n = table[index].len;\ + }\ + run= table[index].run;\ + SKIP_BITS(name, gb, n)\ +} + +// deprecated, dont use get_vlc for new code, use get_vlc2 instead or use GET_VLC directly +static inline int get_vlc(GetBitContext *s, VLC *vlc) +{ + int code; + VLC_TYPE (*table)[2]= vlc->table; + + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + + GET_VLC(code, re, s, table, vlc->bits, 3) + + CLOSE_READER(re, s) + return code; +} + +/** + * parses a vlc code, faster then get_vlc() + * @param bits is the number of bits which will be read at once, must be + * identical to nb_bits in init_vlc() + * @param max_depth is the number of times bits bits must be readed to completly + * read the longest vlc code + * = (max_vlc_length + bits - 1) / bits + */ +static always_inline int get_vlc2(GetBitContext *s, VLC_TYPE (*table)[2], + int bits, int max_depth) +{ + int code; + + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + + GET_VLC(code, re, s, table, bits, max_depth) + + CLOSE_READER(re, s) + return code; +} + +//#define TRACE + +#ifdef TRACE + +static inline void print_bin(int bits, int n){ + int i; + + for(i=n-1; i>=0; i--){ + DEBUG_LOG("%d", (bits>>i)&1); + } + for(i=n; i<24; i++) + DEBUG_LOG(" "); +} + +static inline int get_bits_trace(GetBitContext *s, int n, char *file, char *func, int line){ + int r= get_bits(s, n); + + print_bin(r, n); + DEBUG_LOG("%5d %2d %3d bit @%5d in %s %s:%d\n", r, n, r, get_bits_count(s)-n, file, func, line); + return r; +} +static inline int get_vlc_trace(GetBitContext *s, VLC_TYPE (*table)[2], int bits, int max_depth, char *file, char *func, int line){ + int show= show_bits(s, 24); + int pos= get_bits_count(s); + int r= get_vlc2(s, table, bits, max_depth); + int len= get_bits_count(s) - pos; + int bits2= show>>(24-len); + + print_bin(bits2, len); + + DEBUG_LOG("%5d %2d %3d vlc @%5d in %s %s:%d\n", bits2, len, r, pos, file, func, line); + return r; +} +static inline int get_xbits_trace(GetBitContext *s, int n, char *file, char *func, int line){ + int show= show_bits(s, n); + int r= get_xbits(s, n); + + print_bin(show, n); + DEBUG_LOG("%5d %2d %3d xbt @%5d in %s %s:%d\n", show, n, r, get_bits_count(s)-n, file, func, line); + return r; +} + +#define get_bits(s, n) get_bits_trace(s, n, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_bits1(s) get_bits_trace(s, 1, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_xbits(s, n) get_xbits_trace(s, n, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_vlc(s, vlc) get_vlc_trace(s, (vlc)->table, (vlc)->bits, 3, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_vlc2(s, tab, bits, max) get_vlc_trace(s, tab, bits, max, __FILE__, __PRETTY_FUNCTION__, __LINE__) + +#define tprintf printf + +#else //TRACE +#define tprintf(_arg...) {} +#endif + +/* define it to include statistics code (useful only for optimizing + codec efficiency */ +//#define STATS + +#ifdef STATS + +enum { + ST_UNKNOWN, + ST_DC, + ST_INTRA_AC, + ST_INTER_AC, + ST_INTRA_MB, + ST_INTER_MB, + ST_MV, + ST_NB, +}; + +extern int st_current_index; +extern unsigned int st_bit_counts[ST_NB]; +extern unsigned int st_out_bit_counts[ST_NB]; + +void print_stats(void); +#endif + +/* misc math functions */ +extern const uint8_t ff_log2_tab[256]; + +static inline int av_log2(unsigned int v) +{ + int n; + + n = 0; + if (v & 0xffff0000) { + v >>= 16; + n += 16; + } + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} + +static inline int av_log2_16bit(unsigned int v) +{ + int n; + + n = 0; + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} + + +/* median of 3 */ +static inline int mid_pred(int a, int b, int c) +{ + int vmin, vmax; + vmax = vmin = a; + if (b < vmin) + vmin = b; + else + vmax = b; + + if (c < vmin) + vmin = c; + else if (c > vmax) + vmax = c; + + return a + b + c - vmin - vmax; +} + +static inline int clip(int a, int amin, int amax) +{ + if (a < amin) + return amin; + else if (a > amax) + return amax; + else + return a; +} + +/* math */ +extern const uint8_t ff_sqrt_tab[128]; + +int64_t ff_gcd(int64_t a, int64_t b); + +static inline int ff_sqrt(int a) +{ + int ret=0; + int s; + int ret_sq=0; + + if(a<128) return ff_sqrt_tab[a]; + + for(s=15; s>=0; s--){ + int b= ret_sq + (1<<(s*2)) + (ret<>31;\ + level= (level^mask)-mask; +#endif + + +#if __CPU__ >= 686 && !defined(RUNTIME_CPUDETECT) +#define COPY3_IF_LT(x,y,a,b,c,d)\ +asm volatile (\ + "cmpl %0, %3 \n\t"\ + "cmovl %3, %0 \n\t"\ + "cmovl %4, %1 \n\t"\ + "cmovl %5, %2 \n\t"\ + : "+r" (x), "+r" (a), "+r" (c)\ + : "r" (y), "r" (b), "r" (d)\ +); +#else +#define COPY3_IF_LT(x,y,a,b,c,d)\ +if((y)<(x)){\ + (x)=(y);\ + (a)=(b);\ + (c)=(d);\ +} +#endif + +#ifdef ARCH_X86 +static inline long long rdtsc() +{ + long long l; + asm volatile( "rdtsc\n\t" + : "=A" (l) + ); + return l; +} + +#define START_TIMER \ +static uint64_t tsum=0;\ +static int tcount=0;\ +static int tskip_count=0;\ +uint64_t tend;\ +uint64_t tstart= rdtsc();\ + +#define STOP_TIMER(id) \ +tend= rdtsc();\ +if(tcount<2 || tend - tstart < 4*tsum/tcount){\ + tsum+= tend - tstart;\ + tcount++;\ +}else\ + tskip_count++;\ +if(256*256*256*64%(tcount+tskip_count)==0){\ + fprintf(stderr, "%Ld dezicycles in %s, %d runs, %d skips\n", tsum*10/tcount, id, tcount, tskip_count);\ +} +#endif + +#define CLAMP_TO_8BIT(d) ((d > 0xff) ? 0xff : (d < 0) ? 0 : d) + +/* avoid usage of various functions */ +#define malloc please_use_av_malloc +#define free please_use_av_free +#define realloc please_use_av_realloc + +#define CHECKED_ALLOCZ(p, size)\ +{\ + p= av_mallocz(size);\ + if(p==NULL && (size)!=0){\ + perror("malloc");\ + goto fail;\ + }\ +} + +#endif /* HAVE_AV_CONFIG_H */ + +#endif /* COMMON_H */ diff --git a/plugins/zerogs/opengl/common/PS2Edefs.h b/plugins/zerogs/opengl/common/PS2Edefs.h index 1f65fc02b9..49b16e16d5 100644 --- a/plugins/zerogs/opengl/common/PS2Edefs.h +++ b/plugins/zerogs/opengl/common/PS2Edefs.h @@ -1,885 +1,885 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef __PS2EDEFS_H__ -#define __PS2EDEFS_H__ - -/* - * PS2E Definitions v0.6.2 (beta) - * - * Author: linuzappz@hotmail.com - * shadowpcsx2@yahoo.gr - * florinsasu@hotmail.com - */ - -/* - Notes: - * Since this is still beta things may change. - - * OSflags: - __LINUX__ (linux OS) - _WIN32 (win32 OS) - - * common return values (for ie. GSinit): - 0 - success - -1 - error - - * reserved keys: - F1 to F10 are reserved for the emulator - - * plugins should NOT change the current - working directory. - (on win32, add flag OFN_NOCHANGEDIR for - GetOpenFileName) - -*/ - -#include "PS2Etypes.h" - - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ - defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ - defined(USBdefs) || defined(FWdefs) -#define COMMONdefs -#endif - -// PS2EgetLibType returns (may be OR'd) -#define PS2E_LT_GS 0x01 -#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- -#define PS2E_LT_SPU2 0x04 -#define PS2E_LT_CDVD 0x08 -#define PS2E_LT_DEV9 0x10 -#define PS2E_LT_USB 0x20 -#define PS2E_LT_FW 0x40 -#define PS2E_LT_SIO 0x80 - -// PS2EgetLibVersion2 (high 16 bits) -#define PS2E_GS_VERSION 0x0006 -#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- -#define PS2E_SPU2_VERSION 0x0005 -#define PS2E_CDVD_VERSION 0x0005 -#define PS2E_DEV9_VERSION 0x0003 -#define PS2E_USB_VERSION 0x0003 -#define PS2E_FW_VERSION 0x0002 -#define PS2E_SIO_VERSION 0x0001 -#ifdef COMMONdefs - -u32 CALLBACK PS2EgetLibType(void); -u32 CALLBACK PS2EgetLibVersion2(u32 type); -char* CALLBACK PS2EgetLibName(void); - -#endif - -// key values: -/* key values must be OS dependant: - win32: the VK_XXX will be used (WinUser) - linux: the XK_XXX will be used (XFree86) -*/ - -// event values: -#define KEYPRESS 1 -#define KEYRELEASE 2 - -typedef struct _keyEvent { - u32 key; - u32 evt; -} keyEvent; - -// for 64bit compilers -typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; - -// plugin types -#define SIO_TYPE_PAD 0x00000001 -#define SIO_TYPE_MTAP 0x00000004 -#define SIO_TYPE_RM 0x00000040 -#define SIO_TYPE_MC 0x00000100 - -typedef int (CALLBACK * SIOchangeSlotCB)(int slot); - -typedef struct _cdvdSubQ { - u8 ctrl:4; // control and mode bits - u8 mode:4; // control and mode bits - u8 trackNum; // current track number (1 to 99) - u8 trackIndex; // current index within track (0 to 99) - u8 trackM; // current minute location on the disc (BCD encoded) - u8 trackS; // current sector location on the disc (BCD encoded) - u8 trackF; // current frame location on the disc (BCD encoded) - u8 pad; // unused - u8 discM; // current minute offset from first track (BCD encoded) - u8 discS; // current sector offset from first track (BCD encoded) - u8 discF; // current frame offset from first track (BCD encoded) -} cdvdSubQ; - -typedef struct _cdvdTD { // NOT bcd coded - u32 lsn; - u8 type; -} cdvdTD; - -typedef struct _cdvdTN { - u8 strack; //number of the first track (usually 1) - u8 etrack; //number of the last track -} cdvdTN; - -// CDVDreadTrack mode values: -#define CDVD_MODE_2352 0 // full 2352 bytes -#define CDVD_MODE_2340 1 // skip sync (12) bytes -#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq - -// CDVDgetDiskType returns: -#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc -#define CDVD_TYPE_DVDV 0xfe // DVD Video -#define CDVD_TYPE_CDDA 0xfd // Audio CD -#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD -#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) -#define CDVD_TYPE_PS2CD 0x12 // PS2 CD -#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) -#define CDVD_TYPE_PSCD 0x10 // PS CD -#define CDVD_TYPE_UNKNOWN 0x05 // Unknown -#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided -#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided -#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd -#define CDVD_TYPE_DETCT 0x01 // Detecting -#define CDVD_TYPE_NODISC 0x00 // No Disc - -// CDVDgetTrayStatus returns: -#define CDVD_TRAY_CLOSE 0x00 -#define CDVD_TRAY_OPEN 0x01 - -// cdvdTD.type (track types for cds) -#define CDVD_AUDIO_TRACK 0x01 -#define CDVD_MODE1_TRACK 0x41 -#define CDVD_MODE2_TRACK 0x61 - -#define CDVD_AUDIO_MASK 0x00 -#define CDVD_DATA_MASK 0x40 -// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) - -typedef void (*DEV9callback)(int cycles); -typedef int (*DEV9handler)(void); - -typedef void (*USBcallback)(int cycles); -typedef int (*USBhandler)(void); - -// freeze modes: -#define FREEZE_LOAD 0 -#define FREEZE_SAVE 1 -#define FREEZE_SIZE 2 - -typedef struct _GSdriverInfo { - char name[8]; - void *common; -} GSdriverInfo; - -#ifdef _WINDOWS_ -typedef struct _winInfo { // unsupported values must be set to zero - HWND hWnd; - HMENU hMenu; - HWND hStatusWnd; -} winInfo; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* GS plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef GSdefs - -// basic funcs - -s32 CALLBACK GSinit(); -s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); -void CALLBACK GSclose(); -void CALLBACK GSshutdown(); -void CALLBACK GSvsync(int field); -void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); -void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); -void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); -void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) -void CALLBACK GSgifSoftReset(u32 mask); -void CALLBACK GSreadFIFO(u64 *mem); -void CALLBACK GSreadFIFO2(u64 *mem, int qwc); - -// extended funcs - -// GSkeyEvent gets called when there is a keyEvent from the PAD plugin -void CALLBACK GSkeyEvent(keyEvent *ev); -void CALLBACK GSchangeSaveState(int, const char* filename); -void CALLBACK GSmakeSnapshot(char *path); -void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); -void CALLBACK GSirqCallback(void (*callback)()); -void CALLBACK GSprintf(int timeout, char *fmt, ...); -void CALLBACK GSsetBaseMem(void*); -void CALLBACK GSsetGameCRC(int crc, int gameoptions); - -// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done -void CALLBACK GSsetFrameSkip(int frameskip); - -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK GSsetupRecording(int start, void* pData); - -void CALLBACK GSreset(); -void CALLBACK GSwriteCSR(u32 value); -void CALLBACK GSgetDriverInfo(GSdriverInfo *info); -#ifdef _WIN32 -s32 CALLBACK GSsetWindowInfo(winInfo *info); -#endif -s32 CALLBACK GSfreeze(int mode, freezeData *data); -void CALLBACK GSconfigure(); -void CALLBACK GSabout(); -s32 CALLBACK GStest(); - -#endif - -/* PAD plugin API -=[ OBSOLETE ]=- */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef PADdefs - -// basic funcs - -s32 CALLBACK PADinit(u32 flags); -s32 CALLBACK PADopen(void *pDsp); -void CALLBACK PADclose(); -void CALLBACK PADshutdown(); -// PADkeyEvent is called every vsync (return NULL if no event) -keyEvent* CALLBACK PADkeyEvent(); -u8 CALLBACK PADstartPoll(int pad); -u8 CALLBACK PADpoll(u8 value); -// returns: 1 if supported pad1 -// 2 if supported pad2 -// 3 if both are supported -u32 CALLBACK PADquery(); - -// call to give a hint to the PAD plugin to query for the keyboard state. A -// good plugin will query the OS for keyboard state ONLY in this function. -// This function is necessary when multithreading because otherwise -// the PAD plugin can get into deadlocks with the thread that really owns -// the window (and input). Note that PADupdate can be called from a different -// thread than the other functions, so mutex or other multithreading primitives -// have to be added to maintain data integrity. -void CALLBACK PADupdate(int pad); - -// extended funcs - -void CALLBACK PADgsDriverInfo(GSdriverInfo *info); -void CALLBACK PADconfigure(); -void CALLBACK PADabout(); -s32 CALLBACK PADtest(); - -#endif - -/* SIO plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SIOdefs - -// basic funcs - -s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); -s32 CALLBACK SIOopen(void *pDsp); -void CALLBACK SIOclose(); -void CALLBACK SIOshutdown(); -u8 CALLBACK SIOstartPoll(u8 value); -u8 CALLBACK SIOpoll(u8 value); -// returns: SIO_TYPE_{PAD,MTAP,RM,MC} -u32 CALLBACK SIOquery(); - -// extended funcs - -void CALLBACK SIOconfigure(); -void CALLBACK SIOabout(); -s32 CALLBACK SIOtest(); - -#endif - -/* SPU2 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SPU2defs - -// basic funcs - -s32 CALLBACK SPU2init(); -s32 CALLBACK SPU2open(void *pDsp); -void CALLBACK SPU2close(); -void CALLBACK SPU2shutdown(); -void CALLBACK SPU2write(u32 mem, u16 value); -u16 CALLBACK SPU2read(u32 mem); -void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA4(); -void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); -void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); - -// all addresses passed by dma will be pointers to the array starting at baseaddr -// This function is necessary to successfully save and reload the spu2 state -void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); - -void CALLBACK SPU2interruptDMA7(); -u32 CALLBACK SPU2ReadMemAddr(int core); -void CALLBACK SPU2WriteMemAddr(int core,u32 value); -void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); - -// extended funcs -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK SPU2setupRecording(int start, void* pData); - -void CALLBACK SPU2setClockPtr(u32* ptr); -void CALLBACK SPU2setTimeStretcher(short int enable); - -void CALLBACK SPU2async(u32 cycles); -s32 CALLBACK SPU2freeze(int mode, freezeData *data); -void CALLBACK SPU2configure(); -void CALLBACK SPU2about(); -s32 CALLBACK SPU2test(); - -#endif - -/* CDVD plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef CDVDdefs - -// basic funcs - -s32 CALLBACK CDVDinit(); -s32 CALLBACK CDVDopen(const char* pTitleFilename); -void CALLBACK CDVDclose(); -void CALLBACK CDVDshutdown(); -s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); - -// return can be NULL (for async modes) -u8* CALLBACK CDVDgetBuffer(); - -s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) -s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information -s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type -s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc -s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx -s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx -s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray -s32 CALLBACK CDVDctrlTrayClose(); //close disc tray - -// extended funcs - -void CALLBACK CDVDconfigure(); -void CALLBACK CDVDabout(); -s32 CALLBACK CDVDtest(); -void CALLBACK CDVDnewDiskCB(void (*callback)()); - -#endif - -/* DEV9 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef DEV9defs - -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK DEV9init(); -s32 CALLBACK DEV9open(void *pDsp); -void CALLBACK DEV9close(); -void CALLBACK DEV9shutdown(); -u8 CALLBACK DEV9read8(u32 addr); -u16 CALLBACK DEV9read16(u32 addr); -u32 CALLBACK DEV9read32(u32 addr); -void CALLBACK DEV9write8(u32 addr, u8 value); -void CALLBACK DEV9write16(u32 addr, u16 value); -void CALLBACK DEV9write32(u32 addr, u32 value); -void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); -void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK DEV9irqCallback(DEV9callback callback); -DEV9handler CALLBACK DEV9irqHandler(void); - -// extended funcs - -s32 CALLBACK DEV9freeze(int mode, freezeData *data); -void CALLBACK DEV9configure(); -void CALLBACK DEV9about(); -s32 CALLBACK DEV9test(); - -#endif - -/* USB plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef USBdefs - -// basic funcs - -s32 CALLBACK USBinit(); -s32 CALLBACK USBopen(void *pDsp); -void CALLBACK USBclose(); -void CALLBACK USBshutdown(); -u8 CALLBACK USBread8(u32 addr); -u16 CALLBACK USBread16(u32 addr); -u32 CALLBACK USBread32(u32 addr); -void CALLBACK USBwrite8(u32 addr, u8 value); -void CALLBACK USBwrite16(u32 addr, u16 value); -void CALLBACK USBwrite32(u32 addr, u32 value); -void CALLBACK USBasync(u32 cycles); - -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK USBirqCallback(USBcallback callback); -USBhandler CALLBACK USBirqHandler(void); -void CALLBACK USBsetRAM(void *mem); - -// extended funcs - -s32 CALLBACK USBfreeze(int mode, freezeData *data); -void CALLBACK USBconfigure(); -void CALLBACK USBabout(); -s32 CALLBACK USBtest(); - -#endif - -/* FW plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef FWdefs -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK FWinit(); -s32 CALLBACK FWopen(void *pDsp); -void CALLBACK FWclose(); -void CALLBACK FWshutdown(); -u32 CALLBACK FWread32(u32 addr); -void CALLBACK FWwrite32(u32 addr, u32 value); -void CALLBACK FWirqCallback(void (*callback)()); - -// extended funcs - -s32 CALLBACK FWfreeze(int mode, freezeData *data); -void CALLBACK FWconfigure(); -void CALLBACK FWabout(); -s32 CALLBACK FWtest(); -#endif - -// might be useful for emulators -#ifdef PLUGINtypedefs - -typedef u32 (CALLBACK* _PS2EgetLibType)(void); -typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); -typedef char*(CALLBACK* _PS2EgetLibName)(void); - -// GS -// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _GSinit)(); -typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); -typedef void (CALLBACK* _GSclose)(); -typedef void (CALLBACK* _GSshutdown)(); -typedef void (CALLBACK* _GSvsync)(int field); -typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); -typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) -typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); -typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); -typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); - -typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); -typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); -typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); -typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); -typedef void (CALLBACK* _GSsetBaseMem)(void*); -typedef void (CALLBACK* _GSsetGameCRC)(int, int); -typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); -typedef int (CALLBACK* _GSsetupRecording)(int, void*); -typedef void (CALLBACK* _GSreset)(); -typedef void (CALLBACK* _GSwriteCSR)(u32 value); -typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); -#ifdef _WINDOWS_ -typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); -#endif -typedef void (CALLBACK* _GSmakeSnapshot)(const char *path); -typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); -typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _GSconfigure)(); -typedef s32 (CALLBACK* _GStest)(); -typedef void (CALLBACK* _GSabout)(); - -// PAD -typedef s32 (CALLBACK* _PADinit)(u32 flags); -typedef s32 (CALLBACK* _PADopen)(void *pDsp); -typedef void (CALLBACK* _PADclose)(); -typedef void (CALLBACK* _PADshutdown)(); -typedef keyEvent* (CALLBACK* _PADkeyEvent)(); -typedef u8 (CALLBACK* _PADstartPoll)(int pad); -typedef u8 (CALLBACK* _PADpoll)(u8 value); -typedef u32 (CALLBACK* _PADquery)(); -typedef void (CALLBACK* _PADupdate)(int pad); - -typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); -typedef void (CALLBACK* _PADconfigure)(); -typedef s32 (CALLBACK* _PADtest)(); -typedef void (CALLBACK* _PADabout)(); - -// SIO -typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); -typedef s32 (CALLBACK* _SIOopen)(void *pDsp); -typedef void (CALLBACK* _SIOclose)(); -typedef void (CALLBACK* _SIOshutdown)(); -typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); -typedef u8 (CALLBACK* _SIOpoll)(u8 value); -typedef u32 (CALLBACK* _SIOquery)(); - -typedef void (CALLBACK* _SIOconfigure)(); -typedef s32 (CALLBACK* _SIOtest)(); -typedef void (CALLBACK* _SIOabout)(); - -// SPU2 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _SPU2init)(); -typedef s32 (CALLBACK* _SPU2open)(void *pDsp); -typedef void (CALLBACK* _SPU2close)(); -typedef void (CALLBACK* _SPU2shutdown)(); -typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); -typedef u16 (CALLBACK* _SPU2read)(u32 mem); -typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA4)(); -typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); -typedef void (CALLBACK* _SPU2interruptDMA7)(); -typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); -typedef int (CALLBACK* _SPU2setupRecording)(int, void*); - -typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); -typedef void (CALLBACK* _SPU2setTimeStretcher)(short int enable); - -typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); -typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); -typedef void (CALLBACK* _SPU2async)(u32 cycles); -typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _SPU2configure)(); -typedef s32 (CALLBACK* _SPU2test)(); -typedef void (CALLBACK* _SPU2about)(); - - -// CDVD -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _CDVDinit)(); -typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); -typedef void (CALLBACK* _CDVDclose)(); -typedef void (CALLBACK* _CDVDshutdown)(); -typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); -typedef u8* (CALLBACK* _CDVDgetBuffer)(); -typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); -typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); -typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); -typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); -typedef s32 (CALLBACK* _CDVDgetDiskType)(); -typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); -typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); -typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); - -typedef void (CALLBACK* _CDVDconfigure)(); -typedef s32 (CALLBACK* _CDVDtest)(); -typedef void (CALLBACK* _CDVDabout)(); -typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); - -// DEV9 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _DEV9init)(); -typedef s32 (CALLBACK* _DEV9open)(void *pDsp); -typedef void (CALLBACK* _DEV9close)(); -typedef void (CALLBACK* _DEV9shutdown)(); -typedef u8 (CALLBACK* _DEV9read8)(u32 mem); -typedef u16 (CALLBACK* _DEV9read16)(u32 mem); -typedef u32 (CALLBACK* _DEV9read32)(u32 mem); -typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); -typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); -typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); -typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); -typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); - -typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _DEV9configure)(); -typedef s32 (CALLBACK* _DEV9test)(); -typedef void (CALLBACK* _DEV9about)(); - -// USB -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _USBinit)(); -typedef s32 (CALLBACK* _USBopen)(void *pDsp); -typedef void (CALLBACK* _USBclose)(); -typedef void (CALLBACK* _USBshutdown)(); -typedef u8 (CALLBACK* _USBread8)(u32 mem); -typedef u16 (CALLBACK* _USBread16)(u32 mem); -typedef u32 (CALLBACK* _USBread32)(u32 mem); -typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); -typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); -typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _USBasync)(u32 cycles); - - -typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); -typedef USBhandler (CALLBACK* _USBirqHandler)(void); -typedef void (CALLBACK* _USBsetRAM)(void *mem); - -typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _USBconfigure)(); -typedef s32 (CALLBACK* _USBtest)(); -typedef void (CALLBACK* _USBabout)(); - -//FW -typedef s32 (CALLBACK* _FWinit)(); -typedef s32 (CALLBACK* _FWopen)(void *pDsp); -typedef void (CALLBACK* _FWclose)(); -typedef void (CALLBACK* _FWshutdown)(); -typedef u32 (CALLBACK* _FWread32)(u32 mem); -typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); - -typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _FWconfigure)(); -typedef s32 (CALLBACK* _FWtest)(); -typedef void (CALLBACK* _FWabout)(); - -#endif - -#ifdef PLUGINfuncs - -// GS -extern _GSinit GSinit; -extern _GSopen GSopen; -extern _GSclose GSclose; -extern _GSshutdown GSshutdown; -extern _GSvsync GSvsync; -extern _GSgifTransfer1 GSgifTransfer1; -extern _GSgifTransfer2 GSgifTransfer2; -extern _GSgifTransfer3 GSgifTransfer3; -extern _GSgetLastTag GSgetLastTag; -extern _GSgifSoftReset GSgifSoftReset; -extern _GSreadFIFO GSreadFIFO; -extern _GSreadFIFO2 GSreadFIFO2; - -extern _GSkeyEvent GSkeyEvent; -extern _GSchangeSaveState GSchangeSaveState; -extern _GSmakeSnapshot GSmakeSnapshot; -extern _GSmakeSnapshot2 GSmakeSnapshot2; -extern _GSirqCallback GSirqCallback; -extern _GSprintf GSprintf; -extern _GSsetBaseMem GSsetBaseMem; -extern _GSsetGameCRC GSsetGameCRC; -extern _GSsetFrameSkip GSsetFrameSkip; -extern _GSsetupRecording GSsetupRecording; -extern _GSreset GSreset; -extern _GSwriteCSR GSwriteCSR; -extern _GSgetDriverInfo GSgetDriverInfo; -#ifdef _WINDOWS_ -extern _GSsetWindowInfo GSsetWindowInfo; -#endif -extern _GSfreeze GSfreeze; -extern _GSconfigure GSconfigure; -extern _GStest GStest; -extern _GSabout GSabout; - -// PAD1 -extern _PADinit PAD1init; -extern _PADopen PAD1open; -extern _PADclose PAD1close; -extern _PADshutdown PAD1shutdown; -extern _PADkeyEvent PAD1keyEvent; -extern _PADstartPoll PAD1startPoll; -extern _PADpoll PAD1poll; -extern _PADquery PAD1query; -extern _PADupdate PAD1update; - -extern _PADgsDriverInfo PAD1gsDriverInfo; -extern _PADconfigure PAD1configure; -extern _PADtest PAD1test; -extern _PADabout PAD1about; - -// PAD2 -extern _PADinit PAD2init; -extern _PADopen PAD2open; -extern _PADclose PAD2close; -extern _PADshutdown PAD2shutdown; -extern _PADkeyEvent PAD2keyEvent; -extern _PADstartPoll PAD2startPoll; -extern _PADpoll PAD2poll; -extern _PADquery PAD2query; -extern _PADupdate PAD2update; - -extern _PADgsDriverInfo PAD2gsDriverInfo; -extern _PADconfigure PAD2configure; -extern _PADtest PAD2test; -extern _PADabout PAD2about; - -// SIO[2] -extern _SIOinit SIOinit[2][9]; -extern _SIOopen SIOopen[2][9]; -extern _SIOclose SIOclose[2][9]; -extern _SIOshutdown SIOshutdown[2][9]; -extern _SIOstartPoll SIOstartPoll[2][9]; -extern _SIOpoll SIOpoll[2][9]; -extern _SIOquery SIOquery[2][9]; - -extern _SIOconfigure SIOconfigure[2][9]; -extern _SIOtest SIOtest[2][9]; -extern _SIOabout SIOabout[2][9]; - -// SPU2 -extern _SPU2init SPU2init; -extern _SPU2open SPU2open; -extern _SPU2close SPU2close; -extern _SPU2shutdown SPU2shutdown; -extern _SPU2write SPU2write; -extern _SPU2read SPU2read; -extern _SPU2readDMA4Mem SPU2readDMA4Mem; -extern _SPU2writeDMA4Mem SPU2writeDMA4Mem; -extern _SPU2interruptDMA4 SPU2interruptDMA4; -extern _SPU2readDMA7Mem SPU2readDMA7Mem; -extern _SPU2writeDMA7Mem SPU2writeDMA7Mem; -extern _SPU2setDMABaseAddr SPU2setDMABaseAddr; -extern _SPU2interruptDMA7 SPU2interruptDMA7; -extern _SPU2ReadMemAddr SPU2ReadMemAddr; -extern _SPU2setupRecording SPU2setupRecording; -extern _SPU2WriteMemAddr SPU2WriteMemAddr; -extern _SPU2irqCallback SPU2irqCallback; - -extern _SPU2setClockPtr SPU2setClockPtr; -extern _SPU2setTimeStretcher SPU2setTimeStretcher; - -extern _SPU2async SPU2async; -extern _SPU2freeze SPU2freeze; -extern _SPU2configure SPU2configure; -extern _SPU2test SPU2test; -extern _SPU2about SPU2about; - -// CDVD -extern _CDVDinit CDVDinit; -extern _CDVDopen CDVDopen; -extern _CDVDclose CDVDclose; -extern _CDVDshutdown CDVDshutdown; -extern _CDVDreadTrack CDVDreadTrack; -extern _CDVDgetBuffer CDVDgetBuffer; -extern _CDVDreadSubQ CDVDreadSubQ; -extern _CDVDgetTN CDVDgetTN; -extern _CDVDgetTD CDVDgetTD; -extern _CDVDgetTOC CDVDgetTOC; -extern _CDVDgetDiskType CDVDgetDiskType; -extern _CDVDgetTrayStatus CDVDgetTrayStatus; -extern _CDVDctrlTrayOpen CDVDctrlTrayOpen; -extern _CDVDctrlTrayClose CDVDctrlTrayClose; - -extern _CDVDconfigure CDVDconfigure; -extern _CDVDtest CDVDtest; -extern _CDVDabout CDVDabout; -extern _CDVDnewDiskCB CDVDnewDiskCB; - -// DEV9 -extern _DEV9init DEV9init; -extern _DEV9open DEV9open; -extern _DEV9close DEV9close; -extern _DEV9shutdown DEV9shutdown; -extern _DEV9read8 DEV9read8; -extern _DEV9read16 DEV9read16; -extern _DEV9read32 DEV9read32; -extern _DEV9write8 DEV9write8; -extern _DEV9write16 DEV9write16; -extern _DEV9write32 DEV9write32; -extern _DEV9readDMA8Mem DEV9readDMA8Mem; -extern _DEV9writeDMA8Mem DEV9writeDMA8Mem; -extern _DEV9irqCallback DEV9irqCallback; -extern _DEV9irqHandler DEV9irqHandler; - -extern _DEV9configure DEV9configure; -extern _DEV9freeze DEV9freeze; -extern _DEV9test DEV9test; -extern _DEV9about DEV9about; - -// USB -extern _USBinit USBinit; -extern _USBopen USBopen; -extern _USBclose USBclose; -extern _USBshutdown USBshutdown; -extern _USBread8 USBread8; -extern _USBread16 USBread16; -extern _USBread32 USBread32; -extern _USBwrite8 USBwrite8; -extern _USBwrite16 USBwrite16; -extern _USBwrite32 USBwrite32; -extern _USBasync USBasync; - -extern _USBirqCallback USBirqCallback; -extern _USBirqHandler USBirqHandler; -extern _USBsetRAM USBsetRAM; - -extern _USBconfigure USBconfigure; -extern _USBfreeze USBfreeze; -extern _USBtest USBtest; -extern _USBabout USBabout; - -// FW -extern _FWinit FWinit; -extern _FWopen FWopen; -extern _FWclose FWclose; -extern _FWshutdown FWshutdown; -extern _FWread32 FWread32; -extern _FWwrite32 FWwrite32; -extern _FWirqCallback FWirqCallback; - -extern _FWconfigure FWconfigure; -extern _FWfreeze FWfreeze; -extern _FWtest FWtest; -extern _FWabout FWabout; -#endif - -#ifdef __cplusplus -} // End extern "C" -#endif - -#endif /* __PS2EDEFS_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct _keyEvent { + u32 key; + u32 evt; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct _cdvdSubQ { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct _cdvdTD { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct _cdvdTN { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct _GSdriverInfo { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WINDOWS_ +typedef struct _winInfo { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2setClockPtr(u32* ptr); +void CALLBACK SPU2setTimeStretcher(short int enable); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +void CALLBACK USBasync(u32 cycles); + +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WINDOWS_ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(const char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); + +typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); +typedef void (CALLBACK* _SPU2setTimeStretcher)(short int enable); + +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBasync)(u32 cycles); + + +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +extern _GSinit GSinit; +extern _GSopen GSopen; +extern _GSclose GSclose; +extern _GSshutdown GSshutdown; +extern _GSvsync GSvsync; +extern _GSgifTransfer1 GSgifTransfer1; +extern _GSgifTransfer2 GSgifTransfer2; +extern _GSgifTransfer3 GSgifTransfer3; +extern _GSgetLastTag GSgetLastTag; +extern _GSgifSoftReset GSgifSoftReset; +extern _GSreadFIFO GSreadFIFO; +extern _GSreadFIFO2 GSreadFIFO2; + +extern _GSkeyEvent GSkeyEvent; +extern _GSchangeSaveState GSchangeSaveState; +extern _GSmakeSnapshot GSmakeSnapshot; +extern _GSmakeSnapshot2 GSmakeSnapshot2; +extern _GSirqCallback GSirqCallback; +extern _GSprintf GSprintf; +extern _GSsetBaseMem GSsetBaseMem; +extern _GSsetGameCRC GSsetGameCRC; +extern _GSsetFrameSkip GSsetFrameSkip; +extern _GSsetupRecording GSsetupRecording; +extern _GSreset GSreset; +extern _GSwriteCSR GSwriteCSR; +extern _GSgetDriverInfo GSgetDriverInfo; +#ifdef _WINDOWS_ +extern _GSsetWindowInfo GSsetWindowInfo; +#endif +extern _GSfreeze GSfreeze; +extern _GSconfigure GSconfigure; +extern _GStest GStest; +extern _GSabout GSabout; + +// PAD1 +extern _PADinit PAD1init; +extern _PADopen PAD1open; +extern _PADclose PAD1close; +extern _PADshutdown PAD1shutdown; +extern _PADkeyEvent PAD1keyEvent; +extern _PADstartPoll PAD1startPoll; +extern _PADpoll PAD1poll; +extern _PADquery PAD1query; +extern _PADupdate PAD1update; + +extern _PADgsDriverInfo PAD1gsDriverInfo; +extern _PADconfigure PAD1configure; +extern _PADtest PAD1test; +extern _PADabout PAD1about; + +// PAD2 +extern _PADinit PAD2init; +extern _PADopen PAD2open; +extern _PADclose PAD2close; +extern _PADshutdown PAD2shutdown; +extern _PADkeyEvent PAD2keyEvent; +extern _PADstartPoll PAD2startPoll; +extern _PADpoll PAD2poll; +extern _PADquery PAD2query; +extern _PADupdate PAD2update; + +extern _PADgsDriverInfo PAD2gsDriverInfo; +extern _PADconfigure PAD2configure; +extern _PADtest PAD2test; +extern _PADabout PAD2about; + +// SIO[2] +extern _SIOinit SIOinit[2][9]; +extern _SIOopen SIOopen[2][9]; +extern _SIOclose SIOclose[2][9]; +extern _SIOshutdown SIOshutdown[2][9]; +extern _SIOstartPoll SIOstartPoll[2][9]; +extern _SIOpoll SIOpoll[2][9]; +extern _SIOquery SIOquery[2][9]; + +extern _SIOconfigure SIOconfigure[2][9]; +extern _SIOtest SIOtest[2][9]; +extern _SIOabout SIOabout[2][9]; + +// SPU2 +extern _SPU2init SPU2init; +extern _SPU2open SPU2open; +extern _SPU2close SPU2close; +extern _SPU2shutdown SPU2shutdown; +extern _SPU2write SPU2write; +extern _SPU2read SPU2read; +extern _SPU2readDMA4Mem SPU2readDMA4Mem; +extern _SPU2writeDMA4Mem SPU2writeDMA4Mem; +extern _SPU2interruptDMA4 SPU2interruptDMA4; +extern _SPU2readDMA7Mem SPU2readDMA7Mem; +extern _SPU2writeDMA7Mem SPU2writeDMA7Mem; +extern _SPU2setDMABaseAddr SPU2setDMABaseAddr; +extern _SPU2interruptDMA7 SPU2interruptDMA7; +extern _SPU2ReadMemAddr SPU2ReadMemAddr; +extern _SPU2setupRecording SPU2setupRecording; +extern _SPU2WriteMemAddr SPU2WriteMemAddr; +extern _SPU2irqCallback SPU2irqCallback; + +extern _SPU2setClockPtr SPU2setClockPtr; +extern _SPU2setTimeStretcher SPU2setTimeStretcher; + +extern _SPU2async SPU2async; +extern _SPU2freeze SPU2freeze; +extern _SPU2configure SPU2configure; +extern _SPU2test SPU2test; +extern _SPU2about SPU2about; + +// CDVD +extern _CDVDinit CDVDinit; +extern _CDVDopen CDVDopen; +extern _CDVDclose CDVDclose; +extern _CDVDshutdown CDVDshutdown; +extern _CDVDreadTrack CDVDreadTrack; +extern _CDVDgetBuffer CDVDgetBuffer; +extern _CDVDreadSubQ CDVDreadSubQ; +extern _CDVDgetTN CDVDgetTN; +extern _CDVDgetTD CDVDgetTD; +extern _CDVDgetTOC CDVDgetTOC; +extern _CDVDgetDiskType CDVDgetDiskType; +extern _CDVDgetTrayStatus CDVDgetTrayStatus; +extern _CDVDctrlTrayOpen CDVDctrlTrayOpen; +extern _CDVDctrlTrayClose CDVDctrlTrayClose; + +extern _CDVDconfigure CDVDconfigure; +extern _CDVDtest CDVDtest; +extern _CDVDabout CDVDabout; +extern _CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +extern _DEV9init DEV9init; +extern _DEV9open DEV9open; +extern _DEV9close DEV9close; +extern _DEV9shutdown DEV9shutdown; +extern _DEV9read8 DEV9read8; +extern _DEV9read16 DEV9read16; +extern _DEV9read32 DEV9read32; +extern _DEV9write8 DEV9write8; +extern _DEV9write16 DEV9write16; +extern _DEV9write32 DEV9write32; +extern _DEV9readDMA8Mem DEV9readDMA8Mem; +extern _DEV9writeDMA8Mem DEV9writeDMA8Mem; +extern _DEV9irqCallback DEV9irqCallback; +extern _DEV9irqHandler DEV9irqHandler; + +extern _DEV9configure DEV9configure; +extern _DEV9freeze DEV9freeze; +extern _DEV9test DEV9test; +extern _DEV9about DEV9about; + +// USB +extern _USBinit USBinit; +extern _USBopen USBopen; +extern _USBclose USBclose; +extern _USBshutdown USBshutdown; +extern _USBread8 USBread8; +extern _USBread16 USBread16; +extern _USBread32 USBread32; +extern _USBwrite8 USBwrite8; +extern _USBwrite16 USBwrite16; +extern _USBwrite32 USBwrite32; +extern _USBasync USBasync; + +extern _USBirqCallback USBirqCallback; +extern _USBirqHandler USBirqHandler; +extern _USBsetRAM USBsetRAM; + +extern _USBconfigure USBconfigure; +extern _USBfreeze USBfreeze; +extern _USBtest USBtest; +extern _USBabout USBabout; + +// FW +extern _FWinit FWinit; +extern _FWopen FWopen; +extern _FWclose FWclose; +extern _FWshutdown FWshutdown; +extern _FWread32 FWread32; +extern _FWwrite32 FWwrite32; +extern _FWirqCallback FWirqCallback; + +extern _FWconfigure FWconfigure; +extern _FWfreeze FWfreeze; +extern _FWtest FWtest; +extern _FWabout FWabout; +#endif + +#ifdef __cplusplus +} // End extern "C" +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/zerogs/opengl/common/PS2Etypes.h b/plugins/zerogs/opengl/common/PS2Etypes.h index 59be1c3de4..4c62b47f0f 100644 --- a/plugins/zerogs/opengl/common/PS2Etypes.h +++ b/plugins/zerogs/opengl/common/PS2Etypes.h @@ -1,219 +1,219 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef __PS2ETYPES_H__ -#define __PS2ETYPES_H__ - -#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case -#define __LINUX__ -#endif - -#ifdef __CYGWIN__ -#define __LINUX__ -#endif - -#ifndef ARRAYSIZE -#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) -#endif - -#ifdef __LINUX__ -#define CALLBACK -#else -#define CALLBACK __stdcall -#endif - - -// jASSUME - give hints to the optimizer -// This is primarily useful for the default case switch optimizer, which enables VC to -// generate more compact switches. - -#ifdef NDEBUG -# define jBREAKPOINT() ((void) 0) -# ifdef _MSC_VER -# define jASSUME(exp) (__assume(exp)) -# else -# define jASSUME(exp) ((void) sizeof(exp)) -# endif -#else -# if defined(_MSC_VER) -# define jBREAKPOINT() do { __asm int 3 } while(0) -# else -# define jBREAKPOINT() ((void) *(volatile char *) 0) -# endif -# define jASSUME(exp) if(exp) ; else jBREAKPOINT() -#endif - -// disable the default case in a switch -#define jNO_DEFAULT \ -{ \ - break; \ - \ -default: \ - jASSUME(0); \ - break; \ -} - - -// Basic types -#if defined(_MSC_VER) - -typedef __int8 s8; -typedef __int16 s16; -typedef __int32 s32; -typedef __int64 s64; - -typedef unsigned __int8 u8; -typedef unsigned __int16 u16; -typedef unsigned __int32 u32; -typedef unsigned __int64 u64; - -typedef unsigned int uint; - -#define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x -#define PCSX2_ALIGNED16(x) __declspec(align(16)) x -#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x - -#define __naked __declspec(naked) - -#else // _MSC_VER - -#ifdef __LINUX__ - -#ifdef HAVE_STDINT_H -#include "stdint.h" - -typedef int8_t s8; -typedef int16_t s16; -typedef int32_t s32; -typedef int64_t s64; - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -typedef uintptr_t uptr; -typedef intptr_t sptr; - -#else // HAVE_STDINT_H - -typedef char s8; -typedef short s16; -typedef int s32; -typedef long long s64; - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long long u64; - -#endif // HAVE_STDINT_H - -typedef unsigned int uint; - -#define LONG long -typedef union _LARGE_INTEGER -{ - long long QuadPart; -} LARGE_INTEGER; - -#define __fastcall __attribute__((fastcall)) -#define __unused __attribute__((unused)) -#define _inline __inline__ __attribute__((unused)) -#define __forceinline __attribute__((always_inline,unused)) -#define __naked // GCC lacks the naked specifier - -#endif // __LINUX__ - -#define PCSX2_ALIGNED(alig,x) x __attribute((aligned(alig))) -#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) - -#define PCSX2_ALIGNED16_DECL(x) x - -#endif // _MSC_VER - -#if !defined(__LINUX__) || !defined(HAVE_STDINT_H) -#if defined(__x86_64__) -typedef u64 uptr; -typedef s64 sptr; -#else -typedef u32 uptr; -typedef s32 sptr; -#endif -#endif - -// A rough-and-ready cross platform 128-bit datatype, Non-SSE style. -#ifdef __cplusplus -struct u128 -{ - u64 lo; - u64 hi; - - // Implicit conversion from u64 - u128( u64 src ) : - lo( src ) - , hi( 0 ) {} - - // Implicit conversion from u32 - u128( u32 src ) : - lo( src ) - , hi( 0 ) {} -}; - -struct s128 -{ - s64 lo; - s64 hi; - - // Implicit conversion from u64 - s128( s64 src ) : - lo( src ) - , hi( 0 ) {} - - // Implicit conversion from u32 - s128( s32 src ) : - lo( src ) - , hi( 0 ) {} -}; - -#else - -typedef union _u128_t -{ - u64 lo; - u64 hi; -} u128; - -typedef union _s128_t -{ - s64 lo; - s64 hi; -} s128; - -#endif - -typedef struct { - int size; - s8 *data; -} freezeData; - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#endif /* __PS2ETYPES_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +#ifdef __CYGWIN__ +#define __LINUX__ +#endif + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#ifdef __LINUX__ +#define CALLBACK +#else +#define CALLBACK __stdcall +#endif + + +// jASSUME - give hints to the optimizer +// This is primarily useful for the default case switch optimizer, which enables VC to +// generate more compact switches. + +#ifdef NDEBUG +# define jBREAKPOINT() ((void) 0) +# ifdef _MSC_VER +# define jASSUME(exp) (__assume(exp)) +# else +# define jASSUME(exp) ((void) sizeof(exp)) +# endif +#else +# if defined(_MSC_VER) +# define jBREAKPOINT() do { __asm int 3 } while(0) +# else +# define jBREAKPOINT() ((void) *(volatile char *) 0) +# endif +# define jASSUME(exp) if(exp) ; else jBREAKPOINT() +#endif + +// disable the default case in a switch +#define jNO_DEFAULT \ +{ \ + break; \ + \ +default: \ + jASSUME(0); \ + break; \ +} + + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +typedef unsigned int uint; + +#define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x + +#define __naked __declspec(naked) + +#else // _MSC_VER + +#ifdef __LINUX__ + +#ifdef HAVE_STDINT_H +#include "stdint.h" + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef uintptr_t uptr; +typedef intptr_t sptr; + +#else // HAVE_STDINT_H + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#endif // HAVE_STDINT_H + +typedef unsigned int uint; + +#define LONG long +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; + +#define __fastcall __attribute__((fastcall)) +#define __unused __attribute__((unused)) +#define _inline __inline__ __attribute__((unused)) +#define __forceinline __attribute__((always_inline,unused)) +#define __naked // GCC lacks the naked specifier + +#endif // __LINUX__ + +#define PCSX2_ALIGNED(alig,x) x __attribute((aligned(alig))) +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) + +#define PCSX2_ALIGNED16_DECL(x) x + +#endif // _MSC_VER + +#if !defined(__LINUX__) || !defined(HAVE_STDINT_H) +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif +#endif + +// A rough-and-ready cross platform 128-bit datatype, Non-SSE style. +#ifdef __cplusplus +struct u128 +{ + u64 lo; + u64 hi; + + // Implicit conversion from u64 + u128( u64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + u128( u32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +struct s128 +{ + s64 lo; + s64 hi; + + // Implicit conversion from u64 + s128( s64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + s128( s32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +#else + +typedef union _u128_t +{ + u64 lo; + u64 hi; +} u128; + +typedef union _s128_t +{ + s64 lo; + s64 hi; +} s128; + +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/zerogs/opengl/glprocs.c b/plugins/zerogs/opengl/glprocs.c index da82208f15..f7e3af4efa 100644 --- a/plugins/zerogs/opengl/glprocs.c +++ b/plugins/zerogs/opengl/glprocs.c @@ -1,17864 +1,17864 @@ -/* -** GLprocs utility for getting function addresses for OpenGL(R) 1.2, -** OpenGL 1.3, OpenGL 1.4, OpenGL 1.5 and OpenGL extension functions. -** -** Version: 1.1 -** -** License Applicability. Except to the extent portions of this file are -** made subject to an alternative license as permitted in the SGI Free -** Software License B, Version 1.1 (the "License"), the contents of this -** file are subject only to the provisions of the License. You may not use -** this file except in compliance with the License. You may obtain a copy -** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 -** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: -** -** http://oss.sgi.com/projects/FreeB -** -** Note that, as provided in the License, the Software is distributed on an -** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS -** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND -** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A -** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. -** -** Original Code. The Original Code is: OpenGL Sample Implementation, -** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, -** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. -** Copyright in any portions created by third parties is as indicated -** elsewhere herein. All Rights Reserved. -** -** Additional Notice Provisions: This software was created using the -** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has -** not been independently verified as being compliant with the OpenGL(R) -** version 1.2.1 Specification. -** -** Initial version of glprocs.{c,h} contributed by Intel(R) Corporation. -*/ - -#include -#include - -#ifdef _WIN32 - #include - #include //"gl.h" /* Include local "gl.h". Don't include vc32 . */ - #include "glprocs.h" -#else /* GLX */ - #include - #include - #include -#include "glprocs.h"// -// #define wglGetProcAddress glXGetProcAddress -inline void* wglGetProcAddress(const char* x) { - return (void*)glXGetProcAddress((const GLubyte*)x); -} - -#endif - -#define _ASSERT(a) assert(a) - -static void APIENTRY InitBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBlendColor"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBlendColor = extproc; - - glBlendColor(red, green, blue, alpha); -} - -static void APIENTRY InitBlendEquation (GLenum mode) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBlendEquation"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBlendEquation = extproc; - - glBlendEquation(mode); -} - -static void APIENTRY InitDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDrawRangeElements"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDrawRangeElements = extproc; - - glDrawRangeElements(mode, start, end, count, type, indices); -} - -static void APIENTRY InitColorTable (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColorTable"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColorTable = extproc; - - glColorTable(target, internalformat, width, format, type, table); -} - -static void APIENTRY InitColorTableParameterfv (GLenum target, GLenum pname, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColorTableParameterfv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColorTableParameterfv = extproc; - - glColorTableParameterfv(target, pname, params); -} - -static void APIENTRY InitColorTableParameteriv (GLenum target, GLenum pname, const GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColorTableParameteriv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColorTableParameteriv = extproc; - - glColorTableParameteriv(target, pname, params); -} - -static void APIENTRY InitCopyColorTable (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCopyColorTable"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCopyColorTable = extproc; - - glCopyColorTable(target, internalformat, x, y, width); -} - -static void APIENTRY InitGetColorTable (GLenum target, GLenum format, GLenum type, GLvoid *table) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetColorTable"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetColorTable = extproc; - - glGetColorTable(target, format, type, table); -} - -static void APIENTRY InitGetColorTableParameterfv (GLenum target, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetColorTableParameterfv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetColorTableParameterfv = extproc; - - glGetColorTableParameterfv(target, pname, params); -} - -static void APIENTRY InitGetColorTableParameteriv (GLenum target, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetColorTableParameteriv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetColorTableParameteriv = extproc; - - glGetColorTableParameteriv(target, pname, params); -} - -static void APIENTRY InitColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColorSubTable"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColorSubTable = extproc; - - glColorSubTable(target, start, count, format, type, data); -} - -static void APIENTRY InitCopyColorSubTable (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCopyColorSubTable"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCopyColorSubTable = extproc; - - glCopyColorSubTable(target, start, x, y, width); -} - -static void APIENTRY InitConvolutionFilter1D (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glConvolutionFilter1D"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glConvolutionFilter1D = extproc; - - glConvolutionFilter1D(target, internalformat, width, format, type, image); -} - -static void APIENTRY InitConvolutionFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glConvolutionFilter2D"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glConvolutionFilter2D = extproc; - - glConvolutionFilter2D(target, internalformat, width, height, format, type, image); -} - -static void APIENTRY InitConvolutionParameterf (GLenum target, GLenum pname, GLfloat params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glConvolutionParameterf"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glConvolutionParameterf = extproc; - - glConvolutionParameterf(target, pname, params); -} - -static void APIENTRY InitConvolutionParameterfv (GLenum target, GLenum pname, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glConvolutionParameterfv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glConvolutionParameterfv = extproc; - - glConvolutionParameterfv(target, pname, params); -} - -static void APIENTRY InitConvolutionParameteri (GLenum target, GLenum pname, GLint params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glConvolutionParameteri"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glConvolutionParameteri = extproc; - - glConvolutionParameteri(target, pname, params); -} - -static void APIENTRY InitConvolutionParameteriv (GLenum target, GLenum pname, const GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glConvolutionParameteriv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glConvolutionParameteriv = extproc; - - glConvolutionParameteriv(target, pname, params); -} - -static void APIENTRY InitCopyConvolutionFilter1D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCopyConvolutionFilter1D"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCopyConvolutionFilter1D = extproc; - - glCopyConvolutionFilter1D(target, internalformat, x, y, width); -} - -static void APIENTRY InitCopyConvolutionFilter2D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCopyConvolutionFilter2D"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCopyConvolutionFilter2D = extproc; - - glCopyConvolutionFilter2D(target, internalformat, x, y, width, height); -} - -static void APIENTRY InitGetConvolutionFilter (GLenum target, GLenum format, GLenum type, GLvoid *image) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetConvolutionFilter"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetConvolutionFilter = extproc; - - glGetConvolutionFilter(target, format, type, image); -} - -static void APIENTRY InitGetConvolutionParameterfv (GLenum target, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetConvolutionParameterfv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetConvolutionParameterfv = extproc; - - glGetConvolutionParameterfv(target, pname, params); -} - -static void APIENTRY InitGetConvolutionParameteriv (GLenum target, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetConvolutionParameteriv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetConvolutionParameteriv = extproc; - - glGetConvolutionParameteriv(target, pname, params); -} - -static void APIENTRY InitGetSeparableFilter (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetSeparableFilter"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetSeparableFilter = extproc; - - glGetSeparableFilter(target, format, type, row, column, span); -} - -static void APIENTRY InitSeparableFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSeparableFilter2D"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSeparableFilter2D = extproc; - - glSeparableFilter2D(target, internalformat, width, height, format, type, row, column); -} - -static void APIENTRY InitGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetHistogram"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetHistogram = extproc; - - glGetHistogram(target, reset, format, type, values); -} - -static void APIENTRY InitGetHistogramParameterfv (GLenum target, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetHistogramParameterfv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetHistogramParameterfv = extproc; - - glGetHistogramParameterfv(target, pname, params); -} - -static void APIENTRY InitGetHistogramParameteriv (GLenum target, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetHistogramParameteriv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetHistogramParameteriv = extproc; - - glGetHistogramParameteriv(target, pname, params); -} - -static void APIENTRY InitGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetMinmax"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetMinmax = extproc; - - glGetMinmax(target, reset, format, type, values); -} - -static void APIENTRY InitGetMinmaxParameterfv (GLenum target, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetMinmaxParameterfv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetMinmaxParameterfv = extproc; - - glGetMinmaxParameterfv(target, pname, params); -} - -static void APIENTRY InitGetMinmaxParameteriv (GLenum target, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetMinmaxParameteriv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetMinmaxParameteriv = extproc; - - glGetMinmaxParameteriv(target, pname, params); -} - -static void APIENTRY InitHistogram (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glHistogram"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glHistogram = extproc; - - glHistogram(target, width, internalformat, sink); -} - -static void APIENTRY InitMinmax (GLenum target, GLenum internalformat, GLboolean sink) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMinmax"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMinmax = extproc; - - glMinmax(target, internalformat, sink); -} - -static void APIENTRY InitResetHistogram (GLenum target) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glResetHistogram"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glResetHistogram = extproc; - - glResetHistogram(target); -} - -static void APIENTRY InitResetMinmax (GLenum target) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glResetMinmax"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glResetMinmax = extproc; - - glResetMinmax(target); -} - -static void APIENTRY InitTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexImage3D"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexImage3D = extproc; - - glTexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels); -} - -static void APIENTRY InitTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexSubImage3D"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexSubImage3D = extproc; - - glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); -} - -static void APIENTRY InitCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCopyTexSubImage3D"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCopyTexSubImage3D = extproc; - - glCopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height); -} - -static void APIENTRY InitActiveTexture (GLenum texture) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glActiveTexture"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glActiveTexture = extproc; - - glActiveTexture(texture); -} - -static void APIENTRY InitClientActiveTexture (GLenum texture) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glClientActiveTexture"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glClientActiveTexture = extproc; - - glClientActiveTexture(texture); -} - -static void APIENTRY InitMultiTexCoord1d (GLenum target, GLdouble s) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord1d"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord1d = extproc; - - glMultiTexCoord1d(target, s); -} - -static void APIENTRY InitMultiTexCoord1dv (GLenum target, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord1dv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord1dv = extproc; - - glMultiTexCoord1dv(target, v); -} - -static void APIENTRY InitMultiTexCoord1f (GLenum target, GLfloat s) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord1f"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord1f = extproc; - - glMultiTexCoord1f(target, s); -} - -static void APIENTRY InitMultiTexCoord1fv (GLenum target, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord1fv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord1fv = extproc; - - glMultiTexCoord1fv(target, v); -} - -static void APIENTRY InitMultiTexCoord1i (GLenum target, GLint s) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord1i"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord1i = extproc; - - glMultiTexCoord1i(target, s); -} - -static void APIENTRY InitMultiTexCoord1iv (GLenum target, const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord1iv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord1iv = extproc; - - glMultiTexCoord1iv(target, v); -} - -static void APIENTRY InitMultiTexCoord1s (GLenum target, GLshort s) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord1s"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord1s = extproc; - - glMultiTexCoord1s(target, s); -} - -static void APIENTRY InitMultiTexCoord1sv (GLenum target, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord1sv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord1sv = extproc; - - glMultiTexCoord1sv(target, v); -} - -static void APIENTRY InitMultiTexCoord2d (GLenum target, GLdouble s, GLdouble t) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord2d"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord2d = extproc; - - glMultiTexCoord2d(target, s, t); -} - -static void APIENTRY InitMultiTexCoord2dv (GLenum target, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord2dv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord2dv = extproc; - - glMultiTexCoord2dv(target, v); -} - -static void APIENTRY InitMultiTexCoord2f (GLenum target, GLfloat s, GLfloat t) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord2f"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord2f = extproc; - - glMultiTexCoord2f(target, s, t); -} - -static void APIENTRY InitMultiTexCoord2fv (GLenum target, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord2fv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord2fv = extproc; - - glMultiTexCoord2fv(target, v); -} - -static void APIENTRY InitMultiTexCoord2i (GLenum target, GLint s, GLint t) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord2i"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord2i = extproc; - - glMultiTexCoord2i(target, s, t); -} - -static void APIENTRY InitMultiTexCoord2iv (GLenum target, const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord2iv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord2iv = extproc; - - glMultiTexCoord2iv(target, v); -} - -static void APIENTRY InitMultiTexCoord2s (GLenum target, GLshort s, GLshort t) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord2s"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord2s = extproc; - - glMultiTexCoord2s(target, s, t); -} - -static void APIENTRY InitMultiTexCoord2sv (GLenum target, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord2sv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord2sv = extproc; - - glMultiTexCoord2sv(target, v); -} - -static void APIENTRY InitMultiTexCoord3d (GLenum target, GLdouble s, GLdouble t, GLdouble r) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord3d"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord3d = extproc; - - glMultiTexCoord3d(target, s, t, r); -} - -static void APIENTRY InitMultiTexCoord3dv (GLenum target, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord3dv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord3dv = extproc; - - glMultiTexCoord3dv(target, v); -} - -static void APIENTRY InitMultiTexCoord3f (GLenum target, GLfloat s, GLfloat t, GLfloat r) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord3f"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord3f = extproc; - - glMultiTexCoord3f(target, s, t, r); -} - -static void APIENTRY InitMultiTexCoord3fv (GLenum target, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord3fv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord3fv = extproc; - - glMultiTexCoord3fv(target, v); -} - -static void APIENTRY InitMultiTexCoord3i (GLenum target, GLint s, GLint t, GLint r) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord3i"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord3i = extproc; - - glMultiTexCoord3i(target, s, t, r); -} - -static void APIENTRY InitMultiTexCoord3iv (GLenum target, const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord3iv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord3iv = extproc; - - glMultiTexCoord3iv(target, v); -} - -static void APIENTRY InitMultiTexCoord3s (GLenum target, GLshort s, GLshort t, GLshort r) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord3s"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord3s = extproc; - - glMultiTexCoord3s(target, s, t, r); -} - -static void APIENTRY InitMultiTexCoord3sv (GLenum target, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord3sv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord3sv = extproc; - - glMultiTexCoord3sv(target, v); -} - -static void APIENTRY InitMultiTexCoord4d (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord4d"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord4d = extproc; - - glMultiTexCoord4d(target, s, t, r, q); -} - -static void APIENTRY InitMultiTexCoord4dv (GLenum target, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord4dv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord4dv = extproc; - - glMultiTexCoord4dv(target, v); -} - -static void APIENTRY InitMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord4f"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord4f = extproc; - - glMultiTexCoord4f(target, s, t, r, q); -} - -static void APIENTRY InitMultiTexCoord4fv (GLenum target, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord4fv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord4fv = extproc; - - glMultiTexCoord4fv(target, v); -} - -static void APIENTRY InitMultiTexCoord4i (GLenum target, GLint s, GLint t, GLint r, GLint q) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord4i"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord4i = extproc; - - glMultiTexCoord4i(target, s, t, r, q); -} - -static void APIENTRY InitMultiTexCoord4iv (GLenum target, const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord4iv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord4iv = extproc; - - glMultiTexCoord4iv(target, v); -} - -static void APIENTRY InitMultiTexCoord4s (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord4s"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord4s = extproc; - - glMultiTexCoord4s(target, s, t, r, q); -} - -static void APIENTRY InitMultiTexCoord4sv (GLenum target, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord4sv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord4sv = extproc; - - glMultiTexCoord4sv(target, v); -} - -static void APIENTRY InitLoadTransposeMatrixf (const GLfloat *m) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glLoadTransposeMatrixf"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glLoadTransposeMatrixf = extproc; - - glLoadTransposeMatrixf(m); -} - -static void APIENTRY InitLoadTransposeMatrixd (const GLdouble *m) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glLoadTransposeMatrixd"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glLoadTransposeMatrixd = extproc; - - glLoadTransposeMatrixd(m); -} - -static void APIENTRY InitMultTransposeMatrixf (const GLfloat *m) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultTransposeMatrixf"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultTransposeMatrixf = extproc; - - glMultTransposeMatrixf(m); -} - -static void APIENTRY InitMultTransposeMatrixd (const GLdouble *m) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultTransposeMatrixd"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultTransposeMatrixd = extproc; - - glMultTransposeMatrixd(m); -} - -static void APIENTRY InitSampleCoverage (GLclampf value, GLboolean invert) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSampleCoverage"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSampleCoverage = extproc; - - glSampleCoverage(value, invert); -} - -static void APIENTRY InitCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCompressedTexImage3D"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCompressedTexImage3D = extproc; - - glCompressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, data); -} - -static void APIENTRY InitCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCompressedTexImage2D"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCompressedTexImage2D = extproc; - - glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); -} - -static void APIENTRY InitCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCompressedTexImage1D"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCompressedTexImage1D = extproc; - - glCompressedTexImage1D(target, level, internalformat, width, border, imageSize, data); -} - -static void APIENTRY InitCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCompressedTexSubImage3D"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCompressedTexSubImage3D = extproc; - - glCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); -} - -static void APIENTRY InitCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCompressedTexSubImage2D"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCompressedTexSubImage2D = extproc; - - glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); -} - -static void APIENTRY InitCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCompressedTexSubImage1D"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCompressedTexSubImage1D = extproc; - - glCompressedTexSubImage1D(target, level, xoffset, width, format, imageSize, data); -} - -static void APIENTRY InitGetCompressedTexImage (GLenum target, GLint level, GLvoid *img) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetCompressedTexImage"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetCompressedTexImage = extproc; - - glGetCompressedTexImage(target, level, img); -} - -static void APIENTRY InitBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBlendFuncSeparate"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBlendFuncSeparate = extproc; - - glBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); -} - -static void APIENTRY InitFogCoordf (GLfloat coord) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFogCoordf"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFogCoordf = extproc; - - glFogCoordf(coord); -} - -static void APIENTRY InitFogCoordfv (const GLfloat *coord) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFogCoordfv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFogCoordfv = extproc; - - glFogCoordfv(coord); -} - -static void APIENTRY InitFogCoordd (GLdouble coord) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFogCoordd"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFogCoordd = extproc; - - glFogCoordd(coord); -} - -static void APIENTRY InitFogCoorddv (const GLdouble *coord) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFogCoorddv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFogCoorddv = extproc; - - glFogCoorddv(coord); -} - -static void APIENTRY InitFogCoordPointer (GLenum type, GLsizei stride, const GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFogCoordPointer"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFogCoordPointer = extproc; - - glFogCoordPointer(type, stride, pointer); -} - -static void APIENTRY InitMultiDrawArrays (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiDrawArrays"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiDrawArrays = extproc; - - glMultiDrawArrays(mode, first, count, primcount); -} - -static void APIENTRY InitMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiDrawElements"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiDrawElements = extproc; - - glMultiDrawElements(mode, count, type, indices, primcount); -} - -static void APIENTRY InitPointParameterf (GLenum pname, GLfloat param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPointParameterf"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPointParameterf = extproc; - - glPointParameterf(pname, param); -} - -static void APIENTRY InitPointParameterfv (GLenum pname, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPointParameterfv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPointParameterfv = extproc; - - glPointParameterfv(pname, params); -} - -static void APIENTRY InitPointParameteri (GLenum pname, GLint param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPointParameteri"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPointParameteri = extproc; - - glPointParameteri(pname, param); -} - -static void APIENTRY InitPointParameteriv (GLenum pname, const GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPointParameteriv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPointParameteriv = extproc; - - glPointParameteriv(pname, params); -} - -static void APIENTRY InitSecondaryColor3b (GLbyte red, GLbyte green, GLbyte blue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3b"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3b = extproc; - - glSecondaryColor3b(red, green, blue); -} - -static void APIENTRY InitSecondaryColor3bv (const GLbyte *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3bv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3bv = extproc; - - glSecondaryColor3bv(v); -} - -static void APIENTRY InitSecondaryColor3d (GLdouble red, GLdouble green, GLdouble blue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3d"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3d = extproc; - - glSecondaryColor3d(red, green, blue); -} - -static void APIENTRY InitSecondaryColor3dv (const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3dv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3dv = extproc; - - glSecondaryColor3dv(v); -} - -static void APIENTRY InitSecondaryColor3f (GLfloat red, GLfloat green, GLfloat blue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3f"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3f = extproc; - - glSecondaryColor3f(red, green, blue); -} - -static void APIENTRY InitSecondaryColor3fv (const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3fv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3fv = extproc; - - glSecondaryColor3fv(v); -} - -static void APIENTRY InitSecondaryColor3i (GLint red, GLint green, GLint blue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3i"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3i = extproc; - - glSecondaryColor3i(red, green, blue); -} - -static void APIENTRY InitSecondaryColor3iv (const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3iv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3iv = extproc; - - glSecondaryColor3iv(v); -} - -static void APIENTRY InitSecondaryColor3s (GLshort red, GLshort green, GLshort blue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3s"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3s = extproc; - - glSecondaryColor3s(red, green, blue); -} - -static void APIENTRY InitSecondaryColor3sv (const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3sv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3sv = extproc; - - glSecondaryColor3sv(v); -} - -static void APIENTRY InitSecondaryColor3ub (GLubyte red, GLubyte green, GLubyte blue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3ub"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3ub = extproc; - - glSecondaryColor3ub(red, green, blue); -} - -static void APIENTRY InitSecondaryColor3ubv (const GLubyte *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3ubv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3ubv = extproc; - - glSecondaryColor3ubv(v); -} - -static void APIENTRY InitSecondaryColor3ui (GLuint red, GLuint green, GLuint blue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3ui"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3ui = extproc; - - glSecondaryColor3ui(red, green, blue); -} - -static void APIENTRY InitSecondaryColor3uiv (const GLuint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3uiv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3uiv = extproc; - - glSecondaryColor3uiv(v); -} - -static void APIENTRY InitSecondaryColor3us (GLushort red, GLushort green, GLushort blue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3us"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3us = extproc; - - glSecondaryColor3us(red, green, blue); -} - -static void APIENTRY InitSecondaryColor3usv (const GLushort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3usv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3usv = extproc; - - glSecondaryColor3usv(v); -} - -static void APIENTRY InitSecondaryColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColorPointer"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColorPointer = extproc; - - glSecondaryColorPointer(size, type, stride, pointer); -} - -static void APIENTRY InitWindowPos2d (GLdouble x, GLdouble y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2d"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2d = extproc; - - glWindowPos2d(x, y); -} - -static void APIENTRY InitWindowPos2dv (const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2dv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2dv = extproc; - - glWindowPos2dv(v); -} - -static void APIENTRY InitWindowPos2f (GLfloat x, GLfloat y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2f"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2f = extproc; - - glWindowPos2f(x, y); -} - -static void APIENTRY InitWindowPos2fv (const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2fv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2fv = extproc; - - glWindowPos2fv(v); -} - -static void APIENTRY InitWindowPos2i (GLint x, GLint y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2i"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2i = extproc; - - glWindowPos2i(x, y); -} - -static void APIENTRY InitWindowPos2iv (const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2iv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2iv = extproc; - - glWindowPos2iv(v); -} - -static void APIENTRY InitWindowPos2s (GLshort x, GLshort y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2s"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2s = extproc; - - glWindowPos2s(x, y); -} - -static void APIENTRY InitWindowPos2sv (const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2sv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2sv = extproc; - - glWindowPos2sv(v); -} - -static void APIENTRY InitWindowPos3d (GLdouble x, GLdouble y, GLdouble z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3d"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3d = extproc; - - glWindowPos3d(x, y, z); -} - -static void APIENTRY InitWindowPos3dv (const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3dv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3dv = extproc; - - glWindowPos3dv(v); -} - -static void APIENTRY InitWindowPos3f (GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3f"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3f = extproc; - - glWindowPos3f(x, y, z); -} - -static void APIENTRY InitWindowPos3fv (const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3fv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3fv = extproc; - - glWindowPos3fv(v); -} - -static void APIENTRY InitWindowPos3i (GLint x, GLint y, GLint z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3i"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3i = extproc; - - glWindowPos3i(x, y, z); -} - -static void APIENTRY InitWindowPos3iv (const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3iv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3iv = extproc; - - glWindowPos3iv(v); -} - -static void APIENTRY InitWindowPos3s (GLshort x, GLshort y, GLshort z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3s"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3s = extproc; - - glWindowPos3s(x, y, z); -} - -static void APIENTRY InitWindowPos3sv (const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3sv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3sv = extproc; - - glWindowPos3sv(v); -} - -static void APIENTRY InitGenQueries (GLsizei n, GLuint *ids) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGenQueries"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGenQueries = extproc; - - glGenQueries(n, ids); -} - -static void APIENTRY InitDeleteQueries (GLsizei n, const GLuint *ids) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDeleteQueries"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDeleteQueries = extproc; - - glDeleteQueries(n, ids); -} - -static GLboolean APIENTRY InitIsQuery (GLuint id) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glIsQuery"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glIsQuery = extproc; - - return glIsQuery(id); -} - -static void APIENTRY InitBeginQuery (GLenum target, GLuint id) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBeginQuery"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBeginQuery = extproc; - - glBeginQuery(target, id); -} - -static void APIENTRY InitEndQuery (GLenum target) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glEndQuery"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glEndQuery = extproc; - - glEndQuery(target); -} - -static void APIENTRY InitGetQueryiv (GLenum target, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetQueryiv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetQueryiv = extproc; - - glGetQueryiv(target, pname, params); -} - -static void APIENTRY InitGetQueryObjectiv (GLuint id, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetQueryObjectiv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetQueryObjectiv = extproc; - - glGetQueryObjectiv(id, pname, params); -} - -static void APIENTRY InitGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetQueryObjectuiv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetQueryObjectuiv = extproc; - - glGetQueryObjectuiv(id, pname, params); -} - -static void APIENTRY InitBindBuffer (GLenum target, GLuint buffer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBindBuffer"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBindBuffer = extproc; - - glBindBuffer(target, buffer); -} - -static void APIENTRY InitDeleteBuffers (GLsizei n, const GLuint *buffers) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDeleteBuffers"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDeleteBuffers = extproc; - - glDeleteBuffers(n, buffers); -} - -static void APIENTRY InitGenBuffers (GLsizei n, GLuint *buffers) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGenBuffers"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGenBuffers = extproc; - - glGenBuffers(n, buffers); -} - -static GLboolean APIENTRY InitIsBuffer (GLuint buffer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glIsBuffer"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glIsBuffer = extproc; - - return glIsBuffer(buffer); -} - -static void APIENTRY InitBufferData (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBufferData"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBufferData = extproc; - - glBufferData(target, size, data, usage); -} - -static void APIENTRY InitBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBufferSubData"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBufferSubData = extproc; - - glBufferSubData(target, offset, size, data); -} - -static void APIENTRY InitGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetBufferSubData"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetBufferSubData = extproc; - - glGetBufferSubData(target, offset, size, data); -} - -static GLvoid* APIENTRY InitMapBuffer (GLenum target, GLenum access) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMapBuffer"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glMapBuffer = extproc; - - return glMapBuffer(target, access); -} - -static GLboolean APIENTRY InitUnmapBuffer (GLenum target) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUnmapBuffer"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glUnmapBuffer = extproc; - - return glUnmapBuffer(target); -} - -static void APIENTRY InitGetBufferParameteriv (GLenum target, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetBufferParameteriv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetBufferParameteriv = extproc; - - glGetBufferParameteriv(target, pname, params); -} - -static void APIENTRY InitGetBufferPointerv (GLenum target, GLenum pname, GLvoid* *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetBufferPointerv"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetBufferPointerv = extproc; - - glGetBufferPointerv(target, pname, params); -} - -static void APIENTRY InitActiveTextureARB (GLenum texture) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glActiveTextureARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glActiveTextureARB = extproc; - - glActiveTextureARB(texture); -} - -static void APIENTRY InitClientActiveTextureARB (GLenum texture) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glClientActiveTextureARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glClientActiveTextureARB = extproc; - - glClientActiveTextureARB(texture); -} - -static void APIENTRY InitMultiTexCoord1dARB (GLenum target, GLdouble s) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord1dARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord1dARB = extproc; - - glMultiTexCoord1dARB(target, s); -} - -static void APIENTRY InitMultiTexCoord1dvARB (GLenum target, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord1dvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord1dvARB = extproc; - - glMultiTexCoord1dvARB(target, v); -} - -static void APIENTRY InitMultiTexCoord1fARB (GLenum target, GLfloat s) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord1fARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord1fARB = extproc; - - glMultiTexCoord1fARB(target, s); -} - -static void APIENTRY InitMultiTexCoord1fvARB (GLenum target, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord1fvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord1fvARB = extproc; - - glMultiTexCoord1fvARB(target, v); -} - -static void APIENTRY InitMultiTexCoord1iARB (GLenum target, GLint s) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord1iARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord1iARB = extproc; - - glMultiTexCoord1iARB(target, s); -} - -static void APIENTRY InitMultiTexCoord1ivARB (GLenum target, const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord1ivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord1ivARB = extproc; - - glMultiTexCoord1ivARB(target, v); -} - -static void APIENTRY InitMultiTexCoord1sARB (GLenum target, GLshort s) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord1sARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord1sARB = extproc; - - glMultiTexCoord1sARB(target, s); -} - -static void APIENTRY InitMultiTexCoord1svARB (GLenum target, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord1svARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord1svARB = extproc; - - glMultiTexCoord1svARB(target, v); -} - -static void APIENTRY InitMultiTexCoord2dARB (GLenum target, GLdouble s, GLdouble t) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord2dARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord2dARB = extproc; - - glMultiTexCoord2dARB(target, s, t); -} - -static void APIENTRY InitMultiTexCoord2dvARB (GLenum target, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord2dvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord2dvARB = extproc; - - glMultiTexCoord2dvARB(target, v); -} - -static void APIENTRY InitMultiTexCoord2fARB (GLenum target, GLfloat s, GLfloat t) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord2fARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord2fARB = extproc; - - glMultiTexCoord2fARB(target, s, t); -} - -static void APIENTRY InitMultiTexCoord2fvARB (GLenum target, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord2fvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord2fvARB = extproc; - - glMultiTexCoord2fvARB(target, v); -} - -static void APIENTRY InitMultiTexCoord2iARB (GLenum target, GLint s, GLint t) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord2iARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord2iARB = extproc; - - glMultiTexCoord2iARB(target, s, t); -} - -static void APIENTRY InitMultiTexCoord2ivARB (GLenum target, const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord2ivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord2ivARB = extproc; - - glMultiTexCoord2ivARB(target, v); -} - -static void APIENTRY InitMultiTexCoord2sARB (GLenum target, GLshort s, GLshort t) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord2sARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord2sARB = extproc; - - glMultiTexCoord2sARB(target, s, t); -} - -static void APIENTRY InitMultiTexCoord2svARB (GLenum target, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord2svARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord2svARB = extproc; - - glMultiTexCoord2svARB(target, v); -} - -static void APIENTRY InitMultiTexCoord3dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord3dARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord3dARB = extproc; - - glMultiTexCoord3dARB(target, s, t, r); -} - -static void APIENTRY InitMultiTexCoord3dvARB (GLenum target, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord3dvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord3dvARB = extproc; - - glMultiTexCoord3dvARB(target, v); -} - -static void APIENTRY InitMultiTexCoord3fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord3fARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord3fARB = extproc; - - glMultiTexCoord3fARB(target, s, t, r); -} - -static void APIENTRY InitMultiTexCoord3fvARB (GLenum target, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord3fvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord3fvARB = extproc; - - glMultiTexCoord3fvARB(target, v); -} - -static void APIENTRY InitMultiTexCoord3iARB (GLenum target, GLint s, GLint t, GLint r) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord3iARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord3iARB = extproc; - - glMultiTexCoord3iARB(target, s, t, r); -} - -static void APIENTRY InitMultiTexCoord3ivARB (GLenum target, const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord3ivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord3ivARB = extproc; - - glMultiTexCoord3ivARB(target, v); -} - -static void APIENTRY InitMultiTexCoord3sARB (GLenum target, GLshort s, GLshort t, GLshort r) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord3sARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord3sARB = extproc; - - glMultiTexCoord3sARB(target, s, t, r); -} - -static void APIENTRY InitMultiTexCoord3svARB (GLenum target, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord3svARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord3svARB = extproc; - - glMultiTexCoord3svARB(target, v); -} - -static void APIENTRY InitMultiTexCoord4dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord4dARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord4dARB = extproc; - - glMultiTexCoord4dARB(target, s, t, r, q); -} - -static void APIENTRY InitMultiTexCoord4dvARB (GLenum target, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord4dvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord4dvARB = extproc; - - glMultiTexCoord4dvARB(target, v); -} - -static void APIENTRY InitMultiTexCoord4fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord4fARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord4fARB = extproc; - - glMultiTexCoord4fARB(target, s, t, r, q); -} - -static void APIENTRY InitMultiTexCoord4fvARB (GLenum target, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord4fvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord4fvARB = extproc; - - glMultiTexCoord4fvARB(target, v); -} - -static void APIENTRY InitMultiTexCoord4iARB (GLenum target, GLint s, GLint t, GLint r, GLint q) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord4iARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord4iARB = extproc; - - glMultiTexCoord4iARB(target, s, t, r, q); -} - -static void APIENTRY InitMultiTexCoord4ivARB (GLenum target, const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord4ivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord4ivARB = extproc; - - glMultiTexCoord4ivARB(target, v); -} - -static void APIENTRY InitMultiTexCoord4sARB (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord4sARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord4sARB = extproc; - - glMultiTexCoord4sARB(target, s, t, r, q); -} - -static void APIENTRY InitMultiTexCoord4svARB (GLenum target, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord4svARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord4svARB = extproc; - - glMultiTexCoord4svARB(target, v); -} - -static void APIENTRY InitLoadTransposeMatrixfARB (const GLfloat *m) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glLoadTransposeMatrixfARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glLoadTransposeMatrixfARB = extproc; - - glLoadTransposeMatrixfARB(m); -} - -static void APIENTRY InitLoadTransposeMatrixdARB (const GLdouble *m) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glLoadTransposeMatrixdARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glLoadTransposeMatrixdARB = extproc; - - glLoadTransposeMatrixdARB(m); -} - -static void APIENTRY InitMultTransposeMatrixfARB (const GLfloat *m) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultTransposeMatrixfARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultTransposeMatrixfARB = extproc; - - glMultTransposeMatrixfARB(m); -} - -static void APIENTRY InitMultTransposeMatrixdARB (const GLdouble *m) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultTransposeMatrixdARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultTransposeMatrixdARB = extproc; - - glMultTransposeMatrixdARB(m); -} - -static void APIENTRY InitSampleCoverageARB (GLclampf value, GLboolean invert) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSampleCoverageARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSampleCoverageARB = extproc; - - glSampleCoverageARB(value, invert); -} - -static void APIENTRY InitCompressedTexImage3DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCompressedTexImage3DARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCompressedTexImage3DARB = extproc; - - glCompressedTexImage3DARB(target, level, internalformat, width, height, depth, border, imageSize, data); -} - -static void APIENTRY InitCompressedTexImage2DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCompressedTexImage2DARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCompressedTexImage2DARB = extproc; - - glCompressedTexImage2DARB(target, level, internalformat, width, height, border, imageSize, data); -} - -static void APIENTRY InitCompressedTexImage1DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCompressedTexImage1DARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCompressedTexImage1DARB = extproc; - - glCompressedTexImage1DARB(target, level, internalformat, width, border, imageSize, data); -} - -static void APIENTRY InitCompressedTexSubImage3DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCompressedTexSubImage3DARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCompressedTexSubImage3DARB = extproc; - - glCompressedTexSubImage3DARB(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); -} - -static void APIENTRY InitCompressedTexSubImage2DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCompressedTexSubImage2DARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCompressedTexSubImage2DARB = extproc; - - glCompressedTexSubImage2DARB(target, level, xoffset, yoffset, width, height, format, imageSize, data); -} - -static void APIENTRY InitCompressedTexSubImage1DARB (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCompressedTexSubImage1DARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCompressedTexSubImage1DARB = extproc; - - glCompressedTexSubImage1DARB(target, level, xoffset, width, format, imageSize, data); -} - -static void APIENTRY InitGetCompressedTexImageARB (GLenum target, GLint level, GLvoid *img) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetCompressedTexImageARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetCompressedTexImageARB = extproc; - - glGetCompressedTexImageARB(target, level, img); -} - -static void APIENTRY InitPointParameterfARB (GLenum pname, GLfloat param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPointParameterfARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPointParameterfARB = extproc; - - glPointParameterfARB(pname, param); -} - -static void APIENTRY InitPointParameterfvARB (GLenum pname, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPointParameterfvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPointParameterfvARB = extproc; - - glPointParameterfvARB(pname, params); -} - -static void APIENTRY InitWeightbvARB (GLint size, const GLbyte *weights) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWeightbvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWeightbvARB = extproc; - - glWeightbvARB(size, weights); -} - -static void APIENTRY InitWeightsvARB (GLint size, const GLshort *weights) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWeightsvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWeightsvARB = extproc; - - glWeightsvARB(size, weights); -} - -static void APIENTRY InitWeightivARB (GLint size, const GLint *weights) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWeightivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWeightivARB = extproc; - - glWeightivARB(size, weights); -} - -static void APIENTRY InitWeightfvARB (GLint size, const GLfloat *weights) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWeightfvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWeightfvARB = extproc; - - glWeightfvARB(size, weights); -} - -static void APIENTRY InitWeightdvARB (GLint size, const GLdouble *weights) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWeightdvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWeightdvARB = extproc; - - glWeightdvARB(size, weights); -} - -static void APIENTRY InitWeightubvARB (GLint size, const GLubyte *weights) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWeightubvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWeightubvARB = extproc; - - glWeightubvARB(size, weights); -} - -static void APIENTRY InitWeightusvARB (GLint size, const GLushort *weights) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWeightusvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWeightusvARB = extproc; - - glWeightusvARB(size, weights); -} - -static void APIENTRY InitWeightuivARB (GLint size, const GLuint *weights) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWeightuivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWeightuivARB = extproc; - - glWeightuivARB(size, weights); -} - -static void APIENTRY InitWeightPointerARB (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWeightPointerARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWeightPointerARB = extproc; - - glWeightPointerARB(size, type, stride, pointer); -} - -static void APIENTRY InitVertexBlendARB (GLint count) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexBlendARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexBlendARB = extproc; - - glVertexBlendARB(count); -} - -static void APIENTRY InitCurrentPaletteMatrixARB (GLint index) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCurrentPaletteMatrixARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCurrentPaletteMatrixARB = extproc; - - glCurrentPaletteMatrixARB(index); -} - -static void APIENTRY InitMatrixIndexubvARB (GLint size, const GLubyte *indices) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMatrixIndexubvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMatrixIndexubvARB = extproc; - - glMatrixIndexubvARB(size, indices); -} - -static void APIENTRY InitMatrixIndexusvARB (GLint size, const GLushort *indices) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMatrixIndexusvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMatrixIndexusvARB = extproc; - - glMatrixIndexusvARB(size, indices); -} - -static void APIENTRY InitMatrixIndexuivARB (GLint size, const GLuint *indices) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMatrixIndexuivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMatrixIndexuivARB = extproc; - - glMatrixIndexuivARB(size, indices); -} - -static void APIENTRY InitMatrixIndexPointerARB (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMatrixIndexPointerARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMatrixIndexPointerARB = extproc; - - glMatrixIndexPointerARB(size, type, stride, pointer); -} - -static void APIENTRY InitWindowPos2dARB (GLdouble x, GLdouble y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2dARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2dARB = extproc; - - glWindowPos2dARB(x, y); -} - -static void APIENTRY InitWindowPos2dvARB (const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2dvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2dvARB = extproc; - - glWindowPos2dvARB(v); -} - -static void APIENTRY InitWindowPos2fARB (GLfloat x, GLfloat y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2fARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2fARB = extproc; - - glWindowPos2fARB(x, y); -} - -static void APIENTRY InitWindowPos2fvARB (const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2fvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2fvARB = extproc; - - glWindowPos2fvARB(v); -} - -static void APIENTRY InitWindowPos2iARB (GLint x, GLint y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2iARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2iARB = extproc; - - glWindowPos2iARB(x, y); -} - -static void APIENTRY InitWindowPos2ivARB (const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2ivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2ivARB = extproc; - - glWindowPos2ivARB(v); -} - -static void APIENTRY InitWindowPos2sARB (GLshort x, GLshort y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2sARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2sARB = extproc; - - glWindowPos2sARB(x, y); -} - -static void APIENTRY InitWindowPos2svARB (const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2svARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2svARB = extproc; - - glWindowPos2svARB(v); -} - -static void APIENTRY InitWindowPos3dARB (GLdouble x, GLdouble y, GLdouble z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3dARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3dARB = extproc; - - glWindowPos3dARB(x, y, z); -} - -static void APIENTRY InitWindowPos3dvARB (const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3dvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3dvARB = extproc; - - glWindowPos3dvARB(v); -} - -static void APIENTRY InitWindowPos3fARB (GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3fARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3fARB = extproc; - - glWindowPos3fARB(x, y, z); -} - -static void APIENTRY InitWindowPos3fvARB (const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3fvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3fvARB = extproc; - - glWindowPos3fvARB(v); -} - -static void APIENTRY InitWindowPos3iARB (GLint x, GLint y, GLint z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3iARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3iARB = extproc; - - glWindowPos3iARB(x, y, z); -} - -static void APIENTRY InitWindowPos3ivARB (const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3ivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3ivARB = extproc; - - glWindowPos3ivARB(v); -} - -static void APIENTRY InitWindowPos3sARB (GLshort x, GLshort y, GLshort z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3sARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3sARB = extproc; - - glWindowPos3sARB(x, y, z); -} - -static void APIENTRY InitWindowPos3svARB (const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3svARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3svARB = extproc; - - glWindowPos3svARB(v); -} - -static void APIENTRY InitVertexAttrib1dARB (GLuint index, GLdouble x) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib1dARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib1dARB = extproc; - - glVertexAttrib1dARB(index, x); -} - -static void APIENTRY InitVertexAttrib1dvARB (GLuint index, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib1dvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib1dvARB = extproc; - - glVertexAttrib1dvARB(index, v); -} - -static void APIENTRY InitVertexAttrib1fARB (GLuint index, GLfloat x) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib1fARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib1fARB = extproc; - - glVertexAttrib1fARB(index, x); -} - -static void APIENTRY InitVertexAttrib1fvARB (GLuint index, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib1fvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib1fvARB = extproc; - - glVertexAttrib1fvARB(index, v); -} - -static void APIENTRY InitVertexAttrib1sARB (GLuint index, GLshort x) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib1sARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib1sARB = extproc; - - glVertexAttrib1sARB(index, x); -} - -static void APIENTRY InitVertexAttrib1svARB (GLuint index, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib1svARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib1svARB = extproc; - - glVertexAttrib1svARB(index, v); -} - -static void APIENTRY InitVertexAttrib2dARB (GLuint index, GLdouble x, GLdouble y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib2dARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib2dARB = extproc; - - glVertexAttrib2dARB(index, x, y); -} - -static void APIENTRY InitVertexAttrib2dvARB (GLuint index, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib2dvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib2dvARB = extproc; - - glVertexAttrib2dvARB(index, v); -} - -static void APIENTRY InitVertexAttrib2fARB (GLuint index, GLfloat x, GLfloat y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib2fARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib2fARB = extproc; - - glVertexAttrib2fARB(index, x, y); -} - -static void APIENTRY InitVertexAttrib2fvARB (GLuint index, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib2fvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib2fvARB = extproc; - - glVertexAttrib2fvARB(index, v); -} - -static void APIENTRY InitVertexAttrib2sARB (GLuint index, GLshort x, GLshort y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib2sARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib2sARB = extproc; - - glVertexAttrib2sARB(index, x, y); -} - -static void APIENTRY InitVertexAttrib2svARB (GLuint index, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib2svARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib2svARB = extproc; - - glVertexAttrib2svARB(index, v); -} - -static void APIENTRY InitVertexAttrib3dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib3dARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib3dARB = extproc; - - glVertexAttrib3dARB(index, x, y, z); -} - -static void APIENTRY InitVertexAttrib3dvARB (GLuint index, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib3dvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib3dvARB = extproc; - - glVertexAttrib3dvARB(index, v); -} - -static void APIENTRY InitVertexAttrib3fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib3fARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib3fARB = extproc; - - glVertexAttrib3fARB(index, x, y, z); -} - -static void APIENTRY InitVertexAttrib3fvARB (GLuint index, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib3fvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib3fvARB = extproc; - - glVertexAttrib3fvARB(index, v); -} - -static void APIENTRY InitVertexAttrib3sARB (GLuint index, GLshort x, GLshort y, GLshort z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib3sARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib3sARB = extproc; - - glVertexAttrib3sARB(index, x, y, z); -} - -static void APIENTRY InitVertexAttrib3svARB (GLuint index, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib3svARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib3svARB = extproc; - - glVertexAttrib3svARB(index, v); -} - -static void APIENTRY InitVertexAttrib4NbvARB (GLuint index, const GLbyte *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4NbvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4NbvARB = extproc; - - glVertexAttrib4NbvARB(index, v); -} - -static void APIENTRY InitVertexAttrib4NivARB (GLuint index, const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4NivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4NivARB = extproc; - - glVertexAttrib4NivARB(index, v); -} - -static void APIENTRY InitVertexAttrib4NsvARB (GLuint index, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4NsvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4NsvARB = extproc; - - glVertexAttrib4NsvARB(index, v); -} - -static void APIENTRY InitVertexAttrib4NubARB (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4NubARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4NubARB = extproc; - - glVertexAttrib4NubARB(index, x, y, z, w); -} - -static void APIENTRY InitVertexAttrib4NubvARB (GLuint index, const GLubyte *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4NubvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4NubvARB = extproc; - - glVertexAttrib4NubvARB(index, v); -} - -static void APIENTRY InitVertexAttrib4NuivARB (GLuint index, const GLuint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4NuivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4NuivARB = extproc; - - glVertexAttrib4NuivARB(index, v); -} - -static void APIENTRY InitVertexAttrib4NusvARB (GLuint index, const GLushort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4NusvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4NusvARB = extproc; - - glVertexAttrib4NusvARB(index, v); -} - -static void APIENTRY InitVertexAttrib4bvARB (GLuint index, const GLbyte *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4bvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4bvARB = extproc; - - glVertexAttrib4bvARB(index, v); -} - -static void APIENTRY InitVertexAttrib4dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4dARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4dARB = extproc; - - glVertexAttrib4dARB(index, x, y, z, w); -} - -static void APIENTRY InitVertexAttrib4dvARB (GLuint index, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4dvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4dvARB = extproc; - - glVertexAttrib4dvARB(index, v); -} - -static void APIENTRY InitVertexAttrib4fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4fARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4fARB = extproc; - - glVertexAttrib4fARB(index, x, y, z, w); -} - -static void APIENTRY InitVertexAttrib4fvARB (GLuint index, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4fvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4fvARB = extproc; - - glVertexAttrib4fvARB(index, v); -} - -static void APIENTRY InitVertexAttrib4ivARB (GLuint index, const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4ivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4ivARB = extproc; - - glVertexAttrib4ivARB(index, v); -} - -static void APIENTRY InitVertexAttrib4sARB (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4sARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4sARB = extproc; - - glVertexAttrib4sARB(index, x, y, z, w); -} - -static void APIENTRY InitVertexAttrib4svARB (GLuint index, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4svARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4svARB = extproc; - - glVertexAttrib4svARB(index, v); -} - -static void APIENTRY InitVertexAttrib4ubvARB (GLuint index, const GLubyte *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4ubvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4ubvARB = extproc; - - glVertexAttrib4ubvARB(index, v); -} - -static void APIENTRY InitVertexAttrib4uivARB (GLuint index, const GLuint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4uivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4uivARB = extproc; - - glVertexAttrib4uivARB(index, v); -} - -static void APIENTRY InitVertexAttrib4usvARB (GLuint index, const GLushort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4usvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4usvARB = extproc; - - glVertexAttrib4usvARB(index, v); -} - -static void APIENTRY InitVertexAttribPointerARB (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribPointerARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribPointerARB = extproc; - - glVertexAttribPointerARB(index, size, type, normalized, stride, pointer); -} - -static void APIENTRY InitEnableVertexAttribArrayARB (GLuint index) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glEnableVertexAttribArrayARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glEnableVertexAttribArrayARB = extproc; - - glEnableVertexAttribArrayARB(index); -} - -static void APIENTRY InitDisableVertexAttribArrayARB (GLuint index) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDisableVertexAttribArrayARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDisableVertexAttribArrayARB = extproc; - - glDisableVertexAttribArrayARB(index); -} - -static void APIENTRY InitProgramStringARB (GLenum target, GLenum format, GLsizei len, const GLvoid *string) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glProgramStringARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glProgramStringARB = extproc; - - glProgramStringARB(target, format, len, string); -} - -static void APIENTRY InitBindProgramARB (GLenum target, GLuint program) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBindProgramARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBindProgramARB = extproc; - - glBindProgramARB(target, program); -} - -static void APIENTRY InitDeleteProgramsARB (GLsizei n, const GLuint *programs) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDeleteProgramsARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDeleteProgramsARB = extproc; - - glDeleteProgramsARB(n, programs); -} - -static void APIENTRY InitGenProgramsARB (GLsizei n, GLuint *programs) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGenProgramsARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGenProgramsARB = extproc; - - glGenProgramsARB(n, programs); -} - -static void APIENTRY InitProgramEnvParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glProgramEnvParameter4dARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glProgramEnvParameter4dARB = extproc; - - glProgramEnvParameter4dARB(target, index, x, y, z, w); -} - -static void APIENTRY InitProgramEnvParameter4dvARB (GLenum target, GLuint index, const GLdouble *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glProgramEnvParameter4dvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glProgramEnvParameter4dvARB = extproc; - - glProgramEnvParameter4dvARB(target, index, params); -} - -static void APIENTRY InitProgramEnvParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glProgramEnvParameter4fARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glProgramEnvParameter4fARB = extproc; - - glProgramEnvParameter4fARB(target, index, x, y, z, w); -} - -static void APIENTRY InitProgramEnvParameter4fvARB (GLenum target, GLuint index, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glProgramEnvParameter4fvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glProgramEnvParameter4fvARB = extproc; - - glProgramEnvParameter4fvARB(target, index, params); -} - -static void APIENTRY InitProgramLocalParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glProgramLocalParameter4dARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glProgramLocalParameter4dARB = extproc; - - glProgramLocalParameter4dARB(target, index, x, y, z, w); -} - -static void APIENTRY InitProgramLocalParameter4dvARB (GLenum target, GLuint index, const GLdouble *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glProgramLocalParameter4dvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glProgramLocalParameter4dvARB = extproc; - - glProgramLocalParameter4dvARB(target, index, params); -} - -static void APIENTRY InitProgramLocalParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glProgramLocalParameter4fARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glProgramLocalParameter4fARB = extproc; - - glProgramLocalParameter4fARB(target, index, x, y, z, w); -} - -static void APIENTRY InitProgramLocalParameter4fvARB (GLenum target, GLuint index, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glProgramLocalParameter4fvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glProgramLocalParameter4fvARB = extproc; - - glProgramLocalParameter4fvARB(target, index, params); -} - -static void APIENTRY InitGetProgramEnvParameterdvARB (GLenum target, GLuint index, GLdouble *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetProgramEnvParameterdvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetProgramEnvParameterdvARB = extproc; - - glGetProgramEnvParameterdvARB(target, index, params); -} - -static void APIENTRY InitGetProgramEnvParameterfvARB (GLenum target, GLuint index, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetProgramEnvParameterfvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetProgramEnvParameterfvARB = extproc; - - glGetProgramEnvParameterfvARB(target, index, params); -} - -static void APIENTRY InitGetProgramLocalParameterdvARB (GLenum target, GLuint index, GLdouble *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetProgramLocalParameterdvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetProgramLocalParameterdvARB = extproc; - - glGetProgramLocalParameterdvARB(target, index, params); -} - -static void APIENTRY InitGetProgramLocalParameterfvARB (GLenum target, GLuint index, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetProgramLocalParameterfvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetProgramLocalParameterfvARB = extproc; - - glGetProgramLocalParameterfvARB(target, index, params); -} - -static void APIENTRY InitGetProgramivARB (GLenum target, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetProgramivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetProgramivARB = extproc; - - glGetProgramivARB(target, pname, params); -} - -static void APIENTRY InitGetProgramStringARB (GLenum target, GLenum pname, GLvoid *string) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetProgramStringARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetProgramStringARB = extproc; - - glGetProgramStringARB(target, pname, string); -} - -static void APIENTRY InitGetVertexAttribdvARB (GLuint index, GLenum pname, GLdouble *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetVertexAttribdvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetVertexAttribdvARB = extproc; - - glGetVertexAttribdvARB(index, pname, params); -} - -static void APIENTRY InitGetVertexAttribfvARB (GLuint index, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetVertexAttribfvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetVertexAttribfvARB = extproc; - - glGetVertexAttribfvARB(index, pname, params); -} - -static void APIENTRY InitGetVertexAttribivARB (GLuint index, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetVertexAttribivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetVertexAttribivARB = extproc; - - glGetVertexAttribivARB(index, pname, params); -} - -static void APIENTRY InitGetVertexAttribPointervARB (GLuint index, GLenum pname, GLvoid* *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetVertexAttribPointervARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetVertexAttribPointervARB = extproc; - - glGetVertexAttribPointervARB(index, pname, pointer); -} - -static GLboolean APIENTRY InitIsProgramARB (GLuint program) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glIsProgramARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glIsProgramARB = extproc; - - return glIsProgramARB(program); -} - -static void APIENTRY InitBindBufferARB (GLenum target, GLuint buffer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBindBufferARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBindBufferARB = extproc; - - glBindBufferARB(target, buffer); -} - -static void APIENTRY InitDeleteBuffersARB (GLsizei n, const GLuint *buffers) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDeleteBuffersARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDeleteBuffersARB = extproc; - - glDeleteBuffersARB(n, buffers); -} - -static void APIENTRY InitGenBuffersARB (GLsizei n, GLuint *buffers) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGenBuffersARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGenBuffersARB = extproc; - - glGenBuffersARB(n, buffers); -} - -static GLboolean APIENTRY InitIsBufferARB (GLuint buffer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glIsBufferARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glIsBufferARB = extproc; - - return glIsBufferARB(buffer); -} - -static void APIENTRY InitBufferDataARB (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBufferDataARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBufferDataARB = extproc; - - glBufferDataARB(target, size, data, usage); -} - -static void APIENTRY InitBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBufferSubDataARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBufferSubDataARB = extproc; - - glBufferSubDataARB(target, offset, size, data); -} - -static void APIENTRY InitGetBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetBufferSubDataARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetBufferSubDataARB = extproc; - - glGetBufferSubDataARB(target, offset, size, data); -} - -static GLvoid* APIENTRY InitMapBufferARB (GLenum target, GLenum access) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMapBufferARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glMapBufferARB = extproc; - - return glMapBufferARB(target, access); -} - -static GLboolean APIENTRY InitUnmapBufferARB (GLenum target) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUnmapBufferARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glUnmapBufferARB = extproc; - - return glUnmapBufferARB(target); -} - -static void APIENTRY InitGetBufferParameterivARB (GLenum target, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetBufferParameterivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetBufferParameterivARB = extproc; - - glGetBufferParameterivARB(target, pname, params); -} - -static void APIENTRY InitGetBufferPointervARB (GLenum target, GLenum pname, GLvoid* *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetBufferPointervARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetBufferPointervARB = extproc; - - glGetBufferPointervARB(target, pname, params); -} - -static void APIENTRY InitGenQueriesARB (GLsizei n, GLuint *ids) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGenQueriesARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGenQueriesARB = extproc; - - glGenQueriesARB(n, ids); -} - -static void APIENTRY InitDeleteQueriesARB (GLsizei n, const GLuint *ids) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDeleteQueriesARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDeleteQueriesARB = extproc; - - glDeleteQueriesARB(n, ids); -} - -static GLboolean APIENTRY InitIsQueryARB (GLuint id) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glIsQueryARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glIsQueryARB = extproc; - - return glIsQueryARB(id); -} - -static void APIENTRY InitBeginQueryARB (GLenum target, GLuint id) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBeginQueryARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBeginQueryARB = extproc; - - glBeginQueryARB(target, id); -} - -static void APIENTRY InitEndQueryARB (GLenum target) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glEndQueryARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glEndQueryARB = extproc; - - glEndQueryARB(target); -} - -static void APIENTRY InitGetQueryivARB (GLenum target, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetQueryivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetQueryivARB = extproc; - - glGetQueryivARB(target, pname, params); -} - -static void APIENTRY InitGetQueryObjectivARB (GLuint id, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetQueryObjectivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetQueryObjectivARB = extproc; - - glGetQueryObjectivARB(id, pname, params); -} - -static void APIENTRY InitGetQueryObjectuivARB (GLuint id, GLenum pname, GLuint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetQueryObjectuivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetQueryObjectuivARB = extproc; - - glGetQueryObjectuivARB(id, pname, params); -} - -static void APIENTRY InitDeleteObjectARB (GLhandleARB obj) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDeleteObjectARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDeleteObjectARB = extproc; - - glDeleteObjectARB(obj); -} - -static GLhandleARB APIENTRY InitGetHandleARB (GLenum pname) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetHandleARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glGetHandleARB = extproc; - - return glGetHandleARB(pname); -} - -static void APIENTRY InitDetachObjectARB (GLhandleARB containerObj, GLhandleARB attachedObj) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDetachObjectARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDetachObjectARB = extproc; - - glDetachObjectARB(containerObj, attachedObj); -} - -static GLhandleARB APIENTRY InitCreateShaderObjectARB (GLenum shaderType) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCreateShaderObjectARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glCreateShaderObjectARB = extproc; - - return glCreateShaderObjectARB(shaderType); -} - -static void APIENTRY InitShaderSourceARB (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glShaderSourceARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glShaderSourceARB = extproc; - - glShaderSourceARB(shaderObj, count, string, length); -} - -static void APIENTRY InitCompileShaderARB (GLhandleARB shaderObj) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCompileShaderARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCompileShaderARB = extproc; - - glCompileShaderARB(shaderObj); -} - -static GLhandleARB APIENTRY InitCreateProgramObjectARB (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCreateProgramObjectARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glCreateProgramObjectARB = extproc; - - return glCreateProgramObjectARB(); -} - -static void APIENTRY InitAttachObjectARB (GLhandleARB containerObj, GLhandleARB obj) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glAttachObjectARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glAttachObjectARB = extproc; - - glAttachObjectARB(containerObj, obj); -} - -static void APIENTRY InitLinkProgramARB (GLhandleARB programObj) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glLinkProgramARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glLinkProgramARB = extproc; - - glLinkProgramARB(programObj); -} - -static void APIENTRY InitUseProgramObjectARB (GLhandleARB programObj) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUseProgramObjectARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUseProgramObjectARB = extproc; - - glUseProgramObjectARB(programObj); -} - -static void APIENTRY InitValidateProgramARB (GLhandleARB programObj) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glValidateProgramARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glValidateProgramARB = extproc; - - glValidateProgramARB(programObj); -} - -static void APIENTRY InitUniform1fARB (GLint location, GLfloat v0) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUniform1fARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUniform1fARB = extproc; - - glUniform1fARB(location, v0); -} - -static void APIENTRY InitUniform2fARB (GLint location, GLfloat v0, GLfloat v1) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUniform2fARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUniform2fARB = extproc; - - glUniform2fARB(location, v0, v1); -} - -static void APIENTRY InitUniform3fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUniform3fARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUniform3fARB = extproc; - - glUniform3fARB(location, v0, v1, v2); -} - -static void APIENTRY InitUniform4fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUniform4fARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUniform4fARB = extproc; - - glUniform4fARB(location, v0, v1, v2, v3); -} - -static void APIENTRY InitUniform1iARB (GLint location, GLint v0) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUniform1iARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUniform1iARB = extproc; - - glUniform1iARB(location, v0); -} - -static void APIENTRY InitUniform2iARB (GLint location, GLint v0, GLint v1) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUniform2iARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUniform2iARB = extproc; - - glUniform2iARB(location, v0, v1); -} - -static void APIENTRY InitUniform3iARB (GLint location, GLint v0, GLint v1, GLint v2) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUniform3iARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUniform3iARB = extproc; - - glUniform3iARB(location, v0, v1, v2); -} - -static void APIENTRY InitUniform4iARB (GLint location, GLint v0, GLint v1, GLint v2, GLint v3) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUniform4iARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUniform4iARB = extproc; - - glUniform4iARB(location, v0, v1, v2, v3); -} - -static void APIENTRY InitUniform1fvARB (GLint location, GLsizei count, const GLfloat *value) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUniform1fvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUniform1fvARB = extproc; - - glUniform1fvARB(location, count, value); -} - -static void APIENTRY InitUniform2fvARB (GLint location, GLsizei count, const GLfloat *value) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUniform2fvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUniform2fvARB = extproc; - - glUniform2fvARB(location, count, value); -} - -static void APIENTRY InitUniform3fvARB (GLint location, GLsizei count, const GLfloat *value) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUniform3fvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUniform3fvARB = extproc; - - glUniform3fvARB(location, count, value); -} - -static void APIENTRY InitUniform4fvARB (GLint location, GLsizei count, const GLfloat *value) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUniform4fvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUniform4fvARB = extproc; - - glUniform4fvARB(location, count, value); -} - -static void APIENTRY InitUniform1ivARB (GLint location, GLsizei count, const GLint *value) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUniform1ivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUniform1ivARB = extproc; - - glUniform1ivARB(location, count, value); -} - -static void APIENTRY InitUniform2ivARB (GLint location, GLsizei count, const GLint *value) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUniform2ivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUniform2ivARB = extproc; - - glUniform2ivARB(location, count, value); -} - -static void APIENTRY InitUniform3ivARB (GLint location, GLsizei count, const GLint *value) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUniform3ivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUniform3ivARB = extproc; - - glUniform3ivARB(location, count, value); -} - -static void APIENTRY InitUniform4ivARB (GLint location, GLsizei count, const GLint *value) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUniform4ivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUniform4ivARB = extproc; - - glUniform4ivARB(location, count, value); -} - -static void APIENTRY InitUniformMatrix2fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUniformMatrix2fvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUniformMatrix2fvARB = extproc; - - glUniformMatrix2fvARB(location, count, transpose, value); -} - -static void APIENTRY InitUniformMatrix3fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUniformMatrix3fvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUniformMatrix3fvARB = extproc; - - glUniformMatrix3fvARB(location, count, transpose, value); -} - -static void APIENTRY InitUniformMatrix4fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUniformMatrix4fvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUniformMatrix4fvARB = extproc; - - glUniformMatrix4fvARB(location, count, transpose, value); -} - -static void APIENTRY InitGetObjectParameterfvARB (GLhandleARB obj, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetObjectParameterfvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetObjectParameterfvARB = extproc; - - glGetObjectParameterfvARB(obj, pname, params); -} - -static void APIENTRY InitGetObjectParameterivARB (GLhandleARB obj, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetObjectParameterivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetObjectParameterivARB = extproc; - - glGetObjectParameterivARB(obj, pname, params); -} - -static void APIENTRY InitGetInfoLogARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetInfoLogARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetInfoLogARB = extproc; - - glGetInfoLogARB(obj, maxLength, length, infoLog); -} - -static void APIENTRY InitGetAttachedObjectsARB (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetAttachedObjectsARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetAttachedObjectsARB = extproc; - - glGetAttachedObjectsARB(containerObj, maxCount, count, obj); -} - -static GLint APIENTRY InitGetUniformLocationARB (GLhandleARB programObj, const GLcharARB *name) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetUniformLocationARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glGetUniformLocationARB = extproc; - - return glGetUniformLocationARB(programObj, name); -} - -static void APIENTRY InitGetActiveUniformARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetActiveUniformARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetActiveUniformARB = extproc; - - glGetActiveUniformARB(programObj, index, maxLength, length, size, type, name); -} - -static void APIENTRY InitGetUniformfvARB (GLhandleARB programObj, GLint location, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetUniformfvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetUniformfvARB = extproc; - - glGetUniformfvARB(programObj, location, params); -} - -static void APIENTRY InitGetUniformivARB (GLhandleARB programObj, GLint location, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetUniformivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetUniformivARB = extproc; - - glGetUniformivARB(programObj, location, params); -} - -static void APIENTRY InitGetShaderSourceARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetShaderSourceARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetShaderSourceARB = extproc; - - glGetShaderSourceARB(obj, maxLength, length, source); -} - -static void APIENTRY InitBindAttribLocationARB (GLhandleARB programObj, GLuint index, const GLcharARB *name) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBindAttribLocationARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBindAttribLocationARB = extproc; - - glBindAttribLocationARB(programObj, index, name); -} - -static void APIENTRY InitGetActiveAttribARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetActiveAttribARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetActiveAttribARB = extproc; - - glGetActiveAttribARB(programObj, index, maxLength, length, size, type, name); -} - -static GLint APIENTRY InitGetAttribLocationARB (GLhandleARB programObj, const GLcharARB *name) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetAttribLocationARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glGetAttribLocationARB = extproc; - - return glGetAttribLocationARB(programObj, name); -} - -static void APIENTRY InitBlendColorEXT (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBlendColorEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBlendColorEXT = extproc; - - glBlendColorEXT(red, green, blue, alpha); -} - -static void APIENTRY InitPolygonOffsetEXT (GLfloat factor, GLfloat bias) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPolygonOffsetEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPolygonOffsetEXT = extproc; - - glPolygonOffsetEXT(factor, bias); -} - -static void APIENTRY InitTexImage3DEXT (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexImage3DEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexImage3DEXT = extproc; - - glTexImage3DEXT(target, level, internalformat, width, height, depth, border, format, type, pixels); -} - -static void APIENTRY InitTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexSubImage3DEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexSubImage3DEXT = extproc; - - glTexSubImage3DEXT(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); -} - -static void APIENTRY InitGetTexFilterFuncSGIS (GLenum target, GLenum filter, GLfloat *weights) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetTexFilterFuncSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetTexFilterFuncSGIS = extproc; - - glGetTexFilterFuncSGIS(target, filter, weights); -} - -static void APIENTRY InitTexFilterFuncSGIS (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexFilterFuncSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexFilterFuncSGIS = extproc; - - glTexFilterFuncSGIS(target, filter, n, weights); -} - -static void APIENTRY InitTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexSubImage1DEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexSubImage1DEXT = extproc; - - glTexSubImage1DEXT(target, level, xoffset, width, format, type, pixels); -} - -static void APIENTRY InitTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexSubImage2DEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexSubImage2DEXT = extproc; - - glTexSubImage2DEXT(target, level, xoffset, yoffset, width, height, format, type, pixels); -} - -static void APIENTRY InitCopyTexImage1DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCopyTexImage1DEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCopyTexImage1DEXT = extproc; - - glCopyTexImage1DEXT(target, level, internalformat, x, y, width, border); -} - -static void APIENTRY InitCopyTexImage2DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCopyTexImage2DEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCopyTexImage2DEXT = extproc; - - glCopyTexImage2DEXT(target, level, internalformat, x, y, width, height, border); -} - -static void APIENTRY InitCopyTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCopyTexSubImage1DEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCopyTexSubImage1DEXT = extproc; - - glCopyTexSubImage1DEXT(target, level, xoffset, x, y, width); -} - -static void APIENTRY InitCopyTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCopyTexSubImage2DEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCopyTexSubImage2DEXT = extproc; - - glCopyTexSubImage2DEXT(target, level, xoffset, yoffset, x, y, width, height); -} - -static void APIENTRY InitCopyTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCopyTexSubImage3DEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCopyTexSubImage3DEXT = extproc; - - glCopyTexSubImage3DEXT(target, level, xoffset, yoffset, zoffset, x, y, width, height); -} - -static void APIENTRY InitGetHistogramEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetHistogramEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetHistogramEXT = extproc; - - glGetHistogramEXT(target, reset, format, type, values); -} - -static void APIENTRY InitGetHistogramParameterfvEXT (GLenum target, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetHistogramParameterfvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetHistogramParameterfvEXT = extproc; - - glGetHistogramParameterfvEXT(target, pname, params); -} - -static void APIENTRY InitGetHistogramParameterivEXT (GLenum target, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetHistogramParameterivEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetHistogramParameterivEXT = extproc; - - glGetHistogramParameterivEXT(target, pname, params); -} - -static void APIENTRY InitGetMinmaxEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetMinmaxEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetMinmaxEXT = extproc; - - glGetMinmaxEXT(target, reset, format, type, values); -} - -static void APIENTRY InitGetMinmaxParameterfvEXT (GLenum target, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetMinmaxParameterfvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetMinmaxParameterfvEXT = extproc; - - glGetMinmaxParameterfvEXT(target, pname, params); -} - -static void APIENTRY InitGetMinmaxParameterivEXT (GLenum target, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetMinmaxParameterivEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetMinmaxParameterivEXT = extproc; - - glGetMinmaxParameterivEXT(target, pname, params); -} - -static void APIENTRY InitHistogramEXT (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glHistogramEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glHistogramEXT = extproc; - - glHistogramEXT(target, width, internalformat, sink); -} - -static void APIENTRY InitMinmaxEXT (GLenum target, GLenum internalformat, GLboolean sink) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMinmaxEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMinmaxEXT = extproc; - - glMinmaxEXT(target, internalformat, sink); -} - -static void APIENTRY InitResetHistogramEXT (GLenum target) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glResetHistogramEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glResetHistogramEXT = extproc; - - glResetHistogramEXT(target); -} - -static void APIENTRY InitResetMinmaxEXT (GLenum target) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glResetMinmaxEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glResetMinmaxEXT = extproc; - - glResetMinmaxEXT(target); -} - -static void APIENTRY InitConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glConvolutionFilter1DEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glConvolutionFilter1DEXT = extproc; - - glConvolutionFilter1DEXT(target, internalformat, width, format, type, image); -} - -static void APIENTRY InitConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glConvolutionFilter2DEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glConvolutionFilter2DEXT = extproc; - - glConvolutionFilter2DEXT(target, internalformat, width, height, format, type, image); -} - -static void APIENTRY InitConvolutionParameterfEXT (GLenum target, GLenum pname, GLfloat params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glConvolutionParameterfEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glConvolutionParameterfEXT = extproc; - - glConvolutionParameterfEXT(target, pname, params); -} - -static void APIENTRY InitConvolutionParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glConvolutionParameterfvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glConvolutionParameterfvEXT = extproc; - - glConvolutionParameterfvEXT(target, pname, params); -} - -static void APIENTRY InitConvolutionParameteriEXT (GLenum target, GLenum pname, GLint params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glConvolutionParameteriEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glConvolutionParameteriEXT = extproc; - - glConvolutionParameteriEXT(target, pname, params); -} - -static void APIENTRY InitConvolutionParameterivEXT (GLenum target, GLenum pname, const GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glConvolutionParameterivEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glConvolutionParameterivEXT = extproc; - - glConvolutionParameterivEXT(target, pname, params); -} - -static void APIENTRY InitCopyConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCopyConvolutionFilter1DEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCopyConvolutionFilter1DEXT = extproc; - - glCopyConvolutionFilter1DEXT(target, internalformat, x, y, width); -} - -static void APIENTRY InitCopyConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCopyConvolutionFilter2DEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCopyConvolutionFilter2DEXT = extproc; - - glCopyConvolutionFilter2DEXT(target, internalformat, x, y, width, height); -} - -static void APIENTRY InitGetConvolutionFilterEXT (GLenum target, GLenum format, GLenum type, GLvoid *image) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetConvolutionFilterEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetConvolutionFilterEXT = extproc; - - glGetConvolutionFilterEXT(target, format, type, image); -} - -static void APIENTRY InitGetConvolutionParameterfvEXT (GLenum target, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetConvolutionParameterfvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetConvolutionParameterfvEXT = extproc; - - glGetConvolutionParameterfvEXT(target, pname, params); -} - -static void APIENTRY InitGetConvolutionParameterivEXT (GLenum target, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetConvolutionParameterivEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetConvolutionParameterivEXT = extproc; - - glGetConvolutionParameterivEXT(target, pname, params); -} - -static void APIENTRY InitGetSeparableFilterEXT (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetSeparableFilterEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetSeparableFilterEXT = extproc; - - glGetSeparableFilterEXT(target, format, type, row, column, span); -} - -static void APIENTRY InitSeparableFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSeparableFilter2DEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSeparableFilter2DEXT = extproc; - - glSeparableFilter2DEXT(target, internalformat, width, height, format, type, row, column); -} - -static void APIENTRY InitColorTableSGI (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColorTableSGI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColorTableSGI = extproc; - - glColorTableSGI(target, internalformat, width, format, type, table); -} - -static void APIENTRY InitColorTableParameterfvSGI (GLenum target, GLenum pname, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColorTableParameterfvSGI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColorTableParameterfvSGI = extproc; - - glColorTableParameterfvSGI(target, pname, params); -} - -static void APIENTRY InitColorTableParameterivSGI (GLenum target, GLenum pname, const GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColorTableParameterivSGI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColorTableParameterivSGI = extproc; - - glColorTableParameterivSGI(target, pname, params); -} - -static void APIENTRY InitCopyColorTableSGI (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCopyColorTableSGI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCopyColorTableSGI = extproc; - - glCopyColorTableSGI(target, internalformat, x, y, width); -} - -static void APIENTRY InitGetColorTableSGI (GLenum target, GLenum format, GLenum type, GLvoid *table) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetColorTableSGI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetColorTableSGI = extproc; - - glGetColorTableSGI(target, format, type, table); -} - -static void APIENTRY InitGetColorTableParameterfvSGI (GLenum target, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetColorTableParameterfvSGI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetColorTableParameterfvSGI = extproc; - - glGetColorTableParameterfvSGI(target, pname, params); -} - -static void APIENTRY InitGetColorTableParameterivSGI (GLenum target, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetColorTableParameterivSGI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetColorTableParameterivSGI = extproc; - - glGetColorTableParameterivSGI(target, pname, params); -} - -static void APIENTRY InitPixelTexGenSGIX (GLenum mode) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPixelTexGenSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPixelTexGenSGIX = extproc; - - glPixelTexGenSGIX(mode); -} - -static void APIENTRY InitPixelTexGenParameteriSGIS (GLenum pname, GLint param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPixelTexGenParameteriSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPixelTexGenParameteriSGIS = extproc; - - glPixelTexGenParameteriSGIS(pname, param); -} - -static void APIENTRY InitPixelTexGenParameterivSGIS (GLenum pname, const GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPixelTexGenParameterivSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPixelTexGenParameterivSGIS = extproc; - - glPixelTexGenParameterivSGIS(pname, params); -} - -static void APIENTRY InitPixelTexGenParameterfSGIS (GLenum pname, GLfloat param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPixelTexGenParameterfSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPixelTexGenParameterfSGIS = extproc; - - glPixelTexGenParameterfSGIS(pname, param); -} - -static void APIENTRY InitPixelTexGenParameterfvSGIS (GLenum pname, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPixelTexGenParameterfvSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPixelTexGenParameterfvSGIS = extproc; - - glPixelTexGenParameterfvSGIS(pname, params); -} - -static void APIENTRY InitGetPixelTexGenParameterivSGIS (GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetPixelTexGenParameterivSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetPixelTexGenParameterivSGIS = extproc; - - glGetPixelTexGenParameterivSGIS(pname, params); -} - -static void APIENTRY InitGetPixelTexGenParameterfvSGIS (GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetPixelTexGenParameterfvSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetPixelTexGenParameterfvSGIS = extproc; - - glGetPixelTexGenParameterfvSGIS(pname, params); -} - -static void APIENTRY InitTexImage4DSGIS (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexImage4DSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexImage4DSGIS = extproc; - - glTexImage4DSGIS(target, level, internalformat, width, height, depth, size4d, border, format, type, pixels); -} - -static void APIENTRY InitTexSubImage4DSGIS (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexSubImage4DSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexSubImage4DSGIS = extproc; - - glTexSubImage4DSGIS(target, level, xoffset, yoffset, zoffset, woffset, width, height, depth, size4d, format, type, pixels); -} - -static GLboolean APIENTRY InitAreTexturesResidentEXT (GLsizei n, const GLuint *textures, GLboolean *residences) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glAreTexturesResidentEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glAreTexturesResidentEXT = extproc; - - return glAreTexturesResidentEXT(n, textures, residences); -} - -static void APIENTRY InitBindTextureEXT (GLenum target, GLuint texture) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBindTextureEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBindTextureEXT = extproc; - - glBindTextureEXT(target, texture); -} - -static void APIENTRY InitDeleteTexturesEXT (GLsizei n, const GLuint *textures) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDeleteTexturesEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDeleteTexturesEXT = extproc; - - glDeleteTexturesEXT(n, textures); -} - -static void APIENTRY InitGenTexturesEXT (GLsizei n, GLuint *textures) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGenTexturesEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGenTexturesEXT = extproc; - - glGenTexturesEXT(n, textures); -} - -static GLboolean APIENTRY InitIsTextureEXT (GLuint texture) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glIsTextureEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glIsTextureEXT = extproc; - - return glIsTextureEXT(texture); -} - -static void APIENTRY InitPrioritizeTexturesEXT (GLsizei n, const GLuint *textures, const GLclampf *priorities) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPrioritizeTexturesEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPrioritizeTexturesEXT = extproc; - - glPrioritizeTexturesEXT(n, textures, priorities); -} - -static void APIENTRY InitDetailTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDetailTexFuncSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDetailTexFuncSGIS = extproc; - - glDetailTexFuncSGIS(target, n, points); -} - -static void APIENTRY InitGetDetailTexFuncSGIS (GLenum target, GLfloat *points) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetDetailTexFuncSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetDetailTexFuncSGIS = extproc; - - glGetDetailTexFuncSGIS(target, points); -} - -static void APIENTRY InitSharpenTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSharpenTexFuncSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSharpenTexFuncSGIS = extproc; - - glSharpenTexFuncSGIS(target, n, points); -} - -static void APIENTRY InitGetSharpenTexFuncSGIS (GLenum target, GLfloat *points) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetSharpenTexFuncSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetSharpenTexFuncSGIS = extproc; - - glGetSharpenTexFuncSGIS(target, points); -} - -static void APIENTRY InitSampleMaskSGIS (GLclampf value, GLboolean invert) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSampleMaskSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSampleMaskSGIS = extproc; - - glSampleMaskSGIS(value, invert); -} - -static void APIENTRY InitSamplePatternSGIS (GLenum pattern) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSamplePatternSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSamplePatternSGIS = extproc; - - glSamplePatternSGIS(pattern); -} - -static void APIENTRY InitArrayElementEXT (GLint i) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glArrayElementEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glArrayElementEXT = extproc; - - glArrayElementEXT(i); -} - -static void APIENTRY InitColorPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColorPointerEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColorPointerEXT = extproc; - - glColorPointerEXT(size, type, stride, count, pointer); -} - -static void APIENTRY InitDrawArraysEXT (GLenum mode, GLint first, GLsizei count) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDrawArraysEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDrawArraysEXT = extproc; - - glDrawArraysEXT(mode, first, count); -} - -static void APIENTRY InitEdgeFlagPointerEXT (GLsizei stride, GLsizei count, const GLboolean *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glEdgeFlagPointerEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glEdgeFlagPointerEXT = extproc; - - glEdgeFlagPointerEXT(stride, count, pointer); -} - -static void APIENTRY InitGetPointervEXT (GLenum pname, GLvoid* *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetPointervEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetPointervEXT = extproc; - - glGetPointervEXT(pname, params); -} - -static void APIENTRY InitIndexPointerEXT (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glIndexPointerEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glIndexPointerEXT = extproc; - - glIndexPointerEXT(type, stride, count, pointer); -} - -static void APIENTRY InitNormalPointerEXT (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glNormalPointerEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glNormalPointerEXT = extproc; - - glNormalPointerEXT(type, stride, count, pointer); -} - -static void APIENTRY InitTexCoordPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoordPointerEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoordPointerEXT = extproc; - - glTexCoordPointerEXT(size, type, stride, count, pointer); -} - -static void APIENTRY InitVertexPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexPointerEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexPointerEXT = extproc; - - glVertexPointerEXT(size, type, stride, count, pointer); -} - -static void APIENTRY InitBlendEquationEXT (GLenum mode) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBlendEquationEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBlendEquationEXT = extproc; - - glBlendEquationEXT(mode); -} - -static void APIENTRY InitSpriteParameterfSGIX (GLenum pname, GLfloat param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSpriteParameterfSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSpriteParameterfSGIX = extproc; - - glSpriteParameterfSGIX(pname, param); -} - -static void APIENTRY InitSpriteParameterfvSGIX (GLenum pname, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSpriteParameterfvSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSpriteParameterfvSGIX = extproc; - - glSpriteParameterfvSGIX(pname, params); -} - -static void APIENTRY InitSpriteParameteriSGIX (GLenum pname, GLint param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSpriteParameteriSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSpriteParameteriSGIX = extproc; - - glSpriteParameteriSGIX(pname, param); -} - -static void APIENTRY InitSpriteParameterivSGIX (GLenum pname, const GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSpriteParameterivSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSpriteParameterivSGIX = extproc; - - glSpriteParameterivSGIX(pname, params); -} - -static void APIENTRY InitPointParameterfEXT (GLenum pname, GLfloat param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPointParameterfEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPointParameterfEXT = extproc; - - glPointParameterfEXT(pname, param); -} - -static void APIENTRY InitPointParameterfvEXT (GLenum pname, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPointParameterfvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPointParameterfvEXT = extproc; - - glPointParameterfvEXT(pname, params); -} - -static void APIENTRY InitPointParameterfSGIS (GLenum pname, GLfloat param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPointParameterfSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPointParameterfSGIS = extproc; - - glPointParameterfSGIS(pname, param); -} - -static void APIENTRY InitPointParameterfvSGIS (GLenum pname, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPointParameterfvSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPointParameterfvSGIS = extproc; - - glPointParameterfvSGIS(pname, params); -} - -static GLint APIENTRY InitGetInstrumentsSGIX (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetInstrumentsSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glGetInstrumentsSGIX = extproc; - - return glGetInstrumentsSGIX(); -} - -static void APIENTRY InitInstrumentsBufferSGIX (GLsizei size, GLint *buffer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glInstrumentsBufferSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glInstrumentsBufferSGIX = extproc; - - glInstrumentsBufferSGIX(size, buffer); -} - -static GLint APIENTRY InitPollInstrumentsSGIX (GLint *marker_p) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPollInstrumentsSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glPollInstrumentsSGIX = extproc; - - return glPollInstrumentsSGIX(marker_p); -} - -static void APIENTRY InitReadInstrumentsSGIX (GLint marker) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReadInstrumentsSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReadInstrumentsSGIX = extproc; - - glReadInstrumentsSGIX(marker); -} - -static void APIENTRY InitStartInstrumentsSGIX (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glStartInstrumentsSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glStartInstrumentsSGIX = extproc; - - glStartInstrumentsSGIX(); -} - -static void APIENTRY InitStopInstrumentsSGIX (GLint marker) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glStopInstrumentsSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glStopInstrumentsSGIX = extproc; - - glStopInstrumentsSGIX(marker); -} - -static void APIENTRY InitFrameZoomSGIX (GLint factor) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFrameZoomSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFrameZoomSGIX = extproc; - - glFrameZoomSGIX(factor); -} - -static void APIENTRY InitTagSampleBufferSGIX (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTagSampleBufferSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTagSampleBufferSGIX = extproc; - - glTagSampleBufferSGIX(); -} - -static void APIENTRY InitDeformationMap3dSGIX (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDeformationMap3dSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDeformationMap3dSGIX = extproc; - - glDeformationMap3dSGIX(target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, w1, w2, wstride, worder, points); -} - -static void APIENTRY InitDeformationMap3fSGIX (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDeformationMap3fSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDeformationMap3fSGIX = extproc; - - glDeformationMap3fSGIX(target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, w1, w2, wstride, worder, points); -} - -static void APIENTRY InitDeformSGIX (GLbitfield mask) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDeformSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDeformSGIX = extproc; - - glDeformSGIX(mask); -} - -static void APIENTRY InitLoadIdentityDeformationMapSGIX (GLbitfield mask) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glLoadIdentityDeformationMapSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glLoadIdentityDeformationMapSGIX = extproc; - - glLoadIdentityDeformationMapSGIX(mask); -} - -static void APIENTRY InitReferencePlaneSGIX (const GLdouble *equation) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReferencePlaneSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReferencePlaneSGIX = extproc; - - glReferencePlaneSGIX(equation); -} - -static void APIENTRY InitFlushRasterSGIX (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFlushRasterSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFlushRasterSGIX = extproc; - - glFlushRasterSGIX(); -} - -static void APIENTRY InitFogFuncSGIS (GLsizei n, const GLfloat *points) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFogFuncSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFogFuncSGIS = extproc; - - glFogFuncSGIS(n, points); -} - -static void APIENTRY InitGetFogFuncSGIS (GLfloat *points) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetFogFuncSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetFogFuncSGIS = extproc; - - glGetFogFuncSGIS(points); -} - -static void APIENTRY InitImageTransformParameteriHP (GLenum target, GLenum pname, GLint param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glImageTransformParameteriHP"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glImageTransformParameteriHP = extproc; - - glImageTransformParameteriHP(target, pname, param); -} - -static void APIENTRY InitImageTransformParameterfHP (GLenum target, GLenum pname, GLfloat param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glImageTransformParameterfHP"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glImageTransformParameterfHP = extproc; - - glImageTransformParameterfHP(target, pname, param); -} - -static void APIENTRY InitImageTransformParameterivHP (GLenum target, GLenum pname, const GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glImageTransformParameterivHP"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glImageTransformParameterivHP = extproc; - - glImageTransformParameterivHP(target, pname, params); -} - -static void APIENTRY InitImageTransformParameterfvHP (GLenum target, GLenum pname, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glImageTransformParameterfvHP"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glImageTransformParameterfvHP = extproc; - - glImageTransformParameterfvHP(target, pname, params); -} - -static void APIENTRY InitGetImageTransformParameterivHP (GLenum target, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetImageTransformParameterivHP"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetImageTransformParameterivHP = extproc; - - glGetImageTransformParameterivHP(target, pname, params); -} - -static void APIENTRY InitGetImageTransformParameterfvHP (GLenum target, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetImageTransformParameterfvHP"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetImageTransformParameterfvHP = extproc; - - glGetImageTransformParameterfvHP(target, pname, params); -} - -static void APIENTRY InitColorSubTableEXT (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColorSubTableEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColorSubTableEXT = extproc; - - glColorSubTableEXT(target, start, count, format, type, data); -} - -static void APIENTRY InitCopyColorSubTableEXT (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCopyColorSubTableEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCopyColorSubTableEXT = extproc; - - glCopyColorSubTableEXT(target, start, x, y, width); -} - -static void APIENTRY InitHintPGI (GLenum target, GLint mode) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glHintPGI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glHintPGI = extproc; - - glHintPGI(target, mode); -} - -static void APIENTRY InitColorTableEXT (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColorTableEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColorTableEXT = extproc; - - glColorTableEXT(target, internalFormat, width, format, type, table); -} - -static void APIENTRY InitGetColorTableEXT (GLenum target, GLenum format, GLenum type, GLvoid *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetColorTableEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetColorTableEXT = extproc; - - glGetColorTableEXT(target, format, type, data); -} - -static void APIENTRY InitGetColorTableParameterivEXT (GLenum target, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetColorTableParameterivEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetColorTableParameterivEXT = extproc; - - glGetColorTableParameterivEXT(target, pname, params); -} - -static void APIENTRY InitGetColorTableParameterfvEXT (GLenum target, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetColorTableParameterfvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetColorTableParameterfvEXT = extproc; - - glGetColorTableParameterfvEXT(target, pname, params); -} - -static void APIENTRY InitGetListParameterfvSGIX (GLuint list, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetListParameterfvSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetListParameterfvSGIX = extproc; - - glGetListParameterfvSGIX(list, pname, params); -} - -static void APIENTRY InitGetListParameterivSGIX (GLuint list, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetListParameterivSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetListParameterivSGIX = extproc; - - glGetListParameterivSGIX(list, pname, params); -} - -static void APIENTRY InitListParameterfSGIX (GLuint list, GLenum pname, GLfloat param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glListParameterfSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glListParameterfSGIX = extproc; - - glListParameterfSGIX(list, pname, param); -} - -static void APIENTRY InitListParameterfvSGIX (GLuint list, GLenum pname, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glListParameterfvSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glListParameterfvSGIX = extproc; - - glListParameterfvSGIX(list, pname, params); -} - -static void APIENTRY InitListParameteriSGIX (GLuint list, GLenum pname, GLint param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glListParameteriSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glListParameteriSGIX = extproc; - - glListParameteriSGIX(list, pname, param); -} - -static void APIENTRY InitListParameterivSGIX (GLuint list, GLenum pname, const GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glListParameterivSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glListParameterivSGIX = extproc; - - glListParameterivSGIX(list, pname, params); -} - -static void APIENTRY InitIndexMaterialEXT (GLenum face, GLenum mode) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glIndexMaterialEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glIndexMaterialEXT = extproc; - - glIndexMaterialEXT(face, mode); -} - -static void APIENTRY InitIndexFuncEXT (GLenum func, GLclampf ref) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glIndexFuncEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glIndexFuncEXT = extproc; - - glIndexFuncEXT(func, ref); -} - -static void APIENTRY InitLockArraysEXT (GLint first, GLsizei count) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glLockArraysEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glLockArraysEXT = extproc; - - glLockArraysEXT(first, count); -} - -static void APIENTRY InitUnlockArraysEXT (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUnlockArraysEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUnlockArraysEXT = extproc; - - glUnlockArraysEXT(); -} - -static void APIENTRY InitCullParameterdvEXT (GLenum pname, GLdouble *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCullParameterdvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCullParameterdvEXT = extproc; - - glCullParameterdvEXT(pname, params); -} - -static void APIENTRY InitCullParameterfvEXT (GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCullParameterfvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCullParameterfvEXT = extproc; - - glCullParameterfvEXT(pname, params); -} - -static void APIENTRY InitFragmentColorMaterialSGIX (GLenum face, GLenum mode) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFragmentColorMaterialSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFragmentColorMaterialSGIX = extproc; - - glFragmentColorMaterialSGIX(face, mode); -} - -static void APIENTRY InitFragmentLightfSGIX (GLenum light, GLenum pname, GLfloat param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFragmentLightfSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFragmentLightfSGIX = extproc; - - glFragmentLightfSGIX(light, pname, param); -} - -static void APIENTRY InitFragmentLightfvSGIX (GLenum light, GLenum pname, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFragmentLightfvSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFragmentLightfvSGIX = extproc; - - glFragmentLightfvSGIX(light, pname, params); -} - -static void APIENTRY InitFragmentLightiSGIX (GLenum light, GLenum pname, GLint param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFragmentLightiSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFragmentLightiSGIX = extproc; - - glFragmentLightiSGIX(light, pname, param); -} - -static void APIENTRY InitFragmentLightivSGIX (GLenum light, GLenum pname, const GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFragmentLightivSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFragmentLightivSGIX = extproc; - - glFragmentLightivSGIX(light, pname, params); -} - -static void APIENTRY InitFragmentLightModelfSGIX (GLenum pname, GLfloat param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFragmentLightModelfSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFragmentLightModelfSGIX = extproc; - - glFragmentLightModelfSGIX(pname, param); -} - -static void APIENTRY InitFragmentLightModelfvSGIX (GLenum pname, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFragmentLightModelfvSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFragmentLightModelfvSGIX = extproc; - - glFragmentLightModelfvSGIX(pname, params); -} - -static void APIENTRY InitFragmentLightModeliSGIX (GLenum pname, GLint param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFragmentLightModeliSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFragmentLightModeliSGIX = extproc; - - glFragmentLightModeliSGIX(pname, param); -} - -static void APIENTRY InitFragmentLightModelivSGIX (GLenum pname, const GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFragmentLightModelivSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFragmentLightModelivSGIX = extproc; - - glFragmentLightModelivSGIX(pname, params); -} - -static void APIENTRY InitFragmentMaterialfSGIX (GLenum face, GLenum pname, GLfloat param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFragmentMaterialfSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFragmentMaterialfSGIX = extproc; - - glFragmentMaterialfSGIX(face, pname, param); -} - -static void APIENTRY InitFragmentMaterialfvSGIX (GLenum face, GLenum pname, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFragmentMaterialfvSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFragmentMaterialfvSGIX = extproc; - - glFragmentMaterialfvSGIX(face, pname, params); -} - -static void APIENTRY InitFragmentMaterialiSGIX (GLenum face, GLenum pname, GLint param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFragmentMaterialiSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFragmentMaterialiSGIX = extproc; - - glFragmentMaterialiSGIX(face, pname, param); -} - -static void APIENTRY InitFragmentMaterialivSGIX (GLenum face, GLenum pname, const GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFragmentMaterialivSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFragmentMaterialivSGIX = extproc; - - glFragmentMaterialivSGIX(face, pname, params); -} - -static void APIENTRY InitGetFragmentLightfvSGIX (GLenum light, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetFragmentLightfvSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetFragmentLightfvSGIX = extproc; - - glGetFragmentLightfvSGIX(light, pname, params); -} - -static void APIENTRY InitGetFragmentLightivSGIX (GLenum light, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetFragmentLightivSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetFragmentLightivSGIX = extproc; - - glGetFragmentLightivSGIX(light, pname, params); -} - -static void APIENTRY InitGetFragmentMaterialfvSGIX (GLenum face, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetFragmentMaterialfvSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetFragmentMaterialfvSGIX = extproc; - - glGetFragmentMaterialfvSGIX(face, pname, params); -} - -static void APIENTRY InitGetFragmentMaterialivSGIX (GLenum face, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetFragmentMaterialivSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetFragmentMaterialivSGIX = extproc; - - glGetFragmentMaterialivSGIX(face, pname, params); -} - -static void APIENTRY InitLightEnviSGIX (GLenum pname, GLint param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glLightEnviSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glLightEnviSGIX = extproc; - - glLightEnviSGIX(pname, param); -} - -static void APIENTRY InitDrawRangeElementsEXT (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDrawRangeElementsEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDrawRangeElementsEXT = extproc; - - glDrawRangeElementsEXT(mode, start, end, count, type, indices); -} - -static void APIENTRY InitApplyTextureEXT (GLenum mode) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glApplyTextureEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glApplyTextureEXT = extproc; - - glApplyTextureEXT(mode); -} - -static void APIENTRY InitTextureLightEXT (GLenum pname) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTextureLightEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTextureLightEXT = extproc; - - glTextureLightEXT(pname); -} - -static void APIENTRY InitTextureMaterialEXT (GLenum face, GLenum mode) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTextureMaterialEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTextureMaterialEXT = extproc; - - glTextureMaterialEXT(face, mode); -} - -static void APIENTRY InitAsyncMarkerSGIX (GLuint marker) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glAsyncMarkerSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glAsyncMarkerSGIX = extproc; - - glAsyncMarkerSGIX(marker); -} - -static GLint APIENTRY InitFinishAsyncSGIX (GLuint *markerp) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFinishAsyncSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glFinishAsyncSGIX = extproc; - - return glFinishAsyncSGIX(markerp); -} - -static GLint APIENTRY InitPollAsyncSGIX (GLuint *markerp) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPollAsyncSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glPollAsyncSGIX = extproc; - - return glPollAsyncSGIX(markerp); -} - -static GLuint APIENTRY InitGenAsyncMarkersSGIX (GLsizei range) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGenAsyncMarkersSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glGenAsyncMarkersSGIX = extproc; - - return glGenAsyncMarkersSGIX(range); -} - -static void APIENTRY InitDeleteAsyncMarkersSGIX (GLuint marker, GLsizei range) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDeleteAsyncMarkersSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDeleteAsyncMarkersSGIX = extproc; - - glDeleteAsyncMarkersSGIX(marker, range); -} - -static GLboolean APIENTRY InitIsAsyncMarkerSGIX (GLuint marker) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glIsAsyncMarkerSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glIsAsyncMarkerSGIX = extproc; - - return glIsAsyncMarkerSGIX(marker); -} - -static void APIENTRY InitVertexPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexPointervINTEL"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexPointervINTEL = extproc; - - glVertexPointervINTEL(size, type, pointer); -} - -static void APIENTRY InitNormalPointervINTEL (GLenum type, const GLvoid* *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glNormalPointervINTEL"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glNormalPointervINTEL = extproc; - - glNormalPointervINTEL(type, pointer); -} - -static void APIENTRY InitColorPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColorPointervINTEL"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColorPointervINTEL = extproc; - - glColorPointervINTEL(size, type, pointer); -} - -static void APIENTRY InitTexCoordPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoordPointervINTEL"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoordPointervINTEL = extproc; - - glTexCoordPointervINTEL(size, type, pointer); -} - -static void APIENTRY InitPixelTransformParameteriEXT (GLenum target, GLenum pname, GLint param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPixelTransformParameteriEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPixelTransformParameteriEXT = extproc; - - glPixelTransformParameteriEXT(target, pname, param); -} - -static void APIENTRY InitPixelTransformParameterfEXT (GLenum target, GLenum pname, GLfloat param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPixelTransformParameterfEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPixelTransformParameterfEXT = extproc; - - glPixelTransformParameterfEXT(target, pname, param); -} - -static void APIENTRY InitPixelTransformParameterivEXT (GLenum target, GLenum pname, const GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPixelTransformParameterivEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPixelTransformParameterivEXT = extproc; - - glPixelTransformParameterivEXT(target, pname, params); -} - -static void APIENTRY InitPixelTransformParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPixelTransformParameterfvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPixelTransformParameterfvEXT = extproc; - - glPixelTransformParameterfvEXT(target, pname, params); -} - -static void APIENTRY InitSecondaryColor3bEXT (GLbyte red, GLbyte green, GLbyte blue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3bEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3bEXT = extproc; - - glSecondaryColor3bEXT(red, green, blue); -} - -static void APIENTRY InitSecondaryColor3bvEXT (const GLbyte *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3bvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3bvEXT = extproc; - - glSecondaryColor3bvEXT(v); -} - -static void APIENTRY InitSecondaryColor3dEXT (GLdouble red, GLdouble green, GLdouble blue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3dEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3dEXT = extproc; - - glSecondaryColor3dEXT(red, green, blue); -} - -static void APIENTRY InitSecondaryColor3dvEXT (const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3dvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3dvEXT = extproc; - - glSecondaryColor3dvEXT(v); -} - -static void APIENTRY InitSecondaryColor3fEXT (GLfloat red, GLfloat green, GLfloat blue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3fEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3fEXT = extproc; - - glSecondaryColor3fEXT(red, green, blue); -} - -static void APIENTRY InitSecondaryColor3fvEXT (const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3fvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3fvEXT = extproc; - - glSecondaryColor3fvEXT(v); -} - -static void APIENTRY InitSecondaryColor3iEXT (GLint red, GLint green, GLint blue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3iEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3iEXT = extproc; - - glSecondaryColor3iEXT(red, green, blue); -} - -static void APIENTRY InitSecondaryColor3ivEXT (const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3ivEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3ivEXT = extproc; - - glSecondaryColor3ivEXT(v); -} - -static void APIENTRY InitSecondaryColor3sEXT (GLshort red, GLshort green, GLshort blue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3sEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3sEXT = extproc; - - glSecondaryColor3sEXT(red, green, blue); -} - -static void APIENTRY InitSecondaryColor3svEXT (const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3svEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3svEXT = extproc; - - glSecondaryColor3svEXT(v); -} - -static void APIENTRY InitSecondaryColor3ubEXT (GLubyte red, GLubyte green, GLubyte blue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3ubEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3ubEXT = extproc; - - glSecondaryColor3ubEXT(red, green, blue); -} - -static void APIENTRY InitSecondaryColor3ubvEXT (const GLubyte *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3ubvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3ubvEXT = extproc; - - glSecondaryColor3ubvEXT(v); -} - -static void APIENTRY InitSecondaryColor3uiEXT (GLuint red, GLuint green, GLuint blue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3uiEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3uiEXT = extproc; - - glSecondaryColor3uiEXT(red, green, blue); -} - -static void APIENTRY InitSecondaryColor3uivEXT (const GLuint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3uivEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3uivEXT = extproc; - - glSecondaryColor3uivEXT(v); -} - -static void APIENTRY InitSecondaryColor3usEXT (GLushort red, GLushort green, GLushort blue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3usEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3usEXT = extproc; - - glSecondaryColor3usEXT(red, green, blue); -} - -static void APIENTRY InitSecondaryColor3usvEXT (const GLushort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3usvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3usvEXT = extproc; - - glSecondaryColor3usvEXT(v); -} - -static void APIENTRY InitSecondaryColorPointerEXT (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColorPointerEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColorPointerEXT = extproc; - - glSecondaryColorPointerEXT(size, type, stride, pointer); -} - -static void APIENTRY InitTextureNormalEXT (GLenum mode) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTextureNormalEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTextureNormalEXT = extproc; - - glTextureNormalEXT(mode); -} - -static void APIENTRY InitMultiDrawArraysEXT (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiDrawArraysEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiDrawArraysEXT = extproc; - - glMultiDrawArraysEXT(mode, first, count, primcount); -} - -static void APIENTRY InitMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiDrawElementsEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiDrawElementsEXT = extproc; - - glMultiDrawElementsEXT(mode, count, type, indices, primcount); -} - -static void APIENTRY InitFogCoordfEXT (GLfloat coord) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFogCoordfEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFogCoordfEXT = extproc; - - glFogCoordfEXT(coord); -} - -static void APIENTRY InitFogCoordfvEXT (const GLfloat *coord) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFogCoordfvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFogCoordfvEXT = extproc; - - glFogCoordfvEXT(coord); -} - -static void APIENTRY InitFogCoorddEXT (GLdouble coord) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFogCoorddEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFogCoorddEXT = extproc; - - glFogCoorddEXT(coord); -} - -static void APIENTRY InitFogCoorddvEXT (const GLdouble *coord) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFogCoorddvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFogCoorddvEXT = extproc; - - glFogCoorddvEXT(coord); -} - -static void APIENTRY InitFogCoordPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFogCoordPointerEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFogCoordPointerEXT = extproc; - - glFogCoordPointerEXT(type, stride, pointer); -} - -static void APIENTRY InitTangent3bEXT (GLbyte tx, GLbyte ty, GLbyte tz) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTangent3bEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTangent3bEXT = extproc; - - glTangent3bEXT(tx, ty, tz); -} - -static void APIENTRY InitTangent3bvEXT (const GLbyte *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTangent3bvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTangent3bvEXT = extproc; - - glTangent3bvEXT(v); -} - -static void APIENTRY InitTangent3dEXT (GLdouble tx, GLdouble ty, GLdouble tz) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTangent3dEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTangent3dEXT = extproc; - - glTangent3dEXT(tx, ty, tz); -} - -static void APIENTRY InitTangent3dvEXT (const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTangent3dvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTangent3dvEXT = extproc; - - glTangent3dvEXT(v); -} - -static void APIENTRY InitTangent3fEXT (GLfloat tx, GLfloat ty, GLfloat tz) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTangent3fEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTangent3fEXT = extproc; - - glTangent3fEXT(tx, ty, tz); -} - -static void APIENTRY InitTangent3fvEXT (const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTangent3fvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTangent3fvEXT = extproc; - - glTangent3fvEXT(v); -} - -static void APIENTRY InitTangent3iEXT (GLint tx, GLint ty, GLint tz) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTangent3iEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTangent3iEXT = extproc; - - glTangent3iEXT(tx, ty, tz); -} - -static void APIENTRY InitTangent3ivEXT (const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTangent3ivEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTangent3ivEXT = extproc; - - glTangent3ivEXT(v); -} - -static void APIENTRY InitTangent3sEXT (GLshort tx, GLshort ty, GLshort tz) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTangent3sEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTangent3sEXT = extproc; - - glTangent3sEXT(tx, ty, tz); -} - -static void APIENTRY InitTangent3svEXT (const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTangent3svEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTangent3svEXT = extproc; - - glTangent3svEXT(v); -} - -static void APIENTRY InitBinormal3bEXT (GLbyte bx, GLbyte by, GLbyte bz) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBinormal3bEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBinormal3bEXT = extproc; - - glBinormal3bEXT(bx, by, bz); -} - -static void APIENTRY InitBinormal3bvEXT (const GLbyte *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBinormal3bvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBinormal3bvEXT = extproc; - - glBinormal3bvEXT(v); -} - -static void APIENTRY InitBinormal3dEXT (GLdouble bx, GLdouble by, GLdouble bz) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBinormal3dEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBinormal3dEXT = extproc; - - glBinormal3dEXT(bx, by, bz); -} - -static void APIENTRY InitBinormal3dvEXT (const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBinormal3dvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBinormal3dvEXT = extproc; - - glBinormal3dvEXT(v); -} - -static void APIENTRY InitBinormal3fEXT (GLfloat bx, GLfloat by, GLfloat bz) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBinormal3fEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBinormal3fEXT = extproc; - - glBinormal3fEXT(bx, by, bz); -} - -static void APIENTRY InitBinormal3fvEXT (const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBinormal3fvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBinormal3fvEXT = extproc; - - glBinormal3fvEXT(v); -} - -static void APIENTRY InitBinormal3iEXT (GLint bx, GLint by, GLint bz) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBinormal3iEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBinormal3iEXT = extproc; - - glBinormal3iEXT(bx, by, bz); -} - -static void APIENTRY InitBinormal3ivEXT (const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBinormal3ivEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBinormal3ivEXT = extproc; - - glBinormal3ivEXT(v); -} - -static void APIENTRY InitBinormal3sEXT (GLshort bx, GLshort by, GLshort bz) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBinormal3sEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBinormal3sEXT = extproc; - - glBinormal3sEXT(bx, by, bz); -} - -static void APIENTRY InitBinormal3svEXT (const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBinormal3svEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBinormal3svEXT = extproc; - - glBinormal3svEXT(v); -} - -static void APIENTRY InitTangentPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTangentPointerEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTangentPointerEXT = extproc; - - glTangentPointerEXT(type, stride, pointer); -} - -static void APIENTRY InitBinormalPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBinormalPointerEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBinormalPointerEXT = extproc; - - glBinormalPointerEXT(type, stride, pointer); -} - -static void APIENTRY InitFinishTextureSUNX (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFinishTextureSUNX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFinishTextureSUNX = extproc; - - glFinishTextureSUNX(); -} - -static void APIENTRY InitGlobalAlphaFactorbSUN (GLbyte factor) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorbSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGlobalAlphaFactorbSUN = extproc; - - glGlobalAlphaFactorbSUN(factor); -} - -static void APIENTRY InitGlobalAlphaFactorsSUN (GLshort factor) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorsSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGlobalAlphaFactorsSUN = extproc; - - glGlobalAlphaFactorsSUN(factor); -} - -static void APIENTRY InitGlobalAlphaFactoriSUN (GLint factor) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGlobalAlphaFactoriSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGlobalAlphaFactoriSUN = extproc; - - glGlobalAlphaFactoriSUN(factor); -} - -static void APIENTRY InitGlobalAlphaFactorfSUN (GLfloat factor) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorfSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGlobalAlphaFactorfSUN = extproc; - - glGlobalAlphaFactorfSUN(factor); -} - -static void APIENTRY InitGlobalAlphaFactordSUN (GLdouble factor) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGlobalAlphaFactordSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGlobalAlphaFactordSUN = extproc; - - glGlobalAlphaFactordSUN(factor); -} - -static void APIENTRY InitGlobalAlphaFactorubSUN (GLubyte factor) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorubSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGlobalAlphaFactorubSUN = extproc; - - glGlobalAlphaFactorubSUN(factor); -} - -static void APIENTRY InitGlobalAlphaFactorusSUN (GLushort factor) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorusSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGlobalAlphaFactorusSUN = extproc; - - glGlobalAlphaFactorusSUN(factor); -} - -static void APIENTRY InitGlobalAlphaFactoruiSUN (GLuint factor) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGlobalAlphaFactoruiSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGlobalAlphaFactoruiSUN = extproc; - - glGlobalAlphaFactoruiSUN(factor); -} - -static void APIENTRY InitReplacementCodeuiSUN (GLuint code) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeuiSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeuiSUN = extproc; - - glReplacementCodeuiSUN(code); -} - -static void APIENTRY InitReplacementCodeusSUN (GLushort code) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeusSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeusSUN = extproc; - - glReplacementCodeusSUN(code); -} - -static void APIENTRY InitReplacementCodeubSUN (GLubyte code) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeubSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeubSUN = extproc; - - glReplacementCodeubSUN(code); -} - -static void APIENTRY InitReplacementCodeuivSUN (const GLuint *code) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeuivSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeuivSUN = extproc; - - glReplacementCodeuivSUN(code); -} - -static void APIENTRY InitReplacementCodeusvSUN (const GLushort *code) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeusvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeusvSUN = extproc; - - glReplacementCodeusvSUN(code); -} - -static void APIENTRY InitReplacementCodeubvSUN (const GLubyte *code) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeubvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeubvSUN = extproc; - - glReplacementCodeubvSUN(code); -} - -static void APIENTRY InitReplacementCodePointerSUN (GLenum type, GLsizei stride, const GLvoid* *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodePointerSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodePointerSUN = extproc; - - glReplacementCodePointerSUN(type, stride, pointer); -} - -static void APIENTRY InitColor4ubVertex2fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColor4ubVertex2fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColor4ubVertex2fSUN = extproc; - - glColor4ubVertex2fSUN(r, g, b, a, x, y); -} - -static void APIENTRY InitColor4ubVertex2fvSUN (const GLubyte *c, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColor4ubVertex2fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColor4ubVertex2fvSUN = extproc; - - glColor4ubVertex2fvSUN(c, v); -} - -static void APIENTRY InitColor4ubVertex3fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColor4ubVertex3fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColor4ubVertex3fSUN = extproc; - - glColor4ubVertex3fSUN(r, g, b, a, x, y, z); -} - -static void APIENTRY InitColor4ubVertex3fvSUN (const GLubyte *c, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColor4ubVertex3fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColor4ubVertex3fvSUN = extproc; - - glColor4ubVertex3fvSUN(c, v); -} - -static void APIENTRY InitColor3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColor3fVertex3fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColor3fVertex3fSUN = extproc; - - glColor3fVertex3fSUN(r, g, b, x, y, z); -} - -static void APIENTRY InitColor3fVertex3fvSUN (const GLfloat *c, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColor3fVertex3fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColor3fVertex3fvSUN = extproc; - - glColor3fVertex3fvSUN(c, v); -} - -static void APIENTRY InitNormal3fVertex3fSUN (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glNormal3fVertex3fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glNormal3fVertex3fSUN = extproc; - - glNormal3fVertex3fSUN(nx, ny, nz, x, y, z); -} - -static void APIENTRY InitNormal3fVertex3fvSUN (const GLfloat *n, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glNormal3fVertex3fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glNormal3fVertex3fvSUN = extproc; - - glNormal3fVertex3fvSUN(n, v); -} - -static void APIENTRY InitColor4fNormal3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColor4fNormal3fVertex3fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColor4fNormal3fVertex3fSUN = extproc; - - glColor4fNormal3fVertex3fSUN(r, g, b, a, nx, ny, nz, x, y, z); -} - -static void APIENTRY InitColor4fNormal3fVertex3fvSUN (const GLfloat *c, const GLfloat *n, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColor4fNormal3fVertex3fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColor4fNormal3fVertex3fvSUN = extproc; - - glColor4fNormal3fVertex3fvSUN(c, n, v); -} - -static void APIENTRY InitTexCoord2fVertex3fSUN (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord2fVertex3fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord2fVertex3fSUN = extproc; - - glTexCoord2fVertex3fSUN(s, t, x, y, z); -} - -static void APIENTRY InitTexCoord2fVertex3fvSUN (const GLfloat *tc, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord2fVertex3fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord2fVertex3fvSUN = extproc; - - glTexCoord2fVertex3fvSUN(tc, v); -} - -static void APIENTRY InitTexCoord4fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord4fVertex4fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord4fVertex4fSUN = extproc; - - glTexCoord4fVertex4fSUN(s, t, p, q, x, y, z, w); -} - -static void APIENTRY InitTexCoord4fVertex4fvSUN (const GLfloat *tc, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord4fVertex4fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord4fVertex4fvSUN = extproc; - - glTexCoord4fVertex4fvSUN(tc, v); -} - -static void APIENTRY InitTexCoord2fColor4ubVertex3fSUN (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord2fColor4ubVertex3fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord2fColor4ubVertex3fSUN = extproc; - - glTexCoord2fColor4ubVertex3fSUN(s, t, r, g, b, a, x, y, z); -} - -static void APIENTRY InitTexCoord2fColor4ubVertex3fvSUN (const GLfloat *tc, const GLubyte *c, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord2fColor4ubVertex3fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord2fColor4ubVertex3fvSUN = extproc; - - glTexCoord2fColor4ubVertex3fvSUN(tc, c, v); -} - -static void APIENTRY InitTexCoord2fColor3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord2fColor3fVertex3fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord2fColor3fVertex3fSUN = extproc; - - glTexCoord2fColor3fVertex3fSUN(s, t, r, g, b, x, y, z); -} - -static void APIENTRY InitTexCoord2fColor3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord2fColor3fVertex3fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord2fColor3fVertex3fvSUN = extproc; - - glTexCoord2fColor3fVertex3fvSUN(tc, c, v); -} - -static void APIENTRY InitTexCoord2fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord2fNormal3fVertex3fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord2fNormal3fVertex3fSUN = extproc; - - glTexCoord2fNormal3fVertex3fSUN(s, t, nx, ny, nz, x, y, z); -} - -static void APIENTRY InitTexCoord2fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *n, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord2fNormal3fVertex3fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord2fNormal3fVertex3fvSUN = extproc; - - glTexCoord2fNormal3fVertex3fvSUN(tc, n, v); -} - -static void APIENTRY InitTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord2fColor4fNormal3fVertex3fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord2fColor4fNormal3fVertex3fSUN = extproc; - - glTexCoord2fColor4fNormal3fVertex3fSUN(s, t, r, g, b, a, nx, ny, nz, x, y, z); -} - -static void APIENTRY InitTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord2fColor4fNormal3fVertex3fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord2fColor4fNormal3fVertex3fvSUN = extproc; - - glTexCoord2fColor4fNormal3fVertex3fvSUN(tc, c, n, v); -} - -static void APIENTRY InitTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord4fColor4fNormal3fVertex4fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord4fColor4fNormal3fVertex4fSUN = extproc; - - glTexCoord4fColor4fNormal3fVertex4fSUN(s, t, p, q, r, g, b, a, nx, ny, nz, x, y, z, w); -} - -static void APIENTRY InitTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord4fColor4fNormal3fVertex4fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord4fColor4fNormal3fVertex4fvSUN = extproc; - - glTexCoord4fColor4fNormal3fVertex4fvSUN(tc, c, n, v); -} - -static void APIENTRY InitReplacementCodeuiVertex3fSUN (GLuint rc, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeuiVertex3fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeuiVertex3fSUN = extproc; - - glReplacementCodeuiVertex3fSUN(rc, x, y, z); -} - -static void APIENTRY InitReplacementCodeuiVertex3fvSUN (const GLuint *rc, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeuiVertex3fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeuiVertex3fvSUN = extproc; - - glReplacementCodeuiVertex3fvSUN(rc, v); -} - -static void APIENTRY InitReplacementCodeuiColor4ubVertex3fSUN (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor4ubVertex3fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeuiColor4ubVertex3fSUN = extproc; - - glReplacementCodeuiColor4ubVertex3fSUN(rc, r, g, b, a, x, y, z); -} - -static void APIENTRY InitReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *rc, const GLubyte *c, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor4ubVertex3fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeuiColor4ubVertex3fvSUN = extproc; - - glReplacementCodeuiColor4ubVertex3fvSUN(rc, c, v); -} - -static void APIENTRY InitReplacementCodeuiColor3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor3fVertex3fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeuiColor3fVertex3fSUN = extproc; - - glReplacementCodeuiColor3fVertex3fSUN(rc, r, g, b, x, y, z); -} - -static void APIENTRY InitReplacementCodeuiColor3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor3fVertex3fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeuiColor3fVertex3fvSUN = extproc; - - glReplacementCodeuiColor3fVertex3fvSUN(rc, c, v); -} - -static void APIENTRY InitReplacementCodeuiNormal3fVertex3fSUN (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeuiNormal3fVertex3fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeuiNormal3fVertex3fSUN = extproc; - - glReplacementCodeuiNormal3fVertex3fSUN(rc, nx, ny, nz, x, y, z); -} - -static void APIENTRY InitReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *n, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeuiNormal3fVertex3fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeuiNormal3fVertex3fvSUN = extproc; - - glReplacementCodeuiNormal3fVertex3fvSUN(rc, n, v); -} - -static void APIENTRY InitReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor4fNormal3fVertex3fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeuiColor4fNormal3fVertex3fSUN = extproc; - - glReplacementCodeuiColor4fNormal3fVertex3fSUN(rc, r, g, b, a, nx, ny, nz, x, y, z); -} - -static void APIENTRY InitReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor4fNormal3fVertex3fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeuiColor4fNormal3fVertex3fvSUN = extproc; - - glReplacementCodeuiColor4fNormal3fVertex3fvSUN(rc, c, n, v); -} - -static void APIENTRY InitReplacementCodeuiTexCoord2fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fVertex3fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeuiTexCoord2fVertex3fSUN = extproc; - - glReplacementCodeuiTexCoord2fVertex3fSUN(rc, s, t, x, y, z); -} - -static void APIENTRY InitReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fVertex3fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeuiTexCoord2fVertex3fvSUN = extproc; - - glReplacementCodeuiTexCoord2fVertex3fvSUN(rc, tc, v); -} - -static void APIENTRY InitReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN = extproc; - - glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN(rc, s, t, nx, ny, nz, x, y, z); -} - -static void APIENTRY InitReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN = extproc; - - glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN(rc, tc, n, v); -} - -static void APIENTRY InitReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN = extproc; - - glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN(rc, s, t, r, g, b, a, nx, ny, nz, x, y, z); -} - -static void APIENTRY InitReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN = extproc; - - glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN(rc, tc, c, n, v); -} - -static void APIENTRY InitBlendFuncSeparateEXT (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBlendFuncSeparateEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBlendFuncSeparateEXT = extproc; - - glBlendFuncSeparateEXT(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); -} - -static void APIENTRY InitBlendFuncSeparateINGR (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBlendFuncSeparateINGR"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBlendFuncSeparateINGR = extproc; - - glBlendFuncSeparateINGR(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); -} - -static void APIENTRY InitVertexWeightfEXT (GLfloat weight) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexWeightfEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexWeightfEXT = extproc; - - glVertexWeightfEXT(weight); -} - -static void APIENTRY InitVertexWeightfvEXT (const GLfloat *weight) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexWeightfvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexWeightfvEXT = extproc; - - glVertexWeightfvEXT(weight); -} - -static void APIENTRY InitVertexWeightPointerEXT (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexWeightPointerEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexWeightPointerEXT = extproc; - - glVertexWeightPointerEXT(size, type, stride, pointer); -} - -static void APIENTRY InitFlushVertexArrayRangeNV (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFlushVertexArrayRangeNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFlushVertexArrayRangeNV = extproc; - - glFlushVertexArrayRangeNV(); -} - -static void APIENTRY InitVertexArrayRangeNV (GLsizei length, const GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexArrayRangeNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexArrayRangeNV = extproc; - - glVertexArrayRangeNV(length, pointer); -} - -static void APIENTRY InitCombinerParameterfvNV (GLenum pname, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCombinerParameterfvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCombinerParameterfvNV = extproc; - - glCombinerParameterfvNV(pname, params); -} - -static void APIENTRY InitCombinerParameterfNV (GLenum pname, GLfloat param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCombinerParameterfNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCombinerParameterfNV = extproc; - - glCombinerParameterfNV(pname, param); -} - -static void APIENTRY InitCombinerParameterivNV (GLenum pname, const GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCombinerParameterivNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCombinerParameterivNV = extproc; - - glCombinerParameterivNV(pname, params); -} - -static void APIENTRY InitCombinerParameteriNV (GLenum pname, GLint param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCombinerParameteriNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCombinerParameteriNV = extproc; - - glCombinerParameteriNV(pname, param); -} - -static void APIENTRY InitCombinerInputNV (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCombinerInputNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCombinerInputNV = extproc; - - glCombinerInputNV(stage, portion, variable, input, mapping, componentUsage); -} - -static void APIENTRY InitCombinerOutputNV (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCombinerOutputNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCombinerOutputNV = extproc; - - glCombinerOutputNV(stage, portion, abOutput, cdOutput, sumOutput, scale, bias, abDotProduct, cdDotProduct, muxSum); -} - -static void APIENTRY InitFinalCombinerInputNV (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFinalCombinerInputNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFinalCombinerInputNV = extproc; - - glFinalCombinerInputNV(variable, input, mapping, componentUsage); -} - -static void APIENTRY InitGetCombinerInputParameterfvNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetCombinerInputParameterfvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetCombinerInputParameterfvNV = extproc; - - glGetCombinerInputParameterfvNV(stage, portion, variable, pname, params); -} - -static void APIENTRY InitGetCombinerInputParameterivNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetCombinerInputParameterivNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetCombinerInputParameterivNV = extproc; - - glGetCombinerInputParameterivNV(stage, portion, variable, pname, params); -} - -static void APIENTRY InitGetCombinerOutputParameterfvNV (GLenum stage, GLenum portion, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetCombinerOutputParameterfvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetCombinerOutputParameterfvNV = extproc; - - glGetCombinerOutputParameterfvNV(stage, portion, pname, params); -} - -static void APIENTRY InitGetCombinerOutputParameterivNV (GLenum stage, GLenum portion, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetCombinerOutputParameterivNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetCombinerOutputParameterivNV = extproc; - - glGetCombinerOutputParameterivNV(stage, portion, pname, params); -} - -static void APIENTRY InitGetFinalCombinerInputParameterfvNV (GLenum variable, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetFinalCombinerInputParameterfvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetFinalCombinerInputParameterfvNV = extproc; - - glGetFinalCombinerInputParameterfvNV(variable, pname, params); -} - -static void APIENTRY InitGetFinalCombinerInputParameterivNV (GLenum variable, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetFinalCombinerInputParameterivNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetFinalCombinerInputParameterivNV = extproc; - - glGetFinalCombinerInputParameterivNV(variable, pname, params); -} - -static void APIENTRY InitResizeBuffersMESA (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glResizeBuffersMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glResizeBuffersMESA = extproc; - - glResizeBuffersMESA(); -} - -static void APIENTRY InitWindowPos2dMESA (GLdouble x, GLdouble y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2dMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2dMESA = extproc; - - glWindowPos2dMESA(x, y); -} - -static void APIENTRY InitWindowPos2dvMESA (const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2dvMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2dvMESA = extproc; - - glWindowPos2dvMESA(v); -} - -static void APIENTRY InitWindowPos2fMESA (GLfloat x, GLfloat y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2fMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2fMESA = extproc; - - glWindowPos2fMESA(x, y); -} - -static void APIENTRY InitWindowPos2fvMESA (const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2fvMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2fvMESA = extproc; - - glWindowPos2fvMESA(v); -} - -static void APIENTRY InitWindowPos2iMESA (GLint x, GLint y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2iMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2iMESA = extproc; - - glWindowPos2iMESA(x, y); -} - -static void APIENTRY InitWindowPos2ivMESA (const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2ivMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2ivMESA = extproc; - - glWindowPos2ivMESA(v); -} - -static void APIENTRY InitWindowPos2sMESA (GLshort x, GLshort y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2sMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2sMESA = extproc; - - glWindowPos2sMESA(x, y); -} - -static void APIENTRY InitWindowPos2svMESA (const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos2svMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos2svMESA = extproc; - - glWindowPos2svMESA(v); -} - -static void APIENTRY InitWindowPos3dMESA (GLdouble x, GLdouble y, GLdouble z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3dMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3dMESA = extproc; - - glWindowPos3dMESA(x, y, z); -} - -static void APIENTRY InitWindowPos3dvMESA (const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3dvMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3dvMESA = extproc; - - glWindowPos3dvMESA(v); -} - -static void APIENTRY InitWindowPos3fMESA (GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3fMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3fMESA = extproc; - - glWindowPos3fMESA(x, y, z); -} - -static void APIENTRY InitWindowPos3fvMESA (const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3fvMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3fvMESA = extproc; - - glWindowPos3fvMESA(v); -} - -static void APIENTRY InitWindowPos3iMESA (GLint x, GLint y, GLint z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3iMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3iMESA = extproc; - - glWindowPos3iMESA(x, y, z); -} - -static void APIENTRY InitWindowPos3ivMESA (const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3ivMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3ivMESA = extproc; - - glWindowPos3ivMESA(v); -} - -static void APIENTRY InitWindowPos3sMESA (GLshort x, GLshort y, GLshort z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3sMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3sMESA = extproc; - - glWindowPos3sMESA(x, y, z); -} - -static void APIENTRY InitWindowPos3svMESA (const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos3svMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos3svMESA = extproc; - - glWindowPos3svMESA(v); -} - -static void APIENTRY InitWindowPos4dMESA (GLdouble x, GLdouble y, GLdouble z, GLdouble w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos4dMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos4dMESA = extproc; - - glWindowPos4dMESA(x, y, z, w); -} - -static void APIENTRY InitWindowPos4dvMESA (const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos4dvMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos4dvMESA = extproc; - - glWindowPos4dvMESA(v); -} - -static void APIENTRY InitWindowPos4fMESA (GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos4fMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos4fMESA = extproc; - - glWindowPos4fMESA(x, y, z, w); -} - -static void APIENTRY InitWindowPos4fvMESA (const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos4fvMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos4fvMESA = extproc; - - glWindowPos4fvMESA(v); -} - -static void APIENTRY InitWindowPos4iMESA (GLint x, GLint y, GLint z, GLint w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos4iMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos4iMESA = extproc; - - glWindowPos4iMESA(x, y, z, w); -} - -static void APIENTRY InitWindowPos4ivMESA (const GLint *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos4ivMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos4ivMESA = extproc; - - glWindowPos4ivMESA(v); -} - -static void APIENTRY InitWindowPos4sMESA (GLshort x, GLshort y, GLshort z, GLshort w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos4sMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos4sMESA = extproc; - - glWindowPos4sMESA(x, y, z, w); -} - -static void APIENTRY InitWindowPos4svMESA (const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWindowPos4svMESA"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWindowPos4svMESA = extproc; - - glWindowPos4svMESA(v); -} - -static void APIENTRY InitMultiModeDrawArraysIBM (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiModeDrawArraysIBM"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiModeDrawArraysIBM = extproc; - - glMultiModeDrawArraysIBM(mode, first, count, primcount, modestride); -} - -static void APIENTRY InitMultiModeDrawElementsIBM (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiModeDrawElementsIBM"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiModeDrawElementsIBM = extproc; - - glMultiModeDrawElementsIBM(mode, count, type, indices, primcount, modestride); -} - -static void APIENTRY InitColorPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColorPointerListIBM"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColorPointerListIBM = extproc; - - glColorPointerListIBM(size, type, stride, pointer, ptrstride); -} - -static void APIENTRY InitSecondaryColorPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColorPointerListIBM"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColorPointerListIBM = extproc; - - glSecondaryColorPointerListIBM(size, type, stride, pointer, ptrstride); -} - -static void APIENTRY InitEdgeFlagPointerListIBM (GLint stride, const GLboolean* *pointer, GLint ptrstride) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glEdgeFlagPointerListIBM"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glEdgeFlagPointerListIBM = extproc; - - glEdgeFlagPointerListIBM(stride, pointer, ptrstride); -} - -static void APIENTRY InitFogCoordPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFogCoordPointerListIBM"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFogCoordPointerListIBM = extproc; - - glFogCoordPointerListIBM(type, stride, pointer, ptrstride); -} - -static void APIENTRY InitIndexPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glIndexPointerListIBM"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glIndexPointerListIBM = extproc; - - glIndexPointerListIBM(type, stride, pointer, ptrstride); -} - -static void APIENTRY InitNormalPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glNormalPointerListIBM"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glNormalPointerListIBM = extproc; - - glNormalPointerListIBM(type, stride, pointer, ptrstride); -} - -static void APIENTRY InitTexCoordPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoordPointerListIBM"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoordPointerListIBM = extproc; - - glTexCoordPointerListIBM(size, type, stride, pointer, ptrstride); -} - -static void APIENTRY InitVertexPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexPointerListIBM"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexPointerListIBM = extproc; - - glVertexPointerListIBM(size, type, stride, pointer, ptrstride); -} - -static void APIENTRY InitTbufferMask3DFX (GLuint mask) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTbufferMask3DFX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTbufferMask3DFX = extproc; - - glTbufferMask3DFX(mask); -} - -static void APIENTRY InitSampleMaskEXT (GLclampf value, GLboolean invert) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSampleMaskEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSampleMaskEXT = extproc; - - glSampleMaskEXT(value, invert); -} - -static void APIENTRY InitSamplePatternEXT (GLenum pattern) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSamplePatternEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSamplePatternEXT = extproc; - - glSamplePatternEXT(pattern); -} - -static void APIENTRY InitTextureColorMaskSGIS (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTextureColorMaskSGIS"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTextureColorMaskSGIS = extproc; - - glTextureColorMaskSGIS(red, green, blue, alpha); -} - -static void APIENTRY InitIglooInterfaceSGIX (GLenum pname, const GLvoid *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glIglooInterfaceSGIX"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glIglooInterfaceSGIX = extproc; - - glIglooInterfaceSGIX(pname, params); -} - -static void APIENTRY InitDeleteFencesNV (GLsizei n, const GLuint *fences) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDeleteFencesNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDeleteFencesNV = extproc; - - glDeleteFencesNV(n, fences); -} - -static void APIENTRY InitGenFencesNV (GLsizei n, GLuint *fences) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGenFencesNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGenFencesNV = extproc; - - glGenFencesNV(n, fences); -} - -static GLboolean APIENTRY InitIsFenceNV (GLuint fence) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glIsFenceNV"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glIsFenceNV = extproc; - - return glIsFenceNV(fence); -} - -static GLboolean APIENTRY InitTestFenceNV (GLuint fence) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTestFenceNV"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glTestFenceNV = extproc; - - return glTestFenceNV(fence); -} - -static void APIENTRY InitGetFenceivNV (GLuint fence, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetFenceivNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetFenceivNV = extproc; - - glGetFenceivNV(fence, pname, params); -} - -static void APIENTRY InitFinishFenceNV (GLuint fence) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFinishFenceNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFinishFenceNV = extproc; - - glFinishFenceNV(fence); -} - -static void APIENTRY InitSetFenceNV (GLuint fence, GLenum condition) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSetFenceNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSetFenceNV = extproc; - - glSetFenceNV(fence, condition); -} - -static void APIENTRY InitMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMapControlPointsNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMapControlPointsNV = extproc; - - glMapControlPointsNV(target, index, type, ustride, vstride, uorder, vorder, packed, points); -} - -static void APIENTRY InitMapParameterivNV (GLenum target, GLenum pname, const GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMapParameterivNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMapParameterivNV = extproc; - - glMapParameterivNV(target, pname, params); -} - -static void APIENTRY InitMapParameterfvNV (GLenum target, GLenum pname, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMapParameterfvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMapParameterfvNV = extproc; - - glMapParameterfvNV(target, pname, params); -} - -static void APIENTRY InitGetMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetMapControlPointsNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetMapControlPointsNV = extproc; - - glGetMapControlPointsNV(target, index, type, ustride, vstride, packed, points); -} - -static void APIENTRY InitGetMapParameterivNV (GLenum target, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetMapParameterivNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetMapParameterivNV = extproc; - - glGetMapParameterivNV(target, pname, params); -} - -static void APIENTRY InitGetMapParameterfvNV (GLenum target, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetMapParameterfvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetMapParameterfvNV = extproc; - - glGetMapParameterfvNV(target, pname, params); -} - -static void APIENTRY InitGetMapAttribParameterivNV (GLenum target, GLuint index, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetMapAttribParameterivNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetMapAttribParameterivNV = extproc; - - glGetMapAttribParameterivNV(target, index, pname, params); -} - -static void APIENTRY InitGetMapAttribParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetMapAttribParameterfvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetMapAttribParameterfvNV = extproc; - - glGetMapAttribParameterfvNV(target, index, pname, params); -} - -static void APIENTRY InitEvalMapsNV (GLenum target, GLenum mode) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glEvalMapsNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glEvalMapsNV = extproc; - - glEvalMapsNV(target, mode); -} - -static void APIENTRY InitCombinerStageParameterfvNV (GLenum stage, GLenum pname, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glCombinerStageParameterfvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glCombinerStageParameterfvNV = extproc; - - glCombinerStageParameterfvNV(stage, pname, params); -} - -static void APIENTRY InitGetCombinerStageParameterfvNV (GLenum stage, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetCombinerStageParameterfvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetCombinerStageParameterfvNV = extproc; - - glGetCombinerStageParameterfvNV(stage, pname, params); -} - -static GLboolean APIENTRY InitAreProgramsResidentNV (GLsizei n, const GLuint *programs, GLboolean *residences) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glAreProgramsResidentNV"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glAreProgramsResidentNV = extproc; - - return glAreProgramsResidentNV(n, programs, residences); -} - -static void APIENTRY InitBindProgramNV (GLenum target, GLuint id) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBindProgramNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBindProgramNV = extproc; - - glBindProgramNV(target, id); -} - -static void APIENTRY InitDeleteProgramsNV (GLsizei n, const GLuint *programs) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDeleteProgramsNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDeleteProgramsNV = extproc; - - glDeleteProgramsNV(n, programs); -} - -static void APIENTRY InitExecuteProgramNV (GLenum target, GLuint id, const GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glExecuteProgramNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glExecuteProgramNV = extproc; - - glExecuteProgramNV(target, id, params); -} - -static void APIENTRY InitGenProgramsNV (GLsizei n, GLuint *programs) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGenProgramsNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGenProgramsNV = extproc; - - glGenProgramsNV(n, programs); -} - -static void APIENTRY InitGetProgramParameterdvNV (GLenum target, GLuint index, GLenum pname, GLdouble *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetProgramParameterdvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetProgramParameterdvNV = extproc; - - glGetProgramParameterdvNV(target, index, pname, params); -} - -static void APIENTRY InitGetProgramParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetProgramParameterfvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetProgramParameterfvNV = extproc; - - glGetProgramParameterfvNV(target, index, pname, params); -} - -static void APIENTRY InitGetProgramivNV (GLuint id, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetProgramivNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetProgramivNV = extproc; - - glGetProgramivNV(id, pname, params); -} - -static void APIENTRY InitGetProgramStringNV (GLuint id, GLenum pname, GLubyte *program) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetProgramStringNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetProgramStringNV = extproc; - - glGetProgramStringNV(id, pname, program); -} - -static void APIENTRY InitGetTrackMatrixivNV (GLenum target, GLuint address, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetTrackMatrixivNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetTrackMatrixivNV = extproc; - - glGetTrackMatrixivNV(target, address, pname, params); -} - -static void APIENTRY InitGetVertexAttribdvNV (GLuint index, GLenum pname, GLdouble *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetVertexAttribdvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetVertexAttribdvNV = extproc; - - glGetVertexAttribdvNV(index, pname, params); -} - -static void APIENTRY InitGetVertexAttribfvNV (GLuint index, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetVertexAttribfvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetVertexAttribfvNV = extproc; - - glGetVertexAttribfvNV(index, pname, params); -} - -static void APIENTRY InitGetVertexAttribivNV (GLuint index, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetVertexAttribivNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetVertexAttribivNV = extproc; - - glGetVertexAttribivNV(index, pname, params); -} - -static void APIENTRY InitGetVertexAttribPointervNV (GLuint index, GLenum pname, GLvoid* *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetVertexAttribPointervNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetVertexAttribPointervNV = extproc; - - glGetVertexAttribPointervNV(index, pname, pointer); -} - -static GLboolean APIENTRY InitIsProgramNV (GLuint id) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glIsProgramNV"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glIsProgramNV = extproc; - - return glIsProgramNV(id); -} - -static void APIENTRY InitLoadProgramNV (GLenum target, GLuint id, GLsizei len, const GLubyte *program) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glLoadProgramNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glLoadProgramNV = extproc; - - glLoadProgramNV(target, id, len, program); -} - -static void APIENTRY InitProgramParameter4dNV (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glProgramParameter4dNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glProgramParameter4dNV = extproc; - - glProgramParameter4dNV(target, index, x, y, z, w); -} - -static void APIENTRY InitProgramParameter4dvNV (GLenum target, GLuint index, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glProgramParameter4dvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glProgramParameter4dvNV = extproc; - - glProgramParameter4dvNV(target, index, v); -} - -static void APIENTRY InitProgramParameter4fNV (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glProgramParameter4fNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glProgramParameter4fNV = extproc; - - glProgramParameter4fNV(target, index, x, y, z, w); -} - -static void APIENTRY InitProgramParameter4fvNV (GLenum target, GLuint index, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glProgramParameter4fvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glProgramParameter4fvNV = extproc; - - glProgramParameter4fvNV(target, index, v); -} - -static void APIENTRY InitProgramParameters4dvNV (GLenum target, GLuint index, GLuint count, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glProgramParameters4dvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glProgramParameters4dvNV = extproc; - - glProgramParameters4dvNV(target, index, count, v); -} - -static void APIENTRY InitProgramParameters4fvNV (GLenum target, GLuint index, GLuint count, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glProgramParameters4fvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glProgramParameters4fvNV = extproc; - - glProgramParameters4fvNV(target, index, count, v); -} - -static void APIENTRY InitRequestResidentProgramsNV (GLsizei n, const GLuint *programs) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glRequestResidentProgramsNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glRequestResidentProgramsNV = extproc; - - glRequestResidentProgramsNV(n, programs); -} - -static void APIENTRY InitTrackMatrixNV (GLenum target, GLuint address, GLenum matrix, GLenum transform) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTrackMatrixNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTrackMatrixNV = extproc; - - glTrackMatrixNV(target, address, matrix, transform); -} - -static void APIENTRY InitVertexAttribPointerNV (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribPointerNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribPointerNV = extproc; - - glVertexAttribPointerNV(index, fsize, type, stride, pointer); -} - -static void APIENTRY InitVertexAttrib1dNV (GLuint index, GLdouble x) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib1dNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib1dNV = extproc; - - glVertexAttrib1dNV(index, x); -} - -static void APIENTRY InitVertexAttrib1dvNV (GLuint index, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib1dvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib1dvNV = extproc; - - glVertexAttrib1dvNV(index, v); -} - -static void APIENTRY InitVertexAttrib1fNV (GLuint index, GLfloat x) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib1fNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib1fNV = extproc; - - glVertexAttrib1fNV(index, x); -} - -static void APIENTRY InitVertexAttrib1fvNV (GLuint index, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib1fvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib1fvNV = extproc; - - glVertexAttrib1fvNV(index, v); -} - -static void APIENTRY InitVertexAttrib1sNV (GLuint index, GLshort x) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib1sNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib1sNV = extproc; - - glVertexAttrib1sNV(index, x); -} - -static void APIENTRY InitVertexAttrib1svNV (GLuint index, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib1svNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib1svNV = extproc; - - glVertexAttrib1svNV(index, v); -} - -static void APIENTRY InitVertexAttrib2dNV (GLuint index, GLdouble x, GLdouble y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib2dNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib2dNV = extproc; - - glVertexAttrib2dNV(index, x, y); -} - -static void APIENTRY InitVertexAttrib2dvNV (GLuint index, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib2dvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib2dvNV = extproc; - - glVertexAttrib2dvNV(index, v); -} - -static void APIENTRY InitVertexAttrib2fNV (GLuint index, GLfloat x, GLfloat y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib2fNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib2fNV = extproc; - - glVertexAttrib2fNV(index, x, y); -} - -static void APIENTRY InitVertexAttrib2fvNV (GLuint index, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib2fvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib2fvNV = extproc; - - glVertexAttrib2fvNV(index, v); -} - -static void APIENTRY InitVertexAttrib2sNV (GLuint index, GLshort x, GLshort y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib2sNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib2sNV = extproc; - - glVertexAttrib2sNV(index, x, y); -} - -static void APIENTRY InitVertexAttrib2svNV (GLuint index, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib2svNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib2svNV = extproc; - - glVertexAttrib2svNV(index, v); -} - -static void APIENTRY InitVertexAttrib3dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib3dNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib3dNV = extproc; - - glVertexAttrib3dNV(index, x, y, z); -} - -static void APIENTRY InitVertexAttrib3dvNV (GLuint index, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib3dvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib3dvNV = extproc; - - glVertexAttrib3dvNV(index, v); -} - -static void APIENTRY InitVertexAttrib3fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib3fNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib3fNV = extproc; - - glVertexAttrib3fNV(index, x, y, z); -} - -static void APIENTRY InitVertexAttrib3fvNV (GLuint index, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib3fvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib3fvNV = extproc; - - glVertexAttrib3fvNV(index, v); -} - -static void APIENTRY InitVertexAttrib3sNV (GLuint index, GLshort x, GLshort y, GLshort z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib3sNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib3sNV = extproc; - - glVertexAttrib3sNV(index, x, y, z); -} - -static void APIENTRY InitVertexAttrib3svNV (GLuint index, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib3svNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib3svNV = extproc; - - glVertexAttrib3svNV(index, v); -} - -static void APIENTRY InitVertexAttrib4dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4dNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4dNV = extproc; - - glVertexAttrib4dNV(index, x, y, z, w); -} - -static void APIENTRY InitVertexAttrib4dvNV (GLuint index, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4dvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4dvNV = extproc; - - glVertexAttrib4dvNV(index, v); -} - -static void APIENTRY InitVertexAttrib4fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4fNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4fNV = extproc; - - glVertexAttrib4fNV(index, x, y, z, w); -} - -static void APIENTRY InitVertexAttrib4fvNV (GLuint index, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4fvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4fvNV = extproc; - - glVertexAttrib4fvNV(index, v); -} - -static void APIENTRY InitVertexAttrib4sNV (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4sNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4sNV = extproc; - - glVertexAttrib4sNV(index, x, y, z, w); -} - -static void APIENTRY InitVertexAttrib4svNV (GLuint index, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4svNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4svNV = extproc; - - glVertexAttrib4svNV(index, v); -} - -static void APIENTRY InitVertexAttrib4ubNV (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4ubNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4ubNV = extproc; - - glVertexAttrib4ubNV(index, x, y, z, w); -} - -static void APIENTRY InitVertexAttrib4ubvNV (GLuint index, const GLubyte *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4ubvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4ubvNV = extproc; - - glVertexAttrib4ubvNV(index, v); -} - -static void APIENTRY InitVertexAttribs1dvNV (GLuint index, GLsizei count, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribs1dvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribs1dvNV = extproc; - - glVertexAttribs1dvNV(index, count, v); -} - -static void APIENTRY InitVertexAttribs1fvNV (GLuint index, GLsizei count, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribs1fvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribs1fvNV = extproc; - - glVertexAttribs1fvNV(index, count, v); -} - -static void APIENTRY InitVertexAttribs1svNV (GLuint index, GLsizei count, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribs1svNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribs1svNV = extproc; - - glVertexAttribs1svNV(index, count, v); -} - -static void APIENTRY InitVertexAttribs2dvNV (GLuint index, GLsizei count, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribs2dvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribs2dvNV = extproc; - - glVertexAttribs2dvNV(index, count, v); -} - -static void APIENTRY InitVertexAttribs2fvNV (GLuint index, GLsizei count, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribs2fvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribs2fvNV = extproc; - - glVertexAttribs2fvNV(index, count, v); -} - -static void APIENTRY InitVertexAttribs2svNV (GLuint index, GLsizei count, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribs2svNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribs2svNV = extproc; - - glVertexAttribs2svNV(index, count, v); -} - -static void APIENTRY InitVertexAttribs3dvNV (GLuint index, GLsizei count, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribs3dvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribs3dvNV = extproc; - - glVertexAttribs3dvNV(index, count, v); -} - -static void APIENTRY InitVertexAttribs3fvNV (GLuint index, GLsizei count, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribs3fvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribs3fvNV = extproc; - - glVertexAttribs3fvNV(index, count, v); -} - -static void APIENTRY InitVertexAttribs3svNV (GLuint index, GLsizei count, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribs3svNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribs3svNV = extproc; - - glVertexAttribs3svNV(index, count, v); -} - -static void APIENTRY InitVertexAttribs4dvNV (GLuint index, GLsizei count, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribs4dvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribs4dvNV = extproc; - - glVertexAttribs4dvNV(index, count, v); -} - -static void APIENTRY InitVertexAttribs4fvNV (GLuint index, GLsizei count, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribs4fvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribs4fvNV = extproc; - - glVertexAttribs4fvNV(index, count, v); -} - -static void APIENTRY InitVertexAttribs4svNV (GLuint index, GLsizei count, const GLshort *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribs4svNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribs4svNV = extproc; - - glVertexAttribs4svNV(index, count, v); -} - -static void APIENTRY InitVertexAttribs4ubvNV (GLuint index, GLsizei count, const GLubyte *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribs4ubvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribs4ubvNV = extproc; - - glVertexAttribs4ubvNV(index, count, v); -} - -static void APIENTRY InitTexBumpParameterivATI (GLenum pname, const GLint *param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexBumpParameterivATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexBumpParameterivATI = extproc; - - glTexBumpParameterivATI(pname, param); -} - -static void APIENTRY InitTexBumpParameterfvATI (GLenum pname, const GLfloat *param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexBumpParameterfvATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexBumpParameterfvATI = extproc; - - glTexBumpParameterfvATI(pname, param); -} - -static void APIENTRY InitGetTexBumpParameterivATI (GLenum pname, GLint *param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetTexBumpParameterivATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetTexBumpParameterivATI = extproc; - - glGetTexBumpParameterivATI(pname, param); -} - -static void APIENTRY InitGetTexBumpParameterfvATI (GLenum pname, GLfloat *param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetTexBumpParameterfvATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetTexBumpParameterfvATI = extproc; - - glGetTexBumpParameterfvATI(pname, param); -} - -static GLuint APIENTRY InitGenFragmentShadersATI (GLuint range) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGenFragmentShadersATI"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glGenFragmentShadersATI = extproc; - - return glGenFragmentShadersATI(range); -} - -static void APIENTRY InitBindFragmentShaderATI (GLuint id) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBindFragmentShaderATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBindFragmentShaderATI = extproc; - - glBindFragmentShaderATI(id); -} - -static void APIENTRY InitDeleteFragmentShaderATI (GLuint id) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDeleteFragmentShaderATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDeleteFragmentShaderATI = extproc; - - glDeleteFragmentShaderATI(id); -} - -static void APIENTRY InitBeginFragmentShaderATI (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBeginFragmentShaderATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBeginFragmentShaderATI = extproc; - - glBeginFragmentShaderATI(); -} - -static void APIENTRY InitEndFragmentShaderATI (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glEndFragmentShaderATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glEndFragmentShaderATI = extproc; - - glEndFragmentShaderATI(); -} - -static void APIENTRY InitPassTexCoordATI (GLuint dst, GLuint coord, GLenum swizzle) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPassTexCoordATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPassTexCoordATI = extproc; - - glPassTexCoordATI(dst, coord, swizzle); -} - -static void APIENTRY InitSampleMapATI (GLuint dst, GLuint interp, GLenum swizzle) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSampleMapATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSampleMapATI = extproc; - - glSampleMapATI(dst, interp, swizzle); -} - -static void APIENTRY InitColorFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColorFragmentOp1ATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColorFragmentOp1ATI = extproc; - - glColorFragmentOp1ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod); -} - -static void APIENTRY InitColorFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColorFragmentOp2ATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColorFragmentOp2ATI = extproc; - - glColorFragmentOp2ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod); -} - -static void APIENTRY InitColorFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColorFragmentOp3ATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColorFragmentOp3ATI = extproc; - - glColorFragmentOp3ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, arg3Rep, arg3Mod); -} - -static void APIENTRY InitAlphaFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glAlphaFragmentOp1ATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glAlphaFragmentOp1ATI = extproc; - - glAlphaFragmentOp1ATI(op, dst, dstMod, arg1, arg1Rep, arg1Mod); -} - -static void APIENTRY InitAlphaFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glAlphaFragmentOp2ATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glAlphaFragmentOp2ATI = extproc; - - glAlphaFragmentOp2ATI(op, dst, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod); -} - -static void APIENTRY InitAlphaFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glAlphaFragmentOp3ATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glAlphaFragmentOp3ATI = extproc; - - glAlphaFragmentOp3ATI(op, dst, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, arg3Rep, arg3Mod); -} - -static void APIENTRY InitSetFragmentShaderConstantATI (GLuint dst, const GLfloat *value) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSetFragmentShaderConstantATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSetFragmentShaderConstantATI = extproc; - - glSetFragmentShaderConstantATI(dst, value); -} - -static void APIENTRY InitPNTrianglesiATI (GLenum pname, GLint param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPNTrianglesiATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPNTrianglesiATI = extproc; - - glPNTrianglesiATI(pname, param); -} - -static void APIENTRY InitPNTrianglesfATI (GLenum pname, GLfloat param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPNTrianglesfATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPNTrianglesfATI = extproc; - - glPNTrianglesfATI(pname, param); -} - -static GLuint APIENTRY InitNewObjectBufferATI (GLsizei size, const GLvoid *pointer, GLenum usage) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glNewObjectBufferATI"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glNewObjectBufferATI = extproc; - - return glNewObjectBufferATI(size, pointer, usage); -} - -static GLboolean APIENTRY InitIsObjectBufferATI (GLuint buffer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glIsObjectBufferATI"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glIsObjectBufferATI = extproc; - - return glIsObjectBufferATI(buffer); -} - -static void APIENTRY InitUpdateObjectBufferATI (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUpdateObjectBufferATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUpdateObjectBufferATI = extproc; - - glUpdateObjectBufferATI(buffer, offset, size, pointer, preserve); -} - -static void APIENTRY InitGetObjectBufferfvATI (GLuint buffer, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetObjectBufferfvATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetObjectBufferfvATI = extproc; - - glGetObjectBufferfvATI(buffer, pname, params); -} - -static void APIENTRY InitGetObjectBufferivATI (GLuint buffer, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetObjectBufferivATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetObjectBufferivATI = extproc; - - glGetObjectBufferivATI(buffer, pname, params); -} - -static void APIENTRY InitFreeObjectBufferATI (GLuint buffer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFreeObjectBufferATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFreeObjectBufferATI = extproc; - - glFreeObjectBufferATI(buffer); -} - -static void APIENTRY InitArrayObjectATI (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glArrayObjectATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glArrayObjectATI = extproc; - - glArrayObjectATI(array, size, type, stride, buffer, offset); -} - -static void APIENTRY InitGetArrayObjectfvATI (GLenum array, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetArrayObjectfvATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetArrayObjectfvATI = extproc; - - glGetArrayObjectfvATI(array, pname, params); -} - -static void APIENTRY InitGetArrayObjectivATI (GLenum array, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetArrayObjectivATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetArrayObjectivATI = extproc; - - glGetArrayObjectivATI(array, pname, params); -} - -static void APIENTRY InitVariantArrayObjectATI (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVariantArrayObjectATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVariantArrayObjectATI = extproc; - - glVariantArrayObjectATI(id, type, stride, buffer, offset); -} - -static void APIENTRY InitGetVariantArrayObjectfvATI (GLuint id, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetVariantArrayObjectfvATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetVariantArrayObjectfvATI = extproc; - - glGetVariantArrayObjectfvATI(id, pname, params); -} - -static void APIENTRY InitGetVariantArrayObjectivATI (GLuint id, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetVariantArrayObjectivATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetVariantArrayObjectivATI = extproc; - - glGetVariantArrayObjectivATI(id, pname, params); -} - -static void APIENTRY InitBeginVertexShaderEXT (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBeginVertexShaderEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBeginVertexShaderEXT = extproc; - - glBeginVertexShaderEXT(); -} - -static void APIENTRY InitEndVertexShaderEXT (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glEndVertexShaderEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glEndVertexShaderEXT = extproc; - - glEndVertexShaderEXT(); -} - -static void APIENTRY InitBindVertexShaderEXT (GLuint id) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBindVertexShaderEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBindVertexShaderEXT = extproc; - - glBindVertexShaderEXT(id); -} - -static GLuint APIENTRY InitGenVertexShadersEXT (GLuint range) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGenVertexShadersEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glGenVertexShadersEXT = extproc; - - return glGenVertexShadersEXT(range); -} - -static void APIENTRY InitDeleteVertexShaderEXT (GLuint id) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDeleteVertexShaderEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDeleteVertexShaderEXT = extproc; - - glDeleteVertexShaderEXT(id); -} - -static void APIENTRY InitShaderOp1EXT (GLenum op, GLuint res, GLuint arg1) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glShaderOp1EXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glShaderOp1EXT = extproc; - - glShaderOp1EXT(op, res, arg1); -} - -static void APIENTRY InitShaderOp2EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glShaderOp2EXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glShaderOp2EXT = extproc; - - glShaderOp2EXT(op, res, arg1, arg2); -} - -static void APIENTRY InitShaderOp3EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glShaderOp3EXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glShaderOp3EXT = extproc; - - glShaderOp3EXT(op, res, arg1, arg2, arg3); -} - -static void APIENTRY InitSwizzleEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSwizzleEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSwizzleEXT = extproc; - - glSwizzleEXT(res, in, outX, outY, outZ, outW); -} - -static void APIENTRY InitWriteMaskEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glWriteMaskEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glWriteMaskEXT = extproc; - - glWriteMaskEXT(res, in, outX, outY, outZ, outW); -} - -static void APIENTRY InitInsertComponentEXT (GLuint res, GLuint src, GLuint num) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glInsertComponentEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glInsertComponentEXT = extproc; - - glInsertComponentEXT(res, src, num); -} - -static void APIENTRY InitExtractComponentEXT (GLuint res, GLuint src, GLuint num) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glExtractComponentEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glExtractComponentEXT = extproc; - - glExtractComponentEXT(res, src, num); -} - -static GLuint APIENTRY InitGenSymbolsEXT (GLenum datatype, GLenum storagetype, GLenum range, GLuint components) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGenSymbolsEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glGenSymbolsEXT = extproc; - - return glGenSymbolsEXT(datatype, storagetype, range, components); -} - -static void APIENTRY InitSetInvariantEXT (GLuint id, GLenum type, const GLvoid *addr) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSetInvariantEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSetInvariantEXT = extproc; - - glSetInvariantEXT(id, type, addr); -} - -static void APIENTRY InitSetLocalConstantEXT (GLuint id, GLenum type, const GLvoid *addr) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSetLocalConstantEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSetLocalConstantEXT = extproc; - - glSetLocalConstantEXT(id, type, addr); -} - -static void APIENTRY InitVariantbvEXT (GLuint id, const GLbyte *addr) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVariantbvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVariantbvEXT = extproc; - - glVariantbvEXT(id, addr); -} - -static void APIENTRY InitVariantsvEXT (GLuint id, const GLshort *addr) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVariantsvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVariantsvEXT = extproc; - - glVariantsvEXT(id, addr); -} - -static void APIENTRY InitVariantivEXT (GLuint id, const GLint *addr) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVariantivEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVariantivEXT = extproc; - - glVariantivEXT(id, addr); -} - -static void APIENTRY InitVariantfvEXT (GLuint id, const GLfloat *addr) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVariantfvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVariantfvEXT = extproc; - - glVariantfvEXT(id, addr); -} - -static void APIENTRY InitVariantdvEXT (GLuint id, const GLdouble *addr) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVariantdvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVariantdvEXT = extproc; - - glVariantdvEXT(id, addr); -} - -static void APIENTRY InitVariantubvEXT (GLuint id, const GLubyte *addr) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVariantubvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVariantubvEXT = extproc; - - glVariantubvEXT(id, addr); -} - -static void APIENTRY InitVariantusvEXT (GLuint id, const GLushort *addr) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVariantusvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVariantusvEXT = extproc; - - glVariantusvEXT(id, addr); -} - -static void APIENTRY InitVariantuivEXT (GLuint id, const GLuint *addr) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVariantuivEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVariantuivEXT = extproc; - - glVariantuivEXT(id, addr); -} - -static void APIENTRY InitVariantPointerEXT (GLuint id, GLenum type, GLuint stride, const GLvoid *addr) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVariantPointerEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVariantPointerEXT = extproc; - - glVariantPointerEXT(id, type, stride, addr); -} - -static void APIENTRY InitEnableVariantClientStateEXT (GLuint id) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glEnableVariantClientStateEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glEnableVariantClientStateEXT = extproc; - - glEnableVariantClientStateEXT(id); -} - -static void APIENTRY InitDisableVariantClientStateEXT (GLuint id) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDisableVariantClientStateEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDisableVariantClientStateEXT = extproc; - - glDisableVariantClientStateEXT(id); -} - -static GLuint APIENTRY InitBindLightParameterEXT (GLenum light, GLenum value) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBindLightParameterEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glBindLightParameterEXT = extproc; - - return glBindLightParameterEXT(light, value); -} - -static GLuint APIENTRY InitBindMaterialParameterEXT (GLenum face, GLenum value) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBindMaterialParameterEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glBindMaterialParameterEXT = extproc; - - return glBindMaterialParameterEXT(face, value); -} - -static GLuint APIENTRY InitBindTexGenParameterEXT (GLenum unit, GLenum coord, GLenum value) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBindTexGenParameterEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glBindTexGenParameterEXT = extproc; - - return glBindTexGenParameterEXT(unit, coord, value); -} - -static GLuint APIENTRY InitBindTextureUnitParameterEXT (GLenum unit, GLenum value) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBindTextureUnitParameterEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glBindTextureUnitParameterEXT = extproc; - - return glBindTextureUnitParameterEXT(unit, value); -} - -static GLuint APIENTRY InitBindParameterEXT (GLenum value) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBindParameterEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glBindParameterEXT = extproc; - - return glBindParameterEXT(value); -} - -static GLboolean APIENTRY InitIsVariantEnabledEXT (GLuint id, GLenum cap) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glIsVariantEnabledEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glIsVariantEnabledEXT = extproc; - - return glIsVariantEnabledEXT(id, cap); -} - -static void APIENTRY InitGetVariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetVariantBooleanvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetVariantBooleanvEXT = extproc; - - glGetVariantBooleanvEXT(id, value, data); -} - -static void APIENTRY InitGetVariantIntegervEXT (GLuint id, GLenum value, GLint *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetVariantIntegervEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetVariantIntegervEXT = extproc; - - glGetVariantIntegervEXT(id, value, data); -} - -static void APIENTRY InitGetVariantFloatvEXT (GLuint id, GLenum value, GLfloat *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetVariantFloatvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetVariantFloatvEXT = extproc; - - glGetVariantFloatvEXT(id, value, data); -} - -static void APIENTRY InitGetVariantPointervEXT (GLuint id, GLenum value, GLvoid* *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetVariantPointervEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetVariantPointervEXT = extproc; - - glGetVariantPointervEXT(id, value, data); -} - -static void APIENTRY InitGetInvariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetInvariantBooleanvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetInvariantBooleanvEXT = extproc; - - glGetInvariantBooleanvEXT(id, value, data); -} - -static void APIENTRY InitGetInvariantIntegervEXT (GLuint id, GLenum value, GLint *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetInvariantIntegervEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetInvariantIntegervEXT = extproc; - - glGetInvariantIntegervEXT(id, value, data); -} - -static void APIENTRY InitGetInvariantFloatvEXT (GLuint id, GLenum value, GLfloat *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetInvariantFloatvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetInvariantFloatvEXT = extproc; - - glGetInvariantFloatvEXT(id, value, data); -} - -static void APIENTRY InitGetLocalConstantBooleanvEXT (GLuint id, GLenum value, GLboolean *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetLocalConstantBooleanvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetLocalConstantBooleanvEXT = extproc; - - glGetLocalConstantBooleanvEXT(id, value, data); -} - -static void APIENTRY InitGetLocalConstantIntegervEXT (GLuint id, GLenum value, GLint *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetLocalConstantIntegervEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetLocalConstantIntegervEXT = extproc; - - glGetLocalConstantIntegervEXT(id, value, data); -} - -static void APIENTRY InitGetLocalConstantFloatvEXT (GLuint id, GLenum value, GLfloat *data) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetLocalConstantFloatvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetLocalConstantFloatvEXT = extproc; - - glGetLocalConstantFloatvEXT(id, value, data); -} - -static void APIENTRY InitVertexStream1sATI (GLenum stream, GLshort x) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream1sATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream1sATI = extproc; - - glVertexStream1sATI(stream, x); -} - -static void APIENTRY InitVertexStream1svATI (GLenum stream, const GLshort *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream1svATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream1svATI = extproc; - - glVertexStream1svATI(stream, coords); -} - -static void APIENTRY InitVertexStream1iATI (GLenum stream, GLint x) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream1iATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream1iATI = extproc; - - glVertexStream1iATI(stream, x); -} - -static void APIENTRY InitVertexStream1ivATI (GLenum stream, const GLint *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream1ivATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream1ivATI = extproc; - - glVertexStream1ivATI(stream, coords); -} - -static void APIENTRY InitVertexStream1fATI (GLenum stream, GLfloat x) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream1fATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream1fATI = extproc; - - glVertexStream1fATI(stream, x); -} - -static void APIENTRY InitVertexStream1fvATI (GLenum stream, const GLfloat *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream1fvATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream1fvATI = extproc; - - glVertexStream1fvATI(stream, coords); -} - -static void APIENTRY InitVertexStream1dATI (GLenum stream, GLdouble x) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream1dATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream1dATI = extproc; - - glVertexStream1dATI(stream, x); -} - -static void APIENTRY InitVertexStream1dvATI (GLenum stream, const GLdouble *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream1dvATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream1dvATI = extproc; - - glVertexStream1dvATI(stream, coords); -} - -static void APIENTRY InitVertexStream2sATI (GLenum stream, GLshort x, GLshort y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream2sATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream2sATI = extproc; - - glVertexStream2sATI(stream, x, y); -} - -static void APIENTRY InitVertexStream2svATI (GLenum stream, const GLshort *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream2svATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream2svATI = extproc; - - glVertexStream2svATI(stream, coords); -} - -static void APIENTRY InitVertexStream2iATI (GLenum stream, GLint x, GLint y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream2iATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream2iATI = extproc; - - glVertexStream2iATI(stream, x, y); -} - -static void APIENTRY InitVertexStream2ivATI (GLenum stream, const GLint *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream2ivATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream2ivATI = extproc; - - glVertexStream2ivATI(stream, coords); -} - -static void APIENTRY InitVertexStream2fATI (GLenum stream, GLfloat x, GLfloat y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream2fATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream2fATI = extproc; - - glVertexStream2fATI(stream, x, y); -} - -static void APIENTRY InitVertexStream2fvATI (GLenum stream, const GLfloat *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream2fvATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream2fvATI = extproc; - - glVertexStream2fvATI(stream, coords); -} - -static void APIENTRY InitVertexStream2dATI (GLenum stream, GLdouble x, GLdouble y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream2dATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream2dATI = extproc; - - glVertexStream2dATI(stream, x, y); -} - -static void APIENTRY InitVertexStream2dvATI (GLenum stream, const GLdouble *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream2dvATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream2dvATI = extproc; - - glVertexStream2dvATI(stream, coords); -} - -static void APIENTRY InitVertexStream3sATI (GLenum stream, GLshort x, GLshort y, GLshort z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream3sATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream3sATI = extproc; - - glVertexStream3sATI(stream, x, y, z); -} - -static void APIENTRY InitVertexStream3svATI (GLenum stream, const GLshort *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream3svATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream3svATI = extproc; - - glVertexStream3svATI(stream, coords); -} - -static void APIENTRY InitVertexStream3iATI (GLenum stream, GLint x, GLint y, GLint z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream3iATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream3iATI = extproc; - - glVertexStream3iATI(stream, x, y, z); -} - -static void APIENTRY InitVertexStream3ivATI (GLenum stream, const GLint *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream3ivATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream3ivATI = extproc; - - glVertexStream3ivATI(stream, coords); -} - -static void APIENTRY InitVertexStream3fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream3fATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream3fATI = extproc; - - glVertexStream3fATI(stream, x, y, z); -} - -static void APIENTRY InitVertexStream3fvATI (GLenum stream, const GLfloat *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream3fvATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream3fvATI = extproc; - - glVertexStream3fvATI(stream, coords); -} - -static void APIENTRY InitVertexStream3dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream3dATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream3dATI = extproc; - - glVertexStream3dATI(stream, x, y, z); -} - -static void APIENTRY InitVertexStream3dvATI (GLenum stream, const GLdouble *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream3dvATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream3dvATI = extproc; - - glVertexStream3dvATI(stream, coords); -} - -static void APIENTRY InitVertexStream4sATI (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream4sATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream4sATI = extproc; - - glVertexStream4sATI(stream, x, y, z, w); -} - -static void APIENTRY InitVertexStream4svATI (GLenum stream, const GLshort *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream4svATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream4svATI = extproc; - - glVertexStream4svATI(stream, coords); -} - -static void APIENTRY InitVertexStream4iATI (GLenum stream, GLint x, GLint y, GLint z, GLint w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream4iATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream4iATI = extproc; - - glVertexStream4iATI(stream, x, y, z, w); -} - -static void APIENTRY InitVertexStream4ivATI (GLenum stream, const GLint *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream4ivATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream4ivATI = extproc; - - glVertexStream4ivATI(stream, coords); -} - -static void APIENTRY InitVertexStream4fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream4fATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream4fATI = extproc; - - glVertexStream4fATI(stream, x, y, z, w); -} - -static void APIENTRY InitVertexStream4fvATI (GLenum stream, const GLfloat *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream4fvATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream4fvATI = extproc; - - glVertexStream4fvATI(stream, coords); -} - -static void APIENTRY InitVertexStream4dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream4dATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream4dATI = extproc; - - glVertexStream4dATI(stream, x, y, z, w); -} - -static void APIENTRY InitVertexStream4dvATI (GLenum stream, const GLdouble *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexStream4dvATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexStream4dvATI = extproc; - - glVertexStream4dvATI(stream, coords); -} - -static void APIENTRY InitNormalStream3bATI (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glNormalStream3bATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glNormalStream3bATI = extproc; - - glNormalStream3bATI(stream, nx, ny, nz); -} - -static void APIENTRY InitNormalStream3bvATI (GLenum stream, const GLbyte *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glNormalStream3bvATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glNormalStream3bvATI = extproc; - - glNormalStream3bvATI(stream, coords); -} - -static void APIENTRY InitNormalStream3sATI (GLenum stream, GLshort nx, GLshort ny, GLshort nz) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glNormalStream3sATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glNormalStream3sATI = extproc; - - glNormalStream3sATI(stream, nx, ny, nz); -} - -static void APIENTRY InitNormalStream3svATI (GLenum stream, const GLshort *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glNormalStream3svATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glNormalStream3svATI = extproc; - - glNormalStream3svATI(stream, coords); -} - -static void APIENTRY InitNormalStream3iATI (GLenum stream, GLint nx, GLint ny, GLint nz) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glNormalStream3iATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glNormalStream3iATI = extproc; - - glNormalStream3iATI(stream, nx, ny, nz); -} - -static void APIENTRY InitNormalStream3ivATI (GLenum stream, const GLint *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glNormalStream3ivATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glNormalStream3ivATI = extproc; - - glNormalStream3ivATI(stream, coords); -} - -static void APIENTRY InitNormalStream3fATI (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glNormalStream3fATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glNormalStream3fATI = extproc; - - glNormalStream3fATI(stream, nx, ny, nz); -} - -static void APIENTRY InitNormalStream3fvATI (GLenum stream, const GLfloat *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glNormalStream3fvATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glNormalStream3fvATI = extproc; - - glNormalStream3fvATI(stream, coords); -} - -static void APIENTRY InitNormalStream3dATI (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glNormalStream3dATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glNormalStream3dATI = extproc; - - glNormalStream3dATI(stream, nx, ny, nz); -} - -static void APIENTRY InitNormalStream3dvATI (GLenum stream, const GLdouble *coords) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glNormalStream3dvATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glNormalStream3dvATI = extproc; - - glNormalStream3dvATI(stream, coords); -} - -static void APIENTRY InitClientActiveVertexStreamATI (GLenum stream) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glClientActiveVertexStreamATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glClientActiveVertexStreamATI = extproc; - - glClientActiveVertexStreamATI(stream); -} - -static void APIENTRY InitVertexBlendEnviATI (GLenum pname, GLint param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexBlendEnviATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexBlendEnviATI = extproc; - - glVertexBlendEnviATI(pname, param); -} - -static void APIENTRY InitVertexBlendEnvfATI (GLenum pname, GLfloat param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexBlendEnvfATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexBlendEnvfATI = extproc; - - glVertexBlendEnvfATI(pname, param); -} - -static void APIENTRY InitElementPointerATI (GLenum type, const GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glElementPointerATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glElementPointerATI = extproc; - - glElementPointerATI(type, pointer); -} - -static void APIENTRY InitDrawElementArrayATI (GLenum mode, GLsizei count) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDrawElementArrayATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDrawElementArrayATI = extproc; - - glDrawElementArrayATI(mode, count); -} - -static void APIENTRY InitDrawRangeElementArrayATI (GLenum mode, GLuint start, GLuint end, GLsizei count) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDrawRangeElementArrayATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDrawRangeElementArrayATI = extproc; - - glDrawRangeElementArrayATI(mode, start, end, count); -} - -static void APIENTRY InitDrawMeshArraysSUN (GLenum mode, GLint first, GLsizei count, GLsizei width) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDrawMeshArraysSUN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDrawMeshArraysSUN = extproc; - - glDrawMeshArraysSUN(mode, first, count, width); -} - -static void APIENTRY InitGenOcclusionQueriesNV (GLsizei n, GLuint *ids) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGenOcclusionQueriesNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGenOcclusionQueriesNV = extproc; - - glGenOcclusionQueriesNV(n, ids); -} - -static void APIENTRY InitDeleteOcclusionQueriesNV (GLsizei n, const GLuint *ids) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDeleteOcclusionQueriesNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDeleteOcclusionQueriesNV = extproc; - - glDeleteOcclusionQueriesNV(n, ids); -} - -static GLboolean APIENTRY InitIsOcclusionQueryNV (GLuint id) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glIsOcclusionQueryNV"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glIsOcclusionQueryNV = extproc; - - return glIsOcclusionQueryNV(id); -} - -static void APIENTRY InitBeginOcclusionQueryNV (GLuint id) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBeginOcclusionQueryNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBeginOcclusionQueryNV = extproc; - - glBeginOcclusionQueryNV(id); -} - -static void APIENTRY InitEndOcclusionQueryNV (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glEndOcclusionQueryNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glEndOcclusionQueryNV = extproc; - - glEndOcclusionQueryNV(); -} - -static void APIENTRY InitGetOcclusionQueryivNV (GLuint id, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetOcclusionQueryivNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetOcclusionQueryivNV = extproc; - - glGetOcclusionQueryivNV(id, pname, params); -} - -static void APIENTRY InitGetOcclusionQueryuivNV (GLuint id, GLenum pname, GLuint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetOcclusionQueryuivNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetOcclusionQueryuivNV = extproc; - - glGetOcclusionQueryuivNV(id, pname, params); -} - -static void APIENTRY InitPointParameteriNV (GLenum pname, GLint param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPointParameteriNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPointParameteriNV = extproc; - - glPointParameteriNV(pname, param); -} - -static void APIENTRY InitPointParameterivNV (GLenum pname, const GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPointParameterivNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPointParameterivNV = extproc; - - glPointParameterivNV(pname, params); -} - -static void APIENTRY InitActiveStencilFaceEXT (GLenum face) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glActiveStencilFaceEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glActiveStencilFaceEXT = extproc; - - glActiveStencilFaceEXT(face); -} - -static void APIENTRY InitElementPointerAPPLE (GLenum type, const GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glElementPointerAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glElementPointerAPPLE = extproc; - - glElementPointerAPPLE(type, pointer); -} - -static void APIENTRY InitDrawElementArrayAPPLE (GLenum mode, GLint first, GLsizei count) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDrawElementArrayAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDrawElementArrayAPPLE = extproc; - - glDrawElementArrayAPPLE(mode, first, count); -} - -static void APIENTRY InitDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDrawRangeElementArrayAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDrawRangeElementArrayAPPLE = extproc; - - glDrawRangeElementArrayAPPLE(mode, start, end, first, count); -} - -static void APIENTRY InitMultiDrawElementArrayAPPLE (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiDrawElementArrayAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiDrawElementArrayAPPLE = extproc; - - glMultiDrawElementArrayAPPLE(mode, first, count, primcount); -} - -static void APIENTRY InitMultiDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiDrawRangeElementArrayAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiDrawRangeElementArrayAPPLE = extproc; - - glMultiDrawRangeElementArrayAPPLE(mode, start, end, first, count, primcount); -} - -static void APIENTRY InitGenFencesAPPLE (GLsizei n, GLuint *fences) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGenFencesAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGenFencesAPPLE = extproc; - - glGenFencesAPPLE(n, fences); -} - -static void APIENTRY InitDeleteFencesAPPLE (GLsizei n, const GLuint *fences) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDeleteFencesAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDeleteFencesAPPLE = extproc; - - glDeleteFencesAPPLE(n, fences); -} - -static void APIENTRY InitSetFenceAPPLE (GLuint fence) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSetFenceAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSetFenceAPPLE = extproc; - - glSetFenceAPPLE(fence); -} - -static GLboolean APIENTRY InitIsFenceAPPLE (GLuint fence) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glIsFenceAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glIsFenceAPPLE = extproc; - - return glIsFenceAPPLE(fence); -} - -static GLboolean APIENTRY InitTestFenceAPPLE (GLuint fence) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTestFenceAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glTestFenceAPPLE = extproc; - - return glTestFenceAPPLE(fence); -} - -static void APIENTRY InitFinishFenceAPPLE (GLuint fence) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFinishFenceAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFinishFenceAPPLE = extproc; - - glFinishFenceAPPLE(fence); -} - -static GLboolean APIENTRY InitTestObjectAPPLE (GLenum object, GLuint name) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTestObjectAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glTestObjectAPPLE = extproc; - - return glTestObjectAPPLE(object, name); -} - -static void APIENTRY InitFinishObjectAPPLE (GLenum object, GLint name) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFinishObjectAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFinishObjectAPPLE = extproc; - - glFinishObjectAPPLE(object, name); -} - -static void APIENTRY InitBindVertexArrayAPPLE (GLuint array) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBindVertexArrayAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBindVertexArrayAPPLE = extproc; - - glBindVertexArrayAPPLE(array); -} - -static void APIENTRY InitDeleteVertexArraysAPPLE (GLsizei n, const GLuint *arrays) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDeleteVertexArraysAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDeleteVertexArraysAPPLE = extproc; - - glDeleteVertexArraysAPPLE(n, arrays); -} - -static void APIENTRY InitGenVertexArraysAPPLE (GLsizei n, const GLuint *arrays) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGenVertexArraysAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGenVertexArraysAPPLE = extproc; - - glGenVertexArraysAPPLE(n, arrays); -} - -static GLboolean APIENTRY InitIsVertexArrayAPPLE (GLuint array) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glIsVertexArrayAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glIsVertexArrayAPPLE = extproc; - - return glIsVertexArrayAPPLE(array); -} - -static void APIENTRY InitVertexArrayRangeAPPLE (GLsizei length, GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexArrayRangeAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexArrayRangeAPPLE = extproc; - - glVertexArrayRangeAPPLE(length, pointer); -} - -static void APIENTRY InitFlushVertexArrayRangeAPPLE (GLsizei length, GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFlushVertexArrayRangeAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFlushVertexArrayRangeAPPLE = extproc; - - glFlushVertexArrayRangeAPPLE(length, pointer); -} - -static void APIENTRY InitVertexArrayParameteriAPPLE (GLenum pname, GLint param) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexArrayParameteriAPPLE"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexArrayParameteriAPPLE = extproc; - - glVertexArrayParameteriAPPLE(pname, param); -} - -static void APIENTRY InitDrawBuffersATI (GLsizei n, const GLenum *bufs) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDrawBuffersATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDrawBuffersATI = extproc; - - glDrawBuffersATI(n, bufs); -} - -static void APIENTRY InitProgramNamedParameter4fNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glProgramNamedParameter4fNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glProgramNamedParameter4fNV = extproc; - - glProgramNamedParameter4fNV(id, len, name, x, y, z, w); -} - -static void APIENTRY InitProgramNamedParameter4dNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glProgramNamedParameter4dNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glProgramNamedParameter4dNV = extproc; - - glProgramNamedParameter4dNV(id, len, name, x, y, z, w); -} - -static void APIENTRY InitProgramNamedParameter4fvNV (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glProgramNamedParameter4fvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glProgramNamedParameter4fvNV = extproc; - - glProgramNamedParameter4fvNV(id, len, name, v); -} - -static void APIENTRY InitProgramNamedParameter4dvNV (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glProgramNamedParameter4dvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glProgramNamedParameter4dvNV = extproc; - - glProgramNamedParameter4dvNV(id, len, name, v); -} - -static void APIENTRY InitGetProgramNamedParameterfvNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetProgramNamedParameterfvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetProgramNamedParameterfvNV = extproc; - - glGetProgramNamedParameterfvNV(id, len, name, params); -} - -static void APIENTRY InitGetProgramNamedParameterdvNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetProgramNamedParameterdvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetProgramNamedParameterdvNV = extproc; - - glGetProgramNamedParameterdvNV(id, len, name, params); -} - -static void APIENTRY InitVertex2hNV (GLhalfNV x, GLhalfNV y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertex2hNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertex2hNV = extproc; - - glVertex2hNV(x, y); -} - -static void APIENTRY InitVertex2hvNV (const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertex2hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertex2hvNV = extproc; - - glVertex2hvNV(v); -} - -static void APIENTRY InitVertex3hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertex3hNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertex3hNV = extproc; - - glVertex3hNV(x, y, z); -} - -static void APIENTRY InitVertex3hvNV (const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertex3hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertex3hvNV = extproc; - - glVertex3hvNV(v); -} - -static void APIENTRY InitVertex4hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertex4hNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertex4hNV = extproc; - - glVertex4hNV(x, y, z, w); -} - -static void APIENTRY InitVertex4hvNV (const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertex4hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertex4hvNV = extproc; - - glVertex4hvNV(v); -} - -static void APIENTRY InitNormal3hNV (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glNormal3hNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glNormal3hNV = extproc; - - glNormal3hNV(nx, ny, nz); -} - -static void APIENTRY InitNormal3hvNV (const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glNormal3hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glNormal3hvNV = extproc; - - glNormal3hvNV(v); -} - -static void APIENTRY InitColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColor3hNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColor3hNV = extproc; - - glColor3hNV(red, green, blue); -} - -static void APIENTRY InitColor3hvNV (const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColor3hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColor3hvNV = extproc; - - glColor3hvNV(v); -} - -static void APIENTRY InitColor4hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColor4hNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColor4hNV = extproc; - - glColor4hNV(red, green, blue, alpha); -} - -static void APIENTRY InitColor4hvNV (const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glColor4hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glColor4hvNV = extproc; - - glColor4hvNV(v); -} - -static void APIENTRY InitTexCoord1hNV (GLhalfNV s) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord1hNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord1hNV = extproc; - - glTexCoord1hNV(s); -} - -static void APIENTRY InitTexCoord1hvNV (const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord1hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord1hvNV = extproc; - - glTexCoord1hvNV(v); -} - -static void APIENTRY InitTexCoord2hNV (GLhalfNV s, GLhalfNV t) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord2hNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord2hNV = extproc; - - glTexCoord2hNV(s, t); -} - -static void APIENTRY InitTexCoord2hvNV (const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord2hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord2hvNV = extproc; - - glTexCoord2hvNV(v); -} - -static void APIENTRY InitTexCoord3hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord3hNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord3hNV = extproc; - - glTexCoord3hNV(s, t, r); -} - -static void APIENTRY InitTexCoord3hvNV (const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord3hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord3hvNV = extproc; - - glTexCoord3hvNV(v); -} - -static void APIENTRY InitTexCoord4hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord4hNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord4hNV = extproc; - - glTexCoord4hNV(s, t, r, q); -} - -static void APIENTRY InitTexCoord4hvNV (const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glTexCoord4hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glTexCoord4hvNV = extproc; - - glTexCoord4hvNV(v); -} - -static void APIENTRY InitMultiTexCoord1hNV (GLenum target, GLhalfNV s) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord1hNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord1hNV = extproc; - - glMultiTexCoord1hNV(target, s); -} - -static void APIENTRY InitMultiTexCoord1hvNV (GLenum target, const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord1hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord1hvNV = extproc; - - glMultiTexCoord1hvNV(target, v); -} - -static void APIENTRY InitMultiTexCoord2hNV (GLenum target, GLhalfNV s, GLhalfNV t) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord2hNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord2hNV = extproc; - - glMultiTexCoord2hNV(target, s, t); -} - -static void APIENTRY InitMultiTexCoord2hvNV (GLenum target, const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord2hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord2hvNV = extproc; - - glMultiTexCoord2hvNV(target, v); -} - -static void APIENTRY InitMultiTexCoord3hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord3hNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord3hNV = extproc; - - glMultiTexCoord3hNV(target, s, t, r); -} - -static void APIENTRY InitMultiTexCoord3hvNV (GLenum target, const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord3hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord3hvNV = extproc; - - glMultiTexCoord3hvNV(target, v); -} - -static void APIENTRY InitMultiTexCoord4hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord4hNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord4hNV = extproc; - - glMultiTexCoord4hNV(target, s, t, r, q); -} - -static void APIENTRY InitMultiTexCoord4hvNV (GLenum target, const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMultiTexCoord4hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glMultiTexCoord4hvNV = extproc; - - glMultiTexCoord4hvNV(target, v); -} - -static void APIENTRY InitFogCoordhNV (GLhalfNV fog) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFogCoordhNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFogCoordhNV = extproc; - - glFogCoordhNV(fog); -} - -static void APIENTRY InitFogCoordhvNV (const GLhalfNV *fog) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFogCoordhvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFogCoordhvNV = extproc; - - glFogCoordhvNV(fog); -} - -static void APIENTRY InitSecondaryColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3hNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3hNV = extproc; - - glSecondaryColor3hNV(red, green, blue); -} - -static void APIENTRY InitSecondaryColor3hvNV (const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glSecondaryColor3hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glSecondaryColor3hvNV = extproc; - - glSecondaryColor3hvNV(v); -} - -static void APIENTRY InitVertexWeighthNV (GLhalfNV weight) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexWeighthNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexWeighthNV = extproc; - - glVertexWeighthNV(weight); -} - -static void APIENTRY InitVertexWeighthvNV (const GLhalfNV *weight) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexWeighthvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexWeighthvNV = extproc; - - glVertexWeighthvNV(weight); -} - -static void APIENTRY InitVertexAttrib1hNV (GLuint index, GLhalfNV x) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib1hNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib1hNV = extproc; - - glVertexAttrib1hNV(index, x); -} - -static void APIENTRY InitVertexAttrib1hvNV (GLuint index, const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib1hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib1hvNV = extproc; - - glVertexAttrib1hvNV(index, v); -} - -static void APIENTRY InitVertexAttrib2hNV (GLuint index, GLhalfNV x, GLhalfNV y) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib2hNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib2hNV = extproc; - - glVertexAttrib2hNV(index, x, y); -} - -static void APIENTRY InitVertexAttrib2hvNV (GLuint index, const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib2hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib2hvNV = extproc; - - glVertexAttrib2hvNV(index, v); -} - -static void APIENTRY InitVertexAttrib3hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib3hNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib3hNV = extproc; - - glVertexAttrib3hNV(index, x, y, z); -} - -static void APIENTRY InitVertexAttrib3hvNV (GLuint index, const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib3hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib3hvNV = extproc; - - glVertexAttrib3hvNV(index, v); -} - -static void APIENTRY InitVertexAttrib4hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4hNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4hNV = extproc; - - glVertexAttrib4hNV(index, x, y, z, w); -} - -static void APIENTRY InitVertexAttrib4hvNV (GLuint index, const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttrib4hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttrib4hvNV = extproc; - - glVertexAttrib4hvNV(index, v); -} - -static void APIENTRY InitVertexAttribs1hvNV (GLuint index, GLsizei n, const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribs1hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribs1hvNV = extproc; - - glVertexAttribs1hvNV(index, n, v); -} - -static void APIENTRY InitVertexAttribs2hvNV (GLuint index, GLsizei n, const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribs2hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribs2hvNV = extproc; - - glVertexAttribs2hvNV(index, n, v); -} - -static void APIENTRY InitVertexAttribs3hvNV (GLuint index, GLsizei n, const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribs3hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribs3hvNV = extproc; - - glVertexAttribs3hvNV(index, n, v); -} - -static void APIENTRY InitVertexAttribs4hvNV (GLuint index, GLsizei n, const GLhalfNV *v) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribs4hvNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribs4hvNV = extproc; - - glVertexAttribs4hvNV(index, n, v); -} - -static void APIENTRY InitPixelDataRangeNV (GLenum target, GLsizei length, GLvoid *pointer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPixelDataRangeNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPixelDataRangeNV = extproc; - - glPixelDataRangeNV(target, length, pointer); -} - -static void APIENTRY InitFlushPixelDataRangeNV (GLenum target) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glFlushPixelDataRangeNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glFlushPixelDataRangeNV = extproc; - - glFlushPixelDataRangeNV(target); -} - -static void APIENTRY InitPrimitiveRestartNV (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPrimitiveRestartNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPrimitiveRestartNV = extproc; - - glPrimitiveRestartNV(); -} - -static void APIENTRY InitPrimitiveRestartIndexNV (GLuint index) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glPrimitiveRestartIndexNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glPrimitiveRestartIndexNV = extproc; - - glPrimitiveRestartIndexNV(index); -} - -static GLvoid* APIENTRY InitMapObjectBufferATI (GLuint buffer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glMapObjectBufferATI"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - glMapObjectBufferATI = extproc; - - return glMapObjectBufferATI(buffer); -} - -static void APIENTRY InitUnmapObjectBufferATI (GLuint buffer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glUnmapObjectBufferATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glUnmapObjectBufferATI = extproc; - - glUnmapObjectBufferATI(buffer); -} - -static void APIENTRY InitStencilOpSeparateATI (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glStencilOpSeparateATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glStencilOpSeparateATI = extproc; - - glStencilOpSeparateATI(face, sfail, dpfail, dppass); -} - -static void APIENTRY InitStencilFuncSeparateATI (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glStencilFuncSeparateATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glStencilFuncSeparateATI = extproc; - - glStencilFuncSeparateATI(frontfunc, backfunc, ref, mask); -} - -static void APIENTRY InitVertexAttribArrayObjectATI (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glVertexAttribArrayObjectATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glVertexAttribArrayObjectATI = extproc; - - glVertexAttribArrayObjectATI(index, size, type, normalized, stride, buffer, offset); -} - -static void APIENTRY InitGetVertexAttribArrayObjectfvATI (GLuint index, GLenum pname, GLfloat *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetVertexAttribArrayObjectfvATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetVertexAttribArrayObjectfvATI = extproc; - - glGetVertexAttribArrayObjectfvATI(index, pname, params); -} - -static void APIENTRY InitGetVertexAttribArrayObjectivATI (GLuint index, GLenum pname, GLint *params) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glGetVertexAttribArrayObjectivATI"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glGetVertexAttribArrayObjectivATI = extproc; - - glGetVertexAttribArrayObjectivATI(index, pname, params); -} - -static void APIENTRY InitDepthBoundsEXT (GLclampd zmin, GLclampd zmax) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glDepthBoundsEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glDepthBoundsEXT = extproc; - - glDepthBoundsEXT(zmin, zmax); -} - -static void APIENTRY InitBlendEquationSeparateEXT (GLenum modeRGB, GLenum modeAlpha) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glBlendEquationSeparateEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glBlendEquationSeparateEXT = extproc; - - glBlendEquationSeparateEXT(modeRGB, modeAlpha); -} - -static void APIENTRY InitAddSwapHintRectWIN (GLint x, GLint y, GLsizei width, GLsizei height) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("glAddSwapHintRectWIN"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - glAddSwapHintRectWIN = extproc; - - glAddSwapHintRectWIN(x, y, width, height); -} - -#ifdef _WIN32 - -static HANDLE WINAPI InitCreateBufferRegionARB (HDC hDC, int iLayerPlane, UINT uType) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglCreateBufferRegionARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglCreateBufferRegionARB = extproc; - - return wglCreateBufferRegionARB(hDC, iLayerPlane, uType); -} - -static VOID WINAPI InitDeleteBufferRegionARB (HANDLE hRegion) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglDeleteBufferRegionARB"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - wglDeleteBufferRegionARB = extproc; - - wglDeleteBufferRegionARB(hRegion); -} - -static BOOL WINAPI InitSaveBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglSaveBufferRegionARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglSaveBufferRegionARB = extproc; - - return wglSaveBufferRegionARB(hRegion, x, y, width, height); -} - -static BOOL WINAPI InitRestoreBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglRestoreBufferRegionARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglRestoreBufferRegionARB = extproc; - - return wglRestoreBufferRegionARB(hRegion, x, y, width, height, xSrc, ySrc); -} - -static const WINAPI InitGetExtensionsStringARB (HDC hdc) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetExtensionsStringARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetExtensionsStringARB = extproc; - - return wglGetExtensionsStringARB(hdc); -} - -static BOOL WINAPI InitGetPixelFormatAttribivARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetPixelFormatAttribivARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetPixelFormatAttribivARB = extproc; - - return wglGetPixelFormatAttribivARB(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, piValues); -} - -static BOOL WINAPI InitGetPixelFormatAttribfvARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetPixelFormatAttribfvARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetPixelFormatAttribfvARB = extproc; - - return wglGetPixelFormatAttribfvARB(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, pfValues); -} - -static BOOL WINAPI InitChoosePixelFormatARB (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglChoosePixelFormatARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglChoosePixelFormatARB = extproc; - - return wglChoosePixelFormatARB(hdc, piAttribIList, pfAttribFList, nMaxFormats, piFormats, nNumFormats); -} - -static BOOL WINAPI InitMakeContextCurrentARB (HDC hDrawDC, HDC hReadDC, HGLRC hglrc) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglMakeContextCurrentARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglMakeContextCurrentARB = extproc; - - return wglMakeContextCurrentARB(hDrawDC, hReadDC, hglrc); -} - -static HDC WINAPI InitGetCurrentReadDCARB (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetCurrentReadDCARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetCurrentReadDCARB = extproc; - - return wglGetCurrentReadDCARB(); -} - -static HPBUFFERARB WINAPI InitCreatePbufferARB (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglCreatePbufferARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglCreatePbufferARB = extproc; - - return wglCreatePbufferARB(hDC, iPixelFormat, iWidth, iHeight, piAttribList); -} - -static HDC WINAPI InitGetPbufferDCARB (HPBUFFERARB hPbuffer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetPbufferDCARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetPbufferDCARB = extproc; - - return wglGetPbufferDCARB(hPbuffer); -} - -static int WINAPI InitReleasePbufferDCARB (HPBUFFERARB hPbuffer, HDC hDC) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglReleasePbufferDCARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglReleasePbufferDCARB = extproc; - - return wglReleasePbufferDCARB(hPbuffer, hDC); -} - -static BOOL WINAPI InitDestroyPbufferARB (HPBUFFERARB hPbuffer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglDestroyPbufferARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglDestroyPbufferARB = extproc; - - return wglDestroyPbufferARB(hPbuffer); -} - -static BOOL WINAPI InitQueryPbufferARB (HPBUFFERARB hPbuffer, int iAttribute, int *piValue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglQueryPbufferARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglQueryPbufferARB = extproc; - - return wglQueryPbufferARB(hPbuffer, iAttribute, piValue); -} - -static BOOL WINAPI InitBindTexImageARB (HPBUFFERARB hPbuffer, int iBuffer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglBindTexImageARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglBindTexImageARB = extproc; - - return wglBindTexImageARB(hPbuffer, iBuffer); -} - -static BOOL WINAPI InitReleaseTexImageARB (HPBUFFERARB hPbuffer, int iBuffer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglReleaseTexImageARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglReleaseTexImageARB = extproc; - - return wglReleaseTexImageARB(hPbuffer, iBuffer); -} - -static BOOL WINAPI InitSetPbufferAttribARB (HPBUFFERARB hPbuffer, const int *piAttribList) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglSetPbufferAttribARB"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglSetPbufferAttribARB = extproc; - - return wglSetPbufferAttribARB(hPbuffer, piAttribList); -} - -static GLboolean WINAPI InitCreateDisplayColorTableEXT (GLushort id) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglCreateDisplayColorTableEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglCreateDisplayColorTableEXT = extproc; - - return wglCreateDisplayColorTableEXT(id); -} - -static GLboolean WINAPI InitLoadDisplayColorTableEXT (const GLushort *table, GLuint length) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglLoadDisplayColorTableEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglLoadDisplayColorTableEXT = extproc; - - return wglLoadDisplayColorTableEXT(table, length); -} - -static GLboolean WINAPI InitBindDisplayColorTableEXT (GLushort id) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglBindDisplayColorTableEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglBindDisplayColorTableEXT = extproc; - - return wglBindDisplayColorTableEXT(id); -} - -static VOID WINAPI InitDestroyDisplayColorTableEXT (GLushort id) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglDestroyDisplayColorTableEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - wglDestroyDisplayColorTableEXT = extproc; - - wglDestroyDisplayColorTableEXT(id); -} - -static const WINAPI InitGetExtensionsStringEXT (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetExtensionsStringEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetExtensionsStringEXT = extproc; - - return wglGetExtensionsStringEXT(); -} - -static BOOL WINAPI InitMakeContextCurrentEXT (HDC hDrawDC, HDC hReadDC, HGLRC hglrc) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglMakeContextCurrentEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglMakeContextCurrentEXT = extproc; - - return wglMakeContextCurrentEXT(hDrawDC, hReadDC, hglrc); -} - -static HDC WINAPI InitGetCurrentReadDCEXT (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetCurrentReadDCEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetCurrentReadDCEXT = extproc; - - return wglGetCurrentReadDCEXT(); -} - -static HPBUFFEREXT WINAPI InitCreatePbufferEXT (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglCreatePbufferEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglCreatePbufferEXT = extproc; - - return wglCreatePbufferEXT(hDC, iPixelFormat, iWidth, iHeight, piAttribList); -} - -static HDC WINAPI InitGetPbufferDCEXT (HPBUFFEREXT hPbuffer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetPbufferDCEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetPbufferDCEXT = extproc; - - return wglGetPbufferDCEXT(hPbuffer); -} - -static int WINAPI InitReleasePbufferDCEXT (HPBUFFEREXT hPbuffer, HDC hDC) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglReleasePbufferDCEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglReleasePbufferDCEXT = extproc; - - return wglReleasePbufferDCEXT(hPbuffer, hDC); -} - -static BOOL WINAPI InitDestroyPbufferEXT (HPBUFFEREXT hPbuffer) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglDestroyPbufferEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglDestroyPbufferEXT = extproc; - - return wglDestroyPbufferEXT(hPbuffer); -} - -static BOOL WINAPI InitQueryPbufferEXT (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglQueryPbufferEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglQueryPbufferEXT = extproc; - - return wglQueryPbufferEXT(hPbuffer, iAttribute, piValue); -} - -static BOOL WINAPI InitGetPixelFormatAttribivEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetPixelFormatAttribivEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetPixelFormatAttribivEXT = extproc; - - return wglGetPixelFormatAttribivEXT(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, piValues); -} - -static BOOL WINAPI InitGetPixelFormatAttribfvEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetPixelFormatAttribfvEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetPixelFormatAttribfvEXT = extproc; - - return wglGetPixelFormatAttribfvEXT(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, pfValues); -} - -static BOOL WINAPI InitChoosePixelFormatEXT (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglChoosePixelFormatEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglChoosePixelFormatEXT = extproc; - - return wglChoosePixelFormatEXT(hdc, piAttribIList, pfAttribFList, nMaxFormats, piFormats, nNumFormats); -} - -static BOOL WINAPI InitSwapIntervalEXT (int interval) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglSwapIntervalEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglSwapIntervalEXT = extproc; - - return wglSwapIntervalEXT(interval); -} - -static int WINAPI InitGetSwapIntervalEXT (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetSwapIntervalEXT"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetSwapIntervalEXT = extproc; - - return wglGetSwapIntervalEXT(); -} - -static void* WINAPI InitAllocateMemoryNV (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglAllocateMemoryNV"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglAllocateMemoryNV = extproc; - - return wglAllocateMemoryNV(size, readfreq, writefreq, priority); -} - -static void WINAPI InitFreeMemoryNV (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglFreeMemoryNV"); - - if (extproc == NULL) { - _ASSERT(0); - return; - } - - wglFreeMemoryNV = extproc; - - wglFreeMemoryNV(); -} - -static BOOL WINAPI InitGetSyncValuesOML (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetSyncValuesOML"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetSyncValuesOML = extproc; - - return wglGetSyncValuesOML(hdc, ust, msc, sbc); -} - -static BOOL WINAPI InitGetMscRateOML (HDC hdc, INT32 *numerator, INT32 *denominator) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetMscRateOML"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetMscRateOML = extproc; - - return wglGetMscRateOML(hdc, numerator, denominator); -} - -static INT64 WINAPI InitSwapBuffersMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglSwapBuffersMscOML"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglSwapBuffersMscOML = extproc; - - return wglSwapBuffersMscOML(hdc, target_msc, divisor, remainder); -} - -static INT64 WINAPI InitSwapLayerBuffersMscOML (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglSwapLayerBuffersMscOML"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglSwapLayerBuffersMscOML = extproc; - - return wglSwapLayerBuffersMscOML(hdc, fuPlanes, target_msc, divisor, remainder); -} - -static BOOL WINAPI InitWaitForMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglWaitForMscOML"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglWaitForMscOML = extproc; - - return wglWaitForMscOML(hdc, target_msc, divisor, remainder, ust, msc, sbc); -} - -static BOOL WINAPI InitWaitForSbcOML (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglWaitForSbcOML"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglWaitForSbcOML = extproc; - - return wglWaitForSbcOML(hdc, target_sbc, ust, msc, sbc); -} - -static BOOL WINAPI InitGetDigitalVideoParametersI3D (HDC hDC, int iAttribute, int *piValue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetDigitalVideoParametersI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetDigitalVideoParametersI3D = extproc; - - return wglGetDigitalVideoParametersI3D(hDC, iAttribute, piValue); -} - -static BOOL WINAPI InitSetDigitalVideoParametersI3D (HDC hDC, int iAttribute, const int *piValue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglSetDigitalVideoParametersI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglSetDigitalVideoParametersI3D = extproc; - - return wglSetDigitalVideoParametersI3D(hDC, iAttribute, piValue); -} - -static BOOL WINAPI InitGetGammaTableParametersI3D (HDC hDC, int iAttribute, int *piValue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetGammaTableParametersI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetGammaTableParametersI3D = extproc; - - return wglGetGammaTableParametersI3D(hDC, iAttribute, piValue); -} - -static BOOL WINAPI InitSetGammaTableParametersI3D (HDC hDC, int iAttribute, const int *piValue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglSetGammaTableParametersI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglSetGammaTableParametersI3D = extproc; - - return wglSetGammaTableParametersI3D(hDC, iAttribute, piValue); -} - -static BOOL WINAPI InitGetGammaTableI3D (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetGammaTableI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetGammaTableI3D = extproc; - - return wglGetGammaTableI3D(hDC, iEntries, puRed, puGreen, puBlue); -} - -static BOOL WINAPI InitSetGammaTableI3D (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglSetGammaTableI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglSetGammaTableI3D = extproc; - - return wglSetGammaTableI3D(hDC, iEntries, puRed, puGreen, puBlue); -} - -static BOOL WINAPI InitEnableGenlockI3D (HDC hDC) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglEnableGenlockI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglEnableGenlockI3D = extproc; - - return wglEnableGenlockI3D(hDC); -} - -static BOOL WINAPI InitDisableGenlockI3D (HDC hDC) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglDisableGenlockI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglDisableGenlockI3D = extproc; - - return wglDisableGenlockI3D(hDC); -} - -static BOOL WINAPI InitIsEnabledGenlockI3D (HDC hDC, BOOL *pFlag) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglIsEnabledGenlockI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglIsEnabledGenlockI3D = extproc; - - return wglIsEnabledGenlockI3D(hDC, pFlag); -} - -static BOOL WINAPI InitGenlockSourceI3D (HDC hDC, UINT uSource) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGenlockSourceI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGenlockSourceI3D = extproc; - - return wglGenlockSourceI3D(hDC, uSource); -} - -static BOOL WINAPI InitGetGenlockSourceI3D (HDC hDC, UINT *uSource) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetGenlockSourceI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetGenlockSourceI3D = extproc; - - return wglGetGenlockSourceI3D(hDC, uSource); -} - -static BOOL WINAPI InitGenlockSourceEdgeI3D (HDC hDC, UINT uEdge) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGenlockSourceEdgeI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGenlockSourceEdgeI3D = extproc; - - return wglGenlockSourceEdgeI3D(hDC, uEdge); -} - -static BOOL WINAPI InitGetGenlockSourceEdgeI3D (HDC hDC, UINT *uEdge) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetGenlockSourceEdgeI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetGenlockSourceEdgeI3D = extproc; - - return wglGetGenlockSourceEdgeI3D(hDC, uEdge); -} - -static BOOL WINAPI InitGenlockSampleRateI3D (HDC hDC, UINT uRate) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGenlockSampleRateI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGenlockSampleRateI3D = extproc; - - return wglGenlockSampleRateI3D(hDC, uRate); -} - -static BOOL WINAPI InitGetGenlockSampleRateI3D (HDC hDC, UINT *uRate) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetGenlockSampleRateI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetGenlockSampleRateI3D = extproc; - - return wglGetGenlockSampleRateI3D(hDC, uRate); -} - -static BOOL WINAPI InitGenlockSourceDelayI3D (HDC hDC, UINT uDelay) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGenlockSourceDelayI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGenlockSourceDelayI3D = extproc; - - return wglGenlockSourceDelayI3D(hDC, uDelay); -} - -static BOOL WINAPI InitGetGenlockSourceDelayI3D (HDC hDC, UINT *uDelay) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetGenlockSourceDelayI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetGenlockSourceDelayI3D = extproc; - - return wglGetGenlockSourceDelayI3D(hDC, uDelay); -} - -static BOOL WINAPI InitQueryGenlockMaxSourceDelayI3D (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglQueryGenlockMaxSourceDelayI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglQueryGenlockMaxSourceDelayI3D = extproc; - - return wglQueryGenlockMaxSourceDelayI3D(hDC, uMaxLineDelay, uMaxPixelDelay); -} - -static LPVOID WINAPI InitCreateImageBufferI3D (HDC hDC, DWORD dwSize, UINT uFlags) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglCreateImageBufferI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglCreateImageBufferI3D = extproc; - - return wglCreateImageBufferI3D(hDC, dwSize, uFlags); -} - -static BOOL WINAPI InitDestroyImageBufferI3D (HDC hDC, LPVOID pAddress) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglDestroyImageBufferI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglDestroyImageBufferI3D = extproc; - - return wglDestroyImageBufferI3D(hDC, pAddress); -} - -static BOOL WINAPI InitAssociateImageBufferEventsI3D (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglAssociateImageBufferEventsI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglAssociateImageBufferEventsI3D = extproc; - - return wglAssociateImageBufferEventsI3D(hDC, pEvent, pAddress, pSize, count); -} - -static BOOL WINAPI InitReleaseImageBufferEventsI3D (HDC hDC, const LPVOID *pAddress, UINT count) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglReleaseImageBufferEventsI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglReleaseImageBufferEventsI3D = extproc; - - return wglReleaseImageBufferEventsI3D(hDC, pAddress, count); -} - -static BOOL WINAPI InitEnableFrameLockI3D (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglEnableFrameLockI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglEnableFrameLockI3D = extproc; - - return wglEnableFrameLockI3D(); -} - -static BOOL WINAPI InitDisableFrameLockI3D (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglDisableFrameLockI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglDisableFrameLockI3D = extproc; - - return wglDisableFrameLockI3D(); -} - -static BOOL WINAPI InitIsEnabledFrameLockI3D (BOOL *pFlag) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglIsEnabledFrameLockI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglIsEnabledFrameLockI3D = extproc; - - return wglIsEnabledFrameLockI3D(pFlag); -} - -static BOOL WINAPI InitQueryFrameLockMasterI3D (BOOL *pFlag) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglQueryFrameLockMasterI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglQueryFrameLockMasterI3D = extproc; - - return wglQueryFrameLockMasterI3D(pFlag); -} - -static BOOL WINAPI InitGetFrameUsageI3D (float *pUsage) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglGetFrameUsageI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglGetFrameUsageI3D = extproc; - - return wglGetFrameUsageI3D(pUsage); -} - -static BOOL WINAPI InitBeginFrameTrackingI3D (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglBeginFrameTrackingI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglBeginFrameTrackingI3D = extproc; - - return wglBeginFrameTrackingI3D(); -} - -static BOOL WINAPI InitEndFrameTrackingI3D (void) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglEndFrameTrackingI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglEndFrameTrackingI3D = extproc; - - return wglEndFrameTrackingI3D(); -} - -static BOOL WINAPI InitQueryFrameTrackingI3D (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage) -{ - void *extproc; - - extproc = (void *) wglGetProcAddress("wglQueryFrameTrackingI3D"); - - if (extproc == NULL) { - _ASSERT(0); - return 0; - } - - wglQueryFrameTrackingI3D = extproc; - - return wglQueryFrameTrackingI3D(pFrameCount, pMissedFrames, pLastMissedUsage); -} - -#endif /* _WIN32 */ - -_GLextensionProcs _extensionProcs = { - InitBlendColor, - InitBlendEquation, - InitDrawRangeElements, - InitColorTable, - InitColorTableParameterfv, - InitColorTableParameteriv, - InitCopyColorTable, - InitGetColorTable, - InitGetColorTableParameterfv, - InitGetColorTableParameteriv, - InitColorSubTable, - InitCopyColorSubTable, - InitConvolutionFilter1D, - InitConvolutionFilter2D, - InitConvolutionParameterf, - InitConvolutionParameterfv, - InitConvolutionParameteri, - InitConvolutionParameteriv, - InitCopyConvolutionFilter1D, - InitCopyConvolutionFilter2D, - InitGetConvolutionFilter, - InitGetConvolutionParameterfv, - InitGetConvolutionParameteriv, - InitGetSeparableFilter, - InitSeparableFilter2D, - InitGetHistogram, - InitGetHistogramParameterfv, - InitGetHistogramParameteriv, - InitGetMinmax, - InitGetMinmaxParameterfv, - InitGetMinmaxParameteriv, - InitHistogram, - InitMinmax, - InitResetHistogram, - InitResetMinmax, - InitTexImage3D, - InitTexSubImage3D, - InitCopyTexSubImage3D, - InitActiveTexture, - InitClientActiveTexture, - InitMultiTexCoord1d, - InitMultiTexCoord1dv, - InitMultiTexCoord1f, - InitMultiTexCoord1fv, - InitMultiTexCoord1i, - InitMultiTexCoord1iv, - InitMultiTexCoord1s, - InitMultiTexCoord1sv, - InitMultiTexCoord2d, - InitMultiTexCoord2dv, - InitMultiTexCoord2f, - InitMultiTexCoord2fv, - InitMultiTexCoord2i, - InitMultiTexCoord2iv, - InitMultiTexCoord2s, - InitMultiTexCoord2sv, - InitMultiTexCoord3d, - InitMultiTexCoord3dv, - InitMultiTexCoord3f, - InitMultiTexCoord3fv, - InitMultiTexCoord3i, - InitMultiTexCoord3iv, - InitMultiTexCoord3s, - InitMultiTexCoord3sv, - InitMultiTexCoord4d, - InitMultiTexCoord4dv, - InitMultiTexCoord4f, - InitMultiTexCoord4fv, - InitMultiTexCoord4i, - InitMultiTexCoord4iv, - InitMultiTexCoord4s, - InitMultiTexCoord4sv, - InitLoadTransposeMatrixf, - InitLoadTransposeMatrixd, - InitMultTransposeMatrixf, - InitMultTransposeMatrixd, - InitSampleCoverage, - InitCompressedTexImage3D, - InitCompressedTexImage2D, - InitCompressedTexImage1D, - InitCompressedTexSubImage3D, - InitCompressedTexSubImage2D, - InitCompressedTexSubImage1D, - InitGetCompressedTexImage, - InitBlendFuncSeparate, - InitFogCoordf, - InitFogCoordfv, - InitFogCoordd, - InitFogCoorddv, - InitFogCoordPointer, - InitMultiDrawArrays, - InitMultiDrawElements, - InitPointParameterf, - InitPointParameterfv, - InitPointParameteri, - InitPointParameteriv, - InitSecondaryColor3b, - InitSecondaryColor3bv, - InitSecondaryColor3d, - InitSecondaryColor3dv, - InitSecondaryColor3f, - InitSecondaryColor3fv, - InitSecondaryColor3i, - InitSecondaryColor3iv, - InitSecondaryColor3s, - InitSecondaryColor3sv, - InitSecondaryColor3ub, - InitSecondaryColor3ubv, - InitSecondaryColor3ui, - InitSecondaryColor3uiv, - InitSecondaryColor3us, - InitSecondaryColor3usv, - InitSecondaryColorPointer, - InitWindowPos2d, - InitWindowPos2dv, - InitWindowPos2f, - InitWindowPos2fv, - InitWindowPos2i, - InitWindowPos2iv, - InitWindowPos2s, - InitWindowPos2sv, - InitWindowPos3d, - InitWindowPos3dv, - InitWindowPos3f, - InitWindowPos3fv, - InitWindowPos3i, - InitWindowPos3iv, - InitWindowPos3s, - InitWindowPos3sv, - InitGenQueries, - InitDeleteQueries, - InitIsQuery, - InitBeginQuery, - InitEndQuery, - InitGetQueryiv, - InitGetQueryObjectiv, - InitGetQueryObjectuiv, - InitBindBuffer, - InitDeleteBuffers, - InitGenBuffers, - InitIsBuffer, - InitBufferData, - InitBufferSubData, - InitGetBufferSubData, - InitMapBuffer, - InitUnmapBuffer, - InitGetBufferParameteriv, - InitGetBufferPointerv, - InitActiveTextureARB, - InitClientActiveTextureARB, - InitMultiTexCoord1dARB, - InitMultiTexCoord1dvARB, - InitMultiTexCoord1fARB, - InitMultiTexCoord1fvARB, - InitMultiTexCoord1iARB, - InitMultiTexCoord1ivARB, - InitMultiTexCoord1sARB, - InitMultiTexCoord1svARB, - InitMultiTexCoord2dARB, - InitMultiTexCoord2dvARB, - InitMultiTexCoord2fARB, - InitMultiTexCoord2fvARB, - InitMultiTexCoord2iARB, - InitMultiTexCoord2ivARB, - InitMultiTexCoord2sARB, - InitMultiTexCoord2svARB, - InitMultiTexCoord3dARB, - InitMultiTexCoord3dvARB, - InitMultiTexCoord3fARB, - InitMultiTexCoord3fvARB, - InitMultiTexCoord3iARB, - InitMultiTexCoord3ivARB, - InitMultiTexCoord3sARB, - InitMultiTexCoord3svARB, - InitMultiTexCoord4dARB, - InitMultiTexCoord4dvARB, - InitMultiTexCoord4fARB, - InitMultiTexCoord4fvARB, - InitMultiTexCoord4iARB, - InitMultiTexCoord4ivARB, - InitMultiTexCoord4sARB, - InitMultiTexCoord4svARB, - InitLoadTransposeMatrixfARB, - InitLoadTransposeMatrixdARB, - InitMultTransposeMatrixfARB, - InitMultTransposeMatrixdARB, - InitSampleCoverageARB, - InitCompressedTexImage3DARB, - InitCompressedTexImage2DARB, - InitCompressedTexImage1DARB, - InitCompressedTexSubImage3DARB, - InitCompressedTexSubImage2DARB, - InitCompressedTexSubImage1DARB, - InitGetCompressedTexImageARB, - InitPointParameterfARB, - InitPointParameterfvARB, - InitWeightbvARB, - InitWeightsvARB, - InitWeightivARB, - InitWeightfvARB, - InitWeightdvARB, - InitWeightubvARB, - InitWeightusvARB, - InitWeightuivARB, - InitWeightPointerARB, - InitVertexBlendARB, - InitCurrentPaletteMatrixARB, - InitMatrixIndexubvARB, - InitMatrixIndexusvARB, - InitMatrixIndexuivARB, - InitMatrixIndexPointerARB, - InitWindowPos2dARB, - InitWindowPos2dvARB, - InitWindowPos2fARB, - InitWindowPos2fvARB, - InitWindowPos2iARB, - InitWindowPos2ivARB, - InitWindowPos2sARB, - InitWindowPos2svARB, - InitWindowPos3dARB, - InitWindowPos3dvARB, - InitWindowPos3fARB, - InitWindowPos3fvARB, - InitWindowPos3iARB, - InitWindowPos3ivARB, - InitWindowPos3sARB, - InitWindowPos3svARB, - InitVertexAttrib1dARB, - InitVertexAttrib1dvARB, - InitVertexAttrib1fARB, - InitVertexAttrib1fvARB, - InitVertexAttrib1sARB, - InitVertexAttrib1svARB, - InitVertexAttrib2dARB, - InitVertexAttrib2dvARB, - InitVertexAttrib2fARB, - InitVertexAttrib2fvARB, - InitVertexAttrib2sARB, - InitVertexAttrib2svARB, - InitVertexAttrib3dARB, - InitVertexAttrib3dvARB, - InitVertexAttrib3fARB, - InitVertexAttrib3fvARB, - InitVertexAttrib3sARB, - InitVertexAttrib3svARB, - InitVertexAttrib4NbvARB, - InitVertexAttrib4NivARB, - InitVertexAttrib4NsvARB, - InitVertexAttrib4NubARB, - InitVertexAttrib4NubvARB, - InitVertexAttrib4NuivARB, - InitVertexAttrib4NusvARB, - InitVertexAttrib4bvARB, - InitVertexAttrib4dARB, - InitVertexAttrib4dvARB, - InitVertexAttrib4fARB, - InitVertexAttrib4fvARB, - InitVertexAttrib4ivARB, - InitVertexAttrib4sARB, - InitVertexAttrib4svARB, - InitVertexAttrib4ubvARB, - InitVertexAttrib4uivARB, - InitVertexAttrib4usvARB, - InitVertexAttribPointerARB, - InitEnableVertexAttribArrayARB, - InitDisableVertexAttribArrayARB, - InitProgramStringARB, - InitBindProgramARB, - InitDeleteProgramsARB, - InitGenProgramsARB, - InitProgramEnvParameter4dARB, - InitProgramEnvParameter4dvARB, - InitProgramEnvParameter4fARB, - InitProgramEnvParameter4fvARB, - InitProgramLocalParameter4dARB, - InitProgramLocalParameter4dvARB, - InitProgramLocalParameter4fARB, - InitProgramLocalParameter4fvARB, - InitGetProgramEnvParameterdvARB, - InitGetProgramEnvParameterfvARB, - InitGetProgramLocalParameterdvARB, - InitGetProgramLocalParameterfvARB, - InitGetProgramivARB, - InitGetProgramStringARB, - InitGetVertexAttribdvARB, - InitGetVertexAttribfvARB, - InitGetVertexAttribivARB, - InitGetVertexAttribPointervARB, - InitIsProgramARB, - InitBindBufferARB, - InitDeleteBuffersARB, - InitGenBuffersARB, - InitIsBufferARB, - InitBufferDataARB, - InitBufferSubDataARB, - InitGetBufferSubDataARB, - InitMapBufferARB, - InitUnmapBufferARB, - InitGetBufferParameterivARB, - InitGetBufferPointervARB, - InitGenQueriesARB, - InitDeleteQueriesARB, - InitIsQueryARB, - InitBeginQueryARB, - InitEndQueryARB, - InitGetQueryivARB, - InitGetQueryObjectivARB, - InitGetQueryObjectuivARB, - InitDeleteObjectARB, - InitGetHandleARB, - InitDetachObjectARB, - InitCreateShaderObjectARB, - InitShaderSourceARB, - InitCompileShaderARB, - InitCreateProgramObjectARB, - InitAttachObjectARB, - InitLinkProgramARB, - InitUseProgramObjectARB, - InitValidateProgramARB, - InitUniform1fARB, - InitUniform2fARB, - InitUniform3fARB, - InitUniform4fARB, - InitUniform1iARB, - InitUniform2iARB, - InitUniform3iARB, - InitUniform4iARB, - InitUniform1fvARB, - InitUniform2fvARB, - InitUniform3fvARB, - InitUniform4fvARB, - InitUniform1ivARB, - InitUniform2ivARB, - InitUniform3ivARB, - InitUniform4ivARB, - InitUniformMatrix2fvARB, - InitUniformMatrix3fvARB, - InitUniformMatrix4fvARB, - InitGetObjectParameterfvARB, - InitGetObjectParameterivARB, - InitGetInfoLogARB, - InitGetAttachedObjectsARB, - InitGetUniformLocationARB, - InitGetActiveUniformARB, - InitGetUniformfvARB, - InitGetUniformivARB, - InitGetShaderSourceARB, - InitBindAttribLocationARB, - InitGetActiveAttribARB, - InitGetAttribLocationARB, - InitBlendColorEXT, - InitPolygonOffsetEXT, - InitTexImage3DEXT, - InitTexSubImage3DEXT, - InitGetTexFilterFuncSGIS, - InitTexFilterFuncSGIS, - InitTexSubImage1DEXT, - InitTexSubImage2DEXT, - InitCopyTexImage1DEXT, - InitCopyTexImage2DEXT, - InitCopyTexSubImage1DEXT, - InitCopyTexSubImage2DEXT, - InitCopyTexSubImage3DEXT, - InitGetHistogramEXT, - InitGetHistogramParameterfvEXT, - InitGetHistogramParameterivEXT, - InitGetMinmaxEXT, - InitGetMinmaxParameterfvEXT, - InitGetMinmaxParameterivEXT, - InitHistogramEXT, - InitMinmaxEXT, - InitResetHistogramEXT, - InitResetMinmaxEXT, - InitConvolutionFilter1DEXT, - InitConvolutionFilter2DEXT, - InitConvolutionParameterfEXT, - InitConvolutionParameterfvEXT, - InitConvolutionParameteriEXT, - InitConvolutionParameterivEXT, - InitCopyConvolutionFilter1DEXT, - InitCopyConvolutionFilter2DEXT, - InitGetConvolutionFilterEXT, - InitGetConvolutionParameterfvEXT, - InitGetConvolutionParameterivEXT, - InitGetSeparableFilterEXT, - InitSeparableFilter2DEXT, - InitColorTableSGI, - InitColorTableParameterfvSGI, - InitColorTableParameterivSGI, - InitCopyColorTableSGI, - InitGetColorTableSGI, - InitGetColorTableParameterfvSGI, - InitGetColorTableParameterivSGI, - InitPixelTexGenSGIX, - InitPixelTexGenParameteriSGIS, - InitPixelTexGenParameterivSGIS, - InitPixelTexGenParameterfSGIS, - InitPixelTexGenParameterfvSGIS, - InitGetPixelTexGenParameterivSGIS, - InitGetPixelTexGenParameterfvSGIS, - InitTexImage4DSGIS, - InitTexSubImage4DSGIS, - InitAreTexturesResidentEXT, - InitBindTextureEXT, - InitDeleteTexturesEXT, - InitGenTexturesEXT, - InitIsTextureEXT, - InitPrioritizeTexturesEXT, - InitDetailTexFuncSGIS, - InitGetDetailTexFuncSGIS, - InitSharpenTexFuncSGIS, - InitGetSharpenTexFuncSGIS, - InitSampleMaskSGIS, - InitSamplePatternSGIS, - InitArrayElementEXT, - InitColorPointerEXT, - InitDrawArraysEXT, - InitEdgeFlagPointerEXT, - InitGetPointervEXT, - InitIndexPointerEXT, - InitNormalPointerEXT, - InitTexCoordPointerEXT, - InitVertexPointerEXT, - InitBlendEquationEXT, - InitSpriteParameterfSGIX, - InitSpriteParameterfvSGIX, - InitSpriteParameteriSGIX, - InitSpriteParameterivSGIX, - InitPointParameterfEXT, - InitPointParameterfvEXT, - InitPointParameterfSGIS, - InitPointParameterfvSGIS, - InitGetInstrumentsSGIX, - InitInstrumentsBufferSGIX, - InitPollInstrumentsSGIX, - InitReadInstrumentsSGIX, - InitStartInstrumentsSGIX, - InitStopInstrumentsSGIX, - InitFrameZoomSGIX, - InitTagSampleBufferSGIX, - InitDeformationMap3dSGIX, - InitDeformationMap3fSGIX, - InitDeformSGIX, - InitLoadIdentityDeformationMapSGIX, - InitReferencePlaneSGIX, - InitFlushRasterSGIX, - InitFogFuncSGIS, - InitGetFogFuncSGIS, - InitImageTransformParameteriHP, - InitImageTransformParameterfHP, - InitImageTransformParameterivHP, - InitImageTransformParameterfvHP, - InitGetImageTransformParameterivHP, - InitGetImageTransformParameterfvHP, - InitColorSubTableEXT, - InitCopyColorSubTableEXT, - InitHintPGI, - InitColorTableEXT, - InitGetColorTableEXT, - InitGetColorTableParameterivEXT, - InitGetColorTableParameterfvEXT, - InitGetListParameterfvSGIX, - InitGetListParameterivSGIX, - InitListParameterfSGIX, - InitListParameterfvSGIX, - InitListParameteriSGIX, - InitListParameterivSGIX, - InitIndexMaterialEXT, - InitIndexFuncEXT, - InitLockArraysEXT, - InitUnlockArraysEXT, - InitCullParameterdvEXT, - InitCullParameterfvEXT, - InitFragmentColorMaterialSGIX, - InitFragmentLightfSGIX, - InitFragmentLightfvSGIX, - InitFragmentLightiSGIX, - InitFragmentLightivSGIX, - InitFragmentLightModelfSGIX, - InitFragmentLightModelfvSGIX, - InitFragmentLightModeliSGIX, - InitFragmentLightModelivSGIX, - InitFragmentMaterialfSGIX, - InitFragmentMaterialfvSGIX, - InitFragmentMaterialiSGIX, - InitFragmentMaterialivSGIX, - InitGetFragmentLightfvSGIX, - InitGetFragmentLightivSGIX, - InitGetFragmentMaterialfvSGIX, - InitGetFragmentMaterialivSGIX, - InitLightEnviSGIX, - InitDrawRangeElementsEXT, - InitApplyTextureEXT, - InitTextureLightEXT, - InitTextureMaterialEXT, - InitAsyncMarkerSGIX, - InitFinishAsyncSGIX, - InitPollAsyncSGIX, - InitGenAsyncMarkersSGIX, - InitDeleteAsyncMarkersSGIX, - InitIsAsyncMarkerSGIX, - InitVertexPointervINTEL, - InitNormalPointervINTEL, - InitColorPointervINTEL, - InitTexCoordPointervINTEL, - InitPixelTransformParameteriEXT, - InitPixelTransformParameterfEXT, - InitPixelTransformParameterivEXT, - InitPixelTransformParameterfvEXT, - InitSecondaryColor3bEXT, - InitSecondaryColor3bvEXT, - InitSecondaryColor3dEXT, - InitSecondaryColor3dvEXT, - InitSecondaryColor3fEXT, - InitSecondaryColor3fvEXT, - InitSecondaryColor3iEXT, - InitSecondaryColor3ivEXT, - InitSecondaryColor3sEXT, - InitSecondaryColor3svEXT, - InitSecondaryColor3ubEXT, - InitSecondaryColor3ubvEXT, - InitSecondaryColor3uiEXT, - InitSecondaryColor3uivEXT, - InitSecondaryColor3usEXT, - InitSecondaryColor3usvEXT, - InitSecondaryColorPointerEXT, - InitTextureNormalEXT, - InitMultiDrawArraysEXT, - InitMultiDrawElementsEXT, - InitFogCoordfEXT, - InitFogCoordfvEXT, - InitFogCoorddEXT, - InitFogCoorddvEXT, - InitFogCoordPointerEXT, - InitTangent3bEXT, - InitTangent3bvEXT, - InitTangent3dEXT, - InitTangent3dvEXT, - InitTangent3fEXT, - InitTangent3fvEXT, - InitTangent3iEXT, - InitTangent3ivEXT, - InitTangent3sEXT, - InitTangent3svEXT, - InitBinormal3bEXT, - InitBinormal3bvEXT, - InitBinormal3dEXT, - InitBinormal3dvEXT, - InitBinormal3fEXT, - InitBinormal3fvEXT, - InitBinormal3iEXT, - InitBinormal3ivEXT, - InitBinormal3sEXT, - InitBinormal3svEXT, - InitTangentPointerEXT, - InitBinormalPointerEXT, - InitFinishTextureSUNX, - InitGlobalAlphaFactorbSUN, - InitGlobalAlphaFactorsSUN, - InitGlobalAlphaFactoriSUN, - InitGlobalAlphaFactorfSUN, - InitGlobalAlphaFactordSUN, - InitGlobalAlphaFactorubSUN, - InitGlobalAlphaFactorusSUN, - InitGlobalAlphaFactoruiSUN, - InitReplacementCodeuiSUN, - InitReplacementCodeusSUN, - InitReplacementCodeubSUN, - InitReplacementCodeuivSUN, - InitReplacementCodeusvSUN, - InitReplacementCodeubvSUN, - InitReplacementCodePointerSUN, - InitColor4ubVertex2fSUN, - InitColor4ubVertex2fvSUN, - InitColor4ubVertex3fSUN, - InitColor4ubVertex3fvSUN, - InitColor3fVertex3fSUN, - InitColor3fVertex3fvSUN, - InitNormal3fVertex3fSUN, - InitNormal3fVertex3fvSUN, - InitColor4fNormal3fVertex3fSUN, - InitColor4fNormal3fVertex3fvSUN, - InitTexCoord2fVertex3fSUN, - InitTexCoord2fVertex3fvSUN, - InitTexCoord4fVertex4fSUN, - InitTexCoord4fVertex4fvSUN, - InitTexCoord2fColor4ubVertex3fSUN, - InitTexCoord2fColor4ubVertex3fvSUN, - InitTexCoord2fColor3fVertex3fSUN, - InitTexCoord2fColor3fVertex3fvSUN, - InitTexCoord2fNormal3fVertex3fSUN, - InitTexCoord2fNormal3fVertex3fvSUN, - InitTexCoord2fColor4fNormal3fVertex3fSUN, - InitTexCoord2fColor4fNormal3fVertex3fvSUN, - InitTexCoord4fColor4fNormal3fVertex4fSUN, - InitTexCoord4fColor4fNormal3fVertex4fvSUN, - InitReplacementCodeuiVertex3fSUN, - InitReplacementCodeuiVertex3fvSUN, - InitReplacementCodeuiColor4ubVertex3fSUN, - InitReplacementCodeuiColor4ubVertex3fvSUN, - InitReplacementCodeuiColor3fVertex3fSUN, - InitReplacementCodeuiColor3fVertex3fvSUN, - InitReplacementCodeuiNormal3fVertex3fSUN, - InitReplacementCodeuiNormal3fVertex3fvSUN, - InitReplacementCodeuiColor4fNormal3fVertex3fSUN, - InitReplacementCodeuiColor4fNormal3fVertex3fvSUN, - InitReplacementCodeuiTexCoord2fVertex3fSUN, - InitReplacementCodeuiTexCoord2fVertex3fvSUN, - InitReplacementCodeuiTexCoord2fNormal3fVertex3fSUN, - InitReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN, - InitReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN, - InitReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN, - InitBlendFuncSeparateEXT, - InitBlendFuncSeparateINGR, - InitVertexWeightfEXT, - InitVertexWeightfvEXT, - InitVertexWeightPointerEXT, - InitFlushVertexArrayRangeNV, - InitVertexArrayRangeNV, - InitCombinerParameterfvNV, - InitCombinerParameterfNV, - InitCombinerParameterivNV, - InitCombinerParameteriNV, - InitCombinerInputNV, - InitCombinerOutputNV, - InitFinalCombinerInputNV, - InitGetCombinerInputParameterfvNV, - InitGetCombinerInputParameterivNV, - InitGetCombinerOutputParameterfvNV, - InitGetCombinerOutputParameterivNV, - InitGetFinalCombinerInputParameterfvNV, - InitGetFinalCombinerInputParameterivNV, - InitResizeBuffersMESA, - InitWindowPos2dMESA, - InitWindowPos2dvMESA, - InitWindowPos2fMESA, - InitWindowPos2fvMESA, - InitWindowPos2iMESA, - InitWindowPos2ivMESA, - InitWindowPos2sMESA, - InitWindowPos2svMESA, - InitWindowPos3dMESA, - InitWindowPos3dvMESA, - InitWindowPos3fMESA, - InitWindowPos3fvMESA, - InitWindowPos3iMESA, - InitWindowPos3ivMESA, - InitWindowPos3sMESA, - InitWindowPos3svMESA, - InitWindowPos4dMESA, - InitWindowPos4dvMESA, - InitWindowPos4fMESA, - InitWindowPos4fvMESA, - InitWindowPos4iMESA, - InitWindowPos4ivMESA, - InitWindowPos4sMESA, - InitWindowPos4svMESA, - InitMultiModeDrawArraysIBM, - InitMultiModeDrawElementsIBM, - InitColorPointerListIBM, - InitSecondaryColorPointerListIBM, - InitEdgeFlagPointerListIBM, - InitFogCoordPointerListIBM, - InitIndexPointerListIBM, - InitNormalPointerListIBM, - InitTexCoordPointerListIBM, - InitVertexPointerListIBM, - InitTbufferMask3DFX, - InitSampleMaskEXT, - InitSamplePatternEXT, - InitTextureColorMaskSGIS, - InitIglooInterfaceSGIX, - InitDeleteFencesNV, - InitGenFencesNV, - InitIsFenceNV, - InitTestFenceNV, - InitGetFenceivNV, - InitFinishFenceNV, - InitSetFenceNV, - InitMapControlPointsNV, - InitMapParameterivNV, - InitMapParameterfvNV, - InitGetMapControlPointsNV, - InitGetMapParameterivNV, - InitGetMapParameterfvNV, - InitGetMapAttribParameterivNV, - InitGetMapAttribParameterfvNV, - InitEvalMapsNV, - InitCombinerStageParameterfvNV, - InitGetCombinerStageParameterfvNV, - InitAreProgramsResidentNV, - InitBindProgramNV, - InitDeleteProgramsNV, - InitExecuteProgramNV, - InitGenProgramsNV, - InitGetProgramParameterdvNV, - InitGetProgramParameterfvNV, - InitGetProgramivNV, - InitGetProgramStringNV, - InitGetTrackMatrixivNV, - InitGetVertexAttribdvNV, - InitGetVertexAttribfvNV, - InitGetVertexAttribivNV, - InitGetVertexAttribPointervNV, - InitIsProgramNV, - InitLoadProgramNV, - InitProgramParameter4dNV, - InitProgramParameter4dvNV, - InitProgramParameter4fNV, - InitProgramParameter4fvNV, - InitProgramParameters4dvNV, - InitProgramParameters4fvNV, - InitRequestResidentProgramsNV, - InitTrackMatrixNV, - InitVertexAttribPointerNV, - InitVertexAttrib1dNV, - InitVertexAttrib1dvNV, - InitVertexAttrib1fNV, - InitVertexAttrib1fvNV, - InitVertexAttrib1sNV, - InitVertexAttrib1svNV, - InitVertexAttrib2dNV, - InitVertexAttrib2dvNV, - InitVertexAttrib2fNV, - InitVertexAttrib2fvNV, - InitVertexAttrib2sNV, - InitVertexAttrib2svNV, - InitVertexAttrib3dNV, - InitVertexAttrib3dvNV, - InitVertexAttrib3fNV, - InitVertexAttrib3fvNV, - InitVertexAttrib3sNV, - InitVertexAttrib3svNV, - InitVertexAttrib4dNV, - InitVertexAttrib4dvNV, - InitVertexAttrib4fNV, - InitVertexAttrib4fvNV, - InitVertexAttrib4sNV, - InitVertexAttrib4svNV, - InitVertexAttrib4ubNV, - InitVertexAttrib4ubvNV, - InitVertexAttribs1dvNV, - InitVertexAttribs1fvNV, - InitVertexAttribs1svNV, - InitVertexAttribs2dvNV, - InitVertexAttribs2fvNV, - InitVertexAttribs2svNV, - InitVertexAttribs3dvNV, - InitVertexAttribs3fvNV, - InitVertexAttribs3svNV, - InitVertexAttribs4dvNV, - InitVertexAttribs4fvNV, - InitVertexAttribs4svNV, - InitVertexAttribs4ubvNV, - InitTexBumpParameterivATI, - InitTexBumpParameterfvATI, - InitGetTexBumpParameterivATI, - InitGetTexBumpParameterfvATI, - InitGenFragmentShadersATI, - InitBindFragmentShaderATI, - InitDeleteFragmentShaderATI, - InitBeginFragmentShaderATI, - InitEndFragmentShaderATI, - InitPassTexCoordATI, - InitSampleMapATI, - InitColorFragmentOp1ATI, - InitColorFragmentOp2ATI, - InitColorFragmentOp3ATI, - InitAlphaFragmentOp1ATI, - InitAlphaFragmentOp2ATI, - InitAlphaFragmentOp3ATI, - InitSetFragmentShaderConstantATI, - InitPNTrianglesiATI, - InitPNTrianglesfATI, - InitNewObjectBufferATI, - InitIsObjectBufferATI, - InitUpdateObjectBufferATI, - InitGetObjectBufferfvATI, - InitGetObjectBufferivATI, - InitFreeObjectBufferATI, - InitArrayObjectATI, - InitGetArrayObjectfvATI, - InitGetArrayObjectivATI, - InitVariantArrayObjectATI, - InitGetVariantArrayObjectfvATI, - InitGetVariantArrayObjectivATI, - InitBeginVertexShaderEXT, - InitEndVertexShaderEXT, - InitBindVertexShaderEXT, - InitGenVertexShadersEXT, - InitDeleteVertexShaderEXT, - InitShaderOp1EXT, - InitShaderOp2EXT, - InitShaderOp3EXT, - InitSwizzleEXT, - InitWriteMaskEXT, - InitInsertComponentEXT, - InitExtractComponentEXT, - InitGenSymbolsEXT, - InitSetInvariantEXT, - InitSetLocalConstantEXT, - InitVariantbvEXT, - InitVariantsvEXT, - InitVariantivEXT, - InitVariantfvEXT, - InitVariantdvEXT, - InitVariantubvEXT, - InitVariantusvEXT, - InitVariantuivEXT, - InitVariantPointerEXT, - InitEnableVariantClientStateEXT, - InitDisableVariantClientStateEXT, - InitBindLightParameterEXT, - InitBindMaterialParameterEXT, - InitBindTexGenParameterEXT, - InitBindTextureUnitParameterEXT, - InitBindParameterEXT, - InitIsVariantEnabledEXT, - InitGetVariantBooleanvEXT, - InitGetVariantIntegervEXT, - InitGetVariantFloatvEXT, - InitGetVariantPointervEXT, - InitGetInvariantBooleanvEXT, - InitGetInvariantIntegervEXT, - InitGetInvariantFloatvEXT, - InitGetLocalConstantBooleanvEXT, - InitGetLocalConstantIntegervEXT, - InitGetLocalConstantFloatvEXT, - InitVertexStream1sATI, - InitVertexStream1svATI, - InitVertexStream1iATI, - InitVertexStream1ivATI, - InitVertexStream1fATI, - InitVertexStream1fvATI, - InitVertexStream1dATI, - InitVertexStream1dvATI, - InitVertexStream2sATI, - InitVertexStream2svATI, - InitVertexStream2iATI, - InitVertexStream2ivATI, - InitVertexStream2fATI, - InitVertexStream2fvATI, - InitVertexStream2dATI, - InitVertexStream2dvATI, - InitVertexStream3sATI, - InitVertexStream3svATI, - InitVertexStream3iATI, - InitVertexStream3ivATI, - InitVertexStream3fATI, - InitVertexStream3fvATI, - InitVertexStream3dATI, - InitVertexStream3dvATI, - InitVertexStream4sATI, - InitVertexStream4svATI, - InitVertexStream4iATI, - InitVertexStream4ivATI, - InitVertexStream4fATI, - InitVertexStream4fvATI, - InitVertexStream4dATI, - InitVertexStream4dvATI, - InitNormalStream3bATI, - InitNormalStream3bvATI, - InitNormalStream3sATI, - InitNormalStream3svATI, - InitNormalStream3iATI, - InitNormalStream3ivATI, - InitNormalStream3fATI, - InitNormalStream3fvATI, - InitNormalStream3dATI, - InitNormalStream3dvATI, - InitClientActiveVertexStreamATI, - InitVertexBlendEnviATI, - InitVertexBlendEnvfATI, - InitElementPointerATI, - InitDrawElementArrayATI, - InitDrawRangeElementArrayATI, - InitDrawMeshArraysSUN, - InitGenOcclusionQueriesNV, - InitDeleteOcclusionQueriesNV, - InitIsOcclusionQueryNV, - InitBeginOcclusionQueryNV, - InitEndOcclusionQueryNV, - InitGetOcclusionQueryivNV, - InitGetOcclusionQueryuivNV, - InitPointParameteriNV, - InitPointParameterivNV, - InitActiveStencilFaceEXT, - InitElementPointerAPPLE, - InitDrawElementArrayAPPLE, - InitDrawRangeElementArrayAPPLE, - InitMultiDrawElementArrayAPPLE, - InitMultiDrawRangeElementArrayAPPLE, - InitGenFencesAPPLE, - InitDeleteFencesAPPLE, - InitSetFenceAPPLE, - InitIsFenceAPPLE, - InitTestFenceAPPLE, - InitFinishFenceAPPLE, - InitTestObjectAPPLE, - InitFinishObjectAPPLE, - InitBindVertexArrayAPPLE, - InitDeleteVertexArraysAPPLE, - InitGenVertexArraysAPPLE, - InitIsVertexArrayAPPLE, - InitVertexArrayRangeAPPLE, - InitFlushVertexArrayRangeAPPLE, - InitVertexArrayParameteriAPPLE, - InitDrawBuffersATI, - InitProgramNamedParameter4fNV, - InitProgramNamedParameter4dNV, - InitProgramNamedParameter4fvNV, - InitProgramNamedParameter4dvNV, - InitGetProgramNamedParameterfvNV, - InitGetProgramNamedParameterdvNV, - InitVertex2hNV, - InitVertex2hvNV, - InitVertex3hNV, - InitVertex3hvNV, - InitVertex4hNV, - InitVertex4hvNV, - InitNormal3hNV, - InitNormal3hvNV, - InitColor3hNV, - InitColor3hvNV, - InitColor4hNV, - InitColor4hvNV, - InitTexCoord1hNV, - InitTexCoord1hvNV, - InitTexCoord2hNV, - InitTexCoord2hvNV, - InitTexCoord3hNV, - InitTexCoord3hvNV, - InitTexCoord4hNV, - InitTexCoord4hvNV, - InitMultiTexCoord1hNV, - InitMultiTexCoord1hvNV, - InitMultiTexCoord2hNV, - InitMultiTexCoord2hvNV, - InitMultiTexCoord3hNV, - InitMultiTexCoord3hvNV, - InitMultiTexCoord4hNV, - InitMultiTexCoord4hvNV, - InitFogCoordhNV, - InitFogCoordhvNV, - InitSecondaryColor3hNV, - InitSecondaryColor3hvNV, - InitVertexWeighthNV, - InitVertexWeighthvNV, - InitVertexAttrib1hNV, - InitVertexAttrib1hvNV, - InitVertexAttrib2hNV, - InitVertexAttrib2hvNV, - InitVertexAttrib3hNV, - InitVertexAttrib3hvNV, - InitVertexAttrib4hNV, - InitVertexAttrib4hvNV, - InitVertexAttribs1hvNV, - InitVertexAttribs2hvNV, - InitVertexAttribs3hvNV, - InitVertexAttribs4hvNV, - InitPixelDataRangeNV, - InitFlushPixelDataRangeNV, - InitPrimitiveRestartNV, - InitPrimitiveRestartIndexNV, - InitMapObjectBufferATI, - InitUnmapObjectBufferATI, - InitStencilOpSeparateATI, - InitStencilFuncSeparateATI, - InitVertexAttribArrayObjectATI, - InitGetVertexAttribArrayObjectfvATI, - InitGetVertexAttribArrayObjectivATI, - InitDepthBoundsEXT, - InitBlendEquationSeparateEXT, - InitAddSwapHintRectWIN, -#ifdef _WIN32 - InitCreateBufferRegionARB, - InitDeleteBufferRegionARB, - InitSaveBufferRegionARB, - InitRestoreBufferRegionARB, - InitGetExtensionsStringARB, - InitGetPixelFormatAttribivARB, - InitGetPixelFormatAttribfvARB, - InitChoosePixelFormatARB, - InitMakeContextCurrentARB, - InitGetCurrentReadDCARB, - InitCreatePbufferARB, - InitGetPbufferDCARB, - InitReleasePbufferDCARB, - InitDestroyPbufferARB, - InitQueryPbufferARB, - InitBindTexImageARB, - InitReleaseTexImageARB, - InitSetPbufferAttribARB, - InitCreateDisplayColorTableEXT, - InitLoadDisplayColorTableEXT, - InitBindDisplayColorTableEXT, - InitDestroyDisplayColorTableEXT, - InitGetExtensionsStringEXT, - InitMakeContextCurrentEXT, - InitGetCurrentReadDCEXT, - InitCreatePbufferEXT, - InitGetPbufferDCEXT, - InitReleasePbufferDCEXT, - InitDestroyPbufferEXT, - InitQueryPbufferEXT, - InitGetPixelFormatAttribivEXT, - InitGetPixelFormatAttribfvEXT, - InitChoosePixelFormatEXT, - InitSwapIntervalEXT, - InitGetSwapIntervalEXT, - InitAllocateMemoryNV, - InitFreeMemoryNV, - InitGetSyncValuesOML, - InitGetMscRateOML, - InitSwapBuffersMscOML, - InitSwapLayerBuffersMscOML, - InitWaitForMscOML, - InitWaitForSbcOML, - InitGetDigitalVideoParametersI3D, - InitSetDigitalVideoParametersI3D, - InitGetGammaTableParametersI3D, - InitSetGammaTableParametersI3D, - InitGetGammaTableI3D, - InitSetGammaTableI3D, - InitEnableGenlockI3D, - InitDisableGenlockI3D, - InitIsEnabledGenlockI3D, - InitGenlockSourceI3D, - InitGetGenlockSourceI3D, - InitGenlockSourceEdgeI3D, - InitGetGenlockSourceEdgeI3D, - InitGenlockSampleRateI3D, - InitGetGenlockSampleRateI3D, - InitGenlockSourceDelayI3D, - InitGetGenlockSourceDelayI3D, - InitQueryGenlockMaxSourceDelayI3D, - InitCreateImageBufferI3D, - InitDestroyImageBufferI3D, - InitAssociateImageBufferEventsI3D, - InitReleaseImageBufferEventsI3D, - InitEnableFrameLockI3D, - InitDisableFrameLockI3D, - InitIsEnabledFrameLockI3D, - InitQueryFrameLockMasterI3D, - InitGetFrameUsageI3D, - InitBeginFrameTrackingI3D, - InitEndFrameTrackingI3D, - InitQueryFrameTrackingI3D, -#endif /* _WIN32 */ -}; +/* +** GLprocs utility for getting function addresses for OpenGL(R) 1.2, +** OpenGL 1.3, OpenGL 1.4, OpenGL 1.5 and OpenGL extension functions. +** +** Version: 1.1 +** +** License Applicability. Except to the extent portions of this file are +** made subject to an alternative license as permitted in the SGI Free +** Software License B, Version 1.1 (the "License"), the contents of this +** file are subject only to the provisions of the License. You may not use +** this file except in compliance with the License. You may obtain a copy +** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 +** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: +** +** http://oss.sgi.com/projects/FreeB +** +** Note that, as provided in the License, the Software is distributed on an +** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS +** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND +** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A +** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. +** +** Original Code. The Original Code is: OpenGL Sample Implementation, +** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, +** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. +** Copyright in any portions created by third parties is as indicated +** elsewhere herein. All Rights Reserved. +** +** Additional Notice Provisions: This software was created using the +** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has +** not been independently verified as being compliant with the OpenGL(R) +** version 1.2.1 Specification. +** +** Initial version of glprocs.{c,h} contributed by Intel(R) Corporation. +*/ + +#include +#include + +#ifdef _WIN32 + #include + #include //"gl.h" /* Include local "gl.h". Don't include vc32 . */ + #include "glprocs.h" +#else /* GLX */ + #include + #include + #include +#include "glprocs.h"// +// #define wglGetProcAddress glXGetProcAddress +inline void* wglGetProcAddress(const char* x) { + return (void*)glXGetProcAddress((const GLubyte*)x); +} + +#endif + +#define _ASSERT(a) assert(a) + +static void APIENTRY InitBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendColor"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendColor = extproc; + + glBlendColor(red, green, blue, alpha); +} + +static void APIENTRY InitBlendEquation (GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendEquation"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendEquation = extproc; + + glBlendEquation(mode); +} + +static void APIENTRY InitDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawRangeElements"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawRangeElements = extproc; + + glDrawRangeElements(mode, start, end, count, type, indices); +} + +static void APIENTRY InitColorTable (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTable"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTable = extproc; + + glColorTable(target, internalformat, width, format, type, table); +} + +static void APIENTRY InitColorTableParameterfv (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTableParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTableParameterfv = extproc; + + glColorTableParameterfv(target, pname, params); +} + +static void APIENTRY InitColorTableParameteriv (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTableParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTableParameteriv = extproc; + + glColorTableParameteriv(target, pname, params); +} + +static void APIENTRY InitCopyColorTable (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyColorTable"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyColorTable = extproc; + + glCopyColorTable(target, internalformat, x, y, width); +} + +static void APIENTRY InitGetColorTable (GLenum target, GLenum format, GLenum type, GLvoid *table) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTable"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTable = extproc; + + glGetColorTable(target, format, type, table); +} + +static void APIENTRY InitGetColorTableParameterfv (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableParameterfv = extproc; + + glGetColorTableParameterfv(target, pname, params); +} + +static void APIENTRY InitGetColorTableParameteriv (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableParameteriv = extproc; + + glGetColorTableParameteriv(target, pname, params); +} + +static void APIENTRY InitColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorSubTable"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorSubTable = extproc; + + glColorSubTable(target, start, count, format, type, data); +} + +static void APIENTRY InitCopyColorSubTable (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyColorSubTable"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyColorSubTable = extproc; + + glCopyColorSubTable(target, start, x, y, width); +} + +static void APIENTRY InitConvolutionFilter1D (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionFilter1D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionFilter1D = extproc; + + glConvolutionFilter1D(target, internalformat, width, format, type, image); +} + +static void APIENTRY InitConvolutionFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionFilter2D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionFilter2D = extproc; + + glConvolutionFilter2D(target, internalformat, width, height, format, type, image); +} + +static void APIENTRY InitConvolutionParameterf (GLenum target, GLenum pname, GLfloat params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameterf"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameterf = extproc; + + glConvolutionParameterf(target, pname, params); +} + +static void APIENTRY InitConvolutionParameterfv (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameterfv = extproc; + + glConvolutionParameterfv(target, pname, params); +} + +static void APIENTRY InitConvolutionParameteri (GLenum target, GLenum pname, GLint params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameteri"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameteri = extproc; + + glConvolutionParameteri(target, pname, params); +} + +static void APIENTRY InitConvolutionParameteriv (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameteriv = extproc; + + glConvolutionParameteriv(target, pname, params); +} + +static void APIENTRY InitCopyConvolutionFilter1D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyConvolutionFilter1D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyConvolutionFilter1D = extproc; + + glCopyConvolutionFilter1D(target, internalformat, x, y, width); +} + +static void APIENTRY InitCopyConvolutionFilter2D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyConvolutionFilter2D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyConvolutionFilter2D = extproc; + + glCopyConvolutionFilter2D(target, internalformat, x, y, width, height); +} + +static void APIENTRY InitGetConvolutionFilter (GLenum target, GLenum format, GLenum type, GLvoid *image) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetConvolutionFilter"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetConvolutionFilter = extproc; + + glGetConvolutionFilter(target, format, type, image); +} + +static void APIENTRY InitGetConvolutionParameterfv (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetConvolutionParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetConvolutionParameterfv = extproc; + + glGetConvolutionParameterfv(target, pname, params); +} + +static void APIENTRY InitGetConvolutionParameteriv (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetConvolutionParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetConvolutionParameteriv = extproc; + + glGetConvolutionParameteriv(target, pname, params); +} + +static void APIENTRY InitGetSeparableFilter (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetSeparableFilter"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetSeparableFilter = extproc; + + glGetSeparableFilter(target, format, type, row, column, span); +} + +static void APIENTRY InitSeparableFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSeparableFilter2D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSeparableFilter2D = extproc; + + glSeparableFilter2D(target, internalformat, width, height, format, type, row, column); +} + +static void APIENTRY InitGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHistogram"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetHistogram = extproc; + + glGetHistogram(target, reset, format, type, values); +} + +static void APIENTRY InitGetHistogramParameterfv (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHistogramParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetHistogramParameterfv = extproc; + + glGetHistogramParameterfv(target, pname, params); +} + +static void APIENTRY InitGetHistogramParameteriv (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHistogramParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetHistogramParameteriv = extproc; + + glGetHistogramParameteriv(target, pname, params); +} + +static void APIENTRY InitGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMinmax"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMinmax = extproc; + + glGetMinmax(target, reset, format, type, values); +} + +static void APIENTRY InitGetMinmaxParameterfv (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMinmaxParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMinmaxParameterfv = extproc; + + glGetMinmaxParameterfv(target, pname, params); +} + +static void APIENTRY InitGetMinmaxParameteriv (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMinmaxParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMinmaxParameteriv = extproc; + + glGetMinmaxParameteriv(target, pname, params); +} + +static void APIENTRY InitHistogram (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glHistogram"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glHistogram = extproc; + + glHistogram(target, width, internalformat, sink); +} + +static void APIENTRY InitMinmax (GLenum target, GLenum internalformat, GLboolean sink) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMinmax"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMinmax = extproc; + + glMinmax(target, internalformat, sink); +} + +static void APIENTRY InitResetHistogram (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glResetHistogram"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glResetHistogram = extproc; + + glResetHistogram(target); +} + +static void APIENTRY InitResetMinmax (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glResetMinmax"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glResetMinmax = extproc; + + glResetMinmax(target); +} + +static void APIENTRY InitTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexImage3D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexImage3D = extproc; + + glTexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels); +} + +static void APIENTRY InitTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexSubImage3D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexSubImage3D = extproc; + + glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); +} + +static void APIENTRY InitCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyTexSubImage3D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyTexSubImage3D = extproc; + + glCopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height); +} + +static void APIENTRY InitActiveTexture (GLenum texture) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glActiveTexture"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glActiveTexture = extproc; + + glActiveTexture(texture); +} + +static void APIENTRY InitClientActiveTexture (GLenum texture) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glClientActiveTexture"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glClientActiveTexture = extproc; + + glClientActiveTexture(texture); +} + +static void APIENTRY InitMultiTexCoord1d (GLenum target, GLdouble s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1d = extproc; + + glMultiTexCoord1d(target, s); +} + +static void APIENTRY InitMultiTexCoord1dv (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1dv = extproc; + + glMultiTexCoord1dv(target, v); +} + +static void APIENTRY InitMultiTexCoord1f (GLenum target, GLfloat s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1f = extproc; + + glMultiTexCoord1f(target, s); +} + +static void APIENTRY InitMultiTexCoord1fv (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1fv = extproc; + + glMultiTexCoord1fv(target, v); +} + +static void APIENTRY InitMultiTexCoord1i (GLenum target, GLint s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1i = extproc; + + glMultiTexCoord1i(target, s); +} + +static void APIENTRY InitMultiTexCoord1iv (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1iv = extproc; + + glMultiTexCoord1iv(target, v); +} + +static void APIENTRY InitMultiTexCoord1s (GLenum target, GLshort s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1s = extproc; + + glMultiTexCoord1s(target, s); +} + +static void APIENTRY InitMultiTexCoord1sv (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1sv = extproc; + + glMultiTexCoord1sv(target, v); +} + +static void APIENTRY InitMultiTexCoord2d (GLenum target, GLdouble s, GLdouble t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2d = extproc; + + glMultiTexCoord2d(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2dv (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2dv = extproc; + + glMultiTexCoord2dv(target, v); +} + +static void APIENTRY InitMultiTexCoord2f (GLenum target, GLfloat s, GLfloat t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2f = extproc; + + glMultiTexCoord2f(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2fv (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2fv = extproc; + + glMultiTexCoord2fv(target, v); +} + +static void APIENTRY InitMultiTexCoord2i (GLenum target, GLint s, GLint t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2i = extproc; + + glMultiTexCoord2i(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2iv (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2iv = extproc; + + glMultiTexCoord2iv(target, v); +} + +static void APIENTRY InitMultiTexCoord2s (GLenum target, GLshort s, GLshort t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2s = extproc; + + glMultiTexCoord2s(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2sv (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2sv = extproc; + + glMultiTexCoord2sv(target, v); +} + +static void APIENTRY InitMultiTexCoord3d (GLenum target, GLdouble s, GLdouble t, GLdouble r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3d = extproc; + + glMultiTexCoord3d(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3dv (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3dv = extproc; + + glMultiTexCoord3dv(target, v); +} + +static void APIENTRY InitMultiTexCoord3f (GLenum target, GLfloat s, GLfloat t, GLfloat r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3f = extproc; + + glMultiTexCoord3f(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3fv (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3fv = extproc; + + glMultiTexCoord3fv(target, v); +} + +static void APIENTRY InitMultiTexCoord3i (GLenum target, GLint s, GLint t, GLint r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3i = extproc; + + glMultiTexCoord3i(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3iv (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3iv = extproc; + + glMultiTexCoord3iv(target, v); +} + +static void APIENTRY InitMultiTexCoord3s (GLenum target, GLshort s, GLshort t, GLshort r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3s = extproc; + + glMultiTexCoord3s(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3sv (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3sv = extproc; + + glMultiTexCoord3sv(target, v); +} + +static void APIENTRY InitMultiTexCoord4d (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4d = extproc; + + glMultiTexCoord4d(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4dv (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4dv = extproc; + + glMultiTexCoord4dv(target, v); +} + +static void APIENTRY InitMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4f = extproc; + + glMultiTexCoord4f(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4fv (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4fv = extproc; + + glMultiTexCoord4fv(target, v); +} + +static void APIENTRY InitMultiTexCoord4i (GLenum target, GLint s, GLint t, GLint r, GLint q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4i = extproc; + + glMultiTexCoord4i(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4iv (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4iv = extproc; + + glMultiTexCoord4iv(target, v); +} + +static void APIENTRY InitMultiTexCoord4s (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4s = extproc; + + glMultiTexCoord4s(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4sv (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4sv = extproc; + + glMultiTexCoord4sv(target, v); +} + +static void APIENTRY InitLoadTransposeMatrixf (const GLfloat *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLoadTransposeMatrixf"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLoadTransposeMatrixf = extproc; + + glLoadTransposeMatrixf(m); +} + +static void APIENTRY InitLoadTransposeMatrixd (const GLdouble *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLoadTransposeMatrixd"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLoadTransposeMatrixd = extproc; + + glLoadTransposeMatrixd(m); +} + +static void APIENTRY InitMultTransposeMatrixf (const GLfloat *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultTransposeMatrixf"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultTransposeMatrixf = extproc; + + glMultTransposeMatrixf(m); +} + +static void APIENTRY InitMultTransposeMatrixd (const GLdouble *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultTransposeMatrixd"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultTransposeMatrixd = extproc; + + glMultTransposeMatrixd(m); +} + +static void APIENTRY InitSampleCoverage (GLclampf value, GLboolean invert) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSampleCoverage"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSampleCoverage = extproc; + + glSampleCoverage(value, invert); +} + +static void APIENTRY InitCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexImage3D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexImage3D = extproc; + + glCompressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, data); +} + +static void APIENTRY InitCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexImage2D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexImage2D = extproc; + + glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); +} + +static void APIENTRY InitCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexImage1D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexImage1D = extproc; + + glCompressedTexImage1D(target, level, internalformat, width, border, imageSize, data); +} + +static void APIENTRY InitCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexSubImage3D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexSubImage3D = extproc; + + glCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); +} + +static void APIENTRY InitCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexSubImage2D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexSubImage2D = extproc; + + glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); +} + +static void APIENTRY InitCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexSubImage1D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexSubImage1D = extproc; + + glCompressedTexSubImage1D(target, level, xoffset, width, format, imageSize, data); +} + +static void APIENTRY InitGetCompressedTexImage (GLenum target, GLint level, GLvoid *img) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCompressedTexImage"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCompressedTexImage = extproc; + + glGetCompressedTexImage(target, level, img); +} + +static void APIENTRY InitBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendFuncSeparate"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendFuncSeparate = extproc; + + glBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); +} + +static void APIENTRY InitFogCoordf (GLfloat coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordf"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordf = extproc; + + glFogCoordf(coord); +} + +static void APIENTRY InitFogCoordfv (const GLfloat *coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordfv = extproc; + + glFogCoordfv(coord); +} + +static void APIENTRY InitFogCoordd (GLdouble coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordd"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordd = extproc; + + glFogCoordd(coord); +} + +static void APIENTRY InitFogCoorddv (const GLdouble *coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoorddv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoorddv = extproc; + + glFogCoorddv(coord); +} + +static void APIENTRY InitFogCoordPointer (GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordPointer"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordPointer = extproc; + + glFogCoordPointer(type, stride, pointer); +} + +static void APIENTRY InitMultiDrawArrays (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiDrawArrays"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiDrawArrays = extproc; + + glMultiDrawArrays(mode, first, count, primcount); +} + +static void APIENTRY InitMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiDrawElements"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiDrawElements = extproc; + + glMultiDrawElements(mode, count, type, indices, primcount); +} + +static void APIENTRY InitPointParameterf (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterf"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterf = extproc; + + glPointParameterf(pname, param); +} + +static void APIENTRY InitPointParameterfv (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfv = extproc; + + glPointParameterfv(pname, params); +} + +static void APIENTRY InitPointParameteri (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameteri"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameteri = extproc; + + glPointParameteri(pname, param); +} + +static void APIENTRY InitPointParameteriv (GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameteriv = extproc; + + glPointParameteriv(pname, params); +} + +static void APIENTRY InitSecondaryColor3b (GLbyte red, GLbyte green, GLbyte blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3b"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3b = extproc; + + glSecondaryColor3b(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3bv (const GLbyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3bv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3bv = extproc; + + glSecondaryColor3bv(v); +} + +static void APIENTRY InitSecondaryColor3d (GLdouble red, GLdouble green, GLdouble blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3d = extproc; + + glSecondaryColor3d(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3dv (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3dv = extproc; + + glSecondaryColor3dv(v); +} + +static void APIENTRY InitSecondaryColor3f (GLfloat red, GLfloat green, GLfloat blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3f = extproc; + + glSecondaryColor3f(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3fv (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3fv = extproc; + + glSecondaryColor3fv(v); +} + +static void APIENTRY InitSecondaryColor3i (GLint red, GLint green, GLint blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3i = extproc; + + glSecondaryColor3i(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3iv (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3iv = extproc; + + glSecondaryColor3iv(v); +} + +static void APIENTRY InitSecondaryColor3s (GLshort red, GLshort green, GLshort blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3s = extproc; + + glSecondaryColor3s(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3sv (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3sv = extproc; + + glSecondaryColor3sv(v); +} + +static void APIENTRY InitSecondaryColor3ub (GLubyte red, GLubyte green, GLubyte blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3ub"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3ub = extproc; + + glSecondaryColor3ub(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3ubv (const GLubyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3ubv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3ubv = extproc; + + glSecondaryColor3ubv(v); +} + +static void APIENTRY InitSecondaryColor3ui (GLuint red, GLuint green, GLuint blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3ui"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3ui = extproc; + + glSecondaryColor3ui(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3uiv (const GLuint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3uiv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3uiv = extproc; + + glSecondaryColor3uiv(v); +} + +static void APIENTRY InitSecondaryColor3us (GLushort red, GLushort green, GLushort blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3us"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3us = extproc; + + glSecondaryColor3us(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3usv (const GLushort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3usv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3usv = extproc; + + glSecondaryColor3usv(v); +} + +static void APIENTRY InitSecondaryColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColorPointer"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColorPointer = extproc; + + glSecondaryColorPointer(size, type, stride, pointer); +} + +static void APIENTRY InitWindowPos2d (GLdouble x, GLdouble y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2d = extproc; + + glWindowPos2d(x, y); +} + +static void APIENTRY InitWindowPos2dv (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2dv = extproc; + + glWindowPos2dv(v); +} + +static void APIENTRY InitWindowPos2f (GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2f = extproc; + + glWindowPos2f(x, y); +} + +static void APIENTRY InitWindowPos2fv (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2fv = extproc; + + glWindowPos2fv(v); +} + +static void APIENTRY InitWindowPos2i (GLint x, GLint y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2i = extproc; + + glWindowPos2i(x, y); +} + +static void APIENTRY InitWindowPos2iv (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2iv = extproc; + + glWindowPos2iv(v); +} + +static void APIENTRY InitWindowPos2s (GLshort x, GLshort y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2s = extproc; + + glWindowPos2s(x, y); +} + +static void APIENTRY InitWindowPos2sv (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2sv = extproc; + + glWindowPos2sv(v); +} + +static void APIENTRY InitWindowPos3d (GLdouble x, GLdouble y, GLdouble z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3d = extproc; + + glWindowPos3d(x, y, z); +} + +static void APIENTRY InitWindowPos3dv (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3dv = extproc; + + glWindowPos3dv(v); +} + +static void APIENTRY InitWindowPos3f (GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3f = extproc; + + glWindowPos3f(x, y, z); +} + +static void APIENTRY InitWindowPos3fv (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3fv = extproc; + + glWindowPos3fv(v); +} + +static void APIENTRY InitWindowPos3i (GLint x, GLint y, GLint z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3i = extproc; + + glWindowPos3i(x, y, z); +} + +static void APIENTRY InitWindowPos3iv (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3iv = extproc; + + glWindowPos3iv(v); +} + +static void APIENTRY InitWindowPos3s (GLshort x, GLshort y, GLshort z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3s = extproc; + + glWindowPos3s(x, y, z); +} + +static void APIENTRY InitWindowPos3sv (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3sv = extproc; + + glWindowPos3sv(v); +} + +static void APIENTRY InitGenQueries (GLsizei n, GLuint *ids) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenQueries"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenQueries = extproc; + + glGenQueries(n, ids); +} + +static void APIENTRY InitDeleteQueries (GLsizei n, const GLuint *ids) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteQueries"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteQueries = extproc; + + glDeleteQueries(n, ids); +} + +static GLboolean APIENTRY InitIsQuery (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsQuery"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsQuery = extproc; + + return glIsQuery(id); +} + +static void APIENTRY InitBeginQuery (GLenum target, GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBeginQuery"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBeginQuery = extproc; + + glBeginQuery(target, id); +} + +static void APIENTRY InitEndQuery (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEndQuery"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEndQuery = extproc; + + glEndQuery(target); +} + +static void APIENTRY InitGetQueryiv (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetQueryiv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetQueryiv = extproc; + + glGetQueryiv(target, pname, params); +} + +static void APIENTRY InitGetQueryObjectiv (GLuint id, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetQueryObjectiv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetQueryObjectiv = extproc; + + glGetQueryObjectiv(id, pname, params); +} + +static void APIENTRY InitGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetQueryObjectuiv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetQueryObjectuiv = extproc; + + glGetQueryObjectuiv(id, pname, params); +} + +static void APIENTRY InitBindBuffer (GLenum target, GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindBuffer"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindBuffer = extproc; + + glBindBuffer(target, buffer); +} + +static void APIENTRY InitDeleteBuffers (GLsizei n, const GLuint *buffers) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteBuffers"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteBuffers = extproc; + + glDeleteBuffers(n, buffers); +} + +static void APIENTRY InitGenBuffers (GLsizei n, GLuint *buffers) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenBuffers"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenBuffers = extproc; + + glGenBuffers(n, buffers); +} + +static GLboolean APIENTRY InitIsBuffer (GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsBuffer"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsBuffer = extproc; + + return glIsBuffer(buffer); +} + +static void APIENTRY InitBufferData (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBufferData"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBufferData = extproc; + + glBufferData(target, size, data, usage); +} + +static void APIENTRY InitBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBufferSubData"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBufferSubData = extproc; + + glBufferSubData(target, offset, size, data); +} + +static void APIENTRY InitGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetBufferSubData"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetBufferSubData = extproc; + + glGetBufferSubData(target, offset, size, data); +} + +static GLvoid* APIENTRY InitMapBuffer (GLenum target, GLenum access) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMapBuffer"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glMapBuffer = extproc; + + return glMapBuffer(target, access); +} + +static GLboolean APIENTRY InitUnmapBuffer (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUnmapBuffer"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glUnmapBuffer = extproc; + + return glUnmapBuffer(target); +} + +static void APIENTRY InitGetBufferParameteriv (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetBufferParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetBufferParameteriv = extproc; + + glGetBufferParameteriv(target, pname, params); +} + +static void APIENTRY InitGetBufferPointerv (GLenum target, GLenum pname, GLvoid* *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetBufferPointerv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetBufferPointerv = extproc; + + glGetBufferPointerv(target, pname, params); +} + +static void APIENTRY InitActiveTextureARB (GLenum texture) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glActiveTextureARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glActiveTextureARB = extproc; + + glActiveTextureARB(texture); +} + +static void APIENTRY InitClientActiveTextureARB (GLenum texture) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glClientActiveTextureARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glClientActiveTextureARB = extproc; + + glClientActiveTextureARB(texture); +} + +static void APIENTRY InitMultiTexCoord1dARB (GLenum target, GLdouble s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1dARB = extproc; + + glMultiTexCoord1dARB(target, s); +} + +static void APIENTRY InitMultiTexCoord1dvARB (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1dvARB = extproc; + + glMultiTexCoord1dvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord1fARB (GLenum target, GLfloat s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1fARB = extproc; + + glMultiTexCoord1fARB(target, s); +} + +static void APIENTRY InitMultiTexCoord1fvARB (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1fvARB = extproc; + + glMultiTexCoord1fvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord1iARB (GLenum target, GLint s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1iARB = extproc; + + glMultiTexCoord1iARB(target, s); +} + +static void APIENTRY InitMultiTexCoord1ivARB (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1ivARB = extproc; + + glMultiTexCoord1ivARB(target, v); +} + +static void APIENTRY InitMultiTexCoord1sARB (GLenum target, GLshort s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1sARB = extproc; + + glMultiTexCoord1sARB(target, s); +} + +static void APIENTRY InitMultiTexCoord1svARB (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1svARB = extproc; + + glMultiTexCoord1svARB(target, v); +} + +static void APIENTRY InitMultiTexCoord2dARB (GLenum target, GLdouble s, GLdouble t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2dARB = extproc; + + glMultiTexCoord2dARB(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2dvARB (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2dvARB = extproc; + + glMultiTexCoord2dvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord2fARB (GLenum target, GLfloat s, GLfloat t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2fARB = extproc; + + glMultiTexCoord2fARB(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2fvARB (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2fvARB = extproc; + + glMultiTexCoord2fvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord2iARB (GLenum target, GLint s, GLint t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2iARB = extproc; + + glMultiTexCoord2iARB(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2ivARB (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2ivARB = extproc; + + glMultiTexCoord2ivARB(target, v); +} + +static void APIENTRY InitMultiTexCoord2sARB (GLenum target, GLshort s, GLshort t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2sARB = extproc; + + glMultiTexCoord2sARB(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2svARB (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2svARB = extproc; + + glMultiTexCoord2svARB(target, v); +} + +static void APIENTRY InitMultiTexCoord3dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3dARB = extproc; + + glMultiTexCoord3dARB(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3dvARB (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3dvARB = extproc; + + glMultiTexCoord3dvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord3fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3fARB = extproc; + + glMultiTexCoord3fARB(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3fvARB (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3fvARB = extproc; + + glMultiTexCoord3fvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord3iARB (GLenum target, GLint s, GLint t, GLint r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3iARB = extproc; + + glMultiTexCoord3iARB(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3ivARB (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3ivARB = extproc; + + glMultiTexCoord3ivARB(target, v); +} + +static void APIENTRY InitMultiTexCoord3sARB (GLenum target, GLshort s, GLshort t, GLshort r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3sARB = extproc; + + glMultiTexCoord3sARB(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3svARB (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3svARB = extproc; + + glMultiTexCoord3svARB(target, v); +} + +static void APIENTRY InitMultiTexCoord4dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4dARB = extproc; + + glMultiTexCoord4dARB(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4dvARB (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4dvARB = extproc; + + glMultiTexCoord4dvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord4fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4fARB = extproc; + + glMultiTexCoord4fARB(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4fvARB (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4fvARB = extproc; + + glMultiTexCoord4fvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord4iARB (GLenum target, GLint s, GLint t, GLint r, GLint q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4iARB = extproc; + + glMultiTexCoord4iARB(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4ivARB (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4ivARB = extproc; + + glMultiTexCoord4ivARB(target, v); +} + +static void APIENTRY InitMultiTexCoord4sARB (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4sARB = extproc; + + glMultiTexCoord4sARB(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4svARB (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4svARB = extproc; + + glMultiTexCoord4svARB(target, v); +} + +static void APIENTRY InitLoadTransposeMatrixfARB (const GLfloat *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLoadTransposeMatrixfARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLoadTransposeMatrixfARB = extproc; + + glLoadTransposeMatrixfARB(m); +} + +static void APIENTRY InitLoadTransposeMatrixdARB (const GLdouble *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLoadTransposeMatrixdARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLoadTransposeMatrixdARB = extproc; + + glLoadTransposeMatrixdARB(m); +} + +static void APIENTRY InitMultTransposeMatrixfARB (const GLfloat *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultTransposeMatrixfARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultTransposeMatrixfARB = extproc; + + glMultTransposeMatrixfARB(m); +} + +static void APIENTRY InitMultTransposeMatrixdARB (const GLdouble *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultTransposeMatrixdARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultTransposeMatrixdARB = extproc; + + glMultTransposeMatrixdARB(m); +} + +static void APIENTRY InitSampleCoverageARB (GLclampf value, GLboolean invert) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSampleCoverageARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSampleCoverageARB = extproc; + + glSampleCoverageARB(value, invert); +} + +static void APIENTRY InitCompressedTexImage3DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexImage3DARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexImage3DARB = extproc; + + glCompressedTexImage3DARB(target, level, internalformat, width, height, depth, border, imageSize, data); +} + +static void APIENTRY InitCompressedTexImage2DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexImage2DARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexImage2DARB = extproc; + + glCompressedTexImage2DARB(target, level, internalformat, width, height, border, imageSize, data); +} + +static void APIENTRY InitCompressedTexImage1DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexImage1DARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexImage1DARB = extproc; + + glCompressedTexImage1DARB(target, level, internalformat, width, border, imageSize, data); +} + +static void APIENTRY InitCompressedTexSubImage3DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexSubImage3DARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexSubImage3DARB = extproc; + + glCompressedTexSubImage3DARB(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); +} + +static void APIENTRY InitCompressedTexSubImage2DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexSubImage2DARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexSubImage2DARB = extproc; + + glCompressedTexSubImage2DARB(target, level, xoffset, yoffset, width, height, format, imageSize, data); +} + +static void APIENTRY InitCompressedTexSubImage1DARB (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexSubImage1DARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexSubImage1DARB = extproc; + + glCompressedTexSubImage1DARB(target, level, xoffset, width, format, imageSize, data); +} + +static void APIENTRY InitGetCompressedTexImageARB (GLenum target, GLint level, GLvoid *img) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCompressedTexImageARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCompressedTexImageARB = extproc; + + glGetCompressedTexImageARB(target, level, img); +} + +static void APIENTRY InitPointParameterfARB (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfARB = extproc; + + glPointParameterfARB(pname, param); +} + +static void APIENTRY InitPointParameterfvARB (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfvARB = extproc; + + glPointParameterfvARB(pname, params); +} + +static void APIENTRY InitWeightbvARB (GLint size, const GLbyte *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightbvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightbvARB = extproc; + + glWeightbvARB(size, weights); +} + +static void APIENTRY InitWeightsvARB (GLint size, const GLshort *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightsvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightsvARB = extproc; + + glWeightsvARB(size, weights); +} + +static void APIENTRY InitWeightivARB (GLint size, const GLint *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightivARB = extproc; + + glWeightivARB(size, weights); +} + +static void APIENTRY InitWeightfvARB (GLint size, const GLfloat *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightfvARB = extproc; + + glWeightfvARB(size, weights); +} + +static void APIENTRY InitWeightdvARB (GLint size, const GLdouble *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightdvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightdvARB = extproc; + + glWeightdvARB(size, weights); +} + +static void APIENTRY InitWeightubvARB (GLint size, const GLubyte *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightubvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightubvARB = extproc; + + glWeightubvARB(size, weights); +} + +static void APIENTRY InitWeightusvARB (GLint size, const GLushort *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightusvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightusvARB = extproc; + + glWeightusvARB(size, weights); +} + +static void APIENTRY InitWeightuivARB (GLint size, const GLuint *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightuivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightuivARB = extproc; + + glWeightuivARB(size, weights); +} + +static void APIENTRY InitWeightPointerARB (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightPointerARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightPointerARB = extproc; + + glWeightPointerARB(size, type, stride, pointer); +} + +static void APIENTRY InitVertexBlendARB (GLint count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexBlendARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexBlendARB = extproc; + + glVertexBlendARB(count); +} + +static void APIENTRY InitCurrentPaletteMatrixARB (GLint index) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCurrentPaletteMatrixARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCurrentPaletteMatrixARB = extproc; + + glCurrentPaletteMatrixARB(index); +} + +static void APIENTRY InitMatrixIndexubvARB (GLint size, const GLubyte *indices) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMatrixIndexubvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMatrixIndexubvARB = extproc; + + glMatrixIndexubvARB(size, indices); +} + +static void APIENTRY InitMatrixIndexusvARB (GLint size, const GLushort *indices) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMatrixIndexusvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMatrixIndexusvARB = extproc; + + glMatrixIndexusvARB(size, indices); +} + +static void APIENTRY InitMatrixIndexuivARB (GLint size, const GLuint *indices) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMatrixIndexuivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMatrixIndexuivARB = extproc; + + glMatrixIndexuivARB(size, indices); +} + +static void APIENTRY InitMatrixIndexPointerARB (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMatrixIndexPointerARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMatrixIndexPointerARB = extproc; + + glMatrixIndexPointerARB(size, type, stride, pointer); +} + +static void APIENTRY InitWindowPos2dARB (GLdouble x, GLdouble y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2dARB = extproc; + + glWindowPos2dARB(x, y); +} + +static void APIENTRY InitWindowPos2dvARB (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2dvARB = extproc; + + glWindowPos2dvARB(v); +} + +static void APIENTRY InitWindowPos2fARB (GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2fARB = extproc; + + glWindowPos2fARB(x, y); +} + +static void APIENTRY InitWindowPos2fvARB (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2fvARB = extproc; + + glWindowPos2fvARB(v); +} + +static void APIENTRY InitWindowPos2iARB (GLint x, GLint y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2iARB = extproc; + + glWindowPos2iARB(x, y); +} + +static void APIENTRY InitWindowPos2ivARB (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2ivARB = extproc; + + glWindowPos2ivARB(v); +} + +static void APIENTRY InitWindowPos2sARB (GLshort x, GLshort y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2sARB = extproc; + + glWindowPos2sARB(x, y); +} + +static void APIENTRY InitWindowPos2svARB (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2svARB = extproc; + + glWindowPos2svARB(v); +} + +static void APIENTRY InitWindowPos3dARB (GLdouble x, GLdouble y, GLdouble z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3dARB = extproc; + + glWindowPos3dARB(x, y, z); +} + +static void APIENTRY InitWindowPos3dvARB (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3dvARB = extproc; + + glWindowPos3dvARB(v); +} + +static void APIENTRY InitWindowPos3fARB (GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3fARB = extproc; + + glWindowPos3fARB(x, y, z); +} + +static void APIENTRY InitWindowPos3fvARB (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3fvARB = extproc; + + glWindowPos3fvARB(v); +} + +static void APIENTRY InitWindowPos3iARB (GLint x, GLint y, GLint z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3iARB = extproc; + + glWindowPos3iARB(x, y, z); +} + +static void APIENTRY InitWindowPos3ivARB (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3ivARB = extproc; + + glWindowPos3ivARB(v); +} + +static void APIENTRY InitWindowPos3sARB (GLshort x, GLshort y, GLshort z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3sARB = extproc; + + glWindowPos3sARB(x, y, z); +} + +static void APIENTRY InitWindowPos3svARB (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3svARB = extproc; + + glWindowPos3svARB(v); +} + +static void APIENTRY InitVertexAttrib1dARB (GLuint index, GLdouble x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1dARB = extproc; + + glVertexAttrib1dARB(index, x); +} + +static void APIENTRY InitVertexAttrib1dvARB (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1dvARB = extproc; + + glVertexAttrib1dvARB(index, v); +} + +static void APIENTRY InitVertexAttrib1fARB (GLuint index, GLfloat x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1fARB = extproc; + + glVertexAttrib1fARB(index, x); +} + +static void APIENTRY InitVertexAttrib1fvARB (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1fvARB = extproc; + + glVertexAttrib1fvARB(index, v); +} + +static void APIENTRY InitVertexAttrib1sARB (GLuint index, GLshort x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1sARB = extproc; + + glVertexAttrib1sARB(index, x); +} + +static void APIENTRY InitVertexAttrib1svARB (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1svARB = extproc; + + glVertexAttrib1svARB(index, v); +} + +static void APIENTRY InitVertexAttrib2dARB (GLuint index, GLdouble x, GLdouble y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2dARB = extproc; + + glVertexAttrib2dARB(index, x, y); +} + +static void APIENTRY InitVertexAttrib2dvARB (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2dvARB = extproc; + + glVertexAttrib2dvARB(index, v); +} + +static void APIENTRY InitVertexAttrib2fARB (GLuint index, GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2fARB = extproc; + + glVertexAttrib2fARB(index, x, y); +} + +static void APIENTRY InitVertexAttrib2fvARB (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2fvARB = extproc; + + glVertexAttrib2fvARB(index, v); +} + +static void APIENTRY InitVertexAttrib2sARB (GLuint index, GLshort x, GLshort y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2sARB = extproc; + + glVertexAttrib2sARB(index, x, y); +} + +static void APIENTRY InitVertexAttrib2svARB (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2svARB = extproc; + + glVertexAttrib2svARB(index, v); +} + +static void APIENTRY InitVertexAttrib3dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3dARB = extproc; + + glVertexAttrib3dARB(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3dvARB (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3dvARB = extproc; + + glVertexAttrib3dvARB(index, v); +} + +static void APIENTRY InitVertexAttrib3fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3fARB = extproc; + + glVertexAttrib3fARB(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3fvARB (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3fvARB = extproc; + + glVertexAttrib3fvARB(index, v); +} + +static void APIENTRY InitVertexAttrib3sARB (GLuint index, GLshort x, GLshort y, GLshort z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3sARB = extproc; + + glVertexAttrib3sARB(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3svARB (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3svARB = extproc; + + glVertexAttrib3svARB(index, v); +} + +static void APIENTRY InitVertexAttrib4NbvARB (GLuint index, const GLbyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NbvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NbvARB = extproc; + + glVertexAttrib4NbvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4NivARB (GLuint index, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NivARB = extproc; + + glVertexAttrib4NivARB(index, v); +} + +static void APIENTRY InitVertexAttrib4NsvARB (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NsvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NsvARB = extproc; + + glVertexAttrib4NsvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4NubARB (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NubARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NubARB = extproc; + + glVertexAttrib4NubARB(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4NubvARB (GLuint index, const GLubyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NubvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NubvARB = extproc; + + glVertexAttrib4NubvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4NuivARB (GLuint index, const GLuint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NuivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NuivARB = extproc; + + glVertexAttrib4NuivARB(index, v); +} + +static void APIENTRY InitVertexAttrib4NusvARB (GLuint index, const GLushort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NusvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NusvARB = extproc; + + glVertexAttrib4NusvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4bvARB (GLuint index, const GLbyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4bvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4bvARB = extproc; + + glVertexAttrib4bvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4dARB = extproc; + + glVertexAttrib4dARB(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4dvARB (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4dvARB = extproc; + + glVertexAttrib4dvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4fARB = extproc; + + glVertexAttrib4fARB(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4fvARB (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4fvARB = extproc; + + glVertexAttrib4fvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4ivARB (GLuint index, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4ivARB = extproc; + + glVertexAttrib4ivARB(index, v); +} + +static void APIENTRY InitVertexAttrib4sARB (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4sARB = extproc; + + glVertexAttrib4sARB(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4svARB (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4svARB = extproc; + + glVertexAttrib4svARB(index, v); +} + +static void APIENTRY InitVertexAttrib4ubvARB (GLuint index, const GLubyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4ubvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4ubvARB = extproc; + + glVertexAttrib4ubvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4uivARB (GLuint index, const GLuint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4uivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4uivARB = extproc; + + glVertexAttrib4uivARB(index, v); +} + +static void APIENTRY InitVertexAttrib4usvARB (GLuint index, const GLushort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4usvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4usvARB = extproc; + + glVertexAttrib4usvARB(index, v); +} + +static void APIENTRY InitVertexAttribPointerARB (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribPointerARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribPointerARB = extproc; + + glVertexAttribPointerARB(index, size, type, normalized, stride, pointer); +} + +static void APIENTRY InitEnableVertexAttribArrayARB (GLuint index) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEnableVertexAttribArrayARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEnableVertexAttribArrayARB = extproc; + + glEnableVertexAttribArrayARB(index); +} + +static void APIENTRY InitDisableVertexAttribArrayARB (GLuint index) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDisableVertexAttribArrayARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDisableVertexAttribArrayARB = extproc; + + glDisableVertexAttribArrayARB(index); +} + +static void APIENTRY InitProgramStringARB (GLenum target, GLenum format, GLsizei len, const GLvoid *string) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramStringARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramStringARB = extproc; + + glProgramStringARB(target, format, len, string); +} + +static void APIENTRY InitBindProgramARB (GLenum target, GLuint program) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindProgramARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindProgramARB = extproc; + + glBindProgramARB(target, program); +} + +static void APIENTRY InitDeleteProgramsARB (GLsizei n, const GLuint *programs) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteProgramsARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteProgramsARB = extproc; + + glDeleteProgramsARB(n, programs); +} + +static void APIENTRY InitGenProgramsARB (GLsizei n, GLuint *programs) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenProgramsARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenProgramsARB = extproc; + + glGenProgramsARB(n, programs); +} + +static void APIENTRY InitProgramEnvParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramEnvParameter4dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramEnvParameter4dARB = extproc; + + glProgramEnvParameter4dARB(target, index, x, y, z, w); +} + +static void APIENTRY InitProgramEnvParameter4dvARB (GLenum target, GLuint index, const GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramEnvParameter4dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramEnvParameter4dvARB = extproc; + + glProgramEnvParameter4dvARB(target, index, params); +} + +static void APIENTRY InitProgramEnvParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramEnvParameter4fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramEnvParameter4fARB = extproc; + + glProgramEnvParameter4fARB(target, index, x, y, z, w); +} + +static void APIENTRY InitProgramEnvParameter4fvARB (GLenum target, GLuint index, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramEnvParameter4fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramEnvParameter4fvARB = extproc; + + glProgramEnvParameter4fvARB(target, index, params); +} + +static void APIENTRY InitProgramLocalParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramLocalParameter4dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramLocalParameter4dARB = extproc; + + glProgramLocalParameter4dARB(target, index, x, y, z, w); +} + +static void APIENTRY InitProgramLocalParameter4dvARB (GLenum target, GLuint index, const GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramLocalParameter4dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramLocalParameter4dvARB = extproc; + + glProgramLocalParameter4dvARB(target, index, params); +} + +static void APIENTRY InitProgramLocalParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramLocalParameter4fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramLocalParameter4fARB = extproc; + + glProgramLocalParameter4fARB(target, index, x, y, z, w); +} + +static void APIENTRY InitProgramLocalParameter4fvARB (GLenum target, GLuint index, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramLocalParameter4fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramLocalParameter4fvARB = extproc; + + glProgramLocalParameter4fvARB(target, index, params); +} + +static void APIENTRY InitGetProgramEnvParameterdvARB (GLenum target, GLuint index, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramEnvParameterdvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramEnvParameterdvARB = extproc; + + glGetProgramEnvParameterdvARB(target, index, params); +} + +static void APIENTRY InitGetProgramEnvParameterfvARB (GLenum target, GLuint index, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramEnvParameterfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramEnvParameterfvARB = extproc; + + glGetProgramEnvParameterfvARB(target, index, params); +} + +static void APIENTRY InitGetProgramLocalParameterdvARB (GLenum target, GLuint index, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramLocalParameterdvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramLocalParameterdvARB = extproc; + + glGetProgramLocalParameterdvARB(target, index, params); +} + +static void APIENTRY InitGetProgramLocalParameterfvARB (GLenum target, GLuint index, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramLocalParameterfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramLocalParameterfvARB = extproc; + + glGetProgramLocalParameterfvARB(target, index, params); +} + +static void APIENTRY InitGetProgramivARB (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramivARB = extproc; + + glGetProgramivARB(target, pname, params); +} + +static void APIENTRY InitGetProgramStringARB (GLenum target, GLenum pname, GLvoid *string) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramStringARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramStringARB = extproc; + + glGetProgramStringARB(target, pname, string); +} + +static void APIENTRY InitGetVertexAttribdvARB (GLuint index, GLenum pname, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribdvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribdvARB = extproc; + + glGetVertexAttribdvARB(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribfvARB (GLuint index, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribfvARB = extproc; + + glGetVertexAttribfvARB(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribivARB (GLuint index, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribivARB = extproc; + + glGetVertexAttribivARB(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribPointervARB (GLuint index, GLenum pname, GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribPointervARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribPointervARB = extproc; + + glGetVertexAttribPointervARB(index, pname, pointer); +} + +static GLboolean APIENTRY InitIsProgramARB (GLuint program) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsProgramARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsProgramARB = extproc; + + return glIsProgramARB(program); +} + +static void APIENTRY InitBindBufferARB (GLenum target, GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindBufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindBufferARB = extproc; + + glBindBufferARB(target, buffer); +} + +static void APIENTRY InitDeleteBuffersARB (GLsizei n, const GLuint *buffers) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteBuffersARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteBuffersARB = extproc; + + glDeleteBuffersARB(n, buffers); +} + +static void APIENTRY InitGenBuffersARB (GLsizei n, GLuint *buffers) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenBuffersARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenBuffersARB = extproc; + + glGenBuffersARB(n, buffers); +} + +static GLboolean APIENTRY InitIsBufferARB (GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsBufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsBufferARB = extproc; + + return glIsBufferARB(buffer); +} + +static void APIENTRY InitBufferDataARB (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBufferDataARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBufferDataARB = extproc; + + glBufferDataARB(target, size, data, usage); +} + +static void APIENTRY InitBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBufferSubDataARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBufferSubDataARB = extproc; + + glBufferSubDataARB(target, offset, size, data); +} + +static void APIENTRY InitGetBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetBufferSubDataARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetBufferSubDataARB = extproc; + + glGetBufferSubDataARB(target, offset, size, data); +} + +static GLvoid* APIENTRY InitMapBufferARB (GLenum target, GLenum access) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMapBufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glMapBufferARB = extproc; + + return glMapBufferARB(target, access); +} + +static GLboolean APIENTRY InitUnmapBufferARB (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUnmapBufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glUnmapBufferARB = extproc; + + return glUnmapBufferARB(target); +} + +static void APIENTRY InitGetBufferParameterivARB (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetBufferParameterivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetBufferParameterivARB = extproc; + + glGetBufferParameterivARB(target, pname, params); +} + +static void APIENTRY InitGetBufferPointervARB (GLenum target, GLenum pname, GLvoid* *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetBufferPointervARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetBufferPointervARB = extproc; + + glGetBufferPointervARB(target, pname, params); +} + +static void APIENTRY InitGenQueriesARB (GLsizei n, GLuint *ids) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenQueriesARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenQueriesARB = extproc; + + glGenQueriesARB(n, ids); +} + +static void APIENTRY InitDeleteQueriesARB (GLsizei n, const GLuint *ids) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteQueriesARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteQueriesARB = extproc; + + glDeleteQueriesARB(n, ids); +} + +static GLboolean APIENTRY InitIsQueryARB (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsQueryARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsQueryARB = extproc; + + return glIsQueryARB(id); +} + +static void APIENTRY InitBeginQueryARB (GLenum target, GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBeginQueryARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBeginQueryARB = extproc; + + glBeginQueryARB(target, id); +} + +static void APIENTRY InitEndQueryARB (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEndQueryARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEndQueryARB = extproc; + + glEndQueryARB(target); +} + +static void APIENTRY InitGetQueryivARB (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetQueryivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetQueryivARB = extproc; + + glGetQueryivARB(target, pname, params); +} + +static void APIENTRY InitGetQueryObjectivARB (GLuint id, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetQueryObjectivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetQueryObjectivARB = extproc; + + glGetQueryObjectivARB(id, pname, params); +} + +static void APIENTRY InitGetQueryObjectuivARB (GLuint id, GLenum pname, GLuint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetQueryObjectuivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetQueryObjectuivARB = extproc; + + glGetQueryObjectuivARB(id, pname, params); +} + +static void APIENTRY InitDeleteObjectARB (GLhandleARB obj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteObjectARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteObjectARB = extproc; + + glDeleteObjectARB(obj); +} + +static GLhandleARB APIENTRY InitGetHandleARB (GLenum pname) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHandleARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGetHandleARB = extproc; + + return glGetHandleARB(pname); +} + +static void APIENTRY InitDetachObjectARB (GLhandleARB containerObj, GLhandleARB attachedObj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDetachObjectARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDetachObjectARB = extproc; + + glDetachObjectARB(containerObj, attachedObj); +} + +static GLhandleARB APIENTRY InitCreateShaderObjectARB (GLenum shaderType) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCreateShaderObjectARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glCreateShaderObjectARB = extproc; + + return glCreateShaderObjectARB(shaderType); +} + +static void APIENTRY InitShaderSourceARB (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glShaderSourceARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glShaderSourceARB = extproc; + + glShaderSourceARB(shaderObj, count, string, length); +} + +static void APIENTRY InitCompileShaderARB (GLhandleARB shaderObj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompileShaderARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompileShaderARB = extproc; + + glCompileShaderARB(shaderObj); +} + +static GLhandleARB APIENTRY InitCreateProgramObjectARB (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCreateProgramObjectARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glCreateProgramObjectARB = extproc; + + return glCreateProgramObjectARB(); +} + +static void APIENTRY InitAttachObjectARB (GLhandleARB containerObj, GLhandleARB obj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAttachObjectARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glAttachObjectARB = extproc; + + glAttachObjectARB(containerObj, obj); +} + +static void APIENTRY InitLinkProgramARB (GLhandleARB programObj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLinkProgramARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLinkProgramARB = extproc; + + glLinkProgramARB(programObj); +} + +static void APIENTRY InitUseProgramObjectARB (GLhandleARB programObj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUseProgramObjectARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUseProgramObjectARB = extproc; + + glUseProgramObjectARB(programObj); +} + +static void APIENTRY InitValidateProgramARB (GLhandleARB programObj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glValidateProgramARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glValidateProgramARB = extproc; + + glValidateProgramARB(programObj); +} + +static void APIENTRY InitUniform1fARB (GLint location, GLfloat v0) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform1fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform1fARB = extproc; + + glUniform1fARB(location, v0); +} + +static void APIENTRY InitUniform2fARB (GLint location, GLfloat v0, GLfloat v1) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform2fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform2fARB = extproc; + + glUniform2fARB(location, v0, v1); +} + +static void APIENTRY InitUniform3fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform3fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform3fARB = extproc; + + glUniform3fARB(location, v0, v1, v2); +} + +static void APIENTRY InitUniform4fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform4fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform4fARB = extproc; + + glUniform4fARB(location, v0, v1, v2, v3); +} + +static void APIENTRY InitUniform1iARB (GLint location, GLint v0) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform1iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform1iARB = extproc; + + glUniform1iARB(location, v0); +} + +static void APIENTRY InitUniform2iARB (GLint location, GLint v0, GLint v1) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform2iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform2iARB = extproc; + + glUniform2iARB(location, v0, v1); +} + +static void APIENTRY InitUniform3iARB (GLint location, GLint v0, GLint v1, GLint v2) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform3iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform3iARB = extproc; + + glUniform3iARB(location, v0, v1, v2); +} + +static void APIENTRY InitUniform4iARB (GLint location, GLint v0, GLint v1, GLint v2, GLint v3) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform4iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform4iARB = extproc; + + glUniform4iARB(location, v0, v1, v2, v3); +} + +static void APIENTRY InitUniform1fvARB (GLint location, GLsizei count, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform1fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform1fvARB = extproc; + + glUniform1fvARB(location, count, value); +} + +static void APIENTRY InitUniform2fvARB (GLint location, GLsizei count, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform2fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform2fvARB = extproc; + + glUniform2fvARB(location, count, value); +} + +static void APIENTRY InitUniform3fvARB (GLint location, GLsizei count, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform3fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform3fvARB = extproc; + + glUniform3fvARB(location, count, value); +} + +static void APIENTRY InitUniform4fvARB (GLint location, GLsizei count, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform4fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform4fvARB = extproc; + + glUniform4fvARB(location, count, value); +} + +static void APIENTRY InitUniform1ivARB (GLint location, GLsizei count, const GLint *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform1ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform1ivARB = extproc; + + glUniform1ivARB(location, count, value); +} + +static void APIENTRY InitUniform2ivARB (GLint location, GLsizei count, const GLint *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform2ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform2ivARB = extproc; + + glUniform2ivARB(location, count, value); +} + +static void APIENTRY InitUniform3ivARB (GLint location, GLsizei count, const GLint *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform3ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform3ivARB = extproc; + + glUniform3ivARB(location, count, value); +} + +static void APIENTRY InitUniform4ivARB (GLint location, GLsizei count, const GLint *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform4ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform4ivARB = extproc; + + glUniform4ivARB(location, count, value); +} + +static void APIENTRY InitUniformMatrix2fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniformMatrix2fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniformMatrix2fvARB = extproc; + + glUniformMatrix2fvARB(location, count, transpose, value); +} + +static void APIENTRY InitUniformMatrix3fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniformMatrix3fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniformMatrix3fvARB = extproc; + + glUniformMatrix3fvARB(location, count, transpose, value); +} + +static void APIENTRY InitUniformMatrix4fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniformMatrix4fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniformMatrix4fvARB = extproc; + + glUniformMatrix4fvARB(location, count, transpose, value); +} + +static void APIENTRY InitGetObjectParameterfvARB (GLhandleARB obj, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetObjectParameterfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetObjectParameterfvARB = extproc; + + glGetObjectParameterfvARB(obj, pname, params); +} + +static void APIENTRY InitGetObjectParameterivARB (GLhandleARB obj, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetObjectParameterivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetObjectParameterivARB = extproc; + + glGetObjectParameterivARB(obj, pname, params); +} + +static void APIENTRY InitGetInfoLogARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetInfoLogARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetInfoLogARB = extproc; + + glGetInfoLogARB(obj, maxLength, length, infoLog); +} + +static void APIENTRY InitGetAttachedObjectsARB (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetAttachedObjectsARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetAttachedObjectsARB = extproc; + + glGetAttachedObjectsARB(containerObj, maxCount, count, obj); +} + +static GLint APIENTRY InitGetUniformLocationARB (GLhandleARB programObj, const GLcharARB *name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetUniformLocationARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGetUniformLocationARB = extproc; + + return glGetUniformLocationARB(programObj, name); +} + +static void APIENTRY InitGetActiveUniformARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetActiveUniformARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetActiveUniformARB = extproc; + + glGetActiveUniformARB(programObj, index, maxLength, length, size, type, name); +} + +static void APIENTRY InitGetUniformfvARB (GLhandleARB programObj, GLint location, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetUniformfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetUniformfvARB = extproc; + + glGetUniformfvARB(programObj, location, params); +} + +static void APIENTRY InitGetUniformivARB (GLhandleARB programObj, GLint location, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetUniformivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetUniformivARB = extproc; + + glGetUniformivARB(programObj, location, params); +} + +static void APIENTRY InitGetShaderSourceARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetShaderSourceARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetShaderSourceARB = extproc; + + glGetShaderSourceARB(obj, maxLength, length, source); +} + +static void APIENTRY InitBindAttribLocationARB (GLhandleARB programObj, GLuint index, const GLcharARB *name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindAttribLocationARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindAttribLocationARB = extproc; + + glBindAttribLocationARB(programObj, index, name); +} + +static void APIENTRY InitGetActiveAttribARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetActiveAttribARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetActiveAttribARB = extproc; + + glGetActiveAttribARB(programObj, index, maxLength, length, size, type, name); +} + +static GLint APIENTRY InitGetAttribLocationARB (GLhandleARB programObj, const GLcharARB *name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetAttribLocationARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGetAttribLocationARB = extproc; + + return glGetAttribLocationARB(programObj, name); +} + +static void APIENTRY InitBlendColorEXT (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendColorEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendColorEXT = extproc; + + glBlendColorEXT(red, green, blue, alpha); +} + +static void APIENTRY InitPolygonOffsetEXT (GLfloat factor, GLfloat bias) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPolygonOffsetEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPolygonOffsetEXT = extproc; + + glPolygonOffsetEXT(factor, bias); +} + +static void APIENTRY InitTexImage3DEXT (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexImage3DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexImage3DEXT = extproc; + + glTexImage3DEXT(target, level, internalformat, width, height, depth, border, format, type, pixels); +} + +static void APIENTRY InitTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexSubImage3DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexSubImage3DEXT = extproc; + + glTexSubImage3DEXT(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); +} + +static void APIENTRY InitGetTexFilterFuncSGIS (GLenum target, GLenum filter, GLfloat *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetTexFilterFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetTexFilterFuncSGIS = extproc; + + glGetTexFilterFuncSGIS(target, filter, weights); +} + +static void APIENTRY InitTexFilterFuncSGIS (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexFilterFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexFilterFuncSGIS = extproc; + + glTexFilterFuncSGIS(target, filter, n, weights); +} + +static void APIENTRY InitTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexSubImage1DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexSubImage1DEXT = extproc; + + glTexSubImage1DEXT(target, level, xoffset, width, format, type, pixels); +} + +static void APIENTRY InitTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexSubImage2DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexSubImage2DEXT = extproc; + + glTexSubImage2DEXT(target, level, xoffset, yoffset, width, height, format, type, pixels); +} + +static void APIENTRY InitCopyTexImage1DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyTexImage1DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyTexImage1DEXT = extproc; + + glCopyTexImage1DEXT(target, level, internalformat, x, y, width, border); +} + +static void APIENTRY InitCopyTexImage2DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyTexImage2DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyTexImage2DEXT = extproc; + + glCopyTexImage2DEXT(target, level, internalformat, x, y, width, height, border); +} + +static void APIENTRY InitCopyTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyTexSubImage1DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyTexSubImage1DEXT = extproc; + + glCopyTexSubImage1DEXT(target, level, xoffset, x, y, width); +} + +static void APIENTRY InitCopyTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyTexSubImage2DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyTexSubImage2DEXT = extproc; + + glCopyTexSubImage2DEXT(target, level, xoffset, yoffset, x, y, width, height); +} + +static void APIENTRY InitCopyTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyTexSubImage3DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyTexSubImage3DEXT = extproc; + + glCopyTexSubImage3DEXT(target, level, xoffset, yoffset, zoffset, x, y, width, height); +} + +static void APIENTRY InitGetHistogramEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHistogramEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetHistogramEXT = extproc; + + glGetHistogramEXT(target, reset, format, type, values); +} + +static void APIENTRY InitGetHistogramParameterfvEXT (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHistogramParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetHistogramParameterfvEXT = extproc; + + glGetHistogramParameterfvEXT(target, pname, params); +} + +static void APIENTRY InitGetHistogramParameterivEXT (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHistogramParameterivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetHistogramParameterivEXT = extproc; + + glGetHistogramParameterivEXT(target, pname, params); +} + +static void APIENTRY InitGetMinmaxEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMinmaxEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMinmaxEXT = extproc; + + glGetMinmaxEXT(target, reset, format, type, values); +} + +static void APIENTRY InitGetMinmaxParameterfvEXT (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMinmaxParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMinmaxParameterfvEXT = extproc; + + glGetMinmaxParameterfvEXT(target, pname, params); +} + +static void APIENTRY InitGetMinmaxParameterivEXT (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMinmaxParameterivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMinmaxParameterivEXT = extproc; + + glGetMinmaxParameterivEXT(target, pname, params); +} + +static void APIENTRY InitHistogramEXT (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glHistogramEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glHistogramEXT = extproc; + + glHistogramEXT(target, width, internalformat, sink); +} + +static void APIENTRY InitMinmaxEXT (GLenum target, GLenum internalformat, GLboolean sink) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMinmaxEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMinmaxEXT = extproc; + + glMinmaxEXT(target, internalformat, sink); +} + +static void APIENTRY InitResetHistogramEXT (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glResetHistogramEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glResetHistogramEXT = extproc; + + glResetHistogramEXT(target); +} + +static void APIENTRY InitResetMinmaxEXT (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glResetMinmaxEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glResetMinmaxEXT = extproc; + + glResetMinmaxEXT(target); +} + +static void APIENTRY InitConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionFilter1DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionFilter1DEXT = extproc; + + glConvolutionFilter1DEXT(target, internalformat, width, format, type, image); +} + +static void APIENTRY InitConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionFilter2DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionFilter2DEXT = extproc; + + glConvolutionFilter2DEXT(target, internalformat, width, height, format, type, image); +} + +static void APIENTRY InitConvolutionParameterfEXT (GLenum target, GLenum pname, GLfloat params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameterfEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameterfEXT = extproc; + + glConvolutionParameterfEXT(target, pname, params); +} + +static void APIENTRY InitConvolutionParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameterfvEXT = extproc; + + glConvolutionParameterfvEXT(target, pname, params); +} + +static void APIENTRY InitConvolutionParameteriEXT (GLenum target, GLenum pname, GLint params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameteriEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameteriEXT = extproc; + + glConvolutionParameteriEXT(target, pname, params); +} + +static void APIENTRY InitConvolutionParameterivEXT (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameterivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameterivEXT = extproc; + + glConvolutionParameterivEXT(target, pname, params); +} + +static void APIENTRY InitCopyConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyConvolutionFilter1DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyConvolutionFilter1DEXT = extproc; + + glCopyConvolutionFilter1DEXT(target, internalformat, x, y, width); +} + +static void APIENTRY InitCopyConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyConvolutionFilter2DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyConvolutionFilter2DEXT = extproc; + + glCopyConvolutionFilter2DEXT(target, internalformat, x, y, width, height); +} + +static void APIENTRY InitGetConvolutionFilterEXT (GLenum target, GLenum format, GLenum type, GLvoid *image) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetConvolutionFilterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetConvolutionFilterEXT = extproc; + + glGetConvolutionFilterEXT(target, format, type, image); +} + +static void APIENTRY InitGetConvolutionParameterfvEXT (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetConvolutionParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetConvolutionParameterfvEXT = extproc; + + glGetConvolutionParameterfvEXT(target, pname, params); +} + +static void APIENTRY InitGetConvolutionParameterivEXT (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetConvolutionParameterivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetConvolutionParameterivEXT = extproc; + + glGetConvolutionParameterivEXT(target, pname, params); +} + +static void APIENTRY InitGetSeparableFilterEXT (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetSeparableFilterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetSeparableFilterEXT = extproc; + + glGetSeparableFilterEXT(target, format, type, row, column, span); +} + +static void APIENTRY InitSeparableFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSeparableFilter2DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSeparableFilter2DEXT = extproc; + + glSeparableFilter2DEXT(target, internalformat, width, height, format, type, row, column); +} + +static void APIENTRY InitColorTableSGI (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTableSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTableSGI = extproc; + + glColorTableSGI(target, internalformat, width, format, type, table); +} + +static void APIENTRY InitColorTableParameterfvSGI (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTableParameterfvSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTableParameterfvSGI = extproc; + + glColorTableParameterfvSGI(target, pname, params); +} + +static void APIENTRY InitColorTableParameterivSGI (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTableParameterivSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTableParameterivSGI = extproc; + + glColorTableParameterivSGI(target, pname, params); +} + +static void APIENTRY InitCopyColorTableSGI (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyColorTableSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyColorTableSGI = extproc; + + glCopyColorTableSGI(target, internalformat, x, y, width); +} + +static void APIENTRY InitGetColorTableSGI (GLenum target, GLenum format, GLenum type, GLvoid *table) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableSGI = extproc; + + glGetColorTableSGI(target, format, type, table); +} + +static void APIENTRY InitGetColorTableParameterfvSGI (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableParameterfvSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableParameterfvSGI = extproc; + + glGetColorTableParameterfvSGI(target, pname, params); +} + +static void APIENTRY InitGetColorTableParameterivSGI (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableParameterivSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableParameterivSGI = extproc; + + glGetColorTableParameterivSGI(target, pname, params); +} + +static void APIENTRY InitPixelTexGenSGIX (GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTexGenSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTexGenSGIX = extproc; + + glPixelTexGenSGIX(mode); +} + +static void APIENTRY InitPixelTexGenParameteriSGIS (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTexGenParameteriSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTexGenParameteriSGIS = extproc; + + glPixelTexGenParameteriSGIS(pname, param); +} + +static void APIENTRY InitPixelTexGenParameterivSGIS (GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTexGenParameterivSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTexGenParameterivSGIS = extproc; + + glPixelTexGenParameterivSGIS(pname, params); +} + +static void APIENTRY InitPixelTexGenParameterfSGIS (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTexGenParameterfSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTexGenParameterfSGIS = extproc; + + glPixelTexGenParameterfSGIS(pname, param); +} + +static void APIENTRY InitPixelTexGenParameterfvSGIS (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTexGenParameterfvSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTexGenParameterfvSGIS = extproc; + + glPixelTexGenParameterfvSGIS(pname, params); +} + +static void APIENTRY InitGetPixelTexGenParameterivSGIS (GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetPixelTexGenParameterivSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetPixelTexGenParameterivSGIS = extproc; + + glGetPixelTexGenParameterivSGIS(pname, params); +} + +static void APIENTRY InitGetPixelTexGenParameterfvSGIS (GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetPixelTexGenParameterfvSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetPixelTexGenParameterfvSGIS = extproc; + + glGetPixelTexGenParameterfvSGIS(pname, params); +} + +static void APIENTRY InitTexImage4DSGIS (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexImage4DSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexImage4DSGIS = extproc; + + glTexImage4DSGIS(target, level, internalformat, width, height, depth, size4d, border, format, type, pixels); +} + +static void APIENTRY InitTexSubImage4DSGIS (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexSubImage4DSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexSubImage4DSGIS = extproc; + + glTexSubImage4DSGIS(target, level, xoffset, yoffset, zoffset, woffset, width, height, depth, size4d, format, type, pixels); +} + +static GLboolean APIENTRY InitAreTexturesResidentEXT (GLsizei n, const GLuint *textures, GLboolean *residences) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAreTexturesResidentEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glAreTexturesResidentEXT = extproc; + + return glAreTexturesResidentEXT(n, textures, residences); +} + +static void APIENTRY InitBindTextureEXT (GLenum target, GLuint texture) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindTextureEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindTextureEXT = extproc; + + glBindTextureEXT(target, texture); +} + +static void APIENTRY InitDeleteTexturesEXT (GLsizei n, const GLuint *textures) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteTexturesEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteTexturesEXT = extproc; + + glDeleteTexturesEXT(n, textures); +} + +static void APIENTRY InitGenTexturesEXT (GLsizei n, GLuint *textures) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenTexturesEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenTexturesEXT = extproc; + + glGenTexturesEXT(n, textures); +} + +static GLboolean APIENTRY InitIsTextureEXT (GLuint texture) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsTextureEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsTextureEXT = extproc; + + return glIsTextureEXT(texture); +} + +static void APIENTRY InitPrioritizeTexturesEXT (GLsizei n, const GLuint *textures, const GLclampf *priorities) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPrioritizeTexturesEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPrioritizeTexturesEXT = extproc; + + glPrioritizeTexturesEXT(n, textures, priorities); +} + +static void APIENTRY InitDetailTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDetailTexFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDetailTexFuncSGIS = extproc; + + glDetailTexFuncSGIS(target, n, points); +} + +static void APIENTRY InitGetDetailTexFuncSGIS (GLenum target, GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetDetailTexFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetDetailTexFuncSGIS = extproc; + + glGetDetailTexFuncSGIS(target, points); +} + +static void APIENTRY InitSharpenTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSharpenTexFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSharpenTexFuncSGIS = extproc; + + glSharpenTexFuncSGIS(target, n, points); +} + +static void APIENTRY InitGetSharpenTexFuncSGIS (GLenum target, GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetSharpenTexFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetSharpenTexFuncSGIS = extproc; + + glGetSharpenTexFuncSGIS(target, points); +} + +static void APIENTRY InitSampleMaskSGIS (GLclampf value, GLboolean invert) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSampleMaskSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSampleMaskSGIS = extproc; + + glSampleMaskSGIS(value, invert); +} + +static void APIENTRY InitSamplePatternSGIS (GLenum pattern) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSamplePatternSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSamplePatternSGIS = extproc; + + glSamplePatternSGIS(pattern); +} + +static void APIENTRY InitArrayElementEXT (GLint i) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glArrayElementEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glArrayElementEXT = extproc; + + glArrayElementEXT(i); +} + +static void APIENTRY InitColorPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorPointerEXT = extproc; + + glColorPointerEXT(size, type, stride, count, pointer); +} + +static void APIENTRY InitDrawArraysEXT (GLenum mode, GLint first, GLsizei count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawArraysEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawArraysEXT = extproc; + + glDrawArraysEXT(mode, first, count); +} + +static void APIENTRY InitEdgeFlagPointerEXT (GLsizei stride, GLsizei count, const GLboolean *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEdgeFlagPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEdgeFlagPointerEXT = extproc; + + glEdgeFlagPointerEXT(stride, count, pointer); +} + +static void APIENTRY InitGetPointervEXT (GLenum pname, GLvoid* *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetPointervEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetPointervEXT = extproc; + + glGetPointervEXT(pname, params); +} + +static void APIENTRY InitIndexPointerEXT (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIndexPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glIndexPointerEXT = extproc; + + glIndexPointerEXT(type, stride, count, pointer); +} + +static void APIENTRY InitNormalPointerEXT (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalPointerEXT = extproc; + + glNormalPointerEXT(type, stride, count, pointer); +} + +static void APIENTRY InitTexCoordPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoordPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoordPointerEXT = extproc; + + glTexCoordPointerEXT(size, type, stride, count, pointer); +} + +static void APIENTRY InitVertexPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexPointerEXT = extproc; + + glVertexPointerEXT(size, type, stride, count, pointer); +} + +static void APIENTRY InitBlendEquationEXT (GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendEquationEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendEquationEXT = extproc; + + glBlendEquationEXT(mode); +} + +static void APIENTRY InitSpriteParameterfSGIX (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSpriteParameterfSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSpriteParameterfSGIX = extproc; + + glSpriteParameterfSGIX(pname, param); +} + +static void APIENTRY InitSpriteParameterfvSGIX (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSpriteParameterfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSpriteParameterfvSGIX = extproc; + + glSpriteParameterfvSGIX(pname, params); +} + +static void APIENTRY InitSpriteParameteriSGIX (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSpriteParameteriSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSpriteParameteriSGIX = extproc; + + glSpriteParameteriSGIX(pname, param); +} + +static void APIENTRY InitSpriteParameterivSGIX (GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSpriteParameterivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSpriteParameterivSGIX = extproc; + + glSpriteParameterivSGIX(pname, params); +} + +static void APIENTRY InitPointParameterfEXT (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfEXT = extproc; + + glPointParameterfEXT(pname, param); +} + +static void APIENTRY InitPointParameterfvEXT (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfvEXT = extproc; + + glPointParameterfvEXT(pname, params); +} + +static void APIENTRY InitPointParameterfSGIS (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfSGIS = extproc; + + glPointParameterfSGIS(pname, param); +} + +static void APIENTRY InitPointParameterfvSGIS (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfvSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfvSGIS = extproc; + + glPointParameterfvSGIS(pname, params); +} + +static GLint APIENTRY InitGetInstrumentsSGIX (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetInstrumentsSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGetInstrumentsSGIX = extproc; + + return glGetInstrumentsSGIX(); +} + +static void APIENTRY InitInstrumentsBufferSGIX (GLsizei size, GLint *buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glInstrumentsBufferSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glInstrumentsBufferSGIX = extproc; + + glInstrumentsBufferSGIX(size, buffer); +} + +static GLint APIENTRY InitPollInstrumentsSGIX (GLint *marker_p) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPollInstrumentsSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glPollInstrumentsSGIX = extproc; + + return glPollInstrumentsSGIX(marker_p); +} + +static void APIENTRY InitReadInstrumentsSGIX (GLint marker) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReadInstrumentsSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReadInstrumentsSGIX = extproc; + + glReadInstrumentsSGIX(marker); +} + +static void APIENTRY InitStartInstrumentsSGIX (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glStartInstrumentsSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glStartInstrumentsSGIX = extproc; + + glStartInstrumentsSGIX(); +} + +static void APIENTRY InitStopInstrumentsSGIX (GLint marker) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glStopInstrumentsSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glStopInstrumentsSGIX = extproc; + + glStopInstrumentsSGIX(marker); +} + +static void APIENTRY InitFrameZoomSGIX (GLint factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFrameZoomSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFrameZoomSGIX = extproc; + + glFrameZoomSGIX(factor); +} + +static void APIENTRY InitTagSampleBufferSGIX (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTagSampleBufferSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTagSampleBufferSGIX = extproc; + + glTagSampleBufferSGIX(); +} + +static void APIENTRY InitDeformationMap3dSGIX (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeformationMap3dSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeformationMap3dSGIX = extproc; + + glDeformationMap3dSGIX(target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, w1, w2, wstride, worder, points); +} + +static void APIENTRY InitDeformationMap3fSGIX (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeformationMap3fSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeformationMap3fSGIX = extproc; + + glDeformationMap3fSGIX(target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, w1, w2, wstride, worder, points); +} + +static void APIENTRY InitDeformSGIX (GLbitfield mask) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeformSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeformSGIX = extproc; + + glDeformSGIX(mask); +} + +static void APIENTRY InitLoadIdentityDeformationMapSGIX (GLbitfield mask) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLoadIdentityDeformationMapSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLoadIdentityDeformationMapSGIX = extproc; + + glLoadIdentityDeformationMapSGIX(mask); +} + +static void APIENTRY InitReferencePlaneSGIX (const GLdouble *equation) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReferencePlaneSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReferencePlaneSGIX = extproc; + + glReferencePlaneSGIX(equation); +} + +static void APIENTRY InitFlushRasterSGIX (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFlushRasterSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFlushRasterSGIX = extproc; + + glFlushRasterSGIX(); +} + +static void APIENTRY InitFogFuncSGIS (GLsizei n, const GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogFuncSGIS = extproc; + + glFogFuncSGIS(n, points); +} + +static void APIENTRY InitGetFogFuncSGIS (GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFogFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFogFuncSGIS = extproc; + + glGetFogFuncSGIS(points); +} + +static void APIENTRY InitImageTransformParameteriHP (GLenum target, GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glImageTransformParameteriHP"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glImageTransformParameteriHP = extproc; + + glImageTransformParameteriHP(target, pname, param); +} + +static void APIENTRY InitImageTransformParameterfHP (GLenum target, GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glImageTransformParameterfHP"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glImageTransformParameterfHP = extproc; + + glImageTransformParameterfHP(target, pname, param); +} + +static void APIENTRY InitImageTransformParameterivHP (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glImageTransformParameterivHP"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glImageTransformParameterivHP = extproc; + + glImageTransformParameterivHP(target, pname, params); +} + +static void APIENTRY InitImageTransformParameterfvHP (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glImageTransformParameterfvHP"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glImageTransformParameterfvHP = extproc; + + glImageTransformParameterfvHP(target, pname, params); +} + +static void APIENTRY InitGetImageTransformParameterivHP (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetImageTransformParameterivHP"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetImageTransformParameterivHP = extproc; + + glGetImageTransformParameterivHP(target, pname, params); +} + +static void APIENTRY InitGetImageTransformParameterfvHP (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetImageTransformParameterfvHP"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetImageTransformParameterfvHP = extproc; + + glGetImageTransformParameterfvHP(target, pname, params); +} + +static void APIENTRY InitColorSubTableEXT (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorSubTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorSubTableEXT = extproc; + + glColorSubTableEXT(target, start, count, format, type, data); +} + +static void APIENTRY InitCopyColorSubTableEXT (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyColorSubTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyColorSubTableEXT = extproc; + + glCopyColorSubTableEXT(target, start, x, y, width); +} + +static void APIENTRY InitHintPGI (GLenum target, GLint mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glHintPGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glHintPGI = extproc; + + glHintPGI(target, mode); +} + +static void APIENTRY InitColorTableEXT (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTableEXT = extproc; + + glColorTableEXT(target, internalFormat, width, format, type, table); +} + +static void APIENTRY InitGetColorTableEXT (GLenum target, GLenum format, GLenum type, GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableEXT = extproc; + + glGetColorTableEXT(target, format, type, data); +} + +static void APIENTRY InitGetColorTableParameterivEXT (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableParameterivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableParameterivEXT = extproc; + + glGetColorTableParameterivEXT(target, pname, params); +} + +static void APIENTRY InitGetColorTableParameterfvEXT (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableParameterfvEXT = extproc; + + glGetColorTableParameterfvEXT(target, pname, params); +} + +static void APIENTRY InitGetListParameterfvSGIX (GLuint list, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetListParameterfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetListParameterfvSGIX = extproc; + + glGetListParameterfvSGIX(list, pname, params); +} + +static void APIENTRY InitGetListParameterivSGIX (GLuint list, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetListParameterivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetListParameterivSGIX = extproc; + + glGetListParameterivSGIX(list, pname, params); +} + +static void APIENTRY InitListParameterfSGIX (GLuint list, GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glListParameterfSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glListParameterfSGIX = extproc; + + glListParameterfSGIX(list, pname, param); +} + +static void APIENTRY InitListParameterfvSGIX (GLuint list, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glListParameterfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glListParameterfvSGIX = extproc; + + glListParameterfvSGIX(list, pname, params); +} + +static void APIENTRY InitListParameteriSGIX (GLuint list, GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glListParameteriSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glListParameteriSGIX = extproc; + + glListParameteriSGIX(list, pname, param); +} + +static void APIENTRY InitListParameterivSGIX (GLuint list, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glListParameterivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glListParameterivSGIX = extproc; + + glListParameterivSGIX(list, pname, params); +} + +static void APIENTRY InitIndexMaterialEXT (GLenum face, GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIndexMaterialEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glIndexMaterialEXT = extproc; + + glIndexMaterialEXT(face, mode); +} + +static void APIENTRY InitIndexFuncEXT (GLenum func, GLclampf ref) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIndexFuncEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glIndexFuncEXT = extproc; + + glIndexFuncEXT(func, ref); +} + +static void APIENTRY InitLockArraysEXT (GLint first, GLsizei count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLockArraysEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLockArraysEXT = extproc; + + glLockArraysEXT(first, count); +} + +static void APIENTRY InitUnlockArraysEXT (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUnlockArraysEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUnlockArraysEXT = extproc; + + glUnlockArraysEXT(); +} + +static void APIENTRY InitCullParameterdvEXT (GLenum pname, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCullParameterdvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCullParameterdvEXT = extproc; + + glCullParameterdvEXT(pname, params); +} + +static void APIENTRY InitCullParameterfvEXT (GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCullParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCullParameterfvEXT = extproc; + + glCullParameterfvEXT(pname, params); +} + +static void APIENTRY InitFragmentColorMaterialSGIX (GLenum face, GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentColorMaterialSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentColorMaterialSGIX = extproc; + + glFragmentColorMaterialSGIX(face, mode); +} + +static void APIENTRY InitFragmentLightfSGIX (GLenum light, GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightfSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightfSGIX = extproc; + + glFragmentLightfSGIX(light, pname, param); +} + +static void APIENTRY InitFragmentLightfvSGIX (GLenum light, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightfvSGIX = extproc; + + glFragmentLightfvSGIX(light, pname, params); +} + +static void APIENTRY InitFragmentLightiSGIX (GLenum light, GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightiSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightiSGIX = extproc; + + glFragmentLightiSGIX(light, pname, param); +} + +static void APIENTRY InitFragmentLightivSGIX (GLenum light, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightivSGIX = extproc; + + glFragmentLightivSGIX(light, pname, params); +} + +static void APIENTRY InitFragmentLightModelfSGIX (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightModelfSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightModelfSGIX = extproc; + + glFragmentLightModelfSGIX(pname, param); +} + +static void APIENTRY InitFragmentLightModelfvSGIX (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightModelfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightModelfvSGIX = extproc; + + glFragmentLightModelfvSGIX(pname, params); +} + +static void APIENTRY InitFragmentLightModeliSGIX (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightModeliSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightModeliSGIX = extproc; + + glFragmentLightModeliSGIX(pname, param); +} + +static void APIENTRY InitFragmentLightModelivSGIX (GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightModelivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightModelivSGIX = extproc; + + glFragmentLightModelivSGIX(pname, params); +} + +static void APIENTRY InitFragmentMaterialfSGIX (GLenum face, GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentMaterialfSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentMaterialfSGIX = extproc; + + glFragmentMaterialfSGIX(face, pname, param); +} + +static void APIENTRY InitFragmentMaterialfvSGIX (GLenum face, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentMaterialfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentMaterialfvSGIX = extproc; + + glFragmentMaterialfvSGIX(face, pname, params); +} + +static void APIENTRY InitFragmentMaterialiSGIX (GLenum face, GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentMaterialiSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentMaterialiSGIX = extproc; + + glFragmentMaterialiSGIX(face, pname, param); +} + +static void APIENTRY InitFragmentMaterialivSGIX (GLenum face, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentMaterialivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentMaterialivSGIX = extproc; + + glFragmentMaterialivSGIX(face, pname, params); +} + +static void APIENTRY InitGetFragmentLightfvSGIX (GLenum light, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFragmentLightfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFragmentLightfvSGIX = extproc; + + glGetFragmentLightfvSGIX(light, pname, params); +} + +static void APIENTRY InitGetFragmentLightivSGIX (GLenum light, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFragmentLightivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFragmentLightivSGIX = extproc; + + glGetFragmentLightivSGIX(light, pname, params); +} + +static void APIENTRY InitGetFragmentMaterialfvSGIX (GLenum face, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFragmentMaterialfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFragmentMaterialfvSGIX = extproc; + + glGetFragmentMaterialfvSGIX(face, pname, params); +} + +static void APIENTRY InitGetFragmentMaterialivSGIX (GLenum face, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFragmentMaterialivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFragmentMaterialivSGIX = extproc; + + glGetFragmentMaterialivSGIX(face, pname, params); +} + +static void APIENTRY InitLightEnviSGIX (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLightEnviSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLightEnviSGIX = extproc; + + glLightEnviSGIX(pname, param); +} + +static void APIENTRY InitDrawRangeElementsEXT (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawRangeElementsEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawRangeElementsEXT = extproc; + + glDrawRangeElementsEXT(mode, start, end, count, type, indices); +} + +static void APIENTRY InitApplyTextureEXT (GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glApplyTextureEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glApplyTextureEXT = extproc; + + glApplyTextureEXT(mode); +} + +static void APIENTRY InitTextureLightEXT (GLenum pname) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTextureLightEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTextureLightEXT = extproc; + + glTextureLightEXT(pname); +} + +static void APIENTRY InitTextureMaterialEXT (GLenum face, GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTextureMaterialEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTextureMaterialEXT = extproc; + + glTextureMaterialEXT(face, mode); +} + +static void APIENTRY InitAsyncMarkerSGIX (GLuint marker) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAsyncMarkerSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glAsyncMarkerSGIX = extproc; + + glAsyncMarkerSGIX(marker); +} + +static GLint APIENTRY InitFinishAsyncSGIX (GLuint *markerp) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFinishAsyncSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glFinishAsyncSGIX = extproc; + + return glFinishAsyncSGIX(markerp); +} + +static GLint APIENTRY InitPollAsyncSGIX (GLuint *markerp) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPollAsyncSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glPollAsyncSGIX = extproc; + + return glPollAsyncSGIX(markerp); +} + +static GLuint APIENTRY InitGenAsyncMarkersSGIX (GLsizei range) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenAsyncMarkersSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGenAsyncMarkersSGIX = extproc; + + return glGenAsyncMarkersSGIX(range); +} + +static void APIENTRY InitDeleteAsyncMarkersSGIX (GLuint marker, GLsizei range) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteAsyncMarkersSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteAsyncMarkersSGIX = extproc; + + glDeleteAsyncMarkersSGIX(marker, range); +} + +static GLboolean APIENTRY InitIsAsyncMarkerSGIX (GLuint marker) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsAsyncMarkerSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsAsyncMarkerSGIX = extproc; + + return glIsAsyncMarkerSGIX(marker); +} + +static void APIENTRY InitVertexPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexPointervINTEL"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexPointervINTEL = extproc; + + glVertexPointervINTEL(size, type, pointer); +} + +static void APIENTRY InitNormalPointervINTEL (GLenum type, const GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalPointervINTEL"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalPointervINTEL = extproc; + + glNormalPointervINTEL(type, pointer); +} + +static void APIENTRY InitColorPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorPointervINTEL"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorPointervINTEL = extproc; + + glColorPointervINTEL(size, type, pointer); +} + +static void APIENTRY InitTexCoordPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoordPointervINTEL"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoordPointervINTEL = extproc; + + glTexCoordPointervINTEL(size, type, pointer); +} + +static void APIENTRY InitPixelTransformParameteriEXT (GLenum target, GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTransformParameteriEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTransformParameteriEXT = extproc; + + glPixelTransformParameteriEXT(target, pname, param); +} + +static void APIENTRY InitPixelTransformParameterfEXT (GLenum target, GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTransformParameterfEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTransformParameterfEXT = extproc; + + glPixelTransformParameterfEXT(target, pname, param); +} + +static void APIENTRY InitPixelTransformParameterivEXT (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTransformParameterivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTransformParameterivEXT = extproc; + + glPixelTransformParameterivEXT(target, pname, params); +} + +static void APIENTRY InitPixelTransformParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTransformParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTransformParameterfvEXT = extproc; + + glPixelTransformParameterfvEXT(target, pname, params); +} + +static void APIENTRY InitSecondaryColor3bEXT (GLbyte red, GLbyte green, GLbyte blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3bEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3bEXT = extproc; + + glSecondaryColor3bEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3bvEXT (const GLbyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3bvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3bvEXT = extproc; + + glSecondaryColor3bvEXT(v); +} + +static void APIENTRY InitSecondaryColor3dEXT (GLdouble red, GLdouble green, GLdouble blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3dEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3dEXT = extproc; + + glSecondaryColor3dEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3dvEXT (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3dvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3dvEXT = extproc; + + glSecondaryColor3dvEXT(v); +} + +static void APIENTRY InitSecondaryColor3fEXT (GLfloat red, GLfloat green, GLfloat blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3fEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3fEXT = extproc; + + glSecondaryColor3fEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3fvEXT (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3fvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3fvEXT = extproc; + + glSecondaryColor3fvEXT(v); +} + +static void APIENTRY InitSecondaryColor3iEXT (GLint red, GLint green, GLint blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3iEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3iEXT = extproc; + + glSecondaryColor3iEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3ivEXT (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3ivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3ivEXT = extproc; + + glSecondaryColor3ivEXT(v); +} + +static void APIENTRY InitSecondaryColor3sEXT (GLshort red, GLshort green, GLshort blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3sEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3sEXT = extproc; + + glSecondaryColor3sEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3svEXT (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3svEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3svEXT = extproc; + + glSecondaryColor3svEXT(v); +} + +static void APIENTRY InitSecondaryColor3ubEXT (GLubyte red, GLubyte green, GLubyte blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3ubEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3ubEXT = extproc; + + glSecondaryColor3ubEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3ubvEXT (const GLubyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3ubvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3ubvEXT = extproc; + + glSecondaryColor3ubvEXT(v); +} + +static void APIENTRY InitSecondaryColor3uiEXT (GLuint red, GLuint green, GLuint blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3uiEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3uiEXT = extproc; + + glSecondaryColor3uiEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3uivEXT (const GLuint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3uivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3uivEXT = extproc; + + glSecondaryColor3uivEXT(v); +} + +static void APIENTRY InitSecondaryColor3usEXT (GLushort red, GLushort green, GLushort blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3usEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3usEXT = extproc; + + glSecondaryColor3usEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3usvEXT (const GLushort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3usvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3usvEXT = extproc; + + glSecondaryColor3usvEXT(v); +} + +static void APIENTRY InitSecondaryColorPointerEXT (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColorPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColorPointerEXT = extproc; + + glSecondaryColorPointerEXT(size, type, stride, pointer); +} + +static void APIENTRY InitTextureNormalEXT (GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTextureNormalEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTextureNormalEXT = extproc; + + glTextureNormalEXT(mode); +} + +static void APIENTRY InitMultiDrawArraysEXT (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiDrawArraysEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiDrawArraysEXT = extproc; + + glMultiDrawArraysEXT(mode, first, count, primcount); +} + +static void APIENTRY InitMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiDrawElementsEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiDrawElementsEXT = extproc; + + glMultiDrawElementsEXT(mode, count, type, indices, primcount); +} + +static void APIENTRY InitFogCoordfEXT (GLfloat coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordfEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordfEXT = extproc; + + glFogCoordfEXT(coord); +} + +static void APIENTRY InitFogCoordfvEXT (const GLfloat *coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordfvEXT = extproc; + + glFogCoordfvEXT(coord); +} + +static void APIENTRY InitFogCoorddEXT (GLdouble coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoorddEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoorddEXT = extproc; + + glFogCoorddEXT(coord); +} + +static void APIENTRY InitFogCoorddvEXT (const GLdouble *coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoorddvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoorddvEXT = extproc; + + glFogCoorddvEXT(coord); +} + +static void APIENTRY InitFogCoordPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordPointerEXT = extproc; + + glFogCoordPointerEXT(type, stride, pointer); +} + +static void APIENTRY InitTangent3bEXT (GLbyte tx, GLbyte ty, GLbyte tz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3bEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3bEXT = extproc; + + glTangent3bEXT(tx, ty, tz); +} + +static void APIENTRY InitTangent3bvEXT (const GLbyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3bvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3bvEXT = extproc; + + glTangent3bvEXT(v); +} + +static void APIENTRY InitTangent3dEXT (GLdouble tx, GLdouble ty, GLdouble tz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3dEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3dEXT = extproc; + + glTangent3dEXT(tx, ty, tz); +} + +static void APIENTRY InitTangent3dvEXT (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3dvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3dvEXT = extproc; + + glTangent3dvEXT(v); +} + +static void APIENTRY InitTangent3fEXT (GLfloat tx, GLfloat ty, GLfloat tz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3fEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3fEXT = extproc; + + glTangent3fEXT(tx, ty, tz); +} + +static void APIENTRY InitTangent3fvEXT (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3fvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3fvEXT = extproc; + + glTangent3fvEXT(v); +} + +static void APIENTRY InitTangent3iEXT (GLint tx, GLint ty, GLint tz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3iEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3iEXT = extproc; + + glTangent3iEXT(tx, ty, tz); +} + +static void APIENTRY InitTangent3ivEXT (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3ivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3ivEXT = extproc; + + glTangent3ivEXT(v); +} + +static void APIENTRY InitTangent3sEXT (GLshort tx, GLshort ty, GLshort tz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3sEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3sEXT = extproc; + + glTangent3sEXT(tx, ty, tz); +} + +static void APIENTRY InitTangent3svEXT (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3svEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3svEXT = extproc; + + glTangent3svEXT(v); +} + +static void APIENTRY InitBinormal3bEXT (GLbyte bx, GLbyte by, GLbyte bz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3bEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3bEXT = extproc; + + glBinormal3bEXT(bx, by, bz); +} + +static void APIENTRY InitBinormal3bvEXT (const GLbyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3bvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3bvEXT = extproc; + + glBinormal3bvEXT(v); +} + +static void APIENTRY InitBinormal3dEXT (GLdouble bx, GLdouble by, GLdouble bz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3dEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3dEXT = extproc; + + glBinormal3dEXT(bx, by, bz); +} + +static void APIENTRY InitBinormal3dvEXT (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3dvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3dvEXT = extproc; + + glBinormal3dvEXT(v); +} + +static void APIENTRY InitBinormal3fEXT (GLfloat bx, GLfloat by, GLfloat bz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3fEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3fEXT = extproc; + + glBinormal3fEXT(bx, by, bz); +} + +static void APIENTRY InitBinormal3fvEXT (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3fvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3fvEXT = extproc; + + glBinormal3fvEXT(v); +} + +static void APIENTRY InitBinormal3iEXT (GLint bx, GLint by, GLint bz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3iEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3iEXT = extproc; + + glBinormal3iEXT(bx, by, bz); +} + +static void APIENTRY InitBinormal3ivEXT (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3ivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3ivEXT = extproc; + + glBinormal3ivEXT(v); +} + +static void APIENTRY InitBinormal3sEXT (GLshort bx, GLshort by, GLshort bz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3sEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3sEXT = extproc; + + glBinormal3sEXT(bx, by, bz); +} + +static void APIENTRY InitBinormal3svEXT (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3svEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3svEXT = extproc; + + glBinormal3svEXT(v); +} + +static void APIENTRY InitTangentPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangentPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangentPointerEXT = extproc; + + glTangentPointerEXT(type, stride, pointer); +} + +static void APIENTRY InitBinormalPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormalPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormalPointerEXT = extproc; + + glBinormalPointerEXT(type, stride, pointer); +} + +static void APIENTRY InitFinishTextureSUNX (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFinishTextureSUNX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFinishTextureSUNX = extproc; + + glFinishTextureSUNX(); +} + +static void APIENTRY InitGlobalAlphaFactorbSUN (GLbyte factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorbSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactorbSUN = extproc; + + glGlobalAlphaFactorbSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactorsSUN (GLshort factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorsSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactorsSUN = extproc; + + glGlobalAlphaFactorsSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactoriSUN (GLint factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactoriSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactoriSUN = extproc; + + glGlobalAlphaFactoriSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactorfSUN (GLfloat factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorfSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactorfSUN = extproc; + + glGlobalAlphaFactorfSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactordSUN (GLdouble factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactordSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactordSUN = extproc; + + glGlobalAlphaFactordSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactorubSUN (GLubyte factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorubSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactorubSUN = extproc; + + glGlobalAlphaFactorubSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactorusSUN (GLushort factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorusSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactorusSUN = extproc; + + glGlobalAlphaFactorusSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactoruiSUN (GLuint factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactoruiSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactoruiSUN = extproc; + + glGlobalAlphaFactoruiSUN(factor); +} + +static void APIENTRY InitReplacementCodeuiSUN (GLuint code) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiSUN = extproc; + + glReplacementCodeuiSUN(code); +} + +static void APIENTRY InitReplacementCodeusSUN (GLushort code) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeusSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeusSUN = extproc; + + glReplacementCodeusSUN(code); +} + +static void APIENTRY InitReplacementCodeubSUN (GLubyte code) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeubSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeubSUN = extproc; + + glReplacementCodeubSUN(code); +} + +static void APIENTRY InitReplacementCodeuivSUN (const GLuint *code) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuivSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuivSUN = extproc; + + glReplacementCodeuivSUN(code); +} + +static void APIENTRY InitReplacementCodeusvSUN (const GLushort *code) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeusvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeusvSUN = extproc; + + glReplacementCodeusvSUN(code); +} + +static void APIENTRY InitReplacementCodeubvSUN (const GLubyte *code) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeubvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeubvSUN = extproc; + + glReplacementCodeubvSUN(code); +} + +static void APIENTRY InitReplacementCodePointerSUN (GLenum type, GLsizei stride, const GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodePointerSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodePointerSUN = extproc; + + glReplacementCodePointerSUN(type, stride, pointer); +} + +static void APIENTRY InitColor4ubVertex2fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4ubVertex2fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4ubVertex2fSUN = extproc; + + glColor4ubVertex2fSUN(r, g, b, a, x, y); +} + +static void APIENTRY InitColor4ubVertex2fvSUN (const GLubyte *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4ubVertex2fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4ubVertex2fvSUN = extproc; + + glColor4ubVertex2fvSUN(c, v); +} + +static void APIENTRY InitColor4ubVertex3fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4ubVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4ubVertex3fSUN = extproc; + + glColor4ubVertex3fSUN(r, g, b, a, x, y, z); +} + +static void APIENTRY InitColor4ubVertex3fvSUN (const GLubyte *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4ubVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4ubVertex3fvSUN = extproc; + + glColor4ubVertex3fvSUN(c, v); +} + +static void APIENTRY InitColor3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor3fVertex3fSUN = extproc; + + glColor3fVertex3fSUN(r, g, b, x, y, z); +} + +static void APIENTRY InitColor3fVertex3fvSUN (const GLfloat *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor3fVertex3fvSUN = extproc; + + glColor3fVertex3fvSUN(c, v); +} + +static void APIENTRY InitNormal3fVertex3fSUN (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormal3fVertex3fSUN = extproc; + + glNormal3fVertex3fSUN(nx, ny, nz, x, y, z); +} + +static void APIENTRY InitNormal3fVertex3fvSUN (const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormal3fVertex3fvSUN = extproc; + + glNormal3fVertex3fvSUN(n, v); +} + +static void APIENTRY InitColor4fNormal3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4fNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4fNormal3fVertex3fSUN = extproc; + + glColor4fNormal3fVertex3fSUN(r, g, b, a, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitColor4fNormal3fVertex3fvSUN (const GLfloat *c, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4fNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4fNormal3fVertex3fvSUN = extproc; + + glColor4fNormal3fVertex3fvSUN(c, n, v); +} + +static void APIENTRY InitTexCoord2fVertex3fSUN (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fVertex3fSUN = extproc; + + glTexCoord2fVertex3fSUN(s, t, x, y, z); +} + +static void APIENTRY InitTexCoord2fVertex3fvSUN (const GLfloat *tc, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fVertex3fvSUN = extproc; + + glTexCoord2fVertex3fvSUN(tc, v); +} + +static void APIENTRY InitTexCoord4fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord4fVertex4fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord4fVertex4fSUN = extproc; + + glTexCoord4fVertex4fSUN(s, t, p, q, x, y, z, w); +} + +static void APIENTRY InitTexCoord4fVertex4fvSUN (const GLfloat *tc, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord4fVertex4fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord4fVertex4fvSUN = extproc; + + glTexCoord4fVertex4fvSUN(tc, v); +} + +static void APIENTRY InitTexCoord2fColor4ubVertex3fSUN (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fColor4ubVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fColor4ubVertex3fSUN = extproc; + + glTexCoord2fColor4ubVertex3fSUN(s, t, r, g, b, a, x, y, z); +} + +static void APIENTRY InitTexCoord2fColor4ubVertex3fvSUN (const GLfloat *tc, const GLubyte *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fColor4ubVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fColor4ubVertex3fvSUN = extproc; + + glTexCoord2fColor4ubVertex3fvSUN(tc, c, v); +} + +static void APIENTRY InitTexCoord2fColor3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fColor3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fColor3fVertex3fSUN = extproc; + + glTexCoord2fColor3fVertex3fSUN(s, t, r, g, b, x, y, z); +} + +static void APIENTRY InitTexCoord2fColor3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fColor3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fColor3fVertex3fvSUN = extproc; + + glTexCoord2fColor3fVertex3fvSUN(tc, c, v); +} + +static void APIENTRY InitTexCoord2fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fNormal3fVertex3fSUN = extproc; + + glTexCoord2fNormal3fVertex3fSUN(s, t, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitTexCoord2fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fNormal3fVertex3fvSUN = extproc; + + glTexCoord2fNormal3fVertex3fvSUN(tc, n, v); +} + +static void APIENTRY InitTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fColor4fNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fColor4fNormal3fVertex3fSUN = extproc; + + glTexCoord2fColor4fNormal3fVertex3fSUN(s, t, r, g, b, a, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fColor4fNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fColor4fNormal3fVertex3fvSUN = extproc; + + glTexCoord2fColor4fNormal3fVertex3fvSUN(tc, c, n, v); +} + +static void APIENTRY InitTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord4fColor4fNormal3fVertex4fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord4fColor4fNormal3fVertex4fSUN = extproc; + + glTexCoord4fColor4fNormal3fVertex4fSUN(s, t, p, q, r, g, b, a, nx, ny, nz, x, y, z, w); +} + +static void APIENTRY InitTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord4fColor4fNormal3fVertex4fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord4fColor4fNormal3fVertex4fvSUN = extproc; + + glTexCoord4fColor4fNormal3fVertex4fvSUN(tc, c, n, v); +} + +static void APIENTRY InitReplacementCodeuiVertex3fSUN (GLuint rc, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiVertex3fSUN = extproc; + + glReplacementCodeuiVertex3fSUN(rc, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiVertex3fvSUN (const GLuint *rc, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiVertex3fvSUN = extproc; + + glReplacementCodeuiVertex3fvSUN(rc, v); +} + +static void APIENTRY InitReplacementCodeuiColor4ubVertex3fSUN (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor4ubVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiColor4ubVertex3fSUN = extproc; + + glReplacementCodeuiColor4ubVertex3fSUN(rc, r, g, b, a, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *rc, const GLubyte *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor4ubVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiColor4ubVertex3fvSUN = extproc; + + glReplacementCodeuiColor4ubVertex3fvSUN(rc, c, v); +} + +static void APIENTRY InitReplacementCodeuiColor3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiColor3fVertex3fSUN = extproc; + + glReplacementCodeuiColor3fVertex3fSUN(rc, r, g, b, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiColor3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiColor3fVertex3fvSUN = extproc; + + glReplacementCodeuiColor3fVertex3fvSUN(rc, c, v); +} + +static void APIENTRY InitReplacementCodeuiNormal3fVertex3fSUN (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiNormal3fVertex3fSUN = extproc; + + glReplacementCodeuiNormal3fVertex3fSUN(rc, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiNormal3fVertex3fvSUN = extproc; + + glReplacementCodeuiNormal3fVertex3fvSUN(rc, n, v); +} + +static void APIENTRY InitReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor4fNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiColor4fNormal3fVertex3fSUN = extproc; + + glReplacementCodeuiColor4fNormal3fVertex3fSUN(rc, r, g, b, a, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor4fNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiColor4fNormal3fVertex3fvSUN = extproc; + + glReplacementCodeuiColor4fNormal3fVertex3fvSUN(rc, c, n, v); +} + +static void APIENTRY InitReplacementCodeuiTexCoord2fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiTexCoord2fVertex3fSUN = extproc; + + glReplacementCodeuiTexCoord2fVertex3fSUN(rc, s, t, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiTexCoord2fVertex3fvSUN = extproc; + + glReplacementCodeuiTexCoord2fVertex3fvSUN(rc, tc, v); +} + +static void APIENTRY InitReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN = extproc; + + glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN(rc, s, t, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN = extproc; + + glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN(rc, tc, n, v); +} + +static void APIENTRY InitReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN = extproc; + + glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN(rc, s, t, r, g, b, a, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN = extproc; + + glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN(rc, tc, c, n, v); +} + +static void APIENTRY InitBlendFuncSeparateEXT (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendFuncSeparateEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendFuncSeparateEXT = extproc; + + glBlendFuncSeparateEXT(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); +} + +static void APIENTRY InitBlendFuncSeparateINGR (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendFuncSeparateINGR"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendFuncSeparateINGR = extproc; + + glBlendFuncSeparateINGR(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); +} + +static void APIENTRY InitVertexWeightfEXT (GLfloat weight) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexWeightfEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexWeightfEXT = extproc; + + glVertexWeightfEXT(weight); +} + +static void APIENTRY InitVertexWeightfvEXT (const GLfloat *weight) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexWeightfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexWeightfvEXT = extproc; + + glVertexWeightfvEXT(weight); +} + +static void APIENTRY InitVertexWeightPointerEXT (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexWeightPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexWeightPointerEXT = extproc; + + glVertexWeightPointerEXT(size, type, stride, pointer); +} + +static void APIENTRY InitFlushVertexArrayRangeNV (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFlushVertexArrayRangeNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFlushVertexArrayRangeNV = extproc; + + glFlushVertexArrayRangeNV(); +} + +static void APIENTRY InitVertexArrayRangeNV (GLsizei length, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexArrayRangeNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexArrayRangeNV = extproc; + + glVertexArrayRangeNV(length, pointer); +} + +static void APIENTRY InitCombinerParameterfvNV (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerParameterfvNV = extproc; + + glCombinerParameterfvNV(pname, params); +} + +static void APIENTRY InitCombinerParameterfNV (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerParameterfNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerParameterfNV = extproc; + + glCombinerParameterfNV(pname, param); +} + +static void APIENTRY InitCombinerParameterivNV (GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerParameterivNV = extproc; + + glCombinerParameterivNV(pname, params); +} + +static void APIENTRY InitCombinerParameteriNV (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerParameteriNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerParameteriNV = extproc; + + glCombinerParameteriNV(pname, param); +} + +static void APIENTRY InitCombinerInputNV (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerInputNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerInputNV = extproc; + + glCombinerInputNV(stage, portion, variable, input, mapping, componentUsage); +} + +static void APIENTRY InitCombinerOutputNV (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerOutputNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerOutputNV = extproc; + + glCombinerOutputNV(stage, portion, abOutput, cdOutput, sumOutput, scale, bias, abDotProduct, cdDotProduct, muxSum); +} + +static void APIENTRY InitFinalCombinerInputNV (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFinalCombinerInputNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFinalCombinerInputNV = extproc; + + glFinalCombinerInputNV(variable, input, mapping, componentUsage); +} + +static void APIENTRY InitGetCombinerInputParameterfvNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCombinerInputParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCombinerInputParameterfvNV = extproc; + + glGetCombinerInputParameterfvNV(stage, portion, variable, pname, params); +} + +static void APIENTRY InitGetCombinerInputParameterivNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCombinerInputParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCombinerInputParameterivNV = extproc; + + glGetCombinerInputParameterivNV(stage, portion, variable, pname, params); +} + +static void APIENTRY InitGetCombinerOutputParameterfvNV (GLenum stage, GLenum portion, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCombinerOutputParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCombinerOutputParameterfvNV = extproc; + + glGetCombinerOutputParameterfvNV(stage, portion, pname, params); +} + +static void APIENTRY InitGetCombinerOutputParameterivNV (GLenum stage, GLenum portion, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCombinerOutputParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCombinerOutputParameterivNV = extproc; + + glGetCombinerOutputParameterivNV(stage, portion, pname, params); +} + +static void APIENTRY InitGetFinalCombinerInputParameterfvNV (GLenum variable, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFinalCombinerInputParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFinalCombinerInputParameterfvNV = extproc; + + glGetFinalCombinerInputParameterfvNV(variable, pname, params); +} + +static void APIENTRY InitGetFinalCombinerInputParameterivNV (GLenum variable, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFinalCombinerInputParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFinalCombinerInputParameterivNV = extproc; + + glGetFinalCombinerInputParameterivNV(variable, pname, params); +} + +static void APIENTRY InitResizeBuffersMESA (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glResizeBuffersMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glResizeBuffersMESA = extproc; + + glResizeBuffersMESA(); +} + +static void APIENTRY InitWindowPos2dMESA (GLdouble x, GLdouble y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2dMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2dMESA = extproc; + + glWindowPos2dMESA(x, y); +} + +static void APIENTRY InitWindowPos2dvMESA (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2dvMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2dvMESA = extproc; + + glWindowPos2dvMESA(v); +} + +static void APIENTRY InitWindowPos2fMESA (GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2fMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2fMESA = extproc; + + glWindowPos2fMESA(x, y); +} + +static void APIENTRY InitWindowPos2fvMESA (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2fvMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2fvMESA = extproc; + + glWindowPos2fvMESA(v); +} + +static void APIENTRY InitWindowPos2iMESA (GLint x, GLint y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2iMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2iMESA = extproc; + + glWindowPos2iMESA(x, y); +} + +static void APIENTRY InitWindowPos2ivMESA (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2ivMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2ivMESA = extproc; + + glWindowPos2ivMESA(v); +} + +static void APIENTRY InitWindowPos2sMESA (GLshort x, GLshort y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2sMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2sMESA = extproc; + + glWindowPos2sMESA(x, y); +} + +static void APIENTRY InitWindowPos2svMESA (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2svMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2svMESA = extproc; + + glWindowPos2svMESA(v); +} + +static void APIENTRY InitWindowPos3dMESA (GLdouble x, GLdouble y, GLdouble z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3dMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3dMESA = extproc; + + glWindowPos3dMESA(x, y, z); +} + +static void APIENTRY InitWindowPos3dvMESA (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3dvMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3dvMESA = extproc; + + glWindowPos3dvMESA(v); +} + +static void APIENTRY InitWindowPos3fMESA (GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3fMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3fMESA = extproc; + + glWindowPos3fMESA(x, y, z); +} + +static void APIENTRY InitWindowPos3fvMESA (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3fvMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3fvMESA = extproc; + + glWindowPos3fvMESA(v); +} + +static void APIENTRY InitWindowPos3iMESA (GLint x, GLint y, GLint z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3iMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3iMESA = extproc; + + glWindowPos3iMESA(x, y, z); +} + +static void APIENTRY InitWindowPos3ivMESA (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3ivMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3ivMESA = extproc; + + glWindowPos3ivMESA(v); +} + +static void APIENTRY InitWindowPos3sMESA (GLshort x, GLshort y, GLshort z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3sMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3sMESA = extproc; + + glWindowPos3sMESA(x, y, z); +} + +static void APIENTRY InitWindowPos3svMESA (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3svMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3svMESA = extproc; + + glWindowPos3svMESA(v); +} + +static void APIENTRY InitWindowPos4dMESA (GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4dMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4dMESA = extproc; + + glWindowPos4dMESA(x, y, z, w); +} + +static void APIENTRY InitWindowPos4dvMESA (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4dvMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4dvMESA = extproc; + + glWindowPos4dvMESA(v); +} + +static void APIENTRY InitWindowPos4fMESA (GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4fMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4fMESA = extproc; + + glWindowPos4fMESA(x, y, z, w); +} + +static void APIENTRY InitWindowPos4fvMESA (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4fvMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4fvMESA = extproc; + + glWindowPos4fvMESA(v); +} + +static void APIENTRY InitWindowPos4iMESA (GLint x, GLint y, GLint z, GLint w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4iMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4iMESA = extproc; + + glWindowPos4iMESA(x, y, z, w); +} + +static void APIENTRY InitWindowPos4ivMESA (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4ivMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4ivMESA = extproc; + + glWindowPos4ivMESA(v); +} + +static void APIENTRY InitWindowPos4sMESA (GLshort x, GLshort y, GLshort z, GLshort w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4sMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4sMESA = extproc; + + glWindowPos4sMESA(x, y, z, w); +} + +static void APIENTRY InitWindowPos4svMESA (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4svMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4svMESA = extproc; + + glWindowPos4svMESA(v); +} + +static void APIENTRY InitMultiModeDrawArraysIBM (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiModeDrawArraysIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiModeDrawArraysIBM = extproc; + + glMultiModeDrawArraysIBM(mode, first, count, primcount, modestride); +} + +static void APIENTRY InitMultiModeDrawElementsIBM (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiModeDrawElementsIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiModeDrawElementsIBM = extproc; + + glMultiModeDrawElementsIBM(mode, count, type, indices, primcount, modestride); +} + +static void APIENTRY InitColorPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorPointerListIBM = extproc; + + glColorPointerListIBM(size, type, stride, pointer, ptrstride); +} + +static void APIENTRY InitSecondaryColorPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColorPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColorPointerListIBM = extproc; + + glSecondaryColorPointerListIBM(size, type, stride, pointer, ptrstride); +} + +static void APIENTRY InitEdgeFlagPointerListIBM (GLint stride, const GLboolean* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEdgeFlagPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEdgeFlagPointerListIBM = extproc; + + glEdgeFlagPointerListIBM(stride, pointer, ptrstride); +} + +static void APIENTRY InitFogCoordPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordPointerListIBM = extproc; + + glFogCoordPointerListIBM(type, stride, pointer, ptrstride); +} + +static void APIENTRY InitIndexPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIndexPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glIndexPointerListIBM = extproc; + + glIndexPointerListIBM(type, stride, pointer, ptrstride); +} + +static void APIENTRY InitNormalPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalPointerListIBM = extproc; + + glNormalPointerListIBM(type, stride, pointer, ptrstride); +} + +static void APIENTRY InitTexCoordPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoordPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoordPointerListIBM = extproc; + + glTexCoordPointerListIBM(size, type, stride, pointer, ptrstride); +} + +static void APIENTRY InitVertexPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexPointerListIBM = extproc; + + glVertexPointerListIBM(size, type, stride, pointer, ptrstride); +} + +static void APIENTRY InitTbufferMask3DFX (GLuint mask) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTbufferMask3DFX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTbufferMask3DFX = extproc; + + glTbufferMask3DFX(mask); +} + +static void APIENTRY InitSampleMaskEXT (GLclampf value, GLboolean invert) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSampleMaskEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSampleMaskEXT = extproc; + + glSampleMaskEXT(value, invert); +} + +static void APIENTRY InitSamplePatternEXT (GLenum pattern) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSamplePatternEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSamplePatternEXT = extproc; + + glSamplePatternEXT(pattern); +} + +static void APIENTRY InitTextureColorMaskSGIS (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTextureColorMaskSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTextureColorMaskSGIS = extproc; + + glTextureColorMaskSGIS(red, green, blue, alpha); +} + +static void APIENTRY InitIglooInterfaceSGIX (GLenum pname, const GLvoid *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIglooInterfaceSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glIglooInterfaceSGIX = extproc; + + glIglooInterfaceSGIX(pname, params); +} + +static void APIENTRY InitDeleteFencesNV (GLsizei n, const GLuint *fences) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteFencesNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteFencesNV = extproc; + + glDeleteFencesNV(n, fences); +} + +static void APIENTRY InitGenFencesNV (GLsizei n, GLuint *fences) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenFencesNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenFencesNV = extproc; + + glGenFencesNV(n, fences); +} + +static GLboolean APIENTRY InitIsFenceNV (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsFenceNV"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsFenceNV = extproc; + + return glIsFenceNV(fence); +} + +static GLboolean APIENTRY InitTestFenceNV (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTestFenceNV"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glTestFenceNV = extproc; + + return glTestFenceNV(fence); +} + +static void APIENTRY InitGetFenceivNV (GLuint fence, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFenceivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFenceivNV = extproc; + + glGetFenceivNV(fence, pname, params); +} + +static void APIENTRY InitFinishFenceNV (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFinishFenceNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFinishFenceNV = extproc; + + glFinishFenceNV(fence); +} + +static void APIENTRY InitSetFenceNV (GLuint fence, GLenum condition) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSetFenceNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSetFenceNV = extproc; + + glSetFenceNV(fence, condition); +} + +static void APIENTRY InitMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMapControlPointsNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMapControlPointsNV = extproc; + + glMapControlPointsNV(target, index, type, ustride, vstride, uorder, vorder, packed, points); +} + +static void APIENTRY InitMapParameterivNV (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMapParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMapParameterivNV = extproc; + + glMapParameterivNV(target, pname, params); +} + +static void APIENTRY InitMapParameterfvNV (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMapParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMapParameterfvNV = extproc; + + glMapParameterfvNV(target, pname, params); +} + +static void APIENTRY InitGetMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMapControlPointsNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMapControlPointsNV = extproc; + + glGetMapControlPointsNV(target, index, type, ustride, vstride, packed, points); +} + +static void APIENTRY InitGetMapParameterivNV (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMapParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMapParameterivNV = extproc; + + glGetMapParameterivNV(target, pname, params); +} + +static void APIENTRY InitGetMapParameterfvNV (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMapParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMapParameterfvNV = extproc; + + glGetMapParameterfvNV(target, pname, params); +} + +static void APIENTRY InitGetMapAttribParameterivNV (GLenum target, GLuint index, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMapAttribParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMapAttribParameterivNV = extproc; + + glGetMapAttribParameterivNV(target, index, pname, params); +} + +static void APIENTRY InitGetMapAttribParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMapAttribParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMapAttribParameterfvNV = extproc; + + glGetMapAttribParameterfvNV(target, index, pname, params); +} + +static void APIENTRY InitEvalMapsNV (GLenum target, GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEvalMapsNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEvalMapsNV = extproc; + + glEvalMapsNV(target, mode); +} + +static void APIENTRY InitCombinerStageParameterfvNV (GLenum stage, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerStageParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerStageParameterfvNV = extproc; + + glCombinerStageParameterfvNV(stage, pname, params); +} + +static void APIENTRY InitGetCombinerStageParameterfvNV (GLenum stage, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCombinerStageParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCombinerStageParameterfvNV = extproc; + + glGetCombinerStageParameterfvNV(stage, pname, params); +} + +static GLboolean APIENTRY InitAreProgramsResidentNV (GLsizei n, const GLuint *programs, GLboolean *residences) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAreProgramsResidentNV"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glAreProgramsResidentNV = extproc; + + return glAreProgramsResidentNV(n, programs, residences); +} + +static void APIENTRY InitBindProgramNV (GLenum target, GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindProgramNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindProgramNV = extproc; + + glBindProgramNV(target, id); +} + +static void APIENTRY InitDeleteProgramsNV (GLsizei n, const GLuint *programs) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteProgramsNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteProgramsNV = extproc; + + glDeleteProgramsNV(n, programs); +} + +static void APIENTRY InitExecuteProgramNV (GLenum target, GLuint id, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glExecuteProgramNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glExecuteProgramNV = extproc; + + glExecuteProgramNV(target, id, params); +} + +static void APIENTRY InitGenProgramsNV (GLsizei n, GLuint *programs) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenProgramsNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenProgramsNV = extproc; + + glGenProgramsNV(n, programs); +} + +static void APIENTRY InitGetProgramParameterdvNV (GLenum target, GLuint index, GLenum pname, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramParameterdvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramParameterdvNV = extproc; + + glGetProgramParameterdvNV(target, index, pname, params); +} + +static void APIENTRY InitGetProgramParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramParameterfvNV = extproc; + + glGetProgramParameterfvNV(target, index, pname, params); +} + +static void APIENTRY InitGetProgramivNV (GLuint id, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramivNV = extproc; + + glGetProgramivNV(id, pname, params); +} + +static void APIENTRY InitGetProgramStringNV (GLuint id, GLenum pname, GLubyte *program) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramStringNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramStringNV = extproc; + + glGetProgramStringNV(id, pname, program); +} + +static void APIENTRY InitGetTrackMatrixivNV (GLenum target, GLuint address, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetTrackMatrixivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetTrackMatrixivNV = extproc; + + glGetTrackMatrixivNV(target, address, pname, params); +} + +static void APIENTRY InitGetVertexAttribdvNV (GLuint index, GLenum pname, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribdvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribdvNV = extproc; + + glGetVertexAttribdvNV(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribfvNV (GLuint index, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribfvNV = extproc; + + glGetVertexAttribfvNV(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribivNV (GLuint index, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribivNV = extproc; + + glGetVertexAttribivNV(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribPointervNV (GLuint index, GLenum pname, GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribPointervNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribPointervNV = extproc; + + glGetVertexAttribPointervNV(index, pname, pointer); +} + +static GLboolean APIENTRY InitIsProgramNV (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsProgramNV"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsProgramNV = extproc; + + return glIsProgramNV(id); +} + +static void APIENTRY InitLoadProgramNV (GLenum target, GLuint id, GLsizei len, const GLubyte *program) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLoadProgramNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLoadProgramNV = extproc; + + glLoadProgramNV(target, id, len, program); +} + +static void APIENTRY InitProgramParameter4dNV (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramParameter4dNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramParameter4dNV = extproc; + + glProgramParameter4dNV(target, index, x, y, z, w); +} + +static void APIENTRY InitProgramParameter4dvNV (GLenum target, GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramParameter4dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramParameter4dvNV = extproc; + + glProgramParameter4dvNV(target, index, v); +} + +static void APIENTRY InitProgramParameter4fNV (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramParameter4fNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramParameter4fNV = extproc; + + glProgramParameter4fNV(target, index, x, y, z, w); +} + +static void APIENTRY InitProgramParameter4fvNV (GLenum target, GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramParameter4fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramParameter4fvNV = extproc; + + glProgramParameter4fvNV(target, index, v); +} + +static void APIENTRY InitProgramParameters4dvNV (GLenum target, GLuint index, GLuint count, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramParameters4dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramParameters4dvNV = extproc; + + glProgramParameters4dvNV(target, index, count, v); +} + +static void APIENTRY InitProgramParameters4fvNV (GLenum target, GLuint index, GLuint count, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramParameters4fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramParameters4fvNV = extproc; + + glProgramParameters4fvNV(target, index, count, v); +} + +static void APIENTRY InitRequestResidentProgramsNV (GLsizei n, const GLuint *programs) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glRequestResidentProgramsNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glRequestResidentProgramsNV = extproc; + + glRequestResidentProgramsNV(n, programs); +} + +static void APIENTRY InitTrackMatrixNV (GLenum target, GLuint address, GLenum matrix, GLenum transform) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTrackMatrixNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTrackMatrixNV = extproc; + + glTrackMatrixNV(target, address, matrix, transform); +} + +static void APIENTRY InitVertexAttribPointerNV (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribPointerNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribPointerNV = extproc; + + glVertexAttribPointerNV(index, fsize, type, stride, pointer); +} + +static void APIENTRY InitVertexAttrib1dNV (GLuint index, GLdouble x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1dNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1dNV = extproc; + + glVertexAttrib1dNV(index, x); +} + +static void APIENTRY InitVertexAttrib1dvNV (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1dvNV = extproc; + + glVertexAttrib1dvNV(index, v); +} + +static void APIENTRY InitVertexAttrib1fNV (GLuint index, GLfloat x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1fNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1fNV = extproc; + + glVertexAttrib1fNV(index, x); +} + +static void APIENTRY InitVertexAttrib1fvNV (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1fvNV = extproc; + + glVertexAttrib1fvNV(index, v); +} + +static void APIENTRY InitVertexAttrib1sNV (GLuint index, GLshort x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1sNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1sNV = extproc; + + glVertexAttrib1sNV(index, x); +} + +static void APIENTRY InitVertexAttrib1svNV (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1svNV = extproc; + + glVertexAttrib1svNV(index, v); +} + +static void APIENTRY InitVertexAttrib2dNV (GLuint index, GLdouble x, GLdouble y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2dNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2dNV = extproc; + + glVertexAttrib2dNV(index, x, y); +} + +static void APIENTRY InitVertexAttrib2dvNV (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2dvNV = extproc; + + glVertexAttrib2dvNV(index, v); +} + +static void APIENTRY InitVertexAttrib2fNV (GLuint index, GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2fNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2fNV = extproc; + + glVertexAttrib2fNV(index, x, y); +} + +static void APIENTRY InitVertexAttrib2fvNV (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2fvNV = extproc; + + glVertexAttrib2fvNV(index, v); +} + +static void APIENTRY InitVertexAttrib2sNV (GLuint index, GLshort x, GLshort y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2sNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2sNV = extproc; + + glVertexAttrib2sNV(index, x, y); +} + +static void APIENTRY InitVertexAttrib2svNV (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2svNV = extproc; + + glVertexAttrib2svNV(index, v); +} + +static void APIENTRY InitVertexAttrib3dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3dNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3dNV = extproc; + + glVertexAttrib3dNV(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3dvNV (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3dvNV = extproc; + + glVertexAttrib3dvNV(index, v); +} + +static void APIENTRY InitVertexAttrib3fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3fNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3fNV = extproc; + + glVertexAttrib3fNV(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3fvNV (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3fvNV = extproc; + + glVertexAttrib3fvNV(index, v); +} + +static void APIENTRY InitVertexAttrib3sNV (GLuint index, GLshort x, GLshort y, GLshort z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3sNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3sNV = extproc; + + glVertexAttrib3sNV(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3svNV (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3svNV = extproc; + + glVertexAttrib3svNV(index, v); +} + +static void APIENTRY InitVertexAttrib4dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4dNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4dNV = extproc; + + glVertexAttrib4dNV(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4dvNV (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4dvNV = extproc; + + glVertexAttrib4dvNV(index, v); +} + +static void APIENTRY InitVertexAttrib4fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4fNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4fNV = extproc; + + glVertexAttrib4fNV(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4fvNV (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4fvNV = extproc; + + glVertexAttrib4fvNV(index, v); +} + +static void APIENTRY InitVertexAttrib4sNV (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4sNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4sNV = extproc; + + glVertexAttrib4sNV(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4svNV (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4svNV = extproc; + + glVertexAttrib4svNV(index, v); +} + +static void APIENTRY InitVertexAttrib4ubNV (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4ubNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4ubNV = extproc; + + glVertexAttrib4ubNV(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4ubvNV (GLuint index, const GLubyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4ubvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4ubvNV = extproc; + + glVertexAttrib4ubvNV(index, v); +} + +static void APIENTRY InitVertexAttribs1dvNV (GLuint index, GLsizei count, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs1dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs1dvNV = extproc; + + glVertexAttribs1dvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs1fvNV (GLuint index, GLsizei count, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs1fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs1fvNV = extproc; + + glVertexAttribs1fvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs1svNV (GLuint index, GLsizei count, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs1svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs1svNV = extproc; + + glVertexAttribs1svNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs2dvNV (GLuint index, GLsizei count, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs2dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs2dvNV = extproc; + + glVertexAttribs2dvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs2fvNV (GLuint index, GLsizei count, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs2fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs2fvNV = extproc; + + glVertexAttribs2fvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs2svNV (GLuint index, GLsizei count, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs2svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs2svNV = extproc; + + glVertexAttribs2svNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs3dvNV (GLuint index, GLsizei count, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs3dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs3dvNV = extproc; + + glVertexAttribs3dvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs3fvNV (GLuint index, GLsizei count, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs3fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs3fvNV = extproc; + + glVertexAttribs3fvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs3svNV (GLuint index, GLsizei count, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs3svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs3svNV = extproc; + + glVertexAttribs3svNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs4dvNV (GLuint index, GLsizei count, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs4dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs4dvNV = extproc; + + glVertexAttribs4dvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs4fvNV (GLuint index, GLsizei count, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs4fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs4fvNV = extproc; + + glVertexAttribs4fvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs4svNV (GLuint index, GLsizei count, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs4svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs4svNV = extproc; + + glVertexAttribs4svNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs4ubvNV (GLuint index, GLsizei count, const GLubyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs4ubvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs4ubvNV = extproc; + + glVertexAttribs4ubvNV(index, count, v); +} + +static void APIENTRY InitTexBumpParameterivATI (GLenum pname, const GLint *param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexBumpParameterivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexBumpParameterivATI = extproc; + + glTexBumpParameterivATI(pname, param); +} + +static void APIENTRY InitTexBumpParameterfvATI (GLenum pname, const GLfloat *param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexBumpParameterfvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexBumpParameterfvATI = extproc; + + glTexBumpParameterfvATI(pname, param); +} + +static void APIENTRY InitGetTexBumpParameterivATI (GLenum pname, GLint *param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetTexBumpParameterivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetTexBumpParameterivATI = extproc; + + glGetTexBumpParameterivATI(pname, param); +} + +static void APIENTRY InitGetTexBumpParameterfvATI (GLenum pname, GLfloat *param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetTexBumpParameterfvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetTexBumpParameterfvATI = extproc; + + glGetTexBumpParameterfvATI(pname, param); +} + +static GLuint APIENTRY InitGenFragmentShadersATI (GLuint range) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenFragmentShadersATI"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGenFragmentShadersATI = extproc; + + return glGenFragmentShadersATI(range); +} + +static void APIENTRY InitBindFragmentShaderATI (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindFragmentShaderATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindFragmentShaderATI = extproc; + + glBindFragmentShaderATI(id); +} + +static void APIENTRY InitDeleteFragmentShaderATI (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteFragmentShaderATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteFragmentShaderATI = extproc; + + glDeleteFragmentShaderATI(id); +} + +static void APIENTRY InitBeginFragmentShaderATI (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBeginFragmentShaderATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBeginFragmentShaderATI = extproc; + + glBeginFragmentShaderATI(); +} + +static void APIENTRY InitEndFragmentShaderATI (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEndFragmentShaderATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEndFragmentShaderATI = extproc; + + glEndFragmentShaderATI(); +} + +static void APIENTRY InitPassTexCoordATI (GLuint dst, GLuint coord, GLenum swizzle) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPassTexCoordATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPassTexCoordATI = extproc; + + glPassTexCoordATI(dst, coord, swizzle); +} + +static void APIENTRY InitSampleMapATI (GLuint dst, GLuint interp, GLenum swizzle) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSampleMapATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSampleMapATI = extproc; + + glSampleMapATI(dst, interp, swizzle); +} + +static void APIENTRY InitColorFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorFragmentOp1ATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorFragmentOp1ATI = extproc; + + glColorFragmentOp1ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod); +} + +static void APIENTRY InitColorFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorFragmentOp2ATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorFragmentOp2ATI = extproc; + + glColorFragmentOp2ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod); +} + +static void APIENTRY InitColorFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorFragmentOp3ATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorFragmentOp3ATI = extproc; + + glColorFragmentOp3ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, arg3Rep, arg3Mod); +} + +static void APIENTRY InitAlphaFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAlphaFragmentOp1ATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glAlphaFragmentOp1ATI = extproc; + + glAlphaFragmentOp1ATI(op, dst, dstMod, arg1, arg1Rep, arg1Mod); +} + +static void APIENTRY InitAlphaFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAlphaFragmentOp2ATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glAlphaFragmentOp2ATI = extproc; + + glAlphaFragmentOp2ATI(op, dst, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod); +} + +static void APIENTRY InitAlphaFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAlphaFragmentOp3ATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glAlphaFragmentOp3ATI = extproc; + + glAlphaFragmentOp3ATI(op, dst, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, arg3Rep, arg3Mod); +} + +static void APIENTRY InitSetFragmentShaderConstantATI (GLuint dst, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSetFragmentShaderConstantATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSetFragmentShaderConstantATI = extproc; + + glSetFragmentShaderConstantATI(dst, value); +} + +static void APIENTRY InitPNTrianglesiATI (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPNTrianglesiATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPNTrianglesiATI = extproc; + + glPNTrianglesiATI(pname, param); +} + +static void APIENTRY InitPNTrianglesfATI (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPNTrianglesfATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPNTrianglesfATI = extproc; + + glPNTrianglesfATI(pname, param); +} + +static GLuint APIENTRY InitNewObjectBufferATI (GLsizei size, const GLvoid *pointer, GLenum usage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNewObjectBufferATI"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glNewObjectBufferATI = extproc; + + return glNewObjectBufferATI(size, pointer, usage); +} + +static GLboolean APIENTRY InitIsObjectBufferATI (GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsObjectBufferATI"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsObjectBufferATI = extproc; + + return glIsObjectBufferATI(buffer); +} + +static void APIENTRY InitUpdateObjectBufferATI (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUpdateObjectBufferATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUpdateObjectBufferATI = extproc; + + glUpdateObjectBufferATI(buffer, offset, size, pointer, preserve); +} + +static void APIENTRY InitGetObjectBufferfvATI (GLuint buffer, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetObjectBufferfvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetObjectBufferfvATI = extproc; + + glGetObjectBufferfvATI(buffer, pname, params); +} + +static void APIENTRY InitGetObjectBufferivATI (GLuint buffer, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetObjectBufferivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetObjectBufferivATI = extproc; + + glGetObjectBufferivATI(buffer, pname, params); +} + +static void APIENTRY InitFreeObjectBufferATI (GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFreeObjectBufferATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFreeObjectBufferATI = extproc; + + glFreeObjectBufferATI(buffer); +} + +static void APIENTRY InitArrayObjectATI (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glArrayObjectATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glArrayObjectATI = extproc; + + glArrayObjectATI(array, size, type, stride, buffer, offset); +} + +static void APIENTRY InitGetArrayObjectfvATI (GLenum array, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetArrayObjectfvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetArrayObjectfvATI = extproc; + + glGetArrayObjectfvATI(array, pname, params); +} + +static void APIENTRY InitGetArrayObjectivATI (GLenum array, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetArrayObjectivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetArrayObjectivATI = extproc; + + glGetArrayObjectivATI(array, pname, params); +} + +static void APIENTRY InitVariantArrayObjectATI (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantArrayObjectATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantArrayObjectATI = extproc; + + glVariantArrayObjectATI(id, type, stride, buffer, offset); +} + +static void APIENTRY InitGetVariantArrayObjectfvATI (GLuint id, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVariantArrayObjectfvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVariantArrayObjectfvATI = extproc; + + glGetVariantArrayObjectfvATI(id, pname, params); +} + +static void APIENTRY InitGetVariantArrayObjectivATI (GLuint id, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVariantArrayObjectivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVariantArrayObjectivATI = extproc; + + glGetVariantArrayObjectivATI(id, pname, params); +} + +static void APIENTRY InitBeginVertexShaderEXT (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBeginVertexShaderEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBeginVertexShaderEXT = extproc; + + glBeginVertexShaderEXT(); +} + +static void APIENTRY InitEndVertexShaderEXT (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEndVertexShaderEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEndVertexShaderEXT = extproc; + + glEndVertexShaderEXT(); +} + +static void APIENTRY InitBindVertexShaderEXT (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindVertexShaderEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindVertexShaderEXT = extproc; + + glBindVertexShaderEXT(id); +} + +static GLuint APIENTRY InitGenVertexShadersEXT (GLuint range) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenVertexShadersEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGenVertexShadersEXT = extproc; + + return glGenVertexShadersEXT(range); +} + +static void APIENTRY InitDeleteVertexShaderEXT (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteVertexShaderEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteVertexShaderEXT = extproc; + + glDeleteVertexShaderEXT(id); +} + +static void APIENTRY InitShaderOp1EXT (GLenum op, GLuint res, GLuint arg1) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glShaderOp1EXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glShaderOp1EXT = extproc; + + glShaderOp1EXT(op, res, arg1); +} + +static void APIENTRY InitShaderOp2EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glShaderOp2EXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glShaderOp2EXT = extproc; + + glShaderOp2EXT(op, res, arg1, arg2); +} + +static void APIENTRY InitShaderOp3EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glShaderOp3EXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glShaderOp3EXT = extproc; + + glShaderOp3EXT(op, res, arg1, arg2, arg3); +} + +static void APIENTRY InitSwizzleEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSwizzleEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSwizzleEXT = extproc; + + glSwizzleEXT(res, in, outX, outY, outZ, outW); +} + +static void APIENTRY InitWriteMaskEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWriteMaskEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWriteMaskEXT = extproc; + + glWriteMaskEXT(res, in, outX, outY, outZ, outW); +} + +static void APIENTRY InitInsertComponentEXT (GLuint res, GLuint src, GLuint num) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glInsertComponentEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glInsertComponentEXT = extproc; + + glInsertComponentEXT(res, src, num); +} + +static void APIENTRY InitExtractComponentEXT (GLuint res, GLuint src, GLuint num) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glExtractComponentEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glExtractComponentEXT = extproc; + + glExtractComponentEXT(res, src, num); +} + +static GLuint APIENTRY InitGenSymbolsEXT (GLenum datatype, GLenum storagetype, GLenum range, GLuint components) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenSymbolsEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGenSymbolsEXT = extproc; + + return glGenSymbolsEXT(datatype, storagetype, range, components); +} + +static void APIENTRY InitSetInvariantEXT (GLuint id, GLenum type, const GLvoid *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSetInvariantEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSetInvariantEXT = extproc; + + glSetInvariantEXT(id, type, addr); +} + +static void APIENTRY InitSetLocalConstantEXT (GLuint id, GLenum type, const GLvoid *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSetLocalConstantEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSetLocalConstantEXT = extproc; + + glSetLocalConstantEXT(id, type, addr); +} + +static void APIENTRY InitVariantbvEXT (GLuint id, const GLbyte *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantbvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantbvEXT = extproc; + + glVariantbvEXT(id, addr); +} + +static void APIENTRY InitVariantsvEXT (GLuint id, const GLshort *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantsvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantsvEXT = extproc; + + glVariantsvEXT(id, addr); +} + +static void APIENTRY InitVariantivEXT (GLuint id, const GLint *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantivEXT = extproc; + + glVariantivEXT(id, addr); +} + +static void APIENTRY InitVariantfvEXT (GLuint id, const GLfloat *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantfvEXT = extproc; + + glVariantfvEXT(id, addr); +} + +static void APIENTRY InitVariantdvEXT (GLuint id, const GLdouble *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantdvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantdvEXT = extproc; + + glVariantdvEXT(id, addr); +} + +static void APIENTRY InitVariantubvEXT (GLuint id, const GLubyte *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantubvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantubvEXT = extproc; + + glVariantubvEXT(id, addr); +} + +static void APIENTRY InitVariantusvEXT (GLuint id, const GLushort *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantusvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantusvEXT = extproc; + + glVariantusvEXT(id, addr); +} + +static void APIENTRY InitVariantuivEXT (GLuint id, const GLuint *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantuivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantuivEXT = extproc; + + glVariantuivEXT(id, addr); +} + +static void APIENTRY InitVariantPointerEXT (GLuint id, GLenum type, GLuint stride, const GLvoid *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantPointerEXT = extproc; + + glVariantPointerEXT(id, type, stride, addr); +} + +static void APIENTRY InitEnableVariantClientStateEXT (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEnableVariantClientStateEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEnableVariantClientStateEXT = extproc; + + glEnableVariantClientStateEXT(id); +} + +static void APIENTRY InitDisableVariantClientStateEXT (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDisableVariantClientStateEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDisableVariantClientStateEXT = extproc; + + glDisableVariantClientStateEXT(id); +} + +static GLuint APIENTRY InitBindLightParameterEXT (GLenum light, GLenum value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindLightParameterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glBindLightParameterEXT = extproc; + + return glBindLightParameterEXT(light, value); +} + +static GLuint APIENTRY InitBindMaterialParameterEXT (GLenum face, GLenum value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindMaterialParameterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glBindMaterialParameterEXT = extproc; + + return glBindMaterialParameterEXT(face, value); +} + +static GLuint APIENTRY InitBindTexGenParameterEXT (GLenum unit, GLenum coord, GLenum value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindTexGenParameterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glBindTexGenParameterEXT = extproc; + + return glBindTexGenParameterEXT(unit, coord, value); +} + +static GLuint APIENTRY InitBindTextureUnitParameterEXT (GLenum unit, GLenum value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindTextureUnitParameterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glBindTextureUnitParameterEXT = extproc; + + return glBindTextureUnitParameterEXT(unit, value); +} + +static GLuint APIENTRY InitBindParameterEXT (GLenum value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindParameterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glBindParameterEXT = extproc; + + return glBindParameterEXT(value); +} + +static GLboolean APIENTRY InitIsVariantEnabledEXT (GLuint id, GLenum cap) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsVariantEnabledEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsVariantEnabledEXT = extproc; + + return glIsVariantEnabledEXT(id, cap); +} + +static void APIENTRY InitGetVariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVariantBooleanvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVariantBooleanvEXT = extproc; + + glGetVariantBooleanvEXT(id, value, data); +} + +static void APIENTRY InitGetVariantIntegervEXT (GLuint id, GLenum value, GLint *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVariantIntegervEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVariantIntegervEXT = extproc; + + glGetVariantIntegervEXT(id, value, data); +} + +static void APIENTRY InitGetVariantFloatvEXT (GLuint id, GLenum value, GLfloat *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVariantFloatvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVariantFloatvEXT = extproc; + + glGetVariantFloatvEXT(id, value, data); +} + +static void APIENTRY InitGetVariantPointervEXT (GLuint id, GLenum value, GLvoid* *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVariantPointervEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVariantPointervEXT = extproc; + + glGetVariantPointervEXT(id, value, data); +} + +static void APIENTRY InitGetInvariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetInvariantBooleanvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetInvariantBooleanvEXT = extproc; + + glGetInvariantBooleanvEXT(id, value, data); +} + +static void APIENTRY InitGetInvariantIntegervEXT (GLuint id, GLenum value, GLint *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetInvariantIntegervEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetInvariantIntegervEXT = extproc; + + glGetInvariantIntegervEXT(id, value, data); +} + +static void APIENTRY InitGetInvariantFloatvEXT (GLuint id, GLenum value, GLfloat *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetInvariantFloatvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetInvariantFloatvEXT = extproc; + + glGetInvariantFloatvEXT(id, value, data); +} + +static void APIENTRY InitGetLocalConstantBooleanvEXT (GLuint id, GLenum value, GLboolean *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetLocalConstantBooleanvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetLocalConstantBooleanvEXT = extproc; + + glGetLocalConstantBooleanvEXT(id, value, data); +} + +static void APIENTRY InitGetLocalConstantIntegervEXT (GLuint id, GLenum value, GLint *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetLocalConstantIntegervEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetLocalConstantIntegervEXT = extproc; + + glGetLocalConstantIntegervEXT(id, value, data); +} + +static void APIENTRY InitGetLocalConstantFloatvEXT (GLuint id, GLenum value, GLfloat *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetLocalConstantFloatvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetLocalConstantFloatvEXT = extproc; + + glGetLocalConstantFloatvEXT(id, value, data); +} + +static void APIENTRY InitVertexStream1sATI (GLenum stream, GLshort x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1sATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1sATI = extproc; + + glVertexStream1sATI(stream, x); +} + +static void APIENTRY InitVertexStream1svATI (GLenum stream, const GLshort *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1svATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1svATI = extproc; + + glVertexStream1svATI(stream, coords); +} + +static void APIENTRY InitVertexStream1iATI (GLenum stream, GLint x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1iATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1iATI = extproc; + + glVertexStream1iATI(stream, x); +} + +static void APIENTRY InitVertexStream1ivATI (GLenum stream, const GLint *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1ivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1ivATI = extproc; + + glVertexStream1ivATI(stream, coords); +} + +static void APIENTRY InitVertexStream1fATI (GLenum stream, GLfloat x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1fATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1fATI = extproc; + + glVertexStream1fATI(stream, x); +} + +static void APIENTRY InitVertexStream1fvATI (GLenum stream, const GLfloat *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1fvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1fvATI = extproc; + + glVertexStream1fvATI(stream, coords); +} + +static void APIENTRY InitVertexStream1dATI (GLenum stream, GLdouble x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1dATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1dATI = extproc; + + glVertexStream1dATI(stream, x); +} + +static void APIENTRY InitVertexStream1dvATI (GLenum stream, const GLdouble *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1dvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1dvATI = extproc; + + glVertexStream1dvATI(stream, coords); +} + +static void APIENTRY InitVertexStream2sATI (GLenum stream, GLshort x, GLshort y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2sATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2sATI = extproc; + + glVertexStream2sATI(stream, x, y); +} + +static void APIENTRY InitVertexStream2svATI (GLenum stream, const GLshort *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2svATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2svATI = extproc; + + glVertexStream2svATI(stream, coords); +} + +static void APIENTRY InitVertexStream2iATI (GLenum stream, GLint x, GLint y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2iATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2iATI = extproc; + + glVertexStream2iATI(stream, x, y); +} + +static void APIENTRY InitVertexStream2ivATI (GLenum stream, const GLint *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2ivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2ivATI = extproc; + + glVertexStream2ivATI(stream, coords); +} + +static void APIENTRY InitVertexStream2fATI (GLenum stream, GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2fATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2fATI = extproc; + + glVertexStream2fATI(stream, x, y); +} + +static void APIENTRY InitVertexStream2fvATI (GLenum stream, const GLfloat *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2fvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2fvATI = extproc; + + glVertexStream2fvATI(stream, coords); +} + +static void APIENTRY InitVertexStream2dATI (GLenum stream, GLdouble x, GLdouble y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2dATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2dATI = extproc; + + glVertexStream2dATI(stream, x, y); +} + +static void APIENTRY InitVertexStream2dvATI (GLenum stream, const GLdouble *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2dvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2dvATI = extproc; + + glVertexStream2dvATI(stream, coords); +} + +static void APIENTRY InitVertexStream3sATI (GLenum stream, GLshort x, GLshort y, GLshort z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3sATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3sATI = extproc; + + glVertexStream3sATI(stream, x, y, z); +} + +static void APIENTRY InitVertexStream3svATI (GLenum stream, const GLshort *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3svATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3svATI = extproc; + + glVertexStream3svATI(stream, coords); +} + +static void APIENTRY InitVertexStream3iATI (GLenum stream, GLint x, GLint y, GLint z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3iATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3iATI = extproc; + + glVertexStream3iATI(stream, x, y, z); +} + +static void APIENTRY InitVertexStream3ivATI (GLenum stream, const GLint *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3ivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3ivATI = extproc; + + glVertexStream3ivATI(stream, coords); +} + +static void APIENTRY InitVertexStream3fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3fATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3fATI = extproc; + + glVertexStream3fATI(stream, x, y, z); +} + +static void APIENTRY InitVertexStream3fvATI (GLenum stream, const GLfloat *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3fvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3fvATI = extproc; + + glVertexStream3fvATI(stream, coords); +} + +static void APIENTRY InitVertexStream3dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3dATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3dATI = extproc; + + glVertexStream3dATI(stream, x, y, z); +} + +static void APIENTRY InitVertexStream3dvATI (GLenum stream, const GLdouble *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3dvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3dvATI = extproc; + + glVertexStream3dvATI(stream, coords); +} + +static void APIENTRY InitVertexStream4sATI (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4sATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4sATI = extproc; + + glVertexStream4sATI(stream, x, y, z, w); +} + +static void APIENTRY InitVertexStream4svATI (GLenum stream, const GLshort *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4svATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4svATI = extproc; + + glVertexStream4svATI(stream, coords); +} + +static void APIENTRY InitVertexStream4iATI (GLenum stream, GLint x, GLint y, GLint z, GLint w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4iATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4iATI = extproc; + + glVertexStream4iATI(stream, x, y, z, w); +} + +static void APIENTRY InitVertexStream4ivATI (GLenum stream, const GLint *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4ivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4ivATI = extproc; + + glVertexStream4ivATI(stream, coords); +} + +static void APIENTRY InitVertexStream4fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4fATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4fATI = extproc; + + glVertexStream4fATI(stream, x, y, z, w); +} + +static void APIENTRY InitVertexStream4fvATI (GLenum stream, const GLfloat *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4fvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4fvATI = extproc; + + glVertexStream4fvATI(stream, coords); +} + +static void APIENTRY InitVertexStream4dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4dATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4dATI = extproc; + + glVertexStream4dATI(stream, x, y, z, w); +} + +static void APIENTRY InitVertexStream4dvATI (GLenum stream, const GLdouble *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4dvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4dvATI = extproc; + + glVertexStream4dvATI(stream, coords); +} + +static void APIENTRY InitNormalStream3bATI (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3bATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3bATI = extproc; + + glNormalStream3bATI(stream, nx, ny, nz); +} + +static void APIENTRY InitNormalStream3bvATI (GLenum stream, const GLbyte *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3bvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3bvATI = extproc; + + glNormalStream3bvATI(stream, coords); +} + +static void APIENTRY InitNormalStream3sATI (GLenum stream, GLshort nx, GLshort ny, GLshort nz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3sATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3sATI = extproc; + + glNormalStream3sATI(stream, nx, ny, nz); +} + +static void APIENTRY InitNormalStream3svATI (GLenum stream, const GLshort *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3svATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3svATI = extproc; + + glNormalStream3svATI(stream, coords); +} + +static void APIENTRY InitNormalStream3iATI (GLenum stream, GLint nx, GLint ny, GLint nz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3iATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3iATI = extproc; + + glNormalStream3iATI(stream, nx, ny, nz); +} + +static void APIENTRY InitNormalStream3ivATI (GLenum stream, const GLint *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3ivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3ivATI = extproc; + + glNormalStream3ivATI(stream, coords); +} + +static void APIENTRY InitNormalStream3fATI (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3fATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3fATI = extproc; + + glNormalStream3fATI(stream, nx, ny, nz); +} + +static void APIENTRY InitNormalStream3fvATI (GLenum stream, const GLfloat *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3fvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3fvATI = extproc; + + glNormalStream3fvATI(stream, coords); +} + +static void APIENTRY InitNormalStream3dATI (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3dATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3dATI = extproc; + + glNormalStream3dATI(stream, nx, ny, nz); +} + +static void APIENTRY InitNormalStream3dvATI (GLenum stream, const GLdouble *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3dvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3dvATI = extproc; + + glNormalStream3dvATI(stream, coords); +} + +static void APIENTRY InitClientActiveVertexStreamATI (GLenum stream) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glClientActiveVertexStreamATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glClientActiveVertexStreamATI = extproc; + + glClientActiveVertexStreamATI(stream); +} + +static void APIENTRY InitVertexBlendEnviATI (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexBlendEnviATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexBlendEnviATI = extproc; + + glVertexBlendEnviATI(pname, param); +} + +static void APIENTRY InitVertexBlendEnvfATI (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexBlendEnvfATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexBlendEnvfATI = extproc; + + glVertexBlendEnvfATI(pname, param); +} + +static void APIENTRY InitElementPointerATI (GLenum type, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glElementPointerATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glElementPointerATI = extproc; + + glElementPointerATI(type, pointer); +} + +static void APIENTRY InitDrawElementArrayATI (GLenum mode, GLsizei count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawElementArrayATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawElementArrayATI = extproc; + + glDrawElementArrayATI(mode, count); +} + +static void APIENTRY InitDrawRangeElementArrayATI (GLenum mode, GLuint start, GLuint end, GLsizei count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawRangeElementArrayATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawRangeElementArrayATI = extproc; + + glDrawRangeElementArrayATI(mode, start, end, count); +} + +static void APIENTRY InitDrawMeshArraysSUN (GLenum mode, GLint first, GLsizei count, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawMeshArraysSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawMeshArraysSUN = extproc; + + glDrawMeshArraysSUN(mode, first, count, width); +} + +static void APIENTRY InitGenOcclusionQueriesNV (GLsizei n, GLuint *ids) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenOcclusionQueriesNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenOcclusionQueriesNV = extproc; + + glGenOcclusionQueriesNV(n, ids); +} + +static void APIENTRY InitDeleteOcclusionQueriesNV (GLsizei n, const GLuint *ids) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteOcclusionQueriesNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteOcclusionQueriesNV = extproc; + + glDeleteOcclusionQueriesNV(n, ids); +} + +static GLboolean APIENTRY InitIsOcclusionQueryNV (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsOcclusionQueryNV"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsOcclusionQueryNV = extproc; + + return glIsOcclusionQueryNV(id); +} + +static void APIENTRY InitBeginOcclusionQueryNV (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBeginOcclusionQueryNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBeginOcclusionQueryNV = extproc; + + glBeginOcclusionQueryNV(id); +} + +static void APIENTRY InitEndOcclusionQueryNV (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEndOcclusionQueryNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEndOcclusionQueryNV = extproc; + + glEndOcclusionQueryNV(); +} + +static void APIENTRY InitGetOcclusionQueryivNV (GLuint id, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetOcclusionQueryivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetOcclusionQueryivNV = extproc; + + glGetOcclusionQueryivNV(id, pname, params); +} + +static void APIENTRY InitGetOcclusionQueryuivNV (GLuint id, GLenum pname, GLuint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetOcclusionQueryuivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetOcclusionQueryuivNV = extproc; + + glGetOcclusionQueryuivNV(id, pname, params); +} + +static void APIENTRY InitPointParameteriNV (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameteriNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameteriNV = extproc; + + glPointParameteriNV(pname, param); +} + +static void APIENTRY InitPointParameterivNV (GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterivNV = extproc; + + glPointParameterivNV(pname, params); +} + +static void APIENTRY InitActiveStencilFaceEXT (GLenum face) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glActiveStencilFaceEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glActiveStencilFaceEXT = extproc; + + glActiveStencilFaceEXT(face); +} + +static void APIENTRY InitElementPointerAPPLE (GLenum type, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glElementPointerAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glElementPointerAPPLE = extproc; + + glElementPointerAPPLE(type, pointer); +} + +static void APIENTRY InitDrawElementArrayAPPLE (GLenum mode, GLint first, GLsizei count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawElementArrayAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawElementArrayAPPLE = extproc; + + glDrawElementArrayAPPLE(mode, first, count); +} + +static void APIENTRY InitDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawRangeElementArrayAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawRangeElementArrayAPPLE = extproc; + + glDrawRangeElementArrayAPPLE(mode, start, end, first, count); +} + +static void APIENTRY InitMultiDrawElementArrayAPPLE (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiDrawElementArrayAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiDrawElementArrayAPPLE = extproc; + + glMultiDrawElementArrayAPPLE(mode, first, count, primcount); +} + +static void APIENTRY InitMultiDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiDrawRangeElementArrayAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiDrawRangeElementArrayAPPLE = extproc; + + glMultiDrawRangeElementArrayAPPLE(mode, start, end, first, count, primcount); +} + +static void APIENTRY InitGenFencesAPPLE (GLsizei n, GLuint *fences) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenFencesAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenFencesAPPLE = extproc; + + glGenFencesAPPLE(n, fences); +} + +static void APIENTRY InitDeleteFencesAPPLE (GLsizei n, const GLuint *fences) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteFencesAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteFencesAPPLE = extproc; + + glDeleteFencesAPPLE(n, fences); +} + +static void APIENTRY InitSetFenceAPPLE (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSetFenceAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSetFenceAPPLE = extproc; + + glSetFenceAPPLE(fence); +} + +static GLboolean APIENTRY InitIsFenceAPPLE (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsFenceAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsFenceAPPLE = extproc; + + return glIsFenceAPPLE(fence); +} + +static GLboolean APIENTRY InitTestFenceAPPLE (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTestFenceAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glTestFenceAPPLE = extproc; + + return glTestFenceAPPLE(fence); +} + +static void APIENTRY InitFinishFenceAPPLE (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFinishFenceAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFinishFenceAPPLE = extproc; + + glFinishFenceAPPLE(fence); +} + +static GLboolean APIENTRY InitTestObjectAPPLE (GLenum object, GLuint name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTestObjectAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glTestObjectAPPLE = extproc; + + return glTestObjectAPPLE(object, name); +} + +static void APIENTRY InitFinishObjectAPPLE (GLenum object, GLint name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFinishObjectAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFinishObjectAPPLE = extproc; + + glFinishObjectAPPLE(object, name); +} + +static void APIENTRY InitBindVertexArrayAPPLE (GLuint array) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindVertexArrayAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindVertexArrayAPPLE = extproc; + + glBindVertexArrayAPPLE(array); +} + +static void APIENTRY InitDeleteVertexArraysAPPLE (GLsizei n, const GLuint *arrays) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteVertexArraysAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteVertexArraysAPPLE = extproc; + + glDeleteVertexArraysAPPLE(n, arrays); +} + +static void APIENTRY InitGenVertexArraysAPPLE (GLsizei n, const GLuint *arrays) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenVertexArraysAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenVertexArraysAPPLE = extproc; + + glGenVertexArraysAPPLE(n, arrays); +} + +static GLboolean APIENTRY InitIsVertexArrayAPPLE (GLuint array) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsVertexArrayAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsVertexArrayAPPLE = extproc; + + return glIsVertexArrayAPPLE(array); +} + +static void APIENTRY InitVertexArrayRangeAPPLE (GLsizei length, GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexArrayRangeAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexArrayRangeAPPLE = extproc; + + glVertexArrayRangeAPPLE(length, pointer); +} + +static void APIENTRY InitFlushVertexArrayRangeAPPLE (GLsizei length, GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFlushVertexArrayRangeAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFlushVertexArrayRangeAPPLE = extproc; + + glFlushVertexArrayRangeAPPLE(length, pointer); +} + +static void APIENTRY InitVertexArrayParameteriAPPLE (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexArrayParameteriAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexArrayParameteriAPPLE = extproc; + + glVertexArrayParameteriAPPLE(pname, param); +} + +static void APIENTRY InitDrawBuffersATI (GLsizei n, const GLenum *bufs) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawBuffersATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawBuffersATI = extproc; + + glDrawBuffersATI(n, bufs); +} + +static void APIENTRY InitProgramNamedParameter4fNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramNamedParameter4fNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramNamedParameter4fNV = extproc; + + glProgramNamedParameter4fNV(id, len, name, x, y, z, w); +} + +static void APIENTRY InitProgramNamedParameter4dNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramNamedParameter4dNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramNamedParameter4dNV = extproc; + + glProgramNamedParameter4dNV(id, len, name, x, y, z, w); +} + +static void APIENTRY InitProgramNamedParameter4fvNV (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramNamedParameter4fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramNamedParameter4fvNV = extproc; + + glProgramNamedParameter4fvNV(id, len, name, v); +} + +static void APIENTRY InitProgramNamedParameter4dvNV (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramNamedParameter4dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramNamedParameter4dvNV = extproc; + + glProgramNamedParameter4dvNV(id, len, name, v); +} + +static void APIENTRY InitGetProgramNamedParameterfvNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramNamedParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramNamedParameterfvNV = extproc; + + glGetProgramNamedParameterfvNV(id, len, name, params); +} + +static void APIENTRY InitGetProgramNamedParameterdvNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramNamedParameterdvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramNamedParameterdvNV = extproc; + + glGetProgramNamedParameterdvNV(id, len, name, params); +} + +static void APIENTRY InitVertex2hNV (GLhalfNV x, GLhalfNV y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertex2hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertex2hNV = extproc; + + glVertex2hNV(x, y); +} + +static void APIENTRY InitVertex2hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertex2hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertex2hvNV = extproc; + + glVertex2hvNV(v); +} + +static void APIENTRY InitVertex3hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertex3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertex3hNV = extproc; + + glVertex3hNV(x, y, z); +} + +static void APIENTRY InitVertex3hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertex3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertex3hvNV = extproc; + + glVertex3hvNV(v); +} + +static void APIENTRY InitVertex4hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertex4hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertex4hNV = extproc; + + glVertex4hNV(x, y, z, w); +} + +static void APIENTRY InitVertex4hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertex4hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertex4hvNV = extproc; + + glVertex4hvNV(v); +} + +static void APIENTRY InitNormal3hNV (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormal3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormal3hNV = extproc; + + glNormal3hNV(nx, ny, nz); +} + +static void APIENTRY InitNormal3hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormal3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormal3hvNV = extproc; + + glNormal3hvNV(v); +} + +static void APIENTRY InitColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor3hNV = extproc; + + glColor3hNV(red, green, blue); +} + +static void APIENTRY InitColor3hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor3hvNV = extproc; + + glColor3hvNV(v); +} + +static void APIENTRY InitColor4hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4hNV = extproc; + + glColor4hNV(red, green, blue, alpha); +} + +static void APIENTRY InitColor4hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4hvNV = extproc; + + glColor4hvNV(v); +} + +static void APIENTRY InitTexCoord1hNV (GLhalfNV s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord1hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord1hNV = extproc; + + glTexCoord1hNV(s); +} + +static void APIENTRY InitTexCoord1hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord1hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord1hvNV = extproc; + + glTexCoord1hvNV(v); +} + +static void APIENTRY InitTexCoord2hNV (GLhalfNV s, GLhalfNV t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2hNV = extproc; + + glTexCoord2hNV(s, t); +} + +static void APIENTRY InitTexCoord2hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2hvNV = extproc; + + glTexCoord2hvNV(v); +} + +static void APIENTRY InitTexCoord3hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord3hNV = extproc; + + glTexCoord3hNV(s, t, r); +} + +static void APIENTRY InitTexCoord3hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord3hvNV = extproc; + + glTexCoord3hvNV(v); +} + +static void APIENTRY InitTexCoord4hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord4hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord4hNV = extproc; + + glTexCoord4hNV(s, t, r, q); +} + +static void APIENTRY InitTexCoord4hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord4hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord4hvNV = extproc; + + glTexCoord4hvNV(v); +} + +static void APIENTRY InitMultiTexCoord1hNV (GLenum target, GLhalfNV s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1hNV = extproc; + + glMultiTexCoord1hNV(target, s); +} + +static void APIENTRY InitMultiTexCoord1hvNV (GLenum target, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1hvNV = extproc; + + glMultiTexCoord1hvNV(target, v); +} + +static void APIENTRY InitMultiTexCoord2hNV (GLenum target, GLhalfNV s, GLhalfNV t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2hNV = extproc; + + glMultiTexCoord2hNV(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2hvNV (GLenum target, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2hvNV = extproc; + + glMultiTexCoord2hvNV(target, v); +} + +static void APIENTRY InitMultiTexCoord3hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3hNV = extproc; + + glMultiTexCoord3hNV(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3hvNV (GLenum target, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3hvNV = extproc; + + glMultiTexCoord3hvNV(target, v); +} + +static void APIENTRY InitMultiTexCoord4hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4hNV = extproc; + + glMultiTexCoord4hNV(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4hvNV (GLenum target, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4hvNV = extproc; + + glMultiTexCoord4hvNV(target, v); +} + +static void APIENTRY InitFogCoordhNV (GLhalfNV fog) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordhNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordhNV = extproc; + + glFogCoordhNV(fog); +} + +static void APIENTRY InitFogCoordhvNV (const GLhalfNV *fog) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordhvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordhvNV = extproc; + + glFogCoordhvNV(fog); +} + +static void APIENTRY InitSecondaryColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3hNV = extproc; + + glSecondaryColor3hNV(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3hvNV = extproc; + + glSecondaryColor3hvNV(v); +} + +static void APIENTRY InitVertexWeighthNV (GLhalfNV weight) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexWeighthNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexWeighthNV = extproc; + + glVertexWeighthNV(weight); +} + +static void APIENTRY InitVertexWeighthvNV (const GLhalfNV *weight) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexWeighthvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexWeighthvNV = extproc; + + glVertexWeighthvNV(weight); +} + +static void APIENTRY InitVertexAttrib1hNV (GLuint index, GLhalfNV x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1hNV = extproc; + + glVertexAttrib1hNV(index, x); +} + +static void APIENTRY InitVertexAttrib1hvNV (GLuint index, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1hvNV = extproc; + + glVertexAttrib1hvNV(index, v); +} + +static void APIENTRY InitVertexAttrib2hNV (GLuint index, GLhalfNV x, GLhalfNV y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2hNV = extproc; + + glVertexAttrib2hNV(index, x, y); +} + +static void APIENTRY InitVertexAttrib2hvNV (GLuint index, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2hvNV = extproc; + + glVertexAttrib2hvNV(index, v); +} + +static void APIENTRY InitVertexAttrib3hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3hNV = extproc; + + glVertexAttrib3hNV(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3hvNV (GLuint index, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3hvNV = extproc; + + glVertexAttrib3hvNV(index, v); +} + +static void APIENTRY InitVertexAttrib4hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4hNV = extproc; + + glVertexAttrib4hNV(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4hvNV (GLuint index, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4hvNV = extproc; + + glVertexAttrib4hvNV(index, v); +} + +static void APIENTRY InitVertexAttribs1hvNV (GLuint index, GLsizei n, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs1hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs1hvNV = extproc; + + glVertexAttribs1hvNV(index, n, v); +} + +static void APIENTRY InitVertexAttribs2hvNV (GLuint index, GLsizei n, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs2hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs2hvNV = extproc; + + glVertexAttribs2hvNV(index, n, v); +} + +static void APIENTRY InitVertexAttribs3hvNV (GLuint index, GLsizei n, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs3hvNV = extproc; + + glVertexAttribs3hvNV(index, n, v); +} + +static void APIENTRY InitVertexAttribs4hvNV (GLuint index, GLsizei n, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs4hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs4hvNV = extproc; + + glVertexAttribs4hvNV(index, n, v); +} + +static void APIENTRY InitPixelDataRangeNV (GLenum target, GLsizei length, GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelDataRangeNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelDataRangeNV = extproc; + + glPixelDataRangeNV(target, length, pointer); +} + +static void APIENTRY InitFlushPixelDataRangeNV (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFlushPixelDataRangeNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFlushPixelDataRangeNV = extproc; + + glFlushPixelDataRangeNV(target); +} + +static void APIENTRY InitPrimitiveRestartNV (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPrimitiveRestartNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPrimitiveRestartNV = extproc; + + glPrimitiveRestartNV(); +} + +static void APIENTRY InitPrimitiveRestartIndexNV (GLuint index) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPrimitiveRestartIndexNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPrimitiveRestartIndexNV = extproc; + + glPrimitiveRestartIndexNV(index); +} + +static GLvoid* APIENTRY InitMapObjectBufferATI (GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMapObjectBufferATI"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glMapObjectBufferATI = extproc; + + return glMapObjectBufferATI(buffer); +} + +static void APIENTRY InitUnmapObjectBufferATI (GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUnmapObjectBufferATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUnmapObjectBufferATI = extproc; + + glUnmapObjectBufferATI(buffer); +} + +static void APIENTRY InitStencilOpSeparateATI (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glStencilOpSeparateATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glStencilOpSeparateATI = extproc; + + glStencilOpSeparateATI(face, sfail, dpfail, dppass); +} + +static void APIENTRY InitStencilFuncSeparateATI (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glStencilFuncSeparateATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glStencilFuncSeparateATI = extproc; + + glStencilFuncSeparateATI(frontfunc, backfunc, ref, mask); +} + +static void APIENTRY InitVertexAttribArrayObjectATI (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribArrayObjectATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribArrayObjectATI = extproc; + + glVertexAttribArrayObjectATI(index, size, type, normalized, stride, buffer, offset); +} + +static void APIENTRY InitGetVertexAttribArrayObjectfvATI (GLuint index, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribArrayObjectfvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribArrayObjectfvATI = extproc; + + glGetVertexAttribArrayObjectfvATI(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribArrayObjectivATI (GLuint index, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribArrayObjectivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribArrayObjectivATI = extproc; + + glGetVertexAttribArrayObjectivATI(index, pname, params); +} + +static void APIENTRY InitDepthBoundsEXT (GLclampd zmin, GLclampd zmax) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDepthBoundsEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDepthBoundsEXT = extproc; + + glDepthBoundsEXT(zmin, zmax); +} + +static void APIENTRY InitBlendEquationSeparateEXT (GLenum modeRGB, GLenum modeAlpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendEquationSeparateEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendEquationSeparateEXT = extproc; + + glBlendEquationSeparateEXT(modeRGB, modeAlpha); +} + +static void APIENTRY InitAddSwapHintRectWIN (GLint x, GLint y, GLsizei width, GLsizei height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAddSwapHintRectWIN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glAddSwapHintRectWIN = extproc; + + glAddSwapHintRectWIN(x, y, width, height); +} + +#ifdef _WIN32 + +static HANDLE WINAPI InitCreateBufferRegionARB (HDC hDC, int iLayerPlane, UINT uType) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglCreateBufferRegionARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglCreateBufferRegionARB = extproc; + + return wglCreateBufferRegionARB(hDC, iLayerPlane, uType); +} + +static VOID WINAPI InitDeleteBufferRegionARB (HANDLE hRegion) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDeleteBufferRegionARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + wglDeleteBufferRegionARB = extproc; + + wglDeleteBufferRegionARB(hRegion); +} + +static BOOL WINAPI InitSaveBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSaveBufferRegionARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSaveBufferRegionARB = extproc; + + return wglSaveBufferRegionARB(hRegion, x, y, width, height); +} + +static BOOL WINAPI InitRestoreBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglRestoreBufferRegionARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglRestoreBufferRegionARB = extproc; + + return wglRestoreBufferRegionARB(hRegion, x, y, width, height, xSrc, ySrc); +} + +static const WINAPI InitGetExtensionsStringARB (HDC hdc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetExtensionsStringARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetExtensionsStringARB = extproc; + + return wglGetExtensionsStringARB(hdc); +} + +static BOOL WINAPI InitGetPixelFormatAttribivARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetPixelFormatAttribivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetPixelFormatAttribivARB = extproc; + + return wglGetPixelFormatAttribivARB(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, piValues); +} + +static BOOL WINAPI InitGetPixelFormatAttribfvARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetPixelFormatAttribfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetPixelFormatAttribfvARB = extproc; + + return wglGetPixelFormatAttribfvARB(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, pfValues); +} + +static BOOL WINAPI InitChoosePixelFormatARB (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglChoosePixelFormatARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglChoosePixelFormatARB = extproc; + + return wglChoosePixelFormatARB(hdc, piAttribIList, pfAttribFList, nMaxFormats, piFormats, nNumFormats); +} + +static BOOL WINAPI InitMakeContextCurrentARB (HDC hDrawDC, HDC hReadDC, HGLRC hglrc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglMakeContextCurrentARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglMakeContextCurrentARB = extproc; + + return wglMakeContextCurrentARB(hDrawDC, hReadDC, hglrc); +} + +static HDC WINAPI InitGetCurrentReadDCARB (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetCurrentReadDCARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetCurrentReadDCARB = extproc; + + return wglGetCurrentReadDCARB(); +} + +static HPBUFFERARB WINAPI InitCreatePbufferARB (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglCreatePbufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglCreatePbufferARB = extproc; + + return wglCreatePbufferARB(hDC, iPixelFormat, iWidth, iHeight, piAttribList); +} + +static HDC WINAPI InitGetPbufferDCARB (HPBUFFERARB hPbuffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetPbufferDCARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetPbufferDCARB = extproc; + + return wglGetPbufferDCARB(hPbuffer); +} + +static int WINAPI InitReleasePbufferDCARB (HPBUFFERARB hPbuffer, HDC hDC) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglReleasePbufferDCARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglReleasePbufferDCARB = extproc; + + return wglReleasePbufferDCARB(hPbuffer, hDC); +} + +static BOOL WINAPI InitDestroyPbufferARB (HPBUFFERARB hPbuffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDestroyPbufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglDestroyPbufferARB = extproc; + + return wglDestroyPbufferARB(hPbuffer); +} + +static BOOL WINAPI InitQueryPbufferARB (HPBUFFERARB hPbuffer, int iAttribute, int *piValue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglQueryPbufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglQueryPbufferARB = extproc; + + return wglQueryPbufferARB(hPbuffer, iAttribute, piValue); +} + +static BOOL WINAPI InitBindTexImageARB (HPBUFFERARB hPbuffer, int iBuffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglBindTexImageARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglBindTexImageARB = extproc; + + return wglBindTexImageARB(hPbuffer, iBuffer); +} + +static BOOL WINAPI InitReleaseTexImageARB (HPBUFFERARB hPbuffer, int iBuffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglReleaseTexImageARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglReleaseTexImageARB = extproc; + + return wglReleaseTexImageARB(hPbuffer, iBuffer); +} + +static BOOL WINAPI InitSetPbufferAttribARB (HPBUFFERARB hPbuffer, const int *piAttribList) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSetPbufferAttribARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSetPbufferAttribARB = extproc; + + return wglSetPbufferAttribARB(hPbuffer, piAttribList); +} + +static GLboolean WINAPI InitCreateDisplayColorTableEXT (GLushort id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglCreateDisplayColorTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglCreateDisplayColorTableEXT = extproc; + + return wglCreateDisplayColorTableEXT(id); +} + +static GLboolean WINAPI InitLoadDisplayColorTableEXT (const GLushort *table, GLuint length) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglLoadDisplayColorTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglLoadDisplayColorTableEXT = extproc; + + return wglLoadDisplayColorTableEXT(table, length); +} + +static GLboolean WINAPI InitBindDisplayColorTableEXT (GLushort id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglBindDisplayColorTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglBindDisplayColorTableEXT = extproc; + + return wglBindDisplayColorTableEXT(id); +} + +static VOID WINAPI InitDestroyDisplayColorTableEXT (GLushort id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDestroyDisplayColorTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + wglDestroyDisplayColorTableEXT = extproc; + + wglDestroyDisplayColorTableEXT(id); +} + +static const WINAPI InitGetExtensionsStringEXT (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetExtensionsStringEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetExtensionsStringEXT = extproc; + + return wglGetExtensionsStringEXT(); +} + +static BOOL WINAPI InitMakeContextCurrentEXT (HDC hDrawDC, HDC hReadDC, HGLRC hglrc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglMakeContextCurrentEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglMakeContextCurrentEXT = extproc; + + return wglMakeContextCurrentEXT(hDrawDC, hReadDC, hglrc); +} + +static HDC WINAPI InitGetCurrentReadDCEXT (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetCurrentReadDCEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetCurrentReadDCEXT = extproc; + + return wglGetCurrentReadDCEXT(); +} + +static HPBUFFEREXT WINAPI InitCreatePbufferEXT (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglCreatePbufferEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglCreatePbufferEXT = extproc; + + return wglCreatePbufferEXT(hDC, iPixelFormat, iWidth, iHeight, piAttribList); +} + +static HDC WINAPI InitGetPbufferDCEXT (HPBUFFEREXT hPbuffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetPbufferDCEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetPbufferDCEXT = extproc; + + return wglGetPbufferDCEXT(hPbuffer); +} + +static int WINAPI InitReleasePbufferDCEXT (HPBUFFEREXT hPbuffer, HDC hDC) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglReleasePbufferDCEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglReleasePbufferDCEXT = extproc; + + return wglReleasePbufferDCEXT(hPbuffer, hDC); +} + +static BOOL WINAPI InitDestroyPbufferEXT (HPBUFFEREXT hPbuffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDestroyPbufferEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglDestroyPbufferEXT = extproc; + + return wglDestroyPbufferEXT(hPbuffer); +} + +static BOOL WINAPI InitQueryPbufferEXT (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglQueryPbufferEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglQueryPbufferEXT = extproc; + + return wglQueryPbufferEXT(hPbuffer, iAttribute, piValue); +} + +static BOOL WINAPI InitGetPixelFormatAttribivEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetPixelFormatAttribivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetPixelFormatAttribivEXT = extproc; + + return wglGetPixelFormatAttribivEXT(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, piValues); +} + +static BOOL WINAPI InitGetPixelFormatAttribfvEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetPixelFormatAttribfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetPixelFormatAttribfvEXT = extproc; + + return wglGetPixelFormatAttribfvEXT(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, pfValues); +} + +static BOOL WINAPI InitChoosePixelFormatEXT (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglChoosePixelFormatEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglChoosePixelFormatEXT = extproc; + + return wglChoosePixelFormatEXT(hdc, piAttribIList, pfAttribFList, nMaxFormats, piFormats, nNumFormats); +} + +static BOOL WINAPI InitSwapIntervalEXT (int interval) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSwapIntervalEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSwapIntervalEXT = extproc; + + return wglSwapIntervalEXT(interval); +} + +static int WINAPI InitGetSwapIntervalEXT (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetSwapIntervalEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetSwapIntervalEXT = extproc; + + return wglGetSwapIntervalEXT(); +} + +static void* WINAPI InitAllocateMemoryNV (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglAllocateMemoryNV"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglAllocateMemoryNV = extproc; + + return wglAllocateMemoryNV(size, readfreq, writefreq, priority); +} + +static void WINAPI InitFreeMemoryNV (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglFreeMemoryNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + wglFreeMemoryNV = extproc; + + wglFreeMemoryNV(); +} + +static BOOL WINAPI InitGetSyncValuesOML (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetSyncValuesOML"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetSyncValuesOML = extproc; + + return wglGetSyncValuesOML(hdc, ust, msc, sbc); +} + +static BOOL WINAPI InitGetMscRateOML (HDC hdc, INT32 *numerator, INT32 *denominator) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetMscRateOML"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetMscRateOML = extproc; + + return wglGetMscRateOML(hdc, numerator, denominator); +} + +static INT64 WINAPI InitSwapBuffersMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSwapBuffersMscOML"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSwapBuffersMscOML = extproc; + + return wglSwapBuffersMscOML(hdc, target_msc, divisor, remainder); +} + +static INT64 WINAPI InitSwapLayerBuffersMscOML (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSwapLayerBuffersMscOML"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSwapLayerBuffersMscOML = extproc; + + return wglSwapLayerBuffersMscOML(hdc, fuPlanes, target_msc, divisor, remainder); +} + +static BOOL WINAPI InitWaitForMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglWaitForMscOML"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglWaitForMscOML = extproc; + + return wglWaitForMscOML(hdc, target_msc, divisor, remainder, ust, msc, sbc); +} + +static BOOL WINAPI InitWaitForSbcOML (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglWaitForSbcOML"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglWaitForSbcOML = extproc; + + return wglWaitForSbcOML(hdc, target_sbc, ust, msc, sbc); +} + +static BOOL WINAPI InitGetDigitalVideoParametersI3D (HDC hDC, int iAttribute, int *piValue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetDigitalVideoParametersI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetDigitalVideoParametersI3D = extproc; + + return wglGetDigitalVideoParametersI3D(hDC, iAttribute, piValue); +} + +static BOOL WINAPI InitSetDigitalVideoParametersI3D (HDC hDC, int iAttribute, const int *piValue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSetDigitalVideoParametersI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSetDigitalVideoParametersI3D = extproc; + + return wglSetDigitalVideoParametersI3D(hDC, iAttribute, piValue); +} + +static BOOL WINAPI InitGetGammaTableParametersI3D (HDC hDC, int iAttribute, int *piValue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetGammaTableParametersI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetGammaTableParametersI3D = extproc; + + return wglGetGammaTableParametersI3D(hDC, iAttribute, piValue); +} + +static BOOL WINAPI InitSetGammaTableParametersI3D (HDC hDC, int iAttribute, const int *piValue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSetGammaTableParametersI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSetGammaTableParametersI3D = extproc; + + return wglSetGammaTableParametersI3D(hDC, iAttribute, piValue); +} + +static BOOL WINAPI InitGetGammaTableI3D (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetGammaTableI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetGammaTableI3D = extproc; + + return wglGetGammaTableI3D(hDC, iEntries, puRed, puGreen, puBlue); +} + +static BOOL WINAPI InitSetGammaTableI3D (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSetGammaTableI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSetGammaTableI3D = extproc; + + return wglSetGammaTableI3D(hDC, iEntries, puRed, puGreen, puBlue); +} + +static BOOL WINAPI InitEnableGenlockI3D (HDC hDC) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglEnableGenlockI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglEnableGenlockI3D = extproc; + + return wglEnableGenlockI3D(hDC); +} + +static BOOL WINAPI InitDisableGenlockI3D (HDC hDC) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDisableGenlockI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglDisableGenlockI3D = extproc; + + return wglDisableGenlockI3D(hDC); +} + +static BOOL WINAPI InitIsEnabledGenlockI3D (HDC hDC, BOOL *pFlag) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglIsEnabledGenlockI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglIsEnabledGenlockI3D = extproc; + + return wglIsEnabledGenlockI3D(hDC, pFlag); +} + +static BOOL WINAPI InitGenlockSourceI3D (HDC hDC, UINT uSource) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGenlockSourceI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGenlockSourceI3D = extproc; + + return wglGenlockSourceI3D(hDC, uSource); +} + +static BOOL WINAPI InitGetGenlockSourceI3D (HDC hDC, UINT *uSource) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetGenlockSourceI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetGenlockSourceI3D = extproc; + + return wglGetGenlockSourceI3D(hDC, uSource); +} + +static BOOL WINAPI InitGenlockSourceEdgeI3D (HDC hDC, UINT uEdge) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGenlockSourceEdgeI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGenlockSourceEdgeI3D = extproc; + + return wglGenlockSourceEdgeI3D(hDC, uEdge); +} + +static BOOL WINAPI InitGetGenlockSourceEdgeI3D (HDC hDC, UINT *uEdge) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetGenlockSourceEdgeI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetGenlockSourceEdgeI3D = extproc; + + return wglGetGenlockSourceEdgeI3D(hDC, uEdge); +} + +static BOOL WINAPI InitGenlockSampleRateI3D (HDC hDC, UINT uRate) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGenlockSampleRateI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGenlockSampleRateI3D = extproc; + + return wglGenlockSampleRateI3D(hDC, uRate); +} + +static BOOL WINAPI InitGetGenlockSampleRateI3D (HDC hDC, UINT *uRate) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetGenlockSampleRateI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetGenlockSampleRateI3D = extproc; + + return wglGetGenlockSampleRateI3D(hDC, uRate); +} + +static BOOL WINAPI InitGenlockSourceDelayI3D (HDC hDC, UINT uDelay) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGenlockSourceDelayI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGenlockSourceDelayI3D = extproc; + + return wglGenlockSourceDelayI3D(hDC, uDelay); +} + +static BOOL WINAPI InitGetGenlockSourceDelayI3D (HDC hDC, UINT *uDelay) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetGenlockSourceDelayI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetGenlockSourceDelayI3D = extproc; + + return wglGetGenlockSourceDelayI3D(hDC, uDelay); +} + +static BOOL WINAPI InitQueryGenlockMaxSourceDelayI3D (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglQueryGenlockMaxSourceDelayI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglQueryGenlockMaxSourceDelayI3D = extproc; + + return wglQueryGenlockMaxSourceDelayI3D(hDC, uMaxLineDelay, uMaxPixelDelay); +} + +static LPVOID WINAPI InitCreateImageBufferI3D (HDC hDC, DWORD dwSize, UINT uFlags) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglCreateImageBufferI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglCreateImageBufferI3D = extproc; + + return wglCreateImageBufferI3D(hDC, dwSize, uFlags); +} + +static BOOL WINAPI InitDestroyImageBufferI3D (HDC hDC, LPVOID pAddress) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDestroyImageBufferI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglDestroyImageBufferI3D = extproc; + + return wglDestroyImageBufferI3D(hDC, pAddress); +} + +static BOOL WINAPI InitAssociateImageBufferEventsI3D (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglAssociateImageBufferEventsI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglAssociateImageBufferEventsI3D = extproc; + + return wglAssociateImageBufferEventsI3D(hDC, pEvent, pAddress, pSize, count); +} + +static BOOL WINAPI InitReleaseImageBufferEventsI3D (HDC hDC, const LPVOID *pAddress, UINT count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglReleaseImageBufferEventsI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglReleaseImageBufferEventsI3D = extproc; + + return wglReleaseImageBufferEventsI3D(hDC, pAddress, count); +} + +static BOOL WINAPI InitEnableFrameLockI3D (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglEnableFrameLockI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglEnableFrameLockI3D = extproc; + + return wglEnableFrameLockI3D(); +} + +static BOOL WINAPI InitDisableFrameLockI3D (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDisableFrameLockI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglDisableFrameLockI3D = extproc; + + return wglDisableFrameLockI3D(); +} + +static BOOL WINAPI InitIsEnabledFrameLockI3D (BOOL *pFlag) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglIsEnabledFrameLockI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglIsEnabledFrameLockI3D = extproc; + + return wglIsEnabledFrameLockI3D(pFlag); +} + +static BOOL WINAPI InitQueryFrameLockMasterI3D (BOOL *pFlag) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglQueryFrameLockMasterI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglQueryFrameLockMasterI3D = extproc; + + return wglQueryFrameLockMasterI3D(pFlag); +} + +static BOOL WINAPI InitGetFrameUsageI3D (float *pUsage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetFrameUsageI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetFrameUsageI3D = extproc; + + return wglGetFrameUsageI3D(pUsage); +} + +static BOOL WINAPI InitBeginFrameTrackingI3D (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglBeginFrameTrackingI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglBeginFrameTrackingI3D = extproc; + + return wglBeginFrameTrackingI3D(); +} + +static BOOL WINAPI InitEndFrameTrackingI3D (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglEndFrameTrackingI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglEndFrameTrackingI3D = extproc; + + return wglEndFrameTrackingI3D(); +} + +static BOOL WINAPI InitQueryFrameTrackingI3D (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglQueryFrameTrackingI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglQueryFrameTrackingI3D = extproc; + + return wglQueryFrameTrackingI3D(pFrameCount, pMissedFrames, pLastMissedUsage); +} + +#endif /* _WIN32 */ + +_GLextensionProcs _extensionProcs = { + InitBlendColor, + InitBlendEquation, + InitDrawRangeElements, + InitColorTable, + InitColorTableParameterfv, + InitColorTableParameteriv, + InitCopyColorTable, + InitGetColorTable, + InitGetColorTableParameterfv, + InitGetColorTableParameteriv, + InitColorSubTable, + InitCopyColorSubTable, + InitConvolutionFilter1D, + InitConvolutionFilter2D, + InitConvolutionParameterf, + InitConvolutionParameterfv, + InitConvolutionParameteri, + InitConvolutionParameteriv, + InitCopyConvolutionFilter1D, + InitCopyConvolutionFilter2D, + InitGetConvolutionFilter, + InitGetConvolutionParameterfv, + InitGetConvolutionParameteriv, + InitGetSeparableFilter, + InitSeparableFilter2D, + InitGetHistogram, + InitGetHistogramParameterfv, + InitGetHistogramParameteriv, + InitGetMinmax, + InitGetMinmaxParameterfv, + InitGetMinmaxParameteriv, + InitHistogram, + InitMinmax, + InitResetHistogram, + InitResetMinmax, + InitTexImage3D, + InitTexSubImage3D, + InitCopyTexSubImage3D, + InitActiveTexture, + InitClientActiveTexture, + InitMultiTexCoord1d, + InitMultiTexCoord1dv, + InitMultiTexCoord1f, + InitMultiTexCoord1fv, + InitMultiTexCoord1i, + InitMultiTexCoord1iv, + InitMultiTexCoord1s, + InitMultiTexCoord1sv, + InitMultiTexCoord2d, + InitMultiTexCoord2dv, + InitMultiTexCoord2f, + InitMultiTexCoord2fv, + InitMultiTexCoord2i, + InitMultiTexCoord2iv, + InitMultiTexCoord2s, + InitMultiTexCoord2sv, + InitMultiTexCoord3d, + InitMultiTexCoord3dv, + InitMultiTexCoord3f, + InitMultiTexCoord3fv, + InitMultiTexCoord3i, + InitMultiTexCoord3iv, + InitMultiTexCoord3s, + InitMultiTexCoord3sv, + InitMultiTexCoord4d, + InitMultiTexCoord4dv, + InitMultiTexCoord4f, + InitMultiTexCoord4fv, + InitMultiTexCoord4i, + InitMultiTexCoord4iv, + InitMultiTexCoord4s, + InitMultiTexCoord4sv, + InitLoadTransposeMatrixf, + InitLoadTransposeMatrixd, + InitMultTransposeMatrixf, + InitMultTransposeMatrixd, + InitSampleCoverage, + InitCompressedTexImage3D, + InitCompressedTexImage2D, + InitCompressedTexImage1D, + InitCompressedTexSubImage3D, + InitCompressedTexSubImage2D, + InitCompressedTexSubImage1D, + InitGetCompressedTexImage, + InitBlendFuncSeparate, + InitFogCoordf, + InitFogCoordfv, + InitFogCoordd, + InitFogCoorddv, + InitFogCoordPointer, + InitMultiDrawArrays, + InitMultiDrawElements, + InitPointParameterf, + InitPointParameterfv, + InitPointParameteri, + InitPointParameteriv, + InitSecondaryColor3b, + InitSecondaryColor3bv, + InitSecondaryColor3d, + InitSecondaryColor3dv, + InitSecondaryColor3f, + InitSecondaryColor3fv, + InitSecondaryColor3i, + InitSecondaryColor3iv, + InitSecondaryColor3s, + InitSecondaryColor3sv, + InitSecondaryColor3ub, + InitSecondaryColor3ubv, + InitSecondaryColor3ui, + InitSecondaryColor3uiv, + InitSecondaryColor3us, + InitSecondaryColor3usv, + InitSecondaryColorPointer, + InitWindowPos2d, + InitWindowPos2dv, + InitWindowPos2f, + InitWindowPos2fv, + InitWindowPos2i, + InitWindowPos2iv, + InitWindowPos2s, + InitWindowPos2sv, + InitWindowPos3d, + InitWindowPos3dv, + InitWindowPos3f, + InitWindowPos3fv, + InitWindowPos3i, + InitWindowPos3iv, + InitWindowPos3s, + InitWindowPos3sv, + InitGenQueries, + InitDeleteQueries, + InitIsQuery, + InitBeginQuery, + InitEndQuery, + InitGetQueryiv, + InitGetQueryObjectiv, + InitGetQueryObjectuiv, + InitBindBuffer, + InitDeleteBuffers, + InitGenBuffers, + InitIsBuffer, + InitBufferData, + InitBufferSubData, + InitGetBufferSubData, + InitMapBuffer, + InitUnmapBuffer, + InitGetBufferParameteriv, + InitGetBufferPointerv, + InitActiveTextureARB, + InitClientActiveTextureARB, + InitMultiTexCoord1dARB, + InitMultiTexCoord1dvARB, + InitMultiTexCoord1fARB, + InitMultiTexCoord1fvARB, + InitMultiTexCoord1iARB, + InitMultiTexCoord1ivARB, + InitMultiTexCoord1sARB, + InitMultiTexCoord1svARB, + InitMultiTexCoord2dARB, + InitMultiTexCoord2dvARB, + InitMultiTexCoord2fARB, + InitMultiTexCoord2fvARB, + InitMultiTexCoord2iARB, + InitMultiTexCoord2ivARB, + InitMultiTexCoord2sARB, + InitMultiTexCoord2svARB, + InitMultiTexCoord3dARB, + InitMultiTexCoord3dvARB, + InitMultiTexCoord3fARB, + InitMultiTexCoord3fvARB, + InitMultiTexCoord3iARB, + InitMultiTexCoord3ivARB, + InitMultiTexCoord3sARB, + InitMultiTexCoord3svARB, + InitMultiTexCoord4dARB, + InitMultiTexCoord4dvARB, + InitMultiTexCoord4fARB, + InitMultiTexCoord4fvARB, + InitMultiTexCoord4iARB, + InitMultiTexCoord4ivARB, + InitMultiTexCoord4sARB, + InitMultiTexCoord4svARB, + InitLoadTransposeMatrixfARB, + InitLoadTransposeMatrixdARB, + InitMultTransposeMatrixfARB, + InitMultTransposeMatrixdARB, + InitSampleCoverageARB, + InitCompressedTexImage3DARB, + InitCompressedTexImage2DARB, + InitCompressedTexImage1DARB, + InitCompressedTexSubImage3DARB, + InitCompressedTexSubImage2DARB, + InitCompressedTexSubImage1DARB, + InitGetCompressedTexImageARB, + InitPointParameterfARB, + InitPointParameterfvARB, + InitWeightbvARB, + InitWeightsvARB, + InitWeightivARB, + InitWeightfvARB, + InitWeightdvARB, + InitWeightubvARB, + InitWeightusvARB, + InitWeightuivARB, + InitWeightPointerARB, + InitVertexBlendARB, + InitCurrentPaletteMatrixARB, + InitMatrixIndexubvARB, + InitMatrixIndexusvARB, + InitMatrixIndexuivARB, + InitMatrixIndexPointerARB, + InitWindowPos2dARB, + InitWindowPos2dvARB, + InitWindowPos2fARB, + InitWindowPos2fvARB, + InitWindowPos2iARB, + InitWindowPos2ivARB, + InitWindowPos2sARB, + InitWindowPos2svARB, + InitWindowPos3dARB, + InitWindowPos3dvARB, + InitWindowPos3fARB, + InitWindowPos3fvARB, + InitWindowPos3iARB, + InitWindowPos3ivARB, + InitWindowPos3sARB, + InitWindowPos3svARB, + InitVertexAttrib1dARB, + InitVertexAttrib1dvARB, + InitVertexAttrib1fARB, + InitVertexAttrib1fvARB, + InitVertexAttrib1sARB, + InitVertexAttrib1svARB, + InitVertexAttrib2dARB, + InitVertexAttrib2dvARB, + InitVertexAttrib2fARB, + InitVertexAttrib2fvARB, + InitVertexAttrib2sARB, + InitVertexAttrib2svARB, + InitVertexAttrib3dARB, + InitVertexAttrib3dvARB, + InitVertexAttrib3fARB, + InitVertexAttrib3fvARB, + InitVertexAttrib3sARB, + InitVertexAttrib3svARB, + InitVertexAttrib4NbvARB, + InitVertexAttrib4NivARB, + InitVertexAttrib4NsvARB, + InitVertexAttrib4NubARB, + InitVertexAttrib4NubvARB, + InitVertexAttrib4NuivARB, + InitVertexAttrib4NusvARB, + InitVertexAttrib4bvARB, + InitVertexAttrib4dARB, + InitVertexAttrib4dvARB, + InitVertexAttrib4fARB, + InitVertexAttrib4fvARB, + InitVertexAttrib4ivARB, + InitVertexAttrib4sARB, + InitVertexAttrib4svARB, + InitVertexAttrib4ubvARB, + InitVertexAttrib4uivARB, + InitVertexAttrib4usvARB, + InitVertexAttribPointerARB, + InitEnableVertexAttribArrayARB, + InitDisableVertexAttribArrayARB, + InitProgramStringARB, + InitBindProgramARB, + InitDeleteProgramsARB, + InitGenProgramsARB, + InitProgramEnvParameter4dARB, + InitProgramEnvParameter4dvARB, + InitProgramEnvParameter4fARB, + InitProgramEnvParameter4fvARB, + InitProgramLocalParameter4dARB, + InitProgramLocalParameter4dvARB, + InitProgramLocalParameter4fARB, + InitProgramLocalParameter4fvARB, + InitGetProgramEnvParameterdvARB, + InitGetProgramEnvParameterfvARB, + InitGetProgramLocalParameterdvARB, + InitGetProgramLocalParameterfvARB, + InitGetProgramivARB, + InitGetProgramStringARB, + InitGetVertexAttribdvARB, + InitGetVertexAttribfvARB, + InitGetVertexAttribivARB, + InitGetVertexAttribPointervARB, + InitIsProgramARB, + InitBindBufferARB, + InitDeleteBuffersARB, + InitGenBuffersARB, + InitIsBufferARB, + InitBufferDataARB, + InitBufferSubDataARB, + InitGetBufferSubDataARB, + InitMapBufferARB, + InitUnmapBufferARB, + InitGetBufferParameterivARB, + InitGetBufferPointervARB, + InitGenQueriesARB, + InitDeleteQueriesARB, + InitIsQueryARB, + InitBeginQueryARB, + InitEndQueryARB, + InitGetQueryivARB, + InitGetQueryObjectivARB, + InitGetQueryObjectuivARB, + InitDeleteObjectARB, + InitGetHandleARB, + InitDetachObjectARB, + InitCreateShaderObjectARB, + InitShaderSourceARB, + InitCompileShaderARB, + InitCreateProgramObjectARB, + InitAttachObjectARB, + InitLinkProgramARB, + InitUseProgramObjectARB, + InitValidateProgramARB, + InitUniform1fARB, + InitUniform2fARB, + InitUniform3fARB, + InitUniform4fARB, + InitUniform1iARB, + InitUniform2iARB, + InitUniform3iARB, + InitUniform4iARB, + InitUniform1fvARB, + InitUniform2fvARB, + InitUniform3fvARB, + InitUniform4fvARB, + InitUniform1ivARB, + InitUniform2ivARB, + InitUniform3ivARB, + InitUniform4ivARB, + InitUniformMatrix2fvARB, + InitUniformMatrix3fvARB, + InitUniformMatrix4fvARB, + InitGetObjectParameterfvARB, + InitGetObjectParameterivARB, + InitGetInfoLogARB, + InitGetAttachedObjectsARB, + InitGetUniformLocationARB, + InitGetActiveUniformARB, + InitGetUniformfvARB, + InitGetUniformivARB, + InitGetShaderSourceARB, + InitBindAttribLocationARB, + InitGetActiveAttribARB, + InitGetAttribLocationARB, + InitBlendColorEXT, + InitPolygonOffsetEXT, + InitTexImage3DEXT, + InitTexSubImage3DEXT, + InitGetTexFilterFuncSGIS, + InitTexFilterFuncSGIS, + InitTexSubImage1DEXT, + InitTexSubImage2DEXT, + InitCopyTexImage1DEXT, + InitCopyTexImage2DEXT, + InitCopyTexSubImage1DEXT, + InitCopyTexSubImage2DEXT, + InitCopyTexSubImage3DEXT, + InitGetHistogramEXT, + InitGetHistogramParameterfvEXT, + InitGetHistogramParameterivEXT, + InitGetMinmaxEXT, + InitGetMinmaxParameterfvEXT, + InitGetMinmaxParameterivEXT, + InitHistogramEXT, + InitMinmaxEXT, + InitResetHistogramEXT, + InitResetMinmaxEXT, + InitConvolutionFilter1DEXT, + InitConvolutionFilter2DEXT, + InitConvolutionParameterfEXT, + InitConvolutionParameterfvEXT, + InitConvolutionParameteriEXT, + InitConvolutionParameterivEXT, + InitCopyConvolutionFilter1DEXT, + InitCopyConvolutionFilter2DEXT, + InitGetConvolutionFilterEXT, + InitGetConvolutionParameterfvEXT, + InitGetConvolutionParameterivEXT, + InitGetSeparableFilterEXT, + InitSeparableFilter2DEXT, + InitColorTableSGI, + InitColorTableParameterfvSGI, + InitColorTableParameterivSGI, + InitCopyColorTableSGI, + InitGetColorTableSGI, + InitGetColorTableParameterfvSGI, + InitGetColorTableParameterivSGI, + InitPixelTexGenSGIX, + InitPixelTexGenParameteriSGIS, + InitPixelTexGenParameterivSGIS, + InitPixelTexGenParameterfSGIS, + InitPixelTexGenParameterfvSGIS, + InitGetPixelTexGenParameterivSGIS, + InitGetPixelTexGenParameterfvSGIS, + InitTexImage4DSGIS, + InitTexSubImage4DSGIS, + InitAreTexturesResidentEXT, + InitBindTextureEXT, + InitDeleteTexturesEXT, + InitGenTexturesEXT, + InitIsTextureEXT, + InitPrioritizeTexturesEXT, + InitDetailTexFuncSGIS, + InitGetDetailTexFuncSGIS, + InitSharpenTexFuncSGIS, + InitGetSharpenTexFuncSGIS, + InitSampleMaskSGIS, + InitSamplePatternSGIS, + InitArrayElementEXT, + InitColorPointerEXT, + InitDrawArraysEXT, + InitEdgeFlagPointerEXT, + InitGetPointervEXT, + InitIndexPointerEXT, + InitNormalPointerEXT, + InitTexCoordPointerEXT, + InitVertexPointerEXT, + InitBlendEquationEXT, + InitSpriteParameterfSGIX, + InitSpriteParameterfvSGIX, + InitSpriteParameteriSGIX, + InitSpriteParameterivSGIX, + InitPointParameterfEXT, + InitPointParameterfvEXT, + InitPointParameterfSGIS, + InitPointParameterfvSGIS, + InitGetInstrumentsSGIX, + InitInstrumentsBufferSGIX, + InitPollInstrumentsSGIX, + InitReadInstrumentsSGIX, + InitStartInstrumentsSGIX, + InitStopInstrumentsSGIX, + InitFrameZoomSGIX, + InitTagSampleBufferSGIX, + InitDeformationMap3dSGIX, + InitDeformationMap3fSGIX, + InitDeformSGIX, + InitLoadIdentityDeformationMapSGIX, + InitReferencePlaneSGIX, + InitFlushRasterSGIX, + InitFogFuncSGIS, + InitGetFogFuncSGIS, + InitImageTransformParameteriHP, + InitImageTransformParameterfHP, + InitImageTransformParameterivHP, + InitImageTransformParameterfvHP, + InitGetImageTransformParameterivHP, + InitGetImageTransformParameterfvHP, + InitColorSubTableEXT, + InitCopyColorSubTableEXT, + InitHintPGI, + InitColorTableEXT, + InitGetColorTableEXT, + InitGetColorTableParameterivEXT, + InitGetColorTableParameterfvEXT, + InitGetListParameterfvSGIX, + InitGetListParameterivSGIX, + InitListParameterfSGIX, + InitListParameterfvSGIX, + InitListParameteriSGIX, + InitListParameterivSGIX, + InitIndexMaterialEXT, + InitIndexFuncEXT, + InitLockArraysEXT, + InitUnlockArraysEXT, + InitCullParameterdvEXT, + InitCullParameterfvEXT, + InitFragmentColorMaterialSGIX, + InitFragmentLightfSGIX, + InitFragmentLightfvSGIX, + InitFragmentLightiSGIX, + InitFragmentLightivSGIX, + InitFragmentLightModelfSGIX, + InitFragmentLightModelfvSGIX, + InitFragmentLightModeliSGIX, + InitFragmentLightModelivSGIX, + InitFragmentMaterialfSGIX, + InitFragmentMaterialfvSGIX, + InitFragmentMaterialiSGIX, + InitFragmentMaterialivSGIX, + InitGetFragmentLightfvSGIX, + InitGetFragmentLightivSGIX, + InitGetFragmentMaterialfvSGIX, + InitGetFragmentMaterialivSGIX, + InitLightEnviSGIX, + InitDrawRangeElementsEXT, + InitApplyTextureEXT, + InitTextureLightEXT, + InitTextureMaterialEXT, + InitAsyncMarkerSGIX, + InitFinishAsyncSGIX, + InitPollAsyncSGIX, + InitGenAsyncMarkersSGIX, + InitDeleteAsyncMarkersSGIX, + InitIsAsyncMarkerSGIX, + InitVertexPointervINTEL, + InitNormalPointervINTEL, + InitColorPointervINTEL, + InitTexCoordPointervINTEL, + InitPixelTransformParameteriEXT, + InitPixelTransformParameterfEXT, + InitPixelTransformParameterivEXT, + InitPixelTransformParameterfvEXT, + InitSecondaryColor3bEXT, + InitSecondaryColor3bvEXT, + InitSecondaryColor3dEXT, + InitSecondaryColor3dvEXT, + InitSecondaryColor3fEXT, + InitSecondaryColor3fvEXT, + InitSecondaryColor3iEXT, + InitSecondaryColor3ivEXT, + InitSecondaryColor3sEXT, + InitSecondaryColor3svEXT, + InitSecondaryColor3ubEXT, + InitSecondaryColor3ubvEXT, + InitSecondaryColor3uiEXT, + InitSecondaryColor3uivEXT, + InitSecondaryColor3usEXT, + InitSecondaryColor3usvEXT, + InitSecondaryColorPointerEXT, + InitTextureNormalEXT, + InitMultiDrawArraysEXT, + InitMultiDrawElementsEXT, + InitFogCoordfEXT, + InitFogCoordfvEXT, + InitFogCoorddEXT, + InitFogCoorddvEXT, + InitFogCoordPointerEXT, + InitTangent3bEXT, + InitTangent3bvEXT, + InitTangent3dEXT, + InitTangent3dvEXT, + InitTangent3fEXT, + InitTangent3fvEXT, + InitTangent3iEXT, + InitTangent3ivEXT, + InitTangent3sEXT, + InitTangent3svEXT, + InitBinormal3bEXT, + InitBinormal3bvEXT, + InitBinormal3dEXT, + InitBinormal3dvEXT, + InitBinormal3fEXT, + InitBinormal3fvEXT, + InitBinormal3iEXT, + InitBinormal3ivEXT, + InitBinormal3sEXT, + InitBinormal3svEXT, + InitTangentPointerEXT, + InitBinormalPointerEXT, + InitFinishTextureSUNX, + InitGlobalAlphaFactorbSUN, + InitGlobalAlphaFactorsSUN, + InitGlobalAlphaFactoriSUN, + InitGlobalAlphaFactorfSUN, + InitGlobalAlphaFactordSUN, + InitGlobalAlphaFactorubSUN, + InitGlobalAlphaFactorusSUN, + InitGlobalAlphaFactoruiSUN, + InitReplacementCodeuiSUN, + InitReplacementCodeusSUN, + InitReplacementCodeubSUN, + InitReplacementCodeuivSUN, + InitReplacementCodeusvSUN, + InitReplacementCodeubvSUN, + InitReplacementCodePointerSUN, + InitColor4ubVertex2fSUN, + InitColor4ubVertex2fvSUN, + InitColor4ubVertex3fSUN, + InitColor4ubVertex3fvSUN, + InitColor3fVertex3fSUN, + InitColor3fVertex3fvSUN, + InitNormal3fVertex3fSUN, + InitNormal3fVertex3fvSUN, + InitColor4fNormal3fVertex3fSUN, + InitColor4fNormal3fVertex3fvSUN, + InitTexCoord2fVertex3fSUN, + InitTexCoord2fVertex3fvSUN, + InitTexCoord4fVertex4fSUN, + InitTexCoord4fVertex4fvSUN, + InitTexCoord2fColor4ubVertex3fSUN, + InitTexCoord2fColor4ubVertex3fvSUN, + InitTexCoord2fColor3fVertex3fSUN, + InitTexCoord2fColor3fVertex3fvSUN, + InitTexCoord2fNormal3fVertex3fSUN, + InitTexCoord2fNormal3fVertex3fvSUN, + InitTexCoord2fColor4fNormal3fVertex3fSUN, + InitTexCoord2fColor4fNormal3fVertex3fvSUN, + InitTexCoord4fColor4fNormal3fVertex4fSUN, + InitTexCoord4fColor4fNormal3fVertex4fvSUN, + InitReplacementCodeuiVertex3fSUN, + InitReplacementCodeuiVertex3fvSUN, + InitReplacementCodeuiColor4ubVertex3fSUN, + InitReplacementCodeuiColor4ubVertex3fvSUN, + InitReplacementCodeuiColor3fVertex3fSUN, + InitReplacementCodeuiColor3fVertex3fvSUN, + InitReplacementCodeuiNormal3fVertex3fSUN, + InitReplacementCodeuiNormal3fVertex3fvSUN, + InitReplacementCodeuiColor4fNormal3fVertex3fSUN, + InitReplacementCodeuiColor4fNormal3fVertex3fvSUN, + InitReplacementCodeuiTexCoord2fVertex3fSUN, + InitReplacementCodeuiTexCoord2fVertex3fvSUN, + InitReplacementCodeuiTexCoord2fNormal3fVertex3fSUN, + InitReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN, + InitReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN, + InitReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN, + InitBlendFuncSeparateEXT, + InitBlendFuncSeparateINGR, + InitVertexWeightfEXT, + InitVertexWeightfvEXT, + InitVertexWeightPointerEXT, + InitFlushVertexArrayRangeNV, + InitVertexArrayRangeNV, + InitCombinerParameterfvNV, + InitCombinerParameterfNV, + InitCombinerParameterivNV, + InitCombinerParameteriNV, + InitCombinerInputNV, + InitCombinerOutputNV, + InitFinalCombinerInputNV, + InitGetCombinerInputParameterfvNV, + InitGetCombinerInputParameterivNV, + InitGetCombinerOutputParameterfvNV, + InitGetCombinerOutputParameterivNV, + InitGetFinalCombinerInputParameterfvNV, + InitGetFinalCombinerInputParameterivNV, + InitResizeBuffersMESA, + InitWindowPos2dMESA, + InitWindowPos2dvMESA, + InitWindowPos2fMESA, + InitWindowPos2fvMESA, + InitWindowPos2iMESA, + InitWindowPos2ivMESA, + InitWindowPos2sMESA, + InitWindowPos2svMESA, + InitWindowPos3dMESA, + InitWindowPos3dvMESA, + InitWindowPos3fMESA, + InitWindowPos3fvMESA, + InitWindowPos3iMESA, + InitWindowPos3ivMESA, + InitWindowPos3sMESA, + InitWindowPos3svMESA, + InitWindowPos4dMESA, + InitWindowPos4dvMESA, + InitWindowPos4fMESA, + InitWindowPos4fvMESA, + InitWindowPos4iMESA, + InitWindowPos4ivMESA, + InitWindowPos4sMESA, + InitWindowPos4svMESA, + InitMultiModeDrawArraysIBM, + InitMultiModeDrawElementsIBM, + InitColorPointerListIBM, + InitSecondaryColorPointerListIBM, + InitEdgeFlagPointerListIBM, + InitFogCoordPointerListIBM, + InitIndexPointerListIBM, + InitNormalPointerListIBM, + InitTexCoordPointerListIBM, + InitVertexPointerListIBM, + InitTbufferMask3DFX, + InitSampleMaskEXT, + InitSamplePatternEXT, + InitTextureColorMaskSGIS, + InitIglooInterfaceSGIX, + InitDeleteFencesNV, + InitGenFencesNV, + InitIsFenceNV, + InitTestFenceNV, + InitGetFenceivNV, + InitFinishFenceNV, + InitSetFenceNV, + InitMapControlPointsNV, + InitMapParameterivNV, + InitMapParameterfvNV, + InitGetMapControlPointsNV, + InitGetMapParameterivNV, + InitGetMapParameterfvNV, + InitGetMapAttribParameterivNV, + InitGetMapAttribParameterfvNV, + InitEvalMapsNV, + InitCombinerStageParameterfvNV, + InitGetCombinerStageParameterfvNV, + InitAreProgramsResidentNV, + InitBindProgramNV, + InitDeleteProgramsNV, + InitExecuteProgramNV, + InitGenProgramsNV, + InitGetProgramParameterdvNV, + InitGetProgramParameterfvNV, + InitGetProgramivNV, + InitGetProgramStringNV, + InitGetTrackMatrixivNV, + InitGetVertexAttribdvNV, + InitGetVertexAttribfvNV, + InitGetVertexAttribivNV, + InitGetVertexAttribPointervNV, + InitIsProgramNV, + InitLoadProgramNV, + InitProgramParameter4dNV, + InitProgramParameter4dvNV, + InitProgramParameter4fNV, + InitProgramParameter4fvNV, + InitProgramParameters4dvNV, + InitProgramParameters4fvNV, + InitRequestResidentProgramsNV, + InitTrackMatrixNV, + InitVertexAttribPointerNV, + InitVertexAttrib1dNV, + InitVertexAttrib1dvNV, + InitVertexAttrib1fNV, + InitVertexAttrib1fvNV, + InitVertexAttrib1sNV, + InitVertexAttrib1svNV, + InitVertexAttrib2dNV, + InitVertexAttrib2dvNV, + InitVertexAttrib2fNV, + InitVertexAttrib2fvNV, + InitVertexAttrib2sNV, + InitVertexAttrib2svNV, + InitVertexAttrib3dNV, + InitVertexAttrib3dvNV, + InitVertexAttrib3fNV, + InitVertexAttrib3fvNV, + InitVertexAttrib3sNV, + InitVertexAttrib3svNV, + InitVertexAttrib4dNV, + InitVertexAttrib4dvNV, + InitVertexAttrib4fNV, + InitVertexAttrib4fvNV, + InitVertexAttrib4sNV, + InitVertexAttrib4svNV, + InitVertexAttrib4ubNV, + InitVertexAttrib4ubvNV, + InitVertexAttribs1dvNV, + InitVertexAttribs1fvNV, + InitVertexAttribs1svNV, + InitVertexAttribs2dvNV, + InitVertexAttribs2fvNV, + InitVertexAttribs2svNV, + InitVertexAttribs3dvNV, + InitVertexAttribs3fvNV, + InitVertexAttribs3svNV, + InitVertexAttribs4dvNV, + InitVertexAttribs4fvNV, + InitVertexAttribs4svNV, + InitVertexAttribs4ubvNV, + InitTexBumpParameterivATI, + InitTexBumpParameterfvATI, + InitGetTexBumpParameterivATI, + InitGetTexBumpParameterfvATI, + InitGenFragmentShadersATI, + InitBindFragmentShaderATI, + InitDeleteFragmentShaderATI, + InitBeginFragmentShaderATI, + InitEndFragmentShaderATI, + InitPassTexCoordATI, + InitSampleMapATI, + InitColorFragmentOp1ATI, + InitColorFragmentOp2ATI, + InitColorFragmentOp3ATI, + InitAlphaFragmentOp1ATI, + InitAlphaFragmentOp2ATI, + InitAlphaFragmentOp3ATI, + InitSetFragmentShaderConstantATI, + InitPNTrianglesiATI, + InitPNTrianglesfATI, + InitNewObjectBufferATI, + InitIsObjectBufferATI, + InitUpdateObjectBufferATI, + InitGetObjectBufferfvATI, + InitGetObjectBufferivATI, + InitFreeObjectBufferATI, + InitArrayObjectATI, + InitGetArrayObjectfvATI, + InitGetArrayObjectivATI, + InitVariantArrayObjectATI, + InitGetVariantArrayObjectfvATI, + InitGetVariantArrayObjectivATI, + InitBeginVertexShaderEXT, + InitEndVertexShaderEXT, + InitBindVertexShaderEXT, + InitGenVertexShadersEXT, + InitDeleteVertexShaderEXT, + InitShaderOp1EXT, + InitShaderOp2EXT, + InitShaderOp3EXT, + InitSwizzleEXT, + InitWriteMaskEXT, + InitInsertComponentEXT, + InitExtractComponentEXT, + InitGenSymbolsEXT, + InitSetInvariantEXT, + InitSetLocalConstantEXT, + InitVariantbvEXT, + InitVariantsvEXT, + InitVariantivEXT, + InitVariantfvEXT, + InitVariantdvEXT, + InitVariantubvEXT, + InitVariantusvEXT, + InitVariantuivEXT, + InitVariantPointerEXT, + InitEnableVariantClientStateEXT, + InitDisableVariantClientStateEXT, + InitBindLightParameterEXT, + InitBindMaterialParameterEXT, + InitBindTexGenParameterEXT, + InitBindTextureUnitParameterEXT, + InitBindParameterEXT, + InitIsVariantEnabledEXT, + InitGetVariantBooleanvEXT, + InitGetVariantIntegervEXT, + InitGetVariantFloatvEXT, + InitGetVariantPointervEXT, + InitGetInvariantBooleanvEXT, + InitGetInvariantIntegervEXT, + InitGetInvariantFloatvEXT, + InitGetLocalConstantBooleanvEXT, + InitGetLocalConstantIntegervEXT, + InitGetLocalConstantFloatvEXT, + InitVertexStream1sATI, + InitVertexStream1svATI, + InitVertexStream1iATI, + InitVertexStream1ivATI, + InitVertexStream1fATI, + InitVertexStream1fvATI, + InitVertexStream1dATI, + InitVertexStream1dvATI, + InitVertexStream2sATI, + InitVertexStream2svATI, + InitVertexStream2iATI, + InitVertexStream2ivATI, + InitVertexStream2fATI, + InitVertexStream2fvATI, + InitVertexStream2dATI, + InitVertexStream2dvATI, + InitVertexStream3sATI, + InitVertexStream3svATI, + InitVertexStream3iATI, + InitVertexStream3ivATI, + InitVertexStream3fATI, + InitVertexStream3fvATI, + InitVertexStream3dATI, + InitVertexStream3dvATI, + InitVertexStream4sATI, + InitVertexStream4svATI, + InitVertexStream4iATI, + InitVertexStream4ivATI, + InitVertexStream4fATI, + InitVertexStream4fvATI, + InitVertexStream4dATI, + InitVertexStream4dvATI, + InitNormalStream3bATI, + InitNormalStream3bvATI, + InitNormalStream3sATI, + InitNormalStream3svATI, + InitNormalStream3iATI, + InitNormalStream3ivATI, + InitNormalStream3fATI, + InitNormalStream3fvATI, + InitNormalStream3dATI, + InitNormalStream3dvATI, + InitClientActiveVertexStreamATI, + InitVertexBlendEnviATI, + InitVertexBlendEnvfATI, + InitElementPointerATI, + InitDrawElementArrayATI, + InitDrawRangeElementArrayATI, + InitDrawMeshArraysSUN, + InitGenOcclusionQueriesNV, + InitDeleteOcclusionQueriesNV, + InitIsOcclusionQueryNV, + InitBeginOcclusionQueryNV, + InitEndOcclusionQueryNV, + InitGetOcclusionQueryivNV, + InitGetOcclusionQueryuivNV, + InitPointParameteriNV, + InitPointParameterivNV, + InitActiveStencilFaceEXT, + InitElementPointerAPPLE, + InitDrawElementArrayAPPLE, + InitDrawRangeElementArrayAPPLE, + InitMultiDrawElementArrayAPPLE, + InitMultiDrawRangeElementArrayAPPLE, + InitGenFencesAPPLE, + InitDeleteFencesAPPLE, + InitSetFenceAPPLE, + InitIsFenceAPPLE, + InitTestFenceAPPLE, + InitFinishFenceAPPLE, + InitTestObjectAPPLE, + InitFinishObjectAPPLE, + InitBindVertexArrayAPPLE, + InitDeleteVertexArraysAPPLE, + InitGenVertexArraysAPPLE, + InitIsVertexArrayAPPLE, + InitVertexArrayRangeAPPLE, + InitFlushVertexArrayRangeAPPLE, + InitVertexArrayParameteriAPPLE, + InitDrawBuffersATI, + InitProgramNamedParameter4fNV, + InitProgramNamedParameter4dNV, + InitProgramNamedParameter4fvNV, + InitProgramNamedParameter4dvNV, + InitGetProgramNamedParameterfvNV, + InitGetProgramNamedParameterdvNV, + InitVertex2hNV, + InitVertex2hvNV, + InitVertex3hNV, + InitVertex3hvNV, + InitVertex4hNV, + InitVertex4hvNV, + InitNormal3hNV, + InitNormal3hvNV, + InitColor3hNV, + InitColor3hvNV, + InitColor4hNV, + InitColor4hvNV, + InitTexCoord1hNV, + InitTexCoord1hvNV, + InitTexCoord2hNV, + InitTexCoord2hvNV, + InitTexCoord3hNV, + InitTexCoord3hvNV, + InitTexCoord4hNV, + InitTexCoord4hvNV, + InitMultiTexCoord1hNV, + InitMultiTexCoord1hvNV, + InitMultiTexCoord2hNV, + InitMultiTexCoord2hvNV, + InitMultiTexCoord3hNV, + InitMultiTexCoord3hvNV, + InitMultiTexCoord4hNV, + InitMultiTexCoord4hvNV, + InitFogCoordhNV, + InitFogCoordhvNV, + InitSecondaryColor3hNV, + InitSecondaryColor3hvNV, + InitVertexWeighthNV, + InitVertexWeighthvNV, + InitVertexAttrib1hNV, + InitVertexAttrib1hvNV, + InitVertexAttrib2hNV, + InitVertexAttrib2hvNV, + InitVertexAttrib3hNV, + InitVertexAttrib3hvNV, + InitVertexAttrib4hNV, + InitVertexAttrib4hvNV, + InitVertexAttribs1hvNV, + InitVertexAttribs2hvNV, + InitVertexAttribs3hvNV, + InitVertexAttribs4hvNV, + InitPixelDataRangeNV, + InitFlushPixelDataRangeNV, + InitPrimitiveRestartNV, + InitPrimitiveRestartIndexNV, + InitMapObjectBufferATI, + InitUnmapObjectBufferATI, + InitStencilOpSeparateATI, + InitStencilFuncSeparateATI, + InitVertexAttribArrayObjectATI, + InitGetVertexAttribArrayObjectfvATI, + InitGetVertexAttribArrayObjectivATI, + InitDepthBoundsEXT, + InitBlendEquationSeparateEXT, + InitAddSwapHintRectWIN, +#ifdef _WIN32 + InitCreateBufferRegionARB, + InitDeleteBufferRegionARB, + InitSaveBufferRegionARB, + InitRestoreBufferRegionARB, + InitGetExtensionsStringARB, + InitGetPixelFormatAttribivARB, + InitGetPixelFormatAttribfvARB, + InitChoosePixelFormatARB, + InitMakeContextCurrentARB, + InitGetCurrentReadDCARB, + InitCreatePbufferARB, + InitGetPbufferDCARB, + InitReleasePbufferDCARB, + InitDestroyPbufferARB, + InitQueryPbufferARB, + InitBindTexImageARB, + InitReleaseTexImageARB, + InitSetPbufferAttribARB, + InitCreateDisplayColorTableEXT, + InitLoadDisplayColorTableEXT, + InitBindDisplayColorTableEXT, + InitDestroyDisplayColorTableEXT, + InitGetExtensionsStringEXT, + InitMakeContextCurrentEXT, + InitGetCurrentReadDCEXT, + InitCreatePbufferEXT, + InitGetPbufferDCEXT, + InitReleasePbufferDCEXT, + InitDestroyPbufferEXT, + InitQueryPbufferEXT, + InitGetPixelFormatAttribivEXT, + InitGetPixelFormatAttribfvEXT, + InitChoosePixelFormatEXT, + InitSwapIntervalEXT, + InitGetSwapIntervalEXT, + InitAllocateMemoryNV, + InitFreeMemoryNV, + InitGetSyncValuesOML, + InitGetMscRateOML, + InitSwapBuffersMscOML, + InitSwapLayerBuffersMscOML, + InitWaitForMscOML, + InitWaitForSbcOML, + InitGetDigitalVideoParametersI3D, + InitSetDigitalVideoParametersI3D, + InitGetGammaTableParametersI3D, + InitSetGammaTableParametersI3D, + InitGetGammaTableI3D, + InitSetGammaTableI3D, + InitEnableGenlockI3D, + InitDisableGenlockI3D, + InitIsEnabledGenlockI3D, + InitGenlockSourceI3D, + InitGetGenlockSourceI3D, + InitGenlockSourceEdgeI3D, + InitGetGenlockSourceEdgeI3D, + InitGenlockSampleRateI3D, + InitGetGenlockSampleRateI3D, + InitGenlockSourceDelayI3D, + InitGetGenlockSourceDelayI3D, + InitQueryGenlockMaxSourceDelayI3D, + InitCreateImageBufferI3D, + InitDestroyImageBufferI3D, + InitAssociateImageBufferEventsI3D, + InitReleaseImageBufferEventsI3D, + InitEnableFrameLockI3D, + InitDisableFrameLockI3D, + InitIsEnabledFrameLockI3D, + InitQueryFrameLockMasterI3D, + InitGetFrameUsageI3D, + InitBeginFrameTrackingI3D, + InitEndFrameTrackingI3D, + InitQueryFrameTrackingI3D, +#endif /* _WIN32 */ +}; diff --git a/plugins/zerogs/opengl/glprocs.h b/plugins/zerogs/opengl/glprocs.h index c40e5bdc0f..1df56f18db 100644 --- a/plugins/zerogs/opengl/glprocs.h +++ b/plugins/zerogs/opengl/glprocs.h @@ -1,2213 +1,2213 @@ -#ifndef _GLPROCS_H_ -#define _GLPROCS_H_ - -/* -** GLprocs utility for getting function addresses for OpenGL(R) 1.2, -** OpenGL 1.3, OpenGL 1.4, OpenGL 1.5 and OpenGL extension functions. -** -** Version: 1.1 -** -** License Applicability. Except to the extent portions of this file are -** made subject to an alternative license as permitted in the SGI Free -** Software License B, Version 1.1 (the "License"), the contents of this -** file are subject only to the provisions of the License. You may not use -** this file except in compliance with the License. You may obtain a copy -** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 -** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: -** -** http://oss.sgi.com/projects/FreeB -** -** Note that, as provided in the License, the Software is distributed on an -** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS -** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND -** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A -** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. -** -** Original Code. The Original Code is: OpenGL Sample Implementation, -** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, -** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. -** Copyright in any portions created by third parties is as indicated -** elsewhere herein. All Rights Reserved. -** -** Additional Notice Provisions: This software was created using the -** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has -** not been independently verified as being compliant with the OpenGL(R) -** version 1.2.1 Specification. -** -** Initial version of glprocs.{c,h} contributed by Intel(R) Corporation. -*/ - -#ifdef _WIN32 - #include - #include -#else - #include -#endif - -#ifndef _WIN32 /* non-Windows environment */ - #ifndef APIENTRY - #define APIENTRY - #endif - #ifdef __GNUC__ - #define _inline __inline__ - #else - #define _inline - #endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Structure of all OpenGL {1.2, 1.3, 1.4, 1.5}, GL extension procs.*/ - -typedef struct { - void (APIENTRY *BlendColor) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); - void (APIENTRY *BlendEquation) (GLenum mode); - void (APIENTRY *DrawRangeElements) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); - void (APIENTRY *ColorTable) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); - void (APIENTRY *ColorTableParameterfv) (GLenum target, GLenum pname, const GLfloat *params); - void (APIENTRY *ColorTableParameteriv) (GLenum target, GLenum pname, const GLint *params); - void (APIENTRY *CopyColorTable) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); - void (APIENTRY *GetColorTable) (GLenum target, GLenum format, GLenum type, GLvoid *table); - void (APIENTRY *GetColorTableParameterfv) (GLenum target, GLenum pname, GLfloat *params); - void (APIENTRY *GetColorTableParameteriv) (GLenum target, GLenum pname, GLint *params); - void (APIENTRY *ColorSubTable) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); - void (APIENTRY *CopyColorSubTable) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); - void (APIENTRY *ConvolutionFilter1D) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); - void (APIENTRY *ConvolutionFilter2D) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); - void (APIENTRY *ConvolutionParameterf) (GLenum target, GLenum pname, GLfloat params); - void (APIENTRY *ConvolutionParameterfv) (GLenum target, GLenum pname, const GLfloat *params); - void (APIENTRY *ConvolutionParameteri) (GLenum target, GLenum pname, GLint params); - void (APIENTRY *ConvolutionParameteriv) (GLenum target, GLenum pname, const GLint *params); - void (APIENTRY *CopyConvolutionFilter1D) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); - void (APIENTRY *CopyConvolutionFilter2D) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); - void (APIENTRY *GetConvolutionFilter) (GLenum target, GLenum format, GLenum type, GLvoid *image); - void (APIENTRY *GetConvolutionParameterfv) (GLenum target, GLenum pname, GLfloat *params); - void (APIENTRY *GetConvolutionParameteriv) (GLenum target, GLenum pname, GLint *params); - void (APIENTRY *GetSeparableFilter) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); - void (APIENTRY *SeparableFilter2D) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); - void (APIENTRY *GetHistogram) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); - void (APIENTRY *GetHistogramParameterfv) (GLenum target, GLenum pname, GLfloat *params); - void (APIENTRY *GetHistogramParameteriv) (GLenum target, GLenum pname, GLint *params); - void (APIENTRY *GetMinmax) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); - void (APIENTRY *GetMinmaxParameterfv) (GLenum target, GLenum pname, GLfloat *params); - void (APIENTRY *GetMinmaxParameteriv) (GLenum target, GLenum pname, GLint *params); - void (APIENTRY *Histogram) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); - void (APIENTRY *Minmax) (GLenum target, GLenum internalformat, GLboolean sink); - void (APIENTRY *ResetHistogram) (GLenum target); - void (APIENTRY *ResetMinmax) (GLenum target); - void (APIENTRY *TexImage3D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - void (APIENTRY *TexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); - void (APIENTRY *CopyTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); - void (APIENTRY *ActiveTexture) (GLenum texture); - void (APIENTRY *ClientActiveTexture) (GLenum texture); - void (APIENTRY *MultiTexCoord1d) (GLenum target, GLdouble s); - void (APIENTRY *MultiTexCoord1dv) (GLenum target, const GLdouble *v); - void (APIENTRY *MultiTexCoord1f) (GLenum target, GLfloat s); - void (APIENTRY *MultiTexCoord1fv) (GLenum target, const GLfloat *v); - void (APIENTRY *MultiTexCoord1i) (GLenum target, GLint s); - void (APIENTRY *MultiTexCoord1iv) (GLenum target, const GLint *v); - void (APIENTRY *MultiTexCoord1s) (GLenum target, GLshort s); - void (APIENTRY *MultiTexCoord1sv) (GLenum target, const GLshort *v); - void (APIENTRY *MultiTexCoord2d) (GLenum target, GLdouble s, GLdouble t); - void (APIENTRY *MultiTexCoord2dv) (GLenum target, const GLdouble *v); - void (APIENTRY *MultiTexCoord2f) (GLenum target, GLfloat s, GLfloat t); - void (APIENTRY *MultiTexCoord2fv) (GLenum target, const GLfloat *v); - void (APIENTRY *MultiTexCoord2i) (GLenum target, GLint s, GLint t); - void (APIENTRY *MultiTexCoord2iv) (GLenum target, const GLint *v); - void (APIENTRY *MultiTexCoord2s) (GLenum target, GLshort s, GLshort t); - void (APIENTRY *MultiTexCoord2sv) (GLenum target, const GLshort *v); - void (APIENTRY *MultiTexCoord3d) (GLenum target, GLdouble s, GLdouble t, GLdouble r); - void (APIENTRY *MultiTexCoord3dv) (GLenum target, const GLdouble *v); - void (APIENTRY *MultiTexCoord3f) (GLenum target, GLfloat s, GLfloat t, GLfloat r); - void (APIENTRY *MultiTexCoord3fv) (GLenum target, const GLfloat *v); - void (APIENTRY *MultiTexCoord3i) (GLenum target, GLint s, GLint t, GLint r); - void (APIENTRY *MultiTexCoord3iv) (GLenum target, const GLint *v); - void (APIENTRY *MultiTexCoord3s) (GLenum target, GLshort s, GLshort t, GLshort r); - void (APIENTRY *MultiTexCoord3sv) (GLenum target, const GLshort *v); - void (APIENTRY *MultiTexCoord4d) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); - void (APIENTRY *MultiTexCoord4dv) (GLenum target, const GLdouble *v); - void (APIENTRY *MultiTexCoord4f) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); - void (APIENTRY *MultiTexCoord4fv) (GLenum target, const GLfloat *v); - void (APIENTRY *MultiTexCoord4i) (GLenum target, GLint s, GLint t, GLint r, GLint q); - void (APIENTRY *MultiTexCoord4iv) (GLenum target, const GLint *v); - void (APIENTRY *MultiTexCoord4s) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); - void (APIENTRY *MultiTexCoord4sv) (GLenum target, const GLshort *v); - void (APIENTRY *LoadTransposeMatrixf) (const GLfloat *m); - void (APIENTRY *LoadTransposeMatrixd) (const GLdouble *m); - void (APIENTRY *MultTransposeMatrixf) (const GLfloat *m); - void (APIENTRY *MultTransposeMatrixd) (const GLdouble *m); - void (APIENTRY *SampleCoverage) (GLclampf value, GLboolean invert); - void (APIENTRY *CompressedTexImage3D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); - void (APIENTRY *CompressedTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); - void (APIENTRY *CompressedTexImage1D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); - void (APIENTRY *CompressedTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); - void (APIENTRY *CompressedTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); - void (APIENTRY *CompressedTexSubImage1D) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); - void (APIENTRY *GetCompressedTexImage) (GLenum target, GLint level, GLvoid *img); - void (APIENTRY *BlendFuncSeparate) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); - void (APIENTRY *FogCoordf) (GLfloat coord); - void (APIENTRY *FogCoordfv) (const GLfloat *coord); - void (APIENTRY *FogCoordd) (GLdouble coord); - void (APIENTRY *FogCoorddv) (const GLdouble *coord); - void (APIENTRY *FogCoordPointer) (GLenum type, GLsizei stride, const GLvoid *pointer); - void (APIENTRY *MultiDrawArrays) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); - void (APIENTRY *MultiDrawElements) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); - void (APIENTRY *PointParameterf) (GLenum pname, GLfloat param); - void (APIENTRY *PointParameterfv) (GLenum pname, const GLfloat *params); - void (APIENTRY *PointParameteri) (GLenum pname, GLint param); - void (APIENTRY *PointParameteriv) (GLenum pname, const GLint *params); - void (APIENTRY *SecondaryColor3b) (GLbyte red, GLbyte green, GLbyte blue); - void (APIENTRY *SecondaryColor3bv) (const GLbyte *v); - void (APIENTRY *SecondaryColor3d) (GLdouble red, GLdouble green, GLdouble blue); - void (APIENTRY *SecondaryColor3dv) (const GLdouble *v); - void (APIENTRY *SecondaryColor3f) (GLfloat red, GLfloat green, GLfloat blue); - void (APIENTRY *SecondaryColor3fv) (const GLfloat *v); - void (APIENTRY *SecondaryColor3i) (GLint red, GLint green, GLint blue); - void (APIENTRY *SecondaryColor3iv) (const GLint *v); - void (APIENTRY *SecondaryColor3s) (GLshort red, GLshort green, GLshort blue); - void (APIENTRY *SecondaryColor3sv) (const GLshort *v); - void (APIENTRY *SecondaryColor3ub) (GLubyte red, GLubyte green, GLubyte blue); - void (APIENTRY *SecondaryColor3ubv) (const GLubyte *v); - void (APIENTRY *SecondaryColor3ui) (GLuint red, GLuint green, GLuint blue); - void (APIENTRY *SecondaryColor3uiv) (const GLuint *v); - void (APIENTRY *SecondaryColor3us) (GLushort red, GLushort green, GLushort blue); - void (APIENTRY *SecondaryColor3usv) (const GLushort *v); - void (APIENTRY *SecondaryColorPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); - void (APIENTRY *WindowPos2d) (GLdouble x, GLdouble y); - void (APIENTRY *WindowPos2dv) (const GLdouble *v); - void (APIENTRY *WindowPos2f) (GLfloat x, GLfloat y); - void (APIENTRY *WindowPos2fv) (const GLfloat *v); - void (APIENTRY *WindowPos2i) (GLint x, GLint y); - void (APIENTRY *WindowPos2iv) (const GLint *v); - void (APIENTRY *WindowPos2s) (GLshort x, GLshort y); - void (APIENTRY *WindowPos2sv) (const GLshort *v); - void (APIENTRY *WindowPos3d) (GLdouble x, GLdouble y, GLdouble z); - void (APIENTRY *WindowPos3dv) (const GLdouble *v); - void (APIENTRY *WindowPos3f) (GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *WindowPos3fv) (const GLfloat *v); - void (APIENTRY *WindowPos3i) (GLint x, GLint y, GLint z); - void (APIENTRY *WindowPos3iv) (const GLint *v); - void (APIENTRY *WindowPos3s) (GLshort x, GLshort y, GLshort z); - void (APIENTRY *WindowPos3sv) (const GLshort *v); - void (APIENTRY *GenQueries) (GLsizei n, GLuint *ids); - void (APIENTRY *DeleteQueries) (GLsizei n, const GLuint *ids); - GLboolean (APIENTRY *IsQuery) (GLuint id); - void (APIENTRY *BeginQuery) (GLenum target, GLuint id); - void (APIENTRY *EndQuery) (GLenum target); - void (APIENTRY *GetQueryiv) (GLenum target, GLenum pname, GLint *params); - void (APIENTRY *GetQueryObjectiv) (GLuint id, GLenum pname, GLint *params); - void (APIENTRY *GetQueryObjectuiv) (GLuint id, GLenum pname, GLuint *params); - void (APIENTRY *BindBuffer) (GLenum target, GLuint buffer); - void (APIENTRY *DeleteBuffers) (GLsizei n, const GLuint *buffers); - void (APIENTRY *GenBuffers) (GLsizei n, GLuint *buffers); - GLboolean (APIENTRY *IsBuffer) (GLuint buffer); - void (APIENTRY *BufferData) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); - void (APIENTRY *BufferSubData) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); - void (APIENTRY *GetBufferSubData) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); - GLvoid* (APIENTRY *MapBuffer) (GLenum target, GLenum access); - GLboolean (APIENTRY *UnmapBuffer) (GLenum target); - void (APIENTRY *GetBufferParameteriv) (GLenum target, GLenum pname, GLint *params); - void (APIENTRY *GetBufferPointerv) (GLenum target, GLenum pname, GLvoid* *params); - void (APIENTRY *ActiveTextureARB) (GLenum texture); - void (APIENTRY *ClientActiveTextureARB) (GLenum texture); - void (APIENTRY *MultiTexCoord1dARB) (GLenum target, GLdouble s); - void (APIENTRY *MultiTexCoord1dvARB) (GLenum target, const GLdouble *v); - void (APIENTRY *MultiTexCoord1fARB) (GLenum target, GLfloat s); - void (APIENTRY *MultiTexCoord1fvARB) (GLenum target, const GLfloat *v); - void (APIENTRY *MultiTexCoord1iARB) (GLenum target, GLint s); - void (APIENTRY *MultiTexCoord1ivARB) (GLenum target, const GLint *v); - void (APIENTRY *MultiTexCoord1sARB) (GLenum target, GLshort s); - void (APIENTRY *MultiTexCoord1svARB) (GLenum target, const GLshort *v); - void (APIENTRY *MultiTexCoord2dARB) (GLenum target, GLdouble s, GLdouble t); - void (APIENTRY *MultiTexCoord2dvARB) (GLenum target, const GLdouble *v); - void (APIENTRY *MultiTexCoord2fARB) (GLenum target, GLfloat s, GLfloat t); - void (APIENTRY *MultiTexCoord2fvARB) (GLenum target, const GLfloat *v); - void (APIENTRY *MultiTexCoord2iARB) (GLenum target, GLint s, GLint t); - void (APIENTRY *MultiTexCoord2ivARB) (GLenum target, const GLint *v); - void (APIENTRY *MultiTexCoord2sARB) (GLenum target, GLshort s, GLshort t); - void (APIENTRY *MultiTexCoord2svARB) (GLenum target, const GLshort *v); - void (APIENTRY *MultiTexCoord3dARB) (GLenum target, GLdouble s, GLdouble t, GLdouble r); - void (APIENTRY *MultiTexCoord3dvARB) (GLenum target, const GLdouble *v); - void (APIENTRY *MultiTexCoord3fARB) (GLenum target, GLfloat s, GLfloat t, GLfloat r); - void (APIENTRY *MultiTexCoord3fvARB) (GLenum target, const GLfloat *v); - void (APIENTRY *MultiTexCoord3iARB) (GLenum target, GLint s, GLint t, GLint r); - void (APIENTRY *MultiTexCoord3ivARB) (GLenum target, const GLint *v); - void (APIENTRY *MultiTexCoord3sARB) (GLenum target, GLshort s, GLshort t, GLshort r); - void (APIENTRY *MultiTexCoord3svARB) (GLenum target, const GLshort *v); - void (APIENTRY *MultiTexCoord4dARB) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); - void (APIENTRY *MultiTexCoord4dvARB) (GLenum target, const GLdouble *v); - void (APIENTRY *MultiTexCoord4fARB) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); - void (APIENTRY *MultiTexCoord4fvARB) (GLenum target, const GLfloat *v); - void (APIENTRY *MultiTexCoord4iARB) (GLenum target, GLint s, GLint t, GLint r, GLint q); - void (APIENTRY *MultiTexCoord4ivARB) (GLenum target, const GLint *v); - void (APIENTRY *MultiTexCoord4sARB) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); - void (APIENTRY *MultiTexCoord4svARB) (GLenum target, const GLshort *v); - void (APIENTRY *LoadTransposeMatrixfARB) (const GLfloat *m); - void (APIENTRY *LoadTransposeMatrixdARB) (const GLdouble *m); - void (APIENTRY *MultTransposeMatrixfARB) (const GLfloat *m); - void (APIENTRY *MultTransposeMatrixdARB) (const GLdouble *m); - void (APIENTRY *SampleCoverageARB) (GLclampf value, GLboolean invert); - void (APIENTRY *CompressedTexImage3DARB) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); - void (APIENTRY *CompressedTexImage2DARB) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); - void (APIENTRY *CompressedTexImage1DARB) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); - void (APIENTRY *CompressedTexSubImage3DARB) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); - void (APIENTRY *CompressedTexSubImage2DARB) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); - void (APIENTRY *CompressedTexSubImage1DARB) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); - void (APIENTRY *GetCompressedTexImageARB) (GLenum target, GLint level, GLvoid *img); - void (APIENTRY *PointParameterfARB) (GLenum pname, GLfloat param); - void (APIENTRY *PointParameterfvARB) (GLenum pname, const GLfloat *params); - void (APIENTRY *WeightbvARB) (GLint size, const GLbyte *weights); - void (APIENTRY *WeightsvARB) (GLint size, const GLshort *weights); - void (APIENTRY *WeightivARB) (GLint size, const GLint *weights); - void (APIENTRY *WeightfvARB) (GLint size, const GLfloat *weights); - void (APIENTRY *WeightdvARB) (GLint size, const GLdouble *weights); - void (APIENTRY *WeightubvARB) (GLint size, const GLubyte *weights); - void (APIENTRY *WeightusvARB) (GLint size, const GLushort *weights); - void (APIENTRY *WeightuivARB) (GLint size, const GLuint *weights); - void (APIENTRY *WeightPointerARB) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); - void (APIENTRY *VertexBlendARB) (GLint count); - void (APIENTRY *CurrentPaletteMatrixARB) (GLint index); - void (APIENTRY *MatrixIndexubvARB) (GLint size, const GLubyte *indices); - void (APIENTRY *MatrixIndexusvARB) (GLint size, const GLushort *indices); - void (APIENTRY *MatrixIndexuivARB) (GLint size, const GLuint *indices); - void (APIENTRY *MatrixIndexPointerARB) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); - void (APIENTRY *WindowPos2dARB) (GLdouble x, GLdouble y); - void (APIENTRY *WindowPos2dvARB) (const GLdouble *v); - void (APIENTRY *WindowPos2fARB) (GLfloat x, GLfloat y); - void (APIENTRY *WindowPos2fvARB) (const GLfloat *v); - void (APIENTRY *WindowPos2iARB) (GLint x, GLint y); - void (APIENTRY *WindowPos2ivARB) (const GLint *v); - void (APIENTRY *WindowPos2sARB) (GLshort x, GLshort y); - void (APIENTRY *WindowPos2svARB) (const GLshort *v); - void (APIENTRY *WindowPos3dARB) (GLdouble x, GLdouble y, GLdouble z); - void (APIENTRY *WindowPos3dvARB) (const GLdouble *v); - void (APIENTRY *WindowPos3fARB) (GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *WindowPos3fvARB) (const GLfloat *v); - void (APIENTRY *WindowPos3iARB) (GLint x, GLint y, GLint z); - void (APIENTRY *WindowPos3ivARB) (const GLint *v); - void (APIENTRY *WindowPos3sARB) (GLshort x, GLshort y, GLshort z); - void (APIENTRY *WindowPos3svARB) (const GLshort *v); - void (APIENTRY *VertexAttrib1dARB) (GLuint index, GLdouble x); - void (APIENTRY *VertexAttrib1dvARB) (GLuint index, const GLdouble *v); - void (APIENTRY *VertexAttrib1fARB) (GLuint index, GLfloat x); - void (APIENTRY *VertexAttrib1fvARB) (GLuint index, const GLfloat *v); - void (APIENTRY *VertexAttrib1sARB) (GLuint index, GLshort x); - void (APIENTRY *VertexAttrib1svARB) (GLuint index, const GLshort *v); - void (APIENTRY *VertexAttrib2dARB) (GLuint index, GLdouble x, GLdouble y); - void (APIENTRY *VertexAttrib2dvARB) (GLuint index, const GLdouble *v); - void (APIENTRY *VertexAttrib2fARB) (GLuint index, GLfloat x, GLfloat y); - void (APIENTRY *VertexAttrib2fvARB) (GLuint index, const GLfloat *v); - void (APIENTRY *VertexAttrib2sARB) (GLuint index, GLshort x, GLshort y); - void (APIENTRY *VertexAttrib2svARB) (GLuint index, const GLshort *v); - void (APIENTRY *VertexAttrib3dARB) (GLuint index, GLdouble x, GLdouble y, GLdouble z); - void (APIENTRY *VertexAttrib3dvARB) (GLuint index, const GLdouble *v); - void (APIENTRY *VertexAttrib3fARB) (GLuint index, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *VertexAttrib3fvARB) (GLuint index, const GLfloat *v); - void (APIENTRY *VertexAttrib3sARB) (GLuint index, GLshort x, GLshort y, GLshort z); - void (APIENTRY *VertexAttrib3svARB) (GLuint index, const GLshort *v); - void (APIENTRY *VertexAttrib4NbvARB) (GLuint index, const GLbyte *v); - void (APIENTRY *VertexAttrib4NivARB) (GLuint index, const GLint *v); - void (APIENTRY *VertexAttrib4NsvARB) (GLuint index, const GLshort *v); - void (APIENTRY *VertexAttrib4NubARB) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); - void (APIENTRY *VertexAttrib4NubvARB) (GLuint index, const GLubyte *v); - void (APIENTRY *VertexAttrib4NuivARB) (GLuint index, const GLuint *v); - void (APIENTRY *VertexAttrib4NusvARB) (GLuint index, const GLushort *v); - void (APIENTRY *VertexAttrib4bvARB) (GLuint index, const GLbyte *v); - void (APIENTRY *VertexAttrib4dARB) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); - void (APIENTRY *VertexAttrib4dvARB) (GLuint index, const GLdouble *v); - void (APIENTRY *VertexAttrib4fARB) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void (APIENTRY *VertexAttrib4fvARB) (GLuint index, const GLfloat *v); - void (APIENTRY *VertexAttrib4ivARB) (GLuint index, const GLint *v); - void (APIENTRY *VertexAttrib4sARB) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); - void (APIENTRY *VertexAttrib4svARB) (GLuint index, const GLshort *v); - void (APIENTRY *VertexAttrib4ubvARB) (GLuint index, const GLubyte *v); - void (APIENTRY *VertexAttrib4uivARB) (GLuint index, const GLuint *v); - void (APIENTRY *VertexAttrib4usvARB) (GLuint index, const GLushort *v); - void (APIENTRY *VertexAttribPointerARB) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); - void (APIENTRY *EnableVertexAttribArrayARB) (GLuint index); - void (APIENTRY *DisableVertexAttribArrayARB) (GLuint index); - void (APIENTRY *ProgramStringARB) (GLenum target, GLenum format, GLsizei len, const GLvoid *string); - void (APIENTRY *BindProgramARB) (GLenum target, GLuint program); - void (APIENTRY *DeleteProgramsARB) (GLsizei n, const GLuint *programs); - void (APIENTRY *GenProgramsARB) (GLsizei n, GLuint *programs); - void (APIENTRY *ProgramEnvParameter4dARB) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); - void (APIENTRY *ProgramEnvParameter4dvARB) (GLenum target, GLuint index, const GLdouble *params); - void (APIENTRY *ProgramEnvParameter4fARB) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void (APIENTRY *ProgramEnvParameter4fvARB) (GLenum target, GLuint index, const GLfloat *params); - void (APIENTRY *ProgramLocalParameter4dARB) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); - void (APIENTRY *ProgramLocalParameter4dvARB) (GLenum target, GLuint index, const GLdouble *params); - void (APIENTRY *ProgramLocalParameter4fARB) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void (APIENTRY *ProgramLocalParameter4fvARB) (GLenum target, GLuint index, const GLfloat *params); - void (APIENTRY *GetProgramEnvParameterdvARB) (GLenum target, GLuint index, GLdouble *params); - void (APIENTRY *GetProgramEnvParameterfvARB) (GLenum target, GLuint index, GLfloat *params); - void (APIENTRY *GetProgramLocalParameterdvARB) (GLenum target, GLuint index, GLdouble *params); - void (APIENTRY *GetProgramLocalParameterfvARB) (GLenum target, GLuint index, GLfloat *params); - void (APIENTRY *GetProgramivARB) (GLenum target, GLenum pname, GLint *params); - void (APIENTRY *GetProgramStringARB) (GLenum target, GLenum pname, GLvoid *string); - void (APIENTRY *GetVertexAttribdvARB) (GLuint index, GLenum pname, GLdouble *params); - void (APIENTRY *GetVertexAttribfvARB) (GLuint index, GLenum pname, GLfloat *params); - void (APIENTRY *GetVertexAttribivARB) (GLuint index, GLenum pname, GLint *params); - void (APIENTRY *GetVertexAttribPointervARB) (GLuint index, GLenum pname, GLvoid* *pointer); - GLboolean (APIENTRY *IsProgramARB) (GLuint program); - void (APIENTRY *BindBufferARB) (GLenum target, GLuint buffer); - void (APIENTRY *DeleteBuffersARB) (GLsizei n, const GLuint *buffers); - void (APIENTRY *GenBuffersARB) (GLsizei n, GLuint *buffers); - GLboolean (APIENTRY *IsBufferARB) (GLuint buffer); - void (APIENTRY *BufferDataARB) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); - void (APIENTRY *BufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); - void (APIENTRY *GetBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); - GLvoid* (APIENTRY *MapBufferARB) (GLenum target, GLenum access); - GLboolean (APIENTRY *UnmapBufferARB) (GLenum target); - void (APIENTRY *GetBufferParameterivARB) (GLenum target, GLenum pname, GLint *params); - void (APIENTRY *GetBufferPointervARB) (GLenum target, GLenum pname, GLvoid* *params); - void (APIENTRY *GenQueriesARB) (GLsizei n, GLuint *ids); - void (APIENTRY *DeleteQueriesARB) (GLsizei n, const GLuint *ids); - GLboolean (APIENTRY *IsQueryARB) (GLuint id); - void (APIENTRY *BeginQueryARB) (GLenum target, GLuint id); - void (APIENTRY *EndQueryARB) (GLenum target); - void (APIENTRY *GetQueryivARB) (GLenum target, GLenum pname, GLint *params); - void (APIENTRY *GetQueryObjectivARB) (GLuint id, GLenum pname, GLint *params); - void (APIENTRY *GetQueryObjectuivARB) (GLuint id, GLenum pname, GLuint *params); - void (APIENTRY *DeleteObjectARB) (GLhandleARB obj); - GLhandleARB (APIENTRY *GetHandleARB) (GLenum pname); - void (APIENTRY *DetachObjectARB) (GLhandleARB containerObj, GLhandleARB attachedObj); - GLhandleARB (APIENTRY *CreateShaderObjectARB) (GLenum shaderType); - void (APIENTRY *ShaderSourceARB) (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length); - void (APIENTRY *CompileShaderARB) (GLhandleARB shaderObj); - GLhandleARB (APIENTRY *CreateProgramObjectARB) (void); - void (APIENTRY *AttachObjectARB) (GLhandleARB containerObj, GLhandleARB obj); - void (APIENTRY *LinkProgramARB) (GLhandleARB programObj); - void (APIENTRY *UseProgramObjectARB) (GLhandleARB programObj); - void (APIENTRY *ValidateProgramARB) (GLhandleARB programObj); - void (APIENTRY *Uniform1fARB) (GLint location, GLfloat v0); - void (APIENTRY *Uniform2fARB) (GLint location, GLfloat v0, GLfloat v1); - void (APIENTRY *Uniform3fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); - void (APIENTRY *Uniform4fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); - void (APIENTRY *Uniform1iARB) (GLint location, GLint v0); - void (APIENTRY *Uniform2iARB) (GLint location, GLint v0, GLint v1); - void (APIENTRY *Uniform3iARB) (GLint location, GLint v0, GLint v1, GLint v2); - void (APIENTRY *Uniform4iARB) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); - void (APIENTRY *Uniform1fvARB) (GLint location, GLsizei count, const GLfloat *value); - void (APIENTRY *Uniform2fvARB) (GLint location, GLsizei count, const GLfloat *value); - void (APIENTRY *Uniform3fvARB) (GLint location, GLsizei count, const GLfloat *value); - void (APIENTRY *Uniform4fvARB) (GLint location, GLsizei count, const GLfloat *value); - void (APIENTRY *Uniform1ivARB) (GLint location, GLsizei count, const GLint *value); - void (APIENTRY *Uniform2ivARB) (GLint location, GLsizei count, const GLint *value); - void (APIENTRY *Uniform3ivARB) (GLint location, GLsizei count, const GLint *value); - void (APIENTRY *Uniform4ivARB) (GLint location, GLsizei count, const GLint *value); - void (APIENTRY *UniformMatrix2fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - void (APIENTRY *UniformMatrix3fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - void (APIENTRY *UniformMatrix4fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - void (APIENTRY *GetObjectParameterfvARB) (GLhandleARB obj, GLenum pname, GLfloat *params); - void (APIENTRY *GetObjectParameterivARB) (GLhandleARB obj, GLenum pname, GLint *params); - void (APIENTRY *GetInfoLogARB) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); - void (APIENTRY *GetAttachedObjectsARB) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); - GLint (APIENTRY *GetUniformLocationARB) (GLhandleARB programObj, const GLcharARB *name); - void (APIENTRY *GetActiveUniformARB) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); - void (APIENTRY *GetUniformfvARB) (GLhandleARB programObj, GLint location, GLfloat *params); - void (APIENTRY *GetUniformivARB) (GLhandleARB programObj, GLint location, GLint *params); - void (APIENTRY *GetShaderSourceARB) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); - void (APIENTRY *BindAttribLocationARB) (GLhandleARB programObj, GLuint index, const GLcharARB *name); - void (APIENTRY *GetActiveAttribARB) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); - GLint (APIENTRY *GetAttribLocationARB) (GLhandleARB programObj, const GLcharARB *name); - void (APIENTRY *BlendColorEXT) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); - void (APIENTRY *PolygonOffsetEXT) (GLfloat factor, GLfloat bias); - void (APIENTRY *TexImage3DEXT) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - void (APIENTRY *TexSubImage3DEXT) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); - void (APIENTRY *GetTexFilterFuncSGIS) (GLenum target, GLenum filter, GLfloat *weights); - void (APIENTRY *TexFilterFuncSGIS) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); - void (APIENTRY *TexSubImage1DEXT) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); - void (APIENTRY *TexSubImage2DEXT) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); - void (APIENTRY *CopyTexImage1DEXT) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); - void (APIENTRY *CopyTexImage2DEXT) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); - void (APIENTRY *CopyTexSubImage1DEXT) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); - void (APIENTRY *CopyTexSubImage2DEXT) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); - void (APIENTRY *CopyTexSubImage3DEXT) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); - void (APIENTRY *GetHistogramEXT) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); - void (APIENTRY *GetHistogramParameterfvEXT) (GLenum target, GLenum pname, GLfloat *params); - void (APIENTRY *GetHistogramParameterivEXT) (GLenum target, GLenum pname, GLint *params); - void (APIENTRY *GetMinmaxEXT) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); - void (APIENTRY *GetMinmaxParameterfvEXT) (GLenum target, GLenum pname, GLfloat *params); - void (APIENTRY *GetMinmaxParameterivEXT) (GLenum target, GLenum pname, GLint *params); - void (APIENTRY *HistogramEXT) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); - void (APIENTRY *MinmaxEXT) (GLenum target, GLenum internalformat, GLboolean sink); - void (APIENTRY *ResetHistogramEXT) (GLenum target); - void (APIENTRY *ResetMinmaxEXT) (GLenum target); - void (APIENTRY *ConvolutionFilter1DEXT) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); - void (APIENTRY *ConvolutionFilter2DEXT) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); - void (APIENTRY *ConvolutionParameterfEXT) (GLenum target, GLenum pname, GLfloat params); - void (APIENTRY *ConvolutionParameterfvEXT) (GLenum target, GLenum pname, const GLfloat *params); - void (APIENTRY *ConvolutionParameteriEXT) (GLenum target, GLenum pname, GLint params); - void (APIENTRY *ConvolutionParameterivEXT) (GLenum target, GLenum pname, const GLint *params); - void (APIENTRY *CopyConvolutionFilter1DEXT) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); - void (APIENTRY *CopyConvolutionFilter2DEXT) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); - void (APIENTRY *GetConvolutionFilterEXT) (GLenum target, GLenum format, GLenum type, GLvoid *image); - void (APIENTRY *GetConvolutionParameterfvEXT) (GLenum target, GLenum pname, GLfloat *params); - void (APIENTRY *GetConvolutionParameterivEXT) (GLenum target, GLenum pname, GLint *params); - void (APIENTRY *GetSeparableFilterEXT) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); - void (APIENTRY *SeparableFilter2DEXT) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); - void (APIENTRY *ColorTableSGI) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); - void (APIENTRY *ColorTableParameterfvSGI) (GLenum target, GLenum pname, const GLfloat *params); - void (APIENTRY *ColorTableParameterivSGI) (GLenum target, GLenum pname, const GLint *params); - void (APIENTRY *CopyColorTableSGI) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); - void (APIENTRY *GetColorTableSGI) (GLenum target, GLenum format, GLenum type, GLvoid *table); - void (APIENTRY *GetColorTableParameterfvSGI) (GLenum target, GLenum pname, GLfloat *params); - void (APIENTRY *GetColorTableParameterivSGI) (GLenum target, GLenum pname, GLint *params); - void (APIENTRY *PixelTexGenSGIX) (GLenum mode); - void (APIENTRY *PixelTexGenParameteriSGIS) (GLenum pname, GLint param); - void (APIENTRY *PixelTexGenParameterivSGIS) (GLenum pname, const GLint *params); - void (APIENTRY *PixelTexGenParameterfSGIS) (GLenum pname, GLfloat param); - void (APIENTRY *PixelTexGenParameterfvSGIS) (GLenum pname, const GLfloat *params); - void (APIENTRY *GetPixelTexGenParameterivSGIS) (GLenum pname, GLint *params); - void (APIENTRY *GetPixelTexGenParameterfvSGIS) (GLenum pname, GLfloat *params); - void (APIENTRY *TexImage4DSGIS) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - void (APIENTRY *TexSubImage4DSGIS) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels); - GLboolean (APIENTRY *AreTexturesResidentEXT) (GLsizei n, const GLuint *textures, GLboolean *residences); - void (APIENTRY *BindTextureEXT) (GLenum target, GLuint texture); - void (APIENTRY *DeleteTexturesEXT) (GLsizei n, const GLuint *textures); - void (APIENTRY *GenTexturesEXT) (GLsizei n, GLuint *textures); - GLboolean (APIENTRY *IsTextureEXT) (GLuint texture); - void (APIENTRY *PrioritizeTexturesEXT) (GLsizei n, const GLuint *textures, const GLclampf *priorities); - void (APIENTRY *DetailTexFuncSGIS) (GLenum target, GLsizei n, const GLfloat *points); - void (APIENTRY *GetDetailTexFuncSGIS) (GLenum target, GLfloat *points); - void (APIENTRY *SharpenTexFuncSGIS) (GLenum target, GLsizei n, const GLfloat *points); - void (APIENTRY *GetSharpenTexFuncSGIS) (GLenum target, GLfloat *points); - void (APIENTRY *SampleMaskSGIS) (GLclampf value, GLboolean invert); - void (APIENTRY *SamplePatternSGIS) (GLenum pattern); - void (APIENTRY *ArrayElementEXT) (GLint i); - void (APIENTRY *ColorPointerEXT) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); - void (APIENTRY *DrawArraysEXT) (GLenum mode, GLint first, GLsizei count); - void (APIENTRY *EdgeFlagPointerEXT) (GLsizei stride, GLsizei count, const GLboolean *pointer); - void (APIENTRY *GetPointervEXT) (GLenum pname, GLvoid* *params); - void (APIENTRY *IndexPointerEXT) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); - void (APIENTRY *NormalPointerEXT) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); - void (APIENTRY *TexCoordPointerEXT) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); - void (APIENTRY *VertexPointerEXT) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); - void (APIENTRY *BlendEquationEXT) (GLenum mode); - void (APIENTRY *SpriteParameterfSGIX) (GLenum pname, GLfloat param); - void (APIENTRY *SpriteParameterfvSGIX) (GLenum pname, const GLfloat *params); - void (APIENTRY *SpriteParameteriSGIX) (GLenum pname, GLint param); - void (APIENTRY *SpriteParameterivSGIX) (GLenum pname, const GLint *params); - void (APIENTRY *PointParameterfEXT) (GLenum pname, GLfloat param); - void (APIENTRY *PointParameterfvEXT) (GLenum pname, const GLfloat *params); - void (APIENTRY *PointParameterfSGIS) (GLenum pname, GLfloat param); - void (APIENTRY *PointParameterfvSGIS) (GLenum pname, const GLfloat *params); - GLint (APIENTRY *GetInstrumentsSGIX) (void); - void (APIENTRY *InstrumentsBufferSGIX) (GLsizei size, GLint *buffer); - GLint (APIENTRY *PollInstrumentsSGIX) (GLint *marker_p); - void (APIENTRY *ReadInstrumentsSGIX) (GLint marker); - void (APIENTRY *StartInstrumentsSGIX) (void); - void (APIENTRY *StopInstrumentsSGIX) (GLint marker); - void (APIENTRY *FrameZoomSGIX) (GLint factor); - void (APIENTRY *TagSampleBufferSGIX) (void); - void (APIENTRY *DeformationMap3dSGIX) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); - void (APIENTRY *DeformationMap3fSGIX) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); - void (APIENTRY *DeformSGIX) (GLbitfield mask); - void (APIENTRY *LoadIdentityDeformationMapSGIX) (GLbitfield mask); - void (APIENTRY *ReferencePlaneSGIX) (const GLdouble *equation); - void (APIENTRY *FlushRasterSGIX) (void); - void (APIENTRY *FogFuncSGIS) (GLsizei n, const GLfloat *points); - void (APIENTRY *GetFogFuncSGIS) (GLfloat *points); - void (APIENTRY *ImageTransformParameteriHP) (GLenum target, GLenum pname, GLint param); - void (APIENTRY *ImageTransformParameterfHP) (GLenum target, GLenum pname, GLfloat param); - void (APIENTRY *ImageTransformParameterivHP) (GLenum target, GLenum pname, const GLint *params); - void (APIENTRY *ImageTransformParameterfvHP) (GLenum target, GLenum pname, const GLfloat *params); - void (APIENTRY *GetImageTransformParameterivHP) (GLenum target, GLenum pname, GLint *params); - void (APIENTRY *GetImageTransformParameterfvHP) (GLenum target, GLenum pname, GLfloat *params); - void (APIENTRY *ColorSubTableEXT) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); - void (APIENTRY *CopyColorSubTableEXT) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); - void (APIENTRY *HintPGI) (GLenum target, GLint mode); - void (APIENTRY *ColorTableEXT) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); - void (APIENTRY *GetColorTableEXT) (GLenum target, GLenum format, GLenum type, GLvoid *data); - void (APIENTRY *GetColorTableParameterivEXT) (GLenum target, GLenum pname, GLint *params); - void (APIENTRY *GetColorTableParameterfvEXT) (GLenum target, GLenum pname, GLfloat *params); - void (APIENTRY *GetListParameterfvSGIX) (GLuint list, GLenum pname, GLfloat *params); - void (APIENTRY *GetListParameterivSGIX) (GLuint list, GLenum pname, GLint *params); - void (APIENTRY *ListParameterfSGIX) (GLuint list, GLenum pname, GLfloat param); - void (APIENTRY *ListParameterfvSGIX) (GLuint list, GLenum pname, const GLfloat *params); - void (APIENTRY *ListParameteriSGIX) (GLuint list, GLenum pname, GLint param); - void (APIENTRY *ListParameterivSGIX) (GLuint list, GLenum pname, const GLint *params); - void (APIENTRY *IndexMaterialEXT) (GLenum face, GLenum mode); - void (APIENTRY *IndexFuncEXT) (GLenum func, GLclampf ref); - void (APIENTRY *LockArraysEXT) (GLint first, GLsizei count); - void (APIENTRY *UnlockArraysEXT) (void); - void (APIENTRY *CullParameterdvEXT) (GLenum pname, GLdouble *params); - void (APIENTRY *CullParameterfvEXT) (GLenum pname, GLfloat *params); - void (APIENTRY *FragmentColorMaterialSGIX) (GLenum face, GLenum mode); - void (APIENTRY *FragmentLightfSGIX) (GLenum light, GLenum pname, GLfloat param); - void (APIENTRY *FragmentLightfvSGIX) (GLenum light, GLenum pname, const GLfloat *params); - void (APIENTRY *FragmentLightiSGIX) (GLenum light, GLenum pname, GLint param); - void (APIENTRY *FragmentLightivSGIX) (GLenum light, GLenum pname, const GLint *params); - void (APIENTRY *FragmentLightModelfSGIX) (GLenum pname, GLfloat param); - void (APIENTRY *FragmentLightModelfvSGIX) (GLenum pname, const GLfloat *params); - void (APIENTRY *FragmentLightModeliSGIX) (GLenum pname, GLint param); - void (APIENTRY *FragmentLightModelivSGIX) (GLenum pname, const GLint *params); - void (APIENTRY *FragmentMaterialfSGIX) (GLenum face, GLenum pname, GLfloat param); - void (APIENTRY *FragmentMaterialfvSGIX) (GLenum face, GLenum pname, const GLfloat *params); - void (APIENTRY *FragmentMaterialiSGIX) (GLenum face, GLenum pname, GLint param); - void (APIENTRY *FragmentMaterialivSGIX) (GLenum face, GLenum pname, const GLint *params); - void (APIENTRY *GetFragmentLightfvSGIX) (GLenum light, GLenum pname, GLfloat *params); - void (APIENTRY *GetFragmentLightivSGIX) (GLenum light, GLenum pname, GLint *params); - void (APIENTRY *GetFragmentMaterialfvSGIX) (GLenum face, GLenum pname, GLfloat *params); - void (APIENTRY *GetFragmentMaterialivSGIX) (GLenum face, GLenum pname, GLint *params); - void (APIENTRY *LightEnviSGIX) (GLenum pname, GLint param); - void (APIENTRY *DrawRangeElementsEXT) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); - void (APIENTRY *ApplyTextureEXT) (GLenum mode); - void (APIENTRY *TextureLightEXT) (GLenum pname); - void (APIENTRY *TextureMaterialEXT) (GLenum face, GLenum mode); - void (APIENTRY *AsyncMarkerSGIX) (GLuint marker); - GLint (APIENTRY *FinishAsyncSGIX) (GLuint *markerp); - GLint (APIENTRY *PollAsyncSGIX) (GLuint *markerp); - GLuint (APIENTRY *GenAsyncMarkersSGIX) (GLsizei range); - void (APIENTRY *DeleteAsyncMarkersSGIX) (GLuint marker, GLsizei range); - GLboolean (APIENTRY *IsAsyncMarkerSGIX) (GLuint marker); - void (APIENTRY *VertexPointervINTEL) (GLint size, GLenum type, const GLvoid* *pointer); - void (APIENTRY *NormalPointervINTEL) (GLenum type, const GLvoid* *pointer); - void (APIENTRY *ColorPointervINTEL) (GLint size, GLenum type, const GLvoid* *pointer); - void (APIENTRY *TexCoordPointervINTEL) (GLint size, GLenum type, const GLvoid* *pointer); - void (APIENTRY *PixelTransformParameteriEXT) (GLenum target, GLenum pname, GLint param); - void (APIENTRY *PixelTransformParameterfEXT) (GLenum target, GLenum pname, GLfloat param); - void (APIENTRY *PixelTransformParameterivEXT) (GLenum target, GLenum pname, const GLint *params); - void (APIENTRY *PixelTransformParameterfvEXT) (GLenum target, GLenum pname, const GLfloat *params); - void (APIENTRY *SecondaryColor3bEXT) (GLbyte red, GLbyte green, GLbyte blue); - void (APIENTRY *SecondaryColor3bvEXT) (const GLbyte *v); - void (APIENTRY *SecondaryColor3dEXT) (GLdouble red, GLdouble green, GLdouble blue); - void (APIENTRY *SecondaryColor3dvEXT) (const GLdouble *v); - void (APIENTRY *SecondaryColor3fEXT) (GLfloat red, GLfloat green, GLfloat blue); - void (APIENTRY *SecondaryColor3fvEXT) (const GLfloat *v); - void (APIENTRY *SecondaryColor3iEXT) (GLint red, GLint green, GLint blue); - void (APIENTRY *SecondaryColor3ivEXT) (const GLint *v); - void (APIENTRY *SecondaryColor3sEXT) (GLshort red, GLshort green, GLshort blue); - void (APIENTRY *SecondaryColor3svEXT) (const GLshort *v); - void (APIENTRY *SecondaryColor3ubEXT) (GLubyte red, GLubyte green, GLubyte blue); - void (APIENTRY *SecondaryColor3ubvEXT) (const GLubyte *v); - void (APIENTRY *SecondaryColor3uiEXT) (GLuint red, GLuint green, GLuint blue); - void (APIENTRY *SecondaryColor3uivEXT) (const GLuint *v); - void (APIENTRY *SecondaryColor3usEXT) (GLushort red, GLushort green, GLushort blue); - void (APIENTRY *SecondaryColor3usvEXT) (const GLushort *v); - void (APIENTRY *SecondaryColorPointerEXT) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); - void (APIENTRY *TextureNormalEXT) (GLenum mode); - void (APIENTRY *MultiDrawArraysEXT) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); - void (APIENTRY *MultiDrawElementsEXT) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); - void (APIENTRY *FogCoordfEXT) (GLfloat coord); - void (APIENTRY *FogCoordfvEXT) (const GLfloat *coord); - void (APIENTRY *FogCoorddEXT) (GLdouble coord); - void (APIENTRY *FogCoorddvEXT) (const GLdouble *coord); - void (APIENTRY *FogCoordPointerEXT) (GLenum type, GLsizei stride, const GLvoid *pointer); - void (APIENTRY *Tangent3bEXT) (GLbyte tx, GLbyte ty, GLbyte tz); - void (APIENTRY *Tangent3bvEXT) (const GLbyte *v); - void (APIENTRY *Tangent3dEXT) (GLdouble tx, GLdouble ty, GLdouble tz); - void (APIENTRY *Tangent3dvEXT) (const GLdouble *v); - void (APIENTRY *Tangent3fEXT) (GLfloat tx, GLfloat ty, GLfloat tz); - void (APIENTRY *Tangent3fvEXT) (const GLfloat *v); - void (APIENTRY *Tangent3iEXT) (GLint tx, GLint ty, GLint tz); - void (APIENTRY *Tangent3ivEXT) (const GLint *v); - void (APIENTRY *Tangent3sEXT) (GLshort tx, GLshort ty, GLshort tz); - void (APIENTRY *Tangent3svEXT) (const GLshort *v); - void (APIENTRY *Binormal3bEXT) (GLbyte bx, GLbyte by, GLbyte bz); - void (APIENTRY *Binormal3bvEXT) (const GLbyte *v); - void (APIENTRY *Binormal3dEXT) (GLdouble bx, GLdouble by, GLdouble bz); - void (APIENTRY *Binormal3dvEXT) (const GLdouble *v); - void (APIENTRY *Binormal3fEXT) (GLfloat bx, GLfloat by, GLfloat bz); - void (APIENTRY *Binormal3fvEXT) (const GLfloat *v); - void (APIENTRY *Binormal3iEXT) (GLint bx, GLint by, GLint bz); - void (APIENTRY *Binormal3ivEXT) (const GLint *v); - void (APIENTRY *Binormal3sEXT) (GLshort bx, GLshort by, GLshort bz); - void (APIENTRY *Binormal3svEXT) (const GLshort *v); - void (APIENTRY *TangentPointerEXT) (GLenum type, GLsizei stride, const GLvoid *pointer); - void (APIENTRY *BinormalPointerEXT) (GLenum type, GLsizei stride, const GLvoid *pointer); - void (APIENTRY *FinishTextureSUNX) (void); - void (APIENTRY *GlobalAlphaFactorbSUN) (GLbyte factor); - void (APIENTRY *GlobalAlphaFactorsSUN) (GLshort factor); - void (APIENTRY *GlobalAlphaFactoriSUN) (GLint factor); - void (APIENTRY *GlobalAlphaFactorfSUN) (GLfloat factor); - void (APIENTRY *GlobalAlphaFactordSUN) (GLdouble factor); - void (APIENTRY *GlobalAlphaFactorubSUN) (GLubyte factor); - void (APIENTRY *GlobalAlphaFactorusSUN) (GLushort factor); - void (APIENTRY *GlobalAlphaFactoruiSUN) (GLuint factor); - void (APIENTRY *ReplacementCodeuiSUN) (GLuint code); - void (APIENTRY *ReplacementCodeusSUN) (GLushort code); - void (APIENTRY *ReplacementCodeubSUN) (GLubyte code); - void (APIENTRY *ReplacementCodeuivSUN) (const GLuint *code); - void (APIENTRY *ReplacementCodeusvSUN) (const GLushort *code); - void (APIENTRY *ReplacementCodeubvSUN) (const GLubyte *code); - void (APIENTRY *ReplacementCodePointerSUN) (GLenum type, GLsizei stride, const GLvoid* *pointer); - void (APIENTRY *Color4ubVertex2fSUN) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); - void (APIENTRY *Color4ubVertex2fvSUN) (const GLubyte *c, const GLfloat *v); - void (APIENTRY *Color4ubVertex3fSUN) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *Color4ubVertex3fvSUN) (const GLubyte *c, const GLfloat *v); - void (APIENTRY *Color3fVertex3fSUN) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *Color3fVertex3fvSUN) (const GLfloat *c, const GLfloat *v); - void (APIENTRY *Normal3fVertex3fSUN) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *Normal3fVertex3fvSUN) (const GLfloat *n, const GLfloat *v); - void (APIENTRY *Color4fNormal3fVertex3fSUN) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *Color4fNormal3fVertex3fvSUN) (const GLfloat *c, const GLfloat *n, const GLfloat *v); - void (APIENTRY *TexCoord2fVertex3fSUN) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *TexCoord2fVertex3fvSUN) (const GLfloat *tc, const GLfloat *v); - void (APIENTRY *TexCoord4fVertex4fSUN) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void (APIENTRY *TexCoord4fVertex4fvSUN) (const GLfloat *tc, const GLfloat *v); - void (APIENTRY *TexCoord2fColor4ubVertex3fSUN) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *TexCoord2fColor4ubVertex3fvSUN) (const GLfloat *tc, const GLubyte *c, const GLfloat *v); - void (APIENTRY *TexCoord2fColor3fVertex3fSUN) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *TexCoord2fColor3fVertex3fvSUN) (const GLfloat *tc, const GLfloat *c, const GLfloat *v); - void (APIENTRY *TexCoord2fNormal3fVertex3fSUN) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *TexCoord2fNormal3fVertex3fvSUN) (const GLfloat *tc, const GLfloat *n, const GLfloat *v); - void (APIENTRY *TexCoord2fColor4fNormal3fVertex3fSUN) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *TexCoord2fColor4fNormal3fVertex3fvSUN) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); - void (APIENTRY *TexCoord4fColor4fNormal3fVertex4fSUN) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void (APIENTRY *TexCoord4fColor4fNormal3fVertex4fvSUN) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); - void (APIENTRY *ReplacementCodeuiVertex3fSUN) (GLuint rc, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *ReplacementCodeuiVertex3fvSUN) (const GLuint *rc, const GLfloat *v); - void (APIENTRY *ReplacementCodeuiColor4ubVertex3fSUN) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *ReplacementCodeuiColor4ubVertex3fvSUN) (const GLuint *rc, const GLubyte *c, const GLfloat *v); - void (APIENTRY *ReplacementCodeuiColor3fVertex3fSUN) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *ReplacementCodeuiColor3fVertex3fvSUN) (const GLuint *rc, const GLfloat *c, const GLfloat *v); - void (APIENTRY *ReplacementCodeuiNormal3fVertex3fSUN) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *ReplacementCodeuiNormal3fVertex3fvSUN) (const GLuint *rc, const GLfloat *n, const GLfloat *v); - void (APIENTRY *ReplacementCodeuiColor4fNormal3fVertex3fSUN) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *ReplacementCodeuiColor4fNormal3fVertex3fvSUN) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); - void (APIENTRY *ReplacementCodeuiTexCoord2fVertex3fSUN) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *ReplacementCodeuiTexCoord2fVertex3fvSUN) (const GLuint *rc, const GLfloat *tc, const GLfloat *v); - void (APIENTRY *ReplacementCodeuiTexCoord2fNormal3fVertex3fSUN) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *ReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); - void (APIENTRY *ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); - void (APIENTRY *BlendFuncSeparateEXT) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); - void (APIENTRY *BlendFuncSeparateINGR) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); - void (APIENTRY *VertexWeightfEXT) (GLfloat weight); - void (APIENTRY *VertexWeightfvEXT) (const GLfloat *weight); - void (APIENTRY *VertexWeightPointerEXT) (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer); - void (APIENTRY *FlushVertexArrayRangeNV) (void); - void (APIENTRY *VertexArrayRangeNV) (GLsizei length, const GLvoid *pointer); - void (APIENTRY *CombinerParameterfvNV) (GLenum pname, const GLfloat *params); - void (APIENTRY *CombinerParameterfNV) (GLenum pname, GLfloat param); - void (APIENTRY *CombinerParameterivNV) (GLenum pname, const GLint *params); - void (APIENTRY *CombinerParameteriNV) (GLenum pname, GLint param); - void (APIENTRY *CombinerInputNV) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); - void (APIENTRY *CombinerOutputNV) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); - void (APIENTRY *FinalCombinerInputNV) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); - void (APIENTRY *GetCombinerInputParameterfvNV) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); - void (APIENTRY *GetCombinerInputParameterivNV) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); - void (APIENTRY *GetCombinerOutputParameterfvNV) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); - void (APIENTRY *GetCombinerOutputParameterivNV) (GLenum stage, GLenum portion, GLenum pname, GLint *params); - void (APIENTRY *GetFinalCombinerInputParameterfvNV) (GLenum variable, GLenum pname, GLfloat *params); - void (APIENTRY *GetFinalCombinerInputParameterivNV) (GLenum variable, GLenum pname, GLint *params); - void (APIENTRY *ResizeBuffersMESA) (void); - void (APIENTRY *WindowPos2dMESA) (GLdouble x, GLdouble y); - void (APIENTRY *WindowPos2dvMESA) (const GLdouble *v); - void (APIENTRY *WindowPos2fMESA) (GLfloat x, GLfloat y); - void (APIENTRY *WindowPos2fvMESA) (const GLfloat *v); - void (APIENTRY *WindowPos2iMESA) (GLint x, GLint y); - void (APIENTRY *WindowPos2ivMESA) (const GLint *v); - void (APIENTRY *WindowPos2sMESA) (GLshort x, GLshort y); - void (APIENTRY *WindowPos2svMESA) (const GLshort *v); - void (APIENTRY *WindowPos3dMESA) (GLdouble x, GLdouble y, GLdouble z); - void (APIENTRY *WindowPos3dvMESA) (const GLdouble *v); - void (APIENTRY *WindowPos3fMESA) (GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *WindowPos3fvMESA) (const GLfloat *v); - void (APIENTRY *WindowPos3iMESA) (GLint x, GLint y, GLint z); - void (APIENTRY *WindowPos3ivMESA) (const GLint *v); - void (APIENTRY *WindowPos3sMESA) (GLshort x, GLshort y, GLshort z); - void (APIENTRY *WindowPos3svMESA) (const GLshort *v); - void (APIENTRY *WindowPos4dMESA) (GLdouble x, GLdouble y, GLdouble z, GLdouble w); - void (APIENTRY *WindowPos4dvMESA) (const GLdouble *v); - void (APIENTRY *WindowPos4fMESA) (GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void (APIENTRY *WindowPos4fvMESA) (const GLfloat *v); - void (APIENTRY *WindowPos4iMESA) (GLint x, GLint y, GLint z, GLint w); - void (APIENTRY *WindowPos4ivMESA) (const GLint *v); - void (APIENTRY *WindowPos4sMESA) (GLshort x, GLshort y, GLshort z, GLshort w); - void (APIENTRY *WindowPos4svMESA) (const GLshort *v); - void (APIENTRY *MultiModeDrawArraysIBM) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); - void (APIENTRY *MultiModeDrawElementsIBM) (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride); - void (APIENTRY *ColorPointerListIBM) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); - void (APIENTRY *SecondaryColorPointerListIBM) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); - void (APIENTRY *EdgeFlagPointerListIBM) (GLint stride, const GLboolean* *pointer, GLint ptrstride); - void (APIENTRY *FogCoordPointerListIBM) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); - void (APIENTRY *IndexPointerListIBM) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); - void (APIENTRY *NormalPointerListIBM) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); - void (APIENTRY *TexCoordPointerListIBM) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); - void (APIENTRY *VertexPointerListIBM) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); - void (APIENTRY *TbufferMask3DFX) (GLuint mask); - void (APIENTRY *SampleMaskEXT) (GLclampf value, GLboolean invert); - void (APIENTRY *SamplePatternEXT) (GLenum pattern); - void (APIENTRY *TextureColorMaskSGIS) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); - void (APIENTRY *IglooInterfaceSGIX) (GLenum pname, const GLvoid *params); - void (APIENTRY *DeleteFencesNV) (GLsizei n, const GLuint *fences); - void (APIENTRY *GenFencesNV) (GLsizei n, GLuint *fences); - GLboolean (APIENTRY *IsFenceNV) (GLuint fence); - GLboolean (APIENTRY *TestFenceNV) (GLuint fence); - void (APIENTRY *GetFenceivNV) (GLuint fence, GLenum pname, GLint *params); - void (APIENTRY *FinishFenceNV) (GLuint fence); - void (APIENTRY *SetFenceNV) (GLuint fence, GLenum condition); - void (APIENTRY *MapControlPointsNV) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points); - void (APIENTRY *MapParameterivNV) (GLenum target, GLenum pname, const GLint *params); - void (APIENTRY *MapParameterfvNV) (GLenum target, GLenum pname, const GLfloat *params); - void (APIENTRY *GetMapControlPointsNV) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points); - void (APIENTRY *GetMapParameterivNV) (GLenum target, GLenum pname, GLint *params); - void (APIENTRY *GetMapParameterfvNV) (GLenum target, GLenum pname, GLfloat *params); - void (APIENTRY *GetMapAttribParameterivNV) (GLenum target, GLuint index, GLenum pname, GLint *params); - void (APIENTRY *GetMapAttribParameterfvNV) (GLenum target, GLuint index, GLenum pname, GLfloat *params); - void (APIENTRY *EvalMapsNV) (GLenum target, GLenum mode); - void (APIENTRY *CombinerStageParameterfvNV) (GLenum stage, GLenum pname, const GLfloat *params); - void (APIENTRY *GetCombinerStageParameterfvNV) (GLenum stage, GLenum pname, GLfloat *params); - GLboolean (APIENTRY *AreProgramsResidentNV) (GLsizei n, const GLuint *programs, GLboolean *residences); - void (APIENTRY *BindProgramNV) (GLenum target, GLuint id); - void (APIENTRY *DeleteProgramsNV) (GLsizei n, const GLuint *programs); - void (APIENTRY *ExecuteProgramNV) (GLenum target, GLuint id, const GLfloat *params); - void (APIENTRY *GenProgramsNV) (GLsizei n, GLuint *programs); - void (APIENTRY *GetProgramParameterdvNV) (GLenum target, GLuint index, GLenum pname, GLdouble *params); - void (APIENTRY *GetProgramParameterfvNV) (GLenum target, GLuint index, GLenum pname, GLfloat *params); - void (APIENTRY *GetProgramivNV) (GLuint id, GLenum pname, GLint *params); - void (APIENTRY *GetProgramStringNV) (GLuint id, GLenum pname, GLubyte *program); - void (APIENTRY *GetTrackMatrixivNV) (GLenum target, GLuint address, GLenum pname, GLint *params); - void (APIENTRY *GetVertexAttribdvNV) (GLuint index, GLenum pname, GLdouble *params); - void (APIENTRY *GetVertexAttribfvNV) (GLuint index, GLenum pname, GLfloat *params); - void (APIENTRY *GetVertexAttribivNV) (GLuint index, GLenum pname, GLint *params); - void (APIENTRY *GetVertexAttribPointervNV) (GLuint index, GLenum pname, GLvoid* *pointer); - GLboolean (APIENTRY *IsProgramNV) (GLuint id); - void (APIENTRY *LoadProgramNV) (GLenum target, GLuint id, GLsizei len, const GLubyte *program); - void (APIENTRY *ProgramParameter4dNV) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); - void (APIENTRY *ProgramParameter4dvNV) (GLenum target, GLuint index, const GLdouble *v); - void (APIENTRY *ProgramParameter4fNV) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void (APIENTRY *ProgramParameter4fvNV) (GLenum target, GLuint index, const GLfloat *v); - void (APIENTRY *ProgramParameters4dvNV) (GLenum target, GLuint index, GLuint count, const GLdouble *v); - void (APIENTRY *ProgramParameters4fvNV) (GLenum target, GLuint index, GLuint count, const GLfloat *v); - void (APIENTRY *RequestResidentProgramsNV) (GLsizei n, const GLuint *programs); - void (APIENTRY *TrackMatrixNV) (GLenum target, GLuint address, GLenum matrix, GLenum transform); - void (APIENTRY *VertexAttribPointerNV) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer); - void (APIENTRY *VertexAttrib1dNV) (GLuint index, GLdouble x); - void (APIENTRY *VertexAttrib1dvNV) (GLuint index, const GLdouble *v); - void (APIENTRY *VertexAttrib1fNV) (GLuint index, GLfloat x); - void (APIENTRY *VertexAttrib1fvNV) (GLuint index, const GLfloat *v); - void (APIENTRY *VertexAttrib1sNV) (GLuint index, GLshort x); - void (APIENTRY *VertexAttrib1svNV) (GLuint index, const GLshort *v); - void (APIENTRY *VertexAttrib2dNV) (GLuint index, GLdouble x, GLdouble y); - void (APIENTRY *VertexAttrib2dvNV) (GLuint index, const GLdouble *v); - void (APIENTRY *VertexAttrib2fNV) (GLuint index, GLfloat x, GLfloat y); - void (APIENTRY *VertexAttrib2fvNV) (GLuint index, const GLfloat *v); - void (APIENTRY *VertexAttrib2sNV) (GLuint index, GLshort x, GLshort y); - void (APIENTRY *VertexAttrib2svNV) (GLuint index, const GLshort *v); - void (APIENTRY *VertexAttrib3dNV) (GLuint index, GLdouble x, GLdouble y, GLdouble z); - void (APIENTRY *VertexAttrib3dvNV) (GLuint index, const GLdouble *v); - void (APIENTRY *VertexAttrib3fNV) (GLuint index, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *VertexAttrib3fvNV) (GLuint index, const GLfloat *v); - void (APIENTRY *VertexAttrib3sNV) (GLuint index, GLshort x, GLshort y, GLshort z); - void (APIENTRY *VertexAttrib3svNV) (GLuint index, const GLshort *v); - void (APIENTRY *VertexAttrib4dNV) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); - void (APIENTRY *VertexAttrib4dvNV) (GLuint index, const GLdouble *v); - void (APIENTRY *VertexAttrib4fNV) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void (APIENTRY *VertexAttrib4fvNV) (GLuint index, const GLfloat *v); - void (APIENTRY *VertexAttrib4sNV) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); - void (APIENTRY *VertexAttrib4svNV) (GLuint index, const GLshort *v); - void (APIENTRY *VertexAttrib4ubNV) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); - void (APIENTRY *VertexAttrib4ubvNV) (GLuint index, const GLubyte *v); - void (APIENTRY *VertexAttribs1dvNV) (GLuint index, GLsizei count, const GLdouble *v); - void (APIENTRY *VertexAttribs1fvNV) (GLuint index, GLsizei count, const GLfloat *v); - void (APIENTRY *VertexAttribs1svNV) (GLuint index, GLsizei count, const GLshort *v); - void (APIENTRY *VertexAttribs2dvNV) (GLuint index, GLsizei count, const GLdouble *v); - void (APIENTRY *VertexAttribs2fvNV) (GLuint index, GLsizei count, const GLfloat *v); - void (APIENTRY *VertexAttribs2svNV) (GLuint index, GLsizei count, const GLshort *v); - void (APIENTRY *VertexAttribs3dvNV) (GLuint index, GLsizei count, const GLdouble *v); - void (APIENTRY *VertexAttribs3fvNV) (GLuint index, GLsizei count, const GLfloat *v); - void (APIENTRY *VertexAttribs3svNV) (GLuint index, GLsizei count, const GLshort *v); - void (APIENTRY *VertexAttribs4dvNV) (GLuint index, GLsizei count, const GLdouble *v); - void (APIENTRY *VertexAttribs4fvNV) (GLuint index, GLsizei count, const GLfloat *v); - void (APIENTRY *VertexAttribs4svNV) (GLuint index, GLsizei count, const GLshort *v); - void (APIENTRY *VertexAttribs4ubvNV) (GLuint index, GLsizei count, const GLubyte *v); - void (APIENTRY *TexBumpParameterivATI) (GLenum pname, const GLint *param); - void (APIENTRY *TexBumpParameterfvATI) (GLenum pname, const GLfloat *param); - void (APIENTRY *GetTexBumpParameterivATI) (GLenum pname, GLint *param); - void (APIENTRY *GetTexBumpParameterfvATI) (GLenum pname, GLfloat *param); - GLuint (APIENTRY *GenFragmentShadersATI) (GLuint range); - void (APIENTRY *BindFragmentShaderATI) (GLuint id); - void (APIENTRY *DeleteFragmentShaderATI) (GLuint id); - void (APIENTRY *BeginFragmentShaderATI) (void); - void (APIENTRY *EndFragmentShaderATI) (void); - void (APIENTRY *PassTexCoordATI) (GLuint dst, GLuint coord, GLenum swizzle); - void (APIENTRY *SampleMapATI) (GLuint dst, GLuint interp, GLenum swizzle); - void (APIENTRY *ColorFragmentOp1ATI) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); - void (APIENTRY *ColorFragmentOp2ATI) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); - void (APIENTRY *ColorFragmentOp3ATI) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); - void (APIENTRY *AlphaFragmentOp1ATI) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); - void (APIENTRY *AlphaFragmentOp2ATI) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); - void (APIENTRY *AlphaFragmentOp3ATI) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); - void (APIENTRY *SetFragmentShaderConstantATI) (GLuint dst, const GLfloat *value); - void (APIENTRY *PNTrianglesiATI) (GLenum pname, GLint param); - void (APIENTRY *PNTrianglesfATI) (GLenum pname, GLfloat param); - GLuint (APIENTRY *NewObjectBufferATI) (GLsizei size, const GLvoid *pointer, GLenum usage); - GLboolean (APIENTRY *IsObjectBufferATI) (GLuint buffer); - void (APIENTRY *UpdateObjectBufferATI) (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve); - void (APIENTRY *GetObjectBufferfvATI) (GLuint buffer, GLenum pname, GLfloat *params); - void (APIENTRY *GetObjectBufferivATI) (GLuint buffer, GLenum pname, GLint *params); - void (APIENTRY *FreeObjectBufferATI) (GLuint buffer); - void (APIENTRY *ArrayObjectATI) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); - void (APIENTRY *GetArrayObjectfvATI) (GLenum array, GLenum pname, GLfloat *params); - void (APIENTRY *GetArrayObjectivATI) (GLenum array, GLenum pname, GLint *params); - void (APIENTRY *VariantArrayObjectATI) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); - void (APIENTRY *GetVariantArrayObjectfvATI) (GLuint id, GLenum pname, GLfloat *params); - void (APIENTRY *GetVariantArrayObjectivATI) (GLuint id, GLenum pname, GLint *params); - void (APIENTRY *BeginVertexShaderEXT) (void); - void (APIENTRY *EndVertexShaderEXT) (void); - void (APIENTRY *BindVertexShaderEXT) (GLuint id); - GLuint (APIENTRY *GenVertexShadersEXT) (GLuint range); - void (APIENTRY *DeleteVertexShaderEXT) (GLuint id); - void (APIENTRY *ShaderOp1EXT) (GLenum op, GLuint res, GLuint arg1); - void (APIENTRY *ShaderOp2EXT) (GLenum op, GLuint res, GLuint arg1, GLuint arg2); - void (APIENTRY *ShaderOp3EXT) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); - void (APIENTRY *SwizzleEXT) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); - void (APIENTRY *WriteMaskEXT) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); - void (APIENTRY *InsertComponentEXT) (GLuint res, GLuint src, GLuint num); - void (APIENTRY *ExtractComponentEXT) (GLuint res, GLuint src, GLuint num); - GLuint (APIENTRY *GenSymbolsEXT) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); - void (APIENTRY *SetInvariantEXT) (GLuint id, GLenum type, const GLvoid *addr); - void (APIENTRY *SetLocalConstantEXT) (GLuint id, GLenum type, const GLvoid *addr); - void (APIENTRY *VariantbvEXT) (GLuint id, const GLbyte *addr); - void (APIENTRY *VariantsvEXT) (GLuint id, const GLshort *addr); - void (APIENTRY *VariantivEXT) (GLuint id, const GLint *addr); - void (APIENTRY *VariantfvEXT) (GLuint id, const GLfloat *addr); - void (APIENTRY *VariantdvEXT) (GLuint id, const GLdouble *addr); - void (APIENTRY *VariantubvEXT) (GLuint id, const GLubyte *addr); - void (APIENTRY *VariantusvEXT) (GLuint id, const GLushort *addr); - void (APIENTRY *VariantuivEXT) (GLuint id, const GLuint *addr); - void (APIENTRY *VariantPointerEXT) (GLuint id, GLenum type, GLuint stride, const GLvoid *addr); - void (APIENTRY *EnableVariantClientStateEXT) (GLuint id); - void (APIENTRY *DisableVariantClientStateEXT) (GLuint id); - GLuint (APIENTRY *BindLightParameterEXT) (GLenum light, GLenum value); - GLuint (APIENTRY *BindMaterialParameterEXT) (GLenum face, GLenum value); - GLuint (APIENTRY *BindTexGenParameterEXT) (GLenum unit, GLenum coord, GLenum value); - GLuint (APIENTRY *BindTextureUnitParameterEXT) (GLenum unit, GLenum value); - GLuint (APIENTRY *BindParameterEXT) (GLenum value); - GLboolean (APIENTRY *IsVariantEnabledEXT) (GLuint id, GLenum cap); - void (APIENTRY *GetVariantBooleanvEXT) (GLuint id, GLenum value, GLboolean *data); - void (APIENTRY *GetVariantIntegervEXT) (GLuint id, GLenum value, GLint *data); - void (APIENTRY *GetVariantFloatvEXT) (GLuint id, GLenum value, GLfloat *data); - void (APIENTRY *GetVariantPointervEXT) (GLuint id, GLenum value, GLvoid* *data); - void (APIENTRY *GetInvariantBooleanvEXT) (GLuint id, GLenum value, GLboolean *data); - void (APIENTRY *GetInvariantIntegervEXT) (GLuint id, GLenum value, GLint *data); - void (APIENTRY *GetInvariantFloatvEXT) (GLuint id, GLenum value, GLfloat *data); - void (APIENTRY *GetLocalConstantBooleanvEXT) (GLuint id, GLenum value, GLboolean *data); - void (APIENTRY *GetLocalConstantIntegervEXT) (GLuint id, GLenum value, GLint *data); - void (APIENTRY *GetLocalConstantFloatvEXT) (GLuint id, GLenum value, GLfloat *data); - void (APIENTRY *VertexStream1sATI) (GLenum stream, GLshort x); - void (APIENTRY *VertexStream1svATI) (GLenum stream, const GLshort *coords); - void (APIENTRY *VertexStream1iATI) (GLenum stream, GLint x); - void (APIENTRY *VertexStream1ivATI) (GLenum stream, const GLint *coords); - void (APIENTRY *VertexStream1fATI) (GLenum stream, GLfloat x); - void (APIENTRY *VertexStream1fvATI) (GLenum stream, const GLfloat *coords); - void (APIENTRY *VertexStream1dATI) (GLenum stream, GLdouble x); - void (APIENTRY *VertexStream1dvATI) (GLenum stream, const GLdouble *coords); - void (APIENTRY *VertexStream2sATI) (GLenum stream, GLshort x, GLshort y); - void (APIENTRY *VertexStream2svATI) (GLenum stream, const GLshort *coords); - void (APIENTRY *VertexStream2iATI) (GLenum stream, GLint x, GLint y); - void (APIENTRY *VertexStream2ivATI) (GLenum stream, const GLint *coords); - void (APIENTRY *VertexStream2fATI) (GLenum stream, GLfloat x, GLfloat y); - void (APIENTRY *VertexStream2fvATI) (GLenum stream, const GLfloat *coords); - void (APIENTRY *VertexStream2dATI) (GLenum stream, GLdouble x, GLdouble y); - void (APIENTRY *VertexStream2dvATI) (GLenum stream, const GLdouble *coords); - void (APIENTRY *VertexStream3sATI) (GLenum stream, GLshort x, GLshort y, GLshort z); - void (APIENTRY *VertexStream3svATI) (GLenum stream, const GLshort *coords); - void (APIENTRY *VertexStream3iATI) (GLenum stream, GLint x, GLint y, GLint z); - void (APIENTRY *VertexStream3ivATI) (GLenum stream, const GLint *coords); - void (APIENTRY *VertexStream3fATI) (GLenum stream, GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *VertexStream3fvATI) (GLenum stream, const GLfloat *coords); - void (APIENTRY *VertexStream3dATI) (GLenum stream, GLdouble x, GLdouble y, GLdouble z); - void (APIENTRY *VertexStream3dvATI) (GLenum stream, const GLdouble *coords); - void (APIENTRY *VertexStream4sATI) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); - void (APIENTRY *VertexStream4svATI) (GLenum stream, const GLshort *coords); - void (APIENTRY *VertexStream4iATI) (GLenum stream, GLint x, GLint y, GLint z, GLint w); - void (APIENTRY *VertexStream4ivATI) (GLenum stream, const GLint *coords); - void (APIENTRY *VertexStream4fATI) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void (APIENTRY *VertexStream4fvATI) (GLenum stream, const GLfloat *coords); - void (APIENTRY *VertexStream4dATI) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); - void (APIENTRY *VertexStream4dvATI) (GLenum stream, const GLdouble *coords); - void (APIENTRY *NormalStream3bATI) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); - void (APIENTRY *NormalStream3bvATI) (GLenum stream, const GLbyte *coords); - void (APIENTRY *NormalStream3sATI) (GLenum stream, GLshort nx, GLshort ny, GLshort nz); - void (APIENTRY *NormalStream3svATI) (GLenum stream, const GLshort *coords); - void (APIENTRY *NormalStream3iATI) (GLenum stream, GLint nx, GLint ny, GLint nz); - void (APIENTRY *NormalStream3ivATI) (GLenum stream, const GLint *coords); - void (APIENTRY *NormalStream3fATI) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); - void (APIENTRY *NormalStream3fvATI) (GLenum stream, const GLfloat *coords); - void (APIENTRY *NormalStream3dATI) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); - void (APIENTRY *NormalStream3dvATI) (GLenum stream, const GLdouble *coords); - void (APIENTRY *ClientActiveVertexStreamATI) (GLenum stream); - void (APIENTRY *VertexBlendEnviATI) (GLenum pname, GLint param); - void (APIENTRY *VertexBlendEnvfATI) (GLenum pname, GLfloat param); - void (APIENTRY *ElementPointerATI) (GLenum type, const GLvoid *pointer); - void (APIENTRY *DrawElementArrayATI) (GLenum mode, GLsizei count); - void (APIENTRY *DrawRangeElementArrayATI) (GLenum mode, GLuint start, GLuint end, GLsizei count); - void (APIENTRY *DrawMeshArraysSUN) (GLenum mode, GLint first, GLsizei count, GLsizei width); - void (APIENTRY *GenOcclusionQueriesNV) (GLsizei n, GLuint *ids); - void (APIENTRY *DeleteOcclusionQueriesNV) (GLsizei n, const GLuint *ids); - GLboolean (APIENTRY *IsOcclusionQueryNV) (GLuint id); - void (APIENTRY *BeginOcclusionQueryNV) (GLuint id); - void (APIENTRY *EndOcclusionQueryNV) (void); - void (APIENTRY *GetOcclusionQueryivNV) (GLuint id, GLenum pname, GLint *params); - void (APIENTRY *GetOcclusionQueryuivNV) (GLuint id, GLenum pname, GLuint *params); - void (APIENTRY *PointParameteriNV) (GLenum pname, GLint param); - void (APIENTRY *PointParameterivNV) (GLenum pname, const GLint *params); - void (APIENTRY *ActiveStencilFaceEXT) (GLenum face); - void (APIENTRY *ElementPointerAPPLE) (GLenum type, const GLvoid *pointer); - void (APIENTRY *DrawElementArrayAPPLE) (GLenum mode, GLint first, GLsizei count); - void (APIENTRY *DrawRangeElementArrayAPPLE) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); - void (APIENTRY *MultiDrawElementArrayAPPLE) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); - void (APIENTRY *MultiDrawRangeElementArrayAPPLE) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); - void (APIENTRY *GenFencesAPPLE) (GLsizei n, GLuint *fences); - void (APIENTRY *DeleteFencesAPPLE) (GLsizei n, const GLuint *fences); - void (APIENTRY *SetFenceAPPLE) (GLuint fence); - GLboolean (APIENTRY *IsFenceAPPLE) (GLuint fence); - GLboolean (APIENTRY *TestFenceAPPLE) (GLuint fence); - void (APIENTRY *FinishFenceAPPLE) (GLuint fence); - GLboolean (APIENTRY *TestObjectAPPLE) (GLenum object, GLuint name); - void (APIENTRY *FinishObjectAPPLE) (GLenum object, GLint name); - void (APIENTRY *BindVertexArrayAPPLE) (GLuint array); - void (APIENTRY *DeleteVertexArraysAPPLE) (GLsizei n, const GLuint *arrays); - void (APIENTRY *GenVertexArraysAPPLE) (GLsizei n, const GLuint *arrays); - GLboolean (APIENTRY *IsVertexArrayAPPLE) (GLuint array); - void (APIENTRY *VertexArrayRangeAPPLE) (GLsizei length, GLvoid *pointer); - void (APIENTRY *FlushVertexArrayRangeAPPLE) (GLsizei length, GLvoid *pointer); - void (APIENTRY *VertexArrayParameteriAPPLE) (GLenum pname, GLint param); - void (APIENTRY *DrawBuffersATI) (GLsizei n, const GLenum *bufs); - void (APIENTRY *ProgramNamedParameter4fNV) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void (APIENTRY *ProgramNamedParameter4dNV) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); - void (APIENTRY *ProgramNamedParameter4fvNV) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); - void (APIENTRY *ProgramNamedParameter4dvNV) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); - void (APIENTRY *GetProgramNamedParameterfvNV) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); - void (APIENTRY *GetProgramNamedParameterdvNV) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); - void (APIENTRY *Vertex2hNV) (GLhalfNV x, GLhalfNV y); - void (APIENTRY *Vertex2hvNV) (const GLhalfNV *v); - void (APIENTRY *Vertex3hNV) (GLhalfNV x, GLhalfNV y, GLhalfNV z); - void (APIENTRY *Vertex3hvNV) (const GLhalfNV *v); - void (APIENTRY *Vertex4hNV) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); - void (APIENTRY *Vertex4hvNV) (const GLhalfNV *v); - void (APIENTRY *Normal3hNV) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); - void (APIENTRY *Normal3hvNV) (const GLhalfNV *v); - void (APIENTRY *Color3hNV) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); - void (APIENTRY *Color3hvNV) (const GLhalfNV *v); - void (APIENTRY *Color4hNV) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); - void (APIENTRY *Color4hvNV) (const GLhalfNV *v); - void (APIENTRY *TexCoord1hNV) (GLhalfNV s); - void (APIENTRY *TexCoord1hvNV) (const GLhalfNV *v); - void (APIENTRY *TexCoord2hNV) (GLhalfNV s, GLhalfNV t); - void (APIENTRY *TexCoord2hvNV) (const GLhalfNV *v); - void (APIENTRY *TexCoord3hNV) (GLhalfNV s, GLhalfNV t, GLhalfNV r); - void (APIENTRY *TexCoord3hvNV) (const GLhalfNV *v); - void (APIENTRY *TexCoord4hNV) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); - void (APIENTRY *TexCoord4hvNV) (const GLhalfNV *v); - void (APIENTRY *MultiTexCoord1hNV) (GLenum target, GLhalfNV s); - void (APIENTRY *MultiTexCoord1hvNV) (GLenum target, const GLhalfNV *v); - void (APIENTRY *MultiTexCoord2hNV) (GLenum target, GLhalfNV s, GLhalfNV t); - void (APIENTRY *MultiTexCoord2hvNV) (GLenum target, const GLhalfNV *v); - void (APIENTRY *MultiTexCoord3hNV) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); - void (APIENTRY *MultiTexCoord3hvNV) (GLenum target, const GLhalfNV *v); - void (APIENTRY *MultiTexCoord4hNV) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); - void (APIENTRY *MultiTexCoord4hvNV) (GLenum target, const GLhalfNV *v); - void (APIENTRY *FogCoordhNV) (GLhalfNV fog); - void (APIENTRY *FogCoordhvNV) (const GLhalfNV *fog); - void (APIENTRY *SecondaryColor3hNV) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); - void (APIENTRY *SecondaryColor3hvNV) (const GLhalfNV *v); - void (APIENTRY *VertexWeighthNV) (GLhalfNV weight); - void (APIENTRY *VertexWeighthvNV) (const GLhalfNV *weight); - void (APIENTRY *VertexAttrib1hNV) (GLuint index, GLhalfNV x); - void (APIENTRY *VertexAttrib1hvNV) (GLuint index, const GLhalfNV *v); - void (APIENTRY *VertexAttrib2hNV) (GLuint index, GLhalfNV x, GLhalfNV y); - void (APIENTRY *VertexAttrib2hvNV) (GLuint index, const GLhalfNV *v); - void (APIENTRY *VertexAttrib3hNV) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); - void (APIENTRY *VertexAttrib3hvNV) (GLuint index, const GLhalfNV *v); - void (APIENTRY *VertexAttrib4hNV) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); - void (APIENTRY *VertexAttrib4hvNV) (GLuint index, const GLhalfNV *v); - void (APIENTRY *VertexAttribs1hvNV) (GLuint index, GLsizei n, const GLhalfNV *v); - void (APIENTRY *VertexAttribs2hvNV) (GLuint index, GLsizei n, const GLhalfNV *v); - void (APIENTRY *VertexAttribs3hvNV) (GLuint index, GLsizei n, const GLhalfNV *v); - void (APIENTRY *VertexAttribs4hvNV) (GLuint index, GLsizei n, const GLhalfNV *v); - void (APIENTRY *PixelDataRangeNV) (GLenum target, GLsizei length, GLvoid *pointer); - void (APIENTRY *FlushPixelDataRangeNV) (GLenum target); - void (APIENTRY *PrimitiveRestartNV) (void); - void (APIENTRY *PrimitiveRestartIndexNV) (GLuint index); - GLvoid* (APIENTRY *MapObjectBufferATI) (GLuint buffer); - void (APIENTRY *UnmapObjectBufferATI) (GLuint buffer); - void (APIENTRY *StencilOpSeparateATI) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); - void (APIENTRY *StencilFuncSeparateATI) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); - void (APIENTRY *VertexAttribArrayObjectATI) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); - void (APIENTRY *GetVertexAttribArrayObjectfvATI) (GLuint index, GLenum pname, GLfloat *params); - void (APIENTRY *GetVertexAttribArrayObjectivATI) (GLuint index, GLenum pname, GLint *params); - void (APIENTRY *DepthBoundsEXT) (GLclampd zmin, GLclampd zmax); - void (APIENTRY *BlendEquationSeparateEXT) (GLenum modeRGB, GLenum modeAlpha); - void (APIENTRY *AddSwapHintRectWIN) (GLint x, GLint y, GLsizei width, GLsizei height); -#ifdef _WIN32 - HANDLE (WINAPI *CreateBufferRegionARB) (HDC hDC, int iLayerPlane, UINT uType); - VOID (WINAPI *DeleteBufferRegionARB) (HANDLE hRegion); - BOOL (WINAPI *SaveBufferRegionARB) (HANDLE hRegion, int x, int y, int width, int height); - BOOL (WINAPI *RestoreBufferRegionARB) (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); - const int (WINAPI *GetExtensionsStringARB) (HDC hdc); - BOOL (WINAPI *GetPixelFormatAttribivARB) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); - BOOL (WINAPI *GetPixelFormatAttribfvARB) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); - BOOL (WINAPI *ChoosePixelFormatARB) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); - BOOL (WINAPI *MakeContextCurrentARB) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); - HDC (WINAPI *GetCurrentReadDCARB) (void); - HPBUFFERARB (WINAPI *CreatePbufferARB) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); - HDC (WINAPI *GetPbufferDCARB) (HPBUFFERARB hPbuffer); - int (WINAPI *ReleasePbufferDCARB) (HPBUFFERARB hPbuffer, HDC hDC); - BOOL (WINAPI *DestroyPbufferARB) (HPBUFFERARB hPbuffer); - BOOL (WINAPI *QueryPbufferARB) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); - BOOL (WINAPI *BindTexImageARB) (HPBUFFERARB hPbuffer, int iBuffer); - BOOL (WINAPI *ReleaseTexImageARB) (HPBUFFERARB hPbuffer, int iBuffer); - BOOL (WINAPI *SetPbufferAttribARB) (HPBUFFERARB hPbuffer, const int *piAttribList); - GLboolean (WINAPI *CreateDisplayColorTableEXT) (GLushort id); - GLboolean (WINAPI *LoadDisplayColorTableEXT) (const GLushort *table, GLuint length); - GLboolean (WINAPI *BindDisplayColorTableEXT) (GLushort id); - VOID (WINAPI *DestroyDisplayColorTableEXT) (GLushort id); - const int (WINAPI *GetExtensionsStringEXT) (void); - BOOL (WINAPI *MakeContextCurrentEXT) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); - HDC (WINAPI *GetCurrentReadDCEXT) (void); - HPBUFFEREXT (WINAPI *CreatePbufferEXT) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); - HDC (WINAPI *GetPbufferDCEXT) (HPBUFFEREXT hPbuffer); - int (WINAPI *ReleasePbufferDCEXT) (HPBUFFEREXT hPbuffer, HDC hDC); - BOOL (WINAPI *DestroyPbufferEXT) (HPBUFFEREXT hPbuffer); - BOOL (WINAPI *QueryPbufferEXT) (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); - BOOL (WINAPI *GetPixelFormatAttribivEXT) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); - BOOL (WINAPI *GetPixelFormatAttribfvEXT) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); - BOOL (WINAPI *ChoosePixelFormatEXT) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); - BOOL (WINAPI *SwapIntervalEXT) (int interval); - int (WINAPI *GetSwapIntervalEXT) (void); - void* (WINAPI *AllocateMemoryNV) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); - void (WINAPI *FreeMemoryNV) (void); - BOOL (WINAPI *GetSyncValuesOML) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); - BOOL (WINAPI *GetMscRateOML) (HDC hdc, INT32 *numerator, INT32 *denominator); - INT64 (WINAPI *SwapBuffersMscOML) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); - INT64 (WINAPI *SwapLayerBuffersMscOML) (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); - BOOL (WINAPI *WaitForMscOML) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); - BOOL (WINAPI *WaitForSbcOML) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); - BOOL (WINAPI *GetDigitalVideoParametersI3D) (HDC hDC, int iAttribute, int *piValue); - BOOL (WINAPI *SetDigitalVideoParametersI3D) (HDC hDC, int iAttribute, const int *piValue); - BOOL (WINAPI *GetGammaTableParametersI3D) (HDC hDC, int iAttribute, int *piValue); - BOOL (WINAPI *SetGammaTableParametersI3D) (HDC hDC, int iAttribute, const int *piValue); - BOOL (WINAPI *GetGammaTableI3D) (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); - BOOL (WINAPI *SetGammaTableI3D) (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); - BOOL (WINAPI *EnableGenlockI3D) (HDC hDC); - BOOL (WINAPI *DisableGenlockI3D) (HDC hDC); - BOOL (WINAPI *IsEnabledGenlockI3D) (HDC hDC, BOOL *pFlag); - BOOL (WINAPI *GenlockSourceI3D) (HDC hDC, UINT uSource); - BOOL (WINAPI *GetGenlockSourceI3D) (HDC hDC, UINT *uSource); - BOOL (WINAPI *GenlockSourceEdgeI3D) (HDC hDC, UINT uEdge); - BOOL (WINAPI *GetGenlockSourceEdgeI3D) (HDC hDC, UINT *uEdge); - BOOL (WINAPI *GenlockSampleRateI3D) (HDC hDC, UINT uRate); - BOOL (WINAPI *GetGenlockSampleRateI3D) (HDC hDC, UINT *uRate); - BOOL (WINAPI *GenlockSourceDelayI3D) (HDC hDC, UINT uDelay); - BOOL (WINAPI *GetGenlockSourceDelayI3D) (HDC hDC, UINT *uDelay); - BOOL (WINAPI *QueryGenlockMaxSourceDelayI3D) (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); - LPVOID (WINAPI *CreateImageBufferI3D) (HDC hDC, DWORD dwSize, UINT uFlags); - BOOL (WINAPI *DestroyImageBufferI3D) (HDC hDC, LPVOID pAddress); - BOOL (WINAPI *AssociateImageBufferEventsI3D) (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); - BOOL (WINAPI *ReleaseImageBufferEventsI3D) (HDC hDC, const LPVOID *pAddress, UINT count); - BOOL (WINAPI *EnableFrameLockI3D) (void); - BOOL (WINAPI *DisableFrameLockI3D) (void); - BOOL (WINAPI *IsEnabledFrameLockI3D) (BOOL *pFlag); - BOOL (WINAPI *QueryFrameLockMasterI3D) (BOOL *pFlag); - BOOL (WINAPI *GetFrameUsageI3D) (float *pUsage); - BOOL (WINAPI *BeginFrameTrackingI3D) (void); - BOOL (WINAPI *EndFrameTrackingI3D) (void); - BOOL (WINAPI *QueryFrameTrackingI3D) (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); -#endif /* _WIN32 */ -} _GLextensionProcs; - -#define glBlendColor (_GET_TLS_PROCTABLE()->BlendColor) -#define glBlendEquation (_GET_TLS_PROCTABLE()->BlendEquation) -#define glDrawRangeElements (_GET_TLS_PROCTABLE()->DrawRangeElements) -#define glColorTable (_GET_TLS_PROCTABLE()->ColorTable) -#define glColorTableParameterfv (_GET_TLS_PROCTABLE()->ColorTableParameterfv) -#define glColorTableParameteriv (_GET_TLS_PROCTABLE()->ColorTableParameteriv) -#define glCopyColorTable (_GET_TLS_PROCTABLE()->CopyColorTable) -#define glGetColorTable (_GET_TLS_PROCTABLE()->GetColorTable) -#define glGetColorTableParameterfv (_GET_TLS_PROCTABLE()->GetColorTableParameterfv) -#define glGetColorTableParameteriv (_GET_TLS_PROCTABLE()->GetColorTableParameteriv) -#define glColorSubTable (_GET_TLS_PROCTABLE()->ColorSubTable) -#define glCopyColorSubTable (_GET_TLS_PROCTABLE()->CopyColorSubTable) -#define glConvolutionFilter1D (_GET_TLS_PROCTABLE()->ConvolutionFilter1D) -#define glConvolutionFilter2D (_GET_TLS_PROCTABLE()->ConvolutionFilter2D) -#define glConvolutionParameterf (_GET_TLS_PROCTABLE()->ConvolutionParameterf) -#define glConvolutionParameterfv (_GET_TLS_PROCTABLE()->ConvolutionParameterfv) -#define glConvolutionParameteri (_GET_TLS_PROCTABLE()->ConvolutionParameteri) -#define glConvolutionParameteriv (_GET_TLS_PROCTABLE()->ConvolutionParameteriv) -#define glCopyConvolutionFilter1D (_GET_TLS_PROCTABLE()->CopyConvolutionFilter1D) -#define glCopyConvolutionFilter2D (_GET_TLS_PROCTABLE()->CopyConvolutionFilter2D) -#define glGetConvolutionFilter (_GET_TLS_PROCTABLE()->GetConvolutionFilter) -#define glGetConvolutionParameterfv (_GET_TLS_PROCTABLE()->GetConvolutionParameterfv) -#define glGetConvolutionParameteriv (_GET_TLS_PROCTABLE()->GetConvolutionParameteriv) -#define glGetSeparableFilter (_GET_TLS_PROCTABLE()->GetSeparableFilter) -#define glSeparableFilter2D (_GET_TLS_PROCTABLE()->SeparableFilter2D) -#define glGetHistogram (_GET_TLS_PROCTABLE()->GetHistogram) -#define glGetHistogramParameterfv (_GET_TLS_PROCTABLE()->GetHistogramParameterfv) -#define glGetHistogramParameteriv (_GET_TLS_PROCTABLE()->GetHistogramParameteriv) -#define glGetMinmax (_GET_TLS_PROCTABLE()->GetMinmax) -#define glGetMinmaxParameterfv (_GET_TLS_PROCTABLE()->GetMinmaxParameterfv) -#define glGetMinmaxParameteriv (_GET_TLS_PROCTABLE()->GetMinmaxParameteriv) -#define glHistogram (_GET_TLS_PROCTABLE()->Histogram) -#define glMinmax (_GET_TLS_PROCTABLE()->Minmax) -#define glResetHistogram (_GET_TLS_PROCTABLE()->ResetHistogram) -#define glResetMinmax (_GET_TLS_PROCTABLE()->ResetMinmax) -#define glTexImage3D (_GET_TLS_PROCTABLE()->TexImage3D) -#define glTexSubImage3D (_GET_TLS_PROCTABLE()->TexSubImage3D) -#define glCopyTexSubImage3D (_GET_TLS_PROCTABLE()->CopyTexSubImage3D) -#define glActiveTexture (_GET_TLS_PROCTABLE()->ActiveTexture) -#define glClientActiveTexture (_GET_TLS_PROCTABLE()->ClientActiveTexture) -#define glMultiTexCoord1d (_GET_TLS_PROCTABLE()->MultiTexCoord1d) -#define glMultiTexCoord1dv (_GET_TLS_PROCTABLE()->MultiTexCoord1dv) -#define glMultiTexCoord1f (_GET_TLS_PROCTABLE()->MultiTexCoord1f) -#define glMultiTexCoord1fv (_GET_TLS_PROCTABLE()->MultiTexCoord1fv) -#define glMultiTexCoord1i (_GET_TLS_PROCTABLE()->MultiTexCoord1i) -#define glMultiTexCoord1iv (_GET_TLS_PROCTABLE()->MultiTexCoord1iv) -#define glMultiTexCoord1s (_GET_TLS_PROCTABLE()->MultiTexCoord1s) -#define glMultiTexCoord1sv (_GET_TLS_PROCTABLE()->MultiTexCoord1sv) -#define glMultiTexCoord2d (_GET_TLS_PROCTABLE()->MultiTexCoord2d) -#define glMultiTexCoord2dv (_GET_TLS_PROCTABLE()->MultiTexCoord2dv) -#define glMultiTexCoord2f (_GET_TLS_PROCTABLE()->MultiTexCoord2f) -#define glMultiTexCoord2fv (_GET_TLS_PROCTABLE()->MultiTexCoord2fv) -#define glMultiTexCoord2i (_GET_TLS_PROCTABLE()->MultiTexCoord2i) -#define glMultiTexCoord2iv (_GET_TLS_PROCTABLE()->MultiTexCoord2iv) -#define glMultiTexCoord2s (_GET_TLS_PROCTABLE()->MultiTexCoord2s) -#define glMultiTexCoord2sv (_GET_TLS_PROCTABLE()->MultiTexCoord2sv) -#define glMultiTexCoord3d (_GET_TLS_PROCTABLE()->MultiTexCoord3d) -#define glMultiTexCoord3dv (_GET_TLS_PROCTABLE()->MultiTexCoord3dv) -#define glMultiTexCoord3f (_GET_TLS_PROCTABLE()->MultiTexCoord3f) -#define glMultiTexCoord3fv (_GET_TLS_PROCTABLE()->MultiTexCoord3fv) -#define glMultiTexCoord3i (_GET_TLS_PROCTABLE()->MultiTexCoord3i) -#define glMultiTexCoord3iv (_GET_TLS_PROCTABLE()->MultiTexCoord3iv) -#define glMultiTexCoord3s (_GET_TLS_PROCTABLE()->MultiTexCoord3s) -#define glMultiTexCoord3sv (_GET_TLS_PROCTABLE()->MultiTexCoord3sv) -#define glMultiTexCoord4d (_GET_TLS_PROCTABLE()->MultiTexCoord4d) -#define glMultiTexCoord4dv (_GET_TLS_PROCTABLE()->MultiTexCoord4dv) -#define glMultiTexCoord4f (_GET_TLS_PROCTABLE()->MultiTexCoord4f) -#define glMultiTexCoord4fv (_GET_TLS_PROCTABLE()->MultiTexCoord4fv) -#define glMultiTexCoord4i (_GET_TLS_PROCTABLE()->MultiTexCoord4i) -#define glMultiTexCoord4iv (_GET_TLS_PROCTABLE()->MultiTexCoord4iv) -#define glMultiTexCoord4s (_GET_TLS_PROCTABLE()->MultiTexCoord4s) -#define glMultiTexCoord4sv (_GET_TLS_PROCTABLE()->MultiTexCoord4sv) -#define glLoadTransposeMatrixf (_GET_TLS_PROCTABLE()->LoadTransposeMatrixf) -#define glLoadTransposeMatrixd (_GET_TLS_PROCTABLE()->LoadTransposeMatrixd) -#define glMultTransposeMatrixf (_GET_TLS_PROCTABLE()->MultTransposeMatrixf) -#define glMultTransposeMatrixd (_GET_TLS_PROCTABLE()->MultTransposeMatrixd) -#define glSampleCoverage (_GET_TLS_PROCTABLE()->SampleCoverage) -#define glCompressedTexImage3D (_GET_TLS_PROCTABLE()->CompressedTexImage3D) -#define glCompressedTexImage2D (_GET_TLS_PROCTABLE()->CompressedTexImage2D) -#define glCompressedTexImage1D (_GET_TLS_PROCTABLE()->CompressedTexImage1D) -#define glCompressedTexSubImage3D (_GET_TLS_PROCTABLE()->CompressedTexSubImage3D) -#define glCompressedTexSubImage2D (_GET_TLS_PROCTABLE()->CompressedTexSubImage2D) -#define glCompressedTexSubImage1D (_GET_TLS_PROCTABLE()->CompressedTexSubImage1D) -#define glGetCompressedTexImage (_GET_TLS_PROCTABLE()->GetCompressedTexImage) -#define glBlendFuncSeparate (_GET_TLS_PROCTABLE()->BlendFuncSeparate) -#define glFogCoordf (_GET_TLS_PROCTABLE()->FogCoordf) -#define glFogCoordfv (_GET_TLS_PROCTABLE()->FogCoordfv) -#define glFogCoordd (_GET_TLS_PROCTABLE()->FogCoordd) -#define glFogCoorddv (_GET_TLS_PROCTABLE()->FogCoorddv) -#define glFogCoordPointer (_GET_TLS_PROCTABLE()->FogCoordPointer) -#define glMultiDrawArrays (_GET_TLS_PROCTABLE()->MultiDrawArrays) -#define glMultiDrawElements (_GET_TLS_PROCTABLE()->MultiDrawElements) -#define glPointParameterf (_GET_TLS_PROCTABLE()->PointParameterf) -#define glPointParameterfv (_GET_TLS_PROCTABLE()->PointParameterfv) -#define glPointParameteri (_GET_TLS_PROCTABLE()->PointParameteri) -#define glPointParameteriv (_GET_TLS_PROCTABLE()->PointParameteriv) -#define glSecondaryColor3b (_GET_TLS_PROCTABLE()->SecondaryColor3b) -#define glSecondaryColor3bv (_GET_TLS_PROCTABLE()->SecondaryColor3bv) -#define glSecondaryColor3d (_GET_TLS_PROCTABLE()->SecondaryColor3d) -#define glSecondaryColor3dv (_GET_TLS_PROCTABLE()->SecondaryColor3dv) -#define glSecondaryColor3f (_GET_TLS_PROCTABLE()->SecondaryColor3f) -#define glSecondaryColor3fv (_GET_TLS_PROCTABLE()->SecondaryColor3fv) -#define glSecondaryColor3i (_GET_TLS_PROCTABLE()->SecondaryColor3i) -#define glSecondaryColor3iv (_GET_TLS_PROCTABLE()->SecondaryColor3iv) -#define glSecondaryColor3s (_GET_TLS_PROCTABLE()->SecondaryColor3s) -#define glSecondaryColor3sv (_GET_TLS_PROCTABLE()->SecondaryColor3sv) -#define glSecondaryColor3ub (_GET_TLS_PROCTABLE()->SecondaryColor3ub) -#define glSecondaryColor3ubv (_GET_TLS_PROCTABLE()->SecondaryColor3ubv) -#define glSecondaryColor3ui (_GET_TLS_PROCTABLE()->SecondaryColor3ui) -#define glSecondaryColor3uiv (_GET_TLS_PROCTABLE()->SecondaryColor3uiv) -#define glSecondaryColor3us (_GET_TLS_PROCTABLE()->SecondaryColor3us) -#define glSecondaryColor3usv (_GET_TLS_PROCTABLE()->SecondaryColor3usv) -#define glSecondaryColorPointer (_GET_TLS_PROCTABLE()->SecondaryColorPointer) -#define glWindowPos2d (_GET_TLS_PROCTABLE()->WindowPos2d) -#define glWindowPos2dv (_GET_TLS_PROCTABLE()->WindowPos2dv) -#define glWindowPos2f (_GET_TLS_PROCTABLE()->WindowPos2f) -#define glWindowPos2fv (_GET_TLS_PROCTABLE()->WindowPos2fv) -#define glWindowPos2i (_GET_TLS_PROCTABLE()->WindowPos2i) -#define glWindowPos2iv (_GET_TLS_PROCTABLE()->WindowPos2iv) -#define glWindowPos2s (_GET_TLS_PROCTABLE()->WindowPos2s) -#define glWindowPos2sv (_GET_TLS_PROCTABLE()->WindowPos2sv) -#define glWindowPos3d (_GET_TLS_PROCTABLE()->WindowPos3d) -#define glWindowPos3dv (_GET_TLS_PROCTABLE()->WindowPos3dv) -#define glWindowPos3f (_GET_TLS_PROCTABLE()->WindowPos3f) -#define glWindowPos3fv (_GET_TLS_PROCTABLE()->WindowPos3fv) -#define glWindowPos3i (_GET_TLS_PROCTABLE()->WindowPos3i) -#define glWindowPos3iv (_GET_TLS_PROCTABLE()->WindowPos3iv) -#define glWindowPos3s (_GET_TLS_PROCTABLE()->WindowPos3s) -#define glWindowPos3sv (_GET_TLS_PROCTABLE()->WindowPos3sv) -#define glGenQueries (_GET_TLS_PROCTABLE()->GenQueries) -#define glDeleteQueries (_GET_TLS_PROCTABLE()->DeleteQueries) -#define glIsQuery (_GET_TLS_PROCTABLE()->IsQuery) -#define glBeginQuery (_GET_TLS_PROCTABLE()->BeginQuery) -#define glEndQuery (_GET_TLS_PROCTABLE()->EndQuery) -#define glGetQueryiv (_GET_TLS_PROCTABLE()->GetQueryiv) -#define glGetQueryObjectiv (_GET_TLS_PROCTABLE()->GetQueryObjectiv) -#define glGetQueryObjectuiv (_GET_TLS_PROCTABLE()->GetQueryObjectuiv) -#define glBindBuffer (_GET_TLS_PROCTABLE()->BindBuffer) -#define glDeleteBuffers (_GET_TLS_PROCTABLE()->DeleteBuffers) -#define glGenBuffers (_GET_TLS_PROCTABLE()->GenBuffers) -#define glIsBuffer (_GET_TLS_PROCTABLE()->IsBuffer) -#define glBufferData (_GET_TLS_PROCTABLE()->BufferData) -#define glBufferSubData (_GET_TLS_PROCTABLE()->BufferSubData) -#define glGetBufferSubData (_GET_TLS_PROCTABLE()->GetBufferSubData) -#define glMapBuffer (_GET_TLS_PROCTABLE()->MapBuffer) -#define glUnmapBuffer (_GET_TLS_PROCTABLE()->UnmapBuffer) -#define glGetBufferParameteriv (_GET_TLS_PROCTABLE()->GetBufferParameteriv) -#define glGetBufferPointerv (_GET_TLS_PROCTABLE()->GetBufferPointerv) -#define glActiveTextureARB (_GET_TLS_PROCTABLE()->ActiveTextureARB) -#define glClientActiveTextureARB (_GET_TLS_PROCTABLE()->ClientActiveTextureARB) -#define glMultiTexCoord1dARB (_GET_TLS_PROCTABLE()->MultiTexCoord1dARB) -#define glMultiTexCoord1dvARB (_GET_TLS_PROCTABLE()->MultiTexCoord1dvARB) -#define glMultiTexCoord1fARB (_GET_TLS_PROCTABLE()->MultiTexCoord1fARB) -#define glMultiTexCoord1fvARB (_GET_TLS_PROCTABLE()->MultiTexCoord1fvARB) -#define glMultiTexCoord1iARB (_GET_TLS_PROCTABLE()->MultiTexCoord1iARB) -#define glMultiTexCoord1ivARB (_GET_TLS_PROCTABLE()->MultiTexCoord1ivARB) -#define glMultiTexCoord1sARB (_GET_TLS_PROCTABLE()->MultiTexCoord1sARB) -#define glMultiTexCoord1svARB (_GET_TLS_PROCTABLE()->MultiTexCoord1svARB) -#define glMultiTexCoord2dARB (_GET_TLS_PROCTABLE()->MultiTexCoord2dARB) -#define glMultiTexCoord2dvARB (_GET_TLS_PROCTABLE()->MultiTexCoord2dvARB) -#define glMultiTexCoord2fARB (_GET_TLS_PROCTABLE()->MultiTexCoord2fARB) -#define glMultiTexCoord2fvARB (_GET_TLS_PROCTABLE()->MultiTexCoord2fvARB) -#define glMultiTexCoord2iARB (_GET_TLS_PROCTABLE()->MultiTexCoord2iARB) -#define glMultiTexCoord2ivARB (_GET_TLS_PROCTABLE()->MultiTexCoord2ivARB) -#define glMultiTexCoord2sARB (_GET_TLS_PROCTABLE()->MultiTexCoord2sARB) -#define glMultiTexCoord2svARB (_GET_TLS_PROCTABLE()->MultiTexCoord2svARB) -#define glMultiTexCoord3dARB (_GET_TLS_PROCTABLE()->MultiTexCoord3dARB) -#define glMultiTexCoord3dvARB (_GET_TLS_PROCTABLE()->MultiTexCoord3dvARB) -#define glMultiTexCoord3fARB (_GET_TLS_PROCTABLE()->MultiTexCoord3fARB) -#define glMultiTexCoord3fvARB (_GET_TLS_PROCTABLE()->MultiTexCoord3fvARB) -#define glMultiTexCoord3iARB (_GET_TLS_PROCTABLE()->MultiTexCoord3iARB) -#define glMultiTexCoord3ivARB (_GET_TLS_PROCTABLE()->MultiTexCoord3ivARB) -#define glMultiTexCoord3sARB (_GET_TLS_PROCTABLE()->MultiTexCoord3sARB) -#define glMultiTexCoord3svARB (_GET_TLS_PROCTABLE()->MultiTexCoord3svARB) -#define glMultiTexCoord4dARB (_GET_TLS_PROCTABLE()->MultiTexCoord4dARB) -#define glMultiTexCoord4dvARB (_GET_TLS_PROCTABLE()->MultiTexCoord4dvARB) -#define glMultiTexCoord4fARB (_GET_TLS_PROCTABLE()->MultiTexCoord4fARB) -#define glMultiTexCoord4fvARB (_GET_TLS_PROCTABLE()->MultiTexCoord4fvARB) -#define glMultiTexCoord4iARB (_GET_TLS_PROCTABLE()->MultiTexCoord4iARB) -#define glMultiTexCoord4ivARB (_GET_TLS_PROCTABLE()->MultiTexCoord4ivARB) -#define glMultiTexCoord4sARB (_GET_TLS_PROCTABLE()->MultiTexCoord4sARB) -#define glMultiTexCoord4svARB (_GET_TLS_PROCTABLE()->MultiTexCoord4svARB) -#define glLoadTransposeMatrixfARB (_GET_TLS_PROCTABLE()->LoadTransposeMatrixfARB) -#define glLoadTransposeMatrixdARB (_GET_TLS_PROCTABLE()->LoadTransposeMatrixdARB) -#define glMultTransposeMatrixfARB (_GET_TLS_PROCTABLE()->MultTransposeMatrixfARB) -#define glMultTransposeMatrixdARB (_GET_TLS_PROCTABLE()->MultTransposeMatrixdARB) -#define glSampleCoverageARB (_GET_TLS_PROCTABLE()->SampleCoverageARB) -#define glCompressedTexImage3DARB (_GET_TLS_PROCTABLE()->CompressedTexImage3DARB) -#define glCompressedTexImage2DARB (_GET_TLS_PROCTABLE()->CompressedTexImage2DARB) -#define glCompressedTexImage1DARB (_GET_TLS_PROCTABLE()->CompressedTexImage1DARB) -#define glCompressedTexSubImage3DARB (_GET_TLS_PROCTABLE()->CompressedTexSubImage3DARB) -#define glCompressedTexSubImage2DARB (_GET_TLS_PROCTABLE()->CompressedTexSubImage2DARB) -#define glCompressedTexSubImage1DARB (_GET_TLS_PROCTABLE()->CompressedTexSubImage1DARB) -#define glGetCompressedTexImageARB (_GET_TLS_PROCTABLE()->GetCompressedTexImageARB) -#define glPointParameterfARB (_GET_TLS_PROCTABLE()->PointParameterfARB) -#define glPointParameterfvARB (_GET_TLS_PROCTABLE()->PointParameterfvARB) -#define glWeightbvARB (_GET_TLS_PROCTABLE()->WeightbvARB) -#define glWeightsvARB (_GET_TLS_PROCTABLE()->WeightsvARB) -#define glWeightivARB (_GET_TLS_PROCTABLE()->WeightivARB) -#define glWeightfvARB (_GET_TLS_PROCTABLE()->WeightfvARB) -#define glWeightdvARB (_GET_TLS_PROCTABLE()->WeightdvARB) -#define glWeightubvARB (_GET_TLS_PROCTABLE()->WeightubvARB) -#define glWeightusvARB (_GET_TLS_PROCTABLE()->WeightusvARB) -#define glWeightuivARB (_GET_TLS_PROCTABLE()->WeightuivARB) -#define glWeightPointerARB (_GET_TLS_PROCTABLE()->WeightPointerARB) -#define glVertexBlendARB (_GET_TLS_PROCTABLE()->VertexBlendARB) -#define glCurrentPaletteMatrixARB (_GET_TLS_PROCTABLE()->CurrentPaletteMatrixARB) -#define glMatrixIndexubvARB (_GET_TLS_PROCTABLE()->MatrixIndexubvARB) -#define glMatrixIndexusvARB (_GET_TLS_PROCTABLE()->MatrixIndexusvARB) -#define glMatrixIndexuivARB (_GET_TLS_PROCTABLE()->MatrixIndexuivARB) -#define glMatrixIndexPointerARB (_GET_TLS_PROCTABLE()->MatrixIndexPointerARB) -#define glWindowPos2dARB (_GET_TLS_PROCTABLE()->WindowPos2dARB) -#define glWindowPos2dvARB (_GET_TLS_PROCTABLE()->WindowPos2dvARB) -#define glWindowPos2fARB (_GET_TLS_PROCTABLE()->WindowPos2fARB) -#define glWindowPos2fvARB (_GET_TLS_PROCTABLE()->WindowPos2fvARB) -#define glWindowPos2iARB (_GET_TLS_PROCTABLE()->WindowPos2iARB) -#define glWindowPos2ivARB (_GET_TLS_PROCTABLE()->WindowPos2ivARB) -#define glWindowPos2sARB (_GET_TLS_PROCTABLE()->WindowPos2sARB) -#define glWindowPos2svARB (_GET_TLS_PROCTABLE()->WindowPos2svARB) -#define glWindowPos3dARB (_GET_TLS_PROCTABLE()->WindowPos3dARB) -#define glWindowPos3dvARB (_GET_TLS_PROCTABLE()->WindowPos3dvARB) -#define glWindowPos3fARB (_GET_TLS_PROCTABLE()->WindowPos3fARB) -#define glWindowPos3fvARB (_GET_TLS_PROCTABLE()->WindowPos3fvARB) -#define glWindowPos3iARB (_GET_TLS_PROCTABLE()->WindowPos3iARB) -#define glWindowPos3ivARB (_GET_TLS_PROCTABLE()->WindowPos3ivARB) -#define glWindowPos3sARB (_GET_TLS_PROCTABLE()->WindowPos3sARB) -#define glWindowPos3svARB (_GET_TLS_PROCTABLE()->WindowPos3svARB) -#define glVertexAttrib1dARB (_GET_TLS_PROCTABLE()->VertexAttrib1dARB) -#define glVertexAttrib1dvARB (_GET_TLS_PROCTABLE()->VertexAttrib1dvARB) -#define glVertexAttrib1fARB (_GET_TLS_PROCTABLE()->VertexAttrib1fARB) -#define glVertexAttrib1fvARB (_GET_TLS_PROCTABLE()->VertexAttrib1fvARB) -#define glVertexAttrib1sARB (_GET_TLS_PROCTABLE()->VertexAttrib1sARB) -#define glVertexAttrib1svARB (_GET_TLS_PROCTABLE()->VertexAttrib1svARB) -#define glVertexAttrib2dARB (_GET_TLS_PROCTABLE()->VertexAttrib2dARB) -#define glVertexAttrib2dvARB (_GET_TLS_PROCTABLE()->VertexAttrib2dvARB) -#define glVertexAttrib2fARB (_GET_TLS_PROCTABLE()->VertexAttrib2fARB) -#define glVertexAttrib2fvARB (_GET_TLS_PROCTABLE()->VertexAttrib2fvARB) -#define glVertexAttrib2sARB (_GET_TLS_PROCTABLE()->VertexAttrib2sARB) -#define glVertexAttrib2svARB (_GET_TLS_PROCTABLE()->VertexAttrib2svARB) -#define glVertexAttrib3dARB (_GET_TLS_PROCTABLE()->VertexAttrib3dARB) -#define glVertexAttrib3dvARB (_GET_TLS_PROCTABLE()->VertexAttrib3dvARB) -#define glVertexAttrib3fARB (_GET_TLS_PROCTABLE()->VertexAttrib3fARB) -#define glVertexAttrib3fvARB (_GET_TLS_PROCTABLE()->VertexAttrib3fvARB) -#define glVertexAttrib3sARB (_GET_TLS_PROCTABLE()->VertexAttrib3sARB) -#define glVertexAttrib3svARB (_GET_TLS_PROCTABLE()->VertexAttrib3svARB) -#define glVertexAttrib4NbvARB (_GET_TLS_PROCTABLE()->VertexAttrib4NbvARB) -#define glVertexAttrib4NivARB (_GET_TLS_PROCTABLE()->VertexAttrib4NivARB) -#define glVertexAttrib4NsvARB (_GET_TLS_PROCTABLE()->VertexAttrib4NsvARB) -#define glVertexAttrib4NubARB (_GET_TLS_PROCTABLE()->VertexAttrib4NubARB) -#define glVertexAttrib4NubvARB (_GET_TLS_PROCTABLE()->VertexAttrib4NubvARB) -#define glVertexAttrib4NuivARB (_GET_TLS_PROCTABLE()->VertexAttrib4NuivARB) -#define glVertexAttrib4NusvARB (_GET_TLS_PROCTABLE()->VertexAttrib4NusvARB) -#define glVertexAttrib4bvARB (_GET_TLS_PROCTABLE()->VertexAttrib4bvARB) -#define glVertexAttrib4dARB (_GET_TLS_PROCTABLE()->VertexAttrib4dARB) -#define glVertexAttrib4dvARB (_GET_TLS_PROCTABLE()->VertexAttrib4dvARB) -#define glVertexAttrib4fARB (_GET_TLS_PROCTABLE()->VertexAttrib4fARB) -#define glVertexAttrib4fvARB (_GET_TLS_PROCTABLE()->VertexAttrib4fvARB) -#define glVertexAttrib4ivARB (_GET_TLS_PROCTABLE()->VertexAttrib4ivARB) -#define glVertexAttrib4sARB (_GET_TLS_PROCTABLE()->VertexAttrib4sARB) -#define glVertexAttrib4svARB (_GET_TLS_PROCTABLE()->VertexAttrib4svARB) -#define glVertexAttrib4ubvARB (_GET_TLS_PROCTABLE()->VertexAttrib4ubvARB) -#define glVertexAttrib4uivARB (_GET_TLS_PROCTABLE()->VertexAttrib4uivARB) -#define glVertexAttrib4usvARB (_GET_TLS_PROCTABLE()->VertexAttrib4usvARB) -#define glVertexAttribPointerARB (_GET_TLS_PROCTABLE()->VertexAttribPointerARB) -#define glEnableVertexAttribArrayARB (_GET_TLS_PROCTABLE()->EnableVertexAttribArrayARB) -#define glDisableVertexAttribArrayARB (_GET_TLS_PROCTABLE()->DisableVertexAttribArrayARB) -#define glProgramStringARB (_GET_TLS_PROCTABLE()->ProgramStringARB) -#define glBindProgramARB (_GET_TLS_PROCTABLE()->BindProgramARB) -#define glDeleteProgramsARB (_GET_TLS_PROCTABLE()->DeleteProgramsARB) -#define glGenProgramsARB (_GET_TLS_PROCTABLE()->GenProgramsARB) -#define glProgramEnvParameter4dARB (_GET_TLS_PROCTABLE()->ProgramEnvParameter4dARB) -#define glProgramEnvParameter4dvARB (_GET_TLS_PROCTABLE()->ProgramEnvParameter4dvARB) -#define glProgramEnvParameter4fARB (_GET_TLS_PROCTABLE()->ProgramEnvParameter4fARB) -#define glProgramEnvParameter4fvARB (_GET_TLS_PROCTABLE()->ProgramEnvParameter4fvARB) -#define glProgramLocalParameter4dARB (_GET_TLS_PROCTABLE()->ProgramLocalParameter4dARB) -#define glProgramLocalParameter4dvARB (_GET_TLS_PROCTABLE()->ProgramLocalParameter4dvARB) -#define glProgramLocalParameter4fARB (_GET_TLS_PROCTABLE()->ProgramLocalParameter4fARB) -#define glProgramLocalParameter4fvARB (_GET_TLS_PROCTABLE()->ProgramLocalParameter4fvARB) -#define glGetProgramEnvParameterdvARB (_GET_TLS_PROCTABLE()->GetProgramEnvParameterdvARB) -#define glGetProgramEnvParameterfvARB (_GET_TLS_PROCTABLE()->GetProgramEnvParameterfvARB) -#define glGetProgramLocalParameterdvARB (_GET_TLS_PROCTABLE()->GetProgramLocalParameterdvARB) -#define glGetProgramLocalParameterfvARB (_GET_TLS_PROCTABLE()->GetProgramLocalParameterfvARB) -#define glGetProgramivARB (_GET_TLS_PROCTABLE()->GetProgramivARB) -#define glGetProgramStringARB (_GET_TLS_PROCTABLE()->GetProgramStringARB) -#define glGetVertexAttribdvARB (_GET_TLS_PROCTABLE()->GetVertexAttribdvARB) -#define glGetVertexAttribfvARB (_GET_TLS_PROCTABLE()->GetVertexAttribfvARB) -#define glGetVertexAttribivARB (_GET_TLS_PROCTABLE()->GetVertexAttribivARB) -#define glGetVertexAttribPointervARB (_GET_TLS_PROCTABLE()->GetVertexAttribPointervARB) -#define glIsProgramARB (_GET_TLS_PROCTABLE()->IsProgramARB) -#define glBindBufferARB (_GET_TLS_PROCTABLE()->BindBufferARB) -#define glDeleteBuffersARB (_GET_TLS_PROCTABLE()->DeleteBuffersARB) -#define glGenBuffersARB (_GET_TLS_PROCTABLE()->GenBuffersARB) -#define glIsBufferARB (_GET_TLS_PROCTABLE()->IsBufferARB) -#define glBufferDataARB (_GET_TLS_PROCTABLE()->BufferDataARB) -#define glBufferSubDataARB (_GET_TLS_PROCTABLE()->BufferSubDataARB) -#define glGetBufferSubDataARB (_GET_TLS_PROCTABLE()->GetBufferSubDataARB) -#define glMapBufferARB (_GET_TLS_PROCTABLE()->MapBufferARB) -#define glUnmapBufferARB (_GET_TLS_PROCTABLE()->UnmapBufferARB) -#define glGetBufferParameterivARB (_GET_TLS_PROCTABLE()->GetBufferParameterivARB) -#define glGetBufferPointervARB (_GET_TLS_PROCTABLE()->GetBufferPointervARB) -#define glGenQueriesARB (_GET_TLS_PROCTABLE()->GenQueriesARB) -#define glDeleteQueriesARB (_GET_TLS_PROCTABLE()->DeleteQueriesARB) -#define glIsQueryARB (_GET_TLS_PROCTABLE()->IsQueryARB) -#define glBeginQueryARB (_GET_TLS_PROCTABLE()->BeginQueryARB) -#define glEndQueryARB (_GET_TLS_PROCTABLE()->EndQueryARB) -#define glGetQueryivARB (_GET_TLS_PROCTABLE()->GetQueryivARB) -#define glGetQueryObjectivARB (_GET_TLS_PROCTABLE()->GetQueryObjectivARB) -#define glGetQueryObjectuivARB (_GET_TLS_PROCTABLE()->GetQueryObjectuivARB) -#define glDeleteObjectARB (_GET_TLS_PROCTABLE()->DeleteObjectARB) -#define glGetHandleARB (_GET_TLS_PROCTABLE()->GetHandleARB) -#define glDetachObjectARB (_GET_TLS_PROCTABLE()->DetachObjectARB) -#define glCreateShaderObjectARB (_GET_TLS_PROCTABLE()->CreateShaderObjectARB) -#define glShaderSourceARB (_GET_TLS_PROCTABLE()->ShaderSourceARB) -#define glCompileShaderARB (_GET_TLS_PROCTABLE()->CompileShaderARB) -#define glCreateProgramObjectARB (_GET_TLS_PROCTABLE()->CreateProgramObjectARB) -#define glAttachObjectARB (_GET_TLS_PROCTABLE()->AttachObjectARB) -#define glLinkProgramARB (_GET_TLS_PROCTABLE()->LinkProgramARB) -#define glUseProgramObjectARB (_GET_TLS_PROCTABLE()->UseProgramObjectARB) -#define glValidateProgramARB (_GET_TLS_PROCTABLE()->ValidateProgramARB) -#define glUniform1fARB (_GET_TLS_PROCTABLE()->Uniform1fARB) -#define glUniform2fARB (_GET_TLS_PROCTABLE()->Uniform2fARB) -#define glUniform3fARB (_GET_TLS_PROCTABLE()->Uniform3fARB) -#define glUniform4fARB (_GET_TLS_PROCTABLE()->Uniform4fARB) -#define glUniform1iARB (_GET_TLS_PROCTABLE()->Uniform1iARB) -#define glUniform2iARB (_GET_TLS_PROCTABLE()->Uniform2iARB) -#define glUniform3iARB (_GET_TLS_PROCTABLE()->Uniform3iARB) -#define glUniform4iARB (_GET_TLS_PROCTABLE()->Uniform4iARB) -#define glUniform1fvARB (_GET_TLS_PROCTABLE()->Uniform1fvARB) -#define glUniform2fvARB (_GET_TLS_PROCTABLE()->Uniform2fvARB) -#define glUniform3fvARB (_GET_TLS_PROCTABLE()->Uniform3fvARB) -#define glUniform4fvARB (_GET_TLS_PROCTABLE()->Uniform4fvARB) -#define glUniform1ivARB (_GET_TLS_PROCTABLE()->Uniform1ivARB) -#define glUniform2ivARB (_GET_TLS_PROCTABLE()->Uniform2ivARB) -#define glUniform3ivARB (_GET_TLS_PROCTABLE()->Uniform3ivARB) -#define glUniform4ivARB (_GET_TLS_PROCTABLE()->Uniform4ivARB) -#define glUniformMatrix2fvARB (_GET_TLS_PROCTABLE()->UniformMatrix2fvARB) -#define glUniformMatrix3fvARB (_GET_TLS_PROCTABLE()->UniformMatrix3fvARB) -#define glUniformMatrix4fvARB (_GET_TLS_PROCTABLE()->UniformMatrix4fvARB) -#define glGetObjectParameterfvARB (_GET_TLS_PROCTABLE()->GetObjectParameterfvARB) -#define glGetObjectParameterivARB (_GET_TLS_PROCTABLE()->GetObjectParameterivARB) -#define glGetInfoLogARB (_GET_TLS_PROCTABLE()->GetInfoLogARB) -#define glGetAttachedObjectsARB (_GET_TLS_PROCTABLE()->GetAttachedObjectsARB) -#define glGetUniformLocationARB (_GET_TLS_PROCTABLE()->GetUniformLocationARB) -#define glGetActiveUniformARB (_GET_TLS_PROCTABLE()->GetActiveUniformARB) -#define glGetUniformfvARB (_GET_TLS_PROCTABLE()->GetUniformfvARB) -#define glGetUniformivARB (_GET_TLS_PROCTABLE()->GetUniformivARB) -#define glGetShaderSourceARB (_GET_TLS_PROCTABLE()->GetShaderSourceARB) -#define glBindAttribLocationARB (_GET_TLS_PROCTABLE()->BindAttribLocationARB) -#define glGetActiveAttribARB (_GET_TLS_PROCTABLE()->GetActiveAttribARB) -#define glGetAttribLocationARB (_GET_TLS_PROCTABLE()->GetAttribLocationARB) -#define glBlendColorEXT (_GET_TLS_PROCTABLE()->BlendColorEXT) -#define glPolygonOffsetEXT (_GET_TLS_PROCTABLE()->PolygonOffsetEXT) -#define glTexImage3DEXT (_GET_TLS_PROCTABLE()->TexImage3DEXT) -#define glTexSubImage3DEXT (_GET_TLS_PROCTABLE()->TexSubImage3DEXT) -#define glGetTexFilterFuncSGIS (_GET_TLS_PROCTABLE()->GetTexFilterFuncSGIS) -#define glTexFilterFuncSGIS (_GET_TLS_PROCTABLE()->TexFilterFuncSGIS) -#define glTexSubImage1DEXT (_GET_TLS_PROCTABLE()->TexSubImage1DEXT) -#define glTexSubImage2DEXT (_GET_TLS_PROCTABLE()->TexSubImage2DEXT) -#define glCopyTexImage1DEXT (_GET_TLS_PROCTABLE()->CopyTexImage1DEXT) -#define glCopyTexImage2DEXT (_GET_TLS_PROCTABLE()->CopyTexImage2DEXT) -#define glCopyTexSubImage1DEXT (_GET_TLS_PROCTABLE()->CopyTexSubImage1DEXT) -#define glCopyTexSubImage2DEXT (_GET_TLS_PROCTABLE()->CopyTexSubImage2DEXT) -#define glCopyTexSubImage3DEXT (_GET_TLS_PROCTABLE()->CopyTexSubImage3DEXT) -#define glGetHistogramEXT (_GET_TLS_PROCTABLE()->GetHistogramEXT) -#define glGetHistogramParameterfvEXT (_GET_TLS_PROCTABLE()->GetHistogramParameterfvEXT) -#define glGetHistogramParameterivEXT (_GET_TLS_PROCTABLE()->GetHistogramParameterivEXT) -#define glGetMinmaxEXT (_GET_TLS_PROCTABLE()->GetMinmaxEXT) -#define glGetMinmaxParameterfvEXT (_GET_TLS_PROCTABLE()->GetMinmaxParameterfvEXT) -#define glGetMinmaxParameterivEXT (_GET_TLS_PROCTABLE()->GetMinmaxParameterivEXT) -#define glHistogramEXT (_GET_TLS_PROCTABLE()->HistogramEXT) -#define glMinmaxEXT (_GET_TLS_PROCTABLE()->MinmaxEXT) -#define glResetHistogramEXT (_GET_TLS_PROCTABLE()->ResetHistogramEXT) -#define glResetMinmaxEXT (_GET_TLS_PROCTABLE()->ResetMinmaxEXT) -#define glConvolutionFilter1DEXT (_GET_TLS_PROCTABLE()->ConvolutionFilter1DEXT) -#define glConvolutionFilter2DEXT (_GET_TLS_PROCTABLE()->ConvolutionFilter2DEXT) -#define glConvolutionParameterfEXT (_GET_TLS_PROCTABLE()->ConvolutionParameterfEXT) -#define glConvolutionParameterfvEXT (_GET_TLS_PROCTABLE()->ConvolutionParameterfvEXT) -#define glConvolutionParameteriEXT (_GET_TLS_PROCTABLE()->ConvolutionParameteriEXT) -#define glConvolutionParameterivEXT (_GET_TLS_PROCTABLE()->ConvolutionParameterivEXT) -#define glCopyConvolutionFilter1DEXT (_GET_TLS_PROCTABLE()->CopyConvolutionFilter1DEXT) -#define glCopyConvolutionFilter2DEXT (_GET_TLS_PROCTABLE()->CopyConvolutionFilter2DEXT) -#define glGetConvolutionFilterEXT (_GET_TLS_PROCTABLE()->GetConvolutionFilterEXT) -#define glGetConvolutionParameterfvEXT (_GET_TLS_PROCTABLE()->GetConvolutionParameterfvEXT) -#define glGetConvolutionParameterivEXT (_GET_TLS_PROCTABLE()->GetConvolutionParameterivEXT) -#define glGetSeparableFilterEXT (_GET_TLS_PROCTABLE()->GetSeparableFilterEXT) -#define glSeparableFilter2DEXT (_GET_TLS_PROCTABLE()->SeparableFilter2DEXT) -#define glColorTableSGI (_GET_TLS_PROCTABLE()->ColorTableSGI) -#define glColorTableParameterfvSGI (_GET_TLS_PROCTABLE()->ColorTableParameterfvSGI) -#define glColorTableParameterivSGI (_GET_TLS_PROCTABLE()->ColorTableParameterivSGI) -#define glCopyColorTableSGI (_GET_TLS_PROCTABLE()->CopyColorTableSGI) -#define glGetColorTableSGI (_GET_TLS_PROCTABLE()->GetColorTableSGI) -#define glGetColorTableParameterfvSGI (_GET_TLS_PROCTABLE()->GetColorTableParameterfvSGI) -#define glGetColorTableParameterivSGI (_GET_TLS_PROCTABLE()->GetColorTableParameterivSGI) -#define glPixelTexGenSGIX (_GET_TLS_PROCTABLE()->PixelTexGenSGIX) -#define glPixelTexGenParameteriSGIS (_GET_TLS_PROCTABLE()->PixelTexGenParameteriSGIS) -#define glPixelTexGenParameterivSGIS (_GET_TLS_PROCTABLE()->PixelTexGenParameterivSGIS) -#define glPixelTexGenParameterfSGIS (_GET_TLS_PROCTABLE()->PixelTexGenParameterfSGIS) -#define glPixelTexGenParameterfvSGIS (_GET_TLS_PROCTABLE()->PixelTexGenParameterfvSGIS) -#define glGetPixelTexGenParameterivSGIS (_GET_TLS_PROCTABLE()->GetPixelTexGenParameterivSGIS) -#define glGetPixelTexGenParameterfvSGIS (_GET_TLS_PROCTABLE()->GetPixelTexGenParameterfvSGIS) -#define glTexImage4DSGIS (_GET_TLS_PROCTABLE()->TexImage4DSGIS) -#define glTexSubImage4DSGIS (_GET_TLS_PROCTABLE()->TexSubImage4DSGIS) -#define glAreTexturesResidentEXT (_GET_TLS_PROCTABLE()->AreTexturesResidentEXT) -#define glBindTextureEXT (_GET_TLS_PROCTABLE()->BindTextureEXT) -#define glDeleteTexturesEXT (_GET_TLS_PROCTABLE()->DeleteTexturesEXT) -#define glGenTexturesEXT (_GET_TLS_PROCTABLE()->GenTexturesEXT) -#define glIsTextureEXT (_GET_TLS_PROCTABLE()->IsTextureEXT) -#define glPrioritizeTexturesEXT (_GET_TLS_PROCTABLE()->PrioritizeTexturesEXT) -#define glDetailTexFuncSGIS (_GET_TLS_PROCTABLE()->DetailTexFuncSGIS) -#define glGetDetailTexFuncSGIS (_GET_TLS_PROCTABLE()->GetDetailTexFuncSGIS) -#define glSharpenTexFuncSGIS (_GET_TLS_PROCTABLE()->SharpenTexFuncSGIS) -#define glGetSharpenTexFuncSGIS (_GET_TLS_PROCTABLE()->GetSharpenTexFuncSGIS) -#define glSampleMaskSGIS (_GET_TLS_PROCTABLE()->SampleMaskSGIS) -#define glSamplePatternSGIS (_GET_TLS_PROCTABLE()->SamplePatternSGIS) -#define glArrayElementEXT (_GET_TLS_PROCTABLE()->ArrayElementEXT) -#define glColorPointerEXT (_GET_TLS_PROCTABLE()->ColorPointerEXT) -#define glDrawArraysEXT (_GET_TLS_PROCTABLE()->DrawArraysEXT) -#define glEdgeFlagPointerEXT (_GET_TLS_PROCTABLE()->EdgeFlagPointerEXT) -#define glGetPointervEXT (_GET_TLS_PROCTABLE()->GetPointervEXT) -#define glIndexPointerEXT (_GET_TLS_PROCTABLE()->IndexPointerEXT) -#define glNormalPointerEXT (_GET_TLS_PROCTABLE()->NormalPointerEXT) -#define glTexCoordPointerEXT (_GET_TLS_PROCTABLE()->TexCoordPointerEXT) -#define glVertexPointerEXT (_GET_TLS_PROCTABLE()->VertexPointerEXT) -#define glBlendEquationEXT (_GET_TLS_PROCTABLE()->BlendEquationEXT) -#define glSpriteParameterfSGIX (_GET_TLS_PROCTABLE()->SpriteParameterfSGIX) -#define glSpriteParameterfvSGIX (_GET_TLS_PROCTABLE()->SpriteParameterfvSGIX) -#define glSpriteParameteriSGIX (_GET_TLS_PROCTABLE()->SpriteParameteriSGIX) -#define glSpriteParameterivSGIX (_GET_TLS_PROCTABLE()->SpriteParameterivSGIX) -#define glPointParameterfEXT (_GET_TLS_PROCTABLE()->PointParameterfEXT) -#define glPointParameterfvEXT (_GET_TLS_PROCTABLE()->PointParameterfvEXT) -#define glPointParameterfSGIS (_GET_TLS_PROCTABLE()->PointParameterfSGIS) -#define glPointParameterfvSGIS (_GET_TLS_PROCTABLE()->PointParameterfvSGIS) -#define glGetInstrumentsSGIX (_GET_TLS_PROCTABLE()->GetInstrumentsSGIX) -#define glInstrumentsBufferSGIX (_GET_TLS_PROCTABLE()->InstrumentsBufferSGIX) -#define glPollInstrumentsSGIX (_GET_TLS_PROCTABLE()->PollInstrumentsSGIX) -#define glReadInstrumentsSGIX (_GET_TLS_PROCTABLE()->ReadInstrumentsSGIX) -#define glStartInstrumentsSGIX (_GET_TLS_PROCTABLE()->StartInstrumentsSGIX) -#define glStopInstrumentsSGIX (_GET_TLS_PROCTABLE()->StopInstrumentsSGIX) -#define glFrameZoomSGIX (_GET_TLS_PROCTABLE()->FrameZoomSGIX) -#define glTagSampleBufferSGIX (_GET_TLS_PROCTABLE()->TagSampleBufferSGIX) -#define glDeformationMap3dSGIX (_GET_TLS_PROCTABLE()->DeformationMap3dSGIX) -#define glDeformationMap3fSGIX (_GET_TLS_PROCTABLE()->DeformationMap3fSGIX) -#define glDeformSGIX (_GET_TLS_PROCTABLE()->DeformSGIX) -#define glLoadIdentityDeformationMapSGIX (_GET_TLS_PROCTABLE()->LoadIdentityDeformationMapSGIX) -#define glReferencePlaneSGIX (_GET_TLS_PROCTABLE()->ReferencePlaneSGIX) -#define glFlushRasterSGIX (_GET_TLS_PROCTABLE()->FlushRasterSGIX) -#define glFogFuncSGIS (_GET_TLS_PROCTABLE()->FogFuncSGIS) -#define glGetFogFuncSGIS (_GET_TLS_PROCTABLE()->GetFogFuncSGIS) -#define glImageTransformParameteriHP (_GET_TLS_PROCTABLE()->ImageTransformParameteriHP) -#define glImageTransformParameterfHP (_GET_TLS_PROCTABLE()->ImageTransformParameterfHP) -#define glImageTransformParameterivHP (_GET_TLS_PROCTABLE()->ImageTransformParameterivHP) -#define glImageTransformParameterfvHP (_GET_TLS_PROCTABLE()->ImageTransformParameterfvHP) -#define glGetImageTransformParameterivHP (_GET_TLS_PROCTABLE()->GetImageTransformParameterivHP) -#define glGetImageTransformParameterfvHP (_GET_TLS_PROCTABLE()->GetImageTransformParameterfvHP) -#define glColorSubTableEXT (_GET_TLS_PROCTABLE()->ColorSubTableEXT) -#define glCopyColorSubTableEXT (_GET_TLS_PROCTABLE()->CopyColorSubTableEXT) -#define glHintPGI (_GET_TLS_PROCTABLE()->HintPGI) -#define glColorTableEXT (_GET_TLS_PROCTABLE()->ColorTableEXT) -#define glGetColorTableEXT (_GET_TLS_PROCTABLE()->GetColorTableEXT) -#define glGetColorTableParameterivEXT (_GET_TLS_PROCTABLE()->GetColorTableParameterivEXT) -#define glGetColorTableParameterfvEXT (_GET_TLS_PROCTABLE()->GetColorTableParameterfvEXT) -#define glGetListParameterfvSGIX (_GET_TLS_PROCTABLE()->GetListParameterfvSGIX) -#define glGetListParameterivSGIX (_GET_TLS_PROCTABLE()->GetListParameterivSGIX) -#define glListParameterfSGIX (_GET_TLS_PROCTABLE()->ListParameterfSGIX) -#define glListParameterfvSGIX (_GET_TLS_PROCTABLE()->ListParameterfvSGIX) -#define glListParameteriSGIX (_GET_TLS_PROCTABLE()->ListParameteriSGIX) -#define glListParameterivSGIX (_GET_TLS_PROCTABLE()->ListParameterivSGIX) -#define glIndexMaterialEXT (_GET_TLS_PROCTABLE()->IndexMaterialEXT) -#define glIndexFuncEXT (_GET_TLS_PROCTABLE()->IndexFuncEXT) -#define glLockArraysEXT (_GET_TLS_PROCTABLE()->LockArraysEXT) -#define glUnlockArraysEXT (_GET_TLS_PROCTABLE()->UnlockArraysEXT) -#define glCullParameterdvEXT (_GET_TLS_PROCTABLE()->CullParameterdvEXT) -#define glCullParameterfvEXT (_GET_TLS_PROCTABLE()->CullParameterfvEXT) -#define glFragmentColorMaterialSGIX (_GET_TLS_PROCTABLE()->FragmentColorMaterialSGIX) -#define glFragmentLightfSGIX (_GET_TLS_PROCTABLE()->FragmentLightfSGIX) -#define glFragmentLightfvSGIX (_GET_TLS_PROCTABLE()->FragmentLightfvSGIX) -#define glFragmentLightiSGIX (_GET_TLS_PROCTABLE()->FragmentLightiSGIX) -#define glFragmentLightivSGIX (_GET_TLS_PROCTABLE()->FragmentLightivSGIX) -#define glFragmentLightModelfSGIX (_GET_TLS_PROCTABLE()->FragmentLightModelfSGIX) -#define glFragmentLightModelfvSGIX (_GET_TLS_PROCTABLE()->FragmentLightModelfvSGIX) -#define glFragmentLightModeliSGIX (_GET_TLS_PROCTABLE()->FragmentLightModeliSGIX) -#define glFragmentLightModelivSGIX (_GET_TLS_PROCTABLE()->FragmentLightModelivSGIX) -#define glFragmentMaterialfSGIX (_GET_TLS_PROCTABLE()->FragmentMaterialfSGIX) -#define glFragmentMaterialfvSGIX (_GET_TLS_PROCTABLE()->FragmentMaterialfvSGIX) -#define glFragmentMaterialiSGIX (_GET_TLS_PROCTABLE()->FragmentMaterialiSGIX) -#define glFragmentMaterialivSGIX (_GET_TLS_PROCTABLE()->FragmentMaterialivSGIX) -#define glGetFragmentLightfvSGIX (_GET_TLS_PROCTABLE()->GetFragmentLightfvSGIX) -#define glGetFragmentLightivSGIX (_GET_TLS_PROCTABLE()->GetFragmentLightivSGIX) -#define glGetFragmentMaterialfvSGIX (_GET_TLS_PROCTABLE()->GetFragmentMaterialfvSGIX) -#define glGetFragmentMaterialivSGIX (_GET_TLS_PROCTABLE()->GetFragmentMaterialivSGIX) -#define glLightEnviSGIX (_GET_TLS_PROCTABLE()->LightEnviSGIX) -#define glDrawRangeElementsEXT (_GET_TLS_PROCTABLE()->DrawRangeElementsEXT) -#define glApplyTextureEXT (_GET_TLS_PROCTABLE()->ApplyTextureEXT) -#define glTextureLightEXT (_GET_TLS_PROCTABLE()->TextureLightEXT) -#define glTextureMaterialEXT (_GET_TLS_PROCTABLE()->TextureMaterialEXT) -#define glAsyncMarkerSGIX (_GET_TLS_PROCTABLE()->AsyncMarkerSGIX) -#define glFinishAsyncSGIX (_GET_TLS_PROCTABLE()->FinishAsyncSGIX) -#define glPollAsyncSGIX (_GET_TLS_PROCTABLE()->PollAsyncSGIX) -#define glGenAsyncMarkersSGIX (_GET_TLS_PROCTABLE()->GenAsyncMarkersSGIX) -#define glDeleteAsyncMarkersSGIX (_GET_TLS_PROCTABLE()->DeleteAsyncMarkersSGIX) -#define glIsAsyncMarkerSGIX (_GET_TLS_PROCTABLE()->IsAsyncMarkerSGIX) -#define glVertexPointervINTEL (_GET_TLS_PROCTABLE()->VertexPointervINTEL) -#define glNormalPointervINTEL (_GET_TLS_PROCTABLE()->NormalPointervINTEL) -#define glColorPointervINTEL (_GET_TLS_PROCTABLE()->ColorPointervINTEL) -#define glTexCoordPointervINTEL (_GET_TLS_PROCTABLE()->TexCoordPointervINTEL) -#define glPixelTransformParameteriEXT (_GET_TLS_PROCTABLE()->PixelTransformParameteriEXT) -#define glPixelTransformParameterfEXT (_GET_TLS_PROCTABLE()->PixelTransformParameterfEXT) -#define glPixelTransformParameterivEXT (_GET_TLS_PROCTABLE()->PixelTransformParameterivEXT) -#define glPixelTransformParameterfvEXT (_GET_TLS_PROCTABLE()->PixelTransformParameterfvEXT) -#define glSecondaryColor3bEXT (_GET_TLS_PROCTABLE()->SecondaryColor3bEXT) -#define glSecondaryColor3bvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3bvEXT) -#define glSecondaryColor3dEXT (_GET_TLS_PROCTABLE()->SecondaryColor3dEXT) -#define glSecondaryColor3dvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3dvEXT) -#define glSecondaryColor3fEXT (_GET_TLS_PROCTABLE()->SecondaryColor3fEXT) -#define glSecondaryColor3fvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3fvEXT) -#define glSecondaryColor3iEXT (_GET_TLS_PROCTABLE()->SecondaryColor3iEXT) -#define glSecondaryColor3ivEXT (_GET_TLS_PROCTABLE()->SecondaryColor3ivEXT) -#define glSecondaryColor3sEXT (_GET_TLS_PROCTABLE()->SecondaryColor3sEXT) -#define glSecondaryColor3svEXT (_GET_TLS_PROCTABLE()->SecondaryColor3svEXT) -#define glSecondaryColor3ubEXT (_GET_TLS_PROCTABLE()->SecondaryColor3ubEXT) -#define glSecondaryColor3ubvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3ubvEXT) -#define glSecondaryColor3uiEXT (_GET_TLS_PROCTABLE()->SecondaryColor3uiEXT) -#define glSecondaryColor3uivEXT (_GET_TLS_PROCTABLE()->SecondaryColor3uivEXT) -#define glSecondaryColor3usEXT (_GET_TLS_PROCTABLE()->SecondaryColor3usEXT) -#define glSecondaryColor3usvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3usvEXT) -#define glSecondaryColorPointerEXT (_GET_TLS_PROCTABLE()->SecondaryColorPointerEXT) -#define glTextureNormalEXT (_GET_TLS_PROCTABLE()->TextureNormalEXT) -#define glMultiDrawArraysEXT (_GET_TLS_PROCTABLE()->MultiDrawArraysEXT) -#define glMultiDrawElementsEXT (_GET_TLS_PROCTABLE()->MultiDrawElementsEXT) -#define glFogCoordfEXT (_GET_TLS_PROCTABLE()->FogCoordfEXT) -#define glFogCoordfvEXT (_GET_TLS_PROCTABLE()->FogCoordfvEXT) -#define glFogCoorddEXT (_GET_TLS_PROCTABLE()->FogCoorddEXT) -#define glFogCoorddvEXT (_GET_TLS_PROCTABLE()->FogCoorddvEXT) -#define glFogCoordPointerEXT (_GET_TLS_PROCTABLE()->FogCoordPointerEXT) -#define glTangent3bEXT (_GET_TLS_PROCTABLE()->Tangent3bEXT) -#define glTangent3bvEXT (_GET_TLS_PROCTABLE()->Tangent3bvEXT) -#define glTangent3dEXT (_GET_TLS_PROCTABLE()->Tangent3dEXT) -#define glTangent3dvEXT (_GET_TLS_PROCTABLE()->Tangent3dvEXT) -#define glTangent3fEXT (_GET_TLS_PROCTABLE()->Tangent3fEXT) -#define glTangent3fvEXT (_GET_TLS_PROCTABLE()->Tangent3fvEXT) -#define glTangent3iEXT (_GET_TLS_PROCTABLE()->Tangent3iEXT) -#define glTangent3ivEXT (_GET_TLS_PROCTABLE()->Tangent3ivEXT) -#define glTangent3sEXT (_GET_TLS_PROCTABLE()->Tangent3sEXT) -#define glTangent3svEXT (_GET_TLS_PROCTABLE()->Tangent3svEXT) -#define glBinormal3bEXT (_GET_TLS_PROCTABLE()->Binormal3bEXT) -#define glBinormal3bvEXT (_GET_TLS_PROCTABLE()->Binormal3bvEXT) -#define glBinormal3dEXT (_GET_TLS_PROCTABLE()->Binormal3dEXT) -#define glBinormal3dvEXT (_GET_TLS_PROCTABLE()->Binormal3dvEXT) -#define glBinormal3fEXT (_GET_TLS_PROCTABLE()->Binormal3fEXT) -#define glBinormal3fvEXT (_GET_TLS_PROCTABLE()->Binormal3fvEXT) -#define glBinormal3iEXT (_GET_TLS_PROCTABLE()->Binormal3iEXT) -#define glBinormal3ivEXT (_GET_TLS_PROCTABLE()->Binormal3ivEXT) -#define glBinormal3sEXT (_GET_TLS_PROCTABLE()->Binormal3sEXT) -#define glBinormal3svEXT (_GET_TLS_PROCTABLE()->Binormal3svEXT) -#define glTangentPointerEXT (_GET_TLS_PROCTABLE()->TangentPointerEXT) -#define glBinormalPointerEXT (_GET_TLS_PROCTABLE()->BinormalPointerEXT) -#define glFinishTextureSUNX (_GET_TLS_PROCTABLE()->FinishTextureSUNX) -#define glGlobalAlphaFactorbSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorbSUN) -#define glGlobalAlphaFactorsSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorsSUN) -#define glGlobalAlphaFactoriSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactoriSUN) -#define glGlobalAlphaFactorfSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorfSUN) -#define glGlobalAlphaFactordSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactordSUN) -#define glGlobalAlphaFactorubSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorubSUN) -#define glGlobalAlphaFactorusSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorusSUN) -#define glGlobalAlphaFactoruiSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactoruiSUN) -#define glReplacementCodeuiSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiSUN) -#define glReplacementCodeusSUN (_GET_TLS_PROCTABLE()->ReplacementCodeusSUN) -#define glReplacementCodeubSUN (_GET_TLS_PROCTABLE()->ReplacementCodeubSUN) -#define glReplacementCodeuivSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuivSUN) -#define glReplacementCodeusvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeusvSUN) -#define glReplacementCodeubvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeubvSUN) -#define glReplacementCodePointerSUN (_GET_TLS_PROCTABLE()->ReplacementCodePointerSUN) -#define glColor4ubVertex2fSUN (_GET_TLS_PROCTABLE()->Color4ubVertex2fSUN) -#define glColor4ubVertex2fvSUN (_GET_TLS_PROCTABLE()->Color4ubVertex2fvSUN) -#define glColor4ubVertex3fSUN (_GET_TLS_PROCTABLE()->Color4ubVertex3fSUN) -#define glColor4ubVertex3fvSUN (_GET_TLS_PROCTABLE()->Color4ubVertex3fvSUN) -#define glColor3fVertex3fSUN (_GET_TLS_PROCTABLE()->Color3fVertex3fSUN) -#define glColor3fVertex3fvSUN (_GET_TLS_PROCTABLE()->Color3fVertex3fvSUN) -#define glNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->Normal3fVertex3fSUN) -#define glNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->Normal3fVertex3fvSUN) -#define glColor4fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->Color4fNormal3fVertex3fSUN) -#define glColor4fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->Color4fNormal3fVertex3fvSUN) -#define glTexCoord2fVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fVertex3fSUN) -#define glTexCoord2fVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fVertex3fvSUN) -#define glTexCoord4fVertex4fSUN (_GET_TLS_PROCTABLE()->TexCoord4fVertex4fSUN) -#define glTexCoord4fVertex4fvSUN (_GET_TLS_PROCTABLE()->TexCoord4fVertex4fvSUN) -#define glTexCoord2fColor4ubVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor4ubVertex3fSUN) -#define glTexCoord2fColor4ubVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor4ubVertex3fvSUN) -#define glTexCoord2fColor3fVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor3fVertex3fSUN) -#define glTexCoord2fColor3fVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor3fVertex3fvSUN) -#define glTexCoord2fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fNormal3fVertex3fSUN) -#define glTexCoord2fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fNormal3fVertex3fvSUN) -#define glTexCoord2fColor4fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor4fNormal3fVertex3fSUN) -#define glTexCoord2fColor4fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor4fNormal3fVertex3fvSUN) -#define glTexCoord4fColor4fNormal3fVertex4fSUN (_GET_TLS_PROCTABLE()->TexCoord4fColor4fNormal3fVertex4fSUN) -#define glTexCoord4fColor4fNormal3fVertex4fvSUN (_GET_TLS_PROCTABLE()->TexCoord4fColor4fNormal3fVertex4fvSUN) -#define glReplacementCodeuiVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiVertex3fSUN) -#define glReplacementCodeuiVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiVertex3fvSUN) -#define glReplacementCodeuiColor4ubVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor4ubVertex3fSUN) -#define glReplacementCodeuiColor4ubVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor4ubVertex3fvSUN) -#define glReplacementCodeuiColor3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor3fVertex3fSUN) -#define glReplacementCodeuiColor3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor3fVertex3fvSUN) -#define glReplacementCodeuiNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiNormal3fVertex3fSUN) -#define glReplacementCodeuiNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiNormal3fVertex3fvSUN) -#define glReplacementCodeuiColor4fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor4fNormal3fVertex3fSUN) -#define glReplacementCodeuiColor4fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor4fNormal3fVertex3fvSUN) -#define glReplacementCodeuiTexCoord2fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fVertex3fSUN) -#define glReplacementCodeuiTexCoord2fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fVertex3fvSUN) -#define glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fNormal3fVertex3fSUN) -#define glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN) -#define glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN) -#define glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN) -#define glBlendFuncSeparateEXT (_GET_TLS_PROCTABLE()->BlendFuncSeparateEXT) -#define glBlendFuncSeparateINGR (_GET_TLS_PROCTABLE()->BlendFuncSeparateINGR) -#define glVertexWeightfEXT (_GET_TLS_PROCTABLE()->VertexWeightfEXT) -#define glVertexWeightfvEXT (_GET_TLS_PROCTABLE()->VertexWeightfvEXT) -#define glVertexWeightPointerEXT (_GET_TLS_PROCTABLE()->VertexWeightPointerEXT) -#define glFlushVertexArrayRangeNV (_GET_TLS_PROCTABLE()->FlushVertexArrayRangeNV) -#define glVertexArrayRangeNV (_GET_TLS_PROCTABLE()->VertexArrayRangeNV) -#define glCombinerParameterfvNV (_GET_TLS_PROCTABLE()->CombinerParameterfvNV) -#define glCombinerParameterfNV (_GET_TLS_PROCTABLE()->CombinerParameterfNV) -#define glCombinerParameterivNV (_GET_TLS_PROCTABLE()->CombinerParameterivNV) -#define glCombinerParameteriNV (_GET_TLS_PROCTABLE()->CombinerParameteriNV) -#define glCombinerInputNV (_GET_TLS_PROCTABLE()->CombinerInputNV) -#define glCombinerOutputNV (_GET_TLS_PROCTABLE()->CombinerOutputNV) -#define glFinalCombinerInputNV (_GET_TLS_PROCTABLE()->FinalCombinerInputNV) -#define glGetCombinerInputParameterfvNV (_GET_TLS_PROCTABLE()->GetCombinerInputParameterfvNV) -#define glGetCombinerInputParameterivNV (_GET_TLS_PROCTABLE()->GetCombinerInputParameterivNV) -#define glGetCombinerOutputParameterfvNV (_GET_TLS_PROCTABLE()->GetCombinerOutputParameterfvNV) -#define glGetCombinerOutputParameterivNV (_GET_TLS_PROCTABLE()->GetCombinerOutputParameterivNV) -#define glGetFinalCombinerInputParameterfvNV (_GET_TLS_PROCTABLE()->GetFinalCombinerInputParameterfvNV) -#define glGetFinalCombinerInputParameterivNV (_GET_TLS_PROCTABLE()->GetFinalCombinerInputParameterivNV) -#define glResizeBuffersMESA (_GET_TLS_PROCTABLE()->ResizeBuffersMESA) -#define glWindowPos2dMESA (_GET_TLS_PROCTABLE()->WindowPos2dMESA) -#define glWindowPos2dvMESA (_GET_TLS_PROCTABLE()->WindowPos2dvMESA) -#define glWindowPos2fMESA (_GET_TLS_PROCTABLE()->WindowPos2fMESA) -#define glWindowPos2fvMESA (_GET_TLS_PROCTABLE()->WindowPos2fvMESA) -#define glWindowPos2iMESA (_GET_TLS_PROCTABLE()->WindowPos2iMESA) -#define glWindowPos2ivMESA (_GET_TLS_PROCTABLE()->WindowPos2ivMESA) -#define glWindowPos2sMESA (_GET_TLS_PROCTABLE()->WindowPos2sMESA) -#define glWindowPos2svMESA (_GET_TLS_PROCTABLE()->WindowPos2svMESA) -#define glWindowPos3dMESA (_GET_TLS_PROCTABLE()->WindowPos3dMESA) -#define glWindowPos3dvMESA (_GET_TLS_PROCTABLE()->WindowPos3dvMESA) -#define glWindowPos3fMESA (_GET_TLS_PROCTABLE()->WindowPos3fMESA) -#define glWindowPos3fvMESA (_GET_TLS_PROCTABLE()->WindowPos3fvMESA) -#define glWindowPos3iMESA (_GET_TLS_PROCTABLE()->WindowPos3iMESA) -#define glWindowPos3ivMESA (_GET_TLS_PROCTABLE()->WindowPos3ivMESA) -#define glWindowPos3sMESA (_GET_TLS_PROCTABLE()->WindowPos3sMESA) -#define glWindowPos3svMESA (_GET_TLS_PROCTABLE()->WindowPos3svMESA) -#define glWindowPos4dMESA (_GET_TLS_PROCTABLE()->WindowPos4dMESA) -#define glWindowPos4dvMESA (_GET_TLS_PROCTABLE()->WindowPos4dvMESA) -#define glWindowPos4fMESA (_GET_TLS_PROCTABLE()->WindowPos4fMESA) -#define glWindowPos4fvMESA (_GET_TLS_PROCTABLE()->WindowPos4fvMESA) -#define glWindowPos4iMESA (_GET_TLS_PROCTABLE()->WindowPos4iMESA) -#define glWindowPos4ivMESA (_GET_TLS_PROCTABLE()->WindowPos4ivMESA) -#define glWindowPos4sMESA (_GET_TLS_PROCTABLE()->WindowPos4sMESA) -#define glWindowPos4svMESA (_GET_TLS_PROCTABLE()->WindowPos4svMESA) -#define glMultiModeDrawArraysIBM (_GET_TLS_PROCTABLE()->MultiModeDrawArraysIBM) -#define glMultiModeDrawElementsIBM (_GET_TLS_PROCTABLE()->MultiModeDrawElementsIBM) -#define glColorPointerListIBM (_GET_TLS_PROCTABLE()->ColorPointerListIBM) -#define glSecondaryColorPointerListIBM (_GET_TLS_PROCTABLE()->SecondaryColorPointerListIBM) -#define glEdgeFlagPointerListIBM (_GET_TLS_PROCTABLE()->EdgeFlagPointerListIBM) -#define glFogCoordPointerListIBM (_GET_TLS_PROCTABLE()->FogCoordPointerListIBM) -#define glIndexPointerListIBM (_GET_TLS_PROCTABLE()->IndexPointerListIBM) -#define glNormalPointerListIBM (_GET_TLS_PROCTABLE()->NormalPointerListIBM) -#define glTexCoordPointerListIBM (_GET_TLS_PROCTABLE()->TexCoordPointerListIBM) -#define glVertexPointerListIBM (_GET_TLS_PROCTABLE()->VertexPointerListIBM) -#define glTbufferMask3DFX (_GET_TLS_PROCTABLE()->TbufferMask3DFX) -#define glSampleMaskEXT (_GET_TLS_PROCTABLE()->SampleMaskEXT) -#define glSamplePatternEXT (_GET_TLS_PROCTABLE()->SamplePatternEXT) -#define glTextureColorMaskSGIS (_GET_TLS_PROCTABLE()->TextureColorMaskSGIS) -#define glIglooInterfaceSGIX (_GET_TLS_PROCTABLE()->IglooInterfaceSGIX) -#define glDeleteFencesNV (_GET_TLS_PROCTABLE()->DeleteFencesNV) -#define glGenFencesNV (_GET_TLS_PROCTABLE()->GenFencesNV) -#define glIsFenceNV (_GET_TLS_PROCTABLE()->IsFenceNV) -#define glTestFenceNV (_GET_TLS_PROCTABLE()->TestFenceNV) -#define glGetFenceivNV (_GET_TLS_PROCTABLE()->GetFenceivNV) -#define glFinishFenceNV (_GET_TLS_PROCTABLE()->FinishFenceNV) -#define glSetFenceNV (_GET_TLS_PROCTABLE()->SetFenceNV) -#define glMapControlPointsNV (_GET_TLS_PROCTABLE()->MapControlPointsNV) -#define glMapParameterivNV (_GET_TLS_PROCTABLE()->MapParameterivNV) -#define glMapParameterfvNV (_GET_TLS_PROCTABLE()->MapParameterfvNV) -#define glGetMapControlPointsNV (_GET_TLS_PROCTABLE()->GetMapControlPointsNV) -#define glGetMapParameterivNV (_GET_TLS_PROCTABLE()->GetMapParameterivNV) -#define glGetMapParameterfvNV (_GET_TLS_PROCTABLE()->GetMapParameterfvNV) -#define glGetMapAttribParameterivNV (_GET_TLS_PROCTABLE()->GetMapAttribParameterivNV) -#define glGetMapAttribParameterfvNV (_GET_TLS_PROCTABLE()->GetMapAttribParameterfvNV) -#define glEvalMapsNV (_GET_TLS_PROCTABLE()->EvalMapsNV) -#define glCombinerStageParameterfvNV (_GET_TLS_PROCTABLE()->CombinerStageParameterfvNV) -#define glGetCombinerStageParameterfvNV (_GET_TLS_PROCTABLE()->GetCombinerStageParameterfvNV) -#define glAreProgramsResidentNV (_GET_TLS_PROCTABLE()->AreProgramsResidentNV) -#define glBindProgramNV (_GET_TLS_PROCTABLE()->BindProgramNV) -#define glDeleteProgramsNV (_GET_TLS_PROCTABLE()->DeleteProgramsNV) -#define glExecuteProgramNV (_GET_TLS_PROCTABLE()->ExecuteProgramNV) -#define glGenProgramsNV (_GET_TLS_PROCTABLE()->GenProgramsNV) -#define glGetProgramParameterdvNV (_GET_TLS_PROCTABLE()->GetProgramParameterdvNV) -#define glGetProgramParameterfvNV (_GET_TLS_PROCTABLE()->GetProgramParameterfvNV) -#define glGetProgramivNV (_GET_TLS_PROCTABLE()->GetProgramivNV) -#define glGetProgramStringNV (_GET_TLS_PROCTABLE()->GetProgramStringNV) -#define glGetTrackMatrixivNV (_GET_TLS_PROCTABLE()->GetTrackMatrixivNV) -#define glGetVertexAttribdvNV (_GET_TLS_PROCTABLE()->GetVertexAttribdvNV) -#define glGetVertexAttribfvNV (_GET_TLS_PROCTABLE()->GetVertexAttribfvNV) -#define glGetVertexAttribivNV (_GET_TLS_PROCTABLE()->GetVertexAttribivNV) -#define glGetVertexAttribPointervNV (_GET_TLS_PROCTABLE()->GetVertexAttribPointervNV) -#define glIsProgramNV (_GET_TLS_PROCTABLE()->IsProgramNV) -#define glLoadProgramNV (_GET_TLS_PROCTABLE()->LoadProgramNV) -#define glProgramParameter4dNV (_GET_TLS_PROCTABLE()->ProgramParameter4dNV) -#define glProgramParameter4dvNV (_GET_TLS_PROCTABLE()->ProgramParameter4dvNV) -#define glProgramParameter4fNV (_GET_TLS_PROCTABLE()->ProgramParameter4fNV) -#define glProgramParameter4fvNV (_GET_TLS_PROCTABLE()->ProgramParameter4fvNV) -#define glProgramParameters4dvNV (_GET_TLS_PROCTABLE()->ProgramParameters4dvNV) -#define glProgramParameters4fvNV (_GET_TLS_PROCTABLE()->ProgramParameters4fvNV) -#define glRequestResidentProgramsNV (_GET_TLS_PROCTABLE()->RequestResidentProgramsNV) -#define glTrackMatrixNV (_GET_TLS_PROCTABLE()->TrackMatrixNV) -#define glVertexAttribPointerNV (_GET_TLS_PROCTABLE()->VertexAttribPointerNV) -#define glVertexAttrib1dNV (_GET_TLS_PROCTABLE()->VertexAttrib1dNV) -#define glVertexAttrib1dvNV (_GET_TLS_PROCTABLE()->VertexAttrib1dvNV) -#define glVertexAttrib1fNV (_GET_TLS_PROCTABLE()->VertexAttrib1fNV) -#define glVertexAttrib1fvNV (_GET_TLS_PROCTABLE()->VertexAttrib1fvNV) -#define glVertexAttrib1sNV (_GET_TLS_PROCTABLE()->VertexAttrib1sNV) -#define glVertexAttrib1svNV (_GET_TLS_PROCTABLE()->VertexAttrib1svNV) -#define glVertexAttrib2dNV (_GET_TLS_PROCTABLE()->VertexAttrib2dNV) -#define glVertexAttrib2dvNV (_GET_TLS_PROCTABLE()->VertexAttrib2dvNV) -#define glVertexAttrib2fNV (_GET_TLS_PROCTABLE()->VertexAttrib2fNV) -#define glVertexAttrib2fvNV (_GET_TLS_PROCTABLE()->VertexAttrib2fvNV) -#define glVertexAttrib2sNV (_GET_TLS_PROCTABLE()->VertexAttrib2sNV) -#define glVertexAttrib2svNV (_GET_TLS_PROCTABLE()->VertexAttrib2svNV) -#define glVertexAttrib3dNV (_GET_TLS_PROCTABLE()->VertexAttrib3dNV) -#define glVertexAttrib3dvNV (_GET_TLS_PROCTABLE()->VertexAttrib3dvNV) -#define glVertexAttrib3fNV (_GET_TLS_PROCTABLE()->VertexAttrib3fNV) -#define glVertexAttrib3fvNV (_GET_TLS_PROCTABLE()->VertexAttrib3fvNV) -#define glVertexAttrib3sNV (_GET_TLS_PROCTABLE()->VertexAttrib3sNV) -#define glVertexAttrib3svNV (_GET_TLS_PROCTABLE()->VertexAttrib3svNV) -#define glVertexAttrib4dNV (_GET_TLS_PROCTABLE()->VertexAttrib4dNV) -#define glVertexAttrib4dvNV (_GET_TLS_PROCTABLE()->VertexAttrib4dvNV) -#define glVertexAttrib4fNV (_GET_TLS_PROCTABLE()->VertexAttrib4fNV) -#define glVertexAttrib4fvNV (_GET_TLS_PROCTABLE()->VertexAttrib4fvNV) -#define glVertexAttrib4sNV (_GET_TLS_PROCTABLE()->VertexAttrib4sNV) -#define glVertexAttrib4svNV (_GET_TLS_PROCTABLE()->VertexAttrib4svNV) -#define glVertexAttrib4ubNV (_GET_TLS_PROCTABLE()->VertexAttrib4ubNV) -#define glVertexAttrib4ubvNV (_GET_TLS_PROCTABLE()->VertexAttrib4ubvNV) -#define glVertexAttribs1dvNV (_GET_TLS_PROCTABLE()->VertexAttribs1dvNV) -#define glVertexAttribs1fvNV (_GET_TLS_PROCTABLE()->VertexAttribs1fvNV) -#define glVertexAttribs1svNV (_GET_TLS_PROCTABLE()->VertexAttribs1svNV) -#define glVertexAttribs2dvNV (_GET_TLS_PROCTABLE()->VertexAttribs2dvNV) -#define glVertexAttribs2fvNV (_GET_TLS_PROCTABLE()->VertexAttribs2fvNV) -#define glVertexAttribs2svNV (_GET_TLS_PROCTABLE()->VertexAttribs2svNV) -#define glVertexAttribs3dvNV (_GET_TLS_PROCTABLE()->VertexAttribs3dvNV) -#define glVertexAttribs3fvNV (_GET_TLS_PROCTABLE()->VertexAttribs3fvNV) -#define glVertexAttribs3svNV (_GET_TLS_PROCTABLE()->VertexAttribs3svNV) -#define glVertexAttribs4dvNV (_GET_TLS_PROCTABLE()->VertexAttribs4dvNV) -#define glVertexAttribs4fvNV (_GET_TLS_PROCTABLE()->VertexAttribs4fvNV) -#define glVertexAttribs4svNV (_GET_TLS_PROCTABLE()->VertexAttribs4svNV) -#define glVertexAttribs4ubvNV (_GET_TLS_PROCTABLE()->VertexAttribs4ubvNV) -#define glTexBumpParameterivATI (_GET_TLS_PROCTABLE()->TexBumpParameterivATI) -#define glTexBumpParameterfvATI (_GET_TLS_PROCTABLE()->TexBumpParameterfvATI) -#define glGetTexBumpParameterivATI (_GET_TLS_PROCTABLE()->GetTexBumpParameterivATI) -#define glGetTexBumpParameterfvATI (_GET_TLS_PROCTABLE()->GetTexBumpParameterfvATI) -#define glGenFragmentShadersATI (_GET_TLS_PROCTABLE()->GenFragmentShadersATI) -#define glBindFragmentShaderATI (_GET_TLS_PROCTABLE()->BindFragmentShaderATI) -#define glDeleteFragmentShaderATI (_GET_TLS_PROCTABLE()->DeleteFragmentShaderATI) -#define glBeginFragmentShaderATI (_GET_TLS_PROCTABLE()->BeginFragmentShaderATI) -#define glEndFragmentShaderATI (_GET_TLS_PROCTABLE()->EndFragmentShaderATI) -#define glPassTexCoordATI (_GET_TLS_PROCTABLE()->PassTexCoordATI) -#define glSampleMapATI (_GET_TLS_PROCTABLE()->SampleMapATI) -#define glColorFragmentOp1ATI (_GET_TLS_PROCTABLE()->ColorFragmentOp1ATI) -#define glColorFragmentOp2ATI (_GET_TLS_PROCTABLE()->ColorFragmentOp2ATI) -#define glColorFragmentOp3ATI (_GET_TLS_PROCTABLE()->ColorFragmentOp3ATI) -#define glAlphaFragmentOp1ATI (_GET_TLS_PROCTABLE()->AlphaFragmentOp1ATI) -#define glAlphaFragmentOp2ATI (_GET_TLS_PROCTABLE()->AlphaFragmentOp2ATI) -#define glAlphaFragmentOp3ATI (_GET_TLS_PROCTABLE()->AlphaFragmentOp3ATI) -#define glSetFragmentShaderConstantATI (_GET_TLS_PROCTABLE()->SetFragmentShaderConstantATI) -#define glPNTrianglesiATI (_GET_TLS_PROCTABLE()->PNTrianglesiATI) -#define glPNTrianglesfATI (_GET_TLS_PROCTABLE()->PNTrianglesfATI) -#define glNewObjectBufferATI (_GET_TLS_PROCTABLE()->NewObjectBufferATI) -#define glIsObjectBufferATI (_GET_TLS_PROCTABLE()->IsObjectBufferATI) -#define glUpdateObjectBufferATI (_GET_TLS_PROCTABLE()->UpdateObjectBufferATI) -#define glGetObjectBufferfvATI (_GET_TLS_PROCTABLE()->GetObjectBufferfvATI) -#define glGetObjectBufferivATI (_GET_TLS_PROCTABLE()->GetObjectBufferivATI) -#define glFreeObjectBufferATI (_GET_TLS_PROCTABLE()->FreeObjectBufferATI) -#define glArrayObjectATI (_GET_TLS_PROCTABLE()->ArrayObjectATI) -#define glGetArrayObjectfvATI (_GET_TLS_PROCTABLE()->GetArrayObjectfvATI) -#define glGetArrayObjectivATI (_GET_TLS_PROCTABLE()->GetArrayObjectivATI) -#define glVariantArrayObjectATI (_GET_TLS_PROCTABLE()->VariantArrayObjectATI) -#define glGetVariantArrayObjectfvATI (_GET_TLS_PROCTABLE()->GetVariantArrayObjectfvATI) -#define glGetVariantArrayObjectivATI (_GET_TLS_PROCTABLE()->GetVariantArrayObjectivATI) -#define glBeginVertexShaderEXT (_GET_TLS_PROCTABLE()->BeginVertexShaderEXT) -#define glEndVertexShaderEXT (_GET_TLS_PROCTABLE()->EndVertexShaderEXT) -#define glBindVertexShaderEXT (_GET_TLS_PROCTABLE()->BindVertexShaderEXT) -#define glGenVertexShadersEXT (_GET_TLS_PROCTABLE()->GenVertexShadersEXT) -#define glDeleteVertexShaderEXT (_GET_TLS_PROCTABLE()->DeleteVertexShaderEXT) -#define glShaderOp1EXT (_GET_TLS_PROCTABLE()->ShaderOp1EXT) -#define glShaderOp2EXT (_GET_TLS_PROCTABLE()->ShaderOp2EXT) -#define glShaderOp3EXT (_GET_TLS_PROCTABLE()->ShaderOp3EXT) -#define glSwizzleEXT (_GET_TLS_PROCTABLE()->SwizzleEXT) -#define glWriteMaskEXT (_GET_TLS_PROCTABLE()->WriteMaskEXT) -#define glInsertComponentEXT (_GET_TLS_PROCTABLE()->InsertComponentEXT) -#define glExtractComponentEXT (_GET_TLS_PROCTABLE()->ExtractComponentEXT) -#define glGenSymbolsEXT (_GET_TLS_PROCTABLE()->GenSymbolsEXT) -#define glSetInvariantEXT (_GET_TLS_PROCTABLE()->SetInvariantEXT) -#define glSetLocalConstantEXT (_GET_TLS_PROCTABLE()->SetLocalConstantEXT) -#define glVariantbvEXT (_GET_TLS_PROCTABLE()->VariantbvEXT) -#define glVariantsvEXT (_GET_TLS_PROCTABLE()->VariantsvEXT) -#define glVariantivEXT (_GET_TLS_PROCTABLE()->VariantivEXT) -#define glVariantfvEXT (_GET_TLS_PROCTABLE()->VariantfvEXT) -#define glVariantdvEXT (_GET_TLS_PROCTABLE()->VariantdvEXT) -#define glVariantubvEXT (_GET_TLS_PROCTABLE()->VariantubvEXT) -#define glVariantusvEXT (_GET_TLS_PROCTABLE()->VariantusvEXT) -#define glVariantuivEXT (_GET_TLS_PROCTABLE()->VariantuivEXT) -#define glVariantPointerEXT (_GET_TLS_PROCTABLE()->VariantPointerEXT) -#define glEnableVariantClientStateEXT (_GET_TLS_PROCTABLE()->EnableVariantClientStateEXT) -#define glDisableVariantClientStateEXT (_GET_TLS_PROCTABLE()->DisableVariantClientStateEXT) -#define glBindLightParameterEXT (_GET_TLS_PROCTABLE()->BindLightParameterEXT) -#define glBindMaterialParameterEXT (_GET_TLS_PROCTABLE()->BindMaterialParameterEXT) -#define glBindTexGenParameterEXT (_GET_TLS_PROCTABLE()->BindTexGenParameterEXT) -#define glBindTextureUnitParameterEXT (_GET_TLS_PROCTABLE()->BindTextureUnitParameterEXT) -#define glBindParameterEXT (_GET_TLS_PROCTABLE()->BindParameterEXT) -#define glIsVariantEnabledEXT (_GET_TLS_PROCTABLE()->IsVariantEnabledEXT) -#define glGetVariantBooleanvEXT (_GET_TLS_PROCTABLE()->GetVariantBooleanvEXT) -#define glGetVariantIntegervEXT (_GET_TLS_PROCTABLE()->GetVariantIntegervEXT) -#define glGetVariantFloatvEXT (_GET_TLS_PROCTABLE()->GetVariantFloatvEXT) -#define glGetVariantPointervEXT (_GET_TLS_PROCTABLE()->GetVariantPointervEXT) -#define glGetInvariantBooleanvEXT (_GET_TLS_PROCTABLE()->GetInvariantBooleanvEXT) -#define glGetInvariantIntegervEXT (_GET_TLS_PROCTABLE()->GetInvariantIntegervEXT) -#define glGetInvariantFloatvEXT (_GET_TLS_PROCTABLE()->GetInvariantFloatvEXT) -#define glGetLocalConstantBooleanvEXT (_GET_TLS_PROCTABLE()->GetLocalConstantBooleanvEXT) -#define glGetLocalConstantIntegervEXT (_GET_TLS_PROCTABLE()->GetLocalConstantIntegervEXT) -#define glGetLocalConstantFloatvEXT (_GET_TLS_PROCTABLE()->GetLocalConstantFloatvEXT) -#define glVertexStream1sATI (_GET_TLS_PROCTABLE()->VertexStream1sATI) -#define glVertexStream1svATI (_GET_TLS_PROCTABLE()->VertexStream1svATI) -#define glVertexStream1iATI (_GET_TLS_PROCTABLE()->VertexStream1iATI) -#define glVertexStream1ivATI (_GET_TLS_PROCTABLE()->VertexStream1ivATI) -#define glVertexStream1fATI (_GET_TLS_PROCTABLE()->VertexStream1fATI) -#define glVertexStream1fvATI (_GET_TLS_PROCTABLE()->VertexStream1fvATI) -#define glVertexStream1dATI (_GET_TLS_PROCTABLE()->VertexStream1dATI) -#define glVertexStream1dvATI (_GET_TLS_PROCTABLE()->VertexStream1dvATI) -#define glVertexStream2sATI (_GET_TLS_PROCTABLE()->VertexStream2sATI) -#define glVertexStream2svATI (_GET_TLS_PROCTABLE()->VertexStream2svATI) -#define glVertexStream2iATI (_GET_TLS_PROCTABLE()->VertexStream2iATI) -#define glVertexStream2ivATI (_GET_TLS_PROCTABLE()->VertexStream2ivATI) -#define glVertexStream2fATI (_GET_TLS_PROCTABLE()->VertexStream2fATI) -#define glVertexStream2fvATI (_GET_TLS_PROCTABLE()->VertexStream2fvATI) -#define glVertexStream2dATI (_GET_TLS_PROCTABLE()->VertexStream2dATI) -#define glVertexStream2dvATI (_GET_TLS_PROCTABLE()->VertexStream2dvATI) -#define glVertexStream3sATI (_GET_TLS_PROCTABLE()->VertexStream3sATI) -#define glVertexStream3svATI (_GET_TLS_PROCTABLE()->VertexStream3svATI) -#define glVertexStream3iATI (_GET_TLS_PROCTABLE()->VertexStream3iATI) -#define glVertexStream3ivATI (_GET_TLS_PROCTABLE()->VertexStream3ivATI) -#define glVertexStream3fATI (_GET_TLS_PROCTABLE()->VertexStream3fATI) -#define glVertexStream3fvATI (_GET_TLS_PROCTABLE()->VertexStream3fvATI) -#define glVertexStream3dATI (_GET_TLS_PROCTABLE()->VertexStream3dATI) -#define glVertexStream3dvATI (_GET_TLS_PROCTABLE()->VertexStream3dvATI) -#define glVertexStream4sATI (_GET_TLS_PROCTABLE()->VertexStream4sATI) -#define glVertexStream4svATI (_GET_TLS_PROCTABLE()->VertexStream4svATI) -#define glVertexStream4iATI (_GET_TLS_PROCTABLE()->VertexStream4iATI) -#define glVertexStream4ivATI (_GET_TLS_PROCTABLE()->VertexStream4ivATI) -#define glVertexStream4fATI (_GET_TLS_PROCTABLE()->VertexStream4fATI) -#define glVertexStream4fvATI (_GET_TLS_PROCTABLE()->VertexStream4fvATI) -#define glVertexStream4dATI (_GET_TLS_PROCTABLE()->VertexStream4dATI) -#define glVertexStream4dvATI (_GET_TLS_PROCTABLE()->VertexStream4dvATI) -#define glNormalStream3bATI (_GET_TLS_PROCTABLE()->NormalStream3bATI) -#define glNormalStream3bvATI (_GET_TLS_PROCTABLE()->NormalStream3bvATI) -#define glNormalStream3sATI (_GET_TLS_PROCTABLE()->NormalStream3sATI) -#define glNormalStream3svATI (_GET_TLS_PROCTABLE()->NormalStream3svATI) -#define glNormalStream3iATI (_GET_TLS_PROCTABLE()->NormalStream3iATI) -#define glNormalStream3ivATI (_GET_TLS_PROCTABLE()->NormalStream3ivATI) -#define glNormalStream3fATI (_GET_TLS_PROCTABLE()->NormalStream3fATI) -#define glNormalStream3fvATI (_GET_TLS_PROCTABLE()->NormalStream3fvATI) -#define glNormalStream3dATI (_GET_TLS_PROCTABLE()->NormalStream3dATI) -#define glNormalStream3dvATI (_GET_TLS_PROCTABLE()->NormalStream3dvATI) -#define glClientActiveVertexStreamATI (_GET_TLS_PROCTABLE()->ClientActiveVertexStreamATI) -#define glVertexBlendEnviATI (_GET_TLS_PROCTABLE()->VertexBlendEnviATI) -#define glVertexBlendEnvfATI (_GET_TLS_PROCTABLE()->VertexBlendEnvfATI) -#define glElementPointerATI (_GET_TLS_PROCTABLE()->ElementPointerATI) -#define glDrawElementArrayATI (_GET_TLS_PROCTABLE()->DrawElementArrayATI) -#define glDrawRangeElementArrayATI (_GET_TLS_PROCTABLE()->DrawRangeElementArrayATI) -#define glDrawMeshArraysSUN (_GET_TLS_PROCTABLE()->DrawMeshArraysSUN) -#define glGenOcclusionQueriesNV (_GET_TLS_PROCTABLE()->GenOcclusionQueriesNV) -#define glDeleteOcclusionQueriesNV (_GET_TLS_PROCTABLE()->DeleteOcclusionQueriesNV) -#define glIsOcclusionQueryNV (_GET_TLS_PROCTABLE()->IsOcclusionQueryNV) -#define glBeginOcclusionQueryNV (_GET_TLS_PROCTABLE()->BeginOcclusionQueryNV) -#define glEndOcclusionQueryNV (_GET_TLS_PROCTABLE()->EndOcclusionQueryNV) -#define glGetOcclusionQueryivNV (_GET_TLS_PROCTABLE()->GetOcclusionQueryivNV) -#define glGetOcclusionQueryuivNV (_GET_TLS_PROCTABLE()->GetOcclusionQueryuivNV) -#define glPointParameteriNV (_GET_TLS_PROCTABLE()->PointParameteriNV) -#define glPointParameterivNV (_GET_TLS_PROCTABLE()->PointParameterivNV) -#define glActiveStencilFaceEXT (_GET_TLS_PROCTABLE()->ActiveStencilFaceEXT) -#define glElementPointerAPPLE (_GET_TLS_PROCTABLE()->ElementPointerAPPLE) -#define glDrawElementArrayAPPLE (_GET_TLS_PROCTABLE()->DrawElementArrayAPPLE) -#define glDrawRangeElementArrayAPPLE (_GET_TLS_PROCTABLE()->DrawRangeElementArrayAPPLE) -#define glMultiDrawElementArrayAPPLE (_GET_TLS_PROCTABLE()->MultiDrawElementArrayAPPLE) -#define glMultiDrawRangeElementArrayAPPLE (_GET_TLS_PROCTABLE()->MultiDrawRangeElementArrayAPPLE) -#define glGenFencesAPPLE (_GET_TLS_PROCTABLE()->GenFencesAPPLE) -#define glDeleteFencesAPPLE (_GET_TLS_PROCTABLE()->DeleteFencesAPPLE) -#define glSetFenceAPPLE (_GET_TLS_PROCTABLE()->SetFenceAPPLE) -#define glIsFenceAPPLE (_GET_TLS_PROCTABLE()->IsFenceAPPLE) -#define glTestFenceAPPLE (_GET_TLS_PROCTABLE()->TestFenceAPPLE) -#define glFinishFenceAPPLE (_GET_TLS_PROCTABLE()->FinishFenceAPPLE) -#define glTestObjectAPPLE (_GET_TLS_PROCTABLE()->TestObjectAPPLE) -#define glFinishObjectAPPLE (_GET_TLS_PROCTABLE()->FinishObjectAPPLE) -#define glBindVertexArrayAPPLE (_GET_TLS_PROCTABLE()->BindVertexArrayAPPLE) -#define glDeleteVertexArraysAPPLE (_GET_TLS_PROCTABLE()->DeleteVertexArraysAPPLE) -#define glGenVertexArraysAPPLE (_GET_TLS_PROCTABLE()->GenVertexArraysAPPLE) -#define glIsVertexArrayAPPLE (_GET_TLS_PROCTABLE()->IsVertexArrayAPPLE) -#define glVertexArrayRangeAPPLE (_GET_TLS_PROCTABLE()->VertexArrayRangeAPPLE) -#define glFlushVertexArrayRangeAPPLE (_GET_TLS_PROCTABLE()->FlushVertexArrayRangeAPPLE) -#define glVertexArrayParameteriAPPLE (_GET_TLS_PROCTABLE()->VertexArrayParameteriAPPLE) -#define glDrawBuffersATI (_GET_TLS_PROCTABLE()->DrawBuffersATI) -#define glProgramNamedParameter4fNV (_GET_TLS_PROCTABLE()->ProgramNamedParameter4fNV) -#define glProgramNamedParameter4dNV (_GET_TLS_PROCTABLE()->ProgramNamedParameter4dNV) -#define glProgramNamedParameter4fvNV (_GET_TLS_PROCTABLE()->ProgramNamedParameter4fvNV) -#define glProgramNamedParameter4dvNV (_GET_TLS_PROCTABLE()->ProgramNamedParameter4dvNV) -#define glGetProgramNamedParameterfvNV (_GET_TLS_PROCTABLE()->GetProgramNamedParameterfvNV) -#define glGetProgramNamedParameterdvNV (_GET_TLS_PROCTABLE()->GetProgramNamedParameterdvNV) -#define glVertex2hNV (_GET_TLS_PROCTABLE()->Vertex2hNV) -#define glVertex2hvNV (_GET_TLS_PROCTABLE()->Vertex2hvNV) -#define glVertex3hNV (_GET_TLS_PROCTABLE()->Vertex3hNV) -#define glVertex3hvNV (_GET_TLS_PROCTABLE()->Vertex3hvNV) -#define glVertex4hNV (_GET_TLS_PROCTABLE()->Vertex4hNV) -#define glVertex4hvNV (_GET_TLS_PROCTABLE()->Vertex4hvNV) -#define glNormal3hNV (_GET_TLS_PROCTABLE()->Normal3hNV) -#define glNormal3hvNV (_GET_TLS_PROCTABLE()->Normal3hvNV) -#define glColor3hNV (_GET_TLS_PROCTABLE()->Color3hNV) -#define glColor3hvNV (_GET_TLS_PROCTABLE()->Color3hvNV) -#define glColor4hNV (_GET_TLS_PROCTABLE()->Color4hNV) -#define glColor4hvNV (_GET_TLS_PROCTABLE()->Color4hvNV) -#define glTexCoord1hNV (_GET_TLS_PROCTABLE()->TexCoord1hNV) -#define glTexCoord1hvNV (_GET_TLS_PROCTABLE()->TexCoord1hvNV) -#define glTexCoord2hNV (_GET_TLS_PROCTABLE()->TexCoord2hNV) -#define glTexCoord2hvNV (_GET_TLS_PROCTABLE()->TexCoord2hvNV) -#define glTexCoord3hNV (_GET_TLS_PROCTABLE()->TexCoord3hNV) -#define glTexCoord3hvNV (_GET_TLS_PROCTABLE()->TexCoord3hvNV) -#define glTexCoord4hNV (_GET_TLS_PROCTABLE()->TexCoord4hNV) -#define glTexCoord4hvNV (_GET_TLS_PROCTABLE()->TexCoord4hvNV) -#define glMultiTexCoord1hNV (_GET_TLS_PROCTABLE()->MultiTexCoord1hNV) -#define glMultiTexCoord1hvNV (_GET_TLS_PROCTABLE()->MultiTexCoord1hvNV) -#define glMultiTexCoord2hNV (_GET_TLS_PROCTABLE()->MultiTexCoord2hNV) -#define glMultiTexCoord2hvNV (_GET_TLS_PROCTABLE()->MultiTexCoord2hvNV) -#define glMultiTexCoord3hNV (_GET_TLS_PROCTABLE()->MultiTexCoord3hNV) -#define glMultiTexCoord3hvNV (_GET_TLS_PROCTABLE()->MultiTexCoord3hvNV) -#define glMultiTexCoord4hNV (_GET_TLS_PROCTABLE()->MultiTexCoord4hNV) -#define glMultiTexCoord4hvNV (_GET_TLS_PROCTABLE()->MultiTexCoord4hvNV) -#define glFogCoordhNV (_GET_TLS_PROCTABLE()->FogCoordhNV) -#define glFogCoordhvNV (_GET_TLS_PROCTABLE()->FogCoordhvNV) -#define glSecondaryColor3hNV (_GET_TLS_PROCTABLE()->SecondaryColor3hNV) -#define glSecondaryColor3hvNV (_GET_TLS_PROCTABLE()->SecondaryColor3hvNV) -#define glVertexWeighthNV (_GET_TLS_PROCTABLE()->VertexWeighthNV) -#define glVertexWeighthvNV (_GET_TLS_PROCTABLE()->VertexWeighthvNV) -#define glVertexAttrib1hNV (_GET_TLS_PROCTABLE()->VertexAttrib1hNV) -#define glVertexAttrib1hvNV (_GET_TLS_PROCTABLE()->VertexAttrib1hvNV) -#define glVertexAttrib2hNV (_GET_TLS_PROCTABLE()->VertexAttrib2hNV) -#define glVertexAttrib2hvNV (_GET_TLS_PROCTABLE()->VertexAttrib2hvNV) -#define glVertexAttrib3hNV (_GET_TLS_PROCTABLE()->VertexAttrib3hNV) -#define glVertexAttrib3hvNV (_GET_TLS_PROCTABLE()->VertexAttrib3hvNV) -#define glVertexAttrib4hNV (_GET_TLS_PROCTABLE()->VertexAttrib4hNV) -#define glVertexAttrib4hvNV (_GET_TLS_PROCTABLE()->VertexAttrib4hvNV) -#define glVertexAttribs1hvNV (_GET_TLS_PROCTABLE()->VertexAttribs1hvNV) -#define glVertexAttribs2hvNV (_GET_TLS_PROCTABLE()->VertexAttribs2hvNV) -#define glVertexAttribs3hvNV (_GET_TLS_PROCTABLE()->VertexAttribs3hvNV) -#define glVertexAttribs4hvNV (_GET_TLS_PROCTABLE()->VertexAttribs4hvNV) -#define glPixelDataRangeNV (_GET_TLS_PROCTABLE()->PixelDataRangeNV) -#define glFlushPixelDataRangeNV (_GET_TLS_PROCTABLE()->FlushPixelDataRangeNV) -#define glPrimitiveRestartNV (_GET_TLS_PROCTABLE()->PrimitiveRestartNV) -#define glPrimitiveRestartIndexNV (_GET_TLS_PROCTABLE()->PrimitiveRestartIndexNV) -#define glMapObjectBufferATI (_GET_TLS_PROCTABLE()->MapObjectBufferATI) -#define glUnmapObjectBufferATI (_GET_TLS_PROCTABLE()->UnmapObjectBufferATI) -#define glStencilOpSeparateATI (_GET_TLS_PROCTABLE()->StencilOpSeparateATI) -#define glStencilFuncSeparateATI (_GET_TLS_PROCTABLE()->StencilFuncSeparateATI) -#define glVertexAttribArrayObjectATI (_GET_TLS_PROCTABLE()->VertexAttribArrayObjectATI) -#define glGetVertexAttribArrayObjectfvATI (_GET_TLS_PROCTABLE()->GetVertexAttribArrayObjectfvATI) -#define glGetVertexAttribArrayObjectivATI (_GET_TLS_PROCTABLE()->GetVertexAttribArrayObjectivATI) -#define glDepthBoundsEXT (_GET_TLS_PROCTABLE()->DepthBoundsEXT) -#define glBlendEquationSeparateEXT (_GET_TLS_PROCTABLE()->BlendEquationSeparateEXT) -#define glAddSwapHintRectWIN (_GET_TLS_PROCTABLE()->AddSwapHintRectWIN) -#ifdef _WIN32 -#define wglCreateBufferRegionARB (_GET_TLS_PROCTABLE()->CreateBufferRegionARB) -#define wglDeleteBufferRegionARB (_GET_TLS_PROCTABLE()->DeleteBufferRegionARB) -#define wglSaveBufferRegionARB (_GET_TLS_PROCTABLE()->SaveBufferRegionARB) -#define wglRestoreBufferRegionARB (_GET_TLS_PROCTABLE()->RestoreBufferRegionARB) -#define wglGetExtensionsStringARB (_GET_TLS_PROCTABLE()->GetExtensionsStringARB) -#define wglGetPixelFormatAttribivARB (_GET_TLS_PROCTABLE()->GetPixelFormatAttribivARB) -#define wglGetPixelFormatAttribfvARB (_GET_TLS_PROCTABLE()->GetPixelFormatAttribfvARB) -#define wglChoosePixelFormatARB (_GET_TLS_PROCTABLE()->ChoosePixelFormatARB) -#define wglMakeContextCurrentARB (_GET_TLS_PROCTABLE()->MakeContextCurrentARB) -#define wglGetCurrentReadDCARB (_GET_TLS_PROCTABLE()->GetCurrentReadDCARB) -#define wglCreatePbufferARB (_GET_TLS_PROCTABLE()->CreatePbufferARB) -#define wglGetPbufferDCARB (_GET_TLS_PROCTABLE()->GetPbufferDCARB) -#define wglReleasePbufferDCARB (_GET_TLS_PROCTABLE()->ReleasePbufferDCARB) -#define wglDestroyPbufferARB (_GET_TLS_PROCTABLE()->DestroyPbufferARB) -#define wglQueryPbufferARB (_GET_TLS_PROCTABLE()->QueryPbufferARB) -#define wglBindTexImageARB (_GET_TLS_PROCTABLE()->BindTexImageARB) -#define wglReleaseTexImageARB (_GET_TLS_PROCTABLE()->ReleaseTexImageARB) -#define wglSetPbufferAttribARB (_GET_TLS_PROCTABLE()->SetPbufferAttribARB) -#define wglCreateDisplayColorTableEXT (_GET_TLS_PROCTABLE()->CreateDisplayColorTableEXT) -#define wglLoadDisplayColorTableEXT (_GET_TLS_PROCTABLE()->LoadDisplayColorTableEXT) -#define wglBindDisplayColorTableEXT (_GET_TLS_PROCTABLE()->BindDisplayColorTableEXT) -#define wglDestroyDisplayColorTableEXT (_GET_TLS_PROCTABLE()->DestroyDisplayColorTableEXT) -#define wglGetExtensionsStringEXT (_GET_TLS_PROCTABLE()->GetExtensionsStringEXT) -#define wglMakeContextCurrentEXT (_GET_TLS_PROCTABLE()->MakeContextCurrentEXT) -#define wglGetCurrentReadDCEXT (_GET_TLS_PROCTABLE()->GetCurrentReadDCEXT) -#define wglCreatePbufferEXT (_GET_TLS_PROCTABLE()->CreatePbufferEXT) -#define wglGetPbufferDCEXT (_GET_TLS_PROCTABLE()->GetPbufferDCEXT) -#define wglReleasePbufferDCEXT (_GET_TLS_PROCTABLE()->ReleasePbufferDCEXT) -#define wglDestroyPbufferEXT (_GET_TLS_PROCTABLE()->DestroyPbufferEXT) -#define wglQueryPbufferEXT (_GET_TLS_PROCTABLE()->QueryPbufferEXT) -#define wglGetPixelFormatAttribivEXT (_GET_TLS_PROCTABLE()->GetPixelFormatAttribivEXT) -#define wglGetPixelFormatAttribfvEXT (_GET_TLS_PROCTABLE()->GetPixelFormatAttribfvEXT) -#define wglChoosePixelFormatEXT (_GET_TLS_PROCTABLE()->ChoosePixelFormatEXT) -#define wglSwapIntervalEXT (_GET_TLS_PROCTABLE()->SwapIntervalEXT) -#define wglGetSwapIntervalEXT (_GET_TLS_PROCTABLE()->GetSwapIntervalEXT) -#define wglAllocateMemoryNV (_GET_TLS_PROCTABLE()->AllocateMemoryNV) -#define wglFreeMemoryNV (_GET_TLS_PROCTABLE()->FreeMemoryNV) -#define wglGetSyncValuesOML (_GET_TLS_PROCTABLE()->GetSyncValuesOML) -#define wglGetMscRateOML (_GET_TLS_PROCTABLE()->GetMscRateOML) -#define wglSwapBuffersMscOML (_GET_TLS_PROCTABLE()->SwapBuffersMscOML) -#define wglSwapLayerBuffersMscOML (_GET_TLS_PROCTABLE()->SwapLayerBuffersMscOML) -#define wglWaitForMscOML (_GET_TLS_PROCTABLE()->WaitForMscOML) -#define wglWaitForSbcOML (_GET_TLS_PROCTABLE()->WaitForSbcOML) -#define wglGetDigitalVideoParametersI3D (_GET_TLS_PROCTABLE()->GetDigitalVideoParametersI3D) -#define wglSetDigitalVideoParametersI3D (_GET_TLS_PROCTABLE()->SetDigitalVideoParametersI3D) -#define wglGetGammaTableParametersI3D (_GET_TLS_PROCTABLE()->GetGammaTableParametersI3D) -#define wglSetGammaTableParametersI3D (_GET_TLS_PROCTABLE()->SetGammaTableParametersI3D) -#define wglGetGammaTableI3D (_GET_TLS_PROCTABLE()->GetGammaTableI3D) -#define wglSetGammaTableI3D (_GET_TLS_PROCTABLE()->SetGammaTableI3D) -#define wglEnableGenlockI3D (_GET_TLS_PROCTABLE()->EnableGenlockI3D) -#define wglDisableGenlockI3D (_GET_TLS_PROCTABLE()->DisableGenlockI3D) -#define wglIsEnabledGenlockI3D (_GET_TLS_PROCTABLE()->IsEnabledGenlockI3D) -#define wglGenlockSourceI3D (_GET_TLS_PROCTABLE()->GenlockSourceI3D) -#define wglGetGenlockSourceI3D (_GET_TLS_PROCTABLE()->GetGenlockSourceI3D) -#define wglGenlockSourceEdgeI3D (_GET_TLS_PROCTABLE()->GenlockSourceEdgeI3D) -#define wglGetGenlockSourceEdgeI3D (_GET_TLS_PROCTABLE()->GetGenlockSourceEdgeI3D) -#define wglGenlockSampleRateI3D (_GET_TLS_PROCTABLE()->GenlockSampleRateI3D) -#define wglGetGenlockSampleRateI3D (_GET_TLS_PROCTABLE()->GetGenlockSampleRateI3D) -#define wglGenlockSourceDelayI3D (_GET_TLS_PROCTABLE()->GenlockSourceDelayI3D) -#define wglGetGenlockSourceDelayI3D (_GET_TLS_PROCTABLE()->GetGenlockSourceDelayI3D) -#define wglQueryGenlockMaxSourceDelayI3D (_GET_TLS_PROCTABLE()->QueryGenlockMaxSourceDelayI3D) -#define wglCreateImageBufferI3D (_GET_TLS_PROCTABLE()->CreateImageBufferI3D) -#define wglDestroyImageBufferI3D (_GET_TLS_PROCTABLE()->DestroyImageBufferI3D) -#define wglAssociateImageBufferEventsI3D (_GET_TLS_PROCTABLE()->AssociateImageBufferEventsI3D) -#define wglReleaseImageBufferEventsI3D (_GET_TLS_PROCTABLE()->ReleaseImageBufferEventsI3D) -#define wglEnableFrameLockI3D (_GET_TLS_PROCTABLE()->EnableFrameLockI3D) -#define wglDisableFrameLockI3D (_GET_TLS_PROCTABLE()->DisableFrameLockI3D) -#define wglIsEnabledFrameLockI3D (_GET_TLS_PROCTABLE()->IsEnabledFrameLockI3D) -#define wglQueryFrameLockMasterI3D (_GET_TLS_PROCTABLE()->QueryFrameLockMasterI3D) -#define wglGetFrameUsageI3D (_GET_TLS_PROCTABLE()->GetFrameUsageI3D) -#define wglBeginFrameTrackingI3D (_GET_TLS_PROCTABLE()->BeginFrameTrackingI3D) -#define wglEndFrameTrackingI3D (_GET_TLS_PROCTABLE()->EndFrameTrackingI3D) -#define wglQueryFrameTrackingI3D (_GET_TLS_PROCTABLE()->QueryFrameTrackingI3D) -#endif /* _WIN32 */ - -#ifndef _APP_PROCTABLE - -/* - * Applications can replace the following function with its own function - * for accessing thread local proc/context dependent proc table. - * The following default function works for most applications which - * are using the same device for all their contexts - even if - * the contexts are on different threads. - */ - -static _inline _GLextensionProcs *_GET_TLS_PROCTABLE(void) - -{ - extern _GLextensionProcs _extensionProcs; - - return (&_extensionProcs); -} - -#else - -/* - * Application should replace this compiled function with - * an inlined function for maximum performance. - */ - -extern _GLextensionProcs *_GET_TLS_PROCTABLE(void); - -#endif - -/* - * Provide an initialization function for the application - * to initialize its own proc tables in case the application - * needs to use multiple proc tables. - */ - -static _inline void _InitExtensionProcs(_GLextensionProcs *appProcs) -{ - extern _GLextensionProcs _extensionProcs; - - *appProcs = _extensionProcs; -} - -#ifdef __cplusplus -} -#endif - - -#endif /* _GLPROCS_H_ */ +#ifndef _GLPROCS_H_ +#define _GLPROCS_H_ + +/* +** GLprocs utility for getting function addresses for OpenGL(R) 1.2, +** OpenGL 1.3, OpenGL 1.4, OpenGL 1.5 and OpenGL extension functions. +** +** Version: 1.1 +** +** License Applicability. Except to the extent portions of this file are +** made subject to an alternative license as permitted in the SGI Free +** Software License B, Version 1.1 (the "License"), the contents of this +** file are subject only to the provisions of the License. You may not use +** this file except in compliance with the License. You may obtain a copy +** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 +** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: +** +** http://oss.sgi.com/projects/FreeB +** +** Note that, as provided in the License, the Software is distributed on an +** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS +** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND +** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A +** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. +** +** Original Code. The Original Code is: OpenGL Sample Implementation, +** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, +** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. +** Copyright in any portions created by third parties is as indicated +** elsewhere herein. All Rights Reserved. +** +** Additional Notice Provisions: This software was created using the +** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has +** not been independently verified as being compliant with the OpenGL(R) +** version 1.2.1 Specification. +** +** Initial version of glprocs.{c,h} contributed by Intel(R) Corporation. +*/ + +#ifdef _WIN32 + #include + #include +#else + #include +#endif + +#ifndef _WIN32 /* non-Windows environment */ + #ifndef APIENTRY + #define APIENTRY + #endif + #ifdef __GNUC__ + #define _inline __inline__ + #else + #define _inline + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Structure of all OpenGL {1.2, 1.3, 1.4, 1.5}, GL extension procs.*/ + +typedef struct { + void (APIENTRY *BlendColor) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void (APIENTRY *BlendEquation) (GLenum mode); + void (APIENTRY *DrawRangeElements) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); + void (APIENTRY *ColorTable) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); + void (APIENTRY *ColorTableParameterfv) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *ColorTableParameteriv) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *CopyColorTable) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); + void (APIENTRY *GetColorTable) (GLenum target, GLenum format, GLenum type, GLvoid *table); + void (APIENTRY *GetColorTableParameterfv) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetColorTableParameteriv) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *ColorSubTable) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); + void (APIENTRY *CopyColorSubTable) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); + void (APIENTRY *ConvolutionFilter1D) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); + void (APIENTRY *ConvolutionFilter2D) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); + void (APIENTRY *ConvolutionParameterf) (GLenum target, GLenum pname, GLfloat params); + void (APIENTRY *ConvolutionParameterfv) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *ConvolutionParameteri) (GLenum target, GLenum pname, GLint params); + void (APIENTRY *ConvolutionParameteriv) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *CopyConvolutionFilter1D) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); + void (APIENTRY *CopyConvolutionFilter2D) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY *GetConvolutionFilter) (GLenum target, GLenum format, GLenum type, GLvoid *image); + void (APIENTRY *GetConvolutionParameterfv) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetConvolutionParameteriv) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetSeparableFilter) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); + void (APIENTRY *SeparableFilter2D) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); + void (APIENTRY *GetHistogram) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); + void (APIENTRY *GetHistogramParameterfv) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetHistogramParameteriv) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetMinmax) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); + void (APIENTRY *GetMinmaxParameterfv) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetMinmaxParameteriv) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *Histogram) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); + void (APIENTRY *Minmax) (GLenum target, GLenum internalformat, GLboolean sink); + void (APIENTRY *ResetHistogram) (GLenum target); + void (APIENTRY *ResetMinmax) (GLenum target); + void (APIENTRY *TexImage3D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *TexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *CopyTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY *ActiveTexture) (GLenum texture); + void (APIENTRY *ClientActiveTexture) (GLenum texture); + void (APIENTRY *MultiTexCoord1d) (GLenum target, GLdouble s); + void (APIENTRY *MultiTexCoord1dv) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord1f) (GLenum target, GLfloat s); + void (APIENTRY *MultiTexCoord1fv) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord1i) (GLenum target, GLint s); + void (APIENTRY *MultiTexCoord1iv) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord1s) (GLenum target, GLshort s); + void (APIENTRY *MultiTexCoord1sv) (GLenum target, const GLshort *v); + void (APIENTRY *MultiTexCoord2d) (GLenum target, GLdouble s, GLdouble t); + void (APIENTRY *MultiTexCoord2dv) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord2f) (GLenum target, GLfloat s, GLfloat t); + void (APIENTRY *MultiTexCoord2fv) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord2i) (GLenum target, GLint s, GLint t); + void (APIENTRY *MultiTexCoord2iv) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord2s) (GLenum target, GLshort s, GLshort t); + void (APIENTRY *MultiTexCoord2sv) (GLenum target, const GLshort *v); + void (APIENTRY *MultiTexCoord3d) (GLenum target, GLdouble s, GLdouble t, GLdouble r); + void (APIENTRY *MultiTexCoord3dv) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord3f) (GLenum target, GLfloat s, GLfloat t, GLfloat r); + void (APIENTRY *MultiTexCoord3fv) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord3i) (GLenum target, GLint s, GLint t, GLint r); + void (APIENTRY *MultiTexCoord3iv) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord3s) (GLenum target, GLshort s, GLshort t, GLshort r); + void (APIENTRY *MultiTexCoord3sv) (GLenum target, const GLshort *v); + void (APIENTRY *MultiTexCoord4d) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); + void (APIENTRY *MultiTexCoord4dv) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord4f) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); + void (APIENTRY *MultiTexCoord4fv) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord4i) (GLenum target, GLint s, GLint t, GLint r, GLint q); + void (APIENTRY *MultiTexCoord4iv) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord4s) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); + void (APIENTRY *MultiTexCoord4sv) (GLenum target, const GLshort *v); + void (APIENTRY *LoadTransposeMatrixf) (const GLfloat *m); + void (APIENTRY *LoadTransposeMatrixd) (const GLdouble *m); + void (APIENTRY *MultTransposeMatrixf) (const GLfloat *m); + void (APIENTRY *MultTransposeMatrixd) (const GLdouble *m); + void (APIENTRY *SampleCoverage) (GLclampf value, GLboolean invert); + void (APIENTRY *CompressedTexImage3D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexImage1D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexSubImage1D) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *GetCompressedTexImage) (GLenum target, GLint level, GLvoid *img); + void (APIENTRY *BlendFuncSeparate) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); + void (APIENTRY *FogCoordf) (GLfloat coord); + void (APIENTRY *FogCoordfv) (const GLfloat *coord); + void (APIENTRY *FogCoordd) (GLdouble coord); + void (APIENTRY *FogCoorddv) (const GLdouble *coord); + void (APIENTRY *FogCoordPointer) (GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *MultiDrawArrays) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); + void (APIENTRY *MultiDrawElements) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); + void (APIENTRY *PointParameterf) (GLenum pname, GLfloat param); + void (APIENTRY *PointParameterfv) (GLenum pname, const GLfloat *params); + void (APIENTRY *PointParameteri) (GLenum pname, GLint param); + void (APIENTRY *PointParameteriv) (GLenum pname, const GLint *params); + void (APIENTRY *SecondaryColor3b) (GLbyte red, GLbyte green, GLbyte blue); + void (APIENTRY *SecondaryColor3bv) (const GLbyte *v); + void (APIENTRY *SecondaryColor3d) (GLdouble red, GLdouble green, GLdouble blue); + void (APIENTRY *SecondaryColor3dv) (const GLdouble *v); + void (APIENTRY *SecondaryColor3f) (GLfloat red, GLfloat green, GLfloat blue); + void (APIENTRY *SecondaryColor3fv) (const GLfloat *v); + void (APIENTRY *SecondaryColor3i) (GLint red, GLint green, GLint blue); + void (APIENTRY *SecondaryColor3iv) (const GLint *v); + void (APIENTRY *SecondaryColor3s) (GLshort red, GLshort green, GLshort blue); + void (APIENTRY *SecondaryColor3sv) (const GLshort *v); + void (APIENTRY *SecondaryColor3ub) (GLubyte red, GLubyte green, GLubyte blue); + void (APIENTRY *SecondaryColor3ubv) (const GLubyte *v); + void (APIENTRY *SecondaryColor3ui) (GLuint red, GLuint green, GLuint blue); + void (APIENTRY *SecondaryColor3uiv) (const GLuint *v); + void (APIENTRY *SecondaryColor3us) (GLushort red, GLushort green, GLushort blue); + void (APIENTRY *SecondaryColor3usv) (const GLushort *v); + void (APIENTRY *SecondaryColorPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *WindowPos2d) (GLdouble x, GLdouble y); + void (APIENTRY *WindowPos2dv) (const GLdouble *v); + void (APIENTRY *WindowPos2f) (GLfloat x, GLfloat y); + void (APIENTRY *WindowPos2fv) (const GLfloat *v); + void (APIENTRY *WindowPos2i) (GLint x, GLint y); + void (APIENTRY *WindowPos2iv) (const GLint *v); + void (APIENTRY *WindowPos2s) (GLshort x, GLshort y); + void (APIENTRY *WindowPos2sv) (const GLshort *v); + void (APIENTRY *WindowPos3d) (GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY *WindowPos3dv) (const GLdouble *v); + void (APIENTRY *WindowPos3f) (GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *WindowPos3fv) (const GLfloat *v); + void (APIENTRY *WindowPos3i) (GLint x, GLint y, GLint z); + void (APIENTRY *WindowPos3iv) (const GLint *v); + void (APIENTRY *WindowPos3s) (GLshort x, GLshort y, GLshort z); + void (APIENTRY *WindowPos3sv) (const GLshort *v); + void (APIENTRY *GenQueries) (GLsizei n, GLuint *ids); + void (APIENTRY *DeleteQueries) (GLsizei n, const GLuint *ids); + GLboolean (APIENTRY *IsQuery) (GLuint id); + void (APIENTRY *BeginQuery) (GLenum target, GLuint id); + void (APIENTRY *EndQuery) (GLenum target); + void (APIENTRY *GetQueryiv) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetQueryObjectiv) (GLuint id, GLenum pname, GLint *params); + void (APIENTRY *GetQueryObjectuiv) (GLuint id, GLenum pname, GLuint *params); + void (APIENTRY *BindBuffer) (GLenum target, GLuint buffer); + void (APIENTRY *DeleteBuffers) (GLsizei n, const GLuint *buffers); + void (APIENTRY *GenBuffers) (GLsizei n, GLuint *buffers); + GLboolean (APIENTRY *IsBuffer) (GLuint buffer); + void (APIENTRY *BufferData) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); + void (APIENTRY *BufferSubData) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); + void (APIENTRY *GetBufferSubData) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); + GLvoid* (APIENTRY *MapBuffer) (GLenum target, GLenum access); + GLboolean (APIENTRY *UnmapBuffer) (GLenum target); + void (APIENTRY *GetBufferParameteriv) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetBufferPointerv) (GLenum target, GLenum pname, GLvoid* *params); + void (APIENTRY *ActiveTextureARB) (GLenum texture); + void (APIENTRY *ClientActiveTextureARB) (GLenum texture); + void (APIENTRY *MultiTexCoord1dARB) (GLenum target, GLdouble s); + void (APIENTRY *MultiTexCoord1dvARB) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord1fARB) (GLenum target, GLfloat s); + void (APIENTRY *MultiTexCoord1fvARB) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord1iARB) (GLenum target, GLint s); + void (APIENTRY *MultiTexCoord1ivARB) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord1sARB) (GLenum target, GLshort s); + void (APIENTRY *MultiTexCoord1svARB) (GLenum target, const GLshort *v); + void (APIENTRY *MultiTexCoord2dARB) (GLenum target, GLdouble s, GLdouble t); + void (APIENTRY *MultiTexCoord2dvARB) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord2fARB) (GLenum target, GLfloat s, GLfloat t); + void (APIENTRY *MultiTexCoord2fvARB) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord2iARB) (GLenum target, GLint s, GLint t); + void (APIENTRY *MultiTexCoord2ivARB) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord2sARB) (GLenum target, GLshort s, GLshort t); + void (APIENTRY *MultiTexCoord2svARB) (GLenum target, const GLshort *v); + void (APIENTRY *MultiTexCoord3dARB) (GLenum target, GLdouble s, GLdouble t, GLdouble r); + void (APIENTRY *MultiTexCoord3dvARB) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord3fARB) (GLenum target, GLfloat s, GLfloat t, GLfloat r); + void (APIENTRY *MultiTexCoord3fvARB) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord3iARB) (GLenum target, GLint s, GLint t, GLint r); + void (APIENTRY *MultiTexCoord3ivARB) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord3sARB) (GLenum target, GLshort s, GLshort t, GLshort r); + void (APIENTRY *MultiTexCoord3svARB) (GLenum target, const GLshort *v); + void (APIENTRY *MultiTexCoord4dARB) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); + void (APIENTRY *MultiTexCoord4dvARB) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord4fARB) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); + void (APIENTRY *MultiTexCoord4fvARB) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord4iARB) (GLenum target, GLint s, GLint t, GLint r, GLint q); + void (APIENTRY *MultiTexCoord4ivARB) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord4sARB) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); + void (APIENTRY *MultiTexCoord4svARB) (GLenum target, const GLshort *v); + void (APIENTRY *LoadTransposeMatrixfARB) (const GLfloat *m); + void (APIENTRY *LoadTransposeMatrixdARB) (const GLdouble *m); + void (APIENTRY *MultTransposeMatrixfARB) (const GLfloat *m); + void (APIENTRY *MultTransposeMatrixdARB) (const GLdouble *m); + void (APIENTRY *SampleCoverageARB) (GLclampf value, GLboolean invert); + void (APIENTRY *CompressedTexImage3DARB) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexImage2DARB) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexImage1DARB) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexSubImage3DARB) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexSubImage2DARB) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexSubImage1DARB) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *GetCompressedTexImageARB) (GLenum target, GLint level, GLvoid *img); + void (APIENTRY *PointParameterfARB) (GLenum pname, GLfloat param); + void (APIENTRY *PointParameterfvARB) (GLenum pname, const GLfloat *params); + void (APIENTRY *WeightbvARB) (GLint size, const GLbyte *weights); + void (APIENTRY *WeightsvARB) (GLint size, const GLshort *weights); + void (APIENTRY *WeightivARB) (GLint size, const GLint *weights); + void (APIENTRY *WeightfvARB) (GLint size, const GLfloat *weights); + void (APIENTRY *WeightdvARB) (GLint size, const GLdouble *weights); + void (APIENTRY *WeightubvARB) (GLint size, const GLubyte *weights); + void (APIENTRY *WeightusvARB) (GLint size, const GLushort *weights); + void (APIENTRY *WeightuivARB) (GLint size, const GLuint *weights); + void (APIENTRY *WeightPointerARB) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *VertexBlendARB) (GLint count); + void (APIENTRY *CurrentPaletteMatrixARB) (GLint index); + void (APIENTRY *MatrixIndexubvARB) (GLint size, const GLubyte *indices); + void (APIENTRY *MatrixIndexusvARB) (GLint size, const GLushort *indices); + void (APIENTRY *MatrixIndexuivARB) (GLint size, const GLuint *indices); + void (APIENTRY *MatrixIndexPointerARB) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *WindowPos2dARB) (GLdouble x, GLdouble y); + void (APIENTRY *WindowPos2dvARB) (const GLdouble *v); + void (APIENTRY *WindowPos2fARB) (GLfloat x, GLfloat y); + void (APIENTRY *WindowPos2fvARB) (const GLfloat *v); + void (APIENTRY *WindowPos2iARB) (GLint x, GLint y); + void (APIENTRY *WindowPos2ivARB) (const GLint *v); + void (APIENTRY *WindowPos2sARB) (GLshort x, GLshort y); + void (APIENTRY *WindowPos2svARB) (const GLshort *v); + void (APIENTRY *WindowPos3dARB) (GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY *WindowPos3dvARB) (const GLdouble *v); + void (APIENTRY *WindowPos3fARB) (GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *WindowPos3fvARB) (const GLfloat *v); + void (APIENTRY *WindowPos3iARB) (GLint x, GLint y, GLint z); + void (APIENTRY *WindowPos3ivARB) (const GLint *v); + void (APIENTRY *WindowPos3sARB) (GLshort x, GLshort y, GLshort z); + void (APIENTRY *WindowPos3svARB) (const GLshort *v); + void (APIENTRY *VertexAttrib1dARB) (GLuint index, GLdouble x); + void (APIENTRY *VertexAttrib1dvARB) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib1fARB) (GLuint index, GLfloat x); + void (APIENTRY *VertexAttrib1fvARB) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib1sARB) (GLuint index, GLshort x); + void (APIENTRY *VertexAttrib1svARB) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib2dARB) (GLuint index, GLdouble x, GLdouble y); + void (APIENTRY *VertexAttrib2dvARB) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib2fARB) (GLuint index, GLfloat x, GLfloat y); + void (APIENTRY *VertexAttrib2fvARB) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib2sARB) (GLuint index, GLshort x, GLshort y); + void (APIENTRY *VertexAttrib2svARB) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib3dARB) (GLuint index, GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY *VertexAttrib3dvARB) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib3fARB) (GLuint index, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *VertexAttrib3fvARB) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib3sARB) (GLuint index, GLshort x, GLshort y, GLshort z); + void (APIENTRY *VertexAttrib3svARB) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib4NbvARB) (GLuint index, const GLbyte *v); + void (APIENTRY *VertexAttrib4NivARB) (GLuint index, const GLint *v); + void (APIENTRY *VertexAttrib4NsvARB) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib4NubARB) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); + void (APIENTRY *VertexAttrib4NubvARB) (GLuint index, const GLubyte *v); + void (APIENTRY *VertexAttrib4NuivARB) (GLuint index, const GLuint *v); + void (APIENTRY *VertexAttrib4NusvARB) (GLuint index, const GLushort *v); + void (APIENTRY *VertexAttrib4bvARB) (GLuint index, const GLbyte *v); + void (APIENTRY *VertexAttrib4dARB) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *VertexAttrib4dvARB) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib4fARB) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *VertexAttrib4fvARB) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib4ivARB) (GLuint index, const GLint *v); + void (APIENTRY *VertexAttrib4sARB) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); + void (APIENTRY *VertexAttrib4svARB) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib4ubvARB) (GLuint index, const GLubyte *v); + void (APIENTRY *VertexAttrib4uivARB) (GLuint index, const GLuint *v); + void (APIENTRY *VertexAttrib4usvARB) (GLuint index, const GLushort *v); + void (APIENTRY *VertexAttribPointerARB) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *EnableVertexAttribArrayARB) (GLuint index); + void (APIENTRY *DisableVertexAttribArrayARB) (GLuint index); + void (APIENTRY *ProgramStringARB) (GLenum target, GLenum format, GLsizei len, const GLvoid *string); + void (APIENTRY *BindProgramARB) (GLenum target, GLuint program); + void (APIENTRY *DeleteProgramsARB) (GLsizei n, const GLuint *programs); + void (APIENTRY *GenProgramsARB) (GLsizei n, GLuint *programs); + void (APIENTRY *ProgramEnvParameter4dARB) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *ProgramEnvParameter4dvARB) (GLenum target, GLuint index, const GLdouble *params); + void (APIENTRY *ProgramEnvParameter4fARB) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *ProgramEnvParameter4fvARB) (GLenum target, GLuint index, const GLfloat *params); + void (APIENTRY *ProgramLocalParameter4dARB) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *ProgramLocalParameter4dvARB) (GLenum target, GLuint index, const GLdouble *params); + void (APIENTRY *ProgramLocalParameter4fARB) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *ProgramLocalParameter4fvARB) (GLenum target, GLuint index, const GLfloat *params); + void (APIENTRY *GetProgramEnvParameterdvARB) (GLenum target, GLuint index, GLdouble *params); + void (APIENTRY *GetProgramEnvParameterfvARB) (GLenum target, GLuint index, GLfloat *params); + void (APIENTRY *GetProgramLocalParameterdvARB) (GLenum target, GLuint index, GLdouble *params); + void (APIENTRY *GetProgramLocalParameterfvARB) (GLenum target, GLuint index, GLfloat *params); + void (APIENTRY *GetProgramivARB) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetProgramStringARB) (GLenum target, GLenum pname, GLvoid *string); + void (APIENTRY *GetVertexAttribdvARB) (GLuint index, GLenum pname, GLdouble *params); + void (APIENTRY *GetVertexAttribfvARB) (GLuint index, GLenum pname, GLfloat *params); + void (APIENTRY *GetVertexAttribivARB) (GLuint index, GLenum pname, GLint *params); + void (APIENTRY *GetVertexAttribPointervARB) (GLuint index, GLenum pname, GLvoid* *pointer); + GLboolean (APIENTRY *IsProgramARB) (GLuint program); + void (APIENTRY *BindBufferARB) (GLenum target, GLuint buffer); + void (APIENTRY *DeleteBuffersARB) (GLsizei n, const GLuint *buffers); + void (APIENTRY *GenBuffersARB) (GLsizei n, GLuint *buffers); + GLboolean (APIENTRY *IsBufferARB) (GLuint buffer); + void (APIENTRY *BufferDataARB) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); + void (APIENTRY *BufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); + void (APIENTRY *GetBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); + GLvoid* (APIENTRY *MapBufferARB) (GLenum target, GLenum access); + GLboolean (APIENTRY *UnmapBufferARB) (GLenum target); + void (APIENTRY *GetBufferParameterivARB) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetBufferPointervARB) (GLenum target, GLenum pname, GLvoid* *params); + void (APIENTRY *GenQueriesARB) (GLsizei n, GLuint *ids); + void (APIENTRY *DeleteQueriesARB) (GLsizei n, const GLuint *ids); + GLboolean (APIENTRY *IsQueryARB) (GLuint id); + void (APIENTRY *BeginQueryARB) (GLenum target, GLuint id); + void (APIENTRY *EndQueryARB) (GLenum target); + void (APIENTRY *GetQueryivARB) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetQueryObjectivARB) (GLuint id, GLenum pname, GLint *params); + void (APIENTRY *GetQueryObjectuivARB) (GLuint id, GLenum pname, GLuint *params); + void (APIENTRY *DeleteObjectARB) (GLhandleARB obj); + GLhandleARB (APIENTRY *GetHandleARB) (GLenum pname); + void (APIENTRY *DetachObjectARB) (GLhandleARB containerObj, GLhandleARB attachedObj); + GLhandleARB (APIENTRY *CreateShaderObjectARB) (GLenum shaderType); + void (APIENTRY *ShaderSourceARB) (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length); + void (APIENTRY *CompileShaderARB) (GLhandleARB shaderObj); + GLhandleARB (APIENTRY *CreateProgramObjectARB) (void); + void (APIENTRY *AttachObjectARB) (GLhandleARB containerObj, GLhandleARB obj); + void (APIENTRY *LinkProgramARB) (GLhandleARB programObj); + void (APIENTRY *UseProgramObjectARB) (GLhandleARB programObj); + void (APIENTRY *ValidateProgramARB) (GLhandleARB programObj); + void (APIENTRY *Uniform1fARB) (GLint location, GLfloat v0); + void (APIENTRY *Uniform2fARB) (GLint location, GLfloat v0, GLfloat v1); + void (APIENTRY *Uniform3fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); + void (APIENTRY *Uniform4fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); + void (APIENTRY *Uniform1iARB) (GLint location, GLint v0); + void (APIENTRY *Uniform2iARB) (GLint location, GLint v0, GLint v1); + void (APIENTRY *Uniform3iARB) (GLint location, GLint v0, GLint v1, GLint v2); + void (APIENTRY *Uniform4iARB) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); + void (APIENTRY *Uniform1fvARB) (GLint location, GLsizei count, const GLfloat *value); + void (APIENTRY *Uniform2fvARB) (GLint location, GLsizei count, const GLfloat *value); + void (APIENTRY *Uniform3fvARB) (GLint location, GLsizei count, const GLfloat *value); + void (APIENTRY *Uniform4fvARB) (GLint location, GLsizei count, const GLfloat *value); + void (APIENTRY *Uniform1ivARB) (GLint location, GLsizei count, const GLint *value); + void (APIENTRY *Uniform2ivARB) (GLint location, GLsizei count, const GLint *value); + void (APIENTRY *Uniform3ivARB) (GLint location, GLsizei count, const GLint *value); + void (APIENTRY *Uniform4ivARB) (GLint location, GLsizei count, const GLint *value); + void (APIENTRY *UniformMatrix2fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void (APIENTRY *UniformMatrix3fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void (APIENTRY *UniformMatrix4fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void (APIENTRY *GetObjectParameterfvARB) (GLhandleARB obj, GLenum pname, GLfloat *params); + void (APIENTRY *GetObjectParameterivARB) (GLhandleARB obj, GLenum pname, GLint *params); + void (APIENTRY *GetInfoLogARB) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); + void (APIENTRY *GetAttachedObjectsARB) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); + GLint (APIENTRY *GetUniformLocationARB) (GLhandleARB programObj, const GLcharARB *name); + void (APIENTRY *GetActiveUniformARB) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); + void (APIENTRY *GetUniformfvARB) (GLhandleARB programObj, GLint location, GLfloat *params); + void (APIENTRY *GetUniformivARB) (GLhandleARB programObj, GLint location, GLint *params); + void (APIENTRY *GetShaderSourceARB) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); + void (APIENTRY *BindAttribLocationARB) (GLhandleARB programObj, GLuint index, const GLcharARB *name); + void (APIENTRY *GetActiveAttribARB) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); + GLint (APIENTRY *GetAttribLocationARB) (GLhandleARB programObj, const GLcharARB *name); + void (APIENTRY *BlendColorEXT) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void (APIENTRY *PolygonOffsetEXT) (GLfloat factor, GLfloat bias); + void (APIENTRY *TexImage3DEXT) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *TexSubImage3DEXT) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *GetTexFilterFuncSGIS) (GLenum target, GLenum filter, GLfloat *weights); + void (APIENTRY *TexFilterFuncSGIS) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); + void (APIENTRY *TexSubImage1DEXT) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *TexSubImage2DEXT) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *CopyTexImage1DEXT) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); + void (APIENTRY *CopyTexImage2DEXT) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); + void (APIENTRY *CopyTexSubImage1DEXT) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); + void (APIENTRY *CopyTexSubImage2DEXT) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY *CopyTexSubImage3DEXT) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY *GetHistogramEXT) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); + void (APIENTRY *GetHistogramParameterfvEXT) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetHistogramParameterivEXT) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetMinmaxEXT) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); + void (APIENTRY *GetMinmaxParameterfvEXT) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetMinmaxParameterivEXT) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *HistogramEXT) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); + void (APIENTRY *MinmaxEXT) (GLenum target, GLenum internalformat, GLboolean sink); + void (APIENTRY *ResetHistogramEXT) (GLenum target); + void (APIENTRY *ResetMinmaxEXT) (GLenum target); + void (APIENTRY *ConvolutionFilter1DEXT) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); + void (APIENTRY *ConvolutionFilter2DEXT) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); + void (APIENTRY *ConvolutionParameterfEXT) (GLenum target, GLenum pname, GLfloat params); + void (APIENTRY *ConvolutionParameterfvEXT) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *ConvolutionParameteriEXT) (GLenum target, GLenum pname, GLint params); + void (APIENTRY *ConvolutionParameterivEXT) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *CopyConvolutionFilter1DEXT) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); + void (APIENTRY *CopyConvolutionFilter2DEXT) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY *GetConvolutionFilterEXT) (GLenum target, GLenum format, GLenum type, GLvoid *image); + void (APIENTRY *GetConvolutionParameterfvEXT) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetConvolutionParameterivEXT) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetSeparableFilterEXT) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); + void (APIENTRY *SeparableFilter2DEXT) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); + void (APIENTRY *ColorTableSGI) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); + void (APIENTRY *ColorTableParameterfvSGI) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *ColorTableParameterivSGI) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *CopyColorTableSGI) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); + void (APIENTRY *GetColorTableSGI) (GLenum target, GLenum format, GLenum type, GLvoid *table); + void (APIENTRY *GetColorTableParameterfvSGI) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetColorTableParameterivSGI) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *PixelTexGenSGIX) (GLenum mode); + void (APIENTRY *PixelTexGenParameteriSGIS) (GLenum pname, GLint param); + void (APIENTRY *PixelTexGenParameterivSGIS) (GLenum pname, const GLint *params); + void (APIENTRY *PixelTexGenParameterfSGIS) (GLenum pname, GLfloat param); + void (APIENTRY *PixelTexGenParameterfvSGIS) (GLenum pname, const GLfloat *params); + void (APIENTRY *GetPixelTexGenParameterivSGIS) (GLenum pname, GLint *params); + void (APIENTRY *GetPixelTexGenParameterfvSGIS) (GLenum pname, GLfloat *params); + void (APIENTRY *TexImage4DSGIS) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *TexSubImage4DSGIS) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels); + GLboolean (APIENTRY *AreTexturesResidentEXT) (GLsizei n, const GLuint *textures, GLboolean *residences); + void (APIENTRY *BindTextureEXT) (GLenum target, GLuint texture); + void (APIENTRY *DeleteTexturesEXT) (GLsizei n, const GLuint *textures); + void (APIENTRY *GenTexturesEXT) (GLsizei n, GLuint *textures); + GLboolean (APIENTRY *IsTextureEXT) (GLuint texture); + void (APIENTRY *PrioritizeTexturesEXT) (GLsizei n, const GLuint *textures, const GLclampf *priorities); + void (APIENTRY *DetailTexFuncSGIS) (GLenum target, GLsizei n, const GLfloat *points); + void (APIENTRY *GetDetailTexFuncSGIS) (GLenum target, GLfloat *points); + void (APIENTRY *SharpenTexFuncSGIS) (GLenum target, GLsizei n, const GLfloat *points); + void (APIENTRY *GetSharpenTexFuncSGIS) (GLenum target, GLfloat *points); + void (APIENTRY *SampleMaskSGIS) (GLclampf value, GLboolean invert); + void (APIENTRY *SamplePatternSGIS) (GLenum pattern); + void (APIENTRY *ArrayElementEXT) (GLint i); + void (APIENTRY *ColorPointerEXT) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); + void (APIENTRY *DrawArraysEXT) (GLenum mode, GLint first, GLsizei count); + void (APIENTRY *EdgeFlagPointerEXT) (GLsizei stride, GLsizei count, const GLboolean *pointer); + void (APIENTRY *GetPointervEXT) (GLenum pname, GLvoid* *params); + void (APIENTRY *IndexPointerEXT) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); + void (APIENTRY *NormalPointerEXT) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); + void (APIENTRY *TexCoordPointerEXT) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); + void (APIENTRY *VertexPointerEXT) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); + void (APIENTRY *BlendEquationEXT) (GLenum mode); + void (APIENTRY *SpriteParameterfSGIX) (GLenum pname, GLfloat param); + void (APIENTRY *SpriteParameterfvSGIX) (GLenum pname, const GLfloat *params); + void (APIENTRY *SpriteParameteriSGIX) (GLenum pname, GLint param); + void (APIENTRY *SpriteParameterivSGIX) (GLenum pname, const GLint *params); + void (APIENTRY *PointParameterfEXT) (GLenum pname, GLfloat param); + void (APIENTRY *PointParameterfvEXT) (GLenum pname, const GLfloat *params); + void (APIENTRY *PointParameterfSGIS) (GLenum pname, GLfloat param); + void (APIENTRY *PointParameterfvSGIS) (GLenum pname, const GLfloat *params); + GLint (APIENTRY *GetInstrumentsSGIX) (void); + void (APIENTRY *InstrumentsBufferSGIX) (GLsizei size, GLint *buffer); + GLint (APIENTRY *PollInstrumentsSGIX) (GLint *marker_p); + void (APIENTRY *ReadInstrumentsSGIX) (GLint marker); + void (APIENTRY *StartInstrumentsSGIX) (void); + void (APIENTRY *StopInstrumentsSGIX) (GLint marker); + void (APIENTRY *FrameZoomSGIX) (GLint factor); + void (APIENTRY *TagSampleBufferSGIX) (void); + void (APIENTRY *DeformationMap3dSGIX) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); + void (APIENTRY *DeformationMap3fSGIX) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); + void (APIENTRY *DeformSGIX) (GLbitfield mask); + void (APIENTRY *LoadIdentityDeformationMapSGIX) (GLbitfield mask); + void (APIENTRY *ReferencePlaneSGIX) (const GLdouble *equation); + void (APIENTRY *FlushRasterSGIX) (void); + void (APIENTRY *FogFuncSGIS) (GLsizei n, const GLfloat *points); + void (APIENTRY *GetFogFuncSGIS) (GLfloat *points); + void (APIENTRY *ImageTransformParameteriHP) (GLenum target, GLenum pname, GLint param); + void (APIENTRY *ImageTransformParameterfHP) (GLenum target, GLenum pname, GLfloat param); + void (APIENTRY *ImageTransformParameterivHP) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *ImageTransformParameterfvHP) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *GetImageTransformParameterivHP) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetImageTransformParameterfvHP) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *ColorSubTableEXT) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); + void (APIENTRY *CopyColorSubTableEXT) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); + void (APIENTRY *HintPGI) (GLenum target, GLint mode); + void (APIENTRY *ColorTableEXT) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); + void (APIENTRY *GetColorTableEXT) (GLenum target, GLenum format, GLenum type, GLvoid *data); + void (APIENTRY *GetColorTableParameterivEXT) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetColorTableParameterfvEXT) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetListParameterfvSGIX) (GLuint list, GLenum pname, GLfloat *params); + void (APIENTRY *GetListParameterivSGIX) (GLuint list, GLenum pname, GLint *params); + void (APIENTRY *ListParameterfSGIX) (GLuint list, GLenum pname, GLfloat param); + void (APIENTRY *ListParameterfvSGIX) (GLuint list, GLenum pname, const GLfloat *params); + void (APIENTRY *ListParameteriSGIX) (GLuint list, GLenum pname, GLint param); + void (APIENTRY *ListParameterivSGIX) (GLuint list, GLenum pname, const GLint *params); + void (APIENTRY *IndexMaterialEXT) (GLenum face, GLenum mode); + void (APIENTRY *IndexFuncEXT) (GLenum func, GLclampf ref); + void (APIENTRY *LockArraysEXT) (GLint first, GLsizei count); + void (APIENTRY *UnlockArraysEXT) (void); + void (APIENTRY *CullParameterdvEXT) (GLenum pname, GLdouble *params); + void (APIENTRY *CullParameterfvEXT) (GLenum pname, GLfloat *params); + void (APIENTRY *FragmentColorMaterialSGIX) (GLenum face, GLenum mode); + void (APIENTRY *FragmentLightfSGIX) (GLenum light, GLenum pname, GLfloat param); + void (APIENTRY *FragmentLightfvSGIX) (GLenum light, GLenum pname, const GLfloat *params); + void (APIENTRY *FragmentLightiSGIX) (GLenum light, GLenum pname, GLint param); + void (APIENTRY *FragmentLightivSGIX) (GLenum light, GLenum pname, const GLint *params); + void (APIENTRY *FragmentLightModelfSGIX) (GLenum pname, GLfloat param); + void (APIENTRY *FragmentLightModelfvSGIX) (GLenum pname, const GLfloat *params); + void (APIENTRY *FragmentLightModeliSGIX) (GLenum pname, GLint param); + void (APIENTRY *FragmentLightModelivSGIX) (GLenum pname, const GLint *params); + void (APIENTRY *FragmentMaterialfSGIX) (GLenum face, GLenum pname, GLfloat param); + void (APIENTRY *FragmentMaterialfvSGIX) (GLenum face, GLenum pname, const GLfloat *params); + void (APIENTRY *FragmentMaterialiSGIX) (GLenum face, GLenum pname, GLint param); + void (APIENTRY *FragmentMaterialivSGIX) (GLenum face, GLenum pname, const GLint *params); + void (APIENTRY *GetFragmentLightfvSGIX) (GLenum light, GLenum pname, GLfloat *params); + void (APIENTRY *GetFragmentLightivSGIX) (GLenum light, GLenum pname, GLint *params); + void (APIENTRY *GetFragmentMaterialfvSGIX) (GLenum face, GLenum pname, GLfloat *params); + void (APIENTRY *GetFragmentMaterialivSGIX) (GLenum face, GLenum pname, GLint *params); + void (APIENTRY *LightEnviSGIX) (GLenum pname, GLint param); + void (APIENTRY *DrawRangeElementsEXT) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); + void (APIENTRY *ApplyTextureEXT) (GLenum mode); + void (APIENTRY *TextureLightEXT) (GLenum pname); + void (APIENTRY *TextureMaterialEXT) (GLenum face, GLenum mode); + void (APIENTRY *AsyncMarkerSGIX) (GLuint marker); + GLint (APIENTRY *FinishAsyncSGIX) (GLuint *markerp); + GLint (APIENTRY *PollAsyncSGIX) (GLuint *markerp); + GLuint (APIENTRY *GenAsyncMarkersSGIX) (GLsizei range); + void (APIENTRY *DeleteAsyncMarkersSGIX) (GLuint marker, GLsizei range); + GLboolean (APIENTRY *IsAsyncMarkerSGIX) (GLuint marker); + void (APIENTRY *VertexPointervINTEL) (GLint size, GLenum type, const GLvoid* *pointer); + void (APIENTRY *NormalPointervINTEL) (GLenum type, const GLvoid* *pointer); + void (APIENTRY *ColorPointervINTEL) (GLint size, GLenum type, const GLvoid* *pointer); + void (APIENTRY *TexCoordPointervINTEL) (GLint size, GLenum type, const GLvoid* *pointer); + void (APIENTRY *PixelTransformParameteriEXT) (GLenum target, GLenum pname, GLint param); + void (APIENTRY *PixelTransformParameterfEXT) (GLenum target, GLenum pname, GLfloat param); + void (APIENTRY *PixelTransformParameterivEXT) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *PixelTransformParameterfvEXT) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *SecondaryColor3bEXT) (GLbyte red, GLbyte green, GLbyte blue); + void (APIENTRY *SecondaryColor3bvEXT) (const GLbyte *v); + void (APIENTRY *SecondaryColor3dEXT) (GLdouble red, GLdouble green, GLdouble blue); + void (APIENTRY *SecondaryColor3dvEXT) (const GLdouble *v); + void (APIENTRY *SecondaryColor3fEXT) (GLfloat red, GLfloat green, GLfloat blue); + void (APIENTRY *SecondaryColor3fvEXT) (const GLfloat *v); + void (APIENTRY *SecondaryColor3iEXT) (GLint red, GLint green, GLint blue); + void (APIENTRY *SecondaryColor3ivEXT) (const GLint *v); + void (APIENTRY *SecondaryColor3sEXT) (GLshort red, GLshort green, GLshort blue); + void (APIENTRY *SecondaryColor3svEXT) (const GLshort *v); + void (APIENTRY *SecondaryColor3ubEXT) (GLubyte red, GLubyte green, GLubyte blue); + void (APIENTRY *SecondaryColor3ubvEXT) (const GLubyte *v); + void (APIENTRY *SecondaryColor3uiEXT) (GLuint red, GLuint green, GLuint blue); + void (APIENTRY *SecondaryColor3uivEXT) (const GLuint *v); + void (APIENTRY *SecondaryColor3usEXT) (GLushort red, GLushort green, GLushort blue); + void (APIENTRY *SecondaryColor3usvEXT) (const GLushort *v); + void (APIENTRY *SecondaryColorPointerEXT) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *TextureNormalEXT) (GLenum mode); + void (APIENTRY *MultiDrawArraysEXT) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); + void (APIENTRY *MultiDrawElementsEXT) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); + void (APIENTRY *FogCoordfEXT) (GLfloat coord); + void (APIENTRY *FogCoordfvEXT) (const GLfloat *coord); + void (APIENTRY *FogCoorddEXT) (GLdouble coord); + void (APIENTRY *FogCoorddvEXT) (const GLdouble *coord); + void (APIENTRY *FogCoordPointerEXT) (GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *Tangent3bEXT) (GLbyte tx, GLbyte ty, GLbyte tz); + void (APIENTRY *Tangent3bvEXT) (const GLbyte *v); + void (APIENTRY *Tangent3dEXT) (GLdouble tx, GLdouble ty, GLdouble tz); + void (APIENTRY *Tangent3dvEXT) (const GLdouble *v); + void (APIENTRY *Tangent3fEXT) (GLfloat tx, GLfloat ty, GLfloat tz); + void (APIENTRY *Tangent3fvEXT) (const GLfloat *v); + void (APIENTRY *Tangent3iEXT) (GLint tx, GLint ty, GLint tz); + void (APIENTRY *Tangent3ivEXT) (const GLint *v); + void (APIENTRY *Tangent3sEXT) (GLshort tx, GLshort ty, GLshort tz); + void (APIENTRY *Tangent3svEXT) (const GLshort *v); + void (APIENTRY *Binormal3bEXT) (GLbyte bx, GLbyte by, GLbyte bz); + void (APIENTRY *Binormal3bvEXT) (const GLbyte *v); + void (APIENTRY *Binormal3dEXT) (GLdouble bx, GLdouble by, GLdouble bz); + void (APIENTRY *Binormal3dvEXT) (const GLdouble *v); + void (APIENTRY *Binormal3fEXT) (GLfloat bx, GLfloat by, GLfloat bz); + void (APIENTRY *Binormal3fvEXT) (const GLfloat *v); + void (APIENTRY *Binormal3iEXT) (GLint bx, GLint by, GLint bz); + void (APIENTRY *Binormal3ivEXT) (const GLint *v); + void (APIENTRY *Binormal3sEXT) (GLshort bx, GLshort by, GLshort bz); + void (APIENTRY *Binormal3svEXT) (const GLshort *v); + void (APIENTRY *TangentPointerEXT) (GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *BinormalPointerEXT) (GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *FinishTextureSUNX) (void); + void (APIENTRY *GlobalAlphaFactorbSUN) (GLbyte factor); + void (APIENTRY *GlobalAlphaFactorsSUN) (GLshort factor); + void (APIENTRY *GlobalAlphaFactoriSUN) (GLint factor); + void (APIENTRY *GlobalAlphaFactorfSUN) (GLfloat factor); + void (APIENTRY *GlobalAlphaFactordSUN) (GLdouble factor); + void (APIENTRY *GlobalAlphaFactorubSUN) (GLubyte factor); + void (APIENTRY *GlobalAlphaFactorusSUN) (GLushort factor); + void (APIENTRY *GlobalAlphaFactoruiSUN) (GLuint factor); + void (APIENTRY *ReplacementCodeuiSUN) (GLuint code); + void (APIENTRY *ReplacementCodeusSUN) (GLushort code); + void (APIENTRY *ReplacementCodeubSUN) (GLubyte code); + void (APIENTRY *ReplacementCodeuivSUN) (const GLuint *code); + void (APIENTRY *ReplacementCodeusvSUN) (const GLushort *code); + void (APIENTRY *ReplacementCodeubvSUN) (const GLubyte *code); + void (APIENTRY *ReplacementCodePointerSUN) (GLenum type, GLsizei stride, const GLvoid* *pointer); + void (APIENTRY *Color4ubVertex2fSUN) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); + void (APIENTRY *Color4ubVertex2fvSUN) (const GLubyte *c, const GLfloat *v); + void (APIENTRY *Color4ubVertex3fSUN) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *Color4ubVertex3fvSUN) (const GLubyte *c, const GLfloat *v); + void (APIENTRY *Color3fVertex3fSUN) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *Color3fVertex3fvSUN) (const GLfloat *c, const GLfloat *v); + void (APIENTRY *Normal3fVertex3fSUN) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *Normal3fVertex3fvSUN) (const GLfloat *n, const GLfloat *v); + void (APIENTRY *Color4fNormal3fVertex3fSUN) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *Color4fNormal3fVertex3fvSUN) (const GLfloat *c, const GLfloat *n, const GLfloat *v); + void (APIENTRY *TexCoord2fVertex3fSUN) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *TexCoord2fVertex3fvSUN) (const GLfloat *tc, const GLfloat *v); + void (APIENTRY *TexCoord4fVertex4fSUN) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *TexCoord4fVertex4fvSUN) (const GLfloat *tc, const GLfloat *v); + void (APIENTRY *TexCoord2fColor4ubVertex3fSUN) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *TexCoord2fColor4ubVertex3fvSUN) (const GLfloat *tc, const GLubyte *c, const GLfloat *v); + void (APIENTRY *TexCoord2fColor3fVertex3fSUN) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *TexCoord2fColor3fVertex3fvSUN) (const GLfloat *tc, const GLfloat *c, const GLfloat *v); + void (APIENTRY *TexCoord2fNormal3fVertex3fSUN) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *TexCoord2fNormal3fVertex3fvSUN) (const GLfloat *tc, const GLfloat *n, const GLfloat *v); + void (APIENTRY *TexCoord2fColor4fNormal3fVertex3fSUN) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *TexCoord2fColor4fNormal3fVertex3fvSUN) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); + void (APIENTRY *TexCoord4fColor4fNormal3fVertex4fSUN) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *TexCoord4fColor4fNormal3fVertex4fvSUN) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiVertex3fSUN) (GLuint rc, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiVertex3fvSUN) (const GLuint *rc, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiColor4ubVertex3fSUN) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiColor4ubVertex3fvSUN) (const GLuint *rc, const GLubyte *c, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiColor3fVertex3fSUN) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiColor3fVertex3fvSUN) (const GLuint *rc, const GLfloat *c, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiNormal3fVertex3fSUN) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiNormal3fVertex3fvSUN) (const GLuint *rc, const GLfloat *n, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiColor4fNormal3fVertex3fSUN) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiColor4fNormal3fVertex3fvSUN) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiTexCoord2fVertex3fSUN) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiTexCoord2fVertex3fvSUN) (const GLuint *rc, const GLfloat *tc, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiTexCoord2fNormal3fVertex3fSUN) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); + void (APIENTRY *BlendFuncSeparateEXT) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); + void (APIENTRY *BlendFuncSeparateINGR) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); + void (APIENTRY *VertexWeightfEXT) (GLfloat weight); + void (APIENTRY *VertexWeightfvEXT) (const GLfloat *weight); + void (APIENTRY *VertexWeightPointerEXT) (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *FlushVertexArrayRangeNV) (void); + void (APIENTRY *VertexArrayRangeNV) (GLsizei length, const GLvoid *pointer); + void (APIENTRY *CombinerParameterfvNV) (GLenum pname, const GLfloat *params); + void (APIENTRY *CombinerParameterfNV) (GLenum pname, GLfloat param); + void (APIENTRY *CombinerParameterivNV) (GLenum pname, const GLint *params); + void (APIENTRY *CombinerParameteriNV) (GLenum pname, GLint param); + void (APIENTRY *CombinerInputNV) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); + void (APIENTRY *CombinerOutputNV) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); + void (APIENTRY *FinalCombinerInputNV) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); + void (APIENTRY *GetCombinerInputParameterfvNV) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); + void (APIENTRY *GetCombinerInputParameterivNV) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); + void (APIENTRY *GetCombinerOutputParameterfvNV) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); + void (APIENTRY *GetCombinerOutputParameterivNV) (GLenum stage, GLenum portion, GLenum pname, GLint *params); + void (APIENTRY *GetFinalCombinerInputParameterfvNV) (GLenum variable, GLenum pname, GLfloat *params); + void (APIENTRY *GetFinalCombinerInputParameterivNV) (GLenum variable, GLenum pname, GLint *params); + void (APIENTRY *ResizeBuffersMESA) (void); + void (APIENTRY *WindowPos2dMESA) (GLdouble x, GLdouble y); + void (APIENTRY *WindowPos2dvMESA) (const GLdouble *v); + void (APIENTRY *WindowPos2fMESA) (GLfloat x, GLfloat y); + void (APIENTRY *WindowPos2fvMESA) (const GLfloat *v); + void (APIENTRY *WindowPos2iMESA) (GLint x, GLint y); + void (APIENTRY *WindowPos2ivMESA) (const GLint *v); + void (APIENTRY *WindowPos2sMESA) (GLshort x, GLshort y); + void (APIENTRY *WindowPos2svMESA) (const GLshort *v); + void (APIENTRY *WindowPos3dMESA) (GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY *WindowPos3dvMESA) (const GLdouble *v); + void (APIENTRY *WindowPos3fMESA) (GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *WindowPos3fvMESA) (const GLfloat *v); + void (APIENTRY *WindowPos3iMESA) (GLint x, GLint y, GLint z); + void (APIENTRY *WindowPos3ivMESA) (const GLint *v); + void (APIENTRY *WindowPos3sMESA) (GLshort x, GLshort y, GLshort z); + void (APIENTRY *WindowPos3svMESA) (const GLshort *v); + void (APIENTRY *WindowPos4dMESA) (GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *WindowPos4dvMESA) (const GLdouble *v); + void (APIENTRY *WindowPos4fMESA) (GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *WindowPos4fvMESA) (const GLfloat *v); + void (APIENTRY *WindowPos4iMESA) (GLint x, GLint y, GLint z, GLint w); + void (APIENTRY *WindowPos4ivMESA) (const GLint *v); + void (APIENTRY *WindowPos4sMESA) (GLshort x, GLshort y, GLshort z, GLshort w); + void (APIENTRY *WindowPos4svMESA) (const GLshort *v); + void (APIENTRY *MultiModeDrawArraysIBM) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); + void (APIENTRY *MultiModeDrawElementsIBM) (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride); + void (APIENTRY *ColorPointerListIBM) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *SecondaryColorPointerListIBM) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *EdgeFlagPointerListIBM) (GLint stride, const GLboolean* *pointer, GLint ptrstride); + void (APIENTRY *FogCoordPointerListIBM) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *IndexPointerListIBM) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *NormalPointerListIBM) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *TexCoordPointerListIBM) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *VertexPointerListIBM) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *TbufferMask3DFX) (GLuint mask); + void (APIENTRY *SampleMaskEXT) (GLclampf value, GLboolean invert); + void (APIENTRY *SamplePatternEXT) (GLenum pattern); + void (APIENTRY *TextureColorMaskSGIS) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); + void (APIENTRY *IglooInterfaceSGIX) (GLenum pname, const GLvoid *params); + void (APIENTRY *DeleteFencesNV) (GLsizei n, const GLuint *fences); + void (APIENTRY *GenFencesNV) (GLsizei n, GLuint *fences); + GLboolean (APIENTRY *IsFenceNV) (GLuint fence); + GLboolean (APIENTRY *TestFenceNV) (GLuint fence); + void (APIENTRY *GetFenceivNV) (GLuint fence, GLenum pname, GLint *params); + void (APIENTRY *FinishFenceNV) (GLuint fence); + void (APIENTRY *SetFenceNV) (GLuint fence, GLenum condition); + void (APIENTRY *MapControlPointsNV) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points); + void (APIENTRY *MapParameterivNV) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *MapParameterfvNV) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *GetMapControlPointsNV) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points); + void (APIENTRY *GetMapParameterivNV) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetMapParameterfvNV) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetMapAttribParameterivNV) (GLenum target, GLuint index, GLenum pname, GLint *params); + void (APIENTRY *GetMapAttribParameterfvNV) (GLenum target, GLuint index, GLenum pname, GLfloat *params); + void (APIENTRY *EvalMapsNV) (GLenum target, GLenum mode); + void (APIENTRY *CombinerStageParameterfvNV) (GLenum stage, GLenum pname, const GLfloat *params); + void (APIENTRY *GetCombinerStageParameterfvNV) (GLenum stage, GLenum pname, GLfloat *params); + GLboolean (APIENTRY *AreProgramsResidentNV) (GLsizei n, const GLuint *programs, GLboolean *residences); + void (APIENTRY *BindProgramNV) (GLenum target, GLuint id); + void (APIENTRY *DeleteProgramsNV) (GLsizei n, const GLuint *programs); + void (APIENTRY *ExecuteProgramNV) (GLenum target, GLuint id, const GLfloat *params); + void (APIENTRY *GenProgramsNV) (GLsizei n, GLuint *programs); + void (APIENTRY *GetProgramParameterdvNV) (GLenum target, GLuint index, GLenum pname, GLdouble *params); + void (APIENTRY *GetProgramParameterfvNV) (GLenum target, GLuint index, GLenum pname, GLfloat *params); + void (APIENTRY *GetProgramivNV) (GLuint id, GLenum pname, GLint *params); + void (APIENTRY *GetProgramStringNV) (GLuint id, GLenum pname, GLubyte *program); + void (APIENTRY *GetTrackMatrixivNV) (GLenum target, GLuint address, GLenum pname, GLint *params); + void (APIENTRY *GetVertexAttribdvNV) (GLuint index, GLenum pname, GLdouble *params); + void (APIENTRY *GetVertexAttribfvNV) (GLuint index, GLenum pname, GLfloat *params); + void (APIENTRY *GetVertexAttribivNV) (GLuint index, GLenum pname, GLint *params); + void (APIENTRY *GetVertexAttribPointervNV) (GLuint index, GLenum pname, GLvoid* *pointer); + GLboolean (APIENTRY *IsProgramNV) (GLuint id); + void (APIENTRY *LoadProgramNV) (GLenum target, GLuint id, GLsizei len, const GLubyte *program); + void (APIENTRY *ProgramParameter4dNV) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *ProgramParameter4dvNV) (GLenum target, GLuint index, const GLdouble *v); + void (APIENTRY *ProgramParameter4fNV) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *ProgramParameter4fvNV) (GLenum target, GLuint index, const GLfloat *v); + void (APIENTRY *ProgramParameters4dvNV) (GLenum target, GLuint index, GLuint count, const GLdouble *v); + void (APIENTRY *ProgramParameters4fvNV) (GLenum target, GLuint index, GLuint count, const GLfloat *v); + void (APIENTRY *RequestResidentProgramsNV) (GLsizei n, const GLuint *programs); + void (APIENTRY *TrackMatrixNV) (GLenum target, GLuint address, GLenum matrix, GLenum transform); + void (APIENTRY *VertexAttribPointerNV) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *VertexAttrib1dNV) (GLuint index, GLdouble x); + void (APIENTRY *VertexAttrib1dvNV) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib1fNV) (GLuint index, GLfloat x); + void (APIENTRY *VertexAttrib1fvNV) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib1sNV) (GLuint index, GLshort x); + void (APIENTRY *VertexAttrib1svNV) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib2dNV) (GLuint index, GLdouble x, GLdouble y); + void (APIENTRY *VertexAttrib2dvNV) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib2fNV) (GLuint index, GLfloat x, GLfloat y); + void (APIENTRY *VertexAttrib2fvNV) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib2sNV) (GLuint index, GLshort x, GLshort y); + void (APIENTRY *VertexAttrib2svNV) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib3dNV) (GLuint index, GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY *VertexAttrib3dvNV) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib3fNV) (GLuint index, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *VertexAttrib3fvNV) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib3sNV) (GLuint index, GLshort x, GLshort y, GLshort z); + void (APIENTRY *VertexAttrib3svNV) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib4dNV) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *VertexAttrib4dvNV) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib4fNV) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *VertexAttrib4fvNV) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib4sNV) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); + void (APIENTRY *VertexAttrib4svNV) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib4ubNV) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); + void (APIENTRY *VertexAttrib4ubvNV) (GLuint index, const GLubyte *v); + void (APIENTRY *VertexAttribs1dvNV) (GLuint index, GLsizei count, const GLdouble *v); + void (APIENTRY *VertexAttribs1fvNV) (GLuint index, GLsizei count, const GLfloat *v); + void (APIENTRY *VertexAttribs1svNV) (GLuint index, GLsizei count, const GLshort *v); + void (APIENTRY *VertexAttribs2dvNV) (GLuint index, GLsizei count, const GLdouble *v); + void (APIENTRY *VertexAttribs2fvNV) (GLuint index, GLsizei count, const GLfloat *v); + void (APIENTRY *VertexAttribs2svNV) (GLuint index, GLsizei count, const GLshort *v); + void (APIENTRY *VertexAttribs3dvNV) (GLuint index, GLsizei count, const GLdouble *v); + void (APIENTRY *VertexAttribs3fvNV) (GLuint index, GLsizei count, const GLfloat *v); + void (APIENTRY *VertexAttribs3svNV) (GLuint index, GLsizei count, const GLshort *v); + void (APIENTRY *VertexAttribs4dvNV) (GLuint index, GLsizei count, const GLdouble *v); + void (APIENTRY *VertexAttribs4fvNV) (GLuint index, GLsizei count, const GLfloat *v); + void (APIENTRY *VertexAttribs4svNV) (GLuint index, GLsizei count, const GLshort *v); + void (APIENTRY *VertexAttribs4ubvNV) (GLuint index, GLsizei count, const GLubyte *v); + void (APIENTRY *TexBumpParameterivATI) (GLenum pname, const GLint *param); + void (APIENTRY *TexBumpParameterfvATI) (GLenum pname, const GLfloat *param); + void (APIENTRY *GetTexBumpParameterivATI) (GLenum pname, GLint *param); + void (APIENTRY *GetTexBumpParameterfvATI) (GLenum pname, GLfloat *param); + GLuint (APIENTRY *GenFragmentShadersATI) (GLuint range); + void (APIENTRY *BindFragmentShaderATI) (GLuint id); + void (APIENTRY *DeleteFragmentShaderATI) (GLuint id); + void (APIENTRY *BeginFragmentShaderATI) (void); + void (APIENTRY *EndFragmentShaderATI) (void); + void (APIENTRY *PassTexCoordATI) (GLuint dst, GLuint coord, GLenum swizzle); + void (APIENTRY *SampleMapATI) (GLuint dst, GLuint interp, GLenum swizzle); + void (APIENTRY *ColorFragmentOp1ATI) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); + void (APIENTRY *ColorFragmentOp2ATI) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); + void (APIENTRY *ColorFragmentOp3ATI) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); + void (APIENTRY *AlphaFragmentOp1ATI) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); + void (APIENTRY *AlphaFragmentOp2ATI) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); + void (APIENTRY *AlphaFragmentOp3ATI) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); + void (APIENTRY *SetFragmentShaderConstantATI) (GLuint dst, const GLfloat *value); + void (APIENTRY *PNTrianglesiATI) (GLenum pname, GLint param); + void (APIENTRY *PNTrianglesfATI) (GLenum pname, GLfloat param); + GLuint (APIENTRY *NewObjectBufferATI) (GLsizei size, const GLvoid *pointer, GLenum usage); + GLboolean (APIENTRY *IsObjectBufferATI) (GLuint buffer); + void (APIENTRY *UpdateObjectBufferATI) (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve); + void (APIENTRY *GetObjectBufferfvATI) (GLuint buffer, GLenum pname, GLfloat *params); + void (APIENTRY *GetObjectBufferivATI) (GLuint buffer, GLenum pname, GLint *params); + void (APIENTRY *FreeObjectBufferATI) (GLuint buffer); + void (APIENTRY *ArrayObjectATI) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); + void (APIENTRY *GetArrayObjectfvATI) (GLenum array, GLenum pname, GLfloat *params); + void (APIENTRY *GetArrayObjectivATI) (GLenum array, GLenum pname, GLint *params); + void (APIENTRY *VariantArrayObjectATI) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); + void (APIENTRY *GetVariantArrayObjectfvATI) (GLuint id, GLenum pname, GLfloat *params); + void (APIENTRY *GetVariantArrayObjectivATI) (GLuint id, GLenum pname, GLint *params); + void (APIENTRY *BeginVertexShaderEXT) (void); + void (APIENTRY *EndVertexShaderEXT) (void); + void (APIENTRY *BindVertexShaderEXT) (GLuint id); + GLuint (APIENTRY *GenVertexShadersEXT) (GLuint range); + void (APIENTRY *DeleteVertexShaderEXT) (GLuint id); + void (APIENTRY *ShaderOp1EXT) (GLenum op, GLuint res, GLuint arg1); + void (APIENTRY *ShaderOp2EXT) (GLenum op, GLuint res, GLuint arg1, GLuint arg2); + void (APIENTRY *ShaderOp3EXT) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); + void (APIENTRY *SwizzleEXT) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); + void (APIENTRY *WriteMaskEXT) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); + void (APIENTRY *InsertComponentEXT) (GLuint res, GLuint src, GLuint num); + void (APIENTRY *ExtractComponentEXT) (GLuint res, GLuint src, GLuint num); + GLuint (APIENTRY *GenSymbolsEXT) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); + void (APIENTRY *SetInvariantEXT) (GLuint id, GLenum type, const GLvoid *addr); + void (APIENTRY *SetLocalConstantEXT) (GLuint id, GLenum type, const GLvoid *addr); + void (APIENTRY *VariantbvEXT) (GLuint id, const GLbyte *addr); + void (APIENTRY *VariantsvEXT) (GLuint id, const GLshort *addr); + void (APIENTRY *VariantivEXT) (GLuint id, const GLint *addr); + void (APIENTRY *VariantfvEXT) (GLuint id, const GLfloat *addr); + void (APIENTRY *VariantdvEXT) (GLuint id, const GLdouble *addr); + void (APIENTRY *VariantubvEXT) (GLuint id, const GLubyte *addr); + void (APIENTRY *VariantusvEXT) (GLuint id, const GLushort *addr); + void (APIENTRY *VariantuivEXT) (GLuint id, const GLuint *addr); + void (APIENTRY *VariantPointerEXT) (GLuint id, GLenum type, GLuint stride, const GLvoid *addr); + void (APIENTRY *EnableVariantClientStateEXT) (GLuint id); + void (APIENTRY *DisableVariantClientStateEXT) (GLuint id); + GLuint (APIENTRY *BindLightParameterEXT) (GLenum light, GLenum value); + GLuint (APIENTRY *BindMaterialParameterEXT) (GLenum face, GLenum value); + GLuint (APIENTRY *BindTexGenParameterEXT) (GLenum unit, GLenum coord, GLenum value); + GLuint (APIENTRY *BindTextureUnitParameterEXT) (GLenum unit, GLenum value); + GLuint (APIENTRY *BindParameterEXT) (GLenum value); + GLboolean (APIENTRY *IsVariantEnabledEXT) (GLuint id, GLenum cap); + void (APIENTRY *GetVariantBooleanvEXT) (GLuint id, GLenum value, GLboolean *data); + void (APIENTRY *GetVariantIntegervEXT) (GLuint id, GLenum value, GLint *data); + void (APIENTRY *GetVariantFloatvEXT) (GLuint id, GLenum value, GLfloat *data); + void (APIENTRY *GetVariantPointervEXT) (GLuint id, GLenum value, GLvoid* *data); + void (APIENTRY *GetInvariantBooleanvEXT) (GLuint id, GLenum value, GLboolean *data); + void (APIENTRY *GetInvariantIntegervEXT) (GLuint id, GLenum value, GLint *data); + void (APIENTRY *GetInvariantFloatvEXT) (GLuint id, GLenum value, GLfloat *data); + void (APIENTRY *GetLocalConstantBooleanvEXT) (GLuint id, GLenum value, GLboolean *data); + void (APIENTRY *GetLocalConstantIntegervEXT) (GLuint id, GLenum value, GLint *data); + void (APIENTRY *GetLocalConstantFloatvEXT) (GLuint id, GLenum value, GLfloat *data); + void (APIENTRY *VertexStream1sATI) (GLenum stream, GLshort x); + void (APIENTRY *VertexStream1svATI) (GLenum stream, const GLshort *coords); + void (APIENTRY *VertexStream1iATI) (GLenum stream, GLint x); + void (APIENTRY *VertexStream1ivATI) (GLenum stream, const GLint *coords); + void (APIENTRY *VertexStream1fATI) (GLenum stream, GLfloat x); + void (APIENTRY *VertexStream1fvATI) (GLenum stream, const GLfloat *coords); + void (APIENTRY *VertexStream1dATI) (GLenum stream, GLdouble x); + void (APIENTRY *VertexStream1dvATI) (GLenum stream, const GLdouble *coords); + void (APIENTRY *VertexStream2sATI) (GLenum stream, GLshort x, GLshort y); + void (APIENTRY *VertexStream2svATI) (GLenum stream, const GLshort *coords); + void (APIENTRY *VertexStream2iATI) (GLenum stream, GLint x, GLint y); + void (APIENTRY *VertexStream2ivATI) (GLenum stream, const GLint *coords); + void (APIENTRY *VertexStream2fATI) (GLenum stream, GLfloat x, GLfloat y); + void (APIENTRY *VertexStream2fvATI) (GLenum stream, const GLfloat *coords); + void (APIENTRY *VertexStream2dATI) (GLenum stream, GLdouble x, GLdouble y); + void (APIENTRY *VertexStream2dvATI) (GLenum stream, const GLdouble *coords); + void (APIENTRY *VertexStream3sATI) (GLenum stream, GLshort x, GLshort y, GLshort z); + void (APIENTRY *VertexStream3svATI) (GLenum stream, const GLshort *coords); + void (APIENTRY *VertexStream3iATI) (GLenum stream, GLint x, GLint y, GLint z); + void (APIENTRY *VertexStream3ivATI) (GLenum stream, const GLint *coords); + void (APIENTRY *VertexStream3fATI) (GLenum stream, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *VertexStream3fvATI) (GLenum stream, const GLfloat *coords); + void (APIENTRY *VertexStream3dATI) (GLenum stream, GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY *VertexStream3dvATI) (GLenum stream, const GLdouble *coords); + void (APIENTRY *VertexStream4sATI) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); + void (APIENTRY *VertexStream4svATI) (GLenum stream, const GLshort *coords); + void (APIENTRY *VertexStream4iATI) (GLenum stream, GLint x, GLint y, GLint z, GLint w); + void (APIENTRY *VertexStream4ivATI) (GLenum stream, const GLint *coords); + void (APIENTRY *VertexStream4fATI) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *VertexStream4fvATI) (GLenum stream, const GLfloat *coords); + void (APIENTRY *VertexStream4dATI) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *VertexStream4dvATI) (GLenum stream, const GLdouble *coords); + void (APIENTRY *NormalStream3bATI) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); + void (APIENTRY *NormalStream3bvATI) (GLenum stream, const GLbyte *coords); + void (APIENTRY *NormalStream3sATI) (GLenum stream, GLshort nx, GLshort ny, GLshort nz); + void (APIENTRY *NormalStream3svATI) (GLenum stream, const GLshort *coords); + void (APIENTRY *NormalStream3iATI) (GLenum stream, GLint nx, GLint ny, GLint nz); + void (APIENTRY *NormalStream3ivATI) (GLenum stream, const GLint *coords); + void (APIENTRY *NormalStream3fATI) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); + void (APIENTRY *NormalStream3fvATI) (GLenum stream, const GLfloat *coords); + void (APIENTRY *NormalStream3dATI) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); + void (APIENTRY *NormalStream3dvATI) (GLenum stream, const GLdouble *coords); + void (APIENTRY *ClientActiveVertexStreamATI) (GLenum stream); + void (APIENTRY *VertexBlendEnviATI) (GLenum pname, GLint param); + void (APIENTRY *VertexBlendEnvfATI) (GLenum pname, GLfloat param); + void (APIENTRY *ElementPointerATI) (GLenum type, const GLvoid *pointer); + void (APIENTRY *DrawElementArrayATI) (GLenum mode, GLsizei count); + void (APIENTRY *DrawRangeElementArrayATI) (GLenum mode, GLuint start, GLuint end, GLsizei count); + void (APIENTRY *DrawMeshArraysSUN) (GLenum mode, GLint first, GLsizei count, GLsizei width); + void (APIENTRY *GenOcclusionQueriesNV) (GLsizei n, GLuint *ids); + void (APIENTRY *DeleteOcclusionQueriesNV) (GLsizei n, const GLuint *ids); + GLboolean (APIENTRY *IsOcclusionQueryNV) (GLuint id); + void (APIENTRY *BeginOcclusionQueryNV) (GLuint id); + void (APIENTRY *EndOcclusionQueryNV) (void); + void (APIENTRY *GetOcclusionQueryivNV) (GLuint id, GLenum pname, GLint *params); + void (APIENTRY *GetOcclusionQueryuivNV) (GLuint id, GLenum pname, GLuint *params); + void (APIENTRY *PointParameteriNV) (GLenum pname, GLint param); + void (APIENTRY *PointParameterivNV) (GLenum pname, const GLint *params); + void (APIENTRY *ActiveStencilFaceEXT) (GLenum face); + void (APIENTRY *ElementPointerAPPLE) (GLenum type, const GLvoid *pointer); + void (APIENTRY *DrawElementArrayAPPLE) (GLenum mode, GLint first, GLsizei count); + void (APIENTRY *DrawRangeElementArrayAPPLE) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); + void (APIENTRY *MultiDrawElementArrayAPPLE) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); + void (APIENTRY *MultiDrawRangeElementArrayAPPLE) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); + void (APIENTRY *GenFencesAPPLE) (GLsizei n, GLuint *fences); + void (APIENTRY *DeleteFencesAPPLE) (GLsizei n, const GLuint *fences); + void (APIENTRY *SetFenceAPPLE) (GLuint fence); + GLboolean (APIENTRY *IsFenceAPPLE) (GLuint fence); + GLboolean (APIENTRY *TestFenceAPPLE) (GLuint fence); + void (APIENTRY *FinishFenceAPPLE) (GLuint fence); + GLboolean (APIENTRY *TestObjectAPPLE) (GLenum object, GLuint name); + void (APIENTRY *FinishObjectAPPLE) (GLenum object, GLint name); + void (APIENTRY *BindVertexArrayAPPLE) (GLuint array); + void (APIENTRY *DeleteVertexArraysAPPLE) (GLsizei n, const GLuint *arrays); + void (APIENTRY *GenVertexArraysAPPLE) (GLsizei n, const GLuint *arrays); + GLboolean (APIENTRY *IsVertexArrayAPPLE) (GLuint array); + void (APIENTRY *VertexArrayRangeAPPLE) (GLsizei length, GLvoid *pointer); + void (APIENTRY *FlushVertexArrayRangeAPPLE) (GLsizei length, GLvoid *pointer); + void (APIENTRY *VertexArrayParameteriAPPLE) (GLenum pname, GLint param); + void (APIENTRY *DrawBuffersATI) (GLsizei n, const GLenum *bufs); + void (APIENTRY *ProgramNamedParameter4fNV) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *ProgramNamedParameter4dNV) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *ProgramNamedParameter4fvNV) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); + void (APIENTRY *ProgramNamedParameter4dvNV) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); + void (APIENTRY *GetProgramNamedParameterfvNV) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); + void (APIENTRY *GetProgramNamedParameterdvNV) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); + void (APIENTRY *Vertex2hNV) (GLhalfNV x, GLhalfNV y); + void (APIENTRY *Vertex2hvNV) (const GLhalfNV *v); + void (APIENTRY *Vertex3hNV) (GLhalfNV x, GLhalfNV y, GLhalfNV z); + void (APIENTRY *Vertex3hvNV) (const GLhalfNV *v); + void (APIENTRY *Vertex4hNV) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); + void (APIENTRY *Vertex4hvNV) (const GLhalfNV *v); + void (APIENTRY *Normal3hNV) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); + void (APIENTRY *Normal3hvNV) (const GLhalfNV *v); + void (APIENTRY *Color3hNV) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); + void (APIENTRY *Color3hvNV) (const GLhalfNV *v); + void (APIENTRY *Color4hNV) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); + void (APIENTRY *Color4hvNV) (const GLhalfNV *v); + void (APIENTRY *TexCoord1hNV) (GLhalfNV s); + void (APIENTRY *TexCoord1hvNV) (const GLhalfNV *v); + void (APIENTRY *TexCoord2hNV) (GLhalfNV s, GLhalfNV t); + void (APIENTRY *TexCoord2hvNV) (const GLhalfNV *v); + void (APIENTRY *TexCoord3hNV) (GLhalfNV s, GLhalfNV t, GLhalfNV r); + void (APIENTRY *TexCoord3hvNV) (const GLhalfNV *v); + void (APIENTRY *TexCoord4hNV) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); + void (APIENTRY *TexCoord4hvNV) (const GLhalfNV *v); + void (APIENTRY *MultiTexCoord1hNV) (GLenum target, GLhalfNV s); + void (APIENTRY *MultiTexCoord1hvNV) (GLenum target, const GLhalfNV *v); + void (APIENTRY *MultiTexCoord2hNV) (GLenum target, GLhalfNV s, GLhalfNV t); + void (APIENTRY *MultiTexCoord2hvNV) (GLenum target, const GLhalfNV *v); + void (APIENTRY *MultiTexCoord3hNV) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); + void (APIENTRY *MultiTexCoord3hvNV) (GLenum target, const GLhalfNV *v); + void (APIENTRY *MultiTexCoord4hNV) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); + void (APIENTRY *MultiTexCoord4hvNV) (GLenum target, const GLhalfNV *v); + void (APIENTRY *FogCoordhNV) (GLhalfNV fog); + void (APIENTRY *FogCoordhvNV) (const GLhalfNV *fog); + void (APIENTRY *SecondaryColor3hNV) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); + void (APIENTRY *SecondaryColor3hvNV) (const GLhalfNV *v); + void (APIENTRY *VertexWeighthNV) (GLhalfNV weight); + void (APIENTRY *VertexWeighthvNV) (const GLhalfNV *weight); + void (APIENTRY *VertexAttrib1hNV) (GLuint index, GLhalfNV x); + void (APIENTRY *VertexAttrib1hvNV) (GLuint index, const GLhalfNV *v); + void (APIENTRY *VertexAttrib2hNV) (GLuint index, GLhalfNV x, GLhalfNV y); + void (APIENTRY *VertexAttrib2hvNV) (GLuint index, const GLhalfNV *v); + void (APIENTRY *VertexAttrib3hNV) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); + void (APIENTRY *VertexAttrib3hvNV) (GLuint index, const GLhalfNV *v); + void (APIENTRY *VertexAttrib4hNV) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); + void (APIENTRY *VertexAttrib4hvNV) (GLuint index, const GLhalfNV *v); + void (APIENTRY *VertexAttribs1hvNV) (GLuint index, GLsizei n, const GLhalfNV *v); + void (APIENTRY *VertexAttribs2hvNV) (GLuint index, GLsizei n, const GLhalfNV *v); + void (APIENTRY *VertexAttribs3hvNV) (GLuint index, GLsizei n, const GLhalfNV *v); + void (APIENTRY *VertexAttribs4hvNV) (GLuint index, GLsizei n, const GLhalfNV *v); + void (APIENTRY *PixelDataRangeNV) (GLenum target, GLsizei length, GLvoid *pointer); + void (APIENTRY *FlushPixelDataRangeNV) (GLenum target); + void (APIENTRY *PrimitiveRestartNV) (void); + void (APIENTRY *PrimitiveRestartIndexNV) (GLuint index); + GLvoid* (APIENTRY *MapObjectBufferATI) (GLuint buffer); + void (APIENTRY *UnmapObjectBufferATI) (GLuint buffer); + void (APIENTRY *StencilOpSeparateATI) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); + void (APIENTRY *StencilFuncSeparateATI) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); + void (APIENTRY *VertexAttribArrayObjectATI) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); + void (APIENTRY *GetVertexAttribArrayObjectfvATI) (GLuint index, GLenum pname, GLfloat *params); + void (APIENTRY *GetVertexAttribArrayObjectivATI) (GLuint index, GLenum pname, GLint *params); + void (APIENTRY *DepthBoundsEXT) (GLclampd zmin, GLclampd zmax); + void (APIENTRY *BlendEquationSeparateEXT) (GLenum modeRGB, GLenum modeAlpha); + void (APIENTRY *AddSwapHintRectWIN) (GLint x, GLint y, GLsizei width, GLsizei height); +#ifdef _WIN32 + HANDLE (WINAPI *CreateBufferRegionARB) (HDC hDC, int iLayerPlane, UINT uType); + VOID (WINAPI *DeleteBufferRegionARB) (HANDLE hRegion); + BOOL (WINAPI *SaveBufferRegionARB) (HANDLE hRegion, int x, int y, int width, int height); + BOOL (WINAPI *RestoreBufferRegionARB) (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); + const int (WINAPI *GetExtensionsStringARB) (HDC hdc); + BOOL (WINAPI *GetPixelFormatAttribivARB) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); + BOOL (WINAPI *GetPixelFormatAttribfvARB) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); + BOOL (WINAPI *ChoosePixelFormatARB) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); + BOOL (WINAPI *MakeContextCurrentARB) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); + HDC (WINAPI *GetCurrentReadDCARB) (void); + HPBUFFERARB (WINAPI *CreatePbufferARB) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); + HDC (WINAPI *GetPbufferDCARB) (HPBUFFERARB hPbuffer); + int (WINAPI *ReleasePbufferDCARB) (HPBUFFERARB hPbuffer, HDC hDC); + BOOL (WINAPI *DestroyPbufferARB) (HPBUFFERARB hPbuffer); + BOOL (WINAPI *QueryPbufferARB) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); + BOOL (WINAPI *BindTexImageARB) (HPBUFFERARB hPbuffer, int iBuffer); + BOOL (WINAPI *ReleaseTexImageARB) (HPBUFFERARB hPbuffer, int iBuffer); + BOOL (WINAPI *SetPbufferAttribARB) (HPBUFFERARB hPbuffer, const int *piAttribList); + GLboolean (WINAPI *CreateDisplayColorTableEXT) (GLushort id); + GLboolean (WINAPI *LoadDisplayColorTableEXT) (const GLushort *table, GLuint length); + GLboolean (WINAPI *BindDisplayColorTableEXT) (GLushort id); + VOID (WINAPI *DestroyDisplayColorTableEXT) (GLushort id); + const int (WINAPI *GetExtensionsStringEXT) (void); + BOOL (WINAPI *MakeContextCurrentEXT) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); + HDC (WINAPI *GetCurrentReadDCEXT) (void); + HPBUFFEREXT (WINAPI *CreatePbufferEXT) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); + HDC (WINAPI *GetPbufferDCEXT) (HPBUFFEREXT hPbuffer); + int (WINAPI *ReleasePbufferDCEXT) (HPBUFFEREXT hPbuffer, HDC hDC); + BOOL (WINAPI *DestroyPbufferEXT) (HPBUFFEREXT hPbuffer); + BOOL (WINAPI *QueryPbufferEXT) (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); + BOOL (WINAPI *GetPixelFormatAttribivEXT) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); + BOOL (WINAPI *GetPixelFormatAttribfvEXT) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); + BOOL (WINAPI *ChoosePixelFormatEXT) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); + BOOL (WINAPI *SwapIntervalEXT) (int interval); + int (WINAPI *GetSwapIntervalEXT) (void); + void* (WINAPI *AllocateMemoryNV) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); + void (WINAPI *FreeMemoryNV) (void); + BOOL (WINAPI *GetSyncValuesOML) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); + BOOL (WINAPI *GetMscRateOML) (HDC hdc, INT32 *numerator, INT32 *denominator); + INT64 (WINAPI *SwapBuffersMscOML) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); + INT64 (WINAPI *SwapLayerBuffersMscOML) (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); + BOOL (WINAPI *WaitForMscOML) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); + BOOL (WINAPI *WaitForSbcOML) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); + BOOL (WINAPI *GetDigitalVideoParametersI3D) (HDC hDC, int iAttribute, int *piValue); + BOOL (WINAPI *SetDigitalVideoParametersI3D) (HDC hDC, int iAttribute, const int *piValue); + BOOL (WINAPI *GetGammaTableParametersI3D) (HDC hDC, int iAttribute, int *piValue); + BOOL (WINAPI *SetGammaTableParametersI3D) (HDC hDC, int iAttribute, const int *piValue); + BOOL (WINAPI *GetGammaTableI3D) (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); + BOOL (WINAPI *SetGammaTableI3D) (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); + BOOL (WINAPI *EnableGenlockI3D) (HDC hDC); + BOOL (WINAPI *DisableGenlockI3D) (HDC hDC); + BOOL (WINAPI *IsEnabledGenlockI3D) (HDC hDC, BOOL *pFlag); + BOOL (WINAPI *GenlockSourceI3D) (HDC hDC, UINT uSource); + BOOL (WINAPI *GetGenlockSourceI3D) (HDC hDC, UINT *uSource); + BOOL (WINAPI *GenlockSourceEdgeI3D) (HDC hDC, UINT uEdge); + BOOL (WINAPI *GetGenlockSourceEdgeI3D) (HDC hDC, UINT *uEdge); + BOOL (WINAPI *GenlockSampleRateI3D) (HDC hDC, UINT uRate); + BOOL (WINAPI *GetGenlockSampleRateI3D) (HDC hDC, UINT *uRate); + BOOL (WINAPI *GenlockSourceDelayI3D) (HDC hDC, UINT uDelay); + BOOL (WINAPI *GetGenlockSourceDelayI3D) (HDC hDC, UINT *uDelay); + BOOL (WINAPI *QueryGenlockMaxSourceDelayI3D) (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); + LPVOID (WINAPI *CreateImageBufferI3D) (HDC hDC, DWORD dwSize, UINT uFlags); + BOOL (WINAPI *DestroyImageBufferI3D) (HDC hDC, LPVOID pAddress); + BOOL (WINAPI *AssociateImageBufferEventsI3D) (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); + BOOL (WINAPI *ReleaseImageBufferEventsI3D) (HDC hDC, const LPVOID *pAddress, UINT count); + BOOL (WINAPI *EnableFrameLockI3D) (void); + BOOL (WINAPI *DisableFrameLockI3D) (void); + BOOL (WINAPI *IsEnabledFrameLockI3D) (BOOL *pFlag); + BOOL (WINAPI *QueryFrameLockMasterI3D) (BOOL *pFlag); + BOOL (WINAPI *GetFrameUsageI3D) (float *pUsage); + BOOL (WINAPI *BeginFrameTrackingI3D) (void); + BOOL (WINAPI *EndFrameTrackingI3D) (void); + BOOL (WINAPI *QueryFrameTrackingI3D) (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); +#endif /* _WIN32 */ +} _GLextensionProcs; + +#define glBlendColor (_GET_TLS_PROCTABLE()->BlendColor) +#define glBlendEquation (_GET_TLS_PROCTABLE()->BlendEquation) +#define glDrawRangeElements (_GET_TLS_PROCTABLE()->DrawRangeElements) +#define glColorTable (_GET_TLS_PROCTABLE()->ColorTable) +#define glColorTableParameterfv (_GET_TLS_PROCTABLE()->ColorTableParameterfv) +#define glColorTableParameteriv (_GET_TLS_PROCTABLE()->ColorTableParameteriv) +#define glCopyColorTable (_GET_TLS_PROCTABLE()->CopyColorTable) +#define glGetColorTable (_GET_TLS_PROCTABLE()->GetColorTable) +#define glGetColorTableParameterfv (_GET_TLS_PROCTABLE()->GetColorTableParameterfv) +#define glGetColorTableParameteriv (_GET_TLS_PROCTABLE()->GetColorTableParameteriv) +#define glColorSubTable (_GET_TLS_PROCTABLE()->ColorSubTable) +#define glCopyColorSubTable (_GET_TLS_PROCTABLE()->CopyColorSubTable) +#define glConvolutionFilter1D (_GET_TLS_PROCTABLE()->ConvolutionFilter1D) +#define glConvolutionFilter2D (_GET_TLS_PROCTABLE()->ConvolutionFilter2D) +#define glConvolutionParameterf (_GET_TLS_PROCTABLE()->ConvolutionParameterf) +#define glConvolutionParameterfv (_GET_TLS_PROCTABLE()->ConvolutionParameterfv) +#define glConvolutionParameteri (_GET_TLS_PROCTABLE()->ConvolutionParameteri) +#define glConvolutionParameteriv (_GET_TLS_PROCTABLE()->ConvolutionParameteriv) +#define glCopyConvolutionFilter1D (_GET_TLS_PROCTABLE()->CopyConvolutionFilter1D) +#define glCopyConvolutionFilter2D (_GET_TLS_PROCTABLE()->CopyConvolutionFilter2D) +#define glGetConvolutionFilter (_GET_TLS_PROCTABLE()->GetConvolutionFilter) +#define glGetConvolutionParameterfv (_GET_TLS_PROCTABLE()->GetConvolutionParameterfv) +#define glGetConvolutionParameteriv (_GET_TLS_PROCTABLE()->GetConvolutionParameteriv) +#define glGetSeparableFilter (_GET_TLS_PROCTABLE()->GetSeparableFilter) +#define glSeparableFilter2D (_GET_TLS_PROCTABLE()->SeparableFilter2D) +#define glGetHistogram (_GET_TLS_PROCTABLE()->GetHistogram) +#define glGetHistogramParameterfv (_GET_TLS_PROCTABLE()->GetHistogramParameterfv) +#define glGetHistogramParameteriv (_GET_TLS_PROCTABLE()->GetHistogramParameteriv) +#define glGetMinmax (_GET_TLS_PROCTABLE()->GetMinmax) +#define glGetMinmaxParameterfv (_GET_TLS_PROCTABLE()->GetMinmaxParameterfv) +#define glGetMinmaxParameteriv (_GET_TLS_PROCTABLE()->GetMinmaxParameteriv) +#define glHistogram (_GET_TLS_PROCTABLE()->Histogram) +#define glMinmax (_GET_TLS_PROCTABLE()->Minmax) +#define glResetHistogram (_GET_TLS_PROCTABLE()->ResetHistogram) +#define glResetMinmax (_GET_TLS_PROCTABLE()->ResetMinmax) +#define glTexImage3D (_GET_TLS_PROCTABLE()->TexImage3D) +#define glTexSubImage3D (_GET_TLS_PROCTABLE()->TexSubImage3D) +#define glCopyTexSubImage3D (_GET_TLS_PROCTABLE()->CopyTexSubImage3D) +#define glActiveTexture (_GET_TLS_PROCTABLE()->ActiveTexture) +#define glClientActiveTexture (_GET_TLS_PROCTABLE()->ClientActiveTexture) +#define glMultiTexCoord1d (_GET_TLS_PROCTABLE()->MultiTexCoord1d) +#define glMultiTexCoord1dv (_GET_TLS_PROCTABLE()->MultiTexCoord1dv) +#define glMultiTexCoord1f (_GET_TLS_PROCTABLE()->MultiTexCoord1f) +#define glMultiTexCoord1fv (_GET_TLS_PROCTABLE()->MultiTexCoord1fv) +#define glMultiTexCoord1i (_GET_TLS_PROCTABLE()->MultiTexCoord1i) +#define glMultiTexCoord1iv (_GET_TLS_PROCTABLE()->MultiTexCoord1iv) +#define glMultiTexCoord1s (_GET_TLS_PROCTABLE()->MultiTexCoord1s) +#define glMultiTexCoord1sv (_GET_TLS_PROCTABLE()->MultiTexCoord1sv) +#define glMultiTexCoord2d (_GET_TLS_PROCTABLE()->MultiTexCoord2d) +#define glMultiTexCoord2dv (_GET_TLS_PROCTABLE()->MultiTexCoord2dv) +#define glMultiTexCoord2f (_GET_TLS_PROCTABLE()->MultiTexCoord2f) +#define glMultiTexCoord2fv (_GET_TLS_PROCTABLE()->MultiTexCoord2fv) +#define glMultiTexCoord2i (_GET_TLS_PROCTABLE()->MultiTexCoord2i) +#define glMultiTexCoord2iv (_GET_TLS_PROCTABLE()->MultiTexCoord2iv) +#define glMultiTexCoord2s (_GET_TLS_PROCTABLE()->MultiTexCoord2s) +#define glMultiTexCoord2sv (_GET_TLS_PROCTABLE()->MultiTexCoord2sv) +#define glMultiTexCoord3d (_GET_TLS_PROCTABLE()->MultiTexCoord3d) +#define glMultiTexCoord3dv (_GET_TLS_PROCTABLE()->MultiTexCoord3dv) +#define glMultiTexCoord3f (_GET_TLS_PROCTABLE()->MultiTexCoord3f) +#define glMultiTexCoord3fv (_GET_TLS_PROCTABLE()->MultiTexCoord3fv) +#define glMultiTexCoord3i (_GET_TLS_PROCTABLE()->MultiTexCoord3i) +#define glMultiTexCoord3iv (_GET_TLS_PROCTABLE()->MultiTexCoord3iv) +#define glMultiTexCoord3s (_GET_TLS_PROCTABLE()->MultiTexCoord3s) +#define glMultiTexCoord3sv (_GET_TLS_PROCTABLE()->MultiTexCoord3sv) +#define glMultiTexCoord4d (_GET_TLS_PROCTABLE()->MultiTexCoord4d) +#define glMultiTexCoord4dv (_GET_TLS_PROCTABLE()->MultiTexCoord4dv) +#define glMultiTexCoord4f (_GET_TLS_PROCTABLE()->MultiTexCoord4f) +#define glMultiTexCoord4fv (_GET_TLS_PROCTABLE()->MultiTexCoord4fv) +#define glMultiTexCoord4i (_GET_TLS_PROCTABLE()->MultiTexCoord4i) +#define glMultiTexCoord4iv (_GET_TLS_PROCTABLE()->MultiTexCoord4iv) +#define glMultiTexCoord4s (_GET_TLS_PROCTABLE()->MultiTexCoord4s) +#define glMultiTexCoord4sv (_GET_TLS_PROCTABLE()->MultiTexCoord4sv) +#define glLoadTransposeMatrixf (_GET_TLS_PROCTABLE()->LoadTransposeMatrixf) +#define glLoadTransposeMatrixd (_GET_TLS_PROCTABLE()->LoadTransposeMatrixd) +#define glMultTransposeMatrixf (_GET_TLS_PROCTABLE()->MultTransposeMatrixf) +#define glMultTransposeMatrixd (_GET_TLS_PROCTABLE()->MultTransposeMatrixd) +#define glSampleCoverage (_GET_TLS_PROCTABLE()->SampleCoverage) +#define glCompressedTexImage3D (_GET_TLS_PROCTABLE()->CompressedTexImage3D) +#define glCompressedTexImage2D (_GET_TLS_PROCTABLE()->CompressedTexImage2D) +#define glCompressedTexImage1D (_GET_TLS_PROCTABLE()->CompressedTexImage1D) +#define glCompressedTexSubImage3D (_GET_TLS_PROCTABLE()->CompressedTexSubImage3D) +#define glCompressedTexSubImage2D (_GET_TLS_PROCTABLE()->CompressedTexSubImage2D) +#define glCompressedTexSubImage1D (_GET_TLS_PROCTABLE()->CompressedTexSubImage1D) +#define glGetCompressedTexImage (_GET_TLS_PROCTABLE()->GetCompressedTexImage) +#define glBlendFuncSeparate (_GET_TLS_PROCTABLE()->BlendFuncSeparate) +#define glFogCoordf (_GET_TLS_PROCTABLE()->FogCoordf) +#define glFogCoordfv (_GET_TLS_PROCTABLE()->FogCoordfv) +#define glFogCoordd (_GET_TLS_PROCTABLE()->FogCoordd) +#define glFogCoorddv (_GET_TLS_PROCTABLE()->FogCoorddv) +#define glFogCoordPointer (_GET_TLS_PROCTABLE()->FogCoordPointer) +#define glMultiDrawArrays (_GET_TLS_PROCTABLE()->MultiDrawArrays) +#define glMultiDrawElements (_GET_TLS_PROCTABLE()->MultiDrawElements) +#define glPointParameterf (_GET_TLS_PROCTABLE()->PointParameterf) +#define glPointParameterfv (_GET_TLS_PROCTABLE()->PointParameterfv) +#define glPointParameteri (_GET_TLS_PROCTABLE()->PointParameteri) +#define glPointParameteriv (_GET_TLS_PROCTABLE()->PointParameteriv) +#define glSecondaryColor3b (_GET_TLS_PROCTABLE()->SecondaryColor3b) +#define glSecondaryColor3bv (_GET_TLS_PROCTABLE()->SecondaryColor3bv) +#define glSecondaryColor3d (_GET_TLS_PROCTABLE()->SecondaryColor3d) +#define glSecondaryColor3dv (_GET_TLS_PROCTABLE()->SecondaryColor3dv) +#define glSecondaryColor3f (_GET_TLS_PROCTABLE()->SecondaryColor3f) +#define glSecondaryColor3fv (_GET_TLS_PROCTABLE()->SecondaryColor3fv) +#define glSecondaryColor3i (_GET_TLS_PROCTABLE()->SecondaryColor3i) +#define glSecondaryColor3iv (_GET_TLS_PROCTABLE()->SecondaryColor3iv) +#define glSecondaryColor3s (_GET_TLS_PROCTABLE()->SecondaryColor3s) +#define glSecondaryColor3sv (_GET_TLS_PROCTABLE()->SecondaryColor3sv) +#define glSecondaryColor3ub (_GET_TLS_PROCTABLE()->SecondaryColor3ub) +#define glSecondaryColor3ubv (_GET_TLS_PROCTABLE()->SecondaryColor3ubv) +#define glSecondaryColor3ui (_GET_TLS_PROCTABLE()->SecondaryColor3ui) +#define glSecondaryColor3uiv (_GET_TLS_PROCTABLE()->SecondaryColor3uiv) +#define glSecondaryColor3us (_GET_TLS_PROCTABLE()->SecondaryColor3us) +#define glSecondaryColor3usv (_GET_TLS_PROCTABLE()->SecondaryColor3usv) +#define glSecondaryColorPointer (_GET_TLS_PROCTABLE()->SecondaryColorPointer) +#define glWindowPos2d (_GET_TLS_PROCTABLE()->WindowPos2d) +#define glWindowPos2dv (_GET_TLS_PROCTABLE()->WindowPos2dv) +#define glWindowPos2f (_GET_TLS_PROCTABLE()->WindowPos2f) +#define glWindowPos2fv (_GET_TLS_PROCTABLE()->WindowPos2fv) +#define glWindowPos2i (_GET_TLS_PROCTABLE()->WindowPos2i) +#define glWindowPos2iv (_GET_TLS_PROCTABLE()->WindowPos2iv) +#define glWindowPos2s (_GET_TLS_PROCTABLE()->WindowPos2s) +#define glWindowPos2sv (_GET_TLS_PROCTABLE()->WindowPos2sv) +#define glWindowPos3d (_GET_TLS_PROCTABLE()->WindowPos3d) +#define glWindowPos3dv (_GET_TLS_PROCTABLE()->WindowPos3dv) +#define glWindowPos3f (_GET_TLS_PROCTABLE()->WindowPos3f) +#define glWindowPos3fv (_GET_TLS_PROCTABLE()->WindowPos3fv) +#define glWindowPos3i (_GET_TLS_PROCTABLE()->WindowPos3i) +#define glWindowPos3iv (_GET_TLS_PROCTABLE()->WindowPos3iv) +#define glWindowPos3s (_GET_TLS_PROCTABLE()->WindowPos3s) +#define glWindowPos3sv (_GET_TLS_PROCTABLE()->WindowPos3sv) +#define glGenQueries (_GET_TLS_PROCTABLE()->GenQueries) +#define glDeleteQueries (_GET_TLS_PROCTABLE()->DeleteQueries) +#define glIsQuery (_GET_TLS_PROCTABLE()->IsQuery) +#define glBeginQuery (_GET_TLS_PROCTABLE()->BeginQuery) +#define glEndQuery (_GET_TLS_PROCTABLE()->EndQuery) +#define glGetQueryiv (_GET_TLS_PROCTABLE()->GetQueryiv) +#define glGetQueryObjectiv (_GET_TLS_PROCTABLE()->GetQueryObjectiv) +#define glGetQueryObjectuiv (_GET_TLS_PROCTABLE()->GetQueryObjectuiv) +#define glBindBuffer (_GET_TLS_PROCTABLE()->BindBuffer) +#define glDeleteBuffers (_GET_TLS_PROCTABLE()->DeleteBuffers) +#define glGenBuffers (_GET_TLS_PROCTABLE()->GenBuffers) +#define glIsBuffer (_GET_TLS_PROCTABLE()->IsBuffer) +#define glBufferData (_GET_TLS_PROCTABLE()->BufferData) +#define glBufferSubData (_GET_TLS_PROCTABLE()->BufferSubData) +#define glGetBufferSubData (_GET_TLS_PROCTABLE()->GetBufferSubData) +#define glMapBuffer (_GET_TLS_PROCTABLE()->MapBuffer) +#define glUnmapBuffer (_GET_TLS_PROCTABLE()->UnmapBuffer) +#define glGetBufferParameteriv (_GET_TLS_PROCTABLE()->GetBufferParameteriv) +#define glGetBufferPointerv (_GET_TLS_PROCTABLE()->GetBufferPointerv) +#define glActiveTextureARB (_GET_TLS_PROCTABLE()->ActiveTextureARB) +#define glClientActiveTextureARB (_GET_TLS_PROCTABLE()->ClientActiveTextureARB) +#define glMultiTexCoord1dARB (_GET_TLS_PROCTABLE()->MultiTexCoord1dARB) +#define glMultiTexCoord1dvARB (_GET_TLS_PROCTABLE()->MultiTexCoord1dvARB) +#define glMultiTexCoord1fARB (_GET_TLS_PROCTABLE()->MultiTexCoord1fARB) +#define glMultiTexCoord1fvARB (_GET_TLS_PROCTABLE()->MultiTexCoord1fvARB) +#define glMultiTexCoord1iARB (_GET_TLS_PROCTABLE()->MultiTexCoord1iARB) +#define glMultiTexCoord1ivARB (_GET_TLS_PROCTABLE()->MultiTexCoord1ivARB) +#define glMultiTexCoord1sARB (_GET_TLS_PROCTABLE()->MultiTexCoord1sARB) +#define glMultiTexCoord1svARB (_GET_TLS_PROCTABLE()->MultiTexCoord1svARB) +#define glMultiTexCoord2dARB (_GET_TLS_PROCTABLE()->MultiTexCoord2dARB) +#define glMultiTexCoord2dvARB (_GET_TLS_PROCTABLE()->MultiTexCoord2dvARB) +#define glMultiTexCoord2fARB (_GET_TLS_PROCTABLE()->MultiTexCoord2fARB) +#define glMultiTexCoord2fvARB (_GET_TLS_PROCTABLE()->MultiTexCoord2fvARB) +#define glMultiTexCoord2iARB (_GET_TLS_PROCTABLE()->MultiTexCoord2iARB) +#define glMultiTexCoord2ivARB (_GET_TLS_PROCTABLE()->MultiTexCoord2ivARB) +#define glMultiTexCoord2sARB (_GET_TLS_PROCTABLE()->MultiTexCoord2sARB) +#define glMultiTexCoord2svARB (_GET_TLS_PROCTABLE()->MultiTexCoord2svARB) +#define glMultiTexCoord3dARB (_GET_TLS_PROCTABLE()->MultiTexCoord3dARB) +#define glMultiTexCoord3dvARB (_GET_TLS_PROCTABLE()->MultiTexCoord3dvARB) +#define glMultiTexCoord3fARB (_GET_TLS_PROCTABLE()->MultiTexCoord3fARB) +#define glMultiTexCoord3fvARB (_GET_TLS_PROCTABLE()->MultiTexCoord3fvARB) +#define glMultiTexCoord3iARB (_GET_TLS_PROCTABLE()->MultiTexCoord3iARB) +#define glMultiTexCoord3ivARB (_GET_TLS_PROCTABLE()->MultiTexCoord3ivARB) +#define glMultiTexCoord3sARB (_GET_TLS_PROCTABLE()->MultiTexCoord3sARB) +#define glMultiTexCoord3svARB (_GET_TLS_PROCTABLE()->MultiTexCoord3svARB) +#define glMultiTexCoord4dARB (_GET_TLS_PROCTABLE()->MultiTexCoord4dARB) +#define glMultiTexCoord4dvARB (_GET_TLS_PROCTABLE()->MultiTexCoord4dvARB) +#define glMultiTexCoord4fARB (_GET_TLS_PROCTABLE()->MultiTexCoord4fARB) +#define glMultiTexCoord4fvARB (_GET_TLS_PROCTABLE()->MultiTexCoord4fvARB) +#define glMultiTexCoord4iARB (_GET_TLS_PROCTABLE()->MultiTexCoord4iARB) +#define glMultiTexCoord4ivARB (_GET_TLS_PROCTABLE()->MultiTexCoord4ivARB) +#define glMultiTexCoord4sARB (_GET_TLS_PROCTABLE()->MultiTexCoord4sARB) +#define glMultiTexCoord4svARB (_GET_TLS_PROCTABLE()->MultiTexCoord4svARB) +#define glLoadTransposeMatrixfARB (_GET_TLS_PROCTABLE()->LoadTransposeMatrixfARB) +#define glLoadTransposeMatrixdARB (_GET_TLS_PROCTABLE()->LoadTransposeMatrixdARB) +#define glMultTransposeMatrixfARB (_GET_TLS_PROCTABLE()->MultTransposeMatrixfARB) +#define glMultTransposeMatrixdARB (_GET_TLS_PROCTABLE()->MultTransposeMatrixdARB) +#define glSampleCoverageARB (_GET_TLS_PROCTABLE()->SampleCoverageARB) +#define glCompressedTexImage3DARB (_GET_TLS_PROCTABLE()->CompressedTexImage3DARB) +#define glCompressedTexImage2DARB (_GET_TLS_PROCTABLE()->CompressedTexImage2DARB) +#define glCompressedTexImage1DARB (_GET_TLS_PROCTABLE()->CompressedTexImage1DARB) +#define glCompressedTexSubImage3DARB (_GET_TLS_PROCTABLE()->CompressedTexSubImage3DARB) +#define glCompressedTexSubImage2DARB (_GET_TLS_PROCTABLE()->CompressedTexSubImage2DARB) +#define glCompressedTexSubImage1DARB (_GET_TLS_PROCTABLE()->CompressedTexSubImage1DARB) +#define glGetCompressedTexImageARB (_GET_TLS_PROCTABLE()->GetCompressedTexImageARB) +#define glPointParameterfARB (_GET_TLS_PROCTABLE()->PointParameterfARB) +#define glPointParameterfvARB (_GET_TLS_PROCTABLE()->PointParameterfvARB) +#define glWeightbvARB (_GET_TLS_PROCTABLE()->WeightbvARB) +#define glWeightsvARB (_GET_TLS_PROCTABLE()->WeightsvARB) +#define glWeightivARB (_GET_TLS_PROCTABLE()->WeightivARB) +#define glWeightfvARB (_GET_TLS_PROCTABLE()->WeightfvARB) +#define glWeightdvARB (_GET_TLS_PROCTABLE()->WeightdvARB) +#define glWeightubvARB (_GET_TLS_PROCTABLE()->WeightubvARB) +#define glWeightusvARB (_GET_TLS_PROCTABLE()->WeightusvARB) +#define glWeightuivARB (_GET_TLS_PROCTABLE()->WeightuivARB) +#define glWeightPointerARB (_GET_TLS_PROCTABLE()->WeightPointerARB) +#define glVertexBlendARB (_GET_TLS_PROCTABLE()->VertexBlendARB) +#define glCurrentPaletteMatrixARB (_GET_TLS_PROCTABLE()->CurrentPaletteMatrixARB) +#define glMatrixIndexubvARB (_GET_TLS_PROCTABLE()->MatrixIndexubvARB) +#define glMatrixIndexusvARB (_GET_TLS_PROCTABLE()->MatrixIndexusvARB) +#define glMatrixIndexuivARB (_GET_TLS_PROCTABLE()->MatrixIndexuivARB) +#define glMatrixIndexPointerARB (_GET_TLS_PROCTABLE()->MatrixIndexPointerARB) +#define glWindowPos2dARB (_GET_TLS_PROCTABLE()->WindowPos2dARB) +#define glWindowPos2dvARB (_GET_TLS_PROCTABLE()->WindowPos2dvARB) +#define glWindowPos2fARB (_GET_TLS_PROCTABLE()->WindowPos2fARB) +#define glWindowPos2fvARB (_GET_TLS_PROCTABLE()->WindowPos2fvARB) +#define glWindowPos2iARB (_GET_TLS_PROCTABLE()->WindowPos2iARB) +#define glWindowPos2ivARB (_GET_TLS_PROCTABLE()->WindowPos2ivARB) +#define glWindowPos2sARB (_GET_TLS_PROCTABLE()->WindowPos2sARB) +#define glWindowPos2svARB (_GET_TLS_PROCTABLE()->WindowPos2svARB) +#define glWindowPos3dARB (_GET_TLS_PROCTABLE()->WindowPos3dARB) +#define glWindowPos3dvARB (_GET_TLS_PROCTABLE()->WindowPos3dvARB) +#define glWindowPos3fARB (_GET_TLS_PROCTABLE()->WindowPos3fARB) +#define glWindowPos3fvARB (_GET_TLS_PROCTABLE()->WindowPos3fvARB) +#define glWindowPos3iARB (_GET_TLS_PROCTABLE()->WindowPos3iARB) +#define glWindowPos3ivARB (_GET_TLS_PROCTABLE()->WindowPos3ivARB) +#define glWindowPos3sARB (_GET_TLS_PROCTABLE()->WindowPos3sARB) +#define glWindowPos3svARB (_GET_TLS_PROCTABLE()->WindowPos3svARB) +#define glVertexAttrib1dARB (_GET_TLS_PROCTABLE()->VertexAttrib1dARB) +#define glVertexAttrib1dvARB (_GET_TLS_PROCTABLE()->VertexAttrib1dvARB) +#define glVertexAttrib1fARB (_GET_TLS_PROCTABLE()->VertexAttrib1fARB) +#define glVertexAttrib1fvARB (_GET_TLS_PROCTABLE()->VertexAttrib1fvARB) +#define glVertexAttrib1sARB (_GET_TLS_PROCTABLE()->VertexAttrib1sARB) +#define glVertexAttrib1svARB (_GET_TLS_PROCTABLE()->VertexAttrib1svARB) +#define glVertexAttrib2dARB (_GET_TLS_PROCTABLE()->VertexAttrib2dARB) +#define glVertexAttrib2dvARB (_GET_TLS_PROCTABLE()->VertexAttrib2dvARB) +#define glVertexAttrib2fARB (_GET_TLS_PROCTABLE()->VertexAttrib2fARB) +#define glVertexAttrib2fvARB (_GET_TLS_PROCTABLE()->VertexAttrib2fvARB) +#define glVertexAttrib2sARB (_GET_TLS_PROCTABLE()->VertexAttrib2sARB) +#define glVertexAttrib2svARB (_GET_TLS_PROCTABLE()->VertexAttrib2svARB) +#define glVertexAttrib3dARB (_GET_TLS_PROCTABLE()->VertexAttrib3dARB) +#define glVertexAttrib3dvARB (_GET_TLS_PROCTABLE()->VertexAttrib3dvARB) +#define glVertexAttrib3fARB (_GET_TLS_PROCTABLE()->VertexAttrib3fARB) +#define glVertexAttrib3fvARB (_GET_TLS_PROCTABLE()->VertexAttrib3fvARB) +#define glVertexAttrib3sARB (_GET_TLS_PROCTABLE()->VertexAttrib3sARB) +#define glVertexAttrib3svARB (_GET_TLS_PROCTABLE()->VertexAttrib3svARB) +#define glVertexAttrib4NbvARB (_GET_TLS_PROCTABLE()->VertexAttrib4NbvARB) +#define glVertexAttrib4NivARB (_GET_TLS_PROCTABLE()->VertexAttrib4NivARB) +#define glVertexAttrib4NsvARB (_GET_TLS_PROCTABLE()->VertexAttrib4NsvARB) +#define glVertexAttrib4NubARB (_GET_TLS_PROCTABLE()->VertexAttrib4NubARB) +#define glVertexAttrib4NubvARB (_GET_TLS_PROCTABLE()->VertexAttrib4NubvARB) +#define glVertexAttrib4NuivARB (_GET_TLS_PROCTABLE()->VertexAttrib4NuivARB) +#define glVertexAttrib4NusvARB (_GET_TLS_PROCTABLE()->VertexAttrib4NusvARB) +#define glVertexAttrib4bvARB (_GET_TLS_PROCTABLE()->VertexAttrib4bvARB) +#define glVertexAttrib4dARB (_GET_TLS_PROCTABLE()->VertexAttrib4dARB) +#define glVertexAttrib4dvARB (_GET_TLS_PROCTABLE()->VertexAttrib4dvARB) +#define glVertexAttrib4fARB (_GET_TLS_PROCTABLE()->VertexAttrib4fARB) +#define glVertexAttrib4fvARB (_GET_TLS_PROCTABLE()->VertexAttrib4fvARB) +#define glVertexAttrib4ivARB (_GET_TLS_PROCTABLE()->VertexAttrib4ivARB) +#define glVertexAttrib4sARB (_GET_TLS_PROCTABLE()->VertexAttrib4sARB) +#define glVertexAttrib4svARB (_GET_TLS_PROCTABLE()->VertexAttrib4svARB) +#define glVertexAttrib4ubvARB (_GET_TLS_PROCTABLE()->VertexAttrib4ubvARB) +#define glVertexAttrib4uivARB (_GET_TLS_PROCTABLE()->VertexAttrib4uivARB) +#define glVertexAttrib4usvARB (_GET_TLS_PROCTABLE()->VertexAttrib4usvARB) +#define glVertexAttribPointerARB (_GET_TLS_PROCTABLE()->VertexAttribPointerARB) +#define glEnableVertexAttribArrayARB (_GET_TLS_PROCTABLE()->EnableVertexAttribArrayARB) +#define glDisableVertexAttribArrayARB (_GET_TLS_PROCTABLE()->DisableVertexAttribArrayARB) +#define glProgramStringARB (_GET_TLS_PROCTABLE()->ProgramStringARB) +#define glBindProgramARB (_GET_TLS_PROCTABLE()->BindProgramARB) +#define glDeleteProgramsARB (_GET_TLS_PROCTABLE()->DeleteProgramsARB) +#define glGenProgramsARB (_GET_TLS_PROCTABLE()->GenProgramsARB) +#define glProgramEnvParameter4dARB (_GET_TLS_PROCTABLE()->ProgramEnvParameter4dARB) +#define glProgramEnvParameter4dvARB (_GET_TLS_PROCTABLE()->ProgramEnvParameter4dvARB) +#define glProgramEnvParameter4fARB (_GET_TLS_PROCTABLE()->ProgramEnvParameter4fARB) +#define glProgramEnvParameter4fvARB (_GET_TLS_PROCTABLE()->ProgramEnvParameter4fvARB) +#define glProgramLocalParameter4dARB (_GET_TLS_PROCTABLE()->ProgramLocalParameter4dARB) +#define glProgramLocalParameter4dvARB (_GET_TLS_PROCTABLE()->ProgramLocalParameter4dvARB) +#define glProgramLocalParameter4fARB (_GET_TLS_PROCTABLE()->ProgramLocalParameter4fARB) +#define glProgramLocalParameter4fvARB (_GET_TLS_PROCTABLE()->ProgramLocalParameter4fvARB) +#define glGetProgramEnvParameterdvARB (_GET_TLS_PROCTABLE()->GetProgramEnvParameterdvARB) +#define glGetProgramEnvParameterfvARB (_GET_TLS_PROCTABLE()->GetProgramEnvParameterfvARB) +#define glGetProgramLocalParameterdvARB (_GET_TLS_PROCTABLE()->GetProgramLocalParameterdvARB) +#define glGetProgramLocalParameterfvARB (_GET_TLS_PROCTABLE()->GetProgramLocalParameterfvARB) +#define glGetProgramivARB (_GET_TLS_PROCTABLE()->GetProgramivARB) +#define glGetProgramStringARB (_GET_TLS_PROCTABLE()->GetProgramStringARB) +#define glGetVertexAttribdvARB (_GET_TLS_PROCTABLE()->GetVertexAttribdvARB) +#define glGetVertexAttribfvARB (_GET_TLS_PROCTABLE()->GetVertexAttribfvARB) +#define glGetVertexAttribivARB (_GET_TLS_PROCTABLE()->GetVertexAttribivARB) +#define glGetVertexAttribPointervARB (_GET_TLS_PROCTABLE()->GetVertexAttribPointervARB) +#define glIsProgramARB (_GET_TLS_PROCTABLE()->IsProgramARB) +#define glBindBufferARB (_GET_TLS_PROCTABLE()->BindBufferARB) +#define glDeleteBuffersARB (_GET_TLS_PROCTABLE()->DeleteBuffersARB) +#define glGenBuffersARB (_GET_TLS_PROCTABLE()->GenBuffersARB) +#define glIsBufferARB (_GET_TLS_PROCTABLE()->IsBufferARB) +#define glBufferDataARB (_GET_TLS_PROCTABLE()->BufferDataARB) +#define glBufferSubDataARB (_GET_TLS_PROCTABLE()->BufferSubDataARB) +#define glGetBufferSubDataARB (_GET_TLS_PROCTABLE()->GetBufferSubDataARB) +#define glMapBufferARB (_GET_TLS_PROCTABLE()->MapBufferARB) +#define glUnmapBufferARB (_GET_TLS_PROCTABLE()->UnmapBufferARB) +#define glGetBufferParameterivARB (_GET_TLS_PROCTABLE()->GetBufferParameterivARB) +#define glGetBufferPointervARB (_GET_TLS_PROCTABLE()->GetBufferPointervARB) +#define glGenQueriesARB (_GET_TLS_PROCTABLE()->GenQueriesARB) +#define glDeleteQueriesARB (_GET_TLS_PROCTABLE()->DeleteQueriesARB) +#define glIsQueryARB (_GET_TLS_PROCTABLE()->IsQueryARB) +#define glBeginQueryARB (_GET_TLS_PROCTABLE()->BeginQueryARB) +#define glEndQueryARB (_GET_TLS_PROCTABLE()->EndQueryARB) +#define glGetQueryivARB (_GET_TLS_PROCTABLE()->GetQueryivARB) +#define glGetQueryObjectivARB (_GET_TLS_PROCTABLE()->GetQueryObjectivARB) +#define glGetQueryObjectuivARB (_GET_TLS_PROCTABLE()->GetQueryObjectuivARB) +#define glDeleteObjectARB (_GET_TLS_PROCTABLE()->DeleteObjectARB) +#define glGetHandleARB (_GET_TLS_PROCTABLE()->GetHandleARB) +#define glDetachObjectARB (_GET_TLS_PROCTABLE()->DetachObjectARB) +#define glCreateShaderObjectARB (_GET_TLS_PROCTABLE()->CreateShaderObjectARB) +#define glShaderSourceARB (_GET_TLS_PROCTABLE()->ShaderSourceARB) +#define glCompileShaderARB (_GET_TLS_PROCTABLE()->CompileShaderARB) +#define glCreateProgramObjectARB (_GET_TLS_PROCTABLE()->CreateProgramObjectARB) +#define glAttachObjectARB (_GET_TLS_PROCTABLE()->AttachObjectARB) +#define glLinkProgramARB (_GET_TLS_PROCTABLE()->LinkProgramARB) +#define glUseProgramObjectARB (_GET_TLS_PROCTABLE()->UseProgramObjectARB) +#define glValidateProgramARB (_GET_TLS_PROCTABLE()->ValidateProgramARB) +#define glUniform1fARB (_GET_TLS_PROCTABLE()->Uniform1fARB) +#define glUniform2fARB (_GET_TLS_PROCTABLE()->Uniform2fARB) +#define glUniform3fARB (_GET_TLS_PROCTABLE()->Uniform3fARB) +#define glUniform4fARB (_GET_TLS_PROCTABLE()->Uniform4fARB) +#define glUniform1iARB (_GET_TLS_PROCTABLE()->Uniform1iARB) +#define glUniform2iARB (_GET_TLS_PROCTABLE()->Uniform2iARB) +#define glUniform3iARB (_GET_TLS_PROCTABLE()->Uniform3iARB) +#define glUniform4iARB (_GET_TLS_PROCTABLE()->Uniform4iARB) +#define glUniform1fvARB (_GET_TLS_PROCTABLE()->Uniform1fvARB) +#define glUniform2fvARB (_GET_TLS_PROCTABLE()->Uniform2fvARB) +#define glUniform3fvARB (_GET_TLS_PROCTABLE()->Uniform3fvARB) +#define glUniform4fvARB (_GET_TLS_PROCTABLE()->Uniform4fvARB) +#define glUniform1ivARB (_GET_TLS_PROCTABLE()->Uniform1ivARB) +#define glUniform2ivARB (_GET_TLS_PROCTABLE()->Uniform2ivARB) +#define glUniform3ivARB (_GET_TLS_PROCTABLE()->Uniform3ivARB) +#define glUniform4ivARB (_GET_TLS_PROCTABLE()->Uniform4ivARB) +#define glUniformMatrix2fvARB (_GET_TLS_PROCTABLE()->UniformMatrix2fvARB) +#define glUniformMatrix3fvARB (_GET_TLS_PROCTABLE()->UniformMatrix3fvARB) +#define glUniformMatrix4fvARB (_GET_TLS_PROCTABLE()->UniformMatrix4fvARB) +#define glGetObjectParameterfvARB (_GET_TLS_PROCTABLE()->GetObjectParameterfvARB) +#define glGetObjectParameterivARB (_GET_TLS_PROCTABLE()->GetObjectParameterivARB) +#define glGetInfoLogARB (_GET_TLS_PROCTABLE()->GetInfoLogARB) +#define glGetAttachedObjectsARB (_GET_TLS_PROCTABLE()->GetAttachedObjectsARB) +#define glGetUniformLocationARB (_GET_TLS_PROCTABLE()->GetUniformLocationARB) +#define glGetActiveUniformARB (_GET_TLS_PROCTABLE()->GetActiveUniformARB) +#define glGetUniformfvARB (_GET_TLS_PROCTABLE()->GetUniformfvARB) +#define glGetUniformivARB (_GET_TLS_PROCTABLE()->GetUniformivARB) +#define glGetShaderSourceARB (_GET_TLS_PROCTABLE()->GetShaderSourceARB) +#define glBindAttribLocationARB (_GET_TLS_PROCTABLE()->BindAttribLocationARB) +#define glGetActiveAttribARB (_GET_TLS_PROCTABLE()->GetActiveAttribARB) +#define glGetAttribLocationARB (_GET_TLS_PROCTABLE()->GetAttribLocationARB) +#define glBlendColorEXT (_GET_TLS_PROCTABLE()->BlendColorEXT) +#define glPolygonOffsetEXT (_GET_TLS_PROCTABLE()->PolygonOffsetEXT) +#define glTexImage3DEXT (_GET_TLS_PROCTABLE()->TexImage3DEXT) +#define glTexSubImage3DEXT (_GET_TLS_PROCTABLE()->TexSubImage3DEXT) +#define glGetTexFilterFuncSGIS (_GET_TLS_PROCTABLE()->GetTexFilterFuncSGIS) +#define glTexFilterFuncSGIS (_GET_TLS_PROCTABLE()->TexFilterFuncSGIS) +#define glTexSubImage1DEXT (_GET_TLS_PROCTABLE()->TexSubImage1DEXT) +#define glTexSubImage2DEXT (_GET_TLS_PROCTABLE()->TexSubImage2DEXT) +#define glCopyTexImage1DEXT (_GET_TLS_PROCTABLE()->CopyTexImage1DEXT) +#define glCopyTexImage2DEXT (_GET_TLS_PROCTABLE()->CopyTexImage2DEXT) +#define glCopyTexSubImage1DEXT (_GET_TLS_PROCTABLE()->CopyTexSubImage1DEXT) +#define glCopyTexSubImage2DEXT (_GET_TLS_PROCTABLE()->CopyTexSubImage2DEXT) +#define glCopyTexSubImage3DEXT (_GET_TLS_PROCTABLE()->CopyTexSubImage3DEXT) +#define glGetHistogramEXT (_GET_TLS_PROCTABLE()->GetHistogramEXT) +#define glGetHistogramParameterfvEXT (_GET_TLS_PROCTABLE()->GetHistogramParameterfvEXT) +#define glGetHistogramParameterivEXT (_GET_TLS_PROCTABLE()->GetHistogramParameterivEXT) +#define glGetMinmaxEXT (_GET_TLS_PROCTABLE()->GetMinmaxEXT) +#define glGetMinmaxParameterfvEXT (_GET_TLS_PROCTABLE()->GetMinmaxParameterfvEXT) +#define glGetMinmaxParameterivEXT (_GET_TLS_PROCTABLE()->GetMinmaxParameterivEXT) +#define glHistogramEXT (_GET_TLS_PROCTABLE()->HistogramEXT) +#define glMinmaxEXT (_GET_TLS_PROCTABLE()->MinmaxEXT) +#define glResetHistogramEXT (_GET_TLS_PROCTABLE()->ResetHistogramEXT) +#define glResetMinmaxEXT (_GET_TLS_PROCTABLE()->ResetMinmaxEXT) +#define glConvolutionFilter1DEXT (_GET_TLS_PROCTABLE()->ConvolutionFilter1DEXT) +#define glConvolutionFilter2DEXT (_GET_TLS_PROCTABLE()->ConvolutionFilter2DEXT) +#define glConvolutionParameterfEXT (_GET_TLS_PROCTABLE()->ConvolutionParameterfEXT) +#define glConvolutionParameterfvEXT (_GET_TLS_PROCTABLE()->ConvolutionParameterfvEXT) +#define glConvolutionParameteriEXT (_GET_TLS_PROCTABLE()->ConvolutionParameteriEXT) +#define glConvolutionParameterivEXT (_GET_TLS_PROCTABLE()->ConvolutionParameterivEXT) +#define glCopyConvolutionFilter1DEXT (_GET_TLS_PROCTABLE()->CopyConvolutionFilter1DEXT) +#define glCopyConvolutionFilter2DEXT (_GET_TLS_PROCTABLE()->CopyConvolutionFilter2DEXT) +#define glGetConvolutionFilterEXT (_GET_TLS_PROCTABLE()->GetConvolutionFilterEXT) +#define glGetConvolutionParameterfvEXT (_GET_TLS_PROCTABLE()->GetConvolutionParameterfvEXT) +#define glGetConvolutionParameterivEXT (_GET_TLS_PROCTABLE()->GetConvolutionParameterivEXT) +#define glGetSeparableFilterEXT (_GET_TLS_PROCTABLE()->GetSeparableFilterEXT) +#define glSeparableFilter2DEXT (_GET_TLS_PROCTABLE()->SeparableFilter2DEXT) +#define glColorTableSGI (_GET_TLS_PROCTABLE()->ColorTableSGI) +#define glColorTableParameterfvSGI (_GET_TLS_PROCTABLE()->ColorTableParameterfvSGI) +#define glColorTableParameterivSGI (_GET_TLS_PROCTABLE()->ColorTableParameterivSGI) +#define glCopyColorTableSGI (_GET_TLS_PROCTABLE()->CopyColorTableSGI) +#define glGetColorTableSGI (_GET_TLS_PROCTABLE()->GetColorTableSGI) +#define glGetColorTableParameterfvSGI (_GET_TLS_PROCTABLE()->GetColorTableParameterfvSGI) +#define glGetColorTableParameterivSGI (_GET_TLS_PROCTABLE()->GetColorTableParameterivSGI) +#define glPixelTexGenSGIX (_GET_TLS_PROCTABLE()->PixelTexGenSGIX) +#define glPixelTexGenParameteriSGIS (_GET_TLS_PROCTABLE()->PixelTexGenParameteriSGIS) +#define glPixelTexGenParameterivSGIS (_GET_TLS_PROCTABLE()->PixelTexGenParameterivSGIS) +#define glPixelTexGenParameterfSGIS (_GET_TLS_PROCTABLE()->PixelTexGenParameterfSGIS) +#define glPixelTexGenParameterfvSGIS (_GET_TLS_PROCTABLE()->PixelTexGenParameterfvSGIS) +#define glGetPixelTexGenParameterivSGIS (_GET_TLS_PROCTABLE()->GetPixelTexGenParameterivSGIS) +#define glGetPixelTexGenParameterfvSGIS (_GET_TLS_PROCTABLE()->GetPixelTexGenParameterfvSGIS) +#define glTexImage4DSGIS (_GET_TLS_PROCTABLE()->TexImage4DSGIS) +#define glTexSubImage4DSGIS (_GET_TLS_PROCTABLE()->TexSubImage4DSGIS) +#define glAreTexturesResidentEXT (_GET_TLS_PROCTABLE()->AreTexturesResidentEXT) +#define glBindTextureEXT (_GET_TLS_PROCTABLE()->BindTextureEXT) +#define glDeleteTexturesEXT (_GET_TLS_PROCTABLE()->DeleteTexturesEXT) +#define glGenTexturesEXT (_GET_TLS_PROCTABLE()->GenTexturesEXT) +#define glIsTextureEXT (_GET_TLS_PROCTABLE()->IsTextureEXT) +#define glPrioritizeTexturesEXT (_GET_TLS_PROCTABLE()->PrioritizeTexturesEXT) +#define glDetailTexFuncSGIS (_GET_TLS_PROCTABLE()->DetailTexFuncSGIS) +#define glGetDetailTexFuncSGIS (_GET_TLS_PROCTABLE()->GetDetailTexFuncSGIS) +#define glSharpenTexFuncSGIS (_GET_TLS_PROCTABLE()->SharpenTexFuncSGIS) +#define glGetSharpenTexFuncSGIS (_GET_TLS_PROCTABLE()->GetSharpenTexFuncSGIS) +#define glSampleMaskSGIS (_GET_TLS_PROCTABLE()->SampleMaskSGIS) +#define glSamplePatternSGIS (_GET_TLS_PROCTABLE()->SamplePatternSGIS) +#define glArrayElementEXT (_GET_TLS_PROCTABLE()->ArrayElementEXT) +#define glColorPointerEXT (_GET_TLS_PROCTABLE()->ColorPointerEXT) +#define glDrawArraysEXT (_GET_TLS_PROCTABLE()->DrawArraysEXT) +#define glEdgeFlagPointerEXT (_GET_TLS_PROCTABLE()->EdgeFlagPointerEXT) +#define glGetPointervEXT (_GET_TLS_PROCTABLE()->GetPointervEXT) +#define glIndexPointerEXT (_GET_TLS_PROCTABLE()->IndexPointerEXT) +#define glNormalPointerEXT (_GET_TLS_PROCTABLE()->NormalPointerEXT) +#define glTexCoordPointerEXT (_GET_TLS_PROCTABLE()->TexCoordPointerEXT) +#define glVertexPointerEXT (_GET_TLS_PROCTABLE()->VertexPointerEXT) +#define glBlendEquationEXT (_GET_TLS_PROCTABLE()->BlendEquationEXT) +#define glSpriteParameterfSGIX (_GET_TLS_PROCTABLE()->SpriteParameterfSGIX) +#define glSpriteParameterfvSGIX (_GET_TLS_PROCTABLE()->SpriteParameterfvSGIX) +#define glSpriteParameteriSGIX (_GET_TLS_PROCTABLE()->SpriteParameteriSGIX) +#define glSpriteParameterivSGIX (_GET_TLS_PROCTABLE()->SpriteParameterivSGIX) +#define glPointParameterfEXT (_GET_TLS_PROCTABLE()->PointParameterfEXT) +#define glPointParameterfvEXT (_GET_TLS_PROCTABLE()->PointParameterfvEXT) +#define glPointParameterfSGIS (_GET_TLS_PROCTABLE()->PointParameterfSGIS) +#define glPointParameterfvSGIS (_GET_TLS_PROCTABLE()->PointParameterfvSGIS) +#define glGetInstrumentsSGIX (_GET_TLS_PROCTABLE()->GetInstrumentsSGIX) +#define glInstrumentsBufferSGIX (_GET_TLS_PROCTABLE()->InstrumentsBufferSGIX) +#define glPollInstrumentsSGIX (_GET_TLS_PROCTABLE()->PollInstrumentsSGIX) +#define glReadInstrumentsSGIX (_GET_TLS_PROCTABLE()->ReadInstrumentsSGIX) +#define glStartInstrumentsSGIX (_GET_TLS_PROCTABLE()->StartInstrumentsSGIX) +#define glStopInstrumentsSGIX (_GET_TLS_PROCTABLE()->StopInstrumentsSGIX) +#define glFrameZoomSGIX (_GET_TLS_PROCTABLE()->FrameZoomSGIX) +#define glTagSampleBufferSGIX (_GET_TLS_PROCTABLE()->TagSampleBufferSGIX) +#define glDeformationMap3dSGIX (_GET_TLS_PROCTABLE()->DeformationMap3dSGIX) +#define glDeformationMap3fSGIX (_GET_TLS_PROCTABLE()->DeformationMap3fSGIX) +#define glDeformSGIX (_GET_TLS_PROCTABLE()->DeformSGIX) +#define glLoadIdentityDeformationMapSGIX (_GET_TLS_PROCTABLE()->LoadIdentityDeformationMapSGIX) +#define glReferencePlaneSGIX (_GET_TLS_PROCTABLE()->ReferencePlaneSGIX) +#define glFlushRasterSGIX (_GET_TLS_PROCTABLE()->FlushRasterSGIX) +#define glFogFuncSGIS (_GET_TLS_PROCTABLE()->FogFuncSGIS) +#define glGetFogFuncSGIS (_GET_TLS_PROCTABLE()->GetFogFuncSGIS) +#define glImageTransformParameteriHP (_GET_TLS_PROCTABLE()->ImageTransformParameteriHP) +#define glImageTransformParameterfHP (_GET_TLS_PROCTABLE()->ImageTransformParameterfHP) +#define glImageTransformParameterivHP (_GET_TLS_PROCTABLE()->ImageTransformParameterivHP) +#define glImageTransformParameterfvHP (_GET_TLS_PROCTABLE()->ImageTransformParameterfvHP) +#define glGetImageTransformParameterivHP (_GET_TLS_PROCTABLE()->GetImageTransformParameterivHP) +#define glGetImageTransformParameterfvHP (_GET_TLS_PROCTABLE()->GetImageTransformParameterfvHP) +#define glColorSubTableEXT (_GET_TLS_PROCTABLE()->ColorSubTableEXT) +#define glCopyColorSubTableEXT (_GET_TLS_PROCTABLE()->CopyColorSubTableEXT) +#define glHintPGI (_GET_TLS_PROCTABLE()->HintPGI) +#define glColorTableEXT (_GET_TLS_PROCTABLE()->ColorTableEXT) +#define glGetColorTableEXT (_GET_TLS_PROCTABLE()->GetColorTableEXT) +#define glGetColorTableParameterivEXT (_GET_TLS_PROCTABLE()->GetColorTableParameterivEXT) +#define glGetColorTableParameterfvEXT (_GET_TLS_PROCTABLE()->GetColorTableParameterfvEXT) +#define glGetListParameterfvSGIX (_GET_TLS_PROCTABLE()->GetListParameterfvSGIX) +#define glGetListParameterivSGIX (_GET_TLS_PROCTABLE()->GetListParameterivSGIX) +#define glListParameterfSGIX (_GET_TLS_PROCTABLE()->ListParameterfSGIX) +#define glListParameterfvSGIX (_GET_TLS_PROCTABLE()->ListParameterfvSGIX) +#define glListParameteriSGIX (_GET_TLS_PROCTABLE()->ListParameteriSGIX) +#define glListParameterivSGIX (_GET_TLS_PROCTABLE()->ListParameterivSGIX) +#define glIndexMaterialEXT (_GET_TLS_PROCTABLE()->IndexMaterialEXT) +#define glIndexFuncEXT (_GET_TLS_PROCTABLE()->IndexFuncEXT) +#define glLockArraysEXT (_GET_TLS_PROCTABLE()->LockArraysEXT) +#define glUnlockArraysEXT (_GET_TLS_PROCTABLE()->UnlockArraysEXT) +#define glCullParameterdvEXT (_GET_TLS_PROCTABLE()->CullParameterdvEXT) +#define glCullParameterfvEXT (_GET_TLS_PROCTABLE()->CullParameterfvEXT) +#define glFragmentColorMaterialSGIX (_GET_TLS_PROCTABLE()->FragmentColorMaterialSGIX) +#define glFragmentLightfSGIX (_GET_TLS_PROCTABLE()->FragmentLightfSGIX) +#define glFragmentLightfvSGIX (_GET_TLS_PROCTABLE()->FragmentLightfvSGIX) +#define glFragmentLightiSGIX (_GET_TLS_PROCTABLE()->FragmentLightiSGIX) +#define glFragmentLightivSGIX (_GET_TLS_PROCTABLE()->FragmentLightivSGIX) +#define glFragmentLightModelfSGIX (_GET_TLS_PROCTABLE()->FragmentLightModelfSGIX) +#define glFragmentLightModelfvSGIX (_GET_TLS_PROCTABLE()->FragmentLightModelfvSGIX) +#define glFragmentLightModeliSGIX (_GET_TLS_PROCTABLE()->FragmentLightModeliSGIX) +#define glFragmentLightModelivSGIX (_GET_TLS_PROCTABLE()->FragmentLightModelivSGIX) +#define glFragmentMaterialfSGIX (_GET_TLS_PROCTABLE()->FragmentMaterialfSGIX) +#define glFragmentMaterialfvSGIX (_GET_TLS_PROCTABLE()->FragmentMaterialfvSGIX) +#define glFragmentMaterialiSGIX (_GET_TLS_PROCTABLE()->FragmentMaterialiSGIX) +#define glFragmentMaterialivSGIX (_GET_TLS_PROCTABLE()->FragmentMaterialivSGIX) +#define glGetFragmentLightfvSGIX (_GET_TLS_PROCTABLE()->GetFragmentLightfvSGIX) +#define glGetFragmentLightivSGIX (_GET_TLS_PROCTABLE()->GetFragmentLightivSGIX) +#define glGetFragmentMaterialfvSGIX (_GET_TLS_PROCTABLE()->GetFragmentMaterialfvSGIX) +#define glGetFragmentMaterialivSGIX (_GET_TLS_PROCTABLE()->GetFragmentMaterialivSGIX) +#define glLightEnviSGIX (_GET_TLS_PROCTABLE()->LightEnviSGIX) +#define glDrawRangeElementsEXT (_GET_TLS_PROCTABLE()->DrawRangeElementsEXT) +#define glApplyTextureEXT (_GET_TLS_PROCTABLE()->ApplyTextureEXT) +#define glTextureLightEXT (_GET_TLS_PROCTABLE()->TextureLightEXT) +#define glTextureMaterialEXT (_GET_TLS_PROCTABLE()->TextureMaterialEXT) +#define glAsyncMarkerSGIX (_GET_TLS_PROCTABLE()->AsyncMarkerSGIX) +#define glFinishAsyncSGIX (_GET_TLS_PROCTABLE()->FinishAsyncSGIX) +#define glPollAsyncSGIX (_GET_TLS_PROCTABLE()->PollAsyncSGIX) +#define glGenAsyncMarkersSGIX (_GET_TLS_PROCTABLE()->GenAsyncMarkersSGIX) +#define glDeleteAsyncMarkersSGIX (_GET_TLS_PROCTABLE()->DeleteAsyncMarkersSGIX) +#define glIsAsyncMarkerSGIX (_GET_TLS_PROCTABLE()->IsAsyncMarkerSGIX) +#define glVertexPointervINTEL (_GET_TLS_PROCTABLE()->VertexPointervINTEL) +#define glNormalPointervINTEL (_GET_TLS_PROCTABLE()->NormalPointervINTEL) +#define glColorPointervINTEL (_GET_TLS_PROCTABLE()->ColorPointervINTEL) +#define glTexCoordPointervINTEL (_GET_TLS_PROCTABLE()->TexCoordPointervINTEL) +#define glPixelTransformParameteriEXT (_GET_TLS_PROCTABLE()->PixelTransformParameteriEXT) +#define glPixelTransformParameterfEXT (_GET_TLS_PROCTABLE()->PixelTransformParameterfEXT) +#define glPixelTransformParameterivEXT (_GET_TLS_PROCTABLE()->PixelTransformParameterivEXT) +#define glPixelTransformParameterfvEXT (_GET_TLS_PROCTABLE()->PixelTransformParameterfvEXT) +#define glSecondaryColor3bEXT (_GET_TLS_PROCTABLE()->SecondaryColor3bEXT) +#define glSecondaryColor3bvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3bvEXT) +#define glSecondaryColor3dEXT (_GET_TLS_PROCTABLE()->SecondaryColor3dEXT) +#define glSecondaryColor3dvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3dvEXT) +#define glSecondaryColor3fEXT (_GET_TLS_PROCTABLE()->SecondaryColor3fEXT) +#define glSecondaryColor3fvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3fvEXT) +#define glSecondaryColor3iEXT (_GET_TLS_PROCTABLE()->SecondaryColor3iEXT) +#define glSecondaryColor3ivEXT (_GET_TLS_PROCTABLE()->SecondaryColor3ivEXT) +#define glSecondaryColor3sEXT (_GET_TLS_PROCTABLE()->SecondaryColor3sEXT) +#define glSecondaryColor3svEXT (_GET_TLS_PROCTABLE()->SecondaryColor3svEXT) +#define glSecondaryColor3ubEXT (_GET_TLS_PROCTABLE()->SecondaryColor3ubEXT) +#define glSecondaryColor3ubvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3ubvEXT) +#define glSecondaryColor3uiEXT (_GET_TLS_PROCTABLE()->SecondaryColor3uiEXT) +#define glSecondaryColor3uivEXT (_GET_TLS_PROCTABLE()->SecondaryColor3uivEXT) +#define glSecondaryColor3usEXT (_GET_TLS_PROCTABLE()->SecondaryColor3usEXT) +#define glSecondaryColor3usvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3usvEXT) +#define glSecondaryColorPointerEXT (_GET_TLS_PROCTABLE()->SecondaryColorPointerEXT) +#define glTextureNormalEXT (_GET_TLS_PROCTABLE()->TextureNormalEXT) +#define glMultiDrawArraysEXT (_GET_TLS_PROCTABLE()->MultiDrawArraysEXT) +#define glMultiDrawElementsEXT (_GET_TLS_PROCTABLE()->MultiDrawElementsEXT) +#define glFogCoordfEXT (_GET_TLS_PROCTABLE()->FogCoordfEXT) +#define glFogCoordfvEXT (_GET_TLS_PROCTABLE()->FogCoordfvEXT) +#define glFogCoorddEXT (_GET_TLS_PROCTABLE()->FogCoorddEXT) +#define glFogCoorddvEXT (_GET_TLS_PROCTABLE()->FogCoorddvEXT) +#define glFogCoordPointerEXT (_GET_TLS_PROCTABLE()->FogCoordPointerEXT) +#define glTangent3bEXT (_GET_TLS_PROCTABLE()->Tangent3bEXT) +#define glTangent3bvEXT (_GET_TLS_PROCTABLE()->Tangent3bvEXT) +#define glTangent3dEXT (_GET_TLS_PROCTABLE()->Tangent3dEXT) +#define glTangent3dvEXT (_GET_TLS_PROCTABLE()->Tangent3dvEXT) +#define glTangent3fEXT (_GET_TLS_PROCTABLE()->Tangent3fEXT) +#define glTangent3fvEXT (_GET_TLS_PROCTABLE()->Tangent3fvEXT) +#define glTangent3iEXT (_GET_TLS_PROCTABLE()->Tangent3iEXT) +#define glTangent3ivEXT (_GET_TLS_PROCTABLE()->Tangent3ivEXT) +#define glTangent3sEXT (_GET_TLS_PROCTABLE()->Tangent3sEXT) +#define glTangent3svEXT (_GET_TLS_PROCTABLE()->Tangent3svEXT) +#define glBinormal3bEXT (_GET_TLS_PROCTABLE()->Binormal3bEXT) +#define glBinormal3bvEXT (_GET_TLS_PROCTABLE()->Binormal3bvEXT) +#define glBinormal3dEXT (_GET_TLS_PROCTABLE()->Binormal3dEXT) +#define glBinormal3dvEXT (_GET_TLS_PROCTABLE()->Binormal3dvEXT) +#define glBinormal3fEXT (_GET_TLS_PROCTABLE()->Binormal3fEXT) +#define glBinormal3fvEXT (_GET_TLS_PROCTABLE()->Binormal3fvEXT) +#define glBinormal3iEXT (_GET_TLS_PROCTABLE()->Binormal3iEXT) +#define glBinormal3ivEXT (_GET_TLS_PROCTABLE()->Binormal3ivEXT) +#define glBinormal3sEXT (_GET_TLS_PROCTABLE()->Binormal3sEXT) +#define glBinormal3svEXT (_GET_TLS_PROCTABLE()->Binormal3svEXT) +#define glTangentPointerEXT (_GET_TLS_PROCTABLE()->TangentPointerEXT) +#define glBinormalPointerEXT (_GET_TLS_PROCTABLE()->BinormalPointerEXT) +#define glFinishTextureSUNX (_GET_TLS_PROCTABLE()->FinishTextureSUNX) +#define glGlobalAlphaFactorbSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorbSUN) +#define glGlobalAlphaFactorsSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorsSUN) +#define glGlobalAlphaFactoriSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactoriSUN) +#define glGlobalAlphaFactorfSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorfSUN) +#define glGlobalAlphaFactordSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactordSUN) +#define glGlobalAlphaFactorubSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorubSUN) +#define glGlobalAlphaFactorusSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorusSUN) +#define glGlobalAlphaFactoruiSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactoruiSUN) +#define glReplacementCodeuiSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiSUN) +#define glReplacementCodeusSUN (_GET_TLS_PROCTABLE()->ReplacementCodeusSUN) +#define glReplacementCodeubSUN (_GET_TLS_PROCTABLE()->ReplacementCodeubSUN) +#define glReplacementCodeuivSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuivSUN) +#define glReplacementCodeusvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeusvSUN) +#define glReplacementCodeubvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeubvSUN) +#define glReplacementCodePointerSUN (_GET_TLS_PROCTABLE()->ReplacementCodePointerSUN) +#define glColor4ubVertex2fSUN (_GET_TLS_PROCTABLE()->Color4ubVertex2fSUN) +#define glColor4ubVertex2fvSUN (_GET_TLS_PROCTABLE()->Color4ubVertex2fvSUN) +#define glColor4ubVertex3fSUN (_GET_TLS_PROCTABLE()->Color4ubVertex3fSUN) +#define glColor4ubVertex3fvSUN (_GET_TLS_PROCTABLE()->Color4ubVertex3fvSUN) +#define glColor3fVertex3fSUN (_GET_TLS_PROCTABLE()->Color3fVertex3fSUN) +#define glColor3fVertex3fvSUN (_GET_TLS_PROCTABLE()->Color3fVertex3fvSUN) +#define glNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->Normal3fVertex3fSUN) +#define glNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->Normal3fVertex3fvSUN) +#define glColor4fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->Color4fNormal3fVertex3fSUN) +#define glColor4fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->Color4fNormal3fVertex3fvSUN) +#define glTexCoord2fVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fVertex3fSUN) +#define glTexCoord2fVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fVertex3fvSUN) +#define glTexCoord4fVertex4fSUN (_GET_TLS_PROCTABLE()->TexCoord4fVertex4fSUN) +#define glTexCoord4fVertex4fvSUN (_GET_TLS_PROCTABLE()->TexCoord4fVertex4fvSUN) +#define glTexCoord2fColor4ubVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor4ubVertex3fSUN) +#define glTexCoord2fColor4ubVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor4ubVertex3fvSUN) +#define glTexCoord2fColor3fVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor3fVertex3fSUN) +#define glTexCoord2fColor3fVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor3fVertex3fvSUN) +#define glTexCoord2fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fNormal3fVertex3fSUN) +#define glTexCoord2fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fNormal3fVertex3fvSUN) +#define glTexCoord2fColor4fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor4fNormal3fVertex3fSUN) +#define glTexCoord2fColor4fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor4fNormal3fVertex3fvSUN) +#define glTexCoord4fColor4fNormal3fVertex4fSUN (_GET_TLS_PROCTABLE()->TexCoord4fColor4fNormal3fVertex4fSUN) +#define glTexCoord4fColor4fNormal3fVertex4fvSUN (_GET_TLS_PROCTABLE()->TexCoord4fColor4fNormal3fVertex4fvSUN) +#define glReplacementCodeuiVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiVertex3fSUN) +#define glReplacementCodeuiVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiVertex3fvSUN) +#define glReplacementCodeuiColor4ubVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor4ubVertex3fSUN) +#define glReplacementCodeuiColor4ubVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor4ubVertex3fvSUN) +#define glReplacementCodeuiColor3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor3fVertex3fSUN) +#define glReplacementCodeuiColor3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor3fVertex3fvSUN) +#define glReplacementCodeuiNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiNormal3fVertex3fSUN) +#define glReplacementCodeuiNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiNormal3fVertex3fvSUN) +#define glReplacementCodeuiColor4fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor4fNormal3fVertex3fSUN) +#define glReplacementCodeuiColor4fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor4fNormal3fVertex3fvSUN) +#define glReplacementCodeuiTexCoord2fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fVertex3fSUN) +#define glReplacementCodeuiTexCoord2fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fVertex3fvSUN) +#define glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fNormal3fVertex3fSUN) +#define glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN) +#define glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN) +#define glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN) +#define glBlendFuncSeparateEXT (_GET_TLS_PROCTABLE()->BlendFuncSeparateEXT) +#define glBlendFuncSeparateINGR (_GET_TLS_PROCTABLE()->BlendFuncSeparateINGR) +#define glVertexWeightfEXT (_GET_TLS_PROCTABLE()->VertexWeightfEXT) +#define glVertexWeightfvEXT (_GET_TLS_PROCTABLE()->VertexWeightfvEXT) +#define glVertexWeightPointerEXT (_GET_TLS_PROCTABLE()->VertexWeightPointerEXT) +#define glFlushVertexArrayRangeNV (_GET_TLS_PROCTABLE()->FlushVertexArrayRangeNV) +#define glVertexArrayRangeNV (_GET_TLS_PROCTABLE()->VertexArrayRangeNV) +#define glCombinerParameterfvNV (_GET_TLS_PROCTABLE()->CombinerParameterfvNV) +#define glCombinerParameterfNV (_GET_TLS_PROCTABLE()->CombinerParameterfNV) +#define glCombinerParameterivNV (_GET_TLS_PROCTABLE()->CombinerParameterivNV) +#define glCombinerParameteriNV (_GET_TLS_PROCTABLE()->CombinerParameteriNV) +#define glCombinerInputNV (_GET_TLS_PROCTABLE()->CombinerInputNV) +#define glCombinerOutputNV (_GET_TLS_PROCTABLE()->CombinerOutputNV) +#define glFinalCombinerInputNV (_GET_TLS_PROCTABLE()->FinalCombinerInputNV) +#define glGetCombinerInputParameterfvNV (_GET_TLS_PROCTABLE()->GetCombinerInputParameterfvNV) +#define glGetCombinerInputParameterivNV (_GET_TLS_PROCTABLE()->GetCombinerInputParameterivNV) +#define glGetCombinerOutputParameterfvNV (_GET_TLS_PROCTABLE()->GetCombinerOutputParameterfvNV) +#define glGetCombinerOutputParameterivNV (_GET_TLS_PROCTABLE()->GetCombinerOutputParameterivNV) +#define glGetFinalCombinerInputParameterfvNV (_GET_TLS_PROCTABLE()->GetFinalCombinerInputParameterfvNV) +#define glGetFinalCombinerInputParameterivNV (_GET_TLS_PROCTABLE()->GetFinalCombinerInputParameterivNV) +#define glResizeBuffersMESA (_GET_TLS_PROCTABLE()->ResizeBuffersMESA) +#define glWindowPos2dMESA (_GET_TLS_PROCTABLE()->WindowPos2dMESA) +#define glWindowPos2dvMESA (_GET_TLS_PROCTABLE()->WindowPos2dvMESA) +#define glWindowPos2fMESA (_GET_TLS_PROCTABLE()->WindowPos2fMESA) +#define glWindowPos2fvMESA (_GET_TLS_PROCTABLE()->WindowPos2fvMESA) +#define glWindowPos2iMESA (_GET_TLS_PROCTABLE()->WindowPos2iMESA) +#define glWindowPos2ivMESA (_GET_TLS_PROCTABLE()->WindowPos2ivMESA) +#define glWindowPos2sMESA (_GET_TLS_PROCTABLE()->WindowPos2sMESA) +#define glWindowPos2svMESA (_GET_TLS_PROCTABLE()->WindowPos2svMESA) +#define glWindowPos3dMESA (_GET_TLS_PROCTABLE()->WindowPos3dMESA) +#define glWindowPos3dvMESA (_GET_TLS_PROCTABLE()->WindowPos3dvMESA) +#define glWindowPos3fMESA (_GET_TLS_PROCTABLE()->WindowPos3fMESA) +#define glWindowPos3fvMESA (_GET_TLS_PROCTABLE()->WindowPos3fvMESA) +#define glWindowPos3iMESA (_GET_TLS_PROCTABLE()->WindowPos3iMESA) +#define glWindowPos3ivMESA (_GET_TLS_PROCTABLE()->WindowPos3ivMESA) +#define glWindowPos3sMESA (_GET_TLS_PROCTABLE()->WindowPos3sMESA) +#define glWindowPos3svMESA (_GET_TLS_PROCTABLE()->WindowPos3svMESA) +#define glWindowPos4dMESA (_GET_TLS_PROCTABLE()->WindowPos4dMESA) +#define glWindowPos4dvMESA (_GET_TLS_PROCTABLE()->WindowPos4dvMESA) +#define glWindowPos4fMESA (_GET_TLS_PROCTABLE()->WindowPos4fMESA) +#define glWindowPos4fvMESA (_GET_TLS_PROCTABLE()->WindowPos4fvMESA) +#define glWindowPos4iMESA (_GET_TLS_PROCTABLE()->WindowPos4iMESA) +#define glWindowPos4ivMESA (_GET_TLS_PROCTABLE()->WindowPos4ivMESA) +#define glWindowPos4sMESA (_GET_TLS_PROCTABLE()->WindowPos4sMESA) +#define glWindowPos4svMESA (_GET_TLS_PROCTABLE()->WindowPos4svMESA) +#define glMultiModeDrawArraysIBM (_GET_TLS_PROCTABLE()->MultiModeDrawArraysIBM) +#define glMultiModeDrawElementsIBM (_GET_TLS_PROCTABLE()->MultiModeDrawElementsIBM) +#define glColorPointerListIBM (_GET_TLS_PROCTABLE()->ColorPointerListIBM) +#define glSecondaryColorPointerListIBM (_GET_TLS_PROCTABLE()->SecondaryColorPointerListIBM) +#define glEdgeFlagPointerListIBM (_GET_TLS_PROCTABLE()->EdgeFlagPointerListIBM) +#define glFogCoordPointerListIBM (_GET_TLS_PROCTABLE()->FogCoordPointerListIBM) +#define glIndexPointerListIBM (_GET_TLS_PROCTABLE()->IndexPointerListIBM) +#define glNormalPointerListIBM (_GET_TLS_PROCTABLE()->NormalPointerListIBM) +#define glTexCoordPointerListIBM (_GET_TLS_PROCTABLE()->TexCoordPointerListIBM) +#define glVertexPointerListIBM (_GET_TLS_PROCTABLE()->VertexPointerListIBM) +#define glTbufferMask3DFX (_GET_TLS_PROCTABLE()->TbufferMask3DFX) +#define glSampleMaskEXT (_GET_TLS_PROCTABLE()->SampleMaskEXT) +#define glSamplePatternEXT (_GET_TLS_PROCTABLE()->SamplePatternEXT) +#define glTextureColorMaskSGIS (_GET_TLS_PROCTABLE()->TextureColorMaskSGIS) +#define glIglooInterfaceSGIX (_GET_TLS_PROCTABLE()->IglooInterfaceSGIX) +#define glDeleteFencesNV (_GET_TLS_PROCTABLE()->DeleteFencesNV) +#define glGenFencesNV (_GET_TLS_PROCTABLE()->GenFencesNV) +#define glIsFenceNV (_GET_TLS_PROCTABLE()->IsFenceNV) +#define glTestFenceNV (_GET_TLS_PROCTABLE()->TestFenceNV) +#define glGetFenceivNV (_GET_TLS_PROCTABLE()->GetFenceivNV) +#define glFinishFenceNV (_GET_TLS_PROCTABLE()->FinishFenceNV) +#define glSetFenceNV (_GET_TLS_PROCTABLE()->SetFenceNV) +#define glMapControlPointsNV (_GET_TLS_PROCTABLE()->MapControlPointsNV) +#define glMapParameterivNV (_GET_TLS_PROCTABLE()->MapParameterivNV) +#define glMapParameterfvNV (_GET_TLS_PROCTABLE()->MapParameterfvNV) +#define glGetMapControlPointsNV (_GET_TLS_PROCTABLE()->GetMapControlPointsNV) +#define glGetMapParameterivNV (_GET_TLS_PROCTABLE()->GetMapParameterivNV) +#define glGetMapParameterfvNV (_GET_TLS_PROCTABLE()->GetMapParameterfvNV) +#define glGetMapAttribParameterivNV (_GET_TLS_PROCTABLE()->GetMapAttribParameterivNV) +#define glGetMapAttribParameterfvNV (_GET_TLS_PROCTABLE()->GetMapAttribParameterfvNV) +#define glEvalMapsNV (_GET_TLS_PROCTABLE()->EvalMapsNV) +#define glCombinerStageParameterfvNV (_GET_TLS_PROCTABLE()->CombinerStageParameterfvNV) +#define glGetCombinerStageParameterfvNV (_GET_TLS_PROCTABLE()->GetCombinerStageParameterfvNV) +#define glAreProgramsResidentNV (_GET_TLS_PROCTABLE()->AreProgramsResidentNV) +#define glBindProgramNV (_GET_TLS_PROCTABLE()->BindProgramNV) +#define glDeleteProgramsNV (_GET_TLS_PROCTABLE()->DeleteProgramsNV) +#define glExecuteProgramNV (_GET_TLS_PROCTABLE()->ExecuteProgramNV) +#define glGenProgramsNV (_GET_TLS_PROCTABLE()->GenProgramsNV) +#define glGetProgramParameterdvNV (_GET_TLS_PROCTABLE()->GetProgramParameterdvNV) +#define glGetProgramParameterfvNV (_GET_TLS_PROCTABLE()->GetProgramParameterfvNV) +#define glGetProgramivNV (_GET_TLS_PROCTABLE()->GetProgramivNV) +#define glGetProgramStringNV (_GET_TLS_PROCTABLE()->GetProgramStringNV) +#define glGetTrackMatrixivNV (_GET_TLS_PROCTABLE()->GetTrackMatrixivNV) +#define glGetVertexAttribdvNV (_GET_TLS_PROCTABLE()->GetVertexAttribdvNV) +#define glGetVertexAttribfvNV (_GET_TLS_PROCTABLE()->GetVertexAttribfvNV) +#define glGetVertexAttribivNV (_GET_TLS_PROCTABLE()->GetVertexAttribivNV) +#define glGetVertexAttribPointervNV (_GET_TLS_PROCTABLE()->GetVertexAttribPointervNV) +#define glIsProgramNV (_GET_TLS_PROCTABLE()->IsProgramNV) +#define glLoadProgramNV (_GET_TLS_PROCTABLE()->LoadProgramNV) +#define glProgramParameter4dNV (_GET_TLS_PROCTABLE()->ProgramParameter4dNV) +#define glProgramParameter4dvNV (_GET_TLS_PROCTABLE()->ProgramParameter4dvNV) +#define glProgramParameter4fNV (_GET_TLS_PROCTABLE()->ProgramParameter4fNV) +#define glProgramParameter4fvNV (_GET_TLS_PROCTABLE()->ProgramParameter4fvNV) +#define glProgramParameters4dvNV (_GET_TLS_PROCTABLE()->ProgramParameters4dvNV) +#define glProgramParameters4fvNV (_GET_TLS_PROCTABLE()->ProgramParameters4fvNV) +#define glRequestResidentProgramsNV (_GET_TLS_PROCTABLE()->RequestResidentProgramsNV) +#define glTrackMatrixNV (_GET_TLS_PROCTABLE()->TrackMatrixNV) +#define glVertexAttribPointerNV (_GET_TLS_PROCTABLE()->VertexAttribPointerNV) +#define glVertexAttrib1dNV (_GET_TLS_PROCTABLE()->VertexAttrib1dNV) +#define glVertexAttrib1dvNV (_GET_TLS_PROCTABLE()->VertexAttrib1dvNV) +#define glVertexAttrib1fNV (_GET_TLS_PROCTABLE()->VertexAttrib1fNV) +#define glVertexAttrib1fvNV (_GET_TLS_PROCTABLE()->VertexAttrib1fvNV) +#define glVertexAttrib1sNV (_GET_TLS_PROCTABLE()->VertexAttrib1sNV) +#define glVertexAttrib1svNV (_GET_TLS_PROCTABLE()->VertexAttrib1svNV) +#define glVertexAttrib2dNV (_GET_TLS_PROCTABLE()->VertexAttrib2dNV) +#define glVertexAttrib2dvNV (_GET_TLS_PROCTABLE()->VertexAttrib2dvNV) +#define glVertexAttrib2fNV (_GET_TLS_PROCTABLE()->VertexAttrib2fNV) +#define glVertexAttrib2fvNV (_GET_TLS_PROCTABLE()->VertexAttrib2fvNV) +#define glVertexAttrib2sNV (_GET_TLS_PROCTABLE()->VertexAttrib2sNV) +#define glVertexAttrib2svNV (_GET_TLS_PROCTABLE()->VertexAttrib2svNV) +#define glVertexAttrib3dNV (_GET_TLS_PROCTABLE()->VertexAttrib3dNV) +#define glVertexAttrib3dvNV (_GET_TLS_PROCTABLE()->VertexAttrib3dvNV) +#define glVertexAttrib3fNV (_GET_TLS_PROCTABLE()->VertexAttrib3fNV) +#define glVertexAttrib3fvNV (_GET_TLS_PROCTABLE()->VertexAttrib3fvNV) +#define glVertexAttrib3sNV (_GET_TLS_PROCTABLE()->VertexAttrib3sNV) +#define glVertexAttrib3svNV (_GET_TLS_PROCTABLE()->VertexAttrib3svNV) +#define glVertexAttrib4dNV (_GET_TLS_PROCTABLE()->VertexAttrib4dNV) +#define glVertexAttrib4dvNV (_GET_TLS_PROCTABLE()->VertexAttrib4dvNV) +#define glVertexAttrib4fNV (_GET_TLS_PROCTABLE()->VertexAttrib4fNV) +#define glVertexAttrib4fvNV (_GET_TLS_PROCTABLE()->VertexAttrib4fvNV) +#define glVertexAttrib4sNV (_GET_TLS_PROCTABLE()->VertexAttrib4sNV) +#define glVertexAttrib4svNV (_GET_TLS_PROCTABLE()->VertexAttrib4svNV) +#define glVertexAttrib4ubNV (_GET_TLS_PROCTABLE()->VertexAttrib4ubNV) +#define glVertexAttrib4ubvNV (_GET_TLS_PROCTABLE()->VertexAttrib4ubvNV) +#define glVertexAttribs1dvNV (_GET_TLS_PROCTABLE()->VertexAttribs1dvNV) +#define glVertexAttribs1fvNV (_GET_TLS_PROCTABLE()->VertexAttribs1fvNV) +#define glVertexAttribs1svNV (_GET_TLS_PROCTABLE()->VertexAttribs1svNV) +#define glVertexAttribs2dvNV (_GET_TLS_PROCTABLE()->VertexAttribs2dvNV) +#define glVertexAttribs2fvNV (_GET_TLS_PROCTABLE()->VertexAttribs2fvNV) +#define glVertexAttribs2svNV (_GET_TLS_PROCTABLE()->VertexAttribs2svNV) +#define glVertexAttribs3dvNV (_GET_TLS_PROCTABLE()->VertexAttribs3dvNV) +#define glVertexAttribs3fvNV (_GET_TLS_PROCTABLE()->VertexAttribs3fvNV) +#define glVertexAttribs3svNV (_GET_TLS_PROCTABLE()->VertexAttribs3svNV) +#define glVertexAttribs4dvNV (_GET_TLS_PROCTABLE()->VertexAttribs4dvNV) +#define glVertexAttribs4fvNV (_GET_TLS_PROCTABLE()->VertexAttribs4fvNV) +#define glVertexAttribs4svNV (_GET_TLS_PROCTABLE()->VertexAttribs4svNV) +#define glVertexAttribs4ubvNV (_GET_TLS_PROCTABLE()->VertexAttribs4ubvNV) +#define glTexBumpParameterivATI (_GET_TLS_PROCTABLE()->TexBumpParameterivATI) +#define glTexBumpParameterfvATI (_GET_TLS_PROCTABLE()->TexBumpParameterfvATI) +#define glGetTexBumpParameterivATI (_GET_TLS_PROCTABLE()->GetTexBumpParameterivATI) +#define glGetTexBumpParameterfvATI (_GET_TLS_PROCTABLE()->GetTexBumpParameterfvATI) +#define glGenFragmentShadersATI (_GET_TLS_PROCTABLE()->GenFragmentShadersATI) +#define glBindFragmentShaderATI (_GET_TLS_PROCTABLE()->BindFragmentShaderATI) +#define glDeleteFragmentShaderATI (_GET_TLS_PROCTABLE()->DeleteFragmentShaderATI) +#define glBeginFragmentShaderATI (_GET_TLS_PROCTABLE()->BeginFragmentShaderATI) +#define glEndFragmentShaderATI (_GET_TLS_PROCTABLE()->EndFragmentShaderATI) +#define glPassTexCoordATI (_GET_TLS_PROCTABLE()->PassTexCoordATI) +#define glSampleMapATI (_GET_TLS_PROCTABLE()->SampleMapATI) +#define glColorFragmentOp1ATI (_GET_TLS_PROCTABLE()->ColorFragmentOp1ATI) +#define glColorFragmentOp2ATI (_GET_TLS_PROCTABLE()->ColorFragmentOp2ATI) +#define glColorFragmentOp3ATI (_GET_TLS_PROCTABLE()->ColorFragmentOp3ATI) +#define glAlphaFragmentOp1ATI (_GET_TLS_PROCTABLE()->AlphaFragmentOp1ATI) +#define glAlphaFragmentOp2ATI (_GET_TLS_PROCTABLE()->AlphaFragmentOp2ATI) +#define glAlphaFragmentOp3ATI (_GET_TLS_PROCTABLE()->AlphaFragmentOp3ATI) +#define glSetFragmentShaderConstantATI (_GET_TLS_PROCTABLE()->SetFragmentShaderConstantATI) +#define glPNTrianglesiATI (_GET_TLS_PROCTABLE()->PNTrianglesiATI) +#define glPNTrianglesfATI (_GET_TLS_PROCTABLE()->PNTrianglesfATI) +#define glNewObjectBufferATI (_GET_TLS_PROCTABLE()->NewObjectBufferATI) +#define glIsObjectBufferATI (_GET_TLS_PROCTABLE()->IsObjectBufferATI) +#define glUpdateObjectBufferATI (_GET_TLS_PROCTABLE()->UpdateObjectBufferATI) +#define glGetObjectBufferfvATI (_GET_TLS_PROCTABLE()->GetObjectBufferfvATI) +#define glGetObjectBufferivATI (_GET_TLS_PROCTABLE()->GetObjectBufferivATI) +#define glFreeObjectBufferATI (_GET_TLS_PROCTABLE()->FreeObjectBufferATI) +#define glArrayObjectATI (_GET_TLS_PROCTABLE()->ArrayObjectATI) +#define glGetArrayObjectfvATI (_GET_TLS_PROCTABLE()->GetArrayObjectfvATI) +#define glGetArrayObjectivATI (_GET_TLS_PROCTABLE()->GetArrayObjectivATI) +#define glVariantArrayObjectATI (_GET_TLS_PROCTABLE()->VariantArrayObjectATI) +#define glGetVariantArrayObjectfvATI (_GET_TLS_PROCTABLE()->GetVariantArrayObjectfvATI) +#define glGetVariantArrayObjectivATI (_GET_TLS_PROCTABLE()->GetVariantArrayObjectivATI) +#define glBeginVertexShaderEXT (_GET_TLS_PROCTABLE()->BeginVertexShaderEXT) +#define glEndVertexShaderEXT (_GET_TLS_PROCTABLE()->EndVertexShaderEXT) +#define glBindVertexShaderEXT (_GET_TLS_PROCTABLE()->BindVertexShaderEXT) +#define glGenVertexShadersEXT (_GET_TLS_PROCTABLE()->GenVertexShadersEXT) +#define glDeleteVertexShaderEXT (_GET_TLS_PROCTABLE()->DeleteVertexShaderEXT) +#define glShaderOp1EXT (_GET_TLS_PROCTABLE()->ShaderOp1EXT) +#define glShaderOp2EXT (_GET_TLS_PROCTABLE()->ShaderOp2EXT) +#define glShaderOp3EXT (_GET_TLS_PROCTABLE()->ShaderOp3EXT) +#define glSwizzleEXT (_GET_TLS_PROCTABLE()->SwizzleEXT) +#define glWriteMaskEXT (_GET_TLS_PROCTABLE()->WriteMaskEXT) +#define glInsertComponentEXT (_GET_TLS_PROCTABLE()->InsertComponentEXT) +#define glExtractComponentEXT (_GET_TLS_PROCTABLE()->ExtractComponentEXT) +#define glGenSymbolsEXT (_GET_TLS_PROCTABLE()->GenSymbolsEXT) +#define glSetInvariantEXT (_GET_TLS_PROCTABLE()->SetInvariantEXT) +#define glSetLocalConstantEXT (_GET_TLS_PROCTABLE()->SetLocalConstantEXT) +#define glVariantbvEXT (_GET_TLS_PROCTABLE()->VariantbvEXT) +#define glVariantsvEXT (_GET_TLS_PROCTABLE()->VariantsvEXT) +#define glVariantivEXT (_GET_TLS_PROCTABLE()->VariantivEXT) +#define glVariantfvEXT (_GET_TLS_PROCTABLE()->VariantfvEXT) +#define glVariantdvEXT (_GET_TLS_PROCTABLE()->VariantdvEXT) +#define glVariantubvEXT (_GET_TLS_PROCTABLE()->VariantubvEXT) +#define glVariantusvEXT (_GET_TLS_PROCTABLE()->VariantusvEXT) +#define glVariantuivEXT (_GET_TLS_PROCTABLE()->VariantuivEXT) +#define glVariantPointerEXT (_GET_TLS_PROCTABLE()->VariantPointerEXT) +#define glEnableVariantClientStateEXT (_GET_TLS_PROCTABLE()->EnableVariantClientStateEXT) +#define glDisableVariantClientStateEXT (_GET_TLS_PROCTABLE()->DisableVariantClientStateEXT) +#define glBindLightParameterEXT (_GET_TLS_PROCTABLE()->BindLightParameterEXT) +#define glBindMaterialParameterEXT (_GET_TLS_PROCTABLE()->BindMaterialParameterEXT) +#define glBindTexGenParameterEXT (_GET_TLS_PROCTABLE()->BindTexGenParameterEXT) +#define glBindTextureUnitParameterEXT (_GET_TLS_PROCTABLE()->BindTextureUnitParameterEXT) +#define glBindParameterEXT (_GET_TLS_PROCTABLE()->BindParameterEXT) +#define glIsVariantEnabledEXT (_GET_TLS_PROCTABLE()->IsVariantEnabledEXT) +#define glGetVariantBooleanvEXT (_GET_TLS_PROCTABLE()->GetVariantBooleanvEXT) +#define glGetVariantIntegervEXT (_GET_TLS_PROCTABLE()->GetVariantIntegervEXT) +#define glGetVariantFloatvEXT (_GET_TLS_PROCTABLE()->GetVariantFloatvEXT) +#define glGetVariantPointervEXT (_GET_TLS_PROCTABLE()->GetVariantPointervEXT) +#define glGetInvariantBooleanvEXT (_GET_TLS_PROCTABLE()->GetInvariantBooleanvEXT) +#define glGetInvariantIntegervEXT (_GET_TLS_PROCTABLE()->GetInvariantIntegervEXT) +#define glGetInvariantFloatvEXT (_GET_TLS_PROCTABLE()->GetInvariantFloatvEXT) +#define glGetLocalConstantBooleanvEXT (_GET_TLS_PROCTABLE()->GetLocalConstantBooleanvEXT) +#define glGetLocalConstantIntegervEXT (_GET_TLS_PROCTABLE()->GetLocalConstantIntegervEXT) +#define glGetLocalConstantFloatvEXT (_GET_TLS_PROCTABLE()->GetLocalConstantFloatvEXT) +#define glVertexStream1sATI (_GET_TLS_PROCTABLE()->VertexStream1sATI) +#define glVertexStream1svATI (_GET_TLS_PROCTABLE()->VertexStream1svATI) +#define glVertexStream1iATI (_GET_TLS_PROCTABLE()->VertexStream1iATI) +#define glVertexStream1ivATI (_GET_TLS_PROCTABLE()->VertexStream1ivATI) +#define glVertexStream1fATI (_GET_TLS_PROCTABLE()->VertexStream1fATI) +#define glVertexStream1fvATI (_GET_TLS_PROCTABLE()->VertexStream1fvATI) +#define glVertexStream1dATI (_GET_TLS_PROCTABLE()->VertexStream1dATI) +#define glVertexStream1dvATI (_GET_TLS_PROCTABLE()->VertexStream1dvATI) +#define glVertexStream2sATI (_GET_TLS_PROCTABLE()->VertexStream2sATI) +#define glVertexStream2svATI (_GET_TLS_PROCTABLE()->VertexStream2svATI) +#define glVertexStream2iATI (_GET_TLS_PROCTABLE()->VertexStream2iATI) +#define glVertexStream2ivATI (_GET_TLS_PROCTABLE()->VertexStream2ivATI) +#define glVertexStream2fATI (_GET_TLS_PROCTABLE()->VertexStream2fATI) +#define glVertexStream2fvATI (_GET_TLS_PROCTABLE()->VertexStream2fvATI) +#define glVertexStream2dATI (_GET_TLS_PROCTABLE()->VertexStream2dATI) +#define glVertexStream2dvATI (_GET_TLS_PROCTABLE()->VertexStream2dvATI) +#define glVertexStream3sATI (_GET_TLS_PROCTABLE()->VertexStream3sATI) +#define glVertexStream3svATI (_GET_TLS_PROCTABLE()->VertexStream3svATI) +#define glVertexStream3iATI (_GET_TLS_PROCTABLE()->VertexStream3iATI) +#define glVertexStream3ivATI (_GET_TLS_PROCTABLE()->VertexStream3ivATI) +#define glVertexStream3fATI (_GET_TLS_PROCTABLE()->VertexStream3fATI) +#define glVertexStream3fvATI (_GET_TLS_PROCTABLE()->VertexStream3fvATI) +#define glVertexStream3dATI (_GET_TLS_PROCTABLE()->VertexStream3dATI) +#define glVertexStream3dvATI (_GET_TLS_PROCTABLE()->VertexStream3dvATI) +#define glVertexStream4sATI (_GET_TLS_PROCTABLE()->VertexStream4sATI) +#define glVertexStream4svATI (_GET_TLS_PROCTABLE()->VertexStream4svATI) +#define glVertexStream4iATI (_GET_TLS_PROCTABLE()->VertexStream4iATI) +#define glVertexStream4ivATI (_GET_TLS_PROCTABLE()->VertexStream4ivATI) +#define glVertexStream4fATI (_GET_TLS_PROCTABLE()->VertexStream4fATI) +#define glVertexStream4fvATI (_GET_TLS_PROCTABLE()->VertexStream4fvATI) +#define glVertexStream4dATI (_GET_TLS_PROCTABLE()->VertexStream4dATI) +#define glVertexStream4dvATI (_GET_TLS_PROCTABLE()->VertexStream4dvATI) +#define glNormalStream3bATI (_GET_TLS_PROCTABLE()->NormalStream3bATI) +#define glNormalStream3bvATI (_GET_TLS_PROCTABLE()->NormalStream3bvATI) +#define glNormalStream3sATI (_GET_TLS_PROCTABLE()->NormalStream3sATI) +#define glNormalStream3svATI (_GET_TLS_PROCTABLE()->NormalStream3svATI) +#define glNormalStream3iATI (_GET_TLS_PROCTABLE()->NormalStream3iATI) +#define glNormalStream3ivATI (_GET_TLS_PROCTABLE()->NormalStream3ivATI) +#define glNormalStream3fATI (_GET_TLS_PROCTABLE()->NormalStream3fATI) +#define glNormalStream3fvATI (_GET_TLS_PROCTABLE()->NormalStream3fvATI) +#define glNormalStream3dATI (_GET_TLS_PROCTABLE()->NormalStream3dATI) +#define glNormalStream3dvATI (_GET_TLS_PROCTABLE()->NormalStream3dvATI) +#define glClientActiveVertexStreamATI (_GET_TLS_PROCTABLE()->ClientActiveVertexStreamATI) +#define glVertexBlendEnviATI (_GET_TLS_PROCTABLE()->VertexBlendEnviATI) +#define glVertexBlendEnvfATI (_GET_TLS_PROCTABLE()->VertexBlendEnvfATI) +#define glElementPointerATI (_GET_TLS_PROCTABLE()->ElementPointerATI) +#define glDrawElementArrayATI (_GET_TLS_PROCTABLE()->DrawElementArrayATI) +#define glDrawRangeElementArrayATI (_GET_TLS_PROCTABLE()->DrawRangeElementArrayATI) +#define glDrawMeshArraysSUN (_GET_TLS_PROCTABLE()->DrawMeshArraysSUN) +#define glGenOcclusionQueriesNV (_GET_TLS_PROCTABLE()->GenOcclusionQueriesNV) +#define glDeleteOcclusionQueriesNV (_GET_TLS_PROCTABLE()->DeleteOcclusionQueriesNV) +#define glIsOcclusionQueryNV (_GET_TLS_PROCTABLE()->IsOcclusionQueryNV) +#define glBeginOcclusionQueryNV (_GET_TLS_PROCTABLE()->BeginOcclusionQueryNV) +#define glEndOcclusionQueryNV (_GET_TLS_PROCTABLE()->EndOcclusionQueryNV) +#define glGetOcclusionQueryivNV (_GET_TLS_PROCTABLE()->GetOcclusionQueryivNV) +#define glGetOcclusionQueryuivNV (_GET_TLS_PROCTABLE()->GetOcclusionQueryuivNV) +#define glPointParameteriNV (_GET_TLS_PROCTABLE()->PointParameteriNV) +#define glPointParameterivNV (_GET_TLS_PROCTABLE()->PointParameterivNV) +#define glActiveStencilFaceEXT (_GET_TLS_PROCTABLE()->ActiveStencilFaceEXT) +#define glElementPointerAPPLE (_GET_TLS_PROCTABLE()->ElementPointerAPPLE) +#define glDrawElementArrayAPPLE (_GET_TLS_PROCTABLE()->DrawElementArrayAPPLE) +#define glDrawRangeElementArrayAPPLE (_GET_TLS_PROCTABLE()->DrawRangeElementArrayAPPLE) +#define glMultiDrawElementArrayAPPLE (_GET_TLS_PROCTABLE()->MultiDrawElementArrayAPPLE) +#define glMultiDrawRangeElementArrayAPPLE (_GET_TLS_PROCTABLE()->MultiDrawRangeElementArrayAPPLE) +#define glGenFencesAPPLE (_GET_TLS_PROCTABLE()->GenFencesAPPLE) +#define glDeleteFencesAPPLE (_GET_TLS_PROCTABLE()->DeleteFencesAPPLE) +#define glSetFenceAPPLE (_GET_TLS_PROCTABLE()->SetFenceAPPLE) +#define glIsFenceAPPLE (_GET_TLS_PROCTABLE()->IsFenceAPPLE) +#define glTestFenceAPPLE (_GET_TLS_PROCTABLE()->TestFenceAPPLE) +#define glFinishFenceAPPLE (_GET_TLS_PROCTABLE()->FinishFenceAPPLE) +#define glTestObjectAPPLE (_GET_TLS_PROCTABLE()->TestObjectAPPLE) +#define glFinishObjectAPPLE (_GET_TLS_PROCTABLE()->FinishObjectAPPLE) +#define glBindVertexArrayAPPLE (_GET_TLS_PROCTABLE()->BindVertexArrayAPPLE) +#define glDeleteVertexArraysAPPLE (_GET_TLS_PROCTABLE()->DeleteVertexArraysAPPLE) +#define glGenVertexArraysAPPLE (_GET_TLS_PROCTABLE()->GenVertexArraysAPPLE) +#define glIsVertexArrayAPPLE (_GET_TLS_PROCTABLE()->IsVertexArrayAPPLE) +#define glVertexArrayRangeAPPLE (_GET_TLS_PROCTABLE()->VertexArrayRangeAPPLE) +#define glFlushVertexArrayRangeAPPLE (_GET_TLS_PROCTABLE()->FlushVertexArrayRangeAPPLE) +#define glVertexArrayParameteriAPPLE (_GET_TLS_PROCTABLE()->VertexArrayParameteriAPPLE) +#define glDrawBuffersATI (_GET_TLS_PROCTABLE()->DrawBuffersATI) +#define glProgramNamedParameter4fNV (_GET_TLS_PROCTABLE()->ProgramNamedParameter4fNV) +#define glProgramNamedParameter4dNV (_GET_TLS_PROCTABLE()->ProgramNamedParameter4dNV) +#define glProgramNamedParameter4fvNV (_GET_TLS_PROCTABLE()->ProgramNamedParameter4fvNV) +#define glProgramNamedParameter4dvNV (_GET_TLS_PROCTABLE()->ProgramNamedParameter4dvNV) +#define glGetProgramNamedParameterfvNV (_GET_TLS_PROCTABLE()->GetProgramNamedParameterfvNV) +#define glGetProgramNamedParameterdvNV (_GET_TLS_PROCTABLE()->GetProgramNamedParameterdvNV) +#define glVertex2hNV (_GET_TLS_PROCTABLE()->Vertex2hNV) +#define glVertex2hvNV (_GET_TLS_PROCTABLE()->Vertex2hvNV) +#define glVertex3hNV (_GET_TLS_PROCTABLE()->Vertex3hNV) +#define glVertex3hvNV (_GET_TLS_PROCTABLE()->Vertex3hvNV) +#define glVertex4hNV (_GET_TLS_PROCTABLE()->Vertex4hNV) +#define glVertex4hvNV (_GET_TLS_PROCTABLE()->Vertex4hvNV) +#define glNormal3hNV (_GET_TLS_PROCTABLE()->Normal3hNV) +#define glNormal3hvNV (_GET_TLS_PROCTABLE()->Normal3hvNV) +#define glColor3hNV (_GET_TLS_PROCTABLE()->Color3hNV) +#define glColor3hvNV (_GET_TLS_PROCTABLE()->Color3hvNV) +#define glColor4hNV (_GET_TLS_PROCTABLE()->Color4hNV) +#define glColor4hvNV (_GET_TLS_PROCTABLE()->Color4hvNV) +#define glTexCoord1hNV (_GET_TLS_PROCTABLE()->TexCoord1hNV) +#define glTexCoord1hvNV (_GET_TLS_PROCTABLE()->TexCoord1hvNV) +#define glTexCoord2hNV (_GET_TLS_PROCTABLE()->TexCoord2hNV) +#define glTexCoord2hvNV (_GET_TLS_PROCTABLE()->TexCoord2hvNV) +#define glTexCoord3hNV (_GET_TLS_PROCTABLE()->TexCoord3hNV) +#define glTexCoord3hvNV (_GET_TLS_PROCTABLE()->TexCoord3hvNV) +#define glTexCoord4hNV (_GET_TLS_PROCTABLE()->TexCoord4hNV) +#define glTexCoord4hvNV (_GET_TLS_PROCTABLE()->TexCoord4hvNV) +#define glMultiTexCoord1hNV (_GET_TLS_PROCTABLE()->MultiTexCoord1hNV) +#define glMultiTexCoord1hvNV (_GET_TLS_PROCTABLE()->MultiTexCoord1hvNV) +#define glMultiTexCoord2hNV (_GET_TLS_PROCTABLE()->MultiTexCoord2hNV) +#define glMultiTexCoord2hvNV (_GET_TLS_PROCTABLE()->MultiTexCoord2hvNV) +#define glMultiTexCoord3hNV (_GET_TLS_PROCTABLE()->MultiTexCoord3hNV) +#define glMultiTexCoord3hvNV (_GET_TLS_PROCTABLE()->MultiTexCoord3hvNV) +#define glMultiTexCoord4hNV (_GET_TLS_PROCTABLE()->MultiTexCoord4hNV) +#define glMultiTexCoord4hvNV (_GET_TLS_PROCTABLE()->MultiTexCoord4hvNV) +#define glFogCoordhNV (_GET_TLS_PROCTABLE()->FogCoordhNV) +#define glFogCoordhvNV (_GET_TLS_PROCTABLE()->FogCoordhvNV) +#define glSecondaryColor3hNV (_GET_TLS_PROCTABLE()->SecondaryColor3hNV) +#define glSecondaryColor3hvNV (_GET_TLS_PROCTABLE()->SecondaryColor3hvNV) +#define glVertexWeighthNV (_GET_TLS_PROCTABLE()->VertexWeighthNV) +#define glVertexWeighthvNV (_GET_TLS_PROCTABLE()->VertexWeighthvNV) +#define glVertexAttrib1hNV (_GET_TLS_PROCTABLE()->VertexAttrib1hNV) +#define glVertexAttrib1hvNV (_GET_TLS_PROCTABLE()->VertexAttrib1hvNV) +#define glVertexAttrib2hNV (_GET_TLS_PROCTABLE()->VertexAttrib2hNV) +#define glVertexAttrib2hvNV (_GET_TLS_PROCTABLE()->VertexAttrib2hvNV) +#define glVertexAttrib3hNV (_GET_TLS_PROCTABLE()->VertexAttrib3hNV) +#define glVertexAttrib3hvNV (_GET_TLS_PROCTABLE()->VertexAttrib3hvNV) +#define glVertexAttrib4hNV (_GET_TLS_PROCTABLE()->VertexAttrib4hNV) +#define glVertexAttrib4hvNV (_GET_TLS_PROCTABLE()->VertexAttrib4hvNV) +#define glVertexAttribs1hvNV (_GET_TLS_PROCTABLE()->VertexAttribs1hvNV) +#define glVertexAttribs2hvNV (_GET_TLS_PROCTABLE()->VertexAttribs2hvNV) +#define glVertexAttribs3hvNV (_GET_TLS_PROCTABLE()->VertexAttribs3hvNV) +#define glVertexAttribs4hvNV (_GET_TLS_PROCTABLE()->VertexAttribs4hvNV) +#define glPixelDataRangeNV (_GET_TLS_PROCTABLE()->PixelDataRangeNV) +#define glFlushPixelDataRangeNV (_GET_TLS_PROCTABLE()->FlushPixelDataRangeNV) +#define glPrimitiveRestartNV (_GET_TLS_PROCTABLE()->PrimitiveRestartNV) +#define glPrimitiveRestartIndexNV (_GET_TLS_PROCTABLE()->PrimitiveRestartIndexNV) +#define glMapObjectBufferATI (_GET_TLS_PROCTABLE()->MapObjectBufferATI) +#define glUnmapObjectBufferATI (_GET_TLS_PROCTABLE()->UnmapObjectBufferATI) +#define glStencilOpSeparateATI (_GET_TLS_PROCTABLE()->StencilOpSeparateATI) +#define glStencilFuncSeparateATI (_GET_TLS_PROCTABLE()->StencilFuncSeparateATI) +#define glVertexAttribArrayObjectATI (_GET_TLS_PROCTABLE()->VertexAttribArrayObjectATI) +#define glGetVertexAttribArrayObjectfvATI (_GET_TLS_PROCTABLE()->GetVertexAttribArrayObjectfvATI) +#define glGetVertexAttribArrayObjectivATI (_GET_TLS_PROCTABLE()->GetVertexAttribArrayObjectivATI) +#define glDepthBoundsEXT (_GET_TLS_PROCTABLE()->DepthBoundsEXT) +#define glBlendEquationSeparateEXT (_GET_TLS_PROCTABLE()->BlendEquationSeparateEXT) +#define glAddSwapHintRectWIN (_GET_TLS_PROCTABLE()->AddSwapHintRectWIN) +#ifdef _WIN32 +#define wglCreateBufferRegionARB (_GET_TLS_PROCTABLE()->CreateBufferRegionARB) +#define wglDeleteBufferRegionARB (_GET_TLS_PROCTABLE()->DeleteBufferRegionARB) +#define wglSaveBufferRegionARB (_GET_TLS_PROCTABLE()->SaveBufferRegionARB) +#define wglRestoreBufferRegionARB (_GET_TLS_PROCTABLE()->RestoreBufferRegionARB) +#define wglGetExtensionsStringARB (_GET_TLS_PROCTABLE()->GetExtensionsStringARB) +#define wglGetPixelFormatAttribivARB (_GET_TLS_PROCTABLE()->GetPixelFormatAttribivARB) +#define wglGetPixelFormatAttribfvARB (_GET_TLS_PROCTABLE()->GetPixelFormatAttribfvARB) +#define wglChoosePixelFormatARB (_GET_TLS_PROCTABLE()->ChoosePixelFormatARB) +#define wglMakeContextCurrentARB (_GET_TLS_PROCTABLE()->MakeContextCurrentARB) +#define wglGetCurrentReadDCARB (_GET_TLS_PROCTABLE()->GetCurrentReadDCARB) +#define wglCreatePbufferARB (_GET_TLS_PROCTABLE()->CreatePbufferARB) +#define wglGetPbufferDCARB (_GET_TLS_PROCTABLE()->GetPbufferDCARB) +#define wglReleasePbufferDCARB (_GET_TLS_PROCTABLE()->ReleasePbufferDCARB) +#define wglDestroyPbufferARB (_GET_TLS_PROCTABLE()->DestroyPbufferARB) +#define wglQueryPbufferARB (_GET_TLS_PROCTABLE()->QueryPbufferARB) +#define wglBindTexImageARB (_GET_TLS_PROCTABLE()->BindTexImageARB) +#define wglReleaseTexImageARB (_GET_TLS_PROCTABLE()->ReleaseTexImageARB) +#define wglSetPbufferAttribARB (_GET_TLS_PROCTABLE()->SetPbufferAttribARB) +#define wglCreateDisplayColorTableEXT (_GET_TLS_PROCTABLE()->CreateDisplayColorTableEXT) +#define wglLoadDisplayColorTableEXT (_GET_TLS_PROCTABLE()->LoadDisplayColorTableEXT) +#define wglBindDisplayColorTableEXT (_GET_TLS_PROCTABLE()->BindDisplayColorTableEXT) +#define wglDestroyDisplayColorTableEXT (_GET_TLS_PROCTABLE()->DestroyDisplayColorTableEXT) +#define wglGetExtensionsStringEXT (_GET_TLS_PROCTABLE()->GetExtensionsStringEXT) +#define wglMakeContextCurrentEXT (_GET_TLS_PROCTABLE()->MakeContextCurrentEXT) +#define wglGetCurrentReadDCEXT (_GET_TLS_PROCTABLE()->GetCurrentReadDCEXT) +#define wglCreatePbufferEXT (_GET_TLS_PROCTABLE()->CreatePbufferEXT) +#define wglGetPbufferDCEXT (_GET_TLS_PROCTABLE()->GetPbufferDCEXT) +#define wglReleasePbufferDCEXT (_GET_TLS_PROCTABLE()->ReleasePbufferDCEXT) +#define wglDestroyPbufferEXT (_GET_TLS_PROCTABLE()->DestroyPbufferEXT) +#define wglQueryPbufferEXT (_GET_TLS_PROCTABLE()->QueryPbufferEXT) +#define wglGetPixelFormatAttribivEXT (_GET_TLS_PROCTABLE()->GetPixelFormatAttribivEXT) +#define wglGetPixelFormatAttribfvEXT (_GET_TLS_PROCTABLE()->GetPixelFormatAttribfvEXT) +#define wglChoosePixelFormatEXT (_GET_TLS_PROCTABLE()->ChoosePixelFormatEXT) +#define wglSwapIntervalEXT (_GET_TLS_PROCTABLE()->SwapIntervalEXT) +#define wglGetSwapIntervalEXT (_GET_TLS_PROCTABLE()->GetSwapIntervalEXT) +#define wglAllocateMemoryNV (_GET_TLS_PROCTABLE()->AllocateMemoryNV) +#define wglFreeMemoryNV (_GET_TLS_PROCTABLE()->FreeMemoryNV) +#define wglGetSyncValuesOML (_GET_TLS_PROCTABLE()->GetSyncValuesOML) +#define wglGetMscRateOML (_GET_TLS_PROCTABLE()->GetMscRateOML) +#define wglSwapBuffersMscOML (_GET_TLS_PROCTABLE()->SwapBuffersMscOML) +#define wglSwapLayerBuffersMscOML (_GET_TLS_PROCTABLE()->SwapLayerBuffersMscOML) +#define wglWaitForMscOML (_GET_TLS_PROCTABLE()->WaitForMscOML) +#define wglWaitForSbcOML (_GET_TLS_PROCTABLE()->WaitForSbcOML) +#define wglGetDigitalVideoParametersI3D (_GET_TLS_PROCTABLE()->GetDigitalVideoParametersI3D) +#define wglSetDigitalVideoParametersI3D (_GET_TLS_PROCTABLE()->SetDigitalVideoParametersI3D) +#define wglGetGammaTableParametersI3D (_GET_TLS_PROCTABLE()->GetGammaTableParametersI3D) +#define wglSetGammaTableParametersI3D (_GET_TLS_PROCTABLE()->SetGammaTableParametersI3D) +#define wglGetGammaTableI3D (_GET_TLS_PROCTABLE()->GetGammaTableI3D) +#define wglSetGammaTableI3D (_GET_TLS_PROCTABLE()->SetGammaTableI3D) +#define wglEnableGenlockI3D (_GET_TLS_PROCTABLE()->EnableGenlockI3D) +#define wglDisableGenlockI3D (_GET_TLS_PROCTABLE()->DisableGenlockI3D) +#define wglIsEnabledGenlockI3D (_GET_TLS_PROCTABLE()->IsEnabledGenlockI3D) +#define wglGenlockSourceI3D (_GET_TLS_PROCTABLE()->GenlockSourceI3D) +#define wglGetGenlockSourceI3D (_GET_TLS_PROCTABLE()->GetGenlockSourceI3D) +#define wglGenlockSourceEdgeI3D (_GET_TLS_PROCTABLE()->GenlockSourceEdgeI3D) +#define wglGetGenlockSourceEdgeI3D (_GET_TLS_PROCTABLE()->GetGenlockSourceEdgeI3D) +#define wglGenlockSampleRateI3D (_GET_TLS_PROCTABLE()->GenlockSampleRateI3D) +#define wglGetGenlockSampleRateI3D (_GET_TLS_PROCTABLE()->GetGenlockSampleRateI3D) +#define wglGenlockSourceDelayI3D (_GET_TLS_PROCTABLE()->GenlockSourceDelayI3D) +#define wglGetGenlockSourceDelayI3D (_GET_TLS_PROCTABLE()->GetGenlockSourceDelayI3D) +#define wglQueryGenlockMaxSourceDelayI3D (_GET_TLS_PROCTABLE()->QueryGenlockMaxSourceDelayI3D) +#define wglCreateImageBufferI3D (_GET_TLS_PROCTABLE()->CreateImageBufferI3D) +#define wglDestroyImageBufferI3D (_GET_TLS_PROCTABLE()->DestroyImageBufferI3D) +#define wglAssociateImageBufferEventsI3D (_GET_TLS_PROCTABLE()->AssociateImageBufferEventsI3D) +#define wglReleaseImageBufferEventsI3D (_GET_TLS_PROCTABLE()->ReleaseImageBufferEventsI3D) +#define wglEnableFrameLockI3D (_GET_TLS_PROCTABLE()->EnableFrameLockI3D) +#define wglDisableFrameLockI3D (_GET_TLS_PROCTABLE()->DisableFrameLockI3D) +#define wglIsEnabledFrameLockI3D (_GET_TLS_PROCTABLE()->IsEnabledFrameLockI3D) +#define wglQueryFrameLockMasterI3D (_GET_TLS_PROCTABLE()->QueryFrameLockMasterI3D) +#define wglGetFrameUsageI3D (_GET_TLS_PROCTABLE()->GetFrameUsageI3D) +#define wglBeginFrameTrackingI3D (_GET_TLS_PROCTABLE()->BeginFrameTrackingI3D) +#define wglEndFrameTrackingI3D (_GET_TLS_PROCTABLE()->EndFrameTrackingI3D) +#define wglQueryFrameTrackingI3D (_GET_TLS_PROCTABLE()->QueryFrameTrackingI3D) +#endif /* _WIN32 */ + +#ifndef _APP_PROCTABLE + +/* + * Applications can replace the following function with its own function + * for accessing thread local proc/context dependent proc table. + * The following default function works for most applications which + * are using the same device for all their contexts - even if + * the contexts are on different threads. + */ + +static _inline _GLextensionProcs *_GET_TLS_PROCTABLE(void) + +{ + extern _GLextensionProcs _extensionProcs; + + return (&_extensionProcs); +} + +#else + +/* + * Application should replace this compiled function with + * an inlined function for maximum performance. + */ + +extern _GLextensionProcs *_GET_TLS_PROCTABLE(void); + +#endif + +/* + * Provide an initialization function for the application + * to initialize its own proc tables in case the application + * needs to use multiple proc tables. + */ + +static _inline void _InitExtensionProcs(_GLextensionProcs *appProcs) +{ + extern _GLextensionProcs _extensionProcs; + + *appProcs = _extensionProcs; +} + +#ifdef __cplusplus +} +#endif + + +#endif /* _GLPROCS_H_ */ diff --git a/plugins/zerogs/opengl/memcpy_amd.cpp b/plugins/zerogs/opengl/memcpy_amd.cpp index 0c78690760..dfd1119330 100644 --- a/plugins/zerogs/opengl/memcpy_amd.cpp +++ b/plugins/zerogs/opengl/memcpy_amd.cpp @@ -1,478 +1,478 @@ -/****************************************************************************** - - Copyright (c) 2001 Advanced Micro Devices, Inc. - - LIMITATION OF LIABILITY: THE MATERIALS ARE PROVIDED *AS IS* WITHOUT ANY - EXPRESS OR IMPLIED WARRANTY OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, - NONINFRINGEMENT OF THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY - PARTICULAR PURPOSE. IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY - DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, - BUSINESS INTERRUPTION, LOSS OF INFORMATION) ARISING OUT OF THE USE OF OR - INABILITY TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY - OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE EXCLUSION OR LIMITATION - OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY - NOT APPLY TO YOU. - - AMD does not assume any responsibility for any errors which may appear in the - Materials nor any responsibility to support or update the Materials. AMD retains - the right to make changes to its test specifications at any time, without notice. - - NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any - further information, software, technical information, know-how, or show-how - available to you. - - So that all may benefit from your experience, please report any problems - or suggestions about this software to 3dsdk.support@amd.com - - AMD Developer Technologies, M/S 585 - Advanced Micro Devices, Inc. - 5900 E. Ben White Blvd. - Austin, TX 78741 - 3dsdk.support@amd.com -******************************************************************************/ - -#include - -/***************************************************************************** -MEMCPY_AMD.CPP -******************************************************************************/ - -// Very optimized memcpy() routine for AMD Athlon and Duron family. -// This code uses any of FOUR different basic copy methods, depending -// on the transfer size. -// NOTE: Since this code uses MOVNTQ (also known as "Non-Temporal MOV" or -// "Streaming Store"), and also uses the software prefetch instructions, -// be sure you're running on Athlon/Duron or other recent CPU before calling! - -#define TINY_BLOCK_COPY 64 // upper limit for movsd type copy -// The smallest copy uses the X86 "movsd" instruction, in an optimized -// form which is an "unrolled loop". - -#define IN_CACHE_COPY 2 * 1024 // upper limit for movq/movq copy w/SW prefetch -// Next is a copy that uses the MMX registers to copy 8 bytes at a time, -// also using the "unrolled loop" optimization. This code uses -// the software prefetch instruction to get the data into the cache. - -#define UNCACHED_COPY 4 * 1024 // upper limit for movq/movntq w/SW prefetch -// For larger blocks, which will spill beyond the cache, it's faster to -// use the Streaming Store instruction MOVNTQ. This write instruction -// bypasses the cache and writes straight to main memory. This code also -// uses the software prefetch instruction to pre-read the data. -// USE 64 * 1024 FOR THIS VALUE IF YOU'RE ALWAYS FILLING A "CLEAN CACHE" - -#define BLOCK_PREFETCH_COPY infinity // no limit for movq/movntq w/block prefetch -#define CACHEBLOCK 80h // number of 64-byte blocks (cache lines) for block prefetch -// For the largest size blocks, a special technique called Block Prefetch -// can be used to accelerate the read operations. Block Prefetch reads -// one address per cache line, for a series of cache lines, in a short loop. -// This is faster than using software prefetch. The technique is great for -// getting maximum read bandwidth, especially in DDR memory systems. - -//#include - -// Inline assembly syntax for use with Visual C++ -#ifdef _WIN32 -#include -#endif - -extern "C" { -#include "PS2Etypes.h" - -#if defined(_MSC_VER) && !defined(__x86_64__) - -void * memcpy_amd(void *dest, const void *src, size_t n) -{ - __asm { - mov ecx, [n] ; number of bytes to copy - mov edi, [dest] ; destination - mov esi, [src] ; source - mov ebx, ecx ; keep a copy of count - - cld - cmp ecx, TINY_BLOCK_COPY - jb $memcpy_ic_3 ; tiny? skip mmx copy - - cmp ecx, 32*1024 ; don't align between 32k-64k because - jbe $memcpy_do_align ; it appears to be slower - cmp ecx, 64*1024 - jbe $memcpy_align_done -$memcpy_do_align: - mov ecx, 8 ; a trick that's faster than rep movsb... - sub ecx, edi ; align destination to qword - and ecx, 111b ; get the low bits - sub ebx, ecx ; update copy count - neg ecx ; set up to jump into the array - add ecx, offset $memcpy_align_done - jmp ecx ; jump to array of movsb's - -align 4 - movsb - movsb - movsb - movsb - movsb - movsb - movsb - movsb - -$memcpy_align_done: ; destination is dword aligned - mov ecx, ebx ; number of bytes left to copy - shr ecx, 6 ; get 64-byte block count - jz $memcpy_ic_2 ; finish the last few bytes - - cmp ecx, IN_CACHE_COPY/64 ; too big 4 cache? use uncached copy - jae $memcpy_uc_test - -// This is small block copy that uses the MMX registers to copy 8 bytes -// at a time. It uses the "unrolled loop" optimization, and also uses -// the software prefetch instruction to get the data into the cache. -align 16 -$memcpy_ic_1: ; 64-byte block copies, in-cache copy - - prefetchnta [esi + (200*64/34+192)] ; start reading ahead - - movq mm0, [esi+0] ; read 64 bits - movq mm1, [esi+8] - movq [edi+0], mm0 ; write 64 bits - movq [edi+8], mm1 ; note: the normal movq writes the - movq mm2, [esi+16] ; data to cache; a cache line will be - movq mm3, [esi+24] ; allocated as needed, to store the data - movq [edi+16], mm2 - movq [edi+24], mm3 - movq mm0, [esi+32] - movq mm1, [esi+40] - movq [edi+32], mm0 - movq [edi+40], mm1 - movq mm2, [esi+48] - movq mm3, [esi+56] - movq [edi+48], mm2 - movq [edi+56], mm3 - - add esi, 64 ; update source pointer - add edi, 64 ; update destination pointer - dec ecx ; count down - jnz $memcpy_ic_1 ; last 64-byte block? - -$memcpy_ic_2: - mov ecx, ebx ; has valid low 6 bits of the byte count -$memcpy_ic_3: - shr ecx, 2 ; dword count - and ecx, 1111b ; only look at the "remainder" bits - neg ecx ; set up to jump into the array - add ecx, offset $memcpy_last_few - jmp ecx ; jump to array of movsd's - -$memcpy_uc_test: - cmp ecx, UNCACHED_COPY/64 ; big enough? use block prefetch copy - jae $memcpy_bp_1 - -$memcpy_64_test: - or ecx, ecx ; tail end of block prefetch will jump here - jz $memcpy_ic_2 ; no more 64-byte blocks left - -// For larger blocks, which will spill beyond the cache, it's faster to -// use the Streaming Store instruction MOVNTQ. This write instruction -// bypasses the cache and writes straight to main memory. This code also -// uses the software prefetch instruction to pre-read the data. -align 16 -$memcpy_uc_1: ; 64-byte blocks, uncached copy - - prefetchnta [esi + (200*64/34+192)] ; start reading ahead - - movq mm0,[esi+0] ; read 64 bits - add edi,64 ; update destination pointer - movq mm1,[esi+8] - add esi,64 ; update source pointer - movq mm2,[esi-48] - movntq [edi-64], mm0 ; write 64 bits, bypassing the cache - movq mm0,[esi-40] ; note: movntq also prevents the CPU - movntq [edi-56], mm1 ; from READING the destination address - movq mm1,[esi-32] ; into the cache, only to be over-written - movntq [edi-48], mm2 ; so that also helps performance - movq mm2,[esi-24] - movntq [edi-40], mm0 - movq mm0,[esi-16] - movntq [edi-32], mm1 - movq mm1,[esi-8] - movntq [edi-24], mm2 - movntq [edi-16], mm0 - dec ecx - movntq [edi-8], mm1 - jnz $memcpy_uc_1 ; last 64-byte block? - - jmp $memcpy_ic_2 ; almost done - -// For the largest size blocks, a special technique called Block Prefetch -// can be used to accelerate the read operations. Block Prefetch reads -// one address per cache line, for a series of cache lines, in a short loop. -// This is faster than using software prefetch. The technique is great for -// getting maximum read bandwidth, especially in DDR memory systems. -$memcpy_bp_1: ; large blocks, block prefetch copy - - cmp ecx, CACHEBLOCK ; big enough to run another prefetch loop? - jl $memcpy_64_test ; no, back to regular uncached copy - - mov eax, CACHEBLOCK / 2 ; block prefetch loop, unrolled 2X - add esi, CACHEBLOCK * 64 ; move to the top of the block -align 16 -$memcpy_bp_2: - mov edx, [esi-64] ; grab one address per cache line - mov edx, [esi-128] ; grab one address per cache line - sub esi, 128 ; go reverse order to suppress HW prefetcher - dec eax ; count down the cache lines - jnz $memcpy_bp_2 ; keep grabbing more lines into cache - - mov eax, CACHEBLOCK ; now that it's in cache, do the copy -align 16 -$memcpy_bp_3: - movq mm0, [esi ] ; read 64 bits - movq mm1, [esi+ 8] - movq mm2, [esi+16] - movq mm3, [esi+24] - movq mm4, [esi+32] - movq mm5, [esi+40] - movq mm6, [esi+48] - movq mm7, [esi+56] - add esi, 64 ; update source pointer - movntq [edi ], mm0 ; write 64 bits, bypassing cache - movntq [edi+ 8], mm1 ; note: movntq also prevents the CPU - movntq [edi+16], mm2 ; from READING the destination address - movntq [edi+24], mm3 ; into the cache, only to be over-written, - movntq [edi+32], mm4 ; so that also helps performance - movntq [edi+40], mm5 - movntq [edi+48], mm6 - movntq [edi+56], mm7 - add edi, 64 ; update dest pointer - - dec eax ; count down - - jnz $memcpy_bp_3 ; keep copying - sub ecx, CACHEBLOCK ; update the 64-byte block count - jmp $memcpy_bp_1 ; keep processing chunks - -// The smallest copy uses the X86 "movsd" instruction, in an optimized -// form which is an "unrolled loop". Then it handles the last few bytes. -align 4 - movsd - movsd ; perform last 1-15 dword copies - movsd - movsd - movsd - movsd - movsd - movsd - movsd - movsd ; perform last 1-7 dword copies - movsd - movsd - movsd - movsd - movsd - movsd - -$memcpy_last_few: ; dword aligned from before movsd's - mov ecx, ebx ; has valid low 2 bits of the byte count - and ecx, 11b ; the last few cows must come home - jz $memcpy_final ; no more, let's leave - rep movsb ; the last 1, 2, or 3 bytes - -$memcpy_final: - emms ; clean up the MMX state - sfence ; flush the write buffer - mov eax, [dest] ; ret value = destination pointer - - } -} - -// mmx memcpy implementation, size has to be a multiple of 8 -// returns 0 is equal, nonzero value if not equal -// ~10 times faster than standard memcmp -// (zerofrog) -u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) -{ - assert( (cmpsize&7) == 0 ); - - __asm { -push esi - mov ecx, cmpsize - mov edx, src1 - mov esi, src2 - - cmp ecx, 32 - jl Done4 - - // custom test first 8 to make sure things are ok - movq mm0, [esi] - movq mm1, [esi+8] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pand mm0, mm1 - movq mm2, [esi+16] - pmovmskb eax, mm0 - movq mm3, [esi+24] - - // check if eq - cmp eax, 0xff - je NextComp - mov eax, 1 - jmp End - -NextComp: - pcmpeqd mm2, [edx+16] - pcmpeqd mm3, [edx+24] - pand mm2, mm3 - pmovmskb eax, mm2 - - sub ecx, 32 - add esi, 32 - add edx, 32 - - // check if eq - cmp eax, 0xff - je ContinueTest - mov eax, 1 - jmp End - - cmp ecx, 64 - jl Done8 - -Cmp8: - movq mm0, [esi] - movq mm1, [esi+8] - movq mm2, [esi+16] - movq mm3, [esi+24] - movq mm4, [esi+32] - movq mm5, [esi+40] - movq mm6, [esi+48] - movq mm7, [esi+56] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pcmpeqd mm2, [edx+16] - pcmpeqd mm3, [edx+24] - pand mm0, mm1 - pcmpeqd mm4, [edx+32] - pand mm0, mm2 - pcmpeqd mm5, [edx+40] - pand mm0, mm3 - pcmpeqd mm6, [edx+48] - pand mm0, mm4 - pcmpeqd mm7, [edx+56] - pand mm0, mm5 - pand mm0, mm6 - pand mm0, mm7 - pmovmskb eax, mm0 - - // check if eq - cmp eax, 0xff - je Continue - mov eax, 1 - jmp End - -Continue: - sub ecx, 64 - add esi, 64 - add edx, 64 -ContinueTest: - cmp ecx, 64 - jge Cmp8 - -Done8: - test ecx, 0x20 - jz Done4 - movq mm0, [esi] - movq mm1, [esi+8] - movq mm2, [esi+16] - movq mm3, [esi+24] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pcmpeqd mm2, [edx+16] - pcmpeqd mm3, [edx+24] - pand mm0, mm1 - pand mm0, mm2 - pand mm0, mm3 - pmovmskb eax, mm0 - sub ecx, 32 - add esi, 32 - add edx, 32 - - // check if eq - cmp eax, 0xff - je Done4 - mov eax, 1 - jmp End - -Done4: - cmp ecx, 24 - jne Done2 - movq mm0, [esi] - movq mm1, [esi+8] - movq mm2, [esi+16] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pcmpeqd mm2, [edx+16] - pand mm0, mm1 - pand mm0, mm2 - pmovmskb eax, mm0 - - // check if eq - cmp eax, 0xff - setne al - jmp End - -Done2: - cmp ecx, 16 - jne Done1 - - movq mm0, [esi] - movq mm1, [esi+8] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pand mm0, mm1 - pmovmskb eax, mm0 - - // check if eq - cmp eax, 0xff - setne al - jmp End - -Done1: - cmp ecx, 8 - jne Done - - mov eax, [esi] - mov esi, [esi+4] - cmp eax, [edx] - je Next - mov eax, 1 - jmp End - -Next: - cmp esi, [edx+4] - setne al - jmp End - -Done: - xor eax, eax - -End: - pop esi - emms - } -} - -#else // _MSC_VER -// assume gcc or mingw or win x64 - -#include -#include - -void * memcpy_amd(void *dest, const void *src, size_t n) -{ -memcpy(dest, src, n); -return dest; -} - - -#endif - -} +/****************************************************************************** + + Copyright (c) 2001 Advanced Micro Devices, Inc. + + LIMITATION OF LIABILITY: THE MATERIALS ARE PROVIDED *AS IS* WITHOUT ANY + EXPRESS OR IMPLIED WARRANTY OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, + NONINFRINGEMENT OF THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY + PARTICULAR PURPOSE. IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY + DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, + BUSINESS INTERRUPTION, LOSS OF INFORMATION) ARISING OUT OF THE USE OF OR + INABILITY TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY + OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE EXCLUSION OR LIMITATION + OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY + NOT APPLY TO YOU. + + AMD does not assume any responsibility for any errors which may appear in the + Materials nor any responsibility to support or update the Materials. AMD retains + the right to make changes to its test specifications at any time, without notice. + + NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any + further information, software, technical information, know-how, or show-how + available to you. + + So that all may benefit from your experience, please report any problems + or suggestions about this software to 3dsdk.support@amd.com + + AMD Developer Technologies, M/S 585 + Advanced Micro Devices, Inc. + 5900 E. Ben White Blvd. + Austin, TX 78741 + 3dsdk.support@amd.com +******************************************************************************/ + +#include + +/***************************************************************************** +MEMCPY_AMD.CPP +******************************************************************************/ + +// Very optimized memcpy() routine for AMD Athlon and Duron family. +// This code uses any of FOUR different basic copy methods, depending +// on the transfer size. +// NOTE: Since this code uses MOVNTQ (also known as "Non-Temporal MOV" or +// "Streaming Store"), and also uses the software prefetch instructions, +// be sure you're running on Athlon/Duron or other recent CPU before calling! + +#define TINY_BLOCK_COPY 64 // upper limit for movsd type copy +// The smallest copy uses the X86 "movsd" instruction, in an optimized +// form which is an "unrolled loop". + +#define IN_CACHE_COPY 2 * 1024 // upper limit for movq/movq copy w/SW prefetch +// Next is a copy that uses the MMX registers to copy 8 bytes at a time, +// also using the "unrolled loop" optimization. This code uses +// the software prefetch instruction to get the data into the cache. + +#define UNCACHED_COPY 4 * 1024 // upper limit for movq/movntq w/SW prefetch +// For larger blocks, which will spill beyond the cache, it's faster to +// use the Streaming Store instruction MOVNTQ. This write instruction +// bypasses the cache and writes straight to main memory. This code also +// uses the software prefetch instruction to pre-read the data. +// USE 64 * 1024 FOR THIS VALUE IF YOU'RE ALWAYS FILLING A "CLEAN CACHE" + +#define BLOCK_PREFETCH_COPY infinity // no limit for movq/movntq w/block prefetch +#define CACHEBLOCK 80h // number of 64-byte blocks (cache lines) for block prefetch +// For the largest size blocks, a special technique called Block Prefetch +// can be used to accelerate the read operations. Block Prefetch reads +// one address per cache line, for a series of cache lines, in a short loop. +// This is faster than using software prefetch. The technique is great for +// getting maximum read bandwidth, especially in DDR memory systems. + +//#include + +// Inline assembly syntax for use with Visual C++ +#ifdef _WIN32 +#include +#endif + +extern "C" { +#include "PS2Etypes.h" + +#if defined(_MSC_VER) && !defined(__x86_64__) + +void * memcpy_amd(void *dest, const void *src, size_t n) +{ + __asm { + mov ecx, [n] ; number of bytes to copy + mov edi, [dest] ; destination + mov esi, [src] ; source + mov ebx, ecx ; keep a copy of count + + cld + cmp ecx, TINY_BLOCK_COPY + jb $memcpy_ic_3 ; tiny? skip mmx copy + + cmp ecx, 32*1024 ; don't align between 32k-64k because + jbe $memcpy_do_align ; it appears to be slower + cmp ecx, 64*1024 + jbe $memcpy_align_done +$memcpy_do_align: + mov ecx, 8 ; a trick that's faster than rep movsb... + sub ecx, edi ; align destination to qword + and ecx, 111b ; get the low bits + sub ebx, ecx ; update copy count + neg ecx ; set up to jump into the array + add ecx, offset $memcpy_align_done + jmp ecx ; jump to array of movsb's + +align 4 + movsb + movsb + movsb + movsb + movsb + movsb + movsb + movsb + +$memcpy_align_done: ; destination is dword aligned + mov ecx, ebx ; number of bytes left to copy + shr ecx, 6 ; get 64-byte block count + jz $memcpy_ic_2 ; finish the last few bytes + + cmp ecx, IN_CACHE_COPY/64 ; too big 4 cache? use uncached copy + jae $memcpy_uc_test + +// This is small block copy that uses the MMX registers to copy 8 bytes +// at a time. It uses the "unrolled loop" optimization, and also uses +// the software prefetch instruction to get the data into the cache. +align 16 +$memcpy_ic_1: ; 64-byte block copies, in-cache copy + + prefetchnta [esi + (200*64/34+192)] ; start reading ahead + + movq mm0, [esi+0] ; read 64 bits + movq mm1, [esi+8] + movq [edi+0], mm0 ; write 64 bits + movq [edi+8], mm1 ; note: the normal movq writes the + movq mm2, [esi+16] ; data to cache; a cache line will be + movq mm3, [esi+24] ; allocated as needed, to store the data + movq [edi+16], mm2 + movq [edi+24], mm3 + movq mm0, [esi+32] + movq mm1, [esi+40] + movq [edi+32], mm0 + movq [edi+40], mm1 + movq mm2, [esi+48] + movq mm3, [esi+56] + movq [edi+48], mm2 + movq [edi+56], mm3 + + add esi, 64 ; update source pointer + add edi, 64 ; update destination pointer + dec ecx ; count down + jnz $memcpy_ic_1 ; last 64-byte block? + +$memcpy_ic_2: + mov ecx, ebx ; has valid low 6 bits of the byte count +$memcpy_ic_3: + shr ecx, 2 ; dword count + and ecx, 1111b ; only look at the "remainder" bits + neg ecx ; set up to jump into the array + add ecx, offset $memcpy_last_few + jmp ecx ; jump to array of movsd's + +$memcpy_uc_test: + cmp ecx, UNCACHED_COPY/64 ; big enough? use block prefetch copy + jae $memcpy_bp_1 + +$memcpy_64_test: + or ecx, ecx ; tail end of block prefetch will jump here + jz $memcpy_ic_2 ; no more 64-byte blocks left + +// For larger blocks, which will spill beyond the cache, it's faster to +// use the Streaming Store instruction MOVNTQ. This write instruction +// bypasses the cache and writes straight to main memory. This code also +// uses the software prefetch instruction to pre-read the data. +align 16 +$memcpy_uc_1: ; 64-byte blocks, uncached copy + + prefetchnta [esi + (200*64/34+192)] ; start reading ahead + + movq mm0,[esi+0] ; read 64 bits + add edi,64 ; update destination pointer + movq mm1,[esi+8] + add esi,64 ; update source pointer + movq mm2,[esi-48] + movntq [edi-64], mm0 ; write 64 bits, bypassing the cache + movq mm0,[esi-40] ; note: movntq also prevents the CPU + movntq [edi-56], mm1 ; from READING the destination address + movq mm1,[esi-32] ; into the cache, only to be over-written + movntq [edi-48], mm2 ; so that also helps performance + movq mm2,[esi-24] + movntq [edi-40], mm0 + movq mm0,[esi-16] + movntq [edi-32], mm1 + movq mm1,[esi-8] + movntq [edi-24], mm2 + movntq [edi-16], mm0 + dec ecx + movntq [edi-8], mm1 + jnz $memcpy_uc_1 ; last 64-byte block? + + jmp $memcpy_ic_2 ; almost done + +// For the largest size blocks, a special technique called Block Prefetch +// can be used to accelerate the read operations. Block Prefetch reads +// one address per cache line, for a series of cache lines, in a short loop. +// This is faster than using software prefetch. The technique is great for +// getting maximum read bandwidth, especially in DDR memory systems. +$memcpy_bp_1: ; large blocks, block prefetch copy + + cmp ecx, CACHEBLOCK ; big enough to run another prefetch loop? + jl $memcpy_64_test ; no, back to regular uncached copy + + mov eax, CACHEBLOCK / 2 ; block prefetch loop, unrolled 2X + add esi, CACHEBLOCK * 64 ; move to the top of the block +align 16 +$memcpy_bp_2: + mov edx, [esi-64] ; grab one address per cache line + mov edx, [esi-128] ; grab one address per cache line + sub esi, 128 ; go reverse order to suppress HW prefetcher + dec eax ; count down the cache lines + jnz $memcpy_bp_2 ; keep grabbing more lines into cache + + mov eax, CACHEBLOCK ; now that it's in cache, do the copy +align 16 +$memcpy_bp_3: + movq mm0, [esi ] ; read 64 bits + movq mm1, [esi+ 8] + movq mm2, [esi+16] + movq mm3, [esi+24] + movq mm4, [esi+32] + movq mm5, [esi+40] + movq mm6, [esi+48] + movq mm7, [esi+56] + add esi, 64 ; update source pointer + movntq [edi ], mm0 ; write 64 bits, bypassing cache + movntq [edi+ 8], mm1 ; note: movntq also prevents the CPU + movntq [edi+16], mm2 ; from READING the destination address + movntq [edi+24], mm3 ; into the cache, only to be over-written, + movntq [edi+32], mm4 ; so that also helps performance + movntq [edi+40], mm5 + movntq [edi+48], mm6 + movntq [edi+56], mm7 + add edi, 64 ; update dest pointer + + dec eax ; count down + + jnz $memcpy_bp_3 ; keep copying + sub ecx, CACHEBLOCK ; update the 64-byte block count + jmp $memcpy_bp_1 ; keep processing chunks + +// The smallest copy uses the X86 "movsd" instruction, in an optimized +// form which is an "unrolled loop". Then it handles the last few bytes. +align 4 + movsd + movsd ; perform last 1-15 dword copies + movsd + movsd + movsd + movsd + movsd + movsd + movsd + movsd ; perform last 1-7 dword copies + movsd + movsd + movsd + movsd + movsd + movsd + +$memcpy_last_few: ; dword aligned from before movsd's + mov ecx, ebx ; has valid low 2 bits of the byte count + and ecx, 11b ; the last few cows must come home + jz $memcpy_final ; no more, let's leave + rep movsb ; the last 1, 2, or 3 bytes + +$memcpy_final: + emms ; clean up the MMX state + sfence ; flush the write buffer + mov eax, [dest] ; ret value = destination pointer + + } +} + +// mmx memcpy implementation, size has to be a multiple of 8 +// returns 0 is equal, nonzero value if not equal +// ~10 times faster than standard memcmp +// (zerofrog) +u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) +{ + assert( (cmpsize&7) == 0 ); + + __asm { +push esi + mov ecx, cmpsize + mov edx, src1 + mov esi, src2 + + cmp ecx, 32 + jl Done4 + + // custom test first 8 to make sure things are ok + movq mm0, [esi] + movq mm1, [esi+8] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pand mm0, mm1 + movq mm2, [esi+16] + pmovmskb eax, mm0 + movq mm3, [esi+24] + + // check if eq + cmp eax, 0xff + je NextComp + mov eax, 1 + jmp End + +NextComp: + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm2, mm3 + pmovmskb eax, mm2 + + sub ecx, 32 + add esi, 32 + add edx, 32 + + // check if eq + cmp eax, 0xff + je ContinueTest + mov eax, 1 + jmp End + + cmp ecx, 64 + jl Done8 + +Cmp8: + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + movq mm3, [esi+24] + movq mm4, [esi+32] + movq mm5, [esi+40] + movq mm6, [esi+48] + movq mm7, [esi+56] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm0, mm1 + pcmpeqd mm4, [edx+32] + pand mm0, mm2 + pcmpeqd mm5, [edx+40] + pand mm0, mm3 + pcmpeqd mm6, [edx+48] + pand mm0, mm4 + pcmpeqd mm7, [edx+56] + pand mm0, mm5 + pand mm0, mm6 + pand mm0, mm7 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + je Continue + mov eax, 1 + jmp End + +Continue: + sub ecx, 64 + add esi, 64 + add edx, 64 +ContinueTest: + cmp ecx, 64 + jge Cmp8 + +Done8: + test ecx, 0x20 + jz Done4 + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + movq mm3, [esi+24] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm0, mm1 + pand mm0, mm2 + pand mm0, mm3 + pmovmskb eax, mm0 + sub ecx, 32 + add esi, 32 + add edx, 32 + + // check if eq + cmp eax, 0xff + je Done4 + mov eax, 1 + jmp End + +Done4: + cmp ecx, 24 + jne Done2 + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pand mm0, mm1 + pand mm0, mm2 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + setne al + jmp End + +Done2: + cmp ecx, 16 + jne Done1 + + movq mm0, [esi] + movq mm1, [esi+8] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pand mm0, mm1 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + setne al + jmp End + +Done1: + cmp ecx, 8 + jne Done + + mov eax, [esi] + mov esi, [esi+4] + cmp eax, [edx] + je Next + mov eax, 1 + jmp End + +Next: + cmp esi, [edx+4] + setne al + jmp End + +Done: + xor eax, eax + +End: + pop esi + emms + } +} + +#else // _MSC_VER +// assume gcc or mingw or win x64 + +#include +#include + +void * memcpy_amd(void *dest, const void *src, size_t n) +{ +memcpy(dest, src, n); +return dest; +} + + +#endif + +} diff --git a/plugins/zerogs/opengl/rasterfont.cpp b/plugins/zerogs/opengl/rasterfont.cpp index 8e217e5205..243f4e09f6 100644 --- a/plugins/zerogs/opengl/rasterfont.cpp +++ b/plugins/zerogs/opengl/rasterfont.cpp @@ -1,147 +1,147 @@ - -#ifdef _WIN32 -#include -#endif - -#include -#include - -#include "rasterfont.h" -// globals - -GLubyte rasters[][13] = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36}, - {0x00, 0x00, 0x00, 0x66, 0x66, 0xff, 0x66, 0x66, 0xff, 0x66, 0x66, 0x00, 0x00}, - {0x00, 0x00, 0x18, 0x7e, 0xff, 0x1b, 0x1f, 0x7e, 0xf8, 0xd8, 0xff, 0x7e, 0x18}, - {0x00, 0x00, 0x0e, 0x1b, 0xdb, 0x6e, 0x30, 0x18, 0x0c, 0x76, 0xdb, 0xd8, 0x70}, - {0x00, 0x00, 0x7f, 0xc6, 0xcf, 0xd8, 0x70, 0x70, 0xd8, 0xcc, 0xcc, 0x6c, 0x38}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1c, 0x0c, 0x0e}, - {0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c}, - {0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30}, - {0x00, 0x00, 0x00, 0x00, 0x99, 0x5a, 0x3c, 0xff, 0x3c, 0x5a, 0x99, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00}, - {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x03}, - {0x00, 0x00, 0x3c, 0x66, 0xc3, 0xe3, 0xf3, 0xdb, 0xcf, 0xc7, 0xc3, 0x66, 0x3c}, - {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xe7, 0x7e}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0x07, 0x03, 0x03, 0xe7, 0x7e}, - {0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x03, 0x03, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x03, 0x7f, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, - {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06}, - {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60}, - {0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x06, 0x03, 0xc3, 0xc3, 0x7e}, - {0x00, 0x00, 0x3f, 0x60, 0xcf, 0xdb, 0xd3, 0xdd, 0xc3, 0x7e, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18}, - {0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, - {0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, - {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e}, - {0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06}, - {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3}, - {0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e}, - {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, - {0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c}, - {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, - {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff}, - {0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c}, - {0x00, 0x03, 0x03, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60}, - {0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18}, - {0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x70}, - {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0x7f, 0x03, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03}, - {0x00, 0x00, 0x7f, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x33, 0x1e}, - {0x7e, 0xc3, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00}, - {0x38, 0x6c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x00}, - {0x00, 0x00, 0xc6, 0xcc, 0xf8, 0xf0, 0xd8, 0xcc, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78}, - {0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xfe, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00}, - {0xc0, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00}, - {0x03, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xfe, 0x03, 0x03, 0x7e, 0xc0, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00}, - {0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0xc0, 0x60, 0x60, 0x30, 0x18, 0x3c, 0x66, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xff, 0x60, 0x30, 0x18, 0x0c, 0x06, 0xff, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x0f, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x0f}, - {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, - {0x00, 0x00, 0xf0, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0xf0}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00} -}; - -RasterFont::RasterFont() -{ - // set GL modes - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - // create the raster font - fontOffset = glGenLists (128); - for (int i = 32; i < 127; i++) { - glNewList(i+fontOffset, GL_COMPILE); - glBitmap(8, 13, 0.0f, 2.0f, 10.0f, 0.0f, rasters[i-32]); - glEndList(); - } -} - -RasterFont::~RasterFont() -{ - glDeleteLists(fontOffset, 128); -} - -void RasterFont::printString(const char *s, double x, double y, double z) -{ - // go to the right spot - glRasterPos3d(x, y, z); - - glPushAttrib (GL_LIST_BIT); - glListBase(fontOffset); - glCallLists(strlen(s), GL_UNSIGNED_BYTE, (GLubyte *) s); - glPopAttrib (); -} - -void RasterFont::printCenteredString(const char *s, double y, int screen_width, double z) -{ - int length = strlen(s); - int x = int(screen_width/2.0 - (length/2.0)*char_width); - - printString(s, x, y, z); -} - + +#ifdef _WIN32 +#include +#endif + +#include +#include + +#include "rasterfont.h" +// globals + +GLubyte rasters[][13] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36}, + {0x00, 0x00, 0x00, 0x66, 0x66, 0xff, 0x66, 0x66, 0xff, 0x66, 0x66, 0x00, 0x00}, + {0x00, 0x00, 0x18, 0x7e, 0xff, 0x1b, 0x1f, 0x7e, 0xf8, 0xd8, 0xff, 0x7e, 0x18}, + {0x00, 0x00, 0x0e, 0x1b, 0xdb, 0x6e, 0x30, 0x18, 0x0c, 0x76, 0xdb, 0xd8, 0x70}, + {0x00, 0x00, 0x7f, 0xc6, 0xcf, 0xd8, 0x70, 0x70, 0xd8, 0xcc, 0xcc, 0x6c, 0x38}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1c, 0x0c, 0x0e}, + {0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c}, + {0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30}, + {0x00, 0x00, 0x00, 0x00, 0x99, 0x5a, 0x3c, 0xff, 0x3c, 0x5a, 0x99, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00}, + {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x03}, + {0x00, 0x00, 0x3c, 0x66, 0xc3, 0xe3, 0xf3, 0xdb, 0xcf, 0xc7, 0xc3, 0x66, 0x3c}, + {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xe7, 0x7e}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0x07, 0x03, 0x03, 0xe7, 0x7e}, + {0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x03, 0x03, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x03, 0x7f, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, + {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06}, + {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60}, + {0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x06, 0x03, 0xc3, 0xc3, 0x7e}, + {0x00, 0x00, 0x3f, 0x60, 0xcf, 0xdb, 0xd3, 0xdd, 0xc3, 0x7e, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18}, + {0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, + {0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, + {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e}, + {0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06}, + {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3}, + {0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e}, + {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, + {0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c}, + {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff}, + {0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c}, + {0x00, 0x03, 0x03, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60}, + {0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18}, + {0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x70}, + {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0x7f, 0x03, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03}, + {0x00, 0x00, 0x7f, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x33, 0x1e}, + {0x7e, 0xc3, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00}, + {0x38, 0x6c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x00}, + {0x00, 0x00, 0xc6, 0xcc, 0xf8, 0xf0, 0xd8, 0xcc, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78}, + {0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xfe, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00}, + {0xc0, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00}, + {0x03, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xfe, 0x03, 0x03, 0x7e, 0xc0, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00}, + {0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0xc0, 0x60, 0x60, 0x30, 0x18, 0x3c, 0x66, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xff, 0x60, 0x30, 0x18, 0x0c, 0x06, 0xff, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x0f, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x0f}, + {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, + {0x00, 0x00, 0xf0, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0xf0}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00} +}; + +RasterFont::RasterFont() +{ + // set GL modes + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + // create the raster font + fontOffset = glGenLists (128); + for (int i = 32; i < 127; i++) { + glNewList(i+fontOffset, GL_COMPILE); + glBitmap(8, 13, 0.0f, 2.0f, 10.0f, 0.0f, rasters[i-32]); + glEndList(); + } +} + +RasterFont::~RasterFont() +{ + glDeleteLists(fontOffset, 128); +} + +void RasterFont::printString(const char *s, double x, double y, double z) +{ + // go to the right spot + glRasterPos3d(x, y, z); + + glPushAttrib (GL_LIST_BIT); + glListBase(fontOffset); + glCallLists(strlen(s), GL_UNSIGNED_BYTE, (GLubyte *) s); + glPopAttrib (); +} + +void RasterFont::printCenteredString(const char *s, double y, int screen_width, double z) +{ + int length = strlen(s); + int x = int(screen_width/2.0 - (length/2.0)*char_width); + + printString(s, x, y, z); +} + diff --git a/plugins/zerogs/opengl/rasterfont.h b/plugins/zerogs/opengl/rasterfont.h index 2aaf8ba98f..4a0c39a319 100644 --- a/plugins/zerogs/opengl/rasterfont.h +++ b/plugins/zerogs/opengl/rasterfont.h @@ -1,22 +1,22 @@ -#ifndef RasterFont_Header -#define RasterFont_Header - -class RasterFont { -protected: - int fontOffset; - -public: - RasterFont(); - ~RasterFont(void); - static int debug; - - // some useful constants - enum {char_width = 10}; - enum {char_height = 15}; - - // and the happy helper functions - void printString(const char *s, double x, double y, double z=0.0); - void printCenteredString(const char *s, double y, int screen_width, double z=0.0); -}; - -#endif +#ifndef RasterFont_Header +#define RasterFont_Header + +class RasterFont { +protected: + int fontOffset; + +public: + RasterFont(); + ~RasterFont(void); + static int debug; + + // some useful constants + enum {char_width = 10}; + enum {char_height = 15}; + + // and the happy helper functions + void printString(const char *s, double x, double y, double z=0.0); + void printCenteredString(const char *s, double y, int screen_width, double z=0.0); +}; + +#endif diff --git a/plugins/zerogs/opengl/targets.cpp b/plugins/zerogs/opengl/targets.cpp index c5e3489875..d8c11e5b9a 100644 --- a/plugins/zerogs/opengl/targets.cpp +++ b/plugins/zerogs/opengl/targets.cpp @@ -1,3547 +1,3547 @@ -/* ZeroGS KOSMOS - * Copyright (C) 2005-2006 zerofrog@gmail.com - * - * 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 "GS.h" -#include -#include - -#include - -#include -#include -#include -#include - -#include "Mem.h" -#include "x86.h" -#include "zerogs.h" - -#include "targets.h" - -const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); - -extern int g_GameSettings; -using namespace ZeroGS; -extern int g_TransferredToGPU; -extern BOOL g_bIsLost; -extern BOOL g_bUpdateStencil; -extern u32 s_uFramebuffer; - -#ifdef RELEASE_TO_PUBLIC -#define INC_RESOLVE() -#else -#define INC_RESOLVE() ++g_nResolve -extern u32 g_nResolve; -extern BOOL g_bSaveTrans; -#endif - -namespace ZeroGS { - CRenderTargetMngr s_RTs, s_DepthRTs; - CBitwiseTextureMngr s_BitwiseTextures; - CMemoryTargetMngr g_MemTargs; - - extern u8 s_AAx, s_AAy; - extern Vector g_vdepth; - extern int icurctx; - - extern VERTEXSHADER pvsBitBlt; - extern FRAGMENTSHADER ppsBitBlt[2], ppsBitBltDepth, ppsOne; - extern FRAGMENTSHADER ppsBaseTexture, ppsConvert16to32, ppsConvert32to16; - extern GLuint vboRect; -} - -extern u32 s_ptexCurSet[2]; -extern u32 ptexBilinearBlocks; -extern u32 ptexConv32to16; -BOOL g_bSaveZUpdate = 0; - -//////////////////// -// Render Targets // -//////////////////// -ZeroGS::CRenderTarget::CRenderTarget() : ptex(0), ptexFeedback(0), psys(NULL) -{ - nUpdateTarg = 0; -} - -ZeroGS::CRenderTarget::~CRenderTarget() -{ - Destroy(); -} - -bool ZeroGS::CRenderTarget::Create(const frameInfo& frame) -{ - Resolve(); - Destroy(); - - lastused = timeGetTime(); - fbp = frame.fbp; - fbw = frame.fbw; - fbh = frame.fbh; - psm = (u8)frame.psm; - fbm = frame.fbm; - - vposxy.x = 2.0f * (1.0f / 8.0f) / (float)fbw; - vposxy.y = 2.0f * (1.0f / 8.0f) / (float)fbh; - vposxy.z = -1-0.5f/fbw; - vposxy.w = -1+0.5f/fbh; - status = 0; - - if( fbw > 0 && fbh > 0 ) { - GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); - - psys = _aligned_malloc( (fbh<= fbp ); - - dy = ((256/bpp)*(fbplocal-fbp)) / fbw; - - v.x = vposxy.x; - v.y = vposxy.y; - v.z = vposxy.z; - v.w = vposxy.w - dy*2.0f/(float)fbh; - cgGLSetParameter4fv(g_vparamPosXY[context], v); - } - else - cgGLSetParameter4fv(g_vparamPosXY[context], vposxy); - - // set render states - scissorrect.x = scissor.x0>>3; - scissorrect.y = (scissor.y0>>3) + dy; - scissorrect.w = (scissor.x1>>3)+1; - scissorrect.h = (scissor.y1>>3)+1+dy; - scissorrect.w = min(scissorrect.w, fbw) - scissorrect.x; - scissorrect.h = min(scissorrect.h, fbh) - scissorrect.y; - - scissorrect.x <<= s_AAx; - scissorrect.y <<= s_AAy; - scissorrect.w <<= s_AAx; - scissorrect.h <<= s_AAy; -} - -void ZeroGS::CRenderTarget::SetViewport() -{ - glViewport(0, 0, fbw< 10 || (g_GameSettings&GAME_NOTARGETRESOLVE) ) { - // don't resolve if depths aren't used - status = TS_Resolved; - return; - } - - glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptex); - GL_REPORT_ERRORD(); - //glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), GetRenderFormat()==RFT_float16?GL_FLOAT:GL_UNSIGNED_BYTE, psys); - glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, GL_UNSIGNED_BYTE, psys); - GL_REPORT_ERRORD(); - -#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) - if( g_bSaveResolved ) { - SaveTexture("resolved.tga", GL_TEXTURE_RECTANGLE_NV, ptex, fbw< start ); // make sure it at least intersects - - if( ptex != 0 && !(status&TS_Resolved) && !(status&TS_NeedUpdate) ) { - - // flush if necessary - if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); - if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); - -#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) - if( g_bSaveResolved ) { - SaveTexture("resolved.tga", GL_TEXTURE_RECTANGLE_NV, ptex, fbw<>6); - - // in now way should data be overwritten!, instead resolve less - if( endrange < end ) { - // round down to nearest block and scanline - resolveheight = ((endrange-start)/(0x2000*(fbw>>6))) * blockheight; - if( resolveheight <= 32 ) { - status = TS_Resolved; - return; - } - } - else if( startrange > start ) { - // round up to nearest block and scanline - resolvefbp = startrange + scanlinewidth - 1; - resolvefbp -= resolvefbp % scanlinewidth; - - resolveheight = fbh-((resolvefbp-fbp)*blockheight/scanlinewidth); - if( resolveheight <= 64 ) { // this is a total hack, but kh doesn't resolve now - status = TS_Resolved; - return; - } - - resolvefbp >>= 8; - } - - glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptex); - //glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), GetRenderFormat()==RFT_float16?GL_FLOAT:GL_UNSIGNED_BYTE, psys); - glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, GL_UNSIGNED_BYTE, psys); - GL_REPORT_ERRORD(); - - u8* pbits = (u8*)psys; - u32 Pitch = (fbw<SetDepthStencilSurface(psurfDepth); - ResetRenderTarget(1); - SetRenderTarget(0); - assert( pdepth != NULL ); - ((CDepthTarget*)pdepth)->SetDepthStencilSurface(); - - Vector v = Vector(1,-1,-0.5f/(float)(fbw<second == this ) { - ERROR_LOG("updating self"); - nUpdateTarg = 0; - } - } - else if( ittarg->second == this ) { - ERROR_LOG("updating self"); - nUpdateTarg = 0; - } - } - - SetViewport(); - - if( nUpdateTarg ) { - - cgGLSetTextureParameter(ppsBaseTexture.sFinal, ittarg->second->ptex); - cgGLEnableTextureParameter(ppsBaseTexture.sFinal); - - //assert( ittarg->second->fbw == fbw ); - int offset = (fbp-ittarg->second->fbp)*64/fbw; - if( psm & 2 ) // 16 bit - offset *= 2; - - v.x = (float)(fbw << s_AAx); - v.y = (float)(fbh << s_AAy); - v.z = 0.25f; - v.w = (float)(offset << s_AAy) + 0.25f; - cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); - - v.x = v.y = v.z = v.w = 1; - cgGLSetParameter4fv(ppsBaseTexture.sOneColor, v); - - SETPIXELSHADER(ppsBaseTexture.prog); - nUpdateTarg = 0; - } - else { - // align the rect to the nearest page - // note that fbp is always aligned on page boundaries - tex0Info texframe; - texframe.tbp0 = fbp; - texframe.tbw = fbw; - texframe.tw = fbw; - texframe.th = fbh; - texframe.psm = psm; - CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); - - // write color and zero out stencil buf, always 0 context! - // force bilinear if using AA - SetTexVariablesInt(0, (s_AAx || s_AAy)?2:0, texframe, pmemtarg, &ppsBitBlt[s_AAx], 1); - cgGLSetTextureParameter(ppsBitBlt[s_AAx].sMemory, pmemtarg->ptex->tex); - cgGLEnableTextureParameter(ppsBitBlt[s_AAx].sMemory); - - v = Vector(1,1,0,0); - cgGLSetParameter4fv(pvsBitBlt.sBitBltTex, v); - - v.x = 1; - v.y = 2; - cgGLSetParameter4fv(ppsBitBlt[s_AAx].sOneColor, v); - - assert( ptex != 0 ); - - if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - if( ZeroGS::IsWriteDestAlphaTest() ) { - glEnable(GL_STENCIL_TEST); - glStencilFunc(GL_ALWAYS, 0, 0xff); - glStencilMask(0xff); - glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO); - } - - // render with an AA shader if possible (bilinearly interpolates data) - //cgGLLoadProgram(ppsBitBlt[s_AAx].prog); - SETPIXELSHADER(ppsBitBlt[s_AAx].prog); - } - - SETVERTEXSHADER(pvsBitBlt.prog); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - // fill stencil buf only - if( ZeroGS::IsWriteDestAlphaTest() && !(g_GameSettings&GAME_NOSTENCIL)) { - glColorMask(0,0,0,0); - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GEQUAL, 1); - - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - glStencilFunc(GL_ALWAYS, 1, 0xff); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glColorMask(1,1,1,1); - } - - glEnable(GL_SCISSOR_TEST); - - if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - if( conf.mrtdepth && pdepth != NULL && ZeroGS::IsWriteDepth() ) - pdepth->SetRenderTarget(1); - - status = TS_Resolved; - - // reset since settings changed - vb[0].bVarsTexSync = 0; - ZeroGS::ResetAlphaVariables(); -} - -void ZeroGS::CRenderTarget::ConvertTo32() -{ - u32 ptexConv; - - // create new target - glGenTextures(1, &ptexConv); - glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexConv); - glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), fbw<= 0 ) { - // reset since settings changed - vb[icurctx].bVarsTexSync = 0; - vb[icurctx].bVarsSetTarg = 0; - } - vb[0].bVarsTexSync = 0; -} - -void ZeroGS::CRenderTarget::ConvertTo16() -{ - u32 ptexConv; - - // create new target - glGenTextures(1, &ptexConv); - glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexConv); - glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), fbw<Create(frame); -// s_DepthRTs.mapDummyTargs[(fbw<<16)|fbh] = pnewdepth; -// } -// else pnewdepth = (CDepthTarget*)itdepth->second; -// -// assert( pnewdepth != NULL ); -// pd3dDevice->SetDepthStencilSurface(pnewdepth->pdepth); - - SetViewport(); - - if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - // render with an AA shader if possible (bilinearly interpolates data) - SETVERTEXSHADER(pvsBitBlt.prog); - SETPIXELSHADER(ppsConvert32to16.prog); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - -#ifdef _DEBUG - //g_bSaveZUpdate = 1; - if( g_bSaveZUpdate ) { - SaveTexture("tex1.tga", GL_TEXTURE_RECTANGLE_NV, ptexConv, fbw<= 0 ) { - // reset since settings changed - vb[icurctx].bVarsTexSync = 0; - vb[icurctx].bVarsSetTarg = 0; - } - vb[0].bVarsTexSync = 0; -} - -void ZeroGS::CRenderTarget::_CreateFeedback() -{ - if( ptexFeedback == 0 ) { - // create - glGenTextures(1, &ptexFeedback); - glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexFeedback); - glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), fbw<= 0 ) { - // reset since settings changed - vb[icurctx].bVarsTexSync = 0; - } - - assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); -} - -void ZeroGS::CRenderTarget::SetRenderTarget(int targ) -{ - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+targ, GL_TEXTURE_RECTANGLE_NV, ptex, 0 ); - //assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); -} - -ZeroGS::CDepthTarget::CDepthTarget() : CRenderTarget(), pdepth(0), pstencil(0), icount(0) {} - -ZeroGS::CDepthTarget::~CDepthTarget() -{ - Destroy(); -} - -bool ZeroGS::CDepthTarget::Create(const frameInfo& frame) -{ - if( !CRenderTarget::Create(frame) ) - return false; - - if( psm == 0x31 ) fbm = 0xff000000; - else fbm = 0; - - assert( glGetError() == GL_NO_ERROR ); - - glGenRenderbuffersEXT( 1, &pdepth ); - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, pdepth); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, fbw< 0 if depth is used - -void ZeroGS::CDepthTarget::Resolve() -{ - if( g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && ZeroGS::IsWriteDepth() && !(g_GameSettings&GAME_NODEPTHRESOLVE) ) - CRenderTarget::Resolve(); - else { - // flush if necessary - if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); - if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); - - if( !(status & TS_Virtual) ) - status |= TS_Resolved; - } - - if( !(status&TS_Virtual) ) { - ZeroGS::SetWriteDepth(); - } -} - -void ZeroGS::CDepthTarget::Resolve(int startrange, int endrange) -{ - if( g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && ZeroGS::IsWriteDepth() ) CRenderTarget::Resolve(startrange, endrange); - else { - // flush if necessary - if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); - if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); - - if( !(status & TS_Virtual) ) - status |= TS_Resolved; - } - - if( !(status&TS_Virtual) ) { - ZeroGS::SetWriteDepth(); - } -} - -extern int g_nDepthUpdateCount; - -void ZeroGS::CDepthTarget::Update(int context, ZeroGS::CRenderTarget* prndr) -{ - assert( !(status & TS_Virtual) ); - - // align the rect to the nearest page - // note that fbp is always aligned on page boundaries - tex0Info texframe; - texframe.tbp0 = fbp; - texframe.tbw = fbw; - texframe.tw = fbw; - texframe.th = fbh; - texframe.psm = psm; - CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); - - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - glDisable(GL_ALPHA_TEST); - glEnable(GL_DEPTH_TEST); - glDepthMask(1); - glDisable(GL_STENCIL_TEST); - glDepthFunc(GL_ALWAYS); - - // write color and zero out stencil buf, always 0 context! - SetTexVariablesInt(0, 0, texframe, pmemtarg, &ppsBitBltDepth, 1); - cgGLSetTextureParameter(ppsBitBltDepth.sMemory, pmemtarg->ptex->tex); - cgGLEnableTextureParameter(ppsBaseTexture.sFinal); - - Vector v = Vector(1,-1,0.5f/(float)fbw,-0.5f/(float)fbh); - cgGLSetParameter4fv(pvsBitBlt.sBitBltTex, v); - - v.z = v.w = 0; - v *= 1/32767.0f; - cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); - - v.x = 1; - v.y = 2; - v.z = (psm&3)==2?1.0f:0.0f; - v.w = g_filog32; - cgGLSetParameter4fv(ppsBitBltDepth.sOneColor, v); - - Vector vdepth = ((255.0f/256.0f)*g_vdepth); - if( psm == PSMT24Z ) vdepth.w = 0; - else if( psm != PSMT32Z ) { vdepth.z = vdepth.w = 0; } - assert( ppsBitBltDepth.sBitBltZ != 0 ); - cgGLSetParameter4fv(ppsBitBltDepth.sBitBltZ, ((255.0f/256.0f)*vdepth)); - - assert( pdepth != 0 ); - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_NV, ptex, 0 ); - SetDepthStencilSurface(); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_NV, 0, 0 ); - GLenum buffer = GL_COLOR_ATTACHMENT0_EXT; - if( glDrawBuffers != NULL ) - glDrawBuffers(1, &buffer); - int stat = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); - - SetViewport(); - if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - glBindBuffer(GL_ARRAY_BUFFER, vboRect); - SET_STREAM(); - - SETVERTEXSHADER(pvsBitBlt.prog); - SETPIXELSHADER(ppsBitBltDepth.prog); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - status = TS_Resolved; - - if( !ZeroGS::IsWriteDepth() ) { - ResetRenderTarget(1); - } - - if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glEnable(GL_SCISSOR_TEST); - -#ifdef _DEBUG - if( g_bSaveZUpdate ) { - SaveTex(&texframe, 1); - SaveTexture("frame1.tga", GL_TEXTURE_RECTANGLE_NV, ptex, fbw<second; - mapTargets.clear(); - for(MAPTARGETS::iterator it = mapDummyTargs.begin(); it != mapDummyTargs.end(); ++it) - delete it->second; - mapDummyTargs.clear(); -} - -void ZeroGS::CRenderTargetMngr::DestroyAllTargs(int start, int end, int fbw) -{ - for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end();) { - if( it->second->start < end && start < it->second->end ) { - // if is depth, only resolve if fbw is the same - if( !it->second->IsDepth() ) { - // only resolve if the widths are the same or it->second has bit outside the range - // shadow of colossus swaps between fbw=256,fbh=256 and fbw=512,fbh=448. This kills the game if doing || it->second->end > end - - // kh hack, sometimes kh movies do this to clear the target, so have a static count that periodically checks end - static int count = 0; - - if( it->second->fbw == fbw || (it->second->fbw != fbw && (it->second->start < start || ((count++&0xf)?0:it->second->end > end) )) ) - it->second->Resolve(); - else { - if( vb[0].prndr == it->second || vb[0].pdepth == it->second ) Flush(0); - if( vb[1].prndr == it->second || vb[1].pdepth == it->second ) Flush(1); - - it->second->status |= CRenderTarget::TS_Resolved; - } - } - else { - if( it->second->fbw == fbw ) - it->second->Resolve(); - else { - if( vb[0].prndr == it->second || vb[0].pdepth == it->second ) Flush(0); - if( vb[1].prndr == it->second || vb[1].pdepth == it->second ) Flush(1); - - it->second->status |= CRenderTarget::TS_Resolved; - } - } - - for(int i = 0; i < 2; ++i) { - if( it->second == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } - if( it->second == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } - } - - u32 dummykey = (it->second->fbw<<16)|it->second->fbh; - if( mapDummyTargs.find(dummykey) == mapDummyTargs.end() ) { - mapDummyTargs[dummykey] = it->second; - } - else - delete it->second; - mapTargets.erase(it++); - } - else ++it; - } -} - -void ZeroGS::CRenderTargetMngr::DestroyTarg(CRenderTarget* ptarg) -{ - for(int i = 0; i < 2; ++i) { - if( ptarg == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } - if( ptarg == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } - } - - delete ptarg; -} - -void ZeroGS::CRenderTargetMngr::DestroyIntersecting(CRenderTarget* prndr) -{ - assert( prndr != NULL ); - - int start, end; - GetRectMemAddress(start, end, prndr->psm, 0, 0, prndr->fbw, prndr->fbh, prndr->fbp, prndr->fbw); - - for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end();) { - if( it->second != prndr && it->second->start < end && start < it->second->end ) { - it->second->Resolve(); - - for(int i = 0; i < 2; ++i) { - if( it->second == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } - if( it->second == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } - } - - u32 dummykey = (it->second->fbw<<16)|it->second->fbh; - if( mapDummyTargs.find(dummykey) == mapDummyTargs.end() ) { - mapDummyTargs[dummykey] = it->second; - } - else - delete it->second; - - mapTargets.erase(it++); - } - else ++it; - } -} - -CRenderTarget* ZeroGS::CRenderTargetMngr::GetTarg(const frameInfo& frame, u32 opts, int maxposheight) -{ - if( frame.fbw <= 0 || frame.fbh <= 0 ) - return NULL; - - GL_REPORT_ERRORD(); - - u32 key = frame.fbp|(frame.fbw<<16); - MAPTARGETS::iterator it = mapTargets.find(key); - - // only enforce height if frame.fbh <= 0x1c0 - bool bfound = it != mapTargets.end(); - if( bfound ) { - if( opts&TO_StrictHeight ) { - bfound = it->second->fbh == frame.fbh; - } - else { - if( (frame.psm&2)==(it->second->psm&2) && !(g_GameSettings & GAME_FULL16BITRES) ) - bfound = (frame.fbh > 0x1c0 || it->second->fbh >= frame.fbh) && it->second->fbh <= maxposheight; - } - } - - if( !bfound ) { - // might be a virtual target - it = mapTargets.find(key|TARGET_VIRTUAL_KEY); - bfound = it != mapTargets.end() && ((opts&TO_StrictHeight) ? it->second->fbh == frame.fbh : it->second->fbh >= frame.fbh) && it->second->fbh <= maxposheight; - } - - if( bfound ) { - - // can be both 16bit and 32bit - if( (frame.psm&2) != (it->second->psm&2) ) { - // a lot of games do this actually... -#ifdef _DEBUG - WARN_LOG("Really bad formats! %d %d\n", frame.psm, it->second->psm); -#endif -// if( g_GameSettings & GAME_VSSHACK ) { -// if( it->second->psm & 2 ) { -// it->second->status |= CRenderTarget::TS_NeedConvert32; -// it->second->fbh /= 2; -// } -// else { -// it->second->status |= CRenderTarget::TS_NeedConvert16; -// it->second->fbh *= 2; -// } -// } - - // recalc extents - GetRectMemAddress(it->second->start, it->second->end, frame.psm, 0, 0, frame.fbw, it->second->fbh, it->second->fbp, frame.fbw); - } - else { - // certain variables have to be reset every time - if( (it->second->psm&~1) != (frame.psm&~1) ) { -#ifndef RELEASE_TO_PUBLIC - WARN_LOG("bad formats 2: %d %d\n", frame.psm, it->second->psm); -#endif - it->second->psm = frame.psm; - - // recalc extents - GetRectMemAddress(it->second->start, it->second->end, frame.psm, 0, 0, frame.fbw, it->second->fbh, it->second->fbp, frame.fbw); - } - } - - if( it->second->fbm != frame.fbm ) { - //WARN_LOG("bad fbm: 0x%8.8x 0x%8.8x, psm: %d\n", frame.fbm, it->second->fbm, frame.psm); - } - - it->second->fbm &= frame.fbm; - it->second->psm = frame.psm; // have to convert (ffx2) - - if( (it->first & TARGET_VIRTUAL_KEY) && !(opts&TO_Virtual) ) { - // switch - it->second->lastused = timeGetTime(); - return Promote(it->first&~TARGET_VIRTUAL_KEY); - } - - // check if there exists a more recent target that this target could update from - for(MAPTARGETS::iterator itnew = mapTargets.begin(); itnew != mapTargets.end(); ++itnew) { - if( itnew->second != it->second && itnew->second->start <= it->second->start && itnew->second->end >= it->second->end && - itnew->second->lastused > it->second->lastused && !(itnew->second->status & CRenderTarget::TS_NeedUpdate) ) { - - it->second->status |= CRenderTarget::TS_NeedUpdate; - it->second->nUpdateTarg = itnew->first; - break; - } - } - - it->second->lastused = timeGetTime(); - - return it->second; - } - - // NOTE: instead of resolving, if current render targ is completely outside of old, can transfer - // the data like that. - - // have to change, so recreate (find all intersecting targets and Resolve) - u32 besttarg = 0; - - if( !(opts & CRenderTargetMngr::TO_Virtual) ) { - - int start, end; - GetRectMemAddress(start, end, frame.psm, 0, 0, frame.fbw, frame.fbh, frame.fbp, frame.fbw); - - if( !(opts & CRenderTargetMngr::TO_StrictHeight) ) { - - // if there is only one intersecting target and it encompasses the current one, update the new render target with - // its data instead of resolving then updating (ffx2). Do not change the original target. - for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { - if( it->second->start < end && start < it->second->end ) { -// if( g_GameSettings&GAME_FASTUPDATE ) { -// besttarg = it->first; -// //break; -// } -// else { - if( (g_GameSettings&GAME_FASTUPDATE) || (it->second->fbp != frame.fbp && it->second->fbw == frame.fbw) ) { - - if( besttarg != 0 ) { - besttarg = 0; - break; - } - - if( start >= it->second->start && end <= it->second->end ) { - besttarg = it->first; - } - } -// } - } - } - } - - if( besttarg == 0 ) { - // if none found, resolve all - DestroyAllTargs(start, end, frame.fbw); - } - } - - if( mapTargets.size() > 8 ) { - // release some resources - it = GetOldestTarg(mapTargets); - - // if more than 5s passed since target used, destroy - if( timeGetTime()-it->second->lastused > 5000 ) { - delete it->second; - mapTargets.erase(it); - } - } - - if( mapDummyTargs.size() > 8 ) { - it = GetOldestTarg(mapDummyTargs); - - delete it->second; - mapDummyTargs.erase(it); - } - - // first search for the target - CRenderTarget* ptarg = NULL; - - it = mapDummyTargs.find( (frame.fbw<<16)|frame.fbh ); - if( it != mapDummyTargs.end() ) { - ptarg = it->second; - mapDummyTargs.erase(it); - - // restore all setttings - ptarg->psm = frame.psm; - ptarg->fbm = frame.fbm; - ptarg->fbp = frame.fbp; - GetRectMemAddress(ptarg->start, ptarg->end, frame.psm, 0, 0, frame.fbw, frame.fbh, frame.fbp, frame.fbw); - - ptarg->status = CRenderTarget::TS_NeedUpdate; - } - else { - // create anew - ptarg = (opts&TO_DepthBuffer) ? new CDepthTarget() : new CRenderTarget(); - CRenderTargetMngr* pmngrs[2] = { &s_DepthRTs, this == &s_RTs ? &s_RTs : NULL }; - int cur = 0; - - while( !ptarg->Create(frame) ) { - - // destroy unused targets - if( mapDummyTargs.size() > 0 ) { - it = mapDummyTargs.begin(); - delete it->second; - mapDummyTargs.erase(it); - continue; - } - - if( g_MemTargs.listClearedTargets.size() > 0 ) { - g_MemTargs.DestroyCleared(); - continue; - } - else - if( g_MemTargs.listTargets.size() > 32 ) { - g_MemTargs.DestroyOldest(); - continue; - } - - if( pmngrs[cur] == NULL ) { - cur = !cur; - if( pmngrs[cur] == NULL ) { - WARN_LOG("Out of memory!\n"); - delete ptarg; - return NULL; - } - } - - if( pmngrs[cur]->mapTargets.size() == 0 ) - { - pmngrs[cur] = NULL; - cur = !cur; - continue; - } - - it = GetOldestTarg(pmngrs[cur]->mapTargets); - - DestroyTarg(it->second); - pmngrs[cur]->mapTargets.erase(it); - cur = !cur; - } - } - - if( (opts & CRenderTargetMngr::TO_Virtual) ) { - ptarg->status = CRenderTarget::TS_Virtual; - key |= TARGET_VIRTUAL_KEY; - - if( (it = mapTargets.find(key)) != mapTargets.end() ) { - - DestroyTarg(it->second); - it->second = ptarg; - ptarg->nUpdateTarg = besttarg; - return ptarg; - } - } - else - assert( mapTargets.find(key) == mapTargets.end()); - - ptarg->nUpdateTarg = besttarg; - mapTargets[key] = ptarg; - return ptarg; -} - -ZeroGS::CRenderTargetMngr::MAPTARGETS::iterator ZeroGS::CRenderTargetMngr::GetOldestTarg(MAPTARGETS& m) -{ - if( m.size() == 0 ) { - return m.end(); - } - - // release some resources - u32 curtime = timeGetTime(); - MAPTARGETS::iterator itmaxtarg = m.begin(); - for(MAPTARGETS::iterator it = ++m.begin(); it != m.end(); ++it) { - if( itmaxtarg->second->lastused-curtime < it->second->lastused-curtime ) itmaxtarg = it; - } - - return itmaxtarg; -} - -void ZeroGS::CRenderTargetMngr::GetTargs(int start, int end, list& listTargets) const -{ - for(MAPTARGETS::const_iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { - if( it->second->start < end && start < it->second->end ) listTargets.push_back(it->second); - } -} - -void ZeroGS::CRenderTargetMngr::Resolve(int start, int end) -{ - for(MAPTARGETS::const_iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { - if( it->second->start < end && start < it->second->end ) - it->second->Resolve(); - } -} - -void ZeroGS::CMemoryTargetMngr::Destroy() -{ - listTargets.clear(); - listClearedTargets.clear(); -} - -int memcmp_clut16(u16* pSavedBuffer, u16* pClutBuffer, int clutsize) -{ - assert( (clutsize&31) == 0 ); - - // left > 0 only when csa < 16 - int left = ((u32)(uptr)pClutBuffer & 2) ? 0 : (((u32)(uptr)pClutBuffer & 0x3ff)/2) + clutsize - 512; - if( left > 0 ) clutsize -= left; - - while(clutsize > 0) { - for(int i = 0; i < 16; ++i) { - if( pSavedBuffer[i] != pClutBuffer[2*i] ) - return 1; - } - - clutsize -= 32; - pSavedBuffer += 16; - pClutBuffer += 32; - } - - if( left > 0 ) { - pClutBuffer = (u16*)(g_pbyGSClut + 2); - - while(left > 0) { - for(int i = 0; i < 16; ++i) { - if( pSavedBuffer[i] != pClutBuffer[2*i] ) - return 1; - } - - left -= 32; - pSavedBuffer += 16; - pClutBuffer += 32; - } - } - - return 0; -} - -bool ZeroGS::CMemoryTarget::ValidateClut(const tex0Info& tex0) -{ - assert( tex0.psm == psm && PSMT_ISCLUT(psm) && cpsm == tex0.cpsm ); - - int nClutOffset = 0; - int clutsize = 0; - - int entries = (tex0.psm&3)==3 ? 256 : 16; - if( tex0.cpsm <= 1 ) { // 32 bit - nClutOffset = 64 * tex0.csa; - clutsize = min(entries, 256-tex0.csa*16)*4; - } - else { - nClutOffset = 32 * (tex0.csa&15) + (tex0.csa>=16?2:0); - clutsize = min(entries, 512-tex0.csa*16)*2; - } - - assert( clutsize == clut.size() ); - - if( cpsm <= 1 ) { - if( memcmp_mmx(&clut[0], g_pbyGSClut+nClutOffset, clutsize) ) - return false; - } - else { - if( memcmp_clut16((u16*)&clut[0], (u16*)(g_pbyGSClut+nClutOffset), clutsize) ) - return false; - } - - return true; -} - -int VALIDATE_THRESH = 8; -u32 TEXDESTROY_THRESH = 16; - -bool ZeroGS::CMemoryTarget::ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex) -{ - if( clearmaxy == 0 ) - return true; - - int checkstarty = max(starttex, clearminy); - int checkendy = min(endtex, clearmaxy); - if( checkstarty >= checkendy ) - return true; - - if( validatecount++ > VALIDATE_THRESH ) { - height = 0; - return false; - } - - // lock and compare - assert( ptex != NULL && ptex->memptr != NULL); - - int result = memcmp_mmx(ptex->memptr + (checkstarty-realy)*4*GPU_TEXWIDTH, g_pbyGSMemory+checkstarty*4*GPU_TEXWIDTH, (checkendy-checkstarty)*4*GPU_TEXWIDTH); - - if( result == 0 || !bDeleteBadTex ) { - if( result == 0 ) clearmaxy = 0; - return result == 0; - } - - // delete clearminy, clearmaxy range (not the checkstarty, checkendy range) - int newstarty = 0; - if( clearminy <= starty ) { - if( clearmaxy < starty + height) { - // preserve end - height = starty+height-clearmaxy; - starty = clearmaxy; - assert(height > 0); - } - else { - // destroy - height = 0; - } - } - else { - // beginning can be preserved - height = clearminy-starty; - } - - clearmaxy = 0; - assert( starty >= realy && starty+height<=realy+realheight ); - - return false; -} - -// used to build clut textures (note that this is for both 16 and 32 bit cluts) -#define BUILDCLUT() { \ - switch(tex0.psm) { \ - case PSMT8: \ - for(int i = 0; i < targ->height; ++i) { \ - for(int j = 0; j < GPU_TEXWIDTH/2; ++j) { \ - pdst[0] = pclut[psrc[0]]; \ - pdst[1] = pclut[psrc[1]]; \ - pdst[2] = pclut[psrc[2]]; \ - pdst[3] = pclut[psrc[3]]; \ - pdst[4] = pclut[psrc[4]]; \ - pdst[5] = pclut[psrc[5]]; \ - pdst[6] = pclut[psrc[6]]; \ - pdst[7] = pclut[psrc[7]]; \ - pdst += 8; \ - psrc += 8; \ - } \ - } \ - break; \ - case PSMT4: \ - for(int i = 0; i < targ->height; ++i) { \ - for(int j = 0; j < GPU_TEXWIDTH; ++j) { \ - pdst[0] = pclut[psrc[0]&15]; \ - pdst[1] = pclut[psrc[0]>>4]; \ - pdst[2] = pclut[psrc[1]&15]; \ - pdst[3] = pclut[psrc[1]>>4]; \ - pdst[4] = pclut[psrc[2]&15]; \ - pdst[5] = pclut[psrc[2]>>4]; \ - pdst[6] = pclut[psrc[3]&15]; \ - pdst[7] = pclut[psrc[3]>>4]; \ - \ - pdst += 8; \ - psrc += 4; \ - } \ - } \ - break; \ - case PSMT8H: \ - for(int i = 0; i < targ->height; ++i) { \ - for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ - pdst[0] = pclut[psrc[3]]; \ - pdst[1] = pclut[psrc[7]]; \ - pdst[2] = pclut[psrc[11]]; \ - pdst[3] = pclut[psrc[15]]; \ - pdst[4] = pclut[psrc[19]]; \ - pdst[5] = pclut[psrc[23]]; \ - pdst[6] = pclut[psrc[27]]; \ - pdst[7] = pclut[psrc[31]]; \ - pdst += 8; \ - psrc += 32; \ - } \ - } \ - break; \ - case PSMT4HH: \ - for(int i = 0; i < targ->height; ++i) { \ - for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ - pdst[0] = pclut[psrc[3]>>4]; \ - pdst[1] = pclut[psrc[7]>>4]; \ - pdst[2] = pclut[psrc[11]>>4]; \ - pdst[3] = pclut[psrc[15]>>4]; \ - pdst[4] = pclut[psrc[19]>>4]; \ - pdst[5] = pclut[psrc[23]>>4]; \ - pdst[6] = pclut[psrc[27]>>4]; \ - pdst[7] = pclut[psrc[31]>>4]; \ - pdst += 8; \ - psrc += 32; \ - } \ - } \ - break; \ - case PSMT4HL: \ - for(int i = 0; i < targ->height; ++i) { \ - for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ - pdst[0] = pclut[psrc[3]&15]; \ - pdst[1] = pclut[psrc[7]&15]; \ - pdst[2] = pclut[psrc[11]&15]; \ - pdst[3] = pclut[psrc[15]&15]; \ - pdst[4] = pclut[psrc[19]&15]; \ - pdst[5] = pclut[psrc[23]&15]; \ - pdst[6] = pclut[psrc[27]&15]; \ - pdst[7] = pclut[psrc[31]&15]; \ - pdst += 8; \ - psrc += 32; \ - } \ - } \ - break; \ - default: \ - assert(0); \ - } \ -} \ - -#define TARGET_THRESH 0x500 - -extern int g_MaxTexWidth, g_MaxTexHeight; - -//#define SORT_TARGETS -inline list::iterator ZeroGS::CMemoryTargetMngr::DestroyTargetIter(list::iterator& it) -{ - // find the target and destroy - list::iterator itprev = it; ++it; - listClearedTargets.splice(listClearedTargets.end(), listTargets, itprev); - - if( listClearedTargets.size() > TEXDESTROY_THRESH ) { - listClearedTargets.pop_front(); - } - - return it; -} - -#if defined(_MSC_VER) && defined(__x86_64__) -extern "C" void UnswizzleZ16Target(void* dst, void* src, int iters); -#endif - -ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::GetMemoryTarget(const tex0Info& tex0, int forcevalidate) -{ - int nbStart, nbEnd; - GetRectMemAddress(nbStart, nbEnd, tex0.psm, 0, 0, tex0.tw, tex0.th, tex0.tbp0, tex0.tbw); - assert( nbStart < nbEnd ); - nbEnd = min(nbEnd, 0x00400000); - - int nClutOffset = 0; - int clutsize = 0; - - if( PSMT_ISCLUT(tex0.psm) ) { - int entries = (tex0.psm&3)==3 ? 256 : 16; - if( tex0.cpsm <= 1 ) { // 32 bit - nClutOffset = 64 * tex0.csa; - clutsize = min(entries, 256-tex0.csa*16)*4; - } - else { - nClutOffset = 64 * (tex0.csa&15) + (tex0.csa>=16?2:0); - clutsize = min(entries, 512-tex0.csa*16)*2; - } - } - - DVProfileFunc _pf("GetMemoryTarget"); - - int start = nbStart / (4*GPU_TEXWIDTH); - int end = (nbEnd + GPU_TEXWIDTH*4 - 1) / (4*GPU_TEXWIDTH); - assert( start < end ); - - for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { - - if( it->starty <= start && it->starty+it->height >= end ) { - - assert( it->psm != 0xd ); - - // using clut, validate that same data - if( PSMT_ISCLUT(it->psm) != PSMT_ISCLUT(tex0.psm) ) { - if( it->validatecount++ > VALIDATE_THRESH ) { - it = DestroyTargetIter(it); - if( listTargets.size() == 0 ) - break; - } - else - ++it; - continue; - } - - if( PSMT_ISCLUT(tex0.psm) ) { - assert( it->clut.size() > 0 ); - - if( it->psm != tex0.psm || it->cpsm != tex0.cpsm || it->clut.size() != clutsize ) { - // wrong clut - if( it->validatecount++ > VALIDATE_THRESH ) { - it = DestroyTargetIter(it); - if( listTargets.size() == 0 ) - break; - } - else - ++it; - continue; - } - - if( tex0.cpsm <= 1 ) { - if( memcmp_mmx(&it->clut[0], g_pbyGSClut+nClutOffset, clutsize) ) { - ++it; - continue; - } - } - else { - if( memcmp_clut16((u16*)&it->clut[0], (u16*)(g_pbyGSClut+nClutOffset), clutsize) ) { - ++it; - continue; - } - } - } - else if( PSMT_IS16BIT(tex0.psm) != PSMT_IS16BIT(it->psm) ) { - - if( it->validatecount++ > VALIDATE_THRESH ) { - it = DestroyTargetIter(it); - if( listTargets.size() == 0 ) - break; - } - else - ++it; - - continue; - } - - if( forcevalidate ) {//&& listTargets.size() < TARGET_THRESH ) { - // do more validation checking. delete if not been used for a while - if( !it->ValidateTex(tex0, start, end, curstamp > it->usedstamp + 3) ) { - if( it->height <= 0 ) { - it = DestroyTargetIter(it); - if( listTargets.size() == 0 ) - break; - } - else - ++it; - continue; - } - } - - it->usedstamp = curstamp; - it->validatecount = 0; - - return &(*it); - } -#ifdef SORT_TARGETS - else if( it->starty >= end ) - break; -#endif - - ++it; - } - - // couldn't find so create - DVProfileFunc _pf1("GetMemoryTarget:Create"); - - CMemoryTarget* targ; - - u32 fmt = GL_UNSIGNED_BYTE; - if( (PSMT_ISCLUT(tex0.psm) && tex0.cpsm > 1) || tex0.psm == PSMCT16 || tex0.psm == PSMCT16S) { - fmt = GL_UNSIGNED_SHORT_1_5_5_5_REV; - } - - int widthmult = 1; - if( g_MaxTexHeight < 4096 ) { - if( end-start > g_MaxTexHeight ) - widthmult = 2; - } - - int channels = 1; - if( PSMT_ISCLUT(tex0.psm) ) { - if( tex0.psm == PSMT8 ) channels = 4; - else if( tex0.psm == PSMT4 ) channels = 8; - } - else { - if( PSMT_IS16BIT(tex0.psm) ) { - // 16z needs to be a8r8g8b8 - channels = 2; - } - } - - if( listClearedTargets.size() > 0 ) { - - list::iterator itbest = listClearedTargets.begin(); - while(itbest != listClearedTargets.end()) { - - if( end-start <= itbest->realheight && itbest->fmt == fmt && itbest->widthmult == widthmult && itbest->channels == channels ) { - // check channels - int targchannels = 1; - if( PSMT_ISCLUT(itbest->psm) ) { - if( itbest->psm == PSMT8 ) targchannels = 4; - else if( itbest->psm == PSMT4 ) targchannels = 8; - } - else if( PSMT_IS16BIT(itbest->psm) ) { - targchannels = 2; - } - if( targchannels == channels ) - break; - } - ++itbest; - } - - if( itbest != listClearedTargets.end()) { - listTargets.splice(listTargets.end(), listClearedTargets, itbest); - targ = &listTargets.back(); - targ->validatecount = 0; - } - else { - // create a new - listTargets.push_back(CMemoryTarget()); - targ = &listTargets.back(); - } - } - else { - listTargets.push_back(CMemoryTarget()); - targ = &listTargets.back(); - } - - // fill local clut - if( PSMT_ISCLUT(tex0.psm) ) { - assert( clutsize > 0 ); - targ->cpsm = tex0.cpsm; - targ->clut.reserve(256*4); // no matter what - targ->clut.resize(clutsize); - - if( tex0.cpsm <= 1 ) { // 32 bit - memcpy_amd(&targ->clut[0], g_pbyGSClut+nClutOffset, clutsize); - } - else { - u16* pClutBuffer = (u16*)(g_pbyGSClut + nClutOffset); - u16* pclut = (u16*)&targ->clut[0]; - int left = ((u32)nClutOffset & 2) ? 0 : ((nClutOffset&0x3ff)/2)+clutsize-512; - if( left > 0 ) clutsize -= left; - - while(clutsize > 0) { - pclut[0] = pClutBuffer[0]; - pclut++; - pClutBuffer+=2; - clutsize -= 2; - } - - if( left > 0) { - pClutBuffer = (u16*)(g_pbyGSClut + 2); - while(left > 0) { - pclut[0] = pClutBuffer[0]; - left -= 2; - pClutBuffer += 2; - pclut++; - } - } - } - } - - if( targ->ptex != NULL ) { - - assert( end-start <= targ->realheight && targ->fmt == fmt && targ->widthmult == widthmult ); - // good enough, so init - targ->realy = targ->starty = start; - targ->usedstamp = curstamp; - targ->psm = tex0.psm; - targ->cpsm = tex0.cpsm; - targ->height = end-start; - } - - if( targ->ptex == NULL ) { - - // not initialized yet - targ->fmt = fmt; - targ->realy = targ->starty = start; - targ->realheight = targ->height = end-start; - targ->usedstamp = curstamp; - targ->psm = tex0.psm; - targ->cpsm = tex0.cpsm; - targ->widthmult = widthmult; - targ->channels = channels; - - // alloc the mem - targ->ptex = new CMemoryTarget::TEXTURE(); - targ->ptex->ref = 1; - } - -#ifndef RELEASE_TO_PUBLIC - g_TransferredToGPU += GPU_TEXWIDTH * channels * 4 * targ->height; -#endif - - // fill with data - if( targ->ptex->memptr == NULL ) { - targ->ptex->memptr = (u8*)_aligned_malloc(4 * GPU_TEXWIDTH * targ->realheight, 16); - assert(targ->ptex->ref > 0 ); - } - - memcpy_amd(targ->ptex->memptr, g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy, 4 * GPU_TEXWIDTH * targ->height); - vector texdata; - u8* ptexdata = NULL; - - if( PSMT_ISCLUT(tex0.psm) ) { - - texdata.resize( (tex0.cpsm <= 1?4:2) *GPU_TEXWIDTH*channels*widthmult*(targ->realheight+widthmult-1)/widthmult); - ptexdata = &texdata[0]; - - u8* psrc = (u8*)(g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy); - - if( tex0.cpsm <= 1 ) { // 32bit - u32* pclut = (u32*)&targ->clut[0]; - u32* pdst = (u32*)ptexdata; - - BUILDCLUT(); - } - else { - u16* pclut = (u16*)&targ->clut[0]; - u16* pdst = (u16*)ptexdata; - - BUILDCLUT(); - } - } - else { - if( tex0.psm == PSMT16Z || tex0.psm == PSMT16SZ ) { - - texdata.resize(4*GPU_TEXWIDTH*channels*widthmult*(targ->realheight+widthmult-1)/widthmult); - ptexdata = &texdata[0]; - // needs to be 8 bit, use xmm for unpacking - u16* dst = (u16*)ptexdata; - u16* src = (u16*)(g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy); - - assert( ((u32)(uptr)dst)%16 == 0 ); - -#if defined(ZEROGS_SSE2) - int iters = targ->height*GPU_TEXWIDTH/16; - -#if defined(_MSC_VER) - -#if defined(__x86_64__) - UnswizzleZ16Target(dst, src, iters); -#else - __asm { - mov edx, iters - pxor xmm7, xmm7 - mov eax, dst - mov ecx, src - -Z16Loop: - // unpack 64 bytes at a time - movdqa xmm0, [ecx] - movdqa xmm2, [ecx+16] - movdqa xmm4, [ecx+32] - movdqa xmm6, [ecx+48] - - movdqa xmm1, xmm0 - movdqa xmm3, xmm2 - movdqa xmm5, xmm4 - - punpcklwd xmm0, xmm7 - punpckhwd xmm1, xmm7 - punpcklwd xmm2, xmm7 - punpckhwd xmm3, xmm7 - - // start saving - movdqa [eax], xmm0 - movdqa [eax+16], xmm1 - - punpcklwd xmm4, xmm7 - punpckhwd xmm5, xmm7 - - movdqa [eax+32], xmm2 - movdqa [eax+48], xmm3 - - movdqa xmm0, xmm6 - punpcklwd xmm6, xmm7 - - movdqa [eax+64], xmm4 - movdqa [eax+80], xmm5 - - punpckhwd xmm0, xmm7 - - movdqa [eax+96], xmm6 - movdqa [eax+112], xmm0 - - add ecx, 64 - add eax, 128 - sub edx, 1 - jne Z16Loop - } -#endif // __x86_64__ -#else // _MSC_VER - - __asm__(".intel_syntax\n" - "pxor %%xmm7, %%xmm7\n" - - "Z16Loop:\n" - // unpack 64 bytes at a time - "movdqa %%xmm0, [%0]\n" - "movdqa %%xmm2, [%0+16]\n" - "movdqa %%xmm4, [%0+32]\n" - "movdqa %%xmm6, [%0+48]\n" - - "movdqa %%xmm1, %%xmm0\n" - "movdqa %%xmm3, %%xmm2\n" - "movdqa %%xmm5, %%xmm4\n" - - "punpcklwd %%xmm0, %%xmm7\n" - "punpckhwd %%xmm1, %%xmm7\n" - "punpcklwd %%xmm2, %%xmm7\n" - "punpckhwd %%xmm3, %%xmm7\n" - - // start saving - "movdqa [%1], %%xmm0\n" - "movdqa [%1+16], %%xmm1\n" - - "punpcklwd %%xmm4, %%xmm7\n" - "punpckhwd %%xmm5, %%xmm7\n" - - "movdqa [%1+32], %%xmm2\n" - "movdqa [%1+48], %%xmm3\n" - - "movdqa %%xmm0, %%xmm6\n" - "punpcklwd %%xmm6, %%xmm7\n" - - "movdqa [%1+64], %%xmm4\n" - "movdqa [%1+80], %%xmm5\n" - - "punpckhwd %%xmm0, %%xmm7\n" - - "movdqa [%1+96], %%xmm6\n" - "movdqa [%1+112], %%xmm0\n" - - "add %0, 64\n" - "add %1, 128\n" - "sub %2, 1\n" - "jne Z16Loop\n" - ".att_syntax\n" : "=r"(src), "=r"(dst), "=r"(iters) : "0"(src), "1"(dst), "2"(iters)); - -#endif // _MSC_VER -#else // ZEROGS_SSE2 - for(int i = 0; i < targ->height; ++i) { - for(int j = 0; j < GPU_TEXWIDTH; ++j) { - dst[0] = src[0]; dst[1] = 0; - dst[2] = src[1]; dst[3] = 0; - dst += 4; - src += 2; - } - } -#endif // ZEROGS_SSE2 - } - else { - ptexdata = targ->ptex->memptr; - } - } - - // create the texture - GL_REPORT_ERRORD(); - assert(ptexdata != NULL); - if( targ->ptex->tex == 0 ) - glGenTextures(1, &targ->ptex->tex); - glBindTexture(GL_TEXTURE_RECTANGLE_NV, targ->ptex->tex); - glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, fmt==GL_UNSIGNED_BYTE?4:GL_RGB5_A1, GPU_TEXWIDTH*channels*widthmult, - (targ->realheight+widthmult-1)/widthmult, 0, GL_RGBA, fmt, ptexdata); - - int realheight = targ->realheight; - while( glGetError() != GL_NO_ERROR ) { - - // release resources until can create - if( listClearedTargets.size() > 0 ) - listClearedTargets.pop_front(); - else { - if( listTargets.size() == 0 ) { - ERROR_LOG("Failed to create %dx%x texture\n", GPU_TEXWIDTH*channels*widthmult, (realheight+widthmult-1)/widthmult); - channels = 1; - return NULL; - } - DestroyOldest(); - } - - glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, 4, GPU_TEXWIDTH*channels*widthmult, (targ->realheight+widthmult-1)/widthmult, 0, GL_RGBA, fmt, ptexdata); - } - - glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_T, GL_CLAMP); - - assert( tex0.psm != 0xd ); - if( PSMT_ISCLUT(tex0.psm) ) - assert( targ->clut.size() > 0 ); - - return targ; -} - -void ZeroGS::CMemoryTargetMngr::ClearRange(int nbStartY, int nbEndY) -{ - int starty = nbStartY / (4*GPU_TEXWIDTH); - int endy = (nbEndY+4*GPU_TEXWIDTH-1) / (4*GPU_TEXWIDTH); - //int endy = (nbEndY+4096-1) / 4096; - - //if( listTargets.size() < TARGET_THRESH ) { - for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { - - if( it->starty < endy && (it->starty+it->height) > starty ) { - - // intersects, reduce valid texture mem (or totally delete texture) - // there are 4 cases - int miny = max(it->starty, starty); - int maxy = min(it->starty+it->height, endy); - assert(miny < maxy); - - if( it->clearmaxy == 0 ) { - it->clearminy = miny; - it->clearmaxy = maxy; - } - else { - if( it->clearminy > miny ) it->clearminy = miny; - if( it->clearmaxy < maxy ) it->clearmaxy = maxy; - } - } - - ++it; - } -// } -// else { -// for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { -// -// if( it->starty < endy && (it->starty+it->height) > starty ) { -// int newstarty = 0; -// if( starty <= it->starty ) { -// if( endy < it->starty + it->height) { -// // preserve end -// it->height = it->starty+it->height-endy; -// it->starty = endy; -// assert(it->height > 0); -// } -// else { -// // destroy -// it->height = 0; -// } -// } -// else { -// // beginning can be preserved -// it->height = starty-it->starty; -// } -// -// assert( it->starty >= it->realy && it->starty+it->height<=it->realy+it->realheight ); -// if( it->height <= 0 ) { -// list::iterator itprev = it; ++it; -// listClearedTargets.splice(listClearedTargets.end(), listTargets, itprev); -// continue; -// } -// } -// -// ++it; -// } -// } -} - -void ZeroGS::CMemoryTargetMngr::DestroyCleared() -{ - for(list::iterator it = listClearedTargets.begin(); it != listClearedTargets.end(); ) { - if( it->usedstamp < curstamp - 2 ) { - it = listClearedTargets.erase(it); - continue; - } - - ++it; - } - - if( (curstamp % 3) == 0 ) { - // purge old targets every 3 frames - for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { - if( it->usedstamp < curstamp - 3 ) { - it = listTargets.erase(it); - continue; - } - - ++it; - } - } - - ++curstamp; -} - -void ZeroGS::CMemoryTargetMngr::DestroyOldest() -{ - if( listTargets.size() == 0 ) - return; - - list::iterator it, itbest; - it = itbest = listTargets.begin(); - - while(it != listTargets.end()) { - if( it->usedstamp < itbest->usedstamp ) - itbest = it; - ++it; - } - - listTargets.erase(itbest); -} - -////////////////////////////////////// -// Texture Mngr For Bitwise AND Ops // -////////////////////////////////////// -void ZeroGS::CBitwiseTextureMngr::Destroy() -{ - for(map::iterator it = mapTextures.begin(); it != mapTextures.end(); ++it) - glDeleteTextures(1, &it->second); - mapTextures.clear(); -} - -u32 ZeroGS::CBitwiseTextureMngr::GetTexInt(u32 bitvalue, u32 ptexDoNotDelete) -{ - if( mapTextures.size() > 32 ) { - // randomly delete 8 - for(map::iterator it = mapTextures.begin(); it != mapTextures.end();) { - if( !(rand()&3) && it->second != ptexDoNotDelete) { - glDeleteTextures(1, &it->second); - mapTextures.erase(it++); - } - else ++it; - } - } - - // create a new tex - u32 ptex; - glGenTextures(1, &ptex); - - vector data(GPU_TEXMASKWIDTH); - for(u32 i = 0; i < GPU_TEXMASKWIDTH; ++i) - data[i] = ((i&bitvalue)<<6)|0x1f; // add the 1/2 offset so that - - glBindTexture(GL_TEXTURE_2D, ptex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE16, GPU_TEXMASKWIDTH, 1, 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, &data[0]); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - - if( glGetError() != GL_NO_ERROR ) { - ERROR_LOG("Failed to create bitmask texture\n"); - return 0; - } - - mapTextures[bitvalue] = ptex; - return ptex; -} - -void ZeroGS::CRangeManager::Insert(int start, int end) -{ - int imin = 0, imax = (int)ranges.size(), imid; - -#ifdef _DEBUG - // sanity check - for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); -#endif - - switch( ranges.size() ) { - case 0: - ranges.push_back(RANGE(start, end)); - return; - - case 1: - if( end < ranges.front().start ) { - ranges.insert(ranges.begin(), RANGE(start, end)); - } - else if( start > ranges.front().end ) { - ranges.push_back(RANGE(start, end)); - } - else { - if( start < ranges.front().start ) ranges.front().start = start; - if( end > ranges.front().end ) ranges.front().end = end; - } - - return; - } - - // find where start is - while(imin < imax) { - imid = (imin+imax)>>1; - - assert( imid < (int)ranges.size() ); - - if( ranges[imid].end >= start && (imid == 0 || ranges[imid-1].end < start) ) { - imin = imid; - break; - } - else if( ranges[imid].start > start ) imax = imid; - else imin = imid+1; - } - - int startindex = imin; - - if( startindex >= (int)ranges.size() ) { - // non intersecting - assert( start > ranges.back().end ); - ranges.push_back(RANGE(start, end)); - return; - } - if( startindex == 0 && end < ranges.front().start ) { - ranges.insert(ranges.begin(), RANGE(start, end)); - -#ifdef _DEBUG - // sanity check - for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); -#endif - return; - } - - imin = 0; imax = (int)ranges.size(); - - // find where end is - while(imin < imax) { - imid = (imin+imax)>>1; - - assert( imid < (int)ranges.size() ); - - if( ranges[imid].end <= end && (imid == ranges.size()-1 || ranges[imid+1].start > end ) ) { - imin = imid; - break; - } - else if( ranges[imid].start >= end ) imax = imid; - else imin = imid+1; - } - - int endindex = imin; - - if( startindex > endindex ) { - // create a new range - ranges.insert(ranges.begin()+startindex, RANGE(start, end)); - -#ifdef _DEBUG - // sanity check - for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); -#endif - return; - } - - if( endindex >= (int)ranges.size()-1 ) { - // pop until startindex is reached - int lastend = ranges.back().end; - int numpop = (int)ranges.size() - startindex - 1; - while(numpop-- > 0 ) ranges.pop_back(); - - assert( start <= ranges.back().end ); - if( start < ranges.back().start ) ranges.back().start = start; - if( lastend > ranges.back().end ) ranges.back().end = lastend; - if( end > ranges.back().end ) ranges.back().end = end; - -#ifdef _DEBUG - // sanity check - for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); -#endif - - return; - } - - if( endindex == 0 ) { - assert( end >= ranges.front().start ); - if( start < ranges.front().start ) ranges.front().start = start; - if( end > ranges.front().end ) ranges.front().end = end; - -#ifdef _DEBUG - // sanity check - for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); -#endif - } - - // somewhere in the middle - if( ranges[startindex].start < start ) start = ranges[startindex].start; - - if( startindex < endindex ) { - ranges.erase(ranges.begin() + startindex, ranges.begin() + endindex ); - } - - if( start < ranges[startindex].start ) ranges[startindex].start = start; - if( end > ranges[startindex].end ) ranges[startindex].end = end; - -#ifdef _DEBUG - // sanity check - for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); -#endif -} - -namespace ZeroGS { - -CRangeManager s_RangeMngr; // manages overwritten memory -static int gs_imageEnd = 0; - -void ResolveInRange(int start, int end) -{ - list listTargs; - s_DepthRTs.GetTargs(start, end, listTargs); - s_RTs.GetTargs(start, end, listTargs); - - if( listTargs.size() > 0 ) { - Flush(0); - Flush(1); - - for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) { - // only resolve if not completely covered - (*it)->Resolve(); - } - } -} - -////////////////// -// Transferring // -////////////////// -void FlushTransferRanges(const tex0Info* ptex) -{ - assert( s_RangeMngr.ranges.size() > 0 ); - bool bHasFlushed = false; - list listTransmissionUpdateTargs; - - int texstart = -1, texend = -1; - if( ptex != NULL ) { - GetRectMemAddress(texstart, texend, ptex->psm, 0, 0, ptex->tw, ptex->th, ptex->tbp0, ptex->tbw); - } - - for(vector::iterator itrange = s_RangeMngr.ranges.begin(); itrange != s_RangeMngr.ranges.end(); ++itrange ) { - - int start = itrange->start; - int end = itrange->end; - - listTransmissionUpdateTargs.clear(); - s_DepthRTs.GetTargs(start, end, listTransmissionUpdateTargs); - s_RTs.GetTargs(start, end, listTransmissionUpdateTargs); - -// if( !bHasFlushed && listTransmissionUpdateTargs.size() > 0 ) { -// Flush(0); -// Flush(1); -// -//#ifdef _DEBUG -// // make sure targets are still the same -// list::iterator it; -// FORIT(it, listTransmissionUpdateTargs) { -// CRenderTargetMngr::MAPTARGETS::iterator itmap; -// for(itmap = s_RTs.mapTargets.begin(); itmap != s_RTs.mapTargets.end(); ++itmap) { -// if( itmap->second == *it ) -// break; -// } -// -// if( itmap == s_RTs.mapTargets.end() ) { -// -// for(itmap = s_DepthRTs.mapTargets.begin(); itmap != s_DepthRTs.mapTargets.end(); ++itmap) { -// if( itmap->second == *it ) -// break; -// } -// -// assert( itmap != s_DepthRTs.mapTargets.end() ); -// } -// } -//#endif -// } - - for(list::iterator it = listTransmissionUpdateTargs.begin(); it != listTransmissionUpdateTargs.end(); ++it) { - - CRenderTarget* ptarg = *it; - - if( (ptarg->status & CRenderTarget::TS_Virtual) ) - continue; - - if( !(ptarg->start < texend && ptarg->end > texstart) ) { - // chekc if target is currently being used - - if( !(g_GameSettings & GAME_NOQUICKRESOLVE) ) { - if( ptarg->fbp != vb[0].gsfb.fbp ) {//&& (vb[0].prndr == NULL || ptarg->fbp != vb[0].prndr->fbp) ) { - - if( ptarg->fbp != vb[1].gsfb.fbp ) { //&& (vb[1].prndr == NULL || ptarg->fbp != vb[1].prndr->fbp) ) { - // this render target currently isn't used and is not in the texture's way, so can safely ignore - // resolving it. Also the range has to be big enough compared to the target to really call it resolved - // (ffx changing screens, shadowhearts) - // start == ptarg->start, used for kh to transfer text - if( ptarg->IsDepth() || end-start > 0x50000 || ((g_GameSettings&GAME_QUICKRESOLVE1)&&start == ptarg->start) ) - ptarg->status |= CRenderTarget::TS_NeedUpdate|CRenderTarget::TS_Resolved; - - continue; - } - } - } - } - else { -// if( start <= texstart && end >= texend ) { -// // texture taken care of so can skip!? -// continue; -// } - } - - // the first range check was very rough; some games (dragonball z) have the zbuf in the same page as textures (but not overlapping) - // so detect that condition - if( ptarg->fbh % m_Blocks[ptarg->psm].height ) { - - // get start of left-most boundry page - int targstart, targend; - ZeroGS::GetRectMemAddress(targstart, targend, ptarg->psm, 0, 0, ptarg->fbw, ptarg->fbh & ~(m_Blocks[ptarg->psm].height-1), ptarg->fbp, ptarg->fbw); - - if( start >= targend ) { - - // don't bother - if( (ptarg->fbh % m_Blocks[ptarg->psm].height) <= 2 ) - continue; - - // calc how many bytes of the block that the page spans - } - } - - if( !(ptarg->status & CRenderTarget::TS_Virtual) ) { - - if( start < ptarg->end && end > ptarg->start ) { - - // suikoden5 is faster with check, but too big of a value and kh screens mess up - if( end - start > 0x8000 ) { - // intersects, do only one sided resolves - if( end-start > 4*ptarg->fbw ) { // at least it be greater than one scanline (spiro is faster) - if( start > ptarg->start ) { - ptarg->Resolve(ptarg->start, start); - } - else if( end < ptarg->end ) { - ptarg->Resolve(end, ptarg->end); - } - } - } - - ptarg->status |= CRenderTarget::TS_Resolved; - if( !ptarg->IsDepth() || (!(g_GameSettings & GAME_NODEPTHUPDATE) || end-start > 0x1000) ) - ptarg->status |= CRenderTarget::TS_NeedUpdate; - } - } - } - - ZeroGS::g_MemTargs.ClearRange(start, end); - } - - s_RangeMngr.Clear(); -} - -static vector s_vTempBuffer, s_vTransferCache; - -void InitTransferHostLocal() -{ - if( g_bIsLost ) - return; - -#ifndef RELEASE_TO_PUBLIC - if( gs.trxpos.dx+gs.imageWnew > gs.dstbuf.bw ) - WARN_LOG("Transfer error, width exceeds\n"); -#endif - - bool bHasFlushed = false; - - gs.imageX = gs.trxpos.dx; - gs.imageY = gs.trxpos.dy; - gs.imageEndX = gs.imageX + gs.imageWnew; - gs.imageEndY = gs.imageY + gs.imageHnew; - - assert( gs.imageEndX < 2048 && gs.imageEndY < 2048 ); - - // hack! viewful joe - if( gs.dstbuf.psm == 63 ) - gs.dstbuf.psm = 0; - - int start, end; - GetRectMemAddress(start, end, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); - - if( end > 0x00400000 ) { - WARN_LOG("host local out of bounds!\n"); - //gs.imageTransfer = -1; - end = 0x00400000; - } - - gs_imageEnd = end; - - if( vb[0].nCount > 0 ) - Flush(0); - if( vb[1].nCount > 0 ) - Flush(1); - - //PRIM_LOG("trans: bp:%x x:%x y:%x w:%x h:%x\n", gs.dstbuf.bp, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew); - -// if( !bHasFlushed && (vb[0].bNeedFrameCheck || vb[0].bNeedZCheck || vb[1].bNeedFrameCheck || vb[1].bNeedZCheck)) { -// Flush(0); -// Flush(1); -// bHasFlushed = 1; -// } -// -// // for all ranges, flush the targets -// // check if new rect intersects with current rendering texture, if so, flush -// if( vb[0].nCount > 0 && vb[0].curprim.tme ) { -// int tstart, tend; -// GetRectMemAddress(tstart, tend, vb[0].tex0.psm, 0, 0, vb[0].tex0.tw, vb[0].tex0.th, vb[0].tex0.tbp0, vb[0].tex0.tbw); -// -// if( start < tend && end > tstart ) { -// Flush(0); -// Flush(1); -// bHasFlushed = 1; -// } -// } -// -// if( !bHasFlushed && vb[1].nCount > 0 && vb[1].curprim.tme ) { -// int tstart, tend; -// GetRectMemAddress(tstart, tend, vb[1].tex0.psm, 0, 0, vb[1].tex0.tw, vb[1].tex0.th, vb[1].tex0.tbp0, vb[1].tex0.tbw); -// -// if( start < tend && end > tstart ) { -// Flush(0); -// Flush(1); -// bHasFlushed = 1; -// } -// } - - //ZeroGS::g_MemTargs.ClearRange(start, end); - //s_RangeMngr.Insert(start, end); -} - -void TransferHostLocal(const void* pbyMem, u32 nQWordSize) -{ - if( g_bIsLost ) - return; - - DVProfileFunc _pf("TransferHostLocal"); - - int start, end; - GetRectMemAddress(start, end, gs.dstbuf.psm, gs.imageX, gs.imageY, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); - assert( start < gs_imageEnd ); - - end = gs_imageEnd; - - // sometimes games can decompress to alpha channel of render target only, in this case - // do a resolve right away. wolverine x2 - if( gs.dstbuf.psm == PSMT8H || gs.dstbuf.psm == PSMT4HL || gs.dstbuf.psm == PSMT4HH ) { - list listTransmissionUpdateTargs; - s_RTs.GetTargs(start, end, listTransmissionUpdateTargs); - - for(list::iterator it = listTransmissionUpdateTargs.begin(); it != listTransmissionUpdateTargs.end(); ++it) { - - CRenderTarget* ptarg = *it; - - if( (ptarg->status & CRenderTarget::TS_Virtual) ) - continue; - - //ERROR_LOG("resolving to alpha channel\n"); - ptarg->Resolve(); - } - } - - s_RangeMngr.Insert(start, min(end, start+(int)nQWordSize*16)); - - const u8* porgend = (const u8*)pbyMem + 4 * nQWordSize; - - if( s_vTransferCache.size() > 0 ) { - - int imagecache = s_vTransferCache.size(); - s_vTempBuffer.resize(imagecache + nQWordSize*4); - memcpy(&s_vTempBuffer[0], &s_vTransferCache[0], imagecache); - memcpy(&s_vTempBuffer[imagecache], pbyMem, nQWordSize*4); - - pbyMem = (const void*)&s_vTempBuffer[0]; - porgend = &s_vTempBuffer[0]+s_vTempBuffer.size(); - - int wordinc = imagecache / 4; - if( (nQWordSize * 4 + imagecache)/3 == ((nQWordSize+wordinc) * 4) / 3 ) { - // can use the data - nQWordSize += wordinc; - } - } - - int leftover = m_Blocks[gs.dstbuf.psm].TransferHostLocal(pbyMem, nQWordSize); - - if( leftover > 0 ) { - // copy the last gs.image24bitOffset to the cache - s_vTransferCache.resize(leftover); - memcpy(&s_vTransferCache[0], porgend - leftover, leftover); - } - else s_vTransferCache.resize(0); - -#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) - if( g_bSaveTrans ) { - tex0Info t; - t.tbp0 = gs.dstbuf.bp; - t.tw = gs.imageWnew; - t.th = gs.imageHnew; - t.tbw = gs.dstbuf.bw; - t.psm = gs.dstbuf.psm; - SaveTex(&t, 0); - } -#endif -} - -// left/right, top/down -//void TransferHostLocal(const void* pbyMem, u32 nQWordSize) -//{ -// assert( gs.imageTransfer == 0 ); -// u8* pstart = g_pbyGSMemory + gs.dstbuf.bp*256; -// -// const u8* pendbuf = (const u8*)pbyMem + nQWordSize*4; -// int i = gs.imageY, j = gs.imageX; -// -//#define DSTPSM gs.dstbuf.psm -// -//#define TRANSFERHOSTLOCAL(psm, T, widthlimit) { \ -// const T* pbuf = (const T*)pbyMem; \ -// u32 nSize = nQWordSize*(4/sizeof(T)); \ -// assert( (nSize%widthlimit) == 0 && widthlimit <= 4 ); \ -// if( ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) ERROR_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM); \ -// for(; i < gs.imageEndY; ++i) { \ -// for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += widthlimit) { \ -// /* write as many pixel at one time as possible */ \ -// writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ -// \ -// if( widthlimit > 1 ) { \ -// writePixel##psm##_0(pstart, (j+1)%2048, i%2048, pbuf[1], gs.dstbuf.bw); \ -// \ -// if( widthlimit > 2 ) { \ -// writePixel##psm##_0(pstart, (j+2)%2048, i%2048, pbuf[2], gs.dstbuf.bw); \ -// \ -// if( widthlimit > 3 ) { \ -// writePixel##psm##_0(pstart, (j+3)%2048, i%2048, pbuf[3], gs.dstbuf.bw); \ -// } \ -// } \ -// } \ -// } \ -// \ -// if( j >= gs.imageEndX ) { assert(j == gs.imageEndX); j = gs.trxpos.dx; } \ -// else { assert( nSize == 0 ); goto End; } \ -// } \ -//} \ -// -//#define TRANSFERHOSTLOCAL_4(psm) { \ -// const u8* pbuf = (const u8*)pbyMem; \ -// u32 nSize = nQWordSize*8; \ -// for(; i < gs.imageEndY; ++i) { \ -// for(; j < gs.imageEndX && nSize > 0; j += 8, nSize -= 8) { \ -// /* write as many pixel at one time as possible */ \ -// writePixel##psm##_0(pstart, j%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ -// writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ -// pbuf++; \ -// writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ -// writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ -// pbuf++; \ -// writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ -// writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ -// pbuf++; \ -// writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ -// writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ -// pbuf++; \ -// } \ -// \ -// if( j >= gs.imageEndX ) { /*assert(j == gs.imageEndX);*/ j = gs.trxpos.dx; } \ -// else { assert( nSize == 0 ); goto End; } \ -// } \ -//} \ -// -// switch (gs.dstbuf.psm) { -// case 0x0: TRANSFERHOSTLOCAL(32, u32, 2); break; -// case 0x1: TRANSFERHOSTLOCAL(24, u32, 4); break; -// case 0x2: TRANSFERHOSTLOCAL(16, u16, 4); break; -// case 0xA: TRANSFERHOSTLOCAL(16S, u16, 4); break; -// case 0x13: -// if( ((gs.imageEndX-gs.trxpos.dx)%4) ) { -// TRANSFERHOSTLOCAL(8, u8, 1); -// } -// else { -// TRANSFERHOSTLOCAL(8, u8, 4); -// } -// break; -// -// case 0x14: -//// if( (gs.imageEndX-gs.trxpos.dx)%8 ) { -//// // hack -//// if( abs((int)nQWordSize*8 - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx)) <= 8 ) { -//// // don't transfer -//// ERROR_LOG("bad texture 4: %d %d %d\n", gs.trxpos.dx, gs.imageEndX, nQWordSize); -//// gs.imageEndX = gs.trxpos.dx + (gs.imageEndX-gs.trxpos.dx)&~7; -//// //i = gs.imageEndY; -//// //goto End; -//// gs.imageTransfer = -1; -//// } -//// } -// TRANSFERHOSTLOCAL_4(4); -// break; -// case 0x1B: TRANSFERHOSTLOCAL(8H, u8, 4); break; -// case 0x24: TRANSFERHOSTLOCAL_4(4HL); break; -// case 0x2C: TRANSFERHOSTLOCAL_4(4HH); break; -// case 0x30: TRANSFERHOSTLOCAL(32Z, u32, 2); break; -// case 0x31: TRANSFERHOSTLOCAL(24Z, u32, 4); break; -// case 0x32: TRANSFERHOSTLOCAL(16Z, u16, 4); break; -// case 0x3A: TRANSFERHOSTLOCAL(16SZ, u16, 4); break; -// } -// -//End: -// if( i >= gs.imageEndY ) { -// assert( i == gs.imageEndY ); -// gs.imageTransfer = -1; -// -// if( g_bSaveTrans ) { -// tex0Info t; -// t.tbp0 = gs.dstbuf.bp; -// t.tw = gs.imageWnew; -// t.th = gs.imageHnew; -// t.tbw = gs.dstbuf.bw; -// t.psm = gs.dstbuf.psm; -// SaveTex(&t, 0); -// } -// } -// else { -// /* update new params */ -// gs.imageY = i; -// gs.imageX = j; -// } -//} - -void InitTransferLocalHost() -{ - assert( gs.trxpos.sx+gs.imageWnew <= 2048 && gs.trxpos.sy+gs.imageHnew <= 2048 ); - -#ifndef RELEASE_TO_PUBLIC - if( gs.trxpos.sx+gs.imageWnew > gs.srcbuf.bw ) - WARN_LOG("Transfer error, width exceeds\n"); -#endif - - gs.imageX = gs.trxpos.sx; - gs.imageY = gs.trxpos.sy; - gs.imageEndX = gs.imageX + gs.imageWnew; - gs.imageEndY = gs.imageY + gs.imageHnew; - s_vTransferCache.resize(0); - - int start, end; - GetRectMemAddress(start, end, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw); - ResolveInRange(start, end); -} - -// left/right, top/down -void TransferLocalHost(void* pbyMem, u32 nQWordSize) -{ - assert( gs.imageTransfer == 1 ); - - u8* pstart = g_pbyGSMemory + 256*gs.srcbuf.bp; - int i = gs.imageY, j = gs.imageX; - -#define TRANSFERLOCALHOST(psm, T) { \ - T* pbuf = (T*)pbyMem; \ - u32 nSize = nQWordSize*16/sizeof(T); \ - for(; i < gs.imageEndY; ++i) { \ - for(; j < gs.imageEndX && nSize > 0; ++j, --nSize) { \ - *pbuf++ = readPixel##psm##_0(pstart, j%2048, i%2048, gs.srcbuf.bw); \ - } \ - \ - if( j >= gs.imageEndX ) { assert( j == gs.imageEndX); j = gs.trxpos.sx; } \ - else { assert( nSize == 0 ); break; } \ - } \ -} \ - -#define TRANSFERLOCALHOST_24(psm) { \ - u8* pbuf = (u8*)pbyMem; \ - u32 nSize = nQWordSize*16/3; \ - for(; i < gs.imageEndY; ++i) { \ - for(; j < gs.imageEndX && nSize > 0; ++j, --nSize) { \ - u32 p = readPixel##psm##_0(pstart, j%2048, i%2048, gs.srcbuf.bw); \ - pbuf[0] = (u8)p; \ - pbuf[1] = (u8)(p>>8); \ - pbuf[2] = (u8)(p>>16); \ - pbuf += 3; \ - } \ - \ - if( j >= gs.imageEndX ) { assert( j == gs.imageEndX); j = gs.trxpos.sx; } \ - else { assert( nSize == 0 ); break; } \ - } \ -} \ - - switch (gs.srcbuf.psm) { - case 0x0: TRANSFERLOCALHOST(32, u32); break; - case 0x1: TRANSFERLOCALHOST_24(24); break; - case 0x2: TRANSFERLOCALHOST(16, u16); break; - case 0xA: TRANSFERLOCALHOST(16S, u16); break; - case 0x13: TRANSFERLOCALHOST(8, u8); break; - case 0x1B: TRANSFERLOCALHOST(8H, u8); break; - case 0x30: TRANSFERLOCALHOST(32Z, u32); break; - case 0x31: TRANSFERLOCALHOST_24(24Z); break; - case 0x32: TRANSFERLOCALHOST(16Z, u16); break; - case 0x3A: TRANSFERLOCALHOST(16SZ, u16); break; - default: assert(0); - } - - gs.imageY = i; - gs.imageX = j; - - if( gs.imageY >= gs.imageEndY ) { - assert( gs.imageY == gs.imageEndY ); - gs.imageTransfer = -1; - } -} - -// dir depends on trxpos.dir -void TransferLocalLocal() -{ - assert( gs.imageTransfer == 2 ); - assert( gs.trxpos.sx+gs.imageWnew < 2048 && gs.trxpos.sy+gs.imageHnew < 2048 ); - assert( gs.trxpos.dx+gs.imageWnew < 2048 && gs.trxpos.dy+gs.imageHnew < 2048 ); - assert( (gs.srcbuf.psm&0x7) == (gs.dstbuf.psm&0x7) ); - if( gs.trxpos.sx+gs.imageWnew > gs.srcbuf.bw ) - WARN_LOG("Transfer error, src width exceeds\n"); - if( gs.trxpos.dx+gs.imageWnew > gs.dstbuf.bw ) - WARN_LOG("Transfer error, dst width exceeds\n"); - - int srcstart, srcend, dststart, dstend; - - GetRectMemAddress(srcstart, srcend, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw); - GetRectMemAddress(dststart, dstend, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); - - // resolve the targs - ResolveInRange(srcstart, srcend); - - list listTargs; - s_RTs.GetTargs(dststart, dstend, listTargs); - for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) { - if( !((*it)->status & CRenderTarget::TS_Virtual) ) { - (*it)->Resolve(); - (*it)->status |= CRenderTarget::TS_NeedUpdate; - } - } - - u8* pSrcBuf = g_pbyGSMemory + gs.srcbuf.bp*256; - u8* pDstBuf = g_pbyGSMemory + gs.dstbuf.bp*256; - -#define TRANSFERLOCALLOCAL(srcpsm, dstpsm, widthlimit) { \ - assert( (gs.imageWnew&widthlimit)==0 && widthlimit <= 4); \ - for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < gs.trxpos.sy+gs.imageHnew; i++, i2++) { \ - for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < gs.trxpos.sx+gs.imageWnew; j+=widthlimit, j2+=widthlimit) { \ - \ - writePixel##dstpsm##_0(pDstBuf, j2%2048, i2%2048, \ - readPixel##srcpsm##_0(pSrcBuf, j%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ - \ - if( widthlimit > 1 ) { \ - writePixel##dstpsm##_0(pDstBuf, (j2+1)%2048, i2%2048, \ - readPixel##srcpsm##_0(pSrcBuf, (j+1)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ - \ - if( widthlimit > 2 ) { \ - writePixel##dstpsm##_0(pDstBuf, (j2+2)%2048, i2%2048, \ - readPixel##srcpsm##_0(pSrcBuf, (j+2)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ - \ - if( widthlimit > 3 ) { \ - writePixel##dstpsm##_0(pDstBuf, (j2+3)%2048, i2%2048, \ - readPixel##srcpsm##_0(pSrcBuf, (j+3)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ - } \ - } \ - } \ - } \ - } \ -} \ - -#define TRANSFERLOCALLOCAL_4(srcpsm, dstpsm) { \ - assert( (gs.imageWnew%8) == 0 ); \ - for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < gs.trxpos.sy+gs.imageHnew; ++i, ++i2) { \ - for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < gs.trxpos.sx+gs.imageWnew; j+=8, j2+=8) { \ - /* NOTE: the 2 conseq 4bit values are in NOT in the same byte */ \ - u32 read = getPixelAddress##srcpsm##_0(j%2048, i%2048, gs.srcbuf.bw); \ - u32 write = getPixelAddress##dstpsm##_0(j2%2048, i2%2048, gs.dstbuf.bw); \ - pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ - \ - read = getPixelAddress##srcpsm##_0((j+1)%2048, i%2048, gs.srcbuf.bw); \ - write = getPixelAddress##dstpsm##_0((j2+1)%2048, i2%2048, gs.dstbuf.bw); \ - pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ - \ - read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ - write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ - pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ - \ - read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ - write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ - pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ - \ - read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ - write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ - pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ - \ - read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ - write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ - pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ - \ - read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ - write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ - pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ - \ - read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ - write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ - pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ - } \ - } \ -} \ - - switch (gs.srcbuf.psm) { - case PSMCT32: - if( gs.dstbuf.psm == PSMCT32 ) { - TRANSFERLOCALLOCAL(32, 32, 2); - } - else { - TRANSFERLOCALLOCAL(32, 32Z, 2); - } - break; - - case PSMCT24: - if( gs.dstbuf.psm == PSMCT24 ) { - TRANSFERLOCALLOCAL(24, 24, 4); - } - else { - TRANSFERLOCALLOCAL(24, 24Z, 4); - } - break; - - case PSMCT16: - switch(gs.dstbuf.psm) { - case PSMCT16: TRANSFERLOCALLOCAL(16, 16, 4); break; - case PSMCT16S: TRANSFERLOCALLOCAL(16, 16S, 4); break; - case PSMT16Z: TRANSFERLOCALLOCAL(16, 16Z, 4); break; - case PSMT16SZ: TRANSFERLOCALLOCAL(16, 16SZ, 4); break; - } - break; - - case PSMCT16S: - switch(gs.dstbuf.psm) { - case PSMCT16: TRANSFERLOCALLOCAL(16S, 16, 4); break; - case PSMCT16S: TRANSFERLOCALLOCAL(16S, 16S, 4); break; - case PSMT16Z: TRANSFERLOCALLOCAL(16S, 16Z, 4); break; - case PSMT16SZ: TRANSFERLOCALLOCAL(16S, 16SZ, 4); break; - } - break; - - case PSMT8: - if( gs.dstbuf.psm == PSMT8 ) { - TRANSFERLOCALLOCAL(8, 8, 4); - } - else { - TRANSFERLOCALLOCAL(8, 8H, 4); - } - break; - - case PSMT4: - - switch(gs.dstbuf.psm ) { - case PSMT4: TRANSFERLOCALLOCAL_4(4, 4); break; - case PSMT4HL: TRANSFERLOCALLOCAL_4(4, 4HL); break; - case PSMT4HH: TRANSFERLOCALLOCAL_4(4, 4HH); break; - } - break; - - case PSMT8H: - if( gs.dstbuf.psm == PSMT8 ) { - TRANSFERLOCALLOCAL(8H, 8, 4); - } - else { - TRANSFERLOCALLOCAL(8H, 8H, 4); - } - break; - - case PSMT4HL: - switch(gs.dstbuf.psm ) { - case PSMT4: TRANSFERLOCALLOCAL_4(4HL, 4); break; - case PSMT4HL: TRANSFERLOCALLOCAL_4(4HL, 4HL); break; - case PSMT4HH: TRANSFERLOCALLOCAL_4(4HL, 4HH); break; - } - break; - case PSMT4HH: - switch(gs.dstbuf.psm ) { - case PSMT4: TRANSFERLOCALLOCAL_4(4HH, 4); break; - case PSMT4HL: TRANSFERLOCALLOCAL_4(4HH, 4HL); break; - case PSMT4HH: TRANSFERLOCALLOCAL_4(4HH, 4HH); break; - } - break; - - case PSMT32Z: - if( gs.dstbuf.psm == PSMCT32 ) { - TRANSFERLOCALLOCAL(32Z, 32, 2); - } - else { - TRANSFERLOCALLOCAL(32Z, 32Z, 2); - } - break; - - case PSMT24Z: - if( gs.dstbuf.psm == PSMCT24 ) { - TRANSFERLOCALLOCAL(24Z, 24, 4); - } - else { - TRANSFERLOCALLOCAL(24Z, 24Z, 4); - } - break; - - case PSMT16Z: - switch(gs.dstbuf.psm) { - case PSMCT16: TRANSFERLOCALLOCAL(16Z, 16, 4); break; - case PSMCT16S: TRANSFERLOCALLOCAL(16Z, 16S, 4); break; - case PSMT16Z: TRANSFERLOCALLOCAL(16Z, 16Z, 4); break; - case PSMT16SZ: TRANSFERLOCALLOCAL(16Z, 16SZ, 4); break; - } - break; - - case PSMT16SZ: - switch(gs.dstbuf.psm) { - case PSMCT16: TRANSFERLOCALLOCAL(16SZ, 16, 4); break; - case PSMCT16S: TRANSFERLOCALLOCAL(16SZ, 16S, 4); break; - case PSMT16Z: TRANSFERLOCALLOCAL(16SZ, 16Z, 4); break; - case PSMT16SZ: TRANSFERLOCALLOCAL(16SZ, 16SZ, 4); break; - } - break; - } - - g_MemTargs.ClearRange(dststart, dstend); - -#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) - if( g_bSaveTrans ) { - tex0Info t; - t.tbp0 = gs.dstbuf.bp; - t.tw = gs.imageWnew; - t.th = gs.imageHnew; - t.tbw = gs.dstbuf.bw; - t.psm = gs.dstbuf.psm; - SaveTex(&t, 0); - - t.tbp0 = gs.srcbuf.bp; - t.tw = gs.imageWnew; - t.th = gs.imageHnew; - t.tbw = gs.srcbuf.bw; - t.psm = gs.srcbuf.psm; - SaveTex(&t, 0); - } -#endif -} - -void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw) -{ - if( m_Blocks[psm].bpp == 0 ) { - ERROR_LOG("ZeroGS: Bad psm 0x%x\n", psm); - start = 0; - end = 0x00400000; - return; - } - - if( (psm&0x30) == 0x30 || psm == 0xa ) { - - const BLOCK& b = m_Blocks[psm]; - - bw = (bw + b.width -1)/b.width; - start = bp*256 + ((y/b.height) * bw + (x/b.width) )*0x2000; - end = bp*256 + (((y+h-1)/b.height) * bw + (x + w + b.width - 1)/b.width)*0x2000; - } - else { - // just take the addresses - switch(psm) { - case 0x00: - case 0x01: - case 0x1b: - case 0x24: - case 0x2c: - start = 4*getPixelAddress32(x, y, bp, bw); - end = 4*getPixelAddress32(x+w-1, y+h-1, bp, bw) + 4; - break; - case 0x02: - start = 2*getPixelAddress16(x, y, bp, bw); - end = 2*getPixelAddress16(x+w-1, y+h-1, bp, bw)+2; - break; - case 0x13: - start = getPixelAddress8(x, y, bp, bw); - end = getPixelAddress8(x+w-1, y+h-1, bp, bw)+1; - break; - case 0x14: - { - start = getPixelAddress4(x, y, bp, bw)/2; - int newx = ((x+w-1+31)&~31)-1; - int newy = ((y+h-1+15)&~15)-1; - end = (getPixelAddress4(max(newx,x), max(newy,y), bp, bw)+2)/2; - break; - } - } - } -} - -void _Resolve(const void* psrc, int fbp, int fbw, int fbh, int psm, u32 fbm) -{ - //assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); - s_nResolved += 2; - - // align the rect to the nearest page - // note that fbp is always aligned on page boundaries - int start, end; - GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); - - PRIM_LOG("resolve: %x %x %x (%x-%x)\n", fbp, fbw, fbh, start, end); - - int i, j; - short smask1 = gs.smask&1; - short smask2 = gs.smask&2; - u32 mask, imask; - - if( psm&2 ) { // 16 bit - // mask is shifted - imask = RGBA32to16(fbm); - mask = (~imask)&0xffff; - } - else { - mask = ~fbm; - imask = fbm; - - if( (psm&0xf)>0 ) { - // preserve the alpha? - mask &= 0x00ffffff; - imask |= 0xff000000; - } - } - int Pitch; - -#define RESOLVE_32BIT(psm, T, Tsrc, blockbits, blockwidth, blockheight, convfn, frame, aax, aay) \ - { \ - Tsrc* src = (Tsrc*)psrc; \ - T* pPageOffset = (T*)g_pbyGSMemory + fbp*(256/sizeof(T)), *dst; \ - int srcpitch = Pitch * blockheight/sizeof(Tsrc); \ - int maxfbh = (0x00400000-fbp*256) / (sizeof(T) * fbw); \ - if( maxfbh > fbh ) maxfbh = fbh; \ - for(i = 0; i < (maxfbh&~(blockheight-1)); i += blockheight) { \ - /*if( smask2 && (i&1) == smask1 ) continue; */ \ - for(j = 0; j < fbw; j += blockwidth) { \ - /* have to write in the tiled format*/ \ - frame##SwizzleBlock##blockbits(pPageOffset + getPixelAddress##psm##_0(j, i, fbw), \ - src+(j< psm - switch(psm) { - case PSMCT32: - case PSMCT24: - if( s_AAy ) { - RESOLVE_32BIT(32, u32, u32, 32A4, 8, 8, (u32), Frame, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(32, u32, u32, 32A2, 8, 8, (u32), Frame, 1, 0); - } - else { - RESOLVE_32BIT(32, u32, u32, 32, 8, 8, (u32), Frame, 0, 0); - } - break; - case PSMCT16: - if( s_AAy ) { - RESOLVE_32BIT(16, u16, u32, 16A4, 16, 8, RGBA32to16, Frame, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(16, u16, u32, 16A2, 16, 8, RGBA32to16, Frame, 1, 0); - } - else { - RESOLVE_32BIT(16, u16, u32, 16, 16, 8, RGBA32to16, Frame, 0, 0); - } - - break; - case PSMCT16S: - if( s_AAy ) { - RESOLVE_32BIT(16S, u16, u32, 16A4, 16, 8, RGBA32to16, Frame, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(16S, u16, u32, 16A2, 16, 8, RGBA32to16, Frame, 1, 0); - } - else { - RESOLVE_32BIT(16S, u16, u32, 16, 16, 8, RGBA32to16, Frame, 0, 0); - } - - break; - case PSMT32Z: - case PSMT24Z: - if( s_AAy ) { - RESOLVE_32BIT(32Z, u32, u32, 32A4, 8, 8, (u32), Frame, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(32Z, u32, u32, 32A2, 8, 8, (u32), Frame, 1, 0); - } - else { - RESOLVE_32BIT(32Z, u32, u32, 32, 8, 8, (u32), Frame, 0, 0); - } - - break; - case PSMT16Z: - if( s_AAy ) { - RESOLVE_32BIT(16Z, u16, u32, 16A4, 16, 8, (u16), Frame, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(16Z, u16, u32, 16A2, 16, 8, (u16), Frame, 1, 0); - } - else { - RESOLVE_32BIT(16Z, u16, u32, 16, 16, 8, (u16), Frame, 0, 0); - } - - break; - case PSMT16SZ: - if( s_AAy ) { - RESOLVE_32BIT(16SZ, u16, u32, 16A4, 16, 8, (u16), Frame, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(16SZ, u16, u32, 16A2, 16, 8, (u16), Frame, 1, 0); - } - else { - RESOLVE_32BIT(16SZ, u16, u32, 16, 16, 8, (u16), Frame, 0, 0); - } - - break; - } - } - else { // float16 - - Pitch = fbw * 8; - - switch(psm) { - case PSMCT32: - case PSMCT24: - if( s_AAy ) { - RESOLVE_32BIT(32, u32, Vector_16F, 32A4, 8, 8, Float16ToARGB, Frame16, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(32, u32, Vector_16F, 32A2, 8, 8, Float16ToARGB, Frame16, 1, 0); - } - else { - RESOLVE_32BIT(32, u32, Vector_16F, 32, 8, 8, Float16ToARGB, Frame16, 0, 0); - } - - break; - case PSMCT16: - if( s_AAy ) { - RESOLVE_32BIT(16, u16, Vector_16F, 16A4, 16, 8, Float16ToARGB16, Frame16, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(16, u16, Vector_16F, 16A2, 16, 8, Float16ToARGB16, Frame16, 1, 0); - } - else { - RESOLVE_32BIT(16, u16, Vector_16F, 16, 16, 8, Float16ToARGB16, Frame16, 0, 0); - } - - break; - case PSMCT16S: - if( s_AAy ) { - RESOLVE_32BIT(16S, u16, Vector_16F, 16A4, 16, 8, Float16ToARGB16, Frame16, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(16S, u16, Vector_16F, 16A2, 16, 8, Float16ToARGB16, Frame16, 1, 0); - } - else { - RESOLVE_32BIT(16S, u16, Vector_16F, 16, 16, 8, Float16ToARGB16, Frame16, 0, 0); - } - - break; - case PSMT32Z: - case PSMT24Z: - if( s_AAy ) { - RESOLVE_32BIT(32Z, u32, Vector_16F, 32ZA4, 8, 8, Float16ToARGB_Z, Frame16, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(32Z, u32, Vector_16F, 32ZA2, 8, 8, Float16ToARGB_Z, Frame16, 1, 0); - } - else { - RESOLVE_32BIT(32Z, u32, Vector_16F, 32Z, 8, 8, Float16ToARGB_Z, Frame16, 0, 0); - } - - break; - case PSMT16Z: - if( s_AAy ) { - RESOLVE_32BIT(16Z, u16, Vector_16F, 16ZA4, 16, 8, Float16ToARGB16_Z, Frame16, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(16Z, u16, Vector_16F, 16ZA2, 16, 8, Float16ToARGB16_Z, Frame16, 1, 0); - } - else { - RESOLVE_32BIT(16Z, u16, Vector_16F, 16Z, 16, 8, Float16ToARGB16_Z, Frame16, 0, 0); - } - - break; - case PSMT16SZ: - if( s_AAy ) { - RESOLVE_32BIT(16SZ, u16, Vector_16F, 16ZA4, 16, 8, Float16ToARGB16_Z, Frame16, 1, 1); - } - else if( s_AAx ) { - RESOLVE_32BIT(16SZ, u16, Vector_16F, 16ZA2, 16, 8, Float16ToARGB16_Z, Frame16, 1, 0); - } - else { - RESOLVE_32BIT(16SZ, u16, Vector_16F, 16Z, 16, 8, Float16ToARGB16_Z, Frame16, 0, 0); - } - - break; - } - } - - g_MemTargs.ClearRange(start, end); - INC_RESOLVE(); -} - -//////////// -// Saving // -//////////// -void SaveTex(tex0Info* ptex, int usevid) -{ - vector data(ptex->tw*ptex->th); - vector srcdata; - - u32* dst = &data[0]; - u8* psrc = g_pbyGSMemory; - - CMemoryTarget* pmemtarg = NULL; - - if( usevid ) { - - pmemtarg = g_MemTargs.GetMemoryTarget(*ptex, 0); - assert( pmemtarg != NULL ); - - glBindTexture(GL_TEXTURE_RECTANGLE_NV, pmemtarg->ptex->tex); - srcdata.resize(pmemtarg->realheight*GPU_TEXWIDTH*pmemtarg->widthmult*4*8); // max of 8 cannels - - glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, pmemtarg->fmt, &srcdata[0]); - - u32 offset = pmemtarg->realy * 4 * GPU_TEXWIDTH; - if( ptex->psm == PSMT8 ) offset *= ptex->cpsm <= 1 ? 4 : 2; - else if( ptex->psm == PSMT4 ) offset *= ptex->cpsm <= 1 ? 8 : 4; - - psrc = &srcdata[0] - offset; - } - - for(int i = 0; i < ptex->th; ++i) { - for(int j = 0; j < ptex->tw; ++j) { - u32 u, addr; - switch(ptex->psm) { - case PSMCT32: - addr = getPixelAddress32(j, i, ptex->tbp0, ptex->tbw); - - if( addr*4 < 0x00400000 ) - u = readPixel32(psrc, j, i, ptex->tbp0, ptex->tbw); - else u = 0; - - break; - case PSMCT24: - addr = getPixelAddress24(j, i, ptex->tbp0, ptex->tbw); - - if( addr*4 < 0x00400000 ) - u = readPixel24(psrc, j, i, ptex->tbp0, ptex->tbw); - else u = 0; - - break; - case PSMCT16: - addr = getPixelAddress16(j, i, ptex->tbp0, ptex->tbw); - - if( addr*2 < 0x00400000 ) { - u = readPixel16(psrc, j, i, ptex->tbp0, ptex->tbw); - u = RGBA16to32(u); - } - else u = 0; - - break; - case PSMCT16S: - addr = getPixelAddress16(j, i, ptex->tbp0, ptex->tbw); - - if( addr*2 < 0x00400000 ) { - u = readPixel16S(psrc, j, i, ptex->tbp0, ptex->tbw); - u = RGBA16to32(u); - } - else u = 0; - break; - - case PSMT8: - addr = getPixelAddress8(j, i, ptex->tbp0, ptex->tbw); - - if( addr < 0x00400000 ) { - if( usevid ) { - if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); - else u = RGBA16to32(*(u16*)(psrc+2*addr)); - } - else - u = readPixel8(psrc, j, i, ptex->tbp0, ptex->tbw); - } - else u = 0; - break; - - case PSMT4: - addr = getPixelAddress4(j, i, ptex->tbp0, ptex->tbw); - - if( addr < 2*0x00400000 ) { - if( usevid ) { - if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); - else u = RGBA16to32(*(u16*)(psrc+2*addr)); - } - else - u = readPixel4(psrc, j, i, ptex->tbp0, ptex->tbw); - } - else u = 0; - break; - - case PSMT8H: - addr = getPixelAddress8H(j, i, ptex->tbp0, ptex->tbw); - - if( 4*addr < 0x00400000 ) { - if( usevid ) { - if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); - else u = RGBA16to32(*(u16*)(psrc+2*addr)); - } - else - u = readPixel8H(psrc, j, i, ptex->tbp0, ptex->tbw); - } - else u = 0; - - break; - - case PSMT4HL: - addr = getPixelAddress4HL(j, i, ptex->tbp0, ptex->tbw); - - if( 4*addr < 0x00400000 ) { - if( usevid ) { - if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); - else u = RGBA16to32(*(u16*)(psrc+2*addr)); - } - else - u = readPixel4HL(psrc, j, i, ptex->tbp0, ptex->tbw); - } - else u = 0; - break; - - case PSMT4HH: - addr = getPixelAddress4HH(j, i, ptex->tbp0, ptex->tbw); - - if( 4*addr < 0x00400000 ) { - if( usevid ) { - if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); - else u = RGBA16to32(*(u16*)(psrc+2*addr)); - } - else - u = readPixel4HH(psrc, j, i, ptex->tbp0, ptex->tbw); - } - else u = 0; - break; - - case PSMT32Z: - addr = getPixelAddress32Z(j, i, ptex->tbp0, ptex->tbw); - - if( 4*addr < 0x00400000 ) - u = readPixel32Z(psrc, j, i, ptex->tbp0, ptex->tbw); - else u = 0; - break; - - case PSMT24Z: - addr = getPixelAddress24Z(j, i, ptex->tbp0, ptex->tbw); - - if( 4*addr < 0x00400000 ) - u = readPixel24Z(psrc, j, i, ptex->tbp0, ptex->tbw); - else u = 0; - break; - - case PSMT16Z: - addr = getPixelAddress16Z(j, i, ptex->tbp0, ptex->tbw); - - if( 2*addr < 0x00400000 ) - u = readPixel16Z(psrc, j, i, ptex->tbp0, ptex->tbw); - else u = 0; - break; - - case PSMT16SZ: - addr = getPixelAddress16SZ(j, i, ptex->tbp0, ptex->tbw); - - if( 2*addr < 0x00400000 ) - u = readPixel16SZ(psrc, j, i, ptex->tbp0, ptex->tbw); - else u = 0; - break; - - default: - assert(0); - } - - *dst++ = u; - } - } - - SaveTGA("tex.tga", ptex->tw, ptex->th, &data[0]); -} - -} +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 "GS.h" +#include +#include + +#include + +#include +#include +#include +#include + +#include "Mem.h" +#include "x86.h" +#include "zerogs.h" + +#include "targets.h" + +const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); + +extern int g_GameSettings; +using namespace ZeroGS; +extern int g_TransferredToGPU; +extern BOOL g_bIsLost; +extern BOOL g_bUpdateStencil; +extern u32 s_uFramebuffer; + +#ifdef RELEASE_TO_PUBLIC +#define INC_RESOLVE() +#else +#define INC_RESOLVE() ++g_nResolve +extern u32 g_nResolve; +extern BOOL g_bSaveTrans; +#endif + +namespace ZeroGS { + CRenderTargetMngr s_RTs, s_DepthRTs; + CBitwiseTextureMngr s_BitwiseTextures; + CMemoryTargetMngr g_MemTargs; + + extern u8 s_AAx, s_AAy; + extern Vector g_vdepth; + extern int icurctx; + + extern VERTEXSHADER pvsBitBlt; + extern FRAGMENTSHADER ppsBitBlt[2], ppsBitBltDepth, ppsOne; + extern FRAGMENTSHADER ppsBaseTexture, ppsConvert16to32, ppsConvert32to16; + extern GLuint vboRect; +} + +extern u32 s_ptexCurSet[2]; +extern u32 ptexBilinearBlocks; +extern u32 ptexConv32to16; +BOOL g_bSaveZUpdate = 0; + +//////////////////// +// Render Targets // +//////////////////// +ZeroGS::CRenderTarget::CRenderTarget() : ptex(0), ptexFeedback(0), psys(NULL) +{ + nUpdateTarg = 0; +} + +ZeroGS::CRenderTarget::~CRenderTarget() +{ + Destroy(); +} + +bool ZeroGS::CRenderTarget::Create(const frameInfo& frame) +{ + Resolve(); + Destroy(); + + lastused = timeGetTime(); + fbp = frame.fbp; + fbw = frame.fbw; + fbh = frame.fbh; + psm = (u8)frame.psm; + fbm = frame.fbm; + + vposxy.x = 2.0f * (1.0f / 8.0f) / (float)fbw; + vposxy.y = 2.0f * (1.0f / 8.0f) / (float)fbh; + vposxy.z = -1-0.5f/fbw; + vposxy.w = -1+0.5f/fbh; + status = 0; + + if( fbw > 0 && fbh > 0 ) { + GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); + + psys = _aligned_malloc( (fbh<= fbp ); + + dy = ((256/bpp)*(fbplocal-fbp)) / fbw; + + v.x = vposxy.x; + v.y = vposxy.y; + v.z = vposxy.z; + v.w = vposxy.w - dy*2.0f/(float)fbh; + cgGLSetParameter4fv(g_vparamPosXY[context], v); + } + else + cgGLSetParameter4fv(g_vparamPosXY[context], vposxy); + + // set render states + scissorrect.x = scissor.x0>>3; + scissorrect.y = (scissor.y0>>3) + dy; + scissorrect.w = (scissor.x1>>3)+1; + scissorrect.h = (scissor.y1>>3)+1+dy; + scissorrect.w = min(scissorrect.w, fbw) - scissorrect.x; + scissorrect.h = min(scissorrect.h, fbh) - scissorrect.y; + + scissorrect.x <<= s_AAx; + scissorrect.y <<= s_AAy; + scissorrect.w <<= s_AAx; + scissorrect.h <<= s_AAy; +} + +void ZeroGS::CRenderTarget::SetViewport() +{ + glViewport(0, 0, fbw< 10 || (g_GameSettings&GAME_NOTARGETRESOLVE) ) { + // don't resolve if depths aren't used + status = TS_Resolved; + return; + } + + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptex); + GL_REPORT_ERRORD(); + //glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), GetRenderFormat()==RFT_float16?GL_FLOAT:GL_UNSIGNED_BYTE, psys); + glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, GL_UNSIGNED_BYTE, psys); + GL_REPORT_ERRORD(); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveResolved ) { + SaveTexture("resolved.tga", GL_TEXTURE_RECTANGLE_NV, ptex, fbw< start ); // make sure it at least intersects + + if( ptex != 0 && !(status&TS_Resolved) && !(status&TS_NeedUpdate) ) { + + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveResolved ) { + SaveTexture("resolved.tga", GL_TEXTURE_RECTANGLE_NV, ptex, fbw<>6); + + // in now way should data be overwritten!, instead resolve less + if( endrange < end ) { + // round down to nearest block and scanline + resolveheight = ((endrange-start)/(0x2000*(fbw>>6))) * blockheight; + if( resolveheight <= 32 ) { + status = TS_Resolved; + return; + } + } + else if( startrange > start ) { + // round up to nearest block and scanline + resolvefbp = startrange + scanlinewidth - 1; + resolvefbp -= resolvefbp % scanlinewidth; + + resolveheight = fbh-((resolvefbp-fbp)*blockheight/scanlinewidth); + if( resolveheight <= 64 ) { // this is a total hack, but kh doesn't resolve now + status = TS_Resolved; + return; + } + + resolvefbp >>= 8; + } + + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptex); + //glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), GetRenderFormat()==RFT_float16?GL_FLOAT:GL_UNSIGNED_BYTE, psys); + glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, GL_UNSIGNED_BYTE, psys); + GL_REPORT_ERRORD(); + + u8* pbits = (u8*)psys; + u32 Pitch = (fbw<SetDepthStencilSurface(psurfDepth); + ResetRenderTarget(1); + SetRenderTarget(0); + assert( pdepth != NULL ); + ((CDepthTarget*)pdepth)->SetDepthStencilSurface(); + + Vector v = Vector(1,-1,-0.5f/(float)(fbw<second == this ) { + ERROR_LOG("updating self"); + nUpdateTarg = 0; + } + } + else if( ittarg->second == this ) { + ERROR_LOG("updating self"); + nUpdateTarg = 0; + } + } + + SetViewport(); + + if( nUpdateTarg ) { + + cgGLSetTextureParameter(ppsBaseTexture.sFinal, ittarg->second->ptex); + cgGLEnableTextureParameter(ppsBaseTexture.sFinal); + + //assert( ittarg->second->fbw == fbw ); + int offset = (fbp-ittarg->second->fbp)*64/fbw; + if( psm & 2 ) // 16 bit + offset *= 2; + + v.x = (float)(fbw << s_AAx); + v.y = (float)(fbh << s_AAy); + v.z = 0.25f; + v.w = (float)(offset << s_AAy) + 0.25f; + cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); + + v.x = v.y = v.z = v.w = 1; + cgGLSetParameter4fv(ppsBaseTexture.sOneColor, v); + + SETPIXELSHADER(ppsBaseTexture.prog); + nUpdateTarg = 0; + } + else { + // align the rect to the nearest page + // note that fbp is always aligned on page boundaries + tex0Info texframe; + texframe.tbp0 = fbp; + texframe.tbw = fbw; + texframe.tw = fbw; + texframe.th = fbh; + texframe.psm = psm; + CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); + + // write color and zero out stencil buf, always 0 context! + // force bilinear if using AA + SetTexVariablesInt(0, (s_AAx || s_AAy)?2:0, texframe, pmemtarg, &ppsBitBlt[s_AAx], 1); + cgGLSetTextureParameter(ppsBitBlt[s_AAx].sMemory, pmemtarg->ptex->tex); + cgGLEnableTextureParameter(ppsBitBlt[s_AAx].sMemory); + + v = Vector(1,1,0,0); + cgGLSetParameter4fv(pvsBitBlt.sBitBltTex, v); + + v.x = 1; + v.y = 2; + cgGLSetParameter4fv(ppsBitBlt[s_AAx].sOneColor, v); + + assert( ptex != 0 ); + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + if( ZeroGS::IsWriteDestAlphaTest() ) { + glEnable(GL_STENCIL_TEST); + glStencilFunc(GL_ALWAYS, 0, 0xff); + glStencilMask(0xff); + glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO); + } + + // render with an AA shader if possible (bilinearly interpolates data) + //cgGLLoadProgram(ppsBitBlt[s_AAx].prog); + SETPIXELSHADER(ppsBitBlt[s_AAx].prog); + } + + SETVERTEXSHADER(pvsBitBlt.prog); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + // fill stencil buf only + if( ZeroGS::IsWriteDestAlphaTest() && !(g_GameSettings&GAME_NOSTENCIL)) { + glColorMask(0,0,0,0); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GEQUAL, 1); + + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + glStencilFunc(GL_ALWAYS, 1, 0xff); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glColorMask(1,1,1,1); + } + + glEnable(GL_SCISSOR_TEST); + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + if( conf.mrtdepth && pdepth != NULL && ZeroGS::IsWriteDepth() ) + pdepth->SetRenderTarget(1); + + status = TS_Resolved; + + // reset since settings changed + vb[0].bVarsTexSync = 0; + ZeroGS::ResetAlphaVariables(); +} + +void ZeroGS::CRenderTarget::ConvertTo32() +{ + u32 ptexConv; + + // create new target + glGenTextures(1, &ptexConv); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexConv); + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), fbw<= 0 ) { + // reset since settings changed + vb[icurctx].bVarsTexSync = 0; + vb[icurctx].bVarsSetTarg = 0; + } + vb[0].bVarsTexSync = 0; +} + +void ZeroGS::CRenderTarget::ConvertTo16() +{ + u32 ptexConv; + + // create new target + glGenTextures(1, &ptexConv); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexConv); + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), fbw<Create(frame); +// s_DepthRTs.mapDummyTargs[(fbw<<16)|fbh] = pnewdepth; +// } +// else pnewdepth = (CDepthTarget*)itdepth->second; +// +// assert( pnewdepth != NULL ); +// pd3dDevice->SetDepthStencilSurface(pnewdepth->pdepth); + + SetViewport(); + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + // render with an AA shader if possible (bilinearly interpolates data) + SETVERTEXSHADER(pvsBitBlt.prog); + SETPIXELSHADER(ppsConvert32to16.prog); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + +#ifdef _DEBUG + //g_bSaveZUpdate = 1; + if( g_bSaveZUpdate ) { + SaveTexture("tex1.tga", GL_TEXTURE_RECTANGLE_NV, ptexConv, fbw<= 0 ) { + // reset since settings changed + vb[icurctx].bVarsTexSync = 0; + vb[icurctx].bVarsSetTarg = 0; + } + vb[0].bVarsTexSync = 0; +} + +void ZeroGS::CRenderTarget::_CreateFeedback() +{ + if( ptexFeedback == 0 ) { + // create + glGenTextures(1, &ptexFeedback); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexFeedback); + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), fbw<= 0 ) { + // reset since settings changed + vb[icurctx].bVarsTexSync = 0; + } + + assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); +} + +void ZeroGS::CRenderTarget::SetRenderTarget(int targ) +{ + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+targ, GL_TEXTURE_RECTANGLE_NV, ptex, 0 ); + //assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); +} + +ZeroGS::CDepthTarget::CDepthTarget() : CRenderTarget(), pdepth(0), pstencil(0), icount(0) {} + +ZeroGS::CDepthTarget::~CDepthTarget() +{ + Destroy(); +} + +bool ZeroGS::CDepthTarget::Create(const frameInfo& frame) +{ + if( !CRenderTarget::Create(frame) ) + return false; + + if( psm == 0x31 ) fbm = 0xff000000; + else fbm = 0; + + assert( glGetError() == GL_NO_ERROR ); + + glGenRenderbuffersEXT( 1, &pdepth ); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, pdepth); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, fbw< 0 if depth is used + +void ZeroGS::CDepthTarget::Resolve() +{ + if( g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && ZeroGS::IsWriteDepth() && !(g_GameSettings&GAME_NODEPTHRESOLVE) ) + CRenderTarget::Resolve(); + else { + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + + if( !(status & TS_Virtual) ) + status |= TS_Resolved; + } + + if( !(status&TS_Virtual) ) { + ZeroGS::SetWriteDepth(); + } +} + +void ZeroGS::CDepthTarget::Resolve(int startrange, int endrange) +{ + if( g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && ZeroGS::IsWriteDepth() ) CRenderTarget::Resolve(startrange, endrange); + else { + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + + if( !(status & TS_Virtual) ) + status |= TS_Resolved; + } + + if( !(status&TS_Virtual) ) { + ZeroGS::SetWriteDepth(); + } +} + +extern int g_nDepthUpdateCount; + +void ZeroGS::CDepthTarget::Update(int context, ZeroGS::CRenderTarget* prndr) +{ + assert( !(status & TS_Virtual) ); + + // align the rect to the nearest page + // note that fbp is always aligned on page boundaries + tex0Info texframe; + texframe.tbp0 = fbp; + texframe.tbw = fbw; + texframe.tw = fbw; + texframe.th = fbh; + texframe.psm = psm; + CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); + + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + glEnable(GL_DEPTH_TEST); + glDepthMask(1); + glDisable(GL_STENCIL_TEST); + glDepthFunc(GL_ALWAYS); + + // write color and zero out stencil buf, always 0 context! + SetTexVariablesInt(0, 0, texframe, pmemtarg, &ppsBitBltDepth, 1); + cgGLSetTextureParameter(ppsBitBltDepth.sMemory, pmemtarg->ptex->tex); + cgGLEnableTextureParameter(ppsBaseTexture.sFinal); + + Vector v = Vector(1,-1,0.5f/(float)fbw,-0.5f/(float)fbh); + cgGLSetParameter4fv(pvsBitBlt.sBitBltTex, v); + + v.z = v.w = 0; + v *= 1/32767.0f; + cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); + + v.x = 1; + v.y = 2; + v.z = (psm&3)==2?1.0f:0.0f; + v.w = g_filog32; + cgGLSetParameter4fv(ppsBitBltDepth.sOneColor, v); + + Vector vdepth = ((255.0f/256.0f)*g_vdepth); + if( psm == PSMT24Z ) vdepth.w = 0; + else if( psm != PSMT32Z ) { vdepth.z = vdepth.w = 0; } + assert( ppsBitBltDepth.sBitBltZ != 0 ); + cgGLSetParameter4fv(ppsBitBltDepth.sBitBltZ, ((255.0f/256.0f)*vdepth)); + + assert( pdepth != 0 ); + + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_NV, ptex, 0 ); + SetDepthStencilSurface(); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_NV, 0, 0 ); + GLenum buffer = GL_COLOR_ATTACHMENT0_EXT; + if( glDrawBuffers != NULL ) + glDrawBuffers(1, &buffer); + int stat = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); + + SetViewport(); + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + glBindBuffer(GL_ARRAY_BUFFER, vboRect); + SET_STREAM(); + + SETVERTEXSHADER(pvsBitBlt.prog); + SETPIXELSHADER(ppsBitBltDepth.prog); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + status = TS_Resolved; + + if( !ZeroGS::IsWriteDepth() ) { + ResetRenderTarget(1); + } + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glEnable(GL_SCISSOR_TEST); + +#ifdef _DEBUG + if( g_bSaveZUpdate ) { + SaveTex(&texframe, 1); + SaveTexture("frame1.tga", GL_TEXTURE_RECTANGLE_NV, ptex, fbw<second; + mapTargets.clear(); + for(MAPTARGETS::iterator it = mapDummyTargs.begin(); it != mapDummyTargs.end(); ++it) + delete it->second; + mapDummyTargs.clear(); +} + +void ZeroGS::CRenderTargetMngr::DestroyAllTargs(int start, int end, int fbw) +{ + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end();) { + if( it->second->start < end && start < it->second->end ) { + // if is depth, only resolve if fbw is the same + if( !it->second->IsDepth() ) { + // only resolve if the widths are the same or it->second has bit outside the range + // shadow of colossus swaps between fbw=256,fbh=256 and fbw=512,fbh=448. This kills the game if doing || it->second->end > end + + // kh hack, sometimes kh movies do this to clear the target, so have a static count that periodically checks end + static int count = 0; + + if( it->second->fbw == fbw || (it->second->fbw != fbw && (it->second->start < start || ((count++&0xf)?0:it->second->end > end) )) ) + it->second->Resolve(); + else { + if( vb[0].prndr == it->second || vb[0].pdepth == it->second ) Flush(0); + if( vb[1].prndr == it->second || vb[1].pdepth == it->second ) Flush(1); + + it->second->status |= CRenderTarget::TS_Resolved; + } + } + else { + if( it->second->fbw == fbw ) + it->second->Resolve(); + else { + if( vb[0].prndr == it->second || vb[0].pdepth == it->second ) Flush(0); + if( vb[1].prndr == it->second || vb[1].pdepth == it->second ) Flush(1); + + it->second->status |= CRenderTarget::TS_Resolved; + } + } + + for(int i = 0; i < 2; ++i) { + if( it->second == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } + if( it->second == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } + } + + u32 dummykey = (it->second->fbw<<16)|it->second->fbh; + if( mapDummyTargs.find(dummykey) == mapDummyTargs.end() ) { + mapDummyTargs[dummykey] = it->second; + } + else + delete it->second; + mapTargets.erase(it++); + } + else ++it; + } +} + +void ZeroGS::CRenderTargetMngr::DestroyTarg(CRenderTarget* ptarg) +{ + for(int i = 0; i < 2; ++i) { + if( ptarg == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } + if( ptarg == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } + } + + delete ptarg; +} + +void ZeroGS::CRenderTargetMngr::DestroyIntersecting(CRenderTarget* prndr) +{ + assert( prndr != NULL ); + + int start, end; + GetRectMemAddress(start, end, prndr->psm, 0, 0, prndr->fbw, prndr->fbh, prndr->fbp, prndr->fbw); + + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end();) { + if( it->second != prndr && it->second->start < end && start < it->second->end ) { + it->second->Resolve(); + + for(int i = 0; i < 2; ++i) { + if( it->second == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } + if( it->second == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } + } + + u32 dummykey = (it->second->fbw<<16)|it->second->fbh; + if( mapDummyTargs.find(dummykey) == mapDummyTargs.end() ) { + mapDummyTargs[dummykey] = it->second; + } + else + delete it->second; + + mapTargets.erase(it++); + } + else ++it; + } +} + +CRenderTarget* ZeroGS::CRenderTargetMngr::GetTarg(const frameInfo& frame, u32 opts, int maxposheight) +{ + if( frame.fbw <= 0 || frame.fbh <= 0 ) + return NULL; + + GL_REPORT_ERRORD(); + + u32 key = frame.fbp|(frame.fbw<<16); + MAPTARGETS::iterator it = mapTargets.find(key); + + // only enforce height if frame.fbh <= 0x1c0 + bool bfound = it != mapTargets.end(); + if( bfound ) { + if( opts&TO_StrictHeight ) { + bfound = it->second->fbh == frame.fbh; + } + else { + if( (frame.psm&2)==(it->second->psm&2) && !(g_GameSettings & GAME_FULL16BITRES) ) + bfound = (frame.fbh > 0x1c0 || it->second->fbh >= frame.fbh) && it->second->fbh <= maxposheight; + } + } + + if( !bfound ) { + // might be a virtual target + it = mapTargets.find(key|TARGET_VIRTUAL_KEY); + bfound = it != mapTargets.end() && ((opts&TO_StrictHeight) ? it->second->fbh == frame.fbh : it->second->fbh >= frame.fbh) && it->second->fbh <= maxposheight; + } + + if( bfound ) { + + // can be both 16bit and 32bit + if( (frame.psm&2) != (it->second->psm&2) ) { + // a lot of games do this actually... +#ifdef _DEBUG + WARN_LOG("Really bad formats! %d %d\n", frame.psm, it->second->psm); +#endif +// if( g_GameSettings & GAME_VSSHACK ) { +// if( it->second->psm & 2 ) { +// it->second->status |= CRenderTarget::TS_NeedConvert32; +// it->second->fbh /= 2; +// } +// else { +// it->second->status |= CRenderTarget::TS_NeedConvert16; +// it->second->fbh *= 2; +// } +// } + + // recalc extents + GetRectMemAddress(it->second->start, it->second->end, frame.psm, 0, 0, frame.fbw, it->second->fbh, it->second->fbp, frame.fbw); + } + else { + // certain variables have to be reset every time + if( (it->second->psm&~1) != (frame.psm&~1) ) { +#ifndef RELEASE_TO_PUBLIC + WARN_LOG("bad formats 2: %d %d\n", frame.psm, it->second->psm); +#endif + it->second->psm = frame.psm; + + // recalc extents + GetRectMemAddress(it->second->start, it->second->end, frame.psm, 0, 0, frame.fbw, it->second->fbh, it->second->fbp, frame.fbw); + } + } + + if( it->second->fbm != frame.fbm ) { + //WARN_LOG("bad fbm: 0x%8.8x 0x%8.8x, psm: %d\n", frame.fbm, it->second->fbm, frame.psm); + } + + it->second->fbm &= frame.fbm; + it->second->psm = frame.psm; // have to convert (ffx2) + + if( (it->first & TARGET_VIRTUAL_KEY) && !(opts&TO_Virtual) ) { + // switch + it->second->lastused = timeGetTime(); + return Promote(it->first&~TARGET_VIRTUAL_KEY); + } + + // check if there exists a more recent target that this target could update from + for(MAPTARGETS::iterator itnew = mapTargets.begin(); itnew != mapTargets.end(); ++itnew) { + if( itnew->second != it->second && itnew->second->start <= it->second->start && itnew->second->end >= it->second->end && + itnew->second->lastused > it->second->lastused && !(itnew->second->status & CRenderTarget::TS_NeedUpdate) ) { + + it->second->status |= CRenderTarget::TS_NeedUpdate; + it->second->nUpdateTarg = itnew->first; + break; + } + } + + it->second->lastused = timeGetTime(); + + return it->second; + } + + // NOTE: instead of resolving, if current render targ is completely outside of old, can transfer + // the data like that. + + // have to change, so recreate (find all intersecting targets and Resolve) + u32 besttarg = 0; + + if( !(opts & CRenderTargetMngr::TO_Virtual) ) { + + int start, end; + GetRectMemAddress(start, end, frame.psm, 0, 0, frame.fbw, frame.fbh, frame.fbp, frame.fbw); + + if( !(opts & CRenderTargetMngr::TO_StrictHeight) ) { + + // if there is only one intersecting target and it encompasses the current one, update the new render target with + // its data instead of resolving then updating (ffx2). Do not change the original target. + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end ) { +// if( g_GameSettings&GAME_FASTUPDATE ) { +// besttarg = it->first; +// //break; +// } +// else { + if( (g_GameSettings&GAME_FASTUPDATE) || (it->second->fbp != frame.fbp && it->second->fbw == frame.fbw) ) { + + if( besttarg != 0 ) { + besttarg = 0; + break; + } + + if( start >= it->second->start && end <= it->second->end ) { + besttarg = it->first; + } + } +// } + } + } + } + + if( besttarg == 0 ) { + // if none found, resolve all + DestroyAllTargs(start, end, frame.fbw); + } + } + + if( mapTargets.size() > 8 ) { + // release some resources + it = GetOldestTarg(mapTargets); + + // if more than 5s passed since target used, destroy + if( timeGetTime()-it->second->lastused > 5000 ) { + delete it->second; + mapTargets.erase(it); + } + } + + if( mapDummyTargs.size() > 8 ) { + it = GetOldestTarg(mapDummyTargs); + + delete it->second; + mapDummyTargs.erase(it); + } + + // first search for the target + CRenderTarget* ptarg = NULL; + + it = mapDummyTargs.find( (frame.fbw<<16)|frame.fbh ); + if( it != mapDummyTargs.end() ) { + ptarg = it->second; + mapDummyTargs.erase(it); + + // restore all setttings + ptarg->psm = frame.psm; + ptarg->fbm = frame.fbm; + ptarg->fbp = frame.fbp; + GetRectMemAddress(ptarg->start, ptarg->end, frame.psm, 0, 0, frame.fbw, frame.fbh, frame.fbp, frame.fbw); + + ptarg->status = CRenderTarget::TS_NeedUpdate; + } + else { + // create anew + ptarg = (opts&TO_DepthBuffer) ? new CDepthTarget() : new CRenderTarget(); + CRenderTargetMngr* pmngrs[2] = { &s_DepthRTs, this == &s_RTs ? &s_RTs : NULL }; + int cur = 0; + + while( !ptarg->Create(frame) ) { + + // destroy unused targets + if( mapDummyTargs.size() > 0 ) { + it = mapDummyTargs.begin(); + delete it->second; + mapDummyTargs.erase(it); + continue; + } + + if( g_MemTargs.listClearedTargets.size() > 0 ) { + g_MemTargs.DestroyCleared(); + continue; + } + else + if( g_MemTargs.listTargets.size() > 32 ) { + g_MemTargs.DestroyOldest(); + continue; + } + + if( pmngrs[cur] == NULL ) { + cur = !cur; + if( pmngrs[cur] == NULL ) { + WARN_LOG("Out of memory!\n"); + delete ptarg; + return NULL; + } + } + + if( pmngrs[cur]->mapTargets.size() == 0 ) + { + pmngrs[cur] = NULL; + cur = !cur; + continue; + } + + it = GetOldestTarg(pmngrs[cur]->mapTargets); + + DestroyTarg(it->second); + pmngrs[cur]->mapTargets.erase(it); + cur = !cur; + } + } + + if( (opts & CRenderTargetMngr::TO_Virtual) ) { + ptarg->status = CRenderTarget::TS_Virtual; + key |= TARGET_VIRTUAL_KEY; + + if( (it = mapTargets.find(key)) != mapTargets.end() ) { + + DestroyTarg(it->second); + it->second = ptarg; + ptarg->nUpdateTarg = besttarg; + return ptarg; + } + } + else + assert( mapTargets.find(key) == mapTargets.end()); + + ptarg->nUpdateTarg = besttarg; + mapTargets[key] = ptarg; + return ptarg; +} + +ZeroGS::CRenderTargetMngr::MAPTARGETS::iterator ZeroGS::CRenderTargetMngr::GetOldestTarg(MAPTARGETS& m) +{ + if( m.size() == 0 ) { + return m.end(); + } + + // release some resources + u32 curtime = timeGetTime(); + MAPTARGETS::iterator itmaxtarg = m.begin(); + for(MAPTARGETS::iterator it = ++m.begin(); it != m.end(); ++it) { + if( itmaxtarg->second->lastused-curtime < it->second->lastused-curtime ) itmaxtarg = it; + } + + return itmaxtarg; +} + +void ZeroGS::CRenderTargetMngr::GetTargs(int start, int end, list& listTargets) const +{ + for(MAPTARGETS::const_iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end ) listTargets.push_back(it->second); + } +} + +void ZeroGS::CRenderTargetMngr::Resolve(int start, int end) +{ + for(MAPTARGETS::const_iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end ) + it->second->Resolve(); + } +} + +void ZeroGS::CMemoryTargetMngr::Destroy() +{ + listTargets.clear(); + listClearedTargets.clear(); +} + +int memcmp_clut16(u16* pSavedBuffer, u16* pClutBuffer, int clutsize) +{ + assert( (clutsize&31) == 0 ); + + // left > 0 only when csa < 16 + int left = ((u32)(uptr)pClutBuffer & 2) ? 0 : (((u32)(uptr)pClutBuffer & 0x3ff)/2) + clutsize - 512; + if( left > 0 ) clutsize -= left; + + while(clutsize > 0) { + for(int i = 0; i < 16; ++i) { + if( pSavedBuffer[i] != pClutBuffer[2*i] ) + return 1; + } + + clutsize -= 32; + pSavedBuffer += 16; + pClutBuffer += 32; + } + + if( left > 0 ) { + pClutBuffer = (u16*)(g_pbyGSClut + 2); + + while(left > 0) { + for(int i = 0; i < 16; ++i) { + if( pSavedBuffer[i] != pClutBuffer[2*i] ) + return 1; + } + + left -= 32; + pSavedBuffer += 16; + pClutBuffer += 32; + } + } + + return 0; +} + +bool ZeroGS::CMemoryTarget::ValidateClut(const tex0Info& tex0) +{ + assert( tex0.psm == psm && PSMT_ISCLUT(psm) && cpsm == tex0.cpsm ); + + int nClutOffset = 0; + int clutsize = 0; + + int entries = (tex0.psm&3)==3 ? 256 : 16; + if( tex0.cpsm <= 1 ) { // 32 bit + nClutOffset = 64 * tex0.csa; + clutsize = min(entries, 256-tex0.csa*16)*4; + } + else { + nClutOffset = 32 * (tex0.csa&15) + (tex0.csa>=16?2:0); + clutsize = min(entries, 512-tex0.csa*16)*2; + } + + assert( clutsize == clut.size() ); + + if( cpsm <= 1 ) { + if( memcmp_mmx(&clut[0], g_pbyGSClut+nClutOffset, clutsize) ) + return false; + } + else { + if( memcmp_clut16((u16*)&clut[0], (u16*)(g_pbyGSClut+nClutOffset), clutsize) ) + return false; + } + + return true; +} + +int VALIDATE_THRESH = 8; +u32 TEXDESTROY_THRESH = 16; + +bool ZeroGS::CMemoryTarget::ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex) +{ + if( clearmaxy == 0 ) + return true; + + int checkstarty = max(starttex, clearminy); + int checkendy = min(endtex, clearmaxy); + if( checkstarty >= checkendy ) + return true; + + if( validatecount++ > VALIDATE_THRESH ) { + height = 0; + return false; + } + + // lock and compare + assert( ptex != NULL && ptex->memptr != NULL); + + int result = memcmp_mmx(ptex->memptr + (checkstarty-realy)*4*GPU_TEXWIDTH, g_pbyGSMemory+checkstarty*4*GPU_TEXWIDTH, (checkendy-checkstarty)*4*GPU_TEXWIDTH); + + if( result == 0 || !bDeleteBadTex ) { + if( result == 0 ) clearmaxy = 0; + return result == 0; + } + + // delete clearminy, clearmaxy range (not the checkstarty, checkendy range) + int newstarty = 0; + if( clearminy <= starty ) { + if( clearmaxy < starty + height) { + // preserve end + height = starty+height-clearmaxy; + starty = clearmaxy; + assert(height > 0); + } + else { + // destroy + height = 0; + } + } + else { + // beginning can be preserved + height = clearminy-starty; + } + + clearmaxy = 0; + assert( starty >= realy && starty+height<=realy+realheight ); + + return false; +} + +// used to build clut textures (note that this is for both 16 and 32 bit cluts) +#define BUILDCLUT() { \ + switch(tex0.psm) { \ + case PSMT8: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/2; ++j) { \ + pdst[0] = pclut[psrc[0]]; \ + pdst[1] = pclut[psrc[1]]; \ + pdst[2] = pclut[psrc[2]]; \ + pdst[3] = pclut[psrc[3]]; \ + pdst[4] = pclut[psrc[4]]; \ + pdst[5] = pclut[psrc[5]]; \ + pdst[6] = pclut[psrc[6]]; \ + pdst[7] = pclut[psrc[7]]; \ + pdst += 8; \ + psrc += 8; \ + } \ + } \ + break; \ + case PSMT4: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH; ++j) { \ + pdst[0] = pclut[psrc[0]&15]; \ + pdst[1] = pclut[psrc[0]>>4]; \ + pdst[2] = pclut[psrc[1]&15]; \ + pdst[3] = pclut[psrc[1]>>4]; \ + pdst[4] = pclut[psrc[2]&15]; \ + pdst[5] = pclut[psrc[2]>>4]; \ + pdst[6] = pclut[psrc[3]&15]; \ + pdst[7] = pclut[psrc[3]>>4]; \ + \ + pdst += 8; \ + psrc += 4; \ + } \ + } \ + break; \ + case PSMT8H: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ + pdst[0] = pclut[psrc[3]]; \ + pdst[1] = pclut[psrc[7]]; \ + pdst[2] = pclut[psrc[11]]; \ + pdst[3] = pclut[psrc[15]]; \ + pdst[4] = pclut[psrc[19]]; \ + pdst[5] = pclut[psrc[23]]; \ + pdst[6] = pclut[psrc[27]]; \ + pdst[7] = pclut[psrc[31]]; \ + pdst += 8; \ + psrc += 32; \ + } \ + } \ + break; \ + case PSMT4HH: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ + pdst[0] = pclut[psrc[3]>>4]; \ + pdst[1] = pclut[psrc[7]>>4]; \ + pdst[2] = pclut[psrc[11]>>4]; \ + pdst[3] = pclut[psrc[15]>>4]; \ + pdst[4] = pclut[psrc[19]>>4]; \ + pdst[5] = pclut[psrc[23]>>4]; \ + pdst[6] = pclut[psrc[27]>>4]; \ + pdst[7] = pclut[psrc[31]>>4]; \ + pdst += 8; \ + psrc += 32; \ + } \ + } \ + break; \ + case PSMT4HL: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ + pdst[0] = pclut[psrc[3]&15]; \ + pdst[1] = pclut[psrc[7]&15]; \ + pdst[2] = pclut[psrc[11]&15]; \ + pdst[3] = pclut[psrc[15]&15]; \ + pdst[4] = pclut[psrc[19]&15]; \ + pdst[5] = pclut[psrc[23]&15]; \ + pdst[6] = pclut[psrc[27]&15]; \ + pdst[7] = pclut[psrc[31]&15]; \ + pdst += 8; \ + psrc += 32; \ + } \ + } \ + break; \ + default: \ + assert(0); \ + } \ +} \ + +#define TARGET_THRESH 0x500 + +extern int g_MaxTexWidth, g_MaxTexHeight; + +//#define SORT_TARGETS +inline list::iterator ZeroGS::CMemoryTargetMngr::DestroyTargetIter(list::iterator& it) +{ + // find the target and destroy + list::iterator itprev = it; ++it; + listClearedTargets.splice(listClearedTargets.end(), listTargets, itprev); + + if( listClearedTargets.size() > TEXDESTROY_THRESH ) { + listClearedTargets.pop_front(); + } + + return it; +} + +#if defined(_MSC_VER) && defined(__x86_64__) +extern "C" void UnswizzleZ16Target(void* dst, void* src, int iters); +#endif + +ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::GetMemoryTarget(const tex0Info& tex0, int forcevalidate) +{ + int nbStart, nbEnd; + GetRectMemAddress(nbStart, nbEnd, tex0.psm, 0, 0, tex0.tw, tex0.th, tex0.tbp0, tex0.tbw); + assert( nbStart < nbEnd ); + nbEnd = min(nbEnd, 0x00400000); + + int nClutOffset = 0; + int clutsize = 0; + + if( PSMT_ISCLUT(tex0.psm) ) { + int entries = (tex0.psm&3)==3 ? 256 : 16; + if( tex0.cpsm <= 1 ) { // 32 bit + nClutOffset = 64 * tex0.csa; + clutsize = min(entries, 256-tex0.csa*16)*4; + } + else { + nClutOffset = 64 * (tex0.csa&15) + (tex0.csa>=16?2:0); + clutsize = min(entries, 512-tex0.csa*16)*2; + } + } + + DVProfileFunc _pf("GetMemoryTarget"); + + int start = nbStart / (4*GPU_TEXWIDTH); + int end = (nbEnd + GPU_TEXWIDTH*4 - 1) / (4*GPU_TEXWIDTH); + assert( start < end ); + + for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { + + if( it->starty <= start && it->starty+it->height >= end ) { + + assert( it->psm != 0xd ); + + // using clut, validate that same data + if( PSMT_ISCLUT(it->psm) != PSMT_ISCLUT(tex0.psm) ) { + if( it->validatecount++ > VALIDATE_THRESH ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else + ++it; + continue; + } + + if( PSMT_ISCLUT(tex0.psm) ) { + assert( it->clut.size() > 0 ); + + if( it->psm != tex0.psm || it->cpsm != tex0.cpsm || it->clut.size() != clutsize ) { + // wrong clut + if( it->validatecount++ > VALIDATE_THRESH ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else + ++it; + continue; + } + + if( tex0.cpsm <= 1 ) { + if( memcmp_mmx(&it->clut[0], g_pbyGSClut+nClutOffset, clutsize) ) { + ++it; + continue; + } + } + else { + if( memcmp_clut16((u16*)&it->clut[0], (u16*)(g_pbyGSClut+nClutOffset), clutsize) ) { + ++it; + continue; + } + } + } + else if( PSMT_IS16BIT(tex0.psm) != PSMT_IS16BIT(it->psm) ) { + + if( it->validatecount++ > VALIDATE_THRESH ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else + ++it; + + continue; + } + + if( forcevalidate ) {//&& listTargets.size() < TARGET_THRESH ) { + // do more validation checking. delete if not been used for a while + if( !it->ValidateTex(tex0, start, end, curstamp > it->usedstamp + 3) ) { + if( it->height <= 0 ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else + ++it; + continue; + } + } + + it->usedstamp = curstamp; + it->validatecount = 0; + + return &(*it); + } +#ifdef SORT_TARGETS + else if( it->starty >= end ) + break; +#endif + + ++it; + } + + // couldn't find so create + DVProfileFunc _pf1("GetMemoryTarget:Create"); + + CMemoryTarget* targ; + + u32 fmt = GL_UNSIGNED_BYTE; + if( (PSMT_ISCLUT(tex0.psm) && tex0.cpsm > 1) || tex0.psm == PSMCT16 || tex0.psm == PSMCT16S) { + fmt = GL_UNSIGNED_SHORT_1_5_5_5_REV; + } + + int widthmult = 1; + if( g_MaxTexHeight < 4096 ) { + if( end-start > g_MaxTexHeight ) + widthmult = 2; + } + + int channels = 1; + if( PSMT_ISCLUT(tex0.psm) ) { + if( tex0.psm == PSMT8 ) channels = 4; + else if( tex0.psm == PSMT4 ) channels = 8; + } + else { + if( PSMT_IS16BIT(tex0.psm) ) { + // 16z needs to be a8r8g8b8 + channels = 2; + } + } + + if( listClearedTargets.size() > 0 ) { + + list::iterator itbest = listClearedTargets.begin(); + while(itbest != listClearedTargets.end()) { + + if( end-start <= itbest->realheight && itbest->fmt == fmt && itbest->widthmult == widthmult && itbest->channels == channels ) { + // check channels + int targchannels = 1; + if( PSMT_ISCLUT(itbest->psm) ) { + if( itbest->psm == PSMT8 ) targchannels = 4; + else if( itbest->psm == PSMT4 ) targchannels = 8; + } + else if( PSMT_IS16BIT(itbest->psm) ) { + targchannels = 2; + } + if( targchannels == channels ) + break; + } + ++itbest; + } + + if( itbest != listClearedTargets.end()) { + listTargets.splice(listTargets.end(), listClearedTargets, itbest); + targ = &listTargets.back(); + targ->validatecount = 0; + } + else { + // create a new + listTargets.push_back(CMemoryTarget()); + targ = &listTargets.back(); + } + } + else { + listTargets.push_back(CMemoryTarget()); + targ = &listTargets.back(); + } + + // fill local clut + if( PSMT_ISCLUT(tex0.psm) ) { + assert( clutsize > 0 ); + targ->cpsm = tex0.cpsm; + targ->clut.reserve(256*4); // no matter what + targ->clut.resize(clutsize); + + if( tex0.cpsm <= 1 ) { // 32 bit + memcpy_amd(&targ->clut[0], g_pbyGSClut+nClutOffset, clutsize); + } + else { + u16* pClutBuffer = (u16*)(g_pbyGSClut + nClutOffset); + u16* pclut = (u16*)&targ->clut[0]; + int left = ((u32)nClutOffset & 2) ? 0 : ((nClutOffset&0x3ff)/2)+clutsize-512; + if( left > 0 ) clutsize -= left; + + while(clutsize > 0) { + pclut[0] = pClutBuffer[0]; + pclut++; + pClutBuffer+=2; + clutsize -= 2; + } + + if( left > 0) { + pClutBuffer = (u16*)(g_pbyGSClut + 2); + while(left > 0) { + pclut[0] = pClutBuffer[0]; + left -= 2; + pClutBuffer += 2; + pclut++; + } + } + } + } + + if( targ->ptex != NULL ) { + + assert( end-start <= targ->realheight && targ->fmt == fmt && targ->widthmult == widthmult ); + // good enough, so init + targ->realy = targ->starty = start; + targ->usedstamp = curstamp; + targ->psm = tex0.psm; + targ->cpsm = tex0.cpsm; + targ->height = end-start; + } + + if( targ->ptex == NULL ) { + + // not initialized yet + targ->fmt = fmt; + targ->realy = targ->starty = start; + targ->realheight = targ->height = end-start; + targ->usedstamp = curstamp; + targ->psm = tex0.psm; + targ->cpsm = tex0.cpsm; + targ->widthmult = widthmult; + targ->channels = channels; + + // alloc the mem + targ->ptex = new CMemoryTarget::TEXTURE(); + targ->ptex->ref = 1; + } + +#ifndef RELEASE_TO_PUBLIC + g_TransferredToGPU += GPU_TEXWIDTH * channels * 4 * targ->height; +#endif + + // fill with data + if( targ->ptex->memptr == NULL ) { + targ->ptex->memptr = (u8*)_aligned_malloc(4 * GPU_TEXWIDTH * targ->realheight, 16); + assert(targ->ptex->ref > 0 ); + } + + memcpy_amd(targ->ptex->memptr, g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy, 4 * GPU_TEXWIDTH * targ->height); + vector texdata; + u8* ptexdata = NULL; + + if( PSMT_ISCLUT(tex0.psm) ) { + + texdata.resize( (tex0.cpsm <= 1?4:2) *GPU_TEXWIDTH*channels*widthmult*(targ->realheight+widthmult-1)/widthmult); + ptexdata = &texdata[0]; + + u8* psrc = (u8*)(g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy); + + if( tex0.cpsm <= 1 ) { // 32bit + u32* pclut = (u32*)&targ->clut[0]; + u32* pdst = (u32*)ptexdata; + + BUILDCLUT(); + } + else { + u16* pclut = (u16*)&targ->clut[0]; + u16* pdst = (u16*)ptexdata; + + BUILDCLUT(); + } + } + else { + if( tex0.psm == PSMT16Z || tex0.psm == PSMT16SZ ) { + + texdata.resize(4*GPU_TEXWIDTH*channels*widthmult*(targ->realheight+widthmult-1)/widthmult); + ptexdata = &texdata[0]; + // needs to be 8 bit, use xmm for unpacking + u16* dst = (u16*)ptexdata; + u16* src = (u16*)(g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy); + + assert( ((u32)(uptr)dst)%16 == 0 ); + +#if defined(ZEROGS_SSE2) + int iters = targ->height*GPU_TEXWIDTH/16; + +#if defined(_MSC_VER) + +#if defined(__x86_64__) + UnswizzleZ16Target(dst, src, iters); +#else + __asm { + mov edx, iters + pxor xmm7, xmm7 + mov eax, dst + mov ecx, src + +Z16Loop: + // unpack 64 bytes at a time + movdqa xmm0, [ecx] + movdqa xmm2, [ecx+16] + movdqa xmm4, [ecx+32] + movdqa xmm6, [ecx+48] + + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + movdqa xmm5, xmm4 + + punpcklwd xmm0, xmm7 + punpckhwd xmm1, xmm7 + punpcklwd xmm2, xmm7 + punpckhwd xmm3, xmm7 + + // start saving + movdqa [eax], xmm0 + movdqa [eax+16], xmm1 + + punpcklwd xmm4, xmm7 + punpckhwd xmm5, xmm7 + + movdqa [eax+32], xmm2 + movdqa [eax+48], xmm3 + + movdqa xmm0, xmm6 + punpcklwd xmm6, xmm7 + + movdqa [eax+64], xmm4 + movdqa [eax+80], xmm5 + + punpckhwd xmm0, xmm7 + + movdqa [eax+96], xmm6 + movdqa [eax+112], xmm0 + + add ecx, 64 + add eax, 128 + sub edx, 1 + jne Z16Loop + } +#endif // __x86_64__ +#else // _MSC_VER + + __asm__(".intel_syntax\n" + "pxor %%xmm7, %%xmm7\n" + + "Z16Loop:\n" + // unpack 64 bytes at a time + "movdqa %%xmm0, [%0]\n" + "movdqa %%xmm2, [%0+16]\n" + "movdqa %%xmm4, [%0+32]\n" + "movdqa %%xmm6, [%0+48]\n" + + "movdqa %%xmm1, %%xmm0\n" + "movdqa %%xmm3, %%xmm2\n" + "movdqa %%xmm5, %%xmm4\n" + + "punpcklwd %%xmm0, %%xmm7\n" + "punpckhwd %%xmm1, %%xmm7\n" + "punpcklwd %%xmm2, %%xmm7\n" + "punpckhwd %%xmm3, %%xmm7\n" + + // start saving + "movdqa [%1], %%xmm0\n" + "movdqa [%1+16], %%xmm1\n" + + "punpcklwd %%xmm4, %%xmm7\n" + "punpckhwd %%xmm5, %%xmm7\n" + + "movdqa [%1+32], %%xmm2\n" + "movdqa [%1+48], %%xmm3\n" + + "movdqa %%xmm0, %%xmm6\n" + "punpcklwd %%xmm6, %%xmm7\n" + + "movdqa [%1+64], %%xmm4\n" + "movdqa [%1+80], %%xmm5\n" + + "punpckhwd %%xmm0, %%xmm7\n" + + "movdqa [%1+96], %%xmm6\n" + "movdqa [%1+112], %%xmm0\n" + + "add %0, 64\n" + "add %1, 128\n" + "sub %2, 1\n" + "jne Z16Loop\n" + ".att_syntax\n" : "=r"(src), "=r"(dst), "=r"(iters) : "0"(src), "1"(dst), "2"(iters)); + +#endif // _MSC_VER +#else // ZEROGS_SSE2 + for(int i = 0; i < targ->height; ++i) { + for(int j = 0; j < GPU_TEXWIDTH; ++j) { + dst[0] = src[0]; dst[1] = 0; + dst[2] = src[1]; dst[3] = 0; + dst += 4; + src += 2; + } + } +#endif // ZEROGS_SSE2 + } + else { + ptexdata = targ->ptex->memptr; + } + } + + // create the texture + GL_REPORT_ERRORD(); + assert(ptexdata != NULL); + if( targ->ptex->tex == 0 ) + glGenTextures(1, &targ->ptex->tex); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, targ->ptex->tex); + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, fmt==GL_UNSIGNED_BYTE?4:GL_RGB5_A1, GPU_TEXWIDTH*channels*widthmult, + (targ->realheight+widthmult-1)/widthmult, 0, GL_RGBA, fmt, ptexdata); + + int realheight = targ->realheight; + while( glGetError() != GL_NO_ERROR ) { + + // release resources until can create + if( listClearedTargets.size() > 0 ) + listClearedTargets.pop_front(); + else { + if( listTargets.size() == 0 ) { + ERROR_LOG("Failed to create %dx%x texture\n", GPU_TEXWIDTH*channels*widthmult, (realheight+widthmult-1)/widthmult); + channels = 1; + return NULL; + } + DestroyOldest(); + } + + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, 4, GPU_TEXWIDTH*channels*widthmult, (targ->realheight+widthmult-1)/widthmult, 0, GL_RGBA, fmt, ptexdata); + } + + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_T, GL_CLAMP); + + assert( tex0.psm != 0xd ); + if( PSMT_ISCLUT(tex0.psm) ) + assert( targ->clut.size() > 0 ); + + return targ; +} + +void ZeroGS::CMemoryTargetMngr::ClearRange(int nbStartY, int nbEndY) +{ + int starty = nbStartY / (4*GPU_TEXWIDTH); + int endy = (nbEndY+4*GPU_TEXWIDTH-1) / (4*GPU_TEXWIDTH); + //int endy = (nbEndY+4096-1) / 4096; + + //if( listTargets.size() < TARGET_THRESH ) { + for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { + + if( it->starty < endy && (it->starty+it->height) > starty ) { + + // intersects, reduce valid texture mem (or totally delete texture) + // there are 4 cases + int miny = max(it->starty, starty); + int maxy = min(it->starty+it->height, endy); + assert(miny < maxy); + + if( it->clearmaxy == 0 ) { + it->clearminy = miny; + it->clearmaxy = maxy; + } + else { + if( it->clearminy > miny ) it->clearminy = miny; + if( it->clearmaxy < maxy ) it->clearmaxy = maxy; + } + } + + ++it; + } +// } +// else { +// for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { +// +// if( it->starty < endy && (it->starty+it->height) > starty ) { +// int newstarty = 0; +// if( starty <= it->starty ) { +// if( endy < it->starty + it->height) { +// // preserve end +// it->height = it->starty+it->height-endy; +// it->starty = endy; +// assert(it->height > 0); +// } +// else { +// // destroy +// it->height = 0; +// } +// } +// else { +// // beginning can be preserved +// it->height = starty-it->starty; +// } +// +// assert( it->starty >= it->realy && it->starty+it->height<=it->realy+it->realheight ); +// if( it->height <= 0 ) { +// list::iterator itprev = it; ++it; +// listClearedTargets.splice(listClearedTargets.end(), listTargets, itprev); +// continue; +// } +// } +// +// ++it; +// } +// } +} + +void ZeroGS::CMemoryTargetMngr::DestroyCleared() +{ + for(list::iterator it = listClearedTargets.begin(); it != listClearedTargets.end(); ) { + if( it->usedstamp < curstamp - 2 ) { + it = listClearedTargets.erase(it); + continue; + } + + ++it; + } + + if( (curstamp % 3) == 0 ) { + // purge old targets every 3 frames + for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { + if( it->usedstamp < curstamp - 3 ) { + it = listTargets.erase(it); + continue; + } + + ++it; + } + } + + ++curstamp; +} + +void ZeroGS::CMemoryTargetMngr::DestroyOldest() +{ + if( listTargets.size() == 0 ) + return; + + list::iterator it, itbest; + it = itbest = listTargets.begin(); + + while(it != listTargets.end()) { + if( it->usedstamp < itbest->usedstamp ) + itbest = it; + ++it; + } + + listTargets.erase(itbest); +} + +////////////////////////////////////// +// Texture Mngr For Bitwise AND Ops // +////////////////////////////////////// +void ZeroGS::CBitwiseTextureMngr::Destroy() +{ + for(map::iterator it = mapTextures.begin(); it != mapTextures.end(); ++it) + glDeleteTextures(1, &it->second); + mapTextures.clear(); +} + +u32 ZeroGS::CBitwiseTextureMngr::GetTexInt(u32 bitvalue, u32 ptexDoNotDelete) +{ + if( mapTextures.size() > 32 ) { + // randomly delete 8 + for(map::iterator it = mapTextures.begin(); it != mapTextures.end();) { + if( !(rand()&3) && it->second != ptexDoNotDelete) { + glDeleteTextures(1, &it->second); + mapTextures.erase(it++); + } + else ++it; + } + } + + // create a new tex + u32 ptex; + glGenTextures(1, &ptex); + + vector data(GPU_TEXMASKWIDTH); + for(u32 i = 0; i < GPU_TEXMASKWIDTH; ++i) + data[i] = ((i&bitvalue)<<6)|0x1f; // add the 1/2 offset so that + + glBindTexture(GL_TEXTURE_2D, ptex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE16, GPU_TEXMASKWIDTH, 1, 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, &data[0]); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + if( glGetError() != GL_NO_ERROR ) { + ERROR_LOG("Failed to create bitmask texture\n"); + return 0; + } + + mapTextures[bitvalue] = ptex; + return ptex; +} + +void ZeroGS::CRangeManager::Insert(int start, int end) +{ + int imin = 0, imax = (int)ranges.size(), imid; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + + switch( ranges.size() ) { + case 0: + ranges.push_back(RANGE(start, end)); + return; + + case 1: + if( end < ranges.front().start ) { + ranges.insert(ranges.begin(), RANGE(start, end)); + } + else if( start > ranges.front().end ) { + ranges.push_back(RANGE(start, end)); + } + else { + if( start < ranges.front().start ) ranges.front().start = start; + if( end > ranges.front().end ) ranges.front().end = end; + } + + return; + } + + // find where start is + while(imin < imax) { + imid = (imin+imax)>>1; + + assert( imid < (int)ranges.size() ); + + if( ranges[imid].end >= start && (imid == 0 || ranges[imid-1].end < start) ) { + imin = imid; + break; + } + else if( ranges[imid].start > start ) imax = imid; + else imin = imid+1; + } + + int startindex = imin; + + if( startindex >= (int)ranges.size() ) { + // non intersecting + assert( start > ranges.back().end ); + ranges.push_back(RANGE(start, end)); + return; + } + if( startindex == 0 && end < ranges.front().start ) { + ranges.insert(ranges.begin(), RANGE(start, end)); + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + return; + } + + imin = 0; imax = (int)ranges.size(); + + // find where end is + while(imin < imax) { + imid = (imin+imax)>>1; + + assert( imid < (int)ranges.size() ); + + if( ranges[imid].end <= end && (imid == ranges.size()-1 || ranges[imid+1].start > end ) ) { + imin = imid; + break; + } + else if( ranges[imid].start >= end ) imax = imid; + else imin = imid+1; + } + + int endindex = imin; + + if( startindex > endindex ) { + // create a new range + ranges.insert(ranges.begin()+startindex, RANGE(start, end)); + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + return; + } + + if( endindex >= (int)ranges.size()-1 ) { + // pop until startindex is reached + int lastend = ranges.back().end; + int numpop = (int)ranges.size() - startindex - 1; + while(numpop-- > 0 ) ranges.pop_back(); + + assert( start <= ranges.back().end ); + if( start < ranges.back().start ) ranges.back().start = start; + if( lastend > ranges.back().end ) ranges.back().end = lastend; + if( end > ranges.back().end ) ranges.back().end = end; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + + return; + } + + if( endindex == 0 ) { + assert( end >= ranges.front().start ); + if( start < ranges.front().start ) ranges.front().start = start; + if( end > ranges.front().end ) ranges.front().end = end; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + } + + // somewhere in the middle + if( ranges[startindex].start < start ) start = ranges[startindex].start; + + if( startindex < endindex ) { + ranges.erase(ranges.begin() + startindex, ranges.begin() + endindex ); + } + + if( start < ranges[startindex].start ) ranges[startindex].start = start; + if( end > ranges[startindex].end ) ranges[startindex].end = end; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif +} + +namespace ZeroGS { + +CRangeManager s_RangeMngr; // manages overwritten memory +static int gs_imageEnd = 0; + +void ResolveInRange(int start, int end) +{ + list listTargs; + s_DepthRTs.GetTargs(start, end, listTargs); + s_RTs.GetTargs(start, end, listTargs); + + if( listTargs.size() > 0 ) { + Flush(0); + Flush(1); + + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) { + // only resolve if not completely covered + (*it)->Resolve(); + } + } +} + +////////////////// +// Transferring // +////////////////// +void FlushTransferRanges(const tex0Info* ptex) +{ + assert( s_RangeMngr.ranges.size() > 0 ); + bool bHasFlushed = false; + list listTransmissionUpdateTargs; + + int texstart = -1, texend = -1; + if( ptex != NULL ) { + GetRectMemAddress(texstart, texend, ptex->psm, 0, 0, ptex->tw, ptex->th, ptex->tbp0, ptex->tbw); + } + + for(vector::iterator itrange = s_RangeMngr.ranges.begin(); itrange != s_RangeMngr.ranges.end(); ++itrange ) { + + int start = itrange->start; + int end = itrange->end; + + listTransmissionUpdateTargs.clear(); + s_DepthRTs.GetTargs(start, end, listTransmissionUpdateTargs); + s_RTs.GetTargs(start, end, listTransmissionUpdateTargs); + +// if( !bHasFlushed && listTransmissionUpdateTargs.size() > 0 ) { +// Flush(0); +// Flush(1); +// +//#ifdef _DEBUG +// // make sure targets are still the same +// list::iterator it; +// FORIT(it, listTransmissionUpdateTargs) { +// CRenderTargetMngr::MAPTARGETS::iterator itmap; +// for(itmap = s_RTs.mapTargets.begin(); itmap != s_RTs.mapTargets.end(); ++itmap) { +// if( itmap->second == *it ) +// break; +// } +// +// if( itmap == s_RTs.mapTargets.end() ) { +// +// for(itmap = s_DepthRTs.mapTargets.begin(); itmap != s_DepthRTs.mapTargets.end(); ++itmap) { +// if( itmap->second == *it ) +// break; +// } +// +// assert( itmap != s_DepthRTs.mapTargets.end() ); +// } +// } +//#endif +// } + + for(list::iterator it = listTransmissionUpdateTargs.begin(); it != listTransmissionUpdateTargs.end(); ++it) { + + CRenderTarget* ptarg = *it; + + if( (ptarg->status & CRenderTarget::TS_Virtual) ) + continue; + + if( !(ptarg->start < texend && ptarg->end > texstart) ) { + // chekc if target is currently being used + + if( !(g_GameSettings & GAME_NOQUICKRESOLVE) ) { + if( ptarg->fbp != vb[0].gsfb.fbp ) {//&& (vb[0].prndr == NULL || ptarg->fbp != vb[0].prndr->fbp) ) { + + if( ptarg->fbp != vb[1].gsfb.fbp ) { //&& (vb[1].prndr == NULL || ptarg->fbp != vb[1].prndr->fbp) ) { + // this render target currently isn't used and is not in the texture's way, so can safely ignore + // resolving it. Also the range has to be big enough compared to the target to really call it resolved + // (ffx changing screens, shadowhearts) + // start == ptarg->start, used for kh to transfer text + if( ptarg->IsDepth() || end-start > 0x50000 || ((g_GameSettings&GAME_QUICKRESOLVE1)&&start == ptarg->start) ) + ptarg->status |= CRenderTarget::TS_NeedUpdate|CRenderTarget::TS_Resolved; + + continue; + } + } + } + } + else { +// if( start <= texstart && end >= texend ) { +// // texture taken care of so can skip!? +// continue; +// } + } + + // the first range check was very rough; some games (dragonball z) have the zbuf in the same page as textures (but not overlapping) + // so detect that condition + if( ptarg->fbh % m_Blocks[ptarg->psm].height ) { + + // get start of left-most boundry page + int targstart, targend; + ZeroGS::GetRectMemAddress(targstart, targend, ptarg->psm, 0, 0, ptarg->fbw, ptarg->fbh & ~(m_Blocks[ptarg->psm].height-1), ptarg->fbp, ptarg->fbw); + + if( start >= targend ) { + + // don't bother + if( (ptarg->fbh % m_Blocks[ptarg->psm].height) <= 2 ) + continue; + + // calc how many bytes of the block that the page spans + } + } + + if( !(ptarg->status & CRenderTarget::TS_Virtual) ) { + + if( start < ptarg->end && end > ptarg->start ) { + + // suikoden5 is faster with check, but too big of a value and kh screens mess up + if( end - start > 0x8000 ) { + // intersects, do only one sided resolves + if( end-start > 4*ptarg->fbw ) { // at least it be greater than one scanline (spiro is faster) + if( start > ptarg->start ) { + ptarg->Resolve(ptarg->start, start); + } + else if( end < ptarg->end ) { + ptarg->Resolve(end, ptarg->end); + } + } + } + + ptarg->status |= CRenderTarget::TS_Resolved; + if( !ptarg->IsDepth() || (!(g_GameSettings & GAME_NODEPTHUPDATE) || end-start > 0x1000) ) + ptarg->status |= CRenderTarget::TS_NeedUpdate; + } + } + } + + ZeroGS::g_MemTargs.ClearRange(start, end); + } + + s_RangeMngr.Clear(); +} + +static vector s_vTempBuffer, s_vTransferCache; + +void InitTransferHostLocal() +{ + if( g_bIsLost ) + return; + +#ifndef RELEASE_TO_PUBLIC + if( gs.trxpos.dx+gs.imageWnew > gs.dstbuf.bw ) + WARN_LOG("Transfer error, width exceeds\n"); +#endif + + bool bHasFlushed = false; + + gs.imageX = gs.trxpos.dx; + gs.imageY = gs.trxpos.dy; + gs.imageEndX = gs.imageX + gs.imageWnew; + gs.imageEndY = gs.imageY + gs.imageHnew; + + assert( gs.imageEndX < 2048 && gs.imageEndY < 2048 ); + + // hack! viewful joe + if( gs.dstbuf.psm == 63 ) + gs.dstbuf.psm = 0; + + int start, end; + GetRectMemAddress(start, end, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); + + if( end > 0x00400000 ) { + WARN_LOG("host local out of bounds!\n"); + //gs.imageTransfer = -1; + end = 0x00400000; + } + + gs_imageEnd = end; + + if( vb[0].nCount > 0 ) + Flush(0); + if( vb[1].nCount > 0 ) + Flush(1); + + //PRIM_LOG("trans: bp:%x x:%x y:%x w:%x h:%x\n", gs.dstbuf.bp, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew); + +// if( !bHasFlushed && (vb[0].bNeedFrameCheck || vb[0].bNeedZCheck || vb[1].bNeedFrameCheck || vb[1].bNeedZCheck)) { +// Flush(0); +// Flush(1); +// bHasFlushed = 1; +// } +// +// // for all ranges, flush the targets +// // check if new rect intersects with current rendering texture, if so, flush +// if( vb[0].nCount > 0 && vb[0].curprim.tme ) { +// int tstart, tend; +// GetRectMemAddress(tstart, tend, vb[0].tex0.psm, 0, 0, vb[0].tex0.tw, vb[0].tex0.th, vb[0].tex0.tbp0, vb[0].tex0.tbw); +// +// if( start < tend && end > tstart ) { +// Flush(0); +// Flush(1); +// bHasFlushed = 1; +// } +// } +// +// if( !bHasFlushed && vb[1].nCount > 0 && vb[1].curprim.tme ) { +// int tstart, tend; +// GetRectMemAddress(tstart, tend, vb[1].tex0.psm, 0, 0, vb[1].tex0.tw, vb[1].tex0.th, vb[1].tex0.tbp0, vb[1].tex0.tbw); +// +// if( start < tend && end > tstart ) { +// Flush(0); +// Flush(1); +// bHasFlushed = 1; +// } +// } + + //ZeroGS::g_MemTargs.ClearRange(start, end); + //s_RangeMngr.Insert(start, end); +} + +void TransferHostLocal(const void* pbyMem, u32 nQWordSize) +{ + if( g_bIsLost ) + return; + + DVProfileFunc _pf("TransferHostLocal"); + + int start, end; + GetRectMemAddress(start, end, gs.dstbuf.psm, gs.imageX, gs.imageY, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); + assert( start < gs_imageEnd ); + + end = gs_imageEnd; + + // sometimes games can decompress to alpha channel of render target only, in this case + // do a resolve right away. wolverine x2 + if( gs.dstbuf.psm == PSMT8H || gs.dstbuf.psm == PSMT4HL || gs.dstbuf.psm == PSMT4HH ) { + list listTransmissionUpdateTargs; + s_RTs.GetTargs(start, end, listTransmissionUpdateTargs); + + for(list::iterator it = listTransmissionUpdateTargs.begin(); it != listTransmissionUpdateTargs.end(); ++it) { + + CRenderTarget* ptarg = *it; + + if( (ptarg->status & CRenderTarget::TS_Virtual) ) + continue; + + //ERROR_LOG("resolving to alpha channel\n"); + ptarg->Resolve(); + } + } + + s_RangeMngr.Insert(start, min(end, start+(int)nQWordSize*16)); + + const u8* porgend = (const u8*)pbyMem + 4 * nQWordSize; + + if( s_vTransferCache.size() > 0 ) { + + int imagecache = s_vTransferCache.size(); + s_vTempBuffer.resize(imagecache + nQWordSize*4); + memcpy(&s_vTempBuffer[0], &s_vTransferCache[0], imagecache); + memcpy(&s_vTempBuffer[imagecache], pbyMem, nQWordSize*4); + + pbyMem = (const void*)&s_vTempBuffer[0]; + porgend = &s_vTempBuffer[0]+s_vTempBuffer.size(); + + int wordinc = imagecache / 4; + if( (nQWordSize * 4 + imagecache)/3 == ((nQWordSize+wordinc) * 4) / 3 ) { + // can use the data + nQWordSize += wordinc; + } + } + + int leftover = m_Blocks[gs.dstbuf.psm].TransferHostLocal(pbyMem, nQWordSize); + + if( leftover > 0 ) { + // copy the last gs.image24bitOffset to the cache + s_vTransferCache.resize(leftover); + memcpy(&s_vTransferCache[0], porgend - leftover, leftover); + } + else s_vTransferCache.resize(0); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveTrans ) { + tex0Info t; + t.tbp0 = gs.dstbuf.bp; + t.tw = gs.imageWnew; + t.th = gs.imageHnew; + t.tbw = gs.dstbuf.bw; + t.psm = gs.dstbuf.psm; + SaveTex(&t, 0); + } +#endif +} + +// left/right, top/down +//void TransferHostLocal(const void* pbyMem, u32 nQWordSize) +//{ +// assert( gs.imageTransfer == 0 ); +// u8* pstart = g_pbyGSMemory + gs.dstbuf.bp*256; +// +// const u8* pendbuf = (const u8*)pbyMem + nQWordSize*4; +// int i = gs.imageY, j = gs.imageX; +// +//#define DSTPSM gs.dstbuf.psm +// +//#define TRANSFERHOSTLOCAL(psm, T, widthlimit) { \ +// const T* pbuf = (const T*)pbyMem; \ +// u32 nSize = nQWordSize*(4/sizeof(T)); \ +// assert( (nSize%widthlimit) == 0 && widthlimit <= 4 ); \ +// if( ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) ERROR_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM); \ +// for(; i < gs.imageEndY; ++i) { \ +// for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += widthlimit) { \ +// /* write as many pixel at one time as possible */ \ +// writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ +// \ +// if( widthlimit > 1 ) { \ +// writePixel##psm##_0(pstart, (j+1)%2048, i%2048, pbuf[1], gs.dstbuf.bw); \ +// \ +// if( widthlimit > 2 ) { \ +// writePixel##psm##_0(pstart, (j+2)%2048, i%2048, pbuf[2], gs.dstbuf.bw); \ +// \ +// if( widthlimit > 3 ) { \ +// writePixel##psm##_0(pstart, (j+3)%2048, i%2048, pbuf[3], gs.dstbuf.bw); \ +// } \ +// } \ +// } \ +// } \ +// \ +// if( j >= gs.imageEndX ) { assert(j == gs.imageEndX); j = gs.trxpos.dx; } \ +// else { assert( nSize == 0 ); goto End; } \ +// } \ +//} \ +// +//#define TRANSFERHOSTLOCAL_4(psm) { \ +// const u8* pbuf = (const u8*)pbyMem; \ +// u32 nSize = nQWordSize*8; \ +// for(; i < gs.imageEndY; ++i) { \ +// for(; j < gs.imageEndX && nSize > 0; j += 8, nSize -= 8) { \ +// /* write as many pixel at one time as possible */ \ +// writePixel##psm##_0(pstart, j%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// } \ +// \ +// if( j >= gs.imageEndX ) { /*assert(j == gs.imageEndX);*/ j = gs.trxpos.dx; } \ +// else { assert( nSize == 0 ); goto End; } \ +// } \ +//} \ +// +// switch (gs.dstbuf.psm) { +// case 0x0: TRANSFERHOSTLOCAL(32, u32, 2); break; +// case 0x1: TRANSFERHOSTLOCAL(24, u32, 4); break; +// case 0x2: TRANSFERHOSTLOCAL(16, u16, 4); break; +// case 0xA: TRANSFERHOSTLOCAL(16S, u16, 4); break; +// case 0x13: +// if( ((gs.imageEndX-gs.trxpos.dx)%4) ) { +// TRANSFERHOSTLOCAL(8, u8, 1); +// } +// else { +// TRANSFERHOSTLOCAL(8, u8, 4); +// } +// break; +// +// case 0x14: +//// if( (gs.imageEndX-gs.trxpos.dx)%8 ) { +//// // hack +//// if( abs((int)nQWordSize*8 - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx)) <= 8 ) { +//// // don't transfer +//// ERROR_LOG("bad texture 4: %d %d %d\n", gs.trxpos.dx, gs.imageEndX, nQWordSize); +//// gs.imageEndX = gs.trxpos.dx + (gs.imageEndX-gs.trxpos.dx)&~7; +//// //i = gs.imageEndY; +//// //goto End; +//// gs.imageTransfer = -1; +//// } +//// } +// TRANSFERHOSTLOCAL_4(4); +// break; +// case 0x1B: TRANSFERHOSTLOCAL(8H, u8, 4); break; +// case 0x24: TRANSFERHOSTLOCAL_4(4HL); break; +// case 0x2C: TRANSFERHOSTLOCAL_4(4HH); break; +// case 0x30: TRANSFERHOSTLOCAL(32Z, u32, 2); break; +// case 0x31: TRANSFERHOSTLOCAL(24Z, u32, 4); break; +// case 0x32: TRANSFERHOSTLOCAL(16Z, u16, 4); break; +// case 0x3A: TRANSFERHOSTLOCAL(16SZ, u16, 4); break; +// } +// +//End: +// if( i >= gs.imageEndY ) { +// assert( i == gs.imageEndY ); +// gs.imageTransfer = -1; +// +// if( g_bSaveTrans ) { +// tex0Info t; +// t.tbp0 = gs.dstbuf.bp; +// t.tw = gs.imageWnew; +// t.th = gs.imageHnew; +// t.tbw = gs.dstbuf.bw; +// t.psm = gs.dstbuf.psm; +// SaveTex(&t, 0); +// } +// } +// else { +// /* update new params */ +// gs.imageY = i; +// gs.imageX = j; +// } +//} + +void InitTransferLocalHost() +{ + assert( gs.trxpos.sx+gs.imageWnew <= 2048 && gs.trxpos.sy+gs.imageHnew <= 2048 ); + +#ifndef RELEASE_TO_PUBLIC + if( gs.trxpos.sx+gs.imageWnew > gs.srcbuf.bw ) + WARN_LOG("Transfer error, width exceeds\n"); +#endif + + gs.imageX = gs.trxpos.sx; + gs.imageY = gs.trxpos.sy; + gs.imageEndX = gs.imageX + gs.imageWnew; + gs.imageEndY = gs.imageY + gs.imageHnew; + s_vTransferCache.resize(0); + + int start, end; + GetRectMemAddress(start, end, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw); + ResolveInRange(start, end); +} + +// left/right, top/down +void TransferLocalHost(void* pbyMem, u32 nQWordSize) +{ + assert( gs.imageTransfer == 1 ); + + u8* pstart = g_pbyGSMemory + 256*gs.srcbuf.bp; + int i = gs.imageY, j = gs.imageX; + +#define TRANSFERLOCALHOST(psm, T) { \ + T* pbuf = (T*)pbyMem; \ + u32 nSize = nQWordSize*16/sizeof(T); \ + for(; i < gs.imageEndY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; ++j, --nSize) { \ + *pbuf++ = readPixel##psm##_0(pstart, j%2048, i%2048, gs.srcbuf.bw); \ + } \ + \ + if( j >= gs.imageEndX ) { assert( j == gs.imageEndX); j = gs.trxpos.sx; } \ + else { assert( nSize == 0 ); break; } \ + } \ +} \ + +#define TRANSFERLOCALHOST_24(psm) { \ + u8* pbuf = (u8*)pbyMem; \ + u32 nSize = nQWordSize*16/3; \ + for(; i < gs.imageEndY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; ++j, --nSize) { \ + u32 p = readPixel##psm##_0(pstart, j%2048, i%2048, gs.srcbuf.bw); \ + pbuf[0] = (u8)p; \ + pbuf[1] = (u8)(p>>8); \ + pbuf[2] = (u8)(p>>16); \ + pbuf += 3; \ + } \ + \ + if( j >= gs.imageEndX ) { assert( j == gs.imageEndX); j = gs.trxpos.sx; } \ + else { assert( nSize == 0 ); break; } \ + } \ +} \ + + switch (gs.srcbuf.psm) { + case 0x0: TRANSFERLOCALHOST(32, u32); break; + case 0x1: TRANSFERLOCALHOST_24(24); break; + case 0x2: TRANSFERLOCALHOST(16, u16); break; + case 0xA: TRANSFERLOCALHOST(16S, u16); break; + case 0x13: TRANSFERLOCALHOST(8, u8); break; + case 0x1B: TRANSFERLOCALHOST(8H, u8); break; + case 0x30: TRANSFERLOCALHOST(32Z, u32); break; + case 0x31: TRANSFERLOCALHOST_24(24Z); break; + case 0x32: TRANSFERLOCALHOST(16Z, u16); break; + case 0x3A: TRANSFERLOCALHOST(16SZ, u16); break; + default: assert(0); + } + + gs.imageY = i; + gs.imageX = j; + + if( gs.imageY >= gs.imageEndY ) { + assert( gs.imageY == gs.imageEndY ); + gs.imageTransfer = -1; + } +} + +// dir depends on trxpos.dir +void TransferLocalLocal() +{ + assert( gs.imageTransfer == 2 ); + assert( gs.trxpos.sx+gs.imageWnew < 2048 && gs.trxpos.sy+gs.imageHnew < 2048 ); + assert( gs.trxpos.dx+gs.imageWnew < 2048 && gs.trxpos.dy+gs.imageHnew < 2048 ); + assert( (gs.srcbuf.psm&0x7) == (gs.dstbuf.psm&0x7) ); + if( gs.trxpos.sx+gs.imageWnew > gs.srcbuf.bw ) + WARN_LOG("Transfer error, src width exceeds\n"); + if( gs.trxpos.dx+gs.imageWnew > gs.dstbuf.bw ) + WARN_LOG("Transfer error, dst width exceeds\n"); + + int srcstart, srcend, dststart, dstend; + + GetRectMemAddress(srcstart, srcend, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw); + GetRectMemAddress(dststart, dstend, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); + + // resolve the targs + ResolveInRange(srcstart, srcend); + + list listTargs; + s_RTs.GetTargs(dststart, dstend, listTargs); + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) { + if( !((*it)->status & CRenderTarget::TS_Virtual) ) { + (*it)->Resolve(); + (*it)->status |= CRenderTarget::TS_NeedUpdate; + } + } + + u8* pSrcBuf = g_pbyGSMemory + gs.srcbuf.bp*256; + u8* pDstBuf = g_pbyGSMemory + gs.dstbuf.bp*256; + +#define TRANSFERLOCALLOCAL(srcpsm, dstpsm, widthlimit) { \ + assert( (gs.imageWnew&widthlimit)==0 && widthlimit <= 4); \ + for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < gs.trxpos.sy+gs.imageHnew; i++, i2++) { \ + for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < gs.trxpos.sx+gs.imageWnew; j+=widthlimit, j2+=widthlimit) { \ + \ + writePixel##dstpsm##_0(pDstBuf, j2%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, j%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + \ + if( widthlimit > 1 ) { \ + writePixel##dstpsm##_0(pDstBuf, (j2+1)%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, (j+1)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + \ + if( widthlimit > 2 ) { \ + writePixel##dstpsm##_0(pDstBuf, (j2+2)%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, (j+2)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + \ + if( widthlimit > 3 ) { \ + writePixel##dstpsm##_0(pDstBuf, (j2+3)%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, (j+3)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + } \ + } \ + } \ + } \ + } \ +} \ + +#define TRANSFERLOCALLOCAL_4(srcpsm, dstpsm) { \ + assert( (gs.imageWnew%8) == 0 ); \ + for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < gs.trxpos.sy+gs.imageHnew; ++i, ++i2) { \ + for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < gs.trxpos.sx+gs.imageWnew; j+=8, j2+=8) { \ + /* NOTE: the 2 conseq 4bit values are in NOT in the same byte */ \ + u32 read = getPixelAddress##srcpsm##_0(j%2048, i%2048, gs.srcbuf.bw); \ + u32 write = getPixelAddress##dstpsm##_0(j2%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+1)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+1)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + \ + read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + \ + read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + \ + read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + } \ + } \ +} \ + + switch (gs.srcbuf.psm) { + case PSMCT32: + if( gs.dstbuf.psm == PSMCT32 ) { + TRANSFERLOCALLOCAL(32, 32, 2); + } + else { + TRANSFERLOCALLOCAL(32, 32Z, 2); + } + break; + + case PSMCT24: + if( gs.dstbuf.psm == PSMCT24 ) { + TRANSFERLOCALLOCAL(24, 24, 4); + } + else { + TRANSFERLOCALLOCAL(24, 24Z, 4); + } + break; + + case PSMCT16: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16, 16SZ, 4); break; + } + break; + + case PSMCT16S: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16S, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16S, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16S, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16S, 16SZ, 4); break; + } + break; + + case PSMT8: + if( gs.dstbuf.psm == PSMT8 ) { + TRANSFERLOCALLOCAL(8, 8, 4); + } + else { + TRANSFERLOCALLOCAL(8, 8H, 4); + } + break; + + case PSMT4: + + switch(gs.dstbuf.psm ) { + case PSMT4: TRANSFERLOCALLOCAL_4(4, 4); break; + case PSMT4HL: TRANSFERLOCALLOCAL_4(4, 4HL); break; + case PSMT4HH: TRANSFERLOCALLOCAL_4(4, 4HH); break; + } + break; + + case PSMT8H: + if( gs.dstbuf.psm == PSMT8 ) { + TRANSFERLOCALLOCAL(8H, 8, 4); + } + else { + TRANSFERLOCALLOCAL(8H, 8H, 4); + } + break; + + case PSMT4HL: + switch(gs.dstbuf.psm ) { + case PSMT4: TRANSFERLOCALLOCAL_4(4HL, 4); break; + case PSMT4HL: TRANSFERLOCALLOCAL_4(4HL, 4HL); break; + case PSMT4HH: TRANSFERLOCALLOCAL_4(4HL, 4HH); break; + } + break; + case PSMT4HH: + switch(gs.dstbuf.psm ) { + case PSMT4: TRANSFERLOCALLOCAL_4(4HH, 4); break; + case PSMT4HL: TRANSFERLOCALLOCAL_4(4HH, 4HL); break; + case PSMT4HH: TRANSFERLOCALLOCAL_4(4HH, 4HH); break; + } + break; + + case PSMT32Z: + if( gs.dstbuf.psm == PSMCT32 ) { + TRANSFERLOCALLOCAL(32Z, 32, 2); + } + else { + TRANSFERLOCALLOCAL(32Z, 32Z, 2); + } + break; + + case PSMT24Z: + if( gs.dstbuf.psm == PSMCT24 ) { + TRANSFERLOCALLOCAL(24Z, 24, 4); + } + else { + TRANSFERLOCALLOCAL(24Z, 24Z, 4); + } + break; + + case PSMT16Z: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16Z, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16Z, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16Z, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16Z, 16SZ, 4); break; + } + break; + + case PSMT16SZ: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16SZ, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16SZ, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16SZ, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16SZ, 16SZ, 4); break; + } + break; + } + + g_MemTargs.ClearRange(dststart, dstend); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveTrans ) { + tex0Info t; + t.tbp0 = gs.dstbuf.bp; + t.tw = gs.imageWnew; + t.th = gs.imageHnew; + t.tbw = gs.dstbuf.bw; + t.psm = gs.dstbuf.psm; + SaveTex(&t, 0); + + t.tbp0 = gs.srcbuf.bp; + t.tw = gs.imageWnew; + t.th = gs.imageHnew; + t.tbw = gs.srcbuf.bw; + t.psm = gs.srcbuf.psm; + SaveTex(&t, 0); + } +#endif +} + +void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw) +{ + if( m_Blocks[psm].bpp == 0 ) { + ERROR_LOG("ZeroGS: Bad psm 0x%x\n", psm); + start = 0; + end = 0x00400000; + return; + } + + if( (psm&0x30) == 0x30 || psm == 0xa ) { + + const BLOCK& b = m_Blocks[psm]; + + bw = (bw + b.width -1)/b.width; + start = bp*256 + ((y/b.height) * bw + (x/b.width) )*0x2000; + end = bp*256 + (((y+h-1)/b.height) * bw + (x + w + b.width - 1)/b.width)*0x2000; + } + else { + // just take the addresses + switch(psm) { + case 0x00: + case 0x01: + case 0x1b: + case 0x24: + case 0x2c: + start = 4*getPixelAddress32(x, y, bp, bw); + end = 4*getPixelAddress32(x+w-1, y+h-1, bp, bw) + 4; + break; + case 0x02: + start = 2*getPixelAddress16(x, y, bp, bw); + end = 2*getPixelAddress16(x+w-1, y+h-1, bp, bw)+2; + break; + case 0x13: + start = getPixelAddress8(x, y, bp, bw); + end = getPixelAddress8(x+w-1, y+h-1, bp, bw)+1; + break; + case 0x14: + { + start = getPixelAddress4(x, y, bp, bw)/2; + int newx = ((x+w-1+31)&~31)-1; + int newy = ((y+h-1+15)&~15)-1; + end = (getPixelAddress4(max(newx,x), max(newy,y), bp, bw)+2)/2; + break; + } + } + } +} + +void _Resolve(const void* psrc, int fbp, int fbw, int fbh, int psm, u32 fbm) +{ + //assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); + s_nResolved += 2; + + // align the rect to the nearest page + // note that fbp is always aligned on page boundaries + int start, end; + GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); + + PRIM_LOG("resolve: %x %x %x (%x-%x)\n", fbp, fbw, fbh, start, end); + + int i, j; + short smask1 = gs.smask&1; + short smask2 = gs.smask&2; + u32 mask, imask; + + if( psm&2 ) { // 16 bit + // mask is shifted + imask = RGBA32to16(fbm); + mask = (~imask)&0xffff; + } + else { + mask = ~fbm; + imask = fbm; + + if( (psm&0xf)>0 ) { + // preserve the alpha? + mask &= 0x00ffffff; + imask |= 0xff000000; + } + } + int Pitch; + +#define RESOLVE_32BIT(psm, T, Tsrc, blockbits, blockwidth, blockheight, convfn, frame, aax, aay) \ + { \ + Tsrc* src = (Tsrc*)psrc; \ + T* pPageOffset = (T*)g_pbyGSMemory + fbp*(256/sizeof(T)), *dst; \ + int srcpitch = Pitch * blockheight/sizeof(Tsrc); \ + int maxfbh = (0x00400000-fbp*256) / (sizeof(T) * fbw); \ + if( maxfbh > fbh ) maxfbh = fbh; \ + for(i = 0; i < (maxfbh&~(blockheight-1)); i += blockheight) { \ + /*if( smask2 && (i&1) == smask1 ) continue; */ \ + for(j = 0; j < fbw; j += blockwidth) { \ + /* have to write in the tiled format*/ \ + frame##SwizzleBlock##blockbits(pPageOffset + getPixelAddress##psm##_0(j, i, fbw), \ + src+(j< psm + switch(psm) { + case PSMCT32: + case PSMCT24: + if( s_AAy ) { + RESOLVE_32BIT(32, u32, u32, 32A4, 8, 8, (u32), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32, u32, u32, 32A2, 8, 8, (u32), Frame, 1, 0); + } + else { + RESOLVE_32BIT(32, u32, u32, 32, 8, 8, (u32), Frame, 0, 0); + } + break; + case PSMCT16: + if( s_AAy ) { + RESOLVE_32BIT(16, u16, u32, 16A4, 16, 8, RGBA32to16, Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16, u16, u32, 16A2, 16, 8, RGBA32to16, Frame, 1, 0); + } + else { + RESOLVE_32BIT(16, u16, u32, 16, 16, 8, RGBA32to16, Frame, 0, 0); + } + + break; + case PSMCT16S: + if( s_AAy ) { + RESOLVE_32BIT(16S, u16, u32, 16A4, 16, 8, RGBA32to16, Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16S, u16, u32, 16A2, 16, 8, RGBA32to16, Frame, 1, 0); + } + else { + RESOLVE_32BIT(16S, u16, u32, 16, 16, 8, RGBA32to16, Frame, 0, 0); + } + + break; + case PSMT32Z: + case PSMT24Z: + if( s_AAy ) { + RESOLVE_32BIT(32Z, u32, u32, 32A4, 8, 8, (u32), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32Z, u32, u32, 32A2, 8, 8, (u32), Frame, 1, 0); + } + else { + RESOLVE_32BIT(32Z, u32, u32, 32, 8, 8, (u32), Frame, 0, 0); + } + + break; + case PSMT16Z: + if( s_AAy ) { + RESOLVE_32BIT(16Z, u16, u32, 16A4, 16, 8, (u16), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16Z, u16, u32, 16A2, 16, 8, (u16), Frame, 1, 0); + } + else { + RESOLVE_32BIT(16Z, u16, u32, 16, 16, 8, (u16), Frame, 0, 0); + } + + break; + case PSMT16SZ: + if( s_AAy ) { + RESOLVE_32BIT(16SZ, u16, u32, 16A4, 16, 8, (u16), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16SZ, u16, u32, 16A2, 16, 8, (u16), Frame, 1, 0); + } + else { + RESOLVE_32BIT(16SZ, u16, u32, 16, 16, 8, (u16), Frame, 0, 0); + } + + break; + } + } + else { // float16 + + Pitch = fbw * 8; + + switch(psm) { + case PSMCT32: + case PSMCT24: + if( s_AAy ) { + RESOLVE_32BIT(32, u32, Vector_16F, 32A4, 8, 8, Float16ToARGB, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32, u32, Vector_16F, 32A2, 8, 8, Float16ToARGB, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(32, u32, Vector_16F, 32, 8, 8, Float16ToARGB, Frame16, 0, 0); + } + + break; + case PSMCT16: + if( s_AAy ) { + RESOLVE_32BIT(16, u16, Vector_16F, 16A4, 16, 8, Float16ToARGB16, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16, u16, Vector_16F, 16A2, 16, 8, Float16ToARGB16, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16, u16, Vector_16F, 16, 16, 8, Float16ToARGB16, Frame16, 0, 0); + } + + break; + case PSMCT16S: + if( s_AAy ) { + RESOLVE_32BIT(16S, u16, Vector_16F, 16A4, 16, 8, Float16ToARGB16, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16S, u16, Vector_16F, 16A2, 16, 8, Float16ToARGB16, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16S, u16, Vector_16F, 16, 16, 8, Float16ToARGB16, Frame16, 0, 0); + } + + break; + case PSMT32Z: + case PSMT24Z: + if( s_AAy ) { + RESOLVE_32BIT(32Z, u32, Vector_16F, 32ZA4, 8, 8, Float16ToARGB_Z, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32Z, u32, Vector_16F, 32ZA2, 8, 8, Float16ToARGB_Z, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(32Z, u32, Vector_16F, 32Z, 8, 8, Float16ToARGB_Z, Frame16, 0, 0); + } + + break; + case PSMT16Z: + if( s_AAy ) { + RESOLVE_32BIT(16Z, u16, Vector_16F, 16ZA4, 16, 8, Float16ToARGB16_Z, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16Z, u16, Vector_16F, 16ZA2, 16, 8, Float16ToARGB16_Z, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16Z, u16, Vector_16F, 16Z, 16, 8, Float16ToARGB16_Z, Frame16, 0, 0); + } + + break; + case PSMT16SZ: + if( s_AAy ) { + RESOLVE_32BIT(16SZ, u16, Vector_16F, 16ZA4, 16, 8, Float16ToARGB16_Z, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16SZ, u16, Vector_16F, 16ZA2, 16, 8, Float16ToARGB16_Z, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16SZ, u16, Vector_16F, 16Z, 16, 8, Float16ToARGB16_Z, Frame16, 0, 0); + } + + break; + } + } + + g_MemTargs.ClearRange(start, end); + INC_RESOLVE(); +} + +//////////// +// Saving // +//////////// +void SaveTex(tex0Info* ptex, int usevid) +{ + vector data(ptex->tw*ptex->th); + vector srcdata; + + u32* dst = &data[0]; + u8* psrc = g_pbyGSMemory; + + CMemoryTarget* pmemtarg = NULL; + + if( usevid ) { + + pmemtarg = g_MemTargs.GetMemoryTarget(*ptex, 0); + assert( pmemtarg != NULL ); + + glBindTexture(GL_TEXTURE_RECTANGLE_NV, pmemtarg->ptex->tex); + srcdata.resize(pmemtarg->realheight*GPU_TEXWIDTH*pmemtarg->widthmult*4*8); // max of 8 cannels + + glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, pmemtarg->fmt, &srcdata[0]); + + u32 offset = pmemtarg->realy * 4 * GPU_TEXWIDTH; + if( ptex->psm == PSMT8 ) offset *= ptex->cpsm <= 1 ? 4 : 2; + else if( ptex->psm == PSMT4 ) offset *= ptex->cpsm <= 1 ? 8 : 4; + + psrc = &srcdata[0] - offset; + } + + for(int i = 0; i < ptex->th; ++i) { + for(int j = 0; j < ptex->tw; ++j) { + u32 u, addr; + switch(ptex->psm) { + case PSMCT32: + addr = getPixelAddress32(j, i, ptex->tbp0, ptex->tbw); + + if( addr*4 < 0x00400000 ) + u = readPixel32(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + + break; + case PSMCT24: + addr = getPixelAddress24(j, i, ptex->tbp0, ptex->tbw); + + if( addr*4 < 0x00400000 ) + u = readPixel24(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + + break; + case PSMCT16: + addr = getPixelAddress16(j, i, ptex->tbp0, ptex->tbw); + + if( addr*2 < 0x00400000 ) { + u = readPixel16(psrc, j, i, ptex->tbp0, ptex->tbw); + u = RGBA16to32(u); + } + else u = 0; + + break; + case PSMCT16S: + addr = getPixelAddress16(j, i, ptex->tbp0, ptex->tbw); + + if( addr*2 < 0x00400000 ) { + u = readPixel16S(psrc, j, i, ptex->tbp0, ptex->tbw); + u = RGBA16to32(u); + } + else u = 0; + break; + + case PSMT8: + addr = getPixelAddress8(j, i, ptex->tbp0, ptex->tbw); + + if( addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel8(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT4: + addr = getPixelAddress4(j, i, ptex->tbp0, ptex->tbw); + + if( addr < 2*0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel4(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT8H: + addr = getPixelAddress8H(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel8H(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + + break; + + case PSMT4HL: + addr = getPixelAddress4HL(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel4HL(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT4HH: + addr = getPixelAddress4HH(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel4HH(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT32Z: + addr = getPixelAddress32Z(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) + u = readPixel32Z(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + case PSMT24Z: + addr = getPixelAddress24Z(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) + u = readPixel24Z(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + case PSMT16Z: + addr = getPixelAddress16Z(j, i, ptex->tbp0, ptex->tbw); + + if( 2*addr < 0x00400000 ) + u = readPixel16Z(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + case PSMT16SZ: + addr = getPixelAddress16SZ(j, i, ptex->tbp0, ptex->tbw); + + if( 2*addr < 0x00400000 ) + u = readPixel16SZ(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + default: + assert(0); + } + + *dst++ = u; + } + } + + SaveTGA("tex.tga", ptex->tw, ptex->th, &data[0]); +} + +} diff --git a/plugins/zerogs/opengl/targets.h b/plugins/zerogs/opengl/targets.h index 6c7bfdf6a1..22bf4020d9 100644 --- a/plugins/zerogs/opengl/targets.h +++ b/plugins/zerogs/opengl/targets.h @@ -1,160 +1,160 @@ -/* ZeroGS KOSMOS - * Copyright (C) 2005-2006 zerofrog@gmail.com - * - * 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 - */ - -#define TARGET_VIRTUAL_KEY 0x80000000 - -namespace ZeroGS { - - // manages render targets - class CRenderTargetMngr - { - public: - typedef map MAPTARGETS; - - enum TargetOptions - { - TO_DepthBuffer = 1, - TO_StrictHeight = 2, // height returned has to be the same as requested - TO_Virtual = 4 - }; - - ~CRenderTargetMngr() { Destroy(); } - - void Destroy(); - static MAPTARGETS::iterator GetOldestTarg(MAPTARGETS& m); - - CRenderTarget* GetTarg(const frameInfo& frame, u32 Options, int maxposheight); - inline CRenderTarget* GetTarg(int fbp, int fbw) { - MAPTARGETS::iterator it = mapTargets.find(fbp|(fbw<<16)); - return it != mapTargets.end() ? it->second : NULL; - } - - // gets all targets with a range - void GetTargs(int start, int end, list& listTargets) const; - - // resolves all targets within a range - __forceinline void Resolve(int start, int end); - __forceinline void ResolveAll() { - for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it ) - it->second->Resolve(); - } - - void DestroyAllTargs(int start, int end, int fbw); - void DestroyIntersecting(CRenderTarget* prndr); - - // promotes a target from virtual to real - inline CRenderTarget* Promote(u32 key) { - assert( !(key & TARGET_VIRTUAL_KEY) ); - - // promote to regular targ - CRenderTargetMngr::MAPTARGETS::iterator it = mapTargets.find(key|TARGET_VIRTUAL_KEY); - assert( it != mapTargets.end() ); - - CRenderTarget* ptarg = it->second; - mapTargets.erase(it); - - DestroyIntersecting(ptarg); - - it = mapTargets.find(key); - if( it != mapTargets.end() ) { - DestroyTarg(it->second); - it->second = ptarg; - } - else - mapTargets[key] = ptarg; - - if( g_GameSettings & GAME_RESOLVEPROMOTED ) - ptarg->status = CRenderTarget::TS_Resolved; - else - ptarg->status = CRenderTarget::TS_NeedUpdate; - return ptarg; - } - - static void DestroyTarg(CRenderTarget* ptarg); - - MAPTARGETS mapTargets, mapDummyTargs; - }; - - class CMemoryTargetMngr - { - public: - CMemoryTargetMngr() : curstamp(0) {} - CMemoryTarget* GetMemoryTarget(const tex0Info& tex0, int forcevalidate); // pcbp is pointer to start of clut - - void Destroy(); // destroy all targs - - void ClearRange(int starty, int endy); // set all targets to cleared - void DestroyCleared(); // flush all cleared targes - void DestroyOldest(); - - list listTargets, listClearedTargets; - u32 curstamp; - - private: - list::iterator DestroyTargetIter(list::iterator& it); - }; - - class CBitwiseTextureMngr - { - public: - ~CBitwiseTextureMngr() { Destroy(); } - - void Destroy(); - - // since GetTex can delete textures to free up mem, it is dangerous if using that texture, so specify at least one other tex to save - __forceinline u32 GetTex(u32 bitvalue, u32 ptexDoNotDelete) { - map::iterator it = mapTextures.find(bitvalue); - if( it != mapTextures.end() ) - return it->second; - return GetTexInt(bitvalue, ptexDoNotDelete); - } - - private: - u32 GetTexInt(u32 bitvalue, u32 ptexDoNotDelete); - - map mapTextures; - }; - - // manages - class CRangeManager - { - public: - CRangeManager() - { - ranges.reserve(16); - } - - // [start, end) - struct RANGE - { - RANGE() {} - inline RANGE(int start, int end) : start(start), end(end) {} - int start, end; - }; - - // works in semi logN - void Insert(int start, int end); - inline void Clear() { ranges.resize(0); } - - vector ranges; // organized in ascending order, non-intersecting - }; - - extern CRenderTargetMngr s_RTs, s_DepthRTs; - extern CBitwiseTextureMngr s_BitwiseTextures; - extern CMemoryTargetMngr g_MemTargs; -} +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#define TARGET_VIRTUAL_KEY 0x80000000 + +namespace ZeroGS { + + // manages render targets + class CRenderTargetMngr + { + public: + typedef map MAPTARGETS; + + enum TargetOptions + { + TO_DepthBuffer = 1, + TO_StrictHeight = 2, // height returned has to be the same as requested + TO_Virtual = 4 + }; + + ~CRenderTargetMngr() { Destroy(); } + + void Destroy(); + static MAPTARGETS::iterator GetOldestTarg(MAPTARGETS& m); + + CRenderTarget* GetTarg(const frameInfo& frame, u32 Options, int maxposheight); + inline CRenderTarget* GetTarg(int fbp, int fbw) { + MAPTARGETS::iterator it = mapTargets.find(fbp|(fbw<<16)); + return it != mapTargets.end() ? it->second : NULL; + } + + // gets all targets with a range + void GetTargs(int start, int end, list& listTargets) const; + + // resolves all targets within a range + __forceinline void Resolve(int start, int end); + __forceinline void ResolveAll() { + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it ) + it->second->Resolve(); + } + + void DestroyAllTargs(int start, int end, int fbw); + void DestroyIntersecting(CRenderTarget* prndr); + + // promotes a target from virtual to real + inline CRenderTarget* Promote(u32 key) { + assert( !(key & TARGET_VIRTUAL_KEY) ); + + // promote to regular targ + CRenderTargetMngr::MAPTARGETS::iterator it = mapTargets.find(key|TARGET_VIRTUAL_KEY); + assert( it != mapTargets.end() ); + + CRenderTarget* ptarg = it->second; + mapTargets.erase(it); + + DestroyIntersecting(ptarg); + + it = mapTargets.find(key); + if( it != mapTargets.end() ) { + DestroyTarg(it->second); + it->second = ptarg; + } + else + mapTargets[key] = ptarg; + + if( g_GameSettings & GAME_RESOLVEPROMOTED ) + ptarg->status = CRenderTarget::TS_Resolved; + else + ptarg->status = CRenderTarget::TS_NeedUpdate; + return ptarg; + } + + static void DestroyTarg(CRenderTarget* ptarg); + + MAPTARGETS mapTargets, mapDummyTargs; + }; + + class CMemoryTargetMngr + { + public: + CMemoryTargetMngr() : curstamp(0) {} + CMemoryTarget* GetMemoryTarget(const tex0Info& tex0, int forcevalidate); // pcbp is pointer to start of clut + + void Destroy(); // destroy all targs + + void ClearRange(int starty, int endy); // set all targets to cleared + void DestroyCleared(); // flush all cleared targes + void DestroyOldest(); + + list listTargets, listClearedTargets; + u32 curstamp; + + private: + list::iterator DestroyTargetIter(list::iterator& it); + }; + + class CBitwiseTextureMngr + { + public: + ~CBitwiseTextureMngr() { Destroy(); } + + void Destroy(); + + // since GetTex can delete textures to free up mem, it is dangerous if using that texture, so specify at least one other tex to save + __forceinline u32 GetTex(u32 bitvalue, u32 ptexDoNotDelete) { + map::iterator it = mapTextures.find(bitvalue); + if( it != mapTextures.end() ) + return it->second; + return GetTexInt(bitvalue, ptexDoNotDelete); + } + + private: + u32 GetTexInt(u32 bitvalue, u32 ptexDoNotDelete); + + map mapTextures; + }; + + // manages + class CRangeManager + { + public: + CRangeManager() + { + ranges.reserve(16); + } + + // [start, end) + struct RANGE + { + RANGE() {} + inline RANGE(int start, int end) : start(start), end(end) {} + int start, end; + }; + + // works in semi logN + void Insert(int start, int end); + inline void Clear() { ranges.resize(0); } + + vector ranges; // organized in ascending order, non-intersecting + }; + + extern CRenderTargetMngr s_RTs, s_DepthRTs; + extern CBitwiseTextureMngr s_BitwiseTextures; + extern CMemoryTargetMngr g_MemTargs; +} diff --git a/plugins/zerogs/opengl/x86.cpp b/plugins/zerogs/opengl/x86.cpp index cb33e0302c..26b988b2fd 100644 --- a/plugins/zerogs/opengl/x86.cpp +++ b/plugins/zerogs/opengl/x86.cpp @@ -1,571 +1,571 @@ -/* ZeroGS KOSMOS - * Copyright (C) 2005-2006 Gabest/zerofrog@gmail.com - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "GS.h" -#include "Mem.h" -#include "x86.h" - -#if defined(ZEROGS_SSE2) && (defined(_WIN32)||defined(__x86_64__)) -#include -#include -#endif - -// swizzling - -void __fastcall SwizzleBlock32_c(u8* dst, u8* src, int srcpitch, u32 WriteMask) -{ - u32* d = &g_columnTable32[0][0]; - - if(WriteMask == 0xffffffff) - { - for(int j = 0; j < 8; j++, d += 8, src += srcpitch) - for(int i = 0; i < 8; i++) - ((u32*)dst)[d[i]] = ((u32*)src)[i]; - } - else - { - for(int j = 0; j < 8; j++, d += 8, src += srcpitch) - for(int i = 0; i < 8; i++) - ((u32*)dst)[d[i]] = (((u32*)dst)[d[i]] & ~WriteMask) | (((u32*)src)[i] & WriteMask); - } -} - -void __fastcall SwizzleBlock16_c(u8* dst, u8* src, int srcpitch) -{ - u32* d = &g_columnTable16[0][0]; - - for(int j = 0; j < 8; j++, d += 16, src += srcpitch) - for(int i = 0; i < 16; i++) - ((u16*)dst)[d[i]] = ((u16*)src)[i]; -} - -void __fastcall SwizzleBlock8_c(u8* dst, u8* src, int srcpitch) -{ - u32* d = &g_columnTable8[0][0]; - - for(int j = 0; j < 16; j++, d += 16, src += srcpitch) - for(int i = 0; i < 16; i++) - dst[d[i]] = src[i]; -} - -void __fastcall SwizzleBlock4_c(u8* dst, u8* src, int srcpitch) -{ - u32* d = &g_columnTable4[0][0]; - - for(int j = 0; j < 16; j++, d += 32, src += srcpitch) - { - for(int i = 0; i < 32; i++) - { - u32 addr = d[i]; - u8 c = (src[i>>1] >> ((i&1) << 2)) & 0x0f; - u32 shift = (addr&1) << 2; - dst[addr >> 1] = (dst[addr >> 1] & (0xf0 >> shift)) | (c << shift); - } - } -} - -#define _FrameSwizzleBlock(type, transfer, transfer16, incsrc) \ -/* FrameSwizzleBlock32 */ \ -void __fastcall FrameSwizzleBlock32##type##c(u32* dst, u32* src, int srcpitch, u32 WriteMask) \ -{ \ - u32* d = &g_columnTable32[0][0]; \ - \ - if( WriteMask == 0xffffffff ) { \ - for(int i = 0; i < 8; ++i, d += 8) { \ - for(int j = 0; j < 8; ++j) { \ - dst[d[j]] = (transfer); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ - else { \ - for(int i = 0; i < 8; ++i, d += 8) { \ - for(int j = 0; j < 8; ++j) { \ - dst[d[j]] = ((transfer)&WriteMask)|(dst[d[j]]&~WriteMask); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ -} \ -\ -/* FrameSwizzleBlock16 */ \ -void __fastcall FrameSwizzleBlock16##type##c(u16* dst, u32* src, int srcpitch, u32 WriteMask) \ -{ \ - u32* d = &g_columnTable16[0][0]; \ - \ - if( WriteMask == 0xffff ) { \ - for(int i = 0; i < 8; ++i, d += 16) { \ - for(int j = 0; j < 16; ++j) { \ - u32 temp = (transfer); \ - dst[d[j]] = RGBA32to16(temp); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ - else { \ - for(int i = 0; i < 8; ++i, d += 16) { \ - for(int j = 0; j < 16; ++j) { \ - u32 temp = (transfer); \ - u32 dsrc = RGBA32to16(temp); \ - dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ -} \ -\ -/* Frame16SwizzleBlock32 */ \ -void __fastcall Frame16SwizzleBlock32##type##c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask) \ -{ \ - u32* d = &g_columnTable32[0][0]; \ -\ - if( WriteMask == 0xffffffff ) { \ - for(int i = 0; i < 8; ++i, d += 8) { \ - for(int j = 0; j < 8; ++j) { \ - Vector_16F dsrc16 = (transfer16); \ - dst[d[j]] = Float16ToARGB(dsrc16); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ - else { \ - for(int i = 0; i < 8; ++i, d += 8) { \ - for(int j = 0; j < 8; ++j) { \ - Vector_16F dsrc16 = (transfer16); \ - u32 dsrc = Float16ToARGB(dsrc16); \ - dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ - } \ -\ -/* Frame16SwizzleBlock32Z */ \ -void __fastcall Frame16SwizzleBlock32Z##type##c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask) \ -{ \ - u32* d = &g_columnTable32[0][0]; \ - if( WriteMask == 0xffffffff ) { /* breaks KH text if not checked */ \ - for(int i = 0; i < 8; ++i, d += 8) { \ - for(int j = 0; j < 8; ++j) { \ - Vector_16F dsrc16 = (transfer16); \ - dst[d[j]] = Float16ToARGB_Z(dsrc16); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ - else { \ - for(int i = 0; i < 8; ++i, d += 8) { \ - for(int j = 0; j < 8; ++j) { \ - Vector_16F dsrc16 = (transfer16); \ - u32 dsrc = Float16ToARGB_Z(dsrc16); \ - dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ - } \ - \ - /* Frame16SwizzleBlock16 */ \ -void __fastcall Frame16SwizzleBlock16##type##c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask) \ -{ \ - u32* d = &g_columnTable16[0][0]; \ - \ - if( (WriteMask&0xfff8f8f8) == 0xfff8f8f8) { \ - for(int i = 0; i < 8; ++i, d += 16) { \ - for(int j = 0; j < 16; ++j) { \ - Vector_16F dsrc16 = (transfer16); \ - dst[d[j]] = Float16ToARGB16(dsrc16); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ - else { \ - for(int i = 0; i < 8; ++i, d += 16) { \ - for(int j = 0; j < 16; ++j) { \ - Vector_16F dsrc16 = (transfer16); \ - u32 dsrc = Float16ToARGB16(dsrc16); \ - dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ - } \ - src += srcpitch << incsrc; \ - } \ - } \ - } \ - \ - /* Frame16SwizzleBlock16Z */ \ -void __fastcall Frame16SwizzleBlock16Z##type##c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask) \ -{ \ - u32* d = &g_columnTable16[0][0]; \ - \ - for(int i = 0; i < 8; ++i, d += 16) { \ - for(int j = 0; j < 16; ++j) { \ - Vector_16F dsrc16 = (transfer16); \ - dst[d[j]] = Float16ToARGB16_Z(dsrc16); \ - } \ - src += srcpitch << incsrc; \ - } \ -} \ - -_FrameSwizzleBlock(_, src[j], src[j], 0); -_FrameSwizzleBlock(A2_, (src[2*j]+src[2*j+1])>>1, src[2*j], 0); -_FrameSwizzleBlock(A4_, (src[2*j]+src[2*j+1]+src[2*j+srcpitch]+src[2*j+srcpitch+1])>>2, src[2*j], 1); - -#ifdef ZEROGS_SSE2 - -//void __fastcall WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32* clut) -//{ -// __asm { -// mov eax, vm -// mov ecx, clut -// mov edx, 8 -// } -// -//Extract32x2: -// __asm { -// movdqa xmm0, qword ptr [eax] -// movdqa xmm1, qword ptr [eax+16] -// movdqa xmm2, qword ptr [eax+32] -// movdqa xmm3, qword ptr [eax+48] -// -// // rearrange -// pshuflw xmm0, xmm0, 0xd8 -// pshufhw xmm0, xmm0, 0xd8 -// pshuflw xmm1, xmm1, 0xd8 -// pshufhw xmm1, xmm1, 0xd8 -// pshuflw xmm2, xmm2, 0xd8 -// pshufhw xmm2, xmm2, 0xd8 -// pshuflw xmm3, xmm3, 0xd8 -// pshufhw xmm3, xmm3, 0xd8 -// -// movdqa xmm4, xmm0 -// movdqa xmm6, xmm2 -// -// shufps xmm0, xmm1, 0x88 -// shufps xmm2, xmm3, 0x88 -// -// shufps xmm4, xmm1, 0xdd -// shufps xmm6, xmm3, 0xdd -// -// pshufd xmm0, xmm0, 0xd8 -// pshufd xmm2, xmm2, 0xd8 -// pshufd xmm4, xmm4, 0xd8 -// pshufd xmm6, xmm6, 0xd8 -// -// // left column -// movhlps xmm1, xmm0 -// movlhps xmm0, xmm2 -// //movdqa xmm7, [ecx] -// -// movdqa [ecx], xmm0 -// shufps xmm1, xmm2, 0xe4 -// movdqa [ecx+16], xmm1 -// -// // right column -// movhlps xmm3, xmm4 -// movlhps xmm4, xmm6 -// movdqa [ecx+32], xmm4 -// shufps xmm3, xmm6, 0xe4 -// movdqa [ecx+48], xmm3 -// -// add eax, 16*4 -// add ecx, 16*8 -// sub edx, 1 -// cmp edx, 0 -// jne Extract32x2 -// } -//} - -#if (defined(_WIN32)||defined(__x86_64__)) - -extern "C" void __fastcall WriteCLUT_T32_I8_CSM1_sse2(u32* vm, u32* clut) -{ - __m128i* src = (__m128i*)vm; - __m128i* dst = (__m128i*)clut; - - for(int j = 0; j < 64; j += 32, src += 32, dst += 32) - { - for(int i = 0; i < 16; i += 4) - { - __m128i r0 = _mm_load_si128(&src[i+0]); - __m128i r1 = _mm_load_si128(&src[i+1]); - __m128i r2 = _mm_load_si128(&src[i+2]); - __m128i r3 = _mm_load_si128(&src[i+3]); - - _mm_store_si128(&dst[i*2+0], _mm_unpacklo_epi64(r0, r1)); - _mm_store_si128(&dst[i*2+1], _mm_unpacklo_epi64(r2, r3)); - _mm_store_si128(&dst[i*2+2], _mm_unpackhi_epi64(r0, r1)); - _mm_store_si128(&dst[i*2+3], _mm_unpackhi_epi64(r2, r3)); - - __m128i r4 = _mm_load_si128(&src[i+0+16]); - __m128i r5 = _mm_load_si128(&src[i+1+16]); - __m128i r6 = _mm_load_si128(&src[i+2+16]); - __m128i r7 = _mm_load_si128(&src[i+3+16]); - - _mm_store_si128(&dst[i*2+4], _mm_unpacklo_epi64(r4, r5)); - _mm_store_si128(&dst[i*2+5], _mm_unpacklo_epi64(r6, r7)); - _mm_store_si128(&dst[i*2+6], _mm_unpackhi_epi64(r4, r5)); - _mm_store_si128(&dst[i*2+7], _mm_unpackhi_epi64(r6, r7)); - } - } -} - -extern "C" void __fastcall WriteCLUT_T32_I4_CSM1_sse2(u32* vm, u32* clut) -{ - __m128i* src = (__m128i*)vm; - __m128i* dst = (__m128i*)clut; - - __m128i r0 = _mm_load_si128(&src[0]); - __m128i r1 = _mm_load_si128(&src[1]); - __m128i r2 = _mm_load_si128(&src[2]); - __m128i r3 = _mm_load_si128(&src[3]); - - _mm_store_si128(&dst[0], _mm_unpacklo_epi64(r0, r1)); - _mm_store_si128(&dst[1], _mm_unpacklo_epi64(r2, r3)); - _mm_store_si128(&dst[2], _mm_unpackhi_epi64(r0, r1)); - _mm_store_si128(&dst[3], _mm_unpackhi_epi64(r2, r3)); -} -#endif - -#if defined(_MSC_VER) - -extern "C" { -PCSX2_ALIGNED16(int s_clut16mask2[4]) = { 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff }; -PCSX2_ALIGNED16(int s_clut16mask[8]) = { 0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000, - 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff}; -} - -#if !defined(__x86_64__) - -extern "C" void __fastcall WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut) -{ - __asm { - mov eax, vm - mov ecx, clut - movdqa xmm0, qword ptr [eax] - movdqa xmm1, qword ptr [eax+16] - movdqa xmm2, qword ptr [eax+32] - movdqa xmm3, qword ptr [eax+48] - - // rearrange - pshuflw xmm0, xmm0, 0x88 - pshufhw xmm0, xmm0, 0x88 - pshuflw xmm1, xmm1, 0x88 - pshufhw xmm1, xmm1, 0x88 - pshuflw xmm2, xmm2, 0x88 - pshufhw xmm2, xmm2, 0x88 - pshuflw xmm3, xmm3, 0x88 - pshufhw xmm3, xmm3, 0x88 - - shufps xmm0, xmm1, 0x88 - shufps xmm2, xmm3, 0x88 - - pshufd xmm0, xmm0, 0xd8 - pshufd xmm2, xmm2, 0xd8 - - pxor xmm6, xmm6 - - test ecx, 15 - jnz WriteUnaligned - - movdqa xmm7, s_clut16mask // saves upper 16 bits - - // have to save interlaced with the old data - movdqa xmm4, [ecx] - movdqa xmm5, [ecx+32] - movhlps xmm1, xmm0 - movlhps xmm0, xmm2 // lower 8 colors - - pand xmm4, xmm7 - pand xmm5, xmm7 - - shufps xmm1, xmm2, 0xe4 // upper 8 colors - movdqa xmm2, xmm0 - movdqa xmm3, xmm1 - - punpcklwd xmm0, xmm6 - punpcklwd xmm1, xmm6 - por xmm0, xmm4 - por xmm1, xmm5 - - punpckhwd xmm2, xmm6 - punpckhwd xmm3, xmm6 - - movdqa [ecx], xmm0 - movdqa [ecx+32], xmm1 - - movdqa xmm5, xmm7 - pand xmm7, [ecx+16] - pand xmm5, [ecx+48] - - por xmm2, xmm7 - por xmm3, xmm5 - - movdqa [ecx+16], xmm2 - movdqa [ecx+48], xmm3 - jmp End - -WriteUnaligned: - // ecx is offset by 2 - sub ecx, 2 - - movdqa xmm7, s_clut16mask2 // saves lower 16 bits - - // have to save interlaced with the old data - movdqa xmm4, [ecx] - movdqa xmm5, [ecx+32] - movhlps xmm1, xmm0 - movlhps xmm0, xmm2 // lower 8 colors - - pand xmm4, xmm7 - pand xmm5, xmm7 - - shufps xmm1, xmm2, 0xe4 // upper 8 colors - movdqa xmm2, xmm0 - movdqa xmm3, xmm1 - - punpcklwd xmm0, xmm6 - punpcklwd xmm1, xmm6 - pslld xmm0, 16 - pslld xmm1, 16 - por xmm0, xmm4 - por xmm1, xmm5 - - punpckhwd xmm2, xmm6 - punpckhwd xmm3, xmm6 - pslld xmm2, 16 - pslld xmm3, 16 - - movdqa [ecx], xmm0 - movdqa [ecx+32], xmm1 - - movdqa xmm5, xmm7 - pand xmm7, [ecx+16] - pand xmm5, [ecx+48] - - por xmm2, xmm7 - por xmm3, xmm5 - - movdqa [ecx+16], xmm2 - movdqa [ecx+48], xmm3 -End: - } -} -#endif // __x86_64__ -#endif // _MSC_VER - -#endif // ZEROGS_SSE2 - -void __fastcall WriteCLUT_T16_I8_CSM1_c(u32* _vm, u32* _clut) -{ - const static u32 map[] = - { - 0, 2, 8, 10, 16, 18, 24, 26, - 4, 6, 12, 14, 20, 22, 28, 30, - 1, 3, 9, 11, 17, 19, 25, 27, - 5, 7, 13, 15, 21, 23, 29, 31 - }; - - u16* vm = (u16*)_vm; - u16* clut = (u16*)_clut; - - int left = ((u32)(uptr)clut&2) ? 512 : 512-(((u32)(uptr)clut)&0x3ff)/2; - - for(int j = 0; j < 8; j++, vm += 32, clut += 64, left -= 32) - { - if(left == 32) { - assert( left == 32 ); - for(int i = 0; i < 16; i++) - clut[2*i] = vm[map[i]]; - - clut = (u16*)((uptr)clut & ~0x3ff) + 1; - - for(int i = 16; i < 32; i++) - clut[2*i] = vm[map[i]]; - } - else { - if( left == 0 ) { - clut = (u16*)((uptr)clut & ~0x3ff) + 1; - left = -1; - } - - for(int i = 0; i < 32; i++) - clut[2*i] = vm[map[i]]; - } - } -} - -void __fastcall WriteCLUT_T32_I8_CSM1_c(u32* vm, u32* clut) -{ - u64* src = (u64*)vm; - u64* dst = (u64*)clut; - - for(int j = 0; j < 2; j++, src += 32) { - for(int i = 0; i < 4; i++, dst+=16, src+=8) - { - dst[0] = src[0]; - dst[1] = src[2]; - dst[2] = src[4]; - dst[3] = src[6]; - dst[4] = src[1]; - dst[5] = src[3]; - dst[6] = src[5]; - dst[7] = src[7]; - - dst[8] = src[32]; - dst[9] = src[32+2]; - dst[10] = src[32+4]; - dst[11] = src[32+6]; - dst[12] = src[32+1]; - dst[13] = src[32+3]; - dst[14] = src[32+5]; - dst[15] = src[32+7]; - } - } -} - -void __fastcall WriteCLUT_T16_I4_CSM1_c(u32* _vm, u32* _clut) -{ - u16* dst = (u16*)_clut; - u16* src = (u16*)_vm; - - dst[0] = src[0]; dst[2] = src[2]; - dst[4] = src[8]; dst[6] = src[10]; - dst[8] = src[16]; dst[10] = src[18]; - dst[12] = src[24]; dst[14] = src[26]; - dst[16] = src[4]; dst[18] = src[6]; - dst[20] = src[12]; dst[22] = src[14]; - dst[24] = src[20]; dst[26] = src[22]; - dst[28] = src[28]; dst[30] = src[30]; -} - -void __fastcall WriteCLUT_T32_I4_CSM1_c(u32* vm, u32* clut) -{ - u64* src = (u64*)vm; - u64* dst = (u64*)clut; - - dst[0] = src[0]; - dst[1] = src[2]; - dst[2] = src[4]; - dst[3] = src[6]; - dst[4] = src[1]; - dst[5] = src[3]; - dst[6] = src[5]; - dst[7] = src[7]; -} +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 Gabest/zerofrog@gmail.com + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "GS.h" +#include "Mem.h" +#include "x86.h" + +#if defined(ZEROGS_SSE2) && (defined(_WIN32)||defined(__x86_64__)) +#include +#include +#endif + +// swizzling + +void __fastcall SwizzleBlock32_c(u8* dst, u8* src, int srcpitch, u32 WriteMask) +{ + u32* d = &g_columnTable32[0][0]; + + if(WriteMask == 0xffffffff) + { + for(int j = 0; j < 8; j++, d += 8, src += srcpitch) + for(int i = 0; i < 8; i++) + ((u32*)dst)[d[i]] = ((u32*)src)[i]; + } + else + { + for(int j = 0; j < 8; j++, d += 8, src += srcpitch) + for(int i = 0; i < 8; i++) + ((u32*)dst)[d[i]] = (((u32*)dst)[d[i]] & ~WriteMask) | (((u32*)src)[i] & WriteMask); + } +} + +void __fastcall SwizzleBlock16_c(u8* dst, u8* src, int srcpitch) +{ + u32* d = &g_columnTable16[0][0]; + + for(int j = 0; j < 8; j++, d += 16, src += srcpitch) + for(int i = 0; i < 16; i++) + ((u16*)dst)[d[i]] = ((u16*)src)[i]; +} + +void __fastcall SwizzleBlock8_c(u8* dst, u8* src, int srcpitch) +{ + u32* d = &g_columnTable8[0][0]; + + for(int j = 0; j < 16; j++, d += 16, src += srcpitch) + for(int i = 0; i < 16; i++) + dst[d[i]] = src[i]; +} + +void __fastcall SwizzleBlock4_c(u8* dst, u8* src, int srcpitch) +{ + u32* d = &g_columnTable4[0][0]; + + for(int j = 0; j < 16; j++, d += 32, src += srcpitch) + { + for(int i = 0; i < 32; i++) + { + u32 addr = d[i]; + u8 c = (src[i>>1] >> ((i&1) << 2)) & 0x0f; + u32 shift = (addr&1) << 2; + dst[addr >> 1] = (dst[addr >> 1] & (0xf0 >> shift)) | (c << shift); + } + } +} + +#define _FrameSwizzleBlock(type, transfer, transfer16, incsrc) \ +/* FrameSwizzleBlock32 */ \ +void __fastcall FrameSwizzleBlock32##type##c(u32* dst, u32* src, int srcpitch, u32 WriteMask) \ +{ \ + u32* d = &g_columnTable32[0][0]; \ + \ + if( WriteMask == 0xffffffff ) { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + dst[d[j]] = (transfer); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + dst[d[j]] = ((transfer)&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ +} \ +\ +/* FrameSwizzleBlock16 */ \ +void __fastcall FrameSwizzleBlock16##type##c(u16* dst, u32* src, int srcpitch, u32 WriteMask) \ +{ \ + u32* d = &g_columnTable16[0][0]; \ + \ + if( WriteMask == 0xffff ) { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + u32 temp = (transfer); \ + dst[d[j]] = RGBA32to16(temp); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + u32 temp = (transfer); \ + u32 dsrc = RGBA32to16(temp); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ +} \ +\ +/* Frame16SwizzleBlock32 */ \ +void __fastcall Frame16SwizzleBlock32##type##c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask) \ +{ \ + u32* d = &g_columnTable32[0][0]; \ +\ + if( WriteMask == 0xffffffff ) { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + u32 dsrc = Float16ToARGB(dsrc16); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + } \ +\ +/* Frame16SwizzleBlock32Z */ \ +void __fastcall Frame16SwizzleBlock32Z##type##c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask) \ +{ \ + u32* d = &g_columnTable32[0][0]; \ + if( WriteMask == 0xffffffff ) { /* breaks KH text if not checked */ \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB_Z(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + u32 dsrc = Float16ToARGB_Z(dsrc16); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + } \ + \ + /* Frame16SwizzleBlock16 */ \ +void __fastcall Frame16SwizzleBlock16##type##c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask) \ +{ \ + u32* d = &g_columnTable16[0][0]; \ + \ + if( (WriteMask&0xfff8f8f8) == 0xfff8f8f8) { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB16(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + u32 dsrc = Float16ToARGB16(dsrc16); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + } \ + \ + /* Frame16SwizzleBlock16Z */ \ +void __fastcall Frame16SwizzleBlock16Z##type##c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask) \ +{ \ + u32* d = &g_columnTable16[0][0]; \ + \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB16_Z(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ +} \ + +_FrameSwizzleBlock(_, src[j], src[j], 0); +_FrameSwizzleBlock(A2_, (src[2*j]+src[2*j+1])>>1, src[2*j], 0); +_FrameSwizzleBlock(A4_, (src[2*j]+src[2*j+1]+src[2*j+srcpitch]+src[2*j+srcpitch+1])>>2, src[2*j], 1); + +#ifdef ZEROGS_SSE2 + +//void __fastcall WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32* clut) +//{ +// __asm { +// mov eax, vm +// mov ecx, clut +// mov edx, 8 +// } +// +//Extract32x2: +// __asm { +// movdqa xmm0, qword ptr [eax] +// movdqa xmm1, qword ptr [eax+16] +// movdqa xmm2, qword ptr [eax+32] +// movdqa xmm3, qword ptr [eax+48] +// +// // rearrange +// pshuflw xmm0, xmm0, 0xd8 +// pshufhw xmm0, xmm0, 0xd8 +// pshuflw xmm1, xmm1, 0xd8 +// pshufhw xmm1, xmm1, 0xd8 +// pshuflw xmm2, xmm2, 0xd8 +// pshufhw xmm2, xmm2, 0xd8 +// pshuflw xmm3, xmm3, 0xd8 +// pshufhw xmm3, xmm3, 0xd8 +// +// movdqa xmm4, xmm0 +// movdqa xmm6, xmm2 +// +// shufps xmm0, xmm1, 0x88 +// shufps xmm2, xmm3, 0x88 +// +// shufps xmm4, xmm1, 0xdd +// shufps xmm6, xmm3, 0xdd +// +// pshufd xmm0, xmm0, 0xd8 +// pshufd xmm2, xmm2, 0xd8 +// pshufd xmm4, xmm4, 0xd8 +// pshufd xmm6, xmm6, 0xd8 +// +// // left column +// movhlps xmm1, xmm0 +// movlhps xmm0, xmm2 +// //movdqa xmm7, [ecx] +// +// movdqa [ecx], xmm0 +// shufps xmm1, xmm2, 0xe4 +// movdqa [ecx+16], xmm1 +// +// // right column +// movhlps xmm3, xmm4 +// movlhps xmm4, xmm6 +// movdqa [ecx+32], xmm4 +// shufps xmm3, xmm6, 0xe4 +// movdqa [ecx+48], xmm3 +// +// add eax, 16*4 +// add ecx, 16*8 +// sub edx, 1 +// cmp edx, 0 +// jne Extract32x2 +// } +//} + +#if (defined(_WIN32)||defined(__x86_64__)) + +extern "C" void __fastcall WriteCLUT_T32_I8_CSM1_sse2(u32* vm, u32* clut) +{ + __m128i* src = (__m128i*)vm; + __m128i* dst = (__m128i*)clut; + + for(int j = 0; j < 64; j += 32, src += 32, dst += 32) + { + for(int i = 0; i < 16; i += 4) + { + __m128i r0 = _mm_load_si128(&src[i+0]); + __m128i r1 = _mm_load_si128(&src[i+1]); + __m128i r2 = _mm_load_si128(&src[i+2]); + __m128i r3 = _mm_load_si128(&src[i+3]); + + _mm_store_si128(&dst[i*2+0], _mm_unpacklo_epi64(r0, r1)); + _mm_store_si128(&dst[i*2+1], _mm_unpacklo_epi64(r2, r3)); + _mm_store_si128(&dst[i*2+2], _mm_unpackhi_epi64(r0, r1)); + _mm_store_si128(&dst[i*2+3], _mm_unpackhi_epi64(r2, r3)); + + __m128i r4 = _mm_load_si128(&src[i+0+16]); + __m128i r5 = _mm_load_si128(&src[i+1+16]); + __m128i r6 = _mm_load_si128(&src[i+2+16]); + __m128i r7 = _mm_load_si128(&src[i+3+16]); + + _mm_store_si128(&dst[i*2+4], _mm_unpacklo_epi64(r4, r5)); + _mm_store_si128(&dst[i*2+5], _mm_unpacklo_epi64(r6, r7)); + _mm_store_si128(&dst[i*2+6], _mm_unpackhi_epi64(r4, r5)); + _mm_store_si128(&dst[i*2+7], _mm_unpackhi_epi64(r6, r7)); + } + } +} + +extern "C" void __fastcall WriteCLUT_T32_I4_CSM1_sse2(u32* vm, u32* clut) +{ + __m128i* src = (__m128i*)vm; + __m128i* dst = (__m128i*)clut; + + __m128i r0 = _mm_load_si128(&src[0]); + __m128i r1 = _mm_load_si128(&src[1]); + __m128i r2 = _mm_load_si128(&src[2]); + __m128i r3 = _mm_load_si128(&src[3]); + + _mm_store_si128(&dst[0], _mm_unpacklo_epi64(r0, r1)); + _mm_store_si128(&dst[1], _mm_unpacklo_epi64(r2, r3)); + _mm_store_si128(&dst[2], _mm_unpackhi_epi64(r0, r1)); + _mm_store_si128(&dst[3], _mm_unpackhi_epi64(r2, r3)); +} +#endif + +#if defined(_MSC_VER) + +extern "C" { +PCSX2_ALIGNED16(int s_clut16mask2[4]) = { 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff }; +PCSX2_ALIGNED16(int s_clut16mask[8]) = { 0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000, + 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff}; +} + +#if !defined(__x86_64__) + +extern "C" void __fastcall WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut) +{ + __asm { + mov eax, vm + mov ecx, clut + movdqa xmm0, qword ptr [eax] + movdqa xmm1, qword ptr [eax+16] + movdqa xmm2, qword ptr [eax+32] + movdqa xmm3, qword ptr [eax+48] + + // rearrange + pshuflw xmm0, xmm0, 0x88 + pshufhw xmm0, xmm0, 0x88 + pshuflw xmm1, xmm1, 0x88 + pshufhw xmm1, xmm1, 0x88 + pshuflw xmm2, xmm2, 0x88 + pshufhw xmm2, xmm2, 0x88 + pshuflw xmm3, xmm3, 0x88 + pshufhw xmm3, xmm3, 0x88 + + shufps xmm0, xmm1, 0x88 + shufps xmm2, xmm3, 0x88 + + pshufd xmm0, xmm0, 0xd8 + pshufd xmm2, xmm2, 0xd8 + + pxor xmm6, xmm6 + + test ecx, 15 + jnz WriteUnaligned + + movdqa xmm7, s_clut16mask // saves upper 16 bits + + // have to save interlaced with the old data + movdqa xmm4, [ecx] + movdqa xmm5, [ecx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 // lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0xe4 // upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + + movdqa [ecx], xmm0 + movdqa [ecx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [ecx+16] + pand xmm5, [ecx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [ecx+16], xmm2 + movdqa [ecx+48], xmm3 + jmp End + +WriteUnaligned: + // ecx is offset by 2 + sub ecx, 2 + + movdqa xmm7, s_clut16mask2 // saves lower 16 bits + + // have to save interlaced with the old data + movdqa xmm4, [ecx] + movdqa xmm5, [ecx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 // lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0xe4 // upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + pslld xmm0, 16 + pslld xmm1, 16 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + pslld xmm2, 16 + pslld xmm3, 16 + + movdqa [ecx], xmm0 + movdqa [ecx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [ecx+16] + pand xmm5, [ecx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [ecx+16], xmm2 + movdqa [ecx+48], xmm3 +End: + } +} +#endif // __x86_64__ +#endif // _MSC_VER + +#endif // ZEROGS_SSE2 + +void __fastcall WriteCLUT_T16_I8_CSM1_c(u32* _vm, u32* _clut) +{ + const static u32 map[] = + { + 0, 2, 8, 10, 16, 18, 24, 26, + 4, 6, 12, 14, 20, 22, 28, 30, + 1, 3, 9, 11, 17, 19, 25, 27, + 5, 7, 13, 15, 21, 23, 29, 31 + }; + + u16* vm = (u16*)_vm; + u16* clut = (u16*)_clut; + + int left = ((u32)(uptr)clut&2) ? 512 : 512-(((u32)(uptr)clut)&0x3ff)/2; + + for(int j = 0; j < 8; j++, vm += 32, clut += 64, left -= 32) + { + if(left == 32) { + assert( left == 32 ); + for(int i = 0; i < 16; i++) + clut[2*i] = vm[map[i]]; + + clut = (u16*)((uptr)clut & ~0x3ff) + 1; + + for(int i = 16; i < 32; i++) + clut[2*i] = vm[map[i]]; + } + else { + if( left == 0 ) { + clut = (u16*)((uptr)clut & ~0x3ff) + 1; + left = -1; + } + + for(int i = 0; i < 32; i++) + clut[2*i] = vm[map[i]]; + } + } +} + +void __fastcall WriteCLUT_T32_I8_CSM1_c(u32* vm, u32* clut) +{ + u64* src = (u64*)vm; + u64* dst = (u64*)clut; + + for(int j = 0; j < 2; j++, src += 32) { + for(int i = 0; i < 4; i++, dst+=16, src+=8) + { + dst[0] = src[0]; + dst[1] = src[2]; + dst[2] = src[4]; + dst[3] = src[6]; + dst[4] = src[1]; + dst[5] = src[3]; + dst[6] = src[5]; + dst[7] = src[7]; + + dst[8] = src[32]; + dst[9] = src[32+2]; + dst[10] = src[32+4]; + dst[11] = src[32+6]; + dst[12] = src[32+1]; + dst[13] = src[32+3]; + dst[14] = src[32+5]; + dst[15] = src[32+7]; + } + } +} + +void __fastcall WriteCLUT_T16_I4_CSM1_c(u32* _vm, u32* _clut) +{ + u16* dst = (u16*)_clut; + u16* src = (u16*)_vm; + + dst[0] = src[0]; dst[2] = src[2]; + dst[4] = src[8]; dst[6] = src[10]; + dst[8] = src[16]; dst[10] = src[18]; + dst[12] = src[24]; dst[14] = src[26]; + dst[16] = src[4]; dst[18] = src[6]; + dst[20] = src[12]; dst[22] = src[14]; + dst[24] = src[20]; dst[26] = src[22]; + dst[28] = src[28]; dst[30] = src[30]; +} + +void __fastcall WriteCLUT_T32_I4_CSM1_c(u32* vm, u32* clut) +{ + u64* src = (u64*)vm; + u64* dst = (u64*)clut; + + dst[0] = src[0]; + dst[1] = src[2]; + dst[2] = src[4]; + dst[3] = src[6]; + dst[4] = src[1]; + dst[5] = src[3]; + dst[6] = src[5]; + dst[7] = src[7]; +} diff --git a/plugins/zerogs/opengl/x86.h b/plugins/zerogs/opengl/x86.h index 94cb01e3e3..6cefbc0779 100644 --- a/plugins/zerogs/opengl/x86.h +++ b/plugins/zerogs/opengl/x86.h @@ -1,182 +1,182 @@ -/* ZeroGS KOSMOS - * Copyright (C) 2005-2006 Gabest/zerofrog@gmail.com - * http://www.gabest.org - * - * 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, 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 GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#ifndef ZEROGS_X86 -#define ZEROGS_X86 - -#include "GS.h" - -extern "C" void __fastcall SwizzleBlock32_sse2(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff); -extern "C" void __fastcall SwizzleBlock16_sse2(u8* dst, u8* src, int srcpitch); -extern "C" void __fastcall SwizzleBlock8_sse2(u8* dst, u8* src, int srcpitch); -extern "C" void __fastcall SwizzleBlock4_sse2(u8* dst, u8* src, int srcpitch); -extern "C" void __fastcall SwizzleBlock32u_sse2(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff); -extern "C" void __fastcall SwizzleBlock16u_sse2(u8* dst, u8* src, int srcpitch); -extern "C" void __fastcall SwizzleBlock8u_sse2(u8* dst, u8* src, int srcpitch); -extern "C" void __fastcall SwizzleBlock4u_sse2(u8* dst, u8* src, int srcpitch); - -// frame swizzling - -// no AA -extern "C" void __fastcall FrameSwizzleBlock32_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask); -extern "C" void __fastcall FrameSwizzleBlock16_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask); -extern "C" void __fastcall Frame16SwizzleBlock32_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); -extern "C" void __fastcall Frame16SwizzleBlock32Z_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); -extern "C" void __fastcall Frame16SwizzleBlock16_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); -extern "C" void __fastcall Frame16SwizzleBlock16Z_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); - -// AA 2x -extern "C" void __fastcall FrameSwizzleBlock32A2_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask); -extern "C" void __fastcall FrameSwizzleBlock16A2_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask); -extern "C" void __fastcall Frame16SwizzleBlock32A2_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); -extern "C" void __fastcall Frame16SwizzleBlock32ZA2_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); -extern "C" void __fastcall Frame16SwizzleBlock16A2_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); -extern "C" void __fastcall Frame16SwizzleBlock16ZA2_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); - -// AA 4x -extern "C" void __fastcall FrameSwizzleBlock32A4_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask); -extern "C" void __fastcall FrameSwizzleBlock16A4_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask); -extern "C" void __fastcall Frame16SwizzleBlock32A4_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); -extern "C" void __fastcall Frame16SwizzleBlock32ZA4_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); -extern "C" void __fastcall Frame16SwizzleBlock16A4_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); -extern "C" void __fastcall Frame16SwizzleBlock16ZA4_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); - -extern void __fastcall SwizzleBlock32_c(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff); -extern void __fastcall SwizzleBlock16_c(u8* dst, u8* src, int srcpitch); -extern void __fastcall SwizzleBlock8_c(u8* dst, u8* src, int srcpitch); -extern void __fastcall SwizzleBlock4_c(u8* dst, u8* src, int srcpitch); - -// no AA -extern void __fastcall FrameSwizzleBlock32_c(u32* dst, u32* src, int srcpitch, u32 WriteMask); -extern void __fastcall FrameSwizzleBlock16_c(u16* dst, u32* src, int srcpitch, u32 WriteMask); -extern void __fastcall Frame16SwizzleBlock32_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); -extern void __fastcall Frame16SwizzleBlock32Z_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); -extern void __fastcall Frame16SwizzleBlock16_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); -extern void __fastcall Frame16SwizzleBlock16Z_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); - -// AA 2x -extern void __fastcall FrameSwizzleBlock32A2_c(u32* dst, u32* src, int srcpitch, u32 WriteMask); -extern void __fastcall FrameSwizzleBlock16A2_c(u16* dst, u32* src, int srcpitch, u32 WriteMask); -extern void __fastcall Frame16SwizzleBlock32A2_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); -extern void __fastcall Frame16SwizzleBlock32ZA2_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); -extern void __fastcall Frame16SwizzleBlock16A2_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); -extern void __fastcall Frame16SwizzleBlock16ZA2_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); - -// AA 4x -extern void __fastcall FrameSwizzleBlock32A4_c(u32* dst, u32* src, int srcpitch, u32 WriteMask); -extern void __fastcall FrameSwizzleBlock16A4_c(u16* dst, u32* src, int srcpitch, u32 WriteMask); -extern void __fastcall Frame16SwizzleBlock32A4_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); -extern void __fastcall Frame16SwizzleBlock32ZA4_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); -extern void __fastcall Frame16SwizzleBlock16A4_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); -extern void __fastcall Frame16SwizzleBlock16ZA4_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); - -extern void __fastcall SwizzleColumn32_c(int y, u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff); -extern void __fastcall SwizzleColumn16_c(int y, u8* dst, u8* src, int srcpitch); -extern void __fastcall SwizzleColumn8_c(int y, u8* dst, u8* src, int srcpitch); -extern void __fastcall SwizzleColumn4_c(int y, u8* dst, u8* src, int srcpitch); - -extern "C" void __fastcall WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32* clut); -extern "C" void __fastcall WriteCLUT_T32_I8_CSM1_sse2(u32* vm, u32* clut); -extern "C" void __fastcall WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut); -extern "C" void __fastcall WriteCLUT_T32_I4_CSM1_sse2(u32* vm, u32* clut); -extern void __fastcall WriteCLUT_T16_I8_CSM1_c(u32* vm, u32* clut); -extern void __fastcall WriteCLUT_T32_I8_CSM1_c(u32* vm, u32* clut); - -extern void __fastcall WriteCLUT_T16_I4_CSM1_c(u32* vm, u32* clut); -extern void __fastcall WriteCLUT_T32_I4_CSM1_c(u32* vm, u32* clut); - -#ifdef ZEROGS_SSE2 - -#define SwizzleBlock32 SwizzleBlock32_sse2 -#define SwizzleBlock16 SwizzleBlock16_sse2 -#define SwizzleBlock8 SwizzleBlock8_sse2 -#define SwizzleBlock4 SwizzleBlock4_sse2 -#define SwizzleBlock32u SwizzleBlock32u_sse2 -#define SwizzleBlock16u SwizzleBlock16u_sse2 -#define SwizzleBlock8u SwizzleBlock8u_sse2 -#define SwizzleBlock4u SwizzleBlock4u_sse2 - -#define FrameSwizzleBlock32 FrameSwizzleBlock32_c -#define FrameSwizzleBlock16 FrameSwizzleBlock16_c -#define Frame16SwizzleBlock32 Frame16SwizzleBlock32_c -#define Frame16SwizzleBlock32Z Frame16SwizzleBlock32Z_c -#define Frame16SwizzleBlock16 Frame16SwizzleBlock16_c -#define Frame16SwizzleBlock16Z Frame16SwizzleBlock16Z_c - -#define FrameSwizzleBlock32A2 FrameSwizzleBlock32A2_c -#define FrameSwizzleBlock16A2 FrameSwizzleBlock16A2_c -#define Frame16SwizzleBlock32A2 Frame16SwizzleBlock32A2_c -#define Frame16SwizzleBlock32ZA2 Frame16SwizzleBlock32ZA2_c -#define Frame16SwizzleBlock16A2 Frame16SwizzleBlock16A2_c -#define Frame16SwizzleBlock16ZA2 Frame16SwizzleBlock16ZA2_c - -#define FrameSwizzleBlock32A4 FrameSwizzleBlock32A4_c -#define FrameSwizzleBlock16A4 FrameSwizzleBlock16A4_c -#define Frame16SwizzleBlock32A4 Frame16SwizzleBlock32A4_c -#define Frame16SwizzleBlock32ZA4 Frame16SwizzleBlock32ZA4_c -#define Frame16SwizzleBlock16A4 Frame16SwizzleBlock16A4_c -#define Frame16SwizzleBlock16ZA4 Frame16SwizzleBlock16ZA4_c - -#define WriteCLUT_T16_I8_CSM1 WriteCLUT_T16_I8_CSM1_sse2 -#define WriteCLUT_T32_I8_CSM1 WriteCLUT_T32_I8_CSM1_sse2 -#define WriteCLUT_T16_I4_CSM1 WriteCLUT_T16_I4_CSM1_sse2 -#define WriteCLUT_T32_I4_CSM1 WriteCLUT_T32_I4_CSM1_sse2 - -#else - -#define SwizzleBlock32 SwizzleBlock32_c -#define SwizzleBlock16 SwizzleBlock16_c -#define SwizzleBlock8 SwizzleBlock8_c -#define SwizzleBlock4 SwizzleBlock4_c -#define SwizzleBlock32u SwizzleBlock32_c -#define SwizzleBlock16u SwizzleBlock16_c -#define SwizzleBlock8u SwizzleBlock8_c -#define SwizzleBlock4u SwizzleBlock4_c - -#define FrameSwizzleBlock32 FrameSwizzleBlock32_c -#define FrameSwizzleBlock16 FrameSwizzleBlock16_c -#define Frame16SwizzleBlock32 Frame16SwizzleBlock32_c -#define Frame16SwizzleBlock32Z Frame16SwizzleBlock32Z_c -#define Frame16SwizzleBlock16 Frame16SwizzleBlock16_c -#define Frame16SwizzleBlock16Z Frame16SwizzleBlock16Z_c - -#define FrameSwizzleBlock32A2 FrameSwizzleBlock32A2_c -#define FrameSwizzleBlock16A2 FrameSwizzleBlock16A2_c -#define Frame16SwizzleBlock32A2 Frame16SwizzleBlock32A2_c -#define Frame16SwizzleBlock32ZA2 Frame16SwizzleBlock32ZA2_c -#define Frame16SwizzleBlock16A2 Frame16SwizzleBlock16A2_c -#define Frame16SwizzleBlock16ZA2 Frame16SwizzleBlock16ZA2_c - -#define FrameSwizzleBlock32A4 FrameSwizzleBlock32A4_c -#define FrameSwizzleBlock16A4 FrameSwizzleBlock16A4_c -#define Frame16SwizzleBlock32A4 Frame16SwizzleBlock32A4_c -#define Frame16SwizzleBlock32ZA4 Frame16SwizzleBlock32ZA4_c -#define Frame16SwizzleBlock16A4 Frame16SwizzleBlock16A4_c -#define Frame16SwizzleBlock16ZA4 Frame16SwizzleBlock16ZA4_c - -#define WriteCLUT_T16_I8_CSM1 WriteCLUT_T16_I8_CSM1_c -#define WriteCLUT_T32_I8_CSM1 WriteCLUT_T32_I8_CSM1_c -#define WriteCLUT_T16_I4_CSM1 WriteCLUT_T16_I4_CSM1_c -#define WriteCLUT_T32_I4_CSM1 WriteCLUT_T32_I4_CSM1_c - -#endif - -#endif +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 Gabest/zerofrog@gmail.com + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#ifndef ZEROGS_X86 +#define ZEROGS_X86 + +#include "GS.h" + +extern "C" void __fastcall SwizzleBlock32_sse2(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff); +extern "C" void __fastcall SwizzleBlock16_sse2(u8* dst, u8* src, int srcpitch); +extern "C" void __fastcall SwizzleBlock8_sse2(u8* dst, u8* src, int srcpitch); +extern "C" void __fastcall SwizzleBlock4_sse2(u8* dst, u8* src, int srcpitch); +extern "C" void __fastcall SwizzleBlock32u_sse2(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff); +extern "C" void __fastcall SwizzleBlock16u_sse2(u8* dst, u8* src, int srcpitch); +extern "C" void __fastcall SwizzleBlock8u_sse2(u8* dst, u8* src, int srcpitch); +extern "C" void __fastcall SwizzleBlock4u_sse2(u8* dst, u8* src, int srcpitch); + +// frame swizzling + +// no AA +extern "C" void __fastcall FrameSwizzleBlock32_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall FrameSwizzleBlock16_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock32_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock32Z_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock16_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock16Z_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); + +// AA 2x +extern "C" void __fastcall FrameSwizzleBlock32A2_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall FrameSwizzleBlock16A2_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock32A2_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock32ZA2_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock16A2_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock16ZA2_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); + +// AA 4x +extern "C" void __fastcall FrameSwizzleBlock32A4_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall FrameSwizzleBlock16A4_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock32A4_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock32ZA4_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock16A4_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock16ZA4_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); + +extern void __fastcall SwizzleBlock32_c(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff); +extern void __fastcall SwizzleBlock16_c(u8* dst, u8* src, int srcpitch); +extern void __fastcall SwizzleBlock8_c(u8* dst, u8* src, int srcpitch); +extern void __fastcall SwizzleBlock4_c(u8* dst, u8* src, int srcpitch); + +// no AA +extern void __fastcall FrameSwizzleBlock32_c(u32* dst, u32* src, int srcpitch, u32 WriteMask); +extern void __fastcall FrameSwizzleBlock16_c(u16* dst, u32* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock32_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock32Z_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock16_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock16Z_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); + +// AA 2x +extern void __fastcall FrameSwizzleBlock32A2_c(u32* dst, u32* src, int srcpitch, u32 WriteMask); +extern void __fastcall FrameSwizzleBlock16A2_c(u16* dst, u32* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock32A2_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock32ZA2_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock16A2_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock16ZA2_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); + +// AA 4x +extern void __fastcall FrameSwizzleBlock32A4_c(u32* dst, u32* src, int srcpitch, u32 WriteMask); +extern void __fastcall FrameSwizzleBlock16A4_c(u16* dst, u32* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock32A4_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock32ZA4_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock16A4_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock16ZA4_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); + +extern void __fastcall SwizzleColumn32_c(int y, u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff); +extern void __fastcall SwizzleColumn16_c(int y, u8* dst, u8* src, int srcpitch); +extern void __fastcall SwizzleColumn8_c(int y, u8* dst, u8* src, int srcpitch); +extern void __fastcall SwizzleColumn4_c(int y, u8* dst, u8* src, int srcpitch); + +extern "C" void __fastcall WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32* clut); +extern "C" void __fastcall WriteCLUT_T32_I8_CSM1_sse2(u32* vm, u32* clut); +extern "C" void __fastcall WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut); +extern "C" void __fastcall WriteCLUT_T32_I4_CSM1_sse2(u32* vm, u32* clut); +extern void __fastcall WriteCLUT_T16_I8_CSM1_c(u32* vm, u32* clut); +extern void __fastcall WriteCLUT_T32_I8_CSM1_c(u32* vm, u32* clut); + +extern void __fastcall WriteCLUT_T16_I4_CSM1_c(u32* vm, u32* clut); +extern void __fastcall WriteCLUT_T32_I4_CSM1_c(u32* vm, u32* clut); + +#ifdef ZEROGS_SSE2 + +#define SwizzleBlock32 SwizzleBlock32_sse2 +#define SwizzleBlock16 SwizzleBlock16_sse2 +#define SwizzleBlock8 SwizzleBlock8_sse2 +#define SwizzleBlock4 SwizzleBlock4_sse2 +#define SwizzleBlock32u SwizzleBlock32u_sse2 +#define SwizzleBlock16u SwizzleBlock16u_sse2 +#define SwizzleBlock8u SwizzleBlock8u_sse2 +#define SwizzleBlock4u SwizzleBlock4u_sse2 + +#define FrameSwizzleBlock32 FrameSwizzleBlock32_c +#define FrameSwizzleBlock16 FrameSwizzleBlock16_c +#define Frame16SwizzleBlock32 Frame16SwizzleBlock32_c +#define Frame16SwizzleBlock32Z Frame16SwizzleBlock32Z_c +#define Frame16SwizzleBlock16 Frame16SwizzleBlock16_c +#define Frame16SwizzleBlock16Z Frame16SwizzleBlock16Z_c + +#define FrameSwizzleBlock32A2 FrameSwizzleBlock32A2_c +#define FrameSwizzleBlock16A2 FrameSwizzleBlock16A2_c +#define Frame16SwizzleBlock32A2 Frame16SwizzleBlock32A2_c +#define Frame16SwizzleBlock32ZA2 Frame16SwizzleBlock32ZA2_c +#define Frame16SwizzleBlock16A2 Frame16SwizzleBlock16A2_c +#define Frame16SwizzleBlock16ZA2 Frame16SwizzleBlock16ZA2_c + +#define FrameSwizzleBlock32A4 FrameSwizzleBlock32A4_c +#define FrameSwizzleBlock16A4 FrameSwizzleBlock16A4_c +#define Frame16SwizzleBlock32A4 Frame16SwizzleBlock32A4_c +#define Frame16SwizzleBlock32ZA4 Frame16SwizzleBlock32ZA4_c +#define Frame16SwizzleBlock16A4 Frame16SwizzleBlock16A4_c +#define Frame16SwizzleBlock16ZA4 Frame16SwizzleBlock16ZA4_c + +#define WriteCLUT_T16_I8_CSM1 WriteCLUT_T16_I8_CSM1_sse2 +#define WriteCLUT_T32_I8_CSM1 WriteCLUT_T32_I8_CSM1_sse2 +#define WriteCLUT_T16_I4_CSM1 WriteCLUT_T16_I4_CSM1_sse2 +#define WriteCLUT_T32_I4_CSM1 WriteCLUT_T32_I4_CSM1_sse2 + +#else + +#define SwizzleBlock32 SwizzleBlock32_c +#define SwizzleBlock16 SwizzleBlock16_c +#define SwizzleBlock8 SwizzleBlock8_c +#define SwizzleBlock4 SwizzleBlock4_c +#define SwizzleBlock32u SwizzleBlock32_c +#define SwizzleBlock16u SwizzleBlock16_c +#define SwizzleBlock8u SwizzleBlock8_c +#define SwizzleBlock4u SwizzleBlock4_c + +#define FrameSwizzleBlock32 FrameSwizzleBlock32_c +#define FrameSwizzleBlock16 FrameSwizzleBlock16_c +#define Frame16SwizzleBlock32 Frame16SwizzleBlock32_c +#define Frame16SwizzleBlock32Z Frame16SwizzleBlock32Z_c +#define Frame16SwizzleBlock16 Frame16SwizzleBlock16_c +#define Frame16SwizzleBlock16Z Frame16SwizzleBlock16Z_c + +#define FrameSwizzleBlock32A2 FrameSwizzleBlock32A2_c +#define FrameSwizzleBlock16A2 FrameSwizzleBlock16A2_c +#define Frame16SwizzleBlock32A2 Frame16SwizzleBlock32A2_c +#define Frame16SwizzleBlock32ZA2 Frame16SwizzleBlock32ZA2_c +#define Frame16SwizzleBlock16A2 Frame16SwizzleBlock16A2_c +#define Frame16SwizzleBlock16ZA2 Frame16SwizzleBlock16ZA2_c + +#define FrameSwizzleBlock32A4 FrameSwizzleBlock32A4_c +#define FrameSwizzleBlock16A4 FrameSwizzleBlock16A4_c +#define Frame16SwizzleBlock32A4 Frame16SwizzleBlock32A4_c +#define Frame16SwizzleBlock32ZA4 Frame16SwizzleBlock32ZA4_c +#define Frame16SwizzleBlock16A4 Frame16SwizzleBlock16A4_c +#define Frame16SwizzleBlock16ZA4 Frame16SwizzleBlock16ZA4_c + +#define WriteCLUT_T16_I8_CSM1 WriteCLUT_T16_I8_CSM1_c +#define WriteCLUT_T32_I8_CSM1 WriteCLUT_T32_I8_CSM1_c +#define WriteCLUT_T16_I4_CSM1 WriteCLUT_T16_I4_CSM1_c +#define WriteCLUT_T32_I4_CSM1 WriteCLUT_T32_I4_CSM1_c + +#endif + +#endif diff --git a/plugins/zerogs/opengl/zerogs.cpp b/plugins/zerogs/opengl/zerogs.cpp index 4bbfc5fd2e..0985509b7a 100644 --- a/plugins/zerogs/opengl/zerogs.cpp +++ b/plugins/zerogs/opengl/zerogs.cpp @@ -1,6016 +1,6016 @@ -/* ZeroGS KOSMOS - * Copyright (C) 2005-2006 zerofrog@gmail.com - * - * 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 - */ - -#if defined(_WIN32) -#include -#include - -#include "resource.h" -#endif - -#include - -#include -#include -#include -#include - -#include "GS.h" -#include "Mem.h" -#include "x86.h" -#include "zerogs.h" -#include "zpipe.h" - -#include "ZeroGSShaders/zerogsshaders.h" -#include "targets.h" -#include "rasterfont.h" // simple font - -#define VB_BUFFERSIZE 0x400 -#define VB_NUMBUFFERS 512 -#define SIZEOF_VB sizeof(ZeroGS::VB)//((u32)((u8*)&vb[0].buffers-(u8*)&vb[0])) - -#define MINMAX_SHIFT 3 -#define MAX_ACTIVECLUTS 16 - -#define ZEROGS_SAVEVER 0xaa000005 - -#define STENCIL_ALPHABIT 1 // if set, dest alpha >= 0x80 -#define STENCIL_PIXELWRITE 2 // if set, pixel just written (reset after every Flush) -#define STENCIL_FBA 4 // if set, just written pixel's alpha >= 0 (reset after every Flush) -#define STENCIL_SPECIAL 8 // if set, indicates that pixel passed its alpha test (reset after every Flush) -//#define STENCIL_PBE 16 -#define STENCIL_CLEAR (2|4|8|16) - -#define VBSAVELIMIT ((u32)((u8*)&vb[0].nNextFrameHeight-(u8*)&vb[0])) - -using namespace ZeroGS; - -extern u32 g_nGenVars, g_nTexVars, g_nAlphaVars, g_nResolve; -extern char *libraryName; -extern int g_nFrame, g_nRealFrame; -extern float fFPS; -extern unsigned char zgsrevision, zgsbuild, zgsminor; - -BOOL g_bDisplayMsg = 1; - -#ifdef _WIN32 -HDC hDC=NULL; // Private GDI Device Context -HGLRC hRC=NULL; // Permanent Rendering Context -#endif - -BOOL g_bCRTCBilinear = TRUE; -BOOL g_bSaveFlushedFrame = 0; -BOOL g_bIsLost = 0; -int g_nFrameRender = 10; -int g_nFramesSkipped = 0; - -#ifdef RELEASE_TO_PUBLIC - -#define INC_GENVARS() -#define INC_TEXVARS() -#define INC_ALPHAVARS() -#define INC_RESOLVE() - -#define g_bUpdateEffect 0 -#define g_bSaveTex 0 -#define g_bSaveTrans 0 -#define g_bSaveFrame 0 -#define g_bSaveFinalFrame 0 -#define g_bSaveResolved 0 - -#else - -#define INC_GENVARS() ++g_nGenVars -#define INC_TEXVARS() ++g_nTexVars -#define INC_ALPHAVARS() ++g_nAlphaVars -#define INC_RESOLVE() ++g_nResolve - -BOOL g_bSaveTrans = 0; -BOOL g_bUpdateEffect = 0; -BOOL g_bSaveTex = 0; // saves the curent texture -BOOL g_bSaveFrame = 0; // saves the current psurfTarget -BOOL g_bSaveFinalFrame = 0; // saves the input to the CRTC -BOOL g_bSaveResolved = 0; - -#ifdef _WIN32 -//#define EFFECT_NAME "f:\\ps2dev\\svn\\pcsx2\\ZeroGS\\opengl\\" -char* EFFECT_DIR = "C:\\programming\\ps2dev\\zerogs\\opengl\\"; -char* EFFECT_NAME = "C:\\programming\\ps2dev\\zerogs\\opengl\\ps2hw.fx"; -#else -char EFFECT_DIR[255] = "~/pcsx2/plugins/gs/zerogs/opengl/"; -char EFFECT_NAME[255] = "~/pcsx2/plugins/gs/zerogs/opengl/ps2hw.fx"; -#endif - -#endif - -BOOL g_bUpdateStencil = 1; // only needed for dest alpha test (unfortunately, it has to be on all the time) - -#define DRAW() glDrawArrays(primtype[curvb.curprim.prim], 0, curvb.nCount) - -#define GL_BLEND_RGB(src, dst) { \ - s_srcrgb = src; \ - s_dstrgb = dst; \ - zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha); \ -} - -#define GL_BLEND_ALPHA(src, dst) { \ - s_srcalpha = src; \ - s_dstalpha = dst; \ - zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha); \ -} - -#define GL_BLEND_ALL(srcrgb, dstrgb, srcalpha, dstalpha) { \ - s_srcrgb = srcrgb; \ - s_dstrgb = dstrgb; \ - s_srcalpha = srcalpha; \ - s_dstalpha = dstalpha; \ - zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha); \ -} - -#define GL_BLEND_SET() zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha) - -#define GL_ZTEST(enable) { \ - if( enable ) glEnable(GL_DEPTH_TEST); \ - else glDisable(GL_DEPTH_TEST); \ -} - -#define GL_ALPHATEST(enable) { \ - if( enable ) glEnable(GL_ALPHA_TEST); \ - else glDisable(GL_ALPHA_TEST); \ -} - -#define GL_BLENDEQ_RGB(eq) { \ - s_rgbeq = eq; \ - zgsBlendEquationSeparateEXT(s_rgbeq, s_alphaeq); \ -} - -#define GL_BLENDEQ_ALPHA(eq) { \ - s_alphaeq = eq; \ - zgsBlendEquationSeparateEXT(s_rgbeq, s_alphaeq); \ -} - -#define GL_STENCILFUNC(func, ref, mask) { \ - s_stencilfunc = func; \ - s_stencilref = ref; \ - s_stencilmask = mask; \ - glStencilFunc(func, ref, mask); \ -} - -#define GL_STENCILFUNC_SET() glStencilFunc(s_stencilfunc, s_stencilref, s_stencilmask) - -#define COLORMASK_RED 1 -#define COLORMASK_GREEN 2 -#define COLORMASK_BLUE 4 -#define COLORMASK_ALPHA 8 -#define GL_COLORMASK(mask) glColorMask(!!((mask)&COLORMASK_RED), !!((mask)&COLORMASK_GREEN), !!((mask)&COLORMASK_BLUE), !!((mask)&COLORMASK_ALPHA)) - -typedef void (APIENTRYP _PFNSWAPINTERVAL) (int); - -extern int s_frameskipping; - -static u32 g_SaveFrameNum = 0; -BOOL g_bMakeSnapshot = 0; -string strSnapshot; - -int GPU_TEXWIDTH = 512; -float g_fiGPU_TEXWIDTH = 1/512.0f; - -int g_MaxTexWidth = 4096, g_MaxTexHeight = 4096; -CGprogram g_vsprog = 0, g_psprog = 0; -// AVI Capture -static int s_aviinit = 0; -static int s_avicapturing = 0; - -inline u32 FtoDW(float f) { return (*((u32*)&f)); } - -float g_fBlockMult = 1; -static int s_nFullscreen = 0; -int g_nDepthUpdateCount = 0; -int g_nDepthBias = 0; - -// local alpha blending settings -static GLenum s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha; // set by zgsBlendFuncSeparateEXT -static GLenum s_rgbeq, s_alphaeq; // set by zgsBlendEquationSeparateEXT -static u32 s_stencilfunc, s_stencilref, s_stencilmask; -static GLenum s_drawbuffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT }; - -#ifdef _WIN32 -extern HINSTANCE hInst; - -void (__stdcall *zgsBlendEquationSeparateEXT)(GLenum, GLenum) = NULL; -void (__stdcall *zgsBlendFuncSeparateEXT)(GLenum, GLenum, GLenum, GLenum) = NULL; -#else -void (APIENTRY *zgsBlendEquationSeparateEXT)(GLenum, GLenum) = NULL; -void (APIENTRY *zgsBlendFuncSeparateEXT)(GLenum, GLenum, GLenum, GLenum) = NULL; -#endif - -GLenum g_internalFloatFmt = GL_ALPHA_FLOAT32_ATI; -GLenum g_internalRGBAFloatFmt = GL_RGBA_FLOAT32_ATI; -GLenum g_internalRGBAFloat16Fmt = GL_RGBA_FLOAT16_ATI; - -// Consts -static const GLenum primtype[8] = { GL_POINTS, GL_LINES, GL_LINES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, 0xffffffff }; -static const u32 blendalpha[3] = { GL_SRC_ALPHA, GL_DST_ALPHA, GL_CONSTANT_COLOR_EXT }; -static const u32 blendinvalpha[3] = { GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_CONSTANT_COLOR_EXT }; - -static const int PRIMMASK = 0x0e; // for now ignore 0x10 (AA) - -static const u32 g_dwAlphaCmp[] = { GL_NEVER, GL_ALWAYS, GL_LESS, GL_LEQUAL, GL_EQUAL, GL_GEQUAL, GL_GREATER, GL_NOTEQUAL }; - -// used for afail case -static const u32 g_dwReverseAlphaCmp[] = { GL_ALWAYS, GL_NEVER, GL_GEQUAL, GL_GREATER, GL_NOTEQUAL, GL_LESS, GL_LEQUAL, GL_EQUAL }; - -static const u32 g_dwZCmp[] = { GL_NEVER, GL_ALWAYS, GL_GEQUAL, GL_GREATER }; - -PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT = NULL; -PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT = NULL; -PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT = NULL; -PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT = NULL; -PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT = NULL; -PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT = NULL; -PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT = NULL; -PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = NULL; -PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = NULL; -PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = NULL; -PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = NULL; -PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT = NULL; -PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = NULL; -PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT = NULL; -PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL; -PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL; -PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL; -PFNGLDRAWBUFFERSPROC glDrawBuffers = NULL; - -///////////////////// -// graphics resources -static map mapGLExtensions; -RasterFont* font_p = NULL; -CGprofile cgvProf, cgfProf; -static CGprogram pvs[16] = {NULL}; -static FRAGMENTSHADER ppsRegular[4], ppsTexture[NUM_SHADERS]; -static FRAGMENTSHADER ppsCRTC[2], ppsCRTC24[2], ppsCRTCTarg[2]; -CGparameter g_vparamPosXY[2] = {0}, g_fparamFogColor = 0; - -int g_nPixelShaderVer = 0; // default - -static u8* s_lpShaderResources = NULL; -static map mapShaderResources; - -u32 s_uFramebuffer = 0; -u32 s_ptexCurSet[2] = {0}; - -#define s_bForceTexFlush 1 -static u32 s_ptexNextSet[2] = {0}; - -u32 ptexBlocks = 0, ptexConv16to32 = 0; // holds information on block tiling -u32 ptexBilinearBlocks = 0; -u32 ptexConv32to16 = 0; -static u32 s_ptexInterlace = 0; // holds interlace fields -static int s_nInterlaceTexWidth = 0; // width of texture -static vector s_vecTempTextures; // temporary textures, released at the end of every frame - -static BOOL s_bTexFlush = FALSE; -static u32 ptexLogo = 0; -static int nLogoWidth, nLogoHeight; -static BOOL s_bWriteDepth = FALSE; -static BOOL s_bDestAlphaTest = FALSE; -static int s_nLastResolveReset = 0; -static int s_nResolveCounts[30] = {0}; // resolve counts for last 30 frames -static int s_nCurResolveIndex = 0; -int s_nResolved = 0; // number of targets resolved this frame -int g_nDepthUsed = 0; // ffx2 pal movies -static int s_nWriteDepthCount = 0; -static int s_nWireframeCount = 0; -static int s_nWriteDestAlphaTest = 0; - -//////////////////// -// State parameters -static float fiRendWidth, fiRendHeight; - -static Vector vAlphaBlendColor; // used for GPU_COLOR - -static u8 bNeedBlendFactorInAlpha; // set if the output source alpha is different from the real source alpha (only when blend factor > 0x80) -static u32 s_dwColorWrite = 0xf; // the color write mask of the current target - -BOOL g_bDisplayFPS = FALSE; - -union { - struct { - u8 _bNeedAlphaColor; // set if vAlphaBlendColor needs to be set - u8 _b2XAlphaTest; // Only valid when bNeedAlphaColor is set. if 1st bit set set, double all alpha testing values - // otherwise alpha testing needs to be done separately. - u8 _bDestAlphaColor; // set to 1 if blending with dest color (process only one tri at a time). If 2, dest alpha is always 1. - u8 _bAlphaClamping; // if first bit is set, do min; if second bit, do max - }; - u32 _bAlphaState; -} g_vars; - -//#define bNeedAlphaColor g_vars._bNeedAlphaColor -#define b2XAlphaTest g_vars._b2XAlphaTest -#define bDestAlphaColor g_vars._bDestAlphaColor -#define bAlphaClamping g_vars._bAlphaClamping - -int g_PrevBitwiseTexX = -1, g_PrevBitwiseTexY = -1; // textures stored in SAMP_BITWISEANDX and SAMP_BITWISEANDY - -// stores the buffers for the last RenderCRTC -const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); - -static alphaInfo s_alphaInfo; - -CGcontext g_cgcontext; -static int nBackbufferWidth, nBackbufferHeight; - -u8* g_pbyGSMemory = NULL; // 4Mb GS system mem -u8* g_pbyGSClut = NULL; - -namespace ZeroGS -{ - VB vb[2]; - float fiTexWidth[2], fiTexHeight[2]; // current tex width and height - - GLuint vboRect = 0; - vector g_vboBuffers; // VBOs for all drawing commands - int g_nCurVBOIndex = 0; - - u8 s_AAx = 0, s_AAy = 0; // if AAy is set, then AAx has to be set - RenderFormatType g_RenderFormatType = RFT_float16; - int icurctx = -1; - - Vector g_vdepth = Vector(256.0f*65536.0f, 65536.0f, 256.0f, 65536.0f*65536.0f); - - VERTEXSHADER pvsBitBlt; - FRAGMENTSHADER ppsBitBlt[2], ppsBitBltDepth, ppsOne; - FRAGMENTSHADER ppsBaseTexture, ppsConvert16to32, ppsConvert32to16; - - extern CRangeManager s_RangeMngr; // manages overwritten memory - void FlushTransferRanges(const tex0Info* ptex); - - RenderFormatType GetRenderFormat() { return g_RenderFormatType; } - GLenum GetRenderTargetFormat() { return GetRenderFormat()==RFT_byte8?4:g_internalRGBAFloat16Fmt; } - - // returns the first and last addresses aligned to a page that cover - void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw); - - bool LoadEffects(); - bool LoadExtraEffects(); - FRAGMENTSHADER* LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context, bool* pbFailed); - - static int s_nNewWidth = -1, s_nNewHeight = -1; - void ChangeDeviceSize(int nNewWidth, int nNewHeight); - - void ProcessMessages(); - void RenderCustom(float fAlpha); // intro anim - - struct MESSAGE - { - MESSAGE() {} - MESSAGE(const char* p, u32 dw) { strcpy(str, p); dwTimeStamp = dw; } - char str[255]; - u32 dwTimeStamp; - }; - - static list listMsgs; - - /////////////////////// - // Method Prototypes // - /////////////////////// - - void AdjustTransToAspect(Vector& v, int dispwidth, int dispheight); - - void KickPoint(); - void KickLine(); - void KickTriangle(); - void KickTriangleFan(); - void KickSprite(); - void KickDummy(); - - __forceinline void SetContextTarget(int context); - - // use to update the state - void SetTexVariables(int context, FRAGMENTSHADER* pfragment, int settexint); - void SetAlphaVariables(const alphaInfo& ainfo); - void ResetAlphaVariables(); - - __forceinline void SetAlphaTestInt(pixTest curtest); - - __forceinline void RenderAlphaTest(const VB& curvb, CGparameter sOneColor); - __forceinline void RenderStencil(const VB& curvb, u32 dwUsingSpecialTesting); - __forceinline void ProcessStencil(const VB& curvb); - __forceinline void RenderFBA(const VB& curvb, CGparameter sOneColor); - __forceinline void ProcessFBA(const VB& curvb, CGparameter sOneColor); - - void ResolveInRange(int start, int end); - - void ExtWrite(); - - __forceinline u32 CreateInterlaceTex(int width) { - if( width == s_nInterlaceTexWidth && s_ptexInterlace != 0 ) return s_ptexInterlace; - - SAFE_RELEASE_TEX(s_ptexInterlace); - s_nInterlaceTexWidth = width; - - vector data(width); - for(int i = 0; i < width; ++i) data[i] = (i&1) ? 0xffffffff : 0; - - glGenTextures(1, &s_ptexInterlace); - glBindTexture(GL_TEXTURE_RECTANGLE_NV, s_ptexInterlace); - glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, 4, width, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); - glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - GL_REPORT_ERRORD(); - return s_ptexInterlace; - } - - void ResetRenderTarget(int index) { - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+index, GL_TEXTURE_RECTANGLE_NV, 0, 0 ); - } - - DrawFn drawfn[8] = { KickDummy, KickDummy, KickDummy, KickDummy, - KickDummy, KickDummy, KickDummy, KickDummy }; - -}; // end namespace - -/////////////////// -// Context State // -/////////////////// -ZeroGS::VB::VB() -{ - memset(this, 0, SIZEOF_VB); - tex0.tw = 1; - tex0.th = 1; -} - -ZeroGS::VB::~VB() -{ - Destroy(); -} - -void ZeroGS::VB::Destroy() -{ - _aligned_free(pBufferData); pBufferData = NULL; nNumVertices = 0; - - prndr = NULL; - pdepth = NULL; -} - -bool ZeroGS::VB::CheckPrim() -{ - if( (PRIMMASK & prim->_val) != (PRIMMASK & curprim._val) || primtype[prim->prim] != primtype[curprim.prim] ) - return nCount > 0; - - return false; -} - -// upper bound on max possible height -#define GET_MAXHEIGHT(fbp, fbw, psm) ((((0x00100000-64*(fbp))/(fbw))&~0x1f)<<((psm&2)?1:0)) - -#include -static int maxmin = 608; -//static set s_setFBP[2]; // previous frame/zbuf pointers for the last 2 frames -//static int s_nCurFBPSet = 0; -//static map s_mapFrameHeights[2]; -//static int s_nCurFrameMap = 0; - -// a lot of times, target is too big and overwrites the texture using, if tbp != 0, use it to bound -void ZeroGS::VB::CheckFrame(int tbp) -{ - static int bChanged; - if( bNeedZCheck ) { - PRIM_LOG("zbuf_%d: zbp=0x%x psm=0x%x, zmsk=%d\n", ictx, zbuf.zbp, zbuf.psm, zbuf.zmsk); - //zbuf = *zb; - } - - bChanged = 0; - - if( bNeedFrameCheck ) { - - int maxpos = 0x00100000; - - // important to set before calling GetTarg - bNeedFrameCheck = 0; - bNeedZCheck = 0; - - // add constraints of other targets - if( gsfb.fbw > 0 ) { - maxpos = 0x00100000-64*gsfb.fbp; - - // make sure texture is far away from tbp - if( gsfb.fbp < tbp && gsfb.fbp + 0x2000 < tbp) { - maxpos = min(64*(tbp-gsfb.fbp), maxpos); - } - if( prndr != NULL ) { - // offroad uses 0x80 fbp which messes up targets - if( gsfb.fbp + 0x80 < frame.fbp ) { - // special case when double buffering (hamsterball) - maxpos = min(64*(frame.fbp-gsfb.fbp), maxpos); - } - } - if( zbuf.zbp < tbp && !zbuf.zmsk ) { - maxpos = min((tbp-zbuf.zbp)*((zbuf.psm&2)?128:64), maxpos); - } - - // old caching method - if( gsfb.fbp < zbuf.zbp && !zbuf.zmsk ) { // zmsk necessary for KH movie - int temp = 64*(zbuf.zbp-gsfb.fbp);//min( (0x00100000-64*zbuf.zbp) , 64*(zbuf.zbp-gsfb.fbp) ); - maxpos = min(temp, maxpos); - } - - maxpos /= gsfb.fbw; - if( gsfb.psm & 2 ) maxpos *= 2;; - - maxpos = min(gsfb.fbh, maxpos); - maxpos = min(maxmin, maxpos); - //? atelier iris crashes without it - if( maxpos > 256 ) maxpos &= ~0x1f; - } - else { - ERROR_LOG("render target null, ignoring\n"); - //prndr = NULL; - //pdepth = NULL; - return; - } - - gsfb.psm &= 0xf; // shadow tower - - if( prndr != NULL ) { - - // render target - if( prndr->psm != gsfb.psm ) { - // behavior for dest alpha varies - ResetAlphaVariables(); - } - } - - int fbh = (scissor.y1>>MINMAX_SHIFT)+1; - if( fbh > 2 && (fbh&1) ) fbh -= 1; - - if( !(gsfb.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) { - fbh = min(fbh, maxpos); - } - - frame = gsfb; -// if (frame.fbw > 1024) frame.fbw = 1024; - -// if( fbh > 256 && (fbh % m_Blocks[gsfb.psm].height) <= 2 ) { -// // dragon ball z -// fbh -= fbh%m_Blocks[gsfb.psm].height; -// } - if( !(frame.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) - frame.fbh = fbh; - - if( !(frame.psm&2) ) {//|| !(g_GameSettings&GAME_FULL16BITRES) ) { - if( frame.fbh >= 512 ) { - // neopets hack - maxmin = min(maxmin, frame.fbh); - frame.fbh = maxmin; - } - } - - // mgs3 hack to get proper resolution, targets after 0x2000 are usually feedback - /*if( g_MaxRenderedHeight >= 0xe0 && frame.fbp >= 0x2000 ) { - int considerheight = (g_MaxRenderedHeight/8+31)&~31; - if( frame.fbh > considerheight ) - frame.fbh = considerheight; - else if( frame.fbh <= 32 ) - frame.fbh = considerheight; - - if( frame.fbh == considerheight ) { - // stops bad resolves (mgs3) - if( !curprim.abe && (!test.ate || test.atst == 0) ) - s_nResolved |= 0x100; - } - }*/ - - // ffxii hack to stop resolving - if( !(frame.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) { - if( frame.fbp >= 0x3000 && fbh >= 0x1a0 ) { - int endfbp = frame.fbp + frame.fbw*fbh/((gsfb.psm&2)?128:64); - - // see if there is a previous render target in the way, reduce - for(CRenderTargetMngr::MAPTARGETS::iterator itnew = s_RTs.mapTargets.begin(); itnew != s_RTs.mapTargets.end(); ++itnew) { - if( itnew->second->fbp > frame.fbp && endfbp > itnew->second->fbp ) { - endfbp = itnew->second->fbp; - } - } - - frame.fbh = (endfbp-frame.fbp)*((gsfb.psm&2)?128:64)/frame.fbw; - } - } - - CRenderTarget* pprevrndr = prndr; - CDepthTarget* pprevdepth = pdepth; - - // reset so that Resolve doesn't call Flush - prndr = NULL; - pdepth = NULL; - - CRenderTarget* pnewtarg = s_RTs.GetTarg(frame, 0, maxmin); - assert( pnewtarg != NULL ); - - // pnewtarg->fbh >= 0x1c0 needed for ffx - if( pnewtarg->fbh >= 0x1c0 && pnewtarg->fbh > frame.fbh && zbuf.zbp < tbp && !zbuf.zmsk ) { - // check if zbuf is in the way of the texture (suikoden5) - int maxallowedfbh = (tbp-zbuf.zbp)*((zbuf.psm&2)?128:64) / gsfb.fbw; - if( gsfb.psm & 2 ) - maxallowedfbh *= 2; - - if( pnewtarg->fbh > maxallowedfbh+32 ) { // +32 needed for ffx2 - // destroy and recreate - s_RTs.DestroyAllTargs(0, 0x100, pnewtarg->fbw); - pnewtarg = s_RTs.GetTarg(frame, 0, maxmin); - assert( pnewtarg != NULL ); - } - } - - PRIM_LOG("frame_%d: fbp=0x%x fbw=%d fbh=%d(%d) psm=0x%x fbm=0x%x\n", ictx, gsfb.fbp, gsfb.fbw, gsfb.fbh, pnewtarg->fbh, gsfb.psm, gsfb.fbm); - - if( (pprevrndr != pnewtarg) || (prndr != NULL && (prndr->status & CRenderTarget::TS_NeedUpdate)) ) - bChanged = 1; - - prndr = pnewtarg; - - // update z - frameInfo tempfb; - tempfb.fbw = prndr->fbw; - tempfb.fbp = zbuf.zbp; - tempfb.psm = zbuf.psm; - tempfb.fbh = prndr->fbh; - if( zbuf.psm == 0x31 ) - tempfb.fbm = 0xff000000; - else - tempfb.fbm = 0; - - // check if there is a target that exactly aligns with zbuf (zbuf can be cleared this way, gunbird 2) - //u32 key = zbuf.zbp|(frame.fbw<<16); - //CRenderTargetMngr::MAPTARGETS::iterator it = s_RTs.mapTargets.find(key); -// if( it != s_RTs.mapTargets.end() ) { -//#ifdef _DEBUG -// DEBUG_LOG("zbuf resolve\n"); -//#endif -// if( it->second->status & CRenderTarget::TS_Resolved ) -// it->second->Resolve(); -// } - - GL_REPORT_ERRORD(); - CDepthTarget* pnewdepth = (CDepthTarget*)s_DepthRTs.GetTarg(tempfb, CRenderTargetMngr::TO_DepthBuffer | - CRenderTargetMngr::TO_StrictHeight|(zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), - GET_MAXHEIGHT(zbuf.zbp, gsfb.fbw, 0)); - assert( pnewdepth != NULL && prndr != NULL ); - assert( pnewdepth->fbh == prndr->fbh ); - - if( (pprevdepth != pnewdepth) || (pdepth != NULL && (pdepth->status & CRenderTarget::TS_NeedUpdate)) ) - bChanged |= 2; - - pdepth = pnewdepth; - - if( prndr->status & CRenderTarget::TS_NeedConvert32) { - if( pdepth->pdepth != 0 ) - pdepth->SetDepthStencilSurface(); - prndr->fbh *= 2; - prndr->ConvertTo32(); - prndr->status &= ~CRenderTarget::TS_NeedConvert32; - } - else if( prndr->status & CRenderTarget::TS_NeedConvert16 ) { - if( pdepth->pdepth != 0 ) - pdepth->SetDepthStencilSurface(); - prndr->fbh /= 2; - prndr->ConvertTo16(); - prndr->status &= ~CRenderTarget::TS_NeedConvert16; - } - } - else if( bNeedZCheck ) { - - bNeedZCheck = 0; - CDepthTarget* pprevdepth = pdepth; - pdepth = NULL; - - if( prndr != NULL && gsfb.fbw > 0 ) { - // just z changed - frameInfo f; - f.fbp = zbuf.zbp; - f.fbw = prndr->fbw; - f.fbh = prndr->fbh; - f.psm = zbuf.psm; - - if( zbuf.psm == 0x31 ) f.fbm = 0xff000000; - else f.fbm = 0; - CDepthTarget* pnewdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| - (zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), GET_MAXHEIGHT(zbuf.zbp, gsfb.fbw, 0)); - - assert( pnewdepth != NULL && prndr != NULL ); - assert( pnewdepth->fbh == prndr->fbh ); - - if( (pprevdepth != pnewdepth) || (pdepth != NULL && (pdepth->status & CRenderTarget::TS_NeedUpdate)) ) - bChanged = 2; - - pdepth = pnewdepth; - } - } - - if( prndr != NULL ) SetContextTarget(ictx); -} - -void ZeroGS::VB::FlushTexData() -{ - assert( bNeedTexCheck ); - - bNeedTexCheck = 0; - - u32 psm = (uNextTex0Data[0] >> 20) & 0x3f; - if( psm == 9 ) psm = 1; // hmm..., ffx intro menu - - // don't update unless necessary - if( uCurTex0Data[0] == uNextTex0Data[0] && (uCurTex0Data[1]&0x1f) == (uNextTex0Data[1]&0x1f) ) { - - if( PSMT_ISCLUT(psm) ) { - - // have to write the CLUT again if changed - if( (uCurTex0Data[1]&0x1fffffe0) == (uNextTex0Data[1]&0x1fffffe0) ) { - - if( uNextTex0Data[1]&0xe0000000 ) { - //ZeroGS::Flush(ictx); - ZeroGS::texClutWrite(ictx); - // invalidate to make sure target didn't change! - bVarsTexSync = FALSE; - } - - return; - } - - if( (uNextTex0Data[1]&0xe0000000) == 0 ) { - - if( (uCurTex0Data[1]&0x1ff10000) != (uNextTex0Data[1]&0x1ff10000) ) - ZeroGS::Flush(ictx); - - // clut isn't going to be loaded so can ignore, but at least update CSA and CPSM! - uCurTex0Data[1] = (uCurTex0Data[1]&0xe087ffff)|(uNextTex0Data[1]&0x1f780000); - - if( tex0.cpsm <= 1 ) tex0.csa = (uNextTex0Data[1] >> 24) & 0xf; - else tex0.csa = (uNextTex0Data[1] >> 24) & 0x1f; - - tex0.cpsm = (uNextTex0Data[1] >> 19) & 0xe; - ZeroGS::texClutWrite(ictx); - - bVarsTexSync = FALSE; - return; - } - - // fall through - } - else { - //bVarsTexSync = FALSE; - return; - } - } - - ZeroGS::Flush(ictx); - bVarsTexSync = FALSE; - bTexConstsSync = FALSE; - - uCurTex0Data[0] = uNextTex0Data[0]; - uCurTex0Data[1] = uNextTex0Data[1]; - - tex0.tbp0 = (uNextTex0Data[0] & 0x3fff); - tex0.tbw = ((uNextTex0Data[0] >> 14) & 0x3f) * 64; - tex0.psm = psm; - tex0.tw = (uNextTex0Data[0] >> 26) & 0xf; - if (tex0.tw > 10) tex0.tw = 10; - tex0.tw = 1<> 30) & 0x3) | ((uNextTex0Data[1] & 0x3) << 2); - if (tex0.th > 10) tex0.th = 10; - tex0.th = 1<> 2) & 0x1; - tex0.tfx = (uNextTex0Data[1] >> 3) & 0x3; - - ZeroGS::fiTexWidth[ictx] = (1/16.0f)/ tex0.tw; - ZeroGS::fiTexHeight[ictx] = (1/16.0f) / tex0.th; - - if (tex0.tbw == 0) tex0.tbw = 64; - - if( PSMT_ISCLUT(psm) ) { - tex0.cbp = ((uNextTex0Data[1] >> 5) & 0x3fff); - tex0.cpsm = (uNextTex0Data[1] >> 19) & 0xe; - tex0.csm = (uNextTex0Data[1] >> 23) & 0x1; - - if( tex0.cpsm <= 1 ) tex0.csa = (uNextTex0Data[1] >> 24) & 0xf; - else tex0.csa = (uNextTex0Data[1] >> 24) & 0x1f; - - tex0.cld = (uNextTex0Data[1] >> 29) & 0x7; - - ZeroGS::texClutWrite(ictx); - } -} - -// does one time only initializing/destruction -class ZeroGSInit -{ -public: - ZeroGSInit() { - // clear - g_pbyGSMemory = (u8*)_aligned_malloc(0x00410000, 1024); // leave some room for out of range accesses (saves on the checks) - memset(g_pbyGSMemory, 0, 0x00410000); - - g_pbyGSClut = (u8*)_aligned_malloc(256*8, 1024); // need 512 alignment! - memset(g_pbyGSClut, 0, 256*8); - -#ifndef _WIN32 - memset(&GLWin, 0, sizeof(GLWin)); -#endif - } - ~ZeroGSInit() { - _aligned_free(g_pbyGSMemory); g_pbyGSMemory = NULL; - _aligned_free(g_pbyGSClut); g_pbyGSClut = NULL; - } -}; - -static ZeroGSInit s_ZeroGSInit; - -#ifdef _WIN32 -void __stdcall glBlendFuncSeparateDummy(GLenum e1, GLenum e2, GLenum e3, GLenum e4) -#else -void APIENTRY glBlendFuncSeparateDummy(GLenum e1, GLenum e2, GLenum e3, GLenum e4) -#endif -{ - glBlendFunc(e1, e2); -} - -#ifdef _WIN32 -void __stdcall glBlendEquationSeparateDummy(GLenum e1, GLenum e2) -#else -void APIENTRY glBlendEquationSeparateDummy(GLenum e1, GLenum e2) -#endif -{ - glBlendEquation(e1); -} - -void HandleCgError(CGcontext ctx, CGerror err, void* appdata) -{ - ERROR_LOG("Cg error: %s\n", cgGetErrorString(err)); - const char* listing = cgGetLastListing(g_cgcontext); - if( listing != NULL ) DEBUG_LOG(" last listing: %s\n", listing); -// int loc; -// const GLubyte* pstr = glGetString(GL_PROGRAM_ERROR_STRING_ARB); -// if( pstr != NULL ) printf("error at: %s\n"); -// glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &loc); -// DEBUG_LOG("pos: %d\n", loc); -} - -#ifndef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT -#define GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT 0x8CD8 -#endif - -void ZeroGS::HandleGLError() -{ - // check the error status of this framebuffer */ - GLenum error = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - - // if error != GL_FRAMEBUFFER_COMPLETE_EXT, there's an error of some sort - if( error != 0 ) { - int w, h; - GLint fmt; - glGetRenderbufferParameterivEXT(GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_INTERNAL_FORMAT_EXT, &fmt); - glGetRenderbufferParameterivEXT(GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_WIDTH_EXT, &w); - glGetRenderbufferParameterivEXT(GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_HEIGHT_EXT, &h); - - switch(error) - { - case GL_FRAMEBUFFER_COMPLETE_EXT: - break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: - ERROR_LOG("Error! missing a required image/buffer attachment!\n"); - break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: - ERROR_LOG("Error! has no images/buffers attached!\n"); - break; -// case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT: -// ERROR_LOG("Error! has an image/buffer attached in multiple locations!\n"); -// break; - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: - ERROR_LOG("Error! has mismatched image/buffer dimensions!\n"); - break; - case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: - ERROR_LOG("Error! colorbuffer attachments have different types!\n"); - break; - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: - ERROR_LOG("Error! trying to draw to non-attached color buffer!\n"); - break; - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: - ERROR_LOG("Error! trying to read from a non-attached color buffer!\n"); - break; - case GL_FRAMEBUFFER_UNSUPPORTED_EXT: - ERROR_LOG("Error! format is not supported by current graphics card/driver!\n"); - break; - default: - ERROR_LOG("*UNKNOWN ERROR* reported from glCheckFramebufferStatusEXT() for %s!\n"); - break; - } - } -} - -#ifdef _WIN32 -#define GL_LOADFN(name) { \ - if( (*(void**)&name = (void*)wglGetProcAddress(#name)) == NULL ) { \ - ERROR_LOG("Failed to find %s, exiting\n", #name); \ - } \ -} -#else -// let GLEW take care of it -#define GL_LOADFN(name) -#endif - -bool ZeroGS::IsGLExt( const char* szTargetExtension ) -{ - return mapGLExtensions.find(string(szTargetExtension)) != mapGLExtensions.end(); -} - -bool ZeroGS::Create(int _width, int _height) -{ - GLenum err = GL_NO_ERROR; - bool bSuccess = true; - int i; - - Destroy(1); - GSStateReset(); - - cgSetErrorHandler(HandleCgError, NULL); - g_RenderFormatType = RFT_float16; - - nBackbufferWidth = _width; - nBackbufferHeight = _height; - fiRendWidth = 1.0f / nBackbufferWidth; - fiRendHeight = 1.0f / nBackbufferHeight; - -#ifdef _WIN32 - GLuint PixelFormat; // Holds The Results After Searching For A Match - DWORD dwExStyle; // Window Extended Style - DWORD dwStyle; // Window Style - - RECT rcdesktop; - GetWindowRect(GetDesktopWindow(), &rcdesktop); - - if (conf.options & GSOPTION_FULLSCREEN) { - nBackbufferWidth = rcdesktop.right - rcdesktop.left; - nBackbufferHeight = rcdesktop.bottom - rcdesktop.top; - - DEVMODE dmScreenSettings; - memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); - dmScreenSettings.dmSize=sizeof(dmScreenSettings); - dmScreenSettings.dmPelsWidth = nBackbufferWidth; - dmScreenSettings.dmPelsHeight = nBackbufferHeight; - dmScreenSettings.dmBitsPerPel = 32; - dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; - - // Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar. - if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) - { - if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES) - conf.options &= ~GSOPTION_FULLSCREEN; - else - return false; - } - } - else { - // change to default resolution - ChangeDisplaySettings(NULL, 0); - } - - if( conf.options & GSOPTION_FULLSCREEN) { - dwExStyle=WS_EX_APPWINDOW; - dwStyle=WS_POPUP; - ShowCursor(FALSE); - } - else { - dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; - dwStyle=WS_OVERLAPPEDWINDOW; - } - - RECT rc; - rc.left = 0; rc.top = 0; - rc.right = nBackbufferWidth; rc.bottom = nBackbufferHeight; - AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle); - int X = (rcdesktop.right-rcdesktop.left)/2 - (rc.right-rc.left)/2; - int Y = (rcdesktop.bottom-rcdesktop.top)/2 - (rc.bottom-rc.top)/2; - - SetWindowPos(GShwnd, NULL, X, Y, rc.right-rc.left, rc.bottom-rc.top, SWP_NOREPOSITION|SWP_NOZORDER); - - PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be - { - sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor - 1, // Version Number - PFD_DRAW_TO_WINDOW | // Format Must Support Window - PFD_SUPPORT_OPENGL | // Format Must Support OpenGL - PFD_DOUBLEBUFFER, // Must Support Double Buffering - PFD_TYPE_RGBA, // Request An RGBA Format - 32, // Select Our Color Depth - 0, 0, 0, 0, 0, 0, // Color Bits Ignored - 0, // 8bit Alpha Buffer - 0, // Shift Bit Ignored - 0, // No Accumulation Buffer - 0, 0, 0, 0, // Accumulation Bits Ignored - 24, // 24Bit Z-Buffer (Depth Buffer) - 8, // 8bit Stencil Buffer - 0, // No Auxiliary Buffer - PFD_MAIN_PLANE, // Main Drawing Layer - 0, // Reserved - 0, 0, 0 // Layer Masks Ignored - }; - - if (!(hDC=GetDC(GShwnd))) { - MessageBox(NULL,"(1) Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION); - return false; - } - - if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) { - MessageBox(NULL,"(2) Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION); - return false; - } - - if(!SetPixelFormat(hDC,PixelFormat,&pfd)) { - MessageBox(NULL,"(3) Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION); - return false; - } - - if (!(hRC=wglCreateContext(hDC))) { - MessageBox(NULL,"(4) Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION); - return false; - } - - if(!wglMakeCurrent(hDC,hRC)) { - MessageBox(NULL,"(5) Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION); - return false; - } - -#else - XVisualInfo *vi; - Colormap cmap; - int dpyWidth, dpyHeight; - int glxMajorVersion, glxMinorVersion; - int vidModeMajorVersion, vidModeMinorVersion; - Atom wmDelete; - Window winDummy; - unsigned int borderDummy; - - // attributes for a single buffered visual in RGBA format with at least - // 8 bits per color and a 24 bit depth buffer - int attrListSgl[] = {GLX_RGBA, GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - GLX_DEPTH_SIZE, 24, - None}; - - // attributes for a double buffered visual in RGBA format with at least - // 8 bits per color and a 24 bit depth buffer - int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER, - GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - GLX_DEPTH_SIZE, 24, - None }; - - GLWin.fs = !!(conf.options & GSOPTION_FULLSCREEN); - - /* get an appropriate visual */ - vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDbl); - if (vi == NULL) { - vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListSgl); - GLWin.doubleBuffered = False; - ERROR_LOG("Only Singlebuffered Visual!\n"); - } - else { - GLWin.doubleBuffered = True; - ERROR_LOG("Got Doublebuffered Visual!\n"); - } - - glXQueryVersion(GLWin.dpy, &glxMajorVersion, &glxMinorVersion); - ERROR_LOG("glX-Version %d.%d\n", glxMajorVersion, glxMinorVersion); - /* create a GLX context */ - GLWin.ctx = glXCreateContext(GLWin.dpy, vi, 0, GL_TRUE); - /* create a color map */ - cmap = XCreateColormap(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen), - vi->visual, AllocNone); - GLWin.attr.colormap = cmap; - GLWin.attr.border_pixel = 0; - - // get a connection - XF86VidModeQueryVersion(GLWin.dpy, &vidModeMajorVersion, &vidModeMinorVersion); - - if (GLWin.fs) { - - XF86VidModeModeInfo **modes = NULL; - int modeNum = 0; - int bestMode = 0; - - // set best mode to current - bestMode = 0; - ERROR_LOG("XF86VidModeExtension-Version %d.%d\n", vidModeMajorVersion, vidModeMinorVersion); - XF86VidModeGetAllModeLines(GLWin.dpy, GLWin.screen, &modeNum, &modes); - - if( modeNum > 0 && modes != NULL ) { - /* save desktop-resolution before switching modes */ - GLWin.deskMode = *modes[0]; - /* look for mode with requested resolution */ - for (i = 0; i < modeNum; i++) { - if ((modes[i]->hdisplay == _width) && (modes[i]->vdisplay == _height)) { - bestMode = i; - } - } - - XF86VidModeSwitchToMode(GLWin.dpy, GLWin.screen, modes[bestMode]); - XF86VidModeSetViewPort(GLWin.dpy, GLWin.screen, 0, 0); - dpyWidth = modes[bestMode]->hdisplay; - dpyHeight = modes[bestMode]->vdisplay; - ERROR_LOG("Resolution %dx%d\n", dpyWidth, dpyHeight); - XFree(modes); - - /* create a fullscreen window */ - GLWin.attr.override_redirect = True; - GLWin.attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | - StructureNotifyMask; - GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen), - 0, 0, dpyWidth, dpyHeight, 0, vi->depth, InputOutput, vi->visual, - CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, - &GLWin.attr); - XWarpPointer(GLWin.dpy, None, GLWin.win, 0, 0, 0, 0, 0, 0); - XMapRaised(GLWin.dpy, GLWin.win); - XGrabKeyboard(GLWin.dpy, GLWin.win, True, GrabModeAsync, - GrabModeAsync, CurrentTime); - XGrabPointer(GLWin.dpy, GLWin.win, True, ButtonPressMask, - GrabModeAsync, GrabModeAsync, GLWin.win, None, CurrentTime); - } - else { - ERROR_LOG("Failed to start fullscreen. If you received the \n" - "\"XFree86-VidModeExtension\" extension is missing, add\n" - "Load \"extmod\"\n" - "to your X configuration file (under the Module Section)\n"); - GLWin.fs = 0; - } - } - - - if( !GLWin.fs ) { - - //XRootWindow(dpy,screen) - //int X = (rcdesktop.right-rcdesktop.left)/2 - (rc.right-rc.left)/2; - //int Y = (rcdesktop.bottom-rcdesktop.top)/2 - (rc.bottom-rc.top)/2; - - // create a window in window mode - GLWin.attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | - StructureNotifyMask; - GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen), - 0, 0, _width, _height, 0, vi->depth, InputOutput, vi->visual, - CWBorderPixel | CWColormap | CWEventMask, &GLWin.attr); - // only set window title and handle wm_delete_events if in windowed mode - wmDelete = XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", True); - XSetWMProtocols(GLWin.dpy, GLWin.win, &wmDelete, 1); - XSetStandardProperties(GLWin.dpy, GLWin.win, "ZeroGS", - "ZeroGS", None, NULL, 0, NULL); - XMapRaised(GLWin.dpy, GLWin.win); - } - - // connect the glx-context to the window - glXMakeCurrent(GLWin.dpy, GLWin.win, GLWin.ctx); - XGetGeometry(GLWin.dpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y, - &GLWin.width, &GLWin.height, &borderDummy, &GLWin.depth); - ERROR_LOG("Depth %d\n", GLWin.depth); - if (glXIsDirect(GLWin.dpy, GLWin.ctx)) - ERROR_LOG("you have Direct Rendering!\n"); - else - ERROR_LOG("no Direct Rendering possible!\n"); - - // better for pad plugin key input (thc) - XSelectInput(GLWin.dpy, GLWin.win, ExposureMask | KeyPressMask | KeyReleaseMask | - ButtonPressMask | StructureNotifyMask | EnterWindowMask | LeaveWindowMask | - FocusChangeMask ); - -#endif - - // fill the opengl extension map - const char* ptoken = (const char*)glGetString( GL_EXTENSIONS ); - if( ptoken == NULL ) return false; - - int prevlog = conf.log; - conf.log = 1; - GS_LOG("Supported OpenGL Extensions:\n%s\n", ptoken); // write to the log file - conf.log = prevlog; - - // insert all exts into mapGLExtensions - - const char* pend = NULL; - - while(ptoken != NULL ) { - pend = strchr(ptoken, ' '); - - if( pend != NULL ) { - mapGLExtensions[string(ptoken, pend-ptoken)]; - } - else { - mapGLExtensions[string(ptoken)]; - break; - } - - ptoken = pend; - while(*ptoken == ' ') ++ptoken; - } - - s_nFullscreen = (conf.options & GSOPTION_FULLSCREEN) ? 1 : 0; - conf.mrtdepth = 0; // for now - -#ifndef _WIN32 - int const glew_ok = glewInit(); - if( glew_ok != GLEW_OK ) { - ERROR_LOG("glewInit() is not ok!\n"); - return false; - } -#endif - - if( !IsGLExt("GL_EXT_framebuffer_object") ) { - ERROR_LOG("*********\nZeroGS: ERROR: Need GL_EXT_framebufer_object for multiple render targets\nZeroGS: *********\n"); - bSuccess = false; - } - if( !IsGLExt("GL_EXT_blend_equation_separate") || glBlendEquationSeparateEXT == NULL ) { - ERROR_LOG("*********\nZeroGS: OGL WARNING: Need GL_EXT_blend_equation_separate\nZeroGS: *********\n"); - zgsBlendEquationSeparateEXT = glBlendEquationSeparateDummy; - } - else { - zgsBlendEquationSeparateEXT = glBlendEquationSeparateEXT; - } - - if( !IsGLExt("GL_EXT_blend_func_separate") || glBlendFuncSeparateEXT == NULL ) { - ERROR_LOG("*********\nZeroGS: OGL WARNING: Need GL_EXT_blend_func_separate\nZeroGS: *********\n"); - zgsBlendFuncSeparateEXT = glBlendFuncSeparateDummy; - } - else { - zgsBlendFuncSeparateEXT = glBlendFuncSeparateEXT; - } - - if( !IsGLExt("GL_EXT_secondary_color") ) { - ERROR_LOG("*********\nZeroGS: OGL WARNING: Need GL_EXT_secondary_color\nZeroGS: *********\n"); - bSuccess = false; - } - - if( !IsGLExt("GL_ARB_draw_buffers") && !IsGLExt("GL_ATI_draw_buffers") ) { - ERROR_LOG("*********\nZeroGS: OGL WARNING: multiple render targets not supported, some effects might look bad\nZeroGS: *********\n"); - conf.mrtdepth = 0; - } - - if( !bSuccess ) - return false; - - if( g_GameSettings & GAME_32BITTARGS ) { - g_RenderFormatType = RFT_byte8; - ERROR_LOG("Setting 32 bit render target\n"); - } - else { - if( !IsGLExt("GL_NV_float_buffer") && !IsGLExt("GL_ARB_color_buffer_float") && !IsGLExt("ATI_pixel_format_float") ) { - ERROR_LOG("******\nZeroGS: GS WARNING: Floating point render targets not supported, switching to 32bit\nZeroGS: *********\n"); - g_RenderFormatType = RFT_byte8; - } - } - g_RenderFormatType = RFT_byte8; - -#ifdef _WIN32 - if( IsGLExt("WGL_EXT_swap_control") || IsGLExt("EXT_swap_control") ) - wglSwapIntervalEXT(0); -#else - if( IsGLExt("GLX_SGI_swap_control") ) { - _PFNSWAPINTERVAL swapinterval = (_PFNSWAPINTERVAL)wglGetProcAddress("glXSwapInterval"); - if( !swapinterval ) - swapinterval = (_PFNSWAPINTERVAL)wglGetProcAddress("glXSwapIntervalSGI"); - if( !swapinterval ) - swapinterval = (_PFNSWAPINTERVAL)wglGetProcAddress("glXSwapIntervalEXT"); - - if( swapinterval ) - swapinterval(0); - else - ERROR_LOG("no support for SwapInterval (framerate clamped to monitor refresh rate)\n"); - } -#endif - - // check the max texture width and height - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &g_MaxTexWidth); - g_MaxTexHeight = g_MaxTexWidth; - GPU_TEXWIDTH = g_MaxTexWidth/8; - g_fiGPU_TEXWIDTH = 1.0f / GPU_TEXWIDTH; - -#ifdef RELEASE_TO_PUBLIC -#ifdef _WIN32 - HRSRC hShaderSrc = FindResource(hInst, MAKEINTRESOURCE(IDR_SHADERS), RT_RCDATA); - assert( hShaderSrc != NULL ); - HGLOBAL hShaderGlob = LoadResource(hInst, hShaderSrc); - assert( hShaderGlob != NULL ); - s_lpShaderResources = (u8*)LockResource(hShaderGlob); -#else - FILE* fres = fopen("ps2hw.dat", "rb"); - if( fres == NULL ) { - fres = fopen("plugins/ps2hw.dat", "rb"); - if( fres == NULL ) { - ERROR_LOG("Cannot find ps2hw.dat in working directory. Exiting\n"); - return false; - } - } - fseek(fres, 0, SEEK_END); - size_t s = ftell(fres); - s_lpShaderResources = new u8[s+1]; - fseek(fres, 0, SEEK_SET); - fread(s_lpShaderResources, s, 1, fres); - s_lpShaderResources[s] = 0; -#endif - -#else - -#ifndef _WIN32 - // test if ps2hw.fx exists - char tempstr[255]; - char curwd[255]; - getcwd(curwd, ARRAY_SIZE(curwd)); - - strcpy(tempstr, "../plugins/gs/zerogs/opengl/"); - sprintf(EFFECT_NAME, "%sps2hw.fx", tempstr); - FILE* f = fopen(EFFECT_NAME, "r"); - if( f == NULL ) { - - strcpy(tempstr, "../../plugins/gs/zerogs/opengl/"); - sprintf(EFFECT_NAME, "%sps2hw.fx", tempstr); - f = fopen(EFFECT_NAME, "r"); - - if( f == NULL ) { - ERROR_LOG("Failed to find %s, try compiling a non-devbuild\n", EFFECT_NAME); - return false; - } - } - - fclose(f); - - sprintf(EFFECT_DIR, "%s/%s", curwd, tempstr); - sprintf(EFFECT_NAME, "%sps2hw.fx", EFFECT_DIR); -#endif - -#endif // RELEASE_TO_PUBLIC - - // load the effect, find the best profiles (if any) - if( cgGLIsProfileSupported(CG_PROFILE_ARBVP1) != CG_TRUE ) { - ERROR_LOG("arbvp1 not supported\n"); - return false; - } - if( cgGLIsProfileSupported(CG_PROFILE_ARBFP1) != CG_TRUE ) { - ERROR_LOG("arbfp1 not supported\n"); - return false; - } - - GL_REPORT_ERROR(); - if( err != GL_NO_ERROR ) bSuccess = false; - - s_srcrgb = s_dstrgb = s_srcalpha = s_dstalpha = GL_ONE; - - GL_LOADFN(glIsRenderbufferEXT); - GL_LOADFN(glBindRenderbufferEXT); - GL_LOADFN(glDeleteRenderbuffersEXT); - GL_LOADFN(glGenRenderbuffersEXT); - GL_LOADFN(glRenderbufferStorageEXT); - GL_LOADFN(glGetRenderbufferParameterivEXT); - GL_LOADFN(glIsFramebufferEXT); - GL_LOADFN(glBindFramebufferEXT); - GL_LOADFN(glDeleteFramebuffersEXT); - GL_LOADFN(glGenFramebuffersEXT); - GL_LOADFN(glCheckFramebufferStatusEXT); - GL_LOADFN(glFramebufferTexture1DEXT); - GL_LOADFN(glFramebufferTexture2DEXT); - GL_LOADFN(glFramebufferTexture3DEXT); - GL_LOADFN(glFramebufferRenderbufferEXT); - GL_LOADFN(glGetFramebufferAttachmentParameterivEXT); - GL_LOADFN(glGenerateMipmapEXT); - - if( IsGLExt("GL_ARB_draw_buffers") ) - glDrawBuffers = (PFNGLDRAWBUFFERSPROC)wglGetProcAddress("glDrawBuffers"); - else if( IsGLExt("GL_ATI_draw_buffers") ) - glDrawBuffers = (PFNGLDRAWBUFFERSPROC)wglGetProcAddress("glDrawBuffersATI"); - - glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); - - GL_REPORT_ERROR(); - if( err != GL_NO_ERROR ) bSuccess = false; - - glGenFramebuffersEXT( 1, &s_uFramebuffer); - if( s_uFramebuffer == 0 ) { - ERROR_LOG("failed to create the renderbuffer\n"); - } - - assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); - glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, s_uFramebuffer ); - - if( glDrawBuffers != NULL ) - glDrawBuffers(1, s_drawbuffers); - GL_REPORT_ERROR(); - if( err != GL_NO_ERROR ) bSuccess = false; - - font_p = new RasterFont(); - - GL_REPORT_ERROR(); - if( err != GL_NO_ERROR ) bSuccess = false; - - // init draw fns - drawfn[0] = KickPoint; - drawfn[1] = KickLine; - drawfn[2] = KickLine; - drawfn[3] = KickTriangle; - drawfn[4] = KickTriangle; - drawfn[5] = KickTriangleFan; - drawfn[6] = KickSprite; - drawfn[7] = KickDummy; - - SetAA(conf.aa); - GSsetGameCRC(g_LastCRC, g_GameSettings); - GL_STENCILFUNC(GL_ALWAYS, 0, 0); - - //g_GameSettings |= 0;//GAME_VSSHACK|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE|GAME_FASTUPDATE; - //s_bWriteDepth = TRUE; - - GL_BLEND_ALL(GL_ONE, GL_ONE, GL_ONE, GL_ONE); - - glViewport(0,0,nBackbufferWidth,nBackbufferHeight); // Reset The Current Viewport - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glShadeModel(GL_SMOOTH); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClearDepth(1.0f); - glEnable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - glDepthFunc(GL_LEQUAL); - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations - - glGenTextures(1, &ptexLogo); - glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexLogo); - -#ifdef _WIN32 - HRSRC hBitmapSrc = FindResource(hInst, MAKEINTRESOURCE(IDB_ZEROGSLOGO), RT_BITMAP); - assert( hBitmapSrc != NULL ); - HGLOBAL hBitmapGlob = LoadResource(hInst, hBitmapSrc); - assert( hBitmapGlob != NULL ); - PBITMAPINFO pinfo = (PBITMAPINFO)LockResource(hBitmapGlob); - - glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, 4, pinfo->bmiHeader.biWidth, pinfo->bmiHeader.biHeight, 0, pinfo->bmiHeader.biBitCount==32?GL_RGBA:GL_RGB, GL_UNSIGNED_BYTE, (u8*)pinfo+pinfo->bmiHeader.biSize); - nLogoWidth = pinfo->bmiHeader.biWidth; - nLogoHeight = pinfo->bmiHeader.biHeight; - glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -#else -#endif - - GL_REPORT_ERROR(); - - g_nCurVBOIndex = 0; - g_vboBuffers.resize(VB_NUMBUFFERS); - glGenBuffers((GLsizei)g_vboBuffers.size(), &g_vboBuffers[0]); - for(i = 0; i < (int)g_vboBuffers.size(); ++i) { - glBindBuffer(GL_ARRAY_BUFFER, g_vboBuffers[i]); - glBufferData(GL_ARRAY_BUFFER, 0x100*sizeof(VertexGPU), NULL, GL_STREAM_DRAW); - } - - GL_REPORT_ERROR(); - if( err != GL_NO_ERROR ) bSuccess = false; - - // create the blocks texture - g_fBlockMult = 1; - - vector vBlockData, vBilinearData; - BLOCK::FillBlocks(vBlockData, vBilinearData, 1); - - glGenTextures(1, &ptexBlocks); - glBindTexture(GL_TEXTURE_2D, ptexBlocks); - - g_internalFloatFmt = GL_ALPHA_FLOAT32_ATI; - g_internalRGBAFloatFmt = GL_RGBA_FLOAT32_ATI; - g_internalRGBAFloat16Fmt = GL_RGBA_FLOAT16_ATI; - - glTexImage2D(GL_TEXTURE_2D, 0, g_internalFloatFmt, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_ALPHA, GL_FLOAT, &vBlockData[0]); - - if( glGetError() != GL_NO_ERROR ) { - // try different internal format - g_internalFloatFmt = GL_FLOAT_R32_NV; - glTexImage2D(GL_TEXTURE_2D, 0, g_internalFloatFmt, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_RED, GL_FLOAT, &vBlockData[0]); - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - - if( glGetError() != GL_NO_ERROR ) { - - // error, resort to 16bit - g_fBlockMult = 65535.0f*(float)g_fiGPU_TEXWIDTH; - - BLOCK::FillBlocks(vBlockData, vBilinearData, 0); - glTexImage2D(GL_TEXTURE_2D, 0, 2, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_R, GL_UNSIGNED_SHORT, &vBlockData[0]); - if( glGetError() != GL_NO_ERROR ) - return false; - } - else { - // fill in the bilinear blocks - glGenTextures(1, &ptexBilinearBlocks); - glBindTexture(GL_TEXTURE_2D, ptexBilinearBlocks); - glTexImage2D(GL_TEXTURE_2D, 0, g_internalRGBAFloatFmt, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_RGBA, GL_FLOAT, &vBilinearData[0]); - - if( glGetError() != GL_NO_ERROR ) { - g_internalRGBAFloatFmt = GL_FLOAT_RGBA32_NV; - g_internalRGBAFloat16Fmt = GL_FLOAT_RGBA16_NV; - glTexImage2D(GL_TEXTURE_2D, 0, g_internalRGBAFloatFmt, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_RGBA, GL_FLOAT, &vBilinearData[0]); - B_G(glGetError() == GL_NO_ERROR, return false); - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - - float fpri = 1; - glPrioritizeTextures(1, &ptexBlocks, &fpri); - if( ptexBilinearBlocks != 0 ) - glPrioritizeTextures(1, &ptexBilinearBlocks, &fpri); - - GL_REPORT_ERROR(); - - // fill a simple rect - glGenBuffers(1, &vboRect); - glBindBuffer(GL_ARRAY_BUFFER, vboRect); - - vector verts(4); - VertexGPU* pvert = &verts[0]; - pvert->x = -0x7fff; pvert->y = 0x7fff; pvert->z = 0; pvert->s = 0; pvert->t = 0; pvert++; - pvert->x = 0x7fff; pvert->y = 0x7fff; pvert->z = 0; pvert->s = 1; pvert->t = 0; pvert++; - pvert->x = -0x7fff; pvert->y = -0x7fff; pvert->z = 0; pvert->s = 0; pvert->t = 1; pvert++; - pvert->x = 0x7fff; pvert->y = -0x7fff; pvert->z = 0; pvert->s = 1; pvert->t = 1; pvert++; - glBufferDataARB(GL_ARRAY_BUFFER, 4*sizeof(VertexGPU), &verts[0], GL_STATIC_DRAW); - - // setup the default vertex declaration - glEnableClientState(GL_VERTEX_ARRAY); - glClientActiveTexture(GL_TEXTURE0); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_SECONDARY_COLOR_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - GL_REPORT_ERROR(); - - // some cards don't support this -// glClientActiveTexture(GL_TEXTURE0); -// glEnableClientState(GL_TEXTURE_COORD_ARRAY); -// glTexCoordPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexGPU), (void*)12); - - // create the conversion textures - glGenTextures(1, &ptexConv16to32); - glBindTexture(GL_TEXTURE_2D, ptexConv16to32); - - vector conv16to32data(256*256); - for(i = 0; i < 256*256; ++i) { - u32 tempcol = RGBA16to32(i); - // have to flip r and b - conv16to32data[i] = (tempcol&0xff00ff00)|((tempcol&0xff)<<16)|((tempcol&0xff0000)>>16); - } - glTexImage2D(GL_TEXTURE_2D, 0, 4, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, &conv16to32data[0]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - - GL_REPORT_ERROR(); - if( err != GL_NO_ERROR ) bSuccess = false; - - vector conv32to16data(32*32*32); - - glGenTextures(1, &ptexConv32to16); - glBindTexture(GL_TEXTURE_3D, ptexConv32to16); - u32* dst = &conv32to16data[0]; - for(i = 0; i < 32; ++i) { - for(int j = 0; j < 32; ++j) { - for(int k = 0; k < 32; ++k) { - u32 col = (i<<10)|(j<<5)|k; - *dst++ = ((col&0xff)<<16)|(col&0xff00); - } - } - } - glTexImage3D(GL_TEXTURE_3D, 0, 4, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, &conv32to16data[0]); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP); - GL_REPORT_ERROR(); - if( err != GL_NO_ERROR ) bSuccess = false; - - g_cgcontext = cgCreateContext(); - - cgvProf = CG_PROFILE_ARBVP1; - cgfProf = CG_PROFILE_ARBFP1; - cgGLEnableProfile(cgvProf); - cgGLEnableProfile(cgfProf); - cgGLSetOptimalOptions(cgvProf); - cgGLSetOptimalOptions(cgfProf); - - cgGLSetManageTextureParameters(g_cgcontext, CG_FALSE); - //cgSetAutoCompile(g_cgcontext, CG_COMPILE_IMMEDIATE); - - g_fparamFogColor = cgCreateParameter(g_cgcontext, CG_FLOAT4); - g_vparamPosXY[0] = cgCreateParameter(g_cgcontext, CG_FLOAT4); - g_vparamPosXY[1] = cgCreateParameter(g_cgcontext, CG_FLOAT4); - - ERROR_LOG("Creating effects\n"); - B_G(LoadEffects(), return false); - - g_bDisplayMsg = 0; - - - // create a sample shader - clampInfo temp; - memset(&temp, 0, sizeof(temp)); - temp.wms = 3; temp.wmt = 3; - - g_nPixelShaderVer = SHADER_ACCURATE; - // test - bool bFailed; - FRAGMENTSHADER* pfrag = LoadShadeEffect(0, 1, 1, 1, 1, temp, 0, &bFailed); - if( bFailed || pfrag == NULL ) { - g_nPixelShaderVer = SHADER_ACCURATE|SHADER_REDUCED; - - pfrag = LoadShadeEffect(0, 0, 1, 1, 0, temp, 0, &bFailed); - if( pfrag != NULL ) - cgGLLoadProgram(pfrag->prog); - if( bFailed || pfrag == NULL || cgGetError() != CG_NO_ERROR ) { - g_nPixelShaderVer = SHADER_REDUCED; - ERROR_LOG("Basic shader test failed\n"); - } - } - - g_bDisplayMsg = 1; - if( g_nPixelShaderVer & SHADER_REDUCED ) - conf.bilinear = 0; - - ERROR_LOG("Creating extra effects\n"); - B_G(LoadExtraEffects(), return false); - - ERROR_LOG("using %s shaders\n", g_pShaders[g_nPixelShaderVer]); - - GL_REPORT_ERROR(); - if( err != GL_NO_ERROR ) bSuccess = false; - - glDisable(GL_STENCIL_TEST); - glEnable(GL_SCISSOR_TEST); - - GL_BLEND_ALPHA(GL_ONE, GL_ZERO); - glBlendColorEXT(0, 0, 0, 0.5f); - - glDisable(GL_CULL_FACE); - - // points - // This was changed in SetAA - should we be changing it back? - glPointSize(1.0f); - g_nDepthBias = 0; - glEnable(GL_POLYGON_OFFSET_FILL); - glEnable(GL_POLYGON_OFFSET_LINE); - glPolygonOffset(0, 1); - - vb[0].Init(VB_BUFFERSIZE); - vb[1].Init(VB_BUFFERSIZE); - g_bSaveFlushedFrame = 1; - - g_vsprog = g_psprog = 0; - - return glGetError() == GL_NO_ERROR && bSuccess; -} - -void ZeroGS::Destroy(BOOL bD3D) -{ - if( s_aviinit ) { - StopCapture(); - -#ifdef _WIN32 - STOP_AVI(); -#else // linux - //TODO -#endif - ERROR_LOG("zerogs.avi stopped"); - s_aviinit = 0; - } - - g_MemTargs.Destroy(); - s_RTs.Destroy(); - s_DepthRTs.Destroy(); - s_BitwiseTextures.Destroy(); - - SAFE_RELEASE_TEX(s_ptexInterlace); - SAFE_RELEASE_TEX(ptexBlocks); - SAFE_RELEASE_TEX(ptexBilinearBlocks); - SAFE_RELEASE_TEX(ptexConv16to32); - SAFE_RELEASE_TEX(ptexConv32to16); - - vb[0].Destroy(); - vb[1].Destroy(); - - if( g_vboBuffers.size() > 0 ) { - glDeleteBuffers((GLsizei)g_vboBuffers.size(), &g_vboBuffers[0]); - g_vboBuffers.clear(); - } - g_nCurVBOIndex = 0; - - for(int i = 0; i < ARRAY_SIZE(pvs); ++i) { - SAFE_RELEASE_PROG(pvs[i]); - } - for(int i = 0; i < ARRAY_SIZE(ppsRegular); ++i) { - SAFE_RELEASE_PROG(ppsRegular[i].prog); - } - for(int i = 0; i < ARRAY_SIZE(ppsTexture); ++i) { - SAFE_RELEASE_PROG(ppsTexture[i].prog); - } - - SAFE_RELEASE_PROG(pvsBitBlt.prog); - SAFE_RELEASE_PROG(ppsBitBlt[0].prog); SAFE_RELEASE_PROG(ppsBitBlt[1].prog); - SAFE_RELEASE_PROG(ppsBitBltDepth.prog); - SAFE_RELEASE_PROG(ppsCRTCTarg[0].prog); SAFE_RELEASE_PROG(ppsCRTCTarg[1].prog); - SAFE_RELEASE_PROG(ppsCRTC[0].prog); SAFE_RELEASE_PROG(ppsCRTC[1].prog); - SAFE_RELEASE_PROG(ppsCRTC24[0].prog); SAFE_RELEASE_PROG(ppsCRTC24[1].prog); - SAFE_RELEASE_PROG(ppsOne.prog); - - SAFE_DELETE(font_p); - -#ifdef _WIN32 - if (hRC) // Do We Have A Rendering Context? - { - if (!wglMakeCurrent(NULL,NULL)) // Are We Able To Release The DC And RC Contexts? - { - MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); - } - - if (!wglDeleteContext(hRC)) // Are We Able To Delete The RC? - { - MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); - } - hRC=NULL; // Set RC To NULL - } - - if (hDC && !ReleaseDC(GShwnd,hDC)) // Are We Able To Release The DC - { - MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); - hDC=NULL; // Set DC To NULL - } -#else // linux - if (GLWin.ctx) - { - if (!glXMakeCurrent(GLWin.dpy, None, NULL)) - { - ERROR_LOG("Could not release drawing context.\n"); - } - glXDestroyContext(GLWin.dpy, GLWin.ctx); - GLWin.ctx = NULL; - } - /* switch back to original desktop resolution if we were in fs */ - if( GLWin.dpy != NULL ) { - if (GLWin.fs) { - XF86VidModeSwitchToMode(GLWin.dpy, GLWin.screen, &GLWin.deskMode); - XF86VidModeSetViewPort(GLWin.dpy, GLWin.screen, 0, 0); - } - } -#endif - - mapGLExtensions.clear(); -} - -void ZeroGS::GSStateReset() -{ - icurctx = -1; - - for(int i = 0; i < 2; ++i) { - vb[i].Destroy(); - memset(&vb[i], 0, SIZEOF_VB); - - vb[i].tex0.tw = 1; - vb[i].tex0.th = 1; - vb[i].scissor.x1 = 639; - vb[i].scissor.y1 = 479; - vb[i].tex0.tbw = 64; - vb[i].Init(VB_BUFFERSIZE); - } - - s_RangeMngr.Clear(); - g_MemTargs.Destroy(); - s_RTs.Destroy(); - s_DepthRTs.Destroy(); - s_BitwiseTextures.Destroy(); - - vb[0].ictx = 0; - vb[1].ictx = 1; -} - -void ZeroGS::AddMessage(const char* pstr, u32 ms) -{ - listMsgs.push_back(MESSAGE(pstr, timeGetTime()+ms)); -} - -void ZeroGS::DrawText(const char* pstr, int left, int top, u32 color) -{ - cgGLDisableProfile(cgvProf); - cgGLDisableProfile(cgfProf); - - glColor3f(((color>>16)&0xff)/255.0f, ((color>>8)&0xff)/255.0f, (color&0xff)/255.0f); - - font_p->printString(pstr, left * 2.0f / (float)nBackbufferWidth - 1, 1 - top * 2.0f / (float)nBackbufferHeight,0); - cgGLEnableProfile(cgvProf); - cgGLEnableProfile(cgfProf); -} - -void ZeroGS::ChangeWindowSize(int nNewWidth, int nNewHeight) -{ - nBackbufferWidth = nNewWidth > 16 ? nNewWidth : 16; - nBackbufferHeight = nNewHeight > 16 ? nNewHeight : 16; - - if( !(conf.options & GSOPTION_FULLSCREEN) ) { - conf.width = nNewWidth; - conf.height = nNewHeight; - //SaveConfig(); - } -} - -void ZeroGS::SetChangeDeviceSize(int nNewWidth, int nNewHeight) -{ - s_nNewWidth = nNewWidth; - s_nNewHeight = nNewHeight; - - if( !(conf.options & GSOPTION_FULLSCREEN) ) { - conf.width = nNewWidth; - conf.height = nNewHeight; - //SaveConfig(); - } -} - -void ZeroGS::Reset() -{ - s_RTs.ResolveAll(); - s_DepthRTs.ResolveAll(); - - vb[0].nCount = 0; - vb[1].nCount = 0; - - memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); - s_nLastResolveReset = 0; - - icurctx = -1; - g_vsprog = g_psprog = 0; - - GSStateReset(); - Destroy(0); - - drawfn[0] = KickDummy; - drawfn[1] = KickDummy; - drawfn[2] = KickDummy; - drawfn[3] = KickDummy; - drawfn[4] = KickDummy; - drawfn[5] = KickDummy; - drawfn[6] = KickDummy; - drawfn[7] = KickDummy; -} - -void ZeroGS::ChangeDeviceSize(int nNewWidth, int nNewHeight) -{ - int oldscreen = s_nFullscreen; - - int oldwidth = nBackbufferWidth, oldheight = nBackbufferHeight; - if( !Create(nNewWidth&~7, nNewHeight&~7) ) { - ERROR_LOG("Failed to recreate, changing to old\n"); - if( !Create(oldwidth, oldheight) ) { - SysMessage("failed to create dev, exiting...\n"); - exit(0); - } - } - - for(int i = 0; i < 2; ++i) { - vb[i].bNeedFrameCheck = vb[i].bNeedZCheck = 1; - vb[i].CheckFrame(0); - } - - if( oldscreen && !(conf.options & GSOPTION_FULLSCREEN) ) { // if transitioning from full screen - RECT rc; - rc.left = 0; rc.top = 0; - rc.right = conf.width; rc.bottom = conf.height; - -#ifdef _WIN32 - AdjustWindowRect(&rc, conf.winstyle, FALSE); - - RECT rcdesktop; - GetWindowRect(GetDesktopWindow(), &rcdesktop); - - SetWindowLong( GShwnd, GWL_STYLE, conf.winstyle ); - SetWindowPos(GShwnd, HWND_TOP, ((rcdesktop.right-rcdesktop.left)-(rc.right-rc.left))/2, - ((rcdesktop.bottom-rcdesktop.top)-(rc.bottom-rc.top))/2, - rc.right-rc.left, rc.bottom-rc.top, SWP_SHOWWINDOW); - UpdateWindow(GShwnd); -#else // linux -#endif - } - - assert( vb[0].pBufferData != NULL && vb[1].pBufferData != NULL ); -} - -void ZeroGS::SetAA(int mode) -{ - float f; - - // need to flush all targets - s_RTs.ResolveAll(); - s_RTs.Destroy(); - s_DepthRTs.ResolveAll(); - s_DepthRTs.Destroy(); - - s_AAx = s_AAy = 0; // This is code for x0, x2, x4, x8 and x16 anti-aliasing. - if (mode > 0) - { - s_AAx = (mode+1) / 2; // ( 1, 0 ) ; ( 1, 1 ) ; ( 2, 1 ) ; ( 2, 2 ) -- it's used as binary shift, so x >> s_AAx, y >> s_AAy - s_AAy = mode / 2; - } - - memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); - s_nLastResolveReset = 0; - - vb[0].prndr = NULL; vb[0].pdepth = NULL; vb[0].bNeedFrameCheck = 1; vb[0].bNeedZCheck = 1; - vb[1].prndr = NULL; vb[1].pdepth = NULL; vb[1].bNeedFrameCheck = 1; vb[1].bNeedZCheck = 1; - - f = mode > 0 ? 2.0f : 1.0f; - glPointSize(f); -} - -#define SET_UNIFORMPARAM(var, name) { \ - p = cgGetNamedParameter(pf->prog, name); \ - if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) \ - pf->var = p; \ -} \ - -void SetupFragmentProgramParameters(FRAGMENTSHADER* pf, int context, int type) -{ - // uniform parameters - CGparameter p; - - p = cgGetNamedParameter(pf->prog, "g_fFogColor"); - if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { - cgConnectParameter(g_fparamFogColor, p); - } - - SET_UNIFORMPARAM(sOneColor, "g_fOneColor"); - SET_UNIFORMPARAM(sBitBltZ, "g_fBitBltZ"); - SET_UNIFORMPARAM(sInvTexDims, "g_fInvTexDims"); - SET_UNIFORMPARAM(fTexAlpha2, "fTexAlpha2"); - SET_UNIFORMPARAM(fTexOffset, "g_fTexOffset"); - SET_UNIFORMPARAM(fTexDims, "g_fTexDims"); - SET_UNIFORMPARAM(fTexBlock, "g_fTexBlock"); - SET_UNIFORMPARAM(fClampExts, "g_fClampExts"); - SET_UNIFORMPARAM(fTexWrapMode, "TexWrapMode"); - SET_UNIFORMPARAM(fRealTexDims, "g_fRealTexDims"); - SET_UNIFORMPARAM(fTestBlack, "g_fTestBlack"); - SET_UNIFORMPARAM(fPageOffset, "g_fPageOffset"); - SET_UNIFORMPARAM(fTexAlpha, "fTexAlpha"); - - // textures - p = cgGetNamedParameter(pf->prog, "g_sBlocks"); - if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { - cgGLSetTextureParameter(p, ptexBlocks); - cgGLEnableTextureParameter(p); - } - - // cg parameter usage is wrong, so do it manually - if( type == 3 ) { - p = cgGetNamedParameter(pf->prog, "g_sConv16to32"); - if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { - cgGLSetTextureParameter(p, ptexConv16to32); - cgGLEnableTextureParameter(p); - } - } - else if( type == 4 ) { - p = cgGetNamedParameter(pf->prog, "g_sConv32to16"); - if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { - cgGLSetTextureParameter(p, ptexConv32to16); - cgGLEnableTextureParameter(p); - } - } - else { - p = cgGetNamedParameter(pf->prog, "g_sBilinearBlocks"); - if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { - cgGLSetTextureParameter(p, ptexBilinearBlocks); - cgGLEnableTextureParameter(p); - } - } - - p = cgGetNamedParameter(pf->prog, "g_sMemory"); - if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { - //cgGLEnableTextureParameter(p); - pf->sMemory = p; - } - p = cgGetNamedParameter(pf->prog, "g_sSrcFinal"); - if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { - //cgGLEnableTextureParameter(p); - pf->sFinal = p; - } - p = cgGetNamedParameter(pf->prog, "g_sBitwiseANDX"); - if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { - //cgGLEnableTextureParameter(p); - pf->sBitwiseANDX = p; - } - p = cgGetNamedParameter(pf->prog, "g_sBitwiseANDY"); - if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { - //cgGLEnableTextureParameter(p); - pf->sBitwiseANDY = p; - } - p = cgGetNamedParameter(pf->prog, "g_sCLUT"); - if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { - //cgGLEnableTextureParameter(p); - pf->sCLUT = p; - } - p = cgGetNamedParameter(pf->prog, "g_sInterlace"); - if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { - //cgGLEnableTextureParameter(p); - pf->sInterlace = p; - } - - // set global shader constants - p = cgGetNamedParameter(pf->prog, "g_fExactColor"); - if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { - cgGLSetParameter4fv(p, Vector(0.5f, (g_GameSettings&GAME_EXACTCOLOR)?0.9f/256.0f:0.5f/256.0f, 0,1/255.0f)); - } - - p = cgGetNamedParameter(pf->prog, "g_fBilinear"); - if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) - cgGLSetParameter4fv(p, Vector(-0.2f, -0.65f, 0.9f, 1.0f / 32767.0f )); - - p = cgGetNamedParameter(pf->prog, "g_fZBias"); - if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) - cgGLSetParameter4fv(p, Vector(1.0f/256.0f, 1.0004f, 1, 0.5f)); - - p = cgGetNamedParameter(pf->prog, "g_fc0"); - if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) - cgGLSetParameter4fv(p, Vector(0,1, 0.001f, 0.5f)); - - p = cgGetNamedParameter(pf->prog, "g_fMult"); - if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) - cgGLSetParameter4fv(p, Vector(1/1024.0f, 0.2f/1024.0f, 1/128.0f, 1/512.0f)); -} - -void SetupVertexProgramParameters(CGprogram prog, int context) -{ - CGparameter p; - - p = cgGetNamedParameter(prog, "g_fPosXY"); - if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) - cgConnectParameter(g_vparamPosXY[context], p); - - p = cgGetNamedParameter(prog, "g_fZ"); - if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) - cgGLSetParameter4fv(p, g_vdepth); - - Vector vnorm = Vector(g_filog32, 0, 0,0); - p = cgGetNamedParameter(prog, "g_fZNorm"); - if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) - cgGLSetParameter4fv(p, vnorm); - - p = cgGetNamedParameter(prog, "g_fBilinear"); - if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) - cgGLSetParameter4fv(p, Vector(-0.2f, -0.65f, 0.9f, 1.0f / 32767.0f )); - - p = cgGetNamedParameter(prog, "g_fZBias"); - if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) - cgGLSetParameter4fv(p, Vector(1.0f/256.0f, 1.0004f, 1, 0.5f)); - - p = cgGetNamedParameter(prog, "g_fc0"); - if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) - cgGLSetParameter4fv(p, Vector(0,1, 0.001f, 0.5f)); -} - -#ifdef RELEASE_TO_PUBLIC - -#define LOAD_VS(Index, prog) { \ - assert( mapShaderResources.find(Index) != mapShaderResources.end() ); \ - header = mapShaderResources[Index]; \ - assert( (header) != NULL && (header)->index == (Index) ); \ - prog = cgCreateProgram(g_cgcontext, CG_OBJECT, (char*)(s_lpShaderResources + (header)->offset), cgvProf, NULL, NULL); \ - if( !cgIsProgram(prog) ) { \ - ERROR_LOG("Failed to load vs %d: \n%s\n", Index, cgGetLastListing(g_cgcontext)); \ - return false; \ - } \ - cgGLLoadProgram(prog); \ - if( cgGetError() != CG_NO_ERROR ) ERROR_LOG("failed to load program %d\n", Index); \ - SetupVertexProgramParameters(prog, !!(Index&SH_CONTEXT1)); \ -} \ - -#define LOAD_PS(Index, fragment) { \ - bLoadSuccess = true; \ - assert( mapShaderResources.find(Index) != mapShaderResources.end() ); \ - header = mapShaderResources[Index]; \ - fragment.prog = cgCreateProgram(g_cgcontext, CG_OBJECT, (char*)(s_lpShaderResources + (header)->offset), cgfProf, NULL, NULL); \ - if( !cgIsProgram(fragment.prog) ) { \ - ERROR_LOG("Failed to load ps %d: \n%s\n", Index, cgGetLastListing(g_cgcontext)); \ - return false; \ - } \ - cgGLLoadProgram(fragment.prog); \ - if( cgGetError() != CG_NO_ERROR ) { \ - ERROR_LOG("failed to load program %d\n", Index); \ - bLoadSuccess = false; \ - } \ - SetupFragmentProgramParameters(&fragment, !!(Index&SH_CONTEXT1), 0); \ -} \ - -bool ZeroGS::LoadEffects() -{ - assert( s_lpShaderResources != NULL ); - - // process the header - u32 num = *(u32*)s_lpShaderResources; - int compressed_size = *(int*)(s_lpShaderResources+4); - int real_size = *(int*)(s_lpShaderResources+8); - int out; - - char* pbuffer = (char*)malloc(real_size); - inf((char*)s_lpShaderResources+12, &pbuffer[0], compressed_size, real_size, &out); - assert(out == real_size); - - s_lpShaderResources = (u8*)pbuffer; - SHADERHEADER* header = (SHADERHEADER*)s_lpShaderResources; - - mapShaderResources.clear(); - while(num-- > 0 ) { - mapShaderResources[header->index] = header; - ++header; - } - - // clear the textures - for(int i = 0; i < ARRAY_SIZE(ppsTexture); ++i) { - SAFE_RELEASE_PROG(ppsTexture[i].prog); - ppsTexture[i].prog = NULL; - } -#ifndef _DEBUG - memset(ppsTexture, 0, sizeof(ppsTexture)); -#endif - - return true; -} - -// called -bool ZeroGS::LoadExtraEffects() -{ - SHADERHEADER* header; - bool bLoadSuccess = true; - - const int vsshaders[4] = { SH_REGULARVS, SH_TEXTUREVS, SH_REGULARFOGVS, SH_TEXTUREFOGVS }; - - for(int i = 0; i < 4; ++i) { - LOAD_VS(vsshaders[i], pvs[2*i]); - LOAD_VS(vsshaders[i]|SH_CONTEXT1, pvs[2*i+1]); - //if( conf.mrtdepth ) { - LOAD_VS(vsshaders[i]|SH_WRITEDEPTH, pvs[2*i+8]); - LOAD_VS(vsshaders[i]|SH_WRITEDEPTH|SH_CONTEXT1, pvs[2*i+8+1]); -// } -// else { -// pvs[2*i+8] = pvs[2*i+8+1] = NULL; -// } - } - - LOAD_VS(SH_BITBLTVS, pvsBitBlt.prog); - pvsBitBlt.sBitBltPos = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltPos"); - pvsBitBlt.sBitBltTex = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltTex"); - pvsBitBlt.fBitBltTrans = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltTrans"); - - LOAD_PS(SH_REGULARPS, ppsRegular[0]); - LOAD_PS(SH_REGULARFOGPS, ppsRegular[1]); - - if( conf.mrtdepth ) { - LOAD_PS(SH_REGULARPS, ppsRegular[2]); - if( !bLoadSuccess ) - conf.mrtdepth = 0; - LOAD_PS(SH_REGULARFOGPS, ppsRegular[3]); - if( !bLoadSuccess ) - conf.mrtdepth = 0; - } - - LOAD_PS(SH_BITBLTPS, ppsBitBlt[0]); - LOAD_PS(SH_BITBLTAAPS, ppsBitBlt[1]); - if( !bLoadSuccess ) { - ERROR_LOG("Failed to load BitBltAAPS, using BitBltPS\n"); - LOAD_PS(SH_BITBLTPS, ppsBitBlt[1]); - } - LOAD_PS(SH_BITBLTDEPTHPS, ppsBitBltDepth); - LOAD_PS(SH_CRTCTARGPS, ppsCRTCTarg[0]); - LOAD_PS(SH_CRTCTARGINTERPS, ppsCRTCTarg[1]); - - g_bCRTCBilinear = TRUE; - LOAD_PS(SH_CRTCPS, ppsCRTC[0]); - if( !bLoadSuccess ) { - // switch to simpler - g_bCRTCBilinear = FALSE; - LOAD_PS(SH_CRTC_NEARESTPS, ppsCRTC[0]); - LOAD_PS(SH_CRTCINTER_NEARESTPS, ppsCRTC[0]); - } - else { - LOAD_PS(SH_CRTCINTERPS, ppsCRTC[1]); - } - - if( !bLoadSuccess ) - ERROR_LOG("Failed to create CRTC shaders\n"); - - LOAD_PS(SH_CRTC24PS, ppsCRTC24[0]); - LOAD_PS(SH_CRTC24INTERPS, ppsCRTC24[1]); - LOAD_PS(SH_ZEROPS, ppsOne); - LOAD_PS(SH_BASETEXTUREPS, ppsBaseTexture); - LOAD_PS(SH_CONVERT16TO32PS, ppsConvert16to32); - LOAD_PS(SH_CONVERT32TO16PS, ppsConvert32to16); - - return true; -} - -FRAGMENTSHADER* ZeroGS::LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context, bool* pbFailed) -{ - int texwrap; - assert( texfilter < NUM_FILTERS ); - - if(g_nPixelShaderVer&SHADER_REDUCED) - texfilter = 0; - assert(!(g_nPixelShaderVer&SHADER_REDUCED) || !exactcolor); - - if( clamp.wms == clamp.wmt ) { - switch( clamp.wms ) { - case 0: texwrap = TEXWRAP_REPEAT; break; - case 1: texwrap = TEXWRAP_CLAMP; break; - case 2: texwrap = TEXWRAP_CLAMP; break; - default: texwrap = TEXWRAP_REGION_REPEAT; break; - } - } - else if( clamp.wms==3||clamp.wmt==3) - texwrap = TEXWRAP_REGION_REPEAT; - else - texwrap = TEXWRAP_REPEAT_CLAMP; - - int index = GET_SHADER_INDEX(type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, context, 0); - - assert( index < ARRAY_SIZE(ppsTexture) ); - FRAGMENTSHADER* pf = ppsTexture+index; - - if( pbFailed != NULL ) *pbFailed = false; - - if( pf->prog != NULL ) - return pf; - - if( (g_nPixelShaderVer & SHADER_ACCURATE) && mapShaderResources.find(index+NUM_SHADERS*SHADER_ACCURATE) != mapShaderResources.end() ) - index += NUM_SHADERS*SHADER_ACCURATE; - - assert( mapShaderResources.find(index) != mapShaderResources.end() ); - SHADERHEADER* header = mapShaderResources[index]; - if( header == NULL ) - ERROR_LOG("%d %d\n", index, g_nPixelShaderVer); - assert( header != NULL ); - - //DEBUG_LOG("shader:\n%s\n", (char*)(s_lpShaderResources + (header)->offset)); - pf->prog = cgCreateProgram(g_cgcontext, CG_OBJECT, (char*)(s_lpShaderResources + (header)->offset), cgfProf, NULL, NULL); - if( pf->prog != NULL && cgIsProgram(pf->prog) && cgGetError() == CG_NO_ERROR ) { - SetupFragmentProgramParameters(pf, context, type); - cgGLLoadProgram(pf->prog); - if( cgGetError() != CG_NO_ERROR ) { -// cgGLLoadProgram(pf->prog); -// if( cgGetError() != CG_NO_ERROR ) { - ERROR_LOG("Failed to load shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); - if( pbFailed != NULL ) *pbFailed = true; - return pf; -// } - } - return pf; - } - - ERROR_LOG("Failed to create shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); - if( pbFailed != NULL ) *pbFailed = true; - - return NULL; -} - -#else // not RELEASE_TO_PUBLIC - -#define LOAD_VS(name, prog, shaderver) { \ - prog = cgCreateProgramFromFile(g_cgcontext, CG_SOURCE, EFFECT_NAME, shaderver, name, args); \ - if( !cgIsProgram(prog) ) { \ - ERROR_LOG("Failed to load vs %s: \n%s\n", name, cgGetLastListing(g_cgcontext)); \ - return false; \ - } \ - cgGLLoadProgram(prog); \ - if( cgGetError() != CG_NO_ERROR ) ERROR_LOG("failed to load program %s\n", name); \ - SetupVertexProgramParameters(prog, args[0]==context1); \ -} \ - -#ifdef _DEBUG -#define SET_PSFILENAME(frag, name) frag.filename = name -#else -#define SET_PSFILENAME(frag, name) -#endif - -#define LOAD_PS(name, fragment, shaderver) { \ - bLoadSuccess = true; \ - fragment.prog = cgCreateProgramFromFile(g_cgcontext, CG_SOURCE, EFFECT_NAME, shaderver, name, args); \ - if( !cgIsProgram(fragment.prog) ) { \ - ERROR_LOG("Failed to load ps %s: \n%s\n", name, cgGetLastListing(g_cgcontext)); \ - return false; \ - } \ - cgGLLoadProgram(fragment.prog); \ - if( cgGetError() != CG_NO_ERROR ) { \ - ERROR_LOG("failed to load program %s\n", name); \ - bLoadSuccess = false; \ - } \ - SetupFragmentProgramParameters(&fragment, args[0]==context1, 0); \ - SET_PSFILENAME(fragment, name); \ -} \ - -bool ZeroGS::LoadEffects() -{ - // clear the textures - for(int i = 0; i < ARRAY_SIZE(ppsTexture); ++i) { - SAFE_RELEASE_PROG(ppsTexture[i].prog); - } - -#ifndef _DEBUG - memset(ppsTexture, 0, sizeof(ppsTexture)); -#endif - - return true; -} - -bool ZeroGS::LoadExtraEffects() -{ - const char* args[] = { NULL , NULL, NULL, NULL }; - char context0[255], context1[255]; - sprintf(context0, "-I%sctx0", EFFECT_DIR); - sprintf(context1, "-I%sctx1", EFFECT_DIR); - char* write_depth = "-DWRITE_DEPTH"; - bool bLoadSuccess = true; - - const char* pvsshaders[4] = { "RegularVS", "TextureVS", "RegularFogVS", "TextureFogVS" }; - - for(int i = 0; i < 4; ++i) { - args[0] = context0; - args[1] = NULL; - LOAD_VS(pvsshaders[i], pvs[2*i], cgvProf); - args[0] = context1; - LOAD_VS(pvsshaders[i], pvs[2*i+1], cgvProf); - - //if( conf.mrtdepth ) { - args[0] = context0; - args[1] = write_depth; - LOAD_VS(pvsshaders[i], pvs[2*i+8], cgvProf); - args[0] = context1; - LOAD_VS(pvsshaders[i], pvs[2*i+8+1], cgvProf); -// } -// else { -// pvs[2*i+8] = pvs[2*i+8+1] = NULL; -// } - } - - args[0] = context0; - args[1] = NULL; - LOAD_VS("BitBltVS", pvsBitBlt.prog, cgvProf); - pvsBitBlt.sBitBltPos = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltPos"); - pvsBitBlt.sBitBltTex = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltTex"); - pvsBitBlt.fBitBltTrans = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltTrans"); - - LOAD_PS("RegularPS", ppsRegular[0], cgfProf); - LOAD_PS("RegularFogPS", ppsRegular[1], cgfProf); - - if( conf.mrtdepth ) { - args[0] = context0; - args[1] = write_depth; - LOAD_PS("RegularPS", ppsRegular[2], cgfProf); - if( !bLoadSuccess ) - conf.mrtdepth = 0; - LOAD_PS("RegularFogPS", ppsRegular[3], cgfProf); - if( !bLoadSuccess ) - conf.mrtdepth = 0; - } - - LOAD_PS("BitBltPS", ppsBitBlt[0], cgfProf); - LOAD_PS("BitBltAAPS", ppsBitBlt[1], cgfProf); - if( !bLoadSuccess ) { - ERROR_LOG("Failed to load BitBltAAPS, using BitBltPS\n"); - LOAD_PS("BitBltPS", ppsBitBlt[1], cgfProf); - } - - LOAD_PS("BitBltDepthPS", ppsBitBltDepth, cgfProf); - LOAD_PS("CRTCTargPS", ppsCRTCTarg[0], cgfProf); LOAD_PS("CRTCTargInterPS", ppsCRTCTarg[1], cgfProf); - - g_bCRTCBilinear = TRUE; - LOAD_PS("CRTCPS", ppsCRTC[0], cgfProf); - if( !bLoadSuccess ) { - // switch to simpler - g_bCRTCBilinear = FALSE; - LOAD_PS("CRTCPS_Nearest", ppsCRTC[0], cgfProf); - LOAD_PS("CRTCInterPS_Nearest", ppsCRTC[0], cgfProf); - } - else { - LOAD_PS("CRTCInterPS", ppsCRTC[1], cgfProf); - } - - if( !bLoadSuccess ) - ERROR_LOG("Failed to create CRTC shaders\n"); - - LOAD_PS("CRTC24PS", ppsCRTC24[0], cgfProf); LOAD_PS("CRTC24InterPS", ppsCRTC24[1], cgfProf); - LOAD_PS("ZeroPS", ppsOne, cgfProf); - LOAD_PS("BaseTexturePS", ppsBaseTexture, cgfProf); - LOAD_PS("Convert16to32PS", ppsConvert16to32, cgfProf); - LOAD_PS("Convert32to16PS", ppsConvert32to16, cgfProf); - -// if( !conf.mrtdepth ) { -// ERROR_LOG("Disabling MRT depth writing\n"); -// s_bWriteDepth = FALSE; -// } - - return true; -} - -FRAGMENTSHADER* ZeroGS::LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context, bool* pbFailed) -{ - int texwrap; - - assert( texfilter < NUM_FILTERS ); - //assert( g_nPixelShaderVer == SHADER_30 ); - if( clamp.wms == clamp.wmt ) { - switch( clamp.wms ) { - case 0: texwrap = TEXWRAP_REPEAT; break; - case 1: texwrap = TEXWRAP_CLAMP; break; - case 2: texwrap = TEXWRAP_CLAMP; break; - default: - texwrap = TEXWRAP_REGION_REPEAT; break; - } - } - else if( clamp.wms==3||clamp.wmt==3) - texwrap = TEXWRAP_REGION_REPEAT; - else - texwrap = TEXWRAP_REPEAT_CLAMP; - - int index = GET_SHADER_INDEX(type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, context, 0); - - if( pbFailed != NULL ) *pbFailed = false; - - FRAGMENTSHADER* pf = ppsTexture+index; - - if( pf->prog != NULL ) - return pf; - - pf->prog = LoadShaderFromType(EFFECT_DIR, EFFECT_NAME, type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, g_nPixelShaderVer, context); - - if( pf->prog != NULL ) { -#ifdef _DEBUG - char str[255]; - sprintf(str, "Texture%s%d_%sPS", fog?"Fog":"", texfilter, g_pTexTypes[type]); - pf->filename = str; -#endif - SetupFragmentProgramParameters(pf, context, type); - cgGLLoadProgram(pf->prog); - if( cgGetError() != CG_NO_ERROR ) { - // try again -// cgGLLoadProgram(pf->prog); -// if( cgGetError() != CG_NO_ERROR ) { - ERROR_LOG("Failed to load shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); - if( pbFailed != NULL ) *pbFailed = true; - //assert(0); - // NULL makes things crash - return pf; -// } - } - return pf; - } - - ERROR_LOG("Failed to create shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); - if( pbFailed != NULL ) *pbFailed = true; - - return NULL; -} - -#endif // RELEASE_TO_PUBLIC - -void ZeroGS::Prim() -{ - if( g_bIsLost ) - return; - - VB& curvb = vb[prim->ctxt]; - if( curvb.CheckPrim() ) - Flush(prim->ctxt); - curvb.curprim._val = prim->_val; - - // flush the other pipe if sharing the same buffer -// if( vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp && vb[!prim->ctxt].nCount > 0 ) -// { -// assert( vb[prim->ctxt].nCount == 0 ); -// Flush(!prim->ctxt); -// } - - curvb.curprim.prim = prim->prim; -} - -int GetTexFilter(const tex1Info& tex1) -{ - // always force - if( conf.bilinear == 2 ) - return 1; - - int texfilter = 0; - if( conf.bilinear && ptexBilinearBlocks != 0 ) { - if( tex1.mmin <= 1 ) - texfilter = tex1.mmin|tex1.mmag; - else - texfilter = tex1.mmag ? ((tex1.mmin+2)&5) : tex1.mmin; - - texfilter = texfilter == 1 || texfilter == 4 || texfilter == 5; - } - return texfilter; -} - -void ZeroGS::ReloadEffects() -{ -#ifndef RELEASE_TO_PUBLIC - for(int i = 0; i < ARRAY_SIZE(ppsTexture); ++i) { - SAFE_RELEASE_PROG(ppsTexture[i].prog); - } - memset(ppsTexture, 0, sizeof(ppsTexture)); - LoadExtraEffects(); -#endif -} - -static int s_ClutResolve = 0; -void ZeroGS::Flush(int context) -{ - GL_REPORT_ERRORD(); - assert( context >= 0 && context <= 1 ); - -#ifndef RELEASE_TO_PUBLIC - if( g_bUpdateEffect ) { - ReloadEffects(); - g_bUpdateEffect = 0; - } -#endif - - VB& curvb = vb[context]; - const pixTest curtest = curvb.test; - if( curvb.nCount == 0 || (curtest.zte && curtest.ztst == 0) || g_bIsLost ) { - curvb.nCount = 0; - return; - } - - if( s_RangeMngr.ranges.size() > 0 ) { - - // don't want infinite loop - u32 prevcount = curvb.nCount; - curvb.nCount = 0; - FlushTransferRanges(curvb.curprim.tme ? &curvb.tex0 : NULL); - - curvb.nCount = prevcount; - //if( curvb.nCount == 0 ) - // return; - } - - if( curvb.bNeedTexCheck ) { - curvb.FlushTexData(); - - if( curvb.nCount == 0 ) - return; - } - - DVProfileFunc _pf("Flush"); - - GL_REPORT_ERRORD(); - if( curvb.bNeedFrameCheck || curvb.bNeedZCheck ) { - curvb.CheckFrame(curvb.curprim.tme ? curvb.tex0.tbp0 : 0); - } - - if( curvb.prndr == NULL || curvb.pdepth == NULL ) { - WARN_LOG("Current render target NULL (ctx: %d)", context); - curvb.nCount = 0; - return; - } - -#if defined(PRIM_LOG) && defined(_DEBUG) - static const char* patst[8] = { "NEVER", "ALWAYS", "LESS", "LEQUAL", "EQUAL", "GEQUAL", "GREATER", "NOTEQUAL"}; - static const char* pztst[4] = { "NEVER", "ALWAYS", "GEQUAL", "GREATER" }; - static const char* pafail[4] = { "KEEP", "FB_ONLY", "ZB_ONLY", "RGB_ONLY" }; - PRIM_LOG("**Drawing ctx %d, num %d, fbp: 0x%x, zbp: 0x%x, fpsm: %d, zpsm: %d, fbw: %d\n", context, vb[context].nCount, curvb.prndr->fbp, curvb.zbuf.zbp, curvb.prndr->psm, curvb.zbuf.psm, curvb.prndr->fbw); - PRIM_LOG("prim: prim=%x iip=%x tme=%x fge=%x abe=%x aa1=%x fst=%x ctxt=%x fix=%x\n", - curvb.curprim.prim, curvb.curprim.iip, curvb.curprim.tme, curvb.curprim.fge, curvb.curprim.abe, curvb.curprim.aa1, curvb.curprim.fst, curvb.curprim.ctxt, curvb.curprim.fix); - PRIM_LOG("test: ate:%d, atst: %s, aref: %d, afail: %s, date: %d, datm: %d, zte: %d, ztst: %s, fba: %d\n", - curvb.test.ate, patst[curvb.test.atst], curvb.test.aref, pafail[curvb.test.afail], curvb.test.date, curvb.test.datm, curvb.test.zte, pztst[curvb.test.ztst], curvb.fba.fba); - PRIM_LOG("alpha: A%d B%d C%d D%d FIX:%d pabe: %d; aem: %d, ta0: %d, ta1: %d\n", curvb.alpha.a, curvb.alpha.b, curvb.alpha.c, curvb.alpha.d, curvb.alpha.fix, gs.pabe, gs.texa.aem, gs.texa.ta[0], gs.texa.ta[1]); - PRIM_LOG("tex0: tbp0=0x%x, tbw=%d, psm=0x%x, tw=%d, th=%d, tcc=%d, tfx=%d, cbp=0x%x, cpsm=0x%x, csm=%d, csa=%d, cld=%d\n", - curvb.tex0.tbp0, curvb.tex0.tbw, curvb.tex0.psm, curvb.tex0.tw, - curvb.tex0.th, curvb.tex0.tcc, curvb.tex0.tfx, curvb.tex0.cbp, - curvb.tex0.cpsm, curvb.tex0.csm, curvb.tex0.csa, curvb.tex0.cld); - PRIM_LOG("frame: %d\n\n", g_SaveFrameNum); -#endif - - GL_REPORT_ERRORD(); - CRenderTarget* ptextarg = NULL; - - if( curtest.date || gs.pabe ) - SetDestAlphaTest(); - - // set the correct pixel shaders - if( curvb.curprim.tme ) { - - // if texture is part of a previous target, use that instead - int tbw = curvb.tex0.tbw; - int tbp0 = curvb.tex0.tbp0; - int tpsm = curvb.tex0.psm; - - if( curvb.bNeedTexCheck ) { - // not yet initied, but still need to get correct target! (xeno3 ingame) - tbp0 = (curvb.uNextTex0Data[0] & 0x3fff); - tbw = ((curvb.uNextTex0Data[0] >> 14) & 0x3f) * 64; - tpsm = (curvb.uNextTex0Data[0] >> 20) & 0x3f; - } - ptextarg = s_RTs.GetTarg(tbp0, tbw); - - if( (tpsm&0x30)==0x30 && ptextarg == NULL ) { - // try depth - ptextarg = s_DepthRTs.GetTarg(tbp0, tbw); - } - - if( ptextarg == NULL && (g_GameSettings&GAME_TEXTURETARGS) ) { - // check if any part of the texture intersects the current target - if( !PSMT_ISCLUT(tpsm) && curvb.tex0.tbp0 >= curvb.frame.fbp && (curvb.tex0.tbp0 << 8) < curvb.prndr->end) { - ptextarg = curvb.prndr; - } - } - - if( ptextarg != NULL && !(ptextarg->status&CRenderTarget::TS_NeedUpdate) ) { - if( PSMT_ISCLUT(tpsm) && tpsm != PSMT8H ) { // handle 8h cluts - // don't support clut targets, read from mem - // 4hl - kh2 check - from dx version -- arcum42 - if( tpsm != PSMT4HL && tpsm != PSMT4HH && s_ClutResolve <= 1 ) - { // xenosaga requires 2 resolves - u32 prevcount = curvb.nCount; - curvb.nCount = 0; - ptextarg->Resolve(); - s_ClutResolve++; - curvb.nCount = prevcount; - } - ptextarg = NULL; - } - else { - if( ptextarg == curvb.prndr ) { - // need feedback - curvb.prndr->CreateFeedback(); - - if(s_bWriteDepth && curvb.pdepth != NULL) - curvb.pdepth->SetRenderTarget(1); - else - ResetRenderTarget(1); - } - } - } - else ptextarg = NULL; - } - -#ifdef _DEBUG - if( g_bSaveFlushedFrame & 0x80000000 ) { - char str[255]; - sprintf(str, "rndr.tga", g_SaveFrameNum); - SaveRenderTarget(str, curvb.prndr->fbw, curvb.prndr->fbh, 0); - } -#endif - - if( conf.options & GSOPTION_WIREFRAME ) { - // always render first few geometry as solid - if( s_nWireframeCount > 0 ) { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - } - - if( !curvb.bVarsSetTarg ) - SetContextTarget(context); - else { - assert( curvb.pdepth != NULL ); - - if( curvb.pdepth->status & CRenderTarget::TS_Virtual) { - - if( !curvb.zbuf.zmsk ) { - CRenderTarget* ptemp = s_DepthRTs.Promote(curvb.pdepth->fbp|(curvb.pdepth->fbw<<16)); - assert( ptemp == curvb.pdepth ); - } - else - curvb.pdepth->status &= ~CRenderTarget::TS_NeedUpdate; - } - - if( (curvb.pdepth->status & CRenderTarget::TS_NeedUpdate) || (curvb.prndr->status & CRenderTarget::TS_NeedUpdate) ) - SetContextTarget(context); - } - - icurctx = context; - - DVProfileFunc _pf5("Flush:after texvars"); - - glBindBuffer(GL_ARRAY_BUFFER, g_vboBuffers[g_nCurVBOIndex]); - g_nCurVBOIndex = (g_nCurVBOIndex+1)%g_vboBuffers.size(); - glBufferData(GL_ARRAY_BUFFER, curvb.nCount * sizeof(VertexGPU), curvb.pBufferData, GL_STREAM_DRAW); -// void* pdata = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); -// memcpy_amd(pdata, curvb.pBufferData, curvb.nCount * sizeof(VertexGPU)); -// glUnmapBuffer(GL_ARRAY_BUFFER); - SET_STREAM(); - - assert( !(curvb.prndr->status&CRenderTarget::TS_NeedUpdate) ); - curvb.prndr->status = 0; - - if( curvb.pdepth != NULL ) { - assert( !(curvb.pdepth->status&CRenderTarget::TS_NeedUpdate) ); - if( !curvb.zbuf.zmsk ) { - assert( !(curvb.pdepth->status & CRenderTarget::TS_Virtual) ); - curvb.pdepth->status = 0; - } - } - -#ifdef _DEBUG - //curvb.prndr->SetRenderTarget(0); - //curvb.pdepth->SetDepthStencilSurface(); - //glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_NV, 0, 0 ); - GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); -#endif - s_dwColorWrite = (curvb.prndr->psm&0xf) == 1 ? (COLORMASK_BLUE|COLORMASK_GREEN|COLORMASK_RED) : 0xf; - - if( ((curvb.frame.fbm)&0xff) == 0xff) s_dwColorWrite &= ~COLORMASK_RED; - if( ((curvb.frame.fbm>>8)&0xff) == 0xff) s_dwColorWrite &= ~COLORMASK_GREEN; - if( ((curvb.frame.fbm>>16)&0xff) == 0xff) s_dwColorWrite &= ~COLORMASK_BLUE; - if( ((curvb.frame.fbm>>24)&0xff) == 0xff) s_dwColorWrite &= ~COLORMASK_ALPHA; - - GL_COLORMASK(s_dwColorWrite); - - Rect& scissor = curvb.prndr->scissorrect; - glScissor(scissor.x, scissor.y, scissor.w, scissor.h); - - u32 dwUsingSpecialTesting = 0; - u32 dwFilterOpts = 0; - - FRAGMENTSHADER* pfragment = NULL; - - // need exact if equal or notequal - int exactcolor = 0; - if( !(g_nPixelShaderVer&SHADER_REDUCED) ) - // ffx2 breaks when ==7 - exactcolor = (curtest.ate && curtest.aref <= 128) && (curtest.atst==4);//||curtest.atst==7); - - int shadertype = 0; - - // set the correct pixel shaders - u32 ptexclut = 0; - if( curvb.curprim.tme ) { - - if( ptextarg != NULL ) { - - if( ptextarg->IsDepth() ) - SetWriteDepth(); - - Vector vpageoffset; - vpageoffset.w = 0; - - int psm = curvb.tex0.psm; - if( PSMT_ISCLUT(curvb.tex0.psm) ) psm = curvb.tex0.cpsm; - - shadertype = 1; - if( curvb.tex0.psm == PSMT8H && !(g_GameSettings&GAME_NOTARGETCLUT) ) { - // load the clut to memory - glGenTextures(1, &ptexclut); - glBindTexture(GL_TEXTURE_2D, ptexclut); - vector data((curvb.tex0.cpsm&2) ? 512 : 1024); - - if( ptexclut != 0 ) { - - // fill the buffer by decoding the clut - int nClutOffset = 0, clutsize; - int entries = (curvb.tex0.psm&3)==3 ? 256 : 16; - if( curvb.tex0.cpsm <= 1 ) { // 32 bit - nClutOffset = 64 * curvb.tex0.csa; - clutsize = min(entries, 256-curvb.tex0.csa*16)*4; - } - else { - nClutOffset = 64 * (curvb.tex0.csa&15) + (curvb.tex0.csa>=16?2:0); - clutsize = min(entries, 512-curvb.tex0.csa*16)*2; - } - - if( curvb.tex0.cpsm <= 1 ) { // 32 bit - memcpy_amd(&data[0], g_pbyGSClut+nClutOffset, clutsize); - } - else { - u16* pClutBuffer = (u16*)(g_pbyGSClut + nClutOffset); - u16* pclut = (u16*)&data[0]; - int left = ((u32)nClutOffset & 2) ? 0 : ((nClutOffset&0x3ff)/2)+clutsize-512; - if( left > 0 ) clutsize -= left; - - while(clutsize > 0) { - pclut[0] = pClutBuffer[0]; - pclut++; - pClutBuffer+=2; - clutsize -= 2; - } - - if( left > 0) { - pClutBuffer = (u16*)(g_pbyGSClut + 2); - while(left > 0) { - pclut[0] = pClutBuffer[0]; - left -= 2; - pClutBuffer += 2; - pclut++; - } - } - } - - glTexImage2D(GL_TEXTURE_2D, 0, 4, 256, 1, 0, GL_RGBA, (curvb.tex0.cpsm&2)?GL_UNSIGNED_SHORT_5_5_5_1:GL_UNSIGNED_BYTE, &data[0]); - s_vecTempTextures.push_back(ptexclut); - - if( g_bSaveTex ) - SaveTexture("clut.tga", GL_TEXTURE_2D, ptexclut, 256, 1); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - - if( !(g_nPixelShaderVer&SHADER_REDUCED) && (ptextarg->psm & 2) ) { - shadertype = 4; - } - else - shadertype = 2; - } - else { - if( PSMT_ISCLUT(curvb.tex0.psm) ) - WARN_LOG("Using render target with CLUTs %d!\n", curvb.tex0.psm); - else { - if( (curvb.tex0.psm&2) != (ptextarg->psm&2) && (!(g_nPixelShaderVer&SHADER_REDUCED) || !curvb.curprim.fge) ) { - if( curvb.tex0.psm & 2 ) { - // converting from 32->16 - shadertype = 3; - } - else { - // converting from 16->32 - WARN_LOG("ZeroGS: converting from 16 to 32bit RTs\n"); - //shadetype = 4; - } - } - } - } - - pfragment = LoadShadeEffect(shadertype, 0, curvb.curprim.fge, curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), - exactcolor, curvb.clamp, context, NULL); - - if( shadertype == 3 ) { - Vector v; - v.x = 16.0f / (float)curvb.tex0.tw; - v.y = 16.0f / (float)curvb.tex0.th; - v.z = 0.5f * v.x; - v.w = 0.5f * v.y; - cgGLSetParameter4fv(pfragment->fTexOffset, v); - - vpageoffset.x = -0.1f / 256.0f; - vpageoffset.y = -0.001f / 256.0f; - vpageoffset.z = -0.1f / ptextarg->fbh; - vpageoffset.w = ((ptextarg->psm&0x30)==0x30)?-1.0f:0.0f; - } - else if( shadertype == 4 ) { - Vector v; - v.x = 16.0f / (float)ptextarg->fbw; - v.y = 16.0f / (float)ptextarg->fbh; - v.z = -1; - v.w = 8.0f / (float)ptextarg->fbh; - cgGLSetParameter4fv(pfragment->fTexOffset, v); - - vpageoffset.x = 2; - vpageoffset.y = 1; - vpageoffset.z = 0; - vpageoffset.w = 0.0001f; - } - - u32 ptexset = ptextarg == curvb.prndr ? ptextarg->ptexFeedback : ptextarg->ptex; - s_ptexCurSet[context] = ptexset; - - if( !curvb.tex1.mmag ) { - glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexset); - glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - dwFilterOpts |= 1; - } - - if( !curvb.tex1.mmin ) { - if( curvb.tex1.mmag ) - glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexset); - glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - dwFilterOpts |= 2; - } - - Vector vTexDims; - vTexDims.x = curvb.tex0.tw; - vTexDims.y = curvb.tex0.th; - - // look at the offset of tbp0 from fbp - if( curvb.tex0.tbp0 <= ptextarg->fbp ) { - vTexDims.z = 0;//-0.5f/(float)ptextarg->fbw; - vTexDims.w = 0;//0.2f/(float)ptextarg->fbh; - } - else { - u32 tbp0 = curvb.tex0.tbp0 >> 5; // align to a page - int blockheight = (ptextarg->psm&2) ? 64 : 32; - int ycoord = ((curvb.tex0.tbp0-ptextarg->fbp)/(32*(ptextarg->fbw>>6))) * blockheight; - int xcoord = (((curvb.tex0.tbp0-ptextarg->fbp)%(32*(ptextarg->fbw>>6)))) * 2; - vTexDims.z = (float)xcoord; - vTexDims.w = (float)ycoord; - } - - if( shadertype == 4 ) { - vTexDims.z += 8.0f; - } - - cgGLSetParameter4fv(pfragment->fTexDims, vTexDims); - - // zoe2 - if( (ptextarg->psm&0x30) == 0x30 ) {//&& (psm&2) == (ptextarg->psm&2) ) { - // target of zbuf has +1 added to it, don't do 16bit - vpageoffset.w = -1; -// Vector valpha2; -// valpha2.x = 1; valpha2.y = 0; -// valpha2.z = -1; valpha2.w = 0; -// SETCONSTF(GPU_TEXALPHA20+context, &valpha2); - } - cgGLSetParameter4fv(pfragment->fPageOffset, vpageoffset); - - if( g_bSaveTex ) - SaveTexture("tex.tga", GL_TEXTURE_RECTANGLE_NV, - ptextarg == curvb.prndr ? ptextarg->ptexFeedback : ptextarg->ptex, ptextarg->fbw<fbh<ValidateClut(curvb.tex0) ); -#endif - -//#ifdef ZEROGS_CACHEDCLEAR -// if( !curvb.pmemtarg->ValidateTex(curvb.tex0, true) ) { -// CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 1); -// SetTexVariablesInt(context, GetTexFilter(curvb.tex1), curvb.tex0, pmemtarg, s_bForceTexFlush); -// vb[context].bVarsTexSync = TRUE; -// } -//#endif - - if( g_bSaveTex ) { - if( g_bSaveTex == 1 ) { - SaveTex(&curvb.tex0, 1); -// CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 0); -// int texheight = (pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult; -// int texwidth = GPU_TEXWIDTH*pmemtarg->widthmult*pmemtarg->channels; -// SaveTexture("real.tga", GL_TEXTURE_RECTANGLE_NV, pmemtarg->ptex->tex, texwidth, texheight); - } - else SaveTex(&curvb.tex0, 0); - } - - int psm = curvb.tex0.psm; - if( PSMT_ISCLUT(curvb.tex0.psm) ) psm = curvb.tex0.cpsm; - - pfragment = LoadShadeEffect(0, GetTexFilter(curvb.tex1), curvb.curprim.fge, - curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), - exactcolor, curvb.clamp, context, NULL); - } - - if( pfragment->prog != g_psprog ) { - // programs changed, so reset the texture variables - vb[context].bTexConstsSync = 0; - vb[context].bVarsTexSync = 0; - } - - SetTexVariables(context, pfragment, ptextarg == NULL); - } - else { - pfragment = &ppsRegular[curvb.curprim.fge+2*s_bWriteDepth]; - } - - assert(pfragment != 0 ); - if( curvb.curprim.tme ) { - // have to enable the texture parameters - if( curvb.ptexClamp[0] != 0 ) { - cgGLSetTextureParameter(pfragment->sBitwiseANDX, curvb.ptexClamp[0]); - cgGLEnableTextureParameter(pfragment->sBitwiseANDX); - } - if( curvb.ptexClamp[1] != 0 ) { - cgGLSetTextureParameter(pfragment->sBitwiseANDY, curvb.ptexClamp[1]); - cgGLEnableTextureParameter(pfragment->sBitwiseANDY); - } - if( pfragment->sMemory != NULL && s_ptexCurSet[context] != 0) { - cgGLSetTextureParameter(pfragment->sMemory, s_ptexCurSet[context]); - cgGLEnableTextureParameter(pfragment->sMemory); - } - if( pfragment->sCLUT != NULL && ptexclut != 0 ) { - cgGLSetTextureParameter(pfragment->sCLUT, ptexclut); - cgGLEnableTextureParameter(pfragment->sCLUT); - } - } - - DVProfileFunc _pf4("Flush:before bind"); - GL_REPORT_ERRORD(); - - // set the shaders - SETVERTEXSHADER(pvs[2*((curvb.curprim._val>>1)&3)+8*s_bWriteDepth+context]); - - if( pfragment->prog != g_psprog ) { - cgGLBindProgram(pfragment->prog); - g_psprog = pfragment->prog; - } - - GL_REPORT_ERRORD(); - - DVProfileFunc _pf1("Flush:after bind"); - - BOOL bCanRenderStencil = g_bUpdateStencil && (curvb.prndr->psm&0xf) != 1 && !(curvb.frame.fbm&0x80000000); - if( g_GameSettings & GAME_NOSTENCIL ) - bCanRenderStencil = 0; - - if( s_bDestAlphaTest && bCanRenderStencil) { - glEnable(GL_STENCIL_TEST); - GL_STENCILFUNC(GL_ALWAYS, 0, 0); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - } - else glDisable(GL_STENCIL_TEST); - - glDepthMask(!curvb.zbuf.zmsk); - GL_ZTEST(curtest.zte); - if( curtest.zte ) { - if( curtest.ztst > 1 ) g_nDepthUsed = 2; - if( (curtest.ztst == 2) ^ (g_nDepthBias != 0) ) { - g_nDepthBias = curtest.ztst == 2; - //SETRS(D3DRS_DEPTHBIAS, g_nDepthBias?FtoDW(0.0003f):FtoDW(0.000015f)); - } - - glDepthFunc(g_dwZCmp[curtest.ztst]); - -// if( curtest.ztst == 3 ) { -// // gequal -// if( s_vznorm.y == 0 ) { -// s_vznorm.y = 0.00001f; -// SETCONSTF(GPU_ZNORM, s_vznorm); -// } -// } -// else { -// if( s_vznorm.y > 0 ) { -// s_vznorm.y = 0; -// SETCONSTF(GPU_ZNORM, s_vznorm); -// } -// } - } - - GL_ALPHATEST(curtest.ate&&USEALPHATESTING); - if( curtest.ate ) { - glAlphaFunc(g_dwAlphaCmp[curtest.atst], b2XAlphaTest ? min(1.0f,(float)curtest.aref * (1/ 127.5f)) : curtest.aref*(1/255.0f)); - } - - if( s_bWriteDepth ) { - if(!curvb.zbuf.zmsk) - curvb.pdepth->SetRenderTarget(1); - else - ResetRenderTarget(1); - } - - if( curvb.curprim.abe ) - SetAlphaVariables(curvb.alpha); - else - glDisable(GL_BLEND); - - // needs to be before RenderAlphaTest - if( curvb.fba.fba || s_bDestAlphaTest ) { - if( gs.pabe || (curvb.fba.fba || bCanRenderStencil) && !(curvb.frame.fbm&0x80000000) ) { - RenderFBA(curvb, pfragment->sOneColor); - } - } - - u32 oldabe = curvb.curprim.abe; - if( gs.pabe ) { - //WARN_LOG("PBE!\n"); - curvb.curprim.abe = 1; - glEnable(GL_BLEND); - } - - if( curvb.curprim.abe ) { - - if( //bCanRenderStencil && - (bNeedBlendFactorInAlpha || ((curtest.ate && curtest.atst>1) && (curtest.aref > 0x80))) ) { - // need special stencil processing for the alpha - RenderAlphaTest(curvb, pfragment->sOneColor); - dwUsingSpecialTesting = 1; - } - - // harvest fishing - Vector v = vAlphaBlendColor;// + Vector(0,0,0,(curvb.test.atst==4 && curvb.test.aref>=128)?-0.004f:0); - if( exactcolor ) { v.y *= 255; v.w *= 255; } - cgGLSetParameter4fv(pfragment->sOneColor, v); - } - else { - // not using blending so set to defaults - Vector v = exactcolor ? Vector(1, 510*255.0f/256.0f, 0, 0) : Vector(1,2*255.0f/256.0f,0,0); - cgGLSetParameter4fv(pfragment->sOneColor, v); - } - - if( s_bDestAlphaTest && bCanRenderStencil ) { - // if not 24bit and can write to high alpha bit - RenderStencil(curvb, dwUsingSpecialTesting); - } - else { - s_stencilref = STENCIL_SPECIAL; - s_stencilmask = STENCIL_SPECIAL; - - // setup the stencil to only accept the test pixels - if( dwUsingSpecialTesting ) { - glEnable(GL_STENCIL_TEST); - glStencilMask(STENCIL_PIXELWRITE); - GL_STENCILFUNC(GL_EQUAL, STENCIL_SPECIAL|STENCIL_PIXELWRITE, STENCIL_SPECIAL); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - } - } - -#ifdef _DEBUG - if( bDestAlphaColor == 1 ) { - WARN_LOG("dest alpha blending! manipulate alpha here\n"); - } -#endif - - if( bCanRenderStencil && gs.pabe ) { - // only render the pixels with alpha values >= 0x80 - GL_STENCILFUNC(GL_EQUAL, s_stencilref|STENCIL_FBA, s_stencilmask|STENCIL_FBA); - } - -// curvb.prndr->SetViewport(); -// pd3dDevice->SetScissorRect(&curvb.prndr->scissorrect); -// glEnable(GL_SCISSOR_TEST); - - GL_REPORT_ERRORD(); - if( !curvb.test.ate || curvb.test.atst > 0 ) { - DRAW(); - } - GL_REPORT_ERRORD(); - - if( gs.pabe ) { - // only render the pixels with alpha values < 0x80 - glDisable(GL_BLEND); - GL_STENCILFUNC_SET(); - - Vector v; - v.x = 1; v.y = 2; v.z = 0; v.w = 0; - if( exactcolor ) v.y *= 255; - cgGLSetParameter4fv(pfragment->sOneColor, v); - - DRAW(); - - // reset - if( !s_stencilmask ) s_stencilfunc = GL_ALWAYS; - GL_STENCILFUNC_SET(); - } - - GL_REPORT_ERRORD(); - - // more work on alpha failure case - if( curtest.ate && curtest.atst != 1 && curtest.afail > 0 ) { - - // need to reverse the test and disable some targets - glAlphaFunc(g_dwReverseAlphaCmp[curtest.atst], b2XAlphaTest ? min(1.0f,(float)curtest.aref * (1/ 127.5f)) : curtest.aref*(1/255.0f)); - - if( curtest.afail & 1 ) { // front buffer update only - - if( curtest.afail == 3 ) // disable alpha - glColorMask(1,1,1,0); - - glDepthMask(0); - - if( s_bWriteDepth ) - ResetRenderTarget(1); - } - else { - // zbuffer update only - glColorMask(0,0,0,0); - } - - if( gs.pabe && bCanRenderStencil ) { - // only render the pixels with alpha values >= 0x80 - Vector v = vAlphaBlendColor; - if( exactcolor ) { v.y *= 255; v.w *= 255; } - cgGLSetParameter4fv(pfragment->sOneColor, v); - glEnable(GL_BLEND); - GL_STENCILFUNC(GL_EQUAL, s_stencilref|STENCIL_FBA, s_stencilmask|STENCIL_FBA); - } - -// IDirect3DQuery9* pOcclusionQuery; -// u32 numberOfPixelsDrawn; -// -// pd3dDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &pOcclusionQuery); -// -// // Add an end marker to the command buffer queue. -// pOcclusionQuery->Issue(D3DISSUE_BEGIN); - - DRAW(); - GL_REPORT_ERRORD(); - -// pOcclusionQuery->Issue(D3DISSUE_END); - // Force the driver to execute the commands from the command buffer. - // Empty the command buffer and wait until the GPU is idle. -// while(S_FALSE == pOcclusionQuery->GetData( &numberOfPixelsDrawn, sizeof(u32), D3DGETDATA_FLUSH )); -// SAFE_RELEASE(pOcclusionQuery); - - if( gs.pabe ) { - // only render the pixels with alpha values < 0x80 - glDisable(GL_BLEND); - GL_STENCILFUNC_SET(); - - Vector v; - v.x = 1; v.y = 2; v.z = 0; v.w = 0; - if( exactcolor ) v.y *= 255; - cgGLSetParameter4fv(pfragment->sOneColor, v); - - DRAW(); - - // reset - if( oldabe ) glEnable(GL_BLEND); - - if( !s_stencilmask ) s_stencilfunc = GL_ALWAYS; - GL_STENCILFUNC_SET(); - } - - // restore - - if( (curtest.afail & 1) && !curvb.zbuf.zmsk ) { - glDepthMask(1); - - if( s_bWriteDepth ) { - assert( curvb.pdepth != NULL); - curvb.pdepth->SetRenderTarget(1); - } - } - - GL_COLORMASK(s_dwColorWrite); - - // not needed anymore since rest of ops concentrate on image processing - } - - GL_REPORT_ERRORD(); - - if( dwUsingSpecialTesting ) { - // render the real alpha - glDisable(GL_ALPHA_TEST); - glColorMask(0,0,0,1); - - if( s_bWriteDepth ) { - ResetRenderTarget(1); - } - - glDepthMask(0); - - glStencilFunc(GL_EQUAL, STENCIL_SPECIAL|STENCIL_PIXELWRITE, STENCIL_SPECIAL|STENCIL_PIXELWRITE); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - - Vector v = Vector(0,exactcolor ? 510.0f : 2.0f,0,0); - cgGLSetParameter4fv(pfragment->sOneColor, v); - DRAW(); - - // don't need to restore - } - - GL_REPORT_ERRORD(); - - if( s_bDestAlphaTest ) { - if( (s_dwColorWrite&COLORMASK_ALPHA) ) { - if( curvb.fba.fba ) - ProcessFBA(curvb, pfragment->sOneColor); - else if( bCanRenderStencil ) - // finally make sure all entries are 1 when the dest alpha >= 0x80 (if fba is 1, this is already the case) - ProcessStencil(curvb); - } - } - else if( (s_dwColorWrite&COLORMASK_ALPHA) && curvb.fba.fba ) - ProcessFBA(curvb, pfragment->sOneColor); - - if( bDestAlphaColor == 1 ) { - // need to reset the dest colors to their original counter parts - //WARN_LOG("Need to reset dest alpha color\n"); - } - -#ifdef _DEBUG - if( g_bSaveFlushedFrame & 0xf ) { -#ifdef _WIN32 - CreateDirectory("frames", NULL); -#else - mkdir("frames", 0755); -#endif - char str[255]; - sprintf(str, "frames/frame%.4d.tga", g_SaveFrameNum++); - if( (g_bSaveFlushedFrame & 2) ) { - //glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch to the backbuffer - //glFlush(); - //SaveTexture("tex.jpg", GL_TEXTURE_RECTANGLE_NV, curvb.prndr->ptex, curvb.prndr->fbw<fbh<fbw<fbh<SetRenderTarget(1); - } - } - - if( curvb.test.ate && USEALPHATESTING ) - glEnable(GL_ALPHA_TEST); - - GL_ZTEST(curtest.zte); - } - - if( dwFilterOpts ) { - // undo filter changes (binding didn't change) - if( dwFilterOpts & 1 ) glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - if( dwFilterOpts & 2 ) glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - -//#ifndef RELEASE_TO_PUBLIC - ppf += curvb.nCount+0x100000; -//#endif - - curvb.nCount = 0; - curvb.curprim.abe = oldabe; - //if( oldabe ) glEnable(GL_BLEND); - - if( conf.options & GSOPTION_WIREFRAME ) { - // always render first few geometry as solid - if( s_nWireframeCount > 0 ) { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - --s_nWireframeCount; - } - } - - GL_REPORT_ERRORD(); -} - -void ZeroGS::ProcessMessages() -{ - if( listMsgs.size() > 0 ) { - int left = 25, top = 15; - list::iterator it = listMsgs.begin(); - - while( it != listMsgs.end() ) { - DrawText(it->str, left+1, top+1, 0xff000000); - DrawText(it->str, left, top, 0xffffff30); - top += 15; - - if( (int)(it->dwTimeStamp - timeGetTime()) < 0 ) - it = listMsgs.erase(it); - else ++it; - } - } -} - -void ZeroGS::RenderCustom(float fAlpha) -{ - GLenum err = GL_NO_ERROR; - - GL_REPORT_ERROR(); - - fAlpha = 1; - glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch to the backbuffer - - glDisable(GL_STENCIL_TEST); - glDisable(GL_DEPTH_TEST); - glDepthMask(0); - glColorMask(1,1,1,1); - glDisable(GL_BLEND); - glDisable(GL_ALPHA_TEST); - glDisable(GL_SCISSOR_TEST); - glViewport(0, 0, nBackbufferWidth, nBackbufferHeight); - - // play custom animation - glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); - - // tex coords - Vector v = Vector(1/32767.0f, 1/32767.0f, 0, 0); - cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); - v.x = (float)nLogoWidth; - v.y = (float)nLogoHeight; - cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); - - v.x = v.y = v.z = v.w = fAlpha; - cgGLSetParameter4fv(ppsBaseTexture.sOneColor, v); - - if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - // inside vb[0]'s target area, so render that region only - cgGLSetTextureParameter(ppsBaseTexture.sFinal, ptexLogo); - cgGLEnableTextureParameter(ppsBaseTexture.sFinal); - - glBindBuffer(GL_ARRAY_BUFFER, vboRect); - SET_STREAM(); - - SETVERTEXSHADER(pvsBitBlt.prog); - SETPIXELSHADER(ppsBaseTexture.prog); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - // restore - if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - ProcessMessages(); - -#ifdef _WIN32 - SwapBuffers(hDC); -#else - glXSwapBuffers(GLWin.dpy, GLWin.win); -#endif - - glEnable(GL_SCISSOR_TEST); - glEnable(GL_STENCIL_TEST); - - vb[0].bSyncVars = 0; - vb[1].bSyncVars = 0; - - GL_REPORT_ERROR(); - GLint status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - assert( status == GL_FRAMEBUFFER_COMPLETE_EXT || status == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT ); -} - -// adjusts trans to preserve aspect ratio -void ZeroGS::AdjustTransToAspect(Vector& v, int dispwidth, int dispheight) -{ - double temp; - float f; - if( dispwidth * nBackbufferHeight > dispheight * nBackbufferWidth) { - // limited by width - - // change in ratio - f = ((float)nBackbufferWidth / (float)dispwidth) / ((float)nBackbufferHeight / (float)dispheight); - v.y *= f; - v.w *= f; - - // scanlines mess up when not aligned right - v.y += (1-(float)modf(v.y*(float)nBackbufferHeight*0.5f+0.05f, &temp))*2.0f/(float)nBackbufferHeight; - v.w += (1-(float)modf(v.w*(float)nBackbufferHeight*0.5f+0.05f, &temp))*2.0f/(float)nBackbufferHeight; - } - else { - // limited by height - f = ((float)nBackbufferHeight / (float)dispheight) / ((float)nBackbufferWidth / (float)dispwidth); - f -= (float)modf(f*nBackbufferWidth, &temp)/(float)nBackbufferWidth; - v.x *= f; - v.z *= f; - } - -// v.y *= -1; -// v.w *= -1; - v *= 1/32767.0f; -} - -void ZeroGS::Restore() -{ - if( !g_bIsLost ) - return; - - //if( SUCCEEDED(pd3dDevice->Reset(&d3dpp)) ) { - g_bIsLost = 0; - // handle lost states - ZeroGS::ChangeDeviceSize(nBackbufferWidth, nBackbufferHeight); - //} -} - -void ZeroGS::RenderCRTC(int interlace) -{ - if( g_bIsLost ) return; - -// Crashes Final Fantasy X at startup if uncommented. --arcum42 -//#ifdef RELEASE_TO_PUBLIC -// if(g_nRealFrame < 80 ) { -// RenderCustom( min(1.0f, 2.0f - (float)g_nRealFrame / 40.0f) ); -// -// if( g_nRealFrame == 79 ) -// SAFE_RELEASE_TEX(ptexLogo); -// return; -// } -//#endif - - if( conf.mrtdepth && pvs[8] == NULL ) { - conf.mrtdepth = 0; - s_bWriteDepth = FALSE; - ERROR_LOG("Disabling MRT depth writing\n"); - } - - Flush(0); - Flush(1); - GL_REPORT_ERRORD(); - - DVProfileFunc _pf("RenderCRTC"); - - // frame skipping - if( g_nFrameRender > 0 ) { - - if( g_nFrameRender < 8 ) { - g_nFrameRender++; - if( g_nFrameRender <= 3 ) { - g_nFramesSkipped++; - return; - } - } - } - else { - if( g_nFrameRender < -1 ) { - g_nFramesSkipped++; - return; - } - g_nFrameRender--; - } - - if( g_bSaveFrame ) { - if( vb[0].prndr != NULL ) { - SaveTexture("frame1.tga", GL_TEXTURE_RECTANGLE_NV, vb[0].prndr->ptex, vb[0].prndr->fbw<fbh<ptex, vb[1].prndr->fbw<fbh< 0 ) - FlushTransferRanges(NULL); - - //g_GameSettings |= GAME_VSSHACK|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE; - //s_bWriteDepth = TRUE; - g_SaveFrameNum = 0; - g_bSaveFlushedFrame = 1; - - // reset fba after every frame - vb[0].fba.fba = 0; - vb[1].fba.fba = 0; - -// static int counter = 0; -// counter++; - u32 bInterlace = SMODE2->INT && SMODE2->FFMD && (conf.interlace<2); - glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch to the backbuffer - glViewport(0, 0, nBackbufferWidth, nBackbufferHeight); - - // if interlace, only clear every other vsync - if(!bInterlace ) { - u32 color = COLOR_ARGB(0, BGCOLOR->R, BGCOLOR->G, BGCOLOR->B); - glClear(GL_COLOR_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); - } - - SETVERTEXSHADER(pvsBitBlt.prog); - glBindBuffer(GL_ARRAY_BUFFER, vboRect); - SET_STREAM(); - GL_REPORT_ERRORD(); - - if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glDisable(GL_DEPTH_TEST); - glDepthMask(0); - glColorMask(1,1,1,1); - glDisable(GL_BLEND); - glDisable(GL_ALPHA_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_STENCIL_TEST); - - GL_REPORT_ERRORD(); - - BOOL bUsingStencil = 0; - - if( bInterlace ) g_PrevBitwiseTexX = -1; // reset since will be using - - tex0Info dispinfo[2]; - - for(int i = 0; i < 2; ++i) { - - if( !(*(u32*)(PMODE) & (1<MAGH+1; - int magv = pd->MAGV+1; - - dispinfo[i].tbp0 = pfb->FBP << 5; - dispinfo[i].tbw = pfb->FBW << 6; - dispinfo[i].tw = (pd->DW + 1) / magh; - dispinfo[i].th = (pd->DH + 1) / magv; - dispinfo[i].psm = pfb->PSM; - - // hack!! - // 2 * dispinfo[i].tw / dispinfo[i].th <= 1, metal slug 4 - if( bInterlace && 2 * dispinfo[i].tw / dispinfo[i].th <= 1 && !(g_GameSettings&GAME_INTERLACE2X) ) { - dispinfo[i].th >>= 1; - } - } - - //int dispwidth = max(dispinfo[0].tw, dispinfo[1].tw), dispheight = max(dispinfo[0].th, dispinfo[1].th); - - // hack!, CMOD != 3, gradius -// if( SMODE2->INT && SMODE2->FFMD && SMODE1->CMOD == 3 && dispwidth <= 320) -// dispwidth *= 2; - - // hack! makai - //if( !bInterlace && dispheight * 2 < dispwidth ) dispheight *= 2; - - // start from the last circuit - for(int i = !PMODE->SLBG; i >= 0; --i) { - - tex0Info& texframe = dispinfo[i]; - if( texframe.th <= 1 ) - continue; - - GSRegDISPFB* pfb = i ? DISPFB2 : DISPFB1; - GSRegDISPLAY* pd = i ? DISPLAY2 : DISPLAY1; - - Vector v, valpha; - u32 interlacetex = 0; - - if( bInterlace ) { - - texframe.th >>= 1; - - // interlace mode - interlacetex = CreateInterlaceTex(2*texframe.th); - - if( interlace == (conf.interlace&1) ) { - // pass if odd - valpha.z = 1.0f; - valpha.w = -0.4999f; - } - else { - // pass if even - valpha.z = -1.0f; - valpha.w = 0.5001f; - } - } - else { - - if( SMODE2->INT && SMODE2->FFMD ) { - texframe.th >>= 1; - } - - // always pass interlace test - valpha.z = 0; - valpha.w = 1; - } - - int bpp = 4; - if( texframe.psm == 0x12 ) bpp = 3; - else if( texframe.psm & 2 ) bpp = 2; - - // get the start and end addresses of the buffer - int start, end; - GetRectMemAddress(start, end, texframe.psm, 0, 0, texframe.tw, texframe.th, texframe.tbp0, texframe.tbw); - - if( i == 0 ) { - // setup right blending - glEnable(GL_BLEND); - zgsBlendEquationSeparateEXT(GL_FUNC_ADD, GL_FUNC_ADD); - - if( PMODE->MMOD ) { - glBlendColorEXT(PMODE->ALP*(1/255.0f), PMODE->ALP*(1/255.0f), PMODE->ALP*(1/255.0f), 0.5f); - s_srcrgb = GL_CONSTANT_COLOR_EXT; - s_dstrgb = GL_ONE_MINUS_CONSTANT_COLOR_EXT; - } - else { - s_srcrgb = GL_SRC_ALPHA; - s_dstrgb = GL_ONE_MINUS_SRC_ALPHA; - } - - s_srcalpha = PMODE->AMOD ? GL_ZERO : GL_ONE; - s_dstalpha = PMODE->AMOD? GL_ONE : GL_ZERO; - zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha); - } - - if( bUsingStencil ) { - glStencilMask(1< listTargs; - - s_RTs.GetTargs(start, end, listTargs); - - for(list::iterator it = listTargs.begin(); it != listTargs.end(); ) { - - CRenderTarget* ptarg = *it; - - if( ptarg->fbw == texframe.tbw && !(ptarg->status&CRenderTarget::TS_NeedUpdate) && ((256/bpp)*(texframe.tbp0-ptarg->fbp))%texframe.tbw == 0 ) { - - if( ptarg->fbp != texframe.tbp0 ) { - // look for a better target (metal slug 5) - list::iterator itbetter; - for(itbetter = listTargs.begin(); itbetter != listTargs.end(); ++itbetter ) { - if( (*itbetter)->fbp == texframe.tbp0 ) - break; - } - - if( itbetter != listTargs.end() ) { - it = listTargs.erase(it); - continue; - } - } - - if( g_bSaveFinalFrame ) - SaveTexture("frame1.tga", GL_TEXTURE_RECTANGLE_NV, ptarg->ptex, ptarg->fbw<fbh<DBY; - int movy = 0; - - // determine the rectangle to render - if( ptarg->fbp < texframe.tbp0 ) { - dby += (256/bpp)*(texframe.tbp0-ptarg->fbp)/texframe.tbw; - } - else if( ptarg->fbp > texframe.tbp0 ) { - dby -= (256/bpp)*(ptarg->fbp-texframe.tbp0)/texframe.tbw; - - if( dby < 0 ) { - movy = -dby; - dby = 0; - } - } - - int dh = min(ptarg->fbh - dby, texframe.th-movy); - - if( dh >= 64 ) { - - if( ptarg->fbh - dby < texframe.th-movy && !bUsingStencil ) { - - if( !bUsingStencil ) { - glClear(GL_STENCIL_BUFFER_BIT); - } - bUsingStencil = 1; - glEnable(GL_STENCIL_TEST); - GL_STENCILFUNC(GL_NOTEQUAL, 3, 1<fbh; - - // tex coords - v = Vector((float)(texframe.tw << s_AAx), (float)(dh << s_AAy), (float)(pfb->DBX << s_AAx), (float)(dby< 0 ) - v.w -= movy/(float)texframe.th; - - if (bInterlace && interlace == (conf.interlace&1) ) { - // move down by 1 pixel - v.w += 1.0f / (float)dh; - } - - AdjustTransToAspect(v, 640, 480); - cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); - - cgGLSetParameter4fv(pvsBitBlt.fBitBltTrans, Vector(fih * 0.5f, fih * -0.5f, fih * 0.5f, fih * 0.5f)); - - // use g_fInvTexDims to store inverse texture dims - if( ppsCRTCTarg[bInterlace].sInvTexDims ) { - v.x = fiw; - v.y = fih; - v.z = 0; - cgGLSetParameter4fv(ppsCRTCTarg[bInterlace].sInvTexDims, v); - } - - cgGLSetParameter4fv(ppsCRTCTarg[bInterlace].sOneColor, valpha); - - // inside vb[0]'s target area, so render that region only - cgGLSetTextureParameter(ppsCRTCTarg[bInterlace].sFinal, ptarg->ptex); - cgGLEnableTextureParameter(ppsCRTCTarg[bInterlace].sFinal); - if( interlacetex != 0 ) { - cgGLSetTextureParameter(ppsCRTCTarg[bInterlace].sInterlace, interlacetex); - cgGLEnableTextureParameter(ppsCRTCTarg[bInterlace].sInterlace); - } - - SETPIXELSHADER(ppsCRTCTarg[bInterlace].prog); - GL_REPORT_ERRORD(); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - //SaveRenderTarget("temp.tga", nBackbufferWidth, nBackbufferHeight, 0); - - if( abs(dh - (int)texframe.th) <= 1 ) { - bSkip = 1; - break; - } - if( abs(dh - (int)ptarg->fbh) <= 1 ) { - it = listTargs.erase(it); - continue; - } - } - } - - ++it; - } - - if( !bSkip ) { - for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) - (*it)->Resolve(); - - // context has to be 0 - CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); - SetTexVariablesInt(0, g_bCRTCBilinear?2:0, texframe, pmemtarg, &ppsCRTC[bInterlace], 1); - cgGLSetTextureParameter(ppsCRTC[bInterlace].sMemory, pmemtarg->ptex->tex); - cgGLEnableTextureParameter(ppsCRTC[bInterlace].sMemory); - - if( g_bSaveFinalFrame ) - SaveTex(&texframe, g_bSaveFinalFrame-1>0); - - // finally render from the memory (note that the stencil buffer will keep previous regions) - v = Vector(1,1,0,0); - - if (bInterlace && interlace == (conf.interlace)) { - // move down by 1 pixel - v.w += 1.0f / (float)texframe.th; - } - - cgGLSetParameter4fv(ppsCRTC[bInterlace].sOneColor, valpha); - - AdjustTransToAspect(v, 640, 480); - cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); - - float fih = 1.0f / (float)texframe.th; - if( g_bCRTCBilinear ) - cgGLSetParameter4fv(pvsBitBlt.sBitBltTex, Vector(texframe.tw,texframe.th,-0.5f,-0.5f)); - else - cgGLSetParameter4fv(pvsBitBlt.sBitBltTex, Vector(1,1,-0.5f/(float)texframe.tw,-0.5f/(float)texframe.th)); - - cgGLSetParameter4fv(pvsBitBlt.fBitBltTrans, Vector(fih * 0.5f, fih * -0.5f, fih * 0.5f, fih * 0.5f)); - - // use g_fInvTexDims to store inverse texture dims - if( ppsCRTC[bInterlace].sInvTexDims ) { - v.x = 1.0f / (float)texframe.tw; - v.y = fih; - v.z = 0;//-0.5f * v.x; - v.w = -0.5f * fih; - cgGLSetParameter4fv(ppsCRTC[bInterlace].sInvTexDims, v); - } - - if( interlacetex != 0 ) { - cgGLSetTextureParameter(ppsCRTC[bInterlace].sInterlace, interlacetex); - cgGLEnableTextureParameter(ppsCRTC[bInterlace].sInterlace); - } - - SETPIXELSHADER(ppsCRTC[bInterlace].prog); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - } - } - - GL_REPORT_ERRORD(); - if(1) {// || !bInterlace) { - glDisable(GL_BLEND); - ProcessMessages(); - - if( g_bMakeSnapshot ) { - char str[64]; - int left = 200, top = 15; - sprintf(str, "ZeroGS %d.%d.%d - %.1f fps %s", zgsrevision, zgsbuild, zgsminor, fFPS, s_frameskipping?" - frameskipping":""); - - DrawText(str, left+1, top+1, 0xff000000); - DrawText(str, left, top, 0xffc0ffff); - } - - if( g_bDisplayFPS ) { - char str[64]; - int left = 10, top = 15; - sprintf(str, "%.1f fps", fFPS); - - DrawText(str, left+1, top+1, 0xff000000); - DrawText(str, left, top, 0xffc0ffff); - } - - if (glGetError() != GL_NO_ERROR) DEBUG_LOG("glerror before swap!\n"); - - -#ifdef _WIN32 - static u32 lastswaptime = 0; - //if( timeGetTime() - lastswaptime > 14 ) { - SwapBuffers(hDC); - lastswaptime = timeGetTime(); - //} -#else - glXSwapBuffers(GLWin.dpy, GLWin.win); -#endif - -// if( glGetError() != GL_NO_ERROR) { -// // device is lost, need to recreate -// ERROR_LOG("device lost\n"); -// g_bIsLost = TRUE; -// Reset(); -// return; -// } - - if( conf.options & GSOPTION_WIREFRAME ) { - // clear all targets - s_nWireframeCount = 1; - } - - if( g_bMakeSnapshot ) { - - if( SaveRenderTarget(strSnapshot != ""?strSnapshot.c_str():"temp.jpg", nBackbufferWidth, -nBackbufferHeight, 0)) {//(conf.options&GSOPTION_TGASNAP)?0:1) ) { - char str[255]; - sprintf(str, "saved %s\n", strSnapshot.c_str()); - AddMessage(str, 500); - } - - g_bMakeSnapshot = 0; - } - - if( s_avicapturing ) { - CaptureFrame(); - } - - if( s_nNewWidth >= 0 && s_nNewHeight >= 0 && !g_bIsLost ) { - Reset(); - ChangeDeviceSize(s_nNewWidth, s_nNewHeight); - s_nNewWidth = s_nNewHeight = -1; - } - - // switch the fbp lists -// s_nCurFBPSet ^= 1; -// s_setFBP[s_nCurFBPSet].clear(); - //s_nCurFrameMap ^= 1; - //s_mapFrameHeights[s_nCurFrameMap].clear(); - } - - // switch back to rendering to textures - glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, s_uFramebuffer ); - - g_MemTargs.DestroyCleared(); - - if( s_vecTempTextures.size() > 0 ) - glDeleteTextures((GLsizei)s_vecTempTextures.size(), &s_vecTempTextures[0]); - s_vecTempTextures.clear(); - - if( EXTWRITE->WRITE&1 ) { - WARN_LOG("EXTWRITE\n"); - ExtWrite(); - EXTWRITE->WRITE = 0; - } - - if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glEnable(GL_SCISSOR_TEST); - - if( icurctx >= 0 ) { - vb[icurctx].bVarsSetTarg = FALSE; - vb[icurctx].bVarsTexSync = FALSE; - vb[0].bVarsTexSync = FALSE; - } - - // statistics - if( s_nWriteDepthCount > 0 ) { - assert( conf.mrtdepth ); - if( --s_nWriteDepthCount <= 0 ) { - s_bWriteDepth = FALSE; - } - } - - if( s_nWriteDestAlphaTest > 0 ) { - if( --s_nWriteDestAlphaTest <= 0 ) { - s_bDestAlphaTest = FALSE; - } - } - - if( g_GameSettings & GAME_AUTORESET ) { - s_nResolveCounts[s_nCurResolveIndex] = s_nResolved; - s_nCurResolveIndex = (s_nCurResolveIndex+1)%ARRAY_SIZE(s_nResolveCounts); - - int total = 0; - for(int i = 0; i < ARRAY_SIZE(s_nResolveCounts); ++i) total += s_nResolveCounts[i]; - - if( total / ARRAY_SIZE(s_nResolveCounts) > 3 ) { - if( s_nLastResolveReset > (int)(fFPS * 8) ) { - // reset - ERROR_LOG("video mem reset\n"); - s_nLastResolveReset = 0; - memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); - - s_RTs.ResolveAll(); - s_RTs.Destroy(); - s_DepthRTs.ResolveAll(); - s_DepthRTs.Destroy(); - - vb[0].prndr = NULL; vb[0].pdepth = NULL; vb[0].bNeedFrameCheck = 1; vb[0].bNeedZCheck = 1; - vb[1].prndr = NULL; vb[1].pdepth = NULL; vb[1].bNeedFrameCheck = 1; vb[1].bNeedZCheck = 1; - } - } - - s_nLastResolveReset++; - } - - if( s_nResolved > 8 ) s_nResolved = 2; - else if( s_nResolved > 0 ) --s_nResolved; - - if( g_nDepthUsed > 0 ) --g_nDepthUsed; - - s_ClutResolve = 0; - g_nDepthUpdateCount = 0; - - maxmin = 608; -} - -////////////////////////// -// Internal Definitions // -////////////////////////// - - -__forceinline void MOVZ(VertexGPU *p, u32 gsz, const VB& curvb) -{ - p->z = curvb.zprimmask==0xffff?min((u32)0xffff, gsz):gsz; -} - -__forceinline void MOVFOG(VertexGPU *p, Vertex gsf) -{ - p->f = ((s16)(gsf).f<<7)|0x7f; -} - -__forceinline void SET_VERTEX(VertexGPU *p, int Index, const VB& curvb) -{ - int index = Index; - - p->x = (((int)gs.gsvertex[index].x - curvb.offset.x)>>1)&0xffff; - p->y = (((int)gs.gsvertex[index].y - curvb.offset.y)>>1)&0xffff; - - /*x = ((int)gs.gsvertex[index].x - curvb.offset.x); - y = ((int)gs.gsvertex[index].y - curvb.offset.y); - p.x = (x&0x7fff) | (x < 0 ? 0x8000 : 0); - p.y = (y&0x7fff) | (y < 0 ? 0x8000 : 0);*/ - - p->f = ((s16)gs.gsvertex[index].f<<7)|0x7f; - MOVZ(p, gs.gsvertex[index].z, curvb); - p->rgba = prim->iip ? gs.gsvertex[index].rgba : gs.rgba; - - if ((g_GameSettings & GAME_TEXAHACK) && !(p->rgba&0xffffff)) - p->rgba = 0; - if (prim->tme ) - { - if( prim->fst ) - { - p->s = (float)gs.gsvertex[index].u * fiTexWidth[prim->ctxt]; - p->t = (float)gs.gsvertex[index].v * fiTexHeight[prim->ctxt]; - p->q = 1; - } - else - { - p->s = gs.gsvertex[index].s; - p->t = gs.gsvertex[index].t; - p->q = gs.gsvertex[index].q; - } - } -} - -#define OUTPUT_VERT(fn, vert, id) { \ - fn("%c%d(%d): xyzf=(%4d,%4d,0x%x,%3d), rgba=0x%8.8x, stq = (%2.5f,%2.5f,%2.5f)\n", id==0?'*':' ', id, prim->prim, vert.x/8, vert.y/8, vert.z, vert.f/128, \ - vert.rgba, Clamp(vert.s, -10, 10), Clamp(vert.t, -10, 10), Clamp(vert.q, -10, 10)); \ -} \ - -void ZeroGS::KickPoint() -{ - assert( gs.primC >= 1 ); - - VB& curvb = vb[prim->ctxt]; - if (curvb.bNeedTexCheck) curvb.FlushTexData(); - - if ((vb[!prim->ctxt].nCount > 0) && (vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp)) - { - assert( vb[prim->ctxt].nCount == 0 ); - Flush(!prim->ctxt); - } - - curvb.NotifyWrite(1); - - int last = (gs.primIndex+2)%ARRAY_SIZE(gs.gsvertex); - - VertexGPU* p = curvb.pBufferData+curvb.nCount; - SET_VERTEX(&p[0], last, curvb); - curvb.nCount++; - -#ifdef PRIM_LOG - OUTPUT_VERT(PRIM_LOG, p[0], 0); -#endif -} - -void ZeroGS::KickLine() -{ - assert( gs.primC >= 2 ); - VB& curvb = vb[prim->ctxt]; - if( curvb.bNeedTexCheck ) - curvb.FlushTexData(); - - if( vb[!prim->ctxt].nCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) - { - assert( vb[prim->ctxt].nCount == 0 ); - Flush(!prim->ctxt); - } - - curvb.NotifyWrite(2); - - int next = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); - int last = (gs.primIndex+2)%ARRAY_SIZE(gs.gsvertex); - - VertexGPU* p = curvb.pBufferData+curvb.nCount; - SET_VERTEX(&p[0], next, curvb); - SET_VERTEX(&p[1], last, curvb); - - curvb.nCount += 2; - -#ifdef PRIM_LOG - OUTPUT_VERT(PRIM_LOG, p[0], 0); - OUTPUT_VERT(PRIM_LOG, p[1], 1); -#endif -} - -void ZeroGS::KickTriangle() -{ - assert( gs.primC >= 3 ); - VB& curvb = vb[prim->ctxt]; - if (curvb.bNeedTexCheck) curvb.FlushTexData(); - - if ((vb[!prim->ctxt].nCount > 0) && (vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp)) - { - assert( vb[prim->ctxt].nCount == 0 ); - Flush(!prim->ctxt); - } - - curvb.NotifyWrite(3); - - VertexGPU* p = curvb.pBufferData+curvb.nCount; - SET_VERTEX(&p[0], 0, curvb); - SET_VERTEX(&p[1], 1, curvb); - SET_VERTEX(&p[2], 2, curvb); - - curvb.nCount += 3; - -#ifdef PRIM_LOG - OUTPUT_VERT(PRIM_LOG, p[0], 0); - OUTPUT_VERT(PRIM_LOG, p[1], 1); - OUTPUT_VERT(PRIM_LOG, p[2], 2); -#endif -} - -void ZeroGS::KickTriangleFan() -{ - assert( gs.primC >= 3 ); - VB& curvb = vb[prim->ctxt]; - if (curvb.bNeedTexCheck) curvb.FlushTexData(); - - if ((vb[!prim->ctxt].nCount > 0) && (vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp)) - { - assert( vb[prim->ctxt].nCount == 0 ); - Flush(!prim->ctxt); - } - - curvb.NotifyWrite(3); - - VertexGPU* p = curvb.pBufferData+curvb.nCount; - SET_VERTEX(&p[0], 0, curvb); - SET_VERTEX(&p[1], 1, curvb); - SET_VERTEX(&p[2], 2, curvb); - - curvb.nCount += 3; - - // add 1 to skip the first vertex - if (gs.primIndex == gs.nTriFanVert) - gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); - -#ifdef PRIM_LOG - OUTPUT_VERT(PRIM_LOG, p[0], 0); - OUTPUT_VERT(PRIM_LOG, p[1], 1); - OUTPUT_VERT(PRIM_LOG, p[2], 2); -#endif -} - -__forceinline void SetKickVertex(VertexGPU *p, Vertex v, int next, const VB& curvb) -{ - SET_VERTEX(p, next, curvb); - MOVZ(p, v.z, curvb); - MOVFOG(p, v); -} - -void ZeroGS::KickSprite() -{ - assert( gs.primC >= 2 ); - VB& curvb = vb[prim->ctxt]; - - if (curvb.bNeedTexCheck) curvb.FlushTexData(); - - if ((vb[!prim->ctxt].nCount > 0) && (vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp)) - { - assert( vb[prim->ctxt].nCount == 0 ); - Flush(!prim->ctxt); - } - - curvb.NotifyWrite(6); - - int next = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); - int last = (gs.primIndex+2)%ARRAY_SIZE(gs.gsvertex); - - // sprite is too small and AA shows lines (tek4) - if ( s_AAx ) - { - gs.gsvertex[last].x += 4; - if( s_AAy ) gs.gsvertex[last].y += 4; - } - - // might be bad sprite (KH dialog text) - //if( gs.gsvertex[next].x == gs.gsvertex[last].x || gs.gsvertex[next].y == gs.gsvertex[last].y ) - //return; - - VertexGPU* p = curvb.pBufferData+curvb.nCount; - - SetKickVertex(&p[0], gs.gsvertex[last], next, curvb); - SetKickVertex(&p[3], gs.gsvertex[last], next, curvb); - SetKickVertex(&p[1], gs.gsvertex[last], last, curvb); - SetKickVertex(&p[4], gs.gsvertex[last], last, curvb); - SetKickVertex(&p[2], gs.gsvertex[last], next, curvb); - - p[2].s = p[1].s; - p[2].x = p[1].x; - - SetKickVertex(&p[5], gs.gsvertex[last], last, curvb); - p[5].s = p[0].s; - p[5].x = p[0].x; - - curvb.nCount += 6; - -#ifdef PRIM_LOG - OUTPUT_VERT(PRIM_LOG, p[0], 0); - OUTPUT_VERT(PRIM_LOG, p[1], 1); -#endif -} - -void ZeroGS::KickDummy() -{ - //GREG_LOG("Kicking bad primitive: %.8x\n", *(u32*)prim); -} - -__forceinline void ZeroGS::RenderFBA(const VB& curvb, CGparameter sOneColor) -{ - // add fba to all pixels - GL_STENCILFUNC(GL_ALWAYS, STENCIL_FBA, 0xff); - glStencilMask(STENCIL_CLEAR); - glStencilOp(GL_ZERO, GL_KEEP, GL_REPLACE); - - glDisable(GL_DEPTH_TEST); - glDepthMask(0); - glColorMask(0,0,0,0); - - if( s_bWriteDepth ) ResetRenderTarget(1); - - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GEQUAL, 1); - - Vector v; - v.x = 1; v.y = 2; v.z = 0; v.w = 0; - cgGLSetParameter4fv(sOneColor, v); - - DRAW(); - - if( !curvb.test.ate ) - glDisable(GL_ALPHA_TEST); - else - glAlphaFunc(g_dwAlphaCmp[curvb.test.atst], b2XAlphaTest ? min(1.0f,curvb.test.aref*(1/127.5f)) : curvb.test.aref*(1/255.0f)); - - // reset (not necessary) - GL_COLORMASK(s_dwColorWrite); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - - if( !curvb.zbuf.zmsk ) - { - glDepthMask(1); - - assert( curvb.pdepth != NULL ); - if( s_bWriteDepth ) curvb.pdepth->SetRenderTarget(1); - } - GL_ZTEST(curvb.test.zte); -} - -__forceinline void ZeroGS::RenderAlphaTest(const VB& curvb, CGparameter sOneColor) -{ - if( !g_bUpdateStencil ) return; - - if( curvb.test.ate ) - if( curvb.test.afail == 1 ) glDisable(GL_ALPHA_TEST); - - glDepthMask(0); - glColorMask(0,0,0,0); - - Vector v; - v.x = 1; v.y = 2; v.z = 0; v.w = 0; - cgGLSetParameter4fv(sOneColor, v); - - if (s_bWriteDepth) ResetRenderTarget(1); - - // or a 1 to the stencil buffer wherever alpha passes - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - s_stencilfunc = GL_ALWAYS; - - glEnable(GL_STENCIL_TEST); - - if( !s_bDestAlphaTest ) - { - // clear everything - s_stencilref = 0; - glStencilMask(STENCIL_CLEAR); - glDisable(GL_ALPHA_TEST); - GL_STENCILFUNC_SET(); - DRAW(); - - if( curvb.test.ate && curvb.test.afail != 1 && USEALPHATESTING ) - glEnable(GL_ALPHA_TEST); - } - - if( curvb.test.ate && curvb.test.atst>1 && curvb.test.aref > 0x80) - { - v.x = 1; v.y = 1; v.z = 0; v.w = 0; - cgGLSetParameter4fv(sOneColor, v); - glAlphaFunc(g_dwAlphaCmp[curvb.test.atst], curvb.test.aref*(1/255.0f)); - } - - s_stencilref = STENCIL_SPECIAL; - glStencilMask(STENCIL_SPECIAL); - GL_STENCILFUNC_SET(); - glDisable(GL_DEPTH_TEST); - - DRAW(); - - if( curvb.test.zte ) - glEnable(GL_DEPTH_TEST); - GL_ALPHATEST(0); - GL_COLORMASK(s_dwColorWrite); - - if( !curvb.zbuf.zmsk ) - { - glDepthMask(1); - - // set rt next level - if (s_bWriteDepth) curvb.pdepth->SetRenderTarget(1); - } -} - -__forceinline void ZeroGS::RenderStencil(const VB& curvb, u32 dwUsingSpecialTesting) -{ - //NOTE: This stencil hack for dest alpha testing ONLY works when - // the geometry in one DrawPrimitive call does not overlap - - // mark the stencil buffer for the new data's bits (mark 4 if alpha is >= 0xff) - // mark 4 if a pixel was written (so that the stencil buf can be changed with new values) - glStencilMask(STENCIL_PIXELWRITE); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - - s_stencilmask = (curvb.test.date?STENCIL_ALPHABIT:0)|(dwUsingSpecialTesting?STENCIL_SPECIAL:0); - s_stencilfunc = s_stencilmask ? GL_EQUAL : GL_ALWAYS; - s_stencilref = curvb.test.date*curvb.test.datm|STENCIL_PIXELWRITE|(dwUsingSpecialTesting?STENCIL_SPECIAL:0); - GL_STENCILFUNC_SET(); -} - -__forceinline void ZeroGS::ProcessStencil(const VB& curvb) -{ - assert( !curvb.fba.fba ); - - // set new alpha bit - glStencilMask(STENCIL_ALPHABIT); - GL_STENCILFUNC(GL_EQUAL, STENCIL_PIXELWRITE, STENCIL_PIXELWRITE|STENCIL_FBA); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - - glDisable(GL_DEPTH_TEST); - glDepthMask(0); - glColorMask(0,0,0,0); - - if (s_bWriteDepth) ResetRenderTarget(1); - - GL_ALPHATEST(0); - - SETPIXELSHADER(ppsOne.prog); - DRAW(); - - // process when alpha >= 0xff - GL_STENCILFUNC(GL_EQUAL, STENCIL_PIXELWRITE|STENCIL_FBA|STENCIL_ALPHABIT, STENCIL_PIXELWRITE|STENCIL_FBA); - DRAW(); - - // clear STENCIL_PIXELWRITE bit - glStencilMask(STENCIL_CLEAR); - GL_STENCILFUNC(GL_ALWAYS, 0, STENCIL_PIXELWRITE|STENCIL_FBA); - - DRAW(); - - // restore state - GL_COLORMASK(s_dwColorWrite); - - if( curvb.test.ate && USEALPHATESTING) - glEnable(GL_ALPHA_TEST); - - if( !curvb.zbuf.zmsk ) { - glDepthMask(1); - - if( s_bWriteDepth ) { - assert( curvb.pdepth != NULL ); - curvb.pdepth->SetRenderTarget(1); - } - } - - GL_ZTEST(curvb.test.zte); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); -} - -__forceinline void ZeroGS::ProcessFBA(const VB& curvb, CGparameter sOneColor) -{ - if( (curvb.frame.fbm&0x80000000) ) return; - - // add fba to all pixels that were written and alpha was less than 0xff - glStencilMask(STENCIL_ALPHABIT); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - - GL_STENCILFUNC(GL_EQUAL, STENCIL_FBA|STENCIL_PIXELWRITE|STENCIL_ALPHABIT, STENCIL_PIXELWRITE|STENCIL_FBA); - - glDisable(GL_DEPTH_TEST); - glDepthMask(0); - glColorMask(0,0,0,1); - - if( s_bWriteDepth ) { - ResetRenderTarget(1); - } - - // processes the pixels with ALPHA < 0x80*2 - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_LEQUAL, 1); - - // add 1 to dest - GL_BLEND_ALPHA(GL_ONE, GL_ONE); - GL_BLENDEQ_ALPHA(GL_FUNC_ADD); - - float f = 1; - cgGLSetParameter4fv(sOneColor, &f); - SETPIXELSHADER(ppsOne.prog); - - DRAW(); - - glDisable(GL_ALPHA_TEST); - - // reset bits - glStencilMask(STENCIL_CLEAR); - GL_STENCILFUNC(GL_GREATER, 0, STENCIL_PIXELWRITE|STENCIL_FBA); - glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO); - - DRAW(); - - if( curvb.test.atst && USEALPHATESTING) { - glEnable(GL_ALPHA_TEST); - glAlphaFunc(g_dwAlphaCmp[curvb.test.atst], b2XAlphaTest ? min(1.0f,curvb.test.aref*(1/127.5f)) : curvb.test.aref*(1/255.0f)); - } - - // restore (SetAlphaVariables) - GL_BLEND_ALPHA(GL_ONE, GL_ZERO); - if(vAlphaBlendColor.y<0) GL_BLENDEQ_ALPHA(GL_FUNC_REVERSE_SUBTRACT); - - // reset (not necessary) - GL_COLORMASK(s_dwColorWrite); - - if( !curvb.zbuf.zmsk ) { - glDepthMask(1); - - if (s_bWriteDepth) curvb.pdepth->SetRenderTarget(1); - } - GL_ZTEST(curvb.test.zte); -} - -inline void ZeroGS::SetContextTarget(int context) -{ - VB& curvb = vb[context]; - GL_REPORT_ERRORD(); - - if( curvb.prndr == NULL ) - curvb.prndr = s_RTs.GetTarg(curvb.frame, 0, GET_MAXHEIGHT(curvb.gsfb.fbp, curvb.gsfb.fbw, curvb.gsfb.psm)); - - // make sure targets are valid - if( curvb.pdepth == NULL ) { - frameInfo f; - f.fbp = curvb.zbuf.zbp; - f.fbw = curvb.frame.fbw; - f.fbh = curvb.prndr->fbh; - f.psm = curvb.zbuf.psm; - f.fbm = 0; - curvb.pdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| - (curvb.zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), GET_MAXHEIGHT(curvb.zbuf.zbp, curvb.gsfb.fbw, 0)); - } - - assert( curvb.prndr != NULL && curvb.pdepth != NULL ); - assert( curvb.pdepth->fbh == curvb.prndr->fbh ); - - if( curvb.pdepth->status & CRenderTarget::TS_Virtual) { - - if( !curvb.zbuf.zmsk ) { - CRenderTarget* ptemp = s_DepthRTs.Promote(curvb.pdepth->fbp|(curvb.pdepth->fbw<<16)); - assert( ptemp == curvb.pdepth ); - } - else - curvb.pdepth->status &= ~CRenderTarget::TS_NeedUpdate; - } - - BOOL bSetTarg = 1; - if( curvb.pdepth->status & CRenderTarget::TS_NeedUpdate ) { - - assert( !(curvb.pdepth->status & CRenderTarget::TS_Virtual) ); - - // don't update if virtual - curvb.pdepth->Update(context, curvb.prndr); - bSetTarg = 0; - } - - GL_REPORT_ERRORD(); - if( curvb.prndr->status & CRenderTarget::TS_NeedUpdate ) { - -// if(bSetTarg s_bWriteDepth ) { -// if( s_bWriteDepth ) { -// curvb.pdepth->SetRenderTarget(1); -// curvb.pdepth->SetDepthStencilSurface(); -// } -// else curvb.pdepth->SetDepthStencilSurface(); -// } - - curvb.prndr->Update(context, curvb.pdepth); - } - else { - - //if( (vb[0].prndr != vb[1].prndr && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg ) - curvb.prndr->SetRenderTarget(0); - //if( bSetTarg && ((vb[0].pdepth != vb[1].pdepth && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg) ) - curvb.pdepth->SetDepthStencilSurface(); - - if (conf.mrtdepth && ZeroGS::IsWriteDepth()) curvb.pdepth->SetRenderTarget(1); - - if (s_ptexCurSet[0] == curvb.prndr->ptex) s_ptexCurSet[0] = 0; - if (s_ptexCurSet[1] == curvb.prndr->ptex) s_ptexCurSet[1] = 0; - - curvb.prndr->SetViewport(); - } - - curvb.prndr->SetTarget(curvb.frame.fbp, curvb.scissor, context); - - if( (curvb.zbuf.zbp-curvb.pdepth->fbp) != (curvb.frame.fbp - curvb.prndr->fbp) && curvb.test.zte ) - WARN_LOG("frame and zbuf not aligned\n"); - - curvb.bVarsSetTarg = TRUE; - if( vb[!context].prndr != curvb.prndr ) vb[!context].bVarsSetTarg = FALSE; - - assert( !(curvb.prndr->status&CRenderTarget::TS_NeedUpdate) ); - assert( curvb.pdepth == NULL || !(curvb.pdepth->status&CRenderTarget::TS_NeedUpdate) ); - GL_REPORT_ERRORD(); -} - -void ZeroGS::SetTexVariables(int context, FRAGMENTSHADER* pfragment, int settexint) -{ - if (!vb[context].curprim.tme) return; - - DVProfileFunc _pf("SetTexVariables"); - - assert( !vb[context].bNeedTexCheck ); - - Vector v, v2; - tex0Info& tex0 = vb[context].tex0; - - float fw = (float)tex0.tw; - float fh = (float)tex0.th; - - if( !vb[context].bTexConstsSync ) { - // alpha and texture highlighting - Vector valpha, valpha2; - - // if clut, use the frame format - int psm = tex0.psm; - if( PSMT_ISCLUT(tex0.psm) ) psm = tex0.cpsm; - - int nNeedAlpha = (psm == 1 || psm == 2 || psm == 10); - - Vector vblack; - vblack.x = vblack.y = vblack.z = vblack.w = 10; - - switch(tex0.tfx) { - case 0: - valpha.z = 0; valpha.w = 0; - valpha2.x = 0; valpha2.y = 0; - valpha2.z = 2; valpha2.w = 1; - - break; - case 1: - valpha.z = 0; valpha.w = 1; - valpha2.x = 1; valpha2.y = 0; - valpha2.z = 0; valpha2.w = 0; - - break; - case 2: - valpha.z = 1; valpha.w = 1.0f; - valpha2.x = 0; valpha2.y = tex0.tcc ? 1.0f : 0.0f; - valpha2.z = 2; valpha2.w = 0; - - break; - - case 3: - valpha.z = 1; valpha.w = tex0.tcc ? 0.0f : 1.0f; - valpha2.x = 0; valpha2.y = tex0.tcc ? 1.0f : 0.0f; - valpha2.z = 2; valpha2.w = 0; - - break; - } - - if( tex0.tcc ) { - - if( tex0.tfx == 1 ) { - //mode.x = 10; - valpha.z = 0; valpha.w = 0; - valpha2.x = 1; valpha2.y = 1; - valpha2.z = 0; valpha2.w = 0; - } - - if( nNeedAlpha ) { - - if( tex0.tfx == 0 ) { - // make sure alpha is mult by two when the output is Cv = Ct*Cf - valpha.x = 2*gs.texa.fta[0]; - // if 24bit, always choose ta[0] - valpha.y = 2*gs.texa.fta[psm != 1]; - valpha.y -= valpha.x; - } - else { - valpha.x = gs.texa.fta[0]; - // if 24bit, always choose ta[0] - valpha.y = gs.texa.fta[psm != 1]; - valpha.y -= valpha.x; - } - - // need black detection - if( gs.texa.aem && psm == PSMCT24 ) - vblack.w = 0; - } - else { - if( tex0.tfx == 0 ) { - valpha.x = 0; - valpha.y = 2; - } - else { - valpha.x = 0; - valpha.y = 1; - } - } - } - else { - - // reset alpha to color - valpha.x = valpha.y = 0; - valpha.w = 1; - } - - cgGLSetParameter4fv(pfragment->fTexAlpha, valpha); - cgGLSetParameter4fv(pfragment->fTexAlpha2, valpha2); - if( tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S) ) - cgGLSetParameter4fv(pfragment->fTestBlack, vblack); - - // clamp relies on texture width - { - clampInfo* pclamp = &ZeroGS::vb[context].clamp; - Vector v, v2; - v.x = v.y = 0; - u32* ptex = ZeroGS::vb[context].ptexClamp; - ptex[0] = ptex[1] = 0; - - float fw = ZeroGS::vb[context].tex0.tw; - float fh = ZeroGS::vb[context].tex0.th; - - switch(pclamp->wms) { - case 0: - v2.x = -1e10; v2.z = 1e10; - break; - case 1: // pclamp - // suikoden5 movie text - v2.x = 0; v2.z = 1-0.5f/fw; - break; - case 2: // reg pclamp - v2.x = (pclamp->minu+0.5f)/fw; v2.z = (pclamp->maxu-0.5f)/fw; - break; - - case 3: // region rep x - v.x = 0.9999f; - v.z = fw / (float)GPU_TEXMASKWIDTH; - v2.x = (float)GPU_TEXMASKWIDTH / fw; - v2.z = pclamp->maxu / fw; - - if( pclamp->minu != g_PrevBitwiseTexX ) { - g_PrevBitwiseTexX = pclamp->minu; - ptex[0] = ZeroGS::s_BitwiseTextures.GetTex(pclamp->minu, 0); - } - break; - } - - switch(pclamp->wmt) { - case 0: - v2.y = -1e10; v2.w = 1e10; - break; - case 1: // pclamp - // suikoden5 movie text - v2.y = 0; v2.w = 1-0.5f/fh; - break; - case 2: // reg pclamp - v2.y = (pclamp->minv+0.5f)/fh; v2.w = (pclamp->maxv-0.5f)/fh; - break; - - case 3: // region rep y - v.y = 0.9999f; - v.w = fh / (float)GPU_TEXMASKWIDTH; - v2.y = (float)GPU_TEXMASKWIDTH / fh; - v2.w = pclamp->maxv / fh; - - if( pclamp->minv != g_PrevBitwiseTexY ) { - g_PrevBitwiseTexY = pclamp->minv; - ptex[1] = ZeroGS::s_BitwiseTextures.GetTex(pclamp->minv, ptex[0]); - } - break; - } - - if( pfragment->fTexWrapMode != 0 ) - cgGLSetParameter4fv(pfragment->fTexWrapMode, v); - if( pfragment->fClampExts != 0 ) - cgGLSetParameter4fv(pfragment->fClampExts, v2); - } - - vb[context].bTexConstsSync = TRUE; - } - - if(s_bTexFlush ) { - if( PSMT_ISCLUT(tex0.psm) ) - texClutWrite(context); - else - s_bTexFlush = FALSE; - } - - if( settexint ) { - CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(tex0, 1); - - if( vb[context].bVarsTexSync ) { - if( vb[context].pmemtarg != pmemtarg ) { - SetTexVariablesInt(context, GetTexFilter(vb[context].tex1), tex0, pmemtarg, pfragment, s_bForceTexFlush); - vb[context].bVarsTexSync = TRUE; - } - } - else { - SetTexVariablesInt(context, GetTexFilter(vb[context].tex1), tex0, pmemtarg, pfragment, s_bForceTexFlush); - vb[context].bVarsTexSync = TRUE; - - INC_TEXVARS(); - } - } - else { - vb[context].bVarsTexSync = FALSE; - } -} - -void ZeroGS::SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, CMemoryTarget* pmemtarg, FRAGMENTSHADER* pfragment, int force) -{ - DVProfileFunc _pf("SetTexVariablesInt"); - - Vector v; - assert( pmemtarg != NULL && pfragment != NULL); - - float fw = (float)tex0.tw; - float fh = (float)tex0.th; - - bool bUseBilinear = bilinear > 1 || (bilinear && conf.bilinear); - if( bUseBilinear ) { - v.x = (float)fw; - v.y = (float)fh; - v.z = 1.0f / (float)fw; - v.w = 1.0f / (float)fh; - if (pfragment->fRealTexDims) - cgGLSetParameter4fv(pfragment->fRealTexDims, v); - else - cgGLSetParameter4fv(cgGetNamedParameter(pfragment->prog,"g_fRealTexDims"),v); - } - - if( m_Blocks[tex0.psm].bpp == 0 ) { - ERROR_LOG("Undefined tex psm 0x%x!\n", tex0.psm); - return; - } - - const BLOCK& b = m_Blocks[tex0.psm]; - - float fbw = (float)tex0.tbw; - - Vector vTexDims; - vTexDims.x = b.vTexDims.x * fw; - vTexDims.y = b.vTexDims.y * fh; - vTexDims.z = (float)BLOCK_TEXWIDTH*(0.002f / 64.0f + 0.01f/128.0f); - vTexDims.w = (float)BLOCK_TEXHEIGHT*0.2f/512.0f; - - if( bUseBilinear ) { - vTexDims.x *= 1/128.0f; - vTexDims.y *= 1/512.0f; - vTexDims.z *= 1/128.0f; - vTexDims.w *= 1/512.0f; - } - - float g_fitexwidth = g_fiGPU_TEXWIDTH/(float)pmemtarg->widthmult; - float g_texwidth = GPU_TEXWIDTH*(float)pmemtarg->widthmult; - - float fpage = tex0.tbp0*(64.0f*g_fitexwidth) + 0.05f * g_fitexwidth; - float fpageint = floorf(fpage); - int starttbp = (int)fpage; - - // 2048 is number of words to span one page - float fblockstride = (2048.0f /(float)(g_texwidth*BLOCK_TEXWIDTH)) * b.vTexDims.x * fbw; - assert( fblockstride >= 1.0f ); - - v.x = (float)(2048 * g_fitexwidth); - v.y = fblockstride; - v.z = g_fBlockMult/(float)pmemtarg->widthmult; - v.w = fpage-fpageint; - - if( g_fBlockMult > 1 ) { - // make sure to divide by mult (since the G16R16 texture loses info) - v.z *= b.bpp * (1/32.0f); - } - - cgGLSetParameter4fv(pfragment->fTexDims, vTexDims); - cgGLSetParameter4fv(pfragment->fTexBlock, &b.vTexBlock.x); - cgGLSetParameter4fv(pfragment->fTexOffset, v); - - // get hardware texture dims - int texheight = (pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult; - int texwidth = GPU_TEXWIDTH*pmemtarg->widthmult*pmemtarg->channels; - - v.y = 1;//(float)1.0f / (float)((pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult); - v.x = (fpageint-(float)pmemtarg->realy/(float)pmemtarg->widthmult+0.5f);//*v.y; - -// v.x *= (float)texheight; -// v.y *= (float)texheight; - v.z = (float)texwidth; - if( !(g_nPixelShaderVer & SHADER_ACCURATE) || bUseBilinear ) - v.w = 0.25f; - else - v.w = 0.5f; - - cgGLSetParameter4fv(pfragment->fPageOffset, v); - - if( force ) s_ptexCurSet[context] = pmemtarg->ptex->tex; - else s_ptexNextSet[context] = pmemtarg->ptex->tex; - vb[context].pmemtarg = pmemtarg; - - vb[context].bVarsTexSync = FALSE; -} -#define SET_ALPHA_COLOR_FACTOR(sign) \ -{ \ - switch(a.c) \ - { \ - case 0: \ - vAlphaBlendColor.y = (sign) ? 2.0f*255.0f/256.0f : -2.0f*255.0f/256.0f; \ - s_srcalpha = GL_ONE; \ - s_alphaeq = (sign) ? GL_FUNC_ADD : GL_FUNC_REVERSE_SUBTRACT; \ - break; \ - \ - case 1: \ - /* if in 24 bit mode, dest alpha should be one */ \ - switch(vb[icurctx].prndr->psm&0xf) \ - { \ - case 0: \ - bDestAlphaColor = (a.d!=2)&&((a.a==a.d)||(a.b==a.d)); \ - break; \ - \ - case 1: \ - /* dest alpha should be one */ \ - bDestAlphaColor = 2; \ - break; \ - /* default: 16bit surface, so returned alpha is ok */ \ - } \ - break; \ - \ - case 2: \ - bNeedBlendFactorInAlpha = 1; /* should disable alpha channel writing */ \ - vAlphaBlendColor.y = 0; \ - vAlphaBlendColor.w = (sign) ? (float)a.fix * (2.0f/255.0f) : (float)a.fix * (-2.0f/255.0f); \ - usec = 0; /* change so that alpha comes from source*/ \ - break; \ - } \ -} \ - -//if( a.fix <= 0x80 ) { \ -// dwTemp = (a.fix*2)>255?255:(a.fix*2); \ -// dwTemp = dwTemp|(dwTemp<<8)|(dwTemp<<16)|0x80000000; \ -// printf("bfactor: %8.8x\n", dwTemp); \ -// glBlendColorEXT(dwTemp); \ -// } \ -// else { \ - -void ZeroGS::ResetAlphaVariables() -{ -} - -void ZeroGS::SetAlphaVariables(const alphaInfo& a) -{ - bool alphaenable = true; - - // TODO: negative color when not clamping turns to positive??? - g_vars._bAlphaState = 0; // set all to zero - bNeedBlendFactorInAlpha = 0; - b2XAlphaTest = 1; - u32 dwTemp = 0xffffffff; - - // default - s_srcalpha = GL_ONE; - s_dstalpha = GL_ZERO; - s_alphaeq = GL_FUNC_ADD; - - s_alphaInfo = a; - - vAlphaBlendColor = Vector(1,2*255.0f/256.0f,0,0); - u32 usec = a.c; - - if( a.a == a.b ) - { // just d remains - if( a.d == 0 ) - { - alphaenable = false; - } - else - { - s_dstrgb = a.d == 1 ? GL_ONE : GL_ZERO; - s_srcrgb = GL_ZERO; - s_rgbeq = GL_FUNC_ADD; - } - - goto EndSetAlpha; - } - else if( a.d == 2 ) - { // zero - if( a.a == 2 ) - { - // zero all color - s_srcrgb = GL_ZERO; - s_dstrgb = GL_ZERO; - goto EndSetAlpha; - } - else if( a.b == 2 ) - { - //b2XAlphaTest = 1; - - SET_ALPHA_COLOR_FACTOR(1); - - if( bDestAlphaColor == 2 ) - { - s_rgbeq = GL_FUNC_ADD; - s_srcrgb = a.a == 0 ? GL_ONE : GL_ZERO; - s_dstrgb = a.a == 0 ? GL_ZERO : GL_ONE; - } - else - { - bAlphaClamping = 2; - - s_rgbeq = GL_FUNC_ADD; - s_srcrgb = a.a == 0 ? blendalpha[usec] : GL_ZERO; - s_dstrgb = a.a == 0 ? GL_ZERO : blendalpha[usec]; - } - - goto EndSetAlpha; - } - - // nothing is zero, so must do some real blending - //b2XAlphaTest = 1; - bAlphaClamping = 3; - - SET_ALPHA_COLOR_FACTOR(1); - - s_rgbeq = a.a == 0 ? GL_FUNC_SUBTRACT : GL_FUNC_REVERSE_SUBTRACT; - s_srcrgb = bDestAlphaColor == 2 ? GL_ONE : blendalpha[usec]; - s_dstrgb = bDestAlphaColor == 2 ? GL_ONE : blendalpha[usec]; - } - else if( a.a == 2 ) - { // zero - - //b2XAlphaTest = 1; - bAlphaClamping = 1; // min testing - - SET_ALPHA_COLOR_FACTOR(1); - - if( a.b == a.d ) - { - // can get away with 1-A - s_rgbeq = GL_FUNC_ADD; - s_srcrgb = (a.b == 0 && bDestAlphaColor != 2) ? blendinvalpha[usec] : GL_ZERO; - s_dstrgb = (a.b == 0 || bDestAlphaColor == 2) ? GL_ZERO : blendinvalpha[usec]; - } - else - { - s_rgbeq = a.b==0 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_SUBTRACT; - s_srcrgb = (a.b == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : GL_ONE; - s_dstrgb = (a.b == 0 || bDestAlphaColor == 2 ) ? GL_ONE : blendalpha[usec]; - } - } - else if( a.b == 2 ) - { - bAlphaClamping = 2; // max testing - - SET_ALPHA_COLOR_FACTOR(a.a!=a.d); - - if( a.a == a.d ) - { - // can get away with 1+A, but need to set alpha to negative - s_rgbeq = GL_FUNC_ADD; - - if( bDestAlphaColor == 2 ) - { - assert(usec==1); - - // all ones - bNeedBlendFactorInAlpha = 1; - vAlphaBlendColor.y = 0; - vAlphaBlendColor.w = -1; - - s_srcrgb = (a.a == 0) ? GL_ONE_MINUS_SRC_ALPHA : GL_ZERO; - s_dstrgb = (a.a == 0) ? GL_ZERO : GL_ONE_MINUS_SRC_ALPHA; - } - else - { - s_srcrgb = a.a == 0 ? blendinvalpha[usec] : GL_ZERO; - s_dstrgb = a.a == 0 ? GL_ZERO : blendinvalpha[usec]; - } - } - else - { - //b2XAlphaTest = 1; - s_rgbeq = GL_FUNC_ADD; - s_srcrgb = (a.a == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : GL_ONE; - s_dstrgb = (a.a == 0 || bDestAlphaColor == 2) ? GL_ONE : blendalpha[usec]; - } - } - else - { - // all 3 components are valid! - bAlphaClamping = 3; // all testing - SET_ALPHA_COLOR_FACTOR(a.a!=a.d); - - if( a.a == a.d ) - { - // can get away with 1+A, but need to set alpha to negative - s_rgbeq = GL_FUNC_ADD; - - if( bDestAlphaColor == 2 ) - { - assert(usec==1); - - // all ones - bNeedBlendFactorInAlpha = 1; - vAlphaBlendColor.y = 0; - vAlphaBlendColor.w = -1; - s_srcrgb = a.a == 0 ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA; - s_dstrgb = a.a == 0 ? GL_SRC_ALPHA : GL_ONE_MINUS_SRC_ALPHA; - } - else - { - s_srcrgb = a.a == 0 ? blendinvalpha[usec] : blendalpha[usec]; - s_dstrgb = a.a == 0 ? blendalpha[usec] : blendinvalpha[usec]; - } - } - else - { - assert(a.b == a.d); - s_rgbeq = GL_FUNC_ADD; - - if( bDestAlphaColor == 2 ) - { - assert(usec==1); - - // all ones - bNeedBlendFactorInAlpha = 1; - vAlphaBlendColor.y = 0; - vAlphaBlendColor.w = 1; - s_srcrgb = a.a != 0 ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA; - s_dstrgb = a.a != 0 ? GL_SRC_ALPHA : GL_ONE_MINUS_SRC_ALPHA; - } - else - { - //b2XAlphaTest = 1; - s_srcrgb = a.a != 0 ? blendinvalpha[usec] : blendalpha[usec]; - s_dstrgb = a.a != 0 ? blendalpha[usec] : blendinvalpha[usec]; - } - } - } - - EndSetAlpha: - - GL_BLEND_SET(); - zgsBlendEquationSeparateEXT(s_rgbeq, s_alphaeq); - - if( alphaenable ) - glEnable(GL_BLEND); // always set - else - glDisable(GL_BLEND); - - INC_ALPHAVARS(); -} - -void ZeroGS::SetWriteDepth() -{ - if( conf.mrtdepth ) { - s_bWriteDepth = TRUE; - s_nWriteDepthCount = 4; - } -} - -BOOL ZeroGS::IsWriteDepth() -{ - return s_bWriteDepth; -} - -BOOL ZeroGS::IsWriteDestAlphaTest() -{ - return s_bWriteDepth; -} - -void ZeroGS::SetDestAlphaTest() -{ - s_bDestAlphaTest = TRUE; - s_nWriteDestAlphaTest = 4; -} - -void ZeroGS::SetFogColor(u32 fog) -{ - if( 1||gs.fogcol != fog ) { - gs.fogcol = fog; - - ZeroGS::Flush(0); - ZeroGS::Flush(1); - - if( !g_bIsLost ) { - Vector v; - - // set it immediately - v.x = (gs.fogcol&0xff)/255.0f; - v.y = ((gs.fogcol>>8)&0xff)/255.0f; - v.z = ((gs.fogcol>>16)&0xff)/255.0f; - cgGLSetParameter4fv(g_fparamFogColor, v); - } - } -} - -void ZeroGS::ExtWrite() -{ - WARN_LOG("ExtWrite\n"); - - // use local DISPFB, EXTDATA, EXTBUF, and PMODE -// int bpp, start, end; -// tex0Info texframe; - -// bpp = 4; -// if( texframe.psm == 0x12 ) bpp = 3; -// else if( texframe.psm & 2 ) bpp = 2; -// -// // get the start and end addresses of the buffer -// GetRectMemAddress(start, end, texframe.psm, 0, 0, texframe.tw, texframe.th, texframe.tbp0, texframe.tbw); -} - -//////////// -// Caches // -//////////// -#ifdef __x86_64__ -extern "C" void TestClutChangeMMX(void* src, void* dst, int entries, void* pret); -#endif - -bool ZeroGS::CheckChangeInClut(u32 highdword, u32 psm) -{ - int cld = (highdword >> 29) & 0x7; - int cbp = ((highdword >> 5) & 0x3fff); - - // processing the CLUT after tex0/2 are written - switch(cld) { - case 0: return false; - case 1: break; // Seems to rarely not be 1. - // note sure about changing cbp[0,1] - case 4: return gs.cbp[0] != cbp; - case 5: return gs.cbp[1] != cbp; - - // default: load - default: break; - } - - int cpsm = (highdword >> 19) & 0xe; - int csm = (highdword >> 23) & 0x1; - - if( cpsm > 1 || csm ) - // don't support 16bit for now - return true; - - int csa = (highdword >> 24) & 0x1f; - - int entries = (psm&3)==3 ? 256 : 16; - - u64* src = (u64*)(g_pbyGSMemory + cbp*256); - u64* dst = (u64*)(g_pbyGSClut+64*csa); - - bool bRet = false; - - // do a fast test with MMX -#ifdef _MSC_VER - -#ifdef __x86_64__ - TestClutChangeMMX(dst, src, entries, &bRet); -#else - int storeebx; - __asm { - mov storeebx, ebx - mov edx, dst - mov ecx, src - mov ebx, entries - -Start: - movq mm0, [edx] - movq mm1, [edx+8] - pcmpeqd mm0, [ecx] - pcmpeqd mm1, [ecx+16] - - movq mm2, [edx+16] - movq mm3, [edx+24] - pcmpeqd mm2, [ecx+32] - pcmpeqd mm3, [ecx+48] - - pand mm0, mm1 - pand mm2, mm3 - movq mm4, [edx+32] - movq mm5, [edx+40] - pcmpeqd mm4, [ecx+8] - pcmpeqd mm5, [ecx+24] - - pand mm0, mm2 - pand mm4, mm5 - movq mm6, [edx+48] - movq mm7, [edx+56] - pcmpeqd mm6, [ecx+40] - pcmpeqd mm7, [ecx+56] - - pand mm0, mm4 - pand mm6, mm7 - pand mm0, mm6 - - pmovmskb eax, mm0 - cmp eax, 0xff - je Continue - mov bRet, 1 - jmp Return - -Continue: - cmp ebx, 16 - jle Return - - test ebx, 0x10 - jz AddEcx - sub ecx, 448 // go back and down one column, -AddEcx: - add ecx, 256 // go to the right block - - - jne Continue1 - add ecx, 256 // skip whole block -Continue1: - add edx, 64 - sub ebx, 16 - jmp Start - -Return: - emms - mov ebx, storeebx - } -#endif // __x86_64__ - -#else // linux - -#ifdef __x86_64__ - __asm__( - ".intel_syntax\n" -"Start:\n" - "movq %%mm0, [%%rcx]\n" - "movq %%mm1, [%%rcx+8]\n" - "pcmpeqd %%mm0, [%%rdx]\n" - "pcmpeqd %%mm1, [%%rdx+16]\n" - "movq %%mm2, [%%rcx+16]\n" - "movq %%mm3, [%%rcx+24]\n" - "pcmpeqd %%mm2, [%%rdx+32]\n" - "pcmpeqd %%mm3, [%%rdx+48]\n" - "pand %%mm0, %%mm1\n" - "pand %%mm2, %%mm3\n" - "movq %%mm4, [%%rcx+32]\n" - "movq %%mm5, [%%rcx+40]\n" - "pcmpeqd %%mm4, [%%rdx+8]\n" - "pcmpeqd %%mm5, [%%rdx+24]\n" - "pand %%mm0, %%mm2\n" - "pand %%mm4, %%mm5\n" - "movq %%mm6, [%%rcx+48]\n" - "movq %%mm7, [%%rcx+56]\n" - "pcmpeqd %%mm6, [%%rdx+40]\n" - "pcmpeqd %%mm7, [%%rdx+56]\n" - "pand %%mm0, %%mm4\n" - "pand %%mm6, %%mm7\n" - "pand %%mm0, %%mm6\n" - "pmovmskb %%eax, %%mm0\n" - "cmp %%eax, 0xff\n" - "je Continue\n" - ".att_syntax\n" - "movb $1, %0\n" - ".intel_syntax\n" - "jmp Return\n" -"Continue:\n" - "cmp %%rbx, 16\n" - "jle Return\n" - "test %%rbx, 0x10\n" - "jz AddRcx\n" - "sub %%rdx, 448\n" // go back and down one column -"AddRcx:\n" - "add %%rdx, 256\n" // go to the right block - "cmp %%rbx, 0x90\n" - "jne Continue1\n" - "add %%rdx, 256\n" // skip whole block -"Continue1:\n" - "add %%rcx, 64\n" - "sub %%rbx, 16\n" - "jmp Start\n" -"Return:\n" - "emms\n" - ".att_syntax\n" : "=m"(bRet) : "c"(dst), "d"(src), "b"(entries) : "rax", "memory"); -#else - // do a fast test with MMX - __asm__( - ".intel_syntax\n" -"Start:\n" - "movq %%mm0, [%%ecx]\n" - "movq %%mm1, [%%ecx+8]\n" - "pcmpeqd %%mm0, [%%edx]\n" - "pcmpeqd %%mm1, [%%edx+16]\n" - "movq %%mm2, [%%ecx+16]\n" - "movq %%mm3, [%%ecx+24]\n" - "pcmpeqd %%mm2, [%%edx+32]\n" - "pcmpeqd %%mm3, [%%edx+48]\n" - "pand %%mm0, %%mm1\n" - "pand %%mm2, %%mm3\n" - "movq %%mm4, [%%ecx+32]\n" - "movq %%mm5, [%%ecx+40]\n" - "pcmpeqd %%mm4, [%%edx+8]\n" - "pcmpeqd %%mm5, [%%edx+24]\n" - "pand %%mm0, %%mm2\n" - "pand %%mm4, %%mm5\n" - "movq %%mm6, [%%ecx+48]\n" - "movq %%mm7, [%%ecx+56]\n" - "pcmpeqd %%mm6, [%%edx+40]\n" - "pcmpeqd %%mm7, [%%edx+56]\n" - "pand %%mm0, %%mm4\n" - "pand %%mm6, %%mm7\n" - "pand %%mm0, %%mm6\n" - "pmovmskb %%eax, %%mm0\n" - "cmp %%eax, 0xff\n" - "je Continue\n" - ".att_syntax\n" - "movb $1, %0\n" - ".intel_syntax\n" - "jmp Return\n" -"Continue:\n" - "cmp %%ebx, 16\n" - "jle Return\n" - "test %%ebx, 0x10\n" - "jz AddEcx\n" - "sub %%edx, 448\n" // go back and down one column -"AddEcx:\n" - "add %%edx, 256\n" // go to the right block - "cmp %%ebx, 0x90\n" - "jne Continue1\n" - "add %%edx, 256\n" // skip whole block -"Continue1:\n" - "add %%ecx, 64\n" - "sub %%ebx, 16\n" - "jmp Start\n" -"Return:\n" - "emms\n" - ".att_syntax\n" : "=m"(bRet) : "c"(dst), "d"(src), "b"(entries) : "eax", "memory"); -#endif // __x86_64__ - -#endif // _WIN32 - - return bRet; -} - -void ZeroGS::texClutWrite(int ctx) -{ - s_bTexFlush = 0; - if( g_bIsLost ) - return; - - tex0Info& tex0 = vb[ctx].tex0; - assert( PSMT_ISCLUT(tex0.psm) ); - // processing the CLUT after tex0/2 are written - switch(tex0.cld) { - case 0: return; - case 1: break; // tex0.cld is usually 1. - case 2: gs.cbp[0] = tex0.cbp; break; - case 3: gs.cbp[1] = tex0.cbp; break; - // not sure about changing cbp[0,1] - case 4: - if( gs.cbp[0] == tex0.cbp ) - return; - gs.cbp[0] = tex0.cbp; - break; - case 5: - if( gs.cbp[1] == tex0.cbp ) - return; - gs.cbp[1] = tex0.cbp; - break; - default: //DEBUG_LOG("cld isn't 0-5!"); - break; - } - - Flush(!ctx); - - int entries = (tex0.psm & 3)==3 ? 256 : 16; - - if (tex0.csm) - { - switch (tex0.cpsm) - { - // 16bit psm - // eggomania uses non16bit textures for csm2 - case PSMCT16: - { - u16* src = (u16*)g_pbyGSMemory + tex0.cbp*128; - u16 *dst = (u16*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0)); - - for (int i = 0; i < entries; ++i) - { - *dst = src[getPixelAddress16_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; - dst += 2; - - // check for wrapping - if (((u32)(uptr)dst & 0x3ff) == 0) dst = (u16*)(g_pbyGSClut+2); - } - break; - } - - case PSMCT16S: - { - u16* src = (u16*)g_pbyGSMemory + tex0.cbp*128; - u16 *dst = (u16*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0)); - - for (int i = 0; i < entries; ++i) - { - *dst = src[getPixelAddress16S_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; - dst += 2; - - // check for wrapping - if (((u32)(uptr)dst & 0x3ff) == 0) dst = (u16*)(g_pbyGSClut+2); - } - break; - } - - case PSMCT32: - case PSMCT24: - { - u32* src = (u32*)g_pbyGSMemory + tex0.cbp*64; - u32 *dst = (u32*)(g_pbyGSClut+64*tex0.csa); - - // check if address exceeds src - if( src+getPixelAddress32_0(gs.clut.cou+entries-1, gs.clut.cov, gs.clut.cbw) >= (u32*)g_pbyGSMemory + 0x00100000 ) - ERROR_LOG("texClutWrite out of bounds\n"); - else - for(int i = 0; i < entries; ++i) - { - *dst = src[getPixelAddress32_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; - dst++; - } - break; - } - - default: - { -#ifndef RELEASE_TO_PUBLIC - //DEBUG_LOG("unknown cpsm: %x (%x)\n", tex0.cpsm, tex0.psm); -#endif - break; - } - } - } - else - { - switch (tex0.cpsm) - { - case PSMCT24: - case PSMCT32: - if( entries == 16 ) - WriteCLUT_T32_I4_CSM1((u32*)(g_pbyGSMemory + tex0.cbp*256), (u32*)(g_pbyGSClut+64*tex0.csa)); - else - WriteCLUT_T32_I8_CSM1((u32*)(g_pbyGSMemory + tex0.cbp*256), (u32*)(g_pbyGSClut+64*tex0.csa)); - break; - - default: - if( entries == 16 ) - WriteCLUT_T16_I4_CSM1((u32*)(g_pbyGSMemory + 256 * tex0.cbp), (u32*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0))); - else // sse2 for 256 is more complicated, so use regular - WriteCLUT_T16_I8_CSM1_c((u32*)(g_pbyGSMemory + 256 * tex0.cbp), (u32*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0))); - break; - - } - } -} - -void ZeroGS::SetTexFlush() -{ - s_bTexFlush = TRUE; - -// if( PSMT_ISCLUT(vb[0].tex0.psm) ) -// texClutWrite(0); -// if( PSMT_ISCLUT(vb[1].tex0.psm) ) -// texClutWrite(1); - - if( !s_bForceTexFlush ) - { - if (s_ptexCurSet[0] != s_ptexNextSet[0]) s_ptexCurSet[0] = s_ptexNextSet[0]; - if (s_ptexCurSet[1] != s_ptexNextSet[1]) s_ptexCurSet[1] = s_ptexNextSet[1]; - } -} - -int ZeroGS::Save(char* pbydata) -{ - if( pbydata == NULL ) - return 40 + 0x00400000 + sizeof(gs) + 2*VBSAVELIMIT + 2*sizeof(frameInfo) + 4 + 256*4; - - s_RTs.ResolveAll(); - s_DepthRTs.ResolveAll(); - - strcpy(pbydata, libraryName); - *(u32*)(pbydata+16) = ZEROGS_SAVEVER; - pbydata += 32; - - *(int*)pbydata = icurctx; pbydata += 4; - *(int*)pbydata = VBSAVELIMIT; pbydata += 4; - - memcpy(pbydata, g_pbyGSMemory, 0x00400000); - pbydata += 0x00400000; - - memcpy(pbydata, g_pbyGSClut, 256*4); - pbydata += 256*4; - - *(int*)pbydata = sizeof(gs); - pbydata += 4; - memcpy(pbydata, &gs, sizeof(gs)); - pbydata += sizeof(gs); - - for(int i = 0; i < 2; ++i) { - memcpy(pbydata, &vb[i], VBSAVELIMIT); - pbydata += VBSAVELIMIT; - } - - return 0; -} - -extern u32 s_uTex1Data[2][2], s_uClampData[2]; -extern char *libraryName; -bool ZeroGS::Load(char* pbydata) -{ - memset(s_uTex1Data, 0, sizeof(s_uTex1Data)); - memset(s_uClampData, 0, sizeof(s_uClampData)); - - g_nCurVBOIndex = 0; - - // first 32 bytes are the id - u32 savever = *(u32*)(pbydata+16); - - if( strncmp(pbydata, libraryName, 6) == 0 && (savever == ZEROGS_SAVEVER || savever == 0xaa000004) ) { - - g_MemTargs.Destroy(); - - GSStateReset(); - pbydata += 32; - - int context = *(int*)pbydata; pbydata += 4; - u32 savelimit = VBSAVELIMIT; - - savelimit = *(u32*)pbydata; pbydata += 4; - - memcpy(g_pbyGSMemory, pbydata, 0x00400000); - pbydata += 0x00400000; - - memcpy(g_pbyGSClut, pbydata, 256*4); - pbydata += 256*4; - - memset(&gs, 0, sizeof(gs)); - - int savedgssize; - if( savever == 0xaa000004 ) - savedgssize = 0x1d0; - else { - savedgssize = *(int*)pbydata; - pbydata += 4; - } - - memcpy(&gs, pbydata, savedgssize); - pbydata += savedgssize; - prim = &gs._prim[gs.prac]; - - vb[0].Destroy(); - memcpy(&vb[0], pbydata, min(savelimit, VBSAVELIMIT)); - pbydata += savelimit; - vb[0].pBufferData = NULL; - - vb[1].Destroy(); - memcpy(&vb[1], pbydata, min(savelimit, VBSAVELIMIT)); - pbydata += savelimit; - vb[1].pBufferData = NULL; - - for(int i = 0; i < 2; ++i) { - vb[i].Init(VB_BUFFERSIZE); - vb[i].bNeedZCheck = vb[i].bNeedFrameCheck = 1; - - vb[i].bSyncVars = 0; vb[i].bNeedTexCheck = 1; - memset(vb[i].uCurTex0Data, 0, sizeof(vb[i].uCurTex0Data)); - } - - icurctx = -1; - - glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, s_uFramebuffer ); // switch to the backbuffer - SetFogColor(gs.fogcol); - - GL_REPORT_ERRORD(); - return true; - } - - return false; -} - -void ZeroGS::SaveSnapshot(const char* filename) -{ - g_bMakeSnapshot = 1; - strSnapshot = filename; -} - -bool ZeroGS::SaveRenderTarget(const char* filename, int width, int height, int jpeg) -{ - bool bflip = height < 0; - height = abs(height); - vector data(width*height); - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); - if( glGetError() != GL_NO_ERROR ) - return false; - - if( bflip ) { - // swap scanlines - vector scanline(width); - for(int i = 0; i < height/2; ++i) { - memcpy(&scanline[0], &data[i*width], width*4); - memcpy(&data[i*width], &data[(height-i-1)*width], width*4); - memcpy(&data[(height-i-1)*width], &scanline[0], width*4); - } - } - - if( jpeg ) return SaveJPEG(filename, width, height, &data[0], 70); - - return SaveTGA(filename, width, height, &data[0]); -} - -bool ZeroGS::SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height) -{ - vector data(width*height); - glBindTexture(textarget, tex); - glGetTexImage(textarget, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); - if( glGetError() != GL_NO_ERROR ) { - return false; - } - - return SaveTGA(filename, width, height, &data[0]);//SaveJPEG(filename, width, height, &data[0], 70); -} - -extern "C" { -#ifdef _WIN32 -#define XMD_H -#undef FAR -#define HAVE_BOOLEAN -#endif - -#include "jpeglib.h" -} - -bool ZeroGS::SaveJPEG(const char* filename, int image_width, int image_height, const void* pdata, int quality) -{ - u8* image_buffer = new u8[image_width * image_height * 3]; - u8* psrc = (u8*)pdata; - - // input data is rgba format, so convert to rgb - u8* p = image_buffer; - for(int i = 0; i < image_height; ++i) { - for(int j = 0; j < image_width; ++j) { - p[0] = psrc[0]; - p[1] = psrc[1]; - p[2] = psrc[2]; - p += 3; - psrc += 4; - } - } - - /* This struct contains the JPEG compression parameters and pointers to - * working space (which is allocated as needed by the JPEG library). - * It is possible to have several such structures, representing multiple - * compression/decompression processes, in existence at once. We refer - * to any one struct (and its associated working data) as a "JPEG object". - */ - struct jpeg_compress_struct cinfo; - /* This struct represents a JPEG error handler. It is declared separately - * because applications often want to supply a specialized error handler - * (see the second half of this file for an example). But here we just - * take the easy way out and use the standard error handler, which will - * print a message on stderr and call exit() if compression fails. - * Note that this struct must live as long as the main JPEG parameter - * struct, to avoid dangling-pointer problems. - */ - struct jpeg_error_mgr jerr; - /* More stuff */ - FILE * outfile; /* target file */ - JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ - int row_stride; /* physical row width in image buffer */ - - /* Step 1: allocate and initialize JPEG compression object */ - - /* We have to set up the error handler first, in case the initialization - * step fails. (Unlikely, but it could happen if you are out of memory.) - * This routine fills in the contents of struct jerr, and returns jerr's - * address which we place into the link field in cinfo. - */ - cinfo.err = jpeg_std_error(&jerr); - /* Now we can initialize the JPEG compression object. */ - jpeg_create_compress(&cinfo); - - /* Step 2: specify data destination (eg, a file) */ - /* Note: steps 2 and 3 can be done in either order. */ - - /* Here we use the library-supplied code to send compressed data to a - * stdio stream. You can also write your own code to do something else. - * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that - * requires it in order to write binary files. - */ - if ((outfile = fopen(filename, "wb")) == NULL) { - fprintf(stderr, "can't open %s\n", filename); - exit(1); - } - jpeg_stdio_dest(&cinfo, outfile); - - /* Step 3: set parameters for compression */ - - /* First we supply a description of the input image. - * Four fields of the cinfo struct must be filled in: - */ - cinfo.image_width = image_width; /* image width and height, in pixels */ - cinfo.image_height = image_height; - cinfo.input_components = 3; /* # of color components per pixel */ - cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ - /* Now use the library's routine to set default compression parameters. - * (You must set at least cinfo.in_color_space before calling this, - * since the defaults depend on the source color space.) - */ - jpeg_set_defaults(&cinfo); - /* Now you can set any non-default parameters you wish to. - * Here we just illustrate the use of quality (quantization table) scaling: - */ - jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); - - /* Step 4: Start compressor */ - - /* TRUE ensures that we will write a complete interchange-JPEG file. - * Pass TRUE unless you are very sure of what you're doing. - */ - jpeg_start_compress(&cinfo, TRUE); - - /* Step 5: while (scan lines remain to be written) */ - /* jpeg_write_scanlines(...); */ - - /* Here we use the library's state variable cinfo.next_scanline as the - * loop counter, so that we don't have to keep track ourselves. - * To keep things simple, we pass one scanline per call; you can pass - * more if you wish, though. - */ - row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */ - - while (cinfo.next_scanline < cinfo.image_height) { - /* jpeg_write_scanlines expects an array of pointers to scanlines. - * Here the array is only one element long, but you could pass - * more than one scanline at a time if that's more convenient. - */ - row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; - (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); - } - - /* Step 6: Finish compression */ - - jpeg_finish_compress(&cinfo); - /* After finish_compress, we can close the output file. */ - fclose(outfile); - - /* Step 7: release JPEG compression object */ - - /* This is an important step since it will release a good deal of memory. */ - jpeg_destroy_compress(&cinfo); - - delete image_buffer; - /* And we're done! */ - return true; -} - -#if defined(_MSC_VER) -#pragma pack(push, 1) -#endif - -struct TGA_HEADER -{ - u8 identsize; // size of ID field that follows 18 u8 header (0 usually) - u8 colourmaptype; // type of colour map 0=none, 1=has palette - u8 imagetype; // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed - - s16 colourmapstart; // first colour map entry in palette - s16 colourmaplength; // number of colours in palette - u8 colourmapbits; // number of bits per palette entry 15,16,24,32 - - s16 xstart; // image x origin - s16 ystart; // image y origin - s16 width; // image width in pixels - s16 height; // image height in pixels - u8 bits; // image bits per pixel 8,16,24,32 - u8 descriptor; // image descriptor bits (vh flip bits) - - // pixel data follows header - -#if defined(_MSC_VER) -}; -#pragma pack(pop) -#else -} __attribute__((packed)); -#endif - -bool ZeroGS::SaveTGA(const char* filename, int width, int height, void* pdata) -{ - TGA_HEADER hdr; - FILE* f = fopen(filename, "wb"); - if( f == NULL ) - return false; - - assert( sizeof(TGA_HEADER) == 18 && sizeof(hdr) == 18 ); - - memset(&hdr, 0, sizeof(hdr)); - hdr.imagetype = 2; - hdr.bits = 32; - hdr.width = width; - hdr.height = height; - hdr.descriptor |= 8|(1<<5); // 8bit alpha, flip vertical - - fwrite(&hdr, sizeof(hdr), 1, f); - fwrite(pdata, width*height*4, 1, f); - fclose(f); - return true; -} - -// AVI capture stuff -void ZeroGS::StartCapture() -{ - if( !s_aviinit ) { - -#ifdef _WIN32 - START_AVI("zerogs.avi"); -#else // linux - //TODO -#endif - s_aviinit = 1; - } - else { - ERROR_LOG("Continuing from previous capture"); - } - - s_avicapturing = 1; -} - -void ZeroGS::StopCapture() -{ - s_avicapturing = 0; -} - -void ZeroGS::CaptureFrame() -{ - assert( s_avicapturing && s_aviinit ); - - //vector mem(nBackbufferWidth*nBackbufferHeight); - vector data(nBackbufferWidth*nBackbufferHeight); - glReadPixels(0, 0, nBackbufferWidth, nBackbufferHeight, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); - if( glGetError() != GL_NO_ERROR ) - return; - -// u8* pend = (u8*)&data[0] + (nBackbufferHeight-1)*nBackbufferWidth*4; -// for(int i = 0; i < conf.height; ++i) { -// memcpy_amd(&mem[nBackbufferWidth*4*i], pend - nBackbufferWidth*4*i, nBackbufferWidth * 4); -// } - - int fps = SMODE1->CMOD == 3 ? 50 : 60; - -#ifdef _WIN32 - bool bSuccess = ADD_FRAME_FROM_DIB_TO_AVI("AAAA", fps, nBackbufferWidth, nBackbufferHeight, 32, &data[0]); - - if( !bSuccess ) { - s_avicapturing = 0; - STOP_AVI(); - ZeroGS::AddMessage("Failed to create avi"); - return; - } -#else // linux - //TODO -#endif -} - +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#if defined(_WIN32) +#include +#include + +#include "resource.h" +#endif + +#include + +#include +#include +#include +#include + +#include "GS.h" +#include "Mem.h" +#include "x86.h" +#include "zerogs.h" +#include "zpipe.h" + +#include "ZeroGSShaders/zerogsshaders.h" +#include "targets.h" +#include "rasterfont.h" // simple font + +#define VB_BUFFERSIZE 0x400 +#define VB_NUMBUFFERS 512 +#define SIZEOF_VB sizeof(ZeroGS::VB)//((u32)((u8*)&vb[0].buffers-(u8*)&vb[0])) + +#define MINMAX_SHIFT 3 +#define MAX_ACTIVECLUTS 16 + +#define ZEROGS_SAVEVER 0xaa000005 + +#define STENCIL_ALPHABIT 1 // if set, dest alpha >= 0x80 +#define STENCIL_PIXELWRITE 2 // if set, pixel just written (reset after every Flush) +#define STENCIL_FBA 4 // if set, just written pixel's alpha >= 0 (reset after every Flush) +#define STENCIL_SPECIAL 8 // if set, indicates that pixel passed its alpha test (reset after every Flush) +//#define STENCIL_PBE 16 +#define STENCIL_CLEAR (2|4|8|16) + +#define VBSAVELIMIT ((u32)((u8*)&vb[0].nNextFrameHeight-(u8*)&vb[0])) + +using namespace ZeroGS; + +extern u32 g_nGenVars, g_nTexVars, g_nAlphaVars, g_nResolve; +extern char *libraryName; +extern int g_nFrame, g_nRealFrame; +extern float fFPS; +extern unsigned char zgsrevision, zgsbuild, zgsminor; + +BOOL g_bDisplayMsg = 1; + +#ifdef _WIN32 +HDC hDC=NULL; // Private GDI Device Context +HGLRC hRC=NULL; // Permanent Rendering Context +#endif + +BOOL g_bCRTCBilinear = TRUE; +BOOL g_bSaveFlushedFrame = 0; +BOOL g_bIsLost = 0; +int g_nFrameRender = 10; +int g_nFramesSkipped = 0; + +#ifdef RELEASE_TO_PUBLIC + +#define INC_GENVARS() +#define INC_TEXVARS() +#define INC_ALPHAVARS() +#define INC_RESOLVE() + +#define g_bUpdateEffect 0 +#define g_bSaveTex 0 +#define g_bSaveTrans 0 +#define g_bSaveFrame 0 +#define g_bSaveFinalFrame 0 +#define g_bSaveResolved 0 + +#else + +#define INC_GENVARS() ++g_nGenVars +#define INC_TEXVARS() ++g_nTexVars +#define INC_ALPHAVARS() ++g_nAlphaVars +#define INC_RESOLVE() ++g_nResolve + +BOOL g_bSaveTrans = 0; +BOOL g_bUpdateEffect = 0; +BOOL g_bSaveTex = 0; // saves the curent texture +BOOL g_bSaveFrame = 0; // saves the current psurfTarget +BOOL g_bSaveFinalFrame = 0; // saves the input to the CRTC +BOOL g_bSaveResolved = 0; + +#ifdef _WIN32 +//#define EFFECT_NAME "f:\\ps2dev\\svn\\pcsx2\\ZeroGS\\opengl\\" +char* EFFECT_DIR = "C:\\programming\\ps2dev\\zerogs\\opengl\\"; +char* EFFECT_NAME = "C:\\programming\\ps2dev\\zerogs\\opengl\\ps2hw.fx"; +#else +char EFFECT_DIR[255] = "~/pcsx2/plugins/gs/zerogs/opengl/"; +char EFFECT_NAME[255] = "~/pcsx2/plugins/gs/zerogs/opengl/ps2hw.fx"; +#endif + +#endif + +BOOL g_bUpdateStencil = 1; // only needed for dest alpha test (unfortunately, it has to be on all the time) + +#define DRAW() glDrawArrays(primtype[curvb.curprim.prim], 0, curvb.nCount) + +#define GL_BLEND_RGB(src, dst) { \ + s_srcrgb = src; \ + s_dstrgb = dst; \ + zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha); \ +} + +#define GL_BLEND_ALPHA(src, dst) { \ + s_srcalpha = src; \ + s_dstalpha = dst; \ + zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha); \ +} + +#define GL_BLEND_ALL(srcrgb, dstrgb, srcalpha, dstalpha) { \ + s_srcrgb = srcrgb; \ + s_dstrgb = dstrgb; \ + s_srcalpha = srcalpha; \ + s_dstalpha = dstalpha; \ + zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha); \ +} + +#define GL_BLEND_SET() zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha) + +#define GL_ZTEST(enable) { \ + if( enable ) glEnable(GL_DEPTH_TEST); \ + else glDisable(GL_DEPTH_TEST); \ +} + +#define GL_ALPHATEST(enable) { \ + if( enable ) glEnable(GL_ALPHA_TEST); \ + else glDisable(GL_ALPHA_TEST); \ +} + +#define GL_BLENDEQ_RGB(eq) { \ + s_rgbeq = eq; \ + zgsBlendEquationSeparateEXT(s_rgbeq, s_alphaeq); \ +} + +#define GL_BLENDEQ_ALPHA(eq) { \ + s_alphaeq = eq; \ + zgsBlendEquationSeparateEXT(s_rgbeq, s_alphaeq); \ +} + +#define GL_STENCILFUNC(func, ref, mask) { \ + s_stencilfunc = func; \ + s_stencilref = ref; \ + s_stencilmask = mask; \ + glStencilFunc(func, ref, mask); \ +} + +#define GL_STENCILFUNC_SET() glStencilFunc(s_stencilfunc, s_stencilref, s_stencilmask) + +#define COLORMASK_RED 1 +#define COLORMASK_GREEN 2 +#define COLORMASK_BLUE 4 +#define COLORMASK_ALPHA 8 +#define GL_COLORMASK(mask) glColorMask(!!((mask)&COLORMASK_RED), !!((mask)&COLORMASK_GREEN), !!((mask)&COLORMASK_BLUE), !!((mask)&COLORMASK_ALPHA)) + +typedef void (APIENTRYP _PFNSWAPINTERVAL) (int); + +extern int s_frameskipping; + +static u32 g_SaveFrameNum = 0; +BOOL g_bMakeSnapshot = 0; +string strSnapshot; + +int GPU_TEXWIDTH = 512; +float g_fiGPU_TEXWIDTH = 1/512.0f; + +int g_MaxTexWidth = 4096, g_MaxTexHeight = 4096; +CGprogram g_vsprog = 0, g_psprog = 0; +// AVI Capture +static int s_aviinit = 0; +static int s_avicapturing = 0; + +inline u32 FtoDW(float f) { return (*((u32*)&f)); } + +float g_fBlockMult = 1; +static int s_nFullscreen = 0; +int g_nDepthUpdateCount = 0; +int g_nDepthBias = 0; + +// local alpha blending settings +static GLenum s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha; // set by zgsBlendFuncSeparateEXT +static GLenum s_rgbeq, s_alphaeq; // set by zgsBlendEquationSeparateEXT +static u32 s_stencilfunc, s_stencilref, s_stencilmask; +static GLenum s_drawbuffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT }; + +#ifdef _WIN32 +extern HINSTANCE hInst; + +void (__stdcall *zgsBlendEquationSeparateEXT)(GLenum, GLenum) = NULL; +void (__stdcall *zgsBlendFuncSeparateEXT)(GLenum, GLenum, GLenum, GLenum) = NULL; +#else +void (APIENTRY *zgsBlendEquationSeparateEXT)(GLenum, GLenum) = NULL; +void (APIENTRY *zgsBlendFuncSeparateEXT)(GLenum, GLenum, GLenum, GLenum) = NULL; +#endif + +GLenum g_internalFloatFmt = GL_ALPHA_FLOAT32_ATI; +GLenum g_internalRGBAFloatFmt = GL_RGBA_FLOAT32_ATI; +GLenum g_internalRGBAFloat16Fmt = GL_RGBA_FLOAT16_ATI; + +// Consts +static const GLenum primtype[8] = { GL_POINTS, GL_LINES, GL_LINES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, 0xffffffff }; +static const u32 blendalpha[3] = { GL_SRC_ALPHA, GL_DST_ALPHA, GL_CONSTANT_COLOR_EXT }; +static const u32 blendinvalpha[3] = { GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_CONSTANT_COLOR_EXT }; + +static const int PRIMMASK = 0x0e; // for now ignore 0x10 (AA) + +static const u32 g_dwAlphaCmp[] = { GL_NEVER, GL_ALWAYS, GL_LESS, GL_LEQUAL, GL_EQUAL, GL_GEQUAL, GL_GREATER, GL_NOTEQUAL }; + +// used for afail case +static const u32 g_dwReverseAlphaCmp[] = { GL_ALWAYS, GL_NEVER, GL_GEQUAL, GL_GREATER, GL_NOTEQUAL, GL_LESS, GL_LEQUAL, GL_EQUAL }; + +static const u32 g_dwZCmp[] = { GL_NEVER, GL_ALWAYS, GL_GEQUAL, GL_GREATER }; + +PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT = NULL; +PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT = NULL; +PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT = NULL; +PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT = NULL; +PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT = NULL; +PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT = NULL; +PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = NULL; +PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = NULL; +PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT = NULL; +PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL; +PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL; +PFNGLDRAWBUFFERSPROC glDrawBuffers = NULL; + +///////////////////// +// graphics resources +static map mapGLExtensions; +RasterFont* font_p = NULL; +CGprofile cgvProf, cgfProf; +static CGprogram pvs[16] = {NULL}; +static FRAGMENTSHADER ppsRegular[4], ppsTexture[NUM_SHADERS]; +static FRAGMENTSHADER ppsCRTC[2], ppsCRTC24[2], ppsCRTCTarg[2]; +CGparameter g_vparamPosXY[2] = {0}, g_fparamFogColor = 0; + +int g_nPixelShaderVer = 0; // default + +static u8* s_lpShaderResources = NULL; +static map mapShaderResources; + +u32 s_uFramebuffer = 0; +u32 s_ptexCurSet[2] = {0}; + +#define s_bForceTexFlush 1 +static u32 s_ptexNextSet[2] = {0}; + +u32 ptexBlocks = 0, ptexConv16to32 = 0; // holds information on block tiling +u32 ptexBilinearBlocks = 0; +u32 ptexConv32to16 = 0; +static u32 s_ptexInterlace = 0; // holds interlace fields +static int s_nInterlaceTexWidth = 0; // width of texture +static vector s_vecTempTextures; // temporary textures, released at the end of every frame + +static BOOL s_bTexFlush = FALSE; +static u32 ptexLogo = 0; +static int nLogoWidth, nLogoHeight; +static BOOL s_bWriteDepth = FALSE; +static BOOL s_bDestAlphaTest = FALSE; +static int s_nLastResolveReset = 0; +static int s_nResolveCounts[30] = {0}; // resolve counts for last 30 frames +static int s_nCurResolveIndex = 0; +int s_nResolved = 0; // number of targets resolved this frame +int g_nDepthUsed = 0; // ffx2 pal movies +static int s_nWriteDepthCount = 0; +static int s_nWireframeCount = 0; +static int s_nWriteDestAlphaTest = 0; + +//////////////////// +// State parameters +static float fiRendWidth, fiRendHeight; + +static Vector vAlphaBlendColor; // used for GPU_COLOR + +static u8 bNeedBlendFactorInAlpha; // set if the output source alpha is different from the real source alpha (only when blend factor > 0x80) +static u32 s_dwColorWrite = 0xf; // the color write mask of the current target + +BOOL g_bDisplayFPS = FALSE; + +union { + struct { + u8 _bNeedAlphaColor; // set if vAlphaBlendColor needs to be set + u8 _b2XAlphaTest; // Only valid when bNeedAlphaColor is set. if 1st bit set set, double all alpha testing values + // otherwise alpha testing needs to be done separately. + u8 _bDestAlphaColor; // set to 1 if blending with dest color (process only one tri at a time). If 2, dest alpha is always 1. + u8 _bAlphaClamping; // if first bit is set, do min; if second bit, do max + }; + u32 _bAlphaState; +} g_vars; + +//#define bNeedAlphaColor g_vars._bNeedAlphaColor +#define b2XAlphaTest g_vars._b2XAlphaTest +#define bDestAlphaColor g_vars._bDestAlphaColor +#define bAlphaClamping g_vars._bAlphaClamping + +int g_PrevBitwiseTexX = -1, g_PrevBitwiseTexY = -1; // textures stored in SAMP_BITWISEANDX and SAMP_BITWISEANDY + +// stores the buffers for the last RenderCRTC +const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); + +static alphaInfo s_alphaInfo; + +CGcontext g_cgcontext; +static int nBackbufferWidth, nBackbufferHeight; + +u8* g_pbyGSMemory = NULL; // 4Mb GS system mem +u8* g_pbyGSClut = NULL; + +namespace ZeroGS +{ + VB vb[2]; + float fiTexWidth[2], fiTexHeight[2]; // current tex width and height + + GLuint vboRect = 0; + vector g_vboBuffers; // VBOs for all drawing commands + int g_nCurVBOIndex = 0; + + u8 s_AAx = 0, s_AAy = 0; // if AAy is set, then AAx has to be set + RenderFormatType g_RenderFormatType = RFT_float16; + int icurctx = -1; + + Vector g_vdepth = Vector(256.0f*65536.0f, 65536.0f, 256.0f, 65536.0f*65536.0f); + + VERTEXSHADER pvsBitBlt; + FRAGMENTSHADER ppsBitBlt[2], ppsBitBltDepth, ppsOne; + FRAGMENTSHADER ppsBaseTexture, ppsConvert16to32, ppsConvert32to16; + + extern CRangeManager s_RangeMngr; // manages overwritten memory + void FlushTransferRanges(const tex0Info* ptex); + + RenderFormatType GetRenderFormat() { return g_RenderFormatType; } + GLenum GetRenderTargetFormat() { return GetRenderFormat()==RFT_byte8?4:g_internalRGBAFloat16Fmt; } + + // returns the first and last addresses aligned to a page that cover + void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw); + + bool LoadEffects(); + bool LoadExtraEffects(); + FRAGMENTSHADER* LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context, bool* pbFailed); + + static int s_nNewWidth = -1, s_nNewHeight = -1; + void ChangeDeviceSize(int nNewWidth, int nNewHeight); + + void ProcessMessages(); + void RenderCustom(float fAlpha); // intro anim + + struct MESSAGE + { + MESSAGE() {} + MESSAGE(const char* p, u32 dw) { strcpy(str, p); dwTimeStamp = dw; } + char str[255]; + u32 dwTimeStamp; + }; + + static list listMsgs; + + /////////////////////// + // Method Prototypes // + /////////////////////// + + void AdjustTransToAspect(Vector& v, int dispwidth, int dispheight); + + void KickPoint(); + void KickLine(); + void KickTriangle(); + void KickTriangleFan(); + void KickSprite(); + void KickDummy(); + + __forceinline void SetContextTarget(int context); + + // use to update the state + void SetTexVariables(int context, FRAGMENTSHADER* pfragment, int settexint); + void SetAlphaVariables(const alphaInfo& ainfo); + void ResetAlphaVariables(); + + __forceinline void SetAlphaTestInt(pixTest curtest); + + __forceinline void RenderAlphaTest(const VB& curvb, CGparameter sOneColor); + __forceinline void RenderStencil(const VB& curvb, u32 dwUsingSpecialTesting); + __forceinline void ProcessStencil(const VB& curvb); + __forceinline void RenderFBA(const VB& curvb, CGparameter sOneColor); + __forceinline void ProcessFBA(const VB& curvb, CGparameter sOneColor); + + void ResolveInRange(int start, int end); + + void ExtWrite(); + + __forceinline u32 CreateInterlaceTex(int width) { + if( width == s_nInterlaceTexWidth && s_ptexInterlace != 0 ) return s_ptexInterlace; + + SAFE_RELEASE_TEX(s_ptexInterlace); + s_nInterlaceTexWidth = width; + + vector data(width); + for(int i = 0; i < width; ++i) data[i] = (i&1) ? 0xffffffff : 0; + + glGenTextures(1, &s_ptexInterlace); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, s_ptexInterlace); + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, 4, width, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + GL_REPORT_ERRORD(); + return s_ptexInterlace; + } + + void ResetRenderTarget(int index) { + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+index, GL_TEXTURE_RECTANGLE_NV, 0, 0 ); + } + + DrawFn drawfn[8] = { KickDummy, KickDummy, KickDummy, KickDummy, + KickDummy, KickDummy, KickDummy, KickDummy }; + +}; // end namespace + +/////////////////// +// Context State // +/////////////////// +ZeroGS::VB::VB() +{ + memset(this, 0, SIZEOF_VB); + tex0.tw = 1; + tex0.th = 1; +} + +ZeroGS::VB::~VB() +{ + Destroy(); +} + +void ZeroGS::VB::Destroy() +{ + _aligned_free(pBufferData); pBufferData = NULL; nNumVertices = 0; + + prndr = NULL; + pdepth = NULL; +} + +bool ZeroGS::VB::CheckPrim() +{ + if( (PRIMMASK & prim->_val) != (PRIMMASK & curprim._val) || primtype[prim->prim] != primtype[curprim.prim] ) + return nCount > 0; + + return false; +} + +// upper bound on max possible height +#define GET_MAXHEIGHT(fbp, fbw, psm) ((((0x00100000-64*(fbp))/(fbw))&~0x1f)<<((psm&2)?1:0)) + +#include +static int maxmin = 608; +//static set s_setFBP[2]; // previous frame/zbuf pointers for the last 2 frames +//static int s_nCurFBPSet = 0; +//static map s_mapFrameHeights[2]; +//static int s_nCurFrameMap = 0; + +// a lot of times, target is too big and overwrites the texture using, if tbp != 0, use it to bound +void ZeroGS::VB::CheckFrame(int tbp) +{ + static int bChanged; + if( bNeedZCheck ) { + PRIM_LOG("zbuf_%d: zbp=0x%x psm=0x%x, zmsk=%d\n", ictx, zbuf.zbp, zbuf.psm, zbuf.zmsk); + //zbuf = *zb; + } + + bChanged = 0; + + if( bNeedFrameCheck ) { + + int maxpos = 0x00100000; + + // important to set before calling GetTarg + bNeedFrameCheck = 0; + bNeedZCheck = 0; + + // add constraints of other targets + if( gsfb.fbw > 0 ) { + maxpos = 0x00100000-64*gsfb.fbp; + + // make sure texture is far away from tbp + if( gsfb.fbp < tbp && gsfb.fbp + 0x2000 < tbp) { + maxpos = min(64*(tbp-gsfb.fbp), maxpos); + } + if( prndr != NULL ) { + // offroad uses 0x80 fbp which messes up targets + if( gsfb.fbp + 0x80 < frame.fbp ) { + // special case when double buffering (hamsterball) + maxpos = min(64*(frame.fbp-gsfb.fbp), maxpos); + } + } + if( zbuf.zbp < tbp && !zbuf.zmsk ) { + maxpos = min((tbp-zbuf.zbp)*((zbuf.psm&2)?128:64), maxpos); + } + + // old caching method + if( gsfb.fbp < zbuf.zbp && !zbuf.zmsk ) { // zmsk necessary for KH movie + int temp = 64*(zbuf.zbp-gsfb.fbp);//min( (0x00100000-64*zbuf.zbp) , 64*(zbuf.zbp-gsfb.fbp) ); + maxpos = min(temp, maxpos); + } + + maxpos /= gsfb.fbw; + if( gsfb.psm & 2 ) maxpos *= 2;; + + maxpos = min(gsfb.fbh, maxpos); + maxpos = min(maxmin, maxpos); + //? atelier iris crashes without it + if( maxpos > 256 ) maxpos &= ~0x1f; + } + else { + ERROR_LOG("render target null, ignoring\n"); + //prndr = NULL; + //pdepth = NULL; + return; + } + + gsfb.psm &= 0xf; // shadow tower + + if( prndr != NULL ) { + + // render target + if( prndr->psm != gsfb.psm ) { + // behavior for dest alpha varies + ResetAlphaVariables(); + } + } + + int fbh = (scissor.y1>>MINMAX_SHIFT)+1; + if( fbh > 2 && (fbh&1) ) fbh -= 1; + + if( !(gsfb.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) { + fbh = min(fbh, maxpos); + } + + frame = gsfb; +// if (frame.fbw > 1024) frame.fbw = 1024; + +// if( fbh > 256 && (fbh % m_Blocks[gsfb.psm].height) <= 2 ) { +// // dragon ball z +// fbh -= fbh%m_Blocks[gsfb.psm].height; +// } + if( !(frame.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) + frame.fbh = fbh; + + if( !(frame.psm&2) ) {//|| !(g_GameSettings&GAME_FULL16BITRES) ) { + if( frame.fbh >= 512 ) { + // neopets hack + maxmin = min(maxmin, frame.fbh); + frame.fbh = maxmin; + } + } + + // mgs3 hack to get proper resolution, targets after 0x2000 are usually feedback + /*if( g_MaxRenderedHeight >= 0xe0 && frame.fbp >= 0x2000 ) { + int considerheight = (g_MaxRenderedHeight/8+31)&~31; + if( frame.fbh > considerheight ) + frame.fbh = considerheight; + else if( frame.fbh <= 32 ) + frame.fbh = considerheight; + + if( frame.fbh == considerheight ) { + // stops bad resolves (mgs3) + if( !curprim.abe && (!test.ate || test.atst == 0) ) + s_nResolved |= 0x100; + } + }*/ + + // ffxii hack to stop resolving + if( !(frame.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) { + if( frame.fbp >= 0x3000 && fbh >= 0x1a0 ) { + int endfbp = frame.fbp + frame.fbw*fbh/((gsfb.psm&2)?128:64); + + // see if there is a previous render target in the way, reduce + for(CRenderTargetMngr::MAPTARGETS::iterator itnew = s_RTs.mapTargets.begin(); itnew != s_RTs.mapTargets.end(); ++itnew) { + if( itnew->second->fbp > frame.fbp && endfbp > itnew->second->fbp ) { + endfbp = itnew->second->fbp; + } + } + + frame.fbh = (endfbp-frame.fbp)*((gsfb.psm&2)?128:64)/frame.fbw; + } + } + + CRenderTarget* pprevrndr = prndr; + CDepthTarget* pprevdepth = pdepth; + + // reset so that Resolve doesn't call Flush + prndr = NULL; + pdepth = NULL; + + CRenderTarget* pnewtarg = s_RTs.GetTarg(frame, 0, maxmin); + assert( pnewtarg != NULL ); + + // pnewtarg->fbh >= 0x1c0 needed for ffx + if( pnewtarg->fbh >= 0x1c0 && pnewtarg->fbh > frame.fbh && zbuf.zbp < tbp && !zbuf.zmsk ) { + // check if zbuf is in the way of the texture (suikoden5) + int maxallowedfbh = (tbp-zbuf.zbp)*((zbuf.psm&2)?128:64) / gsfb.fbw; + if( gsfb.psm & 2 ) + maxallowedfbh *= 2; + + if( pnewtarg->fbh > maxallowedfbh+32 ) { // +32 needed for ffx2 + // destroy and recreate + s_RTs.DestroyAllTargs(0, 0x100, pnewtarg->fbw); + pnewtarg = s_RTs.GetTarg(frame, 0, maxmin); + assert( pnewtarg != NULL ); + } + } + + PRIM_LOG("frame_%d: fbp=0x%x fbw=%d fbh=%d(%d) psm=0x%x fbm=0x%x\n", ictx, gsfb.fbp, gsfb.fbw, gsfb.fbh, pnewtarg->fbh, gsfb.psm, gsfb.fbm); + + if( (pprevrndr != pnewtarg) || (prndr != NULL && (prndr->status & CRenderTarget::TS_NeedUpdate)) ) + bChanged = 1; + + prndr = pnewtarg; + + // update z + frameInfo tempfb; + tempfb.fbw = prndr->fbw; + tempfb.fbp = zbuf.zbp; + tempfb.psm = zbuf.psm; + tempfb.fbh = prndr->fbh; + if( zbuf.psm == 0x31 ) + tempfb.fbm = 0xff000000; + else + tempfb.fbm = 0; + + // check if there is a target that exactly aligns with zbuf (zbuf can be cleared this way, gunbird 2) + //u32 key = zbuf.zbp|(frame.fbw<<16); + //CRenderTargetMngr::MAPTARGETS::iterator it = s_RTs.mapTargets.find(key); +// if( it != s_RTs.mapTargets.end() ) { +//#ifdef _DEBUG +// DEBUG_LOG("zbuf resolve\n"); +//#endif +// if( it->second->status & CRenderTarget::TS_Resolved ) +// it->second->Resolve(); +// } + + GL_REPORT_ERRORD(); + CDepthTarget* pnewdepth = (CDepthTarget*)s_DepthRTs.GetTarg(tempfb, CRenderTargetMngr::TO_DepthBuffer | + CRenderTargetMngr::TO_StrictHeight|(zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), + GET_MAXHEIGHT(zbuf.zbp, gsfb.fbw, 0)); + assert( pnewdepth != NULL && prndr != NULL ); + assert( pnewdepth->fbh == prndr->fbh ); + + if( (pprevdepth != pnewdepth) || (pdepth != NULL && (pdepth->status & CRenderTarget::TS_NeedUpdate)) ) + bChanged |= 2; + + pdepth = pnewdepth; + + if( prndr->status & CRenderTarget::TS_NeedConvert32) { + if( pdepth->pdepth != 0 ) + pdepth->SetDepthStencilSurface(); + prndr->fbh *= 2; + prndr->ConvertTo32(); + prndr->status &= ~CRenderTarget::TS_NeedConvert32; + } + else if( prndr->status & CRenderTarget::TS_NeedConvert16 ) { + if( pdepth->pdepth != 0 ) + pdepth->SetDepthStencilSurface(); + prndr->fbh /= 2; + prndr->ConvertTo16(); + prndr->status &= ~CRenderTarget::TS_NeedConvert16; + } + } + else if( bNeedZCheck ) { + + bNeedZCheck = 0; + CDepthTarget* pprevdepth = pdepth; + pdepth = NULL; + + if( prndr != NULL && gsfb.fbw > 0 ) { + // just z changed + frameInfo f; + f.fbp = zbuf.zbp; + f.fbw = prndr->fbw; + f.fbh = prndr->fbh; + f.psm = zbuf.psm; + + if( zbuf.psm == 0x31 ) f.fbm = 0xff000000; + else f.fbm = 0; + CDepthTarget* pnewdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| + (zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), GET_MAXHEIGHT(zbuf.zbp, gsfb.fbw, 0)); + + assert( pnewdepth != NULL && prndr != NULL ); + assert( pnewdepth->fbh == prndr->fbh ); + + if( (pprevdepth != pnewdepth) || (pdepth != NULL && (pdepth->status & CRenderTarget::TS_NeedUpdate)) ) + bChanged = 2; + + pdepth = pnewdepth; + } + } + + if( prndr != NULL ) SetContextTarget(ictx); +} + +void ZeroGS::VB::FlushTexData() +{ + assert( bNeedTexCheck ); + + bNeedTexCheck = 0; + + u32 psm = (uNextTex0Data[0] >> 20) & 0x3f; + if( psm == 9 ) psm = 1; // hmm..., ffx intro menu + + // don't update unless necessary + if( uCurTex0Data[0] == uNextTex0Data[0] && (uCurTex0Data[1]&0x1f) == (uNextTex0Data[1]&0x1f) ) { + + if( PSMT_ISCLUT(psm) ) { + + // have to write the CLUT again if changed + if( (uCurTex0Data[1]&0x1fffffe0) == (uNextTex0Data[1]&0x1fffffe0) ) { + + if( uNextTex0Data[1]&0xe0000000 ) { + //ZeroGS::Flush(ictx); + ZeroGS::texClutWrite(ictx); + // invalidate to make sure target didn't change! + bVarsTexSync = FALSE; + } + + return; + } + + if( (uNextTex0Data[1]&0xe0000000) == 0 ) { + + if( (uCurTex0Data[1]&0x1ff10000) != (uNextTex0Data[1]&0x1ff10000) ) + ZeroGS::Flush(ictx); + + // clut isn't going to be loaded so can ignore, but at least update CSA and CPSM! + uCurTex0Data[1] = (uCurTex0Data[1]&0xe087ffff)|(uNextTex0Data[1]&0x1f780000); + + if( tex0.cpsm <= 1 ) tex0.csa = (uNextTex0Data[1] >> 24) & 0xf; + else tex0.csa = (uNextTex0Data[1] >> 24) & 0x1f; + + tex0.cpsm = (uNextTex0Data[1] >> 19) & 0xe; + ZeroGS::texClutWrite(ictx); + + bVarsTexSync = FALSE; + return; + } + + // fall through + } + else { + //bVarsTexSync = FALSE; + return; + } + } + + ZeroGS::Flush(ictx); + bVarsTexSync = FALSE; + bTexConstsSync = FALSE; + + uCurTex0Data[0] = uNextTex0Data[0]; + uCurTex0Data[1] = uNextTex0Data[1]; + + tex0.tbp0 = (uNextTex0Data[0] & 0x3fff); + tex0.tbw = ((uNextTex0Data[0] >> 14) & 0x3f) * 64; + tex0.psm = psm; + tex0.tw = (uNextTex0Data[0] >> 26) & 0xf; + if (tex0.tw > 10) tex0.tw = 10; + tex0.tw = 1<> 30) & 0x3) | ((uNextTex0Data[1] & 0x3) << 2); + if (tex0.th > 10) tex0.th = 10; + tex0.th = 1<> 2) & 0x1; + tex0.tfx = (uNextTex0Data[1] >> 3) & 0x3; + + ZeroGS::fiTexWidth[ictx] = (1/16.0f)/ tex0.tw; + ZeroGS::fiTexHeight[ictx] = (1/16.0f) / tex0.th; + + if (tex0.tbw == 0) tex0.tbw = 64; + + if( PSMT_ISCLUT(psm) ) { + tex0.cbp = ((uNextTex0Data[1] >> 5) & 0x3fff); + tex0.cpsm = (uNextTex0Data[1] >> 19) & 0xe; + tex0.csm = (uNextTex0Data[1] >> 23) & 0x1; + + if( tex0.cpsm <= 1 ) tex0.csa = (uNextTex0Data[1] >> 24) & 0xf; + else tex0.csa = (uNextTex0Data[1] >> 24) & 0x1f; + + tex0.cld = (uNextTex0Data[1] >> 29) & 0x7; + + ZeroGS::texClutWrite(ictx); + } +} + +// does one time only initializing/destruction +class ZeroGSInit +{ +public: + ZeroGSInit() { + // clear + g_pbyGSMemory = (u8*)_aligned_malloc(0x00410000, 1024); // leave some room for out of range accesses (saves on the checks) + memset(g_pbyGSMemory, 0, 0x00410000); + + g_pbyGSClut = (u8*)_aligned_malloc(256*8, 1024); // need 512 alignment! + memset(g_pbyGSClut, 0, 256*8); + +#ifndef _WIN32 + memset(&GLWin, 0, sizeof(GLWin)); +#endif + } + ~ZeroGSInit() { + _aligned_free(g_pbyGSMemory); g_pbyGSMemory = NULL; + _aligned_free(g_pbyGSClut); g_pbyGSClut = NULL; + } +}; + +static ZeroGSInit s_ZeroGSInit; + +#ifdef _WIN32 +void __stdcall glBlendFuncSeparateDummy(GLenum e1, GLenum e2, GLenum e3, GLenum e4) +#else +void APIENTRY glBlendFuncSeparateDummy(GLenum e1, GLenum e2, GLenum e3, GLenum e4) +#endif +{ + glBlendFunc(e1, e2); +} + +#ifdef _WIN32 +void __stdcall glBlendEquationSeparateDummy(GLenum e1, GLenum e2) +#else +void APIENTRY glBlendEquationSeparateDummy(GLenum e1, GLenum e2) +#endif +{ + glBlendEquation(e1); +} + +void HandleCgError(CGcontext ctx, CGerror err, void* appdata) +{ + ERROR_LOG("Cg error: %s\n", cgGetErrorString(err)); + const char* listing = cgGetLastListing(g_cgcontext); + if( listing != NULL ) DEBUG_LOG(" last listing: %s\n", listing); +// int loc; +// const GLubyte* pstr = glGetString(GL_PROGRAM_ERROR_STRING_ARB); +// if( pstr != NULL ) printf("error at: %s\n"); +// glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &loc); +// DEBUG_LOG("pos: %d\n", loc); +} + +#ifndef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT +#define GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT 0x8CD8 +#endif + +void ZeroGS::HandleGLError() +{ + // check the error status of this framebuffer */ + GLenum error = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + + // if error != GL_FRAMEBUFFER_COMPLETE_EXT, there's an error of some sort + if( error != 0 ) { + int w, h; + GLint fmt; + glGetRenderbufferParameterivEXT(GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_INTERNAL_FORMAT_EXT, &fmt); + glGetRenderbufferParameterivEXT(GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_WIDTH_EXT, &w); + glGetRenderbufferParameterivEXT(GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_HEIGHT_EXT, &h); + + switch(error) + { + case GL_FRAMEBUFFER_COMPLETE_EXT: + break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: + ERROR_LOG("Error! missing a required image/buffer attachment!\n"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: + ERROR_LOG("Error! has no images/buffers attached!\n"); + break; +// case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT: +// ERROR_LOG("Error! has an image/buffer attached in multiple locations!\n"); +// break; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: + ERROR_LOG("Error! has mismatched image/buffer dimensions!\n"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: + ERROR_LOG("Error! colorbuffer attachments have different types!\n"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: + ERROR_LOG("Error! trying to draw to non-attached color buffer!\n"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: + ERROR_LOG("Error! trying to read from a non-attached color buffer!\n"); + break; + case GL_FRAMEBUFFER_UNSUPPORTED_EXT: + ERROR_LOG("Error! format is not supported by current graphics card/driver!\n"); + break; + default: + ERROR_LOG("*UNKNOWN ERROR* reported from glCheckFramebufferStatusEXT() for %s!\n"); + break; + } + } +} + +#ifdef _WIN32 +#define GL_LOADFN(name) { \ + if( (*(void**)&name = (void*)wglGetProcAddress(#name)) == NULL ) { \ + ERROR_LOG("Failed to find %s, exiting\n", #name); \ + } \ +} +#else +// let GLEW take care of it +#define GL_LOADFN(name) +#endif + +bool ZeroGS::IsGLExt( const char* szTargetExtension ) +{ + return mapGLExtensions.find(string(szTargetExtension)) != mapGLExtensions.end(); +} + +bool ZeroGS::Create(int _width, int _height) +{ + GLenum err = GL_NO_ERROR; + bool bSuccess = true; + int i; + + Destroy(1); + GSStateReset(); + + cgSetErrorHandler(HandleCgError, NULL); + g_RenderFormatType = RFT_float16; + + nBackbufferWidth = _width; + nBackbufferHeight = _height; + fiRendWidth = 1.0f / nBackbufferWidth; + fiRendHeight = 1.0f / nBackbufferHeight; + +#ifdef _WIN32 + GLuint PixelFormat; // Holds The Results After Searching For A Match + DWORD dwExStyle; // Window Extended Style + DWORD dwStyle; // Window Style + + RECT rcdesktop; + GetWindowRect(GetDesktopWindow(), &rcdesktop); + + if (conf.options & GSOPTION_FULLSCREEN) { + nBackbufferWidth = rcdesktop.right - rcdesktop.left; + nBackbufferHeight = rcdesktop.bottom - rcdesktop.top; + + DEVMODE dmScreenSettings; + memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); + dmScreenSettings.dmSize=sizeof(dmScreenSettings); + dmScreenSettings.dmPelsWidth = nBackbufferWidth; + dmScreenSettings.dmPelsHeight = nBackbufferHeight; + dmScreenSettings.dmBitsPerPel = 32; + dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; + + // Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar. + if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) + { + if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES) + conf.options &= ~GSOPTION_FULLSCREEN; + else + return false; + } + } + else { + // change to default resolution + ChangeDisplaySettings(NULL, 0); + } + + if( conf.options & GSOPTION_FULLSCREEN) { + dwExStyle=WS_EX_APPWINDOW; + dwStyle=WS_POPUP; + ShowCursor(FALSE); + } + else { + dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; + dwStyle=WS_OVERLAPPEDWINDOW; + } + + RECT rc; + rc.left = 0; rc.top = 0; + rc.right = nBackbufferWidth; rc.bottom = nBackbufferHeight; + AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle); + int X = (rcdesktop.right-rcdesktop.left)/2 - (rc.right-rc.left)/2; + int Y = (rcdesktop.bottom-rcdesktop.top)/2 - (rc.bottom-rc.top)/2; + + SetWindowPos(GShwnd, NULL, X, Y, rc.right-rc.left, rc.bottom-rc.top, SWP_NOREPOSITION|SWP_NOZORDER); + + PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be + { + sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor + 1, // Version Number + PFD_DRAW_TO_WINDOW | // Format Must Support Window + PFD_SUPPORT_OPENGL | // Format Must Support OpenGL + PFD_DOUBLEBUFFER, // Must Support Double Buffering + PFD_TYPE_RGBA, // Request An RGBA Format + 32, // Select Our Color Depth + 0, 0, 0, 0, 0, 0, // Color Bits Ignored + 0, // 8bit Alpha Buffer + 0, // Shift Bit Ignored + 0, // No Accumulation Buffer + 0, 0, 0, 0, // Accumulation Bits Ignored + 24, // 24Bit Z-Buffer (Depth Buffer) + 8, // 8bit Stencil Buffer + 0, // No Auxiliary Buffer + PFD_MAIN_PLANE, // Main Drawing Layer + 0, // Reserved + 0, 0, 0 // Layer Masks Ignored + }; + + if (!(hDC=GetDC(GShwnd))) { + MessageBox(NULL,"(1) Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION); + return false; + } + + if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) { + MessageBox(NULL,"(2) Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION); + return false; + } + + if(!SetPixelFormat(hDC,PixelFormat,&pfd)) { + MessageBox(NULL,"(3) Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION); + return false; + } + + if (!(hRC=wglCreateContext(hDC))) { + MessageBox(NULL,"(4) Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION); + return false; + } + + if(!wglMakeCurrent(hDC,hRC)) { + MessageBox(NULL,"(5) Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION); + return false; + } + +#else + XVisualInfo *vi; + Colormap cmap; + int dpyWidth, dpyHeight; + int glxMajorVersion, glxMinorVersion; + int vidModeMajorVersion, vidModeMinorVersion; + Atom wmDelete; + Window winDummy; + unsigned int borderDummy; + + // attributes for a single buffered visual in RGBA format with at least + // 8 bits per color and a 24 bit depth buffer + int attrListSgl[] = {GLX_RGBA, GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_DEPTH_SIZE, 24, + None}; + + // attributes for a double buffered visual in RGBA format with at least + // 8 bits per color and a 24 bit depth buffer + int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_DEPTH_SIZE, 24, + None }; + + GLWin.fs = !!(conf.options & GSOPTION_FULLSCREEN); + + /* get an appropriate visual */ + vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDbl); + if (vi == NULL) { + vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListSgl); + GLWin.doubleBuffered = False; + ERROR_LOG("Only Singlebuffered Visual!\n"); + } + else { + GLWin.doubleBuffered = True; + ERROR_LOG("Got Doublebuffered Visual!\n"); + } + + glXQueryVersion(GLWin.dpy, &glxMajorVersion, &glxMinorVersion); + ERROR_LOG("glX-Version %d.%d\n", glxMajorVersion, glxMinorVersion); + /* create a GLX context */ + GLWin.ctx = glXCreateContext(GLWin.dpy, vi, 0, GL_TRUE); + /* create a color map */ + cmap = XCreateColormap(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen), + vi->visual, AllocNone); + GLWin.attr.colormap = cmap; + GLWin.attr.border_pixel = 0; + + // get a connection + XF86VidModeQueryVersion(GLWin.dpy, &vidModeMajorVersion, &vidModeMinorVersion); + + if (GLWin.fs) { + + XF86VidModeModeInfo **modes = NULL; + int modeNum = 0; + int bestMode = 0; + + // set best mode to current + bestMode = 0; + ERROR_LOG("XF86VidModeExtension-Version %d.%d\n", vidModeMajorVersion, vidModeMinorVersion); + XF86VidModeGetAllModeLines(GLWin.dpy, GLWin.screen, &modeNum, &modes); + + if( modeNum > 0 && modes != NULL ) { + /* save desktop-resolution before switching modes */ + GLWin.deskMode = *modes[0]; + /* look for mode with requested resolution */ + for (i = 0; i < modeNum; i++) { + if ((modes[i]->hdisplay == _width) && (modes[i]->vdisplay == _height)) { + bestMode = i; + } + } + + XF86VidModeSwitchToMode(GLWin.dpy, GLWin.screen, modes[bestMode]); + XF86VidModeSetViewPort(GLWin.dpy, GLWin.screen, 0, 0); + dpyWidth = modes[bestMode]->hdisplay; + dpyHeight = modes[bestMode]->vdisplay; + ERROR_LOG("Resolution %dx%d\n", dpyWidth, dpyHeight); + XFree(modes); + + /* create a fullscreen window */ + GLWin.attr.override_redirect = True; + GLWin.attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | + StructureNotifyMask; + GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen), + 0, 0, dpyWidth, dpyHeight, 0, vi->depth, InputOutput, vi->visual, + CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, + &GLWin.attr); + XWarpPointer(GLWin.dpy, None, GLWin.win, 0, 0, 0, 0, 0, 0); + XMapRaised(GLWin.dpy, GLWin.win); + XGrabKeyboard(GLWin.dpy, GLWin.win, True, GrabModeAsync, + GrabModeAsync, CurrentTime); + XGrabPointer(GLWin.dpy, GLWin.win, True, ButtonPressMask, + GrabModeAsync, GrabModeAsync, GLWin.win, None, CurrentTime); + } + else { + ERROR_LOG("Failed to start fullscreen. If you received the \n" + "\"XFree86-VidModeExtension\" extension is missing, add\n" + "Load \"extmod\"\n" + "to your X configuration file (under the Module Section)\n"); + GLWin.fs = 0; + } + } + + + if( !GLWin.fs ) { + + //XRootWindow(dpy,screen) + //int X = (rcdesktop.right-rcdesktop.left)/2 - (rc.right-rc.left)/2; + //int Y = (rcdesktop.bottom-rcdesktop.top)/2 - (rc.bottom-rc.top)/2; + + // create a window in window mode + GLWin.attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | + StructureNotifyMask; + GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen), + 0, 0, _width, _height, 0, vi->depth, InputOutput, vi->visual, + CWBorderPixel | CWColormap | CWEventMask, &GLWin.attr); + // only set window title and handle wm_delete_events if in windowed mode + wmDelete = XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", True); + XSetWMProtocols(GLWin.dpy, GLWin.win, &wmDelete, 1); + XSetStandardProperties(GLWin.dpy, GLWin.win, "ZeroGS", + "ZeroGS", None, NULL, 0, NULL); + XMapRaised(GLWin.dpy, GLWin.win); + } + + // connect the glx-context to the window + glXMakeCurrent(GLWin.dpy, GLWin.win, GLWin.ctx); + XGetGeometry(GLWin.dpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y, + &GLWin.width, &GLWin.height, &borderDummy, &GLWin.depth); + ERROR_LOG("Depth %d\n", GLWin.depth); + if (glXIsDirect(GLWin.dpy, GLWin.ctx)) + ERROR_LOG("you have Direct Rendering!\n"); + else + ERROR_LOG("no Direct Rendering possible!\n"); + + // better for pad plugin key input (thc) + XSelectInput(GLWin.dpy, GLWin.win, ExposureMask | KeyPressMask | KeyReleaseMask | + ButtonPressMask | StructureNotifyMask | EnterWindowMask | LeaveWindowMask | + FocusChangeMask ); + +#endif + + // fill the opengl extension map + const char* ptoken = (const char*)glGetString( GL_EXTENSIONS ); + if( ptoken == NULL ) return false; + + int prevlog = conf.log; + conf.log = 1; + GS_LOG("Supported OpenGL Extensions:\n%s\n", ptoken); // write to the log file + conf.log = prevlog; + + // insert all exts into mapGLExtensions + + const char* pend = NULL; + + while(ptoken != NULL ) { + pend = strchr(ptoken, ' '); + + if( pend != NULL ) { + mapGLExtensions[string(ptoken, pend-ptoken)]; + } + else { + mapGLExtensions[string(ptoken)]; + break; + } + + ptoken = pend; + while(*ptoken == ' ') ++ptoken; + } + + s_nFullscreen = (conf.options & GSOPTION_FULLSCREEN) ? 1 : 0; + conf.mrtdepth = 0; // for now + +#ifndef _WIN32 + int const glew_ok = glewInit(); + if( glew_ok != GLEW_OK ) { + ERROR_LOG("glewInit() is not ok!\n"); + return false; + } +#endif + + if( !IsGLExt("GL_EXT_framebuffer_object") ) { + ERROR_LOG("*********\nZeroGS: ERROR: Need GL_EXT_framebufer_object for multiple render targets\nZeroGS: *********\n"); + bSuccess = false; + } + if( !IsGLExt("GL_EXT_blend_equation_separate") || glBlendEquationSeparateEXT == NULL ) { + ERROR_LOG("*********\nZeroGS: OGL WARNING: Need GL_EXT_blend_equation_separate\nZeroGS: *********\n"); + zgsBlendEquationSeparateEXT = glBlendEquationSeparateDummy; + } + else { + zgsBlendEquationSeparateEXT = glBlendEquationSeparateEXT; + } + + if( !IsGLExt("GL_EXT_blend_func_separate") || glBlendFuncSeparateEXT == NULL ) { + ERROR_LOG("*********\nZeroGS: OGL WARNING: Need GL_EXT_blend_func_separate\nZeroGS: *********\n"); + zgsBlendFuncSeparateEXT = glBlendFuncSeparateDummy; + } + else { + zgsBlendFuncSeparateEXT = glBlendFuncSeparateEXT; + } + + if( !IsGLExt("GL_EXT_secondary_color") ) { + ERROR_LOG("*********\nZeroGS: OGL WARNING: Need GL_EXT_secondary_color\nZeroGS: *********\n"); + bSuccess = false; + } + + if( !IsGLExt("GL_ARB_draw_buffers") && !IsGLExt("GL_ATI_draw_buffers") ) { + ERROR_LOG("*********\nZeroGS: OGL WARNING: multiple render targets not supported, some effects might look bad\nZeroGS: *********\n"); + conf.mrtdepth = 0; + } + + if( !bSuccess ) + return false; + + if( g_GameSettings & GAME_32BITTARGS ) { + g_RenderFormatType = RFT_byte8; + ERROR_LOG("Setting 32 bit render target\n"); + } + else { + if( !IsGLExt("GL_NV_float_buffer") && !IsGLExt("GL_ARB_color_buffer_float") && !IsGLExt("ATI_pixel_format_float") ) { + ERROR_LOG("******\nZeroGS: GS WARNING: Floating point render targets not supported, switching to 32bit\nZeroGS: *********\n"); + g_RenderFormatType = RFT_byte8; + } + } + g_RenderFormatType = RFT_byte8; + +#ifdef _WIN32 + if( IsGLExt("WGL_EXT_swap_control") || IsGLExt("EXT_swap_control") ) + wglSwapIntervalEXT(0); +#else + if( IsGLExt("GLX_SGI_swap_control") ) { + _PFNSWAPINTERVAL swapinterval = (_PFNSWAPINTERVAL)wglGetProcAddress("glXSwapInterval"); + if( !swapinterval ) + swapinterval = (_PFNSWAPINTERVAL)wglGetProcAddress("glXSwapIntervalSGI"); + if( !swapinterval ) + swapinterval = (_PFNSWAPINTERVAL)wglGetProcAddress("glXSwapIntervalEXT"); + + if( swapinterval ) + swapinterval(0); + else + ERROR_LOG("no support for SwapInterval (framerate clamped to monitor refresh rate)\n"); + } +#endif + + // check the max texture width and height + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &g_MaxTexWidth); + g_MaxTexHeight = g_MaxTexWidth; + GPU_TEXWIDTH = g_MaxTexWidth/8; + g_fiGPU_TEXWIDTH = 1.0f / GPU_TEXWIDTH; + +#ifdef RELEASE_TO_PUBLIC +#ifdef _WIN32 + HRSRC hShaderSrc = FindResource(hInst, MAKEINTRESOURCE(IDR_SHADERS), RT_RCDATA); + assert( hShaderSrc != NULL ); + HGLOBAL hShaderGlob = LoadResource(hInst, hShaderSrc); + assert( hShaderGlob != NULL ); + s_lpShaderResources = (u8*)LockResource(hShaderGlob); +#else + FILE* fres = fopen("ps2hw.dat", "rb"); + if( fres == NULL ) { + fres = fopen("plugins/ps2hw.dat", "rb"); + if( fres == NULL ) { + ERROR_LOG("Cannot find ps2hw.dat in working directory. Exiting\n"); + return false; + } + } + fseek(fres, 0, SEEK_END); + size_t s = ftell(fres); + s_lpShaderResources = new u8[s+1]; + fseek(fres, 0, SEEK_SET); + fread(s_lpShaderResources, s, 1, fres); + s_lpShaderResources[s] = 0; +#endif + +#else + +#ifndef _WIN32 + // test if ps2hw.fx exists + char tempstr[255]; + char curwd[255]; + getcwd(curwd, ARRAY_SIZE(curwd)); + + strcpy(tempstr, "../plugins/gs/zerogs/opengl/"); + sprintf(EFFECT_NAME, "%sps2hw.fx", tempstr); + FILE* f = fopen(EFFECT_NAME, "r"); + if( f == NULL ) { + + strcpy(tempstr, "../../plugins/gs/zerogs/opengl/"); + sprintf(EFFECT_NAME, "%sps2hw.fx", tempstr); + f = fopen(EFFECT_NAME, "r"); + + if( f == NULL ) { + ERROR_LOG("Failed to find %s, try compiling a non-devbuild\n", EFFECT_NAME); + return false; + } + } + + fclose(f); + + sprintf(EFFECT_DIR, "%s/%s", curwd, tempstr); + sprintf(EFFECT_NAME, "%sps2hw.fx", EFFECT_DIR); +#endif + +#endif // RELEASE_TO_PUBLIC + + // load the effect, find the best profiles (if any) + if( cgGLIsProfileSupported(CG_PROFILE_ARBVP1) != CG_TRUE ) { + ERROR_LOG("arbvp1 not supported\n"); + return false; + } + if( cgGLIsProfileSupported(CG_PROFILE_ARBFP1) != CG_TRUE ) { + ERROR_LOG("arbfp1 not supported\n"); + return false; + } + + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + s_srcrgb = s_dstrgb = s_srcalpha = s_dstalpha = GL_ONE; + + GL_LOADFN(glIsRenderbufferEXT); + GL_LOADFN(glBindRenderbufferEXT); + GL_LOADFN(glDeleteRenderbuffersEXT); + GL_LOADFN(glGenRenderbuffersEXT); + GL_LOADFN(glRenderbufferStorageEXT); + GL_LOADFN(glGetRenderbufferParameterivEXT); + GL_LOADFN(glIsFramebufferEXT); + GL_LOADFN(glBindFramebufferEXT); + GL_LOADFN(glDeleteFramebuffersEXT); + GL_LOADFN(glGenFramebuffersEXT); + GL_LOADFN(glCheckFramebufferStatusEXT); + GL_LOADFN(glFramebufferTexture1DEXT); + GL_LOADFN(glFramebufferTexture2DEXT); + GL_LOADFN(glFramebufferTexture3DEXT); + GL_LOADFN(glFramebufferRenderbufferEXT); + GL_LOADFN(glGetFramebufferAttachmentParameterivEXT); + GL_LOADFN(glGenerateMipmapEXT); + + if( IsGLExt("GL_ARB_draw_buffers") ) + glDrawBuffers = (PFNGLDRAWBUFFERSPROC)wglGetProcAddress("glDrawBuffers"); + else if( IsGLExt("GL_ATI_draw_buffers") ) + glDrawBuffers = (PFNGLDRAWBUFFERSPROC)wglGetProcAddress("glDrawBuffersATI"); + + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); + + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + glGenFramebuffersEXT( 1, &s_uFramebuffer); + if( s_uFramebuffer == 0 ) { + ERROR_LOG("failed to create the renderbuffer\n"); + } + + assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); + glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, s_uFramebuffer ); + + if( glDrawBuffers != NULL ) + glDrawBuffers(1, s_drawbuffers); + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + font_p = new RasterFont(); + + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + // init draw fns + drawfn[0] = KickPoint; + drawfn[1] = KickLine; + drawfn[2] = KickLine; + drawfn[3] = KickTriangle; + drawfn[4] = KickTriangle; + drawfn[5] = KickTriangleFan; + drawfn[6] = KickSprite; + drawfn[7] = KickDummy; + + SetAA(conf.aa); + GSsetGameCRC(g_LastCRC, g_GameSettings); + GL_STENCILFUNC(GL_ALWAYS, 0, 0); + + //g_GameSettings |= 0;//GAME_VSSHACK|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE|GAME_FASTUPDATE; + //s_bWriteDepth = TRUE; + + GL_BLEND_ALL(GL_ONE, GL_ONE, GL_ONE, GL_ONE); + + glViewport(0,0,nBackbufferWidth,nBackbufferHeight); // Reset The Current Viewport + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glShadeModel(GL_SMOOTH); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClearDepth(1.0f); + glEnable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glDepthFunc(GL_LEQUAL); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations + + glGenTextures(1, &ptexLogo); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexLogo); + +#ifdef _WIN32 + HRSRC hBitmapSrc = FindResource(hInst, MAKEINTRESOURCE(IDB_ZEROGSLOGO), RT_BITMAP); + assert( hBitmapSrc != NULL ); + HGLOBAL hBitmapGlob = LoadResource(hInst, hBitmapSrc); + assert( hBitmapGlob != NULL ); + PBITMAPINFO pinfo = (PBITMAPINFO)LockResource(hBitmapGlob); + + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, 4, pinfo->bmiHeader.biWidth, pinfo->bmiHeader.biHeight, 0, pinfo->bmiHeader.biBitCount==32?GL_RGBA:GL_RGB, GL_UNSIGNED_BYTE, (u8*)pinfo+pinfo->bmiHeader.biSize); + nLogoWidth = pinfo->bmiHeader.biWidth; + nLogoHeight = pinfo->bmiHeader.biHeight; + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +#else +#endif + + GL_REPORT_ERROR(); + + g_nCurVBOIndex = 0; + g_vboBuffers.resize(VB_NUMBUFFERS); + glGenBuffers((GLsizei)g_vboBuffers.size(), &g_vboBuffers[0]); + for(i = 0; i < (int)g_vboBuffers.size(); ++i) { + glBindBuffer(GL_ARRAY_BUFFER, g_vboBuffers[i]); + glBufferData(GL_ARRAY_BUFFER, 0x100*sizeof(VertexGPU), NULL, GL_STREAM_DRAW); + } + + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + // create the blocks texture + g_fBlockMult = 1; + + vector vBlockData, vBilinearData; + BLOCK::FillBlocks(vBlockData, vBilinearData, 1); + + glGenTextures(1, &ptexBlocks); + glBindTexture(GL_TEXTURE_2D, ptexBlocks); + + g_internalFloatFmt = GL_ALPHA_FLOAT32_ATI; + g_internalRGBAFloatFmt = GL_RGBA_FLOAT32_ATI; + g_internalRGBAFloat16Fmt = GL_RGBA_FLOAT16_ATI; + + glTexImage2D(GL_TEXTURE_2D, 0, g_internalFloatFmt, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_ALPHA, GL_FLOAT, &vBlockData[0]); + + if( glGetError() != GL_NO_ERROR ) { + // try different internal format + g_internalFloatFmt = GL_FLOAT_R32_NV; + glTexImage2D(GL_TEXTURE_2D, 0, g_internalFloatFmt, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_RED, GL_FLOAT, &vBlockData[0]); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + if( glGetError() != GL_NO_ERROR ) { + + // error, resort to 16bit + g_fBlockMult = 65535.0f*(float)g_fiGPU_TEXWIDTH; + + BLOCK::FillBlocks(vBlockData, vBilinearData, 0); + glTexImage2D(GL_TEXTURE_2D, 0, 2, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_R, GL_UNSIGNED_SHORT, &vBlockData[0]); + if( glGetError() != GL_NO_ERROR ) + return false; + } + else { + // fill in the bilinear blocks + glGenTextures(1, &ptexBilinearBlocks); + glBindTexture(GL_TEXTURE_2D, ptexBilinearBlocks); + glTexImage2D(GL_TEXTURE_2D, 0, g_internalRGBAFloatFmt, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_RGBA, GL_FLOAT, &vBilinearData[0]); + + if( glGetError() != GL_NO_ERROR ) { + g_internalRGBAFloatFmt = GL_FLOAT_RGBA32_NV; + g_internalRGBAFloat16Fmt = GL_FLOAT_RGBA16_NV; + glTexImage2D(GL_TEXTURE_2D, 0, g_internalRGBAFloatFmt, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_RGBA, GL_FLOAT, &vBilinearData[0]); + B_G(glGetError() == GL_NO_ERROR, return false); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + + float fpri = 1; + glPrioritizeTextures(1, &ptexBlocks, &fpri); + if( ptexBilinearBlocks != 0 ) + glPrioritizeTextures(1, &ptexBilinearBlocks, &fpri); + + GL_REPORT_ERROR(); + + // fill a simple rect + glGenBuffers(1, &vboRect); + glBindBuffer(GL_ARRAY_BUFFER, vboRect); + + vector verts(4); + VertexGPU* pvert = &verts[0]; + pvert->x = -0x7fff; pvert->y = 0x7fff; pvert->z = 0; pvert->s = 0; pvert->t = 0; pvert++; + pvert->x = 0x7fff; pvert->y = 0x7fff; pvert->z = 0; pvert->s = 1; pvert->t = 0; pvert++; + pvert->x = -0x7fff; pvert->y = -0x7fff; pvert->z = 0; pvert->s = 0; pvert->t = 1; pvert++; + pvert->x = 0x7fff; pvert->y = -0x7fff; pvert->z = 0; pvert->s = 1; pvert->t = 1; pvert++; + glBufferDataARB(GL_ARRAY_BUFFER, 4*sizeof(VertexGPU), &verts[0], GL_STATIC_DRAW); + + // setup the default vertex declaration + glEnableClientState(GL_VERTEX_ARRAY); + glClientActiveTexture(GL_TEXTURE0); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_SECONDARY_COLOR_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + GL_REPORT_ERROR(); + + // some cards don't support this +// glClientActiveTexture(GL_TEXTURE0); +// glEnableClientState(GL_TEXTURE_COORD_ARRAY); +// glTexCoordPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexGPU), (void*)12); + + // create the conversion textures + glGenTextures(1, &ptexConv16to32); + glBindTexture(GL_TEXTURE_2D, ptexConv16to32); + + vector conv16to32data(256*256); + for(i = 0; i < 256*256; ++i) { + u32 tempcol = RGBA16to32(i); + // have to flip r and b + conv16to32data[i] = (tempcol&0xff00ff00)|((tempcol&0xff)<<16)|((tempcol&0xff0000)>>16); + } + glTexImage2D(GL_TEXTURE_2D, 0, 4, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, &conv16to32data[0]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + vector conv32to16data(32*32*32); + + glGenTextures(1, &ptexConv32to16); + glBindTexture(GL_TEXTURE_3D, ptexConv32to16); + u32* dst = &conv32to16data[0]; + for(i = 0; i < 32; ++i) { + for(int j = 0; j < 32; ++j) { + for(int k = 0; k < 32; ++k) { + u32 col = (i<<10)|(j<<5)|k; + *dst++ = ((col&0xff)<<16)|(col&0xff00); + } + } + } + glTexImage3D(GL_TEXTURE_3D, 0, 4, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, &conv32to16data[0]); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP); + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + g_cgcontext = cgCreateContext(); + + cgvProf = CG_PROFILE_ARBVP1; + cgfProf = CG_PROFILE_ARBFP1; + cgGLEnableProfile(cgvProf); + cgGLEnableProfile(cgfProf); + cgGLSetOptimalOptions(cgvProf); + cgGLSetOptimalOptions(cgfProf); + + cgGLSetManageTextureParameters(g_cgcontext, CG_FALSE); + //cgSetAutoCompile(g_cgcontext, CG_COMPILE_IMMEDIATE); + + g_fparamFogColor = cgCreateParameter(g_cgcontext, CG_FLOAT4); + g_vparamPosXY[0] = cgCreateParameter(g_cgcontext, CG_FLOAT4); + g_vparamPosXY[1] = cgCreateParameter(g_cgcontext, CG_FLOAT4); + + ERROR_LOG("Creating effects\n"); + B_G(LoadEffects(), return false); + + g_bDisplayMsg = 0; + + + // create a sample shader + clampInfo temp; + memset(&temp, 0, sizeof(temp)); + temp.wms = 3; temp.wmt = 3; + + g_nPixelShaderVer = SHADER_ACCURATE; + // test + bool bFailed; + FRAGMENTSHADER* pfrag = LoadShadeEffect(0, 1, 1, 1, 1, temp, 0, &bFailed); + if( bFailed || pfrag == NULL ) { + g_nPixelShaderVer = SHADER_ACCURATE|SHADER_REDUCED; + + pfrag = LoadShadeEffect(0, 0, 1, 1, 0, temp, 0, &bFailed); + if( pfrag != NULL ) + cgGLLoadProgram(pfrag->prog); + if( bFailed || pfrag == NULL || cgGetError() != CG_NO_ERROR ) { + g_nPixelShaderVer = SHADER_REDUCED; + ERROR_LOG("Basic shader test failed\n"); + } + } + + g_bDisplayMsg = 1; + if( g_nPixelShaderVer & SHADER_REDUCED ) + conf.bilinear = 0; + + ERROR_LOG("Creating extra effects\n"); + B_G(LoadExtraEffects(), return false); + + ERROR_LOG("using %s shaders\n", g_pShaders[g_nPixelShaderVer]); + + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + glDisable(GL_STENCIL_TEST); + glEnable(GL_SCISSOR_TEST); + + GL_BLEND_ALPHA(GL_ONE, GL_ZERO); + glBlendColorEXT(0, 0, 0, 0.5f); + + glDisable(GL_CULL_FACE); + + // points + // This was changed in SetAA - should we be changing it back? + glPointSize(1.0f); + g_nDepthBias = 0; + glEnable(GL_POLYGON_OFFSET_FILL); + glEnable(GL_POLYGON_OFFSET_LINE); + glPolygonOffset(0, 1); + + vb[0].Init(VB_BUFFERSIZE); + vb[1].Init(VB_BUFFERSIZE); + g_bSaveFlushedFrame = 1; + + g_vsprog = g_psprog = 0; + + return glGetError() == GL_NO_ERROR && bSuccess; +} + +void ZeroGS::Destroy(BOOL bD3D) +{ + if( s_aviinit ) { + StopCapture(); + +#ifdef _WIN32 + STOP_AVI(); +#else // linux + //TODO +#endif + ERROR_LOG("zerogs.avi stopped"); + s_aviinit = 0; + } + + g_MemTargs.Destroy(); + s_RTs.Destroy(); + s_DepthRTs.Destroy(); + s_BitwiseTextures.Destroy(); + + SAFE_RELEASE_TEX(s_ptexInterlace); + SAFE_RELEASE_TEX(ptexBlocks); + SAFE_RELEASE_TEX(ptexBilinearBlocks); + SAFE_RELEASE_TEX(ptexConv16to32); + SAFE_RELEASE_TEX(ptexConv32to16); + + vb[0].Destroy(); + vb[1].Destroy(); + + if( g_vboBuffers.size() > 0 ) { + glDeleteBuffers((GLsizei)g_vboBuffers.size(), &g_vboBuffers[0]); + g_vboBuffers.clear(); + } + g_nCurVBOIndex = 0; + + for(int i = 0; i < ARRAY_SIZE(pvs); ++i) { + SAFE_RELEASE_PROG(pvs[i]); + } + for(int i = 0; i < ARRAY_SIZE(ppsRegular); ++i) { + SAFE_RELEASE_PROG(ppsRegular[i].prog); + } + for(int i = 0; i < ARRAY_SIZE(ppsTexture); ++i) { + SAFE_RELEASE_PROG(ppsTexture[i].prog); + } + + SAFE_RELEASE_PROG(pvsBitBlt.prog); + SAFE_RELEASE_PROG(ppsBitBlt[0].prog); SAFE_RELEASE_PROG(ppsBitBlt[1].prog); + SAFE_RELEASE_PROG(ppsBitBltDepth.prog); + SAFE_RELEASE_PROG(ppsCRTCTarg[0].prog); SAFE_RELEASE_PROG(ppsCRTCTarg[1].prog); + SAFE_RELEASE_PROG(ppsCRTC[0].prog); SAFE_RELEASE_PROG(ppsCRTC[1].prog); + SAFE_RELEASE_PROG(ppsCRTC24[0].prog); SAFE_RELEASE_PROG(ppsCRTC24[1].prog); + SAFE_RELEASE_PROG(ppsOne.prog); + + SAFE_DELETE(font_p); + +#ifdef _WIN32 + if (hRC) // Do We Have A Rendering Context? + { + if (!wglMakeCurrent(NULL,NULL)) // Are We Able To Release The DC And RC Contexts? + { + MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); + } + + if (!wglDeleteContext(hRC)) // Are We Able To Delete The RC? + { + MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); + } + hRC=NULL; // Set RC To NULL + } + + if (hDC && !ReleaseDC(GShwnd,hDC)) // Are We Able To Release The DC + { + MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); + hDC=NULL; // Set DC To NULL + } +#else // linux + if (GLWin.ctx) + { + if (!glXMakeCurrent(GLWin.dpy, None, NULL)) + { + ERROR_LOG("Could not release drawing context.\n"); + } + glXDestroyContext(GLWin.dpy, GLWin.ctx); + GLWin.ctx = NULL; + } + /* switch back to original desktop resolution if we were in fs */ + if( GLWin.dpy != NULL ) { + if (GLWin.fs) { + XF86VidModeSwitchToMode(GLWin.dpy, GLWin.screen, &GLWin.deskMode); + XF86VidModeSetViewPort(GLWin.dpy, GLWin.screen, 0, 0); + } + } +#endif + + mapGLExtensions.clear(); +} + +void ZeroGS::GSStateReset() +{ + icurctx = -1; + + for(int i = 0; i < 2; ++i) { + vb[i].Destroy(); + memset(&vb[i], 0, SIZEOF_VB); + + vb[i].tex0.tw = 1; + vb[i].tex0.th = 1; + vb[i].scissor.x1 = 639; + vb[i].scissor.y1 = 479; + vb[i].tex0.tbw = 64; + vb[i].Init(VB_BUFFERSIZE); + } + + s_RangeMngr.Clear(); + g_MemTargs.Destroy(); + s_RTs.Destroy(); + s_DepthRTs.Destroy(); + s_BitwiseTextures.Destroy(); + + vb[0].ictx = 0; + vb[1].ictx = 1; +} + +void ZeroGS::AddMessage(const char* pstr, u32 ms) +{ + listMsgs.push_back(MESSAGE(pstr, timeGetTime()+ms)); +} + +void ZeroGS::DrawText(const char* pstr, int left, int top, u32 color) +{ + cgGLDisableProfile(cgvProf); + cgGLDisableProfile(cgfProf); + + glColor3f(((color>>16)&0xff)/255.0f, ((color>>8)&0xff)/255.0f, (color&0xff)/255.0f); + + font_p->printString(pstr, left * 2.0f / (float)nBackbufferWidth - 1, 1 - top * 2.0f / (float)nBackbufferHeight,0); + cgGLEnableProfile(cgvProf); + cgGLEnableProfile(cgfProf); +} + +void ZeroGS::ChangeWindowSize(int nNewWidth, int nNewHeight) +{ + nBackbufferWidth = nNewWidth > 16 ? nNewWidth : 16; + nBackbufferHeight = nNewHeight > 16 ? nNewHeight : 16; + + if( !(conf.options & GSOPTION_FULLSCREEN) ) { + conf.width = nNewWidth; + conf.height = nNewHeight; + //SaveConfig(); + } +} + +void ZeroGS::SetChangeDeviceSize(int nNewWidth, int nNewHeight) +{ + s_nNewWidth = nNewWidth; + s_nNewHeight = nNewHeight; + + if( !(conf.options & GSOPTION_FULLSCREEN) ) { + conf.width = nNewWidth; + conf.height = nNewHeight; + //SaveConfig(); + } +} + +void ZeroGS::Reset() +{ + s_RTs.ResolveAll(); + s_DepthRTs.ResolveAll(); + + vb[0].nCount = 0; + vb[1].nCount = 0; + + memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); + s_nLastResolveReset = 0; + + icurctx = -1; + g_vsprog = g_psprog = 0; + + GSStateReset(); + Destroy(0); + + drawfn[0] = KickDummy; + drawfn[1] = KickDummy; + drawfn[2] = KickDummy; + drawfn[3] = KickDummy; + drawfn[4] = KickDummy; + drawfn[5] = KickDummy; + drawfn[6] = KickDummy; + drawfn[7] = KickDummy; +} + +void ZeroGS::ChangeDeviceSize(int nNewWidth, int nNewHeight) +{ + int oldscreen = s_nFullscreen; + + int oldwidth = nBackbufferWidth, oldheight = nBackbufferHeight; + if( !Create(nNewWidth&~7, nNewHeight&~7) ) { + ERROR_LOG("Failed to recreate, changing to old\n"); + if( !Create(oldwidth, oldheight) ) { + SysMessage("failed to create dev, exiting...\n"); + exit(0); + } + } + + for(int i = 0; i < 2; ++i) { + vb[i].bNeedFrameCheck = vb[i].bNeedZCheck = 1; + vb[i].CheckFrame(0); + } + + if( oldscreen && !(conf.options & GSOPTION_FULLSCREEN) ) { // if transitioning from full screen + RECT rc; + rc.left = 0; rc.top = 0; + rc.right = conf.width; rc.bottom = conf.height; + +#ifdef _WIN32 + AdjustWindowRect(&rc, conf.winstyle, FALSE); + + RECT rcdesktop; + GetWindowRect(GetDesktopWindow(), &rcdesktop); + + SetWindowLong( GShwnd, GWL_STYLE, conf.winstyle ); + SetWindowPos(GShwnd, HWND_TOP, ((rcdesktop.right-rcdesktop.left)-(rc.right-rc.left))/2, + ((rcdesktop.bottom-rcdesktop.top)-(rc.bottom-rc.top))/2, + rc.right-rc.left, rc.bottom-rc.top, SWP_SHOWWINDOW); + UpdateWindow(GShwnd); +#else // linux +#endif + } + + assert( vb[0].pBufferData != NULL && vb[1].pBufferData != NULL ); +} + +void ZeroGS::SetAA(int mode) +{ + float f; + + // need to flush all targets + s_RTs.ResolveAll(); + s_RTs.Destroy(); + s_DepthRTs.ResolveAll(); + s_DepthRTs.Destroy(); + + s_AAx = s_AAy = 0; // This is code for x0, x2, x4, x8 and x16 anti-aliasing. + if (mode > 0) + { + s_AAx = (mode+1) / 2; // ( 1, 0 ) ; ( 1, 1 ) ; ( 2, 1 ) ; ( 2, 2 ) -- it's used as binary shift, so x >> s_AAx, y >> s_AAy + s_AAy = mode / 2; + } + + memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); + s_nLastResolveReset = 0; + + vb[0].prndr = NULL; vb[0].pdepth = NULL; vb[0].bNeedFrameCheck = 1; vb[0].bNeedZCheck = 1; + vb[1].prndr = NULL; vb[1].pdepth = NULL; vb[1].bNeedFrameCheck = 1; vb[1].bNeedZCheck = 1; + + f = mode > 0 ? 2.0f : 1.0f; + glPointSize(f); +} + +#define SET_UNIFORMPARAM(var, name) { \ + p = cgGetNamedParameter(pf->prog, name); \ + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) \ + pf->var = p; \ +} \ + +void SetupFragmentProgramParameters(FRAGMENTSHADER* pf, int context, int type) +{ + // uniform parameters + CGparameter p; + + p = cgGetNamedParameter(pf->prog, "g_fFogColor"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + cgConnectParameter(g_fparamFogColor, p); + } + + SET_UNIFORMPARAM(sOneColor, "g_fOneColor"); + SET_UNIFORMPARAM(sBitBltZ, "g_fBitBltZ"); + SET_UNIFORMPARAM(sInvTexDims, "g_fInvTexDims"); + SET_UNIFORMPARAM(fTexAlpha2, "fTexAlpha2"); + SET_UNIFORMPARAM(fTexOffset, "g_fTexOffset"); + SET_UNIFORMPARAM(fTexDims, "g_fTexDims"); + SET_UNIFORMPARAM(fTexBlock, "g_fTexBlock"); + SET_UNIFORMPARAM(fClampExts, "g_fClampExts"); + SET_UNIFORMPARAM(fTexWrapMode, "TexWrapMode"); + SET_UNIFORMPARAM(fRealTexDims, "g_fRealTexDims"); + SET_UNIFORMPARAM(fTestBlack, "g_fTestBlack"); + SET_UNIFORMPARAM(fPageOffset, "g_fPageOffset"); + SET_UNIFORMPARAM(fTexAlpha, "fTexAlpha"); + + // textures + p = cgGetNamedParameter(pf->prog, "g_sBlocks"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + cgGLSetTextureParameter(p, ptexBlocks); + cgGLEnableTextureParameter(p); + } + + // cg parameter usage is wrong, so do it manually + if( type == 3 ) { + p = cgGetNamedParameter(pf->prog, "g_sConv16to32"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + cgGLSetTextureParameter(p, ptexConv16to32); + cgGLEnableTextureParameter(p); + } + } + else if( type == 4 ) { + p = cgGetNamedParameter(pf->prog, "g_sConv32to16"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + cgGLSetTextureParameter(p, ptexConv32to16); + cgGLEnableTextureParameter(p); + } + } + else { + p = cgGetNamedParameter(pf->prog, "g_sBilinearBlocks"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + cgGLSetTextureParameter(p, ptexBilinearBlocks); + cgGLEnableTextureParameter(p); + } + } + + p = cgGetNamedParameter(pf->prog, "g_sMemory"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + //cgGLEnableTextureParameter(p); + pf->sMemory = p; + } + p = cgGetNamedParameter(pf->prog, "g_sSrcFinal"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + //cgGLEnableTextureParameter(p); + pf->sFinal = p; + } + p = cgGetNamedParameter(pf->prog, "g_sBitwiseANDX"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + //cgGLEnableTextureParameter(p); + pf->sBitwiseANDX = p; + } + p = cgGetNamedParameter(pf->prog, "g_sBitwiseANDY"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + //cgGLEnableTextureParameter(p); + pf->sBitwiseANDY = p; + } + p = cgGetNamedParameter(pf->prog, "g_sCLUT"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + //cgGLEnableTextureParameter(p); + pf->sCLUT = p; + } + p = cgGetNamedParameter(pf->prog, "g_sInterlace"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + //cgGLEnableTextureParameter(p); + pf->sInterlace = p; + } + + // set global shader constants + p = cgGetNamedParameter(pf->prog, "g_fExactColor"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + cgGLSetParameter4fv(p, Vector(0.5f, (g_GameSettings&GAME_EXACTCOLOR)?0.9f/256.0f:0.5f/256.0f, 0,1/255.0f)); + } + + p = cgGetNamedParameter(pf->prog, "g_fBilinear"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(-0.2f, -0.65f, 0.9f, 1.0f / 32767.0f )); + + p = cgGetNamedParameter(pf->prog, "g_fZBias"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(1.0f/256.0f, 1.0004f, 1, 0.5f)); + + p = cgGetNamedParameter(pf->prog, "g_fc0"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(0,1, 0.001f, 0.5f)); + + p = cgGetNamedParameter(pf->prog, "g_fMult"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(1/1024.0f, 0.2f/1024.0f, 1/128.0f, 1/512.0f)); +} + +void SetupVertexProgramParameters(CGprogram prog, int context) +{ + CGparameter p; + + p = cgGetNamedParameter(prog, "g_fPosXY"); + if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) + cgConnectParameter(g_vparamPosXY[context], p); + + p = cgGetNamedParameter(prog, "g_fZ"); + if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) + cgGLSetParameter4fv(p, g_vdepth); + + Vector vnorm = Vector(g_filog32, 0, 0,0); + p = cgGetNamedParameter(prog, "g_fZNorm"); + if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) + cgGLSetParameter4fv(p, vnorm); + + p = cgGetNamedParameter(prog, "g_fBilinear"); + if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(-0.2f, -0.65f, 0.9f, 1.0f / 32767.0f )); + + p = cgGetNamedParameter(prog, "g_fZBias"); + if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(1.0f/256.0f, 1.0004f, 1, 0.5f)); + + p = cgGetNamedParameter(prog, "g_fc0"); + if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(0,1, 0.001f, 0.5f)); +} + +#ifdef RELEASE_TO_PUBLIC + +#define LOAD_VS(Index, prog) { \ + assert( mapShaderResources.find(Index) != mapShaderResources.end() ); \ + header = mapShaderResources[Index]; \ + assert( (header) != NULL && (header)->index == (Index) ); \ + prog = cgCreateProgram(g_cgcontext, CG_OBJECT, (char*)(s_lpShaderResources + (header)->offset), cgvProf, NULL, NULL); \ + if( !cgIsProgram(prog) ) { \ + ERROR_LOG("Failed to load vs %d: \n%s\n", Index, cgGetLastListing(g_cgcontext)); \ + return false; \ + } \ + cgGLLoadProgram(prog); \ + if( cgGetError() != CG_NO_ERROR ) ERROR_LOG("failed to load program %d\n", Index); \ + SetupVertexProgramParameters(prog, !!(Index&SH_CONTEXT1)); \ +} \ + +#define LOAD_PS(Index, fragment) { \ + bLoadSuccess = true; \ + assert( mapShaderResources.find(Index) != mapShaderResources.end() ); \ + header = mapShaderResources[Index]; \ + fragment.prog = cgCreateProgram(g_cgcontext, CG_OBJECT, (char*)(s_lpShaderResources + (header)->offset), cgfProf, NULL, NULL); \ + if( !cgIsProgram(fragment.prog) ) { \ + ERROR_LOG("Failed to load ps %d: \n%s\n", Index, cgGetLastListing(g_cgcontext)); \ + return false; \ + } \ + cgGLLoadProgram(fragment.prog); \ + if( cgGetError() != CG_NO_ERROR ) { \ + ERROR_LOG("failed to load program %d\n", Index); \ + bLoadSuccess = false; \ + } \ + SetupFragmentProgramParameters(&fragment, !!(Index&SH_CONTEXT1), 0); \ +} \ + +bool ZeroGS::LoadEffects() +{ + assert( s_lpShaderResources != NULL ); + + // process the header + u32 num = *(u32*)s_lpShaderResources; + int compressed_size = *(int*)(s_lpShaderResources+4); + int real_size = *(int*)(s_lpShaderResources+8); + int out; + + char* pbuffer = (char*)malloc(real_size); + inf((char*)s_lpShaderResources+12, &pbuffer[0], compressed_size, real_size, &out); + assert(out == real_size); + + s_lpShaderResources = (u8*)pbuffer; + SHADERHEADER* header = (SHADERHEADER*)s_lpShaderResources; + + mapShaderResources.clear(); + while(num-- > 0 ) { + mapShaderResources[header->index] = header; + ++header; + } + + // clear the textures + for(int i = 0; i < ARRAY_SIZE(ppsTexture); ++i) { + SAFE_RELEASE_PROG(ppsTexture[i].prog); + ppsTexture[i].prog = NULL; + } +#ifndef _DEBUG + memset(ppsTexture, 0, sizeof(ppsTexture)); +#endif + + return true; +} + +// called +bool ZeroGS::LoadExtraEffects() +{ + SHADERHEADER* header; + bool bLoadSuccess = true; + + const int vsshaders[4] = { SH_REGULARVS, SH_TEXTUREVS, SH_REGULARFOGVS, SH_TEXTUREFOGVS }; + + for(int i = 0; i < 4; ++i) { + LOAD_VS(vsshaders[i], pvs[2*i]); + LOAD_VS(vsshaders[i]|SH_CONTEXT1, pvs[2*i+1]); + //if( conf.mrtdepth ) { + LOAD_VS(vsshaders[i]|SH_WRITEDEPTH, pvs[2*i+8]); + LOAD_VS(vsshaders[i]|SH_WRITEDEPTH|SH_CONTEXT1, pvs[2*i+8+1]); +// } +// else { +// pvs[2*i+8] = pvs[2*i+8+1] = NULL; +// } + } + + LOAD_VS(SH_BITBLTVS, pvsBitBlt.prog); + pvsBitBlt.sBitBltPos = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltPos"); + pvsBitBlt.sBitBltTex = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltTex"); + pvsBitBlt.fBitBltTrans = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltTrans"); + + LOAD_PS(SH_REGULARPS, ppsRegular[0]); + LOAD_PS(SH_REGULARFOGPS, ppsRegular[1]); + + if( conf.mrtdepth ) { + LOAD_PS(SH_REGULARPS, ppsRegular[2]); + if( !bLoadSuccess ) + conf.mrtdepth = 0; + LOAD_PS(SH_REGULARFOGPS, ppsRegular[3]); + if( !bLoadSuccess ) + conf.mrtdepth = 0; + } + + LOAD_PS(SH_BITBLTPS, ppsBitBlt[0]); + LOAD_PS(SH_BITBLTAAPS, ppsBitBlt[1]); + if( !bLoadSuccess ) { + ERROR_LOG("Failed to load BitBltAAPS, using BitBltPS\n"); + LOAD_PS(SH_BITBLTPS, ppsBitBlt[1]); + } + LOAD_PS(SH_BITBLTDEPTHPS, ppsBitBltDepth); + LOAD_PS(SH_CRTCTARGPS, ppsCRTCTarg[0]); + LOAD_PS(SH_CRTCTARGINTERPS, ppsCRTCTarg[1]); + + g_bCRTCBilinear = TRUE; + LOAD_PS(SH_CRTCPS, ppsCRTC[0]); + if( !bLoadSuccess ) { + // switch to simpler + g_bCRTCBilinear = FALSE; + LOAD_PS(SH_CRTC_NEARESTPS, ppsCRTC[0]); + LOAD_PS(SH_CRTCINTER_NEARESTPS, ppsCRTC[0]); + } + else { + LOAD_PS(SH_CRTCINTERPS, ppsCRTC[1]); + } + + if( !bLoadSuccess ) + ERROR_LOG("Failed to create CRTC shaders\n"); + + LOAD_PS(SH_CRTC24PS, ppsCRTC24[0]); + LOAD_PS(SH_CRTC24INTERPS, ppsCRTC24[1]); + LOAD_PS(SH_ZEROPS, ppsOne); + LOAD_PS(SH_BASETEXTUREPS, ppsBaseTexture); + LOAD_PS(SH_CONVERT16TO32PS, ppsConvert16to32); + LOAD_PS(SH_CONVERT32TO16PS, ppsConvert32to16); + + return true; +} + +FRAGMENTSHADER* ZeroGS::LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context, bool* pbFailed) +{ + int texwrap; + assert( texfilter < NUM_FILTERS ); + + if(g_nPixelShaderVer&SHADER_REDUCED) + texfilter = 0; + assert(!(g_nPixelShaderVer&SHADER_REDUCED) || !exactcolor); + + if( clamp.wms == clamp.wmt ) { + switch( clamp.wms ) { + case 0: texwrap = TEXWRAP_REPEAT; break; + case 1: texwrap = TEXWRAP_CLAMP; break; + case 2: texwrap = TEXWRAP_CLAMP; break; + default: texwrap = TEXWRAP_REGION_REPEAT; break; + } + } + else if( clamp.wms==3||clamp.wmt==3) + texwrap = TEXWRAP_REGION_REPEAT; + else + texwrap = TEXWRAP_REPEAT_CLAMP; + + int index = GET_SHADER_INDEX(type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, context, 0); + + assert( index < ARRAY_SIZE(ppsTexture) ); + FRAGMENTSHADER* pf = ppsTexture+index; + + if( pbFailed != NULL ) *pbFailed = false; + + if( pf->prog != NULL ) + return pf; + + if( (g_nPixelShaderVer & SHADER_ACCURATE) && mapShaderResources.find(index+NUM_SHADERS*SHADER_ACCURATE) != mapShaderResources.end() ) + index += NUM_SHADERS*SHADER_ACCURATE; + + assert( mapShaderResources.find(index) != mapShaderResources.end() ); + SHADERHEADER* header = mapShaderResources[index]; + if( header == NULL ) + ERROR_LOG("%d %d\n", index, g_nPixelShaderVer); + assert( header != NULL ); + + //DEBUG_LOG("shader:\n%s\n", (char*)(s_lpShaderResources + (header)->offset)); + pf->prog = cgCreateProgram(g_cgcontext, CG_OBJECT, (char*)(s_lpShaderResources + (header)->offset), cgfProf, NULL, NULL); + if( pf->prog != NULL && cgIsProgram(pf->prog) && cgGetError() == CG_NO_ERROR ) { + SetupFragmentProgramParameters(pf, context, type); + cgGLLoadProgram(pf->prog); + if( cgGetError() != CG_NO_ERROR ) { +// cgGLLoadProgram(pf->prog); +// if( cgGetError() != CG_NO_ERROR ) { + ERROR_LOG("Failed to load shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); + if( pbFailed != NULL ) *pbFailed = true; + return pf; +// } + } + return pf; + } + + ERROR_LOG("Failed to create shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); + if( pbFailed != NULL ) *pbFailed = true; + + return NULL; +} + +#else // not RELEASE_TO_PUBLIC + +#define LOAD_VS(name, prog, shaderver) { \ + prog = cgCreateProgramFromFile(g_cgcontext, CG_SOURCE, EFFECT_NAME, shaderver, name, args); \ + if( !cgIsProgram(prog) ) { \ + ERROR_LOG("Failed to load vs %s: \n%s\n", name, cgGetLastListing(g_cgcontext)); \ + return false; \ + } \ + cgGLLoadProgram(prog); \ + if( cgGetError() != CG_NO_ERROR ) ERROR_LOG("failed to load program %s\n", name); \ + SetupVertexProgramParameters(prog, args[0]==context1); \ +} \ + +#ifdef _DEBUG +#define SET_PSFILENAME(frag, name) frag.filename = name +#else +#define SET_PSFILENAME(frag, name) +#endif + +#define LOAD_PS(name, fragment, shaderver) { \ + bLoadSuccess = true; \ + fragment.prog = cgCreateProgramFromFile(g_cgcontext, CG_SOURCE, EFFECT_NAME, shaderver, name, args); \ + if( !cgIsProgram(fragment.prog) ) { \ + ERROR_LOG("Failed to load ps %s: \n%s\n", name, cgGetLastListing(g_cgcontext)); \ + return false; \ + } \ + cgGLLoadProgram(fragment.prog); \ + if( cgGetError() != CG_NO_ERROR ) { \ + ERROR_LOG("failed to load program %s\n", name); \ + bLoadSuccess = false; \ + } \ + SetupFragmentProgramParameters(&fragment, args[0]==context1, 0); \ + SET_PSFILENAME(fragment, name); \ +} \ + +bool ZeroGS::LoadEffects() +{ + // clear the textures + for(int i = 0; i < ARRAY_SIZE(ppsTexture); ++i) { + SAFE_RELEASE_PROG(ppsTexture[i].prog); + } + +#ifndef _DEBUG + memset(ppsTexture, 0, sizeof(ppsTexture)); +#endif + + return true; +} + +bool ZeroGS::LoadExtraEffects() +{ + const char* args[] = { NULL , NULL, NULL, NULL }; + char context0[255], context1[255]; + sprintf(context0, "-I%sctx0", EFFECT_DIR); + sprintf(context1, "-I%sctx1", EFFECT_DIR); + char* write_depth = "-DWRITE_DEPTH"; + bool bLoadSuccess = true; + + const char* pvsshaders[4] = { "RegularVS", "TextureVS", "RegularFogVS", "TextureFogVS" }; + + for(int i = 0; i < 4; ++i) { + args[0] = context0; + args[1] = NULL; + LOAD_VS(pvsshaders[i], pvs[2*i], cgvProf); + args[0] = context1; + LOAD_VS(pvsshaders[i], pvs[2*i+1], cgvProf); + + //if( conf.mrtdepth ) { + args[0] = context0; + args[1] = write_depth; + LOAD_VS(pvsshaders[i], pvs[2*i+8], cgvProf); + args[0] = context1; + LOAD_VS(pvsshaders[i], pvs[2*i+8+1], cgvProf); +// } +// else { +// pvs[2*i+8] = pvs[2*i+8+1] = NULL; +// } + } + + args[0] = context0; + args[1] = NULL; + LOAD_VS("BitBltVS", pvsBitBlt.prog, cgvProf); + pvsBitBlt.sBitBltPos = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltPos"); + pvsBitBlt.sBitBltTex = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltTex"); + pvsBitBlt.fBitBltTrans = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltTrans"); + + LOAD_PS("RegularPS", ppsRegular[0], cgfProf); + LOAD_PS("RegularFogPS", ppsRegular[1], cgfProf); + + if( conf.mrtdepth ) { + args[0] = context0; + args[1] = write_depth; + LOAD_PS("RegularPS", ppsRegular[2], cgfProf); + if( !bLoadSuccess ) + conf.mrtdepth = 0; + LOAD_PS("RegularFogPS", ppsRegular[3], cgfProf); + if( !bLoadSuccess ) + conf.mrtdepth = 0; + } + + LOAD_PS("BitBltPS", ppsBitBlt[0], cgfProf); + LOAD_PS("BitBltAAPS", ppsBitBlt[1], cgfProf); + if( !bLoadSuccess ) { + ERROR_LOG("Failed to load BitBltAAPS, using BitBltPS\n"); + LOAD_PS("BitBltPS", ppsBitBlt[1], cgfProf); + } + + LOAD_PS("BitBltDepthPS", ppsBitBltDepth, cgfProf); + LOAD_PS("CRTCTargPS", ppsCRTCTarg[0], cgfProf); LOAD_PS("CRTCTargInterPS", ppsCRTCTarg[1], cgfProf); + + g_bCRTCBilinear = TRUE; + LOAD_PS("CRTCPS", ppsCRTC[0], cgfProf); + if( !bLoadSuccess ) { + // switch to simpler + g_bCRTCBilinear = FALSE; + LOAD_PS("CRTCPS_Nearest", ppsCRTC[0], cgfProf); + LOAD_PS("CRTCInterPS_Nearest", ppsCRTC[0], cgfProf); + } + else { + LOAD_PS("CRTCInterPS", ppsCRTC[1], cgfProf); + } + + if( !bLoadSuccess ) + ERROR_LOG("Failed to create CRTC shaders\n"); + + LOAD_PS("CRTC24PS", ppsCRTC24[0], cgfProf); LOAD_PS("CRTC24InterPS", ppsCRTC24[1], cgfProf); + LOAD_PS("ZeroPS", ppsOne, cgfProf); + LOAD_PS("BaseTexturePS", ppsBaseTexture, cgfProf); + LOAD_PS("Convert16to32PS", ppsConvert16to32, cgfProf); + LOAD_PS("Convert32to16PS", ppsConvert32to16, cgfProf); + +// if( !conf.mrtdepth ) { +// ERROR_LOG("Disabling MRT depth writing\n"); +// s_bWriteDepth = FALSE; +// } + + return true; +} + +FRAGMENTSHADER* ZeroGS::LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context, bool* pbFailed) +{ + int texwrap; + + assert( texfilter < NUM_FILTERS ); + //assert( g_nPixelShaderVer == SHADER_30 ); + if( clamp.wms == clamp.wmt ) { + switch( clamp.wms ) { + case 0: texwrap = TEXWRAP_REPEAT; break; + case 1: texwrap = TEXWRAP_CLAMP; break; + case 2: texwrap = TEXWRAP_CLAMP; break; + default: + texwrap = TEXWRAP_REGION_REPEAT; break; + } + } + else if( clamp.wms==3||clamp.wmt==3) + texwrap = TEXWRAP_REGION_REPEAT; + else + texwrap = TEXWRAP_REPEAT_CLAMP; + + int index = GET_SHADER_INDEX(type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, context, 0); + + if( pbFailed != NULL ) *pbFailed = false; + + FRAGMENTSHADER* pf = ppsTexture+index; + + if( pf->prog != NULL ) + return pf; + + pf->prog = LoadShaderFromType(EFFECT_DIR, EFFECT_NAME, type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, g_nPixelShaderVer, context); + + if( pf->prog != NULL ) { +#ifdef _DEBUG + char str[255]; + sprintf(str, "Texture%s%d_%sPS", fog?"Fog":"", texfilter, g_pTexTypes[type]); + pf->filename = str; +#endif + SetupFragmentProgramParameters(pf, context, type); + cgGLLoadProgram(pf->prog); + if( cgGetError() != CG_NO_ERROR ) { + // try again +// cgGLLoadProgram(pf->prog); +// if( cgGetError() != CG_NO_ERROR ) { + ERROR_LOG("Failed to load shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); + if( pbFailed != NULL ) *pbFailed = true; + //assert(0); + // NULL makes things crash + return pf; +// } + } + return pf; + } + + ERROR_LOG("Failed to create shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); + if( pbFailed != NULL ) *pbFailed = true; + + return NULL; +} + +#endif // RELEASE_TO_PUBLIC + +void ZeroGS::Prim() +{ + if( g_bIsLost ) + return; + + VB& curvb = vb[prim->ctxt]; + if( curvb.CheckPrim() ) + Flush(prim->ctxt); + curvb.curprim._val = prim->_val; + + // flush the other pipe if sharing the same buffer +// if( vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp && vb[!prim->ctxt].nCount > 0 ) +// { +// assert( vb[prim->ctxt].nCount == 0 ); +// Flush(!prim->ctxt); +// } + + curvb.curprim.prim = prim->prim; +} + +int GetTexFilter(const tex1Info& tex1) +{ + // always force + if( conf.bilinear == 2 ) + return 1; + + int texfilter = 0; + if( conf.bilinear && ptexBilinearBlocks != 0 ) { + if( tex1.mmin <= 1 ) + texfilter = tex1.mmin|tex1.mmag; + else + texfilter = tex1.mmag ? ((tex1.mmin+2)&5) : tex1.mmin; + + texfilter = texfilter == 1 || texfilter == 4 || texfilter == 5; + } + return texfilter; +} + +void ZeroGS::ReloadEffects() +{ +#ifndef RELEASE_TO_PUBLIC + for(int i = 0; i < ARRAY_SIZE(ppsTexture); ++i) { + SAFE_RELEASE_PROG(ppsTexture[i].prog); + } + memset(ppsTexture, 0, sizeof(ppsTexture)); + LoadExtraEffects(); +#endif +} + +static int s_ClutResolve = 0; +void ZeroGS::Flush(int context) +{ + GL_REPORT_ERRORD(); + assert( context >= 0 && context <= 1 ); + +#ifndef RELEASE_TO_PUBLIC + if( g_bUpdateEffect ) { + ReloadEffects(); + g_bUpdateEffect = 0; + } +#endif + + VB& curvb = vb[context]; + const pixTest curtest = curvb.test; + if( curvb.nCount == 0 || (curtest.zte && curtest.ztst == 0) || g_bIsLost ) { + curvb.nCount = 0; + return; + } + + if( s_RangeMngr.ranges.size() > 0 ) { + + // don't want infinite loop + u32 prevcount = curvb.nCount; + curvb.nCount = 0; + FlushTransferRanges(curvb.curprim.tme ? &curvb.tex0 : NULL); + + curvb.nCount = prevcount; + //if( curvb.nCount == 0 ) + // return; + } + + if( curvb.bNeedTexCheck ) { + curvb.FlushTexData(); + + if( curvb.nCount == 0 ) + return; + } + + DVProfileFunc _pf("Flush"); + + GL_REPORT_ERRORD(); + if( curvb.bNeedFrameCheck || curvb.bNeedZCheck ) { + curvb.CheckFrame(curvb.curprim.tme ? curvb.tex0.tbp0 : 0); + } + + if( curvb.prndr == NULL || curvb.pdepth == NULL ) { + WARN_LOG("Current render target NULL (ctx: %d)", context); + curvb.nCount = 0; + return; + } + +#if defined(PRIM_LOG) && defined(_DEBUG) + static const char* patst[8] = { "NEVER", "ALWAYS", "LESS", "LEQUAL", "EQUAL", "GEQUAL", "GREATER", "NOTEQUAL"}; + static const char* pztst[4] = { "NEVER", "ALWAYS", "GEQUAL", "GREATER" }; + static const char* pafail[4] = { "KEEP", "FB_ONLY", "ZB_ONLY", "RGB_ONLY" }; + PRIM_LOG("**Drawing ctx %d, num %d, fbp: 0x%x, zbp: 0x%x, fpsm: %d, zpsm: %d, fbw: %d\n", context, vb[context].nCount, curvb.prndr->fbp, curvb.zbuf.zbp, curvb.prndr->psm, curvb.zbuf.psm, curvb.prndr->fbw); + PRIM_LOG("prim: prim=%x iip=%x tme=%x fge=%x abe=%x aa1=%x fst=%x ctxt=%x fix=%x\n", + curvb.curprim.prim, curvb.curprim.iip, curvb.curprim.tme, curvb.curprim.fge, curvb.curprim.abe, curvb.curprim.aa1, curvb.curprim.fst, curvb.curprim.ctxt, curvb.curprim.fix); + PRIM_LOG("test: ate:%d, atst: %s, aref: %d, afail: %s, date: %d, datm: %d, zte: %d, ztst: %s, fba: %d\n", + curvb.test.ate, patst[curvb.test.atst], curvb.test.aref, pafail[curvb.test.afail], curvb.test.date, curvb.test.datm, curvb.test.zte, pztst[curvb.test.ztst], curvb.fba.fba); + PRIM_LOG("alpha: A%d B%d C%d D%d FIX:%d pabe: %d; aem: %d, ta0: %d, ta1: %d\n", curvb.alpha.a, curvb.alpha.b, curvb.alpha.c, curvb.alpha.d, curvb.alpha.fix, gs.pabe, gs.texa.aem, gs.texa.ta[0], gs.texa.ta[1]); + PRIM_LOG("tex0: tbp0=0x%x, tbw=%d, psm=0x%x, tw=%d, th=%d, tcc=%d, tfx=%d, cbp=0x%x, cpsm=0x%x, csm=%d, csa=%d, cld=%d\n", + curvb.tex0.tbp0, curvb.tex0.tbw, curvb.tex0.psm, curvb.tex0.tw, + curvb.tex0.th, curvb.tex0.tcc, curvb.tex0.tfx, curvb.tex0.cbp, + curvb.tex0.cpsm, curvb.tex0.csm, curvb.tex0.csa, curvb.tex0.cld); + PRIM_LOG("frame: %d\n\n", g_SaveFrameNum); +#endif + + GL_REPORT_ERRORD(); + CRenderTarget* ptextarg = NULL; + + if( curtest.date || gs.pabe ) + SetDestAlphaTest(); + + // set the correct pixel shaders + if( curvb.curprim.tme ) { + + // if texture is part of a previous target, use that instead + int tbw = curvb.tex0.tbw; + int tbp0 = curvb.tex0.tbp0; + int tpsm = curvb.tex0.psm; + + if( curvb.bNeedTexCheck ) { + // not yet initied, but still need to get correct target! (xeno3 ingame) + tbp0 = (curvb.uNextTex0Data[0] & 0x3fff); + tbw = ((curvb.uNextTex0Data[0] >> 14) & 0x3f) * 64; + tpsm = (curvb.uNextTex0Data[0] >> 20) & 0x3f; + } + ptextarg = s_RTs.GetTarg(tbp0, tbw); + + if( (tpsm&0x30)==0x30 && ptextarg == NULL ) { + // try depth + ptextarg = s_DepthRTs.GetTarg(tbp0, tbw); + } + + if( ptextarg == NULL && (g_GameSettings&GAME_TEXTURETARGS) ) { + // check if any part of the texture intersects the current target + if( !PSMT_ISCLUT(tpsm) && curvb.tex0.tbp0 >= curvb.frame.fbp && (curvb.tex0.tbp0 << 8) < curvb.prndr->end) { + ptextarg = curvb.prndr; + } + } + + if( ptextarg != NULL && !(ptextarg->status&CRenderTarget::TS_NeedUpdate) ) { + if( PSMT_ISCLUT(tpsm) && tpsm != PSMT8H ) { // handle 8h cluts + // don't support clut targets, read from mem + // 4hl - kh2 check - from dx version -- arcum42 + if( tpsm != PSMT4HL && tpsm != PSMT4HH && s_ClutResolve <= 1 ) + { // xenosaga requires 2 resolves + u32 prevcount = curvb.nCount; + curvb.nCount = 0; + ptextarg->Resolve(); + s_ClutResolve++; + curvb.nCount = prevcount; + } + ptextarg = NULL; + } + else { + if( ptextarg == curvb.prndr ) { + // need feedback + curvb.prndr->CreateFeedback(); + + if(s_bWriteDepth && curvb.pdepth != NULL) + curvb.pdepth->SetRenderTarget(1); + else + ResetRenderTarget(1); + } + } + } + else ptextarg = NULL; + } + +#ifdef _DEBUG + if( g_bSaveFlushedFrame & 0x80000000 ) { + char str[255]; + sprintf(str, "rndr.tga", g_SaveFrameNum); + SaveRenderTarget(str, curvb.prndr->fbw, curvb.prndr->fbh, 0); + } +#endif + + if( conf.options & GSOPTION_WIREFRAME ) { + // always render first few geometry as solid + if( s_nWireframeCount > 0 ) { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + } + + if( !curvb.bVarsSetTarg ) + SetContextTarget(context); + else { + assert( curvb.pdepth != NULL ); + + if( curvb.pdepth->status & CRenderTarget::TS_Virtual) { + + if( !curvb.zbuf.zmsk ) { + CRenderTarget* ptemp = s_DepthRTs.Promote(curvb.pdepth->fbp|(curvb.pdepth->fbw<<16)); + assert( ptemp == curvb.pdepth ); + } + else + curvb.pdepth->status &= ~CRenderTarget::TS_NeedUpdate; + } + + if( (curvb.pdepth->status & CRenderTarget::TS_NeedUpdate) || (curvb.prndr->status & CRenderTarget::TS_NeedUpdate) ) + SetContextTarget(context); + } + + icurctx = context; + + DVProfileFunc _pf5("Flush:after texvars"); + + glBindBuffer(GL_ARRAY_BUFFER, g_vboBuffers[g_nCurVBOIndex]); + g_nCurVBOIndex = (g_nCurVBOIndex+1)%g_vboBuffers.size(); + glBufferData(GL_ARRAY_BUFFER, curvb.nCount * sizeof(VertexGPU), curvb.pBufferData, GL_STREAM_DRAW); +// void* pdata = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); +// memcpy_amd(pdata, curvb.pBufferData, curvb.nCount * sizeof(VertexGPU)); +// glUnmapBuffer(GL_ARRAY_BUFFER); + SET_STREAM(); + + assert( !(curvb.prndr->status&CRenderTarget::TS_NeedUpdate) ); + curvb.prndr->status = 0; + + if( curvb.pdepth != NULL ) { + assert( !(curvb.pdepth->status&CRenderTarget::TS_NeedUpdate) ); + if( !curvb.zbuf.zmsk ) { + assert( !(curvb.pdepth->status & CRenderTarget::TS_Virtual) ); + curvb.pdepth->status = 0; + } + } + +#ifdef _DEBUG + //curvb.prndr->SetRenderTarget(0); + //curvb.pdepth->SetDepthStencilSurface(); + //glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_NV, 0, 0 ); + GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); +#endif + s_dwColorWrite = (curvb.prndr->psm&0xf) == 1 ? (COLORMASK_BLUE|COLORMASK_GREEN|COLORMASK_RED) : 0xf; + + if( ((curvb.frame.fbm)&0xff) == 0xff) s_dwColorWrite &= ~COLORMASK_RED; + if( ((curvb.frame.fbm>>8)&0xff) == 0xff) s_dwColorWrite &= ~COLORMASK_GREEN; + if( ((curvb.frame.fbm>>16)&0xff) == 0xff) s_dwColorWrite &= ~COLORMASK_BLUE; + if( ((curvb.frame.fbm>>24)&0xff) == 0xff) s_dwColorWrite &= ~COLORMASK_ALPHA; + + GL_COLORMASK(s_dwColorWrite); + + Rect& scissor = curvb.prndr->scissorrect; + glScissor(scissor.x, scissor.y, scissor.w, scissor.h); + + u32 dwUsingSpecialTesting = 0; + u32 dwFilterOpts = 0; + + FRAGMENTSHADER* pfragment = NULL; + + // need exact if equal or notequal + int exactcolor = 0; + if( !(g_nPixelShaderVer&SHADER_REDUCED) ) + // ffx2 breaks when ==7 + exactcolor = (curtest.ate && curtest.aref <= 128) && (curtest.atst==4);//||curtest.atst==7); + + int shadertype = 0; + + // set the correct pixel shaders + u32 ptexclut = 0; + if( curvb.curprim.tme ) { + + if( ptextarg != NULL ) { + + if( ptextarg->IsDepth() ) + SetWriteDepth(); + + Vector vpageoffset; + vpageoffset.w = 0; + + int psm = curvb.tex0.psm; + if( PSMT_ISCLUT(curvb.tex0.psm) ) psm = curvb.tex0.cpsm; + + shadertype = 1; + if( curvb.tex0.psm == PSMT8H && !(g_GameSettings&GAME_NOTARGETCLUT) ) { + // load the clut to memory + glGenTextures(1, &ptexclut); + glBindTexture(GL_TEXTURE_2D, ptexclut); + vector data((curvb.tex0.cpsm&2) ? 512 : 1024); + + if( ptexclut != 0 ) { + + // fill the buffer by decoding the clut + int nClutOffset = 0, clutsize; + int entries = (curvb.tex0.psm&3)==3 ? 256 : 16; + if( curvb.tex0.cpsm <= 1 ) { // 32 bit + nClutOffset = 64 * curvb.tex0.csa; + clutsize = min(entries, 256-curvb.tex0.csa*16)*4; + } + else { + nClutOffset = 64 * (curvb.tex0.csa&15) + (curvb.tex0.csa>=16?2:0); + clutsize = min(entries, 512-curvb.tex0.csa*16)*2; + } + + if( curvb.tex0.cpsm <= 1 ) { // 32 bit + memcpy_amd(&data[0], g_pbyGSClut+nClutOffset, clutsize); + } + else { + u16* pClutBuffer = (u16*)(g_pbyGSClut + nClutOffset); + u16* pclut = (u16*)&data[0]; + int left = ((u32)nClutOffset & 2) ? 0 : ((nClutOffset&0x3ff)/2)+clutsize-512; + if( left > 0 ) clutsize -= left; + + while(clutsize > 0) { + pclut[0] = pClutBuffer[0]; + pclut++; + pClutBuffer+=2; + clutsize -= 2; + } + + if( left > 0) { + pClutBuffer = (u16*)(g_pbyGSClut + 2); + while(left > 0) { + pclut[0] = pClutBuffer[0]; + left -= 2; + pClutBuffer += 2; + pclut++; + } + } + } + + glTexImage2D(GL_TEXTURE_2D, 0, 4, 256, 1, 0, GL_RGBA, (curvb.tex0.cpsm&2)?GL_UNSIGNED_SHORT_5_5_5_1:GL_UNSIGNED_BYTE, &data[0]); + s_vecTempTextures.push_back(ptexclut); + + if( g_bSaveTex ) + SaveTexture("clut.tga", GL_TEXTURE_2D, ptexclut, 256, 1); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + + if( !(g_nPixelShaderVer&SHADER_REDUCED) && (ptextarg->psm & 2) ) { + shadertype = 4; + } + else + shadertype = 2; + } + else { + if( PSMT_ISCLUT(curvb.tex0.psm) ) + WARN_LOG("Using render target with CLUTs %d!\n", curvb.tex0.psm); + else { + if( (curvb.tex0.psm&2) != (ptextarg->psm&2) && (!(g_nPixelShaderVer&SHADER_REDUCED) || !curvb.curprim.fge) ) { + if( curvb.tex0.psm & 2 ) { + // converting from 32->16 + shadertype = 3; + } + else { + // converting from 16->32 + WARN_LOG("ZeroGS: converting from 16 to 32bit RTs\n"); + //shadetype = 4; + } + } + } + } + + pfragment = LoadShadeEffect(shadertype, 0, curvb.curprim.fge, curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), + exactcolor, curvb.clamp, context, NULL); + + if( shadertype == 3 ) { + Vector v; + v.x = 16.0f / (float)curvb.tex0.tw; + v.y = 16.0f / (float)curvb.tex0.th; + v.z = 0.5f * v.x; + v.w = 0.5f * v.y; + cgGLSetParameter4fv(pfragment->fTexOffset, v); + + vpageoffset.x = -0.1f / 256.0f; + vpageoffset.y = -0.001f / 256.0f; + vpageoffset.z = -0.1f / ptextarg->fbh; + vpageoffset.w = ((ptextarg->psm&0x30)==0x30)?-1.0f:0.0f; + } + else if( shadertype == 4 ) { + Vector v; + v.x = 16.0f / (float)ptextarg->fbw; + v.y = 16.0f / (float)ptextarg->fbh; + v.z = -1; + v.w = 8.0f / (float)ptextarg->fbh; + cgGLSetParameter4fv(pfragment->fTexOffset, v); + + vpageoffset.x = 2; + vpageoffset.y = 1; + vpageoffset.z = 0; + vpageoffset.w = 0.0001f; + } + + u32 ptexset = ptextarg == curvb.prndr ? ptextarg->ptexFeedback : ptextarg->ptex; + s_ptexCurSet[context] = ptexset; + + if( !curvb.tex1.mmag ) { + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexset); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + dwFilterOpts |= 1; + } + + if( !curvb.tex1.mmin ) { + if( curvb.tex1.mmag ) + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexset); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + dwFilterOpts |= 2; + } + + Vector vTexDims; + vTexDims.x = curvb.tex0.tw; + vTexDims.y = curvb.tex0.th; + + // look at the offset of tbp0 from fbp + if( curvb.tex0.tbp0 <= ptextarg->fbp ) { + vTexDims.z = 0;//-0.5f/(float)ptextarg->fbw; + vTexDims.w = 0;//0.2f/(float)ptextarg->fbh; + } + else { + u32 tbp0 = curvb.tex0.tbp0 >> 5; // align to a page + int blockheight = (ptextarg->psm&2) ? 64 : 32; + int ycoord = ((curvb.tex0.tbp0-ptextarg->fbp)/(32*(ptextarg->fbw>>6))) * blockheight; + int xcoord = (((curvb.tex0.tbp0-ptextarg->fbp)%(32*(ptextarg->fbw>>6)))) * 2; + vTexDims.z = (float)xcoord; + vTexDims.w = (float)ycoord; + } + + if( shadertype == 4 ) { + vTexDims.z += 8.0f; + } + + cgGLSetParameter4fv(pfragment->fTexDims, vTexDims); + + // zoe2 + if( (ptextarg->psm&0x30) == 0x30 ) {//&& (psm&2) == (ptextarg->psm&2) ) { + // target of zbuf has +1 added to it, don't do 16bit + vpageoffset.w = -1; +// Vector valpha2; +// valpha2.x = 1; valpha2.y = 0; +// valpha2.z = -1; valpha2.w = 0; +// SETCONSTF(GPU_TEXALPHA20+context, &valpha2); + } + cgGLSetParameter4fv(pfragment->fPageOffset, vpageoffset); + + if( g_bSaveTex ) + SaveTexture("tex.tga", GL_TEXTURE_RECTANGLE_NV, + ptextarg == curvb.prndr ? ptextarg->ptexFeedback : ptextarg->ptex, ptextarg->fbw<fbh<ValidateClut(curvb.tex0) ); +#endif + +//#ifdef ZEROGS_CACHEDCLEAR +// if( !curvb.pmemtarg->ValidateTex(curvb.tex0, true) ) { +// CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 1); +// SetTexVariablesInt(context, GetTexFilter(curvb.tex1), curvb.tex0, pmemtarg, s_bForceTexFlush); +// vb[context].bVarsTexSync = TRUE; +// } +//#endif + + if( g_bSaveTex ) { + if( g_bSaveTex == 1 ) { + SaveTex(&curvb.tex0, 1); +// CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 0); +// int texheight = (pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult; +// int texwidth = GPU_TEXWIDTH*pmemtarg->widthmult*pmemtarg->channels; +// SaveTexture("real.tga", GL_TEXTURE_RECTANGLE_NV, pmemtarg->ptex->tex, texwidth, texheight); + } + else SaveTex(&curvb.tex0, 0); + } + + int psm = curvb.tex0.psm; + if( PSMT_ISCLUT(curvb.tex0.psm) ) psm = curvb.tex0.cpsm; + + pfragment = LoadShadeEffect(0, GetTexFilter(curvb.tex1), curvb.curprim.fge, + curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), + exactcolor, curvb.clamp, context, NULL); + } + + if( pfragment->prog != g_psprog ) { + // programs changed, so reset the texture variables + vb[context].bTexConstsSync = 0; + vb[context].bVarsTexSync = 0; + } + + SetTexVariables(context, pfragment, ptextarg == NULL); + } + else { + pfragment = &ppsRegular[curvb.curprim.fge+2*s_bWriteDepth]; + } + + assert(pfragment != 0 ); + if( curvb.curprim.tme ) { + // have to enable the texture parameters + if( curvb.ptexClamp[0] != 0 ) { + cgGLSetTextureParameter(pfragment->sBitwiseANDX, curvb.ptexClamp[0]); + cgGLEnableTextureParameter(pfragment->sBitwiseANDX); + } + if( curvb.ptexClamp[1] != 0 ) { + cgGLSetTextureParameter(pfragment->sBitwiseANDY, curvb.ptexClamp[1]); + cgGLEnableTextureParameter(pfragment->sBitwiseANDY); + } + if( pfragment->sMemory != NULL && s_ptexCurSet[context] != 0) { + cgGLSetTextureParameter(pfragment->sMemory, s_ptexCurSet[context]); + cgGLEnableTextureParameter(pfragment->sMemory); + } + if( pfragment->sCLUT != NULL && ptexclut != 0 ) { + cgGLSetTextureParameter(pfragment->sCLUT, ptexclut); + cgGLEnableTextureParameter(pfragment->sCLUT); + } + } + + DVProfileFunc _pf4("Flush:before bind"); + GL_REPORT_ERRORD(); + + // set the shaders + SETVERTEXSHADER(pvs[2*((curvb.curprim._val>>1)&3)+8*s_bWriteDepth+context]); + + if( pfragment->prog != g_psprog ) { + cgGLBindProgram(pfragment->prog); + g_psprog = pfragment->prog; + } + + GL_REPORT_ERRORD(); + + DVProfileFunc _pf1("Flush:after bind"); + + BOOL bCanRenderStencil = g_bUpdateStencil && (curvb.prndr->psm&0xf) != 1 && !(curvb.frame.fbm&0x80000000); + if( g_GameSettings & GAME_NOSTENCIL ) + bCanRenderStencil = 0; + + if( s_bDestAlphaTest && bCanRenderStencil) { + glEnable(GL_STENCIL_TEST); + GL_STENCILFUNC(GL_ALWAYS, 0, 0); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + } + else glDisable(GL_STENCIL_TEST); + + glDepthMask(!curvb.zbuf.zmsk); + GL_ZTEST(curtest.zte); + if( curtest.zte ) { + if( curtest.ztst > 1 ) g_nDepthUsed = 2; + if( (curtest.ztst == 2) ^ (g_nDepthBias != 0) ) { + g_nDepthBias = curtest.ztst == 2; + //SETRS(D3DRS_DEPTHBIAS, g_nDepthBias?FtoDW(0.0003f):FtoDW(0.000015f)); + } + + glDepthFunc(g_dwZCmp[curtest.ztst]); + +// if( curtest.ztst == 3 ) { +// // gequal +// if( s_vznorm.y == 0 ) { +// s_vznorm.y = 0.00001f; +// SETCONSTF(GPU_ZNORM, s_vznorm); +// } +// } +// else { +// if( s_vznorm.y > 0 ) { +// s_vznorm.y = 0; +// SETCONSTF(GPU_ZNORM, s_vznorm); +// } +// } + } + + GL_ALPHATEST(curtest.ate&&USEALPHATESTING); + if( curtest.ate ) { + glAlphaFunc(g_dwAlphaCmp[curtest.atst], b2XAlphaTest ? min(1.0f,(float)curtest.aref * (1/ 127.5f)) : curtest.aref*(1/255.0f)); + } + + if( s_bWriteDepth ) { + if(!curvb.zbuf.zmsk) + curvb.pdepth->SetRenderTarget(1); + else + ResetRenderTarget(1); + } + + if( curvb.curprim.abe ) + SetAlphaVariables(curvb.alpha); + else + glDisable(GL_BLEND); + + // needs to be before RenderAlphaTest + if( curvb.fba.fba || s_bDestAlphaTest ) { + if( gs.pabe || (curvb.fba.fba || bCanRenderStencil) && !(curvb.frame.fbm&0x80000000) ) { + RenderFBA(curvb, pfragment->sOneColor); + } + } + + u32 oldabe = curvb.curprim.abe; + if( gs.pabe ) { + //WARN_LOG("PBE!\n"); + curvb.curprim.abe = 1; + glEnable(GL_BLEND); + } + + if( curvb.curprim.abe ) { + + if( //bCanRenderStencil && + (bNeedBlendFactorInAlpha || ((curtest.ate && curtest.atst>1) && (curtest.aref > 0x80))) ) { + // need special stencil processing for the alpha + RenderAlphaTest(curvb, pfragment->sOneColor); + dwUsingSpecialTesting = 1; + } + + // harvest fishing + Vector v = vAlphaBlendColor;// + Vector(0,0,0,(curvb.test.atst==4 && curvb.test.aref>=128)?-0.004f:0); + if( exactcolor ) { v.y *= 255; v.w *= 255; } + cgGLSetParameter4fv(pfragment->sOneColor, v); + } + else { + // not using blending so set to defaults + Vector v = exactcolor ? Vector(1, 510*255.0f/256.0f, 0, 0) : Vector(1,2*255.0f/256.0f,0,0); + cgGLSetParameter4fv(pfragment->sOneColor, v); + } + + if( s_bDestAlphaTest && bCanRenderStencil ) { + // if not 24bit and can write to high alpha bit + RenderStencil(curvb, dwUsingSpecialTesting); + } + else { + s_stencilref = STENCIL_SPECIAL; + s_stencilmask = STENCIL_SPECIAL; + + // setup the stencil to only accept the test pixels + if( dwUsingSpecialTesting ) { + glEnable(GL_STENCIL_TEST); + glStencilMask(STENCIL_PIXELWRITE); + GL_STENCILFUNC(GL_EQUAL, STENCIL_SPECIAL|STENCIL_PIXELWRITE, STENCIL_SPECIAL); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + } + } + +#ifdef _DEBUG + if( bDestAlphaColor == 1 ) { + WARN_LOG("dest alpha blending! manipulate alpha here\n"); + } +#endif + + if( bCanRenderStencil && gs.pabe ) { + // only render the pixels with alpha values >= 0x80 + GL_STENCILFUNC(GL_EQUAL, s_stencilref|STENCIL_FBA, s_stencilmask|STENCIL_FBA); + } + +// curvb.prndr->SetViewport(); +// pd3dDevice->SetScissorRect(&curvb.prndr->scissorrect); +// glEnable(GL_SCISSOR_TEST); + + GL_REPORT_ERRORD(); + if( !curvb.test.ate || curvb.test.atst > 0 ) { + DRAW(); + } + GL_REPORT_ERRORD(); + + if( gs.pabe ) { + // only render the pixels with alpha values < 0x80 + glDisable(GL_BLEND); + GL_STENCILFUNC_SET(); + + Vector v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + if( exactcolor ) v.y *= 255; + cgGLSetParameter4fv(pfragment->sOneColor, v); + + DRAW(); + + // reset + if( !s_stencilmask ) s_stencilfunc = GL_ALWAYS; + GL_STENCILFUNC_SET(); + } + + GL_REPORT_ERRORD(); + + // more work on alpha failure case + if( curtest.ate && curtest.atst != 1 && curtest.afail > 0 ) { + + // need to reverse the test and disable some targets + glAlphaFunc(g_dwReverseAlphaCmp[curtest.atst], b2XAlphaTest ? min(1.0f,(float)curtest.aref * (1/ 127.5f)) : curtest.aref*(1/255.0f)); + + if( curtest.afail & 1 ) { // front buffer update only + + if( curtest.afail == 3 ) // disable alpha + glColorMask(1,1,1,0); + + glDepthMask(0); + + if( s_bWriteDepth ) + ResetRenderTarget(1); + } + else { + // zbuffer update only + glColorMask(0,0,0,0); + } + + if( gs.pabe && bCanRenderStencil ) { + // only render the pixels with alpha values >= 0x80 + Vector v = vAlphaBlendColor; + if( exactcolor ) { v.y *= 255; v.w *= 255; } + cgGLSetParameter4fv(pfragment->sOneColor, v); + glEnable(GL_BLEND); + GL_STENCILFUNC(GL_EQUAL, s_stencilref|STENCIL_FBA, s_stencilmask|STENCIL_FBA); + } + +// IDirect3DQuery9* pOcclusionQuery; +// u32 numberOfPixelsDrawn; +// +// pd3dDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &pOcclusionQuery); +// +// // Add an end marker to the command buffer queue. +// pOcclusionQuery->Issue(D3DISSUE_BEGIN); + + DRAW(); + GL_REPORT_ERRORD(); + +// pOcclusionQuery->Issue(D3DISSUE_END); + // Force the driver to execute the commands from the command buffer. + // Empty the command buffer and wait until the GPU is idle. +// while(S_FALSE == pOcclusionQuery->GetData( &numberOfPixelsDrawn, sizeof(u32), D3DGETDATA_FLUSH )); +// SAFE_RELEASE(pOcclusionQuery); + + if( gs.pabe ) { + // only render the pixels with alpha values < 0x80 + glDisable(GL_BLEND); + GL_STENCILFUNC_SET(); + + Vector v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + if( exactcolor ) v.y *= 255; + cgGLSetParameter4fv(pfragment->sOneColor, v); + + DRAW(); + + // reset + if( oldabe ) glEnable(GL_BLEND); + + if( !s_stencilmask ) s_stencilfunc = GL_ALWAYS; + GL_STENCILFUNC_SET(); + } + + // restore + + if( (curtest.afail & 1) && !curvb.zbuf.zmsk ) { + glDepthMask(1); + + if( s_bWriteDepth ) { + assert( curvb.pdepth != NULL); + curvb.pdepth->SetRenderTarget(1); + } + } + + GL_COLORMASK(s_dwColorWrite); + + // not needed anymore since rest of ops concentrate on image processing + } + + GL_REPORT_ERRORD(); + + if( dwUsingSpecialTesting ) { + // render the real alpha + glDisable(GL_ALPHA_TEST); + glColorMask(0,0,0,1); + + if( s_bWriteDepth ) { + ResetRenderTarget(1); + } + + glDepthMask(0); + + glStencilFunc(GL_EQUAL, STENCIL_SPECIAL|STENCIL_PIXELWRITE, STENCIL_SPECIAL|STENCIL_PIXELWRITE); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + + Vector v = Vector(0,exactcolor ? 510.0f : 2.0f,0,0); + cgGLSetParameter4fv(pfragment->sOneColor, v); + DRAW(); + + // don't need to restore + } + + GL_REPORT_ERRORD(); + + if( s_bDestAlphaTest ) { + if( (s_dwColorWrite&COLORMASK_ALPHA) ) { + if( curvb.fba.fba ) + ProcessFBA(curvb, pfragment->sOneColor); + else if( bCanRenderStencil ) + // finally make sure all entries are 1 when the dest alpha >= 0x80 (if fba is 1, this is already the case) + ProcessStencil(curvb); + } + } + else if( (s_dwColorWrite&COLORMASK_ALPHA) && curvb.fba.fba ) + ProcessFBA(curvb, pfragment->sOneColor); + + if( bDestAlphaColor == 1 ) { + // need to reset the dest colors to their original counter parts + //WARN_LOG("Need to reset dest alpha color\n"); + } + +#ifdef _DEBUG + if( g_bSaveFlushedFrame & 0xf ) { +#ifdef _WIN32 + CreateDirectory("frames", NULL); +#else + mkdir("frames", 0755); +#endif + char str[255]; + sprintf(str, "frames/frame%.4d.tga", g_SaveFrameNum++); + if( (g_bSaveFlushedFrame & 2) ) { + //glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch to the backbuffer + //glFlush(); + //SaveTexture("tex.jpg", GL_TEXTURE_RECTANGLE_NV, curvb.prndr->ptex, curvb.prndr->fbw<fbh<fbw<fbh<SetRenderTarget(1); + } + } + + if( curvb.test.ate && USEALPHATESTING ) + glEnable(GL_ALPHA_TEST); + + GL_ZTEST(curtest.zte); + } + + if( dwFilterOpts ) { + // undo filter changes (binding didn't change) + if( dwFilterOpts & 1 ) glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if( dwFilterOpts & 2 ) glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + +//#ifndef RELEASE_TO_PUBLIC + ppf += curvb.nCount+0x100000; +//#endif + + curvb.nCount = 0; + curvb.curprim.abe = oldabe; + //if( oldabe ) glEnable(GL_BLEND); + + if( conf.options & GSOPTION_WIREFRAME ) { + // always render first few geometry as solid + if( s_nWireframeCount > 0 ) { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + --s_nWireframeCount; + } + } + + GL_REPORT_ERRORD(); +} + +void ZeroGS::ProcessMessages() +{ + if( listMsgs.size() > 0 ) { + int left = 25, top = 15; + list::iterator it = listMsgs.begin(); + + while( it != listMsgs.end() ) { + DrawText(it->str, left+1, top+1, 0xff000000); + DrawText(it->str, left, top, 0xffffff30); + top += 15; + + if( (int)(it->dwTimeStamp - timeGetTime()) < 0 ) + it = listMsgs.erase(it); + else ++it; + } + } +} + +void ZeroGS::RenderCustom(float fAlpha) +{ + GLenum err = GL_NO_ERROR; + + GL_REPORT_ERROR(); + + fAlpha = 1; + glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch to the backbuffer + + glDisable(GL_STENCIL_TEST); + glDisable(GL_DEPTH_TEST); + glDepthMask(0); + glColorMask(1,1,1,1); + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + glDisable(GL_SCISSOR_TEST); + glViewport(0, 0, nBackbufferWidth, nBackbufferHeight); + + // play custom animation + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); + + // tex coords + Vector v = Vector(1/32767.0f, 1/32767.0f, 0, 0); + cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); + v.x = (float)nLogoWidth; + v.y = (float)nLogoHeight; + cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); + + v.x = v.y = v.z = v.w = fAlpha; + cgGLSetParameter4fv(ppsBaseTexture.sOneColor, v); + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + // inside vb[0]'s target area, so render that region only + cgGLSetTextureParameter(ppsBaseTexture.sFinal, ptexLogo); + cgGLEnableTextureParameter(ppsBaseTexture.sFinal); + + glBindBuffer(GL_ARRAY_BUFFER, vboRect); + SET_STREAM(); + + SETVERTEXSHADER(pvsBitBlt.prog); + SETPIXELSHADER(ppsBaseTexture.prog); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + // restore + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + ProcessMessages(); + +#ifdef _WIN32 + SwapBuffers(hDC); +#else + glXSwapBuffers(GLWin.dpy, GLWin.win); +#endif + + glEnable(GL_SCISSOR_TEST); + glEnable(GL_STENCIL_TEST); + + vb[0].bSyncVars = 0; + vb[1].bSyncVars = 0; + + GL_REPORT_ERROR(); + GLint status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + assert( status == GL_FRAMEBUFFER_COMPLETE_EXT || status == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT ); +} + +// adjusts trans to preserve aspect ratio +void ZeroGS::AdjustTransToAspect(Vector& v, int dispwidth, int dispheight) +{ + double temp; + float f; + if( dispwidth * nBackbufferHeight > dispheight * nBackbufferWidth) { + // limited by width + + // change in ratio + f = ((float)nBackbufferWidth / (float)dispwidth) / ((float)nBackbufferHeight / (float)dispheight); + v.y *= f; + v.w *= f; + + // scanlines mess up when not aligned right + v.y += (1-(float)modf(v.y*(float)nBackbufferHeight*0.5f+0.05f, &temp))*2.0f/(float)nBackbufferHeight; + v.w += (1-(float)modf(v.w*(float)nBackbufferHeight*0.5f+0.05f, &temp))*2.0f/(float)nBackbufferHeight; + } + else { + // limited by height + f = ((float)nBackbufferHeight / (float)dispheight) / ((float)nBackbufferWidth / (float)dispwidth); + f -= (float)modf(f*nBackbufferWidth, &temp)/(float)nBackbufferWidth; + v.x *= f; + v.z *= f; + } + +// v.y *= -1; +// v.w *= -1; + v *= 1/32767.0f; +} + +void ZeroGS::Restore() +{ + if( !g_bIsLost ) + return; + + //if( SUCCEEDED(pd3dDevice->Reset(&d3dpp)) ) { + g_bIsLost = 0; + // handle lost states + ZeroGS::ChangeDeviceSize(nBackbufferWidth, nBackbufferHeight); + //} +} + +void ZeroGS::RenderCRTC(int interlace) +{ + if( g_bIsLost ) return; + +// Crashes Final Fantasy X at startup if uncommented. --arcum42 +//#ifdef RELEASE_TO_PUBLIC +// if(g_nRealFrame < 80 ) { +// RenderCustom( min(1.0f, 2.0f - (float)g_nRealFrame / 40.0f) ); +// +// if( g_nRealFrame == 79 ) +// SAFE_RELEASE_TEX(ptexLogo); +// return; +// } +//#endif + + if( conf.mrtdepth && pvs[8] == NULL ) { + conf.mrtdepth = 0; + s_bWriteDepth = FALSE; + ERROR_LOG("Disabling MRT depth writing\n"); + } + + Flush(0); + Flush(1); + GL_REPORT_ERRORD(); + + DVProfileFunc _pf("RenderCRTC"); + + // frame skipping + if( g_nFrameRender > 0 ) { + + if( g_nFrameRender < 8 ) { + g_nFrameRender++; + if( g_nFrameRender <= 3 ) { + g_nFramesSkipped++; + return; + } + } + } + else { + if( g_nFrameRender < -1 ) { + g_nFramesSkipped++; + return; + } + g_nFrameRender--; + } + + if( g_bSaveFrame ) { + if( vb[0].prndr != NULL ) { + SaveTexture("frame1.tga", GL_TEXTURE_RECTANGLE_NV, vb[0].prndr->ptex, vb[0].prndr->fbw<fbh<ptex, vb[1].prndr->fbw<fbh< 0 ) + FlushTransferRanges(NULL); + + //g_GameSettings |= GAME_VSSHACK|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE; + //s_bWriteDepth = TRUE; + g_SaveFrameNum = 0; + g_bSaveFlushedFrame = 1; + + // reset fba after every frame + vb[0].fba.fba = 0; + vb[1].fba.fba = 0; + +// static int counter = 0; +// counter++; + u32 bInterlace = SMODE2->INT && SMODE2->FFMD && (conf.interlace<2); + glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch to the backbuffer + glViewport(0, 0, nBackbufferWidth, nBackbufferHeight); + + // if interlace, only clear every other vsync + if(!bInterlace ) { + u32 color = COLOR_ARGB(0, BGCOLOR->R, BGCOLOR->G, BGCOLOR->B); + glClear(GL_COLOR_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); + } + + SETVERTEXSHADER(pvsBitBlt.prog); + glBindBuffer(GL_ARRAY_BUFFER, vboRect); + SET_STREAM(); + GL_REPORT_ERRORD(); + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glDisable(GL_DEPTH_TEST); + glDepthMask(0); + glColorMask(1,1,1,1); + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_STENCIL_TEST); + + GL_REPORT_ERRORD(); + + BOOL bUsingStencil = 0; + + if( bInterlace ) g_PrevBitwiseTexX = -1; // reset since will be using + + tex0Info dispinfo[2]; + + for(int i = 0; i < 2; ++i) { + + if( !(*(u32*)(PMODE) & (1<MAGH+1; + int magv = pd->MAGV+1; + + dispinfo[i].tbp0 = pfb->FBP << 5; + dispinfo[i].tbw = pfb->FBW << 6; + dispinfo[i].tw = (pd->DW + 1) / magh; + dispinfo[i].th = (pd->DH + 1) / magv; + dispinfo[i].psm = pfb->PSM; + + // hack!! + // 2 * dispinfo[i].tw / dispinfo[i].th <= 1, metal slug 4 + if( bInterlace && 2 * dispinfo[i].tw / dispinfo[i].th <= 1 && !(g_GameSettings&GAME_INTERLACE2X) ) { + dispinfo[i].th >>= 1; + } + } + + //int dispwidth = max(dispinfo[0].tw, dispinfo[1].tw), dispheight = max(dispinfo[0].th, dispinfo[1].th); + + // hack!, CMOD != 3, gradius +// if( SMODE2->INT && SMODE2->FFMD && SMODE1->CMOD == 3 && dispwidth <= 320) +// dispwidth *= 2; + + // hack! makai + //if( !bInterlace && dispheight * 2 < dispwidth ) dispheight *= 2; + + // start from the last circuit + for(int i = !PMODE->SLBG; i >= 0; --i) { + + tex0Info& texframe = dispinfo[i]; + if( texframe.th <= 1 ) + continue; + + GSRegDISPFB* pfb = i ? DISPFB2 : DISPFB1; + GSRegDISPLAY* pd = i ? DISPLAY2 : DISPLAY1; + + Vector v, valpha; + u32 interlacetex = 0; + + if( bInterlace ) { + + texframe.th >>= 1; + + // interlace mode + interlacetex = CreateInterlaceTex(2*texframe.th); + + if( interlace == (conf.interlace&1) ) { + // pass if odd + valpha.z = 1.0f; + valpha.w = -0.4999f; + } + else { + // pass if even + valpha.z = -1.0f; + valpha.w = 0.5001f; + } + } + else { + + if( SMODE2->INT && SMODE2->FFMD ) { + texframe.th >>= 1; + } + + // always pass interlace test + valpha.z = 0; + valpha.w = 1; + } + + int bpp = 4; + if( texframe.psm == 0x12 ) bpp = 3; + else if( texframe.psm & 2 ) bpp = 2; + + // get the start and end addresses of the buffer + int start, end; + GetRectMemAddress(start, end, texframe.psm, 0, 0, texframe.tw, texframe.th, texframe.tbp0, texframe.tbw); + + if( i == 0 ) { + // setup right blending + glEnable(GL_BLEND); + zgsBlendEquationSeparateEXT(GL_FUNC_ADD, GL_FUNC_ADD); + + if( PMODE->MMOD ) { + glBlendColorEXT(PMODE->ALP*(1/255.0f), PMODE->ALP*(1/255.0f), PMODE->ALP*(1/255.0f), 0.5f); + s_srcrgb = GL_CONSTANT_COLOR_EXT; + s_dstrgb = GL_ONE_MINUS_CONSTANT_COLOR_EXT; + } + else { + s_srcrgb = GL_SRC_ALPHA; + s_dstrgb = GL_ONE_MINUS_SRC_ALPHA; + } + + s_srcalpha = PMODE->AMOD ? GL_ZERO : GL_ONE; + s_dstalpha = PMODE->AMOD? GL_ONE : GL_ZERO; + zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha); + } + + if( bUsingStencil ) { + glStencilMask(1< listTargs; + + s_RTs.GetTargs(start, end, listTargs); + + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ) { + + CRenderTarget* ptarg = *it; + + if( ptarg->fbw == texframe.tbw && !(ptarg->status&CRenderTarget::TS_NeedUpdate) && ((256/bpp)*(texframe.tbp0-ptarg->fbp))%texframe.tbw == 0 ) { + + if( ptarg->fbp != texframe.tbp0 ) { + // look for a better target (metal slug 5) + list::iterator itbetter; + for(itbetter = listTargs.begin(); itbetter != listTargs.end(); ++itbetter ) { + if( (*itbetter)->fbp == texframe.tbp0 ) + break; + } + + if( itbetter != listTargs.end() ) { + it = listTargs.erase(it); + continue; + } + } + + if( g_bSaveFinalFrame ) + SaveTexture("frame1.tga", GL_TEXTURE_RECTANGLE_NV, ptarg->ptex, ptarg->fbw<fbh<DBY; + int movy = 0; + + // determine the rectangle to render + if( ptarg->fbp < texframe.tbp0 ) { + dby += (256/bpp)*(texframe.tbp0-ptarg->fbp)/texframe.tbw; + } + else if( ptarg->fbp > texframe.tbp0 ) { + dby -= (256/bpp)*(ptarg->fbp-texframe.tbp0)/texframe.tbw; + + if( dby < 0 ) { + movy = -dby; + dby = 0; + } + } + + int dh = min(ptarg->fbh - dby, texframe.th-movy); + + if( dh >= 64 ) { + + if( ptarg->fbh - dby < texframe.th-movy && !bUsingStencil ) { + + if( !bUsingStencil ) { + glClear(GL_STENCIL_BUFFER_BIT); + } + bUsingStencil = 1; + glEnable(GL_STENCIL_TEST); + GL_STENCILFUNC(GL_NOTEQUAL, 3, 1<fbh; + + // tex coords + v = Vector((float)(texframe.tw << s_AAx), (float)(dh << s_AAy), (float)(pfb->DBX << s_AAx), (float)(dby< 0 ) + v.w -= movy/(float)texframe.th; + + if (bInterlace && interlace == (conf.interlace&1) ) { + // move down by 1 pixel + v.w += 1.0f / (float)dh; + } + + AdjustTransToAspect(v, 640, 480); + cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); + + cgGLSetParameter4fv(pvsBitBlt.fBitBltTrans, Vector(fih * 0.5f, fih * -0.5f, fih * 0.5f, fih * 0.5f)); + + // use g_fInvTexDims to store inverse texture dims + if( ppsCRTCTarg[bInterlace].sInvTexDims ) { + v.x = fiw; + v.y = fih; + v.z = 0; + cgGLSetParameter4fv(ppsCRTCTarg[bInterlace].sInvTexDims, v); + } + + cgGLSetParameter4fv(ppsCRTCTarg[bInterlace].sOneColor, valpha); + + // inside vb[0]'s target area, so render that region only + cgGLSetTextureParameter(ppsCRTCTarg[bInterlace].sFinal, ptarg->ptex); + cgGLEnableTextureParameter(ppsCRTCTarg[bInterlace].sFinal); + if( interlacetex != 0 ) { + cgGLSetTextureParameter(ppsCRTCTarg[bInterlace].sInterlace, interlacetex); + cgGLEnableTextureParameter(ppsCRTCTarg[bInterlace].sInterlace); + } + + SETPIXELSHADER(ppsCRTCTarg[bInterlace].prog); + GL_REPORT_ERRORD(); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + //SaveRenderTarget("temp.tga", nBackbufferWidth, nBackbufferHeight, 0); + + if( abs(dh - (int)texframe.th) <= 1 ) { + bSkip = 1; + break; + } + if( abs(dh - (int)ptarg->fbh) <= 1 ) { + it = listTargs.erase(it); + continue; + } + } + } + + ++it; + } + + if( !bSkip ) { + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) + (*it)->Resolve(); + + // context has to be 0 + CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); + SetTexVariablesInt(0, g_bCRTCBilinear?2:0, texframe, pmemtarg, &ppsCRTC[bInterlace], 1); + cgGLSetTextureParameter(ppsCRTC[bInterlace].sMemory, pmemtarg->ptex->tex); + cgGLEnableTextureParameter(ppsCRTC[bInterlace].sMemory); + + if( g_bSaveFinalFrame ) + SaveTex(&texframe, g_bSaveFinalFrame-1>0); + + // finally render from the memory (note that the stencil buffer will keep previous regions) + v = Vector(1,1,0,0); + + if (bInterlace && interlace == (conf.interlace)) { + // move down by 1 pixel + v.w += 1.0f / (float)texframe.th; + } + + cgGLSetParameter4fv(ppsCRTC[bInterlace].sOneColor, valpha); + + AdjustTransToAspect(v, 640, 480); + cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); + + float fih = 1.0f / (float)texframe.th; + if( g_bCRTCBilinear ) + cgGLSetParameter4fv(pvsBitBlt.sBitBltTex, Vector(texframe.tw,texframe.th,-0.5f,-0.5f)); + else + cgGLSetParameter4fv(pvsBitBlt.sBitBltTex, Vector(1,1,-0.5f/(float)texframe.tw,-0.5f/(float)texframe.th)); + + cgGLSetParameter4fv(pvsBitBlt.fBitBltTrans, Vector(fih * 0.5f, fih * -0.5f, fih * 0.5f, fih * 0.5f)); + + // use g_fInvTexDims to store inverse texture dims + if( ppsCRTC[bInterlace].sInvTexDims ) { + v.x = 1.0f / (float)texframe.tw; + v.y = fih; + v.z = 0;//-0.5f * v.x; + v.w = -0.5f * fih; + cgGLSetParameter4fv(ppsCRTC[bInterlace].sInvTexDims, v); + } + + if( interlacetex != 0 ) { + cgGLSetTextureParameter(ppsCRTC[bInterlace].sInterlace, interlacetex); + cgGLEnableTextureParameter(ppsCRTC[bInterlace].sInterlace); + } + + SETPIXELSHADER(ppsCRTC[bInterlace].prog); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + } + } + + GL_REPORT_ERRORD(); + if(1) {// || !bInterlace) { + glDisable(GL_BLEND); + ProcessMessages(); + + if( g_bMakeSnapshot ) { + char str[64]; + int left = 200, top = 15; + sprintf(str, "ZeroGS %d.%d.%d - %.1f fps %s", zgsrevision, zgsbuild, zgsminor, fFPS, s_frameskipping?" - frameskipping":""); + + DrawText(str, left+1, top+1, 0xff000000); + DrawText(str, left, top, 0xffc0ffff); + } + + if( g_bDisplayFPS ) { + char str[64]; + int left = 10, top = 15; + sprintf(str, "%.1f fps", fFPS); + + DrawText(str, left+1, top+1, 0xff000000); + DrawText(str, left, top, 0xffc0ffff); + } + + if (glGetError() != GL_NO_ERROR) DEBUG_LOG("glerror before swap!\n"); + + +#ifdef _WIN32 + static u32 lastswaptime = 0; + //if( timeGetTime() - lastswaptime > 14 ) { + SwapBuffers(hDC); + lastswaptime = timeGetTime(); + //} +#else + glXSwapBuffers(GLWin.dpy, GLWin.win); +#endif + +// if( glGetError() != GL_NO_ERROR) { +// // device is lost, need to recreate +// ERROR_LOG("device lost\n"); +// g_bIsLost = TRUE; +// Reset(); +// return; +// } + + if( conf.options & GSOPTION_WIREFRAME ) { + // clear all targets + s_nWireframeCount = 1; + } + + if( g_bMakeSnapshot ) { + + if( SaveRenderTarget(strSnapshot != ""?strSnapshot.c_str():"temp.jpg", nBackbufferWidth, -nBackbufferHeight, 0)) {//(conf.options&GSOPTION_TGASNAP)?0:1) ) { + char str[255]; + sprintf(str, "saved %s\n", strSnapshot.c_str()); + AddMessage(str, 500); + } + + g_bMakeSnapshot = 0; + } + + if( s_avicapturing ) { + CaptureFrame(); + } + + if( s_nNewWidth >= 0 && s_nNewHeight >= 0 && !g_bIsLost ) { + Reset(); + ChangeDeviceSize(s_nNewWidth, s_nNewHeight); + s_nNewWidth = s_nNewHeight = -1; + } + + // switch the fbp lists +// s_nCurFBPSet ^= 1; +// s_setFBP[s_nCurFBPSet].clear(); + //s_nCurFrameMap ^= 1; + //s_mapFrameHeights[s_nCurFrameMap].clear(); + } + + // switch back to rendering to textures + glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, s_uFramebuffer ); + + g_MemTargs.DestroyCleared(); + + if( s_vecTempTextures.size() > 0 ) + glDeleteTextures((GLsizei)s_vecTempTextures.size(), &s_vecTempTextures[0]); + s_vecTempTextures.clear(); + + if( EXTWRITE->WRITE&1 ) { + WARN_LOG("EXTWRITE\n"); + ExtWrite(); + EXTWRITE->WRITE = 0; + } + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glEnable(GL_SCISSOR_TEST); + + if( icurctx >= 0 ) { + vb[icurctx].bVarsSetTarg = FALSE; + vb[icurctx].bVarsTexSync = FALSE; + vb[0].bVarsTexSync = FALSE; + } + + // statistics + if( s_nWriteDepthCount > 0 ) { + assert( conf.mrtdepth ); + if( --s_nWriteDepthCount <= 0 ) { + s_bWriteDepth = FALSE; + } + } + + if( s_nWriteDestAlphaTest > 0 ) { + if( --s_nWriteDestAlphaTest <= 0 ) { + s_bDestAlphaTest = FALSE; + } + } + + if( g_GameSettings & GAME_AUTORESET ) { + s_nResolveCounts[s_nCurResolveIndex] = s_nResolved; + s_nCurResolveIndex = (s_nCurResolveIndex+1)%ARRAY_SIZE(s_nResolveCounts); + + int total = 0; + for(int i = 0; i < ARRAY_SIZE(s_nResolveCounts); ++i) total += s_nResolveCounts[i]; + + if( total / ARRAY_SIZE(s_nResolveCounts) > 3 ) { + if( s_nLastResolveReset > (int)(fFPS * 8) ) { + // reset + ERROR_LOG("video mem reset\n"); + s_nLastResolveReset = 0; + memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); + + s_RTs.ResolveAll(); + s_RTs.Destroy(); + s_DepthRTs.ResolveAll(); + s_DepthRTs.Destroy(); + + vb[0].prndr = NULL; vb[0].pdepth = NULL; vb[0].bNeedFrameCheck = 1; vb[0].bNeedZCheck = 1; + vb[1].prndr = NULL; vb[1].pdepth = NULL; vb[1].bNeedFrameCheck = 1; vb[1].bNeedZCheck = 1; + } + } + + s_nLastResolveReset++; + } + + if( s_nResolved > 8 ) s_nResolved = 2; + else if( s_nResolved > 0 ) --s_nResolved; + + if( g_nDepthUsed > 0 ) --g_nDepthUsed; + + s_ClutResolve = 0; + g_nDepthUpdateCount = 0; + + maxmin = 608; +} + +////////////////////////// +// Internal Definitions // +////////////////////////// + + +__forceinline void MOVZ(VertexGPU *p, u32 gsz, const VB& curvb) +{ + p->z = curvb.zprimmask==0xffff?min((u32)0xffff, gsz):gsz; +} + +__forceinline void MOVFOG(VertexGPU *p, Vertex gsf) +{ + p->f = ((s16)(gsf).f<<7)|0x7f; +} + +__forceinline void SET_VERTEX(VertexGPU *p, int Index, const VB& curvb) +{ + int index = Index; + + p->x = (((int)gs.gsvertex[index].x - curvb.offset.x)>>1)&0xffff; + p->y = (((int)gs.gsvertex[index].y - curvb.offset.y)>>1)&0xffff; + + /*x = ((int)gs.gsvertex[index].x - curvb.offset.x); + y = ((int)gs.gsvertex[index].y - curvb.offset.y); + p.x = (x&0x7fff) | (x < 0 ? 0x8000 : 0); + p.y = (y&0x7fff) | (y < 0 ? 0x8000 : 0);*/ + + p->f = ((s16)gs.gsvertex[index].f<<7)|0x7f; + MOVZ(p, gs.gsvertex[index].z, curvb); + p->rgba = prim->iip ? gs.gsvertex[index].rgba : gs.rgba; + + if ((g_GameSettings & GAME_TEXAHACK) && !(p->rgba&0xffffff)) + p->rgba = 0; + if (prim->tme ) + { + if( prim->fst ) + { + p->s = (float)gs.gsvertex[index].u * fiTexWidth[prim->ctxt]; + p->t = (float)gs.gsvertex[index].v * fiTexHeight[prim->ctxt]; + p->q = 1; + } + else + { + p->s = gs.gsvertex[index].s; + p->t = gs.gsvertex[index].t; + p->q = gs.gsvertex[index].q; + } + } +} + +#define OUTPUT_VERT(fn, vert, id) { \ + fn("%c%d(%d): xyzf=(%4d,%4d,0x%x,%3d), rgba=0x%8.8x, stq = (%2.5f,%2.5f,%2.5f)\n", id==0?'*':' ', id, prim->prim, vert.x/8, vert.y/8, vert.z, vert.f/128, \ + vert.rgba, Clamp(vert.s, -10, 10), Clamp(vert.t, -10, 10), Clamp(vert.q, -10, 10)); \ +} \ + +void ZeroGS::KickPoint() +{ + assert( gs.primC >= 1 ); + + VB& curvb = vb[prim->ctxt]; + if (curvb.bNeedTexCheck) curvb.FlushTexData(); + + if ((vb[!prim->ctxt].nCount > 0) && (vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp)) + { + assert( vb[prim->ctxt].nCount == 0 ); + Flush(!prim->ctxt); + } + + curvb.NotifyWrite(1); + + int last = (gs.primIndex+2)%ARRAY_SIZE(gs.gsvertex); + + VertexGPU* p = curvb.pBufferData+curvb.nCount; + SET_VERTEX(&p[0], last, curvb); + curvb.nCount++; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); +#endif +} + +void ZeroGS::KickLine() +{ + assert( gs.primC >= 2 ); + VB& curvb = vb[prim->ctxt]; + if( curvb.bNeedTexCheck ) + curvb.FlushTexData(); + + if( vb[!prim->ctxt].nCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].nCount == 0 ); + Flush(!prim->ctxt); + } + + curvb.NotifyWrite(2); + + int next = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + int last = (gs.primIndex+2)%ARRAY_SIZE(gs.gsvertex); + + VertexGPU* p = curvb.pBufferData+curvb.nCount; + SET_VERTEX(&p[0], next, curvb); + SET_VERTEX(&p[1], last, curvb); + + curvb.nCount += 2; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); +#endif +} + +void ZeroGS::KickTriangle() +{ + assert( gs.primC >= 3 ); + VB& curvb = vb[prim->ctxt]; + if (curvb.bNeedTexCheck) curvb.FlushTexData(); + + if ((vb[!prim->ctxt].nCount > 0) && (vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp)) + { + assert( vb[prim->ctxt].nCount == 0 ); + Flush(!prim->ctxt); + } + + curvb.NotifyWrite(3); + + VertexGPU* p = curvb.pBufferData+curvb.nCount; + SET_VERTEX(&p[0], 0, curvb); + SET_VERTEX(&p[1], 1, curvb); + SET_VERTEX(&p[2], 2, curvb); + + curvb.nCount += 3; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); + OUTPUT_VERT(PRIM_LOG, p[2], 2); +#endif +} + +void ZeroGS::KickTriangleFan() +{ + assert( gs.primC >= 3 ); + VB& curvb = vb[prim->ctxt]; + if (curvb.bNeedTexCheck) curvb.FlushTexData(); + + if ((vb[!prim->ctxt].nCount > 0) && (vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp)) + { + assert( vb[prim->ctxt].nCount == 0 ); + Flush(!prim->ctxt); + } + + curvb.NotifyWrite(3); + + VertexGPU* p = curvb.pBufferData+curvb.nCount; + SET_VERTEX(&p[0], 0, curvb); + SET_VERTEX(&p[1], 1, curvb); + SET_VERTEX(&p[2], 2, curvb); + + curvb.nCount += 3; + + // add 1 to skip the first vertex + if (gs.primIndex == gs.nTriFanVert) + gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); + OUTPUT_VERT(PRIM_LOG, p[2], 2); +#endif +} + +__forceinline void SetKickVertex(VertexGPU *p, Vertex v, int next, const VB& curvb) +{ + SET_VERTEX(p, next, curvb); + MOVZ(p, v.z, curvb); + MOVFOG(p, v); +} + +void ZeroGS::KickSprite() +{ + assert( gs.primC >= 2 ); + VB& curvb = vb[prim->ctxt]; + + if (curvb.bNeedTexCheck) curvb.FlushTexData(); + + if ((vb[!prim->ctxt].nCount > 0) && (vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp)) + { + assert( vb[prim->ctxt].nCount == 0 ); + Flush(!prim->ctxt); + } + + curvb.NotifyWrite(6); + + int next = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + int last = (gs.primIndex+2)%ARRAY_SIZE(gs.gsvertex); + + // sprite is too small and AA shows lines (tek4) + if ( s_AAx ) + { + gs.gsvertex[last].x += 4; + if( s_AAy ) gs.gsvertex[last].y += 4; + } + + // might be bad sprite (KH dialog text) + //if( gs.gsvertex[next].x == gs.gsvertex[last].x || gs.gsvertex[next].y == gs.gsvertex[last].y ) + //return; + + VertexGPU* p = curvb.pBufferData+curvb.nCount; + + SetKickVertex(&p[0], gs.gsvertex[last], next, curvb); + SetKickVertex(&p[3], gs.gsvertex[last], next, curvb); + SetKickVertex(&p[1], gs.gsvertex[last], last, curvb); + SetKickVertex(&p[4], gs.gsvertex[last], last, curvb); + SetKickVertex(&p[2], gs.gsvertex[last], next, curvb); + + p[2].s = p[1].s; + p[2].x = p[1].x; + + SetKickVertex(&p[5], gs.gsvertex[last], last, curvb); + p[5].s = p[0].s; + p[5].x = p[0].x; + + curvb.nCount += 6; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); +#endif +} + +void ZeroGS::KickDummy() +{ + //GREG_LOG("Kicking bad primitive: %.8x\n", *(u32*)prim); +} + +__forceinline void ZeroGS::RenderFBA(const VB& curvb, CGparameter sOneColor) +{ + // add fba to all pixels + GL_STENCILFUNC(GL_ALWAYS, STENCIL_FBA, 0xff); + glStencilMask(STENCIL_CLEAR); + glStencilOp(GL_ZERO, GL_KEEP, GL_REPLACE); + + glDisable(GL_DEPTH_TEST); + glDepthMask(0); + glColorMask(0,0,0,0); + + if( s_bWriteDepth ) ResetRenderTarget(1); + + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GEQUAL, 1); + + Vector v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + cgGLSetParameter4fv(sOneColor, v); + + DRAW(); + + if( !curvb.test.ate ) + glDisable(GL_ALPHA_TEST); + else + glAlphaFunc(g_dwAlphaCmp[curvb.test.atst], b2XAlphaTest ? min(1.0f,curvb.test.aref*(1/127.5f)) : curvb.test.aref*(1/255.0f)); + + // reset (not necessary) + GL_COLORMASK(s_dwColorWrite); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + if( !curvb.zbuf.zmsk ) + { + glDepthMask(1); + + assert( curvb.pdepth != NULL ); + if( s_bWriteDepth ) curvb.pdepth->SetRenderTarget(1); + } + GL_ZTEST(curvb.test.zte); +} + +__forceinline void ZeroGS::RenderAlphaTest(const VB& curvb, CGparameter sOneColor) +{ + if( !g_bUpdateStencil ) return; + + if( curvb.test.ate ) + if( curvb.test.afail == 1 ) glDisable(GL_ALPHA_TEST); + + glDepthMask(0); + glColorMask(0,0,0,0); + + Vector v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + cgGLSetParameter4fv(sOneColor, v); + + if (s_bWriteDepth) ResetRenderTarget(1); + + // or a 1 to the stencil buffer wherever alpha passes + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + s_stencilfunc = GL_ALWAYS; + + glEnable(GL_STENCIL_TEST); + + if( !s_bDestAlphaTest ) + { + // clear everything + s_stencilref = 0; + glStencilMask(STENCIL_CLEAR); + glDisable(GL_ALPHA_TEST); + GL_STENCILFUNC_SET(); + DRAW(); + + if( curvb.test.ate && curvb.test.afail != 1 && USEALPHATESTING ) + glEnable(GL_ALPHA_TEST); + } + + if( curvb.test.ate && curvb.test.atst>1 && curvb.test.aref > 0x80) + { + v.x = 1; v.y = 1; v.z = 0; v.w = 0; + cgGLSetParameter4fv(sOneColor, v); + glAlphaFunc(g_dwAlphaCmp[curvb.test.atst], curvb.test.aref*(1/255.0f)); + } + + s_stencilref = STENCIL_SPECIAL; + glStencilMask(STENCIL_SPECIAL); + GL_STENCILFUNC_SET(); + glDisable(GL_DEPTH_TEST); + + DRAW(); + + if( curvb.test.zte ) + glEnable(GL_DEPTH_TEST); + GL_ALPHATEST(0); + GL_COLORMASK(s_dwColorWrite); + + if( !curvb.zbuf.zmsk ) + { + glDepthMask(1); + + // set rt next level + if (s_bWriteDepth) curvb.pdepth->SetRenderTarget(1); + } +} + +__forceinline void ZeroGS::RenderStencil(const VB& curvb, u32 dwUsingSpecialTesting) +{ + //NOTE: This stencil hack for dest alpha testing ONLY works when + // the geometry in one DrawPrimitive call does not overlap + + // mark the stencil buffer for the new data's bits (mark 4 if alpha is >= 0xff) + // mark 4 if a pixel was written (so that the stencil buf can be changed with new values) + glStencilMask(STENCIL_PIXELWRITE); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + s_stencilmask = (curvb.test.date?STENCIL_ALPHABIT:0)|(dwUsingSpecialTesting?STENCIL_SPECIAL:0); + s_stencilfunc = s_stencilmask ? GL_EQUAL : GL_ALWAYS; + s_stencilref = curvb.test.date*curvb.test.datm|STENCIL_PIXELWRITE|(dwUsingSpecialTesting?STENCIL_SPECIAL:0); + GL_STENCILFUNC_SET(); +} + +__forceinline void ZeroGS::ProcessStencil(const VB& curvb) +{ + assert( !curvb.fba.fba ); + + // set new alpha bit + glStencilMask(STENCIL_ALPHABIT); + GL_STENCILFUNC(GL_EQUAL, STENCIL_PIXELWRITE, STENCIL_PIXELWRITE|STENCIL_FBA); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + glDisable(GL_DEPTH_TEST); + glDepthMask(0); + glColorMask(0,0,0,0); + + if (s_bWriteDepth) ResetRenderTarget(1); + + GL_ALPHATEST(0); + + SETPIXELSHADER(ppsOne.prog); + DRAW(); + + // process when alpha >= 0xff + GL_STENCILFUNC(GL_EQUAL, STENCIL_PIXELWRITE|STENCIL_FBA|STENCIL_ALPHABIT, STENCIL_PIXELWRITE|STENCIL_FBA); + DRAW(); + + // clear STENCIL_PIXELWRITE bit + glStencilMask(STENCIL_CLEAR); + GL_STENCILFUNC(GL_ALWAYS, 0, STENCIL_PIXELWRITE|STENCIL_FBA); + + DRAW(); + + // restore state + GL_COLORMASK(s_dwColorWrite); + + if( curvb.test.ate && USEALPHATESTING) + glEnable(GL_ALPHA_TEST); + + if( !curvb.zbuf.zmsk ) { + glDepthMask(1); + + if( s_bWriteDepth ) { + assert( curvb.pdepth != NULL ); + curvb.pdepth->SetRenderTarget(1); + } + } + + GL_ZTEST(curvb.test.zte); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); +} + +__forceinline void ZeroGS::ProcessFBA(const VB& curvb, CGparameter sOneColor) +{ + if( (curvb.frame.fbm&0x80000000) ) return; + + // add fba to all pixels that were written and alpha was less than 0xff + glStencilMask(STENCIL_ALPHABIT); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + GL_STENCILFUNC(GL_EQUAL, STENCIL_FBA|STENCIL_PIXELWRITE|STENCIL_ALPHABIT, STENCIL_PIXELWRITE|STENCIL_FBA); + + glDisable(GL_DEPTH_TEST); + glDepthMask(0); + glColorMask(0,0,0,1); + + if( s_bWriteDepth ) { + ResetRenderTarget(1); + } + + // processes the pixels with ALPHA < 0x80*2 + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_LEQUAL, 1); + + // add 1 to dest + GL_BLEND_ALPHA(GL_ONE, GL_ONE); + GL_BLENDEQ_ALPHA(GL_FUNC_ADD); + + float f = 1; + cgGLSetParameter4fv(sOneColor, &f); + SETPIXELSHADER(ppsOne.prog); + + DRAW(); + + glDisable(GL_ALPHA_TEST); + + // reset bits + glStencilMask(STENCIL_CLEAR); + GL_STENCILFUNC(GL_GREATER, 0, STENCIL_PIXELWRITE|STENCIL_FBA); + glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO); + + DRAW(); + + if( curvb.test.atst && USEALPHATESTING) { + glEnable(GL_ALPHA_TEST); + glAlphaFunc(g_dwAlphaCmp[curvb.test.atst], b2XAlphaTest ? min(1.0f,curvb.test.aref*(1/127.5f)) : curvb.test.aref*(1/255.0f)); + } + + // restore (SetAlphaVariables) + GL_BLEND_ALPHA(GL_ONE, GL_ZERO); + if(vAlphaBlendColor.y<0) GL_BLENDEQ_ALPHA(GL_FUNC_REVERSE_SUBTRACT); + + // reset (not necessary) + GL_COLORMASK(s_dwColorWrite); + + if( !curvb.zbuf.zmsk ) { + glDepthMask(1); + + if (s_bWriteDepth) curvb.pdepth->SetRenderTarget(1); + } + GL_ZTEST(curvb.test.zte); +} + +inline void ZeroGS::SetContextTarget(int context) +{ + VB& curvb = vb[context]; + GL_REPORT_ERRORD(); + + if( curvb.prndr == NULL ) + curvb.prndr = s_RTs.GetTarg(curvb.frame, 0, GET_MAXHEIGHT(curvb.gsfb.fbp, curvb.gsfb.fbw, curvb.gsfb.psm)); + + // make sure targets are valid + if( curvb.pdepth == NULL ) { + frameInfo f; + f.fbp = curvb.zbuf.zbp; + f.fbw = curvb.frame.fbw; + f.fbh = curvb.prndr->fbh; + f.psm = curvb.zbuf.psm; + f.fbm = 0; + curvb.pdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| + (curvb.zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), GET_MAXHEIGHT(curvb.zbuf.zbp, curvb.gsfb.fbw, 0)); + } + + assert( curvb.prndr != NULL && curvb.pdepth != NULL ); + assert( curvb.pdepth->fbh == curvb.prndr->fbh ); + + if( curvb.pdepth->status & CRenderTarget::TS_Virtual) { + + if( !curvb.zbuf.zmsk ) { + CRenderTarget* ptemp = s_DepthRTs.Promote(curvb.pdepth->fbp|(curvb.pdepth->fbw<<16)); + assert( ptemp == curvb.pdepth ); + } + else + curvb.pdepth->status &= ~CRenderTarget::TS_NeedUpdate; + } + + BOOL bSetTarg = 1; + if( curvb.pdepth->status & CRenderTarget::TS_NeedUpdate ) { + + assert( !(curvb.pdepth->status & CRenderTarget::TS_Virtual) ); + + // don't update if virtual + curvb.pdepth->Update(context, curvb.prndr); + bSetTarg = 0; + } + + GL_REPORT_ERRORD(); + if( curvb.prndr->status & CRenderTarget::TS_NeedUpdate ) { + +// if(bSetTarg s_bWriteDepth ) { +// if( s_bWriteDepth ) { +// curvb.pdepth->SetRenderTarget(1); +// curvb.pdepth->SetDepthStencilSurface(); +// } +// else curvb.pdepth->SetDepthStencilSurface(); +// } + + curvb.prndr->Update(context, curvb.pdepth); + } + else { + + //if( (vb[0].prndr != vb[1].prndr && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg ) + curvb.prndr->SetRenderTarget(0); + //if( bSetTarg && ((vb[0].pdepth != vb[1].pdepth && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg) ) + curvb.pdepth->SetDepthStencilSurface(); + + if (conf.mrtdepth && ZeroGS::IsWriteDepth()) curvb.pdepth->SetRenderTarget(1); + + if (s_ptexCurSet[0] == curvb.prndr->ptex) s_ptexCurSet[0] = 0; + if (s_ptexCurSet[1] == curvb.prndr->ptex) s_ptexCurSet[1] = 0; + + curvb.prndr->SetViewport(); + } + + curvb.prndr->SetTarget(curvb.frame.fbp, curvb.scissor, context); + + if( (curvb.zbuf.zbp-curvb.pdepth->fbp) != (curvb.frame.fbp - curvb.prndr->fbp) && curvb.test.zte ) + WARN_LOG("frame and zbuf not aligned\n"); + + curvb.bVarsSetTarg = TRUE; + if( vb[!context].prndr != curvb.prndr ) vb[!context].bVarsSetTarg = FALSE; + + assert( !(curvb.prndr->status&CRenderTarget::TS_NeedUpdate) ); + assert( curvb.pdepth == NULL || !(curvb.pdepth->status&CRenderTarget::TS_NeedUpdate) ); + GL_REPORT_ERRORD(); +} + +void ZeroGS::SetTexVariables(int context, FRAGMENTSHADER* pfragment, int settexint) +{ + if (!vb[context].curprim.tme) return; + + DVProfileFunc _pf("SetTexVariables"); + + assert( !vb[context].bNeedTexCheck ); + + Vector v, v2; + tex0Info& tex0 = vb[context].tex0; + + float fw = (float)tex0.tw; + float fh = (float)tex0.th; + + if( !vb[context].bTexConstsSync ) { + // alpha and texture highlighting + Vector valpha, valpha2; + + // if clut, use the frame format + int psm = tex0.psm; + if( PSMT_ISCLUT(tex0.psm) ) psm = tex0.cpsm; + + int nNeedAlpha = (psm == 1 || psm == 2 || psm == 10); + + Vector vblack; + vblack.x = vblack.y = vblack.z = vblack.w = 10; + + switch(tex0.tfx) { + case 0: + valpha.z = 0; valpha.w = 0; + valpha2.x = 0; valpha2.y = 0; + valpha2.z = 2; valpha2.w = 1; + + break; + case 1: + valpha.z = 0; valpha.w = 1; + valpha2.x = 1; valpha2.y = 0; + valpha2.z = 0; valpha2.w = 0; + + break; + case 2: + valpha.z = 1; valpha.w = 1.0f; + valpha2.x = 0; valpha2.y = tex0.tcc ? 1.0f : 0.0f; + valpha2.z = 2; valpha2.w = 0; + + break; + + case 3: + valpha.z = 1; valpha.w = tex0.tcc ? 0.0f : 1.0f; + valpha2.x = 0; valpha2.y = tex0.tcc ? 1.0f : 0.0f; + valpha2.z = 2; valpha2.w = 0; + + break; + } + + if( tex0.tcc ) { + + if( tex0.tfx == 1 ) { + //mode.x = 10; + valpha.z = 0; valpha.w = 0; + valpha2.x = 1; valpha2.y = 1; + valpha2.z = 0; valpha2.w = 0; + } + + if( nNeedAlpha ) { + + if( tex0.tfx == 0 ) { + // make sure alpha is mult by two when the output is Cv = Ct*Cf + valpha.x = 2*gs.texa.fta[0]; + // if 24bit, always choose ta[0] + valpha.y = 2*gs.texa.fta[psm != 1]; + valpha.y -= valpha.x; + } + else { + valpha.x = gs.texa.fta[0]; + // if 24bit, always choose ta[0] + valpha.y = gs.texa.fta[psm != 1]; + valpha.y -= valpha.x; + } + + // need black detection + if( gs.texa.aem && psm == PSMCT24 ) + vblack.w = 0; + } + else { + if( tex0.tfx == 0 ) { + valpha.x = 0; + valpha.y = 2; + } + else { + valpha.x = 0; + valpha.y = 1; + } + } + } + else { + + // reset alpha to color + valpha.x = valpha.y = 0; + valpha.w = 1; + } + + cgGLSetParameter4fv(pfragment->fTexAlpha, valpha); + cgGLSetParameter4fv(pfragment->fTexAlpha2, valpha2); + if( tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S) ) + cgGLSetParameter4fv(pfragment->fTestBlack, vblack); + + // clamp relies on texture width + { + clampInfo* pclamp = &ZeroGS::vb[context].clamp; + Vector v, v2; + v.x = v.y = 0; + u32* ptex = ZeroGS::vb[context].ptexClamp; + ptex[0] = ptex[1] = 0; + + float fw = ZeroGS::vb[context].tex0.tw; + float fh = ZeroGS::vb[context].tex0.th; + + switch(pclamp->wms) { + case 0: + v2.x = -1e10; v2.z = 1e10; + break; + case 1: // pclamp + // suikoden5 movie text + v2.x = 0; v2.z = 1-0.5f/fw; + break; + case 2: // reg pclamp + v2.x = (pclamp->minu+0.5f)/fw; v2.z = (pclamp->maxu-0.5f)/fw; + break; + + case 3: // region rep x + v.x = 0.9999f; + v.z = fw / (float)GPU_TEXMASKWIDTH; + v2.x = (float)GPU_TEXMASKWIDTH / fw; + v2.z = pclamp->maxu / fw; + + if( pclamp->minu != g_PrevBitwiseTexX ) { + g_PrevBitwiseTexX = pclamp->minu; + ptex[0] = ZeroGS::s_BitwiseTextures.GetTex(pclamp->minu, 0); + } + break; + } + + switch(pclamp->wmt) { + case 0: + v2.y = -1e10; v2.w = 1e10; + break; + case 1: // pclamp + // suikoden5 movie text + v2.y = 0; v2.w = 1-0.5f/fh; + break; + case 2: // reg pclamp + v2.y = (pclamp->minv+0.5f)/fh; v2.w = (pclamp->maxv-0.5f)/fh; + break; + + case 3: // region rep y + v.y = 0.9999f; + v.w = fh / (float)GPU_TEXMASKWIDTH; + v2.y = (float)GPU_TEXMASKWIDTH / fh; + v2.w = pclamp->maxv / fh; + + if( pclamp->minv != g_PrevBitwiseTexY ) { + g_PrevBitwiseTexY = pclamp->minv; + ptex[1] = ZeroGS::s_BitwiseTextures.GetTex(pclamp->minv, ptex[0]); + } + break; + } + + if( pfragment->fTexWrapMode != 0 ) + cgGLSetParameter4fv(pfragment->fTexWrapMode, v); + if( pfragment->fClampExts != 0 ) + cgGLSetParameter4fv(pfragment->fClampExts, v2); + } + + vb[context].bTexConstsSync = TRUE; + } + + if(s_bTexFlush ) { + if( PSMT_ISCLUT(tex0.psm) ) + texClutWrite(context); + else + s_bTexFlush = FALSE; + } + + if( settexint ) { + CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(tex0, 1); + + if( vb[context].bVarsTexSync ) { + if( vb[context].pmemtarg != pmemtarg ) { + SetTexVariablesInt(context, GetTexFilter(vb[context].tex1), tex0, pmemtarg, pfragment, s_bForceTexFlush); + vb[context].bVarsTexSync = TRUE; + } + } + else { + SetTexVariablesInt(context, GetTexFilter(vb[context].tex1), tex0, pmemtarg, pfragment, s_bForceTexFlush); + vb[context].bVarsTexSync = TRUE; + + INC_TEXVARS(); + } + } + else { + vb[context].bVarsTexSync = FALSE; + } +} + +void ZeroGS::SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, CMemoryTarget* pmemtarg, FRAGMENTSHADER* pfragment, int force) +{ + DVProfileFunc _pf("SetTexVariablesInt"); + + Vector v; + assert( pmemtarg != NULL && pfragment != NULL); + + float fw = (float)tex0.tw; + float fh = (float)tex0.th; + + bool bUseBilinear = bilinear > 1 || (bilinear && conf.bilinear); + if( bUseBilinear ) { + v.x = (float)fw; + v.y = (float)fh; + v.z = 1.0f / (float)fw; + v.w = 1.0f / (float)fh; + if (pfragment->fRealTexDims) + cgGLSetParameter4fv(pfragment->fRealTexDims, v); + else + cgGLSetParameter4fv(cgGetNamedParameter(pfragment->prog,"g_fRealTexDims"),v); + } + + if( m_Blocks[tex0.psm].bpp == 0 ) { + ERROR_LOG("Undefined tex psm 0x%x!\n", tex0.psm); + return; + } + + const BLOCK& b = m_Blocks[tex0.psm]; + + float fbw = (float)tex0.tbw; + + Vector vTexDims; + vTexDims.x = b.vTexDims.x * fw; + vTexDims.y = b.vTexDims.y * fh; + vTexDims.z = (float)BLOCK_TEXWIDTH*(0.002f / 64.0f + 0.01f/128.0f); + vTexDims.w = (float)BLOCK_TEXHEIGHT*0.2f/512.0f; + + if( bUseBilinear ) { + vTexDims.x *= 1/128.0f; + vTexDims.y *= 1/512.0f; + vTexDims.z *= 1/128.0f; + vTexDims.w *= 1/512.0f; + } + + float g_fitexwidth = g_fiGPU_TEXWIDTH/(float)pmemtarg->widthmult; + float g_texwidth = GPU_TEXWIDTH*(float)pmemtarg->widthmult; + + float fpage = tex0.tbp0*(64.0f*g_fitexwidth) + 0.05f * g_fitexwidth; + float fpageint = floorf(fpage); + int starttbp = (int)fpage; + + // 2048 is number of words to span one page + float fblockstride = (2048.0f /(float)(g_texwidth*BLOCK_TEXWIDTH)) * b.vTexDims.x * fbw; + assert( fblockstride >= 1.0f ); + + v.x = (float)(2048 * g_fitexwidth); + v.y = fblockstride; + v.z = g_fBlockMult/(float)pmemtarg->widthmult; + v.w = fpage-fpageint; + + if( g_fBlockMult > 1 ) { + // make sure to divide by mult (since the G16R16 texture loses info) + v.z *= b.bpp * (1/32.0f); + } + + cgGLSetParameter4fv(pfragment->fTexDims, vTexDims); + cgGLSetParameter4fv(pfragment->fTexBlock, &b.vTexBlock.x); + cgGLSetParameter4fv(pfragment->fTexOffset, v); + + // get hardware texture dims + int texheight = (pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult; + int texwidth = GPU_TEXWIDTH*pmemtarg->widthmult*pmemtarg->channels; + + v.y = 1;//(float)1.0f / (float)((pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult); + v.x = (fpageint-(float)pmemtarg->realy/(float)pmemtarg->widthmult+0.5f);//*v.y; + +// v.x *= (float)texheight; +// v.y *= (float)texheight; + v.z = (float)texwidth; + if( !(g_nPixelShaderVer & SHADER_ACCURATE) || bUseBilinear ) + v.w = 0.25f; + else + v.w = 0.5f; + + cgGLSetParameter4fv(pfragment->fPageOffset, v); + + if( force ) s_ptexCurSet[context] = pmemtarg->ptex->tex; + else s_ptexNextSet[context] = pmemtarg->ptex->tex; + vb[context].pmemtarg = pmemtarg; + + vb[context].bVarsTexSync = FALSE; +} +#define SET_ALPHA_COLOR_FACTOR(sign) \ +{ \ + switch(a.c) \ + { \ + case 0: \ + vAlphaBlendColor.y = (sign) ? 2.0f*255.0f/256.0f : -2.0f*255.0f/256.0f; \ + s_srcalpha = GL_ONE; \ + s_alphaeq = (sign) ? GL_FUNC_ADD : GL_FUNC_REVERSE_SUBTRACT; \ + break; \ + \ + case 1: \ + /* if in 24 bit mode, dest alpha should be one */ \ + switch(vb[icurctx].prndr->psm&0xf) \ + { \ + case 0: \ + bDestAlphaColor = (a.d!=2)&&((a.a==a.d)||(a.b==a.d)); \ + break; \ + \ + case 1: \ + /* dest alpha should be one */ \ + bDestAlphaColor = 2; \ + break; \ + /* default: 16bit surface, so returned alpha is ok */ \ + } \ + break; \ + \ + case 2: \ + bNeedBlendFactorInAlpha = 1; /* should disable alpha channel writing */ \ + vAlphaBlendColor.y = 0; \ + vAlphaBlendColor.w = (sign) ? (float)a.fix * (2.0f/255.0f) : (float)a.fix * (-2.0f/255.0f); \ + usec = 0; /* change so that alpha comes from source*/ \ + break; \ + } \ +} \ + +//if( a.fix <= 0x80 ) { \ +// dwTemp = (a.fix*2)>255?255:(a.fix*2); \ +// dwTemp = dwTemp|(dwTemp<<8)|(dwTemp<<16)|0x80000000; \ +// printf("bfactor: %8.8x\n", dwTemp); \ +// glBlendColorEXT(dwTemp); \ +// } \ +// else { \ + +void ZeroGS::ResetAlphaVariables() +{ +} + +void ZeroGS::SetAlphaVariables(const alphaInfo& a) +{ + bool alphaenable = true; + + // TODO: negative color when not clamping turns to positive??? + g_vars._bAlphaState = 0; // set all to zero + bNeedBlendFactorInAlpha = 0; + b2XAlphaTest = 1; + u32 dwTemp = 0xffffffff; + + // default + s_srcalpha = GL_ONE; + s_dstalpha = GL_ZERO; + s_alphaeq = GL_FUNC_ADD; + + s_alphaInfo = a; + + vAlphaBlendColor = Vector(1,2*255.0f/256.0f,0,0); + u32 usec = a.c; + + if( a.a == a.b ) + { // just d remains + if( a.d == 0 ) + { + alphaenable = false; + } + else + { + s_dstrgb = a.d == 1 ? GL_ONE : GL_ZERO; + s_srcrgb = GL_ZERO; + s_rgbeq = GL_FUNC_ADD; + } + + goto EndSetAlpha; + } + else if( a.d == 2 ) + { // zero + if( a.a == 2 ) + { + // zero all color + s_srcrgb = GL_ZERO; + s_dstrgb = GL_ZERO; + goto EndSetAlpha; + } + else if( a.b == 2 ) + { + //b2XAlphaTest = 1; + + SET_ALPHA_COLOR_FACTOR(1); + + if( bDestAlphaColor == 2 ) + { + s_rgbeq = GL_FUNC_ADD; + s_srcrgb = a.a == 0 ? GL_ONE : GL_ZERO; + s_dstrgb = a.a == 0 ? GL_ZERO : GL_ONE; + } + else + { + bAlphaClamping = 2; + + s_rgbeq = GL_FUNC_ADD; + s_srcrgb = a.a == 0 ? blendalpha[usec] : GL_ZERO; + s_dstrgb = a.a == 0 ? GL_ZERO : blendalpha[usec]; + } + + goto EndSetAlpha; + } + + // nothing is zero, so must do some real blending + //b2XAlphaTest = 1; + bAlphaClamping = 3; + + SET_ALPHA_COLOR_FACTOR(1); + + s_rgbeq = a.a == 0 ? GL_FUNC_SUBTRACT : GL_FUNC_REVERSE_SUBTRACT; + s_srcrgb = bDestAlphaColor == 2 ? GL_ONE : blendalpha[usec]; + s_dstrgb = bDestAlphaColor == 2 ? GL_ONE : blendalpha[usec]; + } + else if( a.a == 2 ) + { // zero + + //b2XAlphaTest = 1; + bAlphaClamping = 1; // min testing + + SET_ALPHA_COLOR_FACTOR(1); + + if( a.b == a.d ) + { + // can get away with 1-A + s_rgbeq = GL_FUNC_ADD; + s_srcrgb = (a.b == 0 && bDestAlphaColor != 2) ? blendinvalpha[usec] : GL_ZERO; + s_dstrgb = (a.b == 0 || bDestAlphaColor == 2) ? GL_ZERO : blendinvalpha[usec]; + } + else + { + s_rgbeq = a.b==0 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_SUBTRACT; + s_srcrgb = (a.b == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : GL_ONE; + s_dstrgb = (a.b == 0 || bDestAlphaColor == 2 ) ? GL_ONE : blendalpha[usec]; + } + } + else if( a.b == 2 ) + { + bAlphaClamping = 2; // max testing + + SET_ALPHA_COLOR_FACTOR(a.a!=a.d); + + if( a.a == a.d ) + { + // can get away with 1+A, but need to set alpha to negative + s_rgbeq = GL_FUNC_ADD; + + if( bDestAlphaColor == 2 ) + { + assert(usec==1); + + // all ones + bNeedBlendFactorInAlpha = 1; + vAlphaBlendColor.y = 0; + vAlphaBlendColor.w = -1; + + s_srcrgb = (a.a == 0) ? GL_ONE_MINUS_SRC_ALPHA : GL_ZERO; + s_dstrgb = (a.a == 0) ? GL_ZERO : GL_ONE_MINUS_SRC_ALPHA; + } + else + { + s_srcrgb = a.a == 0 ? blendinvalpha[usec] : GL_ZERO; + s_dstrgb = a.a == 0 ? GL_ZERO : blendinvalpha[usec]; + } + } + else + { + //b2XAlphaTest = 1; + s_rgbeq = GL_FUNC_ADD; + s_srcrgb = (a.a == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : GL_ONE; + s_dstrgb = (a.a == 0 || bDestAlphaColor == 2) ? GL_ONE : blendalpha[usec]; + } + } + else + { + // all 3 components are valid! + bAlphaClamping = 3; // all testing + SET_ALPHA_COLOR_FACTOR(a.a!=a.d); + + if( a.a == a.d ) + { + // can get away with 1+A, but need to set alpha to negative + s_rgbeq = GL_FUNC_ADD; + + if( bDestAlphaColor == 2 ) + { + assert(usec==1); + + // all ones + bNeedBlendFactorInAlpha = 1; + vAlphaBlendColor.y = 0; + vAlphaBlendColor.w = -1; + s_srcrgb = a.a == 0 ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA; + s_dstrgb = a.a == 0 ? GL_SRC_ALPHA : GL_ONE_MINUS_SRC_ALPHA; + } + else + { + s_srcrgb = a.a == 0 ? blendinvalpha[usec] : blendalpha[usec]; + s_dstrgb = a.a == 0 ? blendalpha[usec] : blendinvalpha[usec]; + } + } + else + { + assert(a.b == a.d); + s_rgbeq = GL_FUNC_ADD; + + if( bDestAlphaColor == 2 ) + { + assert(usec==1); + + // all ones + bNeedBlendFactorInAlpha = 1; + vAlphaBlendColor.y = 0; + vAlphaBlendColor.w = 1; + s_srcrgb = a.a != 0 ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA; + s_dstrgb = a.a != 0 ? GL_SRC_ALPHA : GL_ONE_MINUS_SRC_ALPHA; + } + else + { + //b2XAlphaTest = 1; + s_srcrgb = a.a != 0 ? blendinvalpha[usec] : blendalpha[usec]; + s_dstrgb = a.a != 0 ? blendalpha[usec] : blendinvalpha[usec]; + } + } + } + + EndSetAlpha: + + GL_BLEND_SET(); + zgsBlendEquationSeparateEXT(s_rgbeq, s_alphaeq); + + if( alphaenable ) + glEnable(GL_BLEND); // always set + else + glDisable(GL_BLEND); + + INC_ALPHAVARS(); +} + +void ZeroGS::SetWriteDepth() +{ + if( conf.mrtdepth ) { + s_bWriteDepth = TRUE; + s_nWriteDepthCount = 4; + } +} + +BOOL ZeroGS::IsWriteDepth() +{ + return s_bWriteDepth; +} + +BOOL ZeroGS::IsWriteDestAlphaTest() +{ + return s_bWriteDepth; +} + +void ZeroGS::SetDestAlphaTest() +{ + s_bDestAlphaTest = TRUE; + s_nWriteDestAlphaTest = 4; +} + +void ZeroGS::SetFogColor(u32 fog) +{ + if( 1||gs.fogcol != fog ) { + gs.fogcol = fog; + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + if( !g_bIsLost ) { + Vector v; + + // set it immediately + v.x = (gs.fogcol&0xff)/255.0f; + v.y = ((gs.fogcol>>8)&0xff)/255.0f; + v.z = ((gs.fogcol>>16)&0xff)/255.0f; + cgGLSetParameter4fv(g_fparamFogColor, v); + } + } +} + +void ZeroGS::ExtWrite() +{ + WARN_LOG("ExtWrite\n"); + + // use local DISPFB, EXTDATA, EXTBUF, and PMODE +// int bpp, start, end; +// tex0Info texframe; + +// bpp = 4; +// if( texframe.psm == 0x12 ) bpp = 3; +// else if( texframe.psm & 2 ) bpp = 2; +// +// // get the start and end addresses of the buffer +// GetRectMemAddress(start, end, texframe.psm, 0, 0, texframe.tw, texframe.th, texframe.tbp0, texframe.tbw); +} + +//////////// +// Caches // +//////////// +#ifdef __x86_64__ +extern "C" void TestClutChangeMMX(void* src, void* dst, int entries, void* pret); +#endif + +bool ZeroGS::CheckChangeInClut(u32 highdword, u32 psm) +{ + int cld = (highdword >> 29) & 0x7; + int cbp = ((highdword >> 5) & 0x3fff); + + // processing the CLUT after tex0/2 are written + switch(cld) { + case 0: return false; + case 1: break; // Seems to rarely not be 1. + // note sure about changing cbp[0,1] + case 4: return gs.cbp[0] != cbp; + case 5: return gs.cbp[1] != cbp; + + // default: load + default: break; + } + + int cpsm = (highdword >> 19) & 0xe; + int csm = (highdword >> 23) & 0x1; + + if( cpsm > 1 || csm ) + // don't support 16bit for now + return true; + + int csa = (highdword >> 24) & 0x1f; + + int entries = (psm&3)==3 ? 256 : 16; + + u64* src = (u64*)(g_pbyGSMemory + cbp*256); + u64* dst = (u64*)(g_pbyGSClut+64*csa); + + bool bRet = false; + + // do a fast test with MMX +#ifdef _MSC_VER + +#ifdef __x86_64__ + TestClutChangeMMX(dst, src, entries, &bRet); +#else + int storeebx; + __asm { + mov storeebx, ebx + mov edx, dst + mov ecx, src + mov ebx, entries + +Start: + movq mm0, [edx] + movq mm1, [edx+8] + pcmpeqd mm0, [ecx] + pcmpeqd mm1, [ecx+16] + + movq mm2, [edx+16] + movq mm3, [edx+24] + pcmpeqd mm2, [ecx+32] + pcmpeqd mm3, [ecx+48] + + pand mm0, mm1 + pand mm2, mm3 + movq mm4, [edx+32] + movq mm5, [edx+40] + pcmpeqd mm4, [ecx+8] + pcmpeqd mm5, [ecx+24] + + pand mm0, mm2 + pand mm4, mm5 + movq mm6, [edx+48] + movq mm7, [edx+56] + pcmpeqd mm6, [ecx+40] + pcmpeqd mm7, [ecx+56] + + pand mm0, mm4 + pand mm6, mm7 + pand mm0, mm6 + + pmovmskb eax, mm0 + cmp eax, 0xff + je Continue + mov bRet, 1 + jmp Return + +Continue: + cmp ebx, 16 + jle Return + + test ebx, 0x10 + jz AddEcx + sub ecx, 448 // go back and down one column, +AddEcx: + add ecx, 256 // go to the right block + + + jne Continue1 + add ecx, 256 // skip whole block +Continue1: + add edx, 64 + sub ebx, 16 + jmp Start + +Return: + emms + mov ebx, storeebx + } +#endif // __x86_64__ + +#else // linux + +#ifdef __x86_64__ + __asm__( + ".intel_syntax\n" +"Start:\n" + "movq %%mm0, [%%rcx]\n" + "movq %%mm1, [%%rcx+8]\n" + "pcmpeqd %%mm0, [%%rdx]\n" + "pcmpeqd %%mm1, [%%rdx+16]\n" + "movq %%mm2, [%%rcx+16]\n" + "movq %%mm3, [%%rcx+24]\n" + "pcmpeqd %%mm2, [%%rdx+32]\n" + "pcmpeqd %%mm3, [%%rdx+48]\n" + "pand %%mm0, %%mm1\n" + "pand %%mm2, %%mm3\n" + "movq %%mm4, [%%rcx+32]\n" + "movq %%mm5, [%%rcx+40]\n" + "pcmpeqd %%mm4, [%%rdx+8]\n" + "pcmpeqd %%mm5, [%%rdx+24]\n" + "pand %%mm0, %%mm2\n" + "pand %%mm4, %%mm5\n" + "movq %%mm6, [%%rcx+48]\n" + "movq %%mm7, [%%rcx+56]\n" + "pcmpeqd %%mm6, [%%rdx+40]\n" + "pcmpeqd %%mm7, [%%rdx+56]\n" + "pand %%mm0, %%mm4\n" + "pand %%mm6, %%mm7\n" + "pand %%mm0, %%mm6\n" + "pmovmskb %%eax, %%mm0\n" + "cmp %%eax, 0xff\n" + "je Continue\n" + ".att_syntax\n" + "movb $1, %0\n" + ".intel_syntax\n" + "jmp Return\n" +"Continue:\n" + "cmp %%rbx, 16\n" + "jle Return\n" + "test %%rbx, 0x10\n" + "jz AddRcx\n" + "sub %%rdx, 448\n" // go back and down one column +"AddRcx:\n" + "add %%rdx, 256\n" // go to the right block + "cmp %%rbx, 0x90\n" + "jne Continue1\n" + "add %%rdx, 256\n" // skip whole block +"Continue1:\n" + "add %%rcx, 64\n" + "sub %%rbx, 16\n" + "jmp Start\n" +"Return:\n" + "emms\n" + ".att_syntax\n" : "=m"(bRet) : "c"(dst), "d"(src), "b"(entries) : "rax", "memory"); +#else + // do a fast test with MMX + __asm__( + ".intel_syntax\n" +"Start:\n" + "movq %%mm0, [%%ecx]\n" + "movq %%mm1, [%%ecx+8]\n" + "pcmpeqd %%mm0, [%%edx]\n" + "pcmpeqd %%mm1, [%%edx+16]\n" + "movq %%mm2, [%%ecx+16]\n" + "movq %%mm3, [%%ecx+24]\n" + "pcmpeqd %%mm2, [%%edx+32]\n" + "pcmpeqd %%mm3, [%%edx+48]\n" + "pand %%mm0, %%mm1\n" + "pand %%mm2, %%mm3\n" + "movq %%mm4, [%%ecx+32]\n" + "movq %%mm5, [%%ecx+40]\n" + "pcmpeqd %%mm4, [%%edx+8]\n" + "pcmpeqd %%mm5, [%%edx+24]\n" + "pand %%mm0, %%mm2\n" + "pand %%mm4, %%mm5\n" + "movq %%mm6, [%%ecx+48]\n" + "movq %%mm7, [%%ecx+56]\n" + "pcmpeqd %%mm6, [%%edx+40]\n" + "pcmpeqd %%mm7, [%%edx+56]\n" + "pand %%mm0, %%mm4\n" + "pand %%mm6, %%mm7\n" + "pand %%mm0, %%mm6\n" + "pmovmskb %%eax, %%mm0\n" + "cmp %%eax, 0xff\n" + "je Continue\n" + ".att_syntax\n" + "movb $1, %0\n" + ".intel_syntax\n" + "jmp Return\n" +"Continue:\n" + "cmp %%ebx, 16\n" + "jle Return\n" + "test %%ebx, 0x10\n" + "jz AddEcx\n" + "sub %%edx, 448\n" // go back and down one column +"AddEcx:\n" + "add %%edx, 256\n" // go to the right block + "cmp %%ebx, 0x90\n" + "jne Continue1\n" + "add %%edx, 256\n" // skip whole block +"Continue1:\n" + "add %%ecx, 64\n" + "sub %%ebx, 16\n" + "jmp Start\n" +"Return:\n" + "emms\n" + ".att_syntax\n" : "=m"(bRet) : "c"(dst), "d"(src), "b"(entries) : "eax", "memory"); +#endif // __x86_64__ + +#endif // _WIN32 + + return bRet; +} + +void ZeroGS::texClutWrite(int ctx) +{ + s_bTexFlush = 0; + if( g_bIsLost ) + return; + + tex0Info& tex0 = vb[ctx].tex0; + assert( PSMT_ISCLUT(tex0.psm) ); + // processing the CLUT after tex0/2 are written + switch(tex0.cld) { + case 0: return; + case 1: break; // tex0.cld is usually 1. + case 2: gs.cbp[0] = tex0.cbp; break; + case 3: gs.cbp[1] = tex0.cbp; break; + // not sure about changing cbp[0,1] + case 4: + if( gs.cbp[0] == tex0.cbp ) + return; + gs.cbp[0] = tex0.cbp; + break; + case 5: + if( gs.cbp[1] == tex0.cbp ) + return; + gs.cbp[1] = tex0.cbp; + break; + default: //DEBUG_LOG("cld isn't 0-5!"); + break; + } + + Flush(!ctx); + + int entries = (tex0.psm & 3)==3 ? 256 : 16; + + if (tex0.csm) + { + switch (tex0.cpsm) + { + // 16bit psm + // eggomania uses non16bit textures for csm2 + case PSMCT16: + { + u16* src = (u16*)g_pbyGSMemory + tex0.cbp*128; + u16 *dst = (u16*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0)); + + for (int i = 0; i < entries; ++i) + { + *dst = src[getPixelAddress16_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + dst += 2; + + // check for wrapping + if (((u32)(uptr)dst & 0x3ff) == 0) dst = (u16*)(g_pbyGSClut+2); + } + break; + } + + case PSMCT16S: + { + u16* src = (u16*)g_pbyGSMemory + tex0.cbp*128; + u16 *dst = (u16*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0)); + + for (int i = 0; i < entries; ++i) + { + *dst = src[getPixelAddress16S_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + dst += 2; + + // check for wrapping + if (((u32)(uptr)dst & 0x3ff) == 0) dst = (u16*)(g_pbyGSClut+2); + } + break; + } + + case PSMCT32: + case PSMCT24: + { + u32* src = (u32*)g_pbyGSMemory + tex0.cbp*64; + u32 *dst = (u32*)(g_pbyGSClut+64*tex0.csa); + + // check if address exceeds src + if( src+getPixelAddress32_0(gs.clut.cou+entries-1, gs.clut.cov, gs.clut.cbw) >= (u32*)g_pbyGSMemory + 0x00100000 ) + ERROR_LOG("texClutWrite out of bounds\n"); + else + for(int i = 0; i < entries; ++i) + { + *dst = src[getPixelAddress32_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + dst++; + } + break; + } + + default: + { +#ifndef RELEASE_TO_PUBLIC + //DEBUG_LOG("unknown cpsm: %x (%x)\n", tex0.cpsm, tex0.psm); +#endif + break; + } + } + } + else + { + switch (tex0.cpsm) + { + case PSMCT24: + case PSMCT32: + if( entries == 16 ) + WriteCLUT_T32_I4_CSM1((u32*)(g_pbyGSMemory + tex0.cbp*256), (u32*)(g_pbyGSClut+64*tex0.csa)); + else + WriteCLUT_T32_I8_CSM1((u32*)(g_pbyGSMemory + tex0.cbp*256), (u32*)(g_pbyGSClut+64*tex0.csa)); + break; + + default: + if( entries == 16 ) + WriteCLUT_T16_I4_CSM1((u32*)(g_pbyGSMemory + 256 * tex0.cbp), (u32*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0))); + else // sse2 for 256 is more complicated, so use regular + WriteCLUT_T16_I8_CSM1_c((u32*)(g_pbyGSMemory + 256 * tex0.cbp), (u32*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0))); + break; + + } + } +} + +void ZeroGS::SetTexFlush() +{ + s_bTexFlush = TRUE; + +// if( PSMT_ISCLUT(vb[0].tex0.psm) ) +// texClutWrite(0); +// if( PSMT_ISCLUT(vb[1].tex0.psm) ) +// texClutWrite(1); + + if( !s_bForceTexFlush ) + { + if (s_ptexCurSet[0] != s_ptexNextSet[0]) s_ptexCurSet[0] = s_ptexNextSet[0]; + if (s_ptexCurSet[1] != s_ptexNextSet[1]) s_ptexCurSet[1] = s_ptexNextSet[1]; + } +} + +int ZeroGS::Save(char* pbydata) +{ + if( pbydata == NULL ) + return 40 + 0x00400000 + sizeof(gs) + 2*VBSAVELIMIT + 2*sizeof(frameInfo) + 4 + 256*4; + + s_RTs.ResolveAll(); + s_DepthRTs.ResolveAll(); + + strcpy(pbydata, libraryName); + *(u32*)(pbydata+16) = ZEROGS_SAVEVER; + pbydata += 32; + + *(int*)pbydata = icurctx; pbydata += 4; + *(int*)pbydata = VBSAVELIMIT; pbydata += 4; + + memcpy(pbydata, g_pbyGSMemory, 0x00400000); + pbydata += 0x00400000; + + memcpy(pbydata, g_pbyGSClut, 256*4); + pbydata += 256*4; + + *(int*)pbydata = sizeof(gs); + pbydata += 4; + memcpy(pbydata, &gs, sizeof(gs)); + pbydata += sizeof(gs); + + for(int i = 0; i < 2; ++i) { + memcpy(pbydata, &vb[i], VBSAVELIMIT); + pbydata += VBSAVELIMIT; + } + + return 0; +} + +extern u32 s_uTex1Data[2][2], s_uClampData[2]; +extern char *libraryName; +bool ZeroGS::Load(char* pbydata) +{ + memset(s_uTex1Data, 0, sizeof(s_uTex1Data)); + memset(s_uClampData, 0, sizeof(s_uClampData)); + + g_nCurVBOIndex = 0; + + // first 32 bytes are the id + u32 savever = *(u32*)(pbydata+16); + + if( strncmp(pbydata, libraryName, 6) == 0 && (savever == ZEROGS_SAVEVER || savever == 0xaa000004) ) { + + g_MemTargs.Destroy(); + + GSStateReset(); + pbydata += 32; + + int context = *(int*)pbydata; pbydata += 4; + u32 savelimit = VBSAVELIMIT; + + savelimit = *(u32*)pbydata; pbydata += 4; + + memcpy(g_pbyGSMemory, pbydata, 0x00400000); + pbydata += 0x00400000; + + memcpy(g_pbyGSClut, pbydata, 256*4); + pbydata += 256*4; + + memset(&gs, 0, sizeof(gs)); + + int savedgssize; + if( savever == 0xaa000004 ) + savedgssize = 0x1d0; + else { + savedgssize = *(int*)pbydata; + pbydata += 4; + } + + memcpy(&gs, pbydata, savedgssize); + pbydata += savedgssize; + prim = &gs._prim[gs.prac]; + + vb[0].Destroy(); + memcpy(&vb[0], pbydata, min(savelimit, VBSAVELIMIT)); + pbydata += savelimit; + vb[0].pBufferData = NULL; + + vb[1].Destroy(); + memcpy(&vb[1], pbydata, min(savelimit, VBSAVELIMIT)); + pbydata += savelimit; + vb[1].pBufferData = NULL; + + for(int i = 0; i < 2; ++i) { + vb[i].Init(VB_BUFFERSIZE); + vb[i].bNeedZCheck = vb[i].bNeedFrameCheck = 1; + + vb[i].bSyncVars = 0; vb[i].bNeedTexCheck = 1; + memset(vb[i].uCurTex0Data, 0, sizeof(vb[i].uCurTex0Data)); + } + + icurctx = -1; + + glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, s_uFramebuffer ); // switch to the backbuffer + SetFogColor(gs.fogcol); + + GL_REPORT_ERRORD(); + return true; + } + + return false; +} + +void ZeroGS::SaveSnapshot(const char* filename) +{ + g_bMakeSnapshot = 1; + strSnapshot = filename; +} + +bool ZeroGS::SaveRenderTarget(const char* filename, int width, int height, int jpeg) +{ + bool bflip = height < 0; + height = abs(height); + vector data(width*height); + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); + if( glGetError() != GL_NO_ERROR ) + return false; + + if( bflip ) { + // swap scanlines + vector scanline(width); + for(int i = 0; i < height/2; ++i) { + memcpy(&scanline[0], &data[i*width], width*4); + memcpy(&data[i*width], &data[(height-i-1)*width], width*4); + memcpy(&data[(height-i-1)*width], &scanline[0], width*4); + } + } + + if( jpeg ) return SaveJPEG(filename, width, height, &data[0], 70); + + return SaveTGA(filename, width, height, &data[0]); +} + +bool ZeroGS::SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height) +{ + vector data(width*height); + glBindTexture(textarget, tex); + glGetTexImage(textarget, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); + if( glGetError() != GL_NO_ERROR ) { + return false; + } + + return SaveTGA(filename, width, height, &data[0]);//SaveJPEG(filename, width, height, &data[0], 70); +} + +extern "C" { +#ifdef _WIN32 +#define XMD_H +#undef FAR +#define HAVE_BOOLEAN +#endif + +#include "jpeglib.h" +} + +bool ZeroGS::SaveJPEG(const char* filename, int image_width, int image_height, const void* pdata, int quality) +{ + u8* image_buffer = new u8[image_width * image_height * 3]; + u8* psrc = (u8*)pdata; + + // input data is rgba format, so convert to rgb + u8* p = image_buffer; + for(int i = 0; i < image_height; ++i) { + for(int j = 0; j < image_width; ++j) { + p[0] = psrc[0]; + p[1] = psrc[1]; + p[2] = psrc[2]; + p += 3; + psrc += 4; + } + } + + /* This struct contains the JPEG compression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + * It is possible to have several such structures, representing multiple + * compression/decompression processes, in existence at once. We refer + * to any one struct (and its associated working data) as a "JPEG object". + */ + struct jpeg_compress_struct cinfo; + /* This struct represents a JPEG error handler. It is declared separately + * because applications often want to supply a specialized error handler + * (see the second half of this file for an example). But here we just + * take the easy way out and use the standard error handler, which will + * print a message on stderr and call exit() if compression fails. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct jpeg_error_mgr jerr; + /* More stuff */ + FILE * outfile; /* target file */ + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ + int row_stride; /* physical row width in image buffer */ + + /* Step 1: allocate and initialize JPEG compression object */ + + /* We have to set up the error handler first, in case the initialization + * step fails. (Unlikely, but it could happen if you are out of memory.) + * This routine fills in the contents of struct jerr, and returns jerr's + * address which we place into the link field in cinfo. + */ + cinfo.err = jpeg_std_error(&jerr); + /* Now we can initialize the JPEG compression object. */ + jpeg_create_compress(&cinfo); + + /* Step 2: specify data destination (eg, a file) */ + /* Note: steps 2 and 3 can be done in either order. */ + + /* Here we use the library-supplied code to send compressed data to a + * stdio stream. You can also write your own code to do something else. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to write binary files. + */ + if ((outfile = fopen(filename, "wb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + exit(1); + } + jpeg_stdio_dest(&cinfo, outfile); + + /* Step 3: set parameters for compression */ + + /* First we supply a description of the input image. + * Four fields of the cinfo struct must be filled in: + */ + cinfo.image_width = image_width; /* image width and height, in pixels */ + cinfo.image_height = image_height; + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + /* Now use the library's routine to set default compression parameters. + * (You must set at least cinfo.in_color_space before calling this, + * since the defaults depend on the source color space.) + */ + jpeg_set_defaults(&cinfo); + /* Now you can set any non-default parameters you wish to. + * Here we just illustrate the use of quality (quantization table) scaling: + */ + jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); + + /* Step 4: Start compressor */ + + /* TRUE ensures that we will write a complete interchange-JPEG file. + * Pass TRUE unless you are very sure of what you're doing. + */ + jpeg_start_compress(&cinfo, TRUE); + + /* Step 5: while (scan lines remain to be written) */ + /* jpeg_write_scanlines(...); */ + + /* Here we use the library's state variable cinfo.next_scanline as the + * loop counter, so that we don't have to keep track ourselves. + * To keep things simple, we pass one scanline per call; you can pass + * more if you wish, though. + */ + row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */ + + while (cinfo.next_scanline < cinfo.image_height) { + /* jpeg_write_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could pass + * more than one scanline at a time if that's more convenient. + */ + row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + /* Step 6: Finish compression */ + + jpeg_finish_compress(&cinfo); + /* After finish_compress, we can close the output file. */ + fclose(outfile); + + /* Step 7: release JPEG compression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_compress(&cinfo); + + delete image_buffer; + /* And we're done! */ + return true; +} + +#if defined(_MSC_VER) +#pragma pack(push, 1) +#endif + +struct TGA_HEADER +{ + u8 identsize; // size of ID field that follows 18 u8 header (0 usually) + u8 colourmaptype; // type of colour map 0=none, 1=has palette + u8 imagetype; // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed + + s16 colourmapstart; // first colour map entry in palette + s16 colourmaplength; // number of colours in palette + u8 colourmapbits; // number of bits per palette entry 15,16,24,32 + + s16 xstart; // image x origin + s16 ystart; // image y origin + s16 width; // image width in pixels + s16 height; // image height in pixels + u8 bits; // image bits per pixel 8,16,24,32 + u8 descriptor; // image descriptor bits (vh flip bits) + + // pixel data follows header + +#if defined(_MSC_VER) +}; +#pragma pack(pop) +#else +} __attribute__((packed)); +#endif + +bool ZeroGS::SaveTGA(const char* filename, int width, int height, void* pdata) +{ + TGA_HEADER hdr; + FILE* f = fopen(filename, "wb"); + if( f == NULL ) + return false; + + assert( sizeof(TGA_HEADER) == 18 && sizeof(hdr) == 18 ); + + memset(&hdr, 0, sizeof(hdr)); + hdr.imagetype = 2; + hdr.bits = 32; + hdr.width = width; + hdr.height = height; + hdr.descriptor |= 8|(1<<5); // 8bit alpha, flip vertical + + fwrite(&hdr, sizeof(hdr), 1, f); + fwrite(pdata, width*height*4, 1, f); + fclose(f); + return true; +} + +// AVI capture stuff +void ZeroGS::StartCapture() +{ + if( !s_aviinit ) { + +#ifdef _WIN32 + START_AVI("zerogs.avi"); +#else // linux + //TODO +#endif + s_aviinit = 1; + } + else { + ERROR_LOG("Continuing from previous capture"); + } + + s_avicapturing = 1; +} + +void ZeroGS::StopCapture() +{ + s_avicapturing = 0; +} + +void ZeroGS::CaptureFrame() +{ + assert( s_avicapturing && s_aviinit ); + + //vector mem(nBackbufferWidth*nBackbufferHeight); + vector data(nBackbufferWidth*nBackbufferHeight); + glReadPixels(0, 0, nBackbufferWidth, nBackbufferHeight, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); + if( glGetError() != GL_NO_ERROR ) + return; + +// u8* pend = (u8*)&data[0] + (nBackbufferHeight-1)*nBackbufferWidth*4; +// for(int i = 0; i < conf.height; ++i) { +// memcpy_amd(&mem[nBackbufferWidth*4*i], pend - nBackbufferWidth*4*i, nBackbufferWidth * 4); +// } + + int fps = SMODE1->CMOD == 3 ? 50 : 60; + +#ifdef _WIN32 + bool bSuccess = ADD_FRAME_FROM_DIB_TO_AVI("AAAA", fps, nBackbufferWidth, nBackbufferHeight, 32, &data[0]); + + if( !bSuccess ) { + s_avicapturing = 0; + STOP_AVI(); + ZeroGS::AddMessage("Failed to create avi"); + return; + } +#else // linux + //TODO +#endif +} + diff --git a/plugins/zerogs/opengl/zerogs.h b/plugins/zerogs/opengl/zerogs.h index 53496da968..9228cdcf61 100644 --- a/plugins/zerogs/opengl/zerogs.h +++ b/plugins/zerogs/opengl/zerogs.h @@ -1,555 +1,555 @@ -/* ZeroGS KOSMOS - * Copyright (C) 2005-2006 zerofrog@gmail.com - * - * 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 - */ - -#ifndef __ZEROGS__H -#define __ZEROGS__H - -#pragma warning(disable:4200) // nonstandard extension used : zero-sized array in struct/union - -#ifndef _WIN32 -// adding glew support instead of glXGetProcAddress (thanks to scaught) -#include -#endif - -#include -#include - -#ifndef _WIN32 -#include -inline void* wglGetProcAddress(const char* x) { - return (void*)glXGetProcAddress((const GLubyte*)x); -} -#else -#include "glprocs.h" -#endif - -#include -#include - -#ifndef GL_DEPTH24_STENCIL8_EXT // allows FBOs to support stencils -#define GL_DEPTH_STENCIL_EXT 0x84F9 -#define GL_UNSIGNED_INT_24_8_EXT 0x84FA -#define GL_DEPTH24_STENCIL8_EXT 0x88F0 -#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 -#endif - -#include - -#include -#include -#include -#include -#include -using namespace std; - -#ifndef SAFE_DELETE -#define SAFE_DELETE(x) if( (x) != NULL ) { delete (x); (x) = NULL; } -#endif -#ifndef SAFE_DELETE_ARRAY -#define SAFE_DELETE_ARRAY(x) if( (x) != NULL ) { delete[] (x); (x) = NULL; } -#endif -#ifndef SAFE_RELEASE -#define SAFE_RELEASE(x) if( (x) != NULL ) { (x)->Release(); (x) = NULL; } -#endif - -#define SAFE_RELEASE_PROG(x) { if( (x) != NULL ) { cgDestroyProgram(x); x = NULL; } } -#define SAFE_RELEASE_TEX(x) { if( (x) != 0 ) { glDeleteTextures(1, &(x)); x = 0; } } - -#define FORIT(it, v) for(it = (v).begin(); it != (v).end(); ++(it)) - -// sends a message to output window if assert fails -#define BMSG(x, str) { if( !(x) ) { GS_LOG(str); GS_LOG(str); } } -#define BMSG_RETURN(x, str) { if( !(x) ) { GS_LOG(str); GS_LOG(str); return; } } -#define BMSG_RETURNX(x, str, rtype) { if( !(x) ) { GS_LOG(str); GS_LOG(str); return (##rtype); } } -#define B(x) { if( !(x) ) { GS_LOG(_#x"\n"); GS_LOG(#x"\n"); } } -#define B_RETURN(x) { if( !(x) ) { ERROR_LOG("%s:%d: %s\n", __FILE__, (u32)__LINE__, #x); return; } } -#define B_RETURNX(x, rtype) { if( !(x) ) { ERROR_LOG("%s:%d: %s\n", __FILE__, (u32)__LINE__, #x); return (##rtype); } } -#define B_G(x, action) { if( !(x) ) { ERROR_LOG("%s:%d: %s\n", __FILE__, (u32)__LINE__, #x); action; } } - -#define GL_REPORT_ERROR() { err = glGetError(); if( err != GL_NO_ERROR ) { ERROR_LOG("%s:%d: gl error 0x%x\n", __FILE__, (int)__LINE__, err); ZeroGS::HandleGLError(); } } - -#ifdef _DEBUG -#define GL_REPORT_ERRORD() { GLenum err = glGetError(); if( err != GL_NO_ERROR ) { ERROR_LOG("%s:%d: gl error 0x%x\n", __FILE__, (int)__LINE__, err); ZeroGS::HandleGLError(); } } -#else -#define GL_REPORT_ERRORD() -#endif - -// sets the data stream -#define SET_STREAM() { \ - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexGPU), (void*)8); \ - glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, sizeof(VertexGPU), (void*)12); \ - glTexCoordPointer(3, GL_FLOAT, sizeof(VertexGPU), (void*)16); \ - glVertexPointer(4, GL_SHORT, sizeof(VertexGPU), (void*)0); \ -} - -#define SETVERTEXSHADER(prog) { \ - if( (prog) != g_vsprog ) { \ - cgGLBindProgram(prog); \ - g_vsprog = prog; \ - } \ -} \ - -#define SETPIXELSHADER(prog) { \ - if( (prog) != g_psprog ) { \ - cgGLBindProgram(prog); \ - g_psprog = prog; \ - } \ -} \ - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -#endif - -// all textures have this width -//#define GPU_TEXWIDTH 512 -extern int GPU_TEXWIDTH; -extern float g_fiGPU_TEXWIDTH; -#define GPU_TEXMASKWIDTH 1024 // bitwise mask width for region repeat mode - -extern CGprogram g_vsprog, g_psprog; - -struct FRAGMENTSHADER -{ - FRAGMENTSHADER() : prog(0), sMemory(0), sFinal(0), sBitwiseANDX(0), sBitwiseANDY(0), sInterlace(0), sCLUT(0), sOneColor(0), sBitBltZ(0), - fTexAlpha2(0), fTexOffset(0), fTexDims(0), fTexBlock(0), fClampExts(0), fTexWrapMode(0), - fRealTexDims(0), fTestBlack(0), fPageOffset(0), fTexAlpha(0) {} - - CGprogram prog; - CGparameter sMemory, sFinal, sBitwiseANDX, sBitwiseANDY, sCLUT, sInterlace; - CGparameter sOneColor, sBitBltZ, sInvTexDims; - CGparameter fTexAlpha2, fTexOffset, fTexDims, fTexBlock, fClampExts, fTexWrapMode, fRealTexDims, fTestBlack, fPageOffset, fTexAlpha; - -#ifdef _DEBUG - string filename; -#endif -}; - -struct VERTEXSHADER -{ - VERTEXSHADER() : prog(0), sBitBltPos(0), sBitBltTex(0) {} - CGprogram prog; - CGparameter sBitBltPos, sBitBltTex, fBitBltTrans; // vertex shader constants -}; - -// don't change these values! -#define GAME_TEXTURETARGS 0x01 -#define GAME_AUTORESET 0x02 -#define GAME_INTERLACE2X 0x04 -#define GAME_TEXAHACK 0x08 // apply texa to non textured polys -#define GAME_NOTARGETRESOLVE 0x10 -#define GAME_EXACTCOLOR 0x20 -#define GAME_NOCOLORCLAMP 0x40 -#define GAME_FFXHACK 0x80 -#define GAME_NODEPTHUPDATE 0x0200 -#define GAME_QUICKRESOLVE1 0x0400 -#define GAME_NOQUICKRESOLVE 0x0800 -#define GAME_NOTARGETCLUT 0x1000 // full 16 bit resolution -#define GAME_NOSTENCIL 0x2000 -#define GAME_VSSHACKOFF 0x4000 // vertical stripe syndrome -#define GAME_NODEPTHRESOLVE 0x8000 -#define GAME_FULL16BITRES 0x00010000 -#define GAME_RESOLVEPROMOTED 0x00020000 -#define GAME_FASTUPDATE 0x00040000 -#define GAME_NOALPHATEST 0x00080000 -#define GAME_DISABLEMRTDEPTH 0x00100000 -#define GAME_32BITTARGS 0x00200000 -#define GAME_PATH3HACK 0x00400000 -#define GAME_DOPARALLELCTX 0x00800000 // tries to parallelize both contexts so that render calls are reduced (xenosaga) - // makes the game faster, but can be buggy -#define GAME_XENOSPECHACK 0x01000000 // xenosaga specularity hack (ignore any zmask=1 draws) -#define GAME_PARTIALPOINTERS 0x02000000 // whenver the texture or render target are small, tries to look for bigger ones to read from -#define GAME_PARTIALDEPTH 0x04000000 // tries to save depth targets as much as possible across height changes - -#define USEALPHATESTING (!(g_GameSettings&GAME_NOALPHATEST)) - -extern u8* g_pbyGSMemory; -extern u8* g_pbyGSClut; // the temporary clut buffer -extern CGparameter g_vparamPosXY[2], g_fparamFogColor; - -namespace ZeroGS { - - typedef void (*DrawFn)(); - - enum RenderFormatType - { - RFT_byte8 = 0, // A8R8G8B8 - RFT_float16 = 1, // A32R32B32G32 - }; - - // managers render-to-texture targets - class CRenderTarget - { - public: - CRenderTarget(); - virtual ~CRenderTarget(); - - virtual bool Create(const frameInfo& frame); - virtual void Destroy(); - - // set the GPU_POSXY variable, scissor rect, and current render target - void SetTarget(int fbplocal, const Rect2& scissor, int context); - void SetViewport(); - - // copies/creates the feedback contents - inline void CreateFeedback() { - if( ptexFeedback == 0 || !(status&TS_FeedbackReady) ) - _CreateFeedback(); - } - - virtual void Resolve(); - virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range - virtual void Update(int context, CRenderTarget* pdepth); - virtual void ConvertTo32(); // converts a psm==2 target, to a psm==0 - virtual void ConvertTo16(); // converts a psm==0 target, to a psm==2 - - virtual bool IsDepth() { return false; } - void SetRenderTarget(int targ); - - void* psys; // system data used for comparison - u32 ptex; - - int fbp, fbw, fbh; // if fbp is negative, virtual target (not mapped to any real addr) - int start, end; // in bytes - u32 lastused; // time stamp since last used - Vector vposxy; - - u32 fbm; - u16 status; - u8 psm; - u8 resv0; - Rect scissorrect; - - //int startresolve, endresolve; - u32 nUpdateTarg; // use this target to update the texture if non 0 (one time only) - - // this is optionally used when feedback effects are used (render target is used as a texture when rendering to itself) - u32 ptexFeedback; - - enum TargetStatus { - TS_Resolved = 1, - TS_NeedUpdate = 2, - TS_Virtual = 4, // currently not mapped to memory - TS_FeedbackReady = 8, // feedback effect is ready and doesn't need to be updated - TS_NeedConvert32 = 16, - TS_NeedConvert16 = 32, - }; - - private: - void _CreateFeedback(); - }; - - // manages zbuffers - class CDepthTarget : public CRenderTarget - { - public: - CDepthTarget(); - virtual ~CDepthTarget(); - - virtual bool Create(const frameInfo& frame); - virtual void Destroy(); - - virtual void Resolve(); - virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range - virtual void Update(int context, CRenderTarget* prndr); - - virtual bool IsDepth() { return true; } - - void SetDepthStencilSurface(); - - u32 pdepth; // 24 bit, will contain the stencil buffer if possible - u32 pstencil; // if not 0, contains the stencil buffer - int icount; // internal counter - }; - - // manages contiguous chunks of memory (width is always 1024) - class CMemoryTarget - { - public: - struct TEXTURE - { - inline TEXTURE() : tex(0), memptr(NULL), ref(0) {} - inline ~TEXTURE() { glDeleteTextures(1, &tex); _aligned_free(memptr); } - u32 tex; - int ref; - u8* memptr; // GPU memory used for comparison - }; - - inline CMemoryTarget() : ptex(NULL), starty(0), height(0), realy(0), realheight(0), usedstamp(0), psm(0), channels(0),cpsm(0), clearminy(0), clearmaxy(0), validatecount(0) {} - - inline CMemoryTarget(const CMemoryTarget& r) { - ptex = r.ptex; - if( ptex != NULL ) ptex->ref++; - starty = r.starty; - height = r.height; - realy = r.realy; - realheight = r.realheight; - usedstamp = r.usedstamp; - psm = r.psm; - cpsm = r.cpsm; - clut = r.clut; - clearminy = r.clearminy; - clearmaxy = r.clearmaxy; - widthmult = r.widthmult; - channels = r.channels; - validatecount = r.validatecount; - fmt = r.fmt; - } - - ~CMemoryTarget() { Destroy(); } - - inline void Destroy() { - if( ptex != NULL && ptex->ref > 0 ) { - if( --ptex->ref <= 0 ) - delete ptex; - } - - ptex = NULL; - } - - // returns true if clut data is synced - bool ValidateClut(const tex0Info& tex0); - // returns true if tex data is synced - bool ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex); - - int clearminy, clearmaxy; // when maxy > 0, need to check for clearing - - // realy is offset in pixels from start of valid region - // so texture in memory is [realy,starty+height] - // valid texture is [starty,starty+height] - // offset in mem [starty-realy, height] - int starty, height; // assert(starty >= realy) - int realy, realheight; // this is never touched once allocated - u32 usedstamp; - TEXTURE* ptex; // can be 16bit - u32 fmt; - - int widthmult; - int channels; - - int validatecount; // count how many times has been validated, if too many, destroy - - vector clut; // if nonzero, texture uses CLUT - u8 psm, cpsm; // texture and clut format. For psm, only 16bit/32bit differentiation matters - }; - - - struct VB - { - VB(); - ~VB(); - - void Destroy(); - - __forceinline bool CheckPrim(); - void CheckFrame(int tbp); - - // context specific state - Point offset; - Rect2 scissor; - tex0Info tex0; - tex1Info tex1; - miptbpInfo miptbp0; - miptbpInfo miptbp1; - alphaInfo alpha; - fbaInfo fba; - clampInfo clamp; - pixTest test; - u32 ptexClamp[2]; // textures for x and y dir region clamping - - public: - void FlushTexData(); - - // notify VB that nVerts need to be written to pbuf - inline void NotifyWrite(int nVerts) { - assert( pBufferData != NULL && nCount <= nNumVertices && nVerts > 0 ); - - if( nCount + nVerts > nNumVertices ) { - // recreate except with a bigger count - VertexGPU* ptemp = (VertexGPU*)_aligned_malloc(sizeof(VertexGPU)*nNumVertices*2, 256); - memcpy_amd(ptemp, pBufferData, sizeof(VertexGPU) * nCount); - nNumVertices *= 2; - assert( nCount + nVerts <= nNumVertices ); - _aligned_free(pBufferData); - pBufferData = ptemp; - } - } - - void Init(int nVerts) { - if( pBufferData == NULL && nVerts > 0 ) { - pBufferData = (VertexGPU*)_aligned_malloc(sizeof(VertexGPU)*nVerts, 256); - nNumVertices = nVerts; - } - - nCount = 0; - } - - u8 bNeedFrameCheck; - u8 bNeedZCheck; - u8 bNeedTexCheck; - u8 dummy0; - - union { - struct { - u8 bTexConstsSync; // only pixel shader constants that context owns - u8 bVarsTexSync; // texture info - u8 bVarsSetTarg; - u8 dummy1; - }; - u32 bSyncVars; - }; - - int ictx; - VertexGPU* pBufferData; // current allocated data - - int nNumVertices; // size of pBufferData in terms of VertexGPU objects - int nCount; - primInfo curprim; // the previous prim the current buffers are set to - - zbufInfo zbuf; - frameInfo gsfb; // the real info set by FRAME cmd - frameInfo frame; - int zprimmask; // zmask for incoming points - - u32 uCurTex0Data[2]; // current tex0 data - u32 uNextTex0Data[2]; // tex0 data that has to be applied if bNeedTexCheck is 1 - - //int nFrameHeights[8]; // frame heights for the past frame changes - int nNextFrameHeight; - - CMemoryTarget* pmemtarg; // the current mem target set - CRenderTarget* prndr; - CDepthTarget* pdepth; - }; - - // visible members - extern DrawFn drawfn[8]; - extern VB vb[2]; - extern float fiTexWidth[2], fiTexHeight[2]; // current tex width and height - - void AddMessage(const char* pstr, u32 ms = 5000); - void DrawText(const char* pstr, int left, int top, u32 color); - void ChangeWindowSize(int nNewWidth, int nNewHeight); - void SetChangeDeviceSize(int nNewWidth, int nNewHeight); - void ChangeDeviceSize(int nNewWidth, int nNewHeight); - void SetAA(int mode); - void SetCRC(int crc); - - void ReloadEffects(); - - // Methods // - bool IsGLExt( const char* szTargetExtension ); ///< returns true if the the opengl extension is supported - bool Create(int width, int height); - void Destroy(BOOL bD3D); - - void Restore(); // call to restore device - void Reset(); // call to destroy video resources - - void GSStateReset(); - void HandleGLError(); - - // called on a primitive switch - void Prim(); - - void SetTexFlush(); - // flush current vertices, call before setting new registers (the main render method) - void Flush(int context); - - void ExtWrite(); - - void SetWriteDepth(); - BOOL IsWriteDepth(); - - void SetDestAlphaTest(); - BOOL IsWriteDestAlphaTest(); - - void SetFogColor(u32 fog); - void SaveTex(tex0Info* ptex, int usevid); - - // called when trxdir is accessed. If host is involved, transfers memory to temp buffer byTransferBuf. - // Otherwise performs the transfer. TODO: Perhaps divide the transfers into chunks? - void InitTransferHostLocal(); - void TransferHostLocal(const void* pbyMem, u32 nQWordSize); - - void InitTransferLocalHost(); - void TransferLocalHost(void* pbyMem, u32 nQWordSize); - inline void TerminateLocalHost() {} - - void TransferLocalLocal(); - - // switches the render target to the real target, flushes the current render targets and renders the real image - void RenderCRTC(int interlace); - void ResetRenderTarget(int index); - - bool CheckChangeInClut(u32 highdword, u32 psm); // returns true if clut will change after this tex0 op - - // call to load CLUT data (depending on CLD) - void texClutWrite(int ctx); - RenderFormatType GetRenderFormat(); - GLenum GetRenderTargetFormat(); - - int Save(char* pbydata); - bool Load(char* pbydata); - - void SaveSnapshot(const char* filename); - bool SaveRenderTarget(const char* filename, int width, int height, int jpeg); - bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height); - bool SaveJPEG(const char* filename, int width, int height, const void* pdata, int quality); - bool SaveTGA(const char* filename, int width, int height, void* pdata); - - // private methods - void FlushSysMem(const RECT* prc); - void _Resolve(const void* psrc, int fbp, int fbw, int fbh, int psm, u32 fbm); - - // returns the first and last addresses aligned to a page that cover - void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw); - - // inits the smallest rectangle in ptexMem that covers this region in ptexMem - // returns the offset that needs to be added to the locked rect to get the beginning of the buffer - //void GetMemRect(RECT& rc, int psm, int x, int y, int w, int h, int bp, int bw); - - // only sets a limited amount of state (for Update) - void SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, ZeroGS::CMemoryTarget* pmemtarg, FRAGMENTSHADER* pfragment, int force); - - void ResetAlphaVariables(); - - void StartCapture(); - void StopCapture(); - void CaptureFrame(); -}; - -// GL prototypes -extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; -extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; -extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT; -extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT; -extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT; -extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT; -extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT; -extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT; -extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT; -extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT; -extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT; -extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT; -extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT; -extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT; -extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT; -extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT; -extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; -extern PFNGLDRAWBUFFERSPROC glDrawBuffers; - -#endif +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#ifndef __ZEROGS__H +#define __ZEROGS__H + +#pragma warning(disable:4200) // nonstandard extension used : zero-sized array in struct/union + +#ifndef _WIN32 +// adding glew support instead of glXGetProcAddress (thanks to scaught) +#include +#endif + +#include +#include + +#ifndef _WIN32 +#include +inline void* wglGetProcAddress(const char* x) { + return (void*)glXGetProcAddress((const GLubyte*)x); +} +#else +#include "glprocs.h" +#endif + +#include +#include + +#ifndef GL_DEPTH24_STENCIL8_EXT // allows FBOs to support stencils +#define GL_DEPTH_STENCIL_EXT 0x84F9 +#define GL_UNSIGNED_INT_24_8_EXT 0x84FA +#define GL_DEPTH24_STENCIL8_EXT 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 +#endif + +#include + +#include +#include +#include +#include +#include +using namespace std; + +#ifndef SAFE_DELETE +#define SAFE_DELETE(x) if( (x) != NULL ) { delete (x); (x) = NULL; } +#endif +#ifndef SAFE_DELETE_ARRAY +#define SAFE_DELETE_ARRAY(x) if( (x) != NULL ) { delete[] (x); (x) = NULL; } +#endif +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(x) if( (x) != NULL ) { (x)->Release(); (x) = NULL; } +#endif + +#define SAFE_RELEASE_PROG(x) { if( (x) != NULL ) { cgDestroyProgram(x); x = NULL; } } +#define SAFE_RELEASE_TEX(x) { if( (x) != 0 ) { glDeleteTextures(1, &(x)); x = 0; } } + +#define FORIT(it, v) for(it = (v).begin(); it != (v).end(); ++(it)) + +// sends a message to output window if assert fails +#define BMSG(x, str) { if( !(x) ) { GS_LOG(str); GS_LOG(str); } } +#define BMSG_RETURN(x, str) { if( !(x) ) { GS_LOG(str); GS_LOG(str); return; } } +#define BMSG_RETURNX(x, str, rtype) { if( !(x) ) { GS_LOG(str); GS_LOG(str); return (##rtype); } } +#define B(x) { if( !(x) ) { GS_LOG(_#x"\n"); GS_LOG(#x"\n"); } } +#define B_RETURN(x) { if( !(x) ) { ERROR_LOG("%s:%d: %s\n", __FILE__, (u32)__LINE__, #x); return; } } +#define B_RETURNX(x, rtype) { if( !(x) ) { ERROR_LOG("%s:%d: %s\n", __FILE__, (u32)__LINE__, #x); return (##rtype); } } +#define B_G(x, action) { if( !(x) ) { ERROR_LOG("%s:%d: %s\n", __FILE__, (u32)__LINE__, #x); action; } } + +#define GL_REPORT_ERROR() { err = glGetError(); if( err != GL_NO_ERROR ) { ERROR_LOG("%s:%d: gl error 0x%x\n", __FILE__, (int)__LINE__, err); ZeroGS::HandleGLError(); } } + +#ifdef _DEBUG +#define GL_REPORT_ERRORD() { GLenum err = glGetError(); if( err != GL_NO_ERROR ) { ERROR_LOG("%s:%d: gl error 0x%x\n", __FILE__, (int)__LINE__, err); ZeroGS::HandleGLError(); } } +#else +#define GL_REPORT_ERRORD() +#endif + +// sets the data stream +#define SET_STREAM() { \ + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexGPU), (void*)8); \ + glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, sizeof(VertexGPU), (void*)12); \ + glTexCoordPointer(3, GL_FLOAT, sizeof(VertexGPU), (void*)16); \ + glVertexPointer(4, GL_SHORT, sizeof(VertexGPU), (void*)0); \ +} + +#define SETVERTEXSHADER(prog) { \ + if( (prog) != g_vsprog ) { \ + cgGLBindProgram(prog); \ + g_vsprog = prog; \ + } \ +} \ + +#define SETPIXELSHADER(prog) { \ + if( (prog) != g_psprog ) { \ + cgGLBindProgram(prog); \ + g_psprog = prog; \ + } \ +} \ + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +// all textures have this width +//#define GPU_TEXWIDTH 512 +extern int GPU_TEXWIDTH; +extern float g_fiGPU_TEXWIDTH; +#define GPU_TEXMASKWIDTH 1024 // bitwise mask width for region repeat mode + +extern CGprogram g_vsprog, g_psprog; + +struct FRAGMENTSHADER +{ + FRAGMENTSHADER() : prog(0), sMemory(0), sFinal(0), sBitwiseANDX(0), sBitwiseANDY(0), sInterlace(0), sCLUT(0), sOneColor(0), sBitBltZ(0), + fTexAlpha2(0), fTexOffset(0), fTexDims(0), fTexBlock(0), fClampExts(0), fTexWrapMode(0), + fRealTexDims(0), fTestBlack(0), fPageOffset(0), fTexAlpha(0) {} + + CGprogram prog; + CGparameter sMemory, sFinal, sBitwiseANDX, sBitwiseANDY, sCLUT, sInterlace; + CGparameter sOneColor, sBitBltZ, sInvTexDims; + CGparameter fTexAlpha2, fTexOffset, fTexDims, fTexBlock, fClampExts, fTexWrapMode, fRealTexDims, fTestBlack, fPageOffset, fTexAlpha; + +#ifdef _DEBUG + string filename; +#endif +}; + +struct VERTEXSHADER +{ + VERTEXSHADER() : prog(0), sBitBltPos(0), sBitBltTex(0) {} + CGprogram prog; + CGparameter sBitBltPos, sBitBltTex, fBitBltTrans; // vertex shader constants +}; + +// don't change these values! +#define GAME_TEXTURETARGS 0x01 +#define GAME_AUTORESET 0x02 +#define GAME_INTERLACE2X 0x04 +#define GAME_TEXAHACK 0x08 // apply texa to non textured polys +#define GAME_NOTARGETRESOLVE 0x10 +#define GAME_EXACTCOLOR 0x20 +#define GAME_NOCOLORCLAMP 0x40 +#define GAME_FFXHACK 0x80 +#define GAME_NODEPTHUPDATE 0x0200 +#define GAME_QUICKRESOLVE1 0x0400 +#define GAME_NOQUICKRESOLVE 0x0800 +#define GAME_NOTARGETCLUT 0x1000 // full 16 bit resolution +#define GAME_NOSTENCIL 0x2000 +#define GAME_VSSHACKOFF 0x4000 // vertical stripe syndrome +#define GAME_NODEPTHRESOLVE 0x8000 +#define GAME_FULL16BITRES 0x00010000 +#define GAME_RESOLVEPROMOTED 0x00020000 +#define GAME_FASTUPDATE 0x00040000 +#define GAME_NOALPHATEST 0x00080000 +#define GAME_DISABLEMRTDEPTH 0x00100000 +#define GAME_32BITTARGS 0x00200000 +#define GAME_PATH3HACK 0x00400000 +#define GAME_DOPARALLELCTX 0x00800000 // tries to parallelize both contexts so that render calls are reduced (xenosaga) + // makes the game faster, but can be buggy +#define GAME_XENOSPECHACK 0x01000000 // xenosaga specularity hack (ignore any zmask=1 draws) +#define GAME_PARTIALPOINTERS 0x02000000 // whenver the texture or render target are small, tries to look for bigger ones to read from +#define GAME_PARTIALDEPTH 0x04000000 // tries to save depth targets as much as possible across height changes + +#define USEALPHATESTING (!(g_GameSettings&GAME_NOALPHATEST)) + +extern u8* g_pbyGSMemory; +extern u8* g_pbyGSClut; // the temporary clut buffer +extern CGparameter g_vparamPosXY[2], g_fparamFogColor; + +namespace ZeroGS { + + typedef void (*DrawFn)(); + + enum RenderFormatType + { + RFT_byte8 = 0, // A8R8G8B8 + RFT_float16 = 1, // A32R32B32G32 + }; + + // managers render-to-texture targets + class CRenderTarget + { + public: + CRenderTarget(); + virtual ~CRenderTarget(); + + virtual bool Create(const frameInfo& frame); + virtual void Destroy(); + + // set the GPU_POSXY variable, scissor rect, and current render target + void SetTarget(int fbplocal, const Rect2& scissor, int context); + void SetViewport(); + + // copies/creates the feedback contents + inline void CreateFeedback() { + if( ptexFeedback == 0 || !(status&TS_FeedbackReady) ) + _CreateFeedback(); + } + + virtual void Resolve(); + virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range + virtual void Update(int context, CRenderTarget* pdepth); + virtual void ConvertTo32(); // converts a psm==2 target, to a psm==0 + virtual void ConvertTo16(); // converts a psm==0 target, to a psm==2 + + virtual bool IsDepth() { return false; } + void SetRenderTarget(int targ); + + void* psys; // system data used for comparison + u32 ptex; + + int fbp, fbw, fbh; // if fbp is negative, virtual target (not mapped to any real addr) + int start, end; // in bytes + u32 lastused; // time stamp since last used + Vector vposxy; + + u32 fbm; + u16 status; + u8 psm; + u8 resv0; + Rect scissorrect; + + //int startresolve, endresolve; + u32 nUpdateTarg; // use this target to update the texture if non 0 (one time only) + + // this is optionally used when feedback effects are used (render target is used as a texture when rendering to itself) + u32 ptexFeedback; + + enum TargetStatus { + TS_Resolved = 1, + TS_NeedUpdate = 2, + TS_Virtual = 4, // currently not mapped to memory + TS_FeedbackReady = 8, // feedback effect is ready and doesn't need to be updated + TS_NeedConvert32 = 16, + TS_NeedConvert16 = 32, + }; + + private: + void _CreateFeedback(); + }; + + // manages zbuffers + class CDepthTarget : public CRenderTarget + { + public: + CDepthTarget(); + virtual ~CDepthTarget(); + + virtual bool Create(const frameInfo& frame); + virtual void Destroy(); + + virtual void Resolve(); + virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range + virtual void Update(int context, CRenderTarget* prndr); + + virtual bool IsDepth() { return true; } + + void SetDepthStencilSurface(); + + u32 pdepth; // 24 bit, will contain the stencil buffer if possible + u32 pstencil; // if not 0, contains the stencil buffer + int icount; // internal counter + }; + + // manages contiguous chunks of memory (width is always 1024) + class CMemoryTarget + { + public: + struct TEXTURE + { + inline TEXTURE() : tex(0), memptr(NULL), ref(0) {} + inline ~TEXTURE() { glDeleteTextures(1, &tex); _aligned_free(memptr); } + u32 tex; + int ref; + u8* memptr; // GPU memory used for comparison + }; + + inline CMemoryTarget() : ptex(NULL), starty(0), height(0), realy(0), realheight(0), usedstamp(0), psm(0), channels(0),cpsm(0), clearminy(0), clearmaxy(0), validatecount(0) {} + + inline CMemoryTarget(const CMemoryTarget& r) { + ptex = r.ptex; + if( ptex != NULL ) ptex->ref++; + starty = r.starty; + height = r.height; + realy = r.realy; + realheight = r.realheight; + usedstamp = r.usedstamp; + psm = r.psm; + cpsm = r.cpsm; + clut = r.clut; + clearminy = r.clearminy; + clearmaxy = r.clearmaxy; + widthmult = r.widthmult; + channels = r.channels; + validatecount = r.validatecount; + fmt = r.fmt; + } + + ~CMemoryTarget() { Destroy(); } + + inline void Destroy() { + if( ptex != NULL && ptex->ref > 0 ) { + if( --ptex->ref <= 0 ) + delete ptex; + } + + ptex = NULL; + } + + // returns true if clut data is synced + bool ValidateClut(const tex0Info& tex0); + // returns true if tex data is synced + bool ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex); + + int clearminy, clearmaxy; // when maxy > 0, need to check for clearing + + // realy is offset in pixels from start of valid region + // so texture in memory is [realy,starty+height] + // valid texture is [starty,starty+height] + // offset in mem [starty-realy, height] + int starty, height; // assert(starty >= realy) + int realy, realheight; // this is never touched once allocated + u32 usedstamp; + TEXTURE* ptex; // can be 16bit + u32 fmt; + + int widthmult; + int channels; + + int validatecount; // count how many times has been validated, if too many, destroy + + vector clut; // if nonzero, texture uses CLUT + u8 psm, cpsm; // texture and clut format. For psm, only 16bit/32bit differentiation matters + }; + + + struct VB + { + VB(); + ~VB(); + + void Destroy(); + + __forceinline bool CheckPrim(); + void CheckFrame(int tbp); + + // context specific state + Point offset; + Rect2 scissor; + tex0Info tex0; + tex1Info tex1; + miptbpInfo miptbp0; + miptbpInfo miptbp1; + alphaInfo alpha; + fbaInfo fba; + clampInfo clamp; + pixTest test; + u32 ptexClamp[2]; // textures for x and y dir region clamping + + public: + void FlushTexData(); + + // notify VB that nVerts need to be written to pbuf + inline void NotifyWrite(int nVerts) { + assert( pBufferData != NULL && nCount <= nNumVertices && nVerts > 0 ); + + if( nCount + nVerts > nNumVertices ) { + // recreate except with a bigger count + VertexGPU* ptemp = (VertexGPU*)_aligned_malloc(sizeof(VertexGPU)*nNumVertices*2, 256); + memcpy_amd(ptemp, pBufferData, sizeof(VertexGPU) * nCount); + nNumVertices *= 2; + assert( nCount + nVerts <= nNumVertices ); + _aligned_free(pBufferData); + pBufferData = ptemp; + } + } + + void Init(int nVerts) { + if( pBufferData == NULL && nVerts > 0 ) { + pBufferData = (VertexGPU*)_aligned_malloc(sizeof(VertexGPU)*nVerts, 256); + nNumVertices = nVerts; + } + + nCount = 0; + } + + u8 bNeedFrameCheck; + u8 bNeedZCheck; + u8 bNeedTexCheck; + u8 dummy0; + + union { + struct { + u8 bTexConstsSync; // only pixel shader constants that context owns + u8 bVarsTexSync; // texture info + u8 bVarsSetTarg; + u8 dummy1; + }; + u32 bSyncVars; + }; + + int ictx; + VertexGPU* pBufferData; // current allocated data + + int nNumVertices; // size of pBufferData in terms of VertexGPU objects + int nCount; + primInfo curprim; // the previous prim the current buffers are set to + + zbufInfo zbuf; + frameInfo gsfb; // the real info set by FRAME cmd + frameInfo frame; + int zprimmask; // zmask for incoming points + + u32 uCurTex0Data[2]; // current tex0 data + u32 uNextTex0Data[2]; // tex0 data that has to be applied if bNeedTexCheck is 1 + + //int nFrameHeights[8]; // frame heights for the past frame changes + int nNextFrameHeight; + + CMemoryTarget* pmemtarg; // the current mem target set + CRenderTarget* prndr; + CDepthTarget* pdepth; + }; + + // visible members + extern DrawFn drawfn[8]; + extern VB vb[2]; + extern float fiTexWidth[2], fiTexHeight[2]; // current tex width and height + + void AddMessage(const char* pstr, u32 ms = 5000); + void DrawText(const char* pstr, int left, int top, u32 color); + void ChangeWindowSize(int nNewWidth, int nNewHeight); + void SetChangeDeviceSize(int nNewWidth, int nNewHeight); + void ChangeDeviceSize(int nNewWidth, int nNewHeight); + void SetAA(int mode); + void SetCRC(int crc); + + void ReloadEffects(); + + // Methods // + bool IsGLExt( const char* szTargetExtension ); ///< returns true if the the opengl extension is supported + bool Create(int width, int height); + void Destroy(BOOL bD3D); + + void Restore(); // call to restore device + void Reset(); // call to destroy video resources + + void GSStateReset(); + void HandleGLError(); + + // called on a primitive switch + void Prim(); + + void SetTexFlush(); + // flush current vertices, call before setting new registers (the main render method) + void Flush(int context); + + void ExtWrite(); + + void SetWriteDepth(); + BOOL IsWriteDepth(); + + void SetDestAlphaTest(); + BOOL IsWriteDestAlphaTest(); + + void SetFogColor(u32 fog); + void SaveTex(tex0Info* ptex, int usevid); + + // called when trxdir is accessed. If host is involved, transfers memory to temp buffer byTransferBuf. + // Otherwise performs the transfer. TODO: Perhaps divide the transfers into chunks? + void InitTransferHostLocal(); + void TransferHostLocal(const void* pbyMem, u32 nQWordSize); + + void InitTransferLocalHost(); + void TransferLocalHost(void* pbyMem, u32 nQWordSize); + inline void TerminateLocalHost() {} + + void TransferLocalLocal(); + + // switches the render target to the real target, flushes the current render targets and renders the real image + void RenderCRTC(int interlace); + void ResetRenderTarget(int index); + + bool CheckChangeInClut(u32 highdword, u32 psm); // returns true if clut will change after this tex0 op + + // call to load CLUT data (depending on CLD) + void texClutWrite(int ctx); + RenderFormatType GetRenderFormat(); + GLenum GetRenderTargetFormat(); + + int Save(char* pbydata); + bool Load(char* pbydata); + + void SaveSnapshot(const char* filename); + bool SaveRenderTarget(const char* filename, int width, int height, int jpeg); + bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height); + bool SaveJPEG(const char* filename, int width, int height, const void* pdata, int quality); + bool SaveTGA(const char* filename, int width, int height, void* pdata); + + // private methods + void FlushSysMem(const RECT* prc); + void _Resolve(const void* psrc, int fbp, int fbw, int fbh, int psm, u32 fbm); + + // returns the first and last addresses aligned to a page that cover + void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw); + + // inits the smallest rectangle in ptexMem that covers this region in ptexMem + // returns the offset that needs to be added to the locked rect to get the beginning of the buffer + //void GetMemRect(RECT& rc, int psm, int x, int y, int w, int h, int bp, int bw); + + // only sets a limited amount of state (for Update) + void SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, ZeroGS::CMemoryTarget* pmemtarg, FRAGMENTSHADER* pfragment, int force); + + void ResetAlphaVariables(); + + void StartCapture(); + void StopCapture(); + void CaptureFrame(); +}; + +// GL prototypes +extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; +extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; +extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT; +extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT; +extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT; +extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT; +extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT; +extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT; +extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT; +extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT; +extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT; +extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT; +extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT; +extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT; +extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT; +extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT; +extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; +extern PFNGLDRAWBUFFERSPROC glDrawBuffers; + +#endif diff --git a/plugins/zerogs/opengl/zerogsmath.h b/plugins/zerogs/opengl/zerogsmath.h index 9afad91022..83481ffb5b 100644 --- a/plugins/zerogs/opengl/zerogsmath.h +++ b/plugins/zerogs/opengl/zerogsmath.h @@ -1,903 +1,903 @@ -#ifndef ZEROGS_MATH_H -#define ZEROGS_MATH_H - -#ifndef _WIN32 -#include -#endif - -#include -#include - -#ifndef PI -#define PI ((dReal)3.141592654) -#endif - -#define rswap(x, y) *(int*)&(x) ^= *(int*)&(y) ^= *(int*)&(x) ^= *(int*)&(y); - -template inline T RAD_2_DEG(T radians) { return (radians * (T)57.29577951); } - -class Transform; -class TransformMatrix; - -typedef float dReal; -typedef dReal dMatrix3[3*4]; - -inline dReal* normalize3(dReal* pfout, const dReal* pf); -inline dReal* normalize4(dReal* pfout, const dReal* pf); -inline dReal* cross3(dReal* pfout, const dReal* pf1, const dReal* pf2); - -// multiplies 3x3 matrices -inline dReal* mult3(dReal* pfres, const dReal* pf1, const dReal* pf2); -inline double* mult3(double* pfres, const double* pf1, const double* pf2); - -inline dReal* inv3(const dReal* pf, dReal* pfres, int stride); -inline dReal* inv4(const dReal* pf, dReal* pfres); - -// class used for 3 and 4 dim vectors and quaternions -// It is better to use this for a 3 dim vector because it is 16byte aligned and SIMD instructions can be used -class Vector -{ -public: - dReal x, y, z, w; - - Vector() : x(0), y(0), z(0), w(0) {} - Vector(dReal x, dReal y, dReal z) : x(x), y(y), z(z), w(0) {} - Vector(dReal x, dReal y, dReal z, dReal w) : x(x), y(y), z(z), w(w) {} - Vector(const Vector &vec) : x(vec.x), y(vec.y), z(vec.z), w(vec.w) {} - Vector(const dReal* pf) { assert(pf != NULL); x = pf[0]; y = pf[1]; z = pf[2]; w = 0; } - - dReal operator[](int i) const { return (&x)[i]; } - dReal& operator[](int i) { return (&x)[i]; } - - // casting operators - operator dReal* () { return &x; } - operator const dReal* () const { return (const dReal*)&x; } - - // SCALAR FUNCTIONS - inline dReal dot(const Vector &v) const { return x*v.x + y*v.y + z*v.z + w*v.w; } - inline void normalize() { normalize4(&x, &x); } - - inline void Set3(const float* pvals) { x = pvals[0]; y = pvals[1]; z = pvals[2]; } - inline void Set4(const float* pvals) { x = pvals[0]; y = pvals[1]; z = pvals[2]; w = pvals[3]; } - - // 3 dim cross product, w is not touched - /// this = this x v - inline void Cross(const Vector &v) { cross3(&x, &x, v); } - - /// this = u x v - inline void Cross(const Vector &u, const Vector &v) { cross3(&x, u, v); } - - inline Vector operator-() const { Vector v; v.x = -x; v.y = -y; v.z = -z; v.w = -w; return v; } - inline Vector operator+(const Vector &r) const { Vector v; v.x = x+r.x; v.y = y+r.y; v.z = z+r.z; v.w = w+r.w; return v; } - inline Vector operator-(const Vector &r) const { Vector v; v.x = x-r.x; v.y = y-r.y; v.z = z-r.z; v.w = w-r.w; return v; } - inline Vector operator*(const Vector &r) const { Vector v; v.x = r.x*x; v.y = r.y*y; v.z = r.z*z; v.w = r.w*w; return v; } - inline Vector operator*(dReal k) const { Vector v; v.x = k*x; v.y = k*y; v.z = k*z; v.w = k*w; return v; } - - inline Vector& operator += (const Vector& r) { x += r.x; y += r.y; z += r.z; w += r.w; return *this; } - inline Vector& operator -= (const Vector& r) { x -= r.x; y -= r.y; z -= r.z; w -= r.w; return *this; } - inline Vector& operator *= (const Vector& r) { x *= r.x; y *= r.y; z *= r.z; w *= r.w; return *this; } - - inline Vector& operator *= (const dReal k) { x *= k; y *= k; z *= k; w *= k; return *this; } - inline Vector& operator /= (const dReal _k) { dReal k=1/_k; x *= k; y *= k; z *= k; w *= k; return *this; } - - friend Vector operator* (float f, const Vector& v); - //friend ostream& operator<<(ostream& O, const Vector& v); - //friend istream& operator>>(istream& I, Vector& v); -}; - -inline Vector operator* (float f, const Vector& left) -{ - Vector v; - v.x = f * left.x; - v.y = f * left.y; - v.z = f * left.z; - return v; -} - -struct AABB -{ - Vector pos, extents; -}; - -struct OBB -{ - Vector right, up, dir, pos, extents; -}; - -struct TRIANGLE -{ - TRIANGLE() {} - TRIANGLE(const Vector& v1, const Vector& v2, const Vector& v3) : v1(v1), v2(v2), v3(v3) {} - ~TRIANGLE() {} - - Vector v1, v2, v3; //!< the vertices of the triangle - - const Vector& operator[](int i) const { return (&v1)[i]; } - Vector& operator[](int i) { return (&v1)[i]; } - - /// assumes CCW ordering of vertices - inline Vector ComputeNormal() { - Vector normal; - cross3(normal, v2-v1, v3-v1); - return normal; - } -}; - -// Routines made for 3D graphics that deal with 3 or 4 dim algebra structures -// Functions with postfix 3 are for 3x3 operations, etc - -// all fns return pfout on success or NULL on failure -// results and arguments can share pointers - - -// multiplies 4x4 matrices -inline dReal* mult4(dReal* pfres, const dReal* pf1, const dReal* pf2); -inline double* mult4(double* pfres, const double* pf1, const double* pf2); - -// pf1^T * pf2 -inline dReal* multtrans3(dReal* pfres, const dReal* pf1, const dReal* pf2); -inline double* multtrans3(double* pfres, const double* pf1, const double* pf2); -inline dReal* multtrans4(dReal* pfres, const dReal* pf1, const dReal* pf2); -inline double* multtrans4(double* pfres, const double* pf1, const double* pf2); - -inline dReal* transpose3(const dReal* pf, dReal* pfres); -inline double* transpose3(const double* pf, double* pfres); -inline dReal* transpose4(const dReal* pf, dReal* pfres); -inline double* transpose4(const double* pf, double* pfres); - -inline dReal dot2(const dReal* pf1, const dReal* pf2); -inline dReal dot3(const dReal* pf1, const dReal* pf2); -inline dReal dot4(const dReal* pf1, const dReal* pf2); - -inline dReal lengthsqr2(const dReal* pf); -inline dReal lengthsqr3(const dReal* pf); -inline dReal lengthsqr4(const dReal* pf); - -inline dReal* normalize2(dReal* pfout, const dReal* pf); -inline dReal* normalize3(dReal* pfout, const dReal* pf); -inline dReal* normalize4(dReal* pfout, const dReal* pf); - -//// -// More complex ops that deal with arbitrary matrices // -//// - -// extract eigen values and vectors from a 2x2 matrix and returns true if all values are real -// returned eigen vectors are normalized -inline bool eig2(const dReal* pfmat, dReal* peigs, dReal& fv1x, dReal& fv1y, dReal& fv2x, dReal& fv2y); - -// Simple routines for linear algebra algorithms // -int CubicRoots (double c0, double c1, double c2, double *r0, double *r1, double *r2); -bool QLAlgorithm3 (dReal* m_aafEntry, dReal* afDiag, dReal* afSubDiag); - -void EigenSymmetric3(dReal* fCovariance, dReal* eval, dReal* fAxes); - -void GetCovarBasisVectors(dReal fCovariance[3][3], Vector* vRight, Vector* vUp, Vector* vDir); - -// first root returned is always >= second, roots are defined if the quadratic doesn't have real solutions -void QuadraticSolver(dReal* pfQuadratic, dReal* pfRoots); - -int insideQuadrilateral(const Vector* p0,const Vector* p1, const Vector* p2,const Vector* p3); -int insideTriangle(const Vector* p0, const Vector* p1, const Vector* p2); - -// multiplies a matrix by a scalar -template inline void mult(T* pf, T fa, int r); - -// multiplies a r1xc1 by c1xc2 matrix into pfres, if badd is true adds the result to pfres -// does not handle cases where pfres is equal to pf1 or pf2, use multtox for those cases -template -inline T* mult(T* pf1, R* pf2, int r1, int c1, int c2, S* pfres, bool badd = false); - -// pf1 is transposed before mult -// rows of pf2 must equal rows of pf1 -// pfres will be c1xc2 matrix -template -inline T* multtrans(T* pf1, R* pf2, int r1, int c1, int c2, S* pfres, bool badd = false); - -// pf2 is transposed before mult -// the columns of both matrices must be the same and equal to c1 -// r2 is the number of rows in pf2 -// pfres must be an r1xr2 matrix -template -inline T* multtrans_to2(T* pf1, R* pf2, int r1, int c1, int r2, S* pfres, bool badd = false); - -// multiplies rxc matrix pf1 and cxc matrix pf2 and stores the result in pf1, -// the function needs a temporary buffer the size of c doubles, if pftemp == NULL, -// the function will allocate the necessary memory, otherwise pftemp should be big -// enough to store all the entries -template inline T* multto1(T* pf1, T* pf2, int r1, int c1, T* pftemp = NULL); - -// same as multto1 except stores the result in pf2, pf1 has to be an r2xr2 matrix -// pftemp must be of size r2 if not NULL -template inline T* multto2(T* pf1, S* pf2, int r2, int c2, S* pftemp = NULL); - -// add pf1 + pf2 and store in pf1 -template inline void sub(T* pf1, T* pf2, int r); -template inline T normsqr(T* pf1, int r); -template inline T lengthsqr(T* pf1, T* pf2, int length); -template inline T dot(T* pf1, T* pf2, int length); - -template inline T sum(T* pf, int length); - -// takes the inverse of the 3x3 matrix pf and stores it into pfres, returns true if matrix is invertible -template inline bool inv2(T* pf, T* pfres); - -/////////////////////// -// Function Definitions -/////////////////////// -bool eig2(const dReal* pfmat, dReal* peigs, dReal& fv1x, dReal& fv1y, dReal& fv2x, dReal& fv2y) -{ - // x^2 + bx + c - dReal a, b, c, d; - b = -(pfmat[0] + pfmat[3]); - c = pfmat[0] * pfmat[3] - pfmat[1] * pfmat[2]; - d = b * b - 4.0f * c + 1e-16f; - - if( d < 0 ) return false; - if( d < 1e-16f ) { - a = -0.5f * b; - peigs[0] = a; peigs[1] = a; - fv1x = pfmat[1]; fv1y = a - pfmat[0]; - c = 1 / sqrtf(fv1x*fv1x + fv1y*fv1y); - fv1x *= c; fv1y *= c; - fv2x = -fv1y; fv2y = fv1x; - return true; - } - - // two roots - d = sqrtf(d); - a = -0.5f * (b + d); - peigs[0] = a; - fv1x = pfmat[1]; fv1y = a-pfmat[0]; - c = 1 / sqrtf(fv1x*fv1x + fv1y*fv1y); - fv1x *= c; fv1y *= c; - - a += d; - peigs[1] = a; - fv2x = pfmat[1]; fv2y = a-pfmat[0]; - c = 1 / sqrtf(fv2x*fv2x + fv2y*fv2y); - fv2x *= c; fv2y *= c; - return true; -} - -//#ifndef TI_USING_IPP - -// Functions that are replacable by ipp library funcs -template inline T* _mult3(T* pfres, const T* pf1, const T* pf2) -{ - assert( pf1 != NULL && pf2 != NULL && pfres != NULL ); - - T* pfres2; - if( pfres == pf1 || pfres == pf2 ) pfres2 = (T*)alloca(9 * sizeof(T)); - else pfres2 = pfres; - - pfres2[0*4+0] = pf1[0*4+0]*pf2[0*4+0]+pf1[0*4+1]*pf2[1*4+0]+pf1[0*4+2]*pf2[2*4+0]; - pfres2[0*4+1] = pf1[0*4+0]*pf2[0*4+1]+pf1[0*4+1]*pf2[1*4+1]+pf1[0*4+2]*pf2[2*4+1]; - pfres2[0*4+2] = pf1[0*4+0]*pf2[0*4+2]+pf1[0*4+1]*pf2[1*4+2]+pf1[0*4+2]*pf2[2*4+2]; - - pfres2[1*4+0] = pf1[1*4+0]*pf2[0*4+0]+pf1[1*4+1]*pf2[1*4+0]+pf1[1*4+2]*pf2[2*4+0]; - pfres2[1*4+1] = pf1[1*4+0]*pf2[0*4+1]+pf1[1*4+1]*pf2[1*4+1]+pf1[1*4+2]*pf2[2*4+1]; - pfres2[1*4+2] = pf1[1*4+0]*pf2[0*4+2]+pf1[1*4+1]*pf2[1*4+2]+pf1[1*4+2]*pf2[2*4+2]; - - pfres2[2*4+0] = pf1[2*4+0]*pf2[0*4+0]+pf1[2*4+1]*pf2[1*4+0]+pf1[2*4+2]*pf2[2*4+0]; - pfres2[2*4+1] = pf1[2*4+0]*pf2[0*4+1]+pf1[2*4+1]*pf2[1*4+1]+pf1[2*4+2]*pf2[2*4+1]; - pfres2[2*4+2] = pf1[2*4+0]*pf2[0*4+2]+pf1[2*4+1]*pf2[1*4+2]+pf1[2*4+2]*pf2[2*4+2]; - - if( pfres2 != pfres ) memcpy(pfres, pfres2, 9*sizeof(T)); - - return pfres; -} - -inline dReal* mult3(dReal* pfres, const dReal* pf1, const dReal* pf2) { return _mult3(pfres, pf1, pf2); } -inline double* mult3(double* pfres, const double* pf1, const double* pf2) { return _mult3(pfres, pf1, pf2); } - -template -inline T* _mult4(T* pfres, const T* p1, const T* p2) -{ - assert( pfres != NULL && p1 != NULL && p2 != NULL ); - - T* pfres2; - if( pfres == p1 || pfres == p2 ) pfres2 = (T*)alloca(16 * sizeof(T)); - else pfres2 = pfres; - - pfres2[0*4+0] = p1[0*4+0]*p2[0*4+0] + p1[0*4+1]*p2[1*4+0] + p1[0*4+2]*p2[2*4+0] + p1[0*4+3]*p2[3*4+0]; - pfres2[0*4+1] = p1[0*4+0]*p2[0*4+1] + p1[0*4+1]*p2[1*4+1] + p1[0*4+2]*p2[2*4+1] + p1[0*4+3]*p2[3*4+1]; - pfres2[0*4+2] = p1[0*4+0]*p2[0*4+2] + p1[0*4+1]*p2[1*4+2] + p1[0*4+2]*p2[2*4+2] + p1[0*4+3]*p2[3*4+2]; - pfres2[0*4+3] = p1[0*4+0]*p2[0*4+3] + p1[0*4+1]*p2[1*4+3] + p1[0*4+2]*p2[2*4+3] + p1[0*4+3]*p2[3*4+3]; - - pfres2[1*4+0] = p1[1*4+0]*p2[0*4+0] + p1[1*4+1]*p2[1*4+0] + p1[1*4+2]*p2[2*4+0] + p1[1*4+3]*p2[3*4+0]; - pfres2[1*4+1] = p1[1*4+0]*p2[0*4+1] + p1[1*4+1]*p2[1*4+1] + p1[1*4+2]*p2[2*4+1] + p1[1*4+3]*p2[3*4+1]; - pfres2[1*4+2] = p1[1*4+0]*p2[0*4+2] + p1[1*4+1]*p2[1*4+2] + p1[1*4+2]*p2[2*4+2] + p1[1*4+3]*p2[3*4+2]; - pfres2[1*4+3] = p1[1*4+0]*p2[0*4+3] + p1[1*4+1]*p2[1*4+3] + p1[1*4+2]*p2[2*4+3] + p1[1*4+3]*p2[3*4+3]; - - pfres2[2*4+0] = p1[2*4+0]*p2[0*4+0] + p1[2*4+1]*p2[1*4+0] + p1[2*4+2]*p2[2*4+0] + p1[2*4+3]*p2[3*4+0]; - pfres2[2*4+1] = p1[2*4+0]*p2[0*4+1] + p1[2*4+1]*p2[1*4+1] + p1[2*4+2]*p2[2*4+1] + p1[2*4+3]*p2[3*4+1]; - pfres2[2*4+2] = p1[2*4+0]*p2[0*4+2] + p1[2*4+1]*p2[1*4+2] + p1[2*4+2]*p2[2*4+2] + p1[2*4+3]*p2[3*4+2]; - pfres2[2*4+3] = p1[2*4+0]*p2[0*4+3] + p1[2*4+1]*p2[1*4+3] + p1[2*4+2]*p2[2*4+3] + p1[2*4+3]*p2[3*4+3]; - - pfres2[3*4+0] = p1[3*4+0]*p2[0*4+0] + p1[3*4+1]*p2[1*4+0] + p1[3*4+2]*p2[2*4+0] + p1[3*4+3]*p2[3*4+0]; - pfres2[3*4+1] = p1[3*4+0]*p2[0*4+1] + p1[3*4+1]*p2[1*4+1] + p1[3*4+2]*p2[2*4+1] + p1[3*4+3]*p2[3*4+1]; - pfres2[3*4+2] = p1[3*4+0]*p2[0*4+2] + p1[3*4+1]*p2[1*4+2] + p1[3*4+2]*p2[2*4+2] + p1[3*4+3]*p2[3*4+2]; - pfres2[3*4+3] = p1[3*4+0]*p2[0*4+3] + p1[3*4+1]*p2[1*4+3] + p1[3*4+2]*p2[2*4+3] + p1[3*4+3]*p2[3*4+3]; - - if( pfres != pfres2 ) memcpy(pfres, pfres2, sizeof(T)*16); - return pfres; -} - -inline dReal* mult4(dReal* pfres, const dReal* pf1, const dReal* pf2) { return _mult4(pfres, pf1, pf2); } -inline double* mult4(double* pfres, const double* pf1, const double* pf2) { return _mult4(pfres, pf1, pf2); } - -template -inline T* _multtrans3(T* pfres, const T* pf1, const T* pf2) -{ - T* pfres2; - if( pfres == pf1 ) pfres2 = (T*)alloca(9 * sizeof(T)); - else pfres2 = pfres; - - pfres2[0] = pf1[0]*pf2[0]+pf1[3]*pf2[3]+pf1[6]*pf2[6]; - pfres2[1] = pf1[0]*pf2[1]+pf1[3]*pf2[4]+pf1[6]*pf2[7]; - pfres2[2] = pf1[0]*pf2[2]+pf1[3]*pf2[5]+pf1[6]*pf2[8]; - - pfres2[3] = pf1[1]*pf2[0]+pf1[4]*pf2[3]+pf1[7]*pf2[6]; - pfres2[4] = pf1[1]*pf2[1]+pf1[4]*pf2[4]+pf1[7]*pf2[7]; - pfres2[5] = pf1[1]*pf2[2]+pf1[4]*pf2[5]+pf1[7]*pf2[8]; - - pfres2[6] = pf1[2]*pf2[0]+pf1[5]*pf2[3]+pf1[8]*pf2[6]; - pfres2[7] = pf1[2]*pf2[1]+pf1[5]*pf2[4]+pf1[8]*pf2[7]; - pfres2[8] = pf1[2]*pf2[2]+pf1[5]*pf2[5]+pf1[8]*pf2[8]; - - if( pfres2 != pfres ) memcpy(pfres, pfres2, 9*sizeof(T)); - - return pfres; -} - -template -inline T* _multtrans4(T* pfres, const T* pf1, const T* pf2) -{ - T* pfres2; - if( pfres == pf1 ) pfres2 = (T*)alloca(16 * sizeof(T)); - else pfres2 = pfres; - - for(int i = 0; i < 4; ++i) { - for(int j = 0; j < 4; ++j) { - pfres[4*i+j] = pf1[i] * pf2[j] + pf1[i+4] * pf2[j+4] + pf1[i+8] * pf2[j+8] + pf1[i+12] * pf2[j+12]; - } - } - - return pfres; -} - -inline dReal* multtrans3(dReal* pfres, const dReal* pf1, const dReal* pf2) { return _multtrans3(pfres, pf1, pf2); } -inline double* multtrans3(double* pfres, const double* pf1, const double* pf2) { return _multtrans3(pfres, pf1, pf2); } -inline dReal* multtrans4(dReal* pfres, const dReal* pf1, const dReal* pf2) { return _multtrans4(pfres, pf1, pf2); } -inline double* multtrans4(double* pfres, const double* pf1, const double* pf2) { return _multtrans4(pfres, pf1, pf2); } - -// stride is in T -template inline T* _inv3(const T* pf, T* pfres, int stride) -{ - T* pfres2; - if( pfres == pf ) pfres2 = (T*)alloca(3 * stride * sizeof(T)); - else pfres2 = pfres; - - // inverse = C^t / det(pf) where C is the matrix of coefficients - - // calc C^t - pfres2[0*stride + 0] = pf[1*stride + 1] * pf[2*stride + 2] - pf[1*stride + 2] * pf[2*stride + 1]; - pfres2[0*stride + 1] = pf[0*stride + 2] * pf[2*stride + 1] - pf[0*stride + 1] * pf[2*stride + 2]; - pfres2[0*stride + 2] = pf[0*stride + 1] * pf[1*stride + 2] - pf[0*stride + 2] * pf[1*stride + 1]; - pfres2[1*stride + 0] = pf[1*stride + 2] * pf[2*stride + 0] - pf[1*stride + 0] * pf[2*stride + 2]; - pfres2[1*stride + 1] = pf[0*stride + 0] * pf[2*stride + 2] - pf[0*stride + 2] * pf[2*stride + 0]; - pfres2[1*stride + 2] = pf[0*stride + 2] * pf[1*stride + 0] - pf[0*stride + 0] * pf[1*stride + 2]; - pfres2[2*stride + 0] = pf[1*stride + 0] * pf[2*stride + 1] - pf[1*stride + 1] * pf[2*stride + 0]; - pfres2[2*stride + 1] = pf[0*stride + 1] * pf[2*stride + 0] - pf[0*stride + 0] * pf[2*stride + 1]; - pfres2[2*stride + 2] = pf[0*stride + 0] * pf[1*stride + 1] - pf[0*stride + 1] * pf[1*stride + 0]; - - T fdet = pf[0*stride + 2] * pfres2[2*stride + 0] + pf[1*stride + 2] * pfres2[2*stride + 1] + - pf[2*stride + 2] * pfres2[2*stride + 2]; - - if( fabs(fdet) < 1e-6 ) return NULL; - - fdet = 1 / fdet; - //if( pfdet != NULL ) *pfdet = fdet; - - if( pfres != pf ) { - pfres[0*stride+0] *= fdet; pfres[0*stride+1] *= fdet; pfres[0*stride+2] *= fdet; - pfres[1*stride+0] *= fdet; pfres[1*stride+1] *= fdet; pfres[1*stride+2] *= fdet; - pfres[2*stride+0] *= fdet; pfres[2*stride+1] *= fdet; pfres[2*stride+2] *= fdet; - return pfres; - } - - pfres[0*stride+0] = pfres2[0*stride+0] * fdet; - pfres[0*stride+1] = pfres2[0*stride+1] * fdet; - pfres[0*stride+2] = pfres2[0*stride+2] * fdet; - pfres[1*stride+0] = pfres2[1*stride+0] * fdet; - pfres[1*stride+1] = pfres2[1*stride+1] * fdet; - pfres[1*stride+2] = pfres2[1*stride+2] * fdet; - pfres[2*stride+0] = pfres2[2*stride+0] * fdet; - pfres[2*stride+1] = pfres2[2*stride+1] * fdet; - pfres[2*stride+2] = pfres2[2*stride+2] * fdet; - return pfres; -} - -inline dReal* inv3(const dReal* pf, dReal* pfres, int stride) { return _inv3(pf, pfres, stride); } - -// inverse if 92 mults and 39 adds -template inline T* _inv4(const T* pf, T* pfres) -{ - T* pfres2; - if( pfres == pf ) pfres2 = (T*)alloca(16 * sizeof(T)); - else pfres2 = pfres; - - // inverse = C^t / det(pf) where C is the matrix of coefficients - - // calc C^t - - // determinants of all possibel 2x2 submatrices formed by last two rows - T fd0, fd1, fd2; - T f1, f2, f3; - fd0 = pf[2*4 + 0] * pf[3*4 + 1] - pf[2*4 + 1] * pf[3*4 + 0]; - fd1 = pf[2*4 + 1] * pf[3*4 + 2] - pf[2*4 + 2] * pf[3*4 + 1]; - fd2 = pf[2*4 + 2] * pf[3*4 + 3] - pf[2*4 + 3] * pf[3*4 + 2]; - - f1 = pf[2*4 + 1] * pf[3*4 + 3] - pf[2*4 + 3] * pf[3*4 + 1]; - f2 = pf[2*4 + 0] * pf[3*4 + 3] - pf[2*4 + 3] * pf[3*4 + 0]; - f3 = pf[2*4 + 0] * pf[3*4 + 2] - pf[2*4 + 2] * pf[3*4 + 0]; - - pfres2[0*4 + 0] = pf[1*4 + 1] * fd2 - pf[1*4 + 2] * f1 + pf[1*4 + 3] * fd1; - pfres2[0*4 + 1] = -(pf[0*4 + 1] * fd2 - pf[0*4 + 2] * f1 + pf[0*4 + 3] * fd1); - - pfres2[1*4 + 0] = -(pf[1*4 + 0] * fd2 - pf[1*4 + 2] * f2 + pf[1*4 + 3] * f3); - pfres2[1*4 + 1] = pf[0*4 + 0] * fd2 - pf[0*4 + 2] * f2 + pf[0*4 + 3] * f3; - - pfres2[2*4 + 0] = pf[1*4 + 0] * f1 - pf[1*4 + 1] * f2 + pf[1*4 + 3] * fd0; - pfres2[2*4 + 1] = -(pf[0*4 + 0] * f1 - pf[0*4 + 1] * f2 + pf[0*4 + 3] * fd0); - - pfres2[3*4 + 0] = -(pf[1*4 + 0] * fd1 - pf[1*4 + 1] * f3 + pf[1*4 + 2] * fd0); - pfres2[3*4 + 1] = pf[0*4 + 0] * fd1 - pf[0*4 + 1] * f3 + pf[0*4 + 2] * fd0; - - // determinants of first 2 rows of 4x4 matrix - fd0 = pf[0*4 + 0] * pf[1*4 + 1] - pf[0*4 + 1] * pf[1*4 + 0]; - fd1 = pf[0*4 + 1] * pf[1*4 + 2] - pf[0*4 + 2] * pf[1*4 + 1]; - fd2 = pf[0*4 + 2] * pf[1*4 + 3] - pf[0*4 + 3] * pf[1*4 + 2]; - - f1 = pf[0*4 + 1] * pf[1*4 + 3] - pf[0*4 + 3] * pf[1*4 + 1]; - f2 = pf[0*4 + 0] * pf[1*4 + 3] - pf[0*4 + 3] * pf[1*4 + 0]; - f3 = pf[0*4 + 0] * pf[1*4 + 2] - pf[0*4 + 2] * pf[1*4 + 0]; - - pfres2[0*4 + 2] = pf[3*4 + 1] * fd2 - pf[3*4 + 2] * f1 + pf[3*4 + 3] * fd1; - pfres2[0*4 + 3] = -(pf[2*4 + 1] * fd2 - pf[2*4 + 2] * f1 + pf[2*4 + 3] * fd1); - - pfres2[1*4 + 2] = -(pf[3*4 + 0] * fd2 - pf[3*4 + 2] * f2 + pf[3*4 + 3] * f3); - pfres2[1*4 + 3] = pf[2*4 + 0] * fd2 - pf[2*4 + 2] * f2 + pf[2*4 + 3] * f3; - - pfres2[2*4 + 2] = pf[3*4 + 0] * f1 - pf[3*4 + 1] * f2 + pf[3*4 + 3] * fd0; - pfres2[2*4 + 3] = -(pf[2*4 + 0] * f1 - pf[2*4 + 1] * f2 + pf[2*4 + 3] * fd0); - - pfres2[3*4 + 2] = -(pf[3*4 + 0] * fd1 - pf[3*4 + 1] * f3 + pf[3*4 + 2] * fd0); - pfres2[3*4 + 3] = pf[2*4 + 0] * fd1 - pf[2*4 + 1] * f3 + pf[2*4 + 2] * fd0; - - T fdet = pf[0*4 + 3] * pfres2[3*4 + 0] + pf[1*4 + 3] * pfres2[3*4 + 1] + - pf[2*4 + 3] * pfres2[3*4 + 2] + pf[3*4 + 3] * pfres2[3*4 + 3]; - - if( fabs(fdet) < 1e-6) return NULL; - - fdet = 1 / fdet; - //if( pfdet != NULL ) *pfdet = fdet; - - if( pfres2 == pfres ) { - mult(pfres, fdet, 16); - return pfres; - } - - int i = 0; - while(i < 16) { - pfres[i] = pfres2[i] * fdet; - ++i; - } - - return pfres; -} - -inline dReal* inv4(const dReal* pf, dReal* pfres) { return _inv4(pf, pfres); } - -template inline T* _transpose3(const T* pf, T* pfres) -{ - assert( pf != NULL && pfres != NULL ); - - if( pf == pfres ) { - rswap(pfres[1], pfres[3]); - rswap(pfres[2], pfres[6]); - rswap(pfres[5], pfres[7]); - return pfres; - } - - pfres[0] = pf[0]; pfres[1] = pf[3]; pfres[2] = pf[6]; - pfres[3] = pf[1]; pfres[4] = pf[4]; pfres[5] = pf[7]; - pfres[6] = pf[2]; pfres[7] = pf[5]; pfres[8] = pf[8]; - - return pfres; -} - -inline dReal* transpose3(const dReal* pf, dReal* pfres) { return _transpose3(pf, pfres); } -inline double* transpose3(const double* pf, double* pfres) { return _transpose3(pf, pfres); } - -template inline T* _transpose4(const T* pf, T* pfres) -{ - assert( pf != NULL && pfres != NULL ); - - if( pf == pfres ) { - rswap(pfres[1], pfres[4]); - rswap(pfres[2], pfres[8]); - rswap(pfres[3], pfres[12]); - rswap(pfres[6], pfres[9]); - rswap(pfres[7], pfres[13]); - rswap(pfres[11], pfres[15]); - return pfres; - } - - pfres[0] = pf[0]; pfres[1] = pf[4]; pfres[2] = pf[8]; pfres[3] = pf[12]; - pfres[4] = pf[1]; pfres[5] = pf[5]; pfres[6] = pf[9]; pfres[7] = pf[13]; - pfres[8] = pf[2]; pfres[9] = pf[6]; pfres[10] = pf[10]; pfres[11] = pf[14]; - pfres[12] = pf[3]; pfres[13] = pf[7]; pfres[14] = pf[11]; pfres[15] = pf[15]; - return pfres; -} - -inline dReal* transpose4(const dReal* pf, dReal* pfres) { return _transpose4(pf, pfres); } -inline double* transpose4(const double* pf, double* pfres) { return _transpose4(pf, pfres); } - -inline dReal dot2(const dReal* pf1, const dReal* pf2) -{ - assert( pf1 != NULL && pf2 != NULL ); - return pf1[0]*pf2[0] + pf1[1]*pf2[1]; -} - -inline dReal dot3(const dReal* pf1, const dReal* pf2) -{ - assert( pf1 != NULL && pf2 != NULL ); - return pf1[0]*pf2[0] + pf1[1]*pf2[1] + pf1[2]*pf2[2]; -} - -inline dReal dot4(const dReal* pf1, const dReal* pf2) -{ - assert( pf1 != NULL && pf2 != NULL ); - return pf1[0]*pf2[0] + pf1[1]*pf2[1] + pf1[2]*pf2[2] + pf1[3] * pf2[3]; -} - -inline dReal lengthsqr2(const dReal* pf) -{ - assert( pf != NULL ); - return pf[0] * pf[0] + pf[1] * pf[1]; -} - -inline dReal lengthsqr3(const dReal* pf) -{ - assert( pf != NULL ); - return pf[0] * pf[0] + pf[1] * pf[1] + pf[2] * pf[2]; -} - -inline dReal lengthsqr4(const dReal* pf) -{ - assert( pf != NULL ); - return pf[0] * pf[0] + pf[1] * pf[1] + pf[2] * pf[2] + pf[3] * pf[3]; -} - -inline dReal* normalize2(dReal* pfout, const dReal* pf) -{ - assert(pf != NULL); - - dReal f = pf[0]*pf[0] + pf[1]*pf[1]; - f = 1.0f / sqrtf(f); - pfout[0] = pf[0] * f; - pfout[1] = pf[1] * f; - - return pfout; -} - -inline dReal* normalize3(dReal* pfout, const dReal* pf) -{ - assert(pf != NULL); - - dReal f = pf[0]*pf[0] + pf[1]*pf[1] + pf[2]*pf[2]; - - f = 1.0f / sqrtf(f); - pfout[0] = pf[0] * f; - pfout[1] = pf[1] * f; - pfout[2] = pf[2] * f; - - return pfout; -} - -inline dReal* normalize4(dReal* pfout, const dReal* pf) -{ - assert(pf != NULL); - - dReal f = pf[0]*pf[0] + pf[1]*pf[1] + pf[2]*pf[2] + pf[3]*pf[3]; - - f = 1.0f / sqrtf(f); - pfout[0] = pf[0] * f; - pfout[1] = pf[1] * f; - pfout[2] = pf[2] * f; - pfout[3] = pf[3] * f; - - return pfout; -} - -inline dReal* cross3(dReal* pfout, const dReal* pf1, const dReal* pf2) -{ - assert( pfout != NULL && pf1 != NULL && pf2 != NULL ); - - dReal temp[3]; - temp[0] = pf1[1] * pf2[2] - pf1[2] * pf2[1]; - temp[1] = pf1[2] * pf2[0] - pf1[0] * pf2[2]; - temp[2] = pf1[0] * pf2[1] - pf1[1] * pf2[0]; - - pfout[0] = temp[0]; pfout[1] = temp[1]; pfout[2] = temp[2]; - return pfout; -} - -template inline void mult(T* pf, T fa, int r) -{ - assert( pf != NULL ); - - while(r > 0) { - --r; - pf[r] *= fa; - } -} - -template -inline T* mult(T* pf1, R* pf2, int r1, int c1, int c2, S* pfres, bool badd) -{ - assert( pf1 != NULL && pf2 != NULL && pfres != NULL); - int j, k; - - if( !badd ) memset(pfres, 0, sizeof(S) * r1 * c2); - - while(r1 > 0) { - --r1; - - j = 0; - while(j < c2) { - k = 0; - while(k < c1) { - pfres[j] += pf1[k] * pf2[k*c2 + j]; - ++k; - } - ++j; - } - - pf1 += c1; - pfres += c2; - } - - return pfres; -} - -template -inline T* multtrans(T* pf1, R* pf2, int r1, int c1, int c2, S* pfres, bool badd) -{ - assert( pf1 != NULL && pf2 != NULL && pfres != NULL); - int i, j, k; - - if( !badd ) memset(pfres, 0, sizeof(S) * c1 * c2); - - i = 0; - while(i < c1) { - - j = 0; - while(j < c2) { - - k = 0; - while(k < r1) { - pfres[j] += pf1[k*c1] * pf2[k*c2 + j]; - ++k; - } - ++j; - } - - pfres += c2; - ++pf1; - - ++i; - } - - return pfres; -} - -template -inline T* multtrans_to2(T* pf1, R* pf2, int r1, int c1, int r2, S* pfres, bool badd) -{ - assert( pf1 != NULL && pf2 != NULL && pfres != NULL); - int j, k; - - if( !badd ) memset(pfres, 0, sizeof(S) * r1 * r2); - - while(r1 > 0) { - --r1; - - j = 0; - while(j < r2) { - k = 0; - while(k < c1) { - pfres[j] += pf1[k] * pf2[j*c1 + k]; - ++k; - } - ++j; - } - - pf1 += c1; - pfres += r2; - } - - return pfres; -} - -template inline T* multto1(T* pf1, T* pf2, int r, int c, T* pftemp) -{ - assert( pf1 != NULL && pf2 != NULL ); - - int j, k; - bool bdel = false; - - if( pftemp == NULL ) { - pftemp = new T[c]; - bdel = true; - } - - while(r > 0) { - --r; - - j = 0; - while(j < c) { - - pftemp[j] = 0.0; - - k = 0; - while(k < c) { - pftemp[j] += pf1[k] * pf2[k*c + j]; - ++k; - } - ++j; - } - - memcpy(pf1, pftemp, c * sizeof(T)); - pf1 += c; - } - - if( bdel ) delete[] pftemp; - - return pf1; -} - -template inline T* multto2(T* pf1, S* pf2, int r2, int c2, S* pftemp) -{ - assert( pf1 != NULL && pf2 != NULL ); - - int i, j, k; - bool bdel = false; - - if( pftemp == NULL ) { - pftemp = new S[r2]; - bdel = true; - } - - // do columns first - j = 0; - while(j < c2) { - i = 0; - while(i < r2) { - - pftemp[i] = 0.0; - - k = 0; - while(k < r2) { - pftemp[i] += pf1[i*r2 + k] * pf2[k*c2 + j]; - ++k; - } - ++i; - } - - i = 0; - while(i < r2) { - *(pf2+i*c2+j) = pftemp[i]; - ++i; - } - - ++j; - } - - if( bdel ) delete[] pftemp; - - return pf1; -} - -template inline void add(T* pf1, T* pf2, int r) -{ - assert( pf1 != NULL && pf2 != NULL); - - while(r > 0) { - --r; - pf1[r] += pf2[r]; - } -} - -template inline void sub(T* pf1, T* pf2, int r) -{ - assert( pf1 != NULL && pf2 != NULL); - - while(r > 0) { - --r; - pf1[r] -= pf2[r]; - } -} - -template inline T normsqr(T* pf1, int r) -{ - assert( pf1 != NULL ); - - T d = 0.0; - while(r > 0) { - --r; - d += pf1[r] * pf1[r]; - } - - return d; -} - -template inline T lengthsqr(T* pf1, T* pf2, int length) -{ - T d = 0; - while(length > 0) { - --length; - d += sqr(pf1[length] - pf2[length]); - } - - return d; -} - -template inline T dot(T* pf1, T* pf2, int length) -{ - T d = 0; - while(length > 0) { - --length; - d += pf1[length] * pf2[length]; - } - - return d; -} - -template inline T sum(T* pf, int length) -{ - T d = 0; - while(length > 0) { - --length; - d += pf[length]; - } - - return d; -} - -template inline bool inv2(T* pf, T* pfres) -{ - T fdet = pf[0] * pf[3] - pf[1] * pf[2]; - - if( fabs(fdet) < 1e-16 ) return false; - - fdet = 1 / fdet; - //if( pfdet != NULL ) *pfdet = fdet; - - if( pfres != pf ) { - pfres[0] = fdet * pf[3]; pfres[1] = -fdet * pf[1]; - pfres[2] = -fdet * pf[2]; pfres[3] = fdet * pf[0]; - return true; - } - - dReal ftemp = pf[0]; - pfres[0] = pf[3] * fdet; - pfres[1] *= -fdet; - pfres[2] *= -fdet; - pfres[3] = ftemp * pf[0]; - - return true; -} - -#endif +#ifndef ZEROGS_MATH_H +#define ZEROGS_MATH_H + +#ifndef _WIN32 +#include +#endif + +#include +#include + +#ifndef PI +#define PI ((dReal)3.141592654) +#endif + +#define rswap(x, y) *(int*)&(x) ^= *(int*)&(y) ^= *(int*)&(x) ^= *(int*)&(y); + +template inline T RAD_2_DEG(T radians) { return (radians * (T)57.29577951); } + +class Transform; +class TransformMatrix; + +typedef float dReal; +typedef dReal dMatrix3[3*4]; + +inline dReal* normalize3(dReal* pfout, const dReal* pf); +inline dReal* normalize4(dReal* pfout, const dReal* pf); +inline dReal* cross3(dReal* pfout, const dReal* pf1, const dReal* pf2); + +// multiplies 3x3 matrices +inline dReal* mult3(dReal* pfres, const dReal* pf1, const dReal* pf2); +inline double* mult3(double* pfres, const double* pf1, const double* pf2); + +inline dReal* inv3(const dReal* pf, dReal* pfres, int stride); +inline dReal* inv4(const dReal* pf, dReal* pfres); + +// class used for 3 and 4 dim vectors and quaternions +// It is better to use this for a 3 dim vector because it is 16byte aligned and SIMD instructions can be used +class Vector +{ +public: + dReal x, y, z, w; + + Vector() : x(0), y(0), z(0), w(0) {} + Vector(dReal x, dReal y, dReal z) : x(x), y(y), z(z), w(0) {} + Vector(dReal x, dReal y, dReal z, dReal w) : x(x), y(y), z(z), w(w) {} + Vector(const Vector &vec) : x(vec.x), y(vec.y), z(vec.z), w(vec.w) {} + Vector(const dReal* pf) { assert(pf != NULL); x = pf[0]; y = pf[1]; z = pf[2]; w = 0; } + + dReal operator[](int i) const { return (&x)[i]; } + dReal& operator[](int i) { return (&x)[i]; } + + // casting operators + operator dReal* () { return &x; } + operator const dReal* () const { return (const dReal*)&x; } + + // SCALAR FUNCTIONS + inline dReal dot(const Vector &v) const { return x*v.x + y*v.y + z*v.z + w*v.w; } + inline void normalize() { normalize4(&x, &x); } + + inline void Set3(const float* pvals) { x = pvals[0]; y = pvals[1]; z = pvals[2]; } + inline void Set4(const float* pvals) { x = pvals[0]; y = pvals[1]; z = pvals[2]; w = pvals[3]; } + + // 3 dim cross product, w is not touched + /// this = this x v + inline void Cross(const Vector &v) { cross3(&x, &x, v); } + + /// this = u x v + inline void Cross(const Vector &u, const Vector &v) { cross3(&x, u, v); } + + inline Vector operator-() const { Vector v; v.x = -x; v.y = -y; v.z = -z; v.w = -w; return v; } + inline Vector operator+(const Vector &r) const { Vector v; v.x = x+r.x; v.y = y+r.y; v.z = z+r.z; v.w = w+r.w; return v; } + inline Vector operator-(const Vector &r) const { Vector v; v.x = x-r.x; v.y = y-r.y; v.z = z-r.z; v.w = w-r.w; return v; } + inline Vector operator*(const Vector &r) const { Vector v; v.x = r.x*x; v.y = r.y*y; v.z = r.z*z; v.w = r.w*w; return v; } + inline Vector operator*(dReal k) const { Vector v; v.x = k*x; v.y = k*y; v.z = k*z; v.w = k*w; return v; } + + inline Vector& operator += (const Vector& r) { x += r.x; y += r.y; z += r.z; w += r.w; return *this; } + inline Vector& operator -= (const Vector& r) { x -= r.x; y -= r.y; z -= r.z; w -= r.w; return *this; } + inline Vector& operator *= (const Vector& r) { x *= r.x; y *= r.y; z *= r.z; w *= r.w; return *this; } + + inline Vector& operator *= (const dReal k) { x *= k; y *= k; z *= k; w *= k; return *this; } + inline Vector& operator /= (const dReal _k) { dReal k=1/_k; x *= k; y *= k; z *= k; w *= k; return *this; } + + friend Vector operator* (float f, const Vector& v); + //friend ostream& operator<<(ostream& O, const Vector& v); + //friend istream& operator>>(istream& I, Vector& v); +}; + +inline Vector operator* (float f, const Vector& left) +{ + Vector v; + v.x = f * left.x; + v.y = f * left.y; + v.z = f * left.z; + return v; +} + +struct AABB +{ + Vector pos, extents; +}; + +struct OBB +{ + Vector right, up, dir, pos, extents; +}; + +struct TRIANGLE +{ + TRIANGLE() {} + TRIANGLE(const Vector& v1, const Vector& v2, const Vector& v3) : v1(v1), v2(v2), v3(v3) {} + ~TRIANGLE() {} + + Vector v1, v2, v3; //!< the vertices of the triangle + + const Vector& operator[](int i) const { return (&v1)[i]; } + Vector& operator[](int i) { return (&v1)[i]; } + + /// assumes CCW ordering of vertices + inline Vector ComputeNormal() { + Vector normal; + cross3(normal, v2-v1, v3-v1); + return normal; + } +}; + +// Routines made for 3D graphics that deal with 3 or 4 dim algebra structures +// Functions with postfix 3 are for 3x3 operations, etc + +// all fns return pfout on success or NULL on failure +// results and arguments can share pointers + + +// multiplies 4x4 matrices +inline dReal* mult4(dReal* pfres, const dReal* pf1, const dReal* pf2); +inline double* mult4(double* pfres, const double* pf1, const double* pf2); + +// pf1^T * pf2 +inline dReal* multtrans3(dReal* pfres, const dReal* pf1, const dReal* pf2); +inline double* multtrans3(double* pfres, const double* pf1, const double* pf2); +inline dReal* multtrans4(dReal* pfres, const dReal* pf1, const dReal* pf2); +inline double* multtrans4(double* pfres, const double* pf1, const double* pf2); + +inline dReal* transpose3(const dReal* pf, dReal* pfres); +inline double* transpose3(const double* pf, double* pfres); +inline dReal* transpose4(const dReal* pf, dReal* pfres); +inline double* transpose4(const double* pf, double* pfres); + +inline dReal dot2(const dReal* pf1, const dReal* pf2); +inline dReal dot3(const dReal* pf1, const dReal* pf2); +inline dReal dot4(const dReal* pf1, const dReal* pf2); + +inline dReal lengthsqr2(const dReal* pf); +inline dReal lengthsqr3(const dReal* pf); +inline dReal lengthsqr4(const dReal* pf); + +inline dReal* normalize2(dReal* pfout, const dReal* pf); +inline dReal* normalize3(dReal* pfout, const dReal* pf); +inline dReal* normalize4(dReal* pfout, const dReal* pf); + +//// +// More complex ops that deal with arbitrary matrices // +//// + +// extract eigen values and vectors from a 2x2 matrix and returns true if all values are real +// returned eigen vectors are normalized +inline bool eig2(const dReal* pfmat, dReal* peigs, dReal& fv1x, dReal& fv1y, dReal& fv2x, dReal& fv2y); + +// Simple routines for linear algebra algorithms // +int CubicRoots (double c0, double c1, double c2, double *r0, double *r1, double *r2); +bool QLAlgorithm3 (dReal* m_aafEntry, dReal* afDiag, dReal* afSubDiag); + +void EigenSymmetric3(dReal* fCovariance, dReal* eval, dReal* fAxes); + +void GetCovarBasisVectors(dReal fCovariance[3][3], Vector* vRight, Vector* vUp, Vector* vDir); + +// first root returned is always >= second, roots are defined if the quadratic doesn't have real solutions +void QuadraticSolver(dReal* pfQuadratic, dReal* pfRoots); + +int insideQuadrilateral(const Vector* p0,const Vector* p1, const Vector* p2,const Vector* p3); +int insideTriangle(const Vector* p0, const Vector* p1, const Vector* p2); + +// multiplies a matrix by a scalar +template inline void mult(T* pf, T fa, int r); + +// multiplies a r1xc1 by c1xc2 matrix into pfres, if badd is true adds the result to pfres +// does not handle cases where pfres is equal to pf1 or pf2, use multtox for those cases +template +inline T* mult(T* pf1, R* pf2, int r1, int c1, int c2, S* pfres, bool badd = false); + +// pf1 is transposed before mult +// rows of pf2 must equal rows of pf1 +// pfres will be c1xc2 matrix +template +inline T* multtrans(T* pf1, R* pf2, int r1, int c1, int c2, S* pfres, bool badd = false); + +// pf2 is transposed before mult +// the columns of both matrices must be the same and equal to c1 +// r2 is the number of rows in pf2 +// pfres must be an r1xr2 matrix +template +inline T* multtrans_to2(T* pf1, R* pf2, int r1, int c1, int r2, S* pfres, bool badd = false); + +// multiplies rxc matrix pf1 and cxc matrix pf2 and stores the result in pf1, +// the function needs a temporary buffer the size of c doubles, if pftemp == NULL, +// the function will allocate the necessary memory, otherwise pftemp should be big +// enough to store all the entries +template inline T* multto1(T* pf1, T* pf2, int r1, int c1, T* pftemp = NULL); + +// same as multto1 except stores the result in pf2, pf1 has to be an r2xr2 matrix +// pftemp must be of size r2 if not NULL +template inline T* multto2(T* pf1, S* pf2, int r2, int c2, S* pftemp = NULL); + +// add pf1 + pf2 and store in pf1 +template inline void sub(T* pf1, T* pf2, int r); +template inline T normsqr(T* pf1, int r); +template inline T lengthsqr(T* pf1, T* pf2, int length); +template inline T dot(T* pf1, T* pf2, int length); + +template inline T sum(T* pf, int length); + +// takes the inverse of the 3x3 matrix pf and stores it into pfres, returns true if matrix is invertible +template inline bool inv2(T* pf, T* pfres); + +/////////////////////// +// Function Definitions +/////////////////////// +bool eig2(const dReal* pfmat, dReal* peigs, dReal& fv1x, dReal& fv1y, dReal& fv2x, dReal& fv2y) +{ + // x^2 + bx + c + dReal a, b, c, d; + b = -(pfmat[0] + pfmat[3]); + c = pfmat[0] * pfmat[3] - pfmat[1] * pfmat[2]; + d = b * b - 4.0f * c + 1e-16f; + + if( d < 0 ) return false; + if( d < 1e-16f ) { + a = -0.5f * b; + peigs[0] = a; peigs[1] = a; + fv1x = pfmat[1]; fv1y = a - pfmat[0]; + c = 1 / sqrtf(fv1x*fv1x + fv1y*fv1y); + fv1x *= c; fv1y *= c; + fv2x = -fv1y; fv2y = fv1x; + return true; + } + + // two roots + d = sqrtf(d); + a = -0.5f * (b + d); + peigs[0] = a; + fv1x = pfmat[1]; fv1y = a-pfmat[0]; + c = 1 / sqrtf(fv1x*fv1x + fv1y*fv1y); + fv1x *= c; fv1y *= c; + + a += d; + peigs[1] = a; + fv2x = pfmat[1]; fv2y = a-pfmat[0]; + c = 1 / sqrtf(fv2x*fv2x + fv2y*fv2y); + fv2x *= c; fv2y *= c; + return true; +} + +//#ifndef TI_USING_IPP + +// Functions that are replacable by ipp library funcs +template inline T* _mult3(T* pfres, const T* pf1, const T* pf2) +{ + assert( pf1 != NULL && pf2 != NULL && pfres != NULL ); + + T* pfres2; + if( pfres == pf1 || pfres == pf2 ) pfres2 = (T*)alloca(9 * sizeof(T)); + else pfres2 = pfres; + + pfres2[0*4+0] = pf1[0*4+0]*pf2[0*4+0]+pf1[0*4+1]*pf2[1*4+0]+pf1[0*4+2]*pf2[2*4+0]; + pfres2[0*4+1] = pf1[0*4+0]*pf2[0*4+1]+pf1[0*4+1]*pf2[1*4+1]+pf1[0*4+2]*pf2[2*4+1]; + pfres2[0*4+2] = pf1[0*4+0]*pf2[0*4+2]+pf1[0*4+1]*pf2[1*4+2]+pf1[0*4+2]*pf2[2*4+2]; + + pfres2[1*4+0] = pf1[1*4+0]*pf2[0*4+0]+pf1[1*4+1]*pf2[1*4+0]+pf1[1*4+2]*pf2[2*4+0]; + pfres2[1*4+1] = pf1[1*4+0]*pf2[0*4+1]+pf1[1*4+1]*pf2[1*4+1]+pf1[1*4+2]*pf2[2*4+1]; + pfres2[1*4+2] = pf1[1*4+0]*pf2[0*4+2]+pf1[1*4+1]*pf2[1*4+2]+pf1[1*4+2]*pf2[2*4+2]; + + pfres2[2*4+0] = pf1[2*4+0]*pf2[0*4+0]+pf1[2*4+1]*pf2[1*4+0]+pf1[2*4+2]*pf2[2*4+0]; + pfres2[2*4+1] = pf1[2*4+0]*pf2[0*4+1]+pf1[2*4+1]*pf2[1*4+1]+pf1[2*4+2]*pf2[2*4+1]; + pfres2[2*4+2] = pf1[2*4+0]*pf2[0*4+2]+pf1[2*4+1]*pf2[1*4+2]+pf1[2*4+2]*pf2[2*4+2]; + + if( pfres2 != pfres ) memcpy(pfres, pfres2, 9*sizeof(T)); + + return pfres; +} + +inline dReal* mult3(dReal* pfres, const dReal* pf1, const dReal* pf2) { return _mult3(pfres, pf1, pf2); } +inline double* mult3(double* pfres, const double* pf1, const double* pf2) { return _mult3(pfres, pf1, pf2); } + +template +inline T* _mult4(T* pfres, const T* p1, const T* p2) +{ + assert( pfres != NULL && p1 != NULL && p2 != NULL ); + + T* pfres2; + if( pfres == p1 || pfres == p2 ) pfres2 = (T*)alloca(16 * sizeof(T)); + else pfres2 = pfres; + + pfres2[0*4+0] = p1[0*4+0]*p2[0*4+0] + p1[0*4+1]*p2[1*4+0] + p1[0*4+2]*p2[2*4+0] + p1[0*4+3]*p2[3*4+0]; + pfres2[0*4+1] = p1[0*4+0]*p2[0*4+1] + p1[0*4+1]*p2[1*4+1] + p1[0*4+2]*p2[2*4+1] + p1[0*4+3]*p2[3*4+1]; + pfres2[0*4+2] = p1[0*4+0]*p2[0*4+2] + p1[0*4+1]*p2[1*4+2] + p1[0*4+2]*p2[2*4+2] + p1[0*4+3]*p2[3*4+2]; + pfres2[0*4+3] = p1[0*4+0]*p2[0*4+3] + p1[0*4+1]*p2[1*4+3] + p1[0*4+2]*p2[2*4+3] + p1[0*4+3]*p2[3*4+3]; + + pfres2[1*4+0] = p1[1*4+0]*p2[0*4+0] + p1[1*4+1]*p2[1*4+0] + p1[1*4+2]*p2[2*4+0] + p1[1*4+3]*p2[3*4+0]; + pfres2[1*4+1] = p1[1*4+0]*p2[0*4+1] + p1[1*4+1]*p2[1*4+1] + p1[1*4+2]*p2[2*4+1] + p1[1*4+3]*p2[3*4+1]; + pfres2[1*4+2] = p1[1*4+0]*p2[0*4+2] + p1[1*4+1]*p2[1*4+2] + p1[1*4+2]*p2[2*4+2] + p1[1*4+3]*p2[3*4+2]; + pfres2[1*4+3] = p1[1*4+0]*p2[0*4+3] + p1[1*4+1]*p2[1*4+3] + p1[1*4+2]*p2[2*4+3] + p1[1*4+3]*p2[3*4+3]; + + pfres2[2*4+0] = p1[2*4+0]*p2[0*4+0] + p1[2*4+1]*p2[1*4+0] + p1[2*4+2]*p2[2*4+0] + p1[2*4+3]*p2[3*4+0]; + pfres2[2*4+1] = p1[2*4+0]*p2[0*4+1] + p1[2*4+1]*p2[1*4+1] + p1[2*4+2]*p2[2*4+1] + p1[2*4+3]*p2[3*4+1]; + pfres2[2*4+2] = p1[2*4+0]*p2[0*4+2] + p1[2*4+1]*p2[1*4+2] + p1[2*4+2]*p2[2*4+2] + p1[2*4+3]*p2[3*4+2]; + pfres2[2*4+3] = p1[2*4+0]*p2[0*4+3] + p1[2*4+1]*p2[1*4+3] + p1[2*4+2]*p2[2*4+3] + p1[2*4+3]*p2[3*4+3]; + + pfres2[3*4+0] = p1[3*4+0]*p2[0*4+0] + p1[3*4+1]*p2[1*4+0] + p1[3*4+2]*p2[2*4+0] + p1[3*4+3]*p2[3*4+0]; + pfres2[3*4+1] = p1[3*4+0]*p2[0*4+1] + p1[3*4+1]*p2[1*4+1] + p1[3*4+2]*p2[2*4+1] + p1[3*4+3]*p2[3*4+1]; + pfres2[3*4+2] = p1[3*4+0]*p2[0*4+2] + p1[3*4+1]*p2[1*4+2] + p1[3*4+2]*p2[2*4+2] + p1[3*4+3]*p2[3*4+2]; + pfres2[3*4+3] = p1[3*4+0]*p2[0*4+3] + p1[3*4+1]*p2[1*4+3] + p1[3*4+2]*p2[2*4+3] + p1[3*4+3]*p2[3*4+3]; + + if( pfres != pfres2 ) memcpy(pfres, pfres2, sizeof(T)*16); + return pfres; +} + +inline dReal* mult4(dReal* pfres, const dReal* pf1, const dReal* pf2) { return _mult4(pfres, pf1, pf2); } +inline double* mult4(double* pfres, const double* pf1, const double* pf2) { return _mult4(pfres, pf1, pf2); } + +template +inline T* _multtrans3(T* pfres, const T* pf1, const T* pf2) +{ + T* pfres2; + if( pfres == pf1 ) pfres2 = (T*)alloca(9 * sizeof(T)); + else pfres2 = pfres; + + pfres2[0] = pf1[0]*pf2[0]+pf1[3]*pf2[3]+pf1[6]*pf2[6]; + pfres2[1] = pf1[0]*pf2[1]+pf1[3]*pf2[4]+pf1[6]*pf2[7]; + pfres2[2] = pf1[0]*pf2[2]+pf1[3]*pf2[5]+pf1[6]*pf2[8]; + + pfres2[3] = pf1[1]*pf2[0]+pf1[4]*pf2[3]+pf1[7]*pf2[6]; + pfres2[4] = pf1[1]*pf2[1]+pf1[4]*pf2[4]+pf1[7]*pf2[7]; + pfres2[5] = pf1[1]*pf2[2]+pf1[4]*pf2[5]+pf1[7]*pf2[8]; + + pfres2[6] = pf1[2]*pf2[0]+pf1[5]*pf2[3]+pf1[8]*pf2[6]; + pfres2[7] = pf1[2]*pf2[1]+pf1[5]*pf2[4]+pf1[8]*pf2[7]; + pfres2[8] = pf1[2]*pf2[2]+pf1[5]*pf2[5]+pf1[8]*pf2[8]; + + if( pfres2 != pfres ) memcpy(pfres, pfres2, 9*sizeof(T)); + + return pfres; +} + +template +inline T* _multtrans4(T* pfres, const T* pf1, const T* pf2) +{ + T* pfres2; + if( pfres == pf1 ) pfres2 = (T*)alloca(16 * sizeof(T)); + else pfres2 = pfres; + + for(int i = 0; i < 4; ++i) { + for(int j = 0; j < 4; ++j) { + pfres[4*i+j] = pf1[i] * pf2[j] + pf1[i+4] * pf2[j+4] + pf1[i+8] * pf2[j+8] + pf1[i+12] * pf2[j+12]; + } + } + + return pfres; +} + +inline dReal* multtrans3(dReal* pfres, const dReal* pf1, const dReal* pf2) { return _multtrans3(pfres, pf1, pf2); } +inline double* multtrans3(double* pfres, const double* pf1, const double* pf2) { return _multtrans3(pfres, pf1, pf2); } +inline dReal* multtrans4(dReal* pfres, const dReal* pf1, const dReal* pf2) { return _multtrans4(pfres, pf1, pf2); } +inline double* multtrans4(double* pfres, const double* pf1, const double* pf2) { return _multtrans4(pfres, pf1, pf2); } + +// stride is in T +template inline T* _inv3(const T* pf, T* pfres, int stride) +{ + T* pfres2; + if( pfres == pf ) pfres2 = (T*)alloca(3 * stride * sizeof(T)); + else pfres2 = pfres; + + // inverse = C^t / det(pf) where C is the matrix of coefficients + + // calc C^t + pfres2[0*stride + 0] = pf[1*stride + 1] * pf[2*stride + 2] - pf[1*stride + 2] * pf[2*stride + 1]; + pfres2[0*stride + 1] = pf[0*stride + 2] * pf[2*stride + 1] - pf[0*stride + 1] * pf[2*stride + 2]; + pfres2[0*stride + 2] = pf[0*stride + 1] * pf[1*stride + 2] - pf[0*stride + 2] * pf[1*stride + 1]; + pfres2[1*stride + 0] = pf[1*stride + 2] * pf[2*stride + 0] - pf[1*stride + 0] * pf[2*stride + 2]; + pfres2[1*stride + 1] = pf[0*stride + 0] * pf[2*stride + 2] - pf[0*stride + 2] * pf[2*stride + 0]; + pfres2[1*stride + 2] = pf[0*stride + 2] * pf[1*stride + 0] - pf[0*stride + 0] * pf[1*stride + 2]; + pfres2[2*stride + 0] = pf[1*stride + 0] * pf[2*stride + 1] - pf[1*stride + 1] * pf[2*stride + 0]; + pfres2[2*stride + 1] = pf[0*stride + 1] * pf[2*stride + 0] - pf[0*stride + 0] * pf[2*stride + 1]; + pfres2[2*stride + 2] = pf[0*stride + 0] * pf[1*stride + 1] - pf[0*stride + 1] * pf[1*stride + 0]; + + T fdet = pf[0*stride + 2] * pfres2[2*stride + 0] + pf[1*stride + 2] * pfres2[2*stride + 1] + + pf[2*stride + 2] * pfres2[2*stride + 2]; + + if( fabs(fdet) < 1e-6 ) return NULL; + + fdet = 1 / fdet; + //if( pfdet != NULL ) *pfdet = fdet; + + if( pfres != pf ) { + pfres[0*stride+0] *= fdet; pfres[0*stride+1] *= fdet; pfres[0*stride+2] *= fdet; + pfres[1*stride+0] *= fdet; pfres[1*stride+1] *= fdet; pfres[1*stride+2] *= fdet; + pfres[2*stride+0] *= fdet; pfres[2*stride+1] *= fdet; pfres[2*stride+2] *= fdet; + return pfres; + } + + pfres[0*stride+0] = pfres2[0*stride+0] * fdet; + pfres[0*stride+1] = pfres2[0*stride+1] * fdet; + pfres[0*stride+2] = pfres2[0*stride+2] * fdet; + pfres[1*stride+0] = pfres2[1*stride+0] * fdet; + pfres[1*stride+1] = pfres2[1*stride+1] * fdet; + pfres[1*stride+2] = pfres2[1*stride+2] * fdet; + pfres[2*stride+0] = pfres2[2*stride+0] * fdet; + pfres[2*stride+1] = pfres2[2*stride+1] * fdet; + pfres[2*stride+2] = pfres2[2*stride+2] * fdet; + return pfres; +} + +inline dReal* inv3(const dReal* pf, dReal* pfres, int stride) { return _inv3(pf, pfres, stride); } + +// inverse if 92 mults and 39 adds +template inline T* _inv4(const T* pf, T* pfres) +{ + T* pfres2; + if( pfres == pf ) pfres2 = (T*)alloca(16 * sizeof(T)); + else pfres2 = pfres; + + // inverse = C^t / det(pf) where C is the matrix of coefficients + + // calc C^t + + // determinants of all possibel 2x2 submatrices formed by last two rows + T fd0, fd1, fd2; + T f1, f2, f3; + fd0 = pf[2*4 + 0] * pf[3*4 + 1] - pf[2*4 + 1] * pf[3*4 + 0]; + fd1 = pf[2*4 + 1] * pf[3*4 + 2] - pf[2*4 + 2] * pf[3*4 + 1]; + fd2 = pf[2*4 + 2] * pf[3*4 + 3] - pf[2*4 + 3] * pf[3*4 + 2]; + + f1 = pf[2*4 + 1] * pf[3*4 + 3] - pf[2*4 + 3] * pf[3*4 + 1]; + f2 = pf[2*4 + 0] * pf[3*4 + 3] - pf[2*4 + 3] * pf[3*4 + 0]; + f3 = pf[2*4 + 0] * pf[3*4 + 2] - pf[2*4 + 2] * pf[3*4 + 0]; + + pfres2[0*4 + 0] = pf[1*4 + 1] * fd2 - pf[1*4 + 2] * f1 + pf[1*4 + 3] * fd1; + pfres2[0*4 + 1] = -(pf[0*4 + 1] * fd2 - pf[0*4 + 2] * f1 + pf[0*4 + 3] * fd1); + + pfres2[1*4 + 0] = -(pf[1*4 + 0] * fd2 - pf[1*4 + 2] * f2 + pf[1*4 + 3] * f3); + pfres2[1*4 + 1] = pf[0*4 + 0] * fd2 - pf[0*4 + 2] * f2 + pf[0*4 + 3] * f3; + + pfres2[2*4 + 0] = pf[1*4 + 0] * f1 - pf[1*4 + 1] * f2 + pf[1*4 + 3] * fd0; + pfres2[2*4 + 1] = -(pf[0*4 + 0] * f1 - pf[0*4 + 1] * f2 + pf[0*4 + 3] * fd0); + + pfres2[3*4 + 0] = -(pf[1*4 + 0] * fd1 - pf[1*4 + 1] * f3 + pf[1*4 + 2] * fd0); + pfres2[3*4 + 1] = pf[0*4 + 0] * fd1 - pf[0*4 + 1] * f3 + pf[0*4 + 2] * fd0; + + // determinants of first 2 rows of 4x4 matrix + fd0 = pf[0*4 + 0] * pf[1*4 + 1] - pf[0*4 + 1] * pf[1*4 + 0]; + fd1 = pf[0*4 + 1] * pf[1*4 + 2] - pf[0*4 + 2] * pf[1*4 + 1]; + fd2 = pf[0*4 + 2] * pf[1*4 + 3] - pf[0*4 + 3] * pf[1*4 + 2]; + + f1 = pf[0*4 + 1] * pf[1*4 + 3] - pf[0*4 + 3] * pf[1*4 + 1]; + f2 = pf[0*4 + 0] * pf[1*4 + 3] - pf[0*4 + 3] * pf[1*4 + 0]; + f3 = pf[0*4 + 0] * pf[1*4 + 2] - pf[0*4 + 2] * pf[1*4 + 0]; + + pfres2[0*4 + 2] = pf[3*4 + 1] * fd2 - pf[3*4 + 2] * f1 + pf[3*4 + 3] * fd1; + pfres2[0*4 + 3] = -(pf[2*4 + 1] * fd2 - pf[2*4 + 2] * f1 + pf[2*4 + 3] * fd1); + + pfres2[1*4 + 2] = -(pf[3*4 + 0] * fd2 - pf[3*4 + 2] * f2 + pf[3*4 + 3] * f3); + pfres2[1*4 + 3] = pf[2*4 + 0] * fd2 - pf[2*4 + 2] * f2 + pf[2*4 + 3] * f3; + + pfres2[2*4 + 2] = pf[3*4 + 0] * f1 - pf[3*4 + 1] * f2 + pf[3*4 + 3] * fd0; + pfres2[2*4 + 3] = -(pf[2*4 + 0] * f1 - pf[2*4 + 1] * f2 + pf[2*4 + 3] * fd0); + + pfres2[3*4 + 2] = -(pf[3*4 + 0] * fd1 - pf[3*4 + 1] * f3 + pf[3*4 + 2] * fd0); + pfres2[3*4 + 3] = pf[2*4 + 0] * fd1 - pf[2*4 + 1] * f3 + pf[2*4 + 2] * fd0; + + T fdet = pf[0*4 + 3] * pfres2[3*4 + 0] + pf[1*4 + 3] * pfres2[3*4 + 1] + + pf[2*4 + 3] * pfres2[3*4 + 2] + pf[3*4 + 3] * pfres2[3*4 + 3]; + + if( fabs(fdet) < 1e-6) return NULL; + + fdet = 1 / fdet; + //if( pfdet != NULL ) *pfdet = fdet; + + if( pfres2 == pfres ) { + mult(pfres, fdet, 16); + return pfres; + } + + int i = 0; + while(i < 16) { + pfres[i] = pfres2[i] * fdet; + ++i; + } + + return pfres; +} + +inline dReal* inv4(const dReal* pf, dReal* pfres) { return _inv4(pf, pfres); } + +template inline T* _transpose3(const T* pf, T* pfres) +{ + assert( pf != NULL && pfres != NULL ); + + if( pf == pfres ) { + rswap(pfres[1], pfres[3]); + rswap(pfres[2], pfres[6]); + rswap(pfres[5], pfres[7]); + return pfres; + } + + pfres[0] = pf[0]; pfres[1] = pf[3]; pfres[2] = pf[6]; + pfres[3] = pf[1]; pfres[4] = pf[4]; pfres[5] = pf[7]; + pfres[6] = pf[2]; pfres[7] = pf[5]; pfres[8] = pf[8]; + + return pfres; +} + +inline dReal* transpose3(const dReal* pf, dReal* pfres) { return _transpose3(pf, pfres); } +inline double* transpose3(const double* pf, double* pfres) { return _transpose3(pf, pfres); } + +template inline T* _transpose4(const T* pf, T* pfres) +{ + assert( pf != NULL && pfres != NULL ); + + if( pf == pfres ) { + rswap(pfres[1], pfres[4]); + rswap(pfres[2], pfres[8]); + rswap(pfres[3], pfres[12]); + rswap(pfres[6], pfres[9]); + rswap(pfres[7], pfres[13]); + rswap(pfres[11], pfres[15]); + return pfres; + } + + pfres[0] = pf[0]; pfres[1] = pf[4]; pfres[2] = pf[8]; pfres[3] = pf[12]; + pfres[4] = pf[1]; pfres[5] = pf[5]; pfres[6] = pf[9]; pfres[7] = pf[13]; + pfres[8] = pf[2]; pfres[9] = pf[6]; pfres[10] = pf[10]; pfres[11] = pf[14]; + pfres[12] = pf[3]; pfres[13] = pf[7]; pfres[14] = pf[11]; pfres[15] = pf[15]; + return pfres; +} + +inline dReal* transpose4(const dReal* pf, dReal* pfres) { return _transpose4(pf, pfres); } +inline double* transpose4(const double* pf, double* pfres) { return _transpose4(pf, pfres); } + +inline dReal dot2(const dReal* pf1, const dReal* pf2) +{ + assert( pf1 != NULL && pf2 != NULL ); + return pf1[0]*pf2[0] + pf1[1]*pf2[1]; +} + +inline dReal dot3(const dReal* pf1, const dReal* pf2) +{ + assert( pf1 != NULL && pf2 != NULL ); + return pf1[0]*pf2[0] + pf1[1]*pf2[1] + pf1[2]*pf2[2]; +} + +inline dReal dot4(const dReal* pf1, const dReal* pf2) +{ + assert( pf1 != NULL && pf2 != NULL ); + return pf1[0]*pf2[0] + pf1[1]*pf2[1] + pf1[2]*pf2[2] + pf1[3] * pf2[3]; +} + +inline dReal lengthsqr2(const dReal* pf) +{ + assert( pf != NULL ); + return pf[0] * pf[0] + pf[1] * pf[1]; +} + +inline dReal lengthsqr3(const dReal* pf) +{ + assert( pf != NULL ); + return pf[0] * pf[0] + pf[1] * pf[1] + pf[2] * pf[2]; +} + +inline dReal lengthsqr4(const dReal* pf) +{ + assert( pf != NULL ); + return pf[0] * pf[0] + pf[1] * pf[1] + pf[2] * pf[2] + pf[3] * pf[3]; +} + +inline dReal* normalize2(dReal* pfout, const dReal* pf) +{ + assert(pf != NULL); + + dReal f = pf[0]*pf[0] + pf[1]*pf[1]; + f = 1.0f / sqrtf(f); + pfout[0] = pf[0] * f; + pfout[1] = pf[1] * f; + + return pfout; +} + +inline dReal* normalize3(dReal* pfout, const dReal* pf) +{ + assert(pf != NULL); + + dReal f = pf[0]*pf[0] + pf[1]*pf[1] + pf[2]*pf[2]; + + f = 1.0f / sqrtf(f); + pfout[0] = pf[0] * f; + pfout[1] = pf[1] * f; + pfout[2] = pf[2] * f; + + return pfout; +} + +inline dReal* normalize4(dReal* pfout, const dReal* pf) +{ + assert(pf != NULL); + + dReal f = pf[0]*pf[0] + pf[1]*pf[1] + pf[2]*pf[2] + pf[3]*pf[3]; + + f = 1.0f / sqrtf(f); + pfout[0] = pf[0] * f; + pfout[1] = pf[1] * f; + pfout[2] = pf[2] * f; + pfout[3] = pf[3] * f; + + return pfout; +} + +inline dReal* cross3(dReal* pfout, const dReal* pf1, const dReal* pf2) +{ + assert( pfout != NULL && pf1 != NULL && pf2 != NULL ); + + dReal temp[3]; + temp[0] = pf1[1] * pf2[2] - pf1[2] * pf2[1]; + temp[1] = pf1[2] * pf2[0] - pf1[0] * pf2[2]; + temp[2] = pf1[0] * pf2[1] - pf1[1] * pf2[0]; + + pfout[0] = temp[0]; pfout[1] = temp[1]; pfout[2] = temp[2]; + return pfout; +} + +template inline void mult(T* pf, T fa, int r) +{ + assert( pf != NULL ); + + while(r > 0) { + --r; + pf[r] *= fa; + } +} + +template +inline T* mult(T* pf1, R* pf2, int r1, int c1, int c2, S* pfres, bool badd) +{ + assert( pf1 != NULL && pf2 != NULL && pfres != NULL); + int j, k; + + if( !badd ) memset(pfres, 0, sizeof(S) * r1 * c2); + + while(r1 > 0) { + --r1; + + j = 0; + while(j < c2) { + k = 0; + while(k < c1) { + pfres[j] += pf1[k] * pf2[k*c2 + j]; + ++k; + } + ++j; + } + + pf1 += c1; + pfres += c2; + } + + return pfres; +} + +template +inline T* multtrans(T* pf1, R* pf2, int r1, int c1, int c2, S* pfres, bool badd) +{ + assert( pf1 != NULL && pf2 != NULL && pfres != NULL); + int i, j, k; + + if( !badd ) memset(pfres, 0, sizeof(S) * c1 * c2); + + i = 0; + while(i < c1) { + + j = 0; + while(j < c2) { + + k = 0; + while(k < r1) { + pfres[j] += pf1[k*c1] * pf2[k*c2 + j]; + ++k; + } + ++j; + } + + pfres += c2; + ++pf1; + + ++i; + } + + return pfres; +} + +template +inline T* multtrans_to2(T* pf1, R* pf2, int r1, int c1, int r2, S* pfres, bool badd) +{ + assert( pf1 != NULL && pf2 != NULL && pfres != NULL); + int j, k; + + if( !badd ) memset(pfres, 0, sizeof(S) * r1 * r2); + + while(r1 > 0) { + --r1; + + j = 0; + while(j < r2) { + k = 0; + while(k < c1) { + pfres[j] += pf1[k] * pf2[j*c1 + k]; + ++k; + } + ++j; + } + + pf1 += c1; + pfres += r2; + } + + return pfres; +} + +template inline T* multto1(T* pf1, T* pf2, int r, int c, T* pftemp) +{ + assert( pf1 != NULL && pf2 != NULL ); + + int j, k; + bool bdel = false; + + if( pftemp == NULL ) { + pftemp = new T[c]; + bdel = true; + } + + while(r > 0) { + --r; + + j = 0; + while(j < c) { + + pftemp[j] = 0.0; + + k = 0; + while(k < c) { + pftemp[j] += pf1[k] * pf2[k*c + j]; + ++k; + } + ++j; + } + + memcpy(pf1, pftemp, c * sizeof(T)); + pf1 += c; + } + + if( bdel ) delete[] pftemp; + + return pf1; +} + +template inline T* multto2(T* pf1, S* pf2, int r2, int c2, S* pftemp) +{ + assert( pf1 != NULL && pf2 != NULL ); + + int i, j, k; + bool bdel = false; + + if( pftemp == NULL ) { + pftemp = new S[r2]; + bdel = true; + } + + // do columns first + j = 0; + while(j < c2) { + i = 0; + while(i < r2) { + + pftemp[i] = 0.0; + + k = 0; + while(k < r2) { + pftemp[i] += pf1[i*r2 + k] * pf2[k*c2 + j]; + ++k; + } + ++i; + } + + i = 0; + while(i < r2) { + *(pf2+i*c2+j) = pftemp[i]; + ++i; + } + + ++j; + } + + if( bdel ) delete[] pftemp; + + return pf1; +} + +template inline void add(T* pf1, T* pf2, int r) +{ + assert( pf1 != NULL && pf2 != NULL); + + while(r > 0) { + --r; + pf1[r] += pf2[r]; + } +} + +template inline void sub(T* pf1, T* pf2, int r) +{ + assert( pf1 != NULL && pf2 != NULL); + + while(r > 0) { + --r; + pf1[r] -= pf2[r]; + } +} + +template inline T normsqr(T* pf1, int r) +{ + assert( pf1 != NULL ); + + T d = 0.0; + while(r > 0) { + --r; + d += pf1[r] * pf1[r]; + } + + return d; +} + +template inline T lengthsqr(T* pf1, T* pf2, int length) +{ + T d = 0; + while(length > 0) { + --length; + d += sqr(pf1[length] - pf2[length]); + } + + return d; +} + +template inline T dot(T* pf1, T* pf2, int length) +{ + T d = 0; + while(length > 0) { + --length; + d += pf1[length] * pf2[length]; + } + + return d; +} + +template inline T sum(T* pf, int length) +{ + T d = 0; + while(length > 0) { + --length; + d += pf[length]; + } + + return d; +} + +template inline bool inv2(T* pf, T* pfres) +{ + T fdet = pf[0] * pf[3] - pf[1] * pf[2]; + + if( fabs(fdet) < 1e-16 ) return false; + + fdet = 1 / fdet; + //if( pfdet != NULL ) *pfdet = fdet; + + if( pfres != pf ) { + pfres[0] = fdet * pf[3]; pfres[1] = -fdet * pf[1]; + pfres[2] = -fdet * pf[2]; pfres[3] = fdet * pf[0]; + return true; + } + + dReal ftemp = pf[0]; + pfres[0] = pf[3] * fdet; + pfres[1] *= -fdet; + pfres[2] *= -fdet; + pfres[3] = ftemp * pf[0]; + + return true; +} + +#endif diff --git a/plugins/zerogs/opengl/zpipe.cpp b/plugins/zerogs/opengl/zpipe.cpp index 174daa5f30..703ab487b8 100644 --- a/plugins/zerogs/opengl/zpipe.cpp +++ b/plugins/zerogs/opengl/zpipe.cpp @@ -1,115 +1,115 @@ -// zpipe.cpp : Defines the entry point for the console application. -// - -#include - -#include -#include -#include - -//#define ZLIB_WINAPI -#include "zlib/zlib.h" - -int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) ; -int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress) ; - -int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) -{ - z_stream strm; - - int ret;//, flush; - unsigned have; - - /* allocate deflate state */ - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION) ; - if (ret != Z_OK) - return ret; - - /* compress */ - strm.avail_in = bytes_to_compress ; - strm.avail_out = bytes_to_compress ; - strm.next_in = (Bytef *)src ; - strm.next_out = (Bytef *)dst ; - - ret = deflate(&strm, Z_FINISH) ; - have = bytes_to_compress - strm.avail_out ; - *bytes_after_compressed = have ; - - assert(ret == Z_STREAM_END); /* stream will be complete */ - - /* clean up and return */ - (void)deflateEnd(&strm); - return Z_OK; -} - -int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress, int* outbytes) -{ - z_stream strm; - - int ret; - //unsigned have; - - /* allocate inflate state */ - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = 0; - strm.next_in = Z_NULL; - ret = inflateInit(&strm); - if (ret != Z_OK) - return ret; - - /* decompress */ - strm.avail_in = bytes_to_decompress ; - strm.next_in = (Bytef *)src ; - strm.next_out = (Bytef *)dst ; - strm.avail_out = maximum_after_decompress ; - - ret = inflate(&strm, Z_NO_FLUSH) ; - assert(ret != Z_STREAM_ERROR); /* state not clobbered */ - switch (ret) { - case Z_NEED_DICT: - ret = Z_DATA_ERROR; /* and fall through */ - case Z_DATA_ERROR: - case Z_MEM_ERROR: - (void)inflateEnd(&strm); - return ret; - } - - assert(strm.avail_in == 0); /* all input will be used */ - - if( outbytes != NULL ) - *outbytes = strm.total_out; - - /* clean up and return */ - (void)inflateEnd(&strm); - return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; -} - -/* report a zlib or i/o error */ -void zerr(int ret) -{ - fputs("zpipe: ", stderr); - switch (ret) { - case Z_ERRNO: - if (ferror(stdin)) - fputs("error reading stdin\n", stderr); - if (ferror(stdout)) - fputs("error writing stdout\n", stderr); - break; - case Z_STREAM_ERROR: - fputs("invalid compression level\n", stderr); - break; - case Z_DATA_ERROR: - fputs("invalid or incomplete deflate data\n", stderr); - break; - case Z_MEM_ERROR: - fputs("out of memory\n", stderr); - break; - case Z_VERSION_ERROR: - fputs("zlib version mismatch!\n", stderr); - } -} +// zpipe.cpp : Defines the entry point for the console application. +// + +#include + +#include +#include +#include + +//#define ZLIB_WINAPI +#include "zlib/zlib.h" + +int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) ; +int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress) ; + +int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) +{ + z_stream strm; + + int ret;//, flush; + unsigned have; + + /* allocate deflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION) ; + if (ret != Z_OK) + return ret; + + /* compress */ + strm.avail_in = bytes_to_compress ; + strm.avail_out = bytes_to_compress ; + strm.next_in = (Bytef *)src ; + strm.next_out = (Bytef *)dst ; + + ret = deflate(&strm, Z_FINISH) ; + have = bytes_to_compress - strm.avail_out ; + *bytes_after_compressed = have ; + + assert(ret == Z_STREAM_END); /* stream will be complete */ + + /* clean up and return */ + (void)deflateEnd(&strm); + return Z_OK; +} + +int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress, int* outbytes) +{ + z_stream strm; + + int ret; + //unsigned have; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit(&strm); + if (ret != Z_OK) + return ret; + + /* decompress */ + strm.avail_in = bytes_to_decompress ; + strm.next_in = (Bytef *)src ; + strm.next_out = (Bytef *)dst ; + strm.avail_out = maximum_after_decompress ; + + ret = inflate(&strm, Z_NO_FLUSH) ; + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + switch (ret) { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; /* and fall through */ + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + return ret; + } + + assert(strm.avail_in == 0); /* all input will be used */ + + if( outbytes != NULL ) + *outbytes = strm.total_out; + + /* clean up and return */ + (void)inflateEnd(&strm); + return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; +} + +/* report a zlib or i/o error */ +void zerr(int ret) +{ + fputs("zpipe: ", stderr); + switch (ret) { + case Z_ERRNO: + if (ferror(stdin)) + fputs("error reading stdin\n", stderr); + if (ferror(stdout)) + fputs("error writing stdout\n", stderr); + break; + case Z_STREAM_ERROR: + fputs("invalid compression level\n", stderr); + break; + case Z_DATA_ERROR: + fputs("invalid or incomplete deflate data\n", stderr); + break; + case Z_MEM_ERROR: + fputs("out of memory\n", stderr); + break; + case Z_VERSION_ERROR: + fputs("zlib version mismatch!\n", stderr); + } +} diff --git a/plugins/zerogs/opengl/zpipe.h b/plugins/zerogs/opengl/zpipe.h index cb96229553..2b3f8b3262 100644 --- a/plugins/zerogs/opengl/zpipe.h +++ b/plugins/zerogs/opengl/zpipe.h @@ -1,7 +1,7 @@ -#ifndef zpipe_h -#define zpipe_h - -int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) ; -int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress, int* outbytes); - -#endif +#ifndef zpipe_h +#define zpipe_h + +int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) ; +int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress, int* outbytes); + +#endif diff --git a/plugins/zeropad/Linux/linux.cpp b/plugins/zeropad/Linux/linux.cpp index d520041f50..2bc274c77f 100644 --- a/plugins/zeropad/Linux/linux.cpp +++ b/plugins/zeropad/Linux/linux.cpp @@ -1,829 +1,829 @@ -/* ZeroPAD - author: zerofrog(@gmail.com) - * Copyright (C) 2006-2007 - * - * 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 -#include -#include - -#define JOYSTICK_SUPPORT -#ifdef JOYSTICK_SUPPORT -#include -#endif - -#include "zeropad.h" - -extern "C" { -#include "interface.h" -#include "support.h" -#include "callbacks.h" -} - -Display *GSdsp; -static pthread_spinlock_t s_mutexStatus; -static u32 s_keyPress[2], s_keyRelease[2]; // thread safe -static u32 s_bSDLInit = false; - -// holds all joystick info -class JoystickInfo -{ -public: - JoystickInfo(); - ~JoystickInfo() { Destroy(); } - - void Destroy(); - // opens handles to all possible joysticks - static void EnumerateJoysticks(vector& vjoysticks); - - bool Init(int id, bool bStartThread=true); // opens a handle and gets information - void Assign(int pad); // assigns a joystick to a pad - - void TestForce(); - - const string& GetName() { return devname; } - int GetNumButtons() { return numbuttons; } - int GetNumAxes() { return numaxes; } - int GetNumPOV() { return numpov; } - int GetId() { return _id; } - int GetPAD() { return pad; } - int GetDeadzone(int axis) { return deadzone; } - - void SaveState(); - int GetButtonState(int i) { return vbutstate[i]; } - int GetAxisState(int i) { return vaxisstate[i]; } - void SetButtonState(int i, int state) { vbutstate[i] = state; } - void SetAxisState(int i, int value) { vaxisstate[i] = value; } -#ifdef JOYSTICK_SUPPORT - SDL_Joystick* GetJoy() { return joy; } -#endif - -private: - - string devname; // pretty device name - int _id; - int numbuttons, numaxes, numpov; - int axisrange, deadzone; - int pad; - - vector vbutstate, vaxisstate; - -#ifdef JOYSTICK_SUPPORT - SDL_Joystick* joy; -#endif -}; - -static vector s_vjoysticks; - -extern string s_strIniPath; - -void SaveConfig() -{ - int i, j; - FILE *f; - char cfg[255]; - - strcpy(cfg, s_strIniPath.c_str()); - f = fopen(cfg,"w"); - if (f == NULL) { - printf("ZeroPAD: failed to save ini %s\n", s_strIniPath.c_str()); - return; - } - - for (j=0; j<2; j++) { - for (i=0; i::iterator it; - FORIT(it, s_vjoysticks) delete *it; - s_vjoysticks.clear(); -} - -void _PADupdate(int pad) -{ - pthread_spin_lock(&s_mutexStatus); - status[pad] |= s_keyRelease[pad]; - status[pad] &= ~s_keyPress[pad]; - s_keyRelease[pad] = 0; - s_keyPress[pad] = 0; - pthread_spin_unlock(&s_mutexStatus); -} - -int _GetJoystickIdFromPAD(int pad) -{ - // select the right joystick id - int joyid = -1; - for(int i = 0; i < PADKEYS; ++i) { - if( IS_JOYSTICK(conf.keys[pad][i]) || IS_JOYBUTTONS(conf.keys[pad][i]) ) { - joyid = PAD_GETJOYID(conf.keys[pad][i]); - break; - } - } - - return joyid; -} - -void CALLBACK PADupdate(int pad) -{ - int i; - XEvent E; - int keyPress=0,keyRelease=0; - KeySym key; - - // keyboard input - while (XPending(GSdsp) > 0) { - XNextEvent(GSdsp, &E); - switch (E.type) { - case KeyPress: - //_KeyPress(pad, XLookupKeysym((XKeyEvent *)&E, 0)); break; - key = XLookupKeysym((XKeyEvent *)&E, 0); - for (i=0; i= 0 && joyid < (int)s_vjoysticks.size()) { - pjoy = s_vjoysticks[joyid]; - if( SDL_JoystickGetButton((pjoy)->GetJoy(), PAD_GETJOYBUTTON(key)) ) { - status[(pjoy)->GetPAD()] &= ~(1<GetPAD()] |= (1<= 0 && joyid < (int)s_vjoysticks.size()) { - - pjoy = s_vjoysticks[joyid]; - int value = SDL_JoystickGetAxis((pjoy)->GetJoy(), PAD_GETJOYSTICK_AXIS(key)); - int pad = (pjoy)->GetPAD(); - switch(i) { - case PAD_LX: - if( abs(value) > (pjoy)->GetDeadzone(value) ) { - g_lanalog[pad].x = value/256; - if( conf.options&PADOPTION_REVERTLX ) - g_lanalog[pad].x = -g_lanalog[pad].x; - g_lanalog[pad].x += 0x80; - } - else g_lanalog[pad].x = 0x80; - break; - case PAD_LY: - if( abs(value) > (pjoy)->GetDeadzone(value) ) { - g_lanalog[pad].y = value/256; - if( conf.options&PADOPTION_REVERTLX ) - g_lanalog[pad].y = -g_lanalog[pad].y; - g_lanalog[pad].y += 0x80; - } - else g_lanalog[pad].y = 0x80; - break; - case PAD_RX: - if( abs(value) > (pjoy)->GetDeadzone(value) ) { - g_ranalog[pad].x = value/256; - if( conf.options&PADOPTION_REVERTLX ) - g_ranalog[pad].x = -g_ranalog[pad].x; - g_ranalog[pad].x += 0x80; - } - else g_ranalog[pad].x = 0x80; - break; - case PAD_RY: - if( abs(value) > (pjoy)->GetDeadzone(value) ) { - g_ranalog[pad].y = value/256; - if( conf.options&PADOPTION_REVERTLX ) - g_ranalog[pad].y = -g_ranalog[pad].y; - g_ranalog[pad].y += 0x80; - } - else g_ranalog[pad].y = 0x80; - break; - } - } - } - else if( IS_POV(key) ) { - int joyid = PAD_GETJOYID(key); - if( joyid >= 0 && joyid < (int)s_vjoysticks.size()) { - - pjoy = s_vjoysticks[joyid]; - - int value = SDL_JoystickGetAxis((pjoy)->GetJoy(), PAD_GETJOYSTICK_AXIS(key)); - int pad = (pjoy)->GetPAD(); - if( PAD_GETPOVSIGN(key) && (value<-2048) ) - status[pad] &= ~(1<2048) ) - status[pad] &= ~(1< 0) { - gtk_entry_set_text(GTK_ENTRY(Btn), tmp.c_str()); - } - else - gtk_entry_set_text(GTK_ENTRY(Btn), "Unknown"); - - gtk_object_set_user_data(GTK_OBJECT(Btn), (void*)(PADKEYS*pad+i)); - } - - // check bounds - int joyid = _GetJoystickIdFromPAD(pad); - if( joyid < 0 || joyid >= (int)s_vjoysticks.size() ) { - // get first unused joystick - for(joyid = 0; joyid < s_vjoysticks.size(); ++joyid) { - if( s_vjoysticks[joyid]->GetPAD() < 0 ) - break; - } - } - - if( joyid >= 0 && joyid < (int)s_vjoysticks.size() ) { - // select the combo - gtk_combo_box_set_active(GTK_COMBO_BOX(s_devicecombo), joyid); - } - else gtk_combo_box_set_active(GTK_COMBO_BOX(s_devicecombo), s_vjoysticks.size()); // no gamepad - - int padopts = conf.options>>(16*pad); - gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkbutton_reverselx")), padopts&PADOPTION_REVERTLX); - gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkbutton_reversely")), padopts&PADOPTION_REVERTLY); - gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkbutton_reverserx")), padopts&PADOPTION_REVERTRX); - gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkbutton_reversery")), padopts&PADOPTION_REVERTRY); - gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "forcefeedback")), padopts&PADOPTION_FORCEFEEDBACK); -} - -void OnConf_Key(GtkButton *button, gpointer user_data) -{ - GdkEvent *ev; - GtkWidget* label = lookup_widget(Conf, GetLabelFromButton(gtk_button_get_label(button)).c_str()); - if( label == NULL ) { - printf("couldn't find correct label\n"); - return; - } - - int id = (int)(uptr)gtk_object_get_user_data(GTK_OBJECT(label)); - int pad = id/PADKEYS; - int key = id%PADKEYS; - unsigned long *pkey = &conf.keys[pad][key]; - - vector::iterator itjoy; - - // save the states -#ifdef JOYSTICK_SUPPORT - SDL_JoystickUpdate(); - FORIT(itjoy, s_vjoysticks) (*itjoy)->SaveState(); -#endif - - for (;;) { - ev = gdk_event_get(); - if (ev != NULL) { - if (ev->type == GDK_KEY_PRESS) { - *pkey = ev->key.keyval; - - char* tmp = XKeysymToString(*pkey); - if (tmp != NULL) - gtk_entry_set_text(GTK_ENTRY(label), tmp); - else - gtk_entry_set_text(GTK_ENTRY(label), "Unknown"); - return; - } - } - -#ifdef JOYSTICK_SUPPORT - SDL_JoystickUpdate(); - FORIT(itjoy, s_vjoysticks) { - - // MAKE sure to look for changes in the state!! - - for(int i = 0; i < (*itjoy)->GetNumButtons(); ++i) { - int but = SDL_JoystickGetButton((*itjoy)->GetJoy(), i); - if( but != (*itjoy)->GetButtonState(i) ) { - - if( !but ) { // released, we don't really want this - (*itjoy)->SetButtonState(i, 0); - break; - } - - *pkey = PAD_JOYBUTTON((*itjoy)->GetId(), i); - char str[32]; - sprintf(str, "JBut %d", i); - gtk_entry_set_text(GTK_ENTRY(label), str); - return; - } - } - - for(int i = 0; i < (*itjoy)->GetNumAxes(); ++i) { - int value = SDL_JoystickGetAxis((*itjoy)->GetJoy(), i); - - if( value != (*itjoy)->GetAxisState(i) ) { - - if( abs(value) <= (*itjoy)->GetAxisState(i)) {// we don't want this - // released, we don't really want this - (*itjoy)->SetButtonState(i, value); - break; - } - - - if( abs(value) > 0x3fff ) { - if( key < 16 ) { // POV - *pkey = PAD_POV((*itjoy)->GetId(), value<0, i); - char str[32]; - sprintf(str, "JPOV %d%s", i, value<0?"-":"+"); - gtk_entry_set_text(GTK_ENTRY(label), str); - return; - } - else { // axis - *pkey = PAD_JOYSTICK((*itjoy)->GetId(), i); - char str[32]; - sprintf(str, "JAxis %d", i); - gtk_entry_set_text(GTK_ENTRY(label), str); - return; - } - } - } - } - } -#endif - } -} - -void OnConf_Pad1(GtkButton *button, gpointer user_data) -{ - if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) ) - UpdateConf(0); -} - -void OnConf_Pad2(GtkButton *button, gpointer user_data) -{ - if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) ) - UpdateConf(1); -} - -void OnConf_Ok(GtkButton *button, gpointer user_data) -{ -// conf.analog = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(Analog)); - SaveConfig(); - - gtk_widget_destroy(Conf); - gtk_main_quit(); -} - -void OnConf_Cancel(GtkButton *button, gpointer user_data) -{ - gtk_widget_destroy(Conf); - gtk_main_quit(); - LoadConfig(); // load previous config -} - -void CALLBACK PADconfigure() -{ - LoadConfig(); - - Conf = create_Conf(); - - // recreate - JoystickInfo::EnumerateJoysticks(s_vjoysticks); - - s_devicecombo = lookup_widget(Conf, "joydevicescombo"); - - // fill the combo - char str[255]; - vector::iterator it; - FORIT(it, s_vjoysticks) { - sprintf(str, "%d: %s - but: %d, axes: %d, pov: %d", (*it)->GetId(), (*it)->GetName().c_str(), - (*it)->GetNumButtons(), (*it)->GetNumAxes(), (*it)->GetNumPOV()); - gtk_combo_box_append_text (GTK_COMBO_BOX (s_devicecombo), str); - } - gtk_combo_box_append_text (GTK_COMBO_BOX (s_devicecombo), "No Gamepad"); - - UpdateConf(0); - - gtk_widget_show_all(Conf); - gtk_main(); -} - -// GUI event handlers -void on_joydevicescombo_changed(GtkComboBox *combobox, gpointer user_data) -{ - int joyid = gtk_combo_box_get_active(combobox); - - // unassign every joystick with this pad - for(int i = 0; i < (int)s_vjoysticks.size(); ++i) { - if( s_vjoysticks[i]->GetPAD() == s_selectedpad ) - s_vjoysticks[i]->Assign(-1); - } - - if( joyid >= 0 && joyid < (int)s_vjoysticks.size() ) - s_vjoysticks[joyid]->Assign(s_selectedpad); -} - -void on_checkbutton_reverselx_toggled(GtkToggleButton *togglebutton, gpointer user_data) -{ - int mask = PADOPTION_REVERTLX<<(16*s_selectedpad); - if( gtk_toggle_button_get_active(togglebutton) ) conf.options |= mask; - else conf.options &= ~mask; -} - -void on_checkbutton_reversely_toggled(GtkToggleButton *togglebutton, gpointer user_data) -{ - int mask = PADOPTION_REVERTLY<<(16*s_selectedpad); - if( gtk_toggle_button_get_active(togglebutton) ) conf.options |= mask; - else conf.options &= ~mask; -} - -void on_checkbutton_reverserx_toggled(GtkToggleButton *togglebutton, gpointer user_data) -{ - int mask = PADOPTION_REVERTRX<<(16*s_selectedpad); - if( gtk_toggle_button_get_active(togglebutton) ) conf.options |= mask; - else conf.options &= ~mask; -} - -void on_checkbutton_reversery_toggled(GtkToggleButton *togglebutton, gpointer user_data) -{ - int mask = PADOPTION_REVERTRY<<(16*s_selectedpad); - if( gtk_toggle_button_get_active(togglebutton) ) conf.options |= mask; - else conf.options &= ~mask; -} - -void on_forcefeedback_toggled(GtkToggleButton *togglebutton, gpointer user_data) -{ - int mask = PADOPTION_REVERTLX<<(16*s_selectedpad); - if( gtk_toggle_button_get_active(togglebutton) ) { - conf.options |= mask; - - int joyid = gtk_combo_box_get_active(GTK_COMBO_BOX(s_devicecombo)); - if( joyid >= 0 && joyid < (int)s_vjoysticks.size() ) - s_vjoysticks[joyid]->TestForce(); - } - else conf.options &= ~mask; -} - -GtkWidget *About = NULL; - -void OnAbout_Ok(GtkButton *button, gpointer user_data) -{ - gtk_widget_destroy(About); - gtk_main_quit(); -} - -void CALLBACK PADabout() { - - About = create_About(); - - gtk_widget_show_all(About); - gtk_main(); -} - -s32 CALLBACK PADtest() { - return 0; -} - -////////////////////////// -// Joystick definitions // -////////////////////////// - -// opens handles to all possible joysticks -void JoystickInfo::EnumerateJoysticks(vector& vjoysticks) -{ -#ifdef JOYSTICK_SUPPORT - - if( !s_bSDLInit ) { - if( SDL_Init(SDL_INIT_JOYSTICK) < 0 ) - return; - SDL_JoystickEventState(SDL_QUERY); - s_bSDLInit = true; - } - - vector::iterator it; - FORIT(it, vjoysticks) delete *it; - - vjoysticks.resize(SDL_NumJoysticks()); - for(int i = 0; i < (int)vjoysticks.size(); ++i) { - vjoysticks[i] = new JoystickInfo(); - vjoysticks[i]->Init(i, true); - } - - // set the pads - for(int pad = 0; pad < 2; ++pad) { - // select the right joystick id - int joyid = -1; - for(int i = 0; i < PADKEYS; ++i) { - if( IS_JOYSTICK(conf.keys[pad][i]) || IS_JOYBUTTONS(conf.keys[pad][i]) ) { - joyid = PAD_GETJOYID(conf.keys[pad][i]); - break; - } - } - - if( joyid >= 0 && joyid < (int)s_vjoysticks.size() ) - s_vjoysticks[joyid]->Assign(pad); - } - -#endif -} - -JoystickInfo::JoystickInfo() -{ -#ifdef JOYSTICK_SUPPORT - joy = NULL; -#endif - _id = -1; - pad = -1; - axisrange = 0x7fff; - deadzone = 2000; -} - -void JoystickInfo::Destroy() -{ -#ifdef JOYSTICK_SUPPORT - if( joy != NULL ) { - if( SDL_JoystickOpened(_id) ) - SDL_JoystickClose(joy); - joy = NULL; - } -#endif -} - -bool JoystickInfo::Init(int id, bool bStartThread) -{ -#ifdef JOYSTICK_SUPPORT - Destroy(); - _id = id; - - joy = SDL_JoystickOpen(id); - if( joy == NULL ) { - printf("failed to open joystick %d\n", id); - return false; - } - - numaxes = SDL_JoystickNumAxes(joy); - numbuttons = SDL_JoystickNumButtons(joy); - numpov = SDL_JoystickNumHats(joy); - devname = SDL_JoystickName(id); - vbutstate.resize(numbuttons); - vaxisstate.resize(numbuttons); - - return true; -#else - return false; -#endif -} - -// assigns a joystick to a pad -void JoystickInfo::Assign(int newpad) -{ - if( pad == newpad ) - return; - - pad = newpad; - - if( pad >= 0 ) { - for(int i = 0; i < PADKEYS; ++i) { - if( IS_JOYBUTTONS(conf.keys[pad][i]) ) { - conf.keys[pad][i] = PAD_JOYBUTTON(_id, PAD_GETJOYBUTTON(conf.keys[pad][i])); - } - else if( IS_JOYSTICK(conf.keys[pad][i]) ) { - conf.keys[pad][i] = PAD_JOYSTICK(_id, PAD_GETJOYBUTTON(conf.keys[pad][i])); - } - } - } -} - -void JoystickInfo::SaveState() -{ -#ifdef JOYSTICK_SUPPORT - for(int i = 0; i < numbuttons; ++i) - vbutstate[i] = SDL_JoystickGetButton(joy, i); - for(int i = 0; i < numaxes; ++i) - vaxisstate[i] = SDL_JoystickGetAxis(joy, i); -#endif -} - -void JoystickInfo::TestForce() -{ -} +/* ZeroPAD - author: zerofrog(@gmail.com) + * Copyright (C) 2006-2007 + * + * 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 +#include +#include + +#define JOYSTICK_SUPPORT +#ifdef JOYSTICK_SUPPORT +#include +#endif + +#include "zeropad.h" + +extern "C" { +#include "interface.h" +#include "support.h" +#include "callbacks.h" +} + +Display *GSdsp; +static pthread_spinlock_t s_mutexStatus; +static u32 s_keyPress[2], s_keyRelease[2]; // thread safe +static u32 s_bSDLInit = false; + +// holds all joystick info +class JoystickInfo +{ +public: + JoystickInfo(); + ~JoystickInfo() { Destroy(); } + + void Destroy(); + // opens handles to all possible joysticks + static void EnumerateJoysticks(vector& vjoysticks); + + bool Init(int id, bool bStartThread=true); // opens a handle and gets information + void Assign(int pad); // assigns a joystick to a pad + + void TestForce(); + + const string& GetName() { return devname; } + int GetNumButtons() { return numbuttons; } + int GetNumAxes() { return numaxes; } + int GetNumPOV() { return numpov; } + int GetId() { return _id; } + int GetPAD() { return pad; } + int GetDeadzone(int axis) { return deadzone; } + + void SaveState(); + int GetButtonState(int i) { return vbutstate[i]; } + int GetAxisState(int i) { return vaxisstate[i]; } + void SetButtonState(int i, int state) { vbutstate[i] = state; } + void SetAxisState(int i, int value) { vaxisstate[i] = value; } +#ifdef JOYSTICK_SUPPORT + SDL_Joystick* GetJoy() { return joy; } +#endif + +private: + + string devname; // pretty device name + int _id; + int numbuttons, numaxes, numpov; + int axisrange, deadzone; + int pad; + + vector vbutstate, vaxisstate; + +#ifdef JOYSTICK_SUPPORT + SDL_Joystick* joy; +#endif +}; + +static vector s_vjoysticks; + +extern string s_strIniPath; + +void SaveConfig() +{ + int i, j; + FILE *f; + char cfg[255]; + + strcpy(cfg, s_strIniPath.c_str()); + f = fopen(cfg,"w"); + if (f == NULL) { + printf("ZeroPAD: failed to save ini %s\n", s_strIniPath.c_str()); + return; + } + + for (j=0; j<2; j++) { + for (i=0; i::iterator it; + FORIT(it, s_vjoysticks) delete *it; + s_vjoysticks.clear(); +} + +void _PADupdate(int pad) +{ + pthread_spin_lock(&s_mutexStatus); + status[pad] |= s_keyRelease[pad]; + status[pad] &= ~s_keyPress[pad]; + s_keyRelease[pad] = 0; + s_keyPress[pad] = 0; + pthread_spin_unlock(&s_mutexStatus); +} + +int _GetJoystickIdFromPAD(int pad) +{ + // select the right joystick id + int joyid = -1; + for(int i = 0; i < PADKEYS; ++i) { + if( IS_JOYSTICK(conf.keys[pad][i]) || IS_JOYBUTTONS(conf.keys[pad][i]) ) { + joyid = PAD_GETJOYID(conf.keys[pad][i]); + break; + } + } + + return joyid; +} + +void CALLBACK PADupdate(int pad) +{ + int i; + XEvent E; + int keyPress=0,keyRelease=0; + KeySym key; + + // keyboard input + while (XPending(GSdsp) > 0) { + XNextEvent(GSdsp, &E); + switch (E.type) { + case KeyPress: + //_KeyPress(pad, XLookupKeysym((XKeyEvent *)&E, 0)); break; + key = XLookupKeysym((XKeyEvent *)&E, 0); + for (i=0; i= 0 && joyid < (int)s_vjoysticks.size()) { + pjoy = s_vjoysticks[joyid]; + if( SDL_JoystickGetButton((pjoy)->GetJoy(), PAD_GETJOYBUTTON(key)) ) { + status[(pjoy)->GetPAD()] &= ~(1<GetPAD()] |= (1<= 0 && joyid < (int)s_vjoysticks.size()) { + + pjoy = s_vjoysticks[joyid]; + int value = SDL_JoystickGetAxis((pjoy)->GetJoy(), PAD_GETJOYSTICK_AXIS(key)); + int pad = (pjoy)->GetPAD(); + switch(i) { + case PAD_LX: + if( abs(value) > (pjoy)->GetDeadzone(value) ) { + g_lanalog[pad].x = value/256; + if( conf.options&PADOPTION_REVERTLX ) + g_lanalog[pad].x = -g_lanalog[pad].x; + g_lanalog[pad].x += 0x80; + } + else g_lanalog[pad].x = 0x80; + break; + case PAD_LY: + if( abs(value) > (pjoy)->GetDeadzone(value) ) { + g_lanalog[pad].y = value/256; + if( conf.options&PADOPTION_REVERTLX ) + g_lanalog[pad].y = -g_lanalog[pad].y; + g_lanalog[pad].y += 0x80; + } + else g_lanalog[pad].y = 0x80; + break; + case PAD_RX: + if( abs(value) > (pjoy)->GetDeadzone(value) ) { + g_ranalog[pad].x = value/256; + if( conf.options&PADOPTION_REVERTLX ) + g_ranalog[pad].x = -g_ranalog[pad].x; + g_ranalog[pad].x += 0x80; + } + else g_ranalog[pad].x = 0x80; + break; + case PAD_RY: + if( abs(value) > (pjoy)->GetDeadzone(value) ) { + g_ranalog[pad].y = value/256; + if( conf.options&PADOPTION_REVERTLX ) + g_ranalog[pad].y = -g_ranalog[pad].y; + g_ranalog[pad].y += 0x80; + } + else g_ranalog[pad].y = 0x80; + break; + } + } + } + else if( IS_POV(key) ) { + int joyid = PAD_GETJOYID(key); + if( joyid >= 0 && joyid < (int)s_vjoysticks.size()) { + + pjoy = s_vjoysticks[joyid]; + + int value = SDL_JoystickGetAxis((pjoy)->GetJoy(), PAD_GETJOYSTICK_AXIS(key)); + int pad = (pjoy)->GetPAD(); + if( PAD_GETPOVSIGN(key) && (value<-2048) ) + status[pad] &= ~(1<2048) ) + status[pad] &= ~(1< 0) { + gtk_entry_set_text(GTK_ENTRY(Btn), tmp.c_str()); + } + else + gtk_entry_set_text(GTK_ENTRY(Btn), "Unknown"); + + gtk_object_set_user_data(GTK_OBJECT(Btn), (void*)(PADKEYS*pad+i)); + } + + // check bounds + int joyid = _GetJoystickIdFromPAD(pad); + if( joyid < 0 || joyid >= (int)s_vjoysticks.size() ) { + // get first unused joystick + for(joyid = 0; joyid < s_vjoysticks.size(); ++joyid) { + if( s_vjoysticks[joyid]->GetPAD() < 0 ) + break; + } + } + + if( joyid >= 0 && joyid < (int)s_vjoysticks.size() ) { + // select the combo + gtk_combo_box_set_active(GTK_COMBO_BOX(s_devicecombo), joyid); + } + else gtk_combo_box_set_active(GTK_COMBO_BOX(s_devicecombo), s_vjoysticks.size()); // no gamepad + + int padopts = conf.options>>(16*pad); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkbutton_reverselx")), padopts&PADOPTION_REVERTLX); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkbutton_reversely")), padopts&PADOPTION_REVERTLY); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkbutton_reverserx")), padopts&PADOPTION_REVERTRX); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkbutton_reversery")), padopts&PADOPTION_REVERTRY); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "forcefeedback")), padopts&PADOPTION_FORCEFEEDBACK); +} + +void OnConf_Key(GtkButton *button, gpointer user_data) +{ + GdkEvent *ev; + GtkWidget* label = lookup_widget(Conf, GetLabelFromButton(gtk_button_get_label(button)).c_str()); + if( label == NULL ) { + printf("couldn't find correct label\n"); + return; + } + + int id = (int)(uptr)gtk_object_get_user_data(GTK_OBJECT(label)); + int pad = id/PADKEYS; + int key = id%PADKEYS; + unsigned long *pkey = &conf.keys[pad][key]; + + vector::iterator itjoy; + + // save the states +#ifdef JOYSTICK_SUPPORT + SDL_JoystickUpdate(); + FORIT(itjoy, s_vjoysticks) (*itjoy)->SaveState(); +#endif + + for (;;) { + ev = gdk_event_get(); + if (ev != NULL) { + if (ev->type == GDK_KEY_PRESS) { + *pkey = ev->key.keyval; + + char* tmp = XKeysymToString(*pkey); + if (tmp != NULL) + gtk_entry_set_text(GTK_ENTRY(label), tmp); + else + gtk_entry_set_text(GTK_ENTRY(label), "Unknown"); + return; + } + } + +#ifdef JOYSTICK_SUPPORT + SDL_JoystickUpdate(); + FORIT(itjoy, s_vjoysticks) { + + // MAKE sure to look for changes in the state!! + + for(int i = 0; i < (*itjoy)->GetNumButtons(); ++i) { + int but = SDL_JoystickGetButton((*itjoy)->GetJoy(), i); + if( but != (*itjoy)->GetButtonState(i) ) { + + if( !but ) { // released, we don't really want this + (*itjoy)->SetButtonState(i, 0); + break; + } + + *pkey = PAD_JOYBUTTON((*itjoy)->GetId(), i); + char str[32]; + sprintf(str, "JBut %d", i); + gtk_entry_set_text(GTK_ENTRY(label), str); + return; + } + } + + for(int i = 0; i < (*itjoy)->GetNumAxes(); ++i) { + int value = SDL_JoystickGetAxis((*itjoy)->GetJoy(), i); + + if( value != (*itjoy)->GetAxisState(i) ) { + + if( abs(value) <= (*itjoy)->GetAxisState(i)) {// we don't want this + // released, we don't really want this + (*itjoy)->SetButtonState(i, value); + break; + } + + + if( abs(value) > 0x3fff ) { + if( key < 16 ) { // POV + *pkey = PAD_POV((*itjoy)->GetId(), value<0, i); + char str[32]; + sprintf(str, "JPOV %d%s", i, value<0?"-":"+"); + gtk_entry_set_text(GTK_ENTRY(label), str); + return; + } + else { // axis + *pkey = PAD_JOYSTICK((*itjoy)->GetId(), i); + char str[32]; + sprintf(str, "JAxis %d", i); + gtk_entry_set_text(GTK_ENTRY(label), str); + return; + } + } + } + } + } +#endif + } +} + +void OnConf_Pad1(GtkButton *button, gpointer user_data) +{ + if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) ) + UpdateConf(0); +} + +void OnConf_Pad2(GtkButton *button, gpointer user_data) +{ + if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) ) + UpdateConf(1); +} + +void OnConf_Ok(GtkButton *button, gpointer user_data) +{ +// conf.analog = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(Analog)); + SaveConfig(); + + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void OnConf_Cancel(GtkButton *button, gpointer user_data) +{ + gtk_widget_destroy(Conf); + gtk_main_quit(); + LoadConfig(); // load previous config +} + +void CALLBACK PADconfigure() +{ + LoadConfig(); + + Conf = create_Conf(); + + // recreate + JoystickInfo::EnumerateJoysticks(s_vjoysticks); + + s_devicecombo = lookup_widget(Conf, "joydevicescombo"); + + // fill the combo + char str[255]; + vector::iterator it; + FORIT(it, s_vjoysticks) { + sprintf(str, "%d: %s - but: %d, axes: %d, pov: %d", (*it)->GetId(), (*it)->GetName().c_str(), + (*it)->GetNumButtons(), (*it)->GetNumAxes(), (*it)->GetNumPOV()); + gtk_combo_box_append_text (GTK_COMBO_BOX (s_devicecombo), str); + } + gtk_combo_box_append_text (GTK_COMBO_BOX (s_devicecombo), "No Gamepad"); + + UpdateConf(0); + + gtk_widget_show_all(Conf); + gtk_main(); +} + +// GUI event handlers +void on_joydevicescombo_changed(GtkComboBox *combobox, gpointer user_data) +{ + int joyid = gtk_combo_box_get_active(combobox); + + // unassign every joystick with this pad + for(int i = 0; i < (int)s_vjoysticks.size(); ++i) { + if( s_vjoysticks[i]->GetPAD() == s_selectedpad ) + s_vjoysticks[i]->Assign(-1); + } + + if( joyid >= 0 && joyid < (int)s_vjoysticks.size() ) + s_vjoysticks[joyid]->Assign(s_selectedpad); +} + +void on_checkbutton_reverselx_toggled(GtkToggleButton *togglebutton, gpointer user_data) +{ + int mask = PADOPTION_REVERTLX<<(16*s_selectedpad); + if( gtk_toggle_button_get_active(togglebutton) ) conf.options |= mask; + else conf.options &= ~mask; +} + +void on_checkbutton_reversely_toggled(GtkToggleButton *togglebutton, gpointer user_data) +{ + int mask = PADOPTION_REVERTLY<<(16*s_selectedpad); + if( gtk_toggle_button_get_active(togglebutton) ) conf.options |= mask; + else conf.options &= ~mask; +} + +void on_checkbutton_reverserx_toggled(GtkToggleButton *togglebutton, gpointer user_data) +{ + int mask = PADOPTION_REVERTRX<<(16*s_selectedpad); + if( gtk_toggle_button_get_active(togglebutton) ) conf.options |= mask; + else conf.options &= ~mask; +} + +void on_checkbutton_reversery_toggled(GtkToggleButton *togglebutton, gpointer user_data) +{ + int mask = PADOPTION_REVERTRY<<(16*s_selectedpad); + if( gtk_toggle_button_get_active(togglebutton) ) conf.options |= mask; + else conf.options &= ~mask; +} + +void on_forcefeedback_toggled(GtkToggleButton *togglebutton, gpointer user_data) +{ + int mask = PADOPTION_REVERTLX<<(16*s_selectedpad); + if( gtk_toggle_button_get_active(togglebutton) ) { + conf.options |= mask; + + int joyid = gtk_combo_box_get_active(GTK_COMBO_BOX(s_devicecombo)); + if( joyid >= 0 && joyid < (int)s_vjoysticks.size() ) + s_vjoysticks[joyid]->TestForce(); + } + else conf.options &= ~mask; +} + +GtkWidget *About = NULL; + +void OnAbout_Ok(GtkButton *button, gpointer user_data) +{ + gtk_widget_destroy(About); + gtk_main_quit(); +} + +void CALLBACK PADabout() { + + About = create_About(); + + gtk_widget_show_all(About); + gtk_main(); +} + +s32 CALLBACK PADtest() { + return 0; +} + +////////////////////////// +// Joystick definitions // +////////////////////////// + +// opens handles to all possible joysticks +void JoystickInfo::EnumerateJoysticks(vector& vjoysticks) +{ +#ifdef JOYSTICK_SUPPORT + + if( !s_bSDLInit ) { + if( SDL_Init(SDL_INIT_JOYSTICK) < 0 ) + return; + SDL_JoystickEventState(SDL_QUERY); + s_bSDLInit = true; + } + + vector::iterator it; + FORIT(it, vjoysticks) delete *it; + + vjoysticks.resize(SDL_NumJoysticks()); + for(int i = 0; i < (int)vjoysticks.size(); ++i) { + vjoysticks[i] = new JoystickInfo(); + vjoysticks[i]->Init(i, true); + } + + // set the pads + for(int pad = 0; pad < 2; ++pad) { + // select the right joystick id + int joyid = -1; + for(int i = 0; i < PADKEYS; ++i) { + if( IS_JOYSTICK(conf.keys[pad][i]) || IS_JOYBUTTONS(conf.keys[pad][i]) ) { + joyid = PAD_GETJOYID(conf.keys[pad][i]); + break; + } + } + + if( joyid >= 0 && joyid < (int)s_vjoysticks.size() ) + s_vjoysticks[joyid]->Assign(pad); + } + +#endif +} + +JoystickInfo::JoystickInfo() +{ +#ifdef JOYSTICK_SUPPORT + joy = NULL; +#endif + _id = -1; + pad = -1; + axisrange = 0x7fff; + deadzone = 2000; +} + +void JoystickInfo::Destroy() +{ +#ifdef JOYSTICK_SUPPORT + if( joy != NULL ) { + if( SDL_JoystickOpened(_id) ) + SDL_JoystickClose(joy); + joy = NULL; + } +#endif +} + +bool JoystickInfo::Init(int id, bool bStartThread) +{ +#ifdef JOYSTICK_SUPPORT + Destroy(); + _id = id; + + joy = SDL_JoystickOpen(id); + if( joy == NULL ) { + printf("failed to open joystick %d\n", id); + return false; + } + + numaxes = SDL_JoystickNumAxes(joy); + numbuttons = SDL_JoystickNumButtons(joy); + numpov = SDL_JoystickNumHats(joy); + devname = SDL_JoystickName(id); + vbutstate.resize(numbuttons); + vaxisstate.resize(numbuttons); + + return true; +#else + return false; +#endif +} + +// assigns a joystick to a pad +void JoystickInfo::Assign(int newpad) +{ + if( pad == newpad ) + return; + + pad = newpad; + + if( pad >= 0 ) { + for(int i = 0; i < PADKEYS; ++i) { + if( IS_JOYBUTTONS(conf.keys[pad][i]) ) { + conf.keys[pad][i] = PAD_JOYBUTTON(_id, PAD_GETJOYBUTTON(conf.keys[pad][i])); + } + else if( IS_JOYSTICK(conf.keys[pad][i]) ) { + conf.keys[pad][i] = PAD_JOYSTICK(_id, PAD_GETJOYBUTTON(conf.keys[pad][i])); + } + } + } +} + +void JoystickInfo::SaveState() +{ +#ifdef JOYSTICK_SUPPORT + for(int i = 0; i < numbuttons; ++i) + vbutstate[i] = SDL_JoystickGetButton(joy, i); + for(int i = 0; i < numaxes; ++i) + vaxisstate[i] = SDL_JoystickGetAxis(joy, i); +#endif +} + +void JoystickInfo::TestForce() +{ +} diff --git a/plugins/zeropad/Windows/libs/pthread.h b/plugins/zeropad/Windows/libs/pthread.h index a0add29f5c..eddbb536f8 100644 --- a/plugins/zeropad/Windows/libs/pthread.h +++ b/plugins/zeropad/Windows/libs/pthread.h @@ -1,1368 +1,1368 @@ -/* This is an implementation of the threads API of POSIX 1003.1-2001. - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#if !defined( PTHREAD_H ) -#define PTHREAD_H - -/* - * See the README file for an explanation of the pthreads-win32 version - * numbering scheme and how the DLL is named etc. - */ -#define PTW32_VERSION 2,7,0,0 -#define PTW32_VERSION_STRING "2, 7, 0, 0\0" - -/* There are three implementations of cancel cleanup. - * Note that pthread.h is included in both application - * compilation units and also internally for the library. - * The code here and within the library aims to work - * for all reasonable combinations of environments. - * - * The three implementations are: - * - * WIN32 SEH - * C - * C++ - * - * Please note that exiting a push/pop block via - * "return", "exit", "break", or "continue" will - * lead to different behaviour amongst applications - * depending upon whether the library was built - * using SEH, C++, or C. For example, a library built - * with SEH will call the cleanup routine, while both - * C++ and C built versions will not. - */ - -/* - * Define defaults for cleanup code. - * Note: Unless the build explicitly defines one of the following, then - * we default to standard C style cleanup. This style uses setjmp/longjmp - * in the cancelation and thread exit implementations and therefore won't - * do stack unwinding if linked to applications that have it (e.g. - * C++ apps). This is currently consistent with most/all commercial Unix - * POSIX threads implementations. - */ -#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C ) -# define __CLEANUP_C -#endif - -#if defined( __CLEANUP_SEH ) && ( !defined( _MSC_VER ) && !defined(PTW32_RC_MSC)) -#error ERROR [__FILE__, line __LINE__]: SEH is not supported for this compiler. -#endif - -/* - * Stop here if we are being included by the resource compiler. - */ -#ifndef RC_INVOKED - -#undef PTW32_LEVEL - -#if defined(_POSIX_SOURCE) -#define PTW32_LEVEL 0 -/* Early POSIX */ -#endif - -#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 -#undef PTW32_LEVEL -#define PTW32_LEVEL 1 -/* Include 1b, 1c and 1d */ -#endif - -#if defined(INCLUDE_NP) -#undef PTW32_LEVEL -#define PTW32_LEVEL 2 -/* Include Non-Portable extensions */ -#endif - -#define PTW32_LEVEL_MAX 3 - -#if !defined(PTW32_LEVEL) -#define PTW32_LEVEL PTW32_LEVEL_MAX -/* Include everything */ -#endif - -#ifdef _UWIN -# define HAVE_STRUCT_TIMESPEC 1 -# define HAVE_SIGNAL_H 1 -# undef HAVE_CONFIG_H -# pragma comment(lib, "pthread") -#endif - -/* - * ------------------------------------------------------------- - * - * - * Module: pthread.h - * - * Purpose: - * Provides an implementation of PThreads based upon the - * standard: - * - * POSIX 1003.1-2001 - * and - * The Single Unix Specification version 3 - * - * (these two are equivalent) - * - * in order to enhance code portability between Windows, - * various commercial Unix implementations, and Linux. - * - * See the ANNOUNCE file for a full list of conforming - * routines and defined constants, and a list of missing - * routines and constants not defined in this implementation. - * - * Authors: - * There have been many contributors to this library. - * The initial implementation was contributed by - * John Bossom, and several others have provided major - * sections or revisions of parts of the implementation. - * Often significant effort has been contributed to - * find and fix important bugs and other problems to - * improve the reliability of the library, which sometimes - * is not reflected in the amount of code which changed as - * result. - * As much as possible, the contributors are acknowledged - * in the ChangeLog file in the source code distribution - * where their changes are noted in detail. - * - * Contributors are listed in the CONTRIBUTORS file. - * - * As usual, all bouquets go to the contributors, and all - * brickbats go to the project maintainer. - * - * Maintainer: - * The code base for this project is coordinated and - * eventually pre-tested, packaged, and made available by - * - * Ross Johnson - * - * QA Testers: - * Ultimately, the library is tested in the real world by - * a host of competent and demanding scientists and - * engineers who report bugs and/or provide solutions - * which are then fixed or incorporated into subsequent - * versions of the library. Each time a bug is fixed, a - * test case is written to prove the fix and ensure - * that later changes to the code don't reintroduce the - * same error. The number of test cases is slowly growing - * and therefore so is the code reliability. - * - * Compliance: - * See the file ANNOUNCE for the list of implemented - * and not-implemented routines and defined options. - * Of course, these are all defined is this file as well. - * - * Web site: - * The source code and other information about this library - * are available from - * - * http://sources.redhat.com/pthreads-win32/ - * - * ------------------------------------------------------------- - */ - -/* Try to avoid including windows.h */ -#if defined(__MINGW32__) && defined(__cplusplus) -#define PTW32_INCLUDE_WINDOWS_H -#endif - -#ifdef PTW32_INCLUDE_WINDOWS_H -#include -#endif - -#if defined(_MSC_VER) && _MSC_VER < 1300 || defined(__DMC__) -/* - * VC++6.0 or early compiler's header has no DWORD_PTR type. - */ -typedef unsigned long DWORD_PTR; -#endif -/* - * ----------------- - * autoconf switches - * ----------------- - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#ifndef NEED_FTIME -#include -#else /* NEED_FTIME */ -/* use native WIN32 time API */ -#endif /* NEED_FTIME */ - -#if HAVE_SIGNAL_H -#include -#endif /* HAVE_SIGNAL_H */ - -#include -#include - -/* - * Boolean values to make us independent of system includes. - */ -enum { - PTW32_FALSE = 0, - PTW32_TRUE = (! PTW32_FALSE) -}; - -/* - * This is a duplicate of what is in the autoconf config.h, - * which is only used when building the pthread-win32 libraries. - */ - -#ifndef PTW32_CONFIG_H -# if defined(WINCE) -# define NEED_ERRNO -# define NEED_SEM -# endif -# if defined(_UWIN) || defined(__MINGW32__) -# define HAVE_MODE_T -# endif -#endif - -/* - * - */ - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX -#ifdef NEED_ERRNO -#include "need_errno.h" -#else -#include -#endif -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -/* - * Several systems don't define some error numbers. - */ -#ifndef ENOTSUP -# define ENOTSUP 48 /* This is the value in Solaris. */ -#endif - -#ifndef ETIMEDOUT -# define ETIMEDOUT 10060 /* This is the value in winsock.h. */ -#endif - -#ifndef ENOSYS -# define ENOSYS 140 /* Semi-arbitrary value */ -#endif - -#ifndef EDEADLK -# ifdef EDEADLOCK -# define EDEADLK EDEADLOCK -# else -# define EDEADLK 36 /* This is the value in MSVC. */ -# endif -#endif - -#include - -/* - * To avoid including windows.h we define only those things that we - * actually need from it. - */ -#ifndef PTW32_INCLUDE_WINDOWS_H -#ifndef HANDLE -# define PTW32__HANDLE_DEF -# define HANDLE void * -#endif -#ifndef DWORD -# define PTW32__DWORD_DEF -# define DWORD unsigned long -#endif -#endif - -#ifndef HAVE_STRUCT_TIMESPEC -#define HAVE_STRUCT_TIMESPEC 1 -struct timespec { - long tv_sec; - long tv_nsec; -}; -#endif /* HAVE_STRUCT_TIMESPEC */ - -#ifndef SIG_BLOCK -#define SIG_BLOCK 0 -#endif /* SIG_BLOCK */ - -#ifndef SIG_UNBLOCK -#define SIG_UNBLOCK 1 -#endif /* SIG_UNBLOCK */ - -#ifndef SIG_SETMASK -#define SIG_SETMASK 2 -#endif /* SIG_SETMASK */ - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - -/* - * ------------------------------------------------------------- - * - * POSIX 1003.1-2001 Options - * ========================= - * - * Options are normally set in , which is not provided - * with pthreads-win32. - * - * For conformance with the Single Unix Specification (version 3), all of the - * options below are defined, and have a value of either -1 (not supported) - * or 200112L (supported). - * - * These options can neither be left undefined nor have a value of 0, because - * either indicates that sysconf(), which is not implemented, may be used at - * runtime to check the status of the option. - * - * _POSIX_THREADS (== 200112L) - * If == 200112L, you can use threads - * - * _POSIX_THREAD_ATTR_STACKSIZE (== 200112L) - * If == 200112L, you can control the size of a thread's - * stack - * pthread_attr_getstacksize - * pthread_attr_setstacksize - * - * _POSIX_THREAD_ATTR_STACKADDR (== -1) - * If == 200112L, you can allocate and control a thread's - * stack. If not supported, the following functions - * will return ENOSYS, indicating they are not - * supported: - * pthread_attr_getstackaddr - * pthread_attr_setstackaddr - * - * _POSIX_THREAD_PRIORITY_SCHEDULING (== -1) - * If == 200112L, you can use realtime scheduling. - * This option indicates that the behaviour of some - * implemented functions conforms to the additional TPS - * requirements in the standard. E.g. rwlocks favour - * writers over readers when threads have equal priority. - * - * _POSIX_THREAD_PRIO_INHERIT (== -1) - * If == 200112L, you can create priority inheritance - * mutexes. - * pthread_mutexattr_getprotocol + - * pthread_mutexattr_setprotocol + - * - * _POSIX_THREAD_PRIO_PROTECT (== -1) - * If == 200112L, you can create priority ceiling mutexes - * Indicates the availability of: - * pthread_mutex_getprioceiling - * pthread_mutex_setprioceiling - * pthread_mutexattr_getprioceiling - * pthread_mutexattr_getprotocol + - * pthread_mutexattr_setprioceiling - * pthread_mutexattr_setprotocol + - * - * _POSIX_THREAD_PROCESS_SHARED (== -1) - * If set, you can create mutexes and condition - * variables that can be shared with another - * process.If set, indicates the availability - * of: - * pthread_mutexattr_getpshared - * pthread_mutexattr_setpshared - * pthread_condattr_getpshared - * pthread_condattr_setpshared - * - * _POSIX_THREAD_SAFE_FUNCTIONS (== 200112L) - * If == 200112L you can use the special *_r library - * functions that provide thread-safe behaviour - * - * _POSIX_READER_WRITER_LOCKS (== 200112L) - * If == 200112L, you can use read/write locks - * - * _POSIX_SPIN_LOCKS (== 200112L) - * If == 200112L, you can use spin locks - * - * _POSIX_BARRIERS (== 200112L) - * If == 200112L, you can use barriers - * - * + These functions provide both 'inherit' and/or - * 'protect' protocol, based upon these macro - * settings. - * - * ------------------------------------------------------------- - */ - -/* - * POSIX Options - */ -#undef _POSIX_THREADS -#define _POSIX_THREADS 200112L - -#undef _POSIX_READER_WRITER_LOCKS -#define _POSIX_READER_WRITER_LOCKS 200112L - -#undef _POSIX_SPIN_LOCKS -#define _POSIX_SPIN_LOCKS 200112L - -#undef _POSIX_BARRIERS -#define _POSIX_BARRIERS 200112L - -#undef _POSIX_THREAD_SAFE_FUNCTIONS -#define _POSIX_THREAD_SAFE_FUNCTIONS 200112L - -#undef _POSIX_THREAD_ATTR_STACKSIZE -#define _POSIX_THREAD_ATTR_STACKSIZE 200112L - -/* - * The following options are not supported - */ -#undef _POSIX_THREAD_ATTR_STACKADDR -#define _POSIX_THREAD_ATTR_STACKADDR -1 - -#undef _POSIX_THREAD_PRIO_INHERIT -#define _POSIX_THREAD_PRIO_INHERIT -1 - -#undef _POSIX_THREAD_PRIO_PROTECT -#define _POSIX_THREAD_PRIO_PROTECT -1 - -/* TPS is not fully supported. */ -#undef _POSIX_THREAD_PRIORITY_SCHEDULING -#define _POSIX_THREAD_PRIORITY_SCHEDULING -1 - -#undef _POSIX_THREAD_PROCESS_SHARED -#define _POSIX_THREAD_PROCESS_SHARED -1 - - -/* - * POSIX 1003.1-2001 Limits - * =========================== - * - * These limits are normally set in , which is not provided with - * pthreads-win32. - * - * PTHREAD_DESTRUCTOR_ITERATIONS - * Maximum number of attempts to destroy - * a thread's thread-specific data on - * termination (must be at least 4) - * - * PTHREAD_KEYS_MAX - * Maximum number of thread-specific data keys - * available per process (must be at least 128) - * - * PTHREAD_STACK_MIN - * Minimum supported stack size for a thread - * - * PTHREAD_THREADS_MAX - * Maximum number of threads supported per - * process (must be at least 64). - * - * SEM_NSEMS_MAX - * The maximum number of semaphores a process can have. - * (must be at least 256) - * - * SEM_VALUE_MAX - * The maximum value a semaphore can have. - * (must be at least 32767) - * - */ -#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS -#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 - -#undef PTHREAD_DESTRUCTOR_ITERATIONS -#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS - -#undef _POSIX_THREAD_KEYS_MAX -#define _POSIX_THREAD_KEYS_MAX 128 - -#undef PTHREAD_KEYS_MAX -#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX - -#undef PTHREAD_STACK_MIN -#define PTHREAD_STACK_MIN 0 - -#undef _POSIX_THREAD_THREADS_MAX -#define _POSIX_THREAD_THREADS_MAX 64 - - /* Arbitrary value */ -#undef PTHREAD_THREADS_MAX -#define PTHREAD_THREADS_MAX 2019 - -#undef _POSIX_SEM_NSEMS_MAX -#define _POSIX_SEM_NSEMS_MAX 256 - - /* Arbitrary value */ -#undef SEM_NSEMS_MAX -#define SEM_NSEMS_MAX 1024 - -#undef _POSIX_SEM_VALUE_MAX -#define _POSIX_SEM_VALUE_MAX 32767 - -#undef SEM_VALUE_MAX -#define SEM_VALUE_MAX INT_MAX - - -#if __GNUC__ && ! defined (__declspec) -# error Please upgrade your GNU compiler to one that supports __declspec. -#endif - -/* - * When building the DLL code, you should define PTW32_BUILD so that - * the variables/functions are exported correctly. When using the DLL, - * do NOT define PTW32_BUILD, and then the variables/functions will - * be imported correctly. - */ -#ifndef PTW32_STATIC_LIB -# ifdef PTW32_BUILD -# define PTW32_DLLPORT __declspec (dllexport) -# else -# define PTW32_DLLPORT __declspec (dllimport) -# endif -#else -# define PTW32_DLLPORT -#endif - -/* - * The Open Watcom C/C++ compiler uses a non-standard calling convention - * that passes function args in registers unless __cdecl is explicitly specified - * in exposed function prototypes. - * - * We force all calls to cdecl even though this could slow Watcom code down - * slightly. If you know that the Watcom compiler will be used to build both - * the DLL and application, then you can probably define this as a null string. - * Remember that pthread.h (this file) is used for both the DLL and application builds. - */ -#define PTW32_CDECL __cdecl - -#if defined(_UWIN) && PTW32_LEVEL >= PTW32_LEVEL_MAX -# include -#else -/* - * Generic handle type - intended to extend uniqueness beyond - * that available with a simple pointer. It should scale for either - * IA-32 or IA-64. - */ -typedef struct { - void * p; /* Pointer to actual object */ - unsigned int x; /* Extra information - reuse count etc */ -} ptw32_handle_t; - -typedef ptw32_handle_t pthread_t; -typedef struct pthread_attr_t_ * pthread_attr_t; -typedef struct pthread_once_t_ pthread_once_t; -typedef struct pthread_key_t_ * pthread_key_t; -typedef struct pthread_mutex_t_ * pthread_mutex_t; -typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t; -typedef struct pthread_cond_t_ * pthread_cond_t; -typedef struct pthread_condattr_t_ * pthread_condattr_t; -#endif -typedef struct pthread_rwlock_t_ * pthread_rwlock_t; -typedef struct pthread_rwlockattr_t_ * pthread_rwlockattr_t; -typedef struct pthread_spinlock_t_ * pthread_spinlock_t; -typedef struct pthread_barrier_t_ * pthread_barrier_t; -typedef struct pthread_barrierattr_t_ * pthread_barrierattr_t; - -/* - * ==================== - * ==================== - * POSIX Threads - * ==================== - * ==================== - */ - -enum { -/* - * pthread_attr_{get,set}detachstate - */ - PTHREAD_CREATE_JOINABLE = 0, /* Default */ - PTHREAD_CREATE_DETACHED = 1, - -/* - * pthread_attr_{get,set}inheritsched - */ - PTHREAD_INHERIT_SCHED = 0, - PTHREAD_EXPLICIT_SCHED = 1, /* Default */ - -/* - * pthread_{get,set}scope - */ - PTHREAD_SCOPE_PROCESS = 0, - PTHREAD_SCOPE_SYSTEM = 1, /* Default */ - -/* - * pthread_setcancelstate paramters - */ - PTHREAD_CANCEL_ENABLE = 0, /* Default */ - PTHREAD_CANCEL_DISABLE = 1, - -/* - * pthread_setcanceltype parameters - */ - PTHREAD_CANCEL_ASYNCHRONOUS = 0, - PTHREAD_CANCEL_DEFERRED = 1, /* Default */ - -/* - * pthread_mutexattr_{get,set}pshared - * pthread_condattr_{get,set}pshared - */ - PTHREAD_PROCESS_PRIVATE = 0, - PTHREAD_PROCESS_SHARED = 1, - -/* - * pthread_barrier_wait - */ - PTHREAD_BARRIER_SERIAL_THREAD = -1 -}; - -/* - * ==================== - * ==================== - * Cancelation - * ==================== - * ==================== - */ -#define PTHREAD_CANCELED ((void *) -1) - - -/* - * ==================== - * ==================== - * Once Key - * ==================== - * ==================== - */ -#define PTHREAD_ONCE_INIT { PTW32_FALSE, 0, 0, 0} - -struct pthread_once_t_ -{ - int done; /* indicates if user function has been executed */ - void * lock; - int reserved1; - int reserved2; -}; - - -/* - * ==================== - * ==================== - * Object initialisers - * ==================== - * ==================== - */ -#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) -1) -#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t) -2) -#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t) -3) - -/* - * Compatibility with LinuxThreads - */ -#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER -#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER - -#define PTHREAD_COND_INITIALIZER ((pthread_cond_t) -1) - -#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) -1) - -#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t) -1) - - -/* - * Mutex types. - */ -enum -{ - /* Compatibility with LinuxThreads */ - PTHREAD_MUTEX_FAST_NP, - PTHREAD_MUTEX_RECURSIVE_NP, - PTHREAD_MUTEX_ERRORCHECK_NP, - PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP, - PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP, - /* For compatibility with POSIX */ - PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP, - PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, - PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, - PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL -}; - - -typedef struct ptw32_cleanup_t ptw32_cleanup_t; - -#if defined(_MSC_VER) -/* Disable MSVC 'anachronism used' warning */ -#pragma warning( disable : 4229 ) -#endif - -typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *); - -#if defined(_MSC_VER) -#pragma warning( default : 4229 ) -#endif - -struct ptw32_cleanup_t -{ - ptw32_cleanup_callback_t routine; - void *arg; - struct ptw32_cleanup_t *prev; -}; - -#ifdef __CLEANUP_SEH - /* - * WIN32 SEH version of cancel cleanup. - */ - -#define pthread_cleanup_push( _rout, _arg ) \ - { \ - ptw32_cleanup_t _cleanup; \ - \ - _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \ - _cleanup.arg = (_arg); \ - __try \ - { \ - -#define pthread_cleanup_pop( _execute ) \ - } \ - __finally \ - { \ - if( _execute || AbnormalTermination()) \ - { \ - (*(_cleanup.routine))( _cleanup.arg ); \ - } \ - } \ - } - -#else /* __CLEANUP_SEH */ - -#ifdef __CLEANUP_C - - /* - * C implementation of PThreads cancel cleanup - */ - -#define pthread_cleanup_push( _rout, _arg ) \ - { \ - ptw32_cleanup_t _cleanup; \ - \ - ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \ - -#define pthread_cleanup_pop( _execute ) \ - (void) ptw32_pop_cleanup( _execute ); \ - } - -#else /* __CLEANUP_C */ - -#ifdef __CLEANUP_CXX - - /* - * C++ version of cancel cleanup. - * - John E. Bossom. - */ - - class PThreadCleanup { - /* - * PThreadCleanup - * - * Purpose - * This class is a C++ helper class that is - * used to implement pthread_cleanup_push/ - * pthread_cleanup_pop. - * The destructor of this class automatically - * pops the pushed cleanup routine regardless - * of how the code exits the scope - * (i.e. such as by an exception) - */ - ptw32_cleanup_callback_t cleanUpRout; - void * obj; - int executeIt; - - public: - PThreadCleanup() : - cleanUpRout( 0 ), - obj( 0 ), - executeIt( 0 ) - /* - * No cleanup performed - */ - { - } - - PThreadCleanup( - ptw32_cleanup_callback_t routine, - void * arg ) : - cleanUpRout( routine ), - obj( arg ), - executeIt( 1 ) - /* - * Registers a cleanup routine for 'arg' - */ - { - } - - ~PThreadCleanup() - { - if ( executeIt && ((void *) cleanUpRout != (void *) 0) ) - { - (void) (*cleanUpRout)( obj ); - } - } - - void execute( int exec ) - { - executeIt = exec; - } - }; - - /* - * C++ implementation of PThreads cancel cleanup; - * This implementation takes advantage of a helper - * class who's destructor automatically calls the - * cleanup routine if we exit our scope weirdly - */ -#define pthread_cleanup_push( _rout, _arg ) \ - { \ - PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \ - (void *) (_arg) ); - -#define pthread_cleanup_pop( _execute ) \ - cleanup.execute( _execute ); \ - } - -#else - -#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. - -#endif /* __CLEANUP_CXX */ - -#endif /* __CLEANUP_C */ - -#endif /* __CLEANUP_SEH */ - -/* - * =============== - * =============== - * Methods - * =============== - * =============== - */ - -/* - * PThread Attribute Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getdetachstate (const pthread_attr_t * attr, - int *detachstate); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstackaddr (const pthread_attr_t * attr, - void **stackaddr); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstacksize (const pthread_attr_t * attr, - size_t * stacksize); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setdetachstate (pthread_attr_t * attr, - int detachstate); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstackaddr (pthread_attr_t * attr, - void *stackaddr); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstacksize (pthread_attr_t * attr, - size_t stacksize); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedparam (const pthread_attr_t *attr, - struct sched_param *param); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedparam (pthread_attr_t *attr, - const struct sched_param *param); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedpolicy (pthread_attr_t *, - int); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedpolicy (pthread_attr_t *, - int *); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setinheritsched(pthread_attr_t * attr, - int inheritsched); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getinheritsched(pthread_attr_t * attr, - int * inheritsched); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_setscope (pthread_attr_t *, - int); - -PTW32_DLLPORT int PTW32_CDECL pthread_attr_getscope (const pthread_attr_t *, - int *); - -/* - * PThread Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid, - const pthread_attr_t * attr, - void *(*start) (void *), - void *arg); - -PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid); - -PTW32_DLLPORT int PTW32_CDECL pthread_equal (pthread_t t1, - pthread_t t2); - -PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr); - -PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread, - void **value_ptr); - -PTW32_DLLPORT pthread_t PTW32_CDECL pthread_self (void); - -PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread); - -PTW32_DLLPORT int PTW32_CDECL pthread_setcancelstate (int state, - int *oldstate); - -PTW32_DLLPORT int PTW32_CDECL pthread_setcanceltype (int type, - int *oldtype); - -PTW32_DLLPORT void PTW32_CDECL pthread_testcancel (void); - -PTW32_DLLPORT int PTW32_CDECL pthread_once (pthread_once_t * once_control, - void (*init_routine) (void)); - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX -PTW32_DLLPORT ptw32_cleanup_t * PTW32_CDECL ptw32_pop_cleanup (int execute); - -PTW32_DLLPORT void PTW32_CDECL ptw32_push_cleanup (ptw32_cleanup_t * cleanup, - void (*routine) (void *), - void *arg); -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -/* - * Thread Specific Data Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_key_create (pthread_key_t * key, - void (*destructor) (void *)); - -PTW32_DLLPORT int PTW32_CDECL pthread_key_delete (pthread_key_t key); - -PTW32_DLLPORT int PTW32_CDECL pthread_setspecific (pthread_key_t key, - const void *value); - -PTW32_DLLPORT void * PTW32_CDECL pthread_getspecific (pthread_key_t key); - - -/* - * Mutex Attribute Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_init (pthread_mutexattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_destroy (pthread_mutexattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getpshared (const pthread_mutexattr_t - * attr, - int *pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, - int pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind); -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind); - -/* - * Barrier Attribute Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_init (pthread_barrierattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_destroy (pthread_barrierattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_getpshared (const pthread_barrierattr_t - * attr, - int *pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, - int pshared); - -/* - * Mutex Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex, - const pthread_mutexattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t *mutex, - const struct timespec *abstime); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex); - -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex); - -/* - * Spinlock Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_spin_init (pthread_spinlock_t * lock, int pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_spin_destroy (pthread_spinlock_t * lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_spin_lock (pthread_spinlock_t * lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_spin_trylock (pthread_spinlock_t * lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_spin_unlock (pthread_spinlock_t * lock); - -/* - * Barrier Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_barrier_init (pthread_barrier_t * barrier, - const pthread_barrierattr_t * attr, - unsigned int count); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrier_destroy (pthread_barrier_t * barrier); - -PTW32_DLLPORT int PTW32_CDECL pthread_barrier_wait (pthread_barrier_t * barrier); - -/* - * Condition Variable Attribute Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_condattr_init (pthread_condattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_condattr_destroy (pthread_condattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_condattr_getpshared (const pthread_condattr_t * attr, - int *pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_condattr_setpshared (pthread_condattr_t * attr, - int pshared); - -/* - * Condition Variable Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_cond_init (pthread_cond_t * cond, - const pthread_condattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_destroy (pthread_cond_t * cond); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_wait (pthread_cond_t * cond, - pthread_mutex_t * mutex); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_timedwait (pthread_cond_t * cond, - pthread_mutex_t * mutex, - const struct timespec *abstime); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_signal (pthread_cond_t * cond); - -PTW32_DLLPORT int PTW32_CDECL pthread_cond_broadcast (pthread_cond_t * cond); - -/* - * Scheduling - */ -PTW32_DLLPORT int PTW32_CDECL pthread_setschedparam (pthread_t thread, - int policy, - const struct sched_param *param); - -PTW32_DLLPORT int PTW32_CDECL pthread_getschedparam (pthread_t thread, - int *policy, - struct sched_param *param); - -PTW32_DLLPORT int PTW32_CDECL pthread_setconcurrency (int); - -PTW32_DLLPORT int PTW32_CDECL pthread_getconcurrency (void); - -/* - * Read-Write Lock Functions - */ -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_init(pthread_rwlock_t *lock, - const pthread_rwlockattr_t *attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_destroy(pthread_rwlock_t *lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_tryrdlock(pthread_rwlock_t *); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_trywrlock(pthread_rwlock_t *); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_rdlock(pthread_rwlock_t *lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedrdlock(pthread_rwlock_t *lock, - const struct timespec *abstime); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_wrlock(pthread_rwlock_t *lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedwrlock(pthread_rwlock_t *lock, - const struct timespec *abstime); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_unlock(pthread_rwlock_t *lock); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_init (pthread_rwlockattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, - int *pshared); - -PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, - int pshared); - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 - -/* - * Signal Functions. Should be defined in but MSVC and MinGW32 - * already have signal.h that don't define these. - */ -PTW32_DLLPORT int PTW32_CDECL pthread_kill(pthread_t thread, int sig); - -/* - * Non-portable functions - */ - -/* - * Compatibility with Linux. - */ -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, - int kind); -PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, - int *kind); - -/* - * Possibly supported by other POSIX threads implementations - */ -PTW32_DLLPORT int PTW32_CDECL pthread_delay_np (struct timespec * interval); -PTW32_DLLPORT int PTW32_CDECL pthread_num_processors_np(void); - -/* - * Useful if an application wants to statically link - * the lib rather than load the DLL at run-time. - */ -PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_attach_np(void); -PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_detach_np(void); -PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_attach_np(void); -PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_detach_np(void); - -/* - * Features that are auto-detected at load/run time. - */ -PTW32_DLLPORT int PTW32_CDECL pthread_win32_test_features_np(int); -enum ptw32_features { - PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE = 0x0001, /* System provides it. */ - PTW32_ALERTABLE_ASYNC_CANCEL = 0x0002 /* Can cancel blocked threads. */ -}; - -/* - * Register a system time change with the library. - * Causes the library to perform various functions - * in response to the change. Should be called whenever - * the application's top level window receives a - * WM_TIMECHANGE message. It can be passed directly to - * pthread_create() as a new thread if desired. - */ -PTW32_DLLPORT void * PTW32_CDECL pthread_timechange_handler_np(void *); - -#endif /*PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 */ - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX - -/* - * Returns the Win32 HANDLE for the POSIX thread. - */ -PTW32_DLLPORT HANDLE PTW32_CDECL pthread_getw32threadhandle_np(pthread_t thread); - - -/* - * Protected Methods - * - * This function blocks until the given WIN32 handle - * is signaled or pthread_cancel had been called. - * This function allows the caller to hook into the - * PThreads cancel mechanism. It is implemented using - * - * WaitForMultipleObjects - * - * on 'waitHandle' and a manually reset WIN32 Event - * used to implement pthread_cancel. The 'timeout' - * argument to TimedWait is simply passed to - * WaitForMultipleObjects. - */ -PTW32_DLLPORT int PTW32_CDECL pthreadCancelableWait (HANDLE waitHandle); -PTW32_DLLPORT int PTW32_CDECL pthreadCancelableTimedWait (HANDLE waitHandle, - DWORD timeout); - -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -/* - * Thread-Safe C Runtime Library Mappings. - */ -#ifndef _UWIN -# if defined(NEED_ERRNO) - PTW32_DLLPORT int * PTW32_CDECL _errno( void ); -# else -# ifndef errno -# if (defined(_MT) || defined(_DLL)) - __declspec(dllimport) extern int * __cdecl _errno(void); -# define errno (*_errno()) -# endif -# endif -# endif -#endif - -/* - * WIN32 C runtime library had been made thread-safe - * without affecting the user interface. Provide - * mappings from the UNIX thread-safe versions to - * the standard C runtime library calls. - * Only provide function mappings for functions that - * actually exist on WIN32. - */ - -#if !defined(__MINGW32__) -#define strtok_r( _s, _sep, _lasts ) \ - ( *(_lasts) = strtok( (_s), (_sep) ) ) -#endif /* !__MINGW32__ */ - -#define asctime_r( _tm, _buf ) \ - ( strcpy( (_buf), asctime( (_tm) ) ), \ - (_buf) ) - -#define ctime_r( _clock, _buf ) \ - ( strcpy( (_buf), ctime( (_clock) ) ), \ - (_buf) ) - -#define gmtime_r( _clock, _result ) \ - ( *(_result) = *gmtime( (_clock) ), \ - (_result) ) - -#define localtime_r( _clock, _result ) \ - ( *(_result) = *localtime( (_clock) ), \ - (_result) ) - -#define rand_r( _seed ) \ - ( _seed == _seed? rand() : rand() ) - - -/* - * Some compiler environments don't define some things. - */ -#if defined(__BORLANDC__) -# define _ftime ftime -# define _timeb timeb -#endif - -#ifdef __cplusplus - -/* - * Internal exceptions - */ -class ptw32_exception {}; -class ptw32_exception_cancel : public ptw32_exception {}; -class ptw32_exception_exit : public ptw32_exception {}; - -#endif - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX - -/* FIXME: This is only required if the library was built using SEH */ -/* - * Get internal SEH tag - */ -PTW32_DLLPORT DWORD PTW32_CDECL ptw32_get_exception_services_code(void); - -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -#ifndef PTW32_BUILD - -#ifdef __CLEANUP_SEH - -/* - * Redefine the SEH __except keyword to ensure that applications - * propagate our internal exceptions up to the library's internal handlers. - */ -#define __except( E ) \ - __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \ - ? EXCEPTION_CONTINUE_SEARCH : ( E ) ) - -#endif /* __CLEANUP_SEH */ - -#ifdef __CLEANUP_CXX - -/* - * Redefine the C++ catch keyword to ensure that applications - * propagate our internal exceptions up to the library's internal handlers. - */ -#ifdef _MSC_VER - /* - * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll' - * if you want Pthread-Win32 cancelation and pthread_exit to work. - */ - -#ifndef PtW32NoCatchWarn - -#pragma message("Specify \"/DPtW32NoCatchWarn\" compiler flag to skip this message.") -#pragma message("------------------------------------------------------------------") -#pragma message("When compiling applications with MSVC++ and C++ exception handling:") -#pragma message(" Replace any 'catch( ... )' in routines called from POSIX threads") -#pragma message(" with 'PtW32CatchAll' or 'CATCHALL' if you want POSIX thread") -#pragma message(" cancelation and pthread_exit to work. For example:") -#pragma message("") -#pragma message(" #ifdef PtW32CatchAll") -#pragma message(" PtW32CatchAll") -#pragma message(" #else") -#pragma message(" catch(...)") -#pragma message(" #endif") -#pragma message(" {") -#pragma message(" /* Catchall block processing */") -#pragma message(" }") -#pragma message("------------------------------------------------------------------") - -#endif - -#define PtW32CatchAll \ - catch( ptw32_exception & ) { throw; } \ - catch( ... ) - -#else /* _MSC_VER */ - -#define catch( E ) \ - catch( ptw32_exception & ) { throw; } \ - catch( E ) - -#endif /* _MSC_VER */ - -#endif /* __CLEANUP_CXX */ - -#endif /* ! PTW32_BUILD */ - -#ifdef __cplusplus -} /* End of extern "C" */ -#endif /* __cplusplus */ - -#ifdef PTW32__HANDLE_DEF -# undef HANDLE -#endif -#ifdef PTW32__DWORD_DEF -# undef DWORD -#endif - -#undef PTW32_LEVEL -#undef PTW32_LEVEL_MAX - -#endif /* ! RC_INVOKED */ - -#endif /* PTHREAD_H */ +/* This is an implementation of the threads API of POSIX 1003.1-2001. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if !defined( PTHREAD_H ) +#define PTHREAD_H + +/* + * See the README file for an explanation of the pthreads-win32 version + * numbering scheme and how the DLL is named etc. + */ +#define PTW32_VERSION 2,7,0,0 +#define PTW32_VERSION_STRING "2, 7, 0, 0\0" + +/* There are three implementations of cancel cleanup. + * Note that pthread.h is included in both application + * compilation units and also internally for the library. + * The code here and within the library aims to work + * for all reasonable combinations of environments. + * + * The three implementations are: + * + * WIN32 SEH + * C + * C++ + * + * Please note that exiting a push/pop block via + * "return", "exit", "break", or "continue" will + * lead to different behaviour amongst applications + * depending upon whether the library was built + * using SEH, C++, or C. For example, a library built + * with SEH will call the cleanup routine, while both + * C++ and C built versions will not. + */ + +/* + * Define defaults for cleanup code. + * Note: Unless the build explicitly defines one of the following, then + * we default to standard C style cleanup. This style uses setjmp/longjmp + * in the cancelation and thread exit implementations and therefore won't + * do stack unwinding if linked to applications that have it (e.g. + * C++ apps). This is currently consistent with most/all commercial Unix + * POSIX threads implementations. + */ +#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C ) +# define __CLEANUP_C +#endif + +#if defined( __CLEANUP_SEH ) && ( !defined( _MSC_VER ) && !defined(PTW32_RC_MSC)) +#error ERROR [__FILE__, line __LINE__]: SEH is not supported for this compiler. +#endif + +/* + * Stop here if we are being included by the resource compiler. + */ +#ifndef RC_INVOKED + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + +#ifdef _UWIN +# define HAVE_STRUCT_TIMESPEC 1 +# define HAVE_SIGNAL_H 1 +# undef HAVE_CONFIG_H +# pragma comment(lib, "pthread") +#endif + +/* + * ------------------------------------------------------------- + * + * + * Module: pthread.h + * + * Purpose: + * Provides an implementation of PThreads based upon the + * standard: + * + * POSIX 1003.1-2001 + * and + * The Single Unix Specification version 3 + * + * (these two are equivalent) + * + * in order to enhance code portability between Windows, + * various commercial Unix implementations, and Linux. + * + * See the ANNOUNCE file for a full list of conforming + * routines and defined constants, and a list of missing + * routines and constants not defined in this implementation. + * + * Authors: + * There have been many contributors to this library. + * The initial implementation was contributed by + * John Bossom, and several others have provided major + * sections or revisions of parts of the implementation. + * Often significant effort has been contributed to + * find and fix important bugs and other problems to + * improve the reliability of the library, which sometimes + * is not reflected in the amount of code which changed as + * result. + * As much as possible, the contributors are acknowledged + * in the ChangeLog file in the source code distribution + * where their changes are noted in detail. + * + * Contributors are listed in the CONTRIBUTORS file. + * + * As usual, all bouquets go to the contributors, and all + * brickbats go to the project maintainer. + * + * Maintainer: + * The code base for this project is coordinated and + * eventually pre-tested, packaged, and made available by + * + * Ross Johnson + * + * QA Testers: + * Ultimately, the library is tested in the real world by + * a host of competent and demanding scientists and + * engineers who report bugs and/or provide solutions + * which are then fixed or incorporated into subsequent + * versions of the library. Each time a bug is fixed, a + * test case is written to prove the fix and ensure + * that later changes to the code don't reintroduce the + * same error. The number of test cases is slowly growing + * and therefore so is the code reliability. + * + * Compliance: + * See the file ANNOUNCE for the list of implemented + * and not-implemented routines and defined options. + * Of course, these are all defined is this file as well. + * + * Web site: + * The source code and other information about this library + * are available from + * + * http://sources.redhat.com/pthreads-win32/ + * + * ------------------------------------------------------------- + */ + +/* Try to avoid including windows.h */ +#if defined(__MINGW32__) && defined(__cplusplus) +#define PTW32_INCLUDE_WINDOWS_H +#endif + +#ifdef PTW32_INCLUDE_WINDOWS_H +#include +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1300 || defined(__DMC__) +/* + * VC++6.0 or early compiler's header has no DWORD_PTR type. + */ +typedef unsigned long DWORD_PTR; +#endif +/* + * ----------------- + * autoconf switches + * ----------------- + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#ifndef NEED_FTIME +#include +#else /* NEED_FTIME */ +/* use native WIN32 time API */ +#endif /* NEED_FTIME */ + +#if HAVE_SIGNAL_H +#include +#endif /* HAVE_SIGNAL_H */ + +#include +#include + +/* + * Boolean values to make us independent of system includes. + */ +enum { + PTW32_FALSE = 0, + PTW32_TRUE = (! PTW32_FALSE) +}; + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#ifndef PTW32_CONFIG_H +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#ifdef NEED_ERRNO +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Several systems don't define some error numbers. + */ +#ifndef ENOTSUP +# define ENOTSUP 48 /* This is the value in Solaris. */ +#endif + +#ifndef ETIMEDOUT +# define ETIMEDOUT 10060 /* This is the value in winsock.h. */ +#endif + +#ifndef ENOSYS +# define ENOSYS 140 /* Semi-arbitrary value */ +#endif + +#ifndef EDEADLK +# ifdef EDEADLOCK +# define EDEADLK EDEADLOCK +# else +# define EDEADLK 36 /* This is the value in MSVC. */ +# endif +#endif + +#include + +/* + * To avoid including windows.h we define only those things that we + * actually need from it. + */ +#ifndef PTW32_INCLUDE_WINDOWS_H +#ifndef HANDLE +# define PTW32__HANDLE_DEF +# define HANDLE void * +#endif +#ifndef DWORD +# define PTW32__DWORD_DEF +# define DWORD unsigned long +#endif +#endif + +#ifndef HAVE_STRUCT_TIMESPEC +#define HAVE_STRUCT_TIMESPEC 1 +struct timespec { + long tv_sec; + long tv_nsec; +}; +#endif /* HAVE_STRUCT_TIMESPEC */ + +#ifndef SIG_BLOCK +#define SIG_BLOCK 0 +#endif /* SIG_BLOCK */ + +#ifndef SIG_UNBLOCK +#define SIG_UNBLOCK 1 +#endif /* SIG_UNBLOCK */ + +#ifndef SIG_SETMASK +#define SIG_SETMASK 2 +#endif /* SIG_SETMASK */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* + * ------------------------------------------------------------- + * + * POSIX 1003.1-2001 Options + * ========================= + * + * Options are normally set in , which is not provided + * with pthreads-win32. + * + * For conformance with the Single Unix Specification (version 3), all of the + * options below are defined, and have a value of either -1 (not supported) + * or 200112L (supported). + * + * These options can neither be left undefined nor have a value of 0, because + * either indicates that sysconf(), which is not implemented, may be used at + * runtime to check the status of the option. + * + * _POSIX_THREADS (== 200112L) + * If == 200112L, you can use threads + * + * _POSIX_THREAD_ATTR_STACKSIZE (== 200112L) + * If == 200112L, you can control the size of a thread's + * stack + * pthread_attr_getstacksize + * pthread_attr_setstacksize + * + * _POSIX_THREAD_ATTR_STACKADDR (== -1) + * If == 200112L, you can allocate and control a thread's + * stack. If not supported, the following functions + * will return ENOSYS, indicating they are not + * supported: + * pthread_attr_getstackaddr + * pthread_attr_setstackaddr + * + * _POSIX_THREAD_PRIORITY_SCHEDULING (== -1) + * If == 200112L, you can use realtime scheduling. + * This option indicates that the behaviour of some + * implemented functions conforms to the additional TPS + * requirements in the standard. E.g. rwlocks favour + * writers over readers when threads have equal priority. + * + * _POSIX_THREAD_PRIO_INHERIT (== -1) + * If == 200112L, you can create priority inheritance + * mutexes. + * pthread_mutexattr_getprotocol + + * pthread_mutexattr_setprotocol + + * + * _POSIX_THREAD_PRIO_PROTECT (== -1) + * If == 200112L, you can create priority ceiling mutexes + * Indicates the availability of: + * pthread_mutex_getprioceiling + * pthread_mutex_setprioceiling + * pthread_mutexattr_getprioceiling + * pthread_mutexattr_getprotocol + + * pthread_mutexattr_setprioceiling + * pthread_mutexattr_setprotocol + + * + * _POSIX_THREAD_PROCESS_SHARED (== -1) + * If set, you can create mutexes and condition + * variables that can be shared with another + * process.If set, indicates the availability + * of: + * pthread_mutexattr_getpshared + * pthread_mutexattr_setpshared + * pthread_condattr_getpshared + * pthread_condattr_setpshared + * + * _POSIX_THREAD_SAFE_FUNCTIONS (== 200112L) + * If == 200112L you can use the special *_r library + * functions that provide thread-safe behaviour + * + * _POSIX_READER_WRITER_LOCKS (== 200112L) + * If == 200112L, you can use read/write locks + * + * _POSIX_SPIN_LOCKS (== 200112L) + * If == 200112L, you can use spin locks + * + * _POSIX_BARRIERS (== 200112L) + * If == 200112L, you can use barriers + * + * + These functions provide both 'inherit' and/or + * 'protect' protocol, based upon these macro + * settings. + * + * ------------------------------------------------------------- + */ + +/* + * POSIX Options + */ +#undef _POSIX_THREADS +#define _POSIX_THREADS 200112L + +#undef _POSIX_READER_WRITER_LOCKS +#define _POSIX_READER_WRITER_LOCKS 200112L + +#undef _POSIX_SPIN_LOCKS +#define _POSIX_SPIN_LOCKS 200112L + +#undef _POSIX_BARRIERS +#define _POSIX_BARRIERS 200112L + +#undef _POSIX_THREAD_SAFE_FUNCTIONS +#define _POSIX_THREAD_SAFE_FUNCTIONS 200112L + +#undef _POSIX_THREAD_ATTR_STACKSIZE +#define _POSIX_THREAD_ATTR_STACKSIZE 200112L + +/* + * The following options are not supported + */ +#undef _POSIX_THREAD_ATTR_STACKADDR +#define _POSIX_THREAD_ATTR_STACKADDR -1 + +#undef _POSIX_THREAD_PRIO_INHERIT +#define _POSIX_THREAD_PRIO_INHERIT -1 + +#undef _POSIX_THREAD_PRIO_PROTECT +#define _POSIX_THREAD_PRIO_PROTECT -1 + +/* TPS is not fully supported. */ +#undef _POSIX_THREAD_PRIORITY_SCHEDULING +#define _POSIX_THREAD_PRIORITY_SCHEDULING -1 + +#undef _POSIX_THREAD_PROCESS_SHARED +#define _POSIX_THREAD_PROCESS_SHARED -1 + + +/* + * POSIX 1003.1-2001 Limits + * =========================== + * + * These limits are normally set in , which is not provided with + * pthreads-win32. + * + * PTHREAD_DESTRUCTOR_ITERATIONS + * Maximum number of attempts to destroy + * a thread's thread-specific data on + * termination (must be at least 4) + * + * PTHREAD_KEYS_MAX + * Maximum number of thread-specific data keys + * available per process (must be at least 128) + * + * PTHREAD_STACK_MIN + * Minimum supported stack size for a thread + * + * PTHREAD_THREADS_MAX + * Maximum number of threads supported per + * process (must be at least 64). + * + * SEM_NSEMS_MAX + * The maximum number of semaphores a process can have. + * (must be at least 256) + * + * SEM_VALUE_MAX + * The maximum value a semaphore can have. + * (must be at least 32767) + * + */ +#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 + +#undef PTHREAD_DESTRUCTOR_ITERATIONS +#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS + +#undef _POSIX_THREAD_KEYS_MAX +#define _POSIX_THREAD_KEYS_MAX 128 + +#undef PTHREAD_KEYS_MAX +#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX + +#undef PTHREAD_STACK_MIN +#define PTHREAD_STACK_MIN 0 + +#undef _POSIX_THREAD_THREADS_MAX +#define _POSIX_THREAD_THREADS_MAX 64 + + /* Arbitrary value */ +#undef PTHREAD_THREADS_MAX +#define PTHREAD_THREADS_MAX 2019 + +#undef _POSIX_SEM_NSEMS_MAX +#define _POSIX_SEM_NSEMS_MAX 256 + + /* Arbitrary value */ +#undef SEM_NSEMS_MAX +#define SEM_NSEMS_MAX 1024 + +#undef _POSIX_SEM_VALUE_MAX +#define _POSIX_SEM_VALUE_MAX 32767 + +#undef SEM_VALUE_MAX +#define SEM_VALUE_MAX INT_MAX + + +#if __GNUC__ && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the DLL code, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the DLL, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#ifndef PTW32_STATIC_LIB +# ifdef PTW32_BUILD +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * The Open Watcom C/C++ compiler uses a non-standard calling convention + * that passes function args in registers unless __cdecl is explicitly specified + * in exposed function prototypes. + * + * We force all calls to cdecl even though this could slow Watcom code down + * slightly. If you know that the Watcom compiler will be used to build both + * the DLL and application, then you can probably define this as a null string. + * Remember that pthread.h (this file) is used for both the DLL and application builds. + */ +#define PTW32_CDECL __cdecl + +#if defined(_UWIN) && PTW32_LEVEL >= PTW32_LEVEL_MAX +# include +#else +/* + * Generic handle type - intended to extend uniqueness beyond + * that available with a simple pointer. It should scale for either + * IA-32 or IA-64. + */ +typedef struct { + void * p; /* Pointer to actual object */ + unsigned int x; /* Extra information - reuse count etc */ +} ptw32_handle_t; + +typedef ptw32_handle_t pthread_t; +typedef struct pthread_attr_t_ * pthread_attr_t; +typedef struct pthread_once_t_ pthread_once_t; +typedef struct pthread_key_t_ * pthread_key_t; +typedef struct pthread_mutex_t_ * pthread_mutex_t; +typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t; +typedef struct pthread_cond_t_ * pthread_cond_t; +typedef struct pthread_condattr_t_ * pthread_condattr_t; +#endif +typedef struct pthread_rwlock_t_ * pthread_rwlock_t; +typedef struct pthread_rwlockattr_t_ * pthread_rwlockattr_t; +typedef struct pthread_spinlock_t_ * pthread_spinlock_t; +typedef struct pthread_barrier_t_ * pthread_barrier_t; +typedef struct pthread_barrierattr_t_ * pthread_barrierattr_t; + +/* + * ==================== + * ==================== + * POSIX Threads + * ==================== + * ==================== + */ + +enum { +/* + * pthread_attr_{get,set}detachstate + */ + PTHREAD_CREATE_JOINABLE = 0, /* Default */ + PTHREAD_CREATE_DETACHED = 1, + +/* + * pthread_attr_{get,set}inheritsched + */ + PTHREAD_INHERIT_SCHED = 0, + PTHREAD_EXPLICIT_SCHED = 1, /* Default */ + +/* + * pthread_{get,set}scope + */ + PTHREAD_SCOPE_PROCESS = 0, + PTHREAD_SCOPE_SYSTEM = 1, /* Default */ + +/* + * pthread_setcancelstate paramters + */ + PTHREAD_CANCEL_ENABLE = 0, /* Default */ + PTHREAD_CANCEL_DISABLE = 1, + +/* + * pthread_setcanceltype parameters + */ + PTHREAD_CANCEL_ASYNCHRONOUS = 0, + PTHREAD_CANCEL_DEFERRED = 1, /* Default */ + +/* + * pthread_mutexattr_{get,set}pshared + * pthread_condattr_{get,set}pshared + */ + PTHREAD_PROCESS_PRIVATE = 0, + PTHREAD_PROCESS_SHARED = 1, + +/* + * pthread_barrier_wait + */ + PTHREAD_BARRIER_SERIAL_THREAD = -1 +}; + +/* + * ==================== + * ==================== + * Cancelation + * ==================== + * ==================== + */ +#define PTHREAD_CANCELED ((void *) -1) + + +/* + * ==================== + * ==================== + * Once Key + * ==================== + * ==================== + */ +#define PTHREAD_ONCE_INIT { PTW32_FALSE, 0, 0, 0} + +struct pthread_once_t_ +{ + int done; /* indicates if user function has been executed */ + void * lock; + int reserved1; + int reserved2; +}; + + +/* + * ==================== + * ==================== + * Object initialisers + * ==================== + * ==================== + */ +#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) -1) +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t) -2) +#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t) -3) + +/* + * Compatibility with LinuxThreads + */ +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER +#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER + +#define PTHREAD_COND_INITIALIZER ((pthread_cond_t) -1) + +#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) -1) + +#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t) -1) + + +/* + * Mutex types. + */ +enum +{ + /* Compatibility with LinuxThreads */ + PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP, + /* For compatibility with POSIX */ + PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL +}; + + +typedef struct ptw32_cleanup_t ptw32_cleanup_t; + +#if defined(_MSC_VER) +/* Disable MSVC 'anachronism used' warning */ +#pragma warning( disable : 4229 ) +#endif + +typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *); + +#if defined(_MSC_VER) +#pragma warning( default : 4229 ) +#endif + +struct ptw32_cleanup_t +{ + ptw32_cleanup_callback_t routine; + void *arg; + struct ptw32_cleanup_t *prev; +}; + +#ifdef __CLEANUP_SEH + /* + * WIN32 SEH version of cancel cleanup. + */ + +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + ptw32_cleanup_t _cleanup; \ + \ + _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \ + _cleanup.arg = (_arg); \ + __try \ + { \ + +#define pthread_cleanup_pop( _execute ) \ + } \ + __finally \ + { \ + if( _execute || AbnormalTermination()) \ + { \ + (*(_cleanup.routine))( _cleanup.arg ); \ + } \ + } \ + } + +#else /* __CLEANUP_SEH */ + +#ifdef __CLEANUP_C + + /* + * C implementation of PThreads cancel cleanup + */ + +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + ptw32_cleanup_t _cleanup; \ + \ + ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \ + +#define pthread_cleanup_pop( _execute ) \ + (void) ptw32_pop_cleanup( _execute ); \ + } + +#else /* __CLEANUP_C */ + +#ifdef __CLEANUP_CXX + + /* + * C++ version of cancel cleanup. + * - John E. Bossom. + */ + + class PThreadCleanup { + /* + * PThreadCleanup + * + * Purpose + * This class is a C++ helper class that is + * used to implement pthread_cleanup_push/ + * pthread_cleanup_pop. + * The destructor of this class automatically + * pops the pushed cleanup routine regardless + * of how the code exits the scope + * (i.e. such as by an exception) + */ + ptw32_cleanup_callback_t cleanUpRout; + void * obj; + int executeIt; + + public: + PThreadCleanup() : + cleanUpRout( 0 ), + obj( 0 ), + executeIt( 0 ) + /* + * No cleanup performed + */ + { + } + + PThreadCleanup( + ptw32_cleanup_callback_t routine, + void * arg ) : + cleanUpRout( routine ), + obj( arg ), + executeIt( 1 ) + /* + * Registers a cleanup routine for 'arg' + */ + { + } + + ~PThreadCleanup() + { + if ( executeIt && ((void *) cleanUpRout != (void *) 0) ) + { + (void) (*cleanUpRout)( obj ); + } + } + + void execute( int exec ) + { + executeIt = exec; + } + }; + + /* + * C++ implementation of PThreads cancel cleanup; + * This implementation takes advantage of a helper + * class who's destructor automatically calls the + * cleanup routine if we exit our scope weirdly + */ +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \ + (void *) (_arg) ); + +#define pthread_cleanup_pop( _execute ) \ + cleanup.execute( _execute ); \ + } + +#else + +#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. + +#endif /* __CLEANUP_CXX */ + +#endif /* __CLEANUP_C */ + +#endif /* __CLEANUP_SEH */ + +/* + * =============== + * =============== + * Methods + * =============== + * =============== + */ + +/* + * PThread Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getdetachstate (const pthread_attr_t * attr, + int *detachstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstackaddr (const pthread_attr_t * attr, + void **stackaddr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstacksize (const pthread_attr_t * attr, + size_t * stacksize); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setdetachstate (pthread_attr_t * attr, + int detachstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstackaddr (pthread_attr_t * attr, + void *stackaddr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstacksize (pthread_attr_t * attr, + size_t stacksize); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedparam (const pthread_attr_t *attr, + struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedparam (pthread_attr_t *attr, + const struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedpolicy (pthread_attr_t *, + int); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedpolicy (pthread_attr_t *, + int *); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setinheritsched(pthread_attr_t * attr, + int inheritsched); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getinheritsched(pthread_attr_t * attr, + int * inheritsched); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setscope (pthread_attr_t *, + int); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getscope (const pthread_attr_t *, + int *); + +/* + * PThread Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid, + const pthread_attr_t * attr, + void *(*start) (void *), + void *arg); + +PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid); + +PTW32_DLLPORT int PTW32_CDECL pthread_equal (pthread_t t1, + pthread_t t2); + +PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr); + +PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread, + void **value_ptr); + +PTW32_DLLPORT pthread_t PTW32_CDECL pthread_self (void); + +PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread); + +PTW32_DLLPORT int PTW32_CDECL pthread_setcancelstate (int state, + int *oldstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_setcanceltype (int type, + int *oldtype); + +PTW32_DLLPORT void PTW32_CDECL pthread_testcancel (void); + +PTW32_DLLPORT int PTW32_CDECL pthread_once (pthread_once_t * once_control, + void (*init_routine) (void)); + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +PTW32_DLLPORT ptw32_cleanup_t * PTW32_CDECL ptw32_pop_cleanup (int execute); + +PTW32_DLLPORT void PTW32_CDECL ptw32_push_cleanup (ptw32_cleanup_t * cleanup, + void (*routine) (void *), + void *arg); +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Thread Specific Data Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_key_create (pthread_key_t * key, + void (*destructor) (void *)); + +PTW32_DLLPORT int PTW32_CDECL pthread_key_delete (pthread_key_t key); + +PTW32_DLLPORT int PTW32_CDECL pthread_setspecific (pthread_key_t key, + const void *value); + +PTW32_DLLPORT void * PTW32_CDECL pthread_getspecific (pthread_key_t key); + + +/* + * Mutex Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_init (pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_destroy (pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getpshared (const pthread_mutexattr_t + * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, + int pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind); + +/* + * Barrier Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_init (pthread_barrierattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_destroy (pthread_barrierattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_getpshared (const pthread_barrierattr_t + * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, + int pshared); + +/* + * Mutex Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex, + const pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t *mutex, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex); + +/* + * Spinlock Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_spin_init (pthread_spinlock_t * lock, int pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_destroy (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_lock (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_trylock (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_unlock (pthread_spinlock_t * lock); + +/* + * Barrier Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_init (pthread_barrier_t * barrier, + const pthread_barrierattr_t * attr, + unsigned int count); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_destroy (pthread_barrier_t * barrier); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_wait (pthread_barrier_t * barrier); + +/* + * Condition Variable Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_init (pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_destroy (pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_getpshared (const pthread_condattr_t * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_setpshared (pthread_condattr_t * attr, + int pshared); + +/* + * Condition Variable Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_cond_init (pthread_cond_t * cond, + const pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_destroy (pthread_cond_t * cond); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_wait (pthread_cond_t * cond, + pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_timedwait (pthread_cond_t * cond, + pthread_mutex_t * mutex, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_signal (pthread_cond_t * cond); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_broadcast (pthread_cond_t * cond); + +/* + * Scheduling + */ +PTW32_DLLPORT int PTW32_CDECL pthread_setschedparam (pthread_t thread, + int policy, + const struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_getschedparam (pthread_t thread, + int *policy, + struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_setconcurrency (int); + +PTW32_DLLPORT int PTW32_CDECL pthread_getconcurrency (void); + +/* + * Read-Write Lock Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_init(pthread_rwlock_t *lock, + const pthread_rwlockattr_t *attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_destroy(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_tryrdlock(pthread_rwlock_t *); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_trywrlock(pthread_rwlock_t *); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_rdlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedrdlock(pthread_rwlock_t *lock, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_wrlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedwrlock(pthread_rwlock_t *lock, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_unlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_init (pthread_rwlockattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, + int pshared); + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 + +/* + * Signal Functions. Should be defined in but MSVC and MinGW32 + * already have signal.h that don't define these. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_kill(pthread_t thread, int sig); + +/* + * Non-portable functions + */ + +/* + * Compatibility with Linux. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, + int kind); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, + int *kind); + +/* + * Possibly supported by other POSIX threads implementations + */ +PTW32_DLLPORT int PTW32_CDECL pthread_delay_np (struct timespec * interval); +PTW32_DLLPORT int PTW32_CDECL pthread_num_processors_np(void); + +/* + * Useful if an application wants to statically link + * the lib rather than load the DLL at run-time. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_attach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_detach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_attach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_detach_np(void); + +/* + * Features that are auto-detected at load/run time. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_win32_test_features_np(int); +enum ptw32_features { + PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE = 0x0001, /* System provides it. */ + PTW32_ALERTABLE_ASYNC_CANCEL = 0x0002 /* Can cancel blocked threads. */ +}; + +/* + * Register a system time change with the library. + * Causes the library to perform various functions + * in response to the change. Should be called whenever + * the application's top level window receives a + * WM_TIMECHANGE message. It can be passed directly to + * pthread_create() as a new thread if desired. + */ +PTW32_DLLPORT void * PTW32_CDECL pthread_timechange_handler_np(void *); + +#endif /*PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX + +/* + * Returns the Win32 HANDLE for the POSIX thread. + */ +PTW32_DLLPORT HANDLE PTW32_CDECL pthread_getw32threadhandle_np(pthread_t thread); + + +/* + * Protected Methods + * + * This function blocks until the given WIN32 handle + * is signaled or pthread_cancel had been called. + * This function allows the caller to hook into the + * PThreads cancel mechanism. It is implemented using + * + * WaitForMultipleObjects + * + * on 'waitHandle' and a manually reset WIN32 Event + * used to implement pthread_cancel. The 'timeout' + * argument to TimedWait is simply passed to + * WaitForMultipleObjects. + */ +PTW32_DLLPORT int PTW32_CDECL pthreadCancelableWait (HANDLE waitHandle); +PTW32_DLLPORT int PTW32_CDECL pthreadCancelableTimedWait (HANDLE waitHandle, + DWORD timeout); + +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Thread-Safe C Runtime Library Mappings. + */ +#ifndef _UWIN +# if defined(NEED_ERRNO) + PTW32_DLLPORT int * PTW32_CDECL _errno( void ); +# else +# ifndef errno +# if (defined(_MT) || defined(_DLL)) + __declspec(dllimport) extern int * __cdecl _errno(void); +# define errno (*_errno()) +# endif +# endif +# endif +#endif + +/* + * WIN32 C runtime library had been made thread-safe + * without affecting the user interface. Provide + * mappings from the UNIX thread-safe versions to + * the standard C runtime library calls. + * Only provide function mappings for functions that + * actually exist on WIN32. + */ + +#if !defined(__MINGW32__) +#define strtok_r( _s, _sep, _lasts ) \ + ( *(_lasts) = strtok( (_s), (_sep) ) ) +#endif /* !__MINGW32__ */ + +#define asctime_r( _tm, _buf ) \ + ( strcpy( (_buf), asctime( (_tm) ) ), \ + (_buf) ) + +#define ctime_r( _clock, _buf ) \ + ( strcpy( (_buf), ctime( (_clock) ) ), \ + (_buf) ) + +#define gmtime_r( _clock, _result ) \ + ( *(_result) = *gmtime( (_clock) ), \ + (_result) ) + +#define localtime_r( _clock, _result ) \ + ( *(_result) = *localtime( (_clock) ), \ + (_result) ) + +#define rand_r( _seed ) \ + ( _seed == _seed? rand() : rand() ) + + +/* + * Some compiler environments don't define some things. + */ +#if defined(__BORLANDC__) +# define _ftime ftime +# define _timeb timeb +#endif + +#ifdef __cplusplus + +/* + * Internal exceptions + */ +class ptw32_exception {}; +class ptw32_exception_cancel : public ptw32_exception {}; +class ptw32_exception_exit : public ptw32_exception {}; + +#endif + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX + +/* FIXME: This is only required if the library was built using SEH */ +/* + * Get internal SEH tag + */ +PTW32_DLLPORT DWORD PTW32_CDECL ptw32_get_exception_services_code(void); + +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#ifndef PTW32_BUILD + +#ifdef __CLEANUP_SEH + +/* + * Redefine the SEH __except keyword to ensure that applications + * propagate our internal exceptions up to the library's internal handlers. + */ +#define __except( E ) \ + __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \ + ? EXCEPTION_CONTINUE_SEARCH : ( E ) ) + +#endif /* __CLEANUP_SEH */ + +#ifdef __CLEANUP_CXX + +/* + * Redefine the C++ catch keyword to ensure that applications + * propagate our internal exceptions up to the library's internal handlers. + */ +#ifdef _MSC_VER + /* + * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll' + * if you want Pthread-Win32 cancelation and pthread_exit to work. + */ + +#ifndef PtW32NoCatchWarn + +#pragma message("Specify \"/DPtW32NoCatchWarn\" compiler flag to skip this message.") +#pragma message("------------------------------------------------------------------") +#pragma message("When compiling applications with MSVC++ and C++ exception handling:") +#pragma message(" Replace any 'catch( ... )' in routines called from POSIX threads") +#pragma message(" with 'PtW32CatchAll' or 'CATCHALL' if you want POSIX thread") +#pragma message(" cancelation and pthread_exit to work. For example:") +#pragma message("") +#pragma message(" #ifdef PtW32CatchAll") +#pragma message(" PtW32CatchAll") +#pragma message(" #else") +#pragma message(" catch(...)") +#pragma message(" #endif") +#pragma message(" {") +#pragma message(" /* Catchall block processing */") +#pragma message(" }") +#pragma message("------------------------------------------------------------------") + +#endif + +#define PtW32CatchAll \ + catch( ptw32_exception & ) { throw; } \ + catch( ... ) + +#else /* _MSC_VER */ + +#define catch( E ) \ + catch( ptw32_exception & ) { throw; } \ + catch( E ) + +#endif /* _MSC_VER */ + +#endif /* __CLEANUP_CXX */ + +#endif /* ! PTW32_BUILD */ + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#ifdef PTW32__HANDLE_DEF +# undef HANDLE +#endif +#ifdef PTW32__DWORD_DEF +# undef DWORD +#endif + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* ! RC_INVOKED */ + +#endif /* PTHREAD_H */ diff --git a/plugins/zeropad/Windows/libs/sched.h b/plugins/zeropad/Windows/libs/sched.h index 10ecb5d7ea..dfb8e934af 100644 --- a/plugins/zeropad/Windows/libs/sched.h +++ b/plugins/zeropad/Windows/libs/sched.h @@ -1,178 +1,178 @@ -/* - * Module: sched.h - * - * Purpose: - * Provides an implementation of POSIX realtime extensions - * as defined in - * - * POSIX 1003.1b-1993 (POSIX.1b) - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ -#ifndef _SCHED_H -#define _SCHED_H - -#undef PTW32_LEVEL - -#if defined(_POSIX_SOURCE) -#define PTW32_LEVEL 0 -/* Early POSIX */ -#endif - -#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 -#undef PTW32_LEVEL -#define PTW32_LEVEL 1 -/* Include 1b, 1c and 1d */ -#endif - -#if defined(INCLUDE_NP) -#undef PTW32_LEVEL -#define PTW32_LEVEL 2 -/* Include Non-Portable extensions */ -#endif - -#define PTW32_LEVEL_MAX 3 - -#if !defined(PTW32_LEVEL) -#define PTW32_LEVEL PTW32_LEVEL_MAX -/* Include everything */ -#endif - - -#if __GNUC__ && ! defined (__declspec) -# error Please upgrade your GNU compiler to one that supports __declspec. -#endif - -/* - * When building the DLL code, you should define PTW32_BUILD so that - * the variables/functions are exported correctly. When using the DLL, - * do NOT define PTW32_BUILD, and then the variables/functions will - * be imported correctly. - */ -#ifndef PTW32_STATIC_LIB -# ifdef PTW32_BUILD -# define PTW32_DLLPORT __declspec (dllexport) -# else -# define PTW32_DLLPORT __declspec (dllimport) -# endif -#else -# define PTW32_DLLPORT -#endif - -/* - * This is a duplicate of what is in the autoconf config.h, - * which is only used when building the pthread-win32 libraries. - */ - -#ifndef PTW32_CONFIG_H -# if defined(WINCE) -# define NEED_ERRNO -# define NEED_SEM -# endif -# if defined(_UWIN) || defined(__MINGW32__) -# define HAVE_MODE_T -# endif -#endif - -/* - * - */ - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX -#ifdef NEED_ERRNO -#include "need_errno.h" -#else -#include -#endif -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -#if defined(__MINGW32__) || defined(_UWIN) -#if PTW32_LEVEL >= PTW32_LEVEL_MAX -/* For pid_t */ -# include -/* Required by Unix 98 */ -# include -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ -#else -typedef int pid_t; -#endif - -/* Thread scheduling policies */ - -enum { - SCHED_OTHER = 0, - SCHED_FIFO, - SCHED_RR, - SCHED_MIN = SCHED_OTHER, - SCHED_MAX = SCHED_RR -}; - -struct sched_param { - int sched_priority; -}; - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - -PTW32_DLLPORT int __cdecl sched_yield (void); - -PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy); - -PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy); - -PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy); - -PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid); - -/* - * Note that this macro returns ENOTSUP rather than - * ENOSYS as might be expected. However, returning ENOSYS - * should mean that sched_get_priority_{min,max} are - * not implemented as well as sched_rr_get_interval. - * This is not the case, since we just don't support - * round-robin scheduling. Therefore I have chosen to - * return the same value as sched_setscheduler when - * SCHED_RR is passed to it. - */ -#define sched_rr_get_interval(_pid, _interval) \ - ( errno = ENOTSUP, (int) -1 ) - - -#ifdef __cplusplus -} /* End of extern "C" */ -#endif /* __cplusplus */ - -#undef PTW32_LEVEL -#undef PTW32_LEVEL_MAX - -#endif /* !_SCHED_H */ - +/* + * Module: sched.h + * + * Purpose: + * Provides an implementation of POSIX realtime extensions + * as defined in + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef _SCHED_H +#define _SCHED_H + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + + +#if __GNUC__ && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the DLL code, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the DLL, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#ifndef PTW32_STATIC_LIB +# ifdef PTW32_BUILD +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#ifndef PTW32_CONFIG_H +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#ifdef NEED_ERRNO +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#if defined(__MINGW32__) || defined(_UWIN) +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +/* For pid_t */ +# include +/* Required by Unix 98 */ +# include +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ +#else +typedef int pid_t; +#endif + +/* Thread scheduling policies */ + +enum { + SCHED_OTHER = 0, + SCHED_FIFO, + SCHED_RR, + SCHED_MIN = SCHED_OTHER, + SCHED_MAX = SCHED_RR +}; + +struct sched_param { + int sched_priority; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +PTW32_DLLPORT int __cdecl sched_yield (void); + +PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy); + +PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy); + +PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy); + +PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid); + +/* + * Note that this macro returns ENOTSUP rather than + * ENOSYS as might be expected. However, returning ENOSYS + * should mean that sched_get_priority_{min,max} are + * not implemented as well as sched_rr_get_interval. + * This is not the case, since we just don't support + * round-robin scheduling. Therefore I have chosen to + * return the same value as sched_setscheduler when + * SCHED_RR is passed to it. + */ +#define sched_rr_get_interval(_pid, _interval) \ + ( errno = ENOTSUP, (int) -1 ) + + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* !_SCHED_H */ + diff --git a/plugins/zeropad/Windows/libs/semaphore.h b/plugins/zeropad/Windows/libs/semaphore.h index ea42ce3703..a3330a6388 100644 --- a/plugins/zeropad/Windows/libs/semaphore.h +++ b/plugins/zeropad/Windows/libs/semaphore.h @@ -1,166 +1,166 @@ -/* - * Module: semaphore.h - * - * Purpose: - * Semaphores aren't actually part of the PThreads standard. - * They are defined by the POSIX Standard: - * - * POSIX 1003.1b-1993 (POSIX.1b) - * - * -------------------------------------------------------------------------- - * - * Pthreads-win32 - POSIX Threads Library for Win32 - * Copyright(C) 1998 John E. Bossom - * Copyright(C) 1999,2005 Pthreads-win32 contributors - * - * Contact Email: rpj@callisto.canberra.edu.au - * - * The current list of contributors is contained - * in the file CONTRIBUTORS included with the source - * code distribution. The list can also be seen at the - * following World Wide Web location: - * http://sources.redhat.com/pthreads-win32/contributors.html - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library in the file COPYING.LIB; - * if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ -#if !defined( SEMAPHORE_H ) -#define SEMAPHORE_H - -#undef PTW32_LEVEL - -#if defined(_POSIX_SOURCE) -#define PTW32_LEVEL 0 -/* Early POSIX */ -#endif - -#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 -#undef PTW32_LEVEL -#define PTW32_LEVEL 1 -/* Include 1b, 1c and 1d */ -#endif - -#if defined(INCLUDE_NP) -#undef PTW32_LEVEL -#define PTW32_LEVEL 2 -/* Include Non-Portable extensions */ -#endif - -#define PTW32_LEVEL_MAX 3 - -#if !defined(PTW32_LEVEL) -#define PTW32_LEVEL PTW32_LEVEL_MAX -/* Include everything */ -#endif - -#if __GNUC__ && ! defined (__declspec) -# error Please upgrade your GNU compiler to one that supports __declspec. -#endif - -/* - * When building the DLL code, you should define PTW32_BUILD so that - * the variables/functions are exported correctly. When using the DLL, - * do NOT define PTW32_BUILD, and then the variables/functions will - * be imported correctly. - */ -#ifndef PTW32_STATIC_LIB -# ifdef PTW32_BUILD -# define PTW32_DLLPORT __declspec (dllexport) -# else -# define PTW32_DLLPORT __declspec (dllimport) -# endif -#else -# define PTW32_DLLPORT -#endif - -/* - * This is a duplicate of what is in the autoconf config.h, - * which is only used when building the pthread-win32 libraries. - */ - -#ifndef PTW32_CONFIG_H -# if defined(WINCE) -# define NEED_ERRNO -# define NEED_SEM -# endif -# if defined(_UWIN) || defined(__MINGW32__) -# define HAVE_MODE_T -# endif -#endif - -/* - * - */ - -#if PTW32_LEVEL >= PTW32_LEVEL_MAX -#ifdef NEED_ERRNO -#include "need_errno.h" -#else -#include -#endif -#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ - -#define _POSIX_SEMAPHORES - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - -#ifndef HAVE_MODE_T -typedef unsigned int mode_t; -#endif - - -typedef struct sem_t_ * sem_t; - -PTW32_DLLPORT int __cdecl sem_init (sem_t * sem, - int pshared, - unsigned int value); - -PTW32_DLLPORT int __cdecl sem_destroy (sem_t * sem); - -PTW32_DLLPORT int __cdecl sem_trywait (sem_t * sem); - -PTW32_DLLPORT int __cdecl sem_wait (sem_t * sem); - -PTW32_DLLPORT int __cdecl sem_timedwait (sem_t * sem, - const struct timespec * abstime); - -PTW32_DLLPORT int __cdecl sem_post (sem_t * sem); - -PTW32_DLLPORT int __cdecl sem_post_multiple (sem_t * sem, - int count); - -PTW32_DLLPORT int __cdecl sem_open (const char * name, - int oflag, - mode_t mode, - unsigned int value); - -PTW32_DLLPORT int __cdecl sem_close (sem_t * sem); - -PTW32_DLLPORT int __cdecl sem_unlink (const char * name); - -PTW32_DLLPORT int __cdecl sem_getvalue (sem_t * sem, - int * sval); - -#ifdef __cplusplus -} /* End of extern "C" */ -#endif /* __cplusplus */ - -#undef PTW32_LEVEL -#undef PTW32_LEVEL_MAX - -#endif /* !SEMAPHORE_H */ +/* + * Module: semaphore.h + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#if !defined( SEMAPHORE_H ) +#define SEMAPHORE_H + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + +#if __GNUC__ && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the DLL code, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the DLL, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#ifndef PTW32_STATIC_LIB +# ifdef PTW32_BUILD +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#ifndef PTW32_CONFIG_H +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#ifdef NEED_ERRNO +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#define _POSIX_SEMAPHORES + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#ifndef HAVE_MODE_T +typedef unsigned int mode_t; +#endif + + +typedef struct sem_t_ * sem_t; + +PTW32_DLLPORT int __cdecl sem_init (sem_t * sem, + int pshared, + unsigned int value); + +PTW32_DLLPORT int __cdecl sem_destroy (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_trywait (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_wait (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_timedwait (sem_t * sem, + const struct timespec * abstime); + +PTW32_DLLPORT int __cdecl sem_post (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_post_multiple (sem_t * sem, + int count); + +PTW32_DLLPORT int __cdecl sem_open (const char * name, + int oflag, + mode_t mode, + unsigned int value); + +PTW32_DLLPORT int __cdecl sem_close (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_unlink (const char * name); + +PTW32_DLLPORT int __cdecl sem_getvalue (sem_t * sem, + int * sval); + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* !SEMAPHORE_H */ diff --git a/plugins/zeropad/Windows/resource.h b/plugins/zeropad/Windows/resource.h index eec9db5935..5490aad8ee 100644 --- a/plugins/zeropad/Windows/resource.h +++ b/plugins/zeropad/Windows/resource.h @@ -1,70 +1,70 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by ZeroPAD.rc -// -#define IDD_DIALOG1 110 -#define IDB_BITMAP1 112 -#define IDC_EL3 1012 -#define IDC_L2 1013 -#define IDC_ER3 1014 -#define IDC_R2 1015 -#define IDC_ESTART 1016 -#define IDC_L1 1017 -#define IDC_ESELECT 1018 -#define IDC_R1 1019 -#define IDC_ECROSS 1020 -#define IDC_TRI 1021 -#define IDC_ESQUARE 1022 -#define IDC_CIRCLE 1023 -#define IDC_ECIRCLE 1024 -#define IDC2_CROSS 1025 -#define IDC_ETRIANGLE 1026 -#define IDC_SQUARE 1027 -#define IDC_ER2 1028 -#define IDC_SELECT 1029 -#define IDC_ER1 1030 -#define IDC_L3 1031 -#define IDC_EDOWN 1032 -#define IDC_R3 1033 -#define IDC_ERIGHT 1034 -#define IDC_START 1035 -#define IDC_ELEFT 1036 -#define IDC_UP 1037 -#define IDC_EUP 1038 -#define IDC_RIGHT 1039 -#define IDC_EL2 1040 -#define IDC_DOWN 1041 -#define IDC_EL1 1042 -#define IDC_LEFT 1043 -#define IDC_TABC 1044 -#define IDC_LAX 1045 -#define IDC_LAY 1046 -#define IDC_RAX 1047 -#define IDC_RAY 1048 -#define IDC_SCROSS 1049 -#define IDC_CHECK1 1050 -#define IDC_LOG 1050 -#define IDC_SCIRCLE 1051 -#define IDC_SSQUARE 1052 -#define IDC_STRIANGLE 1053 -#define IDC_SL3 1054 -#define IDC_SUP 1055 -#define IDC_SDOWN 1056 -#define IDC_SLEFT 1057 -#define IDC_SRIGHT 1058 -#define IDC_SR3 1059 -#define IDC_SL1 1060 -#define IDC_SL2 1061 -#define IDC_SR1 1062 -#define IDC_SR2 1063 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 114 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1051 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ZeroPAD.rc +// +#define IDD_DIALOG1 110 +#define IDB_BITMAP1 112 +#define IDC_EL3 1012 +#define IDC_L2 1013 +#define IDC_ER3 1014 +#define IDC_R2 1015 +#define IDC_ESTART 1016 +#define IDC_L1 1017 +#define IDC_ESELECT 1018 +#define IDC_R1 1019 +#define IDC_ECROSS 1020 +#define IDC_TRI 1021 +#define IDC_ESQUARE 1022 +#define IDC_CIRCLE 1023 +#define IDC_ECIRCLE 1024 +#define IDC2_CROSS 1025 +#define IDC_ETRIANGLE 1026 +#define IDC_SQUARE 1027 +#define IDC_ER2 1028 +#define IDC_SELECT 1029 +#define IDC_ER1 1030 +#define IDC_L3 1031 +#define IDC_EDOWN 1032 +#define IDC_R3 1033 +#define IDC_ERIGHT 1034 +#define IDC_START 1035 +#define IDC_ELEFT 1036 +#define IDC_UP 1037 +#define IDC_EUP 1038 +#define IDC_RIGHT 1039 +#define IDC_EL2 1040 +#define IDC_DOWN 1041 +#define IDC_EL1 1042 +#define IDC_LEFT 1043 +#define IDC_TABC 1044 +#define IDC_LAX 1045 +#define IDC_LAY 1046 +#define IDC_RAX 1047 +#define IDC_RAY 1048 +#define IDC_SCROSS 1049 +#define IDC_CHECK1 1050 +#define IDC_LOG 1050 +#define IDC_SCIRCLE 1051 +#define IDC_SSQUARE 1052 +#define IDC_STRIANGLE 1053 +#define IDC_SL3 1054 +#define IDC_SUP 1055 +#define IDC_SDOWN 1056 +#define IDC_SLEFT 1057 +#define IDC_SRIGHT 1058 +#define IDC_SR3 1059 +#define IDC_SL1 1060 +#define IDC_SL2 1061 +#define IDC_SR1 1062 +#define IDC_SR2 1063 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 114 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1051 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/zeropad/Windows/vsprops/svnrev_template.h b/plugins/zeropad/Windows/vsprops/svnrev_template.h index afab6c4fd1..f2656ef1e8 100644 --- a/plugins/zeropad/Windows/vsprops/svnrev_template.h +++ b/plugins/zeropad/Windows/vsprops/svnrev_template.h @@ -1,18 +1,18 @@ -// svnrev_template.h --> svnrev.h -// -// This file acts as a template for the automatic SVN revision/version tag. -// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for -// whichever project is being compiled (as indicated by command line options -// passed to SubWCRev.exe during the project's pre-build step). -// -// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs -// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN -// installed on your system. If you do not have it installed, a generic template -// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not -// necessary. If you do not have it installed, everything will still compile -// fine except without the SVN revision tagged to the application/dll version. -// -// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org - -#define SVN_REV $WCREV$ +// svnrev_template.h --> svnrev.h +// +// This file acts as a template for the automatic SVN revision/version tag. +// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for +// whichever project is being compiled (as indicated by command line options +// passed to SubWCRev.exe during the project's pre-build step). +// +// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs +// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN +// installed on your system. If you do not have it installed, a generic template +// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not +// necessary. If you do not have it installed, everything will still compile +// fine except without the SVN revision tagged to the application/dll version. +// +// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV $WCREV$ #define SVN_MODS $WCMODS?1:0$ \ No newline at end of file diff --git a/plugins/zeropad/Windows/vsprops/svnrev_unknown.h b/plugins/zeropad/Windows/vsprops/svnrev_unknown.h index a2a3703186..4872e23b20 100644 --- a/plugins/zeropad/Windows/vsprops/svnrev_unknown.h +++ b/plugins/zeropad/Windows/vsprops/svnrev_unknown.h @@ -1,23 +1,23 @@ -// svnrev_genric.h --> svnrev.h -// -// This file acts as a placebo for people who do not have TortoiseSVN installed. -// It provides "empty" revision information to the Pcsx2 Playground projects in -// the absence of real revisions derived from the repository being built. -// -// This file does not affect application/dll builds in any significant manner, -// other than the lack of automatic revision tags inserted into the app (which -// is very convenient but hardly necessary). -// -// See svn_template.h for more information on how the process of revision -// templating works. -// -// If you would like to enable automatic revisin tagging, TortoiseSVN can be -// downloaded from http://tortoisesvn.tigris.org - -#define SVN_REV_UNKNOWN - -// The following defines are included so that code will still compile even if it -// doesn't check for the SVN_REV_UNKNOWN define. - -#define SVN_REV 0 +// svnrev_genric.h --> svnrev.h +// +// This file acts as a placebo for people who do not have TortoiseSVN installed. +// It provides "empty" revision information to the Pcsx2 Playground projects in +// the absence of real revisions derived from the repository being built. +// +// This file does not affect application/dll builds in any significant manner, +// other than the lack of automatic revision tags inserted into the app (which +// is very convenient but hardly necessary). +// +// See svn_template.h for more information on how the process of revision +// templating works. +// +// If you would like to enable automatic revisin tagging, TortoiseSVN can be +// downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV_UNKNOWN + +// The following defines are included so that code will still compile even if it +// doesn't check for the SVN_REV_UNKNOWN define. + +#define SVN_REV 0 #define SVN_MODS "" \ No newline at end of file diff --git a/plugins/zeropad/Windows/win.cpp b/plugins/zeropad/Windows/win.cpp index 3c181cca72..ad9e47e1d8 100644 --- a/plugins/zeropad/Windows/win.cpp +++ b/plugins/zeropad/Windows/win.cpp @@ -1,457 +1,457 @@ -/* ZeroPAD - author: zerofrog(@gmail.com) - * Copyright (C) 2006-2007 - * - * 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 -#include -#include -#include - -#include "resource.h" -#include "../zeropad.h" - -#include -#include - -using namespace std; - -HINSTANCE hInst=NULL; -static pthread_spinlock_t s_mutexStatus; -static u32 s_keyPress[2], s_keyRelease[2]; -extern u16 status[2]; - -extern string s_strIniPath; -LRESULT WINAPI PADwndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); -WNDPROC GSwndProc=NULL; -HWND GShwnd=NULL; - -extern keyEvent event; - - -void SaveConfig() -{ - char *szTemp; - char szIniFile[256], szValue[256], szProf[256]; - int i, j; - - GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); - szTemp = strrchr(szIniFile, '\\'); - - if(!szTemp) return; - strcpy(szTemp, "\\inis\\zeropad.ini"); - - for (j=0; j<2; j++) { - for (i=0; i=0x60 && key<=0x69) { - sprintf(buff, "NumPad %c", '0' + key - 0x60); - } - else sprintf(buff, "%c", key); - } - } - else if (key >= 0x1000 && key < 0x2000) - { - sprintf (buff, "J%d_%d", (key & 0xfff) / 0x100, (key & 0xff) + 1); - } - else if (key >= 0x2000 && key < 0x3000) - { - static const char name[][4] = { "MIN", "MAX" }; - const int axis = (key & 0xff); - sprintf (buff, "J%d_AXIS%d_%s", (key & 0xfff) / 0x100, axis / 2, name[axis % 2]); - if (index >= 17 && index <= 20) - buff[strlen (buff) -4] = '\0'; - } - else if (key >= 0x3000 && key < 0x4000) - { - static const char name[][7] = { "FOWARD", "RIGHT", "BACK", "LEFT" }; - const int pov = (key & 0xff); - sprintf (buff, "J%d_POV%d_%s", (key & 0xfff) / 0x100, pov /4, name[pov % 4]); - } - - return buff; -} - -BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { - HWND hWC; - TCITEM tcI; - int i,key, numkeys; - u8* pkeyboard; - static int disabled=0; - static int padn=0; - - switch(uMsg) { - case WM_INITDIALOG: - LoadConfig(); - padn = 0; - if (conf.log) CheckDlgButton(hW, IDC_LOG, TRUE); - - for (i=0; i +#include +#include +#include + +#include "resource.h" +#include "../zeropad.h" + +#include +#include + +using namespace std; + +HINSTANCE hInst=NULL; +static pthread_spinlock_t s_mutexStatus; +static u32 s_keyPress[2], s_keyRelease[2]; +extern u16 status[2]; + +extern string s_strIniPath; +LRESULT WINAPI PADwndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +WNDPROC GSwndProc=NULL; +HWND GShwnd=NULL; + +extern keyEvent event; + + +void SaveConfig() +{ + char *szTemp; + char szIniFile[256], szValue[256], szProf[256]; + int i, j; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\zeropad.ini"); + + for (j=0; j<2; j++) { + for (i=0; i=0x60 && key<=0x69) { + sprintf(buff, "NumPad %c", '0' + key - 0x60); + } + else sprintf(buff, "%c", key); + } + } + else if (key >= 0x1000 && key < 0x2000) + { + sprintf (buff, "J%d_%d", (key & 0xfff) / 0x100, (key & 0xff) + 1); + } + else if (key >= 0x2000 && key < 0x3000) + { + static const char name[][4] = { "MIN", "MAX" }; + const int axis = (key & 0xff); + sprintf (buff, "J%d_AXIS%d_%s", (key & 0xfff) / 0x100, axis / 2, name[axis % 2]); + if (index >= 17 && index <= 20) + buff[strlen (buff) -4] = '\0'; + } + else if (key >= 0x3000 && key < 0x4000) + { + static const char name[][7] = { "FOWARD", "RIGHT", "BACK", "LEFT" }; + const int pov = (key & 0xff); + sprintf (buff, "J%d_POV%d_%s", (key & 0xfff) / 0x100, pov /4, name[pov % 4]); + } + + return buff; +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + HWND hWC; + TCITEM tcI; + int i,key, numkeys; + u8* pkeyboard; + static int disabled=0; + static int padn=0; + + switch(uMsg) { + case WM_INITDIALOG: + LoadConfig(); + padn = 0; + if (conf.log) CheckDlgButton(hW, IDC_LOG, TRUE); + + for (i=0; i -#include - -#include "zeropad.h" - -#include -#include -#include -#ifndef _WIN32 -#include -#else -#include "svnrev.h" -#endif - -char libraryName[256]; - -PADAnalog g_lanalog[2], g_ranalog[2]; -PADconf conf; - -keyEvent event; - -u16 status[2]; -int pressure; -string s_strIniPath="inis/zeropad.ini"; - -const unsigned char version = PS2E_PAD_VERSION; -const unsigned char revision = 0; -const unsigned char build = 2; // increase that with each version - - -u32 pads=0; -u8 stdpar[2][20] = { {0xff, 0x5a, 0xff, 0xff, 0x80, 0x80, 0x80, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}, - {0xff, 0x5a, 0xff, 0xff, 0x80, 0x80, 0x80, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}}; -u8 cmd40[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5a}, - {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5a}}; -u8 cmd41[2][8] = { {0xff, 0x5a, 0xff, 0xff, 0x03, 0x00, 0x00, 0x5a}, - {0xff, 0x5a, 0xff, 0xff, 0x03, 0x00, 0x00, 0x5a}}; -u8 unk46[2][8] = { {0xFF, 0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A}, - {0xFF, 0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A}}; -u8 unk47[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00}, - {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00}}; -u8 unk4c[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -u8 unk4d[2][8] = { {0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - {0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; -u8 cmd4f[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a}, - {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a}}; -u8 stdcfg[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; // 2 & 3 = 0 -u8 stdmode[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -u8 stdmodel[2][8] = { {0xff, 0x5a, - 0x03, // 03 - dualshock2, 01 - dualshock - 0x02, // number of modes - 0x01, // current mode: 01 - analog, 00 - digital - 0x02, - 0x01, - 0x00}, - {0xff, 0x5a, - 0x03, // 03 - dualshock2, 01 - dualshock - 0x02, // number of modes - 0x01, // current mode: 01 - analog, 00 - digital - 0x02, - 0x01, - 0x00}}; - -u8 *buf; -int padID[2]; -int padMode[2]; -int curPad; -int curByte; -int curCmd; -int cmdLen; -int ds2mode = 0; // DS Mode at start -FILE *padLog = NULL; - -int POV(u32 direction, u32 angle){ - if ((direction==0) && (angle>= 0) && (angle< 4500)) return 1;//forward - if ((direction==2) && (angle>= 4500) && (angle<13500)) return 1;//right - if ((direction==1) && (angle>=13500) && (angle<22500)) return 1;//backward - if ((direction==3) && (angle>=22500) && (angle<31500)) return 1;//left - if ((direction==0) && (angle>=31500) && (angle<36000)) return 1;//forward - return 0; -} - -void _KeyPress(int pad, u32 key) -{ - int i; - - for (i=0; i> 8; - stdpar[curPad][3] = status[curPad] & 0xff; - stdpar[curPad][4] = g_ranalog[curPad].x; - stdpar[curPad][5] = g_ranalog[curPad].y; - stdpar[curPad][6] = g_lanalog[curPad].x; - stdpar[curPad][7] = g_lanalog[curPad].y; - if (padMode[curPad] == 1) cmdLen = 20; - else cmdLen = 4; - button_check2 = stdpar[curPad][2] >> 4; - switch(stdpar[curPad][3]) - { - case 0xBF: // X - stdpar[curPad][14] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][16])); - break; - case 0xDF: // Circle - stdpar[curPad][13] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][17])); - break; - case 0xEF: // Triangle - stdpar[curPad][12] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][19])); - break; - case 0x7F: // Square - stdpar[curPad][15] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][18])); - break; - case 0xFB: // L1 - stdpar[curPad][16] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][26])); - break; - case 0xF7: // R1 - stdpar[curPad][17] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][28])); - break; - case 0xFE: // L2 - stdpar[curPad][18] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][27])); - break; - case 0xFD: // R2 - stdpar[curPad][19] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][29])); - break; - default: - stdpar[curPad][14] = 0x00; // Not pressed - stdpar[curPad][13] = 0x00; // Not pressed - stdpar[curPad][12] = 0x00; // Not pressed - stdpar[curPad][15] = 0x00; // Not pressed - stdpar[curPad][16] = 0x00; // Not pressed - stdpar[curPad][17] = 0x00; // Not pressed - stdpar[curPad][18] = 0x00; // Not pressed - stdpar[curPad][19] = 0x00; // Not pressed - break; - } - switch(button_check2) - { - case 0xE: // UP - stdpar[curPad][10] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][21])); - break; - case 0xB: // DOWN - stdpar[curPad][11] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][22])); - break; - case 0x7: // LEFT - stdpar[curPad][9] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][23])); - break; - case 0xD: // RIGHT - stdpar[curPad][8] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][24])); - break; - default: - stdpar[curPad][8] = 0x00; // Not pressed - stdpar[curPad][9] = 0x00; // Not pressed - stdpar[curPad][10] = 0x00; // Not pressed - stdpar[curPad][11] = 0x00; // Not pressed - break; - } - buf = stdpar[curPad]; - return padID[curPad]; - - case 0x43: // CONFIG_MODE - cmdLen = 8; - buf = stdcfg[curPad]; - if (stdcfg[curPad][3] == 0xff) return 0xf3; - else return padID[curPad]; - - case 0x44: // SET_MODE_AND_LOCK - cmdLen = 8; - buf = stdmode[curPad]; - return 0xf3; - - case 0x45: // QUERY_MODEL_AND_MODE - cmdLen = 8; - buf = stdmodel[curPad]; - buf[4] = padMode[curPad]; - return 0xf3; - - case 0x46: // ?? - cmdLen = 8; - buf = unk46[curPad]; - return 0xf3; - - case 0x47: // ?? - cmdLen = 8; - buf = unk47[curPad]; - return 0xf3; - - case 0x4c: // QUERY_MODE ?? - cmdLen = 8; - buf = unk4c[curPad]; - return 0xf3; - - case 0x4d: - cmdLen = 8; - buf = unk4d[curPad]; - return 0xf3; - - case 0x4f: // SET_DS2_NATIVE_MODE - cmdLen = 8; - padID[curPad] = 0x79; // setting ds2 mode - ds2mode = 1; // Set DS2 Mode - buf = cmd4f[curPad]; - return 0xf3; - - default: -#ifdef PAD_LOG - PAD_LOG("*PADpoll*: unknown cmd %x\n", value); -#endif - break; - } - } - - switch (curCmd) { - case 0x43: - if(curByte == 2) - { - switch(value){ - case 0: - buf[2] = 0; - buf[3] = 0; - break; - case 1: - buf[2] = 0xff; - buf[3] = 0xff; - break; - } - } - break; - - case 0x44: - if (curByte == 2) { - PADsetMode(curPad, value); - } - break; - - case 0x46: - if(curByte == 2) { - switch(value) { - case 0: // default - buf[5] = 0x2; - buf[6] = 0x0; - buf[7] = 0xA; - break; - case 1: // Param std conf change - buf[5] = 0x1; - buf[6] = 0x1; - buf[7] = 0x14; - break; - } - } - break; - - case 0x4c: - if (curByte == 2) { - switch (value) { - case 0: // mode 0 - digital mode - buf[5] = 0x4; - break; - - case 1: // mode 1 - analog mode - buf[5] = 0x7; - break; - } - } - break; - } - - if (curByte >= cmdLen) return 0; - return buf[curByte++]; -} - -u8 CALLBACK PADpoll(u8 value) -{ - u8 ret; - ret = _PADpoll(value); -#ifdef PAD_LOG - PAD_LOG("PADpoll: %x (%d: %x)\n", value, curByte, ret); -#endif - return ret; -} - -// PADkeyEvent is called every vsync (return NULL if no event) -static keyEvent s_event; -keyEvent* CALLBACK PADkeyEvent() -{ - s_event = event; - event.evt = 0; - return &s_event; -} +/* ZeroPAD - author: zerofrog(@gmail.com) + * Copyright (C) 2006-2007 + * + * 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 +#include + +#include "zeropad.h" + +#include +#include +#include +#ifndef _WIN32 +#include +#else +#include "svnrev.h" +#endif + +char libraryName[256]; + +PADAnalog g_lanalog[2], g_ranalog[2]; +PADconf conf; + +keyEvent event; + +u16 status[2]; +int pressure; +string s_strIniPath="inis/zeropad.ini"; + +const unsigned char version = PS2E_PAD_VERSION; +const unsigned char revision = 0; +const unsigned char build = 2; // increase that with each version + + +u32 pads=0; +u8 stdpar[2][20] = { {0xff, 0x5a, 0xff, 0xff, 0x80, 0x80, 0x80, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, + {0xff, 0x5a, 0xff, 0xff, 0x80, 0x80, 0x80, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}}; +u8 cmd40[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5a}, + {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5a}}; +u8 cmd41[2][8] = { {0xff, 0x5a, 0xff, 0xff, 0x03, 0x00, 0x00, 0x5a}, + {0xff, 0x5a, 0xff, 0xff, 0x03, 0x00, 0x00, 0x5a}}; +u8 unk46[2][8] = { {0xFF, 0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A}, + {0xFF, 0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A}}; +u8 unk47[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00}, + {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00}}; +u8 unk4c[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +u8 unk4d[2][8] = { {0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; +u8 cmd4f[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a}, + {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a}}; +u8 stdcfg[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; // 2 & 3 = 0 +u8 stdmode[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +u8 stdmodel[2][8] = { {0xff, 0x5a, + 0x03, // 03 - dualshock2, 01 - dualshock + 0x02, // number of modes + 0x01, // current mode: 01 - analog, 00 - digital + 0x02, + 0x01, + 0x00}, + {0xff, 0x5a, + 0x03, // 03 - dualshock2, 01 - dualshock + 0x02, // number of modes + 0x01, // current mode: 01 - analog, 00 - digital + 0x02, + 0x01, + 0x00}}; + +u8 *buf; +int padID[2]; +int padMode[2]; +int curPad; +int curByte; +int curCmd; +int cmdLen; +int ds2mode = 0; // DS Mode at start +FILE *padLog = NULL; + +int POV(u32 direction, u32 angle){ + if ((direction==0) && (angle>= 0) && (angle< 4500)) return 1;//forward + if ((direction==2) && (angle>= 4500) && (angle<13500)) return 1;//right + if ((direction==1) && (angle>=13500) && (angle<22500)) return 1;//backward + if ((direction==3) && (angle>=22500) && (angle<31500)) return 1;//left + if ((direction==0) && (angle>=31500) && (angle<36000)) return 1;//forward + return 0; +} + +void _KeyPress(int pad, u32 key) +{ + int i; + + for (i=0; i> 8; + stdpar[curPad][3] = status[curPad] & 0xff; + stdpar[curPad][4] = g_ranalog[curPad].x; + stdpar[curPad][5] = g_ranalog[curPad].y; + stdpar[curPad][6] = g_lanalog[curPad].x; + stdpar[curPad][7] = g_lanalog[curPad].y; + if (padMode[curPad] == 1) cmdLen = 20; + else cmdLen = 4; + button_check2 = stdpar[curPad][2] >> 4; + switch(stdpar[curPad][3]) + { + case 0xBF: // X + stdpar[curPad][14] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][16])); + break; + case 0xDF: // Circle + stdpar[curPad][13] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][17])); + break; + case 0xEF: // Triangle + stdpar[curPad][12] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][19])); + break; + case 0x7F: // Square + stdpar[curPad][15] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][18])); + break; + case 0xFB: // L1 + stdpar[curPad][16] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][26])); + break; + case 0xF7: // R1 + stdpar[curPad][17] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][28])); + break; + case 0xFE: // L2 + stdpar[curPad][18] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][27])); + break; + case 0xFD: // R2 + stdpar[curPad][19] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][29])); + break; + default: + stdpar[curPad][14] = 0x00; // Not pressed + stdpar[curPad][13] = 0x00; // Not pressed + stdpar[curPad][12] = 0x00; // Not pressed + stdpar[curPad][15] = 0x00; // Not pressed + stdpar[curPad][16] = 0x00; // Not pressed + stdpar[curPad][17] = 0x00; // Not pressed + stdpar[curPad][18] = 0x00; // Not pressed + stdpar[curPad][19] = 0x00; // Not pressed + break; + } + switch(button_check2) + { + case 0xE: // UP + stdpar[curPad][10] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][21])); + break; + case 0xB: // DOWN + stdpar[curPad][11] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][22])); + break; + case 0x7: // LEFT + stdpar[curPad][9] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][23])); + break; + case 0xD: // RIGHT + stdpar[curPad][8] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][24])); + break; + default: + stdpar[curPad][8] = 0x00; // Not pressed + stdpar[curPad][9] = 0x00; // Not pressed + stdpar[curPad][10] = 0x00; // Not pressed + stdpar[curPad][11] = 0x00; // Not pressed + break; + } + buf = stdpar[curPad]; + return padID[curPad]; + + case 0x43: // CONFIG_MODE + cmdLen = 8; + buf = stdcfg[curPad]; + if (stdcfg[curPad][3] == 0xff) return 0xf3; + else return padID[curPad]; + + case 0x44: // SET_MODE_AND_LOCK + cmdLen = 8; + buf = stdmode[curPad]; + return 0xf3; + + case 0x45: // QUERY_MODEL_AND_MODE + cmdLen = 8; + buf = stdmodel[curPad]; + buf[4] = padMode[curPad]; + return 0xf3; + + case 0x46: // ?? + cmdLen = 8; + buf = unk46[curPad]; + return 0xf3; + + case 0x47: // ?? + cmdLen = 8; + buf = unk47[curPad]; + return 0xf3; + + case 0x4c: // QUERY_MODE ?? + cmdLen = 8; + buf = unk4c[curPad]; + return 0xf3; + + case 0x4d: + cmdLen = 8; + buf = unk4d[curPad]; + return 0xf3; + + case 0x4f: // SET_DS2_NATIVE_MODE + cmdLen = 8; + padID[curPad] = 0x79; // setting ds2 mode + ds2mode = 1; // Set DS2 Mode + buf = cmd4f[curPad]; + return 0xf3; + + default: +#ifdef PAD_LOG + PAD_LOG("*PADpoll*: unknown cmd %x\n", value); +#endif + break; + } + } + + switch (curCmd) { + case 0x43: + if(curByte == 2) + { + switch(value){ + case 0: + buf[2] = 0; + buf[3] = 0; + break; + case 1: + buf[2] = 0xff; + buf[3] = 0xff; + break; + } + } + break; + + case 0x44: + if (curByte == 2) { + PADsetMode(curPad, value); + } + break; + + case 0x46: + if(curByte == 2) { + switch(value) { + case 0: // default + buf[5] = 0x2; + buf[6] = 0x0; + buf[7] = 0xA; + break; + case 1: // Param std conf change + buf[5] = 0x1; + buf[6] = 0x1; + buf[7] = 0x14; + break; + } + } + break; + + case 0x4c: + if (curByte == 2) { + switch (value) { + case 0: // mode 0 - digital mode + buf[5] = 0x4; + break; + + case 1: // mode 1 - analog mode + buf[5] = 0x7; + break; + } + } + break; + } + + if (curByte >= cmdLen) return 0; + return buf[curByte++]; +} + +u8 CALLBACK PADpoll(u8 value) +{ + u8 ret; + ret = _PADpoll(value); +#ifdef PAD_LOG + PAD_LOG("PADpoll: %x (%d: %x)\n", value, curByte, ret); +#endif + return ret; +} + +// PADkeyEvent is called every vsync (return NULL if no event) +static keyEvent s_event; +keyEvent* CALLBACK PADkeyEvent() +{ + s_event = event; + event.evt = 0; + return &s_event; +} diff --git a/plugins/zeropad/zeropad.h b/plugins/zeropad/zeropad.h index 1cdea52a15..1ec4a91c00 100644 --- a/plugins/zeropad/zeropad.h +++ b/plugins/zeropad/zeropad.h @@ -1,134 +1,134 @@ -/* ZeroPAD - author: zerofrog(@gmail.com) - * Copyright (C) 2006-2007 - * - * 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 - */ - -#ifndef __PAD_H__ -#define __PAD_H__ - -#include -#include - -#ifdef _WIN32 -#include -#include - -#else - -#include -#include -#include - -#endif - -#include -#include -#include -using namespace std; - -#define PADdefs -extern "C" { -#include "PS2Edefs.h" -} - -extern char libraryName[256]; - -#define FORIT(it, v) for(it = (v).begin(); it != (v).end(); (it)++) - -#define IS_KEYBOARD(key) (key<0x10000) -#define IS_JOYBUTTONS(key) (key>=0x10000 && key<0x20000) // buttons -#define IS_JOYSTICK(key) (key>=0x20000&&key<0x30000) // analog -#define IS_POV(key) (key>=0x30000&&key<0x40000) // uses analog as buttons (cares about sign) -#define IS_MOUSE(key) (key>=0x40000&&key<0x50000) // mouse - -#define PAD_GETKEY(key) ((key)&0xffff) -#define PAD_GETJOYID(key) (((key)&0xf000)>>12) -#define PAD_GETJOYBUTTON(key) ((key)&0xff) -#define PAD_GETJOYSTICK_AXIS(key) ((key)&0xff) -#define PAD_JOYBUTTON(joyid, buttonid) (0x10000|((joyid)<<12)|(buttonid)) -#define PAD_JOYSTICK(joyid, axisid) (0x20000|((joyid)<<12)|(axisid)) -#define PAD_POV(joyid, sign, axisid) (0x30000|((joyid)<<12)|((sign)<<8)|(axisid)) -#define PAD_GETPOVSIGN(key) (((key)&0x100)>>8) - -#define PADKEYS 20 - -#define PADOPTION_FORCEFEEDBACK 1 -#define PADOPTION_REVERTLX 0x2 -#define PADOPTION_REVERTLY 0x4 -#define PADOPTION_REVERTRX 0x8 -#define PADOPTION_REVERTRY 0x10 - -typedef struct { - unsigned long keys[2][PADKEYS]; - int log; - int options; // upper 16 bits are for pad2 -} PADconf; - -typedef struct { - u8 x,y; -} PADAnalog; - -extern PADconf conf; - -extern PADAnalog g_lanalog[2], g_ranalog[2]; -extern FILE *padLog; -#define PAD_LOG __Log - -#define PAD_RY 19 -#define PAD_LY 18 -#define PAD_RX 17 -#define PAD_LX 16 -#define PAD_LEFT 15 -#define PAD_DOWN 14 -#define PAD_RIGHT 13 -#define PAD_UP 12 -#define PAD_START 11 -#define PAD_R3 10 -#define PAD_L3 9 -#define PAD_SELECT 8 -#define PAD_SQUARE 7 -#define PAD_CROSS 6 -#define PAD_CIRCLE 5 -#define PAD_TRIANGLE 4 -#define PAD_R1 3 -#define PAD_L1 2 -#define PAD_R2 1 -#define PAD_L2 0 - -/* end of pad.h */ - -extern keyEvent event; - -extern u16 status[2]; -extern u32 pads; - -int POV(u32 direction, u32 angle); -s32 _PADopen(void *pDsp); -void _PADclose(); -void _KeyPress(int pad, u32 key); -void _KeyRelease(int pad, u32 key); -void PADsetMode(int pad, int mode); -void _PADupdate(int pad); - -void __Log(char *fmt, ...); -void LoadConfig(); -void SaveConfig(); - -void SysMessage(char *fmt, ...); - -#endif - - +/* ZeroPAD - author: zerofrog(@gmail.com) + * Copyright (C) 2006-2007 + * + * 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 + */ + +#ifndef __PAD_H__ +#define __PAD_H__ + +#include +#include + +#ifdef _WIN32 +#include +#include + +#else + +#include +#include +#include + +#endif + +#include +#include +#include +using namespace std; + +#define PADdefs +extern "C" { +#include "PS2Edefs.h" +} + +extern char libraryName[256]; + +#define FORIT(it, v) for(it = (v).begin(); it != (v).end(); (it)++) + +#define IS_KEYBOARD(key) (key<0x10000) +#define IS_JOYBUTTONS(key) (key>=0x10000 && key<0x20000) // buttons +#define IS_JOYSTICK(key) (key>=0x20000&&key<0x30000) // analog +#define IS_POV(key) (key>=0x30000&&key<0x40000) // uses analog as buttons (cares about sign) +#define IS_MOUSE(key) (key>=0x40000&&key<0x50000) // mouse + +#define PAD_GETKEY(key) ((key)&0xffff) +#define PAD_GETJOYID(key) (((key)&0xf000)>>12) +#define PAD_GETJOYBUTTON(key) ((key)&0xff) +#define PAD_GETJOYSTICK_AXIS(key) ((key)&0xff) +#define PAD_JOYBUTTON(joyid, buttonid) (0x10000|((joyid)<<12)|(buttonid)) +#define PAD_JOYSTICK(joyid, axisid) (0x20000|((joyid)<<12)|(axisid)) +#define PAD_POV(joyid, sign, axisid) (0x30000|((joyid)<<12)|((sign)<<8)|(axisid)) +#define PAD_GETPOVSIGN(key) (((key)&0x100)>>8) + +#define PADKEYS 20 + +#define PADOPTION_FORCEFEEDBACK 1 +#define PADOPTION_REVERTLX 0x2 +#define PADOPTION_REVERTLY 0x4 +#define PADOPTION_REVERTRX 0x8 +#define PADOPTION_REVERTRY 0x10 + +typedef struct { + unsigned long keys[2][PADKEYS]; + int log; + int options; // upper 16 bits are for pad2 +} PADconf; + +typedef struct { + u8 x,y; +} PADAnalog; + +extern PADconf conf; + +extern PADAnalog g_lanalog[2], g_ranalog[2]; +extern FILE *padLog; +#define PAD_LOG __Log + +#define PAD_RY 19 +#define PAD_LY 18 +#define PAD_RX 17 +#define PAD_LX 16 +#define PAD_LEFT 15 +#define PAD_DOWN 14 +#define PAD_RIGHT 13 +#define PAD_UP 12 +#define PAD_START 11 +#define PAD_R3 10 +#define PAD_L3 9 +#define PAD_SELECT 8 +#define PAD_SQUARE 7 +#define PAD_CROSS 6 +#define PAD_CIRCLE 5 +#define PAD_TRIANGLE 4 +#define PAD_R1 3 +#define PAD_L1 2 +#define PAD_R2 1 +#define PAD_L2 0 + +/* end of pad.h */ + +extern keyEvent event; + +extern u16 status[2]; +extern u32 pads; + +int POV(u32 direction, u32 angle); +s32 _PADopen(void *pDsp); +void _PADclose(); +void _KeyPress(int pad, u32 key); +void _KeyRelease(int pad, u32 key); +void PADsetMode(int pad, int mode); +void _PADupdate(int pad); + +void __Log(char *fmt, ...); +void LoadConfig(); +void SaveConfig(); + +void SysMessage(char *fmt, ...); + +#endif + + diff --git a/plugins/zerospu2/3rdparty/SoundTouch/3dnow_win.cpp b/plugins/zerospu2/3rdparty/SoundTouch/3dnow_win.cpp index 2e369904ec..01e6dab8a7 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/3dnow_win.cpp +++ b/plugins/zerospu2/3rdparty/SoundTouch/3dnow_win.cpp @@ -1,350 +1,350 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Win32 version of the AMD 3DNow! optimized routines for AMD K6-2/Athlon -/// processors. All 3DNow! optimized functions have been gathered into this -/// single source code file, regardless to their class or original source code -/// file, in order to ease porting the library to other compiler and processor -/// platforms. -/// -/// By the way; the performance gain depends heavily on the CPU generation: On -/// K6-2 these routines provided speed-up of even 2.4 times, while on Athlon the -/// difference to the original routines stayed at unremarkable 8%! Such a small -/// improvement on Athlon is due to 3DNow can perform only two operations in -/// parallel, and obviously also the Athlon FPU is doing a very good job with -/// the standard C floating point routines! Here these routines are anyway, -/// although it might not be worth the effort to convert these to GCC platform, -/// for Athlon CPU at least. The situation is different regarding the SSE -/// optimizations though, thanks to the four parallel operations of SSE that -/// already make a difference. -/// -/// This file is to be compiled in Windows platform with Microsoft Visual C++ -/// Compiler. Please see '3dnow_gcc.cpp' for the gcc compiler version for all -/// GNU platforms (if file supplied). -/// -/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ -/// 6.0 processor pack" update to support 3DNow! instruction set. The update is -/// available for download at Microsoft Developers Network, see here: -/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx -/// -/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and -/// perform a search with keywords "processor pack". -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.10 $ -// -// $Id: 3dnow_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include "cpu_detect.h" -#include "STTypes.h" - -#ifndef _WIN32 -#error "wrong platform - this source code file is exclusively for Win32 platform" -#endif - -using namespace soundtouch; - -#ifdef ALLOW_3DNOW -// 3DNow! routines available only with float sample type - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of 3DNow! optimized functions of class 'TDStretch3DNow' -// -////////////////////////////////////////////////////////////////////////////// - -#include "TDStretch.h" -#include - -// these are declared in 'TDStretch.cpp' -extern int scanOffsets[4][24]; - - -// Calculates cross correlation of two buffers -double TDStretch3DNow::calcCrossCorrStereo(const float *pV1, const float *pV2) const -{ - uint overlapLengthLocal = overlapLength; - float corr; - - // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors - /* - c-pseudocode: - - corr = 0; - for (i = 0; i < overlapLength / 4; i ++) - { - corr += pV1[0] * pV2[0]; - pV1[1] * pV2[1]; - pV1[2] * pV2[2]; - pV1[3] * pV2[3]; - pV1[4] * pV2[4]; - pV1[5] * pV2[5]; - pV1[6] * pV2[6]; - pV1[7] * pV2[7]; - - pV1 += 8; - pV2 += 8; - } - */ - - _asm - { - // give prefetch hints to CPU of what data are to be needed soonish. - // give more aggressive hints on pV1 as that changes more between different calls - // while pV2 stays the same. - prefetch [pV1] - prefetch [pV2] - prefetch [pV1 + 32] - - mov eax, dword ptr pV2 - mov ebx, dword ptr pV1 - - pxor mm0, mm0 - - mov ecx, overlapLengthLocal - shr ecx, 2 // div by four - - loop1: - movq mm1, [eax] - prefetch [eax + 32] // give a prefetch hint to CPU what data are to be needed soonish - pfmul mm1, [ebx] - prefetch [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish - - movq mm2, [eax + 8] - pfadd mm0, mm1 - pfmul mm2, [ebx + 8] - - movq mm3, [eax + 16] - pfadd mm0, mm2 - pfmul mm3, [ebx + 16] - - movq mm4, [eax + 24] - pfadd mm0, mm3 - pfmul mm4, [ebx + 24] - - add eax, 32 - pfadd mm0, mm4 - add ebx, 32 - - dec ecx - jnz loop1 - - // add halfs of mm0 together and return the result. - // note: mm1 is used as a dummy parameter only, we actually don't care about it's value - pfacc mm0, mm1 - movd corr, mm0 - femms - } - - return corr; -} - - - - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of 3DNow! optimized functions of class 'FIRFilter' -// -////////////////////////////////////////////////////////////////////////////// - -#include "FIRFilter.h" - -FIRFilter3DNow::FIRFilter3DNow() : FIRFilter() -{ - filterCoeffsUnalign = NULL; -} - - -FIRFilter3DNow::~FIRFilter3DNow() -{ - delete[] filterCoeffsUnalign; -} - - -// (overloaded) Calculates filter coefficients for 3DNow! routine -void FIRFilter3DNow::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) -{ - uint i; - float fDivider; - - FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); - - // Scale the filter coefficients so that it won't be necessary to scale the filtering result - // also rearrange coefficients suitably for 3DNow! - // Ensure that filter coeffs array is aligned to 16-byte boundary - delete[] filterCoeffsUnalign; - filterCoeffsUnalign = new float[2 * newLength + 4]; - filterCoeffsAlign = (float *)(((uint)filterCoeffsUnalign + 15) & -16); - - fDivider = (float)resultDivider; - - // rearrange the filter coefficients for mmx routines - for (i = 0; i < newLength; i ++) - { - filterCoeffsAlign[2 * i + 0] = - filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; - } -} - - -// 3DNow!-optimized version of the filter routine for stereo sound -uint FIRFilter3DNow::evaluateFilterStereo(float *dest, const float *src, const uint numSamples) const -{ - float *filterCoeffsLocal = filterCoeffsAlign; - uint count = (numSamples - length) & -2; - uint lengthLocal = length / 4; - - assert(length != 0); - assert(count % 2 == 0); - - /* original code: - - double suml1, suml2; - double sumr1, sumr2; - uint i, j; - - for (j = 0; j < count; j += 2) - { - const float *ptr; - - suml1 = sumr1 = 0.0; - suml2 = sumr2 = 0.0; - ptr = src; - filterCoeffsLocal = filterCoeffs; - for (i = 0; i < lengthLocal; i ++) - { - // unroll loop for efficiency. - - suml1 += ptr[0] * filterCoeffsLocal[0] + - ptr[2] * filterCoeffsLocal[2] + - ptr[4] * filterCoeffsLocal[4] + - ptr[6] * filterCoeffsLocal[6]; - - sumr1 += ptr[1] * filterCoeffsLocal[1] + - ptr[3] * filterCoeffsLocal[3] + - ptr[5] * filterCoeffsLocal[5] + - ptr[7] * filterCoeffsLocal[7]; - - suml2 += ptr[8] * filterCoeffsLocal[0] + - ptr[10] * filterCoeffsLocal[2] + - ptr[12] * filterCoeffsLocal[4] + - ptr[14] * filterCoeffsLocal[6]; - - sumr2 += ptr[9] * filterCoeffsLocal[1] + - ptr[11] * filterCoeffsLocal[3] + - ptr[13] * filterCoeffsLocal[5] + - ptr[15] * filterCoeffsLocal[7]; - - ptr += 16; - filterCoeffsLocal += 8; - } - dest[0] = (float)suml1; - dest[1] = (float)sumr1; - dest[2] = (float)suml2; - dest[3] = (float)sumr2; - - src += 4; - dest += 4; - } - - */ - _asm - { - mov eax, dword ptr dest - mov ebx, dword ptr src - mov edx, count - shr edx, 1 - - loop1: - // "outer loop" : during each round 2*2 output samples are calculated - prefetch [ebx] // give a prefetch hint to CPU what data are to be needed soonish - prefetch [filterCoeffsLocal] // give a prefetch hint to CPU what data are to be needed soonish - - mov esi, ebx - mov edi, filterCoeffsLocal - pxor mm0, mm0 - pxor mm1, mm1 - mov ecx, lengthLocal - - loop2: - // "inner loop" : during each round four FIR filter taps are evaluated for 2*2 output samples - movq mm2, [edi] - movq mm3, mm2 - prefetch [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish - pfmul mm2, [esi] - prefetch [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish - pfmul mm3, [esi + 8] - - movq mm4, [edi + 8] - movq mm5, mm4 - pfadd mm0, mm2 - pfmul mm4, [esi + 8] - pfadd mm1, mm3 - pfmul mm5, [esi + 16] - - movq mm2, [edi + 16] - movq mm6, mm2 - pfadd mm0, mm4 - pfmul mm2, [esi + 16] - pfadd mm1, mm5 - pfmul mm6, [esi + 24] - - movq mm3, [edi + 24] - movq mm7, mm3 - pfadd mm0, mm2 - pfmul mm3, [esi + 24] - pfadd mm1, mm6 - pfmul mm7, [esi + 32] - add esi, 32 - pfadd mm0, mm3 - add edi, 32 - pfadd mm1, mm7 - - dec ecx - jnz loop2 - - movq [eax], mm0 - add ebx, 16 - movq [eax + 8], mm1 - add eax, 16 - - dec edx - jnz loop1 - - femms - } - - return count; -} - - -#endif // ALLOW_3DNOW +//////////////////////////////////////////////////////////////////////////////// +/// +/// Win32 version of the AMD 3DNow! optimized routines for AMD K6-2/Athlon +/// processors. All 3DNow! optimized functions have been gathered into this +/// single source code file, regardless to their class or original source code +/// file, in order to ease porting the library to other compiler and processor +/// platforms. +/// +/// By the way; the performance gain depends heavily on the CPU generation: On +/// K6-2 these routines provided speed-up of even 2.4 times, while on Athlon the +/// difference to the original routines stayed at unremarkable 8%! Such a small +/// improvement on Athlon is due to 3DNow can perform only two operations in +/// parallel, and obviously also the Athlon FPU is doing a very good job with +/// the standard C floating point routines! Here these routines are anyway, +/// although it might not be worth the effort to convert these to GCC platform, +/// for Athlon CPU at least. The situation is different regarding the SSE +/// optimizations though, thanks to the four parallel operations of SSE that +/// already make a difference. +/// +/// This file is to be compiled in Windows platform with Microsoft Visual C++ +/// Compiler. Please see '3dnow_gcc.cpp' for the gcc compiler version for all +/// GNU platforms (if file supplied). +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support 3DNow! instruction set. The update is +/// available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx +/// +/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and +/// perform a search with keywords "processor pack". +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: 3dnow_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" +#include "STTypes.h" + +#ifndef _WIN32 +#error "wrong platform - this source code file is exclusively for Win32 platform" +#endif + +using namespace soundtouch; + +#ifdef ALLOW_3DNOW +// 3DNow! routines available only with float sample type + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of 3DNow! optimized functions of class 'TDStretch3DNow' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include + +// these are declared in 'TDStretch.cpp' +extern int scanOffsets[4][24]; + + +// Calculates cross correlation of two buffers +double TDStretch3DNow::calcCrossCorrStereo(const float *pV1, const float *pV2) const +{ + uint overlapLengthLocal = overlapLength; + float corr; + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + /* + c-pseudocode: + + corr = 0; + for (i = 0; i < overlapLength / 4; i ++) + { + corr += pV1[0] * pV2[0]; + pV1[1] * pV2[1]; + pV1[2] * pV2[2]; + pV1[3] * pV2[3]; + pV1[4] * pV2[4]; + pV1[5] * pV2[5]; + pV1[6] * pV2[6]; + pV1[7] * pV2[7]; + + pV1 += 8; + pV2 += 8; + } + */ + + _asm + { + // give prefetch hints to CPU of what data are to be needed soonish. + // give more aggressive hints on pV1 as that changes more between different calls + // while pV2 stays the same. + prefetch [pV1] + prefetch [pV2] + prefetch [pV1 + 32] + + mov eax, dword ptr pV2 + mov ebx, dword ptr pV1 + + pxor mm0, mm0 + + mov ecx, overlapLengthLocal + shr ecx, 2 // div by four + + loop1: + movq mm1, [eax] + prefetch [eax + 32] // give a prefetch hint to CPU what data are to be needed soonish + pfmul mm1, [ebx] + prefetch [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish + + movq mm2, [eax + 8] + pfadd mm0, mm1 + pfmul mm2, [ebx + 8] + + movq mm3, [eax + 16] + pfadd mm0, mm2 + pfmul mm3, [ebx + 16] + + movq mm4, [eax + 24] + pfadd mm0, mm3 + pfmul mm4, [ebx + 24] + + add eax, 32 + pfadd mm0, mm4 + add ebx, 32 + + dec ecx + jnz loop1 + + // add halfs of mm0 together and return the result. + // note: mm1 is used as a dummy parameter only, we actually don't care about it's value + pfacc mm0, mm1 + movd corr, mm0 + femms + } + + return corr; +} + + + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of 3DNow! optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + +FIRFilter3DNow::FIRFilter3DNow() : FIRFilter() +{ + filterCoeffsUnalign = NULL; +} + + +FIRFilter3DNow::~FIRFilter3DNow() +{ + delete[] filterCoeffsUnalign; +} + + +// (overloaded) Calculates filter coefficients for 3DNow! routine +void FIRFilter3DNow::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + float fDivider; + + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Scale the filter coefficients so that it won't be necessary to scale the filtering result + // also rearrange coefficients suitably for 3DNow! + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new float[2 * newLength + 4]; + filterCoeffsAlign = (float *)(((uint)filterCoeffsUnalign + 15) & -16); + + fDivider = (float)resultDivider; + + // rearrange the filter coefficients for mmx routines + for (i = 0; i < newLength; i ++) + { + filterCoeffsAlign[2 * i + 0] = + filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; + } +} + + +// 3DNow!-optimized version of the filter routine for stereo sound +uint FIRFilter3DNow::evaluateFilterStereo(float *dest, const float *src, const uint numSamples) const +{ + float *filterCoeffsLocal = filterCoeffsAlign; + uint count = (numSamples - length) & -2; + uint lengthLocal = length / 4; + + assert(length != 0); + assert(count % 2 == 0); + + /* original code: + + double suml1, suml2; + double sumr1, sumr2; + uint i, j; + + for (j = 0; j < count; j += 2) + { + const float *ptr; + + suml1 = sumr1 = 0.0; + suml2 = sumr2 = 0.0; + ptr = src; + filterCoeffsLocal = filterCoeffs; + for (i = 0; i < lengthLocal; i ++) + { + // unroll loop for efficiency. + + suml1 += ptr[0] * filterCoeffsLocal[0] + + ptr[2] * filterCoeffsLocal[2] + + ptr[4] * filterCoeffsLocal[4] + + ptr[6] * filterCoeffsLocal[6]; + + sumr1 += ptr[1] * filterCoeffsLocal[1] + + ptr[3] * filterCoeffsLocal[3] + + ptr[5] * filterCoeffsLocal[5] + + ptr[7] * filterCoeffsLocal[7]; + + suml2 += ptr[8] * filterCoeffsLocal[0] + + ptr[10] * filterCoeffsLocal[2] + + ptr[12] * filterCoeffsLocal[4] + + ptr[14] * filterCoeffsLocal[6]; + + sumr2 += ptr[9] * filterCoeffsLocal[1] + + ptr[11] * filterCoeffsLocal[3] + + ptr[13] * filterCoeffsLocal[5] + + ptr[15] * filterCoeffsLocal[7]; + + ptr += 16; + filterCoeffsLocal += 8; + } + dest[0] = (float)suml1; + dest[1] = (float)sumr1; + dest[2] = (float)suml2; + dest[3] = (float)sumr2; + + src += 4; + dest += 4; + } + + */ + _asm + { + mov eax, dword ptr dest + mov ebx, dword ptr src + mov edx, count + shr edx, 1 + + loop1: + // "outer loop" : during each round 2*2 output samples are calculated + prefetch [ebx] // give a prefetch hint to CPU what data are to be needed soonish + prefetch [filterCoeffsLocal] // give a prefetch hint to CPU what data are to be needed soonish + + mov esi, ebx + mov edi, filterCoeffsLocal + pxor mm0, mm0 + pxor mm1, mm1 + mov ecx, lengthLocal + + loop2: + // "inner loop" : during each round four FIR filter taps are evaluated for 2*2 output samples + movq mm2, [edi] + movq mm3, mm2 + prefetch [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish + pfmul mm2, [esi] + prefetch [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish + pfmul mm3, [esi + 8] + + movq mm4, [edi + 8] + movq mm5, mm4 + pfadd mm0, mm2 + pfmul mm4, [esi + 8] + pfadd mm1, mm3 + pfmul mm5, [esi + 16] + + movq mm2, [edi + 16] + movq mm6, mm2 + pfadd mm0, mm4 + pfmul mm2, [esi + 16] + pfadd mm1, mm5 + pfmul mm6, [esi + 24] + + movq mm3, [edi + 24] + movq mm7, mm3 + pfadd mm0, mm2 + pfmul mm3, [esi + 24] + pfadd mm1, mm6 + pfmul mm7, [esi + 32] + add esi, 32 + pfadd mm0, mm3 + add edi, 32 + pfadd mm1, mm7 + + dec ecx + jnz loop2 + + movq [eax], mm0 + add ebx, 16 + movq [eax + 8], mm1 + add eax, 16 + + dec edx + jnz loop1 + + femms + } + + return count; +} + + +#endif // ALLOW_3DNOW diff --git a/plugins/zerospu2/3rdparty/SoundTouch/AAFilter.cpp b/plugins/zerospu2/3rdparty/SoundTouch/AAFilter.cpp index 9a5cf539c0..6bf529ccec 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/AAFilter.cpp +++ b/plugins/zerospu2/3rdparty/SoundTouch/AAFilter.cpp @@ -1,184 +1,184 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// FIR low-pass (anti-alias) filter with filter coefficient design routine and -/// MMX optimization. -/// -/// Anti-alias filter is used to prevent folding of high frequencies when -/// transposing the sample rate with interpolation. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.9 $ -// -// $Id: AAFilter.cpp,v 1.9 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include "AAFilter.h" -#include "FIRFilter.h" - -using namespace soundtouch; - -#define PI 3.141592655357989 -#define TWOPI (2 * PI) - -/***************************************************************************** - * - * Implementation of the class 'AAFilter' - * - *****************************************************************************/ - -AAFilter::AAFilter(const uint length) -{ - pFIR = FIRFilter::newInstance(); - cutoffFreq = 0.5; - setLength(length); -} - - - -AAFilter::~AAFilter() -{ - delete pFIR; -} - - - -// Sets new anti-alias filter cut-off edge frequency, scaled to -// sampling frequency (nyquist frequency = 0.5). -// The filter will cut frequencies higher than the given frequency. -void AAFilter::setCutoffFreq(const double newCutoffFreq) -{ - cutoffFreq = newCutoffFreq; - calculateCoeffs(); -} - - - -// Sets number of FIR filter taps -void AAFilter::setLength(const uint newLength) -{ - length = newLength; - calculateCoeffs(); -} - - - -// Calculates coefficients for a low-pass FIR filter using Hamming window -void AAFilter::calculateCoeffs() -{ - uint i; - double cntTemp, temp, tempCoeff,h, w; - double fc2, wc; - double scaleCoeff, sum; - double *work; - SAMPLETYPE *coeffs; - - assert(length > 0); - assert(length % 4 == 0); - assert(cutoffFreq >= 0); - assert(cutoffFreq <= 0.5); - - work = new double[length]; - coeffs = new SAMPLETYPE[length]; - - fc2 = 2.0 * cutoffFreq; - wc = PI * fc2; - tempCoeff = TWOPI / (double)length; - - sum = 0; - for (i = 0; i < length; i ++) - { - cntTemp = (double)i - (double)(length / 2); - - temp = cntTemp * wc; - if (temp != 0) - { - h = fc2 * sin(temp) / temp; // sinc function - } - else - { - h = 1.0; - } - w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window - - temp = w * h; - work[i] = temp; - - // calc net sum of coefficients - sum += temp; - } - - // ensure the sum of coefficients is larger than zero - assert(sum > 0); - - // ensure we've really designed a lowpass filter... - assert(work[length/2] > 0); - assert(work[length/2 + 1] > -1e-6); - assert(work[length/2 - 1] > -1e-6); - - // Calculate a scaling coefficient in such a way that the result can be - // divided by 16384 - scaleCoeff = 16384.0f / sum; - - for (i = 0; i < length; i ++) - { - // scale & round to nearest integer - temp = work[i] * scaleCoeff; - temp += (temp >= 0) ? 0.5 : -0.5; - // ensure no overfloods - assert(temp >= -32768 && temp <= 32767); - coeffs[i] = (SAMPLETYPE)temp; - } - - // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384 - pFIR->setCoefficients(coeffs, length, 14); - - delete[] work; - delete[] coeffs; -} - - -// Applies the filter to the given sequence of samples. -// Note : The amount of outputted samples is by value of 'filter length' -// smaller than the amount of input samples. -uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const -{ - return pFIR->evaluate(dest, src, numSamples, numChannels); -} - - -uint AAFilter::getLength() const -{ - return pFIR->getLength(); -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// FIR low-pass (anti-alias) filter with filter coefficient design routine and +/// MMX optimization. +/// +/// Anti-alias filter is used to prevent folding of high frequencies when +/// transposing the sample rate with interpolation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.9 $ +// +// $Id: AAFilter.cpp,v 1.9 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include "AAFilter.h" +#include "FIRFilter.h" + +using namespace soundtouch; + +#define PI 3.141592655357989 +#define TWOPI (2 * PI) + +/***************************************************************************** + * + * Implementation of the class 'AAFilter' + * + *****************************************************************************/ + +AAFilter::AAFilter(const uint length) +{ + pFIR = FIRFilter::newInstance(); + cutoffFreq = 0.5; + setLength(length); +} + + + +AAFilter::~AAFilter() +{ + delete pFIR; +} + + + +// Sets new anti-alias filter cut-off edge frequency, scaled to +// sampling frequency (nyquist frequency = 0.5). +// The filter will cut frequencies higher than the given frequency. +void AAFilter::setCutoffFreq(const double newCutoffFreq) +{ + cutoffFreq = newCutoffFreq; + calculateCoeffs(); +} + + + +// Sets number of FIR filter taps +void AAFilter::setLength(const uint newLength) +{ + length = newLength; + calculateCoeffs(); +} + + + +// Calculates coefficients for a low-pass FIR filter using Hamming window +void AAFilter::calculateCoeffs() +{ + uint i; + double cntTemp, temp, tempCoeff,h, w; + double fc2, wc; + double scaleCoeff, sum; + double *work; + SAMPLETYPE *coeffs; + + assert(length > 0); + assert(length % 4 == 0); + assert(cutoffFreq >= 0); + assert(cutoffFreq <= 0.5); + + work = new double[length]; + coeffs = new SAMPLETYPE[length]; + + fc2 = 2.0 * cutoffFreq; + wc = PI * fc2; + tempCoeff = TWOPI / (double)length; + + sum = 0; + for (i = 0; i < length; i ++) + { + cntTemp = (double)i - (double)(length / 2); + + temp = cntTemp * wc; + if (temp != 0) + { + h = fc2 * sin(temp) / temp; // sinc function + } + else + { + h = 1.0; + } + w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window + + temp = w * h; + work[i] = temp; + + // calc net sum of coefficients + sum += temp; + } + + // ensure the sum of coefficients is larger than zero + assert(sum > 0); + + // ensure we've really designed a lowpass filter... + assert(work[length/2] > 0); + assert(work[length/2 + 1] > -1e-6); + assert(work[length/2 - 1] > -1e-6); + + // Calculate a scaling coefficient in such a way that the result can be + // divided by 16384 + scaleCoeff = 16384.0f / sum; + + for (i = 0; i < length; i ++) + { + // scale & round to nearest integer + temp = work[i] * scaleCoeff; + temp += (temp >= 0) ? 0.5 : -0.5; + // ensure no overfloods + assert(temp >= -32768 && temp <= 32767); + coeffs[i] = (SAMPLETYPE)temp; + } + + // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384 + pFIR->setCoefficients(coeffs, length, 14); + + delete[] work; + delete[] coeffs; +} + + +// Applies the filter to the given sequence of samples. +// Note : The amount of outputted samples is by value of 'filter length' +// smaller than the amount of input samples. +uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const +{ + return pFIR->evaluate(dest, src, numSamples, numChannels); +} + + +uint AAFilter::getLength() const +{ + return pFIR->getLength(); +} diff --git a/plugins/zerospu2/3rdparty/SoundTouch/AAFilter.h b/plugins/zerospu2/3rdparty/SoundTouch/AAFilter.h index 4c85dcdbe7..68eb50d27f 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/AAFilter.h +++ b/plugins/zerospu2/3rdparty/SoundTouch/AAFilter.h @@ -1,91 +1,91 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo -/// while maintaining the original pitch by using a time domain WSOLA-like method -/// with several performance-increasing tweaks. -/// -/// Anti-alias filter is used to prevent folding of high frequencies when -/// transposing the sample rate with interpolation. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.10 $ -// -// $Id: AAFilter.h,v 1.10 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef AAFilter_H -#define AAFilter_H - -#include "STTypes.h" - -namespace soundtouch -{ - -class AAFilter -{ -protected: - class FIRFilter *pFIR; - - /// Low-pass filter cut-off frequency, negative = invalid - double cutoffFreq; - - /// num of filter taps - uint length; - - /// Calculate the FIR coefficients realizing the given cutoff-frequency - void calculateCoeffs(); -public: - AAFilter(uint length); - - ~AAFilter(); - - /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling - /// frequency (nyquist frequency = 0.5). The filter will cut off the - /// frequencies than that. - void setCutoffFreq(double newCutoffFreq); - - /// Sets number of FIR filter taps, i.e. ~filter complexity - void setLength(uint newLength); - - uint getLength() const; - - /// Applies the filter to the given sequence of samples. - /// Note : The amount of outputted samples is by value of 'filter length' - /// smaller than the amount of input samples. - uint evaluate(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples, - uint numChannels) const; -}; - -} - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like method +/// with several performance-increasing tweaks. +/// +/// Anti-alias filter is used to prevent folding of high frequencies when +/// transposing the sample rate with interpolation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: AAFilter.h,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef AAFilter_H +#define AAFilter_H + +#include "STTypes.h" + +namespace soundtouch +{ + +class AAFilter +{ +protected: + class FIRFilter *pFIR; + + /// Low-pass filter cut-off frequency, negative = invalid + double cutoffFreq; + + /// num of filter taps + uint length; + + /// Calculate the FIR coefficients realizing the given cutoff-frequency + void calculateCoeffs(); +public: + AAFilter(uint length); + + ~AAFilter(); + + /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling + /// frequency (nyquist frequency = 0.5). The filter will cut off the + /// frequencies than that. + void setCutoffFreq(double newCutoffFreq); + + /// Sets number of FIR filter taps, i.e. ~filter complexity + void setLength(uint newLength); + + uint getLength() const; + + /// Applies the filter to the given sequence of samples. + /// Note : The amount of outputted samples is by value of 'filter length' + /// smaller than the amount of input samples. + uint evaluate(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples, + uint numChannels) const; +}; + +} + +#endif diff --git a/plugins/zerospu2/3rdparty/SoundTouch/BPMDetect.h b/plugins/zerospu2/3rdparty/SoundTouch/BPMDetect.h index ac616e7e2b..b5e393979d 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/BPMDetect.h +++ b/plugins/zerospu2/3rdparty/SoundTouch/BPMDetect.h @@ -1,159 +1,159 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Beats-per-minute (BPM) detection routine. -/// -/// The beat detection algorithm works as follows: -/// - Use function 'inputSamples' to input a chunks of samples to the class for -/// analysis. It's a good idea to enter a large sound file or stream in smallish -/// chunks of around few kilosamples in order not to extinguish too much RAM memory. -/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden, -/// which is basically ok as low (bass) frequencies mostly determine the beat rate. -/// Simple averaging is used for anti-alias filtering because the resulting signal -/// quality isn't of that high importance. -/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by -/// taking absolute value that's smoothed by sliding average. Signal levels that -/// are below a couple of times the general RMS amplitude level are cut away to -/// leave only notable peaks there. -/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term -/// autocorrelation function of the enveloped signal. -/// - After whole sound data file has been analyzed as above, the bpm level is -/// detected by function 'getBpm' that finds the highest peak of the autocorrelation -/// function, calculates it's precise location and converts this reading to bpm's. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.5 $ -// -// $Id: BPMDetect.h,v 1.5 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef _BPMDetect_H_ -#define _BPMDetect_H_ - -#include "STTypes.h" -#include "FIFOSampleBuffer.h" - -/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit. -#define MIN_BPM 45 - -/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit. -#define MAX_BPM 230 - - -/// Class for calculating BPM rate for audio data. -class BPMDetect -{ -protected: - /// Auto-correlation accumulator bins. - float *xcorr; - - /// Amplitude envelope sliding average approximation level accumulator - float envelopeAccu; - - /// RMS volume sliding average approximation level accumulator - float RMSVolumeAccu; - - /// Sample average counter. - int decimateCount; - - /// Sample average accumulator for FIFO-like decimation. - soundtouch::LONG_SAMPLETYPE decimateSum; - - /// Decimate sound by this coefficient to reach approx. 500 Hz. - int decimateBy; - - /// Auto-correlation window length - int windowLen; - - /// Number of channels (1 = mono, 2 = stereo) - int channels; - - /// sample rate - int sampleRate; - - /// Beginning of auto-correlation window: Autocorrelation isn't being updated for - /// the first these many correlation bins. - int windowStart; - - /// FIFO-buffer for decimated processing samples. - soundtouch::FIFOSampleBuffer *buffer; - - /// Initialize the class for processing. - void init(int numChannels, int sampleRate); - - /// Updates auto-correlation function for given number of decimated samples that - /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe - /// though). - void updateXCorr(int process_samples /// How many samples are processed. - ); - - /// Decimates samples to approx. 500 Hz. - /// - /// \return Number of output samples. - int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer - const soundtouch::SAMPLETYPE *src, ///< Source sample buffer - int numsamples ///< Number of source samples. - ); - - /// Calculates amplitude envelope for the buffer of samples. - /// Result is output to 'samples'. - void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer - int numsamples ///< Number of samples in buffer - ); - -public: - /// Constructor. - BPMDetect(int numChannels, ///< Number of channels in sample data. - int sampleRate ///< Sample rate in Hz. - ); - - /// Destructor. - virtual ~BPMDetect(); - - /// Inputs a block of samples for analyzing: Envelopes the samples and then - /// updates the autocorrelation estimation. When whole song data has been input - /// in smaller blocks using this function, read the resulting bpm with 'getBpm' - /// function. - /// - /// Notice that data in 'samples' array can be disrupted in processing. - void inputSamples(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer - int numSamples ///< Number of samples in buffer - ); - - - /// Analyzes the results and returns the BPM rate. Use this function to read result - /// after whole song data has been input to the class by consecutive calls of - /// 'inputSamples' function. - /// - /// \return Beats-per-minute rate, or zero if detection failed. - float getBpm(); -}; - -#endif // _BPMDetect_H_ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Beats-per-minute (BPM) detection routine. +/// +/// The beat detection algorithm works as follows: +/// - Use function 'inputSamples' to input a chunks of samples to the class for +/// analysis. It's a good idea to enter a large sound file or stream in smallish +/// chunks of around few kilosamples in order not to extinguish too much RAM memory. +/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden, +/// which is basically ok as low (bass) frequencies mostly determine the beat rate. +/// Simple averaging is used for anti-alias filtering because the resulting signal +/// quality isn't of that high importance. +/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by +/// taking absolute value that's smoothed by sliding average. Signal levels that +/// are below a couple of times the general RMS amplitude level are cut away to +/// leave only notable peaks there. +/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term +/// autocorrelation function of the enveloped signal. +/// - After whole sound data file has been analyzed as above, the bpm level is +/// detected by function 'getBpm' that finds the highest peak of the autocorrelation +/// function, calculates it's precise location and converts this reading to bpm's. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.5 $ +// +// $Id: BPMDetect.h,v 1.5 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _BPMDetect_H_ +#define _BPMDetect_H_ + +#include "STTypes.h" +#include "FIFOSampleBuffer.h" + +/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit. +#define MIN_BPM 45 + +/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit. +#define MAX_BPM 230 + + +/// Class for calculating BPM rate for audio data. +class BPMDetect +{ +protected: + /// Auto-correlation accumulator bins. + float *xcorr; + + /// Amplitude envelope sliding average approximation level accumulator + float envelopeAccu; + + /// RMS volume sliding average approximation level accumulator + float RMSVolumeAccu; + + /// Sample average counter. + int decimateCount; + + /// Sample average accumulator for FIFO-like decimation. + soundtouch::LONG_SAMPLETYPE decimateSum; + + /// Decimate sound by this coefficient to reach approx. 500 Hz. + int decimateBy; + + /// Auto-correlation window length + int windowLen; + + /// Number of channels (1 = mono, 2 = stereo) + int channels; + + /// sample rate + int sampleRate; + + /// Beginning of auto-correlation window: Autocorrelation isn't being updated for + /// the first these many correlation bins. + int windowStart; + + /// FIFO-buffer for decimated processing samples. + soundtouch::FIFOSampleBuffer *buffer; + + /// Initialize the class for processing. + void init(int numChannels, int sampleRate); + + /// Updates auto-correlation function for given number of decimated samples that + /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe + /// though). + void updateXCorr(int process_samples /// How many samples are processed. + ); + + /// Decimates samples to approx. 500 Hz. + /// + /// \return Number of output samples. + int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer + const soundtouch::SAMPLETYPE *src, ///< Source sample buffer + int numsamples ///< Number of source samples. + ); + + /// Calculates amplitude envelope for the buffer of samples. + /// Result is output to 'samples'. + void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer + int numsamples ///< Number of samples in buffer + ); + +public: + /// Constructor. + BPMDetect(int numChannels, ///< Number of channels in sample data. + int sampleRate ///< Sample rate in Hz. + ); + + /// Destructor. + virtual ~BPMDetect(); + + /// Inputs a block of samples for analyzing: Envelopes the samples and then + /// updates the autocorrelation estimation. When whole song data has been input + /// in smaller blocks using this function, read the resulting bpm with 'getBpm' + /// function. + /// + /// Notice that data in 'samples' array can be disrupted in processing. + void inputSamples(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer + int numSamples ///< Number of samples in buffer + ); + + + /// Analyzes the results and returns the BPM rate. Use this function to read result + /// after whole song data has been input to the class by consecutive calls of + /// 'inputSamples' function. + /// + /// \return Beats-per-minute rate, or zero if detection failed. + float getBpm(); +}; + +#endif // _BPMDetect_H_ diff --git a/plugins/zerospu2/3rdparty/SoundTouch/FIFOSampleBuffer.cpp b/plugins/zerospu2/3rdparty/SoundTouch/FIFOSampleBuffer.cpp index 2bf965b763..a8918a8133 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/FIFOSampleBuffer.cpp +++ b/plugins/zerospu2/3rdparty/SoundTouch/FIFOSampleBuffer.cpp @@ -1,252 +1,252 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// A buffer class for temporarily storaging sound samples, operates as a -/// first-in-first-out pipe. -/// -/// Samples are added to the end of the sample buffer with the 'putSamples' -/// function, and are received from the beginning of the buffer by calling -/// the 'receiveSamples' function. The class automatically removes the -/// outputted samples from the buffer, as well as grows the buffer size -/// whenever necessary. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.11 $ -// -// $Id: FIFOSampleBuffer.cpp,v 1.11 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include - -#include "FIFOSampleBuffer.h" - -using namespace soundtouch; - -// Constructor -FIFOSampleBuffer::FIFOSampleBuffer(uint numChannels) -{ - sizeInBytes = 0; // reasonable initial value - buffer = NULL; //new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE)]; - bufferUnaligned = NULL; - samplesInBuffer = 0; - bufferPos = 0; - channels = numChannels; -} - - -// destructor -FIFOSampleBuffer::~FIFOSampleBuffer() -{ - delete[] bufferUnaligned; -} - - -// Sets number of channels, 1 = mono, 2 = stereo -void FIFOSampleBuffer::setChannels(const uint numChannels) -{ - uint usedBytes; - - usedBytes = channels * samplesInBuffer; - channels = numChannels; - samplesInBuffer = usedBytes / channels; -} - - -// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and -// zeroes this pointer by copying samples from the 'bufferPos' pointer -// location on to the beginning of the buffer. -void FIFOSampleBuffer::rewind() -{ - if (bufferPos) - { - memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer); - bufferPos = 0; - } -} - - -// Adds 'numSamples' pcs of samples from the 'samples' memory position to -// the sample buffer. -void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint numSamples) -{ - memcpy(ptrEnd(numSamples), samples, sizeof(SAMPLETYPE) * numSamples * channels); - samplesInBuffer += numSamples; -} - - -// Increases the number of samples in the buffer without copying any actual -// samples. -// -// This function is used to update the number of samples in the sample buffer -// when accessing the buffer directly with 'ptrEnd' function. Please be -// careful though! -void FIFOSampleBuffer::putSamples(uint numSamples) -{ - uint req; - - req = samplesInBuffer + numSamples; - ensureCapacity(req); - samplesInBuffer += numSamples; -} - - -// Returns a pointer to the end of the used part of the sample buffer (i.e. -// where the new samples are to be inserted). This function may be used for -// inserting new samples into the sample buffer directly. Please be careful! -// -// Parameter 'slackCapacity' tells the function how much free capacity (in -// terms of samples) there _at least_ should be, in order to the caller to -// succesfully insert all the required samples to the buffer. When necessary, -// the function grows the buffer size to comply with this requirement. -// -// When using this function as means for inserting new samples, also remember -// to increase the sample count afterwards, by calling the -// 'putSamples(numSamples)' function. -SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity) -{ - ensureCapacity(samplesInBuffer + slackCapacity); - return buffer + samplesInBuffer * channels; -} - - -// Returns a pointer to the beginning of the currently non-outputted samples. -// This function is provided for accessing the output samples directly. -// Please be careful! -// -// When using this function to output samples, also remember to 'remove' the -// outputted samples from the buffer by calling the -// 'receiveSamples(numSamples)' function -SAMPLETYPE *FIFOSampleBuffer::ptrBegin() const -{ - return buffer + bufferPos * channels; -} - - -// Ensures that the buffer has enought capacity, i.e. space for _at least_ -// 'capacityRequirement' number of samples. The buffer is grown in steps of -// 4 kilobytes to eliminate the need for frequently growing up the buffer, -// as well as to round the buffer size up to the virtual memory page size. -void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement) -{ - SAMPLETYPE *tempUnaligned, *temp; - - if (capacityRequirement > getCapacity()) - { - // enlarge the buffer in 4kbyte steps (round up to next 4k boundary) - sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & -4096; - assert(sizeInBytes % 2 == 0); - tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; - if (tempUnaligned == NULL) - { - throw std::runtime_error("Couldn't allocate memory!\n"); - } - temp = (SAMPLETYPE *)(((ulongptr)tempUnaligned + 15) & -16); - memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE)); - delete[] bufferUnaligned; - buffer = temp; - bufferUnaligned = tempUnaligned; - bufferPos = 0; - } - else - { - // simply rewind the buffer (if necessary) - rewind(); - } -} - - -// Returns the current buffer capacity in terms of samples -uint FIFOSampleBuffer::getCapacity() const -{ - return sizeInBytes / (channels * sizeof(SAMPLETYPE)); -} - - -// Returns the number of samples currently in the buffer -uint FIFOSampleBuffer::numSamples() const -{ - return samplesInBuffer; -} - - -// Output samples from beginning of the sample buffer. Copies demanded number -// of samples to output and removes them from the sample buffer. If there -// are less than 'numsample' samples in the buffer, returns all available. -// -// Returns number of samples copied. -uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples) -{ - uint num; - - num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples; - - memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num); - return receiveSamples(num); -} - - -// Removes samples from the beginning of the sample buffer without copying them -// anywhere. Used to reduce the number of samples in the buffer, when accessing -// the sample buffer with the 'ptrBegin' function. -uint FIFOSampleBuffer::receiveSamples(uint maxSamples) -{ - if (maxSamples >= samplesInBuffer) - { - uint temp; - - temp = samplesInBuffer; - samplesInBuffer = 0; - return temp; - } - - samplesInBuffer -= maxSamples; - bufferPos += maxSamples; - - return maxSamples; -} - - -// Returns nonzero if the sample buffer is empty -int FIFOSampleBuffer::isEmpty() const -{ - return (samplesInBuffer == 0) ? 1 : 0; -} - - -// Clears the sample buffer -void FIFOSampleBuffer::clear() -{ - samplesInBuffer = 0; - bufferPos = 0; -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// A buffer class for temporarily storaging sound samples, operates as a +/// first-in-first-out pipe. +/// +/// Samples are added to the end of the sample buffer with the 'putSamples' +/// function, and are received from the beginning of the buffer by calling +/// the 'receiveSamples' function. The class automatically removes the +/// outputted samples from the buffer, as well as grows the buffer size +/// whenever necessary. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.11 $ +// +// $Id: FIFOSampleBuffer.cpp,v 1.11 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include "FIFOSampleBuffer.h" + +using namespace soundtouch; + +// Constructor +FIFOSampleBuffer::FIFOSampleBuffer(uint numChannels) +{ + sizeInBytes = 0; // reasonable initial value + buffer = NULL; //new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE)]; + bufferUnaligned = NULL; + samplesInBuffer = 0; + bufferPos = 0; + channels = numChannels; +} + + +// destructor +FIFOSampleBuffer::~FIFOSampleBuffer() +{ + delete[] bufferUnaligned; +} + + +// Sets number of channels, 1 = mono, 2 = stereo +void FIFOSampleBuffer::setChannels(const uint numChannels) +{ + uint usedBytes; + + usedBytes = channels * samplesInBuffer; + channels = numChannels; + samplesInBuffer = usedBytes / channels; +} + + +// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and +// zeroes this pointer by copying samples from the 'bufferPos' pointer +// location on to the beginning of the buffer. +void FIFOSampleBuffer::rewind() +{ + if (bufferPos) + { + memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer); + bufferPos = 0; + } +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position to +// the sample buffer. +void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + memcpy(ptrEnd(numSamples), samples, sizeof(SAMPLETYPE) * numSamples * channels); + samplesInBuffer += numSamples; +} + + +// Increases the number of samples in the buffer without copying any actual +// samples. +// +// This function is used to update the number of samples in the sample buffer +// when accessing the buffer directly with 'ptrEnd' function. Please be +// careful though! +void FIFOSampleBuffer::putSamples(uint numSamples) +{ + uint req; + + req = samplesInBuffer + numSamples; + ensureCapacity(req); + samplesInBuffer += numSamples; +} + + +// Returns a pointer to the end of the used part of the sample buffer (i.e. +// where the new samples are to be inserted). This function may be used for +// inserting new samples into the sample buffer directly. Please be careful! +// +// Parameter 'slackCapacity' tells the function how much free capacity (in +// terms of samples) there _at least_ should be, in order to the caller to +// succesfully insert all the required samples to the buffer. When necessary, +// the function grows the buffer size to comply with this requirement. +// +// When using this function as means for inserting new samples, also remember +// to increase the sample count afterwards, by calling the +// 'putSamples(numSamples)' function. +SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity) +{ + ensureCapacity(samplesInBuffer + slackCapacity); + return buffer + samplesInBuffer * channels; +} + + +// Returns a pointer to the beginning of the currently non-outputted samples. +// This function is provided for accessing the output samples directly. +// Please be careful! +// +// When using this function to output samples, also remember to 'remove' the +// outputted samples from the buffer by calling the +// 'receiveSamples(numSamples)' function +SAMPLETYPE *FIFOSampleBuffer::ptrBegin() const +{ + return buffer + bufferPos * channels; +} + + +// Ensures that the buffer has enought capacity, i.e. space for _at least_ +// 'capacityRequirement' number of samples. The buffer is grown in steps of +// 4 kilobytes to eliminate the need for frequently growing up the buffer, +// as well as to round the buffer size up to the virtual memory page size. +void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement) +{ + SAMPLETYPE *tempUnaligned, *temp; + + if (capacityRequirement > getCapacity()) + { + // enlarge the buffer in 4kbyte steps (round up to next 4k boundary) + sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & -4096; + assert(sizeInBytes % 2 == 0); + tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; + if (tempUnaligned == NULL) + { + throw std::runtime_error("Couldn't allocate memory!\n"); + } + temp = (SAMPLETYPE *)(((ulongptr)tempUnaligned + 15) & -16); + memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE)); + delete[] bufferUnaligned; + buffer = temp; + bufferUnaligned = tempUnaligned; + bufferPos = 0; + } + else + { + // simply rewind the buffer (if necessary) + rewind(); + } +} + + +// Returns the current buffer capacity in terms of samples +uint FIFOSampleBuffer::getCapacity() const +{ + return sizeInBytes / (channels * sizeof(SAMPLETYPE)); +} + + +// Returns the number of samples currently in the buffer +uint FIFOSampleBuffer::numSamples() const +{ + return samplesInBuffer; +} + + +// Output samples from beginning of the sample buffer. Copies demanded number +// of samples to output and removes them from the sample buffer. If there +// are less than 'numsample' samples in the buffer, returns all available. +// +// Returns number of samples copied. +uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples) +{ + uint num; + + num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples; + + memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num); + return receiveSamples(num); +} + + +// Removes samples from the beginning of the sample buffer without copying them +// anywhere. Used to reduce the number of samples in the buffer, when accessing +// the sample buffer with the 'ptrBegin' function. +uint FIFOSampleBuffer::receiveSamples(uint maxSamples) +{ + if (maxSamples >= samplesInBuffer) + { + uint temp; + + temp = samplesInBuffer; + samplesInBuffer = 0; + return temp; + } + + samplesInBuffer -= maxSamples; + bufferPos += maxSamples; + + return maxSamples; +} + + +// Returns nonzero if the sample buffer is empty +int FIFOSampleBuffer::isEmpty() const +{ + return (samplesInBuffer == 0) ? 1 : 0; +} + + +// Clears the sample buffer +void FIFOSampleBuffer::clear() +{ + samplesInBuffer = 0; + bufferPos = 0; +} diff --git a/plugins/zerospu2/3rdparty/SoundTouch/FIFOSampleBuffer.h b/plugins/zerospu2/3rdparty/SoundTouch/FIFOSampleBuffer.h index 09f74c9a65..bcbfb59d4e 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/FIFOSampleBuffer.h +++ b/plugins/zerospu2/3rdparty/SoundTouch/FIFOSampleBuffer.h @@ -1,174 +1,174 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// A buffer class for temporarily storaging sound samples, operates as a -/// first-in-first-out pipe. -/// -/// Samples are added to the end of the sample buffer with the 'putSamples' -/// function, and are received from the beginning of the buffer by calling -/// the 'receiveSamples' function. The class automatically removes the -/// output samples from the buffer as well as grows the storage size -/// whenever necessary. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.9 $ -// -// $Id: FIFOSampleBuffer.h,v 1.9 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef FIFOSampleBuffer_H -#define FIFOSampleBuffer_H - -#include "FIFOSamplePipe.h" - -namespace soundtouch -{ - -/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes -/// care of storage size adjustment and data moving during input/output operations. -/// -/// Notice that in case of stereo audio, one sample is considered to consist of -/// both channel data. -class FIFOSampleBuffer : public FIFOSamplePipe -{ -private: - /// Sample buffer. - SAMPLETYPE *buffer; - - // Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first - // 16-byte aligned location of this buffer - SAMPLETYPE *bufferUnaligned; - - /// Sample buffer size in bytes - uint sizeInBytes; - - /// How many samples are currently in buffer. - uint samplesInBuffer; - - /// Channels, 1=mono, 2=stereo. - uint channels; - - /// Current position pointer to the buffer. This pointer is increased when samples are - /// removed from the pipe so that it's necessary to actually rewind buffer (move data) - /// only new data when is put to the pipe. - uint bufferPos; - - /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real - /// beginning of the buffer. - void rewind(); - - /// Ensures that the buffer has capacity for at least this many samples. - void ensureCapacity(const uint capacityRequirement); - - /// Returns current capacity. - uint getCapacity() const; - -public: - - /// Constructor - FIFOSampleBuffer(uint numChannels = 2 ///< Number of channels, 1=mono, 2=stereo. - ///< Default is stereo. - ); - - /// destructor - ~FIFOSampleBuffer(); - - /// Returns a pointer to the beginning of the output samples. - /// This function is provided for accessing the output samples directly. - /// Please be careful for not to corrupt the book-keeping! - /// - /// When using this function to output samples, also remember to 'remove' the - /// output samples from the buffer by calling the - /// 'receiveSamples(numSamples)' function - virtual SAMPLETYPE *ptrBegin() const; - - /// Returns a pointer to the end of the used part of the sample buffer (i.e. - /// where the new samples are to be inserted). This function may be used for - /// inserting new samples into the sample buffer directly. Please be careful - /// not corrupt the book-keeping! - /// - /// When using this function as means for inserting new samples, also remember - /// to increase the sample count afterwards, by calling the - /// 'putSamples(numSamples)' function. - SAMPLETYPE *ptrEnd( - uint slackCapacity ///< How much free capacity (in samples) there _at least_ - ///< should be so that the caller can succesfully insert the - ///< desired samples to the buffer. If necessary, the function - ///< grows the buffer size to comply with this requirement. - ); - - /// Adds 'numSamples' pcs of samples from the 'samples' memory position to - /// the sample buffer. - virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. - uint numSamples ///< Number of samples to insert. - ); - - /// Adjusts the book-keeping to increase number of samples in the buffer without - /// copying any actual samples. - /// - /// This function is used to update the number of samples in the sample buffer - /// when accessing the buffer directly with 'ptrEnd' function. Please be - /// careful though! - virtual void putSamples(uint numSamples ///< Number of samples been inserted. - ); - - /// Output samples from beginning of the sample buffer. Copies requested samples to - /// output buffer and removes them from the sample buffer. If there are less than - /// 'numsample' samples in the buffer, returns all that available. - /// - /// \return Number of samples returned. - virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. - uint maxSamples ///< How many samples to receive at max. - ); - - /// Adjusts book-keeping so that given number of samples are removed from beginning of the - /// sample buffer without copying them anywhere. - /// - /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly - /// with 'ptrBegin' function. - virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. - ); - - /// Returns number of samples currently available. - virtual uint numSamples() const; - - /// Sets number of channels, 1 = mono, 2 = stereo. - void setChannels(uint numChannels); - - /// Returns nonzero if there aren't any samples available for outputting. - virtual int isEmpty() const; - - /// Clears all the samples. - virtual void clear(); -}; - -} - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// A buffer class for temporarily storaging sound samples, operates as a +/// first-in-first-out pipe. +/// +/// Samples are added to the end of the sample buffer with the 'putSamples' +/// function, and are received from the beginning of the buffer by calling +/// the 'receiveSamples' function. The class automatically removes the +/// output samples from the buffer as well as grows the storage size +/// whenever necessary. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.9 $ +// +// $Id: FIFOSampleBuffer.h,v 1.9 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIFOSampleBuffer_H +#define FIFOSampleBuffer_H + +#include "FIFOSamplePipe.h" + +namespace soundtouch +{ + +/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes +/// care of storage size adjustment and data moving during input/output operations. +/// +/// Notice that in case of stereo audio, one sample is considered to consist of +/// both channel data. +class FIFOSampleBuffer : public FIFOSamplePipe +{ +private: + /// Sample buffer. + SAMPLETYPE *buffer; + + // Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first + // 16-byte aligned location of this buffer + SAMPLETYPE *bufferUnaligned; + + /// Sample buffer size in bytes + uint sizeInBytes; + + /// How many samples are currently in buffer. + uint samplesInBuffer; + + /// Channels, 1=mono, 2=stereo. + uint channels; + + /// Current position pointer to the buffer. This pointer is increased when samples are + /// removed from the pipe so that it's necessary to actually rewind buffer (move data) + /// only new data when is put to the pipe. + uint bufferPos; + + /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real + /// beginning of the buffer. + void rewind(); + + /// Ensures that the buffer has capacity for at least this many samples. + void ensureCapacity(const uint capacityRequirement); + + /// Returns current capacity. + uint getCapacity() const; + +public: + + /// Constructor + FIFOSampleBuffer(uint numChannels = 2 ///< Number of channels, 1=mono, 2=stereo. + ///< Default is stereo. + ); + + /// destructor + ~FIFOSampleBuffer(); + + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const; + + /// Returns a pointer to the end of the used part of the sample buffer (i.e. + /// where the new samples are to be inserted). This function may be used for + /// inserting new samples into the sample buffer directly. Please be careful + /// not corrupt the book-keeping! + /// + /// When using this function as means for inserting new samples, also remember + /// to increase the sample count afterwards, by calling the + /// 'putSamples(numSamples)' function. + SAMPLETYPE *ptrEnd( + uint slackCapacity ///< How much free capacity (in samples) there _at least_ + ///< should be so that the caller can succesfully insert the + ///< desired samples to the buffer. If necessary, the function + ///< grows the buffer size to comply with this requirement. + ); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position to + /// the sample buffer. + virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. + uint numSamples ///< Number of samples to insert. + ); + + /// Adjusts the book-keeping to increase number of samples in the buffer without + /// copying any actual samples. + /// + /// This function is used to update the number of samples in the sample buffer + /// when accessing the buffer directly with 'ptrEnd' function. Please be + /// careful though! + virtual void putSamples(uint numSamples ///< Number of samples been inserted. + ); + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ); + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ); + + /// Returns number of samples currently available. + virtual uint numSamples() const; + + /// Sets number of channels, 1 = mono, 2 = stereo. + void setChannels(uint numChannels); + + /// Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const; + + /// Clears all the samples. + virtual void clear(); +}; + +} + +#endif diff --git a/plugins/zerospu2/3rdparty/SoundTouch/FIFOSamplePipe.h b/plugins/zerospu2/3rdparty/SoundTouch/FIFOSamplePipe.h index 33e33c7e36..e10b8b26c8 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/FIFOSamplePipe.h +++ b/plugins/zerospu2/3rdparty/SoundTouch/FIFOSamplePipe.h @@ -1,217 +1,217 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound -/// samples by operating like a first-in-first-out pipe: New samples are fed -/// into one end of the pipe with the 'putSamples' function, and the processed -/// samples are received from the other end with the 'receiveSamples' function. -/// -/// 'FIFOProcessor' : A base class for classes the do signal processing with -/// the samples while operating like a first-in-first-out pipe. When samples -/// are input with the 'putSamples' function, the class processes them -/// and moves the processed samples to the given 'output' pipe object, which -/// may be either another processing stage, or a fifo sample buffer object. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.8 $ -// -// $Id: FIFOSamplePipe.h,v 1.8 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef FIFOSamplePipe_H -#define FIFOSamplePipe_H - -#include -#include -#include "STTypes.h" - -namespace soundtouch -{ - -/// Abstract base class for FIFO (first-in-first-out) sample processing classes. -class FIFOSamplePipe -{ -public: - /// Returns a pointer to the beginning of the output samples. - /// This function is provided for accessing the output samples directly. - /// Please be careful for not to corrupt the book-keeping! - /// - /// When using this function to output samples, also remember to 'remove' the - /// output samples from the buffer by calling the - /// 'receiveSamples(numSamples)' function - virtual SAMPLETYPE *ptrBegin() const = 0; - - /// Adds 'numSamples' pcs of samples from the 'samples' memory position to - /// the sample buffer. - virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. - uint numSamples ///< Number of samples to insert. - ) = 0; - - - // Moves samples from the 'other' pipe instance to this instance. - void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data. - ) - { - int oNumSamples = other.numSamples(); - - putSamples(other.ptrBegin(), oNumSamples); - other.receiveSamples(oNumSamples); - }; - - /// Output samples from beginning of the sample buffer. Copies requested samples to - /// output buffer and removes them from the sample buffer. If there are less than - /// 'numsample' samples in the buffer, returns all that available. - /// - /// \return Number of samples returned. - virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. - uint maxSamples ///< How many samples to receive at max. - ) = 0; - - /// Adjusts book-keeping so that given number of samples are removed from beginning of the - /// sample buffer without copying them anywhere. - /// - /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly - /// with 'ptrBegin' function. - virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. - ) = 0; - - /// Returns number of samples currently available. - virtual uint numSamples() const = 0; - - // Returns nonzero if there aren't any samples available for outputting. - virtual int isEmpty() const = 0; - - /// Clears all the samples. - virtual void clear() = 0; -}; - - - -/// Base-class for sound processing routines working in FIFO principle. With this base -/// class it's easy to implement sound processing stages that can be chained together, -/// so that samples that are fed into beginning of the pipe automatically go through -/// all the processing stages. -/// -/// When samples are input to this class, they're first processed and then put to -/// the FIFO pipe that's defined as output of this class. This output pipe can be -/// either other processing stage or a FIFO sample buffer. -class FIFOProcessor :public FIFOSamplePipe -{ -protected: - /// Internal pipe where processed samples are put. - FIFOSamplePipe *output; - - /// Sets output pipe. - void setOutPipe(FIFOSamplePipe *pOutput) - { - assert(output == NULL); - assert(pOutput != NULL); - output = pOutput; - } - - - /// Constructor. Doesn't define output pipe; it has to be set be - /// 'setOutPipe' function. - FIFOProcessor() - { - output = NULL; - } - - - /// Constructor. Configures output pipe. - FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe. - ) - { - output = pOutput; - } - - - /// Destructor. - virtual ~FIFOProcessor() - { - } - - - /// Returns a pointer to the beginning of the output samples. - /// This function is provided for accessing the output samples directly. - /// Please be careful for not to corrupt the book-keeping! - /// - /// When using this function to output samples, also remember to 'remove' the - /// output samples from the buffer by calling the - /// 'receiveSamples(numSamples)' function - virtual SAMPLETYPE *ptrBegin() const - { - return output->ptrBegin(); - } - -public: - - /// Output samples from beginning of the sample buffer. Copies requested samples to - /// output buffer and removes them from the sample buffer. If there are less than - /// 'numsample' samples in the buffer, returns all that available. - /// - /// \return Number of samples returned. - virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples. - uint maxSamples ///< How many samples to receive at max. - ) - { - return output->receiveSamples(outBuffer, maxSamples); - } - - - /// Adjusts book-keeping so that given number of samples are removed from beginning of the - /// sample buffer without copying them anywhere. - /// - /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly - /// with 'ptrBegin' function. - virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. - ) - { - return output->receiveSamples(maxSamples); - } - - - /// Returns number of samples currently available. - virtual uint numSamples() const - { - return output->numSamples(); - } - - - /// Returns nonzero if there aren't any samples available for outputting. - virtual int isEmpty() const - { - return output->isEmpty(); - } -}; - -} - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound +/// samples by operating like a first-in-first-out pipe: New samples are fed +/// into one end of the pipe with the 'putSamples' function, and the processed +/// samples are received from the other end with the 'receiveSamples' function. +/// +/// 'FIFOProcessor' : A base class for classes the do signal processing with +/// the samples while operating like a first-in-first-out pipe. When samples +/// are input with the 'putSamples' function, the class processes them +/// and moves the processed samples to the given 'output' pipe object, which +/// may be either another processing stage, or a fifo sample buffer object. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.8 $ +// +// $Id: FIFOSamplePipe.h,v 1.8 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIFOSamplePipe_H +#define FIFOSamplePipe_H + +#include +#include +#include "STTypes.h" + +namespace soundtouch +{ + +/// Abstract base class for FIFO (first-in-first-out) sample processing classes. +class FIFOSamplePipe +{ +public: + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const = 0; + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position to + /// the sample buffer. + virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. + uint numSamples ///< Number of samples to insert. + ) = 0; + + + // Moves samples from the 'other' pipe instance to this instance. + void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data. + ) + { + int oNumSamples = other.numSamples(); + + putSamples(other.ptrBegin(), oNumSamples); + other.receiveSamples(oNumSamples); + }; + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ) = 0; + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ) = 0; + + /// Returns number of samples currently available. + virtual uint numSamples() const = 0; + + // Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const = 0; + + /// Clears all the samples. + virtual void clear() = 0; +}; + + + +/// Base-class for sound processing routines working in FIFO principle. With this base +/// class it's easy to implement sound processing stages that can be chained together, +/// so that samples that are fed into beginning of the pipe automatically go through +/// all the processing stages. +/// +/// When samples are input to this class, they're first processed and then put to +/// the FIFO pipe that's defined as output of this class. This output pipe can be +/// either other processing stage or a FIFO sample buffer. +class FIFOProcessor :public FIFOSamplePipe +{ +protected: + /// Internal pipe where processed samples are put. + FIFOSamplePipe *output; + + /// Sets output pipe. + void setOutPipe(FIFOSamplePipe *pOutput) + { + assert(output == NULL); + assert(pOutput != NULL); + output = pOutput; + } + + + /// Constructor. Doesn't define output pipe; it has to be set be + /// 'setOutPipe' function. + FIFOProcessor() + { + output = NULL; + } + + + /// Constructor. Configures output pipe. + FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe. + ) + { + output = pOutput; + } + + + /// Destructor. + virtual ~FIFOProcessor() + { + } + + + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const + { + return output->ptrBegin(); + } + +public: + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ) + { + return output->receiveSamples(outBuffer, maxSamples); + } + + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ) + { + return output->receiveSamples(maxSamples); + } + + + /// Returns number of samples currently available. + virtual uint numSamples() const + { + return output->numSamples(); + } + + + /// Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const + { + return output->isEmpty(); + } +}; + +} + +#endif diff --git a/plugins/zerospu2/3rdparty/SoundTouch/FIRFilter.cpp b/plugins/zerospu2/3rdparty/SoundTouch/FIRFilter.cpp index ac57335a18..10a0bb0299 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/FIRFilter.cpp +++ b/plugins/zerospu2/3rdparty/SoundTouch/FIRFilter.cpp @@ -1,272 +1,272 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// General FIR digital filter routines with MMX optimization. -/// -/// Note : MMX optimized functions reside in a separate, platform-specific file, -/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.16 $ -// -// $Id: FIRFilter.cpp,v 1.16 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include "FIRFilter.h" -#include "cpu_detect.h" - -using namespace soundtouch; - -/***************************************************************************** - * - * Implementation of the class 'FIRFilter' - * - *****************************************************************************/ - -FIRFilter::FIRFilter() -{ - resultDivFactor = 0; - length = 0; - lengthDiv8 = 0; - filterCoeffs = NULL; -} - - -FIRFilter::~FIRFilter() -{ - delete[] filterCoeffs; -} - -// Usual C-version of the filter routine for stereo sound -uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const -{ - uint i, j, end; - LONG_SAMPLETYPE suml, sumr; -#ifdef FLOAT_SAMPLES - // when using floating point samples, use a scaler instead of a divider - // because division is much slower operation than multiplying. - double dScaler = 1.0 / (double)resultDivider; -#endif - - assert(length != 0); - - end = 2 * (numSamples - length); - - for (j = 0; j < end; j += 2) - { - const SAMPLETYPE *ptr; - - suml = sumr = 0; - ptr = src + j; - - for (i = 0; i < length; i += 4) - { - // loop is unrolled by factor of 4 here for efficiency - suml += ptr[2 * i + 0] * filterCoeffs[i + 0] + - ptr[2 * i + 2] * filterCoeffs[i + 1] + - ptr[2 * i + 4] * filterCoeffs[i + 2] + - ptr[2 * i + 6] * filterCoeffs[i + 3]; - sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] + - ptr[2 * i + 3] * filterCoeffs[i + 1] + - ptr[2 * i + 5] * filterCoeffs[i + 2] + - ptr[2 * i + 7] * filterCoeffs[i + 3]; - } - -#ifdef INTEGER_SAMPLES - suml >>= resultDivFactor; - sumr >>= resultDivFactor; - // saturate to 16 bit integer limits - suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml; - // saturate to 16 bit integer limits - sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr; -#else - suml *= dScaler; - sumr *= dScaler; -#endif // INTEGER_SAMPLES - dest[j] = (SAMPLETYPE)suml; - dest[j + 1] = (SAMPLETYPE)sumr; - } - return numSamples - length; -} - - - - -// Usual C-version of the filter routine for mono sound -uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const -{ - uint i, j, end; - LONG_SAMPLETYPE sum; -#ifdef FLOAT_SAMPLES - // when using floating point samples, use a scaler instead of a divider - // because division is much slower operation than multiplying. - double dScaler = 1.0 / (double)resultDivider; -#endif - - - assert(length != 0); - - end = numSamples - length; - for (j = 0; j < end; j ++) - { - sum = 0; - for (i = 0; i < length; i += 4) - { - // loop is unrolled by factor of 4 here for efficiency - sum += src[i + 0] * filterCoeffs[i + 0] + - src[i + 1] * filterCoeffs[i + 1] + - src[i + 2] * filterCoeffs[i + 2] + - src[i + 3] * filterCoeffs[i + 3]; - } -#ifdef INTEGER_SAMPLES - sum >>= resultDivFactor; - // saturate to 16 bit integer limits - sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum; -#else - sum *= dScaler; -#endif // INTEGER_SAMPLES - dest[j] = (SAMPLETYPE)sum; - src ++; - } - return end; -} - - -// Set filter coeffiecients and length. -// -// Throws an exception if filter length isn't divisible by 8 -void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor) -{ - assert(newLength > 0); - if (newLength % 8) throw std::runtime_error("FIR filter length not divisible by 8"); - - lengthDiv8 = newLength / 8; - length = lengthDiv8 * 8; - assert(length == newLength); - - resultDivFactor = uResultDivFactor; -#ifdef INTEGER_SAMPLES - resultDivider = (SAMPLETYPE)(1< 0); - assert(lengthDiv8 * 8 == length); - if (numSamples < length) return 0; - assert(resultDivFactor >= 0); - if (numChannels == 2) - { - return evaluateFilterStereo(dest, src, numSamples); - } else { - return evaluateFilterMono(dest, src, numSamples); - } -} - - - -// Operator 'new' is overloaded so that it automatically creates a suitable instance -// depending on if we've a MMX-capable CPU available or not. -void * FIRFilter::operator new(size_t s) -{ - // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! - throw std::runtime_error("Don't use 'new FIRFilter', use 'newInstance' member instead!"); - return NULL; -} - - -FIRFilter * FIRFilter::newInstance() -{ - uint uExtensions = 0; - -#if !defined(_MSC_VER) || !defined(__x86_64__) - uExtensions = detectCPUextensions(); -#endif - - // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU - -#ifdef ALLOW_MMX - // MMX routines available only with integer sample types - if (uExtensions & SUPPORT_MMX) - { - return ::new FIRFilterMMX; - } - else -#endif // ALLOW_MMX - -#ifdef ALLOW_SSE - if (uExtensions & SUPPORT_SSE) - { - // SSE support - return ::new FIRFilterSSE; - } - else -#endif // ALLOW_SSE - -#ifdef ALLOW_3DNOW - if (uExtensions & SUPPORT_3DNOW) - { - // 3DNow! support - return ::new FIRFilter3DNow; - } - else -#endif // ALLOW_3DNOW - - { - // ISA optimizations not supported, use plain C version - return ::new FIRFilter; - } -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// General FIR digital filter routines with MMX optimization. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.16 $ +// +// $Id: FIRFilter.cpp,v 1.16 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include "FIRFilter.h" +#include "cpu_detect.h" + +using namespace soundtouch; + +/***************************************************************************** + * + * Implementation of the class 'FIRFilter' + * + *****************************************************************************/ + +FIRFilter::FIRFilter() +{ + resultDivFactor = 0; + length = 0; + lengthDiv8 = 0; + filterCoeffs = NULL; +} + + +FIRFilter::~FIRFilter() +{ + delete[] filterCoeffs; +} + +// Usual C-version of the filter routine for stereo sound +uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const +{ + uint i, j, end; + LONG_SAMPLETYPE suml, sumr; +#ifdef FLOAT_SAMPLES + // when using floating point samples, use a scaler instead of a divider + // because division is much slower operation than multiplying. + double dScaler = 1.0 / (double)resultDivider; +#endif + + assert(length != 0); + + end = 2 * (numSamples - length); + + for (j = 0; j < end; j += 2) + { + const SAMPLETYPE *ptr; + + suml = sumr = 0; + ptr = src + j; + + for (i = 0; i < length; i += 4) + { + // loop is unrolled by factor of 4 here for efficiency + suml += ptr[2 * i + 0] * filterCoeffs[i + 0] + + ptr[2 * i + 2] * filterCoeffs[i + 1] + + ptr[2 * i + 4] * filterCoeffs[i + 2] + + ptr[2 * i + 6] * filterCoeffs[i + 3]; + sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] + + ptr[2 * i + 3] * filterCoeffs[i + 1] + + ptr[2 * i + 5] * filterCoeffs[i + 2] + + ptr[2 * i + 7] * filterCoeffs[i + 3]; + } + +#ifdef INTEGER_SAMPLES + suml >>= resultDivFactor; + sumr >>= resultDivFactor; + // saturate to 16 bit integer limits + suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml; + // saturate to 16 bit integer limits + sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr; +#else + suml *= dScaler; + sumr *= dScaler; +#endif // INTEGER_SAMPLES + dest[j] = (SAMPLETYPE)suml; + dest[j + 1] = (SAMPLETYPE)sumr; + } + return numSamples - length; +} + + + + +// Usual C-version of the filter routine for mono sound +uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const +{ + uint i, j, end; + LONG_SAMPLETYPE sum; +#ifdef FLOAT_SAMPLES + // when using floating point samples, use a scaler instead of a divider + // because division is much slower operation than multiplying. + double dScaler = 1.0 / (double)resultDivider; +#endif + + + assert(length != 0); + + end = numSamples - length; + for (j = 0; j < end; j ++) + { + sum = 0; + for (i = 0; i < length; i += 4) + { + // loop is unrolled by factor of 4 here for efficiency + sum += src[i + 0] * filterCoeffs[i + 0] + + src[i + 1] * filterCoeffs[i + 1] + + src[i + 2] * filterCoeffs[i + 2] + + src[i + 3] * filterCoeffs[i + 3]; + } +#ifdef INTEGER_SAMPLES + sum >>= resultDivFactor; + // saturate to 16 bit integer limits + sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum; +#else + sum *= dScaler; +#endif // INTEGER_SAMPLES + dest[j] = (SAMPLETYPE)sum; + src ++; + } + return end; +} + + +// Set filter coeffiecients and length. +// +// Throws an exception if filter length isn't divisible by 8 +void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor) +{ + assert(newLength > 0); + if (newLength % 8) throw std::runtime_error("FIR filter length not divisible by 8"); + + lengthDiv8 = newLength / 8; + length = lengthDiv8 * 8; + assert(length == newLength); + + resultDivFactor = uResultDivFactor; +#ifdef INTEGER_SAMPLES + resultDivider = (SAMPLETYPE)(1< 0); + assert(lengthDiv8 * 8 == length); + if (numSamples < length) return 0; + assert(resultDivFactor >= 0); + if (numChannels == 2) + { + return evaluateFilterStereo(dest, src, numSamples); + } else { + return evaluateFilterMono(dest, src, numSamples); + } +} + + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX-capable CPU available or not. +void * FIRFilter::operator new(size_t s) +{ + // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! + throw std::runtime_error("Don't use 'new FIRFilter', use 'newInstance' member instead!"); + return NULL; +} + + +FIRFilter * FIRFilter::newInstance() +{ + uint uExtensions = 0; + +#if !defined(_MSC_VER) || !defined(__x86_64__) + uExtensions = detectCPUextensions(); +#endif + + // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU + +#ifdef ALLOW_MMX + // MMX routines available only with integer sample types + if (uExtensions & SUPPORT_MMX) + { + return ::new FIRFilterMMX; + } + else +#endif // ALLOW_MMX + +#ifdef ALLOW_SSE + if (uExtensions & SUPPORT_SSE) + { + // SSE support + return ::new FIRFilterSSE; + } + else +#endif // ALLOW_SSE + +#ifdef ALLOW_3DNOW + if (uExtensions & SUPPORT_3DNOW) + { + // 3DNow! support + return ::new FIRFilter3DNow; + } + else +#endif // ALLOW_3DNOW + + { + // ISA optimizations not supported, use plain C version + return ::new FIRFilter; + } +} diff --git a/plugins/zerospu2/3rdparty/SoundTouch/FIRFilter.h b/plugins/zerospu2/3rdparty/SoundTouch/FIRFilter.h index be5cdd2943..5e9b3410f8 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/FIRFilter.h +++ b/plugins/zerospu2/3rdparty/SoundTouch/FIRFilter.h @@ -1,163 +1,163 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// General FIR digital filter routines with MMX optimization. -/// -/// Note : MMX optimized functions reside in a separate, platform-specific file, -/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.17 $ -// -// $Id: FIRFilter.h,v 1.17 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef FIRFilter_H -#define FIRFilter_H - -#include "STTypes.h" - -namespace soundtouch -{ - -class FIRFilter -{ -protected: - // Number of FIR filter taps - uint length; - // Number of FIR filter taps divided by 8 - uint lengthDiv8; - - // Result divider factor in 2^k format - uint resultDivFactor; - - // Result divider value. - SAMPLETYPE resultDivider; - - // Memory for filter coefficients - SAMPLETYPE *filterCoeffs; - - virtual uint evaluateFilterStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples) const; - virtual uint evaluateFilterMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples) const; - -public: - FIRFilter(); - virtual ~FIRFilter(); - - /// Operator 'new' is overloaded so that it automatically creates a suitable instance - /// depending on if we've a MMX-capable CPU available or not. - void * operator new(size_t s); - - static FIRFilter *newInstance(); - - /// Applies the filter to the given sequence of samples. - /// Note : The amount of outputted samples is by value of 'filter_length' - /// smaller than the amount of input samples. - /// - /// \return Number of samples copied to 'dest'. - uint evaluate(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples, - uint numChannels) const; - - uint getLength() const; - - virtual void setCoefficients(const SAMPLETYPE *coeffs, - uint newLength, - uint uResultDivFactor); -}; - - -// Optional subclasses that implement CPU-specific optimizations: - -#ifdef ALLOW_MMX - - /// Class that implements MMX optimized functions exclusive for 16bit integer samples type. - class FIRFilterMMX : public FIRFilter - { - protected: - short *filterCoeffsUnalign; - short *filterCoeffsAlign; - - virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const; - public: - FIRFilterMMX(); - ~FIRFilterMMX(); - - virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor); - }; - -#endif // ALLOW_MMX - - -#ifdef ALLOW_3DNOW - - /// Class that implements 3DNow! optimized functions exclusive for floating point samples type. - class FIRFilter3DNow : public FIRFilter - { - protected: - float *filterCoeffsUnalign; - float *filterCoeffsAlign; - - virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; - public: - FIRFilter3DNow(); - ~FIRFilter3DNow(); - virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); - }; - -#endif // ALLOW_3DNOW - - -#ifdef ALLOW_SSE - /// Class that implements SSE optimized functions exclusive for floating point samples type. - class FIRFilterSSE : public FIRFilter - { - protected: - float *filterCoeffsUnalign; - float *filterCoeffsAlign; - - virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; - public: - FIRFilterSSE(); - ~FIRFilterSSE(); - - virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); - }; - -#endif // ALLOW_SSE - -} - -#endif // FIRFilter_H +//////////////////////////////////////////////////////////////////////////////// +/// +/// General FIR digital filter routines with MMX optimization. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.17 $ +// +// $Id: FIRFilter.h,v 1.17 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIRFilter_H +#define FIRFilter_H + +#include "STTypes.h" + +namespace soundtouch +{ + +class FIRFilter +{ +protected: + // Number of FIR filter taps + uint length; + // Number of FIR filter taps divided by 8 + uint lengthDiv8; + + // Result divider factor in 2^k format + uint resultDivFactor; + + // Result divider value. + SAMPLETYPE resultDivider; + + // Memory for filter coefficients + SAMPLETYPE *filterCoeffs; + + virtual uint evaluateFilterStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) const; + virtual uint evaluateFilterMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) const; + +public: + FIRFilter(); + virtual ~FIRFilter(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we've a MMX-capable CPU available or not. + void * operator new(size_t s); + + static FIRFilter *newInstance(); + + /// Applies the filter to the given sequence of samples. + /// Note : The amount of outputted samples is by value of 'filter_length' + /// smaller than the amount of input samples. + /// + /// \return Number of samples copied to 'dest'. + uint evaluate(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples, + uint numChannels) const; + + uint getLength() const; + + virtual void setCoefficients(const SAMPLETYPE *coeffs, + uint newLength, + uint uResultDivFactor); +}; + + +// Optional subclasses that implement CPU-specific optimizations: + +#ifdef ALLOW_MMX + + /// Class that implements MMX optimized functions exclusive for 16bit integer samples type. + class FIRFilterMMX : public FIRFilter + { + protected: + short *filterCoeffsUnalign; + short *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const; + public: + FIRFilterMMX(); + ~FIRFilterMMX(); + + virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // ALLOW_MMX + + +#ifdef ALLOW_3DNOW + + /// Class that implements 3DNow! optimized functions exclusive for floating point samples type. + class FIRFilter3DNow : public FIRFilter + { + protected: + float *filterCoeffsUnalign; + float *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; + public: + FIRFilter3DNow(); + ~FIRFilter3DNow(); + virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // ALLOW_3DNOW + + +#ifdef ALLOW_SSE + /// Class that implements SSE optimized functions exclusive for floating point samples type. + class FIRFilterSSE : public FIRFilter + { + protected: + float *filterCoeffsUnalign; + float *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; + public: + FIRFilterSSE(); + ~FIRFilterSSE(); + + virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // ALLOW_SSE + +} + +#endif // FIRFilter_H diff --git a/plugins/zerospu2/3rdparty/SoundTouch/RateTransposer.cpp b/plugins/zerospu2/3rdparty/SoundTouch/RateTransposer.cpp index b7414b90a6..9e5c962d13 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/RateTransposer.cpp +++ b/plugins/zerospu2/3rdparty/SoundTouch/RateTransposer.cpp @@ -1,626 +1,626 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sample rate transposer. Changes sample rate by using linear interpolation -/// together with anti-alias filtering (first order interpolation with anti- -/// alias filtering should be quite adequate for this application) -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/03/19 10:05:49 $ -// File revision : $Revision: 1.13 $ -// -// $Id: RateTransposer.cpp,v 1.13 2006/03/19 10:05:49 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include "RateTransposer.h" -#include "AAFilter.h" - -using namespace soundtouch; - - -/// A linear samplerate transposer class that uses integer arithmetics. -/// for the transposing. -class RateTransposerInteger : public RateTransposer -{ -protected: - int iSlopeCount; - uint uRate; - SAMPLETYPE sPrevSampleL, sPrevSampleR; - - virtual void resetRegisters(); - - virtual uint transposeStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - virtual uint transposeMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - -public: - RateTransposerInteger(); - virtual ~RateTransposerInteger(); - - /// Sets new target rate. Normal rate = 1.0, smaller values represent slower - /// rate, larger faster rates. - virtual void setRate(float newRate); - -}; - - -/// A linear samplerate transposer class that uses floating point arithmetics -/// for the transposing. -class RateTransposerFloat : public RateTransposer -{ -protected: - float fSlopeCount; - float fRateStep; - SAMPLETYPE sPrevSampleL, sPrevSampleR; - - virtual void resetRegisters(); - - virtual uint transposeStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - virtual uint transposeMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - -public: - RateTransposerFloat(); - virtual ~RateTransposerFloat(); -}; - - - -#ifndef min -#define min(a,b) ((a > b) ? b : a) -#define max(a,b) ((a < b) ? b : a) -#endif - - -// Operator 'new' is overloaded so that it automatically creates a suitable instance -// depending on if we've a MMX/SSE/etc-capable CPU available or not. -void * RateTransposer::operator new(size_t s) -{ - // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! - assert(FALSE); - return NULL; -} - - -RateTransposer *RateTransposer::newInstance() -{ -#ifdef INTEGER_SAMPLES - return ::new RateTransposerInteger; -#else - return ::new RateTransposerFloat; -#endif -} - - -// Constructor -RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer) -{ - uChannels = 2; - bUseAAFilter = TRUE; - - // Instantiates the anti-alias filter with default tap length - // of 32 - pAAFilter = new AAFilter(32); -} - - - -RateTransposer::~RateTransposer() -{ - delete pAAFilter; -} - - - -/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable -void RateTransposer::enableAAFilter(const BOOL newMode) -{ - bUseAAFilter = newMode; -} - - -/// Returns nonzero if anti-alias filter is enabled. -BOOL RateTransposer::isAAFilterEnabled() const -{ - return bUseAAFilter; -} - - -AAFilter *RateTransposer::getAAFilter() const -{ - return pAAFilter; -} - - - -// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower -// uRate, larger faster uRates. -void RateTransposer::setRate(float newRate) -{ - float fCutoff; - - fRate = newRate; - - // design a new anti-alias filter - if (newRate > 1.0f) - { - fCutoff = 0.5f / newRate; - } - else - { - fCutoff = 0.5f * newRate; - } - pAAFilter->setCutoffFreq(fCutoff); -} - - -// Outputs as many samples of the 'outputBuffer' as possible, and if there's -// any room left, outputs also as many of the incoming samples as possible. -// The goal is to drive the outputBuffer empty. -// -// It's allowed for 'output' and 'input' parameters to point to the same -// memory position. -void RateTransposer::flushStoreBuffer() -{ - if (storeBuffer.isEmpty()) return; - - outputBuffer.moveSamples(storeBuffer); -} - - -// Adds 'numSamples' pcs of samples from the 'samples' memory position into -// the input of the object. -void RateTransposer::putSamples(const SAMPLETYPE *samples, uint numSamples) -{ - processSamples(samples, numSamples); -} - - - -// Transposes up the sample rate, causing the observed playback 'rate' of the -// sound to decrease -void RateTransposer::upsample(const SAMPLETYPE *src, uint numSamples) -{ - int count, sizeTemp, num; - - // If the parameter 'uRate' value is smaller than 'SCALE', first transpose - // the samples and then apply the anti-alias filter to remove aliasing. - - // First check that there's enough room in 'storeBuffer' - // (+16 is to reserve some slack in the destination buffer) - sizeTemp = (int)((float)numSamples / fRate + 16.0f); - - // Transpose the samples, store the result into the end of "storeBuffer" - count = transpose(storeBuffer.ptrEnd(sizeTemp), src, numSamples); - storeBuffer.putSamples(count); - - // Apply the anti-alias filter to samples in "store output", output the - // result to "dest" - num = storeBuffer.numSamples(); - count = pAAFilter->evaluate(outputBuffer.ptrEnd(num), - storeBuffer.ptrBegin(), num, uChannels); - outputBuffer.putSamples(count); - - // Remove the processed samples from "storeBuffer" - storeBuffer.receiveSamples(count); -} - - -// Transposes down the sample rate, causing the observed playback 'rate' of the -// sound to increase -void RateTransposer::downsample(const SAMPLETYPE *src, uint numSamples) -{ - int count, sizeTemp; - - // If the parameter 'uRate' value is larger than 'SCALE', first apply the - // anti-alias filter to remove high frequencies (prevent them from folding - // over the lover frequencies), then transpose. */ - - // Add the new samples to the end of the storeBuffer */ - storeBuffer.putSamples(src, numSamples); - - // Anti-alias filter the samples to prevent folding and output the filtered - // data to tempBuffer. Note : because of the FIR filter length, the - // filtering routine takes in 'filter_length' more samples than it outputs. - assert(tempBuffer.isEmpty()); - sizeTemp = storeBuffer.numSamples(); - - count = pAAFilter->evaluate(tempBuffer.ptrEnd(sizeTemp), - storeBuffer.ptrBegin(), sizeTemp, uChannels); - - // Remove the filtered samples from 'storeBuffer' - storeBuffer.receiveSamples(count); - - // Transpose the samples (+16 is to reserve some slack in the destination buffer) - sizeTemp = (int)((float)numSamples / fRate + 16.0f); - count = transpose(outputBuffer.ptrEnd(sizeTemp), tempBuffer.ptrBegin(), count); - outputBuffer.putSamples(count); -} - - -// Transposes sample rate by applying anti-alias filter to prevent folding. -// Returns amount of samples returned in the "dest" buffer. -// The maximum amount of samples that can be returned at a time is set by -// the 'set_returnBuffer_size' function. -void RateTransposer::processSamples(const SAMPLETYPE *src, uint numSamples) -{ - uint count; - uint sizeReq; - - if (numSamples == 0) return; - assert(pAAFilter); - - // If anti-alias filter is turned off, simply transpose without applying - // the filter - if (bUseAAFilter == FALSE) - { - sizeReq = (int)((float)numSamples / fRate + 1.0f); - count = transpose(outputBuffer.ptrEnd(sizeReq), src, numSamples); - outputBuffer.putSamples(count); - return; - } - - // Transpose with anti-alias filter - if (fRate < 1.0f) - { - upsample(src, numSamples); - } - else - { - downsample(src, numSamples); - } -} - - -// Transposes the sample rate of the given samples using linear interpolation. -// Returns the number of samples returned in the "dest" buffer -inline uint RateTransposer::transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) -{ - if (uChannels == 2) - { - return transposeStereo(dest, src, numSamples); - } - else - { - return transposeMono(dest, src, numSamples); - } -} - - -// Sets the number of channels, 1 = mono, 2 = stereo -void RateTransposer::setChannels(const uint numchannels) -{ - if (uChannels == numchannels) return; - - assert(numchannels == 1 || numchannels == 2); - uChannels = numchannels; - - storeBuffer.setChannels(uChannels); - tempBuffer.setChannels(uChannels); - outputBuffer.setChannels(uChannels); - - // Inits the linear interpolation registers - resetRegisters(); -} - - -// Clears all the samples in the object -void RateTransposer::clear() -{ - outputBuffer.clear(); - storeBuffer.clear(); -} - - -// Returns nonzero if there aren't any samples available for outputting. -uint RateTransposer::isEmpty() -{ - int res; - - res = FIFOProcessor::isEmpty(); - if (res == 0) return 0; - return storeBuffer.isEmpty(); -} - - -////////////////////////////////////////////////////////////////////////////// -// -// RateTransposerInteger - integer arithmetic implementation -// - -/// fixed-point interpolation routine precision -#define SCALE 65536 - -// Constructor -RateTransposerInteger::RateTransposerInteger() : RateTransposer() -{ - // call these here as these are virtual functions; calling these - // from the base class constructor wouldn't execute the overloaded - // versions (peculiar C++ can be). - resetRegisters(); - setRate(1.0f); -} - - -RateTransposerInteger::~RateTransposerInteger() -{ -} - - -void RateTransposerInteger::resetRegisters() -{ - iSlopeCount = 0; - sPrevSampleL = - sPrevSampleR = 0; -} - - - -// Transposes the sample rate of the given samples using linear interpolation. -// 'Mono' version of the routine. Returns the number of samples returned in -// the "dest" buffer -uint RateTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) -{ - unsigned int i, used; - LONG_SAMPLETYPE temp, vol1; - - used = 0; - i = 0; - - // Process the last sample saved from the previous call first... - while (iSlopeCount <= SCALE) - { - vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); - temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; - dest[i] = (SAMPLETYPE)(temp / SCALE); - i++; - iSlopeCount += uRate; - } - // now always (iSlopeCount > SCALE) - iSlopeCount -= SCALE; - - while (1) - { - while (iSlopeCount > SCALE) - { - iSlopeCount -= SCALE; - used ++; - if (used >= numSamples - 1) goto end; - } - vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); - temp = src[used] * vol1 + iSlopeCount * src[used + 1]; - dest[i] = (SAMPLETYPE)(temp / SCALE); - - i++; - iSlopeCount += uRate; - } -end: - // Store the last sample for the next round - sPrevSampleL = src[numSamples - 1]; - - return i; -} - - -// Transposes the sample rate of the given samples using linear interpolation. -// 'Stereo' version of the routine. Returns the number of samples returned in -// the "dest" buffer -uint RateTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) -{ - unsigned int srcPos, i, used; - LONG_SAMPLETYPE temp, vol1; - - if (numSamples == 0) return 0; // no samples, no work - - used = 0; - i = 0; - - // Process the last sample saved from the sPrevSampleLious call first... - while (iSlopeCount <= SCALE) - { - vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); - temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; - dest[2 * i] = (SAMPLETYPE)(temp / SCALE); - temp = vol1 * sPrevSampleR + iSlopeCount * src[1]; - dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); - i++; - iSlopeCount += uRate; - } - // now always (iSlopeCount > SCALE) - iSlopeCount -= SCALE; - - while (1) - { - while (iSlopeCount > SCALE) - { - iSlopeCount -= SCALE; - used ++; - if (used >= numSamples - 1) goto end; - } - srcPos = 2 * used; - vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); - temp = src[srcPos] * vol1 + iSlopeCount * src[srcPos + 2]; - dest[2 * i] = (SAMPLETYPE)(temp / SCALE); - temp = src[srcPos + 1] * vol1 + iSlopeCount * src[srcPos + 3]; - dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); - - i++; - iSlopeCount += uRate; - } -end: - // Store the last sample for the next round - sPrevSampleL = src[2 * numSamples - 2]; - sPrevSampleR = src[2 * numSamples - 1]; - - return i; -} - - -// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower -// uRate, larger faster uRates. -void RateTransposerInteger::setRate(float newRate) -{ - uRate = (int)(newRate * SCALE + 0.5f); - RateTransposer::setRate(newRate); -} - - -////////////////////////////////////////////////////////////////////////////// -// -// RateTransposerFloat - floating point arithmetic implementation -// -////////////////////////////////////////////////////////////////////////////// - -// Constructor -RateTransposerFloat::RateTransposerFloat() : RateTransposer() -{ - // call these here as these are virtual functions; calling these - // from the base class constructor wouldn't execute the overloaded - // versions (peculiar C++ can be). - resetRegisters(); - setRate(1.0f); -} - - -RateTransposerFloat::~RateTransposerFloat() -{ -} - - -void RateTransposerFloat::resetRegisters() -{ - fSlopeCount = 0; - sPrevSampleL = - sPrevSampleR = 0; -} - - - -// Transposes the sample rate of the given samples using linear interpolation. -// 'Mono' version of the routine. Returns the number of samples returned in -// the "dest" buffer -uint RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) -{ - unsigned int i, used; - - used = 0; - i = 0; - - // Process the last sample saved from the previous call first... - while (fSlopeCount <= 1.0f) - { - dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); - i++; - fSlopeCount += fRate; - } - fSlopeCount -= 1.0f; - - if (numSamples == 1) goto end; - - while (1) - { - while (fSlopeCount > 1.0f) - { - fSlopeCount -= 1.0f; - used ++; - if (used >= numSamples - 1) goto end; - } - dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[used] + fSlopeCount * src[used + 1]); - i++; - fSlopeCount += fRate; - } -end: - // Store the last sample for the next round - sPrevSampleL = src[numSamples - 1]; - - return i; -} - - -// Transposes the sample rate of the given samples using linear interpolation. -// 'Mono' version of the routine. Returns the number of samples returned in -// the "dest" buffer -uint RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) -{ - unsigned int srcPos, i, used; - - if (numSamples == 0) return 0; // no samples, no work - - used = 0; - i = 0; - - // Process the last sample saved from the sPrevSampleLious call first... - while (fSlopeCount <= 1.0f) - { - dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); - dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleR + fSlopeCount * src[1]); - i++; - fSlopeCount += fRate; - } - // now always (iSlopeCount > 1.0f) - fSlopeCount -= 1.0f; - - if (numSamples == 1) goto end; - - while (1) - { - while (fSlopeCount > 1.0f) - { - fSlopeCount -= 1.0f; - used ++; - if (used >= numSamples - 1) goto end; - } - srcPos = 2 * used; - - dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos] - + fSlopeCount * src[srcPos + 2]); - dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos + 1] - + fSlopeCount * src[srcPos + 3]); - - i++; - fSlopeCount += fRate; - } -end: - // Store the last sample for the next round - sPrevSampleL = src[2 * numSamples - 2]; - sPrevSampleR = src[2 * numSamples - 1]; - - return i; -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sample rate transposer. Changes sample rate by using linear interpolation +/// together with anti-alias filtering (first order interpolation with anti- +/// alias filtering should be quite adequate for this application) +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/03/19 10:05:49 $ +// File revision : $Revision: 1.13 $ +// +// $Id: RateTransposer.cpp,v 1.13 2006/03/19 10:05:49 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include "RateTransposer.h" +#include "AAFilter.h" + +using namespace soundtouch; + + +/// A linear samplerate transposer class that uses integer arithmetics. +/// for the transposing. +class RateTransposerInteger : public RateTransposer +{ +protected: + int iSlopeCount; + uint uRate; + SAMPLETYPE sPrevSampleL, sPrevSampleR; + + virtual void resetRegisters(); + + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + +public: + RateTransposerInteger(); + virtual ~RateTransposerInteger(); + + /// Sets new target rate. Normal rate = 1.0, smaller values represent slower + /// rate, larger faster rates. + virtual void setRate(float newRate); + +}; + + +/// A linear samplerate transposer class that uses floating point arithmetics +/// for the transposing. +class RateTransposerFloat : public RateTransposer +{ +protected: + float fSlopeCount; + float fRateStep; + SAMPLETYPE sPrevSampleL, sPrevSampleR; + + virtual void resetRegisters(); + + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + +public: + RateTransposerFloat(); + virtual ~RateTransposerFloat(); +}; + + + +#ifndef min +#define min(a,b) ((a > b) ? b : a) +#define max(a,b) ((a < b) ? b : a) +#endif + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX/SSE/etc-capable CPU available or not. +void * RateTransposer::operator new(size_t s) +{ + // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! + assert(FALSE); + return NULL; +} + + +RateTransposer *RateTransposer::newInstance() +{ +#ifdef INTEGER_SAMPLES + return ::new RateTransposerInteger; +#else + return ::new RateTransposerFloat; +#endif +} + + +// Constructor +RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer) +{ + uChannels = 2; + bUseAAFilter = TRUE; + + // Instantiates the anti-alias filter with default tap length + // of 32 + pAAFilter = new AAFilter(32); +} + + + +RateTransposer::~RateTransposer() +{ + delete pAAFilter; +} + + + +/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable +void RateTransposer::enableAAFilter(const BOOL newMode) +{ + bUseAAFilter = newMode; +} + + +/// Returns nonzero if anti-alias filter is enabled. +BOOL RateTransposer::isAAFilterEnabled() const +{ + return bUseAAFilter; +} + + +AAFilter *RateTransposer::getAAFilter() const +{ + return pAAFilter; +} + + + +// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower +// uRate, larger faster uRates. +void RateTransposer::setRate(float newRate) +{ + float fCutoff; + + fRate = newRate; + + // design a new anti-alias filter + if (newRate > 1.0f) + { + fCutoff = 0.5f / newRate; + } + else + { + fCutoff = 0.5f * newRate; + } + pAAFilter->setCutoffFreq(fCutoff); +} + + +// Outputs as many samples of the 'outputBuffer' as possible, and if there's +// any room left, outputs also as many of the incoming samples as possible. +// The goal is to drive the outputBuffer empty. +// +// It's allowed for 'output' and 'input' parameters to point to the same +// memory position. +void RateTransposer::flushStoreBuffer() +{ + if (storeBuffer.isEmpty()) return; + + outputBuffer.moveSamples(storeBuffer); +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void RateTransposer::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + processSamples(samples, numSamples); +} + + + +// Transposes up the sample rate, causing the observed playback 'rate' of the +// sound to decrease +void RateTransposer::upsample(const SAMPLETYPE *src, uint numSamples) +{ + int count, sizeTemp, num; + + // If the parameter 'uRate' value is smaller than 'SCALE', first transpose + // the samples and then apply the anti-alias filter to remove aliasing. + + // First check that there's enough room in 'storeBuffer' + // (+16 is to reserve some slack in the destination buffer) + sizeTemp = (int)((float)numSamples / fRate + 16.0f); + + // Transpose the samples, store the result into the end of "storeBuffer" + count = transpose(storeBuffer.ptrEnd(sizeTemp), src, numSamples); + storeBuffer.putSamples(count); + + // Apply the anti-alias filter to samples in "store output", output the + // result to "dest" + num = storeBuffer.numSamples(); + count = pAAFilter->evaluate(outputBuffer.ptrEnd(num), + storeBuffer.ptrBegin(), num, uChannels); + outputBuffer.putSamples(count); + + // Remove the processed samples from "storeBuffer" + storeBuffer.receiveSamples(count); +} + + +// Transposes down the sample rate, causing the observed playback 'rate' of the +// sound to increase +void RateTransposer::downsample(const SAMPLETYPE *src, uint numSamples) +{ + int count, sizeTemp; + + // If the parameter 'uRate' value is larger than 'SCALE', first apply the + // anti-alias filter to remove high frequencies (prevent them from folding + // over the lover frequencies), then transpose. */ + + // Add the new samples to the end of the storeBuffer */ + storeBuffer.putSamples(src, numSamples); + + // Anti-alias filter the samples to prevent folding and output the filtered + // data to tempBuffer. Note : because of the FIR filter length, the + // filtering routine takes in 'filter_length' more samples than it outputs. + assert(tempBuffer.isEmpty()); + sizeTemp = storeBuffer.numSamples(); + + count = pAAFilter->evaluate(tempBuffer.ptrEnd(sizeTemp), + storeBuffer.ptrBegin(), sizeTemp, uChannels); + + // Remove the filtered samples from 'storeBuffer' + storeBuffer.receiveSamples(count); + + // Transpose the samples (+16 is to reserve some slack in the destination buffer) + sizeTemp = (int)((float)numSamples / fRate + 16.0f); + count = transpose(outputBuffer.ptrEnd(sizeTemp), tempBuffer.ptrBegin(), count); + outputBuffer.putSamples(count); +} + + +// Transposes sample rate by applying anti-alias filter to prevent folding. +// Returns amount of samples returned in the "dest" buffer. +// The maximum amount of samples that can be returned at a time is set by +// the 'set_returnBuffer_size' function. +void RateTransposer::processSamples(const SAMPLETYPE *src, uint numSamples) +{ + uint count; + uint sizeReq; + + if (numSamples == 0) return; + assert(pAAFilter); + + // If anti-alias filter is turned off, simply transpose without applying + // the filter + if (bUseAAFilter == FALSE) + { + sizeReq = (int)((float)numSamples / fRate + 1.0f); + count = transpose(outputBuffer.ptrEnd(sizeReq), src, numSamples); + outputBuffer.putSamples(count); + return; + } + + // Transpose with anti-alias filter + if (fRate < 1.0f) + { + upsample(src, numSamples); + } + else + { + downsample(src, numSamples); + } +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// Returns the number of samples returned in the "dest" buffer +inline uint RateTransposer::transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + if (uChannels == 2) + { + return transposeStereo(dest, src, numSamples); + } + else + { + return transposeMono(dest, src, numSamples); + } +} + + +// Sets the number of channels, 1 = mono, 2 = stereo +void RateTransposer::setChannels(const uint numchannels) +{ + if (uChannels == numchannels) return; + + assert(numchannels == 1 || numchannels == 2); + uChannels = numchannels; + + storeBuffer.setChannels(uChannels); + tempBuffer.setChannels(uChannels); + outputBuffer.setChannels(uChannels); + + // Inits the linear interpolation registers + resetRegisters(); +} + + +// Clears all the samples in the object +void RateTransposer::clear() +{ + outputBuffer.clear(); + storeBuffer.clear(); +} + + +// Returns nonzero if there aren't any samples available for outputting. +uint RateTransposer::isEmpty() +{ + int res; + + res = FIFOProcessor::isEmpty(); + if (res == 0) return 0; + return storeBuffer.isEmpty(); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// RateTransposerInteger - integer arithmetic implementation +// + +/// fixed-point interpolation routine precision +#define SCALE 65536 + +// Constructor +RateTransposerInteger::RateTransposerInteger() : RateTransposer() +{ + // call these here as these are virtual functions; calling these + // from the base class constructor wouldn't execute the overloaded + // versions (peculiar C++ can be). + resetRegisters(); + setRate(1.0f); +} + + +RateTransposerInteger::~RateTransposerInteger() +{ +} + + +void RateTransposerInteger::resetRegisters() +{ + iSlopeCount = 0; + sPrevSampleL = + sPrevSampleR = 0; +} + + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int i, used; + LONG_SAMPLETYPE temp, vol1; + + used = 0; + i = 0; + + // Process the last sample saved from the previous call first... + while (iSlopeCount <= SCALE) + { + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; + dest[i] = (SAMPLETYPE)(temp / SCALE); + i++; + iSlopeCount += uRate; + } + // now always (iSlopeCount > SCALE) + iSlopeCount -= SCALE; + + while (1) + { + while (iSlopeCount > SCALE) + { + iSlopeCount -= SCALE; + used ++; + if (used >= numSamples - 1) goto end; + } + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = src[used] * vol1 + iSlopeCount * src[used + 1]; + dest[i] = (SAMPLETYPE)(temp / SCALE); + + i++; + iSlopeCount += uRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[numSamples - 1]; + + return i; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Stereo' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int srcPos, i, used; + LONG_SAMPLETYPE temp, vol1; + + if (numSamples == 0) return 0; // no samples, no work + + used = 0; + i = 0; + + // Process the last sample saved from the sPrevSampleLious call first... + while (iSlopeCount <= SCALE) + { + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; + dest[2 * i] = (SAMPLETYPE)(temp / SCALE); + temp = vol1 * sPrevSampleR + iSlopeCount * src[1]; + dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); + i++; + iSlopeCount += uRate; + } + // now always (iSlopeCount > SCALE) + iSlopeCount -= SCALE; + + while (1) + { + while (iSlopeCount > SCALE) + { + iSlopeCount -= SCALE; + used ++; + if (used >= numSamples - 1) goto end; + } + srcPos = 2 * used; + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = src[srcPos] * vol1 + iSlopeCount * src[srcPos + 2]; + dest[2 * i] = (SAMPLETYPE)(temp / SCALE); + temp = src[srcPos + 1] * vol1 + iSlopeCount * src[srcPos + 3]; + dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); + + i++; + iSlopeCount += uRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[2 * numSamples - 2]; + sPrevSampleR = src[2 * numSamples - 1]; + + return i; +} + + +// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower +// uRate, larger faster uRates. +void RateTransposerInteger::setRate(float newRate) +{ + uRate = (int)(newRate * SCALE + 0.5f); + RateTransposer::setRate(newRate); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// RateTransposerFloat - floating point arithmetic implementation +// +////////////////////////////////////////////////////////////////////////////// + +// Constructor +RateTransposerFloat::RateTransposerFloat() : RateTransposer() +{ + // call these here as these are virtual functions; calling these + // from the base class constructor wouldn't execute the overloaded + // versions (peculiar C++ can be). + resetRegisters(); + setRate(1.0f); +} + + +RateTransposerFloat::~RateTransposerFloat() +{ +} + + +void RateTransposerFloat::resetRegisters() +{ + fSlopeCount = 0; + sPrevSampleL = + sPrevSampleR = 0; +} + + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int i, used; + + used = 0; + i = 0; + + // Process the last sample saved from the previous call first... + while (fSlopeCount <= 1.0f) + { + dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); + i++; + fSlopeCount += fRate; + } + fSlopeCount -= 1.0f; + + if (numSamples == 1) goto end; + + while (1) + { + while (fSlopeCount > 1.0f) + { + fSlopeCount -= 1.0f; + used ++; + if (used >= numSamples - 1) goto end; + } + dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[used] + fSlopeCount * src[used + 1]); + i++; + fSlopeCount += fRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[numSamples - 1]; + + return i; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int srcPos, i, used; + + if (numSamples == 0) return 0; // no samples, no work + + used = 0; + i = 0; + + // Process the last sample saved from the sPrevSampleLious call first... + while (fSlopeCount <= 1.0f) + { + dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); + dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleR + fSlopeCount * src[1]); + i++; + fSlopeCount += fRate; + } + // now always (iSlopeCount > 1.0f) + fSlopeCount -= 1.0f; + + if (numSamples == 1) goto end; + + while (1) + { + while (fSlopeCount > 1.0f) + { + fSlopeCount -= 1.0f; + used ++; + if (used >= numSamples - 1) goto end; + } + srcPos = 2 * used; + + dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos] + + fSlopeCount * src[srcPos + 2]); + dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos + 1] + + fSlopeCount * src[srcPos + 3]); + + i++; + fSlopeCount += fRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[2 * numSamples - 2]; + sPrevSampleR = src[2 * numSamples - 1]; + + return i; +} diff --git a/plugins/zerospu2/3rdparty/SoundTouch/RateTransposer.h b/plugins/zerospu2/3rdparty/SoundTouch/RateTransposer.h index f73978e639..1cd6e9026d 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/RateTransposer.h +++ b/plugins/zerospu2/3rdparty/SoundTouch/RateTransposer.h @@ -1,162 +1,162 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sample rate transposer. Changes sample rate by using linear interpolation -/// together with anti-alias filtering (first order interpolation with anti- -/// alias filtering should be quite adequate for this application). -/// -/// Use either of the derived classes of 'RateTransposerInteger' or -/// 'RateTransposerFloat' for corresponding integer/floating point tranposing -/// algorithm implementation. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.10 $ -// -// $Id: RateTransposer.h,v 1.10 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef RateTransposer_H -#define RateTransposer_H - -#include "AAFilter.h" -#include "FIFOSamplePipe.h" -#include "FIFOSampleBuffer.h" - -#include "STTypes.h" - -namespace soundtouch -{ - -/// A common linear samplerate transposer class. -/// -/// Note: Use function "RateTransposer::newInstance()" to create a new class -/// instance instead of the "new" operator; that function automatically -/// chooses a correct implementation depending on if integer or floating -/// arithmetics are to be used. -class RateTransposer : public FIFOProcessor -{ -protected: - /// Anti-alias filter object - AAFilter *pAAFilter; - - float fRate; - - uint uChannels; - - /// Buffer for collecting samples to feed the anti-alias filter between - /// two batches - FIFOSampleBuffer storeBuffer; - - /// Buffer for keeping samples between transposing & anti-alias filter - FIFOSampleBuffer tempBuffer; - - /// Output sample buffer - FIFOSampleBuffer outputBuffer; - - BOOL bUseAAFilter; - - void init(); - - virtual void resetRegisters() = 0; - - virtual uint transposeStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples) = 0; - virtual uint transposeMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples) = 0; - uint transpose(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - - void flushStoreBuffer(); - - void downsample(const SAMPLETYPE *src, - uint numSamples); - void upsample(const SAMPLETYPE *src, - uint numSamples); - - /// Transposes sample rate by applying anti-alias filter to prevent folding. - /// Returns amount of samples returned in the "dest" buffer. - /// The maximum amount of samples that can be returned at a time is set by - /// the 'set_returnBuffer_size' function. - void processSamples(const SAMPLETYPE *src, - uint numSamples); - - -public: - RateTransposer(); - virtual ~RateTransposer(); - - /// Operator 'new' is overloaded so that it automatically creates a suitable instance - /// depending on if we're to use integer or floating point arithmetics. - void *operator new(size_t s); - - /// Use this function instead of "new" operator to create a new instance of this class. - /// This function automatically chooses a correct implementation, depending on if - /// integer ot floating point arithmetics are to be used. - static RateTransposer *newInstance(); - - /// Returns the output buffer object - FIFOSamplePipe *getOutput() { return &outputBuffer; }; - - /// Returns the store buffer object - FIFOSamplePipe *getStore() { return &storeBuffer; }; - - /// Return anti-alias filter object - AAFilter *getAAFilter() const; - - /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable - void enableAAFilter(BOOL newMode); - - /// Returns nonzero if anti-alias filter is enabled. - BOOL isAAFilterEnabled() const; - - /// Sets new target rate. Normal rate = 1.0, smaller values represent slower - /// rate, larger faster rates. - virtual void setRate(float newRate); - - /// Sets the number of channels, 1 = mono, 2 = stereo - void setChannels(uint channels); - - /// Adds 'numSamples' pcs of samples from the 'samples' memory position into - /// the input of the object. - void putSamples(const SAMPLETYPE *samples, uint numSamples); - - /// Clears all the samples in the object - void clear(); - - /// Returns nonzero if there aren't any samples available for outputting. - uint isEmpty(); -}; - -} - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sample rate transposer. Changes sample rate by using linear interpolation +/// together with anti-alias filtering (first order interpolation with anti- +/// alias filtering should be quite adequate for this application). +/// +/// Use either of the derived classes of 'RateTransposerInteger' or +/// 'RateTransposerFloat' for corresponding integer/floating point tranposing +/// algorithm implementation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: RateTransposer.h,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef RateTransposer_H +#define RateTransposer_H + +#include "AAFilter.h" +#include "FIFOSamplePipe.h" +#include "FIFOSampleBuffer.h" + +#include "STTypes.h" + +namespace soundtouch +{ + +/// A common linear samplerate transposer class. +/// +/// Note: Use function "RateTransposer::newInstance()" to create a new class +/// instance instead of the "new" operator; that function automatically +/// chooses a correct implementation depending on if integer or floating +/// arithmetics are to be used. +class RateTransposer : public FIFOProcessor +{ +protected: + /// Anti-alias filter object + AAFilter *pAAFilter; + + float fRate; + + uint uChannels; + + /// Buffer for collecting samples to feed the anti-alias filter between + /// two batches + FIFOSampleBuffer storeBuffer; + + /// Buffer for keeping samples between transposing & anti-alias filter + FIFOSampleBuffer tempBuffer; + + /// Output sample buffer + FIFOSampleBuffer outputBuffer; + + BOOL bUseAAFilter; + + void init(); + + virtual void resetRegisters() = 0; + + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) = 0; + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) = 0; + uint transpose(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + + void flushStoreBuffer(); + + void downsample(const SAMPLETYPE *src, + uint numSamples); + void upsample(const SAMPLETYPE *src, + uint numSamples); + + /// Transposes sample rate by applying anti-alias filter to prevent folding. + /// Returns amount of samples returned in the "dest" buffer. + /// The maximum amount of samples that can be returned at a time is set by + /// the 'set_returnBuffer_size' function. + void processSamples(const SAMPLETYPE *src, + uint numSamples); + + +public: + RateTransposer(); + virtual ~RateTransposer(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we're to use integer or floating point arithmetics. + void *operator new(size_t s); + + /// Use this function instead of "new" operator to create a new instance of this class. + /// This function automatically chooses a correct implementation, depending on if + /// integer ot floating point arithmetics are to be used. + static RateTransposer *newInstance(); + + /// Returns the output buffer object + FIFOSamplePipe *getOutput() { return &outputBuffer; }; + + /// Returns the store buffer object + FIFOSamplePipe *getStore() { return &storeBuffer; }; + + /// Return anti-alias filter object + AAFilter *getAAFilter() const; + + /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable + void enableAAFilter(BOOL newMode); + + /// Returns nonzero if anti-alias filter is enabled. + BOOL isAAFilterEnabled() const; + + /// Sets new target rate. Normal rate = 1.0, smaller values represent slower + /// rate, larger faster rates. + virtual void setRate(float newRate); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint channels); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position into + /// the input of the object. + void putSamples(const SAMPLETYPE *samples, uint numSamples); + + /// Clears all the samples in the object + void clear(); + + /// Returns nonzero if there aren't any samples available for outputting. + uint isEmpty(); +}; + +} + +#endif diff --git a/plugins/zerospu2/3rdparty/SoundTouch/STTypes.h b/plugins/zerospu2/3rdparty/SoundTouch/STTypes.h index f3a6a5d5c0..d0969ec1c9 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/STTypes.h +++ b/plugins/zerospu2/3rdparty/SoundTouch/STTypes.h @@ -1,202 +1,202 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Common type definitions for SoundTouch audio processing library. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.16 $ -// -// $Id: STTypes.h,v 1.16 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef STTypes_H -#define STTypes_H - -//#define INTEGER_SAMPLES 1 - -typedef unsigned int uint; -typedef unsigned long ulong; - -#ifdef __x86_64__ -typedef unsigned long long ulongptr; -#else -typedef unsigned long ulongptr; -#endif - - -#ifdef __GNUC__ - // In GCC, include soundtouch_config.h made by config scritps -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the `m' library (-lm). */ -#define HAVE_LIBM 1 - -/* Define to 1 if your system has a GNU libc compatible `malloc' function, and - to 0 otherwise. */ -#define HAVE_MALLOC 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Use Integer as Sample type */ -//#define INTEGER_SAMPLES 1 - -/* Define as the return type of signal handlers (`int' or `void'). */ -#define RETSIGTYPE void - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -#endif - -#ifndef _WINDEF_ - // if these aren't defined already by Windows headers, define now - - typedef int BOOL; - -#ifndef FALSE - #define FALSE 0 -#endif - -#ifndef TRUE - #define TRUE 1 -#endif - -#endif // _WINDEF_ - - -namespace soundtouch -{ -/// Activate these undef's to overrule the possible sampletype -/// setting inherited from some other header file: -//#undef INTEGER_SAMPLES -//#undef FLOAT_SAMPLES - -#if !(INTEGER_SAMPLES || FLOAT_SAMPLES) - - /// Choose either 32bit floating point or 16bit integer sampletype - /// by choosing one of the following defines, unless this selection - /// has already been done in some other file. - //// - /// Notes: - /// - In Windows environment, choose the sample format with the - /// following defines. - /// - In GNU environment, the floating point samples are used by - /// default, but integer samples can be chosen by giving the - /// following switch to the configure script: - /// ./configure --enable-integer-samples - /// However, if you still prefer to select the sample format here - /// also in GNU environment, then please #undef the INTEGER_SAMPLE - /// and FLOAT_SAMPLE defines first as in comments above. - //#define INTEGER_SAMPLES 1 //< 16bit integer samples - #define FLOAT_SAMPLES 1 //< 32bit float samples - - #endif - - /// Define this to allow CPU-specific assembler optimizations. Notice that - /// having this enabled on non-x86 platforms doesn't matter; the compiler can - /// drop unsupported extensions on different platforms automatically. - /// However, if you're having difficulties getting the optimized routines - /// compiled with your compler (e.g. some gcc compiler versions may be picky), - /// you may wish to disable the optimizations to make the library compile. - #if !defined(_MSC_VER) || !defined(__x86_64__) - #define ALLOW_OPTIMIZATIONS 1 - #define ALLOW_NONEXACT_SIMD_OPTIMIZATION 1 - #endif - - - // If defined, allows the SIMD-optimized routines to take minor shortcuts - // for improved performance. Undefine to require faithfully similar SIMD - // calculations as in normal C implementation. - - - - #ifdef INTEGER_SAMPLES - // 16bit integer sample type - typedef short SAMPLETYPE; - // data type for sample accumulation: Use 32bit integer to prevent overflows - typedef long LONG_SAMPLETYPE; - - #ifdef FLOAT_SAMPLES - // check that only one sample type is defined - #error "conflicting sample types defined" - #endif // FLOAT_SAMPLES - - #ifdef ALLOW_OPTIMIZATIONS - #if (_WIN32 || __i386__ || __x86_64__) - // Allow MMX optimizations - #define ALLOW_MMX 1 - #endif - #endif - - #else - - // floating point samples - typedef float SAMPLETYPE; - // data type for sample accumulation: Use double to utilize full precision. - typedef double LONG_SAMPLETYPE; - - #ifdef ALLOW_OPTIMIZATIONS - // Allow 3DNow! and SSE optimizations - #if _WIN32 - // #define ALLOW_3DNOW 1 - #endif - - #if (_WIN32 || __i386__ || __x86_64__) - #define ALLOW_SSE 1 - #endif - #endif - - #endif // INTEGER_SAMPLES -}; - +//////////////////////////////////////////////////////////////////////////////// +/// +/// Common type definitions for SoundTouch audio processing library. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.16 $ +// +// $Id: STTypes.h,v 1.16 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef STTypes_H +#define STTypes_H + +//#define INTEGER_SAMPLES 1 + +typedef unsigned int uint; +typedef unsigned long ulong; + +#ifdef __x86_64__ +typedef unsigned long long ulongptr; +#else +typedef unsigned long ulongptr; +#endif + + +#ifdef __GNUC__ + // In GCC, include soundtouch_config.h made by config scritps +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `m' library (-lm). */ +#define HAVE_LIBM 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Use Integer as Sample type */ +//#define INTEGER_SAMPLES 1 + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +#endif + +#ifndef _WINDEF_ + // if these aren't defined already by Windows headers, define now + + typedef int BOOL; + +#ifndef FALSE + #define FALSE 0 +#endif + +#ifndef TRUE + #define TRUE 1 +#endif + +#endif // _WINDEF_ + + +namespace soundtouch +{ +/// Activate these undef's to overrule the possible sampletype +/// setting inherited from some other header file: +//#undef INTEGER_SAMPLES +//#undef FLOAT_SAMPLES + +#if !(INTEGER_SAMPLES || FLOAT_SAMPLES) + + /// Choose either 32bit floating point or 16bit integer sampletype + /// by choosing one of the following defines, unless this selection + /// has already been done in some other file. + //// + /// Notes: + /// - In Windows environment, choose the sample format with the + /// following defines. + /// - In GNU environment, the floating point samples are used by + /// default, but integer samples can be chosen by giving the + /// following switch to the configure script: + /// ./configure --enable-integer-samples + /// However, if you still prefer to select the sample format here + /// also in GNU environment, then please #undef the INTEGER_SAMPLE + /// and FLOAT_SAMPLE defines first as in comments above. + //#define INTEGER_SAMPLES 1 //< 16bit integer samples + #define FLOAT_SAMPLES 1 //< 32bit float samples + + #endif + + /// Define this to allow CPU-specific assembler optimizations. Notice that + /// having this enabled on non-x86 platforms doesn't matter; the compiler can + /// drop unsupported extensions on different platforms automatically. + /// However, if you're having difficulties getting the optimized routines + /// compiled with your compler (e.g. some gcc compiler versions may be picky), + /// you may wish to disable the optimizations to make the library compile. + #if !defined(_MSC_VER) || !defined(__x86_64__) + #define ALLOW_OPTIMIZATIONS 1 + #define ALLOW_NONEXACT_SIMD_OPTIMIZATION 1 + #endif + + + // If defined, allows the SIMD-optimized routines to take minor shortcuts + // for improved performance. Undefine to require faithfully similar SIMD + // calculations as in normal C implementation. + + + + #ifdef INTEGER_SAMPLES + // 16bit integer sample type + typedef short SAMPLETYPE; + // data type for sample accumulation: Use 32bit integer to prevent overflows + typedef long LONG_SAMPLETYPE; + + #ifdef FLOAT_SAMPLES + // check that only one sample type is defined + #error "conflicting sample types defined" + #endif // FLOAT_SAMPLES + + #ifdef ALLOW_OPTIMIZATIONS + #if (_WIN32 || __i386__ || __x86_64__) + // Allow MMX optimizations + #define ALLOW_MMX 1 + #endif + #endif + + #else + + // floating point samples + typedef float SAMPLETYPE; + // data type for sample accumulation: Use double to utilize full precision. + typedef double LONG_SAMPLETYPE; + + #ifdef ALLOW_OPTIMIZATIONS + // Allow 3DNow! and SSE optimizations + #if _WIN32 + // #define ALLOW_3DNOW 1 + #endif + + #if (_WIN32 || __i386__ || __x86_64__) + #define ALLOW_SSE 1 + #endif + #endif + + #endif // INTEGER_SAMPLES +}; + #endif \ No newline at end of file diff --git a/plugins/zerospu2/3rdparty/SoundTouch/SoundTouch.cpp b/plugins/zerospu2/3rdparty/SoundTouch/SoundTouch.cpp index d20fd326ba..381c517162 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/SoundTouch.cpp +++ b/plugins/zerospu2/3rdparty/SoundTouch/SoundTouch.cpp @@ -1,474 +1,474 @@ -////////////////////////////////////////////////////////////////////////////// -/// -/// SoundTouch - main class for tempo/pitch/rate adjusting routines. -/// -/// Notes: -/// - Initialize the SoundTouch object instance by setting up the sound stream -/// parameters with functions 'setSampleRate' and 'setChannels', then set -/// desired tempo/pitch/rate settings with the corresponding functions. -/// -/// - The SoundTouch class behaves like a first-in-first-out pipeline: The -/// samples that are to be processed are fed into one of the pipe by calling -/// function 'putSamples', while the ready processed samples can be read -/// from the other end of the pipeline with function 'receiveSamples'. -/// -/// - The SoundTouch processing classes require certain sized 'batches' of -/// samples in order to process the sound. For this reason the classes buffer -/// incoming samples until there are enough of samples available for -/// processing, then they carry out the processing step and consequently -/// make the processed samples available for outputting. -/// -/// - For the above reason, the processing routines introduce a certain -/// 'latency' between the input and output, so that the samples input to -/// SoundTouch may not be immediately available in the output, and neither -/// the amount of outputtable samples may not immediately be in direct -/// relationship with the amount of previously input samples. -/// -/// - The tempo/pitch/rate control parameters can be altered during processing. -/// Please notice though that they aren't currently protected by semaphores, -/// so in multi-thread application external semaphore protection may be -/// required. -/// -/// - This class utilizes classes 'TDStretch' for tempo change (without modifying -/// pitch) and 'RateTransposer' for changing the playback rate (that is, both -/// tempo and pitch in the same ratio) of the sound. The third available control -/// 'pitch' (change pitch but maintain tempo) is produced by a combination of -/// combining the two other controls. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.13 $ -// -// $Id: SoundTouch.cpp,v 1.13 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include - -#include "SoundTouch.h" -#include "TDStretch.h" -#include "RateTransposer.h" -#include "cpu_detect.h" - -using namespace soundtouch; - -/// Print library version string -extern "C" void soundtouch_ac_test() -{ - printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION); -} - - -SoundTouch::SoundTouch() -{ - // Initialize rate transposer and tempo changer instances - - pRateTransposer = RateTransposer::newInstance(); - pTDStretch = TDStretch::newInstance(); - - setOutPipe(pTDStretch); - - rate = tempo = 0; - - virtualPitch = - virtualRate = - virtualTempo = 1.0; - - calcEffectiveRateAndTempo(); - - channels = 0; - bSrateSet = FALSE; -} - - - -SoundTouch::~SoundTouch() -{ - delete pRateTransposer; - delete pTDStretch; -} - - - -/// Get SoundTouch library version string -const char *SoundTouch::getVersionString() -{ - static const char *_version = SOUNDTOUCH_VERSION; - - return _version; -} - - -/// Get SoundTouch library version Id -uint SoundTouch::getVersionId() -{ - return SOUNDTOUCH_VERSION_ID; -} - - -// Sets the number of channels, 1 = mono, 2 = stereo -void SoundTouch::setChannels(uint numChannels) -{ - if (numChannels != 1 && numChannels != 2) - { - throw std::runtime_error("Illegal number of channels"); - } - channels = numChannels; - pRateTransposer->setChannels(numChannels); - pTDStretch->setChannels(numChannels); -} - - - -// Sets new rate control value. Normal rate = 1.0, smaller values -// represent slower rate, larger faster rates. -void SoundTouch::setRate(float newRate) -{ - virtualRate = newRate; - calcEffectiveRateAndTempo(); -} - - - -// Sets new rate control value as a difference in percents compared -// to the original rate (-50 .. +100 %) -void SoundTouch::setRateChange(float newRate) -{ - virtualRate = 1.0f + 0.01f * newRate; - calcEffectiveRateAndTempo(); -} - - - -// Sets new tempo control value. Normal tempo = 1.0, smaller values -// represent slower tempo, larger faster tempo. -void SoundTouch::setTempo(float newTempo) -{ - virtualTempo = newTempo; - calcEffectiveRateAndTempo(); -} - - - -// Sets new tempo control value as a difference in percents compared -// to the original tempo (-50 .. +100 %) -void SoundTouch::setTempoChange(float newTempo) -{ - virtualTempo = 1.0f + 0.01f * newTempo; - calcEffectiveRateAndTempo(); -} - - - -// Sets new pitch control value. Original pitch = 1.0, smaller values -// represent lower pitches, larger values higher pitch. -void SoundTouch::setPitch(float newPitch) -{ - virtualPitch = newPitch; - calcEffectiveRateAndTempo(); -} - - - -// Sets pitch change in octaves compared to the original pitch -// (-1.00 .. +1.00) -void SoundTouch::setPitchOctaves(float newPitch) -{ - virtualPitch = (float)exp(0.69314718056f * newPitch); - calcEffectiveRateAndTempo(); -} - - - -// Sets pitch change in semi-tones compared to the original pitch -// (-12 .. +12) -void SoundTouch::setPitchSemiTones(int newPitch) -{ - setPitchOctaves((float)newPitch / 12.0f); -} - - - -void SoundTouch::setPitchSemiTones(float newPitch) -{ - setPitchOctaves(newPitch / 12.0f); -} - - -// Calculates 'effective' rate and tempo values from the -// nominal control values. -void SoundTouch::calcEffectiveRateAndTempo() -{ - float oldTempo = tempo; - float oldRate = rate; - - tempo = virtualTempo / virtualPitch; - rate = virtualPitch * virtualRate; - - if (rate != oldRate) pRateTransposer->setRate(rate); - if (tempo != oldTempo) pTDStretch->setTempo(tempo); - - if (rate > 1.0f) - { - if (output != pRateTransposer) - { - FIFOSamplePipe *transOut; - - assert(output == pTDStretch); - // move samples in the current output buffer to the output of pRateTransposer - transOut = pRateTransposer->getOutput(); - transOut->moveSamples(*output); - // move samples in tempo changer's input to pitch transposer's input - pRateTransposer->moveSamples(*pTDStretch->getInput()); - - output = pRateTransposer; - } - } - else - { - if (output != pTDStretch) - { - FIFOSamplePipe *tempoOut; - - assert(output == pRateTransposer); - // move samples in the current output buffer to the output of pTDStretch - tempoOut = pTDStretch->getOutput(); - tempoOut->moveSamples(*output); - // move samples in pitch transposer's store buffer to tempo changer's input - pTDStretch->moveSamples(*pRateTransposer->getStore()); - - output = pTDStretch; - - } - } -} - - -// Sets sample rate. -void SoundTouch::setSampleRate(uint srate) -{ - bSrateSet = TRUE; - // set sample rate, leave other tempo changer parameters as they are. - pTDStretch->setParameters(srate); -} - - -// Adds 'numSamples' pcs of samples from the 'samples' memory position into -// the input of the object. -void SoundTouch::putSamples(const SAMPLETYPE *samples, uint numSamples) -{ - if (bSrateSet == FALSE) - { - throw std::runtime_error("SoundTouch : Sample rate not defined"); - } - else if (channels == 0) - { - throw std::runtime_error("SoundTouch : Number of channels not defined"); - } - - // Transpose the rate of the new samples if necessary - /* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value... - if (rate == 1.0f) - { - // The rate value is same as the original, simply evaluate the tempo changer. - assert(output == pTDStretch); - if (pRateTransposer->isEmpty() == 0) - { - // yet flush the last samples in the pitch transposer buffer - // (may happen if 'rate' changes from a non-zero value to zero) - pTDStretch->moveSamples(*pRateTransposer); - } - pTDStretch->putSamples(samples, numSamples); - } - */ - else if (rate <= 1.0f) - { - // transpose the rate down, output the transposed sound to tempo changer buffer - assert(output == pTDStretch); - pRateTransposer->putSamples(samples, numSamples); - pTDStretch->moveSamples(*pRateTransposer); - } - else - { - assert(rate > 1.0f); - // evaluate the tempo changer, then transpose the rate up, - assert(output == pRateTransposer); - pTDStretch->putSamples(samples, numSamples); - pRateTransposer->moveSamples(*pTDStretch); - } -} - - -// Flushes the last samples from the processing pipeline to the output. -// Clears also the internal processing buffers. -// -// Note: This function is meant for extracting the last samples of a sound -// stream. This function may introduce additional blank samples in the end -// of the sound stream, and thus it's not recommended to call this function -// in the middle of a sound stream. -void SoundTouch::flush() -{ - int i; - uint nOut; - SAMPLETYPE buff[128]; - - nOut = numSamples(); - - memset(buff, 0, 128 * sizeof(SAMPLETYPE)); - // "Push" the last active samples out from the processing pipeline by - // feeding blank samples into the processing pipeline until new, - // processed samples appear in the output (not however, more than - // 8ksamples in any case) - for (i = 0; i < 128; i ++) - { - putSamples(buff, 64); - if (numSamples() != nOut) break; // new samples have appeared in the output! - } - - // Clear working buffers - pRateTransposer->clear(); - pTDStretch->clearInput(); - // yet leave the 'tempoChanger' output intouched as that's where the - // flushed samples are! -} - - -// Changes a setting controlling the processing system behaviour. See the -// 'SETTING_...' defines for available setting ID's. -BOOL SoundTouch::setSetting(uint settingId, uint value) -{ - uint sampleRate, sequenceMs, seekWindowMs, overlapMs; - - // read current tdstretch routine parameters - pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs); - - switch (settingId) - { - case SETTING_USE_AA_FILTER : - // enables / disabless anti-alias filter - pRateTransposer->enableAAFilter((value != 0) ? TRUE : FALSE); - return TRUE; - - case SETTING_AA_FILTER_LENGTH : - // sets anti-alias filter length - pRateTransposer->getAAFilter()->setLength(value); - return TRUE; - - case SETTING_USE_QUICKSEEK : - // enables / disables tempo routine quick seeking algorithm - pTDStretch->enableQuickSeek((value != 0) ? TRUE : FALSE); - return TRUE; - - case SETTING_SEQUENCE_MS: - // change time-stretch sequence duration parameter - pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs); - return TRUE; - - case SETTING_SEEKWINDOW_MS: - // change time-stretch seek window length parameter - pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs); - return TRUE; - - case SETTING_OVERLAP_MS: - // change time-stretch overlap length parameter - pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value); - return TRUE; - - default : - return FALSE; - } -} - - -// Reads a setting controlling the processing system behaviour. See the -// 'SETTING_...' defines for available setting ID's. -// -// Returns the setting value. -uint SoundTouch::getSetting(uint settingId) const -{ - uint temp; - - switch (settingId) - { - case SETTING_USE_AA_FILTER : - return pRateTransposer->isAAFilterEnabled(); - - case SETTING_AA_FILTER_LENGTH : - return pRateTransposer->getAAFilter()->getLength(); - - case SETTING_USE_QUICKSEEK : - return pTDStretch->isQuickSeekEnabled(); - - case SETTING_SEQUENCE_MS: - pTDStretch->getParameters(NULL, &temp, NULL, NULL); - return temp; - - case SETTING_SEEKWINDOW_MS: - pTDStretch->getParameters(NULL, NULL, &temp, NULL); - return temp; - - case SETTING_OVERLAP_MS: - pTDStretch->getParameters(NULL, NULL, NULL, &temp); - return temp; - - default : - return 0; - } -} - - -// Clears all the samples in the object's output and internal processing -// buffers. -void SoundTouch::clear() -{ - pRateTransposer->clear(); - pTDStretch->clear(); -} - - - -/// Returns number of samples currently unprocessed. -uint SoundTouch::numUnprocessedSamples() const -{ - FIFOSamplePipe * psp; - if (pTDStretch) - { - psp = pTDStretch->getInput(); - if (psp) - { - return psp->numSamples(); - } - } - return 0; -} +////////////////////////////////////////////////////////////////////////////// +/// +/// SoundTouch - main class for tempo/pitch/rate adjusting routines. +/// +/// Notes: +/// - Initialize the SoundTouch object instance by setting up the sound stream +/// parameters with functions 'setSampleRate' and 'setChannels', then set +/// desired tempo/pitch/rate settings with the corresponding functions. +/// +/// - The SoundTouch class behaves like a first-in-first-out pipeline: The +/// samples that are to be processed are fed into one of the pipe by calling +/// function 'putSamples', while the ready processed samples can be read +/// from the other end of the pipeline with function 'receiveSamples'. +/// +/// - The SoundTouch processing classes require certain sized 'batches' of +/// samples in order to process the sound. For this reason the classes buffer +/// incoming samples until there are enough of samples available for +/// processing, then they carry out the processing step and consequently +/// make the processed samples available for outputting. +/// +/// - For the above reason, the processing routines introduce a certain +/// 'latency' between the input and output, so that the samples input to +/// SoundTouch may not be immediately available in the output, and neither +/// the amount of outputtable samples may not immediately be in direct +/// relationship with the amount of previously input samples. +/// +/// - The tempo/pitch/rate control parameters can be altered during processing. +/// Please notice though that they aren't currently protected by semaphores, +/// so in multi-thread application external semaphore protection may be +/// required. +/// +/// - This class utilizes classes 'TDStretch' for tempo change (without modifying +/// pitch) and 'RateTransposer' for changing the playback rate (that is, both +/// tempo and pitch in the same ratio) of the sound. The third available control +/// 'pitch' (change pitch but maintain tempo) is produced by a combination of +/// combining the two other controls. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.13 $ +// +// $Id: SoundTouch.cpp,v 1.13 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include "SoundTouch.h" +#include "TDStretch.h" +#include "RateTransposer.h" +#include "cpu_detect.h" + +using namespace soundtouch; + +/// Print library version string +extern "C" void soundtouch_ac_test() +{ + printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION); +} + + +SoundTouch::SoundTouch() +{ + // Initialize rate transposer and tempo changer instances + + pRateTransposer = RateTransposer::newInstance(); + pTDStretch = TDStretch::newInstance(); + + setOutPipe(pTDStretch); + + rate = tempo = 0; + + virtualPitch = + virtualRate = + virtualTempo = 1.0; + + calcEffectiveRateAndTempo(); + + channels = 0; + bSrateSet = FALSE; +} + + + +SoundTouch::~SoundTouch() +{ + delete pRateTransposer; + delete pTDStretch; +} + + + +/// Get SoundTouch library version string +const char *SoundTouch::getVersionString() +{ + static const char *_version = SOUNDTOUCH_VERSION; + + return _version; +} + + +/// Get SoundTouch library version Id +uint SoundTouch::getVersionId() +{ + return SOUNDTOUCH_VERSION_ID; +} + + +// Sets the number of channels, 1 = mono, 2 = stereo +void SoundTouch::setChannels(uint numChannels) +{ + if (numChannels != 1 && numChannels != 2) + { + throw std::runtime_error("Illegal number of channels"); + } + channels = numChannels; + pRateTransposer->setChannels(numChannels); + pTDStretch->setChannels(numChannels); +} + + + +// Sets new rate control value. Normal rate = 1.0, smaller values +// represent slower rate, larger faster rates. +void SoundTouch::setRate(float newRate) +{ + virtualRate = newRate; + calcEffectiveRateAndTempo(); +} + + + +// Sets new rate control value as a difference in percents compared +// to the original rate (-50 .. +100 %) +void SoundTouch::setRateChange(float newRate) +{ + virtualRate = 1.0f + 0.01f * newRate; + calcEffectiveRateAndTempo(); +} + + + +// Sets new tempo control value. Normal tempo = 1.0, smaller values +// represent slower tempo, larger faster tempo. +void SoundTouch::setTempo(float newTempo) +{ + virtualTempo = newTempo; + calcEffectiveRateAndTempo(); +} + + + +// Sets new tempo control value as a difference in percents compared +// to the original tempo (-50 .. +100 %) +void SoundTouch::setTempoChange(float newTempo) +{ + virtualTempo = 1.0f + 0.01f * newTempo; + calcEffectiveRateAndTempo(); +} + + + +// Sets new pitch control value. Original pitch = 1.0, smaller values +// represent lower pitches, larger values higher pitch. +void SoundTouch::setPitch(float newPitch) +{ + virtualPitch = newPitch; + calcEffectiveRateAndTempo(); +} + + + +// Sets pitch change in octaves compared to the original pitch +// (-1.00 .. +1.00) +void SoundTouch::setPitchOctaves(float newPitch) +{ + virtualPitch = (float)exp(0.69314718056f * newPitch); + calcEffectiveRateAndTempo(); +} + + + +// Sets pitch change in semi-tones compared to the original pitch +// (-12 .. +12) +void SoundTouch::setPitchSemiTones(int newPitch) +{ + setPitchOctaves((float)newPitch / 12.0f); +} + + + +void SoundTouch::setPitchSemiTones(float newPitch) +{ + setPitchOctaves(newPitch / 12.0f); +} + + +// Calculates 'effective' rate and tempo values from the +// nominal control values. +void SoundTouch::calcEffectiveRateAndTempo() +{ + float oldTempo = tempo; + float oldRate = rate; + + tempo = virtualTempo / virtualPitch; + rate = virtualPitch * virtualRate; + + if (rate != oldRate) pRateTransposer->setRate(rate); + if (tempo != oldTempo) pTDStretch->setTempo(tempo); + + if (rate > 1.0f) + { + if (output != pRateTransposer) + { + FIFOSamplePipe *transOut; + + assert(output == pTDStretch); + // move samples in the current output buffer to the output of pRateTransposer + transOut = pRateTransposer->getOutput(); + transOut->moveSamples(*output); + // move samples in tempo changer's input to pitch transposer's input + pRateTransposer->moveSamples(*pTDStretch->getInput()); + + output = pRateTransposer; + } + } + else + { + if (output != pTDStretch) + { + FIFOSamplePipe *tempoOut; + + assert(output == pRateTransposer); + // move samples in the current output buffer to the output of pTDStretch + tempoOut = pTDStretch->getOutput(); + tempoOut->moveSamples(*output); + // move samples in pitch transposer's store buffer to tempo changer's input + pTDStretch->moveSamples(*pRateTransposer->getStore()); + + output = pTDStretch; + + } + } +} + + +// Sets sample rate. +void SoundTouch::setSampleRate(uint srate) +{ + bSrateSet = TRUE; + // set sample rate, leave other tempo changer parameters as they are. + pTDStretch->setParameters(srate); +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void SoundTouch::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + if (bSrateSet == FALSE) + { + throw std::runtime_error("SoundTouch : Sample rate not defined"); + } + else if (channels == 0) + { + throw std::runtime_error("SoundTouch : Number of channels not defined"); + } + + // Transpose the rate of the new samples if necessary + /* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value... + if (rate == 1.0f) + { + // The rate value is same as the original, simply evaluate the tempo changer. + assert(output == pTDStretch); + if (pRateTransposer->isEmpty() == 0) + { + // yet flush the last samples in the pitch transposer buffer + // (may happen if 'rate' changes from a non-zero value to zero) + pTDStretch->moveSamples(*pRateTransposer); + } + pTDStretch->putSamples(samples, numSamples); + } + */ + else if (rate <= 1.0f) + { + // transpose the rate down, output the transposed sound to tempo changer buffer + assert(output == pTDStretch); + pRateTransposer->putSamples(samples, numSamples); + pTDStretch->moveSamples(*pRateTransposer); + } + else + { + assert(rate > 1.0f); + // evaluate the tempo changer, then transpose the rate up, + assert(output == pRateTransposer); + pTDStretch->putSamples(samples, numSamples); + pRateTransposer->moveSamples(*pTDStretch); + } +} + + +// Flushes the last samples from the processing pipeline to the output. +// Clears also the internal processing buffers. +// +// Note: This function is meant for extracting the last samples of a sound +// stream. This function may introduce additional blank samples in the end +// of the sound stream, and thus it's not recommended to call this function +// in the middle of a sound stream. +void SoundTouch::flush() +{ + int i; + uint nOut; + SAMPLETYPE buff[128]; + + nOut = numSamples(); + + memset(buff, 0, 128 * sizeof(SAMPLETYPE)); + // "Push" the last active samples out from the processing pipeline by + // feeding blank samples into the processing pipeline until new, + // processed samples appear in the output (not however, more than + // 8ksamples in any case) + for (i = 0; i < 128; i ++) + { + putSamples(buff, 64); + if (numSamples() != nOut) break; // new samples have appeared in the output! + } + + // Clear working buffers + pRateTransposer->clear(); + pTDStretch->clearInput(); + // yet leave the 'tempoChanger' output intouched as that's where the + // flushed samples are! +} + + +// Changes a setting controlling the processing system behaviour. See the +// 'SETTING_...' defines for available setting ID's. +BOOL SoundTouch::setSetting(uint settingId, uint value) +{ + uint sampleRate, sequenceMs, seekWindowMs, overlapMs; + + // read current tdstretch routine parameters + pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs); + + switch (settingId) + { + case SETTING_USE_AA_FILTER : + // enables / disabless anti-alias filter + pRateTransposer->enableAAFilter((value != 0) ? TRUE : FALSE); + return TRUE; + + case SETTING_AA_FILTER_LENGTH : + // sets anti-alias filter length + pRateTransposer->getAAFilter()->setLength(value); + return TRUE; + + case SETTING_USE_QUICKSEEK : + // enables / disables tempo routine quick seeking algorithm + pTDStretch->enableQuickSeek((value != 0) ? TRUE : FALSE); + return TRUE; + + case SETTING_SEQUENCE_MS: + // change time-stretch sequence duration parameter + pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs); + return TRUE; + + case SETTING_SEEKWINDOW_MS: + // change time-stretch seek window length parameter + pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs); + return TRUE; + + case SETTING_OVERLAP_MS: + // change time-stretch overlap length parameter + pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value); + return TRUE; + + default : + return FALSE; + } +} + + +// Reads a setting controlling the processing system behaviour. See the +// 'SETTING_...' defines for available setting ID's. +// +// Returns the setting value. +uint SoundTouch::getSetting(uint settingId) const +{ + uint temp; + + switch (settingId) + { + case SETTING_USE_AA_FILTER : + return pRateTransposer->isAAFilterEnabled(); + + case SETTING_AA_FILTER_LENGTH : + return pRateTransposer->getAAFilter()->getLength(); + + case SETTING_USE_QUICKSEEK : + return pTDStretch->isQuickSeekEnabled(); + + case SETTING_SEQUENCE_MS: + pTDStretch->getParameters(NULL, &temp, NULL, NULL); + return temp; + + case SETTING_SEEKWINDOW_MS: + pTDStretch->getParameters(NULL, NULL, &temp, NULL); + return temp; + + case SETTING_OVERLAP_MS: + pTDStretch->getParameters(NULL, NULL, NULL, &temp); + return temp; + + default : + return 0; + } +} + + +// Clears all the samples in the object's output and internal processing +// buffers. +void SoundTouch::clear() +{ + pRateTransposer->clear(); + pTDStretch->clear(); +} + + + +/// Returns number of samples currently unprocessed. +uint SoundTouch::numUnprocessedSamples() const +{ + FIFOSamplePipe * psp; + if (pTDStretch) + { + psp = pTDStretch->getInput(); + if (psp) + { + return psp->numSamples(); + } + } + return 0; +} diff --git a/plugins/zerospu2/3rdparty/SoundTouch/SoundTouch.h b/plugins/zerospu2/3rdparty/SoundTouch/SoundTouch.h index fab3bb9845..9f3a152f26 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/SoundTouch.h +++ b/plugins/zerospu2/3rdparty/SoundTouch/SoundTouch.h @@ -1,252 +1,252 @@ -////////////////////////////////////////////////////////////////////////////// -/// -/// SoundTouch - main class for tempo/pitch/rate adjusting routines. -/// -/// Notes: -/// - Initialize the SoundTouch object instance by setting up the sound stream -/// parameters with functions 'setSampleRate' and 'setChannels', then set -/// desired tempo/pitch/rate settings with the corresponding functions. -/// -/// - The SoundTouch class behaves like a first-in-first-out pipeline: The -/// samples that are to be processed are fed into one of the pipe by calling -/// function 'putSamples', while the ready processed samples can be read -/// from the other end of the pipeline with function 'receiveSamples'. -/// -/// - The SoundTouch processing classes require certain sized 'batches' of -/// samples in order to process the sound. For this reason the classes buffer -/// incoming samples until there are enough of samples available for -/// processing, then they carry out the processing step and consequently -/// make the processed samples available for outputting. -/// -/// - For the above reason, the processing routines introduce a certain -/// 'latency' between the input and output, so that the samples input to -/// SoundTouch may not be immediately available in the output, and neither -/// the amount of outputtable samples may not immediately be in direct -/// relationship with the amount of previously input samples. -/// -/// - The tempo/pitch/rate control parameters can be altered during processing. -/// Please notice though that they aren't currently protected by semaphores, -/// so in multi-thread application external semaphore protection may be -/// required. -/// -/// - This class utilizes classes 'TDStretch' for tempo change (without modifying -/// pitch) and 'RateTransposer' for changing the playback rate (that is, both -/// tempo and pitch in the same ratio) of the sound. The third available control -/// 'pitch' (change pitch but maintain tempo) is produced by a combination of -/// combining the two other controls. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.14 $ -// -// $Id: SoundTouch.h,v 1.14 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef SoundTouch_H -#define SoundTouch_H - -#include "FIFOSamplePipe.h" -#include "STTypes.h" - -namespace soundtouch -{ - -/// Soundtouch library version string -#define SOUNDTOUCH_VERSION "1.3.1" - -/// SoundTouch library version id -#define SOUNDTOUCH_VERSION_ID 010301 - -// -// Available setting IDs for the 'setSetting' & 'get_setting' functions: - -/// Enable/disable anti-alias filter in pitch transposer (0 = disable) -#define SETTING_USE_AA_FILTER 0 - -/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32) -#define SETTING_AA_FILTER_LENGTH 1 - -/// Enable/disable quick seeking algorithm in tempo changer routine -/// (enabling quick seeking lowers CPU utilization but causes a minor sound -/// quality compromising) -#define SETTING_USE_QUICKSEEK 2 - -/// Time-stretch algorithm single processing sequence length in milliseconds. This determines -/// to how long sequences the original sound is chopped in the time-stretch algorithm. -/// See "STTypes.h" or README for more information. -#define SETTING_SEQUENCE_MS 3 - -/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the -/// best possible overlapping location. This determines from how wide window the algorithm -/// may look for an optimal joining location when mixing the sound sequences back together. -/// See "STTypes.h" or README for more information. -#define SETTING_SEEKWINDOW_MS 4 - -/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences -/// are mixed back together, to form a continuous sound stream, this parameter defines over -/// how long period the two consecutive sequences are let to overlap each other. -/// See "STTypes.h" or README for more information. -#define SETTING_OVERLAP_MS 5 - - -class SoundTouch : public FIFOProcessor -{ -private: - /// Rate transposer class instance - class RateTransposer *pRateTransposer; - - /// Time-stretch class instance - class TDStretch *pTDStretch; - - /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. - float virtualRate; - - /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. - float virtualTempo; - - /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. - float virtualPitch; - - /// Flag: Has sample rate been set? - BOOL bSrateSet; - - /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and - /// 'virtualPitch' parameters. - void calcEffectiveRateAndTempo(); - -protected : - /// Number of channels - uint channels; - - /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' - float rate; - - /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' - float tempo; - -public: - SoundTouch(); - virtual ~SoundTouch(); - - /// Get SoundTouch library version string - static const char *getVersionString(); - - /// Get SoundTouch library version Id - static uint getVersionId(); - - /// Sets new rate control value. Normal rate = 1.0, smaller values - /// represent slower rate, larger faster rates. - void setRate(float newRate); - - /// Sets new tempo control value. Normal tempo = 1.0, smaller values - /// represent slower tempo, larger faster tempo. - void setTempo(float newTempo); - - /// Sets new rate control value as a difference in percents compared - /// to the original rate (-50 .. +100 %) - void setRateChange(float newRate); - - /// Sets new tempo control value as a difference in percents compared - /// to the original tempo (-50 .. +100 %) - void setTempoChange(float newTempo); - - /// Sets new pitch control value. Original pitch = 1.0, smaller values - /// represent lower pitches, larger values higher pitch. - void setPitch(float newPitch); - - /// Sets pitch change in octaves compared to the original pitch - /// (-1.00 .. +1.00) - void setPitchOctaves(float newPitch); - - /// Sets pitch change in semi-tones compared to the original pitch - /// (-12 .. +12) - void setPitchSemiTones(int newPitch); - void setPitchSemiTones(float newPitch); - - /// Sets the number of channels, 1 = mono, 2 = stereo - void setChannels(uint numChannels); - - /// Sets sample rate. - void setSampleRate(uint srate); - - /// Flushes the last samples from the processing pipeline to the output. - /// Clears also the internal processing buffers. - // - /// Note: This function is meant for extracting the last samples of a sound - /// stream. This function may introduce additional blank samples in the end - /// of the sound stream, and thus it's not recommended to call this function - /// in the middle of a sound stream. - void flush(); - - /// Adds 'numSamples' pcs of samples from the 'samples' memory position into - /// the input of the object. Notice that sample rate _has_to_ be set before - /// calling this function, otherwise throws a runtime_error exception. - virtual void putSamples( - const SAMPLETYPE *samples, ///< Pointer to sample buffer. - uint numSamples ///< Number of samples in buffer. Notice - ///< that in case of stereo-sound a single sample - ///< contains data for both channels. - ); - - /// Clears all the samples in the object's output and internal processing - /// buffers. - virtual void clear(); - - /// Changes a setting controlling the processing system behaviour. See the - /// 'SETTING_...' defines for available setting ID's. - /// - /// \return 'TRUE' if the setting was succesfully changed - BOOL setSetting(uint settingId, ///< Setting ID number. see SETTING_... defines. - uint value ///< New setting value. - ); - - /// Reads a setting controlling the processing system behaviour. See the - /// 'SETTING_...' defines for available setting ID's. - /// - /// \return the setting value. - uint getSetting(uint settingId ///< Setting ID number, see SETTING_... defines. - ) const; - - /// Returns number of samples currently unprocessed. - virtual uint numUnprocessedSamples() const; - - - /// Other handy functions that are implemented in the ancestor classes (see - /// classes 'FIFOProcessor' and 'FIFOSamplePipe') - /// - /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch. - /// - numSamples() : Get number of 'ready' samples that can be received with - /// function 'receiveSamples()' - /// - isEmpty() : Returns nonzero if there aren't any 'ready' samples. - /// - clear() : Clears all samples from ready/processing buffers. -}; - -} -#endif +////////////////////////////////////////////////////////////////////////////// +/// +/// SoundTouch - main class for tempo/pitch/rate adjusting routines. +/// +/// Notes: +/// - Initialize the SoundTouch object instance by setting up the sound stream +/// parameters with functions 'setSampleRate' and 'setChannels', then set +/// desired tempo/pitch/rate settings with the corresponding functions. +/// +/// - The SoundTouch class behaves like a first-in-first-out pipeline: The +/// samples that are to be processed are fed into one of the pipe by calling +/// function 'putSamples', while the ready processed samples can be read +/// from the other end of the pipeline with function 'receiveSamples'. +/// +/// - The SoundTouch processing classes require certain sized 'batches' of +/// samples in order to process the sound. For this reason the classes buffer +/// incoming samples until there are enough of samples available for +/// processing, then they carry out the processing step and consequently +/// make the processed samples available for outputting. +/// +/// - For the above reason, the processing routines introduce a certain +/// 'latency' between the input and output, so that the samples input to +/// SoundTouch may not be immediately available in the output, and neither +/// the amount of outputtable samples may not immediately be in direct +/// relationship with the amount of previously input samples. +/// +/// - The tempo/pitch/rate control parameters can be altered during processing. +/// Please notice though that they aren't currently protected by semaphores, +/// so in multi-thread application external semaphore protection may be +/// required. +/// +/// - This class utilizes classes 'TDStretch' for tempo change (without modifying +/// pitch) and 'RateTransposer' for changing the playback rate (that is, both +/// tempo and pitch in the same ratio) of the sound. The third available control +/// 'pitch' (change pitch but maintain tempo) is produced by a combination of +/// combining the two other controls. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.14 $ +// +// $Id: SoundTouch.h,v 1.14 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef SoundTouch_H +#define SoundTouch_H + +#include "FIFOSamplePipe.h" +#include "STTypes.h" + +namespace soundtouch +{ + +/// Soundtouch library version string +#define SOUNDTOUCH_VERSION "1.3.1" + +/// SoundTouch library version id +#define SOUNDTOUCH_VERSION_ID 010301 + +// +// Available setting IDs for the 'setSetting' & 'get_setting' functions: + +/// Enable/disable anti-alias filter in pitch transposer (0 = disable) +#define SETTING_USE_AA_FILTER 0 + +/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32) +#define SETTING_AA_FILTER_LENGTH 1 + +/// Enable/disable quick seeking algorithm in tempo changer routine +/// (enabling quick seeking lowers CPU utilization but causes a minor sound +/// quality compromising) +#define SETTING_USE_QUICKSEEK 2 + +/// Time-stretch algorithm single processing sequence length in milliseconds. This determines +/// to how long sequences the original sound is chopped in the time-stretch algorithm. +/// See "STTypes.h" or README for more information. +#define SETTING_SEQUENCE_MS 3 + +/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the +/// best possible overlapping location. This determines from how wide window the algorithm +/// may look for an optimal joining location when mixing the sound sequences back together. +/// See "STTypes.h" or README for more information. +#define SETTING_SEEKWINDOW_MS 4 + +/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences +/// are mixed back together, to form a continuous sound stream, this parameter defines over +/// how long period the two consecutive sequences are let to overlap each other. +/// See "STTypes.h" or README for more information. +#define SETTING_OVERLAP_MS 5 + + +class SoundTouch : public FIFOProcessor +{ +private: + /// Rate transposer class instance + class RateTransposer *pRateTransposer; + + /// Time-stretch class instance + class TDStretch *pTDStretch; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualRate; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualTempo; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualPitch; + + /// Flag: Has sample rate been set? + BOOL bSrateSet; + + /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and + /// 'virtualPitch' parameters. + void calcEffectiveRateAndTempo(); + +protected : + /// Number of channels + uint channels; + + /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' + float rate; + + /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' + float tempo; + +public: + SoundTouch(); + virtual ~SoundTouch(); + + /// Get SoundTouch library version string + static const char *getVersionString(); + + /// Get SoundTouch library version Id + static uint getVersionId(); + + /// Sets new rate control value. Normal rate = 1.0, smaller values + /// represent slower rate, larger faster rates. + void setRate(float newRate); + + /// Sets new tempo control value. Normal tempo = 1.0, smaller values + /// represent slower tempo, larger faster tempo. + void setTempo(float newTempo); + + /// Sets new rate control value as a difference in percents compared + /// to the original rate (-50 .. +100 %) + void setRateChange(float newRate); + + /// Sets new tempo control value as a difference in percents compared + /// to the original tempo (-50 .. +100 %) + void setTempoChange(float newTempo); + + /// Sets new pitch control value. Original pitch = 1.0, smaller values + /// represent lower pitches, larger values higher pitch. + void setPitch(float newPitch); + + /// Sets pitch change in octaves compared to the original pitch + /// (-1.00 .. +1.00) + void setPitchOctaves(float newPitch); + + /// Sets pitch change in semi-tones compared to the original pitch + /// (-12 .. +12) + void setPitchSemiTones(int newPitch); + void setPitchSemiTones(float newPitch); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint numChannels); + + /// Sets sample rate. + void setSampleRate(uint srate); + + /// Flushes the last samples from the processing pipeline to the output. + /// Clears also the internal processing buffers. + // + /// Note: This function is meant for extracting the last samples of a sound + /// stream. This function may introduce additional blank samples in the end + /// of the sound stream, and thus it's not recommended to call this function + /// in the middle of a sound stream. + void flush(); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position into + /// the input of the object. Notice that sample rate _has_to_ be set before + /// calling this function, otherwise throws a runtime_error exception. + virtual void putSamples( + const SAMPLETYPE *samples, ///< Pointer to sample buffer. + uint numSamples ///< Number of samples in buffer. Notice + ///< that in case of stereo-sound a single sample + ///< contains data for both channels. + ); + + /// Clears all the samples in the object's output and internal processing + /// buffers. + virtual void clear(); + + /// Changes a setting controlling the processing system behaviour. See the + /// 'SETTING_...' defines for available setting ID's. + /// + /// \return 'TRUE' if the setting was succesfully changed + BOOL setSetting(uint settingId, ///< Setting ID number. see SETTING_... defines. + uint value ///< New setting value. + ); + + /// Reads a setting controlling the processing system behaviour. See the + /// 'SETTING_...' defines for available setting ID's. + /// + /// \return the setting value. + uint getSetting(uint settingId ///< Setting ID number, see SETTING_... defines. + ) const; + + /// Returns number of samples currently unprocessed. + virtual uint numUnprocessedSamples() const; + + + /// Other handy functions that are implemented in the ancestor classes (see + /// classes 'FIFOProcessor' and 'FIFOSamplePipe') + /// + /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch. + /// - numSamples() : Get number of 'ready' samples that can be received with + /// function 'receiveSamples()' + /// - isEmpty() : Returns nonzero if there aren't any 'ready' samples. + /// - clear() : Clears all samples from ready/processing buffers. +}; + +} +#endif diff --git a/plugins/zerospu2/3rdparty/SoundTouch/TDStretch.cpp b/plugins/zerospu2/3rdparty/SoundTouch/TDStretch.cpp index d809623689..339c7378fb 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/TDStretch.cpp +++ b/plugins/zerospu2/3rdparty/SoundTouch/TDStretch.cpp @@ -1,940 +1,940 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo -/// while maintaining the original pitch by using a time domain WSOLA-like -/// method with several performance-increasing tweaks. -/// -/// Note : MMX optimized functions reside in a separate, platform-specific -/// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.24 $ -// -// $Id: TDStretch.cpp,v 1.24 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include - -#include "STTypes.h" -#include "cpu_detect.h" -#include "TDStretch.h" - -using namespace soundtouch; - -#ifndef min -#define min(a,b) ((a > b) ? b : a) -#define max(a,b) ((a < b) ? b : a) -#endif - - - -/***************************************************************************** - * - * Constant definitions - * - *****************************************************************************/ - - -// Table for the hierarchical mixing position seeking algorithm -int scanOffsets[4][24]={ - { 124, 186, 248, 310, 372, 434, 496, 558, 620, 682, 744, 806, - 868, 930, 992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488, 0}, - {-100, -75, -50, -25, 25, 50, 75, 100, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { -20, -15, -10, -5, 5, 10, 15, 20, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { -4, -3, -2, -1, 1, 2, 3, 4, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; - -/***************************************************************************** - * - * Implementation of the class 'TDStretch' - * - *****************************************************************************/ - - -TDStretch::TDStretch() : FIFOProcessor(&outputBuffer) -{ - bQuickseek = FALSE; - channels = 2; - bMidBufferDirty = FALSE; - - pMidBuffer = NULL; - pRefMidBufferUnaligned = NULL; - overlapLength = 0; - - setParameters(48000, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS); - - setTempo(1.0f); -} - - - - -TDStretch::~TDStretch() -{ - delete[] pMidBuffer; - delete[] pRefMidBufferUnaligned; -} - - - -// Calculates the x having the closest 2^x value for the given value -static int _getClosest2Power(double value) -{ - return (int)(log(value) / log(2.0) + 0.5); -} - - - -// Sets routine control parameters. These control are certain time constants -// defining how the sound is stretched to the desired duration. -// -// 'sampleRate' = sample rate of the sound -// 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms) -// 'seekwindowMS' = seeking window length for scanning the best overlapping -// position (default = 28 ms) -// 'overlapMS' = overlapping length (default = 12 ms) - -void TDStretch::setParameters(uint aSampleRate, uint aSequenceMS, - uint aSeekWindowMS, uint aOverlapMS) -{ - this->sampleRate = aSampleRate; - this->sequenceMs = aSequenceMS; - this->seekWindowMs = aSeekWindowMS; - this->overlapMs = aOverlapMS; - - seekLength = (sampleRate * seekWindowMs) / 1000; - seekWindowLength = (sampleRate * sequenceMs) / 1000; - - maxOffset = seekLength; - - calculateOverlapLength(overlapMs); - - // set tempo to recalculate 'sampleReq' - setTempo(tempo); - -} - - - -/// Get routine control parameters, see setParameters() function. -/// Any of the parameters to this function can be NULL, in such case corresponding parameter -/// value isn't returned. -void TDStretch::getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs) -{ - if (pSampleRate) - { - *pSampleRate = sampleRate; - } - - if (pSequenceMs) - { - *pSequenceMs = sequenceMs; - } - - if (pSeekWindowMs) - { - *pSeekWindowMs = seekWindowMs; - } - - if (pOverlapMs) - { - *pOverlapMs = overlapMs; - } -} - - -// Overlaps samples in 'midBuffer' with the samples in 'input' -void TDStretch::overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const -{ - int i, itemp; - - for (i = 0; i < (int)overlapLength ; i ++) - { - itemp = overlapLength - i; - output[i] = (input[i] * i + pMidBuffer[i] * itemp ) / overlapLength; // >> overlapDividerBits; - } -} - - - -void TDStretch::clearMidBuffer() -{ - if (bMidBufferDirty) - { - memset(pMidBuffer, 0, 2 * sizeof(SAMPLETYPE) * overlapLength); - bMidBufferDirty = FALSE; - } -} - - -void TDStretch::clearInput() -{ - inputBuffer.clear(); - clearMidBuffer(); -} - - -// Clears the sample buffers -void TDStretch::clear() -{ - outputBuffer.clear(); - inputBuffer.clear(); - clearMidBuffer(); -} - - - -// Enables/disables the quick position seeking algorithm. Zero to disable, nonzero -// to enable -void TDStretch::enableQuickSeek(BOOL enable) -{ - bQuickseek = enable; -} - - -// Returns nonzero if the quick seeking algorithm is enabled. -BOOL TDStretch::isQuickSeekEnabled() const -{ - return bQuickseek; -} - - -// Seeks for the optimal overlap-mixing position. -uint TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos) -{ - if (channels == 2) - { - // stereo sound - if (bQuickseek) - { - return seekBestOverlapPositionStereoQuick(refPos); - } - else - { - return seekBestOverlapPositionStereo(refPos); - } - } - else - { - // mono sound - if (bQuickseek) - { - return seekBestOverlapPositionMonoQuick(refPos); - } - else - { - return seekBestOverlapPositionMono(refPos); - } - } -} - - - - -// Overlaps samples in 'midBuffer' with the samples in 'inputBuffer' at position -// of 'ovlPos'. -inline void TDStretch::overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const -{ - if (channels == 2) - { - // stereo sound - overlapStereo(output, input + 2 * ovlPos); - } else { - // mono sound. - overlapMono(output, input + ovlPos); - } -} - - - - -// Seeks for the optimal overlap-mixing position. The 'stereo' version of the -// routine -// -// The best position is determined as the position where the two overlapped -// sample sequences are 'most alike', in terms of the highest cross-correlation -// value over the overlapping period -uint TDStretch::seekBestOverlapPositionStereo(const SAMPLETYPE *refPos) -{ - uint bestOffs; - LONG_SAMPLETYPE bestCorr, corr; - uint i; - - // Slopes the amplitudes of the 'midBuffer' samples - precalcCorrReferenceStereo(); - - bestCorr = INT_MIN; - bestOffs = 0; - - // Scans for the best correlation value by testing each possible position - // over the permitted range. - for (i = 0; i < seekLength; i ++) - { - // Calculates correlation value for the mixing position corresponding - // to 'i' - corr = calcCrossCorrStereo(refPos + 2 * i, pRefMidBuffer); - - // Checks for the highest correlation value - if (corr > bestCorr) - { - bestCorr = corr; - bestOffs = i; - } - } - // clear cross correlation routine state if necessary (is so e.g. in MMX routines). - clearCrossCorrState(); - - return bestOffs; -} - - -// Seeks for the optimal overlap-mixing position. The 'stereo' version of the -// routine -// -// The best position is determined as the position where the two overlapped -// sample sequences are 'most alike', in terms of the highest cross-correlation -// value over the overlapping period -uint TDStretch::seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos) -{ - uint j; - uint bestOffs; - LONG_SAMPLETYPE bestCorr, corr; - uint scanCount, corrOffset, tempOffset; - - // Slopes the amplitude of the 'midBuffer' samples - precalcCorrReferenceStereo(); - - bestCorr = INT_MIN; - bestOffs = 0; - corrOffset = 0; - tempOffset = 0; - - // Scans for the best correlation value using four-pass hierarchical search. - // - // The look-up table 'scans' has hierarchical position adjusting steps. - // In first pass the routine searhes for the highest correlation with - // relatively coarse steps, then rescans the neighbourhood of the highest - // correlation with better resolution and so on. - for (scanCount = 0;scanCount < 4; scanCount ++) - { - j = 0; - while (scanOffsets[scanCount][j]) - { - tempOffset = corrOffset + scanOffsets[scanCount][j]; - if (tempOffset >= seekLength) break; - - // Calculates correlation value for the mixing position corresponding - // to 'tempOffset' - corr = calcCrossCorrStereo(refPos + 2 * tempOffset, pRefMidBuffer); - - // Checks for the highest correlation value - if (corr > bestCorr) - { - bestCorr = corr; - bestOffs = tempOffset; - } - j ++; - } - corrOffset = bestOffs; - } - // clear cross correlation routine state if necessary (is so e.g. in MMX routines). - clearCrossCorrState(); - - return bestOffs; -} - - - -// Seeks for the optimal overlap-mixing position. The 'mono' version of the -// routine -// -// The best position is determined as the position where the two overlapped -// sample sequences are 'most alike', in terms of the highest cross-correlation -// value over the overlapping period -uint TDStretch::seekBestOverlapPositionMono(const SAMPLETYPE *refPos) -{ - uint bestOffs; - LONG_SAMPLETYPE bestCorr, corr; - uint tempOffset; - const SAMPLETYPE *compare; - - // Slopes the amplitude of the 'midBuffer' samples - precalcCorrReferenceMono(); - - bestCorr = INT_MIN; - bestOffs = 0; - - // Scans for the best correlation value by testing each possible position - // over the permitted range. - for (tempOffset = 0; tempOffset < seekLength; tempOffset ++) - { - compare = refPos + tempOffset; - - // Calculates correlation value for the mixing position corresponding - // to 'tempOffset' - corr = calcCrossCorrMono(pRefMidBuffer, compare); - - // Checks for the highest correlation value - if (corr > bestCorr) - { - bestCorr = corr; - bestOffs = tempOffset; - } - } - // clear cross correlation routine state if necessary (is so e.g. in MMX routines). - clearCrossCorrState(); - - return bestOffs; -} - - -// Seeks for the optimal overlap-mixing position. The 'mono' version of the -// routine -// -// The best position is determined as the position where the two overlapped -// sample sequences are 'most alike', in terms of the highest cross-correlation -// value over the overlapping period -uint TDStretch::seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos) -{ - uint j; - uint bestOffs; - LONG_SAMPLETYPE bestCorr, corr; - uint scanCount, corrOffset, tempOffset; - - // Slopes the amplitude of the 'midBuffer' samples - precalcCorrReferenceMono(); - - bestCorr = INT_MIN; - bestOffs = 0; - corrOffset = 0; - tempOffset = 0; - - // Scans for the best correlation value using four-pass hierarchical search. - // - // The look-up table 'scans' has hierarchical position adjusting steps. - // In first pass the routine searhes for the highest correlation with - // relatively coarse steps, then rescans the neighbourhood of the highest - // correlation with better resolution and so on. - for (scanCount = 0;scanCount < 4; scanCount ++) - { - j = 0; - while (scanOffsets[scanCount][j]) - { - tempOffset = corrOffset + scanOffsets[scanCount][j]; - if (tempOffset >= seekLength) break; - - // Calculates correlation value for the mixing position corresponding - // to 'tempOffset' - corr = calcCrossCorrMono(refPos + tempOffset, pRefMidBuffer); - - // Checks for the highest correlation value - if (corr > bestCorr) - { - bestCorr = corr; - bestOffs = tempOffset; - } - j ++; - } - corrOffset = bestOffs; - } - // clear cross correlation routine state if necessary (is so e.g. in MMX routines). - clearCrossCorrState(); - - return bestOffs; -} - - -/// clear cross correlation routine state if necessary -void TDStretch::clearCrossCorrState() -{ - // default implementation is empty. -} - - -// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower -// tempo, larger faster tempo. -void TDStretch::setTempo(float newTempo) -{ - uint intskip; - - tempo = newTempo; - - // Calculate ideal skip length (according to tempo value) - nominalSkip = tempo * (seekWindowLength - overlapLength); - skipFract = 0; - intskip = (int)(nominalSkip + 0.5f); - - // Calculate how many samples are needed in the 'inputBuffer' to - // process another batch of samples - sampleReq = max(intskip + overlapLength, seekWindowLength) + maxOffset; -} - - - -// Sets the number of channels, 1 = mono, 2 = stereo -void TDStretch::setChannels(uint numChannels) -{ - if (channels == numChannels) return; - assert(numChannels == 1 || numChannels == 2); - - channels = numChannels; - inputBuffer.setChannels(channels); - outputBuffer.setChannels(channels); -} - - -// nominal tempo, no need for processing, just pass the samples through -// to outputBuffer -void TDStretch::processNominalTempo() -{ - assert(tempo == 1.0f); - - if (bMidBufferDirty) - { - // If there are samples in pMidBuffer waiting for overlapping, - // do a single sliding overlapping with them in order to prevent a - // clicking distortion in the output sound - if (inputBuffer.numSamples() < overlapLength) - { - // wait until we've got overlapLength input samples - return; - } - // Mix the samples in the beginning of 'inputBuffer' with the - // samples in 'midBuffer' using sliding overlapping - overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0); - outputBuffer.putSamples(overlapLength); - inputBuffer.receiveSamples(overlapLength); - clearMidBuffer(); - // now we've caught the nominal sample flow and may switch to - // bypass mode - } - - // Simply bypass samples from input to output - outputBuffer.moveSamples(inputBuffer); -} - - -// Processes as many processing frames of the samples 'inputBuffer', store -// the result into 'outputBuffer' -void TDStretch::processSamples() -{ - uint ovlSkip, offset; - int temp; - - /* Removed this small optimization - can introduce a click to sound when tempo setting - crosses the nominal value - if (tempo == 1.0f) - { - // tempo not changed from the original, so bypass the processing - processNominalTempo(); - return; - } - */ - - if (bMidBufferDirty == FALSE) - { - // if midBuffer is empty, move the first samples of the input stream - // into it - if (inputBuffer.numSamples() < overlapLength) - { - // wait until we've got overlapLength samples - return; - } - memcpy(pMidBuffer, inputBuffer.ptrBegin(), channels * overlapLength * sizeof(SAMPLETYPE)); - inputBuffer.receiveSamples(overlapLength); - bMidBufferDirty = TRUE; - } - - // Process samples as long as there are enough samples in 'inputBuffer' - // to form a processing frame. - while (inputBuffer.numSamples() >= sampleReq) - { - // If tempo differs from the normal ('SCALE'), scan for the best overlapping - // position - offset = seekBestOverlapPosition(inputBuffer.ptrBegin()); - - // Mix the samples in the 'inputBuffer' at position of 'offset' with the - // samples in 'midBuffer' using sliding overlapping - // ... first partially overlap with the end of the previous sequence - // (that's in 'midBuffer') - overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), offset); - outputBuffer.putSamples(overlapLength); - - // ... then copy sequence samples from 'inputBuffer' to output - temp = (seekWindowLength - 2 * overlapLength);// & 0xfffffffe; - if (temp > 0) - { - outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * (offset + overlapLength), temp); - } - - // Copies the end of the current sequence from 'inputBuffer' to - // 'midBuffer' for being mixed with the beginning of the next - // processing sequence and so on - assert(offset + seekWindowLength <= inputBuffer.numSamples()); - memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + seekWindowLength - overlapLength), - channels * sizeof(SAMPLETYPE) * overlapLength); - bMidBufferDirty = TRUE; - - // Remove the processed samples from the input buffer. Update - // the difference between integer & nominal skip step to 'skipFract' - // in order to prevent the error from accumulating over time. - skipFract += nominalSkip; // real skip size - ovlSkip = (int)skipFract; // rounded to integer skip - skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip - inputBuffer.receiveSamples(ovlSkip); - } -} - - -// Adds 'numsamples' pcs of samples from the 'samples' memory position into -// the input of the object. -void TDStretch::putSamples(const SAMPLETYPE *samples, uint numSamples) -{ - // Add the samples into the input buffer - inputBuffer.putSamples(samples, numSamples); - // Process the samples in input buffer - processSamples(); -} - - - -/// Set new overlap length parameter & reallocate RefMidBuffer if necessary. -void TDStretch::acceptNewOverlapLength(uint newOverlapLength) -{ - uint prevOvl; - - prevOvl = overlapLength; - overlapLength = newOverlapLength; - - if (overlapLength > prevOvl) - { - delete[] pMidBuffer; - delete[] pRefMidBufferUnaligned; - - pMidBuffer = new SAMPLETYPE[overlapLength * 2]; - bMidBufferDirty = TRUE; - clearMidBuffer(); - - pRefMidBufferUnaligned = new SAMPLETYPE[2 * overlapLength + 16 / sizeof(SAMPLETYPE)]; - // ensure that 'pRefMidBuffer' is aligned to 16 byte boundary for efficiency - pRefMidBuffer = (SAMPLETYPE *)((((ulongptr)pRefMidBufferUnaligned) + 15) & -16); - } -} - - -// Operator 'new' is overloaded so that it automatically creates a suitable instance -// depending on if we've a MMX/SSE/etc-capable CPU available or not. -void * TDStretch::operator new(size_t s) -{ - // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! - assert(FALSE); - return NULL; -} - - -TDStretch * TDStretch::newInstance() -{ - uint uExtensions = 0; - -#if !defined(_MSC_VER) || !defined(__x86_64__) - uExtensions = detectCPUextensions(); -#endif - - // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU - -#ifdef ALLOW_MMX - // MMX routines available only with integer sample types - if (uExtensions & SUPPORT_MMX) - { - return ::new TDStretchMMX; - } - else -#endif // ALLOW_MMX - - -#ifdef ALLOW_SSE - if (uExtensions & SUPPORT_SSE) - { - // SSE support - return ::new TDStretchSSE; - } - else -#endif // ALLOW_SSE - - -#ifdef ALLOW_3DNOW - if (uExtensions & SUPPORT_3DNOW) - { - // 3DNow! support - return ::new TDStretch3DNow; - } - else -#endif // ALLOW_3DNOW - - { - // ISA optimizations not supported, use plain C version - return ::new TDStretch; - } -} - - -////////////////////////////////////////////////////////////////////////////// -// -// Integer arithmetics specific algorithm implementations. -// -////////////////////////////////////////////////////////////////////////////// - -#ifdef INTEGER_SAMPLES - -// Slopes the amplitude of the 'midBuffer' samples so that cross correlation -// is faster to calculate -void TDStretch::precalcCorrReferenceStereo() -{ - int i, cnt2; - int temp, temp2; - - for (i=0 ; i < (int)overlapLength ;i ++) - { - temp = i * (overlapLength - i); - cnt2 = i * 2; - - temp2 = (pMidBuffer[cnt2] * temp) / slopingDivider; - pRefMidBuffer[cnt2] = (short)(temp2); - temp2 = (pMidBuffer[cnt2 + 1] * temp) / slopingDivider; - pRefMidBuffer[cnt2 + 1] = (short)(temp2); - } -} - - -// Slopes the amplitude of the 'midBuffer' samples so that cross correlation -// is faster to calculate -void TDStretch::precalcCorrReferenceMono() -{ - int i; - long temp; - long temp2; - - for (i=0 ; i < (int)overlapLength ;i ++) - { - temp = i * (overlapLength - i); - temp2 = (pMidBuffer[i] * temp) / slopingDivider; - pRefMidBuffer[i] = (short)temp2; - } -} - - -// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo' -// version of the routine. -void TDStretch::overlapStereo(short *output, const short *input) const -{ - int i; - short temp; - uint cnt2; - - for (i = 0; i < (int)overlapLength ; i ++) - { - temp = (short)(overlapLength - i); - cnt2 = 2 * i; - output[cnt2] = (input[cnt2] * i + pMidBuffer[cnt2] * temp ) / overlapLength; - output[cnt2 + 1] = (input[cnt2 + 1] * i + pMidBuffer[cnt2 + 1] * temp ) / overlapLength; - } -} - - -/// Calculates overlap period length in samples. -/// Integer version rounds overlap length to closest power of 2 -/// for a divide scaling operation. -void TDStretch::calculateOverlapLength(uint overlapMs) -{ - uint newOvl; - - overlapDividerBits = _getClosest2Power((sampleRate * overlapMs) / 1000.0); - if (overlapDividerBits > 9) overlapDividerBits = 9; - if (overlapDividerBits < 4) overlapDividerBits = 4; - newOvl = 1<> overlapDividerBits; - } - - return corr; -} - - -long TDStretch::calcCrossCorrStereo(const short *mixingPos, const short *compare) const -{ - long corr; - uint i; - - corr = 0; - for (i = 2; i < 2 * overlapLength; i += 2) - { - corr += (mixingPos[i] * compare[i] + - mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBits; - } - - return corr; -} - -#endif // INTEGER_SAMPLES - -////////////////////////////////////////////////////////////////////////////// -// -// Floating point arithmetics specific algorithm implementations. -// - -#ifdef FLOAT_SAMPLES - - -// Slopes the amplitude of the 'midBuffer' samples so that cross correlation -// is faster to calculate -void TDStretch::precalcCorrReferenceStereo() -{ - int i, cnt2; - float temp; - - for (i=0 ; i < (int)overlapLength ;i ++) - { - temp = (float)i * (float)(overlapLength - i); - cnt2 = i * 2; - pRefMidBuffer[cnt2] = (float)(pMidBuffer[cnt2] * temp); - pRefMidBuffer[cnt2 + 1] = (float)(pMidBuffer[cnt2 + 1] * temp); - } -} - - -// Slopes the amplitude of the 'midBuffer' samples so that cross correlation -// is faster to calculate -void TDStretch::precalcCorrReferenceMono() -{ - int i; - float temp; - - for (i=0 ; i < (int)overlapLength ;i ++) - { - temp = (float)i * (float)(overlapLength - i); - pRefMidBuffer[i] = (float)(pMidBuffer[i] * temp); - } -} - - -// SSE-optimized version of the function overlapStereo -void TDStretch::overlapStereo(float *output, const float *input) const -{ - int i; - uint cnt2; - float fTemp; - float fScale; - float fi; - - fScale = 1.0f / (float)overlapLength; - - for (i = 0; i < (int)overlapLength ; i ++) - { - fTemp = (float)(overlapLength - i) * fScale; - fi = (float)i * fScale; - cnt2 = 2 * i; - output[cnt2 + 0] = input[cnt2 + 0] * fi + pMidBuffer[cnt2 + 0] * fTemp; - output[cnt2 + 1] = input[cnt2 + 1] * fi + pMidBuffer[cnt2 + 1] * fTemp; - } -} - - -/// Calculates overlap period length in samples. -void TDStretch::calculateOverlapLength(uint overlapMs) -{ - uint newOvl; - - newOvl = (sampleRate * overlapMs) / 1000; - if (newOvl < 16) newOvl = 16; - - // must be divisible by 8 - newOvl -= newOvl % 8; - - acceptNewOverlapLength(newOvl); -} - - - -double TDStretch::calcCrossCorrMono(const float *mixingPos, const float *compare) const -{ - double corr; - uint i; - - corr = 0; - for (i = 1; i < overlapLength; i ++) - { - corr += mixingPos[i] * compare[i]; - } - - return corr; -} - - -double TDStretch::calcCrossCorrStereo(const float *mixingPos, const float *compare) const -{ - double corr; - uint i; - - corr = 0; - for (i = 2; i < 2 * overlapLength; i += 2) - { - corr += mixingPos[i] * compare[i] + - mixingPos[i + 1] * compare[i + 1]; - } - - return corr; -} - -#endif // FLOAT_SAMPLES +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like +/// method with several performance-increasing tweaks. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific +/// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.24 $ +// +// $Id: TDStretch.cpp,v 1.24 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include "STTypes.h" +#include "cpu_detect.h" +#include "TDStretch.h" + +using namespace soundtouch; + +#ifndef min +#define min(a,b) ((a > b) ? b : a) +#define max(a,b) ((a < b) ? b : a) +#endif + + + +/***************************************************************************** + * + * Constant definitions + * + *****************************************************************************/ + + +// Table for the hierarchical mixing position seeking algorithm +int scanOffsets[4][24]={ + { 124, 186, 248, 310, 372, 434, 496, 558, 620, 682, 744, 806, + 868, 930, 992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488, 0}, + {-100, -75, -50, -25, 25, 50, 75, 100, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { -20, -15, -10, -5, 5, 10, 15, 20, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { -4, -3, -2, -1, 1, 2, 3, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; + +/***************************************************************************** + * + * Implementation of the class 'TDStretch' + * + *****************************************************************************/ + + +TDStretch::TDStretch() : FIFOProcessor(&outputBuffer) +{ + bQuickseek = FALSE; + channels = 2; + bMidBufferDirty = FALSE; + + pMidBuffer = NULL; + pRefMidBufferUnaligned = NULL; + overlapLength = 0; + + setParameters(48000, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS); + + setTempo(1.0f); +} + + + + +TDStretch::~TDStretch() +{ + delete[] pMidBuffer; + delete[] pRefMidBufferUnaligned; +} + + + +// Calculates the x having the closest 2^x value for the given value +static int _getClosest2Power(double value) +{ + return (int)(log(value) / log(2.0) + 0.5); +} + + + +// Sets routine control parameters. These control are certain time constants +// defining how the sound is stretched to the desired duration. +// +// 'sampleRate' = sample rate of the sound +// 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms) +// 'seekwindowMS' = seeking window length for scanning the best overlapping +// position (default = 28 ms) +// 'overlapMS' = overlapping length (default = 12 ms) + +void TDStretch::setParameters(uint aSampleRate, uint aSequenceMS, + uint aSeekWindowMS, uint aOverlapMS) +{ + this->sampleRate = aSampleRate; + this->sequenceMs = aSequenceMS; + this->seekWindowMs = aSeekWindowMS; + this->overlapMs = aOverlapMS; + + seekLength = (sampleRate * seekWindowMs) / 1000; + seekWindowLength = (sampleRate * sequenceMs) / 1000; + + maxOffset = seekLength; + + calculateOverlapLength(overlapMs); + + // set tempo to recalculate 'sampleReq' + setTempo(tempo); + +} + + + +/// Get routine control parameters, see setParameters() function. +/// Any of the parameters to this function can be NULL, in such case corresponding parameter +/// value isn't returned. +void TDStretch::getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs) +{ + if (pSampleRate) + { + *pSampleRate = sampleRate; + } + + if (pSequenceMs) + { + *pSequenceMs = sequenceMs; + } + + if (pSeekWindowMs) + { + *pSeekWindowMs = seekWindowMs; + } + + if (pOverlapMs) + { + *pOverlapMs = overlapMs; + } +} + + +// Overlaps samples in 'midBuffer' with the samples in 'input' +void TDStretch::overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const +{ + int i, itemp; + + for (i = 0; i < (int)overlapLength ; i ++) + { + itemp = overlapLength - i; + output[i] = (input[i] * i + pMidBuffer[i] * itemp ) / overlapLength; // >> overlapDividerBits; + } +} + + + +void TDStretch::clearMidBuffer() +{ + if (bMidBufferDirty) + { + memset(pMidBuffer, 0, 2 * sizeof(SAMPLETYPE) * overlapLength); + bMidBufferDirty = FALSE; + } +} + + +void TDStretch::clearInput() +{ + inputBuffer.clear(); + clearMidBuffer(); +} + + +// Clears the sample buffers +void TDStretch::clear() +{ + outputBuffer.clear(); + inputBuffer.clear(); + clearMidBuffer(); +} + + + +// Enables/disables the quick position seeking algorithm. Zero to disable, nonzero +// to enable +void TDStretch::enableQuickSeek(BOOL enable) +{ + bQuickseek = enable; +} + + +// Returns nonzero if the quick seeking algorithm is enabled. +BOOL TDStretch::isQuickSeekEnabled() const +{ + return bQuickseek; +} + + +// Seeks for the optimal overlap-mixing position. +uint TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos) +{ + if (channels == 2) + { + // stereo sound + if (bQuickseek) + { + return seekBestOverlapPositionStereoQuick(refPos); + } + else + { + return seekBestOverlapPositionStereo(refPos); + } + } + else + { + // mono sound + if (bQuickseek) + { + return seekBestOverlapPositionMonoQuick(refPos); + } + else + { + return seekBestOverlapPositionMono(refPos); + } + } +} + + + + +// Overlaps samples in 'midBuffer' with the samples in 'inputBuffer' at position +// of 'ovlPos'. +inline void TDStretch::overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const +{ + if (channels == 2) + { + // stereo sound + overlapStereo(output, input + 2 * ovlPos); + } else { + // mono sound. + overlapMono(output, input + ovlPos); + } +} + + + + +// Seeks for the optimal overlap-mixing position. The 'stereo' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionStereo(const SAMPLETYPE *refPos) +{ + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint i; + + // Slopes the amplitudes of the 'midBuffer' samples + precalcCorrReferenceStereo(); + + bestCorr = INT_MIN; + bestOffs = 0; + + // Scans for the best correlation value by testing each possible position + // over the permitted range. + for (i = 0; i < seekLength; i ++) + { + // Calculates correlation value for the mixing position corresponding + // to 'i' + corr = calcCrossCorrStereo(refPos + 2 * i, pRefMidBuffer); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = i; + } + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + +// Seeks for the optimal overlap-mixing position. The 'stereo' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos) +{ + uint j; + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint scanCount, corrOffset, tempOffset; + + // Slopes the amplitude of the 'midBuffer' samples + precalcCorrReferenceStereo(); + + bestCorr = INT_MIN; + bestOffs = 0; + corrOffset = 0; + tempOffset = 0; + + // Scans for the best correlation value using four-pass hierarchical search. + // + // The look-up table 'scans' has hierarchical position adjusting steps. + // In first pass the routine searhes for the highest correlation with + // relatively coarse steps, then rescans the neighbourhood of the highest + // correlation with better resolution and so on. + for (scanCount = 0;scanCount < 4; scanCount ++) + { + j = 0; + while (scanOffsets[scanCount][j]) + { + tempOffset = corrOffset + scanOffsets[scanCount][j]; + if (tempOffset >= seekLength) break; + + // Calculates correlation value for the mixing position corresponding + // to 'tempOffset' + corr = calcCrossCorrStereo(refPos + 2 * tempOffset, pRefMidBuffer); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = tempOffset; + } + j ++; + } + corrOffset = bestOffs; + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + + +// Seeks for the optimal overlap-mixing position. The 'mono' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionMono(const SAMPLETYPE *refPos) +{ + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint tempOffset; + const SAMPLETYPE *compare; + + // Slopes the amplitude of the 'midBuffer' samples + precalcCorrReferenceMono(); + + bestCorr = INT_MIN; + bestOffs = 0; + + // Scans for the best correlation value by testing each possible position + // over the permitted range. + for (tempOffset = 0; tempOffset < seekLength; tempOffset ++) + { + compare = refPos + tempOffset; + + // Calculates correlation value for the mixing position corresponding + // to 'tempOffset' + corr = calcCrossCorrMono(pRefMidBuffer, compare); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = tempOffset; + } + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + +// Seeks for the optimal overlap-mixing position. The 'mono' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos) +{ + uint j; + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint scanCount, corrOffset, tempOffset; + + // Slopes the amplitude of the 'midBuffer' samples + precalcCorrReferenceMono(); + + bestCorr = INT_MIN; + bestOffs = 0; + corrOffset = 0; + tempOffset = 0; + + // Scans for the best correlation value using four-pass hierarchical search. + // + // The look-up table 'scans' has hierarchical position adjusting steps. + // In first pass the routine searhes for the highest correlation with + // relatively coarse steps, then rescans the neighbourhood of the highest + // correlation with better resolution and so on. + for (scanCount = 0;scanCount < 4; scanCount ++) + { + j = 0; + while (scanOffsets[scanCount][j]) + { + tempOffset = corrOffset + scanOffsets[scanCount][j]; + if (tempOffset >= seekLength) break; + + // Calculates correlation value for the mixing position corresponding + // to 'tempOffset' + corr = calcCrossCorrMono(refPos + tempOffset, pRefMidBuffer); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = tempOffset; + } + j ++; + } + corrOffset = bestOffs; + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + +/// clear cross correlation routine state if necessary +void TDStretch::clearCrossCorrState() +{ + // default implementation is empty. +} + + +// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower +// tempo, larger faster tempo. +void TDStretch::setTempo(float newTempo) +{ + uint intskip; + + tempo = newTempo; + + // Calculate ideal skip length (according to tempo value) + nominalSkip = tempo * (seekWindowLength - overlapLength); + skipFract = 0; + intskip = (int)(nominalSkip + 0.5f); + + // Calculate how many samples are needed in the 'inputBuffer' to + // process another batch of samples + sampleReq = max(intskip + overlapLength, seekWindowLength) + maxOffset; +} + + + +// Sets the number of channels, 1 = mono, 2 = stereo +void TDStretch::setChannels(uint numChannels) +{ + if (channels == numChannels) return; + assert(numChannels == 1 || numChannels == 2); + + channels = numChannels; + inputBuffer.setChannels(channels); + outputBuffer.setChannels(channels); +} + + +// nominal tempo, no need for processing, just pass the samples through +// to outputBuffer +void TDStretch::processNominalTempo() +{ + assert(tempo == 1.0f); + + if (bMidBufferDirty) + { + // If there are samples in pMidBuffer waiting for overlapping, + // do a single sliding overlapping with them in order to prevent a + // clicking distortion in the output sound + if (inputBuffer.numSamples() < overlapLength) + { + // wait until we've got overlapLength input samples + return; + } + // Mix the samples in the beginning of 'inputBuffer' with the + // samples in 'midBuffer' using sliding overlapping + overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0); + outputBuffer.putSamples(overlapLength); + inputBuffer.receiveSamples(overlapLength); + clearMidBuffer(); + // now we've caught the nominal sample flow and may switch to + // bypass mode + } + + // Simply bypass samples from input to output + outputBuffer.moveSamples(inputBuffer); +} + + +// Processes as many processing frames of the samples 'inputBuffer', store +// the result into 'outputBuffer' +void TDStretch::processSamples() +{ + uint ovlSkip, offset; + int temp; + + /* Removed this small optimization - can introduce a click to sound when tempo setting + crosses the nominal value + if (tempo == 1.0f) + { + // tempo not changed from the original, so bypass the processing + processNominalTempo(); + return; + } + */ + + if (bMidBufferDirty == FALSE) + { + // if midBuffer is empty, move the first samples of the input stream + // into it + if (inputBuffer.numSamples() < overlapLength) + { + // wait until we've got overlapLength samples + return; + } + memcpy(pMidBuffer, inputBuffer.ptrBegin(), channels * overlapLength * sizeof(SAMPLETYPE)); + inputBuffer.receiveSamples(overlapLength); + bMidBufferDirty = TRUE; + } + + // Process samples as long as there are enough samples in 'inputBuffer' + // to form a processing frame. + while (inputBuffer.numSamples() >= sampleReq) + { + // If tempo differs from the normal ('SCALE'), scan for the best overlapping + // position + offset = seekBestOverlapPosition(inputBuffer.ptrBegin()); + + // Mix the samples in the 'inputBuffer' at position of 'offset' with the + // samples in 'midBuffer' using sliding overlapping + // ... first partially overlap with the end of the previous sequence + // (that's in 'midBuffer') + overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), offset); + outputBuffer.putSamples(overlapLength); + + // ... then copy sequence samples from 'inputBuffer' to output + temp = (seekWindowLength - 2 * overlapLength);// & 0xfffffffe; + if (temp > 0) + { + outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * (offset + overlapLength), temp); + } + + // Copies the end of the current sequence from 'inputBuffer' to + // 'midBuffer' for being mixed with the beginning of the next + // processing sequence and so on + assert(offset + seekWindowLength <= inputBuffer.numSamples()); + memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + seekWindowLength - overlapLength), + channels * sizeof(SAMPLETYPE) * overlapLength); + bMidBufferDirty = TRUE; + + // Remove the processed samples from the input buffer. Update + // the difference between integer & nominal skip step to 'skipFract' + // in order to prevent the error from accumulating over time. + skipFract += nominalSkip; // real skip size + ovlSkip = (int)skipFract; // rounded to integer skip + skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip + inputBuffer.receiveSamples(ovlSkip); + } +} + + +// Adds 'numsamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void TDStretch::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + // Add the samples into the input buffer + inputBuffer.putSamples(samples, numSamples); + // Process the samples in input buffer + processSamples(); +} + + + +/// Set new overlap length parameter & reallocate RefMidBuffer if necessary. +void TDStretch::acceptNewOverlapLength(uint newOverlapLength) +{ + uint prevOvl; + + prevOvl = overlapLength; + overlapLength = newOverlapLength; + + if (overlapLength > prevOvl) + { + delete[] pMidBuffer; + delete[] pRefMidBufferUnaligned; + + pMidBuffer = new SAMPLETYPE[overlapLength * 2]; + bMidBufferDirty = TRUE; + clearMidBuffer(); + + pRefMidBufferUnaligned = new SAMPLETYPE[2 * overlapLength + 16 / sizeof(SAMPLETYPE)]; + // ensure that 'pRefMidBuffer' is aligned to 16 byte boundary for efficiency + pRefMidBuffer = (SAMPLETYPE *)((((ulongptr)pRefMidBufferUnaligned) + 15) & -16); + } +} + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX/SSE/etc-capable CPU available or not. +void * TDStretch::operator new(size_t s) +{ + // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! + assert(FALSE); + return NULL; +} + + +TDStretch * TDStretch::newInstance() +{ + uint uExtensions = 0; + +#if !defined(_MSC_VER) || !defined(__x86_64__) + uExtensions = detectCPUextensions(); +#endif + + // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU + +#ifdef ALLOW_MMX + // MMX routines available only with integer sample types + if (uExtensions & SUPPORT_MMX) + { + return ::new TDStretchMMX; + } + else +#endif // ALLOW_MMX + + +#ifdef ALLOW_SSE + if (uExtensions & SUPPORT_SSE) + { + // SSE support + return ::new TDStretchSSE; + } + else +#endif // ALLOW_SSE + + +#ifdef ALLOW_3DNOW + if (uExtensions & SUPPORT_3DNOW) + { + // 3DNow! support + return ::new TDStretch3DNow; + } + else +#endif // ALLOW_3DNOW + + { + // ISA optimizations not supported, use plain C version + return ::new TDStretch; + } +} + + +////////////////////////////////////////////////////////////////////////////// +// +// Integer arithmetics specific algorithm implementations. +// +////////////////////////////////////////////////////////////////////////////// + +#ifdef INTEGER_SAMPLES + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceStereo() +{ + int i, cnt2; + int temp, temp2; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = i * (overlapLength - i); + cnt2 = i * 2; + + temp2 = (pMidBuffer[cnt2] * temp) / slopingDivider; + pRefMidBuffer[cnt2] = (short)(temp2); + temp2 = (pMidBuffer[cnt2 + 1] * temp) / slopingDivider; + pRefMidBuffer[cnt2 + 1] = (short)(temp2); + } +} + + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceMono() +{ + int i; + long temp; + long temp2; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = i * (overlapLength - i); + temp2 = (pMidBuffer[i] * temp) / slopingDivider; + pRefMidBuffer[i] = (short)temp2; + } +} + + +// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo' +// version of the routine. +void TDStretch::overlapStereo(short *output, const short *input) const +{ + int i; + short temp; + uint cnt2; + + for (i = 0; i < (int)overlapLength ; i ++) + { + temp = (short)(overlapLength - i); + cnt2 = 2 * i; + output[cnt2] = (input[cnt2] * i + pMidBuffer[cnt2] * temp ) / overlapLength; + output[cnt2 + 1] = (input[cnt2 + 1] * i + pMidBuffer[cnt2 + 1] * temp ) / overlapLength; + } +} + + +/// Calculates overlap period length in samples. +/// Integer version rounds overlap length to closest power of 2 +/// for a divide scaling operation. +void TDStretch::calculateOverlapLength(uint overlapMs) +{ + uint newOvl; + + overlapDividerBits = _getClosest2Power((sampleRate * overlapMs) / 1000.0); + if (overlapDividerBits > 9) overlapDividerBits = 9; + if (overlapDividerBits < 4) overlapDividerBits = 4; + newOvl = 1<> overlapDividerBits; + } + + return corr; +} + + +long TDStretch::calcCrossCorrStereo(const short *mixingPos, const short *compare) const +{ + long corr; + uint i; + + corr = 0; + for (i = 2; i < 2 * overlapLength; i += 2) + { + corr += (mixingPos[i] * compare[i] + + mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBits; + } + + return corr; +} + +#endif // INTEGER_SAMPLES + +////////////////////////////////////////////////////////////////////////////// +// +// Floating point arithmetics specific algorithm implementations. +// + +#ifdef FLOAT_SAMPLES + + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceStereo() +{ + int i, cnt2; + float temp; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = (float)i * (float)(overlapLength - i); + cnt2 = i * 2; + pRefMidBuffer[cnt2] = (float)(pMidBuffer[cnt2] * temp); + pRefMidBuffer[cnt2 + 1] = (float)(pMidBuffer[cnt2 + 1] * temp); + } +} + + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceMono() +{ + int i; + float temp; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = (float)i * (float)(overlapLength - i); + pRefMidBuffer[i] = (float)(pMidBuffer[i] * temp); + } +} + + +// SSE-optimized version of the function overlapStereo +void TDStretch::overlapStereo(float *output, const float *input) const +{ + int i; + uint cnt2; + float fTemp; + float fScale; + float fi; + + fScale = 1.0f / (float)overlapLength; + + for (i = 0; i < (int)overlapLength ; i ++) + { + fTemp = (float)(overlapLength - i) * fScale; + fi = (float)i * fScale; + cnt2 = 2 * i; + output[cnt2 + 0] = input[cnt2 + 0] * fi + pMidBuffer[cnt2 + 0] * fTemp; + output[cnt2 + 1] = input[cnt2 + 1] * fi + pMidBuffer[cnt2 + 1] * fTemp; + } +} + + +/// Calculates overlap period length in samples. +void TDStretch::calculateOverlapLength(uint overlapMs) +{ + uint newOvl; + + newOvl = (sampleRate * overlapMs) / 1000; + if (newOvl < 16) newOvl = 16; + + // must be divisible by 8 + newOvl -= newOvl % 8; + + acceptNewOverlapLength(newOvl); +} + + + +double TDStretch::calcCrossCorrMono(const float *mixingPos, const float *compare) const +{ + double corr; + uint i; + + corr = 0; + for (i = 1; i < overlapLength; i ++) + { + corr += mixingPos[i] * compare[i]; + } + + return corr; +} + + +double TDStretch::calcCrossCorrStereo(const float *mixingPos, const float *compare) const +{ + double corr; + uint i; + + corr = 0; + for (i = 2; i < 2 * overlapLength; i += 2) + { + corr += mixingPos[i] * compare[i] + + mixingPos[i + 1] * compare[i + 1]; + } + + return corr; +} + +#endif // FLOAT_SAMPLES diff --git a/plugins/zerospu2/3rdparty/SoundTouch/TDStretch.h b/plugins/zerospu2/3rdparty/SoundTouch/TDStretch.h index a05a7072fc..133c227d49 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/TDStretch.h +++ b/plugins/zerospu2/3rdparty/SoundTouch/TDStretch.h @@ -1,236 +1,236 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo -/// while maintaining the original pitch by using a time domain WSOLA-like method -/// with several performance-increasing tweaks. -/// -/// Note : MMX optimized functions reside in a separate, platform-specific file, -/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.16 $ -// -// $Id: TDStretch.h,v 1.16 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef TDStretch_H -#define TDStretch_H - -#include "STTypes.h" -#include "RateTransposer.h" -#include "FIFOSamplePipe.h" - -namespace soundtouch -{ - -// Default values for sound processing parameters: - -/// Default length of a single processing sequence, in milliseconds. This determines to how -/// long sequences the original sound is chopped in the time-stretch algorithm. -/// -/// The larger this value is, the lesser sequences are used in processing. In principle -/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo -/// and vice versa. -/// -/// Increasing this value reduces computational burden & vice versa. -#define DEFAULT_SEQUENCE_MS 61 - -#define DEFAULT_SEEKWINDOW_MS 18 - -#define DEFAULT_OVERLAP_MS 7 - - -/// Class that does the time-stretch (tempo change) effect for the processed -/// sound. -class TDStretch : public FIFOProcessor -{ -protected: - uint channels; - uint sampleReq; - float tempo; - - SAMPLETYPE *pMidBuffer; - SAMPLETYPE *pRefMidBuffer; - SAMPLETYPE *pRefMidBufferUnaligned; - uint overlapLength; - uint overlapDividerBits; - uint slopingDivider; - uint seekLength; - uint seekWindowLength; - uint maxOffset; - float nominalSkip; - float skipFract; - FIFOSampleBuffer outputBuffer; - FIFOSampleBuffer inputBuffer; - BOOL bQuickseek; - BOOL bMidBufferDirty; - - uint sampleRate; - uint sequenceMs; - uint seekWindowMs; - uint overlapMs; - - void acceptNewOverlapLength(uint newOverlapLength); - - virtual void clearCrossCorrState(); - void calculateOverlapLength(uint overlapMs); - - virtual LONG_SAMPLETYPE calcCrossCorrStereo(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; - virtual LONG_SAMPLETYPE calcCrossCorrMono(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; - - virtual uint seekBestOverlapPositionStereo(const SAMPLETYPE *refPos); - virtual uint seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos); - virtual uint seekBestOverlapPositionMono(const SAMPLETYPE *refPos); - virtual uint seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos); - uint seekBestOverlapPosition(const SAMPLETYPE *refPos); - - virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const; - virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const; - - void clearMidBuffer(); - void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const; - - void precalcCorrReferenceMono(); - void precalcCorrReferenceStereo(); - - void processNominalTempo(); - - /// Changes the tempo of the given sound samples. - /// Returns amount of samples returned in the "output" buffer. - /// The maximum amount of samples that can be returned at a time is set by - /// the 'set_returnBuffer_size' function. - void processSamples(); - -public: - TDStretch(); - virtual ~TDStretch(); - - /// Operator 'new' is overloaded so that it automatically creates a suitable instance - /// depending on if we've a MMX/SSE/etc-capable CPU available or not. - void *operator new(size_t s); - - /// Use this function instead of "new" operator to create a new instance of this class. - /// This function automatically chooses a correct feature set depending on if the CPU - /// supports MMX/SSE/etc extensions. - static TDStretch *newInstance(); - - /// Returns the output buffer object - FIFOSamplePipe *getOutput() { return &outputBuffer; }; - - /// Returns the input buffer object - FIFOSamplePipe *getInput() { return &inputBuffer; }; - - /// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower - /// tempo, larger faster tempo. - void setTempo(float newTempo); - - /// Returns nonzero if there aren't any samples available for outputting. - virtual void clear(); - - /// Clears the input buffer - void clearInput(); - - /// Sets the number of channels, 1 = mono, 2 = stereo - void setChannels(uint numChannels); - - /// Enables/disables the quick position seeking algorithm. Zero to disable, - /// nonzero to enable - void enableQuickSeek(BOOL enable); - - /// Returns nonzero if the quick seeking algorithm is enabled. - BOOL isQuickSeekEnabled() const; - - /// Sets routine control parameters. These control are certain time constants - /// defining how the sound is stretched to the desired duration. - // - /// 'sampleRate' = sample rate of the sound - /// 'sequenceMS' = one processing sequence length in milliseconds - /// 'seekwindowMS' = seeking window length for scanning the best overlapping - /// position - /// 'overlapMS' = overlapping length - void setParameters(uint sampleRate, ///< Samplerate of sound being processed (Hz) - uint sequenceMS = DEFAULT_SEQUENCE_MS, ///< Single processing sequence length (ms) - uint seekwindowMS = DEFAULT_SEEKWINDOW_MS, ///< Offset seeking window length (ms) - uint overlapMS = DEFAULT_OVERLAP_MS ///< Sequence overlapping length (ms) - ); - - /// Get routine control parameters, see setParameters() function. - /// Any of the parameters to this function can be NULL, in such case corresponding parameter - /// value isn't returned. - void getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs); - - /// Adds 'numsamples' pcs of samples from the 'samples' memory position into - /// the input of the object. - virtual void putSamples( - const SAMPLETYPE *samples, ///< Input sample data - uint numSamples ///< Number of samples in 'samples' so that one sample - ///< contains both channels if stereo - ); -}; - - - -// Implementation-specific class declarations: - -//#ifdef ALLOW_MMX -// /// Class that implements MMX optimized routines for 16bit integer samples type. -// class TDStretchMMX : public TDStretch -// { -// protected: -// long calcCrossCorrStereo(const short *mixingPos, const short *compare) const; -// virtual void overlapStereo(short *output, const short *input) const; -// virtual void clearCrossCorrState(); -// }; -//#endif /// ALLOW_MMX -// -// -//#ifdef ALLOW_3DNOW -// /// Class that implements 3DNow! optimized routines for floating point samples type. -// class TDStretch3DNow : public TDStretch -// { -// protected: -// double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; -// }; -//#endif /// ALLOW_3DNOW - - -#ifdef ALLOW_SSE - /// Class that implements SSE optimized routines for floating point samples type. - class TDStretchSSE : public TDStretch - { - protected: - double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; - }; - -#endif /// ALLOW_SSE - -} -#endif /// TDStretch_H +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like method +/// with several performance-increasing tweaks. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.16 $ +// +// $Id: TDStretch.h,v 1.16 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef TDStretch_H +#define TDStretch_H + +#include "STTypes.h" +#include "RateTransposer.h" +#include "FIFOSamplePipe.h" + +namespace soundtouch +{ + +// Default values for sound processing parameters: + +/// Default length of a single processing sequence, in milliseconds. This determines to how +/// long sequences the original sound is chopped in the time-stretch algorithm. +/// +/// The larger this value is, the lesser sequences are used in processing. In principle +/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo +/// and vice versa. +/// +/// Increasing this value reduces computational burden & vice versa. +#define DEFAULT_SEQUENCE_MS 61 + +#define DEFAULT_SEEKWINDOW_MS 18 + +#define DEFAULT_OVERLAP_MS 7 + + +/// Class that does the time-stretch (tempo change) effect for the processed +/// sound. +class TDStretch : public FIFOProcessor +{ +protected: + uint channels; + uint sampleReq; + float tempo; + + SAMPLETYPE *pMidBuffer; + SAMPLETYPE *pRefMidBuffer; + SAMPLETYPE *pRefMidBufferUnaligned; + uint overlapLength; + uint overlapDividerBits; + uint slopingDivider; + uint seekLength; + uint seekWindowLength; + uint maxOffset; + float nominalSkip; + float skipFract; + FIFOSampleBuffer outputBuffer; + FIFOSampleBuffer inputBuffer; + BOOL bQuickseek; + BOOL bMidBufferDirty; + + uint sampleRate; + uint sequenceMs; + uint seekWindowMs; + uint overlapMs; + + void acceptNewOverlapLength(uint newOverlapLength); + + virtual void clearCrossCorrState(); + void calculateOverlapLength(uint overlapMs); + + virtual LONG_SAMPLETYPE calcCrossCorrStereo(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; + virtual LONG_SAMPLETYPE calcCrossCorrMono(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; + + virtual uint seekBestOverlapPositionStereo(const SAMPLETYPE *refPos); + virtual uint seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos); + virtual uint seekBestOverlapPositionMono(const SAMPLETYPE *refPos); + virtual uint seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos); + uint seekBestOverlapPosition(const SAMPLETYPE *refPos); + + virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const; + virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const; + + void clearMidBuffer(); + void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const; + + void precalcCorrReferenceMono(); + void precalcCorrReferenceStereo(); + + void processNominalTempo(); + + /// Changes the tempo of the given sound samples. + /// Returns amount of samples returned in the "output" buffer. + /// The maximum amount of samples that can be returned at a time is set by + /// the 'set_returnBuffer_size' function. + void processSamples(); + +public: + TDStretch(); + virtual ~TDStretch(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we've a MMX/SSE/etc-capable CPU available or not. + void *operator new(size_t s); + + /// Use this function instead of "new" operator to create a new instance of this class. + /// This function automatically chooses a correct feature set depending on if the CPU + /// supports MMX/SSE/etc extensions. + static TDStretch *newInstance(); + + /// Returns the output buffer object + FIFOSamplePipe *getOutput() { return &outputBuffer; }; + + /// Returns the input buffer object + FIFOSamplePipe *getInput() { return &inputBuffer; }; + + /// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower + /// tempo, larger faster tempo. + void setTempo(float newTempo); + + /// Returns nonzero if there aren't any samples available for outputting. + virtual void clear(); + + /// Clears the input buffer + void clearInput(); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint numChannels); + + /// Enables/disables the quick position seeking algorithm. Zero to disable, + /// nonzero to enable + void enableQuickSeek(BOOL enable); + + /// Returns nonzero if the quick seeking algorithm is enabled. + BOOL isQuickSeekEnabled() const; + + /// Sets routine control parameters. These control are certain time constants + /// defining how the sound is stretched to the desired duration. + // + /// 'sampleRate' = sample rate of the sound + /// 'sequenceMS' = one processing sequence length in milliseconds + /// 'seekwindowMS' = seeking window length for scanning the best overlapping + /// position + /// 'overlapMS' = overlapping length + void setParameters(uint sampleRate, ///< Samplerate of sound being processed (Hz) + uint sequenceMS = DEFAULT_SEQUENCE_MS, ///< Single processing sequence length (ms) + uint seekwindowMS = DEFAULT_SEEKWINDOW_MS, ///< Offset seeking window length (ms) + uint overlapMS = DEFAULT_OVERLAP_MS ///< Sequence overlapping length (ms) + ); + + /// Get routine control parameters, see setParameters() function. + /// Any of the parameters to this function can be NULL, in such case corresponding parameter + /// value isn't returned. + void getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs); + + /// Adds 'numsamples' pcs of samples from the 'samples' memory position into + /// the input of the object. + virtual void putSamples( + const SAMPLETYPE *samples, ///< Input sample data + uint numSamples ///< Number of samples in 'samples' so that one sample + ///< contains both channels if stereo + ); +}; + + + +// Implementation-specific class declarations: + +//#ifdef ALLOW_MMX +// /// Class that implements MMX optimized routines for 16bit integer samples type. +// class TDStretchMMX : public TDStretch +// { +// protected: +// long calcCrossCorrStereo(const short *mixingPos, const short *compare) const; +// virtual void overlapStereo(short *output, const short *input) const; +// virtual void clearCrossCorrState(); +// }; +//#endif /// ALLOW_MMX +// +// +//#ifdef ALLOW_3DNOW +// /// Class that implements 3DNow! optimized routines for floating point samples type. +// class TDStretch3DNow : public TDStretch +// { +// protected: +// double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; +// }; +//#endif /// ALLOW_3DNOW + + +#ifdef ALLOW_SSE + /// Class that implements SSE optimized routines for floating point samples type. + class TDStretchSSE : public TDStretch + { + protected: + double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; + }; + +#endif /// ALLOW_SSE + +} +#endif /// TDStretch_H diff --git a/plugins/zerospu2/3rdparty/SoundTouch/WavFile.cpp b/plugins/zerospu2/3rdparty/SoundTouch/WavFile.cpp index 77db8cc431..15a679871c 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/WavFile.cpp +++ b/plugins/zerospu2/3rdparty/SoundTouch/WavFile.cpp @@ -1,714 +1,714 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Classes for easy reading & writing of WAV sound files. -/// -/// For big-endian CPU, define _BIG_ENDIAN_ during compile-time to correctly -/// parse the WAV files with such processors. -/// -/// Admittingly, more complete WAV reader routines may exist in public domain, -/// but the reason for 'yet another' one is that those generic WAV reader -/// libraries are exhaustingly large and cumbersome! Wanted to have something -/// simpler here, i.e. something that's not already larger than rest of the -/// SoundTouch/SoundStretch program... -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.15 $ -// -// $Id: WavFile.cpp,v 1.15 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include - -#include -#include - -#include "WavFile.h" - -using namespace std; - -const static char riffStr[] = "RIFF"; -const static char waveStr[] = "WAVE"; -const static char fmtStr[] = "fmt "; -const static char dataStr[] = "data"; - - -////////////////////////////////////////////////////////////////////////////// -// -// Helper functions for swapping byte order to correctly read/write WAV files -// with big-endian CPU's: Define compile-time definition _BIG_ENDIAN_ to -// turn-on the conversion if it appears necessary. -// -// For example, Intel x86 is little-endian and doesn't require conversion, -// while PowerPC of Mac's and many other RISC cpu's are big-endian. - -#ifdef BYTE_ORDER - // In gcc compiler detect the byte order automatically - #if BYTE_ORDER == BIG_ENDIAN - // big-endian platform. - #define _BIG_ENDIAN_ - #endif -#endif - -#ifdef _BIG_ENDIAN_ - // big-endian CPU, swap bytes in 16 & 32 bit words - - // helper-function to swap byte-order of 32bit integer - static inline void _swap32(unsigned int &dwData) - { - dwData = ((dwData >> 24) & 0x000000FF) | - ((dwData >> 8) & 0x0000FF00) | - ((dwData << 8) & 0x00FF0000) | - ((dwData << 24) & 0xFF000000); - } - - // helper-function to swap byte-order of 16bit integer - static inline void _swap16(unsigned short &wData) - { - wData = ((wData >> 8) & 0x00FF) | - ((wData << 8) & 0xFF00); - } - - // helper-function to swap byte-order of buffer of 16bit integers - static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumWords) - { - unsigned long i; - - for (i = 0; i < dwNumWords; i ++) - { - _swap16(pData[i]); - } - } - -#else // BIG_ENDIAN - // little-endian CPU, WAV file is ok as such - - // dummy helper-function - static inline void _swap32(unsigned int &dwData) - { - // do nothing - } - - // dummy helper-function - static inline void _swap16(unsigned short &wData) - { - // do nothing - } - - // dummy helper-function - static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumBytes) - { - // do nothing - } - -#endif // BIG_ENDIAN - - -////////////////////////////////////////////////////////////////////////////// -// -// Class WavInFile -// - -WavInFile::WavInFile(const char *fileName) -{ - int hdrsOk; - - // Try to open the file for reading - fptr = fopen(fileName, "rb"); - if (fptr == NULL) - { - // didn't succeed - string msg = "Error : Unable to open file \""; - msg += fileName; - msg += "\" for reading."; - throw runtime_error(msg); - } - - // Read the file headers - hdrsOk = readWavHeaders(); - if (hdrsOk != 0) - { - // Something didn't match in the wav file headers - string msg = "File \""; - msg += fileName; - msg += "\" is corrupt or not a WAV file"; - throw runtime_error(msg); - } - - if (header.format.fixed != 1) - { - string msg = "File \""; - msg += fileName; - msg += "\" uses unsupported encoding."; - throw runtime_error(msg); - } - - dataRead = 0; -} - - - -WavInFile::~WavInFile() -{ - close(); -} - - - -void WavInFile::rewind() -{ - int hdrsOk; - - fseek(fptr, 0, SEEK_SET); - hdrsOk = readWavHeaders(); - assert(hdrsOk == 0); - dataRead = 0; -} - - -int WavInFile::checkCharTags() -{ - // header.format.fmt should equal to 'fmt ' - if (memcmp(fmtStr, header.format.fmt, 4) != 0) return -1; - // header.data.data_field should equal to 'data' - if (memcmp(dataStr, header.data.data_field, 4) != 0) return -1; - - return 0; -} - - -int WavInFile::read(char *buffer, int maxElems) -{ - int numBytes; - uint afterDataRead; - - // ensure it's 8 bit format - if (header.format.bits_per_sample != 8) - { - throw runtime_error("Error: WavInFile::read(char*, int) works only with 8bit samples."); - } - assert(sizeof(char) == 1); - - numBytes = maxElems; - afterDataRead = dataRead + numBytes; - if (afterDataRead > header.data.data_len) - { - // Don't read more samples than are marked available in header - numBytes = header.data.data_len - dataRead; - assert(numBytes >= 0); - } - - numBytes = fread(buffer, 1, numBytes, fptr); - dataRead += numBytes; - - return numBytes; -} - - -int WavInFile::read(short *buffer, int maxElems) -{ - unsigned int afterDataRead; - int numBytes; - int numElems; - - if (header.format.bits_per_sample == 8) - { - // 8 bit format - char *temp = new char[maxElems]; - int i; - - numElems = read(temp, maxElems); - // convert from 8 to 16 bit - for (i = 0; i < numElems; i ++) - { - buffer[i] = temp[i] << 8; - } - delete[] temp; - } - else - { - // 16 bit format - assert(header.format.bits_per_sample == 16); - assert(sizeof(short) == 2); - - numBytes = maxElems * 2; - afterDataRead = dataRead + numBytes; - if (afterDataRead > header.data.data_len) - { - // Don't read more samples than are marked available in header - numBytes = header.data.data_len - dataRead; - assert(numBytes >= 0); - } - - numBytes = fread(buffer, 1, numBytes, fptr); - dataRead += numBytes; - numElems = numBytes / 2; - - // 16bit samples, swap byte order if necessary - _swap16Buffer((unsigned short *)buffer, numElems); - } - - return numElems; -} - - - -int WavInFile::read(float *buffer, int maxElems) -{ - short *temp = new short[maxElems]; - int num; - int i; - double fscale; - - num = read(temp, maxElems); - - fscale = 1.0 / 32768.0; - // convert to floats, scale to range [-1..+1[ - for (i = 0; i < num; i ++) - { - buffer[i] = (float)(fscale * (double)temp[i]); - } - - delete[] temp; - - return num; -} - - -int WavInFile::eof() const -{ - // return true if all data has been read or file eof has reached - return (dataRead == header.data.data_len || feof(fptr)); -} - - -void WavInFile::close() -{ - fclose(fptr); - fptr = NULL; -} - - - -// test if character code is between a white space ' ' and little 'z' -static int isAlpha(char c) -{ - return (c >= ' ' && c <= 'z') ? 1 : 0; -} - - -// test if all characters are between a white space ' ' and little 'z' -static int isAlphaStr(char *str) -{ - int c; - - c = str[0]; - while (c) - { - if (isAlpha(c) == 0) return 0; - str ++; - c = str[0]; - } - - return 1; -} - - -int WavInFile::readRIFFBlock() -{ - fread(&(header.riff), sizeof(WavRiff), 1, fptr); - - // swap 32bit data byte order if necessary - _swap32((unsigned int &)header.riff.package_len); - - // header.riff.riff_char should equal to 'RIFF'); - if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1; - // header.riff.wave should equal to 'WAVE' - if (memcmp(waveStr, header.riff.wave, 4) != 0) return -1; - - return 0; -} - - - - -int WavInFile::readHeaderBlock() -{ - char label[5]; - string sLabel; - - // lead label string - fread(label, 1, 4, fptr); - label[4] = 0; - - if (isAlphaStr(label) == 0) return -1; // not a valid label - - // Decode blocks according to their label - if (strcmp(label, fmtStr) == 0) - { - int nLen, nDump; - - // 'fmt ' block - memcpy(header.format.fmt, fmtStr, 4); - - // read length of the format field - fread(&nLen, sizeof(int), 1, fptr); - // swap byte order if necessary - _swap32((unsigned int &)nLen); // int format_len; - header.format.format_len = nLen; - - // calculate how much length differs from expected - nDump = nLen - (sizeof(header.format) - 8); - - // if format_len is larger than expected, read only as much data as we've space for - if (nDump > 0) - { - nLen = sizeof(header.format) - 8; - } - - // read data - fread(&(header.format.fixed), nLen, 1, fptr); - - // swap byte order if necessary - _swap16((unsigned short &)header.format.fixed); // short int fixed; - _swap16((unsigned short &)header.format.channel_number); // short int channel_number; - _swap32((unsigned int &)header.format.sample_rate); // int sample_rate; - _swap32((unsigned int &)header.format.byte_rate); // int byte_rate; - _swap16((unsigned short &)header.format.byte_per_sample); // short int byte_per_sample; - _swap16((unsigned short &)header.format.bits_per_sample); // short int bits_per_sample; - - // if format_len is larger than expected, skip the extra data - if (nDump > 0) - { - fseek(fptr, nDump, SEEK_CUR); - } - - return 0; - } - else if (strcmp(label, dataStr) == 0) - { - // 'data' block - memcpy(header.data.data_field, dataStr, 4); - fread(&(header.data.data_len), sizeof(uint), 1, fptr); - - // swap byte order if necessary - _swap32((unsigned int &)header.data.data_len); - - return 1; - } - else - { - uint len, i; - uint temp; - // unknown block - - // read length - fread(&len, sizeof(len), 1, fptr); - // scan through the block - for (i = 0; i < len; i ++) - { - fread(&temp, 1, 1, fptr); - if (feof(fptr)) return -1; // unexpected eof - } - } - return 0; -} - - -int WavInFile::readWavHeaders() -{ - int res; - - memset(&header, 0, sizeof(header)); - - res = readRIFFBlock(); - if (res) return 1; - // read header blocks until data block is found - do - { - // read header blocks - res = readHeaderBlock(); - if (res < 0) return 1; // error in file structure - } while (res == 0); - // check that all required tags are legal - return checkCharTags(); -} - - -uint WavInFile::getNumChannels() const -{ - return header.format.channel_number; -} - - -uint WavInFile::getNumBits() const -{ - return header.format.bits_per_sample; -} - - -uint WavInFile::getBytesPerSample() const -{ - return getNumChannels() * getNumBits() / 8; -} - - -uint WavInFile::getSampleRate() const -{ - return header.format.sample_rate; -} - - - -uint WavInFile::getDataSizeInBytes() const -{ - return header.data.data_len; -} - - -uint WavInFile::getNumSamples() const -{ - return header.data.data_len / header.format.byte_per_sample; -} - - -uint WavInFile::getLengthMS() const -{ - uint numSamples; - uint sampleRate; - - numSamples = getNumSamples(); - sampleRate = getSampleRate(); - - assert(numSamples < UINT_MAX / 1000); - return (1000 * numSamples / sampleRate); -} - - -////////////////////////////////////////////////////////////////////////////// -// -// Class WavOutFile -// - -WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels) -{ - bytesWritten = 0; - fptr = fopen(fileName, "wb"); - if (fptr == NULL) - { - string msg = "Error : Unable to open file \""; - msg += fileName; - msg += "\" for writing."; - //pmsg = msg.c_str; - throw runtime_error(msg); - } - - fillInHeader(sampleRate, bits, channels); - writeHeader(); -} - - - -WavOutFile::~WavOutFile() -{ - close(); -} - - - -void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels) -{ - // fill in the 'riff' part.. - - // copy string 'RIFF' to riff_char - memcpy(&(header.riff.riff_char), riffStr, 4); - // package_len unknown so far - header.riff.package_len = 0; - // copy string 'WAVE' to wave - memcpy(&(header.riff.wave), waveStr, 4); - - - // fill in the 'format' part.. - - // copy string 'fmt ' to fmt - memcpy(&(header.format.fmt), fmtStr, 4); - - header.format.format_len = 0x10; - header.format.fixed = 1; - header.format.channel_number = (short)channels; - header.format.sample_rate = sampleRate; - header.format.bits_per_sample = (short)bits; - header.format.byte_per_sample = (short)(bits * channels / 8); - header.format.byte_rate = header.format.byte_per_sample * sampleRate; - header.format.sample_rate = sampleRate; - - // fill in the 'data' part.. - - // copy string 'data' to data_field - memcpy(&(header.data.data_field), dataStr, 4); - // data_len unknown so far - header.data.data_len = 0; -} - - -void WavOutFile::finishHeader() -{ - // supplement the file length into the header structure - header.riff.package_len = bytesWritten + 36; - header.data.data_len = bytesWritten; - - writeHeader(); -} - - - -void WavOutFile::writeHeader() -{ - WavHeader hdrTemp; - - // swap byte order if necessary - hdrTemp = header; - _swap32((unsigned int &)hdrTemp.riff.package_len); - _swap32((unsigned int &)hdrTemp.format.format_len); - _swap16((unsigned short &)hdrTemp.format.fixed); - _swap16((unsigned short &)hdrTemp.format.channel_number); - _swap32((unsigned int &)hdrTemp.format.sample_rate); - _swap32((unsigned int &)hdrTemp.format.byte_rate); - _swap16((unsigned short &)hdrTemp.format.byte_per_sample); - _swap16((unsigned short &)hdrTemp.format.bits_per_sample); - _swap32((unsigned int &)hdrTemp.data.data_len); - - // write the supplemented header in the beginning of the file - fseek(fptr, 0, SEEK_SET); - fwrite(&hdrTemp, sizeof(hdrTemp), 1, fptr); - // jump back to the end of the file - fseek(fptr, 0, SEEK_END); -} - - - -void WavOutFile::close() -{ - finishHeader(); - fclose(fptr); - fptr = NULL; -} - - -void WavOutFile::write(const char *buffer, int numElems) -{ - int res; - - if (header.format.bits_per_sample != 8) - { - throw runtime_error("Error: WavOutFile::write(const char*, int) accepts only 8bit samples."); - } - assert(sizeof(char) == 1); - - res = fwrite(buffer, 1, numElems, fptr); - if (res != numElems) - { - throw runtime_error("Error while writing to a wav file."); - } - - bytesWritten += numElems; -} - - -void WavOutFile::write(const short *buffer, int numElems) -{ - int res; - - // 16 bit samples - if (numElems < 1) return; // nothing to do - - if (header.format.bits_per_sample == 8) - { - int i; - char *temp = new char[numElems]; - // convert from 16bit format to 8bit format - for (i = 0; i < numElems; i ++) - { - temp[i] = buffer[i] >> 8; - } - // write in 8bit format - write(temp, numElems); - delete[] temp; - } - else - { - // 16bit format - unsigned short *pTemp = new unsigned short[numElems]; - - assert(header.format.bits_per_sample == 16); - - // allocate temp buffer to swap byte order if necessary - memcpy(pTemp, buffer, numElems * 2); - _swap16Buffer(pTemp, numElems); - - res = fwrite(pTemp, 2, numElems, fptr); - - delete[] pTemp; - - if (res != numElems) - { - throw runtime_error("Error while writing to a wav file."); - } - bytesWritten += 2 * numElems; - } -} - - -void WavOutFile::write(const float *buffer, int numElems) -{ - int i; - short *temp = new short[numElems]; - int iTemp; - - // convert to 16 bit integer - for (i = 0; i < numElems; i ++) - { - // convert to integer - iTemp = (int)(32768.0f * buffer[i]); - - // saturate - if (iTemp < -32768) iTemp = -32768; - if (iTemp > 32767) iTemp = 32767; - temp[i] = (short)iTemp; - } - - write(temp, numElems); - - delete[] temp; -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// Classes for easy reading & writing of WAV sound files. +/// +/// For big-endian CPU, define _BIG_ENDIAN_ during compile-time to correctly +/// parse the WAV files with such processors. +/// +/// Admittingly, more complete WAV reader routines may exist in public domain, +/// but the reason for 'yet another' one is that those generic WAV reader +/// libraries are exhaustingly large and cumbersome! Wanted to have something +/// simpler here, i.e. something that's not already larger than rest of the +/// SoundTouch/SoundStretch program... +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.15 $ +// +// $Id: WavFile.cpp,v 1.15 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include +#include + +#include "WavFile.h" + +using namespace std; + +const static char riffStr[] = "RIFF"; +const static char waveStr[] = "WAVE"; +const static char fmtStr[] = "fmt "; +const static char dataStr[] = "data"; + + +////////////////////////////////////////////////////////////////////////////// +// +// Helper functions for swapping byte order to correctly read/write WAV files +// with big-endian CPU's: Define compile-time definition _BIG_ENDIAN_ to +// turn-on the conversion if it appears necessary. +// +// For example, Intel x86 is little-endian and doesn't require conversion, +// while PowerPC of Mac's and many other RISC cpu's are big-endian. + +#ifdef BYTE_ORDER + // In gcc compiler detect the byte order automatically + #if BYTE_ORDER == BIG_ENDIAN + // big-endian platform. + #define _BIG_ENDIAN_ + #endif +#endif + +#ifdef _BIG_ENDIAN_ + // big-endian CPU, swap bytes in 16 & 32 bit words + + // helper-function to swap byte-order of 32bit integer + static inline void _swap32(unsigned int &dwData) + { + dwData = ((dwData >> 24) & 0x000000FF) | + ((dwData >> 8) & 0x0000FF00) | + ((dwData << 8) & 0x00FF0000) | + ((dwData << 24) & 0xFF000000); + } + + // helper-function to swap byte-order of 16bit integer + static inline void _swap16(unsigned short &wData) + { + wData = ((wData >> 8) & 0x00FF) | + ((wData << 8) & 0xFF00); + } + + // helper-function to swap byte-order of buffer of 16bit integers + static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumWords) + { + unsigned long i; + + for (i = 0; i < dwNumWords; i ++) + { + _swap16(pData[i]); + } + } + +#else // BIG_ENDIAN + // little-endian CPU, WAV file is ok as such + + // dummy helper-function + static inline void _swap32(unsigned int &dwData) + { + // do nothing + } + + // dummy helper-function + static inline void _swap16(unsigned short &wData) + { + // do nothing + } + + // dummy helper-function + static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumBytes) + { + // do nothing + } + +#endif // BIG_ENDIAN + + +////////////////////////////////////////////////////////////////////////////// +// +// Class WavInFile +// + +WavInFile::WavInFile(const char *fileName) +{ + int hdrsOk; + + // Try to open the file for reading + fptr = fopen(fileName, "rb"); + if (fptr == NULL) + { + // didn't succeed + string msg = "Error : Unable to open file \""; + msg += fileName; + msg += "\" for reading."; + throw runtime_error(msg); + } + + // Read the file headers + hdrsOk = readWavHeaders(); + if (hdrsOk != 0) + { + // Something didn't match in the wav file headers + string msg = "File \""; + msg += fileName; + msg += "\" is corrupt or not a WAV file"; + throw runtime_error(msg); + } + + if (header.format.fixed != 1) + { + string msg = "File \""; + msg += fileName; + msg += "\" uses unsupported encoding."; + throw runtime_error(msg); + } + + dataRead = 0; +} + + + +WavInFile::~WavInFile() +{ + close(); +} + + + +void WavInFile::rewind() +{ + int hdrsOk; + + fseek(fptr, 0, SEEK_SET); + hdrsOk = readWavHeaders(); + assert(hdrsOk == 0); + dataRead = 0; +} + + +int WavInFile::checkCharTags() +{ + // header.format.fmt should equal to 'fmt ' + if (memcmp(fmtStr, header.format.fmt, 4) != 0) return -1; + // header.data.data_field should equal to 'data' + if (memcmp(dataStr, header.data.data_field, 4) != 0) return -1; + + return 0; +} + + +int WavInFile::read(char *buffer, int maxElems) +{ + int numBytes; + uint afterDataRead; + + // ensure it's 8 bit format + if (header.format.bits_per_sample != 8) + { + throw runtime_error("Error: WavInFile::read(char*, int) works only with 8bit samples."); + } + assert(sizeof(char) == 1); + + numBytes = maxElems; + afterDataRead = dataRead + numBytes; + if (afterDataRead > header.data.data_len) + { + // Don't read more samples than are marked available in header + numBytes = header.data.data_len - dataRead; + assert(numBytes >= 0); + } + + numBytes = fread(buffer, 1, numBytes, fptr); + dataRead += numBytes; + + return numBytes; +} + + +int WavInFile::read(short *buffer, int maxElems) +{ + unsigned int afterDataRead; + int numBytes; + int numElems; + + if (header.format.bits_per_sample == 8) + { + // 8 bit format + char *temp = new char[maxElems]; + int i; + + numElems = read(temp, maxElems); + // convert from 8 to 16 bit + for (i = 0; i < numElems; i ++) + { + buffer[i] = temp[i] << 8; + } + delete[] temp; + } + else + { + // 16 bit format + assert(header.format.bits_per_sample == 16); + assert(sizeof(short) == 2); + + numBytes = maxElems * 2; + afterDataRead = dataRead + numBytes; + if (afterDataRead > header.data.data_len) + { + // Don't read more samples than are marked available in header + numBytes = header.data.data_len - dataRead; + assert(numBytes >= 0); + } + + numBytes = fread(buffer, 1, numBytes, fptr); + dataRead += numBytes; + numElems = numBytes / 2; + + // 16bit samples, swap byte order if necessary + _swap16Buffer((unsigned short *)buffer, numElems); + } + + return numElems; +} + + + +int WavInFile::read(float *buffer, int maxElems) +{ + short *temp = new short[maxElems]; + int num; + int i; + double fscale; + + num = read(temp, maxElems); + + fscale = 1.0 / 32768.0; + // convert to floats, scale to range [-1..+1[ + for (i = 0; i < num; i ++) + { + buffer[i] = (float)(fscale * (double)temp[i]); + } + + delete[] temp; + + return num; +} + + +int WavInFile::eof() const +{ + // return true if all data has been read or file eof has reached + return (dataRead == header.data.data_len || feof(fptr)); +} + + +void WavInFile::close() +{ + fclose(fptr); + fptr = NULL; +} + + + +// test if character code is between a white space ' ' and little 'z' +static int isAlpha(char c) +{ + return (c >= ' ' && c <= 'z') ? 1 : 0; +} + + +// test if all characters are between a white space ' ' and little 'z' +static int isAlphaStr(char *str) +{ + int c; + + c = str[0]; + while (c) + { + if (isAlpha(c) == 0) return 0; + str ++; + c = str[0]; + } + + return 1; +} + + +int WavInFile::readRIFFBlock() +{ + fread(&(header.riff), sizeof(WavRiff), 1, fptr); + + // swap 32bit data byte order if necessary + _swap32((unsigned int &)header.riff.package_len); + + // header.riff.riff_char should equal to 'RIFF'); + if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1; + // header.riff.wave should equal to 'WAVE' + if (memcmp(waveStr, header.riff.wave, 4) != 0) return -1; + + return 0; +} + + + + +int WavInFile::readHeaderBlock() +{ + char label[5]; + string sLabel; + + // lead label string + fread(label, 1, 4, fptr); + label[4] = 0; + + if (isAlphaStr(label) == 0) return -1; // not a valid label + + // Decode blocks according to their label + if (strcmp(label, fmtStr) == 0) + { + int nLen, nDump; + + // 'fmt ' block + memcpy(header.format.fmt, fmtStr, 4); + + // read length of the format field + fread(&nLen, sizeof(int), 1, fptr); + // swap byte order if necessary + _swap32((unsigned int &)nLen); // int format_len; + header.format.format_len = nLen; + + // calculate how much length differs from expected + nDump = nLen - (sizeof(header.format) - 8); + + // if format_len is larger than expected, read only as much data as we've space for + if (nDump > 0) + { + nLen = sizeof(header.format) - 8; + } + + // read data + fread(&(header.format.fixed), nLen, 1, fptr); + + // swap byte order if necessary + _swap16((unsigned short &)header.format.fixed); // short int fixed; + _swap16((unsigned short &)header.format.channel_number); // short int channel_number; + _swap32((unsigned int &)header.format.sample_rate); // int sample_rate; + _swap32((unsigned int &)header.format.byte_rate); // int byte_rate; + _swap16((unsigned short &)header.format.byte_per_sample); // short int byte_per_sample; + _swap16((unsigned short &)header.format.bits_per_sample); // short int bits_per_sample; + + // if format_len is larger than expected, skip the extra data + if (nDump > 0) + { + fseek(fptr, nDump, SEEK_CUR); + } + + return 0; + } + else if (strcmp(label, dataStr) == 0) + { + // 'data' block + memcpy(header.data.data_field, dataStr, 4); + fread(&(header.data.data_len), sizeof(uint), 1, fptr); + + // swap byte order if necessary + _swap32((unsigned int &)header.data.data_len); + + return 1; + } + else + { + uint len, i; + uint temp; + // unknown block + + // read length + fread(&len, sizeof(len), 1, fptr); + // scan through the block + for (i = 0; i < len; i ++) + { + fread(&temp, 1, 1, fptr); + if (feof(fptr)) return -1; // unexpected eof + } + } + return 0; +} + + +int WavInFile::readWavHeaders() +{ + int res; + + memset(&header, 0, sizeof(header)); + + res = readRIFFBlock(); + if (res) return 1; + // read header blocks until data block is found + do + { + // read header blocks + res = readHeaderBlock(); + if (res < 0) return 1; // error in file structure + } while (res == 0); + // check that all required tags are legal + return checkCharTags(); +} + + +uint WavInFile::getNumChannels() const +{ + return header.format.channel_number; +} + + +uint WavInFile::getNumBits() const +{ + return header.format.bits_per_sample; +} + + +uint WavInFile::getBytesPerSample() const +{ + return getNumChannels() * getNumBits() / 8; +} + + +uint WavInFile::getSampleRate() const +{ + return header.format.sample_rate; +} + + + +uint WavInFile::getDataSizeInBytes() const +{ + return header.data.data_len; +} + + +uint WavInFile::getNumSamples() const +{ + return header.data.data_len / header.format.byte_per_sample; +} + + +uint WavInFile::getLengthMS() const +{ + uint numSamples; + uint sampleRate; + + numSamples = getNumSamples(); + sampleRate = getSampleRate(); + + assert(numSamples < UINT_MAX / 1000); + return (1000 * numSamples / sampleRate); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// Class WavOutFile +// + +WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels) +{ + bytesWritten = 0; + fptr = fopen(fileName, "wb"); + if (fptr == NULL) + { + string msg = "Error : Unable to open file \""; + msg += fileName; + msg += "\" for writing."; + //pmsg = msg.c_str; + throw runtime_error(msg); + } + + fillInHeader(sampleRate, bits, channels); + writeHeader(); +} + + + +WavOutFile::~WavOutFile() +{ + close(); +} + + + +void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels) +{ + // fill in the 'riff' part.. + + // copy string 'RIFF' to riff_char + memcpy(&(header.riff.riff_char), riffStr, 4); + // package_len unknown so far + header.riff.package_len = 0; + // copy string 'WAVE' to wave + memcpy(&(header.riff.wave), waveStr, 4); + + + // fill in the 'format' part.. + + // copy string 'fmt ' to fmt + memcpy(&(header.format.fmt), fmtStr, 4); + + header.format.format_len = 0x10; + header.format.fixed = 1; + header.format.channel_number = (short)channels; + header.format.sample_rate = sampleRate; + header.format.bits_per_sample = (short)bits; + header.format.byte_per_sample = (short)(bits * channels / 8); + header.format.byte_rate = header.format.byte_per_sample * sampleRate; + header.format.sample_rate = sampleRate; + + // fill in the 'data' part.. + + // copy string 'data' to data_field + memcpy(&(header.data.data_field), dataStr, 4); + // data_len unknown so far + header.data.data_len = 0; +} + + +void WavOutFile::finishHeader() +{ + // supplement the file length into the header structure + header.riff.package_len = bytesWritten + 36; + header.data.data_len = bytesWritten; + + writeHeader(); +} + + + +void WavOutFile::writeHeader() +{ + WavHeader hdrTemp; + + // swap byte order if necessary + hdrTemp = header; + _swap32((unsigned int &)hdrTemp.riff.package_len); + _swap32((unsigned int &)hdrTemp.format.format_len); + _swap16((unsigned short &)hdrTemp.format.fixed); + _swap16((unsigned short &)hdrTemp.format.channel_number); + _swap32((unsigned int &)hdrTemp.format.sample_rate); + _swap32((unsigned int &)hdrTemp.format.byte_rate); + _swap16((unsigned short &)hdrTemp.format.byte_per_sample); + _swap16((unsigned short &)hdrTemp.format.bits_per_sample); + _swap32((unsigned int &)hdrTemp.data.data_len); + + // write the supplemented header in the beginning of the file + fseek(fptr, 0, SEEK_SET); + fwrite(&hdrTemp, sizeof(hdrTemp), 1, fptr); + // jump back to the end of the file + fseek(fptr, 0, SEEK_END); +} + + + +void WavOutFile::close() +{ + finishHeader(); + fclose(fptr); + fptr = NULL; +} + + +void WavOutFile::write(const char *buffer, int numElems) +{ + int res; + + if (header.format.bits_per_sample != 8) + { + throw runtime_error("Error: WavOutFile::write(const char*, int) accepts only 8bit samples."); + } + assert(sizeof(char) == 1); + + res = fwrite(buffer, 1, numElems, fptr); + if (res != numElems) + { + throw runtime_error("Error while writing to a wav file."); + } + + bytesWritten += numElems; +} + + +void WavOutFile::write(const short *buffer, int numElems) +{ + int res; + + // 16 bit samples + if (numElems < 1) return; // nothing to do + + if (header.format.bits_per_sample == 8) + { + int i; + char *temp = new char[numElems]; + // convert from 16bit format to 8bit format + for (i = 0; i < numElems; i ++) + { + temp[i] = buffer[i] >> 8; + } + // write in 8bit format + write(temp, numElems); + delete[] temp; + } + else + { + // 16bit format + unsigned short *pTemp = new unsigned short[numElems]; + + assert(header.format.bits_per_sample == 16); + + // allocate temp buffer to swap byte order if necessary + memcpy(pTemp, buffer, numElems * 2); + _swap16Buffer(pTemp, numElems); + + res = fwrite(pTemp, 2, numElems, fptr); + + delete[] pTemp; + + if (res != numElems) + { + throw runtime_error("Error while writing to a wav file."); + } + bytesWritten += 2 * numElems; + } +} + + +void WavOutFile::write(const float *buffer, int numElems) +{ + int i; + short *temp = new short[numElems]; + int iTemp; + + // convert to 16 bit integer + for (i = 0; i < numElems; i ++) + { + // convert to integer + iTemp = (int)(32768.0f * buffer[i]); + + // saturate + if (iTemp < -32768) iTemp = -32768; + if (iTemp > 32767) iTemp = 32767; + temp[i] = (short)iTemp; + } + + write(temp, numElems); + + delete[] temp; +} diff --git a/plugins/zerospu2/3rdparty/SoundTouch/WavFile.h b/plugins/zerospu2/3rdparty/SoundTouch/WavFile.h index dd239034d2..331ef4d3e9 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/WavFile.h +++ b/plugins/zerospu2/3rdparty/SoundTouch/WavFile.h @@ -1,253 +1,253 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Classes for easy reading & writing of WAV sound files. -/// -/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly -/// parse the WAV files with such processors. -/// -/// Admittingly, more complete WAV reader routines may exist in public domain, but -/// the reason for 'yet another' one is that those generic WAV reader libraries are -/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e. -/// something that's not already larger than rest of the SoundTouch/SoundStretch program... -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.7 $ -// -// $Id: WavFile.h,v 1.7 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef WAVFILE_H -#define WAVFILE_H - -#include - -#ifndef uint -typedef unsigned int uint; -#endif - - -/// WAV audio file 'riff' section header -typedef struct -{ - char riff_char[4]; - int package_len; - char wave[4]; -} WavRiff; - -/// WAV audio file 'format' section header -typedef struct -{ - char fmt[4]; - int format_len; - short fixed; - short channel_number; - int sample_rate; - int byte_rate; - short byte_per_sample; - short bits_per_sample; -} WavFormat; - -/// WAV audio file 'data' section header -typedef struct -{ - char data_field[4]; - uint data_len; -} WavData; - - -/// WAV audio file header -typedef struct -{ - WavRiff riff; - WavFormat format; - WavData data; -} WavHeader; - - -/// Class for reading WAV audio files. -class WavInFile -{ -private: - /// File pointer. - FILE *fptr; - - /// Counter of how many bytes of sample data have been read from the file. - uint dataRead; - - /// WAV header information - WavHeader header; - - /// Read WAV file headers. - /// \return zero if all ok, nonzero if file format is invalid. - int readWavHeaders(); - - /// Checks WAV file header tags. - /// \return zero if all ok, nonzero if file format is invalid. - int checkCharTags(); - - /// Reads a single WAV file header block. - /// \return zero if all ok, nonzero if file format is invalid. - int readHeaderBlock(); - - /// Reads WAV file 'riff' block - int readRIFFBlock(); - -public: - /// Constructor: Opens the given WAV file. If the file can't be opened, - /// throws 'runtime_error' exception. - WavInFile(const char *filename); - - /// Destructor: Closes the file. - ~WavInFile(); - - /// Close the file. Notice that file is automatically closed also when the - /// class instance is deleted. - void close(); - - /// Rewind to beginning of the file - void rewind(); - - /// Get sample rate. - uint getSampleRate() const; - - /// Get number of bits per sample, i.e. 8 or 16. - uint getNumBits() const; - - /// Get sample data size in bytes. Ahem, this should return same information as - /// 'getBytesPerSample'... - uint getDataSizeInBytes() const; - - /// Get total number of samples in file. - uint getNumSamples() const; - - /// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample) - uint getBytesPerSample() const; - - /// Get number of audio channels in the file (1=mono, 2=stereo) - uint getNumChannels() const; - - /// Get the audio file length in milliseconds - uint getLengthMS() const; - - /// Reads audio samples from the WAV file. This routine works only for 8 bit samples. - /// Reads given number of elements from the file or if end-of-file reached, as many - /// elements as are left in the file. - /// - /// \return Number of 8-bit integers read from the file. - int read(char *buffer, int maxElems); - - /// Reads audio samples from the WAV file to 16 bit integer format. Reads given number - /// of elements from the file or if end-of-file reached, as many elements as are - /// left in the file. - /// - /// \return Number of 16-bit integers read from the file. - int read(short *buffer, ///< Pointer to buffer where to read data. - int maxElems ///< Size of 'buffer' array (number of array elements). - ); - - /// Reads audio samples from the WAV file to floating point format, converting - /// sample values to range [-1,1[. Reads given number of elements from the file - /// or if end-of-file reached, as many elements as are left in the file. - /// - /// \return Number of elements read from the file. - int read(float *buffer, ///< Pointer to buffer where to read data. - int maxElems ///< Size of 'buffer' array (number of array elements). - ); - - /// Check end-of-file. - /// - /// \return Nonzero if end-of-file reached. - int eof() const; -}; - - - -/// Class for writing WAV audio files. -class WavOutFile -{ -private: - /// Pointer to the WAV file - FILE *fptr; - - /// WAV file header data. - WavHeader header; - - /// Counter of how many bytes have been written to the file so far. - int bytesWritten; - - /// Fills in WAV file header information. - void fillInHeader(const uint sampleRate, const uint bits, const uint channels); - - /// Finishes the WAV file header by supplementing information of amount of - /// data written to file etc - void finishHeader(); - - /// Writes the WAV file header. - void writeHeader(); - -public: - /// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception - /// if file creation fails. - WavOutFile(const char *fileName, ///< Filename - int sampleRate, ///< Sample rate (e.g. 44100 etc) - int bits, ///< Bits per sample (8 or 16 bits) - int channels ///< Number of channels (1=mono, 2=stereo) - ); - - /// Destructor: Finalizes & closes the WAV file. - ~WavOutFile(); - - /// Write data to WAV file. This function works only with 8bit samples. - /// Throws a 'runtime_error' exception if writing to file fails. - void write(const char *buffer, ///< Pointer to sample data buffer. - int numElems ///< How many array items are to be written to file. - ); - - /// Write data to WAV file. Throws a 'runtime_error' exception if writing to - /// file fails. - void write(const short *buffer, ///< Pointer to sample data buffer. - int numElems ///< How many array items are to be written to file. - ); - - /// Write data to WAV file in floating point format, saturating sample values to range - /// [-1..+1[. Throws a 'runtime_error' exception if writing to file fails. - void write(const float *buffer, ///< Pointer to sample data buffer. - int numElems ///< How many array items are to be written to file. - ); - - /// Finalize & close the WAV file. Automatically supplements the WAV file header - /// information according to written data etc. - /// - /// Notice that file is automatically closed also when the class instance is deleted. - void close(); -}; - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// Classes for easy reading & writing of WAV sound files. +/// +/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly +/// parse the WAV files with such processors. +/// +/// Admittingly, more complete WAV reader routines may exist in public domain, but +/// the reason for 'yet another' one is that those generic WAV reader libraries are +/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e. +/// something that's not already larger than rest of the SoundTouch/SoundStretch program... +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.7 $ +// +// $Id: WavFile.h,v 1.7 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef WAVFILE_H +#define WAVFILE_H + +#include + +#ifndef uint +typedef unsigned int uint; +#endif + + +/// WAV audio file 'riff' section header +typedef struct +{ + char riff_char[4]; + int package_len; + char wave[4]; +} WavRiff; + +/// WAV audio file 'format' section header +typedef struct +{ + char fmt[4]; + int format_len; + short fixed; + short channel_number; + int sample_rate; + int byte_rate; + short byte_per_sample; + short bits_per_sample; +} WavFormat; + +/// WAV audio file 'data' section header +typedef struct +{ + char data_field[4]; + uint data_len; +} WavData; + + +/// WAV audio file header +typedef struct +{ + WavRiff riff; + WavFormat format; + WavData data; +} WavHeader; + + +/// Class for reading WAV audio files. +class WavInFile +{ +private: + /// File pointer. + FILE *fptr; + + /// Counter of how many bytes of sample data have been read from the file. + uint dataRead; + + /// WAV header information + WavHeader header; + + /// Read WAV file headers. + /// \return zero if all ok, nonzero if file format is invalid. + int readWavHeaders(); + + /// Checks WAV file header tags. + /// \return zero if all ok, nonzero if file format is invalid. + int checkCharTags(); + + /// Reads a single WAV file header block. + /// \return zero if all ok, nonzero if file format is invalid. + int readHeaderBlock(); + + /// Reads WAV file 'riff' block + int readRIFFBlock(); + +public: + /// Constructor: Opens the given WAV file. If the file can't be opened, + /// throws 'runtime_error' exception. + WavInFile(const char *filename); + + /// Destructor: Closes the file. + ~WavInFile(); + + /// Close the file. Notice that file is automatically closed also when the + /// class instance is deleted. + void close(); + + /// Rewind to beginning of the file + void rewind(); + + /// Get sample rate. + uint getSampleRate() const; + + /// Get number of bits per sample, i.e. 8 or 16. + uint getNumBits() const; + + /// Get sample data size in bytes. Ahem, this should return same information as + /// 'getBytesPerSample'... + uint getDataSizeInBytes() const; + + /// Get total number of samples in file. + uint getNumSamples() const; + + /// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample) + uint getBytesPerSample() const; + + /// Get number of audio channels in the file (1=mono, 2=stereo) + uint getNumChannels() const; + + /// Get the audio file length in milliseconds + uint getLengthMS() const; + + /// Reads audio samples from the WAV file. This routine works only for 8 bit samples. + /// Reads given number of elements from the file or if end-of-file reached, as many + /// elements as are left in the file. + /// + /// \return Number of 8-bit integers read from the file. + int read(char *buffer, int maxElems); + + /// Reads audio samples from the WAV file to 16 bit integer format. Reads given number + /// of elements from the file or if end-of-file reached, as many elements as are + /// left in the file. + /// + /// \return Number of 16-bit integers read from the file. + int read(short *buffer, ///< Pointer to buffer where to read data. + int maxElems ///< Size of 'buffer' array (number of array elements). + ); + + /// Reads audio samples from the WAV file to floating point format, converting + /// sample values to range [-1,1[. Reads given number of elements from the file + /// or if end-of-file reached, as many elements as are left in the file. + /// + /// \return Number of elements read from the file. + int read(float *buffer, ///< Pointer to buffer where to read data. + int maxElems ///< Size of 'buffer' array (number of array elements). + ); + + /// Check end-of-file. + /// + /// \return Nonzero if end-of-file reached. + int eof() const; +}; + + + +/// Class for writing WAV audio files. +class WavOutFile +{ +private: + /// Pointer to the WAV file + FILE *fptr; + + /// WAV file header data. + WavHeader header; + + /// Counter of how many bytes have been written to the file so far. + int bytesWritten; + + /// Fills in WAV file header information. + void fillInHeader(const uint sampleRate, const uint bits, const uint channels); + + /// Finishes the WAV file header by supplementing information of amount of + /// data written to file etc + void finishHeader(); + + /// Writes the WAV file header. + void writeHeader(); + +public: + /// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception + /// if file creation fails. + WavOutFile(const char *fileName, ///< Filename + int sampleRate, ///< Sample rate (e.g. 44100 etc) + int bits, ///< Bits per sample (8 or 16 bits) + int channels ///< Number of channels (1=mono, 2=stereo) + ); + + /// Destructor: Finalizes & closes the WAV file. + ~WavOutFile(); + + /// Write data to WAV file. This function works only with 8bit samples. + /// Throws a 'runtime_error' exception if writing to file fails. + void write(const char *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Write data to WAV file. Throws a 'runtime_error' exception if writing to + /// file fails. + void write(const short *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Write data to WAV file in floating point format, saturating sample values to range + /// [-1..+1[. Throws a 'runtime_error' exception if writing to file fails. + void write(const float *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Finalize & close the WAV file. Automatically supplements the WAV file header + /// information according to written data etc. + /// + /// Notice that file is automatically closed also when the class instance is deleted. + void close(); +}; + +#endif diff --git a/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect.h b/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect.h index 568817f17b..69892102c9 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect.h +++ b/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect.h @@ -1,62 +1,62 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// A header file for detecting the Intel MMX instructions set extension. -/// -/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the -/// routine implementations for x86 Windows, x86 gnu version and non-x86 -/// platforms, respectively. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.4 $ -// -// $Id: cpu_detect.h,v 1.4 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef _CPU_DETECT_H_ -#define _CPU_DETECT_H_ - -#include "STTypes.h" - -#define SUPPORT_MMX 0x0001 -#define SUPPORT_3DNOW 0x0002 -#define SUPPORT_ALTIVEC 0x0004 -#define SUPPORT_SSE 0x0008 -#define SUPPORT_SSE2 0x0010 - -/// Checks which instruction set extensions are supported by the CPU. -/// -/// \return A bitmask of supported extensions, see SUPPORT_... defines. -uint detectCPUextensions(void); - -/// Disables given set of instruction extensions. See SUPPORT_... defines. -void disableExtensions(uint wDisableMask); - -#endif // _CPU_DETECT_H_ +//////////////////////////////////////////////////////////////////////////////// +/// +/// A header file for detecting the Intel MMX instructions set extension. +/// +/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the +/// routine implementations for x86 Windows, x86 gnu version and non-x86 +/// platforms, respectively. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.4 $ +// +// $Id: cpu_detect.h,v 1.4 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _CPU_DETECT_H_ +#define _CPU_DETECT_H_ + +#include "STTypes.h" + +#define SUPPORT_MMX 0x0001 +#define SUPPORT_3DNOW 0x0002 +#define SUPPORT_ALTIVEC 0x0004 +#define SUPPORT_SSE 0x0008 +#define SUPPORT_SSE2 0x0010 + +/// Checks which instruction set extensions are supported by the CPU. +/// +/// \return A bitmask of supported extensions, see SUPPORT_... defines. +uint detectCPUextensions(void); + +/// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint wDisableMask); + +#endif // _CPU_DETECT_H_ diff --git a/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp b/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp index 75bd771099..68423c3a0e 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp +++ b/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp @@ -1,138 +1,138 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// gcc version of the x86 CPU detect routine. -/// -/// This file is to be compiled on any platform with the GNU C compiler. -/// Compiler. Please see 'cpu_detect_x86_win.cpp' for the x86 Windows version -/// of this file. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.6 $ -// -// $Id: cpu_detect_x86_gcc.cpp,v 1.6 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include "cpu_detect.h" - -#ifndef __GNUC__ -#error wrong platform - this source code file is for the GNU C compiler. -#endif - -using namespace std; - -#include -////////////////////////////////////////////////////////////////////////////// -// -// processor instructions extension detection routines -// -////////////////////////////////////////////////////////////////////////////// - - -// Flag variable indicating whick ISA extensions are disabled (for debugging) -static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions - -// Disables given set of instruction extensions. See SUPPORT_... defines. -void disableExtensions(uint dwDisableMask) -{ - _dwDisabledISA = dwDisableMask; -} - - - -/// Checks which instruction set extensions are supported by the CPU. -uint detectCPUextensions(void) -{ -#ifndef __i386__ - return 0; // always disable extensions on non-x86 platforms. -#else - uint res = 0; - - if (_dwDisabledISA == 0xffffffff) return 0; - - asm volatile( - "\n\txor %%esi, %%esi" // clear %%esi = result register - // check if 'cpuid' instructions is available by toggling eflags bit 21 - - "\n\tpushf" // save eflags to stack - "\n\tpop %%eax" // load eax from stack (with eflags) - "\n\tmovl %%eax, %%ecx" // save the original eflags values to ecx - "\n\txor $0x00200000, %%eax" // toggle bit 21 - "\n\tpush %%eax" // store toggled eflags to stack - "\n\tpopf" // load eflags from stack - "\n\tpushf" // save updated eflags to stack - "\n\tpop %%eax" // load from stack - "\n\txor %%edx, %%edx" // clear edx for defaulting no mmx - "\n\tcmp %%ecx, %%eax" // compare to original eflags values - "\n\tjz end" // jumps to 'end' if cpuid not present - - // cpuid instruction available, test for presence of mmx instructions - - "\n\tmovl $1, %%eax" - "\n\tcpuid" -// movl $0x00800000, %edx // force enable MMX - "\n\ttest $0x00800000, %%edx" - "\n\tjz end" // branch if MMX not available - - "\n\tor $0x01, %%esi" // otherwise add MMX support bit - - "\n\ttest $0x02000000, %%edx" - "\n\tjz test3DNow" // branch if SSE not available - - "\n\tor $0x08, %%esi" // otherwise add SSE support bit - - "\n\ttest3DNow:" - // test for precense of AMD extensions - "\n\tmov $0x80000000, %%eax" - "\n\tcpuid" - "\n\tcmp $0x80000000, %%eax" - "\n\tjbe end" // branch if no AMD extensions detected - - // test for precense of 3DNow! extension - "\n\tmov $0x80000001, %%eax" - "\n\tcpuid" - "\n\ttest $0x80000000, %%edx" - "\n\tjz end" // branch if 3DNow! not detected - - "\n\tor $0x02, %%esi" // otherwise add 3DNow support bit - - "\n\tend:" - - "\n\tmov %%esi, %0" - - : "=r" (res) - : /* no inputs */ - : "%edx", "%eax", "%ecx", "%esi" ); - - return res & ~_dwDisabledISA; -#endif -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// gcc version of the x86 CPU detect routine. +/// +/// This file is to be compiled on any platform with the GNU C compiler. +/// Compiler. Please see 'cpu_detect_x86_win.cpp' for the x86 Windows version +/// of this file. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.6 $ +// +// $Id: cpu_detect_x86_gcc.cpp,v 1.6 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "cpu_detect.h" + +#ifndef __GNUC__ +#error wrong platform - this source code file is for the GNU C compiler. +#endif + +using namespace std; + +#include +////////////////////////////////////////////////////////////////////////////// +// +// processor instructions extension detection routines +// +////////////////////////////////////////////////////////////////////////////// + + +// Flag variable indicating whick ISA extensions are disabled (for debugging) +static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions + +// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint dwDisableMask) +{ + _dwDisabledISA = dwDisableMask; +} + + + +/// Checks which instruction set extensions are supported by the CPU. +uint detectCPUextensions(void) +{ +#ifndef __i386__ + return 0; // always disable extensions on non-x86 platforms. +#else + uint res = 0; + + if (_dwDisabledISA == 0xffffffff) return 0; + + asm volatile( + "\n\txor %%esi, %%esi" // clear %%esi = result register + // check if 'cpuid' instructions is available by toggling eflags bit 21 + + "\n\tpushf" // save eflags to stack + "\n\tpop %%eax" // load eax from stack (with eflags) + "\n\tmovl %%eax, %%ecx" // save the original eflags values to ecx + "\n\txor $0x00200000, %%eax" // toggle bit 21 + "\n\tpush %%eax" // store toggled eflags to stack + "\n\tpopf" // load eflags from stack + "\n\tpushf" // save updated eflags to stack + "\n\tpop %%eax" // load from stack + "\n\txor %%edx, %%edx" // clear edx for defaulting no mmx + "\n\tcmp %%ecx, %%eax" // compare to original eflags values + "\n\tjz end" // jumps to 'end' if cpuid not present + + // cpuid instruction available, test for presence of mmx instructions + + "\n\tmovl $1, %%eax" + "\n\tcpuid" +// movl $0x00800000, %edx // force enable MMX + "\n\ttest $0x00800000, %%edx" + "\n\tjz end" // branch if MMX not available + + "\n\tor $0x01, %%esi" // otherwise add MMX support bit + + "\n\ttest $0x02000000, %%edx" + "\n\tjz test3DNow" // branch if SSE not available + + "\n\tor $0x08, %%esi" // otherwise add SSE support bit + + "\n\ttest3DNow:" + // test for precense of AMD extensions + "\n\tmov $0x80000000, %%eax" + "\n\tcpuid" + "\n\tcmp $0x80000000, %%eax" + "\n\tjbe end" // branch if no AMD extensions detected + + // test for precense of 3DNow! extension + "\n\tmov $0x80000001, %%eax" + "\n\tcpuid" + "\n\ttest $0x80000000, %%edx" + "\n\tjz end" // branch if 3DNow! not detected + + "\n\tor $0x02, %%esi" // otherwise add 3DNow support bit + + "\n\tend:" + + "\n\tmov %%esi, %0" + + : "=r" (res) + : /* no inputs */ + : "%edx", "%eax", "%ecx", "%esi" ); + + return res & ~_dwDisabledISA; +#endif +} diff --git a/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect_x86_win.cpp b/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect_x86_win.cpp index d8f9e58dd0..ee3acf69f7 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect_x86_win.cpp +++ b/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect_x86_win.cpp @@ -1,126 +1,126 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Win32 version of the x86 CPU detect routine. -/// -/// This file is to be compiled in Windows platform with Microsoft Visual C++ -/// Compiler. Please see 'cpu_detect_x86_gcc.cpp' for the gcc compiler version -/// for all GNU platforms. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.10 $ -// -// $Id: cpu_detect_x86_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include "cpu_detect.h" - -#ifndef _WIN32 -#error wrong platform - this source code file is exclusively for Win32 platform -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// processor instructions extension detection routines -// -////////////////////////////////////////////////////////////////////////////// - -// Flag variable indicating whick ISA extensions are disabled (for debugging) -static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions - - -// Disables given set of instruction extensions. See SUPPORT_... defines. -void disableExtensions(uint dwDisableMask) -{ - _dwDisabledISA = dwDisableMask; -} - - - -/// Checks which instruction set extensions are supported by the CPU. -uint detectCPUextensions(void) -{ - uint res = 0; - - if (_dwDisabledISA == 0xffffffff) return 0; - - _asm - { - ; check if 'cpuid' instructions is available by toggling eflags bit 21 - ; - xor esi, esi ; clear esi = result register - - pushfd ; save eflags to stack - pop eax ; load eax from stack (with eflags) - mov ecx, eax ; save the original eflags values to ecx - xor eax, 0x00200000 ; toggle bit 21 - push eax ; store toggled eflags to stack - popfd ; load eflags from stack - pushfd ; save updated eflags to stack - pop eax ; load from stack - xor edx, edx ; clear edx for defaulting no mmx - cmp eax, ecx ; compare to original eflags values - jz end ; jumps to 'end' if cpuid not present - - ; cpuid instruction available, test for presence of mmx instructions - mov eax, 1 - cpuid - test edx, 0x00800000 - jz end ; branch if MMX not available - - or esi, SUPPORT_MMX ; otherwise add MMX support bit - - test edx, 0x02000000 - jz test3DNow ; branch if SSE not available - - or esi, SUPPORT_SSE ; otherwise add SSE support bit - - test3DNow: - ; test for precense of AMD extensions - mov eax, 0x80000000 - cpuid - cmp eax, 0x80000000 - jbe end ; branch if no AMD extensions detected - - ; test for precense of 3DNow! extension - mov eax, 0x80000001 - cpuid - test edx, 0x80000000 - jz end ; branch if 3DNow! not detected - - or esi, SUPPORT_3DNOW ; otherwise add 3DNow support bit - - end: - - mov res, esi - } - - return res & ~_dwDisabledISA; -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// Win32 version of the x86 CPU detect routine. +/// +/// This file is to be compiled in Windows platform with Microsoft Visual C++ +/// Compiler. Please see 'cpu_detect_x86_gcc.cpp' for the gcc compiler version +/// for all GNU platforms. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: cpu_detect_x86_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" + +#ifndef _WIN32 +#error wrong platform - this source code file is exclusively for Win32 platform +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// processor instructions extension detection routines +// +////////////////////////////////////////////////////////////////////////////// + +// Flag variable indicating whick ISA extensions are disabled (for debugging) +static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions + + +// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint dwDisableMask) +{ + _dwDisabledISA = dwDisableMask; +} + + + +/// Checks which instruction set extensions are supported by the CPU. +uint detectCPUextensions(void) +{ + uint res = 0; + + if (_dwDisabledISA == 0xffffffff) return 0; + + _asm + { + ; check if 'cpuid' instructions is available by toggling eflags bit 21 + ; + xor esi, esi ; clear esi = result register + + pushfd ; save eflags to stack + pop eax ; load eax from stack (with eflags) + mov ecx, eax ; save the original eflags values to ecx + xor eax, 0x00200000 ; toggle bit 21 + push eax ; store toggled eflags to stack + popfd ; load eflags from stack + pushfd ; save updated eflags to stack + pop eax ; load from stack + xor edx, edx ; clear edx for defaulting no mmx + cmp eax, ecx ; compare to original eflags values + jz end ; jumps to 'end' if cpuid not present + + ; cpuid instruction available, test for presence of mmx instructions + mov eax, 1 + cpuid + test edx, 0x00800000 + jz end ; branch if MMX not available + + or esi, SUPPORT_MMX ; otherwise add MMX support bit + + test edx, 0x02000000 + jz test3DNow ; branch if SSE not available + + or esi, SUPPORT_SSE ; otherwise add SSE support bit + + test3DNow: + ; test for precense of AMD extensions + mov eax, 0x80000000 + cpuid + cmp eax, 0x80000000 + jbe end ; branch if no AMD extensions detected + + ; test for precense of 3DNow! extension + mov eax, 0x80000001 + cpuid + test edx, 0x80000000 + jz end ; branch if 3DNow! not detected + + or esi, SUPPORT_3DNOW ; otherwise add 3DNow support bit + + end: + + mov res, esi + } + + return res & ~_dwDisabledISA; +} diff --git a/plugins/zerospu2/3rdparty/SoundTouch/mmx_optimized.cpp b/plugins/zerospu2/3rdparty/SoundTouch/mmx_optimized.cpp index f5afb595a5..b49584b694 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/mmx_optimized.cpp +++ b/plugins/zerospu2/3rdparty/SoundTouch/mmx_optimized.cpp @@ -1,305 +1,305 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// MMX optimized routines. All MMX optimized functions have been gathered into -/// this single source code file, regardless to their class or original source -/// code file, in order to ease porting the library to other compiler and -/// processor platforms. -/// -/// The MMX-optimizations are programmed using MMX compiler intrinsics that -/// are supported both by Microsoft Visual C++ and GCC compilers, so this file -/// should compile with both toolsets. -/// -/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ -/// 6.0 processor pack" update to support compiler intrinsic syntax. The update -/// is available for download at Microsoft Developers Network, see here: -/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/06 18:52:43 $ -// File revision : $Revision: 1.1 $ -// -// $Id: mmx_optimized.cpp,v 1.1 2006/02/06 18:52:43 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include "STTypes.h" - -#ifdef ALLOW_MMX -// MMX routines available only with integer sample type - -#if !(_WIN32 || __i386__ || __x86_64__) -#error "wrong platform - this source code file is exclusively for x86 platforms" -#endif - -using namespace soundtouch; - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of MMX optimized functions of class 'TDStretchMMX' -// -////////////////////////////////////////////////////////////////////////////// - -#include "TDStretch.h" -#include -#include - - -// Calculates cross correlation of two buffers -long TDStretchMMX::calcCrossCorrStereo(const short *pV1, const short *pV2) const -{ - const __m64 *pVec1, *pVec2; - __m64 shifter; - __m64 accu; - long corr; - uint i; - - pVec1 = (__m64*)pV1; - pVec2 = (__m64*)pV2; - - shifter = _m_from_int(overlapDividerBits); - accu = _mm_setzero_si64(); - - // Process 4 parallel sets of 2 * stereo samples each during each - // round to improve CPU-level parallellization. - for (i = 0; i < overlapLength / 8; i ++) - { - __m64 temp; - - // dictionary of instructions: - // _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3] - // _mm_add_pi32 : 2*32bit add - // _m_psrad : 32bit right-shift - - temp = _mm_add_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), - _mm_madd_pi16(pVec1[1], pVec2[1])); - accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); - - temp = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), - _mm_madd_pi16(pVec1[3], pVec2[3])); - accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); - - pVec1 += 4; - pVec2 += 4; - } - - // copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1 - // and finally store the result into the variable "corr" - - accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32)); - corr = _m_to_int(accu); - - // Clear MMS state - _m_empty(); - - return corr; - // Note: Warning about the missing EMMS instruction is harmless - // as it'll be called elsewhere. -} - - - -void TDStretchMMX::clearCrossCorrState() -{ - // Clear MMS state - _m_empty(); - //_asm EMMS; -} - - - -// MMX-optimized version of the function overlapStereo -void TDStretchMMX::overlapStereo(short *output, const short *input) const -{ - const __m64 *pVinput, *pVMidBuf; - __m64 *pVdest; - __m64 mix1, mix2, adder, shifter; - uint i; - - pVinput = (const __m64*)input; - pVMidBuf = (const __m64*)pMidBuffer; - pVdest = (__m64*)output; - - // mix1 = mixer values for 1st stereo sample - // mix1 = mixer values for 2nd stereo sample - // adder = adder for updating mixer values after each round - - mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength); - adder = _mm_set_pi16(1, -1, 1, -1); - mix2 = _mm_add_pi16(mix1, adder); - adder = _mm_add_pi16(adder, adder); - - shifter = _m_from_int(overlapDividerBits); - - for (i = 0; i < overlapLength / 4; i ++) - { - __m64 temp1, temp2; - - // load & shuffle data so that input & mixbuffer data samples are paired - temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r - temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r - - // temp = (temp .* mix) >> shifter - temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); - temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); - pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit - - // update mix += adder - mix1 = _mm_add_pi16(mix1, adder); - mix2 = _mm_add_pi16(mix2, adder); - - // --- second round begins here --- - - // load & shuffle data so that input & mixbuffer data samples are paired - temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]); // = i2l m2l i2r m2r - temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]); // = i3l m3l i3r m3r - - // temp = (temp .* mix) >> shifter - temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); - temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); - pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit - - // update mix += adder - mix1 = _mm_add_pi16(mix1, adder); - mix2 = _mm_add_pi16(mix2, adder); - - pVinput += 2; - pVMidBuf += 2; - pVdest += 2; - } - - _m_empty(); // clear MMS state -} - - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of MMX optimized functions of class 'FIRFilter' -// -////////////////////////////////////////////////////////////////////////////// - -#include "FIRFilter.h" - - -FIRFilterMMX::FIRFilterMMX() : FIRFilter() -{ - filterCoeffsUnalign = NULL; -} - - -FIRFilterMMX::~FIRFilterMMX() -{ - delete[] filterCoeffsUnalign; -} - - -// (overloaded) Calculates filter coefficients for MMX routine -void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor) -{ - uint i; - FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); - - // Ensure that filter coeffs array is aligned to 16-byte boundary - delete[] filterCoeffsUnalign; - filterCoeffsUnalign = new short[2 * newLength + 8]; - filterCoeffsAlign = (short *)(((ulongptr)filterCoeffsUnalign + 15) & -16); - - // rearrange the filter coefficients for mmx routines - for (i = 0;i < length; i += 4) - { - filterCoeffsAlign[2 * i + 0] = coeffs[i + 0]; - filterCoeffsAlign[2 * i + 1] = coeffs[i + 2]; - filterCoeffsAlign[2 * i + 2] = coeffs[i + 0]; - filterCoeffsAlign[2 * i + 3] = coeffs[i + 2]; - - filterCoeffsAlign[2 * i + 4] = coeffs[i + 1]; - filterCoeffsAlign[2 * i + 5] = coeffs[i + 3]; - filterCoeffsAlign[2 * i + 6] = coeffs[i + 1]; - filterCoeffsAlign[2 * i + 7] = coeffs[i + 3]; - } -} - - - -// mmx-optimized version of the filter routine for stereo sound -uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, const uint numSamples) const -{ - // Create stack copies of the needed member variables for asm routines : - uint i, j; - __m64 *pVdest = (__m64*)dest; - - if (length < 2) return 0; - - for (i = 0; i < numSamples / 2; i ++) - { - __m64 accu1; - __m64 accu2; - const __m64 *pVsrc = (const __m64*)src; - const __m64 *pVfilter = (const __m64*)filterCoeffsAlign; - - accu1 = accu2 = _mm_setzero_si64(); - for (j = 0; j < lengthDiv8 * 2; j ++) - { - __m64 temp1, temp2; - - temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]); // = l2 l0 r2 r0 - temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]); // = l3 l1 r3 r1 - - accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0])); // += l2*f2+l0*f0 r2*f2+r0*f0 - accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1])); // += l3*f3+l1*f1 r3*f3+r1*f1 - - temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]); // = l4 l2 r4 r2 - - accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0])); // += l3*f2+l1*f0 r3*f2+r1*f0 - accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1])); // += l4*f3+l2*f1 r4*f3+r2*f1 - - // accu1 += l2*f2+l0*f0 r2*f2+r0*f0 - // += l3*f3+l1*f1 r3*f3+r1*f1 - - // accu2 += l3*f2+l1*f0 r3*f2+r1*f0 - // l4*f3+l2*f1 r4*f3+r2*f1 - - pVfilter += 2; - pVsrc += 2; - } - // accu >>= resultDivFactor - accu1 = _mm_srai_pi32(accu1, resultDivFactor); - accu2 = _mm_srai_pi32(accu2, resultDivFactor); - - // pack 2*2*32bits => 4*16 bits - pVdest[0] = _mm_packs_pi32(accu1, accu2); - src += 4; - pVdest ++; - } - - _m_empty(); // clear emms state - - return (numSamples & 0xfffffffe) - length; -} - -#endif // ALLOW_MMX +//////////////////////////////////////////////////////////////////////////////// +/// +/// MMX optimized routines. All MMX optimized functions have been gathered into +/// this single source code file, regardless to their class or original source +/// code file, in order to ease porting the library to other compiler and +/// processor platforms. +/// +/// The MMX-optimizations are programmed using MMX compiler intrinsics that +/// are supported both by Microsoft Visual C++ and GCC compilers, so this file +/// should compile with both toolsets. +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support compiler intrinsic syntax. The update +/// is available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/06 18:52:43 $ +// File revision : $Revision: 1.1 $ +// +// $Id: mmx_optimized.cpp,v 1.1 2006/02/06 18:52:43 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "STTypes.h" + +#ifdef ALLOW_MMX +// MMX routines available only with integer sample type + +#if !(_WIN32 || __i386__ || __x86_64__) +#error "wrong platform - this source code file is exclusively for x86 platforms" +#endif + +using namespace soundtouch; + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of MMX optimized functions of class 'TDStretchMMX' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include +#include + + +// Calculates cross correlation of two buffers +long TDStretchMMX::calcCrossCorrStereo(const short *pV1, const short *pV2) const +{ + const __m64 *pVec1, *pVec2; + __m64 shifter; + __m64 accu; + long corr; + uint i; + + pVec1 = (__m64*)pV1; + pVec2 = (__m64*)pV2; + + shifter = _m_from_int(overlapDividerBits); + accu = _mm_setzero_si64(); + + // Process 4 parallel sets of 2 * stereo samples each during each + // round to improve CPU-level parallellization. + for (i = 0; i < overlapLength / 8; i ++) + { + __m64 temp; + + // dictionary of instructions: + // _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3] + // _mm_add_pi32 : 2*32bit add + // _m_psrad : 32bit right-shift + + temp = _mm_add_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), + _mm_madd_pi16(pVec1[1], pVec2[1])); + accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); + + temp = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), + _mm_madd_pi16(pVec1[3], pVec2[3])); + accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); + + pVec1 += 4; + pVec2 += 4; + } + + // copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1 + // and finally store the result into the variable "corr" + + accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32)); + corr = _m_to_int(accu); + + // Clear MMS state + _m_empty(); + + return corr; + // Note: Warning about the missing EMMS instruction is harmless + // as it'll be called elsewhere. +} + + + +void TDStretchMMX::clearCrossCorrState() +{ + // Clear MMS state + _m_empty(); + //_asm EMMS; +} + + + +// MMX-optimized version of the function overlapStereo +void TDStretchMMX::overlapStereo(short *output, const short *input) const +{ + const __m64 *pVinput, *pVMidBuf; + __m64 *pVdest; + __m64 mix1, mix2, adder, shifter; + uint i; + + pVinput = (const __m64*)input; + pVMidBuf = (const __m64*)pMidBuffer; + pVdest = (__m64*)output; + + // mix1 = mixer values for 1st stereo sample + // mix1 = mixer values for 2nd stereo sample + // adder = adder for updating mixer values after each round + + mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength); + adder = _mm_set_pi16(1, -1, 1, -1); + mix2 = _mm_add_pi16(mix1, adder); + adder = _mm_add_pi16(adder, adder); + + shifter = _m_from_int(overlapDividerBits); + + for (i = 0; i < overlapLength / 4; i ++) + { + __m64 temp1, temp2; + + // load & shuffle data so that input & mixbuffer data samples are paired + temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r + temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r + + // temp = (temp .* mix) >> shifter + temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); + temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); + pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit + + // update mix += adder + mix1 = _mm_add_pi16(mix1, adder); + mix2 = _mm_add_pi16(mix2, adder); + + // --- second round begins here --- + + // load & shuffle data so that input & mixbuffer data samples are paired + temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]); // = i2l m2l i2r m2r + temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]); // = i3l m3l i3r m3r + + // temp = (temp .* mix) >> shifter + temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); + temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); + pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit + + // update mix += adder + mix1 = _mm_add_pi16(mix1, adder); + mix2 = _mm_add_pi16(mix2, adder); + + pVinput += 2; + pVMidBuf += 2; + pVdest += 2; + } + + _m_empty(); // clear MMS state +} + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of MMX optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + + +FIRFilterMMX::FIRFilterMMX() : FIRFilter() +{ + filterCoeffsUnalign = NULL; +} + + +FIRFilterMMX::~FIRFilterMMX() +{ + delete[] filterCoeffsUnalign; +} + + +// (overloaded) Calculates filter coefficients for MMX routine +void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new short[2 * newLength + 8]; + filterCoeffsAlign = (short *)(((ulongptr)filterCoeffsUnalign + 15) & -16); + + // rearrange the filter coefficients for mmx routines + for (i = 0;i < length; i += 4) + { + filterCoeffsAlign[2 * i + 0] = coeffs[i + 0]; + filterCoeffsAlign[2 * i + 1] = coeffs[i + 2]; + filterCoeffsAlign[2 * i + 2] = coeffs[i + 0]; + filterCoeffsAlign[2 * i + 3] = coeffs[i + 2]; + + filterCoeffsAlign[2 * i + 4] = coeffs[i + 1]; + filterCoeffsAlign[2 * i + 5] = coeffs[i + 3]; + filterCoeffsAlign[2 * i + 6] = coeffs[i + 1]; + filterCoeffsAlign[2 * i + 7] = coeffs[i + 3]; + } +} + + + +// mmx-optimized version of the filter routine for stereo sound +uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, const uint numSamples) const +{ + // Create stack copies of the needed member variables for asm routines : + uint i, j; + __m64 *pVdest = (__m64*)dest; + + if (length < 2) return 0; + + for (i = 0; i < numSamples / 2; i ++) + { + __m64 accu1; + __m64 accu2; + const __m64 *pVsrc = (const __m64*)src; + const __m64 *pVfilter = (const __m64*)filterCoeffsAlign; + + accu1 = accu2 = _mm_setzero_si64(); + for (j = 0; j < lengthDiv8 * 2; j ++) + { + __m64 temp1, temp2; + + temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]); // = l2 l0 r2 r0 + temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]); // = l3 l1 r3 r1 + + accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0])); // += l2*f2+l0*f0 r2*f2+r0*f0 + accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1])); // += l3*f3+l1*f1 r3*f3+r1*f1 + + temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]); // = l4 l2 r4 r2 + + accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0])); // += l3*f2+l1*f0 r3*f2+r1*f0 + accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1])); // += l4*f3+l2*f1 r4*f3+r2*f1 + + // accu1 += l2*f2+l0*f0 r2*f2+r0*f0 + // += l3*f3+l1*f1 r3*f3+r1*f1 + + // accu2 += l3*f2+l1*f0 r3*f2+r1*f0 + // l4*f3+l2*f1 r4*f3+r2*f1 + + pVfilter += 2; + pVsrc += 2; + } + // accu >>= resultDivFactor + accu1 = _mm_srai_pi32(accu1, resultDivFactor); + accu2 = _mm_srai_pi32(accu2, resultDivFactor); + + // pack 2*2*32bits => 4*16 bits + pVdest[0] = _mm_packs_pi32(accu1, accu2); + src += 4; + pVdest ++; + } + + _m_empty(); // clear emms state + + return (numSamples & 0xfffffffe) - length; +} + +#endif // ALLOW_MMX diff --git a/plugins/zerospu2/3rdparty/SoundTouch/sse_optimized.cpp b/plugins/zerospu2/3rdparty/SoundTouch/sse_optimized.cpp index 57598d78d7..1e70da6608 100644 --- a/plugins/zerospu2/3rdparty/SoundTouch/sse_optimized.cpp +++ b/plugins/zerospu2/3rdparty/SoundTouch/sse_optimized.cpp @@ -1,484 +1,484 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE -/// optimized functions have been gathered into this single source -/// code file, regardless to their class or original source code file, in order -/// to ease porting the library to other compiler and processor platforms. -/// -/// The SSE-optimizations are programmed using SSE compiler intrinsics that -/// are supported both by Microsoft Visual C++ and GCC compilers, so this file -/// should compile with both toolsets. -/// -/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ -/// 6.0 processor pack" update to support SSE instruction set. The update is -/// available for download at Microsoft Developers Network, see here: -/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx -/// -/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and -/// perform a search with keywords "processor pack". -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.2 $ -// -// $Id: sse_optimized.cpp,v 1.2 2006/02/05 16:44:06 Olli Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include "cpu_detect.h" -#include "STTypes.h" - -using namespace soundtouch; - -#ifdef ALLOW_SSE - -// SSE routines available only with float sample type - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of SSE optimized functions of class 'TDStretchSSE' -// -////////////////////////////////////////////////////////////////////////////// - -#include "TDStretch.h" -#include - -// Calculates cross correlation of two buffers -double TDStretchSSE::calcCrossCorrStereo(const float *pV1, const float *pV2) const -{ - uint i; - __m128 vSum, *pVec2; - - // Note. It means a major slow-down if the routine needs to tolerate - // unaligned __m128 memory accesses. It's way faster if we can skip - // unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps. - // This can mean up to ~ 10-fold difference (incl. part of which is - // due to skipping every second round for stereo sound though). - // - // Compile-time define ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided - // for choosing if this little cheating is allowed. - -#ifdef ALLOW_NONEXACT_SIMD_OPTIMIZATION - // Little cheating allowed, return valid correlation only for - // aligned locations, meaning every second round for stereo sound. - - #define _MM_LOAD _mm_load_ps - - if (((ulong)pV1) & 15) return -1e50; // skip unaligned locations - -#else - // No cheating allowed, use unaligned load & take the resulting - // performance hit. - #define _MM_LOAD _mm_loadu_ps -#endif - - // ensure overlapLength is divisible by 8 - assert((overlapLength % 8) == 0); - - // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors - // Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not. - pVec2 = (__m128*)pV2; - vSum = _mm_setzero_ps(); - - // Unroll the loop by factor of 4 * 4 operations - for (i = 0; i < overlapLength / 8; i ++) - { - // vSum += pV1[0..3] * pV2[0..3] - vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1),pVec2[0])); - - // vSum += pV1[4..7] * pV2[4..7] - vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 4), pVec2[1])); - - // vSum += pV1[8..11] * pV2[8..11] - vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 8), pVec2[2])); - - // vSum += pV1[12..15] * pV2[12..15] - vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 12), pVec2[3])); - - pV1 += 16; - pVec2 += 4; - } - - // return value = vSum[0] + vSum[1] + vSum[2] + vSum[3] - float *pvSum = (float*)&vSum; - return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]); - - /* This is approximately corresponding routine in C-language: - double corr; - uint i; - - // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors - corr = 0.0; - for (i = 0; i < overlapLength / 8; i ++) - { - corr += pV1[0] * pV2[0] + - pV1[1] * pV2[1] + - pV1[2] * pV2[2] + - pV1[3] * pV2[3] + - pV1[4] * pV2[4] + - pV1[5] * pV2[5] + - pV1[6] * pV2[6] + - pV1[7] * pV2[7] + - pV1[8] * pV2[8] + - pV1[9] * pV2[9] + - pV1[10] * pV2[10] + - pV1[11] * pV2[11] + - pV1[12] * pV2[12] + - pV1[13] * pV2[13] + - pV1[14] * pV2[14] + - pV1[15] * pV2[15]; - - pV1 += 16; - pV2 += 16; - } - */ - - /* This is corresponding routine in assembler. This may be teeny-weeny bit faster - than intrinsic version, but more difficult to maintain & get compiled on multiple - platforms. - - uint overlapLengthLocal = overlapLength; - float corr; - - _asm - { - // Very important note: data in 'pV2' _must_ be aligned to - // 16-byte boundary! - - // give prefetch hints to CPU of what data are to be needed soonish - // give more aggressive hints on pV1 as that changes while pV2 stays - // same between runs - prefetcht0 [pV1] - prefetcht0 [pV2] - prefetcht0 [pV1 + 32] - - mov eax, dword ptr pV1 - mov ebx, dword ptr pV2 - - xorps xmm0, xmm0 - - mov ecx, overlapLengthLocal - shr ecx, 3 // div by eight - - loop1: - prefetcht0 [eax + 64] // give a prefetch hint to CPU what data are to be needed soonish - prefetcht0 [ebx + 32] // give a prefetch hint to CPU what data are to be needed soonish - movups xmm1, [eax] - mulps xmm1, [ebx] - addps xmm0, xmm1 - - movups xmm2, [eax + 16] - mulps xmm2, [ebx + 16] - addps xmm0, xmm2 - - prefetcht0 [eax + 96] // give a prefetch hint to CPU what data are to be needed soonish - prefetcht0 [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish - - movups xmm3, [eax + 32] - mulps xmm3, [ebx + 32] - addps xmm0, xmm3 - - movups xmm4, [eax + 48] - mulps xmm4, [ebx + 48] - addps xmm0, xmm4 - - add eax, 64 - add ebx, 64 - - dec ecx - jnz loop1 - - // add the four floats of xmm0 together and return the result. - - movhlps xmm1, xmm0 // move 3 & 4 of xmm0 to 1 & 2 of xmm1 - addps xmm1, xmm0 - movaps xmm2, xmm1 - shufps xmm2, xmm2, 0x01 // move 2 of xmm2 as 1 of xmm2 - addss xmm2, xmm1 - movss corr, xmm2 - } - - return (double)corr; - */ -} - - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of SSE optimized functions of class 'FIRFilter' -// -////////////////////////////////////////////////////////////////////////////// - -#include "FIRFilter.h" - -FIRFilterSSE::FIRFilterSSE() : FIRFilter() -{ - filterCoeffsUnalign = NULL; -} - - -FIRFilterSSE::~FIRFilterSSE() -{ - delete[] filterCoeffsUnalign; -} - - -// (overloaded) Calculates filter coefficients for SSE routine -void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) -{ - uint i; - float fDivider; - - FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); - - // Scale the filter coefficients so that it won't be necessary to scale the filtering result - // also rearrange coefficients suitably for 3DNow! - // Ensure that filter coeffs array is aligned to 16-byte boundary - delete[] filterCoeffsUnalign; - filterCoeffsUnalign = new float[2 * newLength + 4]; - filterCoeffsAlign = (float *)(((unsigned long)filterCoeffsUnalign + 15) & -16); - - fDivider = (float)resultDivider; - - // rearrange the filter coefficients for mmx routines - for (i = 0; i < newLength; i ++) - { - filterCoeffsAlign[2 * i + 0] = - filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; - } -} - - - -// SSE-optimized version of the filter routine for stereo sound -uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const -{ - int count = (numSamples - length) & -2; - int j; - - assert(count % 2 == 0); - - if (count < 2) return 0; - - assert((length % 8) == 0); - assert(((unsigned long)filterCoeffsAlign) % 16 == 0); - - // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2' - for (j = 0; j < count; j += 2) - { - const float *pSrc; - const __m128 *pFil; - __m128 sum1, sum2; - uint i; - - pSrc = source; // source audio data - pFil = (__m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients - // are aligned to 16-byte boundary - sum1 = sum2 = _mm_setzero_ps(); - - for (i = 0; i < length / 8; i ++) - { - // Unroll loop for efficiency & calculate filter for 2*2 stereo samples - // at each pass - - // sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset - // sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset. - - sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc) , pFil[0])); - sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0])); - - sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1])); - sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1])); - - sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) , pFil[2])); - sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2])); - - sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3])); - sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3])); - - pSrc += 16; - pFil += 4; - } - - // Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need - // to sum the two hi- and lo-floats of these registers together. - - // post-shuffle & add the filtered values and store to dest. - _mm_storeu_ps(dest, _mm_add_ps( - _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2 - _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0 - )); - source += 4; - dest += 4; - } - - // Ideas for further improvement: - // 1. If it could be guaranteed that 'source' were always aligned to 16-byte - // boundary, a faster aligned '_mm_load_ps' instruction could be used. - // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte - // boundary, a faster '_mm_store_ps' instruction could be used. - - return (uint)count; - - /* original routine in C-language. please notice the C-version has differently - organized coefficients though. - double suml1, suml2; - double sumr1, sumr2; - uint i, j; - - for (j = 0; j < count; j += 2) - { - const float *ptr; - const float *pFil; - - suml1 = sumr1 = 0.0; - suml2 = sumr2 = 0.0; - ptr = src; - pFil = filterCoeffs; - for (i = 0; i < lengthLocal; i ++) - { - // unroll loop for efficiency. - - suml1 += ptr[0] * pFil[0] + - ptr[2] * pFil[2] + - ptr[4] * pFil[4] + - ptr[6] * pFil[6]; - - sumr1 += ptr[1] * pFil[1] + - ptr[3] * pFil[3] + - ptr[5] * pFil[5] + - ptr[7] * pFil[7]; - - suml2 += ptr[8] * pFil[0] + - ptr[10] * pFil[2] + - ptr[12] * pFil[4] + - ptr[14] * pFil[6]; - - sumr2 += ptr[9] * pFil[1] + - ptr[11] * pFil[3] + - ptr[13] * pFil[5] + - ptr[15] * pFil[7]; - - ptr += 16; - pFil += 8; - } - dest[0] = (float)suml1; - dest[1] = (float)sumr1; - dest[2] = (float)suml2; - dest[3] = (float)sumr2; - - src += 4; - dest += 4; - } - */ - - - /* Similar routine in assembly, again obsoleted due to maintainability - _asm - { - // Very important note: data in 'src' _must_ be aligned to - // 16-byte boundary! - mov edx, count - mov ebx, dword ptr src - mov eax, dword ptr dest - shr edx, 1 - - loop1: - // "outer loop" : during each round 2*2 output samples are calculated - - // give prefetch hints to CPU of what data are to be needed soonish - prefetcht0 [ebx] - prefetcht0 [filterCoeffsLocal] - - mov esi, ebx - mov edi, filterCoeffsLocal - xorps xmm0, xmm0 - xorps xmm1, xmm1 - mov ecx, lengthLocal - - loop2: - // "inner loop" : during each round eight FIR filter taps are evaluated for 2*2 samples - prefetcht0 [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish - prefetcht0 [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish - - movups xmm2, [esi] // possibly unaligned load - movups xmm3, [esi + 8] // possibly unaligned load - mulps xmm2, [edi] - mulps xmm3, [edi] - addps xmm0, xmm2 - addps xmm1, xmm3 - - movups xmm4, [esi + 16] // possibly unaligned load - movups xmm5, [esi + 24] // possibly unaligned load - mulps xmm4, [edi + 16] - mulps xmm5, [edi + 16] - addps xmm0, xmm4 - addps xmm1, xmm5 - - prefetcht0 [esi + 64] // give a prefetch hint to CPU what data are to be needed soonish - prefetcht0 [edi + 64] // give a prefetch hint to CPU what data are to be needed soonish - - movups xmm6, [esi + 32] // possibly unaligned load - movups xmm7, [esi + 40] // possibly unaligned load - mulps xmm6, [edi + 32] - mulps xmm7, [edi + 32] - addps xmm0, xmm6 - addps xmm1, xmm7 - - movups xmm4, [esi + 48] // possibly unaligned load - movups xmm5, [esi + 56] // possibly unaligned load - mulps xmm4, [edi + 48] - mulps xmm5, [edi + 48] - addps xmm0, xmm4 - addps xmm1, xmm5 - - add esi, 64 - add edi, 64 - dec ecx - jnz loop2 - - // Now xmm0 and xmm1 both have a filtered 2-channel sample each, but we still need - // to sum the two hi- and lo-floats of these registers together. - - movhlps xmm2, xmm0 // xmm2 = xmm2_3 xmm2_2 xmm0_3 xmm0_2 - movlhps xmm2, xmm1 // xmm2 = xmm1_1 xmm1_0 xmm0_3 xmm0_2 - shufps xmm0, xmm1, 0xe4 // xmm0 = xmm1_3 xmm1_2 xmm0_1 xmm0_0 - addps xmm0, xmm2 - - movaps [eax], xmm0 - add ebx, 16 - add eax, 16 - - dec edx - jnz loop1 - } - */ -} - -#endif // ALLOW_SSE +//////////////////////////////////////////////////////////////////////////////// +/// +/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE +/// optimized functions have been gathered into this single source +/// code file, regardless to their class or original source code file, in order +/// to ease porting the library to other compiler and processor platforms. +/// +/// The SSE-optimizations are programmed using SSE compiler intrinsics that +/// are supported both by Microsoft Visual C++ and GCC compilers, so this file +/// should compile with both toolsets. +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support SSE instruction set. The update is +/// available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx +/// +/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and +/// perform a search with keywords "processor pack". +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.2 $ +// +// $Id: sse_optimized.cpp,v 1.2 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" +#include "STTypes.h" + +using namespace soundtouch; + +#ifdef ALLOW_SSE + +// SSE routines available only with float sample type + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of SSE optimized functions of class 'TDStretchSSE' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include + +// Calculates cross correlation of two buffers +double TDStretchSSE::calcCrossCorrStereo(const float *pV1, const float *pV2) const +{ + uint i; + __m128 vSum, *pVec2; + + // Note. It means a major slow-down if the routine needs to tolerate + // unaligned __m128 memory accesses. It's way faster if we can skip + // unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps. + // This can mean up to ~ 10-fold difference (incl. part of which is + // due to skipping every second round for stereo sound though). + // + // Compile-time define ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided + // for choosing if this little cheating is allowed. + +#ifdef ALLOW_NONEXACT_SIMD_OPTIMIZATION + // Little cheating allowed, return valid correlation only for + // aligned locations, meaning every second round for stereo sound. + + #define _MM_LOAD _mm_load_ps + + if (((ulong)pV1) & 15) return -1e50; // skip unaligned locations + +#else + // No cheating allowed, use unaligned load & take the resulting + // performance hit. + #define _MM_LOAD _mm_loadu_ps +#endif + + // ensure overlapLength is divisible by 8 + assert((overlapLength % 8) == 0); + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + // Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not. + pVec2 = (__m128*)pV2; + vSum = _mm_setzero_ps(); + + // Unroll the loop by factor of 4 * 4 operations + for (i = 0; i < overlapLength / 8; i ++) + { + // vSum += pV1[0..3] * pV2[0..3] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1),pVec2[0])); + + // vSum += pV1[4..7] * pV2[4..7] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 4), pVec2[1])); + + // vSum += pV1[8..11] * pV2[8..11] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 8), pVec2[2])); + + // vSum += pV1[12..15] * pV2[12..15] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 12), pVec2[3])); + + pV1 += 16; + pVec2 += 4; + } + + // return value = vSum[0] + vSum[1] + vSum[2] + vSum[3] + float *pvSum = (float*)&vSum; + return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]); + + /* This is approximately corresponding routine in C-language: + double corr; + uint i; + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + corr = 0.0; + for (i = 0; i < overlapLength / 8; i ++) + { + corr += pV1[0] * pV2[0] + + pV1[1] * pV2[1] + + pV1[2] * pV2[2] + + pV1[3] * pV2[3] + + pV1[4] * pV2[4] + + pV1[5] * pV2[5] + + pV1[6] * pV2[6] + + pV1[7] * pV2[7] + + pV1[8] * pV2[8] + + pV1[9] * pV2[9] + + pV1[10] * pV2[10] + + pV1[11] * pV2[11] + + pV1[12] * pV2[12] + + pV1[13] * pV2[13] + + pV1[14] * pV2[14] + + pV1[15] * pV2[15]; + + pV1 += 16; + pV2 += 16; + } + */ + + /* This is corresponding routine in assembler. This may be teeny-weeny bit faster + than intrinsic version, but more difficult to maintain & get compiled on multiple + platforms. + + uint overlapLengthLocal = overlapLength; + float corr; + + _asm + { + // Very important note: data in 'pV2' _must_ be aligned to + // 16-byte boundary! + + // give prefetch hints to CPU of what data are to be needed soonish + // give more aggressive hints on pV1 as that changes while pV2 stays + // same between runs + prefetcht0 [pV1] + prefetcht0 [pV2] + prefetcht0 [pV1 + 32] + + mov eax, dword ptr pV1 + mov ebx, dword ptr pV2 + + xorps xmm0, xmm0 + + mov ecx, overlapLengthLocal + shr ecx, 3 // div by eight + + loop1: + prefetcht0 [eax + 64] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [ebx + 32] // give a prefetch hint to CPU what data are to be needed soonish + movups xmm1, [eax] + mulps xmm1, [ebx] + addps xmm0, xmm1 + + movups xmm2, [eax + 16] + mulps xmm2, [ebx + 16] + addps xmm0, xmm2 + + prefetcht0 [eax + 96] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish + + movups xmm3, [eax + 32] + mulps xmm3, [ebx + 32] + addps xmm0, xmm3 + + movups xmm4, [eax + 48] + mulps xmm4, [ebx + 48] + addps xmm0, xmm4 + + add eax, 64 + add ebx, 64 + + dec ecx + jnz loop1 + + // add the four floats of xmm0 together and return the result. + + movhlps xmm1, xmm0 // move 3 & 4 of xmm0 to 1 & 2 of xmm1 + addps xmm1, xmm0 + movaps xmm2, xmm1 + shufps xmm2, xmm2, 0x01 // move 2 of xmm2 as 1 of xmm2 + addss xmm2, xmm1 + movss corr, xmm2 + } + + return (double)corr; + */ +} + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of SSE optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + +FIRFilterSSE::FIRFilterSSE() : FIRFilter() +{ + filterCoeffsUnalign = NULL; +} + + +FIRFilterSSE::~FIRFilterSSE() +{ + delete[] filterCoeffsUnalign; +} + + +// (overloaded) Calculates filter coefficients for SSE routine +void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + float fDivider; + + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Scale the filter coefficients so that it won't be necessary to scale the filtering result + // also rearrange coefficients suitably for 3DNow! + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new float[2 * newLength + 4]; + filterCoeffsAlign = (float *)(((unsigned long)filterCoeffsUnalign + 15) & -16); + + fDivider = (float)resultDivider; + + // rearrange the filter coefficients for mmx routines + for (i = 0; i < newLength; i ++) + { + filterCoeffsAlign[2 * i + 0] = + filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; + } +} + + + +// SSE-optimized version of the filter routine for stereo sound +uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const +{ + int count = (numSamples - length) & -2; + int j; + + assert(count % 2 == 0); + + if (count < 2) return 0; + + assert((length % 8) == 0); + assert(((unsigned long)filterCoeffsAlign) % 16 == 0); + + // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2' + for (j = 0; j < count; j += 2) + { + const float *pSrc; + const __m128 *pFil; + __m128 sum1, sum2; + uint i; + + pSrc = source; // source audio data + pFil = (__m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients + // are aligned to 16-byte boundary + sum1 = sum2 = _mm_setzero_ps(); + + for (i = 0; i < length / 8; i ++) + { + // Unroll loop for efficiency & calculate filter for 2*2 stereo samples + // at each pass + + // sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset + // sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset. + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc) , pFil[0])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) , pFil[2])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3])); + + pSrc += 16; + pFil += 4; + } + + // Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need + // to sum the two hi- and lo-floats of these registers together. + + // post-shuffle & add the filtered values and store to dest. + _mm_storeu_ps(dest, _mm_add_ps( + _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2 + _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0 + )); + source += 4; + dest += 4; + } + + // Ideas for further improvement: + // 1. If it could be guaranteed that 'source' were always aligned to 16-byte + // boundary, a faster aligned '_mm_load_ps' instruction could be used. + // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte + // boundary, a faster '_mm_store_ps' instruction could be used. + + return (uint)count; + + /* original routine in C-language. please notice the C-version has differently + organized coefficients though. + double suml1, suml2; + double sumr1, sumr2; + uint i, j; + + for (j = 0; j < count; j += 2) + { + const float *ptr; + const float *pFil; + + suml1 = sumr1 = 0.0; + suml2 = sumr2 = 0.0; + ptr = src; + pFil = filterCoeffs; + for (i = 0; i < lengthLocal; i ++) + { + // unroll loop for efficiency. + + suml1 += ptr[0] * pFil[0] + + ptr[2] * pFil[2] + + ptr[4] * pFil[4] + + ptr[6] * pFil[6]; + + sumr1 += ptr[1] * pFil[1] + + ptr[3] * pFil[3] + + ptr[5] * pFil[5] + + ptr[7] * pFil[7]; + + suml2 += ptr[8] * pFil[0] + + ptr[10] * pFil[2] + + ptr[12] * pFil[4] + + ptr[14] * pFil[6]; + + sumr2 += ptr[9] * pFil[1] + + ptr[11] * pFil[3] + + ptr[13] * pFil[5] + + ptr[15] * pFil[7]; + + ptr += 16; + pFil += 8; + } + dest[0] = (float)suml1; + dest[1] = (float)sumr1; + dest[2] = (float)suml2; + dest[3] = (float)sumr2; + + src += 4; + dest += 4; + } + */ + + + /* Similar routine in assembly, again obsoleted due to maintainability + _asm + { + // Very important note: data in 'src' _must_ be aligned to + // 16-byte boundary! + mov edx, count + mov ebx, dword ptr src + mov eax, dword ptr dest + shr edx, 1 + + loop1: + // "outer loop" : during each round 2*2 output samples are calculated + + // give prefetch hints to CPU of what data are to be needed soonish + prefetcht0 [ebx] + prefetcht0 [filterCoeffsLocal] + + mov esi, ebx + mov edi, filterCoeffsLocal + xorps xmm0, xmm0 + xorps xmm1, xmm1 + mov ecx, lengthLocal + + loop2: + // "inner loop" : during each round eight FIR filter taps are evaluated for 2*2 samples + prefetcht0 [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish + + movups xmm2, [esi] // possibly unaligned load + movups xmm3, [esi + 8] // possibly unaligned load + mulps xmm2, [edi] + mulps xmm3, [edi] + addps xmm0, xmm2 + addps xmm1, xmm3 + + movups xmm4, [esi + 16] // possibly unaligned load + movups xmm5, [esi + 24] // possibly unaligned load + mulps xmm4, [edi + 16] + mulps xmm5, [edi + 16] + addps xmm0, xmm4 + addps xmm1, xmm5 + + prefetcht0 [esi + 64] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [edi + 64] // give a prefetch hint to CPU what data are to be needed soonish + + movups xmm6, [esi + 32] // possibly unaligned load + movups xmm7, [esi + 40] // possibly unaligned load + mulps xmm6, [edi + 32] + mulps xmm7, [edi + 32] + addps xmm0, xmm6 + addps xmm1, xmm7 + + movups xmm4, [esi + 48] // possibly unaligned load + movups xmm5, [esi + 56] // possibly unaligned load + mulps xmm4, [edi + 48] + mulps xmm5, [edi + 48] + addps xmm0, xmm4 + addps xmm1, xmm5 + + add esi, 64 + add edi, 64 + dec ecx + jnz loop2 + + // Now xmm0 and xmm1 both have a filtered 2-channel sample each, but we still need + // to sum the two hi- and lo-floats of these registers together. + + movhlps xmm2, xmm0 // xmm2 = xmm2_3 xmm2_2 xmm0_3 xmm0_2 + movlhps xmm2, xmm1 // xmm2 = xmm1_1 xmm1_0 xmm0_3 xmm0_2 + shufps xmm0, xmm1, 0xe4 // xmm0 = xmm1_3 xmm1_2 xmm0_1 xmm0_0 + addps xmm0, xmm2 + + movaps [eax], xmm0 + add ebx, 16 + add eax, 16 + + dec edx + jnz loop1 + } + */ +} + +#endif // ALLOW_SSE diff --git a/plugins/zerospu2/Win32/Win32.cpp b/plugins/zerospu2/Win32/Win32.cpp index 5be6fd72d2..5702778677 100644 --- a/plugins/zerospu2/Win32/Win32.cpp +++ b/plugins/zerospu2/Win32/Win32.cpp @@ -1,180 +1,180 @@ -/* ZeroSPU2 - * Copyright (C) 2006-2007 zerofrog - * - * 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 -#include -#include - -#include "zerospu2.h" -#include "resource.h" - -extern HINSTANCE hInst; -///////// -// GUI // -///////// -HINSTANCE hInst; - -void SysMessage(char *fmt, ...) -{ - va_list list; - char tmp[512]; - - va_start(list,fmt); - vsprintf_s(tmp,fmt,list); - va_end(list); - - MessageBox(0, tmp, "SPU2NULL Msg", 0); -} - -BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - - switch(uMsg) - { - case WM_INITDIALOG: - LoadConfig(); - if (conf.Log) CheckDlgButton(hW, IDC_LOGGING, TRUE); - if( conf.options & OPTION_REALTIME) - CheckDlgButton(hW, IDC_REALTIME, TRUE); - if( conf.options & OPTION_TIMESTRETCH) - CheckDlgButton(hW, IDC_TIMESTRETCH, TRUE); - if( conf.options & OPTION_MUTE) - CheckDlgButton(hW, IDC_MUTESOUND, TRUE); - if( conf.options & OPTION_RECORDING) - CheckDlgButton(hW, IDC_SNDRECORDING, TRUE); - return TRUE; - - case WM_COMMAND: - switch(LOWORD(wParam)) - { - case IDCANCEL: - EndDialog(hW, TRUE); - return TRUE; - case IDOK: - conf.options = 0; - if (IsDlgButtonChecked(hW, IDC_LOGGING)) - conf.Log = 1; - else - conf.Log = 0; - - if (IsDlgButtonChecked(hW, IDC_REALTIME)) - conf.options |= OPTION_REALTIME; - if (IsDlgButtonChecked(hW, IDC_TIMESTRETCH)) - conf.options |= OPTION_TIMESTRETCH; - if (IsDlgButtonChecked(hW, IDC_MUTESOUND)) - conf.options |= OPTION_MUTE; - if (IsDlgButtonChecked(hW, IDC_SNDRECORDING)) - conf.options |= OPTION_RECORDING; - - SaveConfig(); - EndDialog(hW, FALSE); - return TRUE; - } - } - return FALSE; -} - -BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch(uMsg) - { - case WM_INITDIALOG: - return TRUE; - - case WM_COMMAND: - switch(LOWORD(wParam)) - { - case IDOK: - EndDialog(hW, FALSE); - return TRUE; - } - } - return FALSE; -} - -void CALLBACK SPU2configure() -{ - DialogBox(hInst, MAKEINTRESOURCE(IDD_CONFIG), GetActiveWindow(), (DLGPROC)ConfigureDlgProc); -} - -void CALLBACK SPU2about() -{ - DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUT), GetActiveWindow(), (DLGPROC)AboutDlgProc); -} - - // DLL INIT -BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) -{ - hInst = (HINSTANCE)hModule; - return TRUE; // very quick :) -} - -void SaveConfig() -{ - Config *Conf1 = &conf; - char *szTemp; - char szIniFile[256], szValue[256]; - - GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); - szTemp = strrchr(szIniFile, '\\'); - - if(!szTemp) return; - szTemp[0] = 0; // this modifies szInitFile also. - - strcat_s(szIniFile, "\\inis\\zerospu2.ini"); - sprintf_s(szValue,"%u",Conf1->Log); - WritePrivateProfileString("Interface", "Logging",szValue,szIniFile); - sprintf_s(szValue,"%u",Conf1->options); - WritePrivateProfileString("Interface", "Options",szValue,szIniFile); -} - -void LoadConfig() -{ - FILE *fp; - Config *Conf1 = &conf; - char *szTemp; - char szIniFile[256], szValue[256]; - - GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); - szTemp = strrchr(szIniFile, '\\'); - - if(!szTemp) return ; - szTemp[0] = 0; - - strcat_s(szIniFile, "\\inis\\zerospu2.ini"); - fopen_s(&fp, "inis\\zerospu2.ini","rt");//check if zerospu2.ini really exists - - if (!fp) - { - CreateDirectory("inis",NULL); - memset(&conf, 0, sizeof(conf)); - conf.Log = 0;//default value - conf.options = OPTION_TIMESTRETCH; - SaveConfig();//save and return - return ; - } - fclose(fp); - - GetPrivateProfileString("Interface", "Logging", NULL, szValue, 20, szIniFile); - Conf1->Log = strtoul(szValue, NULL, 10); - GetPrivateProfileString("Interface", "Options", NULL, szValue, 20, szIniFile); - Conf1->options = strtoul(szValue, NULL, 10); - return; - -} - +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 +#include +#include + +#include "zerospu2.h" +#include "resource.h" + +extern HINSTANCE hInst; +///////// +// GUI // +///////// +HINSTANCE hInst; + +void SysMessage(char *fmt, ...) +{ + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf_s(tmp,fmt,list); + va_end(list); + + MessageBox(0, tmp, "SPU2NULL Msg", 0); +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + + switch(uMsg) + { + case WM_INITDIALOG: + LoadConfig(); + if (conf.Log) CheckDlgButton(hW, IDC_LOGGING, TRUE); + if( conf.options & OPTION_REALTIME) + CheckDlgButton(hW, IDC_REALTIME, TRUE); + if( conf.options & OPTION_TIMESTRETCH) + CheckDlgButton(hW, IDC_TIMESTRETCH, TRUE); + if( conf.options & OPTION_MUTE) + CheckDlgButton(hW, IDC_MUTESOUND, TRUE); + if( conf.options & OPTION_RECORDING) + CheckDlgButton(hW, IDC_SNDRECORDING, TRUE); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + case IDOK: + conf.options = 0; + if (IsDlgButtonChecked(hW, IDC_LOGGING)) + conf.Log = 1; + else + conf.Log = 0; + + if (IsDlgButtonChecked(hW, IDC_REALTIME)) + conf.options |= OPTION_REALTIME; + if (IsDlgButtonChecked(hW, IDC_TIMESTRETCH)) + conf.options |= OPTION_TIMESTRETCH; + if (IsDlgButtonChecked(hW, IDC_MUTESOUND)) + conf.options |= OPTION_MUTE; + if (IsDlgButtonChecked(hW, IDC_SNDRECORDING)) + conf.options |= OPTION_RECORDING; + + SaveConfig(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +void CALLBACK SPU2configure() +{ + DialogBox(hInst, MAKEINTRESOURCE(IDD_CONFIG), GetActiveWindow(), (DLGPROC)ConfigureDlgProc); +} + +void CALLBACK SPU2about() +{ + DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUT), GetActiveWindow(), (DLGPROC)AboutDlgProc); +} + + // DLL INIT +BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) +{ + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + +void SaveConfig() +{ + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + szTemp[0] = 0; // this modifies szInitFile also. + + strcat_s(szIniFile, "\\inis\\zerospu2.ini"); + sprintf_s(szValue,"%u",Conf1->Log); + WritePrivateProfileString("Interface", "Logging",szValue,szIniFile); + sprintf_s(szValue,"%u",Conf1->options); + WritePrivateProfileString("Interface", "Options",szValue,szIniFile); +} + +void LoadConfig() +{ + FILE *fp; + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return ; + szTemp[0] = 0; + + strcat_s(szIniFile, "\\inis\\zerospu2.ini"); + fopen_s(&fp, "inis\\zerospu2.ini","rt");//check if zerospu2.ini really exists + + if (!fp) + { + CreateDirectory("inis",NULL); + memset(&conf, 0, sizeof(conf)); + conf.Log = 0;//default value + conf.options = OPTION_TIMESTRETCH; + SaveConfig();//save and return + return ; + } + fclose(fp); + + GetPrivateProfileString("Interface", "Logging", NULL, szValue, 20, szIniFile); + Conf1->Log = strtoul(szValue, NULL, 10); + GetPrivateProfileString("Interface", "Options", NULL, szValue, 20, szIniFile); + Conf1->options = strtoul(szValue, NULL, 10); + return; + +} + diff --git a/plugins/zerospu2/Win32/resource.h b/plugins/zerospu2/Win32/resource.h index 0e2681687e..530ced6cca 100644 --- a/plugins/zerospu2/Win32/resource.h +++ b/plugins/zerospu2/Win32/resource.h @@ -1,28 +1,28 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by ZeroSPU2.rc -// -#define IDD_CONFDLG 101 -#define IDD_CONFIG 101 -#define IDD_ABOUT 103 -#define IDC_NAME 1000 -#define IDC_CHECK1 1007 -#define IDC_LOGGING 1007 -#define IDC_FFXHAC 1008 -#define IDC_FFXHACK 1008 -#define IDC_SNDRECORDING 1008 -#define IDC_RECORDING 1008 -#define IDC_REALTIME 1009 -#define IDC_TIMESTRETCH 1010 -#define IDC_MUTESOUND 1011 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ZeroSPU2.rc +// +#define IDD_CONFDLG 101 +#define IDD_CONFIG 101 +#define IDD_ABOUT 103 +#define IDC_NAME 1000 +#define IDC_CHECK1 1007 +#define IDC_LOGGING 1007 +#define IDC_FFXHAC 1008 +#define IDC_FFXHACK 1008 +#define IDC_SNDRECORDING 1008 +#define IDC_RECORDING 1008 +#define IDC_REALTIME 1009 +#define IDC_TIMESTRETCH 1010 +#define IDC_MUTESOUND 1011 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/zerospu2/Win32/vsprops/svnrev_template.h b/plugins/zerospu2/Win32/vsprops/svnrev_template.h index afab6c4fd1..f2656ef1e8 100644 --- a/plugins/zerospu2/Win32/vsprops/svnrev_template.h +++ b/plugins/zerospu2/Win32/vsprops/svnrev_template.h @@ -1,18 +1,18 @@ -// svnrev_template.h --> svnrev.h -// -// This file acts as a template for the automatic SVN revision/version tag. -// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for -// whichever project is being compiled (as indicated by command line options -// passed to SubWCRev.exe during the project's pre-build step). -// -// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs -// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN -// installed on your system. If you do not have it installed, a generic template -// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not -// necessary. If you do not have it installed, everything will still compile -// fine except without the SVN revision tagged to the application/dll version. -// -// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org - -#define SVN_REV $WCREV$ +// svnrev_template.h --> svnrev.h +// +// This file acts as a template for the automatic SVN revision/version tag. +// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for +// whichever project is being compiled (as indicated by command line options +// passed to SubWCRev.exe during the project's pre-build step). +// +// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs +// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN +// installed on your system. If you do not have it installed, a generic template +// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not +// necessary. If you do not have it installed, everything will still compile +// fine except without the SVN revision tagged to the application/dll version. +// +// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV $WCREV$ #define SVN_MODS $WCMODS?1:0$ \ No newline at end of file diff --git a/plugins/zerospu2/Win32/vsprops/svnrev_unknown.h b/plugins/zerospu2/Win32/vsprops/svnrev_unknown.h index a2a3703186..4872e23b20 100644 --- a/plugins/zerospu2/Win32/vsprops/svnrev_unknown.h +++ b/plugins/zerospu2/Win32/vsprops/svnrev_unknown.h @@ -1,23 +1,23 @@ -// svnrev_genric.h --> svnrev.h -// -// This file acts as a placebo for people who do not have TortoiseSVN installed. -// It provides "empty" revision information to the Pcsx2 Playground projects in -// the absence of real revisions derived from the repository being built. -// -// This file does not affect application/dll builds in any significant manner, -// other than the lack of automatic revision tags inserted into the app (which -// is very convenient but hardly necessary). -// -// See svn_template.h for more information on how the process of revision -// templating works. -// -// If you would like to enable automatic revisin tagging, TortoiseSVN can be -// downloaded from http://tortoisesvn.tigris.org - -#define SVN_REV_UNKNOWN - -// The following defines are included so that code will still compile even if it -// doesn't check for the SVN_REV_UNKNOWN define. - -#define SVN_REV 0 +// svnrev_genric.h --> svnrev.h +// +// This file acts as a placebo for people who do not have TortoiseSVN installed. +// It provides "empty" revision information to the Pcsx2 Playground projects in +// the absence of real revisions derived from the repository being built. +// +// This file does not affect application/dll builds in any significant manner, +// other than the lack of automatic revision tags inserted into the app (which +// is very convenient but hardly necessary). +// +// See svn_template.h for more information on how the process of revision +// templating works. +// +// If you would like to enable automatic revisin tagging, TortoiseSVN can be +// downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV_UNKNOWN + +// The following defines are included so that code will still compile even if it +// doesn't check for the SVN_REV_UNKNOWN define. + +#define SVN_REV 0 #define SVN_MODS "" \ No newline at end of file diff --git a/plugins/zerospu2/common/PS2Edefs.h b/plugins/zerospu2/common/PS2Edefs.h index 1f65fc02b9..49b16e16d5 100644 --- a/plugins/zerospu2/common/PS2Edefs.h +++ b/plugins/zerospu2/common/PS2Edefs.h @@ -1,885 +1,885 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef __PS2EDEFS_H__ -#define __PS2EDEFS_H__ - -/* - * PS2E Definitions v0.6.2 (beta) - * - * Author: linuzappz@hotmail.com - * shadowpcsx2@yahoo.gr - * florinsasu@hotmail.com - */ - -/* - Notes: - * Since this is still beta things may change. - - * OSflags: - __LINUX__ (linux OS) - _WIN32 (win32 OS) - - * common return values (for ie. GSinit): - 0 - success - -1 - error - - * reserved keys: - F1 to F10 are reserved for the emulator - - * plugins should NOT change the current - working directory. - (on win32, add flag OFN_NOCHANGEDIR for - GetOpenFileName) - -*/ - -#include "PS2Etypes.h" - - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ - defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ - defined(USBdefs) || defined(FWdefs) -#define COMMONdefs -#endif - -// PS2EgetLibType returns (may be OR'd) -#define PS2E_LT_GS 0x01 -#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- -#define PS2E_LT_SPU2 0x04 -#define PS2E_LT_CDVD 0x08 -#define PS2E_LT_DEV9 0x10 -#define PS2E_LT_USB 0x20 -#define PS2E_LT_FW 0x40 -#define PS2E_LT_SIO 0x80 - -// PS2EgetLibVersion2 (high 16 bits) -#define PS2E_GS_VERSION 0x0006 -#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- -#define PS2E_SPU2_VERSION 0x0005 -#define PS2E_CDVD_VERSION 0x0005 -#define PS2E_DEV9_VERSION 0x0003 -#define PS2E_USB_VERSION 0x0003 -#define PS2E_FW_VERSION 0x0002 -#define PS2E_SIO_VERSION 0x0001 -#ifdef COMMONdefs - -u32 CALLBACK PS2EgetLibType(void); -u32 CALLBACK PS2EgetLibVersion2(u32 type); -char* CALLBACK PS2EgetLibName(void); - -#endif - -// key values: -/* key values must be OS dependant: - win32: the VK_XXX will be used (WinUser) - linux: the XK_XXX will be used (XFree86) -*/ - -// event values: -#define KEYPRESS 1 -#define KEYRELEASE 2 - -typedef struct _keyEvent { - u32 key; - u32 evt; -} keyEvent; - -// for 64bit compilers -typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; - -// plugin types -#define SIO_TYPE_PAD 0x00000001 -#define SIO_TYPE_MTAP 0x00000004 -#define SIO_TYPE_RM 0x00000040 -#define SIO_TYPE_MC 0x00000100 - -typedef int (CALLBACK * SIOchangeSlotCB)(int slot); - -typedef struct _cdvdSubQ { - u8 ctrl:4; // control and mode bits - u8 mode:4; // control and mode bits - u8 trackNum; // current track number (1 to 99) - u8 trackIndex; // current index within track (0 to 99) - u8 trackM; // current minute location on the disc (BCD encoded) - u8 trackS; // current sector location on the disc (BCD encoded) - u8 trackF; // current frame location on the disc (BCD encoded) - u8 pad; // unused - u8 discM; // current minute offset from first track (BCD encoded) - u8 discS; // current sector offset from first track (BCD encoded) - u8 discF; // current frame offset from first track (BCD encoded) -} cdvdSubQ; - -typedef struct _cdvdTD { // NOT bcd coded - u32 lsn; - u8 type; -} cdvdTD; - -typedef struct _cdvdTN { - u8 strack; //number of the first track (usually 1) - u8 etrack; //number of the last track -} cdvdTN; - -// CDVDreadTrack mode values: -#define CDVD_MODE_2352 0 // full 2352 bytes -#define CDVD_MODE_2340 1 // skip sync (12) bytes -#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes -#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq - -// CDVDgetDiskType returns: -#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc -#define CDVD_TYPE_DVDV 0xfe // DVD Video -#define CDVD_TYPE_CDDA 0xfd // Audio CD -#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD -#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) -#define CDVD_TYPE_PS2CD 0x12 // PS2 CD -#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) -#define CDVD_TYPE_PSCD 0x10 // PS CD -#define CDVD_TYPE_UNKNOWN 0x05 // Unknown -#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided -#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided -#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd -#define CDVD_TYPE_DETCT 0x01 // Detecting -#define CDVD_TYPE_NODISC 0x00 // No Disc - -// CDVDgetTrayStatus returns: -#define CDVD_TRAY_CLOSE 0x00 -#define CDVD_TRAY_OPEN 0x01 - -// cdvdTD.type (track types for cds) -#define CDVD_AUDIO_TRACK 0x01 -#define CDVD_MODE1_TRACK 0x41 -#define CDVD_MODE2_TRACK 0x61 - -#define CDVD_AUDIO_MASK 0x00 -#define CDVD_DATA_MASK 0x40 -// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) - -typedef void (*DEV9callback)(int cycles); -typedef int (*DEV9handler)(void); - -typedef void (*USBcallback)(int cycles); -typedef int (*USBhandler)(void); - -// freeze modes: -#define FREEZE_LOAD 0 -#define FREEZE_SAVE 1 -#define FREEZE_SIZE 2 - -typedef struct _GSdriverInfo { - char name[8]; - void *common; -} GSdriverInfo; - -#ifdef _WINDOWS_ -typedef struct _winInfo { // unsupported values must be set to zero - HWND hWnd; - HMENU hMenu; - HWND hStatusWnd; -} winInfo; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* GS plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef GSdefs - -// basic funcs - -s32 CALLBACK GSinit(); -s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); -void CALLBACK GSclose(); -void CALLBACK GSshutdown(); -void CALLBACK GSvsync(int field); -void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); -void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); -void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); -void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) -void CALLBACK GSgifSoftReset(u32 mask); -void CALLBACK GSreadFIFO(u64 *mem); -void CALLBACK GSreadFIFO2(u64 *mem, int qwc); - -// extended funcs - -// GSkeyEvent gets called when there is a keyEvent from the PAD plugin -void CALLBACK GSkeyEvent(keyEvent *ev); -void CALLBACK GSchangeSaveState(int, const char* filename); -void CALLBACK GSmakeSnapshot(char *path); -void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); -void CALLBACK GSirqCallback(void (*callback)()); -void CALLBACK GSprintf(int timeout, char *fmt, ...); -void CALLBACK GSsetBaseMem(void*); -void CALLBACK GSsetGameCRC(int crc, int gameoptions); - -// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done -void CALLBACK GSsetFrameSkip(int frameskip); - -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK GSsetupRecording(int start, void* pData); - -void CALLBACK GSreset(); -void CALLBACK GSwriteCSR(u32 value); -void CALLBACK GSgetDriverInfo(GSdriverInfo *info); -#ifdef _WIN32 -s32 CALLBACK GSsetWindowInfo(winInfo *info); -#endif -s32 CALLBACK GSfreeze(int mode, freezeData *data); -void CALLBACK GSconfigure(); -void CALLBACK GSabout(); -s32 CALLBACK GStest(); - -#endif - -/* PAD plugin API -=[ OBSOLETE ]=- */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef PADdefs - -// basic funcs - -s32 CALLBACK PADinit(u32 flags); -s32 CALLBACK PADopen(void *pDsp); -void CALLBACK PADclose(); -void CALLBACK PADshutdown(); -// PADkeyEvent is called every vsync (return NULL if no event) -keyEvent* CALLBACK PADkeyEvent(); -u8 CALLBACK PADstartPoll(int pad); -u8 CALLBACK PADpoll(u8 value); -// returns: 1 if supported pad1 -// 2 if supported pad2 -// 3 if both are supported -u32 CALLBACK PADquery(); - -// call to give a hint to the PAD plugin to query for the keyboard state. A -// good plugin will query the OS for keyboard state ONLY in this function. -// This function is necessary when multithreading because otherwise -// the PAD plugin can get into deadlocks with the thread that really owns -// the window (and input). Note that PADupdate can be called from a different -// thread than the other functions, so mutex or other multithreading primitives -// have to be added to maintain data integrity. -void CALLBACK PADupdate(int pad); - -// extended funcs - -void CALLBACK PADgsDriverInfo(GSdriverInfo *info); -void CALLBACK PADconfigure(); -void CALLBACK PADabout(); -s32 CALLBACK PADtest(); - -#endif - -/* SIO plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SIOdefs - -// basic funcs - -s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); -s32 CALLBACK SIOopen(void *pDsp); -void CALLBACK SIOclose(); -void CALLBACK SIOshutdown(); -u8 CALLBACK SIOstartPoll(u8 value); -u8 CALLBACK SIOpoll(u8 value); -// returns: SIO_TYPE_{PAD,MTAP,RM,MC} -u32 CALLBACK SIOquery(); - -// extended funcs - -void CALLBACK SIOconfigure(); -void CALLBACK SIOabout(); -s32 CALLBACK SIOtest(); - -#endif - -/* SPU2 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef SPU2defs - -// basic funcs - -s32 CALLBACK SPU2init(); -s32 CALLBACK SPU2open(void *pDsp); -void CALLBACK SPU2close(); -void CALLBACK SPU2shutdown(); -void CALLBACK SPU2write(u32 mem, u16 value); -u16 CALLBACK SPU2read(u32 mem); -void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); -void CALLBACK SPU2interruptDMA4(); -void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); -void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); - -// all addresses passed by dma will be pointers to the array starting at baseaddr -// This function is necessary to successfully save and reload the spu2 state -void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); - -void CALLBACK SPU2interruptDMA7(); -u32 CALLBACK SPU2ReadMemAddr(int core); -void CALLBACK SPU2WriteMemAddr(int core,u32 value); -void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); - -// extended funcs -// if start is 1, starts recording spu2 data, else stops -// returns a non zero value if successful -// for now, pData is not used -int CALLBACK SPU2setupRecording(int start, void* pData); - -void CALLBACK SPU2setClockPtr(u32* ptr); -void CALLBACK SPU2setTimeStretcher(short int enable); - -void CALLBACK SPU2async(u32 cycles); -s32 CALLBACK SPU2freeze(int mode, freezeData *data); -void CALLBACK SPU2configure(); -void CALLBACK SPU2about(); -s32 CALLBACK SPU2test(); - -#endif - -/* CDVD plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef CDVDdefs - -// basic funcs - -s32 CALLBACK CDVDinit(); -s32 CALLBACK CDVDopen(const char* pTitleFilename); -void CALLBACK CDVDclose(); -void CALLBACK CDVDshutdown(); -s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); - -// return can be NULL (for async modes) -u8* CALLBACK CDVDgetBuffer(); - -s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) -s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information -s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type -s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc -s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx -s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx -s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray -s32 CALLBACK CDVDctrlTrayClose(); //close disc tray - -// extended funcs - -void CALLBACK CDVDconfigure(); -void CALLBACK CDVDabout(); -s32 CALLBACK CDVDtest(); -void CALLBACK CDVDnewDiskCB(void (*callback)()); - -#endif - -/* DEV9 plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef DEV9defs - -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK DEV9init(); -s32 CALLBACK DEV9open(void *pDsp); -void CALLBACK DEV9close(); -void CALLBACK DEV9shutdown(); -u8 CALLBACK DEV9read8(u32 addr); -u16 CALLBACK DEV9read16(u32 addr); -u32 CALLBACK DEV9read32(u32 addr); -void CALLBACK DEV9write8(u32 addr, u8 value); -void CALLBACK DEV9write16(u32 addr, u16 value); -void CALLBACK DEV9write32(u32 addr, u32 value); -void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); -void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK DEV9irqCallback(DEV9callback callback); -DEV9handler CALLBACK DEV9irqHandler(void); - -// extended funcs - -s32 CALLBACK DEV9freeze(int mode, freezeData *data); -void CALLBACK DEV9configure(); -void CALLBACK DEV9about(); -s32 CALLBACK DEV9test(); - -#endif - -/* USB plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef USBdefs - -// basic funcs - -s32 CALLBACK USBinit(); -s32 CALLBACK USBopen(void *pDsp); -void CALLBACK USBclose(); -void CALLBACK USBshutdown(); -u8 CALLBACK USBread8(u32 addr); -u16 CALLBACK USBread16(u32 addr); -u32 CALLBACK USBread32(u32 addr); -void CALLBACK USBwrite8(u32 addr, u8 value); -void CALLBACK USBwrite16(u32 addr, u16 value); -void CALLBACK USBwrite32(u32 addr, u32 value); -void CALLBACK USBasync(u32 cycles); - -// cycles = IOP cycles before calling callback, -// if callback returns 1 the irq is triggered, else not -void CALLBACK USBirqCallback(USBcallback callback); -USBhandler CALLBACK USBirqHandler(void); -void CALLBACK USBsetRAM(void *mem); - -// extended funcs - -s32 CALLBACK USBfreeze(int mode, freezeData *data); -void CALLBACK USBconfigure(); -void CALLBACK USBabout(); -s32 CALLBACK USBtest(); - -#endif - -/* FW plugin API */ - -// if this file is included with this define -// the next api will not be skipped by the compiler -#ifdef FWdefs -// basic funcs - -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -s32 CALLBACK FWinit(); -s32 CALLBACK FWopen(void *pDsp); -void CALLBACK FWclose(); -void CALLBACK FWshutdown(); -u32 CALLBACK FWread32(u32 addr); -void CALLBACK FWwrite32(u32 addr, u32 value); -void CALLBACK FWirqCallback(void (*callback)()); - -// extended funcs - -s32 CALLBACK FWfreeze(int mode, freezeData *data); -void CALLBACK FWconfigure(); -void CALLBACK FWabout(); -s32 CALLBACK FWtest(); -#endif - -// might be useful for emulators -#ifdef PLUGINtypedefs - -typedef u32 (CALLBACK* _PS2EgetLibType)(void); -typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); -typedef char*(CALLBACK* _PS2EgetLibName)(void); - -// GS -// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _GSinit)(); -typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); -typedef void (CALLBACK* _GSclose)(); -typedef void (CALLBACK* _GSshutdown)(); -typedef void (CALLBACK* _GSvsync)(int field); -typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); -typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); -typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) -typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); -typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); -typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); - -typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); -typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); -typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); -typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); -typedef void (CALLBACK* _GSsetBaseMem)(void*); -typedef void (CALLBACK* _GSsetGameCRC)(int, int); -typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); -typedef int (CALLBACK* _GSsetupRecording)(int, void*); -typedef void (CALLBACK* _GSreset)(); -typedef void (CALLBACK* _GSwriteCSR)(u32 value); -typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); -#ifdef _WINDOWS_ -typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); -#endif -typedef void (CALLBACK* _GSmakeSnapshot)(const char *path); -typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); -typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _GSconfigure)(); -typedef s32 (CALLBACK* _GStest)(); -typedef void (CALLBACK* _GSabout)(); - -// PAD -typedef s32 (CALLBACK* _PADinit)(u32 flags); -typedef s32 (CALLBACK* _PADopen)(void *pDsp); -typedef void (CALLBACK* _PADclose)(); -typedef void (CALLBACK* _PADshutdown)(); -typedef keyEvent* (CALLBACK* _PADkeyEvent)(); -typedef u8 (CALLBACK* _PADstartPoll)(int pad); -typedef u8 (CALLBACK* _PADpoll)(u8 value); -typedef u32 (CALLBACK* _PADquery)(); -typedef void (CALLBACK* _PADupdate)(int pad); - -typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); -typedef void (CALLBACK* _PADconfigure)(); -typedef s32 (CALLBACK* _PADtest)(); -typedef void (CALLBACK* _PADabout)(); - -// SIO -typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); -typedef s32 (CALLBACK* _SIOopen)(void *pDsp); -typedef void (CALLBACK* _SIOclose)(); -typedef void (CALLBACK* _SIOshutdown)(); -typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); -typedef u8 (CALLBACK* _SIOpoll)(u8 value); -typedef u32 (CALLBACK* _SIOquery)(); - -typedef void (CALLBACK* _SIOconfigure)(); -typedef s32 (CALLBACK* _SIOtest)(); -typedef void (CALLBACK* _SIOabout)(); - -// SPU2 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _SPU2init)(); -typedef s32 (CALLBACK* _SPU2open)(void *pDsp); -typedef void (CALLBACK* _SPU2close)(); -typedef void (CALLBACK* _SPU2shutdown)(); -typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); -typedef u16 (CALLBACK* _SPU2read)(u32 mem); -typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2interruptDMA4)(); -typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); -typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); -typedef void (CALLBACK* _SPU2interruptDMA7)(); -typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); -typedef int (CALLBACK* _SPU2setupRecording)(int, void*); - -typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); -typedef void (CALLBACK* _SPU2setTimeStretcher)(short int enable); - -typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); -typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); -typedef void (CALLBACK* _SPU2async)(u32 cycles); -typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _SPU2configure)(); -typedef s32 (CALLBACK* _SPU2test)(); -typedef void (CALLBACK* _SPU2about)(); - - -// CDVD -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _CDVDinit)(); -typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); -typedef void (CALLBACK* _CDVDclose)(); -typedef void (CALLBACK* _CDVDshutdown)(); -typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); -typedef u8* (CALLBACK* _CDVDgetBuffer)(); -typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); -typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); -typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); -typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); -typedef s32 (CALLBACK* _CDVDgetDiskType)(); -typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); -typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); -typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); - -typedef void (CALLBACK* _CDVDconfigure)(); -typedef s32 (CALLBACK* _CDVDtest)(); -typedef void (CALLBACK* _CDVDabout)(); -typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); - -// DEV9 -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _DEV9init)(); -typedef s32 (CALLBACK* _DEV9open)(void *pDsp); -typedef void (CALLBACK* _DEV9close)(); -typedef void (CALLBACK* _DEV9shutdown)(); -typedef u8 (CALLBACK* _DEV9read8)(u32 mem); -typedef u16 (CALLBACK* _DEV9read16)(u32 mem); -typedef u32 (CALLBACK* _DEV9read32)(u32 mem); -typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); -typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); -typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); -typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); -typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); -typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); - -typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); -typedef void (CALLBACK* _DEV9configure)(); -typedef s32 (CALLBACK* _DEV9test)(); -typedef void (CALLBACK* _DEV9about)(); - -// USB -// NOTE: The read/write functions CANNOT use XMM/MMX regs -// If you want to use them, need to save and restore current ones -typedef s32 (CALLBACK* _USBinit)(); -typedef s32 (CALLBACK* _USBopen)(void *pDsp); -typedef void (CALLBACK* _USBclose)(); -typedef void (CALLBACK* _USBshutdown)(); -typedef u8 (CALLBACK* _USBread8)(u32 mem); -typedef u16 (CALLBACK* _USBread16)(u32 mem); -typedef u32 (CALLBACK* _USBread32)(u32 mem); -typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); -typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); -typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _USBasync)(u32 cycles); - - -typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); -typedef USBhandler (CALLBACK* _USBirqHandler)(void); -typedef void (CALLBACK* _USBsetRAM)(void *mem); - -typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _USBconfigure)(); -typedef s32 (CALLBACK* _USBtest)(); -typedef void (CALLBACK* _USBabout)(); - -//FW -typedef s32 (CALLBACK* _FWinit)(); -typedef s32 (CALLBACK* _FWopen)(void *pDsp); -typedef void (CALLBACK* _FWclose)(); -typedef void (CALLBACK* _FWshutdown)(); -typedef u32 (CALLBACK* _FWread32)(u32 mem); -typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); -typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); - -typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); -typedef void (CALLBACK* _FWconfigure)(); -typedef s32 (CALLBACK* _FWtest)(); -typedef void (CALLBACK* _FWabout)(); - -#endif - -#ifdef PLUGINfuncs - -// GS -extern _GSinit GSinit; -extern _GSopen GSopen; -extern _GSclose GSclose; -extern _GSshutdown GSshutdown; -extern _GSvsync GSvsync; -extern _GSgifTransfer1 GSgifTransfer1; -extern _GSgifTransfer2 GSgifTransfer2; -extern _GSgifTransfer3 GSgifTransfer3; -extern _GSgetLastTag GSgetLastTag; -extern _GSgifSoftReset GSgifSoftReset; -extern _GSreadFIFO GSreadFIFO; -extern _GSreadFIFO2 GSreadFIFO2; - -extern _GSkeyEvent GSkeyEvent; -extern _GSchangeSaveState GSchangeSaveState; -extern _GSmakeSnapshot GSmakeSnapshot; -extern _GSmakeSnapshot2 GSmakeSnapshot2; -extern _GSirqCallback GSirqCallback; -extern _GSprintf GSprintf; -extern _GSsetBaseMem GSsetBaseMem; -extern _GSsetGameCRC GSsetGameCRC; -extern _GSsetFrameSkip GSsetFrameSkip; -extern _GSsetupRecording GSsetupRecording; -extern _GSreset GSreset; -extern _GSwriteCSR GSwriteCSR; -extern _GSgetDriverInfo GSgetDriverInfo; -#ifdef _WINDOWS_ -extern _GSsetWindowInfo GSsetWindowInfo; -#endif -extern _GSfreeze GSfreeze; -extern _GSconfigure GSconfigure; -extern _GStest GStest; -extern _GSabout GSabout; - -// PAD1 -extern _PADinit PAD1init; -extern _PADopen PAD1open; -extern _PADclose PAD1close; -extern _PADshutdown PAD1shutdown; -extern _PADkeyEvent PAD1keyEvent; -extern _PADstartPoll PAD1startPoll; -extern _PADpoll PAD1poll; -extern _PADquery PAD1query; -extern _PADupdate PAD1update; - -extern _PADgsDriverInfo PAD1gsDriverInfo; -extern _PADconfigure PAD1configure; -extern _PADtest PAD1test; -extern _PADabout PAD1about; - -// PAD2 -extern _PADinit PAD2init; -extern _PADopen PAD2open; -extern _PADclose PAD2close; -extern _PADshutdown PAD2shutdown; -extern _PADkeyEvent PAD2keyEvent; -extern _PADstartPoll PAD2startPoll; -extern _PADpoll PAD2poll; -extern _PADquery PAD2query; -extern _PADupdate PAD2update; - -extern _PADgsDriverInfo PAD2gsDriverInfo; -extern _PADconfigure PAD2configure; -extern _PADtest PAD2test; -extern _PADabout PAD2about; - -// SIO[2] -extern _SIOinit SIOinit[2][9]; -extern _SIOopen SIOopen[2][9]; -extern _SIOclose SIOclose[2][9]; -extern _SIOshutdown SIOshutdown[2][9]; -extern _SIOstartPoll SIOstartPoll[2][9]; -extern _SIOpoll SIOpoll[2][9]; -extern _SIOquery SIOquery[2][9]; - -extern _SIOconfigure SIOconfigure[2][9]; -extern _SIOtest SIOtest[2][9]; -extern _SIOabout SIOabout[2][9]; - -// SPU2 -extern _SPU2init SPU2init; -extern _SPU2open SPU2open; -extern _SPU2close SPU2close; -extern _SPU2shutdown SPU2shutdown; -extern _SPU2write SPU2write; -extern _SPU2read SPU2read; -extern _SPU2readDMA4Mem SPU2readDMA4Mem; -extern _SPU2writeDMA4Mem SPU2writeDMA4Mem; -extern _SPU2interruptDMA4 SPU2interruptDMA4; -extern _SPU2readDMA7Mem SPU2readDMA7Mem; -extern _SPU2writeDMA7Mem SPU2writeDMA7Mem; -extern _SPU2setDMABaseAddr SPU2setDMABaseAddr; -extern _SPU2interruptDMA7 SPU2interruptDMA7; -extern _SPU2ReadMemAddr SPU2ReadMemAddr; -extern _SPU2setupRecording SPU2setupRecording; -extern _SPU2WriteMemAddr SPU2WriteMemAddr; -extern _SPU2irqCallback SPU2irqCallback; - -extern _SPU2setClockPtr SPU2setClockPtr; -extern _SPU2setTimeStretcher SPU2setTimeStretcher; - -extern _SPU2async SPU2async; -extern _SPU2freeze SPU2freeze; -extern _SPU2configure SPU2configure; -extern _SPU2test SPU2test; -extern _SPU2about SPU2about; - -// CDVD -extern _CDVDinit CDVDinit; -extern _CDVDopen CDVDopen; -extern _CDVDclose CDVDclose; -extern _CDVDshutdown CDVDshutdown; -extern _CDVDreadTrack CDVDreadTrack; -extern _CDVDgetBuffer CDVDgetBuffer; -extern _CDVDreadSubQ CDVDreadSubQ; -extern _CDVDgetTN CDVDgetTN; -extern _CDVDgetTD CDVDgetTD; -extern _CDVDgetTOC CDVDgetTOC; -extern _CDVDgetDiskType CDVDgetDiskType; -extern _CDVDgetTrayStatus CDVDgetTrayStatus; -extern _CDVDctrlTrayOpen CDVDctrlTrayOpen; -extern _CDVDctrlTrayClose CDVDctrlTrayClose; - -extern _CDVDconfigure CDVDconfigure; -extern _CDVDtest CDVDtest; -extern _CDVDabout CDVDabout; -extern _CDVDnewDiskCB CDVDnewDiskCB; - -// DEV9 -extern _DEV9init DEV9init; -extern _DEV9open DEV9open; -extern _DEV9close DEV9close; -extern _DEV9shutdown DEV9shutdown; -extern _DEV9read8 DEV9read8; -extern _DEV9read16 DEV9read16; -extern _DEV9read32 DEV9read32; -extern _DEV9write8 DEV9write8; -extern _DEV9write16 DEV9write16; -extern _DEV9write32 DEV9write32; -extern _DEV9readDMA8Mem DEV9readDMA8Mem; -extern _DEV9writeDMA8Mem DEV9writeDMA8Mem; -extern _DEV9irqCallback DEV9irqCallback; -extern _DEV9irqHandler DEV9irqHandler; - -extern _DEV9configure DEV9configure; -extern _DEV9freeze DEV9freeze; -extern _DEV9test DEV9test; -extern _DEV9about DEV9about; - -// USB -extern _USBinit USBinit; -extern _USBopen USBopen; -extern _USBclose USBclose; -extern _USBshutdown USBshutdown; -extern _USBread8 USBread8; -extern _USBread16 USBread16; -extern _USBread32 USBread32; -extern _USBwrite8 USBwrite8; -extern _USBwrite16 USBwrite16; -extern _USBwrite32 USBwrite32; -extern _USBasync USBasync; - -extern _USBirqCallback USBirqCallback; -extern _USBirqHandler USBirqHandler; -extern _USBsetRAM USBsetRAM; - -extern _USBconfigure USBconfigure; -extern _USBfreeze USBfreeze; -extern _USBtest USBtest; -extern _USBabout USBabout; - -// FW -extern _FWinit FWinit; -extern _FWopen FWopen; -extern _FWclose FWclose; -extern _FWshutdown FWshutdown; -extern _FWread32 FWread32; -extern _FWwrite32 FWwrite32; -extern _FWirqCallback FWirqCallback; - -extern _FWconfigure FWconfigure; -extern _FWfreeze FWfreeze; -extern _FWtest FWtest; -extern _FWabout FWabout; -#endif - -#ifdef __cplusplus -} // End extern "C" -#endif - -#endif /* __PS2EDEFS_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct _keyEvent { + u32 key; + u32 evt; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct _cdvdSubQ { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct _cdvdTD { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct _cdvdTN { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct _GSdriverInfo { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WINDOWS_ +typedef struct _winInfo { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2setClockPtr(u32* ptr); +void CALLBACK SPU2setTimeStretcher(short int enable); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +void CALLBACK USBasync(u32 cycles); + +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WINDOWS_ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(const char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); + +typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); +typedef void (CALLBACK* _SPU2setTimeStretcher)(short int enable); + +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBasync)(u32 cycles); + + +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +extern _GSinit GSinit; +extern _GSopen GSopen; +extern _GSclose GSclose; +extern _GSshutdown GSshutdown; +extern _GSvsync GSvsync; +extern _GSgifTransfer1 GSgifTransfer1; +extern _GSgifTransfer2 GSgifTransfer2; +extern _GSgifTransfer3 GSgifTransfer3; +extern _GSgetLastTag GSgetLastTag; +extern _GSgifSoftReset GSgifSoftReset; +extern _GSreadFIFO GSreadFIFO; +extern _GSreadFIFO2 GSreadFIFO2; + +extern _GSkeyEvent GSkeyEvent; +extern _GSchangeSaveState GSchangeSaveState; +extern _GSmakeSnapshot GSmakeSnapshot; +extern _GSmakeSnapshot2 GSmakeSnapshot2; +extern _GSirqCallback GSirqCallback; +extern _GSprintf GSprintf; +extern _GSsetBaseMem GSsetBaseMem; +extern _GSsetGameCRC GSsetGameCRC; +extern _GSsetFrameSkip GSsetFrameSkip; +extern _GSsetupRecording GSsetupRecording; +extern _GSreset GSreset; +extern _GSwriteCSR GSwriteCSR; +extern _GSgetDriverInfo GSgetDriverInfo; +#ifdef _WINDOWS_ +extern _GSsetWindowInfo GSsetWindowInfo; +#endif +extern _GSfreeze GSfreeze; +extern _GSconfigure GSconfigure; +extern _GStest GStest; +extern _GSabout GSabout; + +// PAD1 +extern _PADinit PAD1init; +extern _PADopen PAD1open; +extern _PADclose PAD1close; +extern _PADshutdown PAD1shutdown; +extern _PADkeyEvent PAD1keyEvent; +extern _PADstartPoll PAD1startPoll; +extern _PADpoll PAD1poll; +extern _PADquery PAD1query; +extern _PADupdate PAD1update; + +extern _PADgsDriverInfo PAD1gsDriverInfo; +extern _PADconfigure PAD1configure; +extern _PADtest PAD1test; +extern _PADabout PAD1about; + +// PAD2 +extern _PADinit PAD2init; +extern _PADopen PAD2open; +extern _PADclose PAD2close; +extern _PADshutdown PAD2shutdown; +extern _PADkeyEvent PAD2keyEvent; +extern _PADstartPoll PAD2startPoll; +extern _PADpoll PAD2poll; +extern _PADquery PAD2query; +extern _PADupdate PAD2update; + +extern _PADgsDriverInfo PAD2gsDriverInfo; +extern _PADconfigure PAD2configure; +extern _PADtest PAD2test; +extern _PADabout PAD2about; + +// SIO[2] +extern _SIOinit SIOinit[2][9]; +extern _SIOopen SIOopen[2][9]; +extern _SIOclose SIOclose[2][9]; +extern _SIOshutdown SIOshutdown[2][9]; +extern _SIOstartPoll SIOstartPoll[2][9]; +extern _SIOpoll SIOpoll[2][9]; +extern _SIOquery SIOquery[2][9]; + +extern _SIOconfigure SIOconfigure[2][9]; +extern _SIOtest SIOtest[2][9]; +extern _SIOabout SIOabout[2][9]; + +// SPU2 +extern _SPU2init SPU2init; +extern _SPU2open SPU2open; +extern _SPU2close SPU2close; +extern _SPU2shutdown SPU2shutdown; +extern _SPU2write SPU2write; +extern _SPU2read SPU2read; +extern _SPU2readDMA4Mem SPU2readDMA4Mem; +extern _SPU2writeDMA4Mem SPU2writeDMA4Mem; +extern _SPU2interruptDMA4 SPU2interruptDMA4; +extern _SPU2readDMA7Mem SPU2readDMA7Mem; +extern _SPU2writeDMA7Mem SPU2writeDMA7Mem; +extern _SPU2setDMABaseAddr SPU2setDMABaseAddr; +extern _SPU2interruptDMA7 SPU2interruptDMA7; +extern _SPU2ReadMemAddr SPU2ReadMemAddr; +extern _SPU2setupRecording SPU2setupRecording; +extern _SPU2WriteMemAddr SPU2WriteMemAddr; +extern _SPU2irqCallback SPU2irqCallback; + +extern _SPU2setClockPtr SPU2setClockPtr; +extern _SPU2setTimeStretcher SPU2setTimeStretcher; + +extern _SPU2async SPU2async; +extern _SPU2freeze SPU2freeze; +extern _SPU2configure SPU2configure; +extern _SPU2test SPU2test; +extern _SPU2about SPU2about; + +// CDVD +extern _CDVDinit CDVDinit; +extern _CDVDopen CDVDopen; +extern _CDVDclose CDVDclose; +extern _CDVDshutdown CDVDshutdown; +extern _CDVDreadTrack CDVDreadTrack; +extern _CDVDgetBuffer CDVDgetBuffer; +extern _CDVDreadSubQ CDVDreadSubQ; +extern _CDVDgetTN CDVDgetTN; +extern _CDVDgetTD CDVDgetTD; +extern _CDVDgetTOC CDVDgetTOC; +extern _CDVDgetDiskType CDVDgetDiskType; +extern _CDVDgetTrayStatus CDVDgetTrayStatus; +extern _CDVDctrlTrayOpen CDVDctrlTrayOpen; +extern _CDVDctrlTrayClose CDVDctrlTrayClose; + +extern _CDVDconfigure CDVDconfigure; +extern _CDVDtest CDVDtest; +extern _CDVDabout CDVDabout; +extern _CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +extern _DEV9init DEV9init; +extern _DEV9open DEV9open; +extern _DEV9close DEV9close; +extern _DEV9shutdown DEV9shutdown; +extern _DEV9read8 DEV9read8; +extern _DEV9read16 DEV9read16; +extern _DEV9read32 DEV9read32; +extern _DEV9write8 DEV9write8; +extern _DEV9write16 DEV9write16; +extern _DEV9write32 DEV9write32; +extern _DEV9readDMA8Mem DEV9readDMA8Mem; +extern _DEV9writeDMA8Mem DEV9writeDMA8Mem; +extern _DEV9irqCallback DEV9irqCallback; +extern _DEV9irqHandler DEV9irqHandler; + +extern _DEV9configure DEV9configure; +extern _DEV9freeze DEV9freeze; +extern _DEV9test DEV9test; +extern _DEV9about DEV9about; + +// USB +extern _USBinit USBinit; +extern _USBopen USBopen; +extern _USBclose USBclose; +extern _USBshutdown USBshutdown; +extern _USBread8 USBread8; +extern _USBread16 USBread16; +extern _USBread32 USBread32; +extern _USBwrite8 USBwrite8; +extern _USBwrite16 USBwrite16; +extern _USBwrite32 USBwrite32; +extern _USBasync USBasync; + +extern _USBirqCallback USBirqCallback; +extern _USBirqHandler USBirqHandler; +extern _USBsetRAM USBsetRAM; + +extern _USBconfigure USBconfigure; +extern _USBfreeze USBfreeze; +extern _USBtest USBtest; +extern _USBabout USBabout; + +// FW +extern _FWinit FWinit; +extern _FWopen FWopen; +extern _FWclose FWclose; +extern _FWshutdown FWshutdown; +extern _FWread32 FWread32; +extern _FWwrite32 FWwrite32; +extern _FWirqCallback FWirqCallback; + +extern _FWconfigure FWconfigure; +extern _FWfreeze FWfreeze; +extern _FWtest FWtest; +extern _FWabout FWabout; +#endif + +#ifdef __cplusplus +} // End extern "C" +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/zerospu2/common/PS2Etypes.h b/plugins/zerospu2/common/PS2Etypes.h index 59be1c3de4..4c62b47f0f 100644 --- a/plugins/zerospu2/common/PS2Etypes.h +++ b/plugins/zerospu2/common/PS2Etypes.h @@ -1,219 +1,219 @@ -/* Pcsx2 - Pc Ps2 Emulator - * Copyright (C) 2002-2008 Pcsx2 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 - */ -#ifndef __PS2ETYPES_H__ -#define __PS2ETYPES_H__ - -#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case -#define __LINUX__ -#endif - -#ifdef __CYGWIN__ -#define __LINUX__ -#endif - -#ifndef ARRAYSIZE -#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) -#endif - -#ifdef __LINUX__ -#define CALLBACK -#else -#define CALLBACK __stdcall -#endif - - -// jASSUME - give hints to the optimizer -// This is primarily useful for the default case switch optimizer, which enables VC to -// generate more compact switches. - -#ifdef NDEBUG -# define jBREAKPOINT() ((void) 0) -# ifdef _MSC_VER -# define jASSUME(exp) (__assume(exp)) -# else -# define jASSUME(exp) ((void) sizeof(exp)) -# endif -#else -# if defined(_MSC_VER) -# define jBREAKPOINT() do { __asm int 3 } while(0) -# else -# define jBREAKPOINT() ((void) *(volatile char *) 0) -# endif -# define jASSUME(exp) if(exp) ; else jBREAKPOINT() -#endif - -// disable the default case in a switch -#define jNO_DEFAULT \ -{ \ - break; \ - \ -default: \ - jASSUME(0); \ - break; \ -} - - -// Basic types -#if defined(_MSC_VER) - -typedef __int8 s8; -typedef __int16 s16; -typedef __int32 s32; -typedef __int64 s64; - -typedef unsigned __int8 u8; -typedef unsigned __int16 u16; -typedef unsigned __int32 u32; -typedef unsigned __int64 u64; - -typedef unsigned int uint; - -#define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x -#define PCSX2_ALIGNED16(x) __declspec(align(16)) x -#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x - -#define __naked __declspec(naked) - -#else // _MSC_VER - -#ifdef __LINUX__ - -#ifdef HAVE_STDINT_H -#include "stdint.h" - -typedef int8_t s8; -typedef int16_t s16; -typedef int32_t s32; -typedef int64_t s64; - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -typedef uintptr_t uptr; -typedef intptr_t sptr; - -#else // HAVE_STDINT_H - -typedef char s8; -typedef short s16; -typedef int s32; -typedef long long s64; - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long long u64; - -#endif // HAVE_STDINT_H - -typedef unsigned int uint; - -#define LONG long -typedef union _LARGE_INTEGER -{ - long long QuadPart; -} LARGE_INTEGER; - -#define __fastcall __attribute__((fastcall)) -#define __unused __attribute__((unused)) -#define _inline __inline__ __attribute__((unused)) -#define __forceinline __attribute__((always_inline,unused)) -#define __naked // GCC lacks the naked specifier - -#endif // __LINUX__ - -#define PCSX2_ALIGNED(alig,x) x __attribute((aligned(alig))) -#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) - -#define PCSX2_ALIGNED16_DECL(x) x - -#endif // _MSC_VER - -#if !defined(__LINUX__) || !defined(HAVE_STDINT_H) -#if defined(__x86_64__) -typedef u64 uptr; -typedef s64 sptr; -#else -typedef u32 uptr; -typedef s32 sptr; -#endif -#endif - -// A rough-and-ready cross platform 128-bit datatype, Non-SSE style. -#ifdef __cplusplus -struct u128 -{ - u64 lo; - u64 hi; - - // Implicit conversion from u64 - u128( u64 src ) : - lo( src ) - , hi( 0 ) {} - - // Implicit conversion from u32 - u128( u32 src ) : - lo( src ) - , hi( 0 ) {} -}; - -struct s128 -{ - s64 lo; - s64 hi; - - // Implicit conversion from u64 - s128( s64 src ) : - lo( src ) - , hi( 0 ) {} - - // Implicit conversion from u32 - s128( s32 src ) : - lo( src ) - , hi( 0 ) {} -}; - -#else - -typedef union _u128_t -{ - u64 lo; - u64 hi; -} u128; - -typedef union _s128_t -{ - s64 lo; - s64 hi; -} s128; - -#endif - -typedef struct { - int size; - s8 *data; -} freezeData; - -/* common defines */ -#ifndef C_ASSERT -#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] -#endif - -#endif /* __PS2ETYPES_H__ */ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 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 + */ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +#ifdef __CYGWIN__ +#define __LINUX__ +#endif + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#ifdef __LINUX__ +#define CALLBACK +#else +#define CALLBACK __stdcall +#endif + + +// jASSUME - give hints to the optimizer +// This is primarily useful for the default case switch optimizer, which enables VC to +// generate more compact switches. + +#ifdef NDEBUG +# define jBREAKPOINT() ((void) 0) +# ifdef _MSC_VER +# define jASSUME(exp) (__assume(exp)) +# else +# define jASSUME(exp) ((void) sizeof(exp)) +# endif +#else +# if defined(_MSC_VER) +# define jBREAKPOINT() do { __asm int 3 } while(0) +# else +# define jBREAKPOINT() ((void) *(volatile char *) 0) +# endif +# define jASSUME(exp) if(exp) ; else jBREAKPOINT() +#endif + +// disable the default case in a switch +#define jNO_DEFAULT \ +{ \ + break; \ + \ +default: \ + jASSUME(0); \ + break; \ +} + + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +typedef unsigned int uint; + +#define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x + +#define __naked __declspec(naked) + +#else // _MSC_VER + +#ifdef __LINUX__ + +#ifdef HAVE_STDINT_H +#include "stdint.h" + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef uintptr_t uptr; +typedef intptr_t sptr; + +#else // HAVE_STDINT_H + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#endif // HAVE_STDINT_H + +typedef unsigned int uint; + +#define LONG long +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; + +#define __fastcall __attribute__((fastcall)) +#define __unused __attribute__((unused)) +#define _inline __inline__ __attribute__((unused)) +#define __forceinline __attribute__((always_inline,unused)) +#define __naked // GCC lacks the naked specifier + +#endif // __LINUX__ + +#define PCSX2_ALIGNED(alig,x) x __attribute((aligned(alig))) +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) + +#define PCSX2_ALIGNED16_DECL(x) x + +#endif // _MSC_VER + +#if !defined(__LINUX__) || !defined(HAVE_STDINT_H) +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif +#endif + +// A rough-and-ready cross platform 128-bit datatype, Non-SSE style. +#ifdef __cplusplus +struct u128 +{ + u64 lo; + u64 hi; + + // Implicit conversion from u64 + u128( u64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + u128( u32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +struct s128 +{ + s64 lo; + s64 hi; + + // Implicit conversion from u64 + s128( s64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + s128( s32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +#else + +typedef union _u128_t +{ + u64 lo; + u64 hi; +} u128; + +typedef union _s128_t +{ + s64 lo; + s64 hi; +} s128; + +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/zerospu2/misc.h b/plugins/zerospu2/misc.h index 9a198108c8..17c3426b45 100644 --- a/plugins/zerospu2/misc.h +++ b/plugins/zerospu2/misc.h @@ -1,147 +1,147 @@ -/* ZeroSPU2 - * Copyright (C) 2006-2007 zerofrog - * - * 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 - */ - - #ifdef __LINUX__ -#include -#include -#include // ftime(), struct timeb - -#define Sleep(ms) usleep(1000*ms) - -inline unsigned long timeGetTime() -{ -#ifdef _WIN32 - _timeb t; - _ftime(&t); -#else - timeb t; - ftime(&t); -#endif - - return (unsigned long)(t.time*1000+t.millitm); -} - -#include - -#else -#include -#include - -#include // ftime(), struct timeb -#endif - -inline u64 GetMicroTime() -{ -#ifdef _WIN32 - extern LARGE_INTEGER g_counterfreq; - LARGE_INTEGER count; - QueryPerformanceCounter(&count); - return count.QuadPart * 1000000 / g_counterfreq.QuadPart; -#else - timeval t; - gettimeofday(&t, NULL); - return t.tv_sec*1000000+t.tv_usec; -#endif -} - -#if !defined(_MSC_VER) && !defined(HAVE_ALIGNED_MALLOC) - -#include - -// declare linux equivalents -static __forceinline void* pcsx2_aligned_malloc(size_t size, size_t align) -{ - assert( align < 0x10000 ); - char* p = (char*)malloc(size+align); - int off = 2+align - ((int)(uptr)(p+2) % align); - - p += off; - *(u16*)(p-2) = off; - - return p; -} - -static __forceinline void pcsx2_aligned_free(void* pmem) -{ - if( pmem != NULL ) { - char* p = (char*)pmem; - free(p - (int)*(u16*)(p-2)); - } -} - -#define _aligned_malloc pcsx2_aligned_malloc -#define _aligned_free pcsx2_aligned_free -#endif - -// Atomic Operations -#if defined (_WIN32) - -#ifndef __x86_64__ -extern "C" LONG __cdecl _InterlockedExchangeAdd(LPLONG volatile Addend, LONG Value); -#endif - -#pragma intrinsic (_InterlockedExchangeAdd) -#define InterlockedExchangeAdd _InterlockedExchangeAdd - -#else - -//typedef void* PVOID; - -static __forceinline long InterlockedExchange(volatile long* Target, long Value) -{ - long result; - /* - * The XCHG instruction always locks the bus with or without the - * LOCKED prefix. This makes it significantly slower than CMPXCHG on - * uni-processor machines. The Windows InterlockedExchange function - * is nearly 3 times faster than the XCHG instruction, so this routine - * is not yet very useful for speeding up pthreads. - */ - - __asm__ __volatile__ ( - "xchgl %2,%1" - :"=r" (result) - :"m" (*Target), "0" (Value)); - - return result; -} - -static __forceinline long InterlockedExchangeAdd(volatile long* Addend, long Value) -{ - __asm__ __volatile__( - ".intel_syntax\n" - "lock xadd [%0], %%eax\n" - ".att_syntax\n" : : "r"(Addend), "a"(Value) : "memory"); -} - -static __forceinline long InterlockedCompareExchange(volatile long *dest, long value, long comp) -{ - long result; - - __asm__ __volatile__ ( - "lock\n\t" - "cmpxchgl %2,%1" /* if (EAX == [location]) */ - /* [location] = value */ - /* else */ - /* EAX = [location] */ - :"=a" (result) - :"m" (*dest), "r" (value), "a" (comp)); - - return result; -} -#endif +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 + */ + + #ifdef __LINUX__ +#include +#include +#include // ftime(), struct timeb + +#define Sleep(ms) usleep(1000*ms) + +inline unsigned long timeGetTime() +{ +#ifdef _WIN32 + _timeb t; + _ftime(&t); +#else + timeb t; + ftime(&t); +#endif + + return (unsigned long)(t.time*1000+t.millitm); +} + +#include + +#else +#include +#include + +#include // ftime(), struct timeb +#endif + +inline u64 GetMicroTime() +{ +#ifdef _WIN32 + extern LARGE_INTEGER g_counterfreq; + LARGE_INTEGER count; + QueryPerformanceCounter(&count); + return count.QuadPart * 1000000 / g_counterfreq.QuadPart; +#else + timeval t; + gettimeofday(&t, NULL); + return t.tv_sec*1000000+t.tv_usec; +#endif +} + +#if !defined(_MSC_VER) && !defined(HAVE_ALIGNED_MALLOC) + +#include + +// declare linux equivalents +static __forceinline void* pcsx2_aligned_malloc(size_t size, size_t align) +{ + assert( align < 0x10000 ); + char* p = (char*)malloc(size+align); + int off = 2+align - ((int)(uptr)(p+2) % align); + + p += off; + *(u16*)(p-2) = off; + + return p; +} + +static __forceinline void pcsx2_aligned_free(void* pmem) +{ + if( pmem != NULL ) { + char* p = (char*)pmem; + free(p - (int)*(u16*)(p-2)); + } +} + +#define _aligned_malloc pcsx2_aligned_malloc +#define _aligned_free pcsx2_aligned_free +#endif + +// Atomic Operations +#if defined (_WIN32) + +#ifndef __x86_64__ +extern "C" LONG __cdecl _InterlockedExchangeAdd(LPLONG volatile Addend, LONG Value); +#endif + +#pragma intrinsic (_InterlockedExchangeAdd) +#define InterlockedExchangeAdd _InterlockedExchangeAdd + +#else + +//typedef void* PVOID; + +static __forceinline long InterlockedExchange(volatile long* Target, long Value) +{ + long result; + /* + * The XCHG instruction always locks the bus with or without the + * LOCKED prefix. This makes it significantly slower than CMPXCHG on + * uni-processor machines. The Windows InterlockedExchange function + * is nearly 3 times faster than the XCHG instruction, so this routine + * is not yet very useful for speeding up pthreads. + */ + + __asm__ __volatile__ ( + "xchgl %2,%1" + :"=r" (result) + :"m" (*Target), "0" (Value)); + + return result; +} + +static __forceinline long InterlockedExchangeAdd(volatile long* Addend, long Value) +{ + __asm__ __volatile__( + ".intel_syntax\n" + "lock xadd [%0], %%eax\n" + ".att_syntax\n" : : "r"(Addend), "a"(Value) : "memory"); +} + +static __forceinline long InterlockedCompareExchange(volatile long *dest, long value, long comp) +{ + long result; + + __asm__ __volatile__ ( + "lock\n\t" + "cmpxchgl %2,%1" /* if (EAX == [location]) */ + /* [location] = value */ + /* else */ + /* EAX = [location] */ + :"=a" (result) + :"m" (*dest), "r" (value), "a" (comp)); + + return result; +} +#endif diff --git a/plugins/zerospu2/reg.h b/plugins/zerospu2/reg.h index c5b6cfd429..27f5931fc7 100644 --- a/plugins/zerospu2/reg.h +++ b/plugins/zerospu2/reg.h @@ -1,182 +1,182 @@ -/* ZeroSPU2 - * Copyright (C) 2006-2007 zerofrog - * - * 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 - */ - - -#ifndef __REG_H__ -#define __REG_H__ - -//////////////////// -// SPU2 Registers // -//////////////////// -enum -{ -// Volume Registers - currently not implemented in ZeroSPU2, like most volume registers. - REG_VP_VOLL = 0x0000, // Voice Volume Left - REG_VP_VOLR = 0x0002, // Voice Volume Right - REG_VP_PITCH = 0x0004, // Pitch - REG_VP_ADSR1 = 0x0006, // Envelope 1 (Attack-Decay-Sustain-Release) - REG_VP_ADSR2 = 0x0008, // Envelope 2 (Attack-Decay-Sustain-Release) - REG_VP_ENVX = 0x000A, // Current Envelope - REG_VP_VOLXL = 0x000C, // Current Voice Volume Left - REG_VP_VOLXR = 0x000E, // Current Voice Volume Right -// end unimplemented section - - REG_C0_FMOD1 = 0x0180, // Pitch Modulation Spec. - REG_C0_FMOD2 = 0x0182, - REG_S_NON = 0x0184, // Alloc Noise Generator - unimplemented - REG_C0_VMIXL1 = 0x0188, // Voice Output Mix Left (Dry) - REG_C0_VMIXL2 = 0x018A, - REG_S_VMIXEL = 0x018C, // Voice Output Mix Left (Wet) - unimplemented - REG_C0_VMIXR1 = 0x0190, // Voice Output Mix Right (Dry) - REG_C0_VMIXR2 = 0x0192, - REG_S_VMIXER = 0x0194, // Voice Output Mix Right (Wet) - unimplemented - - REG_C0_MMIX = 0x0198, // Output Spec. After Voice Mix - REG_C0_CTRL = 0x019A, // Core X Attrib - REG_C0_IRQA_HI = 0x019C, // Interrupt Address Spec. - Hi - REG_C0_IRQA_LO = 0x019E, // Interrupt Address Spec. - Lo - - REG_C0_SPUON1 = 0x01A0, // Key On 0/1 - REG_C0_SPUON2 = 0x01A2, - REG_C0_SPUOFF1 = 0x01A4, // Key Off 0/1 - REG_C0_SPUOFF2 = 0x01A6, - - REG_C0_SPUADDR_HI = 0x01A8, // Transfer starting address - hi - REG_C0_SPUADDR_LO = 0x01AA, // Transfer starting address - lo - REG_C0_SPUDATA = 0x01AC, // Transfer data - REG_C0_DMACTRL = 0x01AE, // unimplemented - REG_C0_ADMAS = 0x01B0, // AutoDMA Status - - // Section Unimplemented - // Actually, some are implemented but weren't using the constants. - REG_VA_SSA = 0x01C0, // Waveform data starting address - REG_VA_LSAX = 0x01C4, // Loop point address - REG_VA_NAX = 0x01C8, // Waveform data that should be read next - REG_A_ESA = 0x02E0, //Address: Top address of working area for effects processing - R_FB_SRC_A = 0x02E4, // Feedback Source A - R_FB_SRC_B = 0x02E8, // Feedback Source B -R_IIR_DEST_A0 = 0x02EC, -R_IIR_DEST_A1 = 0x02F0, -R_ACC_SRC_A0 = 0x02F4, -R_ACC_SRC_A1 = 0x02F8, -R_ACC_SRC_B0 = 0x02FC, -R_ACC_SRC_B1 = 0x0300, -R_IIR_SRC_A0 = 0x0304, -R_IIR_SRC_A1 = 0x0308, -R_IIR_DEST_B0 = 0x030C, -R_IIR_DEST_B1 = 0x0310, -R_ACC_SRC_C0 = 0x0314, -R_ACC_SRC_C1 = 0x0318, -R_ACC_SRC_D0 = 0x031C, -R_ACC_SRC_D1 = 0x0320, -R_IIR_SRC_B1 = 0x0324, -R_IIR_SRC_B0 = 0x0328, -R_MIX_DEST_A0 = 0x032C, -R_MIX_DEST_A1 = 0x0330, -R_MIX_DEST_B0 = 0x0334, -R_MIX_DEST_B1 = 0x0338, - REG_A_EEA = 0x033C, // Address: End address of working area for effects processing (upper part of address only!) - // end unimplemented section - - REG_C0_END1 = 0x0340, // End Point passed flag - REG_C0_END2 = 0x0342, - REG_C0_SPUSTAT = 0x0344, // Status register? - - // core 1 has the same registers with 0x400 added, and ends at 0x746. - REG_C1_FMOD1 = 0x0580, - REG_C1_FMOD2 = 0x0582, - REG_C1_VMIXL1 = 0x0588, - REG_C1_VMIXL2 = 0x058A, - REG_C1_VMIXR1 = 0x0590, - REG_C1_VMIXR2 = 0x0592, - REG_C1_MMIX = 0x0598, - REG_C1_CTRL = 0x059A, - REG_C1_IRQA_HI = 0x059C, - REG_C1_IRQA_LO = 0x059E, - REG_C1_SPUON1 = 0x05A0, - REG_C1_SPUON2 = 0x05A2, - REG_C1_SPUOFF1 = 0x05A4, - REG_C1_SPUOFF2 = 0x05A6, - REG_C1_SPUADDR_HI = 0x05A8, - REG_C1_SPUADDR_LO = 0x05AA, - REG_C1_SPUDATA = 0x05AC, - REG_C1_DMACTRL = 0x05AE, // unimplemented - REG_C1_ADMAS = 0x05B0, - REG_C1_END1 = 0x0740, - REG_C1_END2 = 0x0742, - REG_C1_SPUSTAT = 0x0744, - - // Interesting to note that *most* of the volume controls aren't implemented in Zerospu2. - REG_P_MVOLL = 0x0760, // Master Volume Left - unimplemented - REG_P_MVOLR = 0x0762, // Master Volume Right - unimplemented - REG_P_EVOLL = 0x0764, // Effect Volume Left - unimplemented - REG_P_EVOLR = 0x0766, // Effect Volume Right - unimplemented - REG_P_AVOLL = 0x0768, // Core External Input Volume Left (Only Core 1) - unimplemented - REG_P_AVOLR = 0x076A, // Core External Input Volume Right (Only Core 1) - unimplemented - REG_C0_BVOLL = 0x076C, // Sound Data Volume Left - REG_C0_BVOLR = 0x076E, // Sound Data Volume Right - REG_P_MVOLXL = 0x0770, // Current Master Volume Left - unimplemented - REG_P_MVOLXR = 0x0772, // Current Master Volume Right - unimplemented - - // Another unimplemented section - R_IIR_ALPHA = 0x0774, // IIR alpha (% used) - R_ACC_COEF_A = 0x0776, - R_ACC_COEF_B = 0x0778, - R_ACC_COEF_C = 0x077A, - R_ACC_COEF_D = 0x077C, - R_IIR_COEF = 0x077E, - R_FB_ALPHA = 0x0780, // feedback alpha (% used) - R_FB_X = 0x0782, // feedback - R_IN_COEF_L = 0x0784, - R_IN_COEF_R = 0x0786, - // end unimplemented section - - REG_C1_BVOLL = 0x0794, - REG_C1_BVOLR = 0x0796, - - SPDIF_OUT = 0x07C0, // SPDIF Out: OFF/'PCM'/Bitstream/Bypass - unimplemented - REG_IRQINFO = 0x07C2, - SPDIF_MODE = 0x07C6, // unimplemented - SPDIF_MEDIA = 0x07C8, // SPDIF Media: 'CD'/DVD - unimplemented - SPDIF_COPY_PROT = 0x07CC // SPDIF Copy Protection - unimplemented - // NOTE: SPDIF_COPY is defined in Linux kernel headers as 0x0004. -}; - -// These SPDIF defines aren't used yet - swiped from spu2ghz, like a number of the registers I added in. -// -- arcum42 -#define SPDIF_OUT_OFF 0x0000 //no spdif output -#define SPDIF_OUT_PCM 0x0020 //encode spdif from spu2 pcm output -#define SPDIF_OUT_BYPASS 0x0100 //bypass spu2 processing - -#define SPDIF_MODE_BYPASS_BITSTREAM 0x0002 //bypass mode for digital bitstream data -#define SPDIF_MODE_BYPASS_PCM 0x0000 //bypass mode for pcm data (using analog output) - -#define SPDIF_MODE_MEDIA_CD 0x0800 //source media is a CD -#define SPDIF_MODE_MEDIA_DVD 0x0000 //source media is a DVD - -#define SPDIF_MEDIA_CDVD 0x0200 -#define SPDIF_MEDIA_400 0x0000 - -#define SPDIF_COPY_NORMAL 0x0000 // spdif stream is not protected -#define SPDIF_COPY_PROHIBIT 0x8000 // spdif stream can't be copied - -#define SPU_AUTODMA_ONESHOT 0 //spu2 -#define SPU_AUTODMA_LOOP 1 //spu2 -#define SPU_AUTODMA_START_ADDR (1 << 1) //spu2 - +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 + */ + + +#ifndef __REG_H__ +#define __REG_H__ + +//////////////////// +// SPU2 Registers // +//////////////////// +enum +{ +// Volume Registers - currently not implemented in ZeroSPU2, like most volume registers. + REG_VP_VOLL = 0x0000, // Voice Volume Left + REG_VP_VOLR = 0x0002, // Voice Volume Right + REG_VP_PITCH = 0x0004, // Pitch + REG_VP_ADSR1 = 0x0006, // Envelope 1 (Attack-Decay-Sustain-Release) + REG_VP_ADSR2 = 0x0008, // Envelope 2 (Attack-Decay-Sustain-Release) + REG_VP_ENVX = 0x000A, // Current Envelope + REG_VP_VOLXL = 0x000C, // Current Voice Volume Left + REG_VP_VOLXR = 0x000E, // Current Voice Volume Right +// end unimplemented section + + REG_C0_FMOD1 = 0x0180, // Pitch Modulation Spec. + REG_C0_FMOD2 = 0x0182, + REG_S_NON = 0x0184, // Alloc Noise Generator - unimplemented + REG_C0_VMIXL1 = 0x0188, // Voice Output Mix Left (Dry) + REG_C0_VMIXL2 = 0x018A, + REG_S_VMIXEL = 0x018C, // Voice Output Mix Left (Wet) - unimplemented + REG_C0_VMIXR1 = 0x0190, // Voice Output Mix Right (Dry) + REG_C0_VMIXR2 = 0x0192, + REG_S_VMIXER = 0x0194, // Voice Output Mix Right (Wet) - unimplemented + + REG_C0_MMIX = 0x0198, // Output Spec. After Voice Mix + REG_C0_CTRL = 0x019A, // Core X Attrib + REG_C0_IRQA_HI = 0x019C, // Interrupt Address Spec. - Hi + REG_C0_IRQA_LO = 0x019E, // Interrupt Address Spec. - Lo + + REG_C0_SPUON1 = 0x01A0, // Key On 0/1 + REG_C0_SPUON2 = 0x01A2, + REG_C0_SPUOFF1 = 0x01A4, // Key Off 0/1 + REG_C0_SPUOFF2 = 0x01A6, + + REG_C0_SPUADDR_HI = 0x01A8, // Transfer starting address - hi + REG_C0_SPUADDR_LO = 0x01AA, // Transfer starting address - lo + REG_C0_SPUDATA = 0x01AC, // Transfer data + REG_C0_DMACTRL = 0x01AE, // unimplemented + REG_C0_ADMAS = 0x01B0, // AutoDMA Status + + // Section Unimplemented + // Actually, some are implemented but weren't using the constants. + REG_VA_SSA = 0x01C0, // Waveform data starting address + REG_VA_LSAX = 0x01C4, // Loop point address + REG_VA_NAX = 0x01C8, // Waveform data that should be read next + REG_A_ESA = 0x02E0, //Address: Top address of working area for effects processing + R_FB_SRC_A = 0x02E4, // Feedback Source A + R_FB_SRC_B = 0x02E8, // Feedback Source B +R_IIR_DEST_A0 = 0x02EC, +R_IIR_DEST_A1 = 0x02F0, +R_ACC_SRC_A0 = 0x02F4, +R_ACC_SRC_A1 = 0x02F8, +R_ACC_SRC_B0 = 0x02FC, +R_ACC_SRC_B1 = 0x0300, +R_IIR_SRC_A0 = 0x0304, +R_IIR_SRC_A1 = 0x0308, +R_IIR_DEST_B0 = 0x030C, +R_IIR_DEST_B1 = 0x0310, +R_ACC_SRC_C0 = 0x0314, +R_ACC_SRC_C1 = 0x0318, +R_ACC_SRC_D0 = 0x031C, +R_ACC_SRC_D1 = 0x0320, +R_IIR_SRC_B1 = 0x0324, +R_IIR_SRC_B0 = 0x0328, +R_MIX_DEST_A0 = 0x032C, +R_MIX_DEST_A1 = 0x0330, +R_MIX_DEST_B0 = 0x0334, +R_MIX_DEST_B1 = 0x0338, + REG_A_EEA = 0x033C, // Address: End address of working area for effects processing (upper part of address only!) + // end unimplemented section + + REG_C0_END1 = 0x0340, // End Point passed flag + REG_C0_END2 = 0x0342, + REG_C0_SPUSTAT = 0x0344, // Status register? + + // core 1 has the same registers with 0x400 added, and ends at 0x746. + REG_C1_FMOD1 = 0x0580, + REG_C1_FMOD2 = 0x0582, + REG_C1_VMIXL1 = 0x0588, + REG_C1_VMIXL2 = 0x058A, + REG_C1_VMIXR1 = 0x0590, + REG_C1_VMIXR2 = 0x0592, + REG_C1_MMIX = 0x0598, + REG_C1_CTRL = 0x059A, + REG_C1_IRQA_HI = 0x059C, + REG_C1_IRQA_LO = 0x059E, + REG_C1_SPUON1 = 0x05A0, + REG_C1_SPUON2 = 0x05A2, + REG_C1_SPUOFF1 = 0x05A4, + REG_C1_SPUOFF2 = 0x05A6, + REG_C1_SPUADDR_HI = 0x05A8, + REG_C1_SPUADDR_LO = 0x05AA, + REG_C1_SPUDATA = 0x05AC, + REG_C1_DMACTRL = 0x05AE, // unimplemented + REG_C1_ADMAS = 0x05B0, + REG_C1_END1 = 0x0740, + REG_C1_END2 = 0x0742, + REG_C1_SPUSTAT = 0x0744, + + // Interesting to note that *most* of the volume controls aren't implemented in Zerospu2. + REG_P_MVOLL = 0x0760, // Master Volume Left - unimplemented + REG_P_MVOLR = 0x0762, // Master Volume Right - unimplemented + REG_P_EVOLL = 0x0764, // Effect Volume Left - unimplemented + REG_P_EVOLR = 0x0766, // Effect Volume Right - unimplemented + REG_P_AVOLL = 0x0768, // Core External Input Volume Left (Only Core 1) - unimplemented + REG_P_AVOLR = 0x076A, // Core External Input Volume Right (Only Core 1) - unimplemented + REG_C0_BVOLL = 0x076C, // Sound Data Volume Left + REG_C0_BVOLR = 0x076E, // Sound Data Volume Right + REG_P_MVOLXL = 0x0770, // Current Master Volume Left - unimplemented + REG_P_MVOLXR = 0x0772, // Current Master Volume Right - unimplemented + + // Another unimplemented section + R_IIR_ALPHA = 0x0774, // IIR alpha (% used) + R_ACC_COEF_A = 0x0776, + R_ACC_COEF_B = 0x0778, + R_ACC_COEF_C = 0x077A, + R_ACC_COEF_D = 0x077C, + R_IIR_COEF = 0x077E, + R_FB_ALPHA = 0x0780, // feedback alpha (% used) + R_FB_X = 0x0782, // feedback + R_IN_COEF_L = 0x0784, + R_IN_COEF_R = 0x0786, + // end unimplemented section + + REG_C1_BVOLL = 0x0794, + REG_C1_BVOLR = 0x0796, + + SPDIF_OUT = 0x07C0, // SPDIF Out: OFF/'PCM'/Bitstream/Bypass - unimplemented + REG_IRQINFO = 0x07C2, + SPDIF_MODE = 0x07C6, // unimplemented + SPDIF_MEDIA = 0x07C8, // SPDIF Media: 'CD'/DVD - unimplemented + SPDIF_COPY_PROT = 0x07CC // SPDIF Copy Protection - unimplemented + // NOTE: SPDIF_COPY is defined in Linux kernel headers as 0x0004. +}; + +// These SPDIF defines aren't used yet - swiped from spu2ghz, like a number of the registers I added in. +// -- arcum42 +#define SPDIF_OUT_OFF 0x0000 //no spdif output +#define SPDIF_OUT_PCM 0x0020 //encode spdif from spu2 pcm output +#define SPDIF_OUT_BYPASS 0x0100 //bypass spu2 processing + +#define SPDIF_MODE_BYPASS_BITSTREAM 0x0002 //bypass mode for digital bitstream data +#define SPDIF_MODE_BYPASS_PCM 0x0000 //bypass mode for pcm data (using analog output) + +#define SPDIF_MODE_MEDIA_CD 0x0800 //source media is a CD +#define SPDIF_MODE_MEDIA_DVD 0x0000 //source media is a DVD + +#define SPDIF_MEDIA_CDVD 0x0200 +#define SPDIF_MEDIA_400 0x0000 + +#define SPDIF_COPY_NORMAL 0x0000 // spdif stream is not protected +#define SPDIF_COPY_PROHIBIT 0x8000 // spdif stream can't be copied + +#define SPU_AUTODMA_ONESHOT 0 //spu2 +#define SPU_AUTODMA_LOOP 1 //spu2 +#define SPU_AUTODMA_START_ADDR (1 << 1) //spu2 + #endif \ No newline at end of file diff --git a/plugins/zerospu2/zerospu2.cpp b/plugins/zerospu2/zerospu2.cpp index a125025ede..4fe4e5e817 100644 --- a/plugins/zerospu2/zerospu2.cpp +++ b/plugins/zerospu2/zerospu2.cpp @@ -1,1552 +1,1552 @@ -/* ZeroSPU2 - * Copyright (C) 2006-2007 zerofrog - * - * 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 "zerospu2.h" - -#include -#include - -#ifdef _WIN32 -#include "svnrev.h" -#endif - -#include "SoundTouch/SoundTouch.h" -#include "SoundTouch/WavFile.h" - -char libraryName[256]; - -FILE *spu2Log; -Config conf; - -ADMA Adma4; -ADMA Adma7; - -u32 MemAddr[2]; -u32 g_nSpuInit = 0; -u16 interrupt = 0; -s8 *spu2regs = NULL; -u16* spu2mem = NULL; -u16* pSpuIrq[2] = {NULL}; -u32 dwNewChannel2[2] = {0}; // keeps track of what channels that have been turned on -u32 dwEndChannel2[2] = {0}; // keeps track of what channels have ended -unsigned long dwNoiseVal=1; // global noise generator -bool g_bPlaySound = true; // if true, will output sound, otherwise no -int iFMod[NSSIZE]; -int s_buffers[NSSIZE][2]; // left and right buffers - -// mixer thread variables -static bool s_bThreadExit = true; -static int s_nDropPacket = 0; -string s_strIniPath="inis/zerospu2.ini"; - -#ifdef _WIN32 -LARGE_INTEGER g_counterfreq; -extern HWND hWMain; -HANDLE s_threadSPU2 = NULL; -DWORD WINAPI SPU2ThreadProc(LPVOID); -#else -#include -pthread_t s_threadSPU2; -void* SPU2ThreadProc(void*); -#endif - -static AUDIOBUFFER s_pAudioBuffers[NSPACKETS]; -static int s_nCurBuffer = 0, s_nQueuedBuffers = 0; -static s16* s_pCurOutput = NULL; -static u32 g_startcount=0xffffffff; -static u32 g_packetcount=0; - -// time stretch variables -soundtouch::SoundTouch* pSoundTouch=NULL; -WavOutFile* g_pWavRecord=NULL; // used for recording - -static u64 s_GlobalTimeStamp = 0; -static int s_nDurations[64]={0}; -static int s_nCurDuration=0; -static int s_nTotalDuration=0; - -int SPUCycles = 0, SPUWorkerCycles = 0; -int SPUStartCycle[2]; -int SPUTargetCycle[2]; - -int g_logsound=0; - -int ADMASWrite(int c); - -void InitADSR(); - -// functions of main emu, called on spu irq -void (*irqCallbackSPU2)()=0; -void (*irqCallbackDMA4)()=0; -void (*irqCallbackDMA7)()=0; - -uptr g_pDMABaseAddr=0; - -const int f[5][2] = { - { 0, 0 }, - { 60, 0 }, - { 115, -52 }, - { 98, -55 }, - { 122, -60 } }; - -u32 RateTable[160]; - -// channels and voices -VOICE_PROCESSED voices[SPU_NUMBER_VOICES+1]; // +1 for modulation - -static void InitLibraryName() -{ -#ifdef _WIN32 -#ifdef PUBLIC - - // Public Release! - // Output a simplified string that's just our name: - - strcpy( libraryName, "ZeroSPU2" ); - -#elif defined( SVN_REV_UNKNOWN ) - - // Unknown revision. - // Output a name that includes devbuild status but not - // subversion revision tags: - - strcpy( libraryName, "ZeroSPU2" -# ifdef _DEBUG - "-Debug" -# endif - ); -#else - - // Use TortoiseSVN's SubWCRev utility's output - // to label the specific revision: - - sprintf_s( libraryName, "ZeroSPU2 r%d%s" -# ifdef _DEBUG - "-Debug" -# else - "-Dev" -# endif - ,SVN_REV, - SVN_MODS ? "m" : "" - ); -#endif -#else -// I'll hook in svn version code later. --arcum42 - - strcpy( libraryName, "ZeroSPU2 Playground" -# ifdef _DEBUG - "-Debug" -# endif - ); -# endif - -} - -u32 CALLBACK PS2EgetLibType() -{ - return PS2E_LT_SPU2; -} - -char* CALLBACK PS2EgetLibName() -{ - InitLibraryName(); - return libraryName; -} - -u32 CALLBACK PS2EgetLibVersion2(u32 type) -{ - return (SPU2_MINOR<<24) | (SPU2_VERSION<<16) | (SPU2_REVISION<<8) | SPU2_BUILD; -} - -void __Log(char *fmt, ...) -{ - va_list list; - - if (!conf.Log || spu2Log == NULL) return; - - va_start(list, fmt); - vfprintf(spu2Log, fmt, list); - va_end(list); -} - -s32 CALLBACK SPU2init() -{ - LOG_CALLBACK("SPU2init()\n"); - spu2Log = fopen("logs/spu2.txt", "w"); - if (spu2Log) setvbuf(spu2Log, NULL, _IONBF, 0); - - SPU2_LOG("Spu2 null version %d,%d\n",SPU2_REVISION,SPU2_BUILD); - SPU2_LOG("SPU2init\n"); - -#ifdef _WIN32 - QueryPerformanceFrequency(&g_counterfreq); -#else - char strcurdir[256]; - getcwd(strcurdir, 256); - s_strIniPath = strcurdir; - s_strIniPath += "/inis/zerospu2.ini"; -#endif - - spu2regs = (s8*)malloc(0x10000); - spu2mem = (u16*)malloc(0x200000); // 2Mb - memset(spu2regs, 0, 0x10000); - memset(spu2mem, 0, 0x200000); - if ((spu2mem == NULL) || (spu2regs == NULL)) - { - SysMessage("Error allocating Memory\n"); - return -1; - } - - memset(dwEndChannel2, 0, sizeof(dwEndChannel2)); - memset(dwNewChannel2, 0, sizeof(dwNewChannel2)); - memset(iFMod, 0, sizeof(iFMod)); - memset(s_buffers, 0, sizeof(s_buffers)); - - InitADSR(); - - memset(voices, 0, sizeof(voices)); - // last 24 channels have higher mem offset - for (int i = 0; i < 24; ++i) - voices[i+24].memoffset = 0x400; - - // init each channel - for (u32 i = 0; i < ARRAYSIZE(voices); ++i) { - voices[i].chanid = i; - voices[i].pLoop = voices[i].pStart = voices[i].pCurr = (u8*)spu2mem; - - voices[i].pvoice = (_SPU_VOICE*)((u8*)spu2regs+voices[i].memoffset)+(i%24); - voices[i].ADSRX.SustainLevel = 1024; // -> init sustain - } - - return 0; -} - -s32 CALLBACK SPU2open(void *pDsp) -{ - LOG_CALLBACK("SPU2open()\n"); -#ifdef _WIN32 - hWMain = pDsp == NULL ? NULL : *(HWND*)pDsp; - if (!IsWindow(hWMain)) - hWMain=GetActiveWindow(); -#endif - - LoadConfig(); - - SPUCycles = SPUWorkerCycles = 0; - interrupt = 0; - SPUStartCycle[0] = SPUStartCycle[1] = 0; - SPUTargetCycle[0] = SPUTargetCycle[1] = 0; - s_nDropPacket = 0; - - if ( conf.options & OPTION_TIMESTRETCH ) - { - pSoundTouch = new soundtouch::SoundTouch(); - pSoundTouch->setSampleRate(SAMPLE_RATE); - pSoundTouch->setChannels(2); - pSoundTouch->setTempoChange(0); - - pSoundTouch->setSetting(SETTING_USE_QUICKSEEK, 0); - pSoundTouch->setSetting(SETTING_USE_AA_FILTER, 1); - } - - //conf.Log = 1; - - g_bPlaySound = !(conf.options&OPTION_MUTE); - - if ( g_bPlaySound && SetupSound() != 0 ) - { - SysMessage("ZeroSPU2: Failed to initialize sound"); - g_bPlaySound = false; - } - - if ( g_bPlaySound ) { - // initialize the audio buffers - for (u32 i = 0; i < ARRAYSIZE(s_pAudioBuffers); ++i) - { - s_pAudioBuffers[i].pbuf = (u8*)_aligned_malloc(4*NSSIZE*NSFRAMES, 16); // 4 bytes for each sample - s_pAudioBuffers[i].len = 0; - } - - s_nCurBuffer = 0; - s_nQueuedBuffers = 0; - s_pCurOutput = (s16*)s_pAudioBuffers[0].pbuf; - assert( s_pCurOutput != NULL); - - for (int i = 0; i < ARRAYSIZE(s_nDurations); ++i) - { - s_nDurations[i] = NSFRAMES*1000; - } - s_nTotalDuration = ARRAYSIZE(s_nDurations)*NSFRAMES*1000; - s_nCurDuration = 0; - - // launch the thread - s_bThreadExit = false; -#ifdef _WIN32 - s_threadSPU2 = CreateThread(NULL, 0, SPU2ThreadProc, NULL, 0, NULL); - if ( s_threadSPU2 == NULL ) - { - return -1; - } -#else - if ( pthread_create(&s_threadSPU2, NULL, SPU2ThreadProc, NULL) != 0 ) - { - SysMessage("ZeroSPU2: Failed to create spu2thread\n"); - return -1; - } -#endif - } - - g_nSpuInit = 1; - return 0; -} - -void CALLBACK SPU2close() -{ - LOG_CALLBACK("SPU2close()\n"); - g_nSpuInit = 0; - - if ( g_bPlaySound && !s_bThreadExit ) { - s_bThreadExit = true; - printf("ZeroSPU2: Waiting for thread... "); -#ifdef _WIN32 - WaitForSingleObject(s_threadSPU2, INFINITE); - CloseHandle(s_threadSPU2); s_threadSPU2 = NULL; -#else - pthread_join(s_threadSPU2, NULL); -#endif - printf("done\n"); - } - - RemoveSound(); - - delete g_pWavRecord; g_pWavRecord = NULL; - delete pSoundTouch; pSoundTouch = NULL; - - for (u32 i = 0; i < ARRAYSIZE(s_pAudioBuffers); ++i) - { - _aligned_free(s_pAudioBuffers[i].pbuf); - } - memset(s_pAudioBuffers, 0, sizeof(s_pAudioBuffers)); -} - -void CALLBACK SPU2shutdown() -{ - LOG_CALLBACK("SPU2shutdown()\n"); - free(spu2regs); spu2regs = NULL; - free(spu2mem); spu2mem = NULL; - - if (spu2Log) fclose(spu2Log); -} - -void CALLBACK SPU2async(u32 cycle) -{ - //LOG_CALLBACK("SPU2async()\n"); - SPUCycles += cycle; - - if (interrupt & (1<<2)) - { - if (SPUCycles - SPUStartCycle[1] >= SPUTargetCycle[1]) - { - interrupt &= ~(1<<2); - irqCallbackDMA7(); - } - - } - - if (interrupt & (1<<1)) - { - if (SPUCycles - SPUStartCycle[0] >= SPUTargetCycle[0]) - { - interrupt &= ~(1<<1); - irqCallbackDMA4(); - } - } - - if ( g_nSpuInit ) - { - while( SPUCycles-SPUWorkerCycles > 0 && CYCLES_PER_MS < SPUCycles-SPUWorkerCycles ) - { - SPU2Worker(); - SPUWorkerCycles += CYCLES_PER_MS; - } - } - else - SPUWorkerCycles = SPUCycles; -} - -void InitADSR() // INIT ADSR -{ - u32 r,rs,rd; - int i; - memset(RateTable,0,sizeof(u32)*160); // build the rate table according to Neill's rules (see at bottom of file) - - r=3;rs=1;rd=0; - - for (i=32;i<160;i++) // we start at pos 32 with the real values... everything before is 0 - { - if (r<0x3FFFFFFF) - { - r+=rs; - rd++; - - if (rd==5) - { - rd=1; - rs*=2; - } - } - - if (r>0x3FFFFFFF) r=0x3FFFFFFF; - RateTable[i]=r; - } -} - -int MixADSR(VOICE_PROCESSED* pvoice) // MIX ADSR -{ - u32 rateadd[8] = { 0, 4, 6, 8, 9, 10, 11, 12 }; - - if (pvoice->bStop) // should be stopped: - { - if (pvoice->ADSRX.ReleaseModeExp) // do release - { - s32 temp = ((pvoice->ADSRX.EnvelopeVol>>28)&0x7); - pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F)) - 0x18 + rateadd[temp] + 32]; - } - else - { - pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F)) - 0x0C + 32]; - } - - // bIgnoreLoop sets EnvelopeVol to 0 anyways, so we can use one if statement rather then two. - if ((pvoice->ADSRX.EnvelopeVol<0) || (pvoice->bIgnoreLoop == 0)) - { - pvoice->ADSRX.EnvelopeVol=0; - pvoice->bOn=false; - pvoice->pStart= (u8*)(spu2mem+pvoice->iStartAddr); - pvoice->pLoop= (u8*)(spu2mem+pvoice->iStartAddr); - pvoice->pCurr= (u8*)(spu2mem+pvoice->iStartAddr); - pvoice->bStop = true; - pvoice->bIgnoreLoop = false; - //pvoice->bReverb=0; - //pvoice->bNoise=0; - } - - pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; - - return pvoice->ADSRX.lVolume; - } - else // not stopped yet? - { - s32 temp = ((pvoice->ADSRX.EnvelopeVol>>28)&0x7); - - switch (pvoice->ADSRX.State) - { - case 0: // -> attack - if (pvoice->ADSRX.AttackModeExp) - { - if (pvoice->ADSRX.EnvelopeVol<0x60000000) - pvoice->ADSRX.EnvelopeVol += RateTable[(pvoice->ADSRX.AttackRate^0x7F) - 0x10 + 32]; - else - pvoice->ADSRX.EnvelopeVol += RateTable[(pvoice->ADSRX.AttackRate^0x7F) - 0x18 + 32]; - } - else - { - pvoice->ADSRX.EnvelopeVol += RateTable[(pvoice->ADSRX.AttackRate^0x7F) - 0x10 + 32]; - } - - if (pvoice->ADSRX.EnvelopeVol<0) - { - pvoice->ADSRX.EnvelopeVol=0x7FFFFFFF; - pvoice->ADSRX.State=1; - } - break; - - case 1: // -> decay - pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F)) - 0x18+ rateadd[temp] + 32]; - - if (pvoice->ADSRX.EnvelopeVol<0) pvoice->ADSRX.EnvelopeVol=0; - - if (((pvoice->ADSRX.EnvelopeVol>>27)&0xF) <= pvoice->ADSRX.SustainLevel) - pvoice->ADSRX.State=2; - break; - - case 2: // -> sustain - if (pvoice->ADSRX.SustainIncrease) - { - if ((pvoice->ADSRX.SustainModeExp) && (pvoice->ADSRX.EnvelopeVol>=0x60000000)) - pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.SustainRate^0x7F) - 0x18 + 32]; - else - pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.SustainRate^0x7F) - 0x10 + 32]; - - if (pvoice->ADSRX.EnvelopeVol<0) pvoice->ADSRX.EnvelopeVol=0x7FFFFFFF; - } - else - { - if (pvoice->ADSRX.SustainModeExp) - pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F)) - 0x1B +rateadd[temp] + 32]; - else - pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F)) - 0x0F + 32]; - - if (pvoice->ADSRX.EnvelopeVol<0) pvoice->ADSRX.EnvelopeVol=0; - } - break; - - default: - // This should never happen. - return 0; - } - - pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; - return pvoice->ADSRX.lVolume; - } - - return 0; -} - -void MixChannels(int core) -{ - // mix all channels - int c_offset = 0x0400 * core; - int dma, left_vol, right_vol; - ADMA *Adma; - - if (core == 0) - { - Adma = &Adma4; - dma = 4; - left_vol = REG_C0_BVOLL; - right_vol = REG_C0_BVOLR; - } - else - { - Adma = &Adma7; - dma = 7; - left_vol = REG_C1_BVOLL; - right_vol = REG_C1_BVOLR; - } - - if ((spu2Ru16(REG_C0_MMIX + c_offset) & 0xF0) && (spu2Ru16(REG_C0_ADMAS + c_offset) & (0x1 + core))) - { - for (int ns=0;nsIndex]*(int)spu2Ru16(left_vol))>>16; - if ((spu2Ru16(REG_C0_MMIX + c_offset) & 0x40)) - s_buffers[ns][1] += (((short*)spu2mem)[0x2200 + c_offset +Adma->Index]*(int)spu2Ru16(right_vol))>>16; - - Adma->Index +=1; - MemAddr[core] += 4; - - if (Adma->Index == 128 || Adma->Index == 384) - { - if (ADMASWrite(core)) - { - if (interrupt & (0x2 * (core + 1))) - { - interrupt &= ~(0x2 * (core + 1)); - printf("Stopping double interrupt DMA7\n"); - } - if (core == 0) - irqCallbackDMA4(); - else - irqCallbackDMA7(); - - } - if (core == 1) Adma->Enabled = 2; - } - - if (Adma->Index == 512) - { - if ( Adma->Enabled == 2 ) Adma->Enabled = 0; - Adma->Index = 0; - } - } - } -} - -// simulate SPU2 for 1ms -void SPU2Worker() -{ - int s_1,s_2,fa; - u8* start; - u32 nSample; - int ch,predict_nr,shift_factor,flags,d,s; - - // assume s_buffers are zeroed out - if ( dwNewChannel2[0] || dwNewChannel2[1] ) - s_pAudioBuffers[s_nCurBuffer].newchannels++; - - VOICE_PROCESSED* pChannel=voices; - for (ch=0;chbNew) - { - pChannel->StartSound(); // start new sound - dwEndChannel2[ch/24]&=~(1<<(ch%24)); // clear end channel bit - dwNewChannel2[ch/24]&=~(1<<(ch%24)); // clear channel bit - } - - if (!pChannel->bOn) continue; - - if (pChannel->iActFreq!=pChannel->iUsedFreq) // new psx frequency? - pChannel->VoiceChangeFrequency(); - - // loop until 1 ms of data is reached - int ns = 0; - - while(nsbFMod==1 && iFMod[ns]) // fmod freq channel - pChannel->FModChangeFrequency(ns); - - while(pChannel->spos >= 0x10000 ) - { - if (pChannel->iSBPos == 28) // 28 reached? - { - start=pChannel->pCurr; // set up the current pos - - // special "stop" sign - fixme - an *unsigned* -1? - if (start == (u8*)-1) //!pChannel->bOn - { - pChannel->bOn=false; // -> turn everything off - pChannel->ADSRX.lVolume=0; - pChannel->ADSRX.EnvelopeVol=0; - goto ENDX; // -> and done for this channel - } - - pChannel->iSBPos=0; - - // decode the 16byte packet - s_1=pChannel->s_1; - s_2=pChannel->s_2; - - predict_nr=(s32)start[0]; - shift_factor=predict_nr&0xf; - predict_nr >>= 4; - flags=(s32)start[1]; - start += 2; - - for (nSample=0;nSample<28; ++start) - { - d = (int)*start; - s = ((d & 0xf)<<12); - if (s & 0x8000) s |= 0xffff0000; - - fa = (s >> shift_factor); - fa += ((s_1 * f[predict_nr][0]) >> 6) + ((s_2 * f[predict_nr][1]) >> 6); - s_2 = s_1; - s_1 = fa; - s = ((d & 0xf0) << 8); - - pChannel->SB[nSample++]=fa; - - if (s & 0x8000) s|=0xffff0000; - fa = (s>>shift_factor); - fa += ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1]) >> 6); - s_2 = s_1; - s_1 = fa; - - pChannel->SB[nSample++]=fa; - } - - // irq occurs no matter what core access the address - for (int core = 0; core < 2; ++core) - { - if (((SPU_CONTROL_*)(spu2regs + 0x400 * core + REG_C0_CTRL))->irq) // some callback and irq active? - { - // if irq address reached or irq on looping addr, when stop/loop flag is set - u8* pirq = (u8*)pSpuIrq[core]; - if ((pirq > (start - 16) && pirq <= start) || ((flags & 1) && (pirq > (pChannel->pLoop - 16) && pirq <= pChannel->pLoop))) - { - IRQINFO |= 4<bIgnoreLoop)) - pChannel->pLoop=start-16; // loop adress - - if (flags&1) // 1: stop/loop - { - // We play this block out first... - dwEndChannel2[ch/24]|=(1<<(ch%24)); - - if (flags!=3 || pChannel->pLoop==NULL) - { // and checking if pLoop is set avoids crashes, yeah - start = (u8*)-1; - pChannel->bStop = true; - pChannel->bIgnoreLoop = false; - } - else - { - start = pChannel->pLoop; - } - } - - pChannel->pCurr=start; // store values for next cycle - pChannel->s_1=s_1; - pChannel->s_2=s_2; - } - - fa=pChannel->SB[pChannel->iSBPos++]; // get sample data - pChannel->StoreInterpolationVal(fa); - pChannel->spos -= 0x10000; - } - - if (pChannel->bNoise) - fa=pChannel->iGetNoiseVal(); // get noise val - else - fa=pChannel->iGetInterpolationVal(); // get sample val - - int sval = (MixADSR(pChannel) * fa) / 1023; // mix adsr - - if (pChannel->bFMod == 2) // fmod freq channel - { - iFMod[ns] = sval; // -> store 1T sample data, use that to do fmod on next channel - } - else - { - if (pChannel->bVolumeL) - s_buffers[ns][0]+=(sval * pChannel->leftvol)>>14; - - if (pChannel->bVolumeR) - s_buffers[ns][1]+=(sval * pChannel->rightvol)>>14; - } - - // go to the next packet - ns++; - pChannel->spos += pChannel->sinc; - } -ENDX: - ; - } - - // mix all channels - MixChannels(0); - MixChannels(1); - - if ( g_bPlaySound ) - { - assert( s_pCurOutput != NULL); - - for (int ns=0; ns= 4 * NSSIZE * NSFRAMES) - { - - if ( conf.options & OPTION_RECORDING ) - { - static int lastrectime = 0; - if (timeGetTime() - lastrectime > 5000) - { - printf("ZeroSPU2: recording\n"); - lastrectime = timeGetTime(); - } - LogRawSound(s_pAudioBuffers[s_nCurBuffer].pbuf, 4, s_pAudioBuffers[s_nCurBuffer].pbuf+2, 4, NSSIZE*NSFRAMES); - } - - if ( s_nQueuedBuffers >= ARRAYSIZE(s_pAudioBuffers)-1 ) - { - //ZeroSPU2: dropping packets! game too fast - s_nDropPacket += NSFRAMES; - s_GlobalTimeStamp = GetMicroTime(); - } - else { - // submit to final mixer -#ifdef _DEBUG - if ( g_logsound ) - LogRawSound(s_pAudioBuffers[s_nCurBuffer].pbuf, 4, s_pAudioBuffers[s_nCurBuffer].pbuf+2, 4, NSSIZE*NSFRAMES); -#endif - if ( g_startcount == 0xffffffff ) - { - g_startcount = timeGetTime(); - g_packetcount = 0; - } - - if ( conf.options & OPTION_TIMESTRETCH ) - { - u64 newtime = GetMicroTime(); - if ( s_GlobalTimeStamp == 0 ) - s_GlobalTimeStamp = newtime-NSFRAMES*1000; - u32 newtotal = s_nTotalDuration-s_nDurations[s_nCurDuration]; - u32 duration = (u32)(newtime-s_GlobalTimeStamp); - s_nDurations[s_nCurDuration] = duration; - s_nTotalDuration = newtotal + duration; - s_nCurDuration = (s_nCurDuration+1)%ARRAYSIZE(s_nDurations); - s_GlobalTimeStamp = newtime; - s_pAudioBuffers[s_nCurBuffer].timestamp = timeGetTime(); - s_pAudioBuffers[s_nCurBuffer].avgtime = s_nTotalDuration/ARRAYSIZE(s_nDurations); - } - - s_pAudioBuffers[s_nCurBuffer].len = 4*NSSIZE*NSFRAMES; - InterlockedExchangeAdd((long*)&s_nQueuedBuffers, 1); - - s_nCurBuffer = (s_nCurBuffer+1)%ARRAYSIZE(s_pAudioBuffers); - s_pAudioBuffers[s_nCurBuffer].newchannels = 0; // reset - } - - // restart - s_pCurOutput = (s16*)s_pAudioBuffers[s_nCurBuffer].pbuf; - } - } -} - -// resamples pStereoSamples -void ResampleLinear(s16* pStereoSamples, int oldsamples, s16* pNewSamples, int newsamples) -{ - for (int i = 0; i < newsamples; ++i) - { - int io = i * oldsamples; - int old = io / newsamples; - int rem = io - old * newsamples; - - old *= 2; - int newsampL = pStereoSamples[old] * (newsamples - rem) + pStereoSamples[old+2] * rem; - int newsampR = pStereoSamples[old+1] * (newsamples - rem) + pStereoSamples[old+3] * rem; - pNewSamples[2 * i] = newsampL / newsamples; - pNewSamples[2 * i + 1] = newsampR / newsamples; - } -} - -static PCSX2_ALIGNED16(s16 s_ThreadBuffer[NSSIZE*NSFRAMES*2*5]); - -// SoundTouch's INTEGER system is broken these days, so we'll need this to do float conversions... -static PCSX2_ALIGNED16(float s_floatBuffer[NSSIZE*NSFRAMES*2*5]); - -// communicates with the audio hardware -#ifdef _WIN32 -DWORD WINAPI SPU2ThreadProc(LPVOID) -#else -void* SPU2ThreadProc(void* lpParam) -#endif -{ - int nReadBuf = 0; - - while (!s_bThreadExit) - { - - if (!(conf.options&OPTION_REALTIME)) - { - while(s_nQueuedBuffers< 3 && !s_bThreadExit) - { - //Sleeping - Sleep(1); - if ( s_bThreadExit ) - return NULL; - } - - while( SoundGetBytesBuffered() > 72000 ) - { - //Bytes buffered - Sleep(1); - - if ( s_bThreadExit ) return NULL; - } - } - else - { - while(s_nQueuedBuffers< 1 && !s_bThreadExit) - { - //Sleeping - Sleep(1); - } - } - - - //int ps2delay = timeGetTime() - s_pAudioBuffers[nReadBuf].timestamp; - int NewSamples = s_pAudioBuffers[nReadBuf].avgtime; - - if ( (conf.options & OPTION_TIMESTRETCH) ) - { - - int bytesbuf = SoundGetBytesBuffered(); - if ( bytesbuf < 8000 ) - NewSamples += 1000; - // check the current timestamp, if too far apart, speed up audio - else if ( bytesbuf > 40000 ) - { - //printf("making faster %d\n", timeGetTime() - s_pAudioBuffers[nReadBuf].timestamp); - NewSamples -= (bytesbuf-40000)/10;//*(ps2delay-NewSamples*8/1000); - } - - if ( s_nDropPacket > 0 ) - { - s_nDropPacket--; - NewSamples -= 1000; - } - - NewSamples *= NSSIZE; - NewSamples /= 1000; - - NewSamples = min(NewSamples, NSFRAMES * NSSIZE * 3); - - int oldsamples = s_pAudioBuffers[nReadBuf].len / 4; - - if ((nReadBuf & 3) == 0) // wow, this if statement makes the whole difference - pSoundTouch->setTempoChange(100.0f*(float)oldsamples/(float)NewSamples - 100.0f); - - for( int sx=0; sxputSamples(s_floatBuffer, oldsamples); - - // extract 2*NSFRAMES ms at a time - int nOutSamples; - - do - { - nOutSamples = pSoundTouch->receiveSamples(s_floatBuffer, NSSIZE * NSFRAMES * 5); - if ( nOutSamples > 0 ) - { - for( int sx=0; sx>=1) // loop channels - { - if ((val&1) && voices[ch].pStart) // mmm... start has to be set before key on !?! - { - voices[ch].bNew=true; - voices[ch].bIgnoreLoop = false; - dwNewChannel2[ch/24]|=(1<<(ch%24)); // clear end channel bit - } - } -} - -// turn channels off -void SoundOff(int start,int end,unsigned short val) // SOUND OFF PSX COMMAND -{ - for (int ch=start;ch>=1) // loop channels - { - if (val&1) voices[ch].bStop=true; // && s_chan[i].bOn) mmm... - } -} - -void FModOn(int start,int end,unsigned short val) // FMOD ON PSX COMMAND -{ - int ch; - - for (ch=start;ch>=1) // loop channels - { - if (val&1) - { // -> fmod on/off - if (ch>0) - { - voices[ch].bFMod=1; // --> sound channel - voices[ch-1].bFMod=2; // --> freq channel - } - } - else - voices[ch].bFMod=0; // --> turn off fmod - } -} - -void VolumeOn(int start,int end,unsigned short val,int iRight) // VOLUME ON PSX COMMAND -{ - int ch; - - for (ch=start;ch>=1) // loop channels - { - if (val&1) - { // -> reverb on/off - if (iRight) - voices[ch].bVolumeR = true; - else - voices[ch].bVolumeL = true; - } - else - { - if (iRight) - voices[ch].bVolumeR = false; - else - voices[ch].bVolumeL = false; - } - } -} - -void CALLBACK SPU2write(u32 mem, u16 value) -{ - LOG_CALLBACK("SPU2write()\n"); - u32 spuaddr; - SPU2_LOG("SPU2 write mem %x value %x\n", mem, value); - - assert(C0_SPUADDR() < 0x100000); - assert(C1_SPUADDR() < 0x100000); - - spu2Ru16(mem) = value; - u32 r = mem & 0xffff; - - // channel info - if ((r<0x0180) || (r>=0x0400 && r<0x0580)) // u32s are always >= 0. - { - int ch=0; - if (r >= 0x400) - ch = ((r - 0x400) >> 4) + 24; - else - ch = (r >> 4); - - VOICE_PROCESSED* pvoice = &voices[ch]; - - switch(r & 0x0f) - { - case 0: - case 2: - pvoice->SetVolume(mem & 0x2); - break; - case 4: - { - int NP; - if (value> 0x3fff) - NP=0x3fff; // get pitch val - else - NP=value; - - pvoice->pvoice->pitch = NP; - - NP = (SAMPLE_RATE * NP) / 4096L; // calc frequency - if (NP<1) NP = 1; // some security - pvoice->iActFreq = NP; // store frequency - break; - } - case 6: - { - pvoice->ADSRX.AttackModeExp=(value&0x8000)?1:0; - pvoice->ADSRX.AttackRate = ((value>>8) & 0x007f); - pvoice->ADSRX.DecayRate = (((value>>4) & 0x000f)); - pvoice->ADSRX.SustainLevel = (value & 0x000f); - break; - } - case 8: - pvoice->ADSRX.SustainModeExp = (value&0x8000)?1:0; - pvoice->ADSRX.SustainIncrease= (value&0x4000)?0:1; - pvoice->ADSRX.SustainRate = ((value>>6) & 0x007f); - pvoice->ADSRX.ReleaseModeExp = (value&0x0020)?1:0; - pvoice->ADSRX.ReleaseRate = ((value & 0x001f)); - break; - } - - return; - } - - // more channel info - if ((r>=0x01c0 && r<0x02E0)||(r>=0x05c0 && r<0x06E0)) - { - int ch=0; - unsigned long rx=r; - if (rx>=0x400) - { - ch=24; - rx-=0x400; - } - - ch += ((rx-0x1c0)/12); - rx -= (ch%24)*12; - VOICE_PROCESSED* pvoice = &voices[ch]; - - switch(rx) - { - case REG_VA_SSA: - pvoice->iStartAddr=(((u32)value&0x3f)<<16)|(pvoice->iStartAddr&0xFFFF); - pvoice->pStart=(u8*)(spu2mem+pvoice->iStartAddr); - break; - case 0x1C2: - pvoice->iStartAddr=(pvoice->iStartAddr & 0x3f0000) | (value & 0xFFFF); - pvoice->pStart=(u8*)(spu2mem+pvoice->iStartAddr); - break; - case REG_VA_LSAX: - pvoice->iLoopAddr =(((u32)value&0x3f)<<16)|(pvoice->iLoopAddr&0xFFFF); - pvoice->pLoop=(u8*)(spu2mem+pvoice->iLoopAddr); - pvoice->bIgnoreLoop=pvoice->iLoopAddr>0; - break; - case 0x1C6: - pvoice->iLoopAddr=(pvoice->iLoopAddr& 0x3f0000) | (value & 0xFFFF); - pvoice->pLoop=(u8*)(spu2mem+pvoice->iLoopAddr); - pvoice->bIgnoreLoop=pvoice->iLoopAddr>0; - break; - case REG_VA_NAX: - // unused... check if it gets written as well - pvoice->iNextAddr=(((u32)value&0x3f)<<16)|(pvoice->iNextAddr&0xFFFF); - break; - case 0x1CA: - // unused... check if it gets written as well - pvoice->iNextAddr=(pvoice->iNextAddr & 0x3f0000) | (value & 0xFFFF); - break; - } - - return; - } - - // process non-channel data - switch(mem & 0xffff) - { - case REG_C0_SPUDATA: - spuaddr = C0_SPUADDR(); - spu2mem[spuaddr] = value; - spuaddr++; - - if ((spu2Ru16(REG_C0_CTRL)&0x40) && (C0_IRQA() == spuaddr)) - { - IRQINFO |= 4; - SPU2_LOG("SPU2write:C0_CPUDATA interrupt\n"); - irqCallbackSPU2(); - } - - if (spuaddr>0xFFFFE) spuaddr = 0x2800; - - C0_SPUADDR_SET(spuaddr); - spu2Ru16(REG_C0_SPUSTAT)&=~0x80; - spu2Ru16(REG_C0_CTRL)&=~0x30; - break; - - case REG_C1_SPUDATA: - spuaddr = C1_SPUADDR(); - spu2mem[spuaddr] = value; - spuaddr++; - - if ((spu2Ru16(REG_C1_CTRL)&0x40) && (C1_IRQA() == spuaddr)) - { - IRQINFO |= 8; - SPU2_LOG("SPU2write:C1_CPUDATA interrupt\n"); - irqCallbackSPU2(); - } - - if (spuaddr>0xFFFFE) spuaddr = 0x2800; - - C1_SPUADDR_SET(spuaddr); - spu2Ru16(REG_C1_SPUSTAT)&=~0x80; - spu2Ru16(REG_C1_CTRL)&=~0x30; - break; - - case REG_C0_IRQA_HI: - case REG_C0_IRQA_LO: - pSpuIrq[0] = spu2mem + C0_IRQA(); - break; - - case REG_C1_IRQA_HI: - case REG_C1_IRQA_LO: - pSpuIrq[1] = spu2mem + C1_IRQA(); - break; - - case REG_C0_SPUADDR_HI: - case REG_C1_SPUADDR_HI: - spu2Ru16(mem) = value&0xf; - break; - - case REG_C0_CTRL: - spu2Ru16(mem) = value; - // clear interrupt - if (!(value & 0x40)) IRQINFO &= ~0x4; - break; - - case REG_C1_CTRL: - spu2Ru16(mem) = value; - // clear interrupt - if (!(value & 0x40)) IRQINFO &= ~0x8; - break; - - // Could probably simplify - case REG_C0_SPUON1: SoundOn(0,16,value); break; - case REG_C0_SPUON2: SoundOn(16,24,value); break; - case REG_C1_SPUON1: SoundOn(24,40,value); break; - case REG_C1_SPUON2: SoundOn(40,48,value); break; - case REG_C0_SPUOFF1: SoundOff(0,16,value); break; - case REG_C0_SPUOFF2: SoundOff(16,24,value); break; - case REG_C1_SPUOFF1: SoundOff(24,40,value); break; - case REG_C1_SPUOFF2: SoundOff(40,48,value); break; - - // According to manual all bits are cleared by writing an arbitary value - case REG_C0_END1: dwEndChannel2[0] &= 0x00ff0000; break; - case REG_C0_END2: dwEndChannel2[0] &= 0x0000ffff; break; - case REG_C1_END1: dwEndChannel2[1] &= 0x00ff0000; break; - case REG_C1_END2: dwEndChannel2[1] &= 0x0000ffff; break; - case REG_C0_FMOD1: FModOn(0,16,value); break; - case REG_C0_FMOD2: FModOn(16,24,value); break; - case REG_C1_FMOD1: FModOn(24,40,value); break; - case REG_C1_FMOD2: FModOn(40,48,value); break; - case REG_C0_VMIXL1: VolumeOn(0,16,value,0); break; - case REG_C0_VMIXL2: VolumeOn(16,24,value,0); break; - case REG_C1_VMIXL1: VolumeOn(24,40,value,0); break; - case REG_C1_VMIXL2: VolumeOn(40,48,value,0); break; - case REG_C0_VMIXR1: VolumeOn(0,16,value,1); break; - case REG_C0_VMIXR2: VolumeOn(16,24,value,1); break; - case REG_C1_VMIXR1: VolumeOn(24,40,value,1); break; - case REG_C1_VMIXR2: VolumeOn(40,48,value,1); break; - } - - assert( C0_SPUADDR() < 0x100000); - assert( C1_SPUADDR() < 0x100000); -} - -u16 CALLBACK SPU2read(u32 mem) -{ - LOG_CALLBACK("SPU2read()\n"); - u32 spuaddr; - u16 ret = 0; - u32 r = mem & 0xffff; // register - - // channel info - // if the register is any of the regs before core 0, or is somewhere between core 0 and 1... - if ((r < 0x0180) || (r >= 0x0400 && r < 0x0580)) // u32s are always >= 0. - { - int ch = 0; - - if (r >= 0x400) - ch=((r - 0x400) >> 4) + 24; - else - ch = (r >> 4); - - VOICE_PROCESSED* pvoice = &voices[ch]; - - if ((r&0x0f) == 10) return (u16)(pvoice->ADSRX.EnvelopeVol >> 16); - } - - - if ((r>=REG_VA_SSA && r=0x05c0 && r<0x06E0)) // some channel info? - { - int ch=0; - unsigned long rx = r; - - if (rx >=0x400) - { - ch=24; - rx-=0x400; - } - - ch+=((rx-0x1c0)/12); - rx-=(ch%24)*12; - VOICE_PROCESSED* pvoice = &voices[ch]; - - // Note - can we generalize this? - switch(rx) - { - case REG_VA_SSA: - ret = ((((uptr)pvoice->pStart-(uptr)spu2mem)>>17)&0x3F); - break; - case 0x1C2: - ret = ((((uptr)pvoice->pStart-(uptr)spu2mem)>>1)&0xFFFF); - break; - case REG_VA_LSAX: - ret = ((((uptr)pvoice->pLoop-(uptr)spu2mem)>>17)&0x3F); - break; - case 0x1C6: - ret = ((((uptr)pvoice->pLoop-(uptr)spu2mem)>>1)&0xFFFF); - break; - case REG_VA_NAX: - ret = ((((uptr)pvoice->pCurr-(uptr)spu2mem)>>17)&0x3F); - break; - case 0x1CA: - ret = ((((uptr)pvoice->pCurr-(uptr)spu2mem)>>1)&0xFFFF); - break; - } - - SPU2_LOG("SPU2 channel read mem %x: %x\n", mem, ret); - return ret; - } - - switch(mem & 0xffff) - { - case REG_C0_SPUDATA: - spuaddr = C0_SPUADDR(); - ret =spu2mem[spuaddr]; - spuaddr++; - if (spuaddr > 0xfffff) spuaddr=0; - C0_SPUADDR_SET(spuaddr); - break; - case REG_C1_SPUDATA: - spuaddr = C1_SPUADDR(); - ret = spu2mem[spuaddr]; - spuaddr++; - if (spuaddr > 0xfffff) spuaddr=0; - C1_SPUADDR_SET(spuaddr); - break; - - case REG_C0_END1: ret = (dwEndChannel2[0]&0xffff); break; - case REG_C1_END1: ret = (dwEndChannel2[1]&0xffff); break; - case REG_C0_END2: ret = (dwEndChannel2[0]>>16); break; - case REG_C1_END2: ret = (dwEndChannel2[1]>>16); break; - - case REG_IRQINFO: - ret = IRQINFO; - break; - - default: - ret = spu2Ru16(mem); - } - - SPU2_LOG("SPU2 read mem %x: %x\n", mem, ret); - - return ret; -} - -void CALLBACK SPU2WriteMemAddr(int core, u32 value) -{ - LOG_CALLBACK("SPU2WriteMemAddr(%d, %d)\n", core, value); - MemAddr[core] = g_pDMABaseAddr + value; -} - -u32 CALLBACK SPU2ReadMemAddr(int core) -{ - LOG_CALLBACK("SPU2ReadMemAddr(%d)\n", core); - return MemAddr[core] - g_pDMABaseAddr; -} - -void CALLBACK SPU2setDMABaseAddr(uptr baseaddr) -{ - LOG_CALLBACK("SPU2setDMABaseAddr()\n"); - g_pDMABaseAddr = baseaddr; -} - -void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()) -{ - LOG_CALLBACK("SPU2irqCallback()\n"); - irqCallbackSPU2 = SPU2callback; - irqCallbackDMA4 = DMA4callback; - irqCallbackDMA7 = DMA7callback; -} - -s32 CALLBACK SPU2test() -{ - LOG_CALLBACK("SPU2test()\n"); - return 0; -} - -#define SetPacket(s) \ -{ \ - if (s & 0x8000) s|=0xffff0000; \ - fa = (s >> shift_factor); \ - fa += ((s_1 * f[predict_nr][0]) >> 6) + ((s_2 * f[predict_nr][1]) >> 6); \ - s_2 = s_1; \ - s_1 = fa; \ - buf[nSample++] = fa; \ -} - -// size is in bytes -void LogPacketSound(void* packet, int memsize) -{ - u16 buf[28]; - - u8* pstart = (u8*)packet; - int s_1 = 0, s_2=0; - - for (int i = 0; i < memsize; i += 16) - { - int predict_nr=(int)pstart[0]; - int shift_factor=predict_nr&0xf; - predict_nr >>= 4; - pstart += 2; - - for (int nSample=0;nSample<28; ++pstart) - { - int d=(int)*pstart; - int s, fa; - - s =((d & 0xf) << 12); - SetPacket(s); - - s=((d & 0xf0) << 8); - SetPacket(s); - } - - LogRawSound(buf, 2, buf, 2, 28); - } -} - -void LogRawSound(void* pleft, int leftstride, void* pright, int rightstride, int numsamples) -{ - if (g_pWavRecord == NULL ) - g_pWavRecord = new WavOutFile(RECORD_FILENAME, SAMPLE_RATE, 16, 2); - - u8* left = (u8*)pleft; - u8* right = (u8*)pright; - static vector tempbuf; - - tempbuf.resize(2 * numsamples); - - for (int i = 0; i < numsamples; ++i) - { - tempbuf[2*i+0] = *(s16*)left; - tempbuf[2*i+1] = *(s16*)right; - left += leftstride; - right += rightstride; - } - - g_pWavRecord->write(&tempbuf[0], numsamples*2); -} - -int CALLBACK SPU2setupRecording(int start, void* pData) -{ - LOG_CALLBACK("SPU2setupRecording()\n"); - if ( start ) - { - conf.options |= OPTION_RECORDING; - printf("ZeroSPU2: started recording at %s\n", RECORD_FILENAME); - } - else - { - conf.options &= ~OPTION_RECORDING; - printf("ZeroSPU2: stopped recording\n"); - } - - return 1; -} - -s32 CALLBACK SPU2freeze(int mode, freezeData *data) -{ - LOG_CALLBACK("SPU2freeze()\n"); - SPU2freezeData *spud; - int i; - assert( g_pDMABaseAddr != 0 ); - - if (mode == FREEZE_LOAD) - { - spud = (SPU2freezeData*)data->data; - if (spud->version != 0x70000001) - { - printf("zerospu2: data wrong format\n"); - return 0; - } - - memcpy(spu2regs, spud->spu2regs, 0x10000); - memcpy(spu2mem, spud->spu2mem, 0x200000); - pSpuIrq[0] = spu2mem + spud->nSpuIrq[0]; - pSpuIrq[1] = spu2mem + spud->nSpuIrq[1]; - memcpy(dwNewChannel2, spud->dwNewChannel2, 4*2); - memcpy(dwEndChannel2, spud->dwEndChannel2, 4*2); - dwNoiseVal = spud->dwNoiseVal; - memcpy(iFMod, spud->iFMod, sizeof(iFMod)); - interrupt = spud->interrupt; - memcpy(MemAddr, spud->MemAddr, sizeof(MemAddr)); - Adma4 = spud->adma[0]; - Adma4.MemAddr = (u16*)(g_pDMABaseAddr+spud->Adma4MemAddr); - Adma7 = spud->adma[1]; - Adma7.MemAddr = (u16*)(g_pDMABaseAddr+spud->Adma7MemAddr); - - SPUCycles = spud->SPUCycles; - SPUWorkerCycles = spud->SPUWorkerCycles; - memcpy(SPUStartCycle, spud->SPUStartCycle, sizeof(SPUStartCycle)); - memcpy(SPUTargetCycle, spud->SPUTargetCycle, sizeof(SPUTargetCycle)); - - for (i = 0; i < ARRAYSIZE(voices); ++i) - { - memcpy(&voices[i], &spud->voices[i], min((int)SPU_VOICE_STATE_SIZE, spud->voicesize)); - voices[i].pStart = (u8*)((uptr)spud->voices[i].pStart+(uptr)spu2mem); - voices[i].pLoop = (u8*)((uptr)spud->voices[i].pLoop+(uptr)spu2mem); - voices[i].pCurr = (u8*)((uptr)spud->voices[i].pCurr+(uptr)spu2mem); - } - - s_GlobalTimeStamp = 0; - g_startcount = 0xffffffff; - - for (int i = 0; i < ARRAYSIZE(s_nDurations); ++i) - { - s_nDurations[i] = NSFRAMES*1000; - } - - s_nTotalDuration = ARRAYSIZE(s_nDurations)*NSFRAMES*1000; - s_nCurDuration = 0; - s_nQueuedBuffers = 0; - s_nDropPacket = 0; - } - else if (mode == FREEZE_SAVE) - { - spud = (SPU2freezeData*)data->data; - spud->version = 0x70000001; - - memcpy(spud->spu2regs, spu2regs, 0x10000); - memcpy(spud->spu2mem, spu2mem, 0x200000); - spud->nSpuIrq[0] = (int)(pSpuIrq[0] - spu2mem); - spud->nSpuIrq[1] = (int)(pSpuIrq[1] - spu2mem); - memcpy(spud->dwNewChannel2, dwNewChannel2, 4*2); - memcpy(spud->dwEndChannel2, dwEndChannel2, 4*2); - spud->dwNoiseVal = dwNoiseVal; - memcpy(spud->iFMod, iFMod, sizeof(iFMod)); - spud->interrupt = interrupt; - memcpy(spud->MemAddr, MemAddr, sizeof(MemAddr)); - - spud->adma[0] = Adma4; - spud->Adma4MemAddr = (u32)((uptr)Adma4.MemAddr - g_pDMABaseAddr); - spud->adma[1] = Adma7; - spud->Adma7MemAddr = (u32)((uptr)Adma7.MemAddr - g_pDMABaseAddr); - - spud->SPUCycles = SPUCycles; - spud->SPUWorkerCycles = SPUWorkerCycles; - - memcpy(spud->SPUStartCycle, SPUStartCycle, sizeof(SPUStartCycle)); - memcpy(spud->SPUTargetCycle, SPUTargetCycle, sizeof(SPUTargetCycle)); - - for (i = 0; i < ARRAYSIZE(s_nDurations); ++i) - { - s_nDurations[i] = NSFRAMES*1000; - } - s_nTotalDuration = ARRAYSIZE(s_nDurations)*NSFRAMES*1000; - s_nCurDuration = 0; - - spud->voicesize = SPU_VOICE_STATE_SIZE; - for (i = 0; i < ARRAYSIZE(voices); ++i) - { - memcpy(&spud->voices[i], &voices[i], SPU_VOICE_STATE_SIZE); - spud->voices[i].pStart = (u8*)((uptr)voices[i].pStart-(uptr)spu2mem); - spud->voices[i].pLoop = (u8*)((uptr)voices[i].pLoop-(uptr)spu2mem); - spud->voices[i].pCurr = (u8*)((uptr)voices[i].pCurr-(uptr)spu2mem); - } - - g_startcount=0xffffffff; - s_GlobalTimeStamp = 0; - s_nDropPacket = 0; - } - else if (mode == FREEZE_SIZE) - { - data->size = sizeof(SPU2freezeData); - } - - return 0; -} +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 "zerospu2.h" + +#include +#include + +#ifdef _WIN32 +#include "svnrev.h" +#endif + +#include "SoundTouch/SoundTouch.h" +#include "SoundTouch/WavFile.h" + +char libraryName[256]; + +FILE *spu2Log; +Config conf; + +ADMA Adma4; +ADMA Adma7; + +u32 MemAddr[2]; +u32 g_nSpuInit = 0; +u16 interrupt = 0; +s8 *spu2regs = NULL; +u16* spu2mem = NULL; +u16* pSpuIrq[2] = {NULL}; +u32 dwNewChannel2[2] = {0}; // keeps track of what channels that have been turned on +u32 dwEndChannel2[2] = {0}; // keeps track of what channels have ended +unsigned long dwNoiseVal=1; // global noise generator +bool g_bPlaySound = true; // if true, will output sound, otherwise no +int iFMod[NSSIZE]; +int s_buffers[NSSIZE][2]; // left and right buffers + +// mixer thread variables +static bool s_bThreadExit = true; +static int s_nDropPacket = 0; +string s_strIniPath="inis/zerospu2.ini"; + +#ifdef _WIN32 +LARGE_INTEGER g_counterfreq; +extern HWND hWMain; +HANDLE s_threadSPU2 = NULL; +DWORD WINAPI SPU2ThreadProc(LPVOID); +#else +#include +pthread_t s_threadSPU2; +void* SPU2ThreadProc(void*); +#endif + +static AUDIOBUFFER s_pAudioBuffers[NSPACKETS]; +static int s_nCurBuffer = 0, s_nQueuedBuffers = 0; +static s16* s_pCurOutput = NULL; +static u32 g_startcount=0xffffffff; +static u32 g_packetcount=0; + +// time stretch variables +soundtouch::SoundTouch* pSoundTouch=NULL; +WavOutFile* g_pWavRecord=NULL; // used for recording + +static u64 s_GlobalTimeStamp = 0; +static int s_nDurations[64]={0}; +static int s_nCurDuration=0; +static int s_nTotalDuration=0; + +int SPUCycles = 0, SPUWorkerCycles = 0; +int SPUStartCycle[2]; +int SPUTargetCycle[2]; + +int g_logsound=0; + +int ADMASWrite(int c); + +void InitADSR(); + +// functions of main emu, called on spu irq +void (*irqCallbackSPU2)()=0; +void (*irqCallbackDMA4)()=0; +void (*irqCallbackDMA7)()=0; + +uptr g_pDMABaseAddr=0; + +const int f[5][2] = { + { 0, 0 }, + { 60, 0 }, + { 115, -52 }, + { 98, -55 }, + { 122, -60 } }; + +u32 RateTable[160]; + +// channels and voices +VOICE_PROCESSED voices[SPU_NUMBER_VOICES+1]; // +1 for modulation + +static void InitLibraryName() +{ +#ifdef _WIN32 +#ifdef PUBLIC + + // Public Release! + // Output a simplified string that's just our name: + + strcpy( libraryName, "ZeroSPU2" ); + +#elif defined( SVN_REV_UNKNOWN ) + + // Unknown revision. + // Output a name that includes devbuild status but not + // subversion revision tags: + + strcpy( libraryName, "ZeroSPU2" +# ifdef _DEBUG + "-Debug" +# endif + ); +#else + + // Use TortoiseSVN's SubWCRev utility's output + // to label the specific revision: + + sprintf_s( libraryName, "ZeroSPU2 r%d%s" +# ifdef _DEBUG + "-Debug" +# else + "-Dev" +# endif + ,SVN_REV, + SVN_MODS ? "m" : "" + ); +#endif +#else +// I'll hook in svn version code later. --arcum42 + + strcpy( libraryName, "ZeroSPU2 Playground" +# ifdef _DEBUG + "-Debug" +# endif + ); +# endif + +} + +u32 CALLBACK PS2EgetLibType() +{ + return PS2E_LT_SPU2; +} + +char* CALLBACK PS2EgetLibName() +{ + InitLibraryName(); + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) +{ + return (SPU2_MINOR<<24) | (SPU2_VERSION<<16) | (SPU2_REVISION<<8) | SPU2_BUILD; +} + +void __Log(char *fmt, ...) +{ + va_list list; + + if (!conf.Log || spu2Log == NULL) return; + + va_start(list, fmt); + vfprintf(spu2Log, fmt, list); + va_end(list); +} + +s32 CALLBACK SPU2init() +{ + LOG_CALLBACK("SPU2init()\n"); + spu2Log = fopen("logs/spu2.txt", "w"); + if (spu2Log) setvbuf(spu2Log, NULL, _IONBF, 0); + + SPU2_LOG("Spu2 null version %d,%d\n",SPU2_REVISION,SPU2_BUILD); + SPU2_LOG("SPU2init\n"); + +#ifdef _WIN32 + QueryPerformanceFrequency(&g_counterfreq); +#else + char strcurdir[256]; + getcwd(strcurdir, 256); + s_strIniPath = strcurdir; + s_strIniPath += "/inis/zerospu2.ini"; +#endif + + spu2regs = (s8*)malloc(0x10000); + spu2mem = (u16*)malloc(0x200000); // 2Mb + memset(spu2regs, 0, 0x10000); + memset(spu2mem, 0, 0x200000); + if ((spu2mem == NULL) || (spu2regs == NULL)) + { + SysMessage("Error allocating Memory\n"); + return -1; + } + + memset(dwEndChannel2, 0, sizeof(dwEndChannel2)); + memset(dwNewChannel2, 0, sizeof(dwNewChannel2)); + memset(iFMod, 0, sizeof(iFMod)); + memset(s_buffers, 0, sizeof(s_buffers)); + + InitADSR(); + + memset(voices, 0, sizeof(voices)); + // last 24 channels have higher mem offset + for (int i = 0; i < 24; ++i) + voices[i+24].memoffset = 0x400; + + // init each channel + for (u32 i = 0; i < ARRAYSIZE(voices); ++i) { + voices[i].chanid = i; + voices[i].pLoop = voices[i].pStart = voices[i].pCurr = (u8*)spu2mem; + + voices[i].pvoice = (_SPU_VOICE*)((u8*)spu2regs+voices[i].memoffset)+(i%24); + voices[i].ADSRX.SustainLevel = 1024; // -> init sustain + } + + return 0; +} + +s32 CALLBACK SPU2open(void *pDsp) +{ + LOG_CALLBACK("SPU2open()\n"); +#ifdef _WIN32 + hWMain = pDsp == NULL ? NULL : *(HWND*)pDsp; + if (!IsWindow(hWMain)) + hWMain=GetActiveWindow(); +#endif + + LoadConfig(); + + SPUCycles = SPUWorkerCycles = 0; + interrupt = 0; + SPUStartCycle[0] = SPUStartCycle[1] = 0; + SPUTargetCycle[0] = SPUTargetCycle[1] = 0; + s_nDropPacket = 0; + + if ( conf.options & OPTION_TIMESTRETCH ) + { + pSoundTouch = new soundtouch::SoundTouch(); + pSoundTouch->setSampleRate(SAMPLE_RATE); + pSoundTouch->setChannels(2); + pSoundTouch->setTempoChange(0); + + pSoundTouch->setSetting(SETTING_USE_QUICKSEEK, 0); + pSoundTouch->setSetting(SETTING_USE_AA_FILTER, 1); + } + + //conf.Log = 1; + + g_bPlaySound = !(conf.options&OPTION_MUTE); + + if ( g_bPlaySound && SetupSound() != 0 ) + { + SysMessage("ZeroSPU2: Failed to initialize sound"); + g_bPlaySound = false; + } + + if ( g_bPlaySound ) { + // initialize the audio buffers + for (u32 i = 0; i < ARRAYSIZE(s_pAudioBuffers); ++i) + { + s_pAudioBuffers[i].pbuf = (u8*)_aligned_malloc(4*NSSIZE*NSFRAMES, 16); // 4 bytes for each sample + s_pAudioBuffers[i].len = 0; + } + + s_nCurBuffer = 0; + s_nQueuedBuffers = 0; + s_pCurOutput = (s16*)s_pAudioBuffers[0].pbuf; + assert( s_pCurOutput != NULL); + + for (int i = 0; i < ARRAYSIZE(s_nDurations); ++i) + { + s_nDurations[i] = NSFRAMES*1000; + } + s_nTotalDuration = ARRAYSIZE(s_nDurations)*NSFRAMES*1000; + s_nCurDuration = 0; + + // launch the thread + s_bThreadExit = false; +#ifdef _WIN32 + s_threadSPU2 = CreateThread(NULL, 0, SPU2ThreadProc, NULL, 0, NULL); + if ( s_threadSPU2 == NULL ) + { + return -1; + } +#else + if ( pthread_create(&s_threadSPU2, NULL, SPU2ThreadProc, NULL) != 0 ) + { + SysMessage("ZeroSPU2: Failed to create spu2thread\n"); + return -1; + } +#endif + } + + g_nSpuInit = 1; + return 0; +} + +void CALLBACK SPU2close() +{ + LOG_CALLBACK("SPU2close()\n"); + g_nSpuInit = 0; + + if ( g_bPlaySound && !s_bThreadExit ) { + s_bThreadExit = true; + printf("ZeroSPU2: Waiting for thread... "); +#ifdef _WIN32 + WaitForSingleObject(s_threadSPU2, INFINITE); + CloseHandle(s_threadSPU2); s_threadSPU2 = NULL; +#else + pthread_join(s_threadSPU2, NULL); +#endif + printf("done\n"); + } + + RemoveSound(); + + delete g_pWavRecord; g_pWavRecord = NULL; + delete pSoundTouch; pSoundTouch = NULL; + + for (u32 i = 0; i < ARRAYSIZE(s_pAudioBuffers); ++i) + { + _aligned_free(s_pAudioBuffers[i].pbuf); + } + memset(s_pAudioBuffers, 0, sizeof(s_pAudioBuffers)); +} + +void CALLBACK SPU2shutdown() +{ + LOG_CALLBACK("SPU2shutdown()\n"); + free(spu2regs); spu2regs = NULL; + free(spu2mem); spu2mem = NULL; + + if (spu2Log) fclose(spu2Log); +} + +void CALLBACK SPU2async(u32 cycle) +{ + //LOG_CALLBACK("SPU2async()\n"); + SPUCycles += cycle; + + if (interrupt & (1<<2)) + { + if (SPUCycles - SPUStartCycle[1] >= SPUTargetCycle[1]) + { + interrupt &= ~(1<<2); + irqCallbackDMA7(); + } + + } + + if (interrupt & (1<<1)) + { + if (SPUCycles - SPUStartCycle[0] >= SPUTargetCycle[0]) + { + interrupt &= ~(1<<1); + irqCallbackDMA4(); + } + } + + if ( g_nSpuInit ) + { + while( SPUCycles-SPUWorkerCycles > 0 && CYCLES_PER_MS < SPUCycles-SPUWorkerCycles ) + { + SPU2Worker(); + SPUWorkerCycles += CYCLES_PER_MS; + } + } + else + SPUWorkerCycles = SPUCycles; +} + +void InitADSR() // INIT ADSR +{ + u32 r,rs,rd; + int i; + memset(RateTable,0,sizeof(u32)*160); // build the rate table according to Neill's rules (see at bottom of file) + + r=3;rs=1;rd=0; + + for (i=32;i<160;i++) // we start at pos 32 with the real values... everything before is 0 + { + if (r<0x3FFFFFFF) + { + r+=rs; + rd++; + + if (rd==5) + { + rd=1; + rs*=2; + } + } + + if (r>0x3FFFFFFF) r=0x3FFFFFFF; + RateTable[i]=r; + } +} + +int MixADSR(VOICE_PROCESSED* pvoice) // MIX ADSR +{ + u32 rateadd[8] = { 0, 4, 6, 8, 9, 10, 11, 12 }; + + if (pvoice->bStop) // should be stopped: + { + if (pvoice->ADSRX.ReleaseModeExp) // do release + { + s32 temp = ((pvoice->ADSRX.EnvelopeVol>>28)&0x7); + pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F)) - 0x18 + rateadd[temp] + 32]; + } + else + { + pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F)) - 0x0C + 32]; + } + + // bIgnoreLoop sets EnvelopeVol to 0 anyways, so we can use one if statement rather then two. + if ((pvoice->ADSRX.EnvelopeVol<0) || (pvoice->bIgnoreLoop == 0)) + { + pvoice->ADSRX.EnvelopeVol=0; + pvoice->bOn=false; + pvoice->pStart= (u8*)(spu2mem+pvoice->iStartAddr); + pvoice->pLoop= (u8*)(spu2mem+pvoice->iStartAddr); + pvoice->pCurr= (u8*)(spu2mem+pvoice->iStartAddr); + pvoice->bStop = true; + pvoice->bIgnoreLoop = false; + //pvoice->bReverb=0; + //pvoice->bNoise=0; + } + + pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; + + return pvoice->ADSRX.lVolume; + } + else // not stopped yet? + { + s32 temp = ((pvoice->ADSRX.EnvelopeVol>>28)&0x7); + + switch (pvoice->ADSRX.State) + { + case 0: // -> attack + if (pvoice->ADSRX.AttackModeExp) + { + if (pvoice->ADSRX.EnvelopeVol<0x60000000) + pvoice->ADSRX.EnvelopeVol += RateTable[(pvoice->ADSRX.AttackRate^0x7F) - 0x10 + 32]; + else + pvoice->ADSRX.EnvelopeVol += RateTable[(pvoice->ADSRX.AttackRate^0x7F) - 0x18 + 32]; + } + else + { + pvoice->ADSRX.EnvelopeVol += RateTable[(pvoice->ADSRX.AttackRate^0x7F) - 0x10 + 32]; + } + + if (pvoice->ADSRX.EnvelopeVol<0) + { + pvoice->ADSRX.EnvelopeVol=0x7FFFFFFF; + pvoice->ADSRX.State=1; + } + break; + + case 1: // -> decay + pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F)) - 0x18+ rateadd[temp] + 32]; + + if (pvoice->ADSRX.EnvelopeVol<0) pvoice->ADSRX.EnvelopeVol=0; + + if (((pvoice->ADSRX.EnvelopeVol>>27)&0xF) <= pvoice->ADSRX.SustainLevel) + pvoice->ADSRX.State=2; + break; + + case 2: // -> sustain + if (pvoice->ADSRX.SustainIncrease) + { + if ((pvoice->ADSRX.SustainModeExp) && (pvoice->ADSRX.EnvelopeVol>=0x60000000)) + pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.SustainRate^0x7F) - 0x18 + 32]; + else + pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.SustainRate^0x7F) - 0x10 + 32]; + + if (pvoice->ADSRX.EnvelopeVol<0) pvoice->ADSRX.EnvelopeVol=0x7FFFFFFF; + } + else + { + if (pvoice->ADSRX.SustainModeExp) + pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F)) - 0x1B +rateadd[temp] + 32]; + else + pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F)) - 0x0F + 32]; + + if (pvoice->ADSRX.EnvelopeVol<0) pvoice->ADSRX.EnvelopeVol=0; + } + break; + + default: + // This should never happen. + return 0; + } + + pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; + return pvoice->ADSRX.lVolume; + } + + return 0; +} + +void MixChannels(int core) +{ + // mix all channels + int c_offset = 0x0400 * core; + int dma, left_vol, right_vol; + ADMA *Adma; + + if (core == 0) + { + Adma = &Adma4; + dma = 4; + left_vol = REG_C0_BVOLL; + right_vol = REG_C0_BVOLR; + } + else + { + Adma = &Adma7; + dma = 7; + left_vol = REG_C1_BVOLL; + right_vol = REG_C1_BVOLR; + } + + if ((spu2Ru16(REG_C0_MMIX + c_offset) & 0xF0) && (spu2Ru16(REG_C0_ADMAS + c_offset) & (0x1 + core))) + { + for (int ns=0;nsIndex]*(int)spu2Ru16(left_vol))>>16; + if ((spu2Ru16(REG_C0_MMIX + c_offset) & 0x40)) + s_buffers[ns][1] += (((short*)spu2mem)[0x2200 + c_offset +Adma->Index]*(int)spu2Ru16(right_vol))>>16; + + Adma->Index +=1; + MemAddr[core] += 4; + + if (Adma->Index == 128 || Adma->Index == 384) + { + if (ADMASWrite(core)) + { + if (interrupt & (0x2 * (core + 1))) + { + interrupt &= ~(0x2 * (core + 1)); + printf("Stopping double interrupt DMA7\n"); + } + if (core == 0) + irqCallbackDMA4(); + else + irqCallbackDMA7(); + + } + if (core == 1) Adma->Enabled = 2; + } + + if (Adma->Index == 512) + { + if ( Adma->Enabled == 2 ) Adma->Enabled = 0; + Adma->Index = 0; + } + } + } +} + +// simulate SPU2 for 1ms +void SPU2Worker() +{ + int s_1,s_2,fa; + u8* start; + u32 nSample; + int ch,predict_nr,shift_factor,flags,d,s; + + // assume s_buffers are zeroed out + if ( dwNewChannel2[0] || dwNewChannel2[1] ) + s_pAudioBuffers[s_nCurBuffer].newchannels++; + + VOICE_PROCESSED* pChannel=voices; + for (ch=0;chbNew) + { + pChannel->StartSound(); // start new sound + dwEndChannel2[ch/24]&=~(1<<(ch%24)); // clear end channel bit + dwNewChannel2[ch/24]&=~(1<<(ch%24)); // clear channel bit + } + + if (!pChannel->bOn) continue; + + if (pChannel->iActFreq!=pChannel->iUsedFreq) // new psx frequency? + pChannel->VoiceChangeFrequency(); + + // loop until 1 ms of data is reached + int ns = 0; + + while(nsbFMod==1 && iFMod[ns]) // fmod freq channel + pChannel->FModChangeFrequency(ns); + + while(pChannel->spos >= 0x10000 ) + { + if (pChannel->iSBPos == 28) // 28 reached? + { + start=pChannel->pCurr; // set up the current pos + + // special "stop" sign - fixme - an *unsigned* -1? + if (start == (u8*)-1) //!pChannel->bOn + { + pChannel->bOn=false; // -> turn everything off + pChannel->ADSRX.lVolume=0; + pChannel->ADSRX.EnvelopeVol=0; + goto ENDX; // -> and done for this channel + } + + pChannel->iSBPos=0; + + // decode the 16byte packet + s_1=pChannel->s_1; + s_2=pChannel->s_2; + + predict_nr=(s32)start[0]; + shift_factor=predict_nr&0xf; + predict_nr >>= 4; + flags=(s32)start[1]; + start += 2; + + for (nSample=0;nSample<28; ++start) + { + d = (int)*start; + s = ((d & 0xf)<<12); + if (s & 0x8000) s |= 0xffff0000; + + fa = (s >> shift_factor); + fa += ((s_1 * f[predict_nr][0]) >> 6) + ((s_2 * f[predict_nr][1]) >> 6); + s_2 = s_1; + s_1 = fa; + s = ((d & 0xf0) << 8); + + pChannel->SB[nSample++]=fa; + + if (s & 0x8000) s|=0xffff0000; + fa = (s>>shift_factor); + fa += ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1]) >> 6); + s_2 = s_1; + s_1 = fa; + + pChannel->SB[nSample++]=fa; + } + + // irq occurs no matter what core access the address + for (int core = 0; core < 2; ++core) + { + if (((SPU_CONTROL_*)(spu2regs + 0x400 * core + REG_C0_CTRL))->irq) // some callback and irq active? + { + // if irq address reached or irq on looping addr, when stop/loop flag is set + u8* pirq = (u8*)pSpuIrq[core]; + if ((pirq > (start - 16) && pirq <= start) || ((flags & 1) && (pirq > (pChannel->pLoop - 16) && pirq <= pChannel->pLoop))) + { + IRQINFO |= 4<bIgnoreLoop)) + pChannel->pLoop=start-16; // loop adress + + if (flags&1) // 1: stop/loop + { + // We play this block out first... + dwEndChannel2[ch/24]|=(1<<(ch%24)); + + if (flags!=3 || pChannel->pLoop==NULL) + { // and checking if pLoop is set avoids crashes, yeah + start = (u8*)-1; + pChannel->bStop = true; + pChannel->bIgnoreLoop = false; + } + else + { + start = pChannel->pLoop; + } + } + + pChannel->pCurr=start; // store values for next cycle + pChannel->s_1=s_1; + pChannel->s_2=s_2; + } + + fa=pChannel->SB[pChannel->iSBPos++]; // get sample data + pChannel->StoreInterpolationVal(fa); + pChannel->spos -= 0x10000; + } + + if (pChannel->bNoise) + fa=pChannel->iGetNoiseVal(); // get noise val + else + fa=pChannel->iGetInterpolationVal(); // get sample val + + int sval = (MixADSR(pChannel) * fa) / 1023; // mix adsr + + if (pChannel->bFMod == 2) // fmod freq channel + { + iFMod[ns] = sval; // -> store 1T sample data, use that to do fmod on next channel + } + else + { + if (pChannel->bVolumeL) + s_buffers[ns][0]+=(sval * pChannel->leftvol)>>14; + + if (pChannel->bVolumeR) + s_buffers[ns][1]+=(sval * pChannel->rightvol)>>14; + } + + // go to the next packet + ns++; + pChannel->spos += pChannel->sinc; + } +ENDX: + ; + } + + // mix all channels + MixChannels(0); + MixChannels(1); + + if ( g_bPlaySound ) + { + assert( s_pCurOutput != NULL); + + for (int ns=0; ns= 4 * NSSIZE * NSFRAMES) + { + + if ( conf.options & OPTION_RECORDING ) + { + static int lastrectime = 0; + if (timeGetTime() - lastrectime > 5000) + { + printf("ZeroSPU2: recording\n"); + lastrectime = timeGetTime(); + } + LogRawSound(s_pAudioBuffers[s_nCurBuffer].pbuf, 4, s_pAudioBuffers[s_nCurBuffer].pbuf+2, 4, NSSIZE*NSFRAMES); + } + + if ( s_nQueuedBuffers >= ARRAYSIZE(s_pAudioBuffers)-1 ) + { + //ZeroSPU2: dropping packets! game too fast + s_nDropPacket += NSFRAMES; + s_GlobalTimeStamp = GetMicroTime(); + } + else { + // submit to final mixer +#ifdef _DEBUG + if ( g_logsound ) + LogRawSound(s_pAudioBuffers[s_nCurBuffer].pbuf, 4, s_pAudioBuffers[s_nCurBuffer].pbuf+2, 4, NSSIZE*NSFRAMES); +#endif + if ( g_startcount == 0xffffffff ) + { + g_startcount = timeGetTime(); + g_packetcount = 0; + } + + if ( conf.options & OPTION_TIMESTRETCH ) + { + u64 newtime = GetMicroTime(); + if ( s_GlobalTimeStamp == 0 ) + s_GlobalTimeStamp = newtime-NSFRAMES*1000; + u32 newtotal = s_nTotalDuration-s_nDurations[s_nCurDuration]; + u32 duration = (u32)(newtime-s_GlobalTimeStamp); + s_nDurations[s_nCurDuration] = duration; + s_nTotalDuration = newtotal + duration; + s_nCurDuration = (s_nCurDuration+1)%ARRAYSIZE(s_nDurations); + s_GlobalTimeStamp = newtime; + s_pAudioBuffers[s_nCurBuffer].timestamp = timeGetTime(); + s_pAudioBuffers[s_nCurBuffer].avgtime = s_nTotalDuration/ARRAYSIZE(s_nDurations); + } + + s_pAudioBuffers[s_nCurBuffer].len = 4*NSSIZE*NSFRAMES; + InterlockedExchangeAdd((long*)&s_nQueuedBuffers, 1); + + s_nCurBuffer = (s_nCurBuffer+1)%ARRAYSIZE(s_pAudioBuffers); + s_pAudioBuffers[s_nCurBuffer].newchannels = 0; // reset + } + + // restart + s_pCurOutput = (s16*)s_pAudioBuffers[s_nCurBuffer].pbuf; + } + } +} + +// resamples pStereoSamples +void ResampleLinear(s16* pStereoSamples, int oldsamples, s16* pNewSamples, int newsamples) +{ + for (int i = 0; i < newsamples; ++i) + { + int io = i * oldsamples; + int old = io / newsamples; + int rem = io - old * newsamples; + + old *= 2; + int newsampL = pStereoSamples[old] * (newsamples - rem) + pStereoSamples[old+2] * rem; + int newsampR = pStereoSamples[old+1] * (newsamples - rem) + pStereoSamples[old+3] * rem; + pNewSamples[2 * i] = newsampL / newsamples; + pNewSamples[2 * i + 1] = newsampR / newsamples; + } +} + +static PCSX2_ALIGNED16(s16 s_ThreadBuffer[NSSIZE*NSFRAMES*2*5]); + +// SoundTouch's INTEGER system is broken these days, so we'll need this to do float conversions... +static PCSX2_ALIGNED16(float s_floatBuffer[NSSIZE*NSFRAMES*2*5]); + +// communicates with the audio hardware +#ifdef _WIN32 +DWORD WINAPI SPU2ThreadProc(LPVOID) +#else +void* SPU2ThreadProc(void* lpParam) +#endif +{ + int nReadBuf = 0; + + while (!s_bThreadExit) + { + + if (!(conf.options&OPTION_REALTIME)) + { + while(s_nQueuedBuffers< 3 && !s_bThreadExit) + { + //Sleeping + Sleep(1); + if ( s_bThreadExit ) + return NULL; + } + + while( SoundGetBytesBuffered() > 72000 ) + { + //Bytes buffered + Sleep(1); + + if ( s_bThreadExit ) return NULL; + } + } + else + { + while(s_nQueuedBuffers< 1 && !s_bThreadExit) + { + //Sleeping + Sleep(1); + } + } + + + //int ps2delay = timeGetTime() - s_pAudioBuffers[nReadBuf].timestamp; + int NewSamples = s_pAudioBuffers[nReadBuf].avgtime; + + if ( (conf.options & OPTION_TIMESTRETCH) ) + { + + int bytesbuf = SoundGetBytesBuffered(); + if ( bytesbuf < 8000 ) + NewSamples += 1000; + // check the current timestamp, if too far apart, speed up audio + else if ( bytesbuf > 40000 ) + { + //printf("making faster %d\n", timeGetTime() - s_pAudioBuffers[nReadBuf].timestamp); + NewSamples -= (bytesbuf-40000)/10;//*(ps2delay-NewSamples*8/1000); + } + + if ( s_nDropPacket > 0 ) + { + s_nDropPacket--; + NewSamples -= 1000; + } + + NewSamples *= NSSIZE; + NewSamples /= 1000; + + NewSamples = min(NewSamples, NSFRAMES * NSSIZE * 3); + + int oldsamples = s_pAudioBuffers[nReadBuf].len / 4; + + if ((nReadBuf & 3) == 0) // wow, this if statement makes the whole difference + pSoundTouch->setTempoChange(100.0f*(float)oldsamples/(float)NewSamples - 100.0f); + + for( int sx=0; sxputSamples(s_floatBuffer, oldsamples); + + // extract 2*NSFRAMES ms at a time + int nOutSamples; + + do + { + nOutSamples = pSoundTouch->receiveSamples(s_floatBuffer, NSSIZE * NSFRAMES * 5); + if ( nOutSamples > 0 ) + { + for( int sx=0; sx>=1) // loop channels + { + if ((val&1) && voices[ch].pStart) // mmm... start has to be set before key on !?! + { + voices[ch].bNew=true; + voices[ch].bIgnoreLoop = false; + dwNewChannel2[ch/24]|=(1<<(ch%24)); // clear end channel bit + } + } +} + +// turn channels off +void SoundOff(int start,int end,unsigned short val) // SOUND OFF PSX COMMAND +{ + for (int ch=start;ch>=1) // loop channels + { + if (val&1) voices[ch].bStop=true; // && s_chan[i].bOn) mmm... + } +} + +void FModOn(int start,int end,unsigned short val) // FMOD ON PSX COMMAND +{ + int ch; + + for (ch=start;ch>=1) // loop channels + { + if (val&1) + { // -> fmod on/off + if (ch>0) + { + voices[ch].bFMod=1; // --> sound channel + voices[ch-1].bFMod=2; // --> freq channel + } + } + else + voices[ch].bFMod=0; // --> turn off fmod + } +} + +void VolumeOn(int start,int end,unsigned short val,int iRight) // VOLUME ON PSX COMMAND +{ + int ch; + + for (ch=start;ch>=1) // loop channels + { + if (val&1) + { // -> reverb on/off + if (iRight) + voices[ch].bVolumeR = true; + else + voices[ch].bVolumeL = true; + } + else + { + if (iRight) + voices[ch].bVolumeR = false; + else + voices[ch].bVolumeL = false; + } + } +} + +void CALLBACK SPU2write(u32 mem, u16 value) +{ + LOG_CALLBACK("SPU2write()\n"); + u32 spuaddr; + SPU2_LOG("SPU2 write mem %x value %x\n", mem, value); + + assert(C0_SPUADDR() < 0x100000); + assert(C1_SPUADDR() < 0x100000); + + spu2Ru16(mem) = value; + u32 r = mem & 0xffff; + + // channel info + if ((r<0x0180) || (r>=0x0400 && r<0x0580)) // u32s are always >= 0. + { + int ch=0; + if (r >= 0x400) + ch = ((r - 0x400) >> 4) + 24; + else + ch = (r >> 4); + + VOICE_PROCESSED* pvoice = &voices[ch]; + + switch(r & 0x0f) + { + case 0: + case 2: + pvoice->SetVolume(mem & 0x2); + break; + case 4: + { + int NP; + if (value> 0x3fff) + NP=0x3fff; // get pitch val + else + NP=value; + + pvoice->pvoice->pitch = NP; + + NP = (SAMPLE_RATE * NP) / 4096L; // calc frequency + if (NP<1) NP = 1; // some security + pvoice->iActFreq = NP; // store frequency + break; + } + case 6: + { + pvoice->ADSRX.AttackModeExp=(value&0x8000)?1:0; + pvoice->ADSRX.AttackRate = ((value>>8) & 0x007f); + pvoice->ADSRX.DecayRate = (((value>>4) & 0x000f)); + pvoice->ADSRX.SustainLevel = (value & 0x000f); + break; + } + case 8: + pvoice->ADSRX.SustainModeExp = (value&0x8000)?1:0; + pvoice->ADSRX.SustainIncrease= (value&0x4000)?0:1; + pvoice->ADSRX.SustainRate = ((value>>6) & 0x007f); + pvoice->ADSRX.ReleaseModeExp = (value&0x0020)?1:0; + pvoice->ADSRX.ReleaseRate = ((value & 0x001f)); + break; + } + + return; + } + + // more channel info + if ((r>=0x01c0 && r<0x02E0)||(r>=0x05c0 && r<0x06E0)) + { + int ch=0; + unsigned long rx=r; + if (rx>=0x400) + { + ch=24; + rx-=0x400; + } + + ch += ((rx-0x1c0)/12); + rx -= (ch%24)*12; + VOICE_PROCESSED* pvoice = &voices[ch]; + + switch(rx) + { + case REG_VA_SSA: + pvoice->iStartAddr=(((u32)value&0x3f)<<16)|(pvoice->iStartAddr&0xFFFF); + pvoice->pStart=(u8*)(spu2mem+pvoice->iStartAddr); + break; + case 0x1C2: + pvoice->iStartAddr=(pvoice->iStartAddr & 0x3f0000) | (value & 0xFFFF); + pvoice->pStart=(u8*)(spu2mem+pvoice->iStartAddr); + break; + case REG_VA_LSAX: + pvoice->iLoopAddr =(((u32)value&0x3f)<<16)|(pvoice->iLoopAddr&0xFFFF); + pvoice->pLoop=(u8*)(spu2mem+pvoice->iLoopAddr); + pvoice->bIgnoreLoop=pvoice->iLoopAddr>0; + break; + case 0x1C6: + pvoice->iLoopAddr=(pvoice->iLoopAddr& 0x3f0000) | (value & 0xFFFF); + pvoice->pLoop=(u8*)(spu2mem+pvoice->iLoopAddr); + pvoice->bIgnoreLoop=pvoice->iLoopAddr>0; + break; + case REG_VA_NAX: + // unused... check if it gets written as well + pvoice->iNextAddr=(((u32)value&0x3f)<<16)|(pvoice->iNextAddr&0xFFFF); + break; + case 0x1CA: + // unused... check if it gets written as well + pvoice->iNextAddr=(pvoice->iNextAddr & 0x3f0000) | (value & 0xFFFF); + break; + } + + return; + } + + // process non-channel data + switch(mem & 0xffff) + { + case REG_C0_SPUDATA: + spuaddr = C0_SPUADDR(); + spu2mem[spuaddr] = value; + spuaddr++; + + if ((spu2Ru16(REG_C0_CTRL)&0x40) && (C0_IRQA() == spuaddr)) + { + IRQINFO |= 4; + SPU2_LOG("SPU2write:C0_CPUDATA interrupt\n"); + irqCallbackSPU2(); + } + + if (spuaddr>0xFFFFE) spuaddr = 0x2800; + + C0_SPUADDR_SET(spuaddr); + spu2Ru16(REG_C0_SPUSTAT)&=~0x80; + spu2Ru16(REG_C0_CTRL)&=~0x30; + break; + + case REG_C1_SPUDATA: + spuaddr = C1_SPUADDR(); + spu2mem[spuaddr] = value; + spuaddr++; + + if ((spu2Ru16(REG_C1_CTRL)&0x40) && (C1_IRQA() == spuaddr)) + { + IRQINFO |= 8; + SPU2_LOG("SPU2write:C1_CPUDATA interrupt\n"); + irqCallbackSPU2(); + } + + if (spuaddr>0xFFFFE) spuaddr = 0x2800; + + C1_SPUADDR_SET(spuaddr); + spu2Ru16(REG_C1_SPUSTAT)&=~0x80; + spu2Ru16(REG_C1_CTRL)&=~0x30; + break; + + case REG_C0_IRQA_HI: + case REG_C0_IRQA_LO: + pSpuIrq[0] = spu2mem + C0_IRQA(); + break; + + case REG_C1_IRQA_HI: + case REG_C1_IRQA_LO: + pSpuIrq[1] = spu2mem + C1_IRQA(); + break; + + case REG_C0_SPUADDR_HI: + case REG_C1_SPUADDR_HI: + spu2Ru16(mem) = value&0xf; + break; + + case REG_C0_CTRL: + spu2Ru16(mem) = value; + // clear interrupt + if (!(value & 0x40)) IRQINFO &= ~0x4; + break; + + case REG_C1_CTRL: + spu2Ru16(mem) = value; + // clear interrupt + if (!(value & 0x40)) IRQINFO &= ~0x8; + break; + + // Could probably simplify + case REG_C0_SPUON1: SoundOn(0,16,value); break; + case REG_C0_SPUON2: SoundOn(16,24,value); break; + case REG_C1_SPUON1: SoundOn(24,40,value); break; + case REG_C1_SPUON2: SoundOn(40,48,value); break; + case REG_C0_SPUOFF1: SoundOff(0,16,value); break; + case REG_C0_SPUOFF2: SoundOff(16,24,value); break; + case REG_C1_SPUOFF1: SoundOff(24,40,value); break; + case REG_C1_SPUOFF2: SoundOff(40,48,value); break; + + // According to manual all bits are cleared by writing an arbitary value + case REG_C0_END1: dwEndChannel2[0] &= 0x00ff0000; break; + case REG_C0_END2: dwEndChannel2[0] &= 0x0000ffff; break; + case REG_C1_END1: dwEndChannel2[1] &= 0x00ff0000; break; + case REG_C1_END2: dwEndChannel2[1] &= 0x0000ffff; break; + case REG_C0_FMOD1: FModOn(0,16,value); break; + case REG_C0_FMOD2: FModOn(16,24,value); break; + case REG_C1_FMOD1: FModOn(24,40,value); break; + case REG_C1_FMOD2: FModOn(40,48,value); break; + case REG_C0_VMIXL1: VolumeOn(0,16,value,0); break; + case REG_C0_VMIXL2: VolumeOn(16,24,value,0); break; + case REG_C1_VMIXL1: VolumeOn(24,40,value,0); break; + case REG_C1_VMIXL2: VolumeOn(40,48,value,0); break; + case REG_C0_VMIXR1: VolumeOn(0,16,value,1); break; + case REG_C0_VMIXR2: VolumeOn(16,24,value,1); break; + case REG_C1_VMIXR1: VolumeOn(24,40,value,1); break; + case REG_C1_VMIXR2: VolumeOn(40,48,value,1); break; + } + + assert( C0_SPUADDR() < 0x100000); + assert( C1_SPUADDR() < 0x100000); +} + +u16 CALLBACK SPU2read(u32 mem) +{ + LOG_CALLBACK("SPU2read()\n"); + u32 spuaddr; + u16 ret = 0; + u32 r = mem & 0xffff; // register + + // channel info + // if the register is any of the regs before core 0, or is somewhere between core 0 and 1... + if ((r < 0x0180) || (r >= 0x0400 && r < 0x0580)) // u32s are always >= 0. + { + int ch = 0; + + if (r >= 0x400) + ch=((r - 0x400) >> 4) + 24; + else + ch = (r >> 4); + + VOICE_PROCESSED* pvoice = &voices[ch]; + + if ((r&0x0f) == 10) return (u16)(pvoice->ADSRX.EnvelopeVol >> 16); + } + + + if ((r>=REG_VA_SSA && r=0x05c0 && r<0x06E0)) // some channel info? + { + int ch=0; + unsigned long rx = r; + + if (rx >=0x400) + { + ch=24; + rx-=0x400; + } + + ch+=((rx-0x1c0)/12); + rx-=(ch%24)*12; + VOICE_PROCESSED* pvoice = &voices[ch]; + + // Note - can we generalize this? + switch(rx) + { + case REG_VA_SSA: + ret = ((((uptr)pvoice->pStart-(uptr)spu2mem)>>17)&0x3F); + break; + case 0x1C2: + ret = ((((uptr)pvoice->pStart-(uptr)spu2mem)>>1)&0xFFFF); + break; + case REG_VA_LSAX: + ret = ((((uptr)pvoice->pLoop-(uptr)spu2mem)>>17)&0x3F); + break; + case 0x1C6: + ret = ((((uptr)pvoice->pLoop-(uptr)spu2mem)>>1)&0xFFFF); + break; + case REG_VA_NAX: + ret = ((((uptr)pvoice->pCurr-(uptr)spu2mem)>>17)&0x3F); + break; + case 0x1CA: + ret = ((((uptr)pvoice->pCurr-(uptr)spu2mem)>>1)&0xFFFF); + break; + } + + SPU2_LOG("SPU2 channel read mem %x: %x\n", mem, ret); + return ret; + } + + switch(mem & 0xffff) + { + case REG_C0_SPUDATA: + spuaddr = C0_SPUADDR(); + ret =spu2mem[spuaddr]; + spuaddr++; + if (spuaddr > 0xfffff) spuaddr=0; + C0_SPUADDR_SET(spuaddr); + break; + case REG_C1_SPUDATA: + spuaddr = C1_SPUADDR(); + ret = spu2mem[spuaddr]; + spuaddr++; + if (spuaddr > 0xfffff) spuaddr=0; + C1_SPUADDR_SET(spuaddr); + break; + + case REG_C0_END1: ret = (dwEndChannel2[0]&0xffff); break; + case REG_C1_END1: ret = (dwEndChannel2[1]&0xffff); break; + case REG_C0_END2: ret = (dwEndChannel2[0]>>16); break; + case REG_C1_END2: ret = (dwEndChannel2[1]>>16); break; + + case REG_IRQINFO: + ret = IRQINFO; + break; + + default: + ret = spu2Ru16(mem); + } + + SPU2_LOG("SPU2 read mem %x: %x\n", mem, ret); + + return ret; +} + +void CALLBACK SPU2WriteMemAddr(int core, u32 value) +{ + LOG_CALLBACK("SPU2WriteMemAddr(%d, %d)\n", core, value); + MemAddr[core] = g_pDMABaseAddr + value; +} + +u32 CALLBACK SPU2ReadMemAddr(int core) +{ + LOG_CALLBACK("SPU2ReadMemAddr(%d)\n", core); + return MemAddr[core] - g_pDMABaseAddr; +} + +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr) +{ + LOG_CALLBACK("SPU2setDMABaseAddr()\n"); + g_pDMABaseAddr = baseaddr; +} + +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()) +{ + LOG_CALLBACK("SPU2irqCallback()\n"); + irqCallbackSPU2 = SPU2callback; + irqCallbackDMA4 = DMA4callback; + irqCallbackDMA7 = DMA7callback; +} + +s32 CALLBACK SPU2test() +{ + LOG_CALLBACK("SPU2test()\n"); + return 0; +} + +#define SetPacket(s) \ +{ \ + if (s & 0x8000) s|=0xffff0000; \ + fa = (s >> shift_factor); \ + fa += ((s_1 * f[predict_nr][0]) >> 6) + ((s_2 * f[predict_nr][1]) >> 6); \ + s_2 = s_1; \ + s_1 = fa; \ + buf[nSample++] = fa; \ +} + +// size is in bytes +void LogPacketSound(void* packet, int memsize) +{ + u16 buf[28]; + + u8* pstart = (u8*)packet; + int s_1 = 0, s_2=0; + + for (int i = 0; i < memsize; i += 16) + { + int predict_nr=(int)pstart[0]; + int shift_factor=predict_nr&0xf; + predict_nr >>= 4; + pstart += 2; + + for (int nSample=0;nSample<28; ++pstart) + { + int d=(int)*pstart; + int s, fa; + + s =((d & 0xf) << 12); + SetPacket(s); + + s=((d & 0xf0) << 8); + SetPacket(s); + } + + LogRawSound(buf, 2, buf, 2, 28); + } +} + +void LogRawSound(void* pleft, int leftstride, void* pright, int rightstride, int numsamples) +{ + if (g_pWavRecord == NULL ) + g_pWavRecord = new WavOutFile(RECORD_FILENAME, SAMPLE_RATE, 16, 2); + + u8* left = (u8*)pleft; + u8* right = (u8*)pright; + static vector tempbuf; + + tempbuf.resize(2 * numsamples); + + for (int i = 0; i < numsamples; ++i) + { + tempbuf[2*i+0] = *(s16*)left; + tempbuf[2*i+1] = *(s16*)right; + left += leftstride; + right += rightstride; + } + + g_pWavRecord->write(&tempbuf[0], numsamples*2); +} + +int CALLBACK SPU2setupRecording(int start, void* pData) +{ + LOG_CALLBACK("SPU2setupRecording()\n"); + if ( start ) + { + conf.options |= OPTION_RECORDING; + printf("ZeroSPU2: started recording at %s\n", RECORD_FILENAME); + } + else + { + conf.options &= ~OPTION_RECORDING; + printf("ZeroSPU2: stopped recording\n"); + } + + return 1; +} + +s32 CALLBACK SPU2freeze(int mode, freezeData *data) +{ + LOG_CALLBACK("SPU2freeze()\n"); + SPU2freezeData *spud; + int i; + assert( g_pDMABaseAddr != 0 ); + + if (mode == FREEZE_LOAD) + { + spud = (SPU2freezeData*)data->data; + if (spud->version != 0x70000001) + { + printf("zerospu2: data wrong format\n"); + return 0; + } + + memcpy(spu2regs, spud->spu2regs, 0x10000); + memcpy(spu2mem, spud->spu2mem, 0x200000); + pSpuIrq[0] = spu2mem + spud->nSpuIrq[0]; + pSpuIrq[1] = spu2mem + spud->nSpuIrq[1]; + memcpy(dwNewChannel2, spud->dwNewChannel2, 4*2); + memcpy(dwEndChannel2, spud->dwEndChannel2, 4*2); + dwNoiseVal = spud->dwNoiseVal; + memcpy(iFMod, spud->iFMod, sizeof(iFMod)); + interrupt = spud->interrupt; + memcpy(MemAddr, spud->MemAddr, sizeof(MemAddr)); + Adma4 = spud->adma[0]; + Adma4.MemAddr = (u16*)(g_pDMABaseAddr+spud->Adma4MemAddr); + Adma7 = spud->adma[1]; + Adma7.MemAddr = (u16*)(g_pDMABaseAddr+spud->Adma7MemAddr); + + SPUCycles = spud->SPUCycles; + SPUWorkerCycles = spud->SPUWorkerCycles; + memcpy(SPUStartCycle, spud->SPUStartCycle, sizeof(SPUStartCycle)); + memcpy(SPUTargetCycle, spud->SPUTargetCycle, sizeof(SPUTargetCycle)); + + for (i = 0; i < ARRAYSIZE(voices); ++i) + { + memcpy(&voices[i], &spud->voices[i], min((int)SPU_VOICE_STATE_SIZE, spud->voicesize)); + voices[i].pStart = (u8*)((uptr)spud->voices[i].pStart+(uptr)spu2mem); + voices[i].pLoop = (u8*)((uptr)spud->voices[i].pLoop+(uptr)spu2mem); + voices[i].pCurr = (u8*)((uptr)spud->voices[i].pCurr+(uptr)spu2mem); + } + + s_GlobalTimeStamp = 0; + g_startcount = 0xffffffff; + + for (int i = 0; i < ARRAYSIZE(s_nDurations); ++i) + { + s_nDurations[i] = NSFRAMES*1000; + } + + s_nTotalDuration = ARRAYSIZE(s_nDurations)*NSFRAMES*1000; + s_nCurDuration = 0; + s_nQueuedBuffers = 0; + s_nDropPacket = 0; + } + else if (mode == FREEZE_SAVE) + { + spud = (SPU2freezeData*)data->data; + spud->version = 0x70000001; + + memcpy(spud->spu2regs, spu2regs, 0x10000); + memcpy(spud->spu2mem, spu2mem, 0x200000); + spud->nSpuIrq[0] = (int)(pSpuIrq[0] - spu2mem); + spud->nSpuIrq[1] = (int)(pSpuIrq[1] - spu2mem); + memcpy(spud->dwNewChannel2, dwNewChannel2, 4*2); + memcpy(spud->dwEndChannel2, dwEndChannel2, 4*2); + spud->dwNoiseVal = dwNoiseVal; + memcpy(spud->iFMod, iFMod, sizeof(iFMod)); + spud->interrupt = interrupt; + memcpy(spud->MemAddr, MemAddr, sizeof(MemAddr)); + + spud->adma[0] = Adma4; + spud->Adma4MemAddr = (u32)((uptr)Adma4.MemAddr - g_pDMABaseAddr); + spud->adma[1] = Adma7; + spud->Adma7MemAddr = (u32)((uptr)Adma7.MemAddr - g_pDMABaseAddr); + + spud->SPUCycles = SPUCycles; + spud->SPUWorkerCycles = SPUWorkerCycles; + + memcpy(spud->SPUStartCycle, SPUStartCycle, sizeof(SPUStartCycle)); + memcpy(spud->SPUTargetCycle, SPUTargetCycle, sizeof(SPUTargetCycle)); + + for (i = 0; i < ARRAYSIZE(s_nDurations); ++i) + { + s_nDurations[i] = NSFRAMES*1000; + } + s_nTotalDuration = ARRAYSIZE(s_nDurations)*NSFRAMES*1000; + s_nCurDuration = 0; + + spud->voicesize = SPU_VOICE_STATE_SIZE; + for (i = 0; i < ARRAYSIZE(voices); ++i) + { + memcpy(&spud->voices[i], &voices[i], SPU_VOICE_STATE_SIZE); + spud->voices[i].pStart = (u8*)((uptr)voices[i].pStart-(uptr)spu2mem); + spud->voices[i].pLoop = (u8*)((uptr)voices[i].pLoop-(uptr)spu2mem); + spud->voices[i].pCurr = (u8*)((uptr)voices[i].pCurr-(uptr)spu2mem); + } + + g_startcount=0xffffffff; + s_GlobalTimeStamp = 0; + s_nDropPacket = 0; + } + else if (mode == FREEZE_SIZE) + { + data->size = sizeof(SPU2freezeData); + } + + return 0; +}